From aa2a51c44003621b3567efcb85e9168f76f09d8f Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 20 Nov 2024 08:40:21 +0100 Subject: [PATCH 001/354] core/vm/program: evm bytecode-building utility (#30725) In many cases, there is a need to create somewhat nontrivial bytecode. A recent example is the verkle statetests, where we want a `CREATE2`- op to create a contract, which can then be invoked, and when invoked does a selfdestruct-to-self. It is overkill to go full solidity, but it is also a bit tricky do assemble this by concatenating bytes. This PR takes an approach that has been used in in goevmlab for several years. Using this utility, the case can be expressed as: ```golang // Some runtime code runtime := program.New().Ops(vm.ADDRESS, vm.SELFDESTRUCT).Bytecode() // A constructor returning the runtime code initcode := program.New().ReturnData(runtime).Bytecode() // A factory invoking the constructor outer := program.New().Create2AndCall(initcode, nil).Bytecode() ``` We have a lot of places in the codebase where we concatenate bytes, cast from `vm.OpCode` . By taking tihs approach instead, thos places can be made a bit more maintainable/robust. --- core/vm/program/program.go | 430 ++++++++++++++++++++++++++++++++ core/vm/program/program_test.go | 311 +++++++++++++++++++++++ core/vm/program/readme.md | 30 +++ core/vm/runtime/runtime_test.go | 264 +++++--------------- 4 files changed, 840 insertions(+), 195 deletions(-) create mode 100644 core/vm/program/program.go create mode 100644 core/vm/program/program_test.go create mode 100644 core/vm/program/readme.md diff --git a/core/vm/program/program.go b/core/vm/program/program.go new file mode 100644 index 000000000..acc7fd25f --- /dev/null +++ b/core/vm/program/program.go @@ -0,0 +1,430 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The 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. +// +// This 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 goevmlab library. If not, see . + +// package program is a utility to create EVM bytecode for testing, but _not_ for production. As such: +// +// - There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning +// - There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV. +// - There are no stability-guarantees. The utility will `panic` if the inputs do not align / make sense. +package program + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" +) + +// Program is a simple bytecode container. It can be used to construct +// simple EVM programs. Errors during construction of a Program typically +// cause panics: so avoid using these programs in production settings or on +// untrusted input. +// This package is mainly meant to aid in testing. This is not a production +// -level "compiler". +type Program struct { + code []byte +} + +// New creates a new Program +func New() *Program { + return &Program{ + code: make([]byte, 0), + } +} + +// add adds the op to the code. +func (p *Program) add(op byte) *Program { + p.code = append(p.code, op) + return p +} + +// pushBig creates a PUSHX instruction and pushes the given val. +// - If the val is nil, it pushes zero +// - If the val is bigger than 32 bytes, it panics +func (p *Program) doPush(val *uint256.Int) { + if val == nil { + val = new(uint256.Int) + } + valBytes := val.Bytes() + if len(valBytes) == 0 { + valBytes = append(valBytes, 0) + } + bLen := len(valBytes) + p.add(byte(vm.PUSH1) - 1 + byte(bLen)) + p.Append(valBytes) +} + +// Append appends the given data to the code. +func (p *Program) Append(data []byte) *Program { + p.code = append(p.code, data...) + return p +} + +// Bytes returns the Program bytecode. OBS: This is not a copy. +func (p *Program) Bytes() []byte { + return p.code +} + +// SetBytes sets the Program bytecode. The combination of Bytes and SetBytes means +// that external callers can implement missing functionality: +// +// ... +// prog.Push(1) +// code := prog.Bytes() +// manipulate(code) +// prog.SetBytes(code) +func (p *Program) SetBytes(code []byte) { + p.code = code +} + +// Hex returns the Program bytecode as a hex string. +func (p *Program) Hex() string { + return fmt.Sprintf("%02x", p.Bytes()) +} + +// Op appends the given opcode(s). +func (p *Program) Op(ops ...vm.OpCode) *Program { + for _, op := range ops { + p.add(byte(op)) + } + return p +} + +// Push creates a PUSHX instruction with the data provided. If zero is being pushed, +// PUSH0 will be avoided in favour of [PUSH1 0], to ensure backwards compatibility. +func (p *Program) Push(val any) *Program { + switch v := val.(type) { + case int: + p.doPush(new(uint256.Int).SetUint64(uint64(v))) + case uint64: + p.doPush(new(uint256.Int).SetUint64(v)) + case uint32: + p.doPush(new(uint256.Int).SetUint64(uint64(v))) + case uint16: + p.doPush(new(uint256.Int).SetUint64(uint64(v))) + case *big.Int: + p.doPush(uint256.MustFromBig(v)) + case *uint256.Int: + p.doPush(v) + case uint256.Int: + p.doPush(&v) + case []byte: + p.doPush(new(uint256.Int).SetBytes(v)) + case byte: + p.doPush(new(uint256.Int).SetUint64(uint64(v))) + case interface{ Bytes() []byte }: + // Here, we jump through some hoops in order to avoid depending on + // go-ethereum types.Address and common.Hash, and instead use the + // interface. This works on both values and pointers! + p.doPush(new(uint256.Int).SetBytes(v.Bytes())) + case nil: + p.doPush(nil) + default: + panic(fmt.Sprintf("unsupported type %T", v)) + } + return p +} + +// Push0 implements PUSH0 (0x5f). +func (p *Program) Push0() *Program { + return p.Op(vm.PUSH0) +} + +// ExtcodeCopy performs an extcodecopy invocation. +func (p *Program) ExtcodeCopy(address, memOffset, codeOffset, length any) *Program { + p.Push(length) + p.Push(codeOffset) + p.Push(memOffset) + p.Push(address) + return p.Op(vm.EXTCODECOPY) +} + +// Call is a convenience function to make a call. If 'gas' is nil, the opcode GAS will +// be used to provide all gas. +func (p *Program) Call(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { + if outOffset == outSize && inSize == outSize && inOffset == outSize && value == outSize { + p.Push(outSize).Op(vm.DUP1, vm.DUP1, vm.DUP1, vm.DUP1) + } else { + p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset).Push(value) + } + p.Push(address) + if gas == nil { + p.Op(vm.GAS) + } else { + p.doPush(gas) + } + return p.Op(vm.CALL) +} + +// DelegateCall is a convenience function to make a delegatecall. If 'gas' is nil, the opcode GAS will +// be used to provide all gas. +func (p *Program) DelegateCall(gas *uint256.Int, address, inOffset, inSize, outOffset, outSize any) *Program { + if outOffset == outSize && inSize == outSize && inOffset == outSize { + p.Push(outSize).Op(vm.DUP1, vm.DUP1, vm.DUP1) + } else { + p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset) + } + p.Push(address) + if gas == nil { + p.Op(vm.GAS) + } else { + p.doPush(gas) + } + return p.Op(vm.DELEGATECALL) +} + +// StaticCall is a convenience function to make a staticcall. If 'gas' is nil, the opcode GAS will +// be used to provide all gas. +func (p *Program) StaticCall(gas *uint256.Int, address, inOffset, inSize, outOffset, outSize any) *Program { + if outOffset == outSize && inSize == outSize && inOffset == outSize { + p.Push(outSize).Op(vm.DUP1, vm.DUP1, vm.DUP1) + } else { + p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset) + } + p.Push(address) + if gas == nil { + p.Op(vm.GAS) + } else { + p.doPush(gas) + } + return p.Op(vm.STATICCALL) +} + +// StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will +// be used to provide all gas. +func (p *Program) CallCode(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { + if outOffset == outSize && inSize == outSize && inOffset == outSize { + p.Push(outSize).Op(vm.DUP1, vm.DUP1, vm.DUP1) + } else { + p.Push(outSize).Push(outOffset).Push(inSize).Push(inOffset) + } + p.Push(value) + p.Push(address) + if gas == nil { + p.Op(vm.GAS) + } else { + p.doPush(gas) + } + return p.Op(vm.CALLCODE) +} + +// Label returns the PC (of the next instruction). +func (p *Program) Label() uint64 { + return uint64(len(p.code)) +} + +// Jumpdest adds a JUMPDEST op, and returns the PC of that instruction. +func (p *Program) Jumpdest() (*Program, uint64) { + here := p.Label() + p.Op(vm.JUMPDEST) + return p, here +} + +// Jump pushes the destination and adds a JUMP. +func (p *Program) Jump(loc any) *Program { + p.Push(loc) + p.Op(vm.JUMP) + return p +} + +// JumpIf implements JUMPI. +func (p *Program) JumpIf(loc any, condition any) *Program { + p.Push(condition) + p.Push(loc) + p.Op(vm.JUMPI) + return p +} + +// Size returns the current size of the bytecode. +func (p *Program) Size() int { + return len(p.code) +} + +// InputAddressToStack stores the input (calldata) to memory as address (20 bytes). +func (p *Program) InputAddressToStack(inputOffset uint32) *Program { + p.Push(inputOffset) + p.Op(vm.CALLDATALOAD) // Loads [n -> n + 32] of input data to stack top + mask, _ := big.NewInt(0).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) + p.Push(mask) // turn into address + return p.Op(vm.AND) +} + +// MStore stores the provided data (into the memory area starting at memStart). +func (p *Program) Mstore(data []byte, memStart uint32) *Program { + var idx = 0 + // We need to store it in chunks of 32 bytes + for ; idx+32 <= len(data); idx += 32 { + chunk := data[idx : idx+32] + // push the value + p.Push(chunk) + // push the memory index + p.Push(uint32(idx) + memStart) + p.Op(vm.MSTORE) + } + // Remainders become stored using MSTORE8 + for ; idx < len(data); idx++ { + b := data[idx] + // push the byte + p.Push(b) + p.Push(uint32(idx) + memStart) + p.Op(vm.MSTORE8) + } + return p +} + +// MstoreSmall stores the provided data, which must be smaller than 32 bytes, +// into the memory area starting at memStart. +// The data will be LHS zero-added to align on 32 bytes. +// For example, providing data 0x1122, it will do a PUSH2: +// PUSH2 0x1122, resulting in +// stack: 0x0000000000000000000000000000000000000000000000000000000000001122 +// followed by MSTORE(0,0) +// And thus, the resulting memory will be +// [ 0000000000000000000000000000000000000000000000000000000000001122 ] +func (p *Program) MstoreSmall(data []byte, memStart uint32) *Program { + if len(data) > 32 { + // For larger sizes, use Mstore instead. + panic("only <=32 byte data size supported") + } + if len(data) == 0 { + // Storing 0-length data smells of an error somewhere. + panic("data is zero length") + } + // push the value + p.Push(data) + // push the memory index + p.Push(memStart) + p.Op(vm.MSTORE) + return p +} + +// MemToStorage copies the given memory area into SSTORE slots, +// It expects data to be aligned to 32 byte, and does not zero out +// remainders if some data is not +// I.e, if given a 1-byte area, it will still copy the full 32 bytes to storage. +func (p *Program) MemToStorage(memStart, memSize, startSlot int) *Program { + // We need to store it in chunks of 32 bytes + for idx := memStart; idx < (memStart + memSize); idx += 32 { + dataStart := idx + // Mload the chunk + p.Push(dataStart) + p.Op(vm.MLOAD) + // Value is now on stack, + p.Push(startSlot) + p.Op(vm.SSTORE) + startSlot++ + } + return p +} + +// ReturnViaCodeCopy utilises CODECOPY to place the given data in the bytecode of +// p, loads into memory (offset 0) and returns the code. +// This is a typical "constructor". +// Note: since all indexing is calculated immediately, the preceding bytecode +// must not be expanded or shortened. +func (p *Program) ReturnViaCodeCopy(data []byte) *Program { + p.Push(len(data)) + // For convenience, we'll use PUSH2 for the offset. Then we know we can always + // fit, since code is limited to 0xc000 + p.Op(vm.PUSH2) + offsetPos := p.Size() // Need to update this position later on + p.Append([]byte{0, 0}) // Offset of the code to be copied + p.Push(0) // Offset in memory (destination) + p.Op(vm.CODECOPY) // Copy from code[offset:offset+len] to memory[0:] + p.Return(0, len(data)) // Return memory[0:len] + offset := p.Size() + p.Append(data) // And add the data + + // Now, go back and fix the offset + p.code[offsetPos] = byte(offset >> 8) + p.code[offsetPos+1] = byte(offset) + return p +} + +// Sstore stores the given byte array to the given slot. +// OBS! Does not verify that the value indeed fits into 32 bytes. +// If it does not, it will panic later on via doPush. +func (p *Program) Sstore(slot any, value any) *Program { + p.Push(value) + p.Push(slot) + return p.Op(vm.SSTORE) +} + +// Tstore stores the given byte array to the given t-slot. +// OBS! Does not verify that the value indeed fits into 32 bytes. +// If it does not, it will panic later on via doPush. +func (p *Program) Tstore(slot any, value any) *Program { + p.Push(value) + p.Push(slot) + return p.Op(vm.TSTORE) +} + +// Return implements RETURN +func (p *Program) Return(offset, len int) *Program { + p.Push(len) + p.Push(offset) + return p.Op(vm.RETURN) +} + +// ReturnData loads the given data into memory, and does a return with it +func (p *Program) ReturnData(data []byte) *Program { + p.Mstore(data, 0) + return p.Return(0, len(data)) +} + +// Create2 uses create2 to construct a contract with the given bytecode. +// This operation leaves either '0' or address on the stack. +func (p *Program) Create2(code []byte, salt any) *Program { + var ( + value = 0 + offset = 0 + size = len(code) + ) + // Load the code into mem + p.Mstore(code, 0) + // Create it + return p.Push(salt). + Push(size). + Push(offset). + Push(value). + Op(vm.CREATE2) + // On the stack now, is either + // - zero: in case of failure, OR + // - address: in case of success +} + +// Create2ThenCall calls create2 with the given initcode and salt, and then calls +// into the created contract (or calls into zero, if the creation failed). +func (p *Program) Create2ThenCall(code []byte, salt any) *Program { + p.Create2(code, salt) + // If there happen to be a zero on the stack, it doesn't matter, we're + // not sending any value anyway + p.Push(0).Push(0) // mem out + p.Push(0).Push(0) // mem in + p.Push(0) // value + p.Op(vm.DUP6) // address + p.Op(vm.GAS) + p.Op(vm.CALL) + p.Op(vm.POP) // pop the retval + return p.Op(vm.POP) // pop the address +} + +// Selfdestruct pushes beneficiary and invokes selfdestruct. +func (p *Program) Selfdestruct(beneficiary any) *Program { + p.Push(beneficiary) + return p.Op(vm.SELFDESTRUCT) +} diff --git a/core/vm/program/program_test.go b/core/vm/program/program_test.go new file mode 100644 index 000000000..0b3421006 --- /dev/null +++ b/core/vm/program/program_test.go @@ -0,0 +1,311 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The 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. +// +// This 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 goevmlab library. If not, see . + +package program + +import ( + "bytes" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" +) + +func TestPush(t *testing.T) { + tests := []struct { + input interface{} + expected string + }{ + // native ints + {0, "6000"}, + {0xfff, "610fff"}, + {nil, "6000"}, + {uint8(1), "6001"}, + {uint16(1), "6001"}, + {uint32(1), "6001"}, + {uint64(1), "6001"}, + // bigints + {big.NewInt(0), "6000"}, + {big.NewInt(1), "6001"}, + {big.NewInt(0xfff), "610fff"}, + // uint256 + {uint256.NewInt(1), "6001"}, + {uint256.Int{1, 0, 0, 0}, "6001"}, + // Addresses + {common.HexToAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), "73deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"}, + {&common.Address{}, "6000"}, + } + for i, tc := range tests { + have := New().Push(tc.input).Hex() + if have != tc.expected { + t.Errorf("test %d: got %v expected %v", i, have, tc.expected) + } + } +} + +func TestCall(t *testing.T) { + { // Nil gas + have := New().Call(nil, common.HexToAddress("0x1337"), big.NewInt(1), 1, 2, 3, 4).Hex() + want := "600460036002600160016113375af1" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { // Non nil gas + have := New().Call(uint256.NewInt(0xffff), common.HexToAddress("0x1337"), big.NewInt(1), 1, 2, 3, 4).Hex() + want := "6004600360026001600161133761fffff1" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } +} + +func TestMstore(t *testing.T) { + { + have := New().Mstore(common.FromHex("0xaabb"), 0).Hex() + want := "60aa60005360bb600153" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { // store at offset + have := New().Mstore(common.FromHex("0xaabb"), 3).Hex() + want := "60aa60035360bb600453" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { // 34 bytes + data := common.FromHex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFF") + + have := New().Mstore(data, 0).Hex() + want := "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260ff60205360ff602153" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } +} + +func TestMemToStorage(t *testing.T) { + have := New().MemToStorage(0, 33, 1).Hex() + want := "600051600155602051600255" + if have != want { + t.Errorf("have %v want %v", have, want) + } +} + +func TestSstore(t *testing.T) { + have := New().Sstore(0x1337, []byte("1234")).Hex() + want := "633132333461133755" + if have != want { + t.Errorf("have %v want %v", have, want) + } +} + +func TestReturnData(t *testing.T) { + { + have := New().ReturnData([]byte{0xFF}).Hex() + want := "60ff60005360016000f3" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { + // 32 bytes + data := common.FromHex("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") + have := New().ReturnData(data).Hex() + want := "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { // ReturnViaCodeCopy + data := common.FromHex("0x6001") + have := New().Append([]byte{0x5b, 0x5b, 0x5b}).ReturnViaCodeCopy(data).Hex() + want := "5b5b5b600261001060003960026000f36001" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } + { // ReturnViaCodeCopy larger code + data := common.FromHex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3") + have := New().Append([]byte{0x5b, 0x5b, 0x5b}).ReturnViaCodeCopy(data).Hex() + want := "5b5b5b602961001060003960296000f37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f3" + if have != want { + t.Errorf("have %v want %v", have, want) + } + } +} + +func TestCreateAndCall(t *testing.T) { + // A constructor that stores a slot + ctor := New().Sstore(0, big.NewInt(5)) + + // A runtime bytecode which reads the slot and returns + deployed := New() + deployed.Push(0).Op(vm.SLOAD) // [value] in stack + deployed.Push(0) // [value, 0] + deployed.Op(vm.MSTORE) + deployed.Return(0, 32) + + // Pack them + ctor.ReturnData(deployed.Bytes()) + // Verify constructor + runtime code + { + want := "6005600055606060005360006001536054600253606060035360006004536052600553606060065360206007536060600853600060095360f3600a53600b6000f3" + if got := ctor.Hex(); got != want { + t.Fatalf("1: got %v expected %v", got, want) + } + } +} + +func TestCreate2Call(t *testing.T) { + // Some runtime code + runtime := New().Op(vm.ADDRESS, vm.SELFDESTRUCT).Bytes() + want := common.FromHex("0x30ff") + if !bytes.Equal(want, runtime) { + t.Fatalf("runtime code error\nwant: %x\nhave: %x\n", want, runtime) + } + // A constructor returning the runtime code + initcode := New().ReturnData(runtime).Bytes() + want = common.FromHex("603060005360ff60015360026000f3") + if !bytes.Equal(want, initcode) { + t.Fatalf("initcode error\nwant: %x\nhave: %x\n", want, initcode) + } + // A factory invoking the constructor + outer := New().Create2ThenCall(initcode, nil).Bytes() + want = common.FromHex("60606000536030600153606060025360006003536053600453606060055360ff6006536060600753600160085360536009536060600a536002600b536060600c536000600d5360f3600e536000600f60006000f560006000600060006000855af15050") + if !bytes.Equal(want, outer) { + t.Fatalf("factory error\nwant: %x\nhave: %x\n", want, outer) + } +} + +func TestGenerator(t *testing.T) { + for i, tc := range []struct { + want []byte + haveFn func() []byte + }{ + { // CREATE + want: []byte{ + // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) + byte(vm.PUSH5), + // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + // length, offset, value + byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, + byte(vm.CREATE), + byte(vm.POP), + }, + haveFn: func() []byte { + initcode := New().Return(0, 0).Bytes() + return New().MstoreSmall(initcode, 0). + Push(len(initcode)). // length + Push(32 - len(initcode)). // offset + Push(0). // value + Op(vm.CREATE). + Op(vm.POP).Bytes() + }, + }, + { // CREATE2 + want: []byte{ + // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) + byte(vm.PUSH5), + // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) + byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + // salt, length, offset, value + byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, + byte(vm.CREATE2), + byte(vm.POP), + }, + haveFn: func() []byte { + initcode := New().Return(0, 0).Bytes() + return New().MstoreSmall(initcode, 0). + Push(1). // salt + Push(len(initcode)). // length + Push(32 - len(initcode)). // offset + Push(0). // value + Op(vm.CREATE2). + Op(vm.POP).Bytes() + }, + }, + { // CALL + want: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.DUP1), // value + byte(vm.PUSH1), 0xbb, //address + byte(vm.GAS), // gas + byte(vm.CALL), + byte(vm.POP), + }, + haveFn: func() []byte { + return New().Call(nil, 0xbb, 0, 0, 0, 0, 0).Op(vm.POP).Bytes() + }, + }, + { // CALLCODE + want: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0, // value + byte(vm.PUSH1), 0xcc, //address + byte(vm.GAS), // gas + byte(vm.CALLCODE), + byte(vm.POP), + }, + haveFn: func() []byte { + return New().CallCode(nil, 0xcc, 0, 0, 0, 0, 0).Op(vm.POP).Bytes() + }, + }, + { // STATICCALL + want: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xdd, //address + byte(vm.GAS), // gas + byte(vm.STATICCALL), + byte(vm.POP), + }, + haveFn: func() []byte { + return New().StaticCall(nil, 0xdd, 0, 0, 0, 0).Op(vm.POP).Bytes() + }, + }, + { // DELEGATECALL + want: []byte{ + // outsize, outoffset, insize, inoffset + byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xee, //address + byte(vm.GAS), // gas + byte(vm.DELEGATECALL), + byte(vm.POP), + }, + haveFn: func() []byte { + return New().DelegateCall(nil, 0xee, 0, 0, 0, 0).Op(vm.POP).Bytes() + }, + }, + } { + if have := tc.haveFn(); !bytes.Equal(have, tc.want) { + t.Fatalf("test %d error\nhave: %x\nwant: %x\n", i, have, tc.want) + } + } +} diff --git a/core/vm/program/readme.md b/core/vm/program/readme.md new file mode 100644 index 000000000..0e4a54d8f --- /dev/null +++ b/core/vm/program/readme.md @@ -0,0 +1,30 @@ +### What is this + +In many cases, we have a need to create somewhat nontrivial bytecode, for testing various +quirks related to state transition or evm execution. + +For example, we want to have a `CREATE2`- op create a contract, which is then invoked, and when invoked does a selfdestruct-to-self. + +It is overkill to go full solidity, but it is also a bit tricky do assemble this by concatenating bytes. + +This utility takes an approach from [goevmlab](https://github.com/holiman/goevmlab/) where it has been used for several years, +a go-lang utility to assemble evm bytecode. + +Using this utility, the case above can be expressed as: +```golang + // Some runtime code + runtime := program.New().Ops(vm.ADDRESS, vm.SELFDESTRUCT).Bytecode() + // A constructor returning the runtime code + initcode := program.New().ReturnData(runtime).Bytecode() + // A factory invoking the constructor + outer := program.New().Create2AndCall(initcode, nil).Bytecode() +``` + +### Warning + +This package is a utility for testing, _not_ for production. As such: + +- There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning +- There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV. +- There are no stability-guarantees. The utility will `panic` if the inputs do not align / make sense. + diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 97234368e..7d1345a57 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/vm/program" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/params" @@ -436,110 +437,46 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode // BenchmarkSimpleLoop test a pretty simple loop which loops until OOG // 55 ms func BenchmarkSimpleLoop(b *testing.B) { - staticCallIdentity := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.DUP1), // out insize - byte(vm.DUP1), // in offset - byte(vm.PUSH1), 0x4, // address of identity - byte(vm.GAS), // gas - byte(vm.STATICCALL), - byte(vm.POP), // pop return value - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - - callIdentity := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.DUP1), // out insize - byte(vm.DUP1), // in offset - byte(vm.DUP1), // value - byte(vm.PUSH1), 0x4, // address of identity - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), // pop return value - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - - callInexistant := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.DUP1), // out insize - byte(vm.DUP1), // in offset - byte(vm.DUP1), // value - byte(vm.PUSH1), 0xff, // address of existing contract - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), // pop return value - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - - callEOA := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.DUP1), // out insize - byte(vm.DUP1), // in offset - byte(vm.DUP1), // value - byte(vm.PUSH1), 0xE0, // address of EOA - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), // pop return value - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - - loopingCode := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.DUP1), // out insize - byte(vm.DUP1), // in offset - byte(vm.PUSH1), 0x4, // address of identity - byte(vm.GAS), // gas - - byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), byte(vm.POP), - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - - loopingCode2 := []byte{ - byte(vm.JUMPDEST), // [ count ] - // push args for the call - byte(vm.PUSH4), 1, 2, 3, 4, - byte(vm.PUSH5), 1, 2, 3, 4, 5, - - byte(vm.POP), byte(vm.POP), - byte(vm.PUSH6), 0, 0, 0, 0, 0, 0, // jumpdestination - byte(vm.JUMP), - } - - callRevertingContractWithInput := []byte{ - byte(vm.JUMPDEST), // - // push args for the call - byte(vm.PUSH1), 0, // out size - byte(vm.DUP1), // out offset - byte(vm.PUSH1), 0x20, // in size - byte(vm.PUSH1), 0x00, // in offset - byte(vm.PUSH1), 0x00, // value - byte(vm.PUSH1), 0xEE, // address of reverting contract - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), // pop return value - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } + p, lbl := program.New().Jumpdest() + // Call identity, and pop return value + staticCallIdentity := p. + StaticCall(nil, 0x4, 0, 0, 0, 0). + Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label + + p, lbl = program.New().Jumpdest() + callIdentity := p. + Call(nil, 0x4, 0, 0, 0, 0, 0). + Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label + + p, lbl = program.New().Jumpdest() + callInexistant := p. + Call(nil, 0xff, 0, 0, 0, 0, 0). + Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label + + p, lbl = program.New().Jumpdest() + callEOA := p. + Call(nil, 0xE0, 0, 0, 0, 0, 0). // call addr of EOA + Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label + + p, lbl = program.New().Jumpdest() + // Push as if we were making call, then pop it off again, and loop + loopingCode := p.Push(0). + Op(vm.DUP1, vm.DUP1, vm.DUP1). + Push(0x4). + Op(vm.GAS, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP). + Jump(lbl).Bytes() + + p, lbl = program.New().Jumpdest() + loopingCode2 := p. + Push(0x01020304).Push(uint64(0x0102030405)). + Op(vm.POP, vm.POP). + Op(vm.PUSH6).Append(make([]byte, 6)).Op(vm.JUMP). // Jumpdest zero expressed in 6 bytes + Jump(lbl).Bytes() + + p, lbl = program.New().Jumpdest() + callRevertingContractWithInput := p. + Call(nil, 0xee, 0, 0, 0x20, 0x0, 0x0). + Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label //tracer := logger.NewJSONLogger(nil, os.Stdout) //Execute(loopingCode, nil, &Config{ @@ -778,104 +715,49 @@ func TestRuntimeJSTracer(t *testing.T) { this.exits++; this.gasUsed = res.getGasUsed(); }}`} + initcode := program.New().Return(0, 0).Bytes() tests := []struct { code []byte // One result per tracer results []string }{ - { - // CREATE - code: []byte{ - // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) - byte(vm.PUSH5), - // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - // length, offset, value - byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, - byte(vm.CREATE), - byte(vm.POP), - }, + { // CREATE + code: program.New().MstoreSmall(initcode, 0). + Push(len(initcode)). // length + Push(32 - len(initcode)). // offset + Push(0). // value + Op(vm.CREATE). + Op(vm.POP).Bytes(), results: []string{`"1,1,952853,6,12"`, `"1,1,952853,6,0"`}, }, - { - // CREATE2 - code: []byte{ - // Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes) - byte(vm.PUSH5), - // Init code: PUSH1 0, PUSH1 0, RETURN (3 steps) - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN), - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - // salt, length, offset, value - byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0, - byte(vm.CREATE2), - byte(vm.POP), - }, + { // CREATE2 + code: program.New().MstoreSmall(initcode, 0). + Push(1). // salt + Push(len(initcode)). // length + Push(32 - len(initcode)). // offset + Push(0). // value + Op(vm.CREATE2). + Op(vm.POP).Bytes(), results: []string{`"1,1,952844,6,13"`, `"1,1,952844,6,0"`}, }, - { - // CALL - code: []byte{ - // outsize, outoffset, insize, inoffset - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0, // value - byte(vm.PUSH1), 0xbb, //address - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), - }, + { // CALL + code: program.New().Call(nil, 0xbb, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(), results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`}, }, - { - // CALLCODE - code: []byte{ - // outsize, outoffset, insize, inoffset - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0, // value - byte(vm.PUSH1), 0xcc, //address - byte(vm.GAS), // gas - byte(vm.CALLCODE), - byte(vm.POP), - }, + { // CALLCODE + code: program.New().CallCode(nil, 0xcc, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(), results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`}, }, - { - // STATICCALL - code: []byte{ - // outsize, outoffset, insize, inoffset - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0xdd, //address - byte(vm.GAS), // gas - byte(vm.STATICCALL), - byte(vm.POP), - }, + { // STATICCALL + code: program.New().StaticCall(nil, 0xdd, 0, 0, 0, 0).Op(vm.POP).Bytes(), results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`}, }, - { - // DELEGATECALL - code: []byte{ - // outsize, outoffset, insize, inoffset - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0xee, //address - byte(vm.GAS), // gas - byte(vm.DELEGATECALL), - byte(vm.POP), - }, + { // DELEGATECALL + code: program.New().DelegateCall(nil, 0xee, 0, 0, 0, 0).Op(vm.POP).Bytes(), results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`}, }, - { - // CALL self-destructing contract - code: []byte{ - // outsize, outoffset, insize, inoffset - byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0, // value - byte(vm.PUSH1), 0xff, //address - byte(vm.GAS), // gas - byte(vm.CALL), - byte(vm.POP), - }, + { // CALL self-destructing contract + code: program.New().Call(nil, 0xff, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(), results: []string{`"2,2,0,5003,12"`, `"2,2,0,5003,0"`}, }, } @@ -958,16 +840,8 @@ func TestJSTracerCreateTx(t *testing.T) { func BenchmarkTracerStepVsCallFrame(b *testing.B) { // Simply pushes and pops some values in a loop - code := []byte{ - byte(vm.JUMPDEST), - byte(vm.PUSH1), 0, - byte(vm.PUSH1), 0, - byte(vm.POP), - byte(vm.POP), - byte(vm.PUSH1), 0, // jumpdestination - byte(vm.JUMP), - } - + p, lbl := program.New().Jumpdest() + code := p.Push(0).Push(0).Op(vm.POP, vm.POP).Jump(lbl).Bytes() stepTracer := ` { step: function() {}, From 662f1d253ff1c62cbbd046627d64227d450fce3a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 20 Nov 2024 19:35:52 +0800 Subject: [PATCH 002/354] core, eth, internal, cmd: rework EVM constructor (#30745) This pull request refactors the EVM constructor by removing the TxContext parameter. The EVM object is frequently overused. Ideally, only a single EVM instance should be created and reused throughout the entire state transition of a block, with the transaction context switched as needed by calling evm.SetTxContext. Unfortunately, in some parts of the code, the EVM object is repeatedly created, resulting in unnecessary complexity. This pull request is the first step towards gradually improving and simplifying this setup. --------- Co-authored-by: Martin Holst Swende --- cmd/evm/internal/t8ntool/execution.go | 22 ++- core/chain_makers.go | 20 +-- core/state_prefetcher.go | 8 +- core/state_processor.go | 39 +++--- core/verkle_witness_test.go | 2 +- core/vm/evm.go | 21 +-- core/vm/gas_table_test.go | 10 +- core/vm/instructions_test.go | 128 ++++++++---------- core/vm/interpreter_test.go | 2 +- core/vm/runtime/env.go | 4 +- eth/api_backend.go | 5 +- eth/gasestimator/gasestimator.go | 3 +- eth/state_accessor.go | 24 ++-- eth/tracers/api.go | 57 ++++---- eth/tracers/api_test.go | 13 +- .../internal/tracetest/calltrace_test.go | 19 ++- .../internal/tracetest/flat_calltrace_test.go | 3 +- .../internal/tracetest/prestate_test.go | 3 +- eth/tracers/js/tracer_test.go | 17 ++- eth/tracers/logger/logger_test.go | 6 +- eth/tracers/tracers_test.go | 3 +- internal/ethapi/api.go | 6 +- internal/ethapi/api_test.go | 5 +- internal/ethapi/backend.go | 2 +- internal/ethapi/simulate.go | 4 +- internal/ethapi/transaction_args_test.go | 2 +- miner/worker.go | 50 +++---- tests/state_test.go | 3 +- tests/state_test_util.go | 3 +- 29 files changed, 235 insertions(+), 249 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 22f500efd..a80e4480e 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -203,23 +203,18 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { misc.ApplyDAOHardFork(statedb) } - var evm *vm.EVM + evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig) if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { - evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { var ( prevNumber = pre.Env.Number - 1 prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] - evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) ) core.ProcessParentBlockHash(prevHash, evm, statedb) } if chainConfig.DBFT != nil { - if evm == nil { - evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) - } err := core.ProcessOnPersist(evm, statedb) if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process OnPersist: %v", err)) @@ -259,8 +254,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if err != nil { return nil, nil, nil, err } + // TODO (rjl493456442) it's a bit weird to reset the tracer in the + // middle of block execution, please improve it somehow. if tracer != nil { - vmConfig.Tracer = tracer.Hooks + evm.SetTracer(tracer.Hooks) } statedb.SetTxContext(tx.Hash(), txIndex) @@ -269,12 +266,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, snapshot = statedb.Snapshot() prevGas = gaspool.Gas() ) - evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) - if tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) + + evm.SetTxContext(txContext) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { statedb.RevertToSnapshot(snapshot) @@ -388,12 +385,11 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) } requests = append(requests, depositRequests) - // create EVM for system calls - vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + // EIP-7002 withdrawals - requests = append(requests, core.ProcessWithdrawalQueue(vmenv, statedb)) + requests = append(requests, core.ProcessWithdrawalQueue(evm, statedb)) // EIP-7251 consolidations - requests = append(requests, core.ProcessConsolidationQueue(vmenv, statedb)) + requests = append(requests, core.ProcessConsolidationQueue(evm, statedb)) } // Commit block diff --git a/core/chain_makers.go b/core/chain_makers.go index 586979e77..07448abc3 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -100,9 +100,9 @@ func (b *BlockGen) SetParentBeaconRoot(root common.Hash) { b.header.ParentBeaconRoot = &root var ( blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) - vmenv = vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.cm.config, vm.Config{}) + evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{}) ) - ProcessBeaconBlockRoot(root, vmenv, b.statedb) + ProcessBeaconBlockRoot(root, evm, b.statedb) } // addTx adds a transaction to the generated block. If no coinbase has @@ -116,8 +116,12 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti if b.gasPool == nil { b.SetCoinbase(common.Address{}) } + var ( + blockContext = NewEVMBlockContext(b.header, bc, &b.header.Coinbase) + evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig) + ) b.statedb.SetTxContext(tx.Hash(), len(b.txs)) - receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig) + receipt, err := ApplyTransaction(b.cm.config, evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed) if err != nil { panic(err) } @@ -360,12 +364,12 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse requests = append(requests, depositRequests) // create EVM for system calls blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{}) + evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb) + withdrawalRequests := ProcessWithdrawalQueue(evm, statedb) requests = append(requests, withdrawalRequests) // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(vmenv, statedb) + consolidationRequests := ProcessConsolidationQueue(evm, statedb) requests = append(requests, consolidationRequests) } if requests != nil { @@ -466,8 +470,8 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine if config.IsPrague(b.header.Number, b.header.Time) { // EIP-2935 blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{}) - ProcessParentBlockHash(b.header.ParentHash, vmenv, statedb) + evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) + ProcessParentBlockHash(b.header.ParentHash, evm, statedb) } // Execute any user modifications to the block. diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 31405fa07..3b987bb28 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -49,7 +49,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) blockContext = NewEVMBlockContext(header, p.chain, nil) - evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) + evm = vm.NewEVM(blockContext, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number, header.Time) ) // Iterate over and process the individual transactions @@ -65,7 +65,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c return // Also invalid block, bail out } statedb.SetTxContext(tx.Hash(), i) - if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil { + if err := precacheTransaction(msg, gaspool, evm); err != nil { return // Ugh, something went horribly wrong, bail out } // If we're pre-byzantium, pre-load trie nodes for the intermediate root @@ -82,9 +82,9 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c // precacheTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. The goal is not to execute // the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error { +func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error { // Update the evm with the new transaction context. - evm.Reset(NewEVMTxContext(msg), statedb) + evm.SetTxContext(NewEVMTxContext(msg)) // Add addresses to access list if applicable _, err := ApplyMessage(evm, msg, gaspool) return err diff --git a/core/state_processor.go b/core/state_processor.go index 57a267ec8..92cda3672 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -78,21 +78,21 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ) // Apply pre-execution system calls. - context = NewEVMBlockContext(header, p.chain, nil) - - vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) var tracingStateDB = vm.StateDB(statedb) if hooks := cfg.Tracer; hooks != nil { tracingStateDB = state.NewHookedState(statedb, hooks) } + context = NewEVMBlockContext(header, p.chain, nil) + evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - ProcessBeaconBlockRoot(*beaconRoot, vmenv, tracingStateDB) + ProcessBeaconBlockRoot(*beaconRoot, evm, tracingStateDB) } if p.config.IsPrague(block.Number(), block.Time()) { - ProcessParentBlockHash(block.ParentHash(), vmenv, tracingStateDB) + ProcessParentBlockHash(block.ParentHash(), evm, tracingStateDB) } if p.config.DBFT != nil { - err := ProcessOnPersist(vmenv, tracingStateDB) + err := ProcessOnPersist(evm, tracingStateDB) if err != nil { return nil, fmt.Errorf("could not apply OnPersist [%v]: %w", block.Hash().Hex(), err) } @@ -114,7 +114,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } statedb.SetTxContext(tx.Hash(), i) - receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, evm) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -131,10 +131,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } requests = append(requests, depositRequests) // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(vmenv, tracingStateDB) + withdrawalRequests := ProcessWithdrawalQueue(evm, tracingStateDB) requests = append(requests, withdrawalRequests) // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(vmenv, tracingStateDB) + consolidationRequests := ProcessConsolidationQueue(evm, tracingStateDB) requests = append(requests, consolidationRequests) } @@ -153,9 +153,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // and uses the input parameters for its environment similar to ApplyTransaction. However, // this method takes an already created EVM instance as input. func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { - var tracingStateDB = vm.StateDB(statedb) if hooks := evm.Config.Tracer; hooks != nil { - tracingStateDB = state.NewHookedState(statedb, hooks) if hooks.OnTxStart != nil { hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) } @@ -166,7 +164,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) - evm.Reset(txContext, tracingStateDB) + evm.SetTxContext(txContext) // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) @@ -177,7 +175,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo // Update the state with pending changes. var root []byte if config.IsByzantium(blockNumber) { - tracingStateDB.Finalise(true) + evm.StateDB.Finalise(true) } else { root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes() } @@ -228,16 +226,13 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { +func ApplyTransaction(config *params.ChainConfig, evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee) if err != nil { return nil, err } // Create a new context to be used in the EVM environment - blockContext := NewEVMBlockContext(header, bc, author) - txContext := NewEVMTxContext(msg) - vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg) - return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) + return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm) } // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root @@ -260,7 +255,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb vm.St To: ¶ms.BeaconRootsAddress, Data: beaconRoot[:], } - vmenv.Reset(NewEVMTxContext(msg), statedb) + vmenv.SetTxContext(NewEVMTxContext(msg)) statedb.AddAddressToAccessList(params.BeaconRootsAddress) _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) @@ -286,7 +281,7 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.Stat To: ¶ms.HistoryStorageAddress, Data: prevHash.Bytes(), } - vmenv.Reset(NewEVMTxContext(msg), statedb) + vmenv.SetTxContext(NewEVMTxContext(msg)) statedb.AddAddressToAccessList(params.HistoryStorageAddress) _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) @@ -322,7 +317,7 @@ func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType by GasTipCap: common.Big0, To: &addr, } - vmenv.Reset(NewEVMTxContext(msg), statedb) + vmenv.SetTxContext(NewEVMTxContext(msg)) statedb.AddAddressToAccessList(addr) ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) @@ -410,7 +405,7 @@ func applyLocalSystemCall(to common.Address, data []byte, vmenv *vm.EVM, statedb To: &to, Data: data, } - vmenv.Reset(NewEVMTxContext(msg), statedb) + vmenv.SetTxContext(NewEVMTxContext(msg)) statedb.AddAddressToAccessList(to) _, _, err := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) if err != nil { diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 43c5d84a1..5b3fe89f5 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -225,7 +225,7 @@ func TestProcessParentBlockHash(t *testing.T) { for i := 1; i <= num; i++ { header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} vmContext := NewEVMBlockContext(header, nil, new(common.Address)) - evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, params.MergedTestChainConfig, vm.Config{}) + evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{}) ProcessParentBlockHash(header.ParentHash, evm, statedb) } // Read block hashes for block 0 .. num-1 diff --git a/core/vm/evm.go b/core/vm/evm.go index 0593a32a3..34e5fa766 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -116,12 +116,13 @@ type EVM struct { precompiles map[common.Address]PrecompiledContract } -// NewEVM returns a new EVM. The returned EVM is not thread safe and should -// only ever be used *once*. -func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +// NewEVM constructs an EVM instance with the supplied block context, state +// database and several configs. It meant to be used throughout the entire +// state transition of a block, with the transaction context switched as +// needed by calling evm.SetTxContext. +func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ Context: blockCtx, - TxContext: txCtx, StateDB: statedb, Config: config, chainConfig: chainConfig, @@ -132,6 +133,11 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig return evm } +// SetTracer sets the tracer for following state transition. +func (evm *EVM) SetTracer(tracer *tracing.Hooks) { + evm.Config.Tracer = tracer +} + // SetPrecompiles sets the precompiled contracts for the EVM. // This method is only used through RPC calls. // It is not thread-safe. @@ -139,14 +145,13 @@ func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) { evm.precompiles = precompiles } -// Reset resets the EVM with a new transaction context.Reset +// SetTxContext resets the EVM with a new transaction context. // This is not threadsafe and should only be done very cautiously. -func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { +func (evm *EVM) SetTxContext(txCtx TxContext) { if evm.chainRules.IsEIP4762 { - txCtx.AccessEvents = state.NewAccessEvents(statedb.PointCache()) + txCtx.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache()) } evm.TxContext = txCtx - evm.StateDB = statedb } // Cancel cancels any running EVM operation. This may be called concurrently and diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index babe9a5b6..be8688526 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -95,16 +95,16 @@ func TestEIP2200(t *testing.T) { CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {}, } - vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) + evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) - _, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) + _, gas, err := evm.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } if used := tt.gaspool - gas; used != tt.used { t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used) } - if refund := vmenv.StateDB.GetRefund(); refund != tt.refund { + if refund := evm.StateDB.GetRefund(); refund != tt.refund { t.Errorf("test %d: gas refund mismatch: have %v, want %v", i, refund, tt.refund) } } @@ -151,9 +151,9 @@ func TestCreateGas(t *testing.T) { config.ExtraEips = []int{3860} } - vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config) + evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config) var startGas = uint64(testGas) - ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(uint256.Int)) + ret, gas, err := evm.Call(AccountRef(common.Address{}), address, nil, startGas, new(uint256.Int)) if err != nil { return false } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index b8e62e1de..08f2b2bfe 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -104,10 +104,9 @@ func init() { func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - evmInterpreter = env.interpreter + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) for i, test := range tests { @@ -116,7 +115,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected)) stack.push(x) stack.push(y) - opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data)) } @@ -203,10 +202,9 @@ func TestSAR(t *testing.T) { func TestAddMod(t *testing.T) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - evmInterpreter = NewEVMInterpreter(env) - pc = uint64(0) + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) tests := []struct { x string @@ -231,7 +229,7 @@ func TestAddMod(t *testing.T) { stack.push(z) stack.push(y) stack.push(x) - opAddmod(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + opAddmod(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) actual := stack.pop() if actual.Cmp(expected) != 0 { t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual) @@ -247,10 +245,9 @@ func TestWriteExpectedValues(t *testing.T) { // getResult is a convenience function to generate the expected values getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - interpreter = env.interpreter + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) result := make([]TwoOperandTestcase, len(args)) for i, param := range args { @@ -258,7 +255,7 @@ func TestWriteExpectedValues(t *testing.T) { y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) stack.push(x) stack.push(y) - opFn(&pc, interpreter, &ScopeContext{nil, stack, nil}) + opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) actual := stack.pop() result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} } @@ -292,13 +289,10 @@ func TestJsonTestcases(t *testing.T) { func opBenchmark(bench *testing.B, op executionFunc, args ...string) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - scope = &ScopeContext{nil, stack, nil} - evmInterpreter = NewEVMInterpreter(env) + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + scope = &ScopeContext{nil, stack, nil} ) - - env.interpreter = evmInterpreter // convert args intArgs := make([]*uint256.Int, len(args)) for i, arg := range args { @@ -310,7 +304,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) { for _, arg := range intArgs { stack.push(arg) } - op(&pc, evmInterpreter, scope) + op(&pc, evm.interpreter, scope) stack.pop() } bench.StopTimer() @@ -533,25 +527,22 @@ func BenchmarkOpIsZero(b *testing.B) { func TestOpMstore(t *testing.T) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env) + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() ) - - env.interpreter = evmInterpreter mem.Resize(64) pc := uint64(0) v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" stack.push(new(uint256.Int).SetBytes(common.Hex2Bytes(v))) stack.push(new(uint256.Int)) - opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v { t.Fatalf("Mstore fail, got %v, expected %v", got, v) } stack.push(new(uint256.Int).SetUint64(0x1)) stack.push(new(uint256.Int)) - opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } @@ -559,13 +550,10 @@ func TestOpMstore(t *testing.T) { func BenchmarkOpMstore(bench *testing.B) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env) + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() ) - - env.interpreter = evmInterpreter mem.Resize(64) pc := uint64(0) memStart := new(uint256.Int) @@ -575,43 +563,41 @@ func BenchmarkOpMstore(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(value) stack.push(memStart) - opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + opMstore(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) } } func TestOpTstore(t *testing.T) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env) - caller = common.Address{} - to = common.Address{1} - contractRef = contractRef{caller} - contract = NewContract(contractRef, AccountRef(to), new(uint256.Int), 0) - scopeContext = ScopeContext{mem, stack, contract} - value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + evm = NewEVM(BlockContext{}, statedb, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + caller = common.Address{} + to = common.Address{1} + contractRef = contractRef{caller} + contract = NewContract(contractRef, AccountRef(to), new(uint256.Int), 0) + scopeContext = ScopeContext{mem, stack, contract} + value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") ) // Add a stateObject for the caller and the contract being called statedb.CreateAccount(caller) statedb.CreateAccount(to) - env.interpreter = evmInterpreter pc := uint64(0) // push the value to the stack stack.push(new(uint256.Int).SetBytes(value)) // push the location to the stack stack.push(new(uint256.Int)) - opTstore(&pc, evmInterpreter, &scopeContext) + opTstore(&pc, evm.interpreter, &scopeContext) // there should be no elements on the stack after TSTORE if stack.len() != 0 { t.Fatal("stack wrong size") } // push the location to the stack stack.push(new(uint256.Int)) - opTload(&pc, evmInterpreter, &scopeContext) + opTload(&pc, evm.interpreter, &scopeContext) // there should be one element on the stack after TLOAD if stack.len() != 1 { t.Fatal("stack wrong size") @@ -624,12 +610,10 @@ func TestOpTstore(t *testing.T) { func BenchmarkOpKeccak256(bench *testing.B) { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env) + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() ) - env.interpreter = evmInterpreter mem.Resize(32) pc := uint64(0) start := new(uint256.Int) @@ -638,7 +622,7 @@ func BenchmarkOpKeccak256(bench *testing.B) { for i := 0; i < bench.N; i++ { stack.push(uint256.NewInt(32)) stack.push(start) - opKeccak256(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + opKeccak256(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) } } @@ -728,12 +712,11 @@ func TestRandom(t *testing.T) { {name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})}, } { var ( - env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - evmInterpreter = env.interpreter + evm = NewEVM(BlockContext{Random: &tt.random}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) - opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + opRandom(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -769,13 +752,13 @@ func TestBlobHash(t *testing.T) { {name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil}, } { var ( - env = NewEVM(BlockContext{}, TxContext{BlobHashes: tt.hashes}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - evmInterpreter = env.interpreter + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) + evm.SetTxContext(TxContext{BlobHashes: tt.hashes}) stack.push(uint256.NewInt(tt.idx)) - opBlobHash(&pc, evmInterpreter, &ScopeContext{nil, stack, nil}) + opBlobHash(&pc, evm.interpreter, &ScopeContext{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data)) } @@ -872,10 +855,9 @@ func TestOpMCopy(t *testing.T) { }, } { var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - evmInterpreter = env.interpreter + evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) ) data := common.FromHex(strings.ReplaceAll(tc.pre, " ", "")) // Set pre @@ -906,7 +888,7 @@ func TestOpMCopy(t *testing.T) { } // and the dynamic cost var haveGas uint64 - if dynamicCost, err := gasMcopy(env, nil, stack, mem, memorySize); err != nil { + if dynamicCost, err := gasMcopy(evm, nil, stack, mem, memorySize); err != nil { t.Error(err) } else { haveGas = GasFastestStep + dynamicCost @@ -916,7 +898,7 @@ func TestOpMCopy(t *testing.T) { mem.Resize(memorySize) } // Do the copy - opMcopy(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) + opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, nil}) want := common.FromHex(strings.ReplaceAll(tc.want, " ", "")) if have := mem.store; !bytes.Equal(want, have) { t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have) diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index 7d4b2ddf3..cacad8f81 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -47,7 +47,7 @@ func TestLoopInterrupt(t *testing.T) { statedb.SetCode(address, common.Hex2Bytes(tt)) statedb.Finalise(true) - evm := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{}) + evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{}) errChannel := make(chan error) timeout := make(chan bool) diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 34335b8e9..e54041f7e 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -42,5 +42,7 @@ func NewEnv(cfg *Config) *vm.EVM { Random: cfg.Random, } - return vm.NewEVM(blockContext, txContext, cfg.State, cfg.ChainConfig, cfg.EVMConfig) + evm := vm.NewEVM(blockContext, cfg.State, cfg.ChainConfig, cfg.EVMConfig) + evm.SetTxContext(txContext) + return evm } diff --git a/eth/api_backend.go b/eth/api_backend.go index 850d4bf3d..98c1a1885 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -251,18 +251,17 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { +func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } - txContext := core.NewEVMTxContext(msg) var context vm.BlockContext if blockCtx != nil { context = *blockCtx } else { context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) } - return vm.NewEVM(context, txContext, state, b.ChainConfig(), *vmConfig) + return vm.NewEVM(context, state, b.ChainConfig(), *vmConfig) } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index d43057dda..5729f8427 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -230,7 +230,8 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 { evmContext.BlobBaseFee = new(big.Int) } - evm := vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) + evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) + evm.SetTxContext(msgContext) // Monitor the outer context and interrupt the EVM upon cancellation. To avoid // a dangling goroutine until the outer estimation finishes, create an internal // context for the lifetime of this method call. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index cb5a233a8..a91903024 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -235,16 +235,14 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, return nil, vm.BlockContext{}, nil, nil, err } // Insert parent beacon block root in the state as per EIP-4788. + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) + evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) - core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } // If prague hardfork, insert parent block hash in the state as per EIP-2935. if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { - context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) - core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil @@ -252,22 +250,22 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, // Recompute transactions up to the target index. signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time()) for idx, tx := range block.Transactions() { - // Assemble the transaction call message and return if the requested offset - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) if idx == txIndex { return tx, context, statedb, release, nil } + // Assemble the transaction call message and return if the requested offset + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txContext := core.NewEVMTxContext(msg) + evm.SetTxContext(txContext) + // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) statedb.SetTxContext(tx.Hash(), idx) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) } return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 03bb26dee..e73f2bb4d 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -378,16 +378,14 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed } // Insert block's parent beacon block root in the state // as per EIP-4788. + context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) + evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{}) if beaconRoot := next.BeaconRoot(); beaconRoot != nil { - context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } // Insert parent hash in history contract. if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { - context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb) + core.ProcessParentBlockHash(next.ParentHash(), evm, statedb) } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the @@ -537,12 +535,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) + evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { @@ -551,10 +549,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config var ( msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) - vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) + evm.SetTxContext(txContext) statedb.SetTxContext(tx.Hash(), i) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { + if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not // return the roots. Most likely, the caller already knows that a certain transaction fails to @@ -605,13 +603,12 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac defer release() blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { - vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) } // JS tracers have high overhead. In this case run a parallel @@ -695,6 +692,8 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // Feed the transactions into the tracers and return var failed error blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) + txloop: for i, tx := range txs { // Send the trace task over for execution @@ -709,14 +708,14 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) - vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { + evm.SetTxContext(core.NewEVMTxContext(msg)) + if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { failed = err break txloop } // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) } close(jobs) @@ -783,13 +782,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Note: This copies the config, to not screw up the main config chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } + evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } if chainConfig.IsPrague(block.Number(), block.Time()) { - vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution @@ -822,12 +820,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } } // Execute the transaction and flush any traces to disk - vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) + evm.SetTxContext(txContext) statedb.SetTxContext(tx.Hash(), i) if vmConf.Tracer.OnTxStart != nil { - vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } - vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if vmConf.Tracer.OnTxEnd != nil { vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) } @@ -843,7 +841,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) // If we've traced the transaction we were looking for, abort if tx.Hash() == txHash { @@ -1017,7 +1015,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } } // The actual TxContext will be created as part of ApplyTransactionWithEVM. - vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { @@ -1031,14 +1030,14 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { tracer.Stop(errors.New("execution timeout")) // Stop evm execution. Note cancellation is not necessarily immediate. - vmenv.Cancel() + evm.Cancel() } }() defer cancel() // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv) + _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm) if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index e717f5352..431a899c0 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -170,18 +170,19 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block } // Recompute transactions up to the target index. signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time()) + context := core.NewEVMBlockContext(block.Header(), b.chain, nil) + evm := vm.NewEVM(context, statedb, b.chainConfig, vm.Config{}) for idx, tx := range block.Transactions() { - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), b.chain, nil) if idx == txIndex { return tx, context, statedb, release, nil } - vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txContext := core.NewEVMTxContext(msg) + evm.SetTxContext(txContext) + if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } - statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) } return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index cb635e712..869558c32 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -132,7 +132,8 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { @@ -220,12 +221,15 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() + + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) + if err != nil { + b.Fatalf("failed to create call tracer: %v", err) + } + evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(txContext) + for i := 0; i < b.N; i++ { - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) - if err != nil { - b.Fatalf("failed to create call tracer: %v", err) - } - evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) snap := state.StateDB.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -372,7 +376,8 @@ func TestInternals(t *testing.T) { Origin: origin, GasPrice: tx.GasPrice(), } - evm := vm.NewEVM(context, txContext, logState, config, vm.Config{Tracer: tc.tracer.Hooks}) + evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks}) + evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 0ec3c367b..1dbdc7caa 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -98,7 +98,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index c6cf10a48..b8dec51db 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -106,7 +106,8 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index ed2789d70..54f628b5f 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -64,20 +64,21 @@ func testCtx() *vmContext { func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks}) + evm = vm.NewEVM(vmctx.blockCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = uint256.NewInt(0) contract = vm.NewContract(account{}, account{}, value, startGas) ) + evm.SetTxContext(vmctx.txCtx) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} if contractCode != nil { contract.Code = contractCode } - tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) - ret, err := env.Interpreter().Run(contract, []byte{}, false) + ret, err := evm.Interpreter().Run(contract, []byte{}, false) tracer.OnExit(0, ret, startGas-contract.Gas, err, true) // Rest gas assumes no refund tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) @@ -191,8 +192,9 @@ func TestHaltBetweenSteps(t *testing.T) { scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0), } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) - tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(1)}) + tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0)) tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) timeout := errors.New("stahp") @@ -214,8 +216,9 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) - tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) + evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) + evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(100)}) + tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0)) tracer.OnExit(0, nil, 0, nil, false) ret, err := tracer.GetResult() diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index fb1a0154e..e7799dde3 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -58,13 +58,13 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) co func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) + evm = vm.NewEVM(vm.BlockContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash - logger.OnTxStart(env.GetVMContext(), nil, common.Address{}) - _, err := env.Interpreter().Run(contract, []byte{}, false) + logger.OnTxStart(evm.GetVMContext(), nil, common.Address{}) + _, err := evm.Interpreter().Run(contract, []byte{}, false) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 31e14b911..72cc1bde2 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -89,7 +89,8 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) + evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) + evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7807ce121..c2b19827e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -940,10 +940,11 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { blockContext.BlobBaseFee = new(big.Int) } - evm := b.GetEVM(ctx, msg, state, header, vmConfig, blockContext) + evm := b.GetEVM(ctx, state, header, vmConfig, blockContext) if precompiles != nil { evm.SetPrecompiles(precompiles) } + evm.SetTxContext(core.NewEVMTxContext(msg)) res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp) // If an internal state error occurred, let that have precedence. Otherwise, // a "trie root missing" type of error will masquerade as e.g. "insufficient gas" @@ -1433,7 +1434,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} - vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil) + vmenv := b.GetEVM(ctx, statedb, header, &config, nil) // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). if msg.GasPrice.Sign() == 0 { @@ -1442,6 +1443,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { vmenv.Context.BlobBaseFee = new(big.Int) } + vmenv.SetTxContext(core.NewEVMTxContext(msg)) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index b6b844473..439468fad 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -576,16 +576,15 @@ func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { } return big.NewInt(1) } -func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM { +func (b testBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM { if vmConfig == nil { vmConfig = b.chain.GetVMConfig() } - txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, b.chain, nil) if blockContext != nil { context = *blockContext } - return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig) + return vm.NewEVM(context, state, b.chain.Config(), *vmConfig) } func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { panic("implement me") diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 6821d8482..5a045b6a7 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -70,7 +70,7 @@ type Backend interface { StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) Pending() (*types.Block, types.Receipts, *state.StateDB) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) - GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM + GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 81b4633d4..979de352f 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -185,12 +185,12 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, NoBaseFee: !sim.validate, Tracer: tracer.Hooks(), } - evm = vm.NewEVM(blockContext, vm.TxContext{GasPrice: new(big.Int)}, sim.state, sim.chainConfig, *vmConfig) ) var tracingStateDB = vm.StateDB(sim.state) if hooks := tracer.Hooks(); hooks != nil { tracingStateDB = state.NewHookedState(sim.state, hooks) } + evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig) // It is possible to override precompiles with EVM bytecode, or // move them to another address. if precompiles != nil { @@ -208,7 +208,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, tracer.reset(tx.Hash(), uint(i)) // EoA check is always skipped, even in validation mode. msg := call.ToMessage(header.BaseFee, !sim.validate, true) - evm.Reset(core.NewEVMTxContext(msg), tracingStateDB) + evm.SetTxContext(core.NewEVMTxContext(msg)) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) if err != nil { txErr := txValidationError(err) diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 9a9bc8262..539b4cac5 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -376,7 +376,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number return nil, nil } func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { +func (b *backendMock) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { return nil } func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } diff --git a/miner/worker.go b/miner/worker.go index 18d771331..5c830f822 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -92,6 +92,7 @@ type environment struct { ecount int // envelope tx count in cycle gasPool *core.GasPool // available gas used to pack transactions coinbase common.Address + evm *vm.EVM header *types.Header txs []*types.Transaction @@ -713,6 +714,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co coinbase: coinbase, header: header, witness: state.Witness(), + evm: vm.NewEVM(core.NewEVMBlockContext(header, w.chain, &coinbase), state, w.chainConfig, vm.Config{}), } // Keep track of transactions which return errors so they can be removed env.tcount = 0 @@ -778,7 +780,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ snap = env.state.Snapshot() gp = env.gasPool.Gas() ) - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) + receipt, err := core.ApplyTransaction(w.chainConfig, env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.SetGas(gp) @@ -969,6 +971,19 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm if genParams.random != (common.Hash{}) { header.MixDigest = genParams.random } + // Set baseFee and GasLimit if we are on an EIP-1559 chain + if w.chainConfig.IsLondon(header.Number) { + state, err := w.chain.StateAt(parent.Root) + if err != nil { + log.Error("Failed to get state", "err", err) + return nil, err + } + header.BaseFee = eip1559.CalcBaseFeeDBFT(w.chainConfig, parent, state) + if !w.chainConfig.IsLondon(parent.Number) { + parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() + header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) + } + } // Run the consensus preparation with the default or customized consensus engine. // Note that the `header.Time` may be changed. if err := w.engine.Prepare(w.chain, header); err != nil { @@ -988,11 +1003,6 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm header.ExcessBlobGas = &excessBlobGas header.ParentBeaconRoot = genParams.beaconRoot } - // Run the consensus preparation with the default or customized consensus engine. - if err := w.engine.Prepare(w.chain, header); err != nil { - log.Error("Failed to prepare header for sealing", "err", err) - return nil, err - } // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. @@ -1001,34 +1011,14 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm log.Error("Failed to create sealing context", "err", err) return nil, err } - // Set baseFee and GasLimit if we are on an EIP-1559 chain - if w.chainConfig.IsLondon(header.Number) { - header.BaseFee = eip1559.CalcBaseFeeDBFT(w.chainConfig, parent, env.state) - if !w.chainConfig.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() - header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) - } - } - var ( - context vm.BlockContext - vmenv *vm.EVM - ) if header.ParentBeaconRoot != nil { - context = core.NewEVMBlockContext(header, w.chain, nil) - vmenv = vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm, env.state) } if w.chainConfig.IsPrague(header.Number, header.Time) { - context := core.NewEVMBlockContext(header, w.chain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) - core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state) + core.ProcessParentBlockHash(header.ParentHash, env.evm, env.state) } if w.chain.Config().DBFT != nil { - if vmenv == nil { - context = core.NewEVMBlockContext(header, w.chain, nil) - vmenv = vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{}) - } - core.ProcessOnPersist(vmenv, env.state) + core.ProcessOnPersist(env.evm, env.state) } return env, nil } @@ -1129,7 +1119,7 @@ func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadR requests = append(requests, depositRequests) // create EVM for system calls blockContext := core.NewEVMBlockContext(work.header, w.chain, &work.header.Coinbase) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, work.state, w.chainConfig, vm.Config{}) + vmenv := vm.NewEVM(blockContext, work.state, w.chainConfig, vm.Config{}) // EIP-7002 withdrawals withdrawalRequests := core.ProcessWithdrawalQueue(vmenv, work.state) requests = append(requests, withdrawalRequests) diff --git a/tests/state_test.go b/tests/state_test.go index 76d5a601c..7b82b05e5 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -302,7 +302,8 @@ func runBenchmark(b *testing.B, t *StateTest) { context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash context.BaseFee = baseFee - evm := vm.NewEVM(context, txContext, state.StateDB, config, vmconfig) + evm := vm.NewEVM(context, state.StateDB, config, vmconfig) + evm.SetTxContext(txContext) // Create "contract" for sender to cache code analysis. sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From), diff --git a/tests/state_test_util.go b/tests/state_test_util.go index af2cb63d9..446ffb40d 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -293,7 +293,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil { context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas) } - evm := vm.NewEVM(context, txContext, st.StateDB, config, vmconfig) + evm := vm.NewEVM(context, st.StateDB, config, vmconfig) + evm.SetTxContext(txContext) if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) From 5a662ea284a2d388f0964afb87e8ff93fede6e78 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 22 Nov 2024 15:17:32 +0800 Subject: [PATCH 003/354] core, eth, internal, miner: remove unnecessary parameters (#30776) Follow-up to #30745 , this change removes some unnecessary parameters. --- cmd/evm/internal/t8ntool/execution.go | 10 +-- core/chain_makers.go | 15 ++-- core/state_processor.go | 99 +++++++++++++-------------- core/verkle_witness_test.go | 2 +- eth/state_accessor.go | 4 +- eth/tracers/api.go | 18 ++--- internal/ethapi/simulate.go | 2 +- miner/worker.go | 12 ++-- 8 files changed, 79 insertions(+), 83 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a80e4480e..1a4d52242 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -205,17 +205,17 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig) if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { var ( prevNumber = pre.Env.Number - 1 prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] ) - core.ProcessParentBlockHash(prevHash, evm, statedb) + core.ProcessParentBlockHash(prevHash, evm) } if chainConfig.DBFT != nil { - err := core.ProcessOnPersist(evm, statedb) + err := core.ProcessOnPersist(evm) if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process OnPersist: %v", err)) } @@ -387,9 +387,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, requests = append(requests, depositRequests) // EIP-7002 withdrawals - requests = append(requests, core.ProcessWithdrawalQueue(evm, statedb)) + requests = append(requests, core.ProcessWithdrawalQueue(evm)) // EIP-7251 consolidations - requests = append(requests, core.ProcessConsolidationQueue(evm, statedb)) + requests = append(requests, core.ProcessConsolidationQueue(evm)) } // Commit block diff --git a/core/chain_makers.go b/core/chain_makers.go index 07448abc3..e679a9e55 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -98,11 +98,8 @@ func (b *BlockGen) Difficulty() *big.Int { // block. func (b *BlockGen) SetParentBeaconRoot(root common.Hash) { b.header.ParentBeaconRoot = &root - var ( - blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) - evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{}) - ) - ProcessBeaconBlockRoot(root, evm, b.statedb) + blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) + ProcessBeaconBlockRoot(root, vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{})) } // addTx adds a transaction to the generated block. If no coinbase has @@ -121,7 +118,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig) ) b.statedb.SetTxContext(tx.Hash(), len(b.txs)) - receipt, err := ApplyTransaction(b.cm.config, evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed) + receipt, err := ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed) if err != nil { panic(err) } @@ -366,10 +363,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(evm, statedb) + withdrawalRequests := ProcessWithdrawalQueue(evm) requests = append(requests, withdrawalRequests) // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(evm, statedb) + consolidationRequests := ProcessConsolidationQueue(evm) requests = append(requests, consolidationRequests) } if requests != nil { @@ -471,7 +468,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine // EIP-2935 blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - ProcessParentBlockHash(b.header.ParentHash, evm, statedb) + ProcessParentBlockHash(b.header.ParentHash, evm) } // Execute any user modifications to the block. diff --git a/core/state_processor.go b/core/state_processor.go index 92cda3672..15e56c3b3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -86,13 +86,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - ProcessBeaconBlockRoot(*beaconRoot, evm, tracingStateDB) + ProcessBeaconBlockRoot(*beaconRoot, evm) } if p.config.IsPrague(block.Number(), block.Time()) { - ProcessParentBlockHash(block.ParentHash(), evm, tracingStateDB) + ProcessParentBlockHash(block.ParentHash(), evm) } if p.config.DBFT != nil { - err := ProcessOnPersist(evm, tracingStateDB) + err := ProcessOnPersist(evm) if err != nil { return nil, fmt.Errorf("could not apply OnPersist [%v]: %w", block.Hash().Hex(), err) } @@ -114,7 +114,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } statedb.SetTxContext(tx.Hash(), i) - receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, evm) + receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, tx, usedGas, evm) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -131,10 +131,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } requests = append(requests, depositRequests) // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(evm, tracingStateDB) + withdrawalRequests := ProcessWithdrawalQueue(evm) requests = append(requests, withdrawalRequests) // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(evm, tracingStateDB) + consolidationRequests := ProcessConsolidationQueue(evm) requests = append(requests, consolidationRequests) } @@ -152,7 +152,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // ApplyTransactionWithEVM attempts to apply a transaction to the given state database // and uses the input parameters for its environment similar to ApplyTransaction. However, // this method takes an already created EVM instance as input. -func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { +func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { if hooks := evm.Config.Tracer; hooks != nil { if hooks.OnTxStart != nil { hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) @@ -174,10 +174,10 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo // Update the state with pending changes. var root []byte - if config.IsByzantium(blockNumber) { + if evm.ChainConfig().IsByzantium(blockNumber) { evm.StateDB.Finalise(true) } else { - root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes() + root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes() } *usedGas += result.UsedGas @@ -226,19 +226,19 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { - msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee) +func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { + msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee) if err != nil { return nil, err } // Create a new context to be used in the EVM environment - return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm) + return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm) } // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. -func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb vm.StateDB) { - if tracer := vmenv.Config.Tracer; tracer != nil { +func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnSystemCallStart != nil { tracer.OnSystemCallStart() } @@ -255,16 +255,16 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb vm.St To: ¶ms.BeaconRootsAddress, Data: beaconRoot[:], } - vmenv.SetTxContext(NewEVMTxContext(msg)) - statedb.AddAddressToAccessList(params.BeaconRootsAddress) - _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) - statedb.Finalise(true) + evm.SetTxContext(NewEVMTxContext(msg)) + evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress) + _, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + evm.StateDB.Finalise(true) } // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. -func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.StateDB) { - if tracer := vmenv.Config.Tracer; tracer != nil { +func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnSystemCallStart != nil { tracer.OnSystemCallStart() } @@ -281,26 +281,26 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.Stat To: ¶ms.HistoryStorageAddress, Data: prevHash.Bytes(), } - vmenv.SetTxContext(NewEVMTxContext(msg)) - statedb.AddAddressToAccessList(params.HistoryStorageAddress) - _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) - statedb.Finalise(true) + evm.SetTxContext(NewEVMTxContext(msg)) + evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress) + _, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + evm.StateDB.Finalise(true) } // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. // It returns the opaque request data returned by the contract. -func ProcessWithdrawalQueue(vmenv *vm.EVM, statedb vm.StateDB) []byte { - return processRequestsSystemCall(vmenv, statedb, 0x01, params.WithdrawalQueueAddress) +func ProcessWithdrawalQueue(evm *vm.EVM) []byte { + return processRequestsSystemCall(evm, 0x01, params.WithdrawalQueueAddress) } // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract. // It returns the opaque request data returned by the contract. -func ProcessConsolidationQueue(vmenv *vm.EVM, statedb vm.StateDB) []byte { - return processRequestsSystemCall(vmenv, statedb, 0x02, params.ConsolidationQueueAddress) +func ProcessConsolidationQueue(evm *vm.EVM) []byte { + return processRequestsSystemCall(evm, 0x02, params.ConsolidationQueueAddress) } -func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType byte, addr common.Address) []byte { - if tracer := vmenv.Config.Tracer; tracer != nil { +func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Address) []byte { + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnSystemCallStart != nil { tracer.OnSystemCallStart() } @@ -308,7 +308,6 @@ func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType by defer tracer.OnSystemCallEnd() } } - msg := &Message{ From: params.SystemAddress, GasLimit: 30_000_000, @@ -317,10 +316,10 @@ func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType by GasTipCap: common.Big0, To: &addr, } - vmenv.SetTxContext(NewEVMTxContext(msg)) - statedb.AddAddressToAccessList(addr) - ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) - statedb.Finalise(true) + evm.SetTxContext(NewEVMTxContext(msg)) + evm.StateDB.AddAddressToAccessList(addr) + ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + evm.StateDB.Finalise(true) // Create withdrawals requestsData with prefix 0x01 requestsData := make([]byte, len(ret)+1) @@ -346,8 +345,8 @@ func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, er } // ProcessOnPersist applies a system call to the governance contract. -func ProcessOnPersist(vmenv *vm.EVM, statedb vm.StateDB) error { - if tracer := vmenv.Config.Tracer; tracer != nil { +func ProcessOnPersist(evm *vm.EVM) error { + if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnSystemCallStart != nil { tracer.OnSystemCallStart() } @@ -356,21 +355,21 @@ func ProcessOnPersist(vmenv *vm.EVM, statedb vm.StateDB) error { } } - if err := processKeyManagementOnPersist(vmenv, statedb); err != nil { + if err := processKeyManagementOnPersist(evm); err != nil { return err } - if err := processGovernanceOnPersist(vmenv, statedb); err != nil { + if err := processGovernanceOnPersist(evm); err != nil { return err } return nil } -func processGovernanceOnPersist(vmenv *vm.EVM, statedb vm.StateDB) error { +func processGovernanceOnPersist(evm *vm.EVM) error { var ( data []byte err error ) - if vmenv.ChainConfig().IsNeoXDKG(vmenv.Context.BlockNumber) { + if evm.ChainConfig().IsNeoXDKG(evm.Context.BlockNumber) { data, err = systemcontracts.GovernanceABI.Pack("onPersistV2") if err != nil { return fmt.Errorf("failed to pack Governance onPersistV2 call: %w", err) @@ -381,21 +380,21 @@ func processGovernanceOnPersist(vmenv *vm.EVM, statedb vm.StateDB) error { return fmt.Errorf("failed to pack Governance onPersist call: %w", err) } } - return applyLocalSystemCall(systemcontracts.GovernanceProxyHash, data, vmenv, statedb) + return applyLocalSystemCall(systemcontracts.GovernanceProxyHash, data, evm) } -func processKeyManagementOnPersist(vmenv *vm.EVM, statedb vm.StateDB) error { - if !vmenv.ChainConfig().IsNeoXDKG(vmenv.Context.BlockNumber) { +func processKeyManagementOnPersist(evm *vm.EVM) error { + if !evm.ChainConfig().IsNeoXDKG(evm.Context.BlockNumber) { return nil } data, err := systemcontracts.KeyManagementABIBasic.Pack("onPersistV2") if err != nil { return fmt.Errorf("failed to pack KeyManagement onPersistV2 call: %w", err) } - return applyLocalSystemCall(systemcontracts.KeyManagementProxyHash, data, vmenv, statedb) + return applyLocalSystemCall(systemcontracts.KeyManagementProxyHash, data, evm) } -func applyLocalSystemCall(to common.Address, data []byte, vmenv *vm.EVM, statedb vm.StateDB) error { +func applyLocalSystemCall(to common.Address, data []byte, evm *vm.EVM) error { msg := &Message{ From: params.SystemAddress, GasLimit: 30_000_000, @@ -405,12 +404,12 @@ func applyLocalSystemCall(to common.Address, data []byte, vmenv *vm.EVM, statedb To: &to, Data: data, } - vmenv.SetTxContext(NewEVMTxContext(msg)) - statedb.AddAddressToAccessList(to) - _, _, err := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + evm.SetTxContext(NewEVMTxContext(msg)) + evm.StateDB.AddAddressToAccessList(to) + _, _, err := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) if err != nil { return fmt.Errorf("onPersist call failed: %w", err) } - statedb.Finalise(true) + evm.StateDB.Finalise(true) return nil } diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 5b3fe89f5..e3638e987 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -226,7 +226,7 @@ func TestProcessParentBlockHash(t *testing.T) { header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} vmContext := NewEVMBlockContext(header, nil, new(common.Address)) evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{}) - ProcessParentBlockHash(header.ParentHash, evm, statedb) + ProcessParentBlockHash(header.ParentHash, evm) } // Read block hashes for block 0 .. num-1 for i := 0; i < num; i++ { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index a91903024..43432cff3 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -238,11 +238,11 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } // If prague hardfork, insert parent block hash in the state as per EIP-2935. if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm) } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil diff --git a/eth/tracers/api.go b/eth/tracers/api.go index e73f2bb4d..8aebe08f4 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -381,11 +381,11 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{}) if beaconRoot := next.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } // Insert parent hash in history contract. if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { - core.ProcessParentBlockHash(next.ParentHash(), evm, statedb) + core.ProcessParentBlockHash(next.ParentHash(), evm) } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the @@ -537,10 +537,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config ) evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm) } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { @@ -605,10 +605,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm) } // JS tracers have high overhead. In this case run a parallel @@ -784,10 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) + core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm, statedb) + core.ProcessParentBlockHash(block.ParentHash(), evm) } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution @@ -1037,7 +1037,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm) + _, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm) if err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 979de352f..0b58a2709 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -265,7 +265,7 @@ func repairLogs(calls []simCallResult, hash common.Hash) { } } -func (sim *simulator) sanitizeCall(call *TransactionArgs, state *state.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error { +func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error { if call.Nonce == nil { nonce := state.GetNonce(call.from()) call.Nonce = (*hexutil.Uint64)(&nonce) diff --git a/miner/worker.go b/miner/worker.go index 5c830f822..4126e191d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -780,7 +780,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ snap = env.state.Snapshot() gp = env.gasPool.Gas() ) - receipt, err := core.ApplyTransaction(w.chainConfig, env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed) + receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.SetGas(gp) @@ -1012,13 +1012,13 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm return nil, err } if header.ParentBeaconRoot != nil { - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm, env.state) + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) } if w.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, env.evm, env.state) + core.ProcessParentBlockHash(header.ParentHash, env.evm) } if w.chain.Config().DBFT != nil { - core.ProcessOnPersist(env.evm, env.state) + core.ProcessOnPersist(env.evm) } return env, nil } @@ -1121,10 +1121,10 @@ func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadR blockContext := core.NewEVMBlockContext(work.header, w.chain, &work.header.Coinbase) vmenv := vm.NewEVM(blockContext, work.state, w.chainConfig, vm.Config{}) // EIP-7002 withdrawals - withdrawalRequests := core.ProcessWithdrawalQueue(vmenv, work.state) + withdrawalRequests := core.ProcessWithdrawalQueue(vmenv) requests = append(requests, withdrawalRequests) // EIP-7251 consolidations - consolidationRequests := core.ProcessConsolidationQueue(vmenv, work.state) + consolidationRequests := core.ProcessConsolidationQueue(vmenv) requests = append(requests, consolidationRequests) } if requests != nil { From e83fc1fe07431c940cfc1ea8035245069c1448bc Mon Sep 17 00:00:00 2001 From: "Hyunsoo Shin (Lake)" Date: Fri, 22 Nov 2024 16:21:20 +0900 Subject: [PATCH 004/354] internal/ethapi: remove double map-clone (#30788) `ActivePrecompiledContracts()` clones the precompiled contract map, thus its callsite does not need to clone it --- internal/ethapi/api.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c2b19827e..62bdf2d45 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -21,7 +21,6 @@ import ( "encoding/hex" "errors" "fmt" - "maps" gomath "math" "math/big" "strings" @@ -330,7 +329,7 @@ func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string { pending, queue := api.b.TxPoolContent() // Define a formatter to flatten a transaction into a string - var format = func(tx *types.Transaction) string { + format := func(tx *types.Transaction) string { if to := tx.To(); to != nil { return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) } @@ -901,7 +900,7 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S blockOverrides.Apply(&blockCtx) } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) - precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules)) + precompiles := vm.ActivePrecompiledContracts(rules) if err := overrides.Apply(state, precompiles); err != nil { return nil, err } @@ -1913,11 +1912,11 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, matchTx := sendArgs.ToTransaction(types.LegacyTxType) // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. - var price = matchTx.GasPrice() + price := matchTx.GasPrice() if gasPrice != nil { price = gasPrice.ToInt() } - var gas = matchTx.Gas() + gas := matchTx.Gas() if gasLimit != nil { gas = uint64(*gasLimit) } From 33511fbda88f2346d77f887b1f174aea16a91d62 Mon Sep 17 00:00:00 2001 From: wangjingcun Date: Fri, 22 Nov 2024 16:02:45 +0800 Subject: [PATCH 005/354] all: typos in comments (#30779) fixes some typos --- build/ci.go | 2 +- core/verkle_witness_test.go | 2 +- core/vm/eof.go | 2 +- trie/utils/verkle.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/ci.go b/build/ci.go index bae31f728..07d721303 100644 --- a/build/ci.go +++ b/build/ci.go @@ -256,7 +256,7 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) ( // See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options // regarding the options --build-id=none and --strip-all. It is needed for // reproducible builds; removing references to temporary files in C-land, and - // making build-id reproducably absent. + // making build-id reproducibly absent. extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"} if staticLinking { extld = append(extld, "-static") diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index e3638e987..f5aa579fd 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -1033,7 +1033,7 @@ func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiaryAndPrefundedAccount ) // Prefund the account, at an address that the contract will be deployed at, // before it selfdestrucs. We can therefore check that the account itseld is - // NOT destroyed, which is what the currrent version of the spec requires. + // NOT destroyed, which is what the current version of the spec requires. // TODO(gballet) revisit after the spec has been modified. gspec.Alloc[contract] = types.Account{ Balance: big.NewInt(100), diff --git a/core/vm/eof.go b/core/vm/eof.go index fcced6ae7..a5406283d 100644 --- a/core/vm/eof.go +++ b/core/vm/eof.go @@ -96,7 +96,7 @@ func (meta *functionMetadata) checkInputs(stackMin int) error { } // checkStackMax checks the if current maximum stack combined with the -// functin max stack will result in a stack overflow, and if so returns an error. +// function max stack will result in a stack overflow, and if so returns an error. func (meta *functionMetadata) checkStackMax(stackMax int) error { newMaxStack := stackMax + int(meta.maxStackHeight) - int(meta.inputs) if newMaxStack > int(params.StackLimit) { diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 4294f5e4b..b785e512b 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -217,7 +217,7 @@ func StorageIndex(storageKey []byte) (*uint256.Int, byte) { // The first MAIN_STORAGE_OFFSET group will see its // first 64 slots unreachable. This is either a typo in the // spec or intended to conserve the 256-u256 - // aligment. If we decide to ever access these 64 + // alignment. If we decide to ever access these 64 // slots, uncomment this. // // Get the new offset since we now know that we are above 64. // pos.Sub(&pos, codeStorageDelta) From 4920d675c88eb882ff3f32c58ce3b4151cc25c95 Mon Sep 17 00:00:00 2001 From: j2gg0s Date: Fri, 22 Nov 2024 16:16:42 +0800 Subject: [PATCH 006/354] trie: replace custom logic with bytes.HasPrefix (#30771) in `trie` - Replace custom logic with `bytes.HasPrefix` - Remove unnecessary code in `GetNode` --- trie/proof.go | 8 ++++---- trie/trie.go | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/trie/proof.go b/trie/proof.go index a39d6b4ea..40836fba3 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -48,7 +48,7 @@ func (t *Trie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { for len(key) > 0 && tn != nil { switch n := tn.(type) { case *shortNode: - if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { + if !bytes.HasPrefix(key, n.Key) { // The trie doesn't contain the key. tn = nil } else { @@ -371,7 +371,7 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error } return unset(cld, cld.Children[key[pos]], key, pos+1, removeLeft) case *shortNode: - if len(key[pos:]) < len(cld.Key) || !bytes.Equal(cld.Key, key[pos:pos+len(cld.Key)]) { + if !bytes.HasPrefix(key[pos:], cld.Key) { // Find the fork point, it's a non-existent branch. if removeLeft { if bytes.Compare(cld.Key, key[pos:]) < 0 { @@ -434,7 +434,7 @@ func hasRightElement(node node, key []byte) bool { } node, pos = rn.Children[key[pos]], pos+1 case *shortNode: - if len(key)-pos < len(rn.Key) || !bytes.Equal(rn.Key, key[pos:pos+len(rn.Key)]) { + if !bytes.HasPrefix(key[pos:], rn.Key) { return bytes.Compare(rn.Key, key[pos:]) > 0 } node, pos = rn.Val, pos+len(rn.Key) @@ -589,7 +589,7 @@ func get(tn node, key []byte, skipResolved bool) ([]byte, node) { for { switch n := tn.(type) { case *shortNode: - if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { + if !bytes.HasPrefix(key, n.Key) { return nil, nil } tn = n.Val diff --git a/trie/trie.go b/trie/trie.go index e3f3f3924..ae2a7b21a 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -163,7 +163,7 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no case valueNode: return n, n, false, nil case *shortNode: - if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { + if !bytes.HasPrefix(key[pos:], n.Key) { // key not found in trie return nil, n, false, nil } @@ -219,9 +219,6 @@ func (t *Trie) GetNode(path []byte) ([]byte, int, error) { if resolved > 0 { t.root = newroot } - if item == nil { - return nil, resolved, nil - } return item, resolved, nil } @@ -254,7 +251,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod return nil, nil, 0, nil case *shortNode: - if len(path)-pos < len(n.Key) || !bytes.Equal(n.Key, path[pos:pos+len(n.Key)]) { + if !bytes.HasPrefix(path[pos:], n.Key) { // Path branches off from short node return nil, n, 0, nil } From 62b9e92585c5182ead140d827e56c28f3bfb1197 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 22 Nov 2024 16:55:43 +0800 Subject: [PATCH 007/354] core, triedb: remove destruct flag in state snapshot (#30752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request removes the destruct flag from the state snapshot to simplify the code. Previously, this flag indicated that an account was removed during a state transition, making all associated storage slots inaccessible. Because storage deletion can involve a large number of slots, the actual deletion is deferred until the end of the process, where it is handled in batches. With the deprecation of self-destruct in the Cancun fork, storage deletions are no longer expected. Historically, the largest storage deletion event in Ethereum was around 15 megabytes—manageable in memory. In this pull request, the single destruct flag is replaced by a set of deletion markers for individual storage slots. Each deleted storage slot will now appear in the Storage set with a nil value. This change will simplify a lot logics, such as storage accessing, storage flushing, storage iteration and so on. --- core/state/snapshot/conversion.go | 10 -- core/state/snapshot/difflayer.go | 117 +++++------------------ core/state/snapshot/difflayer_test.go | 123 +++++++++--------------- core/state/snapshot/disklayer.go | 4 +- core/state/snapshot/disklayer_test.go | 86 ++++++++++------- core/state/snapshot/generate_test.go | 2 +- core/state/snapshot/iterator.go | 17 ++-- core/state/snapshot/iterator_binary.go | 33 +------ core/state/snapshot/iterator_fast.go | 10 +- core/state/snapshot/iterator_test.go | 126 ++++++++++++------------- core/state/snapshot/journal.go | 37 +++----- core/state/snapshot/snapshot.go | 61 +++++------- core/state/snapshot/snapshot_test.go | 30 +++--- core/state/snapshot/utils.go | 12 +-- core/state/statedb.go | 69 ++++++++------ core/state/statedb_fuzz_test.go | 105 ++++++++++++++------- core/state/statedb_test.go | 4 +- core/state/stateupdate.go | 46 +++++---- triedb/states.go | 2 - 19 files changed, 382 insertions(+), 512 deletions(-) diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 8a0fd1989..4b0774f2a 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -50,16 +50,6 @@ type ( leafCallbackFn func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) ) -// GenerateAccountTrieRoot takes an account iterator and reproduces the root hash. -func GenerateAccountTrieRoot(it AccountIterator) (common.Hash, error) { - return generateTrieRoot(nil, "", it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true) -} - -// GenerateStorageTrieRoot takes a storage iterator and reproduces the root hash. -func GenerateStorageTrieRoot(account common.Hash, it StorageIterator) (common.Hash, error) { - return generateTrieRoot(nil, "", it, account, stackTrieGenerate, nil, newGenerateStats(), true) -} - // GenerateTrie takes the whole snapshot tree as the input, traverses all the // accounts as well as the corresponding storages and regenerate the whole state // (account trie + all storage tries). diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 779c1ea98..dce4f79a1 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" bloomfilter "github.com/holiman/bloomfilter/v2" + "golang.org/x/exp/maps" ) var ( @@ -73,23 +74,14 @@ var ( // bloom key for an account/slot. This is randomized at init(), so that the // global population of nodes do not all display the exact same behaviour with // regards to bloom content - bloomDestructHasherOffset = 0 - bloomAccountHasherOffset = 0 - bloomStorageHasherOffset = 0 + bloomAccountHasherOffset = 0 + bloomStorageHasherOffset = 0 ) func init() { // Init the bloom offsets in the range [0:24] (requires 8 bytes) - bloomDestructHasherOffset = rand.Intn(25) bloomAccountHasherOffset = rand.Intn(25) bloomStorageHasherOffset = rand.Intn(25) - - // The destruct and account blooms must be different, as the storage slots - // will check for destruction too for every bloom miss. It should not collide - // with modified accounts. - for bloomAccountHasherOffset == bloomDestructHasherOffset { - bloomAccountHasherOffset = rand.Intn(25) - } } // diffLayer represents a collection of modifications made to a state snapshot @@ -106,29 +98,16 @@ type diffLayer struct { root common.Hash // Root hash to which this snapshot diff belongs to stale atomic.Bool // Signals that the layer became stale (state progressed) - // destructSet is a very special helper marker. If an account is marked as - // deleted, then it's recorded in this set. However it's allowed that an account - // is included here but still available in other sets(e.g. storageData). The - // reason is the diff layer includes all the changes in a *block*. It can - // happen that in the tx_1, account A is self-destructed while in the tx_2 - // it's recreated. But we still need this marker to indicate the "old" A is - // deleted, all data in other set belongs to the "new" A. - destructSet map[common.Hash]struct{} // Keyed markers for deleted (and potentially) recreated accounts - accountList []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil accountData map[common.Hash][]byte // Keyed accounts for direct retrieval (nil means deleted) - storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted) + accountList []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil + storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil diffed *bloomfilter.Filter // Bloom filter tracking all the diffed items up to the disk layer lock sync.RWMutex } -// destructBloomHash is used to convert a destruct event into a 64 bit mini hash. -func destructBloomHash(h common.Hash) uint64 { - return binary.BigEndian.Uint64(h[bloomDestructHasherOffset : bloomDestructHasherOffset+8]) -} - // accountBloomHash is used to convert an account hash into a 64 bit mini hash. func accountBloomHash(h common.Hash) uint64 { return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8]) @@ -142,12 +121,11 @@ func storageBloomHash(h0, h1 common.Hash) uint64 { // newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low // level persistent database or a hierarchical diff already. -func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { +func newDiffLayer(parent snapshot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { // Create the new layer with some pre-allocated data segments dl := &diffLayer{ parent: parent, root: root, - destructSet: destructs, accountData: accounts, storageData: storage, storageList: make(map[common.Hash][]common.Hash), @@ -161,10 +139,7 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s panic("unknown parent type") } // Sanity check that accounts or storage slots are never nil - for accountHash, blob := range accounts { - if blob == nil { - panic(fmt.Sprintf("account %#x nil", accountHash)) - } + for _, blob := range accounts { // Determine memory size and track the dirty writes dl.memory += uint64(common.HashLength + len(blob)) snapshotDirtyAccountWriteMeter.Mark(int64(len(blob))) @@ -179,7 +154,6 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s snapshotDirtyStorageWriteMeter.Mark(int64(len(data))) } } - dl.memory += uint64(len(destructs) * common.HashLength) return dl } @@ -204,10 +178,6 @@ func (dl *diffLayer) rebloom(origin *diskLayer) { } else { dl.diffed, _ = bloomfilter.New(uint64(bloomSize), uint64(bloomFuncs)) } - // Iterate over all the accounts and storage slots and index them - for hash := range dl.destructSet { - dl.diffed.AddHash(destructBloomHash(hash)) - } for hash := range dl.accountData { dl.diffed.AddHash(accountBloomHash(hash)) } @@ -274,11 +244,8 @@ func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) { } // Check the bloom filter first whether there's even a point in reaching into // all the maps in all the layers below - hit := dl.diffed.ContainsHash(accountBloomHash(hash)) - if !hit { - hit = dl.diffed.ContainsHash(destructBloomHash(hash)) - } var origin *diskLayer + hit := dl.diffed.ContainsHash(accountBloomHash(hash)) if !hit { origin = dl.origin // extract origin while holding the lock } @@ -310,18 +277,14 @@ func (dl *diffLayer) accountRLP(hash common.Hash, depth int) ([]byte, error) { if data, ok := dl.accountData[hash]; ok { snapshotDirtyAccountHitMeter.Mark(1) snapshotDirtyAccountHitDepthHist.Update(int64(depth)) - snapshotDirtyAccountReadMeter.Mark(int64(len(data))) + if n := len(data); n > 0 { + snapshotDirtyAccountReadMeter.Mark(int64(n)) + } else { + snapshotDirtyAccountInexMeter.Mark(1) + } snapshotBloomAccountTrueHitMeter.Mark(1) return data, nil } - // If the account is known locally, but deleted, return it - if _, ok := dl.destructSet[hash]; ok { - snapshotDirtyAccountHitMeter.Mark(1) - snapshotDirtyAccountHitDepthHist.Update(int64(depth)) - snapshotDirtyAccountInexMeter.Mark(1) - snapshotBloomAccountTrueHitMeter.Mark(1) - return nil, nil - } // Account unknown to this diff, resolve from parent if diff, ok := dl.parent.(*diffLayer); ok { return diff.accountRLP(hash, depth+1) @@ -345,11 +308,8 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro dl.lock.RUnlock() return nil, ErrSnapshotStale } - hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash)) - if !hit { - hit = dl.diffed.ContainsHash(destructBloomHash(accountHash)) - } var origin *diskLayer + hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash)) if !hit { origin = dl.origin // extract origin while holding the lock } @@ -391,14 +351,6 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([ return data, nil } } - // If the account is known locally, but deleted, return an empty slot - if _, ok := dl.destructSet[accountHash]; ok { - snapshotDirtyStorageHitMeter.Mark(1) - snapshotDirtyStorageHitDepthHist.Update(int64(depth)) - snapshotDirtyStorageInexMeter.Mark(1) - snapshotBloomStorageTrueHitMeter.Mark(1) - return nil, nil - } // Storage slot unknown to this diff, resolve from parent if diff, ok := dl.parent.(*diffLayer); ok { return diff.storage(accountHash, storageHash, depth+1) @@ -410,8 +362,8 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([ // Update creates a new layer on top of the existing snapshot diff tree with // the specified data items. -func (dl *diffLayer) Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { - return newDiffLayer(dl, blockRoot, destructs, accounts, storage) +func (dl *diffLayer) Update(blockRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { + return newDiffLayer(dl, blockRoot, accounts, storage) } // flatten pushes all data from this point downwards, flattening everything into @@ -436,12 +388,6 @@ func (dl *diffLayer) flatten() snapshot { if parent.stale.Swap(true) { panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo } - // Overwrite all the updated accounts blindly, merge the sorted list - for hash := range dl.destructSet { - parent.destructSet[hash] = struct{}{} - delete(parent.accountData, hash) - delete(parent.storageData, hash) - } for hash, data := range dl.accountData { parent.accountData[hash] = data } @@ -453,17 +399,13 @@ func (dl *diffLayer) flatten() snapshot { continue } // Storage exists in both parent and child, merge the slots - comboData := parent.storageData[accountHash] - for storageHash, data := range storage { - comboData[storageHash] = data - } + maps.Copy(parent.storageData[accountHash], storage) } // Return the combo parent return &diffLayer{ parent: parent.parent, origin: parent.origin, root: dl.root, - destructSet: parent.destructSet, accountData: parent.accountData, storageData: parent.storageData, storageList: make(map[common.Hash][]common.Hash), @@ -489,15 +431,7 @@ func (dl *diffLayer) AccountList() []common.Hash { dl.lock.Lock() defer dl.lock.Unlock() - dl.accountList = make([]common.Hash, 0, len(dl.destructSet)+len(dl.accountData)) - for hash := range dl.accountData { - dl.accountList = append(dl.accountList, hash) - } - for hash := range dl.destructSet { - if _, ok := dl.accountData[hash]; !ok { - dl.accountList = append(dl.accountList, hash) - } - } + dl.accountList = maps.Keys(dl.accountData) slices.SortFunc(dl.accountList, common.Hash.Cmp) dl.memory += uint64(len(dl.accountList) * common.HashLength) return dl.accountList @@ -512,18 +446,17 @@ func (dl *diffLayer) AccountList() []common.Hash { // not empty but the flag is true. // // Note, the returned slice is not a copy, so do not modify it. -func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool) { +func (dl *diffLayer) StorageList(accountHash common.Hash) []common.Hash { dl.lock.RLock() - _, destructed := dl.destructSet[accountHash] if _, ok := dl.storageData[accountHash]; !ok { // Account not tracked by this layer dl.lock.RUnlock() - return nil, destructed + return nil } // If an old list already exists, return it if list, exist := dl.storageList[accountHash]; exist { dl.lock.RUnlock() - return list, destructed // the cached list can't be nil + return list // the cached list can't be nil } dl.lock.RUnlock() @@ -531,13 +464,9 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool) dl.lock.Lock() defer dl.lock.Unlock() - storageMap := dl.storageData[accountHash] - storageList := make([]common.Hash, 0, len(storageMap)) - for k := range storageMap { - storageList = append(storageList, k) - } + storageList := maps.Keys(dl.storageData[accountHash]) slices.SortFunc(storageList, common.Hash.Cmp) dl.storageList[accountHash] = storageList dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) - return storageList, destructed + return storageList } diff --git a/core/state/snapshot/difflayer_test.go b/core/state/snapshot/difflayer_test.go index 674a031b1..b212098e7 100644 --- a/core/state/snapshot/difflayer_test.go +++ b/core/state/snapshot/difflayer_test.go @@ -28,14 +28,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb/memorydb" ) -func copyDestructs(destructs map[common.Hash]struct{}) map[common.Hash]struct{} { - copy := make(map[common.Hash]struct{}) - for hash := range destructs { - copy[hash] = struct{}{} - } - return copy -} - func copyAccounts(accounts map[common.Hash][]byte) map[common.Hash][]byte { copy := make(map[common.Hash][]byte) for hash, blob := range accounts { @@ -58,9 +50,8 @@ func copyStorage(storage map[common.Hash]map[common.Hash][]byte) map[common.Hash // TestMergeBasics tests some simple merges func TestMergeBasics(t *testing.T) { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) // Fill up a parent for i := 0; i < 100; i++ { @@ -69,7 +60,7 @@ func TestMergeBasics(t *testing.T) { accounts[h] = data if rand.Intn(4) == 0 { - destructs[h] = struct{}{} + accounts[h] = nil } if rand.Intn(2) == 0 { accStorage := make(map[common.Hash][]byte) @@ -80,11 +71,12 @@ func TestMergeBasics(t *testing.T) { } } // Add some (identical) layers on top - parent := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child := newDiffLayer(parent, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) - child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) + parent := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage)) + child := newDiffLayer(parent, common.Hash{}, copyAccounts(accounts), copyStorage(storage)) + child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage)) + child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage)) + child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage)) + // And flatten merged := (child.flatten()).(*diffLayer) @@ -99,18 +91,13 @@ func TestMergeBasics(t *testing.T) { t.Errorf("accountList [2] wrong: have %v, want %v", have, want) } } - { // Check account drops - if have, want := len(merged.destructSet), len(destructs); have != want { - t.Errorf("accountDrop wrong: have %v, want %v", have, want) - } - } { // Check storage lists i := 0 for aHash, sMap := range storage { if have, want := len(merged.storageList), i; have != want { t.Errorf("[1] storageList wrong: have %v, want %v", have, want) } - list, _ := merged.StorageList(aHash) + list := merged.StorageList(aHash) if have, want := len(list), len(sMap); have != want { t.Errorf("[2] StorageList() wrong: have %v, want %v", have, want) } @@ -124,41 +111,32 @@ func TestMergeBasics(t *testing.T) { // TestMergeDelete tests some deletion func TestMergeDelete(t *testing.T) { - var ( - storage = make(map[common.Hash]map[common.Hash][]byte) - ) + storage := make(map[common.Hash]map[common.Hash][]byte) + // Fill up a parent h1 := common.HexToHash("0x01") h2 := common.HexToHash("0x02") - flipDrops := func() map[common.Hash]struct{} { - return map[common.Hash]struct{}{ - h2: {}, - } - } - flipAccs := func() map[common.Hash][]byte { + flip := func() map[common.Hash][]byte { return map[common.Hash][]byte{ h1: randomAccount(), + h2: nil, } } - flopDrops := func() map[common.Hash]struct{} { - return map[common.Hash]struct{}{ - h1: {}, - } - } - flopAccs := func() map[common.Hash][]byte { + flop := func() map[common.Hash][]byte { return map[common.Hash][]byte{ + h1: nil, h2: randomAccount(), } } // Add some flipAccs-flopping layers on top - parent := newDiffLayer(emptyLayer(), common.Hash{}, flipDrops(), flipAccs(), storage) - child := parent.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) - child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) - child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage) - child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage) + parent := newDiffLayer(emptyLayer(), common.Hash{}, flip(), storage) + child := parent.Update(common.Hash{}, flop(), storage) + child = child.Update(common.Hash{}, flip(), storage) + child = child.Update(common.Hash{}, flop(), storage) + child = child.Update(common.Hash{}, flip(), storage) + child = child.Update(common.Hash{}, flop(), storage) + child = child.Update(common.Hash{}, flip(), storage) if data, _ := child.Account(h1); data == nil { t.Errorf("last diff layer: expected %x account to be non-nil", h1) @@ -166,12 +144,7 @@ func TestMergeDelete(t *testing.T) { if data, _ := child.Account(h2); data != nil { t.Errorf("last diff layer: expected %x account to be nil", h2) } - if _, ok := child.destructSet[h1]; ok { - t.Errorf("last diff layer: expected %x drop to be missing", h1) - } - if _, ok := child.destructSet[h2]; !ok { - t.Errorf("last diff layer: expected %x drop to be present", h1) - } + // And flatten merged := (child.flatten()).(*diffLayer) @@ -181,12 +154,6 @@ func TestMergeDelete(t *testing.T) { if data, _ := merged.Account(h2); data != nil { t.Errorf("merged layer: expected %x account to be nil", h2) } - if _, ok := merged.destructSet[h1]; !ok { // Note, drops stay alive until persisted to disk! - t.Errorf("merged diff layer: expected %x drop to be present", h1) - } - if _, ok := merged.destructSet[h2]; !ok { // Note, drops stay alive until persisted to disk! - t.Errorf("merged diff layer: expected %x drop to be present", h1) - } // If we add more granular metering of memory, we can enable this again, // but it's not implemented for now //if have, want := merged.memory, child.memory; have != want { @@ -206,22 +173,20 @@ func TestInsertAndMerge(t *testing.T) { ) { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) - parent = newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage) + parent = newDiffLayer(emptyLayer(), common.Hash{}, accounts, storage) } { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) accounts[acc] = randomAccount() storage[acc] = make(map[common.Hash][]byte) storage[acc][slot] = []byte{0x01} - child = newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + child = newDiffLayer(parent, common.Hash{}, accounts, storage) } // And flatten merged := (child.flatten()).(*diffLayer) @@ -250,14 +215,13 @@ func BenchmarkSearch(b *testing.B) { // First, we set up 128 diff layers, with 1K items each fill := func(parent snapshot) *diffLayer { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) for i := 0; i < 10000; i++ { accounts[randomHash()] = randomAccount() } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, accounts, storage) } var layer snapshot layer = emptyLayer() @@ -286,9 +250,8 @@ func BenchmarkSearchSlot(b *testing.B) { accountRLP := randomAccount() fill := func(parent snapshot) *diffLayer { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) accounts[accountKey] = accountRLP @@ -299,7 +262,7 @@ func BenchmarkSearchSlot(b *testing.B) { accStorage[randomHash()] = value storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, accounts, storage) } var layer snapshot layer = emptyLayer() @@ -320,9 +283,8 @@ func BenchmarkSearchSlot(b *testing.B) { func BenchmarkFlatten(b *testing.B) { fill := func(parent snapshot) *diffLayer { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) for i := 0; i < 100; i++ { accountKey := randomHash() @@ -336,7 +298,7 @@ func BenchmarkFlatten(b *testing.B) { } storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, accounts, storage) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -369,9 +331,8 @@ func BenchmarkFlatten(b *testing.B) { func BenchmarkJournal(b *testing.B) { fill := func(parent snapshot) *diffLayer { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) for i := 0; i < 200; i++ { accountKey := randomHash() @@ -385,7 +346,7 @@ func BenchmarkJournal(b *testing.B) { } storage[accountKey] = accStorage } - return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage) + return newDiffLayer(parent, common.Hash{}, accounts, storage) } layer := snapshot(emptyLayer()) for i := 1; i < 128; i++ { diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index 76928edf0..202e6c70e 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -180,8 +180,8 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro // Update creates a new layer on top of the existing snapshot diff tree with // the specified data items. Note, the maps are retained by the method to avoid // copying everything. -func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { - return newDiffLayer(dl, blockHash, destructs, accounts, storage) +func (dl *diskLayer) Update(blockHash common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { + return newDiffLayer(dl, blockHash, accounts, storage) } // stopGeneration aborts the state snapshot generation if it is currently running. diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index 168458c40..6d99a90d6 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -117,20 +117,22 @@ func TestDiskMerge(t *testing.T) { base.Storage(conNukeCache, conNukeCacheSlot) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{ - accDelNoCache: {}, - accDelCache: {}, - conNukeNoCache: {}, - conNukeCache: {}, - }, map[common.Hash][]byte{ - accModNoCache: reverse(accModNoCache[:]), - accModCache: reverse(accModCache[:]), - }, map[common.Hash]map[common.Hash][]byte{ - conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])}, - conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, - conDelNoCache: {conDelNoCacheSlot: nil}, - conDelCache: {conDelCacheSlot: nil}, - }); err != nil { + if err := snaps.Update(diffRoot, baseRoot, + map[common.Hash][]byte{ + accDelNoCache: nil, + accDelCache: nil, + conNukeNoCache: nil, + conNukeCache: nil, + accModNoCache: reverse(accModNoCache[:]), + accModCache: reverse(accModCache[:]), + }, map[common.Hash]map[common.Hash][]byte{ + conNukeNoCache: {conNukeNoCacheSlot: nil}, + conNukeCache: {conNukeCacheSlot: nil}, + conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])}, + conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, + conDelNoCache: {conDelNoCacheSlot: nil}, + conDelCache: {conDelCacheSlot: nil}, + }); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -340,20 +342,27 @@ func TestDiskPartialMerge(t *testing.T) { assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:]) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{ - accDelNoCache: {}, - accDelCache: {}, - conNukeNoCache: {}, - conNukeCache: {}, - }, map[common.Hash][]byte{ - accModNoCache: reverse(accModNoCache[:]), - accModCache: reverse(accModCache[:]), - }, map[common.Hash]map[common.Hash][]byte{ - conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])}, - conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, - conDelNoCache: {conDelNoCacheSlot: nil}, - conDelCache: {conDelCacheSlot: nil}, - }); err != nil { + if err := snaps.Update(diffRoot, baseRoot, + map[common.Hash][]byte{ + accDelNoCache: nil, + accDelCache: nil, + conNukeNoCache: nil, + conNukeCache: nil, + accModNoCache: reverse(accModNoCache[:]), + accModCache: reverse(accModCache[:]), + }, + map[common.Hash]map[common.Hash][]byte{ + conNukeNoCache: { + conNukeNoCacheSlot: nil, + }, + conNukeCache: { + conNukeCacheSlot: nil, + }, + conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])}, + conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])}, + conDelNoCache: {conDelNoCacheSlot: nil}, + conDelCache: {conDelCacheSlot: nil}, + }); err != nil { t.Fatalf("test %d: failed to update snapshot tree: %v", i, err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -462,9 +471,11 @@ func TestDiskGeneratorPersistence(t *testing.T) { }, } // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffRoot, baseRoot, nil, map[common.Hash][]byte{ - accTwo: accTwo[:], - }, nil); err != nil { + if err := snaps.Update(diffRoot, baseRoot, + map[common.Hash][]byte{ + accTwo: accTwo[:], + }, nil, + ); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } if err := snaps.Cap(diffRoot, 0); err != nil { @@ -480,11 +491,14 @@ func TestDiskGeneratorPersistence(t *testing.T) { } // Test scenario 2, the disk layer is fully generated // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffTwoRoot, diffRoot, nil, map[common.Hash][]byte{ - accThree: accThree.Bytes(), - }, map[common.Hash]map[common.Hash][]byte{ - accThree: {accThreeSlot: accThreeSlot.Bytes()}, - }); err != nil { + if err := snaps.Update(diffTwoRoot, diffRoot, + map[common.Hash][]byte{ + accThree: accThree.Bytes(), + }, + map[common.Hash]map[common.Hash][]byte{ + accThree: {accThreeSlot: accThreeSlot.Bytes()}, + }, + ); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) } diskLayer := snaps.layers[snaps.diskRoot()].(*diskLayer) diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 56abff348..661610840 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -134,7 +134,7 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { snapRoot, err := generateTrieRoot(nil, "", accIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { - storageIt, _ := snap.StorageIterator(accountHash, common.Hash{}) + storageIt := snap.StorageIterator(accountHash, common.Hash{}) defer storageIt.Release() hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false) diff --git a/core/state/snapshot/iterator.go b/core/state/snapshot/iterator.go index c1a196c7f..cd9c22584 100644 --- a/core/state/snapshot/iterator.go +++ b/core/state/snapshot/iterator.go @@ -115,6 +115,7 @@ func (it *diffAccountIterator) Next() bool { } // Iterator seems to be still alive, retrieve and cache the live hash it.curHash = it.keys[0] + // key cached, shift the iterator and notify the user of success it.keys = it.keys[1:] return true @@ -135,7 +136,7 @@ func (it *diffAccountIterator) Hash() common.Hash { // This method may _fail_, if the underlying layer has been flattened between // the call to Next and Account. That type of error will set it.Err. // This method assumes that flattening does not delete elements from -// the accountdata mapping (writing nil into it is fine though), and will panic +// the accountData mapping (writing nil into it is fine though), and will panic // if elements have been deleted. // // Note the returned account is not a copy, please don't modify it. @@ -143,10 +144,6 @@ func (it *diffAccountIterator) Account() []byte { it.layer.lock.RLock() blob, ok := it.layer.accountData[it.curHash] if !ok { - if _, ok := it.layer.destructSet[it.curHash]; ok { - it.layer.lock.RUnlock() - return nil - } panic(fmt.Sprintf("iterator referenced non-existent account: %x", it.curHash)) } it.layer.lock.RUnlock() @@ -247,11 +244,11 @@ type diffStorageIterator struct { // "destructed" returned. If it's true then it means the whole storage is // destructed in this layer(maybe recreated too), don't bother deeper layer // for storage retrieval. -func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) { +func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) StorageIterator { // Create the storage for this account even it's marked // as destructed. The iterator is for the new one which // just has the same address as the deleted one. - hashes, destructed := dl.StorageList(account) + hashes := dl.StorageList(account) index := sort.Search(len(hashes), func(i int) bool { return bytes.Compare(seek[:], hashes[i][:]) <= 0 }) @@ -260,7 +257,7 @@ func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) (Sto layer: dl, account: account, keys: hashes[index:], - }, destructed + } } // Next steps the iterator forward one element, returning false if exhausted. @@ -339,13 +336,13 @@ type diskStorageIterator struct { // If the whole storage is destructed, then all entries in the disk // layer are deleted already. So the "destructed" flag returned here // is always false. -func (dl *diskLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) { +func (dl *diskLayer) StorageIterator(account common.Hash, seek common.Hash) StorageIterator { pos := common.TrimRightZeroes(seek[:]) return &diskStorageIterator{ layer: dl, account: account, it: dl.diskdb.NewIterator(append(rawdb.SnapshotStoragePrefix, account.Bytes()...), pos), - }, false + } } // Next steps the iterator forward one element, returning false if exhausted. diff --git a/core/state/snapshot/iterator_binary.go b/core/state/snapshot/iterator_binary.go index 523c7b994..254c4b860 100644 --- a/core/state/snapshot/iterator_binary.go +++ b/core/state/snapshot/iterator_binary.go @@ -67,44 +67,17 @@ func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) Iterator { func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator { parent, ok := dl.parent.(*diffLayer) if !ok { - // If the storage in this layer is already destructed, discard all - // deeper layers but still return a valid single-branch iterator. - a, destructed := dl.StorageIterator(account, seek) - if destructed { - l := &binaryIterator{ - a: a, - account: account, - } - l.aDone = !l.a.Next() - l.bDone = true - return l - } - // The parent is disk layer, don't need to take care "destructed" - // anymore. - b, _ := dl.Parent().StorageIterator(account, seek) l := &binaryIterator{ - a: a, - b: b, + a: dl.StorageIterator(account, seek), + b: dl.Parent().StorageIterator(account, seek), account: account, } l.aDone = !l.a.Next() l.bDone = !l.b.Next() return l } - // If the storage in this layer is already destructed, discard all - // deeper layers but still return a valid single-branch iterator. - a, destructed := dl.StorageIterator(account, seek) - if destructed { - l := &binaryIterator{ - a: a, - account: account, - } - l.aDone = !l.a.Next() - l.bDone = true - return l - } l := &binaryIterator{ - a: a, + a: dl.StorageIterator(account, seek), b: parent.initBinaryStorageIterator(account, seek), account: account, } diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index fa0daea7b..7f7ba876f 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -90,18 +90,10 @@ func newFastIterator(tree *Tree, root common.Hash, account common.Hash, seek com priority: depth, }) } else { - // If the whole storage is destructed in this layer, don't - // bother deeper layer anymore. But we should still keep - // the iterator for this layer, since the iterator can contain - // some valid slots which belongs to the re-created account. - it, destructed := current.StorageIterator(account, seek) fi.iterators = append(fi.iterators, &weightedIterator{ - it: it, + it: current.StorageIterator(account, seek), priority: depth, }) - if destructed { - break - } } current = current.Parent() } diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index f2f4d19f8..b9fe370b8 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -32,9 +32,8 @@ import ( // TestAccountIteratorBasics tests some simple single-layer(diff and disk) iteration func TestAccountIteratorBasics(t *testing.T) { var ( - destructs = make(map[common.Hash]struct{}) - accounts = make(map[common.Hash][]byte) - storage = make(map[common.Hash]map[common.Hash][]byte) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) ) // Fill up a parent for i := 0; i < 100; i++ { @@ -42,9 +41,6 @@ func TestAccountIteratorBasics(t *testing.T) { data := randomAccount() accounts[h] = data - if rand.Intn(4) == 0 { - destructs[h] = struct{}{} - } if rand.Intn(2) == 0 { accStorage := make(map[common.Hash][]byte) value := make([]byte, 32) @@ -54,7 +50,7 @@ func TestAccountIteratorBasics(t *testing.T) { } } // Add some (identical) layers on top - diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage)) + diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage)) it := diffLayer.AccountIterator(common.Hash{}) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator @@ -95,15 +91,15 @@ func TestStorageIteratorBasics(t *testing.T) { nilStorage[h] = nilstorage } // Add some (identical) layers on top - diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, nil, copyAccounts(accounts), copyStorage(storage)) + diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage)) for account := range accounts { - it, _ := diffLayer.StorageIterator(account, common.Hash{}) + it := diffLayer.StorageIterator(account, common.Hash{}) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator } diskLayer := diffToDisk(diffLayer) for account := range accounts { - it, _ := diskLayer.StorageIterator(account, common.Hash{}) + it := diskLayer.StorageIterator(account, common.Hash{}) verifyIterator(t, 100-nilStorage[account], it, verifyNothing) // Nil is allowed for single layer iterator } } @@ -225,13 +221,13 @@ func TestAccountIteratorTraversal(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Verify the single and multi-layer iterators @@ -272,19 +268,19 @@ func TestStorageIteratorTraversal(t *testing.T) { }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) // Verify the single and multi-layer iterators head := snaps.Snapshot(common.HexToHash("0x04")) - diffIter, _ := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{}) + diffIter := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 3, diffIter, verifyNothing) verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage) @@ -357,14 +353,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil) + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), a, nil) + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), b, nil) + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), c, nil) + snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), d, nil) + snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), e, nil) + snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), f, nil) + snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), g, nil) + snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), h, nil) it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -456,14 +452,14 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa"), wrapStorage(a)) + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xaa"), wrapStorage(b)) + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xaa"), wrapStorage(c)) + snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), randomAccountSet("0xaa"), wrapStorage(d)) + snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), randomAccountSet("0xaa"), wrapStorage(e)) + snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), randomAccountSet("0xaa"), wrapStorage(e)) + snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), randomAccountSet("0xaa"), wrapStorage(g)) + snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), randomAccountSet("0xaa"), wrapStorage(h)) it, _ := snaps.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0x09")) @@ -526,7 +522,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) { }, } for i := 1; i < 128; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil) } // Iterate the entire stack and ensure everything is hit only once head := snaps.Snapshot(common.HexToHash("0x80")) @@ -584,13 +580,13 @@ func testAccountIteratorFlattening(t *testing.T, newIterator func(snaps *Tree, r }, } // Create a stack of diffs on top - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Create an iterator and flatten the data from underneath it @@ -630,13 +626,13 @@ func testAccountIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, s base.root: base, }, } - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Account set is now @@ -708,13 +704,13 @@ func testStorageIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, a }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil)) // Account set is now @@ -785,21 +781,16 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), - nil, randomAccountSet("0x11", "0x22", "0x33"), nil) - - deleted := common.HexToHash("0x22") - destructed := map[common.Hash]struct{}{ - deleted: {}, - } - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), - destructed, randomAccountSet("0x11", "0x33"), nil) + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0x11", "0x22", "0x33"), nil) + set := randomAccountSet("0x11", "0x33") + set[common.HexToHash("0x22")] = nil + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), set, nil) snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), - nil, randomAccountSet("0x33", "0x44", "0x55"), nil) + randomAccountSet("0x33", "0x44", "0x55"), nil) // The output should be 11,33,44,55 - it := newIterator(snaps, common.HexToHash("0x04"), (common.Hash{})) + it := newIterator(snaps, common.HexToHash("0x04"), common.Hash{}) // Do a quick check verifyIterator(t, 4, it, verifyAccount) @@ -813,8 +804,8 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro if it.Account() == nil { t.Errorf("iterator returned nil-value for hash %x", hash) } - if hash == deleted { - t.Errorf("expected deleted elem %x to not be returned by iterator", deleted) + if hash == common.HexToHash("0x22") { + t.Errorf("expected deleted elem %x to not be returned by iterator", common.HexToHash("0x22")) } } } @@ -846,10 +837,10 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro }, } // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, + snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}})) // The output should be 02,04,05,06 @@ -863,17 +854,16 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro it.Release() // Destruct the whole storage - destructed := map[common.Hash]struct{}{ - common.HexToHash("0xaa"): {}, - } - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil) + snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), + map[common.Hash][]byte{common.HexToHash("0xaa"): nil}, + randomStorageSet([]string{"0xaa"}, nil, [][]string{{"0x02", "0x04", "0x05", "0x06"}})) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 0, it, verifyStorage) it.Release() // Re-insert the slots of the same account - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, + snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil)) // The output should be 07,08,09 @@ -883,7 +873,9 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro it.Release() // Destruct the whole storage but re-create the account in the same layer - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) + snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), + randomAccountSet("0xaa"), + randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}})) it = newIterator(snaps, common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 it.Release() @@ -928,7 +920,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) { }, } for i := 1; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. @@ -1023,9 +1015,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { base.root: base, }, } - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) + snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), makeAccounts(2000), nil) for i := 2; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) + snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(20), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 8513e73dd..61552c73f 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -33,7 +33,9 @@ import ( "github.com/ethereum/go-ethereum/triedb" ) -const journalVersion uint64 = 0 +// 0: initial version +// 1: destruct flag in diff layer is removed +const journalVersion uint64 = 1 // journalGenerator is a disk layer entry containing the generator progress marker. type journalGenerator struct { @@ -48,11 +50,6 @@ type journalGenerator struct { Storage uint64 } -// journalDestruct is an account deletion entry in a diffLayer's disk journal. -type journalDestruct struct { - Hash common.Hash -} - // journalAccount is an account entry in a diffLayer's disk journal. type journalAccount struct { Hash common.Hash @@ -109,8 +106,8 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou // is not matched with disk layer; or the it's the legacy-format journal, // etc.), we just discard all diffs and try to recover them later. var current snapshot = base - err := iterateJournal(db, func(parent common.Hash, root common.Hash, destructSet map[common.Hash]struct{}, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error { - current = newDiffLayer(current, root, destructSet, accountData, storageData) + err := iterateJournal(db, func(parent common.Hash, root common.Hash, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error { + current = newDiffLayer(current, root, accountData, storageData) return nil }) if err != nil { @@ -238,16 +235,12 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) { if err := rlp.Encode(buffer, dl.root); err != nil { return common.Hash{}, err } - destructs := make([]journalDestruct, 0, len(dl.destructSet)) - for hash := range dl.destructSet { - destructs = append(destructs, journalDestruct{Hash: hash}) - } - if err := rlp.Encode(buffer, destructs); err != nil { - return common.Hash{}, err - } accounts := make([]journalAccount, 0, len(dl.accountData)) for hash, blob := range dl.accountData { - accounts = append(accounts, journalAccount{Hash: hash, Blob: blob}) + accounts = append(accounts, journalAccount{ + Hash: hash, + Blob: blob, + }) } if err := rlp.Encode(buffer, accounts); err != nil { return common.Hash{}, err @@ -271,7 +264,7 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) { // journalCallback is a function which is invoked by iterateJournal, every // time a difflayer is loaded from disk. -type journalCallback = func(parent common.Hash, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error +type journalCallback = func(parent common.Hash, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error // iterateJournal iterates through the journalled difflayers, loading them from // the database, and invoking the callback for each loaded layer. @@ -310,10 +303,8 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { for { var ( root common.Hash - destructs []journalDestruct accounts []journalAccount storage []journalStorage - destructSet = make(map[common.Hash]struct{}) accountData = make(map[common.Hash][]byte) storageData = make(map[common.Hash]map[common.Hash][]byte) ) @@ -325,18 +316,12 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { } return fmt.Errorf("load diff root: %v", err) } - if err := r.Decode(&destructs); err != nil { - return fmt.Errorf("load diff destructs: %v", err) - } if err := r.Decode(&accounts); err != nil { return fmt.Errorf("load diff accounts: %v", err) } if err := r.Decode(&storage); err != nil { return fmt.Errorf("load diff storage: %v", err) } - for _, entry := range destructs { - destructSet[entry.Hash] = struct{}{} - } for _, entry := range accounts { if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that accountData[entry.Hash] = entry.Blob @@ -355,7 +340,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { } storageData[entry.Hash] = slots } - if err := callback(parent, root, destructSet, accountData, storageData); err != nil { + if err := callback(parent, root, accountData, storageData); err != nil { return err } parent = root diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index d1ffb5cc2..7466f1235 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -130,7 +130,7 @@ type snapshot interface { // the specified data items. // // Note, the maps are retained by the method to avoid copying everything. - Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer + Update(blockRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer // Journal commits an entire diff hierarchy to disk into a single journal entry. // This is meant to be used during shutdown to persist the snapshot without @@ -145,7 +145,7 @@ type snapshot interface { AccountIterator(seek common.Hash) AccountIterator // StorageIterator creates a storage iterator over an arbitrary layer. - StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) + StorageIterator(account common.Hash, seek common.Hash) StorageIterator } // Config includes the configurations for snapshots. @@ -335,7 +335,7 @@ func (t *Tree) Snapshots(root common.Hash, limits int, nodisk bool) []Snapshot { // Update adds a new snapshot into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). -func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { +func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { // Reject noop updates to avoid self-loops in the snapshot tree. This is a // special case that can only happen for Clique networks where empty blocks // don't modify the state (0 block subsidy). @@ -350,7 +350,7 @@ func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs m if parent == nil { return fmt.Errorf("parent [%#x] snapshot missing", parentRoot) } - snap := parent.(snapshot).Update(blockRoot, destructs, accounts, storage) + snap := parent.(snapshot).Update(blockRoot, accounts, storage) // Save the new snapshot for later t.lock.Lock() @@ -539,35 +539,6 @@ func diffToDisk(bottom *diffLayer) *diskLayer { base.stale = true base.lock.Unlock() - // Destroy all the destructed accounts from the database - for hash := range bottom.destructSet { - // Skip any account not covered yet by the snapshot - if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 { - continue - } - // Remove all storage slots - rawdb.DeleteAccountSnapshot(batch, hash) - base.cache.Set(hash[:], nil) - - it := rawdb.IterateStorageSnapshots(base.diskdb, hash) - for it.Next() { - key := it.Key() - batch.Delete(key) - base.cache.Del(key[1:]) - snapshotFlushStorageItemMeter.Mark(1) - - // Ensure we don't delete too much data blindly (contract can be - // huge). It's ok to flush, the root will go missing in case of a - // crash and we'll detect and regenerate the snapshot. - if batch.ValueSize() > 64*1024*1024 { - if err := batch.Write(); err != nil { - log.Crit("Failed to write storage deletions", "err", err) - } - batch.Reset() - } - } - it.Release() - } // Push all updated accounts into the database for hash, data := range bottom.accountData { // Skip any account not covered yet by the snapshot @@ -575,10 +546,14 @@ func diffToDisk(bottom *diffLayer) *diskLayer { continue } // Push the account to disk - rawdb.WriteAccountSnapshot(batch, hash, data) - base.cache.Set(hash[:], data) - snapshotCleanAccountWriteMeter.Mark(int64(len(data))) - + if len(data) != 0 { + rawdb.WriteAccountSnapshot(batch, hash, data) + base.cache.Set(hash[:], data) + snapshotCleanAccountWriteMeter.Mark(int64(len(data))) + } else { + rawdb.DeleteAccountSnapshot(batch, hash) + base.cache.Set(hash[:], nil) + } snapshotFlushAccountItemMeter.Mark(1) snapshotFlushAccountSizeMeter.Mark(int64(len(data))) @@ -587,7 +562,7 @@ func diffToDisk(bottom *diffLayer) *diskLayer { // the snapshot. if batch.ValueSize() > 64*1024*1024 { if err := batch.Write(); err != nil { - log.Crit("Failed to write storage deletions", "err", err) + log.Crit("Failed to write state changes", "err", err) } batch.Reset() } @@ -616,6 +591,16 @@ func diffToDisk(bottom *diffLayer) *diskLayer { } snapshotFlushStorageItemMeter.Mark(1) snapshotFlushStorageSizeMeter.Mark(int64(len(data))) + + // Ensure we don't write too much data blindly. It's ok to flush, the + // root will go missing in case of a crash and we'll detect and regen + // the snapshot. + if batch.ValueSize() > 64*1024*1024 { + if err := batch.Write(); err != nil { + log.Crit("Failed to write state changes", "err", err) + } + batch.Reset() + } } } // Update the snapshot block marker and write any remainder data diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index a9ab3eaea..34ef61e8d 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -107,7 +107,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 2 { @@ -151,10 +151,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 3 { @@ -203,13 +203,13 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { + if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := len(snaps.layers); n != 4 { @@ -263,12 +263,12 @@ func TestPostCapBasicDataAccess(t *testing.T) { }, } // The lowest difflayer - snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) - snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) - snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) + snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), setAccount("0xa1"), nil) + snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), setAccount("0xa2"), nil) + snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), setAccount("0xb2"), nil) - snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) - snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) + snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), setAccount("0xa3"), nil) + snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), setAccount("0xb3"), nil) // checkExist verifies if an account exists in a snapshot checkExist := func(layer *diffLayer, key string) error { @@ -363,7 +363,7 @@ func TestSnaphots(t *testing.T) { ) for i := 0; i < 129; i++ { head = makeRoot(uint64(i + 2)) - snaps.Update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil) + snaps.Update(head, last, setAccount(fmt.Sprintf("%d", i+2)), nil) last = head snaps.Cap(head, 128) // 130 layers (128 diffs + 1 accumulator + 1 disk) } @@ -456,9 +456,9 @@ func TestReadStateDuringFlattening(t *testing.T) { }, } // 4 layers in total, 3 diff layers and 1 disk layers - snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) - snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) - snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) + snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), setAccount("0xa1"), nil) + snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), setAccount("0xa2"), nil) + snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), setAccount("0xa3"), nil) // Obtain the topmost snapshot handler for state accessing snap := snaps.Snapshot(common.HexToHash("0xa3")) diff --git a/core/state/snapshot/utils.go b/core/state/snapshot/utils.go index 62f073d2e..c35c82f67 100644 --- a/core/state/snapshot/utils.go +++ b/core/state/snapshot/utils.go @@ -75,7 +75,7 @@ func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error { func checkDanglingMemStorage(db ethdb.KeyValueStore) error { start := time.Now() log.Info("Checking dangling journalled storage") - err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { + err := iterateJournal(db, func(pRoot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { for accHash := range storage { if _, ok := accounts[accHash]; !ok { log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accHash), "root", root) @@ -119,12 +119,11 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { } var depth = 0 - return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { + return iterateJournal(db, func(pRoot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { _, a := accounts[hash] - _, b := destructs[hash] - _, c := storage[hash] + _, b := storage[hash] depth++ - if !a && !b && !c { + if !a && !b { return nil } fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot) @@ -138,9 +137,6 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { fmt.Printf("\taccount.root: %x\n", account.Root) fmt.Printf("\taccount.codehash: %x\n", account.CodeHash) } - if _, ok := destructs[hash]; ok { - fmt.Printf("\t Destructed!") - } if data, ok := storage[hash]; ok { fmt.Printf("\tStorage\n") for k, v := range data { diff --git a/core/state/statedb.go b/core/state/statedb.go index d855e5626..9cc91c933 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -932,16 +932,17 @@ func (s *StateDB) clearJournalAndRefund() { // of a specific account. It leverages the associated state snapshot for fast // storage iteration and constructs trie node deletion markers by creating // stack trie with iterated slots. -func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) { iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) if err != nil { - return nil, nil, err + return nil, nil, nil, err } defer iter.Release() var ( - nodes = trienode.NewNodeSet(addrHash) - slots = make(map[common.Hash][]byte) + nodes = trienode.NewNodeSet(addrHash) // the set for trie node mutations (value is nil) + storages = make(map[common.Hash][]byte) // the set for storage mutations (value is nil) + storageOrigins = make(map[common.Hash][]byte) // the set for tracking the original value of slot ) stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { nodes.AddNode(path, trienode.NewDeleted()) @@ -949,42 +950,47 @@ func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, for iter.Next() { slot := common.CopyBytes(iter.Slot()) if err := iter.Error(); err != nil { // error might occur after Slot function - return nil, nil, err + return nil, nil, nil, err } - slots[iter.Hash()] = slot + key := iter.Hash() + storages[key] = nil + storageOrigins[key] = slot - if err := stack.Update(iter.Hash().Bytes(), slot); err != nil { - return nil, nil, err + if err := stack.Update(key.Bytes(), slot); err != nil { + return nil, nil, nil, err } } if err := iter.Error(); err != nil { // error might occur during iteration - return nil, nil, err + return nil, nil, nil, err } if stack.Hash() != root { - return nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) + return nil, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) } - return slots, nodes, nil + return storages, storageOrigins, nodes, nil } // slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage," // employed when the associated state snapshot is not available. It iterates the // storage slots along with all internal trie nodes via trie directly. -func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) { tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie) if err != nil { - return nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) + return nil, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) } it, err := tr.NodeIterator(nil) if err != nil { - return nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) + return nil, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) } var ( - nodes = trienode.NewNodeSet(addrHash) - slots = make(map[common.Hash][]byte) + nodes = trienode.NewNodeSet(addrHash) // the set for trie node mutations (value is nil) + storages = make(map[common.Hash][]byte) // the set for storage mutations (value is nil) + storageOrigins = make(map[common.Hash][]byte) // the set for tracking the original value of slot ) for it.Next(true) { if it.Leaf() { - slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) + key := common.BytesToHash(it.LeafKey()) + storages[key] = nil + storageOrigins[key] = common.CopyBytes(it.LeafBlob()) continue } if it.Hash() == (common.Hash{}) { @@ -993,35 +999,36 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r nodes.AddNode(it.Path(), trienode.NewDeleted()) } if err := it.Error(); err != nil { - return nil, nil, err + return nil, nil, nil, err } - return slots, nodes, nil + return storages, storageOrigins, nodes, nil } // deleteStorage is designed to delete the storage trie of a designated account. // The function will make an attempt to utilize an efficient strategy if the // associated state snapshot is reachable; otherwise, it will resort to a less // efficient approach. -func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { +func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) { var ( - err error - slots map[common.Hash][]byte - nodes *trienode.NodeSet + err error + nodes *trienode.NodeSet // the set for trie node mutations (value is nil) + storages map[common.Hash][]byte // the set for storage mutations (value is nil) + storageOrigins map[common.Hash][]byte // the set for tracking the original value of slot ) // The fast approach can be failed if the snapshot is not fully // generated, or it's internally corrupted. Fallback to the slow // one just in case. snaps := s.db.Snapshot() if snaps != nil { - slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root) + storages, storageOrigins, nodes, err = s.fastDeleteStorage(snaps, addrHash, root) } if snaps == nil || err != nil { - slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) + storages, storageOrigins, nodes, err = s.slowDeleteStorage(addr, addrHash, root) } if err != nil { - return nil, nil, err + return nil, nil, nil, err } - return slots, nodes, nil + return storages, storageOrigins, nodes, nil } // handleDestruction processes all destruction markers and deletes the account @@ -1068,16 +1075,16 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno deletes[addrHash] = op // Short circuit if the origin storage was empty. - if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() { continue } // Remove storage slots belonging to the account. - slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) + storages, storagesOrigin, set, err := s.deleteStorage(addr, addrHash, prev.Root) if err != nil { return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err) } - op.storagesOrigin = slots + op.storages = storages + op.storagesOrigin = storagesOrigin // Aggregate the associated trie node changes. nodes = append(nodes, set) @@ -1267,7 +1274,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU // If snapshotting is enabled, update the snapshot tree with this new version if snap := s.db.Snapshot(); snap != nil && snap.Snapshot(ret.originRoot) != nil { start := time.Now() - if err := snap.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { + if err := snap.Update(ret.root, ret.originRoot, ret.accounts, ret.storages); err != nil { log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err) } // Keep 128 diff layers in the memory, persistent layer is 129th. diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 90250819e..7cbfd9b9d 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "math" "math/rand" "reflect" @@ -176,24 +177,16 @@ func (test *stateTest) String() string { func (test *stateTest) run() bool { var ( - roots []common.Hash - accountList []map[common.Address][]byte - storageList []map[common.Address]map[common.Hash][]byte - copyUpdate = func(update *stateUpdate) { - accounts := make(map[common.Address][]byte, len(update.accountsOrigin)) - for key, val := range update.accountsOrigin { - accounts[key] = common.CopyBytes(val) - } - accountList = append(accountList, accounts) - - storages := make(map[common.Address]map[common.Hash][]byte, len(update.storagesOrigin)) - for addr, subset := range update.storagesOrigin { - storages[addr] = make(map[common.Hash][]byte, len(subset)) - for key, val := range subset { - storages[addr][key] = common.CopyBytes(val) - } - } - storageList = append(storageList, storages) + roots []common.Hash + accounts []map[common.Hash][]byte + accountOrigin []map[common.Address][]byte + storages []map[common.Hash]map[common.Hash][]byte + storageOrigin []map[common.Address]map[common.Hash][]byte + copyUpdate = func(update *stateUpdate) { + accounts = append(accounts, maps.Clone(update.accounts)) + accountOrigin = append(accountOrigin, maps.Clone(update.accountsOrigin)) + storages = append(storages, maps.Clone(update.storages)) + storageOrigin = append(storageOrigin, maps.Clone(update.storagesOrigin)) } disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults}) @@ -250,7 +243,7 @@ func (test *stateTest) run() bool { if i != 0 { root = roots[i-1] } - test.err = test.verify(root, roots[i], tdb, accountList[i], storageList[i]) + test.err = test.verify(root, roots[i], tdb, accounts[i], accountOrigin[i], storages[i], storageOrigin[i]) if test.err != nil { return false } @@ -265,7 +258,7 @@ func (test *stateTest) run() bool { // - the account was indeed not present in trie // - the account is present in new trie, nil->nil is regarded as invalid // - the slots transition is correct -func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, slots map[common.Hash][]byte) error { +func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, account []byte, storages map[common.Hash][]byte, storagesOrigin map[common.Hash][]byte) error { // Verify account change addrHash := crypto.Keccak256Hash(addr.Bytes()) oBlob, err := otr.Get(addrHash.Bytes()) @@ -282,6 +275,13 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa if len(nBlob) == 0 { return fmt.Errorf("missing account in new trie, %x", addrHash) } + full, err := types.FullAccountRLP(account) + if err != nil { + return err + } + if !bytes.Equal(nBlob, full) { + return fmt.Errorf("unexpected account data, want: %v, got: %v", full, nBlob) + } // Verify storage changes var nAcct types.StateAccount @@ -290,7 +290,10 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa } // Account has no slot, empty slot set is expected if nAcct.Root == types.EmptyRootHash { - if len(slots) != 0 { + if len(storagesOrigin) != 0 { + return fmt.Errorf("unexpected slot changes %x", addrHash) + } + if len(storages) != 0 { return fmt.Errorf("unexpected slot changes %x", addrHash) } return nil @@ -300,9 +303,22 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa if err != nil { return err } - for key, val := range slots { + for key, val := range storagesOrigin { + if _, exist := storages[key]; !exist { + return errors.New("storage data is not found") + } + got, err := st.Get(key.Bytes()) + if err != nil { + return err + } + if !bytes.Equal(got, storages[key]) { + return fmt.Errorf("unexpected storage data, want: %v, got: %v", storages[key], got) + } st.Update(key.Bytes(), val) } + if len(storagesOrigin) != len(storages) { + return fmt.Errorf("extra storage found, want: %d, got: %d", len(storagesOrigin), len(storages)) + } if st.Hash() != types.EmptyRootHash { return errors.New("invalid slot changes") } @@ -316,7 +332,7 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa // - the account was indeed present in trie // - the account in old trie matches the provided value // - the slots transition is correct -func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, origin []byte, slots map[common.Hash][]byte) error { +func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, account []byte, accountOrigin []byte, storages map[common.Hash][]byte, storageOrigin map[common.Hash][]byte) error { // Verify account change addrHash := crypto.Keccak256Hash(addr.Bytes()) oBlob, err := otr.Get(addrHash.Bytes()) @@ -330,14 +346,23 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database if len(oBlob) == 0 { return fmt.Errorf("missing account in old trie, %x", addrHash) } - full, err := types.FullAccountRLP(origin) + full, err := types.FullAccountRLP(accountOrigin) if err != nil { return err } if !bytes.Equal(full, oBlob) { return fmt.Errorf("account value is not matched, %x", addrHash) } - + if len(nBlob) == 0 { + if len(account) != 0 { + return errors.New("unexpected account data") + } + } else { + full, _ = types.FullAccountRLP(account) + if !bytes.Equal(full, nBlob) { + return fmt.Errorf("unexpected account data, %x, want %v, got: %v", addrHash, full, nBlob) + } + } // Decode accounts var ( oAcct types.StateAccount @@ -361,16 +386,29 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database if err != nil { return err } - for key, val := range slots { + for key, val := range storageOrigin { + if _, exist := storages[key]; !exist { + return errors.New("storage data is not found") + } + got, err := st.Get(key.Bytes()) + if err != nil { + return err + } + if !bytes.Equal(got, storages[key]) { + return fmt.Errorf("unexpected storage data, want: %v, got: %v", storages[key], got) + } st.Update(key.Bytes(), val) } + if len(storageOrigin) != len(storages) { + return fmt.Errorf("extra storage found, want: %d, got: %d", len(storageOrigin), len(storages)) + } if st.Hash() != oAcct.Root { return errors.New("invalid slot changes") } return nil } -func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Database, accountsOrigin map[common.Address][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error { +func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Database, accounts map[common.Hash][]byte, accountsOrigin map[common.Address][]byte, storages map[common.Hash]map[common.Hash][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error { otr, err := trie.New(trie.StateTrieID(root), db) if err != nil { return err @@ -379,12 +417,15 @@ func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Dat if err != nil { return err } - for addr, account := range accountsOrigin { - var err error - if len(account) == 0 { - err = test.verifyAccountCreation(next, db, otr, ntr, addr, storagesOrigin[addr]) + for addr, accountOrigin := range accountsOrigin { + var ( + err error + addrHash = crypto.Keccak256Hash(addr.Bytes()) + ) + if len(accountOrigin) == 0 { + err = test.verifyAccountCreation(next, db, otr, ntr, addr, accounts[addrHash], storages[addrHash], storagesOrigin[addr]) } else { - err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accountsOrigin[addr], storagesOrigin[addr]) + err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accounts[addrHash], accountsOrigin[addr], storages[addrHash], storagesOrigin[addr]) } if err != nil { return err diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 3647397df..57886e6e0 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -1305,12 +1305,12 @@ func TestDeleteStorage(t *testing.T) { obj := fastState.getOrNewStateObject(addr) storageRoot := obj.data.Root - _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) if err != nil { t.Fatal(err) } - _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) + _, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) if err != nil { t.Fatal(err) } diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go index c9231f052..a320b72f1 100644 --- a/core/state/stateupdate.go +++ b/core/state/stateupdate.go @@ -17,6 +17,8 @@ package state import ( + "maps" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie/trienode" @@ -33,6 +35,7 @@ type contractCode struct { type accountDelete struct { address common.Address // address is the unique account identifier origin []byte // origin is the original value of account data in slim-RLP encoding. + storages map[common.Hash][]byte // storages stores mutated slots, the value should be nil. storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. } @@ -52,7 +55,6 @@ type accountUpdate struct { type stateUpdate struct { originRoot common.Hash // hash of the state before applying mutation root common.Hash // hash of the state after applying mutation - destructs map[common.Hash]struct{} // destructs contains the list of destructed accounts accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format @@ -71,7 +73,6 @@ func (sc *stateUpdate) empty() bool { // account deletions and account updates to form a comprehensive state update. func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate { var ( - destructs = make(map[common.Hash]struct{}) accounts = make(map[common.Hash][]byte) accountsOrigin = make(map[common.Address][]byte) storages = make(map[common.Hash]map[common.Hash][]byte) @@ -82,8 +83,12 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common // within the same block, the deletions must be aggregated first. for addrHash, op := range deletes { addr := op.address - destructs[addrHash] = struct{}{} + accounts[addrHash] = nil accountsOrigin[addr] = op.origin + + if len(op.storages) > 0 { + storages[addrHash] = op.storages + } if len(op.storagesOrigin) > 0 { storagesOrigin[addr] = op.storagesOrigin } @@ -95,35 +100,41 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common if op.code != nil { codes[addr] = *op.code } - // Aggregate the account changes. The original account value will only - // be tracked if it's not present yet. accounts[addrHash] = op.data + + // Aggregate the account original value. If the account is already + // present in the aggregated accountsOrigin set, skip it. if _, found := accountsOrigin[addr]; !found { accountsOrigin[addr] = op.origin } - // Aggregate the storage changes. The original storage slot value will - // only be tracked if it's not present yet. + // Aggregate the storage mutation list. If a slot in op.storages is + // already present in aggregated storages set, the value will be + // overwritten. if len(op.storages) > 0 { - storages[addrHash] = op.storages + if _, exist := storages[addrHash]; !exist { + storages[addrHash] = op.storages + } else { + maps.Copy(storages[addrHash], op.storages) + } } + // Aggregate the storage original values. If the slot is already present + // in aggregated storagesOrigin set, skip it. if len(op.storagesOrigin) > 0 { - origin := storagesOrigin[addr] - if origin == nil { + origin, exist := storagesOrigin[addr] + if !exist { storagesOrigin[addr] = op.storagesOrigin - continue - } - for key, slot := range op.storagesOrigin { - if _, found := origin[key]; !found { - origin[key] = slot + } else { + for key, slot := range op.storagesOrigin { + if _, found := origin[key]; !found { + origin[key] = slot + } } } - storagesOrigin[addr] = origin } } return &stateUpdate{ originRoot: types.TrieRootHash(originRoot), root: types.TrieRootHash(root), - destructs: destructs, accounts: accounts, accountsOrigin: accountsOrigin, storages: storages, @@ -139,7 +150,6 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common // package. func (sc *stateUpdate) stateSet() *triedb.StateSet { return &triedb.StateSet{ - Destructs: sc.destructs, Accounts: sc.accounts, AccountsOrigin: sc.accountsOrigin, Storages: sc.storages, diff --git a/triedb/states.go b/triedb/states.go index 1f9a0de52..0b03f2b9f 100644 --- a/triedb/states.go +++ b/triedb/states.go @@ -23,7 +23,6 @@ import ( // StateSet represents a collection of mutated states during a state transition. type StateSet struct { - Destructs map[common.Hash]struct{} // Destructed accounts Accounts map[common.Hash][]byte // Mutated accounts in 'slim RLP' encoding AccountsOrigin map[common.Address][]byte // Original values of mutated accounts in 'slim RLP' encoding Storages map[common.Hash]map[common.Hash][]byte // Mutated storage slots in 'prefix-zero-trimmed' RLP format @@ -33,7 +32,6 @@ type StateSet struct { // NewStateSet initializes an empty state set. func NewStateSet() *StateSet { return &StateSet{ - Destructs: make(map[common.Hash]struct{}), Accounts: make(map[common.Hash][]byte), AccountsOrigin: make(map[common.Address][]byte), Storages: make(map[common.Hash]map[common.Hash][]byte), From 9e0a9089922a9d132272ce6c9c1b746c14be9988 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Mon, 25 Nov 2024 03:09:38 +0800 Subject: [PATCH 008/354] internal/flags: fix "flag redefined" bug for alias on custom flags (#30796) This change fixes a bug on the `DirectoryFlag` and the `BigFlag`, which would trigger a `panic` with the message "flag redefined" in case an alias was added to such a flag. --- internal/flags/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 1f6be3d3d..b858e73d0 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -90,7 +90,7 @@ func (f *DirectoryFlag) Apply(set *flag.FlagSet) error { } } eachName(f, func(name string) { - set.Var(&f.Value, f.Name, f.Usage) + set.Var(&f.Value, name, f.Usage) }) return nil } @@ -172,7 +172,7 @@ func (f *BigFlag) Apply(set *flag.FlagSet) error { } eachName(f, func(name string) { f.Value = new(big.Int) - set.Var((*bigValue)(f.Value), f.Name, f.Usage) + set.Var((*bigValue)(f.Value), name, f.Usage) }) return nil } From 6a112f4c298d188782c19a7d49aafe7a6103848b Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 25 Nov 2024 10:07:50 +0100 Subject: [PATCH 009/354] eth/tracers/logger: fix json-logger output missing (#30804) Fixes a flaw introduced in https://github.com/ethereum/go-ethereum/pull/29795 , discovered while reviewing https://github.com/ethereum/go-ethereum/pull/30633 . --- eth/tracers/logger/logger_json.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 797f7ac65..52ac3945d 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -71,7 +71,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { l.hooks = &tracing.Hooks{ OnTxStart: l.OnTxStart, OnSystemCallStart: l.onSystemCallStart, - OnExit: l.OnEnd, + OnExit: l.OnExit, OnOpcode: l.OnOpcode, OnFault: l.OnFault, } @@ -152,13 +152,6 @@ func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common l.encoder.Encode(frame) } -func (l *jsonLogger) OnEnd(depth int, output []byte, gasUsed uint64, err error, reverted bool) { - if depth > 0 { - return - } - l.OnExit(depth, output, gasUsed, err, false) -} - func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { type endLog struct { Output string `json:"output"` From 206e862c7357a24014000ab1aa2cb5a70837fc86 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 25 Nov 2024 13:29:27 +0100 Subject: [PATCH 010/354] eth/tracers/logger: improve markdown logger (#30805) This PR improves the output of the markdown logger a bit. - Remove `RStack` field, - Move `Stack` last, since it may have very large vertical expansion - Make the pre- and post-exec metadata structured into a bullet-list --- eth/tracers/logger/logger.go | 37 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index f918ce154..bdd4e0705 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -363,26 +363,35 @@ func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.A if depth != 0 { return } - create := vm.OpCode(typ) == vm.CREATE - if !create { - fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", - from.String(), to.String(), - input, gas, value) + if create := vm.OpCode(typ) == vm.CREATE; !create { + fmt.Fprintf(t.out, "Pre-execution info:\n"+ + " - from: `%v`\n"+ + " - to: `%v`\n"+ + " - data: `%#x`\n"+ + " - gas: `%d`\n"+ + " - value: `%v` wei\n", + from.String(), to.String(), input, gas, value) } else { - fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", - from.String(), to.String(), - input, gas, value) + fmt.Fprintf(t.out, "Pre-execution info:\n"+ + " - from: `%v`\n"+ + " - create: `%v`\n"+ + " - data: `%#x`\n"+ + " - gas: `%d`\n"+ + " - value: `%v` wei\n", + from.String(), to.String(), input, gas, value) } - fmt.Fprintf(t.out, ` -| Pc | Op | Cost | Stack | RStack | Refund | -|-------|-------------|------|-----------|-----------|---------| +| Pc | Op | Cost | Refund | Stack | +|-------|-------------|------|-----------|-----------| `) } func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { if depth == 0 { - fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", + fmt.Fprintf(t.out, "\nPost-execution info:\n"+ + " - output: `%#x`\n"+ + " - consumed gas: `%d`\n"+ + " - error: `%v`\n", output, gasUsed, err) } } @@ -390,7 +399,8 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { stack := scope.StackData() - fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, vm.OpCode(op).String(), cost) + fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(), + cost, t.env.StateDB.GetRefund()) if !t.cfg.DisableStack { // format stack @@ -401,7 +411,6 @@ func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing. b := fmt.Sprintf("[%v]", strings.Join(a, ",")) fmt.Fprintf(t.out, "%10v |", b) } - fmt.Fprintf(t.out, "%10v |", t.env.StateDB.GetRefund()) fmt.Fprintln(t.out, "") if err != nil { fmt.Fprintf(t.out, "Error: %v\n", err) From 39156668f363975bb8f0aa9d29a51f18961f7769 Mon Sep 17 00:00:00 2001 From: "Hyunsoo Shin (Lake)" Date: Mon, 25 Nov 2024 21:33:28 +0900 Subject: [PATCH 011/354] internal/ethapi: remove double map-clone (#30803) Similar to https://github.com/ethereum/go-ethereum/pull/30788 --- internal/ethapi/simulate.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 0b58a2709..2161e1d5f 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -21,7 +21,6 @@ import ( "encoding/json" "errors" "fmt" - "maps" "math/big" "time" @@ -186,7 +185,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, Tracer: tracer.Hooks(), } ) - var tracingStateDB = vm.StateDB(sim.state) + tracingStateDB := vm.StateDB(sim.state) if hooks := tracer.Hooks(); hooks != nil { tracingStateDB = state.NewHookedState(sim.state, hooks) } @@ -289,7 +288,7 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra isMerge = (base.Difficulty.Sign() == 0) rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time) ) - return maps.Clone(vm.ActivePrecompiledContracts(rules)) + return vm.ActivePrecompiledContracts(rules) } // sanitizeChain checks the chain integrity. Specifically it checks that From 6709293446f2d8ad99929359f574e3189306dd35 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Mon, 25 Nov 2024 06:34:50 -0600 Subject: [PATCH 012/354] accounts/abi: fix MakeTopics mutation of big.Int inputs (#30785) #28764 updated `func MakeTopics` to support negative `*big.Int`s. However, it also changed the behavior of the function from just _reading_ the input `*big.Int` via `Bytes()`, to leveraging `big.U256Bytes` which is documented as being _destructive_: This change updates `MakeTopics` to not mutate the original, and also applies the same change in signer/core/apitypes. --- accounts/abi/topics.go | 2 +- accounts/abi/topics_test.go | 17 +++++++++++++++++ signer/core/apitypes/types.go | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/accounts/abi/topics.go b/accounts/abi/topics.go index 7ce9b7273..4819334ae 100644 --- a/accounts/abi/topics.go +++ b/accounts/abi/topics.go @@ -42,7 +42,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) { case common.Address: copy(topic[common.HashLength-common.AddressLength:], rule[:]) case *big.Int: - copy(topic[:], math.U256Bytes(rule)) + copy(topic[:], math.U256Bytes(new(big.Int).Set(rule))) case bool: if rule { topic[common.HashLength-1] = 1 diff --git a/accounts/abi/topics_test.go b/accounts/abi/topics_test.go index 6a4c50078..161867e2d 100644 --- a/accounts/abi/topics_test.go +++ b/accounts/abi/topics_test.go @@ -149,6 +149,23 @@ func TestMakeTopics(t *testing.T) { } }) } + + t.Run("does not mutate big.Int", func(t *testing.T) { + t.Parallel() + want := [][]common.Hash{{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}} + + in := big.NewInt(-1) + got, err := MakeTopics([]interface{}{in}) + if err != nil { + t.Fatalf("makeTopics() error = %v", err) + } + if !reflect.DeepEqual(got, want) { + t.Fatalf("makeTopics() = %v, want %v", got, want) + } + if orig := big.NewInt(-1); in.Cmp(orig) != 0 { + t.Fatalf("makeTopics() mutated an input parameter from %v to %v", orig, in) + } + }) } type args struct { diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 2ae182279..b56931c1d 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -676,7 +676,7 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf if err != nil { return nil, err } - return math.U256Bytes(b), nil + return math.U256Bytes(new(big.Int).Set(b)), nil } return nil, fmt.Errorf("unrecognized type '%s'", encType) } From e7157080c7487557bd434f670312920399592cfe Mon Sep 17 00:00:00 2001 From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:43:23 +0000 Subject: [PATCH 013/354] core/state/snapshot: simplify snapshot rebuild (#30772) This PR is purely for improved readability; I was doing work involving the file and think this may help others who are trying to understand what's going on. 1. `snapshot.Tree.Rebuild()` now returns a function that blocks until regeneration is complete, allowing `Tree.waitBuild()` to be removed entirely as all it did was search for the `done` channel behind this new function. 2. Its usage inside `New()` is also simplified by (a) only waiting if `!AsyncBuild`; and (b) avoiding the double negative of `if !NoBuild`. --------- Co-authored-by: Martin HS --- core/state/snapshot/snapshot.go | 48 ++++++++++----------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 7466f1235..181dc6b74 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -206,47 +206,24 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo log.Warn("Snapshot maintenance disabled (syncing)") return snap, nil } - // Create the building waiter iff the background generation is allowed - if !config.NoBuild && !config.AsyncBuild { - defer snap.waitBuild() - } if err != nil { log.Warn("Failed to load snapshot", "err", err) - if !config.NoBuild { - snap.Rebuild(root) - return snap, nil + if config.NoBuild { + return nil, err + } + wait := snap.Rebuild(root) + if !config.AsyncBuild { + wait() } - return nil, err // Bail out the error, don't rebuild automatically. + return snap, nil } // Existing snapshot loaded, seed all the layers - for head != nil { + for ; head != nil; head = head.Parent() { snap.layers[head.Root()] = head - head = head.Parent() } return snap, nil } -// waitBuild blocks until the snapshot finishes rebuilding. This method is meant -// to be used by tests to ensure we're testing what we believe we are. -func (t *Tree) waitBuild() { - // Find the rebuild termination channel - var done chan struct{} - - t.lock.RLock() - for _, layer := range t.layers { - if layer, ok := layer.(*diskLayer); ok { - done = layer.genPending - break - } - } - t.lock.RUnlock() - - // Wait until the snapshot is generated - if done != nil { - <-done - } -} - // Disable interrupts any pending snapshot generator, deletes all the snapshot // layers in memory and marks snapshots disabled globally. In order to resume // the snapshot functionality, the caller must invoke Rebuild. @@ -688,8 +665,9 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) { // Rebuild wipes all available snapshot data from the persistent database and // discard all caches and diff layers. Afterwards, it starts a new snapshot -// generator with the given root hash. -func (t *Tree) Rebuild(root common.Hash) { +// generator with the given root hash. The returned function blocks until +// regeneration is complete. +func (t *Tree) Rebuild(root common.Hash) (wait func()) { t.lock.Lock() defer t.lock.Unlock() @@ -721,9 +699,11 @@ func (t *Tree) Rebuild(root common.Hash) { // Start generating a new snapshot from scratch on a background thread. The // generator will run a wiper first if there's not one running right now. log.Info("Rebuilding state snapshot") + disk := generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root) t.layers = map[common.Hash]snapshot{ - root: generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root), + root: disk, } + return func() { <-disk.genPending } } // AccountIterator creates a new account iterator for the specified root hash and From bd0ee43ec823bea78af1469f25c460bdd19bbf6b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 26 Nov 2024 02:49:12 +0100 Subject: [PATCH 014/354] eth/ethconfig: improve error message if TTD missing (#30807) This updates the message you get when trying to initialize Geth with genesis.json that doesn't have `terminalTotalDifficulty`. The previous message was a bit obscure, I had to check the code to find out what the problem was. --- eth/ethconfig/config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 76a8c5a04..ad681f688 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" ) @@ -195,7 +196,8 @@ func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database, statis return bft, nil } if config.TerminalTotalDifficulty == nil { - return nil, fmt.Errorf("only PoS networks are supported, please transition old ones with Geth v1.13.x") + log.Error("Geth only supports PoS networks. Please transition legacy networks using Geth v1.13.x.") + return nil, fmt.Errorf("'terminalTotalDifficulty' is not set in genesis block") } // If proof-of-authority is requested, set it up if config.Clique != nil { From d97caa6f28f948743f2c2d3548e0ee2e5e681bb9 Mon Sep 17 00:00:00 2001 From: Nebojsa Urosevic Date: Mon, 25 Nov 2024 23:16:00 -0800 Subject: [PATCH 015/354] core/tracing: add GetCodeHash to StateDB (#30784) This PR extends the tracing.StateDB interface by adding a GetCodeHash function. --- core/tracing/hooks.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index a21bb1577..0c5cae354 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -42,6 +42,7 @@ type StateDB interface { GetBalance(common.Address) *uint256.Int GetNonce(common.Address) uint64 GetCode(common.Address) []byte + GetCodeHash(common.Address) common.Hash GetState(common.Address, common.Hash) common.Hash GetTransientState(common.Address, common.Hash) common.Hash Exist(common.Address) bool From 96224ddde24013bf239b0272d786ecc11f13dc52 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 26 Nov 2024 18:33:59 +0800 Subject: [PATCH 016/354] Revert "core/state/snapshot: simplify snapshot rebuild (#30772)" (#30810) This reverts commit 23800122b37695be50565f8221858a16ce1763db. The original pull request introduces a bug and some flaky tests are detected because of this flaw. ``` --- FAIL: TestRecoverSnapshotFromWipingCrash (0.27s) blockchain_snapshot_test.go:158: The disk layer is not integrated snapshot is not constructed {"pc":0,"op":88,"gas":"0x7148","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PC"} {"pc":1,"op":255,"gas":"0x7146","gasCost":"0x1db0","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SELFDESTRUCT"} {"output":"","gasUsed":"0x0"} {"output":"","gasUsed":"0x1db2"} {"pc":0,"op":116,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH21"} ``` Before the original PR, the snapshot would block the function until the disk layer was fully generated under the following conditions: (a) explicitly required by users with `AsyncBuild = false`. (b) the snapshot was being fully rebuilt or *the disk layer generation had resumed*. Unfortunately, with the changes introduced in that PR, the snapshot no longer waits for disk layer generation to complete if the generation is resumed. It brings lots of uncertainty and breaks this tiny debug feature. --- core/state/snapshot/snapshot.go | 48 +++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 181dc6b74..7466f1235 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -206,24 +206,47 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo log.Warn("Snapshot maintenance disabled (syncing)") return snap, nil } + // Create the building waiter iff the background generation is allowed + if !config.NoBuild && !config.AsyncBuild { + defer snap.waitBuild() + } if err != nil { log.Warn("Failed to load snapshot", "err", err) - if config.NoBuild { - return nil, err - } - wait := snap.Rebuild(root) - if !config.AsyncBuild { - wait() + if !config.NoBuild { + snap.Rebuild(root) + return snap, nil } - return snap, nil + return nil, err // Bail out the error, don't rebuild automatically. } // Existing snapshot loaded, seed all the layers - for ; head != nil; head = head.Parent() { + for head != nil { snap.layers[head.Root()] = head + head = head.Parent() } return snap, nil } +// waitBuild blocks until the snapshot finishes rebuilding. This method is meant +// to be used by tests to ensure we're testing what we believe we are. +func (t *Tree) waitBuild() { + // Find the rebuild termination channel + var done chan struct{} + + t.lock.RLock() + for _, layer := range t.layers { + if layer, ok := layer.(*diskLayer); ok { + done = layer.genPending + break + } + } + t.lock.RUnlock() + + // Wait until the snapshot is generated + if done != nil { + <-done + } +} + // Disable interrupts any pending snapshot generator, deletes all the snapshot // layers in memory and marks snapshots disabled globally. In order to resume // the snapshot functionality, the caller must invoke Rebuild. @@ -665,9 +688,8 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) { // Rebuild wipes all available snapshot data from the persistent database and // discard all caches and diff layers. Afterwards, it starts a new snapshot -// generator with the given root hash. The returned function blocks until -// regeneration is complete. -func (t *Tree) Rebuild(root common.Hash) (wait func()) { +// generator with the given root hash. +func (t *Tree) Rebuild(root common.Hash) { t.lock.Lock() defer t.lock.Unlock() @@ -699,11 +721,9 @@ func (t *Tree) Rebuild(root common.Hash) (wait func()) { // Start generating a new snapshot from scratch on a background thread. The // generator will run a wiper first if there's not one running right now. log.Info("Rebuilding state snapshot") - disk := generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root) t.layers = map[common.Hash]snapshot{ - root: disk, + root: generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root), } - return func() { <-disk.genPending } } // AccountIterator creates a new account iterator for the specified root hash and From 266cb8c8c15694ecde777c026bcaa4b1c9ade328 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 26 Nov 2024 22:12:38 +0700 Subject: [PATCH 017/354] cmd/evm: don't reuse state between iterations, show errors (#30780) Reusing state between benchmark iterations resulted in inconsistent results across runs, which surfaced in https://github.com/ethereum/go-ethereum/issues/30778 . If these errors are triggered again, they will now trigger panic. --------- Co-authored-by: Martin HS --- cmd/evm/runner.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 8c382e625..2884487fa 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -84,19 +84,20 @@ type execStats struct { func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, execStats, error) { if bench { + testing.Init() // Do one warm-up run output, gasUsed, err := execFunc() result := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { haveOutput, haveGasUsed, haveErr := execFunc() if !bytes.Equal(haveOutput, output) { - b.Fatalf("output differs, have\n%x\nwant%x\n", haveOutput, output) + panic(fmt.Sprintf("output differs\nhave %x\nwant %x\n", haveOutput, output)) } if haveGasUsed != gasUsed { - b.Fatalf("gas differs, have %v want%v", haveGasUsed, gasUsed) + panic(fmt.Sprintf("gas differs, have %v want %v", haveGasUsed, gasUsed)) } if haveErr != err { - b.Fatalf("err differs, have %v want%v", haveErr, err) + panic(fmt.Sprintf("err differs, have %v want %v", haveErr, err)) } } }) @@ -137,7 +138,7 @@ func runCmd(ctx *cli.Context) error { var ( tracer *tracing.Hooks debugLogger *logger.StructLogger - statedb *state.StateDB + prestate *state.StateDB chainConfig *params.ChainConfig sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) @@ -174,7 +175,7 @@ func runCmd(ctx *cli.Context) error { defer triedb.Close() genesis := genesisConfig.MustCommit(db, triedb) sdb := state.NewDatabase(triedb, nil) - statedb, _ = state.New(genesis.Root(), sdb) + prestate, _ = state.New(genesis.Root(), sdb) chainConfig = genesisConfig.Config if ctx.String(SenderFlag.Name) != "" { @@ -231,7 +232,7 @@ func runCmd(ctx *cli.Context) error { } runtimeConfig := runtime.Config{ Origin: sender, - State: statedb, + State: prestate, GasLimit: initialGas, GasPrice: flags.GlobalBig(ctx, PriceFlag.Name), Value: flags.GlobalBig(ctx, ValueFlag.Name), @@ -274,14 +275,18 @@ func runCmd(ctx *cli.Context) error { if ctx.Bool(CreateFlag.Name) { input = append(code, input...) execFunc = func() ([]byte, uint64, error) { + // don't mutate the state! + runtimeConfig.State = prestate.Copy() output, _, gasLeft, err := runtime.Create(input, &runtimeConfig) return output, gasLeft, err } } else { if len(code) > 0 { - statedb.SetCode(receiver, code) + prestate.SetCode(receiver, code) } execFunc = func() ([]byte, uint64, error) { + // don't mutate the state! + runtimeConfig.State = prestate.Copy() output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig) return output, initialGas - gasLeft, err } @@ -291,7 +296,7 @@ func runCmd(ctx *cli.Context) error { output, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { - root, err := statedb.Commit(genesisConfig.Number, true) + root, err := runtimeConfig.State.Commit(genesisConfig.Number, true) if err != nil { fmt.Printf("Failed to commit changes %v\n", err) return err @@ -310,7 +315,7 @@ func runCmd(ctx *cli.Context) error { logger.WriteTrace(os.Stderr, debugLogger.StructLogs()) } fmt.Fprintln(os.Stderr, "#### LOGS ####") - logger.WriteLogs(os.Stderr, statedb.Logs()) + logger.WriteLogs(os.Stderr, runtimeConfig.State.Logs()) } if bench || ctx.Bool(StatDumpFlag.Name) { From aa80ae274d8f0134b1f84d5b5ec56a0a2f953efc Mon Sep 17 00:00:00 2001 From: wangjingcun Date: Wed, 27 Nov 2024 14:17:03 +0800 Subject: [PATCH 018/354] core: better document reason for dropping error on return (#30811) Add a comment for error return of nil Signed-off-by: wangjingcun --- core/blockchain_reader.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index b9bb5e77a..badd15b84 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -293,6 +293,13 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo if tx == nil { progress, err := bc.TxIndexProgress() if err != nil { + // No error is returned if the transaction indexing progress is unreachable + // due to unexpected internal errors. In such cases, it is impossible to + // determine whether the transaction does not exist or has simply not been + // indexed yet without a progress marker. + // + // In such scenarios, the transaction is treated as unreachable, though + // this is clearly an unintended and unexpected situation. return nil, nil, nil } // The transaction indexing is not finished yet, returning an From 035c62198e9e382de01f3f9f35cbdf11a4761322 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 28 Nov 2024 11:21:31 +0800 Subject: [PATCH 019/354] core/state/snapshot: handle legacy journal (#30802) This workaround is meant to minimize the possibility for snapshot generation once the geth node upgrades to new version (specifically #30752 ) In #30752, the journal format in state snapshot is modified by removing the destruct set. Therefore, the existing old format (version = 0) will be discarded and all in-memory layers will be lost. Unfortunately, the lost in-memory layers can't be recovered by some other approaches, and the entire state snapshot will be regenerated (it will last about 2.5 hours). This pull request introduces a workaround to adopt the legacy journal if the destruct set contained is empty. Since self-destruction has been deprecated following the cancun fork, the destruct set is expected to be nil for layers above the fork block. However, an exception occurs during contract deployment: pre-funded accounts may self-destruct, causing accounts with non-zero balances to be removed from the state. For example, https://etherscan.io/tx/0xa087333d83f0cd63b96bdafb686462e1622ce25f40bd499e03efb1051f31fe49). For nodes with a fully synced state, the legacy journal is likely compatible with the updated definition, eliminating the need for regeneration. Unfortunately, nodes performing a full sync of historical chain segments or encountering pre-funded account deletions may face incompatibilities, leading to automatic snapshot regeneration. --- core/state/snapshot/journal.go | 47 +++++++++++++++++++++++++++++---- core/state/snapshot/snapshot.go | 2 +- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 61552c73f..e4b396b99 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -33,9 +33,11 @@ import ( "github.com/ethereum/go-ethereum/triedb" ) -// 0: initial version -// 1: destruct flag in diff layer is removed -const journalVersion uint64 = 1 +const ( + journalV0 uint64 = 0 // initial version + journalV1 uint64 = 1 // current version, with destruct flag (in diff layers) removed + journalCurrentVersion = journalV1 +) // journalGenerator is a disk layer entry containing the generator progress marker. type journalGenerator struct { @@ -50,6 +52,11 @@ type journalGenerator struct { Storage uint64 } +// journalDestruct is an account deletion entry in a diffLayer's disk journal. +type journalDestruct struct { + Hash common.Hash +} + // journalAccount is an account entry in a diffLayer's disk journal. type journalAccount struct { Hash common.Hash @@ -285,8 +292,8 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { log.Warn("Failed to resolve the journal version", "error", err) return errors.New("failed to resolve journal version") } - if version != journalVersion { - log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) + if version != journalV0 && version != journalCurrentVersion { + log.Warn("Discarded journal with wrong version", "required", journalCurrentVersion, "got", version) return errors.New("wrong journal version") } // Secondly, resolve the disk layer root, ensure it's continuous @@ -316,6 +323,36 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { } return fmt.Errorf("load diff root: %v", err) } + // If a legacy journal is detected, decode the destruct set from the stream. + // The destruct set has been deprecated. If the journal contains non-empty + // destruct set, then it is deemed incompatible. + // + // Since self-destruction has been deprecated following the cancun fork, + // the destruct set is expected to be nil for layers above the fork block. + // However, an exception occurs during contract deployment: pre-funded accounts + // may self-destruct, causing accounts with non-zero balances to be removed + // from the state. For example, + // https://etherscan.io/tx/0xa087333d83f0cd63b96bdafb686462e1622ce25f40bd499e03efb1051f31fe49). + // + // For nodes with a fully synced state, the legacy journal is likely compatible + // with the updated definition, eliminating the need for regeneration. Unfortunately, + // nodes performing a full sync of historical chain segments or encountering + // pre-funded account deletions may face incompatibilities, leading to automatic + // snapshot regeneration. + // + // This approach minimizes snapshot regeneration for Geth nodes upgrading from a + // legacy version that are already synced. The workaround can be safely removed + // after the next hard fork. + if version == journalV0 { + var destructs []journalDestruct + if err := r.Decode(&destructs); err != nil { + return fmt.Errorf("load diff destructs: %v", err) + } + if len(destructs) > 0 { + log.Warn("Incompatible legacy journal detected", "version", journalV0) + return fmt.Errorf("incompatible legacy journal detected") + } + } if err := r.Decode(&accounts); err != nil { return fmt.Errorf("load diff accounts: %v", err) } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 7466f1235..f0f629643 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -664,7 +664,7 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) { // Firstly write out the metadata of journal journal := new(bytes.Buffer) - if err := rlp.Encode(journal, journalVersion); err != nil { + if err := rlp.Encode(journal, journalCurrentVersion); err != nil { return common.Hash{}, err } diskroot := t.diskRoot() From 101583477f0cca790010fd3ae5f058f792dd5e3f Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:17:58 +0700 Subject: [PATCH 020/354] trie: combine validation loops in VerifyRangeProof (#30823) Small optimization. It's guaranteed that `len(keys)` == `len(values)`, so we can combine the checks in a single loop rather than 2 separate loops. --- trie/proof.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/trie/proof.go b/trie/proof.go index 40836fba3..2e527348b 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -486,13 +486,11 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)) } // Ensure the received batch is monotonic increasing and contains no deletions - for i := 0; i < len(keys)-1; i++ { - if bytes.Compare(keys[i], keys[i+1]) >= 0 { + for i := 0; i < len(keys); i++ { + if i < len(keys)-1 && bytes.Compare(keys[i], keys[i+1]) >= 0 { return false, errors.New("range is not monotonically increasing") } - } - for _, value := range values { - if len(value) == 0 { + if len(values[i]) == 0 { return false, errors.New("range contains deletion") } } From 8eb16262dc630dfad1e8bfaecd91fcb8b6c7da82 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 28 Nov 2024 11:48:50 +0100 Subject: [PATCH 021/354] all: exclude empty outputs in requests commitment (#30670) Implements changes from these spec PRs: - https://github.com/ethereum/EIPs/pull/8989 - https://github.com/ethereum/execution-apis/pull/599 --- beacon/engine/types.go | 21 +-------- cmd/evm/internal/t8ntool/execution.go | 16 +++---- core/chain_makers.go | 15 +++---- core/genesis.go | 4 +- core/state_processor.go | 43 ++++++++++--------- core/types/hashes.go | 3 ++ eth/tracers/internal/tracetest/supply_test.go | 2 +- ...h_getBlockReceipts-block-with-blob-tx.json | 2 +- ...eceipts-block-with-contract-create-tx.json | 2 +- ...ockReceipts-block-with-dynamic-fee-tx.json | 2 +- ...ts-block-with-legacy-contract-call-tx.json | 4 +- ...eceipts-block-with-legacy-transfer-tx.json | 2 +- .../eth_getBlockReceipts-tag-latest.json | 2 +- .../eth_getTransactionReceipt-blob-tx.json | 2 +- ...TransactionReceipt-create-contract-tx.json | 2 +- ...eipt-create-contract-with-access-list.json | 2 +- ...ansactionReceipt-dynamic-tx-with-logs.json | 2 +- ...TransactionReceipt-normal-transfer-tx.json | 2 +- .../eth_getTransactionReceipt-with-logs.json | 4 +- miner/worker.go | 16 +++---- 20 files changed, 62 insertions(+), 86 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 9f41aa04c..984090ef8 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -265,15 +265,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H var requestsHash *common.Hash if requests != nil { - // Put back request type byte. - typedRequests := make([][]byte, len(requests)) - for i, reqdata := range requests { - typedReqdata := make([]byte, len(reqdata)+1) - typedReqdata[0] = byte(i) - copy(typedReqdata[1:], reqdata) - typedRequests[i] = typedReqdata - } - h := types.CalcRequestsHash(typedRequests) + h := types.CalcRequestsHash(requests) requestsHash = &h } @@ -343,20 +335,11 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. } } - // Remove type byte in requests. - var plainRequests [][]byte - if requests != nil { - plainRequests = make([][]byte, len(requests)) - for i, reqdata := range requests { - plainRequests[i] = reqdata[1:] - } - } - return &ExecutionPayloadEnvelope{ ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, - Requests: plainRequests, + Requests: requests, Override: false, } } diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 1a4d52242..9aeb5ada8 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -375,21 +375,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Gather the execution-layer triggered requests. var requests [][]byte if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) { - // EIP-6110 deposits + requests = [][]byte{} + // EIP-6110 var allLogs []*types.Log for _, receipt := range receipts { allLogs = append(allLogs, receipt.Logs...) } - depositRequests, err := core.ParseDepositLogs(allLogs, chainConfig) - if err != nil { + if err := core.ParseDepositLogs(&requests, allLogs, chainConfig); err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) } - requests = append(requests, depositRequests) - - // EIP-7002 withdrawals - requests = append(requests, core.ProcessWithdrawalQueue(evm)) - // EIP-7251 consolidations - requests = append(requests, core.ProcessConsolidationQueue(evm)) + // EIP-7002 + core.ProcessWithdrawalQueue(&requests, evm) + // EIP-7251 + core.ProcessConsolidationQueue(&requests, evm) } // Commit block diff --git a/core/chain_makers.go b/core/chain_makers.go index e679a9e55..97c785d52 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -349,25 +349,22 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse var requests [][]byte if config.IsPrague(b.header.Number, b.header.Time) { + requests = [][]byte{} // EIP-6110 deposits var blockLogs []*types.Log for _, r := range b.receipts { blockLogs = append(blockLogs, r.Logs...) } - depositRequests, err := ParseDepositLogs(blockLogs, config) - if err != nil { + if err := ParseDepositLogs(&requests, blockLogs, config); err != nil { panic(fmt.Sprintf("failed to parse deposit log: %v", err)) } - requests = append(requests, depositRequests) // create EVM for system calls blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(evm) - requests = append(requests, withdrawalRequests) - // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(evm) - requests = append(requests, consolidationRequests) + // EIP-7002 + ProcessWithdrawalQueue(&requests, evm) + // EIP-7251 + ProcessConsolidationQueue(&requests, evm) } if requests != nil { reqHash := types.CalcRequestsHash(requests) diff --git a/core/genesis.go b/core/genesis.go index bda82db94..6e3cdcd00 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -503,9 +503,7 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { } } if conf.IsPrague(num, g.Timestamp) { - emptyRequests := [][]byte{{0x00}, {0x01}, {0x02}} - rhash := types.CalcRequestsHash(emptyRequests) - head.RequestsHash = &rhash + head.RequestsHash = &types.EmptyRequestsHash } } return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) diff --git a/core/state_processor.go b/core/state_processor.go index 15e56c3b3..34e718a6b 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -124,18 +124,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Read requests if Prague is enabled. var requests [][]byte if p.config.IsPrague(block.Number(), block.Time()) { - // EIP-6110 deposits - depositRequests, err := ParseDepositLogs(allLogs, p.config) - if err != nil { + requests = [][]byte{} + // EIP-6110 + if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil { return nil, err } - requests = append(requests, depositRequests) - // EIP-7002 withdrawals - withdrawalRequests := ProcessWithdrawalQueue(evm) - requests = append(requests, withdrawalRequests) - // EIP-7251 consolidations - consolidationRequests := ProcessConsolidationQueue(evm) - requests = append(requests, consolidationRequests) + // EIP-7002 + ProcessWithdrawalQueue(&requests, evm) + // EIP-7251 + ProcessConsolidationQueue(&requests, evm) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) @@ -289,17 +286,17 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. // It returns the opaque request data returned by the contract. -func ProcessWithdrawalQueue(evm *vm.EVM) []byte { - return processRequestsSystemCall(evm, 0x01, params.WithdrawalQueueAddress) +func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) { + processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress) } // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract. // It returns the opaque request data returned by the contract. -func ProcessConsolidationQueue(evm *vm.EVM) []byte { - return processRequestsSystemCall(evm, 0x02, params.ConsolidationQueueAddress) +func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) { + processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) } -func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Address) []byte { +func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) { if tracer := evm.Config.Tracer; tracer != nil { if tracer.OnSystemCallStart != nil { tracer.OnSystemCallStart() @@ -320,28 +317,34 @@ func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Addres evm.StateDB.AddAddressToAccessList(addr) ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) evm.StateDB.Finalise(true) + if len(ret) == 0 { + return // skip empty output + } - // Create withdrawals requestsData with prefix 0x01 + // Append prefixed requestsData to the requests list. requestsData := make([]byte, len(ret)+1) requestsData[0] = requestType copy(requestsData[1:], ret) - return requestsData + *requests = append(*requests, requestsData) } // ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by // BeaconDepositContract. -func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) { +func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error { deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type) for _, log := range logs { if log.Address == config.DepositContractAddress { request, err := types.DepositLogToRequest(log.Data) if err != nil { - return nil, fmt.Errorf("unable to parse deposit data: %v", err) + return fmt.Errorf("unable to parse deposit data: %v", err) } deposits = append(deposits, request...) } } - return deposits, nil + if len(deposits) > 1 { + *requests = append(*requests, deposits) + } + return nil } // ProcessOnPersist applies a system call to the governance contract. diff --git a/core/types/hashes.go b/core/types/hashes.go index 43e9130fd..55506d63d 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -41,6 +41,9 @@ var ( // EmptyWithdrawalsHash is the known hash of the empty withdrawal set. EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + // EmptyRequestsHash is the known hash of an empty request set, sha256(""). + EmptyRequestsHash = common.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") + // EmptyVerkleHash is the known hash of an empty verkle trie. EmptyVerkleHash = common.Hash{} ) diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 19fdcf9f6..8bd84d9ce 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -86,7 +86,7 @@ func TestSupplyOmittedFields(t *testing.T) { expected := supplyInfo{ Number: 0, - Hash: common.HexToHash("0xc02ee8ee5b54a40e43f0fa827d431e1bd4f217e941790dda10b2521d1925a20b"), + Hash: common.HexToHash("0x3055fc27d6b4a08eb07033a0d1ee755a4b2988086f28a6189eac1b507525eeb1"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), } actual := out[expected.Number] diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json index d315353ec..df2d9349f 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json @@ -2,7 +2,7 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d", + "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-contract-create-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-contract-create-tx.json index f2e5ced2b..453e0abe8 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-contract-create-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-contract-create-tx.json @@ -1,6 +1,6 @@ [ { - "blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1", + "blockHash": "0xb3e447c77374fd285964cba692e96b1673a88a959726826b5b6e2dca15472b0a", "blockNumber": "0x2", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "cumulativeGasUsed": "0xcf50", diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json index 71afd85e5..b01400e60 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json @@ -1,6 +1,6 @@ [ { - "blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d", + "blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3", "blockNumber": "0x4", "contractAddress": null, "cumulativeGasUsed": "0x538d", diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-contract-call-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-contract-call-tx.json index f089ac45a..ae964b3d3 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-contract-call-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-contract-call-tx.json @@ -1,6 +1,6 @@ [ { - "blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f", + "blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa", "blockNumber": "0x3", "contractAddress": null, "cumulativeGasUsed": "0x5e28", @@ -19,7 +19,7 @@ "blockNumber": "0x3", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionIndex": "0x0", - "blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f", + "blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa", "logIndex": "0x0", "removed": false } diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-transfer-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-transfer-tx.json index 8b69dddd6..7af501607 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-transfer-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-legacy-transfer-tx.json @@ -1,6 +1,6 @@ [ { - "blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9", + "blockHash": "0xe9bd1d8c303b1af5c704b9d78e62c54a34af47e0db04ac1389a5ef74a619b9da", "blockNumber": "0x1", "contractAddress": null, "cumulativeGasUsed": "0x5208", diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json index d315353ec..df2d9349f 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json @@ -2,7 +2,7 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d", + "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json index 5debbd444..8e0669d10 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json @@ -1,7 +1,7 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d", + "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-tx.json b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-tx.json index 8cf2ead10..a9391cb57 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-tx.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-tx.json @@ -1,5 +1,5 @@ { - "blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1", + "blockHash": "0xb3e447c77374fd285964cba692e96b1673a88a959726826b5b6e2dca15472b0a", "blockNumber": "0x2", "contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592", "cumulativeGasUsed": "0xcf50", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json index 34c318fac..49c06aad6 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json @@ -1,5 +1,5 @@ { - "blockHash": "0xa04ad6be58c45fe483991b89416572bc50426b0de44b769757e95c704250f874", + "blockHash": "0x53bffe54375c0a31fe7bc0db7455db7d48278234c2400efa4d40d1c57cbe868d", "blockNumber": "0x5", "contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18", "cumulativeGasUsed": "0xe01c", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json index 9f023ed6e..13bd7bd12 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json @@ -1,5 +1,5 @@ { - "blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d", + "blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3", "blockNumber": "0x4", "contractAddress": null, "cumulativeGasUsed": "0x538d", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-normal-transfer-tx.json b/internal/ethapi/testdata/eth_getTransactionReceipt-normal-transfer-tx.json index f180a2197..779223af9 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-normal-transfer-tx.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-normal-transfer-tx.json @@ -1,5 +1,5 @@ { - "blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9", + "blockHash": "0xe9bd1d8c303b1af5c704b9d78e62c54a34af47e0db04ac1389a5ef74a619b9da", "blockNumber": "0x1", "contractAddress": null, "cumulativeGasUsed": "0x5208", diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-with-logs.json b/internal/ethapi/testdata/eth_getTransactionReceipt-with-logs.json index 61aed4b7b..1a1edb788 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-with-logs.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-with-logs.json @@ -1,5 +1,5 @@ { - "blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f", + "blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa", "blockNumber": "0x3", "contractAddress": null, "cumulativeGasUsed": "0x5e28", @@ -18,7 +18,7 @@ "blockNumber": "0x3", "transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287", "transactionIndex": "0x0", - "blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f", + "blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa", "logIndex": "0x0", "removed": false } diff --git a/miner/worker.go b/miner/worker.go index 4126e191d..c2148e308 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1111,21 +1111,15 @@ func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadR // Collect consensus-layer requests if Prague is enabled. var requests [][]byte if w.chainConfig.IsPrague(work.header.Number, work.header.Time) { + requests = [][]byte{} // EIP-6110 deposits - depositRequests, err := core.ParseDepositLogs(allLogs, w.chainConfig) - if err != nil { + if err := core.ParseDepositLogs(&requests, allLogs, w.chainConfig); err != nil { return &newPayloadResult{err: err} } - requests = append(requests, depositRequests) - // create EVM for system calls - blockContext := core.NewEVMBlockContext(work.header, w.chain, &work.header.Coinbase) - vmenv := vm.NewEVM(blockContext, work.state, w.chainConfig, vm.Config{}) - // EIP-7002 withdrawals - withdrawalRequests := core.ProcessWithdrawalQueue(vmenv) - requests = append(requests, withdrawalRequests) + // EIP-7002 + core.ProcessWithdrawalQueue(&requests, work.evm) // EIP-7251 consolidations - consolidationRequests := core.ProcessConsolidationQueue(vmenv) - requests = append(requests, consolidationRequests) + core.ProcessConsolidationQueue(&requests, work.evm) } if requests != nil { reqHash := types.CalcRequestsHash(requests) From dd330a74abd8be834d0a57e78ce80ee18ddd53ac Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 28 Nov 2024 18:43:39 +0100 Subject: [PATCH 022/354] core/types: add length check in CalcRequestsHash (#30829) The existing implementation is correct when building and verifying blocks, since we will only collect non-empty requests into the block requests list. But it isn't correct for cases where a requests list containing empty items is sent by the consensus layer on the engine API. We want to ensure that empty requests do not cause a difference in validation there, so the commitment computation should explicitly skip them. --- core/types/block.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index c9e8bb045..62c49d7fb 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -479,9 +479,11 @@ func CalcRequestsHash(requests [][]byte) common.Hash { h1, h2 := sha256.New(), sha256.New() var buf common.Hash for _, item := range requests { - h1.Reset() - h1.Write(item) - h2.Write(h1.Sum(buf[:0])) + if len(item) > 1 { // skip items with only requestType and no data. + h1.Reset() + h1.Write(item) + h2.Write(h1.Sum(buf[:0])) + } } h2.Sum(buf[:0]) return buf From be456e5a54b28de856d730d3660e41a06c7e5c6c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 29 Nov 2024 19:30:45 +0800 Subject: [PATCH 023/354] triedb/pathdb: track flat state changes in pathdb (snapshot integration pt 2) (#30643) This pull request ports some changes from the main state snapshot integration one, specifically introducing the flat state tracking in pathdb. Note, the tracked flat state changes are only held in memory and won't be persisted in the disk. Meanwhile, the correspoding state retrieval in persistent state is also not supported yet. The states management in disk is more complicated and will be implemented in a separate pull request. Part 1: https://github.com/ethereum/go-ethereum/pull/30752 --- triedb/database.go | 11 + triedb/hashdb/database.go | 6 + triedb/pathdb/buffer.go | 36 ++- triedb/pathdb/database.go | 39 ++- triedb/pathdb/database_test.go | 2 +- triedb/pathdb/difflayer.go | 53 ++++ triedb/pathdb/difflayer_test.go | 8 +- triedb/pathdb/disklayer.go | 100 ++++++- triedb/pathdb/journal.go | 16 +- triedb/pathdb/metrics.go | 23 +- triedb/pathdb/nodes.go | 4 +- triedb/pathdb/reader.go | 53 +++- triedb/pathdb/states.go | 393 ++++++++++++++++++++++++++- triedb/pathdb/states_test.go | 453 ++++++++++++++++++++++++++++++++ triedb/states.go | 2 +- 15 files changed, 1149 insertions(+), 50 deletions(-) create mode 100644 triedb/pathdb/states_test.go diff --git a/triedb/database.go b/triedb/database.go index d3eca57b5..b448d7cd0 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -60,6 +60,10 @@ type backend interface { // An error will be returned if the specified state is not available. NodeReader(root common.Hash) (database.NodeReader, error) + // StateReader returns a reader for accessing flat states within the specified + // state. An error will be returned if the specified state is not available. + StateReader(root common.Hash) (database.StateReader, error) + // Initialized returns an indicator if the state data is already initialized // according to the state scheme. Initialized(genesisRoot common.Hash) bool @@ -122,6 +126,13 @@ func (db *Database) NodeReader(blockRoot common.Hash) (database.NodeReader, erro return db.backend.NodeReader(blockRoot) } +// StateReader returns a reader that allows access to the state data associated +// with the specified state. An error will be returned if the specified state is +// not available. +func (db *Database) StateReader(blockRoot common.Hash) (database.StateReader, error) { + return db.backend.StateReader(blockRoot) +} + // Update performs a state transition by committing dirty nodes contained in the // given set in order to update state from the specified parent to the specified // root. The held pre-images accumulated up to this point will be flushed in case diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index 5de7805c3..fb718f4e7 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -635,3 +635,9 @@ func (reader *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([] blob, _ := reader.db.node(hash) return blob, nil } + +// StateReader returns a reader that allows access to the state data associated +// with the specified state. +func (db *Database) StateReader(root common.Hash) (database.StateReader, error) { + return nil, errors.New("not implemented") +} diff --git a/triedb/pathdb/buffer.go b/triedb/pathdb/buffer.go index 3f1d0e90e..68e136f19 100644 --- a/triedb/pathdb/buffer.go +++ b/triedb/pathdb/buffer.go @@ -33,40 +33,56 @@ import ( // must be checked before diving into disk (since it basically is not yet written // data). type buffer struct { - layers uint64 // The number of diff layers aggregated inside - limit uint64 // The maximum memory allowance in bytes - nodes *nodeSet // Aggregated trie node set + layers uint64 // The number of diff layers aggregated inside + limit uint64 // The maximum memory allowance in bytes + nodes *nodeSet // Aggregated trie node set + states *stateSet // Aggregated state set } // newBuffer initializes the buffer with the provided states and trie nodes. -func newBuffer(limit int, nodes *nodeSet, layers uint64) *buffer { +func newBuffer(limit int, nodes *nodeSet, states *stateSet, layers uint64) *buffer { // Don't panic for lazy users if any provided set is nil if nodes == nil { nodes = newNodeSet(nil) } + if states == nil { + states = newStates(nil, nil) + } return &buffer{ layers: layers, limit: uint64(limit), nodes: nodes, + states: states, } } +// account retrieves the account blob with account address hash. +func (b *buffer) account(hash common.Hash) ([]byte, bool) { + return b.states.account(hash) +} + +// storage retrieves the storage slot with account address hash and slot key. +func (b *buffer) storage(addrHash common.Hash, storageHash common.Hash) ([]byte, bool) { + return b.states.storage(addrHash, storageHash) +} + // node retrieves the trie node with node path and its trie identifier. func (b *buffer) node(owner common.Hash, path []byte) (*trienode.Node, bool) { return b.nodes.node(owner, path) } // commit merges the provided states and trie nodes into the buffer. -func (b *buffer) commit(nodes *nodeSet) *buffer { +func (b *buffer) commit(nodes *nodeSet, states *stateSet) *buffer { b.layers++ b.nodes.merge(nodes) + b.states.merge(states) return b } -// revert is the reverse operation of commit. It also merges the provided states +// revertTo is the reverse operation of commit. It also merges the provided states // and trie nodes into the buffer. The key difference is that the provided state // set should reverse the changes made by the most recent state transition. -func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node) error { +func (b *buffer) revertTo(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node, accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) error { // Short circuit if no embedded state transition to revert if b.layers == 0 { return errStateUnrecoverable @@ -78,7 +94,8 @@ func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[strin b.reset() return nil } - b.nodes.revert(db, nodes) + b.nodes.revertTo(db, nodes) + b.states.revertTo(accounts, storages) return nil } @@ -86,6 +103,7 @@ func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[strin func (b *buffer) reset() { b.layers = 0 b.nodes.reset() + b.states.reset() } // empty returns an indicator if buffer is empty. @@ -101,7 +119,7 @@ func (b *buffer) full() bool { // size returns the approximate memory size of the held content. func (b *buffer) size() uint64 { - return b.nodes.size + return b.states.size + b.nodes.size } // flush persists the in-memory dirty trie node into the disk if the configured diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 48d46c7b0..cfbdb01c4 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -68,6 +68,24 @@ type layer interface { // - no error will be returned if the requested node is not found in database. node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error) + // account directly retrieves the account RLP associated with a particular + // hash in the slim data format. An error will be returned if the read + // operation exits abnormally. Specifically, if the layer is already stale. + // + // Note: + // - the returned account is not a copy, please don't modify it. + // - no error will be returned if the requested account is not found in database. + account(hash common.Hash, depth int) ([]byte, error) + + // storage directly retrieves the storage data associated with a particular hash, + // within a particular account. An error will be returned if the read operation + // exits abnormally. Specifically, if the layer is already stale. + // + // Note: + // - the returned storage data is not a copy, please don't modify it. + // - no error will be returned if the requested slot is not found in database. + storage(accountHash, storageHash common.Hash, depth int) ([]byte, error) + // rootHash returns the root hash for which this layer was made. rootHash() common.Hash @@ -130,17 +148,18 @@ var Defaults = &Config{ // ReadOnly is the config in order to open database in read only mode. var ReadOnly = &Config{ReadOnly: true} -// Database is a multiple-layered structure for maintaining in-memory trie nodes. -// It consists of one persistent base layer backed by a key-value store, on top -// of which arbitrarily many in-memory diff layers are stacked. The memory diffs -// can form a tree with branching, but the disk layer is singleton and common to -// all. If a reorg goes deeper than the disk layer, a batch of reverse diffs can -// be applied to rollback. The deepest reorg that can be handled depends on the -// amount of state histories tracked in the disk. +// Database is a multiple-layered structure for maintaining in-memory states +// along with its dirty trie nodes. It consists of one persistent base layer +// backed by a key-value store, on top of which arbitrarily many in-memory diff +// layers are stacked. The memory diffs can form a tree with branching, but the +// disk layer is singleton and common to all. If a reorg goes deeper than the +// disk layer, a batch of reverse diffs can be applied to rollback. The deepest +// reorg that can be handled depends on the amount of state histories tracked +// in the disk. // // At most one readable and writable database can be opened at the same time in -// the whole system which ensures that only one database writer can operate disk -// state. Unexpected open operations can cause the system to panic. +// the whole system which ensures that only one database writer can operate the +// persistent state. Unexpected open operations can cause the system to panic. type Database struct { // readOnly is the flag whether the mutation is allowed to be applied. // It will be set automatically when the database is journaled during @@ -358,7 +377,7 @@ func (db *Database) Enable(root common.Hash) error { } // Re-construct a new disk layer backed by persistent state // with **empty clean cache and node buffer**. - db.tree.reset(newDiskLayer(root, 0, db, nil, newBuffer(db.config.WriteBufferSize, nil, 0))) + db.tree.reset(newDiskLayer(root, 0, db, nil, newBuffer(db.config.WriteBufferSize, nil, nil, 0))) // Re-enable the database as the final step. db.waitSync = false diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 61e0b0928..648230df1 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -309,7 +309,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode delete(t.storages, addrHash) } } - return root, ctx.nodes, NewStateSetWithOrigin(ctx.accountOrigin, ctx.storageOrigin) + return root, ctx.nodes, NewStateSetWithOrigin(ctx.accounts, ctx.storages, ctx.accountOrigin, ctx.storageOrigin) } // lastHash returns the latest root hash, or empty if nothing is cached. diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go index ecc318614..c06026b6c 100644 --- a/triedb/pathdb/difflayer.go +++ b/triedb/pathdb/difflayer.go @@ -52,6 +52,7 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes states: states, } dirtyNodeWriteMeter.Mark(int64(nodes.size)) + dirtyStateWriteMeter.Mark(int64(states.size)) log.Debug("Created new diff layer", "id", id, "block", block, "nodesize", common.StorageSize(nodes.size), "statesize", common.StorageSize(states.size)) return dl } @@ -96,6 +97,58 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co return dl.parent.node(owner, path, depth+1) } +// account directly retrieves the account RLP associated with a particular +// hash in the slim data format. +// +// Note the returned account is not a copy, please don't modify it. +func (dl *diffLayer) account(hash common.Hash, depth int) ([]byte, error) { + // Hold the lock, ensure the parent won't be changed during the + // state accessing. + dl.lock.RLock() + defer dl.lock.RUnlock() + + if blob, found := dl.states.account(hash); found { + dirtyStateHitMeter.Mark(1) + dirtyStateHitDepthHist.Update(int64(depth)) + dirtyStateReadMeter.Mark(int64(len(blob))) + + if len(blob) == 0 { + stateAccountInexMeter.Mark(1) + } else { + stateAccountExistMeter.Mark(1) + } + return blob, nil + } + // Account is unknown to this layer, resolve from parent + return dl.parent.account(hash, depth+1) +} + +// storage directly retrieves the storage data associated with a particular hash, +// within a particular account. +// +// Note the returned storage slot is not a copy, please don't modify it. +func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([]byte, error) { + // Hold the lock, ensure the parent won't be changed during the + // state accessing. + dl.lock.RLock() + defer dl.lock.RUnlock() + + if blob, found := dl.states.storage(accountHash, storageHash); found { + dirtyStateHitMeter.Mark(1) + dirtyStateHitDepthHist.Update(int64(depth)) + dirtyStateReadMeter.Mark(int64(len(blob))) + + if len(blob) == 0 { + stateStorageInexMeter.Mark(1) + } else { + stateStorageExistMeter.Mark(1) + } + return blob, nil + } + // storage slot is unknown to this layer, resolve from parent + return dl.parent.storage(accountHash, storageHash, depth+1) +} + // update implements the layer interface, creating a new layer on top of the // existing layer tree with the specified data items. func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer { diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index 61e8b4e06..7176d9964 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -30,7 +30,7 @@ import ( func emptyLayer() *diskLayer { return &diskLayer{ db: New(rawdb.NewMemoryDatabase(), nil, false), - buffer: newBuffer(defaultBufferSize, nil, 0), + buffer: newBuffer(defaultBufferSize, nil, nil, 0), } } @@ -76,7 +76,7 @@ func benchmarkSearch(b *testing.B, depth int, total int) { nblob = common.CopyBytes(blob) } } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) } var layer layer layer = emptyLayer() @@ -118,7 +118,7 @@ func BenchmarkPersist(b *testing.B) { ) nodes[common.Hash{}][string(path)] = node } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) } for i := 0; i < b.N; i++ { b.StopTimer() @@ -156,7 +156,7 @@ func BenchmarkJournal(b *testing.B) { ) nodes[common.Hash{}][string(path)] = node } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), new(StateSetWithOrigin)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) } var layer layer layer = emptyLayer() diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index edbe63096..003431b19 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -17,6 +17,7 @@ package pathdb import ( + "errors" "fmt" "sync" @@ -33,7 +34,7 @@ type diskLayer struct { id uint64 // Immutable, corresponding state id db *Database // Path-based trie database nodes *fastcache.Cache // GC friendly memory cache of clean nodes - buffer *buffer // Dirty buffer to aggregate writes of nodes + buffer *buffer // Dirty buffer to aggregate writes of nodes and states stale bool // Signals that the layer became stale (state progressed) lock sync.RWMutex // Lock used to protect stale flag } @@ -140,6 +141,75 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil } +// account directly retrieves the account RLP associated with a particular +// hash in the slim data format. +// +// Note the returned account is not a copy, please don't modify it. +func (dl *diskLayer) account(hash common.Hash, depth int) ([]byte, error) { + dl.lock.RLock() + defer dl.lock.RUnlock() + + if dl.stale { + return nil, errSnapshotStale + } + // Try to retrieve the account from the not-yet-written + // node buffer first. Note the buffer is lock free since + // it's impossible to mutate the buffer before tagging the + // layer as stale. + blob, found := dl.buffer.account(hash) + if found { + dirtyStateHitMeter.Mark(1) + dirtyStateReadMeter.Mark(int64(len(blob))) + dirtyStateHitDepthHist.Update(int64(depth)) + + if len(blob) == 0 { + stateAccountInexMeter.Mark(1) + } else { + stateAccountExistMeter.Mark(1) + } + return blob, nil + } + dirtyStateMissMeter.Mark(1) + + // TODO(rjl493456442) support persistent state retrieval + return nil, errors.New("not supported") +} + +// storage directly retrieves the storage data associated with a particular hash, +// within a particular account. +// +// Note the returned account is not a copy, please don't modify it. +func (dl *diskLayer) storage(accountHash, storageHash common.Hash, depth int) ([]byte, error) { + // Hold the lock, ensure the parent won't be changed during the + // state accessing. + dl.lock.RLock() + defer dl.lock.RUnlock() + + if dl.stale { + return nil, errSnapshotStale + } + // Try to retrieve the storage slot from the not-yet-written + // node buffer first. Note the buffer is lock free since + // it's impossible to mutate the buffer before tagging the + // layer as stale. + if blob, found := dl.buffer.storage(accountHash, storageHash); found { + dirtyStateHitMeter.Mark(1) + dirtyStateReadMeter.Mark(int64(len(blob))) + dirtyStateHitDepthHist.Update(int64(depth)) + + if len(blob) == 0 { + stateStorageInexMeter.Mark(1) + } else { + stateStorageExistMeter.Mark(1) + } + return blob, nil + } + dirtyStateMissMeter.Mark(1) + + // TODO(rjl493456442) support persistent state retrieval + return nil, errors.New("not supported") +} + // update implements the layer interface, returning a new diff layer on top // with the given state set. func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer { @@ -190,14 +260,14 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { // In a unique scenario where the ID of the oldest history object (after tail // truncation) surpasses the persisted state ID, we take the necessary action - // of forcibly committing the cached dirty nodes to ensure that the persisted + // of forcibly committing the cached dirty states to ensure that the persisted // state ID remains higher. if !force && rawdb.ReadPersistentStateID(dl.db.diskdb) < oldest { force = true } - // Merge the trie nodes of the bottom-most diff layer into the buffer as the - // combined layer. - combined := dl.buffer.commit(bottom.nodes) + // Merge the trie nodes and flat states of the bottom-most diff layer into the + // buffer as the combined layer. + combined := dl.buffer.commit(bottom.nodes, bottom.states.stateSet) if combined.full() || force { if err := combined.flush(dl.db.diskdb, dl.db.freezer, dl.nodes, bottom.stateID()); err != nil { return nil, err @@ -225,6 +295,24 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) { if dl.id == 0 { return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable) } + var ( + buff = crypto.NewKeccakState() + hashes = make(map[common.Address]common.Hash) + accounts = make(map[common.Hash][]byte) + storages = make(map[common.Hash]map[common.Hash][]byte) + ) + for addr, blob := range h.accounts { + hash := crypto.HashData(buff, addr.Bytes()) + hashes[addr] = hash + accounts[hash] = blob + } + for addr, storage := range h.storages { + hash, ok := hashes[addr] + if !ok { + panic(fmt.Errorf("storage history with no account %x", addr)) + } + storages[hash] = storage + } // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. @@ -244,7 +332,7 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) { // needs to be reverted is not yet flushed and cached in node // buffer, otherwise, manipulate persistent state directly. if !dl.buffer.empty() { - err := dl.buffer.revert(dl.db.diskdb, nodes) + err := dl.buffer.revertTo(dl.db.diskdb, nodes, accounts, storages) if err != nil { return nil, err } diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 70fa1fb9f..779a262fd 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -45,7 +45,8 @@ var ( // // - Version 0: initial version // - Version 1: storage.Incomplete field is removed -const journalVersion uint64 = 1 +// - Version 2: add post-modification state values +const journalVersion uint64 = 2 // loadJournal tries to parse the layer journal from the disk. func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { @@ -108,7 +109,7 @@ func (db *Database) loadLayers() layer { log.Info("Failed to load journal, discard it", "err", err) } // Return single layer with persistent state. - return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, newBuffer(db.config.WriteBufferSize, nil, 0)) + return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, newBuffer(db.config.WriteBufferSize, nil, nil, 0)) } // loadDiskLayer reads the binary blob from the layer journal, reconstructing @@ -135,7 +136,12 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) { if err := nodes.decode(r); err != nil { return nil, err } - return newDiskLayer(root, id, db, nil, newBuffer(db.config.WriteBufferSize, &nodes, id-stored)), nil + // Resolve flat state sets in aggregated buffer + var states stateSet + if err := states.decode(r); err != nil { + return nil, err + } + return newDiskLayer(root, id, db, nil, newBuffer(db.config.WriteBufferSize, &nodes, &states, id-stored)), nil } // loadDiffLayer reads the next sections of a layer journal, reconstructing a new @@ -189,6 +195,10 @@ func (dl *diskLayer) journal(w io.Writer) error { if err := dl.buffer.nodes.encode(w); err != nil { return err } + // Step four, write the accumulated flat states into the journal + if err := dl.buffer.states.encode(w); err != nil { + return err + } log.Debug("Journaled pathdb disk layer", "root", dl.root) return nil } diff --git a/triedb/pathdb/metrics.go b/triedb/pathdb/metrics.go index 8897cc445..1a2559e38 100644 --- a/triedb/pathdb/metrics.go +++ b/triedb/pathdb/metrics.go @@ -30,10 +30,21 @@ var ( dirtyNodeWriteMeter = metrics.NewRegisteredMeter("pathdb/dirty/node/write", nil) dirtyNodeHitDepthHist = metrics.NewRegisteredHistogram("pathdb/dirty/node/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) - cleanFalseMeter = metrics.NewRegisteredMeter("pathdb/clean/false", nil) - dirtyFalseMeter = metrics.NewRegisteredMeter("pathdb/dirty/false", nil) - diskFalseMeter = metrics.NewRegisteredMeter("pathdb/disk/false", nil) - diffFalseMeter = metrics.NewRegisteredMeter("pathdb/diff/false", nil) + stateAccountInexMeter = metrics.NewRegisteredMeter("pathdb/state/account/inex/total", nil) + stateStorageInexMeter = metrics.NewRegisteredMeter("pathdb/state/storage/inex/total", nil) + stateAccountExistMeter = metrics.NewRegisteredMeter("pathdb/state/account/exist/total", nil) + stateStorageExistMeter = metrics.NewRegisteredMeter("pathdb/state/storage/exist/total", nil) + + dirtyStateHitMeter = metrics.NewRegisteredMeter("pathdb/dirty/state/hit", nil) + dirtyStateMissMeter = metrics.NewRegisteredMeter("pathdb/dirty/state/miss", nil) + dirtyStateReadMeter = metrics.NewRegisteredMeter("pathdb/dirty/state/read", nil) + dirtyStateWriteMeter = metrics.NewRegisteredMeter("pathdb/dirty/state/write", nil) + dirtyStateHitDepthHist = metrics.NewRegisteredHistogram("pathdb/dirty/state/depth", nil, metrics.NewExpDecaySample(1028, 0.015)) + + nodeCleanFalseMeter = metrics.NewRegisteredMeter("pathdb/clean/false", nil) + nodeDirtyFalseMeter = metrics.NewRegisteredMeter("pathdb/dirty/false", nil) + nodeDiskFalseMeter = metrics.NewRegisteredMeter("pathdb/disk/false", nil) + nodeDiffFalseMeter = metrics.NewRegisteredMeter("pathdb/diff/false", nil) commitTimeTimer = metrics.NewRegisteredTimer("pathdb/commit/time", nil) commitNodesMeter = metrics.NewRegisteredMeter("pathdb/commit/nodes", nil) @@ -41,6 +52,10 @@ var ( gcTrieNodeMeter = metrics.NewRegisteredMeter("pathdb/gc/node/count", nil) gcTrieNodeBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/node/bytes", nil) + gcAccountMeter = metrics.NewRegisteredMeter("pathdb/gc/account/count", nil) + gcAccountBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/account/bytes", nil) + gcStorageMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/count", nil) + gcStorageBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/bytes", nil) historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil) historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil) diff --git a/triedb/pathdb/nodes.go b/triedb/pathdb/nodes.go index ade669512..dee8c872a 100644 --- a/triedb/pathdb/nodes.go +++ b/triedb/pathdb/nodes.go @@ -131,9 +131,9 @@ func (s *nodeSet) merge(set *nodeSet) { s.updateSize(delta) } -// revert merges the provided trie nodes into the set. This should reverse the +// revertTo merges the provided trie nodes into the set. This should reverse the // changes made by the most recent state transition. -func (s *nodeSet) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node) { +func (s *nodeSet) revertTo(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node) { var delta int64 for owner, subset := range nodes { current, ok := s.nodes[owner] diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index 2ca4a0205..4bba813b1 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -21,7 +21,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/triedb/database" ) @@ -66,13 +68,13 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, // is not found. switch loc.loc { case locCleanCache: - cleanFalseMeter.Mark(1) + nodeCleanFalseMeter.Mark(1) case locDirtyCache: - dirtyFalseMeter.Mark(1) + nodeDirtyFalseMeter.Mark(1) case locDiffLayer: - diffFalseMeter.Mark(1) + nodeDiffFalseMeter.Mark(1) case locDiskLayer: - diskFalseMeter.Mark(1) + nodeDiskFalseMeter.Mark(1) } blobHex := "nil" if len(blob) > 0 { @@ -84,6 +86,39 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, return blob, nil } +// Account directly retrieves the account associated with a particular hash in +// the slim data format. An error will be returned if the read operation exits +// abnormally. Specifically, if the layer is already stale. +// +// Note: +// - the returned account object is safe to modify +// - no error will be returned if the requested account is not found in database +func (r *reader) Account(hash common.Hash) (*types.SlimAccount, error) { + blob, err := r.layer.account(hash, 0) + if err != nil { + return nil, err + } + if len(blob) == 0 { + return nil, nil + } + account := new(types.SlimAccount) + if err := rlp.DecodeBytes(blob, account); err != nil { + panic(err) + } + return account, nil +} + +// Storage directly retrieves the storage data associated with a particular hash, +// within a particular account. An error will be returned if the read operation +// exits abnormally. Specifically, if the layer is already stale. +// +// Note: +// - the returned storage data is not a copy, please don't modify it +// - no error will be returned if the requested slot is not found in database +func (r *reader) Storage(accountHash, storageHash common.Hash) ([]byte, error) { + return r.layer.storage(accountHash, storageHash, 0) +} + // NodeReader retrieves a layer belonging to the given state root. func (db *Database) NodeReader(root common.Hash) (database.NodeReader, error) { layer := db.tree.get(root) @@ -92,3 +127,13 @@ func (db *Database) NodeReader(root common.Hash) (database.NodeReader, error) { } return &reader{layer: layer, noHashCheck: db.isVerkle}, nil } + +// StateReader returns a reader that allows access to the state data associated +// with the specified state. +func (db *Database) StateReader(root common.Hash) (database.StateReader, error) { + layer := db.tree.get(root) + if layer == nil { + return nil, fmt.Errorf("state %#x is not available", root) + } + return &reader{layer: layer}, nil +} diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index da8befab9..e1611b3eb 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -19,10 +19,15 @@ package pathdb import ( "fmt" "io" + "slices" + "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/exp/maps" ) // counter helps in tracking items and their corresponding sizes. @@ -43,9 +48,373 @@ func (c *counter) report(count metrics.Meter, size metrics.Meter) { size.Mark(int64(c.size)) } +// stateSet represents a collection of state modifications associated with a +// transition (e.g., a block execution) or multiple aggregated transitions. +// +// A stateSet can only reside within a diffLayer or the buffer of a diskLayer, +// serving as the envelope for the set. Lock protection is not required for +// accessing or mutating the account set and storage set, as the associated +// envelope is always marked as stale before any mutation is applied. Any +// subsequent state access will be denied due to the stale flag. Therefore, +// state access and mutation won't happen at the same time with guarantee. +type stateSet struct { + accountData map[common.Hash][]byte // Keyed accounts for direct retrieval (nil means deleted) + storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted) + size uint64 // Memory size of the state data (accountData and storageData) + + accountListSorted []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil + storageListSorted map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil + + // Lock for guarding the two lists above. These lists might be accessed + // concurrently and lock protection is essential to avoid concurrent + // slice or map read/write. + listLock sync.RWMutex +} + +// newStates constructs the state set with the provided account and storage data. +func newStates(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *stateSet { + // Don't panic for the lazy callers, initialize the nil maps instead. + if accounts == nil { + accounts = make(map[common.Hash][]byte) + } + if storages == nil { + storages = make(map[common.Hash]map[common.Hash][]byte) + } + s := &stateSet{ + accountData: accounts, + storageData: storages, + storageListSorted: make(map[common.Hash][]common.Hash), + } + s.size = s.check() + return s +} + +// account returns the account data associated with the specified address hash. +func (s *stateSet) account(hash common.Hash) ([]byte, bool) { + // If the account is known locally, return it + if data, ok := s.accountData[hash]; ok { + return data, true + } + return nil, false // account is unknown in this set +} + +// storage returns the storage slot associated with the specified address hash +// and storage key hash. +func (s *stateSet) storage(accountHash, storageHash common.Hash) ([]byte, bool) { + // If the account is known locally, try to resolve the slot locally + if storage, ok := s.storageData[accountHash]; ok { + if data, ok := storage[storageHash]; ok { + return data, true + } + } + return nil, false // storage is unknown in this set +} + +// check sanitizes accounts and storage slots to ensure the data validity. +// Additionally, it computes the total memory size occupied by the maps. +func (s *stateSet) check() uint64 { + var size int + for _, blob := range s.accountData { + size += common.HashLength + len(blob) + } + for accountHash, slots := range s.storageData { + if slots == nil { + panic(fmt.Sprintf("storage %#x nil", accountHash)) // nil slots is not permitted + } + for _, blob := range slots { + size += 2*common.HashLength + len(blob) + } + } + return uint64(size) +} + +// accountList returns a sorted list of all accounts in this state set, including +// the deleted ones. +// +// Note, the returned slice is not a copy, so do not modify it. +// +// nolint:unused +func (s *stateSet) accountList() []common.Hash { + // If an old list already exists, return it + s.listLock.RLock() + list := s.accountListSorted + s.listLock.RUnlock() + + if list != nil { + return list + } + // No old sorted account list exists, generate a new one. It's possible that + // multiple threads waiting for the write lock may regenerate the list + // multiple times, which is acceptable. + s.listLock.Lock() + defer s.listLock.Unlock() + + list = maps.Keys(s.accountData) + slices.SortFunc(list, common.Hash.Cmp) + s.accountListSorted = list + return list +} + +// StorageList returns a sorted list of all storage slot hashes in this state set +// for the given account. The returned list will include the hash of deleted +// storage slot. +// +// Note, the returned slice is not a copy, so do not modify it. +// +// nolint:unused +func (s *stateSet) storageList(accountHash common.Hash) []common.Hash { + s.listLock.RLock() + if _, ok := s.storageData[accountHash]; !ok { + // Account not tracked by this layer + s.listLock.RUnlock() + return nil + } + // If an old list already exists, return it + if list, exist := s.storageListSorted[accountHash]; exist { + s.listLock.RUnlock() + return list // the cached list can't be nil + } + s.listLock.RUnlock() + + // No old sorted account list exists, generate a new one. It's possible that + // multiple threads waiting for the write lock may regenerate the list + // multiple times, which is acceptable. + s.listLock.Lock() + defer s.listLock.Unlock() + + list := maps.Keys(s.storageData[accountHash]) + slices.SortFunc(list, common.Hash.Cmp) + s.storageListSorted[accountHash] = list + return list +} + +// clearLists invalidates the cached account list and storage lists. +func (s *stateSet) clearLists() { + s.listLock.Lock() + defer s.listLock.Unlock() + + s.accountListSorted = nil + s.storageListSorted = make(map[common.Hash][]common.Hash) +} + +// merge integrates the accounts and storages from the external set into the +// local set, ensuring the combined set reflects the combined state of both. +// +// The stateSet supplied as parameter set will not be mutated by this operation, +// as it may still be referenced by other layers. +func (s *stateSet) merge(other *stateSet) { + var ( + delta int + accountOverwrites counter + storageOverwrites counter + ) + // Apply the updated account data + for accountHash, data := range other.accountData { + if origin, ok := s.accountData[accountHash]; ok { + delta += len(data) - len(origin) + accountOverwrites.add(common.HashLength + len(origin)) + } else { + delta += common.HashLength + len(data) + } + s.accountData[accountHash] = data + } + // Apply all the updated storage slots (individually) + for accountHash, storage := range other.storageData { + // If storage didn't exist in the set, overwrite blindly + if _, ok := s.storageData[accountHash]; !ok { + // To prevent potential concurrent map read/write issues, allocate a + // new map for the storage instead of claiming it directly from the + // passed external set. Even after merging, the slots belonging to the + // external state set remain accessible, so ownership of the map should + // not be taken, and any mutation on it should be avoided. + slots := make(map[common.Hash][]byte, len(storage)) + for storageHash, data := range storage { + slots[storageHash] = data + delta += 2*common.HashLength + len(data) + } + s.storageData[accountHash] = slots + continue + } + // Storage exists in both local and external set, merge the slots + slots := s.storageData[accountHash] + for storageHash, data := range storage { + if origin, ok := slots[storageHash]; ok { + delta += len(data) - len(origin) + storageOverwrites.add(2*common.HashLength + len(origin)) + } else { + delta += 2*common.HashLength + len(data) + } + slots[storageHash] = data + } + } + accountOverwrites.report(gcAccountMeter, gcAccountBytesMeter) + storageOverwrites.report(gcStorageMeter, gcStorageBytesMeter) + s.clearLists() + s.updateSize(delta) +} + +// revertTo takes the original value of accounts and storages as input and reverts +// the latest state transition applied on the state set. +// +// Notably, this operation may result in the set containing more entries after a +// revert. For example, if account x did not exist and was created during transition +// w, reverting w will retain an x=nil entry in the set. And also if account x along +// with its storage slots was deleted in the transition w, reverting w will retain +// a list of additional storage slots with their original value. +func (s *stateSet) revertTo(accountOrigin map[common.Hash][]byte, storageOrigin map[common.Hash]map[common.Hash][]byte) { + var delta int // size tracking + for addrHash, blob := range accountOrigin { + data, ok := s.accountData[addrHash] + if !ok { + panic(fmt.Sprintf("non-existent account for reverting, %x", addrHash)) + } + if len(data) == 0 && len(blob) == 0 { + panic(fmt.Sprintf("invalid account mutation (null to null), %x", addrHash)) + } + delta += len(blob) - len(data) + s.accountData[addrHash] = blob + } + // Overwrite the storage data with original value blindly + for addrHash, storage := range storageOrigin { + slots := s.storageData[addrHash] + if len(slots) == 0 { + panic(fmt.Sprintf("non-existent storage set for reverting, %x", addrHash)) + } + for storageHash, blob := range storage { + data, ok := slots[storageHash] + if !ok { + panic(fmt.Sprintf("non-existent storage slot for reverting, %x-%x", addrHash, storageHash)) + } + if len(blob) == 0 && len(data) == 0 { + panic(fmt.Sprintf("invalid storage slot mutation (null to null), %x-%x", addrHash, storageHash)) + } + delta += len(blob) - len(data) + slots[storageHash] = blob + } + } + s.clearLists() + s.updateSize(delta) +} + +// updateSize updates the total cache size by the given delta. +func (s *stateSet) updateSize(delta int) { + size := int64(s.size) + int64(delta) + if size >= 0 { + s.size = uint64(size) + return + } + log.Error("Stateset size underflow", "prev", common.StorageSize(s.size), "delta", common.StorageSize(delta)) + s.size = 0 +} + +// encode serializes the content of state set into the provided writer. +func (s *stateSet) encode(w io.Writer) error { + // Encode accounts + type accounts struct { + AddrHashes []common.Hash + Accounts [][]byte + } + var enc accounts + for addrHash, blob := range s.accountData { + enc.AddrHashes = append(enc.AddrHashes, addrHash) + enc.Accounts = append(enc.Accounts, blob) + } + if err := rlp.Encode(w, enc); err != nil { + return err + } + // Encode storages + type Storage struct { + AddrHash common.Hash + Keys []common.Hash + Vals [][]byte + } + storages := make([]Storage, 0, len(s.storageData)) + for addrHash, slots := range s.storageData { + keys := make([]common.Hash, 0, len(slots)) + vals := make([][]byte, 0, len(slots)) + for key, val := range slots { + keys = append(keys, key) + vals = append(vals, val) + } + storages = append(storages, Storage{ + AddrHash: addrHash, + Keys: keys, + Vals: vals, + }) + } + return rlp.Encode(w, storages) +} + +// decode deserializes the content from the rlp stream into the state set. +func (s *stateSet) decode(r *rlp.Stream) error { + type accounts struct { + AddrHashes []common.Hash + Accounts [][]byte + } + var ( + dec accounts + accountSet = make(map[common.Hash][]byte) + ) + if err := r.Decode(&dec); err != nil { + return fmt.Errorf("load diff accounts: %v", err) + } + for i := 0; i < len(dec.AddrHashes); i++ { + accountSet[dec.AddrHashes[i]] = dec.Accounts[i] + } + s.accountData = accountSet + + // Decode storages + type storage struct { + AddrHash common.Hash + Keys []common.Hash + Vals [][]byte + } + var ( + storages []storage + storageSet = make(map[common.Hash]map[common.Hash][]byte) + ) + if err := r.Decode(&storages); err != nil { + return fmt.Errorf("load diff storage: %v", err) + } + for _, entry := range storages { + storageSet[entry.AddrHash] = make(map[common.Hash][]byte, len(entry.Keys)) + for i := 0; i < len(entry.Keys); i++ { + storageSet[entry.AddrHash][entry.Keys[i]] = entry.Vals[i] + } + } + s.storageData = storageSet + s.storageListSorted = make(map[common.Hash][]common.Hash) + + s.size = s.check() + return nil +} + +// reset clears all cached state data, including any optional sorted lists that +// may have been generated. +func (s *stateSet) reset() { + s.accountData = make(map[common.Hash][]byte) + s.storageData = make(map[common.Hash]map[common.Hash][]byte) + s.size = 0 + s.accountListSorted = nil + s.storageListSorted = make(map[common.Hash][]common.Hash) +} + +// dbsize returns the approximate size for db write. +// +// nolint:unused +func (s *stateSet) dbsize() int { + m := len(s.accountData) * len(rawdb.SnapshotAccountPrefix) + for _, slots := range s.storageData { + m += len(slots) * len(rawdb.SnapshotStoragePrefix) + } + return m + int(s.size) +} + // StateSetWithOrigin wraps the state set with additional original values of the // mutated states. type StateSetWithOrigin struct { + *stateSet + // AccountOrigin represents the account data before the state transition, // corresponding to both the accountData and destructSet. It's keyed by the // account address. The nil value means the account was not present before. @@ -62,7 +431,7 @@ type StateSetWithOrigin struct { } // NewStateSetWithOrigin constructs the state set with the provided data. -func NewStateSetWithOrigin(accountOrigin map[common.Address][]byte, storageOrigin map[common.Address]map[common.Hash][]byte) *StateSetWithOrigin { +func NewStateSetWithOrigin(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte, accountOrigin map[common.Address][]byte, storageOrigin map[common.Address]map[common.Hash][]byte) *StateSetWithOrigin { // Don't panic for the lazy callers, initialize the nil maps instead. if accountOrigin == nil { accountOrigin = make(map[common.Address][]byte) @@ -82,15 +451,21 @@ func NewStateSetWithOrigin(accountOrigin map[common.Address][]byte, storageOrigi size += 2*common.HashLength + len(data) } } + set := newStates(accounts, storages) return &StateSetWithOrigin{ + stateSet: set, accountOrigin: accountOrigin, storageOrigin: storageOrigin, - size: uint64(size), + size: set.size + uint64(size), } } // encode serializes the content of state set into the provided writer. func (s *StateSetWithOrigin) encode(w io.Writer) error { + // Encode state set + if err := s.stateSet.encode(w); err != nil { + return err + } // Encode accounts type Accounts struct { Addresses []common.Address @@ -108,7 +483,7 @@ func (s *StateSetWithOrigin) encode(w io.Writer) error { type Storage struct { Address common.Address Keys []common.Hash - Blobs [][]byte + Vals [][]byte } storages := make([]Storage, 0, len(s.storageOrigin)) for address, slots := range s.storageOrigin { @@ -118,13 +493,19 @@ func (s *StateSetWithOrigin) encode(w io.Writer) error { keys = append(keys, key) vals = append(vals, val) } - storages = append(storages, Storage{Address: address, Keys: keys, Blobs: vals}) + storages = append(storages, Storage{Address: address, Keys: keys, Vals: vals}) } return rlp.Encode(w, storages) } // decode deserializes the content from the rlp stream into the state set. func (s *StateSetWithOrigin) decode(r *rlp.Stream) error { + if s.stateSet == nil { + s.stateSet = &stateSet{} + } + if err := s.stateSet.decode(r); err != nil { + return err + } // Decode account origin type Accounts struct { Addresses []common.Address @@ -146,7 +527,7 @@ func (s *StateSetWithOrigin) decode(r *rlp.Stream) error { type Storage struct { Address common.Address Keys []common.Hash - Blobs [][]byte + Vals [][]byte } var ( storages []Storage @@ -158,7 +539,7 @@ func (s *StateSetWithOrigin) decode(r *rlp.Stream) error { for _, storage := range storages { storageSet[storage.Address] = make(map[common.Hash][]byte) for i := 0; i < len(storage.Keys); i++ { - storageSet[storage.Address][storage.Keys[i]] = storage.Blobs[i] + storageSet[storage.Address][storage.Keys[i]] = storage.Vals[i] } } s.storageOrigin = storageSet diff --git a/triedb/pathdb/states_test.go b/triedb/pathdb/states_test.go new file mode 100644 index 000000000..4557fa958 --- /dev/null +++ b/triedb/pathdb/states_test.go @@ -0,0 +1,453 @@ +// Copyright 2024 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 + +package pathdb + +import ( + "bytes" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +func TestStatesMerge(t *testing.T) { + a := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa0}, + common.Hash{0xb}: {0xb0}, + common.Hash{0xc}: {0xc0}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x10}, + common.Hash{0x2}: {0x20}, + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x10}, + }, + common.Hash{0xc}: { + common.Hash{0x1}: {0x10}, + }, + }, + ) + b := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa1}, + common.Hash{0xb}: {0xb1}, + common.Hash{0xc}: nil, // delete account + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x11}, + common.Hash{0x2}: nil, // delete slot + common.Hash{0x3}: {0x31}, + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x11}, + }, + common.Hash{0xc}: { + common.Hash{0x1}: nil, // delete slot + }, + }, + ) + a.merge(b) + + blob, exist := a.account(common.Hash{0xa}) + if !exist || !bytes.Equal(blob, []byte{0xa1}) { + t.Error("Unexpected value for account a") + } + blob, exist = a.account(common.Hash{0xb}) + if !exist || !bytes.Equal(blob, []byte{0xb1}) { + t.Error("Unexpected value for account b") + } + blob, exist = a.account(common.Hash{0xc}) + if !exist || len(blob) != 0 { + t.Error("Unexpected value for account c") + } + // unknown account + blob, exist = a.account(common.Hash{0xd}) + if exist || len(blob) != 0 { + t.Error("Unexpected value for account d") + } + + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x1}) + if !exist || !bytes.Equal(blob, []byte{0x11}) { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x2}) + if !exist || len(blob) != 0 { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x3}) + if !exist || !bytes.Equal(blob, []byte{0x31}) { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xb}, common.Hash{0x1}) + if !exist || !bytes.Equal(blob, []byte{0x11}) { + t.Error("Unexpected value for b's storage") + } + blob, exist = a.storage(common.Hash{0xc}, common.Hash{0x1}) + if !exist || len(blob) != 0 { + t.Error("Unexpected value for c's storage") + } + + // unknown storage slots + blob, exist = a.storage(common.Hash{0xd}, common.Hash{0x1}) + if exist || len(blob) != 0 { + t.Error("Unexpected value for d's storage") + } +} + +func TestStatesRevert(t *testing.T) { + a := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa0}, + common.Hash{0xb}: {0xb0}, + common.Hash{0xc}: {0xc0}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x10}, + common.Hash{0x2}: {0x20}, + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x10}, + }, + common.Hash{0xc}: { + common.Hash{0x1}: {0x10}, + }, + }, + ) + b := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa1}, + common.Hash{0xb}: {0xb1}, + common.Hash{0xc}: nil, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x11}, + common.Hash{0x2}: nil, + common.Hash{0x3}: {0x31}, + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x11}, + }, + common.Hash{0xc}: { + common.Hash{0x1}: nil, + }, + }, + ) + a.merge(b) + a.revertTo( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa0}, + common.Hash{0xb}: {0xb0}, + common.Hash{0xc}: {0xc0}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x10}, + common.Hash{0x2}: {0x20}, + common.Hash{0x3}: nil, + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x10}, + }, + common.Hash{0xc}: { + common.Hash{0x1}: {0x10}, + }, + }, + ) + + blob, exist := a.account(common.Hash{0xa}) + if !exist || !bytes.Equal(blob, []byte{0xa0}) { + t.Error("Unexpected value for account a") + } + blob, exist = a.account(common.Hash{0xb}) + if !exist || !bytes.Equal(blob, []byte{0xb0}) { + t.Error("Unexpected value for account b") + } + blob, exist = a.account(common.Hash{0xc}) + if !exist || !bytes.Equal(blob, []byte{0xc0}) { + t.Error("Unexpected value for account c") + } + // unknown account + blob, exist = a.account(common.Hash{0xd}) + if exist || len(blob) != 0 { + t.Error("Unexpected value for account d") + } + + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x1}) + if !exist || !bytes.Equal(blob, []byte{0x10}) { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x2}) + if !exist || !bytes.Equal(blob, []byte{0x20}) { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xa}, common.Hash{0x3}) + if !exist || len(blob) != 0 { + t.Error("Unexpected value for a's storage") + } + blob, exist = a.storage(common.Hash{0xb}, common.Hash{0x1}) + if !exist || !bytes.Equal(blob, []byte{0x10}) { + t.Error("Unexpected value for b's storage") + } + blob, exist = a.storage(common.Hash{0xc}, common.Hash{0x1}) + if !exist || !bytes.Equal(blob, []byte{0x10}) { + t.Error("Unexpected value for c's storage") + } + // unknown storage slots + blob, exist = a.storage(common.Hash{0xd}, common.Hash{0x1}) + if exist || len(blob) != 0 { + t.Error("Unexpected value for d's storage") + } +} + +// TestStateRevertAccountNullMarker tests the scenario that account x did not exist +// before and was created during transition w, reverting w will retain an x=nil +// entry in the set. +func TestStateRevertAccountNullMarker(t *testing.T) { + a := newStates(nil, nil) // empty initial state + b := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa}, + }, + nil, + ) + a.merge(b) // create account 0xa + a.revertTo( + map[common.Hash][]byte{ + common.Hash{0xa}: nil, + }, + nil, + ) // revert the transition b + + blob, exist := a.account(common.Hash{0xa}) + if !exist { + t.Fatal("null marker is not found") + } + if len(blob) != 0 { + t.Fatalf("Unexpected value for account, %v", blob) + } +} + +// TestStateRevertStorageNullMarker tests the scenario that slot x did not exist +// before and was created during transition w, reverting w will retain an x=nil +// entry in the set. +func TestStateRevertStorageNullMarker(t *testing.T) { + a := newStates(map[common.Hash][]byte{ + common.Hash{0xa}: {0xa}, + }, nil) // initial state with account 0xa + + b := newStates( + nil, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x1}, + }, + }, + ) + a.merge(b) // create slot 0x1 + a.revertTo( + nil, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: nil, + }, + }, + ) // revert the transition b + + blob, exist := a.storage(common.Hash{0xa}, common.Hash{0x1}) + if !exist { + t.Fatal("null marker is not found") + } + if len(blob) != 0 { + t.Fatalf("Unexpected value for storage slot, %v", blob) + } +} + +func TestStatesEncode(t *testing.T) { + s := newStates( + map[common.Hash][]byte{ + common.Hash{0x1}: {0x1}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0x1}: { + common.Hash{0x1}: {0x1}, + }, + }, + ) + buf := bytes.NewBuffer(nil) + if err := s.encode(buf); err != nil { + t.Fatalf("Failed to encode states, %v", err) + } + var dec stateSet + if err := dec.decode(rlp.NewStream(buf, 0)); err != nil { + t.Fatalf("Failed to decode states, %v", err) + } + if !reflect.DeepEqual(s.accountData, dec.accountData) { + t.Fatal("Unexpected account data") + } + if !reflect.DeepEqual(s.storageData, dec.storageData) { + t.Fatal("Unexpected storage data") + } +} + +func TestStateWithOriginEncode(t *testing.T) { + s := NewStateSetWithOrigin( + map[common.Hash][]byte{ + common.Hash{0x1}: {0x1}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0x1}: { + common.Hash{0x1}: {0x1}, + }, + }, + map[common.Address][]byte{ + common.Address{0x1}: {0x1}, + }, + map[common.Address]map[common.Hash][]byte{ + common.Address{0x1}: { + common.Hash{0x1}: {0x1}, + }, + }, + ) + buf := bytes.NewBuffer(nil) + if err := s.encode(buf); err != nil { + t.Fatalf("Failed to encode states, %v", err) + } + var dec StateSetWithOrigin + if err := dec.decode(rlp.NewStream(buf, 0)); err != nil { + t.Fatalf("Failed to decode states, %v", err) + } + if !reflect.DeepEqual(s.accountData, dec.accountData) { + t.Fatal("Unexpected account data") + } + if !reflect.DeepEqual(s.storageData, dec.storageData) { + t.Fatal("Unexpected storage data") + } + if !reflect.DeepEqual(s.accountOrigin, dec.accountOrigin) { + t.Fatal("Unexpected account origin data") + } + if !reflect.DeepEqual(s.storageOrigin, dec.storageOrigin) { + t.Fatal("Unexpected storage origin data") + } +} + +func TestStateSizeTracking(t *testing.T) { + expSizeA := 3*(common.HashLength+1) + /* account data */ + 2*(2*common.HashLength+1) + /* storage data of 0xa */ + 2*common.HashLength + 3 + /* storage data of 0xb */ + 2*common.HashLength + 1 /* storage data of 0xc */ + + a := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa0}, // common.HashLength+1 + common.Hash{0xb}: {0xb0}, // common.HashLength+1 + common.Hash{0xc}: {0xc0}, // common.HashLength+1 + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x10}, // 2*common.HashLength+1 + common.Hash{0x2}: {0x20}, // 2*common.HashLength+1 + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x10, 0x11, 0x12}, // 2*common.HashLength+3 + }, + common.Hash{0xc}: { + common.Hash{0x1}: {0x10}, // 2*common.HashLength+1 + }, + }, + ) + if a.size != uint64(expSizeA) { + t.Fatalf("Unexpected size, want: %d, got: %d", expSizeA, a.size) + } + + expSizeB := common.HashLength + 2 + common.HashLength + 3 + common.HashLength + /* account data */ + 2*common.HashLength + 3 + 2*common.HashLength + 2 + /* storage data of 0xa */ + 2*common.HashLength + 2 + 2*common.HashLength + 2 + /* storage data of 0xb */ + 3*2*common.HashLength /* storage data of 0xc */ + b := newStates( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa1, 0xa1}, // common.HashLength+2 + common.Hash{0xb}: {0xb1, 0xb1, 0xb1}, // common.HashLength+3 + common.Hash{0xc}: nil, // common.HashLength, account deletion + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x11, 0x11, 0x11}, // 2*common.HashLength+3 + common.Hash{0x3}: {0x31, 0x31}, // 2*common.HashLength+2, slot creation + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x11, 0x11}, // 2*common.HashLength+2 + common.Hash{0x2}: {0x22, 0x22}, // 2*common.HashLength+2, slot creation + }, + // The storage of 0xc is entirely removed + common.Hash{0xc}: { + common.Hash{0x1}: nil, // 2*common.HashLength, slot deletion + common.Hash{0x2}: nil, // 2*common.HashLength, slot deletion + common.Hash{0x3}: nil, // 2*common.HashLength, slot deletion + }, + }, + ) + if b.size != uint64(expSizeB) { + t.Fatalf("Unexpected size, want: %d, got: %d", expSizeB, b.size) + } + + a.merge(b) + mergeSize := expSizeA + 1 /* account a data change */ + 2 /* account b data change */ - 1 /* account c data change */ + mergeSize += 2*common.HashLength + 2 + 2 /* storage a change */ + mergeSize += 2*common.HashLength + 2 - 1 /* storage b change */ + mergeSize += 2*2*common.HashLength - 1 /* storage data removal of 0xc */ + + if a.size != uint64(mergeSize) { + t.Fatalf("Unexpected size, want: %d, got: %d", mergeSize, a.size) + } + + // Revert the set to original status + a.revertTo( + map[common.Hash][]byte{ + common.Hash{0xa}: {0xa0}, + common.Hash{0xb}: {0xb0}, + common.Hash{0xc}: {0xc0}, + }, + map[common.Hash]map[common.Hash][]byte{ + common.Hash{0xa}: { + common.Hash{0x1}: {0x10}, + common.Hash{0x2}: {0x20}, + common.Hash{0x3}: nil, // revert slot creation + }, + common.Hash{0xb}: { + common.Hash{0x1}: {0x10, 0x11, 0x12}, + common.Hash{0x2}: nil, // revert slot creation + }, + common.Hash{0xc}: { + common.Hash{0x1}: {0x10}, + common.Hash{0x2}: {0x20}, // resurrected slot + common.Hash{0x3}: {0x30}, // resurrected slot + }, + }, + ) + revertSize := expSizeA + 2*common.HashLength + 2*common.HashLength // delete-marker of a.3 and b.2 slot + revertSize += 2 * (2*common.HashLength + 1) // resurrected slot, c.2, c.3 + if a.size != uint64(revertSize) { + t.Fatalf("Unexpected size, want: %d, got: %d", revertSize, a.size) + } +} diff --git a/triedb/states.go b/triedb/states.go index 0b03f2b9f..fa432e070 100644 --- a/triedb/states.go +++ b/triedb/states.go @@ -45,5 +45,5 @@ func (set *StateSet) internal() *pathdb.StateSetWithOrigin { if set == nil { return nil } - return pathdb.NewStateSetWithOrigin(set.AccountsOrigin, set.StoragesOrigin) + return pathdb.NewStateSetWithOrigin(set.Accounts, set.Storages, set.AccountsOrigin, set.StoragesOrigin) } From 132700050c3c68f3eca4d6100a97b091ed49b7e2 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 29 Nov 2024 22:32:45 +0800 Subject: [PATCH 024/354] core/state: introduce code reader interface (#30816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR introduces a `ContractCodeReader` interface with functions defined: type ContractCodeReader interface { Code(addr common.Address, codeHash common.Hash) ([]byte, error) CodeSize(addr common.Address, codeHash common.Hash) (int, error) } This interface can be implemented in various ways. Although the codebase currently includes only one implementation, additional implementations could be created for different purposes and scenarios, such as a code reader designed for the Verkle tree approach or one that reads code from the witness. *Notably, this interface modifies the function’s semantics. If the contract code is not found, no error will be returned. An error should only be returned in the event of an unexpected issue, primarily for future implementations.* The original state.Reader interface is extended with ContractCodeReader methods, it gives us more flexibility to manipulate the reader with additional logic on top, e.g. Hooks. type Reader interface { ContractCodeReader StateReader } --------- Co-authored-by: Felix Lange --- core/blockchain_reader.go | 5 +- core/state/database.go | 48 ++------- core/state/iterator.go | 5 +- core/state/reader.go | 178 ++++++++++++++++++++++------------ core/state/state_object.go | 10 +- core/state/statedb.go | 3 +- core/state/sync_test.go | 45 +++++++-- eth/protocols/snap/handler.go | 2 +- 8 files changed, 176 insertions(+), 120 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index badd15b84..f8c79c229 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -360,10 +360,7 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool { // ContractCodeWithPrefix retrieves a blob of data associated with a contract // hash either from ephemeral in-memory cache, or from persistent storage. -// -// If the code doesn't exist in the in-memory cache, check the storage with -// new code scheme. -func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { +func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte { // TODO(rjl493456442) The associated account address is also required // in Verkle scheme. Fix it once snap-sync is supported for Verkle. return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash) diff --git a/core/state/database.go b/core/state/database.go index 0d8acec35..fff7f1519 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -17,7 +17,6 @@ package state import ( - "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -55,12 +54,6 @@ type Database interface { // OpenStorageTrie opens the storage trie of an account. OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) - // ContractCode retrieves a particular contract's code. - ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) - - // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) - // PointCache returns the cache holding points used in verkle tree key computation PointCache() *utils.PointCache @@ -180,7 +173,7 @@ func NewDatabaseForTesting() *CachingDB { // Reader returns a state reader associated with the specified state root. func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { - var readers []Reader + var readers []StateReader // Set up the state snapshot reader if available. This feature // is optional and may be partially useful if it's not fully @@ -188,7 +181,7 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { if db.snap != nil { snap := db.snap.Snapshot(stateRoot) if snap != nil { - readers = append(readers, newStateReader(snap)) // snap reader is optional + readers = append(readers, newFlatReader(snap)) } } // Set up the trie reader, which is expected to always be available @@ -199,7 +192,11 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { } readers = append(readers, tr) - return newMultiReader(readers...) + combined, err := newMultiStateReader(readers...) + if err != nil { + return nil, err + } + return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil } // OpenTrie opens the main account trie at a specific root hash. @@ -229,45 +226,20 @@ func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre return tr, nil } -// ContractCode retrieves a particular contract's code. -func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { - code, _ := db.codeCache.Get(codeHash) - if len(code) > 0 { - return code, nil - } - code = rawdb.ReadCode(db.disk, codeHash) - if len(code) > 0 { - db.codeCache.Add(codeHash, code) - db.codeSizeCache.Add(codeHash, len(code)) - return code, nil - } - return nil, errors.New("not found") -} - // ContractCodeWithPrefix retrieves a particular contract's code. If the // code can't be found in the cache, then check the existence with **new** // db scheme. -func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { +func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte { code, _ := db.codeCache.Get(codeHash) if len(code) > 0 { - return code, nil + return code } code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) if len(code) > 0 { db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) - return code, nil - } - return nil, errors.New("not found") -} - -// ContractCodeSize retrieves a particular contracts code's size. -func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { - if cached, ok := db.codeSizeCache.Get(codeHash); ok { - return cached, nil } - code, err := db.ContractCode(addr, codeHash) - return len(code), err + return code } // TrieDB retrieves any intermediate trie-node caching layer. diff --git a/core/state/iterator.go b/core/state/iterator.go index 83c552ca1..5ea52c618 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -136,10 +136,13 @@ func (it *nodeIterator) step() error { } if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { it.codeHash = common.BytesToHash(account.CodeHash) - it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash)) + it.code, err = it.state.reader.Code(address, common.BytesToHash(account.CodeHash)) if err != nil { return fmt.Errorf("code %x: %v", account.CodeHash, err) } + if len(it.code) == 0 { + return fmt.Errorf("code is not found: %x", account.CodeHash) + } } it.accountHash = it.stateIt.Parent() return nil diff --git a/core/state/reader.go b/core/state/reader.go index 85842adde..a0f15dfcc 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -18,11 +18,13 @@ package state import ( "errors" - "maps" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/utils" @@ -30,9 +32,26 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) -// Reader defines the interface for accessing accounts and storage slots +// ContractCodeReader defines the interface for accessing contract code. +type ContractCodeReader interface { + // Code retrieves a particular contract's code. + // + // - Returns nil code along with nil error if the requested contract code + // doesn't exist + // - Returns an error only if an unexpected issue occurs + Code(addr common.Address, codeHash common.Hash) ([]byte, error) + + // CodeSize retrieves a particular contracts code's size. + // + // - Returns zero code size along with nil error if the requested contract code + // doesn't exist + // - Returns an error only if an unexpected issue occurs + CodeSize(addr common.Address, codeHash common.Hash) (int, error) +} + +// StateReader defines the interface for accessing accounts and storage slots // associated with a specific state. -type Reader interface { +type StateReader interface { // Account retrieves the account associated with a particular address. // // - Returns a nil account if it does not exist @@ -47,32 +66,84 @@ type Reader interface { // - Returns an error only if an unexpected issue occurs // - The returned storage slot is safe to modify after the call Storage(addr common.Address, slot common.Hash) (common.Hash, error) +} + +// Reader defines the interface for accessing accounts, storage slots and contract +// code associated with a specific state. +type Reader interface { + ContractCodeReader + StateReader +} + +// cachingCodeReader implements ContractCodeReader, accessing contract code either in +// local key-value store or the shared code cache. +type cachingCodeReader struct { + db ethdb.KeyValueReader + + // These caches could be shared by multiple code reader instances, + // they are natively thread-safe. + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + codeSizeCache *lru.Cache[common.Hash, int] +} + +// newCachingCodeReader constructs the code reader. +func newCachingCodeReader(db ethdb.KeyValueReader, codeCache *lru.SizeConstrainedCache[common.Hash, []byte], codeSizeCache *lru.Cache[common.Hash, int]) *cachingCodeReader { + return &cachingCodeReader{ + db: db, + codeCache: codeCache, + codeSizeCache: codeSizeCache, + } +} + +// Code implements ContractCodeReader, retrieving a particular contract's code. +// If the contract code doesn't exist, no error will be returned. +func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) { + code, _ := r.codeCache.Get(codeHash) + if len(code) > 0 { + return code, nil + } + code = rawdb.ReadCode(r.db, codeHash) + if len(code) > 0 { + r.codeCache.Add(codeHash, code) + r.codeSizeCache.Add(codeHash, len(code)) + } + return code, nil +} - // Copy returns a deep-copied state reader. - Copy() Reader +// CodeSize implements ContractCodeReader, retrieving a particular contracts code's size. +// If the contract code doesn't exist, no error will be returned. +func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) { + if cached, ok := r.codeSizeCache.Get(codeHash); ok { + return cached, nil + } + code, err := r.Code(addr, codeHash) + if err != nil { + return 0, err + } + return len(code), nil } -// stateReader wraps a database state reader. -type stateReader struct { +// flatReader wraps a database state reader. +type flatReader struct { reader database.StateReader buff crypto.KeccakState } -// newStateReader constructs a state reader with on the given state root. -func newStateReader(reader database.StateReader) *stateReader { - return &stateReader{ +// newFlatReader constructs a state reader with on the given state root. +func newFlatReader(reader database.StateReader) *flatReader { + return &flatReader{ reader: reader, buff: crypto.NewKeccakState(), } } -// Account implements Reader, retrieving the account specified by the address. +// Account implements StateReader, retrieving the account specified by the address. // // An error will be returned if the associated snapshot is already stale or // the requested account is not yet covered by the snapshot. // // The returned account might be nil if it's not existent. -func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) { +func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) { account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes())) if err != nil { return nil, err @@ -95,14 +166,14 @@ func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) return acct, nil } -// Storage implements Reader, retrieving the storage slot specified by the +// Storage implements StateReader, retrieving the storage slot specified by the // address and slot key. // // An error will be returned if the associated snapshot is already stale or // the requested storage slot is not yet covered by the snapshot. // // The returned storage slot might be empty if it's not existent. -func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { +func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { addrHash := crypto.HashData(r.buff, addr.Bytes()) slotHash := crypto.HashData(r.buff, key.Bytes()) ret, err := r.reader.Storage(addrHash, slotHash) @@ -123,15 +194,7 @@ func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash return value, nil } -// Copy implements Reader, returning a deep-copied snap reader. -func (r *stateReader) Copy() Reader { - return &stateReader{ - reader: r.reader, - buff: crypto.NewKeccakState(), - } -} - -// trieReader implements the Reader interface, providing functions to access +// trieReader implements the StateReader interface, providing functions to access // state from the referenced trie. type trieReader struct { root common.Hash // State root which uniquely represent a state @@ -167,7 +230,7 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach }, nil } -// Account implements Reader, retrieving the account specified by the address. +// Account implements StateReader, retrieving the account specified by the address. // // An error will be returned if the trie state is corrupted. An nil account // will be returned if it's not existent in the trie. @@ -184,7 +247,7 @@ func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) { return account, nil } -// Storage implements Reader, retrieving the storage slot specified by the +// Storage implements StateReader, retrieving the storage slot specified by the // address and slot key. // // An error will be returned if the trie state is corrupted. An empty storage @@ -227,48 +290,32 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, return value, nil } -// Copy implements Reader, returning a deep-copied trie reader. -func (r *trieReader) Copy() Reader { - tries := make(map[common.Address]Trie) - for addr, tr := range r.subTries { - tries[addr] = mustCopyTrie(tr) - } - return &trieReader{ - root: r.root, - db: r.db, - buff: crypto.NewKeccakState(), - mainTrie: mustCopyTrie(r.mainTrie), - subRoots: maps.Clone(r.subRoots), - subTries: tries, - } +// multiStateReader is the aggregation of a list of StateReader interface, +// providing state access by leveraging all readers. The checking priority +// is determined by the position in the reader list. +type multiStateReader struct { + readers []StateReader // List of state readers, sorted by checking priority } -// multiReader is the aggregation of a list of Reader interface, providing state -// access by leveraging all readers. The checking priority is determined by the -// position in the reader list. -type multiReader struct { - readers []Reader // List of readers, sorted by checking priority -} - -// newMultiReader constructs a multiReader instance with the given readers. The -// priority among readers is assumed to be sorted. Note, it must contain at least -// one reader for constructing a multiReader. -func newMultiReader(readers ...Reader) (*multiReader, error) { +// newMultiStateReader constructs a multiStateReader instance with the given +// readers. The priority among readers is assumed to be sorted. Note, it must +// contain at least one reader for constructing a multiStateReader. +func newMultiStateReader(readers ...StateReader) (*multiStateReader, error) { if len(readers) == 0 { return nil, errors.New("empty reader set") } - return &multiReader{ + return &multiStateReader{ readers: readers, }, nil } -// Account implementing Reader interface, retrieving the account associated with -// a particular address. +// Account implementing StateReader interface, retrieving the account associated +// with a particular address. // // - Returns a nil account if it does not exist // - Returns an error only if an unexpected issue occurs // - The returned account is safe to modify after the call -func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) { +func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, error) { var errs []error for _, reader := range r.readers { acct, err := reader.Account(addr) @@ -280,13 +327,13 @@ func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) return nil, errors.Join(errs...) } -// Storage implementing Reader interface, retrieving the storage slot associated -// with a particular account address and slot key. +// Storage implementing StateReader interface, retrieving the storage slot +// associated with a particular account address and slot key. // // - Returns an empty slot if it does not exist // - Returns an error only if an unexpected issue occurs // - The returned storage slot is safe to modify after the call -func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { +func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { var errs []error for _, reader := range r.readers { slot, err := reader.Storage(addr, slot) @@ -298,11 +345,16 @@ func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Has return common.Hash{}, errors.Join(errs...) } -// Copy implementing Reader interface, returning a deep-copied state reader. -func (r *multiReader) Copy() Reader { - var readers []Reader - for _, reader := range r.readers { - readers = append(readers, reader.Copy()) +// reader is the wrapper of ContractCodeReader and StateReader interface. +type reader struct { + ContractCodeReader + StateReader +} + +// newReader constructs a reader with the supplied code reader and state reader. +func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader { + return &reader{ + ContractCodeReader: codeReader, + StateReader: stateReader, } - return &multiReader{readers: readers} } diff --git a/core/state/state_object.go b/core/state/state_object.go index b659bf7ff..2d542e500 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -510,10 +510,13 @@ func (s *stateObject) Code() []byte { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } - code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) + code, err := s.db.reader.Code(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } + if len(code) == 0 { + s.db.setError(fmt.Errorf("code is not found %x", s.CodeHash())) + } s.code = code return code } @@ -528,10 +531,13 @@ func (s *stateObject) CodeSize() int { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } - size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) + size, err := s.db.reader.CodeSize(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) } + if size == 0 { + s.db.setError(fmt.Errorf("code is not found %x", s.CodeHash())) + } return size } diff --git a/core/state/statedb.go b/core/state/statedb.go index 9cc91c933..b0603db7f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -650,10 +650,11 @@ func (s *StateDB) CreateContract(addr common.Address) { // Snapshots of the copied state cannot be applied to the copy. func (s *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones + reader, _ := s.db.Reader(s.originalRoot) // impossible to fail state := &StateDB{ db: s.db, trie: mustCopyTrie(s.trie), - reader: s.reader.Copy(), + reader: reader, originalRoot: s.originalRoot, stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)), diff --git a/core/state/sync_test.go b/core/state/sync_test.go index b2c75e72f..efa56f886 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -210,14 +210,18 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s if err != nil { t.Fatalf("state is not existent, %#x", srcRoot) } + cReader, err := srcDb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeElements)+len(codeElements) > 0 { var ( nodeResults = make([]trie.NodeSyncResult, len(nodeElements)) codeResults = make([]trie.CodeSyncResult, len(codeElements)) ) for i, element := range codeElements { - data, err := srcDb.ContractCode(common.Address{}, element.code) - if err != nil { + data, err := cReader.Code(common.Address{}, element.code) + if err != nil || len(data) == 0 { t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) } codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} @@ -329,6 +333,10 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { if err != nil { t.Fatalf("state is not existent, %#x", srcRoot) } + cReader, err := srcDb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeElements)+len(codeElements) > 0 { // Sync only half of the scheduled nodes var nodeProcessed int @@ -336,8 +344,8 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { if len(codeElements) > 0 { codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) for i, element := range codeElements[:len(codeResults)] { - data, err := srcDb.ContractCode(common.Address{}, element.code) - if err != nil { + data, err := cReader.Code(common.Address{}, element.code) + if err != nil || len(data) == 0 { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} @@ -433,13 +441,17 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { if err != nil { t.Fatalf("state is not existent, %#x", srcRoot) } + cReader, err := srcDb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeQueue)+len(codeQueue) > 0 { // Fetch all the queued nodes in a random order if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Address{}, hash) - if err != nil { + data, err := cReader.Code(common.Address{}, hash) + if err != nil || len(data) == 0 { t.Fatalf("failed to retrieve node data for %x", hash) } results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) @@ -526,6 +538,10 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { if err != nil { t.Fatalf("state is not existent, %#x", srcRoot) } + cReader, err := srcDb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } for len(nodeQueue)+len(codeQueue) > 0 { // Sync only half of the scheduled nodes, even those in random order if len(codeQueue) > 0 { @@ -533,8 +549,8 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { for hash := range codeQueue { delete(codeQueue, hash) - data, err := srcDb.ContractCode(common.Address{}, hash) - if err != nil { + data, err := cReader.Code(common.Address{}, hash) + if err != nil || len(data) == 0 { t.Fatalf("failed to retrieve node data for %x", hash) } results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) @@ -631,6 +647,10 @@ func testIncompleteStateSync(t *testing.T, scheme string) { if err != nil { t.Fatalf("state is not available %x", srcRoot) } + cReader, err := srcDb.Reader(srcRoot) + if err != nil { + t.Fatalf("state is not existent, %#x", srcRoot) + } nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) paths, nodes, codes := sched.Missing(1) @@ -649,8 +669,8 @@ func testIncompleteStateSync(t *testing.T, scheme string) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Address{}, hash) - if err != nil { + data, err := cReader.Code(common.Address{}, hash) + if err != nil || len(data) == 0 { t.Fatalf("failed to retrieve node data for %x", hash) } results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) @@ -713,6 +733,11 @@ func testIncompleteStateSync(t *testing.T, scheme string) { // Sanity check that removing any node from the database is detected for _, node := range addedCodes { val := rawdb.ReadCode(dstDb, node) + if len(val) == 0 { + t.Logf("no code: %v", node) + } else { + t.Logf("has code: %v", node) + } rawdb.DeleteCode(dstDb, node) if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %x", node) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index d36f9621b..8164973c2 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -454,7 +454,7 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [ // Peers should not request the empty code, but if they do, at // least sent them back a correct response without db lookups codes = append(codes, []byte{}) - } else if blob, err := chain.ContractCodeWithPrefix(hash); err == nil { + } else if blob := chain.ContractCodeWithPrefix(hash); len(blob) > 0 { codes = append(codes, blob) bytes += uint64(len(blob)) } From 2bb1e82671e2472ce1f1769fa9d98a8aaa10f3c5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 29 Nov 2024 22:39:42 +0800 Subject: [PATCH 025/354] core: switch EVM tx context in ApplyMessage (#30809) This change relocates the EVM tx context switching to the ApplyMessage function. With this change, we can remove a lot of EVM.SetTxContext calls before message execution. ### Tracing API changes - This PR replaces the `GasPrice` field of the `VMContext` struct with `BaseFee`. Users may instead take the effective gas price from `tx.EffectiveGasTipValue(env.BaseFee)`. --------- Co-authored-by: Sina Mahmoodi --- cmd/evm/internal/t8ntool/execution.go | 7 ++-- core/block_validator.go | 2 +- core/state_prefetcher.go | 16 +++------ core/state_processor.go | 6 ---- core/state_transition.go | 29 ++++++++-------- core/tracing/hooks.go | 5 ++- core/vm/evm.go | 2 +- eth/gasestimator/gasestimator.go | 8 ++--- eth/state_accessor.go | 2 -- eth/tracers/api.go | 20 ++++------- eth/tracers/api_test.go | 2 -- .../internal/tracetest/calltrace_test.go | 33 ++++++++----------- .../internal/tracetest/flat_calltrace_test.go | 1 - .../internal/tracetest/prestate_test.go | 1 - eth/tracers/js/goja.go | 2 +- eth/tracers/js/tracer_test.go | 4 +-- eth/tracers/tracers_test.go | 8 +---- internal/ethapi/api.go | 11 +++---- internal/ethapi/simulate.go | 1 - tests/state_test_util.go | 2 -- 20 files changed, 57 insertions(+), 105 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 9aeb5ada8..39aba8a9c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -262,16 +262,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.SetTxContext(tx.Hash(), txIndex) var ( - txContext = core.NewEVMTxContext(msg) - snapshot = statedb.Snapshot() - prevGas = gaspool.Gas() + snapshot = statedb.Snapshot() + prevGas = gaspool.Gas() ) if tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) - - evm.SetTxContext(txContext) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { statedb.RevertToSnapshot(snapshot) diff --git a/core/block_validator.go b/core/block_validator.go index 59783a040..5885df9ee 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -93,7 +93,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { } // The individual checks for blob validity (version-check + not empty) - // happens in StateTransition. + // happens in state transition. } // Check blob gas usage. diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 3b987bb28..805df5ef6 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -65,7 +65,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c return // Also invalid block, bail out } statedb.SetTxContext(tx.Hash(), i) - if err := precacheTransaction(msg, gaspool, evm); err != nil { + + // We attempt to apply a transaction. The goal is not to execute + // the transaction successfully, rather to warm up touched data slots. + if _, err := ApplyMessage(evm, msg, gaspool); err != nil { return // Ugh, something went horribly wrong, bail out } // If we're pre-byzantium, pre-load trie nodes for the intermediate root @@ -78,14 +81,3 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c statedb.IntermediateRoot(true) } } - -// precacheTransaction attempts to apply a transaction to the given state database -// and uses the input parameters for its environment. The goal is not to execute -// the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error { - // Update the evm with the new transaction context. - evm.SetTxContext(NewEVMTxContext(msg)) - // Add addresses to access list if applicable - _, err := ApplyMessage(evm, msg, gaspool) - return err -} diff --git a/core/state_processor.go b/core/state_processor.go index 34e718a6b..0640caa22 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -158,17 +158,11 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, defer func() { hooks.OnTxEnd(receipt, err) }() } } - - // Create a new context to be used in the EVM environment. - txContext := NewEVMTxContext(msg) - evm.SetTxContext(txContext) - // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) if err != nil { return nil, err } - // Update the state with pending changes. var root []byte if evm.ChainConfig().IsByzantium(blockNumber) { diff --git a/core/state_transition.go b/core/state_transition.go index 32d60df3c..dffba76dc 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -189,10 +189,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) { - return NewStateTransition(evm, msg, gp).TransitionDb() + evm.SetTxContext(NewEVMTxContext(msg)) + return newStateTransition(evm, msg, gp).execute() } -// StateTransition represents a state transition. +// stateTransition represents a state transition. // // == The State Transitioning Model // @@ -214,7 +215,7 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err // // 5. Run Script section // 6. Derive new state root -type StateTransition struct { +type stateTransition struct { gp *GasPool msg *Message gasRemaining uint64 @@ -223,9 +224,9 @@ type StateTransition struct { evm *vm.EVM } -// NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition { - return &StateTransition{ +// newStateTransition initialises and returns a new state transition object. +func newStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *stateTransition { + return &stateTransition{ gp: gp, evm: evm, msg: msg, @@ -234,14 +235,14 @@ func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition } // to returns the recipient of the message. -func (st *StateTransition) to() common.Address { +func (st *stateTransition) to() common.Address { if st.msg == nil || st.msg.To == nil /* contract creation */ { return common.Address{} } return *st.msg.To } -func (st *StateTransition) buyGas() error { +func (st *stateTransition) buyGas() error { mgval := new(big.Int).SetUint64(st.msg.GasLimit) mgval.Mul(mgval, st.msg.GasPrice) balanceCheck := new(big.Int).Set(mgval) @@ -285,7 +286,7 @@ func (st *StateTransition) buyGas() error { return nil } -func (st *StateTransition) preCheck() error { +func (st *stateTransition) preCheck() error { // Only check transactions that are not fake msg := st.msg if !msg.SkipNonceChecks { @@ -408,7 +409,7 @@ func (st *StateTransition) preCheck() error { return st.buyGas() } -// TransitionDb will transition the state by applying the current message and +// execute will transition the state by applying the current message and // returning the evm execution result with following fields. // // - used gas: total gas used (including gas being refunded) @@ -418,7 +419,7 @@ func (st *StateTransition) preCheck() error { // // However if any consensus issue encountered, return the error directly with // nil evm execution result. -func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { +func (st *stateTransition) execute() (*ExecutionResult, error) { // First check this message satisfies all consensus rules before // applying the message. The rules include these clauses // @@ -533,7 +534,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { }, nil } -func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { +func (st *stateTransition) refundGas(refundQuotient uint64) uint64 { // Apply refund counter, capped to a refund quotient refund := st.gasUsed() / refundQuotient if refund > st.state.GetRefund() { @@ -563,11 +564,11 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { } // gasUsed returns the amount of gas used up by the state transition. -func (st *StateTransition) gasUsed() uint64 { +func (st *stateTransition) gasUsed() uint64 { return st.initialGas - st.gasRemaining } // blobGasUsed returns the amount of blob gas used by the message. -func (st *StateTransition) blobGasUsed() uint64 { +func (st *stateTransition) blobGasUsed() uint64 { return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 0c5cae354..5218e80c9 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -55,9 +55,8 @@ type VMContext struct { BlockNumber *big.Int Time uint64 Random *common.Hash - // Effective tx gas price - GasPrice *big.Int - StateDB StateDB + BaseFee *big.Int + StateDB StateDB } // BlockEvent is emitted upon tracing an incoming block. diff --git a/core/vm/evm.go b/core/vm/evm.go index 34e5fa766..07e4a272f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -605,7 +605,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext { BlockNumber: evm.Context.BlockNumber, Time: evm.Context.Time, Random: evm.Context.Random, - GasPrice: evm.TxContext.GasPrice, + BaseFee: evm.Context.BaseFee, StateDB: evm.StateDB, } } diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 5729f8427..9b24bfbf9 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -217,21 +217,19 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) { // Assemble the call and the call context var ( - msgContext = core.NewEVMTxContext(call) evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil) - dirtyState = opts.State.Copy() ) // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). - if msgContext.GasPrice.Sign() == 0 { + if call.GasPrice.Sign() == 0 { evmContext.BaseFee = new(big.Int) } - if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 { + if call.BlobGasFeeCap != nil && call.BlobGasFeeCap.BitLen() == 0 { evmContext.BlobBaseFee = new(big.Int) } evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) - evm.SetTxContext(msgContext) + // Monitor the outer context and interrupt the EVM upon cancellation. To avoid // a dangling goroutine until the outer estimation finishes, create an internal // context for the lifetime of this method call. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 43432cff3..0749d7379 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -255,8 +255,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // Assemble the transaction call message and return if the requested offset msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - evm.SetTxContext(txContext) // Not yet the searched for transaction, execute on top of the current state statedb.SetTxContext(tx.Hash(), idx) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 8aebe08f4..51c675fc7 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -546,11 +546,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if err := ctx.Err(); err != nil { return nil, err } - var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext = core.NewEVMTxContext(msg) - ) - evm.SetTxContext(txContext) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) @@ -708,7 +704,6 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) - evm.SetTxContext(core.NewEVMTxContext(msg)) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { failed = err break txloop @@ -792,12 +787,11 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext = core.NewEVMTxContext(msg) - vmConf vm.Config - dump *os.File - writer *bufio.Writer - err error + msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) + vmConf vm.Config + dump *os.File + writer *bufio.Writer + err error ) // If the transaction needs tracing, swap out the configs if tx.Hash() == txHash || txHash == (common.Hash{}) { @@ -820,7 +814,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } } // Execute the transaction and flush any traces to disk - evm.SetTxContext(txContext) statedb.SetTxContext(tx.Hash(), i) if vmConf.Tracer.OnTxStart != nil { vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) @@ -1016,7 +1009,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } // The actual TxContext will be created as part of ApplyTransactionWithEVM. evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) - evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 431a899c0..fb78569a8 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -177,8 +177,6 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block return tx, context, statedb, release, nil } msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - evm.SetTxContext(txContext) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 869558c32..999ab211c 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -133,7 +133,6 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { @@ -206,11 +205,6 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.Fatalf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - origin, _ := signer.Sender(tx) - txContext := vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } context := test.Context.toBlockContext(test.Genesis) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { @@ -222,19 +216,25 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) - if err != nil { - b.Fatalf("failed to create call tracer: %v", err) - } - evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(txContext) + evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{}) for i := 0; i < b.N; i++ { snap := state.StateDB.Snapshot() - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) + if err != nil { + b.Fatalf("failed to create call tracer: %v", err) + } + evm.Config.Tracer = tracer.Hooks + if tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + } + _, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { b.Fatalf("failed to execute transaction: %v", err) } + if tracer.OnTxEnd != nil { + tracer.OnTxEnd(&types.Receipt{GasUsed: tx.Gas()}, nil) + } if _, err = tracer.GetResult(); err != nil { b.Fatal(err) } @@ -372,12 +372,7 @@ func TestInternals(t *testing.T) { if err != nil { t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } - txContext := vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks}) - evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 1dbdc7caa..553eaf1b5 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -99,7 +99,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index b8dec51db..ad3d75d8d 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -107,7 +107,6 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 35abd0001..227ea5722 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -260,7 +260,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.activePrecompiles = vm.ActivePrecompiles(rules) t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) t.ctx["gas"] = t.vm.ToValue(tx.Gas()) - gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) + gasPriceBig, err := t.toBig(t.vm, tx.EffectiveGasTipValue(env.BaseFee).String()) if err != nil { t.err = err return diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 54f628b5f..faad1e719 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -59,7 +59,7 @@ type vmContext struct { } func testCtx() *vmContext { - return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} + return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1), BaseFee: big.NewInt(0)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { @@ -76,7 +76,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo contract.Code = contractCode } - tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) ret, err := evm.Interpreter().Run(contract, []byte{}, false) tracer.OnExit(0, ret, startGas-contract.Gas, err, true) diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 72cc1bde2..9d8f70386 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -47,10 +47,6 @@ func BenchmarkTransactionTrace(b *testing.B) { if err != nil { b.Fatal(err) } - txContext := vm.TxContext{ - Origin: from, - GasPrice: tx.GasPrice(), - } context := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -90,7 +86,6 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableReturnData: false, }) evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) - evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -101,8 +96,7 @@ func BenchmarkTransactionTrace(b *testing.B) { for i := 0; i < b.N; i++ { snap := state.StateDB.Snapshot() tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - res, err := st.TransitionDb() + res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { b.Fatal(err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 62bdf2d45..7f136c5da 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -943,7 +943,6 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s if precompiles != nil { evm.SetPrecompiles(precompiles) } - evm.SetTxContext(core.NewEVMTxContext(msg)) res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp) // If an internal state error occurred, let that have precedence. Otherwise, // a "trie root missing" type of error will masquerade as e.g. "insufficient gas" @@ -1433,17 +1432,17 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} - vmenv := b.GetEVM(ctx, statedb, header, &config, nil) + evm := b.GetEVM(ctx, statedb, header, &config, nil) + // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). if msg.GasPrice.Sign() == 0 { - vmenv.Context.BaseFee = new(big.Int) + evm.Context.BaseFee = new(big.Int) } if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { - vmenv.Context.BlobBaseFee = new(big.Int) + evm.Context.BlobBaseFee = new(big.Int) } - vmenv.SetTxContext(core.NewEVMTxContext(msg)) - res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 2161e1d5f..f6647c7ba 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -207,7 +207,6 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, tracer.reset(tx.Hash(), uint(i)) // EoA check is always skipped, even in validation mode. msg := call.ToMessage(header.BaseFee, !sim.validate, true) - evm.SetTxContext(core.NewEVMTxContext(msg)) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) if err != nil { txErr := txValidationError(err) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 446ffb40d..6884ae7ed 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -277,7 +277,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh } // Prepare the EVM. - txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash context.BaseFee = baseFee @@ -294,7 +293,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas) } evm := vm.NewEVM(context, st.StateDB, config, vmconfig) - evm.SetTxContext(txContext) if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) From a8908c9f5e4bac23e7a7d2921973016751d28a92 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:42:28 +0100 Subject: [PATCH 026/354] eth/tracers: fix state hooks in API (#30830) When a tx/block was being traced through the API the state hooks weren't being called as they should. This is due to #30745 moving the hooked statedb one level up in the state processor. This PR fixes that. --------- Co-authored-by: Martin HS Co-authored-by: Gary Rong --- eth/tracers/api.go | 4 +- eth/tracers/api_test.go | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 51c675fc7..d351c0903 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -1007,8 +1007,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor return nil, err } } - // The actual TxContext will be created as part of ApplyTransactionWithEVM. - evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + tracingStateDB := state.NewHookedState(statedb, tracer.Hooks) + evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index fb78569a8..1b933f06f 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -185,6 +186,94 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } +type stateTracer struct { + Balance map[common.Address]*hexutil.Big + Nonce map[common.Address]hexutil.Uint64 + Storage map[common.Address]map[common.Hash]common.Hash +} + +func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainConfig) (*Tracer, error) { + t := &stateTracer{ + Balance: make(map[common.Address]*hexutil.Big), + Nonce: make(map[common.Address]hexutil.Uint64), + Storage: make(map[common.Address]map[common.Hash]common.Hash), + } + return &Tracer{ + GetResult: func() (json.RawMessage, error) { + return json.Marshal(t) + }, + Hooks: &tracing.Hooks{ + OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { + t.Balance[addr] = (*hexutil.Big)(new) + }, + OnNonceChange: func(addr common.Address, prev, new uint64) { + t.Nonce[addr] = hexutil.Uint64(new) + }, + OnStorageChange: func(addr common.Address, slot common.Hash, prev, new common.Hash) { + if t.Storage[addr] == nil { + t.Storage[addr] = make(map[common.Hash]common.Hash) + } + t.Storage[addr][slot] = new + }, + }, + }, nil +} + +func TestStateHooks(t *testing.T) { + t.Parallel() + + // Initialize test accounts + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + from = crypto.PubkeyToAddress(key.PublicKey) + to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") + genesis = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{ + from: {Balance: big.NewInt(params.Ether)}, + to: { + Code: []byte{ + byte(vm.PUSH1), 0x2a, // stack: [42] + byte(vm.PUSH1), 0x0, // stack: [0, 42] + byte(vm.SSTORE), // stack: [] + byte(vm.STOP), + }, + }, + }, + } + genBlocks = 2 + signer = types.HomesteadSigner{} + nonce = uint64(0) + backend = newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + // Transfer from account[0] to account[1] + // value: 1000 wei + // fee: 0 wei + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: nonce, + To: &to, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, key) + b.AddTx(tx) + nonce++ + }) + ) + defer backend.teardown() + DefaultDirectory.Register("stateTracer", newStateTracer, false) + api := NewAPI(backend) + tracer := "stateTracer" + res, err := api.TraceCall(context.Background(), ethapi.TransactionArgs{From: &from, To: &to, Value: (*hexutil.Big)(big.NewInt(1000))}, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), &TraceCallConfig{TraceConfig: TraceConfig{Tracer: &tracer}}) + if err != nil { + t.Fatalf("failed to trace call: %v", err) + } + expected := `{"Balance":{"0x00000000000000000000000000000000deadbeef":"0x3e8","0x71562b71999873db5b286df957af199ec94617f7":"0xde0975924ed6f90"},"Nonce":{"0x71562b71999873db5b286df957af199ec94617f7":"0x3"},"Storage":{"0x00000000000000000000000000000000deadbeef":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x000000000000000000000000000000000000000000000000000000000000002a"}}}` + if expected != fmt.Sprintf("%s", res) { + t.Fatalf("unexpected trace result: have %s want %s", res, expected) + } +} + func TestTraceCall(t *testing.T) { t.Parallel() From 4a5aeaf010178ef0e5321962e752e89dbf435bd3 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 2 Dec 2024 07:18:02 -0700 Subject: [PATCH 027/354] cmd/evm: improve block/state test runner (#30633) * unify `staterunner` and `blockrunner` CLI flags, especially around tracing * added support for struct logger or json logging (although having issue #30658) * new --cross-check flag to validate the stateless witness collection / execution matches stateful * adds support for tracing the stateless execution when a tracer is set (to more easily debug differences) * --human for more readable test summary * directory or file input, so if you pass tests/spec-tests/fixtures/blockchain_tests it will execute all blockchain tests --- cmd/evm/blockrunner.go | 87 ++++---- cmd/evm/compiler.go | 55 ------ cmd/evm/disasm.go | 55 ------ cmd/evm/eest.go | 49 +++++ cmd/evm/eofparse.go | 32 ++- cmd/evm/internal/compiler/compiler.go | 39 ---- cmd/evm/main.go | 272 +++++++++++++------------- cmd/evm/reporter.go | 87 ++++++++ cmd/evm/runner.go | 141 +++++++++---- cmd/evm/staterunner.go | 187 ++++++++---------- core/blockchain.go | 2 +- core/stateless.go | 4 +- eth/catalyst/api.go | 3 +- 13 files changed, 523 insertions(+), 490 deletions(-) delete mode 100644 cmd/evm/compiler.go delete mode 100644 cmd/evm/disasm.go create mode 100644 cmd/evm/eest.go delete mode 100644 cmd/evm/internal/compiler/compiler.go create mode 100644 cmd/evm/reporter.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index d5cd8d8e3..2cb0531e2 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -22,79 +22,84 @@ import ( "fmt" "os" "regexp" - "sort" + "slices" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" + "golang.org/x/exp/maps" ) -var RunFlag = &cli.StringFlag{ - Name: "run", - Value: ".*", - Usage: "Run only those tests matching the regular expression.", -} - var blockTestCommand = &cli.Command{ Action: blockTestCmd, Name: "blocktest", Usage: "Executes the given blockchain tests", - ArgsUsage: "", - Flags: []cli.Flag{RunFlag}, + ArgsUsage: "", + Flags: slices.Concat([]cli.Flag{ + DumpFlag, + HumanReadableFlag, + RunFlag, + WitnessCrossCheckFlag, + }, traceFlags), } func blockTestCmd(ctx *cli.Context) error { - if len(ctx.Args().First()) == 0 { - return errors.New("path-to-test argument required") + path := ctx.Args().First() + if len(path) == 0 { + return errors.New("path argument required") } - - var tracer *tracing.Hooks - // Configure the EVM logger - if ctx.Bool(MachineFlag.Name) { - tracer = logger.NewJSONLogger(&logger.Config{ - EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), - DisableStack: ctx.Bool(DisableStackFlag.Name), - DisableStorage: ctx.Bool(DisableStorageFlag.Name), - EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), - }, os.Stderr) + var ( + collected = collectJSONFiles(path) + results []testResult + ) + for _, fname := range collected { + r, err := runBlockTest(ctx, fname) + if err != nil { + return err + } + results = append(results, r...) } - // Load the test content from the input file - src, err := os.ReadFile(ctx.Args().First()) + report(ctx, results) + return nil +} + +func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { + src, err := os.ReadFile(fname) if err != nil { - return err + return nil, err } - var tests map[string]tests.BlockTest + var tests map[string]*tests.BlockTest if err = json.Unmarshal(src, &tests); err != nil { - return err + return nil, err } re, err := regexp.Compile(ctx.String(RunFlag.Name)) if err != nil { - return fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err) + return nil, fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err) } + tracer := tracerFromFlags(ctx) - // Run them in order - var keys []string - for key := range tests { - keys = append(keys, key) - } - sort.Strings(keys) + // Pull out keys to sort and ensure tests are run in order. + keys := maps.Keys(tests) + slices.Sort(keys) + + // Run all the tests. + var results []testResult for _, name := range keys { if !re.MatchString(name) { continue } - test := tests[name] - if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) { + result := &testResult{Name: name, Pass: true} + if err := tests[name].Run(false, rawdb.HashScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) { if ctx.Bool(DumpFlag.Name) { - if state, _ := chain.State(); state != nil { - fmt.Println(string(state.Dump(nil))) + if s, _ := chain.State(); s != nil { + result.State = dump(s) } } }); err != nil { - return fmt.Errorf("test %v: %w", name, err) + result.Pass, result.Error = false, err.Error() } + results = append(results, *result) } - return nil + return results, nil } diff --git a/cmd/evm/compiler.go b/cmd/evm/compiler.go deleted file mode 100644 index c071834b5..000000000 --- a/cmd/evm/compiler.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "errors" - "fmt" - "os" - - "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" - - "github.com/urfave/cli/v2" -) - -var compileCommand = &cli.Command{ - Action: compileCmd, - Name: "compile", - Usage: "Compiles easm source to evm binary", - ArgsUsage: "", -} - -func compileCmd(ctx *cli.Context) error { - debug := ctx.Bool(DebugFlag.Name) - - if len(ctx.Args().First()) == 0 { - return errors.New("filename required") - } - - fn := ctx.Args().First() - src, err := os.ReadFile(fn) - if err != nil { - return err - } - - bin, err := compiler.Compile(fn, src, debug) - if err != nil { - return err - } - fmt.Println(bin) - return nil -} diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go deleted file mode 100644 index b1f35cbaf..000000000 --- a/cmd/evm/disasm.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "errors" - "fmt" - "os" - "strings" - - "github.com/ethereum/go-ethereum/core/asm" - "github.com/urfave/cli/v2" -) - -var disasmCommand = &cli.Command{ - Action: disasmCmd, - Name: "disasm", - Usage: "Disassembles evm binary", - ArgsUsage: "", -} - -func disasmCmd(ctx *cli.Context) error { - var in string - switch { - case len(ctx.Args().First()) > 0: - fn := ctx.Args().First() - input, err := os.ReadFile(fn) - if err != nil { - return err - } - in = string(input) - case ctx.IsSet(InputFlag.Name): - in = ctx.String(InputFlag.Name) - default: - return errors.New("missing filename or --input value") - } - - code := strings.TrimSpace(in) - fmt.Printf("%v\n", code) - return asm.PrintDisassembled(code) -} diff --git a/cmd/evm/eest.go b/cmd/evm/eest.go new file mode 100644 index 000000000..43071a3e5 --- /dev/null +++ b/cmd/evm/eest.go @@ -0,0 +1,49 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import "regexp" + +// testMetadata provides more granular access to the test information encoded +// within its filename by the execution spec test (EEST). +type testMetadata struct { + fork string + module string // which python module gnerated the test, e.g. eip7702 + file string // exact file the test came from, e.g. test_gas.py + function string // func that created the test, e.g. test_valid_mcopy_operations + parameters string // the name of the parameters which were used to fill the test, e.g. zero_inputs +} + +// parseTestMetadata reads a test name and parses out more specific information +// about the test. +func parseTestMetadata(s string) *testMetadata { + var ( + pattern = `tests\/([^\/]+)\/([^\/]+)\/([^:]+)::([^[]+)\[fork_([^-\]]+)-[^-]+-(.+)\]` + re = regexp.MustCompile(pattern) + ) + match := re.FindStringSubmatch(s) + if len(match) == 0 { + return nil + } + return &testMetadata{ + fork: match[5], + module: match[2], + file: match[3], + function: match[4], + parameters: match[6], + } +} diff --git a/cmd/evm/eofparse.go b/cmd/evm/eofparse.go index 212227094..df8581146 100644 --- a/cmd/evm/eofparse.go +++ b/cmd/evm/eofparse.go @@ -31,13 +31,41 @@ import ( "github.com/urfave/cli/v2" ) +var jt vm.JumpTable + +const initcode = "INITCODE" + func init() { jt = vm.NewPragueEOFInstructionSetForTesting() } var ( - jt vm.JumpTable - initcode = "INITCODE" + hexFlag = &cli.StringFlag{ + Name: "hex", + Usage: "Single container data parse and validation", + } + refTestFlag = &cli.StringFlag{ + Name: "test", + Usage: "Path to EOF validation reference test.", + } + eofParseCommand = &cli.Command{ + Name: "eofparse", + Aliases: []string{"eof"}, + Usage: "Parses hex eof container and returns validation errors (if any)", + Action: eofParseAction, + Flags: []cli.Flag{ + hexFlag, + refTestFlag, + }, + } + eofDumpCommand = &cli.Command{ + Name: "eofdump", + Usage: "Parses hex eof container and prints out human-readable representation of the container.", + Action: eofDumpAction, + Flags: []cli.Flag{ + hexFlag, + }, + } ) func eofParseAction(ctx *cli.Context) error { diff --git a/cmd/evm/internal/compiler/compiler.go b/cmd/evm/internal/compiler/compiler.go deleted file mode 100644 index 54981b669..000000000 --- a/cmd/evm/internal/compiler/compiler.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package compiler - -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/core/asm" -) - -func Compile(fn string, src []byte, debug bool) (string, error) { - compiler := asm.NewCompiler(debug) - compiler.Feed(asm.Lex(src, debug)) - - bin, compileErrors := compiler.Compile() - if len(compileErrors) > 0 { - // report errors - for _, err := range compileErrors { - fmt.Printf("%s:%v\n", fn, err) - } - return "", errors.New("compiling failed") - } - return bin, nil -} diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 0d4471b8d..750b26990 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -19,11 +19,14 @@ package main import ( "fmt" - "math/big" + "io/fs" "os" - "slices" + "path/filepath" "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2" @@ -33,122 +36,100 @@ import ( _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) +// Some other nice-to-haves: +// * accumulate traces into an object to bundle with test +// * write tx identifier for trace before hand (blocktest only) +// * combine blocktest and statetest runner logic using unified test interface + +const traceCategory = "TRACING" + var ( - DebugFlag = &cli.BoolFlag{ - Name: "debug", - Usage: "output full trace logs", - Category: flags.VMCategory, - } - StatDumpFlag = &cli.BoolFlag{ - Name: "statdump", - Usage: "displays stack and heap memory information", - Category: flags.VMCategory, - } - CodeFlag = &cli.StringFlag{ - Name: "code", - Usage: "EVM code", - Category: flags.VMCategory, - } - CodeFileFlag = &cli.StringFlag{ - Name: "codefile", - Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", - Category: flags.VMCategory, - } - GasFlag = &cli.Uint64Flag{ - Name: "gas", - Usage: "gas limit for the evm", - Value: 10000000000, - Category: flags.VMCategory, - } - PriceFlag = &flags.BigFlag{ - Name: "price", - Usage: "price set for the evm", - Value: new(big.Int), - Category: flags.VMCategory, - } - ValueFlag = &flags.BigFlag{ - Name: "value", - Usage: "value set for the evm", - Value: new(big.Int), - Category: flags.VMCategory, - } - DumpFlag = &cli.BoolFlag{ - Name: "dump", - Usage: "dumps the state after the run", - Category: flags.VMCategory, - } - InputFlag = &cli.StringFlag{ - Name: "input", - Usage: "input for the EVM", - Category: flags.VMCategory, - } - InputFileFlag = &cli.StringFlag{ - Name: "inputfile", - Usage: "file containing input for the EVM", - Category: flags.VMCategory, + // Test running flags. + RunFlag = &cli.StringFlag{ + Name: "run", + Value: ".*", + Usage: "Run only those tests matching the regular expression.", } BenchFlag = &cli.BoolFlag{ Name: "bench", Usage: "benchmark the execution", Category: flags.VMCategory, } - CreateFlag = &cli.BoolFlag{ - Name: "create", - Usage: "indicates the action should be create rather than call", - Category: flags.VMCategory, + WitnessCrossCheckFlag = &cli.BoolFlag{ + Name: "cross-check", + Aliases: []string{"xc"}, + Usage: "Cross-check stateful execution against stateless, verifying the witness generation.", } - GenesisFlag = &cli.StringFlag{ - Name: "prestate", - Usage: "JSON file with prestate (genesis) config", - Category: flags.VMCategory, + + // Debugging flags. + DumpFlag = &cli.BoolFlag{ + Name: "dump", + Usage: "dumps the state after the run", } - MachineFlag = &cli.BoolFlag{ - Name: "json", - Usage: "output trace logs in machine readable format (json)", - Category: flags.VMCategory, + HumanReadableFlag = &cli.BoolFlag{ + Name: "human", + Usage: "\"Human-readable\" output", } - SenderFlag = &cli.StringFlag{ - Name: "sender", - Usage: "The transaction origin", - Category: flags.VMCategory, + StatDumpFlag = &cli.BoolFlag{ + Name: "statdump", + Usage: "displays stack and heap memory information", } - ReceiverFlag = &cli.StringFlag{ - Name: "receiver", - Usage: "The transaction receiver (execution context)", - Category: flags.VMCategory, + + // Tracing flags. + TraceFlag = &cli.BoolFlag{ + Name: "trace", + Usage: "Enable tracing and output trace log.", + Category: traceCategory, + } + TraceFormatFlag = &cli.StringFlag{ + Name: "trace.format", + Usage: "Trace output format to use (struct|json)", + Value: "struct", + Category: traceCategory, } - DisableMemoryFlag = &cli.BoolFlag{ - Name: "nomemory", + TraceDisableMemoryFlag = &cli.BoolFlag{ + Name: "trace.nomemory", + Aliases: []string{"nomemory"}, Value: true, Usage: "disable memory output", - Category: flags.VMCategory, + Category: traceCategory, } - DisableStackFlag = &cli.BoolFlag{ - Name: "nostack", + TraceDisableStackFlag = &cli.BoolFlag{ + Name: "trace.nostack", + Aliases: []string{"nostack"}, Usage: "disable stack output", - Category: flags.VMCategory, + Category: traceCategory, } - DisableStorageFlag = &cli.BoolFlag{ - Name: "nostorage", + TraceDisableStorageFlag = &cli.BoolFlag{ + Name: "trace.nostorage", + Aliases: []string{"nostorage"}, Usage: "disable storage output", - Category: flags.VMCategory, + Category: traceCategory, } - DisableReturnDataFlag = &cli.BoolFlag{ - Name: "noreturndata", + TraceDisableReturnDataFlag = &cli.BoolFlag{ + Name: "trace.noreturndata", + Aliases: []string{"noreturndata"}, Value: true, Usage: "enable return data output", - Category: flags.VMCategory, + Category: traceCategory, } - refTestFlag = &cli.StringFlag{ - Name: "test", - Usage: "Path to EOF validation reference test.", + + // Deprecated flags. + DebugFlag = &cli.BoolFlag{ + Name: "debug", + Usage: "output full trace logs (deprecated)", + Hidden: true, + Category: traceCategory, } - hexFlag = &cli.StringFlag{ - Name: "hex", - Usage: "single container data parse and validation", + MachineFlag = &cli.BoolFlag{ + Name: "json", + Usage: "output trace logs in machine readable format, json (deprecated)", + Hidden: true, + Category: traceCategory, } ) +// Command definitions. var ( stateTransitionCommand = &cli.Command{ Name: "transition", @@ -175,7 +156,6 @@ var ( t8ntool.RewardFlag, }, } - transactionCommand = &cli.Command{ Name: "transaction", Aliases: []string{"t9n"}, @@ -203,62 +183,27 @@ var ( t8ntool.SealCliqueFlag, }, } - eofParseCommand = &cli.Command{ - Name: "eofparse", - Aliases: []string{"eof"}, - Usage: "Parses hex eof container and returns validation errors (if any)", - Action: eofParseAction, - Flags: []cli.Flag{ - hexFlag, - refTestFlag, - }, - } - - eofDumpCommand = &cli.Command{ - Name: "eofdump", - Usage: "Parses hex eof container and prints out human-readable representation of the container.", - Action: eofDumpAction, - Flags: []cli.Flag{ - hexFlag, - }, - } ) -// vmFlags contains flags related to running the EVM. -var vmFlags = []cli.Flag{ - CodeFlag, - CodeFileFlag, - CreateFlag, - GasFlag, - PriceFlag, - ValueFlag, - InputFlag, - InputFileFlag, - GenesisFlag, - SenderFlag, - ReceiverFlag, -} - // traceFlags contains flags that configure tracing output. var traceFlags = []cli.Flag{ - BenchFlag, + TraceFlag, + TraceFormatFlag, + TraceDisableStackFlag, + TraceDisableMemoryFlag, + TraceDisableStorageFlag, + TraceDisableReturnDataFlag, + + // deprecated DebugFlag, - DumpFlag, MachineFlag, - StatDumpFlag, - DisableMemoryFlag, - DisableStackFlag, - DisableStorageFlag, - DisableReturnDataFlag, } var app = flags.NewApp("the evm command line interface") func init() { - app.Flags = slices.Concat(vmFlags, traceFlags, debug.Flags) + app.Flags = debug.Flags app.Commands = []*cli.Command{ - compileCommand, - disasmCommand, runCommand, blockTestCommand, stateTestCommand, @@ -280,11 +225,56 @@ func init() { func main() { if err := app.Run(os.Args); err != nil { - code := 1 - if ec, ok := err.(*t8ntool.NumberedError); ok { - code = ec.ExitCode() + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// tracerFromFlags parses the cli flags and returns the specified tracer. +func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { + config := &logger.Config{ + EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), + DisableStack: ctx.Bool(TraceDisableStackFlag.Name), + DisableStorage: ctx.Bool(TraceDisableStorageFlag.Name), + EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name), + } + switch { + case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "struct": + return logger.NewStructLogger(config).Hooks() + case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "json": + return logger.NewJSONLogger(config, os.Stderr) + case ctx.Bool(MachineFlag.Name): + return logger.NewJSONLogger(config, os.Stderr) + case ctx.Bool(DebugFlag.Name): + return logger.NewStructLogger(config).Hooks() + default: + return nil + } +} + +// collectJSONFiles walks the given path and accumulates all files with json +// extension. +func collectJSONFiles(path string) []string { + var out []string + err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err } + if !info.IsDir() && filepath.Ext(info.Name()) == ".json" { + out = append(out, path) + } + return nil + }) + if err != nil { fmt.Fprintln(os.Stderr, err) - os.Exit(code) } + return out +} + +// dump returns a state dump for the most current trie. +func dump(s *state.StateDB) *state.Dump { + root := s.IntermediateRoot(false) + cpy, _ := state.New(root, s.Database()) + dump := cpy.RawDump(nil) + return &dump } diff --git a/cmd/evm/reporter.go b/cmd/evm/reporter.go new file mode 100644 index 000000000..f6249e184 --- /dev/null +++ b/cmd/evm/reporter.go @@ -0,0 +1,87 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/urfave/cli/v2" +) + +const ( + PASS = "\033[32mPASS\033[0m" + FAIL = "\033[31mFAIL\033[0m" +) + +// testResult contains the execution status after running a state test, any +// error that might have occurred and a dump of the final state if requested. +type testResult struct { + Name string `json:"name"` + Pass bool `json:"pass"` + Root *common.Hash `json:"stateRoot,omitempty"` + Fork string `json:"fork"` + Error string `json:"error,omitempty"` + State *state.Dump `json:"state,omitempty"` + Stats *execStats `json:"benchStats,omitempty"` +} + +func (r testResult) String() string { + var status string + if r.Pass { + status = fmt.Sprintf("[%s]", PASS) + } else { + status = fmt.Sprintf("[%s]", FAIL) + } + info := r.Name + m := parseTestMetadata(r.Name) + if m != nil { + info = fmt.Sprintf("%s %s, param=%s", m.module, m.function, m.parameters) + } + var extra string + if !r.Pass { + extra = fmt.Sprintf(", err=%v, fork=%s", r.Error, r.Fork) + } + out := fmt.Sprintf("%s %s%s", status, info, extra) + if r.State != nil { + state, _ := json.MarshalIndent(r.State, "", " ") + out += "\n" + string(state) + } + return out +} + +// report prints the after-test summary. +func report(ctx *cli.Context, results []testResult) { + if ctx.Bool(HumanReadableFlag.Name) { + pass := 0 + for _, r := range results { + if r.Pass { + pass++ + } + } + for _, r := range results { + fmt.Println(r) + } + fmt.Println("--") + fmt.Printf("%d tests passed, %d tests failed.\n", pass, len(results)-pass) + return + } + out, _ := json.MarshalIndent(results, "", " ") + fmt.Println(string(out)) +} diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 2884487fa..afb0bec0e 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -25,10 +25,10 @@ import ( "os" goruntime "runtime" "slices" + "strings" "testing" "time" - "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -51,14 +51,82 @@ var runCommand = &cli.Command{ Usage: "Run arbitrary evm binary", ArgsUsage: "", Description: `The run command runs arbitrary EVM code.`, - Flags: slices.Concat(vmFlags, traceFlags), + Flags: slices.Concat([]cli.Flag{ + BenchFlag, + CodeFileFlag, + CreateFlag, + GasFlag, + GenesisFlag, + InputFlag, + InputFileFlag, + PriceFlag, + ReceiverFlag, + SenderFlag, + ValueFlag, + StatDumpFlag, + }, traceFlags), } +var ( + CodeFileFlag = &cli.StringFlag{ + Name: "codefile", + Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", + Category: flags.VMCategory, + } + CreateFlag = &cli.BoolFlag{ + Name: "create", + Usage: "Indicates the action should be create rather than call", + Category: flags.VMCategory, + } + GasFlag = &cli.Uint64Flag{ + Name: "gas", + Usage: "Gas limit for the evm", + Value: 10000000000, + Category: flags.VMCategory, + } + GenesisFlag = &cli.StringFlag{ + Name: "prestate", + Usage: "JSON file with prestate (genesis) config", + Category: flags.VMCategory, + } + InputFlag = &cli.StringFlag{ + Name: "input", + Usage: "Input for the EVM", + Category: flags.VMCategory, + } + InputFileFlag = &cli.StringFlag{ + Name: "inputfile", + Usage: "File containing input for the EVM", + Category: flags.VMCategory, + } + PriceFlag = &flags.BigFlag{ + Name: "price", + Usage: "Price set for the evm", + Value: new(big.Int), + Category: flags.VMCategory, + } + ReceiverFlag = &cli.StringFlag{ + Name: "receiver", + Usage: "The transaction receiver (execution context)", + Category: flags.VMCategory, + } + SenderFlag = &cli.StringFlag{ + Name: "sender", + Usage: "The transaction origin", + Category: flags.VMCategory, + } + ValueFlag = &flags.BigFlag{ + Name: "value", + Usage: "Value set for the evm", + Value: new(big.Int), + Category: flags.VMCategory, + } +) + // readGenesis will read the given JSON format genesis file and return // the initialized Genesis structure func readGenesis(genesisPath string) *core.Genesis { // Make sure we have a valid genesis JSON - //genesisPath := ctx.Args().First() if len(genesisPath) == 0 { utils.Fatalf("Must supply path to genesis JSON file") } @@ -128,10 +196,10 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe func runCmd(ctx *cli.Context) error { logconfig := &logger.Config{ - EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), - DisableStack: ctx.Bool(DisableStackFlag.Name), - DisableStorage: ctx.Bool(DisableStorageFlag.Name), - EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), + EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), + DisableStack: ctx.Bool(TraceDisableStackFlag.Name), + DisableStorage: ctx.Bool(TraceDisableStorageFlag.Name), + EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name), Debug: ctx.Bool(DebugFlag.Name), } @@ -188,48 +256,35 @@ func runCmd(ctx *cli.Context) error { var code []byte codeFileFlag := ctx.String(CodeFileFlag.Name) - codeFlag := ctx.String(CodeFlag.Name) + hexcode := ctx.Args().First() - // The '--code' or '--codefile' flag overrides code in state - if codeFileFlag != "" || codeFlag != "" { - var hexcode []byte - if codeFileFlag != "" { - var err error - // If - is specified, it means that code comes from stdin - if codeFileFlag == "-" { - //Try reading from stdin - if hexcode, err = io.ReadAll(os.Stdin); err != nil { - fmt.Printf("Could not load code from stdin: %v\n", err) - os.Exit(1) - } - } else { - // Codefile with hex assembly - if hexcode, err = os.ReadFile(codeFileFlag); err != nil { - fmt.Printf("Could not load code from file: %v\n", err) - os.Exit(1) - } - } - } else { - hexcode = []byte(codeFlag) - } - hexcode = bytes.TrimSpace(hexcode) - if len(hexcode)%2 != 0 { - fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode)) - os.Exit(1) - } - code = common.FromHex(string(hexcode)) - } else if fn := ctx.Args().First(); len(fn) > 0 { - // EASM-file to compile - src, err := os.ReadFile(fn) + // The '--codefile' flag overrides code in state + if codeFileFlag == "-" { + // If - is specified, it means that code comes from stdin + // Try reading from stdin + input, err := io.ReadAll(os.Stdin) if err != nil { - return err + fmt.Printf("Could not load code from stdin: %v\n", err) + os.Exit(1) } - bin, err := compiler.Compile(fn, src, false) + hexcode = string(input) + } else if codeFileFlag != "" { + // Codefile with hex assembly + input, err := os.ReadFile(codeFileFlag) if err != nil { - return err + fmt.Printf("Could not load code from file: %v\n", err) + os.Exit(1) } - code = common.Hex2Bytes(bin) + hexcode = string(input) + } + + hexcode = strings.TrimSpace(hexcode) + if len(hexcode)%2 != 0 { + fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode)) + os.Exit(1) } + code = common.FromHex(hexcode) + runtimeConfig := runtime.Config{ Origin: sender, State: prestate, diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index d0a0d3287..323b7d60a 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -21,12 +21,12 @@ import ( "encoding/json" "fmt" "os" + "regexp" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" @@ -35,157 +35,124 @@ import ( var ( forkFlag = &cli.StringFlag{ Name: "statetest.fork", - Usage: "The hard-fork to run the test against", + Usage: "Only run tests for the specified fork.", Category: flags.VMCategory, } idxFlag = &cli.IntFlag{ Name: "statetest.index", - Usage: "The index of the subtest to run", + Usage: "The index of the subtest to run.", Category: flags.VMCategory, Value: -1, // default to select all subtest indices } - testNameFlag = &cli.StringFlag{ - Name: "statetest.name", - Usage: "The name of the state test to run", - Category: flags.VMCategory, - } ) var stateTestCommand = &cli.Command{ Action: stateTestCmd, Name: "statetest", Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).", ArgsUsage: "", - Flags: []cli.Flag{ - forkFlag, - idxFlag, - testNameFlag, - }, -} - -// StatetestResult contains the execution status after running a state test, any -// error that might have occurred and a dump of the final state if requested. -type StatetestResult struct { - Name string `json:"name"` - Pass bool `json:"pass"` - Root *common.Hash `json:"stateRoot,omitempty"` - Fork string `json:"fork"` - Error string `json:"error,omitempty"` - State *state.Dump `json:"state,omitempty"` - BenchStats *execStats `json:"benchStats,omitempty"` + Flags: slices.Concat([]cli.Flag{ + DumpFlag, + HumanReadableFlag, + RunFlag, + }, traceFlags), } func stateTestCmd(ctx *cli.Context) error { - // Configure the EVM logger - config := &logger.Config{ - EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), - DisableStack: ctx.Bool(DisableStackFlag.Name), - DisableStorage: ctx.Bool(DisableStorageFlag.Name), - EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), - } - var cfg vm.Config - switch { - case ctx.Bool(MachineFlag.Name): - cfg.Tracer = logger.NewJSONLogger(config, os.Stderr) + path := ctx.Args().First() - case ctx.Bool(DebugFlag.Name): - cfg.Tracer = logger.NewStructLogger(config).Hooks() - } - // Load the test content from the input file - if len(ctx.Args().First()) != 0 { - return runStateTest(ctx, ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name)) + // If path is provided, run the tests at that path. + if len(path) != 0 { + var ( + collected = collectJSONFiles(path) + results []testResult + ) + for _, fname := range collected { + r, err := runStateTest(ctx, fname) + if err != nil { + return err + } + results = append(results, r...) + } + report(ctx, results) + return nil } - // Read filenames from stdin and execute back-to-back + // Otherwise, read filenames from stdin and execute back-to-back. scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { fname := scanner.Text() if len(fname) == 0 { return nil } - if err := runStateTest(ctx, fname, cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name)); err != nil { + results, err := runStateTest(ctx, fname) + if err != nil { return err } + report(ctx, results) } return nil } -type stateTestCase struct { - name string - test tests.StateTest - st tests.StateSubtest -} - -// collectMatchedSubtests returns test cases which match against provided filtering CLI parameters -func collectMatchedSubtests(ctx *cli.Context, testsByName map[string]tests.StateTest) []stateTestCase { - var res []stateTestCase - subtestName := ctx.String(testNameFlag.Name) - if subtestName != "" { - if subtest, ok := testsByName[subtestName]; ok { - testsByName := make(map[string]tests.StateTest) - testsByName[subtestName] = subtest - } - } - idx := ctx.Int(idxFlag.Name) - fork := ctx.String(forkFlag.Name) - - for key, test := range testsByName { - for _, st := range test.Subtests() { - if idx != -1 && st.Index != idx { - continue - } - if fork != "" && st.Fork != fork { - continue - } - res = append(res, stateTestCase{name: key, st: st, test: test}) - } - } - return res -} - // runStateTest loads the state-test given by fname, and executes the test. -func runStateTest(ctx *cli.Context, fname string, cfg vm.Config, dump bool, bench bool) error { +func runStateTest(ctx *cli.Context, fname string) ([]testResult, error) { src, err := os.ReadFile(fname) if err != nil { - return err + return nil, err } var testsByName map[string]tests.StateTest if err := json.Unmarshal(src, &testsByName); err != nil { - return err + return nil, fmt.Errorf("unable to read test file %s: %w", fname, err) } - matchingTests := collectMatchedSubtests(ctx, testsByName) + cfg := vm.Config{Tracer: tracerFromFlags(ctx)} + re, err := regexp.Compile(ctx.String(RunFlag.Name)) + if err != nil { + return nil, fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err) + } // Iterate over all the tests, run them and aggregate the results - var results []StatetestResult - for _, test := range matchingTests { - // Run the test and aggregate the result - result := &StatetestResult{Name: test.name, Fork: test.st.Fork, Pass: true} - test.test.Run(test.st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) { - var root common.Hash - if tstate.StateDB != nil { - root = tstate.StateDB.IntermediateRoot(false) - result.Root = &root - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) - if dump { // Dump any state to aid debugging - cpy, _ := state.New(root, tstate.StateDB.Database()) - dump := cpy.RawDump(nil) - result.State = &dump - } + results := make([]testResult, 0, len(testsByName)) + for key, test := range testsByName { + if !re.MatchString(key) { + continue + } + for i, st := range test.Subtests() { + if idx := ctx.Int(idxFlag.Name); idx != -1 && idx != i { + // If specific index requested, skip all tests that do not match. + continue } - if err != nil { - // Test failed, mark as so - result.Pass, result.Error = false, err.Error() + if fork := ctx.String(forkFlag.Name); fork != "" && st.Fork != fork { + // If specific fork requested, skip all tests that do not match. + continue } - }) - if bench { - _, stats, _ := timedExec(true, func() ([]byte, uint64, error) { - _, _, gasUsed, _ := test.test.RunNoVerify(test.st, cfg, false, rawdb.HashScheme) - return nil, gasUsed, nil + // Run the test and aggregate the result + result := &testResult{Name: key, Fork: st.Fork, Pass: true} + test.Run(st, cfg, false, rawdb.HashScheme, func(err error, state *tests.StateTestState) { + var root common.Hash + if state.StateDB != nil { + root = state.StateDB.IntermediateRoot(false) + result.Root = &root + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) + // Dump any state to aid debugging. + if ctx.Bool(DumpFlag.Name) { + result.State = dump(state.StateDB) + } + } + // Collect bench stats if requested. + if ctx.Bool(BenchFlag.Name) { + _, stats, _ := timedExec(true, func() ([]byte, uint64, error) { + _, _, gasUsed, _ := test.RunNoVerify(st, cfg, false, rawdb.HashScheme) + return nil, gasUsed, nil + }) + result.Stats = &stats + } + if err != nil { + // Test failed, mark as so. + result.Pass, result.Error = false, err.Error() + return + } }) - result.BenchStats = &stats + results = append(results, *result) } - results = append(results, *result) } - out, _ := json.MarshalIndent(results, "", " ") - fmt.Println(string(out)) - return nil + return results, nil } diff --git a/core/blockchain.go b/core/blockchain.go index b25bbe96c..2c6cd44e3 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2086,7 +2086,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s task := types.NewBlockWithHeader(context).WithBody(*block.Body()) // Run the stateless self-cross-validation - crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness) + crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, bc.vmConfig, task, witness) if err != nil { return nil, fmt.Errorf("stateless self-validation failed: %v", err) } diff --git a/core/stateless.go b/core/stateless.go index 5b37d5020..d21a62b4a 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -40,7 +40,7 @@ import ( // - It cannot be placed outside of core, because it needs to construct a dud headerchain // // TODO(karalabe): Would be nice to resolve both issues above somehow and move it. -func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) { +func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) { // Sanity check if the supplied block accidentally contains a set root or // receipt hash. If so, be very loud, but still continue. if block.Root() != (common.Hash{}) { @@ -66,7 +66,7 @@ func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *s validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block // Run the stateless blocks processing and self-validate certain fields - res, err := processor.Process(block, db, vm.Config{}) + res, err := processor.Process(block, db, vmconfig) if err != nil { return common.Hash{}, common.Hash{}, err } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 4779f9756..fa9752734 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/internal/version" @@ -995,7 +996,7 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v api.lastNewPayloadLock.Unlock() log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash) - stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), block, witness) + stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), vm.Config{}, block, witness) if err != nil { log.Warn("ExecuteStatelessPayload: execution failed", "err", err) errorMsg := err.Error() From 1cf953842a78733474c631bd468d57def37069d6 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 2 Dec 2024 15:43:17 +0100 Subject: [PATCH 028/354] fuzzing: fix oss-fuzz fuzzer (#30845) The fuzzer added recenly to fuzz the eth handler doesn't build on oss-fuzz, because it also has dependencies in the peer_test.go. This change fixes it, I hope, by adding that file also for preprocessing. --- oss-fuzz.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 5e4aa1c25..1f222c433 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -234,10 +234,6 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/secp256k1 \ compile_fuzzer github.com/ethereum/go-ethereum/eth/protocols/eth \ FuzzEthProtocolHandlers fuzz_eth_protocol_handlers \ - $repo/eth/protocols/eth/handler_test.go + $repo/eth/protocols/eth/handler_test.go,$repo/eth/protocols/eth/peer_test.go -#compile_fuzzer tests/fuzzers/vflux FuzzClientPool fuzzClientPool -#compile_fuzzer tests/fuzzers/difficulty Fuzz fuzzDifficulty -#compile_fuzzer tests/fuzzers/les Fuzz fuzzLes - From bb5151ccf641e1ec54e593e8c25ca34149bfb0cb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 2 Dec 2024 18:17:43 +0100 Subject: [PATCH 029/354] internal/debug: rename --trace to --go-execution-trace (#30846) This flag is very rarely needed, so it's OK for it to have a verbose name. The name --trace also conflicts with the concept of EVM tracing, which is much more heavily used. --- internal/debug/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 0e05975c7..adb652d59 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -136,8 +136,8 @@ var ( Category: flags.LoggingCategory, } traceFlag = &cli.StringFlag{ - Name: "trace", - Usage: "Write execution trace to the given file", + Name: "go-execution-trace", + Usage: "Write Go execution trace to the given file", Category: flags.LoggingCategory, } ) From 078724eae596c4336e7ea7f7508b4d399632c53c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 3 Dec 2024 16:11:26 +0100 Subject: [PATCH 030/354] CODEOWNERS: add some more entries for auto assignment (#30851) --- .github/CODEOWNERS | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5852865f9..b56918085 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,25 +1,36 @@ # Lines starting with '#' are comments. # Each line is a file pattern followed by one or more owners. -accounts/usbwallet @karalabe -accounts/scwallet @gballet -accounts/abi @gballet @MariusVanDerWijden -beacon/engine @lightclient -cmd/clef @holiman -cmd/evm @holiman @MariusVanDerWijden @lightclient -consensus @karalabe -core/ @karalabe @holiman @rjl493456442 -eth/ @karalabe @holiman @rjl493456442 -eth/catalyst/ @gballet @lightclient +accounts/usbwallet/ @gballet +accounts/scwallet/ @gballet +accounts/abi/ @gballet @MariusVanDerWijden +beacon/engine/ @MariusVanDerWijden @lightclient @fjl +beacon/light/ @zsfelfoldi +beacon/merkle/ @zsfelfoldi +beacon/types/ @zsfelfoldi @fjl +beacon/params/ @zsfelfoldi @fjl +cmd/clef/ @holiman +cmd/evm/ @holiman @MariusVanDerWijden @lightclient +core/state/ @rjl493456442 @holiman +crypto/ @gballet @jwasinger @holiman @fjl +core/ @holiman @rjl493456442 +eth/ @holiman @rjl493456442 +eth/catalyst/ @MariusVanDerWijden @lightclient @fjl @jwasinger eth/tracers/ @s1na +ethclient/ @fjl +ethdb/ @rjl493456442 +event/ @fjl +trie/ @rjl493456442 +triedb/ @rjl493456442 core/tracing/ @s1na graphql/ @s1na -internal/ethapi @lightclient -internal/era @lightclient -les/ @zsfelfoldi @rjl493456442 -light/ @zsfelfoldi @rjl493456442 +internal/ethapi/ @fjl @s1na @lightclient +internal/era/ @lightclient +metrics/ @holiman +miner/ @MariusVanDerWijden @holiman @fjl @rjl493456442 node/ @fjl p2p/ @fjl @zsfelfoldi +rlp/ @fjl params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi rpc/ @fjl @holiman signer/ @holiman From 9b0e376929c8277d8dbf0e4169c4cef2b87cffdd Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 4 Dec 2024 08:52:59 +0100 Subject: [PATCH 031/354] cmd/evm, eth/tracers: refactor structlogger and make it streaming (#30806) This PR refactors the structlog a bit, making it so that it can be used in a streaming mode. ------------- OBS: this PR makes a change in the input `config` config, the third input-parem field to `debug.traceCall`. Previously, seteting it to e.g. ` {"enableMemory": true, "limit": 1024}` would mean that the response was limited to `1024` items. Since an 'item' may include both memory and storage, the actual size of the response was undertermined. After this change, the response will be limited to `1024` __`bytes`__ (or thereabouts). ----------- The commandline usage of structlog now uses the streaming mode, leaving the non-streaming mode of operation for the eth_Call. There are two benefits of streaming mode 1. Not have to maintain a long list of operations, 2. Not have to duplicate / n-plicate data, e.g. memory / stack / returndata so that each entry has their own private slice. --------- Co-authored-by: Gary Rong --- cmd/evm/main.go | 4 +- cmd/evm/runner.go | 29 ++- core/vm/runtime/runtime_test.go | 19 +- eth/tracers/api_test.go | 2 +- eth/tracers/logger/logger.go | 311 ++++++++++++++++---------------- eth/tracers/tracers_test.go | 24 +-- 6 files changed, 200 insertions(+), 189 deletions(-) diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 750b26990..6e0345ce6 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -240,13 +240,13 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { } switch { case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "struct": - return logger.NewStructLogger(config).Hooks() + return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "json": return logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(MachineFlag.Name): return logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(DebugFlag.Name): - return logger.NewStructLogger(config).Hooks() + return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() default: return nil } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index afb0bec0e..59ad8687d 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "encoding/hex" "encoding/json" "fmt" "io" @@ -35,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -205,7 +207,6 @@ func runCmd(ctx *cli.Context) error { var ( tracer *tracing.Hooks - debugLogger *logger.StructLogger prestate *state.StateDB chainConfig *params.ChainConfig sender = common.BytesToAddress([]byte("sender")) @@ -217,10 +218,7 @@ func runCmd(ctx *cli.Context) error { if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) } else if ctx.Bool(DebugFlag.Name) { - debugLogger = logger.NewStructLogger(logconfig) - tracer = debugLogger.Hooks() - } else { - debugLogger = logger.NewStructLogger(logconfig) + tracer = logger.NewStreamingStructLogger(logconfig, os.Stderr).Hooks() } initialGas := ctx.Uint64(GasFlag.Name) @@ -365,12 +363,10 @@ func runCmd(ctx *cli.Context) error { } if ctx.Bool(DebugFlag.Name) { - if debugLogger != nil { - fmt.Fprintln(os.Stderr, "#### TRACE ####") - logger.WriteTrace(os.Stderr, debugLogger.StructLogs()) + if logs := runtimeConfig.State.Logs(); len(logs) > 0 { + fmt.Fprintln(os.Stderr, "### LOGS") + writeLogs(os.Stderr, logs) } - fmt.Fprintln(os.Stderr, "#### LOGS ####") - logger.WriteLogs(os.Stderr, runtimeConfig.State.Logs()) } if bench || ctx.Bool(StatDumpFlag.Name) { @@ -389,3 +385,16 @@ allocated bytes: %d return nil } + +// writeLogs writes vm logs in a readable format to the given writer +func writeLogs(writer io.Writer, logs []*types.Log) { + for _, log := range logs { + fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex) + + for i, topic := range log.Topics { + fmt.Fprintf(writer, "%08d %x\n", i, topic) + } + fmt.Fprint(writer, hex.Dump(log.Data)) + fmt.Fprintln(writer) + } +} diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 7d1345a57..0e774a01c 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/asm" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/program" @@ -670,17 +671,23 @@ func TestColdAccountAccessCost(t *testing.T) { want: 7600, }, } { - tracer := logger.NewStructLogger(nil) + var step = 0 + var have = uint64(0) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: tracer.Hooks(), + Tracer: &tracing.Hooks{ + OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + // Uncomment to investigate failures: + //t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) + if step == tc.step { + have = cost + } + step++ + }, + }, }, }) - have := tracer.StructLogs()[tc.step].GasCost if want := tc.want; have != want { - for ii, op := range tracer.StructLogs() { - t.Logf("%d: %v %d", ii, op.OpName(), op.GasCost) - } t.Fatalf("testcase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want) } } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 1b933f06f..97c86a40e 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -535,7 +535,7 @@ func TestTraceTransaction(t *testing.T) { Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []logger.StructLogRes{}, + StructLogs: []json.RawMessage{}, }) { t.Error("Transaction tracing result is different") } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index bdd4e0705..51b1512d0 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "io" + "maps" "math/big" "strings" "sync/atomic" @@ -38,15 +39,6 @@ import ( // Storage represents a contract's storage. type Storage map[common.Hash]common.Hash -// Copy duplicates the current storage. -func (s Storage) Copy() Storage { - cpy := make(Storage, len(s)) - for key, value := range s { - cpy[key] = value - } - return cpy -} - // Config are the configuration options for structured logger the EVM type Config struct { EnableMemory bool // enable memory capture @@ -54,15 +46,16 @@ type Config struct { DisableStorage bool // disable storage capture EnableReturnData bool // enable return data capture Debug bool // print output during capture end - Limit int // maximum length of output, but zero means unlimited + Limit int // maximum size of output, but zero means unlimited + // Chain overrides, can be used to execute a trace using future fork rules Overrides *params.ChainConfig `json:"overrides,omitempty"` } //go:generate go run github.com/fjl/gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go -// StructLog is emitted to the EVM each cycle and lists information about the current internal state -// prior to the execution of the statement. +// StructLog is emitted to the EVM each cycle and lists information about the +// current internal state prior to the execution of the statement. type StructLog struct { Pc uint64 `json:"pc"` Op vm.OpCode `json:"op"` @@ -102,29 +95,144 @@ func (s *StructLog) ErrorString() string { return "" } +// WriteTo writes the human-readable log data into the supplied writer. +func (s *StructLog) WriteTo(writer io.Writer) { + fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", s.Op, s.Pc, s.Gas, s.GasCost) + if s.Err != nil { + fmt.Fprintf(writer, " ERROR: %v", s.Err) + } + fmt.Fprintln(writer) + + if len(s.Stack) > 0 { + fmt.Fprintln(writer, "Stack:") + for i := len(s.Stack) - 1; i >= 0; i-- { + fmt.Fprintf(writer, "%08d %s\n", len(s.Stack)-i-1, s.Stack[i].Hex()) + } + } + if len(s.Memory) > 0 { + fmt.Fprintln(writer, "Memory:") + fmt.Fprint(writer, hex.Dump(s.Memory)) + } + if len(s.Storage) > 0 { + fmt.Fprintln(writer, "Storage:") + for h, item := range s.Storage { + fmt.Fprintf(writer, "%x: %x\n", h, item) + } + } + if len(s.ReturnData) > 0 { + fmt.Fprintln(writer, "ReturnData:") + fmt.Fprint(writer, hex.Dump(s.ReturnData)) + } + fmt.Fprintln(writer) +} + +// structLogLegacy stores a structured log emitted by the EVM while replaying a +// transaction in debug mode. It's the legacy format used in tracer. The differences +// between the structLog json and the 'legacy' json are: +// +// op: +// Legacy uses string (e.g. "SSTORE"), non-legacy uses a byte. +// non-legacy has an 'opName' field containing the op name. +// +// gas, gasCost: +// Legacy uses integers, non-legacy hex-strings +// +// memory: +// Legacy uses a list of 64-char strings, each representing 32-byte chunks +// of evm memory. Non-legacy just uses a string of hexdata, no chunking. +// +// storage: +// Legacy has a storage field while non-legacy doesn't. +type structLogLegacy struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error string `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + ReturnData string `json:"returnData,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` + RefundCounter uint64 `json:"refund,omitempty"` +} + +// toLegacyJSON converts the structLog to legacy json-encoded legacy form. +func (s *StructLog) toLegacyJSON() json.RawMessage { + msg := structLogLegacy{ + Pc: s.Pc, + Op: s.Op.String(), + Gas: s.Gas, + GasCost: s.GasCost, + Depth: s.Depth, + Error: s.ErrorString(), + RefundCounter: s.RefundCounter, + } + if s.Stack != nil { + stack := make([]string, len(s.Stack)) + for i, stackValue := range s.Stack { + stack[i] = stackValue.Hex() + } + msg.Stack = &stack + } + if len(s.ReturnData) > 0 { + msg.ReturnData = hexutil.Bytes(s.ReturnData).String() + } + if s.Memory != nil { + memory := make([]string, 0, (len(s.Memory)+31)/32) + for i := 0; i+32 <= len(s.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", s.Memory[i:i+32])) + } + msg.Memory = &memory + } + if s.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range s.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + msg.Storage = &storage + } + element, _ := json.Marshal(msg) + return element +} + // StructLogger is an EVM state logger and implements EVMLogger. // // StructLogger can capture state based on the given Log configuration and also keeps // a track record of modified storage which is used in reporting snapshots of the // contract their storage. +// +// A StructLogger can either yield it's output immediately (streaming) or store for +// later output. type StructLogger struct { cfg Config env *tracing.VMContext storage map[common.Address]Storage - logs []StructLog output []byte err error usedGas uint64 + writer io.Writer // If set, the logger will stream instead of store logs + logs []json.RawMessage // buffer of json-encoded logs + resultSize int + interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } -// NewStructLogger returns a new logger +// NewStreamingStructLogger returns a new streaming logger. +func NewStreamingStructLogger(cfg *Config, writer io.Writer) *StructLogger { + l := NewStructLogger(cfg) + l.writer = writer + return l +} + +// NewStructLogger construct a new (non-streaming) struct logger. func NewStructLogger(cfg *Config) *StructLogger { logger := &StructLogger{ storage: make(map[common.Address]Storage), + logs: make([]json.RawMessage, 0), } if cfg != nil { logger.cfg = *cfg @@ -141,44 +249,36 @@ func (l *StructLogger) Hooks() *tracing.Hooks { } } -// Reset clears the data held by the logger. -func (l *StructLogger) Reset() { - l.storage = make(map[common.Address]Storage) - l.output = make([]byte, 0) - l.logs = l.logs[:0] - l.err = nil -} - // OnOpcode logs a new structured log message and pushes it out to the environment // // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { - // If tracing was interrupted, set the error and stop + // If tracing was interrupted, exit if l.interrupt.Load() { return } - // check if already accumulated the specified number of logs - if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { + // check if already accumulated the size of the response. + if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit { return } - - op := vm.OpCode(opcode) - memory := scope.MemoryData() - stack := scope.StackData() - // Copy a snapshot of the current memory state to a new buffer - var mem []byte + var ( + op = vm.OpCode(opcode) + memory = scope.MemoryData() + contractAddr = scope.Address() + stack = scope.StackData() + stackLen = len(stack) + ) + log := StructLog{pc, op, gas, cost, nil, len(memory), nil, nil, nil, depth, l.env.StateDB.GetRefund(), err} if l.cfg.EnableMemory { - mem = make([]byte, len(memory)) - copy(mem, memory) + log.Memory = memory } - // Copy a snapshot of the current stack state to a new buffer - var stck []uint256.Int if !l.cfg.DisableStack { - stck = make([]uint256.Int, len(stack)) - copy(stck, stack) + log.Stack = scope.StackData() + } + if l.cfg.EnableReturnData { + log.ReturnData = rData } - contractAddr := scope.Address() - stackLen := len(stack) + // Copy a snapshot of the current storage to a new container var storage Storage if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) { @@ -194,7 +294,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope value = l.env.StateDB.GetState(contractAddr, address) ) l.storage[contractAddr][address] = value - storage = l.storage[contractAddr].Copy() + storage = maps.Clone(l.storage[contractAddr]) } else if op == vm.SSTORE && stackLen >= 2 { // capture SSTORE opcodes and record the written entry in the local storage. var ( @@ -202,17 +302,19 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope address = common.Hash(stack[stackLen-1].Bytes32()) ) l.storage[contractAddr][address] = value - storage = l.storage[contractAddr].Copy() + storage = maps.Clone(l.storage[contractAddr]) } } - var rdata []byte - if l.cfg.EnableReturnData { - rdata = make([]byte, len(rData)) - copy(rdata, rData) + log.Storage = storage + + // create a log + if l.writer == nil { + entry := log.toLegacyJSON() + l.resultSize += len(entry) + l.logs = append(l.logs, entry) + return } - // create a new snapshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} - l.logs = append(l.logs, log) + log.WriteTo(l.writer) } // OnExit is called a call frame finishes processing. @@ -246,7 +348,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { Gas: l.usedGas, Failed: failed, ReturnValue: returnVal, - StructLogs: formatLogs(l.StructLogs()), + StructLogs: l.logs, }) } @@ -273,9 +375,6 @@ func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { } } -// StructLogs returns the captured log entries. -func (l *StructLogger) StructLogs() []StructLog { return l.logs } - // Error returns the VM error captured by the trace. func (l *StructLogger) Error() error { return l.err } @@ -283,49 +382,10 @@ func (l *StructLogger) Error() error { return l.err } func (l *StructLogger) Output() []byte { return l.output } // WriteTrace writes a formatted trace to the given writer +// @deprecated func WriteTrace(writer io.Writer, logs []StructLog) { for _, log := range logs { - fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost) - if log.Err != nil { - fmt.Fprintf(writer, " ERROR: %v", log.Err) - } - fmt.Fprintln(writer) - - if len(log.Stack) > 0 { - fmt.Fprintln(writer, "Stack:") - for i := len(log.Stack) - 1; i >= 0; i-- { - fmt.Fprintf(writer, "%08d %s\n", len(log.Stack)-i-1, log.Stack[i].Hex()) - } - } - if len(log.Memory) > 0 { - fmt.Fprintln(writer, "Memory:") - fmt.Fprint(writer, hex.Dump(log.Memory)) - } - if len(log.Storage) > 0 { - fmt.Fprintln(writer, "Storage:") - for h, item := range log.Storage { - fmt.Fprintf(writer, "%x: %x\n", h, item) - } - } - if len(log.ReturnData) > 0 { - fmt.Fprintln(writer, "ReturnData:") - fmt.Fprint(writer, hex.Dump(log.ReturnData)) - } - fmt.Fprintln(writer) - } -} - -// WriteLogs writes vm logs in a readable format to the given writer -func WriteLogs(writer io.Writer, logs []*types.Log) { - for _, log := range logs { - fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex) - - for i, topic := range log.Topics { - fmt.Fprintf(writer, "%08d %x\n", i, topic) - } - - fmt.Fprint(writer, hex.Dump(log.Data)) - fmt.Fprintln(writer) + log.WriteTo(writer) } } @@ -425,65 +485,8 @@ func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value type ExecutionResult struct { - Gas uint64 `json:"gas"` - Failed bool `json:"failed"` - ReturnValue string `json:"returnValue"` - StructLogs []StructLogRes `json:"structLogs"` -} - -// StructLogRes stores a structured log emitted by the EVM while replaying a -// transaction in debug mode -type StructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth int `json:"depth"` - Error string `json:"error,omitempty"` - Stack *[]string `json:"stack,omitempty"` - ReturnData string `json:"returnData,omitempty"` - Memory *[]string `json:"memory,omitempty"` - Storage *map[string]string `json:"storage,omitempty"` - RefundCounter uint64 `json:"refund,omitempty"` -} - -// formatLogs formats EVM returned structured logs for json output -func formatLogs(logs []StructLog) []StructLogRes { - formatted := make([]StructLogRes, len(logs)) - for index, trace := range logs { - formatted[index] = StructLogRes{ - Pc: trace.Pc, - Op: trace.Op.String(), - Gas: trace.Gas, - GasCost: trace.GasCost, - Depth: trace.Depth, - Error: trace.ErrorString(), - RefundCounter: trace.RefundCounter, - } - if trace.Stack != nil { - stack := make([]string, len(trace.Stack)) - for i, stackValue := range trace.Stack { - stack[i] = stackValue.Hex() - } - formatted[index].Stack = &stack - } - if len(trace.ReturnData) > 0 { - formatted[index].ReturnData = hexutil.Bytes(trace.ReturnData).String() - } - if trace.Memory != nil { - memory := make([]string, 0, (len(trace.Memory)+31)/32) - for i := 0; i+32 <= len(trace.Memory); i += 32 { - memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) - } - formatted[index].Memory = &memory - } - if trace.Storage != nil { - storage := make(map[string]string) - for i, storageValue := range trace.Storage { - storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) - } - formatted[index].Storage = &storage - } - } - return formatted + Gas uint64 `json:"gas"` + Failed bool `json:"failed"` + ReturnValue string `json:"returnValue"` + StructLogs []json.RawMessage `json:"structLogs"` } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 9d8f70386..13c36379e 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -31,7 +31,7 @@ import ( "github.com/ethereum/go-ethereum/tests" ) -func BenchmarkTransactionTrace(b *testing.B) { +func BenchmarkTransactionTraceV2(b *testing.B) { key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") from := crypto.PubkeyToAddress(key.PublicKey) gas := uint64(1000000) // 1M gas @@ -78,14 +78,8 @@ func BenchmarkTransactionTrace(b *testing.B) { state := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme) defer state.Close() - // Create the tracer, the EVM environment and run it - tracer := logger.NewStructLogger(&logger.Config{ - Debug: false, - //DisableStorage: true, - //EnableMemory: false, - //EnableReturnData: false, - }) - evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) + evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{}) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -94,17 +88,15 @@ func BenchmarkTransactionTrace(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - snap := state.StateDB.Snapshot() + tracer := logger.NewStructLogger(&logger.Config{Debug: false}).Hooks() tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) - res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + evm.Config.Tracer = tracer + + snap := state.StateDB.Snapshot() + _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { b.Fatal(err) } - tracer.OnTxEnd(&types.Receipt{GasUsed: res.UsedGas}, nil) state.StateDB.RevertToSnapshot(snap) - if have, want := len(tracer.StructLogs()), 244752; have != want { - b.Fatalf("trace wrong, want %d steps, have %d", want, have) - } - tracer.Reset() } } From d1c74369ea4c9e07625ec0114f6aaeedfd22d1b2 Mon Sep 17 00:00:00 2001 From: Nebojsa Urosevic Date: Wed, 4 Dec 2024 00:40:37 -0800 Subject: [PATCH 032/354] core/tracing: extends tracing.Hooks with OnSystemCallStartV2 (#30786) This PR extends the Hooks interface with a new method, `OnSystemCallStartV2`, which takes `VMContext` as its parameter. Motivation By including `VMContext` as a parameter, the `OnSystemCallStartV2` hook achieves parity with the `OnTxStart` hook in terms of provided insights. This alignment simplifies the inner tracer logic, enabling consistent handling of state changes and internal calls within the same framework. --------- Co-authored-by: Sina Mahmoodi --- core/state_processor.go | 21 ++++++++++++--------- core/tracing/hooks.go | 21 +++++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 0640caa22..582fb14a7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -230,9 +231,7 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header * // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { if tracer := evm.Config.Tracer; tracer != nil { - if tracer.OnSystemCallStart != nil { - tracer.OnSystemCallStart() - } + onSystemCallStart(tracer, evm.GetVMContext()) if tracer.OnSystemCallEnd != nil { defer tracer.OnSystemCallEnd() } @@ -256,9 +255,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { // as per EIP-2935. func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { if tracer := evm.Config.Tracer; tracer != nil { - if tracer.OnSystemCallStart != nil { - tracer.OnSystemCallStart() - } + onSystemCallStart(tracer, evm.GetVMContext()) if tracer.OnSystemCallEnd != nil { defer tracer.OnSystemCallEnd() } @@ -292,9 +289,7 @@ func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) { func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) { if tracer := evm.Config.Tracer; tracer != nil { - if tracer.OnSystemCallStart != nil { - tracer.OnSystemCallStart() - } + onSystemCallStart(tracer, evm.GetVMContext()) if tracer.OnSystemCallEnd != nil { defer tracer.OnSystemCallEnd() } @@ -341,6 +336,14 @@ func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.Chai return nil } +func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) { + if tracer.OnSystemCallStartV2 != nil { + tracer.OnSystemCallStartV2(ctx) + } else if tracer.OnSystemCallStart != nil { + tracer.OnSystemCallStart() + } +} + // ProcessOnPersist applies a system call to the governance contract. func ProcessOnPersist(evm *vm.EVM) error { if tracer := evm.Config.Tracer; tracer != nil { diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 5218e80c9..728f15069 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -145,6 +145,10 @@ type ( // will not be invoked. OnSystemCallStartHook = func() + // OnSystemCallStartHookV2 is called when a system call is about to be executed. Refer + // to `OnSystemCallStartHook` for more information. + OnSystemCallStartHookV2 = func(vm *VMContext) + // OnSystemCallEndHook is called when a system call has finished executing. Today, // this hook is invoked when the EIP-4788 system call is about to be executed to set the // beacon block root. @@ -180,14 +184,15 @@ type Hooks struct { OnFault FaultHook OnGasChange GasChangeHook // Chain events - OnBlockchainInit BlockchainInitHook - OnClose CloseHook - OnBlockStart BlockStartHook - OnBlockEnd BlockEndHook - OnSkippedBlock SkippedBlockHook - OnGenesisBlock GenesisBlockHook - OnSystemCallStart OnSystemCallStartHook - OnSystemCallEnd OnSystemCallEndHook + OnBlockchainInit BlockchainInitHook + OnClose CloseHook + OnBlockStart BlockStartHook + OnBlockEnd BlockEndHook + OnSkippedBlock SkippedBlockHook + OnGenesisBlock GenesisBlockHook + OnSystemCallStart OnSystemCallStartHook + OnSystemCallStartV2 OnSystemCallStartHookV2 + OnSystemCallEnd OnSystemCallEndHook // State events OnBalanceChange BalanceChangeHook OnNonceChange NonceChangeHook From 5227cba6640f363f6e21f25928cafbee655711bd Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:14:05 +0100 Subject: [PATCH 033/354] trie/utils: ensure master can generate a correct genesis for kaustinen7 (#30856) This imports the following fixes: - update gnark to 1.1.0 - update go-verkle to 0.2.2 - fix: main storage offset bug (gballet/go-ethereum#329) - fix: tree key generation (gballet/go-ethereum#401) --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Ignacio Hagopian --- core/genesis_test.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- trie/utils/verkle.go | 16 ++++------------ trie/verkle_test.go | 4 ++-- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/core/genesis_test.go b/core/genesis_test.go index edbcc8e41..1bb930a6a 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -293,7 +293,7 @@ func TestVerkleGenesisCommit(t *testing.T) { }, } - expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b") + expected := common.FromHex("018d20eebb130b5e2b796465fe36aafab650650729a92435aec071bf2386f080") got := genesis.ToBlock().Root().Bytes() if !bytes.Equal(got, expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) diff --git a/go.mod b/go.mod index dfeeaf27f..6037650a5 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/cockroachdb/pebble v1.1.2 github.com/consensys/gnark v0.13.0 github.com/consensys/gnark-crypto v0.18.0 - github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.6.0 @@ -26,7 +26,7 @@ require ( github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 - github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 + github.com/ethereum/go-verkle v0.2.2 github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.3 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e diff --git a/go.sum b/go.sum index 30aab0175..ba90b6429 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,8 @@ github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -171,8 +171,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= -github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo= diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index b785e512b..1d33f6c3e 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -41,10 +41,10 @@ var ( zero = uint256.NewInt(0) verkleNodeWidthLog2 = 8 headerStorageOffset = uint256.NewInt(64) - mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(256), 31-uint(verkleNodeWidthLog2)) codeOffset = uint256.NewInt(128) verkleNodeWidth = uint256.NewInt(256) codeStorageDelta = uint256.NewInt(0).Sub(codeOffset, headerStorageOffset) + mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(1), 248-uint(verkleNodeWidthLog2)) index0Point *verkle.Point // pre-computed commitment of polynomial [2+256*64] @@ -273,17 +273,9 @@ func StorageSlotKeyWithEvaluatedAddress(evaluated *verkle.Point, storageKey []by } func pointToHash(evaluated *verkle.Point, suffix byte) []byte { - // The output of Byte() is big endian for banderwagon. This - // introduces an imbalance in the tree, because hashes are - // elements of a 253-bit field. This means more than half the - // tree would be empty. To avoid this problem, use a little - // endian commitment and chop the MSB. - bytes := evaluated.Bytes() - for i := 0; i < 16; i++ { - bytes[31-i], bytes[i] = bytes[i], bytes[31-i] - } - bytes[31] = suffix - return bytes[:] + retb := verkle.HashPointToBytes(evaluated) + retb[31] = suffix + return retb[:] } func evaluateAddressPoint(address []byte) *verkle.Point { diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 4cd1717c0..84eec2ed3 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -136,8 +136,8 @@ func TestVerkleRollBack(t *testing.T) { } } - // ensure there is some code in the 2nd group - keyOf2ndGroup := []byte{141, 124, 185, 236, 50, 22, 185, 39, 244, 47, 97, 209, 96, 235, 22, 13, 205, 38, 18, 201, 128, 223, 0, 59, 146, 199, 222, 119, 133, 13, 91, 0} + // ensure there is some code in the 2nd group of the 1st account + keyOf2ndGroup := utils.CodeChunkKeyWithEvaluatedAddress(tr.cache.Get(common.Address{1}.Bytes()), uint256.NewInt(128)) chunk, err := tr.root.Get(keyOf2ndGroup, nil) if err != nil { t.Fatalf("Failed to get account, %v", err) From 766b3b9b72da18004f419c98cf9ea96cde7a2063 Mon Sep 17 00:00:00 2001 From: steven Date: Tue, 10 Dec 2024 02:29:19 +0800 Subject: [PATCH 034/354] core/txpool: remove unused parameter `local` (#30871) --- core/txpool/legacypool/legacypool.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 36c78a0bf..7d6dbcd07 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -751,7 +751,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). -func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error { +func (pool *LegacyPool) validateTx(tx *types.Transaction) error { opts := &txpool.ValidationOptionsWithState{ State: pool.currentState, @@ -807,7 +807,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e isLocal := local || pool.locals.containsTx(tx) // If the transaction fails basic validation, discard it - if err := pool.validateTx(tx, isLocal); err != nil { + if err := pool.validateTx(tx); err != nil { log.Trace("Discarding invalid transaction", "hash", hash, "err", err) invalidTxMeter.Mark(1) return false, err From f46ea0ec828e5977c0f184bab19fb93d2bb5d388 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 10 Dec 2024 10:10:49 +0800 Subject: [PATCH 035/354] core/state: enable partial-functional reader (snapshot integration pt 3) (#30650) It's a pull request based on https://github.com/ethereum/go-ethereum/pull/30643 In this pull request, the partial functional state reader is enabled if **legacy snapshot is not enabled**. The tracked flat states in pathdb will be used to serve the state retrievals, as the second implementation to fasten the state access. This pull request should be a noop change in normal cases. --- core/state/database.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/state/database.go b/core/state/database.go index fff7f1519..faf495465 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -179,10 +179,19 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { // is optional and may be partially useful if it's not fully // generated. if db.snap != nil { + // If standalone state snapshot is available (hash scheme), + // then construct the legacy snap reader. snap := db.snap.Snapshot(stateRoot) if snap != nil { readers = append(readers, newFlatReader(snap)) } + } else { + // If standalone state snapshot is not available, try to construct + // the state reader with database. + reader, err := db.triedb.StateReader(stateRoot) + if err == nil { + readers = append(readers, newFlatReader(reader)) // state reader is optional + } } // Set up the trie reader, which is expected to always be available // as the gatekeeper unless the state is corrupted. From 95df7fa9c6b3afb74b5a8f21f15ddb46bbbec555 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 10 Dec 2024 09:43:24 +0100 Subject: [PATCH 036/354] cmd/evm: consolidate evm output switches (#30849) This PR attempts to clean up some ambiguities and quirks from recent changes to evm flag handling. This PR mainly focuses on `evm run` subcommand, to use the same flags for configuring tracing/output options as `statetest/blocktest` does. Additionally, it adds quite a lot of tests for expected outputs of the various subcommands, to avoid accidental changes. --------- Co-authored-by: Felix Lange --- cmd/evm/internal/t8ntool/transition.go | 1 - cmd/evm/main.go | 18 +- cmd/evm/runner.go | 17 +- cmd/evm/t8n_test.go | 264 ++++--- cmd/evm/testdata/evmrun/1.out.1.txt | 0 cmd/evm/testdata/evmrun/1.out.2.txt | 3 + cmd/evm/testdata/evmrun/2.out.1.txt | 0 cmd/evm/testdata/evmrun/2.out.2.txt | 6 + cmd/evm/testdata/evmrun/3.out.1.txt | 13 + cmd/evm/testdata/evmrun/3.out.2.txt | 9 + cmd/evm/testdata/evmrun/4.out.1.txt | 13 + cmd/evm/testdata/evmrun/4.out.2.txt | 6 + cmd/evm/testdata/evmrun/5.out.1.txt | 0 cmd/evm/testdata/evmrun/5.out.2.txt | 16 + cmd/evm/testdata/evmrun/6.out.1.txt | 9 + cmd/evm/testdata/evmrun/6.out.2.txt | 1 + cmd/evm/testdata/evmrun/7.out.1.txt | 9 + cmd/evm/testdata/evmrun/7.out.2.txt | 925 +++++++++++++++++++++++++ cmd/evm/testdata/evmrun/8.out.1.txt | 9 + cmd/evm/testdata/evmrun/8.out.2.txt | 916 ++++++++++++++++++++++++ cmd/evm/testdata/statetest.json | 57 ++ eth/tracers/api.go | 1 - eth/tracers/logger/logger.go | 15 +- eth/tracers/tracers_test.go | 2 +- 24 files changed, 2188 insertions(+), 122 deletions(-) create mode 100644 cmd/evm/testdata/evmrun/1.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/1.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/2.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/2.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/3.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/3.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/4.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/4.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/5.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/5.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/6.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/6.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/7.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/7.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/8.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/8.out.2.txt create mode 100755 cmd/evm/testdata/statetest.json diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 4a2e5c3b5..4c2bd1b13 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -97,7 +97,6 @@ func Transition(ctx *cli.Context) error { DisableStack: ctx.Bool(TraceDisableStackFlag.Name), EnableMemory: ctx.Bool(TraceEnableMemoryFlag.Name), EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), - Debug: true, } getTracer = func(txIndex int, txHash common.Hash, _ *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) { traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 6e0345ce6..0e6f6fa5b 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -239,10 +239,20 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name), } switch { - case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "struct": - return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() - case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "json": - return logger.NewJSONLogger(config, os.Stderr) + case ctx.Bool(TraceFlag.Name): + switch format := ctx.String(TraceFormatFlag.Name); format { + case "struct": + return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() + case "json": + return logger.NewJSONLogger(config, os.Stderr) + case "md", "markdown": + return logger.NewMarkdownLogger(config, os.Stderr).Hooks() + default: + fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format) + os.Exit(1) + return nil + } + // Deprecated ways of configuring tracing. case ctx.Bool(MachineFlag.Name): return logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(DebugFlag.Name): diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 59ad8687d..c67d3657e 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -66,6 +65,7 @@ var runCommand = &cli.Command{ SenderFlag, ValueFlag, StatDumpFlag, + DumpFlag, }, traceFlags), } @@ -197,14 +197,6 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe } func runCmd(ctx *cli.Context) error { - logconfig := &logger.Config{ - EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), - DisableStack: ctx.Bool(TraceDisableStackFlag.Name), - DisableStorage: ctx.Bool(TraceDisableStorageFlag.Name), - EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name), - Debug: ctx.Bool(DebugFlag.Name), - } - var ( tracer *tracing.Hooks prestate *state.StateDB @@ -215,12 +207,7 @@ func runCmd(ctx *cli.Context) error { blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests blobBaseFee = new(big.Int) // TODO (MariusVanDerWijden) implement blob fee in state tests ) - if ctx.Bool(MachineFlag.Name) { - tracer = logger.NewJSONLogger(logconfig, os.Stdout) - } else if ctx.Bool(DebugFlag.Name) { - tracer = logger.NewStreamingStructLogger(logconfig, os.Stderr).Hooks() - } - + tracer = tracerFromFlags(ctx) initialGas := ctx.Uint64(GasFlag.Name) genesisConfig := new(core.Genesis) genesisConfig.GasLimit = initialGas diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 65723694f..85caf010b 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -341,98 +341,6 @@ func lineIterator(path string) func() (string, error) { } } -// TestT8nTracing is a test that checks the tracing-output from t8n. -func TestT8nTracing(t *testing.T) { - t.Parallel() - tt := new(testT8n) - tt.TestCmd = cmdtest.NewTestCmd(t, tt) - for i, tc := range []struct { - base string - input t8nInput - expExitCode int - extraArgs []string - expectedTraces []string - }{ - { - base: "./testdata/31", - input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Cancun", "", - }, - extraArgs: []string{"--trace"}, - expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"}, - }, - { - base: "./testdata/31", - input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Cancun", "", - }, - extraArgs: []string{"--trace.tracer", ` -{ - result: function(){ - return "hello world" - }, - fault: function(){} -}`}, - expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, - }, - { - base: "./testdata/32", - input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Paris", "", - }, - extraArgs: []string{"--trace", "--trace.callframes"}, - expectedTraces: []string{"trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl"}, - }, - } { - args := []string{"t8n"} - args = append(args, tc.input.get(tc.base)...) - // Place the output somewhere we can find it - outdir := t.TempDir() - args = append(args, "--output.basedir", outdir) - args = append(args, tc.extraArgs...) - - var qArgs []string // quoted args for debugging purposes - for _, arg := range args { - if len(arg) == 0 { - qArgs = append(qArgs, `""`) - } else { - qArgs = append(qArgs, arg) - } - } - tt.Logf("args: %v\n", strings.Join(qArgs, " ")) - tt.Run("evm-test", args...) - t.Log(string(tt.Output())) - - // Compare the expected traces - for _, traceFile := range tc.expectedTraces { - haveFn := lineIterator(filepath.Join(outdir, traceFile)) - wantFn := lineIterator(filepath.Join(tc.base, traceFile)) - - for line := 0; ; line++ { - want, wErr := wantFn() - have, hErr := haveFn() - if want != have { - t.Fatalf("test %d, trace %v, line %d\nwant: %v\nhave: %v\n", - i, traceFile, line, want, have) - } - if wErr != nil && hErr != nil { - break - } - if wErr != nil { - t.Fatal(wErr) - } - if hErr != nil { - t.Fatal(hErr) - } - t.Logf("%v\n", want) - } - } - if have, want := tt.ExitStatus(), tc.expExitCode; have != want { - t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want) - } - } -} - type t9nInput struct { inTxs string stFork string @@ -672,6 +580,88 @@ func TestB11r(t *testing.T) { } } +func TestEvmRun(t *testing.T) { + t.Parallel() + tt := cmdtest.NewTestCmd(t, nil) + for i, tc := range []struct { + input []string + wantStdout string + wantStderr string + }{ + { // json tracing + input: []string{"run", "--trace", "--trace.format=json", "6040"}, + wantStdout: "./testdata/evmrun/1.out.1.txt", + wantStderr: "./testdata/evmrun/1.out.2.txt", + }, + { // Same as above, using the deprecated --json + input: []string{"run", "--json", "6040"}, + wantStdout: "./testdata/evmrun/1.out.1.txt", + wantStderr: "./testdata/evmrun/1.out.2.txt", + }, + { // default tracing (struct) + input: []string{"run", "--trace", "0x6040"}, + wantStdout: "./testdata/evmrun/2.out.1.txt", + wantStderr: "./testdata/evmrun/2.out.2.txt", + }, + { // default tracing (struct), plus alloc-dump + input: []string{"run", "--trace", "--dump", "0x6040"}, + wantStdout: "./testdata/evmrun/3.out.1.txt", + //wantStderr: "./testdata/evmrun/3.out.2.txt", + }, + { // json-tracing, plus alloc-dump + input: []string{"run", "--trace", "--trace.format=json", "--dump", "0x6040"}, + wantStdout: "./testdata/evmrun/4.out.1.txt", + //wantStderr: "./testdata/evmrun/4.out.2.txt", + }, + { // md-tracing + input: []string{"run", "--trace", "--trace.format=md", "0x6040"}, + wantStdout: "./testdata/evmrun/5.out.1.txt", + wantStderr: "./testdata/evmrun/5.out.2.txt", + }, + { // statetest subcommand + input: []string{"statetest", "./testdata/statetest.json"}, + wantStdout: "./testdata/evmrun/6.out.1.txt", + wantStderr: "./testdata/evmrun/6.out.2.txt", + }, + { // statetest subcommand with output + input: []string{"statetest", "--trace", "--trace.format=md", "./testdata/statetest.json"}, + wantStdout: "./testdata/evmrun/7.out.1.txt", + wantStderr: "./testdata/evmrun/7.out.2.txt", + }, + { // statetest subcommand with output + input: []string{"statetest", "--trace", "--trace.format=json", "./testdata/statetest.json"}, + wantStdout: "./testdata/evmrun/8.out.1.txt", + wantStderr: "./testdata/evmrun/8.out.2.txt", + }, + } { + tt.Logf("args: go run ./cmd/evm %v\n", strings.Join(tc.input, " ")) + tt.Run("evm-test", tc.input...) + + haveStdOut := tt.Output() + tt.WaitExit() + haveStdErr := tt.StderrText() + + if have, wantFile := haveStdOut, tc.wantStdout; wantFile != "" { + want, err := os.ReadFile(wantFile) + if err != nil { + t.Fatalf("test %d: could not read expected output: %v", i, err) + } + if string(haveStdOut) != string(want) { + t.Fatalf("test %d, output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want)) + } + } + if have, wantFile := haveStdErr, tc.wantStderr; wantFile != "" { + want, err := os.ReadFile(wantFile) + if err != nil { + t.Fatalf("test %d: could not read expected output: %v", i, err) + } + if have != string(want) { + t.Fatalf("test %d, output wrong\nhave %q\nwant %q\n", i, have, string(want)) + } + } + } +} + // cmpJson compares the JSON in two byte slices. func cmpJson(a, b []byte) (bool, error) { var j, j2 interface{} @@ -683,3 +673,93 @@ func cmpJson(a, b []byte) (bool, error) { } return reflect.DeepEqual(j2, j), nil } + +// TestEVMTracing is a test that checks the tracing-output from evm. +func TestEVMTracing(t *testing.T) { + t.Parallel() + tt := cmdtest.NewTestCmd(t, nil) + for i, tc := range []struct { + base string + input []string + expectedTraces []string + }{ + { + base: "./testdata/31", + input: []string{"t8n", + "--input.alloc=./testdata/31/alloc.json", "--input.txs=./testdata/31/txs.json", + "--input.env=./testdata/31/env.json", "--state.fork=Cancun", + "--trace", + }, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"}, + }, + { + base: "./testdata/31", + input: []string{"t8n", + "--input.alloc=./testdata/31/alloc.json", "--input.txs=./testdata/31/txs.json", + "--input.env=./testdata/31/env.json", "--state.fork=Cancun", + "--trace.tracer", ` +{ + result: function(){ + return "hello world" + }, + fault: function(){} +}`, + }, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, + }, + { + base: "./testdata/32", + input: []string{"t8n", + "--input.alloc=./testdata/32/alloc.json", "--input.txs=./testdata/32/txs.json", + "--input.env=./testdata/32/env.json", "--state.fork=Paris", + "--trace", "--trace.callframes", + }, + expectedTraces: []string{"trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl"}, + }, + // TODO, make it possible to run tracers on statetests, e.g: + //{ + // base: "./testdata/31", + // input: []string{"statetest", "--trace", "--trace.tracer", `{ + // result: function(){ + // return "hello world" + // }, + // fault: function(){} + //}`, "./testdata/statetest.json"}, + // expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, + // }, + } { + // Place the output somewhere we can find it + outdir := t.TempDir() + args := append(tc.input, "--output.basedir", outdir) + + tt.Run("evm-test", args...) + tt.Logf("args: go run ./cmd/evm %v\n", args) + tt.WaitExit() + //t.Log(string(tt.Output())) + + // Compare the expected traces + for _, traceFile := range tc.expectedTraces { + haveFn := lineIterator(filepath.Join(outdir, traceFile)) + wantFn := lineIterator(filepath.Join(tc.base, traceFile)) + + for line := 0; ; line++ { + want, wErr := wantFn() + have, hErr := haveFn() + if want != have { + t.Fatalf("test %d, trace %v, line %d\nwant: %v\nhave: %v\n", + i, traceFile, line, want, have) + } + if wErr != nil && hErr != nil { + break + } + if wErr != nil { + t.Fatal(wErr) + } + if hErr != nil { + t.Fatal(hErr) + } + //t.Logf("%v\n", want) + } + } + } +} diff --git a/cmd/evm/testdata/evmrun/1.out.1.txt b/cmd/evm/testdata/evmrun/1.out.1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/evm/testdata/evmrun/1.out.2.txt b/cmd/evm/testdata/evmrun/1.out.2.txt new file mode 100644 index 000000000..97d6c36c6 --- /dev/null +++ b/cmd/evm/testdata/evmrun/1.out.2.txt @@ -0,0 +1,3 @@ +{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":0,"gas":"0x2540be3fd","gasCost":"0x0","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x3"} diff --git a/cmd/evm/testdata/evmrun/2.out.1.txt b/cmd/evm/testdata/evmrun/2.out.1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/evm/testdata/evmrun/2.out.2.txt b/cmd/evm/testdata/evmrun/2.out.2.txt new file mode 100644 index 000000000..4f31d87cc --- /dev/null +++ b/cmd/evm/testdata/evmrun/2.out.2.txt @@ -0,0 +1,6 @@ +PUSH1 pc=00000000 gas=10000000000 cost=3 + +STOP pc=00000002 gas=9999999997 cost=0 +Stack: +00000000 0x40 + diff --git a/cmd/evm/testdata/evmrun/3.out.1.txt b/cmd/evm/testdata/evmrun/3.out.1.txt new file mode 100644 index 000000000..44956f54f --- /dev/null +++ b/cmd/evm/testdata/evmrun/3.out.1.txt @@ -0,0 +1,13 @@ +{ + "root": "b444481d1367188172f8c6091e948aaa68bae763fd26d6b9e994306a66bf69f9", + "accounts": { + "pre(0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142)": { + "balance": "0", + "nonce": 0, + "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "codeHash": "0x3e48ef54b89079a075f3b8fc253c657a86b110a7aed3568c1517b10edf2c3eb6", + "code": "0x6040", + "key": "0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142" + } + } +} diff --git a/cmd/evm/testdata/evmrun/3.out.2.txt b/cmd/evm/testdata/evmrun/3.out.2.txt new file mode 100644 index 000000000..58e8cbfde --- /dev/null +++ b/cmd/evm/testdata/evmrun/3.out.2.txt @@ -0,0 +1,9 @@ +PUSH1 pc=00000000 gas=10000000000 cost=3 + +STOP pc=00000002 gas=9999999997 cost=0 +Stack: +00000000 0x40 + +INFO [12-03|10:37:15.827] Trie dumping started root=b44448..bf69f9 +WARN [12-03|10:37:15.827] Dump incomplete due to missing preimages missing=1 +INFO [12-03|10:37:15.827] Trie dumping complete accounts=1 elapsed="163.513µs" diff --git a/cmd/evm/testdata/evmrun/4.out.1.txt b/cmd/evm/testdata/evmrun/4.out.1.txt new file mode 100644 index 000000000..44956f54f --- /dev/null +++ b/cmd/evm/testdata/evmrun/4.out.1.txt @@ -0,0 +1,13 @@ +{ + "root": "b444481d1367188172f8c6091e948aaa68bae763fd26d6b9e994306a66bf69f9", + "accounts": { + "pre(0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142)": { + "balance": "0", + "nonce": 0, + "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "codeHash": "0x3e48ef54b89079a075f3b8fc253c657a86b110a7aed3568c1517b10edf2c3eb6", + "code": "0x6040", + "key": "0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142" + } + } +} diff --git a/cmd/evm/testdata/evmrun/4.out.2.txt b/cmd/evm/testdata/evmrun/4.out.2.txt new file mode 100644 index 000000000..20441964e --- /dev/null +++ b/cmd/evm/testdata/evmrun/4.out.2.txt @@ -0,0 +1,6 @@ +{"pc":0,"op":96,"gas":"0x2540be400","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":0,"gas":"0x2540be3fd","gasCost":"0x0","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x3"} +INFO [12-03|10:38:33.360] Trie dumping started root=b44448..bf69f9 +WARN [12-03|10:38:33.361] Dump incomplete due to missing preimages missing=1 +INFO [12-03|10:38:33.361] Trie dumping complete accounts=1 elapsed="240.811µs" diff --git a/cmd/evm/testdata/evmrun/5.out.1.txt b/cmd/evm/testdata/evmrun/5.out.1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/evm/testdata/evmrun/5.out.2.txt b/cmd/evm/testdata/evmrun/5.out.2.txt new file mode 100644 index 000000000..356f731f0 --- /dev/null +++ b/cmd/evm/testdata/evmrun/5.out.2.txt @@ -0,0 +1,16 @@ +Pre-execution info: + - from: `0x000000000000000000000000000073656E646572` + - to: `0x0000000000000000000000007265636569766572` + - data: `` + - gas: `10000000000` + - value: `0` wei + +| Pc | Op | Cost | Refund | Stack | +|-------|-------------|------|-----------|-----------| +| 0 | PUSH1 | 3 | 0 | [] | +| 2 | STOP | 0 | 0 | [0x40] | + +Post-execution info: + - output: `` + - consumed gas: `3` + - error: `` diff --git a/cmd/evm/testdata/evmrun/6.out.1.txt b/cmd/evm/testdata/evmrun/6.out.1.txt new file mode 100644 index 000000000..dc22c2ef3 --- /dev/null +++ b/cmd/evm/testdata/evmrun/6.out.1.txt @@ -0,0 +1,9 @@ +[ + { + "name": "00000006-naivefuzz-0", + "pass": false, + "stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458", + "fork": "London", + "error": "post state root mismatch: got ad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458, want 0000000000000000000000000000000000000000000000000000000000000000" + } +] diff --git a/cmd/evm/testdata/evmrun/6.out.2.txt b/cmd/evm/testdata/evmrun/6.out.2.txt new file mode 100644 index 000000000..2d841c4e3 --- /dev/null +++ b/cmd/evm/testdata/evmrun/6.out.2.txt @@ -0,0 +1 @@ +{"stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458"} diff --git a/cmd/evm/testdata/evmrun/7.out.1.txt b/cmd/evm/testdata/evmrun/7.out.1.txt new file mode 100644 index 000000000..dc22c2ef3 --- /dev/null +++ b/cmd/evm/testdata/evmrun/7.out.1.txt @@ -0,0 +1,9 @@ +[ + { + "name": "00000006-naivefuzz-0", + "pass": false, + "stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458", + "fork": "London", + "error": "post state root mismatch: got ad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458, want 0000000000000000000000000000000000000000000000000000000000000000" + } +] diff --git a/cmd/evm/testdata/evmrun/7.out.2.txt b/cmd/evm/testdata/evmrun/7.out.2.txt new file mode 100644 index 000000000..d81d96c6f --- /dev/null +++ b/cmd/evm/testdata/evmrun/7.out.2.txt @@ -0,0 +1,925 @@ +Pre-execution info: + - from: `0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B` + - to: `0x00000000000000000000000000000000000000f1` + - data: `0x81fbe24d1e33d7944b2e62ee0ff24811bbbcf8cb311e5617c80623dec4477cc14849fc042b9bbaebca9f03f66cca76c46353c5a68c2e134ef75f8c2425d9702f3a4bd3c5527e93d27579bdbd7d237eaa1c0278fce26479aaf11fb8d00e7478` + - gas: `737811` + - value: `1` wei + +| Pc | Op | Cost | Refund | Stack | +|-------|-------------|------|-----------|-----------| +| 0 | PUSH1 | 3 | 0 | [] | +| 2 | PUSH1 | 3 | 0 | [0x2] | +| 4 | SSTORE | 22100 | 0 | [0x2,0x3] | +| 5 | PUSH1 | 3 | 0 | [] | +| 7 | PUSH1 | 3 | 0 | [0x0] | +| 9 | PUSH1 | 3 | 0 | [0x0,0x0] | +| 11 | PUSH1 | 3 | 0 |[0x0,0x0,0x0] | +| 13 | PUSH1 | 3 | 0 |[0x0,0x0,0x0,0x0] | +| 15 | PUSH1 | 3 | 0 |[0x0,0x0,0x0,0x0,0x0] | +| 17 | GAS | 2 | 0 |[0x0,0x0,0x0,0x0,0x0,0x4] | +| 18 | CALLCODE | 704504 | 0 |[0x0,0x0,0x0,0x0,0x0,0x4,0xaeba5] | +| 19 | POP | 2 | 0 | [0x1] | +| 20 | PUSH32 | 3 | 0 | [] | +| 53 | PUSH1 | 3 | 0 |[0x600254506003545060016003557f7f6008545060006004557f60016004556000] | +| 55 | MSTORE | 6 | 0 |[0x600254506003545060016003557f7f6008545060006004557f60016004556000,0x0] | +| 56 | PUSH32 | 3 | 0 | [] | +| 89 | PUSH1 | 3 | 0 |[0x60045560006000600060006000606000527ff96000527f5af250600060006000] | +| 91 | MSTORE | 6 | 0 |[0x60045560006000600060006000606000527ff96000527f5af250600060006000,0x20] | +| 92 | PUSH32 | 3 | 0 | [] | +| 125 | PUSH1 | 3 | 0 |[0x606000527e60f45af45060006000600060006020527f600060f55a6020527ff1] | +| 127 | MSTORE | 6 | 0 |[0x606000527e60f45af45060006000600060006020527f600060f55a6020527ff1,0x40] | +| 128 | PUSH32 | 3 | 0 | [] | +| 161 | PUSH1 | 3 | 0 |[0x50f001075205846a44a283446020527f8ca2600060006040527f600060006004] | +| 163 | MSTORE | 6 | 0 |[0x50f001075205846a44a283446020527f8ca2600060006040527f600060006004,0x60] | +| 164 | PUSH32 | 3 | 0 | [] | +| 197 | PUSH1 | 3 | 0 |[0x5af4506040527f519930847f3b631c54a49b5f600354503260406060527f527f] | +| 199 | MSTORE | 6 | 0 |[0x5af4506040527f519930847f3b631c54a49b5f600354503260406060527f527f,0x80] | +| 200 | PUSH32 | 3 | 0 | [] | +| 233 | PUSH1 | 3 | 0 |[0x77306b60006000600060006060527f6000600c5af15060006000600060006080] | +| 235 | MSTORE | 6 | 0 |[0x77306b60006000600060006060527f6000600c5af15060006000600060006080,0xa0] | +| 236 | PUSH32 | 3 | 0 | [] | +| 269 | PUSH1 | 3 | 0 |[0x527f60f85af450506060527f066001600255606080527f035450600060005560] | +| 271 | MSTORE | 6 | 0 |[0x527f60f85af450506060527f066001600255606080527f035450600060005560,0xc0] | +| 272 | PUSH31 | 3 | 0 | [] | +| 304 | PUSH1 | 3 | 0 |[0x6060a0527f01556c3394fff4607f7f1684317b6080527f387b9f60a0527f19] | +| 306 | MSTORE | 6 | 0 |[0x6060a0527f01556c3394fff4607f7f1684317b6080527f387b9f60a0527f19,0xe0] | +| 307 | PUSH32 | 3 | 0 | [] | +| 340 | PUSH2 | 3 | 0 |[0x20700184809d60c0527f60015450011899016e6009ff60026001556000527f9f] | +| 343 | MSTORE | 6 | 0 |[0x20700184809d60c0527f60015450011899016e6009ff60026001556000527f9f,0x100] | +| 344 | PUSH32 | 3 | 0 | [] | +| 377 | PUSH2 | 3 | 0 |[0x60a05260c0527f7f600060e0527f527f9981600160045582600eff6000600060] | +| 380 | MSTORE | 6 | 0 |[0x60a05260c0527f7f600060e0527f527f9981600160045582600eff6000600060,0x120] | +| 381 | PUSH31 | 3 | 0 | [] | +| 413 | PUSH2 | 3 | 0 |[0x600060f65af45060006060e052610100527f7f6060c0527f20527e60006000] | +| 416 | MSTORE | 6 | 0 |[0x600060f65af45060006060e052610100527f7f6060c0527f20527e60006000,0x140] | +| 417 | PUSH32 | 3 | 0 | [] | +| 450 | PUSH2 | 3 | 0 |[0x6020527f60f75af4501d7f1903166660006000610120527f60610100527e6000] | +| 453 | MSTORE | 6 | 0 |[0x6020527f60f75af4501d7f1903166660006000610120527f60610100527e6000,0x160] | +| 454 | PUSH32 | 3 | 0 | [] | +| 487 | PUSH2 | 3 | 0 |[0x600060e0527f60046040527f5af150600060006000604052610140527f7f6000] | +| 490 | MSTORE | 6 | 0 |[0x600060e0527f60046040527f5af150600060006000604052610140527f7f6000,0x180] | +| 491 | PUSH32 | 3 | 0 | [] | +| 524 | PUSH2 | 3 | 0 |[0x6009610120527f5af4503c95138e5b8f610100527f7f605a6000536060610160] | +| 527 | MSTORE | 6 | 0 |[0x6009610120527f5af4503c95138e5b8f610100527f7f605a6000536060610160,0x1a0] | +| 528 | PUSH32 | 3 | 0 | [] | +| 561 | PUSH2 | 3 | 0 |[0x527f527f6031600153606b60610140527f02536010606060527f035360456061] | +| 564 | MSTORE | 6 | 0 |[0x527f527f6031600153606b60610140527f02536010606060527f035360456061,0x1c0] | +| 565 | PUSH32 | 3 | 0 | [] | +| 598 | PUSH2 | 3 | 0 |[0x120610180527f527f04536060600553600160608052610160527f7e527f6006] | +| 601 | MSTORE | 6 | 0 |[0x120610180527f527f04536060600553600160608052610160527f7e527f6006,0x1e0] | +| 602 | PUSH32 | 3 | 0 | [] | +| 635 | PUSH2 | 3 | 0 |[0x536060600753606101a0527f02600853606080610140527f527f556009536060] | +| 638 | MSTORE | 6 | 0 |[0x536060600753606101a0527f02600853606080610140527f527f556009536060,0x200] | +| 639 | PUSH32 | 3 | 0 | [] | +| 672 | PUSH2 | 3 | 0 |[0x610180527f600a53600160a06101c0527f527f600b536060600c6020527f5360] | +| 675 | MSTORE | 6 | 0 |[0x610180527f600a53600160a06101c0527f527f600b536060600c6020527f5360,0x220] | +| 676 | PUSH31 | 3 | 0 | [] | +| 708 | PUSH2 | 3 | 0 |[0x60610160527f0d53606101a0527f55606101e0527f0e60a0527f536060600f] | +| 711 | MSTORE | 6 | 0 |[0x60610160527f0d53606101a0527f55606101e0527f0e60a0527f536060600f,0x240] | +| 712 | PUSH32 | 3 | 0 | [] | +| 745 | PUSH2 | 3 | 0 |[0x536060c0527f01601053606060115360026101806101610200527fc0527f527f] | +| 748 | MSTORE | 6 | 0 |[0x536060c0527f01601053606060115360026101806101610200527fc0527f527f,0x260] | +| 749 | PUSH32 | 3 | 0 | [] | +| 782 | PUSH2 | 3 | 0 |[0x601253606040527f55601353606060c0527f60145360e0527f6000610220527f] | +| 785 | MSTORE | 6 | 0 |[0x601253606040527f55601353606060c0527f60145360e0527f6000610220527f,0x280] | +| 786 | PUSH32 | 3 | 0 | [] | +| 819 | PUSH2 | 3 | 0 |[0x6015536101e0527f60606101a0527f601653600060175360f360185360196060] | +| 822 | MSTORE | 6 | 0 |[0x6015536101e0527f60606101a0527f601653600060175360f360185360196060,0x2a0] | +| 823 | PUSH32 | 3 | 0 | [] | +| 856 | PUSH2 | 3 | 0 |[0x610240527f605260006060e052610200527f610100527f7f806101c0527f5360] | +| 859 | MSTORE | 7 | 0 |[0x610240527f605260006060e052610200527f610100527f7f806101c0527f5360,0x2c0] | +| 860 | PUSH32 | 3 | 0 | [] | +| 893 | PUSH2 | 3 | 0 |[0xf360815360610260527f8260006000f060006000600060610220527e845af450] | +| 896 | MSTORE | 6 | 0 |[0xf360815360610260527f8260006000f060006000600060610220527e845af450,0x2e0] | +| 897 | PUSH32 | 3 | 0 | [] | +| 930 | PUSH2 | 3 | 0 |[0x506000600061016101e0610280527f527f20527f60610100527e600060006003] | +| 933 | MSTORE | 6 | 0 |[0x506000600061016101e0610280527f527f20527f60610100527e600060006003,0x300] | +| 934 | PUSH32 | 3 | 0 | [] | +| 967 | PUSH2 | 3 | 0 |[0x610240527f5af15060005450c760006102a0527f6002551309f562610200527f] | +| 970 | MSTORE | 6 | 0 |[0x610240527f5af15060005450c760006102a0527f6002551309f562610200527f,0x320] | +| 971 | PUSH32 | 3 | 0 | [] | +| 1004 | PUSH2 | 3 | 0 |[0x66a486610140527f6b00610260527f1d457161016102c0527f20527f60005450] | +| 1007 | MSTORE | 6 | 0 |[0x66a486610140527f6b00610260527f1d457161016102c0527f20527f60005450,0x340] | +| 1008 | PUSH32 | 3 | 0 | [] | +| 1041 | PUSH2 | 3 | 0 |[0x1c641d373c7f60045450610220527f6000600155610280527f6102e0527f6005] | +| 1044 | MSTORE | 6 | 0 |[0x1c641d373c7f60045450610220527f6000600155610280527f6102e0527f6005,0x360] | +| 1045 | PUSH32 | 3 | 0 | [] | +| 1078 | PUSH2 | 3 | 0 |[0x54610160527f50600160025560085450610140527f60006002610240527f6103] | +| 1081 | MSTORE | 6 | 0 |[0x54610160527f50600160025560085450610140527f60006002610240527f6103,0x380] | +| 1082 | PUSH31 | 3 | 0 | [] | +| 1114 | PUSH2 | 3 | 0 |[0x527f6102a0527f557fd86000606000527e600060610180527e600060005af1] | +| 1117 | MSTORE | 6 | 0 |[0x527f6102a0527f557fd86000606000527e600060610180527e600060005af1,0x3a0] | +| 1118 | PUSH32 | 3 | 0 | [] | +| 1151 | PUSH2 | 3 | 0 |[0x508612610320527f17145147356102c0527f610260527f610160527f5198a37e] | +| 1154 | MSTORE | 6 | 0 |[0x508612610320527f17145147356102c0527f610260527f610160527f5198a37e,0x3c0] | +| 1155 | PUSH32 | 3 | 0 | [] | +| 1188 | PUSH2 | 3 | 0 |[0x127a7efa7c600052610340527f6101a0527f606020527f6102e0527f60602053] | +| 1191 | MSTORE | 7 | 0 |[0x127a7efa7c600052610340527f6101a0527f606020527f6102e0527f60602053,0x3e0] | +| 1192 | PUSH32 | 3 | 0 | [] | +| 1225 | PUSH2 | 3 | 0 |[0x60610280527ff760215360ff60610360527f225360610180527fdb6023536037] | +| 1228 | MSTORE | 6 | 0 |[0x60610280527ff760215360ff60610360527f225360610180527fdb6023536037,0x400] | +| 1229 | PUSH32 | 3 | 0 | [] | +| 1262 | PUSH2 | 3 | 0 |[0x60610300527f6101c0527f24536075606102610380527fa0527f2553609f6060] | +| 1265 | MSTORE | 6 | 0 |[0x60610300527f6101c0527f24536075606102610380527fa0527f2553609f6060,0x420] | +| 1266 | PUSH32 | 3 | 0 | [] | +| 1299 | PUSH2 | 3 | 0 |[0x40527f265360fe60275360610320527f8f60286101a0526103a0527f7f536061] | +| 1302 | MSTORE | 6 | 0 |[0x40527f265360fe60275360610320527f8f60286101a0526103a0527f7f536061,0x440] | +| 1303 | PUSH32 | 3 | 0 | [] | +| 1336 | PUSH2 | 3 | 0 |[0x1e0527f6102c0527f0b6029536060602a53600060610340527f2b536103c052] | +| 1339 | MSTORE | 6 | 0 |[0x1e0527f6102c0527f0b6029536060602a53600060610340527f2b536103c052,0x460] | +| 1340 | PUSH32 | 3 | 0 | [] | +| 1373 | PUSH2 | 3 | 0 |[0x7f6060602c53606052606060805360006061016102e0527f610200527fc05261] | +| 1376 | MSTORE | 6 | 0 |[0x7f6060602c53606052606060805360006061016102e0527f610200527fc05261,0x480] | +| 1377 | PUSH32 | 3 | 0 | [] | +| 1410 | PUSH2 | 3 | 0 |[0x36103e0527f60527f7f81536060608253602d60835360536084536060608553] | +| 1413 | MSTORE | 6 | 0 |[0x36103e0527f60527f7f81536060608253602d60835360536084536060608553,0x4a0] | +| 1414 | PUSH32 | 3 | 0 | [] | +| 1447 | PUSH2 | 3 | 0 |[0x60fd61030052610400527f7f6086610380527f536060610220527f6087536101] | +| 1450 | MSTORE | 6 | 0 |[0x60fd61030052610400527f7f6086610380527f536060610220527f6087536101,0x4c0] | +| 1451 | PUSH32 | 3 | 0 | [] | +| 1484 | PUSH2 | 3 | 0 |[0xe0527f602e608853605360610420527f89536060608a61036103a0527f20527f] | +| 1487 | MSTORE | 7 | 0 |[0xe0527f602e608853605360610420527f89536060608a61036103a0527f20527f,0x4e0] | +| 1488 | PUSH32 | 3 | 0 | [] | +| 1521 | PUSH2 | 3 | 0 |[0x53602f608b536060608c610240527f53610440527f6000608d5360f361020052] | +| 1524 | MSTORE | 6 | 0 |[0x53602f608b536060608c610240527f53610440527f6000608d5360f361020052,0x500] | +| 1525 | PUSH32 | 3 | 0 | [] | +| 1558 | PUSH2 | 3 | 0 |[0x60606103c0527f610220610340527f53608e610221610460527f536053610222] | +| 1561 | MSTORE | 6 | 0 |[0x60606103c0527f610220610340527f53608e610221610460527f536053610222,0x520] | +| 1562 | PUSH32 | 3 | 0 | [] | +| 1595 | PUSH2 | 3 | 0 |[0x536060610260527f610223536103e0527f600061022453606061610480527f03] | +| 1598 | MSTORE | 6 | 0 |[0x536060610260527f610223536103e0527f600061022453606061610480527f03,0x540] | +| 1599 | PUSH32 | 3 | 0 | [] | +| 1632 | PUSH2 | 3 | 0 |[0x60527f61022553608f61022653606061022753600061610400527f0261028061] | +| 1635 | MSTORE | 6 | 0 |[0x60527f61022553608f61022653606061022753600061610400527f0261028061,0x560] | +| 1636 | PUSH32 | 3 | 0 | [] | +| 1669 | PUSH2 | 3 | 0 |[0x4a0527f527f28536060610229610380527f53600061022a5360f561022b5360] | +| 1672 | MSTORE | 6 | 0 |[0x4a0527f527f28536060610229610380527f53600061022a5360f561022b5360,0x580] | +| 1673 | PUSH32 | 3 | 0 | [] | +| 1706 | PUSH2 | 3 | 0 |[0x610420526104c0527f7f6061022c53600061022d536102a0527f60606103a052] | +| 1709 | MSTORE | 7 | 0 |[0x610420526104c0527f7f6061022c53600061022d536102a0527f60606103a052,0x5a0] | +| 1710 | PUSH32 | 3 | 0 | [] | +| 1743 | PUSH2 | 3 | 0 |[0x7f61022e53600061026104e0527f2f610440527f536060610230536000610231] | +| 1746 | MSTORE | 6 | 0 |[0x7f61022e53600061026104e0527f2f610440527f536060610230536000610231,0x5c0] | +| 1747 | PUSH32 | 3 | 0 | [] | +| 1780 | PUSH2 | 3 | 0 |[0x53606061023253600061026103c0610500527f527fc0527f61610460527f0233] | +| 1783 | MSTORE | 6 | 0 |[0x53606061023253600061026103c0610500527f527fc0527f61610460527f0233,0x5e0] | +| 1784 | PUSH32 | 3 | 0 | [] | +| 1817 | PUSH2 | 3 | 0 |[0x53606061023453600061023553608561023653610520527f605a610237536061] | +| 1820 | MSTORE | 6 | 0 |[0x53606061023453600061023553608561023653610520527f605a610237536061,0x600] | +| 1821 | PUSH32 | 3 | 0 | [] | +| 1854 | PUSH2 | 3 | 0 |[0x3e052610480527f7ff261026102e0526038610300536053610540527f610301] | +| 1857 | MSTORE | 6 | 0 |[0x3e052610480527f7ff261026102e0526038610300536053610540527f610301,0x620] | +| 1858 | PUSH32 | 3 | 0 | [] | +| 1891 | PUSH2 | 3 | 0 |[0x536060610302536050610303536104a0527f60610400527f6161030453610560] | +| 1894 | MSTORE | 7 | 0 |[0x536060610302536050610303536104a0527f60610400527f6161030453610560,0x640] | +| 1895 | PUSH32 | 3 | 0 | [] | +| 1928 | PUSH2 | 3 | 0 |[0x527f6002610305536039610306536053610307536060616104c0527f03085360] | +| 1931 | MSTORE | 6 | 0 |[0x527f6002610305536039610306536053610307536060616104c0527f03085360,0x660] | +| 1932 | PUSH32 | 3 | 0 | [] | +| 1965 | PUSH2 | 3 | 0 |[0x5061610580527f610420527f030953606161030a53600261030b53603a61030c] | +| 1968 | MSTORE | 6 | 0 |[0x5061610580527f610420527f030953606161030a53600261030b53603a61030c,0x680] | +| 1969 | PUSH32 | 3 | 0 | [] | +| 2002 | PUSH2 | 3 | 0 |[0x536104e0527f606105a0527f5361030d53606161030e610440527f5360026103] | +| 2005 | MSTORE | 6 | 0 |[0x536104e0527f606105a0527f5361030d53606161030e610440527f5360026103,0x6a0] | +| 2006 | PUSH32 | 3 | 0 | [] | +| 2039 | PUSH2 | 3 | 0 |[0xf53603b61031053606061616105c0527f0500527f03115360006103125360f3] | +| 2042 | MSTORE | 6 | 0 |[0xf53603b61031053606061616105c0527f0500527f03115360006103125360f3,0x6c0] | +| 2043 | PUSH32 | 3 | 0 | [] | +| 2076 | PUSH2 | 3 | 0 |[0x61031353616104605260036104805360146105e0527f61048153610520527f60] | +| 2079 | MSTORE | 7 | 0 |[0x61031353616104605260036104805360146105e0527f61048153610520527f60,0x6e0] | +| 2080 | PUSH32 | 3 | 0 | [] | +| 2113 | PUSH2 | 3 | 0 |[0x60610482536000610483536060610484536000610485610600527f5360f06104] | +| 2116 | MSTORE | 6 | 0 |[0x60610482536000610483536060610484536000610485610600527f5360f06104,0x700] | +| 2117 | PUSH32 | 3 | 0 | [] | +| 2150 | PUSH2 | 3 | 0 |[0x86536060610540527f610487536000610488536060610489536000610620527f] | +| 2153 | MSTORE | 6 | 0 |[0x86536060610540527f610487536000610488536060610489536000610620527f,0x720] | +| 2154 | PUSH32 | 3 | 0 | [] | +| 2187 | PUSH2 | 3 | 0 |[0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e] | +| 2190 | MSTORE | 6 | 0 |[0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e,0x740] | +| 2191 | PUSH32 | 3 | 0 | [] | +| 2224 | PUSH2 | 3 | 0 |[0x610640527f53608461048f53605a6104905360f4610491536105805260606105] | +| 2227 | MSTORE | 7 | 0 |[0x610640527f53608461048f53605a6104905360f4610491536105805260606105,0x760] | +| 2228 | PUSH32 | 3 | 0 | [] | +| 2261 | PUSH2 | 3 | 0 |[0xa053605061610660527f05a15360616105a25360046105a35360926105a45360] | +| 2264 | MSTORE | 6 | 0 |[0xa053605061610660527f05a15360616105a25360046105a35360926105a45360,0x780] | +| 2265 | PUSH32 | 3 | 0 | [] | +| 2298 | PUSH2 | 3 | 0 |[0x536105a55360606105a6610680527f5360506105a75360616105a85360046105] | +| 2301 | MSTORE | 6 | 0 |[0x536105a55360606105a6610680527f5360506105a75360616105a85360046105,0x7a0] | +| 2302 | PUSH32 | 3 | 0 | [] | +| 2335 | PUSH2 | 3 | 0 |[0xa95360936105aa5360536105ab53606106a0527f616105ac5360046105ad5360] | +| 2338 | MSTORE | 6 | 0 |[0xa95360936105aa5360536105ab53606106a0527f616105ac5360046105ad5360,0x7c0] | +| 2339 | PUSH32 | 3 | 0 | [] | +| 2372 | PUSH2 | 3 | 0 |[0x946105ae5360606105af5360006105b05360f3616106c05260056106e05360b1] | +| 2375 | MSTORE | 7 | 0 |[0x946105ae5360606105af5360006105b05360f3616106c05260056106e05360b1,0x7e0] | +| 2376 | PUSH32 | 3 | 0 | [] | +| 2409 | PUSH2 | 3 | 0 |[0x6106e15360536106e25360606106e35360006106e45360616106e55360056106] | +| 2412 | MSTORE | 6 | 0 |[0x6106e15360536106e25360606106e35360006106e45360616106e55360056106,0x800] | +| 2413 | PUSH32 | 3 | 0 | [] | +| 2446 | PUSH2 | 3 | 0 |[0xe65360b26106e75360606106e85360006106e95360606106ea5360006106eb53] | +| 2449 | MSTORE | 6 | 0 |[0xe65360b26106e75360606106e85360006106e95360606106ea5360006106eb53,0x820] | +| 2450 | PUSH32 | 3 | 0 | [] | +| 2483 | PUSH2 | 3 | 0 |[0x60f56106ec5360606106ed5360006106ee5360606106ef5360006106f0536060] | +| 2486 | MSTORE | 6 | 0 |[0x60f56106ec5360606106ed5360006106ee5360606106ef5360006106f0536060,0x840] | +| 2487 | PUSH32 | 3 | 0 | [] | +| 2520 | PUSH2 | 3 | 0 |[0x6106f15360006106f25360606106f35360006106f45360606106f55360006106] | +| 2523 | MSTORE | 7 | 0 |[0x6106f15360006106f25360606106f35360006106f45360606106f55360006106,0x860] | +| 2524 | PUSH32 | 3 | 0 | [] | +| 2557 | PUSH2 | 3 | 0 |[0xf65360856106f753605a6106f85360f16106f95360506106fa5360506106fb53] | +| 2560 | MSTORE | 6 | 0 |[0xf65360856106f753605a6106f85360f16106f95360506106fa5360506106fb53,0x880] | +| 2561 | PUSH1 | 3 | 0 | [] | +| 2563 | PUSH2 | 3 | 0 | [0x61] | +| 2566 | MSTORE8 | 6 | 0 |[0x61,0x8a0] | +| 2567 | PUSH1 | 3 | 0 | [] | +| 2569 | PUSH2 | 3 | 0 | [0x6] | +| 2572 | MSTORE8 | 3 | 0 |[0x6,0x8a1] | +| 2573 | PUSH1 | 3 | 0 | [] | +| 2575 | PUSH2 | 3 | 0 | [0xfc] | +| 2578 | MSTORE8 | 3 | 0 |[0xfc,0x8a2] | +| 2579 | PUSH1 | 3 | 0 | [] | +| 2581 | PUSH2 | 3 | 0 | [0x60] | +| 2584 | MSTORE8 | 3 | 0 |[0x60,0x8a3] | +| 2585 | PUSH1 | 3 | 0 | [] | +| 2587 | PUSH2 | 3 | 0 | [0x0] | +| 2590 | MSTORE8 | 3 | 0 |[0x0,0x8a4] | +| 2591 | PUSH1 | 3 | 0 | [] | +| 2593 | PUSH2 | 3 | 0 | [0xf3] | +| 2596 | MSTORE8 | 3 | 0 |[0xf3,0x8a5] | +| 2597 | PUSH2 | 3 | 0 | [] | +| 2600 | PUSH1 | 3 | 0 | [0x8a6] | +| 2602 | PUSH1 | 3 | 0 |[0x8a6,0x0] | +| 2604 | CREATE | 32000 | 0 |[0x8a6,0x0,0x0] | +| 0 | PUSH1 | 3 | 0 | [] | +| 2 | SLOAD | 2100 | 0 | [0x2] | +| 3 | POP | 2 | 0 | [0x0] | +| 4 | PUSH1 | 3 | 0 | [] | +| 6 | SLOAD | 2100 | 0 | [0x3] | +| 7 | POP | 2 | 0 | [0x0] | +| 8 | PUSH1 | 3 | 0 | [] | +| 10 | PUSH1 | 3 | 0 | [0x1] | +| 12 | SSTORE | 20000 | 0 | [0x1,0x3] | +| 13 | PUSH32 | 3 | 0 | [] | +| 46 | PUSH1 | 3 | 0 |[0x7f6008545060006004557f600160045560006004556000600060006000600060] | +| 48 | MSTORE | 6 | 0 |[0x7f6008545060006004557f600160045560006004556000600060006000600060,0x0] | +| 49 | PUSH32 | 3 | 0 | [] | +| 82 | PUSH1 | 3 | 0 |[0xf96000527f5af250600060006000606000527e60f45af4506000600060006000] | +| 84 | MSTORE | 6 | 0 |[0xf96000527f5af250600060006000606000527e60f45af4506000600060006000,0x20] | +| 85 | PUSH32 | 3 | 0 | [] | +| 118 | PUSH1 | 3 | 0 |[0x600060f55a6020527ff150f001075205846a44a283446020527f8ca260006000] | +| 120 | MSTORE | 6 | 0 |[0x600060f55a6020527ff150f001075205846a44a283446020527f8ca260006000,0x40] | +| 121 | PUSH32 | 3 | 0 | [] | +| 154 | PUSH1 | 3 | 0 |[0x6000600060045af4506040527f519930847f3b631c54a49b5f60035450326040] | +| 156 | MSTORE | 6 | 0 |[0x6000600060045af4506040527f519930847f3b631c54a49b5f60035450326040,0x60] | +| 157 | PUSH32 | 3 | 0 | [] | +| 190 | PUSH1 | 3 | 0 |[0x527f77306b60006000600060006060527f6000600c5af1506000600060006000] | +| 192 | MSTORE | 6 | 0 |[0x527f77306b60006000600060006060527f6000600c5af1506000600060006000,0x80] | +| 193 | PUSH32 | 3 | 0 | [] | +| 226 | PUSH1 | 3 | 0 |[0x60f85af450506060527f066001600255606080527f0354506000600055600060] | +| 228 | MSTORE | 6 | 0 |[0x60f85af450506060527f066001600255606080527f0354506000600055600060,0xa0] | +| 229 | PUSH32 | 3 | 0 | [] | +| 262 | PUSH1 | 3 | 0 |[0x1556c3394fff4607f7f1684317b6080527f387b9f60a0527f1920700184809d] | +| 264 | MSTORE | 6 | 0 |[0x1556c3394fff4607f7f1684317b6080527f387b9f60a0527f1920700184809d,0xc0] | +| 265 | PUSH32 | 3 | 0 | [] | +| 298 | PUSH1 | 3 | 0 |[0x60015450011899016e6009ff60026001556000527f9f60a05260c0527f7f6000] | +| 300 | MSTORE | 6 | 0 |[0x60015450011899016e6009ff60026001556000527f9f60a05260c0527f7f6000,0xe0] | +| 301 | PUSH32 | 3 | 0 | [] | +| 334 | PUSH2 | 3 | 0 |[0x527f9981600160045582600eff600060006000600060f65af45060006060e052] | +| 337 | MSTORE | 6 | 0 |[0x527f9981600160045582600eff600060006000600060f65af45060006060e052,0x100] | +| 338 | PUSH32 | 3 | 0 | [] | +| 371 | PUSH2 | 3 | 0 |[0x7f6060c0527f20527e600060006020527f60f75af4501d7f1903166660006000] | +| 374 | MSTORE | 6 | 0 |[0x7f6060c0527f20527e600060006020527f60f75af4501d7f1903166660006000,0x120] | +| 375 | PUSH32 | 3 | 0 | [] | +| 408 | PUSH2 | 3 | 0 |[0x60610100527e6000600060e0527f60046040527f5af150600060006000604052] | +| 411 | MSTORE | 6 | 0 |[0x60610100527e6000600060e0527f60046040527f5af150600060006000604052,0x140] | +| 412 | PUSH32 | 3 | 0 | [] | +| 445 | PUSH2 | 3 | 0 |[0x7f60006009610120527f5af4503c95138e5b8f610100527f7f605a6000536060] | +| 448 | MSTORE | 6 | 0 |[0x7f60006009610120527f5af4503c95138e5b8f610100527f7f605a6000536060,0x160] | +| 449 | PUSH32 | 3 | 0 | [] | +| 482 | PUSH2 | 3 | 0 |[0x527f6031600153606b60610140527f02536010606060527f0353604560610120] | +| 485 | MSTORE | 6 | 0 |[0x527f6031600153606b60610140527f02536010606060527f0353604560610120,0x180] | +| 486 | PUSH32 | 3 | 0 | [] | +| 519 | PUSH2 | 3 | 0 |[0x527f04536060600553600160608052610160527f7e527f600653606060075360] | +| 522 | MSTORE | 6 | 0 |[0x527f04536060600553600160608052610160527f7e527f600653606060075360,0x1a0] | +| 523 | PUSH32 | 3 | 0 | [] | +| 556 | PUSH2 | 3 | 0 |[0x2600853606080610140527f527f556009536060610180527f600a53600160a0] | +| 559 | MSTORE | 6 | 0 |[0x2600853606080610140527f527f556009536060610180527f600a53600160a0,0x1c0] | +| 560 | PUSH32 | 3 | 0 | [] | +| 593 | PUSH2 | 3 | 0 |[0x527f600b536060600c6020527f53600060610160527f0d53606101a0527f5560] | +| 596 | MSTORE | 6 | 0 |[0x527f600b536060600c6020527f53600060610160527f0d53606101a0527f5560,0x1e0] | +| 597 | PUSH32 | 3 | 0 | [] | +| 630 | PUSH2 | 3 | 0 |[0xe60a0527f536060600f536060c0527f01601053606060115360026101806101] | +| 633 | MSTORE | 6 | 0 |[0xe60a0527f536060600f536060c0527f01601053606060115360026101806101,0x200] | +| 634 | PUSH32 | 3 | 0 | [] | +| 667 | PUSH2 | 3 | 0 |[0xc0527f527f601253606040527f55601353606060c0527f60145360e0527f6000] | +| 670 | MSTORE | 6 | 0 |[0xc0527f527f601253606040527f55601353606060c0527f60145360e0527f6000,0x220] | +| 671 | PUSH32 | 3 | 0 | [] | +| 704 | PUSH2 | 3 | 0 |[0x6015536101e0527f60606101a0527f601653600060175360f360185360196060] | +| 707 | MSTORE | 6 | 0 |[0x6015536101e0527f60606101a0527f601653600060175360f360185360196060,0x240] | +| 708 | PUSH32 | 3 | 0 | [] | +| 741 | PUSH2 | 3 | 0 |[0x605260006060e052610200527f610100527f7f806101c0527f5360f360815360] | +| 744 | MSTORE | 6 | 0 |[0x605260006060e052610200527f610100527f7f806101c0527f5360f360815360,0x260] | +| 745 | PUSH32 | 3 | 0 | [] | +| 778 | PUSH2 | 3 | 0 |[0x8260006000f060006000600060610220527e845af450506000600061016101e0] | +| 781 | MSTORE | 6 | 0 |[0x8260006000f060006000600060610220527e845af450506000600061016101e0,0x280] | +| 782 | PUSH32 | 3 | 0 | [] | +| 815 | PUSH2 | 3 | 0 |[0x527f20527f60610100527e600060006003610240527f5af15060005450c76000] | +| 818 | MSTORE | 6 | 0 |[0x527f20527f60610100527e600060006003610240527f5af15060005450c76000,0x2a0] | +| 819 | PUSH32 | 3 | 0 | [] | +| 852 | PUSH2 | 3 | 0 |[0x6002551309f562610200527f66a486610140527f6b00610260527f1d45716101] | +| 855 | MSTORE | 7 | 0 |[0x6002551309f562610200527f66a486610140527f6b00610260527f1d45716101,0x2c0] | +| 856 | PUSH32 | 3 | 0 | [] | +| 889 | PUSH2 | 3 | 0 |[0x20527f600054501c641d373c7f60045450610220527f6000600155610280527f] | +| 892 | MSTORE | 6 | 0 |[0x20527f600054501c641d373c7f60045450610220527f6000600155610280527f,0x2e0] | +| 893 | PUSH32 | 3 | 0 | [] | +| 926 | PUSH2 | 3 | 0 |[0x600554610160527f50600160025560085450610140527f60006002610240527f] | +| 929 | MSTORE | 6 | 0 |[0x600554610160527f50600160025560085450610140527f60006002610240527f,0x300] | +| 930 | PUSH32 | 3 | 0 | [] | +| 963 | PUSH2 | 3 | 0 |[0x6102a0527f557fd86000606000527e600060610180527e600060005af1508612] | +| 966 | MSTORE | 6 | 0 |[0x6102a0527f557fd86000606000527e600060610180527e600060005af1508612,0x320] | +| 967 | PUSH32 | 3 | 0 | [] | +| 1000 | PUSH2 | 3 | 0 |[0x17145147356102c0527f610260527f610160527f5198a37e127a7efa7c600052] | +| 1003 | MSTORE | 6 | 0 |[0x17145147356102c0527f610260527f610160527f5198a37e127a7efa7c600052,0x340] | +| 1004 | PUSH32 | 3 | 0 | [] | +| 1037 | PUSH2 | 3 | 0 |[0x6101a0527f606020527f6102e0527f6060205360610280527ff760215360ff60] | +| 1040 | MSTORE | 6 | 0 |[0x6101a0527f606020527f6102e0527f6060205360610280527ff760215360ff60,0x360] | +| 1041 | PUSH32 | 3 | 0 | [] | +| 1074 | PUSH2 | 3 | 0 |[0x225360610180527fdb602353603760610300527f6101c0527f24536075606102] | +| 1077 | MSTORE | 6 | 0 |[0x225360610180527fdb602353603760610300527f6101c0527f24536075606102,0x380] | +| 1078 | PUSH32 | 3 | 0 | [] | +| 1111 | PUSH2 | 3 | 0 |[0xa0527f2553609f606040527f265360fe60275360610320527f8f60286101a052] | +| 1114 | MSTORE | 6 | 0 |[0xa0527f2553609f606040527f265360fe60275360610320527f8f60286101a052,0x3a0] | +| 1115 | PUSH32 | 3 | 0 | [] | +| 1148 | PUSH2 | 3 | 0 |[0x7f53606101e0527f6102c0527f0b6029536060602a53600060610340527f2b53] | +| 1151 | MSTORE | 6 | 0 |[0x7f53606101e0527f6102c0527f0b6029536060602a53600060610340527f2b53,0x3c0] | +| 1152 | PUSH32 | 3 | 0 | [] | +| 1185 | PUSH2 | 3 | 0 |[0x6060602c53606052606060805360006061016102e0527f610200527fc0526103] | +| 1188 | MSTORE | 7 | 0 |[0x6060602c53606052606060805360006061016102e0527f610200527fc0526103,0x3e0] | +| 1189 | PUSH32 | 3 | 0 | [] | +| 1222 | PUSH2 | 3 | 0 |[0x60527f7f81536060608253602d6083536053608453606060855360fd61030052] | +| 1225 | MSTORE | 6 | 0 |[0x60527f7f81536060608253602d6083536053608453606060855360fd61030052,0x400] | +| 1226 | PUSH32 | 3 | 0 | [] | +| 1259 | PUSH2 | 3 | 0 |[0x7f6086610380527f536060610220527f6087536101e0527f602e608853605360] | +| 1262 | MSTORE | 6 | 0 |[0x7f6086610380527f536060610220527f6087536101e0527f602e608853605360,0x420] | +| 1263 | PUSH32 | 3 | 0 | [] | +| 1296 | PUSH2 | 3 | 0 |[0x89536060608a61036103a0527f20527f53602f608b536060608c610240527f53] | +| 1299 | MSTORE | 6 | 0 |[0x89536060608a61036103a0527f20527f53602f608b536060608c610240527f53,0x440] | +| 1300 | PUSH32 | 3 | 0 | [] | +| 1333 | PUSH2 | 3 | 0 |[0x6000608d5360f36102005260606103c0527f610220610340527f53608e610221] | +| 1336 | MSTORE | 6 | 0 |[0x6000608d5360f36102005260606103c0527f610220610340527f53608e610221,0x460] | +| 1337 | PUSH32 | 3 | 0 | [] | +| 1370 | PUSH2 | 3 | 0 |[0x536053610222536060610260527f610223536103e0527f600061022453606061] | +| 1373 | MSTORE | 6 | 0 |[0x536053610222536060610260527f610223536103e0527f600061022453606061,0x480] | +| 1374 | PUSH32 | 3 | 0 | [] | +| 1407 | PUSH2 | 3 | 0 |[0x360527f61022553608f61022653606061022753600061610400527f02610280] | +| 1410 | MSTORE | 6 | 0 |[0x360527f61022553608f61022653606061022753600061610400527f02610280,0x4a0] | +| 1411 | PUSH32 | 3 | 0 | [] | +| 1444 | PUSH2 | 3 | 0 |[0x527f28536060610229610380527f53600061022a5360f561022b536061042052] | +| 1447 | MSTORE | 6 | 0 |[0x527f28536060610229610380527f53600061022a5360f561022b536061042052,0x4c0] | +| 1448 | PUSH32 | 3 | 0 | [] | +| 1481 | PUSH2 | 3 | 0 |[0x7f6061022c53600061022d536102a0527f60606103a0527f61022e5360006102] | +| 1484 | MSTORE | 7 | 0 |[0x7f6061022c53600061022d536102a0527f60606103a0527f61022e5360006102,0x4e0] | +| 1485 | PUSH32 | 3 | 0 | [] | +| 1518 | PUSH2 | 3 | 0 |[0x2f610440527f53606061023053600061023153606061023253600061026103c0] | +| 1521 | MSTORE | 6 | 0 |[0x2f610440527f53606061023053600061023153606061023253600061026103c0,0x500] | +| 1522 | PUSH32 | 3 | 0 | [] | +| 1555 | PUSH2 | 3 | 0 |[0x527fc0527f61610460527f023353606061023453600061023553608561023653] | +| 1558 | MSTORE | 6 | 0 |[0x527fc0527f61610460527f023353606061023453600061023553608561023653,0x520] | +| 1559 | PUSH32 | 3 | 0 | [] | +| 1592 | PUSH2 | 3 | 0 |[0x605a61023753606103e052610480527f7ff261026102e0526038610300536053] | +| 1595 | MSTORE | 6 | 0 |[0x605a61023753606103e052610480527f7ff261026102e0526038610300536053,0x540] | +| 1596 | PUSH32 | 3 | 0 | [] | +| 1629 | PUSH2 | 3 | 0 |[0x610301536060610302536050610303536104a0527f60610400527f6161030453] | +| 1632 | MSTORE | 6 | 0 |[0x610301536060610302536050610303536104a0527f60610400527f6161030453,0x560] | +| 1633 | PUSH32 | 3 | 0 | [] | +| 1666 | PUSH2 | 3 | 0 |[0x6002610305536039610306536053610307536060616104c0527f030853605061] | +| 1669 | MSTORE | 6 | 0 |[0x6002610305536039610306536053610307536060616104c0527f030853605061,0x580] | +| 1670 | PUSH32 | 3 | 0 | [] | +| 1703 | PUSH2 | 3 | 0 |[0x610420527f030953606161030a53600261030b53603a61030c536104e0527f60] | +| 1706 | MSTORE | 7 | 0 |[0x610420527f030953606161030a53600261030b53603a61030c536104e0527f60,0x5a0] | +| 1707 | PUSH32 | 3 | 0 | [] | +| 1740 | PUSH2 | 3 | 0 |[0x5361030d53606161030e610440527f53600261030f53603b6103105360606161] | +| 1743 | MSTORE | 6 | 0 |[0x5361030d53606161030e610440527f53600261030f53603b6103105360606161,0x5c0] | +| 1744 | PUSH32 | 3 | 0 | [] | +| 1777 | PUSH2 | 3 | 0 |[0x500527f03115360006103125360f36103135361610460526003610480536014] | +| 1780 | MSTORE | 6 | 0 |[0x500527f03115360006103125360f36103135361610460526003610480536014,0x5e0] | +| 1781 | PUSH32 | 3 | 0 | [] | +| 1814 | PUSH2 | 3 | 0 |[0x61048153610520527f6060610482536000610483536060610484536000610485] | +| 1817 | MSTORE | 6 | 0 |[0x61048153610520527f6060610482536000610483536060610484536000610485,0x600] | +| 1818 | PUSH32 | 3 | 0 | [] | +| 1851 | PUSH2 | 3 | 0 |[0x5360f0610486536060610540527f610487536000610488536060610489536000] | +| 1854 | MSTORE | 6 | 0 |[0x5360f0610486536060610540527f610487536000610488536060610489536000,0x620] | +| 1855 | PUSH32 | 3 | 0 | [] | +| 1888 | PUSH2 | 3 | 0 |[0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e] | +| 1891 | MSTORE | 7 | 0 |[0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e,0x640] | +| 1892 | PUSH32 | 3 | 0 | [] | +| 1925 | PUSH2 | 3 | 0 |[0x53608461048f53605a6104905360f4610491536105805260606105a053605061] | +| 1928 | MSTORE | 6 | 0 |[0x53608461048f53605a6104905360f4610491536105805260606105a053605061,0x660] | +| 1929 | PUSH32 | 3 | 0 | [] | +| 1962 | PUSH2 | 3 | 0 |[0x5a15360616105a25360046105a35360926105a45360536105a55360606105a6] | +| 1965 | MSTORE | 6 | 0 |[0x5a15360616105a25360046105a35360926105a45360536105a55360606105a6,0x680] | +| 1966 | PUSH32 | 3 | 0 | [] | +| 1999 | PUSH2 | 3 | 0 |[0x5360506105a75360616105a85360046105a95360936105aa5360536105ab5360] | +| 2002 | MSTORE | 6 | 0 |[0x5360506105a75360616105a85360046105a95360936105aa5360536105ab5360,0x6a0] | +| 2003 | PUSH32 | 3 | 0 | [] | +| 2036 | PUSH2 | 3 | 0 |[0x616105ac5360046105ad5360946105ae5360606105af5360006105b05360f361] | +| 2039 | MSTORE | 6 | 0 |[0x616105ac5360046105ad5360946105ae5360606105af5360006105b05360f361,0x6c0] | +| 2040 | PUSH1 | 3 | 0 | [] | +| 2042 | PUSH2 | 3 | 0 | [0x5] | +| 2045 | MSTORE8 | 7 | 0 |[0x5,0x6e0] | +| 2046 | PUSH1 | 3 | 0 | [] | +| 2048 | PUSH2 | 3 | 0 | [0xb1] | +| 2051 | MSTORE8 | 3 | 0 |[0xb1,0x6e1] | +| 2052 | PUSH1 | 3 | 0 | [] | +| 2054 | PUSH2 | 3 | 0 | [0x53] | +| 2057 | MSTORE8 | 3 | 0 |[0x53,0x6e2] | +| 2058 | PUSH1 | 3 | 0 | [] | +| 2060 | PUSH2 | 3 | 0 | [0x60] | +| 2063 | MSTORE8 | 3 | 0 |[0x60,0x6e3] | +| 2064 | PUSH1 | 3 | 0 | [] | +| 2066 | PUSH2 | 3 | 0 | [0x0] | +| 2069 | MSTORE8 | 3 | 0 |[0x0,0x6e4] | +| 2070 | PUSH1 | 3 | 0 | [] | +| 2072 | PUSH2 | 3 | 0 | [0x61] | +| 2075 | MSTORE8 | 3 | 0 |[0x61,0x6e5] | +| 2076 | PUSH1 | 3 | 0 | [] | +| 2078 | PUSH2 | 3 | 0 | [0x5] | +| 2081 | MSTORE8 | 3 | 0 |[0x5,0x6e6] | +| 2082 | PUSH1 | 3 | 0 | [] | +| 2084 | PUSH2 | 3 | 0 | [0xb2] | +| 2087 | MSTORE8 | 3 | 0 |[0xb2,0x6e7] | +| 2088 | PUSH1 | 3 | 0 | [] | +| 2090 | PUSH2 | 3 | 0 | [0x60] | +| 2093 | MSTORE8 | 3 | 0 |[0x60,0x6e8] | +| 2094 | PUSH1 | 3 | 0 | [] | +| 2096 | PUSH2 | 3 | 0 | [0x0] | +| 2099 | MSTORE8 | 3 | 0 |[0x0,0x6e9] | +| 2100 | PUSH1 | 3 | 0 | [] | +| 2102 | PUSH2 | 3 | 0 | [0x60] | +| 2105 | MSTORE8 | 3 | 0 |[0x60,0x6ea] | +| 2106 | PUSH1 | 3 | 0 | [] | +| 2108 | PUSH2 | 3 | 0 | [0x0] | +| 2111 | MSTORE8 | 3 | 0 |[0x0,0x6eb] | +| 2112 | PUSH1 | 3 | 0 | [] | +| 2114 | PUSH2 | 3 | 0 | [0xf5] | +| 2117 | MSTORE8 | 3 | 0 |[0xf5,0x6ec] | +| 2118 | PUSH1 | 3 | 0 | [] | +| 2120 | PUSH2 | 3 | 0 | [0x60] | +| 2123 | MSTORE8 | 3 | 0 |[0x60,0x6ed] | +| 2124 | PUSH1 | 3 | 0 | [] | +| 2126 | PUSH2 | 3 | 0 | [0x0] | +| 2129 | MSTORE8 | 3 | 0 |[0x0,0x6ee] | +| 2130 | PUSH1 | 3 | 0 | [] | +| 2132 | PUSH2 | 3 | 0 | [0x60] | +| 2135 | MSTORE8 | 3 | 0 |[0x60,0x6ef] | +| 2136 | PUSH1 | 3 | 0 | [] | +| 2138 | PUSH2 | 3 | 0 | [0x0] | +| 2141 | MSTORE8 | 3 | 0 |[0x0,0x6f0] | +| 2142 | PUSH1 | 3 | 0 | [] | +| 2144 | PUSH2 | 3 | 0 | [0x60] | +| 2147 | MSTORE8 | 3 | 0 |[0x60,0x6f1] | +| 2148 | PUSH1 | 3 | 0 | [] | +| 2150 | PUSH2 | 3 | 0 | [0x0] | +| 2153 | MSTORE8 | 3 | 0 |[0x0,0x6f2] | +| 2154 | PUSH1 | 3 | 0 | [] | +| 2156 | PUSH2 | 3 | 0 | [0x60] | +| 2159 | MSTORE8 | 3 | 0 |[0x60,0x6f3] | +| 2160 | PUSH1 | 3 | 0 | [] | +| 2162 | PUSH2 | 3 | 0 | [0x0] | +| 2165 | MSTORE8 | 3 | 0 |[0x0,0x6f4] | +| 2166 | PUSH1 | 3 | 0 | [] | +| 2168 | PUSH2 | 3 | 0 | [0x60] | +| 2171 | MSTORE8 | 3 | 0 |[0x60,0x6f5] | +| 2172 | PUSH1 | 3 | 0 | [] | +| 2174 | PUSH2 | 3 | 0 | [0x0] | +| 2177 | MSTORE8 | 3 | 0 |[0x0,0x6f6] | +| 2178 | PUSH1 | 3 | 0 | [] | +| 2180 | PUSH2 | 3 | 0 | [0x85] | +| 2183 | MSTORE8 | 3 | 0 |[0x85,0x6f7] | +| 2184 | PUSH1 | 3 | 0 | [] | +| 2186 | PUSH2 | 3 | 0 | [0x5a] | +| 2189 | MSTORE8 | 3 | 0 |[0x5a,0x6f8] | +| 2190 | PUSH1 | 3 | 0 | [] | +| 2192 | PUSH2 | 3 | 0 | [0xf1] | +| 2195 | MSTORE8 | 3 | 0 |[0xf1,0x6f9] | +| 2196 | PUSH1 | 3 | 0 | [] | +| 2198 | PUSH2 | 3 | 0 | [0x50] | +| 2201 | MSTORE8 | 3 | 0 |[0x50,0x6fa] | +| 2202 | PUSH1 | 3 | 0 | [] | +| 2204 | PUSH2 | 3 | 0 | [0x50] | +| 2207 | MSTORE8 | 3 | 0 |[0x50,0x6fb] | +| 2208 | PUSH2 | 3 | 0 | [] | +| 2211 | PUSH1 | 3 | 0 | [0x6fc] | +| 2213 | RETURN | 0 | 0 |[0x6fc,0x0] | +| 2605 | PUSH1 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba] | +| 2607 | PUSH1 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0] | +| 2609 | PUSH1 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0] | +| 2611 | PUSH1 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0,0x0] | +| 2613 | PUSH1 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0,0x0,0x0] | +| 2615 | DUP6 | 3 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0,0x0,0x0,0x0] | +| 2616 | GAS | 2 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0,0x0,0x0,0x0,0x7dce2faf43218578e3fcf2ad22df9918a89e2fba] | +| 2617 | CALL | 295218 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x0,0x0,0x0,0x0,0x0,0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x4937e] | +| 0 | PUSH32 | 3 | 0 | [] | +| 33 | PUSH1 | 3 | 0 |[0x6008545060006004557f600160045560006004556000600060006000600060f9] | +| 35 | MSTORE | 6 | 0 |[0x6008545060006004557f600160045560006004556000600060006000600060f9,0x0] | +| 36 | PUSH32 | 3 | 0 | [] | +| 69 | PUSH1 | 3 | 0 |[0x5af250600060006000606000527e60f45af4506000600060006000600060f55a] | +| 71 | MSTORE | 6 | 0 |[0x5af250600060006000606000527e60f45af4506000600060006000600060f55a,0x20] | +| 72 | PUSH32 | 3 | 0 | [] | +| 105 | PUSH1 | 3 | 0 |[0xf150f001075205846a44a283446020527f8ca2600060006000600060045af450] | +| 107 | MSTORE | 6 | 0 |[0xf150f001075205846a44a283446020527f8ca2600060006000600060045af450,0x40] | +| 108 | PUSH32 | 3 | 0 | [] | +| 141 | PUSH1 | 3 | 0 |[0x519930847f3b631c54a49b5f60035450326040527f77306b6000600060006000] | +| 143 | MSTORE | 6 | 0 |[0x519930847f3b631c54a49b5f60035450326040527f77306b6000600060006000,0x60] | +| 144 | PUSH32 | 3 | 0 | [] | +| 177 | PUSH1 | 3 | 0 |[0x6000600c5af150600060006000600060f85af450506060527f06600160025560] | +| 179 | MSTORE | 6 | 0 |[0x6000600c5af150600060006000600060f85af450506060527f06600160025560,0x80] | +| 180 | PUSH32 | 3 | 0 | [] | +| 213 | PUSH1 | 3 | 0 |[0x35450600060005560006001556c3394fff4607f7f1684317b6080527f387b9f] | +| 215 | MSTORE | 6 | 0 |[0x35450600060005560006001556c3394fff4607f7f1684317b6080527f387b9f,0xa0] | +| 216 | PUSH32 | 3 | 0 | [] | +| 249 | PUSH1 | 3 | 0 |[0x1920700184809d60015450011899016e6009ff60026001556000527f9f60a052] | +| 251 | MSTORE | 6 | 0 |[0x1920700184809d60015450011899016e6009ff60026001556000527f9f60a052,0xc0] | +| 252 | PUSH32 | 3 | 0 | [] | +| 285 | PUSH1 | 3 | 0 |[0x7f6000527f9981600160045582600eff600060006000600060f65af450600060] | +| 287 | MSTORE | 6 | 0 |[0x7f6000527f9981600160045582600eff600060006000600060f65af450600060,0xe0] | +| 288 | PUSH32 | 3 | 0 | [] | +| 321 | PUSH2 | 3 | 0 |[0x6060c0527f20527e600060006020527f60f75af4501d7f190316666000600060] | +| 324 | MSTORE | 6 | 0 |[0x6060c0527f20527e600060006020527f60f75af4501d7f190316666000600060,0x100] | +| 325 | PUSH31 | 3 | 0 | [] | +| 357 | PUSH2 | 3 | 0 |[0x6000600060e0527f60046040527f5af1506000600060006040527f60006009] | +| 360 | MSTORE | 6 | 0 |[0x6000600060e0527f60046040527f5af1506000600060006040527f60006009,0x120] | +| 361 | PUSH32 | 3 | 0 | [] | +| 394 | PUSH2 | 3 | 0 |[0x5af4503c95138e5b8f610100527f7f605a6000536060527f6031600153606b60] | +| 397 | MSTORE | 6 | 0 |[0x5af4503c95138e5b8f610100527f7f605a6000536060527f6031600153606b60,0x140] | +| 398 | PUSH32 | 3 | 0 | [] | +| 431 | PUSH2 | 3 | 0 |[0x2536010606060527f0353604560610120527f04536060600553600160608052] | +| 434 | MSTORE | 6 | 0 |[0x2536010606060527f0353604560610120527f04536060600553600160608052,0x160] | +| 435 | PUSH32 | 3 | 0 | [] | +| 468 | PUSH2 | 3 | 0 |[0x7e527f60065360606007536002600853606080610140527f527f556009536060] | +| 471 | MSTORE | 6 | 0 |[0x7e527f60065360606007536002600853606080610140527f527f556009536060,0x180] | +| 472 | PUSH32 | 3 | 0 | [] | +| 505 | PUSH2 | 3 | 0 |[0x600a53600160a0527f600b536060600c6020527f53600060610160527f0d5360] | +| 508 | MSTORE | 6 | 0 |[0x600a53600160a0527f600b536060600c6020527f53600060610160527f0d5360,0x1a0] | +| 509 | PUSH32 | 3 | 0 | [] | +| 542 | PUSH2 | 3 | 0 |[0x55600e60a0527f536060600f536060c0527f0160105360606011536002610180] | +| 545 | MSTORE | 6 | 0 |[0x55600e60a0527f536060600f536060c0527f0160105360606011536002610180,0x1c0] | +| 546 | PUSH32 | 3 | 0 | [] | +| 579 | PUSH2 | 3 | 0 |[0x527f601253606040527f55601353606060c0527f60145360e0527f6000601553] | +| 582 | MSTORE | 6 | 0 |[0x527f601253606040527f55601353606060c0527f60145360e0527f6000601553,0x1e0] | +| 583 | PUSH32 | 3 | 0 | [] | +| 616 | PUSH2 | 3 | 0 |[0x60606101a0527f601653600060175360f360185360196060605260006060e052] | +| 619 | MSTORE | 6 | 0 |[0x60606101a0527f601653600060175360f360185360196060605260006060e052,0x200] | +| 620 | PUSH32 | 3 | 0 | [] | +| 653 | PUSH2 | 3 | 0 |[0x610100527f7f806101c0527f5360f3608153608260006000f060006000600060] | +| 656 | MSTORE | 6 | 0 |[0x610100527f7f806101c0527f5360f3608153608260006000f060006000600060,0x220] | +| 657 | PUSH31 | 3 | 0 | [] | +| 689 | PUSH2 | 3 | 0 |[0x845af450506000600061016101e0527f20527f60610100527e600060006003] | +| 692 | MSTORE | 6 | 0 |[0x845af450506000600061016101e0527f20527f60610100527e600060006003,0x240] | +| 693 | PUSH32 | 3 | 0 | [] | +| 726 | PUSH2 | 3 | 0 |[0x5af15060005450c760006002551309f562610200527f66a486610140527f6b00] | +| 729 | MSTORE | 6 | 0 |[0x5af15060005450c760006002551309f562610200527f66a486610140527f6b00,0x260] | +| 730 | PUSH32 | 3 | 0 | [] | +| 763 | PUSH2 | 3 | 0 |[0x1d4571610120527f600054501c641d373c7f60045450610220527f6000600155] | +| 766 | MSTORE | 6 | 0 |[0x1d4571610120527f600054501c641d373c7f60045450610220527f6000600155,0x280] | +| 767 | PUSH32 | 3 | 0 | [] | +| 800 | PUSH2 | 3 | 0 |[0x600554610160527f50600160025560085450610140527f60006002610240527f] | +| 803 | MSTORE | 6 | 0 |[0x600554610160527f50600160025560085450610140527f60006002610240527f,0x2a0] | +| 804 | PUSH32 | 3 | 0 | [] | +| 837 | PUSH2 | 3 | 0 |[0x557fd86000606000527e600060610180527e600060005af15086121714514735] | +| 840 | MSTORE | 7 | 0 |[0x557fd86000606000527e600060610180527e600060005af15086121714514735,0x2c0] | +| 841 | PUSH32 | 3 | 0 | [] | +| 874 | PUSH2 | 3 | 0 |[0x610260527f610160527f5198a37e127a7efa7c6000526101a0527f606020527f] | +| 877 | MSTORE | 6 | 0 |[0x610260527f610160527f5198a37e127a7efa7c6000526101a0527f606020527f,0x2e0] | +| 878 | PUSH32 | 3 | 0 | [] | +| 911 | PUSH2 | 3 | 0 |[0x6060205360610280527ff760215360ff60225360610180527fdb602353603760] | +| 914 | MSTORE | 6 | 0 |[0x6060205360610280527ff760215360ff60225360610180527fdb602353603760,0x300] | +| 915 | PUSH32 | 3 | 0 | [] | +| 948 | PUSH2 | 3 | 0 |[0x6101c0527f24536075606102a0527f2553609f606040527f265360fe60275360] | +| 951 | MSTORE | 6 | 0 |[0x6101c0527f24536075606102a0527f2553609f606040527f265360fe60275360,0x320] | +| 952 | PUSH32 | 3 | 0 | [] | +| 985 | PUSH2 | 3 | 0 |[0x8f60286101a0527f53606101e0527f6102c0527f0b6029536060602a53600060] | +| 988 | MSTORE | 6 | 0 |[0x8f60286101a0527f53606101e0527f6102c0527f0b6029536060602a53600060,0x340] | +| 989 | PUSH32 | 3 | 0 | [] | +| 1022 | PUSH2 | 3 | 0 |[0x2b536060602c53606052606060805360006061016102e0527f610200527fc052] | +| 1025 | MSTORE | 6 | 0 |[0x2b536060602c53606052606060805360006061016102e0527f610200527fc052,0x360] | +| 1026 | PUSH32 | 3 | 0 | [] | +| 1059 | PUSH2 | 3 | 0 |[0x7f81536060608253602d6083536053608453606060855360fd610300527f6086] | +| 1062 | MSTORE | 6 | 0 |[0x7f81536060608253602d6083536053608453606060855360fd610300527f6086,0x380] | +| 1063 | PUSH32 | 3 | 0 | [] | +| 1096 | PUSH2 | 3 | 0 |[0x536060610220527f6087536101e0527f602e60885360536089536060608a6103] | +| 1099 | MSTORE | 6 | 0 |[0x536060610220527f6087536101e0527f602e60885360536089536060608a6103,0x3a0] | +| 1100 | PUSH32 | 3 | 0 | [] | +| 1133 | PUSH2 | 3 | 0 |[0x20527f53602f608b536060608c610240527f536000608d5360f3610200526060] | +| 1136 | MSTORE | 6 | 0 |[0x20527f53602f608b536060608c610240527f536000608d5360f3610200526060,0x3c0] | +| 1137 | PUSH32 | 3 | 0 | [] | +| 1170 | PUSH2 | 3 | 0 |[0x610220610340527f53608e610221536053610222536060610260527f61022353] | +| 1173 | MSTORE | 7 | 0 |[0x610220610340527f53608e610221536053610222536060610260527f61022353,0x3e0] | +| 1174 | PUSH32 | 3 | 0 | [] | +| 1207 | PUSH2 | 3 | 0 |[0x6000610224536060610360527f61022553608f61022653606061022753600061] | +| 1210 | MSTORE | 6 | 0 |[0x6000610224536060610360527f61022553608f61022653606061022753600061,0x400] | +| 1211 | PUSH32 | 3 | 0 | [] | +| 1244 | PUSH2 | 3 | 0 |[0x2610280527f28536060610229610380527f53600061022a5360f561022b5360] | +| 1247 | MSTORE | 6 | 0 |[0x2610280527f28536060610229610380527f53600061022a5360f561022b5360,0x420] | +| 1248 | PUSH32 | 3 | 0 | [] | +| 1281 | PUSH2 | 3 | 0 |[0x6061022c53600061022d536102a0527f60606103a0527f61022e53600061022f] | +| 1284 | MSTORE | 6 | 0 |[0x6061022c53600061022d536102a0527f60606103a0527f61022e53600061022f,0x440] | +| 1285 | PUSH32 | 3 | 0 | [] | +| 1318 | PUSH2 | 3 | 0 |[0x53606061023053600061023153606061023253600061026103c0527fc0527f61] | +| 1321 | MSTORE | 6 | 0 |[0x53606061023053600061023153606061023253600061026103c0527fc0527f61,0x460] | +| 1322 | PUSH32 | 3 | 0 | [] | +| 1355 | PUSH2 | 3 | 0 |[0x23353606061023453600061023553608561023653605a61023753606103e052] | +| 1358 | MSTORE | 6 | 0 |[0x23353606061023453600061023553608561023653605a61023753606103e052,0x480] | +| 1359 | PUSH32 | 3 | 0 | [] | +| 1392 | PUSH2 | 3 | 0 |[0x7ff261026102e052603861030053605361030153606061030253605061030353] | +| 1395 | MSTORE | 6 | 0 |[0x7ff261026102e052603861030053605361030153606061030253605061030353,0x4a0] | +| 1396 | PUSH32 | 3 | 0 | [] | +| 1429 | PUSH2 | 3 | 0 |[0x60610400527f6161030453600261030553603961030653605361030753606061] | +| 1432 | MSTORE | 6 | 0 |[0x60610400527f6161030453600261030553603961030653605361030753606061,0x4c0] | +| 1433 | PUSH32 | 3 | 0 | [] | +| 1466 | PUSH2 | 3 | 0 |[0x30853605061610420527f030953606161030a53600261030b53603a61030c53] | +| 1469 | MSTORE | 7 | 0 |[0x30853605061610420527f030953606161030a53600261030b53603a61030c53,0x4e0] | +| 1470 | PUSH32 | 3 | 0 | [] | +| 1503 | PUSH2 | 3 | 0 |[0x605361030d53606161030e610440527f53600261030f53603b61031053606061] | +| 1506 | MSTORE | 6 | 0 |[0x605361030d53606161030e610440527f53600261030f53603b61031053606061,0x500] | +| 1507 | PUSH32 | 3 | 0 | [] | +| 1540 | PUSH2 | 3 | 0 |[0x3115360006103125360f3610313536161046052600361048053601461048153] | +| 1543 | MSTORE | 6 | 0 |[0x3115360006103125360f3610313536161046052600361048053601461048153,0x520] | +| 1544 | PUSH32 | 3 | 0 | [] | +| 1577 | PUSH2 | 3 | 0 |[0x60606104825360006104835360606104845360006104855360f0610486536060] | +| 1580 | MSTORE | 6 | 0 |[0x60606104825360006104835360606104845360006104855360f0610486536060,0x540] | +| 1581 | PUSH32 | 3 | 0 | [] | +| 1614 | PUSH2 | 3 | 0 |[0x61048753600061048853606061048953600061048a53606061048b5360006104] | +| 1617 | MSTORE | 6 | 0 |[0x61048753600061048853606061048953600061048a53606061048b5360006104,0x560] | +| 1618 | PUSH32 | 3 | 0 | [] | +| 1651 | PUSH2 | 3 | 0 |[0x8c53606061048d53600061048e53608461048f53605a6104905360f461049153] | +| 1654 | MSTORE | 6 | 0 |[0x8c53606061048d53600061048e53608461048f53605a6104905360f461049153,0x580] | +| 1655 | PUSH1 | 3 | 0 | [] | +| 1657 | PUSH2 | 3 | 0 | [0x60] | +| 1660 | MSTORE8 | 7 | 0 |[0x60,0x5a0] | +| 1661 | PUSH1 | 3 | 0 | [] | +| 1663 | PUSH2 | 3 | 0 | [0x50] | +| 1666 | MSTORE8 | 3 | 0 |[0x50,0x5a1] | +| 1667 | PUSH1 | 3 | 0 | [] | +| 1669 | PUSH2 | 3 | 0 | [0x61] | +| 1672 | MSTORE8 | 3 | 0 |[0x61,0x5a2] | +| 1673 | PUSH1 | 3 | 0 | [] | +| 1675 | PUSH2 | 3 | 0 | [0x4] | +| 1678 | MSTORE8 | 3 | 0 |[0x4,0x5a3] | +| 1679 | PUSH1 | 3 | 0 | [] | +| 1681 | PUSH2 | 3 | 0 | [0x92] | +| 1684 | MSTORE8 | 3 | 0 |[0x92,0x5a4] | +| 1685 | PUSH1 | 3 | 0 | [] | +| 1687 | PUSH2 | 3 | 0 | [0x53] | +| 1690 | MSTORE8 | 3 | 0 |[0x53,0x5a5] | +| 1691 | PUSH1 | 3 | 0 | [] | +| 1693 | PUSH2 | 3 | 0 | [0x60] | +| 1696 | MSTORE8 | 3 | 0 |[0x60,0x5a6] | +| 1697 | PUSH1 | 3 | 0 | [] | +| 1699 | PUSH2 | 3 | 0 | [0x50] | +| 1702 | MSTORE8 | 3 | 0 |[0x50,0x5a7] | +| 1703 | PUSH1 | 3 | 0 | [] | +| 1705 | PUSH2 | 3 | 0 | [0x61] | +| 1708 | MSTORE8 | 3 | 0 |[0x61,0x5a8] | +| 1709 | PUSH1 | 3 | 0 | [] | +| 1711 | PUSH2 | 3 | 0 | [0x4] | +| 1714 | MSTORE8 | 3 | 0 |[0x4,0x5a9] | +| 1715 | PUSH1 | 3 | 0 | [] | +| 1717 | PUSH2 | 3 | 0 | [0x93] | +| 1720 | MSTORE8 | 3 | 0 |[0x93,0x5aa] | +| 1721 | PUSH1 | 3 | 0 | [] | +| 1723 | PUSH2 | 3 | 0 | [0x53] | +| 1726 | MSTORE8 | 3 | 0 |[0x53,0x5ab] | +| 1727 | PUSH1 | 3 | 0 | [] | +| 1729 | PUSH2 | 3 | 0 | [0x61] | +| 1732 | MSTORE8 | 3 | 0 |[0x61,0x5ac] | +| 1733 | PUSH1 | 3 | 0 | [] | +| 1735 | PUSH2 | 3 | 0 | [0x4] | +| 1738 | MSTORE8 | 3 | 0 |[0x4,0x5ad] | +| 1739 | PUSH1 | 3 | 0 | [] | +| 1741 | PUSH2 | 3 | 0 | [0x94] | +| 1744 | MSTORE8 | 3 | 0 |[0x94,0x5ae] | +| 1745 | PUSH1 | 3 | 0 | [] | +| 1747 | PUSH2 | 3 | 0 | [0x60] | +| 1750 | MSTORE8 | 3 | 0 |[0x60,0x5af] | +| 1751 | PUSH1 | 3 | 0 | [] | +| 1753 | PUSH2 | 3 | 0 | [0x0] | +| 1756 | MSTORE8 | 3 | 0 |[0x0,0x5b0] | +| 1757 | PUSH1 | 3 | 0 | [] | +| 1759 | PUSH2 | 3 | 0 | [0xf3] | +| 1762 | MSTORE8 | 3 | 0 |[0xf3,0x5b1] | +| 1763 | PUSH1 | 3 | 0 | [] | +| 1765 | PUSH2 | 3 | 0 | [0x0] | +| 1768 | PUSH1 | 3 | 0 |[0x0,0x5b2] | +| 1770 | PUSH1 | 3 | 0 |[0x0,0x5b2,0x0] | +| 1772 | CREATE2 | 32276 | 0 |[0x0,0x5b2,0x0,0x0] | +| 0 | PUSH1 | 3 | 0 | [] | +| 2 | SLOAD | 2100 | 0 | [0x8] | +| 3 | POP | 2 | 0 | [0x0] | +| 4 | PUSH1 | 3 | 0 | [] | +| 6 | PUSH1 | 3 | 0 | [0x0] | +| 8 | SSTORE | 2200 | 0 | [0x0,0x4] | +| 9 | PUSH32 | 3 | 0 | [] | +| 42 | PUSH1 | 3 | 0 |[0x600160045560006004556000600060006000600060f95af25060006000600060] | +| 44 | MSTORE | 6 | 0 |[0x600160045560006004556000600060006000600060f95af25060006000600060,0x0] | +| 45 | PUSH31 | 3 | 0 | [] | +| 77 | PUSH1 | 3 | 0 |[0x60f45af4506000600060006000600060f55af150f001075205846a44a28344] | +| 79 | MSTORE | 6 | 0 |[0x60f45af4506000600060006000600060f55af150f001075205846a44a28344,0x20] | +| 80 | PUSH32 | 3 | 0 | [] | +| 113 | PUSH1 | 3 | 0 |[0x8ca2600060006000600060045af450519930847f3b631c54a49b5f6003545032] | +| 115 | MSTORE | 6 | 0 |[0x8ca2600060006000600060045af450519930847f3b631c54a49b5f6003545032,0x40] | +| 116 | PUSH32 | 3 | 0 | [] | +| 149 | PUSH1 | 3 | 0 |[0x77306b60006000600060006000600c5af150600060006000600060f85af45050] | +| 151 | MSTORE | 6 | 0 |[0x77306b60006000600060006000600c5af150600060006000600060f85af45050,0x60] | +| 152 | PUSH32 | 3 | 0 | [] | +| 185 | PUSH1 | 3 | 0 |[0x6600160025560035450600060005560006001556c3394fff4607f7f1684317b] | +| 187 | MSTORE | 6 | 0 |[0x6600160025560035450600060005560006001556c3394fff4607f7f1684317b,0x80] | +| 188 | PUSH32 | 3 | 0 | [] | +| 221 | PUSH1 | 3 | 0 |[0x387b9f1920700184809d60015450011899016e6009ff60026001556000527f9f] | +| 223 | MSTORE | 6 | 0 |[0x387b9f1920700184809d60015450011899016e6009ff60026001556000527f9f,0xa0] | +| 224 | PUSH32 | 3 | 0 | [] | +| 257 | PUSH1 | 3 | 0 |[0x6000527f9981600160045582600eff600060006000600060f65af45060006060] | +| 259 | MSTORE | 6 | 0 |[0x6000527f9981600160045582600eff600060006000600060f65af45060006060,0xc0] | +| 260 | PUSH32 | 3 | 0 | [] | +| 293 | PUSH1 | 3 | 0 |[0x20527e600060006020527f60f75af4501d7f1903166660006000600060006000] | +| 295 | MSTORE | 6 | 0 |[0x20527e600060006020527f60f75af4501d7f1903166660006000600060006000,0xe0] | +| 296 | PUSH32 | 3 | 0 | [] | +| 329 | PUSH2 | 3 | 0 |[0x60046040527f5af1506000600060006040527f600060095af4503c95138e5b8f] | +| 332 | MSTORE | 6 | 0 |[0x60046040527f5af1506000600060006040527f600060095af4503c95138e5b8f,0x100] | +| 333 | PUSH32 | 3 | 0 | [] | +| 366 | PUSH2 | 3 | 0 |[0x7f605a6000536060527f6031600153606b6002536010606060527f0353604560] | +| 369 | MSTORE | 6 | 0 |[0x7f605a6000536060527f6031600153606b6002536010606060527f0353604560,0x120] | +| 370 | PUSH32 | 3 | 0 | [] | +| 403 | PUSH2 | 3 | 0 |[0x45360606005536001606080527e527f60065360606007536002600853606080] | +| 406 | MSTORE | 6 | 0 |[0x45360606005536001606080527e527f60065360606007536002600853606080,0x140] | +| 407 | PUSH32 | 3 | 0 | [] | +| 440 | PUSH2 | 3 | 0 |[0x527f556009536060600a53600160a0527f600b536060600c6020527f53600060] | +| 443 | MSTORE | 6 | 0 |[0x527f556009536060600a53600160a0527f600b536060600c6020527f53600060,0x160] | +| 444 | PUSH32 | 3 | 0 | [] | +| 477 | PUSH2 | 3 | 0 |[0xd536055600e60a0527f536060600f536060c0527f0160105360606011536002] | +| 480 | MSTORE | 6 | 0 |[0xd536055600e60a0527f536060600f536060c0527f0160105360606011536002,0x180] | +| 481 | PUSH32 | 3 | 0 | [] | +| 514 | PUSH2 | 3 | 0 |[0x601253606040527f55601353606060c0527f60145360e0527f60006015536060] | +| 517 | MSTORE | 6 | 0 |[0x601253606040527f55601353606060c0527f60145360e0527f60006015536060,0x1a0] | +| 518 | PUSH32 | 3 | 0 | [] | +| 551 | PUSH2 | 3 | 0 |[0x601653600060175360f360185360196060605260006060e052610100527f7f80] | +| 554 | MSTORE | 6 | 0 |[0x601653600060175360f360185360196060605260006060e052610100527f7f80,0x1c0] | +| 555 | PUSH32 | 3 | 0 | [] | +| 588 | PUSH2 | 3 | 0 |[0x5360f3608153608260006000f06000600060006000845af45050600060006101] | +| 591 | MSTORE | 6 | 0 |[0x5360f3608153608260006000f06000600060006000845af45050600060006101,0x1e0] | +| 592 | PUSH32 | 3 | 0 | [] | +| 625 | PUSH2 | 3 | 0 |[0x20527f60610100527e6000600060035af15060005450c760006002551309f562] | +| 628 | MSTORE | 6 | 0 |[0x20527f60610100527e6000600060035af15060005450c760006002551309f562,0x200] | +| 629 | PUSH32 | 3 | 0 | [] | +| 662 | PUSH2 | 3 | 0 |[0x66a486610140527f6b001d4571610120527f600054501c641d373c7f60045450] | +| 665 | MSTORE | 6 | 0 |[0x66a486610140527f6b001d4571610120527f600054501c641d373c7f60045450,0x220] | +| 666 | PUSH32 | 3 | 0 | [] | +| 699 | PUSH2 | 3 | 0 |[0x6000600155600554610160527f50600160025560085450610140527f60006002] | +| 702 | MSTORE | 6 | 0 |[0x6000600155600554610160527f50600160025560085450610140527f60006002,0x240] | +| 703 | PUSH32 | 3 | 0 | [] | +| 736 | PUSH2 | 3 | 0 |[0x557fd86000606000527e600060610180527e600060005af15086121714514735] | +| 739 | MSTORE | 6 | 0 |[0x557fd86000606000527e600060610180527e600060005af15086121714514735,0x260] | +| 740 | PUSH32 | 3 | 0 | [] | +| 773 | PUSH2 | 3 | 0 |[0x610160527f5198a37e127a7efa7c6000526101a0527f606020527f6060205360] | +| 776 | MSTORE | 6 | 0 |[0x610160527f5198a37e127a7efa7c6000526101a0527f606020527f6060205360,0x280] | +| 777 | PUSH32 | 3 | 0 | [] | +| 810 | PUSH2 | 3 | 0 |[0xf760215360ff60225360610180527fdb6023536037606101c0527f2453607560] | +| 813 | MSTORE | 6 | 0 |[0xf760215360ff60225360610180527fdb6023536037606101c0527f2453607560,0x2a0] | +| 814 | PUSH32 | 3 | 0 | [] | +| 847 | PUSH2 | 3 | 0 |[0x2553609f606040527f265360fe602753608f60286101a0527f53606101e0527f] | +| 850 | MSTORE | 7 | 0 |[0x2553609f606040527f265360fe602753608f60286101a0527f53606101e0527f,0x2c0] | +| 851 | PUSH32 | 3 | 0 | [] | +| 884 | PUSH2 | 3 | 0 |[0xb6029536060602a536000602b536060602c5360605260606080536000606101] | +| 887 | MSTORE | 6 | 0 |[0xb6029536060602a536000602b536060602c5360605260606080536000606101,0x2e0] | +| 888 | PUSH32 | 3 | 0 | [] | +| 921 | PUSH2 | 3 | 0 |[0x610200527fc0527f81536060608253602d6083536053608453606060855360fd] | +| 924 | MSTORE | 6 | 0 |[0x610200527fc0527f81536060608253602d6083536053608453606060855360fd,0x300] | +| 925 | PUSH32 | 3 | 0 | [] | +| 958 | PUSH2 | 3 | 0 |[0x6086536060610220527f6087536101e0527f602e60885360536089536060608a] | +| 961 | MSTORE | 6 | 0 |[0x6086536060610220527f6087536101e0527f602e60885360536089536060608a,0x320] | +| 962 | PUSH32 | 3 | 0 | [] | +| 995 | PUSH2 | 3 | 0 |[0x53602f608b536060608c610240527f536000608d5360f3610200526060610220] | +| 998 | MSTORE | 6 | 0 |[0x53602f608b536060608c610240527f536000608d5360f3610200526060610220,0x340] | +| 999 | PUSH32 | 3 | 0 | [] | +| 1032 | PUSH2 | 3 | 0 |[0x53608e610221536053610222536060610260527f610223536000610224536060] | +| 1035 | MSTORE | 6 | 0 |[0x53608e610221536053610222536060610260527f610223536000610224536060,0x360] | +| 1036 | PUSH32 | 3 | 0 | [] | +| 1069 | PUSH2 | 3 | 0 |[0x61022553608f6102265360606102275360006102610280527f28536060610229] | +| 1072 | MSTORE | 6 | 0 |[0x61022553608f6102265360606102275360006102610280527f28536060610229,0x380] | +| 1073 | PUSH32 | 3 | 0 | [] | +| 1106 | PUSH2 | 3 | 0 |[0x53600061022a5360f561022b53606061022c53600061022d536102a0527f6060] | +| 1109 | MSTORE | 6 | 0 |[0x53600061022a5360f561022b53606061022c53600061022d536102a0527f6060,0x3a0] | +| 1110 | PUSH32 | 3 | 0 | [] | +| 1143 | PUSH2 | 3 | 0 |[0x61022e53600061022f5360606102305360006102315360606102325360006102] | +| 1146 | MSTORE | 6 | 0 |[0x61022e53600061022f5360606102305360006102315360606102325360006102,0x3c0] | +| 1147 | PUSH32 | 3 | 0 | [] | +| 1180 | PUSH2 | 3 | 0 |[0xc0527f61023353606061023453600061023553608561023653605a6102375360] | +| 1183 | MSTORE | 7 | 0 |[0xc0527f61023353606061023453600061023553608561023653605a6102375360,0x3e0] | +| 1184 | PUSH32 | 3 | 0 | [] | +| 1217 | PUSH2 | 3 | 0 |[0xf261026102e05260386103005360536103015360606103025360506103035360] | +| 1220 | MSTORE | 6 | 0 |[0xf261026102e05260386103005360536103015360606103025360506103035360,0x400] | +| 1221 | PUSH32 | 3 | 0 | [] | +| 1254 | PUSH2 | 3 | 0 |[0x6161030453600261030553603961030653605361030753606061030853605061] | +| 1257 | MSTORE | 6 | 0 |[0x6161030453600261030553603961030653605361030753606061030853605061,0x420] | +| 1258 | PUSH32 | 3 | 0 | [] | +| 1291 | PUSH2 | 3 | 0 |[0x30953606161030a53600261030b53603a61030c53605361030d53606161030e] | +| 1294 | MSTORE | 6 | 0 |[0x30953606161030a53600261030b53603a61030c53605361030d53606161030e,0x440] | +| 1295 | PUSH32 | 3 | 0 | [] | +| 1328 | PUSH2 | 3 | 0 |[0x53600261030f53603b6103105360606103115360006103125360f36103135361] | +| 1331 | MSTORE | 6 | 0 |[0x53600261030f53603b6103105360606103115360006103125360f36103135361,0x460] | +| 1332 | PUSH1 | 3 | 0 | [] | +| 1334 | PUSH2 | 3 | 0 | [0x3] | +| 1337 | MSTORE8 | 6 | 0 |[0x3,0x480] | +| 1338 | PUSH1 | 3 | 0 | [] | +| 1340 | PUSH2 | 3 | 0 | [0x14] | +| 1343 | MSTORE8 | 3 | 0 |[0x14,0x481] | +| 1344 | PUSH1 | 3 | 0 | [] | +| 1346 | PUSH2 | 3 | 0 | [0x60] | +| 1349 | MSTORE8 | 3 | 0 |[0x60,0x482] | +| 1350 | PUSH1 | 3 | 0 | [] | +| 1352 | PUSH2 | 3 | 0 | [0x0] | +| 1355 | MSTORE8 | 3 | 0 |[0x0,0x483] | +| 1356 | PUSH1 | 3 | 0 | [] | +| 1358 | PUSH2 | 3 | 0 | [0x60] | +| 1361 | MSTORE8 | 3 | 0 |[0x60,0x484] | +| 1362 | PUSH1 | 3 | 0 | [] | +| 1364 | PUSH2 | 3 | 0 | [0x0] | +| 1367 | MSTORE8 | 3 | 0 |[0x0,0x485] | +| 1368 | PUSH1 | 3 | 0 | [] | +| 1370 | PUSH2 | 3 | 0 | [0xf0] | +| 1373 | MSTORE8 | 3 | 0 |[0xf0,0x486] | +| 1374 | PUSH1 | 3 | 0 | [] | +| 1376 | PUSH2 | 3 | 0 | [0x60] | +| 1379 | MSTORE8 | 3 | 0 |[0x60,0x487] | +| 1380 | PUSH1 | 3 | 0 | [] | +| 1382 | PUSH2 | 3 | 0 | [0x0] | +| 1385 | MSTORE8 | 3 | 0 |[0x0,0x488] | +| 1386 | PUSH1 | 3 | 0 | [] | +| 1388 | PUSH2 | 3 | 0 | [0x60] | +| 1391 | MSTORE8 | 3 | 0 |[0x60,0x489] | +| 1392 | PUSH1 | 3 | 0 | [] | +| 1394 | PUSH2 | 3 | 0 | [0x0] | +| 1397 | MSTORE8 | 3 | 0 |[0x0,0x48a] | +| 1398 | PUSH1 | 3 | 0 | [] | +| 1400 | PUSH2 | 3 | 0 | [0x60] | +| 1403 | MSTORE8 | 3 | 0 |[0x60,0x48b] | +| 1404 | PUSH1 | 3 | 0 | [] | +| 1406 | PUSH2 | 3 | 0 | [0x0] | +| 1409 | MSTORE8 | 3 | 0 |[0x0,0x48c] | +| 1410 | PUSH1 | 3 | 0 | [] | +| 1412 | PUSH2 | 3 | 0 | [0x60] | +| 1415 | MSTORE8 | 3 | 0 |[0x60,0x48d] | +| 1416 | PUSH1 | 3 | 0 | [] | +| 1418 | PUSH2 | 3 | 0 | [0x0] | +| 1421 | MSTORE8 | 3 | 0 |[0x0,0x48e] | +| 1422 | PUSH1 | 3 | 0 | [] | +| 1424 | PUSH2 | 3 | 0 | [0x84] | +| 1427 | MSTORE8 | 3 | 0 |[0x84,0x48f] | +| 1428 | PUSH1 | 3 | 0 | [] | +| 1430 | PUSH2 | 3 | 0 | [0x5a] | +| 1433 | MSTORE8 | 3 | 0 |[0x5a,0x490] | +| 1434 | PUSH1 | 3 | 0 | [] | +| 1436 | PUSH2 | 3 | 0 | [0xf4] | +| 1439 | MSTORE8 | 3 | 0 |[0xf4,0x491] | +| 1440 | PUSH1 | 3 | 0 | [] | +| 1442 | PUSH2 | 3 | 0 | [0x50] | +| 1445 | MSTORE8 | 3 | 0 |[0x50,0x492] | +| 1446 | PUSH1 | 3 | 0 | [] | +| 1448 | PUSH2 | 3 | 0 | [0x50] | +| 1451 | MSTORE8 | 3 | 0 |[0x50,0x493] | +| 1452 | PUSH2 | 3 | 0 | [] | +| 1455 | PUSH1 | 3 | 0 | [0x494] | +| 1457 | RETURN | 0 | 0 |[0x494,0x0] | +| 1773 | PUSH1 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26] | +| 1775 | PUSH1 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0] | +| 1777 | PUSH1 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0] | +| 1779 | PUSH1 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0,0x0] | +| 1781 | PUSH1 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0,0x0,0x0] | +| 1783 | DUP6 | 3 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0,0x0,0x0,0x0] | +| 1784 | GAS | 2 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0,0x0,0x0,0x0,0x94a843a7335fc63be036fbdecc40b1365f3c5f26] | +| 1785 | CALL | 22413 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0,0x0,0x0,0x0,0x0,0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x58ef] | +| 0 | PUSH1 | 3 | 0 | [] | +| 2 | PUSH1 | 3 | 0 | [0x1] | +| 4 | SSTORE | 20000 | 0 | [0x1,0x4] | +| 5 | PUSH1 | 3 | 0 | [] | +| 7 | PUSH1 | 3 | 0 | [0x0] | +| 9 | SSTORE | 100 | 19900 | [0x0,0x4] | +| 10 | PUSH1 | 3 | 19900 | [] | +| 12 | PUSH1 | 3 | 19900 | [0x0] | +| 14 | PUSH1 | 3 | 19900 | [0x0,0x0] | +| 16 | PUSH1 | 3 | 19900 |[0x0,0x0,0x0] | +| 18 | PUSH1 | 3 | 19900 |[0x0,0x0,0x0,0x0] | +| 20 | PUSH1 | 3 | 19900 |[0x0,0x0,0x0,0x0,0x0] | +| 22 | GAS | 2 | 19900 |[0x0,0x0,0x0,0x0,0x0,0xf9] | +| 23 | CALLCODE | 100 | 19900 |[0x0,0x0,0x0,0x0,0x0,0xf9,0x885] | +Error: out of gas: out of gas +| 1786 | POP | 2 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0] | +| 1787 | POP | 2 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26] | +| 1788 | STOP | 0 | 0 | [] | +| 2618 | POP | 2 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba,0x1] | +| 2619 | POP | 2 | 0 |[0x7dce2faf43218578e3fcf2ad22df9918a89e2fba] | +| 2620 | STOP | 0 | 0 | [] | + +Post-execution info: + - output: `` + - consumed gas: `732781` + - error: `` +{"stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458"} diff --git a/cmd/evm/testdata/evmrun/8.out.1.txt b/cmd/evm/testdata/evmrun/8.out.1.txt new file mode 100644 index 000000000..dc22c2ef3 --- /dev/null +++ b/cmd/evm/testdata/evmrun/8.out.1.txt @@ -0,0 +1,9 @@ +[ + { + "name": "00000006-naivefuzz-0", + "pass": false, + "stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458", + "fork": "London", + "error": "post state root mismatch: got ad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458, want 0000000000000000000000000000000000000000000000000000000000000000" + } +] diff --git a/cmd/evm/testdata/evmrun/8.out.2.txt b/cmd/evm/testdata/evmrun/8.out.2.txt new file mode 100644 index 000000000..3e6e162e2 --- /dev/null +++ b/cmd/evm/testdata/evmrun/8.out.2.txt @@ -0,0 +1,916 @@ +{"pc":0,"op":96,"gas":"0xb4213","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0xb4210","gasCost":"0x3","memSize":0,"stack":["0x2"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":85,"gas":"0xb420d","gasCost":"0x5654","memSize":0,"stack":["0x2","0x3"],"depth":1,"refund":0,"opName":"SSTORE"} +{"pc":5,"op":96,"gas":"0xaebb9","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":7,"op":96,"gas":"0xaebb6","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":9,"op":96,"gas":"0xaebb3","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":11,"op":96,"gas":"0xaebb0","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":13,"op":96,"gas":"0xaebad","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":15,"op":96,"gas":"0xaebaa","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":17,"op":90,"gas":"0xaeba7","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x4"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":18,"op":242,"gas":"0xaeba5","gasCost":"0xabff8","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0x4","0xaeba5"],"depth":1,"refund":0,"opName":"CALLCODE"} +{"output":"","gasUsed":"0xf"} +{"pc":19,"op":80,"gas":"0xaeb32","gasCost":"0x2","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"POP"} +{"pc":20,"op":127,"gas":"0xaeb30","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":53,"op":96,"gas":"0xaeb2d","gasCost":"0x3","memSize":0,"stack":["0x600254506003545060016003557f7f6008545060006004557f60016004556000"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":55,"op":82,"gas":"0xaeb2a","gasCost":"0x6","memSize":0,"stack":["0x600254506003545060016003557f7f6008545060006004557f60016004556000","0x0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":56,"op":127,"gas":"0xaeb24","gasCost":"0x3","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":89,"op":96,"gas":"0xaeb21","gasCost":"0x3","memSize":32,"stack":["0x60045560006000600060006000606000527ff96000527f5af250600060006000"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":91,"op":82,"gas":"0xaeb1e","gasCost":"0x6","memSize":32,"stack":["0x60045560006000600060006000606000527ff96000527f5af250600060006000","0x20"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":92,"op":127,"gas":"0xaeb18","gasCost":"0x3","memSize":64,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":125,"op":96,"gas":"0xaeb15","gasCost":"0x3","memSize":64,"stack":["0x606000527e60f45af45060006000600060006020527f600060f55a6020527ff1"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":127,"op":82,"gas":"0xaeb12","gasCost":"0x6","memSize":64,"stack":["0x606000527e60f45af45060006000600060006020527f600060f55a6020527ff1","0x40"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":128,"op":127,"gas":"0xaeb0c","gasCost":"0x3","memSize":96,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":161,"op":96,"gas":"0xaeb09","gasCost":"0x3","memSize":96,"stack":["0x50f001075205846a44a283446020527f8ca2600060006040527f600060006004"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":163,"op":82,"gas":"0xaeb06","gasCost":"0x6","memSize":96,"stack":["0x50f001075205846a44a283446020527f8ca2600060006040527f600060006004","0x60"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":164,"op":127,"gas":"0xaeb00","gasCost":"0x3","memSize":128,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":197,"op":96,"gas":"0xaeafd","gasCost":"0x3","memSize":128,"stack":["0x5af4506040527f519930847f3b631c54a49b5f600354503260406060527f527f"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":199,"op":82,"gas":"0xaeafa","gasCost":"0x6","memSize":128,"stack":["0x5af4506040527f519930847f3b631c54a49b5f600354503260406060527f527f","0x80"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":200,"op":127,"gas":"0xaeaf4","gasCost":"0x3","memSize":160,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":233,"op":96,"gas":"0xaeaf1","gasCost":"0x3","memSize":160,"stack":["0x77306b60006000600060006060527f6000600c5af15060006000600060006080"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":235,"op":82,"gas":"0xaeaee","gasCost":"0x6","memSize":160,"stack":["0x77306b60006000600060006060527f6000600c5af15060006000600060006080","0xa0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":236,"op":127,"gas":"0xaeae8","gasCost":"0x3","memSize":192,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":269,"op":96,"gas":"0xaeae5","gasCost":"0x3","memSize":192,"stack":["0x527f60f85af450506060527f066001600255606080527f035450600060005560"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":271,"op":82,"gas":"0xaeae2","gasCost":"0x6","memSize":192,"stack":["0x527f60f85af450506060527f066001600255606080527f035450600060005560","0xc0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":272,"op":126,"gas":"0xaeadc","gasCost":"0x3","memSize":224,"stack":[],"depth":1,"refund":0,"opName":"PUSH31"} +{"pc":304,"op":96,"gas":"0xaead9","gasCost":"0x3","memSize":224,"stack":["0x6060a0527f01556c3394fff4607f7f1684317b6080527f387b9f60a0527f19"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":306,"op":82,"gas":"0xaead6","gasCost":"0x6","memSize":224,"stack":["0x6060a0527f01556c3394fff4607f7f1684317b6080527f387b9f60a0527f19","0xe0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":307,"op":127,"gas":"0xaead0","gasCost":"0x3","memSize":256,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":340,"op":97,"gas":"0xaeacd","gasCost":"0x3","memSize":256,"stack":["0x20700184809d60c0527f60015450011899016e6009ff60026001556000527f9f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":343,"op":82,"gas":"0xaeaca","gasCost":"0x6","memSize":256,"stack":["0x20700184809d60c0527f60015450011899016e6009ff60026001556000527f9f","0x100"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":344,"op":127,"gas":"0xaeac4","gasCost":"0x3","memSize":288,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":377,"op":97,"gas":"0xaeac1","gasCost":"0x3","memSize":288,"stack":["0x60a05260c0527f7f600060e0527f527f9981600160045582600eff6000600060"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":380,"op":82,"gas":"0xaeabe","gasCost":"0x6","memSize":288,"stack":["0x60a05260c0527f7f600060e0527f527f9981600160045582600eff6000600060","0x120"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":381,"op":126,"gas":"0xaeab8","gasCost":"0x3","memSize":320,"stack":[],"depth":1,"refund":0,"opName":"PUSH31"} +{"pc":413,"op":97,"gas":"0xaeab5","gasCost":"0x3","memSize":320,"stack":["0x600060f65af45060006060e052610100527f7f6060c0527f20527e60006000"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":416,"op":82,"gas":"0xaeab2","gasCost":"0x6","memSize":320,"stack":["0x600060f65af45060006060e052610100527f7f6060c0527f20527e60006000","0x140"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":417,"op":127,"gas":"0xaeaac","gasCost":"0x3","memSize":352,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":450,"op":97,"gas":"0xaeaa9","gasCost":"0x3","memSize":352,"stack":["0x6020527f60f75af4501d7f1903166660006000610120527f60610100527e6000"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":453,"op":82,"gas":"0xaeaa6","gasCost":"0x6","memSize":352,"stack":["0x6020527f60f75af4501d7f1903166660006000610120527f60610100527e6000","0x160"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":454,"op":127,"gas":"0xaeaa0","gasCost":"0x3","memSize":384,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":487,"op":97,"gas":"0xaea9d","gasCost":"0x3","memSize":384,"stack":["0x600060e0527f60046040527f5af150600060006000604052610140527f7f6000"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":490,"op":82,"gas":"0xaea9a","gasCost":"0x6","memSize":384,"stack":["0x600060e0527f60046040527f5af150600060006000604052610140527f7f6000","0x180"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":491,"op":127,"gas":"0xaea94","gasCost":"0x3","memSize":416,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":524,"op":97,"gas":"0xaea91","gasCost":"0x3","memSize":416,"stack":["0x6009610120527f5af4503c95138e5b8f610100527f7f605a6000536060610160"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":527,"op":82,"gas":"0xaea8e","gasCost":"0x6","memSize":416,"stack":["0x6009610120527f5af4503c95138e5b8f610100527f7f605a6000536060610160","0x1a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":528,"op":127,"gas":"0xaea88","gasCost":"0x3","memSize":448,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":561,"op":97,"gas":"0xaea85","gasCost":"0x3","memSize":448,"stack":["0x527f527f6031600153606b60610140527f02536010606060527f035360456061"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":564,"op":82,"gas":"0xaea82","gasCost":"0x6","memSize":448,"stack":["0x527f527f6031600153606b60610140527f02536010606060527f035360456061","0x1c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":565,"op":127,"gas":"0xaea7c","gasCost":"0x3","memSize":480,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":598,"op":97,"gas":"0xaea79","gasCost":"0x3","memSize":480,"stack":["0x120610180527f527f04536060600553600160608052610160527f7e527f6006"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":601,"op":82,"gas":"0xaea76","gasCost":"0x6","memSize":480,"stack":["0x120610180527f527f04536060600553600160608052610160527f7e527f6006","0x1e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":602,"op":127,"gas":"0xaea70","gasCost":"0x3","memSize":512,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":635,"op":97,"gas":"0xaea6d","gasCost":"0x3","memSize":512,"stack":["0x536060600753606101a0527f02600853606080610140527f527f556009536060"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":638,"op":82,"gas":"0xaea6a","gasCost":"0x6","memSize":512,"stack":["0x536060600753606101a0527f02600853606080610140527f527f556009536060","0x200"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":639,"op":127,"gas":"0xaea64","gasCost":"0x3","memSize":544,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":672,"op":97,"gas":"0xaea61","gasCost":"0x3","memSize":544,"stack":["0x610180527f600a53600160a06101c0527f527f600b536060600c6020527f5360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":675,"op":82,"gas":"0xaea5e","gasCost":"0x6","memSize":544,"stack":["0x610180527f600a53600160a06101c0527f527f600b536060600c6020527f5360","0x220"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":676,"op":126,"gas":"0xaea58","gasCost":"0x3","memSize":576,"stack":[],"depth":1,"refund":0,"opName":"PUSH31"} +{"pc":708,"op":97,"gas":"0xaea55","gasCost":"0x3","memSize":576,"stack":["0x60610160527f0d53606101a0527f55606101e0527f0e60a0527f536060600f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":711,"op":82,"gas":"0xaea52","gasCost":"0x6","memSize":576,"stack":["0x60610160527f0d53606101a0527f55606101e0527f0e60a0527f536060600f","0x240"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":712,"op":127,"gas":"0xaea4c","gasCost":"0x3","memSize":608,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":745,"op":97,"gas":"0xaea49","gasCost":"0x3","memSize":608,"stack":["0x536060c0527f01601053606060115360026101806101610200527fc0527f527f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":748,"op":82,"gas":"0xaea46","gasCost":"0x6","memSize":608,"stack":["0x536060c0527f01601053606060115360026101806101610200527fc0527f527f","0x260"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":749,"op":127,"gas":"0xaea40","gasCost":"0x3","memSize":640,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":782,"op":97,"gas":"0xaea3d","gasCost":"0x3","memSize":640,"stack":["0x601253606040527f55601353606060c0527f60145360e0527f6000610220527f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":785,"op":82,"gas":"0xaea3a","gasCost":"0x6","memSize":640,"stack":["0x601253606040527f55601353606060c0527f60145360e0527f6000610220527f","0x280"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":786,"op":127,"gas":"0xaea34","gasCost":"0x3","memSize":672,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":819,"op":97,"gas":"0xaea31","gasCost":"0x3","memSize":672,"stack":["0x6015536101e0527f60606101a0527f601653600060175360f360185360196060"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":822,"op":82,"gas":"0xaea2e","gasCost":"0x6","memSize":672,"stack":["0x6015536101e0527f60606101a0527f601653600060175360f360185360196060","0x2a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":823,"op":127,"gas":"0xaea28","gasCost":"0x3","memSize":704,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":856,"op":97,"gas":"0xaea25","gasCost":"0x3","memSize":704,"stack":["0x610240527f605260006060e052610200527f610100527f7f806101c0527f5360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":859,"op":82,"gas":"0xaea22","gasCost":"0x7","memSize":704,"stack":["0x610240527f605260006060e052610200527f610100527f7f806101c0527f5360","0x2c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":860,"op":127,"gas":"0xaea1b","gasCost":"0x3","memSize":736,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":893,"op":97,"gas":"0xaea18","gasCost":"0x3","memSize":736,"stack":["0xf360815360610260527f8260006000f060006000600060610220527e845af450"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":896,"op":82,"gas":"0xaea15","gasCost":"0x6","memSize":736,"stack":["0xf360815360610260527f8260006000f060006000600060610220527e845af450","0x2e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":897,"op":127,"gas":"0xaea0f","gasCost":"0x3","memSize":768,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":930,"op":97,"gas":"0xaea0c","gasCost":"0x3","memSize":768,"stack":["0x506000600061016101e0610280527f527f20527f60610100527e600060006003"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":933,"op":82,"gas":"0xaea09","gasCost":"0x6","memSize":768,"stack":["0x506000600061016101e0610280527f527f20527f60610100527e600060006003","0x300"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":934,"op":127,"gas":"0xaea03","gasCost":"0x3","memSize":800,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":967,"op":97,"gas":"0xaea00","gasCost":"0x3","memSize":800,"stack":["0x610240527f5af15060005450c760006102a0527f6002551309f562610200527f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":970,"op":82,"gas":"0xae9fd","gasCost":"0x6","memSize":800,"stack":["0x610240527f5af15060005450c760006102a0527f6002551309f562610200527f","0x320"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":971,"op":127,"gas":"0xae9f7","gasCost":"0x3","memSize":832,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1004,"op":97,"gas":"0xae9f4","gasCost":"0x3","memSize":832,"stack":["0x66a486610140527f6b00610260527f1d457161016102c0527f20527f60005450"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1007,"op":82,"gas":"0xae9f1","gasCost":"0x6","memSize":832,"stack":["0x66a486610140527f6b00610260527f1d457161016102c0527f20527f60005450","0x340"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1008,"op":127,"gas":"0xae9eb","gasCost":"0x3","memSize":864,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1041,"op":97,"gas":"0xae9e8","gasCost":"0x3","memSize":864,"stack":["0x1c641d373c7f60045450610220527f6000600155610280527f6102e0527f6005"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1044,"op":82,"gas":"0xae9e5","gasCost":"0x6","memSize":864,"stack":["0x1c641d373c7f60045450610220527f6000600155610280527f6102e0527f6005","0x360"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1045,"op":127,"gas":"0xae9df","gasCost":"0x3","memSize":896,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1078,"op":97,"gas":"0xae9dc","gasCost":"0x3","memSize":896,"stack":["0x54610160527f50600160025560085450610140527f60006002610240527f6103"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1081,"op":82,"gas":"0xae9d9","gasCost":"0x6","memSize":896,"stack":["0x54610160527f50600160025560085450610140527f60006002610240527f6103","0x380"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1082,"op":126,"gas":"0xae9d3","gasCost":"0x3","memSize":928,"stack":[],"depth":1,"refund":0,"opName":"PUSH31"} +{"pc":1114,"op":97,"gas":"0xae9d0","gasCost":"0x3","memSize":928,"stack":["0x527f6102a0527f557fd86000606000527e600060610180527e600060005af1"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1117,"op":82,"gas":"0xae9cd","gasCost":"0x6","memSize":928,"stack":["0x527f6102a0527f557fd86000606000527e600060610180527e600060005af1","0x3a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1118,"op":127,"gas":"0xae9c7","gasCost":"0x3","memSize":960,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1151,"op":97,"gas":"0xae9c4","gasCost":"0x3","memSize":960,"stack":["0x508612610320527f17145147356102c0527f610260527f610160527f5198a37e"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1154,"op":82,"gas":"0xae9c1","gasCost":"0x6","memSize":960,"stack":["0x508612610320527f17145147356102c0527f610260527f610160527f5198a37e","0x3c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1155,"op":127,"gas":"0xae9bb","gasCost":"0x3","memSize":992,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1188,"op":97,"gas":"0xae9b8","gasCost":"0x3","memSize":992,"stack":["0x127a7efa7c600052610340527f6101a0527f606020527f6102e0527f60602053"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1191,"op":82,"gas":"0xae9b5","gasCost":"0x7","memSize":992,"stack":["0x127a7efa7c600052610340527f6101a0527f606020527f6102e0527f60602053","0x3e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1192,"op":127,"gas":"0xae9ae","gasCost":"0x3","memSize":1024,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1225,"op":97,"gas":"0xae9ab","gasCost":"0x3","memSize":1024,"stack":["0x60610280527ff760215360ff60610360527f225360610180527fdb6023536037"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1228,"op":82,"gas":"0xae9a8","gasCost":"0x6","memSize":1024,"stack":["0x60610280527ff760215360ff60610360527f225360610180527fdb6023536037","0x400"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1229,"op":127,"gas":"0xae9a2","gasCost":"0x3","memSize":1056,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1262,"op":97,"gas":"0xae99f","gasCost":"0x3","memSize":1056,"stack":["0x60610300527f6101c0527f24536075606102610380527fa0527f2553609f6060"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1265,"op":82,"gas":"0xae99c","gasCost":"0x6","memSize":1056,"stack":["0x60610300527f6101c0527f24536075606102610380527fa0527f2553609f6060","0x420"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1266,"op":127,"gas":"0xae996","gasCost":"0x3","memSize":1088,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1299,"op":97,"gas":"0xae993","gasCost":"0x3","memSize":1088,"stack":["0x40527f265360fe60275360610320527f8f60286101a0526103a0527f7f536061"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1302,"op":82,"gas":"0xae990","gasCost":"0x6","memSize":1088,"stack":["0x40527f265360fe60275360610320527f8f60286101a0526103a0527f7f536061","0x440"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1303,"op":127,"gas":"0xae98a","gasCost":"0x3","memSize":1120,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1336,"op":97,"gas":"0xae987","gasCost":"0x3","memSize":1120,"stack":["0x1e0527f6102c0527f0b6029536060602a53600060610340527f2b536103c052"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1339,"op":82,"gas":"0xae984","gasCost":"0x6","memSize":1120,"stack":["0x1e0527f6102c0527f0b6029536060602a53600060610340527f2b536103c052","0x460"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1340,"op":127,"gas":"0xae97e","gasCost":"0x3","memSize":1152,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1373,"op":97,"gas":"0xae97b","gasCost":"0x3","memSize":1152,"stack":["0x7f6060602c53606052606060805360006061016102e0527f610200527fc05261"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1376,"op":82,"gas":"0xae978","gasCost":"0x6","memSize":1152,"stack":["0x7f6060602c53606052606060805360006061016102e0527f610200527fc05261","0x480"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1377,"op":127,"gas":"0xae972","gasCost":"0x3","memSize":1184,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1410,"op":97,"gas":"0xae96f","gasCost":"0x3","memSize":1184,"stack":["0x36103e0527f60527f7f81536060608253602d60835360536084536060608553"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1413,"op":82,"gas":"0xae96c","gasCost":"0x6","memSize":1184,"stack":["0x36103e0527f60527f7f81536060608253602d60835360536084536060608553","0x4a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1414,"op":127,"gas":"0xae966","gasCost":"0x3","memSize":1216,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1447,"op":97,"gas":"0xae963","gasCost":"0x3","memSize":1216,"stack":["0x60fd61030052610400527f7f6086610380527f536060610220527f6087536101"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1450,"op":82,"gas":"0xae960","gasCost":"0x6","memSize":1216,"stack":["0x60fd61030052610400527f7f6086610380527f536060610220527f6087536101","0x4c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1451,"op":127,"gas":"0xae95a","gasCost":"0x3","memSize":1248,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1484,"op":97,"gas":"0xae957","gasCost":"0x3","memSize":1248,"stack":["0xe0527f602e608853605360610420527f89536060608a61036103a0527f20527f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1487,"op":82,"gas":"0xae954","gasCost":"0x7","memSize":1248,"stack":["0xe0527f602e608853605360610420527f89536060608a61036103a0527f20527f","0x4e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1488,"op":127,"gas":"0xae94d","gasCost":"0x3","memSize":1280,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1521,"op":97,"gas":"0xae94a","gasCost":"0x3","memSize":1280,"stack":["0x53602f608b536060608c610240527f53610440527f6000608d5360f361020052"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1524,"op":82,"gas":"0xae947","gasCost":"0x6","memSize":1280,"stack":["0x53602f608b536060608c610240527f53610440527f6000608d5360f361020052","0x500"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1525,"op":127,"gas":"0xae941","gasCost":"0x3","memSize":1312,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1558,"op":97,"gas":"0xae93e","gasCost":"0x3","memSize":1312,"stack":["0x60606103c0527f610220610340527f53608e610221610460527f536053610222"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1561,"op":82,"gas":"0xae93b","gasCost":"0x6","memSize":1312,"stack":["0x60606103c0527f610220610340527f53608e610221610460527f536053610222","0x520"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1562,"op":127,"gas":"0xae935","gasCost":"0x3","memSize":1344,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1595,"op":97,"gas":"0xae932","gasCost":"0x3","memSize":1344,"stack":["0x536060610260527f610223536103e0527f600061022453606061610480527f03"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1598,"op":82,"gas":"0xae92f","gasCost":"0x6","memSize":1344,"stack":["0x536060610260527f610223536103e0527f600061022453606061610480527f03","0x540"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1599,"op":127,"gas":"0xae929","gasCost":"0x3","memSize":1376,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1632,"op":97,"gas":"0xae926","gasCost":"0x3","memSize":1376,"stack":["0x60527f61022553608f61022653606061022753600061610400527f0261028061"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1635,"op":82,"gas":"0xae923","gasCost":"0x6","memSize":1376,"stack":["0x60527f61022553608f61022653606061022753600061610400527f0261028061","0x560"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1636,"op":127,"gas":"0xae91d","gasCost":"0x3","memSize":1408,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1669,"op":97,"gas":"0xae91a","gasCost":"0x3","memSize":1408,"stack":["0x4a0527f527f28536060610229610380527f53600061022a5360f561022b5360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1672,"op":82,"gas":"0xae917","gasCost":"0x6","memSize":1408,"stack":["0x4a0527f527f28536060610229610380527f53600061022a5360f561022b5360","0x580"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1673,"op":127,"gas":"0xae911","gasCost":"0x3","memSize":1440,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1706,"op":97,"gas":"0xae90e","gasCost":"0x3","memSize":1440,"stack":["0x610420526104c0527f7f6061022c53600061022d536102a0527f60606103a052"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1709,"op":82,"gas":"0xae90b","gasCost":"0x7","memSize":1440,"stack":["0x610420526104c0527f7f6061022c53600061022d536102a0527f60606103a052","0x5a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1710,"op":127,"gas":"0xae904","gasCost":"0x3","memSize":1472,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1743,"op":97,"gas":"0xae901","gasCost":"0x3","memSize":1472,"stack":["0x7f61022e53600061026104e0527f2f610440527f536060610230536000610231"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1746,"op":82,"gas":"0xae8fe","gasCost":"0x6","memSize":1472,"stack":["0x7f61022e53600061026104e0527f2f610440527f536060610230536000610231","0x5c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1747,"op":127,"gas":"0xae8f8","gasCost":"0x3","memSize":1504,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1780,"op":97,"gas":"0xae8f5","gasCost":"0x3","memSize":1504,"stack":["0x53606061023253600061026103c0610500527f527fc0527f61610460527f0233"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1783,"op":82,"gas":"0xae8f2","gasCost":"0x6","memSize":1504,"stack":["0x53606061023253600061026103c0610500527f527fc0527f61610460527f0233","0x5e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1784,"op":127,"gas":"0xae8ec","gasCost":"0x3","memSize":1536,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1817,"op":97,"gas":"0xae8e9","gasCost":"0x3","memSize":1536,"stack":["0x53606061023453600061023553608561023653610520527f605a610237536061"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1820,"op":82,"gas":"0xae8e6","gasCost":"0x6","memSize":1536,"stack":["0x53606061023453600061023553608561023653610520527f605a610237536061","0x600"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1821,"op":127,"gas":"0xae8e0","gasCost":"0x3","memSize":1568,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1854,"op":97,"gas":"0xae8dd","gasCost":"0x3","memSize":1568,"stack":["0x3e052610480527f7ff261026102e0526038610300536053610540527f610301"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1857,"op":82,"gas":"0xae8da","gasCost":"0x6","memSize":1568,"stack":["0x3e052610480527f7ff261026102e0526038610300536053610540527f610301","0x620"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1858,"op":127,"gas":"0xae8d4","gasCost":"0x3","memSize":1600,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1891,"op":97,"gas":"0xae8d1","gasCost":"0x3","memSize":1600,"stack":["0x536060610302536050610303536104a0527f60610400527f6161030453610560"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1894,"op":82,"gas":"0xae8ce","gasCost":"0x7","memSize":1600,"stack":["0x536060610302536050610303536104a0527f60610400527f6161030453610560","0x640"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1895,"op":127,"gas":"0xae8c7","gasCost":"0x3","memSize":1632,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1928,"op":97,"gas":"0xae8c4","gasCost":"0x3","memSize":1632,"stack":["0x527f6002610305536039610306536053610307536060616104c0527f03085360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1931,"op":82,"gas":"0xae8c1","gasCost":"0x6","memSize":1632,"stack":["0x527f6002610305536039610306536053610307536060616104c0527f03085360","0x660"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1932,"op":127,"gas":"0xae8bb","gasCost":"0x3","memSize":1664,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":1965,"op":97,"gas":"0xae8b8","gasCost":"0x3","memSize":1664,"stack":["0x5061610580527f610420527f030953606161030a53600261030b53603a61030c"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":1968,"op":82,"gas":"0xae8b5","gasCost":"0x6","memSize":1664,"stack":["0x5061610580527f610420527f030953606161030a53600261030b53603a61030c","0x680"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":1969,"op":127,"gas":"0xae8af","gasCost":"0x3","memSize":1696,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2002,"op":97,"gas":"0xae8ac","gasCost":"0x3","memSize":1696,"stack":["0x536104e0527f606105a0527f5361030d53606161030e610440527f5360026103"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2005,"op":82,"gas":"0xae8a9","gasCost":"0x6","memSize":1696,"stack":["0x536104e0527f606105a0527f5361030d53606161030e610440527f5360026103","0x6a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2006,"op":127,"gas":"0xae8a3","gasCost":"0x3","memSize":1728,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2039,"op":97,"gas":"0xae8a0","gasCost":"0x3","memSize":1728,"stack":["0xf53603b61031053606061616105c0527f0500527f03115360006103125360f3"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2042,"op":82,"gas":"0xae89d","gasCost":"0x6","memSize":1728,"stack":["0xf53603b61031053606061616105c0527f0500527f03115360006103125360f3","0x6c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2043,"op":127,"gas":"0xae897","gasCost":"0x3","memSize":1760,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2076,"op":97,"gas":"0xae894","gasCost":"0x3","memSize":1760,"stack":["0x61031353616104605260036104805360146105e0527f61048153610520527f60"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2079,"op":82,"gas":"0xae891","gasCost":"0x7","memSize":1760,"stack":["0x61031353616104605260036104805360146105e0527f61048153610520527f60","0x6e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2080,"op":127,"gas":"0xae88a","gasCost":"0x3","memSize":1792,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2113,"op":97,"gas":"0xae887","gasCost":"0x3","memSize":1792,"stack":["0x60610482536000610483536060610484536000610485610600527f5360f06104"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2116,"op":82,"gas":"0xae884","gasCost":"0x6","memSize":1792,"stack":["0x60610482536000610483536060610484536000610485610600527f5360f06104","0x700"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2117,"op":127,"gas":"0xae87e","gasCost":"0x3","memSize":1824,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2150,"op":97,"gas":"0xae87b","gasCost":"0x3","memSize":1824,"stack":["0x86536060610540527f610487536000610488536060610489536000610620527f"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2153,"op":82,"gas":"0xae878","gasCost":"0x6","memSize":1824,"stack":["0x86536060610540527f610487536000610488536060610489536000610620527f","0x720"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2154,"op":127,"gas":"0xae872","gasCost":"0x3","memSize":1856,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2187,"op":97,"gas":"0xae86f","gasCost":"0x3","memSize":1856,"stack":["0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2190,"op":82,"gas":"0xae86c","gasCost":"0x6","memSize":1856,"stack":["0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e","0x740"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2191,"op":127,"gas":"0xae866","gasCost":"0x3","memSize":1888,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2224,"op":97,"gas":"0xae863","gasCost":"0x3","memSize":1888,"stack":["0x610640527f53608461048f53605a6104905360f4610491536105805260606105"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2227,"op":82,"gas":"0xae860","gasCost":"0x7","memSize":1888,"stack":["0x610640527f53608461048f53605a6104905360f4610491536105805260606105","0x760"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2228,"op":127,"gas":"0xae859","gasCost":"0x3","memSize":1920,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2261,"op":97,"gas":"0xae856","gasCost":"0x3","memSize":1920,"stack":["0xa053605061610660527f05a15360616105a25360046105a35360926105a45360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2264,"op":82,"gas":"0xae853","gasCost":"0x6","memSize":1920,"stack":["0xa053605061610660527f05a15360616105a25360046105a35360926105a45360","0x780"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2265,"op":127,"gas":"0xae84d","gasCost":"0x3","memSize":1952,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2298,"op":97,"gas":"0xae84a","gasCost":"0x3","memSize":1952,"stack":["0x536105a55360606105a6610680527f5360506105a75360616105a85360046105"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2301,"op":82,"gas":"0xae847","gasCost":"0x6","memSize":1952,"stack":["0x536105a55360606105a6610680527f5360506105a75360616105a85360046105","0x7a0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2302,"op":127,"gas":"0xae841","gasCost":"0x3","memSize":1984,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2335,"op":97,"gas":"0xae83e","gasCost":"0x3","memSize":1984,"stack":["0xa95360936105aa5360536105ab53606106a0527f616105ac5360046105ad5360"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2338,"op":82,"gas":"0xae83b","gasCost":"0x6","memSize":1984,"stack":["0xa95360936105aa5360536105ab53606106a0527f616105ac5360046105ad5360","0x7c0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2339,"op":127,"gas":"0xae835","gasCost":"0x3","memSize":2016,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2372,"op":97,"gas":"0xae832","gasCost":"0x3","memSize":2016,"stack":["0x946105ae5360606105af5360006105b05360f3616106c05260056106e05360b1"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2375,"op":82,"gas":"0xae82f","gasCost":"0x7","memSize":2016,"stack":["0x946105ae5360606105af5360006105b05360f3616106c05260056106e05360b1","0x7e0"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2376,"op":127,"gas":"0xae828","gasCost":"0x3","memSize":2048,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2409,"op":97,"gas":"0xae825","gasCost":"0x3","memSize":2048,"stack":["0x6106e15360536106e25360606106e35360006106e45360616106e55360056106"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2412,"op":82,"gas":"0xae822","gasCost":"0x6","memSize":2048,"stack":["0x6106e15360536106e25360606106e35360006106e45360616106e55360056106","0x800"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2413,"op":127,"gas":"0xae81c","gasCost":"0x3","memSize":2080,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2446,"op":97,"gas":"0xae819","gasCost":"0x3","memSize":2080,"stack":["0xe65360b26106e75360606106e85360006106e95360606106ea5360006106eb53"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2449,"op":82,"gas":"0xae816","gasCost":"0x6","memSize":2080,"stack":["0xe65360b26106e75360606106e85360006106e95360606106ea5360006106eb53","0x820"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2450,"op":127,"gas":"0xae810","gasCost":"0x3","memSize":2112,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2483,"op":97,"gas":"0xae80d","gasCost":"0x3","memSize":2112,"stack":["0x60f56106ec5360606106ed5360006106ee5360606106ef5360006106f0536060"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2486,"op":82,"gas":"0xae80a","gasCost":"0x6","memSize":2112,"stack":["0x60f56106ec5360606106ed5360006106ee5360606106ef5360006106f0536060","0x840"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2487,"op":127,"gas":"0xae804","gasCost":"0x3","memSize":2144,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2520,"op":97,"gas":"0xae801","gasCost":"0x3","memSize":2144,"stack":["0x6106f15360006106f25360606106f35360006106f45360606106f55360006106"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2523,"op":82,"gas":"0xae7fe","gasCost":"0x7","memSize":2144,"stack":["0x6106f15360006106f25360606106f35360006106f45360606106f55360006106","0x860"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2524,"op":127,"gas":"0xae7f7","gasCost":"0x3","memSize":2176,"stack":[],"depth":1,"refund":0,"opName":"PUSH32"} +{"pc":2557,"op":97,"gas":"0xae7f4","gasCost":"0x3","memSize":2176,"stack":["0xf65360856106f753605a6106f85360f16106f95360506106fa5360506106fb53"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2560,"op":82,"gas":"0xae7f1","gasCost":"0x6","memSize":2176,"stack":["0xf65360856106f753605a6106f85360f16106f95360506106fa5360506106fb53","0x880"],"depth":1,"refund":0,"opName":"MSTORE"} +{"pc":2561,"op":96,"gas":"0xae7eb","gasCost":"0x3","memSize":2208,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2563,"op":97,"gas":"0xae7e8","gasCost":"0x3","memSize":2208,"stack":["0x61"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2566,"op":83,"gas":"0xae7e5","gasCost":"0x6","memSize":2208,"stack":["0x61","0x8a0"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2567,"op":96,"gas":"0xae7df","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2569,"op":97,"gas":"0xae7dc","gasCost":"0x3","memSize":2240,"stack":["0x6"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2572,"op":83,"gas":"0xae7d9","gasCost":"0x3","memSize":2240,"stack":["0x6","0x8a1"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2573,"op":96,"gas":"0xae7d6","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2575,"op":97,"gas":"0xae7d3","gasCost":"0x3","memSize":2240,"stack":["0xfc"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2578,"op":83,"gas":"0xae7d0","gasCost":"0x3","memSize":2240,"stack":["0xfc","0x8a2"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2579,"op":96,"gas":"0xae7cd","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2581,"op":97,"gas":"0xae7ca","gasCost":"0x3","memSize":2240,"stack":["0x60"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2584,"op":83,"gas":"0xae7c7","gasCost":"0x3","memSize":2240,"stack":["0x60","0x8a3"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2585,"op":96,"gas":"0xae7c4","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2587,"op":97,"gas":"0xae7c1","gasCost":"0x3","memSize":2240,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2590,"op":83,"gas":"0xae7be","gasCost":"0x3","memSize":2240,"stack":["0x0","0x8a4"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2591,"op":96,"gas":"0xae7bb","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2593,"op":97,"gas":"0xae7b8","gasCost":"0x3","memSize":2240,"stack":["0xf3"],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2596,"op":83,"gas":"0xae7b5","gasCost":"0x3","memSize":2240,"stack":["0xf3","0x8a5"],"depth":1,"refund":0,"opName":"MSTORE8"} +{"pc":2597,"op":97,"gas":"0xae7b2","gasCost":"0x3","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":2600,"op":96,"gas":"0xae7af","gasCost":"0x3","memSize":2240,"stack":["0x8a6"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2602,"op":96,"gas":"0xae7ac","gasCost":"0x3","memSize":2240,"stack":["0x8a6","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2604,"op":240,"gas":"0xae7a9","gasCost":"0x7d00","memSize":2240,"stack":["0x8a6","0x0","0x0"],"depth":1,"refund":0,"opName":"CREATE"} +{"pc":0,"op":96,"gas":"0xa40ff","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":84,"gas":"0xa40fc","gasCost":"0x834","memSize":0,"stack":["0x2"],"depth":2,"refund":0,"opName":"SLOAD"} +{"pc":3,"op":80,"gas":"0xa38c8","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":2,"refund":0,"opName":"POP"} +{"pc":4,"op":96,"gas":"0xa38c6","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":84,"gas":"0xa38c3","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":2,"refund":0,"opName":"SLOAD"} +{"pc":7,"op":80,"gas":"0xa308f","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":2,"refund":0,"opName":"POP"} +{"pc":8,"op":96,"gas":"0xa308d","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":10,"op":96,"gas":"0xa308a","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":12,"op":85,"gas":"0xa3087","gasCost":"0x4e20","memSize":0,"stack":["0x1","0x3"],"depth":2,"refund":0,"opName":"SSTORE"} +{"pc":13,"op":127,"gas":"0x9e267","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":46,"op":96,"gas":"0x9e264","gasCost":"0x3","memSize":0,"stack":["0x7f6008545060006004557f600160045560006004556000600060006000600060"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":48,"op":82,"gas":"0x9e261","gasCost":"0x6","memSize":0,"stack":["0x7f6008545060006004557f600160045560006004556000600060006000600060","0x0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":49,"op":127,"gas":"0x9e25b","gasCost":"0x3","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":82,"op":96,"gas":"0x9e258","gasCost":"0x3","memSize":32,"stack":["0xf96000527f5af250600060006000606000527e60f45af4506000600060006000"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":84,"op":82,"gas":"0x9e255","gasCost":"0x6","memSize":32,"stack":["0xf96000527f5af250600060006000606000527e60f45af4506000600060006000","0x20"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":85,"op":127,"gas":"0x9e24f","gasCost":"0x3","memSize":64,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":118,"op":96,"gas":"0x9e24c","gasCost":"0x3","memSize":64,"stack":["0x600060f55a6020527ff150f001075205846a44a283446020527f8ca260006000"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":120,"op":82,"gas":"0x9e249","gasCost":"0x6","memSize":64,"stack":["0x600060f55a6020527ff150f001075205846a44a283446020527f8ca260006000","0x40"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":121,"op":127,"gas":"0x9e243","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":154,"op":96,"gas":"0x9e240","gasCost":"0x3","memSize":96,"stack":["0x6000600060045af4506040527f519930847f3b631c54a49b5f60035450326040"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":156,"op":82,"gas":"0x9e23d","gasCost":"0x6","memSize":96,"stack":["0x6000600060045af4506040527f519930847f3b631c54a49b5f60035450326040","0x60"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":157,"op":127,"gas":"0x9e237","gasCost":"0x3","memSize":128,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":190,"op":96,"gas":"0x9e234","gasCost":"0x3","memSize":128,"stack":["0x527f77306b60006000600060006060527f6000600c5af1506000600060006000"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":192,"op":82,"gas":"0x9e231","gasCost":"0x6","memSize":128,"stack":["0x527f77306b60006000600060006060527f6000600c5af1506000600060006000","0x80"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":193,"op":127,"gas":"0x9e22b","gasCost":"0x3","memSize":160,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":226,"op":96,"gas":"0x9e228","gasCost":"0x3","memSize":160,"stack":["0x60f85af450506060527f066001600255606080527f0354506000600055600060"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":228,"op":82,"gas":"0x9e225","gasCost":"0x6","memSize":160,"stack":["0x60f85af450506060527f066001600255606080527f0354506000600055600060","0xa0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":229,"op":127,"gas":"0x9e21f","gasCost":"0x3","memSize":192,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":262,"op":96,"gas":"0x9e21c","gasCost":"0x3","memSize":192,"stack":["0x1556c3394fff4607f7f1684317b6080527f387b9f60a0527f1920700184809d"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":264,"op":82,"gas":"0x9e219","gasCost":"0x6","memSize":192,"stack":["0x1556c3394fff4607f7f1684317b6080527f387b9f60a0527f1920700184809d","0xc0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":265,"op":127,"gas":"0x9e213","gasCost":"0x3","memSize":224,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":298,"op":96,"gas":"0x9e210","gasCost":"0x3","memSize":224,"stack":["0x60015450011899016e6009ff60026001556000527f9f60a05260c0527f7f6000"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":300,"op":82,"gas":"0x9e20d","gasCost":"0x6","memSize":224,"stack":["0x60015450011899016e6009ff60026001556000527f9f60a05260c0527f7f6000","0xe0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":301,"op":127,"gas":"0x9e207","gasCost":"0x3","memSize":256,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":334,"op":97,"gas":"0x9e204","gasCost":"0x3","memSize":256,"stack":["0x527f9981600160045582600eff600060006000600060f65af45060006060e052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":337,"op":82,"gas":"0x9e201","gasCost":"0x6","memSize":256,"stack":["0x527f9981600160045582600eff600060006000600060f65af45060006060e052","0x100"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":338,"op":127,"gas":"0x9e1fb","gasCost":"0x3","memSize":288,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":371,"op":97,"gas":"0x9e1f8","gasCost":"0x3","memSize":288,"stack":["0x7f6060c0527f20527e600060006020527f60f75af4501d7f1903166660006000"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":374,"op":82,"gas":"0x9e1f5","gasCost":"0x6","memSize":288,"stack":["0x7f6060c0527f20527e600060006020527f60f75af4501d7f1903166660006000","0x120"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":375,"op":127,"gas":"0x9e1ef","gasCost":"0x3","memSize":320,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":408,"op":97,"gas":"0x9e1ec","gasCost":"0x3","memSize":320,"stack":["0x60610100527e6000600060e0527f60046040527f5af150600060006000604052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":411,"op":82,"gas":"0x9e1e9","gasCost":"0x6","memSize":320,"stack":["0x60610100527e6000600060e0527f60046040527f5af150600060006000604052","0x140"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":412,"op":127,"gas":"0x9e1e3","gasCost":"0x3","memSize":352,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":445,"op":97,"gas":"0x9e1e0","gasCost":"0x3","memSize":352,"stack":["0x7f60006009610120527f5af4503c95138e5b8f610100527f7f605a6000536060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":448,"op":82,"gas":"0x9e1dd","gasCost":"0x6","memSize":352,"stack":["0x7f60006009610120527f5af4503c95138e5b8f610100527f7f605a6000536060","0x160"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":449,"op":127,"gas":"0x9e1d7","gasCost":"0x3","memSize":384,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":482,"op":97,"gas":"0x9e1d4","gasCost":"0x3","memSize":384,"stack":["0x527f6031600153606b60610140527f02536010606060527f0353604560610120"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":485,"op":82,"gas":"0x9e1d1","gasCost":"0x6","memSize":384,"stack":["0x527f6031600153606b60610140527f02536010606060527f0353604560610120","0x180"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":486,"op":127,"gas":"0x9e1cb","gasCost":"0x3","memSize":416,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":519,"op":97,"gas":"0x9e1c8","gasCost":"0x3","memSize":416,"stack":["0x527f04536060600553600160608052610160527f7e527f600653606060075360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":522,"op":82,"gas":"0x9e1c5","gasCost":"0x6","memSize":416,"stack":["0x527f04536060600553600160608052610160527f7e527f600653606060075360","0x1a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":523,"op":127,"gas":"0x9e1bf","gasCost":"0x3","memSize":448,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":556,"op":97,"gas":"0x9e1bc","gasCost":"0x3","memSize":448,"stack":["0x2600853606080610140527f527f556009536060610180527f600a53600160a0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":559,"op":82,"gas":"0x9e1b9","gasCost":"0x6","memSize":448,"stack":["0x2600853606080610140527f527f556009536060610180527f600a53600160a0","0x1c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":560,"op":127,"gas":"0x9e1b3","gasCost":"0x3","memSize":480,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":593,"op":97,"gas":"0x9e1b0","gasCost":"0x3","memSize":480,"stack":["0x527f600b536060600c6020527f53600060610160527f0d53606101a0527f5560"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":596,"op":82,"gas":"0x9e1ad","gasCost":"0x6","memSize":480,"stack":["0x527f600b536060600c6020527f53600060610160527f0d53606101a0527f5560","0x1e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":597,"op":127,"gas":"0x9e1a7","gasCost":"0x3","memSize":512,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":630,"op":97,"gas":"0x9e1a4","gasCost":"0x3","memSize":512,"stack":["0xe60a0527f536060600f536060c0527f01601053606060115360026101806101"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":633,"op":82,"gas":"0x9e1a1","gasCost":"0x6","memSize":512,"stack":["0xe60a0527f536060600f536060c0527f01601053606060115360026101806101","0x200"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":634,"op":127,"gas":"0x9e19b","gasCost":"0x3","memSize":544,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":667,"op":97,"gas":"0x9e198","gasCost":"0x3","memSize":544,"stack":["0xc0527f527f601253606040527f55601353606060c0527f60145360e0527f6000"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":670,"op":82,"gas":"0x9e195","gasCost":"0x6","memSize":544,"stack":["0xc0527f527f601253606040527f55601353606060c0527f60145360e0527f6000","0x220"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":671,"op":127,"gas":"0x9e18f","gasCost":"0x3","memSize":576,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":704,"op":97,"gas":"0x9e18c","gasCost":"0x3","memSize":576,"stack":["0x6015536101e0527f60606101a0527f601653600060175360f360185360196060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":707,"op":82,"gas":"0x9e189","gasCost":"0x6","memSize":576,"stack":["0x6015536101e0527f60606101a0527f601653600060175360f360185360196060","0x240"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":708,"op":127,"gas":"0x9e183","gasCost":"0x3","memSize":608,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":741,"op":97,"gas":"0x9e180","gasCost":"0x3","memSize":608,"stack":["0x605260006060e052610200527f610100527f7f806101c0527f5360f360815360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":744,"op":82,"gas":"0x9e17d","gasCost":"0x6","memSize":608,"stack":["0x605260006060e052610200527f610100527f7f806101c0527f5360f360815360","0x260"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":745,"op":127,"gas":"0x9e177","gasCost":"0x3","memSize":640,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":778,"op":97,"gas":"0x9e174","gasCost":"0x3","memSize":640,"stack":["0x8260006000f060006000600060610220527e845af450506000600061016101e0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":781,"op":82,"gas":"0x9e171","gasCost":"0x6","memSize":640,"stack":["0x8260006000f060006000600060610220527e845af450506000600061016101e0","0x280"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":782,"op":127,"gas":"0x9e16b","gasCost":"0x3","memSize":672,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":815,"op":97,"gas":"0x9e168","gasCost":"0x3","memSize":672,"stack":["0x527f20527f60610100527e600060006003610240527f5af15060005450c76000"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":818,"op":82,"gas":"0x9e165","gasCost":"0x6","memSize":672,"stack":["0x527f20527f60610100527e600060006003610240527f5af15060005450c76000","0x2a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":819,"op":127,"gas":"0x9e15f","gasCost":"0x3","memSize":704,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":852,"op":97,"gas":"0x9e15c","gasCost":"0x3","memSize":704,"stack":["0x6002551309f562610200527f66a486610140527f6b00610260527f1d45716101"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":855,"op":82,"gas":"0x9e159","gasCost":"0x7","memSize":704,"stack":["0x6002551309f562610200527f66a486610140527f6b00610260527f1d45716101","0x2c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":856,"op":127,"gas":"0x9e152","gasCost":"0x3","memSize":736,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":889,"op":97,"gas":"0x9e14f","gasCost":"0x3","memSize":736,"stack":["0x20527f600054501c641d373c7f60045450610220527f6000600155610280527f"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":892,"op":82,"gas":"0x9e14c","gasCost":"0x6","memSize":736,"stack":["0x20527f600054501c641d373c7f60045450610220527f6000600155610280527f","0x2e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":893,"op":127,"gas":"0x9e146","gasCost":"0x3","memSize":768,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":926,"op":97,"gas":"0x9e143","gasCost":"0x3","memSize":768,"stack":["0x600554610160527f50600160025560085450610140527f60006002610240527f"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":929,"op":82,"gas":"0x9e140","gasCost":"0x6","memSize":768,"stack":["0x600554610160527f50600160025560085450610140527f60006002610240527f","0x300"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":930,"op":127,"gas":"0x9e13a","gasCost":"0x3","memSize":800,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":963,"op":97,"gas":"0x9e137","gasCost":"0x3","memSize":800,"stack":["0x6102a0527f557fd86000606000527e600060610180527e600060005af1508612"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":966,"op":82,"gas":"0x9e134","gasCost":"0x6","memSize":800,"stack":["0x6102a0527f557fd86000606000527e600060610180527e600060005af1508612","0x320"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":967,"op":127,"gas":"0x9e12e","gasCost":"0x3","memSize":832,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1000,"op":97,"gas":"0x9e12b","gasCost":"0x3","memSize":832,"stack":["0x17145147356102c0527f610260527f610160527f5198a37e127a7efa7c600052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1003,"op":82,"gas":"0x9e128","gasCost":"0x6","memSize":832,"stack":["0x17145147356102c0527f610260527f610160527f5198a37e127a7efa7c600052","0x340"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1004,"op":127,"gas":"0x9e122","gasCost":"0x3","memSize":864,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1037,"op":97,"gas":"0x9e11f","gasCost":"0x3","memSize":864,"stack":["0x6101a0527f606020527f6102e0527f6060205360610280527ff760215360ff60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1040,"op":82,"gas":"0x9e11c","gasCost":"0x6","memSize":864,"stack":["0x6101a0527f606020527f6102e0527f6060205360610280527ff760215360ff60","0x360"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1041,"op":127,"gas":"0x9e116","gasCost":"0x3","memSize":896,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1074,"op":97,"gas":"0x9e113","gasCost":"0x3","memSize":896,"stack":["0x225360610180527fdb602353603760610300527f6101c0527f24536075606102"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1077,"op":82,"gas":"0x9e110","gasCost":"0x6","memSize":896,"stack":["0x225360610180527fdb602353603760610300527f6101c0527f24536075606102","0x380"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1078,"op":127,"gas":"0x9e10a","gasCost":"0x3","memSize":928,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1111,"op":97,"gas":"0x9e107","gasCost":"0x3","memSize":928,"stack":["0xa0527f2553609f606040527f265360fe60275360610320527f8f60286101a052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1114,"op":82,"gas":"0x9e104","gasCost":"0x6","memSize":928,"stack":["0xa0527f2553609f606040527f265360fe60275360610320527f8f60286101a052","0x3a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1115,"op":127,"gas":"0x9e0fe","gasCost":"0x3","memSize":960,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1148,"op":97,"gas":"0x9e0fb","gasCost":"0x3","memSize":960,"stack":["0x7f53606101e0527f6102c0527f0b6029536060602a53600060610340527f2b53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1151,"op":82,"gas":"0x9e0f8","gasCost":"0x6","memSize":960,"stack":["0x7f53606101e0527f6102c0527f0b6029536060602a53600060610340527f2b53","0x3c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1152,"op":127,"gas":"0x9e0f2","gasCost":"0x3","memSize":992,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1185,"op":97,"gas":"0x9e0ef","gasCost":"0x3","memSize":992,"stack":["0x6060602c53606052606060805360006061016102e0527f610200527fc0526103"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1188,"op":82,"gas":"0x9e0ec","gasCost":"0x7","memSize":992,"stack":["0x6060602c53606052606060805360006061016102e0527f610200527fc0526103","0x3e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1189,"op":127,"gas":"0x9e0e5","gasCost":"0x3","memSize":1024,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1222,"op":97,"gas":"0x9e0e2","gasCost":"0x3","memSize":1024,"stack":["0x60527f7f81536060608253602d6083536053608453606060855360fd61030052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1225,"op":82,"gas":"0x9e0df","gasCost":"0x6","memSize":1024,"stack":["0x60527f7f81536060608253602d6083536053608453606060855360fd61030052","0x400"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1226,"op":127,"gas":"0x9e0d9","gasCost":"0x3","memSize":1056,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1259,"op":97,"gas":"0x9e0d6","gasCost":"0x3","memSize":1056,"stack":["0x7f6086610380527f536060610220527f6087536101e0527f602e608853605360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1262,"op":82,"gas":"0x9e0d3","gasCost":"0x6","memSize":1056,"stack":["0x7f6086610380527f536060610220527f6087536101e0527f602e608853605360","0x420"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1263,"op":127,"gas":"0x9e0cd","gasCost":"0x3","memSize":1088,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1296,"op":97,"gas":"0x9e0ca","gasCost":"0x3","memSize":1088,"stack":["0x89536060608a61036103a0527f20527f53602f608b536060608c610240527f53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1299,"op":82,"gas":"0x9e0c7","gasCost":"0x6","memSize":1088,"stack":["0x89536060608a61036103a0527f20527f53602f608b536060608c610240527f53","0x440"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1300,"op":127,"gas":"0x9e0c1","gasCost":"0x3","memSize":1120,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1333,"op":97,"gas":"0x9e0be","gasCost":"0x3","memSize":1120,"stack":["0x6000608d5360f36102005260606103c0527f610220610340527f53608e610221"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1336,"op":82,"gas":"0x9e0bb","gasCost":"0x6","memSize":1120,"stack":["0x6000608d5360f36102005260606103c0527f610220610340527f53608e610221","0x460"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1337,"op":127,"gas":"0x9e0b5","gasCost":"0x3","memSize":1152,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1370,"op":97,"gas":"0x9e0b2","gasCost":"0x3","memSize":1152,"stack":["0x536053610222536060610260527f610223536103e0527f600061022453606061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1373,"op":82,"gas":"0x9e0af","gasCost":"0x6","memSize":1152,"stack":["0x536053610222536060610260527f610223536103e0527f600061022453606061","0x480"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1374,"op":127,"gas":"0x9e0a9","gasCost":"0x3","memSize":1184,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1407,"op":97,"gas":"0x9e0a6","gasCost":"0x3","memSize":1184,"stack":["0x360527f61022553608f61022653606061022753600061610400527f02610280"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1410,"op":82,"gas":"0x9e0a3","gasCost":"0x6","memSize":1184,"stack":["0x360527f61022553608f61022653606061022753600061610400527f02610280","0x4a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1411,"op":127,"gas":"0x9e09d","gasCost":"0x3","memSize":1216,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1444,"op":97,"gas":"0x9e09a","gasCost":"0x3","memSize":1216,"stack":["0x527f28536060610229610380527f53600061022a5360f561022b536061042052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1447,"op":82,"gas":"0x9e097","gasCost":"0x6","memSize":1216,"stack":["0x527f28536060610229610380527f53600061022a5360f561022b536061042052","0x4c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1448,"op":127,"gas":"0x9e091","gasCost":"0x3","memSize":1248,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1481,"op":97,"gas":"0x9e08e","gasCost":"0x3","memSize":1248,"stack":["0x7f6061022c53600061022d536102a0527f60606103a0527f61022e5360006102"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1484,"op":82,"gas":"0x9e08b","gasCost":"0x7","memSize":1248,"stack":["0x7f6061022c53600061022d536102a0527f60606103a0527f61022e5360006102","0x4e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1485,"op":127,"gas":"0x9e084","gasCost":"0x3","memSize":1280,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1518,"op":97,"gas":"0x9e081","gasCost":"0x3","memSize":1280,"stack":["0x2f610440527f53606061023053600061023153606061023253600061026103c0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1521,"op":82,"gas":"0x9e07e","gasCost":"0x6","memSize":1280,"stack":["0x2f610440527f53606061023053600061023153606061023253600061026103c0","0x500"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1522,"op":127,"gas":"0x9e078","gasCost":"0x3","memSize":1312,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1555,"op":97,"gas":"0x9e075","gasCost":"0x3","memSize":1312,"stack":["0x527fc0527f61610460527f023353606061023453600061023553608561023653"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1558,"op":82,"gas":"0x9e072","gasCost":"0x6","memSize":1312,"stack":["0x527fc0527f61610460527f023353606061023453600061023553608561023653","0x520"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1559,"op":127,"gas":"0x9e06c","gasCost":"0x3","memSize":1344,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1592,"op":97,"gas":"0x9e069","gasCost":"0x3","memSize":1344,"stack":["0x605a61023753606103e052610480527f7ff261026102e0526038610300536053"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1595,"op":82,"gas":"0x9e066","gasCost":"0x6","memSize":1344,"stack":["0x605a61023753606103e052610480527f7ff261026102e0526038610300536053","0x540"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1596,"op":127,"gas":"0x9e060","gasCost":"0x3","memSize":1376,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1629,"op":97,"gas":"0x9e05d","gasCost":"0x3","memSize":1376,"stack":["0x610301536060610302536050610303536104a0527f60610400527f6161030453"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1632,"op":82,"gas":"0x9e05a","gasCost":"0x6","memSize":1376,"stack":["0x610301536060610302536050610303536104a0527f60610400527f6161030453","0x560"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1633,"op":127,"gas":"0x9e054","gasCost":"0x3","memSize":1408,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1666,"op":97,"gas":"0x9e051","gasCost":"0x3","memSize":1408,"stack":["0x6002610305536039610306536053610307536060616104c0527f030853605061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1669,"op":82,"gas":"0x9e04e","gasCost":"0x6","memSize":1408,"stack":["0x6002610305536039610306536053610307536060616104c0527f030853605061","0x580"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1670,"op":127,"gas":"0x9e048","gasCost":"0x3","memSize":1440,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1703,"op":97,"gas":"0x9e045","gasCost":"0x3","memSize":1440,"stack":["0x610420527f030953606161030a53600261030b53603a61030c536104e0527f60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1706,"op":82,"gas":"0x9e042","gasCost":"0x7","memSize":1440,"stack":["0x610420527f030953606161030a53600261030b53603a61030c536104e0527f60","0x5a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1707,"op":127,"gas":"0x9e03b","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1740,"op":97,"gas":"0x9e038","gasCost":"0x3","memSize":1472,"stack":["0x5361030d53606161030e610440527f53600261030f53603b6103105360606161"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1743,"op":82,"gas":"0x9e035","gasCost":"0x6","memSize":1472,"stack":["0x5361030d53606161030e610440527f53600261030f53603b6103105360606161","0x5c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1744,"op":127,"gas":"0x9e02f","gasCost":"0x3","memSize":1504,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1777,"op":97,"gas":"0x9e02c","gasCost":"0x3","memSize":1504,"stack":["0x500527f03115360006103125360f36103135361610460526003610480536014"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1780,"op":82,"gas":"0x9e029","gasCost":"0x6","memSize":1504,"stack":["0x500527f03115360006103125360f36103135361610460526003610480536014","0x5e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1781,"op":127,"gas":"0x9e023","gasCost":"0x3","memSize":1536,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1814,"op":97,"gas":"0x9e020","gasCost":"0x3","memSize":1536,"stack":["0x61048153610520527f6060610482536000610483536060610484536000610485"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1817,"op":82,"gas":"0x9e01d","gasCost":"0x6","memSize":1536,"stack":["0x61048153610520527f6060610482536000610483536060610484536000610485","0x600"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1818,"op":127,"gas":"0x9e017","gasCost":"0x3","memSize":1568,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1851,"op":97,"gas":"0x9e014","gasCost":"0x3","memSize":1568,"stack":["0x5360f0610486536060610540527f610487536000610488536060610489536000"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1854,"op":82,"gas":"0x9e011","gasCost":"0x6","memSize":1568,"stack":["0x5360f0610486536060610540527f610487536000610488536060610489536000","0x620"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1855,"op":127,"gas":"0x9e00b","gasCost":"0x3","memSize":1600,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1888,"op":97,"gas":"0x9e008","gasCost":"0x3","memSize":1600,"stack":["0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1891,"op":82,"gas":"0x9e005","gasCost":"0x7","memSize":1600,"stack":["0x61048a53606061048b5360006104610560527f8c53606061048d53600061048e","0x640"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1892,"op":127,"gas":"0x9dffe","gasCost":"0x3","memSize":1632,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1925,"op":97,"gas":"0x9dffb","gasCost":"0x3","memSize":1632,"stack":["0x53608461048f53605a6104905360f4610491536105805260606105a053605061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1928,"op":82,"gas":"0x9dff8","gasCost":"0x6","memSize":1632,"stack":["0x53608461048f53605a6104905360f4610491536105805260606105a053605061","0x660"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1929,"op":127,"gas":"0x9dff2","gasCost":"0x3","memSize":1664,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1962,"op":97,"gas":"0x9dfef","gasCost":"0x3","memSize":1664,"stack":["0x5a15360616105a25360046105a35360926105a45360536105a55360606105a6"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1965,"op":82,"gas":"0x9dfec","gasCost":"0x6","memSize":1664,"stack":["0x5a15360616105a25360046105a35360926105a45360536105a55360606105a6","0x680"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1966,"op":127,"gas":"0x9dfe6","gasCost":"0x3","memSize":1696,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1999,"op":97,"gas":"0x9dfe3","gasCost":"0x3","memSize":1696,"stack":["0x5360506105a75360616105a85360046105a95360936105aa5360536105ab5360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2002,"op":82,"gas":"0x9dfe0","gasCost":"0x6","memSize":1696,"stack":["0x5360506105a75360616105a85360046105a95360936105aa5360536105ab5360","0x6a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":2003,"op":127,"gas":"0x9dfda","gasCost":"0x3","memSize":1728,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":2036,"op":97,"gas":"0x9dfd7","gasCost":"0x3","memSize":1728,"stack":["0x616105ac5360046105ad5360946105ae5360606105af5360006105b05360f361"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2039,"op":82,"gas":"0x9dfd4","gasCost":"0x6","memSize":1728,"stack":["0x616105ac5360046105ad5360946105ae5360606105af5360006105b05360f361","0x6c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":2040,"op":96,"gas":"0x9dfce","gasCost":"0x3","memSize":1760,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2042,"op":97,"gas":"0x9dfcb","gasCost":"0x3","memSize":1760,"stack":["0x5"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2045,"op":83,"gas":"0x9dfc8","gasCost":"0x7","memSize":1760,"stack":["0x5","0x6e0"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2046,"op":96,"gas":"0x9dfc1","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2048,"op":97,"gas":"0x9dfbe","gasCost":"0x3","memSize":1792,"stack":["0xb1"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2051,"op":83,"gas":"0x9dfbb","gasCost":"0x3","memSize":1792,"stack":["0xb1","0x6e1"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2052,"op":96,"gas":"0x9dfb8","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2054,"op":97,"gas":"0x9dfb5","gasCost":"0x3","memSize":1792,"stack":["0x53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2057,"op":83,"gas":"0x9dfb2","gasCost":"0x3","memSize":1792,"stack":["0x53","0x6e2"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2058,"op":96,"gas":"0x9dfaf","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2060,"op":97,"gas":"0x9dfac","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2063,"op":83,"gas":"0x9dfa9","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6e3"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2064,"op":96,"gas":"0x9dfa6","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2066,"op":97,"gas":"0x9dfa3","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2069,"op":83,"gas":"0x9dfa0","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6e4"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2070,"op":96,"gas":"0x9df9d","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2072,"op":97,"gas":"0x9df9a","gasCost":"0x3","memSize":1792,"stack":["0x61"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2075,"op":83,"gas":"0x9df97","gasCost":"0x3","memSize":1792,"stack":["0x61","0x6e5"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2076,"op":96,"gas":"0x9df94","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2078,"op":97,"gas":"0x9df91","gasCost":"0x3","memSize":1792,"stack":["0x5"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2081,"op":83,"gas":"0x9df8e","gasCost":"0x3","memSize":1792,"stack":["0x5","0x6e6"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2082,"op":96,"gas":"0x9df8b","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2084,"op":97,"gas":"0x9df88","gasCost":"0x3","memSize":1792,"stack":["0xb2"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2087,"op":83,"gas":"0x9df85","gasCost":"0x3","memSize":1792,"stack":["0xb2","0x6e7"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2088,"op":96,"gas":"0x9df82","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2090,"op":97,"gas":"0x9df7f","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2093,"op":83,"gas":"0x9df7c","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6e8"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2094,"op":96,"gas":"0x9df79","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2096,"op":97,"gas":"0x9df76","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2099,"op":83,"gas":"0x9df73","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6e9"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2100,"op":96,"gas":"0x9df70","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2102,"op":97,"gas":"0x9df6d","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2105,"op":83,"gas":"0x9df6a","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6ea"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2106,"op":96,"gas":"0x9df67","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2108,"op":97,"gas":"0x9df64","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2111,"op":83,"gas":"0x9df61","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6eb"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2112,"op":96,"gas":"0x9df5e","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2114,"op":97,"gas":"0x9df5b","gasCost":"0x3","memSize":1792,"stack":["0xf5"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2117,"op":83,"gas":"0x9df58","gasCost":"0x3","memSize":1792,"stack":["0xf5","0x6ec"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2118,"op":96,"gas":"0x9df55","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2120,"op":97,"gas":"0x9df52","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2123,"op":83,"gas":"0x9df4f","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6ed"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2124,"op":96,"gas":"0x9df4c","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2126,"op":97,"gas":"0x9df49","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2129,"op":83,"gas":"0x9df46","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6ee"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2130,"op":96,"gas":"0x9df43","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2132,"op":97,"gas":"0x9df40","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2135,"op":83,"gas":"0x9df3d","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6ef"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2136,"op":96,"gas":"0x9df3a","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2138,"op":97,"gas":"0x9df37","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2141,"op":83,"gas":"0x9df34","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6f0"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2142,"op":96,"gas":"0x9df31","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2144,"op":97,"gas":"0x9df2e","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2147,"op":83,"gas":"0x9df2b","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6f1"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2148,"op":96,"gas":"0x9df28","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2150,"op":97,"gas":"0x9df25","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2153,"op":83,"gas":"0x9df22","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6f2"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2154,"op":96,"gas":"0x9df1f","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2156,"op":97,"gas":"0x9df1c","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2159,"op":83,"gas":"0x9df19","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6f3"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2160,"op":96,"gas":"0x9df16","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2162,"op":97,"gas":"0x9df13","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2165,"op":83,"gas":"0x9df10","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6f4"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2166,"op":96,"gas":"0x9df0d","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2168,"op":97,"gas":"0x9df0a","gasCost":"0x3","memSize":1792,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2171,"op":83,"gas":"0x9df07","gasCost":"0x3","memSize":1792,"stack":["0x60","0x6f5"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2172,"op":96,"gas":"0x9df04","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2174,"op":97,"gas":"0x9df01","gasCost":"0x3","memSize":1792,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2177,"op":83,"gas":"0x9defe","gasCost":"0x3","memSize":1792,"stack":["0x0","0x6f6"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2178,"op":96,"gas":"0x9defb","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2180,"op":97,"gas":"0x9def8","gasCost":"0x3","memSize":1792,"stack":["0x85"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2183,"op":83,"gas":"0x9def5","gasCost":"0x3","memSize":1792,"stack":["0x85","0x6f7"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2184,"op":96,"gas":"0x9def2","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2186,"op":97,"gas":"0x9deef","gasCost":"0x3","memSize":1792,"stack":["0x5a"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2189,"op":83,"gas":"0x9deec","gasCost":"0x3","memSize":1792,"stack":["0x5a","0x6f8"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2190,"op":96,"gas":"0x9dee9","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2192,"op":97,"gas":"0x9dee6","gasCost":"0x3","memSize":1792,"stack":["0xf1"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2195,"op":83,"gas":"0x9dee3","gasCost":"0x3","memSize":1792,"stack":["0xf1","0x6f9"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2196,"op":96,"gas":"0x9dee0","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2198,"op":97,"gas":"0x9dedd","gasCost":"0x3","memSize":1792,"stack":["0x50"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2201,"op":83,"gas":"0x9deda","gasCost":"0x3","memSize":1792,"stack":["0x50","0x6fa"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2202,"op":96,"gas":"0x9ded7","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2204,"op":97,"gas":"0x9ded4","gasCost":"0x3","memSize":1792,"stack":["0x50"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2207,"op":83,"gas":"0x9ded1","gasCost":"0x3","memSize":1792,"stack":["0x50","0x6fb"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":2208,"op":97,"gas":"0x9dece","gasCost":"0x3","memSize":1792,"stack":[],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":2211,"op":96,"gas":"0x9decb","gasCost":"0x3","memSize":1792,"stack":["0x6fc"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":2213,"op":243,"gas":"0x9dec8","gasCost":"0x0","memSize":1792,"stack":["0x6fc","0x0"],"depth":2,"refund":0,"opName":"RETURN"} +{"output":"7f6008545060006004557f600160045560006004556000600060006000600060f96000527f5af250600060006000606000527e60f45af4506000600060006000600060f55a6020527ff150f001075205846a44a283446020527f8ca2600060006000600060045af4506040527f519930847f3b631c54a49b5f60035450326040527f77306b60006000600060006060527f6000600c5af150600060006000600060f85af450506060527f066001600255606080527f035450600060005560006001556c3394fff4607f7f1684317b6080527f387b9f60a0527f1920700184809d60015450011899016e6009ff60026001556000527f9f60a05260c0527f7f6000527f9981600160045582600eff600060006000600060f65af45060006060e0527f6060c0527f20527e600060006020527f60f75af4501d7f190316666000600060610100527e6000600060e0527f60046040527f5af1506000600060006040527f60006009610120527f5af4503c95138e5b8f610100527f7f605a6000536060527f6031600153606b60610140527f02536010606060527f0353604560610120527f04536060600553600160608052610160527f7e527f60065360606007536002600853606080610140527f527f556009536060610180527f600a53600160a0527f600b536060600c6020527f53600060610160527f0d53606101a0527f55600e60a0527f536060600f536060c0527f01601053606060115360026101806101c0527f527f601253606040527f55601353606060c0527f60145360e0527f60006015536101e0527f60606101a0527f601653600060175360f360185360196060605260006060e052610200527f610100527f7f806101c0527f5360f3608153608260006000f060006000600060610220527e845af450506000600061016101e0527f20527f60610100527e600060006003610240527f5af15060005450c760006002551309f562610200527f66a486610140527f6b00610260527f1d4571610120527f600054501c641d373c7f60045450610220527f6000600155610280527f600554610160527f50600160025560085450610140527f60006002610240527f6102a0527f557fd86000606000527e600060610180527e600060005af150861217145147356102c0527f610260527f610160527f5198a37e127a7efa7c6000526101a0527f606020527f6102e0527f6060205360610280527ff760215360ff60225360610180527fdb602353603760610300527f6101c0527f24536075606102a0527f2553609f606040527f265360fe60275360610320527f8f60286101a0527f53606101e0527f6102c0527f0b6029536060602a53600060610340527f2b536060602c53606052606060805360006061016102e0527f610200527fc052610360527f7f81536060608253602d6083536053608453606060855360fd610300527f6086610380527f536060610220527f6087536101e0527f602e60885360536089536060608a61036103a0527f20527f53602f608b536060608c610240527f536000608d5360f36102005260606103c0527f610220610340527f53608e610221536053610222536060610260527f610223536103e0527f6000610224536060610360527f61022553608f61022653606061022753600061610400527f02610280527f28536060610229610380527f53600061022a5360f561022b5360610420527f6061022c53600061022d536102a0527f60606103a0527f61022e53600061022f610440527f53606061023053600061023153606061023253600061026103c0527fc0527f61610460527f023353606061023453600061023553608561023653605a61023753606103e052610480527f7ff261026102e0526038610300536053610301536060610302536050610303536104a0527f60610400527f61610304536002610305536039610306536053610307536060616104c0527f030853605061610420527f030953606161030a53600261030b53603a61030c536104e0527f605361030d53606161030e610440527f53600261030f53603b61031053606061610500527f03115360006103125360f3610313536161046052600361048053601461048153610520527f60606104825360006104835360606104845360006104855360f0610486536060610540527f61048753600061048853606061048953600061048a53606061048b5360006104610560527f8c53606061048d53600061048e53608461048f53605a6104905360f4610491536105805260606105a05360506105a15360616105a25360046105a35360926105a45360536105a55360606105a65360506105a75360616105a85360046105a95360936105aa5360536105ab5360616105ac5360046105ad5360946105ae5360606105af5360006105b05360f36105b15360006105b260006000f560006000600060006000855af15050","gasUsed":"0x5d717"} +{"pc":2605,"op":96,"gas":"0x49392","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2607,"op":96,"gas":"0x4938f","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2609,"op":96,"gas":"0x4938c","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2611,"op":96,"gas":"0x49389","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2613,"op":96,"gas":"0x49386","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2615,"op":133,"gas":"0x49383","gasCost":"0x3","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0","0x0","0x0","0x0"],"depth":1,"refund":0,"opName":"DUP6"} +{"pc":2616,"op":90,"gas":"0x49380","gasCost":"0x2","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0","0x0","0x0","0x0","0x7dce2faf43218578e3fcf2ad22df9918a89e2fba"],"depth":1,"refund":0,"opName":"GAS"} +{"pc":2617,"op":241,"gas":"0x4937e","gasCost":"0x48132","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x0","0x0","0x0","0x0","0x0","0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x4937e"],"depth":1,"refund":0,"opName":"CALL"} +{"pc":0,"op":127,"gas":"0x480ce","gasCost":"0x3","memSize":0,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":33,"op":96,"gas":"0x480cb","gasCost":"0x3","memSize":0,"stack":["0x6008545060006004557f600160045560006004556000600060006000600060f9"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":35,"op":82,"gas":"0x480c8","gasCost":"0x6","memSize":0,"stack":["0x6008545060006004557f600160045560006004556000600060006000600060f9","0x0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":36,"op":127,"gas":"0x480c2","gasCost":"0x3","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":69,"op":96,"gas":"0x480bf","gasCost":"0x3","memSize":32,"stack":["0x5af250600060006000606000527e60f45af4506000600060006000600060f55a"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":71,"op":82,"gas":"0x480bc","gasCost":"0x6","memSize":32,"stack":["0x5af250600060006000606000527e60f45af4506000600060006000600060f55a","0x20"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":72,"op":127,"gas":"0x480b6","gasCost":"0x3","memSize":64,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":105,"op":96,"gas":"0x480b3","gasCost":"0x3","memSize":64,"stack":["0xf150f001075205846a44a283446020527f8ca2600060006000600060045af450"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":107,"op":82,"gas":"0x480b0","gasCost":"0x6","memSize":64,"stack":["0xf150f001075205846a44a283446020527f8ca2600060006000600060045af450","0x40"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":108,"op":127,"gas":"0x480aa","gasCost":"0x3","memSize":96,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":141,"op":96,"gas":"0x480a7","gasCost":"0x3","memSize":96,"stack":["0x519930847f3b631c54a49b5f60035450326040527f77306b6000600060006000"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":143,"op":82,"gas":"0x480a4","gasCost":"0x6","memSize":96,"stack":["0x519930847f3b631c54a49b5f60035450326040527f77306b6000600060006000","0x60"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":144,"op":127,"gas":"0x4809e","gasCost":"0x3","memSize":128,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":177,"op":96,"gas":"0x4809b","gasCost":"0x3","memSize":128,"stack":["0x6000600c5af150600060006000600060f85af450506060527f06600160025560"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":179,"op":82,"gas":"0x48098","gasCost":"0x6","memSize":128,"stack":["0x6000600c5af150600060006000600060f85af450506060527f06600160025560","0x80"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":180,"op":127,"gas":"0x48092","gasCost":"0x3","memSize":160,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":213,"op":96,"gas":"0x4808f","gasCost":"0x3","memSize":160,"stack":["0x35450600060005560006001556c3394fff4607f7f1684317b6080527f387b9f"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":215,"op":82,"gas":"0x4808c","gasCost":"0x6","memSize":160,"stack":["0x35450600060005560006001556c3394fff4607f7f1684317b6080527f387b9f","0xa0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":216,"op":127,"gas":"0x48086","gasCost":"0x3","memSize":192,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":249,"op":96,"gas":"0x48083","gasCost":"0x3","memSize":192,"stack":["0x1920700184809d60015450011899016e6009ff60026001556000527f9f60a052"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":251,"op":82,"gas":"0x48080","gasCost":"0x6","memSize":192,"stack":["0x1920700184809d60015450011899016e6009ff60026001556000527f9f60a052","0xc0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":252,"op":127,"gas":"0x4807a","gasCost":"0x3","memSize":224,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":285,"op":96,"gas":"0x48077","gasCost":"0x3","memSize":224,"stack":["0x7f6000527f9981600160045582600eff600060006000600060f65af450600060"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":287,"op":82,"gas":"0x48074","gasCost":"0x6","memSize":224,"stack":["0x7f6000527f9981600160045582600eff600060006000600060f65af450600060","0xe0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":288,"op":127,"gas":"0x4806e","gasCost":"0x3","memSize":256,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":321,"op":97,"gas":"0x4806b","gasCost":"0x3","memSize":256,"stack":["0x6060c0527f20527e600060006020527f60f75af4501d7f190316666000600060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":324,"op":82,"gas":"0x48068","gasCost":"0x6","memSize":256,"stack":["0x6060c0527f20527e600060006020527f60f75af4501d7f190316666000600060","0x100"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":325,"op":126,"gas":"0x48062","gasCost":"0x3","memSize":288,"stack":[],"depth":2,"refund":0,"opName":"PUSH31"} +{"pc":357,"op":97,"gas":"0x4805f","gasCost":"0x3","memSize":288,"stack":["0x6000600060e0527f60046040527f5af1506000600060006040527f60006009"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":360,"op":82,"gas":"0x4805c","gasCost":"0x6","memSize":288,"stack":["0x6000600060e0527f60046040527f5af1506000600060006040527f60006009","0x120"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":361,"op":127,"gas":"0x48056","gasCost":"0x3","memSize":320,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":394,"op":97,"gas":"0x48053","gasCost":"0x3","memSize":320,"stack":["0x5af4503c95138e5b8f610100527f7f605a6000536060527f6031600153606b60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":397,"op":82,"gas":"0x48050","gasCost":"0x6","memSize":320,"stack":["0x5af4503c95138e5b8f610100527f7f605a6000536060527f6031600153606b60","0x140"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":398,"op":127,"gas":"0x4804a","gasCost":"0x3","memSize":352,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":431,"op":97,"gas":"0x48047","gasCost":"0x3","memSize":352,"stack":["0x2536010606060527f0353604560610120527f04536060600553600160608052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":434,"op":82,"gas":"0x48044","gasCost":"0x6","memSize":352,"stack":["0x2536010606060527f0353604560610120527f04536060600553600160608052","0x160"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":435,"op":127,"gas":"0x4803e","gasCost":"0x3","memSize":384,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":468,"op":97,"gas":"0x4803b","gasCost":"0x3","memSize":384,"stack":["0x7e527f60065360606007536002600853606080610140527f527f556009536060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":471,"op":82,"gas":"0x48038","gasCost":"0x6","memSize":384,"stack":["0x7e527f60065360606007536002600853606080610140527f527f556009536060","0x180"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":472,"op":127,"gas":"0x48032","gasCost":"0x3","memSize":416,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":505,"op":97,"gas":"0x4802f","gasCost":"0x3","memSize":416,"stack":["0x600a53600160a0527f600b536060600c6020527f53600060610160527f0d5360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":508,"op":82,"gas":"0x4802c","gasCost":"0x6","memSize":416,"stack":["0x600a53600160a0527f600b536060600c6020527f53600060610160527f0d5360","0x1a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":509,"op":127,"gas":"0x48026","gasCost":"0x3","memSize":448,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":542,"op":97,"gas":"0x48023","gasCost":"0x3","memSize":448,"stack":["0x55600e60a0527f536060600f536060c0527f0160105360606011536002610180"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":545,"op":82,"gas":"0x48020","gasCost":"0x6","memSize":448,"stack":["0x55600e60a0527f536060600f536060c0527f0160105360606011536002610180","0x1c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":546,"op":127,"gas":"0x4801a","gasCost":"0x3","memSize":480,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":579,"op":97,"gas":"0x48017","gasCost":"0x3","memSize":480,"stack":["0x527f601253606040527f55601353606060c0527f60145360e0527f6000601553"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":582,"op":82,"gas":"0x48014","gasCost":"0x6","memSize":480,"stack":["0x527f601253606040527f55601353606060c0527f60145360e0527f6000601553","0x1e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":583,"op":127,"gas":"0x4800e","gasCost":"0x3","memSize":512,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":616,"op":97,"gas":"0x4800b","gasCost":"0x3","memSize":512,"stack":["0x60606101a0527f601653600060175360f360185360196060605260006060e052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":619,"op":82,"gas":"0x48008","gasCost":"0x6","memSize":512,"stack":["0x60606101a0527f601653600060175360f360185360196060605260006060e052","0x200"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":620,"op":127,"gas":"0x48002","gasCost":"0x3","memSize":544,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":653,"op":97,"gas":"0x47fff","gasCost":"0x3","memSize":544,"stack":["0x610100527f7f806101c0527f5360f3608153608260006000f060006000600060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":656,"op":82,"gas":"0x47ffc","gasCost":"0x6","memSize":544,"stack":["0x610100527f7f806101c0527f5360f3608153608260006000f060006000600060","0x220"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":657,"op":126,"gas":"0x47ff6","gasCost":"0x3","memSize":576,"stack":[],"depth":2,"refund":0,"opName":"PUSH31"} +{"pc":689,"op":97,"gas":"0x47ff3","gasCost":"0x3","memSize":576,"stack":["0x845af450506000600061016101e0527f20527f60610100527e600060006003"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":692,"op":82,"gas":"0x47ff0","gasCost":"0x6","memSize":576,"stack":["0x845af450506000600061016101e0527f20527f60610100527e600060006003","0x240"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":693,"op":127,"gas":"0x47fea","gasCost":"0x3","memSize":608,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":726,"op":97,"gas":"0x47fe7","gasCost":"0x3","memSize":608,"stack":["0x5af15060005450c760006002551309f562610200527f66a486610140527f6b00"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":729,"op":82,"gas":"0x47fe4","gasCost":"0x6","memSize":608,"stack":["0x5af15060005450c760006002551309f562610200527f66a486610140527f6b00","0x260"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":730,"op":127,"gas":"0x47fde","gasCost":"0x3","memSize":640,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":763,"op":97,"gas":"0x47fdb","gasCost":"0x3","memSize":640,"stack":["0x1d4571610120527f600054501c641d373c7f60045450610220527f6000600155"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":766,"op":82,"gas":"0x47fd8","gasCost":"0x6","memSize":640,"stack":["0x1d4571610120527f600054501c641d373c7f60045450610220527f6000600155","0x280"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":767,"op":127,"gas":"0x47fd2","gasCost":"0x3","memSize":672,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":800,"op":97,"gas":"0x47fcf","gasCost":"0x3","memSize":672,"stack":["0x600554610160527f50600160025560085450610140527f60006002610240527f"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":803,"op":82,"gas":"0x47fcc","gasCost":"0x6","memSize":672,"stack":["0x600554610160527f50600160025560085450610140527f60006002610240527f","0x2a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":804,"op":127,"gas":"0x47fc6","gasCost":"0x3","memSize":704,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":837,"op":97,"gas":"0x47fc3","gasCost":"0x3","memSize":704,"stack":["0x557fd86000606000527e600060610180527e600060005af15086121714514735"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":840,"op":82,"gas":"0x47fc0","gasCost":"0x7","memSize":704,"stack":["0x557fd86000606000527e600060610180527e600060005af15086121714514735","0x2c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":841,"op":127,"gas":"0x47fb9","gasCost":"0x3","memSize":736,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":874,"op":97,"gas":"0x47fb6","gasCost":"0x3","memSize":736,"stack":["0x610260527f610160527f5198a37e127a7efa7c6000526101a0527f606020527f"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":877,"op":82,"gas":"0x47fb3","gasCost":"0x6","memSize":736,"stack":["0x610260527f610160527f5198a37e127a7efa7c6000526101a0527f606020527f","0x2e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":878,"op":127,"gas":"0x47fad","gasCost":"0x3","memSize":768,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":911,"op":97,"gas":"0x47faa","gasCost":"0x3","memSize":768,"stack":["0x6060205360610280527ff760215360ff60225360610180527fdb602353603760"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":914,"op":82,"gas":"0x47fa7","gasCost":"0x6","memSize":768,"stack":["0x6060205360610280527ff760215360ff60225360610180527fdb602353603760","0x300"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":915,"op":127,"gas":"0x47fa1","gasCost":"0x3","memSize":800,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":948,"op":97,"gas":"0x47f9e","gasCost":"0x3","memSize":800,"stack":["0x6101c0527f24536075606102a0527f2553609f606040527f265360fe60275360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":951,"op":82,"gas":"0x47f9b","gasCost":"0x6","memSize":800,"stack":["0x6101c0527f24536075606102a0527f2553609f606040527f265360fe60275360","0x320"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":952,"op":127,"gas":"0x47f95","gasCost":"0x3","memSize":832,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":985,"op":97,"gas":"0x47f92","gasCost":"0x3","memSize":832,"stack":["0x8f60286101a0527f53606101e0527f6102c0527f0b6029536060602a53600060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":988,"op":82,"gas":"0x47f8f","gasCost":"0x6","memSize":832,"stack":["0x8f60286101a0527f53606101e0527f6102c0527f0b6029536060602a53600060","0x340"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":989,"op":127,"gas":"0x47f89","gasCost":"0x3","memSize":864,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1022,"op":97,"gas":"0x47f86","gasCost":"0x3","memSize":864,"stack":["0x2b536060602c53606052606060805360006061016102e0527f610200527fc052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1025,"op":82,"gas":"0x47f83","gasCost":"0x6","memSize":864,"stack":["0x2b536060602c53606052606060805360006061016102e0527f610200527fc052","0x360"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1026,"op":127,"gas":"0x47f7d","gasCost":"0x3","memSize":896,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1059,"op":97,"gas":"0x47f7a","gasCost":"0x3","memSize":896,"stack":["0x7f81536060608253602d6083536053608453606060855360fd610300527f6086"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1062,"op":82,"gas":"0x47f77","gasCost":"0x6","memSize":896,"stack":["0x7f81536060608253602d6083536053608453606060855360fd610300527f6086","0x380"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1063,"op":127,"gas":"0x47f71","gasCost":"0x3","memSize":928,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1096,"op":97,"gas":"0x47f6e","gasCost":"0x3","memSize":928,"stack":["0x536060610220527f6087536101e0527f602e60885360536089536060608a6103"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1099,"op":82,"gas":"0x47f6b","gasCost":"0x6","memSize":928,"stack":["0x536060610220527f6087536101e0527f602e60885360536089536060608a6103","0x3a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1100,"op":127,"gas":"0x47f65","gasCost":"0x3","memSize":960,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1133,"op":97,"gas":"0x47f62","gasCost":"0x3","memSize":960,"stack":["0x20527f53602f608b536060608c610240527f536000608d5360f3610200526060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1136,"op":82,"gas":"0x47f5f","gasCost":"0x6","memSize":960,"stack":["0x20527f53602f608b536060608c610240527f536000608d5360f3610200526060","0x3c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1137,"op":127,"gas":"0x47f59","gasCost":"0x3","memSize":992,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1170,"op":97,"gas":"0x47f56","gasCost":"0x3","memSize":992,"stack":["0x610220610340527f53608e610221536053610222536060610260527f61022353"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1173,"op":82,"gas":"0x47f53","gasCost":"0x7","memSize":992,"stack":["0x610220610340527f53608e610221536053610222536060610260527f61022353","0x3e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1174,"op":127,"gas":"0x47f4c","gasCost":"0x3","memSize":1024,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1207,"op":97,"gas":"0x47f49","gasCost":"0x3","memSize":1024,"stack":["0x6000610224536060610360527f61022553608f61022653606061022753600061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1210,"op":82,"gas":"0x47f46","gasCost":"0x6","memSize":1024,"stack":["0x6000610224536060610360527f61022553608f61022653606061022753600061","0x400"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1211,"op":127,"gas":"0x47f40","gasCost":"0x3","memSize":1056,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1244,"op":97,"gas":"0x47f3d","gasCost":"0x3","memSize":1056,"stack":["0x2610280527f28536060610229610380527f53600061022a5360f561022b5360"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1247,"op":82,"gas":"0x47f3a","gasCost":"0x6","memSize":1056,"stack":["0x2610280527f28536060610229610380527f53600061022a5360f561022b5360","0x420"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1248,"op":127,"gas":"0x47f34","gasCost":"0x3","memSize":1088,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1281,"op":97,"gas":"0x47f31","gasCost":"0x3","memSize":1088,"stack":["0x6061022c53600061022d536102a0527f60606103a0527f61022e53600061022f"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1284,"op":82,"gas":"0x47f2e","gasCost":"0x6","memSize":1088,"stack":["0x6061022c53600061022d536102a0527f60606103a0527f61022e53600061022f","0x440"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1285,"op":127,"gas":"0x47f28","gasCost":"0x3","memSize":1120,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1318,"op":97,"gas":"0x47f25","gasCost":"0x3","memSize":1120,"stack":["0x53606061023053600061023153606061023253600061026103c0527fc0527f61"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1321,"op":82,"gas":"0x47f22","gasCost":"0x6","memSize":1120,"stack":["0x53606061023053600061023153606061023253600061026103c0527fc0527f61","0x460"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1322,"op":127,"gas":"0x47f1c","gasCost":"0x3","memSize":1152,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1355,"op":97,"gas":"0x47f19","gasCost":"0x3","memSize":1152,"stack":["0x23353606061023453600061023553608561023653605a61023753606103e052"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1358,"op":82,"gas":"0x47f16","gasCost":"0x6","memSize":1152,"stack":["0x23353606061023453600061023553608561023653605a61023753606103e052","0x480"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1359,"op":127,"gas":"0x47f10","gasCost":"0x3","memSize":1184,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1392,"op":97,"gas":"0x47f0d","gasCost":"0x3","memSize":1184,"stack":["0x7ff261026102e052603861030053605361030153606061030253605061030353"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1395,"op":82,"gas":"0x47f0a","gasCost":"0x6","memSize":1184,"stack":["0x7ff261026102e052603861030053605361030153606061030253605061030353","0x4a0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1396,"op":127,"gas":"0x47f04","gasCost":"0x3","memSize":1216,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1429,"op":97,"gas":"0x47f01","gasCost":"0x3","memSize":1216,"stack":["0x60610400527f6161030453600261030553603961030653605361030753606061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1432,"op":82,"gas":"0x47efe","gasCost":"0x6","memSize":1216,"stack":["0x60610400527f6161030453600261030553603961030653605361030753606061","0x4c0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1433,"op":127,"gas":"0x47ef8","gasCost":"0x3","memSize":1248,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1466,"op":97,"gas":"0x47ef5","gasCost":"0x3","memSize":1248,"stack":["0x30853605061610420527f030953606161030a53600261030b53603a61030c53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1469,"op":82,"gas":"0x47ef2","gasCost":"0x7","memSize":1248,"stack":["0x30853605061610420527f030953606161030a53600261030b53603a61030c53","0x4e0"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1470,"op":127,"gas":"0x47eeb","gasCost":"0x3","memSize":1280,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1503,"op":97,"gas":"0x47ee8","gasCost":"0x3","memSize":1280,"stack":["0x605361030d53606161030e610440527f53600261030f53603b61031053606061"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1506,"op":82,"gas":"0x47ee5","gasCost":"0x6","memSize":1280,"stack":["0x605361030d53606161030e610440527f53600261030f53603b61031053606061","0x500"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1507,"op":127,"gas":"0x47edf","gasCost":"0x3","memSize":1312,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1540,"op":97,"gas":"0x47edc","gasCost":"0x3","memSize":1312,"stack":["0x3115360006103125360f3610313536161046052600361048053601461048153"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1543,"op":82,"gas":"0x47ed9","gasCost":"0x6","memSize":1312,"stack":["0x3115360006103125360f3610313536161046052600361048053601461048153","0x520"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1544,"op":127,"gas":"0x47ed3","gasCost":"0x3","memSize":1344,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1577,"op":97,"gas":"0x47ed0","gasCost":"0x3","memSize":1344,"stack":["0x60606104825360006104835360606104845360006104855360f0610486536060"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1580,"op":82,"gas":"0x47ecd","gasCost":"0x6","memSize":1344,"stack":["0x60606104825360006104835360606104845360006104855360f0610486536060","0x540"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1581,"op":127,"gas":"0x47ec7","gasCost":"0x3","memSize":1376,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1614,"op":97,"gas":"0x47ec4","gasCost":"0x3","memSize":1376,"stack":["0x61048753600061048853606061048953600061048a53606061048b5360006104"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1617,"op":82,"gas":"0x47ec1","gasCost":"0x6","memSize":1376,"stack":["0x61048753600061048853606061048953600061048a53606061048b5360006104","0x560"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1618,"op":127,"gas":"0x47ebb","gasCost":"0x3","memSize":1408,"stack":[],"depth":2,"refund":0,"opName":"PUSH32"} +{"pc":1651,"op":97,"gas":"0x47eb8","gasCost":"0x3","memSize":1408,"stack":["0x8c53606061048d53600061048e53608461048f53605a6104905360f461049153"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1654,"op":82,"gas":"0x47eb5","gasCost":"0x6","memSize":1408,"stack":["0x8c53606061048d53600061048e53608461048f53605a6104905360f461049153","0x580"],"depth":2,"refund":0,"opName":"MSTORE"} +{"pc":1655,"op":96,"gas":"0x47eaf","gasCost":"0x3","memSize":1440,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1657,"op":97,"gas":"0x47eac","gasCost":"0x3","memSize":1440,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1660,"op":83,"gas":"0x47ea9","gasCost":"0x7","memSize":1440,"stack":["0x60","0x5a0"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1661,"op":96,"gas":"0x47ea2","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1663,"op":97,"gas":"0x47e9f","gasCost":"0x3","memSize":1472,"stack":["0x50"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1666,"op":83,"gas":"0x47e9c","gasCost":"0x3","memSize":1472,"stack":["0x50","0x5a1"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1667,"op":96,"gas":"0x47e99","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1669,"op":97,"gas":"0x47e96","gasCost":"0x3","memSize":1472,"stack":["0x61"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1672,"op":83,"gas":"0x47e93","gasCost":"0x3","memSize":1472,"stack":["0x61","0x5a2"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1673,"op":96,"gas":"0x47e90","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1675,"op":97,"gas":"0x47e8d","gasCost":"0x3","memSize":1472,"stack":["0x4"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1678,"op":83,"gas":"0x47e8a","gasCost":"0x3","memSize":1472,"stack":["0x4","0x5a3"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1679,"op":96,"gas":"0x47e87","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1681,"op":97,"gas":"0x47e84","gasCost":"0x3","memSize":1472,"stack":["0x92"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1684,"op":83,"gas":"0x47e81","gasCost":"0x3","memSize":1472,"stack":["0x92","0x5a4"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1685,"op":96,"gas":"0x47e7e","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1687,"op":97,"gas":"0x47e7b","gasCost":"0x3","memSize":1472,"stack":["0x53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1690,"op":83,"gas":"0x47e78","gasCost":"0x3","memSize":1472,"stack":["0x53","0x5a5"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1691,"op":96,"gas":"0x47e75","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1693,"op":97,"gas":"0x47e72","gasCost":"0x3","memSize":1472,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1696,"op":83,"gas":"0x47e6f","gasCost":"0x3","memSize":1472,"stack":["0x60","0x5a6"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1697,"op":96,"gas":"0x47e6c","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1699,"op":97,"gas":"0x47e69","gasCost":"0x3","memSize":1472,"stack":["0x50"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1702,"op":83,"gas":"0x47e66","gasCost":"0x3","memSize":1472,"stack":["0x50","0x5a7"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1703,"op":96,"gas":"0x47e63","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1705,"op":97,"gas":"0x47e60","gasCost":"0x3","memSize":1472,"stack":["0x61"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1708,"op":83,"gas":"0x47e5d","gasCost":"0x3","memSize":1472,"stack":["0x61","0x5a8"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1709,"op":96,"gas":"0x47e5a","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1711,"op":97,"gas":"0x47e57","gasCost":"0x3","memSize":1472,"stack":["0x4"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1714,"op":83,"gas":"0x47e54","gasCost":"0x3","memSize":1472,"stack":["0x4","0x5a9"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1715,"op":96,"gas":"0x47e51","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1717,"op":97,"gas":"0x47e4e","gasCost":"0x3","memSize":1472,"stack":["0x93"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1720,"op":83,"gas":"0x47e4b","gasCost":"0x3","memSize":1472,"stack":["0x93","0x5aa"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1721,"op":96,"gas":"0x47e48","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1723,"op":97,"gas":"0x47e45","gasCost":"0x3","memSize":1472,"stack":["0x53"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1726,"op":83,"gas":"0x47e42","gasCost":"0x3","memSize":1472,"stack":["0x53","0x5ab"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1727,"op":96,"gas":"0x47e3f","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1729,"op":97,"gas":"0x47e3c","gasCost":"0x3","memSize":1472,"stack":["0x61"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1732,"op":83,"gas":"0x47e39","gasCost":"0x3","memSize":1472,"stack":["0x61","0x5ac"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1733,"op":96,"gas":"0x47e36","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1735,"op":97,"gas":"0x47e33","gasCost":"0x3","memSize":1472,"stack":["0x4"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1738,"op":83,"gas":"0x47e30","gasCost":"0x3","memSize":1472,"stack":["0x4","0x5ad"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1739,"op":96,"gas":"0x47e2d","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1741,"op":97,"gas":"0x47e2a","gasCost":"0x3","memSize":1472,"stack":["0x94"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1744,"op":83,"gas":"0x47e27","gasCost":"0x3","memSize":1472,"stack":["0x94","0x5ae"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1745,"op":96,"gas":"0x47e24","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1747,"op":97,"gas":"0x47e21","gasCost":"0x3","memSize":1472,"stack":["0x60"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1750,"op":83,"gas":"0x47e1e","gasCost":"0x3","memSize":1472,"stack":["0x60","0x5af"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1751,"op":96,"gas":"0x47e1b","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1753,"op":97,"gas":"0x47e18","gasCost":"0x3","memSize":1472,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1756,"op":83,"gas":"0x47e15","gasCost":"0x3","memSize":1472,"stack":["0x0","0x5b0"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1757,"op":96,"gas":"0x47e12","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1759,"op":97,"gas":"0x47e0f","gasCost":"0x3","memSize":1472,"stack":["0xf3"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1762,"op":83,"gas":"0x47e0c","gasCost":"0x3","memSize":1472,"stack":["0xf3","0x5b1"],"depth":2,"refund":0,"opName":"MSTORE8"} +{"pc":1763,"op":96,"gas":"0x47e09","gasCost":"0x3","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1765,"op":97,"gas":"0x47e06","gasCost":"0x3","memSize":1472,"stack":["0x0"],"depth":2,"refund":0,"opName":"PUSH2"} +{"pc":1768,"op":96,"gas":"0x47e03","gasCost":"0x3","memSize":1472,"stack":["0x0","0x5b2"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1770,"op":96,"gas":"0x47e00","gasCost":"0x3","memSize":1472,"stack":["0x0","0x5b2","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1772,"op":245,"gas":"0x47dfd","gasCost":"0x7e14","memSize":1472,"stack":["0x0","0x5b2","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2"} +{"pc":0,"op":96,"gas":"0x3efea","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":84,"gas":"0x3efe7","gasCost":"0x834","memSize":0,"stack":["0x8"],"depth":3,"refund":0,"opName":"SLOAD"} +{"pc":3,"op":80,"gas":"0x3e7b3","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":3,"refund":0,"opName":"POP"} +{"pc":4,"op":96,"gas":"0x3e7b1","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x3e7ae","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":85,"gas":"0x3e7ab","gasCost":"0x898","memSize":0,"stack":["0x0","0x4"],"depth":3,"refund":0,"opName":"SSTORE"} +{"pc":9,"op":127,"gas":"0x3df13","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":42,"op":96,"gas":"0x3df10","gasCost":"0x3","memSize":0,"stack":["0x600160045560006004556000600060006000600060f95af25060006000600060"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":44,"op":82,"gas":"0x3df0d","gasCost":"0x6","memSize":0,"stack":["0x600160045560006004556000600060006000600060f95af25060006000600060","0x0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":45,"op":126,"gas":"0x3df07","gasCost":"0x3","memSize":32,"stack":[],"depth":3,"refund":0,"opName":"PUSH31"} +{"pc":77,"op":96,"gas":"0x3df04","gasCost":"0x3","memSize":32,"stack":["0x60f45af4506000600060006000600060f55af150f001075205846a44a28344"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":79,"op":82,"gas":"0x3df01","gasCost":"0x6","memSize":32,"stack":["0x60f45af4506000600060006000600060f55af150f001075205846a44a28344","0x20"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":80,"op":127,"gas":"0x3defb","gasCost":"0x3","memSize":64,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":113,"op":96,"gas":"0x3def8","gasCost":"0x3","memSize":64,"stack":["0x8ca2600060006000600060045af450519930847f3b631c54a49b5f6003545032"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":115,"op":82,"gas":"0x3def5","gasCost":"0x6","memSize":64,"stack":["0x8ca2600060006000600060045af450519930847f3b631c54a49b5f6003545032","0x40"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":116,"op":127,"gas":"0x3deef","gasCost":"0x3","memSize":96,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":149,"op":96,"gas":"0x3deec","gasCost":"0x3","memSize":96,"stack":["0x77306b60006000600060006000600c5af150600060006000600060f85af45050"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":151,"op":82,"gas":"0x3dee9","gasCost":"0x6","memSize":96,"stack":["0x77306b60006000600060006000600c5af150600060006000600060f85af45050","0x60"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":152,"op":127,"gas":"0x3dee3","gasCost":"0x3","memSize":128,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":185,"op":96,"gas":"0x3dee0","gasCost":"0x3","memSize":128,"stack":["0x6600160025560035450600060005560006001556c3394fff4607f7f1684317b"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":187,"op":82,"gas":"0x3dedd","gasCost":"0x6","memSize":128,"stack":["0x6600160025560035450600060005560006001556c3394fff4607f7f1684317b","0x80"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":188,"op":127,"gas":"0x3ded7","gasCost":"0x3","memSize":160,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":221,"op":96,"gas":"0x3ded4","gasCost":"0x3","memSize":160,"stack":["0x387b9f1920700184809d60015450011899016e6009ff60026001556000527f9f"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":223,"op":82,"gas":"0x3ded1","gasCost":"0x6","memSize":160,"stack":["0x387b9f1920700184809d60015450011899016e6009ff60026001556000527f9f","0xa0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":224,"op":127,"gas":"0x3decb","gasCost":"0x3","memSize":192,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":257,"op":96,"gas":"0x3dec8","gasCost":"0x3","memSize":192,"stack":["0x6000527f9981600160045582600eff600060006000600060f65af45060006060"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":259,"op":82,"gas":"0x3dec5","gasCost":"0x6","memSize":192,"stack":["0x6000527f9981600160045582600eff600060006000600060f65af45060006060","0xc0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":260,"op":127,"gas":"0x3debf","gasCost":"0x3","memSize":224,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":293,"op":96,"gas":"0x3debc","gasCost":"0x3","memSize":224,"stack":["0x20527e600060006020527f60f75af4501d7f1903166660006000600060006000"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":295,"op":82,"gas":"0x3deb9","gasCost":"0x6","memSize":224,"stack":["0x20527e600060006020527f60f75af4501d7f1903166660006000600060006000","0xe0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":296,"op":127,"gas":"0x3deb3","gasCost":"0x3","memSize":256,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":329,"op":97,"gas":"0x3deb0","gasCost":"0x3","memSize":256,"stack":["0x60046040527f5af1506000600060006040527f600060095af4503c95138e5b8f"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":332,"op":82,"gas":"0x3dead","gasCost":"0x6","memSize":256,"stack":["0x60046040527f5af1506000600060006040527f600060095af4503c95138e5b8f","0x100"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":333,"op":127,"gas":"0x3dea7","gasCost":"0x3","memSize":288,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":366,"op":97,"gas":"0x3dea4","gasCost":"0x3","memSize":288,"stack":["0x7f605a6000536060527f6031600153606b6002536010606060527f0353604560"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":369,"op":82,"gas":"0x3dea1","gasCost":"0x6","memSize":288,"stack":["0x7f605a6000536060527f6031600153606b6002536010606060527f0353604560","0x120"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":370,"op":127,"gas":"0x3de9b","gasCost":"0x3","memSize":320,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":403,"op":97,"gas":"0x3de98","gasCost":"0x3","memSize":320,"stack":["0x45360606005536001606080527e527f60065360606007536002600853606080"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":406,"op":82,"gas":"0x3de95","gasCost":"0x6","memSize":320,"stack":["0x45360606005536001606080527e527f60065360606007536002600853606080","0x140"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":407,"op":127,"gas":"0x3de8f","gasCost":"0x3","memSize":352,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":440,"op":97,"gas":"0x3de8c","gasCost":"0x3","memSize":352,"stack":["0x527f556009536060600a53600160a0527f600b536060600c6020527f53600060"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":443,"op":82,"gas":"0x3de89","gasCost":"0x6","memSize":352,"stack":["0x527f556009536060600a53600160a0527f600b536060600c6020527f53600060","0x160"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":444,"op":127,"gas":"0x3de83","gasCost":"0x3","memSize":384,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":477,"op":97,"gas":"0x3de80","gasCost":"0x3","memSize":384,"stack":["0xd536055600e60a0527f536060600f536060c0527f0160105360606011536002"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":480,"op":82,"gas":"0x3de7d","gasCost":"0x6","memSize":384,"stack":["0xd536055600e60a0527f536060600f536060c0527f0160105360606011536002","0x180"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":481,"op":127,"gas":"0x3de77","gasCost":"0x3","memSize":416,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":514,"op":97,"gas":"0x3de74","gasCost":"0x3","memSize":416,"stack":["0x601253606040527f55601353606060c0527f60145360e0527f60006015536060"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":517,"op":82,"gas":"0x3de71","gasCost":"0x6","memSize":416,"stack":["0x601253606040527f55601353606060c0527f60145360e0527f60006015536060","0x1a0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":518,"op":127,"gas":"0x3de6b","gasCost":"0x3","memSize":448,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":551,"op":97,"gas":"0x3de68","gasCost":"0x3","memSize":448,"stack":["0x601653600060175360f360185360196060605260006060e052610100527f7f80"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":554,"op":82,"gas":"0x3de65","gasCost":"0x6","memSize":448,"stack":["0x601653600060175360f360185360196060605260006060e052610100527f7f80","0x1c0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":555,"op":127,"gas":"0x3de5f","gasCost":"0x3","memSize":480,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":588,"op":97,"gas":"0x3de5c","gasCost":"0x3","memSize":480,"stack":["0x5360f3608153608260006000f06000600060006000845af45050600060006101"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":591,"op":82,"gas":"0x3de59","gasCost":"0x6","memSize":480,"stack":["0x5360f3608153608260006000f06000600060006000845af45050600060006101","0x1e0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":592,"op":127,"gas":"0x3de53","gasCost":"0x3","memSize":512,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":625,"op":97,"gas":"0x3de50","gasCost":"0x3","memSize":512,"stack":["0x20527f60610100527e6000600060035af15060005450c760006002551309f562"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":628,"op":82,"gas":"0x3de4d","gasCost":"0x6","memSize":512,"stack":["0x20527f60610100527e6000600060035af15060005450c760006002551309f562","0x200"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":629,"op":127,"gas":"0x3de47","gasCost":"0x3","memSize":544,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":662,"op":97,"gas":"0x3de44","gasCost":"0x3","memSize":544,"stack":["0x66a486610140527f6b001d4571610120527f600054501c641d373c7f60045450"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":665,"op":82,"gas":"0x3de41","gasCost":"0x6","memSize":544,"stack":["0x66a486610140527f6b001d4571610120527f600054501c641d373c7f60045450","0x220"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":666,"op":127,"gas":"0x3de3b","gasCost":"0x3","memSize":576,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":699,"op":97,"gas":"0x3de38","gasCost":"0x3","memSize":576,"stack":["0x6000600155600554610160527f50600160025560085450610140527f60006002"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":702,"op":82,"gas":"0x3de35","gasCost":"0x6","memSize":576,"stack":["0x6000600155600554610160527f50600160025560085450610140527f60006002","0x240"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":703,"op":127,"gas":"0x3de2f","gasCost":"0x3","memSize":608,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":736,"op":97,"gas":"0x3de2c","gasCost":"0x3","memSize":608,"stack":["0x557fd86000606000527e600060610180527e600060005af15086121714514735"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":739,"op":82,"gas":"0x3de29","gasCost":"0x6","memSize":608,"stack":["0x557fd86000606000527e600060610180527e600060005af15086121714514735","0x260"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":740,"op":127,"gas":"0x3de23","gasCost":"0x3","memSize":640,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":773,"op":97,"gas":"0x3de20","gasCost":"0x3","memSize":640,"stack":["0x610160527f5198a37e127a7efa7c6000526101a0527f606020527f6060205360"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":776,"op":82,"gas":"0x3de1d","gasCost":"0x6","memSize":640,"stack":["0x610160527f5198a37e127a7efa7c6000526101a0527f606020527f6060205360","0x280"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":777,"op":127,"gas":"0x3de17","gasCost":"0x3","memSize":672,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":810,"op":97,"gas":"0x3de14","gasCost":"0x3","memSize":672,"stack":["0xf760215360ff60225360610180527fdb6023536037606101c0527f2453607560"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":813,"op":82,"gas":"0x3de11","gasCost":"0x6","memSize":672,"stack":["0xf760215360ff60225360610180527fdb6023536037606101c0527f2453607560","0x2a0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":814,"op":127,"gas":"0x3de0b","gasCost":"0x3","memSize":704,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":847,"op":97,"gas":"0x3de08","gasCost":"0x3","memSize":704,"stack":["0x2553609f606040527f265360fe602753608f60286101a0527f53606101e0527f"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":850,"op":82,"gas":"0x3de05","gasCost":"0x7","memSize":704,"stack":["0x2553609f606040527f265360fe602753608f60286101a0527f53606101e0527f","0x2c0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":851,"op":127,"gas":"0x3ddfe","gasCost":"0x3","memSize":736,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":884,"op":97,"gas":"0x3ddfb","gasCost":"0x3","memSize":736,"stack":["0xb6029536060602a536000602b536060602c5360605260606080536000606101"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":887,"op":82,"gas":"0x3ddf8","gasCost":"0x6","memSize":736,"stack":["0xb6029536060602a536000602b536060602c5360605260606080536000606101","0x2e0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":888,"op":127,"gas":"0x3ddf2","gasCost":"0x3","memSize":768,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":921,"op":97,"gas":"0x3ddef","gasCost":"0x3","memSize":768,"stack":["0x610200527fc0527f81536060608253602d6083536053608453606060855360fd"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":924,"op":82,"gas":"0x3ddec","gasCost":"0x6","memSize":768,"stack":["0x610200527fc0527f81536060608253602d6083536053608453606060855360fd","0x300"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":925,"op":127,"gas":"0x3dde6","gasCost":"0x3","memSize":800,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":958,"op":97,"gas":"0x3dde3","gasCost":"0x3","memSize":800,"stack":["0x6086536060610220527f6087536101e0527f602e60885360536089536060608a"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":961,"op":82,"gas":"0x3dde0","gasCost":"0x6","memSize":800,"stack":["0x6086536060610220527f6087536101e0527f602e60885360536089536060608a","0x320"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":962,"op":127,"gas":"0x3ddda","gasCost":"0x3","memSize":832,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":995,"op":97,"gas":"0x3ddd7","gasCost":"0x3","memSize":832,"stack":["0x53602f608b536060608c610240527f536000608d5360f3610200526060610220"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":998,"op":82,"gas":"0x3ddd4","gasCost":"0x6","memSize":832,"stack":["0x53602f608b536060608c610240527f536000608d5360f3610200526060610220","0x340"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":999,"op":127,"gas":"0x3ddce","gasCost":"0x3","memSize":864,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1032,"op":97,"gas":"0x3ddcb","gasCost":"0x3","memSize":864,"stack":["0x53608e610221536053610222536060610260527f610223536000610224536060"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1035,"op":82,"gas":"0x3ddc8","gasCost":"0x6","memSize":864,"stack":["0x53608e610221536053610222536060610260527f610223536000610224536060","0x360"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1036,"op":127,"gas":"0x3ddc2","gasCost":"0x3","memSize":896,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1069,"op":97,"gas":"0x3ddbf","gasCost":"0x3","memSize":896,"stack":["0x61022553608f6102265360606102275360006102610280527f28536060610229"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1072,"op":82,"gas":"0x3ddbc","gasCost":"0x6","memSize":896,"stack":["0x61022553608f6102265360606102275360006102610280527f28536060610229","0x380"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1073,"op":127,"gas":"0x3ddb6","gasCost":"0x3","memSize":928,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1106,"op":97,"gas":"0x3ddb3","gasCost":"0x3","memSize":928,"stack":["0x53600061022a5360f561022b53606061022c53600061022d536102a0527f6060"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1109,"op":82,"gas":"0x3ddb0","gasCost":"0x6","memSize":928,"stack":["0x53600061022a5360f561022b53606061022c53600061022d536102a0527f6060","0x3a0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1110,"op":127,"gas":"0x3ddaa","gasCost":"0x3","memSize":960,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1143,"op":97,"gas":"0x3dda7","gasCost":"0x3","memSize":960,"stack":["0x61022e53600061022f5360606102305360006102315360606102325360006102"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1146,"op":82,"gas":"0x3dda4","gasCost":"0x6","memSize":960,"stack":["0x61022e53600061022f5360606102305360006102315360606102325360006102","0x3c0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1147,"op":127,"gas":"0x3dd9e","gasCost":"0x3","memSize":992,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1180,"op":97,"gas":"0x3dd9b","gasCost":"0x3","memSize":992,"stack":["0xc0527f61023353606061023453600061023553608561023653605a6102375360"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1183,"op":82,"gas":"0x3dd98","gasCost":"0x7","memSize":992,"stack":["0xc0527f61023353606061023453600061023553608561023653605a6102375360","0x3e0"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1184,"op":127,"gas":"0x3dd91","gasCost":"0x3","memSize":1024,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1217,"op":97,"gas":"0x3dd8e","gasCost":"0x3","memSize":1024,"stack":["0xf261026102e05260386103005360536103015360606103025360506103035360"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1220,"op":82,"gas":"0x3dd8b","gasCost":"0x6","memSize":1024,"stack":["0xf261026102e05260386103005360536103015360606103025360506103035360","0x400"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1221,"op":127,"gas":"0x3dd85","gasCost":"0x3","memSize":1056,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1254,"op":97,"gas":"0x3dd82","gasCost":"0x3","memSize":1056,"stack":["0x6161030453600261030553603961030653605361030753606061030853605061"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1257,"op":82,"gas":"0x3dd7f","gasCost":"0x6","memSize":1056,"stack":["0x6161030453600261030553603961030653605361030753606061030853605061","0x420"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1258,"op":127,"gas":"0x3dd79","gasCost":"0x3","memSize":1088,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1291,"op":97,"gas":"0x3dd76","gasCost":"0x3","memSize":1088,"stack":["0x30953606161030a53600261030b53603a61030c53605361030d53606161030e"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1294,"op":82,"gas":"0x3dd73","gasCost":"0x6","memSize":1088,"stack":["0x30953606161030a53600261030b53603a61030c53605361030d53606161030e","0x440"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1295,"op":127,"gas":"0x3dd6d","gasCost":"0x3","memSize":1120,"stack":[],"depth":3,"refund":0,"opName":"PUSH32"} +{"pc":1328,"op":97,"gas":"0x3dd6a","gasCost":"0x3","memSize":1120,"stack":["0x53600261030f53603b6103105360606103115360006103125360f36103135361"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1331,"op":82,"gas":"0x3dd67","gasCost":"0x6","memSize":1120,"stack":["0x53600261030f53603b6103105360606103115360006103125360f36103135361","0x460"],"depth":3,"refund":0,"opName":"MSTORE"} +{"pc":1332,"op":96,"gas":"0x3dd61","gasCost":"0x3","memSize":1152,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1334,"op":97,"gas":"0x3dd5e","gasCost":"0x3","memSize":1152,"stack":["0x3"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1337,"op":83,"gas":"0x3dd5b","gasCost":"0x6","memSize":1152,"stack":["0x3","0x480"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1338,"op":96,"gas":"0x3dd55","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1340,"op":97,"gas":"0x3dd52","gasCost":"0x3","memSize":1184,"stack":["0x14"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1343,"op":83,"gas":"0x3dd4f","gasCost":"0x3","memSize":1184,"stack":["0x14","0x481"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1344,"op":96,"gas":"0x3dd4c","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1346,"op":97,"gas":"0x3dd49","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1349,"op":83,"gas":"0x3dd46","gasCost":"0x3","memSize":1184,"stack":["0x60","0x482"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1350,"op":96,"gas":"0x3dd43","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1352,"op":97,"gas":"0x3dd40","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1355,"op":83,"gas":"0x3dd3d","gasCost":"0x3","memSize":1184,"stack":["0x0","0x483"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1356,"op":96,"gas":"0x3dd3a","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1358,"op":97,"gas":"0x3dd37","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1361,"op":83,"gas":"0x3dd34","gasCost":"0x3","memSize":1184,"stack":["0x60","0x484"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1362,"op":96,"gas":"0x3dd31","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1364,"op":97,"gas":"0x3dd2e","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1367,"op":83,"gas":"0x3dd2b","gasCost":"0x3","memSize":1184,"stack":["0x0","0x485"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1368,"op":96,"gas":"0x3dd28","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1370,"op":97,"gas":"0x3dd25","gasCost":"0x3","memSize":1184,"stack":["0xf0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1373,"op":83,"gas":"0x3dd22","gasCost":"0x3","memSize":1184,"stack":["0xf0","0x486"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1374,"op":96,"gas":"0x3dd1f","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1376,"op":97,"gas":"0x3dd1c","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1379,"op":83,"gas":"0x3dd19","gasCost":"0x3","memSize":1184,"stack":["0x60","0x487"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1380,"op":96,"gas":"0x3dd16","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1382,"op":97,"gas":"0x3dd13","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1385,"op":83,"gas":"0x3dd10","gasCost":"0x3","memSize":1184,"stack":["0x0","0x488"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1386,"op":96,"gas":"0x3dd0d","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1388,"op":97,"gas":"0x3dd0a","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1391,"op":83,"gas":"0x3dd07","gasCost":"0x3","memSize":1184,"stack":["0x60","0x489"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1392,"op":96,"gas":"0x3dd04","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1394,"op":97,"gas":"0x3dd01","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1397,"op":83,"gas":"0x3dcfe","gasCost":"0x3","memSize":1184,"stack":["0x0","0x48a"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1398,"op":96,"gas":"0x3dcfb","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1400,"op":97,"gas":"0x3dcf8","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1403,"op":83,"gas":"0x3dcf5","gasCost":"0x3","memSize":1184,"stack":["0x60","0x48b"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1404,"op":96,"gas":"0x3dcf2","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1406,"op":97,"gas":"0x3dcef","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1409,"op":83,"gas":"0x3dcec","gasCost":"0x3","memSize":1184,"stack":["0x0","0x48c"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1410,"op":96,"gas":"0x3dce9","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1412,"op":97,"gas":"0x3dce6","gasCost":"0x3","memSize":1184,"stack":["0x60"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1415,"op":83,"gas":"0x3dce3","gasCost":"0x3","memSize":1184,"stack":["0x60","0x48d"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1416,"op":96,"gas":"0x3dce0","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1418,"op":97,"gas":"0x3dcdd","gasCost":"0x3","memSize":1184,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1421,"op":83,"gas":"0x3dcda","gasCost":"0x3","memSize":1184,"stack":["0x0","0x48e"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1422,"op":96,"gas":"0x3dcd7","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1424,"op":97,"gas":"0x3dcd4","gasCost":"0x3","memSize":1184,"stack":["0x84"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1427,"op":83,"gas":"0x3dcd1","gasCost":"0x3","memSize":1184,"stack":["0x84","0x48f"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1428,"op":96,"gas":"0x3dcce","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1430,"op":97,"gas":"0x3dccb","gasCost":"0x3","memSize":1184,"stack":["0x5a"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1433,"op":83,"gas":"0x3dcc8","gasCost":"0x3","memSize":1184,"stack":["0x5a","0x490"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1434,"op":96,"gas":"0x3dcc5","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1436,"op":97,"gas":"0x3dcc2","gasCost":"0x3","memSize":1184,"stack":["0xf4"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1439,"op":83,"gas":"0x3dcbf","gasCost":"0x3","memSize":1184,"stack":["0xf4","0x491"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1440,"op":96,"gas":"0x3dcbc","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1442,"op":97,"gas":"0x3dcb9","gasCost":"0x3","memSize":1184,"stack":["0x50"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1445,"op":83,"gas":"0x3dcb6","gasCost":"0x3","memSize":1184,"stack":["0x50","0x492"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1446,"op":96,"gas":"0x3dcb3","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1448,"op":97,"gas":"0x3dcb0","gasCost":"0x3","memSize":1184,"stack":["0x50"],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1451,"op":83,"gas":"0x3dcad","gasCost":"0x3","memSize":1184,"stack":["0x50","0x493"],"depth":3,"refund":0,"opName":"MSTORE8"} +{"pc":1452,"op":97,"gas":"0x3dcaa","gasCost":"0x3","memSize":1184,"stack":[],"depth":3,"refund":0,"opName":"PUSH2"} +{"pc":1455,"op":96,"gas":"0x3dca7","gasCost":"0x3","memSize":1184,"stack":["0x494"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":1457,"op":243,"gas":"0x3dca4","gasCost":"0x0","memSize":1184,"stack":["0x494","0x0"],"depth":3,"refund":0,"opName":"RETURN"} +{"output":"600160045560006004556000600060006000600060f95af250600060006000600060f45af4506000600060006000600060f55af150f001075205846a44a283448ca2600060006000600060045af450519930847f3b631c54a49b5f600354503277306b60006000600060006000600c5af150600060006000600060f85af4505006600160025560035450600060005560006001556c3394fff4607f7f1684317b387b9f1920700184809d60015450011899016e6009ff60026001556000527f9f6000527f9981600160045582600eff600060006000600060f65af4506000606020527e600060006020527f60f75af4501d7f190316666000600060006000600060046040527f5af1506000600060006040527f600060095af4503c95138e5b8f7f605a6000536060527f6031600153606b6002536010606060527f0353604560045360606005536001606080527e527f60065360606007536002600853606080527f556009536060600a53600160a0527f600b536060600c6020527f536000600d536055600e60a0527f536060600f536060c0527f0160105360606011536002601253606040527f55601353606060c0527f60145360e0527f60006015536060601653600060175360f360185360196060605260006060e052610100527f7f805360f3608153608260006000f06000600060006000845af4505060006000610120527f60610100527e6000600060035af15060005450c760006002551309f56266a486610140527f6b001d4571610120527f600054501c641d373c7f600454506000600155600554610160527f50600160025560085450610140527f60006002557fd86000606000527e600060610180527e600060005af15086121714514735610160527f5198a37e127a7efa7c6000526101a0527f606020527f6060205360f760215360ff60225360610180527fdb6023536037606101c0527f24536075602553609f606040527f265360fe602753608f60286101a0527f53606101e0527f0b6029536060602a536000602b536060602c5360605260606080536000606101610200527fc0527f81536060608253602d6083536053608453606060855360fd6086536060610220527f6087536101e0527f602e60885360536089536060608a53602f608b536060608c610240527f536000608d5360f361020052606061022053608e610221536053610222536060610260527f61022353600061022453606061022553608f6102265360606102275360006102610280527f2853606061022953600061022a5360f561022b53606061022c53600061022d536102a0527f606061022e53600061022f5360606102305360006102315360606102325360006102c0527f61023353606061023453600061023553608561023653605a6102375360f261026102e052603861030053605361030153606061030253605061030353606161030453600261030553603961030653605361030753606061030853605061030953606161030a53600261030b53603a61030c53605361030d53606161030e53600261030f53603b6103105360606103115360006103125360f36103135361031460006000f06000600060006000845af45050","gasUsed":"0x3a6e6"} +{"pc":1773,"op":96,"gas":"0x5903","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1775,"op":96,"gas":"0x5900","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1777,"op":96,"gas":"0x58fd","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1779,"op":96,"gas":"0x58fa","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1781,"op":96,"gas":"0x58f7","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} +{"pc":1783,"op":133,"gas":"0x58f4","gasCost":"0x3","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"DUP6"} +{"pc":1784,"op":90,"gas":"0x58f1","gasCost":"0x2","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0","0x0","0x0","0x0","0x94a843a7335fc63be036fbdecc40b1365f3c5f26"],"depth":2,"refund":0,"opName":"GAS"} +{"pc":1785,"op":241,"gas":"0x58ef","gasCost":"0x578d","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0","0x0","0x0","0x0","0x0","0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x58ef"],"depth":2,"refund":0,"opName":"CALL"} +{"pc":0,"op":96,"gas":"0x5729","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x5726","gasCost":"0x3","memSize":0,"stack":["0x1"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":85,"gas":"0x5723","gasCost":"0x4e20","memSize":0,"stack":["0x1","0x4"],"depth":3,"refund":0,"opName":"SSTORE"} +{"pc":5,"op":96,"gas":"0x903","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":7,"op":96,"gas":"0x900","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":3,"refund":0,"opName":"PUSH1"} +{"pc":9,"op":85,"gas":"0x8fd","gasCost":"0x64","memSize":0,"stack":["0x0","0x4"],"depth":3,"refund":19900,"opName":"SSTORE"} +{"pc":10,"op":96,"gas":"0x899","gasCost":"0x3","memSize":0,"stack":[],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":12,"op":96,"gas":"0x896","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":14,"op":96,"gas":"0x893","gasCost":"0x3","memSize":0,"stack":["0x0","0x0"],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":16,"op":96,"gas":"0x890","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0"],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":18,"op":96,"gas":"0x88d","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":20,"op":96,"gas":"0x88a","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":3,"refund":19900,"opName":"PUSH1"} +{"pc":22,"op":90,"gas":"0x887","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xf9"],"depth":3,"refund":19900,"opName":"GAS"} +{"pc":23,"op":242,"gas":"0x885","gasCost":"0x64","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xf9","0x885"],"depth":3,"refund":19900,"opName":"CALLCODE","error":"out of gas: out of gas"} +{"output":"","gasUsed":"0x5729","error":"out of gas: out of gas"} +{"pc":1786,"op":80,"gas":"0x162","gasCost":"0x2","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26","0x0"],"depth":2,"refund":0,"opName":"POP"} +{"pc":1787,"op":80,"gas":"0x160","gasCost":"0x2","memSize":1472,"stack":["0x94a843a7335fc63be036fbdecc40b1365f3c5f26"],"depth":2,"refund":0,"opName":"POP"} +{"pc":1788,"op":0,"gas":"0x15e","gasCost":"0x0","memSize":1472,"stack":[],"depth":2,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x47f70"} +{"pc":2618,"op":80,"gas":"0x13aa","gasCost":"0x2","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba","0x1"],"depth":1,"refund":0,"opName":"POP"} +{"pc":2619,"op":80,"gas":"0x13a8","gasCost":"0x2","memSize":2240,"stack":["0x7dce2faf43218578e3fcf2ad22df9918a89e2fba"],"depth":1,"refund":0,"opName":"POP"} +{"pc":2620,"op":0,"gas":"0x13a6","gasCost":"0x0","memSize":2240,"stack":[],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0xb2e6d"} +{"stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458"} diff --git a/cmd/evm/testdata/statetest.json b/cmd/evm/testdata/statetest.json new file mode 100755 index 000000000..3b2a91987 --- /dev/null +++ b/cmd/evm/testdata/statetest.json @@ -0,0 +1,57 @@ +{ + "00000006-naivefuzz-0": { + "env": { + "currentCoinbase": "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": "0x200000", + "currentGasLimit": "0x26e1f476fe1e22", + "currentNumber": "0x1", + "currentTimestamp": "0x3e8", + "previousHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "currentBaseFee": "0x10" + }, + "pre": { + "0x00000000000000000000000000000000000000f1": { + "code": "0x60026003556000600060006000600060045af2507f600254506003545060016003557f7f6008545060006004557f600160045560006000527f60045560006000600060006000606000527ff96000527f5af2506000600060006020527f606000527e60f45af45060006000600060006020527f600060f55a6020527ff16040527f50f001075205846a44a283446020527f8ca2600060006040527f6000600060046060527f5af4506040527f519930847f3b631c54a49b5f600354503260406060527f527f6080527f77306b60006000600060006060527f6000600c5af1506000600060006000608060a0527f527f60f85af450506060527f066001600255606080527f03545060006000556060c0527e6060a0527f01556c3394fff4607f7f1684317b6080527f387b9f60a0527f1960e0527f20700184809d60c0527f60015450011899016e6009ff60026001556000527f9f610100527f60a05260c0527f7f600060e0527f527f9981600160045582600eff6000600060610120527e600060f65af45060006060e052610100527f7f6060c0527f20527e60006000610140527f6020527f60f75af4501d7f1903166660006000610120527f60610100527e6000610160527f600060e0527f60046040527f5af150600060006000604052610140527f7f6000610180527f6009610120527f5af4503c95138e5b8f610100527f7f605a60005360606101606101a0527f527f527f6031600153606b60610140527f02536010606060527f0353604560616101c0527f0120610180527f527f04536060600553600160608052610160527f7e527f60066101e0527f536060600753606101a0527f02600853606080610140527f527f556009536060610200527f610180527f600a53600160a06101c0527f527f600b536060600c6020527f5360610220527e60610160527f0d53606101a0527f55606101e0527f0e60a0527f536060600f610240527f536060c0527f01601053606060115360026101806101610200527fc0527f527f610260527f601253606040527f55601353606060c0527f60145360e0527f6000610220527f610280527f6015536101e0527f60606101a0527f601653600060175360f3601853601960606102a0527f610240527f605260006060e052610200527f610100527f7f806101c0527f53606102c0527ff360815360610260527f8260006000f060006000600060610220527e845af4506102e0527f506000600061016101e0610280527f527f20527f60610100527e600060006003610300527f610240527f5af15060005450c760006102a0527f6002551309f562610200527f610320527f66a486610140527f6b00610260527f1d457161016102c0527f20527f60005450610340527f1c641d373c7f60045450610220527f6000600155610280527f6102e0527f6005610360527f54610160527f50600160025560085450610140527f60006002610240527f6103610380527e527f6102a0527f557fd86000606000527e600060610180527e600060005af16103a0527f508612610320527f17145147356102c0527f610260527f610160527f5198a37e6103c0527f127a7efa7c600052610340527f6101a0527f606020527f6102e0527f606020536103e0527f60610280527ff760215360ff60610360527f225360610180527fdb6023536037610400527f60610300527f6101c0527f24536075606102610380527fa0527f2553609f6060610420527f40527f265360fe60275360610320527f8f60286101a0526103a0527f7f536061610440527f01e0527f6102c0527f0b6029536060602a53600060610340527f2b536103c052610460527f7f6060602c53606052606060805360006061016102e0527f610200527fc05261610480527f036103e0527f60527f7f81536060608253602d608353605360845360606085536104a0527f60fd61030052610400527f7f6086610380527f536060610220527f60875361016104c0527fe0527f602e608853605360610420527f89536060608a61036103a0527f20527f6104e0527f53602f608b536060608c610240527f53610440527f6000608d5360f361020052610500527f60606103c0527f610220610340527f53608e610221610460527f536053610222610520527f536060610260527f610223536103e0527f600061022453606061610480527f03610540527f60527f61022553608f61022653606061022753600061610400527f0261028061610560527f04a0527f527f28536060610229610380527f53600061022a5360f561022b5360610580527f610420526104c0527f7f6061022c53600061022d536102a0527f60606103a0526105a0527f7f61022e53600061026104e0527f2f610440527f5360606102305360006102316105c0527f53606061023253600061026103c0610500527f527fc0527f61610460527f02336105e0527f53606061023453600061023553608561023653610520527f605a610237536061610600527f03e052610480527f7ff261026102e0526038610300536053610540527f610301610620527f536060610302536050610303536104a0527f60610400527f6161030453610560610640527f527f6002610305536039610306536053610307536060616104c0527f03085360610660527f5061610580527f610420527f030953606161030a53600261030b53603a61030c610680527f536104e0527f606105a0527f5361030d53606161030e610440527f53600261036106a0527f0f53603b61031053606061616105c0527f0500527f03115360006103125360f36106c0527f61031353616104605260036104805360146105e0527f61048153610520527f606106e0527f60610482536000610483536060610484536000610485610600527f5360f06104610700527f86536060610540527f610487536000610488536060610489536000610620527f610720527f61048a53606061048b5360006104610560527f8c53606061048d53600061048e610740527f610640527f53608461048f53605a6104905360f4610491536105805260606105610760527fa053605061610660527f05a15360616105a25360046105a35360926105a45360610780527f536105a55360606105a6610680527f5360506105a75360616105a853600461056107a0527fa95360936105aa5360536105ab53606106a0527f616105ac5360046105ad53606107c0527f946105ae5360606105af5360006105b05360f3616106c05260056106e05360b16107e0527f6106e15360536106e25360606106e35360006106e45360616106e55360056106610800527fe65360b26106e75360606106e85360006106e95360606106ea5360006106eb53610820527f60f56106ec5360606106ed5360006106ee5360606106ef5360006106f0536060610840527f6106f15360006106f25360606106f35360006106f45360606106f55360006106610860527ff65360856106f753605a6106f85360f16106f95360506106fa5360506106fb536108805260616108a05360066108a15360fc6108a25360606108a35360006108a45360f36108a5536108a660006000f060006000600060006000855af15050", + "storage": {}, + "balance": "0x0", + "nonce": "0x0" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "code": "0x", + "storage": {}, + "balance": "0xffffffffff", + "nonce": "0x0" + } + }, + "transaction": { + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "gasPrice": "0x10", + "nonce": "0x0", + "to": "0x00000000000000000000000000000000000000f1", + "data": [ + "0x81fbe24d1e33d7944b2e62ee0ff24811bbbcf8cb311e5617c80623dec4477cc14849fc042b9bbaebca9f03f66cca76c46353c5a68c2e134ef75f8c2425d9702f3a4bd3c5527e93d27579bdbd7d237eaa1c0278fce26479aaf11fb8d00e7478" + ], + "gasLimit": [ + "0xb9a0b" + ], + "value": [ + "0x01" + ], + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + "out": "0x", + "post": { + "London": [ + { + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logs": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexes": { + "data": 0, + "gas": 0, + "value": 0 + } + } + ] + } + } +} \ No newline at end of file diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d351c0903..aaad261a1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -758,7 +758,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block logConfig = config.Config txHash = config.TxHash } - logConfig.Debug = true // Execute transaction, either tracing all or just the requested one var ( diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 51b1512d0..dc9e6e62b 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -45,9 +45,7 @@ type Config struct { DisableStack bool // disable stack capture DisableStorage bool // disable storage capture EnableReturnData bool // enable return data capture - Debug bool // print output during capture end Limit int // maximum size of output, but zero means unlimited - // Chain overrides, can be used to execute a trace using future fork rules Overrides *params.ChainConfig `json:"overrides,omitempty"` } @@ -324,12 +322,13 @@ func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err erro } l.output = output l.err = err - if l.cfg.Debug { - fmt.Printf("%#x\n", output) - if err != nil { - fmt.Printf(" error: %v\n", err) - } - } + // TODO @holiman, should we output the per-scope output? + //if l.cfg.Debug { + // fmt.Printf("%#x\n", output) + // if err != nil { + // fmt.Printf(" error: %v\n", err) + // } + //} } func (l *StructLogger) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 13c36379e..a72dbf6ee 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -88,7 +88,7 @@ func BenchmarkTransactionTraceV2(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - tracer := logger.NewStructLogger(&logger.Config{Debug: false}).Hooks() + tracer := logger.NewStructLogger(&logger.Config{}).Hooks() tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) evm.Config.Tracer = tracer From a70222ce3ecf8696fcad9c079ecce10a26a29217 Mon Sep 17 00:00:00 2001 From: Zheyuan He Date: Tue, 10 Dec 2024 20:10:17 +0800 Subject: [PATCH 037/354] core/vm: remove unnecessary comment (#30887) --- core/vm/instructions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index ee1d655b3..23822e0e8 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -506,7 +506,6 @@ func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - // pop value of the stack mStart, val := scope.Stack.pop(), scope.Stack.pop() scope.Memory.Set32(mStart.Uint64(), &val) return nil, nil From db4e4c33976c517cf1cf4a8cf3d612807bf68e1b Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 10 Dec 2024 13:27:29 +0100 Subject: [PATCH 038/354] metrics, cmd/geth: change init-process of metrics (#30814) This PR modifies how the metrics library handles `Enabled`: previously, the package `init` decided whether to serve real metrics or just dummy-types. This has several drawbacks: - During pkg init, we need to determine whether metrics are enabled or not. So we first hacked in a check if certain geth-specific commandline-flags were enabled. Then we added a similar check for geth-env-vars. Then we almost added a very elaborate check for toml-config-file, plus toml parsing. - Using "real" types and dummy types interchangeably means that everything is hidden behind interfaces. This has a performance penalty, and also it just adds a lot of code. This PR removes the interface stuff, uses concrete types, and allows for the setting of Enabled to happen later. It is still assumed that `metrics.Enable()` is invoked early on. The somewhat 'heavy' operations, such as ticking meters and exp-decay, now checks the enable-flag to prevent resource leak. The change may be large, but it's mostly pretty trivial, and from the last time I gutted the metrics, I ensured that we have fairly good test coverage. --------- Co-authored-by: Felix Lange --- cmd/geth/chaincmd.go | 11 +- cmd/geth/config.go | 24 +++ cmd/geth/main.go | 7 - cmd/utils/flags.go | 103 +++++----- core/rawdb/freezer_table.go | 12 +- core/state/trie_prefetcher.go | 32 +-- core/txpool/txpool.go | 4 +- eth/downloader/queue.go | 2 +- eth/handler.go | 2 +- eth/protocols/eth/handler.go | 2 +- eth/protocols/eth/handshake.go | 2 +- eth/protocols/eth/metrics.go | 12 +- eth/protocols/snap/handler.go | 2 +- ethdb/leveldb/leveldb.go | 30 +-- ethdb/pebble/pebble.go | 30 +-- metrics/counter.go | 94 ++------- metrics/counter_float64.go | 103 +++------- metrics/counter_float_64_test.go | 58 ++---- metrics/counter_test.go | 38 ++-- metrics/debug.go | 8 +- metrics/ewma.go | 64 +++--- metrics/ewma_test.go | 14 +- metrics/exp/exp.go | 22 +-- metrics/gauge.go | 84 +++----- metrics/gauge_float64.go | 65 ++---- metrics/gauge_info.go | 50 ++--- metrics/graphite.go | 117 ----------- metrics/graphite_test.go | 22 --- metrics/healthcheck.go | 44 +---- metrics/histogram.go | 23 ++- metrics/inactive.go | 48 ----- metrics/influxdb/influxdb.go | 16 +- metrics/influxdb/influxdb_test.go | 2 +- metrics/init_test.go | 2 +- metrics/log.go | 18 +- metrics/meter.go | 156 +++++++-------- metrics/meter_test.go | 12 +- metrics/metrics.go | 57 ++---- metrics/metrics_test.go | 71 ++----- metrics/opentsdb.go | 14 +- metrics/prometheus/collector.go | 22 +-- metrics/prometheus/collector_test.go | 2 +- metrics/registry.go | 39 ++-- metrics/registry_test.go | 18 +- metrics/resetting_sample.go | 2 +- metrics/resetting_timer.go | 90 +++------ metrics/sample.go | 282 +++++++++++++-------------- metrics/sample_test.go | 14 +- metrics/syslog.go | 16 +- metrics/timer.go | 104 ++++------ metrics/writer.go | 16 +- p2p/discover/metrics.go | 4 +- p2p/discover/table.go | 4 +- p2p/metrics.go | 35 +--- p2p/peer.go | 2 +- p2p/tracker/tracker.go | 4 +- p2p/transport.go | 2 +- triedb/pathdb/states.go | 2 +- 58 files changed, 739 insertions(+), 1396 deletions(-) delete mode 100644 metrics/graphite.go delete mode 100644 metrics/graphite_test.go delete mode 100644 metrics/inactive.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index f6dc1cf4b..48564eb5e 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -38,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/era" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -282,14 +281,12 @@ func importChain(ctx *cli.Context) error { if ctx.Args().Len() < 1 { utils.Fatalf("This command requires an argument.") } - // Start metrics export if enabled - utils.SetupMetrics(ctx) - // Start system runtime metrics collection - go metrics.CollectProcessMetrics(3 * time.Second) - - stack, _ := makeConfigNode(ctx) + stack, cfg := makeConfigNode(ctx) defer stack.Close() + // Start metrics export if enabled + utils.SetupMetrics(&cfg.Metrics) + chain, db := utils.MakeChain(ctx, stack, false) defer db.Close() diff --git a/cmd/geth/config.go b/cmd/geth/config.go index de4f67dba..9b1f2d0c7 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -193,6 +193,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { cfg.Eth.OverrideVerkle = &v } + // Start metrics export if enabled + utils.SetupMetrics(&cfg.Metrics) + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Create gauge with geth system and build information @@ -326,6 +329,27 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name) } + // Sanity-check the commandline flags. It is fine if some unused fields is part + // of the toml-config, but we expect the commandline to only contain relevant + // arguments, otherwise it indicates an error. + var ( + enableExport = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name) + enableExportV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name) + ) + if enableExport || enableExportV2 { + v1FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) || + ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) + + v2FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) || + ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) || + ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) + + if enableExport && v2FlagIsSet { + utils.Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2") + } else if enableExportV2 && v1FlagIsSet { + utils.Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1") + } + } } func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ec8d299cb..d9a37e99e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -40,7 +40,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "go.uber.org/automaxprocs/maxprocs" @@ -345,12 +344,6 @@ func prepare(ctx *cli.Context) { ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096)) } } - - // Start metrics export if enabled - utils.SetupMetrics(ctx) - - // Start system runtime metrics collection - go metrics.CollectProcessMetrics(3 * time.Second) } // geth is the main entry point into the system if no special subcommand is run. diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a350fd36c..e994de0b1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2143,67 +2143,56 @@ func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, target common.H log.Info("Registered full-sync tester", "hash", target) } -func SetupMetrics(ctx *cli.Context) { - if metrics.Enabled { - log.Info("Enabling metrics collection") - - var ( - enableExport = ctx.Bool(MetricsEnableInfluxDBFlag.Name) - enableExportV2 = ctx.Bool(MetricsEnableInfluxDBV2Flag.Name) - ) - - if enableExport || enableExportV2 { - CheckExclusive(ctx, MetricsEnableInfluxDBFlag, MetricsEnableInfluxDBV2Flag) - - v1FlagIsSet := ctx.IsSet(MetricsInfluxDBUsernameFlag.Name) || - ctx.IsSet(MetricsInfluxDBPasswordFlag.Name) - - v2FlagIsSet := ctx.IsSet(MetricsInfluxDBTokenFlag.Name) || - ctx.IsSet(MetricsInfluxDBOrganizationFlag.Name) || - ctx.IsSet(MetricsInfluxDBBucketFlag.Name) - - if enableExport && v2FlagIsSet { - Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2") - } else if enableExportV2 && v1FlagIsSet { - Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1") - } - } - - var ( - endpoint = ctx.String(MetricsInfluxDBEndpointFlag.Name) - database = ctx.String(MetricsInfluxDBDatabaseFlag.Name) - username = ctx.String(MetricsInfluxDBUsernameFlag.Name) - password = ctx.String(MetricsInfluxDBPasswordFlag.Name) - - token = ctx.String(MetricsInfluxDBTokenFlag.Name) - bucket = ctx.String(MetricsInfluxDBBucketFlag.Name) - organization = ctx.String(MetricsInfluxDBOrganizationFlag.Name) - ) - - if enableExport { - tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name)) - - log.Info("Enabling metrics export to InfluxDB") - - go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) - } else if enableExportV2 { - tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name)) - - log.Info("Enabling metrics export to InfluxDB (v2)") - - go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap) - } +// SetupMetrics configures the metrics system. +func SetupMetrics(cfg *metrics.Config) { + if !cfg.Enabled { + return + } + log.Info("Enabling metrics collection") + metrics.Enable() - if ctx.IsSet(MetricsHTTPFlag.Name) { - address := net.JoinHostPort(ctx.String(MetricsHTTPFlag.Name), fmt.Sprintf("%d", ctx.Int(MetricsPortFlag.Name))) - log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) - exp.Setup(address) - } else if ctx.IsSet(MetricsPortFlag.Name) { - log.Warn(fmt.Sprintf("--%s specified without --%s, metrics server will not start.", MetricsPortFlag.Name, MetricsHTTPFlag.Name)) - } + // InfluxDB exporter. + var ( + enableExport = cfg.EnableInfluxDB + enableExportV2 = cfg.EnableInfluxDBV2 + ) + if cfg.EnableInfluxDB && cfg.EnableInfluxDBV2 { + Fatalf("Flags %v can't be used at the same time", strings.Join([]string{MetricsEnableInfluxDBFlag.Name, MetricsEnableInfluxDBV2Flag.Name}, ", ")) } + var ( + endpoint = cfg.InfluxDBEndpoint + database = cfg.InfluxDBDatabase + username = cfg.InfluxDBUsername + password = cfg.InfluxDBPassword + + token = cfg.InfluxDBToken + bucket = cfg.InfluxDBBucket + organization = cfg.InfluxDBOrganization + tagsMap = SplitTagsFlag(cfg.InfluxDBTags) + ) + if enableExport { + log.Info("Enabling metrics export to InfluxDB") + go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) + } else if enableExportV2 { + tagsMap := SplitTagsFlag(cfg.InfluxDBTags) + log.Info("Enabling metrics export to InfluxDB (v2)") + go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap) + } + + // Expvar exporter. + if cfg.HTTP != "" { + address := net.JoinHostPort(cfg.HTTP, fmt.Sprintf("%d", cfg.Port)) + log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) + exp.Setup(address) + } else if cfg.HTTP == "" && cfg.Port != 0 { + log.Warn(fmt.Sprintf("--%s specified without --%s, metrics server will not start.", MetricsPortFlag.Name, MetricsHTTPFlag.Name)) + } + + // Enable system metrics collection. + go metrics.CollectProcessMetrics(3 * time.Second) } +// SplitTagsFlag parses a comma-separated list of k=v metrics tags. func SplitTagsFlag(tagsFlag string) map[string]string { tags := strings.Split(tagsFlag, ",") tagsMap := map[string]string{} diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index a8ed17b37..38c47dc22 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -113,10 +113,10 @@ type freezerTable struct { headId uint32 // number of the currently active head file tailId uint32 // number of the earliest file - headBytes int64 // Number of bytes written to the head file - readMeter metrics.Meter // Meter for measuring the effective amount of data read - writeMeter metrics.Meter // Meter for measuring the effective amount of data written - sizeGauge metrics.Gauge // Gauge for tracking the combined size of all freezer tables + headBytes int64 // Number of bytes written to the head file + readMeter *metrics.Meter // Meter for measuring the effective amount of data read + writeMeter *metrics.Meter // Meter for measuring the effective amount of data written + sizeGauge *metrics.Gauge // Gauge for tracking the combined size of all freezer tables logger log.Logger // Logger with database path and table name embedded lock sync.RWMutex // Mutex protecting the data file descriptors @@ -124,13 +124,13 @@ type freezerTable struct { // newFreezerTable opens the given path as a freezer table. func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) { - return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly) + return newTable(path, name, metrics.NewInactiveMeter(), metrics.NewInactiveMeter(), metrics.NewGauge(), freezerTableSize, disableSnappy, readonly) } // newTable opens a freezer table, creating the data and index files if they are // non-existent. Both files are truncated to the shortest common length to ensure // they don't go out of sync. -func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter, sizeGauge metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) { +func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, sizeGauge *metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) { // Ensure the containing directory exists and open the indexEntry file if err := os.MkdirAll(path, 0755); err != nil { return nil, err diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 5b6458343..6f492cf9f 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -47,21 +47,21 @@ type triePrefetcher struct { term chan struct{} // Channel to signal interruption noreads bool // Whether to ignore state-read-only prefetch requests - deliveryMissMeter metrics.Meter - - accountLoadReadMeter metrics.Meter - accountLoadWriteMeter metrics.Meter - accountDupReadMeter metrics.Meter - accountDupWriteMeter metrics.Meter - accountDupCrossMeter metrics.Meter - accountWasteMeter metrics.Meter - - storageLoadReadMeter metrics.Meter - storageLoadWriteMeter metrics.Meter - storageDupReadMeter metrics.Meter - storageDupWriteMeter metrics.Meter - storageDupCrossMeter metrics.Meter - storageWasteMeter metrics.Meter + deliveryMissMeter *metrics.Meter + + accountLoadReadMeter *metrics.Meter + accountLoadWriteMeter *metrics.Meter + accountDupReadMeter *metrics.Meter + accountDupWriteMeter *metrics.Meter + accountDupCrossMeter *metrics.Meter + accountWasteMeter *metrics.Meter + + storageLoadReadMeter *metrics.Meter + storageLoadWriteMeter *metrics.Meter + storageDupReadMeter *metrics.Meter + storageDupWriteMeter *metrics.Meter + storageDupCrossMeter *metrics.Meter + storageWasteMeter *metrics.Meter } func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher { @@ -111,7 +111,7 @@ func (p *triePrefetcher) terminate(async bool) { // report aggregates the pre-fetching and usage metrics and reports them. func (p *triePrefetcher) report() { - if !metrics.Enabled { + if !metrics.Enabled() { return } for _, fetcher := range p.fetchers { diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 1c34f1f44..2450a130e 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -129,7 +129,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver { return ErrAlreadyReserved } p.reservations[addr] = subpool - if metrics.Enabled { + if metrics.Enabled() { m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) metrics.GetOrRegisterGauge(m, nil).Inc(1) } @@ -146,7 +146,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver { return errors.New("address not owned") } delete(p.reservations, addr) - if metrics.Enabled { + if metrics.Enabled() { m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) metrics.GetOrRegisterGauge(m, nil).Dec(1) } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index a2f916ebb..a07a529a7 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -881,7 +881,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt, recei // to access the queue, so they already need a lock anyway. func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, - reqTimer metrics.Timer, resInMeter metrics.Meter, resDropMeter metrics.Meter, + reqTimer *metrics.Timer, resInMeter, resDropMeter *metrics.Meter, results int, validate func(index int, header *types.Header) error, reconstruct func(index int, result *fetchResult)) (int, error) { // Short circuit if the data was never requested diff --git a/eth/handler.go b/eth/handler.go index 3b3304008..03844b0b4 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -431,7 +431,7 @@ func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error defer h.decHandlers() if err := h.peers.registerSnapExtension(peer); err != nil { - if metrics.Enabled { + if metrics.Enabled() { if peer.Inbound() { snap.IngressRegistrationErrorMeter.Mark(1) } else { diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index dc32559c4..28db93a20 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -190,7 +190,7 @@ func handleMessage(backend Backend, peer *Peer) error { var handlers = eth68 // Track the amount of time it takes to serve the request and run the handler - if metrics.Enabled { + if metrics.Enabled() { h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code) defer func(start time.Time) { sampler := func() metrics.Sample { diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index ea16a85b1..68cf84692 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -112,7 +112,7 @@ func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.H // markError registers the error with the corresponding metric. func markError(p *Peer, err error) { - if !metrics.Enabled { + if !metrics.Enabled() { return } m := meters.get(p.Inbound()) diff --git a/eth/protocols/eth/metrics.go b/eth/protocols/eth/metrics.go index 5e0aee39f..adfa84936 100644 --- a/eth/protocols/eth/metrics.go +++ b/eth/protocols/eth/metrics.go @@ -41,23 +41,23 @@ func (h *bidirectionalMeters) get(ingress bool) *hsMeters { type hsMeters struct { // peerError measures the number of errors related to incorrect peer // behaviour, such as invalid message code, size, encoding, etc. - peerError metrics.Meter + peerError *metrics.Meter // timeoutError measures the number of timeouts. - timeoutError metrics.Meter + timeoutError *metrics.Meter // networkIDMismatch measures the number of network id mismatch errors. - networkIDMismatch metrics.Meter + networkIDMismatch *metrics.Meter // protocolVersionMismatch measures the number of differing protocol // versions. - protocolVersionMismatch metrics.Meter + protocolVersionMismatch *metrics.Meter // genesisMismatch measures the number of differing genesises. - genesisMismatch metrics.Meter + genesisMismatch *metrics.Meter // forkidRejected measures the number of differing forkids. - forkidRejected metrics.Meter + forkidRejected *metrics.Meter } // newHandshakeMeters registers and returns handshake meters for the given diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 8164973c2..924aff7ac 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -132,7 +132,7 @@ func HandleMessage(backend Backend, peer *Peer) error { defer msg.Discard() start := time.Now() // Track the amount of time it takes to serve the request and run the handler - if metrics.Enabled { + if metrics.Enabled() { h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code) defer func(start time.Time) { sampler := func() metrics.Sample { diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index ce7d82356..f18503c94 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -62,21 +62,21 @@ type Database struct { fn string // filename for reporting db *leveldb.DB // LevelDB instance - compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction - compReadMeter metrics.Meter // Meter for measuring the data read during compaction - compWriteMeter metrics.Meter // Meter for measuring the data written during compaction - writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction - writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction - diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database - diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read - diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written - memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction - level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 - nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level - seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt - manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC) - - levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels + compTimeMeter *metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter *metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter *metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter *metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter *metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database + diskReadMeter *metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter *metrics.Meter // Meter for measuring the effective amount of data written + memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction + level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0 + nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level + seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt + manualMemAllocGauge *metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC) + + levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels quitLock sync.Mutex // Mutex protecting the quit channel access quitChan chan chan error // Quit channel to stop the metrics collection before closing the database diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index a9151a3bb..8d6fcd2d5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -58,21 +58,21 @@ type Database struct { fn string // filename for reporting db *pebble.DB // Underlying pebble storage engine - compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction - compReadMeter metrics.Meter // Meter for measuring the data read during compaction - compWriteMeter metrics.Meter // Meter for measuring the data written during compaction - writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction - writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction - diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database - diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read - diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written - memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction - level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 - nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level - seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt - manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated - - levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels + compTimeMeter *metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter *metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter *metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter *metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter *metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database + diskReadMeter *metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter *metrics.Meter // Meter for measuring the effective amount of data written + memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction + level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0 + nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level + seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt + manualMemAllocGauge *metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated + + levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag quitChan chan chan error // Quit channel to stop the metrics collection before closing the database diff --git a/metrics/counter.go b/metrics/counter.go index dbe8e16a9..0f373b0d9 100644 --- a/metrics/counter.go +++ b/metrics/counter.go @@ -4,109 +4,55 @@ import ( "sync/atomic" ) -type CounterSnapshot interface { - Count() int64 -} - -// Counter hold an int64 value that can be incremented and decremented. -type Counter interface { - Clear() - Dec(int64) - Inc(int64) - Snapshot() CounterSnapshot -} - // GetOrRegisterCounter returns an existing Counter or constructs and registers -// a new StandardCounter. -func GetOrRegisterCounter(name string, r Registry) Counter { - if nil == r { +// a new Counter. +func GetOrRegisterCounter(name string, r Registry) *Counter { + if r == nil { r = DefaultRegistry } - return r.GetOrRegister(name, NewCounter).(Counter) + return r.GetOrRegister(name, NewCounter).(*Counter) } -// GetOrRegisterCounterForced returns an existing Counter or constructs and registers a -// new Counter no matter the global switch is enabled or not. -// Be sure to unregister the counter from the registry once it is of no use to -// allow for garbage collection. -func GetOrRegisterCounterForced(name string, r Registry) Counter { - if nil == r { - r = DefaultRegistry - } - return r.GetOrRegister(name, NewCounterForced).(Counter) +// NewCounter constructs a new Counter. +func NewCounter() *Counter { + return new(Counter) } -// NewCounter constructs a new StandardCounter. -func NewCounter() Counter { - if !Enabled { - return NilCounter{} - } - return new(StandardCounter) -} - -// NewCounterForced constructs a new StandardCounter and returns it no matter if -// the global switch is enabled or not. -func NewCounterForced() Counter { - return new(StandardCounter) -} - -// NewRegisteredCounter constructs and registers a new StandardCounter. -func NewRegisteredCounter(name string, r Registry) Counter { +// NewRegisteredCounter constructs and registers a new Counter. +func NewRegisteredCounter(name string, r Registry) *Counter { c := NewCounter() - if nil == r { - r = DefaultRegistry - } - r.Register(name, c) - return c -} - -// NewRegisteredCounterForced constructs and registers a new StandardCounter -// and launches a goroutine no matter the global switch is enabled or not. -// Be sure to unregister the counter from the registry once it is of no use to -// allow for garbage collection. -func NewRegisteredCounterForced(name string, r Registry) Counter { - c := NewCounterForced() - if nil == r { + if r == nil { r = DefaultRegistry } r.Register(name, c) return c } -// counterSnapshot is a read-only copy of another Counter. -type counterSnapshot int64 +// CounterSnapshot is a read-only copy of a Counter. +type CounterSnapshot int64 // Count returns the count at the time the snapshot was taken. -func (c counterSnapshot) Count() int64 { return int64(c) } - -// NilCounter is a no-op Counter. -type NilCounter struct{} +func (c CounterSnapshot) Count() int64 { return int64(c) } -func (NilCounter) Clear() {} -func (NilCounter) Dec(i int64) {} -func (NilCounter) Inc(i int64) {} -func (NilCounter) Snapshot() CounterSnapshot { return (*emptySnapshot)(nil) } - -// StandardCounter is the standard implementation of a Counter and uses the -// sync/atomic package to manage a single int64 value. -type StandardCounter atomic.Int64 +// Counter hold an int64 value that can be incremented and decremented. +type Counter atomic.Int64 // Clear sets the counter to zero. -func (c *StandardCounter) Clear() { +func (c *Counter) Clear() { (*atomic.Int64)(c).Store(0) } // Dec decrements the counter by the given amount. -func (c *StandardCounter) Dec(i int64) { +func (c *Counter) Dec(i int64) { (*atomic.Int64)(c).Add(-i) } // Inc increments the counter by the given amount. -func (c *StandardCounter) Inc(i int64) { +func (c *Counter) Inc(i int64) { (*atomic.Int64)(c).Add(i) } // Snapshot returns a read-only copy of the counter. -func (c *StandardCounter) Snapshot() CounterSnapshot { - return counterSnapshot((*atomic.Int64)(c).Load()) +func (c *Counter) Snapshot() CounterSnapshot { + return CounterSnapshot((*atomic.Int64)(c).Load()) } diff --git a/metrics/counter_float64.go b/metrics/counter_float64.go index 15c81494e..91c4215c4 100644 --- a/metrics/counter_float64.go +++ b/metrics/counter_float64.go @@ -5,114 +5,57 @@ import ( "sync/atomic" ) -type CounterFloat64Snapshot interface { - Count() float64 -} - -// CounterFloat64 holds a float64 value that can be incremented and decremented. -type CounterFloat64 interface { - Clear() - Dec(float64) - Inc(float64) - Snapshot() CounterFloat64Snapshot -} - -// GetOrRegisterCounterFloat64 returns an existing CounterFloat64 or constructs and registers -// a new StandardCounterFloat64. -func GetOrRegisterCounterFloat64(name string, r Registry) CounterFloat64 { +// GetOrRegisterCounterFloat64 returns an existing *CounterFloat64 or constructs and registers +// a new CounterFloat64. +func GetOrRegisterCounterFloat64(name string, r Registry) *CounterFloat64 { if nil == r { r = DefaultRegistry } - return r.GetOrRegister(name, NewCounterFloat64).(CounterFloat64) -} - -// GetOrRegisterCounterFloat64Forced returns an existing CounterFloat64 or constructs and registers a -// new CounterFloat64 no matter the global switch is enabled or not. -// Be sure to unregister the counter from the registry once it is of no use to -// allow for garbage collection. -func GetOrRegisterCounterFloat64Forced(name string, r Registry) CounterFloat64 { - if nil == r { - r = DefaultRegistry - } - return r.GetOrRegister(name, NewCounterFloat64Forced).(CounterFloat64) -} - -// NewCounterFloat64 constructs a new StandardCounterFloat64. -func NewCounterFloat64() CounterFloat64 { - if !Enabled { - return NilCounterFloat64{} - } - return &StandardCounterFloat64{} + return r.GetOrRegister(name, NewCounterFloat64).(*CounterFloat64) } -// NewCounterFloat64Forced constructs a new StandardCounterFloat64 and returns it no matter if -// the global switch is enabled or not. -func NewCounterFloat64Forced() CounterFloat64 { - return &StandardCounterFloat64{} +// NewCounterFloat64 constructs a new CounterFloat64. +func NewCounterFloat64() *CounterFloat64 { + return new(CounterFloat64) } -// NewRegisteredCounterFloat64 constructs and registers a new StandardCounterFloat64. -func NewRegisteredCounterFloat64(name string, r Registry) CounterFloat64 { +// NewRegisteredCounterFloat64 constructs and registers a new CounterFloat64. +func NewRegisteredCounterFloat64(name string, r Registry) *CounterFloat64 { c := NewCounterFloat64() - if nil == r { - r = DefaultRegistry - } - r.Register(name, c) - return c -} - -// NewRegisteredCounterFloat64Forced constructs and registers a new StandardCounterFloat64 -// and launches a goroutine no matter the global switch is enabled or not. -// Be sure to unregister the counter from the registry once it is of no use to -// allow for garbage collection. -func NewRegisteredCounterFloat64Forced(name string, r Registry) CounterFloat64 { - c := NewCounterFloat64Forced() - if nil == r { + if r == nil { r = DefaultRegistry } r.Register(name, c) return c } -// counterFloat64Snapshot is a read-only copy of another CounterFloat64. -type counterFloat64Snapshot float64 +// CounterFloat64Snapshot is a read-only copy of a float64 counter. +type CounterFloat64Snapshot float64 // Count returns the value at the time the snapshot was taken. -func (c counterFloat64Snapshot) Count() float64 { return float64(c) } - -type NilCounterFloat64 struct{} +func (c CounterFloat64Snapshot) Count() float64 { return float64(c) } -func (NilCounterFloat64) Clear() {} -func (NilCounterFloat64) Count() float64 { return 0.0 } -func (NilCounterFloat64) Dec(i float64) {} -func (NilCounterFloat64) Inc(i float64) {} -func (NilCounterFloat64) Snapshot() CounterFloat64Snapshot { return NilCounterFloat64{} } - -// StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the -// atomic to manage a single float64 value. -type StandardCounterFloat64 struct { - floatBits atomic.Uint64 -} +// CounterFloat64 holds a float64 value that can be incremented and decremented. +type CounterFloat64 atomic.Uint64 // Clear sets the counter to zero. -func (c *StandardCounterFloat64) Clear() { - c.floatBits.Store(0) +func (c *CounterFloat64) Clear() { + (*atomic.Uint64)(c).Store(0) } // Dec decrements the counter by the given amount. -func (c *StandardCounterFloat64) Dec(v float64) { - atomicAddFloat(&c.floatBits, -v) +func (c *CounterFloat64) Dec(v float64) { + atomicAddFloat((*atomic.Uint64)(c), -v) } // Inc increments the counter by the given amount. -func (c *StandardCounterFloat64) Inc(v float64) { - atomicAddFloat(&c.floatBits, v) +func (c *CounterFloat64) Inc(v float64) { + atomicAddFloat((*atomic.Uint64)(c), v) } // Snapshot returns a read-only copy of the counter. -func (c *StandardCounterFloat64) Snapshot() CounterFloat64Snapshot { - v := math.Float64frombits(c.floatBits.Load()) - return counterFloat64Snapshot(v) +func (c *CounterFloat64) Snapshot() CounterFloat64Snapshot { + return CounterFloat64Snapshot(math.Float64frombits((*atomic.Uint64)(c).Load())) } func atomicAddFloat(fbits *atomic.Uint64, v float64) { diff --git a/metrics/counter_float_64_test.go b/metrics/counter_float_64_test.go index c21bd3307..618cbbbc2 100644 --- a/metrics/counter_float_64_test.go +++ b/metrics/counter_float_64_test.go @@ -32,61 +32,35 @@ func BenchmarkCounterFloat64Parallel(b *testing.B) { } } -func TestCounterFloat64Clear(t *testing.T) { +func TestCounterFloat64(t *testing.T) { c := NewCounterFloat64() - c.Inc(1.0) - c.Clear() if count := c.Snapshot().Count(); count != 0 { - t.Errorf("c.Count(): 0 != %v\n", count) + t.Errorf("wrong count: %v", count) } -} - -func TestCounterFloat64Dec1(t *testing.T) { - c := NewCounterFloat64() c.Dec(1.0) if count := c.Snapshot().Count(); count != -1.0 { - t.Errorf("c.Count(): -1.0 != %v\n", count) + t.Errorf("wrong count: %v", count) } -} - -func TestCounterFloat64Dec2(t *testing.T) { - c := NewCounterFloat64() + snapshot := c.Snapshot() c.Dec(2.0) - if count := c.Snapshot().Count(); count != -2.0 { - t.Errorf("c.Count(): -2.0 != %v\n", count) + if count := c.Snapshot().Count(); count != -3.0 { + t.Errorf("wrong count: %v", count) } -} - -func TestCounterFloat64Inc1(t *testing.T) { - c := NewCounterFloat64() c.Inc(1.0) - if count := c.Snapshot().Count(); count != 1.0 { - t.Errorf("c.Count(): 1.0 != %v\n", count) + if count := c.Snapshot().Count(); count != -2.0 { + t.Errorf("wrong count: %v", count) } -} - -func TestCounterFloat64Inc2(t *testing.T) { - c := NewCounterFloat64() c.Inc(2.0) - if count := c.Snapshot().Count(); count != 2.0 { - t.Errorf("c.Count(): 2.0 != %v\n", count) + if count := c.Snapshot().Count(); count != 0.0 { + t.Errorf("wrong count: %v", count) } -} - -func TestCounterFloat64Snapshot(t *testing.T) { - c := NewCounterFloat64() - c.Inc(1.0) - snapshot := c.Snapshot() - c.Inc(1.0) - if count := snapshot.Count(); count != 1.0 { - t.Errorf("c.Count(): 1.0 != %v\n", count) + if count := snapshot.Count(); count != -1.0 { + t.Errorf("snapshot count wrong: %v", count) } -} - -func TestCounterFloat64Zero(t *testing.T) { - c := NewCounterFloat64() - if count := c.Snapshot().Count(); count != 0 { - t.Errorf("c.Count(): 0 != %v\n", count) + c.Inc(1.0) + c.Clear() + if count := c.Snapshot().Count(); count != 0.0 { + t.Errorf("wrong count: %v", count) } } diff --git a/metrics/counter_test.go b/metrics/counter_test.go index 1b15b23f2..bf0ca6bae 100644 --- a/metrics/counter_test.go +++ b/metrics/counter_test.go @@ -19,35 +19,26 @@ func TestCounterClear(t *testing.T) { } } -func TestCounterDec1(t *testing.T) { +func TestCounter(t *testing.T) { c := NewCounter() + if count := c.Snapshot().Count(); count != 0 { + t.Errorf("wrong count: %v", count) + } c.Dec(1) if count := c.Snapshot().Count(); count != -1 { - t.Errorf("c.Count(): -1 != %v\n", count) + t.Errorf("wrong count: %v", count) } -} - -func TestCounterDec2(t *testing.T) { - c := NewCounter() c.Dec(2) - if count := c.Snapshot().Count(); count != -2 { - t.Errorf("c.Count(): -2 != %v\n", count) + if count := c.Snapshot().Count(); count != -3 { + t.Errorf("wrong count: %v", count) } -} - -func TestCounterInc1(t *testing.T) { - c := NewCounter() c.Inc(1) - if count := c.Snapshot().Count(); count != 1 { - t.Errorf("c.Count(): 1 != %v\n", count) + if count := c.Snapshot().Count(); count != -2 { + t.Errorf("wrong count: %v", count) } -} - -func TestCounterInc2(t *testing.T) { - c := NewCounter() c.Inc(2) - if count := c.Snapshot().Count(); count != 2 { - t.Errorf("c.Count(): 2 != %v\n", count) + if count := c.Snapshot().Count(); count != 0 { + t.Errorf("wrong count: %v", count) } } @@ -61,13 +52,6 @@ func TestCounterSnapshot(t *testing.T) { } } -func TestCounterZero(t *testing.T) { - c := NewCounter() - if count := c.Snapshot().Count(); count != 0 { - t.Errorf("c.Count(): 0 != %v\n", count) - } -} - func TestGetOrRegisterCounter(t *testing.T) { r := NewRegistry() NewRegisteredCounter("foo", r).Inc(47) diff --git a/metrics/debug.go b/metrics/debug.go index 9dfee1a86..5d0d3992f 100644 --- a/metrics/debug.go +++ b/metrics/debug.go @@ -8,13 +8,13 @@ import ( var ( debugMetrics struct { GCStats struct { - LastGC Gauge - NumGC Gauge + LastGC *Gauge + NumGC *Gauge Pause Histogram //PauseQuantiles Histogram - PauseTotal Gauge + PauseTotal *Gauge } - ReadGCStats Timer + ReadGCStats *Timer } gcStats debug.GCStats ) diff --git a/metrics/ewma.go b/metrics/ewma.go index 1d7a4f00c..194527a79 100644 --- a/metrics/ewma.go +++ b/metrics/ewma.go @@ -7,56 +7,36 @@ import ( "time" ) -type EWMASnapshot interface { - Rate() float64 -} +// EWMASnapshot is a read-only copy of an EWMA. +type EWMASnapshot float64 -// EWMAs continuously calculate an exponentially-weighted moving average -// based on an outside source of clock ticks. -type EWMA interface { - Snapshot() EWMASnapshot - Tick() - Update(int64) -} +// Rate returns the rate of events per second at the time the snapshot was +// taken. +func (a EWMASnapshot) Rate() float64 { return float64(a) } // NewEWMA constructs a new EWMA with the given alpha. -func NewEWMA(alpha float64) EWMA { - return &StandardEWMA{alpha: alpha} +func NewEWMA(alpha float64) *EWMA { + return &EWMA{alpha: alpha} } // NewEWMA1 constructs a new EWMA for a one-minute moving average. -func NewEWMA1() EWMA { +func NewEWMA1() *EWMA { return NewEWMA(1 - math.Exp(-5.0/60.0/1)) } // NewEWMA5 constructs a new EWMA for a five-minute moving average. -func NewEWMA5() EWMA { +func NewEWMA5() *EWMA { return NewEWMA(1 - math.Exp(-5.0/60.0/5)) } // NewEWMA15 constructs a new EWMA for a fifteen-minute moving average. -func NewEWMA15() EWMA { +func NewEWMA15() *EWMA { return NewEWMA(1 - math.Exp(-5.0/60.0/15)) } -// ewmaSnapshot is a read-only copy of another EWMA. -type ewmaSnapshot float64 - -// Rate returns the rate of events per second at the time the snapshot was -// taken. -func (a ewmaSnapshot) Rate() float64 { return float64(a) } - -// NilEWMA is a no-op EWMA. -type NilEWMA struct{} - -func (NilEWMA) Snapshot() EWMASnapshot { return (*emptySnapshot)(nil) } -func (NilEWMA) Tick() {} -func (NilEWMA) Update(n int64) {} - -// StandardEWMA is the standard implementation of an EWMA and tracks the number -// of uncounted events and processes them on each tick. It uses the -// sync/atomic package to manage uncounted events. -type StandardEWMA struct { +// EWMA continuously calculate an exponentially-weighted moving average +// based on an outside source of clock ticks. +type EWMA struct { uncounted atomic.Int64 alpha float64 rate atomic.Uint64 @@ -65,27 +45,27 @@ type StandardEWMA struct { } // Snapshot returns a read-only copy of the EWMA. -func (a *StandardEWMA) Snapshot() EWMASnapshot { +func (a *EWMA) Snapshot() EWMASnapshot { r := math.Float64frombits(a.rate.Load()) * float64(time.Second) - return ewmaSnapshot(r) + return EWMASnapshot(r) } -// Tick ticks the clock to update the moving average. It assumes it is called +// tick ticks the clock to update the moving average. It assumes it is called // every five seconds. -func (a *StandardEWMA) Tick() { +func (a *EWMA) tick() { // Optimization to avoid mutex locking in the hot-path. if a.init.Load() { a.updateRate(a.fetchInstantRate()) return } - // Slow-path: this is only needed on the first Tick() and preserves transactional updating + // Slow-path: this is only needed on the first tick() and preserves transactional updating // of init and rate in the else block. The first conditional is needed below because // a different thread could have set a.init = 1 between the time of the first atomic load and when // the lock was acquired. a.mutex.Lock() if a.init.Load() { // The fetchInstantRate() uses atomic loading, which is unnecessary in this critical section - // but again, this section is only invoked on the first successful Tick() operation. + // but again, this section is only invoked on the first successful tick() operation. a.updateRate(a.fetchInstantRate()) } else { a.init.Store(true) @@ -94,18 +74,18 @@ func (a *StandardEWMA) Tick() { a.mutex.Unlock() } -func (a *StandardEWMA) fetchInstantRate() float64 { +func (a *EWMA) fetchInstantRate() float64 { count := a.uncounted.Swap(0) return float64(count) / float64(5*time.Second) } -func (a *StandardEWMA) updateRate(instantRate float64) { +func (a *EWMA) updateRate(instantRate float64) { currentRate := math.Float64frombits(a.rate.Load()) currentRate += a.alpha * (instantRate - currentRate) a.rate.Store(math.Float64bits(currentRate)) } // Update adds n uncounted events. -func (a *StandardEWMA) Update(n int64) { +func (a *EWMA) Update(n int64) { a.uncounted.Add(n) } diff --git a/metrics/ewma_test.go b/metrics/ewma_test.go index 9a91b43db..4b9bde3a4 100644 --- a/metrics/ewma_test.go +++ b/metrics/ewma_test.go @@ -12,7 +12,7 @@ func BenchmarkEWMA(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { a.Update(1) - a.Tick() + a.tick() } } @@ -23,7 +23,7 @@ func BenchmarkEWMAParallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { a.Update(1) - a.Tick() + a.tick() } }) } @@ -31,7 +31,7 @@ func BenchmarkEWMAParallel(b *testing.B) { func TestEWMA1(t *testing.T) { a := NewEWMA1() a.Update(3) - a.Tick() + a.tick() for i, want := range []float64{0.6, 0.22072766470286553, 0.08120116994196772, 0.029872241020718428, 0.01098938333324054, 0.004042768199451294, 0.0014872513059998212, @@ -49,7 +49,7 @@ func TestEWMA1(t *testing.T) { func TestEWMA5(t *testing.T) { a := NewEWMA5() a.Update(3) - a.Tick() + a.tick() for i, want := range []float64{ 0.6, 0.49123845184678905, 0.4021920276213837, 0.32928698165641596, 0.269597378470333, 0.2207276647028654, 0.18071652714732128, @@ -67,7 +67,7 @@ func TestEWMA5(t *testing.T) { func TestEWMA15(t *testing.T) { a := NewEWMA15() a.Update(3) - a.Tick() + a.tick() for i, want := range []float64{ 0.6, 0.5613041910189706, 0.5251039914257684, 0.4912384518467888184678905, 0.459557003018789, 0.4299187863442732, 0.4021920276213831, @@ -82,8 +82,8 @@ func TestEWMA15(t *testing.T) { } } -func elapseMinute(a EWMA) { +func elapseMinute(a *EWMA) { for i := 0; i < 12; i++ { - a.Tick() + a.tick() } } diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 7e3f82a07..5213979aa 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -146,7 +146,7 @@ func (exp *exp) publishHistogram(name string, metric metrics.Histogram) { exp.getFloat(name + ".999-percentile").Set(ps[4]) } -func (exp *exp) publishMeter(name string, metric metrics.Meter) { +func (exp *exp) publishMeter(name string, metric *metrics.Meter) { m := metric.Snapshot() exp.getInt(name + ".count").Set(m.Count()) exp.getFloat(name + ".one-minute").Set(m.Rate1()) @@ -155,7 +155,7 @@ func (exp *exp) publishMeter(name string, metric metrics.Meter) { exp.getFloat(name + ".mean").Set(m.RateMean()) } -func (exp *exp) publishTimer(name string, metric metrics.Timer) { +func (exp *exp) publishTimer(name string, metric *metrics.Timer) { t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) exp.getInt(name + ".count").Set(t.Count()) @@ -174,7 +174,7 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) { exp.getFloat(name + ".mean-rate").Set(t.RateMean()) } -func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) { +func (exp *exp) publishResettingTimer(name string, metric *metrics.ResettingTimer) { t := metric.Snapshot() ps := t.Percentiles([]float64{0.50, 0.75, 0.95, 0.99}) exp.getInt(name + ".count").Set(int64(t.Count())) @@ -188,23 +188,23 @@ func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer func (exp *exp) syncToExpvar() { exp.registry.Each(func(name string, i interface{}) { switch i := i.(type) { - case metrics.Counter: + case *metrics.Counter: exp.publishCounter(name, i.Snapshot()) - case metrics.CounterFloat64: + case *metrics.CounterFloat64: exp.publishCounterFloat64(name, i.Snapshot()) - case metrics.Gauge: + case *metrics.Gauge: exp.publishGauge(name, i.Snapshot()) - case metrics.GaugeFloat64: + case *metrics.GaugeFloat64: exp.publishGaugeFloat64(name, i.Snapshot()) - case metrics.GaugeInfo: + case *metrics.GaugeInfo: exp.publishGaugeInfo(name, i.Snapshot()) case metrics.Histogram: exp.publishHistogram(name, i) - case metrics.Meter: + case *metrics.Meter: exp.publishMeter(name, i) - case metrics.Timer: + case *metrics.Timer: exp.publishTimer(name, i) - case metrics.ResettingTimer: + case *metrics.ResettingTimer: exp.publishResettingTimer(name, i) default: panic(fmt.Sprintf("unsupported type for '%s': %T", name, i)) diff --git a/metrics/gauge.go b/metrics/gauge.go index 6d10bbf85..ba7843e03 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -2,97 +2,69 @@ package metrics import "sync/atomic" -// GaugeSnapshot contains a readonly int64. -type GaugeSnapshot interface { - Value() int64 -} +// GaugeSnapshot is a read-only copy of a Gauge. +type GaugeSnapshot int64 -// Gauge holds an int64 value that can be set arbitrarily. -type Gauge interface { - Snapshot() GaugeSnapshot - Update(int64) - UpdateIfGt(int64) - Dec(int64) - Inc(int64) -} +// Value returns the value at the time the snapshot was taken. +func (g GaugeSnapshot) Value() int64 { return int64(g) } // GetOrRegisterGauge returns an existing Gauge or constructs and registers a -// new StandardGauge. -func GetOrRegisterGauge(name string, r Registry) Gauge { - if nil == r { +// new Gauge. +func GetOrRegisterGauge(name string, r Registry) *Gauge { + if r == nil { r = DefaultRegistry } - return r.GetOrRegister(name, NewGauge).(Gauge) + return r.GetOrRegister(name, NewGauge).(*Gauge) } -// NewGauge constructs a new StandardGauge. -func NewGauge() Gauge { - if !Enabled { - return NilGauge{} - } - return &StandardGauge{} +// NewGauge constructs a new Gauge. +func NewGauge() *Gauge { + return &Gauge{} } -// NewRegisteredGauge constructs and registers a new StandardGauge. -func NewRegisteredGauge(name string, r Registry) Gauge { +// NewRegisteredGauge constructs and registers a new Gauge. +func NewRegisteredGauge(name string, r Registry) *Gauge { c := NewGauge() - if nil == r { + if r == nil { r = DefaultRegistry } r.Register(name, c) return c } -// gaugeSnapshot is a read-only copy of another Gauge. -type gaugeSnapshot int64 - -// Value returns the value at the time the snapshot was taken. -func (g gaugeSnapshot) Value() int64 { return int64(g) } - -// NilGauge is a no-op Gauge. -type NilGauge struct{} - -func (NilGauge) Snapshot() GaugeSnapshot { return (*emptySnapshot)(nil) } -func (NilGauge) Update(v int64) {} -func (NilGauge) UpdateIfGt(v int64) {} -func (NilGauge) Dec(i int64) {} -func (NilGauge) Inc(i int64) {} - -// StandardGauge is the standard implementation of a Gauge and uses the -// sync/atomic package to manage a single int64 value. -type StandardGauge struct { - value atomic.Int64 -} +// Gauge holds an int64 value that can be set arbitrarily. +type Gauge atomic.Int64 // Snapshot returns a read-only copy of the gauge. -func (g *StandardGauge) Snapshot() GaugeSnapshot { - return gaugeSnapshot(g.value.Load()) +func (g *Gauge) Snapshot() GaugeSnapshot { + return GaugeSnapshot((*atomic.Int64)(g).Load()) } // Update updates the gauge's value. -func (g *StandardGauge) Update(v int64) { - g.value.Store(v) +func (g *Gauge) Update(v int64) { + (*atomic.Int64)(g).Store(v) } // UpdateIfGt updates the gauge's value if v is larger then the current value. -func (g *StandardGauge) UpdateIfGt(v int64) { +func (g *Gauge) UpdateIfGt(v int64) { + value := (*atomic.Int64)(g) for { - exist := g.value.Load() + exist := value.Load() if exist >= v { break } - if g.value.CompareAndSwap(exist, v) { + if value.CompareAndSwap(exist, v) { break } } } // Dec decrements the gauge's current value by the given amount. -func (g *StandardGauge) Dec(i int64) { - g.value.Add(-i) +func (g *Gauge) Dec(i int64) { + (*atomic.Int64)(g).Add(-i) } // Inc increments the gauge's current value by the given amount. -func (g *StandardGauge) Inc(i int64) { - g.value.Add(i) +func (g *Gauge) Inc(i int64) { + (*atomic.Int64)(g).Add(i) } diff --git a/metrics/gauge_float64.go b/metrics/gauge_float64.go index c1c3c6b6e..05b401ef9 100644 --- a/metrics/gauge_float64.go +++ b/metrics/gauge_float64.go @@ -5,35 +5,28 @@ import ( "sync/atomic" ) -type GaugeFloat64Snapshot interface { - Value() float64 -} - -// GaugeFloat64 hold a float64 value that can be set arbitrarily. -type GaugeFloat64 interface { - Snapshot() GaugeFloat64Snapshot - Update(float64) -} - // GetOrRegisterGaugeFloat64 returns an existing GaugeFloat64 or constructs and registers a -// new StandardGaugeFloat64. -func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 { +// new GaugeFloat64. +func GetOrRegisterGaugeFloat64(name string, r Registry) *GaugeFloat64 { if nil == r { r = DefaultRegistry } - return r.GetOrRegister(name, NewGaugeFloat64()).(GaugeFloat64) + return r.GetOrRegister(name, NewGaugeFloat64()).(*GaugeFloat64) } -// NewGaugeFloat64 constructs a new StandardGaugeFloat64. -func NewGaugeFloat64() GaugeFloat64 { - if !Enabled { - return NilGaugeFloat64{} - } - return &StandardGaugeFloat64{} +// GaugeFloat64Snapshot is a read-only copy of a GaugeFloat64. +type GaugeFloat64Snapshot float64 + +// Value returns the value at the time the snapshot was taken. +func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) } + +// NewGaugeFloat64 constructs a new GaugeFloat64. +func NewGaugeFloat64() *GaugeFloat64 { + return new(GaugeFloat64) } -// NewRegisteredGaugeFloat64 constructs and registers a new StandardGaugeFloat64. -func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 { +// NewRegisteredGaugeFloat64 constructs and registers a new GaugeFloat64. +func NewRegisteredGaugeFloat64(name string, r Registry) *GaugeFloat64 { c := NewGaugeFloat64() if nil == r { r = DefaultRegistry @@ -42,32 +35,16 @@ func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 { return c } -// gaugeFloat64Snapshot is a read-only copy of another GaugeFloat64. -type gaugeFloat64Snapshot float64 - -// Value returns the value at the time the snapshot was taken. -func (g gaugeFloat64Snapshot) Value() float64 { return float64(g) } - -// NilGaugeFloat64 is a no-op Gauge. -type NilGaugeFloat64 struct{} - -func (NilGaugeFloat64) Snapshot() GaugeFloat64Snapshot { return NilGaugeFloat64{} } -func (NilGaugeFloat64) Update(v float64) {} -func (NilGaugeFloat64) Value() float64 { return 0.0 } - -// StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses -// atomic to manage a single float64 value. -type StandardGaugeFloat64 struct { - floatBits atomic.Uint64 -} +// GaugeFloat64 hold a float64 value that can be set arbitrarily. +type GaugeFloat64 atomic.Uint64 // Snapshot returns a read-only copy of the gauge. -func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64Snapshot { - v := math.Float64frombits(g.floatBits.Load()) - return gaugeFloat64Snapshot(v) +func (g *GaugeFloat64) Snapshot() GaugeFloat64Snapshot { + v := math.Float64frombits((*atomic.Uint64)(g).Load()) + return GaugeFloat64Snapshot(v) } // Update updates the gauge's value. -func (g *StandardGaugeFloat64) Update(v float64) { - g.floatBits.Store(math.Float64bits(v)) +func (g *GaugeFloat64) Update(v float64) { + (*atomic.Uint64)(g).Store(math.Float64bits(v)) } diff --git a/metrics/gauge_info.go b/metrics/gauge_info.go index 0010edc32..2f7845564 100644 --- a/metrics/gauge_info.go +++ b/metrics/gauge_info.go @@ -5,16 +5,6 @@ import ( "sync" ) -type GaugeInfoSnapshot interface { - Value() GaugeInfoValue -} - -// GaugeInfo holds a GaugeInfoValue value that can be set arbitrarily. -type GaugeInfo interface { - Update(GaugeInfoValue) - Snapshot() GaugeInfoSnapshot -} - // GaugeInfoValue is a mapping of keys to values type GaugeInfoValue map[string]string @@ -24,26 +14,23 @@ func (val GaugeInfoValue) String() string { } // GetOrRegisterGaugeInfo returns an existing GaugeInfo or constructs and registers a -// new StandardGaugeInfo. -func GetOrRegisterGaugeInfo(name string, r Registry) GaugeInfo { +// new GaugeInfo. +func GetOrRegisterGaugeInfo(name string, r Registry) *GaugeInfo { if nil == r { r = DefaultRegistry } - return r.GetOrRegister(name, NewGaugeInfo()).(GaugeInfo) + return r.GetOrRegister(name, NewGaugeInfo()).(*GaugeInfo) } -// NewGaugeInfo constructs a new StandardGaugeInfo. -func NewGaugeInfo() GaugeInfo { - if !Enabled { - return NilGaugeInfo{} - } - return &StandardGaugeInfo{ +// NewGaugeInfo constructs a new GaugeInfo. +func NewGaugeInfo() *GaugeInfo { + return &GaugeInfo{ value: GaugeInfoValue{}, } } -// NewRegisteredGaugeInfo constructs and registers a new StandardGaugeInfo. -func NewRegisteredGaugeInfo(name string, r Registry) GaugeInfo { +// NewRegisteredGaugeInfo constructs and registers a new GaugeInfo. +func NewRegisteredGaugeInfo(name string, r Registry) *GaugeInfo { c := NewGaugeInfo() if nil == r { r = DefaultRegistry @@ -53,31 +40,24 @@ func NewRegisteredGaugeInfo(name string, r Registry) GaugeInfo { } // gaugeInfoSnapshot is a read-only copy of another GaugeInfo. -type gaugeInfoSnapshot GaugeInfoValue +type GaugeInfoSnapshot GaugeInfoValue // Value returns the value at the time the snapshot was taken. -func (g gaugeInfoSnapshot) Value() GaugeInfoValue { return GaugeInfoValue(g) } - -type NilGaugeInfo struct{} - -func (NilGaugeInfo) Snapshot() GaugeInfoSnapshot { return NilGaugeInfo{} } -func (NilGaugeInfo) Update(v GaugeInfoValue) {} -func (NilGaugeInfo) Value() GaugeInfoValue { return GaugeInfoValue{} } +func (g GaugeInfoSnapshot) Value() GaugeInfoValue { return GaugeInfoValue(g) } -// StandardGaugeInfo is the standard implementation of a GaugeInfo and uses -// sync.Mutex to manage a single string value. -type StandardGaugeInfo struct { +// GaugeInfo maintains a set of key/value mappings. +type GaugeInfo struct { mutex sync.Mutex value GaugeInfoValue } // Snapshot returns a read-only copy of the gauge. -func (g *StandardGaugeInfo) Snapshot() GaugeInfoSnapshot { - return gaugeInfoSnapshot(g.value) +func (g *GaugeInfo) Snapshot() GaugeInfoSnapshot { + return GaugeInfoSnapshot(g.value) } // Update updates the gauge's value. -func (g *StandardGaugeInfo) Update(v GaugeInfoValue) { +func (g *GaugeInfo) Update(v GaugeInfoValue) { g.mutex.Lock() defer g.mutex.Unlock() g.value = v diff --git a/metrics/graphite.go b/metrics/graphite.go deleted file mode 100644 index aba752e0e..000000000 --- a/metrics/graphite.go +++ /dev/null @@ -1,117 +0,0 @@ -package metrics - -import ( - "bufio" - "fmt" - "log" - "net" - "strconv" - "strings" - "time" -) - -// GraphiteConfig provides a container with configuration parameters for -// the Graphite exporter -type GraphiteConfig struct { - Addr *net.TCPAddr // Network address to connect to - Registry Registry // Registry to be exported - FlushInterval time.Duration // Flush interval - DurationUnit time.Duration // Time conversion unit for durations - Prefix string // Prefix to be prepended to metric names - Percentiles []float64 // Percentiles to export from timers and histograms -} - -// Graphite is a blocking exporter function which reports metrics in r -// to a graphite server located at addr, flushing them every d duration -// and prepending metric names with prefix. -func Graphite(r Registry, d time.Duration, prefix string, addr *net.TCPAddr) { - GraphiteWithConfig(GraphiteConfig{ - Addr: addr, - Registry: r, - FlushInterval: d, - DurationUnit: time.Nanosecond, - Prefix: prefix, - Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999}, - }) -} - -// GraphiteWithConfig is a blocking exporter function just like Graphite, -// but it takes a GraphiteConfig instead. -func GraphiteWithConfig(c GraphiteConfig) { - log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015") - for range time.Tick(c.FlushInterval) { - if err := graphite(&c); nil != err { - log.Println(err) - } - } -} - -// GraphiteOnce performs a single submission to Graphite, returning a -// non-nil error on failed connections. This can be used in a loop -// similar to GraphiteWithConfig for custom error handling. -func GraphiteOnce(c GraphiteConfig) error { - log.Printf("WARNING: This go-metrics client has been DEPRECATED! It has been moved to https://github.com/cyberdelia/go-metrics-graphite and will be removed from rcrowley/go-metrics on August 12th 2015") - return graphite(&c) -} - -func graphite(c *GraphiteConfig) error { - now := time.Now().Unix() - du := float64(c.DurationUnit) - conn, err := net.DialTCP("tcp", nil, c.Addr) - if nil != err { - return err - } - defer conn.Close() - w := bufio.NewWriter(conn) - c.Registry.Each(func(name string, i interface{}) { - switch metric := i.(type) { - case Counter: - fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Snapshot().Count(), now) - case CounterFloat64: - fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Snapshot().Count(), now) - case Gauge: - fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Snapshot().Value(), now) - case GaugeFloat64: - fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Snapshot().Value(), now) - case GaugeInfo: - fmt.Fprintf(w, "%s.%s.value %s %d\n", c.Prefix, name, metric.Snapshot().Value().String(), now) - case Histogram: - h := metric.Snapshot() - ps := h.Percentiles(c.Percentiles) - fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now) - fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now) - fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now) - fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now) - fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now) - for psIdx, psKey := range c.Percentiles { - key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) - fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) - } - case Meter: - m := metric.Snapshot() - fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now) - fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now) - fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now) - fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now) - fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now) - case Timer: - t := metric.Snapshot() - ps := t.Percentiles(c.Percentiles) - fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now) - fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, t.Min()/int64(du), now) - fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, t.Max()/int64(du), now) - fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, t.Mean()/du, now) - fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, t.StdDev()/du, now) - for psIdx, psKey := range c.Percentiles { - key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1) - fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now) - } - fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now) - fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now) - fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now) - fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now) - } - w.Flush() - }) - return nil -} diff --git a/metrics/graphite_test.go b/metrics/graphite_test.go deleted file mode 100644 index c797c781d..000000000 --- a/metrics/graphite_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package metrics - -import ( - "net" - "time" -) - -func ExampleGraphite() { - addr, _ := net.ResolveTCPAddr("net", ":2003") - go Graphite(DefaultRegistry, 1*time.Second, "some.prefix", addr) -} - -func ExampleGraphiteWithConfig() { - addr, _ := net.ResolveTCPAddr("net", ":2003") - go GraphiteWithConfig(GraphiteConfig{ - Addr: addr, - Registry: DefaultRegistry, - FlushInterval: 1 * time.Second, - DurationUnit: time.Millisecond, - Percentiles: []float64{0.5, 0.75, 0.99, 0.999}, - }) -} diff --git a/metrics/healthcheck.go b/metrics/healthcheck.go index adcd15ab5..435e5e0bf 100644 --- a/metrics/healthcheck.go +++ b/metrics/healthcheck.go @@ -1,61 +1,35 @@ package metrics -// Healthcheck holds an error value describing an arbitrary up/down status. -type Healthcheck interface { - Check() - Error() error - Healthy() - Unhealthy(error) -} - // NewHealthcheck constructs a new Healthcheck which will use the given // function to update its status. -func NewHealthcheck(f func(Healthcheck)) Healthcheck { - if !Enabled { - return NilHealthcheck{} - } - return &StandardHealthcheck{nil, f} +func NewHealthcheck(f func(*Healthcheck)) *Healthcheck { + return &Healthcheck{nil, f} } -// NilHealthcheck is a no-op. -type NilHealthcheck struct{} - -// Check is a no-op. -func (NilHealthcheck) Check() {} - -// Error is a no-op. -func (NilHealthcheck) Error() error { return nil } - -// Healthy is a no-op. -func (NilHealthcheck) Healthy() {} - -// Unhealthy is a no-op. -func (NilHealthcheck) Unhealthy(error) {} - -// StandardHealthcheck is the standard implementation of a Healthcheck and +// Healthcheck is the standard implementation of a Healthcheck and // stores the status and a function to call to update the status. -type StandardHealthcheck struct { +type Healthcheck struct { err error - f func(Healthcheck) + f func(*Healthcheck) } // Check runs the healthcheck function to update the healthcheck's status. -func (h *StandardHealthcheck) Check() { +func (h *Healthcheck) Check() { h.f(h) } // Error returns the healthcheck's status, which will be nil if it is healthy. -func (h *StandardHealthcheck) Error() error { +func (h *Healthcheck) Error() error { return h.err } // Healthy marks the healthcheck as healthy. -func (h *StandardHealthcheck) Healthy() { +func (h *Healthcheck) Healthy() { h.err = nil } // Unhealthy marks the healthcheck as unhealthy. The error is stored and // may be retrieved by the Error method. -func (h *StandardHealthcheck) Unhealthy(err error) { +func (h *Healthcheck) Unhealthy(err error) { h.err = err } diff --git a/metrics/histogram.go b/metrics/histogram.go index 10259a246..7c27bcc92 100644 --- a/metrics/histogram.go +++ b/metrics/histogram.go @@ -1,7 +1,16 @@ package metrics type HistogramSnapshot interface { - SampleSnapshot + Count() int64 + Max() int64 + Mean() float64 + Min() int64 + Percentile(float64) float64 + Percentiles([]float64) []float64 + Size() int + StdDev() float64 + Sum() int64 + Variance() float64 } // Histogram calculates distribution statistics from a series of int64 values. @@ -31,10 +40,7 @@ func GetOrRegisterHistogramLazy(name string, r Registry, s func() Sample) Histog // NewHistogram constructs a new StandardHistogram from a Sample. func NewHistogram(s Sample) Histogram { - if !Enabled { - return NilHistogram{} - } - return &StandardHistogram{sample: s} + return &StandardHistogram{s} } // NewRegisteredHistogram constructs and registers a new StandardHistogram from @@ -48,13 +54,6 @@ func NewRegisteredHistogram(name string, r Registry, s Sample) Histogram { return c } -// NilHistogram is a no-op Histogram. -type NilHistogram struct{} - -func (NilHistogram) Clear() {} -func (NilHistogram) Snapshot() HistogramSnapshot { return (*emptySnapshot)(nil) } -func (NilHistogram) Update(v int64) {} - // StandardHistogram is the standard implementation of a Histogram and uses a // Sample to bound its memory use. type StandardHistogram struct { diff --git a/metrics/inactive.go b/metrics/inactive.go deleted file mode 100644 index 1f47f0210..000000000 --- a/metrics/inactive.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2023 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 . - -package metrics - -// compile-time checks that interfaces are implemented. -var ( - _ SampleSnapshot = (*emptySnapshot)(nil) - _ HistogramSnapshot = (*emptySnapshot)(nil) - _ CounterSnapshot = (*emptySnapshot)(nil) - _ GaugeSnapshot = (*emptySnapshot)(nil) - _ MeterSnapshot = (*emptySnapshot)(nil) - _ EWMASnapshot = (*emptySnapshot)(nil) - _ TimerSnapshot = (*emptySnapshot)(nil) -) - -type emptySnapshot struct{} - -func (*emptySnapshot) Count() int64 { return 0 } -func (*emptySnapshot) Max() int64 { return 0 } -func (*emptySnapshot) Mean() float64 { return 0.0 } -func (*emptySnapshot) Min() int64 { return 0 } -func (*emptySnapshot) Percentile(p float64) float64 { return 0.0 } -func (*emptySnapshot) Percentiles(ps []float64) []float64 { return make([]float64, len(ps)) } -func (*emptySnapshot) Size() int { return 0 } -func (*emptySnapshot) StdDev() float64 { return 0.0 } -func (*emptySnapshot) Sum() int64 { return 0 } -func (*emptySnapshot) Values() []int64 { return []int64{} } -func (*emptySnapshot) Variance() float64 { return 0.0 } -func (*emptySnapshot) Value() int64 { return 0 } -func (*emptySnapshot) Rate() float64 { return 0.0 } -func (*emptySnapshot) Rate1() float64 { return 0.0 } -func (*emptySnapshot) Rate5() float64 { return 0.0 } -func (*emptySnapshot) Rate15() float64 { return 0.0 } -func (*emptySnapshot) RateMean() float64 { return 0.0 } diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index 5c8501fd9..11f6c3ad2 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -8,31 +8,31 @@ import ( func readMeter(namespace, name string, i interface{}) (string, map[string]interface{}) { switch metric := i.(type) { - case metrics.Counter: + case *metrics.Counter: measurement := fmt.Sprintf("%s%s.count", namespace, name) fields := map[string]interface{}{ "value": metric.Snapshot().Count(), } return measurement, fields - case metrics.CounterFloat64: + case *metrics.CounterFloat64: measurement := fmt.Sprintf("%s%s.count", namespace, name) fields := map[string]interface{}{ "value": metric.Snapshot().Count(), } return measurement, fields - case metrics.Gauge: + case *metrics.Gauge: measurement := fmt.Sprintf("%s%s.gauge", namespace, name) fields := map[string]interface{}{ "value": metric.Snapshot().Value(), } return measurement, fields - case metrics.GaugeFloat64: + case *metrics.GaugeFloat64: measurement := fmt.Sprintf("%s%s.gauge", namespace, name) fields := map[string]interface{}{ "value": metric.Snapshot().Value(), } return measurement, fields - case metrics.GaugeInfo: + case *metrics.GaugeInfo: ms := metric.Snapshot() measurement := fmt.Sprintf("%s%s.gauge", namespace, name) fields := map[string]interface{}{ @@ -62,7 +62,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf "p9999": ps[6], } return measurement, fields - case metrics.Meter: + case *metrics.Meter: ms := metric.Snapshot() measurement := fmt.Sprintf("%s%s.meter", namespace, name) fields := map[string]interface{}{ @@ -73,7 +73,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf "mean": ms.RateMean(), } return measurement, fields - case metrics.Timer: + case *metrics.Timer: ms := metric.Snapshot() ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) @@ -97,7 +97,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf "meanrate": ms.RateMean(), } return measurement, fields - case metrics.ResettingTimer: + case *metrics.ResettingTimer: ms := metric.Snapshot() if ms.Count() == 0 { break diff --git a/metrics/influxdb/influxdb_test.go b/metrics/influxdb/influxdb_test.go index 5879af7cf..547da138b 100644 --- a/metrics/influxdb/influxdb_test.go +++ b/metrics/influxdb/influxdb_test.go @@ -33,7 +33,7 @@ import ( ) func TestMain(m *testing.M) { - metrics.Enabled = true + metrics.Enable() os.Exit(m.Run()) } diff --git a/metrics/init_test.go b/metrics/init_test.go index 43401e833..af75bee42 100644 --- a/metrics/init_test.go +++ b/metrics/init_test.go @@ -1,5 +1,5 @@ package metrics func init() { - Enabled = true + metricsEnabled = true } diff --git a/metrics/log.go b/metrics/log.go index 3b9773faa..3380bbf9c 100644 --- a/metrics/log.go +++ b/metrics/log.go @@ -21,25 +21,21 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { for range time.Tick(freq) { r.Each(func(name string, i interface{}) { switch metric := i.(type) { - case Counter: + case *Counter: l.Printf("counter %s\n", name) l.Printf(" count: %9d\n", metric.Snapshot().Count()) - case CounterFloat64: + case *CounterFloat64: l.Printf("counter %s\n", name) l.Printf(" count: %f\n", metric.Snapshot().Count()) - case Gauge: + case *Gauge: l.Printf("gauge %s\n", name) l.Printf(" value: %9d\n", metric.Snapshot().Value()) - case GaugeFloat64: + case *GaugeFloat64: l.Printf("gauge %s\n", name) l.Printf(" value: %f\n", metric.Snapshot().Value()) - case GaugeInfo: + case *GaugeInfo: l.Printf("gauge %s\n", name) l.Printf(" value: %s\n", metric.Snapshot().Value()) - case Healthcheck: - metric.Check() - l.Printf("healthcheck %s\n", name) - l.Printf(" error: %v\n", metric.Error()) case Histogram: h := metric.Snapshot() ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) @@ -54,7 +50,7 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { l.Printf(" 95%%: %12.2f\n", ps[2]) l.Printf(" 99%%: %12.2f\n", ps[3]) l.Printf(" 99.9%%: %12.2f\n", ps[4]) - case Meter: + case *Meter: m := metric.Snapshot() l.Printf("meter %s\n", name) l.Printf(" count: %9d\n", m.Count()) @@ -62,7 +58,7 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { l.Printf(" 5-min rate: %12.2f\n", m.Rate5()) l.Printf(" 15-min rate: %12.2f\n", m.Rate15()) l.Printf(" mean rate: %12.2f\n", m.RateMean()) - case Timer: + case *Timer: t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) l.Printf("timer %s\n", name) diff --git a/metrics/meter.go b/metrics/meter.go index 432838f4e..194bd1f30 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -7,114 +7,78 @@ import ( "time" ) -type MeterSnapshot interface { - Count() int64 - Rate1() float64 - Rate5() float64 - Rate15() float64 - RateMean() float64 -} - -// Meters count events to produce exponentially-weighted moving average rates -// at one-, five-, and fifteen-minutes and a mean rate. -type Meter interface { - Mark(int64) - Snapshot() MeterSnapshot - Stop() -} - // GetOrRegisterMeter returns an existing Meter or constructs and registers a -// new StandardMeter. +// new Meter. // Be sure to unregister the meter from the registry once it is of no use to // allow for garbage collection. -func GetOrRegisterMeter(name string, r Registry) Meter { - if nil == r { +func GetOrRegisterMeter(name string, r Registry) *Meter { + if r == nil { r = DefaultRegistry } - return r.GetOrRegister(name, NewMeter).(Meter) + return r.GetOrRegister(name, NewMeter).(*Meter) } -// NewMeter constructs a new StandardMeter and launches a goroutine. +// NewMeter constructs a new Meter and launches a goroutine. // Be sure to call Stop() once the meter is of no use to allow for garbage collection. -func NewMeter() Meter { - if !Enabled { - return NilMeter{} - } - m := newStandardMeter() - arbiter.Lock() - defer arbiter.Unlock() - arbiter.meters[m] = struct{}{} - if !arbiter.started { - arbiter.started = true - go arbiter.tick() - } +func NewMeter() *Meter { + m := newMeter() + arbiter.add(m) return m } // NewInactiveMeter returns a meter but does not start any goroutines. This // method is mainly intended for testing. -func NewInactiveMeter() Meter { - if !Enabled { - return NilMeter{} - } - m := newStandardMeter() - return m +func NewInactiveMeter() *Meter { + return newMeter() } -// NewRegisteredMeter constructs and registers a new StandardMeter +// NewRegisteredMeter constructs and registers a new Meter // and launches a goroutine. // Be sure to unregister the meter from the registry once it is of no use to // allow for garbage collection. -func NewRegisteredMeter(name string, r Registry) Meter { +func NewRegisteredMeter(name string, r Registry) *Meter { return GetOrRegisterMeter(name, r) } -// meterSnapshot is a read-only copy of the meter's internal values. -type meterSnapshot struct { +// MeterSnapshot is a read-only copy of the meter's internal values. +type MeterSnapshot struct { count int64 rate1, rate5, rate15, rateMean float64 } // Count returns the count of events at the time the snapshot was taken. -func (m *meterSnapshot) Count() int64 { return m.count } +func (m *MeterSnapshot) Count() int64 { return m.count } // Rate1 returns the one-minute moving average rate of events per second at the // time the snapshot was taken. -func (m *meterSnapshot) Rate1() float64 { return m.rate1 } +func (m *MeterSnapshot) Rate1() float64 { return m.rate1 } // Rate5 returns the five-minute moving average rate of events per second at // the time the snapshot was taken. -func (m *meterSnapshot) Rate5() float64 { return m.rate5 } +func (m *MeterSnapshot) Rate5() float64 { return m.rate5 } // Rate15 returns the fifteen-minute moving average rate of events per second // at the time the snapshot was taken. -func (m *meterSnapshot) Rate15() float64 { return m.rate15 } +func (m *MeterSnapshot) Rate15() float64 { return m.rate15 } // RateMean returns the meter's mean rate of events per second at the time the // snapshot was taken. -func (m *meterSnapshot) RateMean() float64 { return m.rateMean } - -// NilMeter is a no-op Meter. -type NilMeter struct{} +func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } -func (NilMeter) Count() int64 { return 0 } -func (NilMeter) Mark(n int64) {} -func (NilMeter) Snapshot() MeterSnapshot { return (*emptySnapshot)(nil) } -func (NilMeter) Stop() {} - -// StandardMeter is the standard implementation of a Meter. -type StandardMeter struct { +// Meter count events to produce exponentially-weighted moving average rates +// at one-, five-, and fifteen-minutes and a mean rate. +type Meter struct { count atomic.Int64 uncounted atomic.Int64 // not yet added to the EWMAs rateMean atomic.Uint64 - a1, a5, a15 EWMA + a1, a5, a15 *EWMA startTime time.Time stopped atomic.Bool } -func newStandardMeter() *StandardMeter { - return &StandardMeter{ +func newMeter() *Meter { + return &Meter{ a1: NewEWMA1(), a5: NewEWMA5(), a15: NewEWMA15(), @@ -123,22 +87,20 @@ func newStandardMeter() *StandardMeter { } // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. -func (m *StandardMeter) Stop() { +func (m *Meter) Stop() { if stopped := m.stopped.Swap(true); !stopped { - arbiter.Lock() - delete(arbiter.meters, m) - arbiter.Unlock() + arbiter.remove(m) } } // Mark records the occurrence of n events. -func (m *StandardMeter) Mark(n int64) { +func (m *Meter) Mark(n int64) { m.uncounted.Add(n) } // Snapshot returns a read-only copy of the meter. -func (m *StandardMeter) Snapshot() MeterSnapshot { - return &meterSnapshot{ +func (m *Meter) Snapshot() *MeterSnapshot { + return &MeterSnapshot{ count: m.count.Load() + m.uncounted.Load(), rate1: m.a1.Snapshot().Rate(), rate5: m.a5.Snapshot().Rate(), @@ -147,7 +109,7 @@ func (m *StandardMeter) Snapshot() MeterSnapshot { } } -func (m *StandardMeter) tick() { +func (m *Meter) tick() { // Take the uncounted values, add to count n := m.uncounted.Swap(0) count := m.count.Add(n) @@ -157,33 +119,51 @@ func (m *StandardMeter) tick() { m.a5.Update(n) m.a15.Update(n) // And trigger them to calculate the rates - m.a1.Tick() - m.a5.Tick() - m.a15.Tick() + m.a1.tick() + m.a5.tick() + m.a15.tick() } -// meterArbiter ticks meters every 5s from a single goroutine. +var arbiter = meterTicker{meters: make(map[*Meter]struct{})} + +// meterTicker ticks meters every 5s from a single goroutine. // meters are references in a set for future stopping. -type meterArbiter struct { - sync.RWMutex +type meterTicker struct { + mu sync.RWMutex + started bool - meters map[*StandardMeter]struct{} - ticker *time.Ticker + meters map[*Meter]struct{} } -var arbiter = meterArbiter{ticker: time.NewTicker(5 * time.Second), meters: make(map[*StandardMeter]struct{})} - -// tick meters on the scheduled interval -func (ma *meterArbiter) tick() { - for range ma.ticker.C { - ma.tickMeters() +// add adds another *Meter ot the arbiter, and starts the arbiter ticker. +func (ma *meterTicker) add(m *Meter) { + ma.mu.Lock() + defer ma.mu.Unlock() + ma.meters[m] = struct{}{} + if !ma.started { + ma.started = true + go ma.loop() } } -func (ma *meterArbiter) tickMeters() { - ma.RLock() - defer ma.RUnlock() - for meter := range ma.meters { - meter.tick() +// remove removes a meter from the set of ticked meters. +func (ma *meterTicker) remove(m *Meter) { + ma.mu.Lock() + delete(ma.meters, m) + ma.mu.Unlock() +} + +// loop ticks meters on a 5 second interval. +func (ma *meterTicker) loop() { + ticker := time.NewTicker(5 * time.Second) + for range ticker.C { + if !metricsEnabled { + continue + } + ma.mu.RLock() + for meter := range ma.meters { + meter.tick() + } + ma.mu.RUnlock() } } diff --git a/metrics/meter_test.go b/metrics/meter_test.go index 019c4d765..e3f39684b 100644 --- a/metrics/meter_test.go +++ b/metrics/meter_test.go @@ -28,18 +28,12 @@ func TestGetOrRegisterMeter(t *testing.T) { } func TestMeterDecay(t *testing.T) { - ma := meterArbiter{ - ticker: time.NewTicker(time.Millisecond), - meters: make(map[*StandardMeter]struct{}), - } - defer ma.ticker.Stop() - m := newStandardMeter() - ma.meters[m] = struct{}{} + m := newMeter() m.Mark(1) - ma.tickMeters() + m.tick() rateMean := m.Snapshot().RateMean() time.Sleep(100 * time.Millisecond) - ma.tickMeters() + m.tick() if m.Snapshot().RateMean() >= rateMean { t.Error("m.RateMean() didn't decrease") } diff --git a/metrics/metrics.go b/metrics/metrics.go index c7fe5c733..a9d662317 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -6,52 +6,29 @@ package metrics import ( - "os" "runtime/metrics" "runtime/pprof" - "strconv" - "strings" - "syscall" "time" +) - "github.com/ethereum/go-ethereum/log" +var ( + metricsEnabled = false ) -// Enabled is checked by the constructor functions for all of the -// standard metrics. If it is true, the metric returned is a stub. +// Enabled is checked by functions that are deemed 'expensive', e.g. if a +// meter-type does locking and/or non-trivial math operations during update. +func Enabled() bool { + return metricsEnabled +} + +// Enable enables the metrics system. +// The Enabled-flag is expected to be set, once, during startup, but toggling off and on +// is not supported. // -// This global kill-switch helps quantify the observer effect and makes -// for less cluttered pprof profiles. -var Enabled = false - -// enablerFlags is the CLI flag names to use to enable metrics collections. -var enablerFlags = []string{"metrics"} - -// enablerEnvVars is the env var names to use to enable metrics collections. -var enablerEnvVars = []string{"GETH_METRICS"} - -// init enables or disables the metrics system. Since we need this to run before -// any other code gets to create meters and timers, we'll actually do an ugly hack -// and peek into the command line args for the metrics flag. -func init() { - for _, enabler := range enablerEnvVars { - if val, found := syscall.Getenv(enabler); found && !Enabled { - if enable, _ := strconv.ParseBool(val); enable { // ignore error, flag parser will choke on it later - log.Info("Enabling metrics collection") - Enabled = true - } - } - } - for _, arg := range os.Args { - flag := strings.TrimLeft(arg, "-") - - for _, enabler := range enablerFlags { - if !Enabled && flag == enabler { - log.Info("Enabling metrics collection") - Enabled = true - } - } - } +// Enable is not safe to call concurrently. You need to call this as early as possible in +// the program, before any metrics collection will happen. +func Enable() { + metricsEnabled = true } var threadCreateProfile = pprof.Lookup("threadcreate") @@ -128,7 +105,7 @@ func readRuntimeStats(v *runtimeStats) { // CollectProcessMetrics periodically collects various metrics about the running process. func CollectProcessMetrics(refresh time.Duration) { // Short circuit if the metrics system is disabled - if !Enabled { + if !metricsEnabled { return } diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index 2861d5f2c..dc144f242 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -7,8 +7,6 @@ import ( "time" ) -const FANOUT = 128 - func TestReadRuntimeValues(t *testing.T) { var v runtimeStats readRuntimeStats(&v) @@ -16,60 +14,23 @@ func TestReadRuntimeValues(t *testing.T) { } func BenchmarkMetrics(b *testing.B) { - r := NewRegistry() - c := NewRegisteredCounter("counter", r) - cf := NewRegisteredCounterFloat64("counterfloat64", r) - g := NewRegisteredGauge("gauge", r) - gf := NewRegisteredGaugeFloat64("gaugefloat64", r) - h := NewRegisteredHistogram("histogram", r, NewUniformSample(100)) - m := NewRegisteredMeter("meter", r) - t := NewRegisteredTimer("timer", r) + var ( + r = NewRegistry() + c = NewRegisteredCounter("counter", r) + cf = NewRegisteredCounterFloat64("counterfloat64", r) + g = NewRegisteredGauge("gauge", r) + gf = NewRegisteredGaugeFloat64("gaugefloat64", r) + h = NewRegisteredHistogram("histogram", r, NewUniformSample(100)) + m = NewRegisteredMeter("meter", r) + t = NewRegisteredTimer("timer", r) + ) RegisterDebugGCStats(r) b.ResetTimer() - ch := make(chan bool) - - wgD := &sync.WaitGroup{} - /* - wgD.Add(1) - go func() { - defer wgD.Done() - //log.Println("go CaptureDebugGCStats") - for { - select { - case <-ch: - //log.Println("done CaptureDebugGCStats") - return - default: - CaptureDebugGCStatsOnce(r) - } - } - }() - //*/ - - wgW := &sync.WaitGroup{} - /* - wgW.Add(1) + var wg sync.WaitGroup + wg.Add(128) + for i := 0; i < 128; i++ { go func() { - defer wgW.Done() - //log.Println("go Write") - for { - select { - case <-ch: - //log.Println("done Write") - return - default: - WriteOnce(r, io.Discard) - } - } - }() - //*/ - - wg := &sync.WaitGroup{} - wg.Add(FANOUT) - for i := 0; i < FANOUT; i++ { - go func(i int) { defer wg.Done() - //log.Println("go", i) for i := 0; i < b.N; i++ { c.Inc(1) cf.Inc(1.0) @@ -79,13 +40,9 @@ func BenchmarkMetrics(b *testing.B) { m.Mark(1) t.Update(1) } - //log.Println("done", i) - }(i) + }() } wg.Wait() - close(ch) - wgD.Wait() - wgW.Wait() } func Example() { diff --git a/metrics/opentsdb.go b/metrics/opentsdb.go index e81690f94..57af3d025 100644 --- a/metrics/opentsdb.go +++ b/metrics/opentsdb.go @@ -64,15 +64,15 @@ func (c *OpenTSDBConfig) writeRegistry(w io.Writer, now int64, shortHostname str c.Registry.Each(func(name string, i interface{}) { switch metric := i.(type) { - case Counter: + case *Counter: fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname) - case CounterFloat64: + case *CounterFloat64: fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname) - case Gauge: + case *Gauge: fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname) - case GaugeFloat64: + case *GaugeFloat64: fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname) - case GaugeInfo: + case *GaugeInfo: fmt.Fprintf(w, "put %s.%s.value %d %s host=%s\n", c.Prefix, name, now, metric.Snapshot().Value().String(), shortHostname) case Histogram: h := metric.Snapshot() @@ -87,14 +87,14 @@ func (c *OpenTSDBConfig) writeRegistry(w io.Writer, now int64, shortHostname str fmt.Fprintf(w, "put %s.%s.95-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[2], shortHostname) fmt.Fprintf(w, "put %s.%s.99-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[3], shortHostname) fmt.Fprintf(w, "put %s.%s.999-percentile %d %.2f host=%s\n", c.Prefix, name, now, ps[4], shortHostname) - case Meter: + case *Meter: m := metric.Snapshot() fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, m.Count(), shortHostname) fmt.Fprintf(w, "put %s.%s.one-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate1(), shortHostname) fmt.Fprintf(w, "put %s.%s.five-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate5(), shortHostname) fmt.Fprintf(w, "put %s.%s.fifteen-minute %d %.2f host=%s\n", c.Prefix, name, now, m.Rate15(), shortHostname) fmt.Fprintf(w, "put %s.%s.mean %d %.2f host=%s\n", c.Prefix, name, now, m.RateMean(), shortHostname) - case Timer: + case *Timer: t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, t.Count(), shortHostname) diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index 353336763..31b8c51b6 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -51,23 +51,23 @@ func newCollector() *collector { // metric type is not supported/known. func (c *collector) Add(name string, i any) error { switch m := i.(type) { - case metrics.Counter: + case *metrics.Counter: c.addCounter(name, m.Snapshot()) - case metrics.CounterFloat64: + case *metrics.CounterFloat64: c.addCounterFloat64(name, m.Snapshot()) - case metrics.Gauge: + case *metrics.Gauge: c.addGauge(name, m.Snapshot()) - case metrics.GaugeFloat64: + case *metrics.GaugeFloat64: c.addGaugeFloat64(name, m.Snapshot()) - case metrics.GaugeInfo: + case *metrics.GaugeInfo: c.addGaugeInfo(name, m.Snapshot()) case metrics.Histogram: c.addHistogram(name, m.Snapshot()) - case metrics.Meter: + case *metrics.Meter: c.addMeter(name, m.Snapshot()) - case metrics.Timer: + case *metrics.Timer: c.addTimer(name, m.Snapshot()) - case metrics.ResettingTimer: + case *metrics.ResettingTimer: c.addResettingTimer(name, m.Snapshot()) default: return fmt.Errorf("unknown prometheus metric type %T", i) @@ -106,11 +106,11 @@ func (c *collector) addHistogram(name string, m metrics.HistogramSnapshot) { c.buff.WriteRune('\n') } -func (c *collector) addMeter(name string, m metrics.MeterSnapshot) { +func (c *collector) addMeter(name string, m *metrics.MeterSnapshot) { c.writeGaugeCounter(name, m.Count()) } -func (c *collector) addTimer(name string, m metrics.TimerSnapshot) { +func (c *collector) addTimer(name string, m *metrics.TimerSnapshot) { pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999} ps := m.Percentiles(pv) c.writeSummaryCounter(name, m.Count()) @@ -121,7 +121,7 @@ func (c *collector) addTimer(name string, m metrics.TimerSnapshot) { c.buff.WriteRune('\n') } -func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnapshot) { +func (c *collector) addResettingTimer(name string, m *metrics.ResettingTimerSnapshot) { if m.Count() <= 0 { return } diff --git a/metrics/prometheus/collector_test.go b/metrics/prometheus/collector_test.go index ea17aac45..a8585d122 100644 --- a/metrics/prometheus/collector_test.go +++ b/metrics/prometheus/collector_test.go @@ -27,7 +27,7 @@ import ( ) func TestMain(m *testing.M) { - metrics.Enabled = true + metrics.Enable() os.Exit(m.Run()) } diff --git a/metrics/registry.go b/metrics/registry.go index ca4741fee..527da6238 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -1,6 +1,7 @@ package metrics import ( + "errors" "fmt" "reflect" "sort" @@ -8,14 +9,10 @@ import ( "sync" ) -// DuplicateMetric is the error returned by Registry. Register when a metric +// ErrDuplicateMetric is the error returned by Registry.Register when a metric // already exists. If you mean to Register that metric you must first // Unregister the existing metric. -type DuplicateMetric string - -func (err DuplicateMetric) Error() string { - return fmt.Sprintf("duplicate metric: %s", string(err)) -} +var ErrDuplicateMetric = errors.New("duplicate metric") // A Registry holds references to a set of metrics by name and can iterate // over them, calling callback functions provided by the user. @@ -114,13 +111,13 @@ func (r *StandardRegistry) GetOrRegister(name string, i interface{}) interface{} return item } -// Register the given metric under the given name. Returns a DuplicateMetric +// Register the given metric under the given name. Returns a ErrDuplicateMetric // if a metric by the given name is already registered. func (r *StandardRegistry) Register(name string, i interface{}) error { // fast path _, ok := r.metrics.Load(name) if ok { - return DuplicateMetric(name) + return fmt.Errorf("%w: %v", ErrDuplicateMetric, name) } if v := reflect.ValueOf(i); v.Kind() == reflect.Func { @@ -128,7 +125,7 @@ func (r *StandardRegistry) Register(name string, i interface{}) error { } _, loaded, _ := r.loadOrRegister(name, i) if loaded { - return DuplicateMetric(name) + return fmt.Errorf("%w: %v", ErrDuplicateMetric, name) } return nil } @@ -136,7 +133,7 @@ func (r *StandardRegistry) Register(name string, i interface{}) error { // RunHealthchecks run all registered healthchecks. func (r *StandardRegistry) RunHealthchecks() { r.metrics.Range(func(key, value any) bool { - if h, ok := value.(Healthcheck); ok { + if h, ok := value.(*Healthcheck); ok { h.Check() } return true @@ -149,15 +146,15 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { r.Each(func(name string, i interface{}) { values := make(map[string]interface{}) switch metric := i.(type) { - case Counter: + case *Counter: values["count"] = metric.Snapshot().Count() - case CounterFloat64: + case *CounterFloat64: values["count"] = metric.Snapshot().Count() - case Gauge: + case *Gauge: values["value"] = metric.Snapshot().Value() - case GaugeFloat64: + case *GaugeFloat64: values["value"] = metric.Snapshot().Value() - case Healthcheck: + case *Healthcheck: values["error"] = nil metric.Check() if err := metric.Error(); nil != err { @@ -176,14 +173,14 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { values["95%"] = ps[2] values["99%"] = ps[3] values["99.9%"] = ps[4] - case Meter: + case *Meter: m := metric.Snapshot() values["count"] = m.Count() values["1m.rate"] = m.Rate1() values["5m.rate"] = m.Rate5() values["15m.rate"] = m.Rate15() values["mean.rate"] = m.RateMean() - case Timer: + case *Timer: t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) values["count"] = t.Count() @@ -214,7 +211,7 @@ func (r *StandardRegistry) Unregister(name string) { func (r *StandardRegistry) loadOrRegister(name string, i interface{}) (interface{}, bool, bool) { switch i.(type) { - case Counter, CounterFloat64, Gauge, GaugeFloat64, GaugeInfo, Healthcheck, Histogram, Meter, Timer, ResettingTimer: + case *Counter, *CounterFloat64, *Gauge, *GaugeFloat64, *GaugeInfo, *Healthcheck, Histogram, *Meter, *Timer, *ResettingTimer: default: return nil, false, false } @@ -326,9 +323,7 @@ func (r *PrefixedRegistry) Unregister(name string) { } var ( - DefaultRegistry = NewRegistry() - EphemeralRegistry = NewRegistry() - AccountingRegistry = NewRegistry() // registry used in swarm + DefaultRegistry = NewRegistry() ) // Each call the given function for each registered metric. @@ -347,7 +342,7 @@ func GetOrRegister(name string, i interface{}) interface{} { return DefaultRegistry.GetOrRegister(name, i) } -// Register the given metric under the given name. Returns a DuplicateMetric +// Register the given metric under the given name. Returns a ErrDuplicateMetric // if a metric by the given name is already registered. func Register(name string, i interface{}) error { return DefaultRegistry.Register(name, i) diff --git a/metrics/registry_test.go b/metrics/registry_test.go index 75012dd4a..bdc58fee6 100644 --- a/metrics/registry_test.go +++ b/metrics/registry_test.go @@ -47,7 +47,7 @@ func TestRegistry(t *testing.T) { if name != "foo" { t.Fatal(name) } - if _, ok := iface.(Counter); !ok { + if _, ok := iface.(*Counter); !ok { t.Fatal(iface) } }) @@ -73,7 +73,7 @@ func TestRegistryDuplicate(t *testing.T) { i := 0 r.Each(func(name string, iface interface{}) { i++ - if _, ok := iface.(Counter); !ok { + if _, ok := iface.(*Counter); !ok { t.Fatal(iface) } }) @@ -85,11 +85,11 @@ func TestRegistryDuplicate(t *testing.T) { func TestRegistryGet(t *testing.T) { r := NewRegistry() r.Register("foo", NewCounter()) - if count := r.Get("foo").(Counter).Snapshot().Count(); count != 0 { + if count := r.Get("foo").(*Counter).Snapshot().Count(); count != 0 { t.Fatal(count) } - r.Get("foo").(Counter).Inc(1) - if count := r.Get("foo").(Counter).Snapshot().Count(); count != 1 { + r.Get("foo").(*Counter).Inc(1) + if count := r.Get("foo").(*Counter).Snapshot().Count(); count != 1 { t.Fatal(count) } } @@ -100,7 +100,7 @@ func TestRegistryGetOrRegister(t *testing.T) { // First metric wins with GetOrRegister _ = r.GetOrRegister("foo", NewCounter()) m := r.GetOrRegister("foo", NewGauge()) - if _, ok := m.(Counter); !ok { + if _, ok := m.(*Counter); !ok { t.Fatal(m) } @@ -110,7 +110,7 @@ func TestRegistryGetOrRegister(t *testing.T) { if name != "foo" { t.Fatal(name) } - if _, ok := iface.(Counter); !ok { + if _, ok := iface.(*Counter); !ok { t.Fatal(iface) } }) @@ -125,7 +125,7 @@ func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) { // First metric wins with GetOrRegister _ = r.GetOrRegister("foo", NewCounter) m := r.GetOrRegister("foo", NewGauge) - if _, ok := m.(Counter); !ok { + if _, ok := m.(*Counter); !ok { t.Fatal(m) } @@ -135,7 +135,7 @@ func TestRegistryGetOrRegisterWithLazyInstantiation(t *testing.T) { if name != "foo" { t.Fatal(name) } - if _, ok := iface.(Counter); !ok { + if _, ok := iface.(*Counter); !ok { t.Fatal(iface) } }) diff --git a/metrics/resetting_sample.go b/metrics/resetting_sample.go index c38ffcd3e..730ef9341 100644 --- a/metrics/resetting_sample.go +++ b/metrics/resetting_sample.go @@ -17,7 +17,7 @@ type resettingSample struct { } // Snapshot returns a read-only copy of the sample with the original reset. -func (rs *resettingSample) Snapshot() SampleSnapshot { +func (rs *resettingSample) Snapshot() *sampleSnapshot { s := rs.Sample.Snapshot() rs.Sample.Clear() return s diff --git a/metrics/resetting_timer.go b/metrics/resetting_timer.go index 6802e3fce..1b3e87bc3 100644 --- a/metrics/resetting_timer.go +++ b/metrics/resetting_timer.go @@ -5,36 +5,17 @@ import ( "time" ) -// Initial slice capacity for the values stored in a ResettingTimer -const InitialResettingTimerSliceCap = 10 - -type ResettingTimerSnapshot interface { - Count() int - Mean() float64 - Max() int64 - Min() int64 - Percentiles([]float64) []float64 -} - -// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval. -type ResettingTimer interface { - Snapshot() ResettingTimerSnapshot - Time(func()) - Update(time.Duration) - UpdateSince(time.Time) -} - // GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a -// new StandardResettingTimer. -func GetOrRegisterResettingTimer(name string, r Registry) ResettingTimer { +// new ResettingTimer. +func GetOrRegisterResettingTimer(name string, r Registry) *ResettingTimer { if nil == r { r = DefaultRegistry } - return r.GetOrRegister(name, NewResettingTimer).(ResettingTimer) + return r.GetOrRegister(name, NewResettingTimer).(*ResettingTimer) } -// NewRegisteredResettingTimer constructs and registers a new StandardResettingTimer. -func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer { +// NewRegisteredResettingTimer constructs and registers a new ResettingTimer. +func NewRegisteredResettingTimer(name string, r Registry) *ResettingTimer { c := NewResettingTimer() if nil == r { r = DefaultRegistry @@ -43,33 +24,15 @@ func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer { return c } -// NewResettingTimer constructs a new StandardResettingTimer -func NewResettingTimer() ResettingTimer { - if !Enabled { - return NilResettingTimer{} - } - return &StandardResettingTimer{ - values: make([]int64, 0, InitialResettingTimerSliceCap), +// NewResettingTimer constructs a new ResettingTimer +func NewResettingTimer() *ResettingTimer { + return &ResettingTimer{ + values: make([]int64, 0, 10), } } -// NilResettingTimer is a no-op ResettingTimer. -type NilResettingTimer struct{} - -func (NilResettingTimer) Values() []int64 { return nil } -func (n NilResettingTimer) Snapshot() ResettingTimerSnapshot { return n } -func (NilResettingTimer) Time(f func()) { f() } -func (NilResettingTimer) Update(time.Duration) {} -func (NilResettingTimer) Percentiles([]float64) []float64 { return nil } -func (NilResettingTimer) Mean() float64 { return 0.0 } -func (NilResettingTimer) Max() int64 { return 0 } -func (NilResettingTimer) Min() int64 { return 0 } -func (NilResettingTimer) UpdateSince(time.Time) {} -func (NilResettingTimer) Count() int { return 0 } - -// StandardResettingTimer is the standard implementation of a ResettingTimer. -// and Meter. -type StandardResettingTimer struct { +// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval. +type ResettingTimer struct { values []int64 sum int64 // sum is a running count of the total sum, used later to calculate mean @@ -77,28 +40,31 @@ type StandardResettingTimer struct { } // Snapshot resets the timer and returns a read-only copy of its contents. -func (t *StandardResettingTimer) Snapshot() ResettingTimerSnapshot { +func (t *ResettingTimer) Snapshot() *ResettingTimerSnapshot { t.mutex.Lock() defer t.mutex.Unlock() - snapshot := &resettingTimerSnapshot{} + snapshot := &ResettingTimerSnapshot{} if len(t.values) > 0 { snapshot.mean = float64(t.sum) / float64(len(t.values)) snapshot.values = t.values - t.values = make([]int64, 0, InitialResettingTimerSliceCap) + t.values = make([]int64, 0, 10) } t.sum = 0 return snapshot } // Record the duration of the execution of the given function. -func (t *StandardResettingTimer) Time(f func()) { +func (t *ResettingTimer) Time(f func()) { ts := time.Now() f() t.Update(time.Since(ts)) } // Record the duration of an event. -func (t *StandardResettingTimer) Update(d time.Duration) { +func (t *ResettingTimer) Update(d time.Duration) { + if !metricsEnabled { + return + } t.mutex.Lock() defer t.mutex.Unlock() t.values = append(t.values, int64(d)) @@ -106,12 +72,12 @@ func (t *StandardResettingTimer) Update(d time.Duration) { } // Record the duration of an event that started at a time and ends now. -func (t *StandardResettingTimer) UpdateSince(ts time.Time) { +func (t *ResettingTimer) UpdateSince(ts time.Time) { t.Update(time.Since(ts)) } -// resettingTimerSnapshot is a point-in-time copy of another ResettingTimer. -type resettingTimerSnapshot struct { +// ResettingTimerSnapshot is a point-in-time copy of another ResettingTimer. +type ResettingTimerSnapshot struct { values []int64 mean float64 max int64 @@ -121,20 +87,20 @@ type resettingTimerSnapshot struct { } // Count return the length of the values from snapshot. -func (t *resettingTimerSnapshot) Count() int { +func (t *ResettingTimerSnapshot) Count() int { return len(t.values) } // Percentiles returns the boundaries for the input percentiles. // note: this method is not thread safe -func (t *resettingTimerSnapshot) Percentiles(percentiles []float64) []float64 { +func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []float64 { t.calc(percentiles) return t.thresholdBoundaries } // Mean returns the mean of the snapshotted values // note: this method is not thread safe -func (t *resettingTimerSnapshot) Mean() float64 { +func (t *ResettingTimerSnapshot) Mean() float64 { if !t.calculated { t.calc(nil) } @@ -144,7 +110,7 @@ func (t *resettingTimerSnapshot) Mean() float64 { // Max returns the max of the snapshotted values // note: this method is not thread safe -func (t *resettingTimerSnapshot) Max() int64 { +func (t *ResettingTimerSnapshot) Max() int64 { if !t.calculated { t.calc(nil) } @@ -153,14 +119,14 @@ func (t *resettingTimerSnapshot) Max() int64 { // Min returns the min of the snapshotted values // note: this method is not thread safe -func (t *resettingTimerSnapshot) Min() int64 { +func (t *ResettingTimerSnapshot) Min() int64 { if !t.calculated { t.calc(nil) } return t.min } -func (t *resettingTimerSnapshot) calc(percentiles []float64) { +func (t *ResettingTimerSnapshot) calc(percentiles []float64) { scores := CalculatePercentiles(t.values, percentiles) t.thresholdBoundaries = scores if len(t.values) == 0 { diff --git a/metrics/sample.go b/metrics/sample.go index 17b2bee28..dc8167809 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -10,27 +10,123 @@ import ( const rescaleThreshold = time.Hour -type SampleSnapshot interface { - Count() int64 - Max() int64 - Mean() float64 - Min() int64 - Percentile(float64) float64 - Percentiles([]float64) []float64 - Size() int - StdDev() float64 - Sum() int64 - Variance() float64 -} - -// Samples maintain a statistically-significant selection of values from +// Sample maintains a statistically-significant selection of values from // a stream. type Sample interface { - Snapshot() SampleSnapshot + Snapshot() *sampleSnapshot Clear() Update(int64) } +var ( + _ Sample = (*ExpDecaySample)(nil) + _ Sample = (*UniformSample)(nil) + _ Sample = (*resettingSample)(nil) +) + +// sampleSnapshot is a read-only copy of a Sample. +type sampleSnapshot struct { + count int64 + values []int64 + + max int64 + min int64 + mean float64 + sum int64 + variance float64 +} + +// newSampleSnapshotPrecalculated creates a read-only sampleSnapShot, using +// precalculated sums to avoid iterating the values +func newSampleSnapshotPrecalculated(count int64, values []int64, min, max, sum int64) *sampleSnapshot { + if len(values) == 0 { + return &sampleSnapshot{ + count: count, + values: values, + } + } + return &sampleSnapshot{ + count: count, + values: values, + max: max, + min: min, + mean: float64(sum) / float64(len(values)), + sum: sum, + } +} + +// newSampleSnapshot creates a read-only sampleSnapShot, and calculates some +// numbers. +func newSampleSnapshot(count int64, values []int64) *sampleSnapshot { + var ( + max int64 = math.MinInt64 + min int64 = math.MaxInt64 + sum int64 + ) + for _, v := range values { + sum += v + if v > max { + max = v + } + if v < min { + min = v + } + } + return newSampleSnapshotPrecalculated(count, values, min, max, sum) +} + +// Count returns the count of inputs at the time the snapshot was taken. +func (s *sampleSnapshot) Count() int64 { return s.count } + +// Max returns the maximal value at the time the snapshot was taken. +func (s *sampleSnapshot) Max() int64 { return s.max } + +// Mean returns the mean value at the time the snapshot was taken. +func (s *sampleSnapshot) Mean() float64 { return s.mean } + +// Min returns the minimal value at the time the snapshot was taken. +func (s *sampleSnapshot) Min() int64 { return s.min } + +// Percentile returns an arbitrary percentile of values at the time the +// snapshot was taken. +func (s *sampleSnapshot) Percentile(p float64) float64 { + return SamplePercentile(s.values, p) +} + +// Percentiles returns a slice of arbitrary percentiles of values at the time +// the snapshot was taken. +func (s *sampleSnapshot) Percentiles(ps []float64) []float64 { + return CalculatePercentiles(s.values, ps) +} + +// Size returns the size of the sample at the time the snapshot was taken. +func (s *sampleSnapshot) Size() int { return len(s.values) } + +// StdDev returns the standard deviation of values at the time the snapshot was +// taken. +func (s *sampleSnapshot) StdDev() float64 { + if s.variance == 0.0 { + s.variance = SampleVariance(s.mean, s.values) + } + return math.Sqrt(s.variance) +} + +// Sum returns the sum of values at the time the snapshot was taken. +func (s *sampleSnapshot) Sum() int64 { return s.sum } + +// Values returns a copy of the values in the sample. +func (s *sampleSnapshot) Values() []int64 { + return slices.Clone(s.values) +} + +// Variance returns the variance of values at the time the snapshot was taken. +func (s *sampleSnapshot) Variance() float64 { + if s.variance == 0.0 { + s.variance = SampleVariance(s.mean, s.values) + } + return s.variance +} + // ExpDecaySample is an exponentially-decaying sample using a forward-decaying // priority reservoir. See Cormode et al's "Forward Decay: A Practical Time // Decay Model for Streaming Systems". @@ -49,9 +145,6 @@ type ExpDecaySample struct { // NewExpDecaySample constructs a new exponentially-decaying sample with the // given reservoir size and alpha. func NewExpDecaySample(reservoirSize int, alpha float64) Sample { - if !Enabled { - return NilSample{} - } s := &ExpDecaySample{ alpha: alpha, reservoirSize: reservoirSize, @@ -79,7 +172,7 @@ func (s *ExpDecaySample) Clear() { } // Snapshot returns a read-only copy of the sample. -func (s *ExpDecaySample) Snapshot() SampleSnapshot { +func (s *ExpDecaySample) Snapshot() *sampleSnapshot { s.mutex.Lock() defer s.mutex.Unlock() var ( @@ -105,6 +198,9 @@ func (s *ExpDecaySample) Snapshot() SampleSnapshot { // Update samples a new value. func (s *ExpDecaySample) Update(v int64) { + if !metricsEnabled { + return + } s.update(time.Now(), v) } @@ -140,13 +236,6 @@ func (s *ExpDecaySample) update(t time.Time, v int64) { } } -// NilSample is a no-op Sample. -type NilSample struct{} - -func (NilSample) Clear() {} -func (NilSample) Snapshot() SampleSnapshot { return (*emptySnapshot)(nil) } -func (NilSample) Update(v int64) {} - // SamplePercentile returns an arbitrary percentile of the slice of int64. func SamplePercentile(values []int64, p float64) float64 { return CalculatePercentiles(values, []float64{p})[0] @@ -181,114 +270,6 @@ func CalculatePercentiles(values []int64, ps []float64) []float64 { return scores } -// sampleSnapshot is a read-only copy of another Sample. -type sampleSnapshot struct { - count int64 - values []int64 - - max int64 - min int64 - mean float64 - sum int64 - variance float64 -} - -// newSampleSnapshotPrecalculated creates a read-only sampleSnapShot, using -// precalculated sums to avoid iterating the values -func newSampleSnapshotPrecalculated(count int64, values []int64, min, max, sum int64) *sampleSnapshot { - if len(values) == 0 { - return &sampleSnapshot{ - count: count, - values: values, - } - } - return &sampleSnapshot{ - count: count, - values: values, - max: max, - min: min, - mean: float64(sum) / float64(len(values)), - sum: sum, - } -} - -// newSampleSnapshot creates a read-only sampleSnapShot, and calculates some -// numbers. -func newSampleSnapshot(count int64, values []int64) *sampleSnapshot { - var ( - max int64 = math.MinInt64 - min int64 = math.MaxInt64 - sum int64 - ) - for _, v := range values { - sum += v - if v > max { - max = v - } - if v < min { - min = v - } - } - return newSampleSnapshotPrecalculated(count, values, min, max, sum) -} - -// Count returns the count of inputs at the time the snapshot was taken. -func (s *sampleSnapshot) Count() int64 { return s.count } - -// Max returns the maximal value at the time the snapshot was taken. -func (s *sampleSnapshot) Max() int64 { return s.max } - -// Mean returns the mean value at the time the snapshot was taken. -func (s *sampleSnapshot) Mean() float64 { return s.mean } - -// Min returns the minimal value at the time the snapshot was taken. -func (s *sampleSnapshot) Min() int64 { return s.min } - -// Percentile returns an arbitrary percentile of values at the time the -// snapshot was taken. -func (s *sampleSnapshot) Percentile(p float64) float64 { - return SamplePercentile(s.values, p) -} - -// Percentiles returns a slice of arbitrary percentiles of values at the time -// the snapshot was taken. -func (s *sampleSnapshot) Percentiles(ps []float64) []float64 { - return CalculatePercentiles(s.values, ps) -} - -// Size returns the size of the sample at the time the snapshot was taken. -func (s *sampleSnapshot) Size() int { return len(s.values) } - -// Snapshot returns the snapshot. -func (s *sampleSnapshot) Snapshot() SampleSnapshot { return s } - -// StdDev returns the standard deviation of values at the time the snapshot was -// taken. -func (s *sampleSnapshot) StdDev() float64 { - if s.variance == 0.0 { - s.variance = SampleVariance(s.mean, s.values) - } - return math.Sqrt(s.variance) -} - -// Sum returns the sum of values at the time the snapshot was taken. -func (s *sampleSnapshot) Sum() int64 { return s.sum } - -// Values returns a copy of the values in the sample. -func (s *sampleSnapshot) Values() []int64 { - values := make([]int64, len(s.values)) - copy(values, s.values) - return values -} - -// Variance returns the variance of values at the time the snapshot was taken. -func (s *sampleSnapshot) Variance() float64 { - if s.variance == 0.0 { - s.variance = SampleVariance(s.mean, s.values) - } - return s.variance -} - // SampleVariance returns the variance of the slice of int64. func SampleVariance(mean float64, values []int64) float64 { if len(values) == 0 { @@ -302,7 +283,7 @@ func SampleVariance(mean float64, values []int64) float64 { return sum / float64(len(values)) } -// A uniform sample using Vitter's Algorithm R. +// UniformSample implements a uniform sample using Vitter's Algorithm R. // // type UniformSample struct { @@ -316,9 +297,6 @@ type UniformSample struct { // NewUniformSample constructs a new uniform sample with the given reservoir // size. func NewUniformSample(reservoirSize int) Sample { - if !Enabled { - return NilSample{} - } return &UniformSample{ reservoirSize: reservoirSize, values: make([]int64, 0, reservoirSize), @@ -336,14 +314,13 @@ func (s *UniformSample) Clear() { s.mutex.Lock() defer s.mutex.Unlock() s.count = 0 - s.values = make([]int64, 0, s.reservoirSize) + clear(s.values) } // Snapshot returns a read-only copy of the sample. -func (s *UniformSample) Snapshot() SampleSnapshot { +func (s *UniformSample) Snapshot() *sampleSnapshot { s.mutex.Lock() - values := make([]int64, len(s.values)) - copy(values, s.values) + values := slices.Clone(s.values) count := s.count s.mutex.Unlock() return newSampleSnapshot(count, values) @@ -351,21 +328,24 @@ func (s *UniformSample) Snapshot() SampleSnapshot { // Update samples a new value. func (s *UniformSample) Update(v int64) { + if !metricsEnabled { + return + } s.mutex.Lock() defer s.mutex.Unlock() s.count++ if len(s.values) < s.reservoirSize { s.values = append(s.values, v) + return + } + var r int64 + if s.rand != nil { + r = s.rand.Int63n(s.count) } else { - var r int64 - if s.rand != nil { - r = s.rand.Int63n(s.count) - } else { - r = rand.Int63n(s.count) - } - if r < int64(len(s.values)) { - s.values[int(r)] = v - } + r = rand.Int63n(s.count) + } + if r < int64(len(s.values)) { + s.values[int(r)] = v } } diff --git a/metrics/sample_test.go b/metrics/sample_test.go index c855671ae..6619eb1e9 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -86,7 +86,7 @@ func TestExpDecaySample(t *testing.T) { if have, want := snap.Size(), min(tc.updates, tc.reservoirSize); have != want { t.Errorf("unexpected size: have %d want %d", have, want) } - values := snap.(*sampleSnapshot).values + values := snap.values if have, want := len(values), min(tc.updates, tc.reservoirSize); have != want { t.Errorf("unexpected values length: have %d want %d", have, want) } @@ -111,8 +111,7 @@ func TestExpDecaySampleNanosecondRegression(t *testing.T) { for i := 0; i < 1000; i++ { sw.Update(20) } - s := sw.Snapshot() - v := s.(*sampleSnapshot).values + v := sw.Snapshot().values avg := float64(0) for i := 0; i < len(v); i++ { avg += float64(v[i]) @@ -166,7 +165,7 @@ func TestUniformSample(t *testing.T) { if size := s.Size(); size != 100 { t.Errorf("s.Size(): 100 != %v\n", size) } - values := s.(*sampleSnapshot).values + values := s.values if l := len(values); l != 100 { t.Errorf("len(s.Values()): 100 != %v\n", l) @@ -184,8 +183,7 @@ func TestUniformSampleIncludesTail(t *testing.T) { for i := 0; i < max; i++ { sw.Update(int64(i)) } - s := sw.Snapshot() - v := s.(*sampleSnapshot).values + v := sw.Snapshot().values sum := 0 exp := (max - 1) * max / 2 for i := 0; i < len(v); i++ { @@ -220,7 +218,7 @@ func benchmarkSample(b *testing.B, s Sample) { } } -func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) { +func testExpDecaySampleStatistics(t *testing.T, s *sampleSnapshot) { if sum := s.Sum(); sum != 496598 { t.Errorf("s.Sum(): 496598 != %v\n", sum) } @@ -251,7 +249,7 @@ func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) { } } -func testUniformSampleStatistics(t *testing.T, s SampleSnapshot) { +func testUniformSampleStatistics(t *testing.T, s *sampleSnapshot) { if count := s.Count(); count != 10000 { t.Errorf("s.Count(): 10000 != %v\n", count) } diff --git a/metrics/syslog.go b/metrics/syslog.go index fd856d697..0bc4ed0da 100644 --- a/metrics/syslog.go +++ b/metrics/syslog.go @@ -15,17 +15,17 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) { for range time.Tick(d) { r.Each(func(name string, i interface{}) { switch metric := i.(type) { - case Counter: + case *Counter: w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Snapshot().Count())) - case CounterFloat64: + case *CounterFloat64: w.Info(fmt.Sprintf("counter %s: count: %f", name, metric.Snapshot().Count())) - case Gauge: + case *Gauge: w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Snapshot().Value())) - case GaugeFloat64: + case *GaugeFloat64: w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Snapshot().Value())) - case GaugeInfo: + case *GaugeInfo: w.Info(fmt.Sprintf("gauge %s: value: %s", name, metric.Snapshot().Value())) - case Healthcheck: + case *Healthcheck: metric.Check() w.Info(fmt.Sprintf("healthcheck %s: error: %v", name, metric.Error())) case Histogram: @@ -45,7 +45,7 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) { ps[3], ps[4], )) - case Meter: + case *Meter: m := metric.Snapshot() w.Info(fmt.Sprintf( "meter %s: count: %d 1-min: %.2f 5-min: %.2f 15-min: %.2f mean: %.2f", @@ -56,7 +56,7 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) { m.Rate15(), m.RateMean(), )) - case Timer: + case *Timer: t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) w.Info(fmt.Sprintf( diff --git a/metrics/timer.go b/metrics/timer.go index fc2a88f50..9df15c967 100644 --- a/metrics/timer.go +++ b/metrics/timer.go @@ -5,47 +5,30 @@ import ( "time" ) -type TimerSnapshot interface { - HistogramSnapshot - MeterSnapshot -} - -// Timer capture the duration and rate of events. -type Timer interface { - Snapshot() TimerSnapshot - Stop() - Time(func()) - UpdateSince(time.Time) - Update(time.Duration) -} - // GetOrRegisterTimer returns an existing Timer or constructs and registers a -// new StandardTimer. +// new Timer. // Be sure to unregister the meter from the registry once it is of no use to // allow for garbage collection. -func GetOrRegisterTimer(name string, r Registry) Timer { +func GetOrRegisterTimer(name string, r Registry) *Timer { if nil == r { r = DefaultRegistry } - return r.GetOrRegister(name, NewTimer).(Timer) + return r.GetOrRegister(name, NewTimer).(*Timer) } -// NewCustomTimer constructs a new StandardTimer from a Histogram and a Meter. +// NewCustomTimer constructs a new Timer from a Histogram and a Meter. // Be sure to call Stop() once the timer is of no use to allow for garbage collection. -func NewCustomTimer(h Histogram, m Meter) Timer { - if !Enabled { - return NilTimer{} - } - return &StandardTimer{ +func NewCustomTimer(h Histogram, m *Meter) *Timer { + return &Timer{ histogram: h, meter: m, } } -// NewRegisteredTimer constructs and registers a new StandardTimer. +// NewRegisteredTimer constructs and registers a new Timer. // Be sure to unregister the meter from the registry once it is of no use to // allow for garbage collection. -func NewRegisteredTimer(name string, r Registry) Timer { +func NewRegisteredTimer(name string, r Registry) *Timer { c := NewTimer() if nil == r { r = DefaultRegistry @@ -54,60 +37,47 @@ func NewRegisteredTimer(name string, r Registry) Timer { return c } -// NewTimer constructs a new StandardTimer using an exponentially-decaying +// NewTimer constructs a new Timer using an exponentially-decaying // sample with the same reservoir size and alpha as UNIX load averages. // Be sure to call Stop() once the timer is of no use to allow for garbage collection. -func NewTimer() Timer { - if !Enabled { - return NilTimer{} - } - return &StandardTimer{ +func NewTimer() *Timer { + return &Timer{ histogram: NewHistogram(NewExpDecaySample(1028, 0.015)), meter: NewMeter(), } } -// NilTimer is a no-op Timer. -type NilTimer struct{} - -func (NilTimer) Snapshot() TimerSnapshot { return (*emptySnapshot)(nil) } -func (NilTimer) Stop() {} -func (NilTimer) Time(f func()) { f() } -func (NilTimer) Update(time.Duration) {} -func (NilTimer) UpdateSince(time.Time) {} - -// StandardTimer is the standard implementation of a Timer and uses a Histogram -// and Meter. -type StandardTimer struct { +// Timer captures the duration and rate of events, using a Histogram and a Meter. +type Timer struct { histogram Histogram - meter Meter + meter *Meter mutex sync.Mutex } // Snapshot returns a read-only copy of the timer. -func (t *StandardTimer) Snapshot() TimerSnapshot { +func (t *Timer) Snapshot() *TimerSnapshot { t.mutex.Lock() defer t.mutex.Unlock() - return &timerSnapshot{ + return &TimerSnapshot{ histogram: t.histogram.Snapshot(), meter: t.meter.Snapshot(), } } // Stop stops the meter. -func (t *StandardTimer) Stop() { +func (t *Timer) Stop() { t.meter.Stop() } // Time record the duration of the execution of the given function. -func (t *StandardTimer) Time(f func()) { +func (t *Timer) Time(f func()) { ts := time.Now() f() t.Update(time.Since(ts)) } // Update the duration of an event, in nanoseconds. -func (t *StandardTimer) Update(d time.Duration) { +func (t *Timer) Update(d time.Duration) { t.mutex.Lock() defer t.mutex.Unlock() t.histogram.Update(d.Nanoseconds()) @@ -116,67 +86,67 @@ func (t *StandardTimer) Update(d time.Duration) { // UpdateSince update the duration of an event that started at a time and ends now. // The record uses nanoseconds. -func (t *StandardTimer) UpdateSince(ts time.Time) { +func (t *Timer) UpdateSince(ts time.Time) { t.Update(time.Since(ts)) } -// timerSnapshot is a read-only copy of another Timer. -type timerSnapshot struct { +// TimerSnapshot is a read-only copy of another Timer. +type TimerSnapshot struct { histogram HistogramSnapshot - meter MeterSnapshot + meter *MeterSnapshot } // Count returns the number of events recorded at the time the snapshot was // taken. -func (t *timerSnapshot) Count() int64 { return t.histogram.Count() } +func (t *TimerSnapshot) Count() int64 { return t.histogram.Count() } // Max returns the maximum value at the time the snapshot was taken. -func (t *timerSnapshot) Max() int64 { return t.histogram.Max() } +func (t *TimerSnapshot) Max() int64 { return t.histogram.Max() } // Size returns the size of the sample at the time the snapshot was taken. -func (t *timerSnapshot) Size() int { return t.histogram.Size() } +func (t *TimerSnapshot) Size() int { return t.histogram.Size() } // Mean returns the mean value at the time the snapshot was taken. -func (t *timerSnapshot) Mean() float64 { return t.histogram.Mean() } +func (t *TimerSnapshot) Mean() float64 { return t.histogram.Mean() } // Min returns the minimum value at the time the snapshot was taken. -func (t *timerSnapshot) Min() int64 { return t.histogram.Min() } +func (t *TimerSnapshot) Min() int64 { return t.histogram.Min() } // Percentile returns an arbitrary percentile of sampled values at the time the // snapshot was taken. -func (t *timerSnapshot) Percentile(p float64) float64 { +func (t *TimerSnapshot) Percentile(p float64) float64 { return t.histogram.Percentile(p) } // Percentiles returns a slice of arbitrary percentiles of sampled values at // the time the snapshot was taken. -func (t *timerSnapshot) Percentiles(ps []float64) []float64 { +func (t *TimerSnapshot) Percentiles(ps []float64) []float64 { return t.histogram.Percentiles(ps) } // Rate1 returns the one-minute moving average rate of events per second at the // time the snapshot was taken. -func (t *timerSnapshot) Rate1() float64 { return t.meter.Rate1() } +func (t *TimerSnapshot) Rate1() float64 { return t.meter.Rate1() } // Rate5 returns the five-minute moving average rate of events per second at // the time the snapshot was taken. -func (t *timerSnapshot) Rate5() float64 { return t.meter.Rate5() } +func (t *TimerSnapshot) Rate5() float64 { return t.meter.Rate5() } // Rate15 returns the fifteen-minute moving average rate of events per second // at the time the snapshot was taken. -func (t *timerSnapshot) Rate15() float64 { return t.meter.Rate15() } +func (t *TimerSnapshot) Rate15() float64 { return t.meter.Rate15() } // RateMean returns the meter's mean rate of events per second at the time the // snapshot was taken. -func (t *timerSnapshot) RateMean() float64 { return t.meter.RateMean() } +func (t *TimerSnapshot) RateMean() float64 { return t.meter.RateMean() } // StdDev returns the standard deviation of the values at the time the snapshot // was taken. -func (t *timerSnapshot) StdDev() float64 { return t.histogram.StdDev() } +func (t *TimerSnapshot) StdDev() float64 { return t.histogram.StdDev() } // Sum returns the sum at the time the snapshot was taken. -func (t *timerSnapshot) Sum() int64 { return t.histogram.Sum() } +func (t *TimerSnapshot) Sum() int64 { return t.histogram.Sum() } // Variance returns the variance of the values at the time the snapshot was // taken. -func (t *timerSnapshot) Variance() float64 { return t.histogram.Variance() } +func (t *TimerSnapshot) Variance() float64 { return t.histogram.Variance() } diff --git a/metrics/writer.go b/metrics/writer.go index c211c5046..2a41f8e1f 100644 --- a/metrics/writer.go +++ b/metrics/writer.go @@ -26,22 +26,22 @@ func WriteOnce(r Registry, w io.Writer) { slices.SortFunc(namedMetrics, namedMetric.cmp) for _, namedMetric := range namedMetrics { switch metric := namedMetric.m.(type) { - case Counter: + case *Counter: fmt.Fprintf(w, "counter %s\n", namedMetric.name) fmt.Fprintf(w, " count: %9d\n", metric.Snapshot().Count()) - case CounterFloat64: + case *CounterFloat64: fmt.Fprintf(w, "counter %s\n", namedMetric.name) fmt.Fprintf(w, " count: %f\n", metric.Snapshot().Count()) - case Gauge: + case *Gauge: fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, " value: %9d\n", metric.Snapshot().Value()) - case GaugeFloat64: + case *GaugeFloat64: fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, " value: %f\n", metric.Snapshot().Value()) - case GaugeInfo: + case *GaugeInfo: fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, " value: %s\n", metric.Snapshot().Value().String()) - case Healthcheck: + case *Healthcheck: metric.Check() fmt.Fprintf(w, "healthcheck %s\n", namedMetric.name) fmt.Fprintf(w, " error: %v\n", metric.Error()) @@ -59,7 +59,7 @@ func WriteOnce(r Registry, w io.Writer) { fmt.Fprintf(w, " 95%%: %12.2f\n", ps[2]) fmt.Fprintf(w, " 99%%: %12.2f\n", ps[3]) fmt.Fprintf(w, " 99.9%%: %12.2f\n", ps[4]) - case Meter: + case *Meter: m := metric.Snapshot() fmt.Fprintf(w, "meter %s\n", namedMetric.name) fmt.Fprintf(w, " count: %9d\n", m.Count()) @@ -67,7 +67,7 @@ func WriteOnce(r Registry, w io.Writer) { fmt.Fprintf(w, " 5-min rate: %12.2f\n", m.Rate5()) fmt.Fprintf(w, " 15-min rate: %12.2f\n", m.Rate15()) fmt.Fprintf(w, " mean rate: %12.2f\n", m.RateMean()) - case Timer: + case *Timer: t := metric.Snapshot() ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) fmt.Fprintf(w, "timer %s\n", namedMetric.name) diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go index 9261ae137..5d4c953c9 100644 --- a/p2p/discover/metrics.go +++ b/p2p/discover/metrics.go @@ -34,7 +34,7 @@ const ( ) var ( - bucketsCounter []metrics.Counter + bucketsCounter []*metrics.Counter ingressTrafficMeter = metrics.NewRegisteredMeter(ingressMeterName, nil) egressTrafficMeter = metrics.NewRegisteredMeter(egressMeterName, nil) ) @@ -53,7 +53,7 @@ type meteredUdpConn struct { func newMeteredConn(conn UDPConn) UDPConn { // Short circuit if metrics are disabled - if !metrics.Enabled { + if !metrics.Enabled() { return conn } return &meteredUdpConn{udpConn: conn} diff --git a/p2p/discover/table.go b/p2p/discover/table.go index cbe297254..392279f90 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -570,7 +570,7 @@ func (tab *Table) nodeAdded(b *bucket, n *tableNode) { if tab.nodeAddedHook != nil { tab.nodeAddedHook(b, n) } - if metrics.Enabled { + if metrics.Enabled() { bucketsCounter[b.index].Inc(1) } } @@ -580,7 +580,7 @@ func (tab *Table) nodeRemoved(b *bucket, n *tableNode) { if tab.nodeRemovedHook != nil { tab.nodeRemovedHook(b, n) } - if metrics.Enabled { + if metrics.Enabled() { bucketsCounter[b.index].Dec(1) } } diff --git a/p2p/metrics.go b/p2p/metrics.go index a2ae213b7..1fd0f26db 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -37,19 +37,19 @@ const ( ) var ( - activePeerGauge metrics.Gauge = metrics.NilGauge{} - activeInboundPeerGauge metrics.Gauge = metrics.NilGauge{} - activeOutboundPeerGauge metrics.Gauge = metrics.NilGauge{} + activePeerGauge = metrics.NewRegisteredGauge("p2p/peers", nil) + activeInboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/inbound", nil) + activeOutboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/outbound", nil) ingressTrafficMeter = metrics.NewRegisteredMeter("p2p/ingress", nil) egressTrafficMeter = metrics.NewRegisteredMeter("p2p/egress", nil) // general ingress/egress connection meters - serveMeter metrics.Meter = metrics.NilMeter{} - serveSuccessMeter metrics.Meter = metrics.NilMeter{} - dialMeter metrics.Meter = metrics.NilMeter{} - dialSuccessMeter metrics.Meter = metrics.NilMeter{} - dialConnectionError metrics.Meter = metrics.NilMeter{} + serveMeter = metrics.NewRegisteredMeter("p2p/serves", nil) + serveSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success", nil) + dialMeter = metrics.NewRegisteredMeter("p2p/dials", nil) + dialSuccessMeter = metrics.NewRegisteredMeter("p2p/dials/success", nil) + dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) // handshake error meters dialTooManyPeers = metrics.NewRegisteredMeter("p2p/dials/error/saturated", nil) @@ -61,25 +61,10 @@ var ( dialProtoHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/proto", nil) ) -func init() { - if !metrics.Enabled { - return - } - - activePeerGauge = metrics.NewRegisteredGauge("p2p/peers", nil) - activeInboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/inbound", nil) - activeOutboundPeerGauge = metrics.NewRegisteredGauge("p2p/peers/outbound", nil) - serveMeter = metrics.NewRegisteredMeter("p2p/serves", nil) - serveSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success", nil) - dialMeter = metrics.NewRegisteredMeter("p2p/dials", nil) - dialSuccessMeter = metrics.NewRegisteredMeter("p2p/dials/success", nil) - dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) -} - // markDialError matches errors that occur while setting up a dial connection // to the corresponding meter. func markDialError(err error) { - if !metrics.Enabled { + if !metrics.Enabled() { return } if err2 := errors.Unwrap(err); err2 != nil { @@ -113,7 +98,7 @@ type meteredConn struct { // connection meter and also increases the metered peer count. If the metrics // system is disabled, function returns the original connection. func newMeteredConn(conn net.Conn) net.Conn { - if !metrics.Enabled { + if !metrics.Enabled() { return conn } return &meteredConn{Conn: conn} diff --git a/p2p/peer.go b/p2p/peer.go index c3834965c..30be151a2 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -357,7 +357,7 @@ func (p *Peer) handle(msg Msg) error { if err != nil { return fmt.Errorf("msg code out of range: %v", msg.Code) } - if metrics.Enabled { + if metrics.Enabled() { m := fmt.Sprintf("%s/%s/%d/%#02x", ingressMeterName, proto.Name, proto.Version, msg.Code-proto.offset) metrics.GetOrRegisterMeter(m, nil).Mark(int64(msg.meterSize)) metrics.GetOrRegisterMeter(m+"/packets", nil).Mark(1) diff --git a/p2p/tracker/tracker.go b/p2p/tracker/tracker.go index 6a733b9ba..5b72eb2b8 100644 --- a/p2p/tracker/tracker.go +++ b/p2p/tracker/tracker.go @@ -84,7 +84,7 @@ func New(protocol string, timeout time.Duration) *Tracker { // Track adds a network request to the tracker to wait for a response to arrive // or until the request it cancelled or times out. func (t *Tracker) Track(peer string, version uint, reqCode uint64, resCode uint64, id uint64) { - if !metrics.Enabled { + if !metrics.Enabled() { return } t.lock.Lock() @@ -163,7 +163,7 @@ func (t *Tracker) schedule() { // Fulfil fills a pending request, if any is available, reporting on various metrics. func (t *Tracker) Fulfil(peer string, version uint, code uint64, id uint64) { - if !metrics.Enabled { + if !metrics.Enabled() { return } t.lock.Lock() diff --git a/p2p/transport.go b/p2p/transport.go index 5fc7686fe..360e73a0d 100644 --- a/p2p/transport.go +++ b/p2p/transport.go @@ -98,7 +98,7 @@ func (t *rlpxTransport) WriteMsg(msg Msg) error { // Set metrics. msg.meterSize = size - if metrics.Enabled && msg.meterCap.Name != "" { // don't meter non-subprotocol messages + if metrics.Enabled() && msg.meterCap.Name != "" { // don't meter non-subprotocol messages m := fmt.Sprintf("%s/%s/%d/%#02x", egressMeterName, msg.meterCap.Name, msg.meterCap.Version, msg.meterCode) metrics.GetOrRegisterMeter(m, nil).Mark(int64(msg.meterSize)) metrics.GetOrRegisterMeter(m+"/packets", nil).Mark(1) diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index e1611b3eb..6e633db27 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -43,7 +43,7 @@ func (c *counter) add(size int) { } // report uploads the cached statistics to meters. -func (c *counter) report(count metrics.Meter, size metrics.Meter) { +func (c *counter) report(count, size *metrics.Meter) { count.Mark(int64(c.n)) size.Mark(int64(c.size)) } From 1edd1df3eac2a4ee3563ba6d97b737c63febf389 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Tue, 10 Dec 2024 21:22:43 +0800 Subject: [PATCH 039/354] build: update to Go 1.23.4 (#30872) --- build/checksums.txt | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index b83521585..b8061c924 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,56 +5,56 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.23.3 +# version:golang 1.23.4 # https://go.dev/dl/ -8d6a77332487557c6afa2421131b50f83db4ae3c579c3bc72e670ee1f6968599 go1.23.3.src.tar.gz -bdbf2a243ed4a121c9988684e5b15989cb244c1ff9e41ca823d0187b5c859114 go1.23.3.aix-ppc64.tar.gz -b79c77bbdf61e6e486aa6bea9286f3f7969c28e2ff7686ce10c334f746bfb724 go1.23.3.darwin-amd64.pkg -c7e024d5c0bc81845070f23598caf02f05b8ae88fd4ad2cd3e236ddbea833ad2 go1.23.3.darwin-amd64.tar.gz -3e764df0db8f3c7470b9ff641954a380510a4822613c06bd5a195fd083f4731d go1.23.3.darwin-arm64.pkg -31e119fe9bde6e105407a32558d5b5fa6ca11e2bd17f8b7b2f8a06aba16a0632 go1.23.3.darwin-arm64.tar.gz -3872c9a98331050a242afe63fa6abc8fc313aca83dcaefda318e903309ac0c8d go1.23.3.dragonfly-amd64.tar.gz -69479fa016ec5b4605885643ce0c2dd5c583e02353978feb6de38c961863b9cc go1.23.3.freebsd-386.tar.gz -bf1de22a900646ef4f79480ed88337856d47089cc610f87e6fef46f6b8db0e1f go1.23.3.freebsd-amd64.tar.gz -e461f866479bc36bdd4cfec32bfecb1bb243152268a1b3223de109410dec3407 go1.23.3.freebsd-arm.tar.gz -24154b4018a45540aefeb6b5b9ffdcc8d9a8cdb78cd7fec262787b89fed19997 go1.23.3.freebsd-arm64.tar.gz -218f3f1532e61dd65c330c2a5fc85bec18cc3690489763e62ffa9bb9fc85a68e go1.23.3.freebsd-riscv64.tar.gz -24e3f34858b8687c31f5e5ab9e46d27fb613b0d50a94261c500cebb2d79c0672 go1.23.3.illumos-amd64.tar.gz -3d7b00191a43c50d28e0903a0c576104bc7e171a8670de419d41111c08dfa299 go1.23.3.linux-386.tar.gz -a0afb9744c00648bafb1b90b4aba5bdb86f424f02f9275399ce0c20b93a2c3a8 go1.23.3.linux-amd64.tar.gz -1f7cbd7f668ea32a107ecd41b6488aaee1f5d77a66efd885b175494439d4e1ce go1.23.3.linux-arm64.tar.gz -5f0332754beffc65af65a7b2da76e9dd997567d0d81b6f4f71d3588dc7b4cb00 go1.23.3.linux-armv6l.tar.gz -1d0161a8946c7d99f717bad23631738408511f9f87e78d852224a023d8882ad8 go1.23.3.linux-loong64.tar.gz -e924a7c9027f521f8a3563541ed0f89a4db3ef005b6b71263415b38e0b46e63a go1.23.3.linux-mips.tar.gz -4cdf8c38165627f032c2b17cdd95e4aafff40d75fc873824d4c94914284098ca go1.23.3.linux-mips64.tar.gz -5e49347e7325d2e268fb14040529b704e66eed77154cc73a919e9167d8527a2f go1.23.3.linux-mips64le.tar.gz -142eabc17cee99403e895383ed7a6b7b40e740e8c2f73b79352bb9d1242fbd98 go1.23.3.linux-mipsle.tar.gz -96ad61ba6b6cc0f5adfd75e65231c61e7db26d8236f01117023899528164d1b0 go1.23.3.linux-ppc64.tar.gz -e3b926c81e8099d3cee6e6e270b85b39c3bd44263f8d3df29aacb4d7e00507c8 go1.23.3.linux-ppc64le.tar.gz -324e03b6f59be841dfbaeabc466224b0f0905f5ad3a225b7c0703090e6c4b1a5 go1.23.3.linux-riscv64.tar.gz -6bd72fcef72b046b6282c2d1f2c38f31600e4fe9361fcd8341500c754fb09c38 go1.23.3.linux-s390x.tar.gz -5df382337fe2e4ea6adaafa823da5e083513a97534a38f89d691dd6f599084ca go1.23.3.netbsd-386.tar.gz -9ae7cb6095a3e91182ac03547167e230fddd4941ed02dbdb6af663b2a53d9db7 go1.23.3.netbsd-amd64.tar.gz -4a452c4134a9bea6213d8925d322f26b01c0eccda1330585bb2b241c76a0c3ea go1.23.3.netbsd-arm.tar.gz -8ff3b5184d840148dbca061c04dca35a7070dc894255d3b755066bd76a7094dc go1.23.3.netbsd-arm64.tar.gz -5b6940922e68ac1162a704a8b583fb4f039f955bfe97c35a56c40269cbcff9b1 go1.23.3.openbsd-386.tar.gz -6ae4aeb6a88f3754b10ecec90422a30fb8bf86c3187be2be9408d67a5a235ace go1.23.3.openbsd-amd64.tar.gz -e5eae226391b60c4d1ea1022663f55b225c6d7bab67f31fbafd5dd7a04684006 go1.23.3.openbsd-arm.tar.gz -e12b2c04535e0bf5561d54831122b410d708519c1ec2c56b0c2350b15243c331 go1.23.3.openbsd-arm64.tar.gz -599818e4062166d7a112f6f3fcca2dd4e2cdd3111fe48f9757bd8debf38c7f52 go1.23.3.openbsd-ppc64.tar.gz -9ca4db8cab2a07d561f5b2a9397793684ab3b22326add1fe8cda8a545a1693db go1.23.3.openbsd-riscv64.tar.gz -8fca1ec2aced936e0170605378ee7f0acb38f002490321f67fc83728ee281967 go1.23.3.plan9-386.tar.gz -22d663692224fc1933a97f61d9fe49815e3b9ef1c2be97046505683fdf2e23c7 go1.23.3.plan9-amd64.tar.gz -d0417a702d0e776d57e450fa2ce1ce7efa199a636644776862dbf946c409a462 go1.23.3.plan9-arm.tar.gz -b5d9db1c02e0ca266a142eb687bd7749890c30872b09a4a0ffcd491425039754 go1.23.3.solaris-amd64.tar.gz -14b7baf4af2046013b74dfac6e9a0a7403f15ee9940a16890bc028dfd32c49ac go1.23.3.windows-386.msi -23da9089ea6c5612d718f13c26e9bfc9aaaabe222838075346a8191d48f9dfe5 go1.23.3.windows-386.zip -614f0e3eed82245dfb4356d4e8d5b96abecca6a4c4f0168c0e389e4dd6284db8 go1.23.3.windows-amd64.msi -81968b563642096b8a7521171e2be6e77ff6f44032f7493b7bdec9d33f44f31d go1.23.3.windows-amd64.zip -c9951eecad732c59dfde6dc4803fa9253eb074663c61035c8d856f4d2eb146cb go1.23.3.windows-arm.msi -1a7db02be47deada42082d21d63eba0013f93375cfa0e7768962f1295a469022 go1.23.3.windows-arm.zip -a74e3e195219af4330b93c71cd4b736b709a5654a07cc37eebe181c4984afb82 go1.23.3.windows-arm64.msi -dbdfa868b1a3f8c62950373e4975d83f90dd8b869a3907319af8384919bcaffe go1.23.3.windows-arm64.zip +ad345ac421e90814293a9699cca19dd5238251c3f687980bbcae28495b263531 go1.23.4.src.tar.gz +459a09504f7ebf2cbcee6ac282c8f34f97651217b1feae64557dcdd392b9bb62 go1.23.4.aix-ppc64.tar.gz +0f4e569b2d38cb75cb2efcaf56beb42778ab5e46d89318fef39060fe36d7b9b7 go1.23.4.darwin-amd64.pkg +6700067389a53a1607d30aa8d6e01d198230397029faa0b109e89bc871ab5a0e go1.23.4.darwin-amd64.tar.gz +19c054eaf40c5fac65b027f7443c01382e493d3c8c42cf8b2504832ebddce037 go1.23.4.darwin-arm64.pkg +87d2bb0ad4fe24d2a0685a55df321e0efe4296419a9b3de03369dbe60b8acd3a go1.23.4.darwin-arm64.tar.gz +5e73dc89b44626677ec9d9aa4257d6d2ef1245502bc36a99385284910d0ade0a go1.23.4.dragonfly-amd64.tar.gz +8df26b1e71234756c1f0e82cfffba3f427c5a91a251844ada2c7694a6986c546 go1.23.4.freebsd-386.tar.gz +7de078d94d2af50ee9506ef7df85e4d12d4018b23e0b2cbcbc61d686f549b41a go1.23.4.freebsd-amd64.tar.gz +3f23e0a01cfe24e4160124cd7ab02bdd188264652074abdbce401c93f41e58a4 go1.23.4.freebsd-arm.tar.gz +986a20e7c94431f03b44b3c415abc698c7b4edc2ae8431f7ecae1c2429d4cfa2 go1.23.4.freebsd-arm64.tar.gz +25e39f005f977778ce963fc43089510fe7514f3cfc0358eab584de4ce9f181fb go1.23.4.freebsd-riscv64.tar.gz +7e1d52f93da68c3bab39e3d83f89944d7d151208e54fdc30b0eda2a3812661d7 go1.23.4.illumos-amd64.tar.gz +4a4a0e7587ef8c8a326439b957027f2791795e2d29d4ae3885b4091a48f843bc go1.23.4.linux-386.tar.gz +6924efde5de86fe277676e929dc9917d466efa02fb934197bc2eba35d5680971 go1.23.4.linux-amd64.tar.gz +16e5017863a7f6071363782b1b8042eb12c6ca4f4cd71528b2123f0a1275b13e go1.23.4.linux-arm64.tar.gz +1f1dda0dc7ce0b2295f57258ec5ef0803fd31b9ed0aa20e2e9222334e5755de1 go1.23.4.linux-armv6l.tar.gz +4f469179a335a1a7bb9f991ad0c567f3d3eeb9b412ecd192206ab5c3e1a52b5a go1.23.4.linux-loong64.tar.gz +86b68185bcc43ea07190e95137c3442f062acc7ae10c3f1cf900fbe23e07df24 go1.23.4.linux-mips.tar.gz +3a19245eec76533b3d01c90f3a40a38d63684028f0fd54d442dc9a9d03197891 go1.23.4.linux-mips64.tar.gz +b53a06fc8455f6a875329e8d2e24d39db298122c9cce6e948117022191f6c613 go1.23.4.linux-mips64le.tar.gz +66120a8105b8ba6559f4e6a13b1e39b433fb8032df9d1744e4486876fa1723ce go1.23.4.linux-mipsle.tar.gz +33be2bfb27f2821a65e9f6aba744c85ea7c5e233e16bac27bb3ec253bcd4e970 go1.23.4.linux-ppc64.tar.gz +65a303ef51e48ff77e004a6a5b4db6ce59495cd59c6af51b54bf4f786c01a1b9 go1.23.4.linux-ppc64le.tar.gz +7c40e9e0d722cef14ede765159ba297f4c6e3093bb106f10fbccf8564780049a go1.23.4.linux-riscv64.tar.gz +74aab82bf4eca7c26c830a5b0e2a31d193a4d5ba47045526b92473cc7188d7d7 go1.23.4.linux-s390x.tar.gz +dba009d8bf9928cb5a1e31fcbe0eb41335cce4fe63755d95cef6b5987df4ed5a go1.23.4.netbsd-386.tar.gz +54b081cc36355aa5ecb6db9544cf7e77366a7b08ce96cb98a45d043e393660c7 go1.23.4.netbsd-amd64.tar.gz +f05fec348c7c9f07e1ad4e436db4122e98de99ebcfbf6ac6176869785f334a02 go1.23.4.netbsd-arm.tar.gz +317878da2bface5a57a8eaf5c1fe2b40b1c82d8172a10453ad3eea36f6946bdb go1.23.4.netbsd-arm64.tar.gz +0d84350dfd72c505c6ad474e51676b04e95ffb748c614bd5bf8510026873059b go1.23.4.openbsd-386.tar.gz +cc62f5a14ea3d573d8edbce1833f70a8f99ca048a9db0fcc9e738fd48e950505 go1.23.4.openbsd-amd64.tar.gz +326aba6cf5bb9348fa3e41217abd2c84eac92608684e2fe8c5474fdab23a0db9 go1.23.4.openbsd-arm.tar.gz +51ea2a2588bf3da8e1476f3e2bd4d6724d74126e99f9c6ea9af4ebe389e64de6 go1.23.4.openbsd-arm64.tar.gz +44c5c82ab23e40225b2ba1e7d19150a5973ea58e93b4931e426e6e6f0d108872 go1.23.4.openbsd-ppc64.tar.gz +5fa31fc13d1e3c123a5e96ba38683fa2c947baed23ac9c7c341afcfe007c8993 go1.23.4.openbsd-riscv64.tar.gz +e5952fc93eeaa0094ef09a0e72a9f06f0621ce841a39f9637fb5b9062e77d67a go1.23.4.plan9-386.tar.gz +fb2a9ee3ae5a77e734862e257a9395b43e707ac45e060dfa84c5a40688e73170 go1.23.4.plan9-amd64.tar.gz +e1b95563b19fdebd6ea0d20c07641e69580976fa754e586c831ad7a3ae987140 go1.23.4.plan9-arm.tar.gz +088c282509fc9e1a8f29fc0dd16fe486854d05b8ceba08d077d17d11d6979a41 go1.23.4.solaris-amd64.tar.gz +e5865c1bfc3fee5d003819b2e2c800f598fe9994931bac63f573e8d05a10d91f go1.23.4.windows-386.msi +e544e0e356147ba998e267002bd0f2c4bf3370d495467a55baf2c63595a2026d go1.23.4.windows-386.zip +5f8cc5991eb8f4f96b6c611d839453cd11c9a2c3f23672a4188342c97ee159fa go1.23.4.windows-amd64.msi +16c59ac9196b63afb872ce9b47f945b9821a3e1542ec125f16f6085a1c0f3c39 go1.23.4.windows-amd64.zip +fc77c0531406d092c5356167e45c05a22d16bea84e3fa555e0f03af085c11763 go1.23.4.windows-arm.msi +1012cfd8ca7241c2beecb5c345dd61f01897c6f6baca80ea1bfed357035c868a go1.23.4.windows-arm.zip +8347c1aa4e1e67954d12830f88dbe44bd7ac0ec134bb472783dbfb5a3a8865d0 go1.23.4.windows-arm64.msi +db69cae5006753c785345c3215ad941f8b6224e2f81fec471c42d6857bee0e6f go1.23.4.windows-arm64.zip # version:golangci 1.61.0 # https://github.com/golangci/golangci-lint/releases/ From c2d4647c781b45e1020bd075d1ec1b0ac5119e8d Mon Sep 17 00:00:00 2001 From: Darren Kelly <107671032+darrenvechain@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:30:24 +0000 Subject: [PATCH 040/354] accounts/abi: support unpacking solidity errors (#30738) This PR adds the error fragments to `func (abi ABI) getArguments` which allows typed decoding of errors. --- accounts/abi/abi.go | 7 +++++-- accounts/abi/abi_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index c7bc2b454..f75278c8b 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -84,7 +84,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { func (abi ABI) getArguments(name string, data []byte) (Arguments, 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 + // we need to decide whether we're calling a method, event or an error var args Arguments if method, ok := abi.Methods[name]; ok { if len(data)%32 != 0 { @@ -95,8 +95,11 @@ func (abi ABI) getArguments(name string, data []byte) (Arguments, error) { if event, ok := abi.Events[name]; ok { args = event.Inputs } + if err, ok := abi.Errors[name]; ok { + args = err.Inputs + } if args == nil { - return nil, fmt.Errorf("abi: could not locate named method or event: %s", name) + return nil, fmt.Errorf("abi: could not locate named method, event or error: %s", name) } return args, nil } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index fc290cfe8..db9a4c55a 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testrand" ) const jsondata = ` @@ -317,6 +318,38 @@ func TestCustomErrors(t *testing.T) { check("MyError", "MyError(uint256)") } +func TestCustomErrorUnpackIntoInterface(t *testing.T) { + t.Parallel() + errorName := "MyError" + json := fmt.Sprintf(`[{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"%s","type":"error"}]`, errorName) + abi, err := JSON(strings.NewReader(json)) + if err != nil { + t.Fatal(err) + } + type MyError struct { + Sender common.Address + Balance *big.Int + } + + sender := testrand.Address() + balance := new(big.Int).SetBytes(testrand.Bytes(8)) + encoded, err := abi.Errors[errorName].Inputs.Pack(sender, balance) + if err != nil { + t.Fatal(err) + } + result := MyError{} + err = abi.UnpackIntoInterface(&result, errorName, encoded) + if err != nil { + t.Fatal(err) + } + if result.Sender != sender { + t.Errorf("expected %x got %x", sender, result.Sender) + } + if result.Balance.Cmp(balance) != 0 { + t.Errorf("expected %v got %v", balance, result.Balance) + } +} + func TestMultiPack(t *testing.T) { t.Parallel() abi, err := JSON(strings.NewReader(jsondata)) From 6ce87dcf5b3351aaf6247c375a256e76221cfc5b Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Wed, 11 Dec 2024 18:05:59 +0800 Subject: [PATCH 041/354] core/state: remove pointless wrapper functions (#30891) --- core/state/access_list.go | 5 +---- core/state/statedb_test.go | 14 +++----------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index 90e559074..a58c2b20e 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -139,10 +139,7 @@ func (al *accessList) Equal(other *accessList) bool { if !maps.Equal(al.addresses, other.addresses) { return false } - return slices.EqualFunc(al.slots, other.slots, - func(m map[common.Hash]struct{}, m2 map[common.Hash]struct{}) bool { - return maps.Equal(m, m2) - }) + return slices.EqualFunc(al.slots, other.slots, maps.Equal) } // PrettyPrint prints the contents of the access list in a human-readable form diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 57886e6e0..37141e90b 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -650,11 +650,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { { have := state.transientStorage want := checkstate.transientStorage - eq := maps.EqualFunc(have, want, - func(a Storage, b Storage) bool { - return maps.Equal(a, b) - }) - if !eq { + if !maps.EqualFunc(have, want, maps.Equal) { return fmt.Errorf("transient storage differs ,have\n%v\nwant\n%v", have.PrettyPrint(), want.PrettyPrint()) @@ -1034,12 +1030,8 @@ func testMissingTrieNodes(t *testing.T, scheme string) { func TestStateDBAccessList(t *testing.T) { // Some helpers - addr := func(a string) common.Address { - return common.HexToAddress(a) - } - slot := func(a string) common.Hash { - return common.HexToHash(a) - } + addr := common.HexToAddress + slot := common.HexToHash db := NewDatabaseForTesting() state, _ := New(types.EmptyRootHash, db) From 3a647e07700563b19ef93f159c78f2ff9d749c7f Mon Sep 17 00:00:00 2001 From: lorenzo <31852651+lorenzo-dev1@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:33:42 +0100 Subject: [PATCH 042/354] p2p: fix DiscReason encoding/decoding (#30855) This fixes an issue where the disconnect message was not wrapped in a list. The specification requires it to be a list like any other message. In order to remain compatible with legacy geth versions, we now accept both encodings when parsing a disconnect message. --------- Co-authored-by: Felix Lange --- p2p/peer.go | 25 ++++++++++++++++++++++--- p2p/peer_error.go | 5 ++++- p2p/transport.go | 24 ++++++++++-------------- p2p/transport_test.go | 10 ++++++++-- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/p2p/peer.go b/p2p/peer.go index 30be151a2..a01df63d0 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -345,9 +345,7 @@ func (p *Peer) handle(msg Msg) error { case msg.Code == discMsg: // This is the last message. We don't need to discard or // check errors because, the connection will be closed after it. - var m struct{ R DiscReason } - rlp.Decode(msg.Payload, &m) - return m.R + return decodeDisconnectMessage(msg.Payload) case msg.Code < baseProtocolLength: // ignore other base protocol messages return msg.Discard() @@ -372,6 +370,27 @@ func (p *Peer) handle(msg Msg) error { return nil } +// decodeDisconnectMessage decodes the payload of discMsg. +func decodeDisconnectMessage(r io.Reader) (reason DiscReason) { + s := rlp.NewStream(r, 100) + k, _, err := s.Kind() + if err != nil { + return DiscInvalid + } + if k == rlp.List { + s.List() + err = s.Decode(&reason) + } else { + // Legacy path: some implementations, including geth, used to send the disconnect + // reason as a byte array by accident. + err = s.Decode(&reason) + } + if err != nil { + reason = DiscInvalid + } + return reason +} + func countMatchingProtocols(protocols []Protocol, caps []Cap) int { n := 0 for _, cap := range caps { diff --git a/p2p/peer_error.go b/p2p/peer_error.go index ebc59de25..dcdadf7fe 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -70,6 +70,8 @@ const ( DiscSelf DiscReadTimeout DiscSubprotocolError = DiscReason(0x10) + + DiscInvalid = 0xff ) var discReasonToString = [...]string{ @@ -86,10 +88,11 @@ var discReasonToString = [...]string{ DiscSelf: "connected to self", DiscReadTimeout: "read timeout", DiscSubprotocolError: "subprotocol error", + DiscInvalid: "invalid disconnect reason", } func (d DiscReason) String() string { - if len(discReasonToString) <= int(d) { + if len(discReasonToString) <= int(d) || discReasonToString[d] == "" { return fmt.Sprintf("unknown disconnect reason %d", d) } return discReasonToString[d] diff --git a/p2p/transport.go b/p2p/transport.go index 360e73a0d..87d3013f1 100644 --- a/p2p/transport.go +++ b/p2p/transport.go @@ -113,15 +113,14 @@ func (t *rlpxTransport) close(err error) { // Tell the remote end why we're disconnecting if possible. // We only bother doing this if the underlying connection supports // setting a timeout tough. - if t.conn != nil { - if r, ok := err.(DiscReason); ok && r != DiscNetworkError { - deadline := time.Now().Add(discWriteTimeout) - if err := t.conn.SetWriteDeadline(deadline); err == nil { - // Connection supports write deadline. - t.wbuf.Reset() - rlp.Encode(&t.wbuf, []DiscReason{r}) - t.conn.Write(discMsg, t.wbuf.Bytes()) - } + if reason, ok := err.(DiscReason); ok && reason != DiscNetworkError { + // We do not use the WriteMsg func since we want a custom deadline + deadline := time.Now().Add(discWriteTimeout) + if err := t.conn.SetWriteDeadline(deadline); err == nil { + // Connection supports write deadline. + t.wbuf.Reset() + rlp.Encode(&t.wbuf, []any{reason}) + t.conn.Write(discMsg, t.wbuf.Bytes()) } } t.conn.Close() @@ -163,11 +162,8 @@ func readProtocolHandshake(rw MsgReader) (*protoHandshake, error) { if msg.Code == discMsg { // Disconnect before protocol handshake is valid according to the // spec and we send it ourself if the post-handshake checks fail. - // We can't return the reason directly, though, because it is echoed - // back otherwise. Wrap it in a string instead. - var reason [1]DiscReason - rlp.Decode(msg.Payload, &reason) - return nil, reason[0] + r := decodeDisconnectMessage(msg.Payload) + return nil, r } if msg.Code != handshakeMsg { return nil, fmt.Errorf("expected handshake, got %x", msg.Code) diff --git a/p2p/transport_test.go b/p2p/transport_test.go index 01695cd3a..777be1bd0 100644 --- a/p2p/transport_test.go +++ b/p2p/transport_test.go @@ -97,7 +97,7 @@ func TestProtocolHandshake(t *testing.T) { return } - if err := ExpectMsg(rlpx, discMsg, []DiscReason{DiscQuitting}); err != nil { + if err := ExpectMsg(rlpx, discMsg, []any{DiscQuitting}); err != nil { t.Errorf("error receiving disconnect: %v", err) } }() @@ -112,7 +112,13 @@ func TestProtocolHandshakeErrors(t *testing.T) { }{ { code: discMsg, - msg: []DiscReason{DiscQuitting}, + msg: []any{DiscQuitting}, + err: DiscQuitting, + }, + { + // legacy disconnect encoding as byte array + code: discMsg, + msg: []byte{byte(DiscQuitting)}, err: DiscQuitting, }, { From b9a3e87ef5ee31e5f2789cba0b7e02dbd7f1dcff Mon Sep 17 00:00:00 2001 From: Antony Denyer Date: Thu, 12 Dec 2024 11:39:03 +0000 Subject: [PATCH 043/354] internal/ethapi: add block override to estimateGas (#30695) Add block overrides to `eth_estimateGas` to align consistency with `eth_call`. https://github.com/ethereum/go-ethereum/issues/27800#issuecomment-1658186166 Fixes https://github.com/ethereum/go-ethereum/issues/28175 --------- Co-authored-by: Sina Mahmoodi --- .gitignore | 1 + eth/gasestimator/gasestimator.go | 13 +- eth/protocols/dbft/handler.go | 2 +- eth/tracers/api.go | 5 +- eth/tracers/api_test.go | 35 +-- graphql/graphql.go | 4 +- internal/ethapi/api.go | 193 +------------ internal/ethapi/api_test.go | 323 +++++++++++----------- internal/ethapi/override/override.go | 195 +++++++++++++ internal/ethapi/override/override_test.go | 125 +++++++++ internal/ethapi/simulate.go | 9 +- internal/ethapi/simulate_test.go | 13 +- internal/ethapi/transaction_args.go | 2 +- internal/web3ext/web3ext.go | 4 +- 14 files changed, 547 insertions(+), 377 deletions(-) create mode 100644 internal/ethapi/override/override.go create mode 100644 internal/ethapi/override/override_test.go diff --git a/.gitignore b/.gitignore index 80211b975..0f24cc3d7 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ profile.cov # IdeaIDE .idea +*.iml # VS Code .vscode diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 9b24bfbf9..a6c4718cf 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -38,10 +39,11 @@ import ( // these together, it would be excessively hard to test. Splitting the parts out // allows testing without needing a proper live chain. type Options struct { - Config *params.ChainConfig // Chain configuration for hard fork selection - Chain core.ChainContext // Chain context to access past block hashes - Header *types.Header // Header defining the block context to execute in - State *state.StateDB // Pre-state on top of which to estimate the gas + Config *params.ChainConfig // Chain configuration for hard fork selection + Chain core.ChainContext // Chain context to access past block hashes + Header *types.Header // Header defining the block context to execute in + State *state.StateDB // Pre-state on top of which to estimate the gas + BlockOverrides *override.BlockOverrides // Block overrides to apply during the estimation ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination } @@ -220,6 +222,9 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil) dirtyState = opts.State.Copy() ) + if opts.BlockOverrides != nil { + opts.BlockOverrides.Apply(&evmContext) + } // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). if call.GasPrice.Sign() == 0 { diff --git a/eth/protocols/dbft/handler.go b/eth/protocols/dbft/handler.go index ffb0ed256..70f54f944 100644 --- a/eth/protocols/dbft/handler.go +++ b/eth/protocols/dbft/handler.go @@ -70,7 +70,7 @@ func (s *Service) HandleMessage(peer *Peer) error { defer msg.Discard() start := time.Now() // Track the amount of time it takes to serve the request and run the handler - if metrics.Enabled { + if metrics.Enabled() { h := fmt.Sprintf("%s/%s/%#02x", p2p.HandleHistName, ProtocolName, msg.Code) defer func(start time.Time) { sampler := func() metrics.Sample { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index aaad261a1..45e02ffba 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -163,8 +164,8 @@ type TraceConfig struct { // field to override the state for tracing. type TraceCallConfig struct { TraceConfig - StateOverrides *ethapi.StateOverride - BlockOverrides *ethapi.BlockOverrides + StateOverrides *override.StateOverride + BlockOverrides *override.BlockOverrides TxIndex *hexutil.Uint } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 97c86a40e..1b068954b 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -44,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -454,7 +455,7 @@ func TestTraceCall(t *testing.T) { Input: &hexutil.Bytes{0x43}, // blocknumber }, config: &TraceCallConfig{ - BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, + BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, expectErr: nil, expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[ @@ -698,8 +699,8 @@ func TestTracingWithOverrides(t *testing.T) { Value: (*hexutil.Big)(big.NewInt(1000)), }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, }, }, want: `{"gas":21000,"failed":false,"returnValue":""}`, @@ -740,8 +741,8 @@ func TestTracingWithOverrides(t *testing.T) { }, config: &TraceCallConfig{ //Tracer: &tracer, - StateOverrides: ðapi.StateOverride{ - randomAccounts[2].addr: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), }, @@ -757,7 +758,7 @@ func TestTracingWithOverrides(t *testing.T) { Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")), }, config: &TraceCallConfig{ - BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, + BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`, }, @@ -777,7 +778,7 @@ func TestTracingWithOverrides(t *testing.T) { }, // blocknumber }, config: &TraceCallConfig{ - BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, + BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, }, @@ -807,8 +808,8 @@ func TestTracingWithOverrides(t *testing.T) { Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - randomAccounts[2].addr: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")), }, }, @@ -823,8 +824,8 @@ func TestTracingWithOverrides(t *testing.T) { Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - randomAccounts[2].addr: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")), State: newStates([]common.Hash{{}}, []common.Hash{{}}), }, @@ -841,8 +842,8 @@ func TestTracingWithOverrides(t *testing.T) { Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - storageAccount: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + storageAccount: override.OverrideAccount{ Code: newRPCBytes([]byte{ // SLOAD(3) + SLOAD(4) (which is 0x77) byte(vm.PUSH1), 0x04, @@ -876,8 +877,8 @@ func TestTracingWithOverrides(t *testing.T) { Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - storageAccount: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + storageAccount: override.OverrideAccount{ Code: newRPCBytes([]byte{ // SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00) byte(vm.PUSH1), 0x04, @@ -914,8 +915,8 @@ func TestTracingWithOverrides(t *testing.T) { Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // }, config: &TraceCallConfig{ - StateOverrides: ðapi.StateOverride{ - storageAccount: ethapi.OverrideAccount{ + StateOverrides: &override.StateOverride{ + storageAccount: override.OverrideAccount{ Code: newRPCBytes([]byte{ // SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44) byte(vm.PUSH1), 0x04, diff --git a/graphql/graphql.go b/graphql/graphql.go index 479b79de6..2de9efbe0 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1214,7 +1214,7 @@ func (b *Block) Call(ctx context.Context, args struct { func (b *Block) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { - return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCGasCap()) } type Pending struct { @@ -1278,7 +1278,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, p.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, nil, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7f136c5da..0e18e1996 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -38,19 +38,18 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/gasestimator" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" - "github.com/holiman/uint256" ) // estimateGasErrorRatio is the amount of overestimation eth_estimateGas is @@ -697,171 +696,6 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp return result, nil } -// OverrideAccount indicates the overriding fields of account during the execution -// of a message call. -// Note, state and stateDiff can't be specified at the same time. If state is -// set, message execution will only use the data in the given state. Otherwise -// if stateDiff is set, all diff will be applied first and then execute the call -// message. -type OverrideAccount struct { - Nonce *hexutil.Uint64 `json:"nonce"` - Code *hexutil.Bytes `json:"code"` - Balance *hexutil.Big `json:"balance"` - State map[common.Hash]common.Hash `json:"state"` - StateDiff map[common.Hash]common.Hash `json:"stateDiff"` - MovePrecompileTo *common.Address `json:"movePrecompileToAddress"` -} - -// StateOverride is the collection of overridden accounts. -type StateOverride map[common.Address]OverrideAccount - -func (diff *StateOverride) has(address common.Address) bool { - _, ok := (*diff)[address] - return ok -} - -// Apply overrides the fields of specified accounts into the given state. -func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.PrecompiledContracts) error { - if diff == nil { - return nil - } - // Tracks destinations of precompiles that were moved. - dirtyAddrs := make(map[common.Address]struct{}) - for addr, account := range *diff { - // If a precompile was moved to this address already, it can't be overridden. - if _, ok := dirtyAddrs[addr]; ok { - return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex()) - } - p, isPrecompile := precompiles[addr] - // The MoveTo feature makes it possible to move a precompile - // code to another address. If the target address is another precompile - // the code for the latter is lost for this session. - // Note the destination account is not cleared upon move. - if account.MovePrecompileTo != nil { - if !isPrecompile { - return fmt.Errorf("account %s is not a precompile", addr.Hex()) - } - // Refuse to move a precompile to an address that has been - // or will be overridden. - if diff.has(*account.MovePrecompileTo) { - return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex()) - } - precompiles[*account.MovePrecompileTo] = p - dirtyAddrs[*account.MovePrecompileTo] = struct{}{} - } - if isPrecompile { - delete(precompiles, addr) - } - // Override account nonce. - if account.Nonce != nil { - statedb.SetNonce(addr, uint64(*account.Nonce)) - } - // Override account(contract) code. - if account.Code != nil { - statedb.SetCode(addr, *account.Code) - } - // Override account balance. - if account.Balance != nil { - u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance)) - statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) - } - if account.State != nil && account.StateDiff != nil { - return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) - } - // Replace entire state if caller requires. - if account.State != nil { - statedb.SetStorage(addr, account.State) - } - // Apply state diff into specified accounts. - if account.StateDiff != nil { - for key, value := range account.StateDiff { - statedb.SetState(addr, key, value) - } - } - } - // Now finalize the changes. Finalize is normally performed between transactions. - // By using finalize, the overrides are semantically behaving as - // if they were created in a transaction just before the tracing occur. - statedb.Finalise(false) - return nil -} - -// BlockOverrides is a set of header fields to override. -type BlockOverrides struct { - Number *hexutil.Big - Difficulty *hexutil.Big // No-op if we're simulating post-merge calls. - Time *hexutil.Uint64 - GasLimit *hexutil.Uint64 - FeeRecipient *common.Address - PrevRandao *common.Hash - BaseFeePerGas *hexutil.Big - BlobBaseFee *hexutil.Big -} - -// Apply overrides the given header fields into the given block context. -func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) { - if o == nil { - return - } - if o.Number != nil { - blockCtx.BlockNumber = o.Number.ToInt() - } - if o.Difficulty != nil { - blockCtx.Difficulty = o.Difficulty.ToInt() - } - if o.Time != nil { - blockCtx.Time = uint64(*o.Time) - } - if o.GasLimit != nil { - blockCtx.GasLimit = uint64(*o.GasLimit) - } - if o.FeeRecipient != nil { - blockCtx.Coinbase = *o.FeeRecipient - } - if o.PrevRandao != nil { - blockCtx.Random = o.PrevRandao - } - if o.BaseFeePerGas != nil { - blockCtx.BaseFee = o.BaseFeePerGas.ToInt() - } - if o.BlobBaseFee != nil { - blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt() - } -} - -// MakeHeader returns a new header object with the overridden -// fields. -// Note: MakeHeader ignores BlobBaseFee if set. That's because -// header has no such field. -func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header { - if o == nil { - return header - } - h := types.CopyHeader(header) - if o.Number != nil { - h.Number = o.Number.ToInt() - } - if o.Difficulty != nil { - h.Difficulty = o.Difficulty.ToInt() - } - if o.Time != nil { - h.Time = uint64(*o.Time) - } - if o.GasLimit != nil { - h.GasLimit = uint64(*o.GasLimit) - } - if o.FeeRecipient != nil { - h.Coinbase = *o.FeeRecipient - } - if o.PrevRandao != nil { - h.MixDigest = *o.PrevRandao - } - if o.BaseFeePerGas != nil { - h.BaseFee = o.BaseFeePerGas.ToInt() - } - return h -} - // ChainContextBackend provides methods required to implement ChainContext. type ChainContextBackend interface { Engine() consensus.Engine @@ -894,7 +728,7 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H return header } -func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { blockOverrides.Apply(&blockCtx) @@ -973,7 +807,7 @@ func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, ti return result, nil } -func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) @@ -986,7 +820,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash // DoCallAtState executes the given transaction on the specified state with the given header. It's a // handler for CallAtState and differs from the latter in that it returns the call result as is. -func DoCallAtState(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +func DoCallAtState(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap) @@ -998,7 +832,7 @@ func DoCallAtState(ctx context.Context, b Backend, args TransactionArgs, state * // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { +func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides) (hexutil.Bytes, error) { if blockNrOrHash == nil { latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &latest @@ -1073,7 +907,7 @@ func (api *BlockChainAPI) CallAtState(ctx context.Context, args TransactionArgs, // successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if // there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil & // non-zero) and `gasCap` (if non-zero). -func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) { +func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, gasCap uint64) (hexutil.Uint64, error) { // Retrieve the base state and mutate it with any overrides state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { @@ -1084,11 +918,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr } // Construct the gas estimator option from the user input opts := &gasestimator.Options{ - Config: b.ChainConfig(), - Chain: NewChainContext(ctx, b), - Header: header, - State: state, - ErrorRatio: estimateGasErrorRatio, + Config: b.ChainConfig(), + Chain: NewChainContext(ctx, b), + Header: header, + BlockOverrides: blockOverrides, + State: state, + ErrorRatio: estimateGasErrorRatio, } // Set any required transaction default, but make sure the gas cap itself is not messed with // if it was not specified in the original argument list. @@ -1117,7 +952,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap // configuration (if non-zero). // Note: Required blob gas is not computed in this method. -func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { +func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides) (hexutil.Uint64, error) { if err := args.setFeeMinAllowed(ctx, api.b); err != nil { return 0, err } @@ -1125,7 +960,7 @@ func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap()) + return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, blockOverrides, api.b.RPCGasCap()) } // RPCMarshalHeader converts the given header to the RPC output . diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 439468fad..4b527f16f 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -24,7 +24,6 @@ import ( "encoding/json" "errors" "fmt" - "maps" "math/big" "os" "path/filepath" @@ -34,6 +33,9 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/internal/ethapi/override" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -55,7 +57,6 @@ import ( "github.com/ethereum/go-ethereum/internal/blocktest" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" "github.com/stretchr/testify/require" ) @@ -652,6 +653,17 @@ func TestEstimateGas(t *testing.T) { signer = types.HomesteadSigner{} randomAccounts = newAccounts(2) ) + packRevert := func(revertMessage string) []byte { + var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] + stringType, _ := abi.NewType("string", "", nil) + args := abi.Arguments{ + {Type: stringType}, + } + encodedMessage, _ := args.Pack(revertMessage) + + return append(revertSelector, encodedMessage...) + } + api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei @@ -660,14 +672,16 @@ func TestEstimateGas(t *testing.T) { b.AddTx(tx) b.SetPoS() })) + var testSuite = []struct { - blockNumber rpc.BlockNumber - call TransactionArgs - overrides StateOverride - expectErr error - want uint64 + blockNumber rpc.BlockNumber + call TransactionArgs + overrides override.StateOverride + blockOverrides override.BlockOverrides + expectErr error + want uint64 }{ - // simple transfer on latest block + //simple transfer on latest block { blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ @@ -699,8 +713,8 @@ func TestEstimateGas(t *testing.T) { { blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{}, - overrides: StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, + overrides: override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, }, expectErr: nil, want: 53000, @@ -712,8 +726,8 @@ func TestEstimateGas(t *testing.T) { To: &randomAccounts[1].addr, Value: (*hexutil.Big)(big.NewInt(1000)), }, - overrides: StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, + overrides: override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, }, expectErr: core.ErrInsufficientFunds, }, @@ -770,16 +784,65 @@ func TestEstimateGas(t *testing.T) { }, want: 21000, }, + // // SPDX-License-Identifier: GPL-3.0 + //pragma solidity >=0.8.2 <0.9.0; + // + //contract BlockOverridesTest { + // function call() public view returns (uint256) { + // return block.number; + // } + // + // function estimate() public view { + // revert(string.concat("block ", uint2str(block.number))); + // } + // + // function uint2str(uint256 _i) internal pure returns (string memory str) { + // if (_i == 0) { + // return "0"; + // } + // uint256 j = _i; + // uint256 length; + // while (j != 0) { + // length++; + // j /= 10; + // } + // bytes memory bstr = new bytes(length); + // uint256 k = length; + // j = _i; + // while (j != 0) { + // bstr[--k] = bytes1(uint8(48 + (j % 10))); + // j /= 10; + // } + // str = string(bstr); + // } + //} + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Data: hex2Bytes("0x3592d016"), //estimate + }, + overrides: override.StateOverride{ + accounts[1].addr: override.OverrideAccount{ + Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"), + }, + }, + blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, + expectErr: newRevertError(packRevert("block 11")), + }, } for i, tc := range testSuite { - result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides) + result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) if tc.expectErr != nil { if err == nil { t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) continue } if !errors.Is(err, tc.expectErr) { - t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) + if !reflect.DeepEqual(err, tc.expectErr) { + t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) + } } continue } @@ -830,9 +893,9 @@ func TestCall(t *testing.T) { var testSuite = []struct { name string blockNumber rpc.BlockNumber - overrides StateOverride + overrides override.StateOverride call TransactionArgs - blockOverrides BlockOverrides + blockOverrides override.BlockOverrides expectErr error want string }{ @@ -892,8 +955,8 @@ func TestCall(t *testing.T) { To: &randomAccounts[1].addr, Value: (*hexutil.Big)(big.NewInt(1000)), }, - overrides: StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, + overrides: override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, }, want: "0x", }, @@ -932,27 +995,60 @@ func TestCall(t *testing.T) { To: &randomAccounts[2].addr, Data: hex2Bytes("8381f58a"), // call number() }, - overrides: StateOverride{ - randomAccounts[2].addr: OverrideAccount{ + overrides: override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, }, }, want: "0x000000000000000000000000000000000000000000000000000000000000007b", }, - // Block overrides should work + // // SPDX-License-Identifier: GPL-3.0 + //pragma solidity >=0.8.2 <0.9.0; + // + //contract BlockOverridesTest { + // function call() public view returns (uint256) { + // return block.number; + // } + // + // function estimate() public view { + // revert(string.concat("block ", uint2str(block.number))); + // } + // + // function uint2str(uint256 _i) internal pure returns (string memory str) { + // if (_i == 0) { + // return "0"; + // } + // uint256 j = _i; + // uint256 length; + // while (j != 0) { + // length++; + // j /= 10; + // } + // bytes memory bstr = new bytes(length); + // uint256 k = length; + // j = _i; + // while (j != 0) { + // bstr[--k] = bytes1(uint8(48 + (j % 10))); + // j /= 10; + // } + // str = string(bstr); + // } + //} { - name: "block-override", + name: "block-override-with-state-override", blockNumber: rpc.LatestBlockNumber, call: TransactionArgs{ From: &accounts[1].addr, - Input: &hexutil.Bytes{ - 0x43, // NUMBER - 0x60, 0x00, 0x52, // MSTORE offset 0 - 0x60, 0x20, 0x60, 0x00, 0xf3, + To: &accounts[2].addr, + Data: hex2Bytes("0x28b5e32b"), //call + }, + overrides: override.StateOverride{ + accounts[2].addr: override.OverrideAccount{ + Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"), }, }, - blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, + blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, want: "0x000000000000000000000000000000000000000000000000000000000000000b", }, // Clear storage trie @@ -975,8 +1071,8 @@ func TestCall(t *testing.T) { // } Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), }, - overrides: StateOverride{ - dad: OverrideAccount{ + overrides: override.StateOverride{ + dad: override.OverrideAccount{ State: map[common.Hash]common.Hash{}, }, }, @@ -1003,7 +1099,7 @@ func TestCall(t *testing.T) { BlobHashes: []common.Hash{{0x01, 0x22}}, BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), }, - overrides: StateOverride{ + overrides: override.StateOverride{ randomAccounts[2].addr: { Code: hex2Bytes("60004960005260206000f3"), }, @@ -1029,8 +1125,8 @@ func TestCall(t *testing.T) { // } Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"), }, - overrides: StateOverride{ - dad: OverrideAccount{ + overrides: override.StateOverride{ + dad: override.OverrideAccount{ State: map[common.Hash]common.Hash{}, }, }, @@ -1184,8 +1280,8 @@ func TestSimulateV1(t *testing.T) { name: "simple", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))}, + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))}, }, Calls: []TransactionArgs{{ From: &randomAccounts[0].addr, @@ -1227,8 +1323,8 @@ func TestSimulateV1(t *testing.T) { name: "simple-multi-block", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))}, + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))}, }, Calls: []TransactionArgs{ { @@ -1242,8 +1338,8 @@ func TestSimulateV1(t *testing.T) { }, }, }, { - StateOverrides: &StateOverride{ - randomAccounts[3].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, + StateOverrides: &override.StateOverride{ + randomAccounts[3].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, }, Calls: []TransactionArgs{ { @@ -1301,8 +1397,8 @@ func TestSimulateV1(t *testing.T) { name: "evm-error", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[2].addr: OverrideAccount{Code: hex2Bytes("f3")}, + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{Code: hex2Bytes("f3")}, }, Calls: []TransactionArgs{{ From: &randomAccounts[0].addr, @@ -1328,7 +1424,7 @@ func TestSimulateV1(t *testing.T) { name: "block-overrides", tag: latest, blocks: []simBlock{{ - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(11)), FeeRecipient: &cac, }, @@ -1343,7 +1439,7 @@ func TestSimulateV1(t *testing.T) { }, }, }, { - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(12)), }, Calls: []TransactionArgs{{ @@ -1386,7 +1482,7 @@ func TestSimulateV1(t *testing.T) { name: "block-number-order", tag: latest, blocks: []simBlock{{ - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(12)), }, Calls: []TransactionArgs{{ @@ -1398,7 +1494,7 @@ func TestSimulateV1(t *testing.T) { }, }}, }, { - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(11)), }, Calls: []TransactionArgs{{ @@ -1418,8 +1514,8 @@ func TestSimulateV1(t *testing.T) { name: "storage-contract", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[2].addr: OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Code: hex2Bytes("608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033"), }, }, @@ -1460,8 +1556,8 @@ func TestSimulateV1(t *testing.T) { name: "logs", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[2].addr: OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ // Yul code: // object "Test" { // code { @@ -1502,8 +1598,8 @@ func TestSimulateV1(t *testing.T) { name: "ecrecover-override", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[2].addr: OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ // Yul code that returns ecrecover(0, 0, 0, 0). // object "Test" { // code { @@ -1530,7 +1626,7 @@ func TestSimulateV1(t *testing.T) { // } Code: hex2Bytes("6040516000815260006020820152600060408201526000606082015260208160808360015afa60008103603157600080fd5b601482f3"), }, - common.BytesToAddress([]byte{0x01}): OverrideAccount{ + common.BytesToAddress([]byte{0x01}): override.OverrideAccount{ // Yul code that returns the address of the caller. // object "Test" { // code { @@ -1567,8 +1663,8 @@ func TestSimulateV1(t *testing.T) { name: "precompile-move", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - sha256Address: OverrideAccount{ + StateOverrides: &override.StateOverride{ + sha256Address: override.OverrideAccount{ // Yul code that returns the calldata. // object "Test" { // code { @@ -1622,8 +1718,8 @@ func TestSimulateV1(t *testing.T) { name: "transfer-logs", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[0].addr: OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{ Balance: newRPCBalance(big.NewInt(100)), // Yul code that transfers 100 wei to address passed in calldata: // object "Test" { @@ -1765,8 +1861,8 @@ func TestSimulateV1(t *testing.T) { name: "validation-checks-from-contract", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ - randomAccounts[2].addr: OverrideAccount{ + StateOverrides: &override.StateOverride{ + randomAccounts[2].addr: override.OverrideAccount{ Balance: newRPCBalance(big.NewInt(2098640803896784)), Code: hex2Bytes("00"), Nonce: newUint64(1), @@ -1800,11 +1896,11 @@ func TestSimulateV1(t *testing.T) { name: "validation-checks-success", tag: latest, blocks: []simBlock{{ - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), }, - StateOverrides: &StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))}, + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))}, }, Calls: []TransactionArgs{{ From: &randomAccounts[0].addr, @@ -1833,7 +1929,7 @@ func TestSimulateV1(t *testing.T) { name: "clear-storage", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ + StateOverrides: &override.StateOverride{ randomAccounts[2].addr: { Code: newBytes(genesis.Alloc[bab].Code), StateDiff: map[common.Hash]common.Hash{ @@ -1855,7 +1951,7 @@ func TestSimulateV1(t *testing.T) { To: &bab, }}, }, { - StateOverrides: &StateOverride{ + StateOverrides: &override.StateOverride{ randomAccounts[2].addr: { State: map[common.Hash]common.Hash{ common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)), @@ -1902,10 +1998,10 @@ func TestSimulateV1(t *testing.T) { name: "blockhash-opcode", tag: latest, blocks: []simBlock{{ - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(12)), }, - StateOverrides: &StateOverride{ + StateOverrides: &override.StateOverride{ randomAccounts[2].addr: { Code: hex2Bytes("600035804060008103601057600080fd5b5050"), }, @@ -1927,7 +2023,7 @@ func TestSimulateV1(t *testing.T) { Input: uint256ToBytes(uint256.NewInt(10)), }}, }, { - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ Number: (*hexutil.Big)(big.NewInt(16)), }, Calls: []TransactionArgs{{ @@ -2017,7 +2113,7 @@ func TestSimulateV1(t *testing.T) { name: "basefee-non-validation", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ + StateOverrides: &override.StateOverride{ randomAccounts[2].addr: { // Yul code: // object "Test" { @@ -2052,7 +2148,7 @@ func TestSimulateV1(t *testing.T) { }, }, }, { - BlockOverrides: &BlockOverrides{ + BlockOverrides: &override.BlockOverrides{ BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)), }, Calls: []TransactionArgs{{ @@ -2125,7 +2221,7 @@ func TestSimulateV1(t *testing.T) { name: "basefee-validation-mode", tag: latest, blocks: []simBlock{{ - StateOverrides: &StateOverride{ + StateOverrides: &override.StateOverride{ randomAccounts[2].addr: { // Yul code: // object "Test" { @@ -3298,97 +3394,6 @@ func TestRPCGetBlockReceipts(t *testing.T) { } } -type precompileContract struct{} - -func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } - -func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } - -func TestStateOverrideMovePrecompile(t *testing.T) { - db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) - statedb, err := state.New(common.Hash{}, db) - if err != nil { - t.Fatalf("failed to create statedb: %v", err) - } - precompiles := map[common.Address]vm.PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &precompileContract{}, - common.BytesToAddress([]byte{0x2}): &precompileContract{}, - } - bytes2Addr := func(b []byte) *common.Address { - a := common.BytesToAddress(b) - return &a - } - var testSuite = []struct { - overrides StateOverride - expectedPrecompiles map[common.Address]struct{} - fail bool - }{ - { - overrides: StateOverride{ - common.BytesToAddress([]byte{0x1}): { - Code: hex2Bytes("0xff"), - MovePrecompileTo: bytes2Addr([]byte{0x2}), - }, - common.BytesToAddress([]byte{0x2}): { - Code: hex2Bytes("0x00"), - }, - }, - // 0x2 has already been touched by the moveTo. - fail: true, - }, { - overrides: StateOverride{ - common.BytesToAddress([]byte{0x1}): { - Code: hex2Bytes("0xff"), - MovePrecompileTo: bytes2Addr([]byte{0xff}), - }, - common.BytesToAddress([]byte{0x3}): { - Code: hex2Bytes("0x00"), - MovePrecompileTo: bytes2Addr([]byte{0xfe}), - }, - }, - // 0x3 is not a precompile. - fail: true, - }, { - overrides: StateOverride{ - common.BytesToAddress([]byte{0x1}): { - Code: hex2Bytes("0xff"), - MovePrecompileTo: bytes2Addr([]byte{0xff}), - }, - common.BytesToAddress([]byte{0x2}): { - Code: hex2Bytes("0x00"), - MovePrecompileTo: bytes2Addr([]byte{0xfe}), - }, - }, - expectedPrecompiles: map[common.Address]struct{}{common.BytesToAddress([]byte{0xfe}): {}, common.BytesToAddress([]byte{0xff}): {}}, - }, - } - - for i, tt := range testSuite { - cpy := maps.Clone(precompiles) - // Apply overrides - err := tt.overrides.Apply(statedb, cpy) - if tt.fail { - if err == nil { - t.Errorf("test %d: want error, have nothing", i) - } - continue - } - if err != nil { - t.Errorf("test %d: want no error, have %v", i, err) - continue - } - // Precompile keys - if len(cpy) != len(tt.expectedPrecompiles) { - t.Errorf("test %d: precompile mismatch, want %d, have %d", i, len(tt.expectedPrecompiles), len(cpy)) - } - for k := range tt.expectedPrecompiles { - if _, ok := cpy[k]; !ok { - t.Errorf("test %d: precompile not found: %s", i, k.String()) - } - } - } -} - func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) { data, err := json.MarshalIndent(result, "", " ") if err != nil { diff --git a/internal/ethapi/override/override.go b/internal/ethapi/override/override.go new file mode 100644 index 000000000..70b621027 --- /dev/null +++ b/internal/ethapi/override/override.go @@ -0,0 +1,195 @@ +// Copyright 2024 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 . + +package override + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" +) + +// OverrideAccount indicates the overriding fields of account during the execution +// of a message call. +// Note, state and stateDiff can't be specified at the same time. If state is +// set, message execution will only use the data in the given state. Otherwise +// if stateDiff is set, all diff will be applied first and then execute the call +// message. +type OverrideAccount struct { + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance *hexutil.Big `json:"balance"` + State map[common.Hash]common.Hash `json:"state"` + StateDiff map[common.Hash]common.Hash `json:"stateDiff"` + MovePrecompileTo *common.Address `json:"movePrecompileToAddress"` +} + +// StateOverride is the collection of overridden accounts. +type StateOverride map[common.Address]OverrideAccount + +func (diff *StateOverride) has(address common.Address) bool { + _, ok := (*diff)[address] + return ok +} + +// Apply overrides the fields of specified accounts into the given state. +func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.PrecompiledContracts) error { + if diff == nil { + return nil + } + // Tracks destinations of precompiles that were moved. + dirtyAddrs := make(map[common.Address]struct{}) + for addr, account := range *diff { + // If a precompile was moved to this address already, it can't be overridden. + if _, ok := dirtyAddrs[addr]; ok { + return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex()) + } + p, isPrecompile := precompiles[addr] + // The MoveTo feature makes it possible to move a precompile + // code to another address. If the target address is another precompile + // the code for the latter is lost for this session. + // Note the destination account is not cleared upon move. + if account.MovePrecompileTo != nil { + if !isPrecompile { + return fmt.Errorf("account %s is not a precompile", addr.Hex()) + } + // Refuse to move a precompile to an address that has been + // or will be overridden. + if diff.has(*account.MovePrecompileTo) { + return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex()) + } + precompiles[*account.MovePrecompileTo] = p + dirtyAddrs[*account.MovePrecompileTo] = struct{}{} + } + if isPrecompile { + delete(precompiles, addr) + } + // Override account nonce. + if account.Nonce != nil { + statedb.SetNonce(addr, uint64(*account.Nonce)) + } + // Override account(contract) code. + if account.Code != nil { + statedb.SetCode(addr, *account.Code) + } + // Override account balance. + if account.Balance != nil { + u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance)) + statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) + } + if account.State != nil && account.StateDiff != nil { + return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) + } + // Replace entire state if caller requires. + if account.State != nil { + statedb.SetStorage(addr, account.State) + } + // Apply state diff into specified accounts. + if account.StateDiff != nil { + for key, value := range account.StateDiff { + statedb.SetState(addr, key, value) + } + } + } + // Now finalize the changes. Finalize is normally performed between transactions. + // By using finalize, the overrides are semantically behaving as + // if they were created in a transaction just before the tracing occur. + statedb.Finalise(false) + return nil +} + +// BlockOverrides is a set of header fields to override. +type BlockOverrides struct { + Number *hexutil.Big + Difficulty *hexutil.Big // No-op if we're simulating post-merge calls. + Time *hexutil.Uint64 + GasLimit *hexutil.Uint64 + FeeRecipient *common.Address + PrevRandao *common.Hash + BaseFeePerGas *hexutil.Big + BlobBaseFee *hexutil.Big +} + +// Apply overrides the given header fields into the given block context. +func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) { + if o == nil { + return + } + if o.Number != nil { + blockCtx.BlockNumber = o.Number.ToInt() + } + if o.Difficulty != nil { + blockCtx.Difficulty = o.Difficulty.ToInt() + } + if o.Time != nil { + blockCtx.Time = uint64(*o.Time) + } + if o.GasLimit != nil { + blockCtx.GasLimit = uint64(*o.GasLimit) + } + if o.FeeRecipient != nil { + blockCtx.Coinbase = *o.FeeRecipient + } + if o.PrevRandao != nil { + blockCtx.Random = o.PrevRandao + } + if o.BaseFeePerGas != nil { + blockCtx.BaseFee = o.BaseFeePerGas.ToInt() + } + if o.BlobBaseFee != nil { + blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt() + } +} + +// MakeHeader returns a new header object with the overridden +// fields. +// Note: MakeHeader ignores BlobBaseFee if set. That's because +// header has no such field. +func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header { + if o == nil { + return header + } + h := types.CopyHeader(header) + if o.Number != nil { + h.Number = o.Number.ToInt() + } + if o.Difficulty != nil { + h.Difficulty = o.Difficulty.ToInt() + } + if o.Time != nil { + h.Time = uint64(*o.Time) + } + if o.GasLimit != nil { + h.GasLimit = uint64(*o.GasLimit) + } + if o.FeeRecipient != nil { + h.Coinbase = *o.FeeRecipient + } + if o.PrevRandao != nil { + h.MixDigest = *o.PrevRandao + } + if o.BaseFeePerGas != nil { + h.BaseFee = o.BaseFeePerGas.ToInt() + } + return h +} diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go new file mode 100644 index 000000000..07ed6442b --- /dev/null +++ b/internal/ethapi/override/override_test.go @@ -0,0 +1,125 @@ +// Copyright 2024 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 . + +package override + +import ( + "maps" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/triedb" +) + +type precompileContract struct{} + +func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 } + +func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil } + +func TestStateOverrideMovePrecompile(t *testing.T) { + db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) + statedb, err := state.New(common.Hash{}, db) + if err != nil { + t.Fatalf("failed to create statedb: %v", err) + } + precompiles := map[common.Address]vm.PrecompiledContract{ + common.BytesToAddress([]byte{0x1}): &precompileContract{}, + common.BytesToAddress([]byte{0x2}): &precompileContract{}, + } + bytes2Addr := func(b []byte) *common.Address { + a := common.BytesToAddress(b) + return &a + } + var testSuite = []struct { + overrides StateOverride + expectedPrecompiles map[common.Address]struct{} + fail bool + }{ + { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0x2}), + }, + common.BytesToAddress([]byte{0x2}): { + Code: hex2Bytes("0x00"), + }, + }, + // 0x2 has already been touched by the moveTo. + fail: true, + }, { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0xff}), + }, + common.BytesToAddress([]byte{0x3}): { + Code: hex2Bytes("0x00"), + MovePrecompileTo: bytes2Addr([]byte{0xfe}), + }, + }, + // 0x3 is not a precompile. + fail: true, + }, { + overrides: StateOverride{ + common.BytesToAddress([]byte{0x1}): { + Code: hex2Bytes("0xff"), + MovePrecompileTo: bytes2Addr([]byte{0xff}), + }, + common.BytesToAddress([]byte{0x2}): { + Code: hex2Bytes("0x00"), + MovePrecompileTo: bytes2Addr([]byte{0xfe}), + }, + }, + expectedPrecompiles: map[common.Address]struct{}{common.BytesToAddress([]byte{0xfe}): {}, common.BytesToAddress([]byte{0xff}): {}}, + }, + } + + for i, tt := range testSuite { + cpy := maps.Clone(precompiles) + // Apply overrides + err := tt.overrides.Apply(statedb, cpy) + if tt.fail { + if err == nil { + t.Errorf("test %d: want error, have nothing", i) + } + continue + } + if err != nil { + t.Errorf("test %d: want no error, have %v", i, err) + continue + } + // Precompile keys + if len(cpy) != len(tt.expectedPrecompiles) { + t.Errorf("test %d: precompile mismatch, want %d, have %d", i, len(tt.expectedPrecompiles), len(cpy)) + } + for k := range tt.expectedPrecompiles { + if _, ok := cpy[k]; !ok { + t.Errorf("test %d: precompile not found: %s", i, k.String()) + } + } + } +} + +func hex2Bytes(str string) *hexutil.Bytes { + rpcBytes := hexutil.Bytes(common.FromHex(str)) + return &rpcBytes +} diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index f6647c7ba..5bd0079a9 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" @@ -49,8 +50,8 @@ const ( // simBlock is a batch of calls to be simulated sequentially. type simBlock struct { - BlockOverrides *BlockOverrides - StateOverrides *StateOverride + BlockOverrides *override.BlockOverrides + StateOverrides *override.StateOverride Calls []TransactionArgs } @@ -303,7 +304,7 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { ) for _, block := range blocks { if block.BlockOverrides == nil { - block.BlockOverrides = new(BlockOverrides) + block.BlockOverrides = new(override.BlockOverrides) } if block.BlockOverrides.Number == nil { n := new(big.Int).Add(prevNumber, big.NewInt(1)) @@ -323,7 +324,7 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { for i := uint64(0); i < gap.Uint64(); i++ { n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1))) t := prevTimestamp + timestampIncrement - b := simBlock{BlockOverrides: &BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}} + b := simBlock{BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}} prevTimestamp = t res = append(res, b) } diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go index 37883924a..52ae40cad 100644 --- a/internal/ethapi/simulate_test.go +++ b/internal/ethapi/simulate_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/ethapi/override" ) func TestSimulateSanitizeBlockOrder(t *testing.T) { @@ -45,37 +46,37 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}}, expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}}, }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(12)}}}, err: "block numbers must be in order: 12 <= 13", }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, err: "block timestamps must be in order: 52 <= 52", }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12), Time: newUint64(55)}}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(12), Time: newUint64(55)}}}, err: "block timestamps must be in order: 55 <= 60", }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, err: "block timestamps must be in order: 61 <= 61", }, } { diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 35cbc83fb..5dd053c5f 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -160,7 +160,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas BlobHashes: args.BlobHashes, } latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap()) + estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, nil, b.RPCGasCap()) if err != nil { return err } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 7b89f57cf..10984cc7b 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -550,8 +550,8 @@ web3._extend({ new web3._extend.Method({ name: 'estimateGas', call: 'eth_estimateGas', - params: 3, - inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null], + params: 4, + inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null, null], outputFormatter: web3._extend.utils.toDecimal }), new web3._extend.Method({ From a3cca7feaa7305e28353fc6a20754311fa481e5f Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 13 Dec 2024 08:46:12 -0300 Subject: [PATCH 044/354] p2p: DNS resolution for static nodes (#30822) Closes #23210 # Context When deploying Geth in Kubernetes with ReplicaSets, we encountered two DNS-related issues affecting node connectivity. First, during startup, Geth tries to resolve DNS names for static nodes too early in the config unmarshaling phase. If peer nodes aren't ready yet (which is common in Kubernetes rolling deployments), this causes an immediate failure: ``` INFO [11-26|10:03:42.816] Starting Geth on Ethereum mainnet... INFO [11-26|10:03:42.817] Bumping default cache on mainnet provided=1024 updated=4096 Fatal: config.toml, line 81: (p2p.Config.StaticNodes) lookup idontexist.geth.node: no such host ``` The second issue comes up when pods get rescheduled to different nodes - their IPs change but peers keep using the initially resolved IP, never updating the DNS mapping. This PR adds proper DNS support for enode:// URLs by deferring resolution to connection time. It also handles DNS failures gracefully instead of failing fatally during startup, making it work better in container environments where IPs are dynamic and peers come and go during rollouts. --------- Co-authored-by: Felix Lange --- p2p/dial.go | 143 ++++++++++++++++++++++++++++++++-------- p2p/dial_test.go | 29 ++++++++ p2p/enode/node.go | 22 +++++++ p2p/enode/node_test.go | 19 ++++++ p2p/enode/urlv4.go | 38 ++++++----- p2p/enode/urlv4_test.go | 23 +++---- p2p/peer_test.go | 30 ++++----- 7 files changed, 228 insertions(+), 76 deletions(-) diff --git a/p2p/dial.go b/p2p/dial.go index 24d4dc2e8..225709427 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -24,6 +24,7 @@ import ( "fmt" mrand "math/rand" "net" + "net/netip" "sync" "sync/atomic" "time" @@ -31,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" ) @@ -77,6 +79,7 @@ var ( errRecentlyDialed = errors.New("recently dialed") errNetRestrict = errors.New("not contained in netrestrict list") errNoPort = errors.New("node does not provide TCP port") + errNoResolvedIP = errors.New("node does not provide a resolved IP") ) // dialer creates outbound connections and submits them into Server. @@ -90,16 +93,17 @@ var ( // to create peer connections to nodes arriving through the iterator. type dialScheduler struct { dialConfig - setupFunc dialSetupFunc - wg sync.WaitGroup - cancel context.CancelFunc - ctx context.Context - nodesIn chan *enode.Node - doneCh chan *dialTask - addStaticCh chan *enode.Node - remStaticCh chan *enode.Node - addPeerCh chan *conn - remPeerCh chan *conn + setupFunc dialSetupFunc + dnsLookupFunc func(ctx context.Context, network string, name string) ([]netip.Addr, error) + wg sync.WaitGroup + cancel context.CancelFunc + ctx context.Context + nodesIn chan *enode.Node + doneCh chan *dialTask + addStaticCh chan *enode.Node + remStaticCh chan *enode.Node + addPeerCh chan *conn + remPeerCh chan *conn // Everything below here belongs to loop and // should only be accessed by code on the loop goroutine. @@ -159,18 +163,19 @@ func (cfg dialConfig) withDefaults() dialConfig { func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupFunc) *dialScheduler { cfg := config.withDefaults() d := &dialScheduler{ - dialConfig: cfg, - historyTimer: mclock.NewAlarm(cfg.clock), - setupFunc: setupFunc, - dialing: make(map[enode.ID]*dialTask), - static: make(map[enode.ID]*dialTask), - peers: make(map[enode.ID]struct{}), - doneCh: make(chan *dialTask), - nodesIn: make(chan *enode.Node), - addStaticCh: make(chan *enode.Node), - remStaticCh: make(chan *enode.Node), - addPeerCh: make(chan *conn), - remPeerCh: make(chan *conn), + dialConfig: cfg, + historyTimer: mclock.NewAlarm(cfg.clock), + setupFunc: setupFunc, + dnsLookupFunc: net.DefaultResolver.LookupNetIP, + dialing: make(map[enode.ID]*dialTask), + static: make(map[enode.ID]*dialTask), + peers: make(map[enode.ID]struct{}), + doneCh: make(chan *dialTask), + nodesIn: make(chan *enode.Node), + addStaticCh: make(chan *enode.Node), + remStaticCh: make(chan *enode.Node), + addPeerCh: make(chan *conn), + remPeerCh: make(chan *conn), } d.lastStatsLog = d.clock.Now() d.ctx, d.cancel = context.WithCancel(context.Background()) @@ -274,7 +279,7 @@ loop: case node := <-d.addStaticCh: id := node.ID() _, exists := d.static[id] - d.log.Trace("Adding static node", "id", id, "ip", node.IPAddr(), "added", !exists) + d.log.Trace("Adding static node", "id", id, "endpoint", nodeEndpointForLog(node), "added", !exists) if exists { continue loop } @@ -433,10 +438,68 @@ func (d *dialScheduler) removeFromStaticPool(idx int) { task.staticPoolIndex = -1 } +// dnsResolveHostname updates the given node from its DNS hostname. +// This is used to resolve static dial targets. +func (d *dialScheduler) dnsResolveHostname(n *enode.Node) (*enode.Node, error) { + if n.Hostname() == "" { + return n, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + foundIPs, err := d.dnsLookupFunc(ctx, "ip", n.Hostname()) + if err != nil { + return n, err + } + + // Check for IP updates. + var ( + nodeIP4, nodeIP6 netip.Addr + foundIP4, foundIP6 netip.Addr + ) + n.Load((*enr.IPv4Addr)(&nodeIP4)) + n.Load((*enr.IPv6Addr)(&nodeIP6)) + for _, ip := range foundIPs { + if ip.Is4() && !foundIP4.IsValid() { + foundIP4 = ip + } + if ip.Is6() && !foundIP6.IsValid() { + foundIP6 = ip + } + } + + if !foundIP4.IsValid() && !foundIP6.IsValid() { + // Lookup failed. + return n, errNoResolvedIP + } + if foundIP4 == nodeIP4 && foundIP6 == nodeIP6 { + // No updates necessary. + d.log.Trace("Node DNS lookup had no update", "id", n.ID(), "name", n.Hostname(), "ip", foundIP4, "ip6", foundIP6) + return n, nil + } + + // Update the node. Note this invalidates the ENR signature, because we use SignNull + // to create a modified copy. But this should be OK, since we just use the node as a + // dial target. And nodes will usually only have a DNS hostname if they came from a + // enode:// URL, which has no signature anyway. If it ever becomes a problem, the + // resolved IP could also be stored into dialTask instead of the node. + rec := n.Record() + if foundIP4.IsValid() { + rec.Set(enr.IPv4Addr(foundIP4)) + } + if foundIP6.IsValid() { + rec.Set(enr.IPv6Addr(foundIP6)) + } + rec.SetSeq(n.Seq()) // ensure seq not bumped by update + newNode := enode.SignNull(rec, n.ID()).WithHostname(n.Hostname()) + d.log.Debug("Node updated from DNS lookup", "id", n.ID(), "name", n.Hostname(), "ip", newNode.IP()) + return newNode, nil +} + // startDial runs the given dial task in a separate goroutine. func (d *dialScheduler) startDial(task *dialTask) { node := task.dest() - d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IPAddr(), "flag", task.flags) + d.log.Trace("Starting p2p dial", "id", node.ID(), "endpoint", nodeEndpointForLog(node), "flag", task.flags) hkey := string(node.ID().Bytes()) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.dialing[node.ID()] = task @@ -473,14 +536,29 @@ func (t *dialTask) dest() *enode.Node { } func (t *dialTask) run(d *dialScheduler) { - if t.needResolve() && !t.resolve(d) { - return + if t.isStatic() { + // Resolve DNS. + if n := t.dest(); n.Hostname() != "" { + resolved, err := d.dnsResolveHostname(n) + if err != nil { + d.log.Warn("DNS lookup of static node failed", "id", n.ID(), "name", n.Hostname(), "err", err) + } else { + t.destPtr.Store(resolved) + } + } + // Try resolving node ID through the DHT if there is no IP address. + if !t.dest().IPAddr().IsValid() { + if !t.resolve(d) { + return // DHT resolve failed, skip dial. + } + } } err := t.dial(d, t.dest()) if err != nil { // For static nodes, resolve one more time if dialing fails. - if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { + var dialErr *dialError + if errors.As(err, &dialErr) && t.isStatic() { if t.resolve(d) { t.dial(d, t.dest()) } @@ -488,8 +566,8 @@ func (t *dialTask) run(d *dialScheduler) { } } -func (t *dialTask) needResolve() bool { - return t.flags&staticDialedConn != 0 && !t.dest().IPAddr().IsValid() +func (t *dialTask) isStatic() bool { + return t.flags&staticDialedConn != 0 } // resolve attempts to find the current endpoint for the destination @@ -553,3 +631,10 @@ func cleanupDialErr(err error) error { } return err } + +func nodeEndpointForLog(n *enode.Node) string { + if n.Hostname() != "" { + return n.Hostname() + } + return n.IPAddr().String() +} diff --git a/p2p/dial_test.go b/p2p/dial_test.go index 13908f11e..f18dacce2 100644 --- a/p2p/dial_test.go +++ b/p2p/dial_test.go @@ -22,6 +22,7 @@ import ( "fmt" "math/rand" "net" + "net/netip" "reflect" "sync" "testing" @@ -394,6 +395,34 @@ func TestDialSchedResolve(t *testing.T) { }) } +func TestDialSchedDNSHostname(t *testing.T) { + t.Parallel() + + config := dialConfig{ + maxActiveDials: 1, + maxDialPeers: 1, + } + node := newNode(uintID(0x01), ":30303").WithHostname("node-hostname") + resolved := newNode(uintID(0x01), "1.2.3.4:30303").WithHostname("node-hostname") + runDialTest(t, config, []dialTestRound{ + { + update: func(d *dialScheduler) { + d.dnsLookupFunc = func(ctx context.Context, network string, name string) ([]netip.Addr, error) { + if name != "node-hostname" { + t.Error("wrong hostname in DNS lookup:", name) + } + result := []netip.Addr{netip.MustParseAddr("1.2.3.4")} + return result, nil + } + d.addStatic(node) + }, + wantNewDials: []*enode.Node{ + resolved, + }, + }, + }) +} + // ------- // Code below here is the framework for the tests above. diff --git a/p2p/enode/node.go b/p2p/enode/node.go index 4d93d3f6b..d6f2ac7ff 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -37,6 +37,10 @@ var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded reco type Node struct { r enr.Record id ID + + // hostname tracks the DNS name of the node. + hostname string + // endpoint information ip netip.Addr udp uint16 @@ -77,6 +81,8 @@ func newNodeWithID(r *enr.Record, id ID) *Node { n.setIP4(ip4) case valid6: n.setIP6(ip6) + default: + n.setIPv4Ports() } return n } @@ -103,6 +109,10 @@ func localityScore(ip netip.Addr) int { func (n *Node) setIP4(ip netip.Addr) { n.ip = ip + n.setIPv4Ports() +} + +func (n *Node) setIPv4Ports() { n.Load((*enr.UDP)(&n.udp)) n.Load((*enr.TCP)(&n.tcp)) } @@ -184,6 +194,18 @@ func (n *Node) TCP() int { return int(n.tcp) } +// WithHostname adds a DNS hostname to the node. +func (n *Node) WithHostname(hostname string) *Node { + cpy := *n + cpy.hostname = hostname + return &cpy +} + +// Hostname returns the DNS name assigned by WithHostname. +func (n *Node) Hostname() string { + return n.hostname +} + // UDPEndpoint returns the announced UDP endpoint. func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go index f38c77415..e9fe631f3 100644 --- a/p2p/enode/node_test.go +++ b/p2p/enode/node_test.go @@ -74,6 +74,7 @@ func TestNodeEndpoints(t *testing.T) { wantUDP int wantTCP int wantQUIC int + wantDNS string } tests := []endpointTest{ { @@ -90,6 +91,7 @@ func TestNodeEndpoints(t *testing.T) { r.Set(enr.UDP(9000)) return SignNull(&r, id) }(), + wantUDP: 9000, }, { name: "tcp-only", @@ -98,6 +100,7 @@ func TestNodeEndpoints(t *testing.T) { r.Set(enr.TCP(9000)) return SignNull(&r, id) }(), + wantTCP: 9000, }, { name: "quic-only", @@ -268,6 +271,19 @@ func TestNodeEndpoints(t *testing.T) { wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), wantQUIC: 9001, }, + { + name: "dns-only", + node: func() *Node { + var r enr.Record + r.Set(enr.UDP(30303)) + r.Set(enr.TCP(30303)) + n := SignNull(&r, id).WithHostname("example.com") + return n + }(), + wantTCP: 30303, + wantUDP: 30303, + wantDNS: "example.com", + }, } for _, test := range tests { @@ -284,6 +300,9 @@ func TestNodeEndpoints(t *testing.T) { if quic, _ := test.node.QUICEndpoint(); test.wantQUIC != int(quic.Port()) { t.Errorf("node has wrong QUIC port %d, want %d", quic.Port(), test.wantQUIC) } + if test.wantDNS != test.node.Hostname() { + t.Errorf("node has wrong DNS name %s, want %s", test.node.Hostname(), test.wantDNS) + } }) } } diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go index a55dfa663..b455cd453 100644 --- a/p2p/enode/urlv4.go +++ b/p2p/enode/urlv4.go @@ -33,7 +33,6 @@ import ( var ( incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") - lookupIPFunc = net.LookupIP ) // MustParseV4 parses a node URL. It panics if the URL is not valid. @@ -126,20 +125,9 @@ func parseComplete(rawurl string) (*Node, error) { if id, err = parsePubkey(u.User.String()); err != nil { return nil, fmt.Errorf("invalid public key (%v)", err) } - // Parse the IP address. + + // Parse the IP and ports. ip := net.ParseIP(u.Hostname()) - if ip == nil { - ips, err := lookupIPFunc(u.Hostname()) - if err != nil { - return nil, err - } - ip = ips[0] - } - // Ensure the IP is 4 bytes long for IPv4 addresses. - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } - // Parse the port numbers. if tcpPort, err = strconv.ParseUint(u.Port(), 10, 16); err != nil { return nil, errors.New("invalid port") } @@ -151,7 +139,13 @@ func parseComplete(rawurl string) (*Node, error) { return nil, errors.New("invalid discport in query") } } - return NewV4(id, ip, int(tcpPort), int(udpPort)), nil + + // Create the node. + node := NewV4(id, ip, int(tcpPort), int(udpPort)) + if ip == nil && u.Hostname() != "" { + node = node.WithHostname(u.Hostname()) + } + return node, nil } // parsePubkey parses a hex-encoded secp256k1 public key. @@ -181,15 +175,23 @@ func (n *Node) URLv4() string { nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:]) } u := url.URL{Scheme: "enode"} - if !n.ip.IsValid() { - u.Host = nodeid - } else { + if n.Hostname() != "" { + // For nodes with a DNS name: include DNS name, TCP port, and optional UDP port + u.User = url.User(nodeid) + u.Host = fmt.Sprintf("%s:%d", n.Hostname(), n.TCP()) + if n.UDP() != n.TCP() { + u.RawQuery = "discport=" + strconv.Itoa(n.UDP()) + } + } else if n.ip.IsValid() { + // For IP-based nodes: include IP address, TCP port, and optional UDP port addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()} u.User = url.User(nodeid) u.Host = addr.String() if n.UDP() != n.TCP() { u.RawQuery = "discport=" + strconv.Itoa(n.UDP()) } + } else { + u.Host = nodeid } return u.String() } diff --git a/p2p/enode/urlv4_test.go b/p2p/enode/urlv4_test.go index 33de96cc5..f39d5a2de 100644 --- a/p2p/enode/urlv4_test.go +++ b/p2p/enode/urlv4_test.go @@ -18,7 +18,6 @@ package enode import ( "crypto/ecdsa" - "errors" "net" "reflect" "strings" @@ -28,15 +27,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" ) -func init() { - lookupIPFunc = func(name string) ([]net.IP, error) { - if name == "node.example.org" { - return []net.IP{{33, 44, 55, 66}}, nil - } - return nil, errors.New("no such host") - } -} - var parseNodeTests = []struct { input string wantError string @@ -70,10 +60,6 @@ var parseNodeTests = []struct { wantError: enr.ErrInvalidSig.Error(), }, // Complete node URLs with IP address and ports - { - input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@invalid.:3", - wantError: `no such host`, - }, { input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo", wantError: `invalid port`, @@ -91,6 +77,15 @@ var parseNodeTests = []struct { 52150, ), }, + { + input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@valid.:3", + wantResult: NewV4( + hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), + nil, + 3, + 3, + ).WithHostname("valid."), + }, { input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", wantResult: NewV4( diff --git a/p2p/peer_test.go b/p2p/peer_test.go index 4308bbd2e..dea72875f 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -60,22 +60,22 @@ func uintID(i uint16) enode.ID { // newNode creates a node record with the given address. func newNode(id enode.ID, addr string) *enode.Node { var r enr.Record - if addr != "" { - // Set the port if present. - if strings.Contains(addr, ":") { - hs, ps, err := net.SplitHostPort(addr) - if err != nil { - panic(fmt.Errorf("invalid address %q", addr)) - } - port, err := strconv.Atoi(ps) - if err != nil { - panic(fmt.Errorf("invalid port in %q", addr)) - } - r.Set(enr.TCP(port)) - r.Set(enr.UDP(port)) - addr = hs + // Set the port if present. + if strings.Contains(addr, ":") { + hs, ps, err := net.SplitHostPort(addr) + if err != nil { + panic(fmt.Errorf("invalid address %q", addr)) + } + port, err := strconv.Atoi(ps) + if err != nil { + panic(fmt.Errorf("invalid port in %q", addr)) } - // Set the IP. + r.Set(enr.TCP(port)) + r.Set(enr.UDP(port)) + addr = hs + } + // Set the IP. + if addr != "" { ip := net.ParseIP(addr) if ip == nil { panic(fmt.Errorf("invalid IP %q", addr)) From beeba63c76794f1beca9ee68985f5f69c5c228ad Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 16 Dec 2024 03:29:37 -0700 Subject: [PATCH 045/354] all: implement eip-7702 set code tx (#30078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR implements EIP-7702: "Set EOA account code". Specification: https://eips.ethereum.org/EIPS/eip-7702 > Add a new transaction type that adds a list of `[chain_id, address, nonce, y_parity, r, s]` authorization tuples. For each tuple, write a delegation designator `(0xef0100 ++ address)` to the signing account’s code. All code reading operations must load the code pointed to by the designator. --------- Co-authored-by: Mario Vega Co-authored-by: Martin Holst Swende Co-authored-by: Felix Lange --- accounts/external/backend.go | 2 +- cmd/evm/eofparse.go | 2 +- cmd/evm/eofparse_test.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 4 +- cmd/evm/internal/t8ntool/gen_execresult.go | 4 +- cmd/evm/internal/t8ntool/transaction.go | 2 +- cmd/evm/t8n_test.go | 8 + cmd/evm/testdata/1/exp.json | 3 +- cmd/evm/testdata/13/exp2.json | 3 +- cmd/evm/testdata/14/exp.json | 3 +- cmd/evm/testdata/14/exp2.json | 3 +- cmd/evm/testdata/14/exp_berlin.json | 3 +- cmd/evm/testdata/19/exp_arrowglacier.json | 3 +- cmd/evm/testdata/19/exp_grayglacier.json | 25 +- cmd/evm/testdata/19/exp_london.json | 3 +- cmd/evm/testdata/23/exp.json | 3 +- cmd/evm/testdata/24/exp.json | 3 +- cmd/evm/testdata/25/exp.json | 3 +- cmd/evm/testdata/26/exp.json | 3 +- cmd/evm/testdata/28/exp.json | 3 +- cmd/evm/testdata/29/exp.json | 3 +- cmd/evm/testdata/3/exp.json | 3 +- cmd/evm/testdata/30/exp.json | 5 +- cmd/evm/testdata/33/README.md | 1 + cmd/evm/testdata/33/alloc.json | 30 +++ cmd/evm/testdata/33/env.json | 14 ++ cmd/evm/testdata/33/exp.json | 62 +++++ cmd/evm/testdata/33/txs.json | 37 +++ cmd/evm/testdata/5/exp.json | 3 +- core/bench_test.go | 2 +- core/blockchain_test.go | 94 ++++++++ core/error.go | 21 ++ core/state/journal.go | 19 +- core/state/state_object.go | 7 +- core/state/statedb.go | 5 +- core/state/statedb_hooked.go | 11 +- core/state_processor_test.go | 25 +- core/state_transition.go | 107 ++++++++- core/txpool/validation.go | 2 +- core/types/gen_authorization.go | 75 ++++++ core/types/receipt.go | 4 +- core/types/transaction.go | 12 + core/types/transaction_marshalling.go | 92 +++++++ core/types/transaction_signing.go | 77 +++++- core/types/tx_setcode.go | 226 ++++++++++++++++++ core/types/tx_setcode_test.go | 70 ++++++ core/verkle_witness_test.go | 4 +- core/vm/eips.go | 68 ++++++ core/vm/eof_validation_test.go | 16 +- core/vm/evm.go | 39 ++- core/vm/interface.go | 4 +- core/vm/interpreter.go | 2 + core/vm/jump_table.go | 17 +- core/vm/operations_acl.go | 68 ++++++ core/vm/runtime/runtime_test.go | 80 +++++++ .../testdata/prestate_tracer/setcode_tx.json | 82 +++++++ eth/tracers/native/prestate.go | 9 + graphql/graphql.go | 4 +- internal/ethapi/api.go | 61 +++-- internal/ethapi/api_test.go | 23 +- internal/ethapi/transaction_args.go | 27 +++ params/protocol_params.go | 9 +- tests/gen_stauthorization.go | 74 ++++++ tests/gen_sttransaction.go | 6 + tests/state_test_util.go | 37 +++ tests/transaction_test_util.go | 2 +- 66 files changed, 1609 insertions(+), 115 deletions(-) create mode 100644 cmd/evm/testdata/33/README.md create mode 100644 cmd/evm/testdata/33/alloc.json create mode 100644 cmd/evm/testdata/33/env.json create mode 100644 cmd/evm/testdata/33/exp.json create mode 100644 cmd/evm/testdata/33/txs.json create mode 100644 core/types/gen_authorization.go create mode 100644 core/types/tx_setcode.go create mode 100644 core/types/tx_setcode_test.go create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json create mode 100644 tests/gen_stauthorization.go diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 62322753d..42eaf661c 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -215,7 +215,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio switch tx.Type() { case types.LegacyTxType, types.AccessListTxType: args.GasPrice = (*hexutil.Big)(tx.GasPrice()) - case types.DynamicFeeTxType, types.BlobTxType: + case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType: args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap()) default: diff --git a/cmd/evm/eofparse.go b/cmd/evm/eofparse.go index df8581146..92182a53b 100644 --- a/cmd/evm/eofparse.go +++ b/cmd/evm/eofparse.go @@ -36,7 +36,7 @@ var jt vm.JumpTable const initcode = "INITCODE" func init() { - jt = vm.NewPragueEOFInstructionSetForTesting() + jt = vm.NewEOFInstructionSetForTesting() } var ( diff --git a/cmd/evm/eofparse_test.go b/cmd/evm/eofparse_test.go index 9b17039f5..cda4b38fc 100644 --- a/cmd/evm/eofparse_test.go +++ b/cmd/evm/eofparse_test.go @@ -43,7 +43,7 @@ func FuzzEofParsing(f *testing.F) { // And do the fuzzing f.Fuzz(func(t *testing.T, data []byte) { var ( - jt = vm.NewPragueEOFInstructionSetForTesting() + jt = vm.NewEOFInstructionSetForTesting() c vm.Container ) cpy := common.CopyBytes(data) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 39aba8a9c..90ef54095 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -71,11 +71,11 @@ type ExecutionResult struct { CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` RequestsHash *common.Hash `json:"requestsHash,omitempty"` - Requests [][]byte `json:"requests,omitempty"` + Requests [][]byte `json:"requests"` } type executionResultMarshaling struct { - Requests []hexutil.Bytes `json:"requests,omitempty"` + Requests []hexutil.Bytes `json:"requests"` } type ommer struct { diff --git a/cmd/evm/internal/t8ntool/gen_execresult.go b/cmd/evm/internal/t8ntool/gen_execresult.go index 0da94f5ca..38310b9f2 100644 --- a/cmd/evm/internal/t8ntool/gen_execresult.go +++ b/cmd/evm/internal/t8ntool/gen_execresult.go @@ -31,7 +31,7 @@ func (e ExecutionResult) MarshalJSON() ([]byte, error) { CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` RequestsHash *common.Hash `json:"requestsHash,omitempty"` - Requests []hexutil.Bytes `json:"requests,omitempty"` + Requests []hexutil.Bytes `json:"requests"` } var enc ExecutionResult enc.StateRoot = e.StateRoot @@ -74,7 +74,7 @@ func (e *ExecutionResult) UnmarshalJSON(input []byte) error { CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` RequestsHash *common.Hash `json:"requestsHash,omitempty"` - Requests []hexutil.Bytes `json:"requests,omitempty"` + Requests []hexutil.Bytes `json:"requests"` } var dec ExecutionResult if err := json.Unmarshal(input, &dec); err != nil { diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 7f66ba4d8..64e21b24f 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,7 +133,7 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, + if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 85caf010b..27c6c4316 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -287,6 +287,14 @@ func TestT8n(t *testing.T) { output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", }, + { // Prague test, EIP-7702 transaction + base: "./testdata/33", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Prague", "", + }, + output: t8nOutput{alloc: true, result: true}, + expOut: "exp.json", + }, } { args := []string{"t8n"} args = append(args, tc.output.get()...) diff --git a/cmd/evm/testdata/1/exp.json b/cmd/evm/testdata/1/exp.json index d1351e5b7..50662f35e 100644 --- a/cmd/evm/testdata/1/exp.json +++ b/cmd/evm/testdata/1/exp.json @@ -40,6 +40,7 @@ } ], "currentDifficulty": "0x20000", - "gasUsed": "0x5208" + "gasUsed": "0x5208", + "requests": null } } diff --git a/cmd/evm/testdata/13/exp2.json b/cmd/evm/testdata/13/exp2.json index babce3592..6415a4f1f 100644 --- a/cmd/evm/testdata/13/exp2.json +++ b/cmd/evm/testdata/13/exp2.json @@ -37,6 +37,7 @@ ], "currentDifficulty": "0x20000", "gasUsed": "0x109a0", - "currentBaseFee": "0x36b" + "currentBaseFee": "0x36b", + "requests": null } } diff --git a/cmd/evm/testdata/14/exp.json b/cmd/evm/testdata/14/exp.json index 26d49173c..300217ee3 100644 --- a/cmd/evm/testdata/14/exp.json +++ b/cmd/evm/testdata/14/exp.json @@ -8,6 +8,7 @@ "currentDifficulty": "0x2000020000000", "receipts": [], "gasUsed": "0x0", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/14/exp2.json b/cmd/evm/testdata/14/exp2.json index cd75b47d5..6d139e371 100644 --- a/cmd/evm/testdata/14/exp2.json +++ b/cmd/evm/testdata/14/exp2.json @@ -8,6 +8,7 @@ "receipts": [], "currentDifficulty": "0x1ff8020000000", "gasUsed": "0x0", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/14/exp_berlin.json b/cmd/evm/testdata/14/exp_berlin.json index 5c00ef130..c952d0f51 100644 --- a/cmd/evm/testdata/14/exp_berlin.json +++ b/cmd/evm/testdata/14/exp_berlin.json @@ -8,6 +8,7 @@ "receipts": [], "currentDifficulty": "0x1ff9000000000", "gasUsed": "0x0", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/19/exp_arrowglacier.json b/cmd/evm/testdata/19/exp_arrowglacier.json index dd49f7d02..0822fcc29 100644 --- a/cmd/evm/testdata/19/exp_arrowglacier.json +++ b/cmd/evm/testdata/19/exp_arrowglacier.json @@ -8,6 +8,7 @@ "currentDifficulty": "0x2000000200000", "receipts": [], "gasUsed": "0x0", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/19/exp_grayglacier.json b/cmd/evm/testdata/19/exp_grayglacier.json index 86fd8e6c1..e80c9eb00 100644 --- a/cmd/evm/testdata/19/exp_grayglacier.json +++ b/cmd/evm/testdata/19/exp_grayglacier.json @@ -1,13 +1,14 @@ { - "result": { - "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", - "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts": [], - "currentDifficulty": "0x2000000004000", - "gasUsed": "0x0", - "currentBaseFee": "0x500" - } -} \ No newline at end of file + "result": { + "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "currentDifficulty": "0x2000000004000", + "gasUsed": "0x0", + "currentBaseFee": "0x500", + "requests": null + } +} diff --git a/cmd/evm/testdata/19/exp_london.json b/cmd/evm/testdata/19/exp_london.json index 9e9a17da9..a17f68448 100644 --- a/cmd/evm/testdata/19/exp_london.json +++ b/cmd/evm/testdata/19/exp_london.json @@ -8,6 +8,7 @@ "currentDifficulty": "0x2000080000000", "receipts": [], "gasUsed": "0x0", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/23/exp.json b/cmd/evm/testdata/23/exp.json index 22dde0a27..7f36165e3 100644 --- a/cmd/evm/testdata/23/exp.json +++ b/cmd/evm/testdata/23/exp.json @@ -21,6 +21,7 @@ } ], "currentDifficulty": "0x20000", - "gasUsed": "0x520b" + "gasUsed": "0x520b", + "requests": null } } diff --git a/cmd/evm/testdata/24/exp.json b/cmd/evm/testdata/24/exp.json index ac571d149..8f380c662 100644 --- a/cmd/evm/testdata/24/exp.json +++ b/cmd/evm/testdata/24/exp.json @@ -51,6 +51,7 @@ ], "currentDifficulty": null, "gasUsed": "0x10306", - "currentBaseFee": "0x500" + "currentBaseFee": "0x500", + "requests": null } } diff --git a/cmd/evm/testdata/25/exp.json b/cmd/evm/testdata/25/exp.json index 1cb521794..a67463376 100644 --- a/cmd/evm/testdata/25/exp.json +++ b/cmd/evm/testdata/25/exp.json @@ -34,6 +34,7 @@ ], "currentDifficulty": null, "gasUsed": "0x5208", - "currentBaseFee": "0x460" + "currentBaseFee": "0x460", + "requests": null } } diff --git a/cmd/evm/testdata/26/exp.json b/cmd/evm/testdata/26/exp.json index 4815e5cb6..d6275270f 100644 --- a/cmd/evm/testdata/26/exp.json +++ b/cmd/evm/testdata/26/exp.json @@ -15,6 +15,7 @@ "currentDifficulty": null, "gasUsed": "0x0", "currentBaseFee": "0x500", - "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" + "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5", + "requests": null } } diff --git a/cmd/evm/testdata/28/exp.json b/cmd/evm/testdata/28/exp.json index 75c715e97..b86c2d8de 100644 --- a/cmd/evm/testdata/28/exp.json +++ b/cmd/evm/testdata/28/exp.json @@ -42,6 +42,7 @@ "currentBaseFee": "0x9", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "currentExcessBlobGas": "0x0", - "blobGasUsed": "0x20000" + "blobGasUsed": "0x20000", + "requests": null } } diff --git a/cmd/evm/testdata/29/exp.json b/cmd/evm/testdata/29/exp.json index c4c001ec1..7fbdc1828 100644 --- a/cmd/evm/testdata/29/exp.json +++ b/cmd/evm/testdata/29/exp.json @@ -40,6 +40,7 @@ "currentBaseFee": "0x9", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "currentExcessBlobGas": "0x0", - "blobGasUsed": "0x0" + "blobGasUsed": "0x0", + "requests": null } } diff --git a/cmd/evm/testdata/3/exp.json b/cmd/evm/testdata/3/exp.json index 7230dca2c..831c07859 100644 --- a/cmd/evm/testdata/3/exp.json +++ b/cmd/evm/testdata/3/exp.json @@ -34,6 +34,7 @@ } ], "currentDifficulty": "0x20000", - "gasUsed": "0x521f" + "gasUsed": "0x521f", + "requests": null } } diff --git a/cmd/evm/testdata/30/exp.json b/cmd/evm/testdata/30/exp.json index f0b19c6b3..a206c3bbd 100644 --- a/cmd/evm/testdata/30/exp.json +++ b/cmd/evm/testdata/30/exp.json @@ -59,6 +59,7 @@ "currentBaseFee": "0x7", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "currentExcessBlobGas": "0x0", - "blobGasUsed": "0x0" + "blobGasUsed": "0x0", + "requests": null } -} \ No newline at end of file +} diff --git a/cmd/evm/testdata/33/README.md b/cmd/evm/testdata/33/README.md new file mode 100644 index 000000000..24bea566e --- /dev/null +++ b/cmd/evm/testdata/33/README.md @@ -0,0 +1 @@ +This test sets some EIP-7702 delegations and calls them. diff --git a/cmd/evm/testdata/33/alloc.json b/cmd/evm/testdata/33/alloc.json new file mode 100644 index 000000000..6874a6b33 --- /dev/null +++ b/cmd/evm/testdata/33/alloc.json @@ -0,0 +1,30 @@ +{ + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "nonce": "0x00", + "balance": "0x0de0b6b3a7640000", + "code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355", + "storage": { + "0x01": "0x0100", + "0x02": "0x0100", + "0x03": "0x0100" + } + }, + "0x000000000000000000000000000000000000aaaa": { + "nonce": "0x00", + "balance": "0x4563918244f40000", + "code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100", + "storage": {} + }, + "0x000000000000000000000000000000000000bbbb": { + "nonce": "0x00", + "balance": "0x29a2241af62c0000", + "code": "0x6042805500", + "storage": {} + }, + "0x71562b71999873DB5b286dF957af199Ec94617F7": { + "nonce": "0x00", + "balance": "0x6124fee993bc0000", + "code": "0x", + "storage": {} + } +} diff --git a/cmd/evm/testdata/33/env.json b/cmd/evm/testdata/33/env.json new file mode 100644 index 000000000..70bb7f981 --- /dev/null +++ b/cmd/evm/testdata/33/env.json @@ -0,0 +1,14 @@ +{ + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "71794957647893862", + "currentNumber": "1", + "currentTimestamp": "1000", + "currentRandom": "0", + "currentDifficulty": "0", + "blockHashes": {}, + "ommers": [], + "currentBaseFee": "7", + "parentUncleHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "withdrawals": [], + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/cmd/evm/testdata/33/exp.json b/cmd/evm/testdata/33/exp.json new file mode 100644 index 000000000..ae82ef3ef --- /dev/null +++ b/cmd/evm/testdata/33/exp.json @@ -0,0 +1,62 @@ +{ + "alloc": { + "0x000000000000000000000000000000000000aaaa": { + "code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100", + "balance": "0x4563918244f40000" + }, + "0x000000000000000000000000000000000000bbbb": { + "code": "0x6042805500", + "balance": "0x29a2241af62c0000" + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x2bf52" + }, + "0x703c4b2bd70c169f5717101caee543299fc946c7": { + "code": "0xef0100000000000000000000000000000000000000bbbb", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000042": "0x0000000000000000000000000000000000000000000000000000000000000042" + }, + "balance": "0x1", + "nonce": "0x1" + }, + "0x71562b71999873db5b286df957af199ec94617f7": { + "code": "0xef0100000000000000000000000000000000000000aaaa", + "balance": "0x6124fee993afa30e", + "nonce": "0x2" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000100" + }, + "balance": "0xde0b6b3a7640000" + } + }, + "result": { + "stateRoot": "0x9fdcacd4510e93c4488e537dc51578b5c6d505771db64a2610036eeb4be7b26f", + "txRoot": "0x5d13a0b074e80388dc754da92b22922313a63417b3e25a10f324935e09697a53", + "receiptsRoot": "0x504c5d86c34391f70d210e6c482615b391db4bdb9f43479366399d9c5599850a", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","receipts": [{ + "type": "0x4", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x15fa9", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","logs": null,"transactionHash": "0x0417aab7c1d8a3989190c3167c132876ce9b8afd99262c5a0f9d06802de3d7ef", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15fa9", + "effectiveGasPrice": null, + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x15fa9", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "requests": [] +} +} diff --git a/cmd/evm/testdata/33/txs.json b/cmd/evm/testdata/33/txs.json new file mode 100644 index 000000000..9c4db138c --- /dev/null +++ b/cmd/evm/testdata/33/txs.json @@ -0,0 +1,37 @@ +[ + { + "type": "0x4", + "chainId": "0x1", + "nonce": "0x0", + "to": "0x71562b71999873db5b286df957af199ec94617f7", + "gas": "0x7a120", + "gasPrice": null, + "maxPriorityFeePerGas": "0x2", + "maxFeePerGas": "0x12a05f200", + "value": "0x0", + "input": "0x", + "accessList": [], + "authorizationList": [ + { + "chainId": "0x1", + "address": "0x000000000000000000000000000000000000aaaa", + "nonce": "0x1", + "v": "0x1", + "r": "0xf7e3e597fc097e71ed6c26b14b25e5395bc8510d58b9136af439e12715f2d721", + "s": "0x6cf7c3d7939bfdb784373effc0ebb0bd7549691a513f395e3cdabf8602724987" + }, + { + "chainId": "0x0", + "address": "0x000000000000000000000000000000000000bbbb", + "nonce": "0x0", + "v": "0x1", + "r": "0x5011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98", + "s": "0x56c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf61" + } + ], + "secretKey": "0xb71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291", + "v": "0x0", + "r": "0x0", + "s": "0x0" + } +] diff --git a/cmd/evm/testdata/5/exp.json b/cmd/evm/testdata/5/exp.json index 7d715672c..00af8b084 100644 --- a/cmd/evm/testdata/5/exp.json +++ b/cmd/evm/testdata/5/exp.json @@ -18,6 +18,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], "currentDifficulty": "0x20000", - "gasUsed": "0x0" + "gasUsed": "0x0", + "requests": null } } diff --git a/core/bench_test.go b/core/bench_test.go index b7713af89..9f7c525f0 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -90,7 +90,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { data := make([]byte, nbytes) return func(i int, gen *BlockGen) { toaddr := common.Address{} - gas, _ := IntrinsicGas(data, nil, false, false, false, false) + gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false) signer := gen.Signer() gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index faea5047c..25899ad8e 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "errors" "fmt" gomath "math" @@ -36,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/vm/program" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/ethdb" @@ -4236,3 +4238,95 @@ func TestPragueRequests(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } } + +// TestEIP7702 deploys two delegation designations and calls them. It writes one +// value to storage which is verified after. +func TestEIP7702(t *testing.T) { + var ( + config = *params.MergedTestChainConfig + signer = types.LatestSigner(&config) + engine = beacon.NewFaker() + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + ) + gspec := &Genesis{ + Config: &config, + Alloc: types.GenesisAlloc{ + addr1: {Balance: funds}, + addr2: {Balance: funds}, + aa: { // The address 0xAAAA calls into addr2 + Code: program.New().Call(nil, addr2, 1, 0, 0, 0, 0).Bytes(), + Nonce: 0, + Balance: big.NewInt(0), + }, + bb: { // The address 0xBBBB sstores 42 into slot 42. + Code: program.New().Sstore(0x42, 0x42).Bytes(), + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + + // Sign authorization tuples. + // The way the auths are combined, it becomes + // 1. tx -> addr1 which is delegated to 0xaaaa + // 2. addr1:0xaaaa calls into addr2:0xbbbb + // 3. addr2:0xbbbb writes to storage + auth1, _ := types.SignAuth(types.Authorization{ + ChainID: gspec.Config.ChainID.Uint64(), + Address: aa, + Nonce: 1, + }, key1) + auth2, _ := types.SignAuth(types.Authorization{ + ChainID: 0, + Address: bb, + Nonce: 0, + }, key2) + + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + b.SetCoinbase(aa) + txdata := &types.SetCodeTx{ + ChainID: gspec.Config.ChainID.Uint64(), + Nonce: 0, + To: addr1, + Gas: 500000, + GasFeeCap: uint256.MustFromBig(newGwei(5)), + GasTipCap: uint256.NewInt(2), + AuthList: []types.Authorization{auth1, auth2}, + } + tx := types.MustSignNewTx(key1, signer, txdata) + b.AddTx(tx) + }) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + // Verify delegation designations were deployed. + state, _ := chain.State() + code, want := state.GetCode(addr1), types.AddressToDelegation(auth1.Address) + if !bytes.Equal(code, want) { + t.Fatalf("addr1 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want)) + } + code, want = state.GetCode(addr2), types.AddressToDelegation(auth2.Address) + if !bytes.Equal(code, want) { + t.Fatalf("addr2 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want)) + } + // Verify delegation executed the correct code. + var ( + fortyTwo = common.BytesToHash([]byte{0x42}) + actual = state.GetState(addr2, fortyTwo) + ) + if actual.Cmp(fortyTwo) != 0 { + t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual) + } +} diff --git a/core/error.go b/core/error.go index 50705feb3..7dbe6756a 100644 --- a/core/error.go +++ b/core/error.go @@ -107,6 +107,8 @@ var ( // ErrSenderNoEOA is returned if the sender of a transaction is a contract. ErrSenderNoEOA = errors.New("sender not an eoa") + // -- EIP-4844 errors -- + // ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the // blob gas fee of the block. ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee") @@ -117,6 +119,25 @@ var ( // ErrBlobTxCreate is returned if a blob transaction has no explicit to field. ErrBlobTxCreate = errors.New("blob transaction of type create") + // -- EIP-7702 errors -- + + // Message validation errors: + ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list") + ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract") +) + +// EIP-7702 state transition errors. +// Note these are just informational, and do not cause tx execution abort. +var ( + ErrAuthorizationWrongChainID = errors.New("EIP-7702 authorization chain ID mismatch") + ErrAuthorizationNonceOverflow = errors.New("EIP-7702 authorization nonce > 64 bit") + ErrAuthorizationInvalidSignature = errors.New("EIP-7702 authorization has invalid signature") + ErrAuthorizationDestinationHasCode = errors.New("EIP-7702 authorization destination is a contract") + ErrAuthorizationNonceMismatch = errors.New("EIP-7702 authorization nonce does not match current account nonce") +) + +// DBFT +var ( // ErrBlockedSender is returned if the transaction sender is blocked by policy. ErrBlockedSender = errors.New("blocked sender") diff --git a/core/state/journal.go b/core/state/journal.go index a2fea6b6e..13332dbd7 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -23,7 +23,7 @@ import ( "sort" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" ) @@ -192,8 +192,11 @@ func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) { }) } -func (j *journal) setCode(address common.Address) { - j.append(codeChange{account: address}) +func (j *journal) setCode(address common.Address, prevCode []byte) { + j.append(codeChange{ + account: address, + prevCode: prevCode, + }) } func (j *journal) nonceChange(address common.Address, prev uint64) { @@ -256,7 +259,8 @@ type ( origvalue common.Hash } codeChange struct { - account common.Address + account common.Address + prevCode []byte } // Changes to other state values. @@ -377,7 +381,7 @@ func (ch nonceChange) copy() journalEntry { } func (ch codeChange) revert(s *StateDB) { - s.getStateObject(ch.account).setCode(types.EmptyCodeHash, nil) + s.getStateObject(ch.account).setCode(crypto.Keccak256Hash(ch.prevCode), ch.prevCode) } func (ch codeChange) dirtied() *common.Address { @@ -385,7 +389,10 @@ func (ch codeChange) dirtied() *common.Address { } func (ch codeChange) copy() journalEntry { - return codeChange{account: ch.account} + return codeChange{ + account: ch.account, + prevCode: ch.prevCode, + } } func (ch storageChange) revert(s *StateDB) { diff --git a/core/state/state_object.go b/core/state/state_object.go index 2d542e500..76a3aba92 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "maps" + "slices" "time" "github.com/ethereum/go-ethereum/common" @@ -541,9 +542,11 @@ func (s *stateObject) CodeSize() int { return size } -func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { - s.db.journal.setCode(s.address) +func (s *stateObject) SetCode(codeHash common.Hash, code []byte) (prev []byte) { + prev = slices.Clone(s.code) + s.db.journal.setCode(s.address, prev) s.setCode(codeHash, code) + return prev } func (s *stateObject) setCode(codeHash common.Hash, code []byte) { diff --git a/core/state/statedb.go b/core/state/statedb.go index b0603db7f..d279ccfdf 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -439,11 +439,12 @@ func (s *StateDB) SetNonce(addr common.Address, nonce uint64) { } } -func (s *StateDB) SetCode(addr common.Address, code []byte) { +func (s *StateDB) SetCode(addr common.Address, code []byte) (prev []byte) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { - stateObject.SetCode(crypto.Keccak256Hash(code), code) + return stateObject.SetCode(crypto.Keccak256Hash(code), code) } + return nil } func (s *StateDB) SetState(addr common.Address, key, value common.Hash) common.Hash { diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 26d021709..31bdd06b4 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -182,11 +182,16 @@ func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64) { } } -func (s *hookedStateDB) SetCode(address common.Address, code []byte) { - s.inner.SetCode(address, code) +func (s *hookedStateDB) SetCode(address common.Address, code []byte) []byte { + prev := s.inner.SetCode(address, code) if s.hooks.OnCodeChange != nil { - s.hooks.OnCodeChange(address, types.EmptyCodeHash, nil, crypto.Keccak256Hash(code), code) + prevHash := types.EmptyCodeHash + if len(prev) != 0 { + prevHash = crypto.Keccak256Hash(prev) + } + s.hooks.OnCodeChange(address, prevHash, prev, crypto.Keccak256Hash(code), code) } + return prev } func (s *hookedStateDB) SetState(address common.Address, key common.Hash, value common.Hash) common.Hash { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7118d7d22..ec2823b3f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -63,6 +63,7 @@ func TestStateProcessorErrors(t *testing.T) { TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: new(uint64), CancunTime: new(uint64), + PragueTime: new(uint64), } signer = types.LatestSigner(config) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -110,6 +111,21 @@ func TestStateProcessorErrors(t *testing.T) { } return tx } + var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.Authorization) *types.Transaction { + tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{ + Nonce: nonce, + GasTipCap: uint256.MustFromBig(gasTipCap), + GasFeeCap: uint256.MustFromBig(gasFeeCap), + Gas: gasLimit, + To: to, + Value: new(uint256.Int), + AuthList: authlist, + }), signer, key1) + if err != nil { + t.Fatal(err) + } + return tx + } { // Tests against a 'recent' chain definition var ( @@ -251,6 +267,13 @@ func TestStateProcessorErrors(t *testing.T) { }, want: "could not apply tx 0 [0x6c11015985ce82db691d7b2d017acda296db88b811c3c60dc71449c76256c716]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 1, baseFee: 875000000", }, + { // ErrEmptyAuthList + txs: []*types.Transaction{ + mkSetCodeTx(0, common.Address{}, params.TxGas, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), nil), + }, + want: "could not apply tx 0 [0xc18d10f4c809dbdfa1a074c3300de9bc4b7f16a20f0ec667f6f67312b71b956a]: EIP-7702 transaction with empty auth list (sender 0x71562b71999873DB5b286dF957af199Ec94617F7)", + }, + // ErrSetCodeTxCreate cannot be tested: it is impossible to create a SetCode-tx with nil `to`. } { block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config, false) _, err := blockchain.InsertChain(types.Blocks{block}) @@ -337,7 +360,7 @@ func TestStateProcessorErrors(t *testing.T) { txs: []*types.Transaction{ mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), }, - want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1", + want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, len(code): 4", }, } { block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config, false) diff --git a/core/state_transition.go b/core/state_transition.go index dffba76dc..a98024086 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -69,7 +69,7 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Authorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -115,6 +115,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation, gas += uint64(len(accessList)) * params.TxAccessListAddressGas gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas } + if authList != nil { + gas += uint64(len(authList)) * params.CallNewAccountGas + } return gas, nil } @@ -142,6 +145,7 @@ type Message struct { AccessList types.AccessList BlobGasFeeCap *big.Int BlobHashes []common.Hash + AuthList []types.Authorization // When SkipNonceChecks is true, the message nonce is not checked against the // account nonce in state. @@ -164,6 +168,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In Value: tx.Value(), Data: tx.Data(), AccessList: tx.AccessList(), + AuthList: tx.AuthList(), SkipNonceChecks: false, SkipFromEOACheck: false, BlobHashes: tx.BlobHashes(), @@ -305,10 +310,10 @@ func (st *stateTransition) preCheck() error { } if !msg.SkipFromEOACheck { // Make sure the sender is an EOA - codeHash := st.state.GetCodeHash(msg.From) - if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash { - return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, - msg.From.Hex(), codeHash) + code := st.state.GetCode(msg.From) + _, delegated := types.ParseDelegation(code) + if len(code) > 0 && !delegated { + return fmt.Errorf("%w: address %v, len(code): %d", ErrSenderNoEOA, msg.From.Hex(), len(code)) } // Apply policy blacklist var blocked = st.state.GetState(systemcontracts.PolicyProxyHash, systemcontracts.GetBlackListStateHash(msg.From)) @@ -406,6 +411,15 @@ func (st *stateTransition) preCheck() error { } } } + // Check that EIP-7702 authorization list signatures are well formed. + if msg.AuthList != nil { + if msg.To == nil { + return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From) + } + if len(msg.AuthList) == 0 { + return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From) + } + } return st.buyGas() } @@ -443,7 +457,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.AuthList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } @@ -489,8 +503,27 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if contractCreation { ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value) } else { - // Increment the nonce for the next transaction - st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1) + // Increment the nonce for the next transaction. + st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1) + + // Apply EIP-7702 authorizations. + if msg.AuthList != nil { + for _, auth := range msg.AuthList { + // Note errors are ignored, we simply skip invalid authorizations here. + st.applyAuthorization(msg, &auth) + } + } + + // Perform convenience warming of sender's delegation target. Although the + // sender is already warmed in Prepare(..), it's possible a delegation to + // the account was deployed during this transaction. To handle correctly, + // simply wait until the final state of delegations is determined before + // performing the resolution and warming. + if addr, ok := types.ParseDelegation(st.state.GetCode(*msg.To)); ok { + st.state.AddAddressToAccessList(addr) + } + + // Execute the transaction's call. ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value) } @@ -534,6 +567,64 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { }, nil } +// validateAuthorization validates an EIP-7702 authorization against the state. +func (st *stateTransition) validateAuthorization(auth *types.Authorization) (authority common.Address, err error) { + // Verify chain ID is 0 or equal to current chain ID. + if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { + return authority, ErrAuthorizationWrongChainID + } + // Limit nonce to 2^64-1 per EIP-2681. + if auth.Nonce+1 < auth.Nonce { + return authority, ErrAuthorizationNonceOverflow + } + // Validate signature values and recover authority. + authority, err = auth.Authority() + if err != nil { + return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err) + } + // Check the authority account + // 1) doesn't have code or has exisiting delegation + // 2) matches the auth's nonce + // + // Note it is added to the access list even if the authorization is invalid. + st.state.AddAddressToAccessList(authority) + code := st.state.GetCode(authority) + if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok { + return authority, ErrAuthorizationDestinationHasCode + } + if have := st.state.GetNonce(authority); have != auth.Nonce { + return authority, ErrAuthorizationNonceMismatch + } + return authority, nil +} + +// applyAuthorization applies an EIP-7702 code delegation to the state. +func (st *stateTransition) applyAuthorization(msg *Message, auth *types.Authorization) error { + authority, err := st.validateAuthorization(auth) + if err != nil { + return err + } + + // If the account already exists in state, refund the new account cost + // charged in the intrinsic calculation. + if st.state.Exist(authority) { + st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas) + } + + // Update nonce and account code. + st.state.SetNonce(authority, auth.Nonce+1) + if auth.Address == (common.Address{}) { + // Delegation to zero address means clear. + st.state.SetCode(authority, nil) + return nil + } + + // Otherwise install delegation to auth.Address. + st.state.SetCode(authority, types.AddressToDelegation(auth.Address)) + + return nil +} + func (st *stateTransition) refundGas(refundQuotient uint64) uint64 { // Apply refund counter, capped to a refund quotient refund := st.gasUsed() / refundQuotient diff --git a/core/txpool/validation.go b/core/txpool/validation.go index bf2a0aae6..70b2ca89a 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -110,7 +110,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) if err != nil { return err } diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go new file mode 100644 index 000000000..b598b64ff --- /dev/null +++ b/core/types/gen_authorization.go @@ -0,0 +1,75 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/holiman/uint256" +) + +var _ = (*authorizationMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (a Authorization) MarshalJSON() ([]byte, error) { + type Authorization struct { + ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` + Address common.Address `json:"address" gencodec:"required"` + Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` + V hexutil.Uint64 `json:"v" gencodec:"required"` + R uint256.Int `json:"r" gencodec:"required"` + S uint256.Int `json:"s" gencodec:"required"` + } + var enc Authorization + enc.ChainID = hexutil.Uint64(a.ChainID) + enc.Address = a.Address + enc.Nonce = hexutil.Uint64(a.Nonce) + enc.V = hexutil.Uint64(a.V) + enc.R = a.R + enc.S = a.S + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (a *Authorization) UnmarshalJSON(input []byte) error { + type Authorization struct { + ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` + Address *common.Address `json:"address" gencodec:"required"` + Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` + V *hexutil.Uint64 `json:"v" gencodec:"required"` + R *uint256.Int `json:"r" gencodec:"required"` + S *uint256.Int `json:"s" gencodec:"required"` + } + var dec Authorization + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' for Authorization") + } + a.ChainID = uint64(*dec.ChainID) + if dec.Address == nil { + return errors.New("missing required field 'address' for Authorization") + } + a.Address = *dec.Address + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' for Authorization") + } + a.Nonce = uint64(*dec.Nonce) + if dec.V == nil { + return errors.New("missing required field 'v' for Authorization") + } + a.V = uint8(*dec.V) + if dec.R == nil { + return errors.New("missing required field 'r' for Authorization") + } + a.R = *dec.R + if dec.S == nil { + return errors.New("missing required field 's' for Authorization") + } + a.S = *dec.S + return nil +} diff --git a/core/types/receipt.go b/core/types/receipt.go index 4f96fde59..47f16d950 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -204,7 +204,7 @@ func (r *Receipt) decodeTyped(b []byte) error { return errShortTypedReceipt } switch b[0] { - case DynamicFeeTxType, AccessListTxType, BlobTxType: + case DynamicFeeTxType, AccessListTxType, BlobTxType, SetCodeTxType: var data receiptRLP err := rlp.DecodeBytes(b[1:], &data) if err != nil { @@ -312,7 +312,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { } w.WriteByte(r.Type) switch r.Type { - case AccessListTxType, DynamicFeeTxType, BlobTxType: + case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType: rlp.Encode(w, data) default: // For unsupported types, write nothing. Since this is for diff --git a/core/types/transaction.go b/core/types/transaction.go index ea6f5ad6b..b5fb3e2db 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -48,6 +48,7 @@ const ( AccessListTxType = 0x01 DynamicFeeTxType = 0x02 BlobTxType = 0x03 + SetCodeTxType = 0x04 ) // Transaction is an Ethereum transaction. @@ -205,6 +206,8 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { inner = new(DynamicFeeTx) case BlobTxType: inner = new(BlobTx) + case SetCodeTxType: + inner = new(SetCodeTx) default: return nil, ErrTxTypeNotSupported } @@ -471,6 +474,15 @@ func (tx *Transaction) WithBlobTxSidecar(sideCar *BlobTxSidecar) *Transaction { return cpy } +// AuthList returns the authorizations list of the transaction. +func (tx *Transaction) AuthList() []Authorization { + setcodetx, ok := tx.inner.(*SetCodeTx) + if !ok { + return nil + } + return setcodetx.AuthList +} + // SetTime sets the decoding time of a transaction. This is used by tests to set // arbitrary times and by persistent transaction pools when loading old txs from // disk. diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 4d5b2bcdd..4176a8220 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -43,6 +43,7 @@ type txJSON struct { Input *hexutil.Bytes `json:"input"` AccessList *AccessList `json:"accessList,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + AuthorizationList []Authorization `json:"authorizationList,omitempty"` V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` @@ -153,6 +154,22 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.Commitments = itx.Sidecar.Commitments enc.Proofs = itx.Sidecar.Proofs } + case *SetCodeTx: + enc.ChainID = (*hexutil.Big)(new(big.Int).SetUint64(itx.ChainID)) + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig()) + enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig()) + enc.Value = (*hexutil.Big)(itx.Value.ToBig()) + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.AccessList = &itx.AccessList + enc.AuthorizationList = itx.AuthList + enc.V = (*hexutil.Big)(itx.V.ToBig()) + enc.R = (*hexutil.Big)(itx.R.ToBig()) + enc.S = (*hexutil.Big)(itx.S.ToBig()) + yparity := itx.V.Uint64() + enc.YParity = (*hexutil.Uint64)(&yparity) } return json.Marshal(&enc) } @@ -409,6 +426,81 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } } + case SetCodeTxType: + var itx SetCodeTx + inner = &itx + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' in transaction") + } + itx.ChainID = dec.ChainID.ToInt().Uint64() + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' in transaction") + } + itx.Nonce = uint64(*dec.Nonce) + if dec.To == nil { + return errors.New("missing required field 'to' in transaction") + } + itx.To = *dec.To + if dec.Gas == nil { + return errors.New("missing required field 'gas' for txdata") + } + itx.Gas = uint64(*dec.Gas) + if dec.MaxPriorityFeePerGas == nil { + return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") + } + itx.GasTipCap = uint256.MustFromBig((*big.Int)(dec.MaxPriorityFeePerGas)) + if dec.MaxFeePerGas == nil { + return errors.New("missing required field 'maxFeePerGas' for txdata") + } + itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas)) + if dec.Value == nil { + return errors.New("missing required field 'value' in transaction") + } + itx.Value = uint256.MustFromBig((*big.Int)(dec.Value)) + if dec.Input == nil { + return errors.New("missing required field 'input' in transaction") + } + itx.Data = *dec.Input + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } + if dec.AuthorizationList == nil { + return errors.New("missing required field 'authorizationList' in transaction") + } + itx.AuthList = dec.AuthorizationList + + // signature R + var overflow bool + if dec.R == nil { + return errors.New("missing required field 'r' in transaction") + } + itx.R, overflow = uint256.FromBig((*big.Int)(dec.R)) + if overflow { + return errors.New("'r' value overflows uint256") + } + // signature S + if dec.S == nil { + return errors.New("missing required field 's' in transaction") + } + itx.S, overflow = uint256.FromBig((*big.Int)(dec.S)) + if overflow { + return errors.New("'s' value overflows uint256") + } + // signature V + vbig, err := dec.yParityValue() + if err != nil { + return err + } + itx.V, overflow = uint256.FromBig(vbig) + if overflow { + return errors.New("'v' value overflows uint256") + } + if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { + if err := sanityCheckSignature(vbig, itx.R.ToBig(), itx.S.ToBig(), false); err != nil { + return err + } + } + default: return ErrTxTypeNotSupported } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 73011e238..78fa2fc8e 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,6 +40,8 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { + case config.IsPrague(blockNumber, blockTime): + signer = NewPragueSigner(config.ChainID) case config.IsCancun(blockNumber, blockTime): signer = NewCancunSigner(config.ChainID) case config.IsLondon(blockNumber): @@ -67,6 +69,8 @@ func LatestSigner(config *params.ChainConfig) Signer { var signer Signer if config.ChainID != nil { switch { + case config.PragueTime != nil: + signer = NewPragueSigner(config.ChainID) case config.CancunTime != nil: signer = NewCancunSigner(config.ChainID) case config.LondonBlock != nil: @@ -94,7 +98,7 @@ func LatestSigner(config *params.ChainConfig) Signer { func LatestSignerForChainID(chainID *big.Int) Signer { var signer Signer if chainID != nil { - signer = NewCancunSigner(chainID) + signer = NewPragueSigner(chainID) } else { signer = HomesteadSigner{} } @@ -174,6 +178,77 @@ type Signer interface { Equal(Signer) bool } +type pragueSigner struct{ cancunSigner } + +// NewPragueSigner returns a signer that accepts +// - EIP-7702 set code transactions +// - EIP-4844 blob transactions +// - EIP-1559 dynamic fee transactions +// - EIP-2930 access list transactions, +// - EIP-155 replay protected transactions, and +// - legacy Homestead transactions. +func NewPragueSigner(chainId *big.Int) Signer { + signer, _ := NewCancunSigner(chainId).(cancunSigner) + return pragueSigner{signer} +} + +func (s pragueSigner) Sender(tx *Transaction) (common.Address, error) { + if tx.Type() != SetCodeTxType { + return s.cancunSigner.Sender(tx) + } + V, R, S := tx.RawSignatureValues() + + // Set code txs are defined to use 0 and 1 as their recovery + // id, add 27 to become equivalent to unprotected Homestead signatures. + V = new(big.Int).Add(V, big.NewInt(27)) + if tx.ChainId().Cmp(s.chainId) != 0 { + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) + } + return recoverPlain(s.Hash(tx), R, S, V, true) +} + +func (s pragueSigner) Equal(s2 Signer) bool { + x, ok := s2.(pragueSigner) + return ok && x.chainId.Cmp(s.chainId) == 0 +} + +func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { + txdata, ok := tx.inner.(*SetCodeTx) + if !ok { + return s.cancunSigner.SignatureValues(tx, sig) + } + // Check that chain ID of tx matches the signer. We also accept ID zero here, + // because it indicates that the chain ID was not specified in the tx. + if txdata.ChainID != 0 && new(big.Int).SetUint64(txdata.ChainID).Cmp(s.chainId) != 0 { + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) + } + R, S, _ = decodeSignature(sig) + V = big.NewInt(int64(sig[64])) + return R, S, V, nil +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s pragueSigner) Hash(tx *Transaction) common.Hash { + if tx.Type() != SetCodeTxType { + return s.cancunSigner.Hash(tx) + } + return prefixedRlpHash( + tx.Type(), + []interface{}{ + s.chainId, + tx.Nonce(), + tx.GasTipCap(), + tx.GasFeeCap(), + tx.Gas(), + tx.To(), + tx.Value(), + tx.Data(), + tx.AccessList(), + tx.AuthList(), + }) +} + type cancunSigner struct{ londonSigner } // NewCancunSigner returns a signer that accepts diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go new file mode 100644 index 000000000..0fea9a63a --- /dev/null +++ b/core/types/tx_setcode.go @@ -0,0 +1,226 @@ +// Copyright 2024 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 . + +package types + +import ( + "bytes" + "crypto/ecdsa" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" +) + +// DelegationPrefix is used by code to denote the account is delegating to +// another account. +var DelegationPrefix = []byte{0xef, 0x01, 0x00} + +// ParseDelegation tries to parse the address from a delegation slice. +func ParseDelegation(b []byte) (common.Address, bool) { + if len(b) != 23 || !bytes.HasPrefix(b, DelegationPrefix) { + return common.Address{}, false + } + return common.BytesToAddress(b[len(DelegationPrefix):]), true +} + +// AddressToDelegation adds the delegation prefix to the specified address. +func AddressToDelegation(addr common.Address) []byte { + return append(DelegationPrefix, addr.Bytes()...) +} + +// SetCodeTx implements the EIP-7702 transaction type which temporarily installs +// the code at the signer's address. +type SetCodeTx struct { + ChainID uint64 + Nonce uint64 + GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas + GasFeeCap *uint256.Int // a.k.a. maxFeePerGas + Gas uint64 + To common.Address + Value *uint256.Int + Data []byte + AccessList AccessList + AuthList []Authorization + + // Signature values + V *uint256.Int `json:"v" gencodec:"required"` + R *uint256.Int `json:"r" gencodec:"required"` + S *uint256.Int `json:"s" gencodec:"required"` +} + +//go:generate go run github.com/fjl/gencodec -type Authorization -field-override authorizationMarshaling -out gen_authorization.go + +// Authorization is an authorization from an account to deploy code at its address. +type Authorization struct { + ChainID uint64 `json:"chainId" gencodec:"required"` + Address common.Address `json:"address" gencodec:"required"` + Nonce uint64 `json:"nonce" gencodec:"required"` + V uint8 `json:"v" gencodec:"required"` + R uint256.Int `json:"r" gencodec:"required"` + S uint256.Int `json:"s" gencodec:"required"` +} + +// field type overrides for gencodec +type authorizationMarshaling struct { + ChainID hexutil.Uint64 + Nonce hexutil.Uint64 + V hexutil.Uint64 +} + +// SignAuth signs the provided authorization. +func SignAuth(auth Authorization, prv *ecdsa.PrivateKey) (Authorization, error) { + sighash := auth.sigHash() + sig, err := crypto.Sign(sighash[:], prv) + if err != nil { + return Authorization{}, err + } + return auth.withSignature(sig), nil +} + +// withSignature updates the signature of an Authorization to be equal the +// decoded signature provided in sig. +func (a *Authorization) withSignature(sig []byte) Authorization { + r, s, _ := decodeSignature(sig) + return Authorization{ + ChainID: a.ChainID, + Address: a.Address, + Nonce: a.Nonce, + V: sig[64], + R: *uint256.MustFromBig(r), + S: *uint256.MustFromBig(s), + } +} + +func (a *Authorization) sigHash() common.Hash { + return prefixedRlpHash(0x05, []any{ + a.ChainID, + a.Address, + a.Nonce, + }) +} + +// Authority recovers the the authorizing account of an authorization. +func (a *Authorization) Authority() (common.Address, error) { + sighash := a.sigHash() + if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) { + return common.Address{}, ErrInvalidSig + } + // encode the signature in uncompressed format + var sig [crypto.SignatureLength]byte + a.R.WriteToSlice(sig[:32]) + a.S.WriteToSlice(sig[32:64]) + sig[64] = a.V + // recover the public key from the signature + pub, err := crypto.Ecrecover(sighash[:], sig[:]) + if err != nil { + return common.Address{}, err + } + if len(pub) == 0 || pub[0] != 4 { + return common.Address{}, errors.New("invalid public key") + } + var addr common.Address + copy(addr[:], crypto.Keccak256(pub[1:])[12:]) + return addr, nil +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx *SetCodeTx) copy() TxData { + cpy := &SetCodeTx{ + Nonce: tx.Nonce, + To: tx.To, + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + // These are copied below. + AccessList: make(AccessList, len(tx.AccessList)), + AuthList: make([]Authorization, len(tx.AuthList)), + Value: new(uint256.Int), + ChainID: tx.ChainID, + GasTipCap: new(uint256.Int), + GasFeeCap: new(uint256.Int), + V: new(uint256.Int), + R: new(uint256.Int), + S: new(uint256.Int), + } + copy(cpy.AccessList, tx.AccessList) + copy(cpy.AuthList, tx.AuthList) + if tx.Value != nil { + cpy.Value.Set(tx.Value) + } + if tx.GasTipCap != nil { + cpy.GasTipCap.Set(tx.GasTipCap) + } + if tx.GasFeeCap != nil { + cpy.GasFeeCap.Set(tx.GasFeeCap) + } + if tx.V != nil { + cpy.V.Set(tx.V) + } + if tx.R != nil { + cpy.R.Set(tx.R) + } + if tx.S != nil { + cpy.S.Set(tx.S) + } + return cpy +} + +// accessors for innerTx. +func (tx *SetCodeTx) txType() byte { return SetCodeTxType } +func (tx *SetCodeTx) chainID() *big.Int { return big.NewInt(int64(tx.ChainID)) } +func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList } +func (tx *SetCodeTx) data() []byte { return tx.Data } +func (tx *SetCodeTx) gas() uint64 { return tx.Gas } +func (tx *SetCodeTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *SetCodeTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() } +func (tx *SetCodeTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() } +func (tx *SetCodeTx) value() *big.Int { return tx.Value.ToBig() } +func (tx *SetCodeTx) nonce() uint64 { return tx.Nonce } +func (tx *SetCodeTx) to() *common.Address { tmp := tx.To; return &tmp } + +func (tx *SetCodeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + if baseFee == nil { + return dst.Set(tx.GasFeeCap.ToBig()) + } + tip := dst.Sub(tx.GasFeeCap.ToBig(), baseFee) + if tip.Cmp(tx.GasTipCap.ToBig()) > 0 { + tip.Set(tx.GasTipCap.ToBig()) + } + return tip.Add(tip, baseFee) +} + +func (tx *SetCodeTx) rawSignatureValues() (v, r, s *big.Int) { + return tx.V.ToBig(), tx.R.ToBig(), tx.S.ToBig() +} + +func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) { + tx.ChainID = chainID.Uint64() + tx.V.SetFromBig(v) + tx.R.SetFromBig(r) + tx.S.SetFromBig(s) +} + +func (tx *SetCodeTx) encode(b *bytes.Buffer) error { + return rlp.Encode(b, tx) +} + +func (tx *SetCodeTx) decode(input []byte) error { + return rlp.DecodeBytes(input, tx) +} diff --git a/core/types/tx_setcode_test.go b/core/types/tx_setcode_test.go new file mode 100644 index 000000000..d0544573c --- /dev/null +++ b/core/types/tx_setcode_test.go @@ -0,0 +1,70 @@ +// Copyright 2024 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 . + +package types + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// TestParseDelegation tests a few possible delegation designator values and +// ensures they are parsed correctly. +func TestParseDelegation(t *testing.T) { + addr := common.Address{0x42} + for _, tt := range []struct { + val []byte + want *common.Address + }{ + { // simple correct delegation + val: append(DelegationPrefix, addr.Bytes()...), + want: &addr, + }, + { // wrong address size + val: append(DelegationPrefix, addr.Bytes()[0:19]...), + }, + { // short address + val: append(DelegationPrefix, 0x42), + }, + { // long address + val: append(append(DelegationPrefix, addr.Bytes()...), 0x42), + }, + { // wrong prefix size + val: append(DelegationPrefix[:2], addr.Bytes()...), + }, + { // wrong prefix + val: append([]byte{0xef, 0x01, 0x01}, addr.Bytes()...), + }, + { // wrong prefix + val: append([]byte{0xef, 0x00, 0x00}, addr.Bytes()...), + }, + { // no prefix + val: addr.Bytes(), + }, + { // no address + val: DelegationPrefix, + }, + } { + got, ok := ParseDelegation(tt.val) + if ok && tt.want == nil { + t.Fatalf("expected fail, got %s", got.Hex()) + } + if !ok && tt.want != nil { + t.Fatalf("failed to parse, want %s", tt.want.Hex()) + } + } +} diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index f5aa579fd..c8938c9c6 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -83,12 +83,12 @@ var ( func TestProcessVerkle(t *testing.T) { var ( code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) - intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, true, true, true, true) + intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true) // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness // will not contain that copied data. // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) - intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, true, true, true, true) + intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) signer = types.LatestSigner(testVerkleChainConfig) testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain diff --git a/core/vm/eips.go b/core/vm/eips.go index 71d51f81e..a51a18dc6 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -23,6 +23,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -40,6 +42,7 @@ var activators = map[int]func(*JumpTable){ 1344: enable1344, 1153: enable1153, 4762: enable4762, + 7702: enable7702, } // EnableEIP enables the given EIP on the config. @@ -703,3 +706,68 @@ func enableEOF(jt *JumpTable) { memorySize: memoryExtCall, } } + +// opExtCodeCopyEIP7702 implements the EIP-7702 variation of opExtCodeCopy. +func opExtCodeCopyEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + stack = scope.Stack + a = stack.pop() + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() + ) + uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() + if overflow { + uint64CodeOffset = math.MaxUint64 + } + code := interpreter.evm.StateDB.GetCode(common.Address(a.Bytes20())) + if _, ok := types.ParseDelegation(code); ok { + code = types.DelegationPrefix[:2] + } + codeCopy := getData(code, uint64CodeOffset, length.Uint64()) + scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + + return nil, nil +} + +// opExtCodeSizeEIP7702 implements the EIP-7702 variation of opExtCodeSize. +func opExtCodeSizeEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + slot := scope.Stack.peek() + code := interpreter.evm.StateDB.GetCode(common.Address(slot.Bytes20())) + if _, ok := types.ParseDelegation(code); ok { + code = types.DelegationPrefix[:2] + } + slot.SetUint64(uint64(len(code))) + return nil, nil +} + +// opExtCodeHashEIP7702 implements the EIP-7702 variation of opExtCodeHash. +func opExtCodeHashEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + slot := scope.Stack.peek() + addr := common.Address(slot.Bytes20()) + if interpreter.evm.StateDB.Empty(addr) { + slot.Clear() + return nil, nil + } + code := interpreter.evm.StateDB.GetCode(addr) + if _, ok := types.ParseDelegation(code); ok { + // If the code is a delegation, return the prefix without version. + slot.SetBytes(crypto.Keccak256(types.DelegationPrefix[:2])) + } else { + // Otherwise, return normal code hash. + slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(addr).Bytes()) + } + return nil, nil +} + +// enable7702 the EIP-7702 changes to support delegation designators. +func enable7702(jt *JumpTable) { + jt[EXTCODECOPY].execute = opExtCodeCopyEIP7702 + jt[EXTCODESIZE].execute = opExtCodeSizeEIP7702 + jt[EXTCODEHASH].execute = opExtCodeHashEIP7702 + + jt[CALL].dynamicGas = gasCallEIP7702 + jt[CALLCODE].dynamicGas = gasCallCodeEIP7702 + jt[STATICCALL].dynamicGas = gasStaticCallEIP7702 + jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702 +} diff --git a/core/vm/eof_validation_test.go b/core/vm/eof_validation_test.go index 6680ca3a5..afb856a32 100644 --- a/core/vm/eof_validation_test.go +++ b/core/vm/eof_validation_test.go @@ -251,7 +251,7 @@ func TestValidateCode(t *testing.T) { data: make([]byte, 0), subContainers: make([]*Container, 0), } - _, err := validateCode(test.code, test.section, container, &pragueEOFInstructionSet, false) + _, err := validateCode(test.code, test.section, container, &eofInstructionSet, false) if !errors.Is(err, test.err) { t.Errorf("test %d (%s): unexpected error (want: %v, got: %v)", i, common.Bytes2Hex(test.code), test.err, err) } @@ -277,7 +277,7 @@ func BenchmarkRJUMPI(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &eofInstructionSet, false) if err != nil { b.Fatal(err) } @@ -309,7 +309,7 @@ func BenchmarkRJUMPV(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &pragueInstructionSet, false) if err != nil { b.Fatal(err) } @@ -357,7 +357,7 @@ func BenchmarkEOFValidation(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&pragueInstructionSet, false); err != nil { b.Fatal(err) } } @@ -412,7 +412,7 @@ func BenchmarkEOFValidation2(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&pragueInstructionSet, false); err != nil { b.Fatal(err) } } @@ -468,7 +468,7 @@ func BenchmarkEOFValidation3(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&pragueInstructionSet, false); err != nil { b.Fatal(err) } } @@ -494,7 +494,7 @@ func BenchmarkRJUMPI_2(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &pragueInstructionSet, false) if err != nil { b.Fatal(err) } @@ -512,6 +512,6 @@ func FuzzValidate(f *testing.F) { f.Fuzz(func(_ *testing.T, code []byte, maxStack uint16) { var container Container container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: maxStack}) - validateCode(code, 0, &container, &pragueEOFInstructionSet, true) + validateCode(code, 0, &container, &pragueInstructionSet, true) }) } diff --git a/core/vm/evm.go b/core/vm/evm.go index 07e4a272f..1a0215459 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -217,7 +217,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - code := evm.StateDB.GetCode(addr) + code := evm.resolveCode(addr) if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { @@ -225,7 +225,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // If the account has no code, we can abort here // The depth-check is already done, and precompiles handled above contract := NewContract(caller, AccountRef(addrCopy), value, gas) - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code) + contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), code) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -285,7 +285,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(caller.Address()), value, gas) - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -332,7 +332,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by addrCopy := addr // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -387,7 +387,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas) - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. @@ -567,6 +567,35 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) } +// resolveCode returns the code associated with the provided account. After +// Prague, it can also resolve code pointed to by a delegation designator. +func (evm *EVM) resolveCode(addr common.Address) []byte { + code := evm.StateDB.GetCode(addr) + if !evm.chainRules.IsPrague { + return code + } + if target, ok := types.ParseDelegation(code); ok { + // Note we only follow one level of delegation. + return evm.StateDB.GetCode(target) + } + return code +} + +// resolveCodeHash returns the code hash associated with the provided address. +// After Prague, it can also resolve code hash of the account pointed to by a +// delegation designator. Although this is not accessible in the EVM it is used +// internally to associate jumpdest analysis to code. +func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash { + if evm.chainRules.IsPrague { + code := evm.StateDB.GetCode(addr) + if target, ok := types.ParseDelegation(code); ok { + // Note we only follow one level of delegation. + return evm.StateDB.GetCodeHash(target) + } + } + return evm.StateDB.GetCodeHash(addr) +} + // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } diff --git a/core/vm/interface.go b/core/vm/interface.go index 9229f4d2c..011541dde 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -42,7 +42,9 @@ type StateDB interface { GetCodeHash(common.Address) common.Hash GetCode(common.Address) []byte - SetCode(common.Address, []byte) + + // SetCode sets the new code for the address, and returns the previous code, if any. + SetCode(common.Address, []byte) []byte GetCodeSize(common.Address) int AddRefund(uint64) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1670ea3e2..4b304aa59 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -109,6 +109,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { case evm.chainRules.IsVerkle: // TODO replace with proper instruction set when fork is specified table = &verkleInstructionSet + case evm.chainRules.IsPrague: + table = &pragueInstructionSet case evm.chainRules.IsCancun: table = &cancunInstructionSet case evm.chainRules.IsNeoXDKG: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 8b1a54563..f918022d1 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -62,7 +62,8 @@ var ( neoxdkgInstructionSet = newNeoXDKGInstructionSet() cancunInstructionSet = newCancunInstructionSet() verkleInstructionSet = newVerkleInstructionSet() - pragueEOFInstructionSet = newPragueEOFInstructionSet() + pragueInstructionSet = newPragueInstructionSet() + eofInstructionSet = newEOFInstructionSetForTesting() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -92,16 +93,22 @@ func newVerkleInstructionSet() JumpTable { return validate(instructionSet) } -func NewPragueEOFInstructionSetForTesting() JumpTable { - return newPragueEOFInstructionSet() +func NewEOFInstructionSetForTesting() JumpTable { + return newEOFInstructionSetForTesting() } -func newPragueEOFInstructionSet() JumpTable { - instructionSet := newCancunInstructionSet() +func newEOFInstructionSetForTesting() JumpTable { + instructionSet := newPragueInstructionSet() enableEOF(&instructionSet) return validate(instructionSet) } +func newPragueInstructionSet() JumpTable { + instructionSet := newCancunInstructionSet() + enable7702(&instructionSet) // EIP-7702 Setcode transaction type + return validate(instructionSet) +} + func newCancunInstructionSet() JumpTable { instructionSet := newNeoXDKGInstructionSet() enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index b993b651f..ff3875868 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -242,3 +243,70 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { } return gasFunc } + +var ( + gasCallEIP7702 = makeCallVariantGasCallEIP7702(gasCall) + gasDelegateCallEIP7702 = makeCallVariantGasCallEIP7702(gasDelegateCall) + gasStaticCallEIP7702 = makeCallVariantGasCallEIP7702(gasStaticCall) + gasCallCodeEIP7702 = makeCallVariantGasCallEIP7702(gasCallCode) +) + +func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var ( + total uint64 // total dynamic gas used + addr = common.Address(stack.Back(1).Bytes20()) + ) + + // Check slot presence in the access list + if !evm.StateDB.AddressInAccessList(addr) { + evm.StateDB.AddAddressToAccessList(addr) + // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so + // the cost to charge for cold access, if any, is Cold - Warm + coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 + // Charge the remaining difference here already, to correctly calculate available + // gas for call + if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + return 0, ErrOutOfGas + } + total += coldCost + } + + // Check if code is a delegation and if so, charge for resolution. + if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok { + var cost uint64 + if evm.StateDB.AddressInAccessList(target) { + cost = params.WarmStorageReadCostEIP2929 + } else { + evm.StateDB.AddAddressToAccessList(target) + cost = params.ColdAccountAccessCostEIP2929 + } + if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + return 0, ErrOutOfGas + } + total += cost + } + + // Now call the old calculator, which takes into account + // - create new account + // - transfer value + // - memory expansion + // - 63/64ths rule + old, err := oldCalculator(evm, contract, stack, mem, memorySize) + if err != nil { + return old, err + } + + // Temporarily add the gas charge back to the contract and return value. By + // adding it to the return, it will be charged outside of this function, as + // part of the dynamic gas. This will ensure it is correctly reported to + // tracers. + contract.Gas += total + + var overflow bool + if total, overflow = math.SafeAdd(old, total); overflow { + return 0, ErrGasUintOverflow + } + return total, nil + } +} diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 0e774a01c..6074e9a09 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -866,3 +866,83 @@ func BenchmarkTracerStepVsCallFrame(b *testing.B) { benchmarkNonModifyingCode(10000000, code, "tracer-step-10M", stepTracer, b) benchmarkNonModifyingCode(10000000, code, "tracer-call-frame-10M", callFrameTracer, b) } + +// TestDelegatedAccountAccessCost tests that calling an account with an EIP-7702 +// delegation designator incurs the correct amount of gas based on the tracer. +func TestDelegatedAccountAccessCost(t *testing.T) { + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + statedb.SetCode(common.HexToAddress("0xff"), types.AddressToDelegation(common.HexToAddress("0xaa"))) + statedb.SetCode(common.HexToAddress("0xaa"), program.New().Return(0, 0).Bytes()) + + for i, tc := range []struct { + code []byte + step int + want uint64 + }{ + { // CALL(0xff) + code: []byte{ + byte(vm.PUSH1), 0x0, + byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALL), byte(vm.POP), + }, + step: 7, + want: 5455, + }, + { // CALLCODE(0xff) + code: []byte{ + byte(vm.PUSH1), 0x0, + byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALLCODE), byte(vm.POP), + }, + step: 7, + want: 5455, + }, + { // DELEGATECALL(0xff) + code: []byte{ + byte(vm.PUSH1), 0x0, + byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.DELEGATECALL), byte(vm.POP), + }, + step: 6, + want: 5455, + }, + { // STATICCALL(0xff) + code: []byte{ + byte(vm.PUSH1), 0x0, + byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), + byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.STATICCALL), byte(vm.POP), + }, + step: 6, + want: 5455, + }, + { // SELFDESTRUCT(0xff): should not be affected by resolution + code: []byte{ + byte(vm.PUSH1), 0xff, byte(vm.SELFDESTRUCT), + }, + step: 1, + want: 7600, + }, + } { + var step = 0 + var have = uint64(0) + Execute(tc.code, nil, &Config{ + ChainConfig: params.MergedTestChainConfig, + State: statedb, + EVMConfig: vm.Config{ + Tracer: &tracing.Hooks{ + OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + // Uncomment to investigate failures: + t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) + if step == tc.step { + have = cost + } + step++ + }, + }, + }, + }) + if want := tc.want; have != want { + t.Fatalf("testcase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want) + } + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json new file mode 100644 index 000000000..b7d5ee1c5 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json @@ -0,0 +1,82 @@ +{ + "genesis": { + "baseFeePerGas": "7", + "blobGasUsed": "0", + "difficulty": "0", + "excessBlobGas": "36306944", + "extraData": "0xd983010e00846765746888676f312e32312e308664617277696e", + "gasLimit": "15639172", + "hash": "0xc682259fda061bb9ce8ccb491d5b2d436cb73daf04e1025dd116d045ce4ad28c", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0xae1a5ba939a4c9ac38aabeff361169fb55a6fc2c9511457e0be6eff9514faec0", + "nonce": "0x0000000000000000", + "number": "315", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", + "timestamp": "1709626771", + "withdrawals": [], + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, + "0x000000000000000000000000000000000000aaaa": { + "code": "0x6000600060006000600173703c4b2bd70c169f5717101caee543299fc946c75af1", + "balance": "0x0" + }, + "0x000000000000000000000000000000000000bbbb": { + "code": "0x6042604255", + "balance": "0x0" + }, + "0x703c4b2bd70c169f5717101caee543299fc946c7": { + "balance": "0xde0b6b3a7640000" + }, + "0x71562b71999873db5b286df957af199ec94617f7": { + "balance": "0xde0b6b3a7640000" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "pragueTime": 0, + "terminalTotalDifficulty": 0 + } + }, + "context": { + "number": "316", + "difficulty": "0", + "timestamp": "1709626785", + "gasLimit": "15654443", + "miner": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "7" + }, + "input": "04f90126820539800285012a05f2008307a1209471562b71999873db5b286df957af199ec94617f78080c0f8baf85c82053994000000000000000000000000000000000000aaaa0101a07ed17af7d2d2b9ba7d797a202125bf505b9a0f962a67b3b61b56783d8faf7461a001b73b6e586edc706dce6c074eaec28692fa6359fb3446a2442f36777e1c0669f85a8094000000000000000000000000000000000000bbbb8001a05011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98a056c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf6101a0167b0ecfc343a497095c22ee4270d3cc3b971cc3599fc73bbff727e0d2ed432da01c003c72306807492bf1150e39b2f79da23b49a4e83eb6e9209ae30d3572368f", + "result": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, + "0x703c4b2bd70c169f5717101caee543299fc946c7": { + "balance": "0xde0b6b3a7640000", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000042": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x71562b71999873db5b286df957af199ec94617f7": { + "balance": "0xde0b6b3a7640000" + } + } +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 9706eb43f..5776275c2 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -159,6 +159,15 @@ func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction t.lookupAccount(from) t.lookupAccount(t.to) t.lookupAccount(env.Coinbase) + + // Add accounts with authorizations to the prestate before they get applied. + for _, auth := range tx.AuthList() { + addr, err := auth.Authority() + if err != nil { + continue + } + t.lookupAccount(addr) + } } func (t *prestateTracer) OnTxEnd(receipt *types.Receipt, err error) { diff --git a/graphql/graphql.go b/graphql/graphql.go index 2de9efbe0..bfdadd647 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -319,7 +319,7 @@ func (t *Transaction) MaxFeePerGas(ctx context.Context) *hexutil.Big { return nil } switch tx.Type() { - case types.DynamicFeeTxType, types.BlobTxType: + case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType: return (*hexutil.Big)(tx.GasFeeCap()) default: return nil @@ -332,7 +332,7 @@ func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) *hexutil.Big { return nil } switch tx.Type() { - case types.DynamicFeeTxType, types.BlobTxType: + case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType: return (*hexutil.Big)(tx.GasTipCap()) default: return nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0e18e1996..0fe368f17 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1041,28 +1041,29 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *types.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` - YParity *hexutil.Uint64 `json:"yParity,omitempty"` + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + AuthorizationList []types.Authorization `json:"authorizationList,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` } // newRPCTransaction returns a transaction that will serialize to the RPC @@ -1137,6 +1138,22 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber } result.MaxFeePerBlobGas = (*hexutil.Big)(tx.BlobGasFeeCap()) result.BlobVersionedHashes = tx.BlobHashes() + + case types.SetCodeTxType: + al := tx.AccessList() + yparity := hexutil.Uint64(v.Sign()) + result.Accesses = &al + result.ChainID = (*hexutil.Big)(tx.ChainId()) + result.YParity = &yparity + result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) + result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) + // if the transaction has been mined, compute the effective gas price + if baseFee != nil && blockHash != (common.Hash{}) { + result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee)) + } else { + result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) + } + result.AuthorizationList = tx.AuthList() } return result } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 4b527f16f..3c6c6aec0 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -641,12 +641,13 @@ func TestEstimateGas(t *testing.T) { t.Parallel() // Initialize test accounts var ( - accounts = newAccounts(2) + accounts = newAccounts(4) genesis = &core.Genesis{ Config: params.MergedTestChainConfig, Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether), Code: append(types.DelegationPrefix, accounts[3].addr.Bytes()...)}, }, } genBlocks = 10 @@ -831,6 +832,26 @@ func TestEstimateGas(t *testing.T) { blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, expectErr: newRevertError(packRevert("block 11")), }, + // Should be able to send to an EIP-7702 delegated account. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[2].addr, + Value: (*hexutil.Big)(big.NewInt(1)), + }, + want: 21000, + }, + // Should be able to send as EIP-7702 delegated account. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[2].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1)), + }, + want: 21000, + }, } for i, tc := range testSuite { result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 5dd053c5f..b5e569279 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -72,6 +72,9 @@ type TransactionArgs struct { Commitments []kzg4844.Commitment `json:"commitments"` Proofs []kzg4844.Proof `json:"proofs"` + // For SetCodeTxType + AuthorizationList []types.Authorization `json:"authorizationList"` + // This configures whether blobs are allowed to be passed. blobSidecarAllowed bool } @@ -501,6 +504,8 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { usedType := types.LegacyTxType switch { + case args.AuthorizationList != nil || defaultType == types.SetCodeTxType: + usedType = types.SetCodeTxType case args.BlobHashes != nil || defaultType == types.BlobTxType: usedType = types.BlobTxType case args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType: @@ -514,6 +519,28 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { } var data types.TxData switch usedType { + case types.SetCodeTxType: + al := types.AccessList{} + if args.AccessList != nil { + al = *args.AccessList + } + authList := []types.Authorization{} + if args.AuthorizationList != nil { + authList = args.AuthorizationList + } + data = &types.SetCodeTx{ + To: *args.To, + ChainID: args.ChainID.ToInt().Uint64(), + Nonce: uint64(*args.Nonce), + Gas: uint64(*args.Gas), + GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), + GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)), + Value: uint256.MustFromBig((*big.Int)(args.Value)), + Data: args.data(), + AccessList: al, + AuthList: authList, + } + case types.BlobTxType: al := types.AccessList{} if args.AccessList != nil { diff --git a/params/protocol_params.go b/params/protocol_params.go index fa3d98c3c..3d03b74be 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -90,10 +90,11 @@ const ( SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. - TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. - TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) - TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list - TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list + TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. + TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) + TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list + TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list + TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702 // These have been changed during the course of the chain CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. diff --git a/tests/gen_stauthorization.go b/tests/gen_stauthorization.go new file mode 100644 index 000000000..fbafd6fde --- /dev/null +++ b/tests/gen_stauthorization.go @@ -0,0 +1,74 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package tests + +import ( + "encoding/json" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" +) + +var _ = (*stAuthorizationMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s stAuthorization) MarshalJSON() ([]byte, error) { + type stAuthorization struct { + ChainID math.HexOrDecimal64 + Address common.Address `json:"address" gencodec:"required"` + Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"` + V math.HexOrDecimal64 `json:"v" gencodec:"required"` + R *math.HexOrDecimal256 `json:"r" gencodec:"required"` + S *math.HexOrDecimal256 `json:"s" gencodec:"required"` + } + var enc stAuthorization + enc.ChainID = math.HexOrDecimal64(s.ChainID) + enc.Address = s.Address + enc.Nonce = math.HexOrDecimal64(s.Nonce) + enc.V = math.HexOrDecimal64(s.V) + enc.R = (*math.HexOrDecimal256)(s.R) + enc.S = (*math.HexOrDecimal256)(s.S) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *stAuthorization) UnmarshalJSON(input []byte) error { + type stAuthorization struct { + ChainID *math.HexOrDecimal64 + Address *common.Address `json:"address" gencodec:"required"` + Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"` + V *math.HexOrDecimal64 `json:"v" gencodec:"required"` + R *math.HexOrDecimal256 `json:"r" gencodec:"required"` + S *math.HexOrDecimal256 `json:"s" gencodec:"required"` + } + var dec stAuthorization + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.ChainID != nil { + s.ChainID = uint64(*dec.ChainID) + } + if dec.Address == nil { + return errors.New("missing required field 'address' for stAuthorization") + } + s.Address = *dec.Address + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' for stAuthorization") + } + s.Nonce = uint64(*dec.Nonce) + if dec.V == nil { + return errors.New("missing required field 'v' for stAuthorization") + } + s.V = uint8(*dec.V) + if dec.R == nil { + return errors.New("missing required field 'r' for stAuthorization") + } + s.R = (*big.Int)(dec.R) + if dec.S == nil { + return errors.New("missing required field 's' for stAuthorization") + } + s.S = (*big.Int)(dec.S) + return nil +} diff --git a/tests/gen_sttransaction.go b/tests/gen_sttransaction.go index 9b5aecbfe..b25ce7616 100644 --- a/tests/gen_sttransaction.go +++ b/tests/gen_sttransaction.go @@ -30,6 +30,7 @@ func (s stTransaction) MarshalJSON() ([]byte, error) { Sender *common.Address `json:"sender"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` BlobGasFeeCap *math.HexOrDecimal256 `json:"maxFeePerBlobGas,omitempty"` + AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"` } var enc stTransaction enc.GasPrice = (*math.HexOrDecimal256)(s.GasPrice) @@ -50,6 +51,7 @@ func (s stTransaction) MarshalJSON() ([]byte, error) { enc.Sender = s.Sender enc.BlobVersionedHashes = s.BlobVersionedHashes enc.BlobGasFeeCap = (*math.HexOrDecimal256)(s.BlobGasFeeCap) + enc.AuthorizationList = s.AuthorizationList return json.Marshal(&enc) } @@ -69,6 +71,7 @@ func (s *stTransaction) UnmarshalJSON(input []byte) error { Sender *common.Address `json:"sender"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` BlobGasFeeCap *math.HexOrDecimal256 `json:"maxFeePerBlobGas,omitempty"` + AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"` } var dec stTransaction if err := json.Unmarshal(input, &dec); err != nil { @@ -116,5 +119,8 @@ func (s *stTransaction) UnmarshalJSON(input []byte) error { if dec.BlobGasFeeCap != nil { s.BlobGasFeeCap = (*big.Int)(dec.BlobGasFeeCap) } + if dec.AuthorizationList != nil { + s.AuthorizationList = dec.AuthorizationList + } return nil } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 6884ae7ed..e735ce2fb 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -123,6 +123,7 @@ type stTransaction struct { Sender *common.Address `json:"sender"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` BlobGasFeeCap *big.Int `json:"maxFeePerBlobGas,omitempty"` + AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"` } type stTransactionMarshaling struct { @@ -135,6 +136,27 @@ type stTransactionMarshaling struct { BlobGasFeeCap *math.HexOrDecimal256 } +//go:generate go run github.com/fjl/gencodec -type stAuthorization -field-override stAuthorizationMarshaling -out gen_stauthorization.go + +// Authorization is an authorization from an account to deploy code at it's address. +type stAuthorization struct { + ChainID uint64 + Address common.Address `json:"address" gencodec:"required"` + Nonce uint64 `json:"nonce" gencodec:"required"` + V uint8 `json:"v" gencodec:"required"` + R *big.Int `json:"r" gencodec:"required"` + S *big.Int `json:"s" gencodec:"required"` +} + +// field type overrides for gencodec +type stAuthorizationMarshaling struct { + ChainID math.HexOrDecimal64 + Nonce math.HexOrDecimal64 + V math.HexOrDecimal64 + R *math.HexOrDecimal256 + S *math.HexOrDecimal256 +} + // GetChainConfig takes a fork definition and returns a chain config. // The fork definition can be // - a plain forkname, e.g. `Byzantium`, @@ -419,6 +441,20 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess if gasPrice == nil { return nil, errors.New("no gas price provided") } + var authList []types.Authorization + if tx.AuthorizationList != nil { + authList = make([]types.Authorization, len(tx.AuthorizationList)) + for i, auth := range tx.AuthorizationList { + authList[i] = types.Authorization{ + ChainID: auth.ChainID, + Address: auth.Address, + Nonce: auth.Nonce, + V: auth.V, + R: *uint256.MustFromBig(auth.R), + S: *uint256.MustFromBig(auth.S), + } + } + } msg := &core.Message{ From: from, @@ -433,6 +469,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess AccessList: accessList, BlobHashes: tx.BlobVersionedHashes, BlobGasFeeCap: tx.BlobGasFeeCap, + AuthList: authList, } return msg, nil } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index d3dbbd5db..4da27ff94 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -59,7 +59,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul, false) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, isHomestead, isIstanbul, false) if err != nil { return nil, nil, err } From ca97d2965e965116dbfafd677d99e1427d65fcb9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 16 Dec 2024 21:10:08 +0800 Subject: [PATCH 046/354] trie/pathdb: state iterator (snapshot integration pt 4) (#30654) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this pull request, the state iterator is implemented. It's mostly a copy-paste from the original state snapshot package, but still has some important changes to highlight here: (a) The iterator for the disk layer consists of a diff iterator and a disk iterator. Originally, the disk layer in the state snapshot was a wrapper around the disk, and its corresponding iterator was also a wrapper around the disk iterator. However, due to structural differences, the disk layer iterator is divided into two parts: - The disk iterator, which traverses the content stored on disk. - The diff iterator, which traverses the aggregated state buffer. Checkout `BinaryIterator` and `FastIterator` for more details. (b) The staleness management is improved in the diffAccountIterator and diffStorageIterator Originally, in the `diffAccountIterator`, the layer’s staleness had to be checked within the Next function to ensure the iterator remained usable. Additionally, a read lock on the associated diff layer was required to first retrieve the account blob. This read lock protection is essential to prevent concurrent map read/write. Afterward, a staleness check was performed to ensure the retrieved data was not outdated. The entire logic can be simplified as follows: a loadAccount callback is provided to retrieve account data. If the corresponding state is immutable (e.g., diff layers in the path database), the staleness check can be skipped, and a single account data retrieval is sufficient. However, if the corresponding state is mutable (e.g., the disk layer in the path database), the callback can operate as follows: ```go func(hash common.Hash) ([]byte, error) { dl.lock.RLock() defer dl.lock.RUnlock() if dl.stale { return nil, errSnapshotStale } return dl.buffer.states.mustAccount(hash) } ``` The callback solution can eliminate the complexity for managing concurrency with the read lock for atomic operation. --- triedb/pathdb/database.go | 12 + triedb/pathdb/holdable_iterator.go | 97 ++ triedb/pathdb/holdable_iterator_test.go | 176 ++++ triedb/pathdb/iterator.go | 369 +++++++ triedb/pathdb/iterator_binary.go | 344 +++++++ triedb/pathdb/iterator_fast.go | 380 ++++++++ triedb/pathdb/iterator_test.go | 1162 +++++++++++++++++++++++ triedb/pathdb/reader.go | 11 + triedb/pathdb/states.go | 28 +- triedb/pathdb/states_test.go | 118 +-- 10 files changed, 2634 insertions(+), 63 deletions(-) create mode 100644 triedb/pathdb/holdable_iterator.go create mode 100644 triedb/pathdb/holdable_iterator_test.go create mode 100644 triedb/pathdb/iterator.go create mode 100644 triedb/pathdb/iterator_binary.go create mode 100644 triedb/pathdb/iterator_fast.go create mode 100644 triedb/pathdb/iterator_test.go diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index cfbdb01c4..914b17de5 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -555,3 +555,15 @@ func (db *Database) StorageHistory(address common.Address, slot common.Hash, sta func (db *Database) HistoryRange() (uint64, uint64, error) { return historyRange(db.freezer) } + +// AccountIterator creates a new account iterator for the specified root hash and +// seeks to a starting account hash. +func (db *Database) AccountIterator(root common.Hash, seek common.Hash) (AccountIterator, error) { + return newFastAccountIterator(db, root, seek) +} + +// StorageIterator creates a new storage iterator for the specified root hash and +// account. The iterator will be moved to the specific start position. +func (db *Database) StorageIterator(root common.Hash, account common.Hash, seek common.Hash) (StorageIterator, error) { + return newFastStorageIterator(db, root, account, seek) +} diff --git a/triedb/pathdb/holdable_iterator.go b/triedb/pathdb/holdable_iterator.go new file mode 100644 index 000000000..1f8e6b706 --- /dev/null +++ b/triedb/pathdb/holdable_iterator.go @@ -0,0 +1,97 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" +) + +// holdableIterator is a wrapper of underlying database iterator. It extends +// the basic iterator interface by adding Hold which can hold the element +// locally where the iterator is currently located and serve it up next time. +type holdableIterator struct { + it ethdb.Iterator + key []byte + val []byte + atHeld bool +} + +// newHoldableIterator initializes the holdableIterator with the given iterator. +func newHoldableIterator(it ethdb.Iterator) *holdableIterator { + return &holdableIterator{it: it} +} + +// Hold holds the element locally where the iterator is currently located which +// can be served up next time. +func (it *holdableIterator) Hold() { + if it.it.Key() == nil { + return // nothing to hold + } + it.key = common.CopyBytes(it.it.Key()) + it.val = common.CopyBytes(it.it.Value()) + it.atHeld = false +} + +// Next moves the iterator to the next key/value pair. It returns whether the +// iterator is exhausted. +func (it *holdableIterator) Next() bool { + if !it.atHeld && it.key != nil { + it.atHeld = true + } else if it.atHeld { + it.atHeld = false + it.key = nil + it.val = nil + } + if it.key != nil { + return true // shifted to locally held value + } + return it.it.Next() +} + +// Error returns any accumulated error. Exhausting all the key/value pairs +// is not considered to be an error. +func (it *holdableIterator) Error() error { return it.it.Error() } + +// Release releases associated resources. Release should always succeed and can +// be called multiple times without causing error. +func (it *holdableIterator) Release() { + it.atHeld = false + it.key = nil + it.val = nil + it.it.Release() +} + +// Key returns the key of the current key/value pair, or nil if done. The caller +// should not modify the contents of the returned slice, and its contents may +// change on the next call to Next. +func (it *holdableIterator) Key() []byte { + if it.key != nil { + return it.key + } + return it.it.Key() +} + +// Value returns the value of the current key/value pair, or nil if done. The +// caller should not modify the contents of the returned slice, and its contents +// may change on the next call to Next. +func (it *holdableIterator) Value() []byte { + if it.val != nil { + return it.val + } + return it.it.Value() +} diff --git a/triedb/pathdb/holdable_iterator_test.go b/triedb/pathdb/holdable_iterator_test.go new file mode 100644 index 000000000..2abc92e15 --- /dev/null +++ b/triedb/pathdb/holdable_iterator_test.go @@ -0,0 +1,176 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" +) + +func TestIteratorHold(t *testing.T) { + // Create the key-value data store + var ( + content = map[string]string{"k1": "v1", "k2": "v2", "k3": "v3"} + order = []string{"k1", "k2", "k3"} + db = rawdb.NewMemoryDatabase() + ) + for key, val := range content { + if err := db.Put([]byte(key), []byte(val)); err != nil { + t.Fatalf("failed to insert item %s:%s into database: %v", key, val, err) + } + } + // Iterate over the database with the given configs and verify the results + it, idx := newHoldableIterator(db.NewIterator(nil, nil)), 0 + + // Nothing should be affected for calling Discard on non-initialized iterator + it.Hold() + + for it.Next() { + if len(content) <= idx { + t.Errorf("more items than expected: checking idx=%d (key %q), expecting len=%d", idx, it.Key(), len(order)) + break + } + if !bytes.Equal(it.Key(), []byte(order[idx])) { + t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) + } + if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { + t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) + } + // Should be safe to call discard multiple times + it.Hold() + it.Hold() + + // Shift iterator to the discarded element + it.Next() + if !bytes.Equal(it.Key(), []byte(order[idx])) { + t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) + } + if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { + t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) + } + + // Discard/Next combo should work always + it.Hold() + it.Next() + if !bytes.Equal(it.Key(), []byte(order[idx])) { + t.Errorf("item %d: key mismatch: have %s, want %s", idx, string(it.Key()), order[idx]) + } + if !bytes.Equal(it.Value(), []byte(content[order[idx]])) { + t.Errorf("item %d: value mismatch: have %s, want %s", idx, string(it.Value()), content[order[idx]]) + } + idx++ + } + if err := it.Error(); err != nil { + t.Errorf("iteration failed: %v", err) + } + if idx != len(order) { + t.Errorf("iteration terminated prematurely: have %d, want %d", idx, len(order)) + } + db.Close() +} + +func TestReopenIterator(t *testing.T) { + var ( + content = map[common.Hash]string{ + common.HexToHash("a1"): "v1", + common.HexToHash("a2"): "v2", + common.HexToHash("a3"): "v3", + common.HexToHash("a4"): "v4", + common.HexToHash("a5"): "v5", + common.HexToHash("a6"): "v6", + } + order = []common.Hash{ + common.HexToHash("a1"), + common.HexToHash("a2"), + common.HexToHash("a3"), + common.HexToHash("a4"), + common.HexToHash("a5"), + common.HexToHash("a6"), + } + db = rawdb.NewMemoryDatabase() + + reopen = func(db ethdb.KeyValueStore, iter *holdableIterator) *holdableIterator { + if !iter.Next() { + iter.Release() + return newHoldableIterator(memorydb.New().NewIterator(nil, nil)) + } + next := iter.Key() + iter.Release() + return newHoldableIterator(db.NewIterator(rawdb.SnapshotAccountPrefix, next[1:])) + } + ) + for key, val := range content { + rawdb.WriteAccountSnapshot(db, key, []byte(val)) + } + checkVal := func(it *holdableIterator, index int) { + if !bytes.Equal(it.Key(), append(rawdb.SnapshotAccountPrefix, order[index].Bytes()...)) { + t.Fatalf("Unexpected data entry key, want %v got %v", order[index], it.Key()) + } + if !bytes.Equal(it.Value(), []byte(content[order[index]])) { + t.Fatalf("Unexpected data entry key, want %v got %v", []byte(content[order[index]]), it.Value()) + } + } + // Iterate over the database with the given configs and verify the results + dbIter := db.NewIterator(rawdb.SnapshotAccountPrefix, nil) + iter, idx := newHoldableIterator(rawdb.NewKeyLengthIterator(dbIter, 1+common.HashLength)), -1 + + idx++ + iter.Next() + checkVal(iter, idx) + + iter = reopen(db, iter) + idx++ + iter.Next() + checkVal(iter, idx) + + // reopen twice + iter = reopen(db, iter) + iter = reopen(db, iter) + idx++ + iter.Next() + checkVal(iter, idx) + + // reopen iterator with held value + iter.Next() + iter.Hold() + iter = reopen(db, iter) + idx++ + iter.Next() + checkVal(iter, idx) + + // reopen twice iterator with held value + iter.Next() + iter.Hold() + iter = reopen(db, iter) + iter = reopen(db, iter) + idx++ + iter.Next() + checkVal(iter, idx) + + // shift to the end and reopen + iter.Next() // the end + iter = reopen(db, iter) + iter.Next() + if iter.Key() != nil { + t.Fatal("Unexpected iterated entry") + } +} diff --git a/triedb/pathdb/iterator.go b/triedb/pathdb/iterator.go new file mode 100644 index 000000000..980f228cf --- /dev/null +++ b/triedb/pathdb/iterator.go @@ -0,0 +1,369 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "bytes" + "fmt" + "sort" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +// Iterator is an iterator to step over all the accounts or the specific +// storage in a snapshot which may or may not be composed of multiple layers. +type Iterator interface { + // Next steps the iterator forward one element, returning false if exhausted, + // or an error if iteration failed for some reason (e.g. root being iterated + // becomes stale and garbage collected). + Next() bool + + // Error returns any failure that occurred during iteration, which might have + // caused a premature iteration exit (e.g. layer stack becoming stale). + Error() error + + // Hash returns the hash of the account or storage slot the iterator is + // currently at. + Hash() common.Hash + + // Release releases associated resources. Release should always succeed and + // can be called multiple times without causing error. + Release() +} + +// AccountIterator is an iterator to step over all the accounts in a snapshot, +// which may or may not be composed of multiple layers. +type AccountIterator interface { + Iterator + + // Account returns the RLP encoded slim account the iterator is currently at. + // An error will be returned if the iterator becomes invalid + Account() []byte +} + +// StorageIterator is an iterator to step over the specific storage in a snapshot, +// which may or may not be composed of multiple layers. +type StorageIterator interface { + Iterator + + // Slot returns the storage slot the iterator is currently at. An error will + // be returned if the iterator becomes invalid + Slot() []byte +} + +type ( + // loadAccount is the function to retrieve the account from the associated + // layer. An error will be returned if the associated layer is stale. + loadAccount func(hash common.Hash) ([]byte, error) + + // loadStorage is the function to retrieve the storage slot from the associated + // layer. An error will be returned if the associated layer is stale. + loadStorage func(addrHash common.Hash, slotHash common.Hash) ([]byte, error) +) + +// diffAccountIterator is an account iterator that steps over the accounts (both +// live and deleted) contained within a state set. Higher order iterators will +// use the deleted accounts to skip deeper iterators. +// +// This iterator could be created from the diff layer or the disk layer (the +// aggregated state buffer). +type diffAccountIterator struct { + curHash common.Hash // The current hash the iterator is positioned on + keys []common.Hash // Keys left in the layer to iterate + fail error // Any failures encountered (stale) + loadFn loadAccount // Function to retrieve the account from with supplied hash +} + +// newDiffAccountIterator creates an account iterator over the given state set. +func newDiffAccountIterator(seek common.Hash, states *stateSet, fn loadAccount) AccountIterator { + // Seek out the requested starting account + hashes := states.accountList() + index := sort.Search(len(hashes), func(i int) bool { + return bytes.Compare(seek[:], hashes[i][:]) <= 0 + }) + // Assemble and returned the already seeked iterator + return &diffAccountIterator{ + keys: hashes[index:], + loadFn: fn, + } +} + +// Next steps the iterator forward one element, returning false if exhausted. +func (it *diffAccountIterator) Next() bool { + // If the iterator was already stale, consider it a programmer error. Although + // we could just return false here, triggering this path would probably mean + // somebody forgot to check for Error, so lets blow up instead of undefined + // behavior that's hard to debug. + if it.fail != nil { + panic(fmt.Sprintf("called Next of failed iterator: %v", it.fail)) + } + // Stop iterating if all keys were exhausted + if len(it.keys) == 0 { + return false + } + // Iterator seems to be still alive, retrieve and cache the live hash + it.curHash = it.keys[0] + + // key cached, shift the iterator and notify the user of success + it.keys = it.keys[1:] + return true +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit (e.g. the linked state set becoming stale). +func (it *diffAccountIterator) Error() error { + return it.fail +} + +// Hash returns the hash of the account the iterator is currently at. +func (it *diffAccountIterator) Hash() common.Hash { + return it.curHash +} + +// Account returns the RLP encoded slim account the iterator is currently at. +// This method may fail if the associated state goes stale. An error will +// be set to it.fail just in case. +// +// Note the returned account is not a copy, please don't modify it. +func (it *diffAccountIterator) Account() []byte { + blob, err := it.loadFn(it.curHash) + if err != nil { + it.fail = err + return nil + } + return blob +} + +// Release is a noop for diff account iterators as there are no held resources. +func (it *diffAccountIterator) Release() {} + +// diskAccountIterator is an account iterator that steps over the persistent +// accounts within the database. +// +// To simplify, the staleness of the persistent state is not tracked. The disk +// iterator is not intended to be used alone. It should always be wrapped with +// a diff iterator, as the bottom-most disk layer uses both the in-memory +// aggregated buffer and the persistent disk layer as the data sources. The +// staleness of the diff iterator is sufficient to invalidate the iterator pair. +type diskAccountIterator struct { + it ethdb.Iterator +} + +// newDiskAccountIterator creates an account iterator over the persistent state. +func newDiskAccountIterator(db ethdb.KeyValueStore, seek common.Hash) AccountIterator { + pos := common.TrimRightZeroes(seek[:]) + return &diskAccountIterator{ + it: db.NewIterator(rawdb.SnapshotAccountPrefix, pos), + } +} + +// Next steps the iterator forward one element, returning false if exhausted. +func (it *diskAccountIterator) Next() bool { + // If the iterator was already exhausted, don't bother + if it.it == nil { + return false + } + // Try to advance the iterator and release it if we reached the end + for { + if !it.it.Next() { + it.it.Release() + it.it = nil + return false + } + if len(it.it.Key()) == len(rawdb.SnapshotAccountPrefix)+common.HashLength { + break + } + } + return true +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit. (e.g, any error occurred in the database) +func (it *diskAccountIterator) Error() error { + if it.it == nil { + return nil // Iterator is exhausted and released + } + return it.it.Error() +} + +// Hash returns the hash of the account the iterator is currently at. +func (it *diskAccountIterator) Hash() common.Hash { + return common.BytesToHash(it.it.Key()) // The prefix will be truncated +} + +// Account returns the RLP encoded slim account the iterator is currently at. +func (it *diskAccountIterator) Account() []byte { + return it.it.Value() +} + +// Release releases the database snapshot held during iteration. +func (it *diskAccountIterator) Release() { + // The iterator is auto-released on exhaustion, so make sure it's still alive + if it.it != nil { + it.it.Release() + it.it = nil + } +} + +// diffStorageIterator is a storage iterator that steps over the specific storage +// (both live and deleted) contained within a state set. Higher order iterators +// will use the deleted slot to skip deeper iterators. +// +// This iterator could be created from the diff layer or the disk layer (the +// aggregated state buffer). +type diffStorageIterator struct { + curHash common.Hash // The current slot hash the iterator is positioned on + account common.Hash // The account hash the storage slots belonging to + keys []common.Hash // Keys left in the layer to iterate + fail error // Any failures encountered (stale) + loadFn loadStorage // Function to retrieve the storage slot from with supplied hash +} + +// newDiffStorageIterator creates a storage iterator over a single diff layer. +func newDiffStorageIterator(account common.Hash, seek common.Hash, states *stateSet, fn loadStorage) StorageIterator { + hashes := states.storageList(account) + index := sort.Search(len(hashes), func(i int) bool { + return bytes.Compare(seek[:], hashes[i][:]) <= 0 + }) + // Assemble and returned the already seeked iterator + return &diffStorageIterator{ + account: account, + keys: hashes[index:], + loadFn: fn, + } +} + +// Next steps the iterator forward one element, returning false if exhausted. +func (it *diffStorageIterator) Next() bool { + // If the iterator was already stale, consider it a programmer error. Although + // we could just return false here, triggering this path would probably mean + // somebody forgot to check for Error, so lets blow up instead of undefined + // behavior that's hard to debug. + if it.fail != nil { + panic(fmt.Sprintf("called Next of failed iterator: %v", it.fail)) + } + // Stop iterating if all keys were exhausted + if len(it.keys) == 0 { + return false + } + // Iterator seems to be still alive, retrieve and cache the live hash + it.curHash = it.keys[0] + + // key cached, shift the iterator and notify the user of success + it.keys = it.keys[1:] + return true +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit (e.g. the state set becoming stale). +func (it *diffStorageIterator) Error() error { + return it.fail +} + +// Hash returns the hash of the storage slot the iterator is currently at. +func (it *diffStorageIterator) Hash() common.Hash { + return it.curHash +} + +// Slot returns the raw storage slot value the iterator is currently at. +// This method may fail if the associated state goes stale. An error will +// be set to it.fail just in case. +// +// Note the returned slot is not a copy, please don't modify it. +func (it *diffStorageIterator) Slot() []byte { + storage, err := it.loadFn(it.account, it.curHash) + if err != nil { + it.fail = err + return nil + } + return storage +} + +// Release is a noop for diff account iterators as there are no held resources. +func (it *diffStorageIterator) Release() {} + +// diskStorageIterator is a storage iterator that steps over the persistent +// storage slots contained within the database. +// +// To simplify, the staleness of the persistent state is not tracked. The disk +// iterator is not intended to be used alone. It should always be wrapped with +// a diff iterator, as the bottom-most disk layer uses both the in-memory +// aggregated buffer and the persistent disk layer as the data sources. The +// staleness of the diff iterator is sufficient to invalidate the iterator pair. +type diskStorageIterator struct { + account common.Hash + it ethdb.Iterator +} + +// StorageIterator creates a storage iterator over the persistent state. +func newDiskStorageIterator(db ethdb.KeyValueStore, account common.Hash, seek common.Hash) StorageIterator { + pos := common.TrimRightZeroes(seek[:]) + return &diskStorageIterator{ + account: account, + it: db.NewIterator(append(rawdb.SnapshotStoragePrefix, account.Bytes()...), pos), + } +} + +// Next steps the iterator forward one element, returning false if exhausted. +func (it *diskStorageIterator) Next() bool { + // If the iterator was already exhausted, don't bother + if it.it == nil { + return false + } + // Try to advance the iterator and release it if we reached the end + for { + if !it.it.Next() { + it.it.Release() + it.it = nil + return false + } + if len(it.it.Key()) == len(rawdb.SnapshotStoragePrefix)+common.HashLength+common.HashLength { + break + } + } + return true +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit (e.g. the error occurred in the database). +func (it *diskStorageIterator) Error() error { + if it.it == nil { + return nil // Iterator is exhausted and released + } + return it.it.Error() +} + +// Hash returns the hash of the storage slot the iterator is currently at. +func (it *diskStorageIterator) Hash() common.Hash { + return common.BytesToHash(it.it.Key()) // The prefix will be truncated +} + +// Slot returns the raw storage slot content the iterator is currently at. +func (it *diskStorageIterator) Slot() []byte { + return it.it.Value() +} + +// Release releases the database snapshot held during iteration. +func (it *diskStorageIterator) Release() { + // The iterator is auto-released on exhaustion, so make sure it's still alive + if it.it != nil { + it.it.Release() + it.it = nil + } +} diff --git a/triedb/pathdb/iterator_binary.go b/triedb/pathdb/iterator_binary.go new file mode 100644 index 000000000..dec31e8f3 --- /dev/null +++ b/triedb/pathdb/iterator_binary.go @@ -0,0 +1,344 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" +) + +// binaryIterator is a simplistic iterator to step over the accounts or storage +// in a snapshot, which may or may not be composed of multiple layers. Performance +// wise this iterator is slow, it's meant for cross validating the fast one. +// +// This iterator cannot be used on its own; it should be wrapped with an outer +// iterator, such as accountBinaryIterator or storageBinaryIterator. +// +// This iterator can only traverse the keys of the entries stored in the layers, +// but cannot obtain the corresponding values. Besides, the deleted entry will +// also be traversed, the outer iterator must check the emptiness before returning. +type binaryIterator struct { + a Iterator + b Iterator + aDone bool + bDone bool + k common.Hash + fail error +} + +// initBinaryAccountIterator creates a simplistic iterator to step over all the +// accounts in a slow, but easily verifiable way. Note this function is used +// for initialization, use `newBinaryAccountIterator` as the API. +func (dl *diskLayer) initBinaryAccountIterator(seek common.Hash) *binaryIterator { + // Create two iterators for state buffer and the persistent state in disk + // respectively and combine them as a binary iterator. + l := &binaryIterator{ + // The account loader function is unnecessary; the account key list + // produced by the supplied buffer alone is sufficient for iteration. + // + // The account key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffAccountIterator(seek, dl.buffer.states, nil), + b: newDiskAccountIterator(dl.db.diskdb, seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l +} + +// initBinaryAccountIterator creates a simplistic iterator to step over all the +// accounts in a slow, but easily verifiable way. Note this function is used +// for initialization, use `newBinaryAccountIterator` as the API. +func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) *binaryIterator { + parent, ok := dl.parent.(*diffLayer) + if !ok { + l := &binaryIterator{ + // The account loader function is unnecessary; the account key list + // produced by the supplied state set alone is sufficient for iteration. + // + // The account key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffAccountIterator(seek, dl.states.stateSet, nil), + b: dl.parent.(*diskLayer).initBinaryAccountIterator(seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l + } + l := &binaryIterator{ + // The account loader function is unnecessary; the account key list + // produced by the supplied state set alone is sufficient for iteration. + // + // The account key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffAccountIterator(seek, dl.states.stateSet, nil), + b: parent.initBinaryAccountIterator(seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l +} + +// initBinaryStorageIterator creates a simplistic iterator to step over all the +// storage slots in a slow, but easily verifiable way. Note this function is used +// for initialization, use `newBinaryStorageIterator` as the API. +func (dl *diskLayer) initBinaryStorageIterator(account common.Hash, seek common.Hash) *binaryIterator { + // Create two iterators for state buffer and the persistent state in disk + // respectively and combine them as a binary iterator. + l := &binaryIterator{ + // The storage loader function is unnecessary; the storage key list + // produced by the supplied buffer alone is sufficient for iteration. + // + // The storage key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffStorageIterator(account, seek, dl.buffer.states, nil), + b: newDiskStorageIterator(dl.db.diskdb, account, seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l +} + +// initBinaryStorageIterator creates a simplistic iterator to step over all the +// storage slots in a slow, but easily verifiable way. Note this function is used +// for initialization, use `newBinaryStorageIterator` as the API. +func (dl *diffLayer) initBinaryStorageIterator(account common.Hash, seek common.Hash) *binaryIterator { + parent, ok := dl.parent.(*diffLayer) + if !ok { + l := &binaryIterator{ + // The storage loader function is unnecessary; the storage key list + // produced by the supplied state set alone is sufficient for iteration. + // + // The storage key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffStorageIterator(account, seek, dl.states.stateSet, nil), + b: dl.parent.(*diskLayer).initBinaryStorageIterator(account, seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l + } + l := &binaryIterator{ + // The storage loader function is unnecessary; the storage key list + // produced by the supplied state set alone is sufficient for iteration. + // + // The storage key list for iteration is deterministic once the iterator + // is constructed, no matter the referenced disk layer is stale or not + // later. + a: newDiffStorageIterator(account, seek, dl.states.stateSet, nil), + b: parent.initBinaryStorageIterator(account, seek), + } + l.aDone = !l.a.Next() + l.bDone = !l.b.Next() + return l +} + +// Next advances the iterator by one element, returning false if both iterators +// are exhausted. Note that the entry pointed to by the iterator may be null +// (e.g., when an account is deleted but still accessible for iteration). +// The outer iterator must verify emptiness before terminating the iteration. +// +// There’s no need to check for errors in the two iterators, as we only iterate +// through the entries without retrieving their values. +func (it *binaryIterator) Next() bool { + if it.aDone && it.bDone { + return false + } + for { + if it.aDone { + it.k = it.b.Hash() + it.bDone = !it.b.Next() + return true + } + if it.bDone { + it.k = it.a.Hash() + it.aDone = !it.a.Next() + return true + } + nextA, nextB := it.a.Hash(), it.b.Hash() + if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 { + it.aDone = !it.a.Next() + it.k = nextA + return true + } else if diff == 0 { + // Now we need to advance one of them + it.aDone = !it.a.Next() + continue + } + it.bDone = !it.b.Next() + it.k = nextB + return true + } +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit (e.g. snapshot stack becoming stale). +func (it *binaryIterator) Error() error { + return it.fail +} + +// Hash returns the hash of the account the iterator is currently at. +func (it *binaryIterator) Hash() common.Hash { + return it.k +} + +// Release recursively releases all the iterators in the stack. +func (it *binaryIterator) Release() { + it.a.Release() + it.b.Release() +} + +// accountBinaryIterator is a wrapper around a binary iterator that adds functionality +// to retrieve account data from the associated layer at the current position. +type accountBinaryIterator struct { + *binaryIterator + layer layer +} + +// newBinaryAccountIterator creates a simplistic account iterator to step over +// all the accounts in a slow, but easily verifiable way. +// +// nolint:all +func (dl *diskLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator { + return &accountBinaryIterator{ + binaryIterator: dl.initBinaryAccountIterator(seek), + layer: dl, + } +} + +// newBinaryAccountIterator creates a simplistic account iterator to step over +// all the accounts in a slow, but easily verifiable way. +func (dl *diffLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator { + return &accountBinaryIterator{ + binaryIterator: dl.initBinaryAccountIterator(seek), + layer: dl, + } +} + +// Next steps the iterator forward one element, returning false if exhausted, +// or an error if iteration failed for some reason (e.g. the linked layer is +// stale during the iteration). +func (it *accountBinaryIterator) Next() bool { + for { + if !it.binaryIterator.Next() { + return false + } + // Retrieve the account data referenced by the current iterator, the + // associated layers might be outdated due to chain progressing, + // the relative error will be set to it.fail just in case. + // + // Skip the null account which was deleted before and move to the + // next account. + if len(it.Account()) != 0 { + return true + } + // it.fail might be set if error occurs by calling it.Account(). + // Stop iteration if so. + if it.fail != nil { + return false + } + } +} + +// Account returns the RLP encoded slim account the iterator is currently at, or +// nil if the iterated snapshot stack became stale (you can check Error after +// to see if it failed or not). +// +// Note the returned account is not a copy, please don't modify it. +func (it *accountBinaryIterator) Account() []byte { + blob, err := it.layer.account(it.k, 0) + if err != nil { + it.fail = err + return nil + } + return blob +} + +// storageBinaryIterator is a wrapper around a binary iterator that adds functionality +// to retrieve storage slot data from the associated layer at the current position. +type storageBinaryIterator struct { + *binaryIterator + account common.Hash + layer layer +} + +// newBinaryStorageIterator creates a simplistic account iterator to step over +// all the storage slots in a slow, but easily verifiable way. +// +// nolint:all +func (dl *diskLayer) newBinaryStorageIterator(account common.Hash, seek common.Hash) StorageIterator { + return &storageBinaryIterator{ + binaryIterator: dl.initBinaryStorageIterator(account, seek), + account: account, + layer: dl, + } +} + +// newBinaryStorageIterator creates a simplistic account iterator to step over +// all the storage slots in a slow, but easily verifiable way. +func (dl *diffLayer) newBinaryStorageIterator(account common.Hash, seek common.Hash) StorageIterator { + return &storageBinaryIterator{ + binaryIterator: dl.initBinaryStorageIterator(account, seek), + account: account, + layer: dl, + } +} + +// Next steps the iterator forward one element, returning false if exhausted, +// or an error if iteration failed for some reason (e.g. the linked layer is +// stale during the iteration). +func (it *storageBinaryIterator) Next() bool { + for { + if !it.binaryIterator.Next() { + return false + } + // Retrieve the storage data referenced by the current iterator, the + // associated layers might be outdated due to chain progressing, + // the relative error will be set to it.fail just in case. + // + // Skip the null storage which was deleted before and move to the + // next account. + if len(it.Slot()) != 0 { + return true + } + // it.fail might be set if error occurs by calling it.Slot(). + // Stop iteration if so. + if it.fail != nil { + return false + } + } +} + +// Slot returns the raw storage slot data the iterator is currently at, or +// nil if the iterated snapshot stack became stale (you can check Error after +// to see if it failed or not). +// +// Note the returned slot is not a copy, please don't modify it. +func (it *storageBinaryIterator) Slot() []byte { + blob, err := it.layer.storage(it.account, it.k, 0) + if err != nil { + it.fail = err + return nil + } + return blob +} diff --git a/triedb/pathdb/iterator_fast.go b/triedb/pathdb/iterator_fast.go new file mode 100644 index 000000000..217b211fc --- /dev/null +++ b/triedb/pathdb/iterator_fast.go @@ -0,0 +1,380 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "bytes" + "fmt" + "slices" + "sort" + + "github.com/ethereum/go-ethereum/common" +) + +// weightedIterator is an iterator with an assigned weight. It is used to prioritise +// which account or storage slot is the correct one if multiple iterators find the +// same one (modified in multiple consecutive blocks). +type weightedIterator struct { + it Iterator + priority int +} + +func (it *weightedIterator) Cmp(other *weightedIterator) int { + // Order the iterators primarily by the account hashes + hashI := it.it.Hash() + hashJ := other.it.Hash() + + switch bytes.Compare(hashI[:], hashJ[:]) { + case -1: + return -1 + case 1: + return 1 + } + // Same account/storage-slot in multiple layers, split by priority + if it.priority < other.priority { + return -1 + } + if it.priority > other.priority { + return 1 + } + return 0 +} + +// fastIterator is a more optimized multi-layer iterator which maintains a +// direct mapping of all iterators leading down to the bottom layer. +type fastIterator struct { + curAccount []byte + curSlot []byte + + iterators []*weightedIterator + initiated bool + account bool + fail error +} + +// newFastIterator creates a new hierarchical account or storage iterator with one +// element per diff layer. The returned combo iterator can be used to walk over +// the entire layer stack simultaneously. +func newFastIterator(db *Database, root common.Hash, account common.Hash, seek common.Hash, accountIterator bool) (*fastIterator, error) { + current := db.tree.get(root) + if current == nil { + return nil, fmt.Errorf("unknown layer: %x", root) + } + fi := &fastIterator{ + account: accountIterator, + } + for depth := 0; current != nil; depth++ { + if accountIterator { + switch dl := current.(type) { + case *diskLayer: + fi.iterators = append(fi.iterators, &weightedIterator{ + // The state set in the disk layer is mutable, and the entire state becomes stale + // if a diff layer above is merged into it. Therefore, staleness must be checked, + // and the storage slot should be retrieved with read lock protection. + it: newDiffAccountIterator(seek, dl.buffer.states, func(hash common.Hash) ([]byte, error) { + dl.lock.RLock() + defer dl.lock.RUnlock() + + if dl.stale { + return nil, errSnapshotStale + } + return dl.buffer.states.mustAccount(hash) + }), + priority: depth, + }) + fi.iterators = append(fi.iterators, &weightedIterator{ + it: newDiskAccountIterator(dl.db.diskdb, seek), + priority: depth + 1, + }) + case *diffLayer: + // The state set in diff layer is immutable and will never be stale, + // so the read lock protection is unnecessary. + fi.iterators = append(fi.iterators, &weightedIterator{ + it: newDiffAccountIterator(seek, dl.states.stateSet, dl.states.mustAccount), + priority: depth, + }) + } + } else { + switch dl := current.(type) { + case *diskLayer: + fi.iterators = append(fi.iterators, &weightedIterator{ + // The state set in the disk layer is mutable, and the entire state becomes stale + // if a diff layer above is merged into it. Therefore, staleness must be checked, + // and the storage slot should be retrieved with read lock protection. + it: newDiffStorageIterator(account, seek, dl.buffer.states, func(addrHash common.Hash, slotHash common.Hash) ([]byte, error) { + dl.lock.RLock() + defer dl.lock.RUnlock() + + if dl.stale { + return nil, errSnapshotStale + } + return dl.buffer.states.mustStorage(addrHash, slotHash) + }), + priority: depth, + }) + fi.iterators = append(fi.iterators, &weightedIterator{ + it: newDiskStorageIterator(dl.db.diskdb, account, seek), + priority: depth + 1, + }) + case *diffLayer: + // The state set in diff layer is immutable and will never be stale, + // so the read lock protection is unnecessary. + fi.iterators = append(fi.iterators, &weightedIterator{ + it: newDiffStorageIterator(account, seek, dl.states.stateSet, dl.states.mustStorage), + priority: depth, + }) + } + } + current = current.parentLayer() + } + fi.init() + return fi, nil +} + +// init walks over all the iterators and resolves any clashes between them, after +// which it prepares the stack for step-by-step iteration. +func (fi *fastIterator) init() { + // Track which account hashes are iterators positioned on + var positioned = make(map[common.Hash]int) + + // Position all iterators and track how many remain live + for i := 0; i < len(fi.iterators); i++ { + // Retrieve the first element and if it clashes with a previous iterator, + // advance either the current one or the old one. Repeat until nothing is + // clashing anymore. + it := fi.iterators[i] + for { + // If the iterator is exhausted, drop it off the end + if !it.it.Next() { + it.it.Release() + last := len(fi.iterators) - 1 + + fi.iterators[i] = fi.iterators[last] + fi.iterators[last] = nil + fi.iterators = fi.iterators[:last] + + i-- + break + } + // The iterator is still alive, check for collisions with previous ones + hash := it.it.Hash() + if other, exist := positioned[hash]; !exist { + positioned[hash] = i + break + } else { + // Iterators collide, one needs to be progressed, use priority to + // determine which. + // + // This whole else-block can be avoided, if we instead + // do an initial priority-sort of the iterators. If we do that, + // then we'll only wind up here if a lower-priority (preferred) iterator + // has the same value, and then we will always just continue. + // However, it costs an extra sort, so it's probably not better + if fi.iterators[other].priority < it.priority { + // The 'it' should be progressed + continue + } else { + // The 'other' should be progressed, swap them + it = fi.iterators[other] + fi.iterators[other], fi.iterators[i] = fi.iterators[i], fi.iterators[other] + continue + } + } + } + } + // Re-sort the entire list + slices.SortFunc(fi.iterators, func(a, b *weightedIterator) int { return a.Cmp(b) }) + fi.initiated = false +} + +// Next steps the iterator forward one element, returning false if exhausted. +func (fi *fastIterator) Next() bool { + if len(fi.iterators) == 0 { + return false + } + if !fi.initiated { + // Don't forward first time -- we had to 'Next' once in order to + // do the sorting already + fi.initiated = true + if fi.account { + fi.curAccount = fi.iterators[0].it.(AccountIterator).Account() + } else { + fi.curSlot = fi.iterators[0].it.(StorageIterator).Slot() + } + if innerErr := fi.iterators[0].it.Error(); innerErr != nil { + fi.fail = innerErr + return false + } + if fi.curAccount != nil || fi.curSlot != nil { + return true + } + // Implicit else: we've hit a nil-account or nil-slot, and need to + // fall through to the loop below to land on something non-nil + } + // If an account or a slot is deleted in one of the layers, the key will + // still be there, but the actual value will be nil. However, the iterator + // should not export nil-values (but instead simply omit the key), so we + // need to loop here until we either + // - get a non-nil value, + // - hit an error, + // - or exhaust the iterator + for { + if !fi.next(0) { + return false // exhausted + } + if fi.account { + fi.curAccount = fi.iterators[0].it.(AccountIterator).Account() + } else { + fi.curSlot = fi.iterators[0].it.(StorageIterator).Slot() + } + if innerErr := fi.iterators[0].it.Error(); innerErr != nil { + fi.fail = innerErr + return false // error + } + if fi.curAccount != nil || fi.curSlot != nil { + break // non-nil value found + } + } + return true +} + +// next handles the next operation internally and should be invoked when we know +// that two elements in the list may have the same value. +// +// For example, if the iterated hashes become [2,3,5,5,8,9,10], then we should +// invoke next(3), which will call Next on elem 3 (the second '5') and will +// cascade along the list, applying the same operation if needed. +func (fi *fastIterator) next(idx int) bool { + // If this particular iterator got exhausted, remove it and return true (the + // next one is surely not exhausted yet, otherwise it would have been removed + // already). + if it := fi.iterators[idx].it; !it.Next() { + it.Release() + + fi.iterators = append(fi.iterators[:idx], fi.iterators[idx+1:]...) + return len(fi.iterators) > 0 + } + // If there's no one left to cascade into, return + if idx == len(fi.iterators)-1 { + return true + } + // We next-ed the iterator at 'idx', now we may have to re-sort that element + var ( + cur, next = fi.iterators[idx], fi.iterators[idx+1] + curHash, nextHash = cur.it.Hash(), next.it.Hash() + ) + if diff := bytes.Compare(curHash[:], nextHash[:]); diff < 0 { + // It is still in correct place + return true + } else if diff == 0 && cur.priority < next.priority { + // So still in correct place, but we need to iterate on the next + fi.next(idx + 1) + return true + } + // At this point, the iterator is in the wrong location, but the remaining + // list is sorted. Find out where to move the item. + clash := -1 + index := sort.Search(len(fi.iterators), func(n int) bool { + // The iterator always advances forward, so anything before the old slot + // is known to be behind us, so just skip them altogether. This actually + // is an important clause since the sort order got invalidated. + if n < idx { + return false + } + if n == len(fi.iterators)-1 { + // Can always place an elem last + return true + } + nextHash := fi.iterators[n+1].it.Hash() + if diff := bytes.Compare(curHash[:], nextHash[:]); diff < 0 { + return true + } else if diff > 0 { + return false + } + // The elem we're placing it next to has the same value, + // so whichever winds up on n+1 will need further iteration + clash = n + 1 + + return cur.priority < fi.iterators[n+1].priority + }) + fi.move(idx, index) + if clash != -1 { + fi.next(clash) + } + return true +} + +// move advances an iterator to another position in the list. +func (fi *fastIterator) move(index, newpos int) { + elem := fi.iterators[index] + copy(fi.iterators[index:], fi.iterators[index+1:newpos+1]) + fi.iterators[newpos] = elem +} + +// Error returns any failure that occurred during iteration, which might have +// caused a premature iteration exit (e.g. snapshot stack becoming stale). +func (fi *fastIterator) Error() error { + return fi.fail +} + +// Hash returns the current key +func (fi *fastIterator) Hash() common.Hash { + return fi.iterators[0].it.Hash() +} + +// Account returns the current account blob. +// Note the returned account is not a copy, please don't modify it. +func (fi *fastIterator) Account() []byte { + return fi.curAccount +} + +// Slot returns the current storage slot. +// Note the returned slot is not a copy, please don't modify it. +func (fi *fastIterator) Slot() []byte { + return fi.curSlot +} + +// Release iterates over all the remaining live layer iterators and releases each +// of them individually. +func (fi *fastIterator) Release() { + for _, it := range fi.iterators { + it.it.Release() + } + fi.iterators = nil +} + +// Debug is a convenience helper during testing +func (fi *fastIterator) Debug() { + for _, it := range fi.iterators { + fmt.Printf("[p=%v v=%v] ", it.priority, it.it.Hash()[0]) + } + fmt.Println() +} + +// newFastAccountIterator creates a new hierarchical account iterator with one +// element per diff layer. The returned combo iterator can be used to walk over +// the entire snapshot diff stack simultaneously. +func newFastAccountIterator(db *Database, root common.Hash, seek common.Hash) (AccountIterator, error) { + return newFastIterator(db, root, common.Hash{}, seek, true) +} + +// newFastStorageIterator creates a new hierarchical storage iterator with one +// element per diff layer. The returned combo iterator can be used to walk over +// the entire snapshot diff stack simultaneously. +func newFastStorageIterator(db *Database, root common.Hash, account common.Hash, seek common.Hash) (StorageIterator, error) { + return newFastIterator(db, root, account, seek, false) +} diff --git a/triedb/pathdb/iterator_test.go b/triedb/pathdb/iterator_test.go new file mode 100644 index 000000000..48b5870b5 --- /dev/null +++ b/triedb/pathdb/iterator_test.go @@ -0,0 +1,1162 @@ +// Copyright 2024 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 . + +package pathdb + +import ( + "bytes" + "encoding/binary" + "fmt" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/testrand" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/holiman/uint256" +) + +type verifyContent int + +const ( + verifyNothing verifyContent = iota + verifyAccount + verifyStorage +) + +func verifyIterator(t *testing.T, expCount int, it Iterator, verify verifyContent) { + t.Helper() + + var ( + count = 0 + last = common.Hash{} + ) + for it.Next() { + hash := it.Hash() + if bytes.Compare(last[:], hash[:]) >= 0 { + t.Errorf("wrong order: %x >= %x", last, hash) + } + count++ + if verify == verifyAccount && len(it.(AccountIterator).Account()) == 0 { + t.Errorf("iterator returned nil-value for hash %x", hash) + } else if verify == verifyStorage && len(it.(StorageIterator).Slot()) == 0 { + t.Errorf("iterator returned nil-value for hash %x", hash) + } + last = hash + } + if count != expCount { + t.Errorf("iterator count mismatch: have %d, want %d", count, expCount) + } + if err := it.Error(); err != nil { + t.Errorf("iterator failed: %v", err) + } +} + +// randomAccount generates a random account and returns it RLP encoded. +func randomAccount() []byte { + a := &types.StateAccount{ + Balance: uint256.NewInt(rand.Uint64()), + Nonce: rand.Uint64(), + Root: testrand.Hash(), + CodeHash: types.EmptyCodeHash[:], + } + data, _ := rlp.EncodeToBytes(a) + return data +} + +// randomAccountSet generates a set of random accounts with the given strings as +// the account address hashes. +func randomAccountSet(hashes ...string) map[common.Hash][]byte { + accounts := make(map[common.Hash][]byte) + for _, hash := range hashes { + accounts[common.HexToHash(hash)] = randomAccount() + } + return accounts +} + +// randomStorageSet generates a set of random slots with the given strings as +// the slot addresses. +func randomStorageSet(accounts []string, hashes [][]string, nilStorage [][]string) map[common.Hash]map[common.Hash][]byte { + storages := make(map[common.Hash]map[common.Hash][]byte) + for index, account := range accounts { + storages[common.HexToHash(account)] = make(map[common.Hash][]byte) + + if index < len(hashes) { + hashes := hashes[index] + for _, hash := range hashes { + storages[common.HexToHash(account)][common.HexToHash(hash)] = testrand.Bytes(32) + } + } + if index < len(nilStorage) { + nils := nilStorage[index] + for _, hash := range nils { + storages[common.HexToHash(account)][common.HexToHash(hash)] = nil + } + } + } + return storages +} + +// TestAccountIteratorBasics tests some simple single-layer(diff and disk) iteration +func TestAccountIteratorBasics(t *testing.T) { + var ( + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) + ) + // Fill up a parent + for i := 0; i < 100; i++ { + hash := testrand.Hash() + data := testrand.Bytes(32) + accounts[hash] = data + + if rand.Intn(2) == 0 { + accStorage := make(map[common.Hash][]byte) + accStorage[testrand.Hash()] = testrand.Bytes(32) + storage[hash] = accStorage + } + } + states := newStates(accounts, storage) + it := newDiffAccountIterator(common.Hash{}, states, nil) + verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + //db := rawdb.NewMemoryDatabase() + //batch := db.NewBatch() + //states.write(db, batch, nil, nil) + //batch.Write() + //it = newDiskAccountIterator(db, common.Hash{}) + //verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator +} + +// TestStorageIteratorBasics tests some simple single-layer(diff and disk) iteration for storage +func TestStorageIteratorBasics(t *testing.T) { + var ( + nilStorage = make(map[common.Hash]int) + accounts = make(map[common.Hash][]byte) + storage = make(map[common.Hash]map[common.Hash][]byte) + ) + // Fill some random data + for i := 0; i < 10; i++ { + hash := testrand.Hash() + accounts[hash] = testrand.Bytes(32) + + accStorage := make(map[common.Hash][]byte) + var nilstorage int + for i := 0; i < 100; i++ { + if rand.Intn(2) == 0 { + accStorage[testrand.Hash()] = testrand.Bytes(32) + } else { + accStorage[testrand.Hash()] = nil // delete slot + nilstorage += 1 + } + } + storage[hash] = accStorage + nilStorage[hash] = nilstorage + } + states := newStates(accounts, storage) + for account := range accounts { + it := newDiffStorageIterator(account, common.Hash{}, states, nil) + verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator + } + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + //db := rawdb.NewMemoryDatabase() + //batch := db.NewBatch() + //states.write(db, batch, nil, nil) + //batch.Write() + //for account := range accounts { + // it := newDiskStorageIterator(db, account, common.Hash{}) + // verifyIterator(t, 100-nilStorage[account], it, verifyNothing) // Nil is allowed for single layer iterator + //} +} + +type testIterator struct { + values []byte +} + +func newTestIterator(values ...byte) *testIterator { + return &testIterator{values} +} + +func (ti *testIterator) Seek(common.Hash) { + panic("implement me") +} + +func (ti *testIterator) Next() bool { + ti.values = ti.values[1:] + return len(ti.values) > 0 +} + +func (ti *testIterator) Error() error { + return nil +} + +func (ti *testIterator) Hash() common.Hash { + return common.BytesToHash([]byte{ti.values[0]}) +} + +func (ti *testIterator) Account() []byte { + return nil +} + +func (ti *testIterator) Slot() []byte { + return nil +} + +func (ti *testIterator) Release() {} + +func TestFastIteratorBasics(t *testing.T) { + type testCase struct { + lists [][]byte + expKeys []byte + } + for i, tc := range []testCase{ + {lists: [][]byte{{0, 1, 8}, {1, 2, 8}, {2, 9}, {4}, + {7, 14, 15}, {9, 13, 15, 16}}, + expKeys: []byte{0, 1, 2, 4, 7, 8, 9, 13, 14, 15, 16}}, + {lists: [][]byte{{0, 8}, {1, 2, 8}, {7, 14, 15}, {8, 9}, + {9, 10}, {10, 13, 15, 16}}, + expKeys: []byte{0, 1, 2, 7, 8, 9, 10, 13, 14, 15, 16}}, + } { + var iterators []*weightedIterator + for i, data := range tc.lists { + it := newTestIterator(data...) + iterators = append(iterators, &weightedIterator{it, i}) + } + fi := &fastIterator{ + iterators: iterators, + initiated: false, + } + count := 0 + for fi.Next() { + if got, exp := fi.Hash()[31], tc.expKeys[count]; exp != got { + t.Errorf("tc %d, [%d]: got %d exp %d", i, count, got, exp) + } + count++ + } + } +} + +// TestAccountIteratorTraversal tests some simple multi-layer iteration. +func TestAccountIteratorTraversal(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Stack three diff layers on top with various overlaps + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + + // Verify the single and multi-layer iterators + head := db.tree.get(common.HexToHash("0x04")) + + // singleLayer: 0xcc, 0xf0, 0xff + it := newDiffAccountIterator(common.Hash{}, head.(*diffLayer).states.stateSet, nil) + verifyIterator(t, 3, it, verifyNothing) + + // binaryIterator: 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xf0, 0xff + verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount) + + // fastIterator: 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xf0, 0xff + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.Hash{}) + verifyIterator(t, 7, it, verifyAccount) + it.Release() + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + // Test after persist some bottom-most layers into the disk, + // the functionalities still work. + //db.tree.cap(common.HexToHash("0x04"), 2) + + //head = db.tree.get(common.HexToHash("0x04")) + //verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) + // + //it, _ = db.AccountIterator(common.HexToHash("0x04"), common.Hash{}) + //verifyIterator(t, 7, it, verifyAccount) + //it.Release() +} + +func TestStorageIteratorTraversal(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Stack three diff layers on top with various overlaps + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil), nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 0, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil)) + + // Verify the single and multi-layer iterators + head := db.tree.get(common.HexToHash("0x04")) + + // singleLayer: 0x1, 0x2, 0x3 + diffIter := newDiffStorageIterator(common.HexToHash("0xaa"), common.Hash{}, head.(*diffLayer).states.stateSet, nil) + verifyIterator(t, 3, diffIter, verifyNothing) + + // binaryIterator: 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 + verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage) + + // fastIterator: 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 + it, _ := db.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 6, it, verifyStorage) + it.Release() + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + // Test after persist some bottom-most layers into the disk, + // the functionalities still work. + //db.tree.cap(common.HexToHash("0x04"), 2) + //verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) + // + //it, _ = db.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) + //verifyIterator(t, 6, it, verifyStorage) + //it.Release() +} + +// TestAccountIteratorTraversalValues tests some multi-layer iteration, where we +// also expect the correct values to show up. +func TestAccountIteratorTraversalValues(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Create a batch of account sets to seed subsequent layers with + var ( + a = make(map[common.Hash][]byte) + b = make(map[common.Hash][]byte) + c = make(map[common.Hash][]byte) + d = make(map[common.Hash][]byte) + e = make(map[common.Hash][]byte) + f = make(map[common.Hash][]byte) + g = make(map[common.Hash][]byte) + h = make(map[common.Hash][]byte) + ) + for i := byte(2); i < 0xff; i++ { + a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + if i > 20 && i%2 == 0 { + b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + } + if i%4 == 0 { + c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + } + if i%7 == 0 { + d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + } + if i%8 == 0 { + e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + } + if i > 50 || i < 85 { + f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + } + if i%64 == 0 { + g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + } + if i%128 == 0 { + h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + } + } + // Assemble a stack of snapshots from the account layers + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(a, nil, nil, nil)) + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(b, nil, nil, nil)) + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(c, nil, nil, nil)) + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(d, nil, nil, nil)) + db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(e, nil, nil, nil)) + db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(f, nil, nil, nil)) + db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(g, nil, nil, nil)) + db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(h, nil, nil, nil)) + + // binaryIterator + r, _ := db.StateReader(common.HexToHash("0x09")) + head := db.tree.get(common.HexToHash("0x09")) + it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + for it.Next() { + hash := it.Hash() + want, err := r.(*reader).AccountRLP(hash) + if err != nil { + t.Fatalf("failed to retrieve expected account: %v", err) + } + if have := it.Account(); !bytes.Equal(want, have) { + t.Fatalf("hash %x: account mismatch: have %x, want %x", hash, have, want) + } + } + it.Release() + + // fastIterator + it, _ = db.AccountIterator(common.HexToHash("0x09"), common.Hash{}) + for it.Next() { + hash := it.Hash() + want, err := r.(*reader).AccountRLP(hash) + if err != nil { + t.Fatalf("failed to retrieve expected account: %v", err) + } + if have := it.Account(); !bytes.Equal(want, have) { + t.Fatalf("hash %x: account mismatch: have %x, want %x", hash, have, want) + } + } + it.Release() + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + // Test after persist some bottom-most layers into the disk, + // the functionalities still work. + //db.tree.cap(common.HexToHash("0x09"), 2) + // + //it, _ = db.AccountIterator(common.HexToHash("0x09"), common.Hash{}) + //for it.Next() { + // hash := it.Hash() + // account, err := head.Account(hash) + // if err != nil { + // t.Fatalf("failed to retrieve expected account: %v", err) + // } + // want, _ := rlp.EncodeToBytes(account) + // if have := it.Account(); !bytes.Equal(want, have) { + // t.Fatalf("hash %x: account mismatch: have %x, want %x", hash, have, want) + // } + //} + //it.Release() +} + +func TestStorageIteratorTraversalValues(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + wrapStorage := func(storage map[common.Hash][]byte) map[common.Hash]map[common.Hash][]byte { + return map[common.Hash]map[common.Hash][]byte{ + common.HexToHash("0xaa"): storage, + } + } + // Create a batch of storage sets to seed subsequent layers with + var ( + a = make(map[common.Hash][]byte) + b = make(map[common.Hash][]byte) + c = make(map[common.Hash][]byte) + d = make(map[common.Hash][]byte) + e = make(map[common.Hash][]byte) + f = make(map[common.Hash][]byte) + g = make(map[common.Hash][]byte) + h = make(map[common.Hash][]byte) + ) + for i := byte(2); i < 0xff; i++ { + a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + if i > 20 && i%2 == 0 { + b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + } + if i%4 == 0 { + c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + } + if i%7 == 0 { + d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + } + if i%8 == 0 { + e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + } + if i > 50 || i < 85 { + f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + } + if i%64 == 0 { + g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + } + if i%128 == 0 { + h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + } + } + // Assemble a stack of snapshots from the account layers + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(a), nil, nil)) + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(b), nil, nil)) + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(c), nil, nil)) + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(d), nil, nil)) + db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(e), nil, nil)) + db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(f), nil, nil)) + db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(g), nil, nil)) + db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(h), nil, nil)) + + // binaryIterator + r, _ := db.StateReader(common.HexToHash("0x09")) + head := db.tree.get(common.HexToHash("0x09")) + it := head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}) + for it.Next() { + hash := it.Hash() + want, err := r.Storage(common.HexToHash("0xaa"), hash) + if err != nil { + t.Fatalf("failed to retrieve expected account: %v", err) + } + if have := it.Slot(); !bytes.Equal(want, have) { + t.Fatalf("hash %x: account mismatch: have %x, want %x", hash, have, want) + } + } + it.Release() + + // fastIterator + it, _ = db.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{}) + for it.Next() { + hash := it.Hash() + want, err := r.Storage(common.HexToHash("0xaa"), hash) + if err != nil { + t.Fatalf("failed to retrieve expected storage slot: %v", err) + } + if have := it.Slot(); !bytes.Equal(want, have) { + t.Fatalf("hash %x: slot mismatch: have %x, want %x", hash, have, want) + } + } + it.Release() + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + // Test after persist some bottom-most layers into the disk, + // the functionalities still work. + //db.tree.cap(common.HexToHash("0x09"), 2) + // + //it, _ = db.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{}) + //for it.Next() { + // hash := it.Hash() + // want, err := head.Storage(common.HexToHash("0xaa"), hash) + // if err != nil { + // t.Fatalf("failed to retrieve expected slot: %v", err) + // } + // if have := it.Slot(); !bytes.Equal(want, have) { + // t.Fatalf("hash %x: slot mismatch: have %x, want %x", hash, have, want) + // } + //} + //it.Release() +} + +// This testcase is notorious, all layers contain the exact same 200 accounts. +func TestAccountIteratorLargeTraversal(t *testing.T) { + // Create a custom account factory to recreate the same addresses + makeAccounts := func(num int) map[common.Hash][]byte { + accounts := make(map[common.Hash][]byte) + for i := 0; i < num; i++ { + h := common.Hash{} + binary.BigEndian.PutUint64(h[:], uint64(i+1)) + accounts[h] = randomAccount() + } + return accounts + } + // Build up a large stack of snapshots + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + for i := 1; i < 128; i++ { + parent := types.EmptyRootHash + if i == 1 { + parent = common.HexToHash(fmt.Sprintf("0x%02x", i)) + } + db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), parent, uint64(i), trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil)) + } + // Iterate the entire stack and ensure everything is hit only once + head := db.tree.get(common.HexToHash("0x80")) + verifyIterator(t, 200, newDiffAccountIterator(common.Hash{}, head.(*diffLayer).states.stateSet, nil), verifyNothing) + verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount) + + it, _ := db.AccountIterator(common.HexToHash("0x80"), common.Hash{}) + verifyIterator(t, 200, it, verifyAccount) + it.Release() + + // TODO reenable these tests once the persistent state iteration + // is implemented. + + // Test after persist some bottom-most layers into the disk, + // the functionalities still work. + //db.tree.cap(common.HexToHash("0x80"), 2) + // + //verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) + // + //it, _ = db.AccountIterator(common.HexToHash("0x80"), common.Hash{}) + //verifyIterator(t, 200, it, verifyAccount) + //it.Release() +} + +// TestAccountIteratorFlattening tests what happens when we +// - have a live iterator on child C (parent C1 -> C2 .. CN) +// - flattens C2 all the way into CN +// - continues iterating +func TestAccountIteratorFlattening(t *testing.T) { + config := &Config{ + WriteBufferSize: 10 * 1024, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Create a stack of diffs on top + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + + // Create a binary iterator and flatten the data from underneath it + head := db.tree.get(common.HexToHash("0x04")) + bit := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + defer bit.Release() + + // Create a fast iterator and flatten the data from underneath it + fit, _ := db.AccountIterator(common.HexToHash("0x04"), common.Hash{}) + defer fit.Release() + + if err := db.tree.cap(common.HexToHash("0x04"), 1); err != nil { + t.Fatalf("failed to flatten snapshot stack: %v", err) + } + verifyIterator(t, 7, bit, verifyAccount) + verifyIterator(t, 7, fit, verifyAccount) +} + +func TestAccountIteratorSeek(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + + // Account set is now + // 02: aa, ee, f0, ff + // 03: aa, bb, dd, ee, f0 (, f0), ff + // 04: aa, bb, cc, dd, ee, f0 (, f0), ff (, ff) + // Construct various iterators and ensure their traversal is correct + it, _ := db.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xdd")) + defer it.Release() + verifyIterator(t, 3, it, verifyAccount) // expected: ee, f0, ff + + it, _ = db.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xaa")) + defer it.Release() + verifyIterator(t, 4, it, verifyAccount) // expected: aa, ee, f0, ff + + it, _ = db.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xff")) + defer it.Release() + verifyIterator(t, 1, it, verifyAccount) // expected: ff + + it, _ = db.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xff1")) + defer it.Release() + verifyIterator(t, 0, it, verifyAccount) // expected: nothing + + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xbb")) + defer it.Release() + verifyIterator(t, 6, it, verifyAccount) // expected: bb, cc, dd, ee, f0, ff + + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xef")) + defer it.Release() + verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff + + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xf0")) + defer it.Release() + verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff + + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xff")) + defer it.Release() + verifyIterator(t, 1, it, verifyAccount) // expected: ff + + it, _ = db.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xff1")) + defer it.Release() + verifyIterator(t, 0, it, verifyAccount) // expected: nothing +} + +func TestStorageIteratorSeek(t *testing.T) { + t.Run("fast", func(t *testing.T) { + testStorageIteratorSeek(t, func(db *Database, root, account, seek common.Hash) StorageIterator { + it, _ := db.StorageIterator(root, account, seek) + return it + }) + }) + t.Run("binary", func(t *testing.T) { + testStorageIteratorSeek(t, func(db *Database, root, account, seek common.Hash) StorageIterator { + return db.tree.get(root).(*diffLayer).newBinaryStorageIterator(account, seek) + }) + }) +} + +func testStorageIteratorSeek(t *testing.T, newIterator func(db *Database, root, account, seek common.Hash) StorageIterator) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Stack three diff layers on top with various overlaps + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil), nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil), nil, nil)) + + // Account set is now + // 02: 01, 03, 05 + // 03: 01, 02, 03, 05 (, 05), 06 + // 04: 01(, 01), 02, 03, 05(, 05, 05), 06, 08 + // Construct various iterators and ensure their traversal is correct + it := newIterator(db, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x01")) + defer it.Release() + verifyIterator(t, 3, it, verifyStorage) // expected: 01, 03, 05 + + it = newIterator(db, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x02")) + defer it.Release() + verifyIterator(t, 2, it, verifyStorage) // expected: 03, 05 + + it = newIterator(db, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x5")) + defer it.Release() + verifyIterator(t, 1, it, verifyStorage) // expected: 05 + + it = newIterator(db, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x6")) + defer it.Release() + verifyIterator(t, 0, it, verifyStorage) // expected: nothing + + it = newIterator(db, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x01")) + defer it.Release() + verifyIterator(t, 6, it, verifyStorage) // expected: 01, 02, 03, 05, 06, 08 + + it = newIterator(db, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x05")) + defer it.Release() + verifyIterator(t, 3, it, verifyStorage) // expected: 05, 06, 08 + + it = newIterator(db, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x08")) + defer it.Release() + verifyIterator(t, 1, it, verifyStorage) // expected: 08 + + it = newIterator(db, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x09")) + defer it.Release() + verifyIterator(t, 0, it, verifyStorage) // expected: nothing +} + +// TestAccountIteratorDeletions tests that the iterator behaves correct when there are +// deleted accounts (where the Account() value is nil). The iterator +// should not output any accounts or nil-values for those cases. +func TestAccountIteratorDeletions(t *testing.T) { + t.Run("fast", func(t *testing.T) { + testAccountIteratorDeletions(t, func(db *Database, root, seek common.Hash) AccountIterator { + it, _ := db.AccountIterator(root, seek) + return it + }) + }) + t.Run("binary", func(t *testing.T) { + testAccountIteratorDeletions(t, func(db *Database, root, seek common.Hash) AccountIterator { + return db.tree.get(root).(*diffLayer).newBinaryAccountIterator(seek) + }) + }) +} + +func testAccountIteratorDeletions(t *testing.T, newIterator func(db *Database, root, seek common.Hash) AccountIterator) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Stack three diff layers on top with various overlaps + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0x11", "0x22", "0x33"), nil, nil, nil)) + + deleted := common.HexToHash("0x22") + accounts := randomAccountSet("0x11", "0x33") + accounts[deleted] = nil + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(accounts, nil, nil, nil)) + + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0x33", "0x44", "0x55"), nil, nil, nil)) + + // The output should be 11,33,44,55 + it := newIterator(db, common.HexToHash("0x04"), common.Hash{}) + // Do a quick check + verifyIterator(t, 4, it, verifyAccount) + it.Release() + + // And a more detailed verification that we indeed do not see '0x22' + it = newIterator(db, common.HexToHash("0x04"), common.Hash{}) + defer it.Release() + for it.Next() { + hash := it.Hash() + if it.Account() == nil { + t.Errorf("iterator returned nil-value for hash %x", hash) + } + if hash == deleted { + t.Errorf("expected deleted elem %x to not be returned by iterator", deleted) + } + } +} + +func TestStorageIteratorDeletions(t *testing.T) { + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // Stack three diff layers on top with various overlaps + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil)) + + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}), nil, nil)) + + // The output should be 02,04,05,06 + it, _ := db.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 4, it, verifyStorage) + it.Release() + + // The output should be 04,05,06 + it, _ = db.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.HexToHash("0x03")) + verifyIterator(t, 3, it, verifyStorage) + it.Release() + + // Destruct the whole storage + accounts := map[common.Hash][]byte{ + common.HexToHash("0xaa"): nil, + } + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(accounts, randomStorageSet([]string{"0xaa"}, nil, [][]string{{"0x02", "0x04", "0x05", "0x06"}}), nil, nil)) + + it, _ = db.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 0, it, verifyStorage) + it.Release() + + // Re-insert the slots of the same account + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 4, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil), nil, nil)) + + // The output should be 07,08,09 + it, _ = db.StorageIterator(common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 3, it, verifyStorage) + it.Release() + + // Destruct the whole storage but re-create the account in the same layer + db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 5, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}}), nil, nil)) + + it, _ = db.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) + verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 + it.Release() + + verifyIterator(t, 2, db.tree.get(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage) +} + +// TestStaleIterator tests if the iterator could correctly terminate the iteration +// if the associated layers are outdated. +func TestStaleIterator(t *testing.T) { + testStaleIterator(t, func(db *Database, hash common.Hash) Iterator { + it, _ := db.StorageIterator(hash, common.HexToHash("0xaa"), common.Hash{}) + return it + }) + testStaleIterator(t, func(db *Database, hash common.Hash) Iterator { + head := db.tree.get(hash) + return head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}) + }) +} + +func testStaleIterator(t *testing.T, newIter func(db *Database, hash common.Hash) Iterator) { + config := &Config{ + WriteBufferSize: 16 * 1024 * 1024, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + // [02 (disk), 03] + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01"}}, nil), nil, nil)) + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02"}}, nil), nil, nil)) + db.tree.cap(common.HexToHash("0x03"), 1) + + // [02 (disk), 03, 04] + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x03"}}, nil), nil, nil)) + iter := newIter(db, common.HexToHash("0x04")) + + // [04 (disk), 05] + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 3, trienode.NewMergedNodeSet(), + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04"}}, nil), nil, nil)) + db.tree.cap(common.HexToHash("0x05"), 1) + + // Iterator can't finish the traversal as the layer 02 has becoming stale. + for iter.Next() { + } + err := iter.Error() + t.Log(err) + if err == nil { + t.Fatalf("Expected iterator error is not reported") + } +} + +// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the +// exact same 200 accounts. That means that we need to process 2000 items, but +// only spit out 200 values eventually. +// +// The value-fetching benchmark is easy on the binary iterator, since it never has to reach +// down at any depth for retrieving the values -- all are on the topmost layer +// +// BenchmarkAccountIteratorTraversal/binary_iterator_keys-8 759984 1566 ns/op +// BenchmarkAccountIteratorTraversal/binary_iterator_values-8 150028 7900 ns/op +// BenchmarkAccountIteratorTraversal/fast_iterator_keys-8 172809 7006 ns/op +// BenchmarkAccountIteratorTraversal/fast_iterator_values-8 165112 7658 ns/op +func BenchmarkAccountIteratorTraversal(b *testing.B) { + // Create a custom account factory to recreate the same addresses + makeAccounts := func(num int) map[common.Hash][]byte { + accounts := make(map[common.Hash][]byte) + for i := 0; i < num; i++ { + h := common.Hash{} + binary.BigEndian.PutUint64(h[:], uint64(i+1)) + accounts[h] = randomAccount() + } + return accounts + } + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + for i := 1; i <= 100; i++ { + parent := types.EmptyRootHash + if i == 1 { + parent = common.HexToHash(fmt.Sprintf("0x%02x", i)) + } + db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), parent, uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil)) + } + // We call this once before the benchmark, so the creation of + // sorted accountlists are not included in the results. + head := db.tree.get(common.HexToHash("0x65")) + head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + + b.Run("binary iterator keys", func(b *testing.B) { + for i := 0; i < b.N; i++ { + got := 0 + it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + for it.Next() { + got++ + } + if exp := 200; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("binary iterator values", func(b *testing.B) { + for i := 0; i < b.N; i++ { + got := 0 + it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + for it.Next() { + got++ + head.(*diffLayer).account(it.Hash(), 0) + } + if exp := 200; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("fast iterator keys", func(b *testing.B) { + for i := 0; i < b.N; i++ { + it, _ := db.AccountIterator(common.HexToHash("0x65"), common.Hash{}) + defer it.Release() + + got := 0 + for it.Next() { + got++ + } + if exp := 200; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("fast iterator values", func(b *testing.B) { + for i := 0; i < b.N; i++ { + it, _ := db.AccountIterator(common.HexToHash("0x65"), common.Hash{}) + defer it.Release() + + got := 0 + for it.Next() { + got++ + it.Account() + } + if exp := 200; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) +} + +// BenchmarkAccountIteratorLargeBaselayer is a pretty realistic benchmark, where +// the baselayer is a lot larger than the upper layer. +// +// This is heavy on the binary iterator, which in most cases will have to +// call recursively 100 times for the majority of the values +// +// BenchmarkAccountIteratorLargeBaselayer/binary_iterator_(keys)-6 514 1971999 ns/op +// BenchmarkAccountIteratorLargeBaselayer/binary_iterator_(values)-6 61 18997492 ns/op +// BenchmarkAccountIteratorLargeBaselayer/fast_iterator_(keys)-6 10000 114385 ns/op +// BenchmarkAccountIteratorLargeBaselayer/fast_iterator_(values)-6 4047 296823 ns/op +func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { + // Create a custom account factory to recreate the same addresses + makeAccounts := func(num int) map[common.Hash][]byte { + accounts := make(map[common.Hash][]byte) + for i := 0; i < num; i++ { + h := common.Hash{} + binary.BigEndian.PutUint64(h[:], uint64(i+1)) + accounts[h] = randomAccount() + } + return accounts + } + config := &Config{ + WriteBufferSize: 0, + } + db := New(rawdb.NewMemoryDatabase(), config, false) + // db.WaitGeneration() + + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(2000), nil, nil, nil)) + for i := 2; i <= 100; i++ { + db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(20), nil, nil, nil)) + } + // We call this once before the benchmark, so the creation of + // sorted accountlists are not included in the results. + head := db.tree.get(common.HexToHash("0x65")) + head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + + b.Run("binary iterator (keys)", func(b *testing.B) { + for i := 0; i < b.N; i++ { + got := 0 + it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + for it.Next() { + got++ + } + if exp := 2000; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("binary iterator (values)", func(b *testing.B) { + for i := 0; i < b.N; i++ { + got := 0 + it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{}) + for it.Next() { + got++ + v := it.Hash() + head.(*diffLayer).account(v, 0) + } + if exp := 2000; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("fast iterator (keys)", func(b *testing.B) { + for i := 0; i < b.N; i++ { + it, _ := db.AccountIterator(common.HexToHash("0x65"), common.Hash{}) + defer it.Release() + + got := 0 + for it.Next() { + got++ + } + if exp := 2000; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) + b.Run("fast iterator (values)", func(b *testing.B) { + for i := 0; i < b.N; i++ { + it, _ := db.AccountIterator(common.HexToHash("0x65"), common.Hash{}) + defer it.Release() + + got := 0 + for it.Next() { + it.Account() + got++ + } + if exp := 2000; got != exp { + b.Errorf("iterator len wrong, expected %d, got %d", exp, got) + } + } + }) +} + +/* +func BenchmarkBinaryAccountIteration(b *testing.B) { + benchmarkAccountIteration(b, func(snap snapshot) AccountIterator { + return snap.(*diffLayer).newBinaryAccountIterator() + }) +} + +func BenchmarkFastAccountIteration(b *testing.B) { + benchmarkAccountIteration(b, newFastAccountIterator) +} + +func benchmarkAccountIteration(b *testing.B, iterator func(snap snapshot) AccountIterator) { + // Create a diff stack and randomize the accounts across them + layers := make([]map[common.Hash][]byte, 128) + for i := 0; i < len(layers); i++ { + layers[i] = make(map[common.Hash][]byte) + } + for i := 0; i < b.N; i++ { + depth := rand.Intn(len(layers)) + layers[depth][randomHash()] = randomAccount() + } + stack := snapshot(emptyLayer()) + for _, layer := range layers { + stack = stack.Update(common.Hash{}, layer, nil, nil) + } + // Reset the timers and report all the stats + it := iterator(stack) + + b.ResetTimer() + b.ReportAllocs() + + for it.Next() { + } +} +*/ diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index 4bba813b1..a40440903 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -86,6 +86,17 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, return blob, nil } +// AccountRLP directly retrieves the account associated with a particular hash. +// An error will be returned if the read operation exits abnormally. Specifically, +// if the layer is already stale. +// +// Note: +// - the returned account data is not a copy, please don't modify it +// - no error will be returned if the requested account is not found in database +func (r *reader) AccountRLP(hash common.Hash) ([]byte, error) { + return r.layer.account(hash, 0) +} + // Account directly retrieves the account associated with a particular hash in // the slim data format. An error will be returned if the read operation exits // abnormally. Specifically, if the layer is already stale. diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index 6e633db27..81d34da5d 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -98,6 +98,17 @@ func (s *stateSet) account(hash common.Hash) ([]byte, bool) { return nil, false // account is unknown in this set } +// mustAccount returns the account data associated with the specified address +// hash. The difference is this function will return an error if the account +// is not found. +func (s *stateSet) mustAccount(hash common.Hash) ([]byte, error) { + // If the account is known locally, return it + if data, ok := s.accountData[hash]; ok { + return data, nil + } + return nil, fmt.Errorf("account is not found, %x", hash) +} + // storage returns the storage slot associated with the specified address hash // and storage key hash. func (s *stateSet) storage(accountHash, storageHash common.Hash) ([]byte, bool) { @@ -110,6 +121,19 @@ func (s *stateSet) storage(accountHash, storageHash common.Hash) ([]byte, bool) return nil, false // storage is unknown in this set } +// mustStorage returns the storage slot associated with the specified address +// hash and storage key hash. The difference is this function will return an +// error if the storage slot is not found. +func (s *stateSet) mustStorage(accountHash, storageHash common.Hash) ([]byte, error) { + // If the account is known locally, try to resolve the slot locally + if storage, ok := s.storageData[accountHash]; ok { + if data, ok := storage[storageHash]; ok { + return data, nil + } + } + return nil, fmt.Errorf("storage slot is not found, %x %x", accountHash, storageHash) +} + // check sanitizes accounts and storage slots to ensure the data validity. // Additionally, it computes the total memory size occupied by the maps. func (s *stateSet) check() uint64 { @@ -132,8 +156,6 @@ func (s *stateSet) check() uint64 { // the deleted ones. // // Note, the returned slice is not a copy, so do not modify it. -// -// nolint:unused func (s *stateSet) accountList() []common.Hash { // If an old list already exists, return it s.listLock.RLock() @@ -160,8 +182,6 @@ func (s *stateSet) accountList() []common.Hash { // storage slot. // // Note, the returned slice is not a copy, so do not modify it. -// -// nolint:unused func (s *stateSet) storageList(accountHash common.Hash) []common.Hash { s.listLock.RLock() if _, ok := s.storageData[accountHash]; !ok { diff --git a/triedb/pathdb/states_test.go b/triedb/pathdb/states_test.go index 4557fa958..f097e90e8 100644 --- a/triedb/pathdb/states_test.go +++ b/triedb/pathdb/states_test.go @@ -28,39 +28,39 @@ import ( func TestStatesMerge(t *testing.T) { a := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa0}, - common.Hash{0xb}: {0xb0}, - common.Hash{0xc}: {0xc0}, + {0xa}: {0xa0}, + {0xb}: {0xb0}, + {0xc}: {0xc0}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x10}, common.Hash{0x2}: {0x20}, }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x10}, }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: {0x10}, }, }, ) b := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa1}, - common.Hash{0xb}: {0xb1}, - common.Hash{0xc}: nil, // delete account + {0xa}: {0xa1}, + {0xb}: {0xb1}, + {0xc}: nil, // delete account }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x11}, common.Hash{0x2}: nil, // delete slot common.Hash{0x3}: {0x31}, }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x11}, }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: nil, // delete slot }, }, @@ -116,39 +116,39 @@ func TestStatesMerge(t *testing.T) { func TestStatesRevert(t *testing.T) { a := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa0}, - common.Hash{0xb}: {0xb0}, - common.Hash{0xc}: {0xc0}, + {0xa}: {0xa0}, + {0xb}: {0xb0}, + {0xc}: {0xc0}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x10}, common.Hash{0x2}: {0x20}, }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x10}, }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: {0x10}, }, }, ) b := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa1}, - common.Hash{0xb}: {0xb1}, - common.Hash{0xc}: nil, + {0xa}: {0xa1}, + {0xb}: {0xb1}, + {0xc}: nil, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x11}, common.Hash{0x2}: nil, common.Hash{0x3}: {0x31}, }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x11}, }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: nil, }, }, @@ -156,20 +156,20 @@ func TestStatesRevert(t *testing.T) { a.merge(b) a.revertTo( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa0}, - common.Hash{0xb}: {0xb0}, - common.Hash{0xc}: {0xc0}, + {0xa}: {0xa0}, + {0xb}: {0xb0}, + {0xc}: {0xc0}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x10}, common.Hash{0x2}: {0x20}, common.Hash{0x3}: nil, }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x10}, }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: {0x10}, }, }, @@ -227,14 +227,14 @@ func TestStateRevertAccountNullMarker(t *testing.T) { a := newStates(nil, nil) // empty initial state b := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa}, + {0xa}: {0xa}, }, nil, ) a.merge(b) // create account 0xa a.revertTo( map[common.Hash][]byte{ - common.Hash{0xa}: nil, + {0xa}: nil, }, nil, ) // revert the transition b @@ -253,13 +253,13 @@ func TestStateRevertAccountNullMarker(t *testing.T) { // entry in the set. func TestStateRevertStorageNullMarker(t *testing.T) { a := newStates(map[common.Hash][]byte{ - common.Hash{0xa}: {0xa}, + {0xa}: {0xa}, }, nil) // initial state with account 0xa b := newStates( nil, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x1}, }, }, @@ -268,7 +268,7 @@ func TestStateRevertStorageNullMarker(t *testing.T) { a.revertTo( nil, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: nil, }, }, @@ -286,10 +286,10 @@ func TestStateRevertStorageNullMarker(t *testing.T) { func TestStatesEncode(t *testing.T) { s := newStates( map[common.Hash][]byte{ - common.Hash{0x1}: {0x1}, + {0x1}: {0x1}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0x1}: { + {0x1}: { common.Hash{0x1}: {0x1}, }, }, @@ -313,18 +313,18 @@ func TestStatesEncode(t *testing.T) { func TestStateWithOriginEncode(t *testing.T) { s := NewStateSetWithOrigin( map[common.Hash][]byte{ - common.Hash{0x1}: {0x1}, + {0x1}: {0x1}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0x1}: { + {0x1}: { common.Hash{0x1}: {0x1}, }, }, map[common.Address][]byte{ - common.Address{0x1}: {0x1}, + {0x1}: {0x1}, }, map[common.Address]map[common.Hash][]byte{ - common.Address{0x1}: { + {0x1}: { common.Hash{0x1}: {0x1}, }, }, @@ -359,19 +359,19 @@ func TestStateSizeTracking(t *testing.T) { a := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa0}, // common.HashLength+1 - common.Hash{0xb}: {0xb0}, // common.HashLength+1 - common.Hash{0xc}: {0xc0}, // common.HashLength+1 + {0xa}: {0xa0}, // common.HashLength+1 + {0xb}: {0xb0}, // common.HashLength+1 + {0xc}: {0xc0}, // common.HashLength+1 }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x10}, // 2*common.HashLength+1 common.Hash{0x2}: {0x20}, // 2*common.HashLength+1 }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x10, 0x11, 0x12}, // 2*common.HashLength+3 }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: {0x10}, // 2*common.HashLength+1 }, }, @@ -386,21 +386,21 @@ func TestStateSizeTracking(t *testing.T) { 3*2*common.HashLength /* storage data of 0xc */ b := newStates( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa1, 0xa1}, // common.HashLength+2 - common.Hash{0xb}: {0xb1, 0xb1, 0xb1}, // common.HashLength+3 - common.Hash{0xc}: nil, // common.HashLength, account deletion + {0xa}: {0xa1, 0xa1}, // common.HashLength+2 + {0xb}: {0xb1, 0xb1, 0xb1}, // common.HashLength+3 + {0xc}: nil, // common.HashLength, account deletion }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x11, 0x11, 0x11}, // 2*common.HashLength+3 common.Hash{0x3}: {0x31, 0x31}, // 2*common.HashLength+2, slot creation }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x11, 0x11}, // 2*common.HashLength+2 common.Hash{0x2}: {0x22, 0x22}, // 2*common.HashLength+2, slot creation }, // The storage of 0xc is entirely removed - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: nil, // 2*common.HashLength, slot deletion common.Hash{0x2}: nil, // 2*common.HashLength, slot deletion common.Hash{0x3}: nil, // 2*common.HashLength, slot deletion @@ -424,21 +424,21 @@ func TestStateSizeTracking(t *testing.T) { // Revert the set to original status a.revertTo( map[common.Hash][]byte{ - common.Hash{0xa}: {0xa0}, - common.Hash{0xb}: {0xb0}, - common.Hash{0xc}: {0xc0}, + {0xa}: {0xa0}, + {0xb}: {0xb0}, + {0xc}: {0xc0}, }, map[common.Hash]map[common.Hash][]byte{ - common.Hash{0xa}: { + {0xa}: { common.Hash{0x1}: {0x10}, common.Hash{0x2}: {0x20}, common.Hash{0x3}: nil, // revert slot creation }, - common.Hash{0xb}: { + {0xb}: { common.Hash{0x1}: {0x10, 0x11, 0x12}, common.Hash{0x2}: nil, // revert slot creation }, - common.Hash{0xc}: { + {0xc}: { common.Hash{0x1}: {0x10}, common.Hash{0x2}: {0x20}, // resurrected slot common.Hash{0x3}: {0x30}, // resurrected slot From 53735e3e2b94b9276a7e7354a762f7798318f055 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 17 Dec 2024 08:58:26 +0100 Subject: [PATCH 047/354] core/vm, go.mod: update uint256 and use faster method to write to memory (#30868) Updates geth to use the latest uint256, and use faster memory-writer --- core/vm/memory.go | 3 +-- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/vm/memory.go b/core/vm/memory.go index 1ddd8d1ea..5e11e8374 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -73,8 +73,7 @@ func (m *Memory) Set32(offset uint64, val *uint256.Int) { panic("invalid memory: store empty") } // Fill in relevant bits - b32 := val.Bytes32() - copy(m.store[offset:], b32[:]) + val.PutUint256(m.store[offset:]) } // Resize resizes the memory to size diff --git a/go.mod b/go.mod index 6037650a5..69eef302e 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.3.1 + github.com/holiman/uint256 v1.3.2 github.com/huin/goupnp v1.3.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c diff --git a/go.sum b/go.sum index ba90b6429..96f1bb639 100644 --- a/go.sum +++ b/go.sum @@ -320,8 +320,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= -github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= From 5795556a02eb9851c01bbd1eec27871197702bbb Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 17 Dec 2024 16:12:10 +0800 Subject: [PATCH 048/354] accounts/abi/bind: make it possible to wait for tx hash (#30079) This change adds methods which makes it possible for to wait for a transaction with a specific hash when deploying contracts during abi bind interaction. --------- Co-authored-by: Marius van der Wijden --- accounts/abi/bind/util.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/util.go b/accounts/abi/bind/util.go index b931fbb04..c83116e9a 100644 --- a/accounts/abi/bind/util.go +++ b/accounts/abi/bind/util.go @@ -30,12 +30,18 @@ import ( // WaitMined waits for tx to be mined on the blockchain. // It stops waiting when the context is canceled. func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) { + return WaitMinedHash(ctx, b, tx.Hash()) +} + +// WaitMinedHash waits for a transaction with the provided hash to be mined on the blockchain. +// It stops waiting when the context is canceled. +func WaitMinedHash(ctx context.Context, b DeployBackend, hash common.Hash) (*types.Receipt, error) { queryTicker := time.NewTicker(time.Second) defer queryTicker.Stop() - logger := log.New("hash", tx.Hash()) + logger := log.New("hash", hash) for { - receipt, err := b.TransactionReceipt(ctx, tx.Hash()) + receipt, err := b.TransactionReceipt(ctx, hash) if err == nil { return receipt, nil } @@ -61,7 +67,13 @@ func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) ( if tx.To() != nil { return common.Address{}, errors.New("tx is not contract creation") } - receipt, err := WaitMined(ctx, b, tx) + return WaitDeployedHash(ctx, b, tx.Hash()) +} + +// WaitDeployedHash waits for a contract deployment transaction with the provided hash and returns the on-chain +// contract address when it is mined. It stops waiting when ctx is canceled. +func WaitDeployedHash(ctx context.Context, b DeployBackend, hash common.Hash) (common.Address, error) { + receipt, err := WaitMinedHash(ctx, b, hash) if err != nil { return common.Address{}, err } From a64eec036a9d17e0c1c92862de83e00359c1b5e9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Dec 2024 15:16:17 +0100 Subject: [PATCH 049/354] core: fixes for Prague fork in GenerateChain (#30924) Adding some missing functionality I noticed while updating the hivechain tool for the Prague fork: - we forgot to process the parent block hash - added `ConsensusLayerRequests` to get the requests list of the block --- core/chain_makers.go | 65 +++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 97c785d52..26714845e 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -293,6 +293,41 @@ func (b *BlockGen) OffsetTime(seconds int64) { b.header.Difficulty = b.engine.CalcDifficulty(b.cm, b.header.Time, b.parent.Header()) } +// ConsensusLayerRequests returns the EIP-7685 requests which have accumulated so far. +func (b *BlockGen) ConsensusLayerRequests() [][]byte { + return b.collectRequests(true) +} + +func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) { + statedb := b.statedb + if readonly { + // The system contracts clear themselves on a system-initiated read. + // When reading the requests mid-block, we don't want this behavior, so fork + // off the statedb before executing the system calls. + statedb = statedb.Copy() + } + + if b.cm.config.IsPrague(b.header.Number, b.header.Time) { + requests = [][]byte{} + // EIP-6110 deposits + var blockLogs []*types.Log + for _, r := range b.receipts { + blockLogs = append(blockLogs, r.Logs...) + } + if err := ParseDepositLogs(&requests, blockLogs, b.cm.config); err != nil { + panic(fmt.Sprintf("failed to parse deposit log: %v", err)) + } + // create EVM for system calls + blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) + evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) + // EIP-7002 + ProcessWithdrawalQueue(&requests, evm) + // EIP-7251 + ProcessConsolidationQueue(&requests, evm) + } + return requests +} + // GenerateChain creates a chain of n blocks. The first block's // parent will be the provided parent. db is used to store // intermediate states and should contain the parent's state trie. @@ -330,6 +365,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse b.header.Difficulty = big.NewInt(0) } } + // Mutate the state and block according to any hard-fork specs if daoBlock := config.DAOForkBlock; daoBlock != nil { limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) @@ -342,30 +378,21 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { misc.ApplyDAOHardFork(statedb) } - // Execute any user modifications to the block - if gen != nil { - gen(i, b) - } - var requests [][]byte if config.IsPrague(b.header.Number, b.header.Time) { - requests = [][]byte{} - // EIP-6110 deposits - var blockLogs []*types.Log - for _, r := range b.receipts { - blockLogs = append(blockLogs, r.Logs...) - } - if err := ParseDepositLogs(&requests, blockLogs, config); err != nil { - panic(fmt.Sprintf("failed to parse deposit log: %v", err)) - } - // create EVM for system calls + // EIP-2935 blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) + blockContext.Random = &common.Hash{} // enable post-merge instruction set evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - // EIP-7002 - ProcessWithdrawalQueue(&requests, evm) - // EIP-7251 - ProcessConsolidationQueue(&requests, evm) + ProcessParentBlockHash(b.header.ParentHash, evm) + } + + // Execute any user modifications to the block + if gen != nil { + gen(i, b) } + + requests := b.collectRequests(false) if requests != nil { reqHash := types.CalcRequestsHash(requests) b.header.RequestsHash = &reqHash From a92b8d177193ac21b370bada78146d7f53e430f8 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 17 Dec 2024 18:37:29 +0100 Subject: [PATCH 050/354] core/vm: make all opcodes proper type (#30925) Noticed this omission while doing some work on goevmlab. We don't properly type some of the opcodes, but apparently implicit casting works in all the internal usecases. --- core/vm/opcodes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 162be8f6c..0820b20fb 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -164,7 +164,7 @@ const ( // 0x80 range - dups. const ( - DUP1 = 0x80 + iota + DUP1 OpCode = 0x80 + iota DUP2 DUP3 DUP4 @@ -184,7 +184,7 @@ const ( // 0x90 range - swaps. const ( - SWAP1 = 0x90 + iota + SWAP1 OpCode = 0x90 + iota SWAP2 SWAP3 SWAP4 From e8f02144a93e83e94e5f96199ddf360f8ab455d4 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Dec 2024 19:47:10 +0100 Subject: [PATCH 051/354] core/types, internal/ethapi: fixes for prague RPC encoding (#30926) Fixing some issues I found while regenerating RPC tests for Prague: - Authorization signature values were not encoded as hex - `requestsRoot` in block should be `requestsHash` - `authorizationList` should work for `eth_call` --- core/types/block.go | 2 +- core/types/gen_authorization.go | 16 ++++++++-------- core/types/gen_header_json.go | 4 ++-- core/types/tx_setcode.go | 2 ++ internal/ethapi/api.go | 2 +- internal/ethapi/transaction_args.go | 1 + 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 62c49d7fb..11c9018cc 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -105,7 +105,7 @@ type Header struct { ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` // RequestsHash was added by EIP-7685 and is ignored in legacy headers. - RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` + RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` } // field type overrides for gencodec diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index b598b64ff..cc8fe138e 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -20,16 +20,16 @@ func (a Authorization) MarshalJSON() ([]byte, error) { Address common.Address `json:"address" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` V hexutil.Uint64 `json:"v" gencodec:"required"` - R uint256.Int `json:"r" gencodec:"required"` - S uint256.Int `json:"s" gencodec:"required"` + R hexutil.U256 `json:"r" gencodec:"required"` + S hexutil.U256 `json:"s" gencodec:"required"` } var enc Authorization enc.ChainID = hexutil.Uint64(a.ChainID) enc.Address = a.Address enc.Nonce = hexutil.Uint64(a.Nonce) enc.V = hexutil.Uint64(a.V) - enc.R = a.R - enc.S = a.S + enc.R = hexutil.U256(a.R) + enc.S = hexutil.U256(a.S) return json.Marshal(&enc) } @@ -40,8 +40,8 @@ func (a *Authorization) UnmarshalJSON(input []byte) error { Address *common.Address `json:"address" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` V *hexutil.Uint64 `json:"v" gencodec:"required"` - R *uint256.Int `json:"r" gencodec:"required"` - S *uint256.Int `json:"s" gencodec:"required"` + R *hexutil.U256 `json:"r" gencodec:"required"` + S *hexutil.U256 `json:"s" gencodec:"required"` } var dec Authorization if err := json.Unmarshal(input, &dec); err != nil { @@ -66,10 +66,10 @@ func (a *Authorization) UnmarshalJSON(input []byte) error { if dec.R == nil { return errors.New("missing required field 'r' for Authorization") } - a.R = *dec.R + a.R = uint256.Int(*dec.R) if dec.S == nil { return errors.New("missing required field 's' for Authorization") } - a.S = *dec.S + a.S = uint256.Int(*dec.S) return nil } diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 322c5d564..0af12500b 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -36,7 +36,7 @@ func (h Header) MarshalJSON() ([]byte, error) { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` - RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` + RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` Hash common.Hash `json:"hash"` } var enc Header @@ -88,7 +88,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"` ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` - RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"` + RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index 0fea9a63a..b251cd181 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -83,6 +83,8 @@ type authorizationMarshaling struct { ChainID hexutil.Uint64 Nonce hexutil.Uint64 V hexutil.Uint64 + R hexutil.U256 + S hexutil.U256 } // SignAuth signs the provided authorization. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0fe368f17..4b362de9c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -999,7 +999,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { result["parentBeaconBlockRoot"] = head.ParentBeaconRoot } if head.RequestsHash != nil { - result["requestsRoot"] = head.RequestsHash + result["requestsHash"] = head.RequestsHash } return result } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index b5e569279..89b015f04 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -494,6 +494,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA AccessList: accessList, BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), BlobHashes: args.BlobHashes, + AuthList: args.AuthorizationList, SkipNonceChecks: skipNonceCheck, SkipFromEOACheck: skipEoACheck, } From d00ba7369c6e7cd8837a63daead47ad7beb4295b Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 18 Dec 2024 00:18:36 +0100 Subject: [PATCH 052/354] cmd/evm: make evm statetest accept non-json files (#30927) This fixes a regression introduced recently. Without this fix, it's not possible to use statetests without `.json` suffix. This is problematic for goevmlab `minimizer`, which appends the suffix `.min` during processing. --- cmd/evm/blockrunner.go | 2 +- cmd/evm/main.go | 11 ++++++++--- cmd/evm/staterunner.go | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 2cb0531e2..9a04807b3 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -50,7 +50,7 @@ func blockTestCmd(ctx *cli.Context) error { return errors.New("path argument required") } var ( - collected = collectJSONFiles(path) + collected = collectFiles(path) results []testResult ) for _, fname := range collected { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 0e6f6fa5b..207942541 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -262,10 +262,15 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { } } -// collectJSONFiles walks the given path and accumulates all files with json -// extension. -func collectJSONFiles(path string) []string { +// collectFiles walks the given path. If the path is a directory, it will +// return a list of all accumulates all files with json extension. +// Otherwise (if path points to a file), it will return the path. +func collectFiles(path string) []string { var out []string + if info, err := os.Stat(path); err == nil && !info.IsDir() { + // User explicitly pointed out a file, ignore extension. + return []string{path} + } err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { if err != nil { return err diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 323b7d60a..4c2dfeabc 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -63,7 +63,7 @@ func stateTestCmd(ctx *cli.Context) error { // If path is provided, run the tests at that path. if len(path) != 0 { var ( - collected = collectJSONFiles(path) + collected = collectFiles(path) results []testResult ) for _, fname := range collected { From dca2d4e0b299e3a92097778ec3088a64533ec980 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Dec 2024 19:10:53 +0100 Subject: [PATCH 053/354] core/types: updates for EIP-7702 API functions (#30933) Here I am proposing two small changes to the exported API for EIP-7702: (1) `Authorization` has a very generic name, but it is in fact only used for one niche use case: authorizing code in a `SetCodeTx`. So I propose calling it `SetCodeAuthorization` instead. The signing function is renamed to `SignSetCode` instead of `SignAuth`. (2) The signing function for authorizations should take key as the first parameter, and the authorization second. The key will almost always be in a variable, while the authorization can be given as a literal. --- core/blockchain_test.go | 10 +++--- core/state_processor_test.go | 2 +- core/state_transition.go | 8 ++--- core/types/gen_authorization.go | 48 +++++++++++++-------------- core/types/transaction.go | 2 +- core/types/transaction_marshalling.go | 34 +++++++++---------- core/types/tx_setcode.go | 36 +++++++++----------- internal/ethapi/api.go | 46 ++++++++++++------------- internal/ethapi/transaction_args.go | 4 +-- tests/state_test_util.go | 6 ++-- 10 files changed, 95 insertions(+), 101 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 25899ad8e..fd2fc365b 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4277,16 +4277,16 @@ func TestEIP7702(t *testing.T) { // 1. tx -> addr1 which is delegated to 0xaaaa // 2. addr1:0xaaaa calls into addr2:0xbbbb // 3. addr2:0xbbbb writes to storage - auth1, _ := types.SignAuth(types.Authorization{ + auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{ ChainID: gspec.Config.ChainID.Uint64(), Address: aa, Nonce: 1, - }, key1) - auth2, _ := types.SignAuth(types.Authorization{ + }) + auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{ ChainID: 0, Address: bb, Nonce: 0, - }, key2) + }) _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(aa) @@ -4297,7 +4297,7 @@ func TestEIP7702(t *testing.T) { Gas: 500000, GasFeeCap: uint256.MustFromBig(newGwei(5)), GasTipCap: uint256.NewInt(2), - AuthList: []types.Authorization{auth1, auth2}, + AuthList: []types.SetCodeAuthorization{auth1, auth2}, } tx := types.MustSignNewTx(key1, signer, txdata) b.AddTx(tx) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index ec2823b3f..f1b11a1a3 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -111,7 +111,7 @@ func TestStateProcessorErrors(t *testing.T) { } return tx } - var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.Authorization) *types.Transaction { + var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.SetCodeAuthorization) *types.Transaction { tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{ Nonce: nonce, GasTipCap: uint256.MustFromBig(gasTipCap), diff --git a/core/state_transition.go b/core/state_transition.go index a98024086..c14329de8 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -69,7 +69,7 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Authorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -145,7 +145,7 @@ type Message struct { AccessList types.AccessList BlobGasFeeCap *big.Int BlobHashes []common.Hash - AuthList []types.Authorization + AuthList []types.SetCodeAuthorization // When SkipNonceChecks is true, the message nonce is not checked against the // account nonce in state. @@ -568,7 +568,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } // validateAuthorization validates an EIP-7702 authorization against the state. -func (st *stateTransition) validateAuthorization(auth *types.Authorization) (authority common.Address, err error) { +func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) { // Verify chain ID is 0 or equal to current chain ID. if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { return authority, ErrAuthorizationWrongChainID @@ -599,7 +599,7 @@ func (st *stateTransition) validateAuthorization(auth *types.Authorization) (aut } // applyAuthorization applies an EIP-7702 code delegation to the state. -func (st *stateTransition) applyAuthorization(msg *Message, auth *types.Authorization) error { +func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error { authority, err := st.validateAuthorization(auth) if err != nil { return err diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index cc8fe138e..c9ab3590b 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -14,8 +14,8 @@ import ( var _ = (*authorizationMarshaling)(nil) // MarshalJSON marshals as JSON. -func (a Authorization) MarshalJSON() ([]byte, error) { - type Authorization struct { +func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { + type SetCodeAuthorization struct { ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` @@ -23,19 +23,19 @@ func (a Authorization) MarshalJSON() ([]byte, error) { R hexutil.U256 `json:"r" gencodec:"required"` S hexutil.U256 `json:"s" gencodec:"required"` } - var enc Authorization - enc.ChainID = hexutil.Uint64(a.ChainID) - enc.Address = a.Address - enc.Nonce = hexutil.Uint64(a.Nonce) - enc.V = hexutil.Uint64(a.V) - enc.R = hexutil.U256(a.R) - enc.S = hexutil.U256(a.S) + var enc SetCodeAuthorization + enc.ChainID = hexutil.Uint64(s.ChainID) + enc.Address = s.Address + enc.Nonce = hexutil.Uint64(s.Nonce) + enc.V = hexutil.Uint64(s.V) + enc.R = hexutil.U256(s.R) + enc.S = hexutil.U256(s.S) return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (a *Authorization) UnmarshalJSON(input []byte) error { - type Authorization struct { +func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { + type SetCodeAuthorization struct { ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` @@ -43,33 +43,33 @@ func (a *Authorization) UnmarshalJSON(input []byte) error { R *hexutil.U256 `json:"r" gencodec:"required"` S *hexutil.U256 `json:"s" gencodec:"required"` } - var dec Authorization + var dec SetCodeAuthorization if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.ChainID == nil { - return errors.New("missing required field 'chainId' for Authorization") + return errors.New("missing required field 'chainId' for SetCodeAuthorization") } - a.ChainID = uint64(*dec.ChainID) + s.ChainID = uint64(*dec.ChainID) if dec.Address == nil { - return errors.New("missing required field 'address' for Authorization") + return errors.New("missing required field 'address' for SetCodeAuthorization") } - a.Address = *dec.Address + s.Address = *dec.Address if dec.Nonce == nil { - return errors.New("missing required field 'nonce' for Authorization") + return errors.New("missing required field 'nonce' for SetCodeAuthorization") } - a.Nonce = uint64(*dec.Nonce) + s.Nonce = uint64(*dec.Nonce) if dec.V == nil { - return errors.New("missing required field 'v' for Authorization") + return errors.New("missing required field 'v' for SetCodeAuthorization") } - a.V = uint8(*dec.V) + s.V = uint8(*dec.V) if dec.R == nil { - return errors.New("missing required field 'r' for Authorization") + return errors.New("missing required field 'r' for SetCodeAuthorization") } - a.R = uint256.Int(*dec.R) + s.R = uint256.Int(*dec.R) if dec.S == nil { - return errors.New("missing required field 's' for Authorization") + return errors.New("missing required field 's' for SetCodeAuthorization") } - a.S = uint256.Int(*dec.S) + s.S = uint256.Int(*dec.S) return nil } diff --git a/core/types/transaction.go b/core/types/transaction.go index b5fb3e2db..24b110fa1 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -475,7 +475,7 @@ func (tx *Transaction) WithBlobTxSidecar(sideCar *BlobTxSidecar) *Transaction { } // AuthList returns the authorizations list of the transaction. -func (tx *Transaction) AuthList() []Authorization { +func (tx *Transaction) AuthList() []SetCodeAuthorization { setcodetx, ok := tx.inner.(*SetCodeTx) if !ok { return nil diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 4176a8220..993d633c6 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -31,23 +31,23 @@ import ( type txJSON struct { Type hexutil.Uint64 `json:"type"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - Nonce *hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - Gas *hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` - MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` - Value *hexutil.Big `json:"value"` - Input *hexutil.Bytes `json:"input"` - AccessList *AccessList `json:"accessList,omitempty"` - BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` - AuthorizationList []Authorization `json:"authorizationList,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` - YParity *hexutil.Uint64 `json:"yParity,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + Nonce *hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` + MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + Value *hexutil.Big `json:"value"` + Input *hexutil.Bytes `json:"input"` + AccessList *AccessList `json:"accessList,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + AuthorizationList []SetCodeAuthorization `json:"authorizationList,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` // Blob transaction sidecar encoding: Blobs []kzg4844.Blob `json:"blobs,omitempty"` diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index b251cd181..1be90df61 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -58,7 +58,7 @@ type SetCodeTx struct { Value *uint256.Int Data []byte AccessList AccessList - AuthList []Authorization + AuthList []SetCodeAuthorization // Signature values V *uint256.Int `json:"v" gencodec:"required"` @@ -66,10 +66,10 @@ type SetCodeTx struct { S *uint256.Int `json:"s" gencodec:"required"` } -//go:generate go run github.com/fjl/gencodec -type Authorization -field-override authorizationMarshaling -out gen_authorization.go +//go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go -// Authorization is an authorization from an account to deploy code at its address. -type Authorization struct { +// SetCodeAuthorization is an authorization from an account to deploy code at its address. +type SetCodeAuthorization struct { ChainID uint64 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` @@ -87,31 +87,25 @@ type authorizationMarshaling struct { S hexutil.U256 } -// SignAuth signs the provided authorization. -func SignAuth(auth Authorization, prv *ecdsa.PrivateKey) (Authorization, error) { +// SignSetCode creates a signed the SetCode authorization. +func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAuthorization, error) { sighash := auth.sigHash() sig, err := crypto.Sign(sighash[:], prv) if err != nil { - return Authorization{}, err + return SetCodeAuthorization{}, err } - return auth.withSignature(sig), nil -} - -// withSignature updates the signature of an Authorization to be equal the -// decoded signature provided in sig. -func (a *Authorization) withSignature(sig []byte) Authorization { r, s, _ := decodeSignature(sig) - return Authorization{ - ChainID: a.ChainID, - Address: a.Address, - Nonce: a.Nonce, + return SetCodeAuthorization{ + ChainID: auth.ChainID, + Address: auth.Address, + Nonce: auth.Nonce, V: sig[64], R: *uint256.MustFromBig(r), S: *uint256.MustFromBig(s), - } + }, nil } -func (a *Authorization) sigHash() common.Hash { +func (a *SetCodeAuthorization) sigHash() common.Hash { return prefixedRlpHash(0x05, []any{ a.ChainID, a.Address, @@ -120,7 +114,7 @@ func (a *Authorization) sigHash() common.Hash { } // Authority recovers the the authorizing account of an authorization. -func (a *Authorization) Authority() (common.Address, error) { +func (a *SetCodeAuthorization) Authority() (common.Address, error) { sighash := a.sigHash() if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) { return common.Address{}, ErrInvalidSig @@ -152,7 +146,7 @@ func (tx *SetCodeTx) copy() TxData { Gas: tx.Gas, // These are copied below. AccessList: make(AccessList, len(tx.AccessList)), - AuthList: make([]Authorization, len(tx.AuthList)), + AuthList: make([]SetCodeAuthorization, len(tx.AuthList)), Value: new(uint256.Int), ChainID: tx.ChainID, GasTipCap: new(uint256.Int), diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4b362de9c..432d4de74 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1041,29 +1041,29 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *types.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` - AuthorizationList []types.Authorization `json:"authorizationList,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` - YParity *hexutil.Uint64 `json:"yParity,omitempty"` + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` } // newRPCTransaction returns a transaction that will serialize to the RPC diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 89b015f04..cf5921869 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -73,7 +73,7 @@ type TransactionArgs struct { Proofs []kzg4844.Proof `json:"proofs"` // For SetCodeTxType - AuthorizationList []types.Authorization `json:"authorizationList"` + AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"` // This configures whether blobs are allowed to be passed. blobSidecarAllowed bool @@ -525,7 +525,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { if args.AccessList != nil { al = *args.AccessList } - authList := []types.Authorization{} + authList := []types.SetCodeAuthorization{} if args.AuthorizationList != nil { authList = args.AuthorizationList } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e735ce2fb..266bd7fd2 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -441,11 +441,11 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess if gasPrice == nil { return nil, errors.New("no gas price provided") } - var authList []types.Authorization + var authList []types.SetCodeAuthorization if tx.AuthorizationList != nil { - authList = make([]types.Authorization, len(tx.AuthorizationList)) + authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList)) for i, auth := range tx.AuthorizationList { - authList[i] = types.Authorization{ + authList[i] = types.SetCodeAuthorization{ ChainID: auth.ChainID, Address: auth.Address, Nonce: auth.Nonce, From ec4518d4321edc3d1bb40f8eba88b9b8b6263322 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Dec 2024 19:46:15 +0100 Subject: [PATCH 054/354] core/types: rename SetCodeAuthorization 'v' to 'yParity' The API spec requires the name yParity. --- core/types/gen_authorization.go | 6 +++--- core/types/tx_setcode.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index c9ab3590b..be5467c50 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -19,7 +19,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` - V hexutil.Uint64 `json:"v" gencodec:"required"` + V hexutil.Uint64 `json:"yParity" gencodec:"required"` R hexutil.U256 `json:"r" gencodec:"required"` S hexutil.U256 `json:"s" gencodec:"required"` } @@ -39,7 +39,7 @@ func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` - V *hexutil.Uint64 `json:"v" gencodec:"required"` + V *hexutil.Uint64 `json:"yParity" gencodec:"required"` R *hexutil.U256 `json:"r" gencodec:"required"` S *hexutil.U256 `json:"s" gencodec:"required"` } @@ -60,7 +60,7 @@ func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { } s.Nonce = uint64(*dec.Nonce) if dec.V == nil { - return errors.New("missing required field 'v' for SetCodeAuthorization") + return errors.New("missing required field 'yParity' for SetCodeAuthorization") } s.V = uint8(*dec.V) if dec.R == nil { diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index 1be90df61..f14ae3bc9 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -73,7 +73,7 @@ type SetCodeAuthorization struct { ChainID uint64 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` - V uint8 `json:"v" gencodec:"required"` + V uint8 `json:"yParity" gencodec:"required"` R uint256.Int `json:"r" gencodec:"required"` S uint256.Int `json:"s" gencodec:"required"` } From 7d92a737949ff28ce178f6b747db6c3ac8f13557 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 18 Dec 2024 20:17:49 +0100 Subject: [PATCH 055/354] cmd/evm: update tests for SetCodeAuthorization JSON encoding change (#30936) Fixing a regression introduced by 73a4ecf675f6, which I accidentally pushed to the master branch directly. --- cmd/evm/testdata/33/txs.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/testdata/33/txs.json b/cmd/evm/testdata/33/txs.json index 9c4db138c..c96cdb03e 100644 --- a/cmd/evm/testdata/33/txs.json +++ b/cmd/evm/testdata/33/txs.json @@ -16,7 +16,7 @@ "chainId": "0x1", "address": "0x000000000000000000000000000000000000aaaa", "nonce": "0x1", - "v": "0x1", + "yParity": "0x1", "r": "0xf7e3e597fc097e71ed6c26b14b25e5395bc8510d58b9136af439e12715f2d721", "s": "0x6cf7c3d7939bfdb784373effc0ebb0bd7549691a513f395e3cdabf8602724987" }, @@ -24,7 +24,7 @@ "chainId": "0x0", "address": "0x000000000000000000000000000000000000bbbb", "nonce": "0x0", - "v": "0x1", + "yParity": "0x1", "r": "0x5011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98", "s": "0x56c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf61" } From a8b0f00d2303037c8181214518c9dd276cdbd886 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Dec 2024 10:06:33 +0100 Subject: [PATCH 056/354] core, core/types: rename AuthList to SetCodeAuthorizations (#30935) As a follow-up to #30933, I propose to also use the SetCode prefix in our internal APIs for the authorization list. --- cmd/evm/internal/t8ntool/transaction.go | 2 +- core/state_transition.go | 64 ++++++++++++------------- core/txpool/validation.go | 2 +- core/types/transaction.go | 4 +- core/types/transaction_signing.go | 2 +- eth/tracers/native/prestate.go | 2 +- internal/ethapi/api.go | 2 +- internal/ethapi/transaction_args.go | 30 ++++++------ tests/state_test_util.go | 26 +++++----- tests/transaction_test_util.go | 2 +- 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 64e21b24f..6dac4301d 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,7 +133,7 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, + if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) diff --git a/core/state_transition.go b/core/state_transition.go index c14329de8..f432ad63d 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -133,19 +133,19 @@ func toWordSize(size uint64) uint64 { // A Message contains the data derived from a single transaction that is relevant to state // processing. type Message struct { - To *common.Address - From common.Address - Nonce uint64 - Value *big.Int - GasLimit uint64 - GasPrice *big.Int - GasFeeCap *big.Int - GasTipCap *big.Int - Data []byte - AccessList types.AccessList - BlobGasFeeCap *big.Int - BlobHashes []common.Hash - AuthList []types.SetCodeAuthorization + To *common.Address + From common.Address + Nonce uint64 + Value *big.Int + GasLimit uint64 + GasPrice *big.Int + GasFeeCap *big.Int + GasTipCap *big.Int + Data []byte + AccessList types.AccessList + BlobGasFeeCap *big.Int + BlobHashes []common.Hash + SetCodeAuthorizations []types.SetCodeAuthorization // When SkipNonceChecks is true, the message nonce is not checked against the // account nonce in state. @@ -159,20 +159,20 @@ type Message struct { // TransactionToMessage converts a transaction into a Message. func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { msg := &Message{ - Nonce: tx.Nonce(), - GasLimit: tx.Gas(), - GasPrice: new(big.Int).Set(tx.GasPrice()), - GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), - GasTipCap: new(big.Int).Set(tx.GasTipCap()), - To: tx.To(), - Value: tx.Value(), - Data: tx.Data(), - AccessList: tx.AccessList(), - AuthList: tx.AuthList(), - SkipNonceChecks: false, - SkipFromEOACheck: false, - BlobHashes: tx.BlobHashes(), - BlobGasFeeCap: tx.BlobGasFeeCap(), + Nonce: tx.Nonce(), + GasLimit: tx.Gas(), + GasPrice: new(big.Int).Set(tx.GasPrice()), + GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), + GasTipCap: new(big.Int).Set(tx.GasTipCap()), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + SetCodeAuthorizations: tx.SetCodeAuthorizations(), + SkipNonceChecks: false, + SkipFromEOACheck: false, + BlobHashes: tx.BlobHashes(), + BlobGasFeeCap: tx.BlobGasFeeCap(), } // If baseFee provided, set gasPrice to effectiveGasPrice. if baseFee != nil { @@ -412,11 +412,11 @@ func (st *stateTransition) preCheck() error { } } // Check that EIP-7702 authorization list signatures are well formed. - if msg.AuthList != nil { + if msg.SetCodeAuthorizations != nil { if msg.To == nil { return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From) } - if len(msg.AuthList) == 0 { + if len(msg.SetCodeAuthorizations) == 0 { return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From) } } @@ -457,7 +457,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.AuthList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } @@ -507,8 +507,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1) // Apply EIP-7702 authorizations. - if msg.AuthList != nil { - for _, auth := range msg.AuthList { + if msg.SetCodeAuthorizations != nil { + for _, auth := range msg.SetCodeAuthorizations { // Note errors are ignored, we simply skip invalid authorizations here. st.applyAuthorization(msg, &auth) } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 70b2ca89a..7dc8f1c4d 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -110,7 +110,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) if err != nil { return err } diff --git a/core/types/transaction.go b/core/types/transaction.go index 24b110fa1..35dc1ea3f 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -474,8 +474,8 @@ func (tx *Transaction) WithBlobTxSidecar(sideCar *BlobTxSidecar) *Transaction { return cpy } -// AuthList returns the authorizations list of the transaction. -func (tx *Transaction) AuthList() []SetCodeAuthorization { +// SetCodeAuthorizations returns the authorizations list of the transaction. +func (tx *Transaction) SetCodeAuthorizations() []SetCodeAuthorization { setcodetx, ok := tx.inner.(*SetCodeTx) if !ok { return nil diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 78fa2fc8e..d72643b4a 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -245,7 +245,7 @@ func (s pragueSigner) Hash(tx *Transaction) common.Hash { tx.Value(), tx.Data(), tx.AccessList(), - tx.AuthList(), + tx.SetCodeAuthorizations(), }) } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 5776275c2..e04b77f61 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -161,7 +161,7 @@ func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction t.lookupAccount(env.Coinbase) // Add accounts with authorizations to the prestate before they get applied. - for _, auth := range tx.AuthList() { + for _, auth := range tx.SetCodeAuthorizations() { addr, err := auth.Authority() if err != nil { continue diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 432d4de74..03d4ee705 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1153,7 +1153,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber } else { result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) } - result.AuthorizationList = tx.AuthList() + result.AuthorizationList = tx.SetCodeAuthorizations() } return result } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index cf5921869..8902cab9d 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -482,21 +482,21 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA accessList = *args.AccessList } return &core.Message{ - From: args.from(), - To: args.To, - Value: (*big.Int)(args.Value), - Nonce: uint64(*args.Nonce), - GasLimit: uint64(*args.Gas), - GasPrice: gasPrice, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Data: args.data(), - AccessList: accessList, - BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), - BlobHashes: args.BlobHashes, - AuthList: args.AuthorizationList, - SkipNonceChecks: skipNonceCheck, - SkipFromEOACheck: skipEoACheck, + From: args.from(), + To: args.To, + Value: (*big.Int)(args.Value), + Nonce: uint64(*args.Nonce), + GasLimit: uint64(*args.Gas), + GasPrice: gasPrice, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Data: args.data(), + AccessList: accessList, + BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), + BlobHashes: args.BlobHashes, + SetCodeAuthorizations: args.AuthorizationList, + SkipNonceChecks: skipNonceCheck, + SkipFromEOACheck: skipEoACheck, } } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 266bd7fd2..6e66bbaa7 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -457,19 +457,19 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess } msg := &core.Message{ - From: from, - To: to, - Nonce: tx.Nonce, - Value: value, - GasLimit: gasLimit, - GasPrice: gasPrice, - GasFeeCap: tx.MaxFeePerGas, - GasTipCap: tx.MaxPriorityFeePerGas, - Data: data, - AccessList: accessList, - BlobHashes: tx.BlobVersionedHashes, - BlobGasFeeCap: tx.BlobGasFeeCap, - AuthList: authList, + From: from, + To: to, + Nonce: tx.Nonce, + Value: value, + GasLimit: gasLimit, + GasPrice: gasPrice, + GasFeeCap: tx.MaxFeePerGas, + GasTipCap: tx.MaxPriorityFeePerGas, + Data: data, + AccessList: accessList, + BlobHashes: tx.BlobVersionedHashes, + BlobGasFeeCap: tx.BlobGasFeeCap, + SetCodeAuthorizations: authList, } return msg, nil } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 4da27ff94..55b76df89 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -59,7 +59,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, isHomestead, isIstanbul, false) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) if err != nil { return nil, nil, err } From 9ebba3af6f21304232fe9c74c6b3127d0d037087 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Dec 2024 16:03:05 +0100 Subject: [PATCH 057/354] params: update system contracts for prague devnet-5 (#30938) --- params/protocol_params.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/params/protocol_params.go b/params/protocol_params.go index 3d03b74be..f06346db8 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -203,14 +203,14 @@ var ( BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") // EIP-2935 - Serve historical block hashes from state - HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e") - HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500") + HistoryStorageAddress = common.HexToAddress("0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC") + HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500") // EIP-7002 - Execution layer triggerable withdrawals - WithdrawalQueueAddress = common.HexToAddress("0x09Fc772D0857550724b07B850a4323f39112aAaA") - WithdrawalQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460c7573615156028575f545f5260205ff35b36603814156101f05760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f057600182026001905f5b5f821115608057810190830284830290049160010191906065565b9093900434106101f057600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160db575060105b5f5b81811461017f5780604c02838201600302600401805490600101805490600101549160601b83528260140152807fffffffffffffffffffffffffffffffff0000000000000000000000000000000016826034015260401c906044018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160dd565b9101809214610191579060025561019c565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101c957505f5b6001546002828201116101de5750505f6101e4565b01600290035b5f555f600155604c025ff35b5f5ffd") + WithdrawalQueueAddress = common.HexToAddress("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA") + WithdrawalQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd") // EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE - ConsolidationQueueAddress = common.HexToAddress("0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb") - ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") + ConsolidationQueueAddress = common.HexToAddress("0x00431F263cE400f4455c2dCf564e53007Ca4bbBb") + ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") ) From e6357e0b1071f93bd191c9c90993d1ef743abe7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=92?= <47621124+ronething-bot@users.noreply.github.com> Date: Thu, 2 Jan 2025 09:48:25 +0800 Subject: [PATCH 058/354] internal/flags: update copyright year to 2025 (#30976) --- internal/flags/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index fd706869f..170b67b31 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -40,7 +40,7 @@ func NewApp(usage string) *cli.App { app.EnableBashCompletion = true app.Version = version.WithCommit(git.Commit, git.Date) app.Usage = usage - app.Copyright = "Copyright 2013-2024 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2025 The go-ethereum Authors" app.Before = func(ctx *cli.Context) error { MigrateGlobalFlags(ctx) return nil From e9c1422ee337d72fa2a54fa48703b132afcc205e Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Thu, 2 Jan 2025 21:04:06 +0800 Subject: [PATCH 059/354] crypto/bn256: fix MulScalar (#30974) The `a` parameter should be used in the `MulScalar` function. The upstream cloudflare and google repos have already merged fixes. Reference: * https://cs.opensource.google/go/x/crypto/+/8d7daa0c54b357f3071e11eaef7efc4e19a417e2 * https://github.com/cloudflare/bn256/pull/33 --- crypto/bn256/cloudflare/gfp12.go | 4 ++-- crypto/bn256/google/gfp12.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go index 93fb368a7..767350701 100644 --- a/crypto/bn256/cloudflare/gfp12.go +++ b/crypto/bn256/cloudflare/gfp12.go @@ -105,8 +105,8 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { - e.x.Mul(&e.x, b) - e.y.Mul(&e.y, b) + e.x.Mul(&a.x, b) + e.y.Mul(&a.y, b) return e } diff --git a/crypto/bn256/google/gfp12.go b/crypto/bn256/google/gfp12.go index f084eddf2..2b0151ebc 100644 --- a/crypto/bn256/google/gfp12.go +++ b/crypto/bn256/google/gfp12.go @@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { - e.x.Mul(e.x, b, pool) - e.y.Mul(e.y, b, pool) + e.x.Mul(a.x, b, pool) + e.y.Mul(a.y, b, pool) return e } From 2b83e7e954d338bcb218877adcf01c3051cf3413 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Thu, 2 Jan 2025 21:06:47 +0800 Subject: [PATCH 060/354] all: use cmp.Compare (#30958) --- cmd/devp2p/dns_route53.go | 9 ++------- cmd/devp2p/nodeset.go | 9 ++------- core/state/snapshot/iterator_fast.go | 9 ++------- p2p/protocol.go | 9 ++------- triedb/pathdb/iterator_fast.go | 9 ++------- 5 files changed, 10 insertions(+), 35 deletions(-) diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index a6125b826..86907688f 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -17,6 +17,7 @@ package main import ( + "cmp" "context" "errors" "fmt" @@ -292,13 +293,7 @@ func sortChanges(changes []types.Change) { if a.Action == b.Action { return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name) } - if score[string(a.Action)] < score[string(b.Action)] { - return -1 - } - if score[string(a.Action)] > score[string(b.Action)] { - return 1 - } - return 0 + return cmp.Compare(score[string(a.Action)], score[string(b.Action)]) }) } diff --git a/cmd/devp2p/nodeset.go b/cmd/devp2p/nodeset.go index 4fa862de1..4a6df6cdf 100644 --- a/cmd/devp2p/nodeset.go +++ b/cmd/devp2p/nodeset.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "cmp" "encoding/json" "fmt" "os" @@ -104,13 +105,7 @@ func (ns nodeSet) topN(n int) nodeSet { byscore = append(byscore, v) } slices.SortFunc(byscore, func(a, b nodeJSON) int { - if a.Score > b.Score { - return -1 - } - if a.Score < b.Score { - return 1 - } - return 0 + return cmp.Compare(b.Score, a.Score) }) result := make(nodeSet, n) for _, v := range byscore[:n] { diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 7f7ba876f..61fc43417 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -18,6 +18,7 @@ package snapshot import ( "bytes" + "cmp" "fmt" "slices" "sort" @@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int { return 1 } // Same account/storage-slot in multiple layers, split by priority - if it.priority < other.priority { - return -1 - } - if it.priority > other.priority { - return 1 - } - return 0 + return cmp.Compare(it.priority, other.priority) } // fastIterator is a more optimized multi-layer iterator which maintains a diff --git a/p2p/protocol.go b/p2p/protocol.go index 9bb6785a2..de3127e23 100644 --- a/p2p/protocol.go +++ b/p2p/protocol.go @@ -17,6 +17,7 @@ package p2p import ( + "cmp" "fmt" "strings" @@ -81,13 +82,7 @@ func (cap Cap) String() string { // Cmp defines the canonical sorting order of capabilities. func (cap Cap) Cmp(other Cap) int { if cap.Name == other.Name { - if cap.Version < other.Version { - return -1 - } - if cap.Version > other.Version { - return 1 - } - return 0 + return cmp.Compare(cap.Version, other.Version) } return strings.Compare(cap.Name, other.Name) } diff --git a/triedb/pathdb/iterator_fast.go b/triedb/pathdb/iterator_fast.go index 217b211fc..966e37a7c 100644 --- a/triedb/pathdb/iterator_fast.go +++ b/triedb/pathdb/iterator_fast.go @@ -18,6 +18,7 @@ package pathdb import ( "bytes" + "cmp" "fmt" "slices" "sort" @@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int { return 1 } // Same account/storage-slot in multiple layers, split by priority - if it.priority < other.priority { - return -1 - } - if it.priority > other.priority { - return 1 - } - return 0 + return cmp.Compare(it.priority, other.priority) } // fastIterator is a more optimized multi-layer iterator which maintains a From 7c3f0b7f6f6bd781f084cb4c47f8dabfda478b14 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 2 Jan 2025 18:37:58 +0100 Subject: [PATCH 061/354] eth/tracers/logger: skip system calls (#30923) This commit makes it so that the struct logger will not emit logs while system calls are being executed. This will make it consistent with the JSON and MD loggers. It is as it stands hard to distinguish when system calls are being processed vs when a tx is being processed. --------- Co-authored-by: Sina Mahmoodi --- eth/tracers/logger/logger.go | 64 +++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index dc9e6e62b..07de871f1 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -217,6 +217,7 @@ type StructLogger struct { interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption + skip bool // skip processing hooks. } // NewStreamingStructLogger returns a new streaming logger. @@ -240,10 +241,12 @@ func NewStructLogger(cfg *Config) *StructLogger { func (l *StructLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnTxEnd: l.OnTxEnd, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, + OnTxStart: l.OnTxStart, + OnTxEnd: l.OnTxEnd, + OnSystemCallStartV2: l.OnSystemCallStart, + OnSystemCallEnd: l.OnSystemCallEnd, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, } } @@ -255,6 +258,10 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope if l.interrupt.Load() { return } + // Processing a system call. + if l.skip { + return + } // check if already accumulated the size of the response. if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit { return @@ -320,6 +327,9 @@ func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err erro if depth != 0 { return } + if l.skip { + return + } l.output = output l.err = err // TODO @holiman, should we output the per-scope output? @@ -360,6 +370,13 @@ func (l *StructLogger) Stop(err error) { func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } +func (l *StructLogger) OnSystemCallStart(env *tracing.VMContext) { + l.skip = true +} + +func (l *StructLogger) OnSystemCallEnd() { + l.skip = false +} func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { @@ -389,9 +406,10 @@ func WriteTrace(writer io.Writer, logs []StructLog) { } type mdLogger struct { - out io.Writer - cfg *Config - env *tracing.VMContext + out io.Writer + cfg *Config + env *tracing.VMContext + skip bool } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -406,11 +424,13 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { func (t *mdLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: t.OnTxStart, - OnEnter: t.OnEnter, - OnExit: t.OnExit, - OnOpcode: t.OnOpcode, - OnFault: t.OnFault, + OnTxStart: t.OnTxStart, + OnSystemCallStartV2: t.OnSystemCallStart, + OnSystemCallEnd: t.OnSystemCallEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, } } @@ -418,7 +438,18 @@ func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.env = env } +func (t *mdLogger) OnSystemCallStart(env *tracing.VMContext) { + t.skip = true +} + +func (t *mdLogger) OnSystemCallEnd() { + t.skip = false +} + func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.skip { + return + } if depth != 0 { return } @@ -446,6 +477,9 @@ func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.A } func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.skip { + return + } if depth == 0 { fmt.Fprintf(t.out, "\nPost-execution info:\n"+ " - output: `%#x`\n"+ @@ -457,6 +491,9 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if t.skip { + return + } stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(), cost, t.env.StateDB.GetRefund()) @@ -477,6 +514,9 @@ func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing. } func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + if t.skip { + return + } fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } From 964363a69aaa122431516157ff78a17feacd8f0d Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 3 Jan 2025 13:15:06 +0100 Subject: [PATCH 062/354] internal/ethapi: update default simulation timestamp increment to 12 (#30981) Update the default timestamp increment to 12s for `eth_simulate` endpoint --- internal/ethapi/simulate.go | 2 +- internal/ethapi/simulate_test.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 5bd0079a9..130eaa972 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -45,7 +45,7 @@ const ( maxSimulateBlocks = 256 // timestampIncrement is the default increment between block timestamps. - timestampIncrement = 1 + timestampIncrement = 12 ) // simBlock is a batch of calls to be simulated sequentially. diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go index 52ae40cad..c747b7647 100644 --- a/internal/ethapi/simulate_test.go +++ b/internal/ethapi/simulate_test.go @@ -41,19 +41,19 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{}, {}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}}, }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(80)}}, {}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 80}, {number: 14, timestamp: 92}}, }, { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}, {number: 14, timestamp: 98}, {number: 15, timestamp: 110}}, }, { baseNumber: 10, @@ -64,8 +64,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, - err: "block timestamps must be in order: 52 <= 52", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(74)}}}, + err: "block timestamps must be in order: 74 <= 74", }, { baseNumber: 10, @@ -76,8 +76,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, - err: "block timestamps must be in order: 61 <= 61", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(72)}}}, + err: "block timestamps must be in order: 72 <= 72", }, } { sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} From f3a396657334ee298ec430a3539ffcf19b9b8297 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 6 Jan 2025 07:52:01 +0100 Subject: [PATCH 063/354] core/rawdb: fix panic in freezer (#30973) Fixes an issue where the node panics when an LStat fails with something other than os.ErrNotExist closes https://github.com/ethereum/go-ethereum/issues/30968 --- core/rawdb/freezer.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index d6370cee3..c5a72eff7 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -87,6 +87,10 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui ) // Ensure the datadir is not a symbolic link if it exists. if info, err := os.Lstat(datadir); !os.IsNotExist(err) { + if info == nil { + log.Warn("Could not Lstat the database", "path", datadir) + return nil, errors.New("lstat failed") + } if info.Mode()&os.ModeSymlink != 0 { log.Warn("Symbolic link ancient database is not supported", "path", datadir) return nil, errSymlinkDatadir From 0b4d83bb5b34a0158e9b6187e28cde6c0518c84d Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 6 Jan 2025 23:28:28 +0800 Subject: [PATCH 064/354] core/types: improve printList in DeriveSha test (#30969) --- core/types/hashing_test.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index a6949414f..c846ecd0c 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -111,7 +111,7 @@ func TestFuzzDeriveSha(t *testing.T) { exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { - printList(newDummy(seed)) + printList(t, newDummy(seed)) t.Fatalf("seed %d: got %x exp %x", seed, got, exp) } } @@ -192,15 +192,21 @@ func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) { io.CopyN(w, mrand.New(src), size) } -func printList(l types.DerivableList) { - fmt.Printf("list length: %d\n", l.Len()) - fmt.Printf("{\n") +func printList(t *testing.T, l types.DerivableList) { + var buf bytes.Buffer + _, _ = fmt.Fprintf(&buf, "list length: %d, ", l.Len()) + buf.WriteString("list: [") for i := 0; i < l.Len(); i++ { - var buf bytes.Buffer - l.EncodeIndex(i, &buf) - fmt.Printf("\"%#x\",\n", buf.Bytes()) + var itemBuf bytes.Buffer + l.EncodeIndex(i, &itemBuf) + if i == l.Len()-1 { + _, _ = fmt.Fprintf(&buf, "\"%#x\"", itemBuf.Bytes()) + } else { + _, _ = fmt.Fprintf(&buf, "\"%#x\",", itemBuf.Bytes()) + } } - fmt.Printf("},\n") + buf.WriteString("]") + t.Log(buf.String()) } type flatList []string From 59a265989a9d477d89c77b2954522e36e58f1a07 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 6 Jan 2025 16:31:53 +0100 Subject: [PATCH 065/354] eth/protocols/eth: prevent hanging dispatch (#30918) This PR attempts to fix a strange test-failure (timeout) observed on a windows-32 platform. https://ci.appveyor.com/project/ethereum/go-ethereum/builds/51174391/job/d8ascanwwltrlqd5 A goroutine is stuck trying to deliver a response: ``` goroutine 9632 [select, 29 minutes]: github.com/ethereum/go-ethereum/eth/protocols/eth.(*Peer).dispatchResponse(0x314f100, 0x3e5f6d0, 0x3acbb84) C:/projects/go-ethereum/eth/protocols/eth/dispatcher.go:172 +0x2a5 github.com/ethereum/go-ethereum/eth/protocols/eth.handleBlockHeaders({0x12abe68, 0x30021b8}, {0x12a815c, 0x40b41c0}, 0x314f100) C:/projects/go-ethereum/eth/protocols/eth/handlers.go:301 +0x173 github.com/ethereum/go-ethereum/eth/protocols/eth.handleMessage({0x12abe68, 0x30021b8}, 0x314f100) C:/projects/go-ethereum/eth/protocols/eth/handler.go:205 +0x4f6 github.com/ethereum/go-ethereum/eth/protocols/eth.Handle({0x12abe68, 0x30021b8}, 0x314f100) C:/projects/go-ethereum/eth/protocols/eth/handler.go:149 +0x33 github.com/ethereum/go-ethereum/eth.testSnapSyncDisabling.func1(0x314f100) C:/projects/go-ethereum/eth/sync_test.go:65 +0x33 github.com/ethereum/go-ethereum/eth.(*handler).runEthPeer(0x30021b8, 0x314f100, 0x427f648) C:/projects/go-ethereum/eth/handler.go:355 +0xe65 created by github.com/ethereum/go-ethereum/eth.testSnapSyncDisabling in goroutine 11 C:/projects/go-ethereum/eth/sync_test.go:64 +0x54f FAIL github.com/ethereum/go-ethereum/eth 1800.138s ``` --------- Co-authored-by: Gary Rong --- eth/protocols/eth/dispatcher.go | 2 ++ eth/sync_test.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index 146eec3f6..cba40596f 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -174,6 +174,8 @@ func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) erro return <-res.Done // Response delivered, return any errors case <-res.Req.cancel: return nil // Request cancelled, silently discard response + case <-p.term: + return errDisconnected } } diff --git a/eth/sync_test.go b/eth/sync_test.go index a31986730..602d219e7 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -89,6 +89,8 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { if err := empty.handler.doSync(op); err != nil { t.Fatal("sync failed:", err) } + time.Sleep(time.Second * 5) // Downloader internally has to wait a timer (3s) to be expired before exiting + if empty.handler.snapSync.Load() { t.Fatalf("snap sync not disabled after successful synchronisation") } From aa701daff2ba577e47e52e554f8516a43d36839e Mon Sep 17 00:00:00 2001 From: Savely <136869149+savvar9991@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:31:10 +1100 Subject: [PATCH 066/354] cmd/clef: fix JS issues in documentation (#30980) Fixes a couple of js-flaws in the docs --- cmd/clef/rules.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md index cc4a64559..3cd1bb52c 100644 --- a/cmd/clef/rules.md +++ b/cmd/clef/rules.md @@ -7,7 +7,7 @@ It enables usecases like the following: * I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period * I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei` -The two main features that are required for this to work well are; +The two main features that are required for this to work well are: 1. Rule Implementation: how to create, manage, and interpret rules in a flexible but secure manner 2. Credential management and credentials; how to provide auto-unlock without exposing keys unnecessarily. @@ -29,10 +29,10 @@ function asBig(str) { // Approve transactions to a certain contract if the value is below a certain limit function ApproveTx(req) { - var limit = big.Newint("0xb1a2bc2ec50000") + var limit = new BigNumber("0xb1a2bc2ec50000") var value = asBig(req.transaction.value); - if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9") && value.lt(limit)) { + if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9" && value.lt(limit)) { return "Approve" } // If we return "Reject", it will be rejected. From 9bb11f2fdb88a2bd8dff9db2266f73bdce51f47b Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Tue, 7 Jan 2025 13:49:13 +0300 Subject: [PATCH 067/354] triedb/pathdb: fix tester generator (#30972) This change fixes is a rare bug in test generator: If the run is very unlucky it can use `modifyAccountOp` / `deleteAccountOp` without creating any account, leading to have a trie root same as the parent. This change makes the first operation always be a creation. --- triedb/pathdb/database_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 648230df1..3b35370c8 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -222,7 +222,12 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { - switch rand.Intn(opLen) { + // Start with account creation always + op := createAccountOp + if i > 0 { + op = rand.Intn(opLen) + } + switch op { case createAccountOp: // account creation addr := testrand.Address() From 7b16df6cd408a08b3e7c0e614de685774adc946a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 10 Jan 2025 20:51:19 +0800 Subject: [PATCH 068/354] triedb/pathdb: configure different node hasher in pathdb (#31008) As the node hash scheme in verkle and merkle are totally different, the original default node hasher in pathdb is no longer suitable. Therefore, this pull request configures different node hasher respectively. --- core/genesis.go | 12 ++++- core/state/stateupdate.go | 5 +- core/types/hashes.go | 11 ---- internal/ethapi/override/override_test.go | 3 +- trie/trie_reader.go | 4 -- triedb/pathdb/database.go | 62 +++++++++++++++++------ triedb/pathdb/database_test.go | 4 +- triedb/pathdb/journal.go | 15 +++--- triedb/pathdb/layertree.go | 5 +- 9 files changed, 71 insertions(+), 50 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 6e3cdcd00..db67e9887 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -129,8 +129,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. + emptyRoot := types.EmptyRootHash + if isVerkle { + emptyRoot = types.EmptyVerkleHash + } db := rawdb.NewMemoryDatabase() - statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil)) + statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return common.Hash{}, err } @@ -150,7 +154,11 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { // flushAlloc is very similar with hash, but the main difference is all the // generated states will be persisted into the given database. func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) { - statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil)) + emptyRoot := types.EmptyRootHash + if triedb.IsVerkle() { + emptyRoot = types.EmptyVerkleHash + } + statedb, err := state.New(emptyRoot, state.NewDatabase(triedb, nil)) if err != nil { return common.Hash{}, err } diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go index a320b72f1..45de660ca 100644 --- a/core/state/stateupdate.go +++ b/core/state/stateupdate.go @@ -20,7 +20,6 @@ import ( "maps" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/triedb" ) @@ -133,8 +132,8 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common } } return &stateUpdate{ - originRoot: types.TrieRootHash(originRoot), - root: types.TrieRootHash(root), + originRoot: originRoot, + root: root, accounts: accounts, accountsOrigin: accountsOrigin, storages: storages, diff --git a/core/types/hashes.go b/core/types/hashes.go index 55506d63d..05cfaeed7 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -19,7 +19,6 @@ package types import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" ) var ( @@ -47,13 +46,3 @@ var ( // EmptyVerkleHash is the known hash of an empty verkle trie. EmptyVerkleHash = common.Hash{} ) - -// TrieRootHash returns the hash itself if it's non-empty or the predefined -// emptyHash one instead. -func TrieRootHash(hash common.Hash) common.Hash { - if hash == (common.Hash{}) { - log.Error("Zero trie root hash!") - return EmptyRootHash - } - return hash -} diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 07ed6442b..02a17c133 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/triedb" ) @@ -36,7 +37,7 @@ func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil func TestStateOverrideMovePrecompile(t *testing.T) { db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) - statedb, err := state.New(common.Hash{}, db) + statedb, err := state.New(types.EmptyRootHash, db) if err != nil { t.Fatalf("failed to create statedb: %v", err) } diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 4b8ba808d..a42cdb0cf 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -19,7 +19,6 @@ package trie import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/triedb/database" ) @@ -34,9 +33,6 @@ type trieReader struct { // newTrieReader initializes the trie reader with the given node reader. func newTrieReader(stateRoot, owner common.Hash, db database.NodeDatabase) (*trieReader, error) { if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash { - if stateRoot == (common.Hash{}) { - log.Error("Zero state root hash!") - } return &trieReader{owner: owner}, nil } reader, err := db.NodeReader(stateRoot) diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 914b17de5..c31f1d44f 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/ethereum/go-verkle" ) const ( @@ -148,6 +149,29 @@ var Defaults = &Config{ // ReadOnly is the config in order to open database in read only mode. var ReadOnly = &Config{ReadOnly: true} +// nodeHasher is the function to compute the hash of supplied node blob. +type nodeHasher func([]byte) (common.Hash, error) + +// merkleNodeHasher computes the hash of the given merkle node. +func merkleNodeHasher(blob []byte) (common.Hash, error) { + if len(blob) == 0 { + return types.EmptyRootHash, nil + } + return crypto.Keccak256Hash(blob), nil +} + +// verkleNodeHasher computes the hash of the given verkle node. +func verkleNodeHasher(blob []byte) (common.Hash, error) { + if len(blob) == 0 { + return types.EmptyVerkleHash, nil + } + n, err := verkle.ParseNode(blob, 0) + if err != nil { + return common.Hash{}, err + } + return n.Commit().Bytes(), nil +} + // Database is a multiple-layered structure for maintaining in-memory states // along with its dirty trie nodes. It consists of one persistent base layer // backed by a key-value store, on top of which arbitrarily many in-memory diff @@ -164,9 +188,10 @@ type Database struct { // readOnly is the flag whether the mutation is allowed to be applied. // It will be set automatically when the database is journaled during // the shutdown to reject all following unexpected mutations. - readOnly bool // Flag if database is opened in read only mode - waitSync bool // Flag if database is deactivated due to initial state sync - isVerkle bool // Flag if database is used for verkle tree + readOnly bool // Flag if database is opened in read only mode + waitSync bool // Flag if database is deactivated due to initial state sync + isVerkle bool // Flag if database is used for verkle tree + hasher nodeHasher // Trie node hasher config *Config // Configuration for database diskdb ethdb.Database // Persistent storage for matured trie nodes @@ -184,19 +209,21 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { } config = config.sanitize() + db := &Database{ + readOnly: config.ReadOnly, + isVerkle: isVerkle, + config: config, + diskdb: diskdb, + hasher: merkleNodeHasher, + } // Establish a dedicated database namespace tailored for verkle-specific // data, ensuring the isolation of both verkle and merkle tree data. It's // important to note that the introduction of a prefix won't lead to // substantial storage overhead, as the underlying database will efficiently // compress the shared key prefix. if isVerkle { - diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) - } - db := &Database{ - readOnly: config.ReadOnly, - isVerkle: isVerkle, - config: config, - diskdb: diskdb, + db.diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) + db.hasher = verkleNodeHasher } // Construct the layer tree by resolving the in-disk singleton state // and in-memory layer journal. @@ -277,6 +304,8 @@ func (db *Database) repairHistory() error { // // The passed in maps(nodes, states) will be retained to avoid copying everything. // Therefore, these maps must not be changed afterwards. +// +// The supplied parentRoot and root must be a valid trie hash value. func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *StateSetWithOrigin) error { // Hold the lock to prevent concurrent mutations. db.lock.Lock() @@ -350,10 +379,9 @@ func (db *Database) Enable(root common.Hash) error { return errDatabaseReadOnly } // Ensure the provided state root matches the stored one. - root = types.TrieRootHash(root) - stored := types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - stored = crypto.Keccak256Hash(blob) + stored, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + return err } if stored != root { return fmt.Errorf("state root mismatch: stored %x, synced %x", stored, root) @@ -389,6 +417,8 @@ func (db *Database) Enable(root common.Hash) error { // Recover rollbacks the database to a specified historical point. // The state is supported as the rollback destination only if it's // canonical state and the corresponding trie histories are existent. +// +// The supplied root must be a valid trie hash value. func (db *Database) Recover(root common.Hash) error { db.lock.Lock() defer db.lock.Unlock() @@ -401,7 +431,6 @@ func (db *Database) Recover(root common.Hash) error { return errors.New("state rollback is non-supported") } // Short circuit if the target state is not recoverable - root = types.TrieRootHash(root) if !db.Recoverable(root) { return errStateUnrecoverable } @@ -434,9 +463,10 @@ func (db *Database) Recover(root common.Hash) error { } // Recoverable returns the indicator if the specified state is recoverable. +// +// The supplied root must be a valid trie hash value. func (db *Database) Recoverable(root common.Hash) bool { // Ensure the requested state is a known state. - root = types.TrieRootHash(root) id := rawdb.ReadStateID(db.diskdb, root) if id == nil { return false diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 3b35370c8..a6b1d3c04 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -458,8 +458,8 @@ func TestDatabaseRecoverable(t *testing.T) { // Initial state should be recoverable {types.EmptyRootHash, true}, - // Initial state should be recoverable - {common.Hash{}, true}, + // common.Hash{} is not a valid state root for revert + {common.Hash{}, false}, // Layers below current disk layer are recoverable {tester.roots[index-1], true}, diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 779a262fd..267d675bc 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) @@ -93,9 +92,9 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { // loadLayers loads a pre-existing state layer backed by a key-value store. func (db *Database) loadLayers() layer { // Retrieve the root node of persistent state. - var root = types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - root = crypto.Keccak256Hash(blob) + root, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + log.Crit("Failed to compute node hash", "err", err) } // Load the layers by resolving the journal head, err := db.loadJournal(root) @@ -236,6 +235,8 @@ func (dl *diffLayer) journal(w io.Writer) error { // This is meant to be used during shutdown to persist the layer without // flattening everything down (bad for reorgs). And this function will mark the // database as read-only to prevent all following mutation to disk. +// +// The supplied root must be a valid trie hash value. func (db *Database) Journal(root common.Hash) error { // Retrieve the head layer to journal from. l := db.tree.get(root) @@ -265,9 +266,9 @@ func (db *Database) Journal(root common.Hash) error { } // Secondly write out the state root in disk, ensure all layers // on top are continuous with disk. - diskRoot := types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - diskRoot = crypto.Keccak256Hash(blob) + diskRoot, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + return err } if err := rlp.Encode(journal, diskRoot); err != nil { return err diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index cf6b14e74..0bd086c2f 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -22,7 +22,6 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie/trienode" ) @@ -62,7 +61,7 @@ func (tree *layerTree) get(root common.Hash) layer { tree.lock.RLock() defer tree.lock.RUnlock() - return tree.layers[types.TrieRootHash(root)] + return tree.layers[root] } // forEach iterates the stored layers inside and applies the @@ -92,7 +91,6 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6 // // Although we could silently ignore this internally, it should be the caller's // responsibility to avoid even attempting to insert such a layer. - root, parentRoot = types.TrieRootHash(root), types.TrieRootHash(parentRoot) if root == parentRoot { return errors.New("layer cycle") } @@ -112,7 +110,6 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6 // are crossed. All diffs beyond the permitted number are flattened downwards. func (tree *layerTree) cap(root common.Hash, layers int) error { // Retrieve the head layer to cap from - root = types.TrieRootHash(root) l := tree.get(root) if l == nil { return fmt.Errorf("triedb layer [%#x] missing", root) From 9f0355d49bc6b7cef8961af77422a5b24d276a49 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Mon, 13 Jan 2025 15:26:10 +0800 Subject: [PATCH 069/354] build: upgrade golangci-lint to v1.63.4 (#31019) This PR upgrades `golangci-lint` to v1.63.4 and fixes a warn message which is reported by v1.63.4: ```text WARN [config_reader] The configuration option `run.skip-dirs-use-default` is deprecated, please use `issues.exclude-dirs-use-default`. ``` Also fixes 2 warnings which are reported by v1.63.4: ```text core/txpool/blobpool/blobpool.go:1754:12: S1005: unnecessary assignment to the blank identifier (gosimple) for acct, _ := range p.index { ^ core/txpool/legacypool/legacypool.go:1989:19: S1005: unnecessary assignment to the blank identifier (gosimple) for localSender, _ := range pool.locals.accounts { ^ ``` --- .golangci.yml | 6 +-- build/checksums.txt | 60 ++++++++++++++-------------- core/txpool/blobpool/blobpool.go | 2 +- core/txpool/legacypool/legacypool.go | 2 +- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e355e6f9d..b63251055 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,9 +3,6 @@ run: timeout: 20m tests: true - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true linters: disable-all: true @@ -54,6 +51,9 @@ linters-settings: exclude: [""] issues: + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + exclude-dirs-use-default: true exclude-files: - core/genesis_alloc.go exclude-rules: diff --git a/build/checksums.txt b/build/checksums.txt index b8061c924..b0b7a73a3 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -56,37 +56,37 @@ fc77c0531406d092c5356167e45c05a22d16bea84e3fa555e0f03af085c11763 go1.23.4.windo 8347c1aa4e1e67954d12830f88dbe44bd7ac0ec134bb472783dbfb5a3a8865d0 go1.23.4.windows-arm64.msi db69cae5006753c785345c3215ad941f8b6224e2f81fec471c42d6857bee0e6f go1.23.4.windows-arm64.zip -# version:golangci 1.61.0 +# version:golangci 1.63.4 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.61.0/ -5c280ef3284f80c54fd90d73dc39ca276953949da1db03eb9dd0fbf868cc6e55 golangci-lint-1.61.0-darwin-amd64.tar.gz -544334890701e4e04a6e574bc010bea8945205c08c44cced73745a6378012d36 golangci-lint-1.61.0-darwin-arm64.tar.gz -e885a6f561092055930ebd298914d80e8fd2e10d2b1e9942836c2c6a115301fa golangci-lint-1.61.0-freebsd-386.tar.gz -b13f6a3f11f65e7ff66b734d7554df3bbae0f485768848424e7554ed289e19c2 golangci-lint-1.61.0-freebsd-amd64.tar.gz -cd8e7bbe5b8f33ed1597aa1cc588da96a3b9f22e1b9ae60d93511eae1a0ee8c5 golangci-lint-1.61.0-freebsd-armv6.tar.gz -7ade524dbd88bd250968f45e190af90e151fa5ee63dd6aa7f7bb90e8155db61d golangci-lint-1.61.0-freebsd-armv7.tar.gz -0fe3cd8a1ed8d9f54f48670a5af3df056d6040d94017057f0f4d65c930660ad9 golangci-lint-1.61.0-illumos-amd64.tar.gz -b463fc5053a612abd26393ebaff1d85d7d56058946f4f0f7bf25ed44ea899415 golangci-lint-1.61.0-linux-386.tar.gz -77cb0af99379d9a21d5dc8c38364d060e864a01bd2f3e30b5e8cc550c3a54111 golangci-lint-1.61.0-linux-amd64.tar.gz -af60ac05566d9351615cb31b4cc070185c25bf8cbd9b09c1873aa5ec6f3cc17e golangci-lint-1.61.0-linux-arm64.tar.gz -1f307f2fcc5d7d674062a967a0d83a7091e300529aa237ec6ad2b3dd14c897f5 golangci-lint-1.61.0-linux-armv6.tar.gz -3ad8cbaae75a547450844811300f99c4cd290277398e43d22b9eb1792d15af4c golangci-lint-1.61.0-linux-armv7.tar.gz -9be2ca67d961d7699079739cf6f7c8291c5183d57e34d1677de21ca19d0bd3ed golangci-lint-1.61.0-linux-loong64.tar.gz -90d005e1648115ebf0861b408eab9c936079a24763e883058b0a227cd3135d31 golangci-lint-1.61.0-linux-mips64.tar.gz -6d2ed4f49407115460b8c10ccfc40fd177e0887a48864a2879dd16e84ba2a48c golangci-lint-1.61.0-linux-mips64le.tar.gz -633089589af5a58b7430afb6eee107d4e9c99e8d91711ddc219eb13a07e8d3b8 golangci-lint-1.61.0-linux-ppc64le.tar.gz -4c1a097d9e0d1b4a8144dae6a1f5583a38d662f3bdc1498c4e954b6ed856be98 golangci-lint-1.61.0-linux-riscv64.tar.gz -30581d3c987d287b7064617f1a2694143e10dffc40bc25be6636006ee82d7e1c golangci-lint-1.61.0-linux-s390x.tar.gz -42530bf8100bd43c07f5efe6d92148ba6c5a7a712d510c6f24be85af6571d5eb golangci-lint-1.61.0-netbsd-386.tar.gz -b8bb07c920f6601edf718d5e82ec0784fd590b0992b42b6ec18da99f26013ed4 golangci-lint-1.61.0-netbsd-amd64.tar.gz -353a51527c60bd0776b0891b03f247c791986f625fca689d121972c624e54198 golangci-lint-1.61.0-netbsd-arm64.tar.gz -957a6272c3137910514225704c5dac0723b9c65eb7d9587366a997736e2d7580 golangci-lint-1.61.0-netbsd-armv6.tar.gz -a89eb28ff7f18f5cd52b914739360fa95cf2f643de4adeca46e26bec3a07e8d8 golangci-lint-1.61.0-netbsd-armv7.tar.gz -d8d74c43600b271393000717a4ed157d7a15bb85bab7db2efad9b63a694d4634 golangci-lint-1.61.0-windows-386.zip -e7bc2a81929a50f830244d6d2e657cce4f19a59aff49fa9000176ff34fda64ce golangci-lint-1.61.0-windows-amd64.zip -ed97c221596dd771e3dd9344872c140340bee2e819cd7a90afa1de752f1f2e0f golangci-lint-1.61.0-windows-arm64.zip -4b365233948b13d02d45928a5c390045e00945e919747b9887b5f260247541ae golangci-lint-1.61.0-windows-armv6.zip -595538fb64d152173959d28f6235227f9cd969a828e5af0c4e960d02af4ffd0e golangci-lint-1.61.0-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.63.4/ +878d017cc360e4fb19510d39852c8189852e3c48e7ce0337577df73507c97d68 golangci-lint-1.63.4-darwin-amd64.tar.gz +a2b630c2ac8466393f0ccbbede4462387b6c190697a70bc2298c6d2123f21bbf golangci-lint-1.63.4-darwin-arm64.tar.gz +8938b74aa92888e561a1c5a4c175110b92f84e7d24733703e6d9ebc39e9cd5f8 golangci-lint-1.63.4-freebsd-386.tar.gz +054903339d620df2e760b978920100986e3b03bcb058f669d520a71dac9c34ed golangci-lint-1.63.4-freebsd-amd64.tar.gz +a19d499f961a02608348e8b626537a88edfaab6e1b6534f1eff742b5d6d750e4 golangci-lint-1.63.4-freebsd-armv6.tar.gz +00d616f0fb275b780ce4d26604bdd7fdbfe6bc9c63acd5a0b31498e1f7511108 golangci-lint-1.63.4-freebsd-armv7.tar.gz +d453688e0eabded3c1a97ff5a2777bb0df5a18851efdaaaf6b472e3e5713c33e golangci-lint-1.63.4-illumos-amd64.tar.gz +6b1bec847fc9f347d53712d05606a49d55d0e3b5c1bacadfed2393f3503de0e9 golangci-lint-1.63.4-linux-386.tar.gz +01abb14a4df47b5ca585eff3c34b105023cba92ec34ff17212dbb83855581690 golangci-lint-1.63.4-linux-amd64.tar.gz +51f0c79d19a92353e0465fb30a4901a0644a975d34e6f399ad2eebc0160bbb24 golangci-lint-1.63.4-linux-arm64.tar.gz +8d0a43f41e8424fbae10f7aa2dc29999f98112817c6dba63d7dc76832940a673 golangci-lint-1.63.4-linux-armv6.tar.gz +1045a047b31e9302c9160c7b0f199f4ac1bd02a1b221a2d9521bd3507f0cf671 golangci-lint-1.63.4-linux-armv7.tar.gz +933fe10ab50ce3bb0806e15a4ae69fe20f0549abf91dea0161236000ca706e67 golangci-lint-1.63.4-linux-loong64.tar.gz +45798630cbad5642862766051199fa862ef3c33d569cab12f01cac4f68e2ddd5 golangci-lint-1.63.4-linux-mips64.tar.gz +86ae25335ddb24975d2c915c1af0c7fad70dce99d0b4614fa4bee392de714aa2 golangci-lint-1.63.4-linux-mips64le.tar.gz +33dabd11aaba4b602938da98bcf49aabab55019557e0115cdc3dbcc3009768fa golangci-lint-1.63.4-linux-ppc64le.tar.gz +4e7a81230a663bcdf30bba5689ce96040abc76994dbc2003dce32c8dca8c06f3 golangci-lint-1.63.4-linux-riscv64.tar.gz +21370b49c7c47f4d9b8f982c952f940b01e65710174c3b4dad7b6452d58f92ec golangci-lint-1.63.4-linux-s390x.tar.gz +255866a6464c7e11bb7edd8e6e6ad54f11e1f01b82ba9ca229698ac788cd9724 golangci-lint-1.63.4-netbsd-386.tar.gz +2798c040ac658bda97224f204795199c81ac97bb207b21c02b664aaed380d5d2 golangci-lint-1.63.4-netbsd-amd64.tar.gz +b910eecffd0064103837e7e1abe870deb8ade22331e6dffe319f430d49399c8e golangci-lint-1.63.4-netbsd-arm64.tar.gz +df2693ef37147b457c3e2089614537dd2ae2e18e53641e756a5b404f4c72d3fa golangci-lint-1.63.4-netbsd-armv6.tar.gz +a28a533366974bd7834c4516cd6075bff3419a508d1ed7aa63ae8182768b352e golangci-lint-1.63.4-netbsd-armv7.tar.gz +368932775fb5c620b324dabf018155f3365f5e33c5af5b26e9321db373f96eea golangci-lint-1.63.4-windows-386.zip +184d13c2b8f5441576bec2a0d8ba7b2d45445595cf796b879a73bcc98c39f8c1 golangci-lint-1.63.4-windows-amd64.zip +4fabf175d5b05ef0858ded49527948eebac50e9093814979fd84555a75fb80a6 golangci-lint-1.63.4-windows-arm64.zip +e92be3f3ff30d4a849fb4b9a4c8d56837dee45269cb405a3ecad52fa034c781b golangci-lint-1.63.4-windows-armv6.zip +c71d348653b8f7fbb109bb10c1a481722bc6b0b2b6e731b897f99ac869f7653e golangci-lint-1.63.4-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 122d6f9b5..7a55ad079 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1772,7 +1772,7 @@ func (p *BlobPool) Clear() { // The transaction addition may attempt to reserve the sender addr which // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. - for acct, _ := range p.index { + for acct := range p.index { p.reserve(acct, false) } p.lookup = newLookup() diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 7d6dbcd07..a12af0f08 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -2115,7 +2115,7 @@ func (pool *LegacyPool) Clear() { senderAddr, _ := types.Sender(pool.signer, tx) pool.reserve(senderAddr, false) } - for localSender, _ := range pool.locals.accounts { + for localSender := range pool.locals.accounts { pool.reserve(localSender, false) } From 53fd3750c4ceb1b0e95a553649b39d7e65212d78 Mon Sep 17 00:00:00 2001 From: Martin Redmond <21436+reds@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:12:15 -0500 Subject: [PATCH 070/354] eth/tracers/logger: return revert reason (#31013) Fix the error comparison in tracer to prevent dropping revert reason data --------- Co-authored-by: Martin Co-authored-by: rjl493456442 --- eth/tracers/logger/logger.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 07de871f1..596ee9714 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -19,6 +19,7 @@ package logger import ( "encoding/hex" "encoding/json" + "errors" "fmt" "io" "maps" @@ -350,7 +351,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { returnData := common.CopyBytes(l.output) // Return data when successful and revert reason when reverted, otherwise empty. returnVal := fmt.Sprintf("%x", returnData) - if failed && l.err != vm.ErrExecutionReverted { + if failed && !errors.Is(l.err, vm.ErrExecutionReverted) { returnVal = "" } return json.Marshal(&ExecutionResult{ From 1ba9b247d881ae8b95a0de1f873bcae5ee6416df Mon Sep 17 00:00:00 2001 From: dashangcun <907225865@qq.com> Date: Mon, 13 Jan 2025 18:00:25 +0100 Subject: [PATCH 071/354] cmd/devp2p/internal/ethtest: using slices.SortFunc to simplify the code (#31012) Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/chain.go | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 2a70e0328..222c66d4d 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -28,7 +28,6 @@ import ( "os" "path/filepath" "slices" - "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -41,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/exp/maps" ) // Chain is a lightweight blockchain-like store which can read a hivechain @@ -166,11 +166,8 @@ func (c *Chain) RootAt(height int) common.Hash { // GetSender returns the address associated with account at the index in the // pre-funded accounts list. func (c *Chain) GetSender(idx int) (common.Address, uint64) { - var accounts Addresses - for addr := range c.senders { - accounts = append(accounts, addr) - } - sort.Sort(accounts) + accounts := maps.Keys(c.senders) + slices.SortFunc(accounts, common.Address.Cmp) addr := accounts[idx] return addr, c.senders[addr].Nonce } @@ -260,22 +257,6 @@ func loadGenesis(genesisFile string) (core.Genesis, error) { return gen, nil } -type Addresses []common.Address - -func (a Addresses) Len() int { - return len(a) -} - -func (a Addresses) Less(i, j int) bool { - return bytes.Compare(a[i][:], a[j][:]) < 0 -} - -func (a Addresses) Swap(i, j int) { - tmp := a[i] - a[i] = a[j] - a[j] = tmp -} - func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) { // Load chain.rlp. fh, err := os.Open(chainfile) From 265290ea084dee273008f0e8b133284c65aff644 Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Mon, 13 Jan 2025 19:33:49 +0100 Subject: [PATCH 072/354] core/txpool/legacypool: fix flaky test TestAllowedTxSize (#30975) - it was failing because the maximum data length (previously `dataSize`) was set to `txMaxSize - 213` but should had been `txMaxSize - 103` and the last call `dataSize+1+uint64(rand.Intn(10*txMaxSize)))` would sometimes fail depending on rand.Intn. - Maximal transaction data size comment (invalid) replaced by code logic to find the maximum tx length without its data length - comments and variable naming improved for clarity - 3rd pool add test replaced to add just 1 above the maximum length, which is important to ensure the logic is correct --- core/txpool/legacypool/legacypool_test.go | 31 ++++++++++------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 39673d176..abbde8cae 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -1243,33 +1243,28 @@ func TestAllowedTxSize(t *testing.T) { account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000)) - // Compute maximal data size for transactions (lower bound). - // - // It is assumed the fields in the transaction (except of the data) are: - // - nonce <= 32 bytes - // - gasTip <= 32 bytes - // - gasLimit <= 32 bytes - // - recipient == 20 bytes - // - value <= 32 bytes - // - signature == 65 bytes - // All those fields are summed up to at most 213 bytes. - baseSize := uint64(213) - dataSize := txMaxSize - baseSize + // Find the maximum data length for the kind of transaction which will + // be generated in the pool.addRemoteSync calls below. + const largeDataLength = txMaxSize - 200 // enough to have a 5 bytes RLP encoding of the data length number + txWithLargeData := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, largeDataLength) + maxTxLengthWithoutData := txWithLargeData.Size() - largeDataLength // 103 bytes + maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130953 bytes + // Try adding a transaction with maximal allowed size - tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize) + tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength) if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) } // Try adding a transaction with random allowed size - if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { + if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(maxTxDataLength+1))))); err != nil { t.Fatalf("failed to add transaction of random allowed size: %v", err) } - // Try adding a transaction of minimal not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, txMaxSize)); err == nil { + // Try adding a transaction above maximum size by one + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1)); err == nil { t.Fatalf("expected rejection on slightly oversize transaction") } - // Try adding a transaction of random not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { + // Try adding a transaction above maximum size by more than one + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { t.Fatalf("expected rejection on oversize transaction") } // Run some sanity checks on the pool internals From f1f30300caec63b69af2d80851e7d96ddcaa8ddd Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Mon, 13 Jan 2025 19:35:49 +0100 Subject: [PATCH 073/354] core: remove unused function parameters (#31001) --- core/blockchain_test.go | 17 ++++------------- core/state_transition.go | 4 ++-- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index fd2fc365b..ec2f705a1 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2538,7 +2538,7 @@ func testReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T, scheme strin } // Benchmarks large blocks with value transfers to non-existing accounts -func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { +func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address) { var ( signer = types.HomesteadSigner{} testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -2601,10 +2601,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(1337 + nonce)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { @@ -2618,10 +2615,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(1337)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } func BenchmarkBlockChain_1x1000Executions(b *testing.B) { @@ -2635,10 +2629,7 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(0xc0de)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } // Tests that importing a some old blocks, where all blocks are before the diff --git a/core/state_transition.go b/core/state_transition.go index f432ad63d..182e0ecd9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -510,7 +510,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if msg.SetCodeAuthorizations != nil { for _, auth := range msg.SetCodeAuthorizations { // Note errors are ignored, we simply skip invalid authorizations here. - st.applyAuthorization(msg, &auth) + st.applyAuthorization(&auth) } } @@ -599,7 +599,7 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio } // applyAuthorization applies an EIP-7702 code delegation to the state. -func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error { +func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error { authority, err := st.validateAuthorization(auth) if err != nil { return err From 8b2e2ad3300aab5b92dfcb7b9f86373070d42534 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 14 Jan 2025 18:49:30 +0800 Subject: [PATCH 074/354] cmd, core, miner: rework genesis setup (#30907) This pull request refactors the genesis setup function, the major changes are highlighted here: **(a) Triedb is opened in verkle mode if `EnableVerkleAtGenesis` is configured in chainConfig or the database has been initialized previously with `EnableVerkleAtGenesis` configured**. A new config field `EnableVerkleAtGenesis` has been added in the chainConfig. This field must be configured with True if Geth wants to initialize the genesis in Verkle mode. In the verkle devnet-7, the verkle transition is activated at genesis. Therefore, the verkle rules should be used since the genesis. In production networks (mainnet and public testnets), verkle activation always occurs after the genesis block. Therefore, this flag is only made for devnet and should be deprecated later. Besides, verkle transition at non-genesis block hasn't been implemented yet, it should be done in the following PRs. **(b) The genesis initialization condition has been simplified** There is a special mode supported by the Geth is that: Geth can be initialized with an existing chain segment, which can fasten the node sync process by retaining the chain freezer folder. Originally, if the triedb is regarded as uninitialized and the genesis block can be found in the chain freezer, the genesis block along with genesis state will be committed. This condition has been simplified to checking the presence of chain config in key-value store. The existence of chain config can represent the genesis has been committed. --- cmd/geth/chaincmd.go | 3 +- cmd/utils/history_test.go | 2 +- core/blockchain.go | 31 +++--- core/genesis.go | 208 +++++++++++++++++++++--------------- core/genesis_test.go | 41 +++---- core/verkle_witness_test.go | 2 + miner/miner_test.go | 2 +- params/config.go | 27 +++++ triedb/database.go | 10 -- triedb/hashdb/database.go | 6 -- triedb/pathdb/database.go | 15 --- 11 files changed, 194 insertions(+), 153 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 48564eb5e..bbadb1cc1 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -230,11 +230,10 @@ func initGenesis(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) defer triedb.Close() - _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) + _, hash, _, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } - log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash) return nil diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index a631eaf49..e5acd8bef 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -170,7 +170,7 @@ func TestHistoryImportAndExport(t *testing.T) { db2.Close() }) - genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults)) + genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults)) imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) diff --git a/core/blockchain.go b/core/blockchain.go index 2c6cd44e3..9cdedfe0c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -277,14 +277,19 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } // Open trie database with provided config - triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis != nil && genesis.IsVerkle())) + enableVerkle, err := EnableVerkleAtGenesis(db, genesis) + if err != nil { + return nil, err + } + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle)) - // Setup the genesis block, commit the provided genesis specification - // to database if the genesis block is not present yet, or load the - // stored one from database. - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr + // Write the supplied genesis to the database if it has not been initialized + // yet. The corresponding chain config will be returned, either from the + // provided genesis or from the locally stored configuration if the genesis + // has already been initialized. + chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) + if err != nil { + return nil, err } log.Info("") log.Info(strings.Repeat("-", 153)) @@ -312,7 +317,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis vmConfig: vmConfig, logger: vmConfig.Tracer, } - var err error bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err @@ -467,16 +471,15 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis go bc.updateFutureBlocks() // Rewind the chain in case of an incompatible config upgrade. - if compat, ok := genesisErr.(*params.ConfigCompatError); ok { - log.Warn("Rewinding chain to upgrade configuration", "err", compat) - if compat.RewindToTime > 0 { - bc.SetHeadWithTimestamp(compat.RewindToTime) + if compatErr != nil { + log.Warn("Rewinding chain to upgrade configuration", "err", compatErr) + if compatErr.RewindToTime > 0 { + bc.SetHeadWithTimestamp(compatErr.RewindToTime) } else { - bc.SetHead(compat.RewindToBlock) + bc.SetHead(compatErr.RewindToBlock) } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } - // Start tx indexer if it's enabled. if txLookupLimit != nil { bc.txIndexer = newTxIndexer(*txLookupLimit, bc) diff --git a/core/genesis.go b/core/genesis.go index db67e9887..672cc177c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -249,6 +249,24 @@ type ChainOverrides struct { OverrideVerkle *uint64 } +// apply applies the chain overrides on the supplied chain config. +func (o *ChainOverrides) apply(cfg *params.ChainConfig) (*params.ChainConfig, error) { + if o == nil || cfg == nil { + return cfg, nil + } + cpy := *cfg + if o.OverrideCancun != nil { + cpy.CancunTime = o.OverrideCancun + } + if o.OverrideVerkle != nil { + cpy.VerkleTime = o.OverrideVerkle + } + if err := cpy.CheckConfigForkOrder(); err != nil { + return nil, err + } + return &cpy, nil +} + // SetupGenesisBlock writes or updates the genesis block in db. // The block that will be used is: // @@ -260,113 +278,106 @@ type ChainOverrides struct { // The stored chain configuration will be updated if it is compatible (i.e. does not // specify a fork block below the local head block). In case of a conflict, the // error is a *params.ConfigCompatError and the new, unwritten config is returned. -// -// The returned chain configuration is never nil. -func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlockWithOverride(db, triedb, genesis, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { + // Sanitize the supplied genesis, ensuring it has the associated chain + // config attached. if genesis != nil && genesis.Config == nil { - return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig - } - applyOverrides := func(config *params.ChainConfig) { - if config != nil { - if overrides != nil && overrides.OverrideCancun != nil { - config.CancunTime = overrides.OverrideCancun - } - if overrides != nil && overrides.OverrideVerkle != nil { - config.VerkleTime = overrides.OverrideVerkle - } - } + return nil, common.Hash{}, nil, errGenesisNoConfig } - // Just commit the new block if there is no stored genesis block. - stored := rawdb.ReadCanonicalHash(db, 0) - if (stored == common.Hash{}) { + // Commit the genesis if the database is empty + ghash := rawdb.ReadCanonicalHash(db, 0) + if (ghash == common.Hash{}) { if genesis == nil { log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() } else { log.Info("Writing custom genesis block") } + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg - applyOverrides(genesis.Config) block, err := genesis.Commit(db, triedb) if err != nil { - return genesis.Config, common.Hash{}, err + return nil, common.Hash{}, nil, err } - return genesis.Config, block.Hash(), nil - } - // The genesis block is present(perhaps in ancient database) while the - // state database is not initialized yet. It can happen that the node - // is initialized with an external ancient store. Commit genesis state - // in this case. - header := rawdb.ReadHeader(db, stored, 0) - if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) { + return chainCfg, block.Hash(), nil, nil + } + // Commit the genesis if the genesis block exists in the ancient database + // but the key-value database is empty without initializing the genesis + // fields. This scenario can occur when the node is created from scratch + // with an existing ancient store. + storedCfg := rawdb.ReadChainConfig(db, ghash) + if storedCfg == nil { + // Ensure the stored genesis block matches with the given genesis. Private + // networks must explicitly specify the genesis in the config file, mainnet + // genesis will be used as default and the initialization will always fail. if genesis == nil { + log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() + } else { + log.Info("Writing custom genesis block") } - applyOverrides(genesis.Config) - // Ensure the stored genesis matches with the given one. - hash := genesis.ToBlock().Hash() - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg + + if hash := genesis.ToBlock().Hash(); hash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } block, err := genesis.Commit(db, triedb) if err != nil { - return genesis.Config, hash, err + return nil, common.Hash{}, nil, err } - return genesis.Config, block.Hash(), nil + return chainCfg, block.Hash(), nil, nil } - // Check whether the genesis block is already written. + // The genesis block has already been committed previously. Verify that the + // provided genesis with chain overrides matches the existing one, and update + // the stored chain config if necessary. if genesis != nil { - applyOverrides(genesis.Config) - hash := genesis.ToBlock().Hash() - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg + + if hash := genesis.ToBlock().Hash(); hash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } - } - // Get the existing chain configuration. - newcfg := genesis.configOrDefault(stored) - applyOverrides(newcfg) - if err := newcfg.CheckConfigForkOrder(); err != nil { - return newcfg, common.Hash{}, err - } - storedcfg := rawdb.ReadChainConfig(db, stored) - if storedcfg == nil { - log.Warn("Found genesis block without chain config") - rawdb.WriteChainConfig(db, stored, newcfg) - return newcfg, stored, nil - } - storedData, _ := json.Marshal(storedcfg) - // Special case: if a private network is being used (no genesis and also no - // mainnet hash in the database), we must not apply the `configOrDefault` - // chain config as that would be AllProtocolChanges (applying any new fork - // on top of an existing private network genesis block). In that case, only - // apply the overrides. - if genesis == nil && stored != params.MainnetGenesisHash { - newcfg = storedcfg - applyOverrides(newcfg) } // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. head := rawdb.ReadHeadHeader(db) if head == nil { - return newcfg, stored, errors.New("missing head header") + return nil, common.Hash{}, nil, errors.New("missing head header") } - compatErr := storedcfg.CheckCompatible(newcfg, head.Number.Uint64(), head.Time) + newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) + + // TODO(rjl493456442) better to define the comparator of chain config + // and short circuit if the chain config is not changed. + compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time) if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) { - return newcfg, stored, compatErr + return newCfg, ghash, compatErr, nil } - engineCompatErr := storedcfg.CheckConsensusEngineCompatible(newcfg) + engineCompatErr := storedCfg.CheckConsensusEngineCompatible(newCfg) if engineCompatErr != nil { - return newcfg, stored, engineCompatErr + return newCfg, ghash, nil, engineCompatErr } - // Don't overwrite if the old is identical to the new - if newData, _ := json.Marshal(newcfg); !bytes.Equal(storedData, newData) { - rawdb.WriteChainConfig(db, stored, newcfg) + // Don't overwrite if the old is identical to the new. It's useful + // for the scenarios that database is opened in the read-only mode. + storedData, _ := json.Marshal(storedCfg) + if newData, _ := json.Marshal(newCfg); !bytes.Equal(storedData, newData) { + rawdb.WriteChainConfig(db, ghash, newCfg) } - return newcfg, stored, nil + return newCfg, ghash, nil, nil } // LoadChainConfig loads the stored chain config if it is already present in @@ -402,7 +413,10 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, return params.MainnetChainConfig, nil } -func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { +// chainConfigOrDefault retrieves the attached chain configuration. If the genesis +// object is null, it returns the default chain configuration based on the given +// genesis hash, or the locally stored config if it's not a pre-defined network. +func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainConfig) *params.ChainConfig { switch { case g != nil: return g.Config @@ -413,14 +427,14 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig default: - return params.AllEthashProtocolChanges + return stored } } // IsVerkle indicates whether the state is already stored in a verkle // tree at genesis time. func (g *Genesis) IsVerkle() bool { - return g.Config.IsVerkle(new(big.Int).SetUint64(g.Number), g.Timestamp) + return g.Config.IsVerkleGenesis() } // ToBlock returns the genesis block according to genesis specification. @@ -525,7 +539,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo } config := g.Config if config == nil { - config = params.AllEthashProtocolChanges + return nil, errors.New("invalid genesis without chain config") } if err := config.CheckConfigForkOrder(); err != nil { return nil, err @@ -589,16 +603,17 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo if err != nil { return nil, err } - rawdb.WriteGenesisStateSpec(db, block.Hash(), blob) - rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) - rawdb.WriteBlock(db, block) - rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) - rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) - rawdb.WriteHeadBlockHash(db, block.Hash()) - rawdb.WriteHeadFastBlockHash(db, block.Hash()) - rawdb.WriteHeadHeaderHash(db, block.Hash()) - rawdb.WriteChainConfig(db, block.Hash(), config) - return block, nil + batch := db.NewBatch() + rawdb.WriteGenesisStateSpec(batch, block.Hash(), blob) + rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), block.Difficulty()) + rawdb.WriteBlock(batch, block) + rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil) + rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(batch, block.Hash()) + rawdb.WriteHeadFastBlockHash(batch, block.Hash()) + rawdb.WriteHeadHeaderHash(batch, block.Hash()) + rawdb.WriteChainConfig(batch, block.Hash(), config) + return block, batch.Write() } // MustCommit writes the genesis block and state to db, panicking on error. @@ -611,6 +626,29 @@ func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types. return block } +// EnableVerkleAtGenesis indicates whether the verkle fork should be activated +// at genesis. This is a temporary solution only for verkle devnet testing, where +// verkle fork is activated at genesis, and the configured activation date has +// already passed. +// +// In production networks (mainnet and public testnets), verkle activation always +// occurs after the genesis block, making this function irrelevant in those cases. +func EnableVerkleAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) { + if genesis != nil { + if genesis.Config == nil { + return false, errGenesisNoConfig + } + return genesis.Config.EnableVerkleAtGenesis, nil + } + if ghash := rawdb.ReadCanonicalHash(db, 0); ghash != (common.Hash{}) { + chainCfg := rawdb.ReadChainConfig(db, ghash) + if chainCfg != nil { + return chainCfg.EnableVerkleAtGenesis, nil + } + } + return false, nil +} + // DefaultGenesisBlock returns the Ethereum main net genesis block. func DefaultGenesisBlock() *Genesis { return &Genesis{ diff --git a/core/genesis_test.go b/core/genesis_test.go index 1bb930a6a..93dc34487 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -54,23 +54,23 @@ func testSetupGenesis(t *testing.T, scheme string) { oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} tests := []struct { - name string - fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) - wantConfig *params.ChainConfig - wantHash common.Hash - wantErr error + name string + fn func(ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) + wantConfig *params.ChainConfig + wantHash common.Hash + wantErr error + wantCompactErr *params.ConfigCompatError }{ { name: "genesis without ChainConfig", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis)) }, - wantErr: errGenesisNoConfig, - wantConfig: params.AllEthashProtocolChanges, + wantErr: errGenesisNoConfig, }, { name: "no block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) }, wantHash: params.MainnetGenesisHash, @@ -78,7 +78,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "mainnet block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { DefaultGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme))) return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) }, @@ -87,7 +87,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "custom block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, nil) @@ -97,18 +97,16 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "custom block in DB, genesis == sepolia", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock()) }, - wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, - wantHash: params.SepoliaGenesisHash, - wantConfig: params.SepoliaChainConfig, + wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, }, { name: "compatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) oldcustomg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, &customg) @@ -118,7 +116,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "incompatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. tdb := triedb.NewDatabase(db, newDbConfig(scheme)) @@ -135,7 +133,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, wantHash: customghash, wantConfig: customg.Config, - wantErr: ¶ms.ConfigCompatError{ + wantCompactErr: ¶ms.ConfigCompatError{ What: "Homestead fork block", StoredBlock: big.NewInt(2), NewBlock: big.NewInt(3), @@ -146,12 +144,16 @@ func testSetupGenesis(t *testing.T, scheme string) { for _, test := range tests { db := rawdb.NewMemoryDatabase() - config, hash, err := test.fn(db) + config, hash, compatErr, err := test.fn(db) // Check the return values. if !reflect.DeepEqual(err, test.wantErr) { spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) } + if !reflect.DeepEqual(compatErr, test.wantCompactErr) { + spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} + t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(compatErr), spew.NewFormatter(test.wantCompactErr)) + } if !reflect.DeepEqual(config, test.wantConfig) { t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) } @@ -279,6 +281,7 @@ func TestVerkleGenesisCommit(t *testing.T) { PragueTime: &verkleTime, VerkleTime: &verkleTime, TerminalTotalDifficulty: big.NewInt(0), + EnableVerkleAtGenesis: true, Ethash: nil, Clique: nil, } diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index c8938c9c6..fb72b9461 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -57,6 +57,7 @@ var ( ShanghaiTime: u64(0), VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, + EnableVerkleAtGenesis: true, // TODO uncomment when proof generation is merged // ProofInBlocks: true, } @@ -77,6 +78,7 @@ var ( ShanghaiTime: u64(0), VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, + EnableVerkleAtGenesis: true, } ) diff --git a/miner/miner_test.go b/miner/miner_test.go index 137abe58a..6714e4405 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -303,7 +303,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { chainDB := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(chainDB, nil) genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) - chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) + chainConfig, _, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) if err != nil { t.Fatalf("can't create new chain config: %v", err) } diff --git a/params/config.go b/params/config.go index a30e378bd..e228ac1b1 100644 --- a/params/config.go +++ b/params/config.go @@ -329,6 +329,19 @@ type ChainConfig struct { DepositContractAddress common.Address `json:"depositContractAddress,omitempty"` + // EnableVerkleAtGenesis is a flag that specifies whether the network uses + // the Verkle tree starting from the genesis block. If set to true, the + // genesis state will be committed using the Verkle tree, eliminating the + // need for any Verkle transition later. + // + // This is a temporary flag only for verkle devnet testing, where verkle is + // activated at genesis, and the configured activation date has already passed. + // + // In production networks (mainnet and public testnets), verkle activation + // always occurs after the genesis block, making this flag irrelevant in + // those cases. + EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"` + // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` @@ -567,6 +580,20 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } +// IsVerkleGenesis checks whether the verkle fork is activated at the genesis block. +// +// Verkle mode is considered enabled if the verkle fork time is configured, +// regardless of whether the local time has surpassed the fork activation time. +// This is a temporary workaround for verkle devnet testing, where verkle is +// activated at genesis, and the configured activation date has already passed. +// +// In production networks (mainnet and public testnets), verkle activation +// always occurs after the genesis block, making this function irrelevant in +// those cases. +func (c *ChainConfig) IsVerkleGenesis() bool { + return c.EnableVerkleAtGenesis +} + // IsEIP4762 returns whether eip 4762 has been activated at given block. func (c *ChainConfig) IsEIP4762(num *big.Int, time uint64) bool { return c.IsVerkle(num, time) diff --git a/triedb/database.go b/triedb/database.go index b448d7cd0..f8ccc5ad3 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -64,10 +64,6 @@ type backend interface { // state. An error will be returned if the specified state is not available. StateReader(root common.Hash) (database.StateReader, error) - // Initialized returns an indicator if the state data is already initialized - // according to the state scheme. - Initialized(genesisRoot common.Hash) bool - // Size returns the current storage size of the diff layers on top of the // disk layer and the storage size of the nodes cached in the disk layer. // @@ -178,12 +174,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize, common.Stora return diffs, nodes, preimages } -// Initialized returns an indicator if the state data is already initialized -// according to the state scheme. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - return db.backend.Initialized(genesisRoot) -} - // Scheme returns the node scheme used in the database. func (db *Database) Scheme() string { if db.config.PathDB != nil { diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index fb718f4e7..38392aa51 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -532,12 +532,6 @@ func (c *cleaner) Delete(key []byte) error { panic("not implemented") } -// Initialized returns an indicator if state data is already initialized -// in hash-based scheme by checking the presence of genesis state. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - return rawdb.HasLegacyTrieNode(db.diskdb, genesisRoot) -} - // Update inserts the dirty nodes in provided nodeset into database and link the // account trie with multiple storage tries if necessary. func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet) error { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index c31f1d44f..b0d84eb87 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -529,21 +529,6 @@ func (db *Database) Size() (diffs common.StorageSize, nodes common.StorageSize) return diffs, nodes } -// Initialized returns an indicator if the state data is already -// initialized in path-based scheme. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - var inited bool - db.tree.forEach(func(layer layer) { - if layer.rootHash() != types.EmptyRootHash { - inited = true - } - }) - if !inited { - inited = rawdb.ReadSnapSyncStatusFlag(db.diskdb) != rawdb.StateSyncUnknown - } - return inited -} - // modifyAllowed returns the indicator if mutation is allowed. This function // assumes the db.lock is already held. func (db *Database) modifyAllowed() error { From 03d9395969c3e67eb82aa3be5f4a6a5ae8a0ca1b Mon Sep 17 00:00:00 2001 From: georgehao Date: Tue, 14 Jan 2025 21:16:15 +0800 Subject: [PATCH 075/354] all: fix some typos in comments and names (#31023) --- accounts/accounts.go | 4 +++- cmd/devp2p/internal/ethtest/protocol.go | 1 + cmd/devp2p/internal/v4test/discv4tests.go | 18 ++++++++-------- consensus/clique/snapshot_test.go | 1 - core/tracing/hooks.go | 2 +- core/txpool/legacypool/legacypool2_test.go | 6 +++--- core/types/deposit.go | 2 +- core/vm/eof_validation.go | 6 +++--- core/vm/program/program.go | 5 +++-- crypto/blake2b/blake2b.go | 8 +++---- crypto/bn256/gnark/pairing.go | 2 +- crypto/ecies/ecies.go | 12 +++++------ eth/tracers/dir.go | 2 +- eth/tracers/internal/util.go | 1 + internal/era/builder.go | 3 ++- internal/jsre/jsre.go | 25 +++++++++++++++++++--- internal/reexec/reexec.go | 1 + metrics/exp/exp.go | 1 + metrics/gauge_info.go | 2 +- metrics/log.go | 2 +- metrics/metrics.go | 1 + metrics/resetting_timer.go | 6 +++--- metrics/syslog.go | 2 +- p2p/discover/v5wire/encoding_test.go | 12 +++++------ signer/core/api.go | 2 +- signer/core/uiapi.go | 2 +- 26 files changed, 78 insertions(+), 51 deletions(-) diff --git a/accounts/accounts.go b/accounts/accounts.go index b995498a6..7bd911577 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -214,7 +214,9 @@ const ( // of starting any background processes such as automatic key derivation. WalletOpened - // WalletDropped + // WalletDropped is fired when a wallet is removed or disconnected, either via USB + // or due to a filesystem event in the keystore. This event indicates that the wallet + // is no longer available for operations. WalletDropped ) diff --git a/cmd/devp2p/internal/ethtest/protocol.go b/cmd/devp2p/internal/ethtest/protocol.go index f5f5f7e48..5c2f7d9e4 100644 --- a/cmd/devp2p/internal/ethtest/protocol.go +++ b/cmd/devp2p/internal/ethtest/protocol.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . + package ethtest import ( diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index ca556851b..963df6cdb 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -194,7 +194,7 @@ func PingExtraData(t *utesting.T) { } } -// This test sends a PING packet with additional data and wrong 'from' field +// PingExtraDataWrongFrom sends a PING packet with additional data and wrong 'from' field // and expects a PONG response. func PingExtraDataWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -215,7 +215,7 @@ func PingExtraDataWrongFrom(t *utesting.T) { } } -// This test sends a PING packet with an expiration in the past. +// PingPastExpiration sends a PING packet with an expiration in the past. // The remote node should not respond. func PingPastExpiration(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -234,7 +234,7 @@ func PingPastExpiration(t *utesting.T) { } } -// This test sends an invalid packet. The remote node should not respond. +// WrongPacketType sends an invalid packet. The remote node should not respond. func WrongPacketType(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() @@ -252,7 +252,7 @@ func WrongPacketType(t *utesting.T) { } } -// This test verifies that the default behaviour of ignoring 'from' fields is unaffected by +// BondThenPingWithWrongFrom verifies that the default behaviour of ignoring 'from' fields is unaffected by // the bonding process. After bonding, it pings the target with a different from endpoint. func BondThenPingWithWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -289,7 +289,7 @@ waitForPong: } } -// This test just sends FINDNODE. The remote node should not reply +// FindnodeWithoutEndpointProof sends FINDNODE. The remote node should not reply // because the endpoint proof has not completed. func FindnodeWithoutEndpointProof(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -332,7 +332,7 @@ func BasicFindnode(t *utesting.T) { } } -// This test sends an unsolicited NEIGHBORS packet after the endpoint proof, then sends +// UnsolicitedNeighbors sends an unsolicited NEIGHBORS packet after the endpoint proof, then sends // FINDNODE to read the remote table. The remote node should not return the node contained // in the unsolicited NEIGHBORS packet. func UnsolicitedNeighbors(t *utesting.T) { @@ -373,7 +373,7 @@ func UnsolicitedNeighbors(t *utesting.T) { } } -// This test sends FINDNODE with an expiration timestamp in the past. +// FindnodePastExpiration sends FINDNODE with an expiration timestamp in the past. // The remote node should not respond. func FindnodePastExpiration(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -426,7 +426,7 @@ func bond(t *utesting.T, te *testenv) { } } -// This test attempts to perform a traffic amplification attack against a +// FindnodeAmplificationInvalidPongHash attempts to perform a traffic amplification attack against a // 'victim' endpoint using FINDNODE. In this attack scenario, the attacker // attempts to complete the endpoint proof non-interactively by sending a PONG // with mismatching reply token from the 'victim' endpoint. The attack works if @@ -478,7 +478,7 @@ func FindnodeAmplificationInvalidPongHash(t *utesting.T) { } } -// This test attempts to perform a traffic amplification attack using FINDNODE. +// FindnodeAmplificationWrongIP attempts to perform a traffic amplification attack using FINDNODE. // The attack works if the remote node does not verify the IP address of FINDNODE // against the endpoint verification proof done by PING/PONG. func FindnodeAmplificationWrongIP(t *utesting.T) { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 4ef7a7b3a..05ec22137 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -467,7 +467,6 @@ func (tt *cliqueTest) run(t *testing.T) { for j := 0; j < len(batches)-1; j++ { if k, err := chain.InsertChain(batches[j]); err != nil { t.Fatalf("failed to import batch %d, block %d: %v", j, k, err) - break } } if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure { diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 728f15069..4343edfe8 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -293,7 +293,7 @@ const ( GasChangeCallLeftOverRefunded GasChangeReason = 7 // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. GasChangeCallContractCreation GasChangeReason = 8 - // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. + // GasChangeCallContractCreation2 is the amount of gas that will be burned for a CREATE2. GasChangeCallContractCreation2 GasChangeReason = 9 // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. GasChangeCallCodeStorage GasChangeReason = 10 diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 1377479da..8af962499 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -162,12 +162,12 @@ func TestTransactionZAttack(t *testing.T) { var ivpendingNum int pendingtxs, _ := pool.Content() for account, txs := range pendingtxs { - cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account).ToBig()) + curBalance := new(big.Int).Set(pool.currentState.GetBalance(account).ToBig()) for _, tx := range txs { - if cur_balance.Cmp(tx.Value()) <= 0 { + if curBalance.Cmp(tx.Value()) <= 0 { ivpendingNum++ } else { - cur_balance.Sub(cur_balance, tx.Value()) + curBalance.Sub(curBalance, tx.Value()) } } } diff --git a/core/types/deposit.go b/core/types/deposit.go index 3bba2c7aa..8015f29ca 100644 --- a/core/types/deposit.go +++ b/core/types/deposit.go @@ -24,7 +24,7 @@ const ( depositRequestSize = 192 ) -// UnpackIntoDeposit unpacks a serialized DepositEvent. +// DepositLogToRequest unpacks a serialized DepositEvent. func DepositLogToRequest(data []byte) ([]byte, error) { if len(data) != 576 { return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data)) diff --git a/core/vm/eof_validation.go b/core/vm/eof_validation.go index fa534edce..514f9fb58 100644 --- a/core/vm/eof_validation.go +++ b/core/vm/eof_validation.go @@ -109,8 +109,8 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable, return nil, err } case RJUMPV: - max_size := int(code[i+1]) - length := max_size + 1 + maxSize := int(code[i+1]) + length := maxSize + 1 if len(code) <= i+length { return nil, fmt.Errorf("%w: jump table truncated, op %s, pos %d", errTruncatedImmediate, op, i) } @@ -120,7 +120,7 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable, return nil, err } } - i += 2 * max_size + i += 2 * maxSize case CALLF: arg, _ := parseUint16(code[i+1:]) if arg >= len(container.types) { diff --git a/core/vm/program/program.go b/core/vm/program/program.go index acc7fd25f..3b00bbae6 100644 --- a/core/vm/program/program.go +++ b/core/vm/program/program.go @@ -19,6 +19,7 @@ // - There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning // - There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV. // - There are no stability-guarantees. The utility will `panic` if the inputs do not align / make sense. + package program import ( @@ -204,7 +205,7 @@ func (p *Program) StaticCall(gas *uint256.Int, address, inOffset, inSize, outOff return p.Op(vm.STATICCALL) } -// StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will +// CallCode is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will // be used to provide all gas. func (p *Program) CallCode(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { if outOffset == outSize && inSize == outSize && inOffset == outSize { @@ -263,7 +264,7 @@ func (p *Program) InputAddressToStack(inputOffset uint32) *Program { return p.Op(vm.AND) } -// MStore stores the provided data (into the memory area starting at memStart). +// Mstore stores the provided data (into the memory area starting at memStart). func (p *Program) Mstore(data []byte, memStart uint32) *Program { var idx = 0 // We need to store it in chunks of 32 bytes diff --git a/crypto/blake2b/blake2b.go b/crypto/blake2b/blake2b.go index 7ecaab813..c24a88b99 100644 --- a/crypto/blake2b/blake2b.go +++ b/crypto/blake2b/blake2b.go @@ -23,13 +23,13 @@ import ( ) const ( - // The blocksize of BLAKE2b in bytes. + // BlockSize the blocksize of BLAKE2b in bytes. BlockSize = 128 - // The hash size of BLAKE2b-512 in bytes. + // Size the hash size of BLAKE2b-512 in bytes. Size = 64 - // The hash size of BLAKE2b-384 in bytes. + // Size384 the hash size of BLAKE2b-384 in bytes. Size384 = 48 - // The hash size of BLAKE2b-256 in bytes. + // Size256 the hash size of BLAKE2b-256 in bytes. Size256 = 32 ) diff --git a/crypto/bn256/gnark/pairing.go b/crypto/bn256/gnark/pairing.go index 39e8a657f..439ce0a39 100644 --- a/crypto/bn256/gnark/pairing.go +++ b/crypto/bn256/gnark/pairing.go @@ -4,7 +4,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" ) -// Computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// PairingCheck computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 // // To explain why gnark returns a (bool, error): // diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 1b6c9e97c..76f934c72 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -60,12 +60,12 @@ type PublicKey struct { Params *ECIESParams } -// Export an ECIES public key as an ECDSA public key. +// ExportECDSA exports an ECIES public key as an ECDSA public key. func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} } -// Import an ECDSA public key as an ECIES public key. +// ImportECDSAPublic imports an ECDSA public key as an ECIES public key. func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { return &PublicKey{ X: pub.X, @@ -81,20 +81,20 @@ type PrivateKey struct { D *big.Int } -// Export an ECIES private key as an ECDSA private key. +// ExportECDSA exports an ECIES private key as an ECDSA private key. func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { pub := &prv.PublicKey pubECDSA := pub.ExportECDSA() return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} } -// Import an ECDSA private key as an ECIES private key. +// ImportECDSA imports an ECDSA private key as an ECIES private key. func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { pub := ImportECDSAPublic(&prv.PublicKey) return &PrivateKey{*pub, prv.D} } -// Generate an elliptic curve public / private keypair. If params is nil, +// GenerateKey generates an elliptic curve public / private keypair. If params is nil, // the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { sk, err := ecdsa.GenerateKey(curve, rand) @@ -119,7 +119,7 @@ func MaxSharedKeyLength(pub *PublicKey) int { return (pub.Curve.Params().BitSize + 7) / 8 } -// ECDH key agreement method used to establish secret keys for encryption. +// GenerateShared ECDH key agreement method used to establish secret keys for encryption. func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { if prv.PublicKey.Curve != pub.Curve { return nil, ErrInvalidCurve diff --git a/eth/tracers/dir.go b/eth/tracers/dir.go index 55bcb44d2..1cdfab545 100644 --- a/eth/tracers/dir.go +++ b/eth/tracers/dir.go @@ -34,7 +34,7 @@ type Context struct { TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) } -// The set of methods that must be exposed by a tracer +// Tracer represents the set of methods that must be exposed by a tracer // for it to be available through the RPC interface. // This involves a method to retrieve results and one to // stop tracing. diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go index 347af43d5..cff629556 100644 --- a/eth/tracers/internal/util.go +++ b/eth/tracers/internal/util.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . + package internal import ( diff --git a/internal/era/builder.go b/internal/era/builder.go index 75782a08c..33261555b 100644 --- a/internal/era/builder.go +++ b/internal/era/builder.go @@ -12,7 +12,8 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// along with go-ethereum. If not, see . + package era import ( diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index f6e21d2ef..0dfeae8e1 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -67,7 +67,19 @@ type evalReq struct { done chan bool } -// runtime must be stopped with Stop() after use and cannot be used after stopping +// New creates and initializes a new JavaScript runtime environment (JSRE). +// The runtime is configured with the provided assetPath for loading scripts and +// an output writer for logging or printing results. +// +// The returned JSRE must be stopped by calling Stop() after use to release resources. +// Attempting to use the JSRE after stopping it will result in undefined behavior. +// +// Parameters: +// - assetPath: The path to the directory containing script assets. +// - output: The writer used for logging or printing runtime output. +// +// Returns: +// - A pointer to the newly created JSRE instance. func New(assetPath string, output io.Writer) *JSRE { re := &JSRE{ assetPath: assetPath, @@ -251,8 +263,15 @@ func (re *JSRE) Stop(waitForCallbacks bool) { } } -// Exec(file) loads and runs the contents of a file -// if a relative path is given, the jsre's assetPath is used +// Exec loads and executes the contents of a JavaScript file. +// If a relative path is provided, the file is resolved relative to the JSRE's assetPath. +// The file is read, compiled, and executed in the JSRE's runtime environment. +// +// Parameters: +// - file: The path to the JavaScript file to execute. Can be an absolute path or relative to assetPath. +// +// Returns: +// - error: An error if the file cannot be read, compiled, or executed. func (re *JSRE) Exec(file string) error { code, err := os.ReadFile(common.AbsolutePath(re.assetPath, file)) if err != nil { diff --git a/internal/reexec/reexec.go b/internal/reexec/reexec.go index af8d34798..7dc6d9222 100644 --- a/internal/reexec/reexec.go +++ b/internal/reexec/reexec.go @@ -7,6 +7,7 @@ // we require because of the forking limitations of using Go. Handlers can be // registered with a name and the argv 0 of the exec of the binary will be used // to find and execute custom init paths. + package reexec import ( diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 5213979aa..85cabca6b 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -1,5 +1,6 @@ // Hook go-metrics into expvar // on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler + package exp import ( diff --git a/metrics/gauge_info.go b/metrics/gauge_info.go index 2f7845564..1862ed55c 100644 --- a/metrics/gauge_info.go +++ b/metrics/gauge_info.go @@ -39,7 +39,7 @@ func NewRegisteredGaugeInfo(name string, r Registry) *GaugeInfo { return c } -// gaugeInfoSnapshot is a read-only copy of another GaugeInfo. +// GaugeInfoSnapshot is a read-only copy of another GaugeInfo. type GaugeInfoSnapshot GaugeInfoValue // Value returns the value at the time the snapshot was taken. diff --git a/metrics/log.go b/metrics/log.go index 3380bbf9c..08f3effb8 100644 --- a/metrics/log.go +++ b/metrics/log.go @@ -12,7 +12,7 @@ func Log(r Registry, freq time.Duration, l Logger) { LogScaled(r, freq, time.Nanosecond, l) } -// Output each metric in the given registry periodically using the given +// LogScaled outputs each metric in the given registry periodically using the given // logger. Print timings in `scale` units (eg time.Millisecond) rather than nanos. func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { du := float64(scale) diff --git a/metrics/metrics.go b/metrics/metrics.go index a9d662317..c4c43b757 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -3,6 +3,7 @@ // // // Coda Hale's original work: + package metrics import ( diff --git a/metrics/resetting_timer.go b/metrics/resetting_timer.go index 1b3e87bc3..66458bdb9 100644 --- a/metrics/resetting_timer.go +++ b/metrics/resetting_timer.go @@ -53,14 +53,14 @@ func (t *ResettingTimer) Snapshot() *ResettingTimerSnapshot { return snapshot } -// Record the duration of the execution of the given function. +// Time records the duration of the execution of the given function. func (t *ResettingTimer) Time(f func()) { ts := time.Now() f() t.Update(time.Since(ts)) } -// Record the duration of an event. +// Update records the duration of an event. func (t *ResettingTimer) Update(d time.Duration) { if !metricsEnabled { return @@ -71,7 +71,7 @@ func (t *ResettingTimer) Update(d time.Duration) { t.sum += int64(d) } -// Record the duration of an event that started at a time and ends now. +// UpdateSince records the duration of an event that started at a time and ends now. func (t *ResettingTimer) UpdateSince(ts time.Time) { t.Update(time.Since(ts)) } diff --git a/metrics/syslog.go b/metrics/syslog.go index 0bc4ed0da..b265328f8 100644 --- a/metrics/syslog.go +++ b/metrics/syslog.go @@ -9,7 +9,7 @@ import ( "time" ) -// Output each metric in the given registry to syslog periodically using +// Syslog outputs each metric in the given registry to syslog periodically using // the given syslogger. func Syslog(r Registry, d time.Duration, w *syslog.Writer) { for range time.Tick(d) { diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index c66a0da9d..df97e40e8 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -249,20 +249,20 @@ func TestHandshake_BadHandshakeAttack(t *testing.T) { net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) // A -> B FINDNODE - incorrect_challenge := &Whoareyou{ + incorrectChallenge := &Whoareyou{ IDNonce: [16]byte{5, 6, 7, 8, 9, 6, 11, 12}, RecordSeq: challenge.RecordSeq, Node: challenge.Node, sent: challenge.sent, } - incorrect_findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, incorrect_challenge, &Findnode{}) - incorrect_findnode2 := make([]byte, len(incorrect_findnode)) - copy(incorrect_findnode2, incorrect_findnode) + incorrectFindNode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, incorrectChallenge, &Findnode{}) + incorrectFindNode2 := make([]byte, len(incorrectFindNode)) + copy(incorrectFindNode2, incorrectFindNode) - net.nodeB.expectDecodeErr(t, errInvalidNonceSig, incorrect_findnode) + net.nodeB.expectDecodeErr(t, errInvalidNonceSig, incorrectFindNode) // Reject new findnode as previous handshake is now deleted. - net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, incorrect_findnode2) + net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, incorrectFindNode2) // The findnode packet is again rejected even with a valid challenge this time. findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) diff --git a/signer/core/api.go b/signer/core/api.go index def2d6041..12acf925f 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -664,7 +664,7 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common return &gnosisTx, nil } -// Returns the external api version. This method does not require user acceptance. Available methods are +// Version returns the external api version. This method does not require user acceptance. Available methods are // available via enumeration anyway, and this info does not contain user-specific data func (api *SignerAPI) Version(ctx context.Context) (string, error) { return ExternalAPIVersion, nil diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index 43edfe7d9..2f511c7e1 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -48,7 +48,7 @@ func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI { return &UIServerAPI{extapi, extapi.am} } -// List available accounts. As opposed to the external API definition, this method delivers +// ListAccounts lists available accounts. As opposed to the external API definition, this method delivers // the full Account object and not only Address. // Example call // {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} From 50eea14366e8876c265a7a14b08b0dfda71775b1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 14 Jan 2025 14:42:18 +0100 Subject: [PATCH 076/354] core/types: change SetCodeTx.ChainID to uint256 (#30982) We still need to decide how to handle non-specfic `chainId` in the JSON encoding of authorizations. With `chainId` being a uint64, the previous implementation just used value zero. However, it might actually be more correct to use the value `null` for this case. --- core/blockchain_test.go | 5 ++--- core/state_transition.go | 4 ++-- core/types/gen_authorization.go | 8 ++++---- core/types/transaction_marshalling.go | 16 +++++++++++----- core/types/transaction_signing.go | 2 +- core/types/tx_blob.go | 6 +++--- core/types/tx_dynamic_fee.go | 6 +++--- core/types/tx_setcode.go | 16 ++++++++-------- internal/ethapi/transaction_args.go | 2 +- tests/gen_stauthorization.go | 11 ++++++----- tests/state_test_util.go | 6 +++--- 11 files changed, 44 insertions(+), 38 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ec2f705a1..98fc6e99d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4269,12 +4269,11 @@ func TestEIP7702(t *testing.T) { // 2. addr1:0xaaaa calls into addr2:0xbbbb // 3. addr2:0xbbbb writes to storage auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{ - ChainID: gspec.Config.ChainID.Uint64(), + ChainID: *uint256.MustFromBig(gspec.Config.ChainID), Address: aa, Nonce: 1, }) auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{ - ChainID: 0, Address: bb, Nonce: 0, }) @@ -4282,7 +4281,7 @@ func TestEIP7702(t *testing.T) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(aa) txdata := &types.SetCodeTx{ - ChainID: gspec.Config.ChainID.Uint64(), + ChainID: uint256.MustFromBig(gspec.Config.ChainID), Nonce: 0, To: addr1, Gas: 500000, diff --git a/core/state_transition.go b/core/state_transition.go index 182e0ecd9..46606f770 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -569,8 +569,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // validateAuthorization validates an EIP-7702 authorization against the state. func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) { - // Verify chain ID is 0 or equal to current chain ID. - if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { + // Verify chain ID is null or equal to current chain ID. + if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 { return authority, ErrAuthorizationWrongChainID } // Limit nonce to 2^64-1 per EIP-2681. diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index be5467c50..57069cbb1 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -16,7 +16,7 @@ var _ = (*authorizationMarshaling)(nil) // MarshalJSON marshals as JSON. func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { type SetCodeAuthorization struct { - ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` + ChainID hexutil.U256 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` V hexutil.Uint64 `json:"yParity" gencodec:"required"` @@ -24,7 +24,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { S hexutil.U256 `json:"s" gencodec:"required"` } var enc SetCodeAuthorization - enc.ChainID = hexutil.Uint64(s.ChainID) + enc.ChainID = hexutil.U256(s.ChainID) enc.Address = s.Address enc.Nonce = hexutil.Uint64(s.Nonce) enc.V = hexutil.Uint64(s.V) @@ -36,7 +36,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { type SetCodeAuthorization struct { - ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` + ChainID *hexutil.U256 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` V *hexutil.Uint64 `json:"yParity" gencodec:"required"` @@ -50,7 +50,7 @@ func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' for SetCodeAuthorization") } - s.ChainID = uint64(*dec.ChainID) + s.ChainID = uint256.Int(*dec.ChainID) if dec.Address == nil { return errors.New("missing required field 'address' for SetCodeAuthorization") } diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 993d633c6..1bbb97a3e 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -155,7 +155,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.Proofs = itx.Sidecar.Proofs } case *SetCodeTx: - enc.ChainID = (*hexutil.Big)(new(big.Int).SetUint64(itx.ChainID)) + enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) @@ -353,7 +353,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } - itx.ChainID = uint256.MustFromBig((*big.Int)(dec.ChainID)) + var overflow bool + itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) + if overflow { + return errors.New("'chainId' value overflows uint256") + } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } @@ -395,7 +399,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { itx.BlobHashes = dec.BlobVersionedHashes // signature R - var overflow bool if dec.R == nil { return errors.New("missing required field 'r' in transaction") } @@ -432,7 +435,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } - itx.ChainID = dec.ChainID.ToInt().Uint64() + var overflow bool + itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) + if overflow { + return errors.New("'chainId' value overflows uint256") + } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } @@ -470,7 +477,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { itx.AuthList = dec.AuthorizationList // signature R - var overflow bool if dec.R == nil { return errors.New("missing required field 'r' in transaction") } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index d72643b4a..4d70f37bd 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -219,7 +219,7 @@ func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big } // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID != 0 && new(big.Int).SetUint64(txdata.ChainID).Cmp(s.chainId) != 0 { + if txdata.ChainID != nil && txdata.ChainID.CmpBig(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index ce1f287ca..88251ab95 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -47,9 +47,9 @@ type BlobTx struct { Sidecar *BlobTxSidecar `rlp:"-"` // Signature values - V *uint256.Int `json:"v" gencodec:"required"` - R *uint256.Int `json:"r" gencodec:"required"` - S *uint256.Int `json:"s" gencodec:"required"` + V *uint256.Int + R *uint256.Int + S *uint256.Int } // BlobTxSidecar contains the blobs of a blob transaction. diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 8b5b514fd..981755cf7 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -37,9 +37,9 @@ type DynamicFeeTx struct { AccessList AccessList // Signature values - V *big.Int `json:"v" gencodec:"required"` - R *big.Int `json:"r" gencodec:"required"` - S *big.Int `json:"s" gencodec:"required"` + V *big.Int + R *big.Int + S *big.Int } // copy creates a deep copy of the transaction data and initializes all fields. diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index f14ae3bc9..0fb5362c2 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -49,7 +49,7 @@ func AddressToDelegation(addr common.Address) []byte { // SetCodeTx implements the EIP-7702 transaction type which temporarily installs // the code at the signer's address. type SetCodeTx struct { - ChainID uint64 + ChainID *uint256.Int Nonce uint64 GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas @@ -61,16 +61,16 @@ type SetCodeTx struct { AuthList []SetCodeAuthorization // Signature values - V *uint256.Int `json:"v" gencodec:"required"` - R *uint256.Int `json:"r" gencodec:"required"` - S *uint256.Int `json:"s" gencodec:"required"` + V *uint256.Int + R *uint256.Int + S *uint256.Int } //go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go // SetCodeAuthorization is an authorization from an account to deploy code at its address. type SetCodeAuthorization struct { - ChainID uint64 `json:"chainId" gencodec:"required"` + ChainID uint256.Int `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` V uint8 `json:"yParity" gencodec:"required"` @@ -80,7 +80,7 @@ type SetCodeAuthorization struct { // field type overrides for gencodec type authorizationMarshaling struct { - ChainID hexutil.Uint64 + ChainID hexutil.U256 Nonce hexutil.Uint64 V hexutil.Uint64 R hexutil.U256 @@ -180,7 +180,7 @@ func (tx *SetCodeTx) copy() TxData { // accessors for innerTx. func (tx *SetCodeTx) txType() byte { return SetCodeTxType } -func (tx *SetCodeTx) chainID() *big.Int { return big.NewInt(int64(tx.ChainID)) } +func (tx *SetCodeTx) chainID() *big.Int { return tx.ChainID.ToBig() } func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList } func (tx *SetCodeTx) data() []byte { return tx.Data } func (tx *SetCodeTx) gas() uint64 { return tx.Gas } @@ -207,7 +207,7 @@ func (tx *SetCodeTx) rawSignatureValues() (v, r, s *big.Int) { } func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) { - tx.ChainID = chainID.Uint64() + tx.ChainID = uint256.MustFromBig(chainID) tx.V.SetFromBig(v) tx.R.SetFromBig(r) tx.S.SetFromBig(s) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 8902cab9d..5ce792bf8 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -531,7 +531,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { } data = &types.SetCodeTx{ To: *args.To, - ChainID: args.ChainID.ToInt().Uint64(), + ChainID: uint256.MustFromBig(args.ChainID.ToInt()), Nonce: uint64(*args.Nonce), Gas: uint64(*args.Gas), GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), diff --git a/tests/gen_stauthorization.go b/tests/gen_stauthorization.go index fbafd6fde..4f2c50bd9 100644 --- a/tests/gen_stauthorization.go +++ b/tests/gen_stauthorization.go @@ -16,7 +16,7 @@ var _ = (*stAuthorizationMarshaling)(nil) // MarshalJSON marshals as JSON. func (s stAuthorization) MarshalJSON() ([]byte, error) { type stAuthorization struct { - ChainID math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V math.HexOrDecimal64 `json:"v" gencodec:"required"` @@ -24,7 +24,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { S *math.HexOrDecimal256 `json:"s" gencodec:"required"` } var enc stAuthorization - enc.ChainID = math.HexOrDecimal64(s.ChainID) + enc.ChainID = (*math.HexOrDecimal256)(s.ChainID) enc.Address = s.Address enc.Nonce = math.HexOrDecimal64(s.Nonce) enc.V = math.HexOrDecimal64(s.V) @@ -36,7 +36,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (s *stAuthorization) UnmarshalJSON(input []byte) error { type stAuthorization struct { - ChainID *math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V *math.HexOrDecimal64 `json:"v" gencodec:"required"` @@ -47,9 +47,10 @@ func (s *stAuthorization) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - if dec.ChainID != nil { - s.ChainID = uint64(*dec.ChainID) + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' for stAuthorization") } + s.ChainID = (*big.Int)(dec.ChainID) if dec.Address == nil { return errors.New("missing required field 'address' for stAuthorization") } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 6e66bbaa7..740ebd4af 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -140,7 +140,7 @@ type stTransactionMarshaling struct { // Authorization is an authorization from an account to deploy code at it's address. type stAuthorization struct { - ChainID uint64 + ChainID *big.Int `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` V uint8 `json:"v" gencodec:"required"` @@ -150,7 +150,7 @@ type stAuthorization struct { // field type overrides for gencodec type stAuthorizationMarshaling struct { - ChainID math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 Nonce math.HexOrDecimal64 V math.HexOrDecimal64 R *math.HexOrDecimal256 @@ -446,7 +446,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList)) for i, auth := range tx.AuthorizationList { authList[i] = types.SetCodeAuthorization{ - ChainID: auth.ChainID, + ChainID: *uint256.MustFromBig(auth.ChainID), Address: auth.Address, Nonce: auth.Nonce, V: auth.V, From 414bf0c33f43b86e7b54287b83b6b528a16b4817 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 14 Jan 2025 23:26:24 +0800 Subject: [PATCH 077/354] eth/gasprice: ensure cache purging goroutine terminates with subscription (#31025) --- eth/gasprice/gasprice.go | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 69b346914..8e2585812 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -127,16 +127,23 @@ func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracl cache := lru.NewCache[cacheKey, processedFees](2048) headEvent := make(chan core.ChainHeadEvent, 1) - backend.SubscribeChainHeadEvent(headEvent) - go func() { - var lastHead common.Hash - for ev := range headEvent { - if ev.Header.ParentHash != lastHead { - cache.Purge() + sub := backend.SubscribeChainHeadEvent(headEvent) + if sub != nil { // the gasprice testBackend doesn't support subscribing to head events + go func() { + var lastHead common.Hash + for { + select { + case ev := <-headEvent: + if ev.Header.ParentHash != lastHead { + cache.Purge() + } + lastHead = ev.Header.Hash() + case <-sub.Err(): + return + } } - lastHead = ev.Header.Hash() - } - }() + }() + } return &Oracle{ backend: backend, From 68a224ee9a60e44892cb26fe125ab69cb9727ac9 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Wed, 15 Jan 2025 19:45:20 +0100 Subject: [PATCH 078/354] beacon/engine: check for empty requests (#31010) According to https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_newpayloadv4: > Elements of the list MUST be ordered by request_type in ascending order. Elements with empty request_data MUST be excluded from the list. --------- Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- eth/catalyst/api.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index fa9752734..781b6c73f 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -638,6 +638,9 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads")) } requests := convertRequests(executionRequests) + if err := validateRequests(requests); err != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err) + } return api.newPayload(params, versionedHashes, beaconRoot, requests, false) } @@ -727,6 +730,9 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV4 must only be called for prague payloads")) } requests := convertRequests(executionRequests) + if err := validateRequests(requests); err != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err) + } return api.newPayload(params, versionedHashes, beaconRoot, requests, true) } @@ -1287,3 +1293,20 @@ func convertRequests(hex []hexutil.Bytes) [][]byte { } return req } + +// validateRequests checks that requests are ordered by their type and are not empty. +func validateRequests(requests [][]byte) error { + var last byte + for _, req := range requests { + // No empty requests. + if len(req) < 2 { + return fmt.Errorf("empty request: %v", req) + } + // Check that requests are ordered by their type. + if req[0] < last { + return fmt.Errorf("invalid request order: %v", req) + } + last = req[0] + } + return nil +} From 5502ae8bc5c4fcaa0406056d00e3afc3e4035d29 Mon Sep 17 00:00:00 2001 From: georgehao Date: Thu, 16 Jan 2025 21:36:45 +0800 Subject: [PATCH 079/354] core: use sync.Once for SenderCacher initialization (#31029) This changes the SenderCacher so its goroutines will only be started on first use. Avoids starting them when package core is just imported but core.BlockChain isn't used. --- core/blockchain.go | 2 +- core/sender_cacher.go | 13 +++++++++++-- core/txpool/legacypool/legacypool.go | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 9cdedfe0c..5e9f6937c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1728,7 +1728,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness } // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) - SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) + SenderCacher().RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) var ( stats = insertStats{startTime: mclock.Now()} diff --git a/core/sender_cacher.go b/core/sender_cacher.go index 4be53619e..73bd5c85f 100644 --- a/core/sender_cacher.go +++ b/core/sender_cacher.go @@ -18,12 +18,21 @@ package core import ( "runtime" + "sync" "github.com/ethereum/go-ethereum/core/types" ) -// SenderCacher is a concurrent transaction sender recoverer and cacher. -var SenderCacher = newTxSenderCacher(runtime.NumCPU()) +// senderCacherOnce is used to ensure that the SenderCacher is initialized only once. +var senderCacherOnce = sync.OnceValue(func() *txSenderCacher { + return newTxSenderCacher(runtime.NumCPU()) +}) + +// SenderCacher returns the singleton instance of SenderCacher, initializing it if called for the first time. +// This function is thread-safe and ensures that initialization happens only once. +func SenderCacher() *txSenderCacher { + return senderCacherOnce() +} // txSenderCacherRequest is a request for recovering transaction senders with a // specific signature scheme and caching it into the transactions themselves. diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index a12af0f08..e7d077849 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1569,7 +1569,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) { // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) - core.SenderCacher.Recover(pool.signer, reinject) + core.SenderCacher().Recover(pool.signer, reinject) pool.addTxsLocked(reinject, false) } From e1d063993b9032de2876d77bba336ac6f755b870 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 16 Jan 2025 21:40:15 +0800 Subject: [PATCH 080/354] core/txpool/legacypool: ensure pending nonces are reset by SubPool.Clear (#31020) closes https://github.com/ethereum/go-ethereum/issues/30842 --- core/txpool/legacypool/legacypool.go | 1 + ethclient/simulated/backend_test.go | 51 +++++++++++++- ethclient/simulated/rollback_test.go | 102 +++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 ethclient/simulated/rollback_test.go diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index e7d077849..ce9743208 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -2123,6 +2123,7 @@ func (pool *LegacyPool) Clear() { pool.priced = newPricedList(pool.all) pool.pending = make(map[common.Address]*list) pool.queue = make(map[common.Address]*list) + pool.pendingNonces = newNoncer(pool.currentState) if !pool.config.NoLocals && pool.config.Journal != "" { pool.journal = newTxJournal(pool.config.Journal) diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index 37f4dbbf7..8efe93e24 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -19,11 +19,15 @@ package simulated import ( "context" "crypto/ecdsa" + "crypto/sha256" "math/big" "math/rand" "testing" "time" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/holiman/uint256" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -34,8 +38,10 @@ import ( var _ bind.ContractBackend = (Client)(nil) var ( - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + testKey2, _ = crypto.HexToECDSA("7ee346e3f7efc685250053bfbafbfc880d58dc6145247053d4fb3cb0f66dfcb2") + testAddr2 = crypto.PubkeyToAddress(testKey2.PublicKey) ) func simTestBackend(testAddr common.Address) *Backend { @@ -46,6 +52,46 @@ func simTestBackend(testAddr common.Address) *Backend { ) } +func newBlobTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) { + client := sim.Client() + + testBlob := &kzg4844.Blob{0x00} + testBlobCommit, _ := kzg4844.BlobToCommitment(testBlob) + testBlobProof, _ := kzg4844.ComputeBlobProof(testBlob, testBlobCommit) + testBlobVHash := kzg4844.CalcBlobHashV1(sha256.New(), &testBlobCommit) + + head, _ := client.HeaderByNumber(context.Background(), nil) // Should be child's, good enough + gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)) + gasPriceU256, _ := uint256.FromBig(gasPrice) + gasTipCapU256, _ := uint256.FromBig(big.NewInt(params.GWei)) + + addr := crypto.PubkeyToAddress(key.PublicKey) + chainid, _ := client.ChainID(context.Background()) + nonce, err := client.PendingNonceAt(context.Background(), addr) + if err != nil { + return nil, err + } + + chainidU256, _ := uint256.FromBig(chainid) + tx := types.NewTx(&types.BlobTx{ + ChainID: chainidU256, + GasTipCap: gasTipCapU256, + GasFeeCap: gasPriceU256, + BlobFeeCap: uint256.NewInt(1), + Gas: 21000, + Nonce: nonce, + To: addr, + AccessList: nil, + BlobHashes: []common.Hash{testBlobVHash}, + Sidecar: &types.BlobTxSidecar{ + Blobs: []kzg4844.Blob{*testBlob}, + Commitments: []kzg4844.Commitment{testBlobCommit}, + Proofs: []kzg4844.Proof{testBlobProof}, + }, + }) + return types.SignTx(tx, types.LatestSignerForChainID(chainid), key) +} + func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) { client := sim.Client() @@ -66,6 +112,7 @@ func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) { Gas: 21000, To: &addr, }) + return types.SignTx(tx, types.LatestSignerForChainID(chainid), key) } diff --git a/ethclient/simulated/rollback_test.go b/ethclient/simulated/rollback_test.go new file mode 100644 index 000000000..8fc9f5bc8 --- /dev/null +++ b/ethclient/simulated/rollback_test.go @@ -0,0 +1,102 @@ +package simulated + +import ( + "context" + "crypto/ecdsa" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/core/types" +) + +// TestTransactionRollbackBehavior tests that calling Rollback on the simulated backend doesn't prevent subsequent +// addition of new transactions +func TestTransactionRollbackBehavior(t *testing.T) { + sim := NewBackend( + types.GenesisAlloc{ + testAddr: {Balance: big.NewInt(10000000000000000)}, + testAddr2: {Balance: big.NewInt(10000000000000000)}, + }, + ) + defer sim.Close() + client := sim.Client() + + btx0 := testSendSignedTx(t, testKey, sim, true) + tx0 := testSendSignedTx(t, testKey2, sim, false) + tx1 := testSendSignedTx(t, testKey2, sim, false) + + sim.Rollback() + + if pendingStateHasTx(client, btx0) || pendingStateHasTx(client, tx0) || pendingStateHasTx(client, tx1) { + t.Fatalf("all transactions were not rolled back") + } + + btx2 := testSendSignedTx(t, testKey, sim, true) + tx2 := testSendSignedTx(t, testKey2, sim, false) + tx3 := testSendSignedTx(t, testKey2, sim, false) + + sim.Commit() + + if !pendingStateHasTx(client, btx2) || !pendingStateHasTx(client, tx2) || !pendingStateHasTx(client, tx3) { + t.Fatalf("all post-rollback transactions were not included") + } +} + +// testSendSignedTx sends a signed transaction to the simulated backend. +// It does not commit the block. +func testSendSignedTx(t *testing.T, key *ecdsa.PrivateKey, sim *Backend, isBlobTx bool) *types.Transaction { + t.Helper() + client := sim.Client() + ctx := context.Background() + + var ( + err error + signedTx *types.Transaction + ) + if isBlobTx { + signedTx, err = newBlobTx(sim, key) + } else { + signedTx, err = newTx(sim, key) + } + if err != nil { + t.Fatalf("failed to create transaction: %v", err) + } + + if err = client.SendTransaction(ctx, signedTx); err != nil { + t.Fatalf("failed to send transaction: %v", err) + } + + return signedTx +} + +// pendingStateHasTx returns true if a given transaction was successfully included as of the latest pending state. +func pendingStateHasTx(client Client, tx *types.Transaction) bool { + ctx := context.Background() + + var ( + receipt *types.Receipt + err error + ) + + // Poll for receipt with timeout + deadline := time.Now().Add(2 * time.Second) + for time.Now().Before(deadline) { + receipt, err = client.TransactionReceipt(ctx, tx.Hash()) + if err == nil && receipt != nil { + break + } + time.Sleep(100 * time.Millisecond) + } + + if err != nil { + return false + } + if receipt == nil { + return false + } + if receipt.Status != types.ReceiptStatusSuccessful { + return false + } + return true +} From c07bc472a5bb2b27f830f1f55dfffb97faba8a37 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Thu, 16 Jan 2025 09:58:16 -0500 Subject: [PATCH 081/354] core/tracing: document `OnCodeChange` now being called from SelfDestruct (#31007) Co-authored-by: Sina M <1591639+s1na@users.noreply.github.com> --- core/tracing/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index e8aa3a9e2..270e0a30b 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -9,6 +9,14 @@ All notable changes to the tracing interface will be documented in this file. - `GasChangeReason` has been extended with the following reasons which will be enabled only post-Verkle. There shouldn't be any gas changes with those reasons prior to the fork. - `GasChangeWitnessContractCollisionCheck` flags the event of adding to the witness when checking for contract address collision. +## [v1.14.12] + +This release contains a change in behavior for `OnCodeChange` hook. + +### `OnCodeChange` change + +The `OnCodeChange` hook is now called when the code of a contract is removed due to a selfdestruct. Previously, no code change was emitted on such occasions. + ## [v1.14.4] This release contained only minor extensions to the tracing interface. From a0b81af3b1cae04a855e3ba6bb2be6b6e12d138a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 17 Jan 2025 09:59:02 +0800 Subject: [PATCH 082/354] all: implement state history v2 (#30107) This pull request delivers the new version of the state history, where the raw storage key is used instead of the hash. Before the cancun fork, it's supported by protocol to destruct a specific account and therefore, all the storage slot owned by it should be wiped in the same transition. Technically, storage wiping should be performed through storage iteration, and only the storage key hash will be available for traversal if the state snapshot is not available. Therefore, the storage key hash is chosen as the identifier in the old version state history. Fortunately, account self-destruction has been deprecated by the protocol since the Cancun fork, and there are no empty accounts eligible for deletion under EIP-158. Therefore, we can conclude that no storage wiping should occur after the Cancun fork. In this case, it makes no sense to keep using hash. Besides, another big reason for making this change is the current format state history is unusable if verkle is activated. Verkle tree has a different key derivation scheme (merkle uses keccak256), the preimage of key hash must be provided in order to make verkle rollback functional. This pull request is a prerequisite for landing verkle. Additionally, the raw storage key is more human-friendly for those who want to manually check the history, even though Solidity already performs some hashing to derive the storage location. --- This pull request doesn't bump the database version, as I believe the database should still be compatible if users degrade from the new geth version to old one, the only side effect is the persistent new version state history will be unusable. --------- Co-authored-by: Zsolt Felfoldi --- cmd/evm/internal/t8ntool/execution.go | 4 +- cmd/evm/runner.go | 2 +- cmd/geth/dbcmd.go | 3 +- core/blockchain.go | 2 +- core/blockchain_test.go | 2 +- core/chain_makers.go | 4 +- core/genesis.go | 4 +- core/state/state_object.go | 12 +++- core/state/state_test.go | 6 +- core/state/statedb.go | 25 ++++--- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_hooked_test.go | 2 +- core/state/statedb_test.go | 29 ++++---- core/state/stateupdate.go | 86 +++++++++++++++-------- core/state/sync_test.go | 2 +- core/state/trie_prefetcher_test.go | 2 +- core/txpool/blobpool/blobpool_test.go | 12 ++-- eth/api_debug_test.go | 6 +- eth/state_accessor.go | 2 +- tests/state_test_util.go | 4 +- triedb/pathdb/buffer.go | 2 +- triedb/pathdb/database_test.go | 79 +++++++++++++++------ triedb/pathdb/difflayer_test.go | 6 +- triedb/pathdb/disklayer.go | 2 +- triedb/pathdb/execute.go | 40 +++++++---- triedb/pathdb/history.go | 44 +++++++----- triedb/pathdb/history_inspect.go | 8 ++- triedb/pathdb/history_test.go | 13 ++-- triedb/pathdb/iterator_test.go | 98 +++++++++++++-------------- triedb/pathdb/journal.go | 3 +- triedb/pathdb/states.go | 21 ++++-- triedb/pathdb/states_test.go | 30 +++++++- triedb/states.go | 3 +- 33 files changed, 356 insertions(+), 204 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 90ef54095..357429470 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -388,7 +388,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // Commit block - root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) + root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber), chainConfig.IsCancun(vmContext.BlockNumber, vmContext.Time)) if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) } @@ -446,7 +446,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(0, false) + root, _ := statedb.Commit(0, false, false) statedb, _ = state.New(root, sdb) return statedb } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index c67d3657e..b2cf28353 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -336,7 +336,7 @@ func runCmd(ctx *cli.Context) error { output, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { - root, err := runtimeConfig.State.Commit(genesisConfig.Number, true) + root, err := runtimeConfig.State.Commit(genesisConfig.Number, true, false) if err != nil { fmt.Printf("Failed to commit changes %v\n", err) return err diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 762224605..cd41c57c7 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -829,8 +829,7 @@ func inspectAccount(db *triedb.Database, start uint64, end uint64, address commo func inspectStorage(db *triedb.Database, start uint64, end uint64, address common.Address, slot common.Hash, raw bool) error { // The hash of storage slot key is utilized in the history // rather than the raw slot key, make the conversion. - slotHash := crypto.Keccak256Hash(slot.Bytes()) - stats, err := db.StorageHistory(address, slotHash, start, end) + stats, err := db.StorageHistory(address, slot, start, end) if err != nil { return err } diff --git a/core/blockchain.go b/core/blockchain.go index 5e9f6937c..1b13a74b1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1526,7 +1526,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. log.Crit("Failed to write block into disk", "err", err) } // Commit all cached state changes into underlying memory database. - root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) + root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()), bc.chainConfig.IsCancun(block.Number(), block.Time())) if err != nil { return err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 98fc6e99d..ed117edff 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -181,7 +181,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.chainmu.MustLock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash(), block.NumberU64()-1))) rawdb.WriteBlock(blockchain.db, block) - statedb.Commit(block.NumberU64(), false) + statedb.Commit(block.NumberU64(), false, false) blockchain.chainmu.Unlock() } return nil diff --git a/core/chain_makers.go b/core/chain_makers.go index 26714845e..5298874a4 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -405,7 +405,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } // Write state changes to db - root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number)) + root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time)) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } @@ -510,7 +510,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine } // Write state changes to DB. - root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number)) + root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time)) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } diff --git a/core/genesis.go b/core/genesis.go index 672cc177c..0ce40faf4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -148,7 +148,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { statedb.SetState(addr, key, value) } } - return statedb.Commit(0, false) + return statedb.Commit(0, false, false) } // flushAlloc is very similar with hash, but the main difference is all the @@ -174,7 +174,7 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, e statedb.SetState(addr, key, value) } } - root, err := statedb.Commit(0, false) + root, err := statedb.Commit(0, false, false) if err != nil { return common.Hash{}, err } diff --git a/core/state/state_object.go b/core/state/state_object.go index 76a3aba92..a6979bd36 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -399,10 +399,16 @@ func (s *stateObject) commitStorage(op *accountUpdate) { op.storages = make(map[common.Hash][]byte) } op.storages[hash] = encode(val) - if op.storagesOrigin == nil { - op.storagesOrigin = make(map[common.Hash][]byte) + + if op.storagesOriginByKey == nil { + op.storagesOriginByKey = make(map[common.Hash][]byte) + } + if op.storagesOriginByHash == nil { + op.storagesOriginByHash = make(map[common.Hash][]byte) } - op.storagesOrigin[hash] = encode(s.originStorage[key]) + origin := encode(s.originStorage[key]) + op.storagesOriginByKey[key] = origin + op.storagesOriginByHash[hash] = origin // Overwrite the clean value of storage slots s.originStorage[key] = val diff --git a/core/state/state_test.go b/core/state/state_test.go index 6f54300c3..b443411f1 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -56,7 +56,7 @@ func TestDump(t *testing.T) { // write some of them to the trie s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) - root, _ := s.state.Commit(0, false) + root, _ := s.state.Commit(0, false, false) // check that DumpToCollector contains the state objects that are in trie s.state, _ = New(root, tdb) @@ -116,7 +116,7 @@ func TestIterativeDump(t *testing.T) { // write some of them to the trie s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) - root, _ := s.state.Commit(0, false) + root, _ := s.state.Commit(0, false, false) s.state, _ = New(root, tdb) b := &bytes.Buffer{} @@ -142,7 +142,7 @@ func TestNull(t *testing.T) { var value common.Hash s.state.SetState(address, common.Hash{}, value) - s.state.Commit(0, false) + s.state.Commit(0, false, false) if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { t.Errorf("expected empty current value, got %x", value) diff --git a/core/state/statedb.go b/core/state/statedb.go index d279ccfdf..0310ee697 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1051,7 +1051,7 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root // with their values be tracked as original value. // In case (d), **original** account along with its storages should be deleted, // with their values be tracked as original value. -func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trienode.NodeSet, error) { +func (s *StateDB) handleDestruction(noStorageWiping bool) (map[common.Hash]*accountDelete, []*trienode.NodeSet, error) { var ( nodes []*trienode.NodeSet buf = crypto.NewKeccakState() @@ -1080,6 +1080,9 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() { continue } + if noStorageWiping { + return nil, nil, fmt.Errorf("unexpected storage wiping, %x", addr) + } // Remove storage slots belonging to the account. storages, storagesOrigin, set, err := s.deleteStorage(addr, addrHash, prev.Root) if err != nil { @@ -1101,7 +1104,7 @@ func (s *StateDB) GetTrie() Trie { // commit gathers the state mutations accumulated along with the associated // trie changes, resetting all internal flags with the new state as the base. -func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { +func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool) (*stateUpdate, error) { // Short circuit in case any database failure occurred earlier. if s.dbErr != nil { return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) @@ -1155,7 +1158,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // the same block, account deletions must be processed first. This ensures // that the storage trie nodes deleted during destruction and recreated // during subsequent resurrection can be combined correctly. - deletes, delNodes, err := s.handleDestruction() + deletes, delNodes, err := s.handleDestruction(noStorageWiping) if err != nil { return nil, err } @@ -1252,13 +1255,14 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { origin := s.originalRoot s.originalRoot = root - return newStateUpdate(origin, root, deletes, updates, nodes), nil + + return newStateUpdate(noStorageWiping, origin, root, deletes, updates, nodes), nil } // commitAndFlush is a wrapper of commit which also commits the state mutations // to the configured data stores. -func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateUpdate, error) { - ret, err := s.commit(deleteEmptyObjects) +func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (*stateUpdate, error) { + ret, err := s.commit(deleteEmptyObjects, noStorageWiping) if err != nil { return nil, err } @@ -1310,8 +1314,13 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU // // The associated block number of the state transition is also provided // for more chain context. -func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { - ret, err := s.commitAndFlush(block, deleteEmptyObjects) +// +// noStorageWiping is a flag indicating whether storage wiping is permitted. +// Since self-destruction was deprecated with the Cancun fork and there are +// no empty accounts left that could be deleted by EIP-158, storage wiping +// should not occur. +func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, error) { + ret, err := s.commitAndFlush(block, deleteEmptyObjects, noStorageWiping) if err != nil { return common.Hash{}, err } diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 7cbfd9b9d..ed99cf687 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -228,7 +228,7 @@ func (test *stateTest) run() bool { } else { state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary } - ret, err := state.commitAndFlush(0, true) // call commit at the block boundary + ret, err := state.commitAndFlush(0, true, false) // call commit at the block boundary if err != nil { panic(err) } diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index 5f82ed06d..874a27599 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -71,7 +71,7 @@ func TestBurn(t *testing.T) { hooked.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified) hooked.Finalise(true) - s.Commit(0, false) + s.Commit(0, false, false) if have, want := burned, uint256.NewInt(600); !have.Eq(want) { t.Fatalf("burn-count wrong, have %v want %v", have, want) } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 37141e90b..67eb9cbdc 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -119,7 +119,7 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - transRoot, err := transState.Commit(0, false) + transRoot, err := transState.Commit(0, false, false) if err != nil { t.Fatalf("failed to commit transition state: %v", err) } @@ -127,7 +127,7 @@ func TestIntermediateLeaks(t *testing.T) { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } - finalRoot, err := finalState.Commit(0, false) + finalRoot, err := finalState.Commit(0, false, false) if err != nil { t.Fatalf("failed to commit final state: %v", err) } @@ -240,7 +240,7 @@ func TestCopyWithDirtyJournal(t *testing.T) { obj.data.Root = common.HexToHash("0xdeadbeef") orig.updateStateObject(obj) } - root, _ := orig.Commit(0, true) + root, _ := orig.Commit(0, true, false) orig, _ = New(root, db) // modify all in memory without finalizing @@ -293,7 +293,7 @@ func TestCopyObjectState(t *testing.T) { t.Fatalf("Error in test itself, the 'done' flag should not be set before Commit, have %v want %v", have, want) } } - orig.Commit(0, true) + orig.Commit(0, true, false) for _, op := range cpy.mutations { if have, want := op.applied, false; have != want { t.Fatalf("Error: original state affected copy, have %v want %v", have, want) @@ -696,7 +696,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { func TestTouchDelete(t *testing.T) { s := newStateEnv() s.state.getOrNewStateObject(common.Address{}) - root, _ := s.state.Commit(0, false) + root, _ := s.state.Commit(0, false, false) s.state, _ = New(root, s.state.db) snapshot := s.state.Snapshot() @@ -784,7 +784,7 @@ func TestCopyCommitCopy(t *testing.T) { t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, sval) } // Commit state, ensure states can be loaded from disk - root, _ := state.Commit(0, false) + root, _ := state.Commit(0, false, false) state, _ = New(root, tdb) if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) @@ -898,11 +898,11 @@ func TestCommitCopy(t *testing.T) { if val := state.GetCommittedState(addr, skey1); val != (common.Hash{}) { t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - root, _ := state.Commit(0, true) + root, _ := state.Commit(0, true, false) state, _ = New(root, db) state.SetState(addr, skey2, sval2) - state.Commit(1, true) + state.Commit(1, true, false) // Copy the committed state database, the copied one is not fully functional. copied := state.Copy() @@ -943,7 +943,7 @@ func TestDeleteCreateRevert(t *testing.T) { addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) - root, _ := state.Commit(0, false) + root, _ := state.Commit(0, false, false) state, _ = New(root, state.db) // Simulate self-destructing in one transaction, then create-reverting in another @@ -955,7 +955,7 @@ func TestDeleteCreateRevert(t *testing.T) { state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state - root, _ = state.Commit(0, true) + root, _ = state.Commit(0, true, false) state, _ = New(root, state.db) if state.getStateObject(addr) != nil { @@ -998,7 +998,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}) - root, _ = state.Commit(0, false) + root, _ = state.Commit(0, false, false) t.Logf("root: %x", root) // force-flush tdb.Commit(root, false) @@ -1022,7 +1022,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { } // Modify the state state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) - root, err := state.Commit(0, false) + root, err := state.Commit(0, false, false) if err == nil { t.Fatalf("expected error, got root :%x", root) } @@ -1213,7 +1213,7 @@ func TestFlushOrderDataLoss(t *testing.T) { state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) } } - root, err := state.Commit(0, false) + root, err := state.Commit(0, false, false) if err != nil { t.Fatalf("failed to commit state trie: %v", err) } @@ -1288,8 +1288,7 @@ func TestDeleteStorage(t *testing.T) { value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32()) state.SetState(addr, slot, value) } - root, _ := state.Commit(0, true) - + root, _ := state.Commit(0, true, false) // Init phase done, create two states, one with snap and one without fastState, _ := New(root, NewDatabase(tdb, snaps)) slowState, _ := New(root, NewDatabase(tdb, nil)) diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go index 45de660ca..75c4ca028 100644 --- a/core/state/stateupdate.go +++ b/core/state/stateupdate.go @@ -32,34 +32,56 @@ type contractCode struct { // accountDelete represents an operation for deleting an Ethereum account. type accountDelete struct { - address common.Address // address is the unique account identifier - origin []byte // origin is the original value of account data in slim-RLP encoding. - storages map[common.Hash][]byte // storages stores mutated slots, the value should be nil. - storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. + address common.Address // address is the unique account identifier + origin []byte // origin is the original value of account data in slim-RLP encoding. + + // storages stores mutated slots, the value should be nil. + storages map[common.Hash][]byte + + // storagesOrigin stores the original values of mutated slots in + // prefix-zero-trimmed RLP format. The map key refers to the **HASH** + // of the raw storage slot key. + storagesOrigin map[common.Hash][]byte } // accountUpdate represents an operation for updating an Ethereum account. type accountUpdate struct { - address common.Address // address is the unique account identifier - data []byte // data is the slim-RLP encoded account data. - origin []byte // origin is the original value of account data in slim-RLP encoding. - code *contractCode // code represents mutated contract code; nil means it's not modified. - storages map[common.Hash][]byte // storages stores mutated slots in prefix-zero-trimmed RLP format. - storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. + address common.Address // address is the unique account identifier + data []byte // data is the slim-RLP encoded account data. + origin []byte // origin is the original value of account data in slim-RLP encoding. + code *contractCode // code represents mutated contract code; nil means it's not modified. + storages map[common.Hash][]byte // storages stores mutated slots in prefix-zero-trimmed RLP format. + + // storagesOriginByKey and storagesOriginByHash both store the original values + // of mutated slots in prefix-zero-trimmed RLP format. The difference is that + // storagesOriginByKey uses the **raw** storage slot key as the map ID, while + // storagesOriginByHash uses the **hash** of the storage slot key instead. + storagesOriginByKey map[common.Hash][]byte + storagesOriginByHash map[common.Hash][]byte } // stateUpdate represents the difference between two states resulting from state // execution. It contains information about mutated contract codes, accounts, // and storage slots, along with their original values. type stateUpdate struct { - originRoot common.Hash // hash of the state before applying mutation - root common.Hash // hash of the state after applying mutation - accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding - accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding - storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format - storagesOrigin map[common.Address]map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in 'prefix-zero-trimmed' RLP format - codes map[common.Address]contractCode // codes contains the set of dirty codes - nodes *trienode.MergedNodeSet // Aggregated dirty nodes caused by state changes + originRoot common.Hash // hash of the state before applying mutation + root common.Hash // hash of the state after applying mutation + accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding + accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding + + // storages stores mutated slots in 'prefix-zero-trimmed' RLP format. + // The value is keyed by account hash and **storage slot key hash**. + storages map[common.Hash]map[common.Hash][]byte + + // storagesOrigin stores the original values of mutated slots in + // 'prefix-zero-trimmed' RLP format. + // (a) the value is keyed by account hash and **storage slot key** if rawStorageKey is true; + // (b) the value is keyed by account hash and **storage slot key hash** if rawStorageKey is false; + storagesOrigin map[common.Address]map[common.Hash][]byte + rawStorageKey bool + + codes map[common.Address]contractCode // codes contains the set of dirty codes + nodes *trienode.MergedNodeSet // Aggregated dirty nodes caused by state changes } // empty returns a flag indicating the state transition is empty or not. @@ -67,10 +89,13 @@ func (sc *stateUpdate) empty() bool { return sc.originRoot == sc.root } -// newStateUpdate constructs a state update object, representing the differences -// between two states by performing state execution. It aggregates the given -// account deletions and account updates to form a comprehensive state update. -func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate { +// newStateUpdate constructs a state update object by identifying the differences +// between two states through state execution. It combines the specified account +// deletions and account updates to create a complete state update. +// +// rawStorageKey is a flag indicating whether to use the raw storage slot key or +// the hash of the slot key for constructing state update object. +func newStateUpdate(rawStorageKey bool, originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate { var ( accounts = make(map[common.Hash][]byte) accountsOrigin = make(map[common.Address][]byte) @@ -78,13 +103,14 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common storagesOrigin = make(map[common.Address]map[common.Hash][]byte) codes = make(map[common.Address]contractCode) ) - // Due to the fact that some accounts could be destructed and resurrected - // within the same block, the deletions must be aggregated first. + // Since some accounts might be destroyed and recreated within the same + // block, deletions must be aggregated first. for addrHash, op := range deletes { addr := op.address accounts[addrHash] = nil accountsOrigin[addr] = op.origin + // If storage wiping exists, the hash of the storage slot key must be used if len(op.storages) > 0 { storages[addrHash] = op.storages } @@ -118,12 +144,16 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common } // Aggregate the storage original values. If the slot is already present // in aggregated storagesOrigin set, skip it. - if len(op.storagesOrigin) > 0 { + storageOriginSet := op.storagesOriginByHash + if rawStorageKey { + storageOriginSet = op.storagesOriginByKey + } + if len(storageOriginSet) > 0 { origin, exist := storagesOrigin[addr] if !exist { - storagesOrigin[addr] = op.storagesOrigin + storagesOrigin[addr] = storageOriginSet } else { - for key, slot := range op.storagesOrigin { + for key, slot := range storageOriginSet { if _, found := origin[key]; !found { origin[key] = slot } @@ -138,6 +168,7 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common accountsOrigin: accountsOrigin, storages: storages, storagesOrigin: storagesOrigin, + rawStorageKey: rawStorageKey, codes: codes, nodes: nodes, } @@ -153,5 +184,6 @@ func (sc *stateUpdate) stateSet() *triedb.StateSet { AccountsOrigin: sc.accountsOrigin, Storages: sc.storages, StoragesOrigin: sc.storagesOrigin, + RawStorageKey: sc.rawStorageKey, } } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index efa56f886..5c8b5a90f 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -79,7 +79,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c } accounts = append(accounts, acc) } - root, _ := state.Commit(0, false) + root, _ := state.Commit(0, false, false) // Return the generated state return db, sdb, nodeDb, root, accounts diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index d96727704..4d1b627c4 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -83,7 +83,7 @@ func TestVerklePrefetcher(t *testing.T) { state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie state.SetCode(addr, []byte("hello")) // Change an external metadata state.SetState(addr, skey, sval) // Change the storage trie - root, _ := state.Commit(0, true) + root, _ := state.Commit(0, true, false) state, _ = New(root, sdb) sRoot := state.GetStorageRoot(addr) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index e4441bec5..3d90ec441 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -650,7 +650,7 @@ func TestOpenDrops(t *testing.T) { statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true) + statedb.Commit(0, true, false) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -769,7 +769,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true) + statedb.Commit(0, true, false) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -871,7 +871,7 @@ func TestOpenHeap(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true) + statedb.Commit(0, true, false) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -951,7 +951,7 @@ func TestOpenCap(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true) + statedb.Commit(0, true, false) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -1393,7 +1393,7 @@ func TestAdd(t *testing.T) { store.Put(blob) } } - statedb.Commit(0, true) + statedb.Commit(0, true, false) store.Close() // Create a blob pool out of the pre-seeded dats @@ -1519,7 +1519,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) pool.add(tx) } - statedb.Commit(0, true) + statedb.Commit(0, true, false) defer pool.Close() // Benchmark assembling the pending diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index cfb8829b5..02b85f69f 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -82,7 +82,7 @@ func TestAccountRange(t *testing.T) { m[addr] = true } } - root, _ := sdb.Commit(0, true) + root, _ := sdb.Commit(0, true, false) sdb, _ = state.New(root, statedb) trie, err := statedb.OpenTrie(root) @@ -140,7 +140,7 @@ func TestEmptyAccountRange(t *testing.T) { st, _ = state.New(types.EmptyRootHash, statedb) ) // Commit(although nothing to flush) and re-init the statedb - st.Commit(0, true) + st.Commit(0, true, false) st, _ = state.New(types.EmptyRootHash, statedb) results := st.RawDump(&state.DumpConfig{ @@ -183,7 +183,7 @@ func TestStorageRangeAt(t *testing.T) { for _, entry := range storage { sdb.SetState(addr, *entry.Key, entry.Value) } - root, _ := sdb.Commit(0, false) + root, _ := sdb.Commit(0, false, false) sdb, _ = state.New(root, db) // Check a few combinations of limit and start/end. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 0749d7379..99ed28d96 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -152,7 +152,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } // Finalize the state so any modifications are written to the trie - root, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number())) + root, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number()), eth.blockchain.Config().IsCancun(current.Number(), current.Time())) if err != nil { return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 740ebd4af..e658b62eb 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -339,7 +339,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified) // Commit state mutations into database. - root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number())) + root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time())) if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { receipt := &types.Receipt{GasUsed: vmRet.UsedGas} tracer.OnTxEnd(receipt, nil) @@ -512,7 +512,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(0, false) + root, _ := statedb.Commit(0, false, false) // If snapshot is requested, initialize the snapshotter and use it in state. var snaps *snapshot.Tree diff --git a/triedb/pathdb/buffer.go b/triedb/pathdb/buffer.go index 68e136f19..dea8875bd 100644 --- a/triedb/pathdb/buffer.go +++ b/triedb/pathdb/buffer.go @@ -46,7 +46,7 @@ func newBuffer(limit int, nodes *nodeSet, states *stateSet, layers uint64) *buff nodes = newNodeSet(nil) } if states == nil { - states = newStates(nil, nil) + states = newStates(nil, nil, false) } return &buffer{ layers: layers, diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index a6b1d3c04..f4b3fcec2 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -91,29 +91,47 @@ func newCtx(stateRoot common.Hash) *genctx { } } +func (ctx *genctx) storageOriginSet(rawStorageKey bool, t *tester) map[common.Address]map[common.Hash][]byte { + if !rawStorageKey { + return ctx.storageOrigin + } + set := make(map[common.Address]map[common.Hash][]byte) + for addr, storage := range ctx.storageOrigin { + subset := make(map[common.Hash][]byte) + for hash, val := range storage { + key := t.hashPreimage(hash) + subset[key] = val + } + set[addr] = subset + } + return set +} + type tester struct { db *Database roots []common.Hash - preimages map[common.Hash]common.Address - accounts map[common.Hash][]byte - storages map[common.Hash]map[common.Hash][]byte + preimages map[common.Hash][]byte + + // current state set + accounts map[common.Hash][]byte + storages map[common.Hash]map[common.Hash][]byte // state snapshots snapAccounts map[common.Hash]map[common.Hash][]byte snapStorages map[common.Hash]map[common.Hash]map[common.Hash][]byte } -func newTester(t *testing.T, historyLimit uint64) *tester { +func newTester(t *testing.T, historyLimit uint64, isVerkle bool) *tester { var ( disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db = New(disk, &Config{ StateHistory: historyLimit, CleanCacheSize: 16 * 1024, WriteBufferSize: 16 * 1024, - }, false) + }, isVerkle) obj = &tester{ db: db, - preimages: make(map[common.Hash]common.Address), + preimages: make(map[common.Hash][]byte), accounts: make(map[common.Hash][]byte), storages: make(map[common.Hash]map[common.Hash][]byte), snapAccounts: make(map[common.Hash]map[common.Hash][]byte), @@ -125,7 +143,8 @@ func newTester(t *testing.T, historyLimit uint64) *tester { if len(obj.roots) != 0 { parent = obj.roots[len(obj.roots)-1] } - root, nodes, states := obj.generate(parent) + root, nodes, states := obj.generate(parent, i > 6) + if err := db.Update(root, parent, uint64(i), nodes, states); err != nil { panic(fmt.Errorf("failed to update state changes, err: %w", err)) } @@ -134,6 +153,14 @@ func newTester(t *testing.T, historyLimit uint64) *tester { return obj } +func (t *tester) accountPreimage(hash common.Hash) common.Address { + return common.BytesToAddress(t.preimages[hash]) +} + +func (t *tester) hashPreimage(hash common.Hash) common.Hash { + return common.BytesToHash(t.preimages[hash]) +} + func (t *tester) release() { t.db.Close() t.db.diskdb.Close() @@ -141,7 +168,7 @@ func (t *tester) release() { func (t *tester) randAccount() (common.Address, []byte) { for addrHash, account := range t.accounts { - return t.preimages[addrHash], account + return t.accountPreimage(addrHash), account } return common.Address{}, nil } @@ -154,7 +181,9 @@ func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash { ) for i := 0; i < 10; i++ { v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32))) - hash := testrand.Hash() + key := testrand.Bytes(32) + hash := crypto.Keccak256Hash(key) + t.preimages[hash] = key storage[hash] = v origin[hash] = nil @@ -183,7 +212,9 @@ func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Has } for i := 0; i < 3; i++ { v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(testrand.Bytes(32))) - hash := testrand.Hash() + key := testrand.Bytes(32) + hash := crypto.Keccak256Hash(key) + t.preimages[hash] = key storage[hash] = v origin[hash] = nil @@ -216,7 +247,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash return root } -func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *StateSetWithOrigin) { +func (t *tester) generate(parent common.Hash, rawStorageKey bool) (common.Hash, *trienode.MergedNodeSet, *StateSetWithOrigin) { var ( ctx = newCtx(parent) dirties = make(map[common.Hash]struct{}) @@ -232,9 +263,12 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode // account creation addr := testrand.Address() addrHash := crypto.Keccak256Hash(addr.Bytes()) + + // short circuit if the account was already existent if _, ok := t.accounts[addrHash]; ok { continue } + // short circuit if the account has been modified within the same transition if _, ok := dirties[addrHash]; ok { continue } @@ -243,7 +277,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode root := t.generateStorage(ctx, addr) ctx.accounts[addrHash] = types.SlimAccountRLP(generateAccount(root)) ctx.accountOrigin[addr] = nil - t.preimages[addrHash] = addr + t.preimages[addrHash] = addr.Bytes() case modifyAccountOp: // account mutation @@ -252,6 +286,8 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode continue } addrHash := crypto.Keccak256Hash(addr.Bytes()) + + // short circuit if the account has been modified within the same transition if _, ok := dirties[addrHash]; ok { continue } @@ -271,6 +307,8 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode continue } addrHash := crypto.Keccak256Hash(addr.Bytes()) + + // short circuit if the account has been modified within the same transition if _, ok := dirties[addrHash]; ok { continue } @@ -314,7 +352,8 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode delete(t.storages, addrHash) } } - return root, ctx.nodes, NewStateSetWithOrigin(ctx.accounts, ctx.storages, ctx.accountOrigin, ctx.storageOrigin) + storageOrigin := ctx.storageOriginSet(rawStorageKey, t) + return root, ctx.nodes, NewStateSetWithOrigin(ctx.accounts, ctx.storages, ctx.accountOrigin, storageOrigin, rawStorageKey) } // lastHash returns the latest root hash, or empty if nothing is cached. @@ -409,7 +448,7 @@ func TestDatabaseRollback(t *testing.T) { }() // Verify state histories - tester := newTester(t, 0) + tester := newTester(t, 0, false) defer tester.release() if err := tester.verifyHistory(); err != nil { @@ -443,7 +482,7 @@ func TestDatabaseRecoverable(t *testing.T) { }() var ( - tester = newTester(t, 0) + tester = newTester(t, 0, false) index = tester.bottomIndex() ) defer tester.release() @@ -487,7 +526,7 @@ func TestDisable(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0) + tester := newTester(t, 0, false) defer tester.release() stored := crypto.Keccak256Hash(rawdb.ReadAccountTrieNode(tester.db.diskdb, nil)) @@ -529,7 +568,7 @@ func TestCommit(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0) + tester := newTester(t, 0, false) defer tester.release() if err := tester.db.Commit(tester.lastHash(), false); err != nil { @@ -559,7 +598,7 @@ func TestJournal(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0) + tester := newTester(t, 0, false) defer tester.release() if err := tester.db.Journal(tester.lastHash()); err != nil { @@ -589,7 +628,7 @@ func TestCorruptedJournal(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0) + tester := newTester(t, 0, false) defer tester.release() if err := tester.db.Journal(tester.lastHash()); err != nil { @@ -637,7 +676,7 @@ func TestTailTruncateHistory(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 10) + tester := newTester(t, 10, false) defer tester.release() tester.db.Close() diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index 7176d9964..83ed83348 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -76,7 +76,7 @@ func benchmarkSearch(b *testing.B, depth int, total int) { nblob = common.CopyBytes(blob) } } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil, false)) } var layer layer layer = emptyLayer() @@ -118,7 +118,7 @@ func BenchmarkPersist(b *testing.B) { ) nodes[common.Hash{}][string(path)] = node } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil, false)) } for i := 0; i < b.N; i++ { b.StopTimer() @@ -156,7 +156,7 @@ func BenchmarkJournal(b *testing.B) { ) nodes[common.Hash{}][string(path)] = node } - return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil)) + return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil, false)) } var layer layer layer = emptyLayer() diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 003431b19..5e678dbde 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -316,7 +316,7 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) { // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. - nodes, err := apply(dl.db, h.meta.parent, h.meta.root, h.accounts, h.storages) + nodes, err := apply(dl.db, h.meta.parent, h.meta.root, h.meta.version != stateHistoryV0, h.accounts, h.storages) if err != nil { return nil, err } diff --git a/triedb/pathdb/execute.go b/triedb/pathdb/execute.go index e24d0710f..80cecb82e 100644 --- a/triedb/pathdb/execute.go +++ b/triedb/pathdb/execute.go @@ -30,11 +30,12 @@ import ( // context wraps all fields for executing state diffs. type context struct { - prevRoot common.Hash - postRoot common.Hash - accounts map[common.Address][]byte - storages map[common.Address]map[common.Hash][]byte - nodes *trienode.MergedNodeSet + prevRoot common.Hash + postRoot common.Hash + accounts map[common.Address][]byte + storages map[common.Address]map[common.Hash][]byte + nodes *trienode.MergedNodeSet + rawStorageKey bool // TODO (rjl493456442) abstract out the state hasher // for supporting verkle tree. @@ -43,18 +44,19 @@ type context struct { // apply processes the given state diffs, updates the corresponding post-state // and returns the trie nodes that have been modified. -func apply(db database.NodeDatabase, prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) (map[common.Hash]map[string]*trienode.Node, error) { +func apply(db database.NodeDatabase, prevRoot common.Hash, postRoot common.Hash, rawStorageKey bool, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) (map[common.Hash]map[string]*trienode.Node, error) { tr, err := trie.New(trie.TrieID(postRoot), db) if err != nil { return nil, err } ctx := &context{ - prevRoot: prevRoot, - postRoot: postRoot, - accounts: accounts, - storages: storages, - accountTrie: tr, - nodes: trienode.NewMergedNodeSet(), + prevRoot: prevRoot, + postRoot: postRoot, + accounts: accounts, + storages: storages, + accountTrie: tr, + rawStorageKey: rawStorageKey, + nodes: trienode.NewMergedNodeSet(), } for addr, account := range accounts { var err error @@ -109,11 +111,15 @@ func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) return err } for key, val := range ctx.storages[addr] { + tkey := key + if ctx.rawStorageKey { + tkey = h.hash(key.Bytes()) + } var err error if len(val) == 0 { - err = st.Delete(key.Bytes()) + err = st.Delete(tkey.Bytes()) } else { - err = st.Update(key.Bytes(), val) + err = st.Update(tkey.Bytes(), val) } if err != nil { return err @@ -166,7 +172,11 @@ func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address) if len(val) != 0 { return errors.New("expect storage deletion") } - if err := st.Delete(key.Bytes()); err != nil { + tkey := key + if ctx.rawStorageKey { + tkey = h.hash(key.Bytes()) + } + if err := st.Delete(tkey.Bytes()); err != nil { return err } } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index e1cd98115..9fb7d9e15 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -68,7 +68,8 @@ const ( slotIndexSize = common.HashLength + 5 // The length of encoded slot index historyMetaSize = 9 + 2*common.HashLength // The length of encoded history meta - stateHistoryVersion = uint8(0) // initial version of state history structure. + stateHistoryV0 = uint8(0) // initial version of state history structure + stateHistoryV1 = uint8(1) // use the storage slot raw key as the identifier instead of the key hash ) // Each state history entry is consisted of five elements: @@ -169,15 +170,18 @@ func (i *accountIndex) decode(blob []byte) { // slotIndex describes the metadata belonging to a storage slot. type slotIndex struct { - hash common.Hash // The hash of slot key - length uint8 // The length of storage slot, up to 32 bytes defined in protocol - offset uint32 // The offset of item in storage slot data table + // the identifier of the storage slot. Specifically + // in v0, it's the hash of the raw storage slot key (32 bytes); + // in v1, it's the raw storage slot key (32 bytes); + id common.Hash + length uint8 // The length of storage slot, up to 32 bytes defined in protocol + offset uint32 // The offset of item in storage slot data table } // encode packs slot index into byte stream. func (i *slotIndex) encode() []byte { var buf [slotIndexSize]byte - copy(buf[:common.HashLength], i.hash.Bytes()) + copy(buf[:common.HashLength], i.id.Bytes()) buf[common.HashLength] = i.length binary.BigEndian.PutUint32(buf[common.HashLength+1:], i.offset) return buf[:] @@ -185,7 +189,7 @@ func (i *slotIndex) encode() []byte { // decode unpack slot index from the byte stream. func (i *slotIndex) decode(blob []byte) { - i.hash = common.BytesToHash(blob[:common.HashLength]) + i.id = common.BytesToHash(blob[:common.HashLength]) i.length = blob[common.HashLength] i.offset = binary.BigEndian.Uint32(blob[common.HashLength+1:]) } @@ -214,7 +218,7 @@ func (m *meta) decode(blob []byte) error { return errors.New("no version tag") } switch blob[0] { - case stateHistoryVersion: + case stateHistoryV0, stateHistoryV1: if len(blob) != historyMetaSize { return fmt.Errorf("invalid state history meta, len: %d", len(blob)) } @@ -242,7 +246,7 @@ type history struct { } // newHistory constructs the state history object with provided state change set. -func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *history { +func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, rawStorageKey bool) *history { var ( accountList = maps.Keys(accounts) storageList = make(map[common.Address][]common.Hash) @@ -254,9 +258,13 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map slices.SortFunc(slist, common.Hash.Cmp) storageList[addr] = slist } + version := stateHistoryV0 + if rawStorageKey { + version = stateHistoryV1 + } return &history{ meta: &meta{ - version: stateHistoryVersion, + version: version, parent: parent, root: root, block: block, @@ -289,7 +297,7 @@ func (h *history) encode() ([]byte, []byte, []byte, []byte) { // Encode storage slots in order for _, slotHash := range h.storageList[addr] { sIndex := slotIndex{ - hash: slotHash, + id: slotHash, length: uint8(len(slots[slotHash])), offset: uint32(len(storageData)), } @@ -377,7 +385,7 @@ func (r *decoder) readAccount(pos int) (accountIndex, []byte, error) { // readStorage parses the storage slots from the byte stream with specified account. func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common.Hash][]byte, error) { var ( - last common.Hash + last *common.Hash count = int(accIndex.storageSlots) list = make([]common.Hash, 0, count) storage = make(map[common.Hash][]byte, count) @@ -402,8 +410,10 @@ func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common. } index.decode(r.storageIndexes[start:end]) - if bytes.Compare(last.Bytes(), index.hash.Bytes()) >= 0 { - return nil, nil, errors.New("storage slot is not in order") + if last != nil { + if bytes.Compare(last.Bytes(), index.id.Bytes()) >= 0 { + return nil, nil, fmt.Errorf("storage slot is not in order, last: %x, current: %x", *last, index.id) + } } if index.offset != r.lastSlotDataRead { return nil, nil, errors.New("storage data buffer is gapped") @@ -412,10 +422,10 @@ func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common. if uint32(len(r.storageData)) < sEnd { return nil, nil, errors.New("storage data buffer is corrupted") } - storage[index.hash] = r.storageData[r.lastSlotDataRead:sEnd] - list = append(list, index.hash) + storage[index.id] = r.storageData[r.lastSlotDataRead:sEnd] + list = append(list, index.id) - last = index.hash + last = &index.id r.lastSlotIndexRead = end r.lastSlotDataRead = sEnd } @@ -498,7 +508,7 @@ func writeHistory(writer ethdb.AncientWriter, dl *diffLayer) error { } var ( start = time.Now() - history = newHistory(dl.rootHash(), dl.parentLayer().rootHash(), dl.block, dl.states.accountOrigin, dl.states.storageOrigin) + history = newHistory(dl.rootHash(), dl.parentLayer().rootHash(), dl.block, dl.states.accountOrigin, dl.states.storageOrigin, dl.states.rawStorageKey) ) accountData, storageData, accountIndex, storageIndex := history.encode() dataSize := common.StorageSize(len(accountData) + len(storageData)) diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go index 240474da3..7dbe5959d 100644 --- a/triedb/pathdb/history_inspect.go +++ b/triedb/pathdb/history_inspect.go @@ -21,6 +21,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -109,12 +110,17 @@ func accountHistory(freezer ethdb.AncientReader, address common.Address, start, // storageHistory inspects the storage history within the range. func storageHistory(freezer ethdb.AncientReader, address common.Address, slot common.Hash, start uint64, end uint64) (*HistoryStats, error) { + slotHash := crypto.Keccak256Hash(slot.Bytes()) return inspectHistory(freezer, start, end, func(h *history, stats *HistoryStats) { slots, exists := h.storages[address] if !exists { return } - blob, exists := slots[slot] + key := slotHash + if h.meta.version != stateHistoryV0 { + key = slot + } + blob, exists := slots[key] if !exists { return } diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index d430706de..953f02353 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -49,9 +49,9 @@ func randomStateSet(n int) (map[common.Address][]byte, map[common.Address]map[co return accounts, storages } -func makeHistory() *history { +func makeHistory(rawStorageKey bool) *history { accounts, storages := randomStateSet(3) - return newHistory(testrand.Hash(), types.EmptyRootHash, 0, accounts, storages) + return newHistory(testrand.Hash(), types.EmptyRootHash, 0, accounts, storages, rawStorageKey) } func makeHistories(n int) []*history { @@ -62,7 +62,7 @@ func makeHistories(n int) []*history { for i := 0; i < n; i++ { root := testrand.Hash() accounts, storages := randomStateSet(3) - h := newHistory(root, parent, uint64(i), accounts, storages) + h := newHistory(root, parent, uint64(i), accounts, storages, false) parent = root result = append(result, h) } @@ -70,10 +70,15 @@ func makeHistories(n int) []*history { } func TestEncodeDecodeHistory(t *testing.T) { + testEncodeDecodeHistory(t, false) + testEncodeDecodeHistory(t, true) +} + +func testEncodeDecodeHistory(t *testing.T, rawStorageKey bool) { var ( m meta dec history - obj = makeHistory() + obj = makeHistory(rawStorageKey) ) // check if meta data can be correctly encode/decode blob := obj.meta.encode() diff --git a/triedb/pathdb/iterator_test.go b/triedb/pathdb/iterator_test.go index 48b5870b5..05a166d1b 100644 --- a/triedb/pathdb/iterator_test.go +++ b/triedb/pathdb/iterator_test.go @@ -131,7 +131,7 @@ func TestAccountIteratorBasics(t *testing.T) { storage[hash] = accStorage } } - states := newStates(accounts, storage) + states := newStates(accounts, storage, false) it := newDiffAccountIterator(common.Hash{}, states, nil) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator @@ -171,7 +171,7 @@ func TestStorageIteratorBasics(t *testing.T) { storage[hash] = accStorage nilStorage[hash] = nilstorage } - states := newStates(accounts, storage) + states := newStates(accounts, storage, false) for account := range accounts { it := newDiffStorageIterator(account, common.Hash{}, states, nil) verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator @@ -267,13 +267,13 @@ func TestAccountIteratorTraversal(t *testing.T) { // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil, false)) // Verify the single and multi-layer iterators head := db.tree.get(common.HexToHash("0x04")) @@ -314,13 +314,13 @@ func TestStorageIteratorTraversal(t *testing.T) { // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 0, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil), nil, nil, false)) // Verify the single and multi-layer iterators head := db.tree.get(common.HexToHash("0x04")) @@ -395,14 +395,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(a, nil, nil, nil)) - db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(b, nil, nil, nil)) - db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(c, nil, nil, nil)) - db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(d, nil, nil, nil)) - db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(e, nil, nil, nil)) - db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(f, nil, nil, nil)) - db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(g, nil, nil, nil)) - db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(h, nil, nil, nil)) + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(a, nil, nil, nil, false)) + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(b, nil, nil, nil, false)) + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(c, nil, nil, nil, false)) + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(d, nil, nil, nil, false)) + db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(e, nil, nil, nil, false)) + db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(f, nil, nil, nil, false)) + db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(g, nil, nil, nil, false)) + db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(h, nil, nil, nil, false)) // binaryIterator r, _ := db.StateReader(common.HexToHash("0x09")) @@ -504,14 +504,14 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(a), nil, nil)) - db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(b), nil, nil)) - db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(c), nil, nil)) - db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(d), nil, nil)) - db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(e), nil, nil)) - db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(f), nil, nil)) - db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(g), nil, nil)) - db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(h), nil, nil)) + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 2, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(a), nil, nil, false)) + db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 3, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(b), nil, nil, false)) + db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 4, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(c), nil, nil, false)) + db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 5, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(d), nil, nil, false)) + db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 6, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(e), nil, nil, false)) + db.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), 7, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(f), nil, nil, false)) + db.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), 8, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(g), nil, nil, false)) + db.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), 9, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(randomAccountSet("0xaa"), wrapStorage(h), nil, nil, false)) // binaryIterator r, _ := db.StateReader(common.HexToHash("0x09")) @@ -588,7 +588,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) { parent = common.HexToHash(fmt.Sprintf("0x%02x", i)) } db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), parent, uint64(i), trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil)) + NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil, false)) } // Iterate the entire stack and ensure everything is hit only once head := db.tree.get(common.HexToHash("0x80")) @@ -626,13 +626,13 @@ func TestAccountIteratorFlattening(t *testing.T) { // Create a stack of diffs on top db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil, false)) // Create a binary iterator and flatten the data from underneath it head := db.tree.get(common.HexToHash("0x04")) @@ -658,13 +658,13 @@ func TestAccountIteratorSeek(t *testing.T) { // db.WaitGeneration() db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xbb", "0xdd", "0xf0"), nil, nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xcc", "0xf0", "0xff"), nil, nil, nil, false)) // Account set is now // 02: aa, ee, f0, ff @@ -731,13 +731,13 @@ func testStorageIteratorSeek(t *testing.T, newIterator func(db *Database, root, // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil), nil, nil, false)) // Account set is now // 02: 01, 03, 05 @@ -803,16 +803,16 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(db *Database, r // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0x11", "0x22", "0x33"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0x11", "0x22", "0x33"), nil, nil, nil, false)) deleted := common.HexToHash("0x22") accounts := randomAccountSet("0x11", "0x33") accounts[deleted] = nil db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(accounts, nil, nil, nil)) + NewStateSetWithOrigin(accounts, nil, nil, nil, false)) db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0x33", "0x44", "0x55"), nil, nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0x33", "0x44", "0x55"), nil, nil, nil, false)) // The output should be 11,33,44,55 it := newIterator(db, common.HexToHash("0x04"), common.Hash{}) @@ -843,10 +843,10 @@ func TestStorageIteratorDeletions(t *testing.T) { // Stack three diff layers on top with various overlaps db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}), nil, nil, false)) // The output should be 02,04,05,06 it, _ := db.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{}) @@ -863,7 +863,7 @@ func TestStorageIteratorDeletions(t *testing.T) { common.HexToHash("0xaa"): nil, } db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(accounts, randomStorageSet([]string{"0xaa"}, nil, [][]string{{"0x02", "0x04", "0x05", "0x06"}}), nil, nil)) + NewStateSetWithOrigin(accounts, randomStorageSet([]string{"0xaa"}, nil, [][]string{{"0x02", "0x04", "0x05", "0x06"}}), nil, nil, false)) it, _ = db.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 0, it, verifyStorage) @@ -871,7 +871,7 @@ func TestStorageIteratorDeletions(t *testing.T) { // Re-insert the slots of the same account db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 4, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil), nil, nil, false)) // The output should be 07,08,09 it, _ = db.StorageIterator(common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{}) @@ -880,7 +880,7 @@ func TestStorageIteratorDeletions(t *testing.T) { // Destruct the whole storage but re-create the account in the same layer db.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), 5, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}}), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}}), nil, nil, false)) it, _ = db.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 @@ -911,19 +911,19 @@ func testStaleIterator(t *testing.T, newIter func(db *Database, hash common.Hash // [02 (disk), 03] db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01"}}, nil), nil, nil, false)) db.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), 2, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02"}}, nil), nil, nil, false)) db.tree.cap(common.HexToHash("0x03"), 1) // [02 (disk), 03, 04] db.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x03"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x03"}}, nil), nil, nil, false)) iter := newIter(db, common.HexToHash("0x04")) // [04 (disk), 05] db.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), 3, trienode.NewMergedNodeSet(), - NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04"}}, nil), nil, nil)) + NewStateSetWithOrigin(randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04"}}, nil), nil, nil, false)) db.tree.cap(common.HexToHash("0x05"), 1) // Iterator can't finish the traversal as the layer 02 has becoming stale. @@ -969,7 +969,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) { if i == 1 { parent = common.HexToHash(fmt.Sprintf("0x%02x", i)) } - db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), parent, uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil)) + db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), parent, uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(200), nil, nil, nil, false)) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. @@ -1059,9 +1059,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { db := New(rawdb.NewMemoryDatabase(), config, false) // db.WaitGeneration() - db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(2000), nil, nil, nil)) + db.Update(common.HexToHash("0x02"), types.EmptyRootHash, 1, trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(2000), nil, nil, nil, false)) for i := 2; i <= 100; i++ { - db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(20), nil, nil, nil)) + db.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), uint64(i), trienode.NewMergedNodeSet(), NewStateSetWithOrigin(makeAccounts(20), nil, nil, nil, false)) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 267d675bc..79a7a22e0 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -45,7 +45,8 @@ var ( // - Version 0: initial version // - Version 1: storage.Incomplete field is removed // - Version 2: add post-modification state values -const journalVersion uint64 = 2 +// - Version 3: a flag has been added to indicate whether the storage slot key is the raw key or a hash +const journalVersion uint64 = 3 // loadJournal tries to parse the layer journal from the disk. func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index 81d34da5d..969782e3c 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -65,6 +65,8 @@ type stateSet struct { accountListSorted []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil storageListSorted map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil + rawStorageKey bool // indicates whether the storage set uses the raw slot key or the hash + // Lock for guarding the two lists above. These lists might be accessed // concurrently and lock protection is essential to avoid concurrent // slice or map read/write. @@ -72,7 +74,7 @@ type stateSet struct { } // newStates constructs the state set with the provided account and storage data. -func newStates(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *stateSet { +func newStates(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte, rawStorageKey bool) *stateSet { // Don't panic for the lazy callers, initialize the nil maps instead. if accounts == nil { accounts = make(map[common.Hash][]byte) @@ -83,6 +85,7 @@ func newStates(accounts map[common.Hash][]byte, storages map[common.Hash]map[com s := &stateSet{ accountData: accounts, storageData: storages, + rawStorageKey: rawStorageKey, storageListSorted: make(map[common.Hash][]common.Hash), } s.size = s.check() @@ -330,6 +333,9 @@ func (s *stateSet) updateSize(delta int) { // encode serializes the content of state set into the provided writer. func (s *stateSet) encode(w io.Writer) error { // Encode accounts + if err := rlp.Encode(w, s.rawStorageKey); err != nil { + return err + } type accounts struct { AddrHashes []common.Hash Accounts [][]byte @@ -367,6 +373,9 @@ func (s *stateSet) encode(w io.Writer) error { // decode deserializes the content from the rlp stream into the state set. func (s *stateSet) decode(r *rlp.Stream) error { + if err := r.Decode(&s.rawStorageKey); err != nil { + return fmt.Errorf("load diff raw storage key flag: %v", err) + } type accounts struct { AddrHashes []common.Hash Accounts [][]byte @@ -435,23 +444,23 @@ func (s *stateSet) dbsize() int { type StateSetWithOrigin struct { *stateSet - // AccountOrigin represents the account data before the state transition, + // accountOrigin represents the account data before the state transition, // corresponding to both the accountData and destructSet. It's keyed by the // account address. The nil value means the account was not present before. accountOrigin map[common.Address][]byte - // StorageOrigin represents the storage data before the state transition, + // storageOrigin represents the storage data before the state transition, // corresponding to storageData and deleted slots of destructSet. It's keyed // by the account address and slot key hash. The nil value means the slot was // not present. storageOrigin map[common.Address]map[common.Hash][]byte - // Memory size of the state data (accountOrigin and storageOrigin) + // memory size of the state data (accountOrigin and storageOrigin) size uint64 } // NewStateSetWithOrigin constructs the state set with the provided data. -func NewStateSetWithOrigin(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte, accountOrigin map[common.Address][]byte, storageOrigin map[common.Address]map[common.Hash][]byte) *StateSetWithOrigin { +func NewStateSetWithOrigin(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte, accountOrigin map[common.Address][]byte, storageOrigin map[common.Address]map[common.Hash][]byte, rawStorageKey bool) *StateSetWithOrigin { // Don't panic for the lazy callers, initialize the nil maps instead. if accountOrigin == nil { accountOrigin = make(map[common.Address][]byte) @@ -471,7 +480,7 @@ func NewStateSetWithOrigin(accounts map[common.Hash][]byte, storages map[common. size += 2*common.HashLength + len(data) } } - set := newStates(accounts, storages) + set := newStates(accounts, storages, rawStorageKey) return &StateSetWithOrigin{ stateSet: set, accountOrigin: accountOrigin, diff --git a/triedb/pathdb/states_test.go b/triedb/pathdb/states_test.go index f097e90e8..30eb6ad6c 100644 --- a/triedb/pathdb/states_test.go +++ b/triedb/pathdb/states_test.go @@ -44,6 +44,7 @@ func TestStatesMerge(t *testing.T) { common.Hash{0x1}: {0x10}, }, }, + false, ) b := newStates( map[common.Hash][]byte{ @@ -64,6 +65,7 @@ func TestStatesMerge(t *testing.T) { common.Hash{0x1}: nil, // delete slot }, }, + false, ) a.merge(b) @@ -132,6 +134,7 @@ func TestStatesRevert(t *testing.T) { common.Hash{0x1}: {0x10}, }, }, + false, ) b := newStates( map[common.Hash][]byte{ @@ -152,6 +155,7 @@ func TestStatesRevert(t *testing.T) { common.Hash{0x1}: nil, }, }, + false, ) a.merge(b) a.revertTo( @@ -224,12 +228,13 @@ func TestStatesRevert(t *testing.T) { // before and was created during transition w, reverting w will retain an x=nil // entry in the set. func TestStateRevertAccountNullMarker(t *testing.T) { - a := newStates(nil, nil) // empty initial state + a := newStates(nil, nil, false) // empty initial state b := newStates( map[common.Hash][]byte{ {0xa}: {0xa}, }, nil, + false, ) a.merge(b) // create account 0xa a.revertTo( @@ -254,7 +259,7 @@ func TestStateRevertAccountNullMarker(t *testing.T) { func TestStateRevertStorageNullMarker(t *testing.T) { a := newStates(map[common.Hash][]byte{ {0xa}: {0xa}, - }, nil) // initial state with account 0xa + }, nil, false) // initial state with account 0xa b := newStates( nil, @@ -263,6 +268,7 @@ func TestStateRevertStorageNullMarker(t *testing.T) { common.Hash{0x1}: {0x1}, }, }, + false, ) a.merge(b) // create slot 0x1 a.revertTo( @@ -284,6 +290,11 @@ func TestStateRevertStorageNullMarker(t *testing.T) { } func TestStatesEncode(t *testing.T) { + testStatesEncode(t, false) + testStatesEncode(t, true) +} + +func testStatesEncode(t *testing.T, rawStorageKey bool) { s := newStates( map[common.Hash][]byte{ {0x1}: {0x1}, @@ -293,6 +304,7 @@ func TestStatesEncode(t *testing.T) { common.Hash{0x1}: {0x1}, }, }, + rawStorageKey, ) buf := bytes.NewBuffer(nil) if err := s.encode(buf); err != nil { @@ -308,9 +320,17 @@ func TestStatesEncode(t *testing.T) { if !reflect.DeepEqual(s.storageData, dec.storageData) { t.Fatal("Unexpected storage data") } + if s.rawStorageKey != dec.rawStorageKey { + t.Fatal("Unexpected rawStorageKey flag") + } } func TestStateWithOriginEncode(t *testing.T) { + testStateWithOriginEncode(t, false) + testStateWithOriginEncode(t, true) +} + +func testStateWithOriginEncode(t *testing.T, rawStorageKey bool) { s := NewStateSetWithOrigin( map[common.Hash][]byte{ {0x1}: {0x1}, @@ -328,6 +348,7 @@ func TestStateWithOriginEncode(t *testing.T) { common.Hash{0x1}: {0x1}, }, }, + rawStorageKey, ) buf := bytes.NewBuffer(nil) if err := s.encode(buf); err != nil { @@ -349,6 +370,9 @@ func TestStateWithOriginEncode(t *testing.T) { if !reflect.DeepEqual(s.storageOrigin, dec.storageOrigin) { t.Fatal("Unexpected storage origin data") } + if s.rawStorageKey != dec.rawStorageKey { + t.Fatal("Unexpected rawStorageKey flag") + } } func TestStateSizeTracking(t *testing.T) { @@ -375,6 +399,7 @@ func TestStateSizeTracking(t *testing.T) { common.Hash{0x1}: {0x10}, // 2*common.HashLength+1 }, }, + false, ) if a.size != uint64(expSizeA) { t.Fatalf("Unexpected size, want: %d, got: %d", expSizeA, a.size) @@ -406,6 +431,7 @@ func TestStateSizeTracking(t *testing.T) { common.Hash{0x3}: nil, // 2*common.HashLength, slot deletion }, }, + false, ) if b.size != uint64(expSizeB) { t.Fatalf("Unexpected size, want: %d, got: %d", expSizeB, b.size) diff --git a/triedb/states.go b/triedb/states.go index fa432e070..9fabdb088 100644 --- a/triedb/states.go +++ b/triedb/states.go @@ -27,6 +27,7 @@ type StateSet struct { AccountsOrigin map[common.Address][]byte // Original values of mutated accounts in 'slim RLP' encoding Storages map[common.Hash]map[common.Hash][]byte // Mutated storage slots in 'prefix-zero-trimmed' RLP format StoragesOrigin map[common.Address]map[common.Hash][]byte // Original values of mutated storage slots in 'prefix-zero-trimmed' RLP format + RawStorageKey bool // Flag whether the storage set uses the raw slot key or the hash } // NewStateSet initializes an empty state set. @@ -45,5 +46,5 @@ func (set *StateSet) internal() *pathdb.StateSetWithOrigin { if set == nil { return nil } - return pathdb.NewStateSetWithOrigin(set.Accounts, set.Storages, set.AccountsOrigin, set.StoragesOrigin) + return pathdb.NewStateSetWithOrigin(set.Accounts, set.Storages, set.AccountsOrigin, set.StoragesOrigin, set.RawStorageKey) } From 13592f59d5df4f0830e915a808fdb241c70e8831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 17 Jan 2025 16:54:19 +0100 Subject: [PATCH 083/354] ethdb/memorydb: faster DeleteRange (#31038) This PR replaces the iterator based DeleteRange implementation of memorydb with a simpler and much faster loop that directly deletes keys in the order of iteration instead of unnecessarily collecting keys in memory and sorting them. --------- Co-authored-by: Martin HS --- ethdb/memorydb/memorydb.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index c6fba39cf..a797275e9 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -18,7 +18,6 @@ package memorydb import ( - "bytes" "errors" "sort" "strings" @@ -125,12 +124,15 @@ func (db *Database) Delete(key []byte) error { // DeleteRange deletes all of the keys (and values) in the range [start,end) // (inclusive on start, exclusive on end). func (db *Database) DeleteRange(start, end []byte) error { - it := db.NewIterator(nil, start) - defer it.Release() + db.lock.Lock() + defer db.lock.Unlock() + if db.db == nil { + return errMemorydbClosed + } - for it.Next() && bytes.Compare(end, it.Key()) > 0 { - if err := db.Delete(it.Key()); err != nil { - return err + for key := range db.db { + if key >= string(start) && key < string(end) { + delete(db.db, key) } } return nil From ce1bd7838c3c631badfc103e44b9e1a2f5f41545 Mon Sep 17 00:00:00 2001 From: Cedrick Date: Mon, 20 Jan 2025 08:39:55 +0100 Subject: [PATCH 084/354] cmd/abigen: require either `--abi` or `--combined-json` (#31045) This PR addresses issue #30768 , which highlights that running cmd/abigen/abigen --pkg my_package example.json (erroneously omitting the --abi flag) generates an empty binding, when it should fail explicitly. --------- Co-authored-by: jwasinger --- cmd/abigen/main.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 0149dec52..8ee3130b5 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -98,6 +98,9 @@ func abigen(c *cli.Context) error { if c.String(pkgFlag.Name) == "" { utils.Fatalf("No destination package specified (--pkg)") } + if c.String(abiFlag.Name) == "" && c.String(jsonFlag.Name) == "" { + utils.Fatalf("Either contract ABI source (--abi) or combined-json (--combined-json) are required") + } var lang bind.Lang switch c.String(langFlag.Name) { case "go": From 7e98496622b98bbc7a3f2345f46067ef5ac6ec0e Mon Sep 17 00:00:00 2001 From: Shude Li Date: Mon, 20 Jan 2025 17:12:36 +0800 Subject: [PATCH 085/354] core/types: correct chainId check for pragueSigner (#31032) Use zero value check for the pragueSigner This aligns with cancunSigner and londonSigner as well. --- core/types/transaction_signing.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 4d70f37bd..030fc472a 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -219,7 +219,7 @@ func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big } // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID != nil && txdata.ChainID.CmpBig(s.chainId) != 0 { + if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) @@ -287,7 +287,7 @@ func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big } // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID.Sign() != 0 && txdata.ChainID.ToBig().Cmp(s.chainId) != 0 { + if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) From f2d33c4c86ec063c07b50292f2478d82eecabb5e Mon Sep 17 00:00:00 2001 From: levisyin Date: Tue, 21 Jan 2025 00:04:29 +0800 Subject: [PATCH 086/354] build: upgrade -dlgo version to Go 1.23.5 (#31037) --- build/checksums.txt | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index b0b7a73a3..7270492ec 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,56 +5,56 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.23.4 +# version:golang 1.23.5 # https://go.dev/dl/ -ad345ac421e90814293a9699cca19dd5238251c3f687980bbcae28495b263531 go1.23.4.src.tar.gz -459a09504f7ebf2cbcee6ac282c8f34f97651217b1feae64557dcdd392b9bb62 go1.23.4.aix-ppc64.tar.gz -0f4e569b2d38cb75cb2efcaf56beb42778ab5e46d89318fef39060fe36d7b9b7 go1.23.4.darwin-amd64.pkg -6700067389a53a1607d30aa8d6e01d198230397029faa0b109e89bc871ab5a0e go1.23.4.darwin-amd64.tar.gz -19c054eaf40c5fac65b027f7443c01382e493d3c8c42cf8b2504832ebddce037 go1.23.4.darwin-arm64.pkg -87d2bb0ad4fe24d2a0685a55df321e0efe4296419a9b3de03369dbe60b8acd3a go1.23.4.darwin-arm64.tar.gz -5e73dc89b44626677ec9d9aa4257d6d2ef1245502bc36a99385284910d0ade0a go1.23.4.dragonfly-amd64.tar.gz -8df26b1e71234756c1f0e82cfffba3f427c5a91a251844ada2c7694a6986c546 go1.23.4.freebsd-386.tar.gz -7de078d94d2af50ee9506ef7df85e4d12d4018b23e0b2cbcbc61d686f549b41a go1.23.4.freebsd-amd64.tar.gz -3f23e0a01cfe24e4160124cd7ab02bdd188264652074abdbce401c93f41e58a4 go1.23.4.freebsd-arm.tar.gz -986a20e7c94431f03b44b3c415abc698c7b4edc2ae8431f7ecae1c2429d4cfa2 go1.23.4.freebsd-arm64.tar.gz -25e39f005f977778ce963fc43089510fe7514f3cfc0358eab584de4ce9f181fb go1.23.4.freebsd-riscv64.tar.gz -7e1d52f93da68c3bab39e3d83f89944d7d151208e54fdc30b0eda2a3812661d7 go1.23.4.illumos-amd64.tar.gz -4a4a0e7587ef8c8a326439b957027f2791795e2d29d4ae3885b4091a48f843bc go1.23.4.linux-386.tar.gz -6924efde5de86fe277676e929dc9917d466efa02fb934197bc2eba35d5680971 go1.23.4.linux-amd64.tar.gz -16e5017863a7f6071363782b1b8042eb12c6ca4f4cd71528b2123f0a1275b13e go1.23.4.linux-arm64.tar.gz -1f1dda0dc7ce0b2295f57258ec5ef0803fd31b9ed0aa20e2e9222334e5755de1 go1.23.4.linux-armv6l.tar.gz -4f469179a335a1a7bb9f991ad0c567f3d3eeb9b412ecd192206ab5c3e1a52b5a go1.23.4.linux-loong64.tar.gz -86b68185bcc43ea07190e95137c3442f062acc7ae10c3f1cf900fbe23e07df24 go1.23.4.linux-mips.tar.gz -3a19245eec76533b3d01c90f3a40a38d63684028f0fd54d442dc9a9d03197891 go1.23.4.linux-mips64.tar.gz -b53a06fc8455f6a875329e8d2e24d39db298122c9cce6e948117022191f6c613 go1.23.4.linux-mips64le.tar.gz -66120a8105b8ba6559f4e6a13b1e39b433fb8032df9d1744e4486876fa1723ce go1.23.4.linux-mipsle.tar.gz -33be2bfb27f2821a65e9f6aba744c85ea7c5e233e16bac27bb3ec253bcd4e970 go1.23.4.linux-ppc64.tar.gz -65a303ef51e48ff77e004a6a5b4db6ce59495cd59c6af51b54bf4f786c01a1b9 go1.23.4.linux-ppc64le.tar.gz -7c40e9e0d722cef14ede765159ba297f4c6e3093bb106f10fbccf8564780049a go1.23.4.linux-riscv64.tar.gz -74aab82bf4eca7c26c830a5b0e2a31d193a4d5ba47045526b92473cc7188d7d7 go1.23.4.linux-s390x.tar.gz -dba009d8bf9928cb5a1e31fcbe0eb41335cce4fe63755d95cef6b5987df4ed5a go1.23.4.netbsd-386.tar.gz -54b081cc36355aa5ecb6db9544cf7e77366a7b08ce96cb98a45d043e393660c7 go1.23.4.netbsd-amd64.tar.gz -f05fec348c7c9f07e1ad4e436db4122e98de99ebcfbf6ac6176869785f334a02 go1.23.4.netbsd-arm.tar.gz -317878da2bface5a57a8eaf5c1fe2b40b1c82d8172a10453ad3eea36f6946bdb go1.23.4.netbsd-arm64.tar.gz -0d84350dfd72c505c6ad474e51676b04e95ffb748c614bd5bf8510026873059b go1.23.4.openbsd-386.tar.gz -cc62f5a14ea3d573d8edbce1833f70a8f99ca048a9db0fcc9e738fd48e950505 go1.23.4.openbsd-amd64.tar.gz -326aba6cf5bb9348fa3e41217abd2c84eac92608684e2fe8c5474fdab23a0db9 go1.23.4.openbsd-arm.tar.gz -51ea2a2588bf3da8e1476f3e2bd4d6724d74126e99f9c6ea9af4ebe389e64de6 go1.23.4.openbsd-arm64.tar.gz -44c5c82ab23e40225b2ba1e7d19150a5973ea58e93b4931e426e6e6f0d108872 go1.23.4.openbsd-ppc64.tar.gz -5fa31fc13d1e3c123a5e96ba38683fa2c947baed23ac9c7c341afcfe007c8993 go1.23.4.openbsd-riscv64.tar.gz -e5952fc93eeaa0094ef09a0e72a9f06f0621ce841a39f9637fb5b9062e77d67a go1.23.4.plan9-386.tar.gz -fb2a9ee3ae5a77e734862e257a9395b43e707ac45e060dfa84c5a40688e73170 go1.23.4.plan9-amd64.tar.gz -e1b95563b19fdebd6ea0d20c07641e69580976fa754e586c831ad7a3ae987140 go1.23.4.plan9-arm.tar.gz -088c282509fc9e1a8f29fc0dd16fe486854d05b8ceba08d077d17d11d6979a41 go1.23.4.solaris-amd64.tar.gz -e5865c1bfc3fee5d003819b2e2c800f598fe9994931bac63f573e8d05a10d91f go1.23.4.windows-386.msi -e544e0e356147ba998e267002bd0f2c4bf3370d495467a55baf2c63595a2026d go1.23.4.windows-386.zip -5f8cc5991eb8f4f96b6c611d839453cd11c9a2c3f23672a4188342c97ee159fa go1.23.4.windows-amd64.msi -16c59ac9196b63afb872ce9b47f945b9821a3e1542ec125f16f6085a1c0f3c39 go1.23.4.windows-amd64.zip -fc77c0531406d092c5356167e45c05a22d16bea84e3fa555e0f03af085c11763 go1.23.4.windows-arm.msi -1012cfd8ca7241c2beecb5c345dd61f01897c6f6baca80ea1bfed357035c868a go1.23.4.windows-arm.zip -8347c1aa4e1e67954d12830f88dbe44bd7ac0ec134bb472783dbfb5a3a8865d0 go1.23.4.windows-arm64.msi -db69cae5006753c785345c3215ad941f8b6224e2f81fec471c42d6857bee0e6f go1.23.4.windows-arm64.zip +a6f3f4bbd3e6bdd626f79b668f212fbb5649daf75084fb79b678a0ae4d97423b go1.23.5.src.tar.gz +8d8bc7d1b362dd91426da9352741db298ff73e3e0a3ccbe6f607f80ba17647a4 go1.23.5.aix-ppc64.tar.gz +d8b310b0b6bd6a630307579165cfac8a37571483c7d6804a10dd73bbefb0827f go1.23.5.darwin-amd64.tar.gz +d2b06bf0b8299e0187dfe2d8ad39bd3dd96a6d93fe4d1cfd42c7872452f4a0a2 go1.23.5.darwin-amd64.pkg +047bfce4fbd0da6426bd30cd19716b35a466b1c15a45525ce65b9824acb33285 go1.23.5.darwin-arm64.tar.gz +f819ed94939e08a5016b9a607ec84ebbde6cb3fe59750c59d97aa300c3fd02df go1.23.5.darwin-arm64.pkg +2dec52821e1f04a538d00b2cafe70fa506f2eea94a551bfe3ce1238f1bd4966f go1.23.5.dragonfly-amd64.tar.gz +7204e7bc62913b12f18c61afe0bc1a92fd192c0e45a54125978592296cb84e49 go1.23.5.freebsd-386.tar.gz +90a119995ebc3e36082874df5fa8fe6da194946679d01ae8bef33c87aab99391 go1.23.5.freebsd-amd64.tar.gz +255d26d873e41ff2fc278013bb2e5f25cf2ebe8d0ec84c07e3bb1436216020d3 go1.23.5.freebsd-arm.tar.gz +2785d9122654980b59ca38305a11b34f2a1e12d9f7eb41d52efc137c1fc29e61 go1.23.5.freebsd-arm64.tar.gz +8f66a94018ab666d56868f61c579aa81e549ac9700979ce6004445d315be2d37 go1.23.5.freebsd-riscv64.tar.gz +4b7a69928385ec512a4e77a547e24118adbb92301d2be36187ff0852ba9e6303 go1.23.5.illumos-amd64.tar.gz +6ecf6a41d0925358905fa2641db0e1c9037aa5b5bcd26ca6734caf50d9196417 go1.23.5.linux-386.tar.gz +cbcad4a6482107c7c7926df1608106c189417163428200ce357695cc7e01d091 go1.23.5.linux-amd64.tar.gz +47c84d332123883653b70da2db7dd57d2a865921ba4724efcdf56b5da7021db0 go1.23.5.linux-arm64.tar.gz +04e0b5cf5c216f0aa1bf8204d49312ad0845800ab0702dfe4357c0b1241027a3 go1.23.5.linux-armv6l.tar.gz +e1d14ac2207c78d52b76ba086da18a004c70aeb58cba72cd9bef0da7d1602786 go1.23.5.linux-loong64.tar.gz +d9e937f2fac4fc863850fb4cc31ae76d5495029a62858ef09c78604472d354c0 go1.23.5.linux-mips.tar.gz +59710d0782abafd47e40d1cf96aafa596bbdee09ac7c61062404604f49bd523e go1.23.5.linux-mips64.tar.gz +bc528cd836b4aa6701a42093ed390ef9929639a0e2818759887dc5539e517cab go1.23.5.linux-mips64le.tar.gz +a0404764ea1fd4a175dc5193622b15be6ed1ab59cbfa478f5ae24531bafb6cbd go1.23.5.linux-mipsle.tar.gz +db110284a0c91d4545273f210ca95b9f89f6e3ac90f39eb819033a6b96f25897 go1.23.5.linux-ppc64.tar.gz +db268bf5710b5b1b82ab38722ba6e4427d9e4942aed78c7d09195a9dff329613 go1.23.5.linux-ppc64le.tar.gz +d9da15778442464f32acfa777ac731fd4d47362b233b83a0932380cb6d2d5dc8 go1.23.5.linux-riscv64.tar.gz +14924b917d35311eb130e263f34931043d4f9dc65f20684301bf8f60a72edcdf go1.23.5.linux-s390x.tar.gz +7b8074102e7f039bd6473c44f58cb323c98dcda48df98ad1f78aaa2664769c8f go1.23.5.netbsd-386.tar.gz +1a466b9c8900e66664b15c07548ecb156e8274cf1028ac5da84134728e6dbbed go1.23.5.netbsd-amd64.tar.gz +901c9e72038926e37a4dbde8f03d1d81fcb9992850901a3da1da5a25ef93e65b go1.23.5.netbsd-arm.tar.gz +221f69a7c3a920e3666633ee0b4e5c810176982e74339ba4693226996dc636e4 go1.23.5.netbsd-arm64.tar.gz +42e46cbf73febb8e6ddf848765ce1c39573736383b132402cdc487eb6be3ad06 go1.23.5.openbsd-386.tar.gz +f49e81fce17aab21800fab7c4b10c97ab02f8a9c807fdf8641ccf2f87d69289f go1.23.5.openbsd-amd64.tar.gz +d8bd7269d4670a46e702b64822254a654824347c35923ef1c444d2e8687381ea go1.23.5.openbsd-arm.tar.gz +9cb259adff431d4d28b18e3348e26fe07ea10380675051dcfd740934b5e8b9f2 go1.23.5.openbsd-arm64.tar.gz +72a03223c98fcecfb06e57c3edd584f99fb7f6574a42f59348473f354be1f379 go1.23.5.openbsd-ppc64.tar.gz +c06432b859afb36657207382b7bac03f961b8fafc18176b501d239575a9ace64 go1.23.5.openbsd-riscv64.tar.gz +b1f9b12b269ab5cd4aa7ae3dd3075c2407c1ea8bb1211e6835261f98931201cc go1.23.5.plan9-386.tar.gz +45b4026a103e2f6cd436e2b7ad24b24a40dd22c9903519b98b45c535574fa01a go1.23.5.plan9-amd64.tar.gz +6e28e26f8c1e8620006490260aa5743198843aa0003c400cb65cbf5e743b21c7 go1.23.5.plan9-arm.tar.gz +0496c9969f208bd597f3e63fb27068ce1c7ed776618da1007fcc1c8be83ca413 go1.23.5.solaris-amd64.tar.gz +8441605a005ea74c28d8c02ca5f2708c17b4df7e91796148b9f8760caafb05c1 go1.23.5.windows-386.zip +39962346d8d0cb0cc8716489ee33b08d7a220c24a9e45423487876dd4acbdac6 go1.23.5.windows-386.msi +96d74945d7daeeb98a7978d0cf099321d7eb821b45f5c510373d545162d39c20 go1.23.5.windows-amd64.zip +03e11a988a18ad7e3f9038cef836330af72ba0a454a502cda7b7faee07a0dd8a go1.23.5.windows-amd64.msi +0005b31dcf9732c280a5cceb6aa1c5ab8284bc2541d0256c221256080acf2a09 go1.23.5.windows-arm.zip +a8442de35cbac230db8c4b20e363055671f2295dc4d6b2b2dfec66b89a3c4bce go1.23.5.windows-arm.msi +4f20c2d8a5a387c227e3ef48c5506b22906139d8afd8d66a78ef3de8dda1d1c3 go1.23.5.windows-arm64.zip +6f54fb46b669345c734936c521f7e0f55555e63ed6e11efbbaaed06f9514773c go1.23.5.windows-arm64.msi # version:golangci 1.63.4 # https://github.com/golangci/golangci-lint/releases/ From afee07765a1759173cd5efc10fa7d4ba5518a80c Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 21 Jan 2025 00:06:39 +0800 Subject: [PATCH 087/354] core/types: initialize ChainID in SetCodeTx copy method (#31054) --- core/types/tx_setcode.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index 0fb5362c2..894bac10a 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -148,7 +148,7 @@ func (tx *SetCodeTx) copy() TxData { AccessList: make(AccessList, len(tx.AccessList)), AuthList: make([]SetCodeAuthorization, len(tx.AuthList)), Value: new(uint256.Int), - ChainID: tx.ChainID, + ChainID: new(uint256.Int), GasTipCap: new(uint256.Int), GasFeeCap: new(uint256.Int), V: new(uint256.Int), @@ -160,6 +160,9 @@ func (tx *SetCodeTx) copy() TxData { if tx.Value != nil { cpy.Value.Set(tx.Value) } + if tx.ChainID != nil { + cpy.ChainID.Set(tx.ChainID) + } if tx.GasTipCap != nil { cpy.GasTipCap.Set(tx.GasTipCap) } From 7c94adb32e48e16ce70f6893e2dac758d6be7bdc Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 21 Jan 2025 11:42:05 +0800 Subject: [PATCH 088/354] core/txpool: terminate subpool reset goroutine if pool was closed (#31030) if the pool terminates before `resetDone` can be read, then the go-routine will hang. --- core/txpool/txpool.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 2450a130e..985e005d6 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -227,7 +227,10 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) { for _, subpool := range p.subpools { subpool.Reset(oldHead, newHead) } - resetDone <- newHead + select { + case resetDone <- newHead: + case <-p.term: + } }(oldHead, newHead) // If the reset operation was explicitly requested, consider it From 3519e277100980388488ce1331e6d7e53f1566d3 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 21 Jan 2025 08:35:03 +0100 Subject: [PATCH 089/354] cmd/evm: refactor handling output-files for `t8n` (#30854) As part of trying to make the inputs and outputs of the evm subcommands more streamlined and aligned, this PR modifies how `evm t8n` manages output-files. Previously, we do a kind of wonky thing where between each transaction, we invoke a `getTracer` closure. In that closure, we create a new output-file, a tracer, and then make the tracer stream output to the file. We also fiddle a bit to ensure that the file becomes properly closed. It is a kind of hacky solution we have in place. This PR changes it, so that from the execution-pipeline point of view, we have just a regular tracer. No fiddling with re-setting it or closing files. That particular tracer, however, is a bit special: it takes care of creating new files per transaction (in the tx-start-hook) and closing (on tx-end-hook). Also instantiating the right type of underlying tracer, which can be a json-logger or a custom tracer. --------- Co-authored-by: Gary Rong --- cmd/evm/internal/t8ntool/execution.go | 52 +----- cmd/evm/internal/t8ntool/file_tracer.go | 152 ++++++++++++++++++ cmd/evm/internal/t8ntool/transaction.go | 6 +- cmd/evm/internal/t8ntool/transition.go | 77 ++++----- cmd/evm/main.go | 4 +- cmd/evm/t8n_test.go | 32 ++-- cmd/evm/testdata/31/README.md | 10 ++ ...47543268a5aaf2a6b32a69d2c6d978c45dcfb.json | 2 +- ...3641ef5a8bbdb10ac69f466083a6789c77fb8.json | 1 + ...641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl | 6 + ...86f5a9a08f7ef183da72c23bb3b2374530128.json | 1 + ...6f5a9a08f7ef183da72c23bb3b2374530128.jsonl | 6 + cmd/evm/testdata/31/txs.json | 24 +++ core/vm/evm.go | 5 - 14 files changed, 260 insertions(+), 118 deletions(-) create mode 100644 cmd/evm/internal/t8ntool/file_tracer.go create mode 100644 cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.json create mode 100644 cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl create mode 100644 cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.json create mode 100644 cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 357429470..d365acac1 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -17,9 +17,7 @@ package t8ntool import ( - "encoding/json" "fmt" - "io" "math/big" "github.com/ethereum/go-ethereum/common" @@ -36,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -131,9 +128,7 @@ type rejectedTx struct { } // Apply applies a set of transactions to a pre-state -func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, - txIt txIterator, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { +func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64) (*state.StateDB, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -250,23 +245,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, continue } } - tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash(), chainConfig) - if err != nil { - return nil, nil, nil, err - } - // TODO (rjl493456442) it's a bit weird to reset the tracer in the - // middle of block execution, please improve it somehow. - if tracer != nil { - evm.SetTracer(tracer.Hooks) - } statedb.SetTxContext(tx.Hash(), txIndex) - var ( snapshot = statedb.Snapshot() prevGas = gaspool.Gas() ) - if tracer != nil && tracer.OnTxStart != nil { - tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil { + evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) msgResult, err := core.ApplyMessage(evm, msg, gaspool) @@ -275,13 +260,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) - if tracer != nil { - if tracer.OnTxEnd != nil { - tracer.OnTxEnd(nil, err) - } - if err := writeTraceResult(tracer, traceOutput); err != nil { - log.Warn("Error writing tracer output", "err", err) - } + if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil { + evm.Config.Tracer.OnTxEnd(nil, err) } continue } @@ -325,13 +305,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) - if tracer != nil { - if tracer.Hooks.OnTxEnd != nil { - tracer.Hooks.OnTxEnd(receipt, nil) - } - if err = writeTraceResult(tracer, traceOutput); err != nil { - log.Warn("Error writing tracer output", "err", err) - } + if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil { + evm.Config.Tracer.OnTxEnd(receipt, nil) } } @@ -477,16 +452,3 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime } return ethash.CalcDifficulty(config, currentTime, parent) } - -func writeTraceResult(tracer *tracers.Tracer, f io.WriteCloser) error { - defer f.Close() - result, err := tracer.GetResult() - if err != nil || result == nil { - return err - } - err = json.NewEncoder(f).Encode(result) - if err != nil { - return err - } - return nil -} diff --git a/cmd/evm/internal/t8ntool/file_tracer.go b/cmd/evm/internal/t8ntool/file_tracer.go new file mode 100644 index 000000000..38fc35bd3 --- /dev/null +++ b/cmd/evm/internal/t8ntool/file_tracer.go @@ -0,0 +1,152 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package t8ntool + +import ( + "encoding/json" + "fmt" + "io" + "math/big" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/log" +) + +// fileWritingTracer wraps either a tracer or a logger. On tx start, +// it instantiates a tracer/logger, creates a new file to direct output to, +// and on tx end it closes the file. +type fileWritingTracer struct { + txIndex int // transaction counter + inner *tracing.Hooks // inner hooks + destination io.WriteCloser // the currently open file (if any) + baseDir string // baseDir to write output-files to + suffix string // suffix is the suffix to use when creating files + + // for custom tracing + getResult func() (json.RawMessage, error) +} + +func (l *fileWritingTracer) Write(p []byte) (n int, err error) { + if l.destination != nil { + return l.destination.Write(p) + } + log.Warn("Tracer wrote to non-existing output") + // It is tempting to return an error here, however, the json encoder + // will no retry writing to an io.Writer once it has returned an error once. + // Therefore, we must squash the error. + return n, nil +} + +// newFileWriter creates a set of hooks which wraps inner hooks (typically a logger), +// and writes the output to a file, one file per transaction. +func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *tracing.Hooks { + t := &fileWritingTracer{ + baseDir: baseDir, + suffix: "jsonl", + } + t.inner = innerFn(t) // instantiate the inner tracer + return t.hooks() +} + +// newResultWriter creates a set of hooks wraps and invokes an underlying tracer, +// and writes the result (getResult-output) to file, one per transaction. +func newResultWriter(baseDir string, tracer *tracers.Tracer) *tracing.Hooks { + t := &fileWritingTracer{ + baseDir: baseDir, + getResult: tracer.GetResult, + inner: tracer.Hooks, + suffix: "json", + } + return t.hooks() +} + +// OnTxStart creates a new output-file specific for this transaction, and invokes +// the inner OnTxStart handler. +func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + // Open a new file, or print a warning log if it's failed + fname := filepath.Join(l.baseDir, fmt.Sprintf("trace-%d-%v.%v", l.txIndex, tx.Hash().String(), l.suffix)) + traceFile, err := os.Create(fname) + if err != nil { + log.Warn("Failed creating trace-file", "err", err) + } else { + log.Info("Created tracing-file", "path", fname) + l.destination = traceFile + } + if l.inner != nil && l.inner.OnTxStart != nil { + l.inner.OnTxStart(env, tx, from) + } +} + +// OnTxEnd writes result (if getResult exist), closes any currently open output-file, +// and invokes the inner OnTxEnd handler. +func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) { + if l.inner != nil && l.inner.OnTxEnd != nil { + l.inner.OnTxEnd(receipt, err) + } + if l.getResult != nil && l.destination != nil { + if result, err := l.getResult(); result != nil { + json.NewEncoder(l.destination).Encode(result) + } else { + log.Warn("Error obtaining tracer result", "err", err) + } + l.destination.Close() + l.destination = nil + } + l.txIndex++ +} + +func (l *fileWritingTracer) hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnTxEnd: l.OnTxEnd, + OnEnter: func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if l.inner != nil && l.inner.OnEnter != nil { + l.inner.OnEnter(depth, typ, from, to, input, gas, value) + } + }, + OnExit: func(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if l.inner != nil && l.inner.OnExit != nil { + l.inner.OnExit(depth, output, gasUsed, err, reverted) + } + }, + OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if l.inner != nil && l.inner.OnOpcode != nil { + l.inner.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) + } + }, + OnFault: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + if l.inner != nil && l.inner.OnFault != nil { + l.inner.OnFault(pc, op, gas, cost, scope, depth, err) + } + }, + OnSystemCallStart: func() { + if l.inner != nil && l.inner.OnSystemCallStart != nil { + l.inner.OnSystemCallStart() + } + }, + OnSystemCallEnd: func() { + if l.inner != nil && l.inner.OnSystemCallEnd != nil { + l.inner.OnSystemCallEnd() + } + }, + } +} diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 6dac4301d..d8650beca 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -64,12 +64,10 @@ func (r *result) MarshalJSON() ([]byte, error) { } func Transaction(ctx *cli.Context) error { - var ( - err error - ) // We need to load the transactions. May be either in stdin input or in files. // Check if anything needs to be read from stdin var ( + err error txStr = ctx.String(InputTxsFlag.Name) inputData = &input{} chainConfig *params.ChainConfig @@ -82,6 +80,7 @@ func Transaction(ctx *cli.Context) error { } // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) + var body hexutil.Bytes if txStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) @@ -107,6 +106,7 @@ func Transaction(ctx *cli.Context) error { } } signer := types.MakeSigner(chainConfig, new(big.Int), 0) + // We now have the transactions in 'body', which is supposed to be an // rlp list of transactions it, err := rlp.NewListIterator([]byte(body)) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 4c2bd1b13..ac7ee5bfb 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -82,58 +82,10 @@ type input struct { } func Transition(ctx *cli.Context) error { - var getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) { - return nil, nil, nil - } - baseDir, err := createBasedir(ctx) if err != nil { return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) } - - if ctx.Bool(TraceFlag.Name) { // JSON opcode tracing - // Configure the EVM logger - logConfig := &logger.Config{ - DisableStack: ctx.Bool(TraceDisableStackFlag.Name), - EnableMemory: ctx.Bool(TraceEnableMemoryFlag.Name), - EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), - } - getTracer = func(txIndex int, txHash common.Hash, _ *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) { - traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) - if err != nil { - return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) - } - var l *tracing.Hooks - if ctx.Bool(TraceEnableCallFramesFlag.Name) { - l = logger.NewJSONLoggerWithCallFrames(logConfig, traceFile) - } else { - l = logger.NewJSONLogger(logConfig, traceFile) - } - tracer := &tracers.Tracer{ - Hooks: l, - // jsonLogger streams out result to file. - GetResult: func() (json.RawMessage, error) { return nil, nil }, - Stop: func(err error) {}, - } - return tracer, traceFile, nil - } - } else if ctx.IsSet(TraceTracerFlag.Name) { - var config json.RawMessage - if ctx.IsSet(TraceTracerConfigFlag.Name) { - config = []byte(ctx.String(TraceTracerConfigFlag.Name)) - } - getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) { - traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) - if err != nil { - return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) - } - tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config, chainConfig) - if err != nil { - return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) - } - return tracer, traceFile, nil - } - } // We need to load three things: alloc, env and transactions. May be either in // stdin input or in files. // Check if anything needs to be read from stdin @@ -179,6 +131,7 @@ func Transition(ctx *cli.Context) error { chainConfig = cConf vmConfig.ExtraEips = extraEips } + // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) @@ -200,8 +153,34 @@ func Transition(ctx *cli.Context) error { if err := applyCancunChecks(&prestate.Env, chainConfig); err != nil { return err } + + // Configure tracer + if ctx.IsSet(TraceTracerFlag.Name) { // Custom tracing + config := json.RawMessage(ctx.String(TraceTracerConfigFlag.Name)) + tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), + nil, config, chainConfig) + if err != nil { + return NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %v", err)) + } + vmConfig.Tracer = newResultWriter(baseDir, tracer) + } else if ctx.Bool(TraceFlag.Name) { // JSON opcode tracing + logConfig := &logger.Config{ + DisableStack: ctx.Bool(TraceDisableStackFlag.Name), + EnableMemory: ctx.Bool(TraceEnableMemoryFlag.Name), + EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), + } + if ctx.Bool(TraceEnableCallFramesFlag.Name) { + vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks { + return logger.NewJSONLoggerWithCallFrames(logConfig, out) + }) + } else { + vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks { + return logger.NewJSONLogger(logConfig, out) + }) + } + } // Run the test and aggregate the result - s, result, body, err := prestate.Apply(vmConfig, chainConfig, txIt, ctx.Int64(RewardFlag.Name), getTracer) + s, result, body, err := prestate.Apply(vmConfig, chainConfig, txIt, ctx.Int64(RewardFlag.Name)) if err != nil { return err } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 207942541..61e46aa50 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -83,8 +83,8 @@ var ( } TraceFormatFlag = &cli.StringFlag{ Name: "trace.format", - Usage: "Trace output format to use (struct|json)", - Value: "struct", + Usage: "Trace output format to use (json|struct|md)", + Value: "json", Category: traceCategory, } TraceDisableMemoryFlag = &cli.BoolFlag{ diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 27c6c4316..985dac968 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -606,18 +606,18 @@ func TestEvmRun(t *testing.T) { wantStdout: "./testdata/evmrun/1.out.1.txt", wantStderr: "./testdata/evmrun/1.out.2.txt", }, - { // default tracing (struct) - input: []string{"run", "--trace", "0x6040"}, + { // Struct tracing + input: []string{"run", "--trace", "--trace.format=struct", "0x6040"}, wantStdout: "./testdata/evmrun/2.out.1.txt", wantStderr: "./testdata/evmrun/2.out.2.txt", }, - { // default tracing (struct), plus alloc-dump - input: []string{"run", "--trace", "--dump", "0x6040"}, + { // struct-tracing, plus alloc-dump + input: []string{"run", "--trace", "--trace.format=struct", "--dump", "0x6040"}, wantStdout: "./testdata/evmrun/3.out.1.txt", //wantStderr: "./testdata/evmrun/3.out.2.txt", }, - { // json-tracing, plus alloc-dump - input: []string{"run", "--trace", "--trace.format=json", "--dump", "0x6040"}, + { // json-tracing (default), plus alloc-dump + input: []string{"run", "--trace", "--dump", "0x6040"}, wantStdout: "./testdata/evmrun/4.out.1.txt", //wantStderr: "./testdata/evmrun/4.out.2.txt", }, @@ -698,7 +698,10 @@ func TestEVMTracing(t *testing.T) { "--input.env=./testdata/31/env.json", "--state.fork=Cancun", "--trace", }, - expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"}, + //expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"}, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl", + "trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl", + "trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl"}, }, { base: "./testdata/31", @@ -706,14 +709,17 @@ func TestEVMTracing(t *testing.T) { "--input.alloc=./testdata/31/alloc.json", "--input.txs=./testdata/31/txs.json", "--input.env=./testdata/31/env.json", "--state.fork=Cancun", "--trace.tracer", ` -{ - result: function(){ - return "hello world" - }, - fault: function(){} +{ count: 0, + result: function(){ + this.count = this.count + 1; + return "hello world " + this.count + }, + fault: function(){} }`, }, - expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"}, + expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json", + "trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.json", + "trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.json"}, }, { base: "./testdata/32", diff --git a/cmd/evm/testdata/31/README.md b/cmd/evm/testdata/31/README.md index 305e4f52d..b337c1eb6 100644 --- a/cmd/evm/testdata/31/README.md +++ b/cmd/evm/testdata/31/README.md @@ -1 +1,11 @@ This test does some EVM execution, and can be used to test the tracers and trace-outputs. +This test should yield three output-traces, in separate files + +For example: +``` +[user@work evm]$ go run . t8n --input.alloc ./testdata/31/alloc.json --input.txs ./testdata/31/txs.json --input.env ./testdata/31/env.json --state.fork Cancun --output.basedir /tmp --trace +INFO [12-06|09:53:32.123] Created tracing-file path=/tmp/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl +INFO [12-06|09:53:32.124] Created tracing-file path=/tmp/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl +INFO [12-06|09:53:32.125] Created tracing-file path=/tmp/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl +``` + diff --git a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json index cd4bc1ab6..dfa1d7c7c 100644 --- a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json +++ b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json @@ -1 +1 @@ -"hello world" +"hello world 1" diff --git a/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.json b/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.json new file mode 100644 index 000000000..25980291c --- /dev/null +++ b/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.json @@ -0,0 +1 @@ +"hello world 2" diff --git a/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl b/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl new file mode 100644 index 000000000..26e5c7ee4 --- /dev/null +++ b/cmd/evm/testdata/31/trace-1-0x03a7b0a91e61a170d64ea94b8263641ef5a8bbdb10ac69f466083a6789c77fb8.jsonl @@ -0,0 +1,6 @@ +{"pc":0,"op":96,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x13495","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x13492","gasCost":"0x3","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x1348f","gasCost":"0x3","memSize":0,"stack":["0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":0,"gas":"0x1348c","gasCost":"0x0","memSize":0,"stack":["0x40","0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0xc"} diff --git a/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.json b/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.json new file mode 100644 index 000000000..242587bd8 --- /dev/null +++ b/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.json @@ -0,0 +1 @@ +"hello world 3" diff --git a/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl b/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl new file mode 100644 index 000000000..26e5c7ee4 --- /dev/null +++ b/cmd/evm/testdata/31/trace-2-0xd96e0ce6418ee3360e11d3c7b6886f5a9a08f7ef183da72c23bb3b2374530128.jsonl @@ -0,0 +1,6 @@ +{"pc":0,"op":96,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":96,"gas":"0x13495","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":4,"op":96,"gas":"0x13492","gasCost":"0x3","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":6,"op":96,"gas":"0x1348f","gasCost":"0x3","memSize":0,"stack":["0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":8,"op":0,"gas":"0x1348c","gasCost":"0x0","memSize":0,"stack":["0x40","0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0xc"} diff --git a/cmd/evm/testdata/31/txs.json b/cmd/evm/testdata/31/txs.json index 473c1526f..da8f5761f 100644 --- a/cmd/evm/testdata/31/txs.json +++ b/cmd/evm/testdata/31/txs.json @@ -10,5 +10,29 @@ "r" : "0x0", "s" : "0x0", "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + { + "gas": "0x186a0", + "gasPrice": "0x600", + "input": "0x", + "nonce": "0x1", + "to": "0x1111111111111111111111111111111111111111", + "value": "0x1", + "v" : "0x0", + "r" : "0x0", + "s" : "0x0", + "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + { + "gas": "0x186a0", + "gasPrice": "0x600", + "input": "0x", + "nonce": "0x2", + "to": "0x1111111111111111111111111111111111111111", + "value": "0x1", + "v" : "0x0", + "r" : "0x0", + "s" : "0x0", + "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" } ] diff --git a/core/vm/evm.go b/core/vm/evm.go index 1a0215459..1e52215b7 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -133,11 +133,6 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon return evm } -// SetTracer sets the tracer for following state transition. -func (evm *EVM) SetTracer(tracer *tracing.Hooks) { - evm.Config.Tracer = tracer -} - // SetPrecompiles sets the precompiled contracts for the EVM. // This method is only used through RPC calls. // It is not thread-safe. From 9997318c3e61bdb8133088730dabe8ba2421c449 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 21 Jan 2025 20:11:05 +0800 Subject: [PATCH 090/354] eth/filters: ensure API timeoutLoop terminates with event system (#31056) Discovered from failing test introduced https://github.com/ethereum/go-ethereum/pull/31033 . We should ensure `timeoutLoop` terminates if the filter event system is terminated. --- eth/filters/api.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index b8fcd376e..b39d0c52f 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -92,7 +92,11 @@ func (api *FilterAPI) timeoutLoop(timeout time.Duration) { ticker := time.NewTicker(timeout) defer ticker.Stop() for { - <-ticker.C + select { + case <-ticker.C: + case <-api.events.chainSub.Err(): + return + } api.filtersMu.Lock() for id, f := range api.filters { select { From 5933c69dc629cc047716d29848aa76a9a7276829 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 21 Jan 2025 15:02:17 -0700 Subject: [PATCH 091/354] cmd/evm: restore --bench flag to evm statetest (#31055) Refactoring of the `evm` command moved where some commands were valid. One command, `--bench`, used to work in `evm statetest`. The pluming is still in place. This PR puts the `--bench` flag in the place the trace flags were moved, and adds tests to validate the bench flag operates in `run` and `statetest` --------- Co-authored-by: Felix Lange --- cmd/evm/staterunner.go | 1 + cmd/evm/t8n_test.go | 56 ++++++++++++++++++++++++++++ cmd/evm/testdata/evmrun/10.out.1.txt | 15 ++++++++ cmd/evm/testdata/evmrun/10.out.2.txt | 0 cmd/evm/testdata/evmrun/9.out.1.txt | 0 cmd/evm/testdata/evmrun/9.out.2.txt | 4 ++ 6 files changed, 76 insertions(+) create mode 100644 cmd/evm/testdata/evmrun/10.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/10.out.2.txt create mode 100644 cmd/evm/testdata/evmrun/9.out.1.txt create mode 100644 cmd/evm/testdata/evmrun/9.out.2.txt diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 4c2dfeabc..8f81a9531 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -51,6 +51,7 @@ var stateTestCommand = &cli.Command{ Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).", ArgsUsage: "", Flags: slices.Concat([]cli.Flag{ + BenchFlag, DumpFlag, HumanReadableFlag, RunFlag, diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 985dac968..46146be78 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -24,6 +24,7 @@ import ( "os" "path/filepath" "reflect" + "regexp" "strings" "testing" @@ -670,6 +671,61 @@ func TestEvmRun(t *testing.T) { } } +func TestEvmRunRegEx(t *testing.T) { + t.Parallel() + tt := cmdtest.NewTestCmd(t, nil) + for i, tc := range []struct { + input []string + wantStdout string + wantStderr string + }{ + { // json tracing + input: []string{"run", "--bench", "6040"}, + wantStdout: "./testdata/evmrun/9.out.1.txt", + wantStderr: "./testdata/evmrun/9.out.2.txt", + }, + { // statetest subcommand + input: []string{"statetest", "--bench", "./testdata/statetest.json"}, + wantStdout: "./testdata/evmrun/10.out.1.txt", + wantStderr: "./testdata/evmrun/10.out.2.txt", + }, + } { + tt.Logf("args: go run ./cmd/evm %v\n", strings.Join(tc.input, " ")) + tt.Run("evm-test", tc.input...) + + haveStdOut := tt.Output() + tt.WaitExit() + haveStdErr := tt.StderrText() + + if have, wantFile := haveStdOut, tc.wantStdout; wantFile != "" { + want, err := os.ReadFile(wantFile) + if err != nil { + t.Fatalf("test %d: could not read expected output: %v", i, err) + } + re, err := regexp.Compile(string(want)) + if err != nil { + t.Fatalf("test %d: could not compile regular expression: %v", i, err) + } + if !re.Match(have) { + t.Fatalf("test %d, output wrong, have \n%v\nwant\n%v\n", i, string(have), re) + } + } + if have, wantFile := haveStdErr, tc.wantStderr; wantFile != "" { + want, err := os.ReadFile(wantFile) + if err != nil { + t.Fatalf("test %d: could not read expected output: %v", i, err) + } + re, err := regexp.Compile(string(want)) + if err != nil { + t.Fatalf("test %d: could not compile regular expression: %v", i, err) + } + if !re.MatchString(have) { + t.Fatalf("test %d, output wrong, have \n%v\nwant\n%v\n", i, have, re) + } + } + } +} + // cmpJson compares the JSON in two byte slices. func cmpJson(a, b []byte) (bool, error) { var j, j2 interface{} diff --git a/cmd/evm/testdata/evmrun/10.out.1.txt b/cmd/evm/testdata/evmrun/10.out.1.txt new file mode 100644 index 000000000..5f94bdd26 --- /dev/null +++ b/cmd/evm/testdata/evmrun/10.out.1.txt @@ -0,0 +1,15 @@ +\[ + \{ + "name": "00000006-naivefuzz-0", + "pass": false, + "stateRoot": "0xad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458", + "fork": "London", + "error": "post state root mismatch: got ad1024c87b5548e77c937aa50f72b6cb620d278f4dd79bae7f78f71ff75af458, want 0000000000000000000000000000000000000000000000000000000000000000", + "benchStats": \{ + "time": \d+, + "allocs": \d+, + "bytesAllocated": \d+, + "gasUsed": \d+ + \} + \} +\] \ No newline at end of file diff --git a/cmd/evm/testdata/evmrun/10.out.2.txt b/cmd/evm/testdata/evmrun/10.out.2.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/evm/testdata/evmrun/9.out.1.txt b/cmd/evm/testdata/evmrun/9.out.1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/evm/testdata/evmrun/9.out.2.txt b/cmd/evm/testdata/evmrun/9.out.2.txt new file mode 100644 index 000000000..90def283e --- /dev/null +++ b/cmd/evm/testdata/evmrun/9.out.2.txt @@ -0,0 +1,4 @@ +EVM gas used: \d+ +execution time: \d+\.\d+.s +allocations: \d+ +allocated bytes: \d+ From 4cd1d4c95278668418370b6a5abe8b2564ddbad1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 22 Jan 2025 09:29:34 +0100 Subject: [PATCH 092/354] p2p: support configuring NAT in TOML file (#31041) This is an alternative for #27407 with a solution based on gencodec. With the PR, one can now configure like this: ``` [Node.P2P] NAT = "extip:33.33.33.33" ``` ```shell $ geth --config config.toml ... INFO [01-17|16:37:31.436] Started P2P networking self=enode://2290...ab@33.33.33.33:30303 ``` --- go.mod | 2 +- go.sum | 4 +- p2p/config.go | 144 +++++++++++++++++++++++++++++++++++++++ p2p/config_toml.go | 165 +++++++++++++++++++++++++++++++++++++++++++++ p2p/nat/nat.go | 15 +++-- p2p/nat/natpmp.go | 4 ++ p2p/server.go | 99 --------------------------- 7 files changed, 326 insertions(+), 107 deletions(-) create mode 100644 p2p/config.go create mode 100644 p2p/config_toml.go diff --git a/go.mod b/go.mod index 69eef302e..5a4ba893b 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/ethereum/go-verkle v0.2.2 github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.3 - github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e + github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 diff --git a/go.sum b/go.sum index 96f1bb639..e64fe9d32 100644 --- a/go.sum +++ b/go.sum @@ -177,8 +177,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo= github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE= -github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= -github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4 h1:HhaRPDFEB1BrvBF+UCUnhyY9y5dtuBxy0myn+7sFjAw= +github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4/go.mod h1:Um1dFHPONZGTHog1qD1NaWjXJW/SPB38wPv0O8uZ2fI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= diff --git a/p2p/config.go b/p2p/config.go new file mode 100644 index 000000000..14492a2e5 --- /dev/null +++ b/p2p/config.go @@ -0,0 +1,144 @@ +// Copyright 2025 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 . +package p2p + +import ( + "crypto/ecdsa" + "fmt" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/p2p/netutil" +) + +//go:generate go run github.com/fjl/gencodec -type Config -field-override configMarshaling -formats toml -out config_toml.go + +// Config holds Server options. +type Config struct { + // This field must be set to a valid secp256k1 private key. + PrivateKey *ecdsa.PrivateKey `toml:"-"` + + // MaxPeers is the maximum number of peers that can be + // connected. It must be greater than zero. + MaxPeers int + + // MaxPendingPeers is the maximum number of peers that can be pending in the + // handshake phase, counted separately for inbound and outbound connections. + // Zero defaults to preset values. + MaxPendingPeers int `toml:",omitempty"` + + // DialRatio controls the ratio of inbound to dialed connections. + // Example: a DialRatio of 2 allows 1/2 of connections to be dialed. + // Setting DialRatio to zero defaults it to 3. + DialRatio int `toml:",omitempty"` + + // NoDiscovery can be used to disable the peer discovery mechanism. + // Disabling is useful for protocol debugging (manual topology). + NoDiscovery bool + + // DiscoveryV4 specifies whether V4 discovery should be started. + DiscoveryV4 bool `toml:",omitempty"` + + // DiscoveryV5 specifies whether the new topic-discovery based V5 discovery + // protocol should be started or not. + DiscoveryV5 bool `toml:",omitempty"` + + // Name sets the node name of this server. + Name string `toml:"-"` + + // BootstrapNodes are used to establish connectivity + // with the rest of the network. + BootstrapNodes []*enode.Node + + // BootstrapNodesV5 are used to establish connectivity + // with the rest of the network using the V5 discovery + // protocol. + BootstrapNodesV5 []*enode.Node `toml:",omitempty"` + + // Static nodes are used as pre-configured connections which are always + // maintained and re-connected on disconnects. + StaticNodes []*enode.Node + + // Trusted nodes are used as pre-configured connections which are always + // allowed to connect, even above the peer limit. + TrustedNodes []*enode.Node + + // Connectivity can be restricted to certain IP networks. + // If this option is set to a non-nil value, only hosts which match one of the + // IP networks contained in the list are considered. + NetRestrict *netutil.Netlist `toml:",omitempty"` + + // NodeDatabase is the path to the database containing the previously seen + // live nodes in the network. + NodeDatabase string `toml:",omitempty"` + + // Protocols should contain the protocols supported + // by the server. Matching protocols are launched for + // each peer. + Protocols []Protocol `toml:"-" json:"-"` + + // If ListenAddr is set to a non-nil address, the server + // will listen for incoming connections. + // + // If the port is zero, the operating system will pick a port. The + // ListenAddr field will be updated with the actual address when + // the server is started. + ListenAddr string + + // If DiscAddr is set to a non-nil value, the server will use ListenAddr + // for TCP and DiscAddr for the UDP discovery protocol. + DiscAddr string + + // If set to a non-nil value, the given NAT port mapper + // is used to make the listening port available to the + // Internet. + NAT nat.Interface `toml:",omitempty"` + + // If Dialer is set to a non-nil value, the given Dialer + // is used to dial outbound peer connections. + Dialer NodeDialer `toml:"-"` + + // If NoDial is true, the server will not dial any peers. + NoDial bool `toml:",omitempty"` + + // If EnableMsgEvents is set then the server will emit PeerEvents + // whenever a message is sent to or received from a peer + EnableMsgEvents bool + + // Logger is a custom logger to use with the p2p.Server. + Logger log.Logger `toml:"-"` + + clock mclock.Clock +} + +type configMarshaling struct { + NAT configNAT +} + +type configNAT struct { + nat.Interface +} + +func (w *configNAT) UnmarshalText(input []byte) error { + n, err := nat.Parse(string(input)) + if err != nil { + return fmt.Errorf("invalid NAT specification: %v", err) + } + w.Interface = n + return nil +} diff --git a/p2p/config_toml.go b/p2p/config_toml.go new file mode 100644 index 000000000..8a255e62f --- /dev/null +++ b/p2p/config_toml.go @@ -0,0 +1,165 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package p2p + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/nat" + "github.com/ethereum/go-ethereum/p2p/netutil" +) + +var _ = (*configMarshaling)(nil) + +// MarshalTOML marshals as TOML. +func (c Config) MarshalTOML() (interface{}, error) { + type Config struct { + PrivateKey *ecdsa.PrivateKey `toml:"-"` + MaxPeers int + MaxPendingPeers int `toml:",omitempty"` + DialRatio int `toml:",omitempty"` + NoDiscovery bool + DiscoveryV4 bool `toml:",omitempty"` + DiscoveryV5 bool `toml:",omitempty"` + Name string `toml:"-"` + BootstrapNodes []*enode.Node + BootstrapNodesV5 []*enode.Node `toml:",omitempty"` + StaticNodes []*enode.Node + TrustedNodes []*enode.Node + NetRestrict *netutil.Netlist `toml:",omitempty"` + NodeDatabase string `toml:",omitempty"` + Protocols []Protocol `toml:"-" json:"-"` + ListenAddr string + DiscAddr string + NAT nat.Interface `toml:",omitempty"` + Dialer NodeDialer `toml:"-"` + NoDial bool `toml:",omitempty"` + EnableMsgEvents bool + Logger log.Logger `toml:"-"` + } + var enc Config + enc.PrivateKey = c.PrivateKey + enc.MaxPeers = c.MaxPeers + enc.MaxPendingPeers = c.MaxPendingPeers + enc.DialRatio = c.DialRatio + enc.NoDiscovery = c.NoDiscovery + enc.DiscoveryV4 = c.DiscoveryV4 + enc.DiscoveryV5 = c.DiscoveryV5 + enc.Name = c.Name + enc.BootstrapNodes = c.BootstrapNodes + enc.BootstrapNodesV5 = c.BootstrapNodesV5 + enc.StaticNodes = c.StaticNodes + enc.TrustedNodes = c.TrustedNodes + enc.NetRestrict = c.NetRestrict + enc.NodeDatabase = c.NodeDatabase + enc.Protocols = c.Protocols + enc.ListenAddr = c.ListenAddr + enc.DiscAddr = c.DiscAddr + enc.NAT = c.NAT + enc.Dialer = c.Dialer + enc.NoDial = c.NoDial + enc.EnableMsgEvents = c.EnableMsgEvents + enc.Logger = c.Logger + return &enc, nil +} + +// UnmarshalTOML unmarshals from TOML. +func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { + type Config struct { + PrivateKey *ecdsa.PrivateKey `toml:"-"` + MaxPeers *int + MaxPendingPeers *int `toml:",omitempty"` + DialRatio *int `toml:",omitempty"` + NoDiscovery *bool + DiscoveryV4 *bool `toml:",omitempty"` + DiscoveryV5 *bool `toml:",omitempty"` + Name *string `toml:"-"` + BootstrapNodes []*enode.Node + BootstrapNodesV5 []*enode.Node `toml:",omitempty"` + StaticNodes []*enode.Node + TrustedNodes []*enode.Node + NetRestrict *netutil.Netlist `toml:",omitempty"` + NodeDatabase *string `toml:",omitempty"` + Protocols []Protocol `toml:"-" json:"-"` + ListenAddr *string + DiscAddr *string + NAT *configNAT `toml:",omitempty"` + Dialer NodeDialer `toml:"-"` + NoDial *bool `toml:",omitempty"` + EnableMsgEvents *bool + Logger log.Logger `toml:"-"` + } + var dec Config + if err := unmarshal(&dec); err != nil { + return err + } + if dec.PrivateKey != nil { + c.PrivateKey = dec.PrivateKey + } + if dec.MaxPeers != nil { + c.MaxPeers = *dec.MaxPeers + } + if dec.MaxPendingPeers != nil { + c.MaxPendingPeers = *dec.MaxPendingPeers + } + if dec.DialRatio != nil { + c.DialRatio = *dec.DialRatio + } + if dec.NoDiscovery != nil { + c.NoDiscovery = *dec.NoDiscovery + } + if dec.DiscoveryV4 != nil { + c.DiscoveryV4 = *dec.DiscoveryV4 + } + if dec.DiscoveryV5 != nil { + c.DiscoveryV5 = *dec.DiscoveryV5 + } + if dec.Name != nil { + c.Name = *dec.Name + } + if dec.BootstrapNodes != nil { + c.BootstrapNodes = dec.BootstrapNodes + } + if dec.BootstrapNodesV5 != nil { + c.BootstrapNodesV5 = dec.BootstrapNodesV5 + } + if dec.StaticNodes != nil { + c.StaticNodes = dec.StaticNodes + } + if dec.TrustedNodes != nil { + c.TrustedNodes = dec.TrustedNodes + } + if dec.NetRestrict != nil { + c.NetRestrict = dec.NetRestrict + } + if dec.NodeDatabase != nil { + c.NodeDatabase = *dec.NodeDatabase + } + if dec.Protocols != nil { + c.Protocols = dec.Protocols + } + if dec.ListenAddr != nil { + c.ListenAddr = *dec.ListenAddr + } + if dec.DiscAddr != nil { + c.DiscAddr = *dec.DiscAddr + } + if dec.NAT != nil { + c.NAT = dec.NAT + } + if dec.Dialer != nil { + c.Dialer = dec.Dialer + } + if dec.NoDial != nil { + c.NoDial = *dec.NoDial + } + if dec.EnableMsgEvents != nil { + c.EnableMsgEvents = *dec.EnableMsgEvents + } + if dec.Logger != nil { + c.Logger = dec.Logger + } + return nil +} diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index c65604426..f7fe8196c 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -133,8 +133,9 @@ func Map(m Interface, c <-chan struct{}, protocol string, extport, intport int, // Mapping operations will not return an error but won't actually do anything. type ExtIP net.IP -func (n ExtIP) ExternalIP() (net.IP, error) { return net.IP(n), nil } -func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) } +func (n ExtIP) ExternalIP() (net.IP, error) { return net.IP(n), nil } +func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) } +func (n ExtIP) MarshalText() ([]byte, error) { return []byte(fmt.Sprintf("extip:%v", net.IP(n))), nil } // These do nothing. @@ -148,7 +149,7 @@ func (ExtIP) DeleteMapping(string, int, int) error { return nil } func Any() Interface { // TODO: attempt to discover whether the local machine has an // Internet-class address. Return ExtIP in this case. - return startautodisc("UPnP or NAT-PMP", func() Interface { + return startautodisc("any", func() Interface { found := make(chan Interface, 2) go func() { found <- discoverUPnP() }() go func() { found <- discoverPMP() }() @@ -164,7 +165,7 @@ func Any() Interface { // UPnP returns a port mapper that uses UPnP. It will attempt to // discover the address of your router using UDP broadcasts. func UPnP() Interface { - return startautodisc("UPnP", discoverUPnP) + return startautodisc("upnp", discoverUPnP) } // PMP returns a port mapper that uses NAT-PMP. The provided gateway @@ -174,7 +175,7 @@ func PMP(gateway net.IP) Interface { if gateway != nil { return &pmp{gw: gateway, c: natpmp.NewClient(gateway)} } - return startautodisc("NAT-PMP", discoverPMP) + return startautodisc("natpmp", discoverPMP) } // autodisc represents a port mapping mechanism that is still being @@ -228,6 +229,10 @@ func (n *autodisc) String() string { return n.found.String() } +func (n *autodisc) MarshalText() ([]byte, error) { + return []byte(n.what), nil +} + // wait blocks until auto-discovery has been performed. func (n *autodisc) wait() error { n.once.Do(func() { diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 94ef1f4b6..b8f59ee89 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -70,6 +70,10 @@ func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) { return err } +func (n *pmp) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("natpmp:%v", n.gw)), nil +} + func discoverPMP() Interface { // run external address lookups on all potential gateways gws := potentialGateways() diff --git a/p2p/server.go b/p2p/server.go index 172f0667e..c1564352e 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" ) @@ -72,104 +71,6 @@ var ( errProtoHandshakeError = errors.New("rlpx proto error") ) -// Config holds Server options. -type Config struct { - // This field must be set to a valid secp256k1 private key. - PrivateKey *ecdsa.PrivateKey `toml:"-"` - - // MaxPeers is the maximum number of peers that can be - // connected. It must be greater than zero. - MaxPeers int - - // MaxPendingPeers is the maximum number of peers that can be pending in the - // handshake phase, counted separately for inbound and outbound connections. - // Zero defaults to preset values. - MaxPendingPeers int `toml:",omitempty"` - - // DialRatio controls the ratio of inbound to dialed connections. - // Example: a DialRatio of 2 allows 1/2 of connections to be dialed. - // Setting DialRatio to zero defaults it to 3. - DialRatio int `toml:",omitempty"` - - // NoDiscovery can be used to disable the peer discovery mechanism. - // Disabling is useful for protocol debugging (manual topology). - NoDiscovery bool - - // DiscoveryV4 specifies whether V4 discovery should be started. - DiscoveryV4 bool `toml:",omitempty"` - - // DiscoveryV5 specifies whether the new topic-discovery based V5 discovery - // protocol should be started or not. - DiscoveryV5 bool `toml:",omitempty"` - - // Name sets the node name of this server. - Name string `toml:"-"` - - // BootstrapNodes are used to establish connectivity - // with the rest of the network. - BootstrapNodes []*enode.Node - - // BootstrapNodesV5 are used to establish connectivity - // with the rest of the network using the V5 discovery - // protocol. - BootstrapNodesV5 []*enode.Node `toml:",omitempty"` - - // Static nodes are used as pre-configured connections which are always - // maintained and re-connected on disconnects. - StaticNodes []*enode.Node - - // Trusted nodes are used as pre-configured connections which are always - // allowed to connect, even above the peer limit. - TrustedNodes []*enode.Node - - // Connectivity can be restricted to certain IP networks. - // If this option is set to a non-nil value, only hosts which match one of the - // IP networks contained in the list are considered. - NetRestrict *netutil.Netlist `toml:",omitempty"` - - // NodeDatabase is the path to the database containing the previously seen - // live nodes in the network. - NodeDatabase string `toml:",omitempty"` - - // Protocols should contain the protocols supported - // by the server. Matching protocols are launched for - // each peer. - Protocols []Protocol `toml:"-" json:"-"` - - // If ListenAddr is set to a non-nil address, the server - // will listen for incoming connections. - // - // If the port is zero, the operating system will pick a port. The - // ListenAddr field will be updated with the actual address when - // the server is started. - ListenAddr string - - // If DiscAddr is set to a non-nil value, the server will use ListenAddr - // for TCP and DiscAddr for the UDP discovery protocol. - DiscAddr string - - // If set to a non-nil value, the given NAT port mapper - // is used to make the listening port available to the - // Internet. - NAT nat.Interface `toml:",omitempty"` - - // If Dialer is set to a non-nil value, the given Dialer - // is used to dial outbound peer connections. - Dialer NodeDialer `toml:"-"` - - // If NoDial is true, the server will not dial any peers. - NoDial bool `toml:",omitempty"` - - // If EnableMsgEvents is set then the server will emit PeerEvents - // whenever a message is sent to or received from a peer - EnableMsgEvents bool - - // Logger is a custom logger to use with the p2p.Server. - Logger log.Logger `toml:",omitempty"` - - clock mclock.Clock -} - // Server manages all peer connections. type Server struct { // Config fields may not be modified while the server is running. From e4da857815ff19c18199dc4643b2a9ba8e6324a6 Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 22 Jan 2025 12:53:01 +0000 Subject: [PATCH 093/354] go.mod: gencodec stable v0.1.0 (#31062) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5a4ba893b..0f3327386 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/ethereum/go-verkle v0.2.2 github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.3 - github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4 + github.com/fjl/gencodec v0.1.0 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 diff --git a/go.sum b/go.sum index e64fe9d32..fa4dab0c5 100644 --- a/go.sum +++ b/go.sum @@ -177,8 +177,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo= github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE= -github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4 h1:HhaRPDFEB1BrvBF+UCUnhyY9y5dtuBxy0myn+7sFjAw= -github.com/fjl/gencodec v0.0.0-20250117152317-bc3e1c7619d4/go.mod h1:Um1dFHPONZGTHog1qD1NaWjXJW/SPB38wPv0O8uZ2fI= +github.com/fjl/gencodec v0.1.0 h1:B3K0xPfc52cw52BBgUbSPxYo+HlLfAgWMVKRWXUXBcs= +github.com/fjl/gencodec v0.1.0/go.mod h1:Um1dFHPONZGTHog1qD1NaWjXJW/SPB38wPv0O8uZ2fI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= From 3971ed6f19311d3d5f59824913bd15bbef2d2df5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 22 Jan 2025 21:06:36 +0800 Subject: [PATCH 094/354] triedb/pathdb: fix state revert on v2 history (#31060) State history v2 has been shipped and will take effect after the Cancun fork. However, the state revert function does not differentiate between v1 and v2, instead blindly using the storage map key for state reversion. This mismatch between the keys of the live state set and the state history can trigger a panic: `non-existent storage slot for reverting`. This flaw has been fixed in this PR. --- triedb/pathdb/database_test.go | 43 +++++++++++++++++----------------- triedb/pathdb/disklayer.go | 22 ++++------------- triedb/pathdb/history.go | 41 ++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index f4b3fcec2..c85d7832e 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -73,10 +73,10 @@ const ( type genctx struct { stateRoot common.Hash - accounts map[common.Hash][]byte - storages map[common.Hash]map[common.Hash][]byte - accountOrigin map[common.Address][]byte - storageOrigin map[common.Address]map[common.Hash][]byte + accounts map[common.Hash][]byte // Keyed by the hash of account address + storages map[common.Hash]map[common.Hash][]byte // Keyed by the hash of account address and the hash of storage key + accountOrigin map[common.Address][]byte // Keyed by the account address + storageOrigin map[common.Address]map[common.Hash][]byte // Keyed by the account address and the hash of storage key nodes *trienode.MergedNodeSet } @@ -113,22 +113,23 @@ type tester struct { preimages map[common.Hash][]byte // current state set - accounts map[common.Hash][]byte - storages map[common.Hash]map[common.Hash][]byte + accounts map[common.Hash][]byte // Keyed by the hash of account address + storages map[common.Hash]map[common.Hash][]byte // Keyed by the hash of account address and the hash of storage key // state snapshots - snapAccounts map[common.Hash]map[common.Hash][]byte - snapStorages map[common.Hash]map[common.Hash]map[common.Hash][]byte + snapAccounts map[common.Hash]map[common.Hash][]byte // Keyed by the hash of account address + snapStorages map[common.Hash]map[common.Hash]map[common.Hash][]byte // Keyed by the hash of account address and the hash of storage key } -func newTester(t *testing.T, historyLimit uint64, isVerkle bool) *tester { +func newTester(t *testing.T, historyLimit uint64, isVerkle bool, layers int) *tester { var ( disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db = New(disk, &Config{ StateHistory: historyLimit, - CleanCacheSize: 16 * 1024, - WriteBufferSize: 16 * 1024, + CleanCacheSize: 256 * 1024, + WriteBufferSize: 256 * 1024, }, isVerkle) + obj = &tester{ db: db, preimages: make(map[common.Hash][]byte), @@ -138,7 +139,7 @@ func newTester(t *testing.T, historyLimit uint64, isVerkle bool) *tester { snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte), } ) - for i := 0; i < 12; i++ { + for i := 0; i < layers; i++ { var parent = types.EmptyRootHash if len(obj.roots) != 0 { parent = obj.roots[len(obj.roots)-1] @@ -264,11 +265,11 @@ func (t *tester) generate(parent common.Hash, rawStorageKey bool) (common.Hash, addr := testrand.Address() addrHash := crypto.Keccak256Hash(addr.Bytes()) - // short circuit if the account was already existent + // Short circuit if the account was already existent if _, ok := t.accounts[addrHash]; ok { continue } - // short circuit if the account has been modified within the same transition + // Short circuit if the account has been modified within the same transition if _, ok := dirties[addrHash]; ok { continue } @@ -448,7 +449,7 @@ func TestDatabaseRollback(t *testing.T) { }() // Verify state histories - tester := newTester(t, 0, false) + tester := newTester(t, 0, false, 32) defer tester.release() if err := tester.verifyHistory(); err != nil { @@ -482,7 +483,7 @@ func TestDatabaseRecoverable(t *testing.T) { }() var ( - tester = newTester(t, 0, false) + tester = newTester(t, 0, false, 12) index = tester.bottomIndex() ) defer tester.release() @@ -526,7 +527,7 @@ func TestDisable(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0, false) + tester := newTester(t, 0, false, 32) defer tester.release() stored := crypto.Keccak256Hash(rawdb.ReadAccountTrieNode(tester.db.diskdb, nil)) @@ -568,7 +569,7 @@ func TestCommit(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0, false) + tester := newTester(t, 0, false, 12) defer tester.release() if err := tester.db.Commit(tester.lastHash(), false); err != nil { @@ -598,7 +599,7 @@ func TestJournal(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0, false) + tester := newTester(t, 0, false, 12) defer tester.release() if err := tester.db.Journal(tester.lastHash()); err != nil { @@ -628,7 +629,7 @@ func TestCorruptedJournal(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 0, false) + tester := newTester(t, 0, false, 12) defer tester.release() if err := tester.db.Journal(tester.lastHash()); err != nil { @@ -676,7 +677,7 @@ func TestTailTruncateHistory(t *testing.T) { maxDiffLayers = 128 }() - tester := newTester(t, 10, false) + tester := newTester(t, 10, false, 12) defer tester.release() tester.db.Close() diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 5e678dbde..184f6430a 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -295,24 +295,6 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) { if dl.id == 0 { return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable) } - var ( - buff = crypto.NewKeccakState() - hashes = make(map[common.Address]common.Hash) - accounts = make(map[common.Hash][]byte) - storages = make(map[common.Hash]map[common.Hash][]byte) - ) - for addr, blob := range h.accounts { - hash := crypto.HashData(buff, addr.Bytes()) - hashes[addr] = hash - accounts[hash] = blob - } - for addr, storage := range h.storages { - hash, ok := hashes[addr] - if !ok { - panic(fmt.Errorf("storage history with no account %x", addr)) - } - storages[hash] = storage - } // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. @@ -320,6 +302,10 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) { if err != nil { return nil, err } + // Derive the state modification set from the history, keyed by the hash + // of the account address and the storage key. + accounts, storages := h.stateSet() + // Mark the diskLayer as stale before applying any mutations on top. dl.lock.Lock() defer dl.lock.Unlock() diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 9fb7d9e15..d8fb99ade 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "golang.org/x/exp/maps" @@ -68,8 +69,9 @@ const ( slotIndexSize = common.HashLength + 5 // The length of encoded slot index historyMetaSize = 9 + 2*common.HashLength // The length of encoded history meta - stateHistoryV0 = uint8(0) // initial version of state history structure - stateHistoryV1 = uint8(1) // use the storage slot raw key as the identifier instead of the key hash + stateHistoryV0 = uint8(0) // initial version of state history structure + stateHistoryV1 = uint8(1) // use the storage slot raw key as the identifier instead of the key hash + historyVersion = stateHistoryV1 // the default state history version ) // Each state history entry is consisted of five elements: @@ -258,9 +260,9 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map slices.SortFunc(slist, common.Hash.Cmp) storageList[addr] = slist } - version := stateHistoryV0 - if rawStorageKey { - version = stateHistoryV1 + version := historyVersion + if !rawStorageKey { + version = stateHistoryV0 } return &history{ meta: &meta{ @@ -276,6 +278,35 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map } } +// stateSet returns the state set, keyed by the hash of the account address +// and the hash of the storage slot key. +func (h *history) stateSet() (map[common.Hash][]byte, map[common.Hash]map[common.Hash][]byte) { + var ( + buff = crypto.NewKeccakState() + accounts = make(map[common.Hash][]byte) + storages = make(map[common.Hash]map[common.Hash][]byte) + ) + for addr, blob := range h.accounts { + addrHash := crypto.HashData(buff, addr.Bytes()) + accounts[addrHash] = blob + + storage, exist := h.storages[addr] + if !exist { + continue + } + if h.meta.version == stateHistoryV0 { + storages[addrHash] = storage + } else { + subset := make(map[common.Hash][]byte) + for key, slot := range storage { + subset[crypto.HashData(buff, key.Bytes())] = slot + } + storages[addrHash] = subset + } + } + return accounts, storages +} + // encode serializes the state history and returns four byte streams represent // concatenated account/storage data, account/storage indexes respectively. func (h *history) encode() ([]byte, []byte, []byte, []byte) { From 6eec3a93ce2ea74d376bb9aae2988022bad46415 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 23 Jan 2025 10:17:12 +0100 Subject: [PATCH 095/354] trie: reduce allocations in stacktrie (#30743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR uses various tweaks and tricks to make the stacktrie near alloc-free. ``` [user@work go-ethereum]$ benchstat stacktrie.1 stacktrie.7 goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/trie cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ stacktrie.1 │ stacktrie.7 │ │ sec/op │ sec/op vs base │ Insert100K-8 106.97m ± 8% 88.21m ± 34% -17.54% (p=0.000 n=10) │ stacktrie.1 │ stacktrie.7 │ │ B/op │ B/op vs base │ Insert100K-8 13199.608Ki ± 0% 3.424Ki ± 3% -99.97% (p=0.000 n=10) │ stacktrie.1 │ stacktrie.7 │ │ allocs/op │ allocs/op vs base │ Insert100K-8 553428.50 ± 0% 22.00 ± 5% -100.00% (p=0.000 n=10) ``` Also improves derivesha: ``` goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/types cpu: 12th Gen Intel(R) Core(TM) i7-1270P │ derivesha.1 │ derivesha.2 │ │ sec/op │ sec/op vs base │ DeriveSha200/stack_trie-8 477.8µ ± 2% 430.0µ ± 12% -10.00% (p=0.000 n=10) │ derivesha.1 │ derivesha.2 │ │ B/op │ B/op vs base │ DeriveSha200/stack_trie-8 45.17Ki ± 0% 25.65Ki ± 0% -43.21% (p=0.000 n=10) │ derivesha.1 │ derivesha.2 │ │ allocs/op │ allocs/op vs base │ DeriveSha200/stack_trie-8 1259.0 ± 0% 232.0 ± 0% -81.57% (p=0.000 n=10) ``` --------- Co-authored-by: Gary Rong --- trie/bytepool.go | 64 ++++++++++++++++++++++++++++++++++++ trie/encoding.go | 12 +++++++ trie/hasher.go | 8 +++++ trie/node.go | 35 ++++++++++++-------- trie/node_enc.go | 39 +++++++++++++++++++--- trie/stacktrie.go | 73 +++++++++++++++++++++++++++++------------- trie/stacktrie_test.go | 46 ++++++++++++++++++++++++++ 7 files changed, 238 insertions(+), 39 deletions(-) create mode 100644 trie/bytepool.go diff --git a/trie/bytepool.go b/trie/bytepool.go new file mode 100644 index 000000000..4f9c5672f --- /dev/null +++ b/trie/bytepool.go @@ -0,0 +1,64 @@ +// Copyright 2024 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 . + +package trie + +// bytesPool is a pool for byte slices. It is safe for concurrent use. +type bytesPool struct { + c chan []byte + w int +} + +// newBytesPool creates a new bytesPool. The sliceCap sets the capacity of +// newly allocated slices, and the nitems determines how many items the pool +// will hold, at maximum. +func newBytesPool(sliceCap, nitems int) *bytesPool { + return &bytesPool{ + c: make(chan []byte, nitems), + w: sliceCap, + } +} + +// Get returns a slice. Safe for concurrent use. +func (bp *bytesPool) Get() []byte { + select { + case b := <-bp.c: + return b + default: + return make([]byte, 0, bp.w) + } +} + +// GetWithSize returns a slice with specified byte slice size. +func (bp *bytesPool) GetWithSize(s int) []byte { + b := bp.Get() + if cap(b) < s { + return make([]byte, s) + } + return b[:s] +} + +// Put returns a slice to the pool. Safe for concurrent use. This method +// will ignore slices that are too small or too large (>3x the cap) +func (bp *bytesPool) Put(b []byte) { + if c := cap(b); c < bp.w || c > 3*bp.w { + return + } + select { + case bp.c <- b: + default: + } +} diff --git a/trie/encoding.go b/trie/encoding.go index 3284d3f8f..4cd29f531 100644 --- a/trie/encoding.go +++ b/trie/encoding.go @@ -104,6 +104,18 @@ func keybytesToHex(str []byte) []byte { return nibbles } +// writeHexKey writes the hexkey into the given slice. +// OBS! This method omits the termination flag. +// OBS! The dst slice must be at least 2x as large as the key +func writeHexKey(dst []byte, key []byte) []byte { + _ = dst[2*len(key)-1] + for i, b := range key { + dst[i*2] = b / 16 + dst[i*2+1] = b % 16 + } + return dst[:2*len(key)] +} + // hexToKeybytes turns hex nibbles into key bytes. // This can only be used for keys of even length. func hexToKeybytes(hex []byte) []byte { diff --git a/trie/hasher.go b/trie/hasher.go index abf654c70..28f7f3d0c 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -188,6 +188,14 @@ func (h *hasher) hashData(data []byte) hashNode { return n } +// hashDataTo hashes the provided data to the given destination buffer. The caller +// must ensure that the dst buffer is of appropriate size. +func (h *hasher) hashDataTo(dst, data []byte) { + h.sha.Reset() + h.sha.Write(data) + h.sha.Read(dst) +} + // proofHash is used to construct trie proofs, and returns the 'collapsed' // node (for later RLP encoding) as well as the hashed node -- unless the // node is smaller than 32 bytes, in which case it will be returned as is. diff --git a/trie/node.go b/trie/node.go index 15bbf62f1..ecc2de192 100644 --- a/trie/node.go +++ b/trie/node.go @@ -45,6 +45,27 @@ type ( } hashNode []byte valueNode []byte + + // fullnodeEncoder is a type used exclusively for encoding fullNode. + // Briefly instantiating a fullnodeEncoder and initializing with + // existing slices is less memory intense than using the fullNode type. + fullnodeEncoder struct { + Children [17][]byte + } + + // extNodeEncoder is a type used exclusively for encoding extension node. + // Briefly instantiating a extNodeEncoder and initializing with existing + // slices is less memory intense than using the shortNode type. + extNodeEncoder struct { + Key []byte + Val []byte + } + + // leafNodeEncoder is a type used exclusively for encoding leaf node. + leafNodeEncoder struct { + Key []byte + Val []byte + } ) // nilValueNode is used when collapsing internal trie nodes for hashing, since @@ -89,6 +110,7 @@ func (n *fullNode) fstring(ind string) string { } return resp + fmt.Sprintf("\n%s] ", ind) } + func (n *shortNode) fstring(ind string) string { return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" ")) } @@ -99,19 +121,6 @@ func (n valueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } -// rawNode is a simple binary blob used to differentiate between collapsed trie -// nodes and already encoded RLP binary blobs (while at the same time store them -// in the same cache fields). -type rawNode []byte - -func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } -func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } - -func (n rawNode) EncodeRLP(w io.Writer) error { - _, err := w.Write(n) - return err -} - // mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered. func mustDecodeNode(hash, buf []byte) node { n, err := decodeNode(hash, buf) diff --git a/trie/node_enc.go b/trie/node_enc.go index 1b2eca682..c95587eea 100644 --- a/trie/node_enc.go +++ b/trie/node_enc.go @@ -40,6 +40,20 @@ func (n *fullNode) encode(w rlp.EncoderBuffer) { w.ListEnd(offset) } +func (n *fullnodeEncoder) encode(w rlp.EncoderBuffer) { + offset := w.List() + for _, c := range n.Children { + if c == nil { + w.Write(rlp.EmptyString) + } else if len(c) < 32 { + w.Write(c) // rawNode + } else { + w.WriteBytes(c) // hashNode + } + } + w.ListEnd(offset) +} + func (n *shortNode) encode(w rlp.EncoderBuffer) { offset := w.List() w.WriteBytes(n.Key) @@ -51,6 +65,27 @@ func (n *shortNode) encode(w rlp.EncoderBuffer) { w.ListEnd(offset) } +func (n *extNodeEncoder) encode(w rlp.EncoderBuffer) { + offset := w.List() + w.WriteBytes(n.Key) + + if n.Val == nil { + w.Write(rlp.EmptyString) + } else if len(n.Val) < 32 { + w.Write(n.Val) // rawNode + } else { + w.WriteBytes(n.Val) // hashNode + } + w.ListEnd(offset) +} + +func (n *leafNodeEncoder) encode(w rlp.EncoderBuffer) { + offset := w.List() + w.WriteBytes(n.Key) // Compact format key + w.WriteBytes(n.Val) // Value node, must be non-nil + w.ListEnd(offset) +} + func (n hashNode) encode(w rlp.EncoderBuffer) { w.WriteBytes(n) } @@ -58,7 +93,3 @@ func (n hashNode) encode(w rlp.EncoderBuffer) { func (n valueNode) encode(w rlp.EncoderBuffer) { w.WriteBytes(n) } - -func (n rawNode) encode(w rlp.EncoderBuffer) { - w.Write(n) -} diff --git a/trie/stacktrie.go b/trie/stacktrie.go index d194cbf0a..2b7366c3c 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -27,6 +27,7 @@ import ( var ( stPool = sync.Pool{New: func() any { return new(stNode) }} + bPool = newBytesPool(32, 100) _ = types.TrieHasher((*StackTrie)(nil)) ) @@ -47,6 +48,8 @@ type StackTrie struct { h *hasher last []byte onTrieNode OnTrieNode + kBuf []byte // buf space used for hex-key during insertions + pBuf []byte // buf space used for path during insertions } // NewStackTrie allocates and initializes an empty trie. The committed nodes @@ -56,6 +59,17 @@ func NewStackTrie(onTrieNode OnTrieNode) *StackTrie { root: stPool.Get().(*stNode), h: newHasher(false), onTrieNode: onTrieNode, + kBuf: make([]byte, 64), + pBuf: make([]byte, 64), + } +} + +func (t *StackTrie) grow(key []byte) { + if cap(t.kBuf) < 2*len(key) { + t.kBuf = make([]byte, 2*len(key)) + } + if cap(t.pBuf) < 2*len(key) { + t.pBuf = make([]byte, 2*len(key)) } } @@ -64,7 +78,8 @@ func (t *StackTrie) Update(key, value []byte) error { if len(value) == 0 { return errors.New("trying to insert empty (deletion)") } - k := t.TrieKey(key) + t.grow(key) + k := writeHexKey(t.kBuf, key) if bytes.Compare(t.last, k) >= 0 { return errors.New("non-ascending key order") } @@ -73,7 +88,7 @@ func (t *StackTrie) Update(key, value []byte) error { } else { t.last = append(t.last[:0], k...) // reuse key slice } - t.insert(t.root, k, value, nil) + t.insert(t.root, k, value, t.pBuf[:0]) return nil } @@ -129,6 +144,12 @@ const ( ) func (n *stNode) reset() *stNode { + if n.typ == hashedNode { + // On hashnodes, we 'own' the val: it is guaranteed to be not held + // by external caller. Hence, when we arrive here, we can put it back + // into the pool + bPool.Put(n.val) + } n.key = n.key[:0] n.val = nil for i := range n.children { @@ -150,8 +171,12 @@ func (n *stNode) getDiffIndex(key []byte) int { return len(n.key) } -// Helper function to that inserts a (key, value) pair into -// the trie. +// Helper function to that inserts a (key, value) pair into the trie. +// +// - The key is not retained by this method, but always copied if needed. +// - The value is retained by this method, as long as the leaf that it represents +// remains unhashed. However: it is never modified. +// - The path is not retained by this method. func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { switch st.typ { case branchNode: /* Branch */ @@ -283,7 +308,7 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { case emptyNode: /* Empty */ st.typ = leafNode - st.key = key + st.key = append(st.key, key...) // deep-copy the key as it's volatile st.val = value case hashedNode: @@ -318,35 +343,33 @@ func (t *StackTrie) hash(st *stNode, path []byte) { return case branchNode: - var nodes fullNode + var nodes fullnodeEncoder for i, child := range st.children { if child == nil { - nodes.Children[i] = nilValueNode continue } t.hash(child, append(path, byte(i))) + nodes.Children[i] = child.val + } + nodes.encode(t.h.encbuf) + blob = t.h.encodedBytes() - if len(child.val) < 32 { - nodes.Children[i] = rawNode(child.val) - } else { - nodes.Children[i] = hashNode(child.val) + for i, child := range st.children { + if child == nil { + continue } st.children[i] = nil stPool.Put(child.reset()) // Release child back to pool. } - nodes.encode(t.h.encbuf) - blob = t.h.encodedBytes() case extNode: // recursively hash and commit child as the first step t.hash(st.children[0], append(path, st.key...)) // encode the extension node - n := shortNode{Key: hexToCompactInPlace(st.key)} - if len(st.children[0].val) < 32 { - n.Val = rawNode(st.children[0].val) - } else { - n.Val = hashNode(st.children[0].val) + n := extNodeEncoder{ + Key: hexToCompactInPlace(st.key), + Val: st.children[0].val, } n.encode(t.h.encbuf) blob = t.h.encodedBytes() @@ -356,8 +379,10 @@ func (t *StackTrie) hash(st *stNode, path []byte) { case leafNode: st.key = append(st.key, byte(16)) - n := shortNode{Key: hexToCompactInPlace(st.key), Val: valueNode(st.val)} - + n := leafNodeEncoder{ + Key: hexToCompactInPlace(st.key), + Val: st.val, + } n.encode(t.h.encbuf) blob = t.h.encodedBytes() @@ -368,15 +393,19 @@ func (t *StackTrie) hash(st *stNode, path []byte) { st.typ = hashedNode st.key = st.key[:0] + st.val = nil // Release reference to potentially externally held slice. + // Skip committing the non-root node if the size is smaller than 32 bytes // as tiny nodes are always embedded in their parent except root node. if len(blob) < 32 && len(path) > 0 { - st.val = common.CopyBytes(blob) + st.val = bPool.GetWithSize(len(blob)) + copy(st.val, blob) return } // Write the hash to the 'val'. We allocate a new val here to not mutate // input values. - st.val = t.h.hashData(blob) + st.val = bPool.GetWithSize(32) + t.h.hashDataTo(st.val, blob) // Invoke the callback it's provided. Notably, the path and blob slices are // volatile, please deep-copy the slices in callback if the contents need diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index f053b5112..7e342e64b 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + "encoding/binary" "math/big" "testing" @@ -398,3 +399,48 @@ func TestStackTrieErrors(t *testing.T) { assert.NotNil(t, s.Update([]byte{0x10}, []byte{0xb}), "out of order insert") assert.NotNil(t, s.Update([]byte{0xaa}, []byte{0xb}), "repeat insert same key") } + +func BenchmarkInsert100K(b *testing.B) { + var num = 100_000 + var key = make([]byte, 8) + var val = make([]byte, 20) + var hash common.Hash + b.ReportAllocs() + for i := 0; i < b.N; i++ { + s := NewStackTrie(nil) + var k uint64 + for j := 0; j < num; j++ { + binary.BigEndian.PutUint64(key, k) + if err := s.Update(key, val); err != nil { + b.Fatal(err) + } + k += 1024 + } + if hash == (common.Hash{}) { + hash = s.Hash() + } else { + if hash != s.Hash() && false { + b.Fatalf("hash wrong, have %x want %x", s.Hash(), hash) + } + } + } +} + +func TestInsert100K(t *testing.T) { + var num = 100_000 + var key = make([]byte, 8) + var val = make([]byte, 20) + s := NewStackTrie(nil) + var k uint64 + for j := 0; j < num; j++ { + binary.BigEndian.PutUint64(key, k) + if err := s.Update(key, val); err != nil { + t.Fatal(err) + } + k += 1024 + } + want := common.HexToHash("0xb0071bd257342925d9d8a9f002b9d2b646a35437aa8b089628ab56e428d29a1a") + if have := s.Hash(); have != want { + t.Fatalf("hash wrong, have %x want %x", have, want) + } +} From 314f0d195fe60c898dd43d807555b3b99e51256d Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:38:09 +0100 Subject: [PATCH 096/354] eth/catalyst: fail on duplicate request types (#31071) Refer to: https://github.com/ethereum/execution-apis/pull/623 --- eth/catalyst/api.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 781b6c73f..500500891 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -1303,7 +1303,8 @@ func validateRequests(requests [][]byte) error { return fmt.Errorf("empty request: %v", req) } // Check that requests are ordered by their type. - if req[0] < last { + // Each type must appear only once. + if req[0] <= last { return fmt.Errorf("invalid request order: %v", req) } last = req[0] From 78de5828ea19a57e0dde49d195bba4cf5bfb0201 Mon Sep 17 00:00:00 2001 From: Michael de Hoog Date: Thu, 23 Jan 2025 23:59:33 -1000 Subject: [PATCH 097/354] accounts/usbwallet: fix ledger access for latest firmware and add Ledger Flex (#31004) The latest firmware for Ledger Nano S Plus now returns `0x5000` for it's product ID, which doesn't match any of the product IDs enumerated in `hub.go`. This PR removes the assumption about the interfaces exposed, and simply checks the upper byte for a match. Also adds support for the `0x0007` / `0x7000` product ID (Ledger Flex). --- accounts/usbwallet/hub.go | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index e22dffe97..81457b7da 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -73,7 +73,7 @@ func NewLedgerHub() (*Hub, error) { return newHub(LedgerScheme, 0x2c97, []uint16{ // Device definitions taken from - // https://github.com/LedgerHQ/ledger-live/blob/38012bc8899e0f07149ea9cfe7e64b2c146bc92b/libs/ledgerjs/packages/devices/src/index.ts + // https://github.com/LedgerHQ/ledger-live/blob/595cb73b7e6622dbbcfc11867082ddc886f1bf01/libs/ledgerjs/packages/devices/src/index.ts // Original product IDs 0x0000, /* Ledger Blue */ @@ -81,18 +81,14 @@ func NewLedgerHub() (*Hub, error) { 0x0004, /* Ledger Nano X */ 0x0005, /* Ledger Nano S Plus */ 0x0006, /* Ledger Nano FTS */ - - 0x0015, /* HID + U2F + WebUSB Ledger Blue */ - 0x1015, /* HID + U2F + WebUSB Ledger Nano S */ - 0x4015, /* HID + U2F + WebUSB Ledger Nano X */ - 0x5015, /* HID + U2F + WebUSB Ledger Nano S Plus */ - 0x6015, /* HID + U2F + WebUSB Ledger Nano FTS */ - - 0x0011, /* HID + WebUSB Ledger Blue */ - 0x1011, /* HID + WebUSB Ledger Nano S */ - 0x4011, /* HID + WebUSB Ledger Nano X */ - 0x5011, /* HID + WebUSB Ledger Nano S Plus */ - 0x6011, /* HID + WebUSB Ledger Nano FTS */ + 0x0007, /* Ledger Flex */ + + 0x0000, /* WebUSB Ledger Blue */ + 0x1000, /* WebUSB Ledger Nano S */ + 0x4000, /* WebUSB Ledger Nano X */ + 0x5000, /* WebUSB Ledger Nano S Plus */ + 0x6000, /* WebUSB Ledger Nano FTS */ + 0x7000, /* WebUSB Ledger Flex */ }, 0xffa0, 0, newLedgerDriver) } @@ -185,8 +181,11 @@ func (hub *Hub) refreshWallets() { for _, info := range infos { for _, id := range hub.productIDs { + // We check both the raw ProductID (legacy) and just the upper byte, as Ledger + // uses `MMII`, encoding a model (MM) and an interface bitfield (II) + mmOnly := info.ProductID & 0xff00 // Windows and Macos use UsageID matching, Linux uses Interface matching - if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { + if (info.ProductID == id || mmOnly == id) && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { devices = append(devices, info) break } From d4f8dcb05d06a60ccfda71346765915924da4fc5 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 24 Jan 2025 15:38:17 +0100 Subject: [PATCH 098/354] core/vm: implement EIP-2537 spec updates (#30978) Reference: - Remove MUL precompiles: https://github.com/ethereum/EIPs/pull/8945 - Pricing change for pairing operation: https://github.com/ethereum/EIPs/pull/9098 - Pricing change for add, mapping and mul operations: https://github.com/ethereum/EIPs/pull/9097 - Pricing change for MSM operations: https://github.com/ethereum/EIPs/pull/9116 --------- Co-authored-by: Marius van der Wijden --- tests/fuzzers/bls12381/bls12381_fuzz.go | 50 ------------------------- tests/fuzzers/bls12381/bls12381_test.go | 24 ------------ tests/state_test.go | 4 ++ 3 files changed, 4 insertions(+), 74 deletions(-) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index a3e0e9f72..9efc6f596 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -225,56 +225,6 @@ func fuzzCrossG1MultiExp(data []byte) int { return 1 } -func fuzzCrossG1Mul(data []byte) int { - input := bytes.NewReader(data) - gp, blpAffine, err := getG1Points(input) - if err != nil { - return 0 - } - scalar, err := randomScalar(input, fp.Modulus()) - if err != nil { - return 0 - } - - blScalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(scalar.Bytes(), 32)) - - blp := new(blst.P1) - blp.FromAffine(blpAffine) - - resBl := blp.Mult(blScalar) - resGeth := (new(gnark.G1Affine)).ScalarMultiplication(gp, scalar) - - if !bytes.Equal(resGeth.Marshal(), resBl.Serialize()) { - panic("bytes(blst.G1) != bytes(geth.G1)") - } - return 1 -} - -func fuzzCrossG2Mul(data []byte) int { - input := bytes.NewReader(data) - gp, blpAffine, err := getG2Points(input) - if err != nil { - return 0 - } - scalar, err := randomScalar(input, fp.Modulus()) - if err != nil { - return 0 - } - - blScalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(scalar.Bytes(), 32)) - - blp := new(blst.P2) - blp.FromAffine(blpAffine) - - resBl := blp.Mult(blScalar) - resGeth := (new(gnark.G2Affine)).ScalarMultiplication(gp, scalar) - - if !bytes.Equal(resGeth.Marshal(), resBl.Serialize()) { - panic("bytes(blst.G1) != bytes(geth.G1)") - } - return 1 -} - func fuzzCrossG2MultiExp(data []byte) int { var ( input = bytes.NewReader(data) diff --git a/tests/fuzzers/bls12381/bls12381_test.go b/tests/fuzzers/bls12381/bls12381_test.go index d4e5e20e0..cb89d8a7a 100644 --- a/tests/fuzzers/bls12381/bls12381_test.go +++ b/tests/fuzzers/bls12381/bls12381_test.go @@ -57,12 +57,6 @@ func FuzzG1Add(f *testing.F) { }) } -func FuzzCrossG1Mul(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - fuzzCrossG1Mul(data) - }) -} - func FuzzG1MultiExp(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { fuzz(blsG1MultiExp, data) @@ -75,12 +69,6 @@ func FuzzG2Add(f *testing.F) { }) } -func FuzzCrossG2Mul(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - fuzzCrossG2Mul(data) - }) -} - func FuzzG2MultiExp(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { fuzz(blsG2MultiExp, data) @@ -116,15 +104,3 @@ func FuzzG2SubgroupChecks(f *testing.F) { fuzzG2SubgroupChecks(data) }) } - -func FuzzG2Mul(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - fuzz(blsG2Mul, data) - }) -} - -func FuzzG1Mul(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - fuzz(blsG1Mul, data) - }) -} diff --git a/tests/state_test.go b/tests/state_test.go index 7b82b05e5..da4b8ef79 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -54,6 +54,10 @@ func initMatcher(st *testMatcher) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) + // Out-of-date EIP-2537 tests + // TODO (@s1na) reenable in the future + st.skipLoad(`^stEIP2537/`) + // Broken tests: // EOF is not part of cancun st.skipLoad(`^stEOF/`) From d3382e88080431d9efda7672659bc99689195451 Mon Sep 17 00:00:00 2001 From: zhen peng <505380967@qq.com> Date: Fri, 24 Jan 2025 23:16:02 +0800 Subject: [PATCH 099/354] p2p/nat: add stun protocol (#31064) This implements a basic mechanism to query the node's external IP using a STUN server. There is a built-in list of public STUN servers for convenience. The new detection mechanism must be selected explicitly using `--nat=stun` and is not enabled by default in Geth. Fixes #30881 --------- Co-authored-by: Felix Lange --- cmd/utils/flags.go | 2 +- go.mod | 5 ++ go.sum | 33 +++++++++ p2p/nat/nat.go | 7 +- p2p/nat/nat_test.go | 23 ++++++ p2p/nat/stun-list-update.sh | 5 ++ p2p/nat/stun-list.txt | 96 ++++++++++++++++++++++++ p2p/nat/stun.go | 144 ++++++++++++++++++++++++++++++++++++ p2p/nat/stun_test.go | 40 ++++++++++ 9 files changed, 353 insertions(+), 2 deletions(-) create mode 100755 p2p/nat/stun-list-update.sh create mode 100644 p2p/nat/stun-list.txt create mode 100644 p2p/nat/stun.go create mode 100644 p2p/nat/stun_test.go diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e994de0b1..8c27c859d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -850,7 +850,7 @@ var ( } NATFlag = &cli.StringFlag{ Name: "nat", - Usage: "NAT port mapping mechanism (any|none|upnp|pmp|pmp:|extip:)", + Usage: "NAT port mapping mechanism (any|none|upnp|pmp|pmp:|extip:|stun:)", Value: "any", Category: flags.NetworkingCategory, } diff --git a/go.mod b/go.mod index 0f3327386..d623ed33a 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( github.com/nspcc-dev/dbft v0.3.2 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 + github.com/pion/stun/v2 v2.0.0 github.com/protolambda/bls12-381-util v0.1.0 github.com/protolambda/zrnt v0.32.2 github.com/protolambda/ztyp v0.2.2 @@ -134,6 +135,10 @@ require ( github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/pion/dtls/v2 v2.2.7 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/transport/v2 v2.2.1 // indirect + github.com/pion/transport/v3 v3.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/go.sum b/go.sum index fa4dab0c5..0edf4f4c2 100644 --- a/go.sum +++ b/go.sum @@ -440,6 +440,16 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQm github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -508,11 +518,17 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= @@ -567,6 +583,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -602,6 +620,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -642,6 +661,10 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -663,6 +686,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -725,6 +749,7 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -734,6 +759,10 @@ golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -743,6 +772,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -795,6 +827,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index f7fe8196c..5f7af7424 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -59,13 +59,16 @@ type Interface interface { // "upnp" uses the Universal Plug and Play protocol // "pmp" uses NAT-PMP with an auto-detected gateway address // "pmp:192.168.0.1" uses NAT-PMP with the given gateway address +// "stun" uses stun protocol with default stun server +// "stun:192.168.0.1:1234" uses stun protocol with stun server address 192.168.0.1:1234 func Parse(spec string) (Interface, error) { var ( before, after, found = strings.Cut(spec, ":") mech = strings.ToLower(before) ip net.IP ) - if found { + // stun is not a valid ip + if found && mech != "stun" { ip = net.ParseIP(after) if ip == nil { return nil, errors.New("invalid IP address") @@ -85,6 +88,8 @@ func Parse(spec string) (Interface, error) { return UPnP(), nil case "pmp", "natpmp", "nat-pmp": return PMP(ip), nil + case "stun": + return newSTUN(after) default: return nil, fmt.Errorf("unknown mechanism %q", before) } diff --git a/p2p/nat/nat_test.go b/p2p/nat/nat_test.go index 814e6d9e1..8dd5644fd 100644 --- a/p2p/nat/nat_test.go +++ b/p2p/nat/nat_test.go @@ -18,8 +18,11 @@ package nat import ( "net" + "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) // This test checks that autodisc doesn't hang and returns @@ -61,3 +64,23 @@ func TestAutoDiscRace(t *testing.T) { } } } + +// stun should work well +func TestParseStun(t *testing.T) { + testcases := []struct { + natStr string + want *stun + }{ + {"stun", &stun{serverList: strings.Split(stunDefaultServers, "\n")}}, + {"stun:1.2.3.4:1234", &stun{serverList: []string{"1.2.3.4:1234"}}}, + } + + for _, tc := range testcases { + nat, err := Parse(tc.natStr) + if err != nil { + t.Errorf("should no err, but get %v", err) + } + stun := nat.(*stun) + assert.Equal(t, stun.serverList, tc.want.serverList) + } +} diff --git a/p2p/nat/stun-list-update.sh b/p2p/nat/stun-list-update.sh new file mode 100755 index 000000000..901bfe4ba --- /dev/null +++ b/p2p/nat/stun-list-update.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +rm -f stun-list.txt +curl https://raw.githubusercontent.com/pradt2/always-online-stun/refs/heads/master/valid_ipv4s.txt | sort -n >> stun-list.txt +curl https://raw.githubusercontent.com/pradt2/always-online-stun/refs/heads/master/valid_ipv6s.txt | sort -n >> stun-list.txt diff --git a/p2p/nat/stun-list.txt b/p2p/nat/stun-list.txt new file mode 100644 index 000000000..bc27f7e5a --- /dev/null +++ b/p2p/nat/stun-list.txt @@ -0,0 +1,96 @@ +3.132.228.249:3478 +3.78.237.53:3478 +5.161.52.174:3478 +5.161.57.75:3478 +18.185.125.152:3478 +20.93.239.167:3478 +23.21.199.62:3478 +23.21.92.55:3478 +24.204.48.11:3478 +31.184.236.23:3478 +34.195.177.19:3478 +34.197.205.39:3478 +34.206.168.53:3478 +34.74.124.204:3478 +35.158.233.7:3478 +35.177.202.92:3478 +35.180.81.93:3478 +44.230.252.214:3478 +45.15.102.34:3478 +49.12.125.53:3478 +51.255.31.35:3478 +51.68.112.203:3478 +51.68.45.75:3478 +51.83.15.212:3478 +51.83.201.84:3478 +52.24.174.49:3478 +52.26.251.34:3478 +52.47.70.236:3478 +52.52.70.85:3478 +54.197.117.0:3478 +62.72.83.10:3478 +66.228.54.23:3478 +69.20.59.115:3478 +79.140.42.88:3478 +80.155.54.123:3478 +80.156.214.187:3478 +81.3.27.44:3478 +81.82.206.117:3478 +81.83.12.46:3478 +85.197.87.182:3478 +87.253.140.133:3478 +88.198.151.128:3478 +88.218.220.40:3478 +88.99.67.241:3478 +90.145.158.66:3478 +91.212.41.85:3478 +92.205.106.161:3478 +94.140.180.141:3478 +94.23.17.185:3478 +95.216.145.84:3478 +95.216.78.222:3478 +129.153.212.128:3478 +136.243.59.79:3478 +137.74.112.113:3478 +143.198.60.79:3478 +147.182.188.245:3478 +157.161.10.32:3478 +159.69.191.124:3478 +159.69.191.124:443 +172.233.245.118:3478 +176.9.24.184:3478 +185.125.180.70:3478 +185.88.236.76:3478 +188.138.90.169:3478 +188.40.18.246:3478 +188.40.203.74:3478 +192.172.233.145:3478 +192.76.120.66:3478 +193.182.111.151:3478 +193.22.17.97:3478 +194.149.74.157:3478 +195.145.93.141:3478 +195.201.132.113:3478 +195.208.107.138:3478 +198.100.144.121:3478 +209.251.63.76:3478 +212.103.68.7:3478 +212.144.246.197:3478 +212.18.0.14:3478 +212.53.40.40:3478 +212.53.40.43:3478 +213.239.206.5:3478 +213.251.48.147:3478 +217.146.224.74:3478 +217.91.243.229:3478 +[2001:1538:1::224:74]:3478 +[2001:4060:1:1005::10:32]:3478 +[2001:4060:1:1005::10:32]:3478 +[2001:41d0:2:12b9::1]:3478 +[2001:678:b28::118]:3478 +[2600:1f16:8c5:101:80b:b58b:828:8df4]:3478 +[2a00:1169:11b:a6b0::]:3478 +[2a01:4f8:242:56ca::2]:3478 +[2a01:4f8:c17:8f74::1]:3478 +[2a01:4f8:c17:8f74::1]:443 +[2a03:8600::89]:3478 diff --git a/p2p/nat/stun.go b/p2p/nat/stun.go new file mode 100644 index 000000000..36d54398b --- /dev/null +++ b/p2p/nat/stun.go @@ -0,0 +1,144 @@ +// Copyright 2025 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 . + +package nat + +import ( + _ "embed" + "errors" + "fmt" + "math/rand" + "net" + "strings" + "time" + + "github.com/ethereum/go-ethereum/log" + stunV2 "github.com/pion/stun/v2" +) + +//go:embed stun-list.txt +var stunDefaultServers string + +const requestLimit = 3 + +var errSTUNFailed = errors.New("STUN requests failed") + +type stun struct { + serverList []string +} + +func newSTUN(serverAddr string) (Interface, error) { + s := new(stun) + if serverAddr == "" { + s.serverList = strings.Split(stunDefaultServers, "\n") + } else { + _, err := net.ResolveUDPAddr("udp4", serverAddr) + if err != nil { + return nil, err + } + s.serverList = []string{serverAddr} + } + return s, nil +} + +func (s stun) String() string { + if len(s.serverList) == 1 { + return fmt.Sprintf("stun:%s", s.serverList[0]) + } + return "stun" +} + +func (s stun) MarshalText() ([]byte, error) { + return []byte(s.String()), nil +} + +func (stun) SupportsMapping() bool { + return false +} + +func (stun) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { + return uint16(extport), nil +} + +func (stun) DeleteMapping(string, int, int) error { + return nil +} + +func (s *stun) ExternalIP() (net.IP, error) { + for _, server := range s.randomServers(requestLimit) { + ip, err := s.externalIP(server) + if err != nil { + log.Debug("STUN request failed", "server", server, "err", err) + continue + } + return ip, nil + } + return nil, errSTUNFailed +} + +func (s *stun) randomServers(n int) []string { + n = min(n, len(s.serverList)) + m := make(map[int]struct{}, n) + list := make([]string, 0, n) + for i := 0; i < len(s.serverList)*2 && len(list) < n; i++ { + index := rand.Intn(len(s.serverList)) + if _, alreadyHit := m[index]; alreadyHit { + continue + } + list = append(list, s.serverList[index]) + m[index] = struct{}{} + } + return list +} + +func (s *stun) externalIP(server string) (net.IP, error) { + _, _, err := net.SplitHostPort(server) + if err != nil { + server += fmt.Sprintf(":%d", stunV2.DefaultPort) + } + + log.Trace("Attempting STUN binding request", "server", server) + conn, err := stunV2.Dial("udp4", server) + if err != nil { + return nil, err + } + defer conn.Close() + + message, err := stunV2.Build(stunV2.TransactionID, stunV2.BindingRequest) + if err != nil { + return nil, err + } + + var responseError error + var mappedAddr stunV2.XORMappedAddress + err = conn.Do(message, func(event stunV2.Event) { + if event.Error != nil { + responseError = event.Error + return + } + if err := mappedAddr.GetFrom(event.Message); err != nil { + responseError = err + } + }) + if err != nil { + return nil, err + } + if responseError != nil { + return nil, responseError + } + log.Trace("STUN returned IP", "server", server, "ip", mappedAddr.IP) + return mappedAddr.IP, nil +} diff --git a/p2p/nat/stun_test.go b/p2p/nat/stun_test.go new file mode 100644 index 000000000..b5f429986 --- /dev/null +++ b/p2p/nat/stun_test.go @@ -0,0 +1,40 @@ +// Copyright 2025 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 . + +package nat + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNatStun(t *testing.T) { + nat, err := newSTUN("") + assert.NoError(t, err) + _, err = nat.ExternalIP() + assert.NoError(t, err) +} + +func TestUnreachedNatServer(t *testing.T) { + stun := &stun{ + serverList: []string{"198.51.100.2:1234", "198.51.100.5"}, + } + _, err := stun.ExternalIP() + if err != errSTUNFailed { + t.Fatal("wrong error:", err) + } +} From f76e71d1612d3e7c5bb55ac6a97df0aeade2c769 Mon Sep 17 00:00:00 2001 From: Christina <156356273+cratiu222@users.noreply.github.com> Date: Sun, 26 Jan 2025 01:53:14 +0200 Subject: [PATCH 100/354] fix README.md (#31076) Hi I fixed 2 minor spelling issues. --------- Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4867e0ca..dcd99cfc7 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,7 @@ HTTP based JSON-RPC API options: * `--http.addr` HTTP-RPC server listening interface (default: `localhost`) * `--http.port` HTTP-RPC server listening port (default: `8545`) * `--http.api` API's offered over the HTTP-RPC interface (default: `eth,net,web3`) - * `--http.corsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced) + * `--http.corsdomain` Comma separated list of domains from which to accept cross-origin requests (browser enforced) * `--ws` Enable the WS-RPC server * `--ws.addr` WS-RPC server listening interface (default: `localhost`) * `--ws.port` WS-RPC server listening port (default: `8546`) From 633d38fc1e6e1f21e0d6a9c93b3fcd5b5b946766 Mon Sep 17 00:00:00 2001 From: Christina <156356273+cratiu222@users.noreply.github.com> Date: Tue, 28 Jan 2025 17:56:23 +0200 Subject: [PATCH 101/354] chore: fix various comments (#31082) --- core/vm/eof_validation_test.go | 2 +- tests/fuzzers/bls12381/bls12381_fuzz.go | 2 +- triedb/pathdb/database.go | 4 ++-- triedb/pathdb/difflayer.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/vm/eof_validation_test.go b/core/vm/eof_validation_test.go index afb856a32..f7b0e78f2 100644 --- a/core/vm/eof_validation_test.go +++ b/core/vm/eof_validation_test.go @@ -363,7 +363,7 @@ func BenchmarkEOFValidation(b *testing.B) { } } -// BenchmarkEOFValidation tries to benchmark the code validation for the CALLF/RETF operation. +// BenchmarkEOFValidation2 tries to benchmark the code validation for the CALLF/RETF operation. // For this we set up code that calls into 1024 code sections which // - contain calls to some other code sections. // We can't have all code sections calling each other, otherwise we would exceed 48KB. diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index 9efc6f596..5cb05b566 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -346,7 +346,7 @@ func multiExpG1Gnark(gs []gnark.G1Affine, scalars []fr.Element) gnark.G1Affine { return res } -// multiExpG1Gnark is a naive implementation of G1 multi-exponentiation +// multiExpG2Gnark is a naive implementation of G2 multi-exponentiation func multiExpG2Gnark(gs []gnark.G2Affine, scalars []fr.Element) gnark.G2Affine { res := gnark.G2Affine{} for i := 0; i < len(gs); i++ { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index b0d84eb87..d48850c10 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -471,8 +471,8 @@ func (db *Database) Recoverable(root common.Hash) bool { if id == nil { return false } - // Recoverable state must below the disk layer. The recoverable - // state only refers the state that is currently not available, + // Recoverable state must be below the disk layer. The recoverable + // state only refers to the state that is currently not available, // but can be restored by applying state history. dl := db.tree.bottom() if *id >= dl.stateID() { diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go index c06026b6c..2e1d83c74 100644 --- a/triedb/pathdb/difflayer.go +++ b/triedb/pathdb/difflayer.go @@ -27,8 +27,8 @@ import ( // diffLayer represents a collection of modifications made to the in-memory tries // along with associated state changes after running a block on top. // -// The goal of a diff layer is to act as a journal, tracking recent modifications -// made to the state, that have not yet graduated into a semi-immutable state. +// The purpose of a diff layer is to serve as a journal, recording recent state modifications +// that have not yet been committed to a more stable or semi-permanent state. type diffLayer struct { // Immutables root common.Hash // Root hash to which this layer diff belongs to From fb094f25675752e45c8c9f5b5f282896a237ab2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 28 Jan 2025 19:55:41 +0200 Subject: [PATCH 102/354] all: nuke total difficulty (#30744) The total difficulty is the sum of all block difficulties from genesis to a certain block. This value was used in PoW for deciding which chain is heavier, and thus which chain to select. Since PoS has a different fork selection algorithm, all blocks since the merge have a difficulty of 0, and all total difficulties are the same for the past 2 years. Whilst the TDs are mostly useless nowadays, there was never really a reason to mess around removing them since they are so tiny. This reasoning changes when we go down the path of pruned chain history. In order to reconstruct any TD, we **must** retrieve all the headers from chain head to genesis and then iterate all the difficulties to compute the TD. In a world where we completely prune past chain segments (bodies, receipts, headers), it is not possible to reconstruct the TD at all. In a world where we still keep chain headers and prune only the rest, reconstructing it possible as long as we process (or download) the chain forward from genesis, but trying to snap sync the head first and backfill later hits the same issue, the TD becomes impossible to calculate until genesis is backfilled. All in all, the TD is a messy out-of-state, out-of-consensus computed field that is overall useless nowadays, but code relying on it forces the client into certain modes of operation and prevents other modes or other optimizations. This PR completely nukes out the TD from the node. It doesn't compute it, it doesn't operate on it, it's as if it didn't even exist. Caveats: - Whenever we have APIs that return TD (devp2p handshake, tracer, etc.) we return a TD of 0. - For era files, we recompute the TD during export time (fairly quick) to retain the format content. - It is not possible to "verify" the merge point (i.e. with TD gone, TTD is useless). Since we're not verifying PoW any more, just blindly trust it, not verifying but blindly trusting the many year old merge point seems just the same trust model. - Our tests still need to be able to generate pre and post merge blocks, so they need a new way to split the merge without TTD. The PR introduces a settable ttdBlock field on the consensus object which is used by tests as the block where originally the TTD happened. This is not needed for live nodes, we never want to generate old blocks. - One merge transition consensus test was disabled. With a non-operational TD, testing how the client reacts to TTD is useless, it cannot react. Questions: - Should we also drop total terminal difficulty from the genesis json? It's a number we cannot react on any more, so maybe it would be cleaner to get rid of even more concepts. --------- Co-authored-by: Gary Rong --- cmd/devp2p/internal/ethtest/suite.go | 38 -------- consensus/beacon/consensus.go | 41 +++++++-- consensus/beacon/faker.go | 41 --------- core/blockchain.go | 7 +- core/blockchain_test.go | 6 +- core/chain_makers_test.go | 5 +- eth/catalyst/api_test.go | 91 +------------------ eth/gasprice/gasprice_test.go | 6 +- eth/protocols/eth/handler_test.go | 13 ++- eth/tracers/api_test.go | 2 +- eth/tracers/internal/tracetest/supply_test.go | 5 +- graphql/graphql_test.go | 5 +- tests/block_test.go | 14 +++ 13 files changed, 76 insertions(+), 198 deletions(-) delete mode 100644 consensus/beacon/faker.go diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 5cb9fa029..12dc5711a 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -18,7 +18,6 @@ package ethtest import ( "crypto/rand" - "math/big" "reflect" "github.com/ethereum/go-ethereum/common" @@ -74,7 +73,6 @@ func (s *Suite) EthTests() []utesting.Test { {Name: "GetBlockBodies", Fn: s.TestGetBlockBodies}, // // malicious handshakes + status {Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake}, - {Name: "MaliciousStatus", Fn: s.TestMaliciousStatus}, // test transactions {Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true}, {Name: "Transaction", Fn: s.TestTransaction}, @@ -453,42 +451,6 @@ func (s *Suite) TestMaliciousHandshake(t *utesting.T) { } } -func (s *Suite) TestMaliciousStatus(t *utesting.T) { - t.Log(`This test sends a malicious eth Status message to the node and expects a disconnect.`) - - conn, err := s.dial() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - defer conn.Close() - if err := conn.handshake(); err != nil { - t.Fatalf("handshake failed: %v", err) - } - // Create status with large total difficulty. - status := ð.StatusPacket{ - ProtocolVersion: uint32(conn.negotiatedProtoVersion), - NetworkID: s.chain.config.ChainID.Uint64(), - TD: new(big.Int).SetBytes(randBuf(2048)), - Head: s.chain.Head().Hash(), - Genesis: s.chain.GetBlock(0).Hash(), - ForkID: s.chain.ForkID(), - } - if err := conn.statusExchange(s.chain, status); err != nil { - t.Fatalf("status exchange failed: %v", err) - } - // Wait for disconnect. - code, _, err := conn.Read() - if err != nil { - t.Fatalf("error reading from connection: %v", err) - } - switch code { - case discMsg: - break - default: - t.Fatalf("expected disconnect, got: %d", code) - } -} - func (s *Suite) TestTransaction(t *utesting.T) { t.Log(`This test sends a valid transaction to the node and checks if the transaction gets propagated.`) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index cdacf354a..71cf1dbb1 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -61,7 +61,8 @@ var ( // is only used for necessary consensus checks. The legacy consensus engine can be any // engine implements the consensus interface (except the beacon itself). type Beacon struct { - ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique + ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique + ttdblock *uint64 // Merge block-number for testchain generation without TTDs } // New creates a consensus engine with the given embedded eth1 engine. @@ -72,6 +73,18 @@ func New(ethone consensus.Engine) *Beacon { return &Beacon{ethone: ethone} } +// TestingTTDBlock is a replacement mechanism for TTD-based pre-/post-merge +// splitting. With chain history deletion, TD calculations become impossible. +// This is fine for progressing the live chain, but to be able to generate test +// chains, we do need a split point. This method supports setting an explicit +// block number to use as the splitter *for testing*, instead of having to keep +// the notion of TDs in the client just for testing. +// +// The block with supplied number is regarded as the last pre-merge block. +func (beacon *Beacon) TestingTTDBlock(number uint64) { + beacon.ttdblock = &number +} + // Author implements consensus.Engine, returning the verified author of the block. func (beacon *Beacon) Author(header *types.Header) (common.Address, error) { if !beacon.IsPoSHeader(header) { @@ -334,12 +347,15 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [ // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the beacon protocol. The changes are done inline. func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { - // Transition isn't triggered yet, use the legacy rules for preparation. - reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) - if err != nil { - return err - } - if !reached { + // The beacon engine requires access to total difficulties to be able to + // seal pre-merge and post-merge blocks. With the transition to removing + // old blocks, TDs become unaccessible, thus making TTD based pre-/post- + // merge decisions impossible. + // + // We do not need to seal non-merge blocks anymore live, but we do need + // to be able to generate test chains, thus we're reverting to a testing- + // settable field to direct that. + if beacon.ttdblock != nil && *beacon.ttdblock >= header.Number.Uint64() { return beacon.ethone.Prepare(chain, header) } header.Difficulty = beaconDifficulty @@ -449,8 +465,15 @@ func (beacon *Beacon) SealHash(header *types.Header) common.Hash { // the difficulty that a new block should have when created at time // given the parent block's time and difficulty. func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { - // Transition isn't triggered yet, use the legacy rules for calculation - if reached, _ := IsTTDReached(chain, parent.Hash(), parent.Number.Uint64()); !reached { + // The beacon engine requires access to total difficulties to be able to + // seal pre-merge and post-merge blocks. With the transition to removing + // old blocks, TDs become unaccessible, thus making TTD based pre-/post- + // merge decisions impossible. + // + // We do not need to seal non-merge blocks anymore live, but we do need + // to be able to generate test chains, thus we're reverting to a testing- + // settable field to direct that. + if beacon.ttdblock != nil && *beacon.ttdblock > parent.Number.Uint64() { return beacon.ethone.CalcDifficulty(chain, time, parent) } return beaconDifficulty diff --git a/consensus/beacon/faker.go b/consensus/beacon/faker.go deleted file mode 100644 index 981e345e3..000000000 --- a/consensus/beacon/faker.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2023 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 . - -package beacon - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/types" -) - -// NewFaker creates a fake consensus engine for testing. -// The fake engine simulates a merged network. -// It can not be used to test the merge transition. -// This type is needed since the fakeChainReader can not be used with -// a normal beacon consensus engine. -func NewFaker() consensus.Engine { - return new(faker) -} - -type faker struct { - Beacon -} - -func (f *faker) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { - return beaconDifficulty -} diff --git a/core/blockchain.go b/core/blockchain.go index 1b13a74b1..229ee86d0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1333,9 +1333,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if !bc.HasHeader(last.Hash(), last.NumberU64()) { return 0, fmt.Errorf("containing header #%d [%x..] unknown", last.Number(), last.Hash().Bytes()[:4]) } - // Write all chain data to ancients. - td := bc.GetTd(first.Hash(), first.NumberU64()) + ptd := bc.GetTd(first.ParentHash(), first.NumberU64()-1) + if ptd == nil { + return 0, consensus.ErrUnknownAncestor + } + td := new(big.Int).Add(ptd, first.Difficulty()) writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, td) if err != nil { log.Error("Error importing chain data to ancients", "err", err) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ed117edff..cb40a39a2 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4042,7 +4042,7 @@ func TestEIP3651(t *testing.T) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") - engine = beacon.NewFaker() + engine = beacon.New(ethash.NewFaker()) // A sender who makes transactions, has some funds key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -4158,7 +4158,7 @@ func TestPragueRequests(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) config = *params.MergedTestChainConfig signer = types.LatestSigner(&config) - engine = beacon.NewFaker() + engine = beacon.New(ethash.NewFaker()) ) gspec := &Genesis{ Config: &config, @@ -4236,7 +4236,7 @@ func TestEIP7702(t *testing.T) { var ( config = *params.MergedTestChainConfig signer = types.LatestSigner(&config) - engine = beacon.NewFaker() + engine = beacon.New(ethash.NewFaker()) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") addr1 = crypto.PubkeyToAddress(key1.PublicKey) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 430e5650d..aa8e3f796 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -80,8 +80,9 @@ func TestGeneratePOSChain(t *testing.T) { Code: common.Hex2Bytes("600154600354"), } genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, triedb.HashDefaults)) + engine := beacon.New(ethash.NewFaker()) - genchain, genreceipts := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) { + genchain, genreceipts := GenerateChain(gspec.Config, genesis, engine, gendb, 4, func(i int, gen *BlockGen) { gen.SetParentBeaconRoot(common.Hash{byte(i + 1)}) // Add value transfer tx. @@ -122,7 +123,7 @@ func TestGeneratePOSChain(t *testing.T) { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(genchain); err != nil { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 428f1645e..d40b3ac82 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -32,8 +32,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus" - beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -63,10 +62,11 @@ var ( func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { config := *params.AllEthashProtocolChanges - engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker())) + engine := beacon.New(ethash.NewFaker()) if merged { config.TerminalTotalDifficulty = common.Big0 - engine = beaconConsensus.NewFaker() + } else { + engine.TestingTTDBlock(uint64(n)) } genesis := &core.Genesis{ Config: &config, @@ -102,7 +102,6 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { } config.TerminalTotalDifficulty = totalDifficulty } - return genesis, blocks } @@ -165,24 +164,6 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { } } -func TestSetHeadBeforeTotalDifficulty(t *testing.T) { - genesis, blocks := generateMergeChain(10, false) - n, ethservice := startEthService(t, genesis, blocks) - defer n.Close() - - api := NewConsensusAPI(ethservice) - fcState := engine.ForkchoiceStateV1{ - HeadBlockHash: blocks[5].Hash(), - SafeBlockHash: common.Hash{}, - FinalizedBlockHash: common.Hash{}, - } - if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { - t.Errorf("fork choice updated should not error: %v", err) - } else if resp.PayloadStatus.Status != engine.INVALID_TERMINAL_BLOCK.Status { - t.Errorf("fork choice updated before total terminal difficulty should be INVALID") - } -} - func TestEth2PrepareAndGetPayload(t *testing.T) { genesis, blocks := generateMergeChain(10, false) // We need to properly set the terminal total difficulty @@ -905,70 +886,6 @@ func TestInvalidBloom(t *testing.T) { } } -func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { - genesis, preMergeBlocks := generateMergeChain(100, false) - n, ethservice := startEthService(t, genesis, preMergeBlocks) - defer n.Close() - api := NewConsensusAPI(ethservice) - - // Test parent already post TTD in FCU - parent := preMergeBlocks[len(preMergeBlocks)-2] - fcState := engine.ForkchoiceStateV1{ - HeadBlockHash: parent.Hash(), - SafeBlockHash: common.Hash{}, - FinalizedBlockHash: common.Hash{}, - } - resp, err := api.ForkchoiceUpdatedV1(fcState, nil) - if err != nil { - t.Fatalf("error sending forkchoice, err=%v", err) - } - if resp.PayloadStatus != engine.INVALID_TERMINAL_BLOCK { - t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) - } - - // Test parent already post TTD in NewPayload - args := &miner.BuildPayloadArgs{ - Parent: parent.Hash(), - Timestamp: parent.Time() + 1, - Random: crypto.Keccak256Hash([]byte{byte(1)}), - FeeRecipient: parent.Coinbase(), - } - payload, err := api.eth.Miner().BuildPayload(args, false) - if err != nil { - t.Fatalf("error preparing payload, err=%v", err) - } - data := *payload.Resolve().ExecutionPayload - // We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash - txs, _ := decodeTransactions(data.Transactions) - header := &types.Header{ - ParentHash: data.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: data.FeeRecipient, - Root: data.StateRoot, - TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: data.ReceiptsRoot, - Bloom: types.BytesToBloom(data.LogsBloom), - Difficulty: common.Big0, - Number: new(big.Int).SetUint64(data.Number), - GasLimit: data.GasLimit, - GasUsed: data.GasUsed, - Time: data.Timestamp, - BaseFee: data.BaseFeePerGas, - Extra: data.ExtraData, - MixDigest: data.Random, - } - block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) - data.BlockHash = block.Hash() - // Send the new payload - resp2, err := api.NewPayloadV1(data) - if err != nil { - t.Fatalf("error sending NewPayload, err=%v", err) - } - if resp2 != engine.INVALID_TERMINAL_BLOCK { - t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) - } -} - // TestSimultaneousNewBlock does several parallel inserts, both as // newPayLoad and forkchoiceUpdate. This is to test that the api behaves // well even of the caller is not being 'serial'. diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index f8210703b..7fe55d419 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -25,7 +25,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -148,7 +147,10 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe config.LondonBlock = londonBlock config.ArrowGlacierBlock = londonBlock config.GrayGlacierBlock = londonBlock - var engine consensus.Engine = beacon.New(ethash.NewFaker()) + + engine := beacon.New(ethash.NewFaker()) + engine.TestingTTDBlock(testHead + 1) + td := params.GenesisDifficulty.Uint64() if cancunBlock != nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index e129936fe..22fdb51f1 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -25,7 +25,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -71,12 +70,13 @@ func newTestBackend(blocks int) *testBackend { func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend { var ( // Create a database pre-initialize with a genesis block - db = rawdb.NewMemoryDatabase() - config = params.TestChainConfig - engine consensus.Engine = ethash.NewFaker() + db = rawdb.NewMemoryDatabase() + config = params.TestChainConfig + engine = beacon.New(ethash.NewFaker()) ) - - if shanghai { + if !shanghai { + engine.TestingTTDBlock(math.MaxUint64) + } else { config = ¶ms.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), @@ -99,7 +99,6 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, TerminalTotalDifficulty: big.NewInt(0), Ethash: new(params.EthashConfig), } - engine = beacon.NewFaker() } gspec := &core.Genesis{ diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 1b068954b..5b07e39ef 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -1089,7 +1089,7 @@ func TestTraceChain(t *testing.T) { func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { backend := &testBackend{ chainConfig: gspec.Config, - engine: beacon.NewFaker(), + engine: beacon.New(ethash.NewFaker()), chaindb: rawdb.NewMemoryDatabase(), } // Generate blocks for testing diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 8bd84d9ce..4e2a735f4 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -544,9 +544,8 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { } func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { - var ( - engine = beacon.New(ethash.NewFaker()) - ) + engine := beacon.New(ethash.NewFaker()) + engine.TestingTTDBlock(1) traceOutputPath := filepath.ToSlash(t.TempDir()) traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl") diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 231170c27..3e6a042db 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -29,7 +29,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -457,9 +456,8 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge RPCGasCap: 1000000, StateScheme: rawdb.HashScheme, } - var engine consensus.Engine = ethash.NewFaker() + var engine = beacon.New(ethash.NewFaker()) if shanghai { - engine = beacon.NewFaker() gspec.Config.TerminalTotalDifficulty = common.Big0 // GenerateChain will increment timestamps by 10. // Shanghai upgrade at block 1. @@ -468,6 +466,7 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge } else { // set an arbitrary large ttd as chains are required to be known to be merged gspec.Config.TerminalTotalDifficulty = big.NewInt(math.MaxInt64) + engine.TestingTTDBlock(math.MaxUint64) } ethBackend, err := eth.New(stack, ethConf) if err != nil { diff --git a/tests/block_test.go b/tests/block_test.go index 52184eb27..15806b3ef 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -49,6 +49,20 @@ func TestBlockchain(t *testing.T) { // using 4.6 TGas bt.skipLoad(`.*randomStatetest94.json.*`) + // After the merge we would accept side chains as canonical even if they have lower td + bt.skipLoad(`.*bcMultiChainTest/ChainAtoChainB_difficultyB.json`) + bt.skipLoad(`.*bcMultiChainTest/CallContractFromNotBestBlock.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/uncleBlockAtBlock3afterBlock4.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/lotsOfBranchesOverrideAtTheMiddle.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/sideChainWithMoreTransactions.json`) + bt.skipLoad(`.*bcForkStressTest/ForkStressTest.json`) + bt.skipLoad(`.*bcMultiChainTest/lotsOfLeafs.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain2.json`) + + // With chain history removal, TDs become unavailable, this transition tests based on TTD are unrunnable + bt.skipLoad(`.*bcArrowGlacierToParis/powToPosBlockRejection.json`) + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { execBlockTest(t, bt, test) }) From 501de3d5c446f4aff0335f748347fcd418bec2f4 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:56:20 +0100 Subject: [PATCH 103/354] .github: add lint step (#31068) --- .github/workflows/go.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6406d2fa3..d1d2579df 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -8,6 +8,30 @@ on: workflow_dispatch: jobs: + lint: + name: Lint + runs-on: self-hosted + steps: + - uses: actions/checkout@v4 + + # Cache build tools to avoid downloading them each time + - uses: actions/cache@v4 + with: + path: build/cache + key: ${{ runner.os }}-build-tools-cache-${{ hashFiles('build/checksums.txt') }} + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23.0 + cache: false + + - name: Run linters + run: | + go run build/ci.go lint + go run build/ci.go check_tidy + go run build/ci.go check_baddeps + build: runs-on: self-hosted steps: From 5e76d85cc8f676fd254d68b429ee46fe848bd605 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:31:25 +0100 Subject: [PATCH 104/354] core/{.,state,vm},miner,eth/tracers,tests: implement 7709 with a syscall flag (#31036) Same as #31015 but requires the contract to exist. Not compatible with any verkle testnet up to now. This adds a `isSytemCall` flag so that it is possible to detect when a system call is executed, so that the code execution and other locations are not added to the witness. --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Ignacio Hagopian Co-authored-by: Felix Lange --- core/chain_makers.go | 23 +++++++++------- core/state/statedb_hooked.go | 4 +++ core/state_processor.go | 24 ++++++++++------ core/verkle_witness_test.go | 53 ++++++++++++++++++++---------------- core/vm/contract.go | 1 + core/vm/eips.go | 14 ++++++---- core/vm/evm.go | 9 ++++-- core/vm/gas_table.go | 4 +-- core/vm/interface.go | 3 ++ core/vm/interpreter.go | 2 +- core/vm/operations_verkle.go | 20 +++++++++++++- 11 files changed, 103 insertions(+), 54 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 5298874a4..9b750cc0d 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -122,6 +122,11 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti if err != nil { panic(err) } + // Merge the tx-local access event into the "block-local" one, in order to collect + // all values, so that the witness can be built. + if b.statedb.GetTrie().IsVerkle() { + b.statedb.AccessEvents().Merge(evm.AccessEvents) + } b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) if b.header.BlobGasUsed != nil { @@ -379,7 +384,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse misc.ApplyDAOHardFork(statedb) } - if config.IsPrague(b.header.Number, b.header.Time) { + if config.IsPrague(b.header.Number, b.header.Time) || config.IsVerkle(b.header.Number, b.header.Time) { // EIP-2935 blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) blockContext.Random = &common.Hash{} // enable post-merge instruction set @@ -487,13 +492,11 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine // Save pre state for proof generation // preState := statedb.Copy() - // Pre-execution system calls. - if config.IsPrague(b.header.Number, b.header.Time) { - // EIP-2935 - blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) - evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - ProcessParentBlockHash(b.header.ParentHash, evm) - } + // EIP-2935 / 7709 + blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) + blockContext.Random = &common.Hash{} // enable post-merge instruction set + evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) + ProcessParentBlockHash(b.header.ParentHash, evm) // Execute any user modifications to the block. if gen != nil { @@ -561,7 +564,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine return cm.chain, cm.receipts, proofs, keyvals } -func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) { +func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (common.Hash, ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) { db := rawdb.NewMemoryDatabase() cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) cacheConfig.SnapshotLimit = 0 @@ -572,7 +575,7 @@ func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n panic(err) } blocks, receipts, proofs, keyvals := GenerateVerkleChain(genesis.Config, genesisBlock, engine, db, triedb, n, gen) - return db, blocks, receipts, proofs, keyvals + return genesisBlock.Hash(), db, blocks, receipts, proofs, keyvals } func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 31bdd06b4..25d823cc8 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -157,6 +157,10 @@ func (s *hookedStateDB) Witness() *stateless.Witness { return s.inner.Witness() } +func (s *hookedStateDB) AccessEvents() *AccessEvents { + return s.inner.AccessEvents() +} + func (s *hookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int { prev := s.inner.SubBalance(addr, amount, reason) if s.hooks.OnBalanceChange != nil && !amount.IsZero() { diff --git a/core/state_processor.go b/core/state_processor.go index 582fb14a7..c10f9454a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -89,7 +89,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, evm) } - if p.config.IsPrague(block.Number(), block.Time()) { + if p.config.IsPrague(block.Number(), block.Time()) || p.config.IsVerkle(block.Number(), block.Time()) { ProcessParentBlockHash(block.ParentHash(), evm) } if p.config.DBFT != nil { @@ -173,6 +173,12 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, } *usedGas += result.UsedGas + // Merge the tx-local access event into the "block-local" one, in order to collect + // all values, so that the witness can be built. + if statedb.GetTrie().IsVerkle() { + statedb.AccessEvents().Merge(evm.AccessEvents) + } + return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil } @@ -199,12 +205,6 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } - // Merge the tx-local access event into the "block-local" one, in order to collect - // all values, so that the witness can be built. - if statedb.GetTrie().IsVerkle() { - statedb.AccessEvents().Merge(evm.AccessEvents) - } - // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) @@ -252,7 +252,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { } // ProcessParentBlockHash stores the parent block hash in the history storage contract -// as per EIP-2935. +// as per EIP-2935/7709. func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(tracer, evm.GetVMContext()) @@ -271,7 +271,13 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress) - _, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, err := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + if err != nil { + panic(err) + } + if evm.StateDB.AccessEvents() != nil { + evm.StateDB.AccessEvents().Merge(evm.AccessEvents) + } evm.StateDB.Finalise(true) } diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index fb72b9461..b2230ad42 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -152,7 +152,7 @@ func TestProcessVerkle(t *testing.T) { txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, } - _, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + _, _, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() // TODO need to check that the tx cost provided is the exact amount used (no remaining left-over) @@ -219,7 +219,7 @@ func TestProcessParentBlockHash(t *testing.T) { // block 1 parent hash is 0x0100.... // block 2 parent hash is 0x0200.... // etc - checkBlockHashes := func(statedb *state.StateDB) { + checkBlockHashes := func(statedb *state.StateDB, isVerkle bool) { statedb.SetNonce(params.HistoryStorageAddress, 1) statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) // Process n blocks, from 1 .. num @@ -227,20 +227,24 @@ func TestProcessParentBlockHash(t *testing.T) { for i := 1; i <= num; i++ { header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} vmContext := NewEVMBlockContext(header, nil, new(common.Address)) - evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{}) + chainConfig := params.MergedTestChainConfig + if isVerkle { + chainConfig = testVerkleChainConfig + } + evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{}) ProcessParentBlockHash(header.ParentHash, evm) } // Read block hashes for block 0 .. num-1 for i := 0; i < num; i++ { - have, want := getContractStoredBlockHash(statedb, uint64(i)), common.Hash{byte(i + 1)} + have, want := getContractStoredBlockHash(statedb, uint64(i), isVerkle), common.Hash{byte(i + 1)} if have != want { - t.Errorf("block %d, have parent hash %v, want %v", i, have, want) + t.Errorf("block %d, verkle=%v, have parent hash %v, want %v", i, isVerkle, have, want) } } } t.Run("MPT", func(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - checkBlockHashes(statedb) + checkBlockHashes(statedb, false) }) t.Run("Verkle", func(t *testing.T) { db := rawdb.NewMemoryDatabase() @@ -248,15 +252,18 @@ func TestProcessParentBlockHash(t *testing.T) { cacheConfig.SnapshotLimit = 0 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil)) - checkBlockHashes(statedb) + checkBlockHashes(statedb, true) }) } // getContractStoredBlockHash is a utility method which reads the stored parent blockhash for block 'number' -func getContractStoredBlockHash(statedb *state.StateDB, number uint64) common.Hash { +func getContractStoredBlockHash(statedb *state.StateDB, number uint64, isVerkle bool) common.Hash { ringIndex := number % params.HistoryServeWindow var key common.Hash binary.BigEndian.PutUint64(key[24:], ringIndex) + if isVerkle { + return statedb.GetState(params.HistoryStorageAddress, key) + } return statedb.GetState(params.HistoryStorageAddress, key) } @@ -279,7 +286,7 @@ func TestProcessVerkleInvalidContractCreation(t *testing.T) { // // - The second block contains a single failing contract creation transaction, // that fails right off the bat. - _, chain, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + genesisH, _, chain, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() if i == 0 { @@ -364,8 +371,8 @@ func TestProcessVerkleInvalidContractCreation(t *testing.T) { if stemStateDiff.SuffixDiffs[0].NewValue == nil { t.Fatalf("nil new value in BLOCKHASH contract insert") } - if *stemStateDiff.SuffixDiffs[0].NewValue != chain[0].Hash() { - t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, chain[0].Hash()) + if *stemStateDiff.SuffixDiffs[0].NewValue != genesisH { + t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, genesisH) } } else { // For all other entries present in the witness, check that nothing beyond @@ -393,8 +400,8 @@ func TestProcessVerkleInvalidContractCreation(t *testing.T) { if stemStateDiff.SuffixDiffs[0].NewValue == nil { t.Fatalf("missing post state value for BLOCKHASH contract at block #2") } - if *stemStateDiff.SuffixDiffs[0].NewValue != common.HexToHash("0788c2c0f23aa07eb8bf76fe6c1ca9064a4821c1fd0af803913da488a58dba54") { - t.Fatalf("invalid post state value for BLOCKHASH contract at block #2: 0788c2c0f23aa07eb8bf76fe6c1ca9064a4821c1fd0af803913da488a58dba54 != %x", (*stemStateDiff.SuffixDiffs[0].NewValue)[:]) + if *stemStateDiff.SuffixDiffs[0].NewValue != chain[0].Hash() { + t.Fatalf("invalid post state value for BLOCKHASH contract at block #2: %x != %x", chain[0].Hash(), (*stemStateDiff.SuffixDiffs[0].NewValue)[:]) } } else if suffixDiff.Suffix > 4 { t.Fatalf("invalid suffix diff found for %x in block #2: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) @@ -440,7 +447,7 @@ func TestProcessVerkleContractWithEmptyCode(t *testing.T) { config.ChainID.SetUint64(69421) gspec := verkleTestGenesis(&config) - _, chain, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { + genesisH, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { gen.SetPoS() var tx types.Transaction // a transaction that does some PUSH1n but returns a 0-sized contract @@ -472,8 +479,8 @@ func TestProcessVerkleContractWithEmptyCode(t *testing.T) { if stemStateDiff.SuffixDiffs[0].NewValue == nil { t.Fatalf("nil new value in BLOCKHASH contract insert") } - if *stemStateDiff.SuffixDiffs[0].NewValue != chain[0].Hash() { - t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, chain[0].Hash()) + if *stemStateDiff.SuffixDiffs[0].NewValue != genesisH { + t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, genesisH) } } else { for _, suffixDiff := range stemStateDiff.SuffixDiffs { @@ -532,7 +539,7 @@ func TestProcessVerkleExtCodeHashOpcode(t *testing.T) { } extCodeHashContractAddr := crypto.CreateAddress(deployer, 1) - _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() if i == 0 { @@ -605,7 +612,7 @@ func TestProcessVerkleBalanceOpcode(t *testing.T) { account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") gspec = verkleTestGenesis(&config) ) - _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { + _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { gen.SetPoS() txData := slices.Concat( []byte{byte(vm.PUSH20)}, @@ -686,7 +693,7 @@ func TestProcessVerkleSelfDestructInSeparateTx(t *testing.T) { deployer := crypto.PubkeyToAddress(testKey.PublicKey) contract := crypto.CreateAddress(deployer, 0) - _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() if i == 0 { @@ -794,7 +801,7 @@ func TestProcessVerkleSelfDestructInSameTx(t *testing.T) { deployer := crypto.PubkeyToAddress(testKey.PublicKey) contract := crypto.CreateAddress(deployer, 0) - _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { + _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { gen.SetPoS() tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, Value: big.NewInt(42), @@ -897,7 +904,7 @@ func TestProcessVerkleSelfDestructInSeparateTxWithSelfBeneficiary(t *testing.T) deployer := crypto.PubkeyToAddress(testKey.PublicKey) contract := crypto.CreateAddress(deployer, 0) - _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { + _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { gen.SetPoS() if i == 0 { // Create self-destruct contract, sending 42 wei. @@ -977,7 +984,7 @@ func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiary(t *testing.T) { selfDestructContract := []byte{byte(vm.ADDRESS), byte(vm.SELFDESTRUCT)} - _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { + _, _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { gen.SetPoS() tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, Value: big.NewInt(42), @@ -1043,7 +1050,7 @@ func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiaryAndPrefundedAccount selfDestructContract := []byte{byte(vm.ADDRESS), byte(vm.SELFDESTRUCT)} - _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { + _, _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { gen.SetPoS() tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, Value: big.NewInt(42), diff --git a/core/vm/contract.go b/core/vm/contract.go index cfda75b27..5670244e1 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -59,6 +59,7 @@ type Contract struct { // is the execution frame represented by this object a contract deployment IsDeployment bool + IsSystemCall bool Gas uint64 value *uint256.Int diff --git a/core/vm/eips.go b/core/vm/eips.go index a51a18dc6..ab5870242 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -345,10 +345,12 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC self: AccountRef(addr), } paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) - statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) - if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { - scope.Contract.Gas = 0 - return nil, ErrOutOfGas + if !contract.IsSystemCall { + statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) + if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { + scope.Contract.Gas = 0 + return nil, ErrOutOfGas + } } scope.Memory.Set(memOffset.Uint64(), length.Uint64(), paddedCodeCopy) @@ -367,7 +369,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext if *pc < codeLen { scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc]))) - if !scope.Contract.IsDeployment && *pc%31 == 0 { + if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall && *pc%31 == 0 { // touch next chunk if PUSH1 is at the boundary. if so, *pc has // advanced past this boundary. contractAddr := scope.Contract.Address() @@ -397,7 +399,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc { )), ) - if !scope.Contract.IsDeployment { + if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { contractAddr := scope.Contract.Address() statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false) if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { diff --git a/core/vm/evm.go b/core/vm/evm.go index 1e52215b7..3f9ae621a 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -165,8 +165,12 @@ func (evm *EVM) Interpreter() *EVMInterpreter { return evm.interpreter } +func isSystemCall(caller ContractRef) bool { + return caller.Address() == params.SystemAddress +} + // Call executes the contract associated with the addr with the given input as -// parameters. It also handles any necessary value transfer required and takes +// parameters. It also handles any necessary value transfer required and takse // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { @@ -189,7 +193,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas p, isPrecompile := evm.precompile(addr) if !evm.StateDB.Exist(addr) { - if !isPrecompile && evm.chainRules.IsEIP4762 { + if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) { // add proof of absence to witness wgas := evm.AccessEvents.AddAccount(addr, false) if gas < wgas { @@ -220,6 +224,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // If the account has no code, we can abort here // The depth-check is already done, and precompiles handled above contract := NewContract(caller, AccountRef(addrCopy), value, gas) + contract.IsSystemCall = isSystemCall(caller) contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), code) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index f3a980825..55855727b 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -394,7 +394,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsEIP4762 { + if evm.chainRules.IsEIP4762 && !contract.IsSystemCall { if transfersValue { gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) if overflow { @@ -428,7 +428,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, ErrGasUintOverflow } - if evm.chainRules.IsEIP4762 { + if evm.chainRules.IsEIP4762 && !contract.IsSystemCall { address := common.Address(stack.Back(1).Bytes20()) transfersValue := !stack.Back(2).IsZero() if transfersValue { diff --git a/core/vm/interface.go b/core/vm/interface.go index 011541dde..3488526fc 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -98,6 +99,8 @@ type StateDB interface { Witness() *stateless.Witness + AccessEvents() *state.AccessEvents + // Finalise must be invoked at the end of a transaction Finalise(bool) } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4b304aa59..b6d93b078 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -235,7 +235,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged, pcCopy, gasCopy = false, pc, contract.Gas } - if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment { + if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go index 349299477..751761a91 100644 --- a/core/vm/operations_verkle.go +++ b/core/vm/operations_verkle.go @@ -41,6 +41,9 @@ func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor } func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + if contract.IsSystemCall { + return 0, nil + } address := stack.peek().Bytes20() gas := evm.AccessEvents.BasicDataGas(address, false) if gas == 0 { @@ -54,6 +57,9 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, if _, isPrecompile := evm.precompile(address); isPrecompile { return 0, nil } + if contract.IsSystemCall { + return 0, nil + } gas := evm.AccessEvents.BasicDataGas(address, false) if gas == 0 { gas = params.WarmStorageReadCostEIP2929 @@ -62,6 +68,9 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, } func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + if contract.IsSystemCall { + return 0, nil + } address := stack.peek().Bytes20() if _, isPrecompile := evm.precompile(address); isPrecompile { return 0, nil @@ -79,6 +88,9 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc { if err != nil { return 0, err } + if contract.IsSystemCall { + return gas, nil + } if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile { return gas, nil } @@ -102,6 +114,9 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile { return 0, nil } + if contract.IsSystemCall { + return 0, nil + } contractAddr := contract.Address() statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false) if contractAddr != beneficiaryAddr { @@ -131,7 +146,7 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, uint64CodeOffset = gomath.MaxUint64 } _, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64()) - if !contract.IsDeployment { + if !contract.IsDeployment && !contract.IsSystemCall { gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) } return gas, nil @@ -143,6 +158,9 @@ func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memo if err != nil { return 0, err } + if contract.IsSystemCall { + return gas, nil + } addr := common.Address(stack.peek().Bytes20()) wgas := evm.AccessEvents.BasicDataGas(addr, false) if wgas == 0 { From 0c582683d2e9d5eea9b83c89a7d8802cd2559609 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:58:44 +0100 Subject: [PATCH 105/354] build: bump test timeout (#31095) Travis often fails because the test times out. --- build/ci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 07d721303..dd82ede13 100644 --- a/build/ci.go +++ b/build/ci.go @@ -303,8 +303,8 @@ func doTest(cmdline []string) { } gotest := tc.Go("test") - // CI needs a bit more time for the statetests (default 10m). - gotest.Args = append(gotest.Args, "-timeout=30m") + // CI needs a bit more time for the statetests (default 45m). + gotest.Args = append(gotest.Args, "-timeout=45m") // Enable CKZG backend in CI. gotest.Args = append(gotest.Args, "-tags=ckzg") From 63e8d3466968f5df0a553866fc8dc0e32b3d2201 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 30 Jan 2025 11:10:45 +0100 Subject: [PATCH 106/354] .travis.yml: change arch for Docker build to arm64 (#31096) This is an attempt to work around a gcc issue in the Docker build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2ba3af941..0353aa2e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ jobs: - stage: build if: type = push os: linux - arch: amd64 + arch: arm64 dist: focal go: 1.23.x env: From 27b49ee9a7b628049301cad4e01a4ebf81efc371 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 30 Jan 2025 11:21:23 +0100 Subject: [PATCH 107/354] Revert ".travis.yml: change arch for Docker build to arm64 (#31096)" This reverts commit 7b96ec4dae8d4ddeffc761c7757c12e2d2b8bf74. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0353aa2e4..2ba3af941 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ jobs: - stage: build if: type = push os: linux - arch: arm64 + arch: amd64 dist: focal go: 1.23.x env: From bac66a9979b85b6998d60b59d6fdc3b8cbb262a2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 30 Jan 2025 14:52:02 +0100 Subject: [PATCH 108/354] build: provide a flag to disable publishing in dockerx build (#31098) This changes the `-upload` flag to just toggle the upload. The remote image name is now configured using the `-hub` flag. --- .travis.yml | 2 +- build/ci.go | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ba3af941..8953450e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ jobs: before_install: - export DOCKER_CLI_EXPERIMENTAL=enabled script: - - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64,linux/riscv64" -upload ethereum/client-go + - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64,linux/riscv64" -hub ethereum/client-go -upload # This builder does the Linux Azure uploads - stage: build diff --git a/build/ci.go b/build/ci.go index dd82ede13..dbf4055da 100644 --- a/build/ci.go +++ b/build/ci.go @@ -689,7 +689,8 @@ func maybeSkipArchive(env build.Environment) { func doDockerBuildx(cmdline []string) { var ( platform = flag.String("platform", "", `Push a multi-arch docker image for the specified architectures (usually "linux/amd64,linux/arm64")`) - upload = flag.String("upload", "", `Where to upload the docker image (usually "ethereum/client-go")`) + hubImage = flag.String("hub", "ethereum/client-go", `Where to upload the docker image`) + upload = flag.Bool("upload", false, `Whether to trigger upload`) ) flag.CommandLine.Parse(cmdline) @@ -724,25 +725,33 @@ func doDockerBuildx(cmdline []string) { tags = []string{"stable", fmt.Sprintf("release-%v", version.Family), "v" + version.Semantic} } // Need to create a mult-arch builder - build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform) + check := exec.Command("docker", "buildx", "inspect", "multi-arch-builder") + if check.Run() != nil { + build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform) + } for _, spec := range []struct { file string base string }{ - {file: "Dockerfile", base: fmt.Sprintf("%s:", *upload)}, - {file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *upload)}, + {file: "Dockerfile", base: fmt.Sprintf("%s:", *hubImage)}, + {file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *hubImage)}, } { for _, tag := range tags { // latest, stable etc gethImage := fmt.Sprintf("%s%s", spec.base, tag) - build.MustRunCommand("docker", "buildx", "build", + cmd := exec.Command("docker", "buildx", "build", "--build-arg", "COMMIT="+env.Commit, "--build-arg", "VERSION="+version.WithMeta, "--build-arg", "BUILDNUM="+env.Buildnum, "--tag", gethImage, "--platform", *platform, - "--push", - "--file", spec.file, ".") + "--file", spec.file, + ) + if *upload { + cmd.Args = append(cmd.Args, "--push") + } + cmd.Args = append(cmd.Args, ".") + build.MustRun(cmd) } } } From de815f11a96070fdcca1ee7e1684c2961a52e888 Mon Sep 17 00:00:00 2001 From: Ryan Tinianov Date: Thu, 30 Jan 2025 10:58:53 -0500 Subject: [PATCH 109/354] all: add build tags for wasip1 (#31090) --- cmd/utils/diskusage.go | 4 +-- crypto/kzg4844/kzg4844_ckzg_cgo.go | 2 +- crypto/kzg4844/kzg4844_ckzg_nocgo.go | 2 +- crypto/signature_cgo.go | 4 +-- crypto/signature_nocgo.go | 4 +-- ethdb/leveldb/leveldb.go | 4 +-- metrics/cpu_disabled.go | 4 +-- metrics/cpu_enabled.go | 4 +-- metrics/cputime_unix.go | 4 +-- rpc/ipc_wasip1.go | 38 ++++++++++++++++++++++++++++ 10 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 rpc/ipc_wasip1.go diff --git a/cmd/utils/diskusage.go b/cmd/utils/diskusage.go index 0e88f9194..8174236ab 100644 --- a/cmd/utils/diskusage.go +++ b/cmd/utils/diskusage.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . -//go:build !windows && !openbsd -// +build !windows,!openbsd +//go:build !windows && !openbsd && !wasip1 +// +build !windows,!openbsd,!wasip1 package utils diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 11bc451b5..dce592b44 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build ckzg && !nacl && !js && cgo && !gofuzz +//go:build ckzg && !nacl && !js && !wasip1 && cgo && !gofuzz package kzg4844 diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go index 70a78e80d..0662b2632 100644 --- a/crypto/kzg4844/kzg4844_ckzg_nocgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !ckzg || nacl || js || !cgo || gofuzz +//go:build !ckzg || nacl || js || wasip1 || !cgo || gofuzz package kzg4844 diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 87289253c..5c7810c14 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !nacl && !js && cgo && !gofuzz -// +build !nacl,!js,cgo,!gofuzz +//go:build !nacl && !js && !wasip1 && cgo && !gofuzz +// +build !nacl,!js,!wasip1,cgo,!gofuzz package crypto diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 16a785a18..2d35b4940 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build nacl || js || !cgo || gofuzz -// +build nacl js !cgo gofuzz +//go:build nacl || js || wasip1 || !cgo || gofuzz +// +build nacl js wasip1 !cgo gofuzz package crypto diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index f18503c94..1d88ed460 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !js -// +build !js +//go:build !js && !wasip1 +// +build !js,!wasip1 // Package leveldb implements the key-value database layer based on LevelDB. package leveldb diff --git a/metrics/cpu_disabled.go b/metrics/cpu_disabled.go index 025d97aeb..8404b0edd 100644 --- a/metrics/cpu_disabled.go +++ b/metrics/cpu_disabled.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build ios || js -// +build ios js +//go:build ios || js || wasip1 +// +build ios js wasip1 package metrics diff --git a/metrics/cpu_enabled.go b/metrics/cpu_enabled.go index 2359028a2..838c32fad 100644 --- a/metrics/cpu_enabled.go +++ b/metrics/cpu_enabled.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !ios && !js -// +build !ios,!js +//go:build !ios && !js && !wasip1 +// +build !ios,!js,!wasip1 package metrics diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go index ad4f812fd..a44bf8087 100644 --- a/metrics/cputime_unix.go +++ b/metrics/cputime_unix.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !windows && !js -// +build !windows,!js +//go:build !windows && !js && !wasip1 +// +build !windows,!js,!wasip1 package metrics diff --git a/rpc/ipc_wasip1.go b/rpc/ipc_wasip1.go new file mode 100644 index 000000000..2608e2922 --- /dev/null +++ b/rpc/ipc_wasip1.go @@ -0,0 +1,38 @@ +// 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 . + +//go:build wasip1 +// +build wasip1 + +package rpc + +import ( + "context" + "errors" + "net" +) + +var errNotSupported = errors.New("rpc: not supported") + +// ipcListen will create a named pipe on the given endpoint. +func ipcListen(endpoint string) (net.Listener, error) { + return nil, errNotSupported +} + +// newIPCConnection will connect to a named pipe with the given endpoint as name. +func newIPCConnection(ctx context.Context, endpoint string) (net.Conn, error) { + return nil, errNotSupported +} From b6e6f24a7590e1ad9f214957d41af29d48e6531c Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:07:45 +0100 Subject: [PATCH 110/354] core: implement eip-7623 floor data gas (#30946) This PR builds on #29040 and updates it to the new version of the spec. I filled the EEST tests and they pass. Link to spec: https://eips.ethereum.org/EIPS/eip-7623 --------- Co-authored-by: Marius van der Wijden Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> Co-authored-by: lightclient --- cmd/evm/internal/t8ntool/transaction.go | 26 ++++-- core/error.go | 4 + core/state_processor_test.go | 4 +- core/state_transition.go | 82 +++++++++++++------ core/tracing/hooks.go | 3 + core/txpool/validation.go | 10 +++ core/verkle_witness_test.go | 2 +- ...h_getBlockReceipts-block-with-blob-tx.json | 8 +- ...ockReceipts-block-with-dynamic-fee-tx.json | 8 +- .../eth_getBlockReceipts-tag-latest.json | 8 +- .../eth_getTransactionReceipt-blob-tx.json | 8 +- ...eipt-create-contract-with-access-list.json | 8 +- ...ansactionReceipt-dynamic-tx-with-logs.json | 8 +- params/protocol_params.go | 2 + 14 files changed, 125 insertions(+), 56 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index d8650beca..2bc4f73b6 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,15 +133,29 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, - chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { + rules := chainConfig.Rules(common.Big0, true, 0) + gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + if err != nil { r.Error = err results = append(results, r) continue - } else { - r.IntrinsicGas = gas - if tx.Gas() < gas { - r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas) + } + r.IntrinsicGas = gas + if tx.Gas() < gas { + r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas) + results = append(results, r) + continue + } + // For Prague txs, validate the floor data gas. + if rules.IsPrague { + floorDataGas, err := core.FloorDataGas(tx.Data()) + if err != nil { + r.Error = err + results = append(results, r) + continue + } + if tx.Gas() < floorDataGas { + r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrFloorDataGas, tx.Gas(), floorDataGas) results = append(results, r) continue } diff --git a/core/error.go b/core/error.go index 7dbe6756a..9693b6a5f 100644 --- a/core/error.go +++ b/core/error.go @@ -84,6 +84,10 @@ var ( // than required to start the invocation. ErrIntrinsicGas = errors.New("intrinsic gas too low") + // ErrFloorDataGas is returned if the transaction is specified to use less gas + // than required for the data floor cost. + ErrFloorDataGas = errors.New("insufficient gas for floor data gas cost") + // ErrTxTypeNotSupported is returned if a transaction is not supported in the // current network configuration. ErrTxTypeNotSupported = types.ErrTxTypeNotSupported diff --git a/core/state_processor_test.go b/core/state_processor_test.go index f1b11a1a3..70a2509b2 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -251,9 +251,9 @@ func TestStateProcessorErrors(t *testing.T) { }, { // ErrMaxInitCodeSizeExceeded txs: []*types.Transaction{ - mkDynamicCreationTx(0, 500000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]), + mkDynamicCreationTx(0, 520000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]), }, - want: "could not apply tx 0 [0xd491405f06c92d118dd3208376fcee18a57c54bc52063ee4a26b1cf296857c25]: max initcode size exceeded: code size 49153 limit 49152", + want: "could not apply tx 0 [0x3a30404d42d6ccc843d7c391fd0c87b9b9795a0c174261b46d2ac95ca17b81cd]: max initcode size exceeded: code size 49153 limit 49152", }, { // ErrIntrinsicGas: Not enough gas to cover init code txs: []*types.Transaction{ diff --git a/core/state_transition.go b/core/state_transition.go index 46606f770..b0a4cdb80 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "fmt" "math" "math/big" @@ -81,12 +82,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set // Bump the required gas by the amount of transactional data if dataLen > 0 { // Zero and non-zero bytes are priced differently - var nz uint64 - for _, byt := range data { - if byt != 0 { - nz++ - } - } + z := uint64(bytes.Count(data, []byte{0})) + nz := dataLen - z + // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier if isEIP2028 { @@ -97,7 +95,6 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set } gas += nz * nonZeroGas - z := dataLen - nz if (math.MaxUint64-gas)/params.TxDataZeroGas < z { return 0, ErrGasUintOverflow } @@ -121,6 +118,21 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set return gas, nil } +// FloorDataGas computes the minimum gas required for a transaction based on its data tokens (EIP-7623). +func FloorDataGas(data []byte) (uint64, error) { + var ( + z = uint64(bytes.Count(data, []byte{0})) + nz = uint64(len(data)) - z + tokens = nz*params.TxTokenPerNonZeroByte + z + ) + // Check for overflow + if (math.MaxUint64-params.TxGas)/params.TxCostFloorPerToken < tokens { + return 0, ErrGasUintOverflow + } + // Minimum gas required for a transaction based on its data tokens (EIP-7623). + return params.TxGas + tokens*params.TxCostFloorPerToken, nil +} + // toWordSize returns the ceiled word size required for init code payment calculation. func toWordSize(size uint64) uint64 { if size > math.MaxUint64-31 { @@ -454,6 +466,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { sender = vm.AccountRef(msg.From) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time) contractCreation = msg.To == nil + floorDataGas uint64 ) // Check clauses 4-5, subtract intrinsic gas if everything is correct @@ -464,6 +477,16 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if st.gasRemaining < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) } + // Gas limit suffices for the floor data cost (EIP-7623) + if rules.IsPrague { + floorDataGas, err = FloorDataGas(msg.Data) + if err != nil { + return nil, err + } + if msg.GasLimit < floorDataGas { + return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas) + } + } if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) } @@ -527,14 +550,21 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value) } - var gasRefund uint64 - if !rules.IsLondon { - // Before EIP-3529: refunds were capped to gasUsed / 2 - gasRefund = st.refundGas(params.RefundQuotient) - } else { - // After EIP-3529: refunds are capped to gasUsed / 5 - gasRefund = st.refundGas(params.RefundQuotientEIP3529) + // Compute refund counter, capped to a refund quotient. + gasRefund := st.calcRefund() + st.gasRemaining += gasRefund + if rules.IsPrague { + // After EIP-7623: Data-heavy transactions pay the floor gas. + if st.gasUsed() < floorDataGas { + prev := st.gasRemaining + st.gasRemaining = st.initialGas - floorDataGas + if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { + t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) + } + } } + st.returnGas() + effectiveTip := msg.GasPrice if rules.IsLondon { effectiveTip = new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee) @@ -625,20 +655,28 @@ func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) return nil } -func (st *stateTransition) refundGas(refundQuotient uint64) uint64 { - // Apply refund counter, capped to a refund quotient - refund := st.gasUsed() / refundQuotient +// calcRefund computes refund counter, capped to a refund quotient. +func (st *stateTransition) calcRefund() uint64 { + var refund uint64 + if !st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { + // Before EIP-3529: refunds were capped to gasUsed / 2 + refund = st.gasUsed() / params.RefundQuotient + } else { + // After EIP-3529: refunds are capped to gasUsed / 5 + refund = st.gasUsed() / params.RefundQuotientEIP3529 + } if refund > st.state.GetRefund() { refund = st.state.GetRefund() } - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds) } + return refund +} - st.gasRemaining += refund - - // Return ETH for remaining gas, exchanged at the original rate. +// returnGas returns ETH for remaining gas, +// exchanged at the original rate. +func (st *stateTransition) returnGas() { remaining := uint256.NewInt(st.gasRemaining) remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) @@ -650,8 +688,6 @@ func (st *stateTransition) refundGas(refundQuotient uint64) uint64 { // Also return remaining gas to the block gas counter so it is // available for the next transaction. st.gp.AddGas(st.gasRemaining) - - return refund } // gasUsed returns the amount of gas used up by the state transition. diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 4343edfe8..e1978e483 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -314,6 +314,9 @@ const ( GasChangeWitnessCodeChunk GasChangeReason = 17 // GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision. GasChangeWitnessContractCollisionCheck GasChangeReason = 18 + // GasChangeTxDataFloor is the amount of extra gas the transaction has to pay to reach the minimum gas requirement for the + // transaction data. This change will always be a negative change. + GasChangeTxDataFloor GasChangeReason = 19 // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // it will be "manually" tracked by a direct emit of the gas change event. diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 7dc8f1c4d..7a5155531 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -117,6 +117,16 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types if tx.Gas() < intrGas { return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas) } + // Ensure the transaction can cover floor data gas. + if opts.Config.IsPrague(head.Number, head.Time) { + floorDataGas, err := core.FloorDataGas(tx.Data()) + if err != nil { + return err + } + if tx.Gas() < floorDataGas { + return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrFloorDataGas, tx.Gas(), floorDataGas) + } + } // Ensure the gasprice is high enough to cover the requirement of the calling pool if tx.GasTipCapIntCmp(opts.MinTip) < 0 { return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), opts.MinTip) diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index b2230ad42..eba2fb61a 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -147,7 +147,7 @@ func TestProcessVerkle(t *testing.T) { params.WitnessChunkWriteCost + /* SSTORE in constructor */ params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */ 15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */ - 4844 /* execution costs */ + uint64(4844) /* execution costs */ blockGasUsagesExpected := []uint64{ txCost1*2 + txCost2, txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json index df2d9349f..5853724cd 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json @@ -2,19 +2,19 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", + "blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", - "effectiveGasPrice": "0x1b09d63b", + "effectiveGasPrice": "0x1b0a08c4", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gasUsed": "0x5208", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x1", "to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e", - "transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f", + "transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add", "transactionIndex": "0x0", "type": "0x3" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json index b01400e60..602b25e21 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json @@ -1,12 +1,12 @@ [ { - "blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3", + "blockHash": "0x47cd44027bb55856a175e36be0396bad221e52172529d9c1bf12bf5424a041ae", "blockNumber": "0x4", "contractAddress": null, - "cumulativeGasUsed": "0x538d", + "cumulativeGasUsed": "0x5564", "effectiveGasPrice": "0x2325c42f", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", - "gasUsed": "0x538d", + "gasUsed": "0x5564", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x0", @@ -15,4 +15,4 @@ "transactionIndex": "0x0", "type": "0x2" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json index df2d9349f..5853724cd 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json @@ -2,19 +2,19 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", + "blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", - "effectiveGasPrice": "0x1b09d63b", + "effectiveGasPrice": "0x1b0a08c4", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gasUsed": "0x5208", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x1", "to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e", - "transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f", + "transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add", "transactionIndex": "0x0", "type": "0x3" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json index 8e0669d10..386f1225e 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json @@ -1,18 +1,18 @@ { "blobGasPrice": "0x1", "blobGasUsed": "0x20000", - "blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49", + "blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c", "blockNumber": "0x6", "contractAddress": null, "cumulativeGasUsed": "0x5208", - "effectiveGasPrice": "0x1b09d63b", + "effectiveGasPrice": "0x1b0a08c4", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gasUsed": "0x5208", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x1", "to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e", - "transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f", + "transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add", "transactionIndex": "0x0", "type": "0x3" -} \ No newline at end of file +} diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json index 49c06aad6..0519ae1da 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json @@ -1,16 +1,16 @@ { - "blockHash": "0x53bffe54375c0a31fe7bc0db7455db7d48278234c2400efa4d40d1c57cbe868d", + "blockHash": "0x5bff93f8f94ba7ee52bef1a80062b9fed22c6d1eebb2b0e87a4a003365a7bd66", "blockNumber": "0x5", "contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18", "cumulativeGasUsed": "0xe01c", - "effectiveGasPrice": "0x1ecb3fb4", + "effectiveGasPrice": "0x1ecb7942", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", "gasUsed": "0xe01c", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x1", "to": null, - "transactionHash": "0xb5a1148819cfdfff9bfe70035524fec940eb735d89b76960b97751d01ae2a9f2", + "transactionHash": "0x173dffc76966c72542560c376ce512a871e31b86988f9169bf021da0937640f9", "transactionIndex": "0x0", "type": "0x1" -} \ No newline at end of file +} diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json index 13bd7bd12..4601273a5 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json @@ -1,11 +1,11 @@ { - "blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3", + "blockHash": "0x47cd44027bb55856a175e36be0396bad221e52172529d9c1bf12bf5424a041ae", "blockNumber": "0x4", "contractAddress": null, - "cumulativeGasUsed": "0x538d", + "cumulativeGasUsed": "0x5564", "effectiveGasPrice": "0x2325c42f", "from": "0x703c4b2bd70c169f5717101caee543299fc946c7", - "gasUsed": "0x538d", + "gasUsed": "0x5564", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "status": "0x0", @@ -13,4 +13,4 @@ "transactionHash": "0xdcde2574628c9d7dff22b9afa19f235959a924ceec65a9df903a517ae91f5c84", "transactionIndex": "0x0", "type": "0x2" -} \ No newline at end of file +} diff --git a/params/protocol_params.go b/params/protocol_params.go index f06346db8..a56eed568 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -92,6 +92,8 @@ const ( TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) + TxTokenPerNonZeroByte uint64 = 4 // Token cost per non-zero byte as specified by EIP-7623. + TxCostFloorPerToken uint64 = 10 // Cost floor per byte of data as specified by EIP-7623. TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702 From d829123fee216d638283570e4e969ad1b97cefb9 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:08:42 +0100 Subject: [PATCH 111/354] core/vm: EXTCODE* return delegation designator for 7702 (#31089) Implements https://github.com/ethereum/EIPs/pull/9248 --- core/vm/eips.go | 59 ------------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index ab5870242..515999bd1 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -23,8 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -709,65 +707,8 @@ func enableEOF(jt *JumpTable) { } } -// opExtCodeCopyEIP7702 implements the EIP-7702 variation of opExtCodeCopy. -func opExtCodeCopyEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - var ( - stack = scope.Stack - a = stack.pop() - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() - ) - uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() - if overflow { - uint64CodeOffset = math.MaxUint64 - } - code := interpreter.evm.StateDB.GetCode(common.Address(a.Bytes20())) - if _, ok := types.ParseDelegation(code); ok { - code = types.DelegationPrefix[:2] - } - codeCopy := getData(code, uint64CodeOffset, length.Uint64()) - scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - - return nil, nil -} - -// opExtCodeSizeEIP7702 implements the EIP-7702 variation of opExtCodeSize. -func opExtCodeSizeEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - slot := scope.Stack.peek() - code := interpreter.evm.StateDB.GetCode(common.Address(slot.Bytes20())) - if _, ok := types.ParseDelegation(code); ok { - code = types.DelegationPrefix[:2] - } - slot.SetUint64(uint64(len(code))) - return nil, nil -} - -// opExtCodeHashEIP7702 implements the EIP-7702 variation of opExtCodeHash. -func opExtCodeHashEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - slot := scope.Stack.peek() - addr := common.Address(slot.Bytes20()) - if interpreter.evm.StateDB.Empty(addr) { - slot.Clear() - return nil, nil - } - code := interpreter.evm.StateDB.GetCode(addr) - if _, ok := types.ParseDelegation(code); ok { - // If the code is a delegation, return the prefix without version. - slot.SetBytes(crypto.Keccak256(types.DelegationPrefix[:2])) - } else { - // Otherwise, return normal code hash. - slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(addr).Bytes()) - } - return nil, nil -} - // enable7702 the EIP-7702 changes to support delegation designators. func enable7702(jt *JumpTable) { - jt[EXTCODECOPY].execute = opExtCodeCopyEIP7702 - jt[EXTCODESIZE].execute = opExtCodeSizeEIP7702 - jt[EXTCODEHASH].execute = opExtCodeHashEIP7702 - jt[CALL].dynamicGas = gasCallEIP7702 jt[CALLCODE].dynamicGas = gasCallCodeEIP7702 jt[STATICCALL].dynamicGas = gasStaticCallEIP7702 From c985b814141218899c2242dea3e2d4b9330e960a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 31 Jan 2025 02:36:49 -0700 Subject: [PATCH 112/354] params: update system contract addresses for devnet-6 (#31102) Finalize Prague system contract addresses. Reference: * https://github.com/ethereum/EIPs/pull/9287 * https://github.com/ethereum/EIPs/pull/9288 * https://github.com/ethereum/EIPs/pull/9289 --- params/protocol_params.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/params/protocol_params.go b/params/protocol_params.go index a56eed568..c9179634a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -205,14 +205,14 @@ var ( BeaconRootsCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500") // EIP-2935 - Serve historical block hashes from state - HistoryStorageAddress = common.HexToAddress("0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC") + HistoryStorageAddress = common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935") HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500") // EIP-7002 - Execution layer triggerable withdrawals - WithdrawalQueueAddress = common.HexToAddress("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA") + WithdrawalQueueAddress = common.HexToAddress("0x00000961Ef480Eb55e80D19ad83579A64c007002") WithdrawalQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd") // EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE - ConsolidationQueueAddress = common.HexToAddress("0x00431F263cE400f4455c2dCf564e53007Ca4bbBb") + ConsolidationQueueAddress = common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251") ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") ) From 1162365ead66d648c14c77b12d050d6c9f3c47e4 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 31 Jan 2025 18:34:22 +0100 Subject: [PATCH 113/354] eth/catalyst: fix validation of type 0 request (#31103) I caught this error on Hive. It was introduced by https://github.com/ethereum/go-ethereum/pull/31071 because after adding the equality check the request type 0 will be rejected. --- eth/catalyst/api.go | 6 ++--- eth/catalyst/api_test.go | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 500500891..45a0ac874 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -1296,18 +1296,16 @@ func convertRequests(hex []hexutil.Bytes) [][]byte { // validateRequests checks that requests are ordered by their type and are not empty. func validateRequests(requests [][]byte) error { - var last byte - for _, req := range requests { + for i, req := range requests { // No empty requests. if len(req) < 2 { return fmt.Errorf("empty request: %v", req) } // Check that requests are ordered by their type. // Each type must appear only once. - if req[0] <= last { + if i > 0 && req[0] <= requests[i-1][0] { return fmt.Errorf("invalid request order: %v", req) } - last = req[0] } return nil } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index d40b3ac82..32a843d2e 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1740,3 +1740,61 @@ func TestGetClientVersion(t *testing.T) { t.Fatalf("client info does match expected, got %s", info.String()) } } + +func TestValidateRequests(t *testing.T) { + tests := []struct { + name string + requests [][]byte + wantErr bool + }{ + { + name: "valid ascending", + requests: [][]byte{ + {0x00, 0xAA, 0xBB}, // type 0x00 + {0x01, 0xCC}, // type 0x01 + {0x02, 0xDD}, // type 0x02 + }, + wantErr: false, + }, + { + name: "empty request (too short)", + requests: [][]byte{ + {0x00}, // only 1 byte: type with no data + }, + wantErr: true, + }, + { + name: "duplicate type", + requests: [][]byte{ + {0x00, 0x11}, + {0x01, 0x22}, + {0x01, 0x33}, // duplicate type 0x01 + }, + wantErr: true, + }, + { + name: "out of order", + requests: [][]byte{ + {0x01, 0xAA}, // type 0x01 + {0x00, 0xBB}, // type 0x00 out of order (should be ascending) + }, + wantErr: true, + }, + { + name: "single request valid", + requests: [][]byte{ + {0x01, 0xAB}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateRequests(tt.requests) + if (err != nil) != tt.wantErr { + t.Errorf("validateRequests(%v) error = %v, wantErr = %v", + tt.requests, err, tt.wantErr) + } + }) + } +} From 806c4fc52bdc50ebedb777b15ea97e5f55387ffe Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 3 Feb 2025 09:44:26 -0800 Subject: [PATCH 114/354] core/vm: simplify tracer hook invocation in interpreter loop (#31074) Removes duplicate code in the interpreter loop. --- core/vm/interpreter.go | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index b6d93b078..4ee5448da 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -260,9 +260,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( contract.Gas -= cost } + // All ops with a dynamic memory usage also has a dynamic gas cost. + var memorySize uint64 if operation.dynamicGas != nil { - // All ops with a dynamic memory usage also has a dynamic gas cost. - var memorySize uint64 // calculate the new memory size and expand the memory to fit // the operation // Memory check needs to be done prior to evaluating the dynamic gas portion, @@ -292,21 +292,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } else { contract.Gas -= dynamicCost } + } - // Do tracing before memory expansion - if debug { - if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) - } - if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - logged = true - } - } - if memorySize > 0 { - mem.Resize(memorySize) - } - } else if debug { + // Do tracing before potential memory expansion + if debug { if in.evm.Config.Tracer.OnGasChange != nil { in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) } @@ -315,6 +304,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged = true } } + if memorySize > 0 { + mem.Resize(memorySize) + } // execute the operation res, err = operation.execute(&pc, in, callContext) From 1327614ed404daf300573304dd7b910b2e64b604 Mon Sep 17 00:00:00 2001 From: kazak Date: Tue, 4 Feb 2025 08:09:06 +0200 Subject: [PATCH 115/354] tests/fuzzers/bls12381: fix error message in fuzzCrossG2Add (#31113) Fixes a typo in the error message within the `fuzzCrossG2Add` function. The panic message incorrectly references "G1 point addition mismatch" when it should be "G2 point addition mismatch," as the function deals with G2 points. This doesn't affect functionality but could cause confusion during debugging. I've updated the message to reflect the correct curve. --- tests/fuzzers/bls12381/bls12381_fuzz.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index 5cb05b566..a17c128b7 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -168,7 +168,7 @@ func fuzzCrossG2Add(data []byte) int { bl3 := blst.P2AffinesAdd([]*blst.P2Affine{bl1, bl2}) if !(bytes.Equal(gp.Marshal(), bl3.Serialize())) { - panic("G1 point addition mismatch blst / geth ") + panic("G2 point addition mismatch blst / geth ") } return 1 From 87f7e9ba943dd41f9e1458656b5a9f71c47db082 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 4 Feb 2025 18:45:45 +0800 Subject: [PATCH 116/354] core/rawdb: introduce flush offset in freezer (#30392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up PR to #29792 to get rid of the data file sync. **This is a non-backward compatible change, which increments the database version from 8 to 9**. We introduce a flushOffset for each freezer table, which tracks the position of the most recently fsync’d item in the index file. When this offset moves forward, it indicates that all index entries below it, along with their corresponding data items, have been properly persisted to disk. The offset can also be moved backward when truncating from either the head or tail of the file. Previously, the data file required an explicit fsync after every mutation, which was highly inefficient. With the introduction of the flush offset, the synchronization strategy becomes more flexible, allowing the freezer to sync every 30 seconds instead. The data items above the flush offset are regarded volatile and callers must ensure they are recoverable after the unclean shutdown, or explicitly sync the freezer before any proceeding operations. --------- Co-authored-by: Felix Lange --- core/blockchain.go | 11 +- core/rawdb/accessors_chain_test.go | 3 +- core/rawdb/ancient_scheme.go | 1 + core/rawdb/freezer_batch.go | 10 +- core/rawdb/freezer_meta.go | 186 +++++++++++----- core/rawdb/freezer_meta_test.go | 88 +++++++- core/rawdb/freezer_table.go | 264 +++++++++++++++------- core/rawdb/freezer_table_test.go | 342 ++++++++++++++++++++--------- 8 files changed, 656 insertions(+), 249 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 229ee86d0..f9cab933b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -116,21 +116,30 @@ const ( // * the `BlockNumber`, `TxHash`, `TxIndex`, `BlockHash` and `Index` fields of log are deleted // * the `Bloom` field of receipt is deleted // * the `BlockIndex` and `TxIndex` fields of txlookup are deleted + // // - Version 5 // The following incompatible database changes were added: // * the `TxHash`, `GasCost`, and `ContractAddress` fields are no longer stored for a receipt // * the `TxHash`, `GasCost`, and `ContractAddress` fields are computed by looking up the // receipts' corresponding block + // // - Version 6 // The following incompatible database changes were added: // * Transaction lookup information stores the corresponding block number instead of block hash + // // - Version 7 // The following incompatible database changes were added: // * Use freezer as the ancient database to maintain all ancient data + // // - Version 8 // The following incompatible database changes were added: // * New scheme for contract code in order to separate the codes and trie nodes - BlockChainVersion uint64 = 8 + // + // - Version 9 + // The following incompatible database changes were added: + // * Total difficulty has been removed from both the key-value store and the ancient store. + // * The metadata structure of freezer is changed by adding 'flushOffset' + BlockChainVersion uint64 = 9 ) // CacheConfig contains the configuration values for the trie database diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 0e986f66e..6972f2be2 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -883,6 +883,7 @@ func TestHeadersRLPStorage(t *testing.T) { t.Fatalf("failed to create database with ancient backend") } defer db.Close() + // Create blocks var chain []*types.Block var pHash common.Hash @@ -898,7 +899,7 @@ func TestHeadersRLPStorage(t *testing.T) { chain = append(chain, block) pHash = block.Hash() } - var receipts []types.Receipts = make([]types.Receipts, 100) + receipts := make([]types.Receipts, 100) // Write first half to ancients WriteAncientBlocks(db, chain[:50], receipts[:50], big.NewInt(100)) // Write second half to db diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 371fd384a..3e16d5c04 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -62,6 +62,7 @@ const ( stateHistoryStorageData = "storage.data" ) +// stateFreezerNoSnappy configures whether compression is disabled for the state freezer. var stateFreezerNoSnappy = map[string]bool{ stateHistoryMeta: true, stateHistoryAccountIndex: false, diff --git a/core/rawdb/freezer_batch.go b/core/rawdb/freezer_batch.go index 013d0b9d1..801d30f73 100644 --- a/core/rawdb/freezer_batch.go +++ b/core/rawdb/freezer_batch.go @@ -19,6 +19,7 @@ package rawdb import ( "fmt" "math" + "time" "github.com/ethereum/go-ethereum/rlp" "github.com/golang/snappy" @@ -188,9 +189,6 @@ func (batch *freezerTableBatch) commit() error { if err != nil { return err } - if err := batch.t.head.Sync(); err != nil { - return err - } dataSize := int64(len(batch.dataBuffer)) batch.dataBuffer = batch.dataBuffer[:0] @@ -208,6 +206,12 @@ func (batch *freezerTableBatch) commit() error { // Update metrics. batch.t.sizeGauge.Inc(dataSize + indexSize) batch.t.writeMeter.Mark(dataSize + indexSize) + + // Periodically sync the table, todo (rjl493456442) make it configurable? + if time.Since(batch.t.lastSync) > 30*time.Second { + batch.t.lastSync = time.Now() + return batch.t.Sync() + } return nil } diff --git a/core/rawdb/freezer_meta.go b/core/rawdb/freezer_meta.go index 9eef9df35..3cda9ae45 100644 --- a/core/rawdb/freezer_meta.go +++ b/core/rawdb/freezer_meta.go @@ -17,93 +17,173 @@ package rawdb import ( + "errors" "io" + "math" "os" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) -const freezerVersion = 1 // The initial version tag of freezer table metadata +const ( + freezerTableV1 = 1 // Initial version of metadata struct + freezerTableV2 = 2 // Add field: 'flushOffset' + freezerVersion = freezerTableV2 // The current used version +) -// freezerTableMeta wraps all the metadata of the freezer table. +// freezerTableMeta is a collection of additional properties that describe the +// freezer table. These properties are designed with error resilience, allowing +// them to be automatically corrected after an error occurs without significantly +// impacting overall correctness. type freezerTableMeta struct { - // Version is the versioning descriptor of the freezer table. - Version uint16 + file *os.File // file handler of metadata + version uint16 // version descriptor of the freezer table - // VirtualTail indicates how many items have been marked as deleted. - // Its value is equal to the number of items removed from the table - // plus the number of items hidden in the table, so it should never - // be lower than the "actual tail". - VirtualTail uint64 -} + // virtualTail represents the number of items marked as deleted. It is + // calculated as the sum of items removed from the table and the items + // hidden within the table, and should never be less than the "actual + // tail". + // + // If lost due to a crash or other reasons, it will be reset to the number + // of items deleted from the table, causing the previously hidden items + // to become visible, which is an acceptable consequence. + virtualTail uint64 -// newMetadata initializes the metadata object with the given virtual tail. -func newMetadata(tail uint64) *freezerTableMeta { - return &freezerTableMeta{ - Version: freezerVersion, - VirtualTail: tail, - } + // flushOffset represents the offset in the index file up to which the index + // items along with the corresponding data items in data files has been flushed + // (fsync’d) to disk. Beyond this offset, data integrity is not guaranteed, + // the extra index items along with the associated data items should be removed + // during the startup. + // + // The principle is that all data items above the flush offset are considered + // volatile and should be recoverable if they are discarded after the unclean + // shutdown. If data integrity is required, manually force a sync of the + // freezer before proceeding with further operations (e.g. do freezer.Sync() + // first and then write data to key value store in some circumstances). + // + // The offset could be moved forward by applying sync operation, or be moved + // backward in cases of head/tail truncation, etc. + flushOffset int64 } -// readMetadata reads the metadata of the freezer table from the -// given metadata file. -func readMetadata(file *os.File) (*freezerTableMeta, error) { +// decodeV1 attempts to decode the metadata structure in v1 format. If fails or +// the result is incompatible, nil is returned. +func decodeV1(file *os.File) *freezerTableMeta { _, err := file.Seek(0, io.SeekStart) if err != nil { - return nil, err + return nil } - var meta freezerTableMeta - if err := rlp.Decode(file, &meta); err != nil { - return nil, err + type obj struct { + Version uint16 + Tail uint64 + } + var o obj + if err := rlp.Decode(file, &o); err != nil { + return nil + } + if o.Version != freezerTableV1 { + return nil + } + return &freezerTableMeta{ + file: file, + version: o.Version, + virtualTail: o.Tail, } - return &meta, nil } -// writeMetadata writes the metadata of the freezer table into the -// given metadata file. -func writeMetadata(file *os.File, meta *freezerTableMeta) error { +// decodeV2 attempts to decode the metadata structure in v2 format. If fails or +// the result is incompatible, nil is returned. +func decodeV2(file *os.File) *freezerTableMeta { _, err := file.Seek(0, io.SeekStart) if err != nil { - return err + return nil + } + type obj struct { + Version uint16 + Tail uint64 + Offset uint64 + } + var o obj + if err := rlp.Decode(file, &o); err != nil { + return nil + } + if o.Version != freezerTableV2 { + return nil + } + if o.Offset > math.MaxInt64 { + log.Error("Invalid flushOffset %d in freezer metadata", o.Offset, "file", file.Name()) + return nil + } + return &freezerTableMeta{ + file: file, + version: freezerTableV2, + virtualTail: o.Tail, + flushOffset: int64(o.Offset), } - return rlp.Encode(file, meta) } -// loadMetadata loads the metadata from the given metadata file. -// Initializes the metadata file with the given "actual tail" if -// it's empty. -func loadMetadata(file *os.File, tail uint64) (*freezerTableMeta, error) { +// newMetadata initializes the metadata object, either by loading it from the file +// or by constructing a new one from scratch. +func newMetadata(file *os.File) (*freezerTableMeta, error) { stat, err := file.Stat() if err != nil { return nil, err } - // Write the metadata with the given actual tail into metadata file - // if it's non-existent. There are two possible scenarios here: - // - the freezer table is empty - // - the freezer table is legacy - // In both cases, write the meta into the file with the actual tail - // as the virtual tail. if stat.Size() == 0 { - m := newMetadata(tail) - if err := writeMetadata(file, m); err != nil { + m := &freezerTableMeta{ + file: file, + version: freezerTableV2, + virtualTail: 0, + flushOffset: 0, + } + if err := m.write(true); err != nil { return nil, err } return m, nil } - m, err := readMetadata(file) + if m := decodeV2(file); m != nil { + return m, nil + } + if m := decodeV1(file); m != nil { + return m, nil // legacy metadata + } + return nil, errors.New("failed to decode metadata") +} + +// setVirtualTail sets the virtual tail and flushes the metadata if sync is true. +func (m *freezerTableMeta) setVirtualTail(tail uint64, sync bool) error { + m.virtualTail = tail + return m.write(sync) +} + +// setFlushOffset sets the flush offset and flushes the metadata if sync is true. +func (m *freezerTableMeta) setFlushOffset(offset int64, sync bool) error { + m.flushOffset = offset + return m.write(sync) +} + +// write flushes the content of metadata into file and performs a fsync if required. +func (m *freezerTableMeta) write(sync bool) error { + type obj struct { + Version uint16 + Tail uint64 + Offset uint64 + } + var o obj + o.Version = freezerVersion // forcibly use the current version + o.Tail = m.virtualTail + o.Offset = uint64(m.flushOffset) + + _, err := m.file.Seek(0, io.SeekStart) if err != nil { - return nil, err + return err } - // Update the virtual tail with the given actual tail if it's even - // lower than it. Theoretically it shouldn't happen at all, print - // a warning here. - if m.VirtualTail < tail { - log.Warn("Updated virtual tail", "have", m.VirtualTail, "now", tail) - m.VirtualTail = tail - if err := writeMetadata(file, m); err != nil { - return nil, err - } + if err := rlp.Encode(m.file, &o); err != nil { + return err + } + if !sync { + return nil } - return m, nil + return m.file.Sync() } diff --git a/core/rawdb/freezer_meta_test.go b/core/rawdb/freezer_meta_test.go index 409e81102..31f8c519c 100644 --- a/core/rawdb/freezer_meta_test.go +++ b/core/rawdb/freezer_meta_test.go @@ -19,6 +19,8 @@ package rawdb import ( "os" "testing" + + "github.com/ethereum/go-ethereum/rlp" ) func TestReadWriteFreezerTableMeta(t *testing.T) { @@ -27,36 +29,98 @@ func TestReadWriteFreezerTableMeta(t *testing.T) { t.Fatalf("Failed to create file %v", err) } defer f.Close() - err = writeMetadata(f, newMetadata(100)) + + meta, err := newMetadata(f) if err != nil { - t.Fatalf("Failed to write metadata %v", err) + t.Fatalf("Failed to new metadata %v", err) } - meta, err := readMetadata(f) + meta.setVirtualTail(100, false) + + meta, err = newMetadata(f) if err != nil { - t.Fatalf("Failed to read metadata %v", err) + t.Fatalf("Failed to reload metadata %v", err) } - if meta.Version != freezerVersion { + if meta.version != freezerTableV2 { t.Fatalf("Unexpected version field") } - if meta.VirtualTail != uint64(100) { + if meta.virtualTail != uint64(100) { t.Fatalf("Unexpected virtual tail field") } } -func TestInitializeFreezerTableMeta(t *testing.T) { +func TestUpgradeMetadata(t *testing.T) { f, err := os.CreateTemp(t.TempDir(), "*") if err != nil { t.Fatalf("Failed to create file %v", err) } defer f.Close() - meta, err := loadMetadata(f, uint64(100)) + + // Write legacy metadata into file + type obj struct { + Version uint16 + Tail uint64 + } + var o obj + o.Version = freezerTableV1 + o.Tail = 100 + + if err := rlp.Encode(f, &o); err != nil { + t.Fatalf("Failed to encode %v", err) + } + + // Reload the metadata, a silent upgrade is expected + meta, err := newMetadata(f) if err != nil { t.Fatalf("Failed to read metadata %v", err) } - if meta.Version != freezerVersion { - t.Fatalf("Unexpected version field") + if meta.version != freezerTableV1 { + t.Fatal("Unexpected version field") } - if meta.VirtualTail != uint64(100) { - t.Fatalf("Unexpected virtual tail field") + if meta.virtualTail != uint64(100) { + t.Fatal("Unexpected virtual tail field") + } + if meta.flushOffset != 0 { + t.Fatal("Unexpected flush offset field") + } + + meta.setFlushOffset(100, true) + + meta, err = newMetadata(f) + if err != nil { + t.Fatalf("Failed to read metadata %v", err) + } + if meta.version != freezerTableV2 { + t.Fatal("Unexpected version field") + } + if meta.virtualTail != uint64(100) { + t.Fatal("Unexpected virtual tail field") + } + if meta.flushOffset != 100 { + t.Fatal("Unexpected flush offset field") + } +} + +func TestInvalidMetadata(t *testing.T) { + f, err := os.CreateTemp(t.TempDir(), "*") + if err != nil { + t.Fatalf("Failed to create file %v", err) + } + defer f.Close() + + // Write invalid legacy metadata into file + type obj struct { + Version uint16 + Tail uint64 + } + var o obj + o.Version = freezerTableV2 // -> invalid version tag + o.Tail = 100 + + if err := rlp.Encode(f, &o); err != nil { + t.Fatalf("Failed to encode %v", err) + } + _, err = newMetadata(f) + if err == nil { + t.Fatal("Unexpected success") } } diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 38c47dc22..1ba8cf639 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -108,11 +108,13 @@ type freezerTable struct { head *os.File // File descriptor for the data head of the table index *os.File // File descriptor for the indexEntry file of the table - meta *os.File // File descriptor for metadata of the table files map[uint32]*os.File // open files headId uint32 // number of the currently active head file tailId uint32 // number of the earliest file + metadata *freezerTableMeta // metadata of the table + lastSync time.Time // Timestamp when the last sync was performed + headBytes int64 // Number of bytes written to the head file readMeter *metrics.Meter // Meter for measuring the effective amount of data read writeMeter *metrics.Meter // Meter for measuring the effective amount of data written @@ -166,10 +168,17 @@ func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, si return nil, err } } + // Load metadata from the file. The tag will be true if legacy metadata + // is detected. + metadata, err := newMetadata(meta) + if err != nil { + return nil, err + } // Create the table and repair any past inconsistency tab := &freezerTable{ index: index, - meta: meta, + metadata: metadata, + lastSync: time.Now(), files: make(map[uint32]*os.File), readMeter: readMeter, writeMeter: writeMeter, @@ -221,13 +230,11 @@ func (t *freezerTable) repair() error { return err } // New file can't trigger this path } - // Validate the index file as it might contain some garbage data after the - // power failures. if err := t.repairIndex(); err != nil { return err } // Retrieve the file sizes and prepare for truncation. Note the file size - // might be changed after index validation. + // might be changed after index repair. if stat, err = t.index.Stat(); err != nil { return err } @@ -253,12 +260,14 @@ func (t *freezerTable) repair() error { t.tailId = firstIndex.filenum t.itemOffset.Store(uint64(firstIndex.offset)) - // Load metadata from the file - meta, err := loadMetadata(t.meta, t.itemOffset.Load()) - if err != nil { - return err + // Adjust the number of hidden items if it is less than the number of items + // being removed. + if t.itemOffset.Load() > t.metadata.virtualTail { + if err := t.metadata.setVirtualTail(t.itemOffset.Load(), true); err != nil { + return err + } } - t.itemHidden.Store(meta.VirtualTail) + t.itemHidden.Store(t.metadata.virtualTail) // Read the last index, use the default value in case the freezer is empty if offsetsSize == indexEntrySize { @@ -267,12 +276,6 @@ func (t *freezerTable) repair() error { t.index.ReadAt(buffer, offsetsSize-indexEntrySize) lastIndex.unmarshalBinary(buffer) } - // Print an error log if the index is corrupted due to an incorrect - // last index item. While it is theoretically possible to have a zero offset - // by storing all zero-size items, it is highly unlikely to occur in practice. - if lastIndex.offset == 0 && offsetsSize/indexEntrySize > 1 { - log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "indexes", offsetsSize/indexEntrySize) - } if t.readonly { t.head, err = t.openFile(lastIndex.filenum, openFreezerFileForReadOnly) } else { @@ -293,6 +296,7 @@ func (t *freezerTable) repair() error { return fmt.Errorf("freezer table(path: %s, name: %s, num: %d) is corrupted", t.path, t.name, lastIndex.filenum) } verbose = true + // Truncate the head file to the last offset pointer if contentExp < contentSize { t.logger.Warn("Truncating dangling head", "indexed", contentExp, "stored", contentSize) @@ -304,11 +308,23 @@ func (t *freezerTable) repair() error { // Truncate the index to point within the head file if contentExp > contentSize { t.logger.Warn("Truncating dangling indexes", "indexes", offsetsSize/indexEntrySize, "indexed", contentExp, "stored", contentSize) - if err := truncateFreezerFile(t.index, offsetsSize-indexEntrySize); err != nil { + + newOffset := offsetsSize - indexEntrySize + if err := truncateFreezerFile(t.index, newOffset); err != nil { return err } offsetsSize -= indexEntrySize + // If the index file is truncated beyond the flush offset, move the flush + // offset back to the new end of the file. A crash may occur before the + // offset is updated, leaving a dangling reference that points to a position + // outside the file. If so, the offset will be reset to the new end of the + // file during the next run. + if t.metadata.flushOffset > newOffset { + if err := t.metadata.setFlushOffset(newOffset, true); err != nil { + return err + } + } // Read the new head index, use the default value in case // the freezer is already empty. var newLastIndex indexEntry @@ -345,7 +361,7 @@ func (t *freezerTable) repair() error { if err := t.head.Sync(); err != nil { return err } - if err := t.meta.Sync(); err != nil { + if err := t.metadata.file.Sync(); err != nil { return err } } @@ -372,7 +388,65 @@ func (t *freezerTable) repair() error { return nil } -// repairIndex validates the integrity of the index file. According to the design, +func (t *freezerTable) repairIndex() error { + stat, err := t.index.Stat() + if err != nil { + return err + } + size := stat.Size() + + // Validate the items in the index file to ensure the data integrity. + // It's possible some garbage data is retained in the index file after + // the power failures and should be truncated first. + size, err = t.checkIndex(size) + if err != nil { + return err + } + // If legacy metadata is detected, attempt to recover the offset from the + // index file to avoid clearing the entire table. + if t.metadata.version == freezerTableV1 { + t.logger.Info("Recovering freezer flushOffset for legacy table", "offset", size) + return t.metadata.setFlushOffset(size, true) + } + + switch { + case size == indexEntrySize && t.metadata.flushOffset == 0: + // It's a new freezer table with no content. + // Move the flush offset to the end of the file. + return t.metadata.setFlushOffset(size, true) + + case size == t.metadata.flushOffset: + // flushOffset is aligned with the index file, all is well. + return nil + + case size > t.metadata.flushOffset: + // Extra index items have been detected beyond the flush offset. Since these + // entries correspond to data that has not been fully flushed to disk in the + // last run (because of unclean shutdown), their integrity cannot be guaranteed. + // To ensure consistency, these index items will be truncated, as there is no + // reliable way to validate or recover their associated data. + extraSize := size - t.metadata.flushOffset + if t.readonly { + return fmt.Errorf("index file(path: %s, name: %s) contains %d garbage data bytes", t.path, t.name, extraSize) + } + t.logger.Warn("Truncating freezer items after flushOffset", "size", extraSize) + return truncateFreezerFile(t.index, t.metadata.flushOffset) + + default: // size < flushOffset + // Flush offset refers to a position larger than index file. The only + // possible scenario for this is: a power failure or system crash has occurred after + // truncating the segment in index file from head or tail, but without updating + // the flush offset. In this case, automatically reset the flush offset with + // the file size which implies the entire index file is complete. + if t.readonly { + return nil // do nothing in read only mode + } + t.logger.Warn("Rewinding freezer flushOffset", "old", t.metadata.flushOffset, "new", size) + return t.metadata.setFlushOffset(size, true) + } +} + +// checkIndex validates the integrity of the index file. According to the design, // the initial entry in the file denotes the earliest data file along with the // count of deleted items. Following this, all subsequent entries in the file must // be in order. This function identifies any corrupted entries and truncates items @@ -392,18 +466,11 @@ func (t *freezerTable) repair() error { // leftover garbage or if all items in the table have zero size is impossible. // In such instances, the file will remain unchanged to prevent potential data // loss or misinterpretation. -func (t *freezerTable) repairIndex() error { - // Retrieve the file sizes and prepare for validation - stat, err := t.index.Stat() - if err != nil { - return err - } - size := stat.Size() - +func (t *freezerTable) checkIndex(size int64) (int64, error) { // Move the read cursor to the beginning of the file - _, err = t.index.Seek(0, io.SeekStart) + _, err := t.index.Seek(0, io.SeekStart) if err != nil { - return err + return 0, err } fr := bufio.NewReader(t.index) @@ -425,21 +492,21 @@ func (t *freezerTable) repairIndex() error { entry.unmarshalBinary(buff) return entry, nil } - truncate = func(offset int64) error { + truncate = func(offset int64) (int64, error) { if t.readonly { - return fmt.Errorf("index file is corrupted at %d, size: %d", offset, size) + return 0, fmt.Errorf("index file is corrupted at %d, size: %d", offset, size) } if err := truncateFreezerFile(t.index, offset); err != nil { - return err + return 0, err } log.Warn("Truncated index file", "offset", offset, "truncated", size-offset) - return nil + return offset, nil } ) for offset := int64(0); offset < size; offset += indexEntrySize { entry, err := read() if err != nil { - return err + return 0, err } if offset == 0 { head = entry @@ -468,10 +535,10 @@ func (t *freezerTable) repairIndex() error { // the seek operation anyway as a precaution. _, err = t.index.Seek(0, io.SeekEnd) if err != nil { - return err + return 0, err } log.Debug("Verified index file", "items", size/indexEntrySize, "elapsed", common.PrettyDuration(time.Since(start))) - return nil + return size, nil } // checkIndexItems validates the correctness of two consecutive index items based @@ -550,12 +617,23 @@ func (t *freezerTable) truncateHead(items uint64) error { // Truncate the index file first, the tail position is also considered // when calculating the new freezer table length. length := items - t.itemOffset.Load() - if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil { + newOffset := (length + 1) * indexEntrySize + if err := truncateFreezerFile(t.index, int64(newOffset)); err != nil { return err } if err := t.index.Sync(); err != nil { return err } + // If the index file is truncated beyond the flush offset, move the flush + // offset back to the new end of the file. A crash may occur before the + // offset is updated, leaving a dangling reference that points to a position + // outside the file. If so, the offset will be reset to the new end of the + // file during the next run. + if t.metadata.flushOffset > int64(newOffset) { + if err := t.metadata.setFlushOffset(int64(newOffset), true); err != nil { + return err + } + } // Calculate the new expected size of the data file and truncate it var expected indexEntry if length == 0 { @@ -652,7 +730,10 @@ func (t *freezerTable) truncateTail(items uint64) error { } // Update the virtual tail marker and hidden these entries in table. t.itemHidden.Store(items) - if err := writeMetadata(t.meta, newMetadata(items)); err != nil { + + // Update the virtual tail without fsync, otherwise it will significantly + // impact the overall performance. + if err := t.metadata.setVirtualTail(items, false); err != nil { return err } // Hidden items still fall in the current tail file, no data file @@ -664,6 +745,18 @@ func (t *freezerTable) truncateTail(items uint64) error { if t.tailId > newTailId { return fmt.Errorf("invalid index, tail-file %d, item-file %d", t.tailId, newTailId) } + // Sync the table before performing the index tail truncation. A crash may + // occur after truncating the index file without updating the flush offset, + // leaving a dangling offset that points to a position outside the file. + // The offset will be rewound to the end of file during the next run + // automatically and implicitly assumes all the items within the file are + // complete. + // + // Therefore, forcibly flush everything above the offset to ensure this + // assumption is satisfied! + if err := t.doSync(); err != nil { + return err + } // Count how many items can be deleted from the file. var ( newDeleted = items @@ -681,11 +774,6 @@ func (t *freezerTable) truncateTail(items uint64) error { } newDeleted = current } - // Commit the changes of metadata file first before manipulating - // the indexes file. - if err := t.meta.Sync(); err != nil { - return err - } // Close the index file before shorten it. if err := t.index.Close(); err != nil { return err @@ -716,6 +804,21 @@ func (t *freezerTable) truncateTail(items uint64) error { t.itemOffset.Store(newDeleted) t.releaseFilesBefore(t.tailId, true) + // Move the index flush offset backward due to the deletion of an index segment. + // A crash may occur before the offset is updated, leaving a dangling reference + // that points to a position outside the file. If so, the offset will be reset + // to the new end of the file during the next run. + // + // Note, both the index and head data file has been persisted before performing + // tail truncation and all the items in these files are regarded as complete. + shorten := indexEntrySize * int64(newDeleted-deleted) + if t.metadata.flushOffset <= shorten { + return fmt.Errorf("invalid index flush offset: %d, shorten: %d", t.metadata.flushOffset, shorten) + } else { + if err := t.metadata.setFlushOffset(t.metadata.flushOffset-shorten, true); err != nil { + return err + } + } // Retrieve the new size and update the total size counter newSize, err := t.sizeNolock() if err != nil { @@ -725,40 +828,30 @@ func (t *freezerTable) truncateTail(items uint64) error { return nil } -// Close closes all opened files. +// Close closes all opened files and finalizes the freezer table for use. +// This operation must be completed before shutdown to prevent the loss of +// recent writes. func (t *freezerTable) Close() error { t.lock.Lock() defer t.lock.Unlock() + if err := t.doSync(); err != nil { + return err + } var errs []error - doClose := func(f *os.File, sync bool, close bool) { - if sync && !t.readonly { - if err := f.Sync(); err != nil { - errs = append(errs, err) - } - } - if close { - if err := f.Close(); err != nil { - errs = append(errs, err) - } + doClose := func(f *os.File) { + if err := f.Close(); err != nil { + errs = append(errs, err) } } - // Trying to fsync a file opened in rdonly causes "Access denied" - // error on Windows. - doClose(t.index, true, true) - doClose(t.meta, true, true) - - // The preopened non-head data-files are all opened in readonly. - // The head is opened in rw-mode, so we sync it here - but since it's also - // part of t.files, it will be closed in the loop below. - doClose(t.head, true, false) // sync but do not close - + doClose(t.index) + doClose(t.metadata.file) for _, f := range t.files { - doClose(f, false, true) // close but do not sync + doClose(f) } t.index = nil - t.meta = nil t.head = nil + t.metadata.file = nil if errs != nil { return fmt.Errorf("%v", errs) @@ -917,7 +1010,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i defer t.lock.RUnlock() // Ensure the table and the item are accessible - if t.index == nil || t.head == nil || t.meta == nil { + if t.index == nil || t.head == nil || t.metadata.file == nil { return nil, nil, errClosed } var ( @@ -1042,6 +1135,9 @@ func (t *freezerTable) advanceHead() error { t.lock.Lock() defer t.lock.Unlock() + if err := t.doSync(); err != nil { + return err + } // We open the next file in truncated mode -- if this file already // exists, we need to start over from scratch on it. nextID := t.headId + 1 @@ -1069,7 +1165,18 @@ func (t *freezerTable) advanceHead() error { func (t *freezerTable) Sync() error { t.lock.Lock() defer t.lock.Unlock() - if t.index == nil || t.head == nil || t.meta == nil { + + return t.doSync() +} + +// doSync is the internal version of Sync which assumes the lock is already held. +func (t *freezerTable) doSync() error { + // Trying to fsync a file opened in rdonly causes "Access denied" + // error on Windows. + if t.readonly { + return nil + } + if t.index == nil || t.head == nil || t.metadata.file == nil { return errClosed } var err error @@ -1078,10 +1185,18 @@ func (t *freezerTable) Sync() error { err = e } } - trackError(t.index.Sync()) - trackError(t.meta.Sync()) trackError(t.head.Sync()) + + // A crash may occur before the offset is updated, leaving the offset + // points to a old position. If so, the extra items above the offset + // will be truncated during the next run. + stat, err := t.index.Stat() + if err != nil { + return err + } + offset := stat.Size() + trackError(t.metadata.setFlushOffset(offset, true)) return err } @@ -1097,13 +1212,8 @@ func (t *freezerTable) dumpIndexString(start, stop int64) string { } func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) { - meta, err := readMetadata(t.meta) - if err != nil { - fmt.Fprintf(w, "Failed to decode freezer table %v\n", err) - return - } - fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version, - t.items.Load(), t.itemOffset.Load(), t.itemHidden.Load()) + fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", + t.metadata.version, t.items.Load(), t.itemOffset.Load(), t.itemHidden.Load()) buf := make([]byte, indexEntrySize) diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index fd6e3cf19..9a72af6cc 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -262,28 +262,28 @@ func TestSnappyDetection(t *testing.T) { f.Close() } - // Open without snappy + // Open with snappy { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, false, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) if err != nil { t.Fatal(err) } - if _, err = f.Retrieve(0); err == nil { + // There should be 255 items + if _, err = f.Retrieve(0xfe); err != nil { f.Close() - t.Fatalf("expected empty table") + t.Fatalf("expected no error, got %v", err) } } - // Open with snappy + // Open without snappy { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, false, false) if err != nil { t.Fatal(err) } - // There should be 255 items - if _, err = f.Retrieve(0xfe); err != nil { + if _, err = f.Retrieve(0); err == nil { f.Close() - t.Fatalf("expected no error, got %v", err) + t.Fatalf("expected empty table") } } } @@ -521,93 +521,53 @@ func TestFreezerOffset(t *testing.T) { fname := fmt.Sprintf("offset-%d", rand.Uint64()) // Fill table - { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) - if err != nil { - t.Fatal(err) - } - - // Write 6 x 20 bytes, splitting out into three files - batch := f.newBatch() - require.NoError(t, batch.AppendRaw(0, getChunk(20, 0xFF))) - require.NoError(t, batch.AppendRaw(1, getChunk(20, 0xEE))) - - require.NoError(t, batch.AppendRaw(2, getChunk(20, 0xdd))) - require.NoError(t, batch.AppendRaw(3, getChunk(20, 0xcc))) - - require.NoError(t, batch.AppendRaw(4, getChunk(20, 0xbb))) - require.NoError(t, batch.AppendRaw(5, getChunk(20, 0xaa))) - require.NoError(t, batch.commit()) - - t.Log(f.dumpIndexString(0, 100)) - f.Close() + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + if err != nil { + t.Fatal(err) } - // Now crop it. - { - // delete files 0 and 1 - for i := 0; i < 2; i++ { - p := filepath.Join(os.TempDir(), fmt.Sprintf("%v.%04d.rdat", fname, i)) - if err := os.Remove(p); err != nil { - t.Fatal(err) - } - } - // Read the index file - p := filepath.Join(os.TempDir(), fmt.Sprintf("%v.ridx", fname)) - indexFile, err := os.OpenFile(p, os.O_RDWR, 0644) - if err != nil { - t.Fatal(err) - } - indexBuf := make([]byte, 7*indexEntrySize) - indexFile.Read(indexBuf) - - // Update the index file, so that we store - // [ file = 2, offset = 4 ] at index zero + // Write 6 x 20 bytes, splitting out into three files + batch := f.newBatch() + require.NoError(t, batch.AppendRaw(0, getChunk(20, 0xFF))) + require.NoError(t, batch.AppendRaw(1, getChunk(20, 0xEE))) - zeroIndex := indexEntry{ - filenum: uint32(2), // First file is 2 - offset: uint32(4), // We have removed four items - } - buf := zeroIndex.append(nil) + require.NoError(t, batch.AppendRaw(2, getChunk(20, 0xdd))) + require.NoError(t, batch.AppendRaw(3, getChunk(20, 0xcc))) - // Overwrite index zero - copy(indexBuf, buf) + require.NoError(t, batch.AppendRaw(4, getChunk(20, 0xbb))) + require.NoError(t, batch.AppendRaw(5, getChunk(20, 0xaa))) + require.NoError(t, batch.commit()) - // Remove the four next indices by overwriting - copy(indexBuf[indexEntrySize:], indexBuf[indexEntrySize*5:]) - indexFile.WriteAt(indexBuf, 0) + t.Log(f.dumpIndexString(0, 100)) - // Need to truncate the moved index items - indexFile.Truncate(indexEntrySize * (1 + 2)) - indexFile.Close() - } + // Now crop it. + f.truncateTail(4) + f.Close() // Now open again - { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) - if err != nil { - t.Fatal(err) - } - defer f.Close() - t.Log(f.dumpIndexString(0, 100)) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + if err != nil { + t.Fatal(err) + } + t.Log(f.dumpIndexString(0, 100)) - // It should allow writing item 6. - batch := f.newBatch() - require.NoError(t, batch.AppendRaw(6, getChunk(20, 0x99))) - require.NoError(t, batch.commit()) + // It should allow writing item 6. + batch = f.newBatch() + require.NoError(t, batch.AppendRaw(6, getChunk(20, 0x99))) + require.NoError(t, batch.commit()) - checkRetrieveError(t, f, map[uint64]error{ - 0: errOutOfBounds, - 1: errOutOfBounds, - 2: errOutOfBounds, - 3: errOutOfBounds, - }) - checkRetrieve(t, f, map[uint64][]byte{ - 4: getChunk(20, 0xbb), - 5: getChunk(20, 0xaa), - 6: getChunk(20, 0x99), - }) - } + checkRetrieveError(t, f, map[uint64]error{ + 0: errOutOfBounds, + 1: errOutOfBounds, + 2: errOutOfBounds, + 3: errOutOfBounds, + }) + checkRetrieve(t, f, map[uint64][]byte{ + 4: getChunk(20, 0xbb), + 5: getChunk(20, 0xaa), + 6: getChunk(20, 0x99), + }) + f.Close() // Edit the index again, with a much larger initial offset of 1M. { @@ -1369,45 +1329,63 @@ func TestRandom(t *testing.T) { } func TestIndexValidation(t *testing.T) { - const ( - items = 30 - dataSize = 10 - ) + const dataSize = 10 + garbage := indexEntry{ filenum: 100, offset: 200, } var cases = []struct { - offset int64 - data []byte - expItems int + write int + offset int64 + data []byte + expItems int + hasCorruption bool }{ // extend index file with zero bytes at the end { - offset: (items + 1) * indexEntrySize, + write: 5, + offset: (5 + 1) * indexEntrySize, data: make([]byte, indexEntrySize), - expItems: 30, + expItems: 5, + }, + // extend index file with unaligned zero bytes at the end + { + write: 5, + offset: (5 + 1) * indexEntrySize, + data: make([]byte, indexEntrySize*1.5), + expItems: 5, }, // write garbage in the first non-head item { + write: 5, offset: indexEntrySize, data: garbage.append(nil), expItems: 0, }, - // write garbage in the first non-head item + // write garbage in the middle + { + write: 5, + offset: 3 * indexEntrySize, + data: garbage.append(nil), + expItems: 2, + }, + // fulfill the first data file (but not yet advanced), the zero bytes + // at tail should be truncated. { - offset: (items/2 + 1) * indexEntrySize, + write: 10, + offset: 11 * indexEntrySize, data: garbage.append(nil), - expItems: items / 2, + expItems: 10, }, } for _, c := range cases { fn := fmt.Sprintf("t-%d", rand.Uint64()) - f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 100, true, false) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 10*dataSize, true, false) if err != nil { t.Fatal(err) } - writeChunks(t, f, items, dataSize) + writeChunks(t, f, c.write, dataSize) // write corrupted data f.index.WriteAt(c.data, c.offset) @@ -1421,10 +1399,10 @@ func TestIndexValidation(t *testing.T) { for i := 0; i < c.expItems; i++ { exp := getChunk(10, i) got, err := f.Retrieve(uint64(i)) - if err != nil { + if err != nil && !c.hasCorruption { t.Fatalf("Failed to read from table, %v", err) } - if !bytes.Equal(exp, got) { + if !bytes.Equal(exp, got) && !c.hasCorruption { t.Fatalf("Unexpected item data, want: %v, got: %v", exp, got) } } @@ -1433,3 +1411,163 @@ func TestIndexValidation(t *testing.T) { } } } + +// TestFlushOffsetTracking tests the flush offset tracking. The offset moving +// in the test is mostly triggered by the advanceHead (new data file) and +// heda/tail truncation. +func TestFlushOffsetTracking(t *testing.T) { + const ( + items = 35 + dataSize = 10 + fileSize = 100 + ) + fn := fmt.Sprintf("t-%d", rand.Uint64()) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + if err != nil { + t.Fatal(err) + } + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(5 items, non-full) + writeChunks(t, f, items, dataSize) + + var cases = []struct { + op func(*freezerTable) + offset int64 + }{ + { + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(5 items, non-full) + func(f *freezerTable) {}, // no-op + 31 * indexEntrySize, + }, + { + // Write more items to fulfill the newest data file, but the file advance + // is not triggered. + + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(10 items, full) + func(f *freezerTable) { + batch := f.newBatch() + for i := 0; i < 5; i++ { + batch.AppendRaw(items+uint64(i), make([]byte, dataSize)) + } + batch.commit() + }, + 31 * indexEntrySize, + }, + { + // Write more items to trigger the data file advance + + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(10 items) -> F5(1 item) + func(f *freezerTable) { + batch := f.newBatch() + batch.AppendRaw(items+5, make([]byte, dataSize)) + batch.commit() + }, + 41 * indexEntrySize, + }, + { + // Head truncate + + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(10 items) -> F5(0 item) + func(f *freezerTable) { + f.truncateHead(items + 5) + }, + 41 * indexEntrySize, + }, + { + // Tail truncate + + // Data files: + // F1(1 hidden, 9 visible) -> F2(10 items) -> F3(10 items) -> F4(10 items) -> F5(0 item) + func(f *freezerTable) { + f.truncateTail(1) + }, + 41 * indexEntrySize, + }, + { + // Tail truncate + + // Data files: + // F2(10 items) -> F3(10 items) -> F4(10 items) -> F5(0 item) + func(f *freezerTable) { + f.truncateTail(10) + }, + 31 * indexEntrySize, + }, + { + // Tail truncate + + // Data files: + // F4(10 items) -> F5(0 item) + func(f *freezerTable) { + f.truncateTail(30) + }, + 11 * indexEntrySize, + }, + { + // Head truncate + + // Data files: + // F4(9 items) + func(f *freezerTable) { + f.truncateHead(items + 4) + }, + 10 * indexEntrySize, + }, + } + for _, c := range cases { + c.op(f) + if f.metadata.flushOffset != c.offset { + t.Fatalf("Unexpected index flush offset, want: %d, got: %d", c.offset, f.metadata.flushOffset) + } + } +} + +func TestTailTruncationCrash(t *testing.T) { + const ( + items = 35 + dataSize = 10 + fileSize = 100 + ) + fn := fmt.Sprintf("t-%d", rand.Uint64()) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + if err != nil { + t.Fatal(err) + } + // Data files: + // F1(10 items) -> F2(10 items) -> F3(10 items) -> F4(5 items, non-full) + writeChunks(t, f, items, dataSize) + + // The latest 5 items are not persisted yet + if f.metadata.flushOffset != 31*indexEntrySize { + t.Fatalf("Unexpected index flush offset, want: %d, got: %d", 31*indexEntrySize, f.metadata.flushOffset) + } + + f.truncateTail(5) + if f.metadata.flushOffset != 31*indexEntrySize { + t.Fatalf("Unexpected index flush offset, want: %d, got: %d", 31*indexEntrySize, f.metadata.flushOffset) + } + + // Truncate the first 10 items which results in the first data file + // being removed. The offset should be moved to 26*indexEntrySize. + f.truncateTail(10) + if f.metadata.flushOffset != 26*indexEntrySize { + t.Fatalf("Unexpected index flush offset, want: %d, got: %d", 26*indexEntrySize, f.metadata.flushOffset) + } + + // Write the offset back to 31*indexEntrySize to simulate a crash + // which occurs after truncating the index file without updating + // the offset + f.metadata.setFlushOffset(31*indexEntrySize, true) + + f, err = newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + if err != nil { + t.Fatal(err) + } + if f.metadata.flushOffset != 26*indexEntrySize { + t.Fatalf("Unexpected index flush offset, want: %d, got: %d", 26*indexEntrySize, f.metadata.flushOffset) + } +} From a8e41bf4f7e38650ef914a9e92f50056c5967466 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 4 Feb 2025 14:22:30 +0100 Subject: [PATCH 117/354] core: copy genesis before modifying (#31097) This PR fixes a data race in SetupGenesisWithOverride. --- core/genesis.go | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 0ce40faf4..e3cbd48de 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -77,6 +77,19 @@ type Genesis struct { BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844 } +// copy copies the genesis. +func (g *Genesis) copy() *Genesis { + if g != nil { + cpy := *g + if g.Config != nil { + conf := *g.Config + cpy.Config = &conf + } + return &cpy + } + return nil +} + func ReadGenesis(db ethdb.Database) (*Genesis, error) { var genesis Genesis stored := rawdb.ReadCanonicalHash(db, 0) @@ -250,21 +263,17 @@ type ChainOverrides struct { } // apply applies the chain overrides on the supplied chain config. -func (o *ChainOverrides) apply(cfg *params.ChainConfig) (*params.ChainConfig, error) { +func (o *ChainOverrides) apply(cfg *params.ChainConfig) error { if o == nil || cfg == nil { - return cfg, nil + return nil } - cpy := *cfg if o.OverrideCancun != nil { - cpy.CancunTime = o.OverrideCancun + cfg.CancunTime = o.OverrideCancun } if o.OverrideVerkle != nil { - cpy.VerkleTime = o.OverrideVerkle + cfg.VerkleTime = o.OverrideVerkle } - if err := cpy.CheckConfigForkOrder(); err != nil { - return nil, err - } - return &cpy, nil + return cfg.CheckConfigForkOrder() } // SetupGenesisBlock writes or updates the genesis block in db. @@ -283,6 +292,8 @@ func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Gene } func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { + // Copy the genesis, so we can operate on a copy. + genesis = genesis.copy() // Sanitize the supplied genesis, ensuring it has the associated chain // config attached. if genesis != nil && genesis.Config == nil { @@ -297,17 +308,15 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g } else { log.Info("Writing custom genesis block") } - chainCfg, err := overrides.apply(genesis.Config) - if err != nil { + if err := overrides.apply(genesis.Config); err != nil { return nil, common.Hash{}, nil, err } - genesis.Config = chainCfg block, err := genesis.Commit(db, triedb) if err != nil { return nil, common.Hash{}, nil, err } - return chainCfg, block.Hash(), nil, nil + return genesis.Config, block.Hash(), nil, nil } // Commit the genesis if the genesis block exists in the ancient database // but the key-value database is empty without initializing the genesis @@ -324,11 +333,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g } else { log.Info("Writing custom genesis block") } - chainCfg, err := overrides.apply(genesis.Config) - if err != nil { + if err := overrides.apply(genesis.Config); err != nil { return nil, common.Hash{}, nil, err } - genesis.Config = chainCfg if hash := genesis.ToBlock().Hash(); hash != ghash { return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} @@ -337,17 +344,15 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g if err != nil { return nil, common.Hash{}, nil, err } - return chainCfg, block.Hash(), nil, nil + return genesis.Config, block.Hash(), nil, nil } // The genesis block has already been committed previously. Verify that the // provided genesis with chain overrides matches the existing one, and update // the stored chain config if necessary. if genesis != nil { - chainCfg, err := overrides.apply(genesis.Config) - if err != nil { + if err := overrides.apply(genesis.Config); err != nil { return nil, common.Hash{}, nil, err } - genesis.Config = chainCfg if hash := genesis.ToBlock().Hash(); hash != ghash { return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} From 726b589391a78d68c90129791835934cd8ab1fed Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 4 Feb 2025 15:29:51 +0100 Subject: [PATCH 118/354] params: start osaka fork (#31125) This PR defines the Osaka fork. An easy first step to start our work on the next hardfork (This is needed for EOF testing as well) --------- Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- core/genesis_test.go | 1 + core/vm/jump_table_export.go | 4 +++- eth/tracers/api.go | 4 ++++ params/config.go | 35 ++++++++++++++++++++++------ params/forks/forks.go | 1 + tests/init.go | 44 ++++++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 8 deletions(-) diff --git a/core/genesis_test.go b/core/genesis_test.go index 93dc34487..56386bfec 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -279,6 +279,7 @@ func TestVerkleGenesisCommit(t *testing.T) { ShanghaiTime: &verkleTime, CancunTime: &verkleTime, PragueTime: &verkleTime, + OsakaTime: &verkleTime, VerkleTime: &verkleTime, TerminalTotalDifficulty: big.NewInt(0), EnableVerkleAtGenesis: true, diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index b1d82fc14..12a5c7775 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -28,8 +28,10 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) { switch { case rules.IsVerkle: return newCancunInstructionSet(), errors.New("verkle-fork not defined yet") + case rules.IsOsaka: + return newPragueInstructionSet(), errors.New("osaka-fork not defined yet") case rules.IsPrague: - return newCancunInstructionSet(), errors.New("prague-fork not defined yet") + return newPragueInstructionSet(), nil case rules.IsCancun: return newCancunInstructionSet(), nil case rules.IsNeoXDKG: diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 45e02ffba..224f31ac2 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -1096,6 +1096,10 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.PragueTime = timestamp canon = false } + if timestamp := override.OsakaTime; timestamp != nil { + copy.OsakaTime = timestamp + canon = false + } if timestamp := override.VerkleTime; timestamp != nil { copy.VerkleTime = timestamp canon = false diff --git a/params/config.go b/params/config.go index e228ac1b1..442e77b3b 100644 --- a/params/config.go +++ b/params/config.go @@ -133,6 +133,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, Ethash: new(EthashConfig), Clique: nil, @@ -182,6 +183,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: big.NewInt(math.MaxInt64), Ethash: nil, @@ -211,6 +213,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: big.NewInt(math.MaxInt64), Ethash: new(EthashConfig), @@ -240,6 +243,7 @@ var ( ShanghaiTime: newUint64(0), CancunTime: newUint64(0), PragueTime: newUint64(0), + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: big.NewInt(0), Ethash: new(EthashConfig), @@ -269,6 +273,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: big.NewInt(math.MaxInt64), Ethash: new(EthashConfig), @@ -321,6 +326,7 @@ type ChainConfig struct { NeoXEthSigBlock *big.Int `json:"neoXEthSigBlock,omitempty"` // Block-based switch to fix block signature from NeoXAMEVBlock (nil = no fork, 0 = already activated) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) + OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -459,6 +465,9 @@ func (c *ChainConfig) Description() string { if c.PragueTime != nil { banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) } + if c.OsakaTime != nil { + banner += fmt.Sprintf(" - Osaka: @%-10v\n", *c.OsakaTime) + } if c.VerkleTime != nil { banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime) } @@ -575,6 +584,11 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } +// IsOsaka returns whether time is either equal to the Osaka fork time or greater. +func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time) +} + // IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) @@ -656,6 +670,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "neoXEthSigBlock", block: c.NeoXEthSigBlock, optional: true}, {name: "cancunTime", timestamp: c.CancunTime, optional: true}, {name: "pragueTime", timestamp: c.PragueTime, optional: true}, + {name: "osakaTime", timestamp: c.OsakaTime, optional: true}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, } { if lastFork.name != "" { @@ -769,6 +784,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) { return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) } + if isForkTimestampIncompatible(c.OsakaTime, newcfg.OsakaTime, headTimestamp) { + return newTimestampCompatError("Osaka fork timestamp", c.OsakaTime, newcfg.OsakaTime) + } if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) } @@ -815,6 +833,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { london := c.LondonBlock switch { + case c.IsOsaka(london, time): + return forks.Osaka case c.IsPrague(london, time): return forks.Prague case c.IsCancun(london, time): @@ -961,13 +981,13 @@ func (err *ConfigCompatError) Error() string { // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { - ChainID *big.Int - IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool - IsEIP2929, IsEIP4762 bool - IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool - IsBerlin, IsLondon bool - IsMerge, IsShanghai, IsNeoXDKG, IsCancun, IsPrague bool - IsVerkle bool + ChainID *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool + IsEIP2929, IsEIP4762 bool + IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool + IsBerlin, IsLondon bool + IsMerge, IsShanghai, IsNeoXDKG, IsCancun, IsPrague, IsOsaka bool + IsVerkle bool } // Rules ensures c's ChainID is not nil. @@ -995,6 +1015,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsNeoXDKG: c.IsNeoXDKG(num), IsCancun: c.IsCancun(num, timestamp), IsPrague: c.IsPrague(num, timestamp), + IsOsaka: c.IsOsaka(num, timestamp), IsVerkle: isVerkle, IsEIP4762: isVerkle, } diff --git a/params/forks/forks.go b/params/forks/forks.go index 4f50ff5ae..2d44e13b0 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -39,4 +39,5 @@ const ( Shanghai Cancun Prague + Osaka ) diff --git a/tests/init.go b/tests/init.go index 918e04ec2..18447ca6b 100644 --- a/tests/init.go +++ b/tests/init.go @@ -416,6 +416,50 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, }, + "Osaka": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(0), + OsakaTime: u64(0), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + }, + "PragueToOsakaAtTime15k": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(0), + OsakaTime: u64(15_000), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + }, } // AvailableForks returns the set of defined fork names From d32fea96de1c60316cf3ba6fecc35d4e6851f796 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 4 Feb 2025 07:43:18 -0700 Subject: [PATCH 119/354] params,core: add max and target value to chain config (#31002) Implements [EIP-7840](https://github.com/ethereum/EIPs/pull/9129) and [EIP-7691](https://github.com/ethereum/EIPs/blob/d96625a4dcbbe2572fa006f062bd02b4582eefd5/EIPS/eip-7691.md). --------- Co-authored-by: Marius van der Wijden Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/suite.go | 2 +- .../internal/ethtest/testdata/genesis.json | 11 +- cmd/evm/internal/t8ntool/execution.go | 22 ++- consensus/beacon/consensus.go | 2 +- consensus/misc/eip4844/eip4844.go | 108 +++++++++--- consensus/misc/eip4844/eip4844_test.go | 38 +++-- core/blockchain.go | 5 +- core/chain_makers.go | 18 +- core/chain_makers_test.go | 6 +- core/evm.go | 6 +- core/genesis_test.go | 5 + core/rawdb/accessors_chain.go | 2 +- core/state_processor_test.go | 27 +-- core/txpool/blobpool/blobpool.go | 22 +-- core/txpool/blobpool/blobpool_test.go | 158 +++++++++++++++++- core/txpool/blobpool/evictheap_test.go | 34 ++-- core/txpool/blobpool/limbo.go | 4 +- core/txpool/blobpool/priority_test.go | 6 +- core/txpool/blobpool/slotter.go | 4 +- core/txpool/blobpool/slotter_test.go | 2 +- core/txpool/validation.go | 6 +- core/verkle_witness_test.go | 8 +- core/vm/runtime/runtime_test.go | 4 + eth/api_backend.go | 2 +- eth/catalyst/api_test.go | 3 + eth/fetcher/tx_fetcher_test.go | 6 +- eth/gasprice/feehistory.go | 10 +- eth/gasprice/gasprice_test.go | 1 + eth/tracers/internal/tracetest/supply_test.go | 1 + .../testdata/call_tracer/blob_tx.json | 9 +- .../testdata/prestate_tracer/blob_tx.json | 13 +- .../testdata/prestate_tracer/setcode_tx.json | 14 +- eth/tracers/internal/tracetest/util.go | 6 +- eth/tracers/live/supply.go | 26 +-- ethclient/ethclient_test.go | 9 +- internal/ethapi/api.go | 5 + internal/ethapi/simulate.go | 8 +- internal/ethapi/transaction_args.go | 22 +-- internal/ethapi/transaction_args_test.go | 1 + miner/worker.go | 29 ++-- params/config.go | 98 ++++++++++- params/protocol_params.go | 4 - privnet/four/genesis_privnet.json | 7 + privnet/seven/genesis_privnet.json | 7 + privnet/single/genesis_privnet.json | 7 + tests/init.go | 14 ++ tests/state_test.go | 2 +- tests/state_test_util.go | 34 +++- 48 files changed, 634 insertions(+), 204 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 12dc5711a..2f1731b60 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -743,7 +743,7 @@ func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Tra GasTipCap: uint256.NewInt(1), GasFeeCap: uint256.MustFromBig(s.chain.Head().BaseFee()), Gas: 100000, - BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(*s.chain.Head().ExcessBlobGas())), + BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(s.chain.config, s.chain.Head().Header())), BlobHashes: makeSidecar(blobdata...).BlobHashes(), Sidecar: makeSidecar(blobdata...), } diff --git a/cmd/devp2p/internal/ethtest/testdata/genesis.json b/cmd/devp2p/internal/ethtest/testdata/genesis.json index 4cfebdcac..ace2f7881 100644 --- a/cmd/devp2p/internal/ethtest/testdata/genesis.json +++ b/cmd/devp2p/internal/ethtest/testdata/genesis.json @@ -18,7 +18,14 @@ "shanghaiTime": 780, "cancunTime": 840, "terminalTotalDifficulty": 9454784, - "ethash": {} + "ethash": {}, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + } }, "nonce": "0x0", "timestamp": "0x0", @@ -108,4 +115,4 @@ "baseFeePerGas": null, "excessBlobGas": null, "blobGasUsed": null -} \ No newline at end of file +} diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index d365acac1..a7b68c074 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -180,15 +180,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, var excessBlobGas uint64 if pre.Env.ExcessBlobGas != nil { excessBlobGas = *pre.Env.ExcessBlobGas - vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + header := &types.Header{ + Time: pre.Env.Timestamp, + ExcessBlobGas: pre.Env.ExcessBlobGas, + } + vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header) } else { // If it is not explicitly defined, but we have the parent values, we try // to calculate it ourselves. parentExcessBlobGas := pre.Env.ParentExcessBlobGas parentBlobGasUsed := pre.Env.ParentBlobGasUsed if parentExcessBlobGas != nil && parentBlobGasUsed != nil { - excessBlobGas = eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed) - vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + parent := &types.Header{ + Time: pre.Env.ParentTimestamp, + ExcessBlobGas: pre.Env.ParentExcessBlobGas, + BlobGasUsed: pre.Env.ParentBlobGasUsed, + } + excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent) + header := &types.Header{ + Time: pre.Env.Timestamp, + ExcessBlobGas: &excessBlobGas, + } + vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header) } } // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's @@ -238,7 +251,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txBlobGas := uint64(0) if tx.Type() == types.BlobTxType { txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes())) - if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max { + max := eip4844.MaxBlobGasPerBlock(chainConfig, pre.Env.Timestamp) + if used := blobGasUsed + txBlobGas; used > max { err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max) log.Warn("rejected tx", "index", i, "err", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 71cf1dbb1..1c614bdbc 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -297,7 +297,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa if header.ParentBeaconRoot == nil { return errors.New("header is missing beaconRoot") } - if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { + if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil { return err } } diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 2dad9a0cd..1d76b21b3 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -23,17 +23,17 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/params/forks" ) var ( - minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) - blobGaspriceUpdateFraction = big.NewInt(params.BlobTxBlobGaspriceUpdateFraction) + minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice) ) // VerifyEIP4844Header verifies the presence of the excessBlobGas field and that // if the current block contains no transactions, the excessBlobGas is updated // accordingly. -func VerifyEIP4844Header(parent, header *types.Header) error { +func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error { // Verify the header is not malformed if header.ExcessBlobGas == nil { return errors.New("header is missing excessBlobGas") @@ -42,14 +42,26 @@ func VerifyEIP4844Header(parent, header *types.Header) error { return errors.New("header is missing blobGasUsed") } // Verify that the blob gas used remains within reasonable limits. - if *header.BlobGasUsed > params.MaxBlobGasPerBlock { - return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock) + maxBlobGas := MaxBlobGasPerBlock(config, header.Time) + if *header.BlobGasUsed > maxBlobGas { + return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas) } if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 { return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } // Verify the excessBlobGas is correct based on the parent header + expectedExcessBlobGas := CalcExcessBlobGas(config, parent) + if *header.ExcessBlobGas != expectedExcessBlobGas { + return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) + } + return nil +} + +// CalcExcessBlobGas calculates the excess blob gas after applying the set of +// blobs on top of the excess blob gas. +func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { var ( + targetGas = uint64(targetBlobsPerBlock(config, parent.Time)) * params.BlobTxBlobGasPerBlob parentExcessBlobGas uint64 parentBlobGasUsed uint64 ) @@ -57,27 +69,85 @@ func VerifyEIP4844Header(parent, header *types.Header) error { parentExcessBlobGas = *parent.ExcessBlobGas parentBlobGasUsed = *parent.BlobGasUsed } - expectedExcessBlobGas := CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) - if *header.ExcessBlobGas != expectedExcessBlobGas { - return fmt.Errorf("invalid excessBlobGas: have %d, want %d, parent excessBlobGas %d, parent blobDataUsed %d", - *header.ExcessBlobGas, expectedExcessBlobGas, parentExcessBlobGas, parentBlobGasUsed) + excessBlobGas := parentExcessBlobGas + parentBlobGasUsed + if excessBlobGas < targetGas { + return 0 } - return nil + return excessBlobGas - targetGas } -// CalcExcessBlobGas calculates the excess blob gas after applying the set of -// blobs on top of the excess blob gas. -func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 { - excessBlobGas := parentExcessBlobGas + parentBlobGasUsed - if excessBlobGas < params.BlobTxTargetBlobGasPerBlock { +// CalcBlobFee calculates the blobfee from the header's excess blob gas field. +func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { + var frac uint64 + switch config.LatestFork(header.Time) { + case forks.Prague: + frac = config.BlobScheduleConfig.Prague.UpdateFraction + case forks.Cancun: + frac = config.BlobScheduleConfig.Cancun.UpdateFraction + default: + panic("calculating blob fee on unsupported fork") + } + return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac)) +} + +// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp. +func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { + if cfg.BlobScheduleConfig == nil { + return 0 + } + var ( + london = cfg.LondonBlock + s = cfg.BlobScheduleConfig + ) + switch { + case cfg.IsPrague(london, time) && s.Prague != nil: + return s.Prague.Max + case cfg.IsCancun(london, time) && s.Cancun != nil: + return s.Cancun.Max + default: return 0 } - return excessBlobGas - params.BlobTxTargetBlobGasPerBlock } -// CalcBlobFee calculates the blobfee from the header's excess blob gas field. -func CalcBlobFee(excessBlobGas uint64) *big.Int { - return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction) +// MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp. +func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 { + return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob +} + +// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the +// configuration, regardless of the currently active fork. +func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { + s := cfg.BlobScheduleConfig + if s == nil { + return 0 + } + switch { + case s.Prague != nil: + return s.Prague.Max + case s.Cancun != nil: + return s.Cancun.Max + default: + return 0 + } +} + +// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp. +func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { + if cfg.BlobScheduleConfig == nil { + return 0 + } + var ( + london = cfg.LondonBlock + s = cfg.BlobScheduleConfig + ) + switch { + case cfg.IsPrague(london, time) && s.Prague != nil: + return s.Prague.Target + case cfg.IsCancun(london, time) && s.Cancun != nil: + return s.Cancun.Target + default: + return 0 + } } // fakeExponential approximates factor * e ** (numerator / denominator) using diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index ec417380f..839ea8df2 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -21,36 +21,48 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) func TestCalcExcessBlobGas(t *testing.T) { + var ( + config = params.MainnetChainConfig + targetBlobs = targetBlobsPerBlock(config, *config.CancunTime) + targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob + ) var tests = []struct { excess uint64 - blobs uint64 + blobs int want uint64 }{ // The excess blob gas should not increase from zero if the used blob // slots are below - or equal - to the target. {0, 0, 0}, {0, 1, 0}, - {0, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, 0}, + {0, targetBlobs, 0}, // If the target blob gas is exceeded, the excessBlobGas should increase // by however much it was overshot - {0, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob}, - {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob + 1}, - {1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 2, 2*params.BlobTxBlobGasPerBlob + 1}, + {0, targetBlobs + 1, params.BlobTxBlobGasPerBlob}, + {1, targetBlobs + 1, params.BlobTxBlobGasPerBlob + 1}, + {1, targetBlobs + 2, 2*params.BlobTxBlobGasPerBlob + 1}, // The excess blob gas should decrease by however much the target was // under-shot, capped at zero. - {params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock}, - {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxTargetBlobGasPerBlock - params.BlobTxBlobGasPerBlob}, - {params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxTargetBlobGasPerBlock - (2 * params.BlobTxBlobGasPerBlob)}, - {params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0}, + {targetBlobGas, targetBlobs, targetBlobGas}, + {targetBlobGas, targetBlobs - 1, targetBlobGas - params.BlobTxBlobGasPerBlob}, + {targetBlobGas, targetBlobs - 2, targetBlobGas - (2 * params.BlobTxBlobGasPerBlob)}, + {params.BlobTxBlobGasPerBlob - 1, targetBlobs - 1, 0}, } for i, tt := range tests { - result := CalcExcessBlobGas(tt.excess, tt.blobs*params.BlobTxBlobGasPerBlob) + blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob + parent := &types.Header{ + Time: *config.CancunTime, + ExcessBlobGas: &tt.excess, + BlobGasUsed: &blobGasUsed, + } + result := CalcExcessBlobGas(config, parent) if result != tt.want { t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) } @@ -58,6 +70,8 @@ func TestCalcExcessBlobGas(t *testing.T) { } func TestCalcBlobFee(t *testing.T) { + zero := uint64(0) + tests := []struct { excessBlobGas uint64 blobfee int64 @@ -68,7 +82,9 @@ func TestCalcBlobFee(t *testing.T) { {10 * 1024 * 1024, 23}, } for i, tt := range tests { - have := CalcBlobFee(tt.excessBlobGas) + config := ¶ms.ChainConfig{LondonBlock: big.NewInt(0), CancunTime: &zero, BlobScheduleConfig: params.DefaultBlobSchedule} + header := &types.Header{ExcessBlobGas: &tt.excessBlobGas} + have := CalcBlobFee(config, header) if have.Int64() != tt.blobfee { t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee) } diff --git a/core/blockchain.go b/core/blockchain.go index f9cab933b..bdad7bbe7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2350,9 +2350,8 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co // processing of a block. These logs are later announced as deleted or reborn. func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { var blobGasPrice *big.Int - excessBlobGas := b.ExcessBlobGas() - if excessBlobGas != nil { - blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas) + if b.ExcessBlobGas() != nil { + blobGasPrice = eip4844.CalcBlobFee(bc.chainConfig, b.Header()) } receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil { diff --git a/core/chain_makers.go b/core/chain_makers.go index 9b750cc0d..22d145c79 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -143,7 +143,9 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti // instruction will panic during execution if it attempts to access a block number outside // of the range created by GenerateChain. func (b *BlockGen) AddTx(tx *types.Transaction) { - b.addTx(nil, vm.Config{}, tx) + // Wrap the chain config in an empty BlockChain object to satisfy ChainContext. + bc := &BlockChain{chainConfig: b.cm.config} + b.addTx(bc, vm.Config{}, tx) } // AddTxWithChain adds a transaction to the generated block. If no coinbase has @@ -445,7 +447,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } var blobGasPrice *big.Int if block.ExcessBlobGas() != nil { - blobGasPrice = eip4844.CalcBlobFee(*block.ExcessBlobGas()) + blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header()) } if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil { panic(err) @@ -548,7 +550,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine } var blobGasPrice *big.Int if block.ExcessBlobGas() != nil { - blobGasPrice = eip4844.CalcBlobFee(*block.ExcessBlobGas()) + blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header()) } if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil { panic(err) @@ -598,15 +600,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi } } if cm.config.IsCancun(header.Number, header.Time) { - var ( - parentExcessBlobGas uint64 - parentBlobGasUsed uint64 - ) - if parent.ExcessBlobGas() != nil { - parentExcessBlobGas = *parent.ExcessBlobGas() - parentBlobGasUsed = *parent.BlobGasUsed() - } - excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed) + excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header()) header.ExcessBlobGas = &excessBlobGas header.BlobGasUsed = new(uint64) header.ParentBeaconRoot = new(common.Hash) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index aa8e3f796..118434819 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -42,7 +42,7 @@ func TestGeneratePOSChain(t *testing.T) { aa = common.Address{0xaa} bb = common.Address{0xbb} funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether)) - config = *params.AllEthashProtocolChanges + config = *params.MergedTestChainConfig gspec = &Genesis{ Config: &config, Alloc: types.GenesisAlloc{ @@ -57,10 +57,6 @@ func TestGeneratePOSChain(t *testing.T) { db = rawdb.NewMemoryDatabase() ) - config.TerminalTotalDifficulty = common.Big0 - config.ShanghaiTime = u64(0) - config.CancunTime = u64(0) - // init 0xaa with some storage elements storage := make(map[common.Hash]common.Hash) storage[common.Hash{0x00}] = common.Hash{0x00} diff --git a/core/evm.go b/core/evm.go index 5d3c454d7..41b4e6ac5 100644 --- a/core/evm.go +++ b/core/evm.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -36,6 +37,9 @@ type ChainContext interface { // GetHeader returns the header corresponding to the hash/number argument pair. GetHeader(common.Hash, uint64) *types.Header + + // Config returns the chain's configuration. + Config() *params.ChainConfig } // NewEVMBlockContext creates a new context for use in the EVM. @@ -57,7 +61,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common baseFee = new(big.Int).Set(header.BaseFee) } if header.ExcessBlobGas != nil { - blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) + blobBaseFee = eip4844.CalcBlobFee(chain.Config(), header) } if header.Difficulty.Sign() == 0 { random = &header.MixDigest diff --git a/core/genesis_test.go b/core/genesis_test.go index 56386bfec..e8c7af58b 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -285,6 +285,11 @@ func TestVerkleGenesisCommit(t *testing.T) { EnableVerkleAtGenesis: true, Ethash: nil, Clique: nil, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Verkle: params.DefaultPragueBlobConfig, + }, } genesis := &Genesis{ diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index c4735c850..ef33d5f63 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -635,7 +635,7 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, // Compute effective blob gas price. var blobGasPrice *big.Int if header != nil && header.ExcessBlobGas != nil { - blobGasPrice = eip4844.CalcBlobFee(*header.ExcessBlobGas) + blobGasPrice = eip4844.CalcBlobFee(config, header) } if err := receipts.DeriveFields(config, hash, number, time, baseFee, blobGasPrice, body.Transactions); err != nil { log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 70a2509b2..8b0ba3aea 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -46,25 +46,7 @@ func u64(val uint64) *uint64 { return &val } // contain invalid transactions func TestStateProcessorErrors(t *testing.T) { var ( - config = ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Ethash: new(params.EthashConfig), - TerminalTotalDifficulty: big.NewInt(0), - ShanghaiTime: new(uint64), - CancunTime: new(uint64), - PragueTime: new(uint64), - } + config = params.MergedTestChainConfig signer = types.LatestSigner(config) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020") @@ -425,12 +407,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) if config.IsCancun(header.Number, header.Time) { - var pExcess, pUsed = uint64(0), uint64(0) - if parent.ExcessBlobGas() != nil { - pExcess = *parent.ExcessBlobGas() - pUsed = *parent.BlobGasUsed() - } - excess := eip4844.CalcExcessBlobGas(pExcess, pUsed) + excess := eip4844.CalcExcessBlobGas(config, parent.Header()) used := uint64(nBlobs * params.BlobTxBlobGasPerBlob) header.ExcessBlobGas = &excess header.BlobGasUsed = &used diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 7a55ad079..58840fa05 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -51,11 +51,6 @@ const ( // transaction. There can be multiple of these embedded into a single tx. blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement - // maxBlobsPerTransaction is the maximum number of blobs a single transaction - // is allowed to contain. Whilst the spec states it's unlimited, the block - // data slots are protocol bound, which implicitly also limit this. - maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob - // txAvgSize is an approximate byte size of a transaction metadata to avoid // tiny overflows causing all txs to move a shelf higher, wasting disk space. txAvgSize = 4 * 1024 @@ -223,6 +218,11 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta { // very relaxed ones can be included even if the fees go up, when the closer // ones could already be invalid. // +// - Because the maximum number of blobs allowed in a block can change per +// fork, the pool is designed to handle the maximum number of blobs allowed +// in the chain's latest defined fork -- even if it isn't active. This +// avoids needing to upgrade the database around the fork boundary. +// // When the pool eventually reaches saturation, some old transactions - that may // never execute - will need to be evicted in favor of newer ones. The eviction // strategy is quite complex: @@ -396,7 +396,8 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres fails = append(fails, id) } } - store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, newSlotter(), index) + slotter := newSlotter(eip4844.LatestMaxBlobsPerBlock(p.chain.Config())) + store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index) if err != nil { return err } @@ -423,13 +424,13 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) ) if p.head.ExcessBlobGas != nil { - blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas)) + blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(p.chain.Config(), p.head)) } p.evict = newPriceHeap(basefee, blobfee, p.index) // Pool initialized, attach the blob limbo to it to track blobs included // recently but not yet finalized - p.limbo, err = newLimbo(limbodir) + p.limbo, err = newLimbo(limbodir, eip4844.LatestMaxBlobsPerBlock(p.chain.Config())) if err != nil { p.Close() return err @@ -843,7 +844,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) { blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice)) ) if newHead.ExcessBlobGas != nil { - blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*newHead.ExcessBlobGas)) + blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(p.chain.Config(), newHead)) } p.evict.reinit(basefee, blobfee, false) @@ -1607,7 +1608,8 @@ func (p *BlobPool) updateStorageMetrics() { metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots)) metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots)) - if shelf.SlotSize/blobSize > maxBlobsPerTransaction { + maxBlobs := eip4844.LatestMaxBlobsPerBlock(p.chain.Config()) + if shelf.SlotSize/blobSize > uint32(maxBlobs) { oversizedDataused += slotDataused oversizedDatagaps += slotDatagaps oversizedSlotused += shelf.FilledSlots diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 3d90ec441..0187e8d9a 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -51,8 +51,10 @@ var ( testBlobVHashes [][32]byte ) +const testMaxBlobsPerBlock = 6 + func init() { - for i := 0; i < 10; i++ { + for i := 0; i < 24; i++ { testBlob := &kzg4844.Blob{byte(i)} testBlobs = append(testBlobs, testBlob) @@ -121,7 +123,12 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { mid := new(big.Int).Add(lo, hi) mid.Div(mid, big.NewInt(2)) - if eip4844.CalcBlobFee(mid.Uint64()).Cmp(bc.blobfee.ToBig()) > 0 { + tmp := mid.Uint64() + if eip4844.CalcBlobFee(bc.Config(), &types.Header{ + Number: blockNumber, + Time: blockTime, + ExcessBlobGas: &tmp, + }).Cmp(bc.blobfee.ToBig()) > 0 { hi = mid } else { lo = mid @@ -194,10 +201,43 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) } +// makeMultiBlobTx is a utility method to construct a ramdom blob tx with +// certain number of blobs in its sidecar. +func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction { + var ( + blobs []kzg4844.Blob + blobHashes []common.Hash + commitments []kzg4844.Commitment + proofs []kzg4844.Proof + ) + for i := 0; i < blobCount; i++ { + blobs = append(blobs, *testBlobs[i]) + commitments = append(commitments, testBlobCommits[i]) + proofs = append(proofs, testBlobProofs[i]) + blobHashes = append(blobHashes, testBlobVHashes[i]) + } + blobtx := &types.BlobTx{ + ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID), + Nonce: nonce, + GasTipCap: uint256.NewInt(gasTipCap), + GasFeeCap: uint256.NewInt(gasFeeCap), + Gas: 21000, + BlobFeeCap: uint256.NewInt(blobFeeCap), + BlobHashes: blobHashes, + Value: uint256.NewInt(100), + Sidecar: &types.BlobTxSidecar{ + Blobs: blobs, + Commitments: commitments, + Proofs: proofs, + }, + } + return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx) +} + // makeUnsignedTx is a utility method to construct a random blob transaction // without signing it. func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx { - return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rand.Intn(len(testBlobs))) + return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rnd.Intn(len(testBlobs))) } // makeUnsignedTx is a utility method to construct a random blob transaction @@ -415,7 +455,7 @@ func TestOpenDrops(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a malformed transaction to verify that decoding errors (or format // changes) are handled gracefully (case 1) @@ -738,7 +778,7 @@ func TestOpenIndex(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a sequence of transactions with varying price points to check that // the cumulative minimum will be maintained. @@ -827,7 +867,7 @@ func TestOpenHeap(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a few transactions from a few accounts. To remove randomness from // the heap initialization, use a deterministic account/tx/priority ordering. @@ -914,7 +954,7 @@ func TestOpenCap(t *testing.T) { defer os.RemoveAll(storage) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert a few transactions from a few accounts var ( @@ -992,6 +1032,108 @@ func TestOpenCap(t *testing.T) { } } +// TestChangingSlotterSize attempts to mimic a scenario where the max blob count +// of the pool is increased. This would happen during a client release where a +// new fork is added with a max blob count higher than the previous fork. We +// want to make sure transactions a persisted between those runs. +func TestChangingSlotterSize(t *testing.T) { + //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) + + // Create a temporary folder for the persistent backend + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil) + + // Create transactions from a few accounts. + var ( + key1, _ = crypto.GenerateKey() + key2, _ = crypto.GenerateKey() + key3, _ = crypto.GenerateKey() + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2) + tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3) + + blob1, _ = rlp.EncodeToBytes(tx1) + blob2, _ = rlp.EncodeToBytes(tx2) + ) + + // Write the two safely sized txs to store. note: although the store is + // configured for a blob count of 6, it can also support around ~1mb of call + // data - all this to say that we aren't using the the absolute largest shelf + // available. + store.Put(blob1) + store.Put(blob2) + store.Close() + + // Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24. + for _, maxBlobs := range []int{6, 24} { + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) + statedb.Commit(0, true, false) + + // Make custom chain config where the max blob count changes based on the loop variable. + cancunTime := uint64(0) + config := ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + LondonBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + CancunTime: &cancunTime, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: maxBlobs / 2, + Max: maxBlobs, + UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction, + }, + }, + } + chain := &testBlockChain{ + config: config, + basefee: uint256.NewInt(1050), + blobfee: uint256.NewInt(105), + statedb: statedb, + } + pool := New(Config{Datadir: storage}, chain) + if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + t.Fatalf("failed to create blob pool: %v", err) + } + + // Try to add the big blob tx. In the initial iteration it should overflow + // the pool. On the subsequent iteration it should be accepted. + errs := pool.Add([]*types.Transaction{tx3}, false, true) + if _, ok := pool.index[addr3]; ok && maxBlobs == 6 { + t.Errorf("expected insert of oversized blob tx to fail: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0]) + } else if !ok && maxBlobs == 10 { + t.Errorf("expected insert of oversized blob tx to succeed: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0]) + } + + // Verify the regular two txs are always available. + if got := pool.Get(tx1.Hash()); got == nil { + t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1) + } + if got := pool.Get(tx2.Hash()); got == nil { + t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2) + } + + // Verify all the calculated pool internals. Interestingly, this is **not** + // a duplication of the above checks, this actually validates the verifier + // using the above already hard coded checks. + // + // Do not remove this, nor alter the above to be generic. + verifyPoolInternals(t, pool) + + pool.Close() + } +} + // Tests that adding transaction will correctly store it in the persistent store // and update all the indices. // @@ -1369,7 +1511,7 @@ func TestAdd(t *testing.T) { defer os.RemoveAll(storage) // late defer, still ok os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) - store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil) + store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) // Insert the seed transactions for the pool startup var ( diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go index b03dd83d6..e39293240 100644 --- a/core/txpool/blobpool/evictheap_test.go +++ b/core/txpool/blobpool/evictheap_test.go @@ -26,7 +26,7 @@ import ( "github.com/holiman/uint256" ) -var rand = mrand.New(mrand.NewSource(1)) +var rnd = mrand.New(mrand.NewSource(1)) // verifyHeapInternals verifies that all accounts present in the index are also // present in the heap and internals are consistent across various indices. @@ -193,12 +193,12 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { index := make(map[common.Address][]*blobTxMeta) for i := 0; i < int(blobs); i++ { var addr common.Address - rand.Read(addr[:]) + rnd.Read(addr[:]) var ( - execTip = uint256.NewInt(rand.Uint64()) - execFee = uint256.NewInt(rand.Uint64()) - blobFee = uint256.NewInt(rand.Uint64()) + execTip = uint256.NewInt(rnd.Uint64()) + execFee = uint256.NewInt(rnd.Uint64()) + blobFee = uint256.NewInt(rnd.Uint64()) basefeeJumps = dynamicFeeJumps(execFee) blobfeeJumps = dynamicFeeJumps(blobFee) @@ -218,13 +218,13 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { }} } // Create a price heap and reinit it over and over - heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) + heap := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index) basefees := make([]*uint256.Int, b.N) blobfees := make([]*uint256.Int, b.N) for i := 0; i < b.N; i++ { - basefees[i] = uint256.NewInt(rand.Uint64()) - blobfees[i] = uint256.NewInt(rand.Uint64()) + basefees[i] = uint256.NewInt(rnd.Uint64()) + blobfees[i] = uint256.NewInt(rnd.Uint64()) } b.ResetTimer() b.ReportAllocs() @@ -269,12 +269,12 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { index := make(map[common.Address][]*blobTxMeta) for i := 0; i < int(blobs); i++ { var addr common.Address - rand.Read(addr[:]) + rnd.Read(addr[:]) var ( - execTip = uint256.NewInt(rand.Uint64()) - execFee = uint256.NewInt(rand.Uint64()) - blobFee = uint256.NewInt(rand.Uint64()) + execTip = uint256.NewInt(rnd.Uint64()) + execFee = uint256.NewInt(rnd.Uint64()) + blobFee = uint256.NewInt(rnd.Uint64()) basefeeJumps = dynamicFeeJumps(execFee) blobfeeJumps = dynamicFeeJumps(blobFee) @@ -294,18 +294,18 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { }} } // Create a price heap and overflow it over and over - evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) + evict := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index) var ( addrs = make([]common.Address, b.N) metas = make([]*blobTxMeta, b.N) ) for i := 0; i < b.N; i++ { - rand.Read(addrs[i][:]) + rnd.Read(addrs[i][:]) var ( - execTip = uint256.NewInt(rand.Uint64()) - execFee = uint256.NewInt(rand.Uint64()) - blobFee = uint256.NewInt(rand.Uint64()) + execTip = uint256.NewInt(rnd.Uint64()) + execFee = uint256.NewInt(rnd.Uint64()) + blobFee = uint256.NewInt(rnd.Uint64()) basefeeJumps = dynamicFeeJumps(execFee) blobfeeJumps = dynamicFeeJumps(blobFee) diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index 32381a393..d5992f290 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -48,7 +48,7 @@ type limbo struct { } // newLimbo opens and indexes a set of limboed blob transactions. -func newLimbo(datadir string) (*limbo, error) { +func newLimbo(datadir string, maxBlobsPerTransaction int) (*limbo, error) { l := &limbo{ index: make(map[common.Hash]uint64), groups: make(map[uint64]map[uint64]common.Hash), @@ -60,7 +60,7 @@ func newLimbo(datadir string) (*limbo, error) { fails = append(fails, id) } } - store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(), index) + store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(maxBlobsPerTransaction), index) if err != nil { return nil, err } diff --git a/core/txpool/blobpool/priority_test.go b/core/txpool/blobpool/priority_test.go index cf0e0454a..1eaee6d7d 100644 --- a/core/txpool/blobpool/priority_test.go +++ b/core/txpool/blobpool/priority_test.go @@ -52,7 +52,7 @@ func TestPriorityCalculation(t *testing.T) { func BenchmarkDynamicFeeJumpCalculation(b *testing.B) { fees := make([]*uint256.Int, b.N) for i := 0; i < b.N; i++ { - fees[i] = uint256.NewInt(rand.Uint64()) + fees[i] = uint256.NewInt(rnd.Uint64()) } b.ResetTimer() b.ReportAllocs() @@ -76,8 +76,8 @@ func BenchmarkPriorityCalculation(b *testing.B) { txBasefeeJumps := make([]float64, b.N) txBlobfeeJumps := make([]float64, b.N) for i := 0; i < b.N; i++ { - txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64())) - txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64())) + txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64())) + txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64())) } b.ResetTimer() b.ReportAllocs() diff --git a/core/txpool/blobpool/slotter.go b/core/txpool/blobpool/slotter.go index 35349c344..84ccc0f27 100644 --- a/core/txpool/blobpool/slotter.go +++ b/core/txpool/blobpool/slotter.go @@ -25,13 +25,13 @@ package blobpool // The slotter also creates a shelf for 0-blob transactions. Whilst those are not // allowed in the current protocol, having an empty shelf is not a relevant use // of resources, but it makes stress testing with junk transactions simpler. -func newSlotter() func() (uint32, bool) { +func newSlotter(maxBlobsPerTransaction int) func() (uint32, bool) { slotsize := uint32(txAvgSize) slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return return func() (size uint32, done bool) { slotsize += blobSize - finished := slotsize > maxBlobsPerTransaction*blobSize+txMaxSize + finished := slotsize > uint32(maxBlobsPerTransaction)*blobSize+txMaxSize return slotsize, finished } diff --git a/core/txpool/blobpool/slotter_test.go b/core/txpool/blobpool/slotter_test.go index a7b43b4d2..8d46f47d2 100644 --- a/core/txpool/blobpool/slotter_test.go +++ b/core/txpool/blobpool/slotter_test.go @@ -21,7 +21,7 @@ import "testing" // Tests that the slotter creates the expected database shelves. func TestNewSlotter(t *testing.T) { // Generate the database shelve sizes - slotter := newSlotter() + slotter := newSlotter(6) var shelves []uint32 for { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 7a5155531..ac1f06bcd 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/antimev" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" @@ -146,8 +147,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types if len(hashes) == 0 { return errors.New("blobless blob transaction") } - if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { - return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) + maxBlobs := eip4844.MaxBlobsPerBlock(opts.Config, head.Time) + if len(hashes) > maxBlobs { + return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), maxBlobs) } // Ensure commitments, proofs and hashes are valid if err := validateBlobSidecar(hashes, sidecar); err != nil { diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index eba2fb61a..c41d4a9f7 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -58,6 +58,9 @@ var ( VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, EnableVerkleAtGenesis: true, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Verkle: params.DefaultPragueBlobConfig, + }, // TODO uncomment when proof generation is merged // ProofInBlocks: true, } @@ -79,6 +82,9 @@ var ( VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, EnableVerkleAtGenesis: true, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Verkle: params.DefaultPragueBlobConfig, + }, } ) @@ -226,11 +232,11 @@ func TestProcessParentBlockHash(t *testing.T) { var num = 2 for i := 1; i <= num; i++ { header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} - vmContext := NewEVMBlockContext(header, nil, new(common.Address)) chainConfig := params.MergedTestChainConfig if isVerkle { chainConfig = testVerkleChainConfig } + vmContext := NewEVMBlockContext(header, nil, new(common.Address)) evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{}) ProcessParentBlockHash(header.ParentHash, evm) } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 6074e9a09..44f5bc827 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -314,6 +314,10 @@ func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return fakeHeader(n, parentHash) } +func (d *dummyChain) Config() *params.ChainConfig { + return nil +} + // TestBlockhash tests the blockhash operation. It's a bit special, since it internally // requires access to a chain reader. func TestBlockhash(t *testing.T) { diff --git a/eth/api_backend.go b/eth/api_backend.go index 98c1a1885..dde80bbd5 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -392,7 +392,7 @@ func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastB func (b *EthAPIBackend) BlobBaseFee(ctx context.Context) *big.Int { if excess := b.CurrentHeader().ExcessBlobGas; excess != nil { - return eip4844.CalcBlobFee(*excess) + return eip4844.CalcBlobFee(b.ChainConfig(), b.CurrentHeader()) } return nil } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 32a843d2e..e5ac1cdc6 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1230,6 +1230,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { genesis.Config.ShanghaiTime = &time genesis.Config.CancunTime = &time genesis.Config.PragueTime = &time + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks) @@ -1546,6 +1547,7 @@ func TestParentBeaconBlockRoot(t *testing.T) { time := blocks[len(blocks)-1].Time() + 5 genesis.Config.ShanghaiTime = &time genesis.Config.CancunTime = &time + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks) defer n.Close() @@ -1628,6 +1630,7 @@ func TestWitnessCreationAndConsumption(t *testing.T) { timestamp := blocks[len(blocks)-2].Time() + 5 genesis.Config.ShanghaiTime = ×tamp genesis.Config.CancunTime = ×tamp + genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule n, ethservice := startEthService(t, genesis, blocks[:9]) defer n.Close() diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index f80b1d609..52b359108 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -1108,7 +1108,7 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { doTxNotify{peer: "C", hashes: []common.Hash{{0x07}, {0x08}}, types: []byte{types.BlobTxType, types.BlobTxType}, - sizes: []uint32{params.MaxBlobGasPerBlock, params.MaxBlobGasPerBlock}, + sizes: []uint32{params.BlobTxBlobGasPerBlob * 10, params.BlobTxBlobGasPerBlob * 10}, }, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), @@ -1125,8 +1125,8 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { {common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize}, }, "C": { - {common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock}, - {common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock}, + {common.Hash{0x07}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10}, + {common.Hash{0x08}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10}, }, }, fetching: map[string][]common.Hash{ diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 4c897f0eb..6572155ea 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -102,8 +101,10 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil } // Fill in blob base fee and next blob base fee. if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil { - bf.results.blobBaseFee = eip4844.CalcBlobFee(*excessBlobGas) - bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(eip4844.CalcExcessBlobGas(*excessBlobGas, *bf.header.BlobGasUsed)) + bf.results.blobBaseFee = eip4844.CalcBlobFee(config, bf.header) + excess := eip4844.CalcExcessBlobGas(config, bf.header) + next := &types.Header{Number: bf.header.Number, Time: bf.header.Time, ExcessBlobGas: &excess} + bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(config, next) } else { bf.results.blobBaseFee = new(big.Int) bf.results.nextBlobBaseFee = new(big.Int) @@ -111,7 +112,8 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { - bf.results.blobGasUsedRatio = float64(*blobGasUsed) / params.MaxBlobGasPerBlock + maxBlobs := eip4844.MaxBlobsPerBlock(config, bf.header.Time) + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobs) } if len(percentiles) == 0 { diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 7fe55d419..d32ab62f4 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -157,6 +157,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen config.ShanghaiTime = &ts config.CancunTime = &ts + config.BlobScheduleConfig = params.DefaultBlobSchedule signer = types.LatestSigner(gspec.Config) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 4e2a735f4..16ef7b8f9 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -360,6 +360,7 @@ func TestSupplySelfdestruct(t *testing.T) { cancunTime := uint64(0) gspec.Config.ShanghaiTime = &cancunTime gspec.Config.CancunTime = &cancunTime + gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) if err != nil { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json index 05da3b42e..f8e08532a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json @@ -41,7 +41,14 @@ "grayGlacierBlock": 0, "shanghaiTime": 0, "cancunTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + } } }, "context": { diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json index f8adbabf6..9f452ca5b 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -41,7 +41,14 @@ "grayGlacierBlock": 0, "shanghaiTime": 0, "cancunTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + } } }, "context": { @@ -54,7 +61,9 @@ }, "input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675", "result": { - "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" }, + "0x0000000000000000000000000000000000000000": { + "balance": "0x272e0528" + }, "0x0c2c51a0990aee1d73c1228de158688341557508": { "balance": "0xde0b6b3a7640000" } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json index b7d5ee1c5..043130a07 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json @@ -53,7 +53,19 @@ "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 0, - "terminalTotalDifficulty": 0 + "terminalTotalDifficulty": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 5007716 + } + } } }, "context": { diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index abc269949..e29144e04 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" // Force-load native and js packages, to trigger registration @@ -53,8 +54,9 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { } if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { - excessBlobGas := eip4844.CalcExcessBlobGas(*genesis.ExcessBlobGas, *genesis.BlobGasUsed) - context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas) + excess := eip4844.CalcExcessBlobGas(genesis.Config, genesis.ToBlock().Header()) + header := &types.Header{ExcessBlobGas: &excess, Number: genesis.Config.LondonBlock, Time: *genesis.Config.CancunTime} + context.BlobBaseFee = eip4844.CalcBlobFee(genesis.Config, header) } return context } diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index fa4e5b190..bae7445cb 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "gopkg.in/natefinch/lumberjack.v2" ) @@ -83,6 +84,7 @@ type supplyTracer struct { delta supplyInfo txCallstack []supplyTxCallstack // Callstack for current transaction logger *lumberjack.Logger + chainConfig *params.ChainConfig } type supplyTracerConfig struct { @@ -112,14 +114,15 @@ func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) { logger: logger, } return &tracing.Hooks{ - OnBlockStart: t.onBlockStart, - OnBlockEnd: t.onBlockEnd, - OnGenesisBlock: t.onGenesisBlock, - OnTxStart: t.onTxStart, - OnBalanceChange: t.onBalanceChange, - OnEnter: t.onEnter, - OnExit: t.onExit, - OnClose: t.onClose, + OnBlockchainInit: t.onBlockchainInit, + OnBlockStart: t.onBlockStart, + OnBlockEnd: t.onBlockEnd, + OnGenesisBlock: t.onGenesisBlock, + OnTxStart: t.onTxStart, + OnBalanceChange: t.onBalanceChange, + OnEnter: t.onEnter, + OnExit: t.onExit, + OnClose: t.onClose, }, nil } @@ -146,6 +149,10 @@ func (s *supplyTracer) resetDelta() { s.delta = newSupplyInfo() } +func (s *supplyTracer) onBlockchainInit(chainConfig *params.ChainConfig) { + s.chainConfig = chainConfig +} + func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) { s.resetDelta() @@ -161,8 +168,7 @@ func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) { // Blob burnt gas if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil { var ( - excess = *ev.Block.ExcessBlobGas() - baseFee = eip4844.CalcBlobFee(excess) + baseFee = eip4844.CalcBlobFee(s.chainConfig, ev.Block.Header()) burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee) ) s.delta.Burn.Blob = burn diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index fb863b16c..10c75155d 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -65,7 +66,7 @@ var ( ) var genesis = &core.Genesis{ - Config: params.AllEthashProtocolChanges, + Config: params.AllDevChainProtocolChanges, Alloc: types.GenesisAlloc{ testAddr: {Balance: testBalance}, revertContractAddr: {Code: revertCode}, @@ -136,7 +137,7 @@ func generateTestChain() []*types.Block { g.AddTx(testTx2) } } - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, beacon.New(ethash.NewFaker()), 2, generate) return append([]*types.Block{genesis.ToBlock()}, blocks...) } @@ -223,7 +224,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { if got != nil && got.Number != nil && got.Number.Sign() == 0 { got.Number = big.NewInt(0) // hack to make DeepEqual work } - if !reflect.DeepEqual(got, tt.want) { + if got.Hash() != tt.want.Hash() { t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want) } }) @@ -314,7 +315,7 @@ func testChainID(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 { + if id == nil || id.Cmp(params.AllDevChainProtocolChanges.ChainID) != 0 { t.Fatalf("ChainID returned wrong number: %+v", id) } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 03d4ee705..62e7f0e60 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -700,6 +700,7 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp type ChainContextBackend interface { Engine() consensus.Engine HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error) + ChainConfig() *params.ChainConfig } // ChainContext is an implementation of core.ChainContext. It's main use-case @@ -728,6 +729,10 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H return header } +func (context *ChainContext) Config() *params.ChainConfig { + return context.b.ChainConfig() +} + func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 130eaa972..d364b8048 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -159,9 +159,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsCancun(header.Number, header.Time) { var excess uint64 if sim.chainConfig.IsCancun(parent.Number, parent.Time) { - excess = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) - } else { - excess = eip4844.CalcExcessBlobGas(0, 0) + excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent) } header.ExcessBlobGas = &excess } @@ -415,3 +413,7 @@ func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) } return nil, errors.New("header not found") } + +func (b *simBackend) ChainConfig() *params.ChainConfig { + return b.b.ChainConfig() +} diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 5ce792bf8..ce1dd367c 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -37,10 +37,6 @@ import ( "github.com/holiman/uint256" ) -var ( - maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob -) - // TransactionArgs represents the arguments to construct a new transaction // or a message call. type TransactionArgs struct { @@ -125,8 +121,9 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas if args.BlobHashes != nil && len(args.BlobHashes) == 0 { return errors.New(`need at least 1 blob for a blob transaction`) } - if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction { - return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction) + maxBlobs := eip4844.MaxBlobsPerBlock(b.ChainConfig(), b.CurrentHeader().Time) + if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobs { + return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs) } // create check @@ -219,7 +216,9 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend, head if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 { return errors.New("maxFeePerBlobGas, if specified, must be non-zero") } - args.setCancunFeeDefaults(head) + if b.ChainConfig().IsCancun(head.Number, head.Time) { + args.setCancunFeeDefaults(b.ChainConfig(), head) + } // If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error. if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -271,15 +270,10 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend, head } // setCancunFeeDefaults fills in reasonable default fee values for unspecified fields. -func (args *TransactionArgs) setCancunFeeDefaults(head *types.Header) { +func (args *TransactionArgs) setCancunFeeDefaults(config *params.ChainConfig, head *types.Header) { // Set maxFeePerBlobGas if it is missing. if args.BlobHashes != nil && args.BlobFeeCap == nil { - var excessBlobGas uint64 - if head.ExcessBlobGas != nil { - excessBlobGas = *head.ExcessBlobGas - } - // ExcessBlobGas must be set for a Cancun block. - blobBaseFee := eip4844.CalcBlobFee(excessBlobGas) + blobBaseFee := eip4844.CalcBlobFee(config, head) // Set the max fee to be 2 times larger than the previous block's blob base fee. // The additional slack allows the tx to not become invalidated if the base // fee is rising. diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 539b4cac5..145346c79 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -279,6 +279,7 @@ func newBackendMock() *backendMock { BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(1000), CancunTime: &cancunTime, + BlobScheduleConfig: params.DefaultBlobSchedule, } return &backendMock{ current: &types.Header{ diff --git a/miner/worker.go b/miner/worker.go index c2148e308..92c730ec5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -759,7 +759,8 @@ func (w *worker) commitBlobTransaction(env *environment, tx *types.Transaction) // isn't really a better place right now. The blob gas limit is checked at block validation time // and not during execution. This means core.ApplyTransaction will not return an error if the // tx has too many blobs. So we have to explicitly check it here. - if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { + maxBlobs := eip4844.MaxBlobsPerBlock(w.chainConfig, env.header.Time) + if env.blobs+len(sc.Blobs) > maxBlobs { return nil, errors.New("max data blobs reached") } receipt, err := w.applyTransaction(env, tx) @@ -809,7 +810,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac } // If we don't have enough blob space for any further blob transactions, // skip that list altogether - if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock { + if !blobTxs.Empty() && env.blobs >= eip4844.MaxBlobsPerBlock(w.chainConfig, env.header.Time) { log.Trace("Not enough blob space for further blob transactions") blobTxs.Clear() // Fall though to pick up any plain txs @@ -843,11 +844,19 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac txs.Pop() continue } - if left := uint64(params.MaxBlobGasPerBlock - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas { - log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas) - txs.Pop() - continue + + // Most of the blob gas logic here is agnostic as to if the chain supports + // blobs or not, however the max check panics when called on a chain without + // a defined schedule, so we need to verify it's safe to call. + if w.chainConfig.IsCancun(env.header.Number, env.header.Time) { + left := eip4844.MaxBlobsPerBlock(w.chainConfig, env.header.Time) - env.blobs + if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) { + log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob) + txs.Pop() + continue + } } + // Transaction seems to fit, pull it up from the pool tx := ltx.Resolve() if tx == nil { @@ -855,6 +864,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac txs.Pop() continue } + // Error may be ignored here. The error has already been checked // during transaction acceptance in the transaction pool. from, _ := types.Sender(env.signer, tx) @@ -994,10 +1004,7 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm if w.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 if w.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) - } else { - // For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0 - excessBlobGas = eip4844.CalcExcessBlobGas(0, 0) + excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent) } header.BlobGasUsed = new(uint64) header.ExcessBlobGas = &excessBlobGas @@ -1039,7 +1046,7 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err filter.BaseFee = uint256.MustFromBig(env.header.BaseFee) } if env.header.ExcessBlobGas != nil { - filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas)) + filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(w.chainConfig, env.header)) } filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false pendingPlainTxs := w.eth.TxPool().Pending(filter) diff --git a/params/config.go b/params/config.go index 442e77b3b..84ae987de 100644 --- a/params/config.go +++ b/params/config.go @@ -17,6 +17,7 @@ package params import ( + "errors" "fmt" "math" "math/big" @@ -60,6 +61,9 @@ var ( CancunTime: newUint64(1710338135), DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + }, } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. HoleskyChainConfig = &ChainConfig{ @@ -84,6 +88,9 @@ var ( ShanghaiTime: newUint64(1696000704), CancunTime: newUint64(1707305664), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + }, } // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ @@ -108,6 +115,9 @@ var ( ShanghaiTime: newUint64(1677557088), CancunTime: newUint64(1706655072), Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + }, } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. @@ -158,6 +168,10 @@ var ( CancunTime: newUint64(0), TerminalTotalDifficulty: big.NewInt(0), PragueTime: newUint64(0), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, + }, } // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced @@ -248,6 +262,10 @@ var ( TerminalTotalDifficulty: big.NewInt(0), Ethash: new(EthashConfig), Clique: nil, + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, + }, } // NonActivatedConfig defines the chain configuration without activating @@ -282,6 +300,26 @@ var ( TestRules = TestChainConfig.Rules(new(big.Int), false, 0) ) +var ( + // DefaultCancunBlobConfig is the default blob configuration for the Cancun fork. + DefaultCancunBlobConfig = &BlobConfig{ + Target: 3, + Max: 6, + UpdateFraction: 3338477, + } + // DefaultPragueBlobConfig is the default blob configuration for the Prague fork. + DefaultPragueBlobConfig = &BlobConfig{ + Target: 6, + Max: 9, + UpdateFraction: 5007716, + } + // DefaultBlobSchedule is the latest configured blob schedule for test chains. + DefaultBlobSchedule = &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, + } +) + // NetworkNames are user friendly names to use in the chain spec banner. var NetworkNames = map[string]string{ MainnetChainConfig.ChainID.String(): "mainnet", @@ -349,9 +387,10 @@ type ChainConfig struct { EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"` // Various consensus engines - Ethash *EthashConfig `json:"ethash,omitempty"` - Clique *CliqueConfig `json:"clique,omitempty"` - DBFT *DBFTConfig `json:"dbft,omitempty"` + Ethash *EthashConfig `json:"ethash,omitempty"` + Clique *CliqueConfig `json:"clique,omitempty"` + BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"` + DBFT *DBFTConfig `json:"dbft,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -474,6 +513,20 @@ func (c *ChainConfig) Description() string { return banner } +// BlobConfig specifies the target and max blobs per block for the associated fork. +type BlobConfig struct { + Target int `json:"target"` + Max int `json:"max"` + UpdateFraction uint64 `json:"baseFeeUpdateFraction"` +} + +// BlobScheduleConfig determines target and max number of blobs allow per fork. +type BlobScheduleConfig struct { + Cancun *BlobConfig `json:"cancun,omitempty"` + Prague *BlobConfig `json:"prague,omitempty"` + Verkle *BlobConfig `json:"verkle,omitempty"` +} + // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { return isBlockForked(c.HomesteadBlock, num) @@ -707,6 +760,45 @@ func (c *ChainConfig) CheckConfigForkOrder() error { lastFork = cur } } + + // Check that all forks with blobs explicitly define the blob schedule configuration. + bsc := c.BlobScheduleConfig + if bsc == nil { + bsc = new(BlobScheduleConfig) + } + for _, cur := range []struct { + name string + timestamp *uint64 + config *BlobConfig + }{ + {name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun}, + {name: "prague", timestamp: c.PragueTime, config: bsc.Prague}, + } { + if cur.config != nil { + if err := cur.config.validate(); err != nil { + return fmt.Errorf("invalid blob configuration for fork %s: %v", cur.name, err) + } + } + if cur.timestamp != nil { + // If the fork is configured, a blob schedule must be defined for it. + if cur.config == nil { + return fmt.Errorf("unsupported fork configuration: missing blob configuration entry for %v in schedule", cur.name) + } + } + } + return nil +} + +func (bc *BlobConfig) validate() error { + if bc.Max < 0 { + return errors.New("max < 0") + } + if bc.Target < 0 { + return errors.New("target < 0") + } + if bc.UpdateFraction == 0 { + return errors.New("update fraction must be defined and non-zero") + } return nil } diff --git a/params/protocol_params.go b/params/protocol_params.go index c9179634a..6b06dadae 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -172,12 +172,8 @@ const ( BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs - BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. - BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) - MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block - HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) diff --git a/privnet/four/genesis_privnet.json b/privnet/four/genesis_privnet.json index a116a44a3..a7e42b6d1 100644 --- a/privnet/four/genesis_privnet.json +++ b/privnet/four/genesis_privnet.json @@ -19,6 +19,13 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + }, "dbft": { "period": 5, "standbyValidators": [ diff --git a/privnet/seven/genesis_privnet.json b/privnet/seven/genesis_privnet.json index 4d180771b..30129bef1 100644 --- a/privnet/seven/genesis_privnet.json +++ b/privnet/seven/genesis_privnet.json @@ -19,6 +19,13 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + }, "dbft": { "period": 5, "standbyValidators": [ diff --git a/privnet/single/genesis_privnet.json b/privnet/single/genesis_privnet.json index a8491674f..6b6aa8932 100644 --- a/privnet/single/genesis_privnet.json +++ b/privnet/single/genesis_privnet.json @@ -19,6 +19,13 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + }, "dbft": { "period": 5, "standbyValidators": [ diff --git a/tests/init.go b/tests/init.go index 18447ca6b..a985879ab 100644 --- a/tests/init.go +++ b/tests/init.go @@ -354,6 +354,9 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), CancunTime: u64(0), + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + }, }, "ShanghaiToCancunAtTime15k": { ChainID: big.NewInt(1), @@ -373,6 +376,9 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), CancunTime: u64(15_000), + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + }, }, "Prague": { ChainID: big.NewInt(1), @@ -394,6 +400,10 @@ var Forks = map[string]*params.ChainConfig{ CancunTime: u64(0), PragueTime: u64(0), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + }, }, "CancunToPragueAtTime15k": { ChainID: big.NewInt(1), @@ -415,6 +425,10 @@ var Forks = map[string]*params.ChainConfig{ CancunTime: u64(0), PragueTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + }, }, "Osaka": { ChainID: big.NewInt(1), diff --git a/tests/state_test.go b/tests/state_test.go index da4b8ef79..0c9553c07 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -303,7 +303,7 @@ func runBenchmark(b *testing.B, t *StateTest) { // Prepare the EVM. txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + context := core.NewEVMBlockContext(block.Header(), &dummyChain{config: config}, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash context.BaseFee = baseFee evm := vm.NewEVM(context, state.StateDB, config, vmconfig) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e658b62eb..24caf41ed 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -275,13 +276,14 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh return st, common.Hash{}, 0, err } - { // Blob transactions may be present after the Cancun fork. - // In production, - // - the header is verified against the max in eip4844.go:VerifyEIP4844Header - // - the block body is verified against the header in block_validator.go:ValidateBody - // Here, we just do this shortcut smaller fix, since state tests do not - // utilize those codepaths - if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { + // Blob transactions may be present after the Cancun fork. + // In production, + // - the header is verified against the max in eip4844.go:VerifyEIP4844Header + // - the block body is verified against the header in block_validator.go:ValidateBody + // Here, we just do this shortcut smaller fix, since state tests do not + // utilize those codepaths. + if config.IsCancun(new(big.Int), block.Time()) { + if len(msg.BlobHashes) > eip4844.MaxBlobsPerBlock(config, block.Time()) { return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum") } } @@ -299,7 +301,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh } // Prepare the EVM. - context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + context := core.NewEVMBlockContext(block.Header(), &dummyChain{config: config}, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash context.BaseFee = baseFee context.Random = nil @@ -312,8 +314,13 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.Difficulty = big.NewInt(0) } if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil { - context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas) + header := &types.Header{ + Time: block.Time(), + ExcessBlobGas: t.json.Env.ExcessBlobGas, + } + context.BlobBaseFee = eip4844.CalcBlobFee(config, header) } + evm := vm.NewEVM(context, st.StateDB, config, vmconfig) if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { @@ -543,3 +550,12 @@ func (st *StateTestState) Close() { st.Snapshots = nil } } + +// dummyChain implements the core.ChainContext interface. +type dummyChain struct { + config *params.ChainConfig +} + +func (d *dummyChain) Engine() consensus.Engine { return nil } +func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil } +func (d *dummyChain) Config() *params.ChainConfig { return d.config } From 5a5d4cd562b6f4ff4c667c8c464cafd570216f92 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 4 Feb 2025 17:16:26 +0100 Subject: [PATCH 120/354] core: assign default difficulty to zero for chain without ethash (#31067) I hit this case while trying something with the simulated backend. The EVM only enables instruction set forks after the merge when 'Random' is set. In the simulated backend, the random value will be set via the engine API for all blocks after genesis. But for the genesis block itself, the random value will not be assigned in the vm.BlockContext because the genesis has a non-zero difficulty. For my case, this meant that estimateGas did not work for the first transaction sent on the simulated chain, since the contract contained a PUSH0 instruction. This could also be fixed by explicitly configuring a zero difficulty in the simulated backend. However, I think that zero difficulty is a better default these days. --------- Co-authored-by: lightclient --- core/genesis.go | 8 ++++++-- core/genesis_test.go | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index e3cbd48de..1f410248a 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -470,8 +470,12 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { if g.GasLimit == 0 { head.GasLimit = params.GenesisGasLimit } - if g.Difficulty == nil && g.Mixhash == (common.Hash{}) { - head.Difficulty = params.GenesisDifficulty + if g.Difficulty == nil { + if g.Config != nil && g.Config.Ethash == nil { + head.Difficulty = big.NewInt(0) + } else if g.Mixhash == (common.Hash{}) { + head.Difficulty = params.GenesisDifficulty + } } if g.Config != nil && g.Config.IsLondon(common.Big0) { if g.BaseFee != nil { diff --git a/core/genesis_test.go b/core/genesis_test.go index e8c7af58b..1c7439122 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -44,14 +44,14 @@ func testSetupGenesis(t *testing.T, scheme string) { var ( customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") customg = Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)}, + Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3), Ethash: ¶ms.EthashConfig{}}, Alloc: types.GenesisAlloc{ {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, }, } oldcustomg = customg ) - oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} + oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2), Ethash: ¶ms.EthashConfig{}} tests := []struct { name string From 00a711138503047a1d9e89252065385424bd4455 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 4 Feb 2025 17:23:01 +0100 Subject: [PATCH 121/354] core/txpool: remove locals-tracking from txpools (#30559) Replaces #29297, descendant from #27535 --------- This PR removes `locals` as a concept from transaction pools. Therefore, the pool now acts as very a good simulation/approximation of how our peers' pools behave. What this PR does instead, is implement a locals-tracker, which basically is a little thing which, from time to time, asks the pool "did you forget this transaction?". If it did, the tracker resubmits it. If the txpool _had_ forgotten it, chances are that the peers had also forgotten it. It will be propagated again. Doing this change means that we can simplify the pool internals, quite a lot. Historically, there has been two features, or usecases, that has been combined into the concept of `locals`. 1. "I want my local node to remember this transaction indefinitely, and resubmit to the network occasionally" 2. "I want this (valid) transaction included to be top-prio for my miner" This PR splits these features up, let's call it `1: local` and `2: prio`. The `prio` is not actually individual transaction, but rather a set of `address`es to prioritize. The attribute `local` means it will be tracked, and `prio` means it will be prioritized by miner. For `local`: anything transaction received via the RPC is marked as `local`, and tracked by the tracker. For `prio`: any transactions from this sender is included first, when building a block. The existing commandline-flag `--txpool.locals` sets the set of `prio` addresses. --------- Co-authored-by: Gary Rong --- consensus/dbft/dbft.go | 6 +- core/txpool/blobpool/blobpool.go | 9 +- core/txpool/legacypool/cachepool.go | 36 +- core/txpool/legacypool/cachepool_test.go | 34 +- core/txpool/legacypool/legacypool.go | 389 +++--------- core/txpool/legacypool/legacypool_test.go | 575 +++--------------- core/txpool/legacypool/list.go | 63 +- core/txpool/{legacypool => locals}/journal.go | 2 +- core/txpool/locals/tx_tracker.go | 212 +++++++ core/txpool/subpool.go | 5 +- core/txpool/txpool.go | 19 +- eth/api_backend.go | 3 + eth/backend.go | 22 +- eth/catalyst/simulated_beacon_test.go | 52 +- miner/miner.go | 5 + miner/worker.go | 41 +- 16 files changed, 507 insertions(+), 966 deletions(-) rename core/txpool/{legacypool => locals}/journal.go (99%) create mode 100644 core/txpool/locals/tx_tracker.go diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index 9d60bb0f5..529a86f88 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -926,7 +926,7 @@ func (c *DBFT) verifyPreBlockCb(b dbft.PreBlock[common.Hash]) bool { } ethBlock := dbftBlock.ToEthBlock() - errs := c.staticPool.Add(dbftBlock.transactions, false, false) + errs := c.staticPool.Add(dbftBlock.transactions, false) c.staticPool.ResetStatic() for i, err := range errs { if err != nil { @@ -1144,7 +1144,7 @@ func (c *DBFT) processPreBlockCb(b dbft.PreBlock[common.Hash]) error { "envelope index", i, "reason", reason) } - errs := c.staticPool.Add([]*types.Transaction{pre.transactions[i]}, false, false) + errs := c.staticPool.Add([]*types.Transaction{pre.transactions[i]}, false) if errs[0] != nil { log.Info("Falling back to original set of transactions", "envelope hash", pre.transactions[i].Hash(), @@ -1209,7 +1209,7 @@ func (c *DBFT) processPreBlockCb(b dbft.PreBlock[common.Hash]) error { break } } - errs := c.staticPool.Add([]*types.Transaction{decryptedTx}, false, false) + errs := c.staticPool.Add([]*types.Transaction{decryptedTx}, false) if errs[0] != nil { if fallbackToEnvelope(i, true, fmt.Sprintf("decrypted transaction has pool conflicts: %s", errs[0].Error())) { continue diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 58840fa05..e4bd6c451 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1278,7 +1278,7 @@ func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844. // Add inserts a set of blob transactions into the pool if they pass validation (both // consensus validity and pool restrictions). -func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error { +func (p *BlobPool) Add(txs []*types.Transaction, sync bool) []error { var ( adds = make([]*types.Transaction, 0, len(txs)) errs = make([]error, len(txs)) @@ -1722,13 +1722,6 @@ func (p *BlobPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*ty return []*types.Transaction{}, []*types.Transaction{} } -// Locals retrieves the accounts currently considered local by the pool. -// -// There is no notion of local accounts in the blob pool. -func (p *BlobPool) Locals() []common.Address { - return []common.Address{} -} - // Status returns the known status (unknown/pending/queued) of a transaction // identified by their hashes. func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus { diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index 3b7919480..83968e8e5 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -361,18 +361,11 @@ func (pool *CachePool) Pending(filter txpool.PendingFilter) map[common.Address][ return make(map[common.Address][]*txpool.LazyTransaction) } -// Locals retrieves the accounts currently considered local by the pool. -// -// There is no notion of local accounts in the cache pool. -func (pool *CachePool) Locals() []common.Address { - return []common.Address{} -} - // validateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. // This check is meant as an early check which only needs to be performed once, // and does not require the pool mutex to be held. -func (pool *CachePool) validateTxBasics(tx *types.Transaction, local bool) error { +func (pool *CachePool) validateTxBasics(tx *types.Transaction) error { opts := &txpool.ValidationOptions{ Config: pool.chainconfig, Accept: 0 | @@ -382,9 +375,6 @@ func (pool *CachePool) validateTxBasics(tx *types.Transaction, local bool) error MaxSize: txMaxSize, MinTip: pool.gasTip.Load().ToBig(), } - if local { - opts.MinTip = new(big.Int) - } if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil { return err } @@ -508,7 +498,7 @@ func (pool *CachePool) add(tx *types.Transaction) (replaced bool, err error) { // Nothing was replaced, bump the queued counter cachedGauge.Inc(1) } - pool.all.Add(tx, true) + pool.all.Add(tx) log.Trace("Pooled new executable cached transaction", "hash", hash, "from", from, "to", tx.To()) // Successful promotion, bump the heartbeat @@ -519,27 +509,11 @@ func (pool *CachePool) add(tx *types.Transaction) (replaced bool, err error) { return true, err } -// addLocals enqueues a batch of transactions into the pool if they are valid, marking the -// senders as local ones, ensuring they go around the local pricing constraints. -// -// This method is used to add transactions from the RPC API and performs synchronous pool -// reorganization and event propagation. -func (pool *CachePool) addLocals(txs []*types.Transaction) []error { - return pool.Add(txs, true, true) -} - -// addLocal enqueues a single local transaction into the pool if it is valid. This is -// a convenience wrapper around addLocals. -func (pool *CachePool) addLocal(tx *types.Transaction) error { - return pool.addLocals([]*types.Transaction{tx})[0] -} - -// Add enqueues a batch of transactions into the pool if they are valid. Depending -// on the local flag, full pricing constraints will or will not be applied. +// Add enqueues a batch of transactions into the pool if they are valid. // // If sync is set, the method will block until all internal maintenance related // to the add is finished. Only use this during tests for determinism! -func (pool *CachePool) Add(txs []*types.Transaction, local, sync bool) []error { +func (pool *CachePool) Add(txs []*types.Transaction, sync bool) []error { // Filter out known ones without obtaining the pool lock or recovering signatures var ( errs = make([]error, len(txs)) @@ -555,7 +529,7 @@ func (pool *CachePool) Add(txs []*types.Transaction, local, sync bool) []error { // Exclude transactions with basic errors, e.g invalid signatures and // insufficient intrinsic gas as soon as possible and cache senders // in transactions before obtaining lock - if err := pool.validateTxBasics(tx, local); err != nil { + if err := pool.validateTxBasics(tx); err != nil { errs[i] = err log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err) invalidCachedTxMeter.Mark(1) diff --git a/core/txpool/legacypool/cachepool_test.go b/core/txpool/legacypool/cachepool_test.go index 53b75a4f7..7d8301fe4 100644 --- a/core/txpool/legacypool/cachepool_test.go +++ b/core/txpool/legacypool/cachepool_test.go @@ -98,7 +98,7 @@ func TestCachePool(t *testing.T) { } txs[i] = transaction(i%pool.config.AccountSlots, gasLimit, keys[0]) } - errs := pool.addLocals(txs) + errs := pool.Add(txs, true) for i, err := range errs { switch uint64(i) / pool.config.AccountSlots { case 0: @@ -122,7 +122,7 @@ func TestCachePool(t *testing.T) { for i := uint64(0); i < 3*pool.config.AccountSlots; i++ { txs[i] = dynamicFeeTx(i, 100000, big.NewInt(1), big.NewInt(1), keys[1]) } - pool.addLocals(txs) + pool.Add(txs, true) require.Equal(t, int(pool.config.AccountSlots+3*pool.config.AccountSlots), pool.all.Count()) tx = txs[0] sender = crypto.PubkeyToAddress(keys[1].PublicKey) @@ -148,25 +148,25 @@ func TestCachePoolInvalidTransactions(t *testing.T) { // Intrinsic gas too low testCachePoolAddBalance(pool, from, big.NewInt(1)) - if err, want := pool.addLocal(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { + if err, want := pool.Add([]*types.Transaction{tx}, true)[0], core.ErrIntrinsicGas; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } // Insufficient funds tx = transaction(0, 100000, key) - if err, want := pool.addLocal(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { + if err, want := pool.Add([]*types.Transaction{tx}, true)[0], core.ErrInsufficientFunds; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } testCachePoolSetNonce(pool, from, 1) testCachePoolAddBalance(pool, from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) - if err, want := pool.addLocal(tx), core.ErrNonceTooLow; !errors.Is(err, want) { + if err, want := pool.Add([]*types.Transaction{tx}, true)[0], core.ErrNonceTooLow; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } testCachePoolSetNonce(pool, from, 0) - if err, want := pool.addLocal(tx), ErrTxPoolCached; !errors.Is(err, want) { + if err, want := pool.Add([]*types.Transaction{tx}, true)[0], ErrTxPoolCached; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } } @@ -182,7 +182,7 @@ func TestCache(t *testing.T) { testCachePoolAddBalance(pool, from, big.NewInt(1000000)) <-pool.requestReset(nil, nil) - pool.Add([]*types.Transaction{tx}, true, true) + pool.Add([]*types.Transaction{tx}, true) if len(pool.cached) != 1 { t.Error("expected valid txs to be 1 is", len(pool.cached)) } @@ -190,7 +190,7 @@ func TestCache(t *testing.T) { tx = transaction(1, 100000, key) from, _ = deriveSender(tx) testCachePoolSetNonce(pool, from, 2) - pool.Add([]*types.Transaction{tx}, true, true) + pool.Add([]*types.Transaction{tx}, true) if _, ok := pool.cached[from].txs.items[tx.Nonce()]; ok { t.Error("expected transaction to be in tx pool") @@ -206,7 +206,7 @@ func TestCachePoolNegativeValue(t *testing.T) { tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) testCachePoolAddBalance(pool, from, big.NewInt(1)) - if err := pool.addLocal(tx); err != txpool.ErrNegativeValue { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; err != txpool.ErrNegativeValue { t.Error("expected", txpool.ErrNegativeValue, "got", err) } } @@ -219,7 +219,7 @@ func TestCachePoolTipAboveFeeCap(t *testing.T) { tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) - if err := pool.addLocal(tx); err != core.ErrTipAboveFeeCap { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; err != core.ErrTipAboveFeeCap { t.Error("expected", core.ErrTipAboveFeeCap, "got", err) } } @@ -234,12 +234,12 @@ func TestCachePoolVeryHighValues(t *testing.T) { veryBigNumber.Lsh(veryBigNumber, 300) tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) - if err := pool.addLocal(tx); err != core.ErrTipVeryHigh { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; err != core.ErrTipVeryHigh { t.Error("expected", core.ErrTipVeryHigh, "got", err) } tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) - if err := pool.addLocal(tx2); err != core.ErrFeeCapVeryHigh { + if err := pool.Add([]*types.Transaction{tx2}, true)[0]; err != core.ErrFeeCapVeryHigh { t.Error("expected", core.ErrFeeCapVeryHigh, "got", err) } } @@ -293,7 +293,7 @@ func TestCacheTimeLimiting(t *testing.T) { testCachePoolAddBalance(pool, crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) - if err := pool.addLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); !errors.Is(err, ErrTxPoolCached) { + if err := pool.Add([]*types.Transaction{pricedTransaction(1, 100000, big.NewInt(1), local)}, true)[0]; !errors.Is(err, ErrTxPoolCached) { t.Fatalf("failed to add local transaction: %v", err) } @@ -343,13 +343,13 @@ func TestCacheTimeLimiting(t *testing.T) { } // Cached gapped transactions - if err := pool.addLocal(pricedTransaction(3, 100000, big.NewInt(1), local)); !errors.Is(err, ErrTxPoolCached) { + if err := pool.Add([]*types.Transaction{pricedTransaction(3, 100000, big.NewInt(1), local)}, true)[0]; !errors.Is(err, ErrTxPoolCached) { t.Fatalf("failed to add local transaction: %v", err) } time.Sleep(5 * evictionInterval) // A half lifetime pass // Cached executable transactions, the life cycle should be restarted. - if err := pool.addLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); !errors.Is(err, ErrTxPoolCached) { + if err := pool.Add([]*types.Transaction{pricedTransaction(2, 100000, big.NewInt(1), local)}, true)[0]; !errors.Is(err, ErrTxPoolCached) { t.Fatalf("failed to add local transaction: %v", err) } time.Sleep(6 * evictionInterval) @@ -401,7 +401,7 @@ func TestCachePoolCapClearsFromAll(t *testing.T) { txs = append(txs, transaction(uint64(j), 100000, key)) } // Import the batch and verify that limits have been enforced - pool.addLocals(txs) + pool.Add(txs, true) if err := validateCachePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -435,7 +435,7 @@ func TestCachePoolStatusCheck(t *testing.T) { txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) // Import the transaction and ensure they are correctly added - pool.addLocals(txs) + pool.Add(txs, true) cached := pool.stats() if cached != 4 { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index ce9743208..af43dc977 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -110,7 +110,6 @@ var ( pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil) queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil) - localGauge = metrics.NewRegisteredGauge("txpool/local", nil) slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil) reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil) @@ -177,10 +176,6 @@ var DefaultConfig = Config{ // unreasonable or unworkable. func (config *Config) sanitize() Config { conf := *config - if conf.Rejournal < time.Second { - log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) - conf.Rejournal = time.Second - } if conf.PriceLimit < 1 { log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit) conf.PriceLimit = DefaultConfig.PriceLimit @@ -237,9 +232,6 @@ type LegacyPool struct { currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces - locals *accountSet // Set of local transaction to exempt from eviction rules - journal *journal // Journal of local transaction to back up to disk - reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools pending map[common.Address]*list // All currently processable transactions queue map[common.Address]*list // Queued but non-processable transactions @@ -276,9 +268,6 @@ func New(config Config, chain BlockChain) *LegacyPool { pool.reorgDoneCh = make(chan chan struct{}) pool.reorgShutdownCh = make(chan struct{}) pool.initDoneCh = make(chan struct{}) - if !config.NoLocals && config.Journal != "" { - pool.journal = newTxJournal(config.Journal) - } return pool } @@ -294,7 +283,6 @@ func NewStatic(config Config, chain BlockChain) *LegacyPool { signer: types.LatestSigner(chain.Config()), } pool.setEmptyLists() - pool.setInitialLocals() return pool } @@ -327,8 +315,7 @@ func (pool *LegacyPool) FilterAdd(tx *types.Transaction, local bool) bool { } // Init sets the gas price needed to keep a transaction in the pool and the chain -// head to allow balance / nonce checks. The transaction journal will be loaded -// from disk and filtered based on the provided starting settings. The internal +// head to allow balance / nonce checks. The internal // goroutines will be spun up and the pool deemed operational afterwards. func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error { // Do basic initializations about reserver, gas price and state @@ -339,15 +326,6 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.A pool.wg.Add(1) go pool.scheduleReorgLoop() - // If local transactions and journaling is enabled, load from disk - if pool.journal != nil { - if err := pool.journal.load(pool.addLocals); err != nil { - log.Warn("Failed to load transaction journal", "err", err) - } - if err := pool.journal.rotate(pool.local()); err != nil { - log.Warn("Failed to rotate transaction journal", "err", err) - } - } pool.wg.Add(1) go pool.loop() return nil @@ -390,7 +368,6 @@ func (pool *LegacyPool) InitStatic(gasTip uint64, head *types.Header, statedb *s // and inited by InitStatic, so that the pool can be reused as only initialized. func (pool *LegacyPool) ResetStatic() { pool.setEmptyLists() - pool.setInitialLocals() pool.pendingNonces = newNoncer(pool.currentState) } @@ -403,15 +380,6 @@ func (pool *LegacyPool) setEmptyLists() { pool.priced = newPricedList(pool.all) } -// setInitialLocals resets the local accounts of the pool to initially configured. -func (pool *LegacyPool) setInitialLocals() { - pool.locals = newAccountSet(pool.signer) - for _, addr := range pool.config.Locals { - log.Info("Setting new local account", "address", addr) - pool.locals.add(addr) - } -} - // loop is the transaction pool's main event loop, waiting for and reacting to // outside blockchain events as well as for various reporting and transaction // eviction events. @@ -424,12 +392,10 @@ func (pool *LegacyPool) loop() { // Start the stats reporting and transaction eviction tickers report = time.NewTicker(statsReportInterval) evict = time.NewTicker(evictionInterval) - journal = time.NewTicker(pool.config.Rejournal) reannounce = time.NewTicker(reannounceInterval) ) defer report.Stop() defer evict.Stop() - defer journal.Stop() defer reannounce.Stop() // Notify tests that the init phase is done @@ -456,11 +422,7 @@ func (pool *LegacyPool) loop() { case <-evict.C: pool.mu.Lock() for addr := range pool.queue { - // Skip local transactions from the eviction mechanism - if pool.locals.contains(addr) { - continue - } - // Any non-locals old enough should be removed + // Any old enough should be removed if time.Since(pool.beats[addr]) > pool.config.Lifetime { list := pool.queue[addr].Flatten() for _, tx := range list { @@ -471,24 +433,14 @@ func (pool *LegacyPool) loop() { } pool.mu.Unlock() - // Handle local transaction journal rotation - case <-journal.C: - if pool.journal != nil { - pool.mu.Lock() - if err := pool.journal.rotate(pool.local()); err != nil { - log.Warn("Failed to rotate local tx journal", "err", err) - } - pool.mu.Unlock() - } - // Handle pending transaction reannouncement case <-reannounce.C: pool.mu.RLock() reannoTxs := func() []*types.Transaction { txs := make([]*types.Transaction, 0) - for addr, list := range pool.pending { + for _, list := range pool.pending { // Default ReannounceRemotes is true - if !pool.config.ReannounceRemotes && !pool.locals.contains(addr) { + if !pool.config.ReannounceRemotes { continue } @@ -520,9 +472,6 @@ func (pool *LegacyPool) Close() error { close(pool.reorgShutdownCh) pool.wg.Wait() - if pool.journal != nil { - pool.journal.close() - } log.Info("Transaction pool stopped") return nil } @@ -564,7 +513,7 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) { // If the min miner fee increased, remove transactions below the new threshold if newTip.Cmp(old) > 0 { // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead - drop := pool.all.RemotesBelowTip(tip) + drop := pool.all.TxsBelowTip(tip) for _, tx := range drop { pool.removeTx(tx.Hash(), false, true) } @@ -674,7 +623,7 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address] txs := list.Flatten() // If the miner requests tip enforcement, cap the lists now - if minTipBig != nil && !pool.locals.contains(addr) { + if minTipBig != nil { for i, tx := range txs { if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 { txs = txs[:i] @@ -702,35 +651,11 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address] return pending } -// Locals retrieves the accounts currently considered local by the pool. -func (pool *LegacyPool) Locals() []common.Address { - pool.mu.Lock() - defer pool.mu.Unlock() - - return pool.locals.flatten() -} - -// local retrieves all currently known local transactions, grouped by origin -// account and sorted by nonce. The returned transaction set is a copy and can be -// freely modified by calling code. -func (pool *LegacyPool) local() map[common.Address]types.Transactions { - txs := make(map[common.Address]types.Transactions) - for addr := range pool.locals.accounts { - if pending := pool.pending[addr]; pending != nil { - txs[addr] = append(txs[addr], pending.Flatten()...) - } - if queued := pool.queue[addr]; queued != nil { - txs[addr] = append(txs[addr], queued.Flatten()...) - } - } - return txs -} - // validateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. // This check is meant as an early check which only needs to be performed once, // and does not require the pool mutex to be held. -func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) error { +func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error { opts := &txpool.ValidationOptions{ Config: pool.chainconfig, Accept: 0 | @@ -740,9 +665,6 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro MaxSize: txMaxSize, MinTip: pool.gasTip.Load().ToBig(), } - if local { - opts.MinTip = new(big.Int) - } if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil { return err } @@ -790,11 +712,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { // add validates a transaction and inserts it into the non-executable queue for later // pending promotion and execution. If the transaction is a replacement for an already // pending or queued one, it overwrites the previous transaction if its price is higher. -// -// If a newly added transaction is marked as local, its sending account will be -// added to the allowlist, preventing any associated transaction from being dropped -// out of the pool due to pricing constraints. -func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, err error) { +func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) { // If the transaction is already known, discard it hash := tx.Hash() if pool.all.Get(hash) != nil { @@ -802,9 +720,6 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e knownTxMeter.Mark(1) return false, txpool.ErrAlreadyKnown } - // Make the local flag. If it's from local source or it's from the network but - // the sender is marked as local previously, treat it as the local transaction. - isLocal := local || pool.locals.containsTx(tx) // If the transaction fails basic validation, discard it if err := pool.validateTx(tx); err != nil { @@ -840,7 +755,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e // If the transaction pool is full, discard underpriced transactions if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it - if !isLocal && pool.priced.Underpriced(tx) { + if pool.priced.Underpriced(tx) { log.Trace("Discarding underpriced transaction", "hash", hash, "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) underpricedTxMeter.Mark(1) return false, txpool.ErrUnderpriced @@ -856,19 +771,18 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e } // New transaction is better than our worse ones, make room for it. - // If it's a local transaction, forcibly discard all available transactions. - // Otherwise if we can't make enough room for new one, abort the operation. - drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal) + // If we can't make enough room for new one, abort the operation. + drop, success := pool.priced.Discard(pool.all.Slots() - int(pool.config.GlobalSlots+pool.config.GlobalQueue) + numSlots(tx)) // Special case, we still can't make the room for the new remote one. - if !isLocal && !success { + if !success { log.Trace("Discarding overflown transaction", "hash", hash) overflowedTxMeter.Mark(1) return false, ErrTxPoolOverflow } // If the new transaction is a future transaction it should never churn pending transactions - if !isLocal && pool.isGapped(from, tx) { + if pool.isGapped(from, tx) { var replacesPending bool for _, dropTx := range drop { dropSender, _ := types.Sender(pool.signer, dropTx) @@ -880,7 +794,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e // Add all transactions back to the priced queue if replacesPending { for _, dropTx := range drop { - pool.priced.Put(dropTx, false) + pool.priced.Put(dropTx) } log.Trace("Discarding future transaction replacing pending tx", "hash", hash) return false, txpool.ErrFutureReplacePending @@ -913,9 +827,8 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e pool.priced.Removed(1) pendingReplaceMeter.Mark(1) } - pool.all.Add(tx, isLocal) - pool.priced.Put(tx, isLocal) - pool.journalTx(from, tx) + pool.all.Add(tx) + pool.priced.Put(tx) pool.queueTxEvent(tx) log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) @@ -924,20 +837,10 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e return old != nil, nil } // New transaction isn't replacing a pending one, push into queue - replaced, err = pool.enqueueTx(hash, tx, isLocal, true) + replaced, err = pool.enqueueTx(hash, tx, true) if err != nil { return false, err } - // Mark local addresses and journal local transactions - if local && !pool.locals.contains(from) { - log.Info("Setting new local account", "address", from) - pool.locals.add(from) - pool.priced.Removed(pool.all.RemoteToLocals(pool.locals)) // Migrate the remotes if it's marked as local first time. - } - if isLocal { - localGauge.Inc(1) - } - pool.journalTx(from, tx) log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) return replaced, nil @@ -970,7 +873,7 @@ func (pool *LegacyPool) isGapped(from common.Address, tx *types.Transaction) boo // enqueueTx inserts a new transaction into the non-executable transaction queue. // // Note, this method assumes the pool lock is held! -func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local bool, addAll bool) (bool, error) { +func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, addAll bool) (bool, error) { // Try to insert the transaction into the future queue from, _ := types.Sender(pool.signer, tx) // already validated if pool.queue[from] == nil { @@ -997,8 +900,8 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local log.Error("Missing transaction in lookup set, please report the issue", "hash", hash) } if addAll { - pool.all.Add(tx, local) - pool.priced.Put(tx, local) + pool.all.Add(tx) + pool.priced.Put(tx) } // If we never record the heartbeat, do it right now. if _, exist := pool.beats[from]; !exist { @@ -1007,18 +910,6 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local return old != nil, nil } -// journalTx adds the specified transaction to the local disk journal if it is -// deemed to have been sent from a local account. -func (pool *LegacyPool) journalTx(from common.Address, tx *types.Transaction) { - // Only journal if it's enabled and the transaction is local - if pool.journal == nil || !pool.locals.contains(from) { - return - } - if err := pool.journal.insert(tx); err != nil { - log.Warn("Failed to journal local transaction", "err", err) - } -} - // promoteTx adds a transaction to the pending (processable) list of transactions // and returns whether it was inserted or an older was better. // @@ -1055,28 +946,13 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ return true } -// addLocals enqueues a batch of transactions into the pool if they are valid, marking the -// senders as local ones, ensuring they go around the local pricing constraints. -// -// This method is used to add transactions from the RPC API and performs synchronous pool -// reorganization and event propagation. -func (pool *LegacyPool) addLocals(txs []*types.Transaction) []error { - return pool.Add(txs, !pool.config.NoLocals, true) -} - -// addLocal enqueues a single local transaction into the pool if it is valid. This is -// a convenience wrapper around addLocals. -func (pool *LegacyPool) addLocal(tx *types.Transaction) error { - return pool.addLocals([]*types.Transaction{tx})[0] -} - -// addRemotes enqueues a batch of transactions into the pool if they are valid. If the -// senders are not among the locally tracked ones, full pricing constraints will apply. +// addRemotes enqueues a batch of transactions into the pool if they are valid. +// Full pricing constraints will apply. // // This method is used to add transactions from the p2p network and does not wait for pool // reorganization and internal event propagation. func (pool *LegacyPool) addRemotes(txs []*types.Transaction) []error { - return pool.Add(txs, false, false) + return pool.Add(txs, false) } // addRemote enqueues a single transaction into the pool if it is valid. This is a convenience @@ -1087,23 +963,19 @@ func (pool *LegacyPool) addRemote(tx *types.Transaction) error { // addRemotesSync is like addRemotes, but waits for pool reorganization. Tests use this method. func (pool *LegacyPool) addRemotesSync(txs []*types.Transaction) []error { - return pool.Add(txs, false, true) + return pool.Add(txs, true) } // This is like addRemotes with a single transaction, but waits for pool reorganization. Tests use this method. func (pool *LegacyPool) addRemoteSync(tx *types.Transaction) error { - return pool.Add([]*types.Transaction{tx}, false, true)[0] + return pool.Add([]*types.Transaction{tx}, true)[0] } -// Add enqueues a batch of transactions into the pool if they are valid. Depending -// on the local flag, full pricing constraints will or will not be applied. +// Add enqueues a batch of transactions into the pool if they are valid. // // If sync is set, the method will block until all internal maintenance related // to the add is finished. Only use this during tests for determinism! -func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error { - // Do not treat as local if local transactions have been disabled - local = local && !pool.config.NoLocals - +func (pool *LegacyPool) Add(txs []*types.Transaction, sync bool) []error { // Filter out known ones without obtaining the pool lock or recovering signatures var ( errs = make([]error, len(txs)) @@ -1119,7 +991,7 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error // Exclude transactions with basic errors, e.g invalid signatures and // insufficient intrinsic gas as soon as possible and cache senders // in transactions before obtaining lock - if err := pool.validateTxBasics(tx, local); err != nil { + if err := pool.validateTxBasics(tx); err != nil { errs[i] = err log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err) invalidTxMeter.Mark(1) @@ -1134,7 +1006,7 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error // Process all the new transaction and merge any errors into the original slice pool.mu.Lock() - newErrs, dirtyAddrs := pool.addTxsLocked(news, local) + newErrs, dirtyAddrs := pool.addTxsLocked(news) pool.mu.Unlock() var nilSlot = 0 @@ -1159,11 +1031,11 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, local, sync bool) []error // addTxsLocked attempts to queue a batch of transactions if they are valid. // The transaction pool lock must be held. -func (pool *LegacyPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error, *accountSet) { +func (pool *LegacyPool) addTxsLocked(txs []*types.Transaction) ([]error, *accountSet) { dirty := newAccountSet(pool.signer) errs := make([]error, len(txs)) for i, tx := range txs { - replaced, err := pool.add(tx, local) + replaced, err := pool.add(tx) errs[i] = err if err == nil && !replaced { dirty.addTx(tx) @@ -1255,9 +1127,6 @@ func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bo if outofbound { pool.priced.Removed(1) } - if pool.locals.contains(addr) { - localGauge.Dec(1) - } // Remove the transaction from the pending lists and reset the account nonce if pending := pool.pending[addr]; pending != nil { if removed, invalids := pending.Remove(tx); removed { @@ -1268,7 +1137,7 @@ func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bo // Postpone any invalidated transactions for _, tx := range invalids { // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(tx.Hash(), tx, false, false) + pool.enqueueTx(tx.Hash(), tx, false) } // Update the account nonce if needed pool.pendingNonces.setIfLower(addr, tx.Nonce()) @@ -1333,7 +1202,7 @@ func (pool *LegacyPool) scheduleReorgLoop() { launchNextRun bool reset *txpoolResetRequest dirtyAccounts *accountSet - queuedEvents = make(map[common.Address]*sortedMap) + queuedEvents = make(map[common.Address]*SortedMap) ) for { // Launch next background reorg if needed @@ -1346,7 +1215,7 @@ func (pool *LegacyPool) scheduleReorgLoop() { launchNextRun = false reset, dirtyAccounts = nil, nil - queuedEvents = make(map[common.Address]*sortedMap) + queuedEvents = make(map[common.Address]*SortedMap) } select { @@ -1375,7 +1244,7 @@ func (pool *LegacyPool) scheduleReorgLoop() { // request one later if they want the events sent. addr, _ := types.Sender(pool.signer, tx) if _, ok := queuedEvents[addr]; !ok { - queuedEvents[addr] = newSortedMap() + queuedEvents[addr] = NewSortedMap() } queuedEvents[addr].Put(tx) @@ -1394,7 +1263,7 @@ func (pool *LegacyPool) scheduleReorgLoop() { } // runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. -func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*sortedMap) { +func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*SortedMap) { defer func(t0 time.Time) { reorgDurationTimer.Update(time.Since(t0)) }(time.Now()) @@ -1461,7 +1330,7 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest, for _, tx := range promoted { addr, _ := types.Sender(pool.signer, tx) if _, ok := events[addr]; !ok { - events[addr] = newSortedMap() + events[addr] = NewSortedMap() } events[addr].Put(tx) } @@ -1570,7 +1439,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) { // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) core.SenderCacher().Recover(pool.signer, reinject) - pool.addTxsLocked(reinject, false) + pool.addTxsLocked(reinject) } // promoteExecutables moves transactions that have become processable from the @@ -1615,22 +1484,17 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T queuedGauge.Dec(int64(len(readies))) // Drop all transactions over the allowed limit - var caps types.Transactions - if !pool.locals.contains(addr) { - caps = list.Cap(int(pool.config.AccountQueue)) - for _, tx := range caps { - hash := tx.Hash() - pool.all.Remove(hash) - log.Trace("Removed cap-exceeding queued transaction", "hash", hash) - } - queuedRateLimitMeter.Mark(int64(len(caps))) + var caps = list.Cap(int(pool.config.AccountQueue)) + for _, tx := range caps { + hash := tx.Hash() + pool.all.Remove(hash) + log.Trace("Removed cap-exceeding queued transaction", "hash", hash) } + queuedRateLimitMeter.Mark(int64(len(caps))) // Mark all the items dropped as removed pool.priced.Removed(len(forwards) + len(drops) + len(caps)) queuedGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(forwards) + len(drops) + len(caps))) - } + // Delete the entire queue entry if it became empty. if list.Empty() { delete(pool.queue, addr) @@ -1660,14 +1524,14 @@ func (pool *LegacyPool) truncatePending() { spammers := prque.New[int64, common.Address](nil) for addr, list := range pool.pending { // Only evict transactions from high rollers - if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { + if uint64(list.Len()) > pool.config.AccountSlots { spammers.Push(addr, int64(list.Len())) } } // Gradually drop transactions from offenders offenders := []common.Address{} for pending > pool.config.GlobalSlots && !spammers.Empty() { - // Retrieve the next offender if not local address + // Retrieve the next offender offender, _ := spammers.Pop() offenders = append(offenders, offender) @@ -1693,9 +1557,7 @@ func (pool *LegacyPool) truncatePending() { } pool.priced.Removed(len(caps)) pendingGauge.Dec(int64(len(caps))) - if pool.locals.contains(offenders[i]) { - localGauge.Dec(int64(len(caps))) - } + pending-- } } @@ -1720,9 +1582,6 @@ func (pool *LegacyPool) truncatePending() { } pool.priced.Removed(len(caps)) pendingGauge.Dec(int64(len(caps))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(caps))) - } pending-- } } @@ -1743,13 +1602,11 @@ func (pool *LegacyPool) truncateQueue() { // Sort all accounts with queued transactions by heartbeat addresses := make(addressesByHeartbeat, 0, len(pool.queue)) for addr := range pool.queue { - if !pool.locals.contains(addr) { // don't drop locals - addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) - } + addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) } sort.Sort(sort.Reverse(addresses)) - // Drop transactions until the total is below the limit or only locals remain + // Drop transactions until the total is below the limit for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { addr := addresses[len(addresses)-1] list := pool.queue[addr.address] @@ -1809,12 +1666,10 @@ func (pool *LegacyPool) demoteUnexecutables() { log.Trace("Demoting pending transaction", "hash", hash) // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(hash, tx, false, false) + pool.enqueueTx(hash, tx, false) } pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) - if pool.locals.contains(addr) { - localGauge.Dec(int64(len(olds) + len(drops) + len(invalids))) - } + // If there's a gap in front, alert (should never happen) and postpone all transactions if list.Len() > 0 && list.txs.Get(nonce) == nil { gapped := list.Cap(0) @@ -1823,7 +1678,7 @@ func (pool *LegacyPool) demoteUnexecutables() { log.Error("Demoting invalidated transaction", "hash", hash) // Internal shuffle shouldn't touch the lookup set. - pool.enqueueTx(hash, tx, false, false) + pool.enqueueTx(hash, tx, false) } pendingGauge.Dec(int64(len(gapped))) } @@ -1870,21 +1725,6 @@ func newAccountSet(signer types.Signer, addrs ...common.Address) *accountSet { return as } -// contains checks if a given address is contained within the set. -func (as *accountSet) contains(addr common.Address) bool { - _, exist := as.accounts[addr] - return exist -} - -// containsTx checks if the sender of a given tx is within the set. If the sender -// cannot be derived, this method returns false. -func (as *accountSet) containsTx(tx *types.Transaction) bool { - if addr, err := types.Sender(as.signer, tx); err == nil { - return as.contains(addr) - } - return false -} - // add inserts a new address into the set to track. func (as *accountSet) add(addr common.Address) { as.accounts[addr] = struct{}{} @@ -1922,43 +1762,29 @@ func (as *accountSet) merge(other *accountSet) { // internal mechanisms. The sole purpose of the type is to permit out-of-bound // peeking into the pool in LegacyPool.Get without having to acquire the widely scoped // LegacyPool.mu mutex. -// -// This lookup set combines the notion of "local transactions", which is useful -// to build upper-level structure. type lookup struct { - slots int - lock sync.RWMutex - locals map[common.Hash]*types.Transaction - remotes map[common.Hash]*types.Transaction + slots int + lock sync.RWMutex + txs map[common.Hash]*types.Transaction } // newLookup returns a new lookup structure. func newLookup() *lookup { return &lookup{ - locals: make(map[common.Hash]*types.Transaction), - remotes: make(map[common.Hash]*types.Transaction), + txs: make(map[common.Hash]*types.Transaction), } } // Range calls f on each key and value present in the map. The callback passed // should return the indicator whether the iteration needs to be continued. // Callers need to specify which set (or both) to be iterated. -func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { +func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) { t.lock.RLock() defer t.lock.RUnlock() - if local { - for key, value := range t.locals { - if !f(key, value, true) { - return - } - } - } - if remote { - for key, value := range t.remotes { - if !f(key, value, false) { - return - } + for key, value := range t.txs { + if !f(key, value) { + return } } } @@ -1968,26 +1794,7 @@ func (t *lookup) Get(hash common.Hash) *types.Transaction { t.lock.RLock() defer t.lock.RUnlock() - if tx := t.locals[hash]; tx != nil { - return tx - } - return t.remotes[hash] -} - -// GetLocal returns a transaction if it exists in the lookup, or nil if not found. -func (t *lookup) GetLocal(hash common.Hash) *types.Transaction { - t.lock.RLock() - defer t.lock.RUnlock() - - return t.locals[hash] -} - -// GetRemote returns a transaction if it exists in the lookup, or nil if not found. -func (t *lookup) GetRemote(hash common.Hash) *types.Transaction { - t.lock.RLock() - defer t.lock.RUnlock() - - return t.remotes[hash] + return t.txs[hash] } // Count returns the current number of transactions in the lookup. @@ -1995,23 +1802,7 @@ func (t *lookup) Count() int { t.lock.RLock() defer t.lock.RUnlock() - return len(t.locals) + len(t.remotes) -} - -// LocalCount returns the current number of local transactions in the lookup. -func (t *lookup) LocalCount() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return len(t.locals) -} - -// RemoteCount returns the current number of remote transactions in the lookup. -func (t *lookup) RemoteCount() int { - t.lock.RLock() - defer t.lock.RUnlock() - - return len(t.remotes) + return len(t.txs) } // Slots returns the current number of slots used in the lookup. @@ -2023,18 +1814,14 @@ func (t *lookup) Slots() int { } // Add adds a transaction to the lookup. -func (t *lookup) Add(tx *types.Transaction, local bool) { +func (t *lookup) Add(tx *types.Transaction) { t.lock.Lock() defer t.lock.Unlock() t.slots += numSlots(tx) slotsGauge.Update(int64(t.slots)) - if local { - t.locals[tx.Hash()] = tx - } else { - t.remotes[tx.Hash()] = tx - } + t.txs[tx.Hash()] = tx } // Remove removes a transaction from the lookup. @@ -2042,10 +1829,7 @@ func (t *lookup) Remove(hash common.Hash) { t.lock.Lock() defer t.lock.Unlock() - tx, ok := t.locals[hash] - if !ok { - tx, ok = t.remotes[hash] - } + tx, ok := t.txs[hash] if !ok { log.Error("No transaction found to be deleted", "hash", hash) return @@ -2053,36 +1837,18 @@ func (t *lookup) Remove(hash common.Hash) { t.slots -= numSlots(tx) slotsGauge.Update(int64(t.slots)) - delete(t.locals, hash) - delete(t.remotes, hash) + delete(t.txs, hash) } -// RemoteToLocals migrates the transactions belongs to the given locals to locals -// set. The assumption is held the locals set is thread-safe to be used. -func (t *lookup) RemoteToLocals(locals *accountSet) int { - t.lock.Lock() - defer t.lock.Unlock() - - var migrated int - for hash, tx := range t.remotes { - if locals.containsTx(tx) { - t.locals[hash] = tx - delete(t.remotes, hash) - migrated += 1 - } - } - return migrated -} - -// RemotesBelowTip finds all remote transactions below the given tip threshold. -func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions { +// TxsBelowTip finds all remote transactions below the given tip threshold. +func (t *lookup) TxsBelowTip(threshold *big.Int) types.Transactions { found := make(types.Transactions, 0, 128) - t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { + t.Range(func(hash common.Hash, tx *types.Transaction) bool { if tx.GasTipCapIntCmp(threshold) < 0 { found = append(found, tx) } return true - }, false, true) // Only iterate remotes + }) return found } @@ -2111,24 +1877,13 @@ func (pool *LegacyPool) Clear() { // The transaction addition may attempt to reserve the sender addr which // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. - for _, tx := range pool.all.remotes { + for _, tx := range pool.all.txs { senderAddr, _ := types.Sender(pool.signer, tx) pool.reserve(senderAddr, false) } - for localSender := range pool.locals.accounts { - pool.reserve(localSender, false) - } - pool.all = newLookup() pool.priced = newPricedList(pool.all) pool.pending = make(map[common.Address]*list) pool.queue = make(map[common.Address]*list) pool.pendingNonces = newNoncer(pool.currentState) - - if !pool.config.NoLocals && pool.config.Journal != "" { - pool.journal = newTxJournal(pool.config.Journal) - if err := pool.journal.rotate(pool.local()); err != nil { - log.Warn("Failed to rotate transaction journal", "err", err) - } - } } diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index abbde8cae..55699e93e 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -23,7 +23,6 @@ import ( "fmt" "math/big" "math/rand" - "os" "sync" "sync/atomic" "testing" @@ -183,7 +182,7 @@ func validatePoolInternals(pool *LegacyPool) error { return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued) } pool.priced.Reheap() - priced, remote := pool.priced.urgent.Len()+pool.priced.floating.Len(), pool.all.RemoteCount() + priced, remote := pool.priced.urgent.Len()+pool.priced.floating.Len(), pool.all.Count() if priced != remote { return fmt.Errorf("total priced transaction count %d != %d", priced, remote) } @@ -350,9 +349,6 @@ func TestInvalidTransactions(t *testing.T) { if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } - if err := pool.addLocal(tx); err != nil { - t.Error("expected", nil, "got", err) - } } func TestQueue(t *testing.T) { @@ -366,7 +362,7 @@ func TestQueue(t *testing.T) { testAddBalance(pool, from, big.NewInt(1000)) <-pool.requestReset(nil, nil) - pool.enqueueTx(tx.Hash(), tx, false, true) + pool.enqueueTx(tx.Hash(), tx, true) <-pool.requestPromoteExecutables(newAccountSet(pool.signer, from)) if len(pool.pending) != 1 { t.Error("expected valid txs to be 1 is", len(pool.pending)) @@ -375,7 +371,7 @@ func TestQueue(t *testing.T) { tx = transaction(1, 100, key) from, _ = deriveSender(tx) testSetNonce(pool, from, 2) - pool.enqueueTx(tx.Hash(), tx, false, true) + pool.enqueueTx(tx.Hash(), tx, true) <-pool.requestPromoteExecutables(newAccountSet(pool.signer, from)) if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { @@ -399,9 +395,9 @@ func TestQueue2(t *testing.T) { testAddBalance(pool, from, big.NewInt(1000)) pool.reset(nil, nil) - pool.enqueueTx(tx1.Hash(), tx1, false, true) - pool.enqueueTx(tx2.Hash(), tx2, false, true) - pool.enqueueTx(tx3.Hash(), tx3, false, true) + pool.enqueueTx(tx1.Hash(), tx1, true) + pool.enqueueTx(tx2.Hash(), tx2, true) + pool.enqueueTx(tx3.Hash(), tx3, true) pool.promoteExecutables([]common.Address{from}) if len(pool.pending) != 1 { @@ -476,14 +472,14 @@ func TestChainFork(t *testing.T) { resetState() tx := transaction(0, 100000, key) - if _, err := pool.add(tx, false); err != nil { + if _, err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } pool.removeTx(tx.Hash(), true, true) // reset the pool's internal state resetState() - if _, err := pool.add(tx, false); err != nil { + if _, err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } } @@ -510,10 +506,10 @@ func TestDoubleNonce(t *testing.T) { tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key) // Add the first two transaction, ensure higher priced stays only - if replace, err := pool.add(tx1, false); err != nil || replace { + if replace, err := pool.add(tx1); err != nil || replace { t.Errorf("first transaction insert failed (%v) or reported replacement (%v)", err, replace) } - if replace, err := pool.add(tx2, false); err != nil || !replace { + if replace, err := pool.add(tx2); err != nil || !replace { t.Errorf("second transaction insert failed (%v) or not reported replacement (%v)", err, replace) } <-pool.requestPromoteExecutables(newAccountSet(signer, addr)) @@ -525,7 +521,7 @@ func TestDoubleNonce(t *testing.T) { } // Add the third transaction and ensure it's not saved (smaller price) - pool.add(tx3, false) + pool.add(tx3) <-pool.requestPromoteExecutables(newAccountSet(signer, addr)) if pool.pending[addr].Len() != 1 { t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) @@ -548,7 +544,7 @@ func TestMissingNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, addr, big.NewInt(100000000000000)) tx := transaction(1, 100000, key) - if _, err := pool.add(tx, false); err != nil { + if _, err := pool.add(tx); err != nil { t.Error("didn't expect error", err) } if len(pool.pending) != 0 { @@ -607,21 +603,21 @@ func TestDropping(t *testing.T) { tx11 = transaction(11, 200, key) tx12 = transaction(12, 300, key) ) - pool.all.Add(tx0, false) - pool.priced.Put(tx0, false) + pool.all.Add(tx0) + pool.priced.Put(tx0) pool.promoteTx(account, tx0.Hash(), tx0) - pool.all.Add(tx1, false) - pool.priced.Put(tx1, false) + pool.all.Add(tx1) + pool.priced.Put(tx1) pool.promoteTx(account, tx1.Hash(), tx1) - pool.all.Add(tx2, false) - pool.priced.Put(tx2, false) + pool.all.Add(tx2) + pool.priced.Put(tx2) pool.promoteTx(account, tx2.Hash(), tx2) - pool.enqueueTx(tx10.Hash(), tx10, false, true) - pool.enqueueTx(tx11.Hash(), tx11, false, true) - pool.enqueueTx(tx12.Hash(), tx12, false, true) + pool.enqueueTx(tx10.Hash(), tx10, true) + pool.enqueueTx(tx11.Hash(), tx11, true) + pool.enqueueTx(tx12.Hash(), tx12, true) // Check that pre and post validations leave the pool as is if pool.pending[account].Len() != 3 { @@ -899,13 +895,6 @@ func TestQueueAccountLimiting(t *testing.T) { // This logic should not hold for local transactions, unless the local tracking // mechanism is disabled. func TestQueueGlobalLimiting(t *testing.T) { - testQueueGlobalLimiting(t, false) -} -func TestQueueGlobalLimitingNoLocals(t *testing.T) { - testQueueGlobalLimiting(t, true) -} - -func testQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with @@ -913,7 +902,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig - config.NoLocals = nolocals + config.NoLocals = true config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) pool := New(config, blockchain) @@ -926,7 +915,6 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { keys[i], _ = crypto.GenerateKey() testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) } - local := keys[len(keys)-1] // Generate and queue a batch of transactions nonces := make(map[common.Address]uint64) @@ -952,51 +940,12 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { if queued > int(config.GlobalQueue) { t.Fatalf("total transactions overflow allowance: %d > %d", queued, config.GlobalQueue) } - // Generate a batch of transactions from the local account and import them - txs = txs[:0] - for i := uint64(0); i < 3*config.GlobalQueue; i++ { - txs = append(txs, transaction(i+1, 100000, local)) - } - pool.addLocals(txs) - - // If locals are disabled, the previous eviction algorithm should apply here too - if nolocals { - queued := 0 - for addr, list := range pool.queue { - if list.Len() > int(config.AccountQueue) { - t.Errorf("addr %x: queued accounts overflown allowance: %d > %d", addr, list.Len(), config.AccountQueue) - } - queued += list.Len() - } - if queued > int(config.GlobalQueue) { - t.Fatalf("total transactions overflow allowance: %d > %d", queued, config.GlobalQueue) - } - } else { - // Local exemptions are enabled, make sure the local account owned the queue - if len(pool.queue) != 1 { - t.Errorf("multiple accounts in queue: have %v, want %v", len(pool.queue), 1) - } - // Also ensure no local transactions are ever dropped, even if above global limits - if queued := pool.queue[crypto.PubkeyToAddress(local.PublicKey)].Len(); uint64(queued) != 3*config.GlobalQueue { - t.Fatalf("local account queued transaction count mismatch: have %v, want %v", queued, 3*config.GlobalQueue) - } - } } // Tests that if an account remains idle for a prolonged amount of time, any // non-executable transactions queued up are dropped to prevent wasting resources // on shuffling them around. -// -// This logic should not hold for local transactions, unless the local tracking -// mechanism is disabled. func TestQueueTimeLimiting(t *testing.T) { - testQueueTimeLimiting(t, false) -} -func TestQueueTimeLimitingNoLocals(t *testing.T) { - testQueueTimeLimiting(t, true) -} - -func testQueueTimeLimiting(t *testing.T, nolocals bool) { // Reduce the eviction interval to a testable amount defer func(old time.Duration) { evictionInterval = old }(evictionInterval) evictionInterval = time.Millisecond * 100 @@ -1007,23 +956,17 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { config := testTxPoolConfig config.Lifetime = time.Second - config.NoLocals = nolocals pool := New(config, blockchain) pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) defer pool.Close() - // Create two test accounts to ensure remotes expire but locals do not - local, _ := crypto.GenerateKey() + // Create a test account to ensure remotes expire remote, _ := crypto.GenerateKey() - testAddBalance(pool, crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) - // Add the two transactions and ensure they both are queued up - if err := pool.addLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add local transaction: %v", err) - } + // Add the transaction and ensure it is queued up if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } @@ -1031,7 +974,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { if pending != 0 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) } - if queued != 2 { + if queued != 1 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } if err := validatePoolInternals(pool); err != nil { @@ -1046,7 +989,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { if pending != 0 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) } - if queued != 2 { + if queued != 1 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } if err := validatePoolInternals(pool); err != nil { @@ -1060,14 +1003,8 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { if pending != 0 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) } - if nolocals { - if queued != 0 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) - } - } else { - if queued != 1 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) - } + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) @@ -1075,7 +1012,6 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { // remove current transactions and increase nonce to prepare for a reset and cleanup statedb.SetNonce(crypto.PubkeyToAddress(remote.PublicKey), 2) - statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) <-pool.requestReset(nil, nil) // make sure queue, pending are cleared @@ -1091,18 +1027,12 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { } // Queue gapped transactions - if err := pool.addLocal(pricedTransaction(4, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add remote transaction: %v", err) - } if err := pool.addRemoteSync(pricedTransaction(4, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } time.Sleep(5 * evictionInterval) // A half lifetime pass // Queue executable transactions, the life cycle should be restarted. - if err := pool.addLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add remote transaction: %v", err) - } if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } @@ -1110,11 +1040,11 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { // All gapped transactions shouldn't be kicked out pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 1 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) } - if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) + if queued != 1 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) @@ -1123,17 +1053,11 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { // The whole life time pass after last promotion, kick out stale transactions time.Sleep(2 * config.Lifetime) pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 1 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) } - if nolocals { - if queued != 0 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) - } - } else { - if queued != 1 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) - } + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) @@ -1363,8 +1287,6 @@ func TestPendingMinimumAllowance(t *testing.T) { // Tests that setting the transaction pool gas price to a higher value correctly // discards everything cheaper than that and moves any gapped transactions back // from the pending pool to the queue. -// -// Note, local transactions are never allowed to be dropped. func TestRepricing(t *testing.T) { t.Parallel() @@ -1382,7 +1304,7 @@ func TestRepricing(t *testing.T) { defer sub.Unsubscribe() // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 4) + keys := make([]*ecdsa.PrivateKey, 3) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) @@ -1402,20 +1324,17 @@ func TestRepricing(t *testing.T) { txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2])) - ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3]) - // Import the batch and that both pending and queued transactions match up pool.addRemotesSync(txs) - pool.addLocal(ltx) pending, queued := pool.Stats() - if pending != 7 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7) + if pending != 6 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 6) } if queued != 3 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) } - if err := validateEvents(events, 7); err != nil { + if err := validateEvents(events, 6); err != nil { t.Fatalf("original event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { @@ -1425,8 +1344,8 @@ func TestRepricing(t *testing.T) { pool.SetGasTip(big.NewInt(2)) pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 1 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) } if queued != 5 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) @@ -1453,21 +1372,7 @@ func TestRepricing(t *testing.T) { if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } - // However we can add local underpriced transactions - tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3]) - if err := pool.addLocal(tx); err != nil { - t.Fatalf("failed to add underpriced local transaction: %v", err) - } - if pending, _ = pool.Stats(); pending != 3 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) - } - if err := validateEvents(events, 1); err != nil { - t.Fatalf("post-reprice local event firing failed: %v", err) - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - // And we can fill gaps with properly priced transactions + // we can fill gaps with properly priced transactions if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } @@ -1504,29 +1409,16 @@ func TestMinGasPriceEnforced(t *testing.T) { tx := pricedTransaction(0, 100000, big.NewInt(2), key) pool.SetGasTip(big.NewInt(tx.GasPrice().Int64() + 1)) - if err := pool.addLocal(tx); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("Min tip not enforced") - } - - if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrUnderpriced) { t.Fatalf("Min tip not enforced") } tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), key) pool.SetGasTip(big.NewInt(tx.GasTipCap().Int64() + 1)) - if err := pool.addLocal(tx); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("Min tip not enforced") - } - - if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrUnderpriced) { t.Fatalf("Min tip not enforced") } - // Make sure the tx is accepted if locals are enabled - pool.config.NoLocals = false - if err := pool.Add([]*types.Transaction{tx}, true, false)[0]; err != nil { - t.Fatalf("Min tip enforced with locals enabled, error: %v", err) - } } // Tests that setting the transaction pool gas price to a higher value correctly @@ -1567,20 +1459,17 @@ func TestRepricingDynamicFee(t *testing.T) { txs = append(txs, dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2])) txs = append(txs, dynamicFeeTx(3, 100000, big.NewInt(2), big.NewInt(2), keys[2])) - ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[3]) - // Import the batch and that both pending and queued transactions match up pool.addRemotesSync(txs) - pool.addLocal(ltx) pending, queued := pool.Stats() - if pending != 7 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7) + if pending != 6 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 6) } if queued != 3 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) } - if err := validateEvents(events, 7); err != nil { + if err := validateEvents(events, 6); err != nil { t.Fatalf("original event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { @@ -1590,8 +1479,8 @@ func TestRepricingDynamicFee(t *testing.T) { pool.SetGasTip(big.NewInt(2)) pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 1 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1) } if queued != 5 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5) @@ -1621,20 +1510,7 @@ func TestRepricingDynamicFee(t *testing.T) { if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } - // However we can add local underpriced transactions - tx = dynamicFeeTx(1, 100000, big.NewInt(1), big.NewInt(1), keys[3]) - if err := pool.addLocal(tx); err != nil { - t.Fatalf("failed to add underpriced local transaction: %v", err) - } - if pending, _ = pool.Stats(); pending != 3 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) - } - if err := validateEvents(events, 1); err != nil { - t.Fatalf("post-reprice local event firing failed: %v", err) - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } + // And we can fill gaps with properly priced transactions tx = pricedTransaction(1, 100000, big.NewInt(2), keys[0]) if err := pool.addRemote(tx); err != nil { @@ -1656,77 +1532,6 @@ func TestRepricingDynamicFee(t *testing.T) { } } -// Tests that setting the transaction pool gas price to a higher value does not -// remove local transactions (legacy & dynamic fee). -func TestRepricingKeepsLocals(t *testing.T) { - t.Parallel() - - // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) - - pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) - defer pool.Close() - - // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 3) - for i := 0; i < len(keys); i++ { - keys[i], _ = crypto.GenerateKey() - testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(100000*1000000)) - } - // Create transaction (both pending and queued) with a linearly growing gasprice - for i := uint64(0); i < 500; i++ { - // Add pending transaction. - pendingTx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.addLocal(pendingTx); err != nil { - t.Fatal(err) - } - // Add queued transaction. - queuedTx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) - if err := pool.addLocal(queuedTx); err != nil { - t.Fatal(err) - } - - // Add pending dynamic fee transaction. - pendingTx = dynamicFeeTx(i, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1]) - if err := pool.addLocal(pendingTx); err != nil { - t.Fatal(err) - } - // Add queued dynamic fee transaction. - queuedTx = dynamicFeeTx(i+501, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1]) - if err := pool.addLocal(queuedTx); err != nil { - t.Fatal(err) - } - } - pending, queued := pool.Stats() - expPending, expQueued := 1000, 1000 - validate := func() { - pending, queued = pool.Stats() - if pending != expPending { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, expPending) - } - if queued != expQueued { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, expQueued) - } - - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - } - validate() - - // Reprice the pool and check that nothing is dropped - pool.SetGasTip(big.NewInt(2)) - validate() - - pool.SetGasTip(big.NewInt(2)) - pool.SetGasTip(big.NewInt(4)) - pool.SetGasTip(big.NewInt(8)) - pool.SetGasTip(big.NewInt(100)) - validate() -} - // Tests that when the pool reaches its global transaction limit, underpriced // transactions are gradually shifted out for more expensive ones and any gapped // pending transactions are moved into the queue. @@ -1756,21 +1561,18 @@ func TestUnderpricing(t *testing.T) { keys := make([]*ecdsa.PrivateKey, 5) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() - testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) + testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(10000000)) } // Generate and queue a batch of transactions, both pending and queued txs := types.Transactions{} - txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) - txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) - - txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[1])) - - ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) // pending + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) // pending + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[2])) // pending + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[1])) // queued // Import the batch and that both pending and queued transactions match up - pool.addRemotes(txs) - pool.addLocal(ltx) + pool.addRemotesSync(txs) pending, queued := pool.Stats() if pending != 3 { @@ -1790,7 +1592,7 @@ func TestUnderpricing(t *testing.T) { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } // Replace a future transaction with a future transaction - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that adding high priced transactions drops cheap ones, but not own @@ -1800,48 +1602,26 @@ func TestUnderpricing(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { // +K1:2 => -K0:0 => Pend K1:0, K2:0; Que K0:1 K1:2 t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.addRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 + if err := pool.addRemoteSync(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that replacing a pending transaction with a future transaction fails - if err := pool.addRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending { + if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending { t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, txpool.ErrFutureReplacePending) } pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 4 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) } - if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateEvents(events, 2); err != nil { + if err := validateEvents(events, 4); err != nil { t.Fatalf("additional event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } - // Ensure that adding local transactions can push out even higher priced ones - ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2]) - if err := pool.addLocal(ltx); err != nil { - t.Fatalf("failed to append underpriced local transaction: %v", err) - } - ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3]) - if err := pool.addLocal(ltx); err != nil { - t.Fatalf("failed to add new underpriced local transaction: %v", err) - } - pending, queued = pool.Stats() - if pending != 3 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) - } - if queued != 1 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) - } - if err := validateEvents(events, 2); err != nil { - t.Fatalf("local event firing failed: %v", err) - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } } // Tests that more expensive transactions push out cheap ones from the pool, but @@ -1915,8 +1695,6 @@ func TestStableUnderpricing(t *testing.T) { // Tests that when the pool reaches its global transaction limit, underpriced // transactions (legacy & dynamic fee) are gradually shifted out for more // expensive ones and any gapped pending transactions are moved into the queue. -// -// Note, local transactions are never allowed to be dropped. func TestUnderpricingDynamicFee(t *testing.T) { t.Parallel() @@ -1941,15 +1719,13 @@ func TestUnderpricingDynamicFee(t *testing.T) { // Generate and queue a batch of transactions, both pending and queued txs := types.Transactions{} - txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0])) - txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) - txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(1), keys[1])) - - ltx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[2]) + txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0])) // pending + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) // pending + txs = append(txs, dynamicFeeTx(1, 100000, big.NewInt(2), big.NewInt(1), keys[1])) // queued + txs = append(txs, dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[2])) // pending - // Import the batch and that both pending and queued transactions match up - pool.addRemotes(txs) // Pend K0:0, K0:1; Que K1:1 - pool.addLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1 + // Import the batch and check that both pending and queued transactions match up + pool.addRemotesSync(txs) // Pend K0:0, K0:1; Que K1:1 pending, queued := pool.Stats() if pending != 3 { @@ -1967,13 +1743,13 @@ func TestUnderpricingDynamicFee(t *testing.T) { // Ensure that adding an underpriced transaction fails tx := dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) - if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { // Pend K0:0, K0:1, K2:0; Que K1:1 + if err := pool.addRemoteSync(tx); !errors.Is(err, txpool.ErrUnderpriced) { // Pend K0:0, K0:1, K2:0; Que K1:1 t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) } // Ensure that adding high priced transactions drops cheap ones, but not own tx = pricedTransaction(0, 100000, big.NewInt(2), keys[1]) - if err := pool.addRemote(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - + if err := pool.addRemoteSync(tx); err != nil { // +K1:0, -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - t.Fatalf("failed to add well priced transaction: %v", err) } @@ -1986,40 +1762,18 @@ func TestUnderpricingDynamicFee(t *testing.T) { t.Fatalf("failed to add well priced transaction: %v", err) } pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 4 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) } - if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateEvents(events, 2); err != nil { + if err := validateEvents(events, 3); err != nil { t.Fatalf("additional event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } - // Ensure that adding local transactions can push out even higher priced ones - ltx = dynamicFeeTx(1, 100000, big.NewInt(0), big.NewInt(0), keys[2]) - if err := pool.addLocal(ltx); err != nil { - t.Fatalf("failed to append underpriced local transaction: %v", err) - } - ltx = dynamicFeeTx(0, 100000, big.NewInt(0), big.NewInt(0), keys[3]) - if err := pool.addLocal(ltx); err != nil { - t.Fatalf("failed to add new underpriced local transaction: %v", err) - } - pending, queued = pool.Stats() - if pending != 3 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) - } - if queued != 1 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) - } - if err := validateEvents(events, 2); err != nil { - t.Fatalf("local event firing failed: %v", err) - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } } // Tests whether highest fee cap transaction is retained after a batch of high effective @@ -2039,7 +1793,7 @@ func TestDualHeapEviction(t *testing.T) { ) check := func(tx *types.Transaction, name string) { - if pool.all.GetRemote(tx.Hash()) == nil { + if pool.all.Get(tx.Hash()) == nil { t.Fatalf("highest %s transaction evicted from the pool", name) } } @@ -2336,122 +2090,6 @@ func TestReplacementDynamicFee(t *testing.T) { } } -// Tests that local transactions are journaled to disk, but remote transactions -// get discarded between restarts. -func TestJournaling(t *testing.T) { testJournaling(t, false) } -func TestJournalingNoLocals(t *testing.T) { testJournaling(t, true) } - -func testJournaling(t *testing.T, nolocals bool) { - t.Parallel() - - // Create a temporary file for the journal - file, err := os.CreateTemp("", "") - if err != nil { - t.Fatalf("failed to create temporary journal: %v", err) - } - journal := file.Name() - defer os.Remove(journal) - - // Clean up the temporary file, we only need the path for now - file.Close() - os.Remove(journal) - - // Create the original pool to inject transaction into the journal - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - - config := testTxPoolConfig - config.NoLocals = nolocals - config.Journal = journal - config.Rejournal = time.Second - - pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) - - // Create two test accounts to ensure remotes expire but locals do not - local, _ := crypto.GenerateKey() - remote, _ := crypto.GenerateKey() - - testAddBalance(pool, crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) - testAddBalance(pool, crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) - - // Add three local and a remote transactions and ensure they are queued up - if err := pool.addLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add local transaction: %v", err) - } - if err := pool.addLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add local transaction: %v", err) - } - if err := pool.addLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { - t.Fatalf("failed to add local transaction: %v", err) - } - if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil { - t.Fatalf("failed to add remote transaction: %v", err) - } - pending, queued := pool.Stats() - if pending != 4 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) - } - if queued != 0 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive - pool.Close() - statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - - pool = New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) - - pending, queued = pool.Stats() - if queued != 0 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) - } - if nolocals { - if pending != 0 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) - } - } else { - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) - } - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - // Bump the nonce temporarily and ensure the newly invalidated transaction is removed - statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) - <-pool.requestReset(nil, nil) - time.Sleep(2 * config.Rejournal) - pool.Close() - - statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) - pool = New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) - - pending, queued = pool.Stats() - if pending != 0 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) - } - if nolocals { - if queued != 0 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) - } - } else { - if queued != 1 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) - } - } - if err := validatePoolInternals(pool); err != nil { - t.Fatalf("pool internal state corrupted: %v", err) - } - pool.Close() -} - // TestStatusCheck tests that the pool can correctly retrieve the // pending status of individual transactions. func TestStatusCheck(t *testing.T) { @@ -2566,7 +2204,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) { for i := 0; i < size; i++ { tx := transaction(uint64(1+i), 100000, key) - pool.enqueueTx(tx.Hash(), tx, false, true) + pool.enqueueTx(tx.Hash(), tx, true) } // Benchmark the speed of pool validation b.ResetTimer() @@ -2576,15 +2214,11 @@ func benchmarkFuturePromotion(b *testing.B, size int) { } // Benchmarks the speed of batched transaction insertion. -func BenchmarkBatchInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, false) } -func BenchmarkBatchInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, false) } -func BenchmarkBatchInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, false) } +func BenchmarkBatchInsert100(b *testing.B) { benchmarkBatchInsert(b, 100) } +func BenchmarkBatchInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000) } +func BenchmarkBatchInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000) } -func BenchmarkBatchLocalInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, true) } -func BenchmarkBatchLocalInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, true) } -func BenchmarkBatchLocalInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, true) } - -func benchmarkBatchInsert(b *testing.B, size int, local bool) { +func benchmarkBatchInsert(b *testing.B, size int) { // Generate a batch of transactions to enqueue into the pool pool, key := setupPool() defer pool.Close() @@ -2602,46 +2236,7 @@ func benchmarkBatchInsert(b *testing.B, size int, local bool) { // Benchmark importing the transactions into the queue b.ResetTimer() for _, batch := range batches { - if local { - pool.addLocals(batch) - } else { - pool.addRemotes(batch) - } - } -} - -func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { - // Allocate keys for testing - key, _ := crypto.GenerateKey() - account := crypto.PubkeyToAddress(key.PublicKey) - - remoteKey, _ := crypto.GenerateKey() - remoteAddr := crypto.PubkeyToAddress(remoteKey.PublicKey) - - locals := make([]*types.Transaction, 4096+1024) // Occupy all slots - for i := 0; i < len(locals); i++ { - locals[i] = transaction(uint64(i), 100000, key) - } - remotes := make([]*types.Transaction, 1000) - for i := 0; i < len(remotes); i++ { - remotes[i] = pricedTransaction(uint64(i), 100000, big.NewInt(2), remoteKey) // Higher gasprice - } - // Benchmark importing the transactions into the queue - b.ResetTimer() - for i := 0; i < b.N; i++ { - b.StopTimer() - pool, _ := setupPool() - testAddBalance(pool, account, big.NewInt(100000000)) - for _, local := range locals { - pool.addLocal(local) - } - b.StartTimer() - // Assign a high enough balance for testing - testAddBalance(pool, remoteAddr, big.NewInt(100000000)) - for i := 0; i < len(remotes); i++ { - pool.addRemotes([]*types.Transaction{remotes[i]}) - } - pool.Close() + pool.addRemotes(batch) } } diff --git a/core/txpool/legacypool/list.go b/core/txpool/legacypool/list.go index b07543484..24a4de4b6 100644 --- a/core/txpool/legacypool/list.go +++ b/core/txpool/legacypool/list.go @@ -52,31 +52,31 @@ func (h *nonceHeap) Pop() interface{} { return x } -// sortedMap is a nonce->transaction hash map with a heap based index to allow +// SortedMap is a nonce->transaction hash map with a heap based index to allow // iterating over the contents in a nonce-incrementing way. -type sortedMap struct { +type SortedMap struct { items map[uint64]*types.Transaction // Hash map storing the transaction data index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) cache types.Transactions // Cache of the transactions already sorted cacheMu sync.Mutex // Mutex covering the cache } -// newSortedMap creates a new nonce-sorted transaction map. -func newSortedMap() *sortedMap { - return &sortedMap{ +// NewSortedMap creates a new nonce-sorted transaction map. +func NewSortedMap() *SortedMap { + return &SortedMap{ items: make(map[uint64]*types.Transaction), index: new(nonceHeap), } } // Get retrieves the current transactions associated with the given nonce. -func (m *sortedMap) Get(nonce uint64) *types.Transaction { +func (m *SortedMap) Get(nonce uint64) *types.Transaction { return m.items[nonce] } // Put inserts a new transaction into the map, also updating the map's nonce // index. If a transaction already exists with the same nonce, it's overwritten. -func (m *sortedMap) Put(tx *types.Transaction) { +func (m *SortedMap) Put(tx *types.Transaction) { nonce := tx.Nonce() if m.items[nonce] == nil { heap.Push(m.index, nonce) @@ -89,7 +89,7 @@ func (m *sortedMap) Put(tx *types.Transaction) { // Forward removes all transactions from the map with a nonce lower than the // provided threshold. Every removed transaction is returned for any post-removal // maintenance. -func (m *sortedMap) Forward(threshold uint64) types.Transactions { +func (m *SortedMap) Forward(threshold uint64) types.Transactions { var removed types.Transactions // Pop off heap items until the threshold is reached @@ -112,7 +112,7 @@ func (m *sortedMap) Forward(threshold uint64) types.Transactions { // Filter, as opposed to 'filter', re-initialises the heap after the operation is done. // If you want to do several consecutive filterings, it's therefore better to first // do a .filter(func1) followed by .Filter(func2) or reheap() -func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { +func (m *SortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { removed := m.filter(filter) // If transactions were removed, the heap and cache are ruined if len(removed) > 0 { @@ -121,7 +121,7 @@ func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transacti return removed } -func (m *sortedMap) reheap() { +func (m *SortedMap) reheap() { *m.index = make([]uint64, 0, len(m.items)) for nonce := range m.items { *m.index = append(*m.index, nonce) @@ -134,7 +134,7 @@ func (m *sortedMap) reheap() { // filter is identical to Filter, but **does not** regenerate the heap. This method // should only be used if followed immediately by a call to Filter or reheap() -func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { +func (m *SortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { var removed types.Transactions // Collect all the transactions to filter out @@ -154,7 +154,7 @@ func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transacti // Cap places a hard limit on the number of items, returning all transactions // exceeding that limit. -func (m *sortedMap) Cap(threshold int) types.Transactions { +func (m *SortedMap) Cap(threshold int) types.Transactions { // Short circuit if the number of items is under the limit if len(m.items) <= threshold { return nil @@ -181,7 +181,7 @@ func (m *sortedMap) Cap(threshold int) types.Transactions { // Remove deletes a transaction from the maintained map, returning whether the // transaction was found. -func (m *sortedMap) Remove(nonce uint64) bool { +func (m *SortedMap) Remove(nonce uint64) bool { // Short circuit if no transaction is present _, ok := m.items[nonce] if !ok { @@ -209,7 +209,7 @@ func (m *sortedMap) Remove(nonce uint64) bool { // Note, all transactions with nonces lower than start will also be returned to // prevent getting into an invalid state. This is not something that should ever // happen but better to be self correcting than failing! -func (m *sortedMap) Ready(start uint64) types.Transactions { +func (m *SortedMap) Ready(start uint64) types.Transactions { // Short circuit if no transactions are available if m.index.Len() == 0 || (*m.index)[0] > start { return nil @@ -229,11 +229,11 @@ func (m *sortedMap) Ready(start uint64) types.Transactions { } // Len returns the length of the transaction map. -func (m *sortedMap) Len() int { +func (m *SortedMap) Len() int { return len(m.items) } -func (m *sortedMap) flatten() types.Transactions { +func (m *SortedMap) flatten() types.Transactions { m.cacheMu.Lock() defer m.cacheMu.Unlock() // If the sorting was not cached yet, create and cache it @@ -250,7 +250,7 @@ func (m *sortedMap) flatten() types.Transactions { // Flatten creates a nonce-sorted slice of transactions based on the loosely // sorted internal representation. The result of the sorting is cached in case // it's requested again before any modifications are made to the contents. -func (m *sortedMap) Flatten() types.Transactions { +func (m *SortedMap) Flatten() types.Transactions { cache := m.flatten() // Copy the cache to prevent accidental modification txs := make(types.Transactions, len(cache)) @@ -260,7 +260,7 @@ func (m *sortedMap) Flatten() types.Transactions { // LastElement returns the last element of a flattened list, thus, the // transaction with the highest nonce -func (m *sortedMap) LastElement() *types.Transaction { +func (m *SortedMap) LastElement() *types.Transaction { cache := m.flatten() return cache[len(cache)-1] } @@ -271,7 +271,7 @@ func (m *sortedMap) LastElement() *types.Transaction { // executable/future queue, with minor behavioral changes. type list struct { strict bool // Whether nonces are strictly continuous or not - txs *sortedMap // Heap indexed sorted hash map of the transactions + txs *SortedMap // Heap indexed sorted hash map of the transactions costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance) gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) @@ -283,7 +283,7 @@ type list struct { func newList(strict bool) *list { return &list{ strict: strict, - txs: newSortedMap(), + txs: NewSortedMap(), costcap: new(uint256.Int), totalcost: new(uint256.Int), } @@ -585,10 +585,7 @@ func newPricedList(all *lookup) *pricedList { } // Put inserts a new transaction into the heap. -func (l *pricedList) Put(tx *types.Transaction, local bool) { - if local { - return - } +func (l *pricedList) Put(tx *types.Transaction) { // Insert every new transaction to the urgent heap first; Discard will balance the heaps heap.Push(&l.urgent, tx) } @@ -622,7 +619,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { // Discard stale price points if found at the heap start for len(h.list) > 0 { head := h.list[0] - if l.all.GetRemote(head.Hash()) == nil { // Removed or migrated + if l.all.Get(head.Hash()) == nil { // Removed or migrated l.stales.Add(-1) heap.Pop(h) continue @@ -641,15 +638,13 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { // Discard finds a number of most underpriced transactions, removes them from the // priced list and returns them for further removal from the entire pool. // If noPending is set to true, we will only consider the floating list -// -// Note local transaction won't be considered for eviction. -func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { +func (l *pricedList) Discard(slots int) (types.Transactions, bool) { drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop for slots > 0 { if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio { // Discard stale transactions if found during cleanup tx := heap.Pop(&l.urgent).(*types.Transaction) - if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated + if l.all.Get(tx.Hash()) == nil { // Removed or migrated l.stales.Add(-1) continue } @@ -662,7 +657,7 @@ func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { } // Discard stale transactions if found during cleanup tx := heap.Pop(&l.floating).(*types.Transaction) - if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated + if l.all.Get(tx.Hash()) == nil { // Removed or migrated l.stales.Add(-1) continue } @@ -672,7 +667,7 @@ func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { } } // If we still can't make enough room for the new transaction - if slots > 0 && !force { + if slots > 0 { for _, tx := range drop { heap.Push(&l.urgent, tx) } @@ -687,11 +682,11 @@ func (l *pricedList) Reheap() { defer l.reheapMu.Unlock() start := time.Now() l.stales.Store(0) - l.urgent.list = make([]*types.Transaction, 0, l.all.RemoteCount()) - l.all.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { + l.urgent.list = make([]*types.Transaction, 0, l.all.Count()) + l.all.Range(func(hash common.Hash, tx *types.Transaction) bool { l.urgent.list = append(l.urgent.list, tx) return true - }, false, true) // Only iterate remotes + }) heap.Init(&l.urgent) // balance out the two heaps by moving the worse half of transactions into the diff --git a/core/txpool/legacypool/journal.go b/core/txpool/locals/journal.go similarity index 99% rename from core/txpool/legacypool/journal.go rename to core/txpool/locals/journal.go index 899ed00bc..46fd6de34 100644 --- a/core/txpool/legacypool/journal.go +++ b/core/txpool/locals/journal.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package legacypool +package locals import ( "errors" diff --git a/core/txpool/locals/tx_tracker.go b/core/txpool/locals/tx_tracker.go new file mode 100644 index 000000000..41d5faa7e --- /dev/null +++ b/core/txpool/locals/tx_tracker.go @@ -0,0 +1,212 @@ +// Copyright 2023 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 . + +// Package locals implements tracking for "local" transactions +package locals + +import ( + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" + "golang.org/x/exp/slices" +) + +var ( + recheckInterval = time.Minute + localGauge = metrics.GetOrRegisterGauge("txpool/local", nil) +) + +// TxTracker is a struct used to track priority transactions; it will check from +// time to time if the main pool has forgotten about any of the transaction +// it is tracking, and if so, submit it again. +// This is used to track 'locals'. +// This struct does not care about transaction validity, price-bumps or account limits, +// but optimistically accepts transactions. +type TxTracker struct { + all map[common.Hash]*types.Transaction // All tracked transactions + byAddr map[common.Address]*legacypool.SortedMap // Transactions by address + + journal *journal // Journal of local transaction to back up to disk + rejournal time.Duration // How often to rotate journal + pool *txpool.TxPool // The tx pool to interact with + signer types.Signer + + shutdownCh chan struct{} + mu sync.Mutex + wg sync.WaitGroup +} + +// New creates a new TxTracker +func New(journalPath string, journalTime time.Duration, chainConfig *params.ChainConfig, next *txpool.TxPool) *TxTracker { + pool := &TxTracker{ + all: make(map[common.Hash]*types.Transaction), + byAddr: make(map[common.Address]*legacypool.SortedMap), + signer: types.LatestSigner(chainConfig), + shutdownCh: make(chan struct{}), + pool: next, + } + if journalPath != "" { + pool.journal = newTxJournal(journalPath) + pool.rejournal = journalTime + } + return pool +} + +// Track adds a transaction to the tracked set. +// Note: blob-type transactions are ignored. +func (tracker *TxTracker) Track(tx *types.Transaction) { + tracker.TrackAll([]*types.Transaction{tx}) +} + +// TrackAll adds a list of transactions to the tracked set. +// Note: blob-type transactions are ignored. +func (tracker *TxTracker) TrackAll(txs []*types.Transaction) { + tracker.mu.Lock() + defer tracker.mu.Unlock() + + for _, tx := range txs { + if tx.Type() == types.BlobTxType { + continue + } + // If we're already tracking it, it's a no-op + if _, ok := tracker.all[tx.Hash()]; ok { + continue + } + addr, err := types.Sender(tracker.signer, tx) + if err != nil { // Ignore this tx + continue + } + tracker.all[tx.Hash()] = tx + if tracker.byAddr[addr] == nil { + tracker.byAddr[addr] = legacypool.NewSortedMap() + } + tracker.byAddr[addr].Put(tx) + + if tracker.journal != nil { + _ = tracker.journal.insert(tx) + } + } + localGauge.Update(int64(len(tracker.all))) +} + +// recheck checks and returns any transactions that needs to be resubmitted. +func (tracker *TxTracker) recheck(journalCheck bool) (resubmits []*types.Transaction, rejournal map[common.Address]types.Transactions) { + tracker.mu.Lock() + defer tracker.mu.Unlock() + + var ( + numStales = 0 + numOk = 0 + ) + for sender, txs := range tracker.byAddr { + // Wipe the stales + stales := txs.Forward(tracker.pool.Nonce(sender)) + for _, tx := range stales { + delete(tracker.all, tx.Hash()) + } + numStales += len(stales) + + // Check the non-stale + for _, tx := range txs.Flatten() { + if tracker.pool.Has(tx.Hash()) { + numOk++ + continue + } + resubmits = append(resubmits, tx) + } + } + + if journalCheck { // rejournal + rejournal = make(map[common.Address]types.Transactions) + for _, tx := range tracker.all { + addr, _ := types.Sender(tracker.signer, tx) + rejournal[addr] = append(rejournal[addr], tx) + } + // Sort them + for _, list := range rejournal { + // cmp(a, b) should return a negative number when a < b, + slices.SortFunc(list, func(a, b *types.Transaction) int { + return int(a.Nonce() - b.Nonce()) + }) + } + } + localGauge.Update(int64(len(tracker.all))) + log.Debug("Tx tracker status", "need-resubmit", len(resubmits), "stale", numStales, "ok", numOk) + return resubmits, rejournal +} + +// Start implements node.Lifecycle interface +// Start is called after all services have been constructed and the networking +// layer was also initialized to spawn any goroutines required by the service. +func (tracker *TxTracker) Start() error { + tracker.wg.Add(1) + go tracker.loop() + return nil +} + +// Stop implements node.Lifecycle interface +// Stop terminates all goroutines belonging to the service, blocking until they +// are all terminated. +func (tracker *TxTracker) Stop() error { + close(tracker.shutdownCh) + tracker.wg.Wait() + return nil +} + +func (tracker *TxTracker) loop() { + defer tracker.wg.Done() + + if tracker.journal != nil { + tracker.journal.load(func(transactions []*types.Transaction) []error { + tracker.TrackAll(transactions) + return nil + }) + defer tracker.journal.close() + } + var ( + lastJournal = time.Now() + timer = time.NewTimer(10 * time.Second) // Do initial check after 10 seconds, do rechecks more seldom. + ) + for { + select { + case <-tracker.shutdownCh: + return + case <-timer.C: + checkJournal := tracker.journal != nil && time.Since(lastJournal) > tracker.rejournal + resubmits, rejournal := tracker.recheck(checkJournal) + if len(resubmits) > 0 { + tracker.pool.Add(resubmits, true, false) + } + if checkJournal { + // Lock to prevent journal.rotate <-> journal.insert (via TrackAll) conflicts + tracker.mu.Lock() + lastJournal = time.Now() + if err := tracker.journal.rotate(rejournal); err != nil { + log.Warn("Transaction journal rotation failed", "err", err) + } + tracker.mu.Unlock() + } + timer.Reset(recheckInterval) + } + } +} diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 945d940a4..4e7d3aec8 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -140,7 +140,7 @@ type SubPool interface { // Add enqueues a batch of transactions into the pool if they are valid. Due // to the large transaction churn, add may postpone fully integrating the tx // to a later point to batch multiple ones together. - Add(txs []*types.Transaction, local bool, sync bool) []error + Add(txs []*types.Transaction, sync bool) []error // Pending retrieves all currently processable transactions, grouped by origin // account and sorted by nonce. @@ -173,9 +173,6 @@ type SubPool interface { // pending as well as queued transactions of this address, grouped by nonce. ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) - // Locals retrieves the accounts currently considered local by the pool. - Locals() []common.Address - // Status returns the known status (unknown/pending/queued) of a transaction // identified by their hashes. Status(hash common.Hash) TxStatus diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 985e005d6..664f9e05e 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -358,7 +358,7 @@ func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { // back the errors into the original sort order. errsets := make([][]error, len(p.subpools)) for i := 0; i < len(p.subpools); i++ { - errsets[i] = p.subpools[i].Add(txsets[i], local, sync) + errsets[i] = p.subpools[i].Add(txsets[i], sync) } errs := make([]error, len(txs)) for i, split := range splits { @@ -483,23 +483,6 @@ func (p *TxPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*type return []*types.Transaction{}, []*types.Transaction{} } -// Locals retrieves the accounts currently considered local by the pool. -func (p *TxPool) Locals() []common.Address { - // Retrieve the locals from each subpool and deduplicate them - locals := make(map[common.Address]struct{}) - for _, subpool := range p.subpools { - for _, local := range subpool.Locals() { - locals[local] = struct{}{} - } - } - // Flatten and return the deduplicated local set - flat := make([]common.Address, 0, len(locals)) - for local := range locals { - flat = append(flat, local) - } - return flat -} - // Status returns the known status (unknown/pending/queued) of a transaction // identified by its hash. func (p *TxPool) Status(hash common.Hash) TxStatus { diff --git a/eth/api_backend.go b/eth/api_backend.go index dde80bbd5..946b8eeaa 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -285,6 +285,9 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri } func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { + if locals := b.eth.localTxTracker; locals != nil { + locals.Track(signedTx) + } return b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0] } diff --git a/eth/backend.go b/eth/backend.go index 0085e5ba3..42040c477 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -24,6 +24,7 @@ import ( "math/big" "runtime" "sync" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/antimev" @@ -40,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" + "github.com/ethereum/go-ethereum/core/txpool/locals" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" @@ -73,10 +75,11 @@ type Config = ethconfig.Config // Ethereum implements the Ethereum full node service. type Ethereum struct { // core protocol objects - config *ethconfig.Config - txPool *txpool.TxPool - dbftSrv *dbftproto.Service - blockchain *core.BlockChain + config *ethconfig.Config + txPool *txpool.TxPool + localTxTracker *locals.TxTracker + dbftSrv *dbftproto.Service + blockchain *core.BlockChain handler *handler discmix *enode.FairMix @@ -267,6 +270,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } + + if !config.TxPool.NoLocals { + rejournal := config.TxPool.Rejournal + if rejournal < time.Second { + log.Warn("Sanitizing invalid txpool journal time", "provided", rejournal, "updated", time.Second) + rejournal = time.Second + } + eth.localTxTracker = locals.New(config.TxPool.Journal, rejournal, eth.blockchain.Config(), eth.txPool) + stack.RegisterLifecycle(eth.localTxTracker) + } // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit if eth.handler, err = newHandler(&handlerConfig{ @@ -288,6 +301,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, fmt.Errorf("custom miner Extra is not supported by dBFT") } eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData, chainConfig.DBFT != nil)) + eth.miner.SetPrioAddresses(config.TxPool.Locals) eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} if eth.APIBackend.allowUnprotectedTxs { diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index 7e9fd7b32..1c65bbe30 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -18,6 +18,7 @@ package catalyst import ( "context" + "fmt" "math/big" "testing" "time" @@ -144,9 +145,14 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { // Tests that zero-period dev mode can handle a lot of simultaneous // transactions/withdrawals func TestOnDemandSpam(t *testing.T) { + // This test is flaky, due to various causes, and the root cause is synchronicity. + // We have optimistic timeouts here and there in the simulated becaon and the worker. + // This test typically fails on 32-bit windows appveyor. + t.Skip("flaky test") var ( withdrawals []types.Withdrawal - txs = make(map[common.Hash]*types.Transaction) + txCount = 20000 + wxCount = 20 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddr = crypto.PubkeyToAddress(testKey.PublicKey) gasLimit uint64 = 10_000_000 @@ -161,7 +167,7 @@ func TestOnDemandSpam(t *testing.T) { defer sub.Unsubscribe() // generate some withdrawals - for i := 0; i < 20; i++ { + for i := 0; i < wxCount; i++ { withdrawals = append(withdrawals, types.Withdrawal{Index: uint64(i)}) if err := mock.withdrawals.add(&withdrawals[i]); err != nil { t.Fatal("addWithdrawal failed", err) @@ -169,37 +175,37 @@ func TestOnDemandSpam(t *testing.T) { } // generate a bunch of transactions - for i := 0; i < 20000; i++ { - tx, err := types.SignTx(types.NewTransaction(uint64(i), common.Address{byte(i), byte(1)}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), signer, testKey) - if err != nil { - t.Fatal("error signing transaction", err) - } - txs[tx.Hash()] = tx - if err := eth.APIBackend.SendTx(context.Background(), tx); err != nil { - t.Fatal("error adding txs to pool", err) + go func() { + for i := 0; i < txCount; i++ { + tx, err := types.SignTx(types.NewTransaction(uint64(i), common.Address{byte(i), byte(1)}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), signer, testKey) + if err != nil { + panic(fmt.Sprintf("error signing transaction: %v", err)) + } + if err := eth.TxPool().Add([]*types.Transaction{tx}, true, false)[0]; err != nil { + panic(fmt.Sprintf("error adding txs to pool: %v", err)) + } } - } - + }() var ( - includedTxs = make(map[common.Hash]struct{}) - includedWxs []uint64 + includedTxs int + includedWxs int + abort = time.NewTimer(10 * time.Second) ) + defer abort.Stop() for { select { case ev := <-chainHeadCh: block := eth.BlockChain().GetBlock(ev.Header.Hash(), ev.Header.Number.Uint64()) - for _, itx := range block.Transactions() { - includedTxs[itx.Hash()] = struct{}{} - } - for _, iwx := range block.Withdrawals() { - includedWxs = append(includedWxs, iwx.Index) - } + includedTxs += len(block.Transactions()) + includedWxs += len(block.Withdrawals()) // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10 - if len(includedTxs) == len(txs) && len(includedWxs) == len(withdrawals) { + if includedTxs == txCount && includedWxs == wxCount { return } - case <-time.After(10 * time.Second): - t.Fatalf("timed out without including all withdrawals/txs: have txs %d, want %d, have wxs %d, want %d", len(includedTxs), len(txs), len(includedWxs), len(withdrawals)) + abort.Reset(10 * time.Second) + case <-abort.C: + t.Fatalf("timed out without including all withdrawals/txs: have txs %d, want %d, have wxs %d, want %d", + includedTxs, txCount, includedWxs, wxCount) } } } diff --git a/miner/miner.go b/miner/miner.go index 586990b7d..3229d8eb0 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -213,6 +213,11 @@ func (miner *Miner) SetEtherbase(addr common.Address) { miner.worker.setEtherbase(addr) } +// SetPrioAddresses sets a list of addresses to prioritize for transaction inclusion. +func (miner *Miner) SetPrioAddresses(prio []common.Address) { + miner.worker.setPrioAddresses(prio) +} + // SetGasCeil sets the gaslimit to strive for when mining blocks post 1559. // For pre-1559 blocks, it sets the ceiling. func (miner *Miner) SetGasCeil(ceil uint64) { diff --git a/miner/worker.go b/miner/worker.go index 92c730ec5..4d6a935eb 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -218,7 +218,8 @@ type worker struct { mu sync.RWMutex // The lock used to protect the coinbase and extra fields coinbase common.Address extra []byte - tip *uint256.Int // Minimum tip needed for non-local transaction to include them + tip *uint256.Int // Minimum tip needed for non-local transaction to include them + prio []common.Address // A list of senders to prioritize pendingMu sync.RWMutex pendingTasks map[common.Hash]*task @@ -311,6 +312,13 @@ func (w *worker) etherbase() common.Address { return w.coinbase } +// setPrioAddresses sets a list of addresses to prioritize for transaction inclusion. +func (w *worker) setPrioAddresses(prio []common.Address) { + w.mu.Lock() + defer w.mu.Unlock() + w.prio = prio +} + func (w *worker) setGasCeil(ceil uint64) { w.mu.Lock() defer w.mu.Unlock() @@ -1036,6 +1044,7 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error { w.mu.RLock() tip := w.tip + prio := w.prio w.mu.RUnlock() // Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees @@ -1055,31 +1064,31 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err pendingBlobTxs := w.eth.TxPool().Pending(filter) // Split the pending transactions into locals and remotes. - localPlainTxs, remotePlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs - localBlobTxs, remoteBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs + prioPlainTxs, normalPlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs + prioBlobTxs, normalBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs - for _, account := range w.eth.TxPool().Locals() { - if txs := remotePlainTxs[account]; len(txs) > 0 { - delete(remotePlainTxs, account) - localPlainTxs[account] = txs + for _, account := range prio { + if txs := normalPlainTxs[account]; len(txs) > 0 { + delete(normalPlainTxs, account) + prioPlainTxs[account] = txs } - if txs := remoteBlobTxs[account]; len(txs) > 0 { - delete(remoteBlobTxs, account) - localBlobTxs[account] = txs + if txs := normalBlobTxs[account]; len(txs) > 0 { + delete(normalBlobTxs, account) + prioBlobTxs[account] = txs } } // Fill the block with all available pending transactions. - if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 { - plainTxs := newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee) - blobTxs := newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee) + if len(prioPlainTxs) > 0 || len(prioBlobTxs) > 0 { + plainTxs := newTransactionsByPriceAndNonce(env.signer, prioPlainTxs, env.header.BaseFee) + blobTxs := newTransactionsByPriceAndNonce(env.signer, prioBlobTxs, env.header.BaseFee) if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { return err } } - if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 { - plainTxs := newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee) - blobTxs := newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee) + if len(normalPlainTxs) > 0 || len(normalBlobTxs) > 0 { + plainTxs := newTransactionsByPriceAndNonce(env.signer, normalPlainTxs, env.header.BaseFee) + blobTxs := newTransactionsByPriceAndNonce(env.signer, normalBlobTxs, env.header.BaseFee) if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil { return err From 0d4c0261fac1030603c69b260dad7560aecef0fe Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 4 Feb 2025 18:10:40 +0100 Subject: [PATCH 122/354] core/txpool/blobpool: fix incorrect arguments in test (#31127) Fixes the linter on master which was broken by https://github.com/ethereum/go-ethereum/pull/30559 --- core/txpool/blobpool/blobpool_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 0187e8d9a..88d68eb30 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -1108,7 +1108,7 @@ func TestChangingSlotterSize(t *testing.T) { // Try to add the big blob tx. In the initial iteration it should overflow // the pool. On the subsequent iteration it should be accepted. - errs := pool.Add([]*types.Transaction{tx3}, false, true) + errs := pool.Add([]*types.Transaction{tx3}, true) if _, ok := pool.index[addr3]; ok && maxBlobs == 6 { t.Errorf("expected insert of oversized blob tx to fail: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0]) } else if !ok && maxBlobs == 10 { From 942ea19b0ea0c2ec8db8be40aa1709d10c79cb74 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 4 Feb 2025 13:43:18 -0700 Subject: [PATCH 123/354] consensus/misc/eip4844: use head's target blobs, not parent (#31101) A clarification was made to EIP-7691 stating that at the fork boundary it is required to use the target blob count associated with the head block, rather than the parent as implemented here. See for more: https://github.com/ethereum/EIPs/pull/9249 --- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/misc/eip4844/eip4844.go | 6 +++--- consensus/misc/eip4844/eip4844_test.go | 5 ++++- core/chain_makers.go | 2 +- core/state_processor_test.go | 2 +- eth/gasprice/feehistory.go | 2 +- eth/tracers/internal/tracetest/util.go | 5 +++-- internal/ethapi/simulate.go | 2 +- miner/worker.go | 2 +- 9 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a7b68c074..27ba21279 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -196,11 +196,11 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ExcessBlobGas: pre.Env.ParentExcessBlobGas, BlobGasUsed: pre.Env.ParentBlobGasUsed, } - excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent) header := &types.Header{ Time: pre.Env.Timestamp, ExcessBlobGas: &excessBlobGas, } + excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent, header) vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header) } } diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 1d76b21b3..148ea6027 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -50,7 +50,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } // Verify the excessBlobGas is correct based on the parent header - expectedExcessBlobGas := CalcExcessBlobGas(config, parent) + expectedExcessBlobGas := CalcExcessBlobGas(config, parent, header) if *header.ExcessBlobGas != expectedExcessBlobGas { return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) } @@ -59,9 +59,9 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade // CalcExcessBlobGas calculates the excess blob gas after applying the set of // blobs on top of the excess blob gas. -func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 { +func CalcExcessBlobGas(config *params.ChainConfig, parent, header *types.Header) uint64 { var ( - targetGas = uint64(targetBlobsPerBlock(config, parent.Time)) * params.BlobTxBlobGasPerBlob + targetGas = uint64(targetBlobsPerBlock(config, header.Time)) * params.BlobTxBlobGasPerBlob parentExcessBlobGas uint64 parentBlobGasUsed uint64 ) diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index 839ea8df2..7d221aa96 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -57,12 +57,15 @@ func TestCalcExcessBlobGas(t *testing.T) { } for i, tt := range tests { blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob + head := &types.Header{ + Time: *config.CancunTime, + } parent := &types.Header{ Time: *config.CancunTime, ExcessBlobGas: &tt.excess, BlobGasUsed: &blobGasUsed, } - result := CalcExcessBlobGas(config, parent) + result := CalcExcessBlobGas(config, parent, head) if result != tt.want { t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 22d145c79..fe82fe558 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -600,7 +600,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi } } if cm.config.IsCancun(header.Number, header.Time) { - excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header()) + excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header(), header) header.ExcessBlobGas = &excessBlobGas header.BlobGasUsed = new(uint64) header.ParentBeaconRoot = new(common.Hash) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 8b0ba3aea..b8c307f99 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -407,7 +407,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) if config.IsCancun(header.Number, header.Time) { - excess := eip4844.CalcExcessBlobGas(config, parent.Header()) + excess := eip4844.CalcExcessBlobGas(config, parent.Header(), header) used := uint64(nBlobs * params.BlobTxBlobGasPerBlob) header.ExcessBlobGas = &excess header.BlobGasUsed = &used diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 6572155ea..ae83830c2 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -102,7 +102,7 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil // Fill in blob base fee and next blob base fee. if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil { bf.results.blobBaseFee = eip4844.CalcBlobFee(config, bf.header) - excess := eip4844.CalcExcessBlobGas(config, bf.header) + excess := eip4844.CalcExcessBlobGas(config, bf.header, bf.header) next := &types.Header{Number: bf.header.Number, Time: bf.header.Time, ExcessBlobGas: &excess} bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(config, next) } else { diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index e29144e04..97896213b 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -54,8 +54,9 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { } if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { - excess := eip4844.CalcExcessBlobGas(genesis.Config, genesis.ToBlock().Header()) - header := &types.Header{ExcessBlobGas: &excess, Number: genesis.Config.LondonBlock, Time: *genesis.Config.CancunTime} + header := &types.Header{Number: genesis.Config.LondonBlock, Time: *genesis.Config.CancunTime} + excess := eip4844.CalcExcessBlobGas(genesis.Config, header, genesis.ToBlock().Header()) + header.ExcessBlobGas = &excess context.BlobBaseFee = eip4844.CalcBlobFee(genesis.Config, header) } return context diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index d364b8048..0262f69c0 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -159,7 +159,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsCancun(header.Number, header.Time) { var excess uint64 if sim.chainConfig.IsCancun(parent.Number, parent.Time) { - excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent) + excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent, header) } header.ExcessBlobGas = &excess } diff --git a/miner/worker.go b/miner/worker.go index 4d6a935eb..c8d3803a5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1012,7 +1012,7 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm if w.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 if w.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent) + excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent, header) } header.BlobGasUsed = new(uint64) header.ExcessBlobGas = &excessBlobGas From 0151c0e933720d9d9258269c1b6cf45b5b92778d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 5 Feb 2025 10:35:03 +0100 Subject: [PATCH 124/354] consensus/misc/eip4844: more changes for blob gas calculation (#31128) This PR changes the signature of `CalcExcessBlobGas` to take in just the header timestamp instead of the whole object. It also adds a sanity check for the parent->child block order to `VerifyEIP4844Header`. --- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/misc/eip4844/eip4844.go | 9 ++++++--- consensus/misc/eip4844/eip4844_test.go | 8 ++------ core/chain_makers.go | 7 ++++--- core/state_processor_test.go | 2 +- eth/gasprice/feehistory.go | 2 +- eth/tracers/internal/tracetest/util.go | 2 +- internal/ethapi/simulate.go | 2 +- miner/worker.go | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 27ba21279..7e9b11ac5 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -200,7 +200,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, Time: pre.Env.Timestamp, ExcessBlobGas: &excessBlobGas, } - excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent, header) + excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent, header.Time) vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header) } } diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 148ea6027..4a2754b55 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -34,6 +34,9 @@ var ( // if the current block contains no transactions, the excessBlobGas is updated // accordingly. func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error { + if header.Number.Uint64() != parent.Number.Uint64()+1 { + panic("bad header pair") + } // Verify the header is not malformed if header.ExcessBlobGas == nil { return errors.New("header is missing excessBlobGas") @@ -50,7 +53,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob) } // Verify the excessBlobGas is correct based on the parent header - expectedExcessBlobGas := CalcExcessBlobGas(config, parent, header) + expectedExcessBlobGas := CalcExcessBlobGas(config, parent, header.Time) if *header.ExcessBlobGas != expectedExcessBlobGas { return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) } @@ -59,9 +62,8 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade // CalcExcessBlobGas calculates the excess blob gas after applying the set of // blobs on top of the excess blob gas. -func CalcExcessBlobGas(config *params.ChainConfig, parent, header *types.Header) uint64 { +func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 { var ( - targetGas = uint64(targetBlobsPerBlock(config, header.Time)) * params.BlobTxBlobGasPerBlob parentExcessBlobGas uint64 parentBlobGasUsed uint64 ) @@ -70,6 +72,7 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent, header *types.Header) parentBlobGasUsed = *parent.BlobGasUsed } excessBlobGas := parentExcessBlobGas + parentBlobGasUsed + targetGas := uint64(targetBlobsPerBlock(config, headTimestamp)) * params.BlobTxBlobGasPerBlob if excessBlobGas < targetGas { return 0 } diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index 7d221aa96..f4e3cb3d9 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -57,15 +57,11 @@ func TestCalcExcessBlobGas(t *testing.T) { } for i, tt := range tests { blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob - head := &types.Header{ - Time: *config.CancunTime, - } - parent := &types.Header{ - Time: *config.CancunTime, + header := &types.Header{ ExcessBlobGas: &tt.excess, BlobGasUsed: &blobGasUsed, } - result := CalcExcessBlobGas(config, parent, head) + result := CalcExcessBlobGas(config, header, *config.CancunTime) if result != tt.want { t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want) } diff --git a/core/chain_makers.go b/core/chain_makers.go index fe82fe558..e343e9529 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -582,25 +582,26 @@ func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { time := parent.Time() + 10 // block time is fixed at 10 seconds + parentHeader := parent.Header() header := &types.Header{ Root: state.IntermediateRoot(cm.config.IsEIP158(parent.Number())), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), - Difficulty: engine.CalcDifficulty(cm, time, parent.Header()), + Difficulty: engine.CalcDifficulty(cm, time, parentHeader), GasLimit: parent.GasLimit(), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } if cm.config.IsLondon(header.Number) { - header.BaseFee = eip1559.CalcBaseFee(cm.config, parent.Header()) + header.BaseFee = eip1559.CalcBaseFee(cm.config, parentHeader) if !cm.config.IsLondon(parent.Number()) { parentGasLimit := parent.GasLimit() * cm.config.ElasticityMultiplier() header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) } } if cm.config.IsCancun(header.Number, header.Time) { - excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header(), header) + excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parentHeader, time) header.ExcessBlobGas = &excessBlobGas header.BlobGasUsed = new(uint64) header.ParentBeaconRoot = new(common.Hash) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index b8c307f99..d08f5e1c9 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -407,7 +407,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) if config.IsCancun(header.Number, header.Time) { - excess := eip4844.CalcExcessBlobGas(config, parent.Header(), header) + excess := eip4844.CalcExcessBlobGas(config, parent.Header(), header.Time) used := uint64(nBlobs * params.BlobTxBlobGasPerBlob) header.ExcessBlobGas = &excess header.BlobGasUsed = &used diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index ae83830c2..360199d8e 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -102,7 +102,7 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil // Fill in blob base fee and next blob base fee. if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil { bf.results.blobBaseFee = eip4844.CalcBlobFee(config, bf.header) - excess := eip4844.CalcExcessBlobGas(config, bf.header, bf.header) + excess := eip4844.CalcExcessBlobGas(config, bf.header, bf.header.Time) next := &types.Header{Number: bf.header.Number, Time: bf.header.Time, ExcessBlobGas: &excess} bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(config, next) } else { diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 97896213b..524a396d5 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -55,7 +55,7 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil { header := &types.Header{Number: genesis.Config.LondonBlock, Time: *genesis.Config.CancunTime} - excess := eip4844.CalcExcessBlobGas(genesis.Config, header, genesis.ToBlock().Header()) + excess := eip4844.CalcExcessBlobGas(genesis.Config, header, genesis.Timestamp) header.ExcessBlobGas = &excess context.BlobBaseFee = eip4844.CalcBlobFee(genesis.Config, header) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 0262f69c0..c461b1f0a 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -159,7 +159,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsCancun(header.Number, header.Time) { var excess uint64 if sim.chainConfig.IsCancun(parent.Number, parent.Time) { - excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent, header) + excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent, header.Time) } header.ExcessBlobGas = &excess } diff --git a/miner/worker.go b/miner/worker.go index c8d3803a5..879019df4 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1012,7 +1012,7 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm if w.chainConfig.IsCancun(header.Number, header.Time) { var excessBlobGas uint64 if w.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent, header) + excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent, timestamp) } header.BlobGasUsed = new(uint64) header.ExcessBlobGas = &excessBlobGas From 59e72a2ee5541f241b51d3dcc748a03e903830b4 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Wed, 5 Feb 2025 13:58:25 +0100 Subject: [PATCH 125/354] core/tracing: state journal wrapper (#30441) Here we add some more changes for live tracing API v1.1: - Hook `OnSystemCallStartV2` was introduced with `VMContext` as parameter. - Hook `OnBlockHashRead` was introduced. - `GetCodeHash` was added to the state interface - The new `WrapWithJournal` construction helps with tracking EVM reverts in the tracer. --------- Co-authored-by: Felix Lange --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/genesis.go | 4 +- core/state/statedb.go | 2 +- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_hooked.go | 11 +- core/state/statedb_hooked_test.go | 4 +- core/state/statedb_test.go | 6 +- core/state_transition.go | 4 +- core/tracing/CHANGELOG.md | 47 +++ .../gen_balance_change_reason_stringer.go | 5 +- core/tracing/hooks.go | 47 +++ core/tracing/journal.go | 237 +++++++++++++ core/tracing/journal_test.go | 335 ++++++++++++++++++ core/txpool/blobpool/blobpool_test.go | 8 +- core/txpool/legacypool/cachepool_test.go | 4 +- core/txpool/legacypool/legacypool_test.go | 6 +- core/verkle_witness_test.go | 3 +- core/vm/evm.go | 4 +- core/vm/instructions.go | 3 + core/vm/interface.go | 2 +- core/vm/runtime/runtime_test.go | 2 +- eth/tracers/live/noop.go | 3 + internal/ethapi/override/override.go | 2 +- tests/state_test_util.go | 2 +- 24 files changed, 711 insertions(+), 34 deletions(-) create mode 100644 core/tracing/journal.go create mode 100644 core/tracing/journal_test.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 7e9b11ac5..9416c5c84 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -428,7 +428,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB statedb, _ := state.New(types.EmptyRootHash, sdb) for addr, a := range accounts { statedb.SetCode(addr, a.Code) - statedb.SetNonce(addr, a.Nonce) + statedb.SetNonce(addr, a.Nonce, tracing.NonceChangeGenesis) statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceIncreaseGenesisBalance) for k, v := range a.Storage { statedb.SetState(addr, k, v) diff --git a/core/genesis.go b/core/genesis.go index 1f410248a..0ece99714 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -156,7 +156,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) - statedb.SetNonce(addr, account.Nonce) + statedb.SetNonce(addr, account.Nonce, tracing.NonceChangeGenesis) for key, value := range account.Storage { statedb.SetState(addr, key, value) } @@ -182,7 +182,7 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, e statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) - statedb.SetNonce(addr, account.Nonce) + statedb.SetNonce(addr, account.Nonce, tracing.NonceChangeGenesis) for key, value := range account.Storage { statedb.SetState(addr, key, value) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 0310ee697..efafdc1aa 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -432,7 +432,7 @@ func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int, reason tr } } -func (s *StateDB) SetNonce(addr common.Address, nonce uint64) { +func (s *StateDB) SetNonce(addr common.Address, nonce uint64, reason tracing.NonceChangeReason) { stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.SetNonce(nonce) diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index ed99cf687..2923a2c22 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -69,7 +69,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { name: "SetNonce", fn: func(a testAction, s *StateDB) { - s.SetNonce(addr, uint64(a.args[0])) + s.SetNonce(addr, uint64(a.args[0]), tracing.NonceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 25d823cc8..a2fdfe9a2 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -179,10 +179,13 @@ func (s *hookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, rea return prev } -func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64) { - s.inner.SetNonce(address, nonce) - if s.hooks.OnNonceChange != nil { - s.hooks.OnNonceChange(address, nonce-1, nonce) +func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64, reason tracing.NonceChangeReason) { + prev := s.inner.GetNonce(address) + s.inner.SetNonce(address, nonce, reason) + if s.hooks.OnNonceChangeV2 != nil { + s.hooks.OnNonceChangeV2(address, prev, nonce, reason) + } else if s.hooks.OnNonceChange != nil { + s.hooks.OnNonceChange(address, prev, nonce) } } diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index 874a27599..ce42e9640 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -85,7 +85,7 @@ func TestHooks(t *testing.T) { var wants = []string{ "0xaa00000000000000000000000000000000000000.balance: 0->100 (BalanceChangeUnspecified)", "0xaa00000000000000000000000000000000000000.balance: 100->50 (BalanceChangeTransfer)", - "0xaa00000000000000000000000000000000000000.nonce: 1336->1337", + "0xaa00000000000000000000000000000000000000.nonce: 0->1337", "0xaa00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728)", "0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000000 ->0x0000000000000000000000000000000000000000000000000000000000000011", "0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000011 ->0x0000000000000000000000000000000000000000000000000000000000000022", @@ -113,7 +113,7 @@ func TestHooks(t *testing.T) { }) sdb.AddBalance(common.Address{0xaa}, uint256.NewInt(100), tracing.BalanceChangeUnspecified) sdb.SubBalance(common.Address{0xaa}, uint256.NewInt(50), tracing.BalanceChangeTransfer) - sdb.SetNonce(common.Address{0xaa}, 1337) + sdb.SetNonce(common.Address{0xaa}, 1337, tracing.NonceChangeGenesis) sdb.SetCode(common.Address{0xaa}, []byte{0x13, 37}) sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x11")) sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x22")) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 67eb9cbdc..e740c64fa 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -60,7 +60,7 @@ func TestUpdateLeaks(t *testing.T) { for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) state.AddBalance(addr, uint256.NewInt(uint64(11*i)), tracing.BalanceChangeUnspecified) - state.SetNonce(addr, uint64(42*i)) + state.SetNonce(addr, uint64(42*i), tracing.NonceChangeUnspecified) if i%2 == 0 { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) } @@ -95,7 +95,7 @@ func TestIntermediateLeaks(t *testing.T) { modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified) - state.SetNonce(addr, uint64(42*i+tweak)) + state.SetNonce(addr, uint64(42*i+tweak), tracing.NonceChangeUnspecified) if i%2 == 0 { state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) @@ -357,7 +357,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "SetNonce", fn: func(a testAction, s *StateDB) { - s.SetNonce(addr, uint64(a.args[0])) + s.SetNonce(addr, uint64(a.args[0]), tracing.NonceChangeUnspecified) }, args: make([]int64, 1), }, diff --git a/core/state_transition.go b/core/state_transition.go index b0a4cdb80..a75c44bfa 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -527,7 +527,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value) } else { // Increment the nonce for the next transaction. - st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1) + st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall) // Apply EIP-7702 authorizations. if msg.SetCodeAuthorizations != nil { @@ -642,7 +642,7 @@ func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) } // Update nonce and account code. - st.state.SetNonce(authority, auth.Nonce+1) + st.state.SetNonce(authority, auth.Nonce+1, tracing.NonceChangeAuthorization) if auth.Address == (common.Address{}) { // Delegation to zero address means clear. st.state.SetCode(authority, nil) diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index 270e0a30b..a14e123d9 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -4,6 +4,53 @@ All notable changes to the tracing interface will be documented in this file. ## [Unreleased] +The tracing interface has been extended with backwards-compatible changes to support more use-cases and simplify tracer code. The most notable change is a state journaling library which emits reverse events when a call is reverted. + +### Deprecated methods + +- `OnSystemCallStart()`: This hook is deprecated in favor of `OnSystemCallStartV2(vm *VMContext)`. +- `OnNonceChange(addr common.Address, prev, new uint64)`: This hook is deprecated in favor of `OnNonceChangeV2(addr common.Address, prev, new uint64, reason NonceChangeReason)`. + +### New methods + +- `OnBlockHashRead(blockNum uint64, hash common.Hash)`: This hook is called when a block hash is read by EVM. +- `OnSystemCallStartV2(vm *VMContext)`. This allows access to EVM context during system calls. It is a successor to `OnSystemCallStart`. +- `OnNonceChangeV2(addr common.Address, prev, new uint64, reason NonceChangeReason)`: This hook is called when a nonce change occurs. It is a successor to `OnNonceChange`. + +### New types + +- `NonceChangeReason` is a new type used to provide a reason for nonce changes. Notably it includes `NonceChangeRevert` which will be emitted by the state journaling library when a nonce change is due to a revert. + +### Modified types + +- `VMContext.StateDB` has been extended with `GetCodeHash(addr common.Address) common.Hash` method used to retrieve the code hash an account. +- `BalanceChangeReason` has been extended with the `BalanceChangeRevert` reason. More on that below. + +### State journaling + +Tracers receive state changes events from the node. The tracer was so far expected to keep track of modified accounts and slots and revert those changes when a call frame failed. Now a utility tracer wrapper is provided which will emit "reverse change" events when a call frame fails. To use this feature the hooks have to be wrapped prior to registering the tracer. The following example demonstrates how to use the state journaling library: + +```go +func init() { + tracers.LiveDirectory.Register("test", func (cfg json.RawMessage) (*tracing.Hooks, error) { + hooks, err := newTestTracer(cfg) + if err != nil { + return nil, err + } + return tracing.WrapWithJournal(hooks) + }) +} +``` + +The state changes that are covered by the journaling library are: + +- `OnBalanceChange`. Note that `OnBalanceChange` will carry the `BalanceChangeRevert` reason. +- `OnNonceChange`, `OnNonceChangeV2` +- `OnCodeChange` +- `OnStorageChange` + +## [v1.14.9](https://github.com/ethereum/go-ethereum/releases/tag/v1.14.9) + ### Modified types - `GasChangeReason` has been extended with the following reasons which will be enabled only post-Verkle. There shouldn't be any gas changes with those reasons prior to the fork. diff --git a/core/tracing/gen_balance_change_reason_stringer.go b/core/tracing/gen_balance_change_reason_stringer.go index d3a515a12..4f094efb4 100644 --- a/core/tracing/gen_balance_change_reason_stringer.go +++ b/core/tracing/gen_balance_change_reason_stringer.go @@ -23,11 +23,12 @@ func _() { _ = x[BalanceIncreaseSelfdestruct-12] _ = x[BalanceDecreaseSelfdestruct-13] _ = x[BalanceDecreaseSelfdestructBurn-14] + _ = x[BalanceChangeRevert-15] } -const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurn" +const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurnBalanceChangeRevert" -var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400} +var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400, 419} func (i BalanceChangeReason) String() string { if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) { diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index e1978e483..e1afe22f3 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -14,6 +14,14 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +// Package tracing defines hooks for 'live tracing' of block processing and transaction +// execution. Here we define the low-level [Hooks] object that carries hooks which are +// invoked by the go-ethereum core at various points in the state transition. +// +// To create a tracer that can be invoked with Geth, you need to register it using +// [github.com/ethereum/go-ethereum/eth/tracers.LiveDirectory.Register]. +// +// See https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing for a tutorial. package tracing import ( @@ -164,6 +172,9 @@ type ( // NonceChangeHook is called when the nonce of an account changes. NonceChangeHook = func(addr common.Address, prev, new uint64) + // NonceChangeHookV2 is called when the nonce of an account changes. + NonceChangeHookV2 = func(addr common.Address, prev, new uint64, reason NonceChangeReason) + // CodeChangeHook is called when the code of an account changes. CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) @@ -172,6 +183,9 @@ type ( // LogHook is called when a log is emitted. LogHook = func(log *types.Log) + + // BlockHashReadHook is called when EVM reads the blockhash of a block. + BlockHashReadHook = func(blockNumber uint64, hash common.Hash) ) type Hooks struct { @@ -196,9 +210,12 @@ type Hooks struct { // State events OnBalanceChange BalanceChangeHook OnNonceChange NonceChangeHook + OnNonceChangeV2 NonceChangeHookV2 OnCodeChange CodeChangeHook OnStorageChange StorageChangeHook OnLog LogHook + // Block hash read + OnBlockHashRead BlockHashReadHook } // BalanceChangeReason is used to indicate the reason for a balance change, useful @@ -250,6 +267,10 @@ const ( // account within the same tx (captured at end of tx). // Note it doesn't account for a self-destruct which appoints itself as recipient. BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14 + + // BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure. + // It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal). + BalanceChangeRevert BalanceChangeReason = 15 ) // GasChangeReason is used to indicate the reason for a gas change, useful @@ -322,3 +343,29 @@ const ( // it will be "manually" tracked by a direct emit of the gas change event. GasChangeIgnored GasChangeReason = 0xFF ) + +// NonceChangeReason is used to indicate the reason for a nonce change. +type NonceChangeReason byte + +const ( + NonceChangeUnspecified NonceChangeReason = 0 + + // NonceChangeGenesis is the nonce allocated to accounts at genesis. + NonceChangeGenesis NonceChangeReason = 1 + + // NonceChangeEoACall is the nonce change due to an EoA call. + NonceChangeEoACall NonceChangeReason = 2 + + // NonceChangeContractCreator is the nonce change of an account creating a contract. + NonceChangeContractCreator NonceChangeReason = 3 + + // NonceChangeNewContract is the nonce change of a newly created contract. + NonceChangeNewContract NonceChangeReason = 4 + + // NonceChangeTransaction is the nonce change due to a EIP-7702 authorization. + NonceChangeAuthorization NonceChangeReason = 5 + + // NonceChangeRevert is emitted when the nonce is reverted back to a previous value due to call failure. + // It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal). + NonceChangeRevert NonceChangeReason = 6 +) diff --git a/core/tracing/journal.go b/core/tracing/journal.go new file mode 100644 index 000000000..8937d4c5a --- /dev/null +++ b/core/tracing/journal.go @@ -0,0 +1,237 @@ +// Copyright 2025 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 . + +package tracing + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// journal is a state change journal to be wrapped around a tracer. +// It will emit the state change hooks with reverse values when a call reverts. +type journal struct { + hooks *Hooks + entries []entry + revisions []int +} + +type entry interface { + revert(tracer *Hooks) +} + +// WrapWithJournal wraps the given tracer with a journaling layer. +func WrapWithJournal(hooks *Hooks) (*Hooks, error) { + if hooks == nil { + return nil, fmt.Errorf("wrapping nil tracer") + } + // No state change to journal, return the wrapped hooks as is + if hooks.OnBalanceChange == nil && hooks.OnNonceChange == nil && hooks.OnNonceChangeV2 == nil && hooks.OnCodeChange == nil && hooks.OnStorageChange == nil { + return hooks, nil + } + if hooks.OnNonceChange != nil && hooks.OnNonceChangeV2 != nil { + return nil, fmt.Errorf("cannot have both OnNonceChange and OnNonceChangeV2") + } + + // Create a new Hooks instance and copy all hooks + wrapped := *hooks + + // Create journal + j := &journal{hooks: hooks} + // Scope hooks need to be re-implemented. + wrapped.OnTxEnd = j.OnTxEnd + wrapped.OnEnter = j.OnEnter + wrapped.OnExit = j.OnExit + // Wrap state change hooks. + if hooks.OnBalanceChange != nil { + wrapped.OnBalanceChange = j.OnBalanceChange + } + if hooks.OnNonceChange != nil || hooks.OnNonceChangeV2 != nil { + // Regardless of which hook version is used in the tracer, + // the journal will want to capture the nonce change reason. + wrapped.OnNonceChangeV2 = j.OnNonceChangeV2 + // A precaution to ensure EVM doesn't call both hooks. + wrapped.OnNonceChange = nil + } + if hooks.OnCodeChange != nil { + wrapped.OnCodeChange = j.OnCodeChange + } + if hooks.OnStorageChange != nil { + wrapped.OnStorageChange = j.OnStorageChange + } + + return &wrapped, nil +} + +// reset clears the journal, after this operation the journal can be used anew. +// It is semantically similar to calling 'NewJournal', but the underlying slices +// can be reused. +func (j *journal) reset() { + j.entries = j.entries[:0] + j.revisions = j.revisions[:0] +} + +// snapshot records a revision and stores it to the revision stack. +func (j *journal) snapshot() { + rev := len(j.entries) + j.revisions = append(j.revisions, rev) +} + +// revert reverts all state changes up to the last tracked revision. +func (j *journal) revert(hooks *Hooks) { + // Replay the journal entries above the last revision to undo changes, + // then remove the reverted changes from the journal. + rev := j.revisions[len(j.revisions)-1] + for i := len(j.entries) - 1; i >= rev; i-- { + j.entries[i].revert(hooks) + } + j.entries = j.entries[:rev] + j.popRevision() +} + +// popRevision removes an item from the revision stack. This basically forgets about +// the last call to snapshot() and moves to the one prior. +func (j *journal) popRevision() { + j.revisions = j.revisions[:len(j.revisions)-1] +} + +// OnTxEnd resets the journal since each transaction has its own EVM call stack. +func (j *journal) OnTxEnd(receipt *types.Receipt, err error) { + j.reset() + if j.hooks.OnTxEnd != nil { + j.hooks.OnTxEnd(receipt, err) + } +} + +// OnEnter is invoked for each EVM call frame and records a journal revision. +func (j *journal) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + j.snapshot() + if j.hooks.OnEnter != nil { + j.hooks.OnEnter(depth, typ, from, to, input, gas, value) + } +} + +// OnExit is invoked when an EVM call frame ends. +// If the call has reverted, all state changes made by that frame are undone. +// If the call did not revert, we forget about changes in that revision. +func (j *journal) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if reverted { + j.revert(j.hooks) + } else { + j.popRevision() + } + if j.hooks.OnExit != nil { + j.hooks.OnExit(depth, output, gasUsed, err, reverted) + } +} + +func (j *journal) OnBalanceChange(addr common.Address, prev, new *big.Int, reason BalanceChangeReason) { + j.entries = append(j.entries, balanceChange{addr: addr, prev: prev, new: new}) + if j.hooks.OnBalanceChange != nil { + j.hooks.OnBalanceChange(addr, prev, new, reason) + } +} + +func (j *journal) OnNonceChangeV2(addr common.Address, prev, new uint64, reason NonceChangeReason) { + // When a contract is created, the nonce of the creator is incremented. + // This change is not reverted when the creation fails. + if reason != NonceChangeContractCreator { + j.entries = append(j.entries, nonceChange{addr: addr, prev: prev, new: new}) + } + if j.hooks.OnNonceChangeV2 != nil { + j.hooks.OnNonceChangeV2(addr, prev, new, reason) + } else if j.hooks.OnNonceChange != nil { + j.hooks.OnNonceChange(addr, prev, new) + } +} + +func (j *journal) OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) { + j.entries = append(j.entries, codeChange{ + addr: addr, + prevCodeHash: prevCodeHash, + prevCode: prevCode, + newCodeHash: codeHash, + newCode: code, + }) + if j.hooks.OnCodeChange != nil { + j.hooks.OnCodeChange(addr, prevCodeHash, prevCode, codeHash, code) + } +} + +func (j *journal) OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) { + j.entries = append(j.entries, storageChange{addr: addr, slot: slot, prev: prev, new: new}) + if j.hooks.OnStorageChange != nil { + j.hooks.OnStorageChange(addr, slot, prev, new) + } +} + +type ( + balanceChange struct { + addr common.Address + prev *big.Int + new *big.Int + } + + nonceChange struct { + addr common.Address + prev uint64 + new uint64 + } + + codeChange struct { + addr common.Address + prevCodeHash common.Hash + prevCode []byte + newCodeHash common.Hash + newCode []byte + } + + storageChange struct { + addr common.Address + slot common.Hash + prev common.Hash + new common.Hash + } +) + +func (b balanceChange) revert(hooks *Hooks) { + if hooks.OnBalanceChange != nil { + hooks.OnBalanceChange(b.addr, b.new, b.prev, BalanceChangeRevert) + } +} + +func (n nonceChange) revert(hooks *Hooks) { + if hooks.OnNonceChangeV2 != nil { + hooks.OnNonceChangeV2(n.addr, n.new, n.prev, NonceChangeRevert) + } else if hooks.OnNonceChange != nil { + hooks.OnNonceChange(n.addr, n.new, n.prev) + } +} + +func (c codeChange) revert(hooks *Hooks) { + if hooks.OnCodeChange != nil { + hooks.OnCodeChange(c.addr, c.newCodeHash, c.newCode, c.prevCodeHash, c.prevCode) + } +} + +func (s storageChange) revert(hooks *Hooks) { + if hooks.OnStorageChange != nil { + hooks.OnStorageChange(s.addr, s.slot, s.new, s.prev) + } +} diff --git a/core/tracing/journal_test.go b/core/tracing/journal_test.go new file mode 100644 index 000000000..d9616a2ce --- /dev/null +++ b/core/tracing/journal_test.go @@ -0,0 +1,335 @@ +// Copyright 2025 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 . + +package tracing + +import ( + "errors" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +type testTracer struct { + t *testing.T + bal *big.Int + nonce uint64 + code []byte + storage map[common.Hash]common.Hash +} + +func (t *testTracer) OnBalanceChange(addr common.Address, prev *big.Int, new *big.Int, reason BalanceChangeReason) { + t.t.Logf("OnBalanceChange(%v, %v -> %v, %v)", addr, prev, new, reason) + if t.bal != nil && t.bal.Cmp(prev) != 0 { + t.t.Errorf(" !! wrong prev balance (expected %v)", t.bal) + } + t.bal = new +} + +func (t *testTracer) OnNonceChange(addr common.Address, prev uint64, new uint64) { + t.t.Logf("OnNonceChange(%v, %v -> %v)", addr, prev, new) + t.nonce = new +} + +func (t *testTracer) OnNonceChangeV2(addr common.Address, prev uint64, new uint64, reason NonceChangeReason) { + t.t.Logf("OnNonceChangeV2(%v, %v -> %v, %v)", addr, prev, new, reason) + t.nonce = new +} + +func (t *testTracer) OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) { + t.t.Logf("OnCodeChange(%v, %v -> %v)", addr, prevCodeHash, codeHash) + t.code = code +} + +func (t *testTracer) OnStorageChange(addr common.Address, slot common.Hash, prev common.Hash, new common.Hash) { + t.t.Logf("OnStorageCodeChange(%v, %v, %v -> %v)", addr, slot, prev, new) + if t.storage == nil { + t.storage = make(map[common.Hash]common.Hash) + } + if new == (common.Hash{}) { + delete(t.storage, slot) + } else { + t.storage[slot] = new + } +} + +func TestJournalIntegration(t *testing.T) { + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnBalanceChange: tr.OnBalanceChange, OnNonceChange: tr.OnNonceChange, OnCodeChange: tr.OnCodeChange, OnStorageChange: tr.OnStorageChange}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + wr.OnEnter(0, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, nil, big.NewInt(100), BalanceChangeUnspecified) + wr.OnCodeChange(addr, common.Hash{}, nil, common.Hash{}, []byte{1, 2, 3}) + wr.OnStorageChange(addr, common.Hash{1}, common.Hash{}, common.Hash{2}) + { + wr.OnEnter(1, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnNonceChangeV2(addr, 0, 1, NonceChangeUnspecified) + wr.OnBalanceChange(addr, big.NewInt(100), big.NewInt(200), BalanceChangeUnspecified) + wr.OnBalanceChange(addr, big.NewInt(200), big.NewInt(250), BalanceChangeUnspecified) + wr.OnStorageChange(addr, common.Hash{1}, common.Hash{2}, common.Hash{3}) + wr.OnStorageChange(addr, common.Hash{2}, common.Hash{}, common.Hash{4}) + wr.OnExit(1, nil, 100, errors.New("revert"), true) + } + wr.OnExit(0, nil, 150, nil, false) + } + + if tr.bal.Cmp(big.NewInt(100)) != 0 { + t.Fatalf("unexpected balance: %v", tr.bal) + } + if tr.nonce != 0 { + t.Fatalf("unexpected nonce: %v", tr.nonce) + } + if len(tr.code) != 3 { + t.Fatalf("unexpected code: %v", tr.code) + } + if len(tr.storage) != 1 { + t.Fatalf("unexpected storage len. want %d, have %d", 1, len(tr.storage)) + } + if tr.storage[common.Hash{1}] != (common.Hash{2}) { + t.Fatalf("unexpected storage. want %v, have %v", common.Hash{2}, tr.storage[common.Hash{1}]) + } +} + +func TestJournalTopRevert(t *testing.T) { + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnBalanceChange: tr.OnBalanceChange, OnNonceChange: tr.OnNonceChange}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + wr.OnEnter(0, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(0), big.NewInt(100), BalanceChangeUnspecified) + { + wr.OnEnter(1, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnNonceChangeV2(addr, 0, 1, NonceChangeUnspecified) + wr.OnBalanceChange(addr, big.NewInt(100), big.NewInt(200), BalanceChangeUnspecified) + wr.OnBalanceChange(addr, big.NewInt(200), big.NewInt(250), BalanceChangeUnspecified) + wr.OnExit(1, nil, 100, errors.New("revert"), true) + } + wr.OnExit(0, nil, 150, errors.New("revert"), true) + } + + if tr.bal.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("unexpected balance: %v", tr.bal) + } + if tr.nonce != 0 { + t.Fatalf("unexpected nonce: %v", tr.nonce) + } +} + +// This test checks that changes in nested calls are reverted properly. +func TestJournalNestedCalls(t *testing.T) { + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnBalanceChange: tr.OnBalanceChange, OnNonceChange: tr.OnNonceChange}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + wr.OnEnter(0, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(0), big.NewInt(100), BalanceChangeUnspecified) + { + wr.OnEnter(1, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(100), big.NewInt(200), BalanceChangeUnspecified) + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnExit(2, nil, 100, nil, false) + } + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(200), big.NewInt(300), BalanceChangeUnspecified) + wr.OnExit(2, nil, 100, nil, false) + } + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnExit(2, nil, 100, nil, false) + } + wr.OnBalanceChange(addr, big.NewInt(300), big.NewInt(400), BalanceChangeUnspecified) + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(400), big.NewInt(500), BalanceChangeUnspecified) + wr.OnExit(2, nil, 100, errors.New("revert"), true) + } + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnExit(2, nil, 100, errors.New("revert"), true) + } + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnBalanceChange(addr, big.NewInt(400), big.NewInt(600), BalanceChangeUnspecified) + wr.OnExit(2, nil, 100, nil, false) + } + wr.OnExit(1, nil, 100, errors.New("revert"), true) + } + wr.OnExit(0, nil, 150, nil, false) + } + + if tr.bal.Uint64() != 100 { + t.Fatalf("unexpected balance: %v", tr.bal) + } +} + +func TestNonceIncOnCreate(t *testing.T) { + const opCREATE = 0xf0 + + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnNonceChange: tr.OnNonceChange}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + wr.OnEnter(0, opCREATE, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnNonceChangeV2(addr, 0, 1, NonceChangeContractCreator) + wr.OnExit(0, nil, 100, errors.New("revert"), true) + } + + if tr.nonce != 1 { + t.Fatalf("unexpected nonce: %v", tr.nonce) + } +} + +func TestOnNonceChangeV2(t *testing.T) { + tr := &testTracer{t: t} + wr, err := WrapWithJournal(&Hooks{OnNonceChangeV2: tr.OnNonceChangeV2}) + if err != nil { + t.Fatalf("failed to wrap test tracer: %v", err) + } + + addr := common.HexToAddress("0x1234") + { + wr.OnEnter(2, 0, addr, addr, nil, 1000, big.NewInt(0)) + wr.OnNonceChangeV2(addr, 0, 1, NonceChangeEoACall) + wr.OnExit(2, nil, 100, nil, true) + } + + if tr.nonce != 0 { + t.Fatalf("unexpected nonce: %v", tr.nonce) + } +} + +func TestAllHooksCalled(t *testing.T) { + tracer := newTracerAllHooks() + hooks := tracer.hooks() + + wrapped, err := WrapWithJournal(hooks) + if err != nil { + t.Fatalf("failed to wrap hooks with journal: %v", err) + } + + // Get the underlying value of the wrapped hooks + wrappedValue := reflect.ValueOf(wrapped).Elem() + wrappedType := wrappedValue.Type() + + // Iterate over all fields of the wrapped hooks + for i := 0; i < wrappedType.NumField(); i++ { + field := wrappedType.Field(i) + + // Skip fields that are not function types + if field.Type.Kind() != reflect.Func { + continue + } + // Skip non-hooks, i.e. Copy + if field.Name == "copy" { + continue + } + // Skip if field is not set + if wrappedValue.Field(i).IsNil() { + continue + } + + // Get the method + method := wrappedValue.Field(i) + + // Call the method with zero values + params := make([]reflect.Value, method.Type().NumIn()) + for j := 0; j < method.Type().NumIn(); j++ { + params[j] = reflect.Zero(method.Type().In(j)) + } + method.Call(params) + } + + // Check if all hooks were called + if tracer.numCalled() != tracer.hooksCount() { + t.Errorf("Not all hooks were called. Expected %d, got %d", tracer.hooksCount(), tracer.numCalled()) + } + + for hookName, called := range tracer.hooksCalled { + if !called { + t.Errorf("Hook %s was not called", hookName) + } + } +} + +type tracerAllHooks struct { + hooksCalled map[string]bool +} + +func newTracerAllHooks() *tracerAllHooks { + t := &tracerAllHooks{hooksCalled: make(map[string]bool)} + // Initialize all hooks to false. We will use this to + // get total count of hooks. + hooksType := reflect.TypeOf((*Hooks)(nil)).Elem() + for i := 0; i < hooksType.NumField(); i++ { + t.hooksCalled[hooksType.Field(i).Name] = false + } + delete(t.hooksCalled, "OnNonceChange") + return t +} + +func (t *tracerAllHooks) hooksCount() int { + return len(t.hooksCalled) +} + +func (t *tracerAllHooks) numCalled() int { + count := 0 + for _, called := range t.hooksCalled { + if called { + count++ + } + } + return count +} + +func (t *tracerAllHooks) hooks() *Hooks { + h := &Hooks{} + // Create a function for each hook that sets the + // corresponding hooksCalled field to true. + hooksValue := reflect.ValueOf(h).Elem() + for i := 0; i < hooksValue.NumField(); i++ { + field := hooksValue.Type().Field(i) + if field.Name == "OnNonceChange" { + continue + } + hookMethod := reflect.MakeFunc(field.Type, func(args []reflect.Value) []reflect.Value { + t.hooksCalled[field.Name] = true + return nil + }) + hooksValue.Field(i).Set(hookMethod) + } + return h +} diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 88d68eb30..f7c9e4844 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -680,9 +680,9 @@ func TestOpenDrops(t *testing.T) { statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) - statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) + statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3, tracing.NonceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) - statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) + statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2, tracing.NonceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) @@ -1526,7 +1526,7 @@ func TestAdd(t *testing.T) { // Seed the state database with this account statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified) - statedb.SetNonce(addrs[acc], seed.nonce) + statedb.SetNonce(addrs[acc], seed.nonce, tracing.NonceChangeUnspecified) // Sign the seed transactions and store them in the data store for _, tx := range seed.txs { @@ -1581,7 +1581,7 @@ func TestAdd(t *testing.T) { // Apply the nonce updates to the state db for _, tx := range txs { sender, _ := types.Sender(types.LatestSigner(params.MainnetChainConfig), tx) - chain.statedb.SetNonce(sender, tx.Nonce()+1) + chain.statedb.SetNonce(sender, tx.Nonce()+1, tracing.NonceChangeUnspecified) } pool.Reset(chain.CurrentBlock(), header) verifyPoolInternals(t, pool) diff --git a/core/txpool/legacypool/cachepool_test.go b/core/txpool/legacypool/cachepool_test.go index 7d8301fe4..51ed9ab6a 100644 --- a/core/txpool/legacypool/cachepool_test.go +++ b/core/txpool/legacypool/cachepool_test.go @@ -133,7 +133,7 @@ func TestCachePool(t *testing.T) { func testCachePoolSetNonce(pool *CachePool, addr common.Address, nonce uint64) { pool.mu.Lock() - pool.currentState.SetNonce(addr, nonce) + pool.currentState.SetNonce(addr, nonce, tracing.NonceChangeUnspecified) pool.mu.Unlock() } @@ -330,7 +330,7 @@ func TestCacheTimeLimiting(t *testing.T) { } // remove current transactions and increase nonce to prepare for a reset and cleanup - statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) + statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2, tracing.NonceChangeUnspecified) <-pool.requestReset(nil, nil) // make sure cached is cleared diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 55699e93e..fdbcad3d4 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -251,7 +251,7 @@ func (c *testChain) State() (*state.StateDB, error) { if *c.trigger { c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) // simulate that the new head block included tx0 and tx1 - c.statedb.SetNonce(c.address, 2) + c.statedb.SetNonce(c.address, 2, tracing.NonceChangeUnspecified) c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified) *c.trigger = false } @@ -312,7 +312,7 @@ func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { func testSetNonce(pool *LegacyPool, addr common.Address, nonce uint64) { pool.mu.Lock() - pool.currentState.SetNonce(addr, nonce) + pool.currentState.SetNonce(addr, nonce, tracing.NonceChangeUnspecified) pool.mu.Unlock() } @@ -1011,7 +1011,7 @@ func TestQueueTimeLimiting(t *testing.T) { } // remove current transactions and increase nonce to prepare for a reset and cleanup - statedb.SetNonce(crypto.PubkeyToAddress(remote.PublicKey), 2) + statedb.SetNonce(crypto.PubkeyToAddress(remote.PublicKey), 2, tracing.NonceChangeUnspecified) <-pool.requestReset(nil, nil) // make sure queue, pending are cleared diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index c41d4a9f7..72a0ee7e2 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -226,7 +227,7 @@ func TestProcessParentBlockHash(t *testing.T) { // block 2 parent hash is 0x0200.... // etc checkBlockHashes := func(statedb *state.StateDB, isVerkle bool) { - statedb.SetNonce(params.HistoryStorageAddress, 1) + statedb.SetNonce(params.HistoryStorageAddress, 1, tracing.NonceChangeUnspecified) statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) // Process n blocks, from 1 .. num var num = 2 diff --git a/core/vm/evm.go b/core/vm/evm.go index 3f9ae621a..442441e9a 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -439,7 +439,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if nonce+1 < nonce { return nil, common.Address{}, gas, ErrNonceUintOverflow } - evm.StateDB.SetNonce(caller.Address(), nonce+1) + evm.StateDB.SetNonce(caller.Address(), nonce+1, tracing.NonceChangeContractCreator) // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { @@ -487,7 +487,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, evm.StateDB.CreateContract(address) if evm.chainRules.IsEIP158 { - evm.StateDB.SetNonce(address, 1) + evm.StateDB.SetNonce(address, 1, tracing.NonceChangeNewContract) } // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 23822e0e8..2b7b82c2a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -448,6 +448,9 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if witness := interpreter.evm.StateDB.Witness(); witness != nil { witness.AddBlockHash(num64) } + if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { + tracer.OnBlockHashRead(num64, res) + } num.SetBytes(res[:]) } else { num.Clear() diff --git a/core/vm/interface.go b/core/vm/interface.go index 3488526fc..0d7862a66 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -39,7 +39,7 @@ type StateDB interface { GetBalance(common.Address) *uint256.Int GetNonce(common.Address) uint64 - SetNonce(common.Address, uint64) + SetNonce(common.Address, uint64, tracing.NonceChangeReason) GetCodeHash(common.Address) common.Hash GetCode(common.Address) []byte diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 44f5bc827..bde230b6d 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -414,7 +414,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode eoa := common.HexToAddress("E0") { cfg.State.CreateAccount(eoa) - cfg.State.SetNonce(eoa, 100) + cfg.State.SetNonce(eoa, 100, tracing.NonceChangeUnspecified) } reverting := common.HexToAddress("EE") { diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 46c5700d2..f3def8560 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -57,6 +57,7 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { OnCodeChange: t.OnCodeChange, OnStorageChange: t.OnStorageChange, OnLog: t.OnLog, + OnBlockHashRead: t.OnBlockHashRead, }, nil } @@ -108,5 +109,7 @@ func (t *noop) OnLog(l *types.Log) { } +func (t *noop) OnBlockHashRead(number uint64, hash common.Hash) {} + func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { } diff --git a/internal/ethapi/override/override.go b/internal/ethapi/override/override.go index 70b621027..f6a8a94ff 100644 --- a/internal/ethapi/override/override.go +++ b/internal/ethapi/override/override.go @@ -86,7 +86,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi } // Override account nonce. if account.Nonce != nil { - statedb.SetNonce(addr, uint64(*account.Nonce)) + statedb.SetNonce(addr, uint64(*account.Nonce), tracing.NonceChangeUnspecified) } // Override account(contract) code. if account.Code != nil { diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 24caf41ed..a22e470ad 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -512,7 +512,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo statedb, _ := state.New(types.EmptyRootHash, sdb) for addr, a := range accounts { statedb.SetCode(addr, a.Code) - statedb.SetNonce(addr, a.Nonce) + statedb.SetNonce(addr, a.Nonce, tracing.NonceChangeUnspecified) statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceChangeUnspecified) for k, v := range a.Storage { statedb.SetState(addr, k, v) From b45cc5086b5187ff9a700ea8fdf5c806360f3441 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 5 Feb 2025 23:01:17 +0100 Subject: [PATCH 126/354] all: update license comments and AUTHORS (#31133) --- .mailmap | 89 +++++- AUTHORS | 300 +++++++++++++++++- beacon/light/sync/head_sync.go | 2 +- beacon/params/networks.go | 2 +- cmd/abigen/namefilter.go | 16 + cmd/abigen/namefilter_test.go | 16 + cmd/blsync/main.go | 16 +- cmd/evm/eofparse.go | 2 +- cmd/evm/eofparse_test.go | 16 + cmd/geth/attach_test.go | 14 +- cmd/geth/logging_test.go | 4 +- cmd/geth/logtestcmd_active.go | 4 +- cmd/geth/logtestcmd_inactive.go | 4 +- core/rawdb/accessors_trie.go | 4 +- core/state/statedb_fuzz_test.go | 2 +- core/txindexer.go | 2 +- core/txindexer_test.go | 2 +- core/txpool/blobpool/lookup.go | 2 +- core/txpool/legacypool/legacypool2_test.go | 1 + core/txpool/txpool.go | 2 +- core/types/tx_blob_test.go | 16 + core/vm/eof_control_flow.go | 14 +- core/vm/eof_test.go | 2 +- core/vm/jump_table_test.go | 2 +- core/vm/memory_test.go | 16 + core/vm/program/program.go | 6 +- core/vm/program/program_test.go | 6 +- eth/tracers/dir.go | 2 +- .../internal/tracetest/flat_calltrace_test.go | 16 + eth/tracers/internal/tracetest/makeTest.js | 16 + .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/internal/tracetest/supply_test.go | 2 +- eth/tracers/internal/tracetest/util.go | 16 + eth/tracers/internal/util.go | 2 +- eth/tracers/internal/util_test.go | 3 +- eth/tracers/native/call_flat.go | 2 +- eth/tracers/tracker_test.go | 2 +- ethclient/simulated/backend_test.go | 2 +- ethclient/simulated/rollback_test.go | 16 + ethdb/pebble/pebble_test.go | 2 +- graphql/internal/graphiql/build.go | 16 + internal/era/accumulator.go | 16 +- internal/era/builder.go | 16 +- internal/era/e2store/e2store.go | 16 +- internal/era/e2store/e2store_test.go | 16 +- internal/era/era.go | 16 +- internal/era/era_test.go | 16 +- internal/era/iterator.go | 16 +- miner/payload_building.go | 2 +- miner/payload_building_test.go | 2 +- miner/pending.go | 2 +- p2p/config.go | 1 + p2p/pipes/pipe.go | 2 +- rpc/client_opt_test.go | 16 + tests/fuzzers/difficulty/difficulty_test.go | 2 +- tests/fuzzers/rangeproof/rangeproof_test.go | 2 +- tests/fuzzers/txfetcher/txfetcher_test.go | 2 +- trie/trie_id.go | 2 +- trie/trienode/node.go | 2 +- trie/utils/verkle.go | 2 +- trie/utils/verkle_test.go | 4 +- trie/verkle.go | 2 +- trie/verkle_test.go | 2 +- triedb/pathdb/errors.go | 2 +- triedb/pathdb/execute.go | 2 +- triedb/pathdb/history.go | 4 +- triedb/pathdb/history_inspect.go | 2 +- triedb/pathdb/history_test.go | 4 +- triedb/pathdb/layertree.go | 4 +- triedb/pathdb/metrics.go | 4 +- triedb/pathdb/nodes.go | 2 +- triedb/pathdb/reader.go | 2 +- triedb/pathdb/states.go | 2 +- triedb/pathdb/states_test.go | 2 +- triedb/states.go | 4 +- version/version.go | 2 +- 76 files changed, 697 insertions(+), 157 deletions(-) diff --git a/.mailmap b/.mailmap index 312e51d85..92a9e0774 100644 --- a/.mailmap +++ b/.mailmap @@ -5,6 +5,9 @@ Aaron Kumavis Abel Nieto Abel Nieto +Adrian Sutton +Adrian Sutton + Afri Schoedon <58883403+q9f@users.noreply.github.com> Afri Schoedon <5chdn@users.noreply.github.com> <58883403+q9f@users.noreply.github.com> @@ -22,6 +25,9 @@ Alexey Akhunov Alon Muroch +Andrei Silviu Dragnea +Andrei Silviu Dragnea + Andrey Petrov Andrey Petrov @@ -51,11 +57,17 @@ Chris Ziogas Christoph Jentzsch +Daniel Liu +Daniel Liu <139250065@qq.com> + Diederik Loerakker Dimitry Khokhlov +Ha ĐANG + Domino Valdano +Domino Valdano Edgar Aroutiounian @@ -82,6 +94,9 @@ Gavin Wood Gregg Dourgarian +guangwu +guangwu + Guillaume Ballet Guillaume Ballet <3272758+gballet@users.noreply.github.com> @@ -95,13 +110,21 @@ Heiko Hees Henning Diedrich Henning Diedrich Drake Burroughs +henridf +henridf + Hwanjo Heo <34005989+hwanjo@users.noreply.github.com> +Ikko Eltociear Ashimine + Iskander (Alex) Sharipov Iskander (Alex) Sharipov Jae Kwon +James Prestwich +James Prestwich <10149425+prestwich@users.noreply.github.com> + Janoš Guljaš Janoš Guljaš Janos Guljas @@ -120,23 +143,38 @@ Jeffrey Wilcke Jens Agerberg +Jeremy Schlatter +Jeremy Schlatter + +John Chase <68833933+joohhnnn@users.noreply.github.com> + Joseph Chow Joseph Chow ethers - Joseph Goulden Justin Drake +Karl Bartel +Karl Bartel + Kenso Trabing Kenso Trabing +Liyi Guo <102356659+colinlyguo@users.noreply.github.com> + +lmittmann <3458786+lmittmann@users.noreply.github.com> +lmittmann <3458786+lmittmann@users.noreply.github.com> + Liang Ma Liang Ma Louis Holbrook Louis Holbrook +makcandrov +makcandrov <108467407+makcandrov@users.noreply.github.com> + Maran Hidskes Marian Oancea @@ -144,17 +182,33 @@ Marian Oancea Martin Becze Martin Becze +Martin Holst Swende + Martin Lundfall -Matt Garnett <14004106+lightclient@users.noreply.github.com> +Marius van der Wijden +Marius van der Wijden <115323661+vdwijden@users.noreply.github.com> + +Matt Garnett +Matt Garnett <14004106+lightclient@users.noreply.github.com> Matthew Halpern Matthew Halpern +meowsbits +meowsbits <45600330+meowsbits@users.noreply.github.com> + Michael Riabzev +Michael de Hoog +Michael de Hoog + Nchinda Nchinda +Nebojsa Urosevic + +nedifi <103940716+nedifi@users.noreply.github.com> + Nick Dodson Nick Johnson @@ -169,6 +223,9 @@ Olivier Hervieu Pascal Dierich Pascal Dierich +Paweł Bylica +Paweł Bylica + RJ Catalano RJ Catalano @@ -179,8 +236,22 @@ Rene Lubov <41963722+renaynay@users.noreply.github.com> Robert Zaremba Robert Zaremba +Roberto Bayardo +Roberto Bayardo + Roman Mandeleil +Sebastian Stammler +Sebastian Stammler + +Seungbae Yu +Seungbae Yu <72970043+dbadoy@users.noreply.github.com> + +Sina Mahmoodi <1591639+s1na@users.noreply.github.com> + +Steve Milk +Steve Milk <915337710@qq.com> + Sorin Neacsu Sorin Neacsu @@ -191,8 +262,14 @@ Taylor Gerring Thomas Bocek +tianyeyouyou +tianyeyouyou <150894831+tianyeyouyou@users.noreply.github.com> + Tim Cooijmans +ucwong +ucwong + Valentin Wüstholz Valentin Wüstholz @@ -221,6 +298,9 @@ Xudong Liu <33193253+r1cs@users.noreply.github.com> Yohann Léon +yzb <335357057@qq.com> +yzb <335357057@qq.com> + Zachinquarantine Zachinquarantine @@ -228,9 +308,4 @@ Ziyuan Zhong Zsolt Felföldi -meowsbits -meowsbits <45600330+meowsbits@users.noreply.github.com> - -nedifi <103940716+nedifi@users.noreply.github.com> - Максим Чусовлянов diff --git a/AUTHORS b/AUTHORS index 151c85016..1ec240aeb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,52 +1,81 @@ # This is the official list of go-ethereum authors for copyright purposes. +0xbeny <55846654+0xbeny@users.noreply.github.com> +0xbstn +0xe3b0c4 <110295932+0xe3b0c4@users.noreply.github.com> 6543 <6543@obermui.de> +6xiaowu9 <736518585@qq.com> a e r t h Aaron Buchwald +Aaron Chen +Aaron Kumavis +Aayush Rajasekaran Abel Nieto +Abirdcfly Adam Babik Adam Schmideg Aditya Aditya Arora +Adrian Sutton Adrià Cidre Afanasii Kurakin Afri Schoedon <5chdn@users.noreply.github.com> Agustin Armellini Fischer +Ahmet Avci Ahyun Airead Alan Chen Alejandro Isaza Aleksey Smyrnov Ales Katona +alex <152680487+bodhi-crypo@users.noreply.github.com> Alex Beregszaszi +Alex Gartner Alex Leverington Alex Mazalov +Alex Mylonas Alex Pozhilenkov Alex Prut <1648497+alexprut@users.noreply.github.com> +Alex Stokes Alex Wu +Alexander Mint Alexander van der Meij Alexander Yastrebov Alexandre Van de Sande Alexey Akhunov Alexey Shekhirin alexwang <39109351+dipingxian2@users.noreply.github.com> +Alfie John Ali Atiia <42751398+aliatiia@users.noreply.github.com> Ali Hajimirza +Alvaro Sevilla am2rican5 +Amin Talebi +AMIR <31338382+amiremohamadi@users.noreply.github.com> AmitBRD <60668103+AmitBRD@users.noreply.github.com> Anatole <62328077+a2br@users.noreply.github.com> +Andre Patta Andrea Franz +Andrei Kostakov Andrei Maiboroda +Andrei Silviu Dragnea +Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Andrey Petrov +Andryanau Kanstantsin ANOTHEL Antoine Rondelet Antoine Toulme Anton Evangelatov Antonio Salazar Cardozo +Antony Denyer +Anusha <63559942+anusha-ctrl@users.noreply.github.com> Arba Sasmoyo Armani Ferrante Armin Braun Aron Fischer +Arran Schlosberg <519948+ARR4N@users.noreply.github.com> +ArtificialPB +Artyom Aminov atsushi-ishibashi Austin Roberts ayeowch @@ -54,83 +83,135 @@ b00ris b1ackd0t bailantaotao baizhenxuan +Bala Murali Krishna Komatireddy Balaji Shetty Pachai <32358081+balajipachai@users.noreply.github.com> Balint Gabor baptiste-b-pegasys <85155432+baptiste-b-pegasys@users.noreply.github.com> Bas van Kervel Benjamin Brent +Benjamin Prosnitz benma Benoit Verkindt +Bin <49082129+songzhibin97@users.noreply.github.com> Binacs +bitcoin-lightning <153181187+AtomicInnovation321@users.noreply.github.com> +bk <5810624+bkellerman@users.noreply.github.com> bloonfield +bnovil Bo Bo Ye Bob Glickstein Boqin Qin +BorkBorked <107079055+BorkBorked@users.noreply.github.com> Brandon Harden +Brandon Liu Brent Brian Schroeder +Brion <4777457+cifer76@users.noreply.github.com> Bruno Škvorc +buddho +bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> C. Brown Caesar Chad +cam-schultz <78878559+cam-schultz@users.noreply.github.com> Casey Detrio +caseylove CDsigma +Cedrick Ceelog Ceyhun Onur chabashilah changhong +Charles Cooper Chase Wright +Chawin Aiemvaravutigul Chen Quan +chen4903 <108803001+chen4903@users.noreply.github.com> Cheng Li chenglin <910372762@qq.com> chenyufeng +Chirag Garg <38765776+DeVil2O@users.noreply.github.com> +chirag-bgh <76247491+chirag-bgh@users.noreply.github.com> Chris Pacia Chris Ziogas Christian Muehlhaeuser +Christina <156356273+cratiu222@users.noreply.github.com> Christoph Jentzsch +Christopher Harrison <31964100+chrischarlesharrison@users.noreply.github.com> chuwt +cocoyeal <150209682+cocoyeal@users.noreply.github.com> cong Connor Stein Corey Lin <514971757@qq.com> courtier cpusoft +crazeteam <164632007+crazeteam@users.noreply.github.com> Crispin Flowerday croath cui <523516579@qq.com> +cui fliter +cuinix <65650185+cuinix@users.noreply.github.com> +Curith +cygaar <97691933+cygaar@users.noreply.github.com> +Dan Cline <6798349+Rjected@users.noreply.github.com> Dan DeGreef Dan Kinsley +Dan Laine Dan Sosedoff +danceratopz Daniel A. Nagy +Daniel Fernandes <711733+daferna@users.noreply.github.com> +Daniel Katzan <108216499+dkatzan@users.noreply.github.com> +Daniel Knopik <107140945+dknopik@users.noreply.github.com> +Daniel Liu Daniel Perez Daniel Sloof +Danno Ferrin +Danyal Prout Darioush Jalali Darrel Herbst +Darren Kelly <107671032+darrenvechain@users.noreply.github.com> +dashangcun <907225865@qq.com> Dave Appleton Dave McGregor David Cai +David Dzhalaev <72649244+DavidRomanovizc@users.noreply.github.com> David Huie +David Murdoch <187813+davidmurdoch@users.noreply.github.com> +David Theodore <29786815+infosecual@users.noreply.github.com> +ddl +Dean Eigenmann <7621705+decanus@users.noreply.github.com> +Delweng Denver Derek Chiang Derek Gottfrid +deterclosed <164524498+deterclosed@users.noreply.github.com> +Devon Bear Di Peng Diederik Loerakker Diego Siqueira Diep Pham +Dimitris Apostolou dipingxian2 <39109351+dipingxian2@users.noreply.github.com> divergencetech <94644849+divergencetech@users.noreply.github.com> +dknopik <107140945+dknopik@users.noreply.github.com> dm4 Dmitrij Koniajev Dmitry Shulyak Dmitry Zenovich Domino Valdano +DongXi Huang <418498589@qq.com> Dragan Milic dragonvslinux <35779158+dragononcrypto@users.noreply.github.com> +Dylan Vassallo +easyfold <137396765+easyfold@users.noreply.github.com> Edgar Aroutiounian Eduard S Egon Elbre Elad Eli Elias Naur +Elias Rad <146735585+nnsW3@users.noreply.github.com> Elliot Shepherd Emil emile @@ -151,11 +232,13 @@ Evgeny Evgeny Danilenko <6655321@bk.ru> evgk Evolution404 <35091674+Evolution404@users.noreply.github.com> +Exca-DK <85954505+Exca-DK@users.noreply.github.com> EXEC Fabian Vogelsteller Fabio Barone Fabio Berger FaceHo +felipe Felipe Strozberg <48066928+FelStroz@users.noreply.github.com> Felix Lange Ferenc Szabo @@ -163,68 +246,102 @@ ferhat elmas Ferran Borreguero Fiisio Fire Man <55934298+basdevelop@users.noreply.github.com> +FletcherMan flowerofdream <775654398@qq.com> fomotrader <82184770+fomotrader@users.noreply.github.com> +Ford <153042616+guerrierindien@users.noreply.github.com> ForLina <471133417@qq.com> Frank Szendzielarz <33515470+FrankSzendzielarz@users.noreply.github.com> Frank Wang Franklin +Freeman Jiang Furkan KAMACI Fuyang Deng GagziW Gary Rong Gautam Botrel +Gealber Morales <48373523+Gealber@users.noreply.github.com> +George Ma <164313692+availhang@users.noreply.github.com> George Ornbo +georgehao +gitglorythegreat Giuseppe Bertone Greg Colvin Gregg Dourgarian Gregory Markou <16929357+GregTheGreek@users.noreply.github.com> +guangwu +Guido Vranken Guifel Guilherme Salgado Guillaume Ballet +Guillaume Michel Guillaume Nicolas GuiltyMorishita Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Gus Gustav Simonsson +Gustavo Silva Gísli Kristjánsson Ha ĐANG HackyMiner -hadv +Halimao <1065621723@qq.com> Hanjiang Yu Hao Bryan Cheng Hao Duan +haoran <159284258+hr98w@users.noreply.github.com> +Haotian <51777534+tmelhao@users.noreply.github.com> HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Harry Dutton +Harry Kalodner haryu703 <34744512+haryu703@users.noreply.github.com> +hattizai Hendrik Hofstadt Henning Diedrich henopied <13500516+henopied@users.noreply.github.com> +henridf +Henry <101552941+henry-0@users.noreply.github.com> hero5512 holisticode Hongbin Mao Hsien-Tang Kao hsyodyssey <47173566+hsyodyssey@users.noreply.github.com> +Hteev Oli Husam Ibrahim <39692071+HusamIbrahim@users.noreply.github.com> Hwanjo Heo <34005989+hwanjo@users.noreply.github.com> hydai +hyhnet +hyunchel <3271191+hyunchel@users.noreply.github.com> Hyung-Kyu Hqueue Choi +Hyunsoo Shin (Lake) +hzysvilla Håvard Anda Estensen Ian Macalinao Ian Norden +Icarus Wu icodezjb -Ikko Ashimine +ids +Ignacio Hagopian +Ikko Eltociear Ashimine Ilan Gitter <8359193+gitteri@users.noreply.github.com> +imalasong <55082705+imalasong@users.noreply.github.com> ImanSharaf <78227895+ImanSharaf@users.noreply.github.com> +imulmat4 <117636097+imulmat4@users.noreply.github.com> +Inphi +int88 <106391185+int88@users.noreply.github.com> Isidoro Ghezzi Iskander (Alex) Sharipov +Ivan Aracki Ivan Bogatyy Ivan Daniluk Ivo Georgiev +j2gg0s jacksoom +jackyin <648588267@qq.com> Jae Kwon -James Prestwich <10149425+prestwich@users.noreply.github.com> +Jakub Freebit <49676311+jakub-freebit@users.noreply.github.com> +James Prestwich Jamie Pitts +Janko Simonovic Janoš Guljaš Jared Wasinger Jason Carver @@ -239,42 +356,63 @@ Jeff Wentworth Jeffery Robert Walsh Jeffrey Wilcke Jens Agerberg +Jens W <8270201+DragonDev1906@users.noreply.github.com> Jeremy McNevin Jeremy Schlatter Jerzy Lasyk Jesse Tane Jia Chenhui Jim McDonald +jin <35813306+lochjin@users.noreply.github.com> jk-jeongkyun <45347815+jeongkyun-oh@users.noreply.github.com> jkcomment +Joe Netti JoeGruffins <34998433+JoeGruffins@users.noreply.github.com> Joel Burget John C. Vernaleo +John Chase <68833933+joohhnnn@users.noreply.github.com> John Difool +John Hilliard +John Xu Johns Beharry +Jolly Zhao Jonas Jonathan Brown Jonathan Chappelow Jonathan Gimeno +Jonathan Otto JoranHonig Jordan Krage +Jorge Jorropo Joseph Chow +Joseph Cook <33655003+jmcook1186@users.noreply.github.com> Joshua Colvin Joshua Gutow jovijovi +jp-imx <109574657+jp-imx@users.noreply.github.com> jtakalai JU HYEONG PARK Julian Y Justin Clark-Casey +Justin Dhillon Justin Drake +Justin Traglia <95511699+jtraglia@users.noreply.github.com> Justus +KAI <35927054+ThreeAndTwo@users.noreply.github.com> +kaliubuntu0206 <139627505+kaliubuntu0206@users.noreply.github.com> +Karl Bartel +Karol Chojnowski Kawashima <91420903+sscodereth@users.noreply.github.com> +kazak ken10100147 Kenji Siu Kenso Trabing +Kero +kevaundray Kevin kevin.xu +Kiarash Hajian <133909368+kiarash8112@users.noreply.github.com> KibGzr kiel barry kilic @@ -282,8 +420,10 @@ kimmylin <30611210+kimmylin@users.noreply.github.com> Kitten King <53072918+kittenking@users.noreply.github.com> knarfeh Kobi Gurkan +Koichi Shiraishi komika Konrad Feldmeier +Kosuke Taniguchi <73885532+TaniguchiKosuke@users.noreply.github.com> Kris Shinn Kristofer Peterson Kumar Anirudha @@ -296,6 +436,8 @@ Lefteris Karapetsas Leif Jurvetson Leo Shklovskii LeoLiao +Leon <316032931@qq.com> +levisyin <150114626+levisyin@users.noreply.github.com> Lewis Marshall lhendre Li Dongwei @@ -305,36 +447,58 @@ libby kent libotony LieutenantRoger ligi +lilasxie +Lindlof Lio李欧 -lmittmann +Liyi Guo <102356659+colinlyguo@users.noreply.github.com> +llkhacquan <3724362+llkhacquan@users.noreply.github.com> +lmittmann <3458786+lmittmann@users.noreply.github.com> +lorenzo <31852651+lorenzo-dev1@users.noreply.github.com> Lorenzo Manacorda Louis Holbrook Luca Zeug +Lucas Lucas Hendren +Luozhu <70309026+LuozhuZhang@users.noreply.github.com> +lwh lzhfromustc <43191155+lzhfromustc@users.noreply.github.com> +Maciej Kulawik <10907694+magicxyyz@users.noreply.github.com> +Madhur Shrimal Magicking +makcandrov manlio +Manoj Kumar Maran Hidskes +Marcin Sobczak <77129288+marcindsobczak@users.noreply.github.com> +Marcus Baldassarre Marek Kotewicz Mariano Cortesi +Mario Vega +Marius G <90795310+bearpebble@users.noreply.github.com> +Marius Kjærstad Marius van der Wijden Mark Mark Rushakoff +Mark Tyneway mark.lin +markus <55011443+mdymalla@users.noreply.github.com> +Marquis Shanahan <29431502+9547@users.noreply.github.com> Martin Alex Philip Dawson Martin Holst Swende Martin Klepsch Martin Lundfall Martin Michlmayr Martin Redmond <21436+reds@users.noreply.github.com> +maskpp Mason Fischer Mateusz Morusiewicz <11313015+Ruteri@users.noreply.github.com> Mats Julian Olsen -Matt Garnett <14004106+lightclient@users.noreply.github.com> +Matt Garnett Matt K <1036969+mkrump@users.noreply.github.com> Matthew Di Ferrante Matthew Halpern Matthew Wampler-Doty +Matthieu Vachon Max Sistemich Maxim Zhiburt Maximilian Meister @@ -342,34 +506,55 @@ me020523 Melvin Junhee Woo meowsbits Micah Zoltu +Michael de Hoog Michael Forney Michael Riabzev Michael Ruminer michael1011 Miguel Mota Mike Burr +Mikel Cortes <45786396+cortze@users.noreply.github.com> Mikhail Mikheev +Mikhail Vazhnov +miles <66052478+miles-six@users.noreply.github.com> +Miles Chen milesvant +minh-bq <97180373+minh-bq@users.noreply.github.com> +Mio Miro Miya Chen +mmsqe +Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Mohanson +moomin <67548026+nothingmin@users.noreply.github.com> mr_franklin +Mskxn <118117161+Mskxn@users.noreply.github.com> Mudit Gupta Mymskmkt <1847234666@qq.com> Nalin Bhardwaj +nand2 +Nathan +Nathan Jo <162083209+qqqeck@users.noreply.github.com> Natsu Kagami +Naveen <116692862+naveen-imtb@users.noreply.github.com> Nchinda Nchinda -nebojsa94 +Nebojsa Urosevic necaremus nedifi <103940716+nedifi@users.noreply.github.com> needkane <604476380@qq.com> +Newt6611 <45097780+Newt6611@users.noreply.github.com> +Ng Wei Han <47109095+weiihann@users.noreply.github.com> Nguyen Kien Trung Nguyen Sy Thanh Son Nic Jansma +Nicholas Nick Dodson Nick Johnson +Nicola Cocchiaro <3538109+ncocchiaro@users.noreply.github.com> Nicolas Feignon +Nicolas Gotchac Nicolas Guillaume +Nikhil Suri Nikita Kozhemyakin Nikola Madjarevic Nilesh Trivedi @@ -379,32 +564,47 @@ njupt-moon <1015041018@njupt.edu.cn> nkbai noam-alchemy <76969113+noam-alchemy@users.noreply.github.com> nobody +noel <72006780+0x00Duke@users.noreply.github.com> Noman +norwnd <112318969+norwnd@users.noreply.github.com> nujabes403 Nye Liu +Obtuse7772 <117080049+Obtuse7772@users.noreply.github.com> Oleg Kovalov Oli Bye Oliver Tale-Yazdi Olivier Hervieu +openex Or Neeman +oseau Osoro Bironga Osuke +panicalways <113693386+panicalways@users.noreply.github.com> Pantelis Peslis +Parithosh Jayanthi +Park Changwan Pascal Dierich Patrick O'Grady Pau +Paul <41552663+molecula451@users.noreply.github.com> Paul Berg +Paul Lange Paul Litvak Paul-Armand Verhaegen Paulo L F Casaretto +Pawan Dhananjay Paweł Bylica Pedro Gomes Pedro Pombeiro +persmor <166146971+persmor@users.noreply.github.com> +Peter (bitfly) <1674920+peterbitfly@users.noreply.github.com> Peter Broadhurst peter cresswell Peter Pratscher Peter Simard +Peter Straus <153843855+krauspt@users.noreply.github.com> Petr Mikusek +phenix3443 Philip Schlump Pierre Neter Pierre R @@ -412,15 +612,24 @@ piersy PilkyuJung Piotr Dyraga ploui <64719999+ploui@users.noreply.github.com> +PolyMa <151764357+polymaer@users.noreply.github.com> Preston Van Loon Prince Sinha +psogv0308 +puhtaytow <18026645+puhtaytow@users.noreply.github.com> Péter Szilágyi +qcrao qd-ethan <31876119+qdgogogo@users.noreply.github.com> Qian Bin +qiuhaohao +Qt +Quentin McGaw Quest Henkart +Rachel Bousfield Rachel Franks Rafael Matias Raghav Sood +Rajaram Gaunker Ralph Caraveo Ramesh Nair rangzen @@ -430,45 +639,65 @@ rhaps107 Ricardo Catalinas Jiménez Ricardo Domingos Richard Hart +RichΛrd Rick RJ Catalano Rob Rob Mulholand Robert Zaremba +Roberto Bayardo Roc Yu +Roman Krasiuk Roman Mazalov <83914728+gopherxyz@users.noreply.github.com> Ross <9055337+Chadsr@users.noreply.github.com> +Rossen Krastev +Roy Crihfield Runchao Han +Ruohui Wang Russ Cox Ryan Schneider +Ryan Tinianov ryanc414 Rémy Roy S. Matthew English salanfe Sam <39165351+Xia-Sam@users.noreply.github.com> +Saman H. Pasha <51169592+saman-pasha@users.noreply.github.com> Sammy Libre <7374093+sammy007@users.noreply.github.com> Samuel Marks +Sanghee Choi <32831939+pengin7384@users.noreply.github.com> +SangIlMo <156392700+SangIlMo@users.noreply.github.com> sanskarkhare +SanYe Sarlor Sasuke1964 Satpal <28562234+SatpalSandhu61@users.noreply.github.com> Saulius Grigaitis Sean +seayyyy <163325936+seay404@users.noreply.github.com> +Sebastian Stammler Serhat Şevki Dinçer +Seungbae Yu +Seungmin Kim Shane Bammel shawn <36943337+lxex@users.noreply.github.com> shigeyuki azuchi Shihao Xia Shiming +Shiming Zhang Shintaro Kaneko shiqinfeng1 <150627601@qq.com> +Shivam Sandbhor +shivhg Shuai Qi Shude Li Shunsuke Watanabe +shuo silence Simon Jentzsch Sina Mahmoodi <1591639+s1na@users.noreply.github.com> sixdays +sjlee1125 <47561537+sjlee1125@users.noreply.github.com> SjonHortensius Slava Karpenko slumber1122 @@ -477,17 +706,29 @@ soc1c Sorin Neacsu Sparty Stein Dekker +Stephen Flynn +Stephen Guo Steve Gattuso +Steve Milk Steve Ruckdashel Steve Waldman Steven E. Harris Steven Roose stompesi stormpang +storyicon +strykerin +sudeep +SuiYuan <165623542+suiyuan1314@users.noreply.github.com> +Sungwoo Kim sunxiaojun2014 Suriyaa Sundararuban Sylvain Laurent +Szupingwang +tactical_retreat +Taeguk Kwon Taeik Lim +taiking tamirms Tangui Clairet Tatsuya Shimoda @@ -495,21 +736,35 @@ Taylor Gerring TColl <38299499+TColl@users.noreply.github.com> terasum tgyKomgo <52910426+tgyKomgo@users.noreply.github.com> +Thabokani <149070269+Thabokani@users.noreply.github.com> Thad Guidry +therainisme Thomas Bocek thomasmodeneis thumb8432 Ti Zhou tia-99 <67107070+tia-99@users.noreply.github.com> +tianyeyouyou +Tien Nguyen <116023870+htiennv@users.noreply.github.com> Tim Cooijmans +TinyFoxy Tobias Hildebrandt <79341166+tobias-hildebrandt@users.noreply.github.com> +tokikuch +Tom <45168162+tomdever@users.noreply.github.com> Tosh Camille +trillo +Tristan-Wilson <87238672+Tristan-Wilson@users.noreply.github.com> +trocher tsarpaul +TY <45994721+tylerK1294@users.noreply.github.com> Tyler Chambers <2775339+tylerchambers@users.noreply.github.com> +tylerni7 tzapu -ucwong +ucwong uji <49834542+uji@users.noreply.github.com> ult-bobonovski +Undefinedor +Ursulafe <152976968+Ursulafe@users.noreply.github.com> Valentin Trinqué Valentin Wüstholz Vedhavyas Singareddi @@ -528,39 +783,60 @@ Vitaly V Vivek Anand Vlad Bokov Vlad Gluhovsky +VM <112189277+sysvm@users.noreply.github.com> +vuittont60 <81072379+vuittont60@users.noreply.github.com> +wangjingcun +wangyifan Ward Bradt Water <44689567+codeoneline@users.noreply.github.com> wbt +Wei Tang weimumu <934657014@qq.com> Wenbiao Zheng Wenshao Zhong +Wihan de Beer Will Villanueva William Morriss William Setzer williambannas +willian.eth +winniehere +winterjihwan <113398351+winterjihwan@users.noreply.github.com> wuff1996 <33193253+wuff1996@users.noreply.github.com> Wuxiang Xiaobing Jiang +xiaodong <81516175+javaandfly@users.noreply.github.com> xiekeyang +xinbenlv xincaosu xinluyin <31590468+xinluyin@users.noreply.github.com> +xiyang <90125263+JBossBC@users.noreply.github.com> Xudong Liu <33193253+r1cs@users.noreply.github.com> xwjack yahtoo Yang Hau YaoZengzeng +ycyraum YH-Zhou +Yier <90763233+yierx@users.noreply.github.com> Yihau Chen +yihuang Yohann Léon Yoichi Hirai Yole <007yuyue@gmail.com> Yondon Fu +yong <33920876+yzhaoyu@users.noreply.github.com> YOSHIDA Masanori yoza +ysh0566 +yudrywet <166895665+yudrywet@users.noreply.github.com> +yujinpark +yukionfire yumiel yoomee1313 Yusup yutianwu ywzqwwt <39263032+ywzqwwt@users.noreply.github.com> +yzb <335357057@qq.com> zaccoding Zach Zachinquarantine @@ -568,24 +844,34 @@ zah Zahoor Mohamed Zak Cole zcheng9 +zeim839 <50573884+zeim839@users.noreply.github.com> zer0to0ne <36526113+zer0to0ne@users.noreply.github.com> zgfzgf <48779939+zgfzgf@users.noreply.github.com> Zhang Zhuo zhangsoledad <787953403@qq.com> zhaochonghe <41711151+zhaochonghe@users.noreply.github.com> +zhen peng <505380967@qq.com> Zhenguo Niu +Zheyuan He +Zhihao Lin <3955922+kkqy@users.noreply.github.com> zhiqiangxu <652732310@qq.com> Zhou Zhiyao Ziyuan Zhong Zoe Nolan +zoereco <158379334+zoereco@users.noreply.github.com> +Zoo +Zoro <40222601+BabyHalimao@users.noreply.github.com> Zou Guangxian Zsolt Felföldi Łukasz Kurowski Łukasz Zimnoch ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com> Максим Чусовлянов +かげ <47621124+ronething-bot@users.noreply.github.com> +スパイク <1311798+spkjp@users.noreply.github.com> 大彬 沉风 +牛晓婕 <30611384+niuxiaojie81@users.noreply.github.com> 贺鹏飞 陈佳 유용환 <33824408+eric-yoo@users.noreply.github.com> diff --git a/beacon/light/sync/head_sync.go b/beacon/light/sync/head_sync.go index dd05d3958..5e4125805 100644 --- a/beacon/light/sync/head_sync.go +++ b/beacon/light/sync/head_sync.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2024 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 diff --git a/beacon/params/networks.go b/beacon/params/networks.go index 5b00b2795..1204e0176 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2024 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 diff --git a/cmd/abigen/namefilter.go b/cmd/abigen/namefilter.go index eea5c643c..00945ef47 100644 --- a/cmd/abigen/namefilter.go +++ b/cmd/abigen/namefilter.go @@ -1,3 +1,19 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + package main import ( diff --git a/cmd/abigen/namefilter_test.go b/cmd/abigen/namefilter_test.go index ccee71201..254b3302e 100644 --- a/cmd/abigen/namefilter_test.go +++ b/cmd/abigen/namefilter_test.go @@ -1,3 +1,19 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + package main import ( diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index d74e1496c..57bc46c36 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -1,18 +1,18 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. +// Copyright 2024 The go-ethereum Authors +// This file is part of go-ethereum. // -// 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 +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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, +// go-ethereum 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. +// GNU 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 . +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . package main diff --git a/cmd/evm/eofparse.go b/cmd/evm/eofparse.go index 92182a53b..971073557 100644 --- a/cmd/evm/eofparse.go +++ b/cmd/evm/eofparse.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2024 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify diff --git a/cmd/evm/eofparse_test.go b/cmd/evm/eofparse_test.go index cda4b38fc..a9119916a 100644 --- a/cmd/evm/eofparse_test.go +++ b/cmd/evm/eofparse_test.go @@ -1,3 +1,19 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + package main import ( diff --git a/cmd/geth/attach_test.go b/cmd/geth/attach_test.go index ceae3a122..1df25359c 100644 --- a/cmd/geth/attach_test.go +++ b/cmd/geth/attach_test.go @@ -1,18 +1,18 @@ // Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. +// This file is part of go-ethereum. // -// 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 +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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, +// go-ethereum 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. +// GNU 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 . +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . package main diff --git a/cmd/geth/logging_test.go b/cmd/geth/logging_test.go index 4293a860e..37fffecc3 100644 --- a/cmd/geth/logging_test.go +++ b/cmd/geth/logging_test.go @@ -1,5 +1,3 @@ -//go:build integrationtests - // Copyright 2023 The go-ethereum Authors // This file is part of go-ethereum. // @@ -16,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . +//go:build integrationtests + package main import ( diff --git a/cmd/geth/logtestcmd_active.go b/cmd/geth/logtestcmd_active.go index f2a2c5ded..f9bbc3d4e 100644 --- a/cmd/geth/logtestcmd_active.go +++ b/cmd/geth/logtestcmd_active.go @@ -1,5 +1,3 @@ -//go:build integrationtests - // Copyright 2023 The go-ethereum Authors // This file is part of go-ethereum. // @@ -16,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . +//go:build integrationtests + package main import ( diff --git a/cmd/geth/logtestcmd_inactive.go b/cmd/geth/logtestcmd_inactive.go index 691ab5bcd..8dda1c47e 100644 --- a/cmd/geth/logtestcmd_inactive.go +++ b/cmd/geth/logtestcmd_inactive.go @@ -1,5 +1,3 @@ -//go:build !integrationtests - // Copyright 2023 The go-ethereum Authors // This file is part of go-ethereum. // @@ -16,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . +//go:build !integrationtests + package main import "github.com/urfave/cli/v2" diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index bfe20767d..8bd6b71ee 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package rawdb diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 2923a2c22..7dada63d4 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package state diff --git a/core/txindexer.go b/core/txindexer.go index b2f218859..293124f68 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package core diff --git a/core/txindexer_test.go b/core/txindexer_test.go index 0a606ed8f..c96a71297 100644 --- a/core/txindexer_test.go +++ b/core/txindexer_test.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package core diff --git a/core/txpool/blobpool/lookup.go b/core/txpool/blobpool/lookup.go index 2d8d0fd2b..b5cf4d379 100644 --- a/core/txpool/blobpool/lookup.go +++ b/core/txpool/blobpool/lookup.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2024 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 diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 8af962499..d55e85d74 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . + package legacypool import ( diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 664f9e05e..f1dfe965b 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2014 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 diff --git a/core/types/tx_blob_test.go b/core/types/tx_blob_test.go index 6bd0f183b..b9e6dcb0b 100644 --- a/core/types/tx_blob_test.go +++ b/core/types/tx_blob_test.go @@ -1,3 +1,19 @@ +// Copyright 2023 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 . + package types import ( diff --git a/core/vm/eof_control_flow.go b/core/vm/eof_control_flow.go index 823078077..c0a445990 100644 --- a/core/vm/eof_control_flow.go +++ b/core/vm/eof_control_flow.go @@ -1,18 +1,18 @@ // Copyright 2024 The go-ethereum Authors -// This file is part of go-ethereum. +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package vm diff --git a/core/vm/eof_test.go b/core/vm/eof_test.go index 8106a2972..0a9cf638c 100644 --- a/core/vm/eof_test.go +++ b/core/vm/eof_test.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2024 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 diff --git a/core/vm/jump_table_test.go b/core/vm/jump_table_test.go index 02558035c..a4f9759ed 100644 --- a/core/vm/jump_table_test.go +++ b/core/vm/jump_table_test.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2016 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 diff --git a/core/vm/memory_test.go b/core/vm/memory_test.go index ba36f8023..41389b729 100644 --- a/core/vm/memory_test.go +++ b/core/vm/memory_test.go @@ -1,3 +1,19 @@ +// Copyright 2023 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 . + package vm import ( diff --git a/core/vm/program/program.go b/core/vm/program/program.go index 3b00bbae6..5b9cfdcc5 100644 --- a/core/vm/program/program.go +++ b/core/vm/program/program.go @@ -1,18 +1,18 @@ // Copyright 2024 The go-ethereum Authors // This file is part of the go-ethereum library. // -// The library is free software: you can redistribute it and/or modify +// 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. // -// This library is distributed in the hope that it will be useful, +// 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 goevmlab library. If not, see . +// along with the go-ethereum library. If not, see . // package program is a utility to create EVM bytecode for testing, but _not_ for production. As such: // diff --git a/core/vm/program/program_test.go b/core/vm/program/program_test.go index 0b3421006..ceb7d8be6 100644 --- a/core/vm/program/program_test.go +++ b/core/vm/program/program_test.go @@ -1,18 +1,18 @@ // Copyright 2024 The go-ethereum Authors // This file is part of the go-ethereum library. // -// The library is free software: you can redistribute it and/or modify +// 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. // -// This library is distributed in the hope that it will be useful, +// 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 goevmlab library. If not, see . +// along with the go-ethereum library. If not, see . package program diff --git a/eth/tracers/dir.go b/eth/tracers/dir.go index 1cdfab545..05c76bceb 100644 --- a/eth/tracers/dir.go +++ b/eth/tracers/dir.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2024 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 diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 553eaf1b5..4390a62b4 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -1,3 +1,19 @@ +// Copyright 2023 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 . + package tracetest import ( diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js index 7a5074893..826c91f63 100644 --- a/eth/tracers/internal/tracetest/makeTest.js +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -1,3 +1,19 @@ +// Copyright 2024 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 . + // makeTest generates a test for the configured tracer by running // a prestate reassembled and a call trace run, assembling all the // gathered information into a test case. diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index ad3d75d8d..680645970 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -1,4 +1,4 @@ -// Copyright 2021 The go-ethereum Authors +// Copyright 2022 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 diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 16ef7b8f9..0ea35cb1a 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -1,4 +1,4 @@ -// Copyright 2021 The go-ethereum Authors +// Copyright 2024 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 diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 524a396d5..85727e29e 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -1,3 +1,19 @@ +// Copyright 2022 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 . + package tracetest import ( diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go index cff629556..88a9f5db4 100644 --- a/eth/tracers/internal/util.go +++ b/eth/tracers/internal/util.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2024 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 diff --git a/eth/tracers/internal/util_test.go b/eth/tracers/internal/util_test.go index 6a467314c..d6b51c4d8 100644 --- a/eth/tracers/internal/util_test.go +++ b/eth/tracers/internal/util_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2024 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 @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . + package internal import ( diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index e56d01113..4e7fc31a9 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 diff --git a/eth/tracers/tracker_test.go b/eth/tracers/tracker_test.go index 46f6ac8e5..447ab4e6b 100644 --- a/eth/tracers/tracker_test.go +++ b/eth/tracers/tracker_test.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package tracers diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index 8efe93e24..5bf3c6be2 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 The go-ethereum Authors +// Copyright 2024 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 diff --git a/ethclient/simulated/rollback_test.go b/ethclient/simulated/rollback_test.go index 8fc9f5bc8..57c59496d 100644 --- a/ethclient/simulated/rollback_test.go +++ b/ethclient/simulated/rollback_test.go @@ -1,3 +1,19 @@ +// Copyright 2025 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 . + package simulated import ( diff --git a/ethdb/pebble/pebble_test.go b/ethdb/pebble/pebble_test.go index 1d5611f21..3265491d4 100644 --- a/ethdb/pebble/pebble_test.go +++ b/ethdb/pebble/pebble_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2019 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 diff --git a/graphql/internal/graphiql/build.go b/graphql/internal/graphiql/build.go index 0065c1112..1daa406a8 100644 --- a/graphql/internal/graphiql/build.go +++ b/graphql/internal/graphiql/build.go @@ -1,3 +1,19 @@ +// Copyright 2023 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 . + package graphiql import ( diff --git a/internal/era/accumulator.go b/internal/era/accumulator.go index 2ece2755e..cb383d8e6 100644 --- a/internal/era/accumulator.go +++ b/internal/era/accumulator.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package era diff --git a/internal/era/builder.go b/internal/era/builder.go index 33261555b..975561564 100644 --- a/internal/era/builder.go +++ b/internal/era/builder.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package era diff --git a/internal/era/e2store/e2store.go b/internal/era/e2store/e2store.go index 8e4d5dd24..9832b72d4 100644 --- a/internal/era/e2store/e2store.go +++ b/internal/era/e2store/e2store.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package e2store diff --git a/internal/era/e2store/e2store_test.go b/internal/era/e2store/e2store_test.go index 353942f0b..cdaefc484 100644 --- a/internal/era/e2store/e2store_test.go +++ b/internal/era/e2store/e2store_test.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package e2store diff --git a/internal/era/era.go b/internal/era/era.go index 6ad7339b3..daf337963 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package era diff --git a/internal/era/era_test.go b/internal/era/era_test.go index d0f56b6f8..e0bebfa44 100644 --- a/internal/era/era_test.go +++ b/internal/era/era_test.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package era diff --git a/internal/era/iterator.go b/internal/era/iterator.go index f48aab46b..3c4f82d85 100644 --- a/internal/era/iterator.go +++ b/internal/era/iterator.go @@ -1,18 +1,18 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of go-ethereum. +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . package era diff --git a/miner/payload_building.go b/miner/payload_building.go index 548f78831..5b1b0bb61 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package miner diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index dbfec5689..5e3af6f62 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package miner diff --git a/miner/pending.go b/miner/pending.go index bb91fe896..9480f9cae 100644 --- a/miner/pending.go +++ b/miner/pending.go @@ -1,4 +1,4 @@ -// Copyright 2024 The go-ethereum Authors +// Copyright 2016 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 diff --git a/p2p/config.go b/p2p/config.go index 14492a2e5..5ea62e12f 100644 --- a/p2p/config.go +++ b/p2p/config.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . + package p2p import ( diff --git a/p2p/pipes/pipe.go b/p2p/pipes/pipe.go index cf1f3e2a8..a1423687b 100644 --- a/p2p/pipes/pipe.go +++ b/p2p/pipes/pipe.go @@ -1,4 +1,4 @@ -// Copyright 2024 The go-ethereum Authors +// 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 diff --git a/rpc/client_opt_test.go b/rpc/client_opt_test.go index d7cc2572a..f62f689f6 100644 --- a/rpc/client_opt_test.go +++ b/rpc/client_opt_test.go @@ -1,3 +1,19 @@ +// Copyright 2022 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 . + package rpc_test import ( diff --git a/tests/fuzzers/difficulty/difficulty_test.go b/tests/fuzzers/difficulty/difficulty_test.go index 49beedb48..c906089f8 100644 --- a/tests/fuzzers/difficulty/difficulty_test.go +++ b/tests/fuzzers/difficulty/difficulty_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2017 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 diff --git a/tests/fuzzers/rangeproof/rangeproof_test.go b/tests/fuzzers/rangeproof/rangeproof_test.go index bc7badc5b..6b8d140e9 100644 --- a/tests/fuzzers/rangeproof/rangeproof_test.go +++ b/tests/fuzzers/rangeproof/rangeproof_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2017 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 diff --git a/tests/fuzzers/txfetcher/txfetcher_test.go b/tests/fuzzers/txfetcher/txfetcher_test.go index ac2e6b1c6..c6647f62d 100644 --- a/tests/fuzzers/txfetcher/txfetcher_test.go +++ b/tests/fuzzers/txfetcher/txfetcher_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2017 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 diff --git a/trie/trie_id.go b/trie/trie_id.go index 8ab490ca3..7ac371b53 100644 --- a/trie/trie_id.go +++ b/trie/trie_id.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package trie diff --git a/trie/trienode/node.go b/trie/trienode/node.go index 047a7a4bd..b09ec6637 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package trienode diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go index 1d33f6c3e..dea210c04 100644 --- a/trie/utils/verkle.go +++ b/trie/utils/verkle.go @@ -1,4 +1,4 @@ -// Copyright 2023 go-ethereum Authors +// Copyright 2023 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 diff --git a/trie/utils/verkle_test.go b/trie/utils/verkle_test.go index dbec29685..44c67ba03 100644 --- a/trie/utils/verkle_test.go +++ b/trie/utils/verkle_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package utils diff --git a/trie/verkle.go b/trie/verkle.go index 2e4d62cd1..015b8f659 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -1,4 +1,4 @@ -// Copyright 2023 go-ethereum Authors +// Copyright 2023 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 diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 84eec2ed3..f31ab02df 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 go-ethereum Authors +// Copyright 2023 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 diff --git a/triedb/pathdb/errors.go b/triedb/pathdb/errors.go index 498bc9ec8..49e9c3ca6 100644 --- a/triedb/pathdb/errors.go +++ b/triedb/pathdb/errors.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/execute.go b/triedb/pathdb/execute.go index 80cecb82e..2400f280a 100644 --- a/triedb/pathdb/execute.go +++ b/triedb/pathdb/execute.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index d8fb99ade..6ba9aaf1b 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go index 7dbe5959d..9458e2478 100644 --- a/triedb/pathdb/history_inspect.go +++ b/triedb/pathdb/history_inspect.go @@ -12,7 +12,7 @@ // 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 . package pathdb diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index 953f02353..2928d19d7 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index 0bd086c2f..85a5e470e 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/metrics.go b/triedb/pathdb/metrics.go index 1a2559e38..45dad6f1a 100644 --- a/triedb/pathdb/metrics.go +++ b/triedb/pathdb/metrics.go @@ -1,4 +1,4 @@ -// Copyright 2022 The go-ethereum Authors +// Copyright 2023 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/nodes.go b/triedb/pathdb/nodes.go index dee8c872a..c56e38066 100644 --- a/triedb/pathdb/nodes.go +++ b/triedb/pathdb/nodes.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index a40440903..30f75d105 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index 969782e3c..873a7ba61 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/pathdb/states_test.go b/triedb/pathdb/states_test.go index 30eb6ad6c..4d181cc91 100644 --- a/triedb/pathdb/states_test.go +++ b/triedb/pathdb/states_test.go @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package pathdb diff --git a/triedb/states.go b/triedb/states.go index 9fabdb088..c5aa7c64b 100644 --- a/triedb/states.go +++ b/triedb/states.go @@ -1,4 +1,4 @@ -// Copyright 2023 The go-ethereum Authors +// Copyright 2024 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 @@ -12,7 +12,7 @@ // 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 +// along with the go-ethereum library. If not, see . package triedb diff --git a/version/version.go b/version/version.go index a6ed3c1fe..7c56cca67 100644 --- a/version/version.go +++ b/version/version.go @@ -1,4 +1,4 @@ -// Copyright 2016 The go-ethereum Authors +// Copyright 2024 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 From ad994c4dd4ce951bda66b9c9c78d6a779f1730a2 Mon Sep 17 00:00:00 2001 From: ericxtheodore Date: Thu, 6 Feb 2025 06:19:09 +0800 Subject: [PATCH 127/354] build: update to Go 1.23.6 (#31130) Co-authored-by: Felix Lange --- build/checksums.txt | 92 +++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 7270492ec..9a7101a3d 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,56 +5,50 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.23.5 +# version:golang 1.23.6 # https://go.dev/dl/ -a6f3f4bbd3e6bdd626f79b668f212fbb5649daf75084fb79b678a0ae4d97423b go1.23.5.src.tar.gz -8d8bc7d1b362dd91426da9352741db298ff73e3e0a3ccbe6f607f80ba17647a4 go1.23.5.aix-ppc64.tar.gz -d8b310b0b6bd6a630307579165cfac8a37571483c7d6804a10dd73bbefb0827f go1.23.5.darwin-amd64.tar.gz -d2b06bf0b8299e0187dfe2d8ad39bd3dd96a6d93fe4d1cfd42c7872452f4a0a2 go1.23.5.darwin-amd64.pkg -047bfce4fbd0da6426bd30cd19716b35a466b1c15a45525ce65b9824acb33285 go1.23.5.darwin-arm64.tar.gz -f819ed94939e08a5016b9a607ec84ebbde6cb3fe59750c59d97aa300c3fd02df go1.23.5.darwin-arm64.pkg -2dec52821e1f04a538d00b2cafe70fa506f2eea94a551bfe3ce1238f1bd4966f go1.23.5.dragonfly-amd64.tar.gz -7204e7bc62913b12f18c61afe0bc1a92fd192c0e45a54125978592296cb84e49 go1.23.5.freebsd-386.tar.gz -90a119995ebc3e36082874df5fa8fe6da194946679d01ae8bef33c87aab99391 go1.23.5.freebsd-amd64.tar.gz -255d26d873e41ff2fc278013bb2e5f25cf2ebe8d0ec84c07e3bb1436216020d3 go1.23.5.freebsd-arm.tar.gz -2785d9122654980b59ca38305a11b34f2a1e12d9f7eb41d52efc137c1fc29e61 go1.23.5.freebsd-arm64.tar.gz -8f66a94018ab666d56868f61c579aa81e549ac9700979ce6004445d315be2d37 go1.23.5.freebsd-riscv64.tar.gz -4b7a69928385ec512a4e77a547e24118adbb92301d2be36187ff0852ba9e6303 go1.23.5.illumos-amd64.tar.gz -6ecf6a41d0925358905fa2641db0e1c9037aa5b5bcd26ca6734caf50d9196417 go1.23.5.linux-386.tar.gz -cbcad4a6482107c7c7926df1608106c189417163428200ce357695cc7e01d091 go1.23.5.linux-amd64.tar.gz -47c84d332123883653b70da2db7dd57d2a865921ba4724efcdf56b5da7021db0 go1.23.5.linux-arm64.tar.gz -04e0b5cf5c216f0aa1bf8204d49312ad0845800ab0702dfe4357c0b1241027a3 go1.23.5.linux-armv6l.tar.gz -e1d14ac2207c78d52b76ba086da18a004c70aeb58cba72cd9bef0da7d1602786 go1.23.5.linux-loong64.tar.gz -d9e937f2fac4fc863850fb4cc31ae76d5495029a62858ef09c78604472d354c0 go1.23.5.linux-mips.tar.gz -59710d0782abafd47e40d1cf96aafa596bbdee09ac7c61062404604f49bd523e go1.23.5.linux-mips64.tar.gz -bc528cd836b4aa6701a42093ed390ef9929639a0e2818759887dc5539e517cab go1.23.5.linux-mips64le.tar.gz -a0404764ea1fd4a175dc5193622b15be6ed1ab59cbfa478f5ae24531bafb6cbd go1.23.5.linux-mipsle.tar.gz -db110284a0c91d4545273f210ca95b9f89f6e3ac90f39eb819033a6b96f25897 go1.23.5.linux-ppc64.tar.gz -db268bf5710b5b1b82ab38722ba6e4427d9e4942aed78c7d09195a9dff329613 go1.23.5.linux-ppc64le.tar.gz -d9da15778442464f32acfa777ac731fd4d47362b233b83a0932380cb6d2d5dc8 go1.23.5.linux-riscv64.tar.gz -14924b917d35311eb130e263f34931043d4f9dc65f20684301bf8f60a72edcdf go1.23.5.linux-s390x.tar.gz -7b8074102e7f039bd6473c44f58cb323c98dcda48df98ad1f78aaa2664769c8f go1.23.5.netbsd-386.tar.gz -1a466b9c8900e66664b15c07548ecb156e8274cf1028ac5da84134728e6dbbed go1.23.5.netbsd-amd64.tar.gz -901c9e72038926e37a4dbde8f03d1d81fcb9992850901a3da1da5a25ef93e65b go1.23.5.netbsd-arm.tar.gz -221f69a7c3a920e3666633ee0b4e5c810176982e74339ba4693226996dc636e4 go1.23.5.netbsd-arm64.tar.gz -42e46cbf73febb8e6ddf848765ce1c39573736383b132402cdc487eb6be3ad06 go1.23.5.openbsd-386.tar.gz -f49e81fce17aab21800fab7c4b10c97ab02f8a9c807fdf8641ccf2f87d69289f go1.23.5.openbsd-amd64.tar.gz -d8bd7269d4670a46e702b64822254a654824347c35923ef1c444d2e8687381ea go1.23.5.openbsd-arm.tar.gz -9cb259adff431d4d28b18e3348e26fe07ea10380675051dcfd740934b5e8b9f2 go1.23.5.openbsd-arm64.tar.gz -72a03223c98fcecfb06e57c3edd584f99fb7f6574a42f59348473f354be1f379 go1.23.5.openbsd-ppc64.tar.gz -c06432b859afb36657207382b7bac03f961b8fafc18176b501d239575a9ace64 go1.23.5.openbsd-riscv64.tar.gz -b1f9b12b269ab5cd4aa7ae3dd3075c2407c1ea8bb1211e6835261f98931201cc go1.23.5.plan9-386.tar.gz -45b4026a103e2f6cd436e2b7ad24b24a40dd22c9903519b98b45c535574fa01a go1.23.5.plan9-amd64.tar.gz -6e28e26f8c1e8620006490260aa5743198843aa0003c400cb65cbf5e743b21c7 go1.23.5.plan9-arm.tar.gz -0496c9969f208bd597f3e63fb27068ce1c7ed776618da1007fcc1c8be83ca413 go1.23.5.solaris-amd64.tar.gz -8441605a005ea74c28d8c02ca5f2708c17b4df7e91796148b9f8760caafb05c1 go1.23.5.windows-386.zip -39962346d8d0cb0cc8716489ee33b08d7a220c24a9e45423487876dd4acbdac6 go1.23.5.windows-386.msi -96d74945d7daeeb98a7978d0cf099321d7eb821b45f5c510373d545162d39c20 go1.23.5.windows-amd64.zip -03e11a988a18ad7e3f9038cef836330af72ba0a454a502cda7b7faee07a0dd8a go1.23.5.windows-amd64.msi -0005b31dcf9732c280a5cceb6aa1c5ab8284bc2541d0256c221256080acf2a09 go1.23.5.windows-arm.zip -a8442de35cbac230db8c4b20e363055671f2295dc4d6b2b2dfec66b89a3c4bce go1.23.5.windows-arm.msi -4f20c2d8a5a387c227e3ef48c5506b22906139d8afd8d66a78ef3de8dda1d1c3 go1.23.5.windows-arm64.zip -6f54fb46b669345c734936c521f7e0f55555e63ed6e11efbbaaed06f9514773c go1.23.5.windows-arm64.msi +039c5b04e65279daceee8a6f71e70bd05cf5b801782b6f77c6e19e2ed0511222 go1.23.6.src.tar.gz +adec10f4ba56591f523aa04851f7f6900b1c61508dfa6b80e62717a8e6684a5c go1.23.6.aix-ppc64.tar.gz +782da50ce8ec5e98fac2cd3cdc6a1d7130d093294fc310038f651444232a3fb0 go1.23.6.darwin-amd64.tar.gz +5cae2450a1708aeb0333237a155640d5562abaf195defebc4306054565536221 go1.23.6.darwin-arm64.tar.gz +d52efb3020d9332477ade98163c03d2f2fe3e051b0e7e01f0e167412c66de0cb go1.23.6.dragonfly-amd64.tar.gz +d3287706b5823712ac6cf7dff684a556cff98163ef60e7b275abe3388c17aac7 go1.23.6.freebsd-386.tar.gz +ebb4c6a9b0673dbdabc439877779ed6add16575e21bd0a7955c33f692789aef6 go1.23.6.freebsd-amd64.tar.gz +b7241584afb0b161c09148f8fde16171bb743e47b99d451fbc5f5217ec7a88b6 go1.23.6.freebsd-arm.tar.gz +004718b53cedd7955d1b1dc4053539fcd1053c031f5f3374334a22befd1f8310 go1.23.6.freebsd-arm64.tar.gz +ca026ec8a30dd0c18164f40e1ce21bd725e2445f11699177d05815189a38de7a go1.23.6.freebsd-riscv64.tar.gz +7db973efa3fb2e48e45059b855721550fce8e90803e7373d3efd37b88dd821e8 go1.23.6.illumos-amd64.tar.gz +e61f87693169c0bbcc43363128f1e929b9dff0b7f448573f1bdd4e4a0b9687ba go1.23.6.linux-386.tar.gz +9379441ea310de000f33a4dc767bd966e72ab2826270e038e78b2c53c2e7802d go1.23.6.linux-amd64.tar.gz +561c780e8f4a8955d32bf72e46af0b5ee5e0debe1e4633df9a03781878219202 go1.23.6.linux-arm64.tar.gz +27a4611010c16b8c4f37ade3aada55bd5781998f02f348b164302fd5eea4eb74 go1.23.6.linux-armv6l.tar.gz +c459226424372abc2b35957cc8955dad348330714f7605093325dbb73e33c750 go1.23.6.linux-loong64.tar.gz +e2a0aff70b958a3463a7d47132a2d0238369f64578d4f7f95e679e3a5af05622 go1.23.6.linux-mips.tar.gz +7d30ec7db056311d420bf930c16abcae13c0f41c26a202868f279721ec3c2f2f go1.23.6.linux-mips64.tar.gz +74ca7bc475bcc084c6718b74df024d7de9612932cea8a6dc75e29d3a5315a23a go1.23.6.linux-mips64le.tar.gz +09bf935a14e9f59a20499989438b1655453480016bdbcb10406acf4df2678ccb go1.23.6.linux-mipsle.tar.gz +5cb2f6a5090276c72c5eda8a55896f5a3d6ea0f28d10fa1a50e8318640f02d6c go1.23.6.linux-ppc64.tar.gz +0f817201e83d78ddbfa27f5f78d9b72450b92cc21d5e045145efacd0d3244a99 go1.23.6.linux-ppc64le.tar.gz +f95f7f817ab22ecab4503d0704d6449ea1aa26a595f57bf9b9f94ddf2aa7c1f3 go1.23.6.linux-riscv64.tar.gz +321e7ed0d5416f731479c52fa7610b52b8079a8061967bd48cec6d66f671a60e go1.23.6.linux-s390x.tar.gz +92d678fb8e1eeeb8c6af6f22e4e5494652dcbb4a320113fc08325cb9956a2d4c go1.23.6.netbsd-386.tar.gz +86ba51e7bb26b30ea6a8d88ddb79d8e8c83b4116200040ecb7a5a44cf90a8c5c go1.23.6.netbsd-amd64.tar.gz +4b974c35345100f0be6ea66afab2781de91ee9882117314126eaf0ae90fd3816 go1.23.6.netbsd-arm.tar.gz +53e3589fc38e787a493ea038961f8e40803714dbb42754c1713b00099c12e9b9 go1.23.6.netbsd-arm64.tar.gz +6d2317b3a8505ccebff8f72d943f2ac9b82c115632e54a53a786eff24ced56d9 go1.23.6.openbsd-386.tar.gz +f699e707d95a984fcc00361d91aecdb413d3c75e18235156ffba7a89edf68aae go1.23.6.openbsd-amd64.tar.gz +3c1cf6ab893657d0bf1942e40ce115acfd27cbce1ccb9bc88fd9cd21ca3d489f go1.23.6.openbsd-arm.tar.gz +cc0875535d14001f2da23ae9af89025b28c466e8f4f4c63f991ebb6f4b02f66c go1.23.6.openbsd-arm64.tar.gz +64de80e29ca66cb566cbf8be030bf8599953af4e48402eab724cbe0a08b40602 go1.23.6.openbsd-ppc64.tar.gz +c398a6b43c569f34bb4a2d16b52f8010eaac9a2a82ecac0602b4338e35cef377 go1.23.6.openbsd-riscv64.tar.gz +10998b6b130bb7b542b407f0db42b86a913b111f8fa86d44394beaace4d45f01 go1.23.6.plan9-386.tar.gz +9fbe8065436d8d12c02f19f64f51c9107da3a7a4ac46ab5777e182e9fe88c32f go1.23.6.plan9-amd64.tar.gz +8e3c826b884daee2de37e3b070d7eac4cea5d68edab8db09910e22201c75db83 go1.23.6.plan9-arm.tar.gz +b619eff63fec86daaea92ca170559e448a58b8ba0b92eef1971bc14e92ea86a7 go1.23.6.solaris-amd64.tar.gz +96820c0f5d464dd694543329e9b4d413b17c821c03a055717a29e6735b44c2d8 go1.23.6.windows-386.zip +53fec1586850b2cf5ad6438341ff7adc5f6700dd3ec1cfa3f5e8b141df190243 go1.23.6.windows-amd64.zip +22c2518c45c20018afa20d5376dc9fd7a7e74367240ed7b5209e79a30b5c4218 go1.23.6.windows-arm.zip +a2d2ec1b3759552bdd9cdf58858f91dfbfd6ab3a472f00b5255acbed30b1aa41 go1.23.6.windows-arm64.zip # version:golangci 1.63.4 # https://github.com/golangci/golangci-lint/releases/ From b2edca7cfc2021e6af54465dc493992ea23b003e Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:33:40 +0100 Subject: [PATCH 128/354] build: update EEST fixtures to prague devnet-6 (#31088) Co-authored-by: lightclient --- build/checksums.txt | 6 +- build/ci.go | 4 +- tests/init_test.go | 21 +++--- tests/transaction_test.go | 32 +++++++++ tests/transaction_test_util.go | 121 ++++++++++++++++++++------------- 5 files changed, 122 insertions(+), 62 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 9a7101a3d..76f05e5b6 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,9 +1,9 @@ # This file contains sha256 checksums of optional build dependencies. -# version:spec-tests 2.1.0 +# version:spec-tests pectra-devnet-6@v1.0.0 # https://github.com/ethereum/execution-spec-tests/releases -# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ -ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz +# https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/fixtures_pectra-devnet-6.tar.gz +b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz # version:golang 1.23.6 # https://go.dev/dl/ diff --git a/build/ci.go b/build/ci.go index dbf4055da..2f26f3ed9 100644 --- a/build/ci.go +++ b/build/ci.go @@ -343,8 +343,8 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { log.Fatal(err) } ext := ".tar.gz" - base := "fixtures_develop" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename - url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/v%s/%s%s", executionSpecTestsVersion, base, ext) + base := "fixtures_pectra-devnet-6" // TODO(s1na) rename once the version becomes part of the filename + url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/%s/%s%s", executionSpecTestsVersion, base, ext) archivePath := filepath.Join(cachedir, base+ext) if err := csdb.DownloadFile(url, archivePath); err != nil { log.Fatal(err) diff --git a/tests/init_test.go b/tests/init_test.go index effeec2b8..b933c9808 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -34,16 +34,17 @@ import ( ) var ( - baseDir = filepath.Join(".", "testdata") - blockTestDir = filepath.Join(baseDir, "BlockchainTests") - stateTestDir = filepath.Join(baseDir, "GeneralStateTests") - legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests") - transactionTestDir = filepath.Join(baseDir, "TransactionTests") - rlpTestDir = filepath.Join(baseDir, "RLPTests") - difficultyTestDir = filepath.Join(baseDir, "BasicTests") - executionSpecBlockchainTestDir = filepath.Join(".", "spec-tests", "fixtures", "blockchain_tests") - executionSpecStateTestDir = filepath.Join(".", "spec-tests", "fixtures", "state_tests") - benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks") + baseDir = filepath.Join(".", "testdata") + blockTestDir = filepath.Join(baseDir, "BlockchainTests") + stateTestDir = filepath.Join(baseDir, "GeneralStateTests") + legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests") + transactionTestDir = filepath.Join(baseDir, "TransactionTests") + rlpTestDir = filepath.Join(baseDir, "RLPTests") + difficultyTestDir = filepath.Join(baseDir, "BasicTests") + executionSpecBlockchainTestDir = filepath.Join(".", "spec-tests", "fixtures", "blockchain_tests") + executionSpecStateTestDir = filepath.Join(".", "spec-tests", "fixtures", "state_tests") + executionSpecTransactionTestDir = filepath.Join(".", "spec-tests", "fixtures", "transaction_tests") + benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks") ) func readJSON(reader io.Reader, value interface{}) error { diff --git a/tests/transaction_test.go b/tests/transaction_test.go index 5179fc9af..814717390 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -19,6 +19,7 @@ package tests import ( "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" ) @@ -42,6 +43,20 @@ func TestTransaction(t *testing.T) { // Geth accepts it, which is not a consensus issue since we use big.Int's // internally to calculate the cost txt.skipLoad("^ttValue/TransactionWithHighValueOverflow.json") + + // The size of a create tx's initcode is only checked during the state + // transition + txt.skipLoad("^ttEIP3860/DataTestInitCodeTooBig.json") + + // The following tests require the tx precheck to be performed + // TODO(s1na): expose stateTransition.precheck publicly to be able to run these tests + txt.skipLoad("^ttEIP1559/maxPriorityFeePerGass32BytesValue.json") + txt.skipLoad("^ttEIP1559/maxPriorityFeePerGasOverflow.json") + txt.skipLoad("^ttEIP1559/maxFeePerGas32BytesValue.json") + txt.skipLoad("^ttEIP1559/maxFeePerGasOverflow.json") + txt.skipLoad("^ttEIP1559/GasLimitPriceProductPlusOneOverflow.json") + txt.skipLoad("^ttEIP1559/GasLimitPriceProductOverflow.json") + txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { cfg := params.MainnetChainConfig if err := txt.checkFailure(t, test.Run(cfg)); err != nil { @@ -49,3 +64,20 @@ func TestTransaction(t *testing.T) { } }) } + +func TestExecutionSpecTransaction(t *testing.T) { + if !common.FileExist(executionSpecStateTestDir) { + t.Skipf("directory %s does not exist", executionSpecStateTestDir) + } + st := new(testMatcher) + + // Emptiness of authorization list is only validated during the tx precheck + st.skipLoad("^prague/eip7702_set_code_tx/invalid_tx/empty_authorization_list.json") + + st.walk(t, executionSpecTransactionTestDir, func(t *testing.T, name string, test *TransactionTest) { + cfg := params.MainnetChainConfig + if err := st.checkFailure(t, test.Run(cfg)); err != nil { + t.Error(err) + } + }) +} diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 55b76df89..3f91a82ec 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -21,93 +21,120 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" ) // TransactionTest checks RLP decoding and sender derivation of transactions. type TransactionTest struct { Txbytes hexutil.Bytes `json:"txbytes"` - Result ttResult + Result map[string]*ttFork } -type ttResult struct { - Byzantium ttFork - Constantinople ttFork - Istanbul ttFork - EIP150 ttFork - EIP158 ttFork - Frontier ttFork - Homestead ttFork +type ttFork struct { + Sender *common.UnprefixedAddress `json:"sender"` + Hash *common.UnprefixedHash `json:"hash"` + Exception *string `json:"exception"` + IntrinsicGas math.HexOrDecimal64 `json:"intrinsicGas"` } -type ttFork struct { - Sender common.UnprefixedAddress `json:"sender"` - Hash common.UnprefixedHash `json:"hash"` +func (tt *TransactionTest) validate() error { + if tt.Txbytes == nil { + return fmt.Errorf("missing txbytes") + } + for name, fork := range tt.Result { + if err := tt.validateFork(fork); err != nil { + return fmt.Errorf("invalid %s: %v", name, err) + } + } + return nil +} + +func (tt *TransactionTest) validateFork(fork *ttFork) error { + if fork == nil { + return nil + } + if fork.Hash == nil && fork.Exception == nil { + return fmt.Errorf("missing hash and exception") + } + if fork.Hash != nil && fork.Sender == nil { + return fmt.Errorf("missing sender") + } + return nil } func (tt *TransactionTest) Run(config *params.ChainConfig) error { - validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool, isIstanbul bool) (*common.Address, *common.Hash, error) { + if err := tt.validate(); err != nil { + return err + } + validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead, isIstanbul, isShanghai bool) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { tx := new(types.Transaction) - if err := rlp.DecodeBytes(rlpData, tx); err != nil { - return nil, nil, err + if err = tx.UnmarshalBinary(rlpData); err != nil { + return } - sender, err := types.Sender(signer, tx) + sender, err = types.Sender(signer, tx) if err != nil { - return nil, nil, err + return } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) + requiredGas, err = core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, isShanghai) if err != nil { - return nil, nil, err + return } if requiredGas > tx.Gas() { - return nil, nil, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) + return sender, hash, 0, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) } - h := tx.Hash() - return &sender, &h, nil + hash = tx.Hash() + return sender, hash, requiredGas, nil } - for _, testcase := range []struct { name string signer types.Signer - fork ttFork + fork *ttFork isHomestead bool isIstanbul bool + isShanghai bool }{ - {"Frontier", types.FrontierSigner{}, tt.Result.Frontier, false, false}, - {"Homestead", types.HomesteadSigner{}, tt.Result.Homestead, true, false}, - {"EIP150", types.HomesteadSigner{}, tt.Result.EIP150, true, false}, - {"EIP158", types.NewEIP155Signer(config.ChainID), tt.Result.EIP158, true, false}, - {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Result.Byzantium, true, false}, - {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Result.Constantinople, true, false}, - {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Result.Istanbul, true, true}, + {"Frontier", types.FrontierSigner{}, tt.Result["Frontier"], false, false, false}, + {"Homestead", types.HomesteadSigner{}, tt.Result["Homestead"], true, false, false}, + {"EIP150", types.HomesteadSigner{}, tt.Result["EIP150"], true, false, false}, + {"EIP158", types.NewEIP155Signer(config.ChainID), tt.Result["EIP158"], true, false, false}, + {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Result["Byzantium"], true, false, false}, + {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Result["Constantinople"], true, false, false}, + {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Result["Istanbul"], true, true, false}, + {"Berlin", types.NewEIP2930Signer(config.ChainID), tt.Result["Berlin"], true, true, false}, + {"London", types.NewLondonSigner(config.ChainID), tt.Result["London"], true, true, false}, + {"Paris", types.NewLondonSigner(config.ChainID), tt.Result["Paris"], true, true, false}, + {"Shanghai", types.NewLondonSigner(config.ChainID), tt.Result["Shanghai"], true, true, true}, + {"Cancun", types.NewCancunSigner(config.ChainID), tt.Result["Cancun"], true, true, true}, + {"Prague", types.NewPragueSigner(config.ChainID), tt.Result["Prague"], true, true, true}, } { - sender, txhash, err := validateTx(tt.Txbytes, testcase.signer, testcase.isHomestead, testcase.isIstanbul) - - if testcase.fork.Sender == (common.UnprefixedAddress{}) { - if err == nil { - return fmt.Errorf("expected error, got none (address %v)[%v]", sender.String(), testcase.name) - } + if testcase.fork == nil { continue } - // Should resolve the right address + sender, hash, gas, err := validateTx(tt.Txbytes, testcase.signer, testcase.isHomestead, testcase.isIstanbul, testcase.isShanghai) if err != nil { - return fmt.Errorf("got error, expected none: %v", err) + if testcase.fork.Hash != nil { + return fmt.Errorf("unexpected error: %v", err) + } + continue + } + if testcase.fork.Exception != nil { + return fmt.Errorf("expected error %v, got none (%v)", *testcase.fork.Exception, err) } - if sender == nil { - return fmt.Errorf("sender was nil, should be %x", common.Address(testcase.fork.Sender)) + if common.Hash(*testcase.fork.Hash) != hash { + return fmt.Errorf("hash mismatch: got %x, want %x", hash, common.Hash(*testcase.fork.Hash)) } - if *sender != common.Address(testcase.fork.Sender) { + if common.Address(*testcase.fork.Sender) != sender { return fmt.Errorf("sender mismatch: got %x, want %x", sender, testcase.fork.Sender) } - if txhash == nil { - return fmt.Errorf("txhash was nil, should be %x", common.Hash(testcase.fork.Hash)) + if hash != common.Hash(*testcase.fork.Hash) { + return fmt.Errorf("hash mismatch: got %x, want %x", hash, testcase.fork.Hash) } - if *txhash != common.Hash(testcase.fork.Hash) { - return fmt.Errorf("hash mismatch: got %x, want %x", *txhash, testcase.fork.Hash) + if uint64(testcase.fork.IntrinsicGas) != gas { + return fmt.Errorf("intrinsic gas mismatch: got %d, want %d", gas, uint64(testcase.fork.IntrinsicGas)) } } return nil From 50c6b4a2428c13211b056a2ae0cec9f63f3c5a45 Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Fri, 8 Aug 2025 18:14:13 +0800 Subject: [PATCH 129/354] docker: fix the ip resolution error --- .docker/docker-compose-four.yml | 15 +++++++++------ .docker/docker-compose-seven.yml | 21 ++++++++++++--------- .docker/docker-compose.yml | 9 ++++++--- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.docker/docker-compose-four.yml b/.docker/docker-compose-four.yml index 7e86007f4..857494d1e 100644 --- a/.docker/docker-compose-four.yml +++ b/.docker/docker-compose-four.yml @@ -20,6 +20,9 @@ services: - ../privnet:/privnet ports: - 30304:30304 + networks: + default: + ipv4_address: 172.200.0.1 miner0: image: neox_node container_name: miner0 @@ -32,7 +35,7 @@ services: geth init --datadir ${FOUR_NODE0_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE0_DIR} \ --port 30305 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE0_DIR}/node_address.txt)" \ --authrpc.port 8551 \ @@ -73,7 +76,7 @@ services: geth init --datadir ${FOUR_NODE1_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE1_DIR} \ --port 30306 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE1_DIR}/node_address.txt)" \ --authrpc.port 8552 \ @@ -114,7 +117,7 @@ services: geth init --datadir ${FOUR_NODE2_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE2_DIR} \ --port 30307 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE2_DIR}/node_address.txt)" \ --authrpc.port 8553 \ @@ -155,7 +158,7 @@ services: geth init --datadir ${FOUR_NODE3_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE3_DIR} \ --port 30308 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE3_DIR}/node_address.txt)" \ --authrpc.port 8554 \ @@ -196,7 +199,7 @@ services: geth init --datadir ${FOUR_NODE4_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE4_DIR} \ --port 30309 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE4_DIR}/node_address.txt)" \ --authrpc.port 8555 \ @@ -237,7 +240,7 @@ services: geth init --datadir ${FOUR_NODE5_DIR} ${FOUR_DIR}/genesis_privnet.json geth --datadir ${FOUR_NODE5_DIR} \ --port 30310 \ - --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${FOUR_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${FOUR_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${FOUR_NODE5_DIR}/node_address.txt)" \ --authrpc.port 8556 \ diff --git a/.docker/docker-compose-seven.yml b/.docker/docker-compose-seven.yml index ba4b36b8e..61c5a7a37 100644 --- a/.docker/docker-compose-seven.yml +++ b/.docker/docker-compose-seven.yml @@ -20,6 +20,9 @@ services: - ../privnet:/privnet ports: - 30304:30304 + networks: + default: + ipv4_address: 172.200.0.1 miner0: image: neox_node container_name: miner0 @@ -32,7 +35,7 @@ services: geth init --datadir ${SEVEN_NODE0_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE0_DIR} \ --port 30305 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE0_DIR}/node_address.txt)" \ --authrpc.port 8551 \ @@ -73,7 +76,7 @@ services: geth init --datadir ${SEVEN_NODE1_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE1_DIR} \ --port 30306 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE1_DIR}/node_address.txt)" \ --authrpc.port 8552 \ @@ -114,7 +117,7 @@ services: geth init --datadir ${SEVEN_NODE2_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE2_DIR} \ --port 30307 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE2_DIR}/node_address.txt)" \ --authrpc.port 8553 \ @@ -155,7 +158,7 @@ services: geth init --datadir ${SEVEN_NODE3_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE3_DIR} \ --port 30308 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE3_DIR}/node_address.txt)" \ --authrpc.port 8554 \ @@ -196,7 +199,7 @@ services: geth init --datadir ${SEVEN_NODE4_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE4_DIR} \ --port 30309 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE4_DIR}/node_address.txt)" \ --authrpc.port 8555 \ @@ -237,7 +240,7 @@ services: geth init --datadir ${SEVEN_NODE5_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE5_DIR} \ --port 30310 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE5_DIR}/node_address.txt)" \ --authrpc.port 8556 \ @@ -278,7 +281,7 @@ services: geth init --datadir ${SEVEN_NODE6_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE6_DIR} \ --port 30311 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE6_DIR}/node_address.txt)" \ --authrpc.port 8557 \ @@ -319,7 +322,7 @@ services: geth init --datadir ${SEVEN_NODE7_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE7_DIR} \ --port 30312 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE7_DIR}/node_address.txt)" \ --authrpc.port 8558 \ @@ -360,7 +363,7 @@ services: geth init --datadir ${SEVEN_NODE8_DIR} ${SEVEN_DIR}/genesis_privnet.json geth --datadir ${SEVEN_NODE8_DIR} \ --port 30313 \ - --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SEVEN_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SEVEN_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SEVEN_NODE8_DIR}/node_address.txt)" \ --authrpc.port 8559 \ diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 67bfeab91..d62a0b5c5 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -20,6 +20,9 @@ services: - ../privnet:/privnet ports: - 30304:30304 + networks: + default: + ipv4_address: 172.200.0.1 miner0: image: neox_node container_name: miner0 @@ -32,7 +35,7 @@ services: geth init --datadir ${SINGLE_NODE0_DIR} ${SINGLE_DIR}/genesis_privnet.json geth --datadir ${SINGLE_NODE0_DIR} \ --port 30305 \ - --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SINGLE_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SINGLE_NODE0_DIR}/node_address.txt)" \ --authrpc.port 8551 \ @@ -73,7 +76,7 @@ services: geth init --datadir ${SINGLE_NODE1_DIR} ${SINGLE_DIR}/genesis_privnet.json geth --datadir ${SINGLE_NODE1_DIR} \ --port 30306 \ - --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SINGLE_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SINGLE_NODE1_DIR}/node_address.txt)" \ --authrpc.port 8552 \ @@ -114,7 +117,7 @@ services: geth init --datadir ${SINGLE_NODE2_DIR} ${SINGLE_DIR}/genesis_privnet.json geth --datadir ${SINGLE_NODE2_DIR} \ --port 30307 \ - --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@bootnode:0?discport=30304" \ + --bootnodes "enode://$$(cat ${SINGLE_DIR}/bootnode/bootnode_address.txt)@172.200.0.1:0?discport=30304" \ --networkid "$$(cat ${SINGLE_DIR}/networkid.txt)" \ --unlock 0x"$$(cat ${SINGLE_NODE2_DIR}/node_address.txt)" \ --authrpc.port 8553 \ From cef8a6b26f4b24f48f25fc533231326e5e3f9c8b Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Tue, 19 Aug 2025 14:09:59 +0800 Subject: [PATCH 130/354] dbft: fix VerifyEIP4844Header function --- consensus/dbft/dbft.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index 529a86f88..a0f1a1903 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -1846,7 +1846,7 @@ func (c *DBFT) verifyCascadingFields(chain consensus.ChainHeaderReader, header * case header.ParentBeaconRoot != nil: return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot) } - } else if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { + } else if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil { // Verify cancun-specific header fields return err } From c0b80669e7fe043f66721cd654479eccc32bfcc9 Mon Sep 17 00:00:00 2001 From: Marcin Sobczak <77129288+marcindsobczak@users.noreply.github.com> Date: Fri, 7 Feb 2025 02:59:12 +0100 Subject: [PATCH 131/354] cmd/devp2p/internal/ethtest: remove TD from status validation (#31137) After recent changes in Geth (removing TD): https://github.com/ethereum/go-ethereum/commit/39638c81c56db2b2dfe6f51999ffd3029ee212cb#diff-d70a44d4b7a0e84fe9dcca25d368f626ae6c9bc0b8fe9690074ba92d298bcc0d Non-Geth clients are failing many devp2p tests with an error: `peering failed: status exchange failed: wrong TD in status: have 1 want 0` Right now only Geth is passing it - all other clients are affected by this change. I think there should be no validation of TD when checking `Status` message in hive tests. Now Geth has 0 (and hive tests requires 0) and all other clients have actual TD. And on real networks there is no validation of TD when peering --- cmd/devp2p/internal/ethtest/conn.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/conn.go b/cmd/devp2p/internal/ethtest/conn.go index 757b137aa..b555b1478 100644 --- a/cmd/devp2p/internal/ethtest/conn.go +++ b/cmd/devp2p/internal/ethtest/conn.go @@ -316,9 +316,6 @@ loop: return fmt.Errorf("wrong head block in status, want: %#x (block %d) have %#x", want, chain.blocks[chain.Len()-1].NumberU64(), have) } - if have, want := msg.TD.Cmp(chain.TD()), 0; have != want { - return fmt.Errorf("wrong TD in status: have %v want %v", have, want) - } if have, want := msg.ForkID, chain.ForkID(); !reflect.DeepEqual(have, want) { return fmt.Errorf("wrong fork ID in status: have %v, want %v", have, want) } From d6575cbe1720d6770f9078acf419a34f621326d2 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Sat, 8 Feb 2025 05:26:15 -0700 Subject: [PATCH 132/354] params,core/forkid: enable prague on holesky and sepolia (#31139) Agreed to the following fork dates for Holesky and Sepolia on ACDC 150 Holesky slot: 3710976 (Mon, Feb 24 at 21:55:12 UTC) Sepolia slot: 7118848 (Wed, Mar 5 at 07:29:36 UTC) --- core/forkid/forkid_test.go | 12 ++++++++---- params/config.go | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index de589c0d4..bebc20ad9 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -91,8 +91,10 @@ func TestCreation(t *testing.T) { {1735372, 1677557087, ID{Hash: checksumToBytes(0xb96cbd13), Next: 1677557088}}, // Last MergeNetsplit block {1735372, 1677557088, ID{Hash: checksumToBytes(0xf7f9bc08), Next: 1706655072}}, // First Shanghai block {1735372, 1706655071, ID{Hash: checksumToBytes(0xf7f9bc08), Next: 1706655072}}, // Last Shanghai block - {1735372, 1706655072, ID{Hash: checksumToBytes(0x88cf81d9), Next: 0}}, // First Cancun block - {1735372, 2706655072, ID{Hash: checksumToBytes(0x88cf81d9), Next: 0}}, // Future Cancun block + {1735372, 1706655072, ID{Hash: checksumToBytes(0x88cf81d9), Next: 1741159776}}, // First Cancun block + {1735372, 1741159775, ID{Hash: checksumToBytes(0x88cf81d9), Next: 1741159776}}, // Last Cancun block + {1735372, 1741159776, ID{Hash: checksumToBytes(0xed88b5fd), Next: 0}}, // First Prague block + {1735372, 2741159776, ID{Hash: checksumToBytes(0xed88b5fd), Next: 0}}, // Future Prague block }, }, // Holesky test cases @@ -104,8 +106,10 @@ func TestCreation(t *testing.T) { {123, 0, ID{Hash: checksumToBytes(0xc61a6098), Next: 1696000704}}, // First MergeNetsplit block {123, 1696000704, ID{Hash: checksumToBytes(0xfd4f016b), Next: 1707305664}}, // First Shanghai block {123, 1707305663, ID{Hash: checksumToBytes(0xfd4f016b), Next: 1707305664}}, // Last Shanghai block - {123, 1707305664, ID{Hash: checksumToBytes(0x9b192ad0), Next: 0}}, // First Cancun block - {123, 2707305664, ID{Hash: checksumToBytes(0x9b192ad0), Next: 0}}, // Future Cancun block + {123, 1707305664, ID{Hash: checksumToBytes(0x9b192ad0), Next: 1740434112}}, // First Cancun block + {123, 1740434111, ID{Hash: checksumToBytes(0x9b192ad0), Next: 1740434112}}, // Last Cancun block + {123, 1740434112, ID{Hash: checksumToBytes(0xdfbd9bed), Next: 0}}, // First Prague block + {123, 2740434112, ID{Hash: checksumToBytes(0xdfbd9bed), Next: 0}}, // Future Prague block }, }, } diff --git a/params/config.go b/params/config.go index 84ae987de..dc9b8a6ee 100644 --- a/params/config.go +++ b/params/config.go @@ -87,9 +87,11 @@ var ( MergeNetsplitBlock: nil, ShanghaiTime: newUint64(1696000704), CancunTime: newUint64(1707305664), + PragueTime: newUint64(1740434112), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, }, } // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. @@ -114,9 +116,11 @@ var ( MergeNetsplitBlock: big.NewInt(1735371), ShanghaiTime: newUint64(1677557088), CancunTime: newUint64(1706655072), + PragueTime: newUint64(1741159776), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, }, } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced From 226020bfb0299b88a3b44315d443cbd7cf5d49d2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 11 Feb 2025 13:44:25 +0100 Subject: [PATCH 133/354] consensus/beacon: remove TestingTTDBlock (#31153) This removes the method `TestingTTDBlock` introduced by #30744. It was added to make the beacon consensus engine aware of the merge block in tests without relying on the total difficulty. However, tracking the merge block this way is very annoying. We usually configure forks in the `ChainConfig`, but the method is on the consensus engine, which isn't always created in the same place. By sidestepping the `ChainConfig` we don't get the usual fork-order checking, so it's possible to enable the merge before the London fork, for example. This in turn can lead to very hard-to-debug outputs and validation errors. So here I'm changing the consensus engine to check the `MergeNetsplitBlock` instead. Alternatively, we assume a network is merged if it has a `TerminalTotalDifficulty` of zero, which is a very common configuration in tests. --- consensus/beacon/consensus.go | 39 +++++-------------- eth/catalyst/api_test.go | 5 ++- eth/gasprice/gasprice_test.go | 6 ++- eth/protocols/eth/handler_test.go | 4 +- eth/tracers/internal/tracetest/supply_test.go | 1 - graphql/graphql_test.go | 7 +--- 6 files changed, 20 insertions(+), 42 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 1c614bdbc..5199fd845 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -61,8 +61,7 @@ var ( // is only used for necessary consensus checks. The legacy consensus engine can be any // engine implements the consensus interface (except the beacon itself). type Beacon struct { - ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique - ttdblock *uint64 // Merge block-number for testchain generation without TTDs + ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique } // New creates a consensus engine with the given embedded eth1 engine. @@ -73,16 +72,12 @@ func New(ethone consensus.Engine) *Beacon { return &Beacon{ethone: ethone} } -// TestingTTDBlock is a replacement mechanism for TTD-based pre-/post-merge -// splitting. With chain history deletion, TD calculations become impossible. -// This is fine for progressing the live chain, but to be able to generate test -// chains, we do need a split point. This method supports setting an explicit -// block number to use as the splitter *for testing*, instead of having to keep -// the notion of TDs in the client just for testing. -// -// The block with supplied number is regarded as the last pre-merge block. -func (beacon *Beacon) TestingTTDBlock(number uint64) { - beacon.ttdblock = &number +// isPostMerge reports whether the given block number is assumed to be post-merge. +// Here we check the MergeNetsplitBlock to allow configuring networks with a PoW or +// PoA chain for unit testing purposes. +func isPostMerge(config *params.ChainConfig, block uint64) bool { + mergedAtGenesis := config.TerminalTotalDifficulty != nil && config.TerminalTotalDifficulty.Sign() == 0 + return mergedAtGenesis || config.MergeNetsplitBlock != nil && block >= config.MergeNetsplitBlock.Uint64() } // Author implements consensus.Engine, returning the verified author of the block. @@ -347,15 +342,7 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [ // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the beacon protocol. The changes are done inline. func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { - // The beacon engine requires access to total difficulties to be able to - // seal pre-merge and post-merge blocks. With the transition to removing - // old blocks, TDs become unaccessible, thus making TTD based pre-/post- - // merge decisions impossible. - // - // We do not need to seal non-merge blocks anymore live, but we do need - // to be able to generate test chains, thus we're reverting to a testing- - // settable field to direct that. - if beacon.ttdblock != nil && *beacon.ttdblock >= header.Number.Uint64() { + if !isPostMerge(chain.Config(), header.Number.Uint64()) { return beacon.ethone.Prepare(chain, header) } header.Difficulty = beaconDifficulty @@ -465,15 +452,7 @@ func (beacon *Beacon) SealHash(header *types.Header) common.Hash { // the difficulty that a new block should have when created at time // given the parent block's time and difficulty. func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { - // The beacon engine requires access to total difficulties to be able to - // seal pre-merge and post-merge blocks. With the transition to removing - // old blocks, TDs become unaccessible, thus making TTD based pre-/post- - // merge decisions impossible. - // - // We do not need to seal non-merge blocks anymore live, but we do need - // to be able to generate test chains, thus we're reverting to a testing- - // settable field to direct that. - if beacon.ttdblock != nil && *beacon.ttdblock > parent.Number.Uint64() { + if !isPostMerge(chain.Config(), parent.Number.Uint64()+1) { return beacon.ethone.CalcDifficulty(chain, time, parent) } return beaconDifficulty diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index e5ac1cdc6..3a0f5652b 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -65,9 +65,12 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { engine := beacon.New(ethash.NewFaker()) if merged { config.TerminalTotalDifficulty = common.Big0 + config.MergeNetsplitBlock = common.Big0 } else { - engine.TestingTTDBlock(uint64(n)) + // When !merged, the tests expect the next block after the generated chain to be in PoS. + config.MergeNetsplitBlock = big.NewInt(int64(n + 1)) } + genesis := &core.Genesis{ Config: &config, Alloc: types.GenesisAlloc{ diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index d32ab62f4..c3edfa0a1 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -147,9 +147,11 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe config.LondonBlock = londonBlock config.ArrowGlacierBlock = londonBlock config.GrayGlacierBlock = londonBlock - + if cancunBlock != nil { + // Enable the merge with cancun fork. + config.MergeNetsplitBlock = cancunBlock + } engine := beacon.New(ethash.NewFaker()) - engine.TestingTTDBlock(testHead + 1) td := params.GenesisDifficulty.Uint64() diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 22fdb51f1..1c1b3a24a 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -74,9 +74,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, config = params.TestChainConfig engine = beacon.New(ethash.NewFaker()) ) - if !shanghai { - engine.TestingTTDBlock(math.MaxUint64) - } else { + if shanghai { config = ¶ms.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 0ea35cb1a..f009b2059 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -546,7 +546,6 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) { func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { engine := beacon.New(ethash.NewFaker()) - engine.TestingTTDBlock(1) traceOutputPath := filepath.ToSlash(t.TempDir()) traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl") diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 3e6a042db..0f6ba10b9 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -21,7 +21,6 @@ import ( "encoding/json" "fmt" "io" - "math" "math/big" "net/http" "strings" @@ -459,15 +458,13 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge var engine = beacon.New(ethash.NewFaker()) if shanghai { gspec.Config.TerminalTotalDifficulty = common.Big0 + gspec.Config.MergeNetsplitBlock = common.Big0 // GenerateChain will increment timestamps by 10. // Shanghai upgrade at block 1. shanghaiTime := uint64(5) gspec.Config.ShanghaiTime = &shanghaiTime - } else { - // set an arbitrary large ttd as chains are required to be known to be merged - gspec.Config.TerminalTotalDifficulty = big.NewInt(math.MaxInt64) - engine.TestingTTDBlock(math.MaxUint64) } + ethBackend, err := eth.New(stack, ethConf) if err != nil { t.Fatalf("could not create eth backend: %v", err) From 766c84e03a0aef418b95845bc25686db69d953ed Mon Sep 17 00:00:00 2001 From: Harry Ngo <17699212+huyngopt1994@users.noreply.github.com> Date: Tue, 11 Feb 2025 19:45:44 +0700 Subject: [PATCH 134/354] p2p/discover: remove unused parameter in revalidationList.get (#31155) --- p2p/discover/table_reval.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 2465fee90..1519313d1 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -79,7 +79,7 @@ func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *tableNode) { func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { reval := func(list *revalidationList) { if list.nextTime <= now { - if n := list.get(now, &tab.rand, tr.activeReq); n != nil { + if n := list.get(&tab.rand, tr.activeReq); n != nil { tr.startRequest(tab, n) } // Update nextTime regardless if any requests were started because @@ -203,7 +203,7 @@ type revalidationList struct { } // get returns a random node from the queue. Nodes in the 'exclude' map are not returned. -func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode { +func (list *revalidationList) get(rand randomSource, exclude map[enode.ID]struct{}) *tableNode { if len(list.nodes) == 0 { return nil } From 9001447ac24ff3789151d7e9f8752a2759cd7497 Mon Sep 17 00:00:00 2001 From: Chen Kai <281165273grape@gmail.com> Date: Tue, 11 Feb 2025 20:52:43 +0800 Subject: [PATCH 135/354] p2p/discover: make discv5 response timeout configurable (#31119) --- p2p/discover/common.go | 8 ++++++-- p2p/discover/v5_udp.go | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/p2p/discover/common.go b/p2p/discover/common.go index cabc5c796..767cc23b9 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -49,8 +49,9 @@ type Config struct { // All remaining settings are optional. // Packet handling configuration: - NetRestrict *netutil.Netlist // list of allowed IP networks - Unhandled chan<- ReadPacket // unhandled packets are sent on this channel + NetRestrict *netutil.Netlist // list of allowed IP networks + Unhandled chan<- ReadPacket // unhandled packets are sent on this channel + V5RespTimeout time.Duration // timeout for v5 queries // Node table configuration: Bootnodes []*enode.Node // list of bootstrap nodes @@ -73,6 +74,9 @@ func (cfg Config) withDefaults() Config { if cfg.RefreshInterval == 0 { cfg.RefreshInterval = 30 * time.Minute } + if cfg.V5RespTimeout == 0 { + cfg.V5RespTimeout = 700 * time.Millisecond + } // Debug/test settings: if cfg.Log == nil { diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 4453d1069..48256ea4d 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -42,8 +42,6 @@ const ( lookupRequestLimit = 3 // max requests against a single node during lookup findnodeResultLimit = 16 // applies in FINDNODE handler totalNodesResponseLimit = 5 // applies in waitForNodes - - respTimeoutV5 = 700 * time.Millisecond ) // codecV5 is implemented by v5wire.Codec (and testCodec). @@ -71,6 +69,7 @@ type UDPv5 struct { log log.Logger clock mclock.Clock validSchemes enr.IdentityScheme + respTimeout time.Duration // misc buffers used during message handling logcontext []interface{} @@ -158,6 +157,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { log: cfg.Log, validSchemes: cfg.ValidSchemes, clock: cfg.Clock, + respTimeout: cfg.V5RespTimeout, // channels into dispatch packetInCh: make(chan ReadPacket, 1), readNextCh: make(chan struct{}, 1), @@ -576,7 +576,7 @@ func (t *UDPv5) startResponseTimeout(c *callV5) { timer mclock.Timer done = make(chan struct{}) ) - timer = t.clock.AfterFunc(respTimeoutV5, func() { + timer = t.clock.AfterFunc(t.respTimeout, func() { <-done select { case t.respTimeoutCh <- &callTimeout{c, timer}: From c20d592ae68727b11a4ee4572e6163afb96b7b7c Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:15:04 -0700 Subject: [PATCH 136/354] core/txpool/legacypool: add support for SetCode transactions (#31073) The new SetCode transaction type introduces some additional complexity when handling the transaction pool. This complexity stems from two new account behaviors: 1. The balance and nonce of an account can change during regular transaction execution *when they have a deployed delegation*. 2. The nonce and code of an account can change without any EVM execution at all. This is the "set code" mechanism introduced by EIP-7702. The first issue has already been considered extensively during the design of ERC-4337, and we're relatively confident in the solution of simply limiting the number of in-flight pending transactions an account can have to one. This puts a reasonable bound on transaction cancellation. Normally to cancel, you would need to spend 21,000 gas. Now it's possible to cancel for around the cost of warming the account and sending value (`2,600+9,000=11,600`). So 50% cheaper. The second issue is more novel and needs further consideration. Since authorizations are not bound to a specific transaction, we cannot drop transactions with conflicting authorizations. Otherwise, it might be possible to cherry-pick authorizations from txs and front run them with different txs at much lower fee amounts, effectively DoSing the authority. Fortunately, conflicting authorizations do not affect the underlying validity of the transaction so we can just accept both. --------- Co-authored-by: Marius van der Wijden Co-authored-by: Felix Lange --- core/txpool/blobpool/blobpool_test.go | 6 +- core/txpool/errors.go | 9 + core/txpool/legacypool/legacypool.go | 89 +++++++- core/txpool/legacypool/legacypool_test.go | 234 +++++++++++++++++++++- core/txpool/validation.go | 32 ++- core/types/transaction.go | 15 ++ 6 files changed, 368 insertions(+), 17 deletions(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index f7c9e4844..8589e5c01 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -142,6 +142,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { GasLimit: gasLimit, BaseFee: baseFee, ExcessBlobGas: &excessBlobGas, + Difficulty: common.Big0, } } @@ -1565,8 +1566,9 @@ func TestAdd(t *testing.T) { if tt.block != nil { // Fake a header for the new set of transactions header := &types.Header{ - Number: big.NewInt(int64(chain.CurrentBlock().Number.Uint64() + 1)), - BaseFee: chain.CurrentBlock().BaseFee, // invalid, but nothing checks it, yolo + Number: big.NewInt(int64(chain.CurrentBlock().Number.Uint64() + 1)), + Difficulty: common.Big0, + BaseFee: chain.CurrentBlock().BaseFee, // invalid, but nothing checks it, yolo } // Inject the fake block into the chain txs := make([]*types.Transaction, len(tt.block)) diff --git a/core/txpool/errors.go b/core/txpool/errors.go index 05cbc1872..a6c0e38f9 100644 --- a/core/txpool/errors.go +++ b/core/txpool/errors.go @@ -67,4 +67,13 @@ var ( // input transaction of non-blob type when a blob transaction from this sender // remains pending (and vice-versa). ErrAlreadyReserved = errors.New("address already reserved") + + // ErrAuthorityReserved is returned if a transaction has an authorization + // signed by an address which already has in-flight transactions known to the + // pool. + ErrAuthorityReserved = errors.New("authority already reserved") + + // ErrAuthorityNonce is returned if a transaction has an authorization with + // a nonce that is not currently valid for the authority. + ErrAuthorityNonceTooLow = errors.New("authority nonce too low") ) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index af43dc977..2d3a1048c 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -22,6 +22,7 @@ import ( "fmt" "math" "math/big" + "slices" "sort" "sync" "sync/atomic" @@ -218,6 +219,20 @@ func (config *Config) sanitize() Config { // The pool separates processable transactions (which can be applied to the // current state) and future transactions. Transactions move between those // two states over time as they are received and processed. +// +// In addition to tracking transactions, the pool also tracks a set of pending SetCode +// authorizations (EIP7702). This helps minimize number of transactions that can be +// trivially churned in the pool. As a standard rule, any account with a deployed +// delegation or an in-flight authorization to deploy a delegation will only be allowed a +// single transaction slot instead of the standard number. This is due to the possibility +// of the account being sweeped by an unrelated account. +// +// Because SetCode transactions can have many authorizations included, we avoid explicitly +// checking their validity to save the state lookup. So long as the encompassing +// transaction is valid, the authorization will be accepted and tracked by the pool. In +// case the pool is tracking a pending / queued transaction from a specific account, it +// will reject new transactions with delegations from that account with standard in-flight +// transactions. type LegacyPool struct { config Config chainconfig *params.ChainConfig @@ -290,7 +305,7 @@ func NewStatic(config Config, chain BlockChain) *LegacyPool { // pool, specifically, whether it is a Legacy, AccessList or Dynamic transaction. func (pool *LegacyPool) Filter(tx *types.Transaction) bool { switch tx.Type() { - case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType: + case types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType, types.SetCodeTxType: return true default: return false @@ -661,7 +676,8 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error { Accept: 0 | 1<= 0 { + list = append(list[:i], list[i+1:]...) + } else { + log.Error("Authority with untracked tx", "addr", addr, "hash", hash) + } + if len(list) == 0 { + // If list is newly empty, delete it entirely. + delete(t.auths, addr) + continue + } + t.auths[addr] = list + } +} + // numSlots calculates the number of slots needed for a single transaction. func numSlots(tx *types.Transaction) int { return int((tx.Size() + txSlotSize - 1) / txSlotSize) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index fdbcad3d4..da28e8a75 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -79,8 +80,9 @@ func (bc *testBlockChain) Config() *params.ChainConfig { func (bc *testBlockChain) CurrentBlock() *types.Header { return &types.Header{ - Number: new(big.Int), - GasLimit: bc.gasLimit.Load(), + Number: new(big.Int), + Difficulty: common.Big0, + GasLimit: bc.gasLimit.Load(), } } @@ -128,6 +130,39 @@ func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, return tx } +type unsignedAuth struct { + nonce uint64 + key *ecdsa.PrivateKey +} + +func setCodeTx(nonce uint64, key *ecdsa.PrivateKey, unsigned []unsignedAuth) *types.Transaction { + return pricedSetCodeTx(nonce, 250000, uint256.NewInt(1000), uint256.NewInt(1), key, unsigned) +} + +func pricedSetCodeTx(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, unsigned []unsignedAuth) *types.Transaction { + var authList []types.SetCodeAuthorization + for _, u := range unsigned { + auth, _ := types.SignSetCode(u.key, types.SetCodeAuthorization{ + ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), + Address: common.Address{0x42}, + Nonce: u.nonce, + }) + authList = append(authList, auth) + } + return types.MustSignNewTx(key, types.LatestSignerForChainID(params.TestChainConfig.ChainID), &types.SetCodeTx{ + ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID), + Nonce: nonce, + GasTipCap: tip, + GasFeeCap: gasFee, + Gas: gaslimit, + To: common.Address{}, + Value: uint256.NewInt(100), + Data: nil, + AccessList: nil, + AuthList: authList, + }) +} + func makeAddressReserver() txpool.AddressReserver { var ( reserved = make(map[common.Address]struct{}) @@ -2163,6 +2198,201 @@ func TestSlotCount(t *testing.T) { } } +// TestSetCodeTransactions tests a few scenarios regarding the EIP-7702 +// SetCodeTx. +func TestSetCodeTransactions(t *testing.T) { + t.Parallel() + + // Create the pool to test the status retrievals with + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) + + pool := New(testTxPoolConfig, blockchain) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() + + // Create the test accounts + var ( + keyA, _ = crypto.GenerateKey() + keyB, _ = crypto.GenerateKey() + keyC, _ = crypto.GenerateKey() + addrA = crypto.PubkeyToAddress(keyA.PublicKey) + addrB = crypto.PubkeyToAddress(keyB.PublicKey) + addrC = crypto.PubkeyToAddress(keyC.PublicKey) + ) + testAddBalance(pool, addrA, big.NewInt(params.Ether)) + testAddBalance(pool, addrB, big.NewInt(params.Ether)) + testAddBalance(pool, addrC, big.NewInt(params.Ether)) + + for _, tt := range []struct { + name string + pending int + queued int + run func(string) + }{ + { + // Check that only one in-flight transaction is allowed for accounts + // with delegation set. Also verify the accepted transaction can be + // replaced by fee. + name: "only-one-in-flight", + pending: 1, + run: func(name string) { + aa := common.Address{0xaa, 0xaa} + statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...)) + statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)}) + // Send transactions. First is accepted, second is rejected. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { + t.Fatalf("%s: failed to add remote transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + } + // Also check gapped transaction. + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + } + // Replace by fee. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + }, + }, + { + name: "allow-setcode-tx-with-pending-authority-tx", + pending: 2, + run: func(name string) { + // Send two transactions where the first has no conflicting delegations and + // the second should be allowed despite conflicting with the authorities in 1). + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { + t.Fatalf("%s: failed to add conflicting delegation: %v", name, err) + } + }, + }, + { + name: "allow-one-tx-from-pooled-delegation", + pending: 2, + run: func(name string) { + // Verify C cannot originate another transaction when it has a pooled delegation. + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyC)); err != nil { + t.Fatalf("%s: failed to add with pending delegatio: %v", name, err) + } + // Also check gapped transaction is rejected. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + } + }, + }, + { + name: "replace-by-fee-setcode-tx", + pending: 1, + run: func(name string) { + // 4. Fee bump the setcode tx send. + if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(2000), uint256.NewInt(2), keyB, []unsignedAuth{{0, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + }, + }, + { + name: "allow-tx-from-replaced-authority", + pending: 2, + run: func(name string) { + // Fee bump with a different auth list. Make sure that unlocks the authorities. + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(3000), uint256.NewInt(300), keyA, []unsignedAuth{{0, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + // Now send a regular tx from B. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyB)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + }, + }, + { + name: "allow-tx-from-replaced-self-sponsor-authority", + pending: 2, + run: func(name string) { + // + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyA}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyA, []unsignedAuth{{0, keyB}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + // Now send a regular tx from keyA. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyA)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + // Make sure we can still send from keyB. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyB)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + }, + }, + { + name: "track-multiple-conflicting-delegations", + pending: 3, + run: func(name string) { + // Send two setcode txs both with C as an authority. + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyB, []unsignedAuth{{0, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + // Replace the tx from A with a non-setcode tx. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyA)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + // Make sure we can only pool one tx from keyC since it is still a + // pending authority. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { + t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err) + } + if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrAccountLimitExceeded; !errors.Is(err, want) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) + } + }, + }, + { + name: "reject-delegation-from-pending-account", + pending: 1, + run: func(name string) { + // Attempt to submit a delegation from an account with a pending tx. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err, want := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})), txpool.ErrAuthorityReserved; !errors.Is(err, want) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) + } + }, + }, + } { + tt.run(tt.name) + pending, queued := pool.Stats() + if pending != tt.pending { + t.Fatalf("%s: pending transactions mismatched: have %d, want %d", tt.name, pending, tt.pending) + } + if queued != tt.queued { + t.Fatalf("%s: queued transactions mismatched: have %d, want %d", tt.name, queued, tt.queued) + } + if err := validatePoolInternals(pool); err != nil { + t.Fatalf("%s: pool internal state corrupted: %v", tt.name, err) + } + pool.Clear() + } +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index ac1f06bcd..e7f42586f 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -72,17 +72,21 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return fmt.Errorf("%w: transaction size %v, limit %v", ErrOversizedData, tx.Size(), opts.MaxSize) } // Ensure only transactions that have been enabled are accepted - if !opts.Config.IsBerlin(head.Number) && tx.Type() != types.LegacyTxType { + rules := opts.Config.Rules(head.Number, head.Difficulty.Sign() == 0, head.Time) + if !rules.IsBerlin && tx.Type() != types.LegacyTxType { return fmt.Errorf("%w: type %d rejected, pool not yet in Berlin", core.ErrTxTypeNotSupported, tx.Type()) } - if !opts.Config.IsLondon(head.Number) && tx.Type() == types.DynamicFeeTxType { + if !rules.IsLondon && tx.Type() == types.DynamicFeeTxType { return fmt.Errorf("%w: type %d rejected, pool not yet in London", core.ErrTxTypeNotSupported, tx.Type()) } - if !opts.Config.IsCancun(head.Number, head.Time) && tx.Type() == types.BlobTxType { + if !rules.IsCancun && tx.Type() == types.BlobTxType { return fmt.Errorf("%w: type %d rejected, pool not yet in Cancun", core.ErrTxTypeNotSupported, tx.Type()) } + if !rules.IsPrague && tx.Type() == types.SetCodeTxType { + return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type()) + } // Check whether the init code size has been exceeded - if opts.Config.IsShanghai(head.Number, head.Time) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) } // Transactions can't be negative. This may never happen using RLP decoded @@ -111,7 +115,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, rules.IsIstanbul, rules.IsShanghai) if err != nil { return err } @@ -156,6 +160,11 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return err } } + if tx.Type() == types.SetCodeTxType { + if len(tx.SetCodeAuthorizations()) == 0 { + return fmt.Errorf("set code tx must have at least one authorization tuple") + } + } return nil } @@ -211,6 +220,11 @@ type ValidationOptionsWithState struct { // ExistingCost is a mandatory callback to retrieve an already pooled // transaction's cost with the given nonce to check for overdrafts. ExistingCost func(addr common.Address, nonce uint64) *big.Int + + // KnownConflicts is an optional callback which iterates over the list of + // addresses and returns all addresses known to the pool with in-flight + // transactions. + KnownConflicts func(sender common.Address, authorizers []common.Address) []common.Address } // ValidateTransactionWithState is a helper method to check whether a transaction @@ -302,6 +316,14 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op if used, left := opts.UsedAndLeftSlots(from); left <= 0 { return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used) } + + // Verify no authorizations will invalidate existing transactions known to + // the pool. + if opts.KnownConflicts != nil { + if conflicts := opts.KnownConflicts(from, tx.SetCodeAuthorities()); len(conflicts) > 0 { + return fmt.Errorf("%w: authorization conflicts with other known tx", ErrAuthorityReserved) + } + } } return nil } diff --git a/core/types/transaction.go b/core/types/transaction.go index 35dc1ea3f..7df13e04b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -483,6 +483,21 @@ func (tx *Transaction) SetCodeAuthorizations() []SetCodeAuthorization { return setcodetx.AuthList } +// SetCodeAuthorities returns a list of each authorization's corresponding authority. +func (tx *Transaction) SetCodeAuthorities() []common.Address { + setcodetx, ok := tx.inner.(*SetCodeTx) + if !ok { + return nil + } + auths := make([]common.Address, 0, len(setcodetx.AuthList)) + for _, auth := range setcodetx.AuthList { + if addr, err := auth.Authority(); err == nil { + auths = append(auths, addr) + } + } + return auths +} + // SetTime sets the decoding time of a transaction. This is used by tests to set // arbitrary times and by persistent transaction pools when loading old txs from // disk. From e2295aa6d88aa5453bc486aa19b99cca6f44fb01 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:02:30 +0100 Subject: [PATCH 137/354] internal/ethapi: fix panic in debug methods (#31157) Fixes an error when the block is not found in debug methods. --- internal/ethapi/api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 62e7f0e60..2a21ca051 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1826,7 +1826,7 @@ func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNu hash = h } else { block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) - if err != nil { + if block == nil || err != nil { return nil, err } hash = block.Hash() @@ -1845,7 +1845,7 @@ func (api *DebugAPI) GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNum hash = h } else { block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) - if err != nil { + if block == nil || err != nil { return nil, err } hash = block.Hash() @@ -1864,7 +1864,7 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block hash = h } else { block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) - if err != nil { + if block == nil || err != nil { return nil, err } hash = block.Hash() From 9bdf42788b128ba6b3d58fee98ca7544f2de2d7c Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 11 Feb 2025 17:55:00 -0800 Subject: [PATCH 138/354] trie: copy preimage store pointer in StateTrie.Copy (#31158) This fixes an error where executing `evm run --dump ...` omits preimages from the dump (because the statedb used for execution is a copy of another instance). --- cmd/evm/testdata/evmrun/3.out.1.txt | 3 ++- cmd/evm/testdata/evmrun/4.out.1.txt | 3 ++- trie/secure_trie.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/evm/testdata/evmrun/3.out.1.txt b/cmd/evm/testdata/evmrun/3.out.1.txt index 44956f54f..25dd8da5a 100644 --- a/cmd/evm/testdata/evmrun/3.out.1.txt +++ b/cmd/evm/testdata/evmrun/3.out.1.txt @@ -1,12 +1,13 @@ { "root": "b444481d1367188172f8c6091e948aaa68bae763fd26d6b9e994306a66bf69f9", "accounts": { - "pre(0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142)": { + "0x0000000000000000000000007265636569766572": { "balance": "0", "nonce": 0, "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "codeHash": "0x3e48ef54b89079a075f3b8fc253c657a86b110a7aed3568c1517b10edf2c3eb6", "code": "0x6040", + "address": "0x0000000000000000000000007265636569766572", "key": "0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142" } } diff --git a/cmd/evm/testdata/evmrun/4.out.1.txt b/cmd/evm/testdata/evmrun/4.out.1.txt index 44956f54f..25dd8da5a 100644 --- a/cmd/evm/testdata/evmrun/4.out.1.txt +++ b/cmd/evm/testdata/evmrun/4.out.1.txt @@ -1,12 +1,13 @@ { "root": "b444481d1367188172f8c6091e948aaa68bae763fd26d6b9e994306a66bf69f9", "accounts": { - "pre(0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142)": { + "0x0000000000000000000000007265636569766572": { "balance": "0", "nonce": 0, "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "codeHash": "0x3e48ef54b89079a075f3b8fc253c657a86b110a7aed3568c1517b10edf2c3eb6", "code": "0x6040", + "address": "0x0000000000000000000000007265636569766572", "key": "0x30d7a0694cb29af31b982480e11d7ebb003a3fca4026939149071f014689b142" } } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index f53b10758..45d5fd63e 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -275,6 +275,7 @@ func (t *StateTrie) Copy() *StateTrie { trie: *t.trie.Copy(), db: t.db, secKeyCache: t.secKeyCache, + preimages: t.preimages, } } From ee52c9a5fdada774b542981fb3b64234d84bb866 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 13 Feb 2025 09:45:27 +0100 Subject: [PATCH 139/354] go.mod: update blst to v0.3.14 (#31165) closes https://github.com/ethereum/go-ethereum/issues/31072 BLST released their newest version which includes a fix for go v.1.24: https://github.com/supranational/blst/releases/tag/v0.3.14 I went through all commits between 0.3.14 and 0.3.13 for a sanity check --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d623ed33a..65c7d5b1e 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.10.0 - github.com/supranational/blst v0.3.13 + github.com/supranational/blst v0.3.14 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/urfave/cli/v2 v2.25.7 github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 diff --git a/go.sum b/go.sum index 0edf4f4c2..4d67804bb 100644 --- a/go.sum +++ b/go.sum @@ -531,8 +531,8 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= -github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo= +github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= From 1387b95cafeaee61c93827873121dad63ab5be4d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 13 Feb 2025 13:05:05 +0100 Subject: [PATCH 140/354] core: sanity-check fork configuration in genesis (#31171) This is to prevent a crash on startup with a custom genesis configuration. With this change in place, upgrading a chain created by geth v1.14.x and below will now print an error instead of crashing: Fatal: Failed to register the Ethereum service: invalid chain configuration: missing entry for fork "cancun" in blobSchedule Arguably this is not great, and it should just auto-upgrade the config. We'll address this in a follow-up PR for geth v1.15.2 --- core/genesis.go | 5 +++++ params/config.go | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 0ece99714..edc270ff5 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -366,6 +366,11 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g } newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) + // Sanity-check the new configuration. + if err := newCfg.CheckConfigForkOrder(); err != nil { + return nil, common.Hash{}, nil, err + } + // TODO(rjl493456442) better to define the comparator of chain config // and short circuit if the chain config is not changed. compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time) diff --git a/params/config.go b/params/config.go index dc9b8a6ee..5b50be0dc 100644 --- a/params/config.go +++ b/params/config.go @@ -780,13 +780,13 @@ func (c *ChainConfig) CheckConfigForkOrder() error { } { if cur.config != nil { if err := cur.config.validate(); err != nil { - return fmt.Errorf("invalid blob configuration for fork %s: %v", cur.name, err) + return fmt.Errorf("invalid chain configuration in blobSchedule for fork %q: %v", cur.name, err) } } if cur.timestamp != nil { // If the fork is configured, a blob schedule must be defined for it. if cur.config == nil { - return fmt.Errorf("unsupported fork configuration: missing blob configuration entry for %v in schedule", cur.name) + return fmt.Errorf("invalid chain configuration: missing entry for fork %q in blobSchedule", cur.name) } } } From 2e50e8f7de9650cae6f14709f9c74a80e41bc04f Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 13 Feb 2025 21:48:03 +0800 Subject: [PATCH 141/354] core/rawdb: skip setting flushOffset in read-only mode (#31173) This PR addresses a flaw in the freezer table upgrade path. In v1.15.0, freezer table v2 was introduced, including an additional field (`flushOffset`) maintained in the metadata file. To ensure backward compatibility, an upgrade path was implemented for legacy freezer tables by setting `flushOffset` to the size of the index file. However, if the freezer table is opened in read-only mode, this file write operation is rejected, causing Geth to shut down entirely. Given that invalid items in the freezer index file can be detected and truncated, all items in freezer v0 index files are guaranteed to be complete. Therefore, when operating in read-only mode, it is safe to use the freezer data without performing an upgrade. --- core/rawdb/freezer_table.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 1ba8cf639..e553df702 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -405,6 +405,13 @@ func (t *freezerTable) repairIndex() error { // If legacy metadata is detected, attempt to recover the offset from the // index file to avoid clearing the entire table. if t.metadata.version == freezerTableV1 { + // Skip truncation if the legacy metadata is opened in read-only mode. + // Since all items in the legacy index file were forcibly synchronized, + // data integrity is guaranteed. Therefore, it's safe to leave any extra + // items untruncated in this special scenario. + if t.readonly { + return nil + } t.logger.Info("Recovering freezer flushOffset for legacy table", "offset", size) return t.metadata.setFlushOffset(size, true) } From 9dd5060b5865b8bd5fb3fd3ccf3977ca3c4fe009 Mon Sep 17 00:00:00 2001 From: minh-bq Date: Fri, 14 Feb 2025 00:05:58 +0700 Subject: [PATCH 142/354] core/types: create block's bloom by merging receipts' bloom (#31129) Currently, when calculating block's bloom, we loop through all the receipt logs to calculate the hash value. However, normally, after going through applyTransaction, the receipt's bloom is already calculated based on the receipt log, so the block's bloom can be calculated by just ORing these receipt's blooms. ``` goos: darwin goarch: arm64 pkg: github.com/ethereum/go-ethereum/core/types cpu: Apple M1 Pro BenchmarkCreateBloom BenchmarkCreateBloom/small BenchmarkCreateBloom/small-10 810922 1481 ns/op 104 B/op 5 allocs/op BenchmarkCreateBloom/large BenchmarkCreateBloom/large-10 8173 143764 ns/op 9614 B/op 401 allocs/op BenchmarkCreateBloom/small-mergebloom BenchmarkCreateBloom/small-mergebloom-10 5178918 232.0 ns/op 0 B/op 0 allocs/op BenchmarkCreateBloom/large-mergebloom BenchmarkCreateBloom/large-mergebloom-10 54110 22207 ns/op 0 B/op 0 allocs/op ``` --------- Co-authored-by: Gary Rong Co-authored-by: Zsolt Felfoldi --- cmd/evm/internal/t8ntool/execution.go | 5 +-- core/block_validator.go | 6 +++- core/rawdb/accessors_chain_test.go | 8 ++--- core/state_processor.go | 2 +- core/types/block.go | 8 ++++- core/types/bloom9.go | 39 ++++++++++---------- core/types/bloom9_test.go | 52 ++++++++++++++++++++++++--- core/types/receipt.go | 2 +- core/types/receipt_test.go | 12 +++---- eth/filters/filter_test.go | 2 +- 10 files changed, 97 insertions(+), 39 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 9416c5c84..e38a510ef 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -313,7 +313,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) + // These three are non-consensus fields: //receipt.BlockHash //receipt.BlockNumber @@ -385,7 +386,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, StateRoot: root, TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)), ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)), - Bloom: types.CreateBloom(receipts), + Bloom: types.MergeBloom(receipts), LogsHash: rlpHash(statedb.Logs()), Receipts: receipts, Rejected: rejectedTxs, diff --git a/core/block_validator.go b/core/block_validator.go index 5885df9ee..591e472bc 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -129,7 +129,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. - rbloom := types.CreateBloom(res.Receipts) + // + // Receipts must go through MakeReceipt to calculate the receipt's bloom + // already. Merge the receipt's bloom together instead of recalculating + // everything. + rbloom := types.MergeBloom(res.Receipts) if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 6972f2be2..9dbb8c5a8 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -361,7 +361,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, } - receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) + receipt1.Bloom = types.CreateBloom(receipt1) receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), @@ -374,7 +374,7 @@ func TestBlockReceiptStorage(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), GasUsed: 222222, } - receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) + receipt2.Bloom = types.CreateBloom(receipt2) receipts := []*types.Receipt{receipt1, receipt2} // Check that no receipt entries are in a pristine database @@ -713,7 +713,7 @@ func TestReadLogs(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, } - receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) + receipt1.Bloom = types.CreateBloom(receipt1) receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), @@ -726,7 +726,7 @@ func TestReadLogs(t *testing.T) { ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), GasUsed: 222222, } - receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) + receipt2.Bloom = types.CreateBloom(receipt2) receipts := []*types.Receipt{receipt1, receipt2} hash := common.BytesToHash([]byte{0x03, 0x14}) diff --git a/core/state_processor.go b/core/state_processor.go index c10f9454a..e2d65e682 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -207,7 +207,7 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber receipt.TransactionIndex = uint(statedb.TxIndex()) diff --git a/core/types/block.go b/core/types/block.go index 11c9018cc..26980ac56 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -252,6 +252,9 @@ type extblock struct { // // The body elements and the receipts are used to recompute and overwrite the // relevant portions of the header. +// +// The receipt's bloom must already calculated for the block's bloom to be +// correctly calculated. func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher) *Block { if body == nil { body = &Body{} @@ -275,7 +278,10 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher b.header.ReceiptHash = EmptyReceiptsHash } else { b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher) - b.header.Bloom = CreateBloom(receipts) + // Receipts must go through MakeReceipt to calculate the receipt's bloom + // already. Merge the receipt's bloom together instead of recalculating + // everything. + b.header.Bloom = MergeBloom(receipts) } if len(uncles) == 0 { diff --git a/core/types/bloom9.go b/core/types/bloom9.go index a560a2072..962ba46d4 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -100,32 +100,35 @@ func (b *Bloom) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("Bloom", input, b[:]) } -// CreateBloom creates a bloom filter out of the give Receipts (+Logs) -func CreateBloom(receipts Receipts) Bloom { - buf := make([]byte, 6) - var bin Bloom - for _, receipt := range receipts { - for _, log := range receipt.Logs { - bin.add(log.Address.Bytes(), buf) - for _, b := range log.Topics { - bin.add(b[:], buf) - } +// CreateBloom creates a bloom filter out of the give Receipt (+Logs) +func CreateBloom(receipt *Receipt) Bloom { + var ( + bin Bloom + buf = make([]byte, 6) + ) + for _, log := range receipt.Logs { + bin.add(log.Address.Bytes(), buf) + for _, b := range log.Topics { + bin.add(b[:], buf) } } return bin } -// LogsBloom returns the bloom bytes for the given logs -func LogsBloom(logs []*Log) []byte { - buf := make([]byte, 6) +// MergeBloom merges the precomputed bloom filters in the Receipts without +// recalculating them. It assumes that each receipt’s Bloom field is already +// correctly populated. +func MergeBloom(receipts Receipts) Bloom { var bin Bloom - for _, log := range logs { - bin.add(log.Address.Bytes(), buf) - for _, b := range log.Topics { - bin.add(b[:], buf) + for _, receipt := range receipts { + if len(receipt.Logs) != 0 { + bl := receipt.Bloom.Bytes() + for i := range bin { + bin[i] |= bl[i] + } } } - return bin[:] + return bin } // Bloom9 returns the bloom filter for the given data diff --git a/core/types/bloom9_test.go b/core/types/bloom9_test.go index d3178d112..07f6446a9 100644 --- a/core/types/bloom9_test.go +++ b/core/types/bloom9_test.go @@ -126,26 +126,70 @@ func BenchmarkCreateBloom(b *testing.B) { for i := 0; i < 200; i += 2 { copy(rLarge[i:], rSmall) } - b.Run("small", func(b *testing.B) { + b.Run("small-createbloom", func(b *testing.B) { b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, receipt := range rSmall { + receipt.Bloom = CreateBloom(receipt) + } + } + b.StopTimer() + + bl := MergeBloom(rSmall) + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") + got := crypto.Keccak256Hash(bl.Bytes()) + if got != exp { + b.Errorf("Got %x, exp %x", got, exp) + } + }) + b.Run("large-createbloom", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + for _, receipt := range rLarge { + receipt.Bloom = CreateBloom(receipt) + } + } + b.StopTimer() + + bl := MergeBloom(rLarge) + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") + got := crypto.Keccak256Hash(bl.Bytes()) + if got != exp { + b.Errorf("Got %x, exp %x", got, exp) + } + }) + b.Run("small-mergebloom", func(b *testing.B) { + for _, receipt := range rSmall { + receipt.Bloom = CreateBloom(receipt) + } + b.ReportAllocs() + b.ResetTimer() + var bl Bloom for i := 0; i < b.N; i++ { - bl = CreateBloom(rSmall) + bl = MergeBloom(rSmall) } b.StopTimer() + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") got := crypto.Keccak256Hash(bl.Bytes()) if got != exp { b.Errorf("Got %x, exp %x", got, exp) } }) - b.Run("large", func(b *testing.B) { + b.Run("large-mergebloom", func(b *testing.B) { + for _, receipt := range rLarge { + receipt.Bloom = CreateBloom(receipt) + } b.ReportAllocs() + b.ResetTimer() + var bl Bloom for i := 0; i < b.N; i++ { - bl = CreateBloom(rLarge) + bl = MergeBloom(rLarge) } b.StopTimer() + var exp = common.HexToHash("c384c56ece49458a427c67b90fefe979ebf7104795be65dc398b280f24104949") got := crypto.Keccak256Hash(bl.Bytes()) if got != exp { diff --git a/core/types/receipt.go b/core/types/receipt.go index 47f16d950..e52a0c647 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -291,7 +291,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { } r.CumulativeGasUsed = stored.CumulativeGasUsed r.Logs = stored.Logs - r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) + r.Bloom = CreateBloom((*Receipt)(r)) return nil } diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index fc51eb11a..78b43c7e4 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -394,7 +394,7 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) { func TestReceiptMarshalBinary(t *testing.T) { // Legacy Receipt - legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt}) + legacyReceipt.Bloom = CreateBloom(legacyReceipt) have, err := legacyReceipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -421,7 +421,7 @@ func TestReceiptMarshalBinary(t *testing.T) { // 2930 Receipt buf.Reset() - accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt}) + accessListReceipt.Bloom = CreateBloom(accessListReceipt) have, err = accessListReceipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -439,7 +439,7 @@ func TestReceiptMarshalBinary(t *testing.T) { // 1559 Receipt buf.Reset() - eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt}) + eip1559Receipt.Bloom = CreateBloom(eip1559Receipt) have, err = eip1559Receipt.MarshalBinary() if err != nil { t.Fatalf("marshal binary error: %v", err) @@ -463,7 +463,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := gotLegacyReceipt.UnmarshalBinary(legacyBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt}) + legacyReceipt.Bloom = CreateBloom(legacyReceipt) if !reflect.DeepEqual(gotLegacyReceipt, legacyReceipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotLegacyReceipt, legacyReceipt) } @@ -474,7 +474,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := gotAccessListReceipt.UnmarshalBinary(accessListBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt}) + accessListReceipt.Bloom = CreateBloom(accessListReceipt) if !reflect.DeepEqual(gotAccessListReceipt, accessListReceipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotAccessListReceipt, accessListReceipt) } @@ -485,7 +485,7 @@ func TestReceiptUnmarshalBinary(t *testing.T) { if err := got1559Receipt.UnmarshalBinary(eip1559RctBinary); err != nil { t.Fatalf("unmarshal binary error: %v", err) } - eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt}) + eip1559Receipt.Bloom = CreateBloom(eip1559Receipt) if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) { t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 1a91007ec..fa958e62d 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -42,7 +42,7 @@ func makeReceipt(addr common.Address) *types.Receipt { receipt.Logs = []*types.Log{ {Address: addr}, } - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + receipt.Bloom = types.CreateBloom(receipt) return receipt } From 8c267e62ab50529e284fd40c728615883af50d3a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 17 Feb 2025 07:30:06 +0100 Subject: [PATCH 143/354] consensus/beacon: fix isPostMerge for mainnet (#31191) This fixes a regression introduced in #31153 where we didn't consider mainnet to be in PoS, causing #31190. The problem is, `params.MainnetChainConfig` does not have a defined `MergeNetsplitBlock`, so it isn't considered to be in PoS in `CalcDifficulty`. --- consensus/beacon/consensus.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 5199fd845..967d762b1 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -75,9 +75,11 @@ func New(ethone consensus.Engine) *Beacon { // isPostMerge reports whether the given block number is assumed to be post-merge. // Here we check the MergeNetsplitBlock to allow configuring networks with a PoW or // PoA chain for unit testing purposes. -func isPostMerge(config *params.ChainConfig, block uint64) bool { +func isPostMerge(config *params.ChainConfig, blockNum uint64, timestamp uint64) bool { mergedAtGenesis := config.TerminalTotalDifficulty != nil && config.TerminalTotalDifficulty.Sign() == 0 - return mergedAtGenesis || config.MergeNetsplitBlock != nil && block >= config.MergeNetsplitBlock.Uint64() + return mergedAtGenesis || + config.MergeNetsplitBlock != nil && blockNum >= config.MergeNetsplitBlock.Uint64() || + config.ShanghaiTime != nil && timestamp >= *config.ShanghaiTime } // Author implements consensus.Engine, returning the verified author of the block. @@ -342,7 +344,7 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [ // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the beacon protocol. The changes are done inline. func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { - if !isPostMerge(chain.Config(), header.Number.Uint64()) { + if !isPostMerge(chain.Config(), header.Number.Uint64(), header.Time) { return beacon.ethone.Prepare(chain, header) } header.Difficulty = beaconDifficulty @@ -452,7 +454,7 @@ func (beacon *Beacon) SealHash(header *types.Header) common.Hash { // the difficulty that a new block should have when created at time // given the parent block's time and difficulty. func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { - if !isPostMerge(chain.Config(), parent.Number.Uint64()+1) { + if !isPostMerge(chain.Config(), parent.Number.Uint64()+1, time) { return beacon.ethone.CalcDifficulty(chain, time, parent) } return beaconDifficulty From 122779348ba2e59155f51d5a3bd0c5aca5071823 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 17 Feb 2025 09:47:12 +0100 Subject: [PATCH 144/354] p2p: fix marshaling of NAT in TOML (#31192) This fixes an issue where a nat.Interface unmarshaled from the TOML config file could not be re-marshaled to TOML correctly. Fixes #31183 --- p2p/config.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/p2p/config.go b/p2p/config.go index 5ea62e12f..68a9c0bb5 100644 --- a/p2p/config.go +++ b/p2p/config.go @@ -18,6 +18,7 @@ package p2p import ( "crypto/ecdsa" + "encoding" "fmt" "github.com/ethereum/go-ethereum/common/mclock" @@ -135,6 +136,13 @@ type configNAT struct { nat.Interface } +func (w *configNAT) MarshalText() ([]byte, error) { + if tm, ok := w.Interface.(encoding.TextMarshaler); ok { + return tm.MarshalText() + } + return nil, fmt.Errorf("NAT specification %#v cannot be marshaled", w.Interface) +} + func (w *configNAT) UnmarshalText(input []byte) error { n, err := nat.Parse(string(input)) if err != nil { From ffa0dec55c68608c63f787a013f378b5c41f9645 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 17 Feb 2025 10:12:03 +0100 Subject: [PATCH 145/354] eth/protocols/eth: add discovery iterator to protocol (#31185) We somehow forgot to add this in #30302, so discv5 and DNS have actually been disabled since then. Fixes #31168 --- eth/protocols/eth/handler.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 28db93a20..64fc99f6b 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -90,7 +90,7 @@ type TxPool interface { } // MakeProtocols constructs the P2P protocol definitions for `eth`. -func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2p.Protocol { +func MakeProtocols(backend Backend, network uint64, disc enode.Iterator) []p2p.Protocol { protocols := make([]p2p.Protocol, 0, len(ProtocolVersions)) for _, version := range ProtocolVersions { protocols = append(protocols, p2p.Protocol{ @@ -111,7 +111,8 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{currentENREntry(backend.Chain())}, + DialCandidates: disc, + Attributes: []enr.Entry{currentENREntry(backend.Chain())}, }) } return protocols From 302d013a97b21c0355b0865c8526f50435a4f216 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 18 Feb 2025 03:48:42 +0100 Subject: [PATCH 146/354] trie: do not expect ordering in stacktrie during fuzzing (#31170) This PR removes the assumption of the stacktrie and trie to have the same ordering. This was hit by the fuzzers on oss-fuzz --------- Co-authored-by: Gary Rong --- trie/stacktrie_fuzzer_test.go | 25 ++++++++++------------ trie/trie_test.go | 39 ++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index df487d16b..7ff6ef023 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -37,16 +37,13 @@ func FuzzStackTrie(f *testing.F) { } func fuzz(data []byte, debugging bool) { - // This spongeDb is used to check the sequence of disk-db-writes var ( - input = bytes.NewReader(data) - spongeA = &spongeDb{sponge: crypto.NewKeccakState()} - dbA = newTestDatabase(rawdb.NewDatabase(spongeA), rawdb.HashScheme) - trieA = NewEmpty(dbA) - spongeB = &spongeDb{sponge: crypto.NewKeccakState()} - dbB = newTestDatabase(rawdb.NewDatabase(spongeB), rawdb.HashScheme) - trieB = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(spongeB, common.Hash{}, path, hash, blob, dbB.Scheme()) + input = bytes.NewReader(data) + dbA = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) + trieA = NewEmpty(dbA) + memDB = rawdb.NewMemoryDatabase() + trieB = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + rawdb.WriteTrieNode(memDB, common.Hash{}, path, hash, blob, rawdb.HashScheme) }) vals []*kv maxElements = 10000 @@ -55,13 +52,17 @@ func fuzz(data []byte, debugging bool) { ) // Fill the trie with elements for i := 0; input.Len() > 0 && i < maxElements; i++ { + // Build the key k := make([]byte, 32) input.Read(k) + + // Build the val var a uint16 binary.Read(input, binary.LittleEndian, &a) a = 1 + a%100 v := make([]byte, a) input.Read(v) + if input.Len() == 0 { // If it was exhausted while reading, the value may be all zeroes, // thus 'deletion' which is not supported on stacktrie @@ -73,6 +74,7 @@ func fuzz(data []byte, debugging bool) { } keys[string(k)] = struct{}{} vals = append(vals, &kv{k: k, v: v}) + trieA.MustUpdate(k, v) } if len(vals) == 0 { @@ -99,11 +101,6 @@ func fuzz(data []byte, debugging bool) { if rootA != rootB { panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootB)) } - sumA := spongeA.sponge.Sum(nil) - sumB := spongeB.sponge.Sum(nil) - if !bytes.Equal(sumA, sumB) { - panic(fmt.Sprintf("sequence differ: (trie) %x != %x (stacktrie)", sumA, sumB)) - } // Ensure all the nodes are persisted correctly var ( diff --git a/trie/trie_test.go b/trie/trie_test.go index 423ed30fe..77234d9d9 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -779,6 +779,7 @@ func TestCommitAfterHash(t *testing.T) { func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { // Make the random benchmark deterministic random := rand.New(rand.NewSource(0)) + // Create a realistic account trie to hash addresses = make([][20]byte, size) for i := 0; i < len(addresses); i++ { @@ -795,13 +796,18 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { ) // The big.Rand function is not deterministic with regards to 64 vs 32 bit systems, // and will consume different amount of data from the rand source. - //balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) + // balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) // Therefore, we instead just read via byte buffer numBytes := random.Uint32() % 33 // [0, 32] bytes balanceBytes := make([]byte, numBytes) random.Read(balanceBytes) balance := new(uint256.Int).SetBytes(balanceBytes) - data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code}) + data, _ := rlp.EncodeToBytes(&types.StateAccount{ + Nonce: nonce, + Balance: balance, + Root: root, + CodeHash: code, + }) accounts[i] = data } return addresses, accounts @@ -856,6 +862,7 @@ func (s *spongeDb) Flush() { s.sponge.Write([]byte(key)) s.sponge.Write([]byte(s.values[key])) } + fmt.Println(len(s.keys)) } // spongeBatch is a dummy batch which immediately writes to the underlying spongedb @@ -873,10 +880,12 @@ func (b *spongeBatch) Write() error { return nil } func (b *spongeBatch) Reset() {} func (b *spongeBatch) Replay(w ethdb.KeyValueWriter) error { return nil } -// TestCommitSequence tests that the trie.Commit operation writes the elements of the trie -// in the expected order. -// The test data was based on the 'master' code, and is basically random. It can be used -// to check whether changes to the trie modifies the write order or data in any way. +// TestCommitSequence tests that the trie.Commit operation writes the elements +// of the trie in the expected order. +// +// The test data was based on the 'master' code, and is basically random. +// It can be used to check whether changes to the trie modifies the write order +// or data in any way. func TestCommitSequence(t *testing.T) { for i, tc := range []struct { count int @@ -887,19 +896,23 @@ func TestCommitSequence(t *testing.T) { {2000, common.FromHex("4574cd8e6b17f3fe8ad89140d1d0bf4f1bd7a87a8ac3fb623b33550544c77635")}, } { addresses, accounts := makeAccounts(tc.count) + // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: crypto.NewKeccakState()} db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) + // Fill the trie with elements + trie := NewEmpty(db) for i := 0; i < tc.count; i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + // Flush memdb -> disk (sponge) db.Commit(root) + if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { t.Errorf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) } @@ -917,12 +930,13 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { {200, common.FromHex("dde92ca9812e068e6982d04b40846dc65a61a9fd4996fc0f55f2fde172a8e13c")}, {2000, common.FromHex("ab553a7f9aff82e3929c382908e30ef7dd17a332933e92ba3fe873fc661ef382")}, } { - prng := rand.New(rand.NewSource(int64(i))) // This spongeDb is used to check the sequence of disk-db-writes + prng := rand.New(rand.NewSource(int64(i))) s := &spongeDb{sponge: crypto.NewKeccakState()} db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) + // Fill the trie with elements + trie := NewEmpty(db) for i := 0; i < tc.count; i++ { key := make([]byte, 32) var val []byte @@ -939,6 +953,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { // Flush trie -> database root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) + // Flush memdb -> disk (sponge) db.Commit(root) if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { @@ -974,19 +989,22 @@ func TestCommitSequenceStackTrie(t *testing.T) { // For the stack trie, we need to do inserts in proper order key := make([]byte, 32) binary.BigEndian.PutUint64(key, uint64(i)) - var val []byte + // 50% short elements, 50% large elements + var val []byte if prng.Intn(2) == 0 { val = make([]byte, 1+prng.Intn(32)) } else { val = make([]byte, 1+prng.Intn(1024)) } prng.Read(val) + trie.Update(key, val) stTrie.Update(key, val) } // Flush trie -> database root, nodes := trie.Commit(false) + // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) @@ -1045,6 +1063,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { // Flush trie -> database root, nodes := trie.Commit(false) + // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) From d762afab1d59418ed43cce6ff35d7ef8d5c39c33 Mon Sep 17 00:00:00 2001 From: piersy Date: Tue, 18 Feb 2025 05:50:19 +0000 Subject: [PATCH 147/354] utils: clarify description for history.state flag (#31164) --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8c27c859d..0e456982a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -263,7 +263,7 @@ var ( } StateHistoryFlag = &cli.Uint64Flag{ Name: "history.state", - Usage: "Number of recent blocks to retain state history for (default = 90,000 blocks, 0 = entire chain)", + Usage: "Number of recent blocks to retain state history for, only relevant in state.scheme=path (default = 90,000 blocks, 0 = entire chain)", Value: ethconfig.Defaults.StateHistory, Category: flags.StateCategory, } From 41f64e83994c125a905020db1084df87b7e3d03a Mon Sep 17 00:00:00 2001 From: EdisonSR <61781882@qq.com> Date: Tue, 18 Feb 2025 18:15:36 +0800 Subject: [PATCH 148/354] ethclient: add comment describing block number tags (#30984) Adds a comment on how to use rpc.*BlockNumber and the explanation of the block number tags --------- Co-authored-by: Gary Rong --- ethclient/ethclient.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index bbddc4620..cefd4f61b 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -85,11 +85,23 @@ func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo return ec.getBlock(ctx, "eth_getBlockByHash", hash, true) } -// BlockByNumber returns a block from the current canonical chain. If number is nil, the -// latest known block is returned. +// BlockByNumber returns a block from the current canonical chain. +// If `number` is nil, the latest known block is returned. // -// Note that loading full blocks requires two requests. Use HeaderByNumber -// if you don't need all transactions or uncle headers. +// Use `HeaderByNumber` if you don't need full transaction data or uncle headers. +// +// Supported special block number tags: +// - `earliest` : The genesis (earliest) block +// - `latest` : The most recently included block +// - `safe` : The latest safe head block +// - `finalized` : The latest finalized block +// - `pending` : The pending block +// +// Example usage: +// +// ```go +// BlockByNumber(context.Background(), big.NewInt(int64(rpc.LatestBlockNumber))) +// ``` func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { return ec.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true) } @@ -210,8 +222,21 @@ func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.He return head, err } -// HeaderByNumber returns a block header from the current canonical chain. If number is -// nil, the latest known header is returned. +// HeaderByNumber returns a block header from the current canonical chain. +// If `number` is nil, the latest known block header is returned. +// +// Supported special block number tags: +// - `earliest` : The genesis (earliest) block +// - `latest` : The most recently included block +// - `safe` : The latest safe head block +// - `finalized` : The latest finalized block +// - `pending` : The pending block +// +// Example usage: +// +// ```go +// HeaderByNumber(context.Background(), big.NewInt(int64(rpc.LatestBlockNumber))) +// ``` func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { var head *types.Header err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) From 7f4335a78a2c768017344831f7777948874947d9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 18 Feb 2025 21:53:33 +0800 Subject: [PATCH 149/354] core/vm: clean up EVM environmental structure (#31061) This PR does a few things including: - Remove `ContractRef` interface - Remove `vm.AccountRef` which implements `ContractRef` interface - Maintain the `jumpDests` struct in EVM for sharing between call frames - Simplify the delegateCall context initialization --- core/state_processor.go | 8 +- core/state_transition.go | 5 +- core/vm/contract.go | 86 +++++--------------- core/vm/eips.go | 8 +- core/vm/evm.go | 130 ++++++++++++++---------------- core/vm/gas_table_test.go | 4 +- core/vm/instructions.go | 12 +-- core/vm/instructions_test.go | 11 +-- core/vm/interface.go | 15 ---- core/vm/interpreter_test.go | 2 +- core/vm/runtime/runtime.go | 13 ++- eth/tracers/js/tracer_test.go | 19 +---- eth/tracers/logger/logger_test.go | 18 +---- tests/state_test.go | 5 +- 14 files changed, 110 insertions(+), 226 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index e2d65e682..4708dddc9 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -247,7 +247,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress) - _, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) evm.StateDB.Finalise(true) } @@ -271,7 +271,7 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress) - _, _, err := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) if err != nil { panic(err) } @@ -310,7 +310,7 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(addr) - ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + ret, _, _ := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) evm.StateDB.Finalise(true) if len(ret) == 0 { return // skip empty output @@ -412,7 +412,7 @@ func applyLocalSystemCall(to common.Address, data []byte, evm *vm.EVM) error { } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(to) - _, _, err := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) if err != nil { return fmt.Errorf("onPersist call failed: %w", err) } diff --git a/core/state_transition.go b/core/state_transition.go index a75c44bfa..59be0a81c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -463,7 +463,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { var ( msg = st.msg - sender = vm.AccountRef(msg.From) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time) contractCreation = msg.To == nil floorDataGas uint64 @@ -524,7 +523,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) if contractCreation { - ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value) + ret, _, st.gasRemaining, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining, value) } else { // Increment the nonce for the next transaction. st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall) @@ -547,7 +546,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } // Execute the transaction's call. - ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value) + ret, st.gasRemaining, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value) } // Compute refund counter, capped to a refund quotient. diff --git a/core/vm/contract.go b/core/vm/contract.go index 5670244e1..0eaa91d95 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -22,39 +22,20 @@ import ( "github.com/holiman/uint256" ) -// ContractRef is a reference to the contract's backing object -type ContractRef interface { - Address() common.Address -} - -// AccountRef implements ContractRef. -// -// Account references are used during EVM initialisation and -// its primary use is to fetch addresses. Removing this object -// proves difficult because of the cached jump destinations which -// are fetched from the parent contract (i.e. the caller), which -// is a ContractRef. -type AccountRef common.Address - -// Address casts AccountRef to an Address -func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } - // Contract represents an ethereum contract in the state database. It contains // the contract code, calling arguments. Contract implements ContractRef type Contract struct { - // CallerAddress is the result of the caller which initialised this - // contract. However when the "call method" is delegated this value - // needs to be initialised to that of the caller's caller. - CallerAddress common.Address - caller ContractRef - self ContractRef + // caller is the result of the caller which initialised this + // contract. However, when the "call method" is delegated this + // value needs to be initialised to that of the caller's caller. + caller common.Address + address common.Address jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. analysis bitvec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash - CodeAddr *common.Address Input []byte // is the execution frame represented by this object a contract deployment @@ -66,23 +47,18 @@ type Contract struct { } // NewContract returns a new contract environment for the execution of EVM. -func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas uint64) *Contract { - c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} - - if parent, ok := caller.(*Contract); ok { - // Reuse JUMPDEST analysis from parent context if available. - c.jumpdests = parent.jumpdests - } else { - c.jumpdests = make(map[common.Hash]bitvec) +func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests map[common.Hash]bitvec) *Contract { + // Initialize the jump analysis map if it's nil, mostly for tests + if jumpDests == nil { + jumpDests = make(map[common.Hash]bitvec) + } + return &Contract{ + caller: caller, + address: address, + jumpdests: jumpDests, + Gas: gas, + value: value, } - - // Gas should be a pointer so it can safely be reduced through the run - // This pointer will be off the state transition - c.Gas = gas - // ensures a value is set - c.value = value - - return c } func (c *Contract) validJumpdest(dest *uint256.Int) bool { @@ -132,18 +108,6 @@ func (c *Contract) isCode(udest uint64) bool { return c.analysis.codeSegment(udest) } -// AsDelegate sets the contract to be a delegate call and returns the current -// contract (for chaining calls) -func (c *Contract) AsDelegate() *Contract { - // NOTE: caller must, at all times be a contract. It should never happen - // that caller is something other than a Contract. - parent := c.caller.(*Contract) - c.CallerAddress = parent.CallerAddress - c.value = parent.value - - return c -} - // GetOp returns the n'th element in the contract's byte array func (c *Contract) GetOp(n uint64) OpCode { if n < uint64(len(c.Code)) { @@ -158,7 +122,7 @@ func (c *Contract) GetOp(n uint64) OpCode { // Caller will recursively call caller when the contract is a delegate // call, including that of caller's caller. func (c *Contract) Caller() common.Address { - return c.CallerAddress + return c.caller } // UseGas attempts the use gas and subtracts it and returns true on success @@ -186,7 +150,7 @@ func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.G // Address returns the contracts address func (c *Contract) Address() common.Address { - return c.self.Address() + return c.address } // Value returns the contract's value (sent to it from it's caller) @@ -194,18 +158,8 @@ func (c *Contract) Value() *uint256.Int { return c.value } -// SetCallCode sets the code of the contract and address of the backing data -// object -func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { +// SetCallCode sets the code of the contract, +func (c *Contract) SetCallCode(hash common.Hash, code []byte) { c.Code = code c.CodeHash = hash - c.CodeAddr = addr -} - -// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. -// In case hash is not provided, the jumpdest analysis will not be saved to the parent context -func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { - c.Code = codeAndHash.code - c.CodeHash = codeAndHash.hash - c.CodeAddr = addr } diff --git a/core/vm/eips.go b/core/vm/eips.go index 515999bd1..6159eade7 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -338,13 +338,9 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC } addr := common.Address(a.Bytes20()) code := interpreter.evm.StateDB.GetCode(addr) - contract := &Contract{ - Code: code, - self: AccountRef(addr), - } paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) - if !contract.IsSystemCall { - statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) + if !scope.Contract.IsSystemCall { + statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false) if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { scope.Contract.Gas = 0 return nil, ErrOutOfGas diff --git a/core/vm/evm.go b/core/vm/evm.go index 442441e9a..c28dcb255 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -91,29 +91,40 @@ type EVM struct { // Context provides auxiliary blockchain related information Context BlockContext TxContext + // StateDB gives access to the underlying state StateDB StateDB - // Depth is the current call stack + + // depth is the current call stack depth int // chainConfig contains information about the current chain chainConfig *params.ChainConfig + // chain rules contains the chain rules for the current epoch chainRules params.Rules - // virtual machine configuration options used to initialise the - // evm. + + // virtual machine configuration options used to initialise the evm Config Config - // global (to this context) ethereum virtual machine - // used throughout the execution of the tx. + + // global (to this context) ethereum virtual machine used throughout + // the execution of the tx interpreter *EVMInterpreter + // abort is used to abort the EVM calling operations abort atomic.Bool + // callGasTemp holds the gas available for the current call. This is needed because the // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. callGasTemp uint64 + // precompiles holds the precompiled contracts for the current epoch precompiles map[common.Address]PrecompiledContract + + // jumpDests is the aggregated result of JUMPDEST analysis made through + // the life cycle of EVM. + jumpDests map[common.Hash]bitvec } // NewEVM constructs an EVM instance with the supplied block context, state @@ -127,6 +138,7 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), + jumpDests: make(map[common.Hash]bitvec), } evm.precompiles = activePrecompiledContracts(evm.chainRules) evm.interpreter = NewEVMInterpreter(evm) @@ -165,18 +177,18 @@ func (evm *EVM) Interpreter() *EVMInterpreter { return evm.interpreter } -func isSystemCall(caller ContractRef) bool { - return caller.Address() == params.SystemAddress +func isSystemCall(caller common.Address) bool { + return caller == params.SystemAddress } // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takse // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. -func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Capture the tracer start/end events in debug mode if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value.ToBig()) + evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -186,7 +198,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrDepth } // Fail if we're trying to transfer more than the available balance - if !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() @@ -209,23 +221,20 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.StateDB.CreateAccount(addr) } - evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) + evm.Context.Transfer(evm.StateDB, caller, addr, value) if isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. - // The contract is a scoped environment for this execution context only. code := evm.resolveCode(addr) if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { - addrCopy := addr - // If the account has no code, we can abort here - // The depth-check is already done, and precompiles handled above - contract := NewContract(caller, AccountRef(addrCopy), value, gas) + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, addr, value, gas, evm.jumpDests) contract.IsSystemCall = isSystemCall(caller) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), code) + contract.SetCallCode(evm.resolveCodeHash(addr), code) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -256,10 +265,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value.ToBig()) + evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -272,7 +281,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Note although it's noop to transfer X ether to caller itself. But // if caller doesn't have enough balance, it would be an error to allow // over-charging itself. So the check here is necessary. - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, gas, ErrInsufficientBalance } var snapshot = evm.StateDB.Snapshot() @@ -281,11 +290,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { - addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, AccountRef(caller.Address()), value, gas) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + contract := NewContract(caller, caller, value, gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -295,7 +303,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } - gas = 0 } } @@ -307,14 +314,11 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. -func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - // NOTE: caller must, at all times be a contract. It should never happen - // that caller is something other than a Contract. - parent := caller.(*Contract) // DELEGATECALL inherits value from parent call - evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig()) + evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -329,10 +333,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { - addrCopy := addr // Initialise a new contract and make initialise the delegate values - contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + // + // Note: The value refers to the original value from the parent call. + contract := NewContract(originCaller, caller, value, gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -352,10 +357,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // as parameters while disallowing any modifications to the state during the call. // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. -func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil) + evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -380,14 +385,11 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) } else { - // At this point, we use a copy of address. If we don't, the go compiler will - // leak the 'contract' to the outer scope, and make allocation for 'contract' - // even if the actual execution ends on RunPrecompiled above. - addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + contract := NewContract(caller, addr, new(uint256.Int), gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) + // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. @@ -407,22 +409,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return ret, gas, err } -type codeAndHash struct { - code []byte - hash common.Hash -} - -func (c *codeAndHash) Hash() common.Hash { - if c.hash == (common.Hash{}) { - c.hash = crypto.Keccak256Hash(c.code) - } - return c.hash -} - // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { +func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig()) + evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -432,14 +422,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.depth > int(params.CallCreateDepth) { return nil, common.Address{}, gas, ErrDepth } - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, common.Address{}, gas, ErrInsufficientBalance } - nonce := evm.StateDB.GetNonce(caller.Address()) + nonce := evm.StateDB.GetNonce(caller) if nonce+1 < nonce { return nil, common.Address{}, gas, ErrNonceUintOverflow } - evm.StateDB.SetNonce(caller.Address(), nonce+1, tracing.NonceChangeContractCreator) + evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator) // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { @@ -500,15 +490,18 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } gas = gas - statelessGas } - evm.Context.Transfer(evm.StateDB, caller.Address(), address, value) + evm.Context.Transfer(evm.StateDB, caller, address, value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, AccountRef(address), value, gas) - contract.SetCodeOptionalHash(&address, codeAndHash) + contract := NewContract(caller, address, value, gas, evm.jumpDests) + + // Explicitly set the code to a null hash to prevent caching of jump analysis + // for the initialization code. + contract.SetCallCode(common.Hash{}, code) contract.IsDeployment = true - ret, err = evm.initNewContract(contract, address, value) + ret, err = evm.initNewContract(contract, address) if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { @@ -520,7 +513,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // initNewContract runs a new contract's creation code, performs checks on the // resulting code that is to be deployed, and consumes necessary gas. -func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) { +func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]byte, error) { ret, err := evm.interpreter.Run(contract, nil, false) if err != nil { return ret, err @@ -552,19 +545,18 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE) +func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress(caller, evm.StateDB.GetNonce(caller)) + return evm.create(caller, code, gas, value, contractAddr, CREATE) } // Create2 creates a new contract using code as deployment code. // // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. -func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - codeAndHash := &codeAndHash{code: code} - contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) - return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) +func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), crypto.Keccak256(code)) + return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) } // resolveCode returns the code associated with the provided account. After diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index be8688526..cb6143c0b 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -97,7 +97,7 @@ func TestEIP2200(t *testing.T) { } evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) - _, gas, err := evm.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) + _, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int)) if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } @@ -153,7 +153,7 @@ func TestCreateGas(t *testing.T) { evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config) var startGas = uint64(testGas) - ret, gas, err := evm.Call(AccountRef(common.Address{}), address, nil, startGas, new(uint256.Int)) + ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int)) if err != nil { return false } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2b7b82c2a..1d68f09ef 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -682,7 +682,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, &value) + res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must @@ -723,7 +723,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas, + res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -760,7 +760,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt if !value.IsZero() { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, &value) + ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() @@ -794,7 +794,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, &value) + ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() } else { @@ -823,7 +823,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) if err != nil { temp.Clear() } else { @@ -852,7 +852,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) if err != nil { temp.Clear() } else { diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 08f2b2bfe..0902d17c5 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -49,14 +49,6 @@ var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffff var commonParams []*twoOperandParams var twoOpMethods map[string]executionFunc -type contractRef struct { - addr common.Address -} - -func (c contractRef) Address() common.Address { - return c.addr -} - func init() { // Params is a list of common edgecases that should be used for some common tests params := []string{ @@ -575,8 +567,7 @@ func TestOpTstore(t *testing.T) { mem = NewMemory() caller = common.Address{} to = common.Address{1} - contractRef = contractRef{caller} - contract = NewContract(contractRef, AccountRef(to), new(uint256.Int), 0) + contract = NewContract(caller, to, new(uint256.Int), 0, nil) scopeContext = ScopeContext{mem, stack, contract} value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") ) diff --git a/core/vm/interface.go b/core/vm/interface.go index 0d7862a66..57f35cb24 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -17,8 +17,6 @@ package vm import ( - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/stateless" @@ -104,16 +102,3 @@ type StateDB interface { // Finalise must be invoked at the end of a transaction Finalise(bool) } - -// CallContext provides a basic interface for the EVM calling conventions. The EVM -// depends on this context being implemented for doing subcalls and initialising new EVM contracts. -type CallContext interface { - // Call calls another contract. - Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // CallCode takes another contracts code and execute within our own context - CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // DelegateCall is same as CallCode except sender and value is propagated from parent to child scope - DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) - // Create creates a new contract - Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) -} diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index cacad8f81..0b93dd59e 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -53,7 +53,7 @@ func TestLoopInterrupt(t *testing.T) { timeout := make(chan bool) go func(evm *EVM) { - _, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(uint256.Int)) + _, _, err := evm.Call(common.Address{}, address, nil, math.MaxUint64, new(uint256.Int)) errChannel <- err }(evm) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 2243e14b6..9d984291f 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -128,7 +128,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { var ( address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { @@ -143,7 +142,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { cfg.State.SetCode(address, code) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( - sender, + cfg.Origin, common.BytesToAddress([]byte("contract")), input, cfg.GasLimit, @@ -166,9 +165,8 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) } var ( - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) + vmenv = NewEnv(cfg) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) @@ -179,7 +177,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( - sender, + cfg.Origin, input, cfg.GasLimit, uint256.MustFromBig(cfg.Value), @@ -200,7 +198,6 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er var ( vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) statedb = cfg.State rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) @@ -214,7 +211,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( - sender, + cfg.Origin, address, input, cfg.GasLimit, diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index faad1e719..dbfc7308f 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -33,19 +33,6 @@ import ( "github.com/holiman/uint256" ) -type account struct{} - -func (account) SubBalance(amount *big.Int) {} -func (account) AddBalance(amount *big.Int) {} -func (account) SetAddress(common.Address) {} -func (account) Value() *big.Int { return nil } -func (account) SetBalance(*uint256.Int) {} -func (account) SetNonce(uint64) {} -func (account) Balance() *uint256.Int { return nil } -func (account) Address() common.Address { return common.Address{} } -func (account) SetCode(common.Hash, []byte) {} -func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} - type dummyStatedb struct { state.StateDB } @@ -68,7 +55,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo gasLimit uint64 = 31000 startGas uint64 = 10000 value = uint256.NewInt(0) - contract = vm.NewContract(account{}, account{}, value, startGas) + contract = vm.NewContract(common.Address{}, common.Address{}, value, startGas, nil) ) evm.SetTxContext(vmctx.txCtx) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} @@ -190,7 +177,7 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0), + Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), 0, nil), } evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(1)}) @@ -288,7 +275,7 @@ func TestEnterExit(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0), + Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), 0, nil), } tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) tracer.OnExit(1, []byte{}, 400, nil, false) diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index e7799dde3..b1e38bf62 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -29,22 +29,6 @@ import ( "github.com/holiman/uint256" ) -type dummyContractRef struct { - calledForEach bool -} - -func (dummyContractRef) Address() common.Address { return common.Address{} } -func (dummyContractRef) Value() *big.Int { return new(big.Int) } -func (dummyContractRef) SetCode(common.Hash, []byte) {} -func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) { - d.calledForEach = true -} -func (d *dummyContractRef) SubBalance(amount *big.Int) {} -func (d *dummyContractRef) AddBalance(amount *big.Int) {} -func (d *dummyContractRef) SetBalance(*big.Int) {} -func (d *dummyContractRef) SetNonce(uint64) {} -func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) } - type dummyStatedb struct { state.StateDB } @@ -59,7 +43,7 @@ func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) evm = vm.NewEVM(vm.BlockContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) - contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 100000) + contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 100000, nil) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash diff --git a/tests/state_test.go b/tests/state_test.go index 0c9553c07..e7525118e 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -310,8 +310,7 @@ func runBenchmark(b *testing.B, t *StateTest) { evm.SetTxContext(txContext) // Create "contract" for sender to cache code analysis. - sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From), - nil, 0) + sender := vm.NewContract(msg.From, msg.From, nil, 0, nil) var ( gasUsed uint64 @@ -326,7 +325,7 @@ func runBenchmark(b *testing.B, t *StateTest) { start := time.Now() // Execute the message. - _, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value)) + _, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value)) if err != nil { b.Error(err) return From d55e0bae802e1a7e71e9a2cba8df39d606884b76 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 18 Feb 2025 15:03:48 +0100 Subject: [PATCH 150/354] params: add osaka blob schedule (#31174) Prevents crashes when running execution spec tests for osaka --- consensus/misc/eip4844/eip4844.go | 8 ++++++++ core/genesis_test.go | 1 + params/config.go | 9 +++++++++ tests/init.go | 10 ++++++++++ 4 files changed, 28 insertions(+) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 4a2754b55..32b34f4e5 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -83,6 +83,8 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { var frac uint64 switch config.LatestFork(header.Time) { + case forks.Osaka: + frac = config.BlobScheduleConfig.Osaka.UpdateFraction case forks.Prague: frac = config.BlobScheduleConfig.Prague.UpdateFraction case forks.Cancun: @@ -103,6 +105,8 @@ func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { s = cfg.BlobScheduleConfig ) switch { + case cfg.IsOsaka(london, time) && s.Osaka != nil: + return s.Osaka.Max case cfg.IsPrague(london, time) && s.Prague != nil: return s.Prague.Max case cfg.IsCancun(london, time) && s.Cancun != nil: @@ -125,6 +129,8 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { return 0 } switch { + case s.Osaka != nil: + return s.Osaka.Max case s.Prague != nil: return s.Prague.Max case s.Cancun != nil: @@ -144,6 +150,8 @@ func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { s = cfg.BlobScheduleConfig ) switch { + case cfg.IsOsaka(london, time) && s.Osaka != nil: + return s.Osaka.Target case cfg.IsPrague(london, time) && s.Prague != nil: return s.Prague.Target case cfg.IsCancun(london, time) && s.Cancun != nil: diff --git a/core/genesis_test.go b/core/genesis_test.go index 1c7439122..d023422d1 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -288,6 +288,7 @@ func TestVerkleGenesisCommit(t *testing.T) { BlobScheduleConfig: ¶ms.BlobScheduleConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, Verkle: params.DefaultPragueBlobConfig, }, } diff --git a/params/config.go b/params/config.go index 5b50be0dc..884866e21 100644 --- a/params/config.go +++ b/params/config.go @@ -317,10 +317,17 @@ var ( Max: 9, UpdateFraction: 5007716, } + // DefaultOsakaBlobConfig is the default blob configuration for the Osaka fork. + DefaultOsakaBlobConfig = &BlobConfig{ + Target: 6, + Max: 9, + UpdateFraction: 5007716, + } // DefaultBlobSchedule is the latest configured blob schedule for test chains. DefaultBlobSchedule = &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, Prague: DefaultPragueBlobConfig, + Osaka: DefaultOsakaBlobConfig, } ) @@ -528,6 +535,7 @@ type BlobConfig struct { type BlobScheduleConfig struct { Cancun *BlobConfig `json:"cancun,omitempty"` Prague *BlobConfig `json:"prague,omitempty"` + Osaka *BlobConfig `json:"osaka,omitempty"` Verkle *BlobConfig `json:"verkle,omitempty"` } @@ -777,6 +785,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { }{ {name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun}, {name: "prague", timestamp: c.PragueTime, config: bsc.Prague}, + {name: "osaka", timestamp: c.OsakaTime, config: bsc.Osaka}, } { if cur.config != nil { if err := cur.config.validate(); err != nil { diff --git a/tests/init.go b/tests/init.go index a985879ab..13ceb7205 100644 --- a/tests/init.go +++ b/tests/init.go @@ -451,6 +451,11 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(0), OsakaTime: u64(0), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, + }, }, "PragueToOsakaAtTime15k": { ChainID: big.NewInt(1), @@ -473,6 +478,11 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(0), OsakaTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + BlobScheduleConfig: ¶ms.BlobScheduleConfig{ + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, + }, }, } From 69e39d34637f8e50bbc3434fbe05a43895488b07 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Tue, 18 Feb 2025 15:08:43 -0500 Subject: [PATCH 151/354] eth/catalyst: support earlier forks in SimulatedBeacon (#31084) Co-authored-by: Marius van der Wijden --- eth/catalyst/simulated_beacon.go | 54 +++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index a24ff5210..c71add93b 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -33,6 +33,8 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/params/forks" "github.com/ethereum/go-ethereum/rpc" ) @@ -95,6 +97,16 @@ type SimulatedBeacon struct { lastBlockTime uint64 } +func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion { + switch config.LatestFork(time) { + case forks.Prague, forks.Cancun: + return engine.PayloadV3 + case forks.Paris, forks.Shanghai: + return engine.PayloadV2 + } + panic("invalid fork, simulated beacon needs to be started post-merge") +} + // NewSimulatedBeacon constructs a new simulated beacon chain. func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) { block := eth.BlockChain().CurrentBlock() @@ -107,7 +119,8 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err // if genesis block, send forkchoiceUpdated to trigger transition to PoS if block.Number.Sign() == 0 { - if _, err := engineAPI.ForkchoiceUpdatedV3(current, nil); err != nil { + version := payloadVersion(eth.BlockChain().Config(), block.Time) + if _, err := engineAPI.forkchoiceUpdated(current, nil, version, false); err != nil { return nil, err } } @@ -171,6 +184,8 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u return fmt.Errorf("failed to sync txpool: %w", err) } + version := payloadVersion(c.eth.BlockChain().Config(), timestamp) + var random [32]byte rand.Read(random[:]) fcResponse, err := c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, &engine.PayloadAttributes{ @@ -179,7 +194,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u Withdrawals: withdrawals, Random: random, BeaconRoot: &common.Hash{}, - }, engine.PayloadV3, false) + }, version, false) if err != nil { return err } @@ -204,28 +219,39 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u } } - // Independently calculate the blob hashes from sidecars. - blobHashes := make([]common.Hash, 0) - if envelope.BlobsBundle != nil { - hasher := sha256.New() - for _, commit := range envelope.BlobsBundle.Commitments { - var c kzg4844.Commitment - if len(commit) != len(c) { - return errors.New("invalid commitment length") + var ( + blobHashes []common.Hash + beaconRoot *common.Hash + requests [][]byte + ) + // Compute post-shanghai fields + if version > engine.PayloadV2 { + // Independently calculate the blob hashes from sidecars. + blobHashes = make([]common.Hash, 0) + if envelope.BlobsBundle != nil { + hasher := sha256.New() + for _, commit := range envelope.BlobsBundle.Commitments { + var c kzg4844.Commitment + if len(commit) != len(c) { + return errors.New("invalid commitment length") + } + copy(c[:], commit) + blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c)) } - copy(c[:], commit) - blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c)) } + beaconRoot = &common.Hash{} + requests = envelope.Requests } + // Mark the payload as canon - _, err = c.engineAPI.newPayload(*payload, blobHashes, &common.Hash{}, envelope.Requests, false) + _, err = c.engineAPI.newPayload(*payload, blobHashes, beaconRoot, requests, false) if err != nil { return err } c.setCurrentState(payload.BlockHash, finalizedHash) // Mark the block containing the payload as canonical - if _, err = c.engineAPI.ForkchoiceUpdatedV3(c.curForkchoiceState, nil); err != nil { + if _, err = c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, nil, version, false); err != nil { return err } c.lastBlockTime = payload.Timestamp From eb45c52878e09e6a520bfcb6b828cdb335b32b3f Mon Sep 17 00:00:00 2001 From: levisyin Date: Wed, 19 Feb 2025 18:21:22 +0800 Subject: [PATCH 152/354] build: upgrade -dlgo version to Go 1.24.0 (#31159) Co-authored-by: Felix Lange --- .github/workflows/go.yml | 4 +- .travis.yml | 14 ++-- Dockerfile | 2 +- Dockerfile.alltools | 2 +- build/checksums.txt | 173 ++++++++++++++++++++++----------------- go.mod | 2 - 6 files changed, 111 insertions(+), 86 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d1d2579df..90449ef30 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.23.0 + go-version: 1.24.0 cache: false - name: Run linters @@ -39,7 +39,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.23.0 + go-version: 1.24.0 cache: false - name: Run tests run: go test -short ./... diff --git a/.travis.yml b/.travis.yml index 8953450e8..5e8a493d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ jobs: os: linux arch: amd64 dist: focal - go: 1.23.x + go: 1.24.x env: - docker services: @@ -33,7 +33,7 @@ jobs: os: linux dist: focal sudo: required - go: 1.23.x + go: 1.24.x env: - azure-linux git: @@ -85,7 +85,7 @@ jobs: os: linux arch: amd64 dist: focal - go: 1.23.x + go: 1.24.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -93,7 +93,7 @@ jobs: if: type = push os: linux dist: focal - go: 1.22.x + go: 1.23.x script: - travis_wait 45 go run build/ci.go test $TEST_PACKAGES @@ -102,7 +102,7 @@ jobs: if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: focal - go: 1.23.x + go: 1.24.x env: - ubuntu-ppa git: @@ -118,7 +118,7 @@ jobs: if: type = cron os: linux dist: focal - go: 1.23.x + go: 1.24.x env: - azure-purge git: @@ -131,7 +131,7 @@ jobs: if: type = cron os: linux dist: focal - go: 1.23.x + go: 1.24.x env: - racetests script: diff --git a/Dockerfile b/Dockerfile index ff89e92f2..9b70e9e8a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.23-alpine AS builder +FROM golang:1.24-alpine AS builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index 44d5065af..ac9303c67 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.23-alpine AS builder +FROM golang:1.24-alpine AS builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/build/checksums.txt b/build/checksums.txt index 76f05e5b6..1646cc6c4 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,82 +5,109 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/fixtures_pectra-devnet-6.tar.gz b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz -# version:golang 1.23.6 +# version:golang 1.24.0 # https://go.dev/dl/ -039c5b04e65279daceee8a6f71e70bd05cf5b801782b6f77c6e19e2ed0511222 go1.23.6.src.tar.gz -adec10f4ba56591f523aa04851f7f6900b1c61508dfa6b80e62717a8e6684a5c go1.23.6.aix-ppc64.tar.gz -782da50ce8ec5e98fac2cd3cdc6a1d7130d093294fc310038f651444232a3fb0 go1.23.6.darwin-amd64.tar.gz -5cae2450a1708aeb0333237a155640d5562abaf195defebc4306054565536221 go1.23.6.darwin-arm64.tar.gz -d52efb3020d9332477ade98163c03d2f2fe3e051b0e7e01f0e167412c66de0cb go1.23.6.dragonfly-amd64.tar.gz -d3287706b5823712ac6cf7dff684a556cff98163ef60e7b275abe3388c17aac7 go1.23.6.freebsd-386.tar.gz -ebb4c6a9b0673dbdabc439877779ed6add16575e21bd0a7955c33f692789aef6 go1.23.6.freebsd-amd64.tar.gz -b7241584afb0b161c09148f8fde16171bb743e47b99d451fbc5f5217ec7a88b6 go1.23.6.freebsd-arm.tar.gz -004718b53cedd7955d1b1dc4053539fcd1053c031f5f3374334a22befd1f8310 go1.23.6.freebsd-arm64.tar.gz -ca026ec8a30dd0c18164f40e1ce21bd725e2445f11699177d05815189a38de7a go1.23.6.freebsd-riscv64.tar.gz -7db973efa3fb2e48e45059b855721550fce8e90803e7373d3efd37b88dd821e8 go1.23.6.illumos-amd64.tar.gz -e61f87693169c0bbcc43363128f1e929b9dff0b7f448573f1bdd4e4a0b9687ba go1.23.6.linux-386.tar.gz -9379441ea310de000f33a4dc767bd966e72ab2826270e038e78b2c53c2e7802d go1.23.6.linux-amd64.tar.gz -561c780e8f4a8955d32bf72e46af0b5ee5e0debe1e4633df9a03781878219202 go1.23.6.linux-arm64.tar.gz -27a4611010c16b8c4f37ade3aada55bd5781998f02f348b164302fd5eea4eb74 go1.23.6.linux-armv6l.tar.gz -c459226424372abc2b35957cc8955dad348330714f7605093325dbb73e33c750 go1.23.6.linux-loong64.tar.gz -e2a0aff70b958a3463a7d47132a2d0238369f64578d4f7f95e679e3a5af05622 go1.23.6.linux-mips.tar.gz -7d30ec7db056311d420bf930c16abcae13c0f41c26a202868f279721ec3c2f2f go1.23.6.linux-mips64.tar.gz -74ca7bc475bcc084c6718b74df024d7de9612932cea8a6dc75e29d3a5315a23a go1.23.6.linux-mips64le.tar.gz -09bf935a14e9f59a20499989438b1655453480016bdbcb10406acf4df2678ccb go1.23.6.linux-mipsle.tar.gz -5cb2f6a5090276c72c5eda8a55896f5a3d6ea0f28d10fa1a50e8318640f02d6c go1.23.6.linux-ppc64.tar.gz -0f817201e83d78ddbfa27f5f78d9b72450b92cc21d5e045145efacd0d3244a99 go1.23.6.linux-ppc64le.tar.gz -f95f7f817ab22ecab4503d0704d6449ea1aa26a595f57bf9b9f94ddf2aa7c1f3 go1.23.6.linux-riscv64.tar.gz -321e7ed0d5416f731479c52fa7610b52b8079a8061967bd48cec6d66f671a60e go1.23.6.linux-s390x.tar.gz -92d678fb8e1eeeb8c6af6f22e4e5494652dcbb4a320113fc08325cb9956a2d4c go1.23.6.netbsd-386.tar.gz -86ba51e7bb26b30ea6a8d88ddb79d8e8c83b4116200040ecb7a5a44cf90a8c5c go1.23.6.netbsd-amd64.tar.gz -4b974c35345100f0be6ea66afab2781de91ee9882117314126eaf0ae90fd3816 go1.23.6.netbsd-arm.tar.gz -53e3589fc38e787a493ea038961f8e40803714dbb42754c1713b00099c12e9b9 go1.23.6.netbsd-arm64.tar.gz -6d2317b3a8505ccebff8f72d943f2ac9b82c115632e54a53a786eff24ced56d9 go1.23.6.openbsd-386.tar.gz -f699e707d95a984fcc00361d91aecdb413d3c75e18235156ffba7a89edf68aae go1.23.6.openbsd-amd64.tar.gz -3c1cf6ab893657d0bf1942e40ce115acfd27cbce1ccb9bc88fd9cd21ca3d489f go1.23.6.openbsd-arm.tar.gz -cc0875535d14001f2da23ae9af89025b28c466e8f4f4c63f991ebb6f4b02f66c go1.23.6.openbsd-arm64.tar.gz -64de80e29ca66cb566cbf8be030bf8599953af4e48402eab724cbe0a08b40602 go1.23.6.openbsd-ppc64.tar.gz -c398a6b43c569f34bb4a2d16b52f8010eaac9a2a82ecac0602b4338e35cef377 go1.23.6.openbsd-riscv64.tar.gz -10998b6b130bb7b542b407f0db42b86a913b111f8fa86d44394beaace4d45f01 go1.23.6.plan9-386.tar.gz -9fbe8065436d8d12c02f19f64f51c9107da3a7a4ac46ab5777e182e9fe88c32f go1.23.6.plan9-amd64.tar.gz -8e3c826b884daee2de37e3b070d7eac4cea5d68edab8db09910e22201c75db83 go1.23.6.plan9-arm.tar.gz -b619eff63fec86daaea92ca170559e448a58b8ba0b92eef1971bc14e92ea86a7 go1.23.6.solaris-amd64.tar.gz -96820c0f5d464dd694543329e9b4d413b17c821c03a055717a29e6735b44c2d8 go1.23.6.windows-386.zip -53fec1586850b2cf5ad6438341ff7adc5f6700dd3ec1cfa3f5e8b141df190243 go1.23.6.windows-amd64.zip -22c2518c45c20018afa20d5376dc9fd7a7e74367240ed7b5209e79a30b5c4218 go1.23.6.windows-arm.zip -a2d2ec1b3759552bdd9cdf58858f91dfbfd6ab3a472f00b5255acbed30b1aa41 go1.23.6.windows-arm64.zip +d14120614acb29d12bcab72bd689f257eb4be9e0b6f88a8fb7e41ac65f8556e5 go1.24.0.src.tar.gz +5d04588154d5923bd8e26b76111806340ec55c41af1b05623ea744fcb3d6bc22 go1.24.0.aix-ppc64.tar.gz +7af054e5088b68c24b3d6e135e5ca8d91bbd5a05cb7f7f0187367b3e6e9e05ee go1.24.0.darwin-amd64.tar.gz +dee0ea64411a00b47ded586d5a8e30cfe3acf51564aa1bb24e039a6dca807a29 go1.24.0.darwin-amd64.pkg +fd9cfb5dd6c75a347cfc641a253f0db1cebaca16b0dd37965351c6184ba595e4 go1.24.0.darwin-arm64.tar.gz +b19eb6b7ae87f8371c3e7a84d129db67779a2883d2fffa6bb90412b0167df133 go1.24.0.darwin-arm64.pkg +d0dc34ad86aea746abe245994c68a9e1ad8f46ba8c4af901cd5861a4dd4c21df go1.24.0.dragonfly-amd64.tar.gz +4ee02b1f3812aff4da79c79464ee4038ca61ad74b3a9619850f30435f81c2536 go1.24.0.freebsd-386.tar.gz +838191001f9324da904dece35a586a3156d548687db87ac9461aa3d38fc88b09 go1.24.0.freebsd-amd64.tar.gz +ce6ad4e84a40a8a1d848b7e31b0cddfd1cee8f7959e7dc358a8fa8b5566ea718 go1.24.0.freebsd-arm.tar.gz +511f7b0cac4c4ed1066d324072ce223b906ad6b2a85f2e1c5d260eb7d08b5901 go1.24.0.freebsd-arm64.tar.gz +a1e4072630dc589a2975ef51317b52c7d8599bf6f389fc59033c01e0a0fa705a go1.24.0.freebsd-riscv64.tar.gz +7593e9dcee9f07c3df6d099f7d259f5734a6c0dccc5f28962f18e7f501c9bb21 go1.24.0.illumos-amd64.tar.gz +90521453a59c6ce20364d2dc7c38532949b033b602ba12d782caeb90af1b0624 go1.24.0.linux-386.tar.gz +dea9ca38a0b852a74e81c26134671af7c0fbe65d81b0dc1c5bfe22cf7d4c8858 go1.24.0.linux-amd64.tar.gz +c3fa6d16ffa261091a5617145553c71d21435ce547e44cc6dfb7470865527cc7 go1.24.0.linux-arm64.tar.gz +695dc54fa14cd3124fa6900d7b5ae39eeac23f7a4ecea81656070160fac2c54a go1.24.0.linux-armv6l.tar.gz +a201e4c9b7e6d29ed64c43296ed88e81a66f82f2093ce45b766d2c526941396f go1.24.0.linux-loong64.tar.gz +f3ac039aae78ad0bfb08106406c2e62eaf763dd82ebaf0ecd539adadd1d729a6 go1.24.0.linux-mips.tar.gz +f2e6456d45e024831b1da8d88b1bb6392cca9500c1b00841f525d76c9e9553e0 go1.24.0.linux-mips64.tar.gz +b847893ff119389c939adc2b8516b6500204b7cb49d5e19b25e1c2091d2c74c6 go1.24.0.linux-mips64le.tar.gz +bd4aed27d02746c237c3921e97029ac6b6fe687a67436b8f52ff1f698d330bd9 go1.24.0.linux-mipsle.tar.gz +007123c9b06c41729a4bb3f166f4df7196adf4e33c2d2ab0e7e990175f0ce1d4 go1.24.0.linux-ppc64.tar.gz +a871a43de7d26c91dd90cb6e0adacb214c9e35ee2188c617c91c08c017efe81a go1.24.0.linux-ppc64le.tar.gz +620dcf48c6297519aad6c81f8e344926dc0ab09a2a79f1e306964aece95a553d go1.24.0.linux-riscv64.tar.gz +544d78b077c6b54bf78958c4a8285abec2d21f668fb007261c77418cd2edbb46 go1.24.0.linux-s390x.tar.gz +8b143a7edefbaa2a0b0246c9df2df1bac9fbed909d8615a375c08da7744e697d go1.24.0.netbsd-386.tar.gz +67150a6dd7bdb9c4e88d77f46ee8c4dc99d5e71deca4912d8c2c85f7a16d0262 go1.24.0.netbsd-amd64.tar.gz +446b2539f11218fd6f6f6e3dd90b20ae55a06afe129885eeb3df51eb344eb0f6 go1.24.0.netbsd-arm.tar.gz +370115b6ff7d30b29431223de348eb11ab65e3c92627532d97fd55f63f94e7a8 go1.24.0.netbsd-arm64.tar.gz +cbda5f15f06ed9630f122a53542d9de13d149643633c74f1dcb45e79649b788a go1.24.0.openbsd-386.tar.gz +926f601d0e655ab1e8d7f357fd82542e5cf206c38c4e2f9fccf0706987d38836 go1.24.0.openbsd-amd64.tar.gz +8a54892f8c933c541fff144a825d0fdc41bae14b0832aab703cb75eb4cb64f2c go1.24.0.openbsd-arm.tar.gz +ef7fddcef0a22c7900c178b7687cf5aa25c2a9d46a3cc330b77a6de6e6c2396b go1.24.0.openbsd-arm64.tar.gz +b3b5e2e2b53489ded2c2c21900ddcbbdb7991632bb5b42f05f125d71675e0b76 go1.24.0.openbsd-ppc64.tar.gz +fbcb1dbf1269b4079dc4fd0b15f3274b9d635f1a7e319c3fc1a907b03280348e go1.24.0.openbsd-riscv64.tar.gz +33b4221e1c174a16e3f661deab6c60838ac4ae6cb869a4da1d1115773ceed88b go1.24.0.plan9-386.tar.gz +111a89014019cdbd69c2978de9b3e201f77e35183c8ab3606fba339d38f28549 go1.24.0.plan9-amd64.tar.gz +8da3d3997049f40ebe0cd336a9bb9e4bfa4832df3c90a32f07383371d6d74849 go1.24.0.plan9-arm.tar.gz +b6069da21dc95ccdbd047675b584e5480ffc3eba35f9e7c8b0e7b317aaf01e2c go1.24.0.solaris-amd64.tar.gz +b53c28a4c2863ec50ab4a1dbebe818ef6177f86773b6f43475d40a5d9aa4ec9e go1.24.0.windows-386.zip +f07677013cd7861c5e16067b0a82144c23c4bf72c139c762e142440f4c926f61 go1.24.0.windows-386.msi +96b7280979205813759ee6947be7e3bb497da85c482711116c00522e3bb41ff1 go1.24.0.windows-amd64.zip +4e78016d889431eb16aa0f87868cf52479b90059791c94a4ff45872d0573089e go1.24.0.windows-amd64.msi +53f73450fb66075d16be9f206e9177bd972b528168271918c4747903b5596c3d go1.24.0.windows-arm64.zip +4f9780158fb7996dcbcbc7c7ef208f880b5e8c1f2792ba3ede0c75050c1bc23a go1.24.0.windows-arm64.msi -# version:golangci 1.63.4 +# version:golangci 1.64.4 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.63.4/ -878d017cc360e4fb19510d39852c8189852e3c48e7ce0337577df73507c97d68 golangci-lint-1.63.4-darwin-amd64.tar.gz -a2b630c2ac8466393f0ccbbede4462387b6c190697a70bc2298c6d2123f21bbf golangci-lint-1.63.4-darwin-arm64.tar.gz -8938b74aa92888e561a1c5a4c175110b92f84e7d24733703e6d9ebc39e9cd5f8 golangci-lint-1.63.4-freebsd-386.tar.gz -054903339d620df2e760b978920100986e3b03bcb058f669d520a71dac9c34ed golangci-lint-1.63.4-freebsd-amd64.tar.gz -a19d499f961a02608348e8b626537a88edfaab6e1b6534f1eff742b5d6d750e4 golangci-lint-1.63.4-freebsd-armv6.tar.gz -00d616f0fb275b780ce4d26604bdd7fdbfe6bc9c63acd5a0b31498e1f7511108 golangci-lint-1.63.4-freebsd-armv7.tar.gz -d453688e0eabded3c1a97ff5a2777bb0df5a18851efdaaaf6b472e3e5713c33e golangci-lint-1.63.4-illumos-amd64.tar.gz -6b1bec847fc9f347d53712d05606a49d55d0e3b5c1bacadfed2393f3503de0e9 golangci-lint-1.63.4-linux-386.tar.gz -01abb14a4df47b5ca585eff3c34b105023cba92ec34ff17212dbb83855581690 golangci-lint-1.63.4-linux-amd64.tar.gz -51f0c79d19a92353e0465fb30a4901a0644a975d34e6f399ad2eebc0160bbb24 golangci-lint-1.63.4-linux-arm64.tar.gz -8d0a43f41e8424fbae10f7aa2dc29999f98112817c6dba63d7dc76832940a673 golangci-lint-1.63.4-linux-armv6.tar.gz -1045a047b31e9302c9160c7b0f199f4ac1bd02a1b221a2d9521bd3507f0cf671 golangci-lint-1.63.4-linux-armv7.tar.gz -933fe10ab50ce3bb0806e15a4ae69fe20f0549abf91dea0161236000ca706e67 golangci-lint-1.63.4-linux-loong64.tar.gz -45798630cbad5642862766051199fa862ef3c33d569cab12f01cac4f68e2ddd5 golangci-lint-1.63.4-linux-mips64.tar.gz -86ae25335ddb24975d2c915c1af0c7fad70dce99d0b4614fa4bee392de714aa2 golangci-lint-1.63.4-linux-mips64le.tar.gz -33dabd11aaba4b602938da98bcf49aabab55019557e0115cdc3dbcc3009768fa golangci-lint-1.63.4-linux-ppc64le.tar.gz -4e7a81230a663bcdf30bba5689ce96040abc76994dbc2003dce32c8dca8c06f3 golangci-lint-1.63.4-linux-riscv64.tar.gz -21370b49c7c47f4d9b8f982c952f940b01e65710174c3b4dad7b6452d58f92ec golangci-lint-1.63.4-linux-s390x.tar.gz -255866a6464c7e11bb7edd8e6e6ad54f11e1f01b82ba9ca229698ac788cd9724 golangci-lint-1.63.4-netbsd-386.tar.gz -2798c040ac658bda97224f204795199c81ac97bb207b21c02b664aaed380d5d2 golangci-lint-1.63.4-netbsd-amd64.tar.gz -b910eecffd0064103837e7e1abe870deb8ade22331e6dffe319f430d49399c8e golangci-lint-1.63.4-netbsd-arm64.tar.gz -df2693ef37147b457c3e2089614537dd2ae2e18e53641e756a5b404f4c72d3fa golangci-lint-1.63.4-netbsd-armv6.tar.gz -a28a533366974bd7834c4516cd6075bff3419a508d1ed7aa63ae8182768b352e golangci-lint-1.63.4-netbsd-armv7.tar.gz -368932775fb5c620b324dabf018155f3365f5e33c5af5b26e9321db373f96eea golangci-lint-1.63.4-windows-386.zip -184d13c2b8f5441576bec2a0d8ba7b2d45445595cf796b879a73bcc98c39f8c1 golangci-lint-1.63.4-windows-amd64.zip -4fabf175d5b05ef0858ded49527948eebac50e9093814979fd84555a75fb80a6 golangci-lint-1.63.4-windows-arm64.zip -e92be3f3ff30d4a849fb4b9a4c8d56837dee45269cb405a3ecad52fa034c781b golangci-lint-1.63.4-windows-armv6.zip -c71d348653b8f7fbb109bb10c1a481722bc6b0b2b6e731b897f99ac869f7653e golangci-lint-1.63.4-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.64.4/ +f31ef6e20c62acc31eb7b851d611b4bd10256d1b1d8be38f0cceec300b5b60db golangci-lint-1.64.4-darwin-amd64.tar.gz +bb4a9ece7ef66ef49bd6de873f5f5ec801cf93dacf58efb360cc939b4fd37c47 golangci-lint-1.64.4-darwin-arm64.tar.gz +fd8f9046150356e36ad8af31f99219515d5e0ff6e8e9f4204182312447018fcf golangci-lint-1.64.4-freebsd-386.tar.gz +bbae940caa31cb1d2d8d26abd867666cd92746d2ddc63d6917d128c456d715ef golangci-lint-1.64.4-freebsd-amd64.tar.gz +86eb00cbdc5e277857a380d556d78a42b3edf8aae5991de8767dce7da337d73b golangci-lint-1.64.4-freebsd-armv6.tar.gz +c0f7d50f4fcd39ae8bda181c127b078a79d87c885ac472c4cce5b01134dde5bc golangci-lint-1.64.4-freebsd-armv7.tar.gz +31d264fa26a73a583425bc9b39c18de70a330e346fe800e80c277ddb5f8477b6 golangci-lint-1.64.4-illumos-amd64.tar.gz +3dccc18a6b1a0f2518196190ed56277b1480b381231605936eca6b862426b83c golangci-lint-1.64.4-linux-386.deb +b95f3e757c59ada75144bd086478ab63bcda83c2b2a935e60d8f39aff20fbcd2 golangci-lint-1.64.4-linux-386.rpm +8fa58af0022ae0487162c02d08075e2d869c9b5f8613a64b85fd769a2a2d2b93 golangci-lint-1.64.4-linux-386.tar.gz +fa80d2ad920fc74b85a0b93ad1671fd27c9c4d6f22e167cc4e1da758d72dd893 golangci-lint-1.64.4-linux-amd64.deb +8bf2e3c82504a893a12e84ecbc8071f787075d2fdc1ef946deda3d29aae1afad golangci-lint-1.64.4-linux-amd64.rpm +7de8f80a12cd3052610e6be21f08f2220805b1f3e43b3b6ec843f14a12140de2 golangci-lint-1.64.4-linux-amd64.tar.gz +ade222b9ae997a2875e44ed53ca5a129f24944b232132d0a5898f101381d3bfa golangci-lint-1.64.4-linux-arm64.deb +8f9f8617ed0d8b8f62c8dfe69877932c0d85f0d83a9ec3250b04777c7133ada1 golangci-lint-1.64.4-linux-arm64.rpm +debf1f73e71f1dd288957574eab4e7515b1b04c4ac2f127192181da8a42f0e8e golangci-lint-1.64.4-linux-arm64.tar.gz +3f616caa4a16738114ad29076a333c62bb0650fe4846b438c341d235f78ee5aa golangci-lint-1.64.4-linux-armv6.deb +6a7c9d7b7c57d7d440e1e3f133e18e4b5b703604d4ae7f7862fb9ea461887a8b golangci-lint-1.64.4-linux-armv6.rpm +d7b9e3c89af93d98c6b5a555ef48e25bee24f84d7825a29e343e9966404d5b4d golangci-lint-1.64.4-linux-armv6.tar.gz +18179ecf04ace3051450852424b31a4d26644a3912e759cd595e624eee0174bd golangci-lint-1.64.4-linux-armv7.deb +f669fce85d3edc3d557d1e64e2241d895f1ee676f79d139874bf76693cc447a2 golangci-lint-1.64.4-linux-armv7.rpm +9bbaa13b474ecb1560fb05aee0a8cab3e9cc327d41632bee8b553b766f2bf756 golangci-lint-1.64.4-linux-armv7.tar.gz +b5a2725adba2a1b04a5160ffa0730ba30b88c1ee99ecbc65dd7075a8d70f3730 golangci-lint-1.64.4-linux-loong64.deb +28ac00afb3f6407808fe7c15a6002e5fe6b3b461df3fe0223603542e6f9b974a golangci-lint-1.64.4-linux-loong64.rpm +121170309fed82cb64d6fae5020ef2b194e591a53156370c221a80121cc4aa08 golangci-lint-1.64.4-linux-loong64.tar.gz +aadfaab41380f53ada8f7ad4fa9af784bb882eaaa1e3939e048b3a5ea8f2c13f golangci-lint-1.64.4-linux-mips64.deb +6fecbff69086e316dd028050d3ebf82fc466c7f4dc0f6084307054621101c202 golangci-lint-1.64.4-linux-mips64.rpm +430c48034527af028dc608c115166f47b6b67c8cb83a317d9d44876b9753292a golangci-lint-1.64.4-linux-mips64.tar.gz +432126af2bbbd639dbbcc2c265337f104cc613a7b4c5a8fb5e49f182b428f077 golangci-lint-1.64.4-linux-mips64le.deb +cfa663eee0fae721510d6dc31e61db4be51b4e4244eb7de2b6a9bc6d475551e5 golangci-lint-1.64.4-linux-mips64le.rpm +2bacfac65182893c5ceb67b61d5b9d2b24da47726d84cb87d734a6e32f040148 golangci-lint-1.64.4-linux-mips64le.tar.gz +66d86e47d68420c03045eff0698e9acf9f82d97cd1f07d7e52837a6e544eceed golangci-lint-1.64.4-linux-ppc64le.deb +05466bd2d8e82f7245b838e29d0c90cdbaf67375b2b5bc980d8510d5edb206ad golangci-lint-1.64.4-linux-ppc64le.rpm +e013b6980f7140712af0aedc9a661265e1d3c6adc7e9d045734e3686a3601acc golangci-lint-1.64.4-linux-ppc64le.tar.gz +753980d2fb421d35292b71b51f9bb0552f18de2eb181ccf692ef79e086ad2304 golangci-lint-1.64.4-linux-riscv64.deb +73a33a883020298f8c652a4ace4f6888103d80d411fe3e9b77ce0a3b36ff7d3a golangci-lint-1.64.4-linux-riscv64.rpm +020efd09b894dc75012f43b1d4c58e69e5446ca3f79845b5e10a02588def3e1b golangci-lint-1.64.4-linux-riscv64.tar.gz +4d99a16bc9ff5cea5e4ae3568c6254390fbdad8f1d370c287744409112bceff9 golangci-lint-1.64.4-linux-s390x.deb +6e63374a9f95fc09f2bb9501059eb18b8107e08416722ba7b561ae385d80b33b golangci-lint-1.64.4-linux-s390x.rpm +62a6febb892b26eee84a32cc99d04afe90bf62d0970774b1bab75e36b66f53b4 golangci-lint-1.64.4-linux-s390x.tar.gz +5ba4d235f9abd60d2d280f9fe4228c6ddab11ae9fe48d253b7e477046675f1f6 golangci-lint-1.64.4-netbsd-386.tar.gz +061643bb4370a52010e5e76f88f5b5220e51058df50af86b45286263af92b321 golangci-lint-1.64.4-netbsd-amd64.tar.gz +12b2be6c35bcf7a36374e952c7efec7905a17fa3ebe6214924ba8721b766c4af golangci-lint-1.64.4-netbsd-arm64.tar.gz +553a71a677751dccee082ed8afe24cf58bef725f72aa02aedcc6758dd8f44125 golangci-lint-1.64.4-netbsd-armv6.tar.gz +74a5a5a7b8c8cd11dccdec303ee6592d904b09836782e6d658be359737f300ef golangci-lint-1.64.4-netbsd-armv7.tar.gz +b3ceea2187843f9ba6510303141a72465621e3f190a262c0b48707b9e983ea9a golangci-lint-1.64.4-source.tar.gz +fda4de312fcb0b4853b03bcdfb31ac631a68fa0b966f6aa010eb30d14427180b golangci-lint-1.64.4-windows-386.zip +8fc60bd809f86c6431ed8f3d1f25917538c0ebc93e670cfb199f25bbaa56e602 golangci-lint-1.64.4-windows-amd64.zip +b9058c9d2ae8d75048c6ad8885d11e5ac0a6c40be2af85bfa6605e48d69d3eb6 golangci-lint-1.64.4-windows-arm64.zip +809b0131adb1aa8b359becd13222df367b505bc2955bb3b1d2d0dd6f07347b13 golangci-lint-1.64.4-windows-armv6.zip +fc43f8c95d6bec8ba9a3557a0bb63cf9f504137ce6d24cfdc4c330d46f7779d2 golangci-lint-1.64.4-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # diff --git a/go.mod b/go.mod index 65c7d5b1e..fbf852628 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/ethereum/go-ethereum go 1.23.0 -toolchain go1.23.1 - require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 github.com/Microsoft/go-winio v0.6.2 From 22a4ced35e36592491b18bd878788a3d5dc68394 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 19 Feb 2025 14:57:08 +0100 Subject: [PATCH 153/354] core/asm: delete assembler/disassembler (#31211) I maintain an improved version of the go-ethereum assembler at https://github.com/fjl/geas. We don't really use core/asm in our tests, and it has some bugs that prevent it from being useful, so I'm removing the package. --- core/asm/asm.go | 156 ----------------- core/asm/asm_test.go | 94 ---------- core/asm/compiler.go | 292 -------------------------------- core/asm/compiler_test.go | 79 --------- core/asm/lex_test.go | 93 ---------- core/asm/lexer.go | 275 ------------------------------ core/asm/tokentype_string.go | 31 ---- core/vm/runtime/runtime_test.go | 15 +- 8 files changed, 1 insertion(+), 1034 deletions(-) delete mode 100644 core/asm/asm.go delete mode 100644 core/asm/asm_test.go delete mode 100644 core/asm/compiler.go delete mode 100644 core/asm/compiler_test.go delete mode 100644 core/asm/lex_test.go delete mode 100644 core/asm/lexer.go delete mode 100644 core/asm/tokentype_string.go diff --git a/core/asm/asm.go b/core/asm/asm.go deleted file mode 100644 index f4b59f447..000000000 --- a/core/asm/asm.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2017 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 . - -// Package asm provides support for dealing with EVM assembly instructions (e.g., disassembling them). -package asm - -import ( - "encoding/hex" - "fmt" - - "github.com/ethereum/go-ethereum/core/vm" -) - -// Iterator for disassembled EVM instructions -type instructionIterator struct { - code []byte - pc uint64 - arg []byte - op vm.OpCode - error error - started bool - eofEnabled bool -} - -// NewInstructionIterator creates a new instruction iterator. -func NewInstructionIterator(code []byte) *instructionIterator { - it := new(instructionIterator) - it.code = code - return it -} - -// NewEOFInstructionIterator creates a new instruction iterator for EOF-code. -func NewEOFInstructionIterator(code []byte) *instructionIterator { - it := NewInstructionIterator(code) - it.eofEnabled = true - return it -} - -// Next returns true if there is a next instruction and moves on. -func (it *instructionIterator) Next() bool { - if it.error != nil || uint64(len(it.code)) <= it.pc { - // We previously reached an error or the end. - return false - } - - if it.started { - // Since the iteration has been already started we move to the next instruction. - if it.arg != nil { - it.pc += uint64(len(it.arg)) - } - it.pc++ - } else { - // We start the iteration from the first instruction. - it.started = true - } - - if uint64(len(it.code)) <= it.pc { - // We reached the end. - return false - } - it.op = vm.OpCode(it.code[it.pc]) - var a int - if !it.eofEnabled { // Legacy code - if it.op.IsPush() { - a = int(it.op) - int(vm.PUSH0) - } - } else { // EOF code - if it.op == vm.RJUMPV { - // RJUMPV is unique as it has a variable sized operand. The total size is - // determined by the count byte which immediately follows RJUMPV. - maxIndex := int(it.code[it.pc+1]) - a = (maxIndex+1)*2 + 1 - } else { - a = vm.Immediates(it.op) - } - } - if a > 0 { - u := it.pc + 1 + uint64(a) - if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u { - it.error = fmt.Errorf("incomplete instruction at %v", it.pc) - return false - } - it.arg = it.code[it.pc+1 : u] - } else { - it.arg = nil - } - return true -} - -// Error returns any error that may have been encountered. -func (it *instructionIterator) Error() error { - return it.error -} - -// PC returns the PC of the current instruction. -func (it *instructionIterator) PC() uint64 { - return it.pc -} - -// Op returns the opcode of the current instruction. -func (it *instructionIterator) Op() vm.OpCode { - return it.op -} - -// Arg returns the argument of the current instruction. -func (it *instructionIterator) Arg() []byte { - return it.arg -} - -// PrintDisassembled pretty-print all disassembled EVM instructions to stdout. -func PrintDisassembled(code string) error { - script, err := hex.DecodeString(code) - if err != nil { - return err - } - it := NewInstructionIterator(script) - for it.Next() { - if it.Arg() != nil && 0 < len(it.Arg()) { - fmt.Printf("%05x: %v %#x\n", it.PC(), it.Op(), it.Arg()) - } else { - fmt.Printf("%05x: %v\n", it.PC(), it.Op()) - } - } - return it.Error() -} - -// Disassemble returns all disassembled EVM instructions in human-readable format. -func Disassemble(script []byte) ([]string, error) { - instrs := make([]string, 0) - - it := NewInstructionIterator(script) - for it.Next() { - if it.Arg() != nil && 0 < len(it.Arg()) { - instrs = append(instrs, fmt.Sprintf("%05x: %v %#x\n", it.PC(), it.Op(), it.Arg())) - } else { - instrs = append(instrs, fmt.Sprintf("%05x: %v\n", it.PC(), it.Op())) - } - } - if err := it.Error(); err != nil { - return nil, err - } - return instrs, nil -} diff --git a/core/asm/asm_test.go b/core/asm/asm_test.go deleted file mode 100644 index 50fe9e122..000000000 --- a/core/asm/asm_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2017 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 . - -package asm - -import ( - "encoding/hex" - "fmt" - "strings" - "testing" -) - -// Tests disassembling instructions -func TestInstructionIterator(t *testing.T) { - for i, tc := range []struct { - code string - legacyWant string - eofWant string - }{ - {"", "", ""}, // empty - {"6100", `err: incomplete instruction at 0`, `err: incomplete instruction at 0`}, - {"61000000", ` -00000: PUSH2 0x0000 -00003: STOP`, ` -00000: PUSH2 0x0000 -00003: STOP`}, - {"5F00", ` -00000: PUSH0 -00001: STOP`, ` -00000: PUSH0 -00001: STOP`}, - {"d1aabb00", `00000: DATALOADN -00001: opcode 0xaa not defined -00002: opcode 0xbb not defined -00003: STOP`, ` -00000: DATALOADN 0xaabb -00003: STOP`}, // DATALOADN(aabb),STOP - {"d1aa", ` -00000: DATALOADN -00001: opcode 0xaa not defined`, "err: incomplete instruction at 0\n"}, // DATALOADN(aa) invalid - {"e20211223344556600", ` -00000: RJUMPV -00001: MUL -00002: GT -00003: opcode 0x22 not defined -00004: CALLER -00005: DIFFICULTY -00006: SSTORE -err: incomplete instruction at 7`, ` -00000: RJUMPV 0x02112233445566 -00008: STOP`}, // RJUMPV( 6 bytes), STOP - - } { - var ( - code, _ = hex.DecodeString(tc.code) - legacy = strings.TrimSpace(disassembly(NewInstructionIterator(code))) - eof = strings.TrimSpace(disassembly(NewEOFInstructionIterator(code))) - ) - if want := strings.TrimSpace(tc.legacyWant); legacy != want { - t.Errorf("test %d: wrong (legacy) output. have:\n%q\nwant:\n%q\n", i, legacy, want) - } - if want := strings.TrimSpace(tc.eofWant); eof != want { - t.Errorf("test %d: wrong (eof) output. have:\n%q\nwant:\n%q\n", i, eof, want) - } - } -} - -func disassembly(it *instructionIterator) string { - var out = new(strings.Builder) - for it.Next() { - if it.Arg() != nil && 0 < len(it.Arg()) { - fmt.Fprintf(out, "%05x: %v %#x\n", it.PC(), it.Op(), it.Arg()) - } else { - fmt.Fprintf(out, "%05x: %v\n", it.PC(), it.Op()) - } - } - if err := it.Error(); err != nil { - fmt.Fprintf(out, "err: %v\n", err) - } - return out.String() -} diff --git a/core/asm/compiler.go b/core/asm/compiler.go deleted file mode 100644 index 02c589b2c..000000000 --- a/core/asm/compiler.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2017 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 . - -package asm - -import ( - "encoding/hex" - "errors" - "fmt" - "math/big" - "os" - "strings" - - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" -) - -// Compiler contains information about the parsed source -// and holds the tokens for the program. -type Compiler struct { - tokens []token - out []byte - - labels map[string]int - - pc, pos int - - debug bool -} - -// NewCompiler returns a new allocated compiler. -func NewCompiler(debug bool) *Compiler { - return &Compiler{ - labels: make(map[string]int), - debug: debug, - } -} - -// Feed feeds tokens into ch and are interpreted by -// the compiler. -// -// feed is the first pass in the compile stage as it collects the used labels in the -// program and keeps a program counter which is used to determine the locations of the -// jump dests. The labels can than be used in the second stage to push labels and -// determine the right position. -func (c *Compiler) Feed(ch <-chan token) { - var prev token - for i := range ch { - switch i.typ { - case number: - num := math.MustParseBig256(i.text).Bytes() - if len(num) == 0 { - num = []byte{0} - } - c.pc += len(num) - case stringValue: - c.pc += len(i.text) - 2 - case element: - c.pc++ - case labelDef: - c.labels[i.text] = c.pc - c.pc++ - case label: - c.pc += 4 - if prev.typ == element && isJump(prev.text) { - c.pc++ - } - } - c.tokens = append(c.tokens, i) - prev = i - } - if c.debug { - fmt.Fprintln(os.Stderr, "found", len(c.labels), "labels") - } -} - -// Compile compiles the current tokens and returns a binary string that can be interpreted -// by the EVM and an error if it failed. -// -// compile is the second stage in the compile phase which compiles the tokens to EVM -// instructions. -func (c *Compiler) Compile() (string, []error) { - var errors []error - // continue looping over the tokens until - // the stack has been exhausted. - for c.pos < len(c.tokens) { - if err := c.compileLine(); err != nil { - errors = append(errors, err) - } - } - - // turn the binary to hex - h := hex.EncodeToString(c.out) - return h, errors -} - -// next returns the next token and increments the -// position. -func (c *Compiler) next() token { - token := c.tokens[c.pos] - c.pos++ - return token -} - -// compileLine compiles a single line instruction e.g. -// "push 1", "jump @label". -func (c *Compiler) compileLine() error { - n := c.next() - if n.typ != lineStart { - return compileErr(n, n.typ.String(), lineStart.String()) - } - - lvalue := c.next() - switch lvalue.typ { - case eof: - return nil - case element: - if err := c.compileElement(lvalue); err != nil { - return err - } - case labelDef: - c.compileLabel() - case lineEnd: - return nil - default: - return compileErr(lvalue, lvalue.text, fmt.Sprintf("%v or %v", labelDef, element)) - } - - if n := c.next(); n.typ != lineEnd { - return compileErr(n, n.text, lineEnd.String()) - } - - return nil -} - -// parseNumber compiles the number to bytes -func parseNumber(tok token) ([]byte, error) { - if tok.typ != number { - panic("parseNumber of non-number token") - } - num, ok := math.ParseBig256(tok.text) - if !ok { - return nil, errors.New("invalid number") - } - bytes := num.Bytes() - if len(bytes) == 0 { - bytes = []byte{0} - } - return bytes, nil -} - -// compileElement compiles the element (push & label or both) -// to a binary representation and may error if incorrect statements -// where fed. -func (c *Compiler) compileElement(element token) error { - switch { - case isJump(element.text): - return c.compileJump(element.text) - case isPush(element.text): - return c.compilePush() - default: - c.outputOpcode(toBinary(element.text)) - return nil - } -} - -func (c *Compiler) compileJump(jumpType string) error { - rvalue := c.next() - switch rvalue.typ { - case number: - numBytes, err := parseNumber(rvalue) - if err != nil { - return err - } - c.outputBytes(numBytes) - - case stringValue: - // strings are quoted, remove them. - str := rvalue.text[1 : len(rvalue.text)-2] - c.outputBytes([]byte(str)) - - case label: - c.outputOpcode(vm.PUSH4) - pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes() - pos = append(make([]byte, 4-len(pos)), pos...) - c.outputBytes(pos) - - case lineEnd: - // push without argument is supported, it just takes the destination from the stack. - c.pos-- - - default: - return compileErr(rvalue, rvalue.text, "number, string or label") - } - // push the operation - c.outputOpcode(toBinary(jumpType)) - return nil -} - -func (c *Compiler) compilePush() error { - // handle pushes. pushes are read from left to right. - var value []byte - rvalue := c.next() - switch rvalue.typ { - case number: - value = math.MustParseBig256(rvalue.text).Bytes() - if len(value) == 0 { - value = []byte{0} - } - case stringValue: - value = []byte(rvalue.text[1 : len(rvalue.text)-1]) - case label: - value = big.NewInt(int64(c.labels[rvalue.text])).Bytes() - value = append(make([]byte, 4-len(value)), value...) - default: - return compileErr(rvalue, rvalue.text, "number, string or label") - } - if len(value) > 32 { - return fmt.Errorf("%d: string or number size > 32 bytes", rvalue.lineno+1) - } - c.outputOpcode(vm.OpCode(int(vm.PUSH1) - 1 + len(value))) - c.outputBytes(value) - return nil -} - -// compileLabel pushes a jumpdest to the binary slice. -func (c *Compiler) compileLabel() { - c.outputOpcode(vm.JUMPDEST) -} - -func (c *Compiler) outputOpcode(op vm.OpCode) { - if c.debug { - fmt.Printf("%d: %v\n", len(c.out), op) - } - c.out = append(c.out, byte(op)) -} - -// output pushes the value v to the binary stack. -func (c *Compiler) outputBytes(b []byte) { - if c.debug { - fmt.Printf("%d: %x\n", len(c.out), b) - } - c.out = append(c.out, b...) -} - -// isPush returns whether the string op is either any of -// push(N). -func isPush(op string) bool { - return strings.EqualFold(op, "PUSH") -} - -// isJump returns whether the string op is jump(i) -func isJump(op string) bool { - return strings.EqualFold(op, "JUMPI") || strings.EqualFold(op, "JUMP") -} - -// toBinary converts text to a vm.OpCode -func toBinary(text string) vm.OpCode { - return vm.StringToOp(strings.ToUpper(text)) -} - -type compileError struct { - got string - want string - - lineno int -} - -func (err compileError) Error() string { - return fmt.Sprintf("%d: syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want) -} - -func compileErr(c token, got, want string) error { - return compileError{ - got: got, - want: want, - lineno: c.lineno + 1, - } -} diff --git a/core/asm/compiler_test.go b/core/asm/compiler_test.go deleted file mode 100644 index 3d64c96bc..000000000 --- a/core/asm/compiler_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 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 . - -package asm - -import ( - "testing" -) - -func TestCompiler(t *testing.T) { - tests := []struct { - input, output string - }{ - { - input: ` - GAS - label: - PUSH @label -`, - output: "5a5b6300000001", - }, - { - input: ` - PUSH @label - label: -`, - output: "63000000055b", - }, - { - input: ` - PUSH @label - JUMP - label: -`, - output: "6300000006565b", - }, - { - input: ` - JUMP @label - label: -`, - output: "6300000006565b", - }, - { - input: ` - JUMP @label -label: ;; comment - ADD ;; comment -`, - output: "6300000006565b01", - }, - } - for _, test := range tests { - ch := Lex([]byte(test.input), false) - c := NewCompiler(false) - c.Feed(ch) - output, err := c.Compile() - if len(err) != 0 { - t.Errorf("compile error: %v\ninput: %s", err, test.input) - continue - } - if output != test.output { - t.Errorf("incorrect output\ninput: %sgot: %s\nwant: %s\n", test.input, output, test.output) - } - } -} diff --git a/core/asm/lex_test.go b/core/asm/lex_test.go deleted file mode 100644 index 1e62d776d..000000000 --- a/core/asm/lex_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017 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 . - -package asm - -import ( - "reflect" - "testing" -) - -func lexAll(src string) []token { - ch := Lex([]byte(src), false) - - var tokens []token - for i := range ch { - tokens = append(tokens, i) - } - return tokens -} - -func TestLexer(t *testing.T) { - tests := []struct { - input string - tokens []token - }{ - { - input: ";; this is a comment", - tokens: []token{{typ: lineStart}, {typ: eof}}, - }, - { - input: "0x12345678", - tokens: []token{{typ: lineStart}, {typ: number, text: "0x12345678"}, {typ: eof}}, - }, - { - input: "0x123ggg", - tokens: []token{{typ: lineStart}, {typ: number, text: "0x123"}, {typ: element, text: "ggg"}, {typ: eof}}, - }, - { - input: "12345678", - tokens: []token{{typ: lineStart}, {typ: number, text: "12345678"}, {typ: eof}}, - }, - { - input: "123abc", - tokens: []token{{typ: lineStart}, {typ: number, text: "123"}, {typ: element, text: "abc"}, {typ: eof}}, - }, - { - input: "0123abc", - tokens: []token{{typ: lineStart}, {typ: number, text: "0123"}, {typ: element, text: "abc"}, {typ: eof}}, - }, - { - input: "00123abc", - tokens: []token{{typ: lineStart}, {typ: number, text: "00123"}, {typ: element, text: "abc"}, {typ: eof}}, - }, - { - input: "@foo", - tokens: []token{{typ: lineStart}, {typ: label, text: "foo"}, {typ: eof}}, - }, - { - input: "@label123", - tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}}, - }, - // Comment after label - { - input: "@label123 ;; comment", - tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}}, - }, - // Comment after instruction - { - input: "push 3 ;; comment\nadd", - tokens: []token{{typ: lineStart}, {typ: element, text: "push"}, {typ: number, text: "3"}, {typ: lineEnd, text: "\n"}, {typ: lineStart, lineno: 1}, {typ: element, lineno: 1, text: "add"}, {typ: eof, lineno: 1}}, - }, - } - - for _, test := range tests { - tokens := lexAll(test.input) - if !reflect.DeepEqual(tokens, test.tokens) { - t.Errorf("input %q\ngot: %+v\nwant: %+v", test.input, tokens, test.tokens) - } - } -} diff --git a/core/asm/lexer.go b/core/asm/lexer.go deleted file mode 100644 index 630360b10..000000000 --- a/core/asm/lexer.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2017 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 . - -package asm - -import ( - "fmt" - "os" - "strings" - "unicode" - "unicode/utf8" -) - -// stateFn is used through the lifetime of the -// lexer to parse the different values at the -// current state. -type stateFn func(*lexer) stateFn - -// token is emitted when the lexer has discovered -// a new parsable token. These are delivered over -// the tokens channels of the lexer -type token struct { - typ tokenType - lineno int - text string -} - -// tokenType are the different types the lexer -// is able to parse and return. -type tokenType int - -//go:generate go run golang.org/x/tools/cmd/stringer -type tokenType - -const ( - eof tokenType = iota // end of file - lineStart // emitted when a line starts - lineEnd // emitted when a line ends - invalidStatement // any invalid statement - element // any element during element parsing - label // label is emitted when a label is found - labelDef // label definition is emitted when a new label is found - number // number is emitted when a number is found - stringValue // stringValue is emitted when a string has been found -) - -const ( - decimalNumbers = "1234567890" // characters representing any decimal number - hexNumbers = decimalNumbers + "aAbBcCdDeEfF" // characters representing any hexadecimal - alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric -) - -// lexer is the basic construct for parsing -// source code and turning them in to tokens. -// Tokens are interpreted by the compiler. -type lexer struct { - input string // input contains the source code of the program - - tokens chan token // tokens is used to deliver tokens to the listener - state stateFn // the current state function - - lineno int // current line number in the source file - start, pos, width int // positions for lexing and returning value - - debug bool // flag for triggering debug output -} - -// Lex lexes the program by name with the given source. It returns a -// channel on which the tokens are delivered. -func Lex(source []byte, debug bool) <-chan token { - ch := make(chan token) - l := &lexer{ - input: string(source), - tokens: ch, - state: lexLine, - debug: debug, - } - go func() { - l.emit(lineStart) - for l.state != nil { - l.state = l.state(l) - } - l.emit(eof) - close(l.tokens) - }() - - return ch -} - -// next returns the next rune in the program's source. -func (l *lexer) next() (rune rune) { - if l.pos >= len(l.input) { - l.width = 0 - return 0 - } - rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) - l.pos += l.width - return rune -} - -// backup backsup the last parsed element (multi-character) -func (l *lexer) backup() { - l.pos -= l.width -} - -// peek returns the next rune but does not advance the seeker -func (l *lexer) peek() rune { - r := l.next() - l.backup() - return r -} - -// ignore advances the seeker and ignores the value -func (l *lexer) ignore() { - l.start = l.pos -} - -// accept checks whether the given input matches the next rune -func (l *lexer) accept(valid string) bool { - if strings.ContainsRune(valid, l.next()) { - return true - } - - l.backup() - - return false -} - -// acceptRun will continue to advance the seeker until valid -// can no longer be met. -func (l *lexer) acceptRun(valid string) { - for strings.ContainsRune(valid, l.next()) { - } - l.backup() -} - -// acceptRunUntil is the inverse of acceptRun and will continue -// to advance the seeker until the rune has been found. -func (l *lexer) acceptRunUntil(until rune) bool { - // Continues running until a rune is found - for i := l.next(); !strings.ContainsRune(string(until), i); i = l.next() { - if i == 0 { - return false - } - } - - return true -} - -// blob returns the current value -func (l *lexer) blob() string { - return l.input[l.start:l.pos] -} - -// Emits a new token on to token channel for processing -func (l *lexer) emit(t tokenType) { - token := token{t, l.lineno, l.blob()} - - if l.debug { - fmt.Fprintf(os.Stderr, "%04d: (%-20v) %s\n", token.lineno, token.typ, token.text) - } - - l.tokens <- token - l.start = l.pos -} - -// lexLine is state function for lexing lines -func lexLine(l *lexer) stateFn { - for { - switch r := l.next(); { - case r == '\n': - l.emit(lineEnd) - l.ignore() - l.lineno++ - l.emit(lineStart) - case r == ';' && l.peek() == ';': - return lexComment - case isSpace(r): - l.ignore() - case isLetter(r) || r == '_': - return lexElement - case isNumber(r): - return lexNumber - case r == '@': - l.ignore() - return lexLabel - case r == '"': - return lexInsideString - default: - return nil - } - } -} - -// lexComment parses the current position until the end -// of the line and discards the text. -func lexComment(l *lexer) stateFn { - l.acceptRunUntil('\n') - l.backup() - l.ignore() - - return lexLine -} - -// lexLabel parses the current label, emits and returns -// the lex text state function to advance the parsing -// process. -func lexLabel(l *lexer) stateFn { - l.acceptRun(alpha + "_" + decimalNumbers) - - l.emit(label) - - return lexLine -} - -// lexInsideString lexes the inside of a string until -// the state function finds the closing quote. -// It returns the lex text state function. -func lexInsideString(l *lexer) stateFn { - if l.acceptRunUntil('"') { - l.emit(stringValue) - } - - return lexLine -} - -func lexNumber(l *lexer) stateFn { - acceptance := decimalNumbers - if l.accept("xX") { - acceptance = hexNumbers - } - l.acceptRun(acceptance) - - l.emit(number) - - return lexLine -} - -func lexElement(l *lexer) stateFn { - l.acceptRun(alpha + "_" + decimalNumbers) - - if l.peek() == ':' { - l.emit(labelDef) - - l.accept(":") - l.ignore() - } else { - l.emit(element) - } - return lexLine -} - -func isLetter(t rune) bool { - return unicode.IsLetter(t) -} - -func isSpace(t rune) bool { - return unicode.IsSpace(t) -} - -func isNumber(t rune) bool { - return unicode.IsNumber(t) -} diff --git a/core/asm/tokentype_string.go b/core/asm/tokentype_string.go deleted file mode 100644 index ade76aa36..000000000 --- a/core/asm/tokentype_string.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "stringer -type tokenType"; DO NOT EDIT. - -package asm - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[eof-0] - _ = x[lineStart-1] - _ = x[lineEnd-2] - _ = x[invalidStatement-3] - _ = x[element-4] - _ = x[label-5] - _ = x[labelDef-6] - _ = x[number-7] - _ = x[stringValue-8] -} - -const _tokenType_name = "eoflineStartlineEndinvalidStatementelementlabellabelDefnumberstringValue" - -var _tokenType_index = [...]uint8{0, 3, 12, 19, 35, 42, 47, 55, 61, 72} - -func (i tokenType) String() string { - if i < 0 || i >= tokenType(len(_tokenType_index)-1) { - return "tokenType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _tokenType_name[_tokenType_index[i]:_tokenType_index[i+1]] -} diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index bde230b6d..d75a5b045 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/asm" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -508,21 +507,9 @@ func TestEip2929Cases(t *testing.T) { t.Skip("Test only useful for generating documentation") id := 1 prettyPrint := func(comment string, code []byte) { - instrs := make([]string, 0) - it := asm.NewInstructionIterator(code) - for it.Next() { - if it.Arg() != nil && 0 < len(it.Arg()) { - instrs = append(instrs, fmt.Sprintf("%v %#x", it.Op(), it.Arg())) - } else { - instrs = append(instrs, fmt.Sprintf("%v", it.Op())) - } - } - ops := strings.Join(instrs, ", ") fmt.Printf("### Case %d\n\n", id) id++ - fmt.Printf("%v\n\nBytecode: \n```\n%#x\n```\nOperations: \n```\n%v\n```\n\n", - comment, - code, ops) + fmt.Printf("%v\n\nBytecode: \n```\n%#x\n```\n", comment, code) Execute(code, nil, &Config{ EVMConfig: vm.Config{ Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Hooks(), From 1e536d061c73426eb105fdcb20f96c4a5b3919f2 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 20 Feb 2025 10:27:13 +0100 Subject: [PATCH 154/354] .github: downgrade go for lint step (#31217) --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 90449ef30..4da92f243 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.24.0 + go-version: 1.23.0 cache: false - name: Run linters From 5a3189d1cb7bbd2cc1af2bdc306dccbf78f1f7d0 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 20 Feb 2025 13:11:48 +0100 Subject: [PATCH 155/354] core/txpool/legacypool: add setCodeTx reorg test (#31206) This PR adds a test that makes sure that a node can send multiple transactions again once a authorization is removed --- core/txpool/legacypool/legacypool_test.go | 63 +++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index da28e8a75..7e35e0cc6 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -149,6 +149,10 @@ func pricedSetCodeTx(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, ke }) authList = append(authList, auth) } + return pricedSetCodeTxWithAuth(nonce, gaslimit, gasFee, tip, key, authList) +} + +func pricedSetCodeTxWithAuth(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, authList []types.SetCodeAuthorization) *types.Transaction { return types.MustSignNewTx(key, types.LatestSignerForChainID(params.TestChainConfig.ChainID), &types.SetCodeTx{ ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID), Nonce: nonce, @@ -2393,6 +2397,65 @@ func TestSetCodeTransactions(t *testing.T) { } } +func TestSetCodeTransactionsReorg(t *testing.T) { + t.Parallel() + + // Create the pool to test the status retrievals with + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) + + pool := New(testTxPoolConfig, blockchain) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + defer pool.Close() + + // Create the test accounts + var ( + keyA, _ = crypto.GenerateKey() + addrA = crypto.PubkeyToAddress(keyA.PublicKey) + ) + testAddBalance(pool, addrA, big.NewInt(params.Ether)) + // Send an authorization for 0x42 + var authList []types.SetCodeAuthorization + auth, _ := types.SignSetCode(keyA, types.SetCodeAuthorization{ + ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), + Address: common.Address{0x42}, + Nonce: 0, + }) + authList = append(authList, auth) + if err := pool.addRemoteSync(pricedSetCodeTxWithAuth(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, authList)); err != nil { + t.Fatalf("failed to add with remote setcode transaction: %v", err) + } + // Simulate the chain moving + blockchain.statedb.SetNonce(addrA, 1, tracing.NonceChangeAuthorization) + blockchain.statedb.SetCode(addrA, types.AddressToDelegation(auth.Address)) + <-pool.requestReset(nil, nil) + // Set an authorization for 0x00 + auth, _ = types.SignSetCode(keyA, types.SetCodeAuthorization{ + ChainID: *uint256.MustFromBig(params.TestChainConfig.ChainID), + Address: common.Address{}, + Nonce: 0, + }) + authList = append(authList, auth) + if err := pool.addRemoteSync(pricedSetCodeTxWithAuth(1, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, authList)); err != nil { + t.Fatalf("failed to add with remote setcode transaction: %v", err) + } + // Try to add a transactions in + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { + t.Fatalf("unexpected error %v, expecting %v", err, txpool.ErrAccountLimitExceeded) + } + // Simulate the chain moving + blockchain.statedb.SetNonce(addrA, 2, tracing.NonceChangeAuthorization) + blockchain.statedb.SetCode(addrA, nil) + <-pool.requestReset(nil, nil) + // Now send two transactions from addrA + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); err != nil { + t.Fatalf("failed to added single transaction: %v", err) + } + if err := pool.addRemoteSync(pricedTransaction(3, 100000, big.NewInt(1000), keyA)); err != nil { + t.Fatalf("failed to added single transaction: %v", err) + } +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } From 1a41e2ca0ed19dc46b57d5eb5189943b87cda96f Mon Sep 17 00:00:00 2001 From: nethoxa <135072738+nethoxa@users.noreply.github.com> Date: Thu, 20 Feb 2025 14:30:55 +0100 Subject: [PATCH 156/354] internal/ethapi: handle prague system calls in eth_simulate (#31176) eth_simulate was not processing prague system calls for history contract and EL requests resulting in inaccurate stateRoot and requestsRoot fields in the block. --- internal/ethapi/simulate.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index c461b1f0a..227fd0e8e 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -194,6 +194,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if precompiles != nil { evm.SetPrecompiles(precompiles) } + if sim.chainConfig.IsPrague(header.Number, header.Time) || sim.chainConfig.IsVerkle(header.Number, header.Time) { + core.ProcessParentBlockHash(header.ParentHash, evm) + } + var allLogs []*types.Log for i, call := range block.Calls { if err := ctx.Err(); err != nil { return nil, nil, err @@ -234,9 +238,23 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, } } else { callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful) + allLogs = append(allLogs, callRes.Logs...) } callResults[i] = callRes } + var requests [][]byte + // Process EIP-7685 requests + if sim.chainConfig.IsPrague(header.Number, header.Time) { + requests = [][]byte{} + // EIP-6110 + if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil { + return nil, nil, err + } + // EIP-7002 + core.ProcessWithdrawalQueue(&requests, evm) + // EIP-7251 + core.ProcessConsolidationQueue(&requests, evm) + } header.Root = sim.state.IntermediateRoot(true) header.GasUsed = gasUsed if sim.chainConfig.IsCancun(header.Number, header.Time) { @@ -246,6 +264,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsShanghai(header.Number, header.Time) { withdrawals = make([]*types.Withdrawal, 0) } + if requests != nil { + reqHash := types.CalcRequestsHash(requests) + header.RequestsHash = &reqHash + } b := types.NewBlock(header, &types.Body{Transactions: txes, Withdrawals: withdrawals}, receipts, trie.NewStackTrie(nil)) repairLogs(callResults, b.Hash()) return b, callResults, nil From 6eafc0919c4e6f58308166da9d634af48af82fe9 Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 20 Feb 2025 22:04:35 +0800 Subject: [PATCH 157/354] eth/tracers: refactor block context in test runner (#29450) This commit contains a minor refactoring of the block context used within the test runners. --------- Signed-off-by: jsvisa --- .../internal/tracetest/calltrace_test.go | 7 ++----- .../internal/tracetest/flat_calltrace_test.go | 7 ++----- eth/tracers/internal/tracetest/makeTest.js | 17 ++++++++++----- .../internal/tracetest/prestate_test.go | 21 ++++++++----------- .../testdata/call_tracer/blob_tx.json | 2 -- .../testdata/prestate_tracer/blob_tx.json | 2 -- .../prestate_tracer/create_create.json | 2 -- eth/tracers/internal/tracetest/util.go | 14 +++++++++++-- 8 files changed, 37 insertions(+), 35 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 999ab211c..b2486661e 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -65,11 +65,8 @@ type callTrace struct { // callTracerTest defines a single test to check the call tracer against. type callTracerTest struct { - Genesis *core.Genesis `json:"genesis"` - Context *callContext `json:"context"` - Input string `json:"input"` - TracerConfig json.RawMessage `json:"tracerConfig"` - Result *callTrace `json:"result"` + tracerTestEnv + Result *callTrace `json:"result"` } // Iterates over all the input-output datasets in the tracer test harness and diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 4390a62b4..d1fa44e9d 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -77,11 +77,8 @@ type flatCallTraceResult struct { // flatCallTracerTest defines a single test to check the call tracer against. type flatCallTracerTest struct { - Genesis *core.Genesis `json:"genesis"` - Context *callContext `json:"context"` - Input string `json:"input"` - TracerConfig json.RawMessage `json:"tracerConfig"` - Result []flatCallTrace `json:"result"` + tracerTestEnv + Result []flatCallTrace `json:"result"` } func flatCallTracerTestRunner(tracerName string, filename string, dirPath string, t testing.TB) error { diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js index 826c91f63..cb41ebde0 100644 --- a/eth/tracers/internal/tracetest/makeTest.js +++ b/eth/tracers/internal/tracetest/makeTest.js @@ -31,6 +31,9 @@ var makeTest = function(tx, traceConfig) { delete genesis.transactions; delete genesis.transactionsRoot; delete genesis.uncles; + delete genesis.withdrawals; + delete genesis.withdrawalsRoot; + delete genesis.baseFeePerGas; genesis.gasLimit = genesis.gasLimit.toString(); genesis.number = genesis.number.toString(); @@ -60,11 +63,15 @@ var makeTest = function(tx, traceConfig) { context.baseFeePerGas = block.baseFeePerGas.toString(); } - console.log(JSON.stringify({ + var data = { genesis: genesis, context: context, - input: eth.getRawTransaction(tx), - result: result, - tracerConfig: traceConfig.tracerConfig, - }, null, 2)); + input: eth.getRawTransaction(tx), + result: result, + }; + if (traceConfig && traceConfig.tracerConfig) { + data.tracerConfig = traceConfig.tracerConfig; + } + + console.log(JSON.stringify(data, null, 2)); } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 680645970..29c2834ba 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -43,28 +43,25 @@ type account struct { Storage map[common.Hash]common.Hash `json:"storage"` } -// testcase defines a single test to check the stateDiff tracer against. -type testcase struct { - Genesis *core.Genesis `json:"genesis"` - Context *callContext `json:"context"` - Input string `json:"input"` - TracerConfig json.RawMessage `json:"tracerConfig"` - Result interface{} `json:"result"` +// prestateTracerTest defines a single test to check the stateDiff tracer against. +type prestateTracerTest struct { + tracerTestEnv + Result interface{} `json:"result"` } func TestPrestateTracerLegacy(t *testing.T) { - testPrestateDiffTracer("prestateTracerLegacy", "prestate_tracer_legacy", t) + testPrestateTracer("prestateTracerLegacy", "prestate_tracer_legacy", t) } func TestPrestateTracer(t *testing.T) { - testPrestateDiffTracer("prestateTracer", "prestate_tracer", t) + testPrestateTracer("prestateTracer", "prestate_tracer", t) } func TestPrestateWithDiffModeTracer(t *testing.T) { - testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t) + testPrestateTracer("prestateTracer", "prestate_tracer_with_diff_mode", t) } -func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { +func testPrestateTracer(tracerName string, dirPath string, t *testing.T) { files, err := os.ReadDir(filepath.Join("testdata", dirPath)) if err != nil { t.Fatalf("failed to retrieve tracer test suite: %v", err) @@ -77,7 +74,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Parallel() var ( - test = new(testcase) + test = new(prestateTracerTest) tx = new(types.Transaction) ) // Call tracer test found, read if from disk diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json index f8e08532a..f59285cfb 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/blob_tx.json @@ -14,8 +14,6 @@ "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", "timestamp": "1709626771", - "withdrawals": [], - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json index 9f452ca5b..50f320973 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/blob_tx.json @@ -14,8 +14,6 @@ "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a", "timestamp": "1709626771", - "withdrawals": [], - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { "0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json index 489a1ae6b..dd4fca1ec 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json @@ -11,8 +11,6 @@ "number": "1", "stateRoot": "0xd2ebe0a7f3572ffe3e5b4c78147376d3fca767f236e4dd23f9151acfec7cb0d1", "timestamp": "1699617692", - "withdrawals": [], - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "alloc": { "0x0000000000000000000000000000000000000000": { "balance": "0x5208" diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index 85727e29e..04fff12fe 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -17,6 +17,7 @@ package tracetest import ( + "encoding/json" "math/big" "strings" "unicode" @@ -42,7 +43,8 @@ func camel(str string) string { return strings.Join(pieces, "") } -type callContext struct { +// traceContext defines a context used to construct the block context +type traceContext struct { Number math.HexOrDecimal64 `json:"number"` Difficulty *math.HexOrDecimal256 `json:"difficulty"` Time math.HexOrDecimal64 `json:"timestamp"` @@ -51,7 +53,7 @@ type callContext struct { BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` } -func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { +func (c *traceContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { context := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -77,3 +79,11 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext { } return context } + +// tracerTestEnv defines a tracer test required fields +type tracerTestEnv struct { + Genesis *core.Genesis `json:"genesis"` + Context *traceContext `json:"context"` + Input string `json:"input"` + TracerConfig json.RawMessage `json:"tracerConfig"` +} From d3c5159d0dc39b718381065294c41b09bd9323b6 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 20 Feb 2025 18:46:25 +0100 Subject: [PATCH 158/354] oss-fuzz: remove deprecated targets (#31224) Fixes https://github.com/ethereum/go-ethereum/issues/31223 (sorry, I thought the fork fork would be created on my repo, not upstream, when I used the GH editor) --- oss-fuzz.sh | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 1f222c433..4db245a78 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -160,14 +160,6 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ FuzzG1Add fuzz_g1_add\ $repo/tests/fuzzers/bls12381/bls12381_test.go -compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ - FuzzCrossG1Mul fuzz_cross_g1_mul\ - $repo/tests/fuzzers/bls12381/bls12381_test.go - -compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ - FuzzG1Mul fuzz_g1_mul\ - $repo/tests/fuzzers/bls12381/bls12381_test.go - compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ FuzzG1MultiExp fuzz_g1_multiexp \ $repo/tests/fuzzers/bls12381/bls12381_test.go @@ -176,14 +168,6 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ FuzzG2Add fuzz_g2_add \ $repo/tests/fuzzers/bls12381/bls12381_test.go -compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ - FuzzCrossG2Mul fuzz_cross_g2_mul\ - $repo/tests/fuzzers/bls12381/bls12381_test.go - -compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ - FuzzG2Mul fuzz_g2_mul\ - $repo/tests/fuzzers/bls12381/bls12381_test.go - compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/bls12381 \ FuzzG2MultiExp fuzz_g2_multiexp \ $repo/tests/fuzzers/bls12381/bls12381_test.go From 6eca2436d46ee56325d30c2ad5bc709a3d143eae Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 21 Feb 2025 03:42:54 +0100 Subject: [PATCH 159/354] p2p/nat: remove test with default servers (#31225) The test occasionally fails when network connectivity is bad or if it hits the wrong server. We usually don't add tests with external network dependency so I'm removing them. Fixes #31220 --- p2p/nat/stun_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/p2p/nat/stun_test.go b/p2p/nat/stun_test.go index b5f429986..6bcaf45f9 100644 --- a/p2p/nat/stun_test.go +++ b/p2p/nat/stun_test.go @@ -18,17 +18,8 @@ package nat import ( "testing" - - "github.com/stretchr/testify/assert" ) -func TestNatStun(t *testing.T) { - nat, err := newSTUN("") - assert.NoError(t, err) - _, err = nat.ExternalIP() - assert.NoError(t, err) -} - func TestUnreachedNatServer(t *testing.T) { stun := &stun{ serverList: []string{"198.51.100.2:1234", "198.51.100.5"}, From dc8d523028253277f4836f374567884a08d78c66 Mon Sep 17 00:00:00 2001 From: rrhlrmrr <39875249+rrhlrmrr@users.noreply.github.com> Date: Fri, 21 Feb 2025 14:45:29 +0900 Subject: [PATCH 160/354] core/types: remove unneeded todo marker (#31179) --- core/types/transaction_marshalling.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 1bbb97a3e..f76d4b92e 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -514,6 +514,5 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { // Now set the inner transaction. tx.setDecoded(inner, 0) - // TODO: check hash here? return nil } From a9a5bc18dd921996d0e9419d1dbd743ea898ff26 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Fri, 21 Feb 2025 00:48:24 -0800 Subject: [PATCH 161/354] signer/core: fix encoding of `bytes` nested within array (#31049) Fixes an incorrect encoding of recursive bytes types. closes https://github.com/ethereum/go-ethereum/issues/30979 --- signer/core/apitypes/types.go | 11 +++++++- signer/core/signed_data_test.go | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index b56931c1d..b8b96bef9 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -501,7 +501,16 @@ func (typedData *TypedData) encodeArrayValue(encValue interface{}, encType strin for _, item := range arrayValue { if reflect.TypeOf(item).Kind() == reflect.Slice || reflect.TypeOf(item).Kind() == reflect.Array { - encodedData, err := typedData.encodeArrayValue(item, parsedType, depth+1) + var ( + encodedData hexutil.Bytes + err error + ) + if reflect.TypeOf(item).Elem().Kind() == reflect.Uint8 { + // the item type is bytes. encode the bytes array directly instead of recursing. + encodedData, err = typedData.EncodePrimitiveValue(parsedType, item, depth+1) + } else { + encodedData, err = typedData.encodeArrayValue(item, parsedType, depth+1) + } if err != nil { return nil, err } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index d0637010b..b6c080736 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -1014,3 +1014,49 @@ func TestComplexTypedDataWithLowercaseReftype(t *testing.T) { t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) } } + +var recursiveBytesTypesStandard = apitypes.Types{ + "EIP712Domain": { + { + Name: "name", + Type: "string", + }, + { + Name: "version", + Type: "string", + }, + { + Name: "chainId", + Type: "uint256", + }, + { + Name: "verifyingContract", + Type: "address", + }, + }, + "Val": { + { + Name: "field", + Type: "bytes[][]", + }, + }, +} + +var recursiveBytesMessageStandard = map[string]interface{}{ + "field": [][][]byte{{{1}, {2}}, {{3}, {4}}}, +} + +var recursiveBytesTypedData = apitypes.TypedData{ + Types: recursiveBytesTypesStandard, + PrimaryType: "Val", + Domain: domainStandard, + Message: recursiveBytesMessageStandard, +} + +func TestEncodeDataRecursiveBytes(t *testing.T) { + typedData := recursiveBytesTypedData + _, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0) + if err != nil { + t.Fatalf("got err %v", err) + } +} From 28c02792b53eb10773b60f14d7350e83546ceea5 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:52:55 +0100 Subject: [PATCH 162/354] internal/ethapi: fix prev hashes in eth_simulate (#31122) Shout-out to @Gabriel-Trintinalia for discovering this issue. The gist of it as follows: When processing a block, we should provide the parent block as well as the last 256 block hashes. Some of these parents data (specifically the hash) was incorrect because even though during the processing of the parent block we have updated the header, that header was not updating the TransactionsRoot and ReceiptsRoot fields (types.NewBlock makes a new copy of the header and changes it only on that instance). --------- Co-authored-by: lightclient --- internal/ethapi/api.go | 2 +- internal/ethapi/api_test.go | 96 +++++++++++++++++++++++++++++++++++++ internal/ethapi/simulate.go | 26 +++++++--- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2a21ca051..eeda6b811 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -860,7 +860,7 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN // // Note, this function doesn't make any changes in the state/blockchain and is // useful to execute and retrieve values. -func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { +func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]*simBlockResult, error) { if len(opts.BlockStateCalls) == 0 { return nil, &invalidParamsError{message: "empty input"} } else if len(opts.BlockStateCalls) > maxSimulateBlocks { diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3c6c6aec0..dbbe83e68 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -24,6 +24,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "math/big" "os" "path/filepath" @@ -2327,6 +2328,101 @@ func TestSimulateV1(t *testing.T) { } } +func TestSimulateV1ChainLinkage(t *testing.T) { + var ( + acc = newTestAccount() + sender = acc.addr + contractAddr = common.Address{0xaa, 0xaa} + recipient = common.Address{0xbb, 0xbb} + gspec = &core.Genesis{ + Config: params.MergedTestChainConfig, + Alloc: types.GenesisAlloc{ + sender: {Balance: big.NewInt(params.Ether)}, + contractAddr: {Code: common.Hex2Bytes("5f35405f8114600f575f5260205ff35b5f80fd")}, + }, + } + signer = types.LatestSigner(params.MergedTestChainConfig) + ) + backend := newTestBackend(t, 1, gspec, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) { + tx := types.MustSignNewTx(acc.key, signer, &types.LegacyTx{ + Nonce: uint64(i), + GasPrice: b.BaseFee(), + Gas: params.TxGas, + To: &recipient, + Value: big.NewInt(500), + }) + b.AddTx(tx) + }) + + ctx := context.Background() + stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) + if err != nil { + t.Fatalf("failed to get state and header: %v", err) + } + + sim := &simulator{ + b: backend, + state: stateDB, + base: baseHeader, + chainConfig: backend.ChainConfig(), + gp: new(core.GasPool).AddGas(math.MaxUint64), + traceTransfers: false, + validate: false, + fullTx: false, + } + + var ( + call1 = TransactionArgs{ + From: &sender, + To: &recipient, + Value: (*hexutil.Big)(big.NewInt(1000)), + } + call2 = TransactionArgs{ + From: &sender, + To: &recipient, + Value: (*hexutil.Big)(big.NewInt(2000)), + } + call3a = TransactionArgs{ + From: &sender, + To: &contractAddr, + Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 1)), + Gas: newUint64(1000000), + } + call3b = TransactionArgs{ + From: &sender, + To: &contractAddr, + Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 2)), + Gas: newUint64(1000000), + } + blocks = []simBlock{ + {Calls: []TransactionArgs{call1}}, + {Calls: []TransactionArgs{call2}}, + {Calls: []TransactionArgs{call3a, call3b}}, + } + ) + + results, err := sim.execute(ctx, blocks) + if err != nil { + t.Fatalf("simulation execution failed: %v", err) + } + require.Equal(t, 3, len(results), "expected 3 simulated blocks") + + // Check linkages of simulated blocks: + // Verify that block2's parent hash equals block1's hash. + block1 := results[0].Block + block2 := results[1].Block + block3 := results[2].Block + require.Equal(t, block1.ParentHash(), baseHeader.Hash(), "parent hash of block1 should equal hash of base block") + require.Equal(t, block1.Hash(), block2.Header().ParentHash, "parent hash of block2 should equal hash of block1") + require.Equal(t, block2.Hash(), block3.Header().ParentHash, "parent hash of block3 should equal hash of block2") + + // In block3, two calls were executed to our contract. + // The first call in block3 should return the blockhash for block1 (i.e. block1.Hash()), + // whereas the second call should return the blockhash for block2 (i.e. block2.Hash()). + require.Equal(t, block1.Hash().Bytes(), []byte(results[2].Calls[0].ReturnValue), "returned blockhash for block1 does not match") + require.Equal(t, block2.Hash().Bytes(), []byte(results[2].Calls[1].ReturnValue), "returned blockhash for block2 does not match") +} + func TestSignTransaction(t *testing.T) { t.Parallel() // Initialize test accounts diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 227fd0e8e..ac7637242 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -73,6 +73,20 @@ func (r *simCallResult) MarshalJSON() ([]byte, error) { return json.Marshal((*callResultAlias)(r)) } +// simBlockResult is the result of a simulated block. +type simBlockResult struct { + fullTx bool + chainConfig *params.ChainConfig + Block *types.Block + Calls []simCallResult +} + +func (r *simBlockResult) MarshalJSON() ([]byte, error) { + blockData := RPCMarshalBlock(r.Block, true, r.fullTx, r.chainConfig) + blockData["calls"] = r.Calls + return json.Marshal(blockData) +} + // simOpts are the inputs to eth_simulateV1. type simOpts struct { BlockStateCalls []simBlock @@ -95,7 +109,7 @@ type simulator struct { } // execute runs the simulation of a series of blocks. -func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[string]interface{}, error) { +func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlockResult, error) { if err := ctx.Err(); err != nil { return nil, err } @@ -123,7 +137,7 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str return nil, err } var ( - results = make([]map[string]interface{}, len(blocks)) + results = make([]*simBlockResult, len(blocks)) parent = sim.base ) for bi, block := range blocks { @@ -131,11 +145,9 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]map[str if err != nil { return nil, err } - enc := RPCMarshalBlock(result, true, sim.fullTx, sim.chainConfig) - enc["calls"] = callResults - results[bi] = enc - - parent = headers[bi] + headers[bi] = result.Header() + results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults} + parent = result.Header() } return results, nil } From 4f89a28ce0067dc502f9c88939cb1d8b27099b23 Mon Sep 17 00:00:00 2001 From: Maximilian Hubert <64627729+gap-editor@users.noreply.github.com> Date: Fri, 21 Feb 2025 11:45:02 +0100 Subject: [PATCH 163/354] cmd/clef: improve documentation in readme (#31218) Fixed broken or outdated links and improved documentation formatting to ensure consistency and correct references. --------- Co-authored-by: Sina M <1591639+s1na@users.noreply.github.com> --- cmd/clef/intapi_changelog.md | 2 +- signer/core/testdata/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/clef/intapi_changelog.md b/cmd/clef/intapi_changelog.md index eaeb2e686..85d04f6d0 100644 --- a/cmd/clef/intapi_changelog.md +++ b/cmd/clef/intapi_changelog.md @@ -94,7 +94,7 @@ type Account struct { > Notifications are not confirmable by definition, since they do not have a Response object to be returned. As such, the Client would not be aware of any errors (like e.g. "Invalid params","Internal error" ### 3.1.0 -* Add `ContentType` `string` to `SignDataRequest` to accommodate the latest EIP-191 and EIP-712 implementations. +* Add `ContentType` `string` to `SignDataRequest` to accommodate the latest [EIP-191](https://eips.ethereum.org/EIPS/eip-191) and [EIP-712](https://eips.ethereum.org/EIPS/eip-712) implementations. ### 3.0.0 diff --git a/signer/core/testdata/README.md b/signer/core/testdata/README.md index f425450a0..85aa70c04 100644 --- a/signer/core/testdata/README.md +++ b/signer/core/testdata/README.md @@ -1,5 +1,5 @@ -### EIP 712 tests +### EIP-712 tests -These tests are json files which are converted into eip-712 typed data. +These tests are json files which are converted into [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data. All files are expected to be proper json, and tests will fail if they are not. Files that begin with `expfail' are expected to not pass the hashstruct construction. From 5a573c01fb9106cc0ea3070d452033737e66a9e9 Mon Sep 17 00:00:00 2001 From: levisyin Date: Fri, 21 Feb 2025 20:36:18 +0800 Subject: [PATCH 164/354] build: replace `tenv` linter with `usetesting` (#31172) --- .golangci.yml | 2 +- README.md | 2 +- cmd/clef/run_test.go | 8 +------- cmd/utils/history_test.go | 6 +----- core/txpool/blobpool/blobpool_test.go | 19 +++++++------------ crypto/crypto_test.go | 4 ++-- crypto/signify/signify_test.go | 16 ++++------------ internal/era/era_test.go | 3 ++- node/config_test.go | 3 +-- 9 files changed, 20 insertions(+), 43 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b63251055..a702da524 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: - gocheckcompilerdirectives - reassign - mirror - - tenv + - usetesting ### linters we tried and will not be using: ### # - structcheck # lots of false positives diff --git a/README.md b/README.md index dcd99cfc7..7563a067e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ published at https://github.com/bane-labs/go-ethereum/releases. For prerequisites and detailed build instructions please read the [Installation Instructions](https://docs.banelabs.org/development/running-a-node-in-testnet). -Building `geth` requires both a Go (version 1.22 or later) and a C compiler. You can install +Building `geth` requires both a Go (version 1.23 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell diff --git a/cmd/clef/run_test.go b/cmd/clef/run_test.go index 5fa6e02e1..d404457ba 100644 --- a/cmd/clef/run_test.go +++ b/cmd/clef/run_test.go @@ -57,13 +57,7 @@ func TestMain(m *testing.M) { // This method creates a temporary keystore folder which will be removed after // the test exits. func runClef(t *testing.T, args ...string) *testproc { - ddir, err := os.MkdirTemp("", "cleftest-*") - if err != nil { - return nil - } - t.Cleanup(func() { - os.RemoveAll(ddir) - }) + ddir := t.TempDir() return runWithKeystore(t, ddir, args...) } diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index e5acd8bef..b4616c306 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -87,11 +87,7 @@ func TestHistoryImportAndExport(t *testing.T) { } // Make temp directory for era files. - dir, err := os.MkdirTemp("", "history-export-test") - if err != nil { - t.Fatalf("error creating temp test directory: %v", err) - } - defer os.RemoveAll(dir) + dir := t.TempDir() // Export history to temp directory. if err := ExportHistory(chain, dir, 0, count, step); err != nil { diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 8589e5c01..d9137cb67 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -21,6 +21,7 @@ import ( "crypto/ecdsa" "crypto/sha256" "errors" + "fmt" "math" "math/big" "os" @@ -452,8 +453,7 @@ func TestOpenDrops(t *testing.T) { //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) + storage := t.TempDir() os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) @@ -775,8 +775,7 @@ func TestOpenIndex(t *testing.T) { //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) + storage := t.TempDir() os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) @@ -864,8 +863,7 @@ func TestOpenHeap(t *testing.T) { //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) + storage := t.TempDir() os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) @@ -951,8 +949,7 @@ func TestOpenCap(t *testing.T) { //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) + storage := t.TempDir() os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) @@ -1041,8 +1038,7 @@ func TestChangingSlotterSize(t *testing.T) { //log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true))) // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) + storage := t.TempDir() os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil) @@ -1508,8 +1504,7 @@ func TestAdd(t *testing.T) { } for i, tt := range tests { // Create a temporary folder for the persistent backend - storage, _ := os.MkdirTemp("", "blobpool-") - defer os.RemoveAll(storage) // late defer, still ok + storage := filepath.Join(t.TempDir(), fmt.Sprintf("test-%d", i)) os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700) store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil) diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index da123cf98..5b0c9c053 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -181,7 +181,7 @@ func TestLoadECDSA(t *testing.T) { } for _, test := range tests { - f, err := os.CreateTemp("", "loadecdsa_test.*.txt") + f, err := os.CreateTemp(t.TempDir(), "loadecdsa_test.*.txt") if err != nil { t.Fatal(err) } @@ -202,7 +202,7 @@ func TestLoadECDSA(t *testing.T) { } func TestSaveECDSA(t *testing.T) { - f, err := os.CreateTemp("", "saveecdsa_test.*.txt") + f, err := os.CreateTemp(t.TempDir(), "saveecdsa_test.*.txt") if err != nil { t.Fatal(err) } diff --git a/crypto/signify/signify_test.go b/crypto/signify/signify_test.go index 9bac2c825..ce41c1bd0 100644 --- a/crypto/signify/signify_test.go +++ b/crypto/signify/signify_test.go @@ -33,11 +33,10 @@ var ( ) func TestSignify(t *testing.T) { - tmpFile, err := os.CreateTemp("", "") + tmpFile, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name()) defer tmpFile.Close() data := make([]byte, 1024) @@ -52,7 +51,6 @@ func TestSignify(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name() + ".sig") // Verify the signature using a golang library sig, err := minisign.NewSignatureFromFile(tmpFile.Name() + ".sig") @@ -75,11 +73,10 @@ func TestSignify(t *testing.T) { } func TestSignifyTrustedCommentTooManyLines(t *testing.T) { - tmpFile, err := os.CreateTemp("", "") + tmpFile, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name()) defer tmpFile.Close() data := make([]byte, 1024) @@ -94,15 +91,13 @@ func TestSignifyTrustedCommentTooManyLines(t *testing.T) { if err == nil || err.Error() == "" { t.Fatalf("should have errored on a multi-line trusted comment, got %v", err) } - defer os.Remove(tmpFile.Name() + ".sig") } func TestSignifyTrustedCommentTooManyLinesLF(t *testing.T) { - tmpFile, err := os.CreateTemp("", "") + tmpFile, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name()) defer tmpFile.Close() data := make([]byte, 1024) @@ -117,15 +112,13 @@ func TestSignifyTrustedCommentTooManyLinesLF(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name() + ".sig") } func TestSignifyTrustedCommentEmpty(t *testing.T) { - tmpFile, err := os.CreateTemp("", "") + tmpFile, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name()) defer tmpFile.Close() data := make([]byte, 1024) @@ -140,5 +133,4 @@ func TestSignifyTrustedCommentEmpty(t *testing.T) { if err != nil { t.Fatal(err) } - defer os.Remove(tmpFile.Name() + ".sig") } diff --git a/internal/era/era_test.go b/internal/era/era_test.go index e0bebfa44..72c3b385d 100644 --- a/internal/era/era_test.go +++ b/internal/era/era_test.go @@ -37,7 +37,7 @@ func TestEra1Builder(t *testing.T) { t.Parallel() // Get temp directory. - f, err := os.CreateTemp("", "era1-test") + f, err := os.CreateTemp(t.TempDir(), "era1-test") if err != nil { t.Fatalf("error creating temp file: %v", err) } @@ -78,6 +78,7 @@ func TestEra1Builder(t *testing.T) { if err != nil { t.Fatalf("failed to open era: %v", err) } + defer e.Close() it, err := NewRawIterator(e) if err != nil { t.Fatalf("failed to make iterator: %s", err) diff --git a/node/config_test.go b/node/config_test.go index e8af8ddcd..067796d66 100644 --- a/node/config_test.go +++ b/node/config_test.go @@ -53,13 +53,12 @@ func TestDatadirCreation(t *testing.T) { t.Fatalf("freshly created datadir not accessible: %v", err) } // Verify that an impossible datadir fails creation - file, err := os.CreateTemp("", "") + file, err := os.CreateTemp(t.TempDir(), "") if err != nil { t.Fatalf("failed to create temporary file: %v", err) } defer func() { file.Close() - os.Remove(file.Name()) }() dir = filepath.Join(file.Name(), "invalid/path") From 3a52974c2f32a6460c9cd1419a66d8814f7a6040 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 23 Feb 2025 17:38:32 +0100 Subject: [PATCH 165/354] eth: report error from setupDiscovery at startup (#31233) I ran into this while trying to debug a discv5 thing. I tried to disable DNS discovery using `--discovery.dns=false`, which doesn't work. Annoyingly, geth started anyway and discarded the error silently. I eventually found my mistake, but it took way longer than it should have. Also including a small change to the error message for invalid DNS URLs here. The user actually needs to see the URL to make sense of the error. --- eth/backend.go | 4 +++- p2p/dnsdisc/client.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 42040c477..91397017e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -567,7 +567,9 @@ func (s *Ethereum) Protocols() []p2p.Protocol { // Start implements node.Lifecycle, starting all internal goroutines needed by the // Ethereum protocol implementation. func (s *Ethereum) Start() error { - s.setupDiscovery() + if err := s.setupDiscovery(); err != nil { + return err + } // Start the bloom bits servicing goroutines s.startBloomHandlers(params.BloomBitsBlocks) diff --git a/p2p/dnsdisc/client.go b/p2p/dnsdisc/client.go index 4f14d860e..ac369ce07 100644 --- a/p2p/dnsdisc/client.go +++ b/p2p/dnsdisc/client.go @@ -263,7 +263,7 @@ func (it *randomIterator) Next() bool { func (it *randomIterator) addTree(url string) error { le, err := parseLink(url) if err != nil { - return fmt.Errorf("invalid enrtree URL: %v", err) + return fmt.Errorf("invalid DNS discovery URL %q: %v", url, err) } it.lc.addLink("", le.str) return nil From 75b20d57121f329b3b6fd76a600c92d4d0f2ab61 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 24 Feb 2025 10:31:33 +0100 Subject: [PATCH 166/354] go.mod: update cloudflare-go (#31240) Updates cloudflare-go from v0.79.0 to v0.114.0 which also gets rid of a dependency to `github.com/hashicorp/go-retryablehttp` which had a security flaw. Diff: https://github.com/cloudflare/cloudflare-go/compare/v0.79.0...v0.114.0 I did a quick sanity check on the diff on all methods that we use and went through the release notes, there was nothing related to how we use it afaict --- go.mod | 14 ++++++-------- go.sum | 31 ++++++++++++------------------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index fbf852628..a2035ce62 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 github.com/bane-labs/zk-dkg v0.3.0 github.com/cespare/cp v0.1.0 - github.com/cloudflare/cloudflare-go v0.79.0 + github.com/cloudflare/cloudflare-go v0.114.0 github.com/cockroachdb/pebble v1.1.2 github.com/consensys/gnark v0.13.0 github.com/consensys/gnark-crypto v0.18.0 @@ -65,7 +65,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/supranational/blst v0.3.14 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/urfave/cli/v2 v2.25.7 + github.com/urfave/cli/v2 v2.27.5 github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 go.uber.org/automaxprocs v1.5.2 go.uber.org/zap v1.27.0 @@ -74,7 +74,7 @@ require ( golang.org/x/sync v0.15.0 golang.org/x/sys v0.33.0 golang.org/x/text v0.26.0 - golang.org/x/time v0.5.0 + golang.org/x/time v0.9.0 golang.org/x/tools v0.34.0 google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -104,7 +104,7 @@ require ( github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.8.0 // indirect @@ -112,13 +112,11 @@ require ( github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect @@ -151,7 +149,7 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect diff --git a/go.sum b/go.sum index 4d67804bb..67779bd92 100644 --- a/go.sum +++ b/go.sum @@ -111,8 +111,8 @@ github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86c github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M= -github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= +github.com/cloudflare/cloudflare-go v0.114.0 h1:ucoti4/7Exo0XQ+rzpn1H+IfVVe++zgiM+tyKtf0HUA= +github.com/cloudflare/cloudflare-go v0.114.0/go.mod h1:O7fYfFfA6wKqKFn2QIR9lhj7FDw6VQCGOY6hd2TBtd0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= @@ -133,8 +133,8 @@ github.com/consensys/gnark v0.13.0/go.mod h1:F6k35ZIi9GC//wW2i9Fz9mURBcLF8qJLQQ/ github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= @@ -215,8 +215,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -302,13 +302,6 @@ github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY4 github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= -github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -541,8 +534,8 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10 h1:CQh33pStIp/E30b7TxDlXfM0145bn2e8boI30IxAhTg= github.com/umbracle/gohashtree v0.0.2-alpha.0.20230207094856-5b775a815c10/go.mod h1:x/Pa0FF5Te9kdrlZKJK82YmAkvL8+f989USgz6Jiw7M= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -554,8 +547,8 @@ github.com/wealdtech/go-eth2-wallet-types/v2 v2.11.0 h1:yX9+FfUXvPDvZ8Q5bhF+64AW github.com/wealdtech/go-eth2-wallet-types/v2 v2.11.0/go.mod h1:UVP9YFcnPiIzHqbmCMW3qrQ3TK5FOqr1fmKqNT9JGr8= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -782,8 +775,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= From 36504656824f0a03394f2e863c49416363dec15b Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 24 Feb 2025 12:23:25 +0100 Subject: [PATCH 167/354] crypto: add comment to FromECDSAPub (#31241) closes https://github.com/ethereum/go-ethereum/issues/26240 --- crypto/crypto.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crypto/crypto.go b/crypto/crypto.go index f25fca412..e2959bc4d 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -184,6 +184,9 @@ func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil } +// FromECDSAPub converts a secp256k1 public key to bytes. +// Note: it does not use the curve from pub, instead it always +// encodes using secp256k1. func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil From b2f8bc31e421c2b8b4d38febbcacedcf9935bd0d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 25 Feb 2025 05:17:21 +0800 Subject: [PATCH 168/354] core/txpool: move setcode tx validation into legacyPool (#31209) In this PR, several improvements have been made: Authorization-related validations have been moved to legacyPool. Previously, these checks were part of the standard validation procedure, which applies common validations across different pools. Since these checks are specific to SetCode transactions, relocating them to legacyPool is a more reasonable choice. Additionally, authorization conflict checks are now performed regardless of whether the transaction is a replacement or not. --------- Co-authored-by: lightclient --- core/txpool/errors.go | 13 ---- core/txpool/legacypool/cachepool.go | 45 +++++++++--- core/txpool/legacypool/legacypool.go | 84 +++++++++++++++-------- core/txpool/legacypool/legacypool_test.go | 24 +++---- core/txpool/validation.go | 19 ++--- 5 files changed, 107 insertions(+), 78 deletions(-) diff --git a/core/txpool/errors.go b/core/txpool/errors.go index a6c0e38f9..5ac280749 100644 --- a/core/txpool/errors.go +++ b/core/txpool/errors.go @@ -58,22 +58,9 @@ var ( // making the transaction invalid, rather a DOS protection. ErrOversizedData = errors.New("oversized data") - // ErrFutureReplacePending is returned if a future transaction replaces a pending - // one. Future transactions should only be able to replace other future transactions. - ErrFutureReplacePending = errors.New("future transaction tries to replace pending") - // ErrAlreadyReserved is returned if the sender address has a pending transaction // in a different subpool. For example, this error is returned in response to any // input transaction of non-blob type when a blob transaction from this sender // remains pending (and vice-versa). ErrAlreadyReserved = errors.New("address already reserved") - - // ErrAuthorityReserved is returned if a transaction has an authorization - // signed by an address which already has in-flight transactions known to the - // pool. - ErrAuthorityReserved = errors.New("authority already reserved") - - // ErrAuthorityNonce is returned if a transaction has an authorization with - // a nonce that is not currently valid for the authority. - ErrAuthorityNonceTooLow = errors.New("authority nonce too low") ) diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index 83968e8e5..cef99acec 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -3,7 +3,6 @@ package legacypool import ( "errors" "fmt" - "math" "math/big" "sync" "sync/atomic" @@ -387,14 +386,8 @@ func (pool *CachePool) validateTx(tx *types.Transaction) error { opts := &txpool.ValidationOptionsWithState{ State: pool.currentState, - FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps - UsedAndLeftSlots: func(addr common.Address) (int, int) { - var have int - if list := pool.cached[addr]; list != nil { - have += list.Len() - } - return have, math.MaxInt - }, + FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps + UsedAndLeftSlots: nil, // Pool has own mechanism to limit the number of transactions ExistingExpenditure: func(addr common.Address) *big.Int { if list := pool.cached[addr]; list != nil { return list.totalcost.ToBig() @@ -413,6 +406,40 @@ func (pool *CachePool) validateTx(tx *types.Transaction) error { if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil { return err } + return pool.validateAuth(tx) +} + +// validateAuth verifies that the transaction complies with code authorization +// restrictions brought by SetCode transaction type. +func (pool *CachePool) validateAuth(tx *types.Transaction) error { + from, _ := types.Sender(pool.signer, tx) // validated + + // Allow at most one in-flight tx for delegated accounts or those with a + // pending authorization. + if pool.currentState.GetCodeHash(from) != types.EmptyCodeHash || len(pool.all.auths[from]) != 0 { + var ( + count int + exists bool + ) + cached := pool.cached[from] + if cached != nil { + count += cached.Len() + exists = cached.Contains(tx.Nonce()) + } + // Replace the existing in-flight transaction for delegated accounts + // are still supported + if count >= 1 && !exists { + return ErrInflightTxLimitReached + } + } + // Authorities cannot conflict with any cached transactions. + if auths := tx.SetCodeAuthorities(); len(auths) > 0 { + for _, auth := range auths { + if pool.cached[auth] != nil { + return ErrAuthorityReserved + } + } + } return nil } diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 2d3a1048c..d033907cb 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -71,6 +71,19 @@ var ( // ErrTxPoolOverflow is returned if the transaction pool is full and can't accept // another remote transaction. ErrTxPoolOverflow = errors.New("txpool is full") + + // ErrInflightTxLimitReached is returned when the maximum number of in-flight + // transactions is reached for specific accounts. + ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts") + + // ErrAuthorityReserved is returned if a transaction has an authorization + // signed by an address which already has in-flight transactions known to the + // pool. + ErrAuthorityReserved = errors.New("authority already reserved") + + // ErrFutureReplacePending is returned if a future transaction replaces a pending + // one. Future transactions should only be able to replace other future transactions. + ErrFutureReplacePending = errors.New("future transaction tries to replace pending") ) var ( @@ -693,22 +706,8 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { opts := &txpool.ValidationOptionsWithState{ State: pool.currentState, - FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps - UsedAndLeftSlots: func(addr common.Address) (int, int) { - var have int - if list := pool.pending[addr]; list != nil { - have += list.Len() - } - if list := pool.queue[addr]; list != nil { - have += list.Len() - } - if pool.currentState.GetCodeHash(addr) != types.EmptyCodeHash || len(pool.all.auths[addr]) != 0 { - // Allow at most one in-flight tx for delegated accounts or those with - // a pending authorization. - return have, max(0, 1-have) - } - return have, math.MaxInt - }, + FirstNonceGap: nil, // Pool allows arbitrary arrival order, don't invalidate nonce gaps + UsedAndLeftSlots: nil, // Pool has own mechanism to limit the number of transactions ExistingExpenditure: func(addr common.Address) *big.Int { if list := pool.pending[addr]; list != nil { return list.totalcost.ToBig() @@ -723,22 +722,49 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { } return nil }, - KnownConflicts: func(from common.Address, auths []common.Address) []common.Address { - var conflicts []common.Address - // Authorities cannot conflict with any pending or queued transactions. - for _, addr := range auths { - if list := pool.pending[addr]; list != nil { - conflicts = append(conflicts, addr) - } else if list := pool.queue[addr]; list != nil { - conflicts = append(conflicts, addr) - } - } - return conflicts - }, } if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil { return err } + return pool.validateAuth(tx) +} + +// validateAuth verifies that the transaction complies with code authorization +// restrictions brought by SetCode transaction type. +func (pool *LegacyPool) validateAuth(tx *types.Transaction) error { + from, _ := types.Sender(pool.signer, tx) // validated + + // Allow at most one in-flight tx for delegated accounts or those with a + // pending authorization. + if pool.currentState.GetCodeHash(from) != types.EmptyCodeHash || len(pool.all.auths[from]) != 0 { + var ( + count int + exists bool + ) + pending := pool.pending[from] + if pending != nil { + count += pending.Len() + exists = pending.Contains(tx.Nonce()) + } + queue := pool.queue[from] + if queue != nil { + count += queue.Len() + exists = exists || queue.Contains(tx.Nonce()) + } + // Replace the existing in-flight transaction for delegated accounts + // are still supported + if count >= 1 && !exists { + return ErrInflightTxLimitReached + } + } + // Authorities cannot conflict with any pending or queued transactions. + if auths := tx.SetCodeAuthorities(); len(auths) > 0 { + for _, auth := range auths { + if pool.pending[auth] != nil || pool.queue[auth] != nil { + return ErrAuthorityReserved + } + } + } return nil } @@ -830,7 +856,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) { pool.priced.Put(dropTx) } log.Trace("Discarding future transaction replacing pending tx", "hash", hash) - return false, txpool.ErrFutureReplacePending + return false, ErrFutureReplacePending } } diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 7e35e0cc6..b2a068467 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -1645,8 +1645,8 @@ func TestUnderpricing(t *testing.T) { t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that replacing a pending transaction with a future transaction fails - if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != txpool.ErrFutureReplacePending { - t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, txpool.ErrFutureReplacePending) + if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending { + t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending) } pending, queued = pool.Stats() if pending != 4 { @@ -2248,12 +2248,12 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { t.Fatalf("%s: failed to add remote transaction: %v", name, err) } - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) } // Also check gapped transaction. - if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) } // Replace by fee. if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil { @@ -2287,8 +2287,8 @@ func TestSetCodeTransactions(t *testing.T) { t.Fatalf("%s: failed to add with pending delegatio: %v", name, err) } // Also check gapped transaction is rejected. - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrAccountLimitExceeded, err) + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) } }, }, @@ -2363,7 +2363,7 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err) } - if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrAccountLimitExceeded; !errors.Is(err, want) { + if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), ErrInflightTxLimitReached; !errors.Is(err, want) { t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) } }, @@ -2376,7 +2376,7 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } - if err, want := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})), txpool.ErrAuthorityReserved; !errors.Is(err, want) { + if err, want := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})), ErrAuthorityReserved; !errors.Is(err, want) { t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) } }, @@ -2440,8 +2440,8 @@ func TestSetCodeTransactionsReorg(t *testing.T) { t.Fatalf("failed to add with remote setcode transaction: %v", err) } // Try to add a transactions in - if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, txpool.ErrAccountLimitExceeded) { - t.Fatalf("unexpected error %v, expecting %v", err, txpool.ErrAccountLimitExceeded) + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { + t.Fatalf("unexpected error %v, expecting %v", err, ErrInflightTxLimitReached) } // Simulate the chain moving blockchain.statedb.SetNonce(addrA, 2, tracing.NonceChangeAuthorization) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index e7f42586f..5d041d063 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -208,7 +208,7 @@ type ValidationOptionsWithState struct { // nonce gaps will be ignored and permitted. FirstNonceGap func(addr common.Address) uint64 - // UsedAndLeftSlots is a mandatory callback to retrieve the number of tx slots + // UsedAndLeftSlots is an optional callback to retrieve the number of tx slots // used and the number still permitted for an account. New transactions will // be rejected once the number of remaining slots reaches zero. UsedAndLeftSlots func(addr common.Address) (int, int) @@ -220,11 +220,6 @@ type ValidationOptionsWithState struct { // ExistingCost is a mandatory callback to retrieve an already pooled // transaction's cost with the given nonce to check for overdrafts. ExistingCost func(addr common.Address, nonce uint64) *big.Int - - // KnownConflicts is an optional callback which iterates over the list of - // addresses and returns all addresses known to the pool with in-flight - // transactions. - KnownConflicts func(sender common.Address, authorizers []common.Address) []common.Address } // ValidateTransactionWithState is a helper method to check whether a transaction @@ -313,15 +308,9 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op // Transaction takes a new nonce value out of the pool. Ensure it doesn't // overflow the number of permitted transactions from a single account // (i.e. max cancellable via out-of-bound transaction). - if used, left := opts.UsedAndLeftSlots(from); left <= 0 { - return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used) - } - - // Verify no authorizations will invalidate existing transactions known to - // the pool. - if opts.KnownConflicts != nil { - if conflicts := opts.KnownConflicts(from, tx.SetCodeAuthorities()); len(conflicts) > 0 { - return fmt.Errorf("%w: authorization conflicts with other known tx", ErrAuthorityReserved) + if opts.UsedAndLeftSlots != nil { + if used, left := opts.UsedAndLeftSlots(from); left <= 0 { + return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used) } } } From d8334d35df996cdac73f98375bb4e9cba9c09a7a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 25 Feb 2025 00:42:00 +0100 Subject: [PATCH 169/354] params: add deposit contract addresses (#31247) We forgot to add the deposit contract address for holesky, causing deposits to not be flagged correctly --------- Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- params/config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/params/config.go b/params/config.go index 884866e21..29926c59e 100644 --- a/params/config.go +++ b/params/config.go @@ -88,6 +88,7 @@ var ( ShanghaiTime: newUint64(1696000704), CancunTime: newUint64(1707305664), PragueTime: newUint64(1740434112), + DepositContractAddress: common.HexToAddress("0x4242424242424242424242424242424242424242"), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, @@ -117,6 +118,7 @@ var ( ShanghaiTime: newUint64(1677557088), CancunTime: newUint64(1706655072), PragueTime: newUint64(1741159776), + DepositContractAddress: common.HexToAddress("0x7f02c3e3c98b133055b8b348b2ac625669ed295d"), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, From 141447a9201179a5f770944b4cb2f9eab49de0c4 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 25 Feb 2025 12:21:35 +0100 Subject: [PATCH 170/354] ethclient/simulated: add goroutine leak test (#31033) Adds a basic sanity test case to catch any go-routines leaked from instantiation/closing of a simulated backend. --- ethclient/simulated/backend_test.go | 19 +++++++++++++++++++ go.mod | 1 + 2 files changed, 20 insertions(+) diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index 5bf3c6be2..fc78e8436 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -25,6 +25,8 @@ import ( "testing" "time" + "go.uber.org/goleak" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" @@ -350,3 +352,20 @@ func TestAdjustTimeAfterFork(t *testing.T) { t.Errorf("failed to build block on fork") } } + +func createAndCloseSimBackend() { + genesisData := types.GenesisAlloc{} + simulatedBackend := NewBackend(genesisData) + defer simulatedBackend.Close() +} + +// TestCheckSimBackendGoroutineLeak checks whether creation of a simulated backend leaks go-routines. Any long-lived go-routines +// spawned by global variables are not considered leaked. +func TestCheckSimBackendGoroutineLeak(t *testing.T) { + createAndCloseSimBackend() + ignoreCur := goleak.IgnoreCurrent() + // ignore this leveldb function: this go-routine is guaranteed to be terminated 1 second after closing db handle + ignoreLdb := goleak.IgnoreAnyFunction("github.com/syndtr/goleveldb/leveldb.(*DB).mpoolDrain") + createAndCloseSimBackend() + goleak.VerifyNone(t, ignoreCur, ignoreLdb) +} diff --git a/go.mod b/go.mod index a2035ce62..bd27a56e8 100644 --- a/go.mod +++ b/go.mod @@ -68,6 +68,7 @@ require ( github.com/urfave/cli/v2 v2.27.5 github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.4.1 go.uber.org/automaxprocs v1.5.2 + go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.39.0 golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 From d3934d9963ab4f68f40e162468ab0e3119062d1c Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 25 Feb 2025 20:40:57 +0800 Subject: [PATCH 171/354] eth/protocols/eth: fix loading "eth" ENR key in dial filter (#31251) This fixes an issue where dial candidates from discv5 would be ignored because the "eth" ENR entry was not loaded correctly. --- eth/protocols/eth/discovery.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 075a85b69..f43e6f864 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -42,6 +42,7 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { var newHead = make(chan core.ChainHeadEvent, 10) sub := chain.SubscribeChainHeadEvent(newHead) + ln.Set(currentENREntry(chain)) go func() { defer sub.Unsubscribe() for { @@ -71,7 +72,7 @@ func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool { filter := forkid.NewFilter(chain) return func(n *enode.Node) bool { var entry enrEntry - if err := n.Load(entry); err != nil { + if err := n.Load(&entry); err != nil { return false } err := filter(entry.ForkID) From 99585116c3a0d844cba6e7b9402b41dd739d7065 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 26 Feb 2025 18:49:02 +0800 Subject: [PATCH 172/354] build: filter out .git folder for go generate check (#31265) Fixes lint issue >>> /home/appveyor/.gvm/gos/go1.24.0/bin/go generate ./... ci.go:404: File changed: .git/index ci.go:407: One or more generated files were updated by running 'go generate ./...' exit status 1 --- build/ci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 2f26f3ed9..f50c29268 100644 --- a/build/ci.go +++ b/build/ci.go @@ -385,7 +385,7 @@ func doCheckGenerate() { var hashes map[string][32]byte var err error - hashes, err = build.HashFolder(".", []string{"tests/testdata", "build/cache"}) + hashes, err = build.HashFolder(".", []string{"tests/testdata", "build/cache", ".git"}) if err != nil { log.Fatal("Error computing hashes", "err", err) } @@ -400,7 +400,7 @@ func doCheckGenerate() { build.MustRun(c) // Check if generate file hashes have changed - generated, err := build.HashFolder(".", []string{"tests/testdata", "build/cache"}) + generated, err := build.HashFolder(".", []string{"tests/testdata", "build/cache", ".git"}) if err != nil { log.Fatalf("Error re-computing hashes: %v", err) } From 68dc2437fc1db25458954218ccfa68cdf94de60a Mon Sep 17 00:00:00 2001 From: James Date: Thu, 27 Feb 2025 07:24:14 +1300 Subject: [PATCH 173/354] eth/gasprice: fix eth_feeHistory blobGasRatio (#31246) This change divides BlobGasUsed by MaxBlobGasPerBlock instead of MaxBlobsPerBlock. Dividing by MaxBlobsPerBlock meant the blobGasUsedRatio was an incorrect large number. This bug was introduced by a typo [here](https://github.com/ethereum/go-ethereum/commit/e6f3ce7b168b8f346de621a8f60d2fa57c2ebfb0#diff-3357b2399699d7cf954c543cbfb02ff442eb24491e55f5e813e3cc85829b3e8dR110) Fixes https://github.com/ethereum/go-ethereum/issues/31245 --- eth/gasprice/feehistory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 360199d8e..5885ce067 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -112,8 +112,8 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil // Compute gas used ratio for normal and blob gas. bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { - maxBlobs := eip4844.MaxBlobsPerBlock(config, bf.header.Time) - bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobs) + maxBlobGas := eip4844.MaxBlobGasPerBlock(config, bf.header.Time) + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobGas) } if len(percentiles) == 0 { From d2028bd3c571d2a52f62fb78eb23bd6691efe315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 27 Feb 2025 00:07:14 +0100 Subject: [PATCH 174/354] cmd/workload: RPC workload tests for filters and history (#31189) Co-authored-by: Felix Lange Co-authored-by: Sina Mahmoodi --- cmd/abigen/main.go | 2 +- cmd/utils/flags.go | 53 +-- cmd/workload/README.md | 29 ++ cmd/workload/filtertest.go | 216 ++++++++++ cmd/workload/filtertestgen.go | 382 ++++++++++++++++++ cmd/workload/filtertestperf.go | 137 +++++++ cmd/workload/historytest.go | 309 ++++++++++++++ cmd/workload/historytestgen.go | 147 +++++++ cmd/workload/main.go | 86 ++++ .../queries/filter_queries_mainnet.json | 1 + .../queries/filter_queries_sepolia.json | 1 + cmd/workload/queries/history_mainnet.json | 1 + cmd/workload/queries/history_sepolia.json | 1 + cmd/workload/testsuite.go | 145 +++++++ internal/flags/helpers.go | 42 ++ 15 files changed, 1504 insertions(+), 48 deletions(-) create mode 100644 cmd/workload/README.md create mode 100644 cmd/workload/filtertest.go create mode 100644 cmd/workload/filtertestgen.go create mode 100644 cmd/workload/filtertestperf.go create mode 100644 cmd/workload/historytest.go create mode 100644 cmd/workload/historytestgen.go create mode 100644 cmd/workload/main.go create mode 100644 cmd/workload/queries/filter_queries_mainnet.json create mode 100644 cmd/workload/queries/filter_queries_sepolia.json create mode 100644 cmd/workload/queries/history_mainnet.json create mode 100644 cmd/workload/queries/history_sepolia.json create mode 100644 cmd/workload/testsuite.go diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 8ee3130b5..10343190c 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -93,7 +93,7 @@ func init() { } func abigen(c *cli.Context) error { - utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. + flags.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. if c.String(pkgFlag.Name) == "" { utils.Fatalf("No destination package specified (--pkg)") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 0e456982a..dd7c4eac1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1287,7 +1287,7 @@ func setWS(ctx *cli.Context, cfg *node.Config) { // setIPC creates an IPC path configuration from the set command line flags, // returning an empty string if IPC was explicitly disabled, or the set path. func setIPC(ctx *cli.Context, cfg *node.Config) { - CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) + flags.CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) switch { case ctx.Bool(IPCDisabledFlag.Name): cfg.IPCPath = "" @@ -1436,8 +1436,8 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NoDiscovery = true } - CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag) - CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag) + flags.CheckExclusive(ctx, DiscoveryV4Flag, NoDiscoverFlag) + flags.CheckExclusive(ctx, DiscoveryV5Flag, NoDiscoverFlag) cfg.DiscoveryV4 = ctx.Bool(DiscoveryV4Flag.Name) cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name) @@ -1678,52 +1678,11 @@ func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { } } -// CheckExclusive verifies that only a single instance of the provided flags was -// set by the user. Each flag might optionally be followed by a string type to -// specialize it further. -func CheckExclusive(ctx *cli.Context, args ...interface{}) { - set := make([]string, 0, 1) - for i := 0; i < len(args); i++ { - // Make sure the next argument is a flag and skip if not set - flag, ok := args[i].(cli.Flag) - if !ok { - panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) - } - // Check if next arg extends current and expand its name if so - name := flag.Names()[0] - - if i+1 < len(args) { - switch option := args[i+1].(type) { - case string: - // Extended flag check, make sure value set doesn't conflict with passed in option - if ctx.String(flag.Names()[0]) == option { - name += "=" + option - set = append(set, "--"+name) - } - // shift arguments and continue - i++ - continue - - case cli.Flag: - default: - panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) - } - } - // Mark the flag if it's set - if ctx.IsSet(flag.Names()[0]) { - set = append(set, "--"+name) - } - } - if len(set) > 1 { - Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) - } -} - // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags - CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag) - CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer + flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag) + flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer // Set configurations from CLI flags setEtherbase(ctx, cfg) @@ -2016,7 +1975,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig { var config bparams.ClientConfig customConfig := ctx.IsSet(BeaconConfigFlag.Name) - CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, BeaconConfigFlag) + flags.CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, BeaconConfigFlag) switch { case ctx.Bool(MainnetFlag.Name): config.ChainConfig = *bparams.MainnetLightConfig diff --git a/cmd/workload/README.md b/cmd/workload/README.md new file mode 100644 index 000000000..c85e58a04 --- /dev/null +++ b/cmd/workload/README.md @@ -0,0 +1,29 @@ +## Workload Testing Tool + +This tool performs RPC calls against a live node. It has tests for the Sepolia testnet and +Mainnet. Note the tests require a fully synced node. + +To run the tests against a Sepolia node, use: + +```shell +> ./workload test --sepolia http://host:8545 +``` + +To run a specific test, use the `--run` flag to filter the test cases. Filtering works +similar to the `go test` command. For example, to run only tests for `eth_getBlockByHash` +and `eth_getBlockByNumber`, use this command: + +``` +> ./workload test --sepolia --run History/getBlockBy http://host:8545 +``` + +### Regenerating tests + +There is a facility for updating the tests from the chain. This can also be used to +generate the tests for a new network. As an example, to recreate tests for mainnet, run +the following commands (in this directory) against a synced mainnet node: + +```shell +> go run . filtergen --queries queries/filter_queries_mainnet.json http://host:8545 +> go run . historygen --history-tests queries/history_mainnet.json http://host:8545 +``` diff --git a/cmd/workload/filtertest.go b/cmd/workload/filtertest.go new file mode 100644 index 000000000..0e709ac0f --- /dev/null +++ b/cmd/workload/filtertest.go @@ -0,0 +1,216 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/utesting" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" +) + +type filterTestSuite struct { + cfg testConfig + queries [][]*filterQuery +} + +func newFilterTestSuite(cfg testConfig) *filterTestSuite { + s := &filterTestSuite{cfg: cfg} + if err := s.loadQueries(); err != nil { + exit(err) + } + return s +} + +func (s *filterTestSuite) allTests() []utesting.Test { + return []utesting.Test{ + {Name: "Filter/ShortRange", Fn: s.filterShortRange}, + {Name: "Filter/LongRange", Fn: s.filterLongRange, Slow: true}, + {Name: "Filter/FullRange", Fn: s.filterFullRange, Slow: true}, + } +} + +func (s *filterTestSuite) filterRange(t *utesting.T, test func(query *filterQuery) bool, do func(t *utesting.T, query *filterQuery)) { + var count, total int + for _, bucket := range s.queries { + for _, query := range bucket { + if test(query) { + total++ + } + } + } + if total == 0 { + t.Fatalf("No suitable queries available") + } + start := time.Now() + last := start + for _, bucket := range s.queries { + for _, query := range bucket { + if test(query) { + do(t, query) + count++ + if time.Since(last) > time.Second*5 { + t.Logf("Making filter query %d/%d (elapsed: %v)", count, total, time.Since(start)) + last = time.Now() + } + } + } + } + t.Logf("Made %d filter queries (elapsed: %v)", count, time.Since(start)) +} + +const filterRangeThreshold = 10000 + +// filterShortRange runs all short-range filter tests. +func (s *filterTestSuite) filterShortRange(t *utesting.T) { + s.filterRange(t, func(query *filterQuery) bool { + return query.ToBlock+1-query.FromBlock <= filterRangeThreshold + }, s.queryAndCheck) +} + +// filterShortRange runs all long-range filter tests. +func (s *filterTestSuite) filterLongRange(t *utesting.T) { + s.filterRange(t, func(query *filterQuery) bool { + return query.ToBlock+1-query.FromBlock > filterRangeThreshold + }, s.queryAndCheck) +} + +// filterFullRange runs all filter tests, extending their range from genesis up +// to the latest block. Note that results are only partially verified in this mode. +func (s *filterTestSuite) filterFullRange(t *utesting.T) { + finalized := mustGetFinalizedBlock(s.cfg.client) + s.filterRange(t, func(query *filterQuery) bool { + return query.ToBlock+1-query.FromBlock > finalized/2 + }, s.fullRangeQueryAndCheck) +} + +func (s *filterTestSuite) queryAndCheck(t *utesting.T, query *filterQuery) { + query.run(s.cfg.client) + if query.Err != nil { + t.Errorf("Filter query failed (fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics, query.Err) + return + } + if *query.ResultHash != query.calculateHash() { + t.Fatalf("Filter query result mismatch (fromBlock: %d toBlock: %d addresses: %v topics: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics) + } +} + +func (s *filterTestSuite) fullRangeQueryAndCheck(t *utesting.T, query *filterQuery) { + frQuery := &filterQuery{ // create full range query + FromBlock: 0, + ToBlock: int64(rpc.LatestBlockNumber), + Address: query.Address, + Topics: query.Topics, + } + frQuery.run(s.cfg.client) + if frQuery.Err != nil { + t.Errorf("Full range filter query failed (addresses: %v topics: %v error: %v)", frQuery.Address, frQuery.Topics, frQuery.Err) + return + } + // filter out results outside the original query range + j := 0 + for _, log := range frQuery.results { + if int64(log.BlockNumber) >= query.FromBlock && int64(log.BlockNumber) <= query.ToBlock { + frQuery.results[j] = log + j++ + } + } + frQuery.results = frQuery.results[:j] + if *query.ResultHash != frQuery.calculateHash() { + t.Fatalf("Full range filter query result mismatch (fromBlock: %d toBlock: %d addresses: %v topics: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics) + } +} + +func (s *filterTestSuite) loadQueries() error { + file, err := s.cfg.fsys.Open(s.cfg.filterQueryFile) + if err != nil { + return fmt.Errorf("can't open filterQueryFile: %v", err) + } + defer file.Close() + + var queries [][]*filterQuery + if err := json.NewDecoder(file).Decode(&queries); err != nil { + return fmt.Errorf("invalid JSON in %s: %v", s.cfg.filterQueryFile, err) + } + var count int + for _, bucket := range queries { + count += len(bucket) + } + if count == 0 { + return fmt.Errorf("filterQueryFile %s is empty", s.cfg.filterQueryFile) + } + s.queries = queries + return nil +} + +// filterQuery is a single query for testing. +type filterQuery struct { + FromBlock int64 `json:"fromBlock"` + ToBlock int64 `json:"toBlock"` + Address []common.Address `json:"address"` + Topics [][]common.Hash `json:"topics"` + ResultHash *common.Hash `json:"resultHash,omitempty"` + results []types.Log + Err error `json:"error,omitempty"` +} + +func (fq *filterQuery) isWildcard() bool { + if len(fq.Address) != 0 { + return false + } + for _, topics := range fq.Topics { + if len(topics) != 0 { + return false + } + } + return true +} + +func (fq *filterQuery) calculateHash() common.Hash { + enc, err := rlp.EncodeToBytes(&fq.results) + if err != nil { + exit(fmt.Errorf("Error encoding logs: %v", err)) + } + return crypto.Keccak256Hash(enc) +} + +func (fq *filterQuery) run(client *client) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) + defer cancel() + logs, err := client.Eth.FilterLogs(ctx, ethereum.FilterQuery{ + FromBlock: big.NewInt(fq.FromBlock), + ToBlock: big.NewInt(fq.ToBlock), + Addresses: fq.Address, + Topics: fq.Topics, + }) + if err != nil { + fq.Err = err + fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n", + fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err) + return + } + fq.results = logs +} diff --git a/cmd/workload/filtertestgen.go b/cmd/workload/filtertestgen.go new file mode 100644 index 000000000..29aad9ddd --- /dev/null +++ b/cmd/workload/filtertestgen.go @@ -0,0 +1,382 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "encoding/json" + "fmt" + "math" + "math/big" + "math/rand" + "os" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/rpc" + "github.com/urfave/cli/v2" +) + +var ( + filterGenerateCommand = &cli.Command{ + Name: "filtergen", + Usage: "Generates query set for log filter workload test", + ArgsUsage: "", + Action: filterGenCmd, + Flags: []cli.Flag{ + filterQueryFileFlag, + filterErrorFileFlag, + }, + } + filterQueryFileFlag = &cli.StringFlag{ + Name: "queries", + Usage: "JSON file containing filter test queries", + Value: "filter_queries.json", + Category: flags.TestingCategory, + } + filterErrorFileFlag = &cli.StringFlag{ + Name: "errors", + Usage: "JSON file containing failed filter queries", + Value: "filter_errors.json", + Category: flags.TestingCategory, + } +) + +// filterGenCmd is the main function of the filter tests generator. +func filterGenCmd(ctx *cli.Context) error { + f := newFilterTestGen(ctx) + lastWrite := time.Now() + for { + select { + case <-ctx.Done(): + return nil + default: + } + + f.updateFinalizedBlock() + query := f.newQuery() + query.run(f.client) + if query.Err != nil { + f.errors = append(f.errors, query) + continue + } + if len(query.results) > 0 && len(query.results) <= maxFilterResultSize { + for { + extQuery := f.extendRange(query) + if extQuery == nil { + break + } + extQuery.run(f.client) + if extQuery.Err == nil && len(extQuery.results) < len(query.results) { + extQuery.Err = fmt.Errorf("invalid result length; old range %d %d; old length %d; new range %d %d; new length %d; address %v; Topics %v", + query.FromBlock, query.ToBlock, len(query.results), + extQuery.FromBlock, extQuery.ToBlock, len(extQuery.results), + extQuery.Address, extQuery.Topics, + ) + } + if extQuery.Err != nil { + f.errors = append(f.errors, extQuery) + break + } + if len(extQuery.results) > maxFilterResultSize { + break + } + query = extQuery + } + f.storeQuery(query) + if time.Since(lastWrite) > time.Second*10 { + f.writeQueries() + f.writeErrors() + lastWrite = time.Now() + } + } + } +} + +// filterTestGen is the filter query test generator. +type filterTestGen struct { + client *client + queryFile string + errorFile string + + finalizedBlock int64 + queries [filterBuckets][]*filterQuery + errors []*filterQuery +} + +func newFilterTestGen(ctx *cli.Context) *filterTestGen { + return &filterTestGen{ + client: makeClient(ctx), + queryFile: ctx.String(filterQueryFileFlag.Name), + errorFile: ctx.String(filterErrorFileFlag.Name), + } +} + +func (s *filterTestGen) updateFinalizedBlock() { + s.finalizedBlock = mustGetFinalizedBlock(s.client) +} + +const ( + // Parameter of the random filter query generator. + maxFilterRange = 10000000 + maxFilterResultSize = 300 + filterBuckets = 10 + maxFilterBucketSize = 100 + filterSeedChance = 10 + filterMergeChance = 45 +) + +// storeQuery adds a filter query to the output file. +func (s *filterTestGen) storeQuery(query *filterQuery) { + query.ResultHash = new(common.Hash) + *query.ResultHash = query.calculateHash() + logRatio := math.Log(float64(len(query.results))*float64(s.finalizedBlock)/float64(query.ToBlock+1-query.FromBlock)) / math.Log(float64(s.finalizedBlock)*maxFilterResultSize) + bucket := int(math.Floor(logRatio * filterBuckets)) + if bucket >= filterBuckets { + bucket = filterBuckets - 1 + } + if len(s.queries[bucket]) < maxFilterBucketSize { + s.queries[bucket] = append(s.queries[bucket], query) + } else { + s.queries[bucket][rand.Intn(len(s.queries[bucket]))] = query + } + fmt.Print("Generated queries per bucket:") + for _, list := range s.queries { + fmt.Print(" ", len(list)) + } + fmt.Println() +} + +func (s *filterTestGen) extendRange(q *filterQuery) *filterQuery { + rangeLen := q.ToBlock + 1 - q.FromBlock + extLen := rand.Int63n(rangeLen) + 1 + if rangeLen+extLen > s.finalizedBlock { + return nil + } + extBefore := min(rand.Int63n(extLen+1), q.FromBlock) + extAfter := extLen - extBefore + if q.ToBlock+extAfter > s.finalizedBlock { + d := q.ToBlock + extAfter - s.finalizedBlock + extAfter -= d + if extBefore+d <= q.FromBlock { + extBefore += d + } else { + extBefore = q.FromBlock + } + } + return &filterQuery{ + FromBlock: q.FromBlock - extBefore, + ToBlock: q.ToBlock + extAfter, + Address: q.Address, + Topics: q.Topics, + } +} + +// newQuery generates a new filter query. +func (s *filterTestGen) newQuery() *filterQuery { + for { + t := rand.Intn(100) + if t < filterSeedChance { + return s.newSeedQuery() + } + if t < filterSeedChance+filterMergeChance { + if query := s.newMergedQuery(); query != nil { + return query + } + continue + } + if query := s.newNarrowedQuery(); query != nil { + return query + } + } +} + +// newSeedQuery creates a query that gets all logs in a random non-finalized block. +func (s *filterTestGen) newSeedQuery() *filterQuery { + block := rand.Int63n(s.finalizedBlock + 1) + return &filterQuery{ + FromBlock: block, + ToBlock: block, + } +} + +// newMergedQuery creates a new query by combining (with OR) the filter criteria +// of two existing queries (chosen at random). +func (s *filterTestGen) newMergedQuery() *filterQuery { + q1 := s.randomQuery() + q2 := s.randomQuery() + if q1 == nil || q2 == nil || q1 == q2 { + return nil + } + var ( + block int64 + topicCount int + ) + if rand.Intn(2) == 0 { + block = q1.FromBlock + rand.Int63n(q1.ToBlock+1-q1.FromBlock) + topicCount = len(q1.Topics) + } else { + block = q2.FromBlock + rand.Int63n(q2.ToBlock+1-q2.FromBlock) + topicCount = len(q2.Topics) + } + m := &filterQuery{ + FromBlock: block, + ToBlock: block, + Topics: make([][]common.Hash, topicCount), + } + for _, addr := range q1.Address { + if rand.Intn(2) == 0 { + m.Address = append(m.Address, addr) + } + } + for _, addr := range q2.Address { + if rand.Intn(2) == 0 { + m.Address = append(m.Address, addr) + } + } + for i := range m.Topics { + if len(q1.Topics) > i { + for _, topic := range q1.Topics[i] { + if rand.Intn(2) == 0 { + m.Topics[i] = append(m.Topics[i], topic) + } + } + } + if len(q2.Topics) > i { + for _, topic := range q2.Topics[i] { + if rand.Intn(2) == 0 { + m.Topics[i] = append(m.Topics[i], topic) + } + } + } + } + return m +} + +// newNarrowedQuery creates a new query by 'narrowing' an existing (randomly chosen) +// query. The new query is made more specific by analyzing the filter criteria and adding +// topics/addresses from the known result set. +func (s *filterTestGen) newNarrowedQuery() *filterQuery { + q := s.randomQuery() + if q == nil { + return nil + } + log := q.results[rand.Intn(len(q.results))] + var emptyCount int + if len(q.Address) == 0 { + emptyCount++ + } + for i := range log.Topics { + if len(q.Topics) <= i || len(q.Topics[i]) == 0 { + emptyCount++ + } + } + if emptyCount == 0 { + return nil + } + query := &filterQuery{ + FromBlock: q.FromBlock, + ToBlock: q.ToBlock, + Address: make([]common.Address, len(q.Address)), + Topics: make([][]common.Hash, len(q.Topics)), + } + copy(query.Address, q.Address) + for i, topics := range q.Topics { + if len(topics) > 0 { + query.Topics[i] = make([]common.Hash, len(topics)) + copy(query.Topics[i], topics) + } + } + pick := rand.Intn(emptyCount) + if len(query.Address) == 0 { + if pick == 0 { + query.Address = []common.Address{log.Address} + return query + } + pick-- + } + for i := range log.Topics { + if len(query.Topics) <= i || len(query.Topics[i]) == 0 { + if pick == 0 { + if len(query.Topics) <= i { + query.Topics = append(query.Topics, make([][]common.Hash, i+1-len(query.Topics))...) + } + query.Topics[i] = []common.Hash{log.Topics[i]} + return query + } + pick-- + } + } + panic("unreachable") +} + +// randomQuery returns a random query from the ones that were already generated. +func (s *filterTestGen) randomQuery() *filterQuery { + var bucket, bucketCount int + for _, list := range s.queries { + if len(list) > 0 { + bucketCount++ + } + } + if bucketCount == 0 { + return nil + } + pick := rand.Intn(bucketCount) + for i, list := range s.queries { + if len(list) > 0 { + if pick == 0 { + bucket = i + break + } + pick-- + } + } + return s.queries[bucket][rand.Intn(len(s.queries[bucket]))] +} + +// writeQueries serializes the generated queries to the output file. +func (s *filterTestGen) writeQueries() { + file, err := os.Create(s.queryFile) + if err != nil { + exit(fmt.Errorf("Error creating filter test query file %s: %v", s.queryFile, err)) + return + } + json.NewEncoder(file).Encode(&s.queries) + file.Close() +} + +// writeQueries serializes the generated errors to the error file. +func (s *filterTestGen) writeErrors() { + file, err := os.Create(s.errorFile) + if err != nil { + exit(fmt.Errorf("Error creating filter error file %s: %v", s.errorFile, err)) + return + } + defer file.Close() + json.NewEncoder(file).Encode(s.errors) +} + +func mustGetFinalizedBlock(client *client) int64 { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + header, err := client.Eth.HeaderByNumber(ctx, big.NewInt(int64(rpc.FinalizedBlockNumber))) + if err != nil { + exit(fmt.Errorf("could not fetch finalized header (error: %v)", err)) + } + return header.Number.Int64() +} diff --git a/cmd/workload/filtertestperf.go b/cmd/workload/filtertestperf.go new file mode 100644 index 000000000..c1f2aff58 --- /dev/null +++ b/cmd/workload/filtertestperf.go @@ -0,0 +1,137 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "math/rand" + "slices" + "sort" + "time" + + "github.com/urfave/cli/v2" +) + +var ( + filterPerfCommand = &cli.Command{ + Name: "filterperf", + Usage: "Runs log filter performance test against an RPC endpoint", + ArgsUsage: "", + Action: filterPerfCmd, + Flags: []cli.Flag{ + testSepoliaFlag, + testMainnetFlag, + filterQueryFileFlag, + filterErrorFileFlag, + }, + } +) + +const passCount = 1 + +func filterPerfCmd(ctx *cli.Context) error { + cfg := testConfigFromCLI(ctx) + f := newFilterTestSuite(cfg) + + type queryTest struct { + query *filterQuery + bucket, index int + runtime []time.Duration + medianTime time.Duration + } + var queries, processed []queryTest + for i, bucket := range f.queries[:] { + for j, query := range bucket { + queries = append(queries, queryTest{query: query, bucket: i, index: j}) + } + } + + // Run test queries. + var failed, mismatch int + for i := 1; i <= passCount; i++ { + fmt.Println("Performance test pass", i, "/", passCount) + for len(queries) > 0 { + pick := rand.Intn(len(queries)) + qt := queries[pick] + queries[pick] = queries[len(queries)-1] + queries = queries[:len(queries)-1] + start := time.Now() + qt.query.run(cfg.client) + qt.runtime = append(qt.runtime, time.Since(start)) + slices.Sort(qt.runtime) + qt.medianTime = qt.runtime[len(qt.runtime)/2] + if qt.query.Err != nil { + failed++ + continue + } + if rhash := qt.query.calculateHash(); *qt.query.ResultHash != rhash { + fmt.Printf("Filter query result mismatch: fromBlock: %d toBlock: %d addresses: %v topics: %v expected hash: %064x calculated hash: %064x\n", qt.query.FromBlock, qt.query.ToBlock, qt.query.Address, qt.query.Topics, *qt.query.ResultHash, rhash) + continue + } + processed = append(processed, qt) + if len(processed)%50 == 0 { + fmt.Println(" processed:", len(processed), "remaining", len(queries), "failed:", failed, "result mismatch:", mismatch) + } + } + queries, processed = processed, nil + } + + // Show results and stats. + fmt.Println("Performance test finished; processed:", len(queries), "failed:", failed, "result mismatch:", mismatch) + stats := make([]bucketStats, len(f.queries)) + var wildcardStats bucketStats + for _, qt := range queries { + bs := &stats[qt.bucket] + if qt.query.isWildcard() { + bs = &wildcardStats + } + bs.blocks += qt.query.ToBlock + 1 - qt.query.FromBlock + bs.count++ + bs.logs += len(qt.query.results) + bs.runtime += qt.medianTime + } + + fmt.Println() + for i := range stats { + stats[i].print(fmt.Sprintf("bucket #%d", i+1)) + } + wildcardStats.print("wild card queries") + fmt.Println() + sort.Slice(queries, func(i, j int) bool { + return queries[i].medianTime > queries[j].medianTime + }) + for i := 0; i < 10; i++ { + q := queries[i] + fmt.Printf("Most expensive query #%-2d median runtime: %13v max runtime: %13v result count: %4d fromBlock: %9d toBlock: %9d addresses: %v topics: %v\n", + i+1, q.medianTime, q.runtime[len(q.runtime)-1], len(q.query.results), q.query.FromBlock, q.query.ToBlock, q.query.Address, q.query.Topics) + } + return nil +} + +type bucketStats struct { + blocks int64 + count, logs int + runtime time.Duration +} + +func (st *bucketStats) print(name string) { + if st.count == 0 { + return + } + fmt.Printf("%-20s queries: %4d average block length: %12.2f average log count: %7.2f average runtime: %13v\n", + name, st.count, float64(st.blocks)/float64(st.count), float64(st.logs)/float64(st.count), st.runtime/time.Duration(st.count)) +} diff --git a/cmd/workload/historytest.go b/cmd/workload/historytest.go new file mode 100644 index 000000000..a68151042 --- /dev/null +++ b/cmd/workload/historytest.go @@ -0,0 +1,309 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/utesting" +) + +// historyTest is the content of a history test. +type historyTest struct { + BlockNumbers []uint64 `json:"blockNumbers"` + BlockHashes []common.Hash `json:"blockHashes"` + TxCounts []int `json:"txCounts"` + TxHashIndex []int `json:"txHashIndex"` + TxHashes []*common.Hash `json:"txHashes"` + ReceiptsHashes []common.Hash `json:"blockReceiptsHashes"` +} + +type historyTestSuite struct { + cfg testConfig + tests historyTest +} + +func newHistoryTestSuite(cfg testConfig) *historyTestSuite { + s := &historyTestSuite{cfg: cfg} + if err := s.loadTests(); err != nil { + exit(err) + } + return s +} + +func (s *historyTestSuite) loadTests() error { + file, err := s.cfg.fsys.Open(s.cfg.historyTestFile) + if err != nil { + return fmt.Errorf("can't open historyTestFile: %v", err) + } + defer file.Close() + if err := json.NewDecoder(file).Decode(&s.tests); err != nil { + return fmt.Errorf("invalid JSON in %s: %v", s.cfg.historyTestFile, err) + } + if len(s.tests.BlockNumbers) == 0 { + return fmt.Errorf("historyTestFile %s has no test data", s.cfg.historyTestFile) + } + return nil +} + +func (s *historyTestSuite) allTests() []utesting.Test { + return []utesting.Test{ + { + Name: "History/getBlockByHash", + Fn: s.testGetBlockByHash, + }, + { + Name: "History/getBlockByNumber", + Fn: s.testGetBlockByNumber, + }, + { + Name: "History/getBlockReceiptsByHash", + Fn: s.testGetBlockReceiptsByHash, + }, + { + Name: "History/getBlockReceiptsByNumber", + Fn: s.testGetBlockReceiptsByNumber, + }, + { + Name: "History/getBlockTransactionCountByHash", + Fn: s.testGetBlockTransactionCountByHash, + }, + { + Name: "History/getBlockTransactionCountByNumber", + Fn: s.testGetBlockTransactionCountByNumber, + }, + { + Name: "History/getTransactionByBlockHashAndIndex", + Fn: s.testGetTransactionByBlockHashAndIndex, + }, + { + Name: "History/getTransactionByBlockNumberAndIndex", + Fn: s.testGetTransactionByBlockNumberAndIndex, + }, + } +} + +func (s *historyTestSuite) testGetBlockByHash(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + b, err := s.cfg.client.getBlockByHash(ctx, bhash, false) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + if b == nil { + t.Errorf("block %d (hash %v): not found", num, bhash) + continue + } + if b.Hash != bhash || uint64(b.Number) != num { + t.Errorf("block %d (hash %v): invalid number/hash", num, bhash) + } + } +} + +func (s *historyTestSuite) testGetBlockByNumber(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + b, err := s.cfg.client.getBlockByNumber(ctx, num, false) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + if b == nil { + t.Errorf("block %d (hash %v): not found", num, bhash) + continue + } + if b.Hash != bhash || uint64(b.Number) != num { + t.Errorf("block %d (hash %v): invalid number/hash", num, bhash) + } + } +} + +func (s *historyTestSuite) testGetBlockTransactionCountByHash(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + count, err := s.cfg.client.getBlockTransactionCountByHash(ctx, bhash) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + expectedCount := uint64(s.tests.TxCounts[i]) + if count != expectedCount { + t.Errorf("block %d (hash %v): wrong txcount %d, want %d", count, expectedCount) + } + } +} + +func (s *historyTestSuite) testGetBlockTransactionCountByNumber(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + count, err := s.cfg.client.getBlockTransactionCountByNumber(ctx, num) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + expectedCount := uint64(s.tests.TxCounts[i]) + if count != expectedCount { + t.Errorf("block %d (hash %v): wrong txcount %d, want %d", count, expectedCount) + } + } +} + +func (s *historyTestSuite) testGetBlockReceiptsByHash(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + receipts, err := s.cfg.client.getBlockReceipts(ctx, bhash) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + hash := calcReceiptsHash(receipts) + expectedHash := s.tests.ReceiptsHashes[i] + if hash != expectedHash { + t.Errorf("block %d (hash %v): wrong receipts hash %v, want %v", num, bhash, hash, expectedHash) + } + } +} + +func (s *historyTestSuite) testGetBlockReceiptsByNumber(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + receipts, err := s.cfg.client.getBlockReceipts(ctx, hexutil.Uint64(num)) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + hash := calcReceiptsHash(receipts) + expectedHash := s.tests.ReceiptsHashes[i] + if hash != expectedHash { + t.Errorf("block %d (hash %v): wrong receipts hash %v, want %v", num, bhash, hash, expectedHash) + } + } +} + +func (s *historyTestSuite) testGetTransactionByBlockHashAndIndex(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + txIndex := s.tests.TxHashIndex[i] + expectedHash := s.tests.TxHashes[i] + if expectedHash == nil { + continue // no txs in block + } + + tx, err := s.cfg.client.getTransactionByBlockHashAndIndex(ctx, bhash, uint64(txIndex)) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + if tx == nil { + t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex) + continue + } + if tx.Hash != *expectedHash || uint64(tx.TransactionIndex) != uint64(txIndex) { + t.Errorf("block %d (hash %v): txIndex %d has wrong txHash/Index", num, bhash, txIndex) + } + } +} + +func (s *historyTestSuite) testGetTransactionByBlockNumberAndIndex(t *utesting.T) { + ctx := context.Background() + + for i, num := range s.tests.BlockNumbers { + bhash := s.tests.BlockHashes[i] + txIndex := s.tests.TxHashIndex[i] + expectedHash := s.tests.TxHashes[i] + if expectedHash == nil { + continue // no txs in block + } + + tx, err := s.cfg.client.getTransactionByBlockNumberAndIndex(ctx, num, uint64(txIndex)) + if err != nil { + t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + } + if tx == nil { + t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex) + continue + } + if tx.Hash != *expectedHash || uint64(tx.TransactionIndex) != uint64(txIndex) { + t.Errorf("block %d (hash %v): txIndex %d has wrong txHash/Index", num, bhash, txIndex) + } + } +} + +type simpleBlock struct { + Number hexutil.Uint64 `json:"number"` + Hash common.Hash `json:"hash"` +} + +type simpleTransaction struct { + Hash common.Hash `json:"hash"` + TransactionIndex hexutil.Uint64 `json:"transactionIndex"` +} + +func (c *client) getBlockByHash(ctx context.Context, arg common.Hash, fullTx bool) (*simpleBlock, error) { + var r *simpleBlock + err := c.RPC.CallContext(ctx, &r, "eth_getBlockByHash", arg, fullTx) + return r, err +} + +func (c *client) getBlockByNumber(ctx context.Context, arg uint64, fullTx bool) (*simpleBlock, error) { + var r *simpleBlock + err := c.RPC.CallContext(ctx, &r, "eth_getBlockByNumber", hexutil.Uint64(arg), fullTx) + return r, err +} + +func (c *client) getTransactionByBlockHashAndIndex(ctx context.Context, block common.Hash, index uint64) (*simpleTransaction, error) { + var r *simpleTransaction + err := c.RPC.CallContext(ctx, &r, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)) + return r, err +} + +func (c *client) getTransactionByBlockNumberAndIndex(ctx context.Context, block uint64, index uint64) (*simpleTransaction, error) { + var r *simpleTransaction + err := c.RPC.CallContext(ctx, &r, "eth_getTransactionByBlockNumberAndIndex", hexutil.Uint64(block), hexutil.Uint64(index)) + return r, err +} + +func (c *client) getBlockTransactionCountByHash(ctx context.Context, block common.Hash) (uint64, error) { + var r hexutil.Uint64 + err := c.RPC.CallContext(ctx, &r, "eth_getBlockTransactionCountByHash", block) + return uint64(r), err +} + +func (c *client) getBlockTransactionCountByNumber(ctx context.Context, block uint64) (uint64, error) { + var r hexutil.Uint64 + err := c.RPC.CallContext(ctx, &r, "eth_getBlockTransactionCountByNumber", hexutil.Uint64(block)) + return uint64(r), err +} + +func (c *client) getBlockReceipts(ctx context.Context, arg any) ([]*types.Receipt, error) { + var result []*types.Receipt + err := c.RPC.CallContext(ctx, &result, "eth_getBlockReceipts", arg) + return result, err +} diff --git a/cmd/workload/historytestgen.go b/cmd/workload/historytestgen.go new file mode 100644 index 000000000..9d98bb28e --- /dev/null +++ b/cmd/workload/historytestgen.go @@ -0,0 +1,147 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "os" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/rlp" + "github.com/urfave/cli/v2" +) + +var ( + historyGenerateCommand = &cli.Command{ + Name: "historygen", + Usage: "Generates history retrieval tests", + ArgsUsage: "", + Action: generateHistoryTests, + Flags: []cli.Flag{ + historyTestFileFlag, + historyTestEarliestFlag, + }, + } + + historyTestFileFlag = &cli.StringFlag{ + Name: "history-tests", + Usage: "JSON file containing filter test queries", + Value: "history_tests.json", + Category: flags.TestingCategory, + } + historyTestEarliestFlag = &cli.IntFlag{ + Name: "earliest", + Usage: "JSON file containing filter test queries", + Value: 0, + Category: flags.TestingCategory, + } +) + +const historyTestBlockCount = 2000 + +func generateHistoryTests(clictx *cli.Context) error { + var ( + client = makeClient(clictx) + earliest = uint64(clictx.Int(historyTestEarliestFlag.Name)) + outputFile = clictx.String(historyTestFileFlag.Name) + ctx = context.Background() + ) + + test := new(historyTest) + + // Create the block numbers. Here we choose 1k blocks between earliest and head. + latest, err := client.Eth.BlockNumber(ctx) + if err != nil { + exit(err) + } + if latest < historyTestBlockCount { + exit(fmt.Errorf("node seems not synced, latest block is %d", latest)) + } + test.BlockNumbers = make([]uint64, 0, historyTestBlockCount) + stride := (latest - earliest) / historyTestBlockCount + for b := earliest; b < latest; b += stride { + test.BlockNumbers = append(test.BlockNumbers, b) + } + + // Get blocks and assign block info into the test + fmt.Println("Fetching blocks") + blocks := make([]*types.Block, len(test.BlockNumbers)) + for i, blocknum := range test.BlockNumbers { + b, err := client.Eth.BlockByNumber(ctx, new(big.Int).SetUint64(blocknum)) + if err != nil { + exit(fmt.Errorf("error fetching block %d: %v", blocknum, err)) + } + blocks[i] = b + } + test.BlockHashes = make([]common.Hash, len(blocks)) + test.TxCounts = make([]int, len(blocks)) + for i, block := range blocks { + test.BlockHashes[i] = block.Hash() + test.TxCounts[i] = len(block.Transactions()) + } + + // Fill tx index. + test.TxHashIndex = make([]int, len(blocks)) + test.TxHashes = make([]*common.Hash, len(blocks)) + for i, block := range blocks { + txs := block.Transactions() + if len(txs) == 0 { + continue + } + index := len(txs) / 2 + txhash := txs[index].Hash() + test.TxHashIndex[i] = index + test.TxHashes[i] = &txhash + } + + // Get receipts. + fmt.Println("Fetching receipts") + test.ReceiptsHashes = make([]common.Hash, len(blocks)) + for i, blockHash := range test.BlockHashes { + receipts, err := client.getBlockReceipts(ctx, blockHash) + if err != nil { + exit(fmt.Errorf("error fetching block %v receipts: %v", blockHash, err)) + } + test.ReceiptsHashes[i] = calcReceiptsHash(receipts) + } + + // Write output file. + writeJSON(outputFile, test) + return nil +} + +func calcReceiptsHash(rcpt []*types.Receipt) common.Hash { + h := crypto.NewKeccakState() + rlp.Encode(h, rcpt) + return common.Hash(h.Sum(nil)) +} + +func writeJSON(fileName string, value any) { + file, err := os.Create(fileName) + if err != nil { + exit(fmt.Errorf("Error creating %s: %v", fileName, err)) + return + } + defer file.Close() + json.NewEncoder(file).Encode(value) +} diff --git a/cmd/workload/main.go b/cmd/workload/main.go new file mode 100644 index 000000000..6ade426c1 --- /dev/null +++ b/cmd/workload/main.go @@ -0,0 +1,86 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/rpc" + "github.com/urfave/cli/v2" +) + +var app = flags.NewApp("go-ethereum workload test tool") + +func init() { + app.Flags = append(app.Flags, debug.Flags...) + app.Before = func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) + return debug.Setup(ctx) + } + app.After = func(ctx *cli.Context) error { + debug.Exit() + return nil + } + app.CommandNotFound = func(ctx *cli.Context, cmd string) { + fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd) + os.Exit(1) + } + + // Add subcommands. + app.Commands = []*cli.Command{ + runTestCommand, + historyGenerateCommand, + filterGenerateCommand, + filterPerfCommand, + } +} + +func main() { + exit(app.Run(os.Args)) +} + +type client struct { + Eth *ethclient.Client + RPC *rpc.Client +} + +func makeClient(ctx *cli.Context) *client { + if ctx.NArg() < 1 { + exit("missing RPC endpoint URL as command-line argument") + } + url := ctx.Args().First() + cl, err := rpc.Dial(url) + if err != nil { + exit(fmt.Errorf("Could not create RPC client at %s: %v", url, err)) + } + return &client{ + RPC: cl, + Eth: ethclient.NewClient(cl), + } +} + +func exit(err any) { + if err == nil { + os.Exit(0) + } + fmt.Fprintln(os.Stderr, err) + os.Exit(1) +} diff --git a/cmd/workload/queries/filter_queries_mainnet.json b/cmd/workload/queries/filter_queries_mainnet.json new file mode 100644 index 000000000..348688572 --- /dev/null +++ b/cmd/workload/queries/filter_queries_mainnet.json @@ -0,0 +1 @@ +[[{"fromBlock":0,"toBlock":20533811,"address":["0xa6794dec66df7d8b69752956df1b28ca93f77cd7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"]],"resultHash":"0xf3e78259332c6228e609b59b361024cafe5481304eb44eea49682c998afa7ff4"},{"fromBlock":3224543,"toBlock":21893937,"address":["0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007b73644935b8e68019ac6356c40661e1bc315860"],["0x0000000000000000000000000ef7f9c5549165d204d8f440d1d84ea4f8c1dca4"]],"resultHash":"0xd064e462d2e964638bc8ee4fd6d87a764d55e0e9161a5b2b937a44d6fcc88fe3"},{"fromBlock":2248391,"toBlock":21894159,"address":["0xcd6bcca48069f8588780dfa274960f15685aee0e"],"topics":[null,["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"],["0x000000000000000000000000cd6bcca48069f8588780dfa274960f15685aee0e"]],"resultHash":"0xb98df5d2fbe3931f0217701b7321db3b2af224c4950c5d03cc18d92c963f349d"},{"fromBlock":4017902,"toBlock":18202413,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000139ff314a62816d7d4d10c05c77b870169ecc7f0"]],"resultHash":"0x9dfca1a50f07ccf47a38cdd07df8367e1096a5ea1b70f45633e1a8a9db3c65d6"},{"fromBlock":1139493,"toBlock":21053654,"address":["0x5f98805a4e8be255a32880fdec7f6728c6568ba0"],"topics":[null,["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"],["0x000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca"]],"resultHash":"0x1e54da0de45e85b9f25c891e0979a2243e3e51b2747d1cae25565519ceb21a34"},{"fromBlock":3451035,"toBlock":21893937,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x000000000000000000000000a3338b2b1a2cdfc448832ac1a511b628a24e7b77"]],"resultHash":"0x41bde228497f768920951f4c84f8997648fef7cd7dc89799d6abcf4a61f638e9"},{"fromBlock":671018,"toBlock":21894063,"address":["0xbcf935d206ca32929e1b887a07ed240f0d8ccd22"],"topics":[["0xce7dc747411ac40191c5335943fcc79d8c2d8c01ca5ae83d9fed160409fa6120"],["0x000000000000000000000000984026d27708ee0cac29fceb19400a7a5301e4df"]],"resultHash":"0x47748f41e60872acc3e6659c7e1405bc73d41aa36286e7211b4da8cc29141c97"},{"fromBlock":2767062,"toBlock":19649121,"address":[],"topics":[null,null,["0x000000000000000000000000bd554c3df133a850a2a8e65708f37ba5efe35cbd"]],"resultHash":"0xba1afb57e2103ca9f0e345c52e8e078ac7a9e572620813223efd3b0e8a3916a5"},{"fromBlock":1490593,"toBlock":21894191,"address":["0x172a9be5ea7f8602d6b9a97a914d23859053790a"],"topics":[["0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82"],["0x587d09fe5fa45354680537d38145a28b772971e0f293af3ee0c536fc919710fb"],["0x182b30867035c40c01114804fc90b9942f453de79d07993be1d614abfc37848c"]],"resultHash":"0xcd6d61bbe2f84b667484980ba5d4f07e90ba769d8c60373c19d10c2b87058272"},{"fromBlock":3199906,"toBlock":21894159,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x00000000000000000000000040e10218e0ab001b109d9f9ca96c8487c457e65f"]],"resultHash":"0x576f6817c2edb9891a88866339ca70e51e9a118b27bc46ee87decc0181599798"},{"fromBlock":3706091,"toBlock":21894191,"address":["0x54bcf4948e32a8706c286416e3ced37284f17fc9"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0xdd97c5982e0f2d107103ce0ef3254ccb3c1a69b5cd031b618b08ad12d29e9241"},{"fromBlock":3465199,"toBlock":21894191,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000693010a4d33112679ed95ffced9b47d778de52ba"]],"resultHash":"0x7f8e419c604abeebb32c74f7dbd24f401b148a4aa84a9cb1c7d06ef7b8c6b61f"},{"fromBlock":0,"toBlock":18866229,"address":["0xef68e7c694f40c8202821edf525de3782458639f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000cb049f3fada20d42fec84866bbd55246648e98a7"],["0x00000000000000000000000069ea6b31ef305d6b99bb2d4c9d99456fa108b02a"]],"resultHash":"0x34d50ab86df13d954ffba5f7840ee68ec06ceac641eddff5a73f3deae6227d5f"},{"fromBlock":4904975,"toBlock":21894159,"address":["0x7cc768b882be41ca03f9daccfc48b8bd6d25eb25"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xad8164b03737df9fe26e85aeaa8f52e34d862634cd3da65eb791f5beeddbffdd"},{"fromBlock":2961299,"toBlock":21253772,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000e80b1375ff7a498d5c28454fb60d79ad3434cfd2"]],"resultHash":"0x3e1b8eb8ed40a5b0e09e3b7737b02c8936cce6814ea973a642a9ec67ad2383eb"},{"fromBlock":1862102,"toBlock":21894159,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000002fbcf7714202a6996430436e67a4f11b17ed598a"]],"resultHash":"0x29c1edc31a7707c6dbeeb99685e6e6dcbbdeb69eed818f9e22ec58dd2b5b7139"},{"fromBlock":3224543,"toBlock":21893937,"address":["0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000000ef7f9c5549165d204d8f440d1d84ea4f8c1dca4"]],"resultHash":"0xd064e462d2e964638bc8ee4fd6d87a764d55e0e9161a5b2b937a44d6fcc88fe3"},{"fromBlock":0,"toBlock":16729622,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000a666f70f6db2c204a19a2dd0272a96b8830387ed"]],"resultHash":"0x920c36b51d85a19ae89db401ea88821d20e89ff6596f2d03fa49ed02617323d9"},{"fromBlock":0,"toBlock":19855084,"address":["0x99ea4db9ee77acd40b119bd1dc4e33e1c070b80d"],"topics":[null,["0x0000000000000000000000000e590f8b856ecaf9acfd52ce03cd3cf1c525453f"],["0x0000000000000000000000003f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be"]],"resultHash":"0xe2f68f5f2ed2600f345f4e3ebbf41220784f3e471fe5338505fa36981d9086ee"},{"fromBlock":0,"toBlock":13467038,"address":["0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53"],"topics":[null,null,["0x000000000000000000000000dea5585adcaafbe30e84ccd693214481c0daa4ee"]],"resultHash":"0x95f274fbc2ea9d7f4c96b809ba6cf8b3614e37814237005310f70f9aaac1cc44"},{"fromBlock":8566638,"toBlock":21754255,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a8ecaf8745c56d5935c232d2c5b83b9cd3de1f6a"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xba23d0a7f5b565b4a5e5dc71595a83b193f8a8f2b53ba0fd6ae7421272f92092"},{"fromBlock":2660315,"toBlock":21893969,"address":["0xd1b3460f28681464d2b5cee4e71bb332c429ec1c"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45"],["0x000000000000000000000000e27f661ff53326f65cd6f89e5e789f3731e4001c"]],"resultHash":"0x67651677f9793a9aaca3518eac8ad47cf9a6acae30f9614df89545bfce345870"},{"fromBlock":421009,"toBlock":21894159,"address":["0x819f3450da6f110ba6ea52195b3beafa246062de"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d"],["0x0000000000000000000000009620e9bc10597f68586fc61d38b86cd485191b70"]],"resultHash":"0xceba8cbdcb2206ae84fa0a86fb05dbbdcaaba3fe387627147c7e5ed3cfcec88f"},{"fromBlock":4828985,"toBlock":21894159,"address":["0x0652687e87a4b8b5370b05bc298ff00d205d9b5f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000007f46f400fadf8fe55a8b95e302175d8aea362337"]],"resultHash":"0x0f0b5af0d37251884abfdd2eb53112ef8ce5375144208fcebde60b0e7b1296c8"},{"fromBlock":4904975,"toBlock":21894159,"address":["0x7cc768b882be41ca03f9daccfc48b8bd6d25eb25"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xad8164b03737df9fe26e85aeaa8f52e34d862634cd3da65eb791f5beeddbffdd"},{"fromBlock":498010,"toBlock":21893810,"address":["0x777be1c6075c20184c4fd76344b7b0b7c858fe6b"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0x3da24d79906e2fc8145e02664af279d478f90c7bf930371e9d63f8b91ddc6d4b"},{"fromBlock":5620043,"toBlock":19365774,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x0000000000000000000000009b43c10b1cd9b18f8ba2f3e90025f51c4461262e"]],"resultHash":"0xf3242ab1d2f0356b6a31b6c42ee01ae4618a520b9d07fa0f983227c790ec4025"},{"fromBlock":3257732,"toBlock":21894063,"address":["0xb39304157227d684f28353fb7a016bd1c685da5f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000fe806c79275b249d87baa5dac4d21a594f240ad6"],["0x00000000000000000000000000000000000000000000000000000000000020a0"]],"resultHash":"0x3d87c080d653f5245823cfcd20a9ee759f48f450514e327c58223fd7ff65eef8"},{"fromBlock":3632042,"toBlock":20667694,"address":["0x7adb368141248d6c50b614aee3b6a9ef9f8c20bd"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000018c0ca3947e255881f94de50b3a906fc2759f7fe"],["0x00000000000000000000000018c0ca3947e255881f94de50b3a906fc2759f7fe"]],"resultHash":"0x50b2cf09e407a99bb098cc3f843e36bd3091beb7de66b95d00e840b8ff5a1daa"},{"fromBlock":1599354,"toBlock":21894159,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000046340b20830761efd32832a74d7169b29feb9758"],["0x0000000000000000000000002fbcf7714202a6996430436e67a4f11b17ed598a"]],"resultHash":"0x29c1edc31a7707c6dbeeb99685e6e6dcbbdeb69eed818f9e22ec58dd2b5b7139"},{"fromBlock":1211116,"toBlock":19491941,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000add9e07b04272f66c803f0e724f005a653e77040"],["0x0000000000000000000000003ce2a0101df6b034635f0bcec7a6cd9597768796"]],"resultHash":"0x1f4ed421c0a00145d68ee9b227e3ec707109cbad86dfdf2b942c4e3fe5a7d6d2"},{"fromBlock":498010,"toBlock":21893810,"address":["0x2f3c1a1c8d069b47cd756cbc22120ae82d61448e"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000005a47c638a0243a1f307e6a869f5140278da41921"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0x4efce609e4f2a7316d899d862a6ce4e7c923f0b4387fe4784a3bd9fb26de736a"},{"fromBlock":2416385,"toBlock":20517327,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000f3a71cc1be5ce833c471e3f25aa391f9cd56e1aa"],["0x0000000000000000000000001e6706370b007605347d2de24c2506152ca5a9d6"]],"resultHash":"0x694c173f7226a39786a148ca98fca04f8766a86cd71fa26d65299f69aa23eaff"},{"fromBlock":0,"toBlock":19274842,"address":["0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53"],"topics":[null,["0x00000000000000000000000028a44f49b940b3875f882d08487d16295fb8bc09"],["0x000000000000000000000000dea5585adcaafbe30e84ccd693214481c0daa4ee"]],"resultHash":"0x95f274fbc2ea9d7f4c96b809ba6cf8b3614e37814237005310f70f9aaac1cc44"},{"fromBlock":3538090,"toBlock":21894191,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"],["0x0000000000000000000000000000000000000000000000000000000000000d5d"]],"resultHash":"0xf187387c8d5b4bf93705f26466651e78128cfe1e837dc362d976856d22e2a483"},{"fromBlock":287082,"toBlock":21894191,"address":["0x57fbb364041d860995ed610579d70727ac51e470"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"],["0x00000000000000000000000000000000000000000000000000000000000011eb"]],"resultHash":"0x05af91b100cbfdcf50d3a90f064557188605c58b383f0c1d9e523da99e510b03"},{"fromBlock":0,"toBlock":20539755,"address":["0xe65ee7c03bbb3c950cfd4895c24989afa233ef01"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000008ad4bfd99281f8a9e15f2668f701212050433a6a"],["0x000000000000000000000000f0073a6f7c86beb89c011a0f3e648dec980f16ec"]],"resultHash":"0x331c708ca4a7b826456ec0bb45426ab3649ca4236ef3671107664d56099d8d9f"},{"fromBlock":906415,"toBlock":21894127,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e9da256a28630efdc637bfd4c65f0887be1aeda8"],["0x0000000000000000000000008baf23f273edcf9cc3f51127e591f189115a2b8d"]],"resultHash":"0xade5ee4822e3d0dd9804ea249ccac7320daa51adc69d41af2ebdfbc20fddc390"},{"fromBlock":5620043,"toBlock":19365774,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000009b43c10b1cd9b18f8ba2f3e90025f51c4461262e"]],"resultHash":"0xf3242ab1d2f0356b6a31b6c42ee01ae4618a520b9d07fa0f983227c790ec4025"},{"fromBlock":0,"toBlock":21022866,"address":[],"topics":[["0xb51168059c83c860caf5b830c5d2e64c2172c6fb2fe9f25447d9838e18d93b60"],["0x00000000000000000000000000000000000000000000000000000004034e41c8"],["0x000000000000000000000000000000000000000000000000000000000000890c"]],"resultHash":"0xd5533c985ab1e771535a19b4728e758e5f2aff0c4a3305c1d5aa76898969544f"},{"fromBlock":7171052,"toBlock":21894191,"address":["0xce407cd7b95b39d3b4d53065e711e713dd5c5999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000f3de3c0d654fda23dad170f0f320a92172509127"],["0x000000000000000000000000e14c3d81ee9d8684f8a4690dddb8139dece5d468"]],"resultHash":"0x152745971191f832343c99bb4ddd590117a30ea96101cdabdeb10349f1fe66f9"},{"fromBlock":3109653,"toBlock":21894031,"address":["0xb39304157227d684f28353fb7a016bd1c685da5f"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000ade336f3496452e5cb47a75649d14ca0823e7a11"],["0x0000000000000000000000000000000000000000000000000000000000001605"]],"resultHash":"0x359b612cd9fb37024b943193b42ffd7678172316ad789bdd87f469d035e60760"},{"fromBlock":3379313,"toBlock":21894159,"address":["0xa9ca155590671bbc01d7e1d95c0adec749e39cfc"],"topics":[["0x0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f"],null,["0x0000000000000000000000000000000000000000000000000000000000000043"]],"resultHash":"0x66e12d88814b935d5453d8cd5e9d59eed7c0453d8891ff4f0b5e47b639b87993"},{"fromBlock":738864,"toBlock":21893842,"address":["0x0a3aefdb58a03d7c30b2a063e1fd49c4cb5f8b60"],"topics":[null,["0x000000000000000000000000cdfaaa35d00f5b22cb8ff285c40e89b96d34adde"]],"resultHash":"0xb8c01edc4959040f50e685a3d785f80b1b0bd58d4a736f53b3972f7a200907fb"},{"fromBlock":0,"toBlock":20734392,"address":["0x7d3e7d41da367b4fdce7cbe06502b13294deb758"],"topics":[null,null,["0x000000000000000000000000c4af36f14bdb20d22ab27d8fbae5747aa166fbef"]],"resultHash":"0xbbfe86370c89fd29f9a0c742cf35da63a0809d4073684af9ea02c59a3c4163f9"},{"fromBlock":7828246,"toBlock":21329307,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,null,["0x0000000000000000000000003d5164cd6a0358cc1a7e98bdf3cabbd0f5ad92ba"]],"resultHash":"0x7a6967772e3e94d0a1c279da2a7aa22077b1dc7a21c449bb2ede85cbe14ef58e"},{"fromBlock":0,"toBlock":20330118,"address":[],"topics":[null,null,["0x000000000000000000000000cb22ebc93b4c58ffab85c28901585f186a1c604b"]],"resultHash":"0xad4c510ca89bd799f7396f01e6304a5808af0debe472cbb0f7ea98ebf270d0b6"},{"fromBlock":3810079,"toBlock":21894095,"address":[],"topics":[null,["0x000000000000000000000000833c907a80f892259ce75a880d714e6dd22509a3"],["0x000000000000000000000000399213292ad58cfd53517f4de23b853e5b5b60c8"]],"resultHash":"0xb7f67982419321110471a2a1fd12651e601885fb28b23a54b6e6ba60285b48c9"},{"fromBlock":6042343,"toBlock":21077039,"address":["0x94693c9e342f759272d6f7b481703df8e83b1818"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000004310aa2dd0f78635fa6409f4ef5a388f0458ab17"]],"resultHash":"0x78c8b6221b0d8a6ebba35124e89ccbb6dc3b01937fc4d84ac25187504b5f69f7"},{"fromBlock":622631,"toBlock":20195871,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000d2cf555449596b91150b1daec11682ec8b0ea8ca"]],"resultHash":"0x414f91848de83541f15e232ee0e071cd273df9f27ff3c4d3c4fafd0ed8ca285f"},{"fromBlock":0,"toBlock":19930598,"address":[],"topics":[null,["0x000000000000000000000000dd2a23c77372725018593b631241cafec8b78a06"]],"resultHash":"0x833319f0cb334002ad70d983534b274fb719abcbbcafa0afd811bef1e391413d"},{"fromBlock":3451035,"toBlock":21893937,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x000000000000000000000000a3338b2b1a2cdfc448832ac1a511b628a24e7b77"]],"resultHash":"0x41bde228497f768920951f4c84f8997648fef7cd7dc89799d6abcf4a61f638e9"},{"fromBlock":0,"toBlock":19438664,"address":["0x99ea4db9ee77acd40b119bd1dc4e33e1c070b80d"],"topics":[null,["0x0000000000000000000000000e590f8b856ecaf9acfd52ce03cd3cf1c525453f"]],"resultHash":"0xe2f68f5f2ed2600f345f4e3ebbf41220784f3e471fe5338505fa36981d9086ee"},{"fromBlock":2404893,"toBlock":21894159,"address":["0xe12af1218b4e9272e9628d7c7dc6354d137d024e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000001ede2d0da4834df237b47b603b8e0c7a1bc2885a"]],"resultHash":"0x4853351d5aa917e8fe609d41d5f436b4b74cb37d7ae43b406167b56714d43dd4"},{"fromBlock":4716258,"toBlock":18636602,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000da478cdb499f3509d399fa3823a70ec40c7777e2"]],"resultHash":"0xe0a01952780a5dcc5c2c1a1512a7ca49db368b8b0f3efc1a35019b90911fdd9a"},{"fromBlock":3545156,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"]],"resultHash":"0x9d54ba92b3a367f2c9cff8736229388b5f78141f35d0aea59e82576f1e656c4e"},{"fromBlock":1444933,"toBlock":21894063,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"],["0x00000000000000000000000000000000000000000000000000000000000011ec"]],"resultHash":"0x857867a9f4c926cb2af98810f7b5502a1cfbd8bf8a403eb9567a2e20b3526921"},{"fromBlock":2680494,"toBlock":21893873,"address":["0x1580eb65edb0b903e7b3624ca963219d0c5c565e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000007af443393b95d2ee5ebdaab98dc2b0778a789e0f"],["0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"]],"resultHash":"0x3254c9032fa38e8f54bc610b2eea0c47c04bad497e89c92afc108e5f75199cd1"},{"fromBlock":7807822,"toBlock":21470616,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000004cefd3a57ee8e1d6a3f564bb297254c51aeeb4ed"]],"resultHash":"0x96439488568de0496fb59522f750cf1fa4a1911648e45771daca8c13971f28d5"},{"fromBlock":0,"toBlock":16861090,"address":["0x6531f133e6deebe7f2dce5a0441aa7ef330b4e53"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000dea5585adcaafbe30e84ccd693214481c0daa4ee"]],"resultHash":"0x95f274fbc2ea9d7f4c96b809ba6cf8b3614e37814237005310f70f9aaac1cc44"},{"fromBlock":2048677,"toBlock":21894159,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000397ff1542f962076d0bfe58ea045ffa2d347aca0"]],"resultHash":"0xe1eeca04cfaaaeac8bf0a1b4680a47c09d3940f63e4fd61d69db922affdfff9c"},{"fromBlock":3109653,"toBlock":21894031,"address":["0xb39304157227d684f28353fb7a016bd1c685da5f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000ade336f3496452e5cb47a75649d14ca0823e7a11"],["0x0000000000000000000000000000000000000000000000000000000000001605"]],"resultHash":"0x359b612cd9fb37024b943193b42ffd7678172316ad789bdd87f469d035e60760"},{"fromBlock":2741398,"toBlock":21894063,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000007e9771d2ffcebfc97fd6e84927b964c787cfc698"]],"resultHash":"0xacfdcba31145ad71b6f1ca9e32e309f69c5cd48bb9b0f28691ae83267a9e1b68"},{"fromBlock":0,"toBlock":16729622,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000a666f70f6db2c204a19a2dd0272a96b8830387ed"]],"resultHash":"0x920c36b51d85a19ae89db401ea88821d20e89ff6596f2d03fa49ed02617323d9"},{"fromBlock":1302339,"toBlock":19803394,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000871a30f835e293304c153c2ea619316c02658e61"]],"resultHash":"0xdb1181afa524366ae5bd24ac234b5d9b79a5c5353a78ba60a758887bca3f202b"},{"fromBlock":1418458,"toBlock":21410675,"address":["0x6b3595068778dd592e39a122f4f5a5cf09c90fe2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009420fdfcb670db7e97d2da5dd8b8f66b11309ab9"]],"resultHash":"0xb5a94e8dc48c525ddafafa303537b6340f7d0adb2a82723c7a814161c3bd26e3"},{"fromBlock":0,"toBlock":16628811,"address":["0xbcf935d206ca32929e1b887a07ed240f0d8ccd22"],"topics":[null,null,["0x00000000000000000000000018a65ae8a292df5f460c5dec1ca08850e66e02df"]],"resultHash":"0x58577c7f75523485356582c2830144c0e66838e80dd5c6d38f6c3119c192865e"},{"fromBlock":0,"toBlock":14447940,"address":["0xe65ee7c03bbb3c950cfd4895c24989afa233ef01"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000f0073a6f7c86beb89c011a0f3e648dec980f16ec"]],"resultHash":"0x331c708ca4a7b826456ec0bb45426ab3649ca4236ef3671107664d56099d8d9f"},{"fromBlock":0,"toBlock":21022866,"address":["0x79febf6b9f76853edbcbc913e6aae8232cfb9de9"],"topics":[["0xb51168059c83c860caf5b830c5d2e64c2172c6fb2fe9f25447d9838e18d93b60"],["0x00000000000000000000000000000000000000000000000000000004034e41c8"]],"resultHash":"0xd5533c985ab1e771535a19b4728e758e5f2aff0c4a3305c1d5aa76898969544f"},{"fromBlock":1123728,"toBlock":21894159,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000021a31ee1afc51d94c2efccaa2092ad1028285549"],["0x0000000000000000000000008f9f8721b1dfa254bf877172edc87389a89dd304"]],"resultHash":"0x93fdeba5de28f09205eb7d30a8f1ebdb2b6f6bc176eeb31e32e0f7ef7913d873"},{"fromBlock":1907920,"toBlock":21894159,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x00000000000000000000000040e10218e0ab001b109d9f9ca96c8487c457e65f"]],"resultHash":"0x576f6817c2edb9891a88866339ca70e51e9a118b27bc46ee87decc0181599798"},{"fromBlock":372054,"toBlock":21894191,"address":[],"topics":[null,null,["0x000000000000000000000000be70287dc323b6f2596147f7566596f183aaf767"]],"resultHash":"0x328357832df217f377f33e1cf943db52f51da5feda61b0ce5da3584696839c44"},{"fromBlock":0,"toBlock":16729622,"address":["0x701c244b988a513c945973defa05de933b23fe1d"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000a666f70f6db2c204a19a2dd0272a96b8830387ed"]],"resultHash":"0x920c36b51d85a19ae89db401ea88821d20e89ff6596f2d03fa49ed02617323d9"},{"fromBlock":1801832,"toBlock":21893873,"address":["0xb39304157227d684f28353fb7a016bd1c685da5f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000071042f6b3aaae4b7cceaa0abee9b151a0c109cc0"],["0x000000000000000000000000000000000000000000000000000000000000121a"]],"resultHash":"0x4bdb9baaed99ff24c10df0be65a901dd173fdb9f233e20301dea29d91d9f547d"},{"fromBlock":3199906,"toBlock":21894159,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x00000000000000000000000040e10218e0ab001b109d9f9ca96c8487c457e65f"]],"resultHash":"0x576f6817c2edb9891a88866339ca70e51e9a118b27bc46ee87decc0181599798"},{"fromBlock":3810079,"toBlock":21894095,"address":[],"topics":[null,null,["0x000000000000000000000000399213292ad58cfd53517f4de23b853e5b5b60c8"]],"resultHash":"0xb7f67982419321110471a2a1fd12651e601885fb28b23a54b6e6ba60285b48c9"},{"fromBlock":0,"toBlock":16999593,"address":["0xef68e7c694f40c8202821edf525de3782458639f"],"topics":[null,["0x000000000000000000000000cb049f3fada20d42fec84866bbd55246648e98a7"],["0x00000000000000000000000069ea6b31ef305d6b99bb2d4c9d99456fa108b02a"]],"resultHash":"0x34d50ab86df13d954ffba5f7840ee68ec06ceac641eddff5a73f3deae6227d5f"},{"fromBlock":3580144,"toBlock":21894095,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000c50c79ed8bc14643f344836170f3a6b2624d2a33"]],"resultHash":"0x0313656e7b513b060cfb8f496fb232ca37a29091095b65e48dc811012d95eb59"},{"fromBlock":0,"toBlock":19930598,"address":[],"topics":[["0x56b138798bd325f6cc79f626c4644aa2fd6703ecb0ab0fb168f883caed75bf32"],["0x000000000000000000000000dd2a23c77372725018593b631241cafec8b78a06"]],"resultHash":"0x833319f0cb334002ad70d983534b274fb719abcbbcafa0afd811bef1e391413d"},{"fromBlock":5620043,"toBlock":19365774,"address":["0x17890deb188f2de6c3e966e053da1c9a111ed4a5"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000009b43c10b1cd9b18f8ba2f3e90025f51c4461262e"]],"resultHash":"0xf3242ab1d2f0356b6a31b6c42ee01ae4618a520b9d07fa0f983227c790ec4025"},{"fromBlock":498010,"toBlock":21893810,"address":["0x2f3c1a1c8d069b47cd756cbc22120ae82d61448e"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000005a47c638a0243a1f307e6a869f5140278da41921"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0x4efce609e4f2a7316d899d862a6ce4e7c923f0b4387fe4784a3bd9fb26de736a"},{"fromBlock":3456602,"toBlock":21893842,"address":["0x77fba179c79de5b7653f68b5039af940ada60ce0"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"],["0x00000000000000000000000011111112542d85b3ef69ae05771c2dccff4faa26"]],"resultHash":"0xd46a1ffef28d97ebeffd97b8191389658058ecbe161bbd47e08d852e0128bfcf"},{"fromBlock":4140627,"toBlock":21894191,"address":["0x13cc598e8a2257e7e87407b6e79c00f7692361fa"],"topics":[null,null,null,["0x000000000000000000000000000000000000000000000000000000000000120d"]],"resultHash":"0x1eb870085ea988166d33d2e00b0beb3173e8756f19bdac1a54c7944849160c60"},{"fromBlock":6867998,"toBlock":21894063,"address":["0x34d7d7aaf50ad4944b70b320acb24c95fa2def7c"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000ab48272303c177e18d63605cb78aeecf38aae93d"]],"resultHash":"0x95ff39ceac35a9c52e814322de10ac2b0d31c0704c8e2a444b6e6ba084e08ec4"},{"fromBlock":1083496,"toBlock":21894031,"address":["0x6a091a3406e0073c3cd6340122143009adac0eda"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e70101ac5d6db9f867eb53bb80220b85af488c4f"]],"resultHash":"0x745d6e0f22d646ef637684106f46bd082d94db4324c44e9d641a2146b768abb0"},{"fromBlock":3451035,"toBlock":21893937,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x000000000000000000000000a3338b2b1a2cdfc448832ac1a511b628a24e7b77"]],"resultHash":"0x41bde228497f768920951f4c84f8997648fef7cd7dc89799d6abcf4a61f638e9"},{"fromBlock":3740924,"toBlock":20457747,"address":["0xe12af1218b4e9272e9628d7c7dc6354d137d024e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000139ff314a62816d7d4d10c05c77b870169ecc7f0"]],"resultHash":"0x9dfca1a50f07ccf47a38cdd07df8367e1096a5ea1b70f45633e1a8a9db3c65d6"},{"fromBlock":906415,"toBlock":21894127,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000008baf23f273edcf9cc3f51127e591f189115a2b8d"]],"resultHash":"0xbbfe49a3c06c3021c24bb05e9d52f932cf480dff6145c504d7bd8e0b9c31d370"},{"fromBlock":498010,"toBlock":21893810,"address":["0x2f3c1a1c8d069b47cd756cbc22120ae82d61448e"],"topics":[null,["0x0000000000000000000000005a47c638a0243a1f307e6a869f5140278da41921"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0x4efce609e4f2a7316d899d862a6ce4e7c923f0b4387fe4784a3bd9fb26de736a"},{"fromBlock":5606654,"toBlock":21894095,"address":["0xae7ab96520de3a18e5e111b5eaab095312d7fe84"],"topics":[["0x9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000001341e0bf0ecd9d7df015c14a1fa33d2d4cc5ec1c"]],"resultHash":"0xed3fbe8e1157541bd8a0143c68d9ff31ffca40646983fb4b99a18a269b2d75d2"},{"fromBlock":293890,"toBlock":21894127,"address":["0x170217d48f8c9388f67ca2c65ef48e55a1352cc6"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xe7c820dbb8ce25cd9a2d2c9e72be14ccbeedfcef7e37e831e940b95a8e90885b"},{"fromBlock":2334639,"toBlock":21894191,"address":[],"topics":[null,null,["0x0000000000000000000000001fcab39c506517d0cc2a12d49ebe5b98f415ed92"],["0x000000000000000000000000000000000000000000000000000000000000120d"]],"resultHash":"0x91205f17941cc3e0b4ba7b8690e197df0325321e15783e22279583dd783456b0"},{"fromBlock":3200760,"toBlock":19454437,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000011bab7"],null],"resultHash":"0xe1fea93b1d7528c1503d031a2707af1c3a885c8447c904b1655fc18858541176"},{"fromBlock":3224543,"toBlock":21893937,"address":["0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007b73644935b8e68019ac6356c40661e1bc315860"],["0x0000000000000000000000000ef7f9c5549165d204d8f440d1d84ea4f8c1dca4"]],"resultHash":"0xd064e462d2e964638bc8ee4fd6d87a764d55e0e9161a5b2b937a44d6fcc88fe3"},{"fromBlock":319309,"toBlock":21894063,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000046340b20830761efd32832a74d7169b29feb9758"],["0x0000000000000000000000003d5164cd6a0358cc1a7e98bdf3cabbd0f5ad92ba"]],"resultHash":"0x7a6967772e3e94d0a1c279da2a7aa22077b1dc7a21c449bb2ede85cbe14ef58e"},{"fromBlock":775754,"toBlock":21894159,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000ca05da65c7f83a30556ffffb035e58bada4d9ccf"],null,["0x000000000000000000000000000000000000000000000000000000000000263e"]],"resultHash":"0x5d5a0e928847050f90304dba3ea031233394fb9200180ad4c93926552fe09823"},{"fromBlock":287082,"toBlock":21894191,"address":["0x57fbb364041d860995ed610579d70727ac51e470"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"],["0x00000000000000000000000000000000000000000000000000000000000011eb"]],"resultHash":"0x05af91b100cbfdcf50d3a90f064557188605c58b383f0c1d9e523da99e510b03"},{"fromBlock":8556647,"toBlock":21894095,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000002fbcf7714202a6996430436e67a4f11b17ed598a"]],"resultHash":"0x29c1edc31a7707c6dbeeb99685e6e6dcbbdeb69eed818f9e22ec58dd2b5b7139"},{"fromBlock":4414787,"toBlock":21894031,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000213d374a227141834e64675ba9b6571a813a007a"]],"resultHash":"0x99ef87ca1c5de134684566fabf00d722eeade1494e45f40be5e6bb41f7f77a48"},{"fromBlock":904105,"toBlock":21894159,"address":["0xce407cd7b95b39d3b4d53065e711e713dd5c5999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000f3de3c0d654fda23dad170f0f320a92172509127"],["0x000000000000000000000000e14c3d81ee9d8684f8a4690dddb8139dece5d468"]],"resultHash":"0x152745971191f832343c99bb4ddd590117a30ea96101cdabdeb10349f1fe66f9"}],[{"fromBlock":7486286,"toBlock":21418779,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,["0x000000000000000000000000e137faa86acba1b35efccc22195bcd1707cc7176"]],"resultHash":"0xa5b400a951ac47b2cca28944e71ade85a78538095ef24292fb193032f30bb2ed"},{"fromBlock":7999897,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000005c57ac8dc5d8589dab9d422993ed3de8cc244151"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0xf9e68e76f28865140de9ac09af771d1bfb81fdc7864eb42dc29ae974b33c2fe5"},{"fromBlock":582435,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x752c774441aafb1bad7989a4956cf5ad05aaf9ee2950f75a42c51e6972011bb5"},{"fromBlock":498010,"toBlock":21893810,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xb233781eb14a1512d29f99d35730b5afb56981ca4e77c6d44f75d1d74792f4ab"},{"fromBlock":377138,"toBlock":21894159,"address":["0xdff71165a646be71fcfbaa6206342faa503aed5d"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0x3e2bb28b01522a480a070771f1207e7fe672100d2afa578876384a6524a614a3"},{"fromBlock":498010,"toBlock":21893810,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xc4ccb46ec96cae5adfbdc436ab2fe197adb88b88f09b440f8f1abeed011e46c1"},{"fromBlock":582435,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x752c774441aafb1bad7989a4956cf5ad05aaf9ee2950f75a42c51e6972011bb5"},{"fromBlock":719383,"toBlock":18717181,"address":[],"topics":[null,["0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"],["0x000000000000000000000000180148c00c8a3951f29baaea949f5dcbdceed7ae"]],"resultHash":"0x3bb3883be73827a6f278beca009de972a0b6d9533df1c04ea4816535b088b7a1"},{"fromBlock":2346116,"toBlock":21894127,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009f817c535f01d0233ad003be4b6872204d4e374c"],["0x000000000000000000000000e49849f768e114bf06a4d715f6aca57c6cc0c35f"]],"resultHash":"0x3ea126ad3557ebf90124145fe8952c7d7dacfa6c3ee76a4dcb35502219f17e96"},{"fromBlock":757877,"toBlock":21894095,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x6fb33727d5d9f1fcd986957b11f0a4c2a95bd35070af3ae868c64ca15a3b353b"},{"fromBlock":665080,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000000000000a84d1a9b0063a910315c7ffa9cd248"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x8592daf1002c678ea61d3c4bf1b61565e1a1de1f1f5dd936003ee1b6f06e09d6"},{"fromBlock":1058578,"toBlock":21894127,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xa81fe6571947d1abc79e23b0927bac9058677f353a2a41b4ac9bdba0428d87cf"},{"fromBlock":2306836,"toBlock":21893842,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000000c4b632b389b09b0c6b546f5dbbb15bffad0961e"]],"resultHash":"0xffb3bdd75029ea4098f6a0de6fbb3ce19fe5381acb51b2bbe845c7af15d66d14"},{"fromBlock":1708350,"toBlock":19452274,"address":[],"topics":[null,["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"]],"resultHash":"0x4cd609a7ec7d0df36b9724850f7bb1f5a811c7e910603e67a4452c582e02c944"},{"fromBlock":779698,"toBlock":21893842,"address":[],"topics":[["0xa55c5f48fd29482ad55f4b59bf070cd1ac1a7132a31f7a136ebe8877ae37e1ff"],["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"]],"resultHash":"0x613dfdefe3d0b316c44294f684ba20fcb92d1ca71e44a5270cdd1822c78890f3"},{"fromBlock":3778080,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x45402fdb57ea6cf2041718497f22b7eab9d97c6d8fb8b164b7175bc93ee15734"},{"fromBlock":0,"toBlock":20002094,"address":[],"topics":[null,null,["0x000000000000000000000000c4af36f14bdb20d22ab27d8fbae5747aa166fbef"]],"resultHash":"0xff78ca5991f7a203f28cf54ba9f74e9174db740cd34060d7c8ff2168d01e80b3"},{"fromBlock":8480619,"toBlock":21894159,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000009aef7c447f6bc8d010b22aff52d5b67785ed942c"]],"resultHash":"0x3229c8c2513fa6a3bf1ea76112b049bd5be3114b6ebedb5ffbac0b69055409f6"},{"fromBlock":873698,"toBlock":16384126,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009d64dbe82a38b3e2a75bf44e4a91b2bfa8b86133"],["0x000000000000000000000000a8b3bf51e1bb5e227ec683e1bdf7f1f5110bfacc"]],"resultHash":"0xa80667ef9375b923773d663e85401df535ab608624e773fcc2e5d61c6bea77c9"},{"fromBlock":4993374,"toBlock":17708487,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000ade2edad8d2f3a5bd43d11948de9f55973f9ce07"]],"resultHash":"0xaec12a2645aa97caa72437efc1f368cfde740e267f4b96c1c3ef9c138a8aba91"},{"fromBlock":1770218,"toBlock":21894031,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000f207e674b23183b75b7dd59cd0a579f75a6d36d9"]],"resultHash":"0xd0e21e41daca0166dbb942c51eef7b76e0b98d3754d958bd94b743f9de60d7fa"},{"fromBlock":317883,"toBlock":21894127,"address":["0x7ad4780dfa1624ad1dca5d514c90ea7cf6eb37f9"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000008fe7d9643077b4ab2885cb2dad4236cc4784413f"],["0x0000000000000000000000008f19fff300a55dc8d2c5f321526b1647589cab58"]],"resultHash":"0x4e5d507dd096467034606fc747e037ea8716fbf9b760d8006389ed8b735ffc82"},{"fromBlock":779698,"toBlock":21893842,"address":["0x24179cd81c9e782a4096035f7ec97fb8b783e007"],"topics":[["0xa55c5f48fd29482ad55f4b59bf070cd1ac1a7132a31f7a136ebe8877ae37e1ff"],["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"]],"resultHash":"0x613dfdefe3d0b316c44294f684ba20fcb92d1ca71e44a5270cdd1822c78890f3"},{"fromBlock":5837444,"toBlock":21893238,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000005dd6b9daa65838079c56f148a2daea8b6fe3ee6b"]],"resultHash":"0xcf9b313d36c9996f76ec25f1da8b2f03e5a79446c9e93d74f6397c5f82aebc5f"},{"fromBlock":1018734,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x4ca589d6231f064c8662886d3d797a9f111016f2b839a407871ec39f00a27d34"},{"fromBlock":0,"toBlock":18643412,"address":["0x6a091a3406e0073c3cd6340122143009adac0eda"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0x3e2ff1930e720e2ccade825ceb95022b99d524813c81bd3609c055d8597bd825"},{"fromBlock":498010,"toBlock":21893810,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xc4ccb46ec96cae5adfbdc436ab2fe197adb88b88f09b440f8f1abeed011e46c1"},{"fromBlock":1375339,"toBlock":19288373,"address":[],"topics":[null,["0x00000000000000000000000070ebe06a95996b1a0adcbc104b6260f087005d64"]],"resultHash":"0x7c064d9c1b629735974686d55a8b82fba5cfa00af5e7385787da00894da412f9"},{"fromBlock":3522755,"toBlock":20703757,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000008d90113a1e286a5ab3e496fbd1853f265e5913c6"]],"resultHash":"0x924731ecaeaa5e4a568f41361a28db7e9cc86423a5858f82274d9d4781406953"},{"fromBlock":1055911,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x752c774441aafb1bad7989a4956cf5ad05aaf9ee2950f75a42c51e6972011bb5"},{"fromBlock":3246943,"toBlock":21894063,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000eae044f00b0af300500f090ea00027097d03000"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0xda5d61491acbe4063f22dd9836de638ff8a6cb9235f49d7d0eb65c4292a2b2c0"},{"fromBlock":3687824,"toBlock":21894191,"address":[],"topics":[null,["0x0000000000000000000000009f817c535f01d0233ad003be4b6872204d4e374c"],["0x000000000000000000000000e49849f768e114bf06a4d715f6aca57c6cc0c35f"]],"resultHash":"0x3ea126ad3557ebf90124145fe8952c7d7dacfa6c3ee76a4dcb35502219f17e96"},{"fromBlock":0,"toBlock":18643412,"address":["0x6a091a3406e0073c3cd6340122143009adac0eda"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0x3e2ff1930e720e2ccade825ceb95022b99d524813c81bd3609c055d8597bd825"},{"fromBlock":2291900,"toBlock":21894063,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000000000000a84d1a9b0063a910315c7ffa9cd248"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x0402502a2cadff21607d273db245589c81a4a292374f2f018f0ab09f160fcb99"},{"fromBlock":2990473,"toBlock":21894191,"address":["0x48ab01de6f130a794c92c1fa260750e805e3a48a"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"]],"resultHash":"0xddc4c3add50a1d24e89edaa609b2984d3e74b552272f1d7e477678f717b05509"},{"fromBlock":2306836,"toBlock":21893842,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000ced92fa7f0797cbc851b48140ae218a0b0d41ce0"],["0x0000000000000000000000000c4b632b389b09b0c6b546f5dbbb15bffad0961e"]],"resultHash":"0x915580b8360c7df84f4ebc2e6171b64d1087fce792c640c67607d6594e405c0f"},{"fromBlock":1018734,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],null,["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0xa00d6abe5fb30be437f037ad126714b0089c50af8d8232e0f6e23dfee30906c0"},{"fromBlock":3900190,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000000000000a84d1a9b0063a910315c7ffa9cd248"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x8592daf1002c678ea61d3c4bf1b61565e1a1de1f1f5dd936003ee1b6f06e09d6"},{"fromBlock":1018734,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x9e2fd8fe2084ce391d23074bab8d5c62c2c30d890f10cd567352f1e95dc3f660"},{"fromBlock":0,"toBlock":18643412,"address":["0x6a091a3406e0073c3cd6340122143009adac0eda"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0x3e2ff1930e720e2ccade825ceb95022b99d524813c81bd3609c055d8597bd825"},{"fromBlock":0,"toBlock":14447940,"address":[],"topics":[null,null,["0x000000000000000000000000f0073a6f7c86beb89c011a0f3e648dec980f16ec"]],"resultHash":"0x55a78fcf6ff6c8def7ab563511d0e35541369d8be9f2afb9a25faf0d9c84f9d3"},{"fromBlock":0,"toBlock":19467161,"address":[],"topics":[null,["0x2d71caede3523746c9bec44231534e5645f562180b5cfb76522cc731447b0371"]],"resultHash":"0x53fc19021225397776d671bbf46b22c4cadb52f38e32489fa9d9913b0b016546"},{"fromBlock":4811934,"toBlock":19243856,"address":["0x7818a7e2ab095a15dcb348c7dd6d1d88d7ceabfd"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0xbccf526ce3d1c8a0cd85657f716c68dcd413ded39eaa29c85269f712adab9394"},{"fromBlock":3860688,"toBlock":17071003,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000009c13b9c6bcc19ba14f309bf823304ad71c652211"]],"resultHash":"0x5449930c0f355976a0ef0bd57ebc7693edf49710b436ce33d6190a307e701361"},{"fromBlock":2832850,"toBlock":21132336,"address":["0xcffdded873554f362ac02f8fb1f02e5ada10516f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000001a1527a5127f721a4c9ff955c93f6faef2f6deb"]],"resultHash":"0xc305ca64b1593584ff364d2fcb57447e7f6e587a98bddf2058f17f512c7ba802"},{"fromBlock":0,"toBlock":20289029,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b3ab7423fede87c31e77163e3a90d20445eca0b3"],["0x00000000000000000000000062c50f2dfd68daef43b38acb22a32626fe5071c2"]],"resultHash":"0x18c42a6fdcfe73c384bbfd940c6cb4924f727edee85c2d1e5d2ab02aa4f3cbc8"},{"fromBlock":1770218,"toBlock":21894031,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000f207e674b23183b75b7dd59cd0a579f75a6d36d9"]],"resultHash":"0xd0e21e41daca0166dbb942c51eef7b76e0b98d3754d958bd94b743f9de60d7fa"},{"fromBlock":498010,"toBlock":21893810,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xb233781eb14a1512d29f99d35730b5afb56981ca4e77c6d44f75d1d74792f4ab"},{"fromBlock":2076442,"toBlock":18707645,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000005c19b9abcfe6791ddb319cb909b20049a5076c53"],null],"resultHash":"0xd706ba50d02d39be5990069d9fa7e1a2ac783a8f21a6191fa0b83a6e00685fde"},{"fromBlock":1560895,"toBlock":21894095,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000045e2aa1483a1c02f1e7d07ff904bb1ded9350ab7"]],"resultHash":"0xb1ba5a4d19da809d9f365903a1e1c0f4751004abe670cdf33511eb374e644951"},{"fromBlock":2346116,"toBlock":21894127,"address":[],"topics":[null,["0x0000000000000000000000009f817c535f01d0233ad003be4b6872204d4e374c"],["0x000000000000000000000000e49849f768e114bf06a4d715f6aca57c6cc0c35f"]],"resultHash":"0x3ea126ad3557ebf90124145fe8952c7d7dacfa6c3ee76a4dcb35502219f17e96"},{"fromBlock":4505710,"toBlock":17219835,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000b94fb3cc45c11b3e1dffbc12490537a78306f1fe"]],"resultHash":"0x186f159071b0889db778ba273294d842c0c606c8517d8d58c85bd951f065a499"},{"fromBlock":3985702,"toBlock":21893842,"address":["0x767fe9edc9e0df98e07454847909b5e959d7ca0e"],"topics":[["0x769254a71d2f67d8ac6cb44f2803c0d05cfbcf9effadb6a984f10ff9de3df6c3"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000004d82a8afdf423681b60811943015c26d0c796ae9"],["0x0000000000000000000000006a091a3406e0073c3cd6340122143009adac0eda"]],"resultHash":"0xa8d522ca3a5c01ada33c3b7cd7dbdb5f0ac274f6a743f13156a2e78900e1ab55"},{"fromBlock":6550738,"toBlock":21893999,"address":["0x80d77b4ae7cd0d7a21fd3c1b2da25a4a06b63923"],"topics":[null,["0x000000000000000000000000bda13cbdadd055527ce95d82d39580a5cb412782"]],"resultHash":"0x13755de37725e0b2bdf8fe4e3b85beed3b1e9e9f152f52cf9c3898019120b1b3"},{"fromBlock":561656,"toBlock":20425331,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"]],"resultHash":"0x8a3550182f1e5f7e12327e4d01a584f502c6814aaae94b5c487c9308dfb70c74"},{"fromBlock":3262923,"toBlock":18342784,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000ade2edad8d2f3a5bd43d11948de9f55973f9ce07"]],"resultHash":"0xaec12a2645aa97caa72437efc1f368cfde740e267f4b96c1c3ef9c138a8aba91"},{"fromBlock":2306836,"toBlock":21893842,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,["0x0000000000000000000000000c4b632b389b09b0c6b546f5dbbb15bffad0961e"]],"resultHash":"0xb34a8e5b2cee1218497c013cbedd2dc209148625c2f95723b6843e1e810022b1"},{"fromBlock":1708350,"toBlock":19452274,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"]],"resultHash":"0x4cd609a7ec7d0df36b9724850f7bb1f5a811c7e910603e67a4452c582e02c944"},{"fromBlock":8963773,"toBlock":21894191,"address":["0xf0ab9667469334bf7943406d766f4c48c05c6820"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45"],["0x000000000000000000000000c44c70fbfef750862fbcf73f5197a28bcaa11253"]],"resultHash":"0x43a1943da819df4a35110a267470fce49de100a869667b4d4e7af78caa57e220"},{"fromBlock":3226696,"toBlock":16587445,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000006637e824c12e1e9b4d0ba8bf0b12874e37192990"]],"resultHash":"0x5bc03006dfa8b7be0eb330ba9b224fb6ebe064424c43ec368a5e2d9a16048e2b"},{"fromBlock":1560895,"toBlock":21894095,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000045e2aa1483a1c02f1e7d07ff904bb1ded9350ab7"]],"resultHash":"0xb1ba5a4d19da809d9f365903a1e1c0f4751004abe670cdf33511eb374e644951"},{"fromBlock":1680976,"toBlock":20417273,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"],["0x0000000000000000000000006748f50f686bfbca6fe8ad62b22228b87f31ff2b"]],"resultHash":"0xf3fc5412340be8676ca9479b03e23ab67c67ab4cc7564fe2167e30f537ff5ec7"},{"fromBlock":0,"toBlock":19835735,"address":["0xdd9fd6b6f8f7ea932997992bbe67eabb3e316f3c"],"topics":[["0x590bbc0fc16915a85269a48f74783c39842b7ae9eceb7c295c95dbe8b3ec7331"],["0x0000000000000000000000000000000000000000000000000000000000000c9d"],["0x0000000000000000000000000000000000000000000000000000000000000001"],["0x00000000000000000000000000000000000000000000000000000000000074fe"]],"resultHash":"0x70404ee2c4a20b754b8260b4547c2c76d9ad602572b2b838f20504eb69b6cdbf"},{"fromBlock":5577609,"toBlock":21894191,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b89eb49bc337d2bfaee360ec63ad606b6788ceb2"],["0x000000000000000000000000e137faa86acba1b35efccc22195bcd1707cc7176"]],"resultHash":"0xa5b400a951ac47b2cca28944e71ade85a78538095ef24292fb193032f30bb2ed"},{"fromBlock":7174588,"toBlock":21893905,"address":["0x5c9921d0dcdd854525f89c62c3a0d8561e182cae"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0xb592363268cfee9c79d93f49e76ce8bd7ba48f63bdcb2e4f5a1cd136ebbef46a"},{"fromBlock":3246340,"toBlock":18546544,"address":[],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000ade2edad8d2f3a5bd43d11948de9f55973f9ce07"]],"resultHash":"0xaec12a2645aa97caa72437efc1f368cfde740e267f4b96c1c3ef9c138a8aba91"},{"fromBlock":3273221,"toBlock":21894127,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000000000000a84d1a9b0063a910315c7ffa9cd248"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"]],"resultHash":"0x33c64bcb9216d613ba200edbc725a5f5d953b52542e26fdd4840a30d203106a3"},{"fromBlock":1548048,"toBlock":21894127,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9"]],"resultHash":"0xf80e59faf84a78dd7e20bfc0be734578944d92bc73078df7006e5db61ded17de"},{"fromBlock":498010,"toBlock":21893810,"address":["0xb9f599ce614feb2e1bbe58f180f370d05b39344e"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x000000000000000000000000031946c8972121053e3fef32cf5ea15dba132fe7"]],"resultHash":"0xebd8535ef0eca9a057a676a16e86f469fb58d71f3e9851a9beb8931bf256ac7c"},{"fromBlock":2031541,"toBlock":17607165,"address":["0xecd20f0ebc3da5e514b4454e3dc396e7da18ca6a"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000848be39d1e89f413f31957f229406069900aa20b"]],"resultHash":"0x8f043387b3db1b73d89a05b3e95505f2b2e6d4a795bb394f8b40bf9f6d7907e6"},{"fromBlock":2306836,"toBlock":21893842,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ced92fa7f0797cbc851b48140ae218a0b0d41ce0"],["0x0000000000000000000000000c4b632b389b09b0c6b546f5dbbb15bffad0961e"]],"resultHash":"0x915580b8360c7df84f4ebc2e6171b64d1087fce792c640c67607d6594e405c0f"},{"fromBlock":3343185,"toBlock":20028240,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000001d8acbe644edc3e077a1d41b84b00dcc1387c000"]],"resultHash":"0xa00f90100ea8fdbc8803a6ac7692313951f0b3b5f9ddf1c90360e0f20042d064"},{"fromBlock":3985702,"toBlock":21893842,"address":["0x767fe9edc9e0df98e07454847909b5e959d7ca0e"],"topics":[["0x769254a71d2f67d8ac6cb44f2803c0d05cfbcf9effadb6a984f10ff9de3df6c3"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000004d82a8afdf423681b60811943015c26d0c796ae9"],["0x0000000000000000000000006a091a3406e0073c3cd6340122143009adac0eda"]],"resultHash":"0xa8d522ca3a5c01ada33c3b7cd7dbdb5f0ac274f6a743f13156a2e78900e1ab55"},{"fromBlock":779698,"toBlock":21893842,"address":["0x24179cd81c9e782a4096035f7ec97fb8b783e007"],"topics":[["0xa55c5f48fd29482ad55f4b59bf070cd1ac1a7132a31f7a136ebe8877ae37e1ff"],["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"]],"resultHash":"0x613dfdefe3d0b316c44294f684ba20fcb92d1ca71e44a5270cdd1822c78890f3"},{"fromBlock":0,"toBlock":20686234,"address":["0x8597fa0773888107e2867d36dd87fe5bafeab328"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0xb424a6afe2786c976fa9c8b6551dd05e14a8e371964b4106e1e14871f04d26e0"},{"fromBlock":5734655,"toBlock":21894063,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000f86b96bb30a5eccc5193d11a0e97bb6572f8962e"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x9a60e4a546c26d7c15556823a32a8cdfd7d41abcbcd452ca2276c5899cc58aff"},{"fromBlock":0,"toBlock":12375709,"address":[],"topics":[null,null,["0x00000000000000000000000039a5707a8c367f2a8a225daea6de53b55e8ec55b"]],"resultHash":"0x6bb32a558b3d468c807b2fe4fde0e15ce933871e247c0ff682f90fb8a3b2ab02"},{"fromBlock":1807231,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x56bbbe6df981199c68f0378a770692c77b374cc316bc192ce0fa1000904ef634"},{"fromBlock":0,"toBlock":20289029,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000032f7ccc365a4ae5f6c3f81f63fb0dfa97a31248d"],["0x00000000000000000000000062c50f2dfd68daef43b38acb22a32626fe5071c2"]],"resultHash":"0x37046876814a9bd24d96233710e70e01d508ee123b5542b8cb867b4032a85d45"},{"fromBlock":8932336,"toBlock":21894159,"address":["0x654ca24793270d5183c69e77df8ccb25bb4cd9fe"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000004d32c8ff2facc771ec7efc70d6a8468bc30c26bf"]],"resultHash":"0x67b2b4602959092374ef113125aa1e0012ba92437c0a633b74be014dea4181be"},{"fromBlock":0,"toBlock":15955059,"address":[],"topics":[["0x590bbc0fc16915a85269a48f74783c39842b7ae9eceb7c295c95dbe8b3ec7331"],null,null,["0x0000000000000000000000000000000000000000000000000000000000005006"]],"resultHash":"0x2a14dc78bf21e6b6cd54b544b431e3ac5278b1fe3dfb18178b60e79982475b44"},{"fromBlock":5698656,"toBlock":21894095,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0xcadc80029938add1c4eaba777c879b894768d25f511b90951ccfe4bd28468799"},{"fromBlock":4179561,"toBlock":21894127,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000001d8acbe644edc3e077a1d41b84b00dcc1387c000"]],"resultHash":"0xa00f90100ea8fdbc8803a6ac7692313951f0b3b5f9ddf1c90360e0f20042d064"},{"fromBlock":0,"toBlock":20483228,"address":["0x907bcfa97fa02037a0a1228709e7756d41f212c5"],"topics":[["0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15"]],"resultHash":"0x5b4cb44fbb1ebc0499dc278f1f89ac3c2b32f06c47eb574ce39fda2df53b86be"},{"fromBlock":7486286,"toBlock":21418779,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b89eb49bc337d2bfaee360ec63ad606b6788ceb2"],["0x000000000000000000000000e137faa86acba1b35efccc22195bcd1707cc7176"]],"resultHash":"0xa5b400a951ac47b2cca28944e71ade85a78538095ef24292fb193032f30bb2ed"},{"fromBlock":7092747,"toBlock":21894063,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000c6cf51f57969129654c5014748e44e2a8f6ebd81"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0x932c43c6e41c3105dc93f0cd52f2ca6b86f4ab21970455377551e0b8a63b8e99"},{"fromBlock":2799555,"toBlock":21894159,"address":[],"topics":[null,null,["0x00000000000000000000000085a23457a05c0f06f097ea0c0ae8da41a02f2bb7"]],"resultHash":"0x4f2763337cb3be0f8db42602e7915efec6fd7ab8cb3e5b7f76aa75dd58449f3a"},{"fromBlock":5022814,"toBlock":21893937,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000047294092daeafc531860a357346502fc3bc70f58"]],"resultHash":"0xe6dc4b56ac6e25fa69a9e04b2de7ac86078cca9f0aaa1e759220590f9bcacb3f"},{"fromBlock":555391,"toBlock":19178028,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x0000000000000000000000001d8acbe644edc3e077a1d41b84b00dcc1387c000"]],"resultHash":"0xa00f90100ea8fdbc8803a6ac7692313951f0b3b5f9ddf1c90360e0f20042d064"},{"fromBlock":5435433,"toBlock":19575687,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41"]],"resultHash":"0x84bb7455f8784403829993af8d7a28e03ee2fdc40b30623f66834fa23f3f6182"},{"fromBlock":4033076,"toBlock":21894191,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003cd751e6b0078be393132286c442345e5dc49699"],["0x000000000000000000000000b725c93b1757648615688961491cc18e70ab9193"]],"resultHash":"0xa134899b2c53eaeb81d7f130257a9ec884cfc3107c2311d88ef1472be67b784f"},{"fromBlock":0,"toBlock":20686234,"address":["0x8597fa0773888107e2867d36dd87fe5bafeab328"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0xb424a6afe2786c976fa9c8b6551dd05e14a8e371964b4106e1e14871f04d26e0"},{"fromBlock":8256499,"toBlock":21894127,"address":[],"topics":[null,null,["0x000000000000000000000000e49849f768e114bf06a4d715f6aca57c6cc0c35f"]],"resultHash":"0xc43647114f9aea1be6433940c32c619daa19c40ad51eddf5fdb8431bea49bce8"},{"fromBlock":9841,"toBlock":21894191,"address":[],"topics":[null,null,["0x0000000000000000000000007da35b3cf8bb5c35036414f32efb2e75e21c016f"]],"resultHash":"0x4f34e5cf10775212d71aef9e357fd3d782bb5633c2c874b50eb21f1681681a63"},{"fromBlock":561656,"toBlock":20425331,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"],["0x0000000000000000000000006748f50f686bfbca6fe8ad62b22228b87f31ff2b"]],"resultHash":"0xf3fc5412340be8676ca9479b03e23ab67c67ab4cc7564fe2167e30f537ff5ec7"},{"fromBlock":7174588,"toBlock":21893905,"address":["0x5c9921d0dcdd854525f89c62c3a0d8561e182cae"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0xb592363268cfee9c79d93f49e76ce8bd7ba48f63bdcb2e4f5a1cd136ebbef46a"},{"fromBlock":1560895,"toBlock":21894095,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000045e2aa1483a1c02f1e7d07ff904bb1ded9350ab7"]],"resultHash":"0xb1ba5a4d19da809d9f365903a1e1c0f4751004abe670cdf33511eb374e644951"},{"fromBlock":779698,"toBlock":21893842,"address":["0x24179cd81c9e782a4096035f7ec97fb8b783e007"],"topics":[["0xa55c5f48fd29482ad55f4b59bf070cd1ac1a7132a31f7a136ebe8877ae37e1ff"],["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"]],"resultHash":"0x613dfdefe3d0b316c44294f684ba20fcb92d1ca71e44a5270cdd1822c78890f3"},{"fromBlock":3262923,"toBlock":18342784,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"],["0x000000000000000000000000ade2edad8d2f3a5bd43d11948de9f55973f9ce07"]],"resultHash":"0xaec12a2645aa97caa72437efc1f368cfde740e267f4b96c1c3ef9c138a8aba91"},{"fromBlock":1708350,"toBlock":19452274,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000030aeb40fdd5165bed9e39c9b20557776329c0617"]],"resultHash":"0x4cd609a7ec7d0df36b9724850f7bb1f5a811c7e910603e67a4452c582e02c944"}],[{"fromBlock":858629,"toBlock":21098839,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000397ff1542f962076d0bfe58ea045ffa2d347aca0"]],"resultHash":"0x165ed93cf839ae1cd2a5c995ab7721a6d2bb998bf52b04bda8999cbc5c014182"},{"fromBlock":11746708,"toBlock":17218172,"address":[],"topics":[null,["0x000000000000000000000000c384ac6ee27c39e2f278c220bdfa5baed626d9d3"]],"resultHash":"0x3655e14a31a83bccdae575d92854bc0dd1aa24b3c42560ea353aaf25313d8635"},{"fromBlock":7477115,"toBlock":17759594,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000022f9dcf4647084d6c31b2765f6910cd85c178c18"]],"resultHash":"0xb9fc739b2867b3eb71cc82ea5d7963190a8aaede09165f5e04a7216b6d98b014"},{"fromBlock":13258007,"toBlock":18370344,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],null,["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x35a1f6e1f190d32c013fcea73c97dfd3a2164e96068b57e4b16e82c342f81b5b"},{"fromBlock":0,"toBlock":20289029,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000062c50f2dfd68daef43b38acb22a32626fe5071c2"]],"resultHash":"0xa065ee163e07ffc77dec98c4d514eb0599a0275ca309f24d3c21b1eb2fe2b1db"},{"fromBlock":1820980,"toBlock":21894127,"address":["0xc83ce8612164ef7a13d17ddea4271dd8e8eebe5d"],"topics":[["0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc505667d1297ab606ef4e5ef6290f36a07d98eb260835f3b9166aecac6319c66"},{"fromBlock":3353941,"toBlock":21893842,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x484fc9b5ce077f8f2cb6c020d48f0bced09216c0b1ac0da9e0001bbf9bca9c76"},{"fromBlock":5117595,"toBlock":21894159,"address":["0x84ca8bc7997272c7cfb4d0cd3d55cd942b3c9419"],"topics":[null,["0x000000000000000000000000a14afc841a2742cbd52587b705f00f322309580e"],["0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582"]],"resultHash":"0x4ee6e708ec24b5f0f66f446ac212c3923094c22e547ebfc41ce66d1600579f59"},{"fromBlock":2963691,"toBlock":21893873,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x484fc9b5ce077f8f2cb6c020d48f0bced09216c0b1ac0da9e0001bbf9bca9c76"},{"fromBlock":582435,"toBlock":21894159,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6c3233107442d18416ade7b79fd533de21764e66f4ca25ce9ba3c0b6756e261c"},{"fromBlock":1857537,"toBlock":21893873,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000008fc6003daded7aeef374ec36030d7770fe41ca3b"]],"resultHash":"0x8e219ae45246dc29efda030f2cdde8e8b98abf6f47a9df3693d3c38c0d35b2bd"},{"fromBlock":5046656,"toBlock":21893873,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"]],"resultHash":"0xd6be99adf427eda717d9faabeee61ae04949d8a7d47f6bf75707296ef57a0c26"},{"fromBlock":2159059,"toBlock":21893873,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":2046014,"toBlock":21894063,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,["0x000000000000000000000000f3a71cc1be5ce833c471e3f25aa391f9cd56e1aa"],["0x00000000000000000000000031d38869257c8af9023077d2316e42b948c74a17"]],"resultHash":"0xd98a051dddb5c2693d0a4f4ff67ab4a0e3fb5e11e0609dc798da410699526842"},{"fromBlock":5659008,"toBlock":20787948,"address":["0x5b272ce3e225b019a3fbd968206824b24c674344"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0x5150b1201282f07ec34a1874fd79f990b3efbb505b10396bb2b801c074a7496a"},{"fromBlock":1857537,"toBlock":21893873,"address":["0xec78bd3b23ac867fcc028f2db405a1d9a0a2f712"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000008fc6003daded7aeef374ec36030d7770fe41ca3b"]],"resultHash":"0x06ec627b839b58730cc13213218e71f5515b803518a7920d9a4c451dfd5b1e90"},{"fromBlock":0,"toBlock":16618657,"address":[],"topics":[null,["0x000000000000000000000000e85430a51bd131905219bb2460fb893f48236cef"],["0x00000000000000000000000049ab3df9ce5de1e321357e35f51fbde7e0e6a294"]],"resultHash":"0x9d26e74af44ab8f52fff14928929b8c28738590c60ab177073dabf77944a86fd"},{"fromBlock":7300018,"toBlock":21894063,"address":["0x8597fa0773888107e2867d36dd87fe5bafeab328"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0xb424a6afe2786c976fa9c8b6551dd05e14a8e371964b4106e1e14871f04d26e0"},{"fromBlock":9258484,"toBlock":21596057,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"],null,["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xcd63004fb1b98175a09ef9fb68c62d0a77705530817dd329faaaecd889728175"},{"fromBlock":7643516,"toBlock":21869131,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[null,["0x0000000000000000000000004870525eae23fceb31df613d179ef6275e1b93a9"],["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xb8d1170e45e6c0bf31964956c562019a40370922cbdcbeb3cd993a9d6eb5a26a"},{"fromBlock":4204051,"toBlock":21894159,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[null,["0x0000000000000000000000004870525eae23fceb31df613d179ef6275e1b93a9"],["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xb8d1170e45e6c0bf31964956c562019a40370922cbdcbeb3cd993a9d6eb5a26a"},{"fromBlock":7174588,"toBlock":21893905,"address":["0x5c9921d0dcdd854525f89c62c3a0d8561e182cae"],"topics":[],"resultHash":"0x9fa1c6d661838ebe2ee3a996093a7105c8b6802c337905b3be990c66e8960654"},{"fromBlock":12516253,"toBlock":14846181,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0xa9eb14873480c988ad3064d4672ec0c669fb3a4ba28ad8a2c266adaaf58273e4"},{"fromBlock":5377061,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":5860646,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":1548048,"toBlock":21894127,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6c3233107442d18416ade7b79fd533de21764e66f4ca25ce9ba3c0b6756e261c"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":5759874,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000c6cf51f57969129654c5014748e44e2a8f6ebd81"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6053ffc37d74d5bb214410fda120b4cb4e2ddc9d8255477d62ec2c03646dfb88"},{"fromBlock":179021,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":12593555,"toBlock":14774164,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0xa009cbb7c40ff16eefb49c0ea7a0348c5d969f8972602621296ff528184b1fa3"},{"fromBlock":3499853,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":5052437,"toBlock":21893905,"address":["0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007835cb043e8d53a5b361d489956d6c30808349da"],["0x0000000000000000000000004585fe77225b41b697c938b018e2ac67ac5a20c0"]],"resultHash":"0x6247976a772901b29f48b3b63bb53ad636b5787a6c08bbde7acc64c4058d0f62"},{"fromBlock":2133143,"toBlock":21894191,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000930af7923b8b5f8d3461ad1999ceeb8a62884b19"]],"resultHash":"0x27b700ad73bb589322c65818d818ddf625087bb76b4bd9186da78a7f045f3a52"},{"fromBlock":6380717,"toBlock":20391181,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0x858770148af52a5bc2057de44a63859986a9d6bc22b828301e5908237000df3d"},{"fromBlock":182183,"toBlock":21893905,"address":["0x1580eb65edb0b903e7b3624ca963219d0c5c565e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"]],"resultHash":"0xb4fb9017fcd461ef4167c9aa013c7f83f4ac7fde0db492c473fc9bbaa6fc7c3a"},{"fromBlock":6545879,"toBlock":19939849,"address":["0x8597fa0773888107e2867d36dd87fe5bafeab328"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0xb424a6afe2786c976fa9c8b6551dd05e14a8e371964b4106e1e14871f04d26e0"},{"fromBlock":3224543,"toBlock":21893937,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000000ef7f9c5549165d204d8f440d1d84ea4f8c1dca4"]],"resultHash":"0x682af1b9d18d3f1eb76cda18cb59fb4247c84e6d96dbac3e70c5ba8590ed0782"},{"fromBlock":11837911,"toBlock":20537481,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0x1ead1b3630ef89a7cbb6223ea2c7019e2d48c222472a4e2ed3b1ba855d3f3cf7"},{"fromBlock":894101,"toBlock":21894095,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007316f8dd242974f0fd7b16dbcc68920b96bc4db1"],["0x00000000000000000000000073a8a6f5d9762ea5f1de193ec19cdf476c7e86b1","0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x30b08f22ebd2786d40db0ddb9a6d07004274c5ac4c5378f0ee0a5907e472d438"},{"fromBlock":5046705,"toBlock":20777213,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0xb6758c982200700783d68838ece59848e13a5b899e449a98851d12f6059c0ddc"},{"fromBlock":1211116,"toBlock":19491941,"address":["0xd77bcd9cf4212a41defbcd2e2ff0f50fea2be643"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000003ce2a0101df6b034635f0bcec7a6cd9597768796"]],"resultHash":"0xc85149c68026f8c90afb6eb16acc6465d7a8ecf9de9425a813fc22f1ec6f48a9"},{"fromBlock":0,"toBlock":19953000,"address":["0xd73be539d6b2076bab83ca6ba62dfe189abc6bbe"],"topics":[["0x0b95606a57983e48ae4c9631df8d2e17766c3017421531c1004a4882888ef274"],["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0xe37c942941ca7d356a6f84958d872d105c852a08478d85d2819c5bc3de33e4c7"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":0,"toBlock":21311753,"address":[],"topics":[null,["0x000000000000000000000000b647dd3226e2811d86990ea7766f5d851eb78b75"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0xf5ceffa06b492e7cdc91530c034069e00a69741f757b9fa828e363bfabe1a540"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0xb6758c982200700783d68838ece59848e13a5b899e449a98851d12f6059c0ddc"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":7643516,"toBlock":21869131,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],["0x0000000000000000000000004870525eae23fceb31df613d179ef6275e1b93a9"],["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xb8d1170e45e6c0bf31964956c562019a40370922cbdcbeb3cd993a9d6eb5a26a"},{"fromBlock":2680494,"toBlock":21893873,"address":["0x1580eb65edb0b903e7b3624ca963219d0c5c565e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"]],"resultHash":"0xb4fb9017fcd461ef4167c9aa013c7f83f4ac7fde0db492c473fc9bbaa6fc7c3a"},{"fromBlock":1336992,"toBlock":21894191,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000f3a71cc1be5ce833c471e3f25aa391f9cd56e1aa"],["0x00000000000000000000000031d38869257c8af9023077d2316e42b948c74a17"]],"resultHash":"0xd98a051dddb5c2693d0a4f4ff67ab4a0e3fb5e11e0609dc798da410699526842"},{"fromBlock":9775446,"toBlock":21893937,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6c3233107442d18416ade7b79fd533de21764e66f4ca25ce9ba3c0b6756e261c"},{"fromBlock":7173828,"toBlock":20903756,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x0000000000000000000000004a137fd5e7a256ef08a7de531a17d0be0cc7b6b6"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x4a8fa44bf717ed1f6d2aa0e41a692696e8d70615f4fe7b829af045fe63da447b"},{"fromBlock":6557870,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000c6cf51f57969129654c5014748e44e2a8f6ebd81"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6053ffc37d74d5bb214410fda120b4cb4e2ddc9d8255477d62ec2c03646dfb88"},{"fromBlock":8082667,"toBlock":21631503,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x0000000000000000000000005b6be21c4d1f2c1c5a3d6af3599f3bb0a785ae2f"]],"resultHash":"0x12349f34fbf81fc91e331c4514b35f955c6bb1aa6bb9dab782436977d5d9719a"},{"fromBlock":0,"toBlock":21385893,"address":["0xd73be539d6b2076bab83ca6ba62dfe189abc6bbe"],"topics":[["0x0b95606a57983e48ae4c9631df8d2e17766c3017421531c1004a4882888ef274"],["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0xe37c942941ca7d356a6f84958d872d105c852a08478d85d2819c5bc3de33e4c7"},{"fromBlock":1300386,"toBlock":21894095,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xbf3454ca1c15ac8eb2d327f70e180f59d2d87c96cc0f4527339252092e03a2f3"},{"fromBlock":0,"toBlock":21281139,"address":[],"topics":[["0x0b95606a57983e48ae4c9631df8d2e17766c3017421531c1004a4882888ef274"],["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0xe37c942941ca7d356a6f84958d872d105c852a08478d85d2819c5bc3de33e4c7"},{"fromBlock":7272863,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],null,["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0xcd02c26f900f02aaa4c64f843ebee92dc1a5ea20d889f7a6a77943d44ddcf98b"},{"fromBlock":9775446,"toBlock":21893937,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x752c774441aafb1bad7989a4956cf5ad05aaf9ee2950f75a42c51e6972011bb5"},{"fromBlock":1066914,"toBlock":16528429,"address":["0x5b272ce3e225b019a3fbd968206824b24c674344"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0x5150b1201282f07ec34a1874fd79f990b3efbb505b10396bb2b801c074a7496a"},{"fromBlock":9258998,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000000000000000a84d1a9b0063a910315c7ffa9cd248"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x7afbcda9db33cb632a5cafa3d70a839f9925cd0219408baeabe2befd2acf0a98"},{"fromBlock":6597345,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xacfccfac41d3f6a30b6fc92ba4444c483ef225b62bec7921a733e2f293dd9965"},{"fromBlock":5044153,"toBlock":21894127,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000aaf5110db6e744ff70fb339de037b990a20bdace"]],"resultHash":"0x5dc8a7c0b859b49a72a24bce1a0d0812feaac042017e726dabd2a0450c81edce"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":13590571,"toBlock":20555719,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xf66582f49ef22141ec895dd9dc7f7f4658da09e02c56db3fd9df448bc284af22"},{"fromBlock":0,"toBlock":16977620,"address":["0xcced5b8288086be8c38e23567e684c3740be4d48"],"topics":[["0x7d19c7776f05049226f581a23a4df896c65115763d8ec30490658efc4e8649cd"],["0x000000000000000000000000aa4adaa72dd05a84dbedb813c04eff90336d7c29"]],"resultHash":"0x495e9976c3e1db953581b9a2ef7763c42cdaae69aa61cfc6707afe7a248ddcbe"},{"fromBlock":113660,"toBlock":17433476,"address":["0x191557728e4d8caa4ac94f86af842148c0fa8f7e"],"topics":[null,["0x0000000000000000000000007aa96ef1261c21da7fdadb5613e356348cc088ca"]],"resultHash":"0xf4d58347fc060a177cbe50f490c6c81b37973fbae6ee1ea78ca64c2777b2223f"},{"fromBlock":1767302,"toBlock":21894191,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6c3233107442d18416ade7b79fd533de21764e66f4ca25ce9ba3c0b6756e261c"},{"fromBlock":1505748,"toBlock":13182280,"address":[],"topics":[null,["0x000000000000000000000000cdf9c1fedad9f92c5c2e0c4c37aa15387eda11cd"]],"resultHash":"0xca8a34d6c5c24c318aec0855a6ea628cbac1339007eec15ce8a34c7b465d4f74"},{"fromBlock":1100280,"toBlock":17937411,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b1035d946d6548feca96341485d28eba463ad9cb"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"]],"resultHash":"0x140607d5e71d4b4fa5746d136dff83b43f5edff28bdd780f4b955f434fd4d38f"},{"fromBlock":2680494,"toBlock":21893873,"address":["0x1580eb65edb0b903e7b3624ca963219d0c5c565e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"]],"resultHash":"0xb4fb9017fcd461ef4167c9aa013c7f83f4ac7fde0db492c473fc9bbaa6fc7c3a"},{"fromBlock":6815398,"toBlock":21893999,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"]],"resultHash":"0xd6be99adf427eda717d9faabeee61ae04949d8a7d47f6bf75707296ef57a0c26"},{"fromBlock":994757,"toBlock":18740247,"address":[],"topics":[null,null,["0x000000000000000000000000fba8763d939f30af181657c8722b57e9b5a58c50"]],"resultHash":"0x65c082202e8eeff57b250421c066ecc67981add3e287f312c441200c24f59727"},{"fromBlock":6550738,"toBlock":21893999,"address":[],"topics":[null,["0x000000000000000000000000bda13cbdadd055527ce95d82d39580a5cb412782"]],"resultHash":"0x7c82628b4c176ca32b5653f3b7f886572bcd6e6e4b6baa28c16ba71e833789c8"},{"fromBlock":6597345,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xacfccfac41d3f6a30b6fc92ba4444c483ef225b62bec7921a733e2f293dd9965"},{"fromBlock":893718,"toBlock":17209388,"address":["0xd73be539d6b2076bab83ca6ba62dfe189abc6bbe"],"topics":[["0x0b95606a57983e48ae4c9631df8d2e17766c3017421531c1004a4882888ef274"],["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0xe37c942941ca7d356a6f84958d872d105c852a08478d85d2819c5bc3de33e4c7"},{"fromBlock":0,"toBlock":20626416,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000009d7157deaa4af751701736576d7f5f03bd718a9f"]],"resultHash":"0xf5f2d1759f3b258008e908f2f25b457aa1f689b96e4c1871e4ecf781e324597c"},{"fromBlock":9775446,"toBlock":21893937,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x752c774441aafb1bad7989a4956cf5ad05aaf9ee2950f75a42c51e6972011bb5"},{"fromBlock":7429255,"toBlock":21894063,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000f7ac25089776c904db0e6c06502f9fc114e36863"],null],"resultHash":"0xb298bda8d09abf754c0f17ec503db379f2a25df3adcf00c1e5eae8c65b0cc818"},{"fromBlock":12107583,"toBlock":14999416,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0x85e7f2024dcfe534a412883ee6029409a08aa7ec7895b53caae1c65df9b8cd8c"},{"fromBlock":3226696,"toBlock":16587445,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x0000000000000000000000006637e824c12e1e9b4d0ba8bf0b12874e37192990"]],"resultHash":"0x589159069c3dcc85df7d2ffc467e4269c3ef2c927d6f5c936118d778232ceb93"},{"fromBlock":3388912,"toBlock":21893999,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba11d00c5f74255f56a5e366f4f77f5a186d7f55"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xacfccfac41d3f6a30b6fc92ba4444c483ef225b62bec7921a733e2f293dd9965"},{"fromBlock":7643516,"toBlock":21869131,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],["0x0000000000000000000000004870525eae23fceb31df613d179ef6275e1b93a9"],["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xb8d1170e45e6c0bf31964956c562019a40370922cbdcbeb3cd993a9d6eb5a26a"},{"fromBlock":7745619,"toBlock":20558302,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000c6cf51f57969129654c5014748e44e2a8f6ebd81"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6053ffc37d74d5bb214410fda120b4cb4e2ddc9d8255477d62ec2c03646dfb88"},{"fromBlock":0,"toBlock":19212688,"address":["0x7cc768b882be41ca03f9daccfc48b8bd6d25eb25"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0x0374b41686c1a6c2cdf211a015fad106c4ac04ef553487de12fb848c69c42ffd"},{"fromBlock":4588195,"toBlock":19768276,"address":["0xc730ef0f4973da9cc0ab8ab291890d3e77f58f79"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000000000000089341e263b85d84a0eea39f47c37a9d2"],["0x0000000000000000000000000000000089341e263b85d84a0eea39f47c37a9d2"]],"resultHash":"0xbf97904122c251d2b145143b47de395c2d98e5b545bff35945d53ec8eb50d780"},{"fromBlock":0,"toBlock":19248027,"address":["0xcffdded873554f362ac02f8fb1f02e5ada10516f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000004d246be90c2f36730bb853ad41d0a189061192d3"],["0x0000000000000000000000004d246be90c2f36730bb853ad41d0a189061192d3"]],"resultHash":"0x3e4fe7261ff83ec87adef5af34e82469e744eb77eed67f27dd4f6f30a557d65f"},{"fromBlock":317883,"toBlock":21894127,"address":["0x7ad4780dfa1624ad1dca5d514c90ea7cf6eb37f9"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000008fe7d9643077b4ab2885cb2dad4236cc4784413f"],null],"resultHash":"0x83abf0d1b90ed7557c2d0e44467ff7af7ce181b9ee79671011eb800343222195"},{"fromBlock":34595,"toBlock":16109879,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000037bd00aa1d2e98e48c0db302d35530212f388cd1"]],"resultHash":"0x639c713d9cea69fe6a1add8877510f3a1c5a4008799fae0b016be55c857f5764"},{"fromBlock":2472500,"toBlock":21893905,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":3940581,"toBlock":21823220,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45"],["0x000000000000000000000000cc164307e9642d2adea4ff102082ccdefe5e8282"]],"resultHash":"0xba000b48ac7a9814e2d8cee1d1fe682b96b4a08db53c72f1486e0285d05c290b"},{"fromBlock":5619876,"toBlock":21894127,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xbf3454ca1c15ac8eb2d327f70e180f59d2d87c96cc0f4527339252092e03a2f3"},{"fromBlock":4711049,"toBlock":19656623,"address":["0x795065dcc9f64b5614c407a6efdc400da6221fb0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000594fe7c3d4c52c0e9ab377bc6d8acd66adc8ea9d","0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0x5338b3ee1b64a5df0e0f76216d6922e2eee34cb3a61e6392d4fc8c9160ea8506"},{"fromBlock":0,"toBlock":19248027,"address":["0xcffdded873554f362ac02f8fb1f02e5ada10516f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000004d246be90c2f36730bb853ad41d0a189061192d3"]],"resultHash":"0x3e4fe7261ff83ec87adef5af34e82469e744eb77eed67f27dd4f6f30a557d65f"},{"fromBlock":2076827,"toBlock":21894031,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x7aa8d86a67288e966d8e87864bfb57529ed927d39b0613c7d74f517261c9e3c7"},{"fromBlock":998893,"toBlock":21894159,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000e382ec905825ddbbff33321dd82ed588aef53a79"]],"resultHash":"0x08fbdb3df764c22af1dadb4b9af9da81cc0ab9fc516d2d9644de7aa187c41653"},{"fromBlock":120089,"toBlock":18033710,"address":[],"topics":[["0x0b95606a57983e48ae4c9631df8d2e17766c3017421531c1004a4882888ef274"],["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0xe37c942941ca7d356a6f84958d872d105c852a08478d85d2819c5bc3de33e4c7"},{"fromBlock":0,"toBlock":19835735,"address":["0xdd9fd6b6f8f7ea932997992bbe67eabb3e316f3c"],"topics":[["0x590bbc0fc16915a85269a48f74783c39842b7ae9eceb7c295c95dbe8b3ec7331"],["0x0000000000000000000000000000000000000000000000000000000000000c9d"],["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0x1f7a87c98be3c5b2d93aa4f3fa8dae2fdcfa3a9df916a68e4fdd9b53e56a5512"},{"fromBlock":5759874,"toBlock":21893969,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000c6cf51f57969129654c5014748e44e2a8f6ebd81"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x6053ffc37d74d5bb214410fda120b4cb4e2ddc9d8255477d62ec2c03646dfb88"},{"fromBlock":2275417,"toBlock":19872511,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0x6342bf689bc6db0f5a98fbb77c0dc42e58738444bb642f0ec1624bde0768f917"}],[{"fromBlock":11839013,"toBlock":14284317,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000036e2fcccc59e5747ff63a03ea2e5c0c2c14911e7"]],"resultHash":"0x6906b73f0b0f66a6c6f9fa7fc9a108faedc2427d1d9dfacef3256921b5fa0af7"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xacbec158aec75fe8ce89950fa1b95acb231026a12d2a7ea68c1b74c7138fbbb4"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xacbec158aec75fe8ce89950fa1b95acb231026a12d2a7ea68c1b74c7138fbbb4"},{"fromBlock":12504138,"toBlock":14210036,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x71379a2ca31e2cb4227a090bb0db3f57d47187886df730b3cb2b07abf923559a"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xacbec158aec75fe8ce89950fa1b95acb231026a12d2a7ea68c1b74c7138fbbb4"},{"fromBlock":15140544,"toBlock":17805709,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0xf549a9667bea908e32dadbbb5b9ec49aa930070594a37196873197e45fed2450"},{"fromBlock":15048301,"toBlock":17978752,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000000000000c2cf7648c169b25ef1c217864bfa38cc"]],"resultHash":"0xcffc8bf85a0856832eef729a2b4064f63451707206d4431ead14125549123312"},{"fromBlock":11613954,"toBlock":14323073,"address":[],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0xa0fdaed4ec2f3460f99c0f96943b7eefd123102c6ef1fb833c41957f9dceb54e"},{"fromBlock":11416062,"toBlock":14469068,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x77c4c77fd2df40547a5fcbdeb0a5a2b2ec4b3244641e47ff6945149b7686dd70"},{"fromBlock":12301000,"toBlock":13791213,"address":["0x5b272ce3e225b019a3fbd968206824b24c674344"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0x994bc419722a4fb8b3d7ffeb02bc6d56744ecc0589261e46ad57051faa4ba016"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xacbec158aec75fe8ce89950fa1b95acb231026a12d2a7ea68c1b74c7138fbbb4"},{"fromBlock":12431122,"toBlock":13427755,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x7517cb2e4d59f8c24138583eb2b487618884ac89a5a2a1cd203ba76db4b6c0cf"},{"fromBlock":11613954,"toBlock":14323073,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0xbf9631c2f7c77cfcb0536102bba22ff5301b0193619280b949732289473d2a9d"},{"fromBlock":11416062,"toBlock":14469068,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1aa629db11f2770d551eed52ccd8414f782683871c56e1beb46ed39b14dd50c7"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":12522337,"toBlock":13954331,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x9d027a0cebfb2cf001210a5397d9fabbe33d647872c3d174942d57adc09087dd"},{"fromBlock":12865129,"toBlock":19934618,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x52a31da088639b81b5353f339085ae96891f5eec27a24fce0ddd097adf7310a9"},{"fromBlock":11416062,"toBlock":14469068,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1aa629db11f2770d551eed52ccd8414f782683871c56e1beb46ed39b14dd50c7"},{"fromBlock":12416519,"toBlock":13910111,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x4951c1a95d4132b8b2a950986d6b487247d95f6926bc751fe68b7fe0f4009d11"},{"fromBlock":12608049,"toBlock":13369158,"address":["0x7b504a15ef05f4eed1c07208c5815c49022a0c19"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000004a137fd5e7a256ef08a7de531a17d0be0cc7b6b6"]],"resultHash":"0x74e5a4ba9b5a9d9cacffbd1d0ed877d4c9e6a55d31b174ce1fe162fc8b31361c"},{"fromBlock":15409639,"toBlock":16351372,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"]],"resultHash":"0x41eab43c6bf42aac822fa2791dce48d967ee361dda18fcf4e9977ed3f6ec7a2c"},{"fromBlock":12461919,"toBlock":13392681,"address":["0xcb2286d9471cc185281c4f763d34a962ed212962"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc637ee294c931f97f5a1bd5e5b195e6994c1684ebd75beb455e98a3271a8966a"},{"fromBlock":12922251,"toBlock":13636183,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"]],"resultHash":"0x13ad363e5347f188b8d47a104f856a7a6d9d27d1795f825cb6449d2c14d9e5ef"},{"fromBlock":12390674,"toBlock":14001099,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000b3c839dbde6b96d37c56ee4f9dad3390d49310aa"]],"resultHash":"0x0821c0976e7c53f210d0e7d0e195bbcf750ba0f3192080a5176e56ed303fbf33"},{"fromBlock":12476959,"toBlock":13885934,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x0ee14a2e6f4073ce495e1d4992b1060627f9933981d733968192d582352b8d77"},{"fromBlock":11416062,"toBlock":14469068,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1aa629db11f2770d551eed52ccd8414f782683871c56e1beb46ed39b14dd50c7"},{"fromBlock":15140544,"toBlock":17805709,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0xf549a9667bea908e32dadbbb5b9ec49aa930070594a37196873197e45fed2450"},{"fromBlock":12624557,"toBlock":13430093,"address":["0xcb2286d9471cc185281c4f763d34a962ed212962"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x25dc4526530aadb70644e7210930ce534f3e3dc0b842fd02e9e1e4c9299e24e7"},{"fromBlock":14418700,"toBlock":18236043,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"]],"resultHash":"0x0e33448a22cbd2c3dbd1141c8a363f41998abc90c7a6049e5be8b9fb13268e6a"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":14651521,"toBlock":17875529,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x8201aa3f00000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"]],"resultHash":"0x56ffd48746def7d6da4f018f6f84761687c5f75686cecb5ea28f6e035fd7b973"},{"fromBlock":15771134,"toBlock":16461475,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45"],["0x000000000000000000000000c44c70fbfef750862fbcf73f5197a28bcaa11253"]],"resultHash":"0x8ffa386dcecb233eeb2e5825f89e8efc61c44680123b3a41c5e77002c0236ef8"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1ad156a080eb3202e61c0c78b506e53454ae1fd081b58342f2ee218539bed43b"},{"fromBlock":12544847,"toBlock":13476803,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x5f7c4671078041cb2112ace33792a39c94c8846fe9c8f3d1c5ca3de4fd75d82b"},{"fromBlock":13951704,"toBlock":17518225,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x8201aa3f00000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"]],"resultHash":"0xc4801ad2945a4f06e376cf53633fc86f74bbba63e5fabbdb48d06cdfac46e928"},{"fromBlock":10086946,"toBlock":12244571,"address":[],"topics":[null,["0x00000000000000000000000078b950c15e9deffd256075ce6c2698239a334541"]],"resultHash":"0xaa31abb65b849539fc258ecb6a563b24559573d861d0b518c36301b4e6c08519"},{"fromBlock":12506301,"toBlock":13514978,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x97baae9c34e26ade57314f1019d9822dfad3f3ba4731672cf027e86d775124aa"},{"fromBlock":12516899,"toBlock":13399954,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0","0x7b504a15ef05f4eed1c07208c5815c49022a0c19"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0x30b9129de159cbb17d7f0f548d32318c6b9e62edd0a5430fb1aaa8ab327ec15b"},{"fromBlock":13032438,"toBlock":14926063,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000665fb69d812666794588a58f25b91a65b40f1bde"]],"resultHash":"0x20b189bf4f69788d8f2cca3b5603d417c70018fa36c1bc3a3e3f8e5f990a24e5"},{"fromBlock":14020248,"toBlock":17904165,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x8201aa3f00000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000006317c5e82a06e1d8bf200d21f4510ac2c038ac81"]],"resultHash":"0xfe48e1b28235bf2398cc081fa62a9bf7942c5aa60fa7181ff6aeb5b7e89c33e9"},{"fromBlock":12153933,"toBlock":13463385,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000064c29aac69d3122f6e5531ceca1b753f95350af4"],["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0xf9ac647d4d143198204100084f6e5b99e6cf65f3fd66bb9edb3fba07a664ff09"},{"fromBlock":12202346,"toBlock":13711217,"address":["0x62f22a47e5d2f8b71cc44fd85863753618312f67"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x0000000000000000000000000652687e87a4b8b5370b05bc298ff00d205d9b5f"]],"resultHash":"0xd6e92f67244139b4bffd846c28810cb60a25b10420023f319203bfbb68c880a7"},{"fromBlock":12475336,"toBlock":13335919,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000aaf5110db6e744ff70fb339de037b990a20bdace"]],"resultHash":"0x932204b2a28773952d34195710ef28b7e1adb94de54b690f5762fa6a4872dfd7"},{"fromBlock":14539343,"toBlock":17375669,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xfde2cdc3231fd4fefb0575021cee57332de9331e31e09034a877affe3ba6be8e"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":12699475,"toBlock":13411689,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0x63b2fdd39a9f4e0ca43e5b7ce01f6b1d8982e2d63ac9c6453ed31886f10b2f84"},{"fromBlock":11296015,"toBlock":14101136,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,["0x000000000000000000000000f3a71cc1be5ce833c471e3f25aa391f9cd56e1aa"],null],"resultHash":"0xfbb9529dc92f4419cddcec6d28767428479ca8e61d368eb9c694e0a7338d10a3"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x357188f6d1d38581c197d16458ed5ec35ab6ad20182883cc516926fbece8f0f8"},{"fromBlock":14881287,"toBlock":18089474,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0x817052d1f6a5fda24e083c9f14d1f3e3f75b9f3ed79b114b622a45c0aa222c5d"},{"fromBlock":15125183,"toBlock":16564131,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,["0x00000000000000000000000024902aa0cf0000a08c0ea0b003b0c0bf600000e0"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x30acc4118b57fc0ba3ea05eca6d5e51615b26b89acd2d4171e209e9f7633c088"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1ad156a080eb3202e61c0c78b506e53454ae1fd081b58342f2ee218539bed43b"},{"fromBlock":12559679,"toBlock":13428937,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0","0x7b504a15ef05f4eed1c07208c5815c49022a0c19"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0xeb64f87423c165e24297c2bc9497e00edaee140efa11f8a9e859ebe2a742caae"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":12540456,"toBlock":13448910,"address":["0x3fd4cf9303c4bc9e13772618828712c8eac7dd2f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x4d57fd13f22b2a29ef70dcdaf5697673fdd66f76e60647e5ebbbf2fbc492d1d7"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x357188f6d1d38581c197d16458ed5ec35ab6ad20182883cc516926fbece8f0f8"},{"fromBlock":11692350,"toBlock":15074655,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0x612146a8f2f8b0b34f29d6ed0a350294a75a48d9800481a9d3ab6dfed15c1ba3"},{"fromBlock":11544128,"toBlock":14545282,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x6832d6096512941ced59e65aba3b40c613ff3478d908ccb456fffeda375510de"},{"fromBlock":14539343,"toBlock":17375669,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xfde2cdc3231fd4fefb0575021cee57332de9331e31e09034a877affe3ba6be8e"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":11613954,"toBlock":14323073,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0xbf9631c2f7c77cfcb0536102bba22ff5301b0193619280b949732289473d2a9d"},{"fromBlock":15125183,"toBlock":16564131,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000024902aa0cf0000a08c0ea0b003b0c0bf600000e0"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x30acc4118b57fc0ba3ea05eca6d5e51615b26b89acd2d4171e209e9f7633c088"},{"fromBlock":11544128,"toBlock":14545282,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x08547c364309bf608994c574a7e3631c0b09c64c55875a3d0e2d8d3e39130378"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x357188f6d1d38581c197d16458ed5ec35ab6ad20182883cc516926fbece8f0f8"},{"fromBlock":11380001,"toBlock":14866061,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0xb6641c42de5d662e7bb143ffcff3a9c9836c36d30e4b55b3904da7b8004c32c5"},{"fromBlock":19238012,"toBlock":20653018,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09"],["0x000000000000000000000000f07c735011c311f55425bf8c534471a0410d85ad"]],"resultHash":"0xfbbfec7a73b7b483327f696001d8b3d8047be2319bd0597c31a3f5f249348728"},{"fromBlock":13330524,"toBlock":15982025,"address":["0xa9ca155590671bbc01d7e1d95c0adec749e39cfc"],"topics":[null,null,null,["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"]],"resultHash":"0x5e7ab29d61fe9781fc54ffe1a4d14f2f6f82bece06d379742a86f8729495607f"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x357188f6d1d38581c197d16458ed5ec35ab6ad20182883cc516926fbece8f0f8"},{"fromBlock":12670867,"toBlock":13440248,"address":["0xba38eca6dfdb92ec605c4281c3944fccd9dec898"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x6d81b020417d8ac7eb471ea2b7a31f654a99ca403fa90cd1ba87afb1586d0190"},{"fromBlock":15125183,"toBlock":16564131,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000024902aa0cf0000a08c0ea0b003b0c0bf600000e0"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x30acc4118b57fc0ba3ea05eca6d5e51615b26b89acd2d4171e209e9f7633c088"},{"fromBlock":12509850,"toBlock":13827509,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x88631e36611c620100217d84e615647cafdac505dc26c1b88412f425790dd0e1"},{"fromBlock":13803946,"toBlock":18039300,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x0ce0dbb6618b22c2fad02ba08ee798a446c4c0d8305817ee02534f9ba104cf83"},{"fromBlock":12539155,"toBlock":13733050,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x160c18c5fe9cb9cbf61ba59ba6d4e9d85961b3fc6492c9c40f15b877d66de830"},{"fromBlock":15099458,"toBlock":17831942,"address":[],"topics":[null,["0x00000000000000000000000093c329189b3f6fef306b98ee88dd0aa5ec1ec15e"]],"resultHash":"0xe5a173464ee39b50b00b57cf435ab5439d7d0ee8fbf9fe6ab6a4ce59e35b188c"},{"fromBlock":14237149,"toBlock":19268681,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x6d9e377636b3270f9b3bb45a4689c815367654ec217f04b63df3ab610013d7c6"},{"fromBlock":11501829,"toBlock":14467264,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x20bec368440da0e8cd2041800d61b7a7461b46697059a1daef8376d9893a4b72"},{"fromBlock":12719414,"toBlock":13495086,"address":["0x18d98d452072ac2eb7b74ce3db723374360539f1"],"topics":[["0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xaae505ecfb47fcd47fcbe78d0baeac0fc76d816809a8902396eb6e9f31b4bdf9"},{"fromBlock":12901053,"toBlock":13437194,"address":["0xd73be539d6b2076bab83ca6ba62dfe189abc6bbe","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000652687e87a4b8b5370b05bc298ff00d205d9b5f"]],"resultHash":"0x66b335c56e33cc5f4b30a0670472d83e6414aeb292a93b67266161a30a28f9c9"},{"fromBlock":12532649,"toBlock":14240089,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xaa71cb2bb9c7bea535ff2cbd46212d8dd926e07b4551b46f7e05b6c33094d457"},{"fromBlock":15125183,"toBlock":16564131,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x00000000000000000000000024902aa0cf0000a08c0ea0b003b0c0bf600000e0"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x30acc4118b57fc0ba3ea05eca6d5e51615b26b89acd2d4171e209e9f7633c088"},{"fromBlock":11516074,"toBlock":15361176,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1350793c356e20b4b62d3bb503264af1ff16f58d237ecb3194eb0317ed7149d6"},{"fromBlock":19130008,"toBlock":21513200,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09"],["0x000000000000000000000000f07c735011c311f55425bf8c534471a0410d85ad"]],"resultHash":"0x075da09437ffcbb104d92bd67b278a4a387771ce84ad81e961aa1e5041a89a17"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1ad156a080eb3202e61c0c78b506e53454ae1fd081b58342f2ee218539bed43b"},{"fromBlock":11534372,"toBlock":15826161,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0xc0cadc070e710e0778cb9598a57361e480bddcafb95e2c49a3cfd62b8de7536d"},{"fromBlock":13679707,"toBlock":14944982,"address":["0xa9ca155590671bbc01d7e1d95c0adec749e39cfc"],"topics":[["0x0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f"],null,null],"resultHash":"0x5c41998fe55464fe102d4ebd925729ddda4adc2a100f2efe81b9a20bacba6800"},{"fromBlock":15140544,"toBlock":17805709,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599"]],"resultHash":"0xf549a9667bea908e32dadbbb5b9ec49aa930070594a37196873197e45fed2450"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x357188f6d1d38581c197d16458ed5ec35ab6ad20182883cc516926fbece8f0f8"},{"fromBlock":11483430,"toBlock":14443237,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x707698a6608f9e42a6a7f2034e752711cb99f5bb3896028b4f99a954da2ba932"},{"fromBlock":13197619,"toBlock":17794010,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xcc1b88a7e3ff32d43ed2851300897d3e7b4812ed4acb7de7bf647152cf6187e6"},{"fromBlock":11843564,"toBlock":15208469,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"],["0x0000000000000000000000001592923d399fc2f6a7ee416e776d5158e6d13b25"]],"resultHash":"0xad2933999f3ffd801d7e90366268eb076541cb0c193afb529cc3dee62fac015a"},{"fromBlock":12570985,"toBlock":13178834,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000a47bb4f34298052048c4d7319686e23064eb22d9"]],"resultHash":"0xbb41dfd3c16c1bd9439df14b6552d0e60a68c945cc77e8bd005b5180c415c21a"},{"fromBlock":19008524,"toBlock":21894159,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09"],["0x000000000000000000000000f07c735011c311f55425bf8c534471a0410d85ad"]],"resultHash":"0x3d3ff215b3c05beb76c44c57b57411cc2c6d2e9b4916bdb6b1ed7c58e118f155"},{"fromBlock":14539343,"toBlock":17375669,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000a1006d0051a35b0000f961a8000000009ea8d2db"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0xfde2cdc3231fd4fefb0575021cee57332de9331e31e09034a877affe3ba6be8e"},{"fromBlock":13447111,"toBlock":17632175,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x2e67479e797761a5e9c6a9e2a5c6ba7772e352f59f93acbea7a57e17d03759aa"},{"fromBlock":11613954,"toBlock":14323073,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166"]],"resultHash":"0x1ad156a080eb3202e61c0c78b506e53454ae1fd081b58342f2ee218539bed43b"},{"fromBlock":13447111,"toBlock":17632175,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"],["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x2e67479e797761a5e9c6a9e2a5c6ba7772e352f59f93acbea7a57e17d03759aa"},{"fromBlock":10752826,"toBlock":17116195,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d1b430eb6f5de67cc2f2fccfa559b8db70d9d96d"]],"resultHash":"0x37c9f762a19a0faff3af5089f7b957c5d3b040de318ad50310f93be841e5f2a5"},{"fromBlock":5595291,"toBlock":7299424,"address":[],"topics":[null,["0x00000000000000000000000094d6faac6b98f58afd5da954e88c50d104381e58"]],"resultHash":"0x6ac7d17d2f8adbf0e04566a15f3f3ba51d04232137180ee027bb8bbbaf601fef"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xacbec158aec75fe8ce89950fa1b95acb231026a12d2a7ea68c1b74c7138fbbb4"},{"fromBlock":12561975,"toBlock":13425760,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa29e57325f90b58600f81fe96db5dcf6de848e4fa5e18f4340900dc95c26f551"},{"fromBlock":12439978,"toBlock":13665265,"address":["0xfffae206a0c17c4804f04af3880ff8a9dea39210"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x2d9b073f92783b63d78db520ed1831fb87e3afd6efbfa807a5fb7d64a23fe483"}],[{"fromBlock":13013858,"toBlock":13113462,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc3262efd06edb3c32e7006c509bf816af37c7e8af1da86f41cccf5e86b2bf975"},{"fromBlock":3592098,"toBlock":3785535,"address":["0x3ec225d0cd929148a1473c546c06dd1ee9f558b1"],"topics":[["0xe4c14a344e557cc7c4b7e0d1f6dff174b9a6ad4e51273606bd0c0d4bd6339303"]],"resultHash":"0xfdfcba6693fbb40f42ac0ac5aea584684844891300d657b7d96f3dec59e18b91"},{"fromBlock":15676332,"toBlock":15821080,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"]],"resultHash":"0x1ace94825f78066527e8e1cb6c41eeee287ab3ddaa1ecac939ca7cef5545e522"},{"fromBlock":3242464,"toBlock":3512214,"address":[],"topics":[null,null,["0x0000000000000000000000004bbd29b9c1dc5dc624db6c76364a38ab2a3c5f65"]],"resultHash":"0x179b2e151e09aa1242c71b59acde0a68b90a9219cb4938a3aed54ca4fd0ce72a"},{"fromBlock":15629719,"toBlock":15833314,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x50da69bb63aaacb497c6c115007dd47659ec0ef1e3738bc77014ca36694a1580"},{"fromBlock":12675039,"toBlock":13371963,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000269db91fc3c7fcc275c2e6f22e5552504512811c"]],"resultHash":"0x7285fff6c58a1893e70ef9661a9b92be6fd2b79ad4879fbfbf11e51cea0fe800"},{"fromBlock":7192208,"toBlock":7517625,"address":[],"topics":[null,null,["0x0000000000000000000000009c23d67aea7b95d80942e3836bcdf7e708a747c2"]],"resultHash":"0x113db6ba5f0394de52870e67cd9d07f3eb25d9cb4e293d2f19ddc791051fb934"},{"fromBlock":6890568,"toBlock":7178538,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000000a4b2"]],"resultHash":"0x5e6b9434369162e27f85420ceb15759077e30bec806daabc04505e1fb36e11cd"},{"fromBlock":12966340,"toBlock":13150792,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x40bf567ea120d29ed4fbc1a4d6bc54397819963fa1ec15a71900046dc22c6b78"},{"fromBlock":7490288,"toBlock":7623726,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"]],"resultHash":"0x4531de3c9cfa11ef696bdc8648dd11b1cf4907cc1f73da2f36a50b4c6dd5baf3"},{"fromBlock":19998377,"toBlock":20084984,"address":[],"topics":[["0x06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc82614677987"],null,["0x0000000000000000000000006cc5f688a315f3dc28a7781717a9a798a59fda7b"]],"resultHash":"0xd46800a63f304bf6c80b818c1dcff0b0d6aaa7f002eea1e94138c6106e3d3de4"},{"fromBlock":14826852,"toBlock":14989903,"address":[],"topics":[null,["0x00000000000000000000000063945489ef54398f3ccc8cb44f2a93ba1ac91ab8"]],"resultHash":"0x6545bec98bb9256069559aaf286b79d08184fac2da57f214ab6e35e184c6347e"},{"fromBlock":15629719,"toBlock":15833314,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x9cb72c5b3db7ad0f3310dcb5f46cf3519a1bb1a225dd2df558c2dd75d6b4b078"},{"fromBlock":13018033,"toBlock":13096839,"address":["0x36e2fcccc59e5747ff63a03ea2e5c0c2c14911e7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x9a1a33a4669b8951203f11d75bbd0000fb7265a027d4f39e34a3e019b66a2466"},{"fromBlock":13389791,"toBlock":13537791,"address":["0x938625591adb4e865b882377e2c965f9f9b85e34"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xb0afc68aba812a191d809b94676341f8eab963e79ef123ab7c479f86231c674a"},{"fromBlock":12949179,"toBlock":13127449,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x68cc14b1c3f79beafef4c6ac6422a5367b73fe20fe87131d4c9c0ebe934bb8a7"},{"fromBlock":15655918,"toBlock":16025322,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],["0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],null,["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xe687d7faae657c613f1ddb7c2a9c5f9c8e63894821fbb7a8941b6728867c2e2b"},{"fromBlock":16811448,"toBlock":16880089,"address":["0x172a9be5ea7f8602d6b9a97a914d23859053790a"],"topics":[["0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82"],["0x587d09fe5fa45354680537d38145a28b772971e0f293af3ee0c536fc919710fb"]],"resultHash":"0x90db29ce25bb5cfcd1d3ac860729b1a16500b888ab88f3eb79ffabba024d6a60"},{"fromBlock":18096540,"toBlock":18663712,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null,["0x000000000000000000000000000000000000000000000000000000000000119f"]],"resultHash":"0x579247db10d064d044bdbf36056255933f10700f15901174f9ba570eaf128403"},{"fromBlock":2877473,"toBlock":2991041,"address":["0xdd98b423dc61a756e1070de151b1485425505954"],"topics":[["0xa5acb022726d980b249ddc212f4992ad87f28c093550232fcc48bd8af803f2d5"]],"resultHash":"0x060ff3b139b9a4aaf555f07f15fb27943a49499280dfe571702828ea44159cf4"},{"fromBlock":19938072,"toBlock":20091951,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000a14afc841a2742cbd52587b705f00f322309580e"]],"resultHash":"0x70099f0d0024b485b3df9a3667d1cd7e5c2aaa81f80c1a1fb6f221798abc104b"},{"fromBlock":16825828,"toBlock":16874876,"address":["0x172a9be5ea7f8602d6b9a97a914d23859053790a"],"topics":[null,["0x587d09fe5fa45354680537d38145a28b772971e0f293af3ee0c536fc919710fb"]],"resultHash":"0xf22145447f128689c1fa37a9ada540905e58efd40cf483206604705d6ac2ad53"},{"fromBlock":13205541,"toBlock":13568469,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"]],"resultHash":"0xe1131c3427fb66d385bad543d1d588a01f24fb243affbaac121f45c892438d0b"},{"fromBlock":13293223,"toBlock":13544555,"address":["0x938625591adb4e865b882377e2c965f9f9b85e34"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x9ef0eef12a2c2290c6d1a9d2ee54c9bfa3e6cc8041d605da65f69604537a2f90"},{"fromBlock":15658364,"toBlock":15857114,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,null,["0x000000000000000000000000408e41876cccdc0f92210600ef50372656052a38"]],"resultHash":"0x0a5347cee4d95203809de7458c4b5ca3ded2959c3a39a2d2f4c0d5f0a882678c"},{"fromBlock":12773372,"toBlock":13168769,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000c558f600b34a5f69dd2f0d06cb8a88d829b7420a"]],"resultHash":"0x41aeba15a2d24ecdce0429961e5d534fb653079d59d062d21e0358d90c2e26b2"},{"fromBlock":12973850,"toBlock":13117324,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[null,["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xec71446c6b56d292f471bb7b364333fcf1705b9398e6bd0577fbb58bcae4487e"},{"fromBlock":12973850,"toBlock":13117324,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"]],"resultHash":"0xec71446c6b56d292f471bb7b364333fcf1705b9398e6bd0577fbb58bcae4487e"},{"fromBlock":19455242,"toBlock":19553399,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x00000000000000000000000091204649a5c9ab2cadfc2089fd22ed0fbfe170ed"]],"resultHash":"0x6b772a513221b5ca62d7a7ee13fe077b8456d0b7eb49880a1ea912b39918b23e"},{"fromBlock":12912181,"toBlock":13133628,"address":["0x0652687e87a4b8b5370b05bc298ff00d205d9b5f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x3d00f162e30f7646ed4b39162e6b6e614cc5052703cdcd79fde3a1bef46cb82b"},{"fromBlock":20681638,"toBlock":20940363,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000004d32c8ff2facc771ec7efc70d6a8468bc30c26bf"]],"resultHash":"0x3cabc02900fa78bacfd06aead13e14e4abb976ecbbeeb3aff08c4690472d0b77"},{"fromBlock":16827035,"toBlock":16872886,"address":["0x172a9be5ea7f8602d6b9a97a914d23859053790a"],"topics":[["0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82"]],"resultHash":"0x758ab2ecf3a34e671536314beac5968f677c29e59f92230a74fcf41308c42de8"},{"fromBlock":15605613,"toBlock":15940652,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0xa906dc84e3eee39216d0de2ed0c1651a39885287433043064dc0d22577c647f5"},{"fromBlock":20681638,"toBlock":20940363,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000004d32c8ff2facc771ec7efc70d6a8468bc30c26bf"]],"resultHash":"0x3cabc02900fa78bacfd06aead13e14e4abb976ecbbeeb3aff08c4690472d0b77"},{"fromBlock":12586181,"toBlock":13192054,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d45afa3649e57a961c001b935ded1c79d81a9d23"]],"resultHash":"0x368749deff2b9056533cef64117d094fd49994165ed5718bfd19897625189e3e"},{"fromBlock":13000947,"toBlock":13088151,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x000000000000000000000000cc00b641305c639d9f2b3c34067c69679ee1dbef"]],"resultHash":"0x34d3292906682b46318c5093fc86b8101f9cac117fe27585b52430c5d9a53b74"},{"fromBlock":12964363,"toBlock":13152994,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x3d9ef32e9661d92456648a4d0114ebd88c5972db790b5e4cfbeacd5c808ab5b8"},{"fromBlock":11586188,"toBlock":11762313,"address":["0xc5fa164247d2f8d68804139457146efbde8370f6"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x264cb155e867786f4bfc963e689f7b0ecf322434c146072cdd995c3bf8fa49f5"},{"fromBlock":19938072,"toBlock":20091951,"address":[],"topics":[null,["0x000000000000000000000000a14afc841a2742cbd52587b705f00f322309580e"]],"resultHash":"0x70099f0d0024b485b3df9a3667d1cd7e5c2aaa81f80c1a1fb6f221798abc104b"},{"fromBlock":15044857,"toBlock":15312899,"address":[],"topics":[null,["0x000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8"],["0x000000000000000000000000acd4ec996aad815efe72a11944188c6db6c30176"]],"resultHash":"0x8bf07e8ea2642c43ddce728ba5956a2abc6c6dd2494729c14e7c4ed0493f6829"},{"fromBlock":14050024,"toBlock":14396266,"address":["0xa9ca155590671bbc01d7e1d95c0adec749e39cfc"],"topics":[null,null,null],"resultHash":"0xa36b883e8c1c247bcd58a2e4a59c1502033406c3709e00bd3737f0be1c79908f"},{"fromBlock":12965510,"toBlock":13125998,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x517127e38c31299fc1effb132b9b6d5e2f72ee8d6b5d7772c1c7293a87d21dc6"},{"fromBlock":12703765,"toBlock":13242375,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0xef5d997667ef71e2f2ef6f9ed80bdb3b5f748336264c32532a5535d737aa4ca1"},{"fromBlock":12675039,"toBlock":13371963,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000269db91fc3c7fcc275c2e6f22e5552504512811c"]],"resultHash":"0x7285fff6c58a1893e70ef9661a9b92be6fd2b79ad4879fbfbf11e51cea0fe800"},{"fromBlock":15596730,"toBlock":15841600,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"]],"resultHash":"0x1d5e46b3f2cc10a43cc876950f64d76afdd91dd0bab4bf269f4d4967abdefe15"},{"fromBlock":15564631,"toBlock":15835055,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x97b337102d12ed4cd07c2d8284748792674619f0a58de6b26104569613d90795"},{"fromBlock":12988157,"toBlock":13081677,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000058dc5a51fe44589beb22e8ce67720b5bc5378009"]],"resultHash":"0x8018c937ff7881876a7048883d9ef90979213359892f86588b05ed0e42b255e0"},{"fromBlock":19815654,"toBlock":20144291,"address":["0x84ca8bc7997272c7cfb4d0cd3d55cd942b3c9419"],"topics":[null,["0x000000000000000000000000a14afc841a2742cbd52587b705f00f322309580e"]],"resultHash":"0xcb2af12f0cbdafc9ed0bff95d479559b4e47d1bf5f5c0fefb6b91b7268ffc322"},{"fromBlock":12867265,"toBlock":13203590,"address":["0x382c4a5147fd4090f7be3a9ff398f95638f5d39e"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x00000000000000000000000092f1ff14a80ea8c23028a40c74c05bb994ea0ee2"]],"resultHash":"0x1462001baeaa24756154df15d48c1400346df7c7162e4585927623087df29c8b"},{"fromBlock":2859119,"toBlock":3034125,"address":["0xd86c6f0bb961e83c1ea30e8ab9d5cc291952ec08"],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000058"]],"resultHash":"0xe777e2ec0b7d432248252e275e6fea7ce4d9a0243f1760869d0ee3969cbe659c"},{"fromBlock":12687449,"toBlock":13175995,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d45afa3649e57a961c001b935ded1c79d81a9d23"]],"resultHash":"0xf4c33a309beb45143ea0e343994947f874e0ffa9fa627990c8563fef929bba5d"},{"fromBlock":12679577,"toBlock":13184107,"address":[],"topics":[null,null,["0x0000000000000000000000004abcca8fcf84cb0aa1431c36740a213da7aa838c"]],"resultHash":"0xeea580ea214192680928dcf8a9b08b81cf8834a4a602463e09fae890ad04bbe7"},{"fromBlock":3197122,"toBlock":3572860,"address":["0xedbaf3c5100302dcdda53269322f3730b1f0416d"],"topics":[null,null,["0x0000000000000000000000004bbd29b9c1dc5dc624db6c76364a38ab2a3c5f65"]],"resultHash":"0xca122bee2eb91a266ecb9db66daaef6e15cc320102890e54478fbcdb690cf33c"},{"fromBlock":12927803,"toBlock":13177392,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000aaf5110db6e744ff70fb339de037b990a20bdace"]],"resultHash":"0xc44184392902f5a31f6a40c157cbfc51f814699e8a3c4193dc9b5563c61702d8"},{"fromBlock":12834996,"toBlock":12879291,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000fe7444f63e0010a7208529608eb173760629483b"]],"resultHash":"0xa5ea3613aad74e5ad37e170ff6b87adb2775b93a36fb6957974792d159a079e2"},{"fromBlock":20606236,"toBlock":21110666,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000f007476bb27430795138c511f18f821e8d1e5ee2"]],"resultHash":"0x2ab367e389cc0d37444e6abdb3d46ac9de7b54c64ed07dd3f2de9fdd53ba7b5b"},{"fromBlock":12927795,"toBlock":13232141,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000a47bb4f34298052048c4d7319686e23064eb22d9"]],"resultHash":"0xa32e7d9f4a24a3fc4d1cf22d78fc91f71cfba5a309bb65454da5a896d5431273"},{"fromBlock":15586016,"toBlock":15834006,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x073fe755551f7e62a4b5413998c66370e55024b82682ccfa46ae7687017e4d92"},{"fromBlock":12903065,"toBlock":13315124,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x00000000000000000000000080eac0b5954d861849824e21dba32c3b3b90ef96"]],"resultHash":"0x8932c0c239b1dc4e14cc4b1358a9bf99fbb63ddedb86d4574f2f02906a5345a8"},{"fromBlock":14403971,"toBlock":14633596,"address":["0x63b4f3e3fa4e438698ce330e365e831f7ccd1ef4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0xf6691709c661cd1291e335556c7557d88d03f69e1d9a485b52ffac7c1c1ee928"},{"fromBlock":20681638,"toBlock":20940363,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000004d32c8ff2facc771ec7efc70d6a8468bc30c26bf"]],"resultHash":"0x3cabc02900fa78bacfd06aead13e14e4abb976ecbbeeb3aff08c4690472d0b77"},{"fromBlock":12965114,"toBlock":13053499,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000005d2dd39191196d764c6fd33dc488caf13af482ac"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x5eab660e93e659679760acaebca360722713abc70da4e12d47284e3a09e877dc"},{"fromBlock":12966340,"toBlock":13150792,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"]],"resultHash":"0x40bf567ea120d29ed4fbc1a4d6bc54397819963fa1ec15a71900046dc22c6b78"},{"fromBlock":13358986,"toBlock":13564064,"address":["0x938625591adb4e865b882377e2c965f9f9b85e34"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x17535d588a530d8f7fd03684f3e6f29090f31d7b00311f569a106ae7112e91a4"},{"fromBlock":12936450,"toBlock":13220573,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e"],"topics":[["0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x9b56935c7a19659268eec06040332677fa5cc64229a2de3356b3a4731ccc1326"},{"fromBlock":12944620,"toBlock":13145113,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000a47bb4f34298052048c4d7319686e23064eb22d9"]],"resultHash":"0xe9f2b6cdc69cf8a7225d850fb041787f8e5756fb4cc452c323b6df3c4dcaac4c"},{"fromBlock":19938072,"toBlock":20091951,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000a14afc841a2742cbd52587b705f00f322309580e"]],"resultHash":"0x70099f0d0024b485b3df9a3667d1cd7e5c2aaa81f80c1a1fb6f221798abc104b"},{"fromBlock":15596730,"toBlock":15841600,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x88c595f6740afcc10e9f05da22aa9e6cf991b473f3da69c68a6bd2d60cc90579"},{"fromBlock":18276024,"toBlock":18455497,"address":[],"topics":[null,null,null,["0x000000000000000000000000000000000000000000000000000000000000120d"]],"resultHash":"0xe1d91587a9f84fc8b8d7d14cb12e4735159583e43136570704ceb04274ab9ab2"},{"fromBlock":14469463,"toBlock":14766966,"address":["0xe6f51e892046cb5b437e0033d990b527ea4367c8"],"topics":[null,null],"resultHash":"0xd8ad1547885e8a4c71e80a00e337cc6d58c59874b6527b913ac23aaeb5785526"},{"fromBlock":13004161,"toBlock":13078129,"address":["0x0e26a21013f2f8c0362cfae608b4e69a249d5efc"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x98a70e2a2b6f92df10ff562f70f7206d98266a2a41f91b4e2470df728e2febf0"},{"fromBlock":12687449,"toBlock":13175995,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d45afa3649e57a961c001b935ded1c79d81a9d23"]],"resultHash":"0xf4c33a309beb45143ea0e343994947f874e0ffa9fa627990c8563fef929bba5d"},{"fromBlock":20021263,"toBlock":20064223,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000be8bc29765e11894f803906ee1055a344fdf2511"],["0x00000000000000000000000073a8a6f5d9762ea5f1de193ec19cdf476c7e86b1","0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x6320f9a3b69f08455be3ec2b8eb3093b500e3f6827eb1d459cae3fc55c3726e8"},{"fromBlock":12939128,"toBlock":13144428,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000755560f094b26e0e0a39a1dd7e47a3c4788830ec"]],"resultHash":"0x9f7dde4a192ec76fb10b2cc87426bed87a0a92ad7bece1280a2aae602c5c3568"},{"fromBlock":20606236,"toBlock":21110666,"address":["0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000f007476bb27430795138c511f18f821e8d1e5ee2"]],"resultHash":"0x2ab367e389cc0d37444e6abdb3d46ac9de7b54c64ed07dd3f2de9fdd53ba7b5b"},{"fromBlock":12989365,"toBlock":13110467,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[null,null,["0x0000000000000000000000008d06afd8e322d39ebaba6dd98f17a0ae81c875b8"]],"resultHash":"0x446493321bd81d28b7b9a5290b4247032414d856cc034d181b05fac04d68c1df"},{"fromBlock":16639846,"toBlock":16777984,"address":["0x819f3450da6f110ba6ea52195b3beafa246062de"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d"]],"resultHash":"0x4712ec30762d4f2297d935c209b6cea67a93d6db9e5444ed925736b163dcde22"},{"fromBlock":12973850,"toBlock":13117324,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xec71446c6b56d292f471bb7b364333fcf1705b9398e6bd0577fbb58bcae4487e"},{"fromBlock":12741126,"toBlock":13145414,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000737aad349312f36b43041737d648051a39f146e8"]],"resultHash":"0xd15b065f48375cfad97d719ebf53acf9d6860ebb498178b005e4e0ed0d3db791"},{"fromBlock":12941672,"toBlock":13096804,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d75ea151a61d06868e31f8988d28dfe5e9df57b4"]],"resultHash":"0x53fb6e5d0cb0f943b906d9b007ce9e0b2b7a2aef25a561d5076f24544fa92f0d"},{"fromBlock":12960594,"toBlock":13096642,"address":["0x795065dcc9f64b5614c407a6efdc400da6221fb0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000036e2fcccc59e5747ff63a03ea2e5c0c2c14911e7"]],"resultHash":"0x414a095ca51c774bc0234e3f5df457b21422535d70dad5083dd7d7a00d9b52df"},{"fromBlock":13389791,"toBlock":13537791,"address":["0x938625591adb4e865b882377e2c965f9f9b85e34"],"topics":[null,null,["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x19b965b7dc4d92e223a139466aa28843f5e9185d873d91f814eaf2d471aed9fe"},{"fromBlock":12908991,"toBlock":13094283,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x6fe8527a1928ae757b4c482b4639b8be53599afd91c402b6203ecfa382ffa060"},{"fromBlock":12973850,"toBlock":13117324,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xec71446c6b56d292f471bb7b364333fcf1705b9398e6bd0577fbb58bcae4487e"},{"fromBlock":12741126,"toBlock":13145414,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000737aad349312f36b43041737d648051a39f146e8"]],"resultHash":"0xd15b065f48375cfad97d719ebf53acf9d6860ebb498178b005e4e0ed0d3db791"},{"fromBlock":12903065,"toBlock":13315124,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x00000000000000000000000080eac0b5954d861849824e21dba32c3b3b90ef96"]],"resultHash":"0x8932c0c239b1dc4e14cc4b1358a9bf99fbb63ddedb86d4574f2f02906a5345a8"},{"fromBlock":14069853,"toBlock":14290125,"address":["0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000004a137fd5e7a256ef08a7de531a17d0be0cc7b6b6"],["0x0000000000000000000000004585fe77225b41b697c938b018e2ac67ac5a20c0"]],"resultHash":"0x991b06079cfe3bf914dad7458001b0c76d5279cc3f363849b1d6222ca56f7a5d"},{"fromBlock":12973850,"toBlock":13117324,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000002f87b1fca1769bc3361700078e1985b2dc0f1142"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xec71446c6b56d292f471bb7b364333fcf1705b9398e6bd0577fbb58bcae4487e"},{"fromBlock":13015734,"toBlock":13591503,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000008534b5e068e1adb57cfe44554f4e65c914603f8a"]],"resultHash":"0x92aa70b5d1b8dbef91f03848c795265eca00be95b0716da155d162128b76b9d6"},{"fromBlock":12123204,"toBlock":12246035,"address":["0x7cc768b882be41ca03f9daccfc48b8bd6d25eb25"],"topics":[],"resultHash":"0xb8e617f3c3d8460fc92f1cca19681909f097847bb81233f0e874a5cb6d052569"},{"fromBlock":11611354,"toBlock":11704218,"address":["0xc40d16476380e4037e6b1a2594caf6a6cc8da967"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006de2b77d89759c1275b99175494e29299f845cbc"]],"resultHash":"0x3ff37bb7bb743d7084f66621305470ecaca7189c5d48b23121578f320a32e8be"},{"fromBlock":12988157,"toBlock":13081677,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000058dc5a51fe44589beb22e8ce67720b5bc5378009"]],"resultHash":"0x8018c937ff7881876a7048883d9ef90979213359892f86588b05ed0e42b255e0"},{"fromBlock":14600142,"toBlock":15053424,"address":[],"topics":[null,["0x000000000000000000000000dc0d08c6bc98ecdf176941de7517018f613e8977"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xb1e677df65ee7770ead7064da3a55fcd7596f700bb1572da084ef1d3a174d9f0"},{"fromBlock":12977496,"toBlock":13066009,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000877d9c970b8b5501e95967fe845b7293f63e72f7"]],"resultHash":"0xc55ffc3ee5d9ef4f91fd3bfecc464f91feca8ff232b04cb7e72cc478afbce856"},{"fromBlock":6026548,"toBlock":6159932,"address":["0xdd9fd6b6f8f7ea932997992bbe67eabb3e316f3c"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000c9d"],null],"resultHash":"0xb01029650bbece654875b35f93370e833c6c80cd0bfcfbd66d55180c74287af3"},{"fromBlock":12964360,"toBlock":13051552,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8a1a865e4405281311c5bc0f90c240498472d3e"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x4fa0cdd9e5b59806f1b1df5842eeb648969efbb1275f33e9d28c3366fc05d1e8"},{"fromBlock":15571414,"toBlock":15893654,"address":["0x49ff149d649769033d43783e7456f626862cd160"],"topics":[null,null,["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x09a03d949ce9eb97222a827c27184d072825439c0d475b805989ae240d1c99a5"},{"fromBlock":12922929,"toBlock":13123768,"address":["0x8f9ef75cd6e610dd8acf8611c344573032fb9c3d"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xffd66882c51220b404536710d128f7fd6812c75ef8c212522d85b6c3fa181ddf"},{"fromBlock":6026548,"toBlock":6159932,"address":["0xdd9fd6b6f8f7ea932997992bbe67eabb3e316f3c"],"topics":[["0x590bbc0fc16915a85269a48f74783c39842b7ae9eceb7c295c95dbe8b3ec7331"],["0x0000000000000000000000000000000000000000000000000000000000000c9d"],null],"resultHash":"0xd940e6c45b744dba009307c4f7adfb00754e84bc1214c0b9c6f462e11a1ad494"},{"fromBlock":12872992,"toBlock":13223367,"address":["0x9a632cd9cb44f9383bf6f3117056c2455b30a6e0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"],["0x000000000000000000000000e66b31678d6c16e9ebf358268a790b763c133750"]],"resultHash":"0x06612a12f530d4dc4d728cc9219fc4e27f80d3cfe49a8675ca226b64f689c4c5"}],[{"fromBlock":19121905,"toBlock":19156222,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b0aac1f129651e62cde6d1ae683c8a49f4d004d1"],["0x0000000000000000000000005c7bcd6e7de5423a257d81b442095a1a6ced35c5"]],"resultHash":"0xd0e87456d5ff56889e5069d23b5ceac692a24480e19facf43c1b0b972f84bd9b"},{"fromBlock":13029262,"toBlock":13061696,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x3e052c340e5836cacb1fe9c3ad374d4c1ecf2df3e16170237796e8a7111b29ee"},{"fromBlock":13036999,"toBlock":13044083,"address":["0x20e95253e54490d8d30ea41574b24f741ee70201"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0xda0488ddba3de247251589c1134bfa7b250ece47cae4fe19f5f397cd641869ed"},{"fromBlock":14186651,"toBlock":14198096,"address":["0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"],"topics":[null,null,["0x0000000000000000000000004585fe77225b41b697c938b018e2ac67ac5a20c0"]],"resultHash":"0x903b83930040c7d56c97bae7619dadeb210624d31dc7b4bc070febb6c6f93f84"},{"fromBlock":13029262,"toBlock":13061696,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x5f900a7ca43e9a977d19f8207bf4e5ff6aab75ee457d89ed7d1a23bb4d2dcfbc"},{"fromBlock":19121905,"toBlock":19156222,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b0aac1f129651e62cde6d1ae683c8a49f4d004d1"]],"resultHash":"0xd0e87456d5ff56889e5069d23b5ceac692a24480e19facf43c1b0b972f84bd9b"},{"fromBlock":13028679,"toBlock":13059548,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x9ea193a41d45fbf094e442a47fae7b0187116ae93f98767104ca1854e68de3bf"},{"fromBlock":13028679,"toBlock":13059548,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x3493bedfb19b13a38dde7269fd52b96a985375eaf5b8fded4930e048143f5a92"},{"fromBlock":13028679,"toBlock":13059548,"address":["0xb5de0c3753b6e1b4dba616db82767f17513e6d4e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x3493bedfb19b13a38dde7269fd52b96a985375eaf5b8fded4930e048143f5a92"},{"fromBlock":13031256,"toBlock":13054552,"address":["0x6fcc7db7acbc3e9dde3ee7d96cb61fc9c0ca17a7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x45e175c2376de02eb7ba7c2001d23311e2ac49c5ceb3e53ff2c7bb00f5f40b06"},{"fromBlock":13009113,"toBlock":13073242,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000036e2fcccc59e5747ff63a03ea2e5c0c2c14911e7"]],"resultHash":"0xe53fa3fc30a4a5a0e3d2e5c9b70f432c49f395c79fe7edde49f9bcd9333ec44f"},{"fromBlock":13022581,"toBlock":13058593,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000000c365789dbbb94a29f8720dc465554c587e897db"]],"resultHash":"0xaaef421eaac897f367bf848077689a6be509ff8a46326c1de260bfe4a8f970c9"},{"fromBlock":11661635,"toBlock":11668358,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006de2b77d89759c1275b99175494e29299f845cbc"]],"resultHash":"0x0d92bbe3abb7b8f3e6f2d565417088ad0705774569b8ee4678f1601d2c304154"},{"fromBlock":13028961,"toBlock":13061694,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e78388b4ce79068e89bf8aa7f218ef6b9ab0e9d0"]],"resultHash":"0x5fde0bf4fef34f4d78531c56974be71d1a6d291a689927bbecd1fd181da3c1f0"},{"fromBlock":13033534,"toBlock":13044454,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x8b16a4f116db806d970f2209ff35b77c142f361c15f579e64ca6116cfff09864"},{"fromBlock":13023879,"toBlock":13050945,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x942ecff5692339d92febc5d38274fea1cf284999d369ad9cef6235114cf9ff02"},{"fromBlock":20797153,"toBlock":20803970,"address":["0xae7ab96520de3a18e5e111b5eaab095312d7fe84"],"topics":[["0x9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"]],"resultHash":"0xb85cc8673fc4a60d523541ed4defc762d3b6eb0048b474f9301e14748b77d096"},{"fromBlock":14215997,"toBlock":14245382,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000039f6a6c85d39d5abad8a398310c52e7c374f2ba3"]],"resultHash":"0xfbd3c2670eac930ad8603beed4d4943f15be27fe3fea0c3a282ada995e4cb178"},{"fromBlock":14218528,"toBlock":14273522,"address":["0xba12222222228d8ba445958a75a0704d566bf2c8"],"topics":[null,["0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014"],["0x000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d","0x00000000000000000000000043c7d0e58d8644c6d65d5d536bb6bd59bdac7ea3"],["0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]],"resultHash":"0x3d3ede56f08696bfbea7624559e462a17dc79faf3e62711dbf19a3138bd3487d"},{"fromBlock":20036412,"toBlock":20053415,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e"]],"resultHash":"0x02737356cea6de2a8580ca60346c5f6164b12038624872bd318a9d4f1b2acf46"},{"fromBlock":20032287,"toBlock":20050541,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e"]],"resultHash":"0x9408d31d60a4fb645bc00f0aa0b93772c767e98e3e3b4527755de51cc80f326c"},{"fromBlock":13015047,"toBlock":13056502,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x06cb2cfd2b5b134d096c1279387ccf1c3a6f216947106d59f76e248dabed0f77"},{"fromBlock":15998174,"toBlock":16004186,"address":["0x94693c9e342f759272d6f7b481703df8e83b1818"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x40e0aded7640410a863f7048dd4aaf87fb3181c227c55ff04aef89ff4dc7e34e"},{"fromBlock":20036412,"toBlock":20053415,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e"]],"resultHash":"0x02737356cea6de2a8580ca60346c5f6164b12038624872bd318a9d4f1b2acf46"},{"fromBlock":5347095,"toBlock":5373390,"address":["0xcdaf9abed7c74b3c5abba6c168bab8fa8539c892"],"topics":[],"resultHash":"0x03a26a1f756112626f943d13ea9d50b043b2da3a17badf016608537beb92ff71"},{"fromBlock":13015047,"toBlock":13056502,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x06cb2cfd2b5b134d096c1279387ccf1c3a6f216947106d59f76e248dabed0f77"},{"fromBlock":13035729,"toBlock":13044465,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x00000000000000000000000034d7d7aaf50ad4944b70b320acb24c95fa2def7c"]],"resultHash":"0x51b699b4f24544ed72c1dba81edf55c6914a2cb7a7b35c6badc501d7e97be077"},{"fromBlock":13015841,"toBlock":13056651,"address":["0x877d9c970b8b5501e95967fe845b7293f63e72f7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x5e83c35594977f86546933b5178026be47b8d1be5e8e0e53ab62be4ed55c10b0"},{"fromBlock":20037416,"toBlock":20052857,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x000000000000000000000000f621fb08bbe51af70e7e0f4ea63496894166ff7f"]],"resultHash":"0x2a6bf2cf03754a3e7c15e014097dce32574345d5a0b5c0311edbe04e4279e603"},{"fromBlock":13014827,"toBlock":13052515,"address":["0x0e26a21013f2f8c0362cfae608b4e69a249d5efc"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x64fcab7747a7010a7f60a23f256d0e088f1fe178381bab81f5312bed49796efb"},{"fromBlock":10542443,"toBlock":10562098,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508","0x398ec7346dcd622edc5ae82352f02be94c62d119"],"topics":[null,["0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x18fa1e53203f344096f9b03f4609014b913e18f8b544e84c186b8ce38de6fb9e"},{"fromBlock":14044736,"toBlock":14111521,"address":["0x328dfd0139e26cb0fef7b0742b49b0fe4325f821"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000f2f400c138f9fb900576263af0bc7fcde2b1b8a8"],null],"resultHash":"0x86a247cf2041acf5c45306f3d6ee99dab2d8ca1179a6eb97d35a1622ec78f777"},{"fromBlock":3778450,"toBlock":3826264,"address":[],"topics":[["0x7d19c7776f05049226f581a23a4df896c65115763d8ec30490658efc4e8649cd"]],"resultHash":"0xe14a8f781ceae515595fe0f1f9dbf04ed441bac50b670a64ff31fdd2b0d4a3c0"},{"fromBlock":14222848,"toBlock":14229178,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000881d40237659c251811cec9c364ef91dc08d300c"]],"resultHash":"0x977472abbba5ed462de0461b34c8478d0b70259c4058c35aa1e6246a35121207"},{"fromBlock":5326722,"toBlock":5373355,"address":["0xcdaf9abed7c74b3c5abba6c168bab8fa8539c892"],"topics":[["0xbfbb2c004ee5852a056aab3d9e02f42f824fb466821c4ebee60ef24939b8fb5c"]],"resultHash":"0x2e604941a4924d72eeae7b3913bed642ba88e3d442c1b5313c7de6e41b1931f0"},{"fromBlock":13028275,"toBlock":13039896,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x9b23b50ce20903f344f5e739bd942138c46f059b822219cac77ffa1fec27cdab"},{"fromBlock":13025470,"toBlock":13041929,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x1979c6978dda79035db83d1ddbc6db32c944596512b5b9854d598c761a702a12"},{"fromBlock":13031494,"toBlock":13046760,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000088ee5007c98a9677165d78dd2109ae4a3d04d0c"]],"resultHash":"0xe34b9ec1fa8b92c2c3ce39db0a865f378b4046ab945086f156222aa25b1faf63"},{"fromBlock":20155716,"toBlock":20164497,"address":["0x95d9a1a365f01ffce582fc1d6732bb5cbf502359"],"topics":[],"resultHash":"0xf3cd5c20dfedfa11d171ffad5afbdce1dd6e0efc86dd2a95e0faf28bf1757c5e"},{"fromBlock":13033469,"toBlock":13044614,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xdbe602ef0b9158659ed92ffeb65e41d3e7ea2ad02f3fd3476351b0816a546f98"},{"fromBlock":5326722,"toBlock":5373355,"address":["0xcdaf9abed7c74b3c5abba6c168bab8fa8539c892"],"topics":[["0xbfbb2c004ee5852a056aab3d9e02f42f824fb466821c4ebee60ef24939b8fb5c"]],"resultHash":"0x2e604941a4924d72eeae7b3913bed642ba88e3d442c1b5313c7de6e41b1931f0"},{"fromBlock":16827938,"toBlock":16874720,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[null,null,["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xfc498ceb56bf4b8e5c9a633363f1666b9d124ce4a4bd8d7fcad82098f0787cc9"},{"fromBlock":14520453,"toBlock":14528688,"address":["0x2acae338d313be9505736fc262a1cc2f95832ede"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0x52fa9a5c00c40770f74e2a3096a2ea8fa328ce0b301f347bca9770e315504507"},{"fromBlock":13020352,"toBlock":13057437,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000c558f600b34a5f69dd2f0d06cb8a88d829b7420a"]],"resultHash":"0x3c0046adae57d36fc2fde5743ab4a19f958406b8bb7e289272b09d064fcf7a0b"},{"fromBlock":5326722,"toBlock":5373355,"address":["0xcdaf9abed7c74b3c5abba6c168bab8fa8539c892"],"topics":[["0xbfbb2c004ee5852a056aab3d9e02f42f824fb466821c4ebee60ef24939b8fb5c"]],"resultHash":"0x2e604941a4924d72eeae7b3913bed642ba88e3d442c1b5313c7de6e41b1931f0"},{"fromBlock":13035729,"toBlock":13044465,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000034d7d7aaf50ad4944b70b320acb24c95fa2def7c"]],"resultHash":"0x4135bfc089556eb827cd99eb59d5d8d3ff273cd5d478b0bb214ebc69712cf1de"},{"fromBlock":12971230,"toBlock":12989649,"address":["0x5b272ce3e225b019a3fbd968206824b24c674344"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xdd3403d76de432cf133aaabf13e666d0ce00ea63b0b328096f65765795001889"},{"fromBlock":14222848,"toBlock":14229178,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,["0x000000000000000000000000881d40237659c251811cec9c364ef91dc08d300c"]],"resultHash":"0x977472abbba5ed462de0461b34c8478d0b70259c4058c35aa1e6246a35121207"},{"fromBlock":13027015,"toBlock":13053541,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000018c0ca3947e255881f94de50b3a906fc2759f7fe"],["0x00000000000000000000000018c0ca3947e255881f94de50b3a906fc2759f7fe"]],"resultHash":"0x404085839e589fc1d95b993b6257ec1efcf0d48ed36d3c45f25e349bed478c3c"},{"fromBlock":13036980,"toBlock":13043285,"address":[],"topics":[["0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x08ede5f9ef7ec4e89c604d2e37a82f5b7792868acbd38ca84904f52a9ce438d0"},{"fromBlock":13026628,"toBlock":13048002,"address":[],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000058dc5a51fe44589beb22e8ce67720b5bc5378009"]],"resultHash":"0x82d85900117034d4bb135339a1890074e2d5b5998f686fb48646c07a781fa624"},{"fromBlock":20039359,"toBlock":20052699,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e"]],"resultHash":"0xcddebb593e1ea60a3d8b8fac5aca10835824b6ae01a30182e768521b24425dd2"},{"fromBlock":16827938,"toBlock":16874720,"address":["0xd9d27decffa31c061bf3ae0a92689ed02f973d5e"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],null,["0x0000000000000000000000001b425529c9d7472603e2dcf125fd195f71dfb412"]],"resultHash":"0xfc498ceb56bf4b8e5c9a633363f1666b9d124ce4a4bd8d7fcad82098f0787cc9"},{"fromBlock":13052213,"toBlock":13067980,"address":["0x99b42f2b49c395d2a77d973f6009abb5d67da343"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xd476bbbe819ea35e60b3e27617146a2bdf467b5140106e03fb51093a27774579"},{"fromBlock":20037236,"toBlock":20048327,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x000000000000000000000000f621fb08bbe51af70e7e0f4ea63496894166ff7f"]],"resultHash":"0xfa3f4d877fc605e893e30b5206855cd579b4147ac213a01db39a3941508be542"},{"fromBlock":13014399,"toBlock":13049195,"address":["0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xcece652f92fc21ccadb5eb62afb20c01004cacc1b10ce52633817f7140d2a55d"},{"fromBlock":13033183,"toBlock":13042385,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x61fa2f4109615a2b7950b0346230b54165054f74656c6ddbfc2566f11ee9b970"},{"fromBlock":7464086,"toBlock":7480785,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000000681e844593a051e2882ec897ecd5444efe19ff2"]],"resultHash":"0xcb67fece631a88a9fec2ff44802244d9962895dc3d3bc4168ba80bb5b155cfec"},{"fromBlock":13033370,"toBlock":13044044,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000034d7d7aaf50ad4944b70b320acb24c95fa2def7c"]],"resultHash":"0xb4459c61c2f6c8b84c0f057f06c1330c04015817af26b649b47aa3bc65fdf135"},{"fromBlock":13028923,"toBlock":13061943,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e78388b4ce79068e89bf8aa7f218ef6b9ab0e9d0"]],"resultHash":"0x65a2249ce337625e3a9435cc731aa68f0f773db17643f2b9bebfe5d7ac3215fc"},{"fromBlock":13048703,"toBlock":13056584,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x3707ea7c55f9d17d2ce96f5cc598ff02d4be2fa0157639dfb923334c73b3e13a"},{"fromBlock":13004094,"toBlock":13067449,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000c3d03e4f041fd4cd388c549ee2a29a9e5075882f"]],"resultHash":"0x266dc8633baa44374a1e5191843c897df6d7e86c1cc529f7e40e154b27fcad5c"},{"fromBlock":12371909,"toBlock":12434428,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x000000000000000000000000c7a1cb6edc22e94f17c80eb5b959f2ad28511d4e"]],"resultHash":"0x9e2ff5d913fe4d8aebad11d6d863e49c667d78e6774d646cba3f15f55d6f1245"},{"fromBlock":13018352,"toBlock":13064803,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"],["0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"]],"resultHash":"0x623e351f75a5a2a8afcf29cbfd24da2b777a95214cafefd23c616ef28c1839a8"},{"fromBlock":13048703,"toBlock":13056584,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x3707ea7c55f9d17d2ce96f5cc598ff02d4be2fa0157639dfb923334c73b3e13a"},{"fromBlock":13035476,"toBlock":13046867,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x71f9559a2bc8fc8333ef06eab3f11a677f8ee27de1668761b0699b6ccacf4ac8"},{"fromBlock":3532918,"toBlock":3540688,"address":["0x4b9e0d224dabcc96191cace2d367a8d8b75c9c81"],"topics":[],"resultHash":"0x13a9c1fce7f326993a54bccc279fac9c6705af22554e3f432a57db9240582ece"},{"fromBlock":7587153,"toBlock":7616049,"address":["0x744d70fdbe2ba4cf95131626614a1763df805b9e"],"topics":[null,null,["0x000000000000000000000000650007a41dc5477a000de8fb3ae44617c7517e3c"]],"resultHash":"0x4de91b17739fa57497dccd7c91e3296114aa9d150e7ecb9cd1c6106c40f97642"},{"fromBlock":20027213,"toBlock":20053955,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x000000000000000000000000c64350c0eab6faed8f17cc2cdff0761c53fb4152"]],"resultHash":"0x96ebc6b52d2cf5fbd51e26af733f984556ff922529aca2ba5eac7fbb3d716302"},{"fromBlock":11657142,"toBlock":11667192,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc16c851913f9c79a1bbd64e423f911d3d0cc5510145d6bab4a72a1b6b1159bab"},{"fromBlock":13029262,"toBlock":13061696,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x5f900a7ca43e9a977d19f8207bf4e5ff6aab75ee457d89ed7d1a23bb4d2dcfbc"},{"fromBlock":10549083,"toBlock":10560254,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508","0x398ec7346dcd622edc5ae82352f02be94c62d119"],"topics":[null,["0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"]],"resultHash":"0x8d315d40221556933f0ad1c9b130df873914f3bebfc05fd7f68924e8c210ecdc"},{"fromBlock":11328274,"toBlock":11387318,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000004b6baeb330334a6b2d5ef08a834751c35c49080b"]],"resultHash":"0x6ce07937b0309f457af59fa13ffb8969a0ce84218b76d2c5aec98c878638f031"},{"fromBlock":9905767,"toBlock":9965462,"address":["0x5d3a536e4d6dbd6114cc1ead35777bab948e3643"],"topics":[null,["0x00000000000000000000000000000000001876eb1444c986fd502e618c587430"]],"resultHash":"0x81da576d67d2baa57ca71c82824ae09bd69890c5620fc99d7ff0c4ca755d3685"},{"fromBlock":13033569,"toBlock":13043965,"address":["0xff64cb7ba5717a10dabc4be3a41acd2c2f95ee22"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,null],"resultHash":"0xd46e8ffc28ecac01a5ca44c715ccd52a1e2eafb6bbc39c49bcd8ea11028d17ee"},{"fromBlock":20027213,"toBlock":20053955,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],["0x000000000000000000000000c64350c0eab6faed8f17cc2cdff0761c53fb4152"]],"resultHash":"0x96ebc6b52d2cf5fbd51e26af733f984556ff922529aca2ba5eac7fbb3d716302"},{"fromBlock":13028275,"toBlock":13039896,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"]],"resultHash":"0x9b23b50ce20903f344f5e739bd942138c46f059b822219cac77ffa1fec27cdab"},{"fromBlock":14217193,"toBlock":14242118,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x00000000000000000000000039f6a6c85d39d5abad8a398310c52e7c374f2ba3"]],"resultHash":"0x11f0bbf82d64bb17ed52486f7cf90cd9d02867a6984495b2f5619da0ba519261"},{"fromBlock":15954548,"toBlock":15983163,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000006c6bc977e13df9b0de53b251522280bb72383700"]],"resultHash":"0x5be06318f789f63870a83a750dc97e53f288613162e3afda2967cd68ba9c794b"},{"fromBlock":15209584,"toBlock":15223289,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000ba8da9dcf11b50b03fd5284f164ef5cdef910705"],["0x0000000000000000000000000615dbba33fe61a31c7ed131bda6655ed76748b1"]],"resultHash":"0x99b1849681d401f3c4232daf9ad645fb96e1e0fc0a0cebf28c823cf28f7174e1"},{"fromBlock":19439984,"toBlock":19475816,"address":["0xce407cd7b95b39d3b4d53065e711e713dd5c5999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x5705a4b41fa629e8477f03860c61655a227a2489cebfa03e813004d437bafeec"},{"fromBlock":15954548,"toBlock":15983163,"address":[],"topics":[null,null,["0x0000000000000000000000006c6bc977e13df9b0de53b251522280bb72383700"]],"resultHash":"0xb7de838d445858370ad0d522d79acceefcd8426d9a2ba7745605abb3425ff451"},{"fromBlock":3778450,"toBlock":3826264,"address":["0xcced5b8288086be8c38e23567e684c3740be4d48"],"topics":[["0x7d19c7776f05049226f581a23a4df896c65115763d8ec30490658efc4e8649cd"]],"resultHash":"0xe14a8f781ceae515595fe0f1f9dbf04ed441bac50b670a64ff31fdd2b0d4a3c0"},{"fromBlock":13024943,"toBlock":13053579,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000005767d9ef41dc40689678ffca0608878fb3de906"]],"resultHash":"0x85e73c7338f4f1fc200dd164cc90fbd9868650a88b82332087b31fa737125a8a"},{"fromBlock":13010408,"toBlock":13059222,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x2e56d03e1674bf2c73b5f72844ae516d349d636326c7f4c62769e0f9359f5e76"},{"fromBlock":12335867,"toBlock":12346225,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000737aad349312f36b43041737d648051a39f146e8"]],"resultHash":"0x1734e117d44f5bc3b1818cacad13e10a3e3174f371e7d21a76cf0be4063e5a95"},{"fromBlock":13064924,"toBlock":13085532,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x313be4e9cb39adc87382b2adf33f06b78c011960602820edc54d55153aed15e7"},{"fromBlock":19121905,"toBlock":19156222,"address":[],"topics":[null,["0x000000000000000000000000b0aac1f129651e62cde6d1ae683c8a49f4d004d1"]],"resultHash":"0x03f6c6efbd5ed1a5e04a12f5aa4e2fca32226c4b0263f617dd2482deced4ee58"},{"fromBlock":13026464,"toBlock":13048285,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000c3d03e4f041fd4cd388c549ee2a29a9e5075882f"]],"resultHash":"0xbe8d7280be606961d2f7f7d8e70ded4b9859dad6b2dc8c92b31126b8b565ba97"},{"fromBlock":13030038,"toBlock":13036558,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x7c57c99570c75a5490eba0ce4bea85d02332460ed5df13bf1bfd767b89b41599"},{"fromBlock":20035325,"toBlock":20052246,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"],["0x0000000000000000000000005523985926aa12ba58dc5ad00ddca99678d7227e"]],"resultHash":"0x7ac0a1a177bc3c602d05dfada0bb7b8df0273d7e593fd4b1aadecfc2726dbf3c"},{"fromBlock":16897006,"toBlock":16914204,"address":["0x26fc1f11e612366d3367fc0cbfff9e819da91c8d"],"topics":[null,null,["0x00000000000000000000000087dde3a3f4b629e389ce5894c9a1f34a7eec5648"]],"resultHash":"0xfbe8c2092a89c166bbab015b200771ecf19a0cf036f64d9ce5e4040687e78d86"},{"fromBlock":13028275,"toBlock":13039896,"address":["0x53aabccae8c1713a6a150d9981d2ee867d0720e8","0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x9b23b50ce20903f344f5e739bd942138c46f059b822219cac77ffa1fec27cdab"},{"fromBlock":11661450,"toBlock":11669818,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc8830413b912b4c2037d97c84f9eae5595e2a43ccd93df5fede8b934a20f644b"},{"fromBlock":11378138,"toBlock":11397745,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000d6ad7a6750a7593e092a9b218d66c0a814a3436e"]],"resultHash":"0x1da62d1f0e52df0dad1cafc8267667849218b35b6670caa742d035de04a28183"},{"fromBlock":7554995,"toBlock":7591795,"address":["0x744d70fdbe2ba4cf95131626614a1763df805b9e"],"topics":[null,["0x000000000000000000000000ba826fec90cefdf6706858e5fbafcb27a290fbe0"]],"resultHash":"0x861687092d0a0e95396d6322979c32ac1200961341113e52fe40100cd68770b7"},{"fromBlock":12991241,"toBlock":13012816,"address":["0xcffdded873554f362ac02f8fb1f02e5ada10516f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0xa622968aa51af69414a036f23fc3ab2880eb98ae3dba121eb3dcd417c923965b"},{"fromBlock":13028961,"toBlock":13061694,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000e78388b4ce79068e89bf8aa7f218ef6b9ab0e9d0"]],"resultHash":"0x5fde0bf4fef34f4d78531c56974be71d1a6d291a689927bbecd1fd181da3c1f0"},{"fromBlock":3778450,"toBlock":3826264,"address":["0xcced5b8288086be8c38e23567e684c3740be4d48"],"topics":[["0x7d19c7776f05049226f581a23a4df896c65115763d8ec30490658efc4e8649cd"]],"resultHash":"0xe14a8f781ceae515595fe0f1f9dbf04ed441bac50b670a64ff31fdd2b0d4a3c0"},{"fromBlock":13028244,"toBlock":13074804,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0xdebb3a0e9c04728fa39f0c98a70b87281271049078cbc6ceca45c64f611d6f6c"}],[{"fromBlock":11661690,"toBlock":11666222,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006de2b77d89759c1275b99175494e29299f845cbc"]],"resultHash":"0x991c03c2c4f97f7bf066c3a2142b3b26f1697c03ef7955bee817ec03dfbe8b66"},{"fromBlock":20042922,"toBlock":20043743,"address":[],"topics":[["0x06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc82614677987"],null],"resultHash":"0xe8f0160471733abb03a7cf03c9c105e73a4881e762818c15d368e797a0114fca"},{"fromBlock":7372892,"toBlock":7375732,"address":[],"topics":[["0x73b3810100000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xec1431e92dada7934f15777cb1547c7509d30eb1049090a9968e465e39e5a881"},{"fromBlock":11667745,"toBlock":11668836,"address":["0xceff51756c56ceffca006cd410b03ffc46dd3a58"],"topics":[null,null,null],"resultHash":"0xc6041688d5b238f5813d792df3f0cde783a3e5f9e545851070e467782b32a731"},{"fromBlock":13040114,"toBlock":13041525,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x8f7c9147f0a600d561b309b0793382370ae0ecb19596763d9b08cf91195a3c99"},{"fromBlock":13617849,"toBlock":13621072,"address":null,"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"],null,null],"resultHash":"0x6c7dcbb29ef3092d3d0789a490228b949e0f2be119c68714b69570d426d4edc7"},{"fromBlock":7591162,"toBlock":7592971,"address":["0x744d70fdbe2ba4cf95131626614a1763df805b9e"],"topics":[null,null],"resultHash":"0x7d4ca88c025ac57f55978fd37f5ca19d447a2ba689097a06318d6b4fff38e319"},{"fromBlock":14228993,"toBlock":14229809,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003cd751e6b0078be393132286c442345e5dc49699"]],"resultHash":"0xce827660f8eed0c9727b01d625f274cec1b567ca9d7dc120f3d14f3956f8a108"},{"fromBlock":7266572,"toBlock":7269149,"address":["0xb6ed7644c69416d67b522e20bc294a9a9b405b31"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x380ff6080e5ed06503bfca57146bd8835ab18382357da542413c7ea9a9da088b"},{"fromBlock":13046352,"toBlock":13047770,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x0000000000000000000000000cfbed8f2248d2735203f602be0cae5a3131ec68"],["0x000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564"]],"resultHash":"0xbcfc227805d7358a75cd9a8debcb52bc40923a6db8ab989ed842e3fe7fd4cd4a"},{"fromBlock":13038453,"toBlock":13041618,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x01332413de3f5eaffc5bba8113f04054bb04d7bc1b42801042cb32639c2ea527"},{"fromBlock":13040114,"toBlock":13041525,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x393623ef0dae1b1890407eb4ca2bd36132a59feee70841810c7e9d493273c434"},{"fromBlock":13042228,"toBlock":13044862,"address":["0x34d7d7aaf50ad4944b70b320acb24c95fa2def7c"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x252bec1e3dbc830ae8d9139de25c33d6a589839757cc99a8c00cf21e6f361ab7"},{"fromBlock":13040655,"toBlock":13041404,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x497493dbf544ec77374bf5913b459e80a0f9f290b0e77911e9783ed2d6884073"},{"fromBlock":12722630,"toBlock":12728216,"address":["0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x4c3625ce76141008f441e0000e6a89303794a4945baf5558133e640174beeb67"},{"fromBlock":13040040,"toBlock":13040976,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x364e3c94637bef4e98efb3923dfcadadd49f761f9686ee933b1c44351e9a09a3"},{"fromBlock":13048068,"toBlock":13053370,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x00000000000000000000000034d7d7aaf50ad4944b70b320acb24c95fa2def7c"]],"resultHash":"0x4aefc4fabeabe25ee64e398d1b18b975cbaa84b901ee3213003a9bee33aca4db"},{"fromBlock":2680088,"toBlock":2681182,"address":["0xfa52274dd61e1643d2205169732f29114bc240b3"],"topics":[],"resultHash":"0x2449848305b1a215b4e96e8f7a71e2506330a6003f3604e7ffc057583c4805b5"},{"fromBlock":13036980,"toBlock":13043285,"address":[],"topics":[["0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa411430ec2a9f71749f27b4b0b93c9cedfa396ffce1c77436f04813b6a68a9ac"},{"fromBlock":13318181,"toBlock":13320011,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null],"resultHash":"0x40e83cbdcbf3a5046761642090499c5f11c76025c15b3303f25b5790a5f58a51"},{"fromBlock":9487884,"toBlock":9492111,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[null,["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],null],"resultHash":"0xc7c9cedaea1a7c70b773fc8e6a3c0ee2a85ed94240c82547c5f34aec1569bd66"},{"fromBlock":7267433,"toBlock":7269101,"address":["0xb6ed7644c69416d67b522e20bc294a9a9b405b31"],"topics":[],"resultHash":"0xef9f03688b4f82bb21cc639135398f7a7f097c773f86054deb1f1183fb38a404"},{"fromBlock":13058747,"toBlock":13060847,"address":["0x99b42f2b49c395d2a77d973f6009abb5d67da343"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xf9ee1f54dcc133bb8efebf8df16e4de1ab4f400444e3cc8219c23e2bd3fe60ad"},{"fromBlock":13039392,"toBlock":13041853,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006a091a3406e0073c3cd6340122143009adac0eda"]],"resultHash":"0x24212a0582990625c5bcb020e674a778d2ddaa35f0fcb3f241a56c66e0c7ee96"},{"fromBlock":14228993,"toBlock":14229809,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000003cd751e6b0078be393132286c442345e5dc49699"]],"resultHash":"0xce827660f8eed0c9727b01d625f274cec1b567ca9d7dc120f3d14f3956f8a108"},{"fromBlock":7577672,"toBlock":7580116,"address":["0x06012c8cf97bead5deae237070f9587f8e7a266d","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x00000000000000000000000039755357759ce0d7f32dc8dc45414cca409ae24e"]],"resultHash":"0xeb1dc739a44a126cc8a8be785d0525a1d151428ac2120233f05570443bb26b87"},{"fromBlock":12723374,"toBlock":12728565,"address":[],"topics":[null,["0x000000000000000000000000397ff1542f962076d0bfe58ea045ffa2d347aca0"],["0x00000000000000000000000003747f06215b44e498831da019b27f53e483599f","0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x56871e5b5447936e8a196c96fb04bec3805600ba552fd2661c53a706fee59aa2"},{"fromBlock":844081,"toBlock":845396,"address":["0x7de5aba7de728950c92c57d08e20d4077161f12f"],"topics":[],"resultHash":"0x5c3aeaf116735e195abe0271da985a606a587bc7e267d39a341632bb3ed5c169"},{"fromBlock":2942021,"toBlock":2942983,"address":["0xcd111aa492a9c77a367c36e6d6af8e6f212e0c8e"],"topics":[],"resultHash":"0xdf109a923886810ed7c6badaad10de911a6cdb92e44b7e3e079a9171939de2c6"},{"fromBlock":13036698,"toBlock":13037908,"address":[],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631"]],"resultHash":"0x2dcaba4442d8d8803387da80f8a87e3dd6b81318a52e3e0171bdc6284144667b"},{"fromBlock":10295073,"toBlock":10295809,"address":["0xcffdded873554f362ac02f8fb1f02e5ada10516f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x5da87f7d4fba8d4df26d9db0986c4c5a894b9793a26ca5ffef8bb85a45c0212e"},{"fromBlock":12724070,"toBlock":12728697,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0xfbcdbc0aac9359cca21013785027febede9af33ad07c03db1e8a075e2d6c5d98"},{"fromBlock":12723065,"toBlock":12728002,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x10ce1b306b736fc42135bf7e0687832ea71bdd786f537957207c67b6a6f0ee04"},{"fromBlock":10553954,"toBlock":10556609,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508","0x398ec7346dcd622edc5ae82352f02be94c62d119"],"topics":[["0xc12c57b1c73a2c3a2ea4613e9476abb3d8d146857aab7329e24243fb59710c82"]],"resultHash":"0x05f78aff9318467ea2ec94bcfe289589e245223dc24e65a2c400700b6fa1a024"},{"fromBlock":21431396,"toBlock":21433630,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x7c5e9ea400000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"]],"resultHash":"0x14ba15b3be74ad531665eb3b4a57890f4d4db36d56424e7ebe8558897c23e077"},{"fromBlock":13040514,"toBlock":13041613,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xb0717d254638bbf3941dfd98d92351c3d767e96b0cea887df180a2bb55390141"},{"fromBlock":13051070,"toBlock":13052839,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xd9dc04cea1465239158a63afa892e5dcab1fd63495665b2126584c7583a78df3"},{"fromBlock":7564842,"toBlock":7568039,"address":["0x744d70fdbe2ba4cf95131626614a1763df805b9e"],"topics":[],"resultHash":"0x81da9cd1d11671670d481920fb265b0b6ad30ead0bcefd522e0af296c36de423"},{"fromBlock":13038947,"toBlock":13042003,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006a091a3406e0073c3cd6340122143009adac0eda"]],"resultHash":"0x346f45be72a78e920a136e19d7577df90de5f4bd93dac603be20dc458c536f63"},{"fromBlock":13039370,"toBlock":13044992,"address":["0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9"],"topics":[["0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"]],"resultHash":"0x67d0ccc61032507b4bda27ab16eaae1314f38ba403cbe2bc188ea60e56486df6"},{"fromBlock":13093264,"toBlock":13099553,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x000000000000000000000000ddf8390ced9fad414b1ca1dd4fe14f881c2cfa70"]],"resultHash":"0x70a1c28215e088844d7bc03cb67fe90fd7474a0062734a9832afbaaeafba42a6"},{"fromBlock":11661690,"toBlock":11666222,"address":[],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006de2b77d89759c1275b99175494e29299f845cbc"]],"resultHash":"0x991c03c2c4f97f7bf066c3a2142b3b26f1697c03ef7955bee817ec03dfbe8b66"},{"fromBlock":13051070,"toBlock":13052839,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xd9dc04cea1465239158a63afa892e5dcab1fd63495665b2126584c7583a78df3"},{"fromBlock":11661779,"toBlock":11665556,"address":["0xc40d16476380e4037e6b1a2594caf6a6cc8da967"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0xce1cf241fa20b46da90effb92687039b5ccdaf979ae3e59f302e931acec77bc4"},{"fromBlock":14652255,"toBlock":14654590,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xdc77f56873c07503c790047025266df1004ee0f0ec072c5cc6f00c3ad8b6a27a"},{"fromBlock":9929051,"toBlock":9930286,"address":["0x5d3a536e4d6dbd6114cc1ead35777bab948e3643"],"topics":[["0x4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc04"]],"resultHash":"0x7ccf3e243ef267a9d298b304d57e7215619b412651068888ef2b0f3d0867a05e"},{"fromBlock":21462072,"toBlock":21467905,"address":[],"topics":[null,["0x0000000000000000000000004eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1"]],"resultHash":"0xce98d0efe7c11e3caa3257774ad47cd2d58d2385db13ebceecfa8dd9f93760be"},{"fromBlock":11660487,"toBlock":11666787,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006de2b77d89759c1275b99175494e29299f845cbc"]],"resultHash":"0x3a9c0b8b67dc9b3d267c5bc3ac7e5243c11654f01b1facd77bdce3b1922b3eb6"},{"fromBlock":13039798,"toBlock":13041279,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x5df0f5f21e9a40f35d8e72e659ae5f9399e9dcb02217364539b96f59665dd40f"},{"fromBlock":13039971,"toBlock":13041378,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x706d4c3d423e6cda788dd2804c477c9210f70fb5f17b484fcb608dc3cd1bdc49"},{"fromBlock":13038651,"toBlock":13040929,"address":["0x34d7d7aaf50ad4944b70b320acb24c95fa2def7c"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x2bc5d22e5b61f9f93445440c5fc2f3d17c2f7932425ebc4f80f343727570d4b3"},{"fromBlock":13039665,"toBlock":13041010,"address":["0x024cc95611d478dd367240e72c82662d9e390a6a"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x951901ac914bb471f33eb772f78ed0323c8236a57fd56332a93bc81352754a31"},{"fromBlock":13039437,"toBlock":13044684,"address":["0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef"]],"resultHash":"0x1c05ecdf175ded74f347fd9073e7202bc1896a905cb4383a0109e54b7b7fdf3c"},{"fromBlock":13039021,"toBlock":13043745,"address":["0x767fe9edc9e0df98e07454847909b5e959d7ca0e"],"topics":[["0x769254a71d2f67d8ac6cb44f2803c0d05cfbcf9effadb6a984f10ff9de3df6c3"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x7882332e1692da27a6deec69496a13a1eb6b170f67331d3e1a014220bf93d639"},{"fromBlock":13039056,"toBlock":13041565,"address":["0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"],["0x000000000000000000000000e66b31678d6c16e9ebf358268a790b763c133750"]],"resultHash":"0x41e93db5313da89327599eb2e29a6223f6304e6f5c2841e135f3a69eba24a92a"},{"fromBlock":15214027,"toBlock":15219162,"address":[],"topics":[null,null,["0x000000000000000000000000acd4ec996aad815efe72a11944188c6db6c30176"]],"resultHash":"0xd9dc3d5fca4944c27d5b93143997344c49d21dd05c101538ff40b102c21c770f"},{"fromBlock":10555157,"toBlock":10556358,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508","0x398ec7346dcd622edc5ae82352f02be94c62d119"],"topics":[],"resultHash":"0x0cd7e538351233bf81a0cc11ccc387d9246bd8d178d0b36c2bedbc62210a8857"},{"fromBlock":2941680,"toBlock":2943301,"address":[],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000058"]],"resultHash":"0x27148dae376160eaa994fde7a25ed3935fda149d8117ca63e7b6fb642fcd2c81"},{"fromBlock":12724457,"toBlock":12727144,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[null,["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0xf3f2e78ef22949e5179fd56adfead4f3dab190d50f05a59390359dddeba9ec43"},{"fromBlock":13038262,"toBlock":13043344,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0x9423c0ed23ece3e0cfb738499b1b12e7cedaedf0e3c9dd7e7c3e54223d0e0a5c"},{"fromBlock":13036239,"toBlock":13038128,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd2"]],"resultHash":"0xabfcc4cd1258206fe567646e9bb708c2c7acf0df9959b6cd4132b04e2a25cfad"},{"fromBlock":12722630,"toBlock":12728216,"address":["0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[null,["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x4c3625ce76141008f441e0000e6a89303794a4945baf5558133e640174beeb67"},{"fromBlock":20798827,"toBlock":20802879,"address":["0xae7ab96520de3a18e5e111b5eaab095312d7fe84"],"topics":[["0x9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x5186730411725013a4516f295891dc23448668f76cd0e60a69b97b269edcb3f8"},{"fromBlock":14898675,"toBlock":14899540,"address":null,"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x22d7726010bd1dfcbae718440c5b65989a327104aaec44c4c7a1128e7b71a9da"},{"fromBlock":20042635,"toBlock":20043870,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000fbeedcfe378866dab6abbafd8b2986f5c1768737"]],"resultHash":"0x73a2d4de8f594b61a4b8aac7cd337c5cac815c041613138ab9d2d0d19eb42a5c"},{"fromBlock":3534392,"toBlock":3535921,"address":[],"topics":[["0xc7e416c5685d8971558840f05c5e63e02575b29997d8da6b9ba44dc10da6a370"]],"resultHash":"0x4761586aa5f2eaa54070a294d435f35ed5b9970098b5c63257090754d8424d0f"},{"fromBlock":13036585,"toBlock":13037963,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631"]],"resultHash":"0x57c84b64864223cbb9c14d8ba8f08324e626d770f0cd617c895106afc2bfbb70"},{"fromBlock":13039251,"toBlock":13042675,"address":["0x767fe9edc9e0df98e07454847909b5e959d7ca0e"],"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xfba67e360c98dfb967bcfaa77bff5875a1cc7646e8ac375138b240df8ebef80b"},{"fromBlock":13036279,"toBlock":13043818,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000e12af1218b4e9272e9628d7c7dc6354d137d024e"]],"resultHash":"0x54390e0dfaca9e4bdcb42e8d0d1b9b89076ab6acc8f4be1b07d509e26eb478c3"},{"fromBlock":14227986,"toBlock":14230065,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xadd7e577c4a34d9a80e8367674e1e252d68fbef73effaee96f6c0d93e0914939"},{"fromBlock":13038603,"toBlock":13041823,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x0000000000000000000000006a091a3406e0073c3cd6340122143009adac0eda"]],"resultHash":"0x22d913e204de5979f8657bae357fa1cdbb3a963071a8ca8c54717b2ac4d895b3"},{"fromBlock":13031913,"toBlock":13033205,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x228cb394791c1bda35b689cc6d6d3b8a26d82f9ec465b239e69c45e05bb18def"},{"fromBlock":12204902,"toBlock":12207298,"address":["0x37ac54dc7dd237eecfd0b61efdd57b15fe158be0"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0x766ed453fd17d6ebf9caf2c5a5feef6d1095071c278171f37d6b81bf4f453c56"},{"fromBlock":15842864,"toBlock":15848444,"address":[],"topics":[["0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9"]],"resultHash":"0x0dd2c18e45a552db99ad07ecd1bfe337d862567cbdfcf2a25955ce5802de180d"},{"fromBlock":13069964,"toBlock":13071228,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,null],"resultHash":"0x46797e22d82ef19f6bc8b48922bddb43c00090746bac4e5ad381d988b03224bb"},{"fromBlock":13216293,"toBlock":13217569,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xcd0d6949b39c7830296826a1b5c0972af6a98729144d9920bc8bc26b4fbe8aa0"},{"fromBlock":13046526,"toBlock":13047579,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x0000000000000000000000000cfbed8f2248d2735203f602be0cae5a3131ec68"]],"resultHash":"0x2790678b3e25cc78e1d028872149843bf75e30ff87f43de30a514fc072afffc8"},{"fromBlock":13040353,"toBlock":13041431,"address":["0x397ff1542f962076d0bfe58ea045ffa2d347aca0","0x7b504a15ef05f4eed1c07208c5815c49022a0c19"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc50785a40596f0ede84630437f42b14ad38cfb4e709f4d457b0960e7d11b5a5c"},{"fromBlock":7654197,"toBlock":7655358,"address":[],"topics":[null,null,["0x000000000000000000000000cbc6a023eb975a1e2630223a7959988948e664f3"]],"resultHash":"0xc1ea8e577273ffa5458001fbead1ffac93823fcb7e1576ede5e10cea3d86154b"},{"fromBlock":10555345,"toBlock":10556439,"address":["0x398ec7346dcd622edc5ae82352f02be94c62d119"],"topics":[],"resultHash":"0x8d7cc5872ce1e3d1508c7abc1f8d59762ff1eb1d6ff0042255c0776d75aa217c"},{"fromBlock":14989083,"toBlock":14990778,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d"],["0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631"]],"resultHash":"0x06803c6bb685bf3c09faf07ff7fd79ac717a14ded328284fd3f03c8cb0484ce6"},{"fromBlock":3953800,"toBlock":3955192,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xcfaee5aaa72ac4e1696fba1eea2630389b0436f124de1850947bbccf92d8c2dc"},{"fromBlock":13037971,"toBlock":13044033,"address":["0xe12af1218b4e9272e9628d7c7dc6354d137d024e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x6fbe087696e4ce4769fb3eb5a9c31e12b326ec249712584ef8f2fbcea182690b"},{"fromBlock":16714077,"toBlock":16715539,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d"]],"resultHash":"0x2243900ab78eee08408829c4f61f0ee3d7e1c3a3700247f03718cde7d4ff90f7"},{"fromBlock":13034541,"toBlock":13040108,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0x53aabccae8c1713a6a150d9981d2ee867d0720e8"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x5a16ecf4180b12c76605892ddbcbc3190b321fd0b10a3e689042e9ccaef64b85"},{"fromBlock":13039882,"toBlock":13040928,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xca9451ae9b9d76af6cf8a992e6ce439b14c2bfff6dab7f0f7eb9169f57aae5b8"},{"fromBlock":13039281,"toBlock":13041551,"address":["0x811beed0119b4afce20d2583eb608c6f7af1954f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"],["0x000000000000000000000000e66b31678d6c16e9ebf358268a790b763c133750"]],"resultHash":"0x21f185c79b47a38e71feb0fb23daf8692d368687b9e921241b9408026627cdd3"},{"fromBlock":844081,"toBlock":845396,"address":["0x7de5aba7de728950c92c57d08e20d4077161f12f"],"topics":[["0xcc494284735b76f0235b8a507abc67ce930b369dac12b8a45e49510ccee0abe5"]],"resultHash":"0x1b9cc53446457661d61127ea84d9f73a0f7f7c84b55fdfddb4637f88ccfb5c9b"},{"fromBlock":13039376,"toBlock":13041129,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff"],["0x000000000000000000000000e66b31678d6c16e9ebf358268a790b763c133750"]],"resultHash":"0x800fe9edfbb8e77b189a6550090de250db3b21cff862d6032f7414e80935c54a"},{"fromBlock":3714914,"toBlock":3715553,"address":[],"topics":[["0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15"],["0x0000000000000000000000001e9939daaad6924ad004c2560e90804164900341"]],"resultHash":"0xd6b3b0a8c18b1f56fd8918f103750305b0ff719ceb1995e6ad24a054eaacbb54"},{"fromBlock":12878757,"toBlock":12879703,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xf027c053af2709b8d30bab1450986b6ea6d9cb7a133508a03454d3c8747121f7"},{"fromBlock":20798313,"toBlock":20801576,"address":["0xae7ab96520de3a18e5e111b5eaab095312d7fe84"],"topics":[["0x9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0xa04b6a3c00ac96ccae8faf1fa6e90e9cb3991ce3a8a720ca43d8c8f5b9e220da"},{"fromBlock":13038453,"toBlock":13041618,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0x01332413de3f5eaffc5bba8113f04054bb04d7bc1b42801042cb32639c2ea527"},{"fromBlock":7577672,"toBlock":7580116,"address":["0x06012c8cf97bead5deae237070f9587f8e7a266d","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000039755357759ce0d7f32dc8dc45414cca409ae24e"]],"resultHash":"0xeb1dc739a44a126cc8a8be785d0525a1d151428ac2120233f05570443bb26b87"},{"fromBlock":8754374,"toBlock":8756402,"address":[],"topics":[null,["0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"]],"resultHash":"0x6fa13d499317aaa09f9975eab6531079442dad6bf03bcf4c73d70d615fe314ad"},{"fromBlock":13038459,"toBlock":13041142,"address":["0x9cbfb60a09a9a33a10312da0f39977cbdb7fde23"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x08f636ed5aec543aee94aaafa124d7ade9176ee662d579974ad435760e7b973c"},{"fromBlock":13245760,"toBlock":13246585,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa6e5762044b187773ae36f515a157e8193f0fb9ddb9af8a544b4dd7333366dc8"},{"fromBlock":13039720,"toBlock":13041085,"address":["0x024cc95611d478dd367240e72c82662d9e390a6a"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x919e57e39f13885d118a06a2ab9745476b8614bb2fe1916b394a38813742b135"},{"fromBlock":13040142,"toBlock":13041044,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xb428e43351cd018b1e5333eaad975b7e7cf4fbc8ccb65f8a391e154ee8ed5b04"},{"fromBlock":13069964,"toBlock":13071228,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[null,null,null],"resultHash":"0x46797e22d82ef19f6bc8b48922bddb43c00090746bac4e5ad381d988b03224bb"}],[{"fromBlock":10206719,"toBlock":10206839,"address":["0xbcf935d206ca32929e1b887a07ed240f0d8ccd22"],"topics":[null,null,null],"resultHash":"0xd792b96604c4bc2484adb93bc948b781435815d0f0e65c28fe190a594d385c79"},{"fromBlock":3714936,"toBlock":3715405,"address":[],"topics":[["0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15"]],"resultHash":"0x459d70aaea32485b880f081e34ef6d0bb533de9e89b683deb48e303e056974e6"},{"fromBlock":7441446,"toBlock":7441498,"address":[],"topics":[["0xefaee3c90b37d63765790779d33d0b50dbd22a4eb719facd2a4863412441d2e0"]],"resultHash":"0xa627c74b2bb09bf6b0a57020fdd5763f9e301da254b49715e932280ee0da1e2f"},{"fromBlock":13039731,"toBlock":13039910,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x1f6c377498f7aef252b8bd49dd2e2990ab7d48bac1ad752872a03d2e69794889"},{"fromBlock":9853030,"toBlock":9853092,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0x1a8f110aaa73d8cb5e4ebbdf6f64d6750d589a417efcee1504ea273a03e5d342"},{"fromBlock":20049731,"toBlock":20049854,"address":[],"topics":[null,["0x000000000000000000000000f3de3c0d654fda23dad170f0f320a92172509127"],null],"resultHash":"0x105d070d58b265afbef263834c0455789fc932ec1f40d674727a4effe574a0ff"},{"fromBlock":13040509,"toBlock":13040580,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x47f8d5ccb4ee50f957a2aca1bd72c6e40d85026d1c95914091a01f00bb36f8a1"},{"fromBlock":13040843,"toBlock":13040925,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xe2e1a70f9ee718986f3efbc8bd2822619e1deb559f4fa830354be920b643c232"},{"fromBlock":2774142,"toBlock":2774576,"address":[],"topics":[["0x23919512b2162ddc59b67a65e3b03c419d4105366f7d4a632f5d3c3bee9b1cff"]],"resultHash":"0x02dfa71a64417d69e00cfeb5a3344db53a40c892310d8d6a6d765bdee1f86070"},{"fromBlock":13037118,"toBlock":13037214,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x23a53724f262e66c52b9a6aef5dca73df9e12e89d1760ccec59c9178d9dd11f3"},{"fromBlock":8139167,"toBlock":8139324,"address":[],"topics":[["0x8940c4b8e215f8822c5c8f0056c12652c746cbc57eedbd2a440b175971d47a77"]],"resultHash":"0xd2c3502453e38496ab05500933d2ed830a993ced59497a43124759d401a9c4a4"},{"fromBlock":1940173,"toBlock":1940921,"address":["0xbb9bc244d798123fde783fcc1c72d3bb8c189413"],"topics":[],"resultHash":"0x54222846f6ca453034e8c7e7f5f6099c38160581ea65271ae7f795a524a997ee"},{"fromBlock":10097706,"toBlock":10098287,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508"],"topics":[["0x35351404ba8a24ad4037a3df787e21ae5c0da5615468b58f6dec0925db0dea68"]],"resultHash":"0x03f1a8356137889542bfbdff532e098fbff6cbd905bf5ec32014f507d37d1a82"},{"fromBlock":20957125,"toBlock":20957177,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xc1e93c10a81bd5d5e51631125c26a626d1c62b470f77d342c2ac44b23239a3a7"},{"fromBlock":17601656,"toBlock":17601774,"address":["0xebd16e764ce252a6b1e07b062dcfb876e1b8a3f6"],"topics":[null,null,null],"resultHash":"0xad2c8cd311102613b6b2fb258ec6fb93479543122e1965409ca437a447ebfecb"},{"fromBlock":13046809,"toBlock":13047075,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000001a2a1c938ce3ec39b6d47113c7955baa9dd454f2"]],"resultHash":"0xa6bf6d643777510f77d856ffa92e243491eb270e0cd72c70d1653526eae44c7f"},{"fromBlock":12205584,"toBlock":12205774,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000011111112542d85b3ef69ae05771c2dccff4faa26"]],"resultHash":"0xa162f18cf766565087fd2e78fd88c2343579160ba221b1b3b01a9de7d0e5731d"},{"fromBlock":13040461,"toBlock":13040556,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x0000000000000000000000000cfbed8f2248d2735203f602be0cae5a3131ec68"]],"resultHash":"0xec8aee7724142d5c50fc9fb0cf17f38d02f4cfcf8132a7ab35ba29c610049de8"},{"fromBlock":7578677,"toBlock":7578799,"address":["0x06012c8cf97bead5deae237070f9587f8e7a266d","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0x321db676e45cbdf1fce723fb7c4abde1079e65ce8c73f9e539052351c755463a"},{"fromBlock":13038716,"toBlock":13039195,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0xc229cc32913535694c0009703e1ec9d83868b283342142acd3d728ae65f6fc72"},{"fromBlock":12961841,"toBlock":12961984,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x9bfa392f33b5757f195251927fe6290c0a98bdc19870b1963df919c27a5eaf69"},{"fromBlock":13040560,"toBlock":13040649,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xc22d893889d8670ccc1c1dfff4f3ced41914ca06b0f79929b2ef9f4237b98694"},{"fromBlock":10097959,"toBlock":10098035,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508"],"topics":[["0xa0538452cc1d076ff5b8d3f28c9dc9694023cce753f22d03e2af7d86459d2437"]],"resultHash":"0x2af1d0bdb5e8d3c0640440872672d3626ff591d80f7d882211c3715faa7ad8a4"},{"fromBlock":3331403,"toBlock":3331487,"address":null,"topics":null,"resultHash":"0xc23046934996ef25e1ae025617faf5a2d418a43c716a88391c02dcea232a6b5d"},{"fromBlock":13040266,"toBlock":13040681,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x55d4f97da3ae29fda22b9edaf20bd9a43d64b0100c4f19248f563880e75ca948"},{"fromBlock":2774299,"toBlock":2774449,"address":null,"topics":null,"resultHash":"0x8564efb04942acf0a6001554a44dade9b0c2e81e7b474d97f457beaca42f0ade"},{"fromBlock":13040026,"toBlock":13040175,"address":["0x6b3595068778dd592e39a122f4f5a5cf09c90fe2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x117dadb8f36cc23a1fe49ebcfc254ef705c301d999b6730a1686e126c446052a"},{"fromBlock":13039818,"toBlock":13040056,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x7fa53f469ff9ff0ef7da04adcdb242a0a986e452027d868d21b649a0a6a5e953"},{"fromBlock":13040574,"toBlock":13040699,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x38d809aa5eddf595a4bb72c988a6c8253d9accba2784702a786ff287d53dbf8a"},{"fromBlock":20923038,"toBlock":20923190,"address":null,"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0xdf040499d10c091cfaae3e38273d1419afbc02a565bdcb708c52527fda3c95bb"},{"fromBlock":942370,"toBlock":942664,"address":["0x276c5c6ca8507ed7bac085fc9b9521f4f54b58d3"],"topics":[["0xea0f544916910bb1ff33390cbe54a3f5d36d298328578399311cde3c9a750686"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x57ec38081ed656e50b8cc881530ee38f19570bed575534458e390ab2c0156b55"},{"fromBlock":1960709,"toBlock":1960788,"address":null,"topics":null,"resultHash":"0x7da9eea290afceee604d5acaf177aed292ed636e66a9d31035e668f86487e680"},{"fromBlock":3427303,"toBlock":3427508,"address":[],"topics":[null,null,null,["0x54494d4500000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x2779a8d0073730e51744539439016db00ccaa62449da5c2da475c75e95ae120f"},{"fromBlock":2774159,"toBlock":2774577,"address":null,"topics":[["0x23919512b2162ddc59b67a65e3b03c419d4105366f7d4a632f5d3c3bee9b1cff"]],"resultHash":"0x8c1736360c858672b83cdbd65b2bb707c63ab98c8fa99e01a7a6b3565e22f51d"},{"fromBlock":12892097,"toBlock":12892437,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0xad2fd917b403093baca57b9f5ea7b4226d02f9ccad99372267ee800e3cff0330"},{"fromBlock":13039737,"toBlock":13039900,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378","0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x847f83dabf7c48e9c599ff5d21d5c305ad4c5d94bb250d874e810a05da2c5bbe"},{"fromBlock":13042309,"toBlock":13043035,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xef9571206a5bd691b61d99e34e1aa6d2cf98ee2bb72aa795497ab216a08a216d"},{"fromBlock":13476070,"toBlock":13476211,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x610b17eee0cbcc519ae5d16488e93df779ab091945ec580d79344c437b53d69c"},{"fromBlock":16236568,"toBlock":16236726,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xa0ce0fc284eb64aa3ea49d08b1a7418fdd066321fdf49e69f2a7787bb3d52284"},{"fromBlock":13040233,"toBlock":13040770,"address":["0xe12af1218b4e9272e9628d7c7dc6354d137d024e"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xc0eef932fe7c5d3838897d39036555ab86408fed77ee2c8ae2ba52bd541e6fea"},{"fromBlock":13318886,"toBlock":13319225,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,null,null],"resultHash":"0x3e424ed897171ede702da60252e9d6646d5a4c89f0363bba173e5177c46c9a2d"},{"fromBlock":11662850,"toBlock":11663001,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x767edb0eb817be3c2fecb927e607a2f0d86f3503cd10cdb86ef54912169bb92a"},{"fromBlock":10097706,"toBlock":10098287,"address":[],"topics":[["0x35351404ba8a24ad4037a3df787e21ae5c0da5615468b58f6dec0925db0dea68"]],"resultHash":"0x03f1a8356137889542bfbdff532e098fbff6cbd905bf5ec32014f507d37d1a82"},{"fromBlock":13040449,"toBlock":13040557,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x28169c7008c0339805b42c7da0b50a90cd483cc0f399a9674b94bbe111af0568"},{"fromBlock":1447756,"toBlock":1448151,"address":null,"topics":null,"resultHash":"0x781192e87e2b5d6df7d2951205ce02a382e8ad4e2a2247101bd055819cdbec64"},{"fromBlock":11392095,"toBlock":11392258,"address":["0xf5b0a3efb8e8e4c201e2a935f110eaaf3ffecb8d"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x09243490ea2d6a519a4d7002d2fead39840e64a79fe75926626e722e0e43068d"},{"fromBlock":13040504,"toBlock":13040576,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xa4745f253839f0a4fb6569a142e1929ac4b33da5328e3d40a38d7e89bbb021bf"},{"fromBlock":14883294,"toBlock":14883580,"address":["0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc"],"topics":[],"resultHash":"0xc0cdca0f063eb8a0e72d3aa02b83de0ef83ddd447fc536c8d3c51d4ec6cddbf1"},{"fromBlock":16714648,"toBlock":16714869,"address":[],"topics":[null,["0x0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d"]],"resultHash":"0x200533f43d156a414baef4ebe3b97946608baa96c22a0408e4f538f9527e0d29"},{"fromBlock":3534732,"toBlock":3534956,"address":[],"topics":[["0x78e4fc71ff7e525b3b4660a76336a2046232fd9bba9c65abb22fa3d07d6e7066"]],"resultHash":"0xb75ad826cb866124c423bc036435f78781193b814b15c4c9980095d3bca02eda"},{"fromBlock":11664073,"toBlock":11664711,"address":[],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x69a9e52f9951ce8c055b9c3e832d2cbdd11efd53ec7fd09817e2569cc9d5d7d8"},{"fromBlock":13024437,"toBlock":13024599,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x00000000000000000000000063945489ef54398f3ccc8cb44f2a93ba1ac91ab8"],null],"resultHash":"0x1fac348588933c195c32822c80d9408752fb4cbb6f0f52a7bde301c5f7bca2c1"},{"fromBlock":13040474,"toBlock":13040534,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x12eff26cb1ac6f324ce5bd99d6b03ae647587a201b8b61b8e987e983f9175e9a"},{"fromBlock":13039824,"toBlock":13039900,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xf507f6e5b10289e97b2125792f04e0edbf817644960c8620b7c8e53c6b390551"},{"fromBlock":13475874,"toBlock":13476331,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000594fe7c3d4c52c0e9ab377bc6d8acd66adc8ea9d","0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x4db12e325e8a8e10358875876c94dd611ed1cf9262b89a1a6ec6d131435a43a5"},{"fromBlock":21463506,"toBlock":21463623,"address":[],"topics":[["0xed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c2"]],"resultHash":"0x0a39768360340110edc00269da50d5edb7cf00f38f303c270ef6bcfdc73fdd6e"},{"fromBlock":13040410,"toBlock":13040487,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x3a3491d504cdece799c5a6741c354088882401f25c502d59a11ba71f540da3dd"},{"fromBlock":10295449,"toBlock":10295573,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xe75f6d1fa2b0c0b65f8b55b98a57d16f6e664dfbef670ec669469cb84088f579"},{"fromBlock":5357744,"toBlock":5357823,"address":["0x4540fcf016bcb67290c3e14238702c64e6a51600"],"topics":[],"resultHash":"0x16dea750684eda1543d86e6cc562282433c7a1c37b5a7bd6752b79f50fa7a2a0"},{"fromBlock":7567899,"toBlock":7568409,"address":["0xd1ceeeeee83f8bcf3bedad437202b6154e9f5405"],"topics":[["0x5bdd2fc99022530157777690475b670d3872f32262eb1d47d9ba8000dad58f87"]],"resultHash":"0x9e6ed7f2aa537c3c09db147112de187de0d08eeb666ce7e25e74f677791e3432"},{"fromBlock":5573149,"toBlock":5573367,"address":[],"topics":[null,null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x4cfbff18374cbf9f37387fffb626643b45de897d75e5dd540ae5d4bd99d3808f"},{"fromBlock":12892139,"toBlock":12892574,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0xf46661478ccbe277be6d327fd58147561ae633d0859dc134a122904440b5d33e"},{"fromBlock":8408238,"toBlock":8408393,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0x52aa70ba25e111f099abde1409f6da8bce82a943c5d27cc498de7fbb04e9f9eb"},{"fromBlock":13040609,"toBlock":13040681,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xfe9a46dbbd8e77330d03aed7249e7c95bc1bac3424cf68767a4a9b6f81ba7703"},{"fromBlock":5542264,"toBlock":5542392,"address":[],"topics":[["0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567"]],"resultHash":"0x48c6213aeca511bbee472f36e1cae81cf985646e4996e6f1d13d1179ffa4e1db"},{"fromBlock":12836700,"toBlock":12837002,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000a57bd00134b2850b2a1c55860c9e9ea100fdd6cf"],["0x000000000000000000000000fe7444f63e0010a7208529608eb173760629483b","0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x2b7b039b831f6070de1b7e6021f562d4ae9f61741de52f380ed4b20cca748cb0"},{"fromBlock":6051324,"toBlock":6051373,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x3c33999dec4d7c9d55a752fcf517ee9066bdb16e611bf3432e76753a3a8d2672"},{"fromBlock":13037443,"toBlock":13037578,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x0212abf4faf32bace62b149b654ab40455ef7bf2fadb930482d595729304769b"},{"fromBlock":13040275,"toBlock":13040401,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xd5dff86990ba5b5052de203fecd49e354057ee5be14acf115b5bda2faec5a8e8"},{"fromBlock":9929342,"toBlock":9929782,"address":["0x5d3a536e4d6dbd6114cc1ead35777bab948e3643"],"topics":[],"resultHash":"0x7fcca1fc83bad8eaf8e6f07ec3ab45b0451c1010da560dfa2ab36e68941ae614"},{"fromBlock":7445323,"toBlock":7445591,"address":["0xba3ed686cc32ffa8664628b1e96d8022e40543de"],"topics":[null,null,null,null],"resultHash":"0x64fb7ec10914129165c7deef69043c9c4379bcc3142614eb37111d5510135919"},{"fromBlock":13318908,"toBlock":13319153,"address":["0x514910771af9ca656af840dff83e8264ecf986ca"],"topics":[null,null,null],"resultHash":"0x2414b06a21edbc2258891d07e00846eb7b8bbdb4a5de8a813114b9b7bde2fec5"},{"fromBlock":13040375,"toBlock":13040756,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x7789eaf16b0625516e7d2cd0d51da805cea96d53e54d3fe3644730c37d028542"},{"fromBlock":18343780,"toBlock":18343981,"address":[],"topics":[null,null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x96417af1c8e8fbf698e8df8d9a1c63fc87baa4e71ab30d929e8b4620795ea79c"},{"fromBlock":12892182,"toBlock":12892378,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0xf50d43236307de2de4d79f1d788956ee5f85036c781f2eaac343f83321f2522e"},{"fromBlock":15671326,"toBlock":15671799,"address":["0x49ff149d649769033d43783e7456f626862cd160","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null],"resultHash":"0x23dfde4309ccc2559111fa06b03b382bf0eb8b5fc3c3c8434ca8d53fdfea850f"},{"fromBlock":13040160,"toBlock":13040795,"address":["0x06da0fd433c1a5d7a4faa01111c044910a184553"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x8806548ddacecfb5eadb00b76fa83530f0c0f77fde4db13dec34bdc842e54fdd"},{"fromBlock":13039818,"toBlock":13040019,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xd2f61c353fbf9de4bdb1a1ebd959910658a3d87b04866e46f73b7c3ef348576a"},{"fromBlock":20042968,"toBlock":20043723,"address":[],"topics":[null,null,["0x000000000000000000000000fbeedcfe378866dab6abbafd8b2986f5c1768737"]],"resultHash":"0x5ebcd58fcbc0e945cc4a9202657db70d62dfe735ef76782c680e233bd9190373"},{"fromBlock":11695575,"toBlock":11695866,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,["0x000000000000000000000000b8a5a55a34d92757f4d440e58927c9191fcb2166","0x0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852"]],"resultHash":"0xf2b0af884b69e1e6759703f1bf9f65680bf914d96fa78addd355c22f759048df"},{"fromBlock":13039715,"toBlock":13040581,"address":["0xfa52274dd61e1643d2205169732f29114bc240b3","0x877d9c970b8b5501e95967fe845b7293f63e72f7"],"topics":[null,null,null],"resultHash":"0xacb517414c25d227f929e1728269eca6d936d1f01d1da3120e33f36e2177b19e"},{"fromBlock":12891963,"toBlock":12892259,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null,["0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"]],"resultHash":"0x2225ba09325a5e0ebb8f4b75bb5804c788ab299a8adfc6bce359b6f4ac9f8034"},{"fromBlock":13040520,"toBlock":13040613,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xb536d7f4cfa3be1b3bf1080877c84e278e667ca581cdb2862e6aa96af5449b77"},{"fromBlock":13050666,"toBlock":13050816,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x12a4aa27e86c6f0765805e7e291c1814ca3efdfa9ab107651eca3037be929308"},{"fromBlock":13038832,"toBlock":13039205,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],null],"resultHash":"0x6b7ae5a21e1be59033c5e58c0d3aa6545b5811e6d3732b7312f6156d9edd782f"},{"fromBlock":18343729,"toBlock":18343946,"address":["0xc662c410c0ecf747543f5ba90660f6abebd9c8c4"],"topics":[["0x9592d37825c744e33fa80c469683bbd04d336241bb600b574758efd182abe26a"],null,null,null],"resultHash":"0x9305fe64df1cd4b7e89a991a69101d680c2ba6cf7e59c5e46990ac7d93b1d329"},{"fromBlock":13785421,"toBlock":13785495,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xa4f8c66a7e742a8ec5ba155f4b4f6556509266be514f2f795cf7dc6cd6d802bb"},{"fromBlock":13040602,"toBlock":13040673,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xf8821108b1703edf3125bd74c3b958fdc24c05d5b1353a0766665ad3e867f916"},{"fromBlock":942370,"toBlock":942664,"address":[],"topics":[["0xea0f544916910bb1ff33390cbe54a3f5d36d298328578399311cde3c9a750686"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x57ec38081ed656e50b8cc881530ee38f19570bed575534458e390ab2c0156b55"},{"fromBlock":1940441,"toBlock":1940609,"address":null,"topics":null,"resultHash":"0x2d724c4b8f3f7f93efd9ba5e32f0b4aa38b6cc19b98475c039b6ec2b8257b6e5"},{"fromBlock":10166417,"toBlock":10166497,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0x2a43cb2d19bc3e9e37dc9b2ad609d76cf1887bfbc0d1ed2ad74ce5b675926b09"},{"fromBlock":3534751,"toBlock":3534921,"address":[],"topics":[["0x23919512b2162ddc59b67a65e3b03c419d4105366f7d4a632f5d3c3bee9b1cff"]],"resultHash":"0xc76ee4aa2e83e71f31d95ff8a893a156652da6e9bbbe9b3b7b4a331de7db1aa1"},{"fromBlock":12205543,"toBlock":12205964,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x00000000000000000000000011111112542d85b3ef69ae05771c2dccff4faa26"],["0x00000000000000000000000074de5d4fcbf63e00296fd95d33236b9794016631"]],"resultHash":"0x4eeefecafc207a9ae4007f44a3e1de74b3eb45590fc5f6f2fc87c68201494f18"},{"fromBlock":7566927,"toBlock":7567331,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0xee3f8e540a0907cde3bf423fc9ed3bb40774e22b7da6c4a31e978f1094e236f9"},{"fromBlock":2111717,"toBlock":2111871,"address":null,"topics":null,"resultHash":"0x0d3962e49ba36ffff2dc34c74cbad1ecd8970f68501e1582853f2f8eec76ebc2"},{"fromBlock":13024437,"toBlock":13024599,"address":null,"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x00000000000000000000000063945489ef54398f3ccc8cb44f2a93ba1ac91ab8"],null],"resultHash":"0x4895ee1adb27632ac084830aff16942b6272a54e91b04c92c2fec06b18505bd9"},{"fromBlock":20799049,"toBlock":20799403,"address":["0xae7ab96520de3a18e5e111b5eaab095312d7fe84"],"topics":[null,null,null],"resultHash":"0xa10430acaa753245e8fa441b2a863062bbe1a8610e7f79a24699ef3b18f0d228"},{"fromBlock":7567091,"toBlock":7567520,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0x6316fafa6180b283db9b60c78ead580a86c62079ca3b7cd26199cc4a6ef3a757"},{"fromBlock":13047430,"toBlock":13047807,"address":[],"topics":[null,null,null,["0x000000000000000000000000bb0e17ef65f82ab018d8edd776e8dd940327b28b"]],"resultHash":"0x7d407aae4b85467cdffccb30f28dc191efad511bb6a8d2c92599270506650c6e"},{"fromBlock":13075394,"toBlock":13075670,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xf7f197956deebf17e8cad217e623578dcc8b10cb2b3189fa0d76efc5a977e7ac"}],[{"fromBlock":13040363,"toBlock":13040376,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null],"resultHash":"0x0c85940b815535c18e1f954d0671084785ae23c4b5346b5e2e2c952208321b66"},{"fromBlock":13041601,"toBlock":13041612,"address":null,"topics":[null,null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000024cc95611d478dd367240e72c82662d9e390a6a"]],"resultHash":"0xf08a34f7413b5403f3f9283cf2cef3e206685d3af3d32b38948e3e5ed4ca6d60"},{"fromBlock":13040474,"toBlock":13040534,"address":null,"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xbac98c1f7d46e515d3f1318ae16541319d01c01dcb06671046018c8c812e33ca"},{"fromBlock":13037013,"toBlock":13037027,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],null],"resultHash":"0x5dfd02e729509f8e1465f1cf29adea2a54e106ed4b746b331b11ca88233854ac"},{"fromBlock":3798448,"toBlock":3798472,"address":null,"topics":[],"resultHash":"0xc32fe14ac305fdba7ac39c90103b3b0fe052f9ee2b1517102ed333ccf9a1e83d"},{"fromBlock":13040553,"toBlock":13040593,"address":null,"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xf9cf42d7ac449de2b29e13c2cd4230f905bbd6259377a8baa5489fbfc4dca63e"},{"fromBlock":3715172,"toBlock":3715195,"address":null,"topics":null,"resultHash":"0x038255591685e988b35be479347a93590cbba04ad429e3c32a12075b707c3b32"},{"fromBlock":13040615,"toBlock":13040637,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x173f776c471a86f2099c94dd0281b34debad5d1ff7865b6ce685e7264cf3aa28"},{"fromBlock":13040671,"toBlock":13040671,"address":null,"topics":[null,null],"resultHash":"0x7e026b9febf1b7895e638f9b975c6a1cded538b70ee004c32db6b3af725ce571"},{"fromBlock":13039864,"toBlock":13039924,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x94be78bfa67aac8239cb81a4cac1d147b08b1ec35c35f5167f2637087c340682"},{"fromBlock":12985494,"toBlock":12985535,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xb4d015acca9ea24f72d30b5dcafb4e1fefec0e6b8e55bb0a58bdbf9b2d2df437"},{"fromBlock":13039495,"toBlock":13039513,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,null],"resultHash":"0xd39763306410f4e11d1e249663e6c5af68f7dd31c8e319c58b5f0ed3c51f0604"},{"fromBlock":13039792,"toBlock":13039821,"address":null,"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x33f45e14c53bbfb40518a6be49a95338aee3e78aefb6fd813c3f7f1dcba32201"},{"fromBlock":16236608,"toBlock":16236626,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null,null],"resultHash":"0xf5ddeacd96cc446aaee4968438e0540fd921c59512cba5c6215ba33245d6f225"},{"fromBlock":3534789,"toBlock":3534844,"address":null,"topics":null,"resultHash":"0xa51628828c1c31c6d55f3e372fd2e64e10140459c9423be91c96f9ace4e31501"},{"fromBlock":20264600,"toBlock":20264607,"address":null,"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1","0x908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378"]],"resultHash":"0x482cd7d5b8aae1b6f1147e0f5a66487a4363558978aae4c0999d1a6df07b8067"},{"fromBlock":13785435,"toBlock":13785449,"address":[],"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x96deeba13e2b6bf5ab5e89465bd2c3ee56403ef6e023ee6062091ef9857cab3f"},{"fromBlock":14526515,"toBlock":14526521,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0xae7561506bb13a36c80c30f7530ee2594d0543d410c28fd409db4ac1cd1c9a44"},{"fromBlock":12726345,"toBlock":12726409,"address":null,"topics":[null,null,["0x00000000000000000000000003747f06215b44e498831da019b27f53e483599f","0x00000000000000000000000056178a0d5f301baf6cf3e1cd53d9863437345bf9"]],"resultHash":"0x87dfc4e21373e54b9131f22de3098d089a3d02864e5075d355aa561d2435f3f9"},{"fromBlock":10780328,"toBlock":10780337,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x702d35c5576cd01e947c784ffeda735f2665c41ac44988e8baedd16a81e5fbc5"},{"fromBlock":13040534,"toBlock":13040546,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x48fb253446873234f2febbf9bdeaa72d9d387f94"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x22da381c606d94c4d1a476c02d6e6ab46a2513d6b35bb1f7b3f0e90c27e5e5ea"},{"fromBlock":16703649,"toBlock":16703657,"address":["0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null],"resultHash":"0x6ef95b6cc8796a12db32dfc03d726bc55892b9a3906ede4d125a9c71de2f1867"},{"fromBlock":13040479,"toBlock":13040518,"address":null,"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x000000000000000000000000b8f275fbf7a959f4bce59999a2ef122a099e81a8"]],"resultHash":"0x87c51a434dcfed54e47923e6c5a9a5fa1c7d6fc7a3bab80cb56f2db6bd290f0b"},{"fromBlock":13177262,"toBlock":13177283,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,null],"resultHash":"0x52f3111f584446ee31ce4a2b3bf910d9018912e6d202699f6d41a8b08114b265"},{"fromBlock":13041387,"toBlock":13041394,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0xa37511e6a15b20b4752306c822f4faccd92a41b06396a9e5ad60727f5d42d36c"},{"fromBlock":13039033,"toBlock":13039043,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,null],"resultHash":"0xecdb86eab5b5c0dd38d6ef2fa0fe8d43c1c3fe44044062ec26de3c8fbbddba3a"},{"fromBlock":13762907,"toBlock":13762921,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[],"resultHash":"0xcc51f221e5b8c9df7696537d901f038d9e115a764e65356452bd6f6e52635b7c"},{"fromBlock":17583491,"toBlock":17583507,"address":[],"topics":[null,null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x16751bc9438d4dee9e2b1d0fb845920588fa7d5e9e12f2176cb4dcae0de51318"},{"fromBlock":12450864,"toBlock":12450873,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null],"resultHash":"0xd53ab7019b18b1118abeb8610cd265b2c89f669108dbb50fd49ebe7dc9c72e64"},{"fromBlock":14226761,"toBlock":14226787,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null],"resultHash":"0xd0670fb0b1739fad33e881e92f626ee5c8ab41933261ac76399cad1b037a9673"},{"fromBlock":13040669,"toBlock":13040675,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null],"resultHash":"0xfe2f6847e6b681859d4133ddd2702cc5619a551b8ca985e1ae7cd54c549d9a0d"},{"fromBlock":7445381,"toBlock":7445405,"address":null,"topics":[null,null,null,null],"resultHash":"0x3c17b3deab2a9d355313aabc5a3ce67c87f457d6228e7eed25834cbb7358e106"},{"fromBlock":13040597,"toBlock":13040660,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xe87aefe0efe9aadc728eda0acecc747cdd9985beb7926f77961d25ced0ad6724"},{"fromBlock":5321271,"toBlock":5321276,"address":null,"topics":[],"resultHash":"0x71d09c411d3adf41aa96d504560a9749e5e213e24bf1da3c19d42b114e474f5e"},{"fromBlock":13180336,"toBlock":13180342,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x8b370c9f57921998713ececea1f41b3104bf067b2e2f689dcabf34e01b2c7f19"},{"fromBlock":871805,"toBlock":871853,"address":null,"topics":null,"resultHash":"0x88f758217f922c95e5074a82c7fe5ddb73637960671f52212372b660c8157784"},{"fromBlock":4081699,"toBlock":4081718,"address":null,"topics":null,"resultHash":"0x0699b14587fcaa6db0c9222e052173e161c86dd542474467770f946e389b6acb"},{"fromBlock":15502349,"toBlock":15502381,"address":null,"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x74060a2c21538a4ddc97213db1467020aee3eec87c58625d44103f922f72798e"},{"fromBlock":3427375,"toBlock":3427415,"address":null,"topics":[null,null,null],"resultHash":"0xec56d28b280c824f7a8129e96c845825ba326d627af27a219ae6271e6472c399"},{"fromBlock":3784903,"toBlock":3784926,"address":null,"topics":null,"resultHash":"0xce4b719469d10f94aa2fd7f517c51f08eac59b798d6f2702c2b9f1248a15daed"},{"fromBlock":14192957,"toBlock":14192986,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7","0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xad349b149ed6e7bd71290458e1b9faef30946d606529f64609b02ff21b14c200"},{"fromBlock":20042156,"toBlock":20042172,"address":null,"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09"]],"resultHash":"0xe23be3f92d48e4fdb286debed4287195c40aee4427357df64ebf3597e3897b38"},{"fromBlock":13038588,"toBlock":13038602,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,null],"resultHash":"0x0720caa0f7e4ff680d53e4974dafc05f710a9c7c66eed832da56fc054e180189"},{"fromBlock":21463472,"toBlock":21463484,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x153832d61008e412c5d3c022c292c2c482d7b320c3f3c9b2293670c1a9e2767e"},{"fromBlock":13040652,"toBlock":13040686,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],null],"resultHash":"0x2b298a950890da3d82e6e6ab39347a6936c64d80eab9b2d60003254ca96813ad"},{"fromBlock":5910525,"toBlock":5910545,"address":["0xe6bc60a00b81c7f3cbc8f4ef3b0a6805b6851753"],"topics":[],"resultHash":"0x6fe7e172924d7dca7f7b9539af9d3469b22cb1106e9473339e61ad150c2314ef"},{"fromBlock":18343803,"toBlock":18343812,"address":null,"topics":[null,null,null,null],"resultHash":"0x096ea25377feb3e327d62c267ef4a6c42b1ecc71ed2c6da875a3a38d6e67307e"},{"fromBlock":17361666,"toBlock":17361688,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,null],"resultHash":"0xd00bf2dcfd984d8e97497e19a948e0a47db3a8f941e21d3795da8364ddb7d91c"},{"fromBlock":13040546,"toBlock":13040579,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0xd39736ff1c07c0fb3a1b169632ad77f108091afb82bd6d97aeafcb39bf85508a"},{"fromBlock":5910488,"toBlock":5910551,"address":["0xe6bc60a00b81c7f3cbc8f4ef3b0a6805b6851753"],"topics":[null,["0x00000000000000000000000024fb92c936a9429303dfae39b8824b931a009fe8"]],"resultHash":"0x15002a19f9b33c7d4b16bb1d047b46dde23fa3ffb29bb1d2b136317b63884e3a"},{"fromBlock":3451247,"toBlock":3451286,"address":null,"topics":null,"resultHash":"0x4af995ed498cfaa6c7e0be1e3e555155156d8c6042aac0d74e39a4f10993a6b2"},{"fromBlock":6327069,"toBlock":6327093,"address":["0x8e306b005773bee6ba6a6e8972bc79d766cc15c8"],"topics":[],"resultHash":"0xa65aeda8d396f01afe40432943208a1d8ab0153b1281adbc89be7360d70e9798"},{"fromBlock":13040662,"toBlock":13040692,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],null],"resultHash":"0x7dc7612d90babdef8ae4b9f56570451284ecb5d5e234a52daa4ef2d54c54966f"},{"fromBlock":13040602,"toBlock":13040675,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f"],"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x514b100e61a4ec901b68687fdbc0ae97aa50a3457bf507add9da473bd1a9eda6"},{"fromBlock":4057595,"toBlock":4057608,"address":null,"topics":[],"resultHash":"0x9ad554d914f71f33421cf445d1f37c14b75c5433c3701c3e99f58bdf0da499f0"},{"fromBlock":11695738,"toBlock":11695747,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null],"resultHash":"0xbb6827a9fb918c8318df225099adb81443ed4e7e4953f0b485a6f5c7674f78df"},{"fromBlock":13042401,"toBlock":13042412,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null,null],"resultHash":"0xc89ad796eeefbad79ed083c57c255e547cfc6790bcbe2813d806bfdbc38b44ca"},{"fromBlock":13047512,"toBlock":13047521,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0x5cbce47a15ad1a1ca02d438651408495305de411180bd642648b21bee426a893"},{"fromBlock":13040680,"toBlock":13040727,"address":null,"topics":[null,["0x000000000000000000000000fa103c21ea2df71dfb92b0652f8b1d795e51cdef","0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0x87699c723756d44f4d901489113761c9f3d710d061534b5fbf6a193c16ac0eea"},{"fromBlock":13047763,"toBlock":13047812,"address":["0x1a2a1c938ce3ec39b6d47113c7955baa9dd454f2"],"topics":[null,null,null,null],"resultHash":"0x0db94629204a3ba1576df0c8f5b60fcdc338ecb0cf56ea239b83017df4cb3875"},{"fromBlock":15848281,"toBlock":15848293,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"]],"resultHash":"0x5e7ddb91085eaf2be41c4d5e8f6d07bcdf38e7479403de1cbc5acbdfb25f0409"},{"fromBlock":3798453,"toBlock":3798470,"address":null,"topics":null,"resultHash":"0xfdf2bf1c800dd96c7ba59d7e8de42317c2b66fb198f3aad86140201595b7b87c"},{"fromBlock":3798454,"toBlock":3798473,"address":null,"topics":[],"resultHash":"0xa196d1b1d8624afc987bc5d789b39e8c36e5b2a0ee7d5ff02668df365d5849d3"},{"fromBlock":20042946,"toBlock":20042958,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc82614677987"],null],"resultHash":"0xf7bab2c2cc41a4db4600547f11d1a0ecd2f3554f11282058f3ee2ac39ebb2797"},{"fromBlock":14229000,"toBlock":14229025,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0xca100fde8b07263afbcbd77ac86c3422efbeaf18d2a27d869106fa017c5981ca"},{"fromBlock":11902460,"toBlock":11902475,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x865bdbfce3a71aecda4a235a09e8524ae7f8c71b0b7ad1452cca751465560a26"},{"fromBlock":13137207,"toBlock":13137222,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null,null],"resultHash":"0x0f1c36577dc10764604c86fda065e756218f3e4ab6917ef8af62c96d00cff409"},{"fromBlock":5039772,"toBlock":5039816,"address":["0xb8327f32127afe37a544c52b628653e222a93bad"],"topics":[],"resultHash":"0x7c4cfc3c1ec426f2c175d19a50f22762b7cacdc7de47291006fe3dc22aaf6fe8"},{"fromBlock":21431904,"toBlock":21431920,"address":null,"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"],null],"resultHash":"0x8f1de6421fbe1848b2ec2224acae523d9793157ca558d0a67c76d8c5a4755eaa"},{"fromBlock":13040246,"toBlock":13040294,"address":null,"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],null],"resultHash":"0xe94e57570717c9bd1f33f51d1f25442a9b624a80006fa32377bf7e302dcba74b"},{"fromBlock":12205711,"toBlock":12205720,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"]],"resultHash":"0xb8bdd13b4fc12c72bff6078612c35efcc192e52cb843cbba85febae125a15645"},{"fromBlock":12607634,"toBlock":12607647,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[null,null,null],"resultHash":"0x8265c24926ece92ef855c721fd3a54b4a66c75b988ad096e151b769744b18a74"},{"fromBlock":13058884,"toBlock":13058955,"address":null,"topics":[null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f","0x00000000000000000000000092f1ff14a80ea8c23028a40c74c05bb994ea0ee2"]],"resultHash":"0xcfad58ebe19f88abd7582e84dfaa58e88b284404c92bc84c155a1e943c48b7dc"},{"fromBlock":14883445,"toBlock":14883446,"address":null,"topics":null,"resultHash":"0x5eebf3e7f3ffb139212e7f995705022306a085d53de66a51e63eaec61d8fb547"},{"fromBlock":10097989,"toBlock":10098004,"address":["0x8a91c9a16cd62693649d80afa85a09dbbdcb8508"],"topics":[],"resultHash":"0x7caf48a0605ea17071d0dae11abc5e1542896168fcbc28f0b42ee5d0cc025bf3"},{"fromBlock":14229362,"toBlock":14229371,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x39f0e754f66f970422c71db37d4e7a2765f0bf9f029a1ddc4b8814a150c9d8d8"},{"fromBlock":13042819,"toBlock":13042825,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,null],"resultHash":"0x433cc2971aafab67863137d585e9f900bb103ea7f8e119728af285e44dde900b"},{"fromBlock":13040634,"toBlock":13040665,"address":null,"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],null],"resultHash":"0xd2b4cd32f9449d0ec5438c69a44a2357d3f8b1145cbe7d7e5e417f92ba8e7bfc"},{"fromBlock":16986579,"toBlock":16986598,"address":["0x5b1085136a811e55b2bb2ca1ea456ba82126a376"],"topics":[],"resultHash":"0xc15e7b859d59bd13d8380bcc243b9e3a6d5ec647de8d94bac48ef34549852edd"},{"fromBlock":13040644,"toBlock":13040665,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"],null],"resultHash":"0xe1533cdaf6e12504b12f636d51ddef324d8c99d4804c9b9ddbabee3ea2ab6e89"},{"fromBlock":14526509,"toBlock":14526527,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[null,["0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45"]],"resultHash":"0x1cb3160aec8bba240c1b6af4e4970477e02e6c44543ff7f7d26d055eec981778"},{"fromBlock":3554829,"toBlock":3554842,"address":[],"topics":[["0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15"],["0x00000000000000000000000061c808d82a3ac53231750dadc13c777b59310bd9"]],"resultHash":"0xf6a0cde7fbd739f1764dea4872e3b007fdbe457bf8e78a3512b7e5eeb3773182"},{"fromBlock":7073378,"toBlock":7073387,"address":[],"topics":[null,["0x000000000000000000000000e85430a51bd131905219bb2460fb893f48236cef"]],"resultHash":"0xe0462a6f16982666246fb152f4e8d5c9d81b7ec46bfab613f5d2598ee51c1130"},{"fromBlock":13075441,"toBlock":13075485,"address":null,"topics":[null,null,["0x000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f"]],"resultHash":"0xa7d2a88a785757f792377f6f6d03a10fd20c3f995efa863e2fe6a018f3ec97cc"},{"fromBlock":13040614,"toBlock":13040630,"address":null,"topics":[null,["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x02b4327502aeb94ff702463328f0bacf50f445e18e06fa0e570dbddfd9f7ccc3"},{"fromBlock":3954664,"toBlock":3954674,"address":null,"topics":null,"resultHash":"0x1886b8f9a54ffca51ca560f3354433f04b45936275c00728271483acfad5fe90"},{"fromBlock":3534815,"toBlock":3534863,"address":null,"topics":[],"resultHash":"0x7c5066ac63ee9199d9623c266829ad8a84ff440beead7d21bb1db855b82a45eb"},{"fromBlock":16000075,"toBlock":16000102,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[],"resultHash":"0x9b29fa45c0f1b4d269b3ac19dd578c581964da81c7e8bb5e2d8a39faee489f45"},{"fromBlock":9706995,"toBlock":9707003,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[],"resultHash":"0xc8ffb4a53fc71a442395bb7e106598d4d7124463b7338e6830867fec532f6e70"},{"fromBlock":14653403,"toBlock":14653417,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"]],"resultHash":"0xa40221cf6e90ec690106e0e37986a8885231496cd9c07b57ca521e6e372b9b67"},{"fromBlock":14526516,"toBlock":14526521,"address":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],"topics":[],"resultHash":"0x2acdeb10ecc00acdbbfad1670556434fae16e444700a0c0a2311f646349aa0cf"},{"fromBlock":3798476,"toBlock":3798489,"address":null,"topics":[],"resultHash":"0x6941e0c609e169a8246fdba41da76e129841ef3c66255648b8f4bf63672e7f71"},{"fromBlock":11933759,"toBlock":11933800,"address":["0x62b9f8741bf53a6986a5411c0557c30f6f11f3af","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x9cbfb60a09a9a33a10312da0f39977cbdb7fde23"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b39459616226deab278e1b2bd230309a27f98139","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],null],"resultHash":"0xf43d02433a55c175100589e4dcd0e6bb0abf94c72eacfb1f0f7bd56d99323066"},{"fromBlock":13040518,"toBlock":13040554,"address":null,"topics":[["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x0040691b9a3ed238f545b565514a9f17b56bc372cdd37b74577ca7a4e6410543"},{"fromBlock":19478184,"toBlock":19478192,"address":null,"topics":[null,["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],null],"resultHash":"0x244734a8355fb8625c60ca4ba7b96f6b3c500b90e7809e351802788cb70ca51d"},{"fromBlock":13037481,"toBlock":13037496,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"]],"resultHash":"0x4ca5f1663227b795cc7f7b8b82b48090e97d791f9ae1ed0d9b80abf6a2b3e024"},{"fromBlock":4057591,"toBlock":4057602,"address":null,"topics":[],"resultHash":"0x127510ac0a7a4fb4007ae4642187385040757c61b596925f9857e92b51b51a13"},{"fromBlock":5321269,"toBlock":5321277,"address":null,"topics":null,"resultHash":"0xfa1efd8188c42f3d3166d64f852334e43a61c1d3b9f306b1071267ae06b89efc"},{"fromBlock":14192957,"toBlock":14192993,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x0b697c79cfe172c0332a36e031041f436a8b4efe75a921b7809c68a676062e3c"},{"fromBlock":6849906,"toBlock":6849908,"address":null,"topics":null,"resultHash":"0x85a1d052c2acfd21d7e07e3aad22862e9ff77dc32f5583559c01d179c75ecd0d"}],[{"fromBlock":8051936,"toBlock":8051937,"address":null,"topics":[null],"resultHash":"0x9753425f53709b696f691db20a8be8c4f5d4d45040ba5fb4409fc3714b6260dd"},{"fromBlock":8051931,"toBlock":8051932,"address":null,"topics":[],"resultHash":"0x51e6477ec4928d5fca5dafc8beabe45a668e56b0d6af37513981c55720f52b9e"},{"fromBlock":8755456,"toBlock":8755457,"address":null,"topics":null,"resultHash":"0x4065049eb50f41ef1a9739431707b6505b83f487782debadd285df60294b5757"},{"fromBlock":9984803,"toBlock":9984803,"address":null,"topics":[],"resultHash":"0xd7bf03b75ce2dfc026cc66c02d8fe2c22a38415ee7d1ef837503ce75735a6717"},{"fromBlock":5357794,"toBlock":5357800,"address":null,"topics":[],"resultHash":"0x874ffa42a5681b70ed2975700612b2ab23bc31b198d1aa54c6c80318ed4d7acc"},{"fromBlock":6261430,"toBlock":6261431,"address":null,"topics":null,"resultHash":"0xa58a13ccc23766ee71631bf60e7ba4853dd68c92a8dbbb5e19d18883ed67fe69"},{"fromBlock":12205713,"toBlock":12205713,"address":null,"topics":[],"resultHash":"0x4f0c3710e46718b1d085aaa9b8f291a7a950d8e5cbc121df6aec2d1ed5f2278a"},{"fromBlock":15729905,"toBlock":15729906,"address":null,"topics":null,"resultHash":"0x35e53ed17942c5b42563f250d56d9627bbb99b91b043a051b8e817ba3e119dc7"},{"fromBlock":9632316,"toBlock":9632316,"address":null,"topics":null,"resultHash":"0xcac49d3a44404ac4a210768c820400022383bb2622544ef2ec2f0b5c0400b517"},{"fromBlock":5108707,"toBlock":5108710,"address":null,"topics":[null,null],"resultHash":"0x6d2a39d169ffb5830bfcad74fc0f02792fd4272b792a161a5739476bb61a4b66"},{"fromBlock":12205713,"toBlock":12205713,"address":null,"topics":[],"resultHash":"0x4f0c3710e46718b1d085aaa9b8f291a7a950d8e5cbc121df6aec2d1ed5f2278a"},{"fromBlock":14891535,"toBlock":14891535,"address":null,"topics":null,"resultHash":"0x0f4aea3fa540c1642f06a1bbc4019595043fbc28928e4ad84369d362e6dc4c0b"},{"fromBlock":14610199,"toBlock":14610199,"address":null,"topics":[null,null,null],"resultHash":"0xaa4c4354adf1b9d001cfe5959e2801751cf1d8ab7d657cc7b646df05da114817"},{"fromBlock":14125651,"toBlock":14125652,"address":null,"topics":null,"resultHash":"0xcbb82b4061f940ab9a8d4347b4837ec679340f0e112b4d0b8f07aea2afdb7c3d"},{"fromBlock":13041042,"toBlock":13041042,"address":null,"topics":[null,null],"resultHash":"0xa7613d3e4271423a873c2ab331a8bc863dba50e2adfff6a63511bd32787f0e84"},{"fromBlock":10475739,"toBlock":10475739,"address":null,"topics":null,"resultHash":"0x787da3276e8411d8382b830faa0a3cc604e2688c65c5474a7cd7e6c359d809b7"},{"fromBlock":14865839,"toBlock":14865840,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0xf63d66dba89cda4fd24f25db2aa384009dcb961f8a2b6fa136d0873e06c44d05"},{"fromBlock":10117726,"toBlock":10117727,"address":null,"topics":null,"resultHash":"0xd289d38ed73842aed26af0ca8ec5a118ea492f80cc08896a8523bbf398d45a1a"},{"fromBlock":7466201,"toBlock":7466203,"address":null,"topics":null,"resultHash":"0x1252f6f68863353d5d0fe3b0cc495c71b29124d3ff818c601c2601d9aa961b2b"},{"fromBlock":6073249,"toBlock":6073250,"address":null,"topics":null,"resultHash":"0x32297feec66dc9d2930ea3dec7ae487060ccd40072511c8b81f98a2c9da7fa6d"},{"fromBlock":14000155,"toBlock":14000155,"address":null,"topics":null,"resultHash":"0xd9fde4dec8fadc9698e883832c31558f33e47012b9889d23c1e782dcaa9ed509"},{"fromBlock":12976693,"toBlock":12976693,"address":null,"topics":[null,null],"resultHash":"0x29397c88ad5b397aba5f7b937079ae4a056827d9cbef3bb1e143528d3c7f45c7"},{"fromBlock":9870632,"toBlock":9870632,"address":null,"topics":null,"resultHash":"0x42fc326ec7089f4be6a4722f7fc838f159514ad3c81dcdd171881b7d4f1757d2"},{"fromBlock":17115803,"toBlock":17115803,"address":null,"topics":null,"resultHash":"0xace584e27fa6a079931d0c04dcfdfd0a46efc59283b794c93b4dddd4b21fc4bb"},{"fromBlock":14440278,"toBlock":14440283,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0x4ea33e061f4ecdd23601f412f2ecef6933bb73a6f9ca572eef4a8de8b21ea325"},{"fromBlock":13041388,"toBlock":13041391,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null],"resultHash":"0x09f277fbca0bf70bf1282b96ad57db83c92ec5d38e12621e952b412a347c1448"},{"fromBlock":8755456,"toBlock":8755457,"address":null,"topics":[],"resultHash":"0x4065049eb50f41ef1a9739431707b6505b83f487782debadd285df60294b5757"},{"fromBlock":10956087,"toBlock":10956087,"address":null,"topics":null,"resultHash":"0x0fec5062bed616ca21bac660f9dae1455edfaf8ec35189d4cdbea13a8c8f4876"},{"fromBlock":14440281,"toBlock":14440284,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0x3998592b753c60eaf6bca5307f369ae5f82eb24eb66a70ef834a7fd7142fb220"},{"fromBlock":7073381,"toBlock":7073382,"address":null,"topics":[],"resultHash":"0x047da2ebf97c1804cb1637bc32b8e6f8fb2646c60f4b4fa90080ad06b5978307"},{"fromBlock":20534257,"toBlock":20534257,"address":null,"topics":null,"resultHash":"0x18c8403db561cf765999371b2e1c302856b971c8c86ed23b0eddaf6c0707ea07"},{"fromBlock":12205713,"toBlock":12205713,"address":null,"topics":[],"resultHash":"0x4f0c3710e46718b1d085aaa9b8f291a7a950d8e5cbc121df6aec2d1ed5f2278a"},{"fromBlock":21467845,"toBlock":21467845,"address":null,"topics":null,"resultHash":"0x8c123e8ed4d360a8008455b994f7d9e965607d8896fcf6a707e63823c1ee8bd1"},{"fromBlock":10448364,"toBlock":10448365,"address":null,"topics":null,"resultHash":"0x2d250208dc2ffd44b2da87843a93ecd712a8a7d48117d78fd3ed84ae76301c58"},{"fromBlock":11977389,"toBlock":11977389,"address":null,"topics":null,"resultHash":"0xab1def45ee00251e752e849cc7258251066a5ba8b9bddf497d5c4a1cda2475d5"},{"fromBlock":10298764,"toBlock":10298765,"address":null,"topics":null,"resultHash":"0xe27f8f01b5c7c89cf120f18cbab02b9ebb08157694762294d6e2641af326d2ad"},{"fromBlock":5507052,"toBlock":5507055,"address":null,"topics":null,"resultHash":"0xfaecb393c494e8269a40605e075a17d8a817d4d2605e33c6a5ae80f5e1231333"},{"fromBlock":15845368,"toBlock":15845368,"address":null,"topics":null,"resultHash":"0xde95cb3bd96801400a838bfba5613b6d8a3fbe3a35782f0f78971dd918e5b43e"},{"fromBlock":8750142,"toBlock":8750142,"address":null,"topics":[null,null],"resultHash":"0xc2576c79cf8145ade5531ca6518f2ce54333ea3dec8b573d27c2fd81d5e132ce"},{"fromBlock":5039791,"toBlock":5039791,"address":null,"topics":null,"resultHash":"0xefbc929f93b03983d93f6de27f4d7a4b0da3b5b3f288f1cb4b2663196ad6c030"},{"fromBlock":12574970,"toBlock":12574970,"address":null,"topics":null,"resultHash":"0x776e9e868c5906b72cf1cebdb4eaa604d4c23db83eec7ba28ae6da8cf552d517"},{"fromBlock":5290013,"toBlock":5290013,"address":null,"topics":[],"resultHash":"0x24b169ae5d6425e749e312bb81bc5d609f4aab010eb0672fab7570c3479b5cf6"},{"fromBlock":6594645,"toBlock":6594646,"address":null,"topics":null,"resultHash":"0x3ec18e24709747cf29ae27dd05aa97a05fa86b073326991109b7a2fb370b6a48"},{"fromBlock":16430371,"toBlock":16430371,"address":null,"topics":null,"resultHash":"0x88b7c11ef5851d4d92b2783d00b4621968ec3c2e604d6cc036e4ce97a1e4a2dd"},{"fromBlock":8148296,"toBlock":8148298,"address":null,"topics":null,"resultHash":"0x91ec757d189b7611170553ffdbc4a31e6e8b5bc99393a11cdf773873d5d0d1ba"},{"fromBlock":5912147,"toBlock":5912148,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x28767a8ab268adaf8551f940f4a99e9c102b36d75f161ec45353f72df3da6d36"},{"fromBlock":8568129,"toBlock":8568134,"address":null,"topics":null,"resultHash":"0x91340874bf456ae66e5fe471703b8d97ced5bacc90553490fc8ade92acf462f6"},{"fromBlock":7073381,"toBlock":7073382,"address":null,"topics":[],"resultHash":"0x047da2ebf97c1804cb1637bc32b8e6f8fb2646c60f4b4fa90080ad06b5978307"},{"fromBlock":13785440,"toBlock":13785441,"address":null,"topics":null,"resultHash":"0xe3d109e6a1c642cab7ce89e3191d99387898604d76fa1fefd48b954878af6e01"},{"fromBlock":16465844,"toBlock":16465844,"address":null,"topics":null,"resultHash":"0xbfa68a6a779c57d2faa4bd11fafedd3b111145ecba23af0421f9fbf71c01ebfb"},{"fromBlock":6825405,"toBlock":6825406,"address":null,"topics":null,"resultHash":"0x5cf327789f42aa42d6811f86a69627673e327d6f02564a029ca50d26d13ef6a0"},{"fromBlock":6672946,"toBlock":6672947,"address":null,"topics":null,"resultHash":"0xf6a802c71d3d12b3de0fd3ae42203fe8a074caf2c541ee77f7761c9cfb920b84"},{"fromBlock":14559412,"toBlock":14559412,"address":null,"topics":[],"resultHash":"0x6e39afe11c1a36b4645f7092bd856a1c47fd26ae751fe5116ed0f2416d7ab3b4"},{"fromBlock":5304480,"toBlock":5304481,"address":null,"topics":[],"resultHash":"0x388790a0f1018778c1d8c5a8fd1c947c84da06e5692dd43a001c225b8f0c1a96"},{"fromBlock":8051932,"toBlock":8051933,"address":null,"topics":[],"resultHash":"0xe9312ae1d001320ea05848334917bcd4903f7ba04efcb09600b1e71c8514916b"},{"fromBlock":12702839,"toBlock":12702839,"address":null,"topics":[],"resultHash":"0x5f4f28e6cfddc0978c90a07fb20b75ed98d2d1dddb4d2cac091aa676e0d1dc38"},{"fromBlock":14509035,"toBlock":14509039,"address":null,"topics":[null,null,null,null],"resultHash":"0xed7af39049721af06945efebeffd45766a94a0aed11bdc4220b7760e7d7cf03b"},{"fromBlock":15729905,"toBlock":15729905,"address":null,"topics":[],"resultHash":"0x54af891df694b0dc265c905ad258cc9a434cef1ba79cdd9ff81bfca9ea24d426"},{"fromBlock":10537179,"toBlock":10537179,"address":null,"topics":null,"resultHash":"0x53f4ad8bdc5055119d21c57978e818ed94801fb338a5527d81fb45663170e2cd"},{"fromBlock":21464471,"toBlock":21464479,"address":["0xdac17f958d2ee523a2206206994597c13d831ec7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x8d6107f63a3698f71f24353622cf968852e478b74c421449555c966c9e09b120"},{"fromBlock":7073382,"toBlock":7073383,"address":null,"topics":null,"resultHash":"0x2ae3a44010d35a515b9e7a1d97bd7330b619329c460ab26a062dff5f87d96b82"},{"fromBlock":13047787,"toBlock":13047795,"address":null,"topics":[null,null,null,null],"resultHash":"0xf17aad2c3583494036d43609e2718e760a01062cdceeb1159ecbce9660ef80de"},{"fromBlock":9984803,"toBlock":9984803,"address":null,"topics":null,"resultHash":"0xd7bf03b75ce2dfc026cc66c02d8fe2c22a38415ee7d1ef837503ce75735a6717"},{"fromBlock":9157387,"toBlock":9157388,"address":null,"topics":[],"resultHash":"0xfbe3aac345b6479516984b349846b9f226bfc041590d80a1ef675e173a9dc586"},{"fromBlock":14526512,"toBlock":14526513,"address":null,"topics":[],"resultHash":"0xbd5ff6b4a72b9c74fafd25cc1ffbd7e8b37b6a46426dca129148bb220305a7d6"},{"fromBlock":17583500,"toBlock":17583500,"address":null,"topics":[],"resultHash":"0xf67f72eeb2888d3b7c0febc36aec0466f6522a8a354e2c9ac98f1a5796c5f47a"},{"fromBlock":20052976,"toBlock":20052983,"address":null,"topics":[null,["0x0000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad"],null],"resultHash":"0x4d14aa296546b1ccd1106cf88526df80e80d741bf348c3eec3c117aea54ac0c1"},{"fromBlock":7314304,"toBlock":7314305,"address":null,"topics":null,"resultHash":"0x42052c2967021cc5e8c8f746d97e7ea4a60eca2dd0e067b261180313f6dea5c5"},{"fromBlock":15729905,"toBlock":15729907,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x1598ab153f5da806aedcbf1ea505d712b95f54e6516b9e1e571689328d4e4b67"},{"fromBlock":7268103,"toBlock":7268104,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xb4eaa2c40a9dc9ccc53d65305e1d31398f69565e578b60cac2d8da1a8a54e014"},{"fromBlock":7453627,"toBlock":7453630,"address":null,"topics":null,"resultHash":"0xee2036cf643b7c8cd3131413e1eb02556ee180ea9d0493fb2a68e4c211af3493"},{"fromBlock":18178255,"toBlock":18178255,"address":null,"topics":null,"resultHash":"0x52937682f9d5ae4e234ba97a2a0bf438639ab5b5916e9964702cf740fa291363"},{"fromBlock":15373193,"toBlock":15373193,"address":null,"topics":null,"resultHash":"0x3ee396c19ddb10733e2d325eed00840173489a11462470f4bd5ab7c68ba89b0c"},{"fromBlock":11392189,"toBlock":11392189,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x8fccc6ddb867e3345a8f794a0a67f47dcbfc1606643b4d48b40765b0a8276dcd"},{"fromBlock":9523960,"toBlock":9523962,"address":null,"topics":null,"resultHash":"0x8ef63694085491efe0434e22e7ca0b1f7150dcc7bf2969850436b9cfd6f2fa1b"},{"fromBlock":14728967,"toBlock":14728967,"address":null,"topics":null,"resultHash":"0x23f62d332ef9bf2b648bf710f1efd12ad3eec86befdee64f1bdf862b7dae8e2e"},{"fromBlock":21709514,"toBlock":21709514,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x5e8d1be716f8cb538f25f22a994c7a927d4a64c70433ab9176f6095552181964"},{"fromBlock":12702839,"toBlock":12702839,"address":null,"topics":null,"resultHash":"0x5f4f28e6cfddc0978c90a07fb20b75ed98d2d1dddb4d2cac091aa676e0d1dc38"},{"fromBlock":20778343,"toBlock":20778343,"address":null,"topics":null,"resultHash":"0x58a6bf22fc64d9e8d93d9dc0e59033261415c079001dd7b18348cd3ba498e421"},{"fromBlock":15845368,"toBlock":15845368,"address":null,"topics":[],"resultHash":"0xde95cb3bd96801400a838bfba5613b6d8a3fbe3a35782f0f78971dd918e5b43e"},{"fromBlock":15840964,"toBlock":15840964,"address":null,"topics":[null,null,null],"resultHash":"0x9bccdb653a88ed119feb06b47c9a51555f05384ebdd3e4149a0d930ac55b7071"},{"fromBlock":14559412,"toBlock":14559412,"address":null,"topics":null,"resultHash":"0x6e39afe11c1a36b4645f7092bd856a1c47fd26ae751fe5116ed0f2416d7ab3b4"},{"fromBlock":18890411,"toBlock":18890414,"address":["0x86ecdc01c4a06a35e69659488c70546a06713ae4"],"topics":[null,null,null],"resultHash":"0xc94d915783355ff9fb4035a81e547a7fa475b88357a2183c606f204e0cca45a5"},{"fromBlock":14238413,"toBlock":14238415,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0xd46c0e31def1b92cad1b15e253cf78d8d811aa95b3c6185ce2d5c4a0a34a2173"},{"fromBlock":20799204,"toBlock":20799204,"address":null,"topics":[null,null,null],"resultHash":"0x76c44d4126a0695f117a869e9075bf1c8a41c5e040b6711294be1f5e54019c54"},{"fromBlock":14349534,"toBlock":14349534,"address":null,"topics":[null,null,null],"resultHash":"0x738743b021626c5336a923e29a80e5d8aab0f99d9f2cf32a9f58afa2e7a020d6"},{"fromBlock":13037490,"toBlock":13037493,"address":null,"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0x055c2d086674abed5783ad5def47f470ad8a829457cfb1c9556cce6693bbd60a"},{"fromBlock":10661759,"toBlock":10661759,"address":null,"topics":null,"resultHash":"0xd3f5f3a5e28e099f677d661bd3eb52ca64f51d1c00da69ed0706849c205b7883"},{"fromBlock":5039790,"toBlock":5039791,"address":null,"topics":[],"resultHash":"0xa7704646e76483f000466cd030439a2e8b2e9c9fa39aa44fe85bea9e3f61eca7"},{"fromBlock":5290012,"toBlock":5290013,"address":null,"topics":null,"resultHash":"0xf1de99306efe4744146d2c40c5963b780bc5e871301cd60772c006060e78b360"},{"fromBlock":6814291,"toBlock":6814292,"address":null,"topics":[],"resultHash":"0xb9570e970afdd43ade72d2d42f80219fea37ae836b5da85162ad1d7e56547877"},{"fromBlock":13785467,"toBlock":13785468,"address":null,"topics":[null,null],"resultHash":"0x1cb41023a7db0338e770b5cad202888b10e8fad0027ed832d32ea21390b19318"},{"fromBlock":9687995,"toBlock":9687996,"address":null,"topics":[],"resultHash":"0xbcfa0e95029ac4d27509a19ab4bd724d55e813b70acd50f7b7337e2437ed10f1"},{"fromBlock":12205713,"toBlock":12205713,"address":null,"topics":[null],"resultHash":"0x4f0c3710e46718b1d085aaa9b8f291a7a950d8e5cbc121df6aec2d1ed5f2278a"},{"fromBlock":16986593,"toBlock":16986593,"address":null,"topics":null,"resultHash":"0x1936d87df56e1afb9cce9bba19ea2df1f8a86404bfb2feb61eb8b2f53f232719"},{"fromBlock":19238253,"toBlock":19238253,"address":null,"topics":null,"resultHash":"0x1132ab18e2c347e0190668455fb682b9950956fdfaaba243572e79ef0b2e990b"},{"fromBlock":12205713,"toBlock":12205714,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xee86e29f44ab3a9cd2a527deb5c4aca4676cda37cc0a5a5e14ede73cb6dda425"},{"fromBlock":9147389,"toBlock":9147390,"address":null,"topics":null,"resultHash":"0xc463513835c6ff58ee188b50682183bfbc6cc1b15818eb1570674da1f3047999"},{"fromBlock":13040442,"toBlock":13040443,"address":null,"topics":[null,null],"resultHash":"0xe9ff3039e1235ffca998b05895ed8eae8cb586c9931fd782c648532150769f3a"},{"fromBlock":8051931,"toBlock":8051932,"address":null,"topics":null,"resultHash":"0x51e6477ec4928d5fca5dafc8beabe45a668e56b0d6af37513981c55720f52b9e"}]] diff --git a/cmd/workload/queries/filter_queries_sepolia.json b/cmd/workload/queries/filter_queries_sepolia.json new file mode 100644 index 000000000..e9d40387a --- /dev/null +++ b/cmd/workload/queries/filter_queries_sepolia.json @@ -0,0 +1 @@ +[[{"fromBlock":329160,"toBlock":7369873,"address":["0x7451ee8eecf3b8534fa07b15b4b5cee4bcc88778"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"]],"resultHash":"0x25db53749138a4c37510a0805ae166c507f3acae2ab12a530deae7655f2823f8"},{"fromBlock":0,"toBlock":7713721,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x00000000000000000000000000000000000000000000000000000000000016b0"],["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0x4b9354c69b4847cc33ddbf4d99b1e118c051371df0c9beb4f4cf26bd4d81e927"},{"fromBlock":0,"toBlock":7665156,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x00000000000000000000000000000000000000000000000000000000000016fc"],["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xce425b1bb2c807961ebf20a91f40e702d0d102352517458aad37e50151b2f3bc"},{"fromBlock":0,"toBlock":6875691,"address":["0xa777279ac63f977bddd294f33e3cdb182f900ac5"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000277b56a340"],["0x0000000000000000000000000000000000000000000000000000000000001410"]],"resultHash":"0x0e83f0594962b8562c38fefedeeca04e812fa96ba51bec788eede056b5a90afe"},{"fromBlock":2364138,"toBlock":6984783,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000000000000000000000000000000000000000000346"]],"resultHash":"0x32724d34432774ced966156e39eddbf1a756d0494289f64f2099880e5832d896"},{"fromBlock":655698,"toBlock":7755800,"address":[],"topics":[["0xb9fa1caa1e1541788a4b5cd68270e6d375e3a28f4f94017af9351c5955d58fa7"],null,["0x00000000000000000000000000000000000000000000000000000000000017b0"],["0x000000000000000000000000093132745c59e283668783cfc75be29a9090bbdc"]],"resultHash":"0x4e5de76ee4910cb171491add2f62074ab851a7e395fb11adc4d8732c24718f55"},{"fromBlock":2797035,"toBlock":7755769,"address":[],"topics":[["0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0"],["0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000e3a73cf48dd65a92f03cbf2bf85fad1fab8b32bc"]],"resultHash":"0x600f6fca4007f0ba0892d80297a8dca7d7b65cfea8ea8f708b96b088127e8949"},{"fromBlock":658060,"toBlock":7082999,"address":[],"topics":[null,["0x0000000000000000000000001b89a43d543260fee7e0cad06a4b3b1beab20527"],["0x0000000000000000000000008f73f932d0310ec85731648bcbacf2de3b60bb0c"]],"resultHash":"0x74b50821877454def9388a8e4fb9496d91eb71ef4ce1b414bdf74f14ab4c3388"},{"fromBlock":1487735,"toBlock":7755769,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271","0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],["0x000000000000000000000000c98326d3c5afe5c76799bf97385321d52bf1927a"],["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x5fad9f825436f3041030a2df2b23c8f428ce44161d1a9d68399325f3233b02f1"},{"fromBlock":0,"toBlock":7714615,"address":["0x55679e247913942bdaf980a26c2e814203e8e012"],"topics":[null,["0xfd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x6affe85e9269f82072e76b72605c34b9b4b44a6d53a3869d157597158c22a52c"},{"fromBlock":191174,"toBlock":5649601,"address":["0x55679e247913942bdaf980a26c2e814203e8e012"],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5"]],"resultHash":"0x04169538996f1dbed7206b61b407a168d3b37172ddcc1d031caad97e68f975a6"},{"fromBlock":0,"toBlock":5559009,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],["0x000000000000000000000000000000000000000000000000000000000000145e"]],"resultHash":"0x6f727b53a1e78267db08f9a4a834c4c7aae17f44611773467f31500cb158bc2d"},{"fromBlock":0,"toBlock":6959720,"address":[],"topics":[null,["0x000000000000000000000000ec25efbe53018c4a7c3c5f959ad52a4c39fbd8ef"]],"resultHash":"0xfb26697132fb58e78ac7d7a28e110f32f50126f41757919424d4ee26345d5653"},{"fromBlock":429456,"toBlock":6285336,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000003fedafc30a6c9da74d22084d67d7e7fef2c1ea97"],["0x0000000000000000000000000000000000000000000000000000000000000364"]],"resultHash":"0xc5adbfc48e7dd40ec5812717607f720939c82c401b1ae2a9b592f05ad01b7ef9"},{"fromBlock":0,"toBlock":7246717,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x00000000000000000000000000000000000000000000000000000001636c28c0"],["0x000000000000000000000000000000000000000000000000000000000000165a"],["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x81fdcd3e13ceebea3deaf279e9830b471b2952a98196bc9694d0e865f72cd37f"},{"fromBlock":697441,"toBlock":7210145,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000cf581dbfa198e4b31e7cb79a5c23f25e8282eac4"],["0x0000000000000000000000009ea18de905e654f9fb98498109c60edfe133c145"]],"resultHash":"0x13e2b48c3b7a885d9ca03421babff65d9fbd1b510d30915b45fa99233face744"},{"fromBlock":1006390,"toBlock":5566214,"address":["0x22c1317fe43132b22860e8b465548613d6151a9f"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000c48d2559dcac2c87de79c0bdc4aed3a3dbb54fff"],["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0xcb9892fb7cd0f1c510951197e60e5272712ceaf1b52032a5a2d6191efe22842b"},{"fromBlock":0,"toBlock":6435215,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x000000000000000000000000000000000000000000000000000000000001ad4d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x683916e4f4bf0e6cda3a4c8a5d84722a312ae06daa8bf3eb2e2de6a7516bf6e5"},{"fromBlock":492944,"toBlock":7755769,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002afd"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xbb1f814b0ea567a45cdfe3a2577bc6048327608e7ee010fca9f28736c6d66544"},{"fromBlock":1106931,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000000000000000000000000000000000000000001fc"]],"resultHash":"0x6ee7afc9db91ce14c6af3222975cf81641b3045d1a90f51593b22b7001c350ef"},{"fromBlock":65384,"toBlock":7755800,"address":["0x666ca6fc75b44f3ff2d321c5947031141409b152"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000005db2"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xb914252b9263ebbd8d1a2e1cf3f0900f3640d988f744f6a01762ec65fb5118a6"},{"fromBlock":134126,"toBlock":7755769,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002ada"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x49e36f2defbc6bbda0f18c7969aa07ddd4461088b4ce1b567bd6457d85762195"},{"fromBlock":1153907,"toBlock":7755708,"address":["0x08394e7e653472694ecd4527656b2881e5701a14"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000062c2976bde177248e359eae3245cfaeba22a1bdf"],["0x000000000000000000000000321ce961084fcf3a56de4be2f2006707a0421aa4"]],"resultHash":"0x66bd6e704003650f5c1ecc139204182f1cd608f6485af126764fc2f3b8e9b284"},{"fromBlock":1477743,"toBlock":7755769,"address":["0x182ec567f33ac802e9e80c0a0bbe7610d5923e0e"],"topics":[null,["0x7fccf3cf41117a39dccbb957bda719d39cc8a68c8be4b55897b49be6e571feff"],null,["0x000000000000000000000000000000000000000000000000000000000017d39c"]],"resultHash":"0x9e54120991b987854b13772ddab24bcc1f25feb8b191580eb8dc1f8b4983b352"},{"fromBlock":658060,"toBlock":7082999,"address":["0x2df684c8f22f87200f1860ca0856d4410a07fcb9"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000001b89a43d543260fee7e0cad06a4b3b1beab20527"],["0x0000000000000000000000008f73f932d0310ec85731648bcbacf2de3b60bb0c"]],"resultHash":"0x23f5aff5f9675955263dfa5b8602a9d6bd8ca2408b136f177a393aa7c5ad2f42"},{"fromBlock":1466011,"toBlock":7501340,"address":["0xbd3cf0422ac029f46f12a3dcfb9bc0d90a7665d8"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000000000000000000000000000000000000000000fa"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xbc7a95ef941f5ff4d6c25bbe0adf62dd1288c10cbafcb086688ae34976080299"},{"fromBlock":1562615,"toBlock":7079448,"address":["0xd4eaf2a5da8c51a30c245ad71a0b93f39fa1ec53"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x0000000000000000000000009b38debc05d4a2145c11e1effb6c6f7216178232"],["0x000000000000000000000000d1292d09173fc26cb82ddcc047d5d19f7369d56e"]],"resultHash":"0x326a032c461af6c1dc2028e152895bb2daee22cb05a252bf69094d89d0991352"},{"fromBlock":2002816,"toBlock":7755769,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],["0x29233435440149c2f178675f72d5fee66628ecb7950abbefcfeca71f773b72c4"]],"resultHash":"0x3f912f4880a1331f6ab24917aa7e664562c88ffdb3a73b4ea1b0ff4ee8eeb1ba"},{"fromBlock":191174,"toBlock":5649601,"address":["0x55679e247913942bdaf980a26c2e814203e8e012"],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x04169538996f1dbed7206b61b407a168d3b37172ddcc1d031caad97e68f975a6"},{"fromBlock":538836,"toBlock":6372228,"address":["0x2dec7530742c2c0039f8c466afffb6e39f171d8b"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null,["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0x0371b629b27c18371b9001118715517b74dc26135b45dd4403b2293b1f223790"},{"fromBlock":1466011,"toBlock":7501340,"address":["0x0a69d6b0671ef71bf69f8f33e426f3da46d4d8c5"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000000000000000000000000000000000000000000fa"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x94ca2b27f71399f8cfa36eb71869758237e9521a8bbbee507ed3a7908ab076bd"},{"fromBlock":270240,"toBlock":6693893,"address":[],"topics":[null,null,["0x00000000000000000000000000000000000000000000000000000000000d0b39"]],"resultHash":"0xa0f778ac764047894a84a885948a9eadd21d74c075c74b8550eac447728fba52"},{"fromBlock":413856,"toBlock":7410314,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000015e2d62c0"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xf153c0c2a0b90ffff6b289a98cbee8bd13b00afb9de51dd1a956e745a8469b12"},{"fromBlock":678703,"toBlock":7755800,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002a76"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xadbd2bf9ef8a7d4a763bf963b1fe115a3edd130b85849cadd33c8cc10303ddbc"},{"fromBlock":473395,"toBlock":6071332,"address":["0x4b5011c89f3e727b71e113334e36ff70972a969f"],"topics":[["0x27333edb8bdcd40a0ae944fb121b5e2d62ea782683946654a0f5e607a908d578"],["0x0000000000000000000000007f2698714842f59e89f1eb8b1b70ccb053b5a176"],["0x0000000000000000000000003367dfa11e3148a07c2da773e1f65b155b0abe56"],["0x00050000381eb7d25d5a6d99b343042fe9e4e219ffa955b70000000000000c33"]],"resultHash":"0x793e4939f0b3fe62ba1bcb3fb67ab1708a29257a9d03a2a99380333700780d78"},{"fromBlock":319574,"toBlock":7658479,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000002716b6c0"],["0x0000000000000000000000000000000000000000000000000000000000001459"]],"resultHash":"0x1d69427c35c9933579010801259ae1f445af26496a696676635898ec30650eeb"},{"fromBlock":730800,"toBlock":5387842,"address":["0xfbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],"topics":[null,["0x00000000000000000000000084141972ee5ded3fd5c21f099007c4f64080ab76"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xde173ea745f3972187ed784be19c7e4d28cd594a23035d3ea65b2867ad23ff1e"},{"fromBlock":2930524,"toBlock":7755769,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002b0a"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x92dd14d70aa964b592be3de4091ddb9f7a3a327ee163f1341866ac621e6777be"},{"fromBlock":501967,"toBlock":7114558,"address":["0xd4eaf2a5da8c51a30c245ad71a0b93f39fa1ec53"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x00000000000000000000000035fbb60f453a9abf3b6aa27451a0b83f00256265"],["0x000000000000000000000000d1292d09173fc26cb82ddcc047d5d19f7369d56e"]],"resultHash":"0xfb9107e9b16acced8a14d0bf264b8d6fb8cc7799c49be7a85dd032064fa51358"},{"fromBlock":3072436,"toBlock":7755769,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],["0x2828326ef1e3d5c84d222f081bd23ce9481e732fe9eda1a704538461aadfe64c"],["0x000000000000000000000000000000000000000000000000000000000000358b"]],"resultHash":"0x0eb32d9e396f973734f56a1c0c8fd95d808ab55770b0a922e922ee64a5ee6ec1"},{"fromBlock":0,"toBlock":7189296,"address":["0x1f1df9f7fc939e71819f766978d8f900b816761b"],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000001cdb5"]],"resultHash":"0x110a53e1aab1bdf65ac54b616b1cd16acc783b7653246256ded91321d18399bf"},{"fromBlock":0,"toBlock":7659342,"address":["0xe3e87577bf7abfaca3b3ab37ee3521eca839506e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000eb680d091cb442db16e35d00c6cdb2cb9dda3f05"],["0x00000000000000000000000072b9c3c2847e0c09776c071b2610dec9521c54d6"]],"resultHash":"0x6f0f0792ab4200e9c8ae8b1f01bd16e36272fd94897f7af66ec06078db991f25"},{"fromBlock":0,"toBlock":7184764,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x00000000000000000000000000000000000000000000000000000000000016ca"],["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0x23ebd5098b97d64283c723ea464e3fd7425d11ce2e4e2e31ea3ab7b2fb290f9f"},{"fromBlock":1962203,"toBlock":7755739,"address":[],"topics":[null,["0x4e10fea446dec52edeae544909c2ee6217bb8c7e8d66af35305e9f780cf241cd"],["0x0000000000000000000000000000000000000000000000000000000000008809"],["0x00000000000000000000000000000000000000000000000000000000003fc4b0"]],"resultHash":"0x60fddfd775ebae4594ff2ce5af3d47a95d1c87d02b0d0cf4150623c53651f159"},{"fromBlock":0,"toBlock":7331384,"address":[],"topics":[["0x2402307311a4d6604e4e7b4c8a15a7e1213edb39c16a31efa70afb06030d3165"],["0x000000000000000000000000000000000000000000000000000000000001ad8f"],null,["0x8c27175bb5d6a1656aab86592e5b96ec499f9a5235a8719208942b6aaa7814c2"]],"resultHash":"0xa7ec12665c16f1f2eadabba7427f11e7cb8dd9ce6f74230cb5050c4f51d14216"},{"fromBlock":0,"toBlock":7689788,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000001cea2"],["0x000000000000000000000000c757f0742a5efa639de6ec9afbd899aaada5c4e1"]],"resultHash":"0x7b280fbbb2fed590f1b6263827dfc01471e4be27effd213b518c86bdf4b1fc09"},{"fromBlock":0,"toBlock":5559009,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],["0x000000000000000000000000000000000000000000000000000000000000145e"],["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xc354af61486916c6837ee9fc21db0c9b3c16661503369a137370eabe25170862"},{"fromBlock":1085910,"toBlock":7580612,"address":["0x8d171fcf12fcfcd88478834f5736ed058402344b"],"topics":[null,["0x00000000000000000000000000000000000000000000000000000000000000fa"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x25a5f27d7f45dd20cfb3a70b27e395269de115ad69592f886d0be4c8ac24c150"},{"fromBlock":0,"toBlock":6432433,"address":["0xfc6acfe4f69b41bf174230107e4b81b7b03bd91c"],"topics":[["0x51bbdc1d2a76e18752092da32318ce9d5ad268aae23f908efaf64aab614f8190"],["0x000000000000000000000000919663102b19fae17492a150bbf24a5196738441"]],"resultHash":"0x9607ffc2e2f85d617d30a8c67315223a912cddc2c60fd8f998d8387b8b885838"},{"fromBlock":1317354,"toBlock":7755769,"address":["0xbdd800ee3fe0300a4a1b702cbc8b836453eb3877"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000006b29975137d7de522bf6c4615051370c55820b3e"]],"resultHash":"0x7dcc1e578cae00d171c6360f07fa9bb7759b5669cb33ed06e46e16ae24b53ca1"},{"fromBlock":1172544,"toBlock":7755800,"address":["0x2a0f1c1ce263202f629bf41fa7caa3d5f8fd52c4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null,["0x000000000000000000000000000000000000000000000000000000000001f0e5"]],"resultHash":"0xc58ee10bc1f8140e2ba871d5e0ceba32cac63d723c651a26a709dfbc7b6132f4"},{"fromBlock":0,"toBlock":7029899,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000ed0bc1d60a1a58630dfab759150f9b35e2f8e6ac"],["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0xbe1723ec4affbdd4b2c96e1ee3ef0894843690a29aad18fa511343c4cad1ecca"},{"fromBlock":1019467,"toBlock":7755769,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],["0x000000000000000000000000b97ee3b6579c019aacdea9f90a34c7ea40b1ecaf"],["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xc03be8ce200dfaba250abcfa2221621c72e7cd9a6581738e3195987a1185756d"},{"fromBlock":40844,"toBlock":7755769,"address":[],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000000000000000000000000000000000000000000c3"]],"resultHash":"0x3c07cf517f9c95ec6c9fac65c543239308e446c5cbce655ad3b3db067244ac7a"},{"fromBlock":2676270,"toBlock":7755800,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271","0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],["0x000000000000000000000000f641fab94463451256938d7c9312aa1c58567942"],["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xb1f96269005bbcca36f978b0480295be7d0bcb878f06fc65b76d06314da69025"},{"fromBlock":2027722,"toBlock":7755769,"address":["0x1cd40deb4196d219097499031922ff690f9ea813"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000093b714330996f3dec51c455e4ac85f3864274fae"]],"resultHash":"0xa02d3cd63ea10c0707545f43460fbbd45dbb601ca7a5bbad1fa7f45524a3f93f"},{"fromBlock":2411824,"toBlock":7755769,"address":[],"topics":[null,["0x29233435440149c2f178675f72d5fee66628ecb7950abbefcfeca71f773b72c4"]],"resultHash":"0x3f912f4880a1331f6ab24917aa7e664562c88ffdb3a73b4ea1b0ff4ee8eeb1ba"},{"fromBlock":1268701,"toBlock":7755769,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],["0x861d4dea01ea22e402526c43d4edb4b0a8ed655cd76997e8f0527bc298cd65f4"],["0x0000000000000000000000000000000000000000000000000000000000008809"],["0x00000000000000000000000000000000000000000000000000000000003fc4b0"]],"resultHash":"0xc0eb6e399462a641a7aae1d86de90fe6c3bfaf2b9c17e424990a993663e3af7f"},{"fromBlock":145539,"toBlock":7755769,"address":["0x80ba15dcd21e3260ddf573daaa59cccd442c2109"],"topics":[null,null,["0x00000000000000000000000000839a4f507e16d3d8c0ed04068a6f9557e79e3e"]],"resultHash":"0xed2a05b4039712dba8cdf482cc7256f046bd436377510943c0c7cf38a4949ac8"},{"fromBlock":2501102,"toBlock":7608761,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002af4"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xc18579dc53345f29150d3e87af0b8312b5210a3a3dc5a1c164d146626ac8e626"},{"fromBlock":1477743,"toBlock":7755769,"address":["0x182ec567f33ac802e9e80c0a0bbe7610d5923e0e"],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],["0x7fccf3cf41117a39dccbb957bda719d39cc8a68c8be4b55897b49be6e571feff"],null,["0x000000000000000000000000000000000000000000000000000000000017d39c"]],"resultHash":"0x9e54120991b987854b13772ddab24bcc1f25feb8b191580eb8dc1f8b4983b352"},{"fromBlock":0,"toBlock":7331384,"address":[],"topics":[["0x2402307311a4d6604e4e7b4c8a15a7e1213edb39c16a31efa70afb06030d3165"],["0x000000000000000000000000000000000000000000000000000000000001ad8f"],["0x434ab18e74443aedaf60deb40b86a46652a31f8e7946b89e38d87010a8c71dfa"]],"resultHash":"0xa7ec12665c16f1f2eadabba7427f11e7cb8dd9ce6f74230cb5050c4f51d14216"},{"fromBlock":0,"toBlock":6091590,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x000000000000000000000000000000000000000000000000000000000000169f"],["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x1206d4af9287217417eda7c7976c211afe9b752201992f34ab0fcdc2ad310e71"},{"fromBlock":779060,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000000000000000000000000000000000000000002f7"]],"resultHash":"0x3c6d85093272d0b7655dde7e5c1dafe0f3ed40b7d510e560d6d84f29e6ce37cc"},{"fromBlock":1522662,"toBlock":7755769,"address":[],"topics":[null,["0x10862ada1ca9077572160e37d2c6def4a83b17b544194b59eed77cbbe06730d3"]],"resultHash":"0x91c076089539179dd2089f91db29205af4a3fd19ea901095665a5c5180bc8090"},{"fromBlock":712373,"toBlock":7755769,"address":["0x22c1317fe43132b22860e8b465548613d6151a9f"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000b82d55450c18b9b28b3939c00b1dba5307c6e177"],["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0xb398071d75a75a079e71825bff6aef3476e1ed19901d19d707591c333ef897a7"},{"fromBlock":1006390,"toBlock":5566214,"address":["0x22c1317fe43132b22860e8b465548613d6151a9f"],"topics":[null,["0x000000000000000000000000c48d2559dcac2c87de79c0bdc4aed3a3dbb54fff"],["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0x61fe918b0c085d85ea1f228055266b1ad0286b0f212fa439b227df6c3ff86571"},{"fromBlock":0,"toBlock":7531627,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],["0x000000000000000000000000000000000000000000000000000000000000148e"],["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x44ee7ce0647093cbb1dab61d20d81f81de3e88a80d966b9fa5890d62a37ce101"},{"fromBlock":129898,"toBlock":7755739,"address":["0x71320dd08a45521c269ea7a37432973c7a57707f"],"topics":[["0x166e0f25af06322bfb9011ee3dd804ca0b93dc1276c71d8d605d661d22aa4172"],["0xbc3e8d090b1b642be9d033fd1403aa6d8ed3629fe9bc9036b19173cb76615d3a"],["0x0000000000000000000000000000000000000000000000000000000000028c60"],["0x000000000000000000000000ae23c1f73a8b1c138ab3aefb7b17fe53a26f0ba4"]],"resultHash":"0xabfa30a25a5dff5bb9ebde5123210fa78396c7ae9931d129932df08e73bb4bed"},{"fromBlock":0,"toBlock":7331384,"address":[],"topics":[["0x2402307311a4d6604e4e7b4c8a15a7e1213edb39c16a31efa70afb06030d3165"],["0x000000000000000000000000000000000000000000000000000000000001ad8f"]],"resultHash":"0xa7ec12665c16f1f2eadabba7427f11e7cb8dd9ce6f74230cb5050c4f51d14216"},{"fromBlock":469534,"toBlock":7755769,"address":["0xd86e1fedb7120369ff5175b74f4413cb74fcacdb"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002877"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x67875e05a1022def8a74be30bc54f97df541fa2d9549ba9f90d521e15fbeaf61"},{"fromBlock":1124482,"toBlock":7755739,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],["0x0000000000000000000000008e17d8f42bf281657e3b96f1637bce965fb45aae"],["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa0d8b3a995e77ecfc95a97d4c8509f75fd87216d96c517131ff3f8900e343bdf"},{"fromBlock":0,"toBlock":7331384,"address":[],"topics":[["0x2402307311a4d6604e4e7b4c8a15a7e1213edb39c16a31efa70afb06030d3165"],["0x000000000000000000000000000000000000000000000000000000000001ad8f"],["0x434ab18e74443aedaf60deb40b86a46652a31f8e7946b89e38d87010a8c71dfa"]],"resultHash":"0xa7ec12665c16f1f2eadabba7427f11e7cb8dd9ce6f74230cb5050c4f51d14216"},{"fromBlock":0,"toBlock":6647562,"address":["0xda9d4f9b69ac6c22e444ed9af0cfc043b7a7f53f"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000b21d8d14e2ec2837fa187848109f806b9172b82b"],["0x000000000000000000000000e7ec1b0015eb2adeedb1b7f9f1ce82f9dad6df08"]],"resultHash":"0xe86144ddfbd406af4c1b8cc2ff35218be614bbc668f536e8e9f2e9e5cd34ac7a"},{"fromBlock":2027722,"toBlock":7755769,"address":["0x1cd40deb4196d219097499031922ff690f9ea813"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000093b714330996f3dec51c455e4ac85f3864274fae"]],"resultHash":"0xa02d3cd63ea10c0707545f43460fbbd45dbb601ca7a5bbad1fa7f45524a3f93f"},{"fromBlock":440737,"toBlock":7755739,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002a67"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x573c4eadf583b0d44a4d6efbfc7d11cb686c966567d74b636fa7c0643ca319b8"},{"fromBlock":1332316,"toBlock":7755769,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],["0x00000000000000000000000016ee14bcdc1b1f5bc13842aa1c005e72cf8046f0"],["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf0e6d179cb320ff3073773424a2527335b2e2b090ddf2bbeb4ae4521f78a4f7d"},{"fromBlock":97914,"toBlock":6198290,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,["0x00000000000000000000000000000000000000000000000000000000000026f0"],["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xb22ca6d721e6efae3a08cd5f3cc8445ce2dad505f09887d2d610a96beb344878"},{"fromBlock":1779212,"toBlock":7755769,"address":["0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000c94b1bee63a3e101fe5f71c80f912b4f4b055925"],["0x0000000000000000000000006b29975137d7de522bf6c4615051370c55820b3e"]],"resultHash":"0xeade6da3b2d7a6dacbc0f1c1cda1fdf07194f8b3f51831a2fc71fa1a861ec248"},{"fromBlock":0,"toBlock":6963740,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x0000000000000000000000000000000000000000000000000000000000001691"],["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0xd3ef8289c9a1952596e940a68f90099c7caea45b0b1d99e77151e65907182c40"},{"fromBlock":149843,"toBlock":7755739,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],["0x000000000000000000000000000000000000000000000000000000000000143a"],["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x6077db27849bef200b3541993126367612b3c1e6ed9458f9c1a8c32281660a49"},{"fromBlock":1322151,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000000000000000000000000000000000000000000238"]],"resultHash":"0x22a2495a4d5c903dd509ef936525f9c49399129d433f5e40e395803aeab179ce"},{"fromBlock":37570,"toBlock":7755739,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002b3c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x7277f377d26ae279ba35746e6bb51d6d78c74aefb495545c782a3a3297e83f51"},{"fromBlock":3425286,"toBlock":7503281,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000007046ba909536b39cf09850c551670456a689ade0"],["0x0000000000000000000000009ea18de905e654f9fb98498109c60edfe133c145"]],"resultHash":"0xfec37559bfdb750b326c11090c974e0ab17d81ac86c6d2632aaeb8e5b9f5a86b"},{"fromBlock":1577956,"toBlock":7755800,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000000000000000000000000000000000000000020c"]],"resultHash":"0xd7dbc2c173a5d7f078ad22aa7af6054a0ad8088bde45beb5681ae9042282249b"},{"fromBlock":0,"toBlock":6361726,"address":["0xb015188cb963080f9ecee1cfe591d4b5e75f162f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xe976749493b17bc67904fd83d21972968d3f66ef29f6af3da6809b477abb53a2"},{"fromBlock":772075,"toBlock":5340530,"address":["0xbdbfd0f7593637c64624191008f46e0ce9e408f3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1dde06b3e0106b19be7b944b4ffbbd264541c3d249d4971bee3f8bfeefe2fe1a"},{"fromBlock":658060,"toBlock":7082999,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000001b89a43d543260fee7e0cad06a4b3b1beab20527"],["0x0000000000000000000000008f73f932d0310ec85731648bcbacf2de3b60bb0c"]],"resultHash":"0x643de3d3865f816e15b33f59fc08ac65c320f97841539305d12d140dc2baafe6"},{"fromBlock":0,"toBlock":7184764,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x00000000000000000000000000000000000000000000000000000000000016ca"],["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0x23ebd5098b97d64283c723ea464e3fd7425d11ce2e4e2e31ea3ab7b2fb290f9f"},{"fromBlock":1268701,"toBlock":7755769,"address":["0x10434f7420dc32ad66132651d62b0b05490ab980"],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x0000000000000000000000000000000000000000000000000000000000008809"],["0x00000000000000000000000000000000000000000000000000000000003fc4b0"]],"resultHash":"0xe1787b3c025de2b588fc661cf1fa4c1b030285de045f138d0dba37b863e632ce"},{"fromBlock":0,"toBlock":7469432,"address":["0xd86e1fedb7120369ff5175b74f4413cb74fcacdb"],"topics":[null,["0x000000000000000000000000000000000000000000000000000000002b10a031"],["0x000000000000000000000000000000000000000000000000000000000001ad5b"]],"resultHash":"0xe83c59505d21a5d612db76d0783d2eb6ac981542d914ecfbfb09e790e0eaf5ed"},{"fromBlock":2485608,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000000000000000000000000000000000000000000c4"]],"resultHash":"0x90c8ebb546a054508bfb54b6104e7a3b3ab67b8be244442c179a3eafd0add481"},{"fromBlock":1916125,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000000000000000000000000000000000000000000346"]],"resultHash":"0x32724d34432774ced966156e39eddbf1a756d0494289f64f2099880e5832d896"},{"fromBlock":974029,"toBlock":7755769,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002aa2"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x73c2bed0c7eb59190097192e9b4e138c5fa3b314f5409bb9baa2b4e718509c10"},{"fromBlock":1494097,"toBlock":7755769,"address":["0x4873528341d33ec918c7465f244491acb75bc95f"],"topics":[null,null,["0x0000000000000000000000005fe6d3ddf7c8bf6a36a86cbb9c2edc225a20a458"]],"resultHash":"0x6c029c73f8493170a23af4df2486fb925c7a960053623a48515daaca01d19dbf"},{"fromBlock":618159,"toBlock":7755800,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000097f75fb0350d562bf64b051c2a1937825609a2db"]],"resultHash":"0xe04dce7ecc2f73611f1ddb4822c562762c6b9f6f323adb5dbbb17869de9aa437"},{"fromBlock":0,"toBlock":6963740,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x0000000000000000000000000000000000000000000000000000000000001691"],["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0xd3ef8289c9a1952596e940a68f90099c7caea45b0b1d99e77151e65907182c40"},{"fromBlock":0,"toBlock":6002762,"address":[],"topics":[null,["0x00000000000000000000000000000000000000000000000000044471043de100"],["0x00000000000000000000000000000000000000000000000000000000000012dd"]],"resultHash":"0x260d28a179d7bf21c310e89a8597da7a7e02af5b7512fba5963ac4a4007ec9e0"},{"fromBlock":0,"toBlock":7184318,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],["0x00000000000000000000000000000000000000000000000000000000000016fd"],["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x2dfcf14420e2035042b6c26b3e010977fb6f061a2076e2ca273a5e23224d65d1"},{"fromBlock":1203535,"toBlock":5963354,"address":["0xe72c66da780842bd8815d7616dc1f7e5b6b104b9"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000006bc2445ae61f40ba1672afe4c75af5a9049011aa"],["0x00000000000000000000000072b9c3c2847e0c09776c071b2610dec9521c54d6"]],"resultHash":"0x64905200d66c93aff1f590335dcd93537a4aa7496bc052d13d17366c17d71677"}],[{"fromBlock":218186,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000093c4a726466183e43551973b5dcc9aa3e106f6cb"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x5c2b0fe71c1bc5590be1ccdb676f56ef408bc475596b4d9517b1a68312ffc5b7"},{"fromBlock":1817119,"toBlock":7755769,"address":[],"topics":[null,["0x000000000000000000000000ce4ebf96f01ca3a7c987d755ca2e87e86d6b169d"]],"resultHash":"0x323931c385c02cd8a3fee4c9b754cad333ed5cd9b9705a5faad024ea92f6a1d6"},{"fromBlock":0,"toBlock":5602481,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[null,["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":0,"toBlock":7067412,"address":["0xfbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],"topics":[["0x91fb9d98b786c57d74c099ccd2beca1739e9f6a81fb49001ca465c4b7591bbe2"],["0x000000000000000000000000b0446f6b31376491690c6b4e2e2a24ed13486ea3"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1c5864e06d9b74ca73c86ca99c40a91af014299deb156deb310c357c517a910e"},{"fromBlock":0,"toBlock":4746864,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000001cea2"]],"resultHash":"0xcf8556b7df3ba469af191b2f7bbeb7d8b0a3516020eedcd4d66702d781556cc2"},{"fromBlock":0,"toBlock":6736853,"address":[],"topics":[null,null,["0x0000000000000000000000009883c1e85440aa4f8d1220bf7c544b13e13d0625"]],"resultHash":"0xb5fe5e688a6cc230dcfb25aff44faa52f2c035ef9d7950fba392a978071cb089"},{"fromBlock":35918,"toBlock":7755708,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x1c07275dfc8a6121a64a504eabcc7c2fba30360ed3a5b78e9ce882fbe3a9cca9"},{"fromBlock":102389,"toBlock":6533396,"address":["0xb0446f6b31376491690c6b4e2e2a24ed13486ea3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x2aa514d480e36fcbe0a7eb8043f4151870d25d9692281073c68ec1f803c572e8"},{"fromBlock":319574,"toBlock":7658479,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,["0x0000000000000000000000000000000000000000000000000000000000001459"]],"resultHash":"0x210dd4ea001848a745ca5b84d72dee7c3894ba5c7e5905b9ea8236af8abb42c6"},{"fromBlock":2829143,"toBlock":7755739,"address":[],"topics":[null,["0xcf5384602957fef6c885e5319d928d8d970b930871c6ca008ef6b69cf0e7564f"]],"resultHash":"0x9330260210cb68ead1ec8aa8b3c0422d24d0dd16d0e59b75792bdb430337726a"},{"fromBlock":1501140,"toBlock":7755800,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[null,["0x000000000000000000000000e430f677a5e41db1e0a4b398af58a41c12fa27fe"],["0x0000000000000000000000009ea18de905e654f9fb98498109c60edfe133c145"]],"resultHash":"0x0c1c91612957b7f3927f0d3a263423be392967a10bc08dbfaafecbdfb38f62a6"},{"fromBlock":35918,"toBlock":7755708,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x1c07275dfc8a6121a64a504eabcc7c2fba30360ed3a5b78e9ce882fbe3a9cca9"},{"fromBlock":0,"toBlock":7127855,"address":["0x3cb855c19fef72dfbe8d238e07ba49f7017ef85f"],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000000000000000000000000000000000000000000004"]],"resultHash":"0x0973b75419b145d45f243e430a161f4a60b6377f0de8485b777b020ca1047129"},{"fromBlock":2930719,"toBlock":7755769,"address":["0xf813d7a9dc058df8da69992ba978a2e76d6447ee"],"topics":[],"resultHash":"0x9074b64ce2cc9f2006c890c5c5676cf73ad421ac0ec786e81fd154b1935f60a7"},{"fromBlock":1222594,"toBlock":7755769,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000037648ceff8591473c09e5de49422a403bbf9756d"]],"resultHash":"0x1d4a343a932f79623a4b94fa1ae8960ec1024919010143d17176615c9a66a433"},{"fromBlock":1544694,"toBlock":7755769,"address":[],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000000000000000000000000000000000000000020bf"]],"resultHash":"0xbfba2e394642314af307282851d545daf89ed2c0ebaf0c5d1b3f9563dbe9effc"},{"fromBlock":729251,"toBlock":6467006,"address":["0x6ef88a8825753a0f66de42ac51e48956530372eb"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000004cd6c9069cd0e8d23e6560a9b9ea10e296dca86e"],["0x000000000000000000000000680b102a587a0ee4495b3013a708aa23b8c684e1"]],"resultHash":"0x304da208266de63accc272eb2ae2d720c1192770cedba21e5a64acc54053d0c2"},{"fromBlock":0,"toBlock":7089740,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[["0x2295930c498c7b1f60143439a63dd1d24bbb730f08ff6ed383b490ba2c1cafa4"],["0x000000000000000000000000000000000000000000000000000000000005f6e0"]],"resultHash":"0x159f8460372be2931e8d14431e716d7e34488b4c7a8fb397c5baebde6737f14f"},{"fromBlock":671105,"toBlock":7719053,"address":["0x22c1317fe43132b22860e8b465548613d6151a9f"],"topics":[null,["0x000000000000000000000000ebe7f58df983241023672cfd7fef1e166849e936"],["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0x5185fa7f41d6dd38153c83216905a099903fa01cf9fc29c6fc39967e8d345d2b"},{"fromBlock":1815960,"toBlock":7755739,"address":[],"topics":[null,null,["0x00000000000000000000000000839a4f507e16d3d8c0ed04068a6f9557e79e3e"]],"resultHash":"0xfd78e5b32d8405b17763b1e0083409b54151d39c17e62fb7d36b9be34f0d9bf6"},{"fromBlock":619345,"toBlock":6465701,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000005f6fe"]],"resultHash":"0xade939a407d2c0ea5291057a02e48a45d5e8bbfb2087a1574436a92b2f6c883a"},{"fromBlock":615694,"toBlock":7610170,"address":["0x11d82a3cf69d22a9af546f7f26af16d04f64e54e"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000026baac08cb753303de111e904e19baf91e6b5e4d"]],"resultHash":"0x54eb3c7e3ca68f58aab277813c09298ee338034127b5f8132e9e4ef5b0c8ba96"},{"fromBlock":0,"toBlock":7298572,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000024bdbd3f1beb74f48628476b69bc009113950d36"],null],"resultHash":"0x16107e89f35ae2a8bdccbf7918948fe843fdd82bed87d8f8ccb78db19ed35e52"},{"fromBlock":773167,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000f9488af53b849014168eb123f5fa774a8effcf60"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xdac70f6ede8c023b1bc496a1265f3d5bbee568607b25c3266605aac1fa0d8256"},{"fromBlock":290791,"toBlock":6998007,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x6c86afa1aa1610c179d4439582e3bd68a12784e183e509e65f143f2d9864dd6b"},{"fromBlock":1581505,"toBlock":7755800,"address":[],"topics":[["0xa1a0dabcc18e414e32ee23df17c071b7112131effdebabcb06191c9e1cc12f60"]],"resultHash":"0x1b905c4ae5cb2144abe53d4091343cad344ef5374ed2fb2d08a1af2be51fd814"},{"fromBlock":0,"toBlock":6559652,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":2818800,"toBlock":7755800,"address":["0xea58fca6849d79ead1f26608855c2d6407d54ce2"],"topics":[null,null,["0x000000000000000000000000813d308658d82f338c75e63ca5eac41dc76e717b"]],"resultHash":"0x450597e8a229b123b7c5f27124934d52f3c9f925b9f063b2c58f809be7d20fc0"},{"fromBlock":2655386,"toBlock":7755739,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000","0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"],null,["0x0000000000000000000000000000000000000000000000000000000000063c57"]],"resultHash":"0x1af401ab50a5ce62bf6e73620c43ee0350160bf7d2cec4cba1c0771e162c6cb6"},{"fromBlock":927975,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":2132337,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":927975,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":0,"toBlock":7246717,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x00000000000000000000000000000000000000000000000000000001636c28c0"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xf1b66b91ac19216bb81eb6345e23894d6b9779360f4f8471798be8f3aa62d068"},{"fromBlock":249911,"toBlock":6196974,"address":["0xa3c8ba0a9261ff47a146e6755afa430f0126ea34"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1673a124f214802aaa94ef67cc18b3165057ebf148008b0d604a706bb1cf8fc1"},{"fromBlock":1013045,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000081fd82b125b863c1ddb8aad1f313a16df0308b23"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xd6dfc06feceaaa8fc694e30c49b9d7e00f4be320f669018c041c26d79f4f2e77"},{"fromBlock":319032,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[null,["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x3dfbeb8b859cab25592cb88ba8e206f2d922972bdc7de15752ecc38600e83870"},{"fromBlock":0,"toBlock":6846660,"address":["0xaaea189325f03da321e1c590583daca15d4ef055"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000444f875c1754eb221032f8023dc03de2bc2098ff"]],"resultHash":"0xa0016a7b27f7dd55e3e0f68ac4d807ff15141b026b4415bf433a597774c23d23"},{"fromBlock":118341,"toBlock":7755739,"address":[],"topics":[["0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"]],"resultHash":"0x1ffe9f0d8b8bb414f1e8c7d3f0dc91cbaa806d05722050522ef254041fe562db"},{"fromBlock":767048,"toBlock":5904242,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,["0x0000000000000000000000000000000000000000000000000000000000001318"],["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0x244ab27cf83cf231aefd594de219976de0cf2b3ab72b75918dbda11f208c3e8f"},{"fromBlock":0,"toBlock":5602481,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":2132337,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":755490,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000000446cfb718171eedb2bfae289c961fbed8df2555"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xb51986054b3c9f20e4d3565fdb38bded2148f59cb19473163f85cc6679d17ab5"},{"fromBlock":1575510,"toBlock":7755769,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000001b8e"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x4d539691373a7fe64c8f0c6f83ec75a7572c6c1c12ce15b99376fa6c1d4aa596"},{"fromBlock":466962,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000009c4e1984341f8e1149f8daed7f9f45af49bef010"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xd608e9f3cf7b312c962ac423f46c06bd7130abbc4d7150b99da4d6e5f73d38ae"},{"fromBlock":0,"toBlock":7189296,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000001cdb5"]],"resultHash":"0x9e70ea924ba3ffed550596ccba84932273972dba01d8f78af0036caefb1e51bf"},{"fromBlock":0,"toBlock":7089740,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000005f6e0"]],"resultHash":"0xa0a349e5400bd2564622c2316e2dcdfd4db86956c7cac695ba64543a5f692566"},{"fromBlock":586592,"toBlock":6225433,"address":["0xb0446f6b31376491690c6b4e2e2a24ed13486ea3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000005b3f3266a9fcce9dfd996cd6f08d8513cb021062"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xa992384b2342d6051204e8f0cf3e9abe0d3c6f355bb5115280a11fcf9625639f"},{"fromBlock":1948623,"toBlock":7755739,"address":["0x9072495afc2d59d857118ee59b4ef6cfc407d103"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000bde8fb9f69c9359f887f64a17f4a0edadbd9f668"],["0x00000000000000000000000092c7017c9dca00a8dfa55e918d7c0c647500c640"]],"resultHash":"0x7ffb9d7fb1352dbac68611e490ff4c742e36bdc66c439ae3d57f377593a75e5e"},{"fromBlock":756310,"toBlock":7755769,"address":[],"topics":[["0x35d79ab81f2b2017e19afb5c5571778877782d7a8786f5907f93b0f4702f4f23"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0xfc36e2649fea727e0b3cc165611b6efc4075cf0747a44ae52b21763371262ff3"},{"fromBlock":118341,"toBlock":7755739,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"]],"resultHash":"0x1ffe9f0d8b8bb414f1e8c7d3f0dc91cbaa806d05722050522ef254041fe562db"},{"fromBlock":1689113,"toBlock":7755769,"address":[],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":491064,"toBlock":7022525,"address":["0xeb8ba4184fe5f76bc55055c85aafae9af372d28d"],"topics":[null,["0x000000000000000000000000fbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x3057b6fed8b19c69be28a5abf5ad4e58139732193ee957cc67b5d17f703f72aa"},{"fromBlock":564562,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":2132337,"toBlock":7755739,"address":[],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":319032,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":2252326,"toBlock":7755739,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000004b7d4ee7c2126dc2967e36f10fe4f7322812e34"]],"resultHash":"0x77874a27e346d61f4a84660b4cde4f4aa5f405cc64fe25d9a77bf29b87599e80"},{"fromBlock":2655613,"toBlock":7755739,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[null,["0x000000000000000000000000e430f677a5e41db1e0a4b398af58a41c12fa27fe"]],"resultHash":"0xb54fef8ca006042b7c6665f461a502d81f22efab1e73db824f5493b893a0d6ac"},{"fromBlock":1013045,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000081fd82b125b863c1ddb8aad1f313a16df0308b23"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xd6dfc06feceaaa8fc694e30c49b9d7e00f4be320f669018c041c26d79f4f2e77"},{"fromBlock":0,"toBlock":6499817,"address":["0x40001ecac527d825d8d73f50ceab01925676099b"],"topics":[null,["0x0000000000000000000000002c6ede8d0e0e41975d2a141a3d1fcd65c9affdff"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f31e2589ccb683e665fed930f0638521badca1726975752fcd821a189141b2a"},{"fromBlock":586380,"toBlock":7755708,"address":["0xe83ebf27702244dd5997526692f03415f741b98f"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000085fb57a0dcab5b8ed7b699b0803ed455ab6ea472"]],"resultHash":"0x2b8ce5904fb087cec112e7b3c4209675f393fe6bf3aa13fba9cdf903d18a10f4"},{"fromBlock":319574,"toBlock":7658479,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,["0x0000000000000000000000000000000000000000000000000000000000001459"],["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0x13e16d3f7d4338abd755f2cee598a3f962be48c86eaefe9a1a5924eab508eb0c"},{"fromBlock":0,"toBlock":6625642,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,["0x0000000000000000000000000000000000000000000000000000000000001410"],["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0x8f0307797c8f4511f30a732a843414c040850fd0ab915208fc761150db50e138"},{"fromBlock":491064,"toBlock":7022525,"address":["0xeb8ba4184fe5f76bc55055c85aafae9af372d28d"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x3057b6fed8b19c69be28a5abf5ad4e58139732193ee957cc67b5d17f703f72aa"},{"fromBlock":0,"toBlock":7687772,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x00000000000000000000000000000000000000000000000000000001502b9200"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xd7988b474adc8d0f7cd6eac64b6b988673d2ff6680147877aeceb71999de3700"},{"fromBlock":0,"toBlock":7214277,"address":[],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000014029"]],"resultHash":"0x08499c749883c61abe307a4650e85b0a88e9e4babaf6bb563f4969ef6a196f05"},{"fromBlock":2360290,"toBlock":7309771,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000026baac08cb753303de111e904e19baf91e6b5e4d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xb058404826bb3ad6d19edbc6bf62ad48a4b4f9f60796560406275970a3ad43d4"},{"fromBlock":0,"toBlock":5350924,"address":[],"topics":[null,null,null,["0x0000000000000000000000004eba5a3f148d354a06f2dca293792e9970dd0431"]],"resultHash":"0xee25f546e6f89beba4fc91dfc37ed3dc90517b7dcca6848878d46e876b6658aa"},{"fromBlock":491064,"toBlock":7022525,"address":["0xeb8ba4184fe5f76bc55055c85aafae9af372d28d"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000fbed2b7f3cde372a5aa7f92d53e6a9599e22ac5e"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x3057b6fed8b19c69be28a5abf5ad4e58139732193ee957cc67b5d17f703f72aa"},{"fromBlock":2223786,"toBlock":7755739,"address":["0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0"],"topics":[null,["0x00000000000000000000000084a1488afeb5cbec88d000f5c7d6114779e1e2e9"]],"resultHash":"0x02dcc447aab01af0d7c4cdfe864c946be5800cd1e2de5d88e49e45f5894834d1"},{"fromBlock":2132337,"toBlock":7755739,"address":[],"topics":[null,["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x3dfbeb8b859cab25592cb88ba8e206f2d922972bdc7de15752ecc38600e83870"},{"fromBlock":2829143,"toBlock":7755739,"address":["0x19fc4f304c1198c8ae1c23630a1611b27883693a"],"topics":[null,["0xcf5384602957fef6c885e5319d928d8d970b930871c6ca008ef6b69cf0e7564f"]],"resultHash":"0x9330260210cb68ead1ec8aa8b3c0422d24d0dd16d0e59b75792bdb430337726a"},{"fromBlock":991171,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":249911,"toBlock":6196974,"address":["0xa3c8ba0a9261ff47a146e6755afa430f0126ea34"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1673a124f214802aaa94ef67cc18b3165057ebf148008b0d604a706bb1cf8fc1"},{"fromBlock":0,"toBlock":6991621,"address":[],"topics":[null,null,null,["0x000000000000000000000000d28b3e460c660cb2ab0a4398aaf214fe822827a5"]],"resultHash":"0x2315e5403c48f5765c1529b5f11dafe9292210a890be7b71f4134603826dcd12"},{"fromBlock":218186,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000093c4a726466183e43551973b5dcc9aa3e106f6cb"]],"resultHash":"0x5c2b0fe71c1bc5590be1ccdb676f56ef408bc475596b4d9517b1a68312ffc5b7"},{"fromBlock":114273,"toBlock":7542814,"address":[],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000078865a27"]],"resultHash":"0xb9ec0f0d81693772fd26f7687dde9fb00a620907029059384b5aaeb371fa29a9"},{"fromBlock":0,"toBlock":7591891,"address":[],"topics":[null,null,null,["0x000000000000000000000000000000000000000000000000000000000000fa9e"]],"resultHash":"0xd426f1774c84c1e10ddcb847dfd52ba59aa14075dcdccb23efa58d1250ee3d5f"},{"fromBlock":2132337,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":35918,"toBlock":7755708,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x1c07275dfc8a6121a64a504eabcc7c2fba30360ed3a5b78e9ce882fbe3a9cca9"},{"fromBlock":991171,"toBlock":7755708,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":0,"toBlock":5602481,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":368360,"toBlock":7755769,"address":["0x7abf52a91d3d078960bafc9912fa1be248ef6dcf"],"topics":[["0xaeeb0cb16f299136e7e5467ea84217150fe83008833064528f360cde7b7b54c3"],["0x000000000000000000000000d23ce3b387eb7e80ca658457562c7198f7f83c40"]],"resultHash":"0xe6b4f020458ec2ffa72e703c15c7406f9b0bac67be6d12658f060232640ada21"},{"fromBlock":756310,"toBlock":7755769,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0xb5497a6ece590089795d7cfa420df4a5f3ad890cb26ec4a31f2b421b454e9d34"},{"fromBlock":265477,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":819093,"toBlock":7755739,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000000d6e94d085a597f316be1833649e05a45103e873"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x7b1b00c8fc4d2c6311ffa1f63d38a4b4411eca8dfd6eda9c126353d07bd8d7c7"},{"fromBlock":411526,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83","0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000079240ea3dba4f6e58a77192c9c24dd57bc79304a"]],"resultHash":"0x4261b62aced3c3e413c8438f3c341bf1d9f04224c98b881b1fccaa6446ff62bc"},{"fromBlock":319032,"toBlock":7755739,"address":["0xb31c077c99e0d61305fcd873a39f974d13bc773c"],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x196b99b963fabbc8bf8fc0b53aa4f5196c48509e7c877b9441b9b8ff36be0a19"},{"fromBlock":2796902,"toBlock":7755800,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000001c59a21211362f2a5fea0d7879a2a7dcf88aae7c"]],"resultHash":"0xb9fea08ecf0dab96e5f7afd22b7eedee3feedfb9adf9f8de4a3ab55ead3f3e1c"},{"fromBlock":1815960,"toBlock":7755739,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000000839a4f507e16d3d8c0ed04068a6f9557e79e3e"]],"resultHash":"0xc7d89a12e7437b0823b28d756216b8e54e13fe83316142e175ef57632d0f0759"},{"fromBlock":2829143,"toBlock":7755739,"address":[],"topics":[["0x53bb90500b4bcd81f514e255a8d31018839272f80fc8c3d7f7f153e58c056568"],["0xcf5384602957fef6c885e5319d928d8d970b930871c6ca008ef6b69cf0e7564f"]],"resultHash":"0x9330260210cb68ead1ec8aa8b3c0422d24d0dd16d0e59b75792bdb430337726a"},{"fromBlock":118341,"toBlock":7755739,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"]],"resultHash":"0x1ffe9f0d8b8bb414f1e8c7d3f0dc91cbaa806d05722050522ef254041fe562db"},{"fromBlock":35918,"toBlock":7755708,"address":[],"topics":[["0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x1c07275dfc8a6121a64a504eabcc7c2fba30360ed3a5b78e9ce882fbe3a9cca9"},{"fromBlock":0,"toBlock":6432433,"address":[],"topics":[["0x51bbdc1d2a76e18752092da32318ce9d5ad268aae23f908efaf64aab614f8190"],["0x000000000000000000000000919663102b19fae17492a150bbf24a5196738441"]],"resultHash":"0x52169c89d8e3d1e71f69ea5f27543752f38b7c91db5d666a74971be1ec1c7c29"},{"fromBlock":700234,"toBlock":7755739,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xe41ae498b19bc37605d7b76851107908ff10f1fd3cf508b8c8ca186455428626"},{"fromBlock":539956,"toBlock":6303041,"address":["0x8eb074ddacc85832fda109ab3d93cc21914bee5f"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xfdad440386874d4cbd78a88c8dab034f4508d18610ebbf29bc2248c365731726"},{"fromBlock":1494097,"toBlock":7755769,"address":[],"topics":[null,null,["0x0000000000000000000000005fe6d3ddf7c8bf6a36a86cbb9c2edc225a20a458"]],"resultHash":"0x3b50adb0b99b6f1f51197e44017490e53bf3563ada3a9534ec52d525733c8fb5"},{"fromBlock":981711,"toBlock":7741762,"address":[],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000002877"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa2affcbbb5d5b5ff2f41233b9b354ab984a5c2483a3ea478f11ebf64a3b6ca01"},{"fromBlock":0,"toBlock":6559652,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[null,["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"],["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":0,"toBlock":5760683,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x00000000000000000000000027f0b7fa41a6e4617b4284138278f81281214cc1"]],"resultHash":"0xf5a706bd471646ca308163105515fe99218ef10d6e8e2c9de7e6b02999564103"},{"fromBlock":1088752,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x7012f930062bb41825d874ca35039ab8945dc3e536e109b4e7464fbb3317fd78"}],[{"fromBlock":960895,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":0,"toBlock":7184764,"address":[],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xd14fe5cc8237c75bd416800cb1150c55f7371a015cc1470cd20d88cd3369c95f"},{"fromBlock":1696164,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1127343,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":0,"toBlock":7665156,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xac6e0c2854e815f242460671ef73ecf8b6da189bd899782ae6bfcfc2526c0de9"},{"fromBlock":662475,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xe66bcdc172b6a719f1e5b96fa280cbb33d981950167475d193474c458bf81949"},{"fromBlock":729251,"toBlock":6467006,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000004cd6c9069cd0e8d23e6560a9b9ea10e296dca86e"],null],"resultHash":"0xe9b5d3dc09bbe4587cce7e7ed72d2da6ed31fd13ba5d1ef5647c75825518912d"},{"fromBlock":565376,"toBlock":7692773,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":2060394,"toBlock":7755739,"address":["0x7abf52a91d3d078960bafc9912fa1be248ef6dcf"],"topics":[null,["0x000000000000000000000000d23ce3b387eb7e80ca658457562c7198f7f83c40"]],"resultHash":"0x0454105e91743a267887113a6a6a2bb3fa3289798d343a47fee337ceeea8032d"},{"fromBlock":0,"toBlock":6133952,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],null,["0x000000000000000000000000f28e3d6e64cd5ae909177ea99ecac63755ca978f"]],"resultHash":"0xbb114350fe45198706be9a1b7a61b11d6a6b86f1556b823afd38026f9172bb3f"},{"fromBlock":1067513,"toBlock":7444699,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xac6e0c2854e815f242460671ef73ecf8b6da189bd899782ae6bfcfc2526c0de9"},{"fromBlock":0,"toBlock":7671140,"address":["0xb647735a3dcd086d5e7adc1c8f1f4733f5b46a5a"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x0000000000000000000000003d52b839a410fc977e73b98f36d1a40102e1ab79"]],"resultHash":"0x3cc6243513f8886631a5dd9fa63220df847ff03f850a1478866c4d1b5cc8001f"},{"fromBlock":263733,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1268701,"toBlock":7755769,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x0000000000000000000000000000000000000000000000000000000000008809"],["0x00000000000000000000000000000000000000000000000000000000003fc4b0"]],"resultHash":"0x56b0e14277a624891e94b38c9cca4bd09ba522c5dc9c4ed83e1dd891aaa87dc2"},{"fromBlock":0,"toBlock":7276691,"address":["0xb647735a3dcd086d5e7adc1c8f1f4733f5b46a5a"],"topics":[],"resultHash":"0xba50a141bc33e6152c8cbb995d0558dd96c372b5df54eb37677234c9eea435ca"},{"fromBlock":729251,"toBlock":6467006,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000004cd6c9069cd0e8d23e6560a9b9ea10e296dca86e"],["0x000000000000000000000000680b102a587a0ee4495b3013a708aa23b8c684e1"]],"resultHash":"0x29d2ad54bee7ad71976cc75d24dafde9f222cab5470066b830a4d84c4717938c"},{"fromBlock":2601817,"toBlock":7755800,"address":["0xe2b378d9181046c84db1156b0f90cf3108e25e9d"],"topics":[null,null,null],"resultHash":"0x329df5d58922a08e0c3b725b9bd23947a442694295a1e15a8388db7e7487d3e4"},{"fromBlock":492162,"toBlock":5529852,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x461b31b4027f7b5e5fee16fad5841d0304bcfc96060a1b66f72364472a79229f"},{"fromBlock":448397,"toBlock":7755769,"address":["0x9c556a50fe68a15cda2591da6d451928b46ac8ed"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xcbe3cdb6970d3f3e0a8fb9b166a28fa59d9d3926a808b943ccc142f86b0c6c84"},{"fromBlock":446332,"toBlock":6953276,"address":["0x6ef88a8825753a0f66de42ac51e48956530372eb"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x0000000000000000000000004cd6c9069cd0e8d23e6560a9b9ea10e296dca86e"],null],"resultHash":"0x42a1f0b262c3278ee7499dc2669c93831e0ed027b2c2a10f596988afadd6c77b"},{"fromBlock":1127343,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":2781431,"toBlock":7713400,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1780365,"toBlock":7755739,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0x5b7c44a6534eb053fe041808a63fad020ab4f7c224a14270307209f809a61ec0"},{"fromBlock":1696164,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":695016,"toBlock":6326832,"address":[],"topics":[null,null,["0x0000000000000000000000003a0cafcb6f2a8c3187879cd137c8aaaca74ccaca"]],"resultHash":"0x4eac0ff36c2181b94266b2c7d921de32b31cb780fff5965c63d04fc60ae7ae86"},{"fromBlock":416771,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":2905486,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1466011,"toBlock":7501340,"address":[],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000000000000000000000000000000000000000000fa"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x67a049e4e78a0bf3beaf1a4052682273a50972af7f401e29e8ec9cc0c58808e7"},{"fromBlock":544245,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1127343,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":661266,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":2747833,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":678685,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1127343,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":587408,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":0,"toBlock":5750538,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xac6e0c2854e815f242460671ef73ecf8b6da189bd899782ae6bfcfc2526c0de9"},{"fromBlock":0,"toBlock":7111656,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000089097060177dbd38bb762ef6b94b349d4ce2c423"]],"resultHash":"0x874ea63221cb2940a952cad17eda293b19c8a58519f7dbc2f941cdddf005d694"},{"fromBlock":326616,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1127343,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":2781431,"toBlock":7713400,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":0,"toBlock":7026965,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xac6935f746fe30a2748502d5c2fd57e9bcbf502a5bf05d046f3e9fd45339d7f2"},{"fromBlock":926413,"toBlock":5043576,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xac6935f746fe30a2748502d5c2fd57e9bcbf502a5bf05d046f3e9fd45339d7f2"},{"fromBlock":367339,"toBlock":7755769,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],null],"resultHash":"0x58e5734303c746219710de04c9436843522532cfc9bcea94d5a64b609627f68a"},{"fromBlock":1715035,"toBlock":7445152,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83","0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[null,["0x00000000000000000000000079240ea3dba4f6e58a77192c9c24dd57bc79304a"]],"resultHash":"0xfc3066bfa6eed6a35a9eb769c5b13859178b61bdc132e97325dc3575dc1381c8"},{"fromBlock":164489,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],null],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":1883646,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0xfabeb6eee9d30787fdadf82a38cd59de6b1889367b29fd10563cdae8f88e1be8"},{"fromBlock":996634,"toBlock":7755708,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0x58e5734303c746219710de04c9436843522532cfc9bcea94d5a64b609627f68a"},{"fromBlock":133116,"toBlock":4681344,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],null,["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x5a892f6b1e370b21038d792725af88a2db7531e78d31e2e585778a500d492317"},{"fromBlock":0,"toBlock":5522067,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xac6935f746fe30a2748502d5c2fd57e9bcbf502a5bf05d046f3e9fd45339d7f2"},{"fromBlock":0,"toBlock":7322615,"address":["0x8bda81d46a459f0cf67afc69e98d03b7e8bdb325"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x9844384cb2cd1f7041fa5c17ea0b4eca8015fbd83fb59b65b62a40402571be16"},{"fromBlock":2221602,"toBlock":7755769,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000db20ce3fea5b3e6522720dd9dce8bedc9d80cf79"],null],"resultHash":"0xf135ed1738a2bca0d1a84268b6ad95698286264a4055d0d9a65c22c894e8d45b"},{"fromBlock":606393,"toBlock":7755708,"address":[],"topics":[["0xdda5547a2857faf5056d2d09b4cf7d457608f1e1801ca7a1c774d61b6dcc7354"],null,null,["0x0000000000000000000000000a235b06c47bb3fdddfb76ca1a72c9d39b9f794d"]],"resultHash":"0x15ecc8ca1adb166f0241974361d1ce7587b67c44537a15125770eac3155c26d9"},{"fromBlock":414598,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":817880,"toBlock":7755708,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":772075,"toBlock":5340530,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xb95f5c877425205b1b4842dd732850f33a2aace893800e8ef89f6b93a0c38a25"},{"fromBlock":0,"toBlock":7181458,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],null,["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x5a892f6b1e370b21038d792725af88a2db7531e78d31e2e585778a500d492317"},{"fromBlock":17433,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xdfdaf6783751217b303dddf50c08324b98b2bcc5ad145dd0b6c34293a34c979b"},{"fromBlock":1950992,"toBlock":7755769,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xe41ae498b19bc37605d7b76851107908ff10f1fd3cf508b8c8ca186455428626"},{"fromBlock":0,"toBlock":5364118,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],null,["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x5a892f6b1e370b21038d792725af88a2db7531e78d31e2e585778a500d492317"},{"fromBlock":501931,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":2280658,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":17433,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xdfdaf6783751217b303dddf50c08324b98b2bcc5ad145dd0b6c34293a34c979b"},{"fromBlock":0,"toBlock":5794696,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xc8305d94705a3b588f2d7b448459900c8238cb2c43993e7dc55b72e38be685f9"},{"fromBlock":614227,"toBlock":7755769,"address":["0x7abf52a91d3d078960bafc9912fa1be248ef6dcf"],"topics":[null,["0x000000000000000000000000d23ce3b387eb7e80ca658457562c7198f7f83c40"]],"resultHash":"0x0454105e91743a267887113a6a6a2bb3fa3289798d343a47fee337ceeea8032d"},{"fromBlock":138020,"toBlock":7755800,"address":[],"topics":[null,null,["0x00000000000000000000000000000000000000000000000000000000000105c9"]],"resultHash":"0x5a9cb4e8e065dc30748c9d5254d8e54565eebc7b370b68922e5b13f5982cc0de"},{"fromBlock":3320334,"toBlock":7755739,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":128029,"toBlock":7755739,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000e7c5196c14c953694599c32975ab3214eec6fe14"]],"resultHash":"0x15a662e554029239015dd014075768011f0dd43c6a3aa4959bb471168ad6153a"},{"fromBlock":164038,"toBlock":7755769,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1466011,"toBlock":7501340,"address":[],"topics":[null,["0x00000000000000000000000000000000000000000000000000000000000000fa"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x3a687a18bf9b48169e6185b5092d97713b08b514d1d003e0602b9720222ab56c"},{"fromBlock":662475,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xdfdaf6783751217b303dddf50c08324b98b2bcc5ad145dd0b6c34293a34c979b"},{"fromBlock":1993626,"toBlock":6861845,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"]],"resultHash":"0xf5b6e6e901d5457a49d487e6badce52aec57a32e563c94831426aa7b8019c82f"},{"fromBlock":1696164,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":0,"toBlock":7184318,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x00000000000000000000000038dc84830b92d171d7b4c129c813360d6ab8b54e"]],"resultHash":"0x461b31b4027f7b5e5fee16fad5841d0304bcfc96060a1b66f72364472a79229f"},{"fromBlock":20085,"toBlock":7755769,"address":[],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x0000000000000000000000000000000000000000000000000000000000000332"]],"resultHash":"0x3d67cfd4dc186efe23b6edfec0d492c0d26633bc3bee9d2f473e9db033335206"},{"fromBlock":662475,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000023c276729c2dc6ea306a5ac9b270598ce5ff2b37"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0xdfdaf6783751217b303dddf50c08324b98b2bcc5ad145dd0b6c34293a34c979b"},{"fromBlock":832967,"toBlock":7755708,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1086373,"toBlock":7755739,"address":["0x135fabf0958a9dfb852953911fde610247cbcb20"],"topics":[["0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"]],"resultHash":"0xf84dfdb9f8a15fd80c17b2712d4fcb83b82636e0b1fd9fe86935d9958265139e"},{"fromBlock":1779995,"toBlock":7755739,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1942656,"toBlock":7755769,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":848368,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":817880,"toBlock":7755708,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":849302,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":606393,"toBlock":7755708,"address":[],"topics":[["0xdda5547a2857faf5056d2d09b4cf7d457608f1e1801ca7a1c774d61b6dcc7354"]],"resultHash":"0x15ecc8ca1adb166f0241974361d1ce7587b67c44537a15125770eac3155c26d9"},{"fromBlock":0,"toBlock":7276691,"address":["0xb647735a3dcd086d5e7adc1c8f1f4733f5b46a5a"],"topics":[null,null,["0x0000000000000000000000003d52b839a410fc977e73b98f36d1a40102e1ab79"]],"resultHash":"0x97c3c5a3076c3d397b0ff147366d44930ba7b3d7a157daf88bc393a027421ae1"},{"fromBlock":2042759,"toBlock":6241556,"address":["0xb0446f6b31376491690c6b4e2e2a24ed13486ea3"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0xd86ac73ba9d23d82cfff644cb1b1b8ec643b3c1057e1227a546a2c16320d5ed8"},{"fromBlock":550373,"toBlock":7755769,"address":["0x930fc4c47f34855bcad8bb4ea03b5c7c2a1d1120"],"topics":[["0xdda5547a2857faf5056d2d09b4cf7d457608f1e1801ca7a1c774d61b6dcc7354"],null,["0x7acb8ce1efb4b1ed3a0ccdba4b1a589601eb79e2605529404e8cf863e9ec84c0"],["0x0000000000000000000000000a235b06c47bb3fdddfb76ca1a72c9d39b9f794d"]],"resultHash":"0x92fc25426163ca5ba2f484b1cd4a542a133393b0ba41af3238dee9747718c9f0"},{"fromBlock":17855,"toBlock":7755769,"address":["0x135fabf0958a9dfb852953911fde610247cbcb20"],"topics":[["0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"]],"resultHash":"0xf84dfdb9f8a15fd80c17b2712d4fcb83b82636e0b1fd9fe86935d9958265139e"},{"fromBlock":833592,"toBlock":7755769,"address":["0x135fabf0958a9dfb852953911fde610247cbcb20"],"topics":[["0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"]],"resultHash":"0xf84dfdb9f8a15fd80c17b2712d4fcb83b82636e0b1fd9fe86935d9958265139e"},{"fromBlock":2988033,"toBlock":7755708,"address":null,"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],null],"resultHash":"0x9902e8bdcb3af765d6e417eb3805b7340be2b1cf6679b9d9c6a0746ae55214cf"},{"fromBlock":1780365,"toBlock":7755739,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":0,"toBlock":5391887,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"],null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xac6e0c2854e815f242460671ef73ecf8b6da189bd899782ae6bfcfc2526c0de9"},{"fromBlock":250558,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"},{"fromBlock":1636471,"toBlock":5948881,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x000000000000000000000000000000000000000000000000000000000000225a"]],"resultHash":"0x89814e2659b557f4214dce3af5de14ca686d16f50028b8754da8a3bbe8563541"},{"fromBlock":1293701,"toBlock":7755739,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83","0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000f6b37bbad2b741cb163f629bbd7a5d4f9f19c879"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x01f2b378623819b70498f2f865b9deee9a768438bacb877a4cc5450dd360321c"},{"fromBlock":544245,"toBlock":7755708,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":249911,"toBlock":6196974,"address":[],"topics":[["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x158476f75ce4fe845fe4ba0a135088e7551c28e9ef8126a6213881c8e8772f99"},{"fromBlock":2781431,"toBlock":7713400,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":4980899,"toBlock":7755800,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000001a3f"]],"resultHash":"0x8e843e01c110105c41c376c4778bc7f6dc4fbf9887152c0735ee4c9074082556"},{"fromBlock":496081,"toBlock":7755769,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x8548e56e79bdc81da6aa2a20817e7353b8ce42f2aae709172dffb7c986cfb484"},{"fromBlock":1791934,"toBlock":7512130,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x49f183b418a2fecabc21aef3e9f064ccf60836af4529b0b759c1fba51db639ea"}],[{"fromBlock":5312537,"toBlock":5827968,"address":[],"topics":[null,["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"]],"resultHash":"0x512b774502b5f5482c5a4112ff7059dd068ecdb6ca925929d5ba30ad1da13e91"},{"fromBlock":2814160,"toBlock":3146808,"address":[],"topics":[null,null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x829bd5a72848481785e590b40c4d9942e43a3bca2a6839634febe0ad80e42668"},{"fromBlock":2602758,"toBlock":3639658,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1ce24648687221d81dcdfd73b61d3d9765ba81ed7aa20b4ec48af402511df3b1"},{"fromBlock":6249387,"toBlock":7572741,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x82c07c8ba9db822f89888187aa77ebb6bc0f458603a1a0889f69d0b6ba2425e3"},{"fromBlock":1609490,"toBlock":4309586,"address":[],"topics":[null,["0x000000000000000000000000000000000000000000000000000000000000032a"]],"resultHash":"0x0236d29bfe35ef96c87b0f78fd12331ee4072ae7774c79a7e86ea2e8501bc3d4"},{"fromBlock":2609181,"toBlock":3180325,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000c98fa5773deac2ee02d51f5ae678bdb26608c499"]],"resultHash":"0x1ce24648687221d81dcdfd73b61d3d9765ba81ed7aa20b4ec48af402511df3b1"},{"fromBlock":7088312,"toBlock":7724095,"address":[],"topics":[null,["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7007774,"toBlock":7753907,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[null,["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7007774,"toBlock":7753907,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[null,["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6288866,"toBlock":7545898,"address":["0x33f60714bbd74d62b66d79213c348614de51901c"],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x57f6ae6de8922a24c471a9323c67b34c88a6eb3895aacca296e3823ba87bc83b"},{"fromBlock":7003590,"toBlock":7745276,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7007774,"toBlock":7753907,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[null,["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[null,null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x79f2c3aec1cba39b6e975aa6df6e8e5b61e8f4d32f9e18ce51fece21b9f6c79e"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7007774,"toBlock":7753907,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":5481907,"toBlock":7562617,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x540871ae7be1e484c15908a60ca094dd3c2463bfde440081fb5cd14c07221682"},{"fromBlock":6262795,"toBlock":7547523,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[null,["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6961788,"toBlock":7736024,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7088312,"toBlock":7724095,"address":[],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6777939,"toBlock":7156548,"address":[],"topics":[null,["0x00000000000000000000000084a1488afeb5cbec88d000f5c7d6114779e1e2e9"]],"resultHash":"0x67ec0ae2292cd5462991438f3380f66276d09f5d40c866d9d884c6187056d204"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7045424,"toBlock":7734387,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":6997534,"toBlock":7755739,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":6271143,"toBlock":7547138,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":6271143,"toBlock":7547138,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":4618359,"toBlock":7017022,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x0000000000000000000000000000000000000000000000000000000000002c9f"]],"resultHash":"0xa437f498df73e39b6ad475a4341357f1d21ce1c65e05cd3caa38cb52fe0f126c"},{"fromBlock":6967215,"toBlock":7744682,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6591206,"toBlock":7240258,"address":[],"topics":[null,null,["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0xc369d523c9726cf2cd02a5a00526124cb42edc86c7673814f5383bc594e36a6f"},{"fromBlock":7088312,"toBlock":7724095,"address":[],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6271143,"toBlock":7547138,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":2601170,"toBlock":3157422,"address":["0xf9b7e9bb840b7bbf7e0c42724f11121d4d1efc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0xe93646bf112af5886a5a39817c0448543a840a747093e1ac5c1f44069dfa4779"},{"fromBlock":7007774,"toBlock":7753907,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x095905c2b4f8d2cb2445457ab00acec6441f24d11c79c3ee56cc527e99eaedd2"},{"fromBlock":6288866,"toBlock":7545898,"address":[],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],null,["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x57f6ae6de8922a24c471a9323c67b34c88a6eb3895aacca296e3823ba87bc83b"},{"fromBlock":5317487,"toBlock":7571528,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x82c07c8ba9db822f89888187aa77ebb6bc0f458603a1a0889f69d0b6ba2425e3"},{"fromBlock":6262795,"toBlock":7547523,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":6070683,"toBlock":7152086,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000006b29975137d7de522bf6c4615051370c55820b3e"]],"resultHash":"0x1642a42cf8646d6f1d301101e75defd33f21b9c9721109e61d4c5079aea98b36"},{"fromBlock":5317487,"toBlock":7571528,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x82c07c8ba9db822f89888187aa77ebb6bc0f458603a1a0889f69d0b6ba2425e3"},{"fromBlock":7088312,"toBlock":7724095,"address":[],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6591206,"toBlock":7240258,"address":[],"topics":[null,["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x23f9cb1ebc0071c07cf0f485ac049db3f91f8b49119e0af5663ba6ed244a409e"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":7088312,"toBlock":7724095,"address":[],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6288866,"toBlock":7545898,"address":[],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x57f6ae6de8922a24c471a9323c67b34c88a6eb3895aacca296e3823ba87bc83b"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":5521951,"toBlock":6901427,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x0000000000000000000000000000000000000000000000000000000000001c7a"]],"resultHash":"0x9614ae2f5edce85b27374af6642e18af382449905c196b2bca7912bf60de7c19"},{"fromBlock":6591206,"toBlock":7240258,"address":["0x33f60714bbd74d62b66d79213c348614de51901c"],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0xb7c86d62d535f921c13d4ba1282b10f2827d2b52c1826561cef8648b1d711946"},{"fromBlock":2388625,"toBlock":3265789,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null,["0x00000000000000000000000000000000000000000000000000000000000004af"]],"resultHash":"0x65e32f4345324c727c4f565b3e68bd3d19997b11fede56ab922e87a836a5a366"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6216314,"toBlock":7559852,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x7d9469656704beea628f676ddc56f6bb9eb92f059225c324f486ce5fee9176e7"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":7088312,"toBlock":7724095,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x6623e6dc452e7da9bca7da555aa3b30caa6210d6928c1a4b06e2bcb6bbf797d5"},{"fromBlock":6111257,"toBlock":7579987,"address":["0x33f60714bbd74d62b66d79213c348614de51901c"],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x933650b8af15176adc5f8570984ba5b098ec1bd8165068c5bc4b88ef048efd54"},{"fromBlock":6278555,"toBlock":7543950,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":945904,"toBlock":3044662,"address":[],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000000000000000000000000000000000000000000004"]],"resultHash":"0xbcceed6fd4c7e7bf182819adf6e75f1edd9c34c233ccc639d368011524d0b971"},{"fromBlock":2568917,"toBlock":3421829,"address":[],"topics":[null,null,null,["0x00000000000000000000000000000000000000000000000000000000000004a3"]],"resultHash":"0x64d23dc06f41178ef5c3a56191aa38efcbaac2929577ce3415de12e55aaddcc2"},{"fromBlock":6288866,"toBlock":7545898,"address":[],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x57f6ae6de8922a24c471a9323c67b34c88a6eb3895aacca296e3823ba87bc83b"},{"fromBlock":5577293,"toBlock":7349259,"address":[],"topics":[["0x35d79ab81f2b2017e19afb5c5571778877782d7a8786f5907f93b0f4702f4f23"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x1794cbd4b4830536584c5302ec4a01592d5951a0f2f16f12b5b9192612bd4777"},{"fromBlock":5628636,"toBlock":7587447,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0xf3d4c4a5f067bb0c2cd9ae744ef801f4d9b99001d81117c1757e6caf570513d8"},{"fromBlock":6591206,"toBlock":7240258,"address":[],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0xb7c86d62d535f921c13d4ba1282b10f2827d2b52c1826561cef8648b1d711946"},{"fromBlock":5657074,"toBlock":7553882,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x7797b365483656866c38871582f9365e387f0acad4852057e10cc062a2475813"},{"fromBlock":7244870,"toBlock":7755769,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000011"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x7539546c3abbda4ed315bdd6e72c6ef5b09782094689c70d3b580a528269541d"},{"fromBlock":7086805,"toBlock":7724757,"address":["0x9f78a25cd8a8211937ea2756aa66f57c836fd6b7"],"topics":[["0xda53325387d61a6b685c31632cef66c5f3e88c3a0f1c2730ef68fb2d039d3e9d"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17"]],"resultHash":"0x5ea69c3ebae57efe1d3ebfefc019182db58c3b08c37e73ef4e96b6ab666d5db9"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6164416,"toBlock":7561065,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x540871ae7be1e484c15908a60ca094dd3c2463bfde440081fb5cd14c07221682"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":6233478,"toBlock":7560039,"address":[],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],null,["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x0ce07d46f5b30864edd1e6839bb483bc8ac27219c3066c0e5d4dc48690619aaf"},{"fromBlock":6150609,"toBlock":7492130,"address":[],"topics":[["0x35d79ab81f2b2017e19afb5c5571778877782d7a8786f5907f93b0f4702f4f23"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0xe57283bc7deeac32d90cb7c49406d048ef82e70a2f900f0bd5f0028ed1db628a"},{"fromBlock":6350158,"toBlock":7475163,"address":["0x33f60714bbd74d62b66d79213c348614de51901c"],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x25c01158e8b91a7352afe51bb3f7866d5e2aa5cf8a470ae5b3966fa05fcffe99"},{"fromBlock":6288866,"toBlock":7545898,"address":["0x33f60714bbd74d62b66d79213c348614de51901c"],"topics":[["0x2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af5"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"],["0x0000000000000000000000004230c9e7171615d144251c1a0e6bf9d71c4ac54a"]],"resultHash":"0x57f6ae6de8922a24c471a9323c67b34c88a6eb3895aacca296e3823ba87bc83b"},{"fromBlock":6216314,"toBlock":7559852,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x7d9469656704beea628f676ddc56f6bb9eb92f059225c324f486ce5fee9176e7"},{"fromBlock":6262795,"toBlock":7547523,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x09835d4f17eb08b7dc2ea514f5fdae1b87a50a5dac623c487c001bc465eb4aae"},{"fromBlock":6252717,"toBlock":7580222,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0xe0342db5e4aff7a34a2cbf46dfd7e990cab796d207ec21699d062d91ce41e97b"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"},{"fromBlock":2360036,"toBlock":2536055,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[null,["0x0000000000000000000000006e2c879382520c7b15927902eef1c0fbc1f8de91"]],"resultHash":"0x13fc176aca1738f4944b4863defd65fedad077a486c108990f2c9f3408546073"},{"fromBlock":6216314,"toBlock":7559852,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x7d9469656704beea628f676ddc56f6bb9eb92f059225c324f486ce5fee9176e7"},{"fromBlock":5580431,"toBlock":7467968,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,["0x000000000000000000000000000000000000000000000000000000000000358b"]],"resultHash":"0xd505866110147d608b27a13dfc3131f96838347e029ae139b2bc772a59db761a"},{"fromBlock":3136083,"toBlock":4460931,"address":[],"topics":[null,null,["0x000000000000000000000000000000000000000000000000000000000000014e"]],"resultHash":"0xddfb3fb80ad18c70a042434be3bb7343ccc792e6d22b6de8f3d7b4d54d494af4"},{"fromBlock":5317487,"toBlock":7571528,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x82c07c8ba9db822f89888187aa77ebb6bc0f458603a1a0889f69d0b6ba2425e3"},{"fromBlock":6278555,"toBlock":7543950,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a"]],"resultHash":"0x3631b12dc0ea2718a4369c199d258baf83d8638cd2c3d21edf1086a1a4af159d"}],[{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":7400338,"toBlock":7573531,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000010"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x32502b9fe1cd4cbc7831f54bead8899793bb64833946acfdd69e40e722ade2f5"},{"fromBlock":5460621,"toBlock":5523843,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf7ad4dd50224b023340d9576dcfa18c9a2558702b00f190dada31d76037c5b6c"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":2346203,"toBlock":2450447,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[],"resultHash":"0xaf3eb7a9b5aa96d848f2d32cfb6877119cd968097c3ce4f3869ef9447b9a8056"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":2346203,"toBlock":2450447,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0x67578e8c26d27184f314c76b81139d12c37646a9a584a5574f501a61b04f542c"},{"fromBlock":4500308,"toBlock":4557601,"address":[],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0x0c919b7ca9aaf46e00c122d30082dffe8b4e81ddd60992ea8f114b18a4ce7dd3"},{"fromBlock":4473769,"toBlock":4567107,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0x7a2eb8f395900c085dffa299e81fb192361de91433ad992e88ae0606b92e3654"},{"fromBlock":4462978,"toBlock":4562463,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0x3bd5572fe5858140811cb60736169c55d76ec65946d175dedcaafe8f62609874"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":7401694,"toBlock":7531232,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb0fb7baf653a07a22307629a52bf677342311704af815d443744da4d83e58243"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,null,["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":5462278,"toBlock":5521715,"address":["0x719e22e3d4b690e5d96ccb40619180b5427f14ae"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x9f627460e509ff66bc62825b46a8ef30cf3bee0cb32a4f94ab1803995b6b0c23"},{"fromBlock":7424911,"toBlock":7506285,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0x1d9f30260051d51d70339da239ea7b080021adcaabfa71c9b0ea339a20cf9a25"],["0x0000000000000000000000000000000000000000000000000000000000000015"]],"resultHash":"0xb932798e018fc44daa77b158ecc793b6b3088bdd8565c049044cc8608a394049"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":5402883,"toBlock":5563969,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf0acf909b2f222d6665c5f38d5e1601db7ad49e18b3112733f38700a9109c63e"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":6234966,"toBlock":6286957,"address":[],"topics":[["0xbaa1d762384057169afd12b625998a5a7ed502c2e229acdbead30f3f6496399d"]],"resultHash":"0x9b16b111c2e538988e7e6e05aee62589bab50d1577ad8e14d50b24ab0f513501"},{"fromBlock":2852708,"toBlock":2904307,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xcb594379bee7a4135be6e90141b4358269984f0c8b1bd13ee8c5335cfde0dba3"},{"fromBlock":5435576,"toBlock":5546944,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x41944cb8bbb11b90fca664d28a289b0ab67a36d1131aac905100f71bf7351bdf"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2852708,"toBlock":2904307,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xcb594379bee7a4135be6e90141b4358269984f0c8b1bd13ee8c5335cfde0dba3"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2407874,"toBlock":2543976,"address":["0x85edb7a0cbacf5bd641e0ff5d6270bef9c72bd6b"],"topics":[null,null,["0x000000000000000000000000855aa5fac685841c96f6d5ce103bf4a7122b016c"]],"resultHash":"0x632dd0a604e9b7e9df1f5e2c7b35c8cd9c443397bbb2c012e11645d699ec360b"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2852708,"toBlock":2904307,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xcb594379bee7a4135be6e90141b4358269984f0c8b1bd13ee8c5335cfde0dba3"},{"fromBlock":7400338,"toBlock":7573531,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000010"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x32502b9fe1cd4cbc7831f54bead8899793bb64833946acfdd69e40e722ade2f5"},{"fromBlock":7412101,"toBlock":7528561,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb866a6a0e2e61faed988e0bd43c72660555c08b927c684f2c415d2b01ed7cc46"},{"fromBlock":7407413,"toBlock":7530398,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x3a467beb063319f3a6309852cf2df5ae6d6303879f4bea2a74a31e7895a38958"},{"fromBlock":4391681,"toBlock":4445784,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],null,["0x000000000000000000000000d1292d09173fc26cb82ddcc047d5d19f7369d56e"]],"resultHash":"0x99ac7ca7a080e32bb806e2778fae4c40458c9523cfbcc8d25a5fa230a2437413"},{"fromBlock":5441762,"toBlock":5552695,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xc2b1447ad80162863aa6a584140ab6fa56ba968b5d567dc3a3ce862edc94c9c2"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2852708,"toBlock":2904307,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xcb594379bee7a4135be6e90141b4358269984f0c8b1bd13ee8c5335cfde0dba3"},{"fromBlock":4458486,"toBlock":4559611,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0xd97269108aadeec8bcd20720e1dd328892b321e0a88345361665425ca0f414d2"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":3385764,"toBlock":3457017,"address":[],"topics":[null,null,["0x00000000000000000000000026baac08cb753303de111e904e19baf91e6b5e4d"]],"resultHash":"0xeef5ce5159987dac87fbbc44717189b14e547be463018b77b715e10ab7b59e43"},{"fromBlock":3456545,"toBlock":3701349,"address":[],"topics":[null,null,null,["0x0000000000000000000000000000000000000000000000000000000000000364"]],"resultHash":"0xc85f1ef7e4e86e56112b84a0257ef39ff6d93efd65114cb3cfea4d0ab0f547f3"},{"fromBlock":2320120,"toBlock":2382408,"address":["0xe72c66da780842bd8815d7616dc1f7e5b6b104b9"],"topics":[null,null,["0x00000000000000000000000072b9c3c2847e0c09776c071b2610dec9521c54d6"]],"resultHash":"0x2afb01863b7152217e7854fa3b57ebe2bd51dbf11452b5ab2875e202a0575698"},{"fromBlock":4391681,"toBlock":4445784,"address":["0xd4eaf2a5da8c51a30c245ad71a0b93f39fa1ec53"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],null,["0x000000000000000000000000d1292d09173fc26cb82ddcc047d5d19f7369d56e"]],"resultHash":"0x99ac7ca7a080e32bb806e2778fae4c40458c9523cfbcc8d25a5fa230a2437413"},{"fromBlock":7398809,"toBlock":7485698,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0x1d9f30260051d51d70339da239ea7b080021adcaabfa71c9b0ea339a20cf9a25"],["0x0000000000000000000000000000000000000000000000000000000000000015"]],"resultHash":"0x1dde9a7da4c58f19024a86f7e007208b87e455fff29fcf95098fe465e7d45543"},{"fromBlock":2346203,"toBlock":2450447,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"]],"resultHash":"0x67578e8c26d27184f314c76b81139d12c37646a9a584a5574f501a61b04f542c"},{"fromBlock":7412101,"toBlock":7528561,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb866a6a0e2e61faed988e0bd43c72660555c08b927c684f2c415d2b01ed7cc46"},{"fromBlock":4458569,"toBlock":4531620,"address":[],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x00000000000000000000000045da549856896a4f2ceb02d7512c8dc41a6f0a86"]],"resultHash":"0x795ffd862a08112e31f7e9e51575fd2d79f85360c7f85290eb2e87412f2aca7f"},{"fromBlock":7400338,"toBlock":7573531,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000010"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x32502b9fe1cd4cbc7831f54bead8899793bb64833946acfdd69e40e722ade2f5"},{"fromBlock":2375233,"toBlock":2526190,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999"],"topics":[],"resultHash":"0x75fa85e6a0860afd93385e1d5e30c61948a6fc6f047a9b8201a4be5242e44109"},{"fromBlock":4385662,"toBlock":4447501,"address":["0xd4eaf2a5da8c51a30c245ad71a0b93f39fa1ec53"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],null,["0x000000000000000000000000d1292d09173fc26cb82ddcc047d5d19f7369d56e"]],"resultHash":"0xa91eb9fed34f3f65996df6f1019cb9f134d521d370645bf5fa21fda6c1944bb0"},{"fromBlock":7405793,"toBlock":7485690,"address":["0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[null,null,["0x00000000000000000000000089009d02e4da2eaa8c1553bc8ecc2fce27cc97cd"]],"resultHash":"0x7a2b37313beae18153b4362d3985ec9af77471c7808f89dd556a4dfe357a170f"},{"fromBlock":4500308,"toBlock":4557601,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0x0c919b7ca9aaf46e00c122d30082dffe8b4e81ddd60992ea8f114b18a4ce7dd3"},{"fromBlock":6234966,"toBlock":6286957,"address":["0x9dcc53737fcb3e86a17cf435ca3c15390d4fc7ed"],"topics":[["0xbaa1d762384057169afd12b625998a5a7ed502c2e229acdbead30f3f6496399d"]],"resultHash":"0x9b16b111c2e538988e7e6e05aee62589bab50d1577ad8e14d50b24ab0f513501"},{"fromBlock":1871348,"toBlock":1968246,"address":["0x708d0ec21e1639fd70f4316474ad21a84c9540fc"],"topics":[["0x1b205f71b08271339a2b02ceaf7d8533d96f8cf7ddc94948c274c49565497f34"]],"resultHash":"0x7526ec0fc980f7a71a486e9e3a2f88f77df3793e64c71e3ca40cf7c40521a788"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":7412101,"toBlock":7528561,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb866a6a0e2e61faed988e0bd43c72660555c08b927c684f2c415d2b01ed7cc46"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":7403222,"toBlock":7520095,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000015"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x6603c84b17286e4642b4d34df969732b8807e223dcd24adcab7865a25ac75101"},{"fromBlock":4481230,"toBlock":4566120,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000007217fbb1337462be420b271cd77f213a20354e33"]],"resultHash":"0x95b720070c44e878de527d3f6cd51be631f4bd866a05a06f438c1917174db077"},{"fromBlock":6556416,"toBlock":6791440,"address":[],"topics":[null,null,["0x000000000000000000000000f984be01f03d2866b2ef96ec95aa865304aacc8c"]],"resultHash":"0x165259c3a8ec7bf80d8e94d577c681d137f614ae431e13f28de9d8344e5e1753"},{"fromBlock":5402883,"toBlock":5563969,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf0acf909b2f222d6665c5f38d5e1601db7ad49e18b3112733f38700a9109c63e"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":3281755,"toBlock":3357452,"address":["0x7afc4f6c9677d42f36ac11225ce612140a5bc968"],"topics":[],"resultHash":"0x83ef99164dfff81cc06a33b183516ee6b0d18f862f5d899506b103ec3f380be2"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2852708,"toBlock":2904307,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xcb594379bee7a4135be6e90141b4358269984f0c8b1bd13ee8c5335cfde0dba3"},{"fromBlock":6125361,"toBlock":6437424,"address":[],"topics":[["0x00d05ab44e279ac59e855cb75dc2ae23b200ad994797b6f1f028f96a46ecce02"],null,["0x00000000000000000000000000000000000000000000000000007ac8230b7000"]],"resultHash":"0xe1ed78400266a71f700832a1ea5dd3b8280e0badd986633cdb5c84f61a67f230"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":3375304,"toBlock":3504687,"address":["0x5c7a6cf20cbd3eef32e19b9cad4eca17c432a794"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x5bd7b2cb2a274f35c85795cd6d80cd18f42dc5cf09ca9e01359600814e40c507"},{"fromBlock":3403868,"toBlock":3433558,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null,["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0xbe82c5b4dcea0770f02a448d4e85cdbf24c9b8ef636ba92039dc959c58a17e14"},{"fromBlock":7412101,"toBlock":7528561,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb866a6a0e2e61faed988e0bd43c72660555c08b927c684f2c415d2b01ed7cc46"},{"fromBlock":7414222,"toBlock":7498447,"address":["0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[null,["0x000000000000000000000000b224f94546e61638241211a3e6ebb75b6664fc42"]],"resultHash":"0xae8e2b5d653d7121de28245b6b83c35a322a43e18afd0737d042ad7a7d2e772b"},{"fromBlock":2861852,"toBlock":2908608,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"]],"resultHash":"0x79ccd42eb26f5919a1689cb2be2e3266ffb59e6d12071a04f8424e0a8110173c"},{"fromBlock":3282677,"toBlock":3602558,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000026baac08cb753303de111e904e19baf91e6b5e4d"]],"resultHash":"0x86dae19fc52506ccb98084c0ccb077e16af7e3ae04c5b45e2a4cb02d9bd3b0ae"},{"fromBlock":7412101,"toBlock":7528561,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb866a6a0e2e61faed988e0bd43c72660555c08b927c684f2c415d2b01ed7cc46"},{"fromBlock":1862387,"toBlock":2013963,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null,["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0x07db5401bd4dd3dc7b0d6f0464e5fd1daa64c46ee4c45557aee729decf928ae2"},{"fromBlock":5402883,"toBlock":5563969,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf0acf909b2f222d6665c5f38d5e1601db7ad49e18b3112733f38700a9109c63e"},{"fromBlock":5482148,"toBlock":5538088,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa68b2e94fd56c4e7225825007873c721a6f66eeee4e1c171df9bee91a15f70c3"},{"fromBlock":4482416,"toBlock":4521277,"address":[],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x000000000000000000000000b1927224f07b070ae2e52fc03c8dab39f345ea89"]],"resultHash":"0xb177e29ed9be101f97c893f44db939742e8bcfa71cb56c6f4cb4dbabb8e54c29"},{"fromBlock":7418359,"toBlock":7527299,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0x1d9f30260051d51d70339da239ea7b080021adcaabfa71c9b0ea339a20cf9a25"],["0x0000000000000000000000000000000000000000000000000000000000000015"]],"resultHash":"0x0e728b804db3f558b14f2658caa2e738fd090b3fab6b2feb5e8d526e67498779"},{"fromBlock":6234966,"toBlock":6286957,"address":["0x9dcc53737fcb3e86a17cf435ca3c15390d4fc7ed"],"topics":[["0xbaa1d762384057169afd12b625998a5a7ed502c2e229acdbead30f3f6496399d"]],"resultHash":"0x9b16b111c2e538988e7e6e05aee62589bab50d1577ad8e14d50b24ab0f513501"},{"fromBlock":6191947,"toBlock":6247160,"address":[],"topics":[["0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f"],null,["0x000000000000000000000000c7b98f0a54849b8ff5d45fd97988581da37d167f"]],"resultHash":"0x14c9276fcde8626957e6ebb0a6d19469ee02d10a13b47d55181ebdfd43384870"},{"fromBlock":7402844,"toBlock":7567043,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000013"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x83d06f80db07f05a16e09b843e20497ace2a69f81b3c008b92fc424750dd4e82"},{"fromBlock":7416848,"toBlock":7491327,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000010"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x6481428cd13cdc8947047174eae9b1ee45729b3bb108a50e9b2884ed842a0393"},{"fromBlock":7411206,"toBlock":7498874,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000015"]],"resultHash":"0x84cf9f2d57e97436df8ecd075eabe3384ef512541015fe036a5960bcb0de8d7c"},{"fromBlock":2853102,"toBlock":2903629,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"],["0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0x0398749d0d8ffa626f970d8ef589cc6295b227b728d80641b09ee9d269003f41"},{"fromBlock":2839477,"toBlock":2900104,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0xd1dfa2efdd8ac1b42eae75fa2566f47e9b22257e0f0a20be30668bf70de77a48"},{"fromBlock":7398298,"toBlock":7505084,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000017"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x56780f5f764fdf19693368b234645fa29f9576f0366dcd6b4863fe9fd61337fa"},{"fromBlock":7421806,"toBlock":7488067,"address":["0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000089009d02e4da2eaa8c1553bc8ecc2fce27cc97cd"]],"resultHash":"0x1ddb944c089bf1de55c71e33b5d80a29770ef4b082998fbe1ae52d86649305b0"},{"fromBlock":7406849,"toBlock":7477439,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000007bcc97d1f73b023734187299fc9ea0915294c050"]],"resultHash":"0xae31d89b587fef4fee5fb7df9142ee69e41df20f38ad5913b95dd207a43ab62f"},{"fromBlock":5483649,"toBlock":5535687,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[null,["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa75498e7efe7d98df5217f5aff858e54c8c28c6c3ee1e1cc69b4a20baa5be810"},{"fromBlock":7411112,"toBlock":7501401,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000016"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x5d55946325b61453931e871b5950eb0cd634dc08856055b897bc0d3f6c2bfe30"},{"fromBlock":1882401,"toBlock":1955972,"address":["0x708d0ec21e1639fd70f4316474ad21a84c9540fc"],"topics":[["0x1b205f71b08271339a2b02ceaf7d8533d96f8cf7ddc94948c274c49565497f34"]],"resultHash":"0x79ffc1360277e46e806f511226de6b7cd5425c93ceeb0a56a93923b671ccc8de"},{"fromBlock":7406536,"toBlock":7524130,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000015"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x225e2c7281787c68343812c3a5ec66b47edacf6d474df1952093adc3bd77f765"},{"fromBlock":7401931,"toBlock":7638124,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000010"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x7a8d27e8293c5ee889ea70ca28b5b2e7d1a7683ca8a994ba6e4d1a77e2f0ebe3"},{"fromBlock":3283310,"toBlock":3527939,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000026baac08cb753303de111e904e19baf91e6b5e4d"]],"resultHash":"0x86dae19fc52506ccb98084c0ccb077e16af7e3ae04c5b45e2a4cb02d9bd3b0ae"},{"fromBlock":6837948,"toBlock":7000658,"address":["0x582cc5d9b509391232cd544cdf9da036e55833af"],"topics":[["0xd342ddf7a308dec111745b00315c14b7efb2bdae570a6856e088ed0c65a3576c"]],"resultHash":"0xc30f94d49fd2aa54f43e201b9ba3cd9d306b522618f79d75c3818b4f11a3895d"},{"fromBlock":2859845,"toBlock":2915517,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0x34c1e5422b2de68e1a1c46651c1afbecede628583b6a50a7f41f0c69ccd85d63"},{"fromBlock":7398779,"toBlock":7484931,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],["0x0000000000000000000000000000000000000000000000000000000000000018"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xb0fdacc23aa45519bd4f3f5de37c3618b16262b89d514dba11c988d3444cd7ed"},{"fromBlock":5429939,"toBlock":5565055,"address":["0x26b0fae932db549c4537fe1b563882583af9e0a5"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000ddc9ffbdb2b24f9e646b1a20fce1f6c78995043d"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xd6df9eafd9291851246cf19652c661cac086c302175ffc01b34facb85767b27f"},{"fromBlock":7393221,"toBlock":7490518,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000018"],["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xe85626a892641ba8f156d7eba18fac95daeb2addb093f48132306546d540d4c6"}],[{"fromBlock":7284472,"toBlock":7315296,"address":["0x666ca6fc75b44f3ff2d321c5947031141409b152"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null],"resultHash":"0x4671ebc2307b53d91681e1f5d59d31709fc81211873b74ab90230d270a3fe11d"},{"fromBlock":2871651,"toBlock":2881283,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"]],"resultHash":"0xeb0ea1a3b6e5f0f6dc79f89f9c9fd0e79d341049957244ba61e6b83e7761f89c"},{"fromBlock":6255572,"toBlock":6276265,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":3411973,"toBlock":3430335,"address":["0xe20cf465a163c395e7dde1466cdd1abe695b4658"],"topics":[null,["0x0000000000000000000000000c4b9f731696bed1b0834f48a7f24e513dc3cfd7"],null],"resultHash":"0x3bb41f553effea092280722d2a49b212cb4ce266f09e4c4a342982f6cc9a3391"},{"fromBlock":5595503,"toBlock":5608828,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"],["0x00000000000000000000000098cbc1530bfec21f8d10662d769608217364513a"]],"resultHash":"0xff493896d83be90aa3a65755f94a40ab79453e6ed2ddb349468b34995d529aad"},{"fromBlock":2866012,"toBlock":2898386,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xdd985a938683015da8e1f7a53524a49d38eb31154a6ce7c0b94fd739bb0aae1f"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":6320202,"toBlock":6340301,"address":[],"topics":[["0x00d05ab44e279ac59e855cb75dc2ae23b200ad994797b6f1f028f96a46ecce02"],null,["0x000000000000000000000000000000000000000000000000000cca2e51310000"]],"resultHash":"0x66e9c6089ae1a135d167eb47238fb4590c468cbbdc8a1d950f466609a4e12936"},{"fromBlock":5767601,"toBlock":5788560,"address":["0xf158908549032149090d59eb86b7b38bd5d15621"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x96e15a8f7598519f6822606610b2f20b212622372c06bd0acbfa628df6857169"},{"fromBlock":2867182,"toBlock":2884938,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"]],"resultHash":"0x3f8459a2730466cef857ed8736a945c2145774da0e563bcdff6ccba16247bb23"},{"fromBlock":6255580,"toBlock":6276252,"address":[],"topics":[null,["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":2871768,"toBlock":2881746,"address":["0x295c871e10bff8f810043a03a647b7fe9e2dd7ef"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"]],"resultHash":"0xb99a52556ae4af1a37e6ea57fae7543789accde93f72c3aeab1adcbe07fd7585"},{"fromBlock":2871651,"toBlock":2881283,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x3ff7f127bfdad0831165c394e4ba67e4dd579d62f7830618b5da8d9f134b7c2e"},{"fromBlock":2545695,"toBlock":2558232,"address":["0x2d5a67ed56afe3f56ff035e3f269bd3b230b108a"],"topics":[],"resultHash":"0x975080c03432147244c5976c39e6b4ecd94dccfa5fa401aa6225f44e900dac0b"},{"fromBlock":4518982,"toBlock":4526318,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x00000000000000000000000083efd3ee9278cc7800e93e7f9a14607f5c331b3e"]],"resultHash":"0xe9efd4465a3ff5e9e857c79a111e7db36be45f7be6d8fcba198088f93ca822bf"},{"fromBlock":2871651,"toBlock":2881283,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x3ff7f127bfdad0831165c394e4ba67e4dd579d62f7830618b5da8d9f134b7c2e"},{"fromBlock":2857034,"toBlock":2892294,"address":["0x295c871e10bff8f810043a03a647b7fe9e2dd7ef"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0xfec538f56612c5f6a5e147cfaba3687daaca5a7f0d4c2ae623d61293e10d9696"},{"fromBlock":7060981,"toBlock":7080815,"address":[],"topics":[["0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0"],null,["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05","0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x96df148fc6fc0c177524ab68929b0f2a1124e5f8d727bb05cd9141329bb00f42"},{"fromBlock":2874369,"toBlock":2880544,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[],"resultHash":"0xa7037d915a722a03d3277c81d8097fbb7fcfbf2a32b4b7da41963a05611bf291"},{"fromBlock":2867182,"toBlock":2884938,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"]],"resultHash":"0x3f8459a2730466cef857ed8736a945c2145774da0e563bcdff6ccba16247bb23"},{"fromBlock":2545695,"toBlock":2558232,"address":["0x2d5a67ed56afe3f56ff035e3f269bd3b230b108a"],"topics":[["0x11cedc7f83a9a6f5228b8fcd3c3c0ae686a51e2e04ea46923e3491a32a4bbaa8"]],"resultHash":"0x975080c03432147244c5976c39e6b4ecd94dccfa5fa401aa6225f44e900dac0b"},{"fromBlock":2871532,"toBlock":2881494,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x7913f167e2bd1437b78bb3107e649962917783da57469af8148341ef3f326778"},{"fromBlock":2871333,"toBlock":2883472,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x826375c90b7dd722a1a4ab9d1117acd2fecc0f1ff67e2125ef3619d9796082d7"},{"fromBlock":2865895,"toBlock":2897932,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000005b942fcd936702a00df9277bae624f8b6da9e2b3"]],"resultHash":"0x7422d194438522f7fd9cfa09746c3740cd2d5aaae0665ff777c4af0e89d9e55a"},{"fromBlock":7448059,"toBlock":7469066,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x281c6d712ecdf865375a9be14eae7644e39bdcbebd4aa2ed020abf04d01f3445"},{"fromBlock":2864150,"toBlock":2891299,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0xe06d22f7ca749d47286067c59b2b15dbf03e9e03385d26bd4a826cf1ca208aa5"},{"fromBlock":7284472,"toBlock":7315296,"address":["0x666ca6fc75b44f3ff2d321c5947031141409b152"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x4671ebc2307b53d91681e1f5d59d31709fc81211873b74ab90230d270a3fe11d"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[null,["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":2867182,"toBlock":2884938,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"]],"resultHash":"0x3f8459a2730466cef857ed8736a945c2145774da0e563bcdff6ccba16247bb23"},{"fromBlock":5772645,"toBlock":5786223,"address":["0x034b7ccf069fe523de04f765fc22356a099a9853"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x791ce784407488b8856f44112a7b356edda92788275a6a0e90a7edb0839ba758"},{"fromBlock":3421821,"toBlock":3426164,"address":["0x5c7a6cf20cbd3eef32e19b9cad4eca17c432a794"],"topics":[null,null,null],"resultHash":"0xaa3d8fec2a6908fda6d1f60055a1c0db2869003728d5f9df66f40444c5a95f0e"},{"fromBlock":7452142,"toBlock":7458903,"address":["0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x2f9d039fc87f2fffa599117087b74b778af945d324b855a211d626f9191dcffc"},{"fromBlock":2866096,"toBlock":2885370,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0xbe42c404ae6281fa8cebd817284d41027820c8485f1bc9b86436501d0ddc35c9"},{"fromBlock":4515660,"toBlock":4528755,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[null,null,["0x000000000000000000000000db412c9598c41d72778744d8ee7d028214f00282"]],"resultHash":"0x84e0b361b020e60e45eb4ad1f8119871ecc517ca4b8d88929e50eeca7cc473c0"},{"fromBlock":7451293,"toBlock":7456945,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[],"resultHash":"0x15a76618dbff170841832845ae71d143d16be85fe299362ad56222dc8027fde6"},{"fromBlock":2871090,"toBlock":2884924,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"]],"resultHash":"0xbc933b216df1a3d91169dc5405171f3716c0995b7a260b3717ed4b964471bdf8"},{"fromBlock":2501204,"toBlock":2507597,"address":["0x13e9cc252d1ba1c6a25bf12597bf5dc608689e32"],"topics":[["0xdd71a1d19fcba687442a1d5c58578f1e409af71a79d10fd95a4d66efd8fa9ae7"]],"resultHash":"0xbe1e24d4f2bef0f4c7a09a7f2a95d6bd50e31ca84d9d7287a8a592f7c1c12c45"},{"fromBlock":5015531,"toBlock":5040888,"address":[],"topics":[["0x435e19089f6ae5362a112155f011980907d2ff69b4c2bb894f8324260650ee6a"]],"resultHash":"0x74f2128b7c84cc2ee59bed973028edbeea259d07e8789b080cac700be9357dbc"},{"fromBlock":6320202,"toBlock":6340301,"address":["0x27f03f2422f0c3715bec8e43bf5bcd178ab406b4"],"topics":[["0x00d05ab44e279ac59e855cb75dc2ae23b200ad994797b6f1f028f96a46ecce02"],null,["0x000000000000000000000000000000000000000000000000000cca2e51310000"]],"resultHash":"0xa83cdf0b0fd2ea77e0097372e19d7c8f857c23351ad6d2a278afe5af24c2d34b"},{"fromBlock":4359240,"toBlock":4366818,"address":["0xb0910e7c7adec52ef3bae5db9d01fd967a22fb7b"],"topics":[],"resultHash":"0x18e60409276bd0e6742aa0dcc04d87735cd64e919c4dd851f34e7f3a14b90223"},{"fromBlock":2545695,"toBlock":2558232,"address":["0x2d5a67ed56afe3f56ff035e3f269bd3b230b108a"],"topics":[["0x11cedc7f83a9a6f5228b8fcd3c3c0ae686a51e2e04ea46923e3491a32a4bbaa8"]],"resultHash":"0x975080c03432147244c5976c39e6b4ecd94dccfa5fa401aa6225f44e900dac0b"},{"fromBlock":4519005,"toBlock":4526285,"address":[],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x00000000000000000000000083efd3ee9278cc7800e93e7f9a14607f5c331b3e"]],"resultHash":"0x1bbd2efde01bf9df0a341cb65496ce44d6f11dff5e4df9fb3e041d7bdcc8c026"},{"fromBlock":4428726,"toBlock":4436405,"address":["0x8737a1c3d55779d03b7a08188e97af87b4110946"],"topics":[["0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x000000000000000000000000000000000000000000000000b8159170038f96fb"]],"resultHash":"0x4b6ae8bdde8dc5547be7bf147b17fc3019d4d03ca4d6f4a17346e25746f47808"},{"fromBlock":5409980,"toBlock":5414794,"address":["0x182ec567f33ac802e9e80c0a0bbe7610d5923e0e"],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"]],"resultHash":"0xe42cf4b3c6cf6ef35ea492559385ce9e928650a0ba1d24fcb62cb907c61f7db8"},{"fromBlock":4519005,"toBlock":4526285,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x00000000000000000000000083efd3ee9278cc7800e93e7f9a14607f5c331b3e"]],"resultHash":"0x1bbd2efde01bf9df0a341cb65496ce44d6f11dff5e4df9fb3e041d7bdcc8c026"},{"fromBlock":7448059,"toBlock":7469066,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x281c6d712ecdf865375a9be14eae7644e39bdcbebd4aa2ed020abf04d01f3445"},{"fromBlock":7448059,"toBlock":7469066,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x281c6d712ecdf865375a9be14eae7644e39bdcbebd4aa2ed020abf04d01f3445"},{"fromBlock":3317369,"toBlock":3329704,"address":[],"topics":[["0x27333edb8bdcd40a0ae944fb121b5e2d62ea782683946654a0f5e607a908d578"],null,["0x0000000000000000000000003367dfa11e3148a07c2da773e1f65b155b0abe56"]],"resultHash":"0xe8133c50deccf421e9ee03e7467ee28573fac1cd24f84216d01a02d23af47a68"},{"fromBlock":4417825,"toBlock":4437464,"address":["0xc86d830fd72e77673c5f58014c530f6242378bc7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000e0ffca70d862314ca067bb03813f52bd9225459"],["0x000000000000000000000000cd48b1739d2f1a72705320a9025d057262bc41de"]],"resultHash":"0xb204b27986191e7c8492a463e396154796f186283d65a8c795655641c876203a"},{"fromBlock":2706902,"toBlock":2722781,"address":[],"topics":[["0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"]],"resultHash":"0xbb445fc14615421c7ad21e3675551a39d6f06fd2bb0b578bb92364dbc6a1aca6"},{"fromBlock":5776890,"toBlock":5783469,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000b8714f0a601b432e37a1e78854492f8e4bd52f75"],null],"resultHash":"0xc0eba7960dca2bdffed2ee981f840e13f2707c7ef94b6b0b22a1d10341027ac3"},{"fromBlock":7452142,"toBlock":7458903,"address":["0xa06bc650f98c11fbe102bece34df529650a60de6"],"topics":[],"resultHash":"0x2b52a74e56d877bac69685dc4f5a203bff1b6506f3de4e51044edaed9ff77445"},{"fromBlock":2863083,"toBlock":2888077,"address":["0x295c871e10bff8f810043a03a647b7fe9e2dd7ef"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x1303d3652e7e369d13a65e15e8669c3d70bfad431862c435d821a1f66490f079"},{"fromBlock":2867198,"toBlock":2886423,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0x72501d9c75ef392649698fa19e50d369c56f78864d2ae47543effe816a4a396b"},{"fromBlock":5015531,"toBlock":5040888,"address":["0xd098701586c4fdbbdf6081d2a85209c812c7d045"],"topics":[["0x435e19089f6ae5362a112155f011980907d2ff69b4c2bb894f8324260650ee6a"]],"resultHash":"0x74f2128b7c84cc2ee59bed973028edbeea259d07e8789b080cac700be9357dbc"},{"fromBlock":2545695,"toBlock":2558232,"address":["0x2d5a67ed56afe3f56ff035e3f269bd3b230b108a"],"topics":[["0x11cedc7f83a9a6f5228b8fcd3c3c0ae686a51e2e04ea46923e3491a32a4bbaa8"]],"resultHash":"0x975080c03432147244c5976c39e6b4ecd94dccfa5fa401aa6225f44e900dac0b"},{"fromBlock":4430318,"toBlock":4436731,"address":["0x8737a1c3d55779d03b7a08188e97af87b4110946"],"topics":[["0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x000000000000000000000000000000000000000000000000b8159170038f96fb"]],"resultHash":"0x5c07c9eda4b9579fd357276bfb82823f564a37bb7d9cdf550f70027945b2dc2e"},{"fromBlock":3317037,"toBlock":3329804,"address":["0x4b5011c89f3e727b71e113334e36ff70972a969f"],"topics":[["0x27333edb8bdcd40a0ae944fb121b5e2d62ea782683946654a0f5e607a908d578"],["0x0000000000000000000000007f2698714842f59e89f1eb8b1b70ccb053b5a176"],["0x0000000000000000000000003367dfa11e3148a07c2da773e1f65b155b0abe56"]],"resultHash":"0x96a2bd130d8993f9c893511f0f83ebe3eaeb369a2f028ef5b552bf247604fa78"},{"fromBlock":2426609,"toBlock":2442439,"address":["0x85edb7a0cbacf5bd641e0ff5d6270bef9c72bd6b"],"topics":[],"resultHash":"0x1738195edc9f3fac0032c25682856c240658ccaeef8b80de6b6b12d2176607fd"},{"fromBlock":4519005,"toBlock":4526285,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x00000000000000000000000083efd3ee9278cc7800e93e7f9a14607f5c331b3e"]],"resultHash":"0x1bbd2efde01bf9df0a341cb65496ce44d6f11dff5e4df9fb3e041d7bdcc8c026"},{"fromBlock":5015531,"toBlock":5040888,"address":["0xd098701586c4fdbbdf6081d2a85209c812c7d045"],"topics":[["0x435e19089f6ae5362a112155f011980907d2ff69b4c2bb894f8324260650ee6a"]],"resultHash":"0x74f2128b7c84cc2ee59bed973028edbeea259d07e8789b080cac700be9357dbc"},{"fromBlock":5601641,"toBlock":5607811,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[],"resultHash":"0x863719269e9dc7c254a0fd25b1eebe8558f75ccc90aec0f681b2ec7638bb0791"},{"fromBlock":4359240,"toBlock":4366818,"address":["0xb0910e7c7adec52ef3bae5db9d01fd967a22fb7b"],"topics":[["0x5e1276d0e2c70e310694b5a7522e8710ee90fe71e646e8a1307024f214566a36"]],"resultHash":"0x18e60409276bd0e6742aa0dcc04d87735cd64e919c4dd851f34e7f3a14b90223"},{"fromBlock":7593516,"toBlock":7627518,"address":["0xbbd234155c2e2aa78fb4de2299db0b3b5b40600a"],"topics":[],"resultHash":"0x0ed08e047cebf302edc2751f3f2cb5a34abd98365c7d65ca9721f89622068740"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":2868071,"toBlock":2885866,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0xfd399afe985193cb10afa6abaddf7bb6a1750a1f5f427970d61f3dae620c7724"},{"fromBlock":2501204,"toBlock":2507597,"address":[],"topics":[["0xdd71a1d19fcba687442a1d5c58578f1e409af71a79d10fd95a4d66efd8fa9ae7"]],"resultHash":"0xbe1e24d4f2bef0f4c7a09a7f2a95d6bd50e31ca84d9d7287a8a592f7c1c12c45"},{"fromBlock":2865928,"toBlock":2885459,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x0cd06634724893c07bf18b8e8b7616db7fd3647a2e13fc4b63b3952f8bba47ac"},{"fromBlock":3416388,"toBlock":3442563,"address":["0x5c7a6cf20cbd3eef32e19b9cad4eca17c432a794"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],null,null],"resultHash":"0x7cff77806fd31155ecbb4cc274a430283c6757040a4048b395c16e9b46170f97"},{"fromBlock":7446867,"toBlock":7463757,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x6cc35a7707ee763849a645c248668601468da4aed4439cf1a0e92a6e747a23ae"},{"fromBlock":5601641,"toBlock":5607811,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x863719269e9dc7c254a0fd25b1eebe8558f75ccc90aec0f681b2ec7638bb0791"},{"fromBlock":4515660,"toBlock":4528755,"address":[],"topics":[null,null,["0x000000000000000000000000db412c9598c41d72778744d8ee7d028214f00282"]],"resultHash":"0x245e024bf264627d14ba9577049f82ee61f355de9a718060b18285654d6917cb"},{"fromBlock":3317037,"toBlock":3329804,"address":[],"topics":[["0x27333edb8bdcd40a0ae944fb121b5e2d62ea782683946654a0f5e607a908d578"],["0x0000000000000000000000007f2698714842f59e89f1eb8b1b70ccb053b5a176"],["0x0000000000000000000000003367dfa11e3148a07c2da773e1f65b155b0abe56"]],"resultHash":"0x96a2bd130d8993f9c893511f0f83ebe3eaeb369a2f028ef5b552bf247604fa78"},{"fromBlock":2863218,"toBlock":2888686,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0x4ac3047fe503798f4b73b7c64f9da1845837f8617861c2e46e3ae6d3828bbda4"},{"fromBlock":7449076,"toBlock":7463225,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[null,null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xc9afa2e32c4f9dd400462c2f4dfcf4739181a3c96d6b94e02d523780efe232fc"},{"fromBlock":7447036,"toBlock":7459203,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"]],"resultHash":"0xba1ee847df60d1e71be77814f6e729714faf5b4e1c728344e77a5c981b72e209"},{"fromBlock":4856412,"toBlock":4857687,"address":[],"topics":[["0xb9fa1caa1e1541788a4b5cd68270e6d375e3a28f4f94017af9351c5955d58fa7"],null,["0x00000000000000000000000000000000000000000000000000000000000017b0"]],"resultHash":"0x88eedc10bfe45114515f6b2c843f728644744134fe180206e8e530fc20591094"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":7448059,"toBlock":7469066,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x281c6d712ecdf865375a9be14eae7644e39bdcbebd4aa2ed020abf04d01f3445"},{"fromBlock":4417825,"toBlock":4437464,"address":["0xc86d830fd72e77673c5f58014c530f6242378bc7"],"topics":[null,["0x0000000000000000000000000e0ffca70d862314ca067bb03813f52bd9225459"],["0x000000000000000000000000cd48b1739d2f1a72705320a9025d057262bc41de"]],"resultHash":"0xb204b27986191e7c8492a463e396154796f186283d65a8c795655641c876203a"},{"fromBlock":7445147,"toBlock":7464578,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0xed3b3841ea5b2491e5f82b221bf98f083257e9983f601ac390c617d0e8c0037f"},{"fromBlock":5597184,"toBlock":5608306,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000098cbc1530bfec21f8d10662d769608217364513a"]],"resultHash":"0xad08a6a11cfeb2d8150bc6a3385d12977d344fc3714e08643082ea429c0d1f8f"},{"fromBlock":2574122,"toBlock":2583701,"address":[],"topics":[null,["0x00000000000000000000000089a5f2c62213b18ee5f83b21cb1a323920c9b101"]],"resultHash":"0xaedc313ad31d6b984dc2f9e4d1feb64063c84f539fc3f6da90059f82592724af"},{"fromBlock":2860514,"toBlock":2889605,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"]],"resultHash":"0x5202007a2095bc5408ce1b279c54399838934b63cad0205ce0cff93d93a0a6ea"},{"fromBlock":2874186,"toBlock":2884030,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0xdff7f0423c528b982f61468e0837e69364b48d9092ca83b883a14e9a23eba053"},{"fromBlock":3412532,"toBlock":3450477,"address":["0xfda9adbc51ca64d932621e7711caac40f98025d8"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],null,null,["0x0000000000000000000000008d37ac95786c542a0f2760a182a6936ba34d0b42"]],"resultHash":"0x5e15bf2eb0262388321d4a6c76a064df8685d51570efaa4d2831425051e88acd"},{"fromBlock":2873839,"toBlock":2882996,"address":null,"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x0000000000000000000000000000000000000000000000000000000154486d40"]],"resultHash":"0x1f9b060d3237805a634f7b5645fa44c56aeb4c8f7e3950c5e19530b09bfa6115"},{"fromBlock":7571103,"toBlock":7576927,"address":["0xfe17d34dc09666ea591825bb0a3f90167573eb6c"],"topics":[],"resultHash":"0xe52bde12042066d2e1a507cf89b3ba373ac2ed16cf1d3884a4a06c9a4b293c61"},{"fromBlock":5597870,"toBlock":5611067,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[null,null,["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"]],"resultHash":"0x7b559e0db68fc9c73550f5d92a0fe334a4d28d9c023829396bc31c42fb390976"},{"fromBlock":5340753,"toBlock":5346010,"address":["0x63eaf4307d4ac2010d6abf2cce570ca11a5cf30f"],"topics":[["0x9866f8ddfe70bb512b2f2b28b49d4017c43f7ba775f1a20c61c13eea8cdac111"]],"resultHash":"0x9efe47324df7bf9a58672e7737d856be0cf31dae2af5b2252e39d669fd972d0d"},{"fromBlock":1903235,"toBlock":1915633,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xca317d26c2f3e87cf994633351760bd8f8f697bdde68d2d220351becb34faecc"},{"fromBlock":2870278,"toBlock":2885241,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"],["0x000000000000000000000000257a443076cab725287f3930fb024e15fa550fa2"]],"resultHash":"0xedb804a1d67b1f2f29c7d5db21d9a947bf39f7f83354d5472689bcdc26b8e433"},{"fromBlock":2866139,"toBlock":2892532,"address":["0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000d9c35bb2e27f4cbe1bedb8894414b94bda4232c0"]],"resultHash":"0xd8a88a59c02e00897ff59b04c5913a64c574d6115f661321f4a7e5a7b6f43087"},{"fromBlock":2868003,"toBlock":2885082,"address":["0x53eab61b720c4ed4bb886c681f4f69385e15f201"],"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c"],["0x000000000000000000000000000000000000000000000000000000038416f940"]],"resultHash":"0x9df5228b0616b1c72f537ea86ad76c1606c4114652f5692a78bfedcc224bb085"},{"fromBlock":5601603,"toBlock":5608203,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"]],"resultHash":"0xf82a1b429f36a09f1f2d0e860ca789b669f832138a81dd8cad18ab58b6361ef8"},{"fromBlock":7448059,"toBlock":7469066,"address":["0x32d33d5137a7cffb54c5bf8371172bcec5f310ff"],"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null,["0x0000000000000000000000000325686a18aa829b9faaad70f22ea0830aa6076f"]],"resultHash":"0x281c6d712ecdf865375a9be14eae7644e39bdcbebd4aa2ed020abf04d01f3445"},{"fromBlock":5601641,"toBlock":5607811,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"]],"resultHash":"0x863719269e9dc7c254a0fd25b1eebe8558f75ccc90aec0f681b2ec7638bb0791"},{"fromBlock":5597193,"toBlock":5612047,"address":["0xfdfd239c9dd30445d0e080ecf055a5cc53456a72"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"],["0x0000000000000000000000009337117fe4fde0335a4f7cdbadca0862fe29f668"]],"resultHash":"0x2cfd3e39bc82692099446cf568590f5628b0eaec6f441acd976c6226fe9d8265"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"},{"fromBlock":6255580,"toBlock":6276252,"address":["0x26280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],"topics":[["0xb4e1304f97b5093610f51b33ddab6622388422e2dac138b0d32f93dcfbd39edf"],["0x00000000000000000000000081b9c651549b1af22b51b734bdcc968722dacba0"]],"resultHash":"0xed70e01668fd02978926418e13e49dcc8c13cdd444e2b94ed9e7e617bd16dec6"}],[{"fromBlock":7754096,"toBlock":7755210,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x36abdf19849b466fa552c51cce4baadaf7927da2b9ab1e89c1058eb24a7a3de2"},{"fromBlock":7754011,"toBlock":7755111,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x8da1efa3210efcf4caa457632e2dd6ff6717ecb330bfff02dfc7e972de68aa86"},{"fromBlock":2817410,"toBlock":2819554,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000041e49d86fc1b767d6a02590fb8a8b6f3668a0018"],null],"resultHash":"0x31481fcb092850eb3361d4f71658921c4b03c50a9efa4109f37f45d1d2c37067"},{"fromBlock":2876716,"toBlock":2879641,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0x6d505007bdd75ff5ed6a8512c79b54285c40fd9b2c785a12daff60ab588e2652"},{"fromBlock":7754220,"toBlock":7755166,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x856c9ff69dc7e66c85ae9c6080e221fe26b81013db4c90fbe9c2d970701271d9"},{"fromBlock":6478713,"toBlock":6480825,"address":["0x04890fd959b09592c8c033e87e27ecb927c06e3d"],"topics":[["0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x00000000000000000000000000000000000000000000000048810ec3e431431f"]],"resultHash":"0xf43d275796c59a3e6dab8b6b5e3f59cee439d1dd304a1ffb8e4389851c63ce37"},{"fromBlock":2876716,"toBlock":2879641,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"]],"resultHash":"0x6d505007bdd75ff5ed6a8512c79b54285c40fd9b2c785a12daff60ab588e2652"},{"fromBlock":3030982,"toBlock":3031855,"address":["0x26223f9c67871cfcea329975f7bc0c9cb8fbdb9b"],"topics":[],"resultHash":"0xf23f951a9972589e6cbb512191a7e063005c086d05b7cf9808e18ea72cfb7532"},{"fromBlock":4908248,"toBlock":4912449,"address":["0x9ef7d57a4ea30b9e37794e55b0c75f2a70275dcc"],"topics":[null,["0x000000000000000000000000000000000000000000000000b8159170038f96fb"]],"resultHash":"0xe5e6d20544dcc76f605e7906c2eb8598b0ca69684099fbd40bc563409c66a753"},{"fromBlock":5712018,"toBlock":5713058,"address":null,"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3"],null],"resultHash":"0x35d184a0325d0e13a4a4a1748678f4e267050d122b6169e286ec3cc37ab69eeb"},{"fromBlock":6262236,"toBlock":6262827,"address":[],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"]],"resultHash":"0x99d876c62b58a2da7688af191ccfdaaee8166920caddc37a443986124dff23d9"},{"fromBlock":5598940,"toBlock":5599868,"address":[],"topics":[["0x2ac69ee804d9a7a0984249f508dfab7cb2534b465b6ce1580f99a38ba9c5e631"],null],"resultHash":"0x338beff6f966a940f4de1883098183896e3b82b9ffc006a9d2fdaa529c39ab3a"},{"fromBlock":4810897,"toBlock":4813172,"address":[],"topics":[null,null,null,["0x000000000000000000000000000000000000000000000000000000000000000f"]],"resultHash":"0x26b61e7cccf37d9d79af1949dfc8bef9465f191a20f7b2cbe4304a3710f25b72"},{"fromBlock":4741288,"toBlock":4742021,"address":[],"topics":[["0x59200007defbdd8d2c9e53dd05f81091fe977b424f38f2562df9ee8725d58469"],["0x9d6bae620ed8be3a38c5ad6a74fe994e1c3cfe3bbdce71474ba8b08b11b4f3eb"]],"resultHash":"0x6b2cab37e7dcd02c1ac2831e3d42ab54d814c23e83f90fa32d9efea2d8ae5543"},{"fromBlock":1825517,"toBlock":1826178,"address":["0xd86e1fedb7120369ff5175b74f4413cb74fcacdb"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"]],"resultHash":"0x3c7acc280640fc0506346ae237db6858d5a985320fb59fffd75ee7bd2a7890bc"},{"fromBlock":5492930,"toBlock":5493453,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x0000000000000000000000009ea18de905e654f9fb98498109c60edfe133c145"]],"resultHash":"0x17a72519887f781af3f397b0eac5b56aef52200337b37ba75f55d909f6a3ec45"},{"fromBlock":3030535,"toBlock":3032420,"address":[],"topics":[null,null,["0x0000000000000000000000007fe27d970bc8afc3b11cc8d9737bfb66b1efd799"]],"resultHash":"0x0777274284f6bb66fd5a224652190653a8719320c8d996cdad281a2bb45015e8"},{"fromBlock":5653528,"toBlock":5654841,"address":["0xd4aa4138e66700ba20ceba075f48ffe9d31cb177"],"topics":[],"resultHash":"0xf242eac00ed361cdeadf09d3cb4f87dd2ad744de5b8299fba5ef149dceb5b316"},{"fromBlock":3510085,"toBlock":3510756,"address":[],"topics":[null,["0x0000000000000000000000000000000062241003302aca83b655e463ec85e05a"]],"resultHash":"0x7df9afa4a613c99b8a270133a8a37c913835103e5e5ffee048b6642c23024887"},{"fromBlock":5598945,"toBlock":5599726,"address":["0xe1978b1d689a4f8b1989ba1293b87f8ed0b1137e"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000773adcc4e914a4ce0c647d8d5bc583ee6da5528a"],["0x000000000000000000000000f9dc021985e9869227ff3e5fcccc9a0ef2ce7ebd"]],"resultHash":"0x4d2963358ccc80410af09f7500d7a6ee7883c97a3a5c96a4db87bbbefca80f53"},{"fromBlock":5492882,"toBlock":5493475,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x0000000000000000000000009ea18de905e654f9fb98498109c60edfe133c145"]],"resultHash":"0x4dddd89c2363c84b025c3cf0aa814ad0137eaee3cfc8fbcb10f7eaf0a3b70006"},{"fromBlock":4113477,"toBlock":4115169,"address":["0x66d20c6aa53e7f2b1bdb539f12bed20eaacda79f"],"topics":[],"resultHash":"0x2130cf35fc4267cf4909956f24de1911e4a9ea89f28b4fdf7eb0b83771d1afcf"},{"fromBlock":3030128,"toBlock":3031924,"address":["0x26223f9c67871cfcea329975f7bc0c9cb8fbdb9b"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000002fe022ffcf16b515a13077e53b0a19b3e3447855"]],"resultHash":"0x1c06b76ebde2c35e8efc64def6ddc0adbed0050e312bfc2c61c994e0e96b6c41"},{"fromBlock":2817410,"toBlock":2819554,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000041e49d86fc1b767d6a02590fb8a8b6f3668a0018"],null],"resultHash":"0x31481fcb092850eb3361d4f71658921c4b03c50a9efa4109f37f45d1d2c37067"},{"fromBlock":2876693,"toBlock":2879814,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xc08d6f3a1c40699cd1f2cc30dc73be46c17ecae337a32faad17fc136b77f6307"},{"fromBlock":1528092,"toBlock":1531096,"address":[],"topics":[null,["0x1b549b7328c744f2b3b1dca394f6dcfbef53c46b82fad4ae76e09ba178eb550c"],["0x0000000000000000000000000000000000000000000000000000000000000001"]],"resultHash":"0x871aef3d4bb838dc9a93bbae3039dc1525177f79a3311b882b6ddc611023cb1c"},{"fromBlock":3422219,"toBlock":3427280,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000031f5b934a60f2c9b649a657e14f1a2b2e83f8ac7"],["0x0000000000000000000000000a36795b3006f50088c11ea45b960a1b0406f03b"]],"resultHash":"0xe886625ca614b4e9adfe4d640054c83a2843ac24d35d896becd7076c1aa5f641"},{"fromBlock":1528363,"toBlock":1531081,"address":[],"topics":[null,["0x1b549b7328c744f2b3b1dca394f6dcfbef53c46b82fad4ae76e09ba178eb550c"]],"resultHash":"0xecfd08401852763293902798b8e5db97aaed856cbdd9e0b7965f37c9aae22025"},{"fromBlock":2876716,"toBlock":2879641,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0x6d505007bdd75ff5ed6a8512c79b54285c40fd9b2c785a12daff60ab588e2652"},{"fromBlock":7636632,"toBlock":7637531,"address":[],"topics":[["0x9c7519dcf6aef530f7209189ddd559038a69f8bb53f818b7fa76c67379aa6b2c"]],"resultHash":"0x028691d18e507259dcb8ffe65d9c191bfa16c74445726045156e67c750805815"},{"fromBlock":2875554,"toBlock":2880068,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xf3165f923fa457fc62a5d73cf33be5845ef2d26092796431494565cde5152b3b"},{"fromBlock":7754220,"toBlock":7755166,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x856c9ff69dc7e66c85ae9c6080e221fe26b81013db4c90fbe9c2d970701271d9"},{"fromBlock":7369867,"toBlock":7370761,"address":["0x83e40da6b06fb6fa86fb73e24b17ff959d05fab0"],"topics":[["0xc5d455e9addd7a804d8865ad7de39474f361eb662373c346d94f86246e259037"]],"resultHash":"0xc28929c604d342587030989dba8c81605585530255a6daf7fa8b6e7c5b09dc75"},{"fromBlock":5404711,"toBlock":5405796,"address":["0xd3e770e4ae02993fc292d79af165727f92eb0765"],"topics":[],"resultHash":"0x60cd0a722b3c81479c82749f24d42ba7a2262b2af15b9d0509ef71d33cfbeca8"},{"fromBlock":3421466,"toBlock":3425281,"address":["0xe20cf465a163c395e7dde1466cdd1abe695b4658"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null],"resultHash":"0x797b6e81912ab51386daeac95dc1192c961e023f2dc51653fc3dde88c4a3419b"},{"fromBlock":2876326,"toBlock":2879062,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"]],"resultHash":"0x0a7648121e432ef9df2ed4aa93847eca942e213dd0f01924c259766c01021194"},{"fromBlock":6452241,"toBlock":6454183,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x00000000000000000000000028e66deb112ef12f67c13f6a198540bb0fdfeb45"]],"resultHash":"0xd67e567da2d4fb60a107b20c7793a5788088adc15122d0eadad72680052d14aa"},{"fromBlock":3381316,"toBlock":3383654,"address":[],"topics":[null,["0x000000000000000000000000e6b3b50f621d3b625714e1ea0e0f4f2abe2a84ec"]],"resultHash":"0xfcae662ea96ae9e47860934a49aaf9862da4820842065eb44e98c96d6dc7f63e"},{"fromBlock":6965510,"toBlock":6966807,"address":[],"topics":[["0xd342ddf7a308dec111745b00315c14b7efb2bdae570a6856e088ed0c65a3576c"]],"resultHash":"0x17dcb43ddb060f96aa89d9f8b4e58d2cc8d884996f645f69f848ba20bdf576f4"},{"fromBlock":6693316,"toBlock":6695466,"address":[],"topics":[["0x2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d466"],["0x000000000000000000000000878ac6ab417f57251b3192d4c86a4d175fd4ca22"]],"resultHash":"0xe6b48b2074e406a856a241a65b7000eef50addb8c406e6938ad1b0ffc58979fa"},{"fromBlock":7754089,"toBlock":7755177,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x956ee10d041782d9b2f7f134ca5ed071375a719c350fa6e404ffd39eb5e8728f"},{"fromBlock":3427167,"toBlock":3428459,"address":["0x9072495afc2d59d857118ee59b4ef6cfc407d103"],"topics":[null,["0x000000000000000000000000cd5b876728abbabc0515ef55e160c70b340c2705"]],"resultHash":"0x4bb75b87fa04dcc6141a7129090cbf6f9aec1afa01ca7936019bafa3479a6746"},{"fromBlock":5507318,"toBlock":5508308,"address":[],"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf891d59d92809541c53a742ccfb3d8ae4a0d15cb4bcd3c7f36d40440fc3e7ebc"},{"fromBlock":5492919,"toBlock":5493714,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x6b30f75cc259e51b40013e6037ddd081cb0e0764dc5cc0e5fb806868a12b504e"},{"fromBlock":5492919,"toBlock":5493714,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x6b30f75cc259e51b40013e6037ddd081cb0e0764dc5cc0e5fb806868a12b504e"},{"fromBlock":5492865,"toBlock":5493609,"address":null,"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],null],"resultHash":"0x7310d8ed477cbbdb59051cf4d29d0cd9c0b8ac1e46e8e743320bc2e188604969"},{"fromBlock":6425515,"toBlock":6426639,"address":["0x00c5c0b8e0f75ab862cbaaecfff499db555fbdd2"],"topics":[],"resultHash":"0x3e0462928a64b7c3565c21c75309c1fc7b7ff5b51b087e4953b844e4d6bd3b16"},{"fromBlock":2875089,"toBlock":2879558,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x000000000000000000000000428c4dc89b6bf908b82d77c9cbcea786ea8cc7d0"]],"resultHash":"0xcd39e89e3835d52f7af0be7a775f3599c84c96991401c4ccef91e618aae9a445"},{"fromBlock":7754209,"toBlock":7755190,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x2285a163c25091abbb665846e0e7a61792535da9db60a6c2f3273b460c5ea44a"},{"fromBlock":2876543,"toBlock":2880258,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xd350a8a8b799a7436760976960d562a7f4331ddc1f4239509ec9dd6a92a4841f"},{"fromBlock":4432159,"toBlock":4432945,"address":[],"topics":[["0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"]],"resultHash":"0x342209be770e1f88a5582c9e002af6e797c1373945ad2003f7060811b70d514c"},{"fromBlock":2876716,"toBlock":2879641,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0x6d505007bdd75ff5ed6a8512c79b54285c40fd9b2c785a12daff60ab588e2652"},{"fromBlock":6261871,"toBlock":6262655,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271","0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],null,["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x8c14a966efa550a3cd28ea2414f3230a830eb079dce71469e401fe4fcaa4bff3"},{"fromBlock":2876989,"toBlock":2879713,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"]],"resultHash":"0x2526e3e20adfceccf596fe8f62d5a65b86240ae410d41b64acba8db4c33af57e"},{"fromBlock":6762364,"toBlock":6763235,"address":["0x56171b3242587bb5c2c19883434dc054db525e91"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000eee96830f08c6835b706cbee997d431a94b55332"]],"resultHash":"0xde5af1160c34ac4d8ef31da5fb873c06340f5b140968a7d8e747cea4ee7265ea"},{"fromBlock":2525459,"toBlock":2525915,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000207cb7aeb640fa6cee696269dee1a441d0425a3d"]],"resultHash":"0xf212af5fe2f5fb510cf9c9adef06e1286d5f7ea26eeeb886f363298cd518ab91"},{"fromBlock":2876716,"toBlock":2879641,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0x6d505007bdd75ff5ed6a8512c79b54285c40fd9b2c785a12daff60ab588e2652"},{"fromBlock":4908248,"toBlock":4912449,"address":["0x9ef7d57a4ea30b9e37794e55b0c75f2a70275dcc"],"topics":[["0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],["0x000000000000000000000000000000000000000000000000b8159170038f96fb"]],"resultHash":"0xe5e6d20544dcc76f605e7906c2eb8598b0ca69684099fbd40bc563409c66a753"},{"fromBlock":5507081,"toBlock":5508454,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa7fd65e290742ea1189c96ad618e74a64db4f4757e65b636b714548c332640d0"},{"fromBlock":6221287,"toBlock":6223725,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f"]],"resultHash":"0xdaf95d5b8b18fe96cc3974500eee048d84a374c534434a5c38e6eef97d4746a8"},{"fromBlock":1873308,"toBlock":1874122,"address":["0xf549af21578cfe2385ffd3488b3039fd9e52f006"],"topics":[["0xf6a97944f31ea060dfde0566e4167c1a1082551e64b60ecb14d599a9d023d451"]],"resultHash":"0xf68b71f9cd5b4a4d482d9bb0f55dd619732c1b903901a88e94473725538208cc"},{"fromBlock":3163030,"toBlock":3164381,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000a68d4c1e3de1b721ad1356bbf827d6bc8cef304f"],["0x000000000000000000000000ab4493b5ca548110a4d7a9c494bfe473367cd3c8"]],"resultHash":"0xc0f5059efb8aca9c72bf5a4c67be47f0d9394e963f607d19d59bb27a0454163c"},{"fromBlock":5493015,"toBlock":5493715,"address":null,"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],null],"resultHash":"0xf6993c5dc9315ea1ec67939a66b127a030e3cc9059be6e2225d60ee7418e8fd6"},{"fromBlock":2875811,"toBlock":2879780,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xed47adfc7fc637ec595040d4012087a4ac35535805eb6dd58287d28fffa4b68e"},{"fromBlock":6422381,"toBlock":6423781,"address":["0x5ac5b7fd4550902ba12df16175f7d0a6ef8b0549"],"topics":[],"resultHash":"0x212a0dca029578e7fd5a7b9d2d886c69e88f338acaac04add22f79aade98ac36"},{"fromBlock":6262154,"toBlock":6262844,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],null,["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa13d466d1e237a9af3f4dddec1d9581acae9f69f18f98bc0ee0c3968b904b5c6"},{"fromBlock":3030611,"toBlock":3032656,"address":["0x7fe27d970bc8afc3b11cc8d9737bfb66b1efd799"],"topics":[],"resultHash":"0xfa53986c5c246c60170adfa114fcb4f398231c46f1e04c7f202567aada14a767"},{"fromBlock":2875808,"toBlock":2880072,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x000000000000000000000000428c4dc89b6bf908b82d77c9cbcea786ea8cc7d0"]],"resultHash":"0xbeed6c6249ad23674fd4611d02bf045a70e5ff1d6334d64380f25165db3cccb6"},{"fromBlock":5492919,"toBlock":5493714,"address":[],"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x6b30f75cc259e51b40013e6037ddd081cb0e0764dc5cc0e5fb806868a12b504e"},{"fromBlock":3422219,"toBlock":3427280,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000031f5b934a60f2c9b649a657e14f1a2b2e83f8ac7"],null],"resultHash":"0xe886625ca614b4e9adfe4d640054c83a2843ac24d35d896becd7076c1aa5f641"},{"fromBlock":2525345,"toBlock":2526342,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000051bdc8bd6d9d4d37d0d33c3439ac3c5fb960671c"]],"resultHash":"0x6124f71654af879e946a4d4583b03559f146e2ceb09027df1a59c700abf4799a"},{"fromBlock":2876196,"toBlock":2879408,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[null,null,["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xa9d88b176878ab1a1b0fa49a00a5826d3b48d9cd085bb7b0fc2b9a71fad3b327"},{"fromBlock":7369867,"toBlock":7370761,"address":[],"topics":[["0xc5d455e9addd7a804d8865ad7de39474f361eb662373c346d94f86246e259037"]],"resultHash":"0xc28929c604d342587030989dba8c81605585530255a6daf7fa8b6e7c5b09dc75"},{"fromBlock":2875808,"toBlock":2880072,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x000000000000000000000000428c4dc89b6bf908b82d77c9cbcea786ea8cc7d0"]],"resultHash":"0xbeed6c6249ad23674fd4611d02bf045a70e5ff1d6334d64380f25165db3cccb6"},{"fromBlock":5492857,"toBlock":5493587,"address":null,"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x0051122210c97e0812ed11f27bf2b573c7736f5a4bdfe947d94e08f01c57bf97"},{"fromBlock":7754089,"toBlock":7755177,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x956ee10d041782d9b2f7f134ca5ed071375a719c350fa6e404ffd39eb5e8728f"},{"fromBlock":7369867,"toBlock":7370761,"address":["0x83e40da6b06fb6fa86fb73e24b17ff959d05fab0"],"topics":[["0xc5d455e9addd7a804d8865ad7de39474f361eb662373c346d94f86246e259037"]],"resultHash":"0xc28929c604d342587030989dba8c81605585530255a6daf7fa8b6e7c5b09dc75"},{"fromBlock":2876318,"toBlock":2879230,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[null,["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x000000000000000000000000428c4dc89b6bf908b82d77c9cbcea786ea8cc7d0"]],"resultHash":"0xa361308f8d82b560e279cb90ee8b319488eca10417dbd66c92abb218a3495ab3"},{"fromBlock":2875619,"toBlock":2880156,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0x4ac70e54ceeb5f425482d3acbb2d35279a1ad514f5625bc3e0e72871353b6207"},{"fromBlock":6262154,"toBlock":6262844,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],null,["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"]],"resultHash":"0xa13d466d1e237a9af3f4dddec1d9581acae9f69f18f98bc0ee0c3968b904b5c6"},{"fromBlock":5342350,"toBlock":5345207,"address":["0x63eaf4307d4ac2010d6abf2cce570ca11a5cf30f"],"topics":[],"resultHash":"0x4068aa47a469144cdd32b3c71b4940469ef5432b4b680b232871755079098588"},{"fromBlock":2876295,"toBlock":2880243,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"],["0x0000000000000000000000001041d5b06b9f1e73a4d6ae4f4d2a3d5c9e0aa88e"]],"resultHash":"0xb364a14e519f6efb62895c410d795ebe633c7dec9460391ed4c9f7eea35408bb"},{"fromBlock":6221510,"toBlock":6223168,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[],"resultHash":"0x4200d26647709332d33cb4ce1f6bac9491e503e31f66c4d9e0fd43cda0fb8083"},{"fromBlock":2525345,"toBlock":2526342,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000051bdc8bd6d9d4d37d0d33c3439ac3c5fb960671c"],["0x000000000000000000000000207cb7aeb640fa6cee696269dee1a441d0425a3d"]],"resultHash":"0x6124f71654af879e946a4d4583b03559f146e2ceb09027df1a59c700abf4799a"},{"fromBlock":5598945,"toBlock":5599726,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x000000000000000000000000773adcc4e914a4ce0c647d8d5bc583ee6da5528a"],["0x000000000000000000000000f9dc021985e9869227ff3e5fcccc9a0ef2ce7ebd"]],"resultHash":"0x4d2963358ccc80410af09f7500d7a6ee7883c97a3a5c96a4db87bbbefca80f53"},{"fromBlock":6262154,"toBlock":6262844,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],null,["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa13d466d1e237a9af3f4dddec1d9581acae9f69f18f98bc0ee0c3968b904b5c6"},{"fromBlock":5978864,"toBlock":5979542,"address":[],"topics":[null,null,["0x000000000000000000000000e4c60b750b851d88ff30ac492d809d911360584d"]],"resultHash":"0xf747c0cea288c577d7dba332ec0f6657d5f36c60007b76108c1e875a3628b190"},{"fromBlock":4063476,"toBlock":4066395,"address":["0xf651467aecd1a7905efb4cd35502f16880ee0c23"],"topics":[["0xf80dd09632f046e05472e1c239271a3b2ad3de73c27a1b03d0bb0329ba6716df"],null,null,["0x00000000000000000000000000000000000000000000000000000000658e0c00"]],"resultHash":"0x4853195aa4b792871cfa9bf13734bd8faf4909e6debbf8a65849a1416c0b01c6"},{"fromBlock":1528363,"toBlock":1531081,"address":null,"topics":null,"resultHash":"0xfd06c484c534671365952a6c1f93accad4162dd4cd8404fcb1153bd5d1709fb1"},{"fromBlock":6262154,"toBlock":6262844,"address":["0xb3f15a44f91a08a93a11c6fbf6a4933c623275fe"],"topics":[["0x8967dcaa00d8fcb9bb2b5beff4aaf8c020063512cf08fbe11fec37a1e3a150f2"],null,["0x0000000000000000000000001965cd0bf68db7d007613e79d8386d48b9061ea6"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xa13d466d1e237a9af3f4dddec1d9581acae9f69f18f98bc0ee0c3968b904b5c6"},{"fromBlock":7754089,"toBlock":7755177,"address":["0xc4545a0b4a87cbaff03a73f45c377c0b5f416e00"],"topics":[null,null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0x956ee10d041782d9b2f7f134ca5ed071375a719c350fa6e404ffd39eb5e8728f"},{"fromBlock":5507318,"toBlock":5508308,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xf891d59d92809541c53a742ccfb3d8ae4a0d15cb4bcd3c7f36d40440fc3e7ebc"},{"fromBlock":2877134,"toBlock":2878871,"address":["0x779877a7b0d9e8603169ddbd7836e478b4624789"],"topics":[null,["0x000000000000000000000000177e068bc512ad99ec73db6feb7c731d9fea0cb3"]],"resultHash":"0x6722e252b25d644b95771d1aa219294a5cbdade1a5378dbf65d0449fabdb600b"},{"fromBlock":5492930,"toBlock":5493453,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"]],"resultHash":"0x653a14a4b4c98231b378179a5aa1ad3d087920c44c396ad22a480d83b3dd708e"},{"fromBlock":5492919,"toBlock":5493714,"address":["0xfd57b4ddbf88a4e07ff4e34c487b99af2fe82a05"],"topics":[null,["0x00000000000000000000000038d1ef9619cd40cf5482c045660ae7c82ada062c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x6b30f75cc259e51b40013e6037ddd081cb0e0764dc5cc0e5fb806868a12b504e"},{"fromBlock":3322417,"toBlock":3323040,"address":["0xc3a11ef77e260e9bff04b6b2e0a4f1619436a9c2"],"topics":[["0x48257dc961b6f792c2b78a080dacfed693b660960a702de21cee364e20270e2f"]],"resultHash":"0xcc97509e54083a9adb399fe300fc33f8f5814a80f7582098c2688cfbecef51c9"},{"fromBlock":5598859,"toBlock":5599379,"address":["0x38d1ef9619cd40cf5482c045660ae7c82ada062c"],"topics":[["0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7"],["0x00000000000000000000000081660dc846f0528a7ce003c1f7774d7c4135f344"]],"resultHash":"0x42d5eb89bd9ef03060199eca5034fd65e5fd27efd5a05ac507cd36514b79d077"},{"fromBlock":3030438,"toBlock":3031924,"address":["0x26223f9c67871cfcea329975f7bc0c9cb8fbdb9b"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xac01f4ab8ddf07d5b0fa276c8fcafd7c9d7682765b17cd78a9a2e21154f6b41f"},{"fromBlock":3422361,"toBlock":3425676,"address":["0xda9d4f9b69ac6c22e444ed9af0cfc043b7a7f53f"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000e7ec1b0015eb2adeedb1b7f9f1ce82f9dad6df08"]],"resultHash":"0xe41aedbbdd76c4f8b28f7a307e6acb693c7cf9aa6c7fed69e33b79e4f049aa97"},{"fromBlock":1908852,"toBlock":1913921,"address":null,"topics":null,"resultHash":"0xc2cbab221f0a74a24a5189a6b8916307bc451103aee2b5ad44273d41557edbdf"}],[{"fromBlock":3676092,"toBlock":3676222,"address":["0xb5e7041ca1b7024c77cedccb3da205a660643697","0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,null,["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0x1fc40ce6939f1b2e27e6a91e3fc402fef2e73075c3a9aacb83a031025730673a"},{"fromBlock":7754446,"toBlock":7754755,"address":[],"topics":[null,["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"],["0x0000000000000000000000003a9d48ab9751398bbfa63ad67599bb04e4bdf98b"]],"resultHash":"0xae624936bd44883c1ffe7bb475a16f73ea113e035f08461d0fd766e13837a71d"},{"fromBlock":6479878,"toBlock":6479944,"address":[],"topics":[["0x1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859"]],"resultHash":"0x9d458a373d07027ef70f6ded810b3ac7cc9063227e466a96b6b539e4dfbfa5be"},{"fromBlock":5493294,"toBlock":5493367,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x9ad4ae5744b4eefab2e8634790156d16d592e92426079eedd72af3279a89c92b"},{"fromBlock":3792221,"toBlock":3792285,"address":["0x22c1317fe43132b22860e8b465548613d6151a9f"],"topics":[null,null,["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0x7dbd3d260f9c5554b2923dc70627a18013f1eb83903186c0d3b2608751dc2a52"},{"fromBlock":4886507,"toBlock":4886732,"address":["0x236f697c518b7aec0bb227d8b7547b3c27ca29bc"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0x4bd3cea91f08d6f4799c635196505b8001e57c5e6dc55588c682b194c1513c36"},{"fromBlock":3423903,"toBlock":3424314,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x0000000000000000000000004c00cb23d75530798593593401d977bfa04bd321"]],"resultHash":"0x21903735fb4c21a7e876907781eae922ce536fb7f6c3ce79ee787b7e4a70dcc7"},{"fromBlock":3423594,"toBlock":3423849,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,null,["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xf5c336f0d3cea3e86c9e3ca89118d52942ad4ccb77cfb3dbdff9d180fa093b15"},{"fromBlock":6453499,"toBlock":6453793,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000708d8f13492900da663fd2421cbbef1419b2f185"]],"resultHash":"0xba7943cfae732f8ff908302f37f3ded7fa4d91eb2fd2961e2f3e4b10ac6a8706"},{"fromBlock":2319423,"toBlock":2319518,"address":null,"topics":null,"resultHash":"0x6db2bdebafdc4468b30b9f203f06a5f4d3a307b5feb0cea71d687fcecdc4bdd2"},{"fromBlock":3423718,"toBlock":3423997,"address":null,"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000044e1d00ef5ea916b66c3a4a57ec3786750d8968a","0x00000000000000000000000025aa96bf246423b96b69dcd300e34467edafcf67"]],"resultHash":"0x1a5d9097c515c6e3ec5cc47375ae01a8a6203943b474a8aa030a53c8d78f04c6"},{"fromBlock":2768915,"toBlock":2769104,"address":[],"topics":[["0x2ad3120f495e551d2c27d842512ed4f16e008ed3bf4df24aaf729a37080444a6"]],"resultHash":"0x4409eccb5d1be49dbba2d99ea9042a8c28877b085f719ab1d727134d79dc674f"},{"fromBlock":3423752,"toBlock":3424025,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000054ea27b8faea91b29f43793badb44066d77e2d17","0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000025aa96bf246423b96b69dcd300e34467edafcf67"]],"resultHash":"0x1a5d9097c515c6e3ec5cc47375ae01a8a6203943b474a8aa030a53c8d78f04c6"},{"fromBlock":2510213,"toBlock":2510333,"address":null,"topics":null,"resultHash":"0x4ecd528ea4a8484665703d0f6f77084efb50dd4941b8532f7dd335a23e58a6b9"},{"fromBlock":3586273,"toBlock":3586404,"address":["0xb5e7041ca1b7024c77cedccb3da205a660643697"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x958ed0086a302bc530c2d9e75095468aacdbbbbd6622f4e1f644a6948d8fd8bc"},{"fromBlock":2861232,"toBlock":2861287,"address":null,"topics":[null,null,null],"resultHash":"0x9e7660487fb78c641dd5ae28b1ec83aa5c9f2ee6fe9a8e0737ca911db8c29eb8"},{"fromBlock":3423749,"toBlock":3423991,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xc245ef6bfc7823613f1ec2e962255b06f02b7bedafe36b34304e7efd1900148e"},{"fromBlock":3423328,"toBlock":3423621,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xe4fc09d78d8fb34cfee6e01c7aaa3e509dfad16c3f4e1b264e11f3e86bb8e7f4"},{"fromBlock":1795452,"toBlock":1795565,"address":null,"topics":null,"resultHash":"0xe3a13ced5ae9df33489bd722f421917f77488cd405c3df257b843ee9ec2e76cc"},{"fromBlock":3423594,"toBlock":3423849,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xf5c336f0d3cea3e86c9e3ca89118d52942ad4ccb77cfb3dbdff9d180fa093b15"},{"fromBlock":6453503,"toBlock":6453593,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"],null],"resultHash":"0x2a9819a0e1c8afd3fe6e651d7d279321bbe663334f76bdd017cc489f3173a42e"},{"fromBlock":2320280,"toBlock":2320452,"address":null,"topics":null,"resultHash":"0x7017b79fb0b3580f0a301b9a6802335d5d763e99dcda983468ac42b9351aaa02"},{"fromBlock":3586285,"toBlock":3586388,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x8d18648b2a96d3fe290f24724c97693a7c1185910299b7d9b90e3fcb4a8b8f74"},{"fromBlock":3423749,"toBlock":3423991,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xc245ef6bfc7823613f1ec2e962255b06f02b7bedafe36b34304e7efd1900148e"},{"fromBlock":2903663,"toBlock":2903743,"address":null,"topics":[null,null,null],"resultHash":"0xf1a43edc1b0443676d59a8997b59a3842c3c497f9390f8a5c19acebc940cb2fe"},{"fromBlock":2112216,"toBlock":2112588,"address":null,"topics":[null,null],"resultHash":"0xe7e8c930ce6bee7923ffb6c42b81942ec242195f126ca63258af65e4c4f63edf"},{"fromBlock":3163640,"toBlock":3163832,"address":["0x5b9fedd37f0b92e7e282b19cebcf06f57b77c604"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x6e316bdfdc978b8666555edf12b3995777e2b2a6a156f024e53f90f327f1697c"},{"fromBlock":5289506,"toBlock":5289716,"address":["0x3f4b6664338f23d2397c953f2ab4ce8031663f80"],"topics":[null,null,["0x000000000000000000000000fa885f6579ae1cdc381e647fc306dcde4f976164"]],"resultHash":"0x38fad159a0c6318a8a0697622895552efac5063f55936625a5c725ebe536a872"},{"fromBlock":5704029,"toBlock":5704170,"address":["0x5f8403cfada2c58ae2adccbaaa983d48160e4b57"],"topics":[["0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a"],["0x0000000000000000000000004200000000000000000000000000000000000010"]],"resultHash":"0xd577f886182954eca5db0278df72aef8eab2684d64eda218570b3e8c52e51653"},{"fromBlock":5493294,"toBlock":5493374,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0xd9c6ed522a9564cde38764dea2642e0ec1150cfa890371cf69f970ebc8076a1e"},{"fromBlock":5493513,"toBlock":5493669,"address":[],"topics":[null,null,["0x0000000000000000000000007a4ee6f9f0ab037fe771fc36d39c1e19bcc0fdb5"]],"resultHash":"0x846c13936d229f2624caa97191f6b145a0eacd0625e304d21701c7a45bac661f"},{"fromBlock":2434304,"toBlock":2434385,"address":null,"topics":[],"resultHash":"0x1af9584bcecc66b35fff70e09a47f7ef6be55dff43d282204d94e19255b302b0"},{"fromBlock":5289506,"toBlock":5289716,"address":[],"topics":[null,null,["0x000000000000000000000000fa885f6579ae1cdc381e647fc306dcde4f976164"]],"resultHash":"0x38fad159a0c6318a8a0697622895552efac5063f55936625a5c725ebe536a872"},{"fromBlock":5978978,"toBlock":5979072,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0x271474b370e2fefd72a1ca40052213b73e1119c34526d53b08efe05cdeb27417"},{"fromBlock":2768966,"toBlock":2769008,"address":null,"topics":[],"resultHash":"0xb0101f32669c5af6c548425281a41e3be8f85d01059b5ea2c9a2188ad0c24d6f"},{"fromBlock":5289495,"toBlock":5289691,"address":["0x3f4b6664338f23d2397c953f2ab4ce8031663f80","0x91b333a8485737f9b93327483030f48526fadc22"],"topics":[null,null,["0x000000000000000000000000fa885f6579ae1cdc381e647fc306dcde4f976164","0x000000000000000000000000788685c1fe1404b2473347dfb3242a124da99635"]],"resultHash":"0xb33d37186358d5cfd9ebd1494f7dafeb228cb2d8b59526c39b099f2b34b71589"},{"fromBlock":3765940,"toBlock":3766025,"address":[],"topics":[["0x47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f3"]],"resultHash":"0x4538059a2713138e395eebe8e64de79683664552f695f5c8751f543b9464c86d"},{"fromBlock":3423456,"toBlock":3423649,"address":null,"topics":[null,null,["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8","0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0x345d86ea7de90287fc20d80512c17abd937cb538a5ee7b90e4b90dd280d22037"},{"fromBlock":6288012,"toBlock":6288384,"address":null,"topics":[["0x35d79ab81f2b2017e19afb5c5571778877782d7a8786f5907f93b0f4702f4f23"],null,null],"resultHash":"0x9314519ed14044a6ce62f67aceaa8082fffd462527bd88e49d0fcef90355a958"},{"fromBlock":5051245,"toBlock":5051419,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xfc9615e20872671b16e57132264d4c616a7459dd2c92c77f88e08b4f55268044"},{"fromBlock":5979005,"toBlock":5979055,"address":[],"topics":[null,["0x000000000000000000000000f89215880b3f56b92b7731e9c917d3737c441c4b"]],"resultHash":"0x6a68906308f8958718e555d47128a507caf5d34aec6ac04431043ec8ab463cc6"},{"fromBlock":1873466,"toBlock":1873708,"address":[],"topics":[["0xf6a97944f31ea060dfde0566e4167c1a1082551e64b60ecb14d599a9d023d451"]],"resultHash":"0x34b4264dcfd1ef78f5812bce3d3304e9756a4aa45b6ccc05818f9256b7e2e47e"},{"fromBlock":6222552,"toBlock":6222794,"address":["0x000000007f56768de3133034fa730a909003a165"],"topics":[],"resultHash":"0x4be31532852706748b29c9c4a242449a50de0b78237ce777f6b73aa20535479b"},{"fromBlock":6769631,"toBlock":6769685,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[null,null,["0x0000000000000000000000007abf52a91d3d078960bafc9912fa1be248ef6dcf"]],"resultHash":"0x8b5497a9faca1be8d310706ba05da4e16ce8a39e8670663c1244c5ed417edb2d"},{"fromBlock":2742001,"toBlock":2742061,"address":null,"topics":null,"resultHash":"0xccb0ab85d618184e5028c13f021ad836c4eb52c3b940820aa3c7699430a35e3b"},{"fromBlock":3423663,"toBlock":3423934,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67","0x00000000000000000000000004b7d4ee7c2126dc2967e36f10fe4f7322812e34"]],"resultHash":"0x527fe7f4d6800f6cbcb6a6b802955690a3810fce055e59bdeb316f7a4f6e9a2d"},{"fromBlock":4886524,"toBlock":4886638,"address":["0x236f697c518b7aec0bb227d8b7547b3c27ca29bc"],"topics":[null,null],"resultHash":"0xcbad350b752b3b3528636ba2346dc63d0e505756713481dd92b6ce4cb415c84d"},{"fromBlock":5654119,"toBlock":5654408,"address":null,"topics":[null,["0x000000000000000000000000d9d4b3ad7edb8f852ab75afa66c1456c46fef210"]],"resultHash":"0xdf2c6fca90d8abd33f990784149298111534354be64b60f5a4c2fd3761a336df"},{"fromBlock":4524747,"toBlock":4524858,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],null],"resultHash":"0x5dd702668c17059d057dac84a60fbc36ca1d65d6db542fb9207d45d0cb7f957f"},{"fromBlock":3628250,"toBlock":3628366,"address":[],"topics":[null,["0x000000000000000000000000d35bcf3da45426a9df5e58d2221bd79e6af0338d"]],"resultHash":"0xd644a2bc3031f5dc55696ef3beb4dcede40e19b2c58675c21c77e02ff4537843"},{"fromBlock":6769631,"toBlock":6769685,"address":[],"topics":[null,null,["0x0000000000000000000000007abf52a91d3d078960bafc9912fa1be248ef6dcf"]],"resultHash":"0x8b5497a9faca1be8d310706ba05da4e16ce8a39e8670663c1244c5ed417edb2d"},{"fromBlock":3423466,"toBlock":3423724,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xd582fdf7a87a93939e2068fe7e76689a498879efcb2906a1f9ff1d7e6a8ce3be"},{"fromBlock":2225544,"toBlock":2225631,"address":null,"topics":[],"resultHash":"0xf2603f467216189dfe2ae3890801b6b50a23b5207324ad91a6d2ff97e1fb21a9"},{"fromBlock":4115926,"toBlock":4116312,"address":null,"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,null],"resultHash":"0xb8072f33c5bfd51977fec0f5533e749815223ce7c20ca2be29cc36b1d350620f"},{"fromBlock":2358802,"toBlock":2358913,"address":null,"topics":[null,null],"resultHash":"0x578fc94222fb45859b03101af72f148e9a886c9ec00dccd9905c10921bb00ecb"},{"fromBlock":3163633,"toBlock":3163719,"address":["0xeee369870a52ea60cef0162a5b3aca1673f90999","0x5b9fedd37f0b92e7e282b19cebcf06f57b77c604"],"topics":[null,null,null],"resultHash":"0x9df98b9f86129933947c833cf116eb97be8473c3043f77f30701e7aef4d9cf36"},{"fromBlock":1767490,"toBlock":1767578,"address":null,"topics":null,"resultHash":"0x9a2cfdb9d425b3ee5c11c7ef633399928a8aa1df92a92b6ae30356f38fa54628"},{"fromBlock":4524746,"toBlock":4524828,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],null],"resultHash":"0xf7932d0f2ab7068c10169bcd77ff9d3510b172e06a8fbd4e3097a957f47cabcc"},{"fromBlock":5289506,"toBlock":5289716,"address":["0x3f4b6664338f23d2397c953f2ab4ce8031663f80"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000fa885f6579ae1cdc381e647fc306dcde4f976164"]],"resultHash":"0x38fad159a0c6318a8a0697622895552efac5063f55936625a5c725ebe536a872"},{"fromBlock":5405001,"toBlock":5405400,"address":[],"topics":[["0xab39b6198177d86fa26959fef9bca1102673c1ae25242930e42bc859b25b3790"]],"resultHash":"0xa607fd5175c6883be5af2dcc6813b6c50a6ed68455ef50269d2728955ce97539"},{"fromBlock":5289429,"toBlock":5289763,"address":["0x2de7b7364a37fbb35f946ca7175a1b596710b262"],"topics":[null,["0x0000000000000000000000000545c5fe980098c16fcd0ecb5e79753afa6d9af9"]],"resultHash":"0x16891f2bfc91b08af08cffe7c4c6346c19b29b2e236bf6765bf5da6e36d7d2d5"},{"fromBlock":6480660,"toBlock":6480864,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x5f091a9dc66316ef56f29b72d982a6f4e1ac0994b9320d7caf0a0dbe65d7434a"},{"fromBlock":3423328,"toBlock":3423621,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xe4fc09d78d8fb34cfee6e01c7aaa3e509dfad16c3f4e1b264e11f3e86bb8e7f4"},{"fromBlock":4886507,"toBlock":4886732,"address":["0x236f697c518b7aec0bb227d8b7547b3c27ca29bc"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x0000000000000000000000000bcb9ea12d0b02d846fb8bbb8763ec8efecb4c79"]],"resultHash":"0x9df1a813db58f913288a74349ce7a1f1d0058e90add5ca1591183e00318c1dcf"},{"fromBlock":5507705,"toBlock":5507851,"address":null,"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x4dd066db433f3fc5519136552bcdc42d69cb698d969f3aa4d211b759c061c015"},{"fromBlock":2290144,"toBlock":2290225,"address":null,"topics":null,"resultHash":"0xfe4ec31f3ae38c3b73c7e6c8fc1105dfe91de02cf3e275abde3c1bb0888f2495"},{"fromBlock":5493325,"toBlock":5493373,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0xe5bb267e0c5e285e7ec30eb9b08ea8009bd91df599dbd31e6ae2a5d82dd32105"},{"fromBlock":3427488,"toBlock":3427661,"address":["0x9072495afc2d59d857118ee59b4ef6cfc407d103"],"topics":[],"resultHash":"0xe90b168df929738d554647be2a57e2c0b2d64f85bbdf6fb491df8dd0f89d2e06"},{"fromBlock":3063178,"toBlock":3063189,"address":null,"topics":[["0xd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0xfe7a257584a7c4a7509beb3b7642eba0b9608e231e855884fde00d4f0029e767"},{"fromBlock":5654097,"toBlock":5654471,"address":[],"topics":[null,["0x000000000000000000000000d9d4b3ad7edb8f852ab75afa66c1456c46fef210"]],"resultHash":"0x9d745397a79c89798beeb713dcef00c5c00e01bae084d16623955cf9dc0da103"},{"fromBlock":6453397,"toBlock":6453749,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000708d8f13492900da663fd2421cbbef1419b2f185"]],"resultHash":"0xf29cd3c3269af94d4c094cba3c151cebea1ee6a6b2c2bcc2b74e1a17fdee93d5"},{"fromBlock":2421882,"toBlock":2421959,"address":null,"topics":[],"resultHash":"0xa8c93c76948e54c3683d7e73ed734b3abc93371af194d9830925fe8481024bcd"},{"fromBlock":2768769,"toBlock":2769076,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xb1e3a1b46819155385694310ea4f465c5fd3db96c2af810043594cace05e1179"},{"fromBlock":1795337,"toBlock":1795655,"address":[],"topics":[["0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"]],"resultHash":"0x07496dc844fe21c63dd976a681a83d0120c3718c70254eaa30f05e33071c2d5d"},{"fromBlock":6762946,"toBlock":6763024,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x61a8b5e4fadc033572450b206dbd01233204c584426345d1acc9b571c1be8162"},{"fromBlock":2319450,"toBlock":2319538,"address":null,"topics":[],"resultHash":"0x69d8d1fee324e82873d7a12b922e2042de4abd8859978916acf365dbc1e60a73"},{"fromBlock":3381844,"toBlock":3382342,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000301daf80d468510939d4ded583b323dc29759186"]],"resultHash":"0x288826ec2d2fa8b131de3df1f56351c7a2861aa1bb14546b24ada00bbfd9c23b"},{"fromBlock":2685337,"toBlock":2685433,"address":[],"topics":[["0xdd71a1d19fcba687442a1d5c58578f1e409af71a79d10fd95a4d66efd8fa9ae7"]],"resultHash":"0x33e8995a79e593563d3f80f5cc9c5d13808f1f631f3ffe0b0e7b88873ff119bb"},{"fromBlock":6872591,"toBlock":6872960,"address":["0xf2919afbf712071ddf73c22f0afe8011608e1e9c"],"topics":[["0x8ebb2ec2465bdb2a06a66fc37a0963af8a2a6a1479d81d56fdb8cbb98096d546"],["0x0000000000000000000000009228665c0d8f9fc36843572be50b716b81e042ba"]],"resultHash":"0x9ec1dfac7c93cc356b22e2d766058b78f6996535ab0359e845f8c997ad16a544"},{"fromBlock":6456741,"toBlock":6457259,"address":[],"topics":[["0x5f971bd00bf3ffbca8a6d72cdd4fd92cfd4f62636161921d1e5a64f0b64ccb6d"]],"resultHash":"0x79489baf7868be6322aabfa2b17646ef4dcec832010ef4c9111ef3b51016abb0"},{"fromBlock":5420716,"toBlock":5420988,"address":["0x1c7d4b196cb0c7b01d743fbc6116a902379c7238"],"topics":[null,null,["0x0000000000000000000000006fac84fb0cdf5bcc40300dbd3b47d3d918eeee04"]],"resultHash":"0xb89cbd976c1b16a4d7ca15285db0c48b7a78480c400d7cb6313e681c7b21130e"},{"fromBlock":2818512,"toBlock":2818700,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x851effc5d685c784facee8752ef9f38ad01cdc76f94334589a37a3d0aac30cb2"},{"fromBlock":3423749,"toBlock":3423991,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xc245ef6bfc7823613f1ec2e962255b06f02b7bedafe36b34304e7efd1900148e"},{"fromBlock":6453522,"toBlock":6453679,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xae9e1adc84c3bdf69d9ca9894608ab0b26a52cf37141a9623b8429ecec879e66"},{"fromBlock":1854913,"toBlock":1854993,"address":null,"topics":[],"resultHash":"0x1f9f0b4582633ccd39cfe3da40a3e3afd7ec98b70ba8555079b3ebee8eec2914"},{"fromBlock":5493346,"toBlock":5493420,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x3b8ab7d50fc6afcbe84d2a3a24a691c9120836904219bf824c25c3cafde98e45"},{"fromBlock":3423401,"toBlock":3423699,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8","0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0xe21a673f75a6b9af7e05fd33c2b7654bb7597725e5ca0f33711a81e7fd672426"},{"fromBlock":6456692,"toBlock":6457134,"address":[],"topics":[null,null,["0x0000000000000000000000004200000000000000000000000000000000000007"]],"resultHash":"0xf5f1425fb81e1ce6fed13d68967b279d4bb795d9356f054a82dbc17f521202a7"},{"fromBlock":5978973,"toBlock":5979048,"address":null,"topics":[["0x92e98423f8adac6e64d0608e519fd1cefb861498385c6dee70d58fc926ddc68c","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0xd066c191c38d881001c7934774411445fde8c1958c4882e94a53098f22d675d7"},{"fromBlock":4524644,"toBlock":4525015,"address":["0x95ff8d3ce9dcb7455beb7845143bea84fe5c4f6f"],"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2"],["0x0000000000000000000000005c4220e10d0d835e9edf04061379ded26e845ba8"]],"resultHash":"0x66debf176104a8ad03f124bdd27607ff95ced007a3f5ff2d89bd4033f42a926b"},{"fromBlock":6453500,"toBlock":6453598,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x283cd33d622ca679f2b384940a406998f52cff5121f70ba98068bb41dc52acc6"},{"fromBlock":3423789,"toBlock":3424098,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757"],["0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0x78b7bccb6e71df1213b52f0a4e1e98f339f714b79ef95be1ea0ef41894f3e5cd"},{"fromBlock":1730079,"toBlock":1730168,"address":null,"topics":null,"resultHash":"0x13fad578a8cdb7e6da2256185141844212c30d7b10922aad89e0a4ad82192197"},{"fromBlock":5420816,"toBlock":5420940,"address":["0x1c7d4b196cb0c7b01d743fbc6116a902379c7238"],"topics":[null,null,null],"resultHash":"0x8aac8a3498acc51879c5e6ddbf9095ccf237d229d5ff73f51c215fa619f825ec"},{"fromBlock":6453433,"toBlock":6453732,"address":["0xd98b590ebe0a3ed8c144170ba4122d402182976f"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xe5db67eb4a08037e976f0d7ed5cc52986dbf21d36f03bd33ed8cd2ddd793883c"],null,["0x000000000000000000000000708d8f13492900da663fd2421cbbef1419b2f185"]],"resultHash":"0x5685ce5015d4d51331cee6fe0a3a95f86cc0d44f65ffb60493e971adb2287d72"},{"fromBlock":5493294,"toBlock":5493367,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x23a809ab1e40a2a6168d045320a95a751ac1c26972f66780e08306ce213b1144"},{"fromBlock":6456865,"toBlock":6456936,"address":[],"topics":[["0xbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972"]],"resultHash":"0xf1609789a30298b9b95080dc4935e591e7b3a185b2a843eb9d0c8619c847f032"},{"fromBlock":3765940,"toBlock":3766025,"address":["0x7d992599e1b8b4508ba6e2ba97893b4c36c23a28"],"topics":[["0x47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f3"]],"resultHash":"0x4538059a2713138e395eebe8e64de79683664552f695f5c8751f543b9464c86d"},{"fromBlock":1873487,"toBlock":1873768,"address":["0xf549af21578cfe2385ffd3488b3039fd9e52f006"],"topics":[],"resultHash":"0xe4d05e93fd6626426e3f070891d068fedaca4918fe4ae92da04f63d7464cd24e"},{"fromBlock":6330387,"toBlock":6330689,"address":[],"topics":[["0x00d05ab44e279ac59e855cb75dc2ae23b200ad994797b6f1f028f96a46ecce02"],["0x00000000000000000000000026280ec2fa5e4987520e4c84d55b7320f1f3c4ce"],null],"resultHash":"0xaadb93d01ea561c20865eef8eb9151a2d317da298cb7df3392cbc33a09c537f9"}],[{"fromBlock":3031192,"toBlock":3031213,"address":null,"topics":[],"resultHash":"0xd36ddeb76f2f417146a5ecccdcbe8c411e339221f82787dbe7399568f1e6febf"},{"fromBlock":5493317,"toBlock":5493327,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xb94308f05360a2e6f2d9554ea68d630bb8d536e38d639d2443837c8a1b201db4"},{"fromBlock":3393844,"toBlock":3393855,"address":null,"topics":[],"resultHash":"0xbbb6fac5b54a9316e61ab957f73f1c67921800522ba2cd1486ecabbf9f94c76b"},{"fromBlock":3031190,"toBlock":3031203,"address":null,"topics":[],"resultHash":"0x35c6ace8e7c59a4e77306a2f4999f4e99d201f83f29802ecd800d7bddb622225"},{"fromBlock":6339472,"toBlock":6339497,"address":null,"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"],null,null],"resultHash":"0x5e265c018fc7ae7559f3114c5edb74e201b91c1e9a9721113a118b2c6fc2119f"},{"fromBlock":2989372,"toBlock":2989414,"address":null,"topics":null,"resultHash":"0xa3507809e46a6b3ddae1200107d9ac778625bd419eb022f882e29f1ea2e864c7"},{"fromBlock":3323981,"toBlock":3323995,"address":null,"topics":[],"resultHash":"0xda9e518833b1c73b2c9a1b67465a6fe59f76ffdf90bc57e05ccde3bc2c26bb1d"},{"fromBlock":5493329,"toBlock":5493349,"address":null,"topics":[null,["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x5880d5baaf8dbff366de5b8b81e1822a737014a329110b8bb7245eac341a0e2f"},{"fromBlock":6373602,"toBlock":6373608,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x11bb0cf81b0549ca27ff0ac0939ba88b6bc8022a06ad7e8fa331a9e651a8fbbf"},{"fromBlock":5139565,"toBlock":5139590,"address":["0xf68f872f0dde0ec1ba8c28eed9d0674760aa8eb1"],"topics":[["0x838807fe70997cb429689dd35bc6ccb21720aa7d7daac8736b398060104fb0fa"]],"resultHash":"0x45b20509041ba441883718b2bc96cb8755b35e8fe42d7d4b64ef57d5bd0d7adc"},{"fromBlock":3427582,"toBlock":3427593,"address":null,"topics":null,"resultHash":"0x23264b009c5d7e1ffad3059727abd5cb789619b9eb57a784748b93f430eb6b9e"},{"fromBlock":5493326,"toBlock":5493338,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4","0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x11ced34ae0b5e1fd0332dd066fddd61d2919a466e08d689c9f86e89e564f0260"},{"fromBlock":5493314,"toBlock":5493323,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xdd9025c89cd8cd2bf041f7ac887195a3d0412a16635fa4721b2984c2b4ba5a59"},{"fromBlock":2939170,"toBlock":2939184,"address":null,"topics":null,"resultHash":"0x2bedec7917a150100672e9ebafd77fb649565e339d2194867d891c56a957e60f"},{"fromBlock":5505412,"toBlock":5505423,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],null],"resultHash":"0x88f1fcb15c6a6933066e73c2dfafd3f7b066953f641c54cb4d70670d772eb1f5"},{"fromBlock":5493596,"toBlock":5493634,"address":[],"topics":[null,null,["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x342008a5dfc8e3addb399df7a053cdb67d29f5e794057c7633a4af74208fff5a"},{"fromBlock":5493302,"toBlock":5493312,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c","0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x5ef557ae98fe7bd3f804f0f160364f1d5390bfd5143edf90072c50a74081e56d"},{"fromBlock":2685362,"toBlock":2685410,"address":null,"topics":[],"resultHash":"0x980bd077508d4a95dc9ba6b58877a94d29a821101809a6f046341310f79042aa"},{"fromBlock":5493331,"toBlock":5493340,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x4f560094c3fbcc28232da5a2675552a05a2e9773e0f1861421e4d4495ad15641"},{"fromBlock":5493605,"toBlock":5493630,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x837684b68e3b2a2538435da4fdd43bc83217f972545eccf5e8093f9d8ae010ce"},{"fromBlock":5493347,"toBlock":5493354,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],null],"resultHash":"0x28c0132eefe3dfeb6d79ef524f7d3fd3fbbcd0b4e8ebfab94d6d019706d4e0c5"},{"fromBlock":6379517,"toBlock":6379524,"address":["0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789"],"topics":[],"resultHash":"0xca2f2db7bf96efdd9fa08f780598048bff07e7a12423fbfcb6ddfc289e30971c"},{"fromBlock":4637932,"toBlock":4637935,"address":null,"topics":[null,null,null],"resultHash":"0x1fce5b6fd9066042d92f73f2f5c34c74452e089260b4c2aea52ea683174d59f7"},{"fromBlock":5493330,"toBlock":5493336,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xd276ffc43d3fb16427421d5cc1d7f470f3a1676e146f5171cf4aed92fd313ab1"},{"fromBlock":6064256,"toBlock":6064264,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x40ed5672f93dde0622ebecf50982dd606642833ea51ff7786d2aba394ae35f2d"},{"fromBlock":3765971,"toBlock":3766004,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[["0x2295930c498c7b1f60143439a63dd1d24bbb730f08ff6ed383b490ba2c1cafa4"]],"resultHash":"0x0b9c8c346932a26a203ec354b870b79a5c5e0fdccecb75e0adad7f4b9684bfb5"},{"fromBlock":3111341,"toBlock":3111370,"address":null,"topics":null,"resultHash":"0x26e9148ef9602f6c47772f64f03eac91d488634ce1c2234c7faeafc9bbf1fc62"},{"fromBlock":3233799,"toBlock":3233808,"address":null,"topics":null,"resultHash":"0xd4e6ef290bb77f92019dd5c05d8b03d8b14dadbc83efeffb1cb2066a6c110742"},{"fromBlock":5493302,"toBlock":5493312,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c","0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x5ef557ae98fe7bd3f804f0f160364f1d5390bfd5143edf90072c50a74081e56d"},{"fromBlock":5654269,"toBlock":5654302,"address":["0xf1d6d31b577a2e54f6909813bfefcd73b9341f1f"],"topics":[],"resultHash":"0x9f2e3a694c034841722599de72487ff15109109b8adcd0937d6fe7421d055ec7"},{"fromBlock":3024294,"toBlock":3024313,"address":null,"topics":null,"resultHash":"0x37c57273a3d3210babc60ae0cd7da6ee4dd18c3f9588fabf6c02687860981520"},{"fromBlock":4178736,"toBlock":4178738,"address":["0x39e12053803898211f21047d56017986e0f070c1"],"topics":[],"resultHash":"0x3e43e97106f97c72a610c60643827555fce4bc0e33c7b71ad8cf0a2303aa36fa"},{"fromBlock":4534035,"toBlock":4534051,"address":null,"topics":[["0xbb2d4a4c4a679d81940f242e401d2b2cc3383dbcb0ae798c14bd7905b1f6cae2","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null],"resultHash":"0xa388d799ce609c0db3ef0e43f45510d0128c1747212218956ca1b0634ea313bf"},{"fromBlock":6596502,"toBlock":6596538,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x000000000000000000000000e6a568604b4a93f2b2a8fa0e13920d076c31a757","0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x33b9201ee7a212f4a752879dc366291cc7752dfd15aa88a7146264c80562c7a1"},{"fromBlock":3815100,"toBlock":3815122,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[],"resultHash":"0x8e2ce600397f5af05f0f798002646b9be85d60dda8eb9d61934e62557008c4e5"},{"fromBlock":5493307,"toBlock":5493323,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c"]],"resultHash":"0xfb998d99a181a60b261cf27353c47fca7cfd5e841919360f0068d0a6793d922e"},{"fromBlock":5493605,"toBlock":5493630,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x837684b68e3b2a2538435da4fdd43bc83217f972545eccf5e8093f9d8ae010ce"},{"fromBlock":2034342,"toBlock":2034364,"address":null,"topics":null,"resultHash":"0x4fb18033d4a0bbf5870f2158a351e7470be5950796eb9a67c1cb42bd2db102aa"},{"fromBlock":5550783,"toBlock":5550827,"address":null,"topics":[null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x4fa75b33bc49790dbc31ec843ea9aad04867a756e64b7e5ccdc7a173a9a2143c"},{"fromBlock":5493310,"toBlock":5493322,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c"]],"resultHash":"0x14ab4073f5be0f030393deb0d0bc83771ca91e3ccaa349819155f8757cb27706"},{"fromBlock":6269499,"toBlock":6269544,"address":[],"topics":[null,null,null,["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0xfc9cf595fb3b939d948fb1b0246c0a7d6e7a6190d428cbf37192f53c37758653"},{"fromBlock":3323979,"toBlock":3323992,"address":null,"topics":[],"resultHash":"0xa6cdd185775bb8eafa2c5a537a330bf6ba65e3fbeb547f711aa8584a43c21831"},{"fromBlock":6762951,"toBlock":6762990,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x443a4ee09e771954cb46ef380cd401477a7e2e61a079e9f84e82ffcf57dd77b4"},{"fromBlock":3031198,"toBlock":3031209,"address":null,"topics":null,"resultHash":"0x7d3d0eb41b2955b9d3867a14cd0d2a416ac08ad87594bd8b37e89fa3dcf296d0"},{"fromBlock":3586342,"toBlock":3586357,"address":null,"topics":null,"resultHash":"0xf6d4caba2d82acf0faf85beca1563374ba3a224aa63a4a90d83aa009b74a1c1c"},{"fromBlock":4515314,"toBlock":4515320,"address":null,"topics":[null,null],"resultHash":"0xc9b4763a679067ccbde7c239fb492e950efe447a5d0c954957e85c15c9975336"},{"fromBlock":6872886,"toBlock":6872928,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"]],"resultHash":"0x245b8131bb7190efc0dd72de0f5c429afb62a017a42d24efd8ee54bc576b5f2e"},{"fromBlock":5493341,"toBlock":5493354,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],null],"resultHash":"0xcad906a09fce6f97a5cf8e4e7e63d3037177fb548497ccc5e43e268087a77e35"},{"fromBlock":3815077,"toBlock":3815097,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[],"resultHash":"0x7aeacbe9393cba82f217ff13dcc2ebc62c088f6745b79354295c50e3030b1396"},{"fromBlock":3625839,"toBlock":3625847,"address":null,"topics":null,"resultHash":"0x926644cf1e9aa917d9aad888b9d92a8dd448f35122f67090de164301a9ffabfb"},{"fromBlock":5493331,"toBlock":5493340,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0x4f560094c3fbcc28232da5a2675552a05a2e9773e0f1861421e4d4495ad15641"},{"fromBlock":6680565,"toBlock":6680567,"address":["0x800ec0d65adb70f0b69b7db052c6bd89c2406ac4"],"topics":[null,null,null],"resultHash":"0xff5658503ee1fedc05d1d2e8ba2cf93d6fd17afb1f77acf7e7970315411243c9"},{"fromBlock":5493616,"toBlock":5493622,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[null,null,null],"resultHash":"0x100e14a4ad45a3d43fece09adbe8055d114838ad0c5e89587e888da2da14a01d"},{"fromBlock":5493293,"toBlock":5493314,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x0000000000000000000000000000000000000000000000000000000000000000"],null],"resultHash":"0x01a50b95d8e03e26ac4ba52e0b17590adb593ea91dfe3d1a13bfd4cfc6dddf35"},{"fromBlock":5493339,"toBlock":5493363,"address":["0x40001ecac527d825d8d73f50ceab01925676099b","0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[null,["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x92582f6b68f65f9c06d90292600b8b65399fc6c03744fa752435b50dec7de2c2"},{"fromBlock":5493331,"toBlock":5493357,"address":null,"topics":[null,["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x2f26cd5f0094a8805f350cfcedc5aa7340740d2187568033dc714af950498030"},{"fromBlock":2598719,"toBlock":2598757,"address":null,"topics":null,"resultHash":"0x3a0acb66a0b06141df598a78244b4e8e2f081bfac02109711ac8f32da7eea34f"},{"fromBlock":3323980,"toBlock":3323993,"address":null,"topics":null,"resultHash":"0x4c4a84cb751db0c3630e18d1f30b2aad7c204e9fb54010de32c0514d7611ee1f"},{"fromBlock":3382071,"toBlock":3382082,"address":null,"topics":[],"resultHash":"0x78f9d9d08ed9a3991add11bcfedb54869aa3f435641a6f792c6e8dc3935462f8"},{"fromBlock":5493306,"toBlock":5493333,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05","0x0000000000000000000000005b3f3266a9fcce9dfd996cd6f08d8513cb021062"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0xc0e01946f6ff0576963dfd62879a6a2d56e3c3618a80024057887e46860a222a"},{"fromBlock":5493303,"toBlock":5493316,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c"]],"resultHash":"0x72836c9def3c2767c27d1da6836d08f4eefc1405e37b95be56a2500e3b0695f0"},{"fromBlock":3792248,"toBlock":3792284,"address":[],"topics":[null,null,["0x000000000000000000000000572af1afa5afcfc6fdf1eb2913aa4463037860e8"]],"resultHash":"0xb431ba440baa3b59ea1c59a1d240cfa18ac70519da584de0e6f509373c07f009"},{"fromBlock":3323984,"toBlock":3323991,"address":null,"topics":[],"resultHash":"0xf33f353e4d570634fd5eb13a68b89b8b618c18cca578c90e390d8efb20f786ec"},{"fromBlock":3031191,"toBlock":3031213,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x22388408f33994428f5c2654b0106389f94ba29c7297788ea1ede484c75d94b1"},{"fromBlock":5493342,"toBlock":5493348,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x32eb4a5a4d836f002b42e42ed882adae5044f70d9909e345910548da61327a5a"},{"fromBlock":5493310,"toBlock":5493330,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0xd4dce78e5596fe7f78b7ec121c56a023f41dc3b53c61130454843bb76fe8ad99"},{"fromBlock":5654229,"toBlock":5654250,"address":["0xf1d6d31b577a2e54f6909813bfefcd73b9341f1f"],"topics":[],"resultHash":"0xa320ac5e74496483f37cf0c4585d7be73d50308ba4308b70d1549d357b4344fa"},{"fromBlock":3957469,"toBlock":3957537,"address":null,"topics":[null,null,null,null],"resultHash":"0x945421a800835e7681cf29beea43c5dae6bdb302bd77057d9d18eb5435a4a1e0"},{"fromBlock":7376209,"toBlock":7376215,"address":[],"topics":[null,["0x0000000000000000000000000000000000000000000000000000000000002b74"]],"resultHash":"0x5d64b3e32a1a21403ee33c8cd4a4a3054b0290ee4a41158943af1d2f32cf7991"},{"fromBlock":3415430,"toBlock":3415451,"address":null,"topics":[null],"resultHash":"0xc2a666f730140d3ad0e219f1ab6b3cad0b0e46a781020208987a95b13731e21e"},{"fromBlock":3323980,"toBlock":3323993,"address":null,"topics":[],"resultHash":"0x4c4a84cb751db0c3630e18d1f30b2aad7c204e9fb54010de32c0514d7611ee1f"},{"fromBlock":5493282,"toBlock":5493339,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x0eb3848b06830ff718d7f37511de4e113067755ec3d6e826dec112b2cf253ac0"},{"fromBlock":5493330,"toBlock":5493345,"address":null,"topics":[null,null,["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0xcf8d2a4fc3238e85ce808adf99ce726b16dd0a365d60a4232692a952b79e93c1"},{"fromBlock":3814610,"toBlock":3814620,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x64369a70df6cf631cb3191630bb3c79917de4528e05cd243a62984496d15149c"},{"fromBlock":3445845,"toBlock":3445853,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x61d93f45d87fad47230c35af30f7309667b86d58034aeacf0f615a9649a7b4c8"},{"fromBlock":5493301,"toBlock":5493355,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05","0x0000000000000000000000005b3f3266a9fcce9dfd996cd6f08d8513cb021062"],["0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x3bbeefb89ca10686e5f3fd5024124e53c35f36ca92743ee7292b0f1f58b732ae"},{"fromBlock":5505409,"toBlock":5505427,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c"]],"resultHash":"0x8977d4a7814d57ab342654f731a641fa0e4dae0fa4690e3c9c007c74c4cbf3e3"},{"fromBlock":3029501,"toBlock":3029534,"address":null,"topics":null,"resultHash":"0x1eb691e7a65ed03bf92f3b262b8d2e789bd5d4022d2dbfe6123c847752f89a3f"},{"fromBlock":7321450,"toBlock":7321480,"address":["0xea58fca6849d79ead1f26608855c2d6407d54ce2"],"topics":[],"resultHash":"0x102bb5ee57555f26557be81ad83f2ecee74a14c2be509f0352f60a99fefd39eb"},{"fromBlock":6222643,"toBlock":6222651,"address":[],"topics":[["0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f"]],"resultHash":"0x47c10465fb7398387112a36bb992803dec8e5508a4fa68fbd7b04b366c327d67"},{"fromBlock":3765977,"toBlock":3765996,"address":["0x6375394335f34848b850114b66a49d6f47f2cda8"],"topics":[],"resultHash":"0x18ffb55c84ed84c9f7b5a05c666c5ef5d0f1838ea306c31292cbb1d052221f12"},{"fromBlock":5411960,"toBlock":5412029,"address":[],"topics":[["0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"]],"resultHash":"0x5cdfbabb65fa946373787a22c67dc6a97929c3140c940b16072e068fe248e03d"},{"fromBlock":5493332,"toBlock":5493341,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"],null,["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xd334b0ee8c494f9667978abf688c3cc583215131f2040d80149817ca7a7ab047"},{"fromBlock":5493312,"toBlock":5493322,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x6521f31c4b64bcf3de19e45743925c73ca398b5b691c4abee40cd39862b54909"},{"fromBlock":3423625,"toBlock":3423664,"address":["0x53844f9577c2334e541aec7df7174ece5df1fcf0"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x5420a3c09990469a4330a55fdce7e00e5fbc06666e220014f4db37d5c15092e6"},{"fromBlock":3480792,"toBlock":3480813,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0xf14caf0fe9be0fe65bb040d55bdc85a39acbb901fe82f605e2b7cda7b8e75fd4"},{"fromBlock":6262696,"toBlock":6262702,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0xcadd21bd5ac71bde6732cc4afa7a0891e270cee4a1ee7d86eec03161e8b7272b"},{"fromBlock":5493320,"toBlock":5493326,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"]],"resultHash":"0x6f6d68deae4494b3ffb4969e22e7965bf982a785de36fdff2e3d08b28da654a7"},{"fromBlock":6610820,"toBlock":6610824,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00d05ab44e279ac59e855cb75dc2ae23b200ad994797b6f1f028f96a46ecce02"],null,null],"resultHash":"0x52c67010783d267bb01a96ecf4348ba18266ba3171f211adf2e5b101ff43cbc0"},{"fromBlock":2939169,"toBlock":2939192,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xc0ca92c9f1e3b5944d7b16db06e0cdba3157c040ea0a2817826ee1480a30e01c"},{"fromBlock":7370181,"toBlock":7370240,"address":["0x5500e5f864d07a7026d9abc7ad49e2364987ffbf"],"topics":[["0xcf8c667058d3773bf421bedb38a6938759b277329bac254c37f52f8b252548e2"]],"resultHash":"0xd5bd2f8de5f9fef3265a08ee2157bc495e4293f9d9be0c86215615098e62824a"},{"fromBlock":2768957,"toBlock":2769013,"address":null,"topics":null,"resultHash":"0x0063bd8c580193ac10e22d3358f495872a0ecc87541087009d68593f2e177320"},{"fromBlock":5493298,"toBlock":5493304,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0xe2477957a48e5c442d27ba7ab0674647de6a9d79eeab88965979f0e2169cc0d4"},{"fromBlock":5493314,"toBlock":5493323,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xdd9025c89cd8cd2bf041f7ac887195a3d0412a16635fa4721b2984c2b4ba5a59"},{"fromBlock":3814619,"toBlock":3814636,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x652da9f1d878e182dd5d3ddf241d455d2de94664a708476d392dfea7e77a7c7a"},{"fromBlock":5599488,"toBlock":5599496,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x2c457e0c3c6bc80a75c6b3e2fe31fde6c9f8b805495ba031b21d592906dd0728"},{"fromBlock":5493341,"toBlock":5493354,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xcad906a09fce6f97a5cf8e4e7e63d3037177fb548497ccc5e43e268087a77e35"},{"fromBlock":5493294,"toBlock":5493305,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c"]],"resultHash":"0xd58974c47e4d8b8f5672bf189144ed5f90fc93c124d9fde51626ee31b5a98b2a"},{"fromBlock":2989393,"toBlock":2989442,"address":null,"topics":[],"resultHash":"0x56a9b7f938a39a602fb6a7f7f83ea63553eb02cbce0a8da9b9a39bc55aeec7ae"},{"fromBlock":4574102,"toBlock":4574112,"address":["0x09547e68ce13fdecb5bf52fd17379fffa97cb797"],"topics":[],"resultHash":"0x5d5813acb1ef3de71c45d9fce4828ff81daa3852649b3bd7b6b869eb969e5b11"}],[{"fromBlock":6565905,"toBlock":6565906,"address":null,"topics":null,"resultHash":"0xaf76e893cb9ce0d861aacc543bc4d3766b1d8b62396e8a52da14d30c2ae972aa"},{"fromBlock":5242179,"toBlock":5242179,"address":null,"topics":null,"resultHash":"0xf4e66bea5f947f9cd2848e14eda0f260c75cfa729e3669956ed136d2b6ded5b1"},{"fromBlock":5654231,"toBlock":5654232,"address":null,"topics":[],"resultHash":"0x6517f9d2db7ac2dc33fe98ad35ce7e6cda037eb01483626bd9272c024a9e6a26"},{"fromBlock":4432894,"toBlock":4432895,"address":null,"topics":[null],"resultHash":"0x066879d2ba5c1a81b347a6630bf959ab6da137982a119d4d77cb3c6031080ba4"},{"fromBlock":4251794,"toBlock":4251800,"address":null,"topics":null,"resultHash":"0x92c8fd918cb78a06e121573358fa3b43e1728410cdf300e6caa574fb1de7440a"},{"fromBlock":5599361,"toBlock":5599363,"address":null,"topics":[null,null,null],"resultHash":"0x7534c20335ce21e0413d903e2d04caa5390e63c20eece7ca8f150167b2a5ac91"},{"fromBlock":6456884,"toBlock":6456885,"address":null,"topics":null,"resultHash":"0xb05d0123c35050017f7b44d1b533bb360c2227aa42c9dd6a7cbb6612738fef27"},{"fromBlock":3801924,"toBlock":3801928,"address":null,"topics":null,"resultHash":"0x713b9f4bd0e0b141472d951f76beb5393b268ee98230c0111763bceb5fbcaaf9"},{"fromBlock":7572250,"toBlock":7572253,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xc6aa420ff5d9e4c57a34d5d90e5819ac96ad4598001057063cabcbc18902b2ba"},{"fromBlock":2407656,"toBlock":2407659,"address":null,"topics":null,"resultHash":"0x727cfec79e61c0f79e9adbf01e05eb8e53a412688b6facbb1c86c5f9a44dee0f"},{"fromBlock":5034145,"toBlock":5034145,"address":null,"topics":[null],"resultHash":"0xd9b02b55f4445129c0d6572b2b2a68f3fbda8ad96f6ff3ecdf19299bed44e6e1"},{"fromBlock":6745063,"toBlock":6745064,"address":null,"topics":[null,null,null],"resultHash":"0x9690f9fc27dc66103468054b21bdf56d05a541303e67c33421ab1466d098f516"},{"fromBlock":4040372,"toBlock":4040373,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0xe613bd44a92e7a2339ed49a4a22b914e5ebc6f9c940f53729af41c250c5631cd"},{"fromBlock":6837588,"toBlock":6837588,"address":null,"topics":null,"resultHash":"0x0d84cdef0c770630787cb4d4da2ee619c5283372d5cfc30c8d3ad04b7fc4673f"},{"fromBlock":5493364,"toBlock":5493371,"address":["0xaee8e96bed6c5445658447fdee8edd12a1fd79b4"],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,["0x000000000000000000000000b6f4a8dccac0beab1062212f4665879d9937c83c","0x000000000000000000000000b31c077c99e0d61305fcd873a39f974d13bc773c"]],"resultHash":"0x5ccfe5b1ffdab03c32d580b2ee6ce0fd1a984e9e16f0a9e264ee8ffc07e5c87b"},{"fromBlock":5405140,"toBlock":5405142,"address":null,"topics":[],"resultHash":"0xe2a9e7f0a4e7bc9b3a03b74872427252370377ae830a6a33a14bbca5cc7f20d6"},{"fromBlock":5139583,"toBlock":5139583,"address":null,"topics":[],"resultHash":"0x42c4b1d2cea373114f509dfe5f7a3510bfc49b660712f93228591aba2dde000a"},{"fromBlock":7118886,"toBlock":7118887,"address":null,"topics":[null,null],"resultHash":"0x80daa9d128f3a724c21195ace784dea18bc9d40ca1666642129af707e15e6914"},{"fromBlock":6197749,"toBlock":6197749,"address":null,"topics":[],"resultHash":"0x3f5e8ec8cdd98b45f400793ac0314016aaa429e6b2107ca5224663fabad82fc8"},{"fromBlock":5139583,"toBlock":5139583,"address":null,"topics":[],"resultHash":"0x42c4b1d2cea373114f509dfe5f7a3510bfc49b660712f93228591aba2dde000a"},{"fromBlock":4040372,"toBlock":4040373,"address":["0x958b482c4e9479a600bfffddfe94d974951ca3c7"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]],"resultHash":"0x12ce9c8987085cecca97dfead91c5aece1b70a96dc54643955609da265916a7c"},{"fromBlock":6269386,"toBlock":6269386,"address":null,"topics":null,"resultHash":"0xf1036eef997cf51ecb1978006f73fa844c73122f7ecdfbd1115f824cb1e4e8e4"},{"fromBlock":7037380,"toBlock":7037381,"address":null,"topics":null,"resultHash":"0xd458f5a3cbb9466665d117f58c99e9512ffde0a90103af37bb0877aeac43e8a8"},{"fromBlock":3685673,"toBlock":3685674,"address":null,"topics":null,"resultHash":"0x1e23f4f8b470c7b3d4fe0f4aa14723e890c1649f1caa6892ec4183e76801aa69"},{"fromBlock":4554814,"toBlock":4554814,"address":null,"topics":[],"resultHash":"0xfa6b462843ab60dad05863af3a86e640cd90c845990cacfef836a722579aa2c3"},{"fromBlock":4257517,"toBlock":4257517,"address":null,"topics":null,"resultHash":"0x1068639788247dedb33968ed12137ed699a790af76b4b6cda5db9f80962ec5f8"},{"fromBlock":6291250,"toBlock":6291250,"address":null,"topics":null,"resultHash":"0x1fe751bfa3e8d81bfaa8c0acc793b685d3703db2a35f0e5ee955471bcd543556"},{"fromBlock":5493617,"toBlock":5493618,"address":null,"topics":[null,null,null],"resultHash":"0x1112009917007fdb935408783295b129a085732e58661623e7460d7967166a1e"},{"fromBlock":5654275,"toBlock":5654276,"address":null,"topics":[],"resultHash":"0x7d0f31a63e57ee6ab990107cdb64aa683592d58bba7eef1ffc3131e1a714e337"},{"fromBlock":6449052,"toBlock":6449053,"address":null,"topics":null,"resultHash":"0xc38a6c69d734cd9788afef915bafe6b6dbf9fe29c9e10e7d4fe555f429844b1d"},{"fromBlock":3711954,"toBlock":3711955,"address":null,"topics":[null,null],"resultHash":"0xbcafb9bdaef4e26e3c7218c35fd0257ca81e9d8bad760d1d180444da6cb8fefa"},{"fromBlock":4349153,"toBlock":4349153,"address":null,"topics":null,"resultHash":"0xf475b96e6656fe43f673ffd25feccb5fb162fab8d79b955a851327187eee5b75"},{"fromBlock":5360198,"toBlock":5360198,"address":null,"topics":null,"resultHash":"0xd53fee7fa1a4f0ada71be57fcf9098893db2a0e3ea187a63d0e5cc2e9074504e"},{"fromBlock":5779938,"toBlock":5779944,"address":[],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null,null],"resultHash":"0x65c1dec6584d9b772fbe2070fdc7345edd912069cf46b2550c305cae65bd5fd9"},{"fromBlock":5493617,"toBlock":5493618,"address":null,"topics":[null,null,null],"resultHash":"0x1112009917007fdb935408783295b129a085732e58661623e7460d7967166a1e"},{"fromBlock":5493298,"toBlock":5493300,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],null,null],"resultHash":"0x91f77fb657d475747e03a6a44c6219ddcf317f04a8bc29d20a7d7059cb71cf9b"},{"fromBlock":5493325,"toBlock":5493329,"address":[],"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4"]],"resultHash":"0xc0e1e36cd6258ffd011c45cd804536248494dc0e73f239898f06237a6366500d"},{"fromBlock":4584825,"toBlock":4584826,"address":null,"topics":[null,null,null],"resultHash":"0x5f1a9ebbb2c9f64eeda1553df9d3717c188dc91f2d99046638442e5379183c56"},{"fromBlock":5626614,"toBlock":5626615,"address":null,"topics":[null,null],"resultHash":"0x76fe5e0369d87226c31a57b6da2ec6bf2ea654185c12287a7486f035968d9de6"},{"fromBlock":4554814,"toBlock":4554814,"address":null,"topics":[],"resultHash":"0xfa6b462843ab60dad05863af3a86e640cd90c845990cacfef836a722579aa2c3"},{"fromBlock":5139515,"toBlock":5139516,"address":null,"topics":[null,null,null],"resultHash":"0x7985983304ce909a7b59120c03d64858b6d844f63a95f49d8230135d6837d58b"},{"fromBlock":6480761,"toBlock":6480763,"address":null,"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e"],null],"resultHash":"0xb8e9bf1dbb746c1072b8fc11a2cb8477056becb669e1c99ad0a7acfc1657bc08"},{"fromBlock":6769658,"toBlock":6769659,"address":null,"topics":null,"resultHash":"0xf5f2071f52ca26daa5396956de118ce6e8387f1528b4967e8fc75d029827cb2e"},{"fromBlock":5493325,"toBlock":5493327,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],null],"resultHash":"0x66cac069aae581cd319e9a1da5c759bdada66aed1ddd298757690cd700a7de60"},{"fromBlock":5493321,"toBlock":5493328,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0xe37d302cd4d8b94b8c8118eacac9b9846717bfd87220e954e9726e1e13aa3a81"},{"fromBlock":3323134,"toBlock":3323139,"address":null,"topics":[null,null,null],"resultHash":"0x22cc6efc06476d95c94ed208e2b28ab120e9f08af1cd4883f08ed1175d0d17d1"},{"fromBlock":7118886,"toBlock":7118888,"address":null,"topics":[null,null],"resultHash":"0x4b98b93f63a9b3f7e09797a39e0db77e23ea98037f7b9e3d5688aac9a3c569a5"},{"fromBlock":6884098,"toBlock":6884098,"address":null,"topics":null,"resultHash":"0xbd77cc5638889bcf6e26ca55d192270b7610a5519832069dbeb16c12b779d351"},{"fromBlock":6443316,"toBlock":6443317,"address":null,"topics":null,"resultHash":"0xf30e2313713d397591bc207e3351535129e1bbb9b41735ea76c2ba6f181bcc0a"},{"fromBlock":6569037,"toBlock":6569038,"address":null,"topics":[],"resultHash":"0x17030ad9a65abdc3fd4cc1cdcac568e62e3d63c4631e8a5f5030a78a09eec33a"},{"fromBlock":3660928,"toBlock":3660929,"address":null,"topics":[],"resultHash":"0x53520a227fd9c8c22d4b8911c68453708b30c9567da83f5e6e6be795b86e43bf"},{"fromBlock":4864076,"toBlock":4864078,"address":null,"topics":[],"resultHash":"0xea58d8d378952057be211f23df0b6f96ede9cae714eeef0c35126a4fb25cf45d"},{"fromBlock":7027513,"toBlock":7027513,"address":null,"topics":null,"resultHash":"0xb561f7dcf5e1d075fe4850ee4b907080b0f6714d3df137d7be222c3ae8f89575"},{"fromBlock":5979222,"toBlock":5979223,"address":null,"topics":null,"resultHash":"0x3e44433a2d3285cd899585eb54b1062f29c57a8403e79d081de2d5393a42d044"},{"fromBlock":4065028,"toBlock":4065029,"address":null,"topics":[],"resultHash":"0xe9c84b484160004dc794d61ac80dd4cb705c7a1d3b19142b6c9f5fddcb924d90"},{"fromBlock":7717495,"toBlock":7717495,"address":null,"topics":null,"resultHash":"0xf8ff48953fbc7fcdce27cd136e6659554a8f3f5331b2f2d3026e529383e2a6d3"},{"fromBlock":5493325,"toBlock":5493328,"address":["0x0305ea0a4b43a12e3d130448e9b4711932231e83"],"topics":[["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],null],"resultHash":"0x2734a9bfaf05e6f6be37ba94602d9c19a890ea12c8b965459d542dee388f23b5"},{"fromBlock":4574105,"toBlock":4574105,"address":null,"topics":null,"resultHash":"0xefa9b35a2c9b47525943d8fe99f856b9b1abfeee2c7b1b31a3c915b2fe75f005"},{"fromBlock":7572251,"toBlock":7572251,"address":null,"topics":[null],"resultHash":"0xd0d2123b2d33c47b334b8966028b999ee3c4c020ddfe9278c1a5a001f4ddd9cb"},{"fromBlock":6262696,"toBlock":6262696,"address":null,"topics":[null],"resultHash":"0x76931464d54a710c3a3f062a1c87e471c338dcfa6371d5d5d9bf7bbd3333239a"},{"fromBlock":6565905,"toBlock":6565906,"address":null,"topics":[],"resultHash":"0xaf76e893cb9ce0d861aacc543bc4d3766b1d8b62396e8a52da14d30c2ae972aa"},{"fromBlock":6205025,"toBlock":6205025,"address":null,"topics":[],"resultHash":"0x3f700dc32fc073b0559ce5e60f2ea24e1ae29013c8f4730aaa237fa27380f7c0"},{"fromBlock":6717558,"toBlock":6717561,"address":null,"topics":[null,null,null],"resultHash":"0xaacb2d01ee893d2560dc74c80ed7fe2bf3ae2f0d84980ea7d3b1ada22160efc7"},{"fromBlock":5493303,"toBlock":5493303,"address":null,"topics":[null,null,null],"resultHash":"0x42b1d4e0a9db338433d542f2f0929051d7d2230518df015af6b5bfce600be042"},{"fromBlock":6197749,"toBlock":6197749,"address":null,"topics":[],"resultHash":"0x3f5e8ec8cdd98b45f400793ac0314016aaa429e6b2107ca5224663fabad82fc8"},{"fromBlock":7616944,"toBlock":7616944,"address":null,"topics":null,"resultHash":"0x1b1b020e0c4523eb31378e7ad39cce1f631ee18d6666ff7d1093ecaf85efe953"},{"fromBlock":7580259,"toBlock":7580259,"address":null,"topics":[null,null],"resultHash":"0x5d0800e2b672a54de565351b3f17a374ec7617dec7f19314a12b02344144bc44"},{"fromBlock":3660929,"toBlock":3660930,"address":null,"topics":[],"resultHash":"0xeeb27b76a1e3e209f72948800327f0fae51b0f58958b8b8ef93ecba29265f6af"},{"fromBlock":5712350,"toBlock":5712351,"address":null,"topics":[null,null],"resultHash":"0xa8b147b8117ac09a555f158d147ff287c749be54954f82daa6d4ecf98d9c72c9"},{"fromBlock":6197749,"toBlock":6197749,"address":null,"topics":null,"resultHash":"0x3f5e8ec8cdd98b45f400793ac0314016aaa429e6b2107ca5224663fabad82fc8"},{"fromBlock":7370203,"toBlock":7370203,"address":null,"topics":[],"resultHash":"0xcc398610f7d47312132e785062dfad562d65ef2cc3700d9d24e10bbba0a737ba"},{"fromBlock":4584824,"toBlock":4584825,"address":null,"topics":[null,null,null],"resultHash":"0x7642c78ad6110d34a6c23e18b783ec80ef86b87fe556da33e9ca1c67ed7909ad"},{"fromBlock":6301968,"toBlock":6301968,"address":null,"topics":null,"resultHash":"0x146c59d9cf24837378452579154cd01004c0dab6970880a52349bcb9c6f89d19"},{"fromBlock":4341355,"toBlock":4341356,"address":null,"topics":null,"resultHash":"0x164219d00b3d20a89cb4d4d8d1ecd859191605665e3ccfe3d01f9b1f29ad8b63"},{"fromBlock":3903294,"toBlock":3903301,"address":null,"topics":[null,null,null],"resultHash":"0xde11c34087aad96fcb81d2ac23d42e2fd72d9f95c2282c7689ec74fe9759586e"},{"fromBlock":4811912,"toBlock":4811915,"address":null,"topics":[null,null],"resultHash":"0x063cf752dd50e421f82909fa47fe0ff93141d7fb38bb28e1d9a452ca90485765"},{"fromBlock":3510475,"toBlock":3510477,"address":null,"topics":[null,null],"resultHash":"0x64b8dbe61dc24b0efdb602504e8114ee91c4e78ed13dea93deb3547402c4d99a"},{"fromBlock":3660928,"toBlock":3660929,"address":null,"topics":[],"resultHash":"0x53520a227fd9c8c22d4b8911c68453708b30c9567da83f5e6e6be795b86e43bf"},{"fromBlock":6291406,"toBlock":6291406,"address":null,"topics":[],"resultHash":"0xbbb0336986caccf3fb9da71441f2c6a65ca254c3c6c9c7e877b3144de9edce0f"},{"fromBlock":7376212,"toBlock":7376212,"address":null,"topics":null,"resultHash":"0x8ec658d95d64ad6fd6f112d9e1ede080c75686d93ee6cab5ed331191073bfc80"},{"fromBlock":4347818,"toBlock":4347819,"address":null,"topics":null,"resultHash":"0xfe4dcf817b71cdee584c2b71cb2fd4dd3976583e2416f8a45cb88964065fbff2"},{"fromBlock":6222647,"toBlock":6222648,"address":null,"topics":[],"resultHash":"0x9268c68b4b85c2970a071fddd3c0223ffbf3bb9212ec8bb9a62e14894fa55416"},{"fromBlock":3465581,"toBlock":3465582,"address":null,"topics":null,"resultHash":"0x6ee80d97ad18f96d4c9319b33c3a9183a257ae69fa33121c4aa69c2c37e5d67a"},{"fromBlock":3757519,"toBlock":3757520,"address":null,"topics":null,"resultHash":"0x8fc77c06bbb1a80ee802733e3442f05efe8bb687b957a38c34932073754d123b"},{"fromBlock":7613871,"toBlock":7613873,"address":["0x6866b4923fc3fe89ac10b3ef0ab7e9ef5fc00dca"],"topics":[],"resultHash":"0x67ecc24faa016d9194ef4f74e1ab3b86ca0a53515e963234e279dde6004f87e0"},{"fromBlock":5654275,"toBlock":5654276,"address":null,"topics":[],"resultHash":"0x7d0f31a63e57ee6ab990107cdb64aa683592d58bba7eef1ffc3131e1a714e337"},{"fromBlock":5626614,"toBlock":5626615,"address":null,"topics":[null,null],"resultHash":"0x76fe5e0369d87226c31a57b6da2ec6bf2ea654185c12287a7486f035968d9de6"},{"fromBlock":6569037,"toBlock":6569038,"address":null,"topics":null,"resultHash":"0x17030ad9a65abdc3fd4cc1cdcac568e62e3d63c4631e8a5f5030a78a09eec33a"},{"fromBlock":6456958,"toBlock":6456959,"address":null,"topics":[null],"resultHash":"0xc7b2c0861416cd76d05ba982d2ac458dd333fdf0a71e069c9a0a2f3daa0be58c"},{"fromBlock":7370203,"toBlock":7370203,"address":null,"topics":[],"resultHash":"0xcc398610f7d47312132e785062dfad562d65ef2cc3700d9d24e10bbba0a737ba"},{"fromBlock":3660929,"toBlock":3660930,"address":null,"topics":null,"resultHash":"0xeeb27b76a1e3e209f72948800327f0fae51b0f58958b8b8ef93ecba29265f6af"},{"fromBlock":3628313,"toBlock":3628313,"address":null,"topics":null,"resultHash":"0x2428b225b8eab790e2af04f4c55bab2cdf9ea859e054ef0190c86492dc4e88be"},{"fromBlock":7572251,"toBlock":7572251,"address":null,"topics":[null],"resultHash":"0xd0d2123b2d33c47b334b8966028b999ee3c4c020ddfe9278c1a5a001f4ddd9cb"},{"fromBlock":5493324,"toBlock":5493330,"address":null,"topics":[["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"],["0x00000000000000000000000019c7680f666e51a6086c270e2aa2a517ae585d05"],["0x000000000000000000000000aee8e96bed6c5445658447fdee8edd12a1fd79b4","0x000000000000000000000000aabb8c0deb1270151b9b0776bbf9c890cd877e67"]],"resultHash":"0x6abb0ecbfeba3159b9f0a814a1ef9d99db2f48afbf20febf8edaf1e4e0752680"},{"fromBlock":3765989,"toBlock":3765990,"address":null,"topics":[],"resultHash":"0x50a0b7dd015eb4b34bc4a3182071c7b85442fe8bd5276e51d0bcdc0531420c4f"},{"fromBlock":6306764,"toBlock":6306764,"address":null,"topics":null,"resultHash":"0x3b10108fec0249fe6669e75d90ae9fe99511de1e54d36b4769a6d9bcdeabea77"},{"fromBlock":4341448,"toBlock":4341448,"address":null,"topics":null,"resultHash":"0x4478b7691f0e2950791ef90b6e326c57fdc3b15adfae9f9f2ffaabcaad42ea05"},{"fromBlock":5963332,"toBlock":5963333,"address":null,"topics":null,"resultHash":"0x3dac6cf693b06b72c6bae99d03194cf1c9e1294f71b4d7bcea17799dc565a522"},{"fromBlock":5654245,"toBlock":5654245,"address":null,"topics":[],"resultHash":"0xd04aa18b27effaca9d8ad1e479408117ef5961984e14e1f256771903ec7b45fd"},{"fromBlock":6425793,"toBlock":6425794,"address":null,"topics":null,"resultHash":"0x8eb1acbb576fd5c348ef3a84783996e2319adf028906a09c334067b13907cb2a"}]] diff --git a/cmd/workload/queries/history_mainnet.json b/cmd/workload/queries/history_mainnet.json new file mode 100644 index 000000000..69382381d --- /dev/null +++ b/cmd/workload/queries/history_mainnet.json @@ -0,0 +1 @@ +{"blockNumbers":[0,10965,21930,32895,43860,54825,65790,76755,87720,98685,109650,120615,131580,142545,153510,164475,175440,186405,197370,208335,219300,230265,241230,252195,263160,274125,285090,296055,307020,317985,328950,339915,350880,361845,372810,383775,394740,405705,416670,427635,438600,449565,460530,471495,482460,493425,504390,515355,526320,537285,548250,559215,570180,581145,592110,603075,614040,625005,635970,646935,657900,668865,679830,690795,701760,712725,723690,734655,745620,756585,767550,778515,789480,800445,811410,822375,833340,844305,855270,866235,877200,888165,899130,910095,921060,932025,942990,953955,964920,975885,986850,997815,1008780,1019745,1030710,1041675,1052640,1063605,1074570,1085535,1096500,1107465,1118430,1129395,1140360,1151325,1162290,1173255,1184220,1195185,1206150,1217115,1228080,1239045,1250010,1260975,1271940,1282905,1293870,1304835,1315800,1326765,1337730,1348695,1359660,1370625,1381590,1392555,1403520,1414485,1425450,1436415,1447380,1458345,1469310,1480275,1491240,1502205,1513170,1524135,1535100,1546065,1557030,1567995,1578960,1589925,1600890,1611855,1622820,1633785,1644750,1655715,1666680,1677645,1688610,1699575,1710540,1721505,1732470,1743435,1754400,1765365,1776330,1787295,1798260,1809225,1820190,1831155,1842120,1853085,1864050,1875015,1885980,1896945,1907910,1918875,1929840,1940805,1951770,1962735,1973700,1984665,1995630,2006595,2017560,2028525,2039490,2050455,2061420,2072385,2083350,2094315,2105280,2116245,2127210,2138175,2149140,2160105,2171070,2182035,2193000,2203965,2214930,2225895,2236860,2247825,2258790,2269755,2280720,2291685,2302650,2313615,2324580,2335545,2346510,2357475,2368440,2379405,2390370,2401335,2412300,2423265,2434230,2445195,2456160,2467125,2478090,2489055,2500020,2510985,2521950,2532915,2543880,2554845,2565810,2576775,2587740,2598705,2609670,2620635,2631600,2642565,2653530,2664495,2675460,2686425,2697390,2708355,2719320,2730285,2741250,2752215,2763180,2774145,2785110,2796075,2807040,2818005,2828970,2839935,2850900,2861865,2872830,2883795,2894760,2905725,2916690,2927655,2938620,2949585,2960550,2971515,2982480,2993445,3004410,3015375,3026340,3037305,3048270,3059235,3070200,3081165,3092130,3103095,3114060,3125025,3135990,3146955,3157920,3168885,3179850,3190815,3201780,3212745,3223710,3234675,3245640,3256605,3267570,3278535,3289500,3300465,3311430,3322395,3333360,3344325,3355290,3366255,3377220,3388185,3399150,3410115,3421080,3432045,3443010,3453975,3464940,3475905,3486870,3497835,3508800,3519765,3530730,3541695,3552660,3563625,3574590,3585555,3596520,3607485,3618450,3629415,3640380,3651345,3662310,3673275,3684240,3695205,3706170,3717135,3728100,3739065,3750030,3760995,3771960,3782925,3793890,3804855,3815820,3826785,3837750,3848715,3859680,3870645,3881610,3892575,3903540,3914505,3925470,3936435,3947400,3958365,3969330,3980295,3991260,4002225,4013190,4024155,4035120,4046085,4057050,4068015,4078980,4089945,4100910,4111875,4122840,4133805,4144770,4155735,4166700,4177665,4188630,4199595,4210560,4221525,4232490,4243455,4254420,4265385,4276350,4287315,4298280,4309245,4320210,4331175,4342140,4353105,4364070,4375035,4386000,4396965,4407930,4418895,4429860,4440825,4451790,4462755,4473720,4484685,4495650,4506615,4517580,4528545,4539510,4550475,4561440,4572405,4583370,4594335,4605300,4616265,4627230,4638195,4649160,4660125,4671090,4682055,4693020,4703985,4714950,4725915,4736880,4747845,4758810,4769775,4780740,4791705,4802670,4813635,4824600,4835565,4846530,4857495,4868460,4879425,4890390,4901355,4912320,4923285,4934250,4945215,4956180,4967145,4978110,4989075,5000040,5011005,5021970,5032935,5043900,5054865,5065830,5076795,5087760,5098725,5109690,5120655,5131620,5142585,5153550,5164515,5175480,5186445,5197410,5208375,5219340,5230305,5241270,5252235,5263200,5274165,5285130,5296095,5307060,5318025,5328990,5339955,5350920,5361885,5372850,5383815,5394780,5405745,5416710,5427675,5438640,5449605,5460570,5471535,5482500,5493465,5504430,5515395,5526360,5537325,5548290,5559255,5570220,5581185,5592150,5603115,5614080,5625045,5636010,5646975,5657940,5668905,5679870,5690835,5701800,5712765,5723730,5734695,5745660,5756625,5767590,5778555,5789520,5800485,5811450,5822415,5833380,5844345,5855310,5866275,5877240,5888205,5899170,5910135,5921100,5932065,5943030,5953995,5964960,5975925,5986890,5997855,6008820,6019785,6030750,6041715,6052680,6063645,6074610,6085575,6096540,6107505,6118470,6129435,6140400,6151365,6162330,6173295,6184260,6195225,6206190,6217155,6228120,6239085,6250050,6261015,6271980,6282945,6293910,6304875,6315840,6326805,6337770,6348735,6359700,6370665,6381630,6392595,6403560,6414525,6425490,6436455,6447420,6458385,6469350,6480315,6491280,6502245,6513210,6524175,6535140,6546105,6557070,6568035,6579000,6589965,6600930,6611895,6622860,6633825,6644790,6655755,6666720,6677685,6688650,6699615,6710580,6721545,6732510,6743475,6754440,6765405,6776370,6787335,6798300,6809265,6820230,6831195,6842160,6853125,6864090,6875055,6886020,6896985,6907950,6918915,6929880,6940845,6951810,6962775,6973740,6984705,6995670,7006635,7017600,7028565,7039530,7050495,7061460,7072425,7083390,7094355,7105320,7116285,7127250,7138215,7149180,7160145,7171110,7182075,7193040,7204005,7214970,7225935,7236900,7247865,7258830,7269795,7280760,7291725,7302690,7313655,7324620,7335585,7346550,7357515,7368480,7379445,7390410,7401375,7412340,7423305,7434270,7445235,7456200,7467165,7478130,7489095,7500060,7511025,7521990,7532955,7543920,7554885,7565850,7576815,7587780,7598745,7609710,7620675,7631640,7642605,7653570,7664535,7675500,7686465,7697430,7708395,7719360,7730325,7741290,7752255,7763220,7774185,7785150,7796115,7807080,7818045,7829010,7839975,7850940,7861905,7872870,7883835,7894800,7905765,7916730,7927695,7938660,7949625,7960590,7971555,7982520,7993485,8004450,8015415,8026380,8037345,8048310,8059275,8070240,8081205,8092170,8103135,8114100,8125065,8136030,8146995,8157960,8168925,8179890,8190855,8201820,8212785,8223750,8234715,8245680,8256645,8267610,8278575,8289540,8300505,8311470,8322435,8333400,8344365,8355330,8366295,8377260,8388225,8399190,8410155,8421120,8432085,8443050,8454015,8464980,8475945,8486910,8497875,8508840,8519805,8530770,8541735,8552700,8563665,8574630,8585595,8596560,8607525,8618490,8629455,8640420,8651385,8662350,8673315,8684280,8695245,8706210,8717175,8728140,8739105,8750070,8761035,8772000,8782965,8793930,8804895,8815860,8826825,8837790,8848755,8859720,8870685,8881650,8892615,8903580,8914545,8925510,8936475,8947440,8958405,8969370,8980335,8991300,9002265,9013230,9024195,9035160,9046125,9057090,9068055,9079020,9089985,9100950,9111915,9122880,9133845,9144810,9155775,9166740,9177705,9188670,9199635,9210600,9221565,9232530,9243495,9254460,9265425,9276390,9287355,9298320,9309285,9320250,9331215,9342180,9353145,9364110,9375075,9386040,9397005,9407970,9418935,9429900,9440865,9451830,9462795,9473760,9484725,9495690,9506655,9517620,9528585,9539550,9550515,9561480,9572445,9583410,9594375,9605340,9616305,9627270,9638235,9649200,9660165,9671130,9682095,9693060,9704025,9714990,9725955,9736920,9747885,9758850,9769815,9780780,9791745,9802710,9813675,9824640,9835605,9846570,9857535,9868500,9879465,9890430,9901395,9912360,9923325,9934290,9945255,9956220,9967185,9978150,9989115,10000080,10011045,10022010,10032975,10043940,10054905,10065870,10076835,10087800,10098765,10109730,10120695,10131660,10142625,10153590,10164555,10175520,10186485,10197450,10208415,10219380,10230345,10241310,10252275,10263240,10274205,10285170,10296135,10307100,10318065,10329030,10339995,10350960,10361925,10372890,10383855,10394820,10405785,10416750,10427715,10438680,10449645,10460610,10471575,10482540,10493505,10504470,10515435,10526400,10537365,10548330,10559295,10570260,10581225,10592190,10603155,10614120,10625085,10636050,10647015,10657980,10668945,10679910,10690875,10701840,10712805,10723770,10734735,10745700,10756665,10767630,10778595,10789560,10800525,10811490,10822455,10833420,10844385,10855350,10866315,10877280,10888245,10899210,10910175,10921140,10932105,10943070,10954035,10965000,10975965,10986930,10997895,11008860,11019825,11030790,11041755,11052720,11063685,11074650,11085615,11096580,11107545,11118510,11129475,11140440,11151405,11162370,11173335,11184300,11195265,11206230,11217195,11228160,11239125,11250090,11261055,11272020,11282985,11293950,11304915,11315880,11326845,11337810,11348775,11359740,11370705,11381670,11392635,11403600,11414565,11425530,11436495,11447460,11458425,11469390,11480355,11491320,11502285,11513250,11524215,11535180,11546145,11557110,11568075,11579040,11590005,11600970,11611935,11622900,11633865,11644830,11655795,11666760,11677725,11688690,11699655,11710620,11721585,11732550,11743515,11754480,11765445,11776410,11787375,11798340,11809305,11820270,11831235,11842200,11853165,11864130,11875095,11886060,11897025,11907990,11918955,11929920,11940885,11951850,11962815,11973780,11984745,11995710,12006675,12017640,12028605,12039570,12050535,12061500,12072465,12083430,12094395,12105360,12116325,12127290,12138255,12149220,12160185,12171150,12182115,12193080,12204045,12215010,12225975,12236940,12247905,12258870,12269835,12280800,12291765,12302730,12313695,12324660,12335625,12346590,12357555,12368520,12379485,12390450,12401415,12412380,12423345,12434310,12445275,12456240,12467205,12478170,12489135,12500100,12511065,12522030,12532995,12543960,12554925,12565890,12576855,12587820,12598785,12609750,12620715,12631680,12642645,12653610,12664575,12675540,12686505,12697470,12708435,12719400,12730365,12741330,12752295,12763260,12774225,12785190,12796155,12807120,12818085,12829050,12840015,12850980,12861945,12872910,12883875,12894840,12905805,12916770,12927735,12938700,12949665,12960630,12971595,12982560,12993525,13004490,13015455,13026420,13037385,13048350,13059315,13070280,13081245,13092210,13103175,13114140,13125105,13136070,13147035,13158000,13168965,13179930,13190895,13201860,13212825,13223790,13234755,13245720,13256685,13267650,13278615,13289580,13300545,13311510,13322475,13333440,13344405,13355370,13366335,13377300,13388265,13399230,13410195,13421160,13432125,13443090,13454055,13465020,13475985,13486950,13497915,13508880,13519845,13530810,13541775,13552740,13563705,13574670,13585635,13596600,13607565,13618530,13629495,13640460,13651425,13662390,13673355,13684320,13695285,13706250,13717215,13728180,13739145,13750110,13761075,13772040,13783005,13793970,13804935,13815900,13826865,13837830,13848795,13859760,13870725,13881690,13892655,13903620,13914585,13925550,13936515,13947480,13958445,13969410,13980375,13991340,14002305,14013270,14024235,14035200,14046165,14057130,14068095,14079060,14090025,14100990,14111955,14122920,14133885,14144850,14155815,14166780,14177745,14188710,14199675,14210640,14221605,14232570,14243535,14254500,14265465,14276430,14287395,14298360,14309325,14320290,14331255,14342220,14353185,14364150,14375115,14386080,14397045,14408010,14418975,14429940,14440905,14451870,14462835,14473800,14484765,14495730,14506695,14517660,14528625,14539590,14550555,14561520,14572485,14583450,14594415,14605380,14616345,14627310,14638275,14649240,14660205,14671170,14682135,14693100,14704065,14715030,14725995,14736960,14747925,14758890,14769855,14780820,14791785,14802750,14813715,14824680,14835645,14846610,14857575,14868540,14879505,14890470,14901435,14912400,14923365,14934330,14945295,14956260,14967225,14978190,14989155,15000120,15011085,15022050,15033015,15043980,15054945,15065910,15076875,15087840,15098805,15109770,15120735,15131700,15142665,15153630,15164595,15175560,15186525,15197490,15208455,15219420,15230385,15241350,15252315,15263280,15274245,15285210,15296175,15307140,15318105,15329070,15340035,15351000,15361965,15372930,15383895,15394860,15405825,15416790,15427755,15438720,15449685,15460650,15471615,15482580,15493545,15504510,15515475,15526440,15537405,15548370,15559335,15570300,15581265,15592230,15603195,15614160,15625125,15636090,15647055,15658020,15668985,15679950,15690915,15701880,15712845,15723810,15734775,15745740,15756705,15767670,15778635,15789600,15800565,15811530,15822495,15833460,15844425,15855390,15866355,15877320,15888285,15899250,15910215,15921180,15932145,15943110,15954075,15965040,15976005,15986970,15997935,16008900,16019865,16030830,16041795,16052760,16063725,16074690,16085655,16096620,16107585,16118550,16129515,16140480,16151445,16162410,16173375,16184340,16195305,16206270,16217235,16228200,16239165,16250130,16261095,16272060,16283025,16293990,16304955,16315920,16326885,16337850,16348815,16359780,16370745,16381710,16392675,16403640,16414605,16425570,16436535,16447500,16458465,16469430,16480395,16491360,16502325,16513290,16524255,16535220,16546185,16557150,16568115,16579080,16590045,16601010,16611975,16622940,16633905,16644870,16655835,16666800,16677765,16688730,16699695,16710660,16721625,16732590,16743555,16754520,16765485,16776450,16787415,16798380,16809345,16820310,16831275,16842240,16853205,16864170,16875135,16886100,16897065,16908030,16918995,16929960,16940925,16951890,16962855,16973820,16984785,16995750,17006715,17017680,17028645,17039610,17050575,17061540,17072505,17083470,17094435,17105400,17116365,17127330,17138295,17149260,17160225,17171190,17182155,17193120,17204085,17215050,17226015,17236980,17247945,17258910,17269875,17280840,17291805,17302770,17313735,17324700,17335665,17346630,17357595,17368560,17379525,17390490,17401455,17412420,17423385,17434350,17445315,17456280,17467245,17478210,17489175,17500140,17511105,17522070,17533035,17544000,17554965,17565930,17576895,17587860,17598825,17609790,17620755,17631720,17642685,17653650,17664615,17675580,17686545,17697510,17708475,17719440,17730405,17741370,17752335,17763300,17774265,17785230,17796195,17807160,17818125,17829090,17840055,17851020,17861985,17872950,17883915,17894880,17905845,17916810,17927775,17938740,17949705,17960670,17971635,17982600,17993565,18004530,18015495,18026460,18037425,18048390,18059355,18070320,18081285,18092250,18103215,18114180,18125145,18136110,18147075,18158040,18169005,18179970,18190935,18201900,18212865,18223830,18234795,18245760,18256725,18267690,18278655,18289620,18300585,18311550,18322515,18333480,18344445,18355410,18366375,18377340,18388305,18399270,18410235,18421200,18432165,18443130,18454095,18465060,18476025,18486990,18497955,18508920,18519885,18530850,18541815,18552780,18563745,18574710,18585675,18596640,18607605,18618570,18629535,18640500,18651465,18662430,18673395,18684360,18695325,18706290,18717255,18728220,18739185,18750150,18761115,18772080,18783045,18794010,18804975,18815940,18826905,18837870,18848835,18859800,18870765,18881730,18892695,18903660,18914625,18925590,18936555,18947520,18958485,18969450,18980415,18991380,19002345,19013310,19024275,19035240,19046205,19057170,19068135,19079100,19090065,19101030,19111995,19122960,19133925,19144890,19155855,19166820,19177785,19188750,19199715,19210680,19221645,19232610,19243575,19254540,19265505,19276470,19287435,19298400,19309365,19320330,19331295,19342260,19353225,19364190,19375155,19386120,19397085,19408050,19419015,19429980,19440945,19451910,19462875,19473840,19484805,19495770,19506735,19517700,19528665,19539630,19550595,19561560,19572525,19583490,19594455,19605420,19616385,19627350,19638315,19649280,19660245,19671210,19682175,19693140,19704105,19715070,19726035,19737000,19747965,19758930,19769895,19780860,19791825,19802790,19813755,19824720,19835685,19846650,19857615,19868580,19879545,19890510,19901475,19912440,19923405,19934370,19945335,19956300,19967265,19978230,19989195,20000160,20011125,20022090,20033055,20044020,20054985,20065950,20076915,20087880,20098845,20109810,20120775,20131740,20142705,20153670,20164635,20175600,20186565,20197530,20208495,20219460,20230425,20241390,20252355,20263320,20274285,20285250,20296215,20307180,20318145,20329110,20340075,20351040,20362005,20372970,20383935,20394900,20405865,20416830,20427795,20438760,20449725,20460690,20471655,20482620,20493585,20504550,20515515,20526480,20537445,20548410,20559375,20570340,20581305,20592270,20603235,20614200,20625165,20636130,20647095,20658060,20669025,20679990,20690955,20701920,20712885,20723850,20734815,20745780,20756745,20767710,20778675,20789640,20800605,20811570,20822535,20833500,20844465,20855430,20866395,20877360,20888325,20899290,20910255,20921220,20932185,20943150,20954115,20965080,20976045,20987010,20997975,21008940,21019905,21030870,21041835,21052800,21063765,21074730,21085695,21096660,21107625,21118590,21129555,21140520,21151485,21162450,21173415,21184380,21195345,21206310,21217275,21228240,21239205,21250170,21261135,21272100,21283065,21294030,21304995,21315960,21326925,21337890,21348855,21359820,21370785,21381750,21392715,21403680,21414645,21425610,21436575,21447540,21458505,21469470,21480435,21491400,21502365,21513330,21524295,21535260,21546225,21557190,21568155,21579120,21590085,21601050,21612015,21622980,21633945,21644910,21655875,21666840,21677805,21688770,21699735,21710700,21721665,21732630,21743595,21754560,21765525,21776490,21787455,21798420,21809385,21820350,21831315,21842280,21853245,21864210,21875175,21886140,21897105,21908070,21919035,21930000],"blockHashes":["0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3","0x83227dbd864567a72712bf12f58b3998ddeeb77744978bde3bc0f21fc7dafbe8","0x912b473d9816d8228421b91311839c4f1b023bb33a17ba3fe7279f915821dd49","0x6492c40f133cac0bb7c1c179db9434c3a383d90fc644d71d1fd52e094d800189","0xde63303e6f9e8522325e1312087c12072131e7e0ae32027d6885a5f84b6bc09e","0xfa57aa0a4a2b4b5077f420bbb9f1abcfaaa3ee42293cea56ea4ad9df308c1be8","0xf0969986e0ceb402175d75f8f17736d00bfaa279d3f8625523ab992c6691bd25","0xc9000883d09d3ecd0651081925859aa6925ca69ca3f0dcca443a45d38b4df358","0xb418b7ac9ac7392678ca03b54bd85a7afb4425b26687037df9a7ab6dd93f49e1","0x3ad928b3040ba3922132a36396e33072432c8f92a94a538214daa6ba60432299","0xbd5683e1eba72c1eed4ad4fd6c3137e340bc4ccf1da6b3c90b541f46c0a8197a","0x8cdd42e577a738aa6d22fae1463fca7d94962eac7528c3fc05a90f062fcdc590","0xbf25fea185254ff380d564594caebcf59cbeb93971cf8c31b1b1d246c12ee2f6","0x29cb6b6e32a7f3dfb7d82ed5407caa422e01179b332c21c4758229df73c8bb4f","0xfb178ecad03f29112c8ec4a99dd4a67e2f5e79908314208fade693a332a63dc9","0x043fd7bda65dcef9641b03ecdabea5e8eb0e61d9bdcaf32a758d0429aedf8630","0x68fd4714849c5021a062b229938c2b150c2b49fb3ce81d3e767f80f931591204","0xc9edb3c95dcc7964d5b542531b49d6ab977ea30c341e14be52259d99e7411e59","0x4d9c798b06ba9d06214f2dc19f3ba3ffcaef246e4acb198254d9bd5a723d4d6d","0xf6aaf93f34d25bd3718fb15cfa15139327ab87f81c2a8734b89b1472ea1554c1","0xdc6ea9c81f393cb34aefa8331d26171edbab83f48c70e287aa99e4041b233428","0x7e29ccab38bd15ca29a039c2cec2cbad2fb0928d2bcc431f76a042d63af08b83","0x0fa327a1b017706660eeef94217f53d323d54b66f60588ecf72b552f9ea4cd00","0xe3b65d05f1e629c674dc365fc1b49d712f9c5c19c2775f5afcd3bfda1e47aa2e","0x268135ad8e2dd63029c19fcf936f3346a44611e46519ae96d61293d663dd1a43","0xbd916c150b51da5cecb78c66e6468a47ffb49fbe939eaba5dbb2c4da4255cb12","0x13f56d8c53a771fc715545bbbcb9e58730c7ad50dfa5d8da7031669a171c7bc0","0xb7e3b57306d24656bdf66c2024501c6b08d2cf58b32905c378a6bf5e30db64df","0x1ade7e40144179707c7498a5bd41325297b2aa5710990eae39b50547946bb6d0","0xd2d4436b871937515e59ae698e4681418e0ce01d1cabd761f083b9aa654032b2","0x180791cbe96fe7386d6236b2a5e05f4b7086399c60f69dd9488238492edeea7b","0x6bcf8493ca297e4b5aea4719f4dcece4cbdfe2dbfed6227b361321341123a55a","0x722c7b24714ff079d739d4ba27a1731af14868b740dd76fcee9699d33fedffb4","0xc1bd93e8499ddeb27343d4e58f528e6410e62e5afad312f01775a3a85e7bba16","0x69d6ee42d3619f622a891ac4cb11e192e434964a698d881c5b5905ee79663dbf","0x85e08bde473e82bab0b67f0e619bee658dda6bb49616361f691374fafc81665f","0x7d8e0cd575d7baaad167a471d388cddb9d67e158c271e3048e0edc297724bd9d","0x82120575dbb0eb1893b77aebd9e3bc65980289f55ad0da51ddb30409cdfaf0c8","0xb8793c62334bde8bbfed7e4740f0a9d4967d42b6cb73fdc934be3a681bf12ba9","0x5bb5347181e34a4e785cc96e49d195665dbfb7e9999ee13edcf1bea01be468e2","0x85913b756978796b5e155399d668aa3eea8adf03d08f83c57ade96185b7ecde8","0x00b9e835b7cba2149217cacfcc1ddcfb343a581edb2e76cccfd0b659838d4c4e","0xc4bdb43262f246d82d2ebe8efe7ce253e708ede04fb015d07c20fc386b15f2fe","0xd3fa41dc6a0b3d41e2aafb38c11398551233bb77f31eadc247db887fe7bc7f0b","0x556a5f3b95715d0fa104284c986de65a9315900e77badffbbf9e740ec11ca5af","0x06f43c7204475fedfa4af294c4f16840db56eb9a0d76213b6bafb17a869ffe62","0x33c34ed64bb543275df9e1c5d7b7d8d8ce83bb9e70414947ff605debcc20406a","0xf3481ab9554f22de8fb902b0f8359c2a82122d8c4b1da370f9e6e299b33f5c75","0x30629d6270b1edcaf146e4eb2709c93bfd4d75de400a87cf599e19df21142c47","0xe706da2e89b02b9c25913d2264a0a9953fb378ec8e8b88ff11f7d09c2096d147","0xfc73c67d849517cfa637c1e2cb7b4f8c9af9c9e0022d728c8e048af222d9511c","0x222f25a2a24a08fa9f9474aac4f2c246b9f62214d89e0b39887be3759c8c7fbd","0x3fc6a5a61122ac490d77401c1924ef772e54f3fdf9f6e5233961a8cdeb68ec73","0x6e36ae0d017277b596df8a6efa63e1c596e721275870b05ae233ceefe17cb06b","0x51d8f8fcb04156211a5722b9400a72f2bde549ec09344bba8e235ac8e39c0d1c","0x77df665df59be84200d419c1686c055aca862a510787ab7ad895dff568a69d09","0x3712fa5c426d99145e56f5e0bc14e80dc36e73c71f7e2817137792f7cbb66aab","0xe57e50d7ef79c3152b507b11d95fd95f20672ca4a7fb98941c06591e6a188226","0x48776e03c21e490a0863df8f6687bc03eaf4991d112a3c2f99b7d773f38db932","0x837da5eadea76e73e0565b868336b999be061f43bb8222d310f7b0f1db40daa6","0xbadfd3fb137fe24e2221afcc9f1b8cab773439095bc694f629e681d3411a1876","0xb6afe94e8984608356471a1e7aeadc3ff0439fa9f70393918c801fbc34d9095f","0xc3126aba584e4b8e924ca485f8770b86ecb00cc64a7efe04d6e6851cef77102a","0x168c237cf0fed96aa9ce8e39802186ac3f608a5635bf43f7e97b29196b46edca","0x09cee82e04dd2795214d62547a9ffbdb1b00377c8e46fe0aa30a93e4b95a92df","0x47ed031744d4b8247c75d4f5799fb627212687e545eacda624fbe731d1ded8c8","0xe153e1dac15f569458931e4f8d3bc27d489e0af4efe1354ff454f33b2e0726c0","0x4a1328ddf8af70154879a5271ec036b9f52591665ea7efd2a6eee51f9e3becf2","0x3cd36d88f2efcda6870815c446e1e047075718ae7a70e9d3e7ae83a050ff0d86","0x12cdf99e7fe3f247ef93fda55b8f8331d43b7bb545605c598dea71036ea4d4b0","0x458b839b6119fbab883a8ed578f7c4f522961cdf5d25f1a43cdf520417bdcde0","0x9c5613690e2b497365184f417fc97b3e894ab7d6d9fa00a9951bab4834da866e","0x52ba41373f816325421ebf2a2cc7eab29ae9f2a9ba49ac83195533a843424f6b","0x5bbab190cba0fcef4469aed605882b7cc3e9f5af5ffc5c210bdfeb3dbb7feb3b","0x9e132385f40f6cccf86c74dc577d0800339ecb341463f38da73695663f2a1986","0x79038d6072b4f466ad22e68a93cc6db9bbfdf181216bfa75ec82df3b77d5743c","0x2124b6bb1567225d552190a3e1275801556e611d5dec8826116cf74cc1945580","0x46cb726d5a768dc1433ac0a62b4a356257712daca1b8b0bce375a2c4aa845c05","0xf0b6ab3013139438c5a503362802e45d813beb5619d064357431172fa419bd25","0x2df10b2e03f83efe5eecb3ee00345bcea52617a047fbdff8aa7b5587b883e4a6","0x1146af18bac3dd9a3bfa8adc19e49efdb1cfa0f4ce4ceb761ec35ba627ef56e0","0xb48126f5d82a8ea3b6cc5bb5d793520d52fbc3f810bc98e121f6b0d35fc1b51b","0xae55ce5582a27c9c53d18142641d3e64370a6211937d55c63f83a99240039925","0xa5821da43931c54fe012bee97d60f0bb27a43e81a0e66b6f4efe79bd0e560d22","0x52d2140c0f18c228dc30341414711f8b6c15af4d83a89b3e6273653f15575c56","0xeb632a4ad8d66da8b5ee692154cc82d00e325657ead72561f862369edbab8cbf","0xfac2141f7bafe4d76e9b4e3c4278c91388ea5d3e535557c5d539649215d57b09","0xaee885368d0df8d68bd6bb0916989fdfdaeb93b948183120f05508cbbf480bec","0xcde1f3ecbd1734272afad1b46e14d6d5f4240f7a7eef48acf3c232a6dfd32ecc","0x300bcd91f539b7f2d7f2222eef0dd335eac3160b44f30465a8a477a30c6037e2","0x57b911f67ec4d327604004791bb8a744e6be26f2470998327411ce142a9bb01c","0x16b5d77aa5ecb080b517eadca9125eb5ff79c2ef0486065f1a704d27b555e7c7","0xff2895e24d8f92c12556a1c6e97a2e3030b78aa29fe961c169a2944c78d6a4af","0xc0f8e7ad94c2b6a3fb5cc5b911a4a10e7ef45a98b949ee57c1f016722ff40e30","0xbf6674c77d0d7d12d3db9b9be9d22889ce77e2428c07d522f70ec2445f81e1ec","0xe27dc8dc657bfa55491760e02e75bae8a8a514719c2a4a1d93a6856f4a5f8a7f","0xee94e39020eda225a49567a2777f4b2b6dbe28bebf2b76a113ca23d5bb89d269","0x0555e9df749b4facec7bf2bb1f604a1ebd38ba20a8ff0411b5003d6c3a7562af","0x79576e0dc239a55ec34eaf38b8c571b5d7d56fe56e95da87f97b971a2bf3e2f0","0xbd8c5319815e033c51b36a68637537f5f83bc936ca7410407b1b5bdaff4e54ec","0x2e46b6d0b96637364dbadb4ee1c753160b319aa9e8640033f0c29f9848a78721","0xb6c4c2e39554c8e86b571d4e39700743302344f959f110f462b50bc2661391f4","0x1dba1aa914a99bb85a7a38192f909141406cb497645401ec7f84b3fc8a3d11c6","0xa89c18f90e1c3dadfabfe476de8f7eb94e5bd19898899c0c20c2c1ce19170256","0x0b917d8fc0fc523339faf93308bfeec3b8dfd37d1973e9dc1e6d811359d2c531","0x5fb1051562258120d494c162e27bf7cf705275c3b80f168d41f82fed95a3dee1","0x87ea75561d3e445bacdd7e248775520e1a5d526e5687a3e744b74fc6fa5c6b17","0x07eadb70b4d6e61d753be6215791f30696e27a67c96bf032d7263acadc6f7572","0xc5d0dbdcc2b1c9b5e793adba639dd337594a5dd62ea4a271949f732af7275c20","0x51f769d1794d8219531a5085fef9b15a253e4473cfffd91c1987aa9f39398b93","0xa0f674d29fc635ff6abcd86afdbb576439168fa75487b370c353466cbeed58f4","0x25b8f440a7a2ff8181478ffdac1a4d132028d7583c337f39aa47e457d9b812eb","0x3c8212c7c446f4d2b1ff9ba18fa5eeaecff87cac1fa5ba558af72513916dba70","0x1a65dd7a0e93226af1c1f468f9efb3daf2fa97ccdcedaab1a2df3c3cce92b34b","0xe90e8ac799af6edb9d948d353e1446da7feda3f7ff7cb636a27cacaa0fceb7f0","0x62c2c39abbd38b6c2d95ef2bc840bfd7487f2183512d722d6e1fc51e8cd7dbbd","0x60ddf229a5a6fff0c54fc7d3d441b79aae445335e55fa9de960eabad22be0e0a","0xf4edb0eda566442fa39876ba9c38bb98b929a0496482771570d25aa2334057c4","0x6a2e6e8a9fbe25b0e997037dbcab9f2e73665c41219cbb79f94f1d9774bbe671","0xb10c87cdaa13717d853da2a2b7c81c9faedf76c7ade8021969af2022d5fcd553","0xfd236b9ea6cf8b61442e19617f7474f3ec9b0aad155962b576a601b0fa20e013","0x9a46c101d1cc7d2fabaacb3040ce36d9e89a18aa7b936334276f88e5e7c36ab8","0x33b792fccefaf085ca8a8be56681c03c43b5137e648ced4789ff0d062414dd86","0x9e20106f4f287dffbd5cdbdb5fd452631787d9585b4973800ee90e58a62ac468","0x973969d2f2efd0fa7b94443db1f759957135a23024cd610087b1342ac94a479b","0xbd61a037f3395c11eca3bdb8322170ba81121a34b1929a7867a8225340a115fc","0x5c9d7c534f55a292eb6d3b6d037f5046246de91863f1174c8154d7caa838cf8f","0xdbaeff64fdc13ac0a3b97891fcd8cf856582ee7aad02521eca9ec3ff5e99d571","0xfe1d23fca4e93790b1ad6895d014734918891fb42af1c036a686e22b1455d923","0x6426b6e733fab9a7a8e66ef31546ead0e800f2e94448f3e1c12ff407f6037fb1","0x5b34398025209dfc9d4bd2025c79c67e7a807f4a71903b203cc122d51d8e8cea","0x7e1cc05a2a563ffde15afbed5a721dfdd8ff09871d7e472cb09de7a569489964","0x724861998c9ec8c18b2c61b606699bf0f812e6dbc4c2d97f5c04f59e576e7a69","0x1728d61efce368b9218a1a7fa5e82209941be01a2b6170108b557fd427425e12","0x2603da7670328ad8304e9ab7b065e0e2b4e6eedce27683091affed393bb26460","0xf7a862865d0d7528b5e2bc986c5b6e2671c5d0795d1408ce9649c3325cc51a5a","0xda5a921c44bc4cf089251de5aea823f965a1271366399b4e3b4770222824c7a7","0x881364d25cf169514c6608c01edde62b30d92d13eb6a6c5dfbe06e89cdacd57d","0x2c0080ba2975091d249eff09f0b054d8d3766e3d40d40d821669460f9df03cf4","0xa5a002e5fddb8956c6fd9aee1c70dca55fdebb54fc829fefc51fc53748983971","0x8a906c231122259f088a120c0cd66740f3539c7594a600dbd4fb31a1acc63114","0xdceb94e51b29e7211d62e14cf5625e130d57e1ea5e42d41feef469af083e57ec","0x7d348b03a6968e531e4612294700dda7b1353bdec357bf29740f0875be8da4e7","0x9279e736b9ec93ca9f290eb50d3d917b33771f0c560289c6cae8fe4eccce3d42","0xe10e81647a94e5223e1ddd2a6be74d96cf1aca968f1b8437b5beb86439ef56d8","0xc73653624bf8dafa4922c2e643255ced2123ae2532fefbabcdc6dc353ffd5378","0xdadf72c4f0c0f2f2f493a64e7a87feb856c3415cb6e869f06f820b503c05f475","0x34bd5fab49358f11b78eb73911496d183446cc9422f8146192df773c5e4e9ea1","0x14d9e009ac1d503af77058746bfc5d906253e86a055dbbb0c21563f588c6b57b","0x8c0978139b4dc49a63ce498d11e20febe34b7f6be66acaa40443a914aa5788f2","0xaa64d0aaf444b1c88dfa37e2dfb6dc3746e023ff2bd3089fd6a1d573281c5dfd","0xa6f7219b93eb787d21eef4c89da27490a35af5746daefc3d69ad85969b731758","0xad383559053f0d0ed3cecb519e9d96f43acb11f9f59594a534c2488f6268389c","0x44cdda9af7b037739979706d8466d3ea0e06952a5d555ca6df672e9b3bb29e5d","0xa4ea8a9908cad0c5319d34de330ecb9a1ade4f4d9a6e84f5b1ec830675d40a12","0x38090cf903b7973cc7de69d6ec5ea6aa78212d1f52ab44bfd4873071b78175c0","0x2b75deaef097493a45df53a28b1adb66da18070549db4ebdba5562bd6aa9044d","0x3b9554a75fa804b95e4b3f913f483d9fca243814c906e6fabc9b28530482745f","0x75639c7f02d472a9d92f06ae0bf833b1b27028809deb258697d1421fcfef08c2","0x7b479911397a14112927904cdcaed23d139d254065b20e773a91a4612c4cf06b","0xe6c341c1edd3a6c069a19694ad212ede7dfb059666ad35db74f68f5cf16bb1b2","0x13646b69383ec42ccdcd0dac84cbe30761db29185464669e1c98294330946646","0x28f956eb62b84edb67ed1fde42391f8cc473a7e9d6db215a9081798d7009e44b","0x17c7e227b1dba102a4fd022085520abf9748f48e20885a308e7e82248d0f5c0b","0x11a413c0079d68b0555b2691f67a63d85749ed4f8d71f5b5d30a1cab6d665c27","0x82552ee44933e3061ef4ab9551dd9dc1ca79670bee3ecad81de931b42702e294","0xcf098070ad59c2d7a07605f9c1e7ffcd6d1b3c65db88813c17750fbe75fd2308","0xa2351a384cbb137618a102bbdefb8144b90a27d172a26b4f39dbcd8129b98b4d","0x9479a9129f4540e909b063f28280afb4972e5a6b856215ecdad5a821b01eab87","0xa0676bdbb7a1df8057b3cb70945ebbedb58a588fe8d9ac3bd58d18a9e172c858","0xa9a5790ee9ead7fc84c56bf1d2a3b24f603007d35f6f78791e817d38785b5ae5","0x71f90ec192e772da5ad3c0eadacb69f7e737ac203fd2e170d27e1262a6f53282","0xaeab8e7d7a7692c05ff0c6e3aa5bae1df0fa553bd630040e5e1034b7524d5f1c","0x56a00fa0b948c4528fb22e41c7b0dbac3aa8f474c9b797e7410eb302e695938e","0xc3bb281fb787a82690475c611ecf4a3503c60ba604b04411992da7240a2d961d","0x68a32cbf86581deb36936a435d6c047ecc57ed58c065626b6c5594aaeea297f4","0xe600d11a7c4c62a4acf0d063d9ce309165e74dc81dfc59265a410594b2a09412","0x00dd5480f9b45fa5b312188dbf73f022a59703fe1aec2fb57be231fb26590443","0x3c342204833d8a1fbc8385592408dcbaf7b01cf646241c9636c2d204dc66f85f","0x71e30a5480575eff3b970664c6281abcb5264a25eb93da7f08d3e5f1b7b54ee4","0x83d7787032384911f9e55cb21a92e0efa9a4259221afc94d8c8660de56024cad","0x78812c0daa38084400eac387779486fbbf4cfd0a94ca8e394badd346dfafdfd0","0xf05f0cbd5a11b2cb95c8eeb41b469687b27cb7c5a7f68470a0129a0cba9e701e","0x195c1772121056e51fc16f12c3ef948bf4dfd6bb86c83497736a146a1ad6cb28","0x607b635662c939c83990260d0832328c99b77aaf7c4425cbf20909e567a05191","0xaf674b5dc3954f2ea955e7f465814fe85874a8d6f6935663814259b3191e5cc2","0x9e56795506a9cf1fc6e539929c11e3e8c51d8acb21a6695c90a7f98883d3934d","0x24ccf5ef9c12526cac8f5dc046364dad886fe9472d75f81d2e3b8913f5a01583","0xc6a500693481ca6a7b3cb7f97dc7d0f7e2c3cdc6753d7384826ac8be6509a657","0x312c37cef94725798835d8489ff7de337a1c3ee75234c84db81a9e4b04aabc32","0xb2de5e1dd16bd809cdf9bcc1a13c49ddbeb1c0f4c713db66c899b52cc007acd3","0xf3dd4029ecd91edadb0b5a9587b0847adf0d983bd57a48fa90076759918ba955","0x923a9ebaa191c2987010830e8703d8687c2f7d824185d3ee75ea44f717654bd3","0x30bda956c80180b9eca21eca8d0dfd50ec6b714d7e13589dc7a4b1c6d4d46dd7","0x9976febcc7caab07c775a0263aa0c0a0e411b4276da8ea169e5e19a6b5c0504b","0xdea781ab4c4c013045a918b23e2ea13d53f6580ab0dfa89c65ab247c46b48ff2","0x2c5a833ade1fcaa3ac2b092845608b7768c24ef50d51225e140a9f39aa923676","0xed68beaa622e806f73c8e0bae394de3cf4f146a706f1bc565ff1b19730f2f948","0x2b4cb171185e85337bb0fcda2e87c85b771abae9167ebbe0332f3bad2e0a790b","0x1839cf8a6239894fa7e785bcc60eedceae4d9be517146c3f5b5f45ad2e92fecd","0x5966effdbc328d56bedc60c102be954cd31e5dcd5944c6dcce50851f3d6e87e6","0x2199afa30fb07e66c2985f81a3a28cf67bb34e3eae82fa40af6c728af85d6f01","0x7033ead211fddf0b0fb3b645d8d7c03da7194566f7b985ae3b9a9ebaea31b2ad","0x9bea12f37559706422d5f5771aec8452fce1506aa6532c094f494e9a0b8abcc7","0x22a350f5f0fd4e5c9ce4dd725c578ecbd5b46b41a9a38e7ecbe5fb0fb990cc33","0xb1137a931f8c193b0c13ff22e8e45777f6e8614eec22e3a26cd53a42e2e2926b","0x04c5faec727ef9157c0be846b43a5bd4b8daee34903c85d5a708491e36c5db0a","0x62d916a1599eec73e812876105423c5c384ddd928546a7f7619b2e8488639cce","0x9d711a7c38267beba116e900c181ae14942f33961e80460988c80886b8102b83","0x89af9d56da38a5257892a1f69b43fb5b6dea28089772110beef583ae57278498","0x77e4855b1e131213e22b6351d5ecd653e7810fb09930c0be6888c8c9149098e5","0xe2c3338344da9d10270f66b3af5bd229abc71472b4da4dda9db1a1d8e4a9f5ee","0x9801ae5f9cef229d6d9ff069053cc8e82f6fdd68acacfb64658f43f656ac853f","0x5baf8f28e17b18fe0154586f02f95b69f00dd5cd686678981a23ae5f0a01ea76","0x911dcf284a23959bd14215dac24d35528b3944f813fc8c45009edc3bc84abeb1","0x32b7dc827f105a5c59231123951d535434e85ef07a8bc510fee23daa6d7a0a7b","0xd248c07dbbb15fa93280b700b5686e0f18ac8126917b9b763c8dedd74669c38a","0xd46fbe14047e5d2970f0cb82e4a166eaeb596aabff0775057184353c1f0ea0b9","0x7bdd686dff839be0b1d182fa5d7bed784dae6f5f5240e15c9e1329f840663c3c","0x1400940fc7f8594b98ae7e32465d516e6fc841e05039f465efd8c285975b14ec","0x597dfbf5b087d7dbdc1f498324af6dd69dd2727940470bb62cc7187b661d16bb","0x047def5f2aabac221dc6664ada5554aa90954885059ae41780b0e23106756a51","0x9965fadffcdf930e99e7f5cd46c3f066d0ec7b059e74b3d41703599c31b05988","0xa8e5c27263590cb361a5fbf8f900659c9b52c8295a2e5c556aa9bdcbbfdeca8f","0xc97093c4a4d607ad067aedeed2c2c5076e9fb35641956ea3c22ad78a55881e04","0x0245c16b2298f908eb503dd9cb8d4f61239b0cbef96d0ff4edfa8c41a4b2b86c","0x7695cc1da5aa5871ebbbb087d3456ef8de1cd44dfa5a7ab9506dcc89aed74948","0xba9a431c8a0dff961ede934c802449f7bf305418e892a338d5bb47c657d4245a","0x7132c92c158e5e91763c6cccbddccbf68b9670bffb50c3ef72cede8f4df04db7","0xa3abde16365f73274ab68f70f2882d87f9d0f34cf0cd483d663195c1a4e60673","0xe974c234b082b1444c6f461469c72ea0f20dd8cbfe44a7a714a3bb805390b6bb","0x24e573679ea9a1a6ec9a845c470499ecbfee24c06294251bafa854e597cd96ae","0xd5b7954040215a9cd83d8366d7f151b8e5be27551b8f979e681177ae20f9db1b","0xb44da9a163a1ea399c3c4d226160713fb401590089f6eee333c9f6c85855c955","0xd3ad8eecc200708209172cb5ccd8c2646c8e56bc8aef5283a13c8a02d05e03f1","0x88f268d6ee0a99126d1db08fc8dd7935bf54728965358e670fb9faad12a0d787","0xa354c1fb13999fbe8154e11fb5493b0a5378b84f4729627ba15e6ec5250cc107","0xd75dd4971817e89b9d624d9b0e8714da81be3e9c1a546daa6fc08edd7e002d48","0x0a4fd233201b86400a12afb816f21d1f191fee5e3fbbf28e46bcf06caf120d9b","0x782e6faf21a703a226e8e90d03833beb829670c85fb242304c3f2478e4eb8635","0xa140ad315af0878cf688fec8e85440aad6897f59eacc4ab5bf268e5740599199","0x8314e159a2a4087d667b1a3c6aa17eefffe36fbfbd233d0aadcf2bc61f054e64","0xecdce41d5814fa27f0382563fe6dfec6c33d64843dcf5552bd6152dc95de40fa","0xbdc1cf5f1725e773cc0c9a5827437987e63d05bb580b6c2ed421f429ca54164d","0x7758ba74c52a4426c8f6cc17dcc74518bff9fcf8b033a82403c9581851d79e28","0x411a1a3715794123a64158f55e53d42f525a31bb71719bdcbf892481d7fdee61","0x6111cad188f9cce66f56dd3623eec0a8308939e6c704de07fa399af0816e27d4","0x3ecb4b37081c3dabfe50357e02df0d88311843d6b12b784e1e732c99887b7f77","0x49fb31411a2cdbb7de75ea2722d6778d3a1b52d32437a4fa4be4f45f131bfde3","0x89597fe8117452072e7465119cb44da30f1de56e5520c2949d9aa52c65076c62","0x7c92d3f307bad8138a57e3d467d742aad85ab8d728a9c832fddfc3da55dfcaba","0x0c63d0caaa6a13ea8e63922b03ee84fc8b136f3304527ec8ca89d1620f607ae9","0x45f03af717aceb3a70befeb1f3a30bd1e89ed5f56333ff7ee3dd89bbe9bfd279","0x546ff5eb3c5c9c37fb49cb1f58299617eefd9a34c1c04c04f47b871111e75146","0x7c3566321ab7574be40d8c3cd17ff1b4f3477fa7486ac501548bb8427a7db537","0x5b74c0a0287a553484de0e92e196e489c6e9db1273edc2f7e99e154edb0a32e6","0xfaf2141115bd1d9feaf27e23d994cdc94914fb5ef0fec2ba174c1938f955d1e6","0xa393dfabaedef822151c750bbcae6d3e47f4ebda55ffbc64a2b08506daba66f0","0x3fb2e18559060311f09210d173f6e2d5496a1e776c22f7016312d664fb3b23c8","0xf6443831a0a36b9fcd371bd9bab4cf3e315d1840eeab476ec3c3b18abf6ca997","0xb97c819069b2a2b4a577193964cc726ce911b9e3715d56c71f765617b4b1e697","0x22074ee5d24b79e8ddb040e177e6ae9caa699d5bede0ae34bbbabbfe16118b85","0x206a8a664c2d026e5301accac15cf1a12b623da1cd16dbccb0557152a076279d","0x00bfa5899131508850ed7c314a12620534b185a3416e3beb30dd462386ea5ca9","0xfed1ce53b924c5adee187da1ca3bb46762db7c5ed3c9f0caeae313b3280dc8d4","0x06aa46578dd9a997ccaba4d8a76da07ddbc90bacb9a9f53deaddbf2f374e15f6","0x50532f61e930a4c495888776a6dba1df330886daef0af7f5c568415f1fe792fa","0x06f271bc3298acba76e5526ce2cb229ba503256f90098dcee53cd25d83cf91df","0x3b3621f8af3fa89b959f02654ff76d9c4419011de6848ce856b228f85d5e4dd6","0xd37def227e4feb01c3bd08fefee0421a16f1913f81ed985291f931d32ccf803f","0x192a8f1855884ea577830d9514e094d16ea452220757acecb43780731786c850","0x09cbd0c86898c404a7b947678aeadeed1dbef3733fbab7e7b3fd7b0ea24ba9a5","0xf31e6a8e8c5fe051da89b328b1c6e6e505850bb327762d98012ee2625dcb94a4","0x1bfd5ca049b0565235c734e38ef65f7fc9c072b3ba18231a8bf6fee259665a92","0x4fb5c98b968ba936b7c7f2f190692ce652a0bbc50e3894d32df5a3ea0ab8f5cf","0x98e61bee9d4697ce9340bf97fedfe84133ff2c8bdf9f4664adfeb31a60456b6d","0x26490e7c5250b2f8ecdc243d3b6ba7020062cf02577c40c528db365af19e90cf","0x1c5bdb06c7deb61136edb737acd2a2c01240944914569fb0d9299bafdaa51b5d","0xe23e6fe7c803ca6f574f257e85db682274074532d7634d45c3b7a76dd85409a0","0x5a40e1be2cf0d2f7e5a79d75eef53eb7e02097037691b155924a790261eab4c2","0x62ffcf3704638302517265bc28678b98eb5a43fbb5655240d141a76b60b22c40","0xc350e8e54fb46631332e59c52c8b567ce41715089a19a4e18e8636b27ad6cf16","0xb4ff355e098ccd6b92018404680c00421805ba5aae69ae3111c9ac8513d7d141","0xd3fd9717676c57a15dd31d285c2506988f2f0fdb6c210a3e96cb99dc6f93b340","0xda3bf7f6f6465b9832a1d5a52e3dfff236e6a0f9f094286e392f57cc08544c6f","0x7b4b378b5841b85da84b759654642e865c546018a9877ad568a5ae2a382aebeb","0xd8bc6556a1607eeb449c28d675d066c3bdafe1a13f771c69f0a3996a98f65151","0x87324c3959bbf11f1133b6d4ed83f171a057661d56655606145249775dcea390","0xda5a2971ef30d0868664c1c236d11540b8d6147ae042eb6634e56ddc65589f9c","0xbb14b621c2dfc535073ceb7df7b6ddfe5effef3f2508e7d72448fabb9fb36b9d","0x3a9255925c30f192a5249cbf0b77962c877a8611a3c985b01a9e82d8b11155c1","0x50093dc67d915312075e981a145fbc90e888b0fa0e31c4de05d50b5d6e4d58ee","0xc199e4955bdfec5ad88ec1dc23e57a641e2e79f9b526e4ca9ea4e1db6aae8c9a","0xd0e612cd45c9d1ff1f17e1ec60bcb80a5e5421ac282cc1fcde5e040eebc6005d","0xc2003b5aa1553af3075b8cb666652a843edfc8ce8344fab9dec4c110dae6413e","0xf5e3f26ee4e580aeb26b15f7f79a2e810486559d4bc818cd7a4505220cc603cb","0xde498791cbd4d2de017639470a539c4f303b22b32a049b0ae9f68c208b8433da","0xfc26231fed384ad9a2176942964b844f294a67364c04cf12d9004b6967529b1c","0x63bf5ea366ca5fc0b94f680998ab1e6eed64c72759c3d81c0d7c57579d09ee43","0xf7489d1a76b54d32a30d67bad209dcf9be1c668fdcd941a26e34490458da6427","0x0e1441a43cc5cbd1704965f7da9153499021f4ac31b24ef5400665451f9ade98","0xab425493e09ad54783625d2c242b21ef291fff6dc04b80fe677e4ed678a5c97b","0xaa8b389bddb87bd90aa9ee8d8613d6aa080ca835f805f3c2fcc134e15e0b6459","0x6df1f1385e22b631884cfb0334b2d726ed6af03d2b0434a810fc858cae1edfac","0x2802e7043c213f9e52fd352c21bc95c9f71df1af2cce12d44196eacab73b4916","0xb454bb033151c2416ff5d0b112594ab4cfb989f17b0de6d9f7c7abe3f6488c08","0x0694fb5f2f35b0d299ac9affeb2c58c839092026b59db520089e831b71fea3e9","0x097302fb0461d2022ab721814ef81aeb295ca713c9be1b521e44c1cf3beb6c18","0x1028d69a4ed54546d839055574d21f9e7f3a4abb222714413dfd0e5332c244d3","0xa60d59de16f0b9e1127e392f449e59649a84ea4539c2e2bcad31781dd1cdeb42","0xdfd0f8151f56e12358540361bff09daff59ffe3998fe9fb1c5c421739a506758","0xbf47d7ec9d2e94c0dafbedac5768216e7a6baef911254604878cc8bb98a7cb2a","0x71b569676c1e992eaa1e568190f7a46ce14c26739b3db44fd3e28f437ac6c660","0xaaf5ad10bbe017415b6d891469a43e399a8d519b1bc2bf68a417e92e8503b65b","0x085a675a73e60894f47fe0a37e9b3be5d1de8aeb6c3762a961bf10bf02952ed1","0x434d5f4d6b2b56e52528a662128fcc49247baca488957915d611429ca4dd1dcf","0x74ca6fae5797f4fd893f7704e22e930b2baad45211b3234c412c828153cebe41","0x7695727b3f171685dd818f1f2d7df9bb660a9ee08dbb2b329661e3fa554e9cea","0x255cc59f46e93786aada36f50a2a5d5c1ef9bcc4e92bedc6a6bb882128b7059b","0xddf107252190cd976db16ac16f28a010f3d7825516bd9f784d2f65469ad0adbd","0x5f90b0221ea76019fc7cb0e3da908cca2a49e23b5215d2b47524de296de977ab","0x3a854968b5e463d80a2befa1f84b5b552539a50af0ecedb09f628469057a517d","0xf08c0c3fbe39d9a8f8695969f4e7e0230deba95f593b103242b5fb48c197b795","0xd3542dc29f6d59b2cc96359f4b21f6f309aedbcf301d7cc5796b7b12a0ad6845","0x3ca02ac518f396869612ab0682e29696154cd9ba2e07938017f9b1d70fedbbf0","0x40aadb0dd4057935f2fd421b84bf24d98c1acbfd61145f766719c87555c30baa","0x7d54ada0891b8f3ca3acda2803c03a02502161b9937f316c9bb00ff79e41ada7","0x31065264bc2d6fd26274958bb6b78734a4eddc85964d290fae9efe43bd981743","0x2600484ac76dce4ed83c1e1d5abdd747ebc96938ca9fcec54f90c87b4d15ed57","0xb2ea6db793987e1e8f3058fb87e4e193f9419cb82a5c981548761527c5774768","0x42e7e5fcaeba947b23ba485137f4dca89cf1ef67d5cbcfc32f38e5b04f46c025","0xd8c36ad17f50ed88cee1476c78e4c713003b92b102637249c2ae8d1fddb76c6d","0xeaf715e56bd835bb99731fdfec4342f09024ed9b7925ff01b2527919e90ce47a","0x87f2571fb27eea2bc19fd3f9e881f91d8fd06d35c40f6a636784776e2960a74e","0xe221c8dd99aadcbd7184cec9a459c42b927d73294b5c301dc9100e8255165dea","0x0aefedd9b6259846f2733e0436ef494366b657157406d92aa561ddfb0ed2683e","0x80d35f934cd0fb51f66245befe53b2681e30349f2cdf39a6683a659d847fe019","0xec4bb573ef2905a9e2d47e20c0f76784acce16a8566640874e25fc209df55e80","0x11f420a0e6a810a7928a90847aa7134e4d59e1865d7cbd0faaf713ea8a886232","0x289b96eb826c1668870f27be825d2dadf67de241dd05e8cbc16a0db40296acc9","0x7f794d611246c4d28ee70c42e54ca60d1539d9e2cab72f370b31e548b70ce275","0x7be21cc7187fd60aeee06313d0c768bbf86cb43080a548dd2c5c7e66cfd50697","0x5403f531d6737d55b7401508201f7036675cd78d98ecf858cc161ac9366336fe","0x199a05fcb9bd2c6c5791e7bdf551ac223dbab82520d172a6b4a9ae57030c63d5","0x54a8a35731a9c58bce2e6a7a017965ca35a2bdd49914c2f48d0edfdfab7ebaa6","0x1031c687bf115828c0690b5197ad3c3775f6d0401d225a82cf4c7a7b888e2cb0","0xa5fc4483dac9eb505e9d8679fe359f55cda384afa7cc77caa639e6b2765121be","0x17fa6d5b02bc65c1002d077b77a78b132531e3155ca4628032456d7fb7c201d1","0xde6c025cef09ed089fc9d6af346d892ea026ac2ec6f12dc8559880b58125426d","0xde16aee51311016b3e4c716bbf1bfd22eac59686ca946bc13fe023ba99680dca","0x391384addab56c4e13ce58a928b21f70a03c9476836fd17f069bc5bc6b0f108f","0x949034e950025f434cda3723fc0891b374eb38024c7c972bbb44266e73b2ca3b","0x07ada8ba16887dc33c93a3cea24480cdf3cbf0ff4f850659bc6db1f894d2e32e","0x432ddc6a11f3092d258a94f7a354c4aa97c56c8713fa83cc45e53eb0d276a861","0xc02bcd0499aeda0b67056d4c0b1e6b217e34c7ef41e583a47fb9c27483f42357","0x188d10dcf2b8394f03714c84eaf683d3aec6e33d3bb50a72460c9016e14cb6ee","0x91186c17dfa17dc4ef549b67f967a6c1fea0b9646367301f045140ec6290edcb","0xbdb63517bdda7e13c8a89be94b29605d9cd413d7d8bed9c8f2ab9ac9596118b1","0x971471f26b128e96788c323add0492bd2d35f09627b12067a64e9e87220d6f22","0xe0eb6d39b6866ade12073aed1dd5717412d4a7a72421fd9558ac125bb514f076","0xe121cd22817a4b7142ed1b311010a9f37a3eed2439755be918812aa4271a75e6","0xecbe4fb0702826726dd780088c2d2cb99a5bf2ae7a2324240d618c43fb8596a4","0x892489105daf6f8d5438040a913893102249cea0e6aaf3d46189217ff54f7e15","0x8c75bcfc93f304774e710204bee1e7cb239b7579625646bba41182af61a95352","0x0ae61fcccf2566e41f9144deec54ac8fa347e2d910874fcd5a3ba553eca6d02b","0xebf9b373c9df96a6fd65db1b54f6d649ebb63468d14f4fe3bbd6763cdb3cdcb2","0xaf57a6dfb03d040fc74a476b5a79fcd1c1e59ee4180e0aa63efaa628e869c6c8","0xe76e2a959949d12b41cca055745873d3aa96e15b44f815f1b7aeb5e67791fbd8","0x23d71a436bc0f685b2f68aa2b0a69e799aca8d518d7b8f18fce1fccb45b0669b","0xce230ed62816821e3143e085b1d2999ca9bafccd0f0fa9398396402cd5652011","0x00b2f50b78620976d0d79ee1bb948dd8f4d44a0232970f44e724aed7b630c003","0x5ccec19b843f9539fdf8fd504609f041243bd6f1e0a9809cba72307fc2081759","0x6d45231346f554e8872b885bb54aa759c1f5723206f85671c60a3fd836b93363","0xccda96da0cf56e32aad46e5f10f8b2fa7422111d37c282630c0e2d3da719ef5f","0xb5e218d4dd9ea2aeca21a5bb32865a450a8c882541905ae7766a0a999b63e2d2","0xb2e1149c37de1cd59f02a090b30a335519345cc755e64629cfbf22eb84241277","0x9497cf501d1f5aaaca743544f43707067630eed2b942fff75ec220ee70fd32bd","0xda188516d816b7e57b6fdcb91a54d40bb78eb3b99eefd73b878a22408410534d","0xc88b9088536ee65e7e04451bd1b756697abc111ba0f30cbb4f92b5efc6143b00","0x7c4a3ca02a97f8daf7e4d8bbc611bf30810781b1e06fc4cbd518247b77707f43","0x4318e5ae71d8fe08a1f57f722b9ddcade84bfa5cb6c6d27168cf0b71b0cd5a45","0xd6a1dac39dca9dfdfb79935437bb2a0b6b881d6a8c0a1a2d1b4f3daf3990934d","0x142d935fe914220241bed584d35cbf80b5d7a61255aee234ae4f008d83b51269","0x50830a66b1673f45f184d0b7537018f936a29ec7592c1dae5f015ff1b33438c9","0x57cf3a1047bd9f67fecec74c802e30ad896f8f50b2bc79ed76dc7e17a06b7362","0xfea9767971c2636891931f2b286ee72b65a8a5c593337f7a3573a493e04bfe87","0x26f4fc0fe324c8f46e7c135ffe1e252ddd204ea18395e916483126cfb7af27d7","0xba69dee211aa06d2aa7fada2e1ea776a8abb5857ec0a5382126432dafbd2184e","0x828fa48d4c85e85c3bd06639f48e4378dd4dcbbe20ab3541e44a63b537dc3215","0xe9ea827a7121c71bd24af44db7afa9cc931c2e0a9a3ea029d4997f3d6725bcc9","0x5c74b7097fc6c9d1c8bfac5b4f91790771fb89507115f9a05faf04fc149aca80","0x93db3e69900892b1bcfd61ca80a06dd7d40cc1b3996aabc046ed6b1399d59928","0xa500bb9c8c78d1d2b469a62137279eebde15ca8d9a72a53bf84deb9628cae418","0x3c9431a11c97cd5f151a17dd93d595d1b3a1e7cc60d0889a88bf7507d1ca9743","0xe3ea157fdd382cc9970f3b6fb6de5ed3834e652d0f481d40efcda9f14fd66746","0xa0d509d1725b27477217b5afbe5048e9b2d3c5051c839aebf6e2292f15686a46","0x9a3a2898092b02843b1393862b096d545caff3444cc6e3bea6615b096a2f51e2","0xd9bf38488ddde3cd6ddd8cfa56cd3de61e11bc88ea8a6f6fdc842f1a873ab531","0x37d152aa0a4b77ccdc78e7add46711cd89fb86b710dcadda0744386406518234","0x2c22a86748317d973322e52c1d800cf92cd4e7be31aa6e04f49e1a266d6c253c","0x954ec32c06d759a21c950a5a5703127ee1f7fcd5863682aab1e2b5f000798eb3","0x146806d5741f3a002a5fd23ae885640c4426352603b91a68143dddce01d5aeb1","0xed4852fbc6ecc07d4afcce4280fe7de208016a6f624452c22460e20a82276198","0x107b02dbaff7bdc58ad915570a3ae2735789e72be040e2c523d6b5ec895ec263","0xc7c2af6687140dae517e4955b1e3654f5469fcbfcd3aef611565260c0d453ee1","0xb655153d8ddaf5e38d981c428823c0ca76d6b8ce3b762e9076c589e15db04ed3","0x521cc7652943bbbc574aa01c7b02312377724fb2b8d8e3ba316beb3f5ff0caf3","0x240b9306df6ffa5382b9bbf628a0f5452a9171250be795088c57475584b3892d","0x150a57e8ab066dc635e7a59ddc6d7a817c41427263ca81ff8ef078a7cdf58791","0x1ac3fc240d4a143b1923feb7f9486b19208e4cf04bccd1130265c213cdf0b444","0xed5a9e1a5ca1c2a4cfb826ec6ffbb8913c1d23f9be1992c0c9a52df983603ea1","0xdac79b205cceccd94044df87b4548cf746df486df9b9f4e7a75b728701a2eaea","0x59c9671c22180d7a734d2d54a5eed1b8e98f96820f2a6e3c81fa481d9255eeb9","0xc6ff16c1a15667b4c1f7dec1cc06bacea2b3b13d129238ea9118a07c1b2da2aa","0x456bf5d002eda6820a8fad3cfc7d50f1c96c9c754a79e5f9272d01793d14842a","0x6122c2006b1d98297509bc639564350afd229c9112da7e62bc0a00b65210db0f","0x0103e96a89784063c99c92de692a1756a5e5ae7945f944d8bf324fef18f14689","0x2771c7738ecb451bafb1f43f21efd0dbd9a9ee4190f76a0068c84cadfad16efb","0x42a8359413462cb20c449311670f8fa07f636a52b1ed9177137e7eab262673b9","0x7d5f7cafec49afb91d905f6a48a97019bcdf96ec87db1af49fb63b1b62836f38","0xc3e63046dfdb8fff58e05b533a0a44a49232e0b732e3df3d90a8f20c3927afb1","0x5d9e9a8dbb099cc487509f22eba32e87c32a4e7e297d6de35f82a0bceecfee39","0xc9bd1abf8f92ed3a69f80963b5d73e489973e8359b23863d2f508caa63095b5b","0x47bb5da604724e2e96f7694c08a189b006a61066c9ff834fdb354ceac6386d80","0xb4cf34c8bb26fa4737c45670d3bef6bb3cfdb7338007002a23210f4704cb7f63","0xcf144f444e4c0bb0760886a655ca96427e5fe782249d3942dda45778d3d3f825","0x84f71c862fddc80db59d59320abb4dd457a8ae85bb0b0b3e9884dd694bfb86d6","0x4bbf4e79aac96ef0adeb34493420c71ef2aaa5d3846ffeb4a038b9c346fb8975","0xa8fa827f55cbd30db12f067b7d17424f21610008883499fef2fd0ef2b7ced959","0xe733bd868fb7bb6ae942996594403ad2919c645dda5aee2a556436cf9499d4ed","0x367f5d2a6dea72ab8ce47d89ccdd21c02402a2a54986487b611b5af967ef2b83","0xbfdee323cd60c2fc3f6527e879e00936327f3aaec960d0abd5565cc0ca29ad56","0xd37b824560c1cc43a05121ed59bb303563c6e4bc17415ae2a424eaf362cf6d6e","0xa886685c5bb57c41763ff6a26f2ff21c57db74ba1d95045384e17cad83382261","0x0ec914fa71edf31bb4863535f142ee980bd0110f0d4fd379102274a43863fcf7","0xc73aac426f8706908565824fedf656eb9a0288b41a56c29bc645f1038f9edee4","0x06de716e0d6d68dfaab92979fda144268369bcc0a718f1d76c7af2a1318200d4","0x6644005f27b0b746ac39ea56f777263063e67cbdfdb07ab5b8318f9ef8fb4aa6","0xb91d33c07f4da2b27d0df54c96df68033ceaa798f5b93966ad14fb04f4e68e13","0x06e6e001371c3e1b9e43d0996d0eddc7f3eca19f7d69591bd15b6227c6bddb80","0x85a5fbc1329872ef94241e896c9c95ba02481dd09510604c97d565a7a38e540e","0xf6c86404cae2e1c5015c3fffe5dc6f2842eb0041f4addda4e995ebda95486f05","0x62843d6c5892d7f2ef8aa3c6966722f0b475c5336fbe0c2f1a1278582db97941","0x70210b739bb31fa915886c2550522cdabc17e66f19564d6ee188c0b42c641d51","0xcd206f1e2c04f32f7fac59a68d35884cbec681de71a066d7abb476ffac967a1e","0x6b832bbac8d6dee7a0a48521d7103db790b7405057ee77a7d5555847f7257786","0xd363d11cbc193fa1a742b29f5b4238ce5725db8f87622023a6d7d104053a3764","0xf45c1703e121737cb7dc440a4dba4306a8311c12c2a8454ad934c409e7efefb2","0x50c19390bb1f9634481c36e84eb3c5ae23214f21bb081aee5d57c007e1543cac","0x4530e84f6389461c3152c36e6751b1a9cebf64220c2a35a5b47f4eaa527025be","0x5d81439c90aa5440cd9977d093acf34afc4f65966b78dd4aabb6db2fd544c7f6","0x28adb7d9bbfb6de8305e7ec46601316db9d194727b139ea692583e27cd48af66","0xc27a4a8383e0e9916f5a01c2b90288f5fbc18b12f7e2af0daa4903c7878ded41","0x5211bd7980e8f653d9d88e175c35fa4362b45a2fd66ec38e35006a4bc27e1350","0xae3182f3fbebe91933c5234733f6eee5adb369a95172aca524e3f85ba011b702","0xfc6ef9285c5befdd42aa08d9dc9153e2f2d54efc6d166e0e63a2a80ed389455d","0xee39f2b3a9ec2607a6e818524897deeb378daac28a072d24cf0b68f677001648","0xad7f79fb99573e838db0811c2cb57e902b11dd501987a4bcc96114276ec4fe05","0x29bbfcad364bdd3041df7a54c8224c334d0b9174b566daff73d1f17425a9db35","0x22a967cacabb4180dc980b548fe7b1dad105e2a8899600a51648b46c3b9b0ec8","0xc6385ae8ebd4a5c3e8e5762dcd29afaca25127d1464dfc03eff8047eb530f458","0xbee0e5de067bf21b7911b05de20e53fa5f6840efa4dc789d9c1b3ad3246603a1","0x64695d7b4505ac4b9ee4297d1e327bdd863a831d3f730abdbdc6744b6f7b2fc6","0x3e50ad93ac4ea02df9276bee70776a211ffe76797ac40a0926595c5d926a85dd","0xe8613efeaf62a6cbe572712fadff56926e3a93cc13ba16a6b90f264c92c078ab","0xbe7930fe61a14581787cf9a85d48debd61cba7ad63b534d0d4dc0596bae09be3","0x4c8d7e1c7ee5c37b8e4be7ad6c770a949605873ac62aaac73be18f0476c45168","0x076b2502375409eed617e5e14b23497d24eea69c81c02179b26d799fe234a292","0x80a22eb89c8c483cdee8d0d3759b7735fd5ad6e12498e540ba4b57c7b7eeb69a","0xf4eaa45f8fa9f84763b286353c4e77227f0f29b77d236c21696c05e0615e832f","0x3357b1d6d05955fe013e38f918bc889e9720370ce9d8742e2e184ae2da057a43","0x81586ef7b87feb7c6a3ad6688158f023e9561e3f66ade8b92970ea462b390bb0","0x95f25935d8ab621eb1e9d2648e28d72ac2821efa55d5c033feaaea6492894191","0xa1da7dcd0b030acff985c48ca82fbd64b57cb09656c0e0dc15b289fa8e93fe38","0x36f4d146fbed5819fa279716174bba013782c6d7d0126a370c9f876f22269d67","0xb07208b0b696004853ec2a5a94c8bc7dfff9d36d00ce7b85e4609edc4702716e","0xb4d0231cd5b278cfe42e38abd1ae12aea243f20e5cf3d054af1521816095b583","0x280b3b2c289be041b6a00b1424ec8588bc944a5aeb4d0366db63bcb5d53c74d9","0xf7d5b217214ab127666bee5370a99d4339b8805dd13bc8eaa9297883dbb54561","0xe8d086e9eaec4af921efe93fdeefc58b8c0be00ba359aeb3a3af0c00ec93dc57","0x517112d53ddb6cff69ff7255fcc9ff56a8ae29fb5dece8c270dfadc8e249676a","0xec28b16d60343e01924b0447e5d27cfaf8a1ebbe6280f081f034da4cae0ba398","0xc7e1cfbeb3281b64beeda6929fa60222a427c173815ec1dbd0cd5d0022894ec8","0x7f696710513ed74e65d00d0080a9e6c45b60d7c51f7c7a4beefd0861c925ebae","0x9107adf99fb7e020fd00cfa932cefeec88956a8d8c7bc48c9e5f847d543e8b55","0x1ab6d064270b1a2c47b8eeb3a8865772663f3f723a4fb1ee17e398ef9ae07c51","0x559e209956642b59ac3a4a967951cb81d8ab54f7f4f8e529918d76cbd5f3beff","0x1835d61d37cba5debcf6ea2c796a94056049ca145f2fc6f65afde249ce6866c7","0x303dd0416d391a574ba1124e73936c75589c523118b15f8f9fd8061083a89ec9","0x3c60f8a61fad184703cc4f8455a24959d44ba31f7b91da05f0703f65932721b2","0x792becd3b181d7b59ed94197f085213d651ca1794a4068aa0da1fad2db95d373","0x3614d358bb155b1f67d84a66a379d69367fa17cc0e955087d67a3c3b389584f4","0xd793e7f67d60df0a941be4bd1248ca094bf80d9c3a195e465528ff85edf02b1b","0x42bcb6e93a596a275cf3c385b06821e3213e21542691dc8a85f383eedcbf48d3","0x562193b84fdf04344b31c913fb117907c21ecf9e6513d19817aa51587842d2cb","0xe3bf1f56adbcea5d83e1d143ff45f752d92816b877033ab54671e9eecf98cbb0","0xd1607557a0d4790caf54667e2016039dea297d1f3c4bb857512b94803d090c52","0x9e1962489ab301a3093aef63b7f4ee53aa26534bedae9109ece71c278d67dc5e","0x3f341fe9c6618718455fc317d8b3c00dfa17b1c10ba5701df6a17d7671ef9361","0x22e3b76f1603ebc28c467b3908df9c5924bfa52df53de5ed352f230e0c71e8d1","0x5c64b9ba28673a70b00d6b25bdb686cd262083ba83f87f2b754ac89d74e9f523","0xd7878ee83ff04e4737e6a6dc62cd8b9860769b6ce97ed496500cfbe7bed63212","0xe28e82f9e23348d7213f931f36263421fe231c5af8aeeb34038d4d03bac34c8c","0x23973f3f91af25fe00cd2fa1e2952fef02bccfc4fcb4b2a37dea656fc84f936f","0x537d4bbd996c258c69f288f74a8a13b2f3a07aab9becf8c1f09b5ee94b7549de","0xc21a323f5500b4a9cc090cad01af0805180cd6c19997d1da9c5b4120ae5a5c2c","0x38d5b9a1bf7cfc24c693e7567777d7bceb9060dfb71635a7a323b8c2f1fbffaa","0xf3096e1fc40f405994b7af52576bd3f0be1fe5aed861d322e73cc18665bf9fe0","0x8d5c8d8b9ac29543b259338708dec1c40752a704d281301341f8c51daf226ad4","0xce3364f21eb6822785cb74a5a835c0aa8c601aef60aed177bc77aecab2d7ee3e","0x7c69977023bca0ea982777a09eaee0569cc6e8f9cdbed05762783c4010959ee8","0xcff3e6614777474909eda810e882b3bd88690839ee71b1b4f1aee152324dd040","0xf3d11e5b976e08e23501718b8111f0d06dac205103df4e807f4a7916dfadbaca","0xd24788a603d7a8ded7007344bd80a6d57959d96d6db8d8f82c4a3e8917971d5a","0x987574f8188e366190ffc885d9c0587670287a0e1200aa6911920fa6f4c430a8","0x51b17c163c48cd89d7312e6dbd84cec17f9b2e39936dbafba3020832fc3ebcfe","0xffae3e7ef61b6f08c58518c510153069780fb10cb8b979e15481af3aa63a2680","0x1f2ed3c01fed476ddf873ef196151ab70a5bd8e30bd273d7c45007320e2458e5","0x6fd4eb4c71abb49a844829b25870eff748182c4ef713771ff8a2f63bbf59767d","0x4de55e79c131d65d8eb0b78d05e2d609bc0144273effcfeabe4fafb212c9b785","0x2215302e2f864155caee3beb0d5b359ef0457f2d1a019a2786c017beebba1a17","0x2654f4020c6f782b4db6c50787b0e3df56f683d560db138355b5fb25df8c1de0","0xbd61b656b83eb33b40e61dce4d9fc3ec9e6cf88da199089ab4279c4e81be916a","0x5896ccc4e513c6d8a6592da00bcce49b9a7381d5635a901d333c281842ea9b87","0x392a9cb9f465f8cccc3ea355f8b9b20b0765f2b1a2b50634484e552c3ad31034","0xf679ef34189b63ddde9ae44fa16a228531554d6595e2fa0efca11a354434fae6","0xbd6f9f4525530cbbccc755f401ca17c450fc4537c615488728aaa2c01b681d38","0x948e76acb6563652c1874649feb225bd8bdb0875a8ae9a0ac571df00863a1008","0xe8154fcd25ab57bbbe75d7e377e97120bb141a1078ad652b83ddb3f9192c6aed","0xbff1ab99e382dd3d794b63076bac5823ee98dd6dd55c9774ab56687fefb97dac","0x7df8670d630b8145cca3ec8aa2cedba53ff18e99100b59a8ce30ab9f2c260843","0xa096436f49dc01728e7b1fff8e8f8b2552b001affc8ca57269e453076b25d526","0x44eba53319d07735ef7950d289ca608a5d0698c3df7ad1d579a42f099a56b41f","0x613cff66580eb9e4a266fbeb42d1573c1dac69d8eeaab03c3ec2f2c50122fe03","0x0664c3076336e950808f78e4046f734a31942dc831cdbe8cf0e85bd93f9b3250","0x468676e8051db28db14d50c042b2a50e09f627b0a3de57f0f1e86335c9709542","0xe7d49549db66ac92149bba0b99f73f5de35a1b90182347ad252013824913ca1d","0x7614dacde94957de97808892c5955dc1a694984eb2b0ad8beb5e95181d3e1a5d","0xf2da428ebee8389d9d1b6ea760ef6e97564d057489cf675f1e2fd84183bcf9a6","0x9a05d58752477dcc0fb20d185cf73c76e98d2979bafd8881be9d4bb205893f3d","0x128a1d8ec38c51fd17e740eea29fc3c32c8957983f3fde6b73a8df18fdf5cb7e","0x846078397e1f1f6ad4130f9e86a35eaf2788556f2068306fa9742f13fef9e7d9","0x3b75b926262ff70c6d6bc904d9ebc86867bc2d67ad3f4e55a88ac1cddf213e64","0xc4fbcf459bb03f05982afe317c7eeb8f837f71e43ab72db96b2d87f65cc8c5c1","0x2c35f0cf736a0e9e22eb28a1f6b7663518aca8f649701f878b21e1519a360d29","0xd0adf624bb6a3417c35ee3fa2e14b2f72c5ca55f87debead0171532fd320ed10","0xbc079b8ecd1003c8a4b74feaa019d889e102cc226de9f8677a6f5c5eb6b6ba53","0xba5cd9f14248487117e0cd8b13ae6c87cf62cec84d5dcbcee1044ab3c7451413","0x11ea8de7f0df3ce215d8afcb92107200ac0c85e1a04339b8396f590a49c12225","0x64a8b34aeadc5d8c8f9927b791323075b063e2edb5da3b142226f161ca7b1920","0x7298ee017f2939eecf06c9a951215be79140a6b6b94da0abc5f6af87645a9c3d","0xfc73423a808254291adbc17e846674775331815c2e5e670c3f163e87ab30d2e4","0x18e30c6f8b3d58691c6e2569b66439509dc48c5de363e8938c5c2237a9604a84","0xef9bfebd231de90b73f1e449b6936a67876a319186b07679298c11b6fd916eba","0xcb7b0ea686074c0b3b1ca134ab777fd21288f6e017e1242d86354731ba834465","0x9cb8f8573b0f000f9019162bb607d3854448acbe95a8b41713adc9e65f1f1fd2","0x7bff0c98ad5fde09157aa00640ee85eb4e12bf7a27c8ee1e0e8d5bee377f0e37","0x2fbb259ee5846e5e72feced587ad271e323589991a3734566c6fc389d7106914","0xd0f1dd1d15180dfe2d7c56c520b0cbd1022c5fd08a55e73e03dd815ae62a2bd0","0x98ca841aeeb0be1ae52fab3009383f4bd6b41534b7a270284a59d91711d9fbf8","0x23edb4128271bbe2a156b34b18d213443ec15e3d58078912182fc2f0c2814ca5","0x276a1896852f048dc04fe4adef00248714baa5c76bc5184a7cccae1e8ebcefab","0x039e593477e72c0ceb72c82b60e41d9f4c092a53f754abecd74b75a999ab3acb","0x915057a5a6f0cb631e42f7005f50995a3a23b88cddc953c215b91f4f844e23ed","0xe659c6fb97c0adc1e39de6cfbe33e620be4838d12b8907d7d187e122bb443697","0x75589abae7a1589f9970cd3d052387f1a2c9ab2bf501bca7fbdbd99938962d3a","0x6810707dea1167d62b2e4a470d730fe7b66594610e2c34596f7cec4a82af7b49","0xbd14e265e4f6fdb508e5d753b437e9d86f4300f46e9c6e6ca54f3806a823780f","0xb046e1193f0874eeaaffd4dea447fddb5c59f3ba7df946f43a842181473a1dad","0xa996f017d63abde03daf7a4e97fe714c184bb8abb393af337cea54be312ed8e6","0x7f61ee7d8e901fe8c199b403f8a0946a1b5f8f860ce071c76613abd85449cd13","0x8c6c88ee2d4f23525d3918064a248ffc470f920cd4327b4163d9cc968879bca6","0x0ded8f5001ae806e4f1dbbaf27a58d37f085e36e07fcef6b992697e675203116","0xe850d18ca6d73c07d05abfbead8a8b7db9e23fbb508f652e7ca839b13ab8fc13","0x7d5aba7259a2e20ffcc9da3ebc341ae49750fa9b14c1304df1bbac4a7819e172","0x8734748e1942675ca23881fd26bfd3a9a3734fdd3a7ed9ab6813ac1fb7f8b285","0xf1474e7e9015bf5ca97337255b377edd617cb3a430c36669299e1ae933da85d5","0x642acc9280ffe23c88655df7114160484301c1fdea15e482c15cb96a61c6da1d","0xabc4a64671789ba461e50e5e5bde7c58b54be2f0828598a707a4f87d51065df5","0xc19dff21563604a385c3128471b869ec91ee42dd476ea3afb59f74867df60f55","0x0c9a9eaf12686e9fb9a70ea31ed417281129536d7565516e4dbc1ffa133ce827","0xed5d56932afd24e9df1f3a2fef8187127833a41f0afc56ed8da4490a6753e657","0x33dd05c3acc9445a20d83a4318df4d63b599dd02da1e02562dd8b652e83b7b81","0x1899867333fe25d5d3c96814109e41f98acaf2e87f7f1f1748bb8efc74dd3847","0xa4f078429a943ca59d6ad79fa72a065c0372b113e35a211c6f21f4c4d1150f9b","0x6623263cfaa8a05afe70eacc3f53b90d23d2167e39795470b61098a31067cd7e","0x0eccd57c2221b18f5b461934b2666c92701b69554cdc9bc8dcad6bf5d84a0d40","0xed7762320d97474e3244db1641088ef990314dfc2645fe522db1043b0b881d9f","0xa3c44c2f8a1eb649e121779dc7af652334ba0e44851e61876c87b6c0d29f769e","0x9250026ddbca31e0c948c53709a5804fa8b4022c2cf726822ffb1500a027a1b6","0xcfbdcb8ffa52fc7254137d37937f48c992a8262f2419a3425e550b5cde9e01f6","0x32635da6f007f54b2d85a9d559f8f7689a50d3292841e137414d8b59ec7884a4","0x88e06f51eea23568dad305cf3eb8628bb87c700e83baab3a4a221ccdba37f040","0xc92415ffb613b383e7549a453bea4a7a32d45e4766f6095ebf39e6c6380d763c","0xf5620e96a63c1ab5c1d2ee87a74ba2a466bea86a7744687e12134d3b3f3b71ad","0xbd0621b5be68b1eb4709dbecf560ab81bf120c43db29e2741d367c73e28ea3dd","0xb98619fd81ed2de4b8464c044b195d53abaa993940201e225cefde50355a8f07","0x817e56d8632fea6d5183d3ac4133607189496d3758c28e47344bc67d2570c2d7","0xa0f393f07d9499df5e2785ae6f977bc84fccbff63ad5ca531614b6c71ab74d01","0xf0c670bdd022478bd5701db88d39db0d9d03de746b7c5806b20599eef5607858","0x298b8ca85cb5d11e340c58d6d5d89b4d126c3f2813d61e244fba255d694ed9c6","0x4d74ed6bd511c001e1229041f710cd82fa2266c72dc2f0ef581a7cdaca68c6e8","0x445ebed715aaa8513c10fe8a0e010e194ba98263f67d6a19ca265326c1a0bd75","0xfb669ccb09e45cecc4367eee0d1fcf6ae3f0389ea26c70e89d0788fa0d2f11ab","0x12f4adf3fe455cc7377d53d146a32bd31fe2f797b39811700e85b7ec57aa919f","0xbecfe298ced7cd45075d2a0a240b7f121eea659b09a194e8a0046b7bcc8de600","0x5d3a7cc62e429b359f4772a0097ba112ae9ef9cd467cafab38338114ae32ca98","0x147f939158855e1b26f022269d0943fcc3dec8151b2f060e4792b8bb13b3c802","0xf2081a44881661375f786f0f8080c5df2e342858728ac4508bf4f2eceefb1ec1","0xa04edd0ed5d16ce2bf8c3aac6675cec7cdc668949351261dbf9590e6c07d4b61","0x869fa3735692f5927631c94fcc3454c62f2c212ecff0d4b355dabd3f69ab56be","0x08db3ed18894b26e14bc8f1e52eb8ad031dcdd402010c52c4cb9f68c09433621","0xda9e5fd540dd1ad15237d72ef5be3155e0005effd540ddbc4363f16f53b90421","0xc9574e187f0e4e14f19932798203bec3069ce575b453ba7a82522a3700dc0498","0x0d6772d9e89d490d7c332e923578f3f7e0c972a4198cd3164b4ff01adff26fe2","0x544484c9490f8c2d3d4bc98c44344c5d819a2c8647a7657653bf51c8ce1eed69","0x755245294f71da632eacdc4b25298896c3893e90e5ddea7e82aa1f008185a938","0xc629b0771eadff9905762f68fb1eb729206ed784e9b0e4afa44c0fda2a9b663b","0x75fc3f62f1f02921c3729503092e2ddcab1dfc810e84f415ad507d54b73f24a3","0xc1f009360235d26f313e9c185d97d4ee496058a17bb8c9a2c1e3f100b49b8df4","0xa7246291452268f5ef5a88e2529537e787bff1304723a664bf97eb95b4e8b7c0","0xb808e40fd15ec98085a2d6a91718598246129cfd222b96ca9fded2026f709ea4","0x85d1bdff6603d1fc59be83cc09c30361a0bf5efd353661a8ed1a1a015490ab28","0x8a897b4b600c2f71e4e5918dd5dc9881a162f5e91a4008c10f6970a42d2479d0","0xa7ec27f444b0e49762d47f811dd4e4a388497aa902062abe5af451e3b8ce86cf","0x184f7cfdfd8b3b0cf7972af86afc6c29526756d03e600e1e9149dee10ba24309","0x0dbef8855a889c3a5235766d4711e1312715933f6bfc0854ba5848c7b0bcb9f4","0xb268c3ae6a06cc570949a3cc381c9ad175437cd642cc4d5616f97a7c8e019ead","0xae142a87e8a513035b898d5c8a6b5b19a36246666537f4a17526e1b2b5cfef79","0xbd1437082b26c8e1bb2ede2ca8415dda4de3255980bd53f1bea6e2a7d45a9e5c","0x369a185a5dc6a97e157884057f81e9627875c8d8e8520f1c254b8463f5dc10b1","0xac20d68051cb6463550716deb4da86e95ee6788d9a403988ce8cd8b1343b2040","0x2538ecfe29cbe6f0a24b761fcef80d01d59e09d57bc97b7eaf0fb7f18ef355f2","0x7c60e25358c428800feee75f24b1dad0966b975733b7a73ea1b0561221dea615","0x8ace7cdd9c328f89edc7bd820849e48dff8d17a4730c2bf041417ea50822938a","0x0e663eb4dff04d481e6d3a36963dea98e60a21d638e343c288bf811a0ccf03df","0x724c43cb2a2ed0d293105f642f76040d96e03d3ae47a363539e77c801eb4db1a","0x539982cc32b9014c035af99cc63060085b8e69556d36944e21ce74a74192afcc","0x0d6d380054e9221a24507703785a7519fd83141af8a65780d7f24e5998cd7371","0xd7450f620c19a58bde3660b015ce97e9d59d76635673518136ec46f2c9e4e562","0xeb6368570ea7ae67cb672467c389022cabb00ab798930ace8cde70428a325378","0xc1ad01b3cc126593d0f7b21a70371f8461b48185957ff7f0b8ac1ac0553cdb9f","0x14b00bfa1d97806a04eec5af08ae3c18c9a63459d6a58ea89fad3506077bc366","0xcc0efb7d16e0a30f95513f011ebf7a0f467b2edd5066100c92347e6da083ef9c","0x0b9b76207b6f654455c96a01f8d4c12590daadd2139ee28d323650dad757afcf","0x8f1351f2f9680d8032712a90edb67fde6d4ccfe5486d756b13c747e828577984","0xd9a841b08092ca4787c3b71fd88fab9ecc3ab6834b2d631969775ca405a3794a","0x260d4047923eb6c466fc669dec021b6d123b740fa0651ae83673ad858063acda","0xd7a660819621c35ab28d2628660241be0b630a1d7057abb744d3ff6582f8ac0b","0x657ae1f4d59964dad943546acd9171ad7dff6e22f94dfdc7338f36c8354d1779","0xdcb7a379150748ddc36692c3b52721356763a3642ae8d0e25a6528ce19a60133","0x509a82cd64fcaf33bec6eecf00a71f8fb537dd8f0000986806f6e9737c4a862f","0xf5b268f255e805fbec647121f08877f3f3da79aa51c0fab3b445e952e91f2b53","0xcd1c2a5fceb061abf1608eddd1d64c97ad8054b925163ba0737a9683c19c09b9","0xbc5a12e1cd7dcafb1a2ea4bfa91c73741a12067b079d2027d0af8a9adc99d8c8","0x7506775441ec1d32b47ff3b017169d16d22c81dababe83b5b5e5293e978ed4cb","0x99592af4cff5a327165ec342b59bbc0b4b09b20a82755682c07b9d25a2e2e863","0xcf7407543547fc6b8fd1240449011a37b7698e8ebddb619b6d282b7f679706dd","0x26a02d49626d47bf9a502ceb70144bdcdfc7ffd2575ac676dd1fd6c525eb32a8","0x7387c563aee679e8ce01649be5c134d6eb336188e813707df24dcceb3f4fc094","0x8299a8ae7e612c886b1357ca8dc9346b13e7e34a1c0c4d1027f6d1412649845d","0x48e672f719b4a0dcb7b5a64a99ed2366ee59bf18294325127dca429a8b5ddc76","0x1f7556f2000fd91fc041690e8eafc5d221f3ac560808b671b7b7c3c475d9191a","0xa62ab43d90ced19cc900aed7ab4b5be6d06bf20a06e7bcd46f92aa8b51e1774c","0x54e5e38cd38cad75858a166d14ec29302981a0359a2e8ee30606dfc84d500543","0x5e608556e50f476013799046c15babaeea5d9e2122d70202168b1a284ade6e49","0xd1cfd48fe7a47af45fca475d389fbae7fee7784ddaad81411148c1bd41624054","0x73f4259a322858359d8a3624f7223e99a47f9478a3933022b4191764a6feecce","0x67ad0efe621059c2b5ff8ba979600dcf843f4af6e78f7fcea982c5061e1c68be","0x0f791559eacd4eabf87624edbf538cd5884f95c365c0f3f9e70df10a60ae993b","0x9f8096202dcd5e04750ac785773caf91569bcf06338f674db7e809a78066e3e1","0x282a0e4c139edb69239eb8586f8b92a6d647e142d1fb25154d93c9f617cb8eda","0x6fc9054ffad75190a07a68f97865696d4e35a14d10ccd88f986879b7c093b843","0x70a7af26aab8ae31925e9cb33d4d1701ae2672ef1658082015ec91acc9148cfe","0xfdf7906d90e03096227e60730c39d7d42febc4951190cabede8eaa5128d632fd","0xb58e9393ff32720d34d29523b799eb84e42ce45c97ad6c80a0ed8973d720096a","0x04657e664fa9443a53e828f70ee1aa356cd2a395147d16d0edde37bc516a0257","0x3395788df6707036f7de1313fbf794a4576a93ace9cfbee7b25e73af73fe1fb1","0x131309c1ad35184f6e66ca0631ecc42d8bf946bfe0feb1acae5fcf4d19ce5771","0x5c94f2161b8a8664a49c210a4ef3f4d247785ac683e387fe80be0c6200e8d802","0x586392d0cb7fb0418dac07308e51f77d2587456269943585887a76bad7ee940b","0xd8bf219ce90f89b4c4553dcf65b3f6abd8ba312b51bb4d67423841d93844d302","0xfdd260d05bc8acad56d93255c7c170fd07495daed7f9a18242f15deaf2bd931e","0x31d95331dc4931dc8881780eb36fa818ab55ea51b2b71f5c2b4a5e105a35d668","0x7ff471bd4031fb900ba9a2052147dd07f88fcbfbf1e8c03e7180c3097eb6a004","0xb2bcbc59a7b01c7d1a338b2ba0c78a3f246280c2e2557a9ba60bf5dcad28449c","0x85763c6f40ecc5c084f84f0adb80304451aafdf9d360e4608750d546699dbcca","0xafdac5ea26356531c5dcc98fe2c8cfeb3fe661031cb48faf42a9d9eb42f389d6","0xc63626edd46a5726f45346e4877a9cd685665c009a1cf4a339ba78f027e40a78","0xfb2564aff91c948ef5d414dac82bcdd4d23f234ed2fc951347257c7fa12e3226","0xe44d918d863ef51710bc95c837dd651c1f536304e5761a6acef09e9c4c7ab151","0xc0cb6fc7cd4ff26a99dc8bbaedc753bdf608de98102d32949ebc1ceefaf8b016","0xed2f430e2b72d5759f9b9a8d958eda3719b967799ba5984a6b614adc02398b49","0x1979e50df2837155a0c27d8091f54cd44eb0903f12e4bbca317b019008dc0db6","0xc3b9553ad2f4903a2fc096c1b24b54c42d2b23c394fe79fcff30efef73dc9610","0xe28d8446f4633af7c4f667ce19503332d03919524b7adba9aecf267bc1ad1d00","0x0d5f7823f34d17d51f43429cece51d54276fc65c65410e23750dc5caed33df19","0xaf42aabfb1f00eb73d36e1eafcb56437b5aa76f5ebd35d9d2826a80785c1a113","0xdb50b07d86a0ac6c7acc8ba1567b634cecc6d4f51ac0963c841c24719f82b5ae","0xc3125b1616ff091d8424d7cf2e4f600720e57600846ffd52799f38ddec30b415","0x504223f7255b68837a3f19d97d9e613651d98e5a73247b6688ed1bf830ac794b","0xa6f32c54c0313bf807d5e0a1401028b1fbda07613f82668e8cf881722d22d3f0","0x3aa566a98fd56333c1594c49c0e200b26b109f99099de9f7c2dc8ed3c045e3fc","0xd4295c6d35aa2a17db44e34ae2f7aa597fc048a4bb32498d1070471fc64bec96","0xce1afb677c24a10fc608b70336fda07060b2f8a838e419d41ebf8dfda733233f","0xfc0dd7187c1e2f2b0d4d94ff1c17dd2a1917c308f6a9970bd011927db8999085","0xdda7d35d584c2435e91ccabae3995c631e2a5334ebf356720a5c972e79a22ad3","0x8e54021050300f8448ddbacde68e5d9d0b1afc949a7c71d6133ef35eda0503d7","0x55bd7a6c880efd2aa7c631ecfe9ec61ead2f47c815d3e028cf93ff4a38537110","0xb20edc98604c5bc0c29cee29341a78526d7949ffcc3c888d3a2205468adbcfab","0x4f5561cb3671cc781a58a88104923b5e80137ef76a5a69546256ca5788ed8598","0xe3872bb97f0516474170fef6d1ce4cd2d2fe599f5415f2de0770c9a3dec4091d","0x64597a8c934f7ab8e2ee6c8f98982edcb3487471d804ce83469cabd671a95de1","0x841dd174b0b584571b47e7dcd49babc5cc8263d37971c953ab72ec3c79432ea6","0xeabe1478b2465e36bab08f0085cf3738eab74058c422eeef98db07f79d8b93fd","0x014a189c699b30c01b8b81569e2d8acfba382546aca1ab7161d15b9176ebc9ef","0x260752527a2eb856bd4d3e0d538d888fd1b307458f84d99a73c9001a4d046d62","0x1da6b8e6df57f74165998b72756b2de098e55f7b049b8c5725365a23ca559b65","0xecb4d68c450ac1c26b94f1742666b676a02f6f322ce412d7a54c6eacab803326","0xbf6d555512c4134cdc36ad681b3f76e41cdf66d7d7cfbc94b0126c260fd1f58f","0x2e81fa5cdd8df1bbff0587ba469f332124e363302e61554f01127b00861b0fff","0x4ab8e88d695e0d9acb9b8c1a6eb1927b26c15f532724b4675dde918c5d56a308","0xb1425276d8c178f881f67146fd6088b7a86bc2c742a7ec45ac86d4416ef6f039","0x5eb44ca7943653a6cf3332a367db920ddf8be991f8b332ef864423ecbd23e40d","0x7b0e7136f34d50cf2caad9b7b52f0bc474267c01a04692ae50a7f2cbc54d519f","0xb2323f3468ab3167d59e10b2befc7d405e06a60c6d69bb270c1e034ffeb9e388","0x6b45b4c46a930376fbdb32cfa904aea82c4f6436f656d55d98d04ab2f0978084","0x95f25947dfc689033749f9ddf2c379dd84c1866260d0d65af1adc65213631e24","0x717f6ae7a9e986e402933e15c6c875c12c6f32ac0a23b05f1a040191ead87bb2","0xe6e8f9d8a8f53057494b80f30e0a0444a81240e51bd48b33834b00f88d58b354","0xd4117792813dd0411783d8678d6b1ebd737df06b267b43d6aca5b2f696dc360e","0xe43ec1abc5297479abccda565eec4b0e8efd9257f23fa76a7d24478b07bc0bd2","0x5d68d25e6d1880ceebeccbe193053a5895dc53f62de18a3478995b7523120d96","0x3b35a8ccc3bc98099a83d603e2edb3bab7dd0fe74c91024ac9de6aea84ef408c","0x28ae81141fb36280dcad4f91481239f8388dd8f3e28020cb7ea57f2774c0fa65","0x030a457d82b9d303983b0c7200b64ff973e8b5153fe8036a1a3b27956ac1c491","0xad8cb0cfce953f4d30414768c93a4c14d44cc8464905a6d3179ec231253fe2ca","0x5707b968671fe8b72d3b11a0229f328f1318ed51ab49afc5a7f4b56a85602149","0x9ea07b93abd0a73a584302af9da5f95263cec6c3a2e6990a2c3e3941f4613bda","0xc343f6d88b464672011233b050d7ff89ace42787f6a4f45e8daca9b2a547b710","0x8616c97bd54042c39b5b44aed4f5879ce17f440c5f46e78bf5023dce3c53c9bf","0x368ff7c5c2b2d85b5179d183fa69ca2f76c53b5009a440bbca9380cb6f1fa308","0xc791d6634cb7d033ce7ac02eae0a31d19683ec625a20f1629404f1e669912bb7","0xddb0086152951b4b7cdd5a2fb3a31de2b6bda33d94f41e12c580fbb2ffdd87d8","0x1b9b006a3f1e9a620ddb3297d0c0c943dfded3ca9ebc33514037e836a93c1d54","0xa9f0884af8790ed624a186a232c41392f51877bcc736a21d50aec16d243e42db","0xc4525af4404aa4e8a4f99794f394931214c2743c8c5b3bd577999664d4c95db3","0x1cb26fa057f3776ca1bf6b263c91af242c56cdef78a251ae9c53101293f569ca","0xe996dd6fbee1020ace4be2b064d81de1eebb75f12ded285f5140ff7263cb80ad","0x50ce9cf71e84b755086fcc6103617e97a5a2e01eb67a04d7eeebb911ef4ecab9","0xc5431c7f8e33f945fcbf646ff938a596e04e9060e4bbde1b2be020e23d6685e7","0x7d8773aa0c8de2caf2de449a854138615151f2fecd6cb09863d59d6f19905613","0x7a472882757b66f9a7b0dbe3d2223df851fc9a5b353a02c801c70f7245003616","0xbefa193ce6af03f4e4a0b792cacd7a5bf55e67bd3e8019c88f880445d32226b7","0x1e6237b1c6585e93c7ffdc82ddee63f433b45105d252b1588d147ab9b7908d21","0x68adbec613a26a78e7a2b2e3c98ca389bab8fda26b054232840f713649c3ea22","0xa860182e252da2d23a46f3471a71053a77b35084464af89e57c2320402e362e0","0x862288b41be23ff6ae9b804e33fe795bf1cf41837bb3fe58878355d5796afa77","0x597aa936ede8636f4fc185ba2cd31d4500d43e99ffd09b275b48ee4a677a6666","0xe5300425e726d70f3a3a6e1b86d2c7ca8f55e86b32188b0df7787f6a9532b59e","0xb91b180f32f49aa5889e2b82142c6bccd3a62878935eb8bea8f43dd3c1a3d201","0xb11f88e29d3e1b21abf88525f3846d37aa13e65f2467b82be57182859c2954b0","0x83e677d9cbc3bb311cb57bf2fb75e9be9e49c16ab1b6f31c404ed33f70f5c37a","0xb5f7b469bf41fa33de3891a55f544b0524be2031263f566b7ae27903e1ec2c2f","0x804b7737666a26cce01b985c408477636ff803e5a09103bd0593e4784c5fa52b","0xaa259e088c246edcafc1c24d404168f3d452ba928923decc93304eb06c2126b7","0xa2347475b545bcd8a90a200b50a415b4b25aea40268ecae10a86622a7a55f355","0x69a2d3dceabceee2e5ca8855ac58b4e74db666bae0ad9c37d4983e4c23e4a166","0x06b3c05df6ec4edb5dba119e5c2494a5a77590903d8e8f8f2f79747af76f92ba","0x643e111fe9037f74b42a5a4371e9cf62a27c3e5cb4ef251fb7e9296cbb931a93","0xf0b11be23623845e2af7d801b54f21edb51f143a15d716fda9a2467d571c03b9","0xe85b8e9d39403e2fe08f91763aa1baaf56066a2c3cab95ba9ef42b11fec5f651","0xcb89e00dcc55af5a3f1a2c4920d440462be457205ea0e3e6bd126f56ccb6d674","0xa915c6e1746d30ba02827e29577f8eb3239312065402c0f1958b873244b3e4a9","0x44bfb1efcd161cf37b9f87a79c8f930d8e305c58a1fbbd9c735c19b241a89c70","0x1a4ef586d0dd82b1bb605d2891b8b5f807da45e0d5a709fb20869936b6b4d4f1","0xcb84586b686f4714f1efc505c491cf2f64e12a9dcc3699c5a79d704fa3a869e2","0x34d80f87e433df46d7869d2d00b315dd5704138860482929afc82f2f9facea27","0x9c16c71ed251a64da0eef22718de1d0ff51a38a8e5d45f8b16eb97b1431f8633","0x7c761a750bf6fbb29e7bbd5dd0164cb2e0ff9278ed5c072f02918700a1fb8aa3","0xe442f280f6b839724b95aeff2264b74f3d33fc1c54a5d32bc2e672edf12725e5","0xa1b520b94b56dfcf9f2c0d59ade126d6764b33f2c17b6c25f5c6307792de78b6","0xbc94915d0ea4e232cea793e760084f5487ac2d30e7c6ab900332b2c027a8b571","0xb4d8fd923ee1cda742c7112237eeb7013e20ca0436099b88063a7fd4058f82f0","0x0df9dbc949b1e9f3644ee0f43f081542fff9872f2310fce9f6519ccd7afdfe58","0x1bc55176e21f9c41ce2254d44a6f4166163ee597a0bb1daf8936996312ee52fc","0xc80bf6404072a933e7642954c8b7a5d3b075cdbaef909fe6ec0fed29d9f9dbb7","0x7073aa7c0e249e3ad718aaf30e78e62936bf9d4266687576b6148fd0119274d8","0x9d483a1f4bc357ebe64eee99903494b9ceb759569c0db0e438c070d24cc67223","0x9322494b16fe77f9d6bb47cfee97308ce71035afc6685a93fcb03f868ec0a89a","0x3b12dcf838cf3ffa3d3532aaea29c4a3bfed46ab3599c2a0e0a52cf3930ad491","0x0c958bd20f0b20a082304a6bdee96e32d4f2105e2f67fd2beb02198cb5902f49","0xa889359b027a04818e286393fc202bb8c446da597a2a5df6959a6f4e74f186ab","0x210953c1b33f09470091f7d02b667467c3cd1b0f4c633985973a99c76a9d6f2f","0x16bb532f81776ea39a93bb2ebca580c5a823cdb843172bb819bae0046a4b95c8","0x85d8384af0ac3d1e3421dff7c7cb9c67505732741afe0a92fec4dd2300f193de","0x2f1ca0137532f20974517ce4c75705b6c22520993310a96c27c8b639f0442911","0x785f3b18a7b3194f5a380427325a0fbcdc6f3b89c368933a3b62055b7f84038d","0x41d5e77891fca74c8e7642234363c10f42e6bdff16795292755d124553e1a69a","0x353f8f094fa9d664c10d191ec25929ad3e8c05746346e9c11cd64f4353d855ad","0xaeb0f39aa5d8a20c83e081d4f28a38277519b47a04deea6ddeb1998aa9f2a9b4","0xaf19d602f5b205be142a26193c1a8e358321e08d2e268a47be154361a97cb5ea","0x0bf9f5381841bacc705a328f50f5e5612bcc26d01994c8d515b71941d7efb19f","0xf86974ca5b60d1ae75072f65a85e9d1be58a477382e80bfc392ed141f7a062bc","0x9278bed36d57ba579d9bc132073885bb88de029d7d948b511f805e1382468603","0x61f1bf8bfb11d20a06b46fba87a1390c09cbbf7f9f52f59baf8ea05eb5eecee0","0x117de9531d7bfb906fa7e6357a288832a3affed0725e22e014ee233d97d40835","0x4a246fe69541ed17d328bcd1bf55148d69deea0e8fbba8fb0152a4530f3a0fe4","0x4b3af292f551c9bf204132c15a7b1ad80e2f34ab62e46be6c04bfe713f5f8f9b","0xb5d3cf366da5a91f89bfec817977babb68ae4bfbc50ab2f2f767d9f74f702ce4","0xddcf7be0a4a70f02eee3da38dac1ba1597de8120f4c150e628c427c4b10c1a7a","0x399be75332275f2f9f6fa6c50da5bd95d108d706aa1cbb00a7d43731b7755cdb","0x8b28c3d012d98ffa4016b93132300cad4c080d9ac8629225be80ab53ee964c8f","0x9cc05dc0122ca9a597118b802f88e83fc6746ffc624b3b4f1bbd9841cd90f223","0x4f56672e89c781ee7ad65d328902d17042a164f2826eb123cecd578867475842","0x70651ed9c0c8d9eb7ed28b6770b119c18b10a385d2b7ae75a52b80e403fdb0f7","0x628f7b3ca546619e4600bc85f7f74413d7c6f7b95a4ee760fafe5b3538c1cb2c","0x6c07d9df4fceb17bb8edb2f28ead4cfb97ee3c6d6d4b592272091403aabefae6","0x0753e74284e5e0df6e617d741bfed40a44d37f3037fd1bcd424ddfe07a6b2972","0x0e3214fb1514707c38134a97c4b0fc538c828d7de673d0c1a69304f415ca673e","0xb4554aacabebe32ea9834c85320ed9bb4428ad59fc41d3ca070f3e3b30e5d1a8","0x77b7b6eddc8b988cad512f27a07c219d71a8bae0527d3ebf481aa3a7476e0297","0x7d84a222c07d6b1d2b9ec9cf2f15eb497b52d0014f4f5879447a98e402344a6d","0x38f775b574a7be37b21c34462ee0c19bdd2de26d6f5f928a114e929c97234451","0xa31a5d27bc18c31439b93acc6e8b38aa837cffaa95789ed3f9bd4555abccd4be","0x8cc5ed02048b472421f6adde050f5c66d4dcc0f59565418cc6f557811a66eb53","0xf703b18660e7ca79b2ba69c85fb2ad5f246bca8aa35cdabbf47216741dfeb4ef","0xf24cb8420aab5010e0efaa63cb366e950c0c96141d1fc4451cada3206f3c4658","0x4a7bafa6a9546f881fcef89beafaa6696037422a26504c952cacdb999ab0b056","0xf03048fe36382760417a8574ec5ed7ae490e289159e941e7b22254e4d3ed9c7c","0x829e325abb468342cc1eae1ee6beb2e439c9252b05b7a6774263df0110780f22","0xce75d1c240b0e42537f67cf013269388b9d66c3f4c16557cc3807118f4d0efc4","0xfe2df588419cff5ae80ec9112024021bb063396da146b6bd466ba5c9251271d1","0x5fb23a06aa939faa7193898a5ccf88a119d4340a2302b6aa3fddbf62e009bf50","0x3534e0c98605fd9fb39de012d4dfb737c44e5d9090b5d4ebe87e11696528e784","0xc4c914455ea08f37003476891bad2c69d5f63301014128f2d82df2b52e27fd99","0x797f4097673c2689f566d21eab7c32b00730247fdfb5c1e05fe181dfb17c3a30","0x58b63a5485645f712ab31e091a75b9c33d807da35e9ad2cbb8fd1e27bef78694","0xd53ee9ba0e782b431ef09da8f574136166db5ecd3b628c69bdbc7dc59d676d8f","0x2400aa2e3dc7801ea396b1616ffbc32ae772312d200475a5ccad99928cd4cafe","0x380b3e0344b4c97fd7028e8a4957d6b286fe19e41a8e7e499736ee9f9e75e337","0x23c1fee2ef41a92c4208a281158a8357311aa04279c4fcee1813922e18104ca5","0xfe9e84921be70af7a2cd39aa9eee50d46e52749f95f259a0b6682d279234152a","0xeb4890812b07f975346e506504c1903ab011db4e9eb5741522aadf44b2a4d07d","0x72eefe7902337741bed781ed074f8e6dd58ac29f8f316ff5fecb33bf4de4a067","0x112fd9f01d38e248768c141c1eeddecec2c53dfc7680fdc4b9cff7b569ded305","0x1ed5fa95e0def9284e7e81c9a589d96a89331a53901b256aded5195e1f7608f5","0xc3873ccef527d3ddcada7825dee04ba42c3a7ab794cadbb0189076dc199d74db","0x4150a55142a7466fb2518111a339aeffc1986b72753bf945fb55347704129b17","0xb21287f12c0045c781e6964d95e8f1b2dadbe0f79a9723528eccea9c26c2b171","0x6afc27f22cd4ceb88fd2a1e2064d9b66b68cff63b7e36b8d3f0ebab13d63d746","0x62b1926010281e7ade488d85688915b62cc69bd0df7d3b592b9cd7a91a2ca399","0xc3a3135ce8196975ca6e747b121be89e6ee5b7aeda2f49cfa09266c7348ebc11","0xd6ce6a60b7a3847010040ab856a235ecbcdf5ea23aa00d892dd45059cf084842","0x47eac1a1d48442105c54550258d958c3ebb0c391736a04fcb2ef4df1acd05af2","0x7713a66e39afdc98199082b835d4ce328863ad753e942156b7374f369e4d68b4","0x0678eb24e830bd2032f808a4520b3dbc60bc47cf3286a8b7b8568346f0794523","0x41f805ea0ecb85099f5baad16e11d699c059b4c0ef8d475dba5d7b36e0a1736d","0xaf447fa8d2ffe3b38b6bc2c0d28c7c6d2573fbc7dee65e994023738ac8596b4f","0xf3ee5158d63e6d15a8a224dd4f4243430987d93b235c3d65ec76c1cbac2ebdbf","0x35b4705d3161a9c6831bcdcf649a9b827da10981150a9c797731ccd116f512ff","0x4f90567d9b5b0c0becf3bcb2f3840ad12bd424ae2d013d46b832452c37f13d89","0x70ceb9087a3edd2ddfe8f288d16ef76a6b2825f4331ce4935cf45d2e5dfbc4e9","0x6974f30e74b09a16b9479d392da366d527c9e328185ef0c6db1c1c49257f61a8","0x4e3472569eb278ca423489cb350b1b607871039360d48a3e2233bb83ec49a7fe","0x1490ea1863d3cd139d71ca98c1edbc77aad814f2703fa199bd35293bb71ee561","0x0ddbe5e974706cc3e6e7ea60148cecf91d9dea563ce721601a601f5b9ea3be10","0x13ba6f13461d2a077b4a1117731aa6040b1e268d6bb1a1c7ad0c80205c0c2948","0xc16e00dcfe69a57af383d6fc43354827ff1c523f3c16256ad3a04765a97e7fc9","0x11e147af8ad7a7ba726e515c68ac3bcb468ec8e638820b3d8c25e139fdea202d","0xd1f6d31aaef6b5285383213da20b4c98b9e7eac4991cafcfb37f4b652e847e1d","0xa9df47539df2d0d13c71ec3bf014f6162f7a58c8e20db63cc3d352d8d938278c","0x418e02cc25e9b8f099109e32be4fbe964a9768c60b36d6d529315cf0ee522b2d","0x16c20db00dfcbfd0f1988bb39f467b88d42b8f3de8a7f0d6c2e94560082a2652","0x5cc756be4a5561d8be3aa5bfc2b2c9f0daca44d73699e1c9721894a004b477f5","0x52fb513763c085a9da65072b6c46efbe4a63839b06bf06eefa1e369025026304","0x649b5f91888b3a1be3389132a79016e16ed3cc67fdef262979c3ef8316a66e01","0xac6af63f8623a2ee87de819aeba8639e81da5fabaafe0cbb1944b54df8b6b11d","0xbf770ec7c198474333fc23e98c50a12a9474ca563c6049f9b9a15e760a10fadb","0x9be1fd57716c41f96912200c2c68475447d8066953c1185e69004863a9fcb0e7","0x0a8e6d23b4df238e1ad727711d04e028d7216dd211b0e16f2cb53fc68ca1d397","0x33d22370a51cc6feba7083bc390c7d874edf01e5cc276cf90a107b6b97c4ffbe","0xf4bbe4b3c32c89cbb0630cc69322f601524a1426741cf932ae03a4d6cc109228","0x4dc0817102ebcd5e06bb874b73f76637bb0f62c3c25dd0fd88221fca3856636a","0x857ee39c0e6eeb4264816bd780b471bfa495e08ec99ae60392c946b964b270fd","0xecd5a3cc05d79b5fe1f7146bb0ac74a2dd7ea92367fd3d9f421e31c40925c3b8","0x4b52381ccbfd01ddae49ac6c98d26b17468b5ce3344c35a3755d509ada78d3ba","0x60a5f1cc8fa71c311529ede775425bbbf2170e1747048ff049163a377cf69330","0xd44c7f93ad2b9944fd4c289c8f419e3108f8b997f54f36a66dc38e1bbab32e18","0xac9a7b384d922f9568a53d8b2a734b5323962a0bdce482d93859c97dcd713cc9","0x00bb458b8f9f902fe820dcc3ae71c6008139ed58aecd68f7dd4e8ff052745247","0x5d73b708d6fdc1cacb9b027611f74b6d798b94ed94f999dbfe4e68d56ab4886d","0xad8eb9caeb61ed2099490c03140e3ff12e02e2bdae6ff53107fbf311680af8eb","0xd9ab4e579111a2cdde246ed1bcd9a7e9e678da22076b58f2db4dc13effb07286","0x98f1523eeda352a5ff5b5651baf5db7e888142d0ae44fd665552c9120735d5fa","0x85e4b836b0e938b091b8f49825d8d4dedc829c9ea210b185dfa6da6c5636ffac","0x06a999ed887ec29133266070727e44542d505a641cae7bc6719873cddc4d45b0","0x7840883151cd1fe3503751657c77c4a9465f55bbe81b0e863352e68a28d651b6","0xbb4d0aea45d78f8978da3f2cd7739f57d2895130fce66fe57e0f53d99db078d3","0xf6301053f27aeeb2f1f19787f047848409badd1bb707271864cbb0164a6e3fce","0x6e1a97a2f825d49f1953d2c51c0a9f4d00ca3005b50ec50b840623f0440e0f5e","0xaed23034703884daa74723d3f449a2fdb1be8b55b3aa01a5405acca1976de23d","0x6aa3698d7081595c338b8e4f58a19334e6f10e531c90133dced29b16ccdd4d44","0x4fef9294ff61e2579e3e02bb6b28b69d7f86ed69dfc7a9cf3858e90dc263b2be","0xd2f3d16f94a2ee30d270bf62024ffd4dce16f07f48ddcf96c23257f9256b88eb","0xf132005ce781ab2ef5da9d2d2702b2314a5c300c6cf92316818f0617e15c14a1","0xa3a55a8480668c26bfa941aa96f70cd4c3b8b5432fa4fe783f2b04c4d1a26177","0xcc850830681c1a0a2c4edc17b78cfd11df5cedffb9bb9b1e049d27247a05edf6","0x854bc12788de601bd85640073f296178da68a9ef46de489715634b44313aa99f","0xcb53e4a739c7ee435b9cbefbc54cd0e5690f0409a69eb48d65ee051c1aef68af","0xdf8bb5effc74d0941bfbb6790cc6f15266e6e8e4b9acd80c43f5d288cffe1708","0x3e8f1449b93043a63e49c3b7ce4c78e2ba882d43de11f6aac6d5408e8ff4343a","0xf20dd366acb7c3fadb71895e45b03958d791b7278f86e9220d705b6dea23c7c8","0x3d2385f1aee6ad4169cc12ae1a6e5d1d837c8312dfe1e2c75f98cba83887031d","0xe7450ae2367a7d12ca13e4e27532a73921168ed3f701f45b429d467272e586e6","0x110cf442f749f057c61214cc97389cc49626200b4a97f4ab9ec17d8ac583511e","0xda3c587e1a4120ee9b3660ecaa98a44ac17ce0f28c51487bb5dc565f3be2b56d","0x37de68658a4a5baef2d0b4478d3da6b4512161b97e02cdc9eabe7b55ad7d8d24","0xf94579c122ce94d1783a2cac6ed37f92f15599459dfbfa6412640886dade1e9f","0x30bedb7d7b077048cceb025fa559df6c19042bab610e2a13840b78d9e867ae96","0x83214ebce6dd0845cc2665d79a36560b3d8776132de4fa7609537dbe8878e479","0xf7adb4ef8ed0622a7c6113aad53c51fae8406ded5bcb64618da89e1f7f7ac480","0x20f79e29c797c6e2ebd6cf0273d9bdb5e0c2f528078a260a3c071097c68cecaa","0xda80a5fac6c9e14df3d254bb898b068a7225c4a6f179a7a9050fe99ad384947d","0xcf600e1794e9c8a455e64634d4b05a2a51773d934da70313e2203cf930724cba","0xfcf36c5b07de359cd953ceb5d3cfd80b734b13783519211216be9369d86d239f","0xfe124caa3f9c3df8e5e94b5448bc7f0c135ba141baf8a9d4eac9eb523a597e22","0xa602852ef281609f3e31a931af8e5455ac9b35e45d6924cbc1d4090a4dd8daab","0x3522edeb45fe67089870b94b5c84debc487c1f23251013e36fbb7f87e02a404f","0x51c475233813b774a3f7b431e3846a44585ba911853d5cd44ee3484364fb76e1","0xbc36ff3120f21f34e9e34c65c76e57dd2cae9354fe6bde509f41b33c123ea2b3","0xb3718a5a3088d2ec9e4ff5ed6e8e4277c99185ea3ab7d06f42a90a33a05117bd","0x9590e94f3dcbb88e3a9247e140791246c52d7d59ab052aa84458215c9ec91673","0xc2b03e0be59e61ea347b0ac2e5746133264094506d74ea6ff9067c03a7afe0e4","0xba7cb5b9fd61300f49c92c7cf06df397d2ca1baefcdfe60cafaa8c4c1daf6a0d","0x2b342f0080c5dcfec436026dae9f4a7d47bbcd6f123989bf6d55b11a4c7a1d09","0xfbf3d12ab67626ebbbe91bd1c48438d003d7515b865078ebebaae381fc0ac335","0x455dc7c9e6cd716869313c7b9dd6ba91e5aa4392ac5e8a7ffe0a1744ada69d1f","0x1591ec8ab5b10aae35817e06b21436652a1fbc827e41bf94a4e46dbd3c8b52e8","0xfc3bee72a04a6dfe749c5436e5ef0f04804a80b91b0284a9196ffd91a5a9b7ff","0x4fc1e131794de5436133a4670babfdc9f19b4aff05c74829fdd1c7e91d8997bd","0x5b433508e77b12bf23694fc7b1b6c01fa2b742aca5e1b115d5f337532ab4a37e","0x65e261371ad58c12d23592ff2962099567760eea53755b7d57ac7063890e039d","0xaac5ae3786cdcfed66dd6844a45f9f66902aa9b1cb83718f2434d70cb5217a6f","0x4ef685d0192130a8924d4919b7631f824ea8a3d8d7a9a61051a7e501ed4fb94c","0xb726017a0a8d0c5dc0816e3edd5e21beb67a91ab3595ea0f3bd5e96861928718","0x13e840d9cf67c8d6e0d1b2523f981ab1e45702e05910bd011a283f3951902f56","0x359e2ed7061cccfec3e92e77daea181a3c3692bb7168f5bd1f835ef4e86026b1","0x970ec00d9f0e94dcd59d8bcae2c232a3ccacd1da8a2a353706fea35ff62e9421","0x3a3c6f174e69b60138d7246707f84c74847ba5d1fa50d2e097550114717089fb","0x9136a90ee609414f29d55cc5e4d387d6b962c9ddb8e4aa46f331ac11624ed590","0x197ca446530abf07f01993c6e3fd932d76d47e9831899f95b2a8b82fb7beae55","0xcd30a084aa82e106830f367c2c55d5f8e7f4621cd0405de87d41dda4bf5d4bf8","0xfaf105e8e19a4768ea91034db14f0894358ac368cf42013774f5489c9cc28fc0","0x9be9368b8573145c38cb062085285be21477b1332c377fc5fbf221a515c2d58b","0x98915ec655078f741a93d488ffdcbdfb5bd0193e39b9acdf8c3b6d53fb38b726","0xb692ba481b855e575414e232d88c2848bdff0e7dd6365e7353801d42eb223a8d","0x09b767b73bfe9ee44cdd837cf1e32741fca80118e7f32e155e4315e0123f1fe3","0x3173a0cca15b6072869134efe2fe3ca44c94656a0f59bfce220bfb33c660afcb","0xb4fefbc3bf6c77510fc3bb2886d1c0f1fea0d52fb703e3c8248bfb7c64de433a","0x01cca4296bb510a081c3930c4c8241b552cb7af805dfd836879a565a332863c8","0x89a88c13512d29d7bcf121c4d04c24a5ff2b7f79281efa81c9abf005d550ce20","0xc70aae38d30b4e4a95457a5b1e692c8747fa3f1312bc22d316892c141131780b","0x83cd5b2d0dc023b0bfb9e09ca8c732187ed8017356625791953faae6e228e3de","0x3e1912bacd4910abb9f67a16c2984fbe5da4719bcda0ed3f0352e44aaefa593e","0xdc67021da78ef54b0664289ad47426bdc21ed9d052284c662ddfdb1e76870a09","0xfcadf119f7daeceb83633dfe3b011bcf3f692336c8f0311420cd7cadbd1fdf91","0x548362e136856d3604bdaf2df483b8d356e25d0ad3f8cb818c7221dc916b0f29","0x1f584add6a90eb997396ed58f4e1619dd1f319c8bb32b339175514af0453a2a0","0x874e2d5792f0a7bd0fcb469690271c696ba713573aec52f6d00a8f6b697d7c74","0x8de8e8b9706af0a2d5f01d4fcd3fcd4b254bb26ecf68fe20aba755de496b58e9","0xec8c58ca899d1b8b0c92f4588796207dcc4202ea054be4695e4869d485577ebc","0x9705944ec73d9e5111c09c8a1e3a91269fc16269e0494d0dff528d341bb605e1","0x00c74bebf18654c80f393d279f4efea787a11995cb3bb6bb3e40ff5a9f2b0c83","0xab428f3d5d4e7e0fe906d1297f04df2eb42870ebe9d6616443a4ebc36bfaa56f","0xf8931fe3ad35d362d44a9619cd6f5b40cf1acf4f3d95d0d59d08604c89978236","0x9669a7765b60a8be8f23c200fb653287d75f5f9c06e8f4266f62ed1f9d109ea3","0x57f1c2fa3bcc3926d9430b4496d5824a679a6bd219d2a3901e98a0fa336880e4","0xb28cb0180d03cdd640123788d8cb7fa3d776cd13dc5a189d7076760920dbb430","0x4558cca8061edfc42697b356764d6bb850e8d68a68aa26c5fe29e8a283d46bf5","0x21a668d283bfa91484a3b14670d148f0f6a5ddf8da00c211245c7530570f38b6","0x4e5ac70afb4d7425e82aca20da209b743f3489032057d852b0e43d440b350c50","0x815006b4bfbb8d4f5687a6348592a2ae4899c35f87d4eb1ad1e7fe5c02441420","0xb394a2bf1c80b2d0403a601f002efad68d072db5836df5d2167a54c8d2d984cb","0x062e5a6cc429c85a4efb3a8e613d3ca8fef52911b166fac4e5a8908fd2180132","0xe7a292567f49ff2f51dfb43504c7766895329349cad57db9778d5229bbc93fd5","0xf82bd78c80be44fddd6555f0ee3e305f737d3bc22dc50fd4630c4b41a864ecc8","0xf2069d9e0b06a29ad8ca7f2c6ff835d2ddc27a73cb3c0c662c1fc333f0ceb2e0","0xf0248412af974aeaf4a74f2704e0b2b1896e8ba2dfe59e86cfcb504102985aef","0x2d8dff058d59e06df242e6adf0582f296444d823a6735712f75e9a900bf12484","0xf5c2c75184f0c9834d00927003d403a58a9c40a987cd11656b99564a343dc57b","0xcb6b279204dd88301c6068ee95ec787645a90a0de350e12a3aaea03c15c4273e","0x32b8ee98815c690382b0ad445468b7f370d0df4d3596bd87a1096c97fe0c0cff","0x345b8bfe579ce4349d1f461a54382917b1bc34334fdfda3d5412f8e41ad48fa7","0xb9bb8777694032e90aa47c9a68f96752e78920cf8cd5da0b7e409041947eb0f3","0xbd1f9c6dd49f5f6d2d919adc78872b5897e5ef9050b9578416cd310ce512ce8e","0x6a930d3c4db9ce36b0ff785db3b013e6a1eca94a4ceb556a943759fb8758384d","0x656b7a37f73d3d1c60b74fdd8d083fd47d149b579810e7665f734038777ccc34","0xa766219a3e37315b388ef0f9c7ecc0875cd2bca9c3023b5261bcc3d9cb1a74a3","0x5b02b772a3d91929b42bb12938bc5a1212fc7829e3be26bcf98d787888bb07c9","0x03df6952b2458126363f7f47cc48e4d9ca07c0d6594cae740a0654b820bd80a3","0xf7e23b8ed376488a88f50588b064d32b8ec7925c8af1bc4359f389072847f32e","0x0a1157256ec1cbb7029819c71249d081228790758be406f3f17578a64cdd479b","0x42a61229a34262b17f13dd76585c15d7a479ba88fd81afcac6e7d40eeb2a9a28","0x1fbfa1b7ceed7fe8f26c0f9d77c64f404aa2a15635c13aa829d2344e1f63839a","0x8c5918a0888ef5dea0f2f99c8a03ae2a83c10db214f80905367574be9e809332","0x9d82cdd20a7541e1d5198a484a86624d084eac7848b0099b711f74664b26436d","0x3dcffacf4c42269b67c7ac372c93712aeb281136a9f11b9592891a385f84db81","0xc544ac49fca06fd6dc8f176bc336dd55161855682cf73c28ec3f3f337670f860","0xb2f4dfe04eeb27d42886ae5df2efb6b77f5a70576ed5f7c426b96c378039e36e","0xc997c2bf6def4d2c0a213d875bb54845c57eb3d3618079299c57ac0bda778855","0x7e2bc446e3f3ef627f4f193fa1fd5f5e3ba83ff6e603825711713f76db342c3b","0x365c500c47f15c7d1040c827eeb3c0fccb54babfcb6672c853fa0899ee39c334","0x6871f4822cd60ff40997d66f167cd2fb498f866a80dd4a1ecca9eb2ceb063b31","0x4147b6a3d41cbadce25612ca4a2235c9bccfc809f3b07d8e4af32e84a2bf4759","0x7da190e708b9daeefdc17209d8db554edbd3b73274b818ff789ade9c02271b4b","0xa53906d4261adb1a4afcd602872b0d258ed1da9bf980658b0b20f3465f0b9936","0xc6890a2b8ae38b0413033bf53c5ac876a6a25cd740ae9927dd51c4cf294cc3c1","0xec90483187e8d3bfb07c4e49f6e5319a64ef138ca88eca45774e7da07a29a98e","0x69ef407dd3b71b874ca45d2bc8f5130dc92b8f8179272be4210b84c7635a570a","0x3e57925f7eef24ab0109e1a7ad596489ad92b06669e763047fc358de01141b9f","0x50395bffc859afd0037919dc4aae4d2b1804402cf8b8c4d774f7577002f70e98","0x513879e7e7467718614512c6f3d5d19a4706b03276d59ed4f36d3df297a3315a","0x3a73a3d579cb884916f59d3d206552eb99b03d2e5af2b006d583e1dec7687dff","0xcbec9abcfdb531e26c98bf42976317d7e638f2ec1c67c67170d39993f6d67827","0xda76784459c701c32fae0c50d748ee3fe92ff8f2a4cb421a45ceee31e4d5bed1","0x3bd755fc394d73295d2b822616388177737e6993f5a496e853e1262eee176917","0x514860bc1343626796a6c9d71f43daa722e730036871ba0c8d78e0fb9c7ee7a5","0x502fd7d1c377d14a91dc026fb65c7d4f088a136c476e856155241ab5b97c2b95","0x46a830e46dc875d7a9baf7cfaa940c0fffd4535e7c3be3bd49f0d0bd9e598bc6","0x690015b7e2b0d38aa1555051ed988a6f91d1efa571e38434c95f96d9aa852faf","0x90f96d53f012d40e33d736c5e948371acf476ca04997d49976f314d048d1318c","0xe8879cc9c5a105f957500515e80036d12c0fd09911f0472b91e21bc1e6dacaf2","0x79edb32f9cc6570821fc5d9f3f963f5bcc81371415751ce4186029c8504f5d0f","0x5d312f42d95b2b2a83cb023c106b99f7140d300723cfb32acae1ab1708992627","0xc449434805815ddaaa6cd75f93ef3cbeb0304f8187beb503c2cb35f19a860b51","0xd6b6e53f624cf04ddad6011c4219fa4bacc0b68e2351706f34bfc44107c44f45","0xf26735231a0ac1205720aa33480004c6f73a18fdb14889d3cc8b30adf600001e","0xbd90f2708063101e114bd204fc3ef47304fee1ec5817143579a41a721c562b03","0xc49a5abeedc587e9b2f7151e52cfe78ae059c28e123822da61862298e04cd346","0x424a387740b6495066e666059cb53ee1176bda277060c8c71b51977fd5fff3f1","0x45548473e65dc960f35aa1e5b7f3fa69f7da57d891430d096d755ef3d6392624","0x62e141c4985bb20a564b079f31184d8971bb7fbf9d77f22ccd0174d83fe5cb2c","0x9b76ae3ce0d40513cfd5ee9fda8fa84532bf0cc11bcda36944058b79c250835c","0x2e1da286c39328706282cb11b5eecdda2c47f2da79ad9a53d985d0ce1ec1b645","0xde27ce9073fcce37cfed86dd6e9fbc2fcd7279a7f86e67aa45c23348cc4bd999","0x54ceea78ee3e8888ed920757d079bf6136b053c77aed4df808e3cc521816b5c3","0xb39fa8db1e46919ba359846bb40bba0a79678d39168788e289572cddbefac91c","0x1d6e95bea7571b51156f55a819bf6eb298f46a4c44485ad49cad714cbf4a438a","0xcc02a4989a211d05263b89c99551f04621d975408aa7362b0a78e649b07b0ee6","0xca82918ecefd5c893f7ec77f1f55c7ad4e38b243d277d200602cd5cefafdcb53","0x3deb18568d53b87364e7d647d5b1d7ec057c2b9cb201e9ff86469bf82ca58abd","0x5ed9d2ae314d831403b34522a394972b51347b17fcfffc59e618c95cb7d34490","0xd79a74dc3d9535cef76cd4feae8f29e490b1f7b26d39126af503edbba8d9c724","0x011bf58187d194e346a6a45bcca5694b22e7d89ab00cac49d00f5e5916849402","0x72d969f094ea246c6e06f5b422166d0b84be7025485a056370251267dab5140f","0x997fe5e54843a8debd8245efb5f99f2cfccfe5ef3d9dba4610c182fd1c725cde","0xb6474a01ae843f149349c59133da76849d4fb8223b64f4301a890d957292272f","0x562657ff259f13d4592b9c2b2e011e30e30e84b405c0f10e1167fbd63bff027a","0x51a2148b5f2e3fd420dba7c10cbda0a94d2b20cf7ac3e1a3526d54fdbb2c3cd4","0x8a4fac1757ac781c2212d8bcd0cd6f43f8ef252ae17456ff28da31b7eb67967b","0x5f12a99ff281c28c2fc6abe5f881c952a3d614aa768168403e641890936434cc","0xd3dd9614106bd363e83f947054fdd92839c4ea21813c58c0ab2646eb98e98e6e","0xe3db645af52ca9f05d3ec3336baab0046323c643f34d2fdba7cc704ce5e560b4","0xe8b486370dbfbf244889fb5d52bc9a4f008504f85556cd95968f382486095777","0x02a5bfcf66d11044d515d4f94c5d3a350d42aca09896e864f187e00c4b7c7c15","0x36b0ad4efc857ea532f6004c37f114316cefca17f0032aecdefa5124298f497f","0x28fedf5730a9217a3f49da53194201932f477d4729f984d8a543133ea7f20d91","0x201727ccd59db1fb01e93d4da11b9b5f51b152e2b1b75b77c4be9f31e157460d","0x3ba3ff48da4f46b4ce280fcb496f0b7ab6d4539da1b26c58d3235f002fa3ff19","0x25fd50b136452c982d6e763d03774640379c100cf486d2505504dd268fe99d4f","0xf16785a82a16eff11556ab59ba0725776b78bf36d5104f18460727891d378c60","0x611d106d65b2e09ee17575347e5edc227ab9289e9b743db87cc98ebf97073e18","0xe7074e02efc4071584ca603cb9c3080937feb74d5af90db0e17c5648e9bf26f0","0xaca15ce779991960eb0f8754c332bc520e4c58bb93f25c85f1974aac09314803","0x4d79fa63f6009bed881f2fca6e96dcf4169454669453f934aa78088af8ebb06f","0x566cac6e0041ffccdf5df58eb5fa6ad6da8e1a7348b19aacf0f89abb9ec9ccac","0x5c1d2fc583553931715ea2f6c157a79ad3848c4ad6bfc38d5f00723bcd55c3f9","0xfa7df5f8f545c0c1e986198d63a4f0b3ec87ae82869f5c27e2f91c717f81f825","0xe229908d860d689605f3292a62d3b8e4ec8dd3a856d0da6a1fba2453ea217feb","0x29e40528da6afd837797cac58642cc7e7f5fa4706767599d6c044d7e0ec666d0","0xf61e87ebe53a26d4f54dd7bb602e06e2071e75bf3c42af4c2c5b5153e277527e","0xba360df45c2bef070b2cb57a88be08fdea40b5555c7b720983fd9e04613d612f","0x9ebc5734174e0cb59dcd535714feafeca729eb9df9ff0e32c3998b96b8b4f2f8","0x65a4f856e3b3ae68faa27aefaccb6d53b3f65243d5f3edcfafe4a63bd6e73a87","0x6796b85f8bb6cc1d442d3afb3187252db60b53e8b66f45820227bfc695047c1a","0x429f6b4d06f0f16e75764069d1bf700fa5d17c397104c2c834bf276a86324cb8","0xfcd1c3f528c230d40b818d83e1018dea0b9644ffbee3d465019e9639cb4e4062","0x602b39f67716d1d2cdb3487692386d9cf6482731be31079452af5764483b6397","0x7e3f8fdc468e4ba1d1fa9b3d27e0a27d5cf0aea575fb1f44960553de74758d8b","0xd9f5a29ab3084a9b86119370782231ad81d370d6ddd2731eba4129ada3de6075","0x3ef426be92a36cd9b5e619597b6a4f8aa9af70f207f692dbc6251ed019e0faad","0x5d2426c304fc4cb6dd1ea3fde29357e0e9c7d825705dd939bbc357709a300a6f","0x4f96e5df987cd14c636b36929703073175241655945590c60b595b4b6eea3cf7","0x0d584ef104838ec239eafa89953c7a1be92b136456471d8d704a256dde71d41a","0xa93a1a8f28f41352012cdc4f9ff4c70306adb925f005078166e337355eb256d9","0xc40406d104e0b96b98eaa0f3e0a8b8e61c009a7589c831d86b4ca75f13f213bf","0xa2f6929ce9b7d88277846db6517828c0a6ccb802524ff30af36d52cbaf75fb26","0x7336b6f21c273c4da62fe5e4b1939aed805c0b48f6d3e7965aa4cad96e651ccd","0x0155f6e29bc0b74b8b9f4a7dbf3a05b60c383f2381ff48a2e30d744c3d54a8c2","0xe667f96b63b817da8a3f4ffba2947b55da6e9c63e4c94ea38931d83670e16b5b","0x21df483d8dc4203f8201a7c9d1373c7a6eb7934fde3258a05c1704da7d835e21","0x3fc56f78ae533092a6729a0bfbffb7c60d83cc7fabe41b4668418e6d50767032","0x4b5885dda2537a7044d7e67fd9e3839026c30414ac5c060885dd6387c03aa852","0x486611ab1967911720ad6f06693ef280a86678370b53dba2b16878762e326689","0xd52ce654f3426998f5c8b55c443169d2afe3648d5c636bc67b4683e83a1a4f1d","0xd362d89524f1cbcd2c8b45c06ee27ccfc7e02d84592ee7f6f151fa6bf5064f73","0xda3cd28ddad867f9191365f4686eee4ca0729a265bb2cf3489ce27fd2ea42f5e","0x29abd8b5538f508208673ff1525cd988b68f7e257a1a1bd86b0987858bab09ca","0xf6c745cac32723683ef63436f93306ab389da41d7e845f6fcec319dba85eb601","0x8f75a0b33a168ade9a7ec109ad8ad3536a0996f038958ceeb310ab004fb01760","0xe39cb68bc34146951d2faa4fa13a61ed09a5e5d6dd8d652eb349111cd29e746b","0x3d26309acf915cc45916ecf51e7f8293c58ea89d7ea51af711e752b08fa252de","0xb913542a8c02ba36a2df88eaa0d7142c331b0e3f035ffd832e5ed4cd2434cb6c","0x264b418cddb4b00d7848683ef6d05f9dc76d93088f6636f55cdb727ed9b401fb","0x98f3ae2012ae2bbef852b40a75376bf41a94d32b433587e2f2236efad15a6d2d","0xdb57ac93fb6a71017d850727869dff11a639c74a274e9c571a708f4ebff34e26","0xef0799c2bf563094927e513fa1f7d23e82376665342b002c64119d7d7e5044d4","0x81fa62e9453e51b90682dd6814a6a1b733e4aa7a5f47683dbef105ebcef3356d","0x340531e85c0eebc710de8665ae8a44722cca1967ff4cbaf9ed564c567971e7a2","0x46110b27a9b764740f89f3e5809b28bbbb2068c53eb8e1a1c7da83715fb32cdf","0x63003cb1a4b4374d3ce0607a71e5ab35cce99924ea555617a633803ea50e5b7b","0x088d6f709589d0c1a1b6f36bd482008728343a58549a83364ca736e7e7978173","0x7a9b6d3e6151a2e657f30e9f6d0211d77e164359d883a18580a81808d143032a","0xe64ac1ff94885336ce7adf01e2f29e948036582b08e7f18565b0dcd94a612883","0x071f13ab3550f3422ca7db078bb288f24e8ddfca9cd9768416c6f22fc8a9c8d6","0x2afecec626d2321e510bf76d628dd95c94765268d535eadbee73301f9cfffd37","0xf9c4e050ab7eaeb3abedba9f326faec47e52131a7d8a1cecf90bebb204deab8e","0x8901b2d566310f5d9ddd7a7d707b3d8babcff81a1a4419543bbdaaf1e0b390c4","0xe7dcf74ed1bcc3f53db4bfdcfc227131e1a95aa12a9a26a3e4988d9967db6c9a","0x267de43bf567e6c998d67449607e04a00b2094f18f8e5f2891ec1ce47bda4875","0x3de804d79560dd3e4301cb656e0ae17ea304e68b696b821d616a1df098066c43","0xd16bc7a55138fdca29dab6fd9c2e5f7af07a5bdfaab2dfb4a576ef8d274eb006","0x5c6cca34d8f06c6ebbf3caa4e900170762b0458adbf19cdb122508adf3b7333e","0x55502c32c8c54602769ad934e11b9fa29f594d47de2d9efae8fbac06cba04dbb","0xaceebf050091df0fcdc6ef6d1ab1b6be7e58831a82ac3a27a51aa01f22314d9e","0x5d1f11c3c7a2e50107cb58c0c02bb15d2a88aa1272c0ec353c86959200ba40f9","0xc6e917d5c138026360a4cdc1b36d48b828e9d88942582c5d9dc8a93bdf77c2e9","0xf56478262b33fd61fe6ed0704247cc3018c7d726ec19c4c42fe57110e6f059ad","0x79fa042051373c8486ab362dbbb72a61f56b7706c8f41362a8670305b638c72a","0xcdf53446c05ba740bd66ba07a7c9b1a4ab714e0de4c95e519afb51ff3afd23ea","0x1a7c85cad11ec099cf4495e72f9c2a63d15a0c1b73ed293b048df48337b70711","0x547f62798f46d5e9fca984cfbe8a5549d738eb24f25a8f4b13424d4c17b079ad","0x2aeb90a432aed16e1c8c0a024adaf00d28cc819acffda0993fd2e6f9c76f1452","0xb3d8e90e9de6908ebcce515ee46b590bdc4ec66c7f77e0d28b4bd1c90e9119c1","0x28ffba821af6d47c8b8db9739431e6b97e29af2c2ecb583d31a26310fa26e53e","0xec18d5e338b832bf3ce47673f73c0763967a63215ed4baea179c0d8fcb6df4e4","0x83ecd7ffdfa041600ae6bdca3fd8630352e191feda46c6c106dcad267443f2fd","0xbe292d690e2038e1e5530d001739fc066307f6c683674036b125fc662b637e1f","0xfaef339ae7e808a42dbcb000133ae1111db4d36593561c5ac75528e01c0fc0b9","0x838f3e8103963d1c7383a32db3f61f6eafa3309cfe512cf8b8fed3f460c3db68","0xfc463207176c996efeeab0fafabd52fb141d8f426fa177b0e02210f1b0e61b99","0x2a363c476cc5f087154888ed37aa70c2781230bbce767702f9b32fc394bad0bc","0xcd7fb179eb3893e396e38c612ed605b8b2ed65188144f9b12ca085f99c373eff","0xcb8b7e347e46dec1ce7d8aa41d1e0a5568d32cb98acfef30e278008a02566e27","0xd8c98dc7bdb467e284d136e84e8d0af9a1d176a17825c9ef9ba4f2395747c1b9","0x49ac16ff441ad407aef14826d9958f30263175d98fa4f136fc62b722fbeb5aba","0xed5265726cfbdeecf6ebaa19d99b09798b0ba4d2cef2e38f2c09b5e7b5d53056","0x130ed86b0f863bb8196830e3f019f22cc680f25b90d05083a565363820824e13","0x6b4e6ab53fcd109b3eccb5a62b0e7bb94256f6bba66798202364c524e47f09db","0xa3af5d9d79114f01687c9b8d4c139ae2d47ae1cce71f123dbbb92836a4456324","0x84774fbf107ee10d2486d891a2e0d5fb1f10dd5683ca3a41a6fd94a51f437aac","0x9f189375bef4c7d205cc8f560e054d07e79bd8b823c7ff9a26c8aca4f91d734c","0x828c0178362a80f927d2b133d4ed5ea83c5cd7c326a2dc0cf03787ecf18231f3","0xa917888622bc9589534f319742439c0404d3dfa09e5faae24700f9beb634cfa6","0x2b1104f67c9aa3d03e2adb313567fd15a52303b7219b907f3d87b1aa99080fb4","0x2ab139c41c4fd7715ded3d18857c36d0b2cc63201c6ca464615e84a6160e4c4d","0xc07a4e93b26eb4a4e5a289781518211169a8534ad21e81700e611d8bfeee9fa6","0x8f0905c550c003f05a52c5b0fedd8a50db5f00bb0363cc4f8ecc4d4f233b857b","0x7f0b65cd3c04717b4d3080eb39eeffb0ec576a03f35907b521b08092e0f3411d","0x65e9a2b085dc9dc477a589b77fa03c0fbe7e462b0abcfb870e70d623544c388c","0x6f77c80b5d588150411c368741ab9e304926fbaf521defbe6eb8788ea65378ce","0x4a842217cd34b034fc688cbe3b79b0a8438b48569ee088cea42118c32d36595c","0x0779d818db2c338d0a045bbcb00438c6d440739d3ba07a5e645b4db4ac52aefa","0x3c5db30ed6dbb41292ea6bbb1c245fd1695017e1e329c6dded5d85eaf497ed92","0x53731953584cf84228fde312dd4f629ea6a161956a532a7b3d1e88d9b5886e97","0x1a36b483f95ca989411dc2a17761957c70097c98256e3bc241fea1b72d42ea68","0x8dbf48f9595c0aa5eaf00f65428a7607e6e481ebe0c4f4def82b1876ad91a2ce","0x72e636c4baeb0ebcf537568e69eb8d3911373cbe44371610dadb19d9c96397e8","0x145891cc43449c55fd97c6e7b4aa1a679d5f6147dbb762b60a3f37f812df6d77","0xbe6d63cbac7340e07901a4f03c0cdc59768a020efed335f815c78679c0878550","0x59c1a2858520ac90eca28177d75e788abec3364522967b2d83b072488f9e197a","0x5bf5cf72d5012f6dbf5002519975b246bd309076aad41750584f170dce36f3da","0x90fee0f80a80866b8f438ba269e66ba3fdd914d77c471a84cd70a6541d4cbdf3","0xdea80646ca7f29475e98081518e50a88ce20d784865e87bc275ba5ec24fb76a1","0x69fd34e2425c795a0ec5ec8b30c30d11b4f17da32412231ed362eb44737aeaae","0xfa73e4c8f688512cc0a1f4c2f821bf62cd9a2330f09b2a1699ca2864e8ab1d78","0x67806dee722636c0d81433b949085d144436c220c0bdfae5ac7a4a80a9cbf81a","0x1356803b983ffa7d57675a7da964b10c572d679321bfdd48b7e9f000c1756347","0xad82515db867218d1d03e0540b5f5abc238a6777e673194afaa67ee530f29046","0x83ffe5a4550fa8e551e6eb61ce6aa8de4ab411c27fea51fafe1142d5d142c727","0xc48e64030a03ce5adb1596eb9caf7a4c14c90d4f6e7b6ecd4c19a0b45567d5f0","0xeb39518090c21c5134a806e745df99c37f8b79566ac0b057d0a80a77f74cc0c6","0xf48d6b8c530895d96d71bb4f1c00119a102a0b84311f84e13409543d460931d3","0x70ce898e6b3a93987c494b4a5f61a0a0b42d2e857db087de2df41912e98cd79a","0x4500e50b3d67550959a3faeb0d3ff803d38698ddd73b2a104c5d8d86a58a70a5","0xd16131b8b37b4ae684ad27bf671e9f512f1416a3de9285c81c99dfd12287c922","0xc4f8b4b8815e1dd5a828eeec7b346dd36595727f39b39ff94c982efbb8a31879","0xc04c3565961a6fcba38d6d29004092fd4408e56e868aec552c0f2d82b57425c2","0x65237c56b1d568075a245bcfa78aca04c07d809f5b6dc953c34419227dd01437","0x59dc4887cf01a9cf7b6f5350d32000f2911594abe8336a0c47b2f1731ce33330","0xc3ffd5ff8cd6b5372ae07fe909686ec3ea7f5a335d917f8f3f629910a95dcbd2","0x889847e9c9dd73f5666bc9d75ac0520fcb1b044e8e0f6368306218f449e6428a","0x64db51310e97325443d13242d3d0f1a79b4e8fd0c7e5f4d007cc9c8d9db5f4ce","0x33ca7229fdb5a21a6838aa87866a259ee8201727e3809b758b6c8767b2e97d7c","0x35d789cefa779c48803c1f31c3234dfb2a411a28fcfe27754cb90de384e6e27e","0xb108cdc20f49fc4fd53a84a67283f7d49234ef20fe1707c90bf01016308f027c","0x2f6ff20902b607c2c7de23095c1378677852ad6b5f724bce96fb03d8e92c7433","0xcf19542c97d0c112d0b06c27bdddfd958afcc0b1ee29331df1bb480e9c0477c7","0xdda6ff8189a23f10ee44651dbf91c914fe2cdadbdb7875fc624ed91eab0672cf","0x2a8e550bf5a0cc32c84f26f25a0944e5fb3724a6d4dc23ea19c9545a1b8ba59b","0xb615154a514f927191bd87d6c61dde6d747910c1e31a445b6032db2576bd5f1c","0xfa680d2a1f854917f339d56c7c221b64fa179a9c8488eda1341c0e4c16f10c18","0x5001f95bdf6d2dc1d2e0f73458030c30b36393cac82b5812c37b726b4a2b0e77","0x58fbc48d27b0114a09c2e66531d48cae03fe029ed576b2b751402a4e1933e5e4","0xcce53281b3ad92c5926c2f36b39f764d632dd9aef8c3cfe6b949fb8251d91be1","0x71c09269ea98a111a67ba5d71fdef1f827a050c11977003f49c0721b519f706a","0xa87bece1f99c87a6ca1dab52bee0420b327ef993a65fe8ed6cf1482b23c4c4b5","0xdb25a765f57084ae6957e0bedb0c6e7390ae194377abbed7297b670f60c191c3","0x6d3c2e9314e1cf869e055671d9788f75407b92942f5721c39fc217c58cc77769","0xa67923fba0d9fd7548017567ead76a7f61ebf758262a0f69e3ce87427a068c9e","0x73e214694ef458289f0dc0a3115a1f869c07a858e87a09e9e7779a64f9ae692d","0xa14959a1de597873c6afa1e245b2478f6862dc3e599891f945fad8ba3e1c9d01","0xb2c0b0137344687290c6c21eee78c334408d774df65582212906bf8ddd0d2f99","0xc86300a80b0d46ff75a107b9f566acf8a9b502d1a2c322535dd428ddbab1a0b3","0x789f805630a1b4f23a239dd9d5e85aa845ec95b50a2717028e33b3a4df394c00","0xa7b541581715955dec1e688e3e11a59d6c312274f71bfa05e7e653b670687d50","0x11ff395b7e7d2537cbaed9b8f0a88d7caf3f7bd35f1098176b815601d3dadffb","0xfbef1666559041a854bb77a2131288bb601461abf9e4fc1f3cb7a31a250c7f40","0x6a59e2745e263a9f2ff507b7376cb491dc8e7e3094dbd43b8e45aae280b5bb82","0xcfc6a28d072827d0891b202a653735781f922be15710d19edb6679425b57609d","0x6b1964559a26f0bcd0f0b4d66dd1edcd989d590135954731ef85c06f59192952","0x93d7332a0938d12e0af412d0e166ef4297f3828047578c52877bc17dcaef7183","0x3777550b953f0034071fc90394d684a240db66e7010431f9d3ab44ec820c5742","0xd4e1bfd18839a3b26cb7db486242037376c270035b0f7de2895d3e114a0f3cca","0xf1088e65dd2bb858b2c67c14b33509152a25d17b5c291d0dd040c022483cf246","0x8cd1a3e8a249031d8c7dac0752cf81a2f146889296ab36e112d1585f8d2de397","0xb9f31c87fa45053ff9c1a19ca92e11db6fa592c74abdd6ab05008d11c09b619d","0xccec89c19e5653113cc318352e388f5f96e18137826d002ace31d0f389c03864","0x567eb91ffd65d0c65da99900341018ffa6394c134454367ec8ebc8ce2791dcfe","0xa9d91b764c66fa8145e36fd1ba258fcf698185fb2616af83ba967b9f74755171","0x32e58b1ef3ee8f3ed13be1641066f4ed018b763683e227c8112fb917f43137b0","0xbda592ac266de8988d065442fd7941a60ac110c75b924a1428f5fce4c00ac4a5","0x61dbb3a3d5513eb54d7bba0cb2c0f576719b40f78bdfe699933b9e4a0a515c62","0x1bceb3ca54beef22f78576eb0180f1cbd1b4efd5bca5ecdb694d992acbaa6bfd","0x62bedf575f83fbccdf22acf68bb281a2519013753a7fd6f12f29a9376e6fc77c","0x2d99ffd5f801048903945a32c20a6d9a56e414284fc75a392c5693a8970993d4","0x91a940f729f7ff4cb53453086c4886bbf71c012381d6f8e6bea0420936045c6e","0x071883e9a69bcfee26884a31a7538b4355f8555ba68e119d7888ecad57bab76b","0x3b1e43721c1bc891d3c256ea02d81f92d9a5ce0aa9bf015383e772849259cd92","0x64d7a5735ea3bd930d6199a247802599c51f9bd003fbe02364e6dd90577b0703","0x765987d7d78214b7cf9884ffce47f6840c25b191d6db131daa68cadbfe4dd3d2","0x7b9f1e7a79668ff97ec28f24ed58d632db496a4ca0a66c92fefd62f5b8e27df9","0x253026280380a7bbf04b76abbd87fb7873717e8a2351b3fcb69a688055501fbe","0xc6bc3f8c1dcab0a772a7b5dd624f9340fc873ad24266de9e61db5392da51642d","0x23ff24b24d593845f3c7871f5ab3ff7825ca5c0b7be6678e1bdd9ac68a4e4c95","0x581fb007e5cc81ac39b451ba968f2d7a7b9f61928fb2d2b6bd01a20fb58eea3e","0xead6b5337b03ac957446bd8a4cb4beea237883ded9d52fccbff42c036e37afbc","0x178a6f994bd3efb7e57b4e9a898fea5b392c3835342bbad4fddceb76477190ad","0xbef02acae652d895ccdb3f70573d7fe7645a7353fcb2c913be1d91ac9d7c79cc","0x350d2fd3b209aded263e8a8e42c259e2e38cfd0834f71c911df80156336079e6","0x8f62e6c9774292b046f190eda137e2d290f128c12b633223e41b5365b57ad86d","0xf6bbd1ab3fad49124394350c36b65072172d8d7ec0336dbaf5974bd5eec1a316","0x6dc823b92cc789d781d997995a9aab65c822b2ba86d503a0d2a4870c0bb0c2ed","0xe2c95523c89f75dd02c1ae0907021b3a3e08494e0933f9b450d34640e94f3275","0xd6538f19f68fbad0607e0d45b70e8a717a4ea152fd55d802755ec55fb2d0667f","0xddbe7735da2b25d56e4175514e82407fab7eacec6135621681e06b21cdf5ccf3","0x5789df09801eb49622ae08cd6ea3509047b5d3f7e15716bc4432782350b670c4","0xd84aee7d626aaf9bf907ab4e62a462cc67738a32481c8c0c40118f3fbe626ef9","0xc787160bef3e53c983c22f053227eabd1ef60e473d29c1ea17b09c30c05c7bdf","0xb830f458a8eb9628cd91943f92a07a8b80dc610302afbd5b4cb9042414cbcf1a","0x210b8deba5510e256aa2b630ee8243553a94be00cc8fba1e9f79efc1f4645d4e","0x5beab2ed504d73bf2d5b71959c4ff082b2d868eeaef39fe87413cad6bb21231a","0x748779af9adc9849a1647e0ea3cfcde3e50d3b87a0346213c67ea53c052dc7ae","0xa8ae2c818bf7c33c8b3301b43e66b9b8e6816e342855e83ee87e65e91eb7eeb2","0xa6017879ec1eae873774b97f93cfb854ada5ee7851d0f0bea08da62b5eb08aef","0xae77c0d0a35c76de0517c4c80c65d1dc4fa5d6da6d9ba526f30fef89ff738657","0x2820da7892afbc450cc9ab8296bb8710e4a7b46a47319deb7ec5dedc7ca0637c","0x9cd872dbd0fa893c40c6be1cc264bf28d37987972cced5071380b8bcce483672","0x89497a29383001390e0b33fae3af5ebf4aff790f9b5a683e3e4ffd4601e014b8","0x1b0c460144d02ef0819c425adf28bdabcbec6b504afdcf8cb10f85f01ba6c632","0x8a951ba096b330734e1f669a2c480ef1280ca1f9c455fefcae0e351aa72d7580","0x1ccc1c9443f947db02d9f0991731cbd9b6e9eafc47dcbbfd3bfad40193972bc2","0x67447ddef0ef5f7c6aef0a2969f761aaaaef1a4e708ed2f76dd0b6018d09d9a9","0x45704ce0959f8a8fd80d605deb7a740660a429968decb88d615a373ae3fa6b03","0xe1ba6d94b4dd33b66ec5469a5d39abf420bedd6aa14fa134f88b74c20e3e2e8a","0xa2c309991e93728c8ff156b93cf6a3cd11d536cbbb8d00d2699bcf30105ecf60","0x0c027d4d4a8a8d3f719e30865601d1554d804dfda464a5060b6172c5b09aa339","0x4aa7e6ba6e1e56d15904594d8433d8e66202530137e061ba11ac1ce6a16eb105","0x34e9f52de0c97c0feb43f12306bf5800274815599887d9d7f6b8305346da2010","0x9363428216fe1db1c534ebf6fba7cd17320501f757b4eb9553f5350006e5c9ca","0xd8820d8d81c0a6f8f3ca3e33e82b225521db55b667c88a286137e071ba5dcba1","0xbf73d4fd691fef9b240c0323784fd4dbf02bc7a781eb2ad1b4ef798452f3b60c","0x031f797a328a8b47179c85530669f0db20b5a1f490da581c87c7a8e8cd5a0cff","0x60d2316df090bbcafe3853679d16335b670eacc74e05da03be544eb203132d3b","0x3d5515245d87838225ab838f4fbdc2e072f02515b0e9f22e55f5ff9c8d885522","0xe60883b98113fa27247d1e1a934f3a9a80a629be627e5dc80bf750805ba84ef1","0x8c403c950b471aa9db696a52a8e8b0e8c4317439d25469e7e276d10767a45263","0x2af8bcf9533d1d63143d4a03dd2a550af70394f866fa13feb53baab127ef02b7","0xb3cea28afc9041d45faf1a2e311a60f8ac7e9960360d45f3611e8250797e13ab","0x7da9bb3b6d503655ce496d38ed957da087f77ddaffa30a82b5b33600b2d1dbab","0x332a5b869d7ed901cb13ad9a6d47a08452438486f8b077f91d132b51ae1c990b","0xae5134ea2e35459d5f1e0a1dad8eb1459cb1f2b0116f77b0c38761f35a6e3901","0xdebc492da4bdcab867dfdb2de0b6be57eaf0b7343743d2612557ef0b9ecc2517","0x4c990517cb2e28c21aee6be4f143a5799d907cfa6a0ddfede0a00d6650a2dbfe","0xbddaf6c61e0069fc9ab3f65ba2061952911fe88cf29cf55390fb0cbe82383b9b","0xbb7a9c2b23e4d2e0446cad49f591e53a890fc63925f9d31e3ff0bd3b6dbd6ea7","0x8dfdb7783f9c3adca688142762c4d20ac5d00f2430c701098a37170a6f768c09","0x519c46b67d573c9ebd2ad82666d96b6283f29018e9bb45c98798145042c50d66","0xa1ee1ba7a79517d6bcb660d33901acc696bacb064311691a58788c4a7a30b02d","0x896a2aa3273da6df6262f5bd10d93bc27780e9d3086f227615a74a54cbf5ff0a","0xf870ed6c6ba3e55600d9c558c0fcc7428f42ba5582998e5f98d63e682efcbb0f","0x13812ed42a9dd2f6f94db253a87c10c7e0d72197187c480b3a5fd0c150b69fb2","0x05979679e55e965df2a6ded02e8ffc47c461e883ce51fbac866d7fa580fb1d45","0xb20e2ff0ec44026efca65a8fd9eacd268780e22b101876a868fb8de4052963a4","0x8167b73ea287c2f379fc97e6cc2f88fbfdaef0061f1d7e593e69881e56302fbf","0x7952dbf232ff3c7846adba39c440c71e988fe10da1ceaf55f1062023270ba1b4","0xe9493a53b80edb27394ad06964d75e39cebb7b419409c7256cca2f5bf4057613","0x88954355698fdd0e0c194fef738f065b213ee8858468e473354f4967185252fb","0xf7c29e8f183c4fd49262d1de83cae2b1af44dce31c0c91aa926f2d4468e74516","0x1a21e5b5ae8ebd196b2528c134a14bdf0e3e07d7a27e862fe555d76dd1320170","0x7ab1af798eb056e0ac3c0c495a1d86b3e9b41ae948c9bc91faebddc43961aa1e","0xcf1ec0bc7fc926d2abae3a7ae3929c094d075c6b88a1c27bf34ed1ae2be4f8b7","0xbe7ce1d6144d57f5aff61c68968e5568d8c2d9613ee0d9723dafd3f18fa74c76","0x9e21d3e7c46526da1354d2fcd280c7b5e681f9a17ea5cada95bc378152243b69","0xa16aeb847b2bd20cc6354328dd51fb2177882226c345e1309c3b9da6ab5b0a93","0x379ce5a735c4a8fff46b93e776436a8ca798731506ccc2a6ce87bdab4a5fc887","0x89dfaa8918bc14a0bf3307dfaf5393155119cea911747181bd5967a90542c1e9","0x324bf76b9783ad3827d16caf4ed47eddab5c271c3705dfbd85e2b832ef9015c0","0xf57061a44950419d09efebb0d7e2e7927f31c427e2febe908e8706ecebd4f972","0x873eb2353031e2475280fc4f2ef52ac8dd5543b68d0df1a5b5f36fb043e2b7b2","0x05ab06191dd1da04ccba3fb4a249c95852e0de12bb9fb310142ce9e5d52f2f95","0xb61662275f7213c57c3153fa9e83978f7eec23ba7600404653fa1daa3e3eab54","0xe85ffa219c9e0fe480a71e9a4146b1d94b85669fdc378bc7945082a00fb310da","0xfaf540f10e41fe2a1dc728cb93b8127d3cda8ff8c82ada69c9e5c5a056fbaeb5","0xbb51fffeccbea502cb2c5e14ac5528003caf80abcfa73551278fa72f2b10f4bc","0xcf8931ea18933feb1f03ecb87751064287acc64b9ac36c1ea8802ee06ede2ecd","0xbd2e3466a16326b2c498574a7ab32389b2b9180bda1af09a0378e50d39dbd4a2","0x73269fc626604842aa281c7d0dbe7250af6c0566d569e40dccd44b1796eb2f45","0xfb3528f4333a5e8c64775a334e6885f5e7d437d77e951857da1398f0dda78614","0x2f0e326e13656df51ae616304d06bcbafc7fc577f384fcf742323dc12df5b2bc","0x956d0d90605ee0ab45056428d6cbf9a56682bfec02cee0c067e3fe2b050a325d","0x507a16d488c44b9e79bb21168676205d82a293968e17fb643005131b1f3e8a17","0x0c3b5cdf47e3dba56b903abf87a85ee5cd1fd55dcd8ae15820dfca1c0062da2c","0x10e11a0b43752684a4c4aec0a6476b8b689eae1e69ce227a0146b8f6ade93577","0xf94cb72a9ec712b74c1f5d639d95deec63c587e147243a98514c5691694aadb0","0x65c98bdb7af77e94690cee17a0d9c20085628a97d435aefb1489dcecba0fb252","0x19fc28a62e9c86e23210b9f274b7d65f46a25ece3e004f992521f470c3e6a195","0x7d8b2e2abf89884168c46fb061f0ddff3904928c0eb44d2ba04fd22a34b01250","0xe2fe0f6276f6dcfc552a0979bb7d115c7dea3865cfb92620f35d9268b75d9470","0x764843cbe47cab1da4a14dda8c141ea5284f0df68ea9a50d5e4f09801c6af362","0xe467ecab821453bc9c607dfce5cf4df2124f8398c677029b5b67805b5985f539","0x1bbe2711ba84553b32705737ad914072f7a13879435e55f7e8e44b8ac3ced245","0xd2ee712ebb5cbaa808037a46225f3dba11414ae62a8aecfe02f8b02f6e40d756","0xdf6253fbaa7e38111133eddce637d093bded99aef876992cbf75b3af66b6a0fa","0x4007f3ec0ea82ed04c534194d3ee5a58b360425beaa64d888c1cc984cc7671a5","0x79cfebdec1e1234e34c9d220d66544fab3bcd94a6c6663ad4d9e7bc25123dd07","0x24e184e5e842bf0b7da0a50b1312e1625554fa44ad47d1a829e335127472f152","0xe5919b97b5e3e977ec55790fa6c09abe2f5147d6e25e2ac89e1c42b7e02b32a9","0xfc9f97b870192f958fbec351309827dbea2c8008d1d2cfff48ef77051a52f2cc","0xbe597447dd724f41c9357ffce2ef24d5eac25b41931e9c24ab4a46178e2387f9","0x756ce67b6546843015a07af93f9038c19695bdad106e9f905f4a46b24a96b605","0xb0a409ef3d6a36c0501a4db90cb012fd84bf9724b8ddfbc998c540ae5e5d56fc","0x837e1f69d969ecf4d593498d57c97efbbf05091cf5c780b53b5e75f202ef1a90","0x0e2446385e566213716897def1c95c05b72a1b318369c455e93aa2488a5763e9","0xf96c74237d15e7f5457eab825d1d2d2d0413d290d875b20b5b06d6c7010dd111","0x795e8eb7d2eed09a3c17da867a009f71a227948fa17fc521bbdf7fb4a4bd3059","0xb42a407b7dcc2f5f62a3d6f39c8e92d07fade29b301055dea92426b6f7b1d278","0x14fc463824d22ec9bbf5566a26a98795dddb696e622bd54d347f8c91271d5e08","0xbc8409191b228f4ab99aa9b649b22643eff9d1f8beacd8e3455affc6638acece","0xb9b92a3046bfb34ccc86abb77003732c06a82bafe0e068699e8f19cc1fb5bf1c","0xceca300a06e1771e72050722f2bc4877baccb15781c8596e89e3fc373df50188","0x86e564d4c2e7399c5ea20831db122b7be3d2c995b3e635eee6ff4dced223f1a9","0xa09270bf6cfe649eb33806c05a843582e58557f2a74bea943f5ef59d4ba6b443","0x876485f06f9536f4bb4726c2d34f1d03375b01fba4750ac77d83c726dc2a8b4a","0xa20f8655694affc0d8d3b8357e8f4dacd726527bb54cca492ca629ffe0f2fa65","0x95bda2d34a4e78e0af09f5faed09f3aa0815f48d3688fb63a0e724243e6eb75f","0x88ad0e296549b7e0c91347ee667ce7001c2f6f6407cc6a8ea8b7fd95b78afa46","0xe9cbb20aa4fb5213f5cb0bf7149d87f74241a8e1404bef9b3f01ace96b042305","0xdac99242b62d79a4f9ab5cbe68abd4b7a12239e12602a032fd8cd650f73b0019","0xf7894c79680f6b66ee6c05fc4c5ecb7348a32d079a85f863960c6282226063bf","0xd35fd182fba38efbf47597ab6454e4c524695d8c85403731d666b7da87280b49","0x51365612ad793b85edb3787bd2078b821129fc376eb7fc9ba52796a076b8d7b3","0x4ecca59e5a4b6852a3f8a1856ac3a8f9b15f63c5f55a961ebedc232636398328","0x1bd98a37a9e81d38cf6bd8cefdae042f47548ff260b6747504d22cced876bd7b","0x9cd2a9d14c9c030058a4a46cc5583792cba49cc8f27da34f4b27a886822e393c","0x9db29993d0f0c0b2f6b66e81a5068b3d261644a062725e9fa7997925851611da","0x83f83175f2033dcb29c2959a73dac989f89701cc129449dcd70b3b30de478d5b","0xefeb8c7e3a557afe8fabb252eed9b4798ee27d620d1023c0342c79fb716be08f","0xeb506a4f20b6289099503fdb25a79335a5af6192ec6258ce208c83df2ca5cb90","0x1c43818b1fd7e4a30080af2efdf7111882c833aaf69fb0e5a50481dc45d0d7db","0x8b4b0a038e092bee67060e04085b072054cc2eafe3f0549c74fc44a596d7d766","0xba023a3edac28dff9edbf3c05b0ea3681074399337e261528ff4a07eddfa5a7f","0xecb2b32931b23ae4fd00acf43352c4902898364ba3116ef2b7b58aa89d57d575","0xd74b7a5e1e67c7c9a0c3640f3132990cb885d1e1010a4dc8d357ea16d86b1f69","0x6f588967cb066a112027fdf99abe64a08c765a3de7f0855bff3a88398c22e8cb","0x91af6ef7542c42a10c4738ce62efc16ab53af8cee4575a064798f72d44290394","0x78aa2bb11c0c93009061240edcb79de784a62b872e1cc9fef18993572e2bf567","0x438f97b60d22788a634373a0c9d9ae6f2ae60215ac8b0984443b76f590425f4c","0xeb8a67c447f05d66864fa994e2de4c669ec38b3e1735eb992dd35763b2eb88e1","0x7f9e9e0e3a1d7bc923bc84362a676ac05fdc453aa7488544650cab0df11fceb9","0xca2d7712491a9031ac79628d854ec7145dd180805ccb42e8a7082f89e0e5996d","0x1cc0d88c60eba473ed97d187d3619bb341f1ad5589d79bb40bcadb85ee229cc8","0x0a8ec1dbddb20c6e4828fa1febdfdede107b23e10d6ed0972ac90c190edf6772","0x52cba7f849a62342eff69eb6dd7c252706b4da248d7ef0d6a8767378bc8d3034","0x6af7fb965624ca22ef89c255b7e320e17dd1e0488a3426be4c75e303a4b9dd90","0xea9628b3ab8d44bd66fc00525dcdc45cb69cbf34ec978a43ff8c3c9024725bb5","0xc8171d1662ded2e95105ba5a2b3d1c75ff7e26c306e8a0de96f85041881441fd","0x3cfd9560130fe7748848daa3e1920b2eb428e5b5c695adfe8aab499aba1a66b4","0x965deb07a96aa2e622f7eb3d65116c12e079d9e0bad49a3a04a3bc5bb1d7806d","0x7ccfde23913f93678946d6d3954cabe0241e3e83db91a199cb388e5f261077f3","0x0c4d4357c788997621d10b571f884dac7bdb52c2dd941aaf9284066586088bc5","0xb5d13e56629682ad107fc4e24d6e40b7c20a89a900c198b802378915fe8069ef","0x376628d85486b6890083eee78f114ac006f8033adc7f67baf96f12024bc8a3c6","0x0ed6c88c78f06786285a4f733a7c038c16d508da19fe71de2fd7bd99aacaa556","0x2349a75e93c6145249d10367c74249f45e3f657cff26418269b142ef2373c397","0xe30bdf1719d077369cd9e467984144bca1d393b03530694333f7852ea8f0aac0","0xa0192fc60988089f640b2a225fa67c165cef4f5ac60cecdd45db4e887632528d","0x1647b89b49044c362445ad26b4c073a6065cfb73f30962601946d367cbaa4135","0xd4eb68cdfca2ce063cefbf7670b22151dec9689cc011906f2b79cf78324d9dae","0xa998bc517456f6e9542f343546051d4fba2fd38ffa0a7b04037e4a7a2f7546b8","0x55c199b417e5e3860bb2d2b0527a05bb81488c42ce0c672e466ee6bc8b84f54d","0xb2dd9e9cc5aa818dd884464189eca0b0e7a0050418d87ca3dc1fc1e4e387e9b1","0xfed5b4fb0bc9c0c88fa314030e4bd8a12afcc73318fc9e664bb35bdfd60750aa","0x14f36cc07a6c244f1fb40fc424b12ee7dbbfa14c5bff2050ccab468810f33d21","0x522ca550e57394f8112db4f8025c8751080eb432790f17d4a4047baa74b05eac","0x27a68403ed028b3ed4db565a5af12c7fa63fdc89a444370d4d889f1a383a6cc9","0x2bb805d1ab8c2a666cc4cd830768cc4900a5e12b7617c8ae6774721b5d015c56","0xd3397432f95a803a8ef184c38664efbe4fe1bd8618505c914226d7978fd48763","0x23c4349a09d5f02b413833b8f8995bcd4c0777e5b0e9ca06f26f8da5a8a0f401","0x18a95ffeec9bd4e1f809afa9deb5d570abdf0d4e34884eead7fbc4775da4df7c","0xcc33191605525e43cc1e9ed84de30dbf5d46c17781df9e1c293cfbe806d19fd0","0xa9a48ba11b17b5ed2227a4c96eb4262993dc524fbbaefb7992eb160bbc48cb44","0x9035c540fb71a54b71f2b62414b086a7a60c1b23a57141dd74909ea7a2bc877a","0x45cf5481f904d8ffb6ede2f54ee84ee7cb565018f43f4281efbee8ba3a0a1306","0x09aa924d0572df80d1b47926312b2831a7072ba7ad8783324a4c021d6b40cf0b","0xe87d23a082e670343ad05437bdd513152dba5cce4a60074935a82f7180adaf14","0x869d6dabb85896eeb66eec97ea4cc13f332666c1427e9d38d348ebe72a68d798","0xe6596cc2f6759336154174c98d9334582bea42a6963efc858d587eeb3884ca8f","0xb164f30707cdb17f361663521a7dbbb29f8b20ce750d797493fdbd436696efd5","0x5d62bba9c7df1e1e52f32dae5b4a1b47d2a9e02d09ee40c55dddde10737bedcc","0xdb692e4d6d8cde9536bf4879de3277dff30315201d50cbd9dea489bdff0fac99","0x11216c7b4a74895e10fe4bcefa8d96dc73459cbf2b766799984e9b717a5a6ea8","0x865445b642c80ad5fbff75787949563fa1a6524ff29b2e6268630246ac2f00b1","0xe56894e766303814d12926d153b01ae0139889f7ad986a41c0f32a01d686a5a0","0x004044f2e37d98e57dd144911496fc7118e779e0933bb84fbaf42eb81bff42c5","0xcaff262b575a093e3def18ccba98cd1c123d09dd2ed7a7d111297ed4e303a85b","0x882f5090d0552d52dedf3e1511539ab3f3fbe99dd7d2e2d776a844580fb9459e","0xe484edd26883b97a1ab4711c668a8340151a279bfdd5a59201bd1cb18b6354cc","0x1421b4b1bd342a79a1ba29868e702c730b5a84b5333f06737fa88654ec842299","0x0ed989e85e71f699e1e102904cf8e5c671e60126f74b6ee42b0ee1eace816c2d","0x6daa7340586e59b8d17a41e3eb8e99129a6b846755ce972d892b5ae1c085c0e9","0x982cad5a350d148fe0cf9c676c920367fc61fd841ea691deaa1306777af04ef6","0x65d4df7b767c3203648f38312605491cec431d3f9a4d414a4c0f6381dfe11cdd","0x7417745675da95ef5b6d90631d12cf74fa23cf833efdc2ed38a56dd311c3dd2c","0x199f3ff6fafc3714df2572ca7190d1e7b22ef496806c87d1e909e8825757d085","0x99630dea5ab130b669908ef222eef06145d92014921dce1ef6943238b261e14f","0x7f7eef5a6fd9712ed45c41a43d3fa2c327aaf4d3cb64abb3c9845a5aa66b03ac","0xdf3cafb4004b26ce42633b7040c66c6c3c4be8e71a493ffb57b87114d3876c46","0xa2bc14195d520afded9987d068e4295a2f09bdf5c64a3258b9bed2bcb4102f69","0x1880059d9eb1608f65c728632bd63bd02158256bdc1a3ab2c92769cc1eed476c","0xefa2278c826413c47c4f95fa946b2475a0454f066a2e759562304d3b90088e4c","0x841b6b7e9d9c4013bdff5c33d3756a5034924aa793cf3be25042f56e4e7da6f2","0x769e1757057da3feda909b5efcc7d5f87e4bfdfa2988b45a238c4de861443c5a","0xb6c1b5d3fb20f388e95d451b90669299c7e921b5ef6fbe1cd9942ae6ff7b73a0","0xbc1fbd99a1be9d13dd83c818f07ebcef6c66939c4f9fa891bf14021f22753d12","0x3ac471336d90df49c1dc1087d387efda472a12098f5d279175e60cd83a3934b5","0xda3ea07bb48bf22eae2b0f28eefafce4ed6a89874583fac7334b1df292c76818","0xaee72cad5e8ee3efbb044ca8ff509bc824ba4cebf8e99d544bc6b02f5dd94059","0xf099b1087645d9a279820ece3e1425286f9139b8474c28a70af78f513e78be84","0xdef30adb9ad7fd55c2f1db2252c3b80ebec64d8796d159db29d029310491f42a","0xe977db6124fd3848575e1b571e3fb93a2bb5aef911a198b8e171f97fa363aad7","0xb75aa5b6f4949dfed2c3afaef841ca5dcef4a5c236dea46edce1c7f21c101b24","0x1be1c983eb7245f41ace9392fad586980a0a5c3998cbd7fba9c09e54825562a6","0x58fe0752c08f69eaaaea270745e6553bb674aeacc522efe230feb46be2a1277f","0x321186b6bff809a7f1767ae0d8d35db56b054068310e799549d61f56c183c0f1","0x90a08fd77ab468eb6e448209a4c39ebe78a8f967b9bb2a9b6d7f1a2c8c2ca053","0xbff7c4d140a96ca22a427cc5dbe3c8568825c2fe47151078f7f652593f0df1bd","0x5b9bb30129abb4e98830ec8dd4d19f2e8e20b2637ba667713e6fbff4d747ab78","0x8598e0224a2a1ae1bf4801374d97b2776c8e9e7d0cfc2569499d49d7e25e0d0e","0xd8fa2a0b799edb6bf6179ced0eabfdecee90f57a008556a5d4407fbbcd24720a","0x0031e4af5bc3aecd96ad65cf44c44d5fd51783046a2e2ab4dc0b0a03df52fce9","0x85273d809184674bf41347e9d48efbc0e97580542f251e7d949bce702851e64f","0x7dded26be6fee4d59b410f861c4deeeb0cf20a78f0c5424585e90b4e675d3616","0xca11bcb7a25885bb523b4b064a19d3c9ccc91b88056a9de724b58640b9d2efd5","0xf7fa64aebca0bc211867b738970b7452de5106c64f79d6bed8fea82ee101b140","0xd0034d25827da2828d2cfc95b2b4eaacc4b266bac367a5095f5101a69c64d0f5","0xcf4094c65e96bc58bc7cfd969229eec78871c61e62cd23a01e898b6ba92711c9","0x2557ca7f4eb438482947b1ad606d0fe1b4878ddb9441762ada46108cf99156a0","0xcdec15756baccf8e5145f752894944fb47943d91678f7346071eff6f25573a38","0x17c6d297dbd3e2602b78b3f5b33c1d4fdde0d31bd2a8f61816c169122885a5f8","0x4892976ad273f170674c6ae83a50a9fb39dcd3a3635ffd74d137013bb0032132","0x7d3b8de532f4991f5ad73c654a4897d4cea4f4d721963bc8695f4013770f34a1","0x807186736861a81a84e1212700ebc8759da5c0c7d604938ce24ba4dff1d4eae0","0x11d87917e23dcbceff4ed682e85b2d8532c39763be3d623c990aa8f782959f99","0x253f11163f214e460b5078f10c4626622ef5b6030ddb4269d606883231d7565f","0x97da7441514850d2190773cdfc80e33feb313024c1ceca2f05954037a2b7e05f","0xc5759ee496188ed0a88b353bd1a49d84b275cd00aa5d3533616e74fb8839e909","0xe26c08785583d7c4ce5f9015b46cfcc7f2c389b99bab6a0eb0b64e748926ad58","0x346103fb6cd74e6538984d9da5f5d13f7eb55f5977cbb28c28276be8226de393","0x758ba03bb4fa4963e87c6a47e9ecadd2b3889722a79a5eb5531e4a5d91ad194a","0x76136f31a1a3a869805b17f4ff7f11295c9ac260acd8f90afa07c72528cf25bb","0xba0cbfebde385e79c771d3ac20b66b46fad270e985fd1e2a2835e25ddac352e3","0x4733f33179b96ab9f276df792bc0c6a0ca6ce192cb5a33731c332ae2f760f6c7","0x95e7bd4f8f9945dd0dcbe0c9082f02c8b158695f9e55a4ac6c535ad7bacd28db","0x5a7dd726a20c63ae75e07234117b660376dd28bb5f44a7066a6370704c719a5f","0xc48e97f8c561dad93272c7b1e9eaf4c28eee967cad0d13e3ae94aa903e3e4d15","0x512e7457df7fc118216794df2d538bc89810fa10c659fc9bd68bd6ef0d19d9af","0x8dc2a6ad61cf8acbddd1b9966177f9e1b410b9ef5b17a78483db46d1dc1a8169","0x466c036fe37d7d9e089c553e180c006f5703a19800a9929379b5b1414fbbf0d8","0x6c4b2e50192dc6a519b0eb6425e298edb3fb19ff1f1c0e42f47daed060b01c7b","0xb80c161e74a7594ecc0ebc67703e9bf5e22e269b158c19a7373ed6e86413faa3","0x0244e7fc95bc0ffe5a8256389417fc038aa325703a28a0e7aa7dafe28e699feb","0x2c4d346ac2aff5b00663c26fbed840888e728f142e6bce07efd1b627d4d81b8d","0x23ac3553193945e9dd2bd911b0554d03fc2d6adb6f508dfc6bb89685335fc5dc","0xdd6ac5cc051cf149b499ec304e4dee537dd48aee1c0403f1b82cee89196d6a15","0xa59af9fe91e03f8b26204e3a4a437c266eac4d69290b948402123d171b0a3404","0x2bf5a9323b44d5585a22416b1f6d480bb714b435229180d5404c2507e4adc087","0x01c4866c2789c9e7ede00b92990d2cfff0b310006a81a3ee91275fc98e40b504","0x81fe6fcfe24e76d3c761dff43e22a459096a86f8acc9d7a89beab4c43762465a","0x3b8498b8de1726832779c0f39b2bf6b93d9a1c9c8f20103d71c173b5083a813a","0xcd4fdf89d3bec78f28262fd6e4ca7b583403cf1d96eb20c9a570adb0b45f1aec","0x55da2ec0e63a30404257ac02d5d91e8a10a5263da98093900dc63bb25f9d9d2f","0x18d28cee25cfbe34d25aa90ebc55686b5529907e4d3a61197155c896df6dcb10","0xcd78fe82712af631329c062fb8f10a8db791a16f168aa11367cdec8aa4c8c870","0xb70c6a3c342500d3db0fff7a16d09f635d5c90ff61930f58e29c9a02b7943acb","0xa19d80bfb85ba6a5d2a02426784bb856f5b45173d1a44be710f2c046b09ae698","0x8a5e3347650e76c39865fd11fdaa6ea0412e250c36e7564a7c344c25681bedc3","0xe9c9edd2b03704e038775d79a7ca1670da1201bb078e6b4cccae10ed3b77fe05","0x975f08c28a5d302ae48b728b2f928458c1208f5569855d47c8ec79b0bbae11bc","0xac1ed4aa3ad7966eb86ebc578991abc0f48a39a1cddfc531745edf70ef9ce171","0x1c99ff1ba511cd5d5f736925fcfd8be7f9f302f0ff9732e6a03044a071b71837","0x771b3945602edc385bfdbedfc9152cde5b1987ba8316a36ac6ef0f25220b0c90","0x9bf15895c4573324ec244db136a73c827a6fa067412b4564b652f68dadfa3ce9","0x3d843f6922d72e04c3ba69f0557c5c1614e3104543ed98f28b3e3bdc4cf97042","0x08ceca0792d69f9fee8509c22f1bb4320856fa01bbb3c452c2f492551a552765","0xa3c86527054a450f8adfb175d20fe2988166bf488aaf37f88de01c41b50f1a54","0xafa22b96361df58d64f015a105afa80b30751c7eed32f515ad33c68124b3faa7","0x4936c7ba45c54924baa4abc2b333a17b1ad9ec74156a3df72e0306f73f778482","0x0ea21f8dd85218a3cfd63c39dbd6184458fe345304747d24bb904165836d962c","0x5f52e018002be82f5bab154bf27abfe0b864c8f2b1e76facf6890e23c77d036a","0xee5b2676cb5cb0c6e346786897b7068b601eeb997b98df3f02ec4ac0c840888a","0xcef8608c57a7b8652230df92dd386615ab70390650c070f6635cac75ae4d8a12","0xda0323330d96c1cdf2390881e7057bcbf50365fed440b27b4eda4b2baab8cd03","0xf792a33a77b9424ac5672568aa310f27932adfec0b73959bf530a206e3fda028","0x0140376b66764738eb29ab00844cfe26a08a5b99310ac87f6ecda09d0990fd2c","0xb8932c35ca4dde4b6bbe34898f90f55e2c6381b866879f0355f11a011086a29b","0xf25b29409f8c0a51cf34868699814ca63f1e89fb39bcbcf6771f6b82f74b5081","0xa49ef0c5a24a7f985a0e40b3dc31651fa3fefb04268b24437148b9e7663caeb1","0xd95a0b1d1abc74c19afe478da5daa3d81900492d7b6ce262cf1640c9331b2581","0xb7ff28289fdd1382f79aed1d71a0a8cc61622fbdbdbe6b5d895cde54a1eb3c6d","0xe4e2eeda3e3e8e894925e821946122a2ad193b9e565fc7d7a00beb97d238ff7d","0x62dc61e3ebf7d3dbb630069443c9b9eefe7cc055b7b3840f144a99c649f2f8db","0x5c9f78d6fdf1a93bbbd17e5f9b0d481dcf1299ee9a468f74da748b27e9e5de6e","0xbf1a495a97fb026b55f8b9cb9cc10c869194cf73a572703d0f9bc16e27bf9432","0xdfb603f8695073946afc98462f2f06283a5ef88195451fcb80c20b733f5127d6","0x71edbdead42dc42feef79ac1a83422b3575b22e34e7c1d24f7e213187de53b65","0x957124048ca5ed6973d8c6de4b85f95f924cf8642ce61d9c032ca982af3c58ed","0x7d0c9be43ce1c40300f86edcd4aee309bd2e956ba76a9746f869155fa60df76c","0x2e80ec8dc00f5dbd7b42555039b0a560ad1e90bcbef0dfb983ad5ffee98d7f57","0x6954b9298a02f7faca4660d9eabe6afe0817524efa30edc42edf5fc6b25ffc9f","0x234131182e3df2bdb32dbca22d9e1982d4c8724d76b0bbca4cf2866d096f60fa","0x0bfae40decb1f7add316f3fdaae216f171877becefd80ec36eeeb550e3f86b17","0x4cc0d272f3fc33548aac98a8b6b73463003ebc8bf4318504d138bf2f71631fb2","0x374bc2df592db33ebd858c5c26ebfbc0740654398d08b81c3602af70c41d0077","0x5db2933f474fd6402a3ddcc0284553fedde9a222572b3421beee4ffa73ff50fd","0x6ce5cd2ffe9299995e3d5164a4fb79c2db7f6f3e6fdbc9a942024ad1a1835a5c","0x00335bea52fa9ab89a3bb2a7e5eeb046147227dc2ec507c60b7cb0c4263fae1d","0x70cdadebbda66cb3e94211e47234f3ebce58dcc7bb5e99130cdb0ee5f88c2fab","0xbfa826291a43969091f755483cb5e3b6f860fd266f56b113e4658e1feea2399b","0xad18aff6677d3beafbaa89bbf524087fcc22c1a637a1e6ab7d7ada5af2ebf533","0x5601c81f93fcafb9a2e64715deb5ad0305521d6c943826ff66b5e21497b8dc2b","0xbcddb3b867a21f803c42552409251c3c4517a1ce00ca8f6dc746fdcd895f38e0","0x65d0cce86a02c0847bce8849bae04a275fbf81bb9ca4798c2274262f2fedb2e1","0x9d4621b76b7465d16865f8714915f00a6f658e694feffc23a9ad01082f2e1d36","0xababb9b74df8ebcf0264125b9482fed3e085dada62b18455be2d7171ec9c3ff6","0x72a639ee91f7cd25dab1c218b0d2edfbb76c804af3665441fd9ed5fd59a6637e","0x8e66f5490cef678c1cdb1a78e6672c406a78bef3f25d84df009472885dd6403f","0xb02cc911f4971cba433a26146cdca1e113e3484515d799f7014a73bb1455d909","0x1b2af0e62d8a1c1a8121c9bafa5e84a68f40dd80e8d17732e07acf69f26782ed","0x4586e08b278e9f51ba55ea1540ac632c3193bd21065f7d6b0b7c10141c3d6c98","0xfa8457c9d35edf6241ad5db2887f1498bbc4d92dfc1ab465b6a93ddfb3bbae19","0x96c164118e1033737219af619253df4825103820eb170a6c0bee6f3be554c80d","0x92f04e61c3b0a13c9a9e9e0d459321271109e8a0dbfabbfac7cec09bf35ea35c","0xd9380f970aba630d357bd333576bb11c81ba74ab9cb09bbf0a02a1128e211d01","0x47bf7db10238ee785cc4ec972ee006811e4a033523cce9bce41670e6b480c1fb","0x2d1476baf4b2d901924ad597a5e8e8b4ef5ad14398f71394c4c77c7051a056ea","0x1a02e82acc7c9d1d2ee7480119fc26734090dde3c83b2b3cd60c912289613c8d","0x8ba5694444aec97815f64b179a9b3bfe479b0a93c01e056ce460b1e66bc10d12","0xbd0b6276f887559895b17a22839f7f1c0e809601b3bb7d7ac82683c543d69d50","0xee21a8dafee63387ccd695cb70ab27336ebff66f2a17b1c7af9438c2619a9fb3","0x6899225cebb1f4419357b3ce993bd410ee8c923a23edc83448713ab89c78e7c3","0xd115bf5384070d754bf422444fd8bb40aef0781dab81c3733e49eef2efd6b6d6","0xb24fb68cb72c89ab72ee0dd06662f4a4ce37a09d18782bee87715106de084270","0x19de2dff8264118824dd98bf95967be5a73bce39c4fea78f9788a15d5df89f8d","0x6987de226e7ad342d0ddfa0f2c89288e1c5749fa02a8d3149a14a84af0b87718","0x53a661fd74e173836b34a17917d3a3db7c771ac3e4a28a24ca19891fcce42e04","0xf94b5ad20524b2679efa13ccf372be54d0aea4f9aabdeaa71ad8cb150d7084a1","0x208a3e9652e1efb3a0885f812b473ffc943df43c537a625d7da85089958d7938","0x31f7aef2c1953465e512acaa3c892487d9af5b589fdd77ed7c66c4a6179723a8","0x3a00948b04fb8246bf66acffcce1c7f723ab8b8247078e8b0cafc735a7ac62aa","0xce3a6b3f4e1ebd964fbdb8d08ba31059e7e2e26c1363bc2f8704e3f8406a6cd3","0xed56faf937213cb1c28abd284f98bffbdc9429c62c97cd829357fb443976fa0f","0x642d14de1a156b5c6a5725b69783dd386840dbb10543bbc6607f5bbe5a91f62b","0x84b9b4d733978b493971b0e770569eed23e152dff793b9fced993b2ee394ecac","0xad1501da23eaa2c034d349448d8a9688557c348ffd86253f7a48a8ac95abfe8c","0x2ee7f47f1dfa7fe6b90ce71966e9de87228bd601b0f62e82ee0f97b489629e85","0x01f59fb9df9cb75cf5d7b7940c812175cdb1951d8ab125d01ccee51f71f336c4","0x5bbf0e900c9a1d76b237b7439b0a50b6c9c3975f15ab763e961439605a504e9a","0xf2c9df30d0160c12c9363d969115b2d82633bf478640736278d81301e5f115c9","0x5cf660e105cf9c0c58825338f01569fb541c7d832b3c3e500dc51489e8fd4343","0x3de367df383db311d00050c840d96effaa8884c858990a73f69211a6bc174f95","0x3a6d9ac1f46dcbe468356dda48e24d83b3530f4eb87cc37dbb10de7535327673","0xe6f578a9989a524c06d5863b5a4cc37bdce01b2f2cfd8d000115b6f32f59ba28","0xdc3943d12c775c941d4cc6ab01776395c94fcde3864bf51e1eb0587b3a928138","0xee8a330f679946e72db4af38242f0a1b844c54ff73e05dbc52791da4fb68f785","0xfcdcd27910cb66e2d452113546467dae34c07fb4e1d2592735fc1137fcc1a118","0xf66083a48ae138a26fcde42be0b1d71048573b96c1f17cb81fc57a72be3279eb","0x81e353adba0c3205aa3132d1c0e35d5e2d29907bfe6807372fbf2336a4d724e8","0xc16f290cb14e3cd713a1169035759c49a3c41372e6055098e2bb087f646be7a3","0x32a4a90ece1b9d99cfe85b02d4382ea574e441b23fadb81f1a4ddbf87e27be4f","0x6488b08e8af4522d4ea02a54a6e068a04180e4e881ffdbdea60a9b356f9701d8","0xa4d2b148bc14d355605ce8344a93224f4073e737302ed02508b1c22e37906205","0xee4f60b75d2dccd5b73c2eeaa29f325490ff0e5785c7ba4a3eba834b88223944","0x07aced2183c003bdaa2cf885b18ddb041ad9d527f88415bca0290d4a83e74643","0x88cd8c0d8ef770d4ebed5ac6e4b40453e7be5b396e22426d2c4e3fd8c99c7b9e","0x50fca6a28396e0f68d56bf4c00aed4c419357c079f5d8b102583f5b622d262e8","0xd28a1c01cd001992fc81e44dde12ccecb3e2358027196e1d6cd055a01986e19f","0x8f9d4f34c71d4a0bb01d90247d6183825707fe84da3e58955759598bdee9eb69","0xff7ca5d4031adf9ee65d649ab98770a1358dac0cb4029884b9a85b77e298f203","0x29cc0f834e3991960802b47657d0b126e3838c965442060a99615728425ff1de","0xaa82dbf418ebaafe6e7bdb2e7757e6f36b401d73dd4f55e4b2f7e109d538ae00","0x840f68ed62af609324fa16fafadb3c79920954f4dc94d4ad30576a82b11bde68","0x6bdce520075f1a0650d2ee7aa69aad788f26b85dd771ee4993a4df19ec9cb7fa","0x74904646708d6c8954b905c6e845e2399b824b200f15cfa0f112a1bb0f3d70fd","0x407b3b758024ebf701d200c3bb37f7378dc509c3786810358212639f17ed429b","0xca4170444b1ea3ba0970e4ac20b8e230854e0d1606186279600436ea8b730535","0xc90dbfabae3b3cc87307d98e3bb220cd4555a73c4ef10bd77fa18658c8ddb4ab","0xf05593b82068b53a74d56c1308aef8599ff5b11264937a4aea975d60c18bacc3","0xfb784da94650511eb92bc01594a9e5ef3705565decf49d6b6188df63932dbfa9","0x48d3d40234997691cc69559ad97177561625635b5e52a7144391031a40a0e8f0","0x07cec773e11afe88bf5e9d88fa3b981239307afc75b285c3e5f3b4e8948cc26d","0xbcfedd8214881e293193a0c1bf2e123989ed8eed619f8aae9a203218bce87403","0xbffa2e1e84d8f68ce60fd52209a9543452007a256473f8f2248e2e204a92be52","0xf5caa4d2db6071477811712829ad13287d140e3bf4f2243f6e3430aa2c2b2fd1","0xc21d1602c403852dd43659d3124844a03d9fb9fb7903d57b7558ef34a596c996","0xa82d14a6b0fc98090e827ba4e39dc95bb9da21f2f0cec970c586e959d4a58d55","0x76baf9966ec61d5e15824419c05b40f5e4527aae69dcc50c295b600e2a53cec3","0x5fb403a24d67e5b1e486cee69ad989bc121a968772505f98a16c2b86f7679416","0x523b8b75972289f95263c7282d67135a38f320056bab14beae1da227899a144b","0x8f6e7e5c687ccfb5a236e7b5398381cfdf9ec54dc54be87f0187e20ff7772abf","0x2dd1f86d3019c17b05cce0aa39334365d73a51626ae4a6c9b5e1e864600540a0","0x89355145b37945d95d50620792cbb07ff4d8399871afee2c31228af9c6261b57","0x0049d0fccdafae89248edfd666c32189451ca147880b0c9edc6416faf9a87b06","0x2d2626e8cb868554e394dada3c1d27a2d18485f4e18a848a64f4532944129fbf","0x252bbdbdfd23c07dfefc9c842490e41d92b626c48bf378a1f03e8eb3e9de59cf","0x0b37856e1fbc18a5e9b92dfc4e483d0f2f67dae05c6bc05302478bf5b264b6ac","0x5aaff0f7de297995c7a79f623550985c261c0e7c4f9378a9dfec61de9900f51c","0xf8225635e5a1f9e7204a14c9c4181c0cff74867867df6ddbd29637e093dbbe80","0xa18671ef9feb1ba5b9170e5240986e3047714a90744595094472591375709d14","0xbdf54e1805280426e9284994c89edb59ee64dd7e6bdc07d53ec65f16619edcdb","0xc43525479e471c1e0694805db8d0e1446fdce2b7bef1f7bb834a71fe23db75ca","0xa92a5ff72d93cb8fa3c2f22db3177c00fc8c119f4bf16426c002af1d3d9f5ab8","0x321fc495b802e1a1b78b545c0361ae7fb1d8979b5a13f5ff2f28523167668a50","0x9e1f1d11c943969020b1230619b4787a3b10d334b4b698d2bc0b8b9ed0a78114","0x41f5668c5d29c5c04c5eba0e860c8b9090f1d69f71bd0c8682655b0d4c6a1056","0x3839e60515b56fcc8a803cdd505a2e93edc5ca88d210fc941e093d23f0f5c872","0x233f38042e6478330a63604db936a6820a39fe307f1fe1263b5dc152e1d6bdaf","0x2551efd399da526155ca271f700b692ee8b1d65931fa364ea51cc7d16ae5a345","0xdb51a3d4b23905f44133980994b0a601565d0cb24312da369bcc0013f02a528d","0x812ad46a000867e0a7e869f2a9f3377888eaa1bb343163977537fd1595ff3aa1","0xc322eb9ea2c19e71256407d27a9fd43ee6525e98f25566eea4b5e7e58793115a","0xf30d148088b45ef7fd1db1f5502c4a8a7c506a81afc64fc3202aae81f885946f","0x821fabf8ebefcd211e044630af153922823ffd8798fe0d5653da1494a2074806","0x49393e2d271759912f5d011540f574f5c0f5dbc53a28109678c7a44feffc35d2","0x424736ac8485eb0bbd5df5cba1a7d641f246e55ae1346a2468f7ba783fcee4a3","0xe57f12defb20f1c5ce45411e39bea82c8f7ac63489a5e0c7f973ed992c3247c4","0x8b1a16a68ca48fd959cba4c82d6b206a93cf93088b41eca4c48c65b9c70b8a3b","0xcfee1de9ebeeb0218f2ba72fda1ba4af2aa115038c0ae3fd209e479298581ec5","0xcb48734cbff3381126b80695f4e3433c3c84d50220df4beb0232051a8b9f1224","0xd118301c4a79721602a1b596929ebe2071e4776409b47457ecdcdd6cd93bf8a0","0xf5ebb62467daf005884b3c212a6f138cb631997f4f6b67250d7edd3ae1095c4d","0x5ab222eec5532126957a7828d415128b459fb782e761586ba97166fae4a858b0","0xa8f292e5fa7655ba1d4e378c170435c17a9a276f458771bf6c153c9ace360408","0x1073027222069208ff2d1dda67f549b7bba4d5680af9bb45004f96d7d31bddf5","0x5d3359b1583ad2ba3df287e052fab9c21d9b2db7a1b9be6c021e22271508c9f0","0x00563dc75940f0fa2efa515a6929f4233ab3ea7ff99824e36a236499bf720791","0x4250b22c81a12261e44cb1d70aed2cb031af3ef276f538e5ffe1adf334236493","0x47404945e6c8aaa9eb0b3bcb52cc09fe0176e4d1e6ce0486e221f2bdbfb3caee","0xc050ff87985f77dee83e521c8541ed13cdd8bd30f22decec20d09f307f8f945d","0x0c1549e32a26bcf378cf78fce47cbe366daa8c2381deeeb9589983fb65d3c4ca","0x00c1c0cf98ab3defa98a76c126f1a5bc229ad787ea5b998f0baf705581087c07","0xc23384837316bfff278ed9a4f47c8beb2fa235ab6391a1c96004a86c33d1c29c","0xd95e84983083ee04a3a04528b1e976c4f50a4bfd632bceec33caa531561896da","0xc6fd82b3f8d4cb7c2c7343d15ff3bd8924f68490340178e294bc55c711b43bf2","0x31edfe4aa8f5aab03dca2bbbe992b3ee6dc2a37b359d88bcb3cf9f675c9b8bbc","0x788fba61c3e0a45edadfeea93b0308586a9c3c5ca7f1e79a745772a12c33981d","0xdc7221cba9d95281b735705c676b78f0e450dac3ac03cf3ce7142666f1f36450","0xa2e706b0e6b1ac215d2f352c5b4e3045639b44fba59811b9055b1b213cd6a911","0x5a13256f55842f61e97d2699fe543dd4d7db3f4b385f3ebf4eee23dfc441fe69","0x67ff37748fe8bccbbc4880348065c5dc4c08ef26dfa724e94b90eae78b5fe943","0x32efc13739f41f4677697de14ff761b234d8d4cf2e7def453adfd7317a7c5f5a","0xab9bee6fb60dfa9ca6a9d88ccb252b1368588836fdfd52ea762197b3581ce0ba","0xccb8be6c03016115a1b60321c71b18c9b5b50e2e9bdae0f9d3c3d769072387ad","0x4c5eabd1bcc4ef385acd8ddbc973d0b11b0471dbaddffbff994a059f6449b3ae","0x5d88789a07a21b381a40b73019e5bde33ce77faf4b78ecd49ff5a7f798bce18e","0xba44f6904afe8a24872d258f058b7a5ae50de11895b167bae8699758e7390b82","0x6a85fac2a6581a060af8b4e775ed73216688e6c2b2b090dbc3d533e1aace9f17","0x39d985e332e41652eafcb0e9295f68b39a71aad7becdfb3728f8b2b71d19e8cb","0x7e6e166ee7111180a90cee3878612313b0e1e9c1597dfadd99f4c0f82bf0bf6c","0x4d683de66b7132f7e36d9d685a3361fe0b146c7a9b9a6e718d4426623c7702b0","0x2f9656f1324d4afe4c786f237b33468c33b0f1dbfb727db6cbff568860bd3be9","0xaca703608cc9e7b455577065f38e22b643f0b3e860393a028259ff296e8d6b7f","0x76cf098eca3cb9b07d9377cc0737a1953ec94848662907997560fe239210696a","0xc3f65535dfe59ff6ab535eaa457efa06f57e91064e8fb43b4d78e9fe71815f7c","0x1b8c7c8b5b79255ed1bc29db15023f1e8fd27de1475e1366c6acceca4beccc7e","0x163bfab5e56342aca8dc0f2eab88378b567bb039d26411b84aded63f7d98eb5c","0xffafce9906830cf4c12744b143563164e33a765169786f7681dfc273c6ad8373","0xd57f39452aab119685d3f77bc173c3381efab79bf6cb66b32e6ac090f45f607c","0x895ea41548f9fbe679df4898c1e1f2485fbfd4858da2be5c019d063d0ca4d423","0x8bfb507029a0cbe66c362478721b9afc5415504eb46330dcdf18454e89a8eab7","0x5ed3dbb85a59ca1ec43f63733f7097806031941413d0c132cee42140910426b7","0x38ec0d94221c415f9338fbfcb68a37fa05c237321d09b1f117ab104b8bd73222","0xb22b05f309298fd2dfaf9f6844ec41c787f94b7f9bb1b4e49e66ad385c59ea00","0x77aa31c08e980f60d51b9de41e96f0c8c7bc587ae38d6b59eba3ca05b7b0cec6","0x5e131d4e10f5b2c759e43764339cd3f8e11e48902d6d9bff7107f9fd254fc6f2","0xce3f2fbecd64425cd630a220b50e9b5d4b1c76bcee9fb31caca75d4438c18834","0x2f2883c89657ecdbda487a6139e8639b7522fc2d47ad02e7b8a871b5156366f0","0x05070c6c4df8f9af1fbbfb518ca0fcbe5db93ddf5e69206493908197e0dc8fa1","0x3e3de3d2e6e3bd46b3b3702d43a91377390b14e797ce7ec7a955abce67f28b33","0xe15471e7ddfea7af0d611f651d62a90702a90b33a4098de84b25b4bed1c9760f","0x5330317c144be565824cd5a5bbfffcf01f8d30842888333a7d0eda8599847868","0xa45ec351bc9b8bfd0d3df145bb3937b9388569e2bcd837ce883e0d4be9efdebd","0xff2d29660d3ed6361e73ce551eed264a62bdc827fd5377c97c8b956d481050a3","0x13c7035ac1feaa00bc33d96e0b652bb0fd83f17b79d8d973b079a71e10efe648","0x3399ad8b8d9e2144fb1e545ae858c20cdc43ef126c0044f88d5878606004866c","0xb24213aef5749d9d5840754e0822d861ae0f2f44090d6ec82d4a3e9c0f94e60e","0x4c5144a4262139217195bfef522675ea9c4df8384e662829220af12f8edba947","0x532e2519a1d10262fbcbc1da4bf27f94705f498c00df28c654ce81065fcfd033","0x01c1f7c83c99c3449397f2a44349fab9b01fba986199124cb0adaeff8dbaa8d7","0xcba56a74adca10553af7c2a643c802e01954d213e94e868047f58cd13d75f115","0xdeabd34cafe8c557767d256575ebe51087e43b22a01878288f007197a599045e","0x9fce1d7231e56c1d5ab619bb75d94fcc9b74f75185fa2d6fa9f8c8a734b1d876","0x626d5f8e8d37a3db33fef26915c576e238e41df9d53fb05de826c25df6e857fe","0x2a736c95c6564bf000b920ac7f7d37fafdb2174ada86ba7fe457c16e862b2987","0xfb0f2031556b3cef2a8b276492d311854fa3af847577986d4904e08642165fc2","0xe9e4c1a7b52585daecf6f7415c32cd9f3d6be0941503a860b93679b127d9f8ca","0x78dc670c76a89ad9d64b8ff50a43d74d874971fc670ebfa1478c71ebae2fc10c","0x64d33bf855a193bada26c94ac9fb6a03c9d179e713603f5ea30b04d05042b8d7","0xcca87dd627d92908cdd38d034d78e8f79799d0e71530ff51a014c08b0f521a49","0x250872b019eb9f373da5908857b1592a3fb13ab15b824ca192259c03a423e1a3","0x47f063e24a73c5c363c3431e72d08984b7bb6f032b7057836d62bf2bd1763488","0x4ae1153e19259e2e0b8bd60aea58f9c8f9976e6153f8bc1313f06b75316e28a2","0x0ec7004469eb00ba6aa9c485953084d49b0e0e033e10fca981974f1621ae9d08","0x0ffce367b000a6f44075da85d010c9318680005a102e109ccf4807bea78f7e71","0xf235a15c403f2125a79544b74d7297b95bc5c5723ffb9775589dfc7d4420c782","0x5e8f2260b37e93452ae950a3a79ee226c98856643ac7118cf19880b19e44ca48","0x96b76a92d4dce62a71994856dec173951174538d34a583ea8c63ecd7ec37d1cb","0xeae7cba4b64317ff2be0608dbc264bbe2f3fd7db5ecc9ead11603aaa3e4ec2a4","0x4a81212226915e0ef6d16698602c3e7dde98bd39b156c41c2157c3747293873f","0x2b23286f7b1d1b299830e8f047669a4c18e269a9fdb99aec92388175b2ccd27a","0x27a6ca6f0fb5ea06ba1fd60a651465b6e78d5e3a7c56e51fffc1200ac6ff4e08","0x9fb556cdb57a52ec73ac017264817a29e759489eebbfdcda705b292dd86fb2a1","0xcb1929a9a47a58ab276cd1ae5f57fe82235cd0ef0588c893f091f5804282230d","0xbc97930626f3f0c728c27a2494c7ff58458f0faf2498154aeb25b5da7aea4c28","0x133b04f3b19be5878eef8de954f4cf65c85af5fafdc2533dab0d683d8bc34601","0x7aa392f0a9e7c09d54aab0ca8d7f26c6c99d55e3e85feb0dbdb01142c90fc54c","0x9d7f6a69b3cc32bb8919585d34541d76c1bfe173afd147fa9f50a6a2f5c63f75","0x3d8376960bec55390206cfef66de2660349d79611bd8b59c39207c329ab66ea5","0x41b7ec65f4bdc77eb9b5a18dca6c2b5f87eca918d9b6f27aaa5c9e9c6e59e8ef","0x0eb55e098cf8b207dbb2539571101e3a5117dcae0ddd53080f35b5fb8e37d3a3","0xe5c5646b44d755b4dd52d1c4253aa0c5a06958cc3f4e02ea2c280a4879fb537d","0xc12807af52882c1358d822aca14228c0754039811c044f9e00419302274d1c8b","0x9e9b20cd1512f6d8d8bbb44b2505f80ff6ee17951ec8ceec06016f3b1c595c53","0x5b18544b2b42566e884bc294a7a4ba91ef2d9ef071b8c366eb08f6df98fd202a","0xb66153baa1d63d6eea19a431fabb9d7d1c0470cf0bf27c121478ec9ed15259c5","0x9a152d77d836329946a4c7e8a584d296f008571b23ad302d276b0722c7ec9880","0xb338fe60ad7a86f6e244d47bb21904e167254d1c23972286418a2a904749c0df","0x52e1f488bd73a471c37a1af9dbd12be64cf727d125dd4e91981588c88262b08b","0xae86cd1c983dd16bcf027ca1a2cedd03bf7ab0c715f33ce5b1e8ca73a065b8b2","0x37ddff1e7a90020b2ed08ecd73e0ad29a829cbab01a12a7efbb62d28b83f0a33","0xbe33e6100d1233e2d6b89c33c65526cdfea027d010264615b3a495090309761c","0xbe63f43c8fd898d2a5b8ebf88fdc38be04eabc99e04e455ef0cd06a7f67f9de9","0xcf536b96ffcde711a5506bd8e236935ad008ef0eae715c6d9ea00ead375ebfff","0x817028a2c348fc02b82565d6fcfeb1afce821214a1563210d06c117150b1ded7","0xc2f64e215d69cb24e674244a7fa877fef6cc0f390670335bd1255eb202c452e6","0x3178600cb3b9f1fb2c151bbf9fb71d6a3c993a063282f5917644b56c2f1cf195","0x26093f980b88c38fda1c759c7fb84ac14f5a863715e71ce5eed0fd80f4af758e","0xd6c53f08b58e0dab40b9eb608536b6c3f752ba1ebd3c621feeef2e277b1f92d8","0xea8efd539edec4a67c626fb5cedc3c5fcadd4f64c7818e671013b43275cca867","0x9941fec48c2983a7f3ba52f1aa24dbd23032761a23c6449288899a31734b2c76","0x55cb37c5614613d54eaff1651970b44cf9cfe79bb0ea881acc618d8bffe1e269","0xe2de020d5c7dbd54e5535b244a58416b58e2b7ec150a2d1b3240553e20821b93","0x0cd191362532cb937b75c340d30f42de632c09715a9ea3cd342db63961ec432d","0xd260265dc98c33937e475b9246e0d6efb8d8dc29ac49749703728e588870f742","0x51dcdc9408f51d695bb211796bdd8065d4da31d58a638d63ad055aea43d24391","0x8be7b98cbc6680372be9cf3324e5b078151d47135a54bea0edcde132d9fc060b","0xe2d5000030abd6c7f521ca9a9f3bff6644e6245cfc931a230ada90c8150bd46c","0x8a9fa1d59bbba9d82790bd5f626955ce567ab8ed7f7ee5ab3d87c6b9861cf8cb","0x5da10aba7f2a10049632441a9783275b024354384a56dda8a53e7bf0f9b3573d","0x23cb2d74ca4bf95a04705c1942f68163b7cd3a07091de726b82f42c46ee1db81","0x711a770eb7e227acc6d8192056a53d7efeff17301bd8befc1435a576a89e00f0","0x14c17e5d0f165ff904a0d478d757a458171b61ac058672a922cabaeaeb966488","0xc181a432d75a7e94f1dcacc06be336380715a7dd95424d573f1e85fdb0d47721","0x4ad61d9c653344600273501be9cab3a4f3400f39b556739bd7341b88e12dddc4","0x06da3c029a1b99fb6ca7f2d4f863a6e7a46adb5df85d403dfa5c474747a65197","0xc4252d612f23d9278b8d58465b179fc33592c9d33ea305c918146d71a6880ae1","0x495048a9473e25a9ba620ee9ca207420f5f4b1a3062454ca246dad02d504d070","0x201f5debb12fe92817cfac3189a6f74d4b0836bb8250f964e3606cf8e061d4be","0x9583a93f6c7387b7ad9cc145dcdb41dbeaea42fcf705b223c7454df0a3a7a146","0x4c197d4b296d9baa92102457ebe13af451e267226bfee983a0cd5dd11804fde6","0xd89692badfad96bfca593e3977faa557cb1a12d7d93cd7e3d1e95c9e7a907fd7","0xfb633e2c4228df769c30d80cc09aade34b504968ca50d4e968cd736991ae340b","0xfde53336ae40788c28c9dae447e5de2c22a31552a082a3fbfac2ecb3fd0b0afe","0x53cf7930380a7678aa2f0d561a6283d968290d05a309bb77f70891e0f791f7bb","0xb1eb4c4372badaf37f1874b055f46fe2a5417a78c0fde4a6dcf424768f0c4576","0xcdb5e7dceae096a36fc0959343bdf54a5aae9721f95fad68de837b9e82b7cbaa","0xca3452f0f818b070ba766d071f99fcb0e04254140f8ae91f8682216f6dcb01ab","0xbbdc330192449403bcd61cb7f7f1e5687675ff960b0ec23ad003d05498d097c3","0xe65c7021783548d99e412426ce8797b3941cb086b6dde77fe7874f248a51cbc8","0x4b8544c69103256b19066ac0ffc4f7aba37020bb96c01fd85c57eb8877dfeeba","0xed51a7e116bcb88060b901d00a8b67d2a4af86913ebd61e5ddeb4549ece6ade1","0x84bbc5d00c04fb8f16e5a5e059fba76aa3250c739ec6ddaa18f643c7a26abdb0","0x0a072908f6e2fc752375ad0d944324451bd09306b61cbb6c67090362d89dfc2a","0xa9cf5f8f1b628d98926a268e60e49f768927e777dafd7643f30264ae011405e9","0x51a6c004ec8f99238bdf0c436ce7c9fb4633e94800063f1268e8d6a46863e168","0x6a08d5eb606ec36c3101428eaccca62b65021b80905a4540046906467c939f18","0x4fde204dccf2ada6a902008e540b9b19c6c559196dd8902e961de60d864a7b0e","0x76ade02044b01534672c644ad1a5240281ad618864b848d37ca0fb800fd82546","0x2994c7617034391f65211bd99e8cfdec7c3265671ac9af04b6624707695b7a8b","0x4752a2721ff909a7e9b044d4d7fc564f95ad48f1ea1b3a01a4204a6a62ce34cc","0x75b9fe3c98cf4c30f7cb818ab527a08d0ffe452b0df241eaa5060bf703ed0d53","0x2e1ae711c35bc62f2c441ee64059f4e01208b6ef447d86cd0102e9f2d0c25aea","0x46f3b1a7491df2bcb0176b7cb2148b6159ec231e03c812c7ae90ee7ea98e6047","0xf4f6f9320ec234aa0cb4fba5c154fafb2b9bef3a9bde8e75ed5c7fb662156e79","0xa00c6fb89365b50248aae7ea0cad22d60c9a2b98bc988ae63e1569e2ed1e8fd8","0xf20afa097961a2a3be63cb88792e2a0dc3c450d587aa0507efa7e4a4849c0b08","0xdaf7eab64c8849796be2feacf4809b57cd5c14945f74a854f3e9d561384f0fac","0x722745ffb39b494cce9ee99d2c96eff7efc06a20aef2d9f8d422a217a6ee953b","0x6092ef74c19c276c4101f9913eb788565176e9724ba3e3d1761846682b200765","0xb28a93109f6929cbc13037cb56bb4dcca0e1db182db441d8c070285eee93e490","0xcb693a14c4c759681231d158c3f04c8a7351c1ed3d993aad4dbf0453f7e511f5","0xbb27fde6b11c1089dc31a4aeda73e07e465b72cb409bbfa52661dc8efafbd02f","0xcdc33e1baf1d7601a93a5b99ac3e89d51ec9b46e7dc5d48e567c5a35bc717166","0xd0e588ff41c26cc9af179e44a1d9bc50f70178e0dfdaf779019284ccd5f66b8f","0xcfa7e6c0aea0b046423c4b50769ea497e705332b094a0ba97d47bbe06ce7e3d7","0x400bbe5255ae5d193df4c8390c15480ed5db3b44705ba5a29d6393548c84ca0c","0xa4729ce3bd95d1f38d8ba80da811d1a42a0bb6ed70579f47db1223144066c603","0x1f252132af1cd4b19b7a3c5dde633920b4960831f526b65b4b07bc7bee84634b","0x5d6b964669632e57a66a4f474881579c3ce4d0ef7fefd05f10d89564aad22ee1","0x2876a43fa932de3607f848f10e893ab1b60d6b5f83baea7e9675974e91a99f26","0x50e4644e9f8de368692ffeaa0e3cf6442f40e62bd4f791eae61d0f08a272c3b7","0x63877fccc56a8d5abce4338417826707d26db76358f86c4f055e94ef38c28ae6","0x334860d8702eae7814881279b7d70eb9fe3a1ccf09f7602671560090a53b5abb","0x8b4fbffad18a8793069e3c22156e8b1ef60abbd3e5c58cfaae5fe6daf99b4b9e","0x10a3f8a7356e91e43171cc3567eb7319a76f9463e4bab4eee65d39ced1ac36d8","0xcac87ec886045c1f38eda82ef2c1d89dfd0f77f9becf74e07a4577654cbf022b","0x0b34bed875174b8badbc3c32ea96739d3ec8c5b402b3437a4e5c0722e11e64e9","0x66d1350d56ccbc45de3cf6f23b35ed6b84106c6b87952fcaf3f1f7510aec43da","0x7803eb3a01190a318b24fe265aa1f1f3f4a2a7f2e18185a237c11b8a5a88022b","0xb8633f1f52b76fa8c61da39e8db766cc848e2e119a9afb456803eef3a68b78af","0x19059f8df642ee02e99604f8718041ef5ef18ad2761e216e5d3e8235ddd3cb7e","0x0ccc9043942be8abc289705a171bb87e649983664b85810a49d7c521314082a1","0x4b05213f73787628c42f270b1e8c8943f60ec81325a69bb7e11e9599954c9891","0x1b6706e8d0632377ead4ae8bcf9be2d65944cc8a96a02185a7c1aa1e238fee0b","0x2725628f46ff79f680efa6ec1e3e1be850fc136933d71a4a78970e1ae50e2b2a","0x6d6a83f47b97d946fa0b793a051b886acc76e7d5d7ff9312dddfdf781f680ecc","0x16a0efbd33c6f0164cd6c9cd8e90a325cc43cc37712be7fc264417c409e52ab4","0x32592a25042f1e45f236e5eae7b5cc4a60f9892c96af486fdf1cb787dc1b1752","0xec83bd31a09a4ecf80a6725d01c4ee81f9320a6b4974aa43c7fad55f11587641","0x57bcab06f564430c67afd296a709a738897c3ca187fd7df9f1994e5b270d1d3b","0xff67f63ac0b09cd2739c96e5dff795e531e56362d598400be09289e48840e588","0x82b187ab4936ca4b10b358d5dd098848ca29d38b44b81d4b5bb39f407143c929","0x3313a81e1f97300203a64fd21a098792dc66e1ead6eb0038d9ce5d1550b2d49b","0x091a965c1fe8bfbccb8205485df94c1a805b70cbfd2c26858983554b3e49f0c8","0xd46149cb13e9694c5c9726a5d899109fadfd126b49cb7d3ba8798cb073d34bbd","0x3bdaa1bd12de393ab55eb13e27f14182a10aa1c73802ed8bdd3d009cefdffbdc","0x68369364513c8a71133953b33a39505084d9f01d446e85a80070f76be6f818d9","0xc829cff5a3b99039f9aa071461fd94961f9f91f0f13af602679086fb1105918d","0x21e71dde8bd6c3fe6c1017890954bbd495a980a0ea9f961b22e07619adab04d6","0x02c2cd7358ae1e8a2d6bcab393dd07bce8bb99c3e379a0a16e54af88b0cc7849","0x52f866c2acb440f9c21ccb8c1942979ccde781ced5f177e29792eed2eb1ff9ac","0xb5718132012450c7b69d2222850d9d712cb30827e96d5043e37d09ef1ae53fc7","0x5f956ec45ad18f565a27619038917b4309cbe088627ac6be1fe28e7a152cd536","0xf0a4f916cea55f76ff97c22452650a6767c8062945227d2b4ca79f88e4b83d82","0x2805f71c5095e51d98fa5f13303394f6cd24bc89cef189fefd71be1f31b97023","0x71e900d52c5c9a3e1884b916e9070744795bb6c44596f34b8ed31b32c3cfa4b7","0x5b9fbcd3978befc7df20298950829f93ad49ca9b2c3496f6616bf66b4b12cf66","0x266db59a14c82448063f519377cc83edaf0a762b45c6f916a08edf8ccc021661","0xd6185a553b3ec555996ee0bf8fd5abf57d6ff090bd5d742e0fc2b87d139c69f8","0xdbc31dc4a704d6613ad37d30f1b3504835bf821c770e71ce75b96e720683f264","0x20a591bc984f37cfd69c4526777fdff95aa73c6d3ceb15f1d9072e044451e365","0x7a7858621b03cd7cac7ff64816469fc58246b3e8834fd77101b1518365a7c935","0x755b7857fd6ce6de17b07d1d2c6a84225b62eb8fc8270e4b3f9645817cd0d0b4","0x839afeab0841e2a33b14848a949c0b10521d1d657ad3fd2a9857d16c90e91fab","0x85b1b4bf991b67b7094dd40303a511bdff3f200e71886c7274347bc9c5425520","0x182c070f883d21c4414652350858be42ee00de8a456541fce7b903eeb83ece2c","0xdb0666348278f2a0fd9291c9beeb1a93645ed0b23cf6eaddec4c102931224395","0xd2854a721c71a44a979e50007c550872075d9de3a8f80295b27192f353f5c18c","0x59de2de7662e06274adc2befc9039410f99b3208e09c2ed5d398ca3945c265bb","0x1d3f2c6817d46ae6b7605ea36f11d53b51920236ae49ed4f76f25141c4634c84","0x19e364d7133d3882cee45f1d7aff5bd1e1204a24aba972f2d7d136a48da28659","0xd709a623c599f366b8731143f0c7be3aac44988a02893e7ff7269fd675847559","0x99df0644485331007f19442f46d2845e199a87fa9bb3ee98bac8bb73da9e0200","0x688522eb588879b6ca133ab29b72469483cc3a29946e66a1b705a92f850b7dff","0x1e2ea13adca753465a53850c00067eb6b7448b5735c86b59eba4e4becc3802bc","0x13d78e0dbf5816824b950d6205a51fd478320fdf14483f6c96d45089eae0f87d","0x4ed4697c6453b1bb59d2f4675e21c59e1a95ae760c05c051eb3965a0b76fdd6b","0x79e4f785fcc14e40a49d60e17c680ab0eef8fc8baf33a96f5572370059b49c96","0x476f964caad763c8ebc9a0d0cee7a7ad17eea4d49d1577873ee6e245dd0fd563","0x8fe617cf2366d5fef8d2a0325687232728715950833a6ffa6bc5c9fe6f98586d","0xda1fb7c91174fe4622106d2efbc1e6b24e537dcba44d3cd94cfe8dec405da856","0xa7eea93c3def7751b529a3d41af6f4d9a37d63448d681f4e18a314def8dfc4ab","0xb6f445e41f76fe7f2448201502949cf2e42add1232ad83b82d7574071a63ade4","0x8ed1e8e529503337de1076b8b2008cd4b86fdd0e9905f4aae9968fcd76287536","0xd049338e6f42d0e67017c3558cd1a1a3ecb5b00d4f228fbace2ec96788f6469a","0x58e89b3bbedf7b64216bd2ad0408e0a36e11b1152558eff586eb9218ee416be3","0xa877c625bb74c733711d9cb2a9677ff4032df591e37b969629e8840dcc25cb60","0x4557ab90820ef75b5ac74e8de6ecfc69cfabbf3393af50fa1081492d0b0c2610","0x7a214e25fc3dddadcf0e07ace5908bfc4efc12d68fb324497cfd998bea444ecd","0xdeb0b4d58b21ed4fcf1a93915904aeb77fcbdb1ccf51904d7ba22b0c27ded143","0x5629ba4b1beafaa1e59e24681ac354e35f4bddb1638f39bf8679ba4b43a2062b","0xd947304fd152744c1a34f5687a1bdb0edc6dd88cf4cac69b9147cc70cb25591a","0x2c0debbf7878ca09a7a9c68347fb1be9143356106dbdae6dcc2ab63b343136da","0x6a26a67805d873b848f15e609e7bb10b78b2034398137d2e90a7474433737e4f","0x53fa8552628c69aa06ca0230c88a1e2872a6b2250d50e46efc09777b992055a1","0x0d5943de3b6d108aa6b731b0a66d6cd44b39c8ceae7658444e0f1ed3acb11e73","0x91fb0f2da95867de5d8cc815192076ded5ffa26a50cd1c719dd1aad887b865d3","0x4f5dc07f421e163f7c21b168bb6d9582ccd023f4a5795e2b0ed0196f76068dcc","0x95e930d6c525a8b551153e1e60eccc533f7602b10fcecfa6f0799d1105cbe957","0xbfebe1603fdd6ab825c51df99f2ffa7b0964ff3abbd8a49fee557fef7f1cedf0","0xd9038c67201c96f0cb8e7cc616b0ee3a24e56d1be51d90290fc34cf353cfd26b","0x4f6ad386e9a49af86a91c6e78adcd8a9779556d35c51c02c31fb13d496bbc391","0xfdda6e4cb24ac52e6ded7780ffaed0c06982a53e8cc2005306508a162bcd27de","0x42d3a08b3a780bf98945b0f4de90c53162bef61c0b31ff6f797433b6a436d772","0x6e4e0643cab8c1f41d5a02211b8a4158fcf800f1724e787ad2268a5ce11c11d7","0x45ecce5652a86fd45862cab4c2d28f2a68d3023765ec56b42b7d1f3eedea2198","0x97f1e237e20d8dc4c0857823b8ff813a5c5f8092391e982ffd64686ef838633a","0x431e2add2cb9e49ff0ea8facd6e1fae4dd116d56065047e24978deb0ef7efe59","0x0dd9d2a07f6ed4f23622c1b7b6683add5a394dfd13ee9e5ca35df33e11f82ee1","0x3d698da0e0dfe296dff80e309f80910d0cb59ed58acb6ca8db870428b1222e11","0x0e9c8444a4c866328f96ef2692085e63b75c76063874f40c2846eee04a54f0c9","0xc9e91775daab3973290e9a0ed93a24ddd5e6a328427dddcc550b8f664bed567d","0x70eabfab61439a635664a79b986cd7a18839adcc399d78998c240b8b3a7af555","0x08ddc39ee392d1965b67aa66e4afefa92030410b2d99612798ed902d60699bd2","0xca126ba044a2ffbde08e107cccf45ffc1b42c577098e4eec1fae5c4b1720aff2","0x80575a1ec38cef92312884196c06530fc41ce0575ecc7086e045c66b51ee0b9d","0x9d79677020d92ad0c14a9ae3e4c8774b38a5c1dc5218cc1f4f4dce3020b9a535","0x8103deab6705f2c7468dc908161f50dbb0b8110d0bac842421fbdea70a066822","0xeb89c381c2eca2baa3452ae9c8d47a2ccedc8dbe82c04f5036e25326693262e6","0x641a40cb0b9f049d527067a9d2038e596b7d6666062e0b35f4ec8a24b7d3481c","0x73e0d99d953b1f2073ebbf92398bfaedc7c458ee5e34a5ec9da6331f6f2af092","0x62d5978f35a63d4f132ba0a54192a305bf90cb03237fbad726e47927f0be20d3","0x48eaa28f1aec60d8c42d49f2e0f8980679f7680588f0c97a136d82dc9fa32fce","0x0a71dff9217981d16766f08aff7570dac7916d62e9dcf7af29dafef5ddb5fb4a","0x78ca168a65747f652e981a9e0ce4f97aa28ab6240f456cda04d3d0a48c52eff2","0xb1d6e739b290b878d63cf7a39ac6a44e465e108e1058360282b016a02bc05211","0x0c3eb583458e753c90517ca1ed596f89e085fe8793b918f323db5e5fc6ab05c8","0x67db4c79c6f9cf3ad90f3bb53c031035842153b7a1cdde1b4cebd11cb77e36bd","0x3da95a4db6f5d7b62f954cf098784ef85dc8ae6cbc16f0b953c0543c5804c439","0x8409f29bef6bb18b0aaf447451336aed1474c51a27b49712299f622fd0d1ccb4","0x009cafb33459411f38a6f0b54714af64a64cee790eac4dd2ede908a44afc873e","0x07cee3a30af2611bb099823e66bc9004368d2937a01153b4935709b54c6999ee","0xdcc4bfd58329d545cb1bd58574560cf846e9987719d432d5df1af6614f631658","0x11a4bf619738c7500537c51ebf4f64401b7a6bc236e009b41d5a79cf34bb0d77","0x922bc8f982efa2fd5ec1c9b0ed7e4ed653eacd4fb2eb153755af92408ee67d16","0x0e2189d893f7698bb4d3ac223779f0842599e1b6b5801be555425980353adb4f","0xe3729b123ff15eedbff2609726a1b6cc9e3626b2761fae59f798a26d7b766fca","0x689f2bc144a585a5b9905f8001073fd5abff91bf983577cf4a657c91a82f6a45","0x3f8dc47613f1296000f78acf982f3f957f923d94375deb1a73cf71678d56667e","0x12352a0e1beb94113c79d525704e036ade6304beaeb1212644f89c34b16d7236","0x58c921e4713d2e889177979d2581626d9097373520f198918f7034bda90f920e","0xec976d990f9e1ac9ba709cab35ef619d1ab82a17024d85d64d388bf90b413e20","0x0f823c7352d99b40f4253e4075c991b77d5e9cc1d58427ece66b07bfbd0742a5","0x34395cbe01622d83fa89f2fd84ba5b06426fbcac995538a56a2f0cb83614a6b8","0x47d4da98d44e67d3629f5de0ef89afaac05d1ccbadec327269944dfbc1b232bc","0x9a10d5c0322eba22df99c82547cfe584778fd47e1a2a6a71ef7b050dcf2b42e6","0xaa1ed4a7ec430a8d73ad636d97c5d271b2557932a714a7001599d9a8f8f27010","0x8231888f27e65775be79119bcb1de5480e0475ce352b9c867514bf536467d263","0xe0901ba43a6259d1010ded14076d686ab0a3811dfa2994163c7604be20020e85","0x890754a7a664850a9fcd185953f99ae7707ccc66e0fadb8eb8c115824c27a354","0xd23daff203f3132a98a83a77e96365d0c59110ae8761ff3e486706b21e006fc4","0xc97032e622feb241cc01e4740ab777387d6877d58124debd8c4a5d92d757e4a1","0xd461a8d5c1714e993b0a67014315fc22f7b38f273ec86b0fc9b78d0ec659c1ef","0xdc1bb5b3603a63a2d5f288f72b0a48e248835f1e13cde0865e15e6b5fcf8d5de","0x5a2a3a125387958bff090e4bd16393a1683cf169db17eff8b8761c17358bafe0","0x28134cf6679d83c33877f9243fe990cdbb62ee4c887023862db74787c4fc55d7","0x3cc71c0bb2373b8506eb659ef456dcc824513db236f468d23643d9c46ee3e25a","0x378040d0ef6ed1c452a3dc9fc32e903a891baf2655de212c2a1153aef74571c6","0xc5c746dfe7be18566fe74937e197c517b6cf373d1f1b1603b1d2b2cdc5f78a55","0xe080da92b79727d39bf6accfd2a96dc60719ad361a35b516e8ad0aadae5b30e5","0xf33488efc39ad37677013f9dea6422afc7b53e17db5271db5f1f8ad13e4f6c97","0x6b1698017d56a8e7224112cb5fc4269b59f4207872787b50649ce65e199fed53","0x23f97bd0caf28b45572fe964850fc700eabb4583dd6b4a2ed1927df91ab5187e","0xac4caf5ec9c60cd70cf7403eb6c153fd53a43b43c2a5705d5c61e80ca248d34a","0x4e64073f026ce5734026eea4ad92b9de19a0d516c77ec480100caaeb9f7da155","0x518a97d8b45551abf464a7619f5294d8454008cd05cc59c7b58333b01ab07d15","0xa78f6b3696ccd4d4138df10e97b9e1616f449bf0322ac92730af607966c11fd8","0x503cd7224b069151d632b8abcd0545b6683a981477eea994357dd87008f49cb9","0x48facf692f330888fc45d8952959855d9b0b2d489195e63fce9e5df4a6f9afda","0x5370c5cf87715fe6840095e43a8973431549be3158479485993d0f777d5fe7fb"],"txCounts":[0,0,0,0,0,3,0,0,0,2,0,0,149,2,0,0,1,2,0,0,0,2,0,1,0,0,0,0,1,0,1,0,2,0,0,0,1,2,0,4,0,2,0,2,1,3,0,0,2,1,1,6,0,0,0,0,3,0,1,0,0,1,1,0,8,0,0,3,0,2,3,13,3,1,2,0,14,1,1,1,0,2,2,0,0,2,0,1,2,1,1,1,2,11,4,2,0,0,9,3,1,2,3,0,4,0,2,0,0,2,1,0,1,3,4,5,5,17,4,1,0,1,0,1,14,1,0,2,1,0,8,26,1,6,10,15,1,2,1,1,5,38,0,2,1,7,5,2,2,7,13,2,88,3,15,13,222,3,0,14,25,0,3,6,0,1,1,2,6,0,3,1,2,0,1,6,1,2,3,2,7,0,0,0,0,0,6,0,1,0,1,8,0,0,2,33,2,9,1,0,1,1,0,8,0,7,9,5,1,1,0,0,0,4,0,1,0,0,7,0,0,34,0,13,0,0,1,1,14,6,0,0,0,4,0,0,0,2,1,3,13,13,27,0,0,10,3,0,4,8,4,11,0,35,35,1,5,5,34,0,8,28,1,29,6,6,0,0,10,8,6,5,15,0,3,1,1,2,2,0,0,12,0,0,3,14,38,4,0,0,127,34,0,12,16,1,0,1,0,2,11,0,0,1,1,0,2,0,0,23,0,0,61,43,9,77,0,1,2,24,5,0,0,0,0,2,21,17,3,1,12,0,23,39,26,11,3,1,25,32,2,0,14,2,0,58,40,10,65,97,5,45,21,88,66,5,35,201,40,6,4,108,3,32,94,80,22,46,75,152,69,81,289,60,54,88,82,70,89,41,110,1,180,4,82,36,145,47,262,7,111,77,41,232,162,0,43,164,43,0,14,97,45,2,55,21,43,40,18,29,171,125,55,168,82,66,120,93,11,40,84,52,124,56,56,2,138,105,134,99,136,205,146,121,219,217,187,121,67,120,290,214,205,144,179,277,234,231,114,156,156,366,266,314,259,289,264,236,9,40,66,145,136,334,378,73,170,88,34,127,100,112,196,59,109,26,303,89,40,56,58,85,188,13,107,65,164,21,224,77,57,380,80,14,219,143,94,89,94,124,197,63,11,173,51,122,148,180,101,113,166,94,107,125,51,144,147,85,121,127,155,82,176,130,164,185,307,250,47,22,150,125,213,133,136,131,114,44,128,111,44,139,200,92,21,116,205,118,281,119,156,136,44,130,288,83,59,66,59,67,141,76,75,144,24,63,123,155,44,119,63,157,23,74,53,70,0,10,49,129,137,58,304,54,104,74,95,94,41,242,28,76,5,17,11,125,18,31,137,111,86,168,14,16,20,153,75,185,112,159,166,48,11,108,57,84,30,49,72,141,10,49,79,99,15,48,16,71,151,114,29,89,5,105,3,175,34,130,149,154,25,5,140,7,110,61,170,85,80,172,100,98,166,0,74,76,99,41,58,0,132,187,152,165,113,45,149,142,2,96,110,44,44,59,98,6,91,126,64,147,18,11,28,205,129,0,83,51,20,50,63,57,35,77,160,31,63,64,0,24,121,129,70,21,99,106,36,74,168,101,129,229,198,0,211,134,44,40,178,211,51,49,108,99,205,224,205,119,69,232,62,51,194,0,103,91,147,38,237,103,92,108,123,193,43,131,190,32,29,155,166,20,128,103,11,93,78,138,12,204,0,193,76,30,38,68,184,108,22,208,53,34,0,141,55,58,190,61,0,121,188,49,0,45,184,136,103,171,51,117,324,262,13,111,215,45,38,108,71,11,26,246,58,81,38,57,108,67,12,46,109,73,7,88,121,113,63,10,20,210,237,218,251,184,217,9,60,46,170,115,84,130,23,105,0,184,141,104,147,109,14,84,208,32,90,167,85,99,281,11,55,18,98,65,22,72,26,118,251,97,123,71,113,145,83,118,0,146,89,152,43,197,9,134,56,34,124,125,72,215,52,47,125,143,58,157,131,220,170,126,193,99,40,61,148,63,0,138,49,186,68,32,137,43,175,124,96,131,157,130,142,112,97,159,179,209,171,177,100,214,0,80,117,161,163,51,167,96,103,208,116,277,194,151,31,118,191,172,107,123,54,0,254,191,66,349,168,285,80,158,544,176,171,210,149,136,246,201,169,213,161,149,277,246,171,184,172,118,188,191,213,139,136,172,49,0,403,261,194,255,220,197,314,135,154,187,92,112,178,234,167,255,286,137,271,156,186,128,175,109,217,212,122,151,210,240,137,123,265,132,188,182,134,105,157,165,159,167,97,0,101,179,208,157,138,98,233,178,85,162,136,194,213,259,0,111,290,143,127,224,131,207,162,282,338,126,421,125,145,222,147,121,182,208,194,193,178,214,205,242,145,243,235,90,105,51,146,207,243,136,130,218,218,230,175,279,164,146,172,206,304,179,183,228,245,107,238,199,229,132,99,145,123,155,165,286,151,122,196,180,354,152,164,244,171,120,167,204,156,220,134,243,267,251,30,283,186,213,147,273,191,213,234,209,202,357,259,616,230,288,283,229,219,293,127,261,417,122,141,169,90,249,245,216,165,208,290,155,135,155,198,236,140,364,188,168,119,319,205,154,139,203,160,175,142,314,221,0,205,246,190,0,150,188,149,182,188,119,148,189,141,173,139,336,295,79,114,85,44,327,327,89,242,97,69,128,55,7,47,133,45,57,131,44,504,55,178,12,13,6,609,132,249,57,324,60,22,57,343,294,484,280,453,339,238,320,39,41,429,329,43,273,168,89,23,200,255,222,5,159,23,271,425,343,101,153,311,122,171,412,215,35,64,208,17,357,221,175,345,230,523,407,690,102,232,419,233,167,129,62,284,299,152,356,39,444,247,34,8,173,283,223,125,46,209,116,167,129,180,404,90,130,420,347,49,141,33,123,335,37,13,117,378,15,78,23,77,112,111,199,90,205,190,690,561,373,425,63,356,235,98,214,308,209,316,325,219,303,82,16,429,40,125,179,113,137,151,91,94,120,0,273,241,196,113,530,225,196,58,230,129,39,0,305,75,281,215,223,62,192,178,196,85,0,65,339,139,91,307,41,286,330,338,14,178,154,293,129,334,25,279,163,323,159,252,373,249,344,123,11,48,344,193,54,298,103,169,8,172,87,75,123,142,5,363,267,0,9,170,127,218,1130,182,91,47,374,188,167,61,414,31,274,165,124,57,175,192,163,139,200,31,243,138,14,5,144,244,136,114,183,195,135,446,20,196,20,197,181,171,179,150,114,197,163,140,206,159,210,97,158,95,164,85,27,83,96,239,131,238,222,124,120,143,183,147,31,167,107,70,209,124,150,410,79,147,150,114,116,116,145,128,94,53,154,125,157,115,153,129,590,104,174,115,115,107,99,123,108,159,115,155,232,119,158,151,174,22,190,93,173,135,178,95,163,208,127,138,197,131,87,156,99,144,142,126,180,196,154,103,168,159,132,204,190,131,248,194,175,150,181,154,120,137,46,161,731,163,156,151,107,118,129,72,149,93,138,95,112,144,163,131,166,146,127,153,131,177,134,106,112,142,148,104,161,133,135,126,116,183,142,156,78,107,110,124,144,123,90,116,114,119,111,166,142,124,129,107,112,78,218,105,140,318,176,110,123,200,120,156,141,137,160,150,107,112,162,155,163,118,121,184,139,139,110,135,129,190,115,125,227,128,129,166,152,159,121,96,82,144,122,298,126,139,586,100,117,136,171,137,93,87,154,379,117,134,131,90,150,90,171,152,84,140,189,118,103,146,126,205,157,298,168,111,152,290,134,97,214,128,130,144,151,128,128,151,137,182,147,115,171,73,113,158,127,140,335,138,158,128,228,143,133,221,179,187,122,109,106,156,131,134,122,134,106,124,162,137,0,148,178,86,131,127,159,270,98,186,143,113,123,265,158,10,25,183,129,256,145,187,104,128,84,80,81,92,305,140,184,157,172,149,67,219,112,225,108,230,116,132,250,163,175,117,72,328,190,390,143,179,213,156,273,128,200,99,134,268,155,192,147,264,210,99,119,252,236,101,308,150,42,111,158,67,151,128,180,27,126,140,142,250,159,144,235,164,127,173,63,159,97,197,59,62,147,143,153,129,184,111,123,106,163,99,199,191,202,192,215,123,111,196,200,227,149,140,132,246,143,102,67,140,141,131,212,137,138,128,154,194,229,141,135,89,187,109,126,125,119,119,128,380,199,276,151,205,145,240,103,96,161,202,243,312,98,14,123,165,154,109,153,187,167,120,130,145,241,156,233,119,130,144,131,133,160,101,52,270,195,206,172,175,124,165,148,212,152,107,160,69,110,140,124,109,186,137,138,161,237,143,150,123,154,135,205,213,233,145,232,115,107,316,94,105,117,169,161,290,139,84,231,192,194,123,246,183,149,157,144,146,156,251,180,135,243,177,268,188,257,107,130,185,235,81,148,357,287,127,213,39,175,158,124,151,200,174,375,194,545,189,208,124,74,159,195,319,287,219,323,159,64,168],"txHashIndex":[0,0,0,0,0,1,0,0,0,1,0,0,74,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,2,0,1,0,1,0,1,0,0,1,0,0,3,0,0,0,0,1,0,0,0,0,0,0,0,4,0,0,1,0,1,1,6,1,0,1,0,7,0,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,5,2,1,0,0,4,1,0,1,1,0,2,0,1,0,0,1,0,0,0,1,2,2,2,8,2,0,0,0,0,0,7,0,0,1,0,0,4,13,0,3,5,7,0,1,0,0,2,19,0,1,0,3,2,1,1,3,6,1,44,1,7,6,111,1,0,7,12,0,1,3,0,0,0,1,3,0,1,0,1,0,0,3,0,1,1,1,3,0,0,0,0,0,3,0,0,0,0,4,0,0,1,16,1,4,0,0,0,0,0,4,0,3,4,2,0,0,0,0,0,2,0,0,0,0,3,0,0,17,0,6,0,0,0,0,7,3,0,0,0,2,0,0,0,1,0,1,6,6,13,0,0,5,1,0,2,4,2,5,0,17,17,0,2,2,17,0,4,14,0,14,3,3,0,0,5,4,3,2,7,0,1,0,0,1,1,0,0,6,0,0,1,7,19,2,0,0,63,17,0,6,8,0,0,0,0,1,5,0,0,0,0,0,1,0,0,11,0,0,30,21,4,38,0,0,1,12,2,0,0,0,0,1,10,8,1,0,6,0,11,19,13,5,1,0,12,16,1,0,7,1,0,29,20,5,32,48,2,22,10,44,33,2,17,100,20,3,2,54,1,16,47,40,11,23,37,76,34,40,144,30,27,44,41,35,44,20,55,0,90,2,41,18,72,23,131,3,55,38,20,116,81,0,21,82,21,0,7,48,22,1,27,10,21,20,9,14,85,62,27,84,41,33,60,46,5,20,42,26,62,28,28,1,69,52,67,49,68,102,73,60,109,108,93,60,33,60,145,107,102,72,89,138,117,115,57,78,78,183,133,157,129,144,132,118,4,20,33,72,68,167,189,36,85,44,17,63,50,56,98,29,54,13,151,44,20,28,29,42,94,6,53,32,82,10,112,38,28,190,40,7,109,71,47,44,47,62,98,31,5,86,25,61,74,90,50,56,83,47,53,62,25,72,73,42,60,63,77,41,88,65,82,92,153,125,23,11,75,62,106,66,68,65,57,22,64,55,22,69,100,46,10,58,102,59,140,59,78,68,22,65,144,41,29,33,29,33,70,38,37,72,12,31,61,77,22,59,31,78,11,37,26,35,0,5,24,64,68,29,152,27,52,37,47,47,20,121,14,38,2,8,5,62,9,15,68,55,43,84,7,8,10,76,37,92,56,79,83,24,5,54,28,42,15,24,36,70,5,24,39,49,7,24,8,35,75,57,14,44,2,52,1,87,17,65,74,77,12,2,70,3,55,30,85,42,40,86,50,49,83,0,37,38,49,20,29,0,66,93,76,82,56,22,74,71,1,48,55,22,22,29,49,3,45,63,32,73,9,5,14,102,64,0,41,25,10,25,31,28,17,38,80,15,31,32,0,12,60,64,35,10,49,53,18,37,84,50,64,114,99,0,105,67,22,20,89,105,25,24,54,49,102,112,102,59,34,116,31,25,97,0,51,45,73,19,118,51,46,54,61,96,21,65,95,16,14,77,83,10,64,51,5,46,39,69,6,102,0,96,38,15,19,34,92,54,11,104,26,17,0,70,27,29,95,30,0,60,94,24,0,22,92,68,51,85,25,58,162,131,6,55,107,22,19,54,35,5,13,123,29,40,19,28,54,33,6,23,54,36,3,44,60,56,31,5,10,105,118,109,125,92,108,4,30,23,85,57,42,65,11,52,0,92,70,52,73,54,7,42,104,16,45,83,42,49,140,5,27,9,49,32,11,36,13,59,125,48,61,35,56,72,41,59,0,73,44,76,21,98,4,67,28,17,62,62,36,107,26,23,62,71,29,78,65,110,85,63,96,49,20,30,74,31,0,69,24,93,34,16,68,21,87,62,48,65,78,65,71,56,48,79,89,104,85,88,50,107,0,40,58,80,81,25,83,48,51,104,58,138,97,75,15,59,95,86,53,61,27,0,127,95,33,174,84,142,40,79,272,88,85,105,74,68,123,100,84,106,80,74,138,123,85,92,86,59,94,95,106,69,68,86,24,0,201,130,97,127,110,98,157,67,77,93,46,56,89,117,83,127,143,68,135,78,93,64,87,54,108,106,61,75,105,120,68,61,132,66,94,91,67,52,78,82,79,83,48,0,50,89,104,78,69,49,116,89,42,81,68,97,106,129,0,55,145,71,63,112,65,103,81,141,169,63,210,62,72,111,73,60,91,104,97,96,89,107,102,121,72,121,117,45,52,25,73,103,121,68,65,109,109,115,87,139,82,73,86,103,152,89,91,114,122,53,119,99,114,66,49,72,61,77,82,143,75,61,98,90,177,76,82,122,85,60,83,102,78,110,67,121,133,125,15,141,93,106,73,136,95,106,117,104,101,178,129,308,115,144,141,114,109,146,63,130,208,61,70,84,45,124,122,108,82,104,145,77,67,77,99,118,70,182,94,84,59,159,102,77,69,101,80,87,71,157,110,0,102,123,95,0,75,94,74,91,94,59,74,94,70,86,69,168,147,39,57,42,22,163,163,44,121,48,34,64,27,3,23,66,22,28,65,22,252,27,89,6,6,3,304,66,124,28,162,30,11,28,171,147,242,140,226,169,119,160,19,20,214,164,21,136,84,44,11,100,127,111,2,79,11,135,212,171,50,76,155,61,85,206,107,17,32,104,8,178,110,87,172,115,261,203,345,51,116,209,116,83,64,31,142,149,76,178,19,222,123,17,4,86,141,111,62,23,104,58,83,64,90,202,45,65,210,173,24,70,16,61,167,18,6,58,189,7,39,11,38,56,55,99,45,102,95,345,280,186,212,31,178,117,49,107,154,104,158,162,109,151,41,8,214,20,62,89,56,68,75,45,47,60,0,136,120,98,56,265,112,98,29,115,64,19,0,152,37,140,107,111,31,96,89,98,42,0,32,169,69,45,153,20,143,165,169,7,89,77,146,64,167,12,139,81,161,79,126,186,124,172,61,5,24,172,96,27,149,51,84,4,86,43,37,61,71,2,181,133,0,4,85,63,109,565,91,45,23,187,94,83,30,207,15,137,82,62,28,87,96,81,69,100,15,121,69,7,2,72,122,68,57,91,97,67,223,10,98,10,98,90,85,89,75,57,98,81,70,103,79,105,48,79,47,82,42,13,41,48,119,65,119,111,62,60,71,91,73,15,83,53,35,104,62,75,205,39,73,75,57,58,58,72,64,47,26,77,62,78,57,76,64,295,52,87,57,57,53,49,61,54,79,57,77,116,59,79,75,87,11,95,46,86,67,89,47,81,104,63,69,98,65,43,78,49,72,71,63,90,98,77,51,84,79,66,102,95,65,124,97,87,75,90,77,60,68,23,80,365,81,78,75,53,59,64,36,74,46,69,47,56,72,81,65,83,73,63,76,65,88,67,53,56,71,74,52,80,66,67,63,58,91,71,78,39,53,55,62,72,61,45,58,57,59,55,83,71,62,64,53,56,39,109,52,70,159,88,55,61,100,60,78,70,68,80,75,53,56,81,77,81,59,60,92,69,69,55,67,64,95,57,62,113,64,64,83,76,79,60,48,41,72,61,149,63,69,293,50,58,68,85,68,46,43,77,189,58,67,65,45,75,45,85,76,42,70,94,59,51,73,63,102,78,149,84,55,76,145,67,48,107,64,65,72,75,64,64,75,68,91,73,57,85,36,56,79,63,70,167,69,79,64,114,71,66,110,89,93,61,54,53,78,65,67,61,67,53,62,81,68,0,74,89,43,65,63,79,135,49,93,71,56,61,132,79,5,12,91,64,128,72,93,52,64,42,40,40,46,152,70,92,78,86,74,33,109,56,112,54,115,58,66,125,81,87,58,36,164,95,195,71,89,106,78,136,64,100,49,67,134,77,96,73,132,105,49,59,126,118,50,154,75,21,55,79,33,75,64,90,13,63,70,71,125,79,72,117,82,63,86,31,79,48,98,29,31,73,71,76,64,92,55,61,53,81,49,99,95,101,96,107,61,55,98,100,113,74,70,66,123,71,51,33,70,70,65,106,68,69,64,77,97,114,70,67,44,93,54,63,62,59,59,64,190,99,138,75,102,72,120,51,48,80,101,121,156,49,7,61,82,77,54,76,93,83,60,65,72,120,78,116,59,65,72,65,66,80,50,26,135,97,103,86,87,62,82,74,106,76,53,80,34,55,70,62,54,93,68,69,80,118,71,75,61,77,67,102,106,116,72,116,57,53,158,47,52,58,84,80,145,69,42,115,96,97,61,123,91,74,78,72,73,78,125,90,67,121,88,134,94,128,53,65,92,117,40,74,178,143,63,106,19,87,79,62,75,100,87,187,97,272,94,104,62,37,79,97,159,143,109,161,79,32,84],"txHashes":[null,null,null,null,null,"0x1d31a775de39f8d41fcced175436fc2653a51ada160934f1d6b428d0b6febfb2",null,null,null,"0xfd5f813f7970fdbcb6306bb5522c4ee651b1be1f0c93387206282c5453cad018",null,null,"0xee0d26305131e14ad22faed44e7aea060c8f09278413ab2a926ac9484a004d60","0xffc847a3fd6a475bfecfe0b970f9ac39b2bcf684eb6fcdae4b593a505831b2c3",null,null,"0x42db9dd2959c89c42ca8c5bcbfa79b6d5cc9546b1af87f128e04831e7ea32e03","0x3d93beb4d7dac02b2bbdd8fbd248cb42ebabc02b7a6e70df538ffd34127a6711",null,null,null,"0xd3557edd4843c4a2f9ad2971938299acb2ebcdd0080c4af5803664606f8227bb",null,"0x977158b15a9488235c36ab8a5739ae98fa06ce4e5b836726b7d44294d0f01b0c",null,null,null,null,"0x90d41c6122aad7f46cb4b020f3fe7a2a8a00a2a9212bb8a010214c2f4e45d5f3",null,"0xdfe39c078869c77643402615f0e39f4808d27e137414b7adbc6acd887b4e28f7",null,"0x3cd359d0e28df61715e873e9df25fe5e17f251d7218c473e596dd8ab16a51f0b",null,null,null,"0xb3aa4f61efaf31946900171f6178ac1754c177e85861cec16db35f8b82867a35","0x00c6c5da425bfe7bca6bebf85a273915ac4498ca1eebd13b519a3424086750b6",null,"0xa89e3df60e00f5718f676eac0fee128fa0d49cd96afa95f8868c66199d98d895",null,"0x60b13bb3d58df3c36c899c52188b818005a7e35b06921ab185d87eaad3860cd9",null,"0xcd7c4d1843988495f43dc42c816fb636e974880a07c4e5381ab4a502ab66cabc","0xf9b5710e6a251308225b96ed44c25c38cb36b9d6a447d94ae6cc51d9b620e182","0x13cd7ee6b8d713195ea387578214636ceb6a0d0ce98af37f4d8f4ddd14d5ba23",null,null,"0x8ad68a639ca9f5ef499b01a75b16c9f29ab08e15216e06cb4310fe1edf38ecc0","0x879f628ef2b99a312e0d22fb1f425185369831e29ea6c93311c0f91554b99cd4","0x1141605daf14dd1f667d06f30e8e7de7a1ea127c7c547147a90306bd13a64612","0xa50dab9efe599713d66bc4e064946030b426faf429ff96abccfe37bb8072aff6",null,null,null,null,"0xd67afe14005bdc791584a9c46d7f45dbdc77074c1451bb4814e2a470871aae71",null,"0xd33f785902abb5e163406102d889b9966ecfb531cff8e91b9874887a35043762",null,null,"0x299ebcd04af9ea6a26f198449addcdc821e9365d184d533539359c4ef8dcfe17","0x89473a7b99cbc33c7c3722de4c0efb0db621e1066a94b7abfd293ed2e21c7ac6",null,"0xe1b254d579e7808e2be225ba372e604ad30e1bf0d35a18f70a20f64a348a8fa5",null,null,"0x263ad9e43f696f2f0f02213b67d8a9d13b436d10986642acd3e70b2e7911f00b",null,"0xdfd06faf8c30ffbb776b6c13d1b564c58714a17b32e3bf1436d680b562da5990","0xd4bba08715de662b51398355b261ad9c2a2bf27f7c0cf496d195023bb733915c","0x8ac786c11fd9c1e1f278736cda0ae293a567bc773939e47b30e4b792b45d90a3","0xc3504f7bcd91c822a547f0f5290b3bfdf4bf64009e1cf8ed68605c445a2ab459","0x2cedea1e46efe8c43af1788c38f3eeae34bca049d7041a0703893985adfddd23","0x230f8bed1dfa7937825fa06cb990a638f37ac2c9c8d23363757d0d0804702ab7",null,"0x1d372e867e1ab43cdcf5182c37e5f230b2c881f4e10f435d55c31bffcaf87670","0xad4929f0e5500060fab13626ae951410631f17ddbbc93e3ddff24118f2925363","0x69fcd4b3da729fa7062bbfe31da7dc26a3cf835027107c7235cacdfe0aeb15ac","0x0c15f8fe75c299648e064c31f539abf062c4292c52d326ad3a7a0b851a7a63a4",null,"0xdb9b652b504dcda6379e000a89bd9a07995a89bb02670e3e082db514708624fb","0x2f4884509a78661b4d941841f8b6437dd7a206b82316cd0ed18040d0fa446f76",null,null,"0xb5cffb03506700cabe0b7cfb3cc104a49fb191e2c72d216c5935321cc57f7e1f",null,"0x31cd016f481382b26893cc4a24bfe539130cbf68681e898323ca06006add6093","0xbff1e7b607cb8329e6188184435308077c6b1dd2ede960a621207b6c878d3f03","0xf29aa081e6f8149297bad0a481c819bc61e9f2cb5bb3b37792119f4170aaf36c","0x0bbf06e96766028b6ba408557fc550df3b96d339948af9c1a6df75ae45a0907c","0xfa887e6b16f950c30cbddd38cf0c622cd73a9aa35032bbf54109530057e254fb","0xfabd14d1b72948b5717ae5c3c3abd2dd87ba8a1b62db02717572d392903d9548","0xa61eda06227ea40603e2f74deff248655aadcd7c389c7c015db84c5004993358","0x04fc73c10c0c371c67b19fde48c4dd319cbad2edf21ed7e903321cd33235b8e9","0xfd337a0593eea93533ca91f35c91655b3d608eda57726a62c4588a8e7476c007",null,null,"0x8ee6f92f4cc9356b16b76056937850364179e77540b13327ab3cdf8fcedab45e","0xe4395d036b55cd3240d9bc03dc4cc314468fb08b54f749af1f34a9dee4fb4d8a","0x5b9666ca98edd2856f282715f5b7a7400bedeffed2c559bbef2261814be4d05d","0x1d1ebf618d534cd5fe21d116e31f6b088091bf574fe9a1b0d56f51bb4fa62f6d","0xdb02b932e50977059a3e2db246e2509ee3f6dc2d8571b974f868328edb4d6a2e",null,"0x9cb3cad337ac20bf23337e0fc821fc49211e2803741ce9ad1fda85c8fd7ab467",null,"0x248f3285551b6c0762bc381fa23d2adb0aa1fd95f223daff6e925d24b00786fb",null,null,"0x17bff3701fa1f034421f18416e85bbb1d86265176593d564477bdada88418235","0x454000226995f3f5e006c31d09457289b6e960e23e5db675988ac4033acca768",null,"0xe174313bcc4b113c942aad621b6f32c9aabcfae162d09e81cea9f3f80d30d990","0x085da1c3469c23b8e7544a1dff09dd1508b0156e2ae33c15312403497f1b64b3","0xa1dd8d3686d52945925ae3a3660955eddfa4685559faf458841c08d824e5f78f","0x9eb736bf6178af06813574b1a567836da0f1ae9ce28e38b19721db748172c3a5","0xfcadc6baa441d6108ef0bf2c1d0ef88f802b5563ddaf709d08991f3d3dc8fa5a","0xe10c28e3f71d20c8e224d40485af318e48c8c0ee1ab91bb3469a7724a4c2dd33","0xad531d143cabef1f2d079df5db0e426913ec03095db4bcddd20096b07f9a41d4","0x2f1f23e59938e188ddc8020c8f08d1f199493e1d902e898b6bc91fe8eb8300b8",null,"0x74bf297c63494d4ee6d4cecc283979b6fec5677f41cc1b785431a41e5d26d00e",null,"0xec2afac638a420b687318ab3a5027ea06b6485134ab4ac703bb28f3e3555ad6a","0xf62433c20daa7de71ff7bbe6f801a0c6169929c35bd10f1d425fb393ce5ed084","0x8c3920eaafc9d545f93052dabce91e4cacd6b0d458e1f7895c33b1dd484c7dd9",null,"0xc36ad06641a1651dbc2055a1b5406669675ff7b2abf214edf40b1f1a9216b2cd","0x8b6a1ef14dfa426a15d53c7775f7affd780c619e635fa5c7b6db29e6c1f14585",null,"0x82041b1409841232270ce72b73ed98c86369d421296c033dea3f5937934169ed","0x6d875a8fdcdbd8fc82a517ebba5f69366154ce6ae5bbaf2b60023cf826208d17","0x451195e063eb2dc73ddf780a8554cc001842548d6ffb3a07a20d17b87a6094f9","0x692ff0a3e582226987ceab98c309df7a7dbf835b8278949595a17f631765e2a0","0x44340b4934d71303568f6c5bdbb6fbab7366fa7109f649268b617e2a9203df38","0xb94558691f861cf4128cc612cae1de4edb93f1a0ec9df228f81f946baa6e6467","0xae430f9e4316d1af98810f64c4a9a90bdfa4b0b11c40ca0cae09e1d8f2a7ed09","0x6c427a2fc60a6a9d1ec71f3c039e18461810faaefbfcaf03d62f6046c2d85bd4","0x4ec624ddfebe75d983ace8626978cde7a9fc402596d8f5723de67af27791a5ee","0xd2a1dcb420820776a886512563aa44bea602dd3f43c588c2955ad1f205cb621c","0x8c046d4b0aecdc3ea33ac694ba2ab810a9a582421640274a607dbb2e484c8d42","0x83253494c3756aac94bc07e1b7aa0fd1c0e9db94ff35dd6de7b927999679f8c2",null,"0x2f397eeb49edd1fb5130f574d64ba405a9361c34f2918df4273b50c2cc56f38c","0x126c0827ddd2eb88a1c6b119f671e6c50b0352bfb4f49d4af60471051c950046","0x248c53b2043a20b241035788fa6de4eb7f592a2bd59fef62070a19cf7e485565","0x09ca05a074ffff1a4b13f2b22b1314f02961a20d1f69ea9000f80eba08aeb068","0x150d8bdd8f8b7ab928aadda15544454d879cc71b8e7104c956357d256efa1766","0x47bf049bc17acda40c6e387d536ef248213a508e353867a4687bc3dec7989dac","0x03fd84502c5a92a54bc6cd2c66ad799b241597ce17cbbeda871c33418d3ae9d6","0x8f3cac2966814879004f69b79427bfad14f81993cc4b7d8816e31a19c4d08ccf","0xe7170305e8c59182f5db85e7b76597c284fd78718bf78fce0faf6c6aba72bb24","0x6edd1b9aece2ee8b4ec83dbdc8ed02173b2ced54d080259953a7091b6fb026d2","0xb81fb49de4a40741789f584c827e191a76d357436b989cabd067981ed97571dc","0x8ebaee1f0ea1e7d793623628192c4269a73666178c4522b07c28ebc5fee9b974","0xfe8aae7cc2a9e294833f18c4eaa30d6c38c79d7e187d954e4a7df9ddeca4680a","0xb277c845616203e3875920ecd2847fab245e6301bdd7c0c58a24fc52cd6ba8d4","0x8f0865b2e18db8106b5cad222eef727233ada7bf820373ded6ac68dc655ee253",null,"0xac1a744b5f4dc5cb824e1c0ef2c0aa0481e8f17a4936882d333882d71ae8ff04","0xf157147e23da9117899841d6561a4a22fd50b0c4f7f0f21075a80452aa262c09",null,"0x6ac04f38bce293f2acbd7e536cf6c54e12d032124334c67bc905f643ce606638","0xb25035a132f6d50fdbc8cdba0d28089a55a555497954980800a7281595a7a48a",null,"0xea36ac1f4cd25afb9e90d27775a7e616fbb43e7ba8b836d580fb93f54ba5ed35","0xdf91fbc4103bc9d6a9413b6516b6a7a53d04327f5fe46c419293931d8965c74a","0x002abe52612d371b2e427f678a1c183882433715c8a9fa0e7a7d196c4631728d","0x85b5740fcb04ee4c74304bb0bf2789f04d37490920acc2b868c582015bddac62",null,"0xf5ecc907a5eeb03fec03110aa309520848c8c28006f9e92fa0fe249acb83a410","0x6df17f5096f220784a562b695a2e5b72aadbd5efbe0f9b31b29dd241a39a0763","0xeec68bafb42f1ce5939a591a6e78e187860ecafef6e95ee5461dadfea72d8f83",null,"0x90bfe805c09678c419343de22e4b58f5be27248e955fdd0a8cf229c988a79040","0xfe1a489f42805bfb19f915b04642db56f9b184778df204e871aa8d6088303a9f","0x4948de61bd6c1fa91f10e51e404c21e0b70e81a0e453fc63427dfd12ae4242c5","0x526c0574c969f6c7b2029de60244af4b2b0fe352aa29e351f7c8ce5339d68c16","0x9f95254aec6c8937e80ec12340905b4e732aa6e742c59fb28af3be8767534566","0xdedd96cf30fce50df2a17e0775da8e05891d017678595ba0c7846c0402f5fd4a","0xd8399a252d6afdf441003a8329602b7a52c2c0212b7603215d27a56c1993f7ac",null,null,null,null,null,"0xe21204ae6880c8b96f1c2d06557453267ec62d09e9825c9dbedc0f75dc9c7c75",null,"0x6c0a9da4f64351da953aafe72468156605b6a33306a0bca5b73982ba8f32ad6a",null,"0x3699fc89374ef5beb279b937a834e2abae95c9dbbfaa5c60a9ed4ef65e7120e0","0x7e33338b2e1879bbe0090b0ab4089508dac99f7cc5493079ae2735f471666a6c",null,null,"0x55c0baafa87614255dae6fa0432c866528a4d5a7b8e66f99b9be903f56b29ed9","0x71c53ec5f11f1f4c3a1702c27d7986bd1dd3657dcc2dca3624197a37486f1b13","0x49a5d3dcbf75cd2a2a6a165a16420643e079fe47d77b26846acf3c34c788d3c5","0x8c1d7fea963bf513575f9990a078b79a6389a4f81b1e179282702f41ffe5a657","0x5279ab400ac9dbd7351fa36646fe983455d928054aa944bd532edd28b616d501",null,"0x2a5e265342797ebfae89e7b0f9d0aea59926319c9e0e6a1c61513339677d6839","0xbaece21ed2071f7285276f0a1c887bf69795f377817ff9e563c1c1ab15f88778",null,"0x14ac8ecf9cf6390f3bc463ca57cb6a16beb86d14d98db7f21a1cf5b5b5891594",null,"0x381bd15fb72a079c1df8dd4885b974d18a4db592723258fa78cde2b344d48c39","0x10a5f7cb3aaa4e46ec985edffe9210d1411b7b27064d230fff92acca15a6382b","0x073acd9a0c0bf9e3770ef5c14bc563b84e18377824b94e587d765432dd986d88","0xd1a67e38f0ebacf8901fa585f2c27bf6f0c0626556af4fcd6df3179966c9e5dc","0xea7008ca8d603882b3bd3ea12d1c3b4f4f5682ac7293af1539a90a1df41b1d92",null,null,null,"0xd5b6619a20df4698b17c5d542e0b67b6a1201d47f3d662f459496005446f4d99",null,"0x676dd1f33a5d53bbfb3de6fe78b8b8d74c2b09cbbb216a2304317d234b6cdde5",null,null,"0x7005564492c6796e928e2a02dd7285e9dfb6e25e090d5aa5b9f38d73bf781841",null,null,"0x760cd2b6139447fbafd9b056ae5fe5219f093b0d88e952428bdd61479adcbd87",null,"0xdc123671b1f66e388f9be81b7390e11621216159d09da4d08d9b5dc80c69090e",null,null,"0x6e13c6d6d2e52b7f3700f1bc731529f171e7f5bc0430b916899f60cb4b4beb4b","0xa21f9d0bc25bbb7c9c5dd3b284abef952902b49fb36db9b17591191b3853d687","0xda0a41b211c91db0deafc8034285ed392dd3648822380254aea6ef08ad547080","0x867161e3c9200f8e51d706b3522d884e8f054108af442d77dbc0b9df6eeb0270",null,null,null,"0x142b3d4b385463f690fb5c206e95d1061a281914bbf7fd0c3e6691cb9902bd91",null,null,null,"0x5147fd79aa40d970d0b0978c378220b100373f336ca0b0f682bb2a0952c13302","0xec257c4a5a5913c58b6b255936972084d6debe03f76aef702fd7d733181851a0","0xd2a8456234e79f4412afbe6c44caf64f87456c41552b47bd4de366f195be7d36","0x312a4f1dc3295bc9285edf57e28efe899035e60b955bd2635c2048f80c387449","0x8cecb9d427d0bb850c447fb7582e9cb6f2c9b475801ae0b364811d656ca9d486","0xe6b3f2f1d8543a13a4ab733dad7f1a9bbef1239f9bfd3daf61c406d86561cb02",null,null,"0x7e5200926a25c97f033e1d6113673b6fc3f47b949ae5c9e7040add94cb47cfdb","0x840b4f823276d566df59cdc45d355e75b2a799e372f8d1b44ca0548666dbc837",null,"0xa8f6380b5492cc6d67f2e0dbb563663be7541a79c5d52fef6d3b2ea720fac334","0xda562be1671bf38cc7b80c25107621d55af8787b4ee66743aeb7ed0f5404c7bd","0x78895d3f5f9e7828da29ca06175ee242f864da6248593b7638e6fad095ed82d9","0xe744daeb8b5f4a766b1e3be1de64288175012af5b27f7a354021db6336a6d7ea",null,"0xe8659b63075ef381d904ce7cf933fb7e2b6a4e10e52d59cee265e8d90f2b0b82","0xa7dc397655741c06ed1804a88938558ff2f55703589aa16931626389c7df8de9","0xeedf79c08c03bd8ef447c32623f76add2ea14be033f393d5573c275eb1cdd817","0xf86e0a7064c42ee173309da4d0b4c7af4a755256c5b7412a1f458b5675619b93","0xe68acab741ec77bda63a38f8a2177cfa07aa00313fb1848ffb3a412e168f261d","0xf2250323be07b28ef239222d31d6b801c833b7d4ec96b763c871c3e916964e90",null,"0xeac76834b9e49ae9cad9b399064ef2c74ef02ab61492daeb5c3f9d9640ec7b4f","0x374e9e4abfc3271ab64be8b42928280fa221aa78256096a98be7ff3bf7a5eb77","0xc0725c7dfa5b445c4dfffabc786632a8622073f71c64669abd7c27ae2d619dc1","0x6efec79ac4a135fc4608fd99285bb9a2747005087a403ba6bea26c18e2293372","0x906e05ab98dcc3f4c85920643f5551e3b5e09a3f344c9e4b2487a54e08e5cf2d","0xb68e31b0d6b06aec100ba53a2788e0c100b03df7578054dcb85408b397b1c3f3",null,null,"0xaedb066a7f6fdcfa5f35048dd4fd4852e85e8654fdcfbbb6e4adee1e4aca7ab9","0x668b1dc99b39410716a0faa7f5d58b6f1d97b48a6b9cd1382602451a123703f0","0x0fc3f83601b8b49afa50a6e1d372d46f51e11fbf6bcb056bfb48350d0e120ab3","0xcf9c5c6f808e1fe5d3128046c8a48bc9796d58d5c5c47b6caaa9e7efb790f795","0x623b2137f346f35bd1c33d6b2f1c18d57e6633d032fadc32ce76734afb26b6b0",null,"0x50c2c16a65828fbc2d51d0fd0c55a0c6c40f923e3bc46009a18ca651d0aeaa8d","0x0a49386be882c4ff6684975a7849b7f1be10cb2c45085c71eab6bf205428428d","0xed77fe54967a9b2f95f90fdf444eb5652e84e27731936ef52b072119f16fb535","0x9c2f17c616419ae978f6bdc992aeb081a4181b383f81bce279b93ad8f6257520","0xd87c500ef632d07f3d557664135be14be5982ec00d23854c58f164bc66211bb9",null,null,"0x9e88bb170341b31fbfb307ee05caa7efe6bf10c065e99e2292e44ba46fe42489",null,null,"0x8834ff7ef111d8ceccd3b62a90ac6f4cf95442f4473fe133b8de76b6e63d13b3","0xc48c659cf87fa466ff3576d65eb65a0b6e9e8b0de0837e626276cf7e7e8d9440","0xb54be7bbebf12c0861c5637f76138fa6e6d247535464f5d2135a4b8fc8bcaa76","0x3e584cd29e423f2fdda22845db9558b67c802658343cafbba98404b3c31ec9ec",null,null,"0x5d2238bd7b2ca13d1ad5d3a0a2e63e2aa7da3da93add884606633dfb2f7c3a8a","0x147bf570294cb43dce66958d0529a7778f3038d037eb7f31e33a63bcb10487d8",null,"0x4ab8b2494fa4d83991c0929616639ac55c1933219b6366be972de2c7c6ddf079","0xa17e7a1ce21f07fa41517a234fb5beae34aca9e52e91a7949991c3b8dc713132","0x64995e4e03374dd433f6e64ff56882643f015be03ec9ceab56b014508ffb8021",null,"0xa0b2f59758cd745fb4162541b8327f502e2dc76a29fadeda1cff3eccf4c57c72",null,"0x67983abdac96ca026503816dfbf8a5304177cb566b3e6c78e4d53f72bc61dda0","0x9b82b5d66af4b9a2aed0449ac425d8bdf3a6f8aaadfa84c57878c9100bb73c44",null,null,"0xe21d2ca7b9c334ee0f44deb4a6f3cefb64afaa470fc3bebbdfe79308d2efd65b","0x97b27ce49151428fcc5ec0bd9a398c3e72ef80958e58c6d47ee1f37426a3d31e",null,"0xc6c2d10a454d5037dc55180c24e0d1346f71ea24ce4631b7d0c60fdcd6645938",null,null,"0x901ccb93e9d7b76e5c721e1e543c1d12ec90d36a1f9bd5aa72fb62bd434579c2",null,null,"0xd616e4ca7d8fde74893b05fe5a98377f114718baa65b43e8464973f94558df8f","0xf70e27d0b5e0741d6c6c586e277b4bbea7565febf3df3b426aa888700fb7cfea","0xa5119845a088407425d7012772ece073a32b4dd115c4ee14c50bd1126cbc7a23","0xbc95822ec2432d53d1df6a9afc2c71b66c8f6ec3125af0b1e66fe56ae69f5986",null,"0x4424b625b41249d2199de89ed1585cbd6fa6f73872f1b4a97e1becb320a871b6","0x69ad3e176bb53697339963e6520f9c26b802002b7fa2f2b720701d006e4d072a","0x3b9c9d2a0882d4cd2848082662eb2b11e95124720029fd599a9952ed68eee47e","0x679b68a52a5ef003d934a1a79fbb4a8465d4c48be3a99f225e88034e97f44804",null,null,null,null,"0x8e1ed7db31e561ff3d599032209f0824df1d7d8531234c0cffa6bc254ebf3732","0xde158b41f827fb85b164d9fdab87c80b3020cd8a72c113dba39211cd2cbd43fc","0xc7165e8e505116294db667abf4882e9b081a963bddaa8e2bb8917bd251273daa","0x57807af6556e1ee6b4f45ca82478a5dd816ee567c42a1551f3825b01d4be9451","0xe221ab752de76260771c67a0d07f8f710efed29267377e05528ddac5eab2a7ba","0xd8d9ca068fec6015a70908cf97501757feef557239cabdf83bff6e0f88a28332",null,"0x1daa8acc6024bc3baa2df7797b1589dc6ff2d5fde2d8ca7a33ea29055ca6cad9","0x7eeb3b6b01923d95bbe3ceccfde66bd2837a1dce0f00776218911ed3fb1c32dd","0xc08c0da9248a53b1618e17ee421ed1a993fcb749f958f1d903cc202fae63be6a","0x01964bbc69991b031ea3fa4b72fd6fc18c70c0c089be277355bd6ce32c9a9e22","0x0e0b87c952fcc7e20b2523acb75faa5bdae5b20487b68f7eb338ee10c13abd19","0x8b1c13ab9e948ff7d13d26ab07f1b713148f4137d789606af6482cabd59face9","0x22d3242d5db9704f4ed85a5be4975f528a1d431970ddd472187d5657874508d8","0x7a1fb580118330b353b74b2dfbbbe7ac6c0134a21bf7670c743cbe1a367c0b19","0xe1514e856a9e93d413c1e69c521903548b422b7e218a8570225de8717497a81a",null,"0x474e59a5c5b8c04cc7faf0446b318705433b767e73e3a2cdc9dccb77cbc0afb7","0x72b4bd1c6f9bad26fe676a7fd1990847a290c24b1a7d52685799d79643d128f1",null,"0xffd9cfe1da7af617f83da875074f1e02e13bd93fcd9fd821899907b8c247a192","0x771daf4af4099f922564e09765dcfb7dd1bc2108c7c6d3126a4acde4befbb3f7","0x6709e236dae287c5db549a3d748ee7f40713ebcc7b4f252a27aaa284330f1e4f","0x38931440beadfe8e3704c6ef13cdf943866d2a24b12b0667159962a76f19e30a","0x6ddcacb41cae49fc10c5cf65e30b705fb1bacd262ccbb6dd224bf813b9c58965","0xb8131f3c14f937bbb891821c58f56cacefbc4ae4d90473ad4d2ccdab70d62b47","0x5967874ab04dd0ea22dce40d1bc0ac061f5c1f209ef166efa46868bad959ec5d","0xfefafa3ce5970621b87ae8a0d9263c94ffbd6e763eb2c7104ea1fea62587c7e7","0x497c19000cf5d0cd6da7a65865113d887e27a8ec9438186b9c147ba7d2a12f8a","0x0e65dd7fc53e1f857c5b4a962efaabe8b684b22176887f3ab2670aa5cf35371b","0xaef1655b3866c2ea6fd34be151606ba7e147a4b639b650e993e8fc19d5c34679","0x0c21366ab54f81b3d3c1df180937105893d8f48c61afd403c0eb6305880be0e8","0x7e042164dd38bc49f0d6b935f6f0cb5611921e7c13280bb12e106a9542cb5a52","0xfda8c5db3f4bd2eef563c02aa3173430d69463fc7c77798358897e1f95bba406","0x88925f251322fd3506bec69e7669018b1100a46436bbea922905f9e0aa3d91b5","0xcf530fbf7f2ea5738ec9260a60d008203d63fbecfcc2cfbe289b9a18732dc5ec","0x8539fb098d723ae10494efb18d1ad9a4a0e440481da19f39ba5d41e257597e0e","0x6c3c0608a8ded6f81d76c9fe7ffe123db06fc1f35de3719861e52b25f9281a34","0x943fd88d631873ebcc124c41fda8fa506189c99e0873178361421f13ebf1d499","0x88c4f4bca1a0e76d8b33976851cc8160f68709e71adc94cf7dd4ac1c52bb4e7d","0x016ab87e15513d70284463ddcb5db944a7f19d7abe173d53c8cc204ca48654e8","0x977b498e71878a10cd8c49de5c150b000d8be4f94ee0ad73854b4febc1d6cc94","0x021957efde5d8af9dfc3b434a4b993d67086507352371914fa7444d8342b1453","0x4bf40149bfa3ae7b5e43b089f1d6adb265151994c96d02d349f221da897ac442","0xd0c93532c761f80a32ed821eb6ddab521749999907f9a54a45cae295c1495088","0xdbf32967edf5ecdc8aaa7efb4c507e8590cc6053bf3ec658228fca5c24bff034","0x72bfd1b785cc9d377cf5215fc9db8870e8000d3c0040062298f7b38add669148","0xd834080a85f66ba69e294593c5d840f78af189147dae5b46a239b7d2810fdced","0xa74a6d8145f7b4308bd0cc42198dc32ff339214888a16da11cf229a97edf63ce","0xefa459ab7f825716d71e042e34ad3dae2b0c172b0ce2858524ec2f3db92629e7","0x4d30557703781d402ff9e458fb402d2e14c633fc3a3feb0ea2e648a77e27d6c3","0xdaf5ccd36f366b3e78f866a2fc3387a742ab4ab24184104f41297e34878b06dc","0x8c52ed7f4f89c4761592611238cb571c6ff4603bd2a173f60255b30ad49bf0c9","0xbfdc8e2b4bc14d2d3668392c0db464c3d11e77f601c95705e5be4428db0fcaa8","0x5429015b4a0af1e7b8a4855b395b47af68316730489bee2611c5b5aaddef4f74","0x8ad8a497de132f064070b6ac124aa6eec1c5bf0bc7b6fabd0b7705a5dcd96b92","0xae048bbc9ddb0e2c3ff2f1808389a915d486729082f9a6aa020698bdaa2c3f4b","0xc0aa41b74c23ecd2bca3abe0849f08374760b00999967a21c8457540fd6b3e0a","0x49aa5acc8c53480d0455d88664adb0a8756a5004c3e4efe2ad9cd439c9d49664","0x6f55adaed78cbc6e9d65206201bbf282e553f9bee998ebc6cfc768c5ab58b58f","0xda48f37fef66d97dbf522c8fd58957e025e67d067b68240fe6394e59cb9ceb0b","0x256ba4d812a5de16b632cb2b7535bf995adcdd9aaacd7b7b8060d56eeffb809f","0x8a22c29cc3e8c6b0b552036fcb2956dd4e744eebfaaf3a3fae8abb954747e542","0xcf18f7e7be61b55a12d4de1b92dc55f3519abe05682b8452a17c7ee47cebca89","0x90ec2554fb3739584255009e16767433848586b72aca2262cb4ebb1bc02c7ff3","0x40a74e438da839f9f7dd9c95eccb1f3fe7e4d5024f0665c533a23c348a5e9aa7","0x8efe12b8ff55f7cff4a6840d469c09ac5ed52e3ced2ce48f437b58e6b4e33bd3","0x57a4459a3b040764f781f2d886f8c46bfa3dac774bcea00c223ba9e5e202c665","0xbb3e1905a7b54b0535875457a4ddc0e1a483c2936d30bdc3eb9d8ac4527f50d5","0xa93e8d99107317984bbd40004b1e4f6778e54be2ba7b19ba8e7b882358d60f4c",null,"0xc2e42649041c9d7ee76bb9da6035ed307da84f445a8ea77de6e018e7adafb9c5","0xd22987fa476a04fce4de726478f1bbc454f7d4de82eab0247bc20bfcc6490c55","0x49a9ac49cd60beb0b5d9c58637581b22476301e64b58dd2e74e042928114de64",null,"0x11909a0e386cd3a7034fa577ff67b8add57c990005b2779660c9f32ed9d4957f","0xfcc33a27059bfc39154b7fe8575d85d1dda7e47b47b7c52b8ee17e64af178a3f","0xd3efc997dfc0cb7819aaa4c6f055beca14c818643bcc85d8993998cd47b21e75","0xe83202d73675e418d10f97a68ef58c277b88be409dad9a948d37bdca0d001874","0x1f16df15b16704f45910e81b61d2e611039927981607663108e802ea684e60cf","0x4c0931ec9da4d260f78f1d278fb25d0510c137c37b0e07ff9a912c6e3dd1e231","0x7159f5f015cde1e6e566b9b736593537aadc07e8537eda8144d677bc04ed8bf6","0xa5bcbe6f1b84a4f95687053ce8afb89db66816ec5dd62d4c308c16f807b0d0cb","0x741af8418ef8cfe3d9c9b1c26925bc69a32746fd9aea147281f1a274fc820bb0","0x77c126ca9a5ba21972967480b0973420487cfe74fdb4c02447be7f1a94449880","0x044214ce8c0cada80ab5a6152b000a0ec85de3cf551cf482ead6063db8700bbd","0xafe7d8ff88eca91d9974de7130a5770ac0b149233e1f9f13f935c1728c496b59","0x8d55a87d1ce61dab1631539424ea625915f0ae67073cc0b7cfb6712bf5617cb2","0x3084228ba3803d1111bf7dd15010d80d149c0bc402480c6775d13643773e48db","0xfd252aa59f4d6d4c06f3e740638fe4daad976b25e6632060c100069adc922b70","0xf7da43de308b6396f2798a8d7da0ee81867e8407f2e0ca73166a6360c12ffbfd","0x3d92e397a5415413c4286f2a9d6bb0d92ef39f64b82f2dd15187574450914423","0x08ab56e18a7c194c30d88a48ddf2ea8e956a47c00ac4c703bf335adf3aa6f014","0x7f1066e95b1b3be9c4828ecb3430cff48850f5c9507a22023aeed6a3f3c377f1","0x986c5234b64859ed4585a188bc2b9bccc7a3076b017863e67989948547336553","0xc7e206ac2b9ee78b95dc7b79abae23513bb78601df933a690eaa8158987fd4f2","0x0f877f13a6924208f758a12e97e252862e88532d31d23f359d1ddcb3268a79d1","0x02d3ae088d5d805317d7ca184ea215a154623ea4834638d147a232b3a9e9c3eb","0xe4633a4391fc67a1b90c656284ef848b0bcc8736437bc2cb9c3fe5f768d5a794","0x1916e79e38738c79bd2a8e52784a924d7682f6f6338af87311cf209c82343169","0xa2f62128d15217c50a75b96ac6929db4ae22a9d2afb4f730d8b0b8f1521a0048","0x56f47f508ca44fe4b1dddc08f5673fb7506cd095b3169ed3ddf27e6eb64ccacc","0x9b72905764f4a5cab981e8eba67636fed0012f57b7dd68ad4e1855730e79eea5","0xdf1cffcce8a97e5e3e90c61ea1757ef3abf26143e070f35c5bd8ec9fdac3e2ed","0x198162f89e3ab60b8fe3baac7065bbb36cf585a62009579908df7985a1e36b1c","0x0012b2f4ecdf37d95486cbf37fb95442b1380a86a83d9cbe90c7e02f99bf9ad7","0xf8f526cd5c9350879605b3d1cbdef333fa826c1d2c0d709f934f112eb9faa48b","0x2f22767efffa0e277d81c4d39b49ec6b58306820474a5069c88696149060f406","0x5bc08a4b3bebd85328040e0c598ae027f0b9ff5e2c401c3671af5bbf4943b71a","0x6d88370c25f125987dc13252191ff7cea0926b2a1cb90b46d71d75c78643f638","0x277a3e1d786ff2c1629bec54c3ce325a653352899d7764616582d8b56eb04fb9","0x99c50d6e104d87e78f39b212d71d630b0495e9adc7acd0b1be4916e42f98f807","0xecea40670259b5a11c5f38982afbe4ea5663a2fbf2dc27acd5c077149fb20aab","0x119875b9040cab0d55d0e45bf656694d18339d8972bea28b80e7fea0c8a9bb0e","0xb2b1d4d2adbd3bd00852a836675069eb69ee54ab613f0094c367339cd918aad1","0xd47b50889930011aef80e2f0c3e1d8094570d31cbfa09a729b1c88fe326826bb","0x0c109494c446a22f217a19fbbe49beb095ee6ffb7b2d9e205aa900765e02e4a2","0x2926d34338c342cb3e38bda70cb33cf5223a70583945985582d61dcd217921d0","0xb043ad551a78a1c770447c1f1545a90623d3b6c870d76e67b52fabec069094b9","0xa276ca11d1c249301bf24dcf575199b7f6da5667eca7e503886e5a07e82adb3a","0x6e1e2585f76d12cd3d25d249e8b10acd76fcff3479e796b96a75c4c1cbcc1413","0xaea7d9cc34d77f97f456d87338eb172d79cb5f3b630a804bc0b3274a86461610","0x3e16e36ea95d0327ea54adbdd7688bee53909d076822edf40a5ab23c706ae6fa","0x4dbdb928f584ff1a7a7c2dcb8976c6c9892c5f5dcd4d026a5810d778751e21c4","0xb1e67f71a14a37d7d082a268171608f1d710563afd971f50e21db79493c71c16","0x7717e3c1cbc813e00fc042d5454996b3a85c43136ee187cb63b45e565060e23f","0xb673199118f2fde7a11991b7d01b9b3e8d2bf8b2c0adc76c5a7f000a3e13023c","0x8be038d32403894ca48311e22e16032976f03649429a38c8a4dbd30bb27627fd","0x8e23794d9dfb8a9c0deedadb7eb32c98f7b421de56190fa1c481098d07409587","0x09a03472292fc7024e929e990a81e3f20c56b7a636728eeebe7c117126b64a68","0x87953f5297b411415dc1fba616de978577a3936011b9f2c800e280bdb962b976","0x102962e469f82c48c6e35956a517790476a8fc3f3f78aeef5b270de236c2f973","0xf98e6b09a21178ab2be29d73fa0677fbfad9f827ca90248f2a2a2e89eaac839f","0x8781e46ce41b0a5092ced4814569e11aa01b12920768db489c7b64b3bfe55b8c","0x08f27efc239f14ac20ef09d57a54f592a95bda9d31da8af8bab61b32a60e5d7d","0xa87a41227f90499da781dc6d892158da7d81eaa71c089aeb82cd69676b445635","0x8f4a9521588126bdd52657753e7e9baf70520ed130ac2a4da3d65874028bebfa","0x820e6c179b71937d93d3b6b3b93b95f519f0066768676c4e4bfb2eda063d4785","0x6402974194da5c83adda46d6d7038bc7898815dff5e704452f23cbf82c35b074","0xe2c4b92c5a317fe305c34300fc81061136bb0db276192d1e31dd88eebec35c23","0x30c21081bc59bd3602762056f6d031326ec8eaf5d5837861a4fb64252e58365b","0x70d3508f27d2a0efb7fef01eea40906107bda6c3039a7419ccd1668c4271a535","0xc7ac3cda2a064b7af84c2850e94513b3957c6e7098573ae4e7e73869df69fea4","0x2432022f1e2d78dc54addc836f8dace1c0201bb796d535a962218539e630a2aa","0xc5fce5be621171f516554789c0cb6a99d969611d7d139092e0a53df77e46617b","0x092714b27c35f722a6f0538609053c2c7936f0b4fd5f8bdba0457a4750423660","0xa5c33003bab34aed08e2e345eb114a5c7900e41450a4a2d00920acab487d314d","0x639d0a473d87e5c1c592a3cd5693a1838d415cb733e9c0d593859012f6206588","0x106a8898a50080a83a3a8aea97317be214cb36683e2e6afbc2524f2a13c7ca94","0x400bbe96ba459631a694439aabf4080e7aa5a939a5a6e330bb1c85264fdc21c5","0xb13aa7c20f218849c4469b2bd6704750fdd8807db0e23d0ae9502ab3e7b0f295","0x1543cee509f6b15f9ccc5e2ec995051627e0af5524c5bcc72becd934db448398","0x0e84ad7cb391f23326fe808976b5070a16eeacaa3b640b272642227a7046da3c","0xfd593f7b0930954dc22f018afddc81a37e4eaffb061a38db0d3359342a9d2b54","0xecbe9e8cd294dc8fcee3e23dff5cd053431026625b8d00b4dbb2d81d4fa3cec7","0xf55acef3730a062b250673d2c4a09b528dafc8e15fc23a5d8396412d31dc20e1","0x32b3de61307b71b54301143075fa0193004a83efacb06cf29634ca8ffc4e437e","0xcf5e4015adeaeb65434c00d8e45d18850a8136f84478b621977b96c7d76cee96","0x2f8f0b930f67fcd8255aaabe2c51cd5d9c6d6cd7703920099163fdc1ca5d0e55","0xc95c6ebb18df23ec963bf792884084375b13e679d91f04d1cd5c031a360db78d","0x6c2e44f1d05769d5d079e5398c27a3e67b9c170da291a0637c5a4dd2c1bfefac","0x57935ecb138b0c1f9fc897e469b87ef578813b21410f9fefb394a751e2788942","0x81f94dd69361817a99c13fb077ab24c11c1927ade76efd54029925c5ca5f8216","0xeb388244021687cb2ae146a6bfd678dd44588f1261558a5c20926bf7897e9437","0x0a32591ae255b01f06f826c0bc0a6506821a26a367e94bb4c0e49c27b359f1c6","0xeb645dc3f34c0a516877709d0ce68a00339c2c58ebe0a4289bc8909a56689d2d","0x6b25453d0a296a2630f478f5b841f43f4c2b9939a65b3940874d886874aaa0cc","0x54b0acc6cd6f1645623f1327ce3ec5acdb14ba42779f198ce8e1e34d52cfed9c","0xc387b36a94c2501641e9f4313be05d92853ba09865114c681bd19d240fe508e4","0x81b2e416d93d5c1776ee7dee2412d72e78be92917dd0ff948750050c03978aea","0x84e31e565d3a28c8358778beea0e57770db81bae072f9ce2322d020f7acc1460","0x8b74e7e9fef12948c0b5b908979ee52f0e044dabbabd620afa320ec4cda5f89f","0x02be5c770d7c135a526485934ccf76d69627738bc29cb2b2e5a3d8bbcce6a5c5","0xd24ceb80b6f6b3aec4dc1165319240fa5631388da73aa552e494c5af1ea7f1b6","0x51e99ff5cdb359aa15f6e2988e3d6a41a17d5f460aac798c3c84adeb9d918437","0x779faf349d174f6800f1e8f7fbe4ded1e0f7a5d5367aa020f524028bd51c40d5","0xd9d9c74a49bcc38b848da1031b8c78a6e3a22d7fa8aa9a5f25aa306cc45cad57","0x578f0e56c43dca483cac915a43a00f24f66db0ace0a01f5188de32bcb13aa7b5","0xd362123bb1c8404551455485616377b5a1847bacd84ce11237a7c5c3618dfebc","0x7a3e6a0fea2a4ced14164e74c0eb1c642b59f0c1293de0da5ce8ba931c2bfb9d","0x5d63a9ab1f7f93587440f9c6c3448579c930779b95a94d5e8eec2a12a9953daf","0x8477bccce9b2878c1b8208bd45024665a3934b90c773cab9304432050e07490f","0x83ac7a9048e9f4895fcbe36e475fa1446c444a222958da2f9f515005cc6afc4a","0xf48f8eb4cb153a0f8d6ac20c4c4ec1b0fc948252a06df3ec9fe4df2ef3b76d9a","0xa152619ad5cdbcd2ea3738b373741b375f0504ca92784f3158b43670149af79c","0x219b846c1a4319bd0d000e7e2c6b1accd4e0adae1429c2767dc9c07b7c1f46d9","0xdb14bbac216f95e38f225f0c8044ea36293612cc0a5759c255200eed46f5061b","0xfc2d8d4331fdf72e6d1aadcb506692553cf5c45a1a55190cf6e084053808bfe6","0xd1d0347aa34d6a05173515dcfcc7376af947fe0c23459a96f39991089b4df462","0x88e5b34f4e3829700c7ab8f806385f09ec9c0bdd327bd70f7ce9b62800bcf0fe","0x2ab60dba70f289538e522592fe504a46d11d0a458b2c92bc19401070d0bf0717","0x8ca68a021c15b5c6ea944d53909338a83e293a854b6a18b22ab99a74052d9b01","0x385075638e58b55afc2117daf51b500aa5d71c46da78d6c33d7ed6d5c817fb17","0x3c8ace89188b7f5423cfc434c6ee3336e325cdfeb6c6117f5180fc3be0858091","0xaf2371fdcc3ec6b7337f88afc3c0b130bfcfbdcf02e2c48fdfc2e04530f36a75","0x84b79a115d35fd7cd28026ea26757eb4f6841decdf31c3a9263c6f3e984cbe49","0x2ab9db0df624b1cde97c36866f8eb9fdd37fb9c0e072678d82334a67c146d11b","0x69993f832331eb6f5b05930c79fa700a8fc55bb6e06cd91705fd6d245ef08ef4","0x8ced49f1814602e2ae6b91f519e97950354ddec52ae654a9e536930f3949f14d","0x21d78e83fa85e698dbf8207fe6ddab4a67fab0232c4fb7faf8f274ff37fb6e8b","0x6f6f5381924c10b6b4c8e9fe9f39cff1c70faa7332d4b360485f584f0fad503b","0x398a056409bdf43faf32b4d58663d64c6e8b6383e55f5776f476ea5591b365dd","0x1f7c3b494fab52f6124ba88d67cacc991f46db6c3879962588b74231ef91c8ac","0x7379558c79e5331a3a3e1e7e9e5446313146e2f8eccf16ce1913c3073c95b0ab","0xbb9369bbb3cfc7407abbb3bcda2a3c520513340409ed6060fcc622ac4b16c571","0x47f803b2e04634a6085492a70f74593d05da07503d69cae8b8ad9da9ad4d90ee","0x4b70a5603b46e5d3aa58b5abdfbb35b8b7deb96dfd30257d6486b0d26ab9f3b8","0x35ecf80cdaa68940df70b9d19c941cff334fafa50b7520f59e4f74428a5963b0","0x145b1da471f5f3548184dfdd999c9a4c7d462a3a07d932a16aed7516bc2dad95","0xe7229a9c550ed71aacfbccdcb3bb23b7f1c8535c27797c750df4f4834263ddc2","0x9980b741f4163fe1b214d0ca5fd4c2fdffb07e9453afbefb83fdff6e37b327ae","0xe5bf1e41a7fe87d3a3380ca09c90e30968bebaccb240bf71382d7356be7f6e70","0xddf8bc1e9da6c9f089d66f9236ba047e64cfcae142cf6fa7d3dbb5998f2119f8","0x07b9b0cf8a5662e86d76eafc5eebfcc2a3e1181391111020eb4379204ea4a18d","0x5aa754d2f04817b2fbf5d3991607ad52499bac4c01fa339f540160bea44db110","0x5ef595d5c10a874c8282c9842b6795af4e13e35699ae3cc1dce9544eb46f4d31","0xa8603130bcb184f08dab93ba2788dfd01c30d2bdf40d743ecf697d330d8efcda","0x331c09e4c46c1a5e0a4b00f0dd4e6032534ed955e514f757dda437a874fb6cc6","0x8e572e6224a1b2ecbc9f551bf4a4c7df60d40b634b78cc7a5cdfa11f8131a43d","0x7d1c3d6369c4af9d2d0d0a4353daa305a4298998bb7b8c0423c59287b787c091","0x9d60895cb6a68836ddc72f6706bdf728c2065880af130824578fd89a5df16a2b","0x7432918a3ef097adb4c8423c3b946d7da82c4fd4beea232ae520d5cbe26104b8","0x8fbc230534e835beccf62289484d98cc2d23db4a1f5bbabee8d7dc9ffb639c16","0x909852635f0670197a07a439af530eea22647565ef70b4ea0b9e79cea52e0f5f","0xd21bcb7df4118167f571df4a313d781da7697f321fe617f16ef315d841dccbfd","0x13538dc0345aff003256ea2cee96d9c6704deb369c733cdebad469224eaf7fcb","0x3a406db9092f67fec0bac7b14774ba1c6fcb9a482d3b79603f5fb71d78ca4669","0xecc70a9e7180a6b4dcc2bb9fd52cf6a44417df20ed60d7a9c29cceb715921398","0x6389f3d5cb8aee2775dab706404727b3aa2f8412532246ff286a0feea906dad9","0x34039e8dd4f36ee4f7db297291e9348bb76ff117c751a9fb2de1891f01a71a04","0x2540386d72438b4607bce204cc77b9c58194c5f3ee1245a4c4a1232c7642a068","0xb64e2f54c1c9317c6b4d052be4695ce84eea6fdfd46c0c14370a8c5039356f9f","0x0f85c546b0c82621ea9bdd1992ef0f1f188d0d3ccc0403fcc9d5e6d92acaf5da","0x956d40a6e06af05fd9391e0dba48c2f2fe38d66617b1e25a074abf5f2b81944c","0x77909b653a9b732dba6c5554ba3278a234581fe3de5e482e1fb2863737ad77ed","0x07a625658554a487c78095f9f6cfbf8d3434c12f2c6e52f426976aaa5abba018","0x5a4054dd9fa2dfb9fba3c5c91161d39524a213427cbac2a3eeb479154013a385","0xc66c238c6645cf09000b459958fdc0a6bfdcfa892339da6e6730dc67807e57a2","0xe96f0c0b9cf9fda13f17aa09395502e68a0ef68119f622c4470f1dc04f8ebe5f","0xc17b8c15c3fce3784c6050f6df31c59ac49ce5d41347bea6261a7c38d863f15a","0x4cd5de1dc253042da7d66a96174db5e309fcd89f82953379c75055cdef906d90","0xe922970e14660a3f03f59ba92c776f6cd1d3e0bd576c466d8685d0cb940f4021","0x1c590670b60ce83da23d34aa2ee935bffc9ba18cd345640a1d3efbb178f52e14","0xa4a7e9edfb5f61df160cb16a5a00bd8af2967ee72a1114d141ee456bd039889d","0xd3ac5dfb11d9805203581963a67a6b2e96a3a8bbf8e75fa0722eedc010854319","0x24bb6a5d53e769481e3d613d0538f785b955835f4d3abfed2a411d4ab8086f46","0x603ad22b75f0a59bae623e67756b39c9d6c3e4ec6af50fa400b127113d06fcc5","0x37591b105f0df9d3b5320722a3d69df092b9808a7709e946bb03584dea24ddfa","0x4c9b205e656471404554be277135e1e85b1933d43119382db68d6efd37d2ae42","0x29eecb03e9345e1e7ac37c242a65afc8cfedda2aaaec0a11c686f454cd54684c","0xf62d1ab941f4d3be02ca89b348c69547c1ad5c010f1a6399ce843e337acee310",null,"0xbe1e5ab040f9ee2721202aa6ea84139e156ffa0ea0d4e813bfb824a726fc4a7e","0x414ba751854f75b39cd9f23471a2e2ce898e041678bd7f4cd202a69fce42c98f","0x7234948f2f819dd7d9965dc2e3404f6429338e366ee72c0184c47471ba96a5cc","0x911dfd0edf57cdd72e2edec5b25c58db00918a1e7df41cfab1d058b5b8af364e","0x6dd41722bb58804f60684ab3a43ae5acd28d0f780a0023b13c8bf67179e21bb3","0xbfbdb9155c645636824023af9c69f5c5f01fcb5375c91116031a7111c01551b1","0xeb2ad0d182dfc72c4093a9238ded71101bc00c57d8c665e00d26940f33882208","0xd7218439b10dc76b92fd75d6b03f50f4dcbfe9796a58bc2c131caeb6699d44e9","0xc04c1198a96da53b1b3d050f4277825801d27198cdc3a67cad3a360204eb78f6","0x3ed9de8080649c3d7588c7b4d83ea3e3ee08fdc334e8b2e0b252c0ca18f5b1b3","0x7fec943e2205ce0f510b0f63ad618d3ddf23bb17642486f9638255bab5baa99c","0x565eea027e1d2b2d74a3b760e2056bee1f5191b8e4551645cc913a97f4a6a892","0x446c2d4ee027204848479c46b0053b82fe84142fa9fe256edeb5ac710a143ffb","0x03181b30d66d60889bd2326083162fdac0077924aaa6a788ee43fed6efbe3d4b","0xb4c1e714509fca00c9ae17308057da5875819a6b4ff43683e637eac7a66ac43e","0xaf6cf75266f9be45deb2fcc43fb31dc44572b9fcd20856b74b8e208032b73f4c","0xdf623682de9570dbe8c078916b95a132e211a496bd20f68e0a32f71e1ec64b9b","0x667953d0c2f8c93354f6df823d5a9f4ad9ef939753ecf769f998b0a4cee06cc2","0x628979bc6a23d614c154aa0988185bf90f6fdfd1ad2ce4434cf5d1f0e18d9c4d","0xaabe26a5f1977751a30508f314bf8335738ed5bcff578cc2710939d473699b58","0x87205940639d0238d995b52e689d2f45754dfc625ef0470db94c8b8926e7fc85","0x097dd9659e2f25caab009052f52d00caa3380362a70aee10c6b513323b581f2d","0xc65a6d394b627ea66d7482671d730926cebe5047c80ef0bdb7099e38e9e0ca1e","0xf6f4d5aa00e49bd362f16dffb0acf23c80ebbd3ca54371be61d0a6f1de4c157e","0xb39663b0f8c3b9e866e130100d67183488fe3f4860e14fb0b7a42370b77ccdac","0xefde8f45c791f84b76867ca41bf9ff7bae292ad7190ececd6cb8740e9e20183f","0x88f75ff535dbc7c885bf73eb5cafd7a182cd5f403908c03de1cc374b7dab6f6d","0x03fd36ada049cdf544b8fbdd002827b1e6718d5996056978d3122af7d1a42996","0x6b5a9e06ec2f752955de4c1d1ce2a3829bfb731193387ee27a7508e004c5ada7","0xfa9bb533dd70ee1c3eef519bf39ee5bd9b64949381b01334f5110b0b9bc118ed","0xdf3d44d84feaeada6989516071971eeead21c937561cba1ce6fe4b9a62842ade","0xc3a7e2c67a9737c7adc99d5b99419ac5b5322764658e91dae205e89aff1be073","0xfd2427877e3a06ddaa5afc4aba33f9b59dfbcc63cd26a36de9d4789d6e0d9424","0x03016d30184550ec8b0907598be3a6a300393a2e060c9b7da5c7e27e04b01bf3","0x8d1ace72c7aa55d0770f90fc09b3954c6728600eacc0f49bcb465369a6ece118","0xb4d7cbab8411b92ec6e730e8c9d390ccc3454593a42fbca132dd1ea905cbc902","0x28150c4efe743dc8252be156d7142d806532fc73d0907ba9869e6a82cd213922","0x926db2660a9c0190509a403ea0f939ebccc2700a6ed278062350cff107e6f29e","0x9b844c56cbafdcdb23d1a37f2afa368400c2b0c4ebfd8249551c3100d8a4c5ad","0x80bda8593a26345282bbaf0ad69819e968165768ff51a180b94e1d3dce5c567d","0x3502634004f2d98fc14c063a2859ec795456fb53e2681809f99dc8d977bde5da","0x2be9a1c46964a953e9f086ad3cfa4c2dd80d9962677b98e89a34c83492d2fe97","0x1b8ab07c6ecfa80f954c69cb7fcceb66fbba74f4477b0247ecba2c27f9c072df","0x827391e27edcd3b2f0494ab3ba3543ac09de63d532d9a03c1f49274688900f05","0x472f7ec2af8ef93ad07a2c2d58ab9c9dc044aab9a379555a9d8a8ddfd77e8a8a","0x6e70fa8fc12117f5877cf5753632cb78b51c781a0da9f7930ea55cfd23b5ab94","0x59203931dcf4685c008e9dbb5374ab6866d360ca7c715036a5f1254580313354","0x21f983e4807a9eb409f65295cc07219454f7d3cdc197d3503ba991ffb876e92c","0xe351f5b98ee83d82e0c9715c0e7e97d04b528418dfcd9b7613dc2bc01bdf3f80","0x4d19bf2c828beb8420669a8738342f998860dd8a5516feeee58c1ccf43142d9f","0xcf645518c9ba3e381f827aabbf19be84640650575a3051f92ae0991f9273840e","0x42602cdc51408a4452f1166c3883791b5dcf4b6cb1ea13bbbdf9ea2050214d4f","0xa54fb92fe5a13124067cbe39804160308e23effcdeeb3a469cbeeb3fbc695496","0x639053a4703510cbb3282cebd822180679478845d516b0a4fe0103b98e77d49e","0xad0a248e009a3a371568911a3a6c67963ae533e092316bae27ae901e5c26bff7","0xff4452806107fc768a74dbc9a09b1961e9e5baf3c6fb61e7d81aab190cc58c92","0x3493d439d5a0ba00b64e69be6d391388b386e02f5c2e40267c37d066ba7867ad","0x218f37cf36aa8300be4f01b761f6d9cc34cca9b18268a369f3394d5d7f5e7428","0x72d64ebcecd31225e6ad7468840431f8e851327d19c59cd0a795e0cb084ef653","0x9783121862e99c8bb7c8b36b3f1da791bc73b0f5021038ccffe6ae823bcaf2d6","0x2326364030e4c4c8a292ce5350870986dff2341cbb47c0cf306ea6f200f6d4e4","0x01676cc9fbe015a8960971640a6a895433f610beb5faa43445fc78cd20c7a436","0x59e8ba83d4db4d2a0cee2a153b7c680fb1b7930c901c744be6a3738a08de0ba5","0xadff449cafa75885da9b2205998885068af0f9100082129a81874db28af9c193","0x43a5ee52b490e0e0a694e7b249eeab45b5e22010b47f590304458170e84f4ed5","0x62f9625af86b6af21dcd3bb1138a036ce313b6b9885f39d711e3eaf7659535eb","0xd5bec35ff5050fe1908920eeed2dd6d1dd27e0120bd6581e2624bf48959b3723","0x985fbc2ae11f530458bf41fbc1b9d1bf7540e78adacc6fd8e29bf9c3407c01b4","0xb56294b35db7f99c756b9f8a3addba3920aea96298303055a76ca0ad1711aca5","0x16d153c58ee76f3233f82e4a6ad9d54b8121a9467f39edba6f32c206b892de02","0xedd87c37a3ff5e3c67f4c470b465bf21fa97cfd71141d0692a26b28e1dd629b5","0x0c07ac57a07a9e2a4fcdd3b5f05651ffea18be744cc1b0bde151b10dd942bf59","0x371dc54a466b244dfde22ee15bba42e10e7aa468c430f4a3d21c6057b621a251","0x3efebee705217275aaddbd742d8efeb6e5eec7be9edc4f7ddbc97623ef136778","0x1b31d2cea219574422a918416d9e7de52b8110eec030918cddc773b459ff1787","0xde7940dd9936de25949be93ec72a3736f3e5de888922a065edb3e90d533b1920",null,"0x03bfe68819748cbd44d8173938610df7be50a9119555a65f981937c721dff99c","0x14d00f7a794affb6754298d22b1d48a9f36d290e10c8a50fbb70ce5c34aa6951","0xb8054c7f35a296e2915cd7596d4fc80d88bfe6a04fda0ba86f19de2a35438b1d","0x97abf5459b4ac14e312cbb7cb1a640231afe95498f74913bf7e16d251437f6d8","0xab1d9ef4685befdc424531194ad4550caee778726fc6492a9809a4899ffb8f1f",null,"0x6b85b771e867bb73b74e57cf34297598429250f73bb5d6f1de10eb4ca87f7c69","0xfe08254553c0db15f70603c27e584f85e9c1fbdc71816d5ff74485f38dad8a7b","0x354f6aee856f9292c2596446b2808fc7d1f90c99c0152fe5fd5d65b0d1c1b79d","0xce1ef08cf159a11496c33b4b907934e6c04185ed0c6ad25faa77b6d07de399ce","0xc83a4955e74d11f93e1061c34632737c7a164d274a35dcf2dfe7b01abae17e90","0xfca0eb619367ffd2fb5f95f1ec054487982f01c1f60c7916aefaa62d7bf496f5","0x250a4ffb9eb2098607bbaf88335619ebc5b0932f8e698ddfc8dd1a7625ebccf8","0x1d39019e9afea87fcb64e9c13bee6d752044433767ea8a0ee6ee250878e83790","0x46c4253bfd3214ef012f754d0170ee9fe08f4c7cd12be98384ba20aa534a0b24","0x835ac93be4cd6b7011026a0164366a90df12bca79ee837e0f6a58eec7ea26b3d","0x6cc68e67b18f36b2265ff96dbb020e4b5b461ef88e580e9d5ee53eb318477e55","0xf50b661f422fcf482b61d06aa6c28221a8dd43af3d7037b6169000241db28dce","0xa2240d60dd31deec46496683b3524b62b322ad5dc6c649ac6f003410f231a0e3","0xa8baebd8f1e579919c9931c3e3eb2113a40797ce4f8f75f04e71a2abfbfa0887","0x6be8c919562ef75555ad1f097edce7d80a5b3e8ea0f7946d85ee57fa3c782900","0xfae82097054f5d1f275436f01c046bf5113fb72d71a59ec4e544d7894daa3c58","0xe21bb792fb6bc5a69da614084b2be8d3a65f3c1c0e18ab8a1d840f4796a5313d","0x4eff7edf2dec63142a63cc92b7fe0dce2243eac7d7f67581751d87f21ae8fbdf","0x3836875c6743f70d7329916902e8aea8ed73136dd9a1a91ea7d0a0a48620d648","0x27d2e0844c1fbb3c664783c47a051b5d95583f096efafe064db5ccb0063aca99","0xe8465f7235140677acb0f47e707b7ea9ac64804e4b1bef1f90a01cf72e392854","0x5f4ccf121ea24c333c25aaae80936790fd9992c7aac948cff0a10b74b15ec133","0x6cb01bba558dd89f1076642a0c6ca37ae2a7eda078c2d638e2040427e4062fd1","0x67205aa576549aaaddd7f156efed15fc6c8240d7b01b0f28ef69ab2895aa20eb","0x61bb8f7381586d6b2ae0bcf46d707cd0b92c57e68ebb4fc2488dfa780a8e2c66",null,"0xd159c22b1bb0d67f8649dd9b184e47c6771cfc6fa4a89b4bb0f498463f41f185","0x5313cec32a9e552bf79cdd747264f989dcb5e3bc6d13a709d847ebd4853dd733","0x7f3705cc025cc3559118d66df65a815eb422d425556b3eb2c30a9c6ba6eb568a","0x1c16f4d08b487d3b8b903f23cc340b738d2d4b03f226118c9ef637c6a8e1f668","0x48084bb093b66b7ff1de22c52fdcf2e77f87b6d141b5abb4489bced9a9ced002","0xd43bb84b5c891195591f9b7e2d7a2e8754d8ed1ce562c22cd8786847ae044f2d","0x5283cff9a6c2e3eb3e972eb0b6772536224ee3e90f630be673b275a37606a89b","0x2d25cda19d1642639ce32e96d67daf2729f73d60cb7c0fa3534853c0f6050dfa","0xa64f79b2e6d2be58358d3fda2d4f78d15e657f0eaf34c26509446424187a03e0","0xfe60375d7d6cebfbf6593da64663aed478dfaa0a919777c8b1f943fa66eb648d","0xac4fddf8f34c0c8b0faca7742c1e7788608b34d7a60c7540964a8032fe5eeedd","0x33166a9a1e9268a916250af7fc96750c392577c1ced1d2ac53e66bfd87c33eb4",null,"0x2c6f940debb1e29c3ef22f76ac7e414139a82465e25361d1796448e0f9924f60","0x422afcbfb1da325e33d268601ecc61fa378bdbf6a856c2f1f4e2d94519642b0c","0xc61c5ffc9121efa23a031b60169af11397b051d961d30823f369ecf1d23c3587","0x5b4fa68c31afb86121052f35c91458c92da4a8368acf6a42812beb1fb85882af","0xca07db9cb8142ac8f925bcef21b006befd167ef6f77e5d0f45df9412c88f63f7","0xbf327bd93af84beb4afaa69a5bb492ad6c65c1a43baa8e50be8d611412ce7302","0x900e5609c07287a341e4d018e91edc5417f8d633e235002109e772647cc117be","0x494c329efc112c7893f32fc9ebbba8c51a6d8930c276fee0ec17001310d2494a","0xa845b8c74322a27ca6c4def53300be2029abe550ee9a5097f9085081bb7dd0b7","0x4bbfd12953a15aa51ea51d412e19a2d41f8ab176b0b15e7bc1bbdf5d6985de7a","0x99e5c4763451b21757f678ec4fc1900fbc5396ba12727c99dbcf2a0e9322dcb5","0xae18e25d5b6c27ffdb3fb5844389543e66f011378b62846ce036ab78dd1b29a0","0x2ed6b52f5664209dbf5a6ecebd313a071f398c0fbc2615fe2fd6531ccf93fadc","0x34364eed2639c59b14c4e816b46b48eca06b721cb25f01b514c4480ebf86f007",null,"0x413db3920fa57bc1cbe6bb4da960d29259a08dc2beef7eecff32996303221b5f","0x01cbd7174e8ad1e911c7c4e596cb543ca37bc838599daae1efb94f98e11e40d8","0x84c83d63120e6fcd77a850f435153e54bdd9713cb331eb7994168819f242d9da","0x3afea25396a3e6f35e438201a48464c5cc01b13fa1c9ca5c032e11ec7c0b07f4","0xf4f2b2939a306fd9cd7da18dc2594722c677780d4827921a67ca98e4dcfa881f","0x1e655181dbce7c0ec33d730a4c70bde7d2ec606847b133ede1326f8ddde8509f","0xa314d083db5e48f6f64a14e56980b5ef08e8e4864005324747f5be9ec5552db0","0xc5e8351826e8f6155a4d0c77b84aac2b5e4039f5e1b5713c36ca4aa84c07d456","0xc1a7bb380d1baef6680f6e9b2e3adf9acff73ac19f894c97d29e1bfb4e9459f2","0xc9ec72549f8d31d67cf6e0ea33fa826f2e0f2215408dc188478e3a289a3510ce","0xb03974e7a62432e107443438125fc2e5e01879c69a8ee028bb10599615049e3b","0x30d5115d90ec29583f31cfb09a92b92d893aa03fde06fdae3da7acc87459b295","0xb98d7e2527bf13dd316c3cf926c8d09ea590995251692bc61190e1afc1249e19","0xfd6fa47162575f3e4466ddc6d01fdeb2c8cbf46d2661e9b0d2d7bd8cbc3c2b25","0x4f29930fccc77dcc7f4a991421fb93611c82ee723aa3996a4ee37347c34d5533","0x241e81ca7ce6eff8dc80e09352ad4489ff9ac315caaa95d7260c9dcb7acb0c1a","0xfe75405729c94747a7858f3665ea52ed1c87f212c44c407312c0a8880f4e5622","0x3a542120f4bb0c57b1bdc3cb79ee651c488b1a660916996f426e1512549f4475","0xd7e4a72e4383b154d35a9ca7a34cea82a89654e6401b41ded25ff788ea1158e2",null,"0xde8ceed9c02d3535670b3bded8b47c37a39ec3a560b46daecd5237d37ee22a09","0x1d52d3a15e2f1a37b42f5955b8890d55d1d027c0885abbde97a5c222d30439ba","0x7ea5cc7e4b390a8252a7ea8dc7e54d58b10efd9622d4046662ea8b01323aa91b","0xa060563d5521d0a38baf6e74a1201e6076583fb7bae543379848ad4b89f82af5","0xf8d8ab9e4f6c4f46052b8a26dcf33c32615aaae0ff1ba4cbf73e19601df0a20d","0xc50c2b1339bc7e61757cc36165c56992c599af6412d4097220e66a2078174822","0x2ab15e20939512ac54c26cf6ddf86599e401cb5154ac4658ce78bb34dce61274","0x6dba169a794f2ca931fe77055905e820d0d9d5099f1bca836dbf34f24d9060ff","0x76124ff40304a8464511123402e3ea209a63d399685e86a299294f306304b02b","0x5b669c8170b044a5a7f53819ad63901f8762dbde4ded611a7925a707e8263096","0x04ca247aca19a75ce7862cd299a0fa1321dad5ddd7a8ec8167a8a33c86fbeb55","0xb78516fa91f482d115cedd3836b968d7332b93f8386508d939a6bd1d4aee3063","0xb1f686efb429b22efc1f22fa2a23a160c7d5a33c324ba02ff7a6d975ccc5479f","0xcb0861d6656e5669b5408401b56b31d6abf483b401f5c267d57b70229abb87f9","0x164e2118856e9d571a5fef7255ef17a2163136dd0bf311fa70b2e7f65cf8df26","0x57fabceaac8172efc34a2f5de3de2735c7ab0ae3a8ed8b98ed76a3742f653666","0x1d20c74f8841ed11ceec1c661e1f2cf29597c205ee7cd3b3b1772f23cb33b0d7","0x6230be17049db01747987d61e4178864ef0a4c015af2fd332075d717462a5a95","0x09ae49e3710cebcc4c1db006e8d51affe7404a074d777c0c015de3b131b4f3fa","0x0d15dabb63a109be75a6c094f994e1da1a526530be4beeeea50aa6977b29752d","0x745633b938c81cabc51e08a8814b99449f0a2828a071444e7cbf5bfa5cb3bacc","0xcb34fb67e8dfb0dc8ace05086a2418ff75638166f6d4386def2d040336424a5e","0x72679084ccc07f3187735e7a5985635243cd0eecdb677623395945f4b3fe6e6e","0x4456be4fea962a999129c979b7856baa42bd6e30b47b54c8b8e662a27a130c36","0x52cba683dfdbac88e20577aba07d4529fa030f4e59272fff633abd19e01f7feb","0x2fa2127a0dc3278b529524e57dc958611a19f98d16c0eb051344347b8598b90a",null,"0xb7bfa8f22e0a5944b8b6156a7ad8a925771208b990a8db2bda2258cb727d1a5a","0x26bdef95218113d5db8919364ef34dfd182838525fc6624ba431e35c735d7717","0xa1bae82eca9d92ce79830568c1af7b35955c97e915c466e31af142f568056a53","0xcda5678f66a5696f9a1e8347c35d6a0313d8af7ec4e1a97978956c970cd9d0af","0x8e978382a9f39f034dae4f909be12e25b7076271f31af850dfea9c36c07241de","0x3e9291ccf67e4425443629f5d24aa93162723f98762ace228616e2c098c1ea57","0xbdad472a30dcc8a475ecd242bbf6d23a632ce4cce706e3aab619a206be415218","0x3e1377070b7cda69bdd6c3e729958f9e0257ac1bfb72654f5a57f76165f236d3","0xeac0dbac71ca21f9744fe2f5147016b0e2d5d6e269d83ef09a02ff7f726e94d3","0xb150236da3b578165532d960eb4d7327d7d0a6a4c6c85a1d8f9d4b0ba2145bc7","0x651875674a922c7498bc31b847b363f47d4c28da339bfe0481fe27567d4556f7",null,"0x8dcc26a1b1a4660b72c114763ae3b32822e206f136f67b2ca40861c3a03ec6db","0xd3da05260f847161cf9bd98c0526d4c92e2fb69eaefbdd98fb5b562e5a6bf29a","0xd2a48e47ef5beb7b607cadba52d799d21945198e490bf26c268b9b89726afa79","0xff57b39233ea9ce839de000ba40f9591b3b61af8cb107e1d3a7cd59ad9775ad8","0xf4f7226bc78a502128a530c63b4c9adeb92444a8351ed79422adb1ad2446a840",null,"0x1c9c237f275b2fc6f7bfd813a0e077959cf01461fa0470c3e30a9ee9978b6bd3","0x6fbeee5ee6a86af4569a0be7fd69f989479aa6afdd1d38a44a1500c317c28e45","0x280c82e767e50f0e4665bfbd776afed93aedc27901e8ec38fede61d8e0e67f87",null,"0x0766f7dc8c77d78dfd462aad56430a9990f6b111d1ca8fa9b1b6a0bba6dad53c","0x9cdd91d1bdf9773642fa30be6c71a61ffb94070c5d98748aafdf102726a73893","0x08fa58e84c8ead64a5ebe3ae4fea13277378ef4c07eae5ad0b3e416ce76eeb97","0x34a2bfd05bfa44114226a4027c75bf0da12255a6b6a559e9a28ae9aa374f02cd","0x4f6956111b3abfb6eaf81bf680b95a49a7803b3c8bb53a8f3ac3ced0df77152a","0x59f87a6d55be8ccfa9b4135d58ebe50807d14f1df8f9226fc2ba30067a8b886e","0xfd7b7da9d0e58cd2b432a55d0d682e0dcf634b37530b8d433e07b30167c47ccd","0x73a62dfc0dfdf4607db93fdf8ee673436ff7bb8434ebd1e9ffae2f950bb79a9b","0xbff58e2da1c4eaedfef2e35768fd6e37061724ee3165cce4f37405bb4c7dfc53","0xae61879ce8bb2e0f3101fdba791b24902524bf804363be9524fda8973336923e","0x8d2d361a86b063e40486b159b88e5eef2658cbaf266611c34064997477f1103a","0x5ab59fbf65acb290594a128b802b6de1e8e17992d3d94e74ef23eb5e756ced24","0xf7cdc69edceb33bab5c7ce79792adaa0532df97cffa1e62846fc855de337afe3","0x5094a647bdaed880d96f4f6841082ec6f3e345708b0efe107ca0e7508abecb10","0x9c553abf386cf222604ef5b14d1a3ff61fac7009380e8d008b03643e8231a046","0x5d1009a65da54ff98ecf083494ab9e30313577359d4337531aa2402acd85481b","0x3c108acc7fdec6445ccc6f8d74c3844d3c684648962809a73e701587c0880750","0x1f37460ee9fca543871aba3ddf1c142c97983b6663b4d7c16f6c4490a7c16f45","0x0fe589732204d3a0aaa5be5830ba660f12df48a6707895e3ff202b4c18b61af5","0x8e72f54970a43129ead1eae70cd23f2a1fe34558400a5c50a28e4e828b790043","0x3362d697733917ef52e969ea97a8662a11cf83e9adedb5cf1a176675ecf32f9b","0xfde573768101e749cc5a77751d0041952c924a72186879bbea942280c7409640","0x7fbc00d6586b7e139f8673ce7b49552cce7e1fdac38e74b899055c76ba9c3a00","0x0c8b87c1b7b81fb82f489d10967fde9dbde4615b08b309894d369c96a8e59fa1","0x7ff3b7ca0dae607fcab0290cec9c5ce4e11acae7504a876aff620afd167820ce","0xd2aeed0f8a60b44f86bd1ffc876464c006c92f0489cd68a23f076eb39e856520","0x1b95e638fe146233b2ad7e4093f591d88351d7fe8d554dd69783d3b15e99b868","0xbd71b3fba9aafbf216386d5ea67bba838990d949c4dad9c324ed7e45c3026df8","0xc5235859f1c8b0c980a1030300325493fd10ccab6e9c9c87ec972cb854b155a4","0x890a6467e557b854c306b452bb1ebbcbd9323f2d57ddfd34972c52fde2a37208","0x4874d9d4110017db6a13055bc210fe1c1846f42d316b6b5098ab2f9badbabd31","0x2218163389386e0b8606b563cc479fcba4a1e5b865006cd5d2b3d50e0a62146c","0x74f1862f08ae91de2cb75f8a7c4abd50652c9c82470bf7d6954916de9b9074d9","0x3d9d9468c340c61e5e5fc35cd01a5295b79759eab09ec1522ebc463c70bbc83a","0xa37a594e434e8b482cf83213451807df6c562819d48e5848400e32711f11caf8","0xaa735c5e8781521b498c6285cb83400aa51053981824b92e8bd1d036dd3a3323","0x4729f4e03dffc0da252009a59e5713f4467c6767abfdb2ad6311542f21ff1a10","0xe82176b5062a2a166f78d6e637ee99090387fecd7933bfcfa4a485c3c39276b6","0xc358b11adf6b6eda5c4bbeaafe45919754c2fd15c2ef143ecbdedd3bca65b18e","0xa059a822fe533e55b00bb2312e420e958c8008a22e15347ee3561e5cf56b7585","0x8c817d1fae938e9fa7f7dc663ff4e935c86dad118e7116d7c784bd10d4f30a03","0x06f385a3e7ddea62c47f0ee602ce00545fa7c8f9b40c01e4ca037e29b665edb2","0x153c196344e4dced1e8a7cb0d37163615e34abbb6580448e1e5a24b506f2cbe2","0x2ddee9eed8c27a9e6cd00027f178d94dba21c1c7b6f7e5b7b948f44a425fe34b","0x1345c14c0ca019a4422663b7907a19f74fe3d213243d7c3d0bf6088878788ffc","0x132e4cc72575cee44a04cce771b9b6046e7df58b1e3080b4017fed995ce44bd7","0x436a8892c21ecb602a17a38572d5e432f935b6adf5fe3fc93f3e14e323424997","0x565a60cddc2e1faa3b74577c0c0d15b301611094e0cdfed36825e64b1dabef53","0x75144ec04b97e51feab1b21db777ee66112ce72ff3b4ba986f18aa9992236922","0x2c3529e7a8ff6052212253004b8c332523527e3759ad6fe7598c2c62d00edbb9","0x10e3f883b874d31ab86c6182b9167ee711c19552ebcda1b246e82ffe4086bf0c",null,"0x84c4fd14b97dafa78bf718576346907dd762ac89ffa0bbdb06ef7227ff955f6d","0x5a05575fdcafb87b5a3b5bee4969153e0c511f75f050e1688b805253e2c0243a","0x462af4a2c89a2dd66f6aefe5f14251533dc47b575186a24a3268700246ec33f3","0x49a74ca7a09146d9e3686e3d95acad349e46a26ff8dec1b7f7f4154acf444f8d","0x142cb8b658a444ab0402a29efb55b2465f8194b59f980de42be947d12eb6ba52","0x0811e8266319f56135d018d435ae9d1113172df32fb2f4b00a3556740ebd3e7d","0x58ed5fa5a07799f3fcb154768675cf00cf75da4a7d293aa46ba007f577f0b1a5","0x2681ab7b897b25393026467c50aee092398eadfe0422228c64b5809b91943a1b","0xd340cbaee88a153a147858661feeedad672a7a5ceee49a9410dcbc77d62b1c8f","0x82ea467615390f0d18a1851a3b03536fc504460b9772004b1746c714ef461a5f","0xe74687b412ec0800916876313b213d5cf9a4177a59caa978d405570ecfec7b90","0x960d190faa4e050a99f09db155a001444c8c7217dee670d2f5709c6108a5c04c","0x0ba4b89fcc2be39a9c196c20c7bd4e41c2664071f4306e783cf9301be886b067","0x8a49d5db50fc52ad857c58866cbdbfbfea2815b7e2ef04f15a71b4a07c706d06","0x230cb804d0f0e335ccb7ffb565bd75e80c1b77976a414bbeb63d76e4d7c4344b","0xd4fbc8ebd990857ce8dde921cd72615a44e61626abb9899e9b220d81255a1152","0xa4c658788356f2ad9a80e57407d0c2760ad7ce70f4bba6760c8ae3da9ef7523d","0xbfe7e170c06ffabadd8c9ecd906f036b1665636f9f2998cdd124344a96c8373f","0xb5968631c394b3ae8bd445ebaaa8622486c2f29d3f802ec7e9c6fe1a1e40060c","0x3f593a0d036b9ab437108928958ee5a208cb74350bb7f0afcab69fdbf5c6eb83","0xd26f4f1a42d2a89e96b3ff9932c3a43ce578281db3fc56f6c8fd8c947cf5f959","0x20c05519efe322716778a75798b63c73b5794ebc7c8178d61f466396c8b30e60","0x428402239bdf37bc91ef04440a02714f81ffda9fb3083c1e4992bc7a0d5a86cd","0x5655bc4260704aaeed27ad0697703e77c140566096596989c99afe8f6d2f082a","0x417f96c159576435e919c62189b20fdb8f7e204d570fcd8d3366aaf4919df069","0xc8cfbbdcf2b4e6a845dfe0f4298631864fca687eaabe5fb833d21c74a1d0e6fb","0x92b9db626ffca9cfdc6434e412edeaa97194bfe3baae9fbe3a95700c82e5f675","0x84dc04090335c5b48def13161c015c3b132a47e77983bcb1f9d2692cb8892abb","0xef7bb20fa1a3defab5a983eb259c93941807fdb67d7c06b21e30ad5857422571","0x3a5fd143cac1d30bdbd345e9dfdc51781337ac588ffe779894cdf5ec8d754316","0x26b702fadf41cc8cebb7f0b425e835c967f608fa12f90fc7f225e53bd5232a92",null,"0x4f34ef5d25f07e0fa9f69afd599fbd14ad023d5ddc1018aac85b46a2a1d6da8b","0x0dc867fdf6dde72471c06dea1c867d5f28f94ad58d213855a3da654b589ab63d","0xa381082facf40b059358aa83d291f32a7f3118192abc119438aa9c5f61dc71c5","0xccc8b417d7e087686bb26050d14874df08687030db12b64578fc215c0dce4385","0xfb6e9126e04301b92534de421ae536c77ff7f07f2bb730a629bc1bc1da9128a4","0x66db17f85565ce8a229a40ecb1f71695a584884bde9ef02295625c4c1426c271","0xab0ad2702da2bc587a59c9693249534f6dba1b7ebc65e76016ab76d824b318b8","0xfa6ca120ae3ae49fb71548e6e41f09f16a3440a0f165082fdd37e33262552b65","0x5e25bf5822f109427326783af5b9558afe6fc3dffd20d3b58c3044179240d71a","0xd0e98620254544a752d0955a8e00b71022081e2d964fb8b7f4a426bcf782a32c","0xcadc2f32098571786de42b412ff1141979a93973f363d531940d5cd959879532","0x8a1bdc66c90d21720c2c156a225340748f0e74eeeeabb9a0a531d57cf4d740ec","0x302139986937550b64ff2b6143d6aa93cd4aecd46c606617de334ee7b58f8693","0x42ea054168980640dd2f35c8900938d76c89d73e8a31a80d77af20683e0d1311","0x371320f779d20f5b2b08dfbb7f1191476ff6efe5246a36940ae3d8ce0e596247","0xa2c963823533831258526a40ac30eb671690ca685643da48bcd37e663a20b17f","0x19012a97f690c7bd5fa7f640c722c54b01ad656e146f71bd5726b88abd5dc2ec","0x76a99b80a1c42e9254fc2b5bf65029006455def295346cdd8cf9959471ea6f53","0xb5f75adb990f0209d81a85e6966fff7bc154293a3400ad1b3b665d9ff42d8c1e","0x914938d18b5e1a5f407020bd1033dd00f434d69ae1d003f075d5ccb9548a2cae","0x801e749d2ef6d8a0d18dea2a312747b0f3c200b453573208044ac94be5915511","0x5d7b6bea8a6e85dd146dc533f2427bac30f4fac032fdc4f8c9af71f7f0c05395","0x54abf5b3609b0b25217db96bf7c2493b1b41430fbb755149354252a75831bf5f","0x1b0e0ca894b531b935c772969ebcdaef47457e3d946d87e39ea3d9a268cb1118","0x5a98c13816325198a5ff7744304e514d3b8e988c28d1f97668c93fef53b07de1","0x504f8ec725ea6b82ec37a52dc47622aed54b6689fb6036d2f879f5d10cf860e7","0x76ae9bd1ef3a66593351b0949e6c9bea4640bc27f574164f8e9a64262d334868","0x177f957f46fa50a820e30dd907e71194880d7ffc6731df3fa607f0f211ccb77f","0x41fba9f4ff12d152d84f8470cd1a470fa5d2b6788fc3c1a4780b934bddb724a2",null,"0xb3d8053a52e0d137533fe14042b9c3ea7349533787e972ce61266860968ad930","0x59acc74a1a5e91cb5f0f0371fb5798d33a8e9763ddcd6acf6f2c9c5feb3b7a0e","0xb422db692da50c55fbae0c56c8a21c8987b69d90ef5bff9e78aa9ce273e34fae","0xdf85bdf292fbffcbb2cc14c963b1481910bc51b0420b19153583fb24f8dce5cb","0xcb21aec50513585239d29a69cebc0ee02936155946a95867e7f8b4a6112df251","0x0e6bfb6aba4d8cbd3cca1baa5295481315b2df632ed49dddf252b7df179e64eb","0x97865eb5613c29a24fb1609ea8c792ce7c53cc7320f86c7d755a9fca679e9b77","0x0991044732397e9906faa7b07e16543f06fbab8cee3225b1c468566b1f595c13","0x2f6cb64b74e6e3b5e357a6861040b0769727feaa5743a110bfcbc662b3147505","0x03495b6c3203d7a5e7104e965271a4d0b4cef4cb3391763e825c7ccd3978617d","0x62b91ff7e832742bab963c7ce5e555cf05a110a15a29fed189cb8585ce95607f","0xaaabf5a0bf5ede019cc82c3587a2bb94e002e484ec61f4eacebd335ab0483293","0xffe6a8d194a899183fedc291da73a6ab3a4bb3becc1950909b2a035704522642","0x5bf9e432bb3d1a3ed0d7007b8788d7af22ed57b96d27cb0f1740b1540e41e6db","0x7f8051e74db33806de2e972993a0965dc406309986a15ac698e8349d8830ca7f","0xe9d3a929f6f51786571fae61245c60ef6c4487a5814eae3bb7a2a1e5f03e00a8","0x422f98f30b4d08c7417f80a9375c1f8579fbcad270cb43e0e7068373549faf6a","0x487051dec8a10ec378a9d3cb023f2b496183e3fe12629ec276aef07f4bb2c689","0x1ea3e0f19e55c1b0d564496945552e3c5cd087fa929676b7f6c9cb199eb888e8","0x0c0e1cf14e210b3164e2b5cabb41a54ab2cced5cbb05307bf46af130ef6f6c8d","0x67a42674d4a87aed897e8a54e117baef7ae3c78d55ca2a23760696a5ecc7b69b","0xadd334b326f87acba8a5043fa4c076c42ba4b39b90ab8b805bcaf41dbfb95946","0x11d825f6622b4edeea109783e2b2a9a98cb9d3eb9f01c36e90e35b73a5a0000f",null,"0x3c11f1ec45454385c251b284efcfa185afa5d1b57bfdbeeb4c1c55a4956204b7","0x95dd9169067afc1c294a8c10cef803ecbc793710de5b8d1b41e93274196c5fd0","0xa694e4290e59dd0fa8c2aa534158f459339280bf2ed05a6dd76a037ecdc2e442","0x8199c4147c3fc317747cb324e15984d799de66341b9061f0c7c3b1eb89584b44","0xf4929e4500a68dde049091dcf40532b6db16f9d51d4796d7d3356035f07b5310","0xb2d38ae7444740dabd48a09152c359b5254e67b6c3904924b8b5536b66fada8b","0x16c9847443d4da8a8df5f213ab1dc329acd418a99cf8825f41f9014555b5b5c4","0xf099e4dab5a47ae45bdc18b64f29700460b55c18d7ba33589b412b684c9167e2","0x66ba3c71e9cc492b0ebd268c25bd333b7eeee62e2e8d4858ae92b2c4c76649cf","0x8db5ad3e59ed8a015785bc669c0365e3ee90b17d2ee0bb2ad7bc7ea6baff2a0f","0xcff5ea7715bd2534991f0050e6e2336d939ae67631d2bc0a67e8e08fe5380573","0x6193f87c919040f299c749a3fe2afb5028c8c75315963381c7d50ea4638827a9","0x3b3e12567ae941caeac22afaf0f026962e6996f7df71e1aaa44cdb7e9df95244","0x8eb05b8a3b70a55eeaa0a3033ff897264f078e207d5c2b1901b687a77b718acf","0x5073a314dcacc582012f3492201fd20115137c43f481050c902b6d8251241c79","0xc7d3b9d9d4153ed8a3a5440f78c8c8276b49df7ac40b60ea6689a98c3869aca7","0xbe10fa60df4af66135f34cd6697d8c728be8bcaf42db1448d1860ea9e0b72e26","0x8c485af5ed9e1705e7ab42b0af5d3d8f6214c371b250d43700af1604b25226c7","0x50b13ab71b233c055bb8cc923b95e71f7e5ca215822cf0dd14809dd8e8a05d8b","0x335a920b02447bb1f2c4ffdfd76fca791045f7bfa0f8c8cdd967ee0310c0bb43",null,"0x8299559714b02942a8f100a3e042712620cea00dfde1b9dfdcea8fb107a14442","0xcf2e29d6ffc0ecb1ce009c6cae2e7c7063b7f962a6e47457c3b0508bf5eda6f9","0x936761e96e96da21d056ff892eb237f416a21dbe415c5934c2eebd2ee0efc5d4","0xea7d4f4431d64d3cb5b35b30dff1d677058ca229647fcef8c5fa778f8c6bbc7e","0xf6e0e3422eb09ee83a7c7ec9aad30c66bb269411de3763ef6568e1afbff4c9fe","0x7457d52da7a64ebcaa5fc7c5682e11b15b7fcb7a1e38d97143e978306b393017","0x8e1235f300fd40b6215a92363173a75ab4e2f0099a138f433c6e398dd7dfd7de","0x89b8c02046d9a62d0999061a82cee266e457970f6c287984f5c7fb0868f69843","0xed11f7e24ce60c6521199482f5bc5bc7e66acee4be38aada1df84e953d9f5b71","0xb2f0c3eec0df0d554b3db479038301cde1c69ef03e3238571c23f116ef391e18","0xe2db6cc87f2ff28fe046c49f809d71bc34384349b3861a65cdbf464c80f57c97","0x6d49d748bf030c7e68f2abf19d3d88ee8bab72878a68e87c08cd5031aec071ea","0x6d818e44096a85b9e2dbef96aba0fa298351ffcf220e0ed199291c435ca5bfe6","0x768b62aa73376fb68e83fe91388e6523eeb9180f3a9820d225ad3b28befcbe38","0x66ccb957166ceb38ec4a8e3b2cdb9d16e2048f5cfc9838f72e9826cea13d5b28","0x62e8e4bd8a3adcbd3d80816bd327d53d06b172538fdb2b406364c16438ed7bee","0x5b590297a3dd5bcd2e7c7bf7bfd6bf39fcb491f0573d1389bfd1bac36f19deee","0xf22065c1b2468ccd49113bed13051d44a101dc04134dc4a8d0e11dc472da1a20","0xcf4dc205c3a19c129609fa3e7616f4dba05c5804738dc728322bed02cfdd9ade","0xa54337e1a3914ebb69166c70f566f510da6e94bb70ee9eaf42b0e4ac615d86f0","0x3fd22f062217b624e2a6f423070761683639d3a0c500c09c6928fba7d265f226","0x376cb1cbdaba90923d31bb85a65a288ed5fba9442db9a8a031d5871e3cf95b8c","0x6258ea54b64a2493c8c7947fe8ed3ca41273dc3dc2acd5549e8ead5f584a7718","0x4cb7b4b0bc9f66c7ce4feac8a479d1e9a8ec78f1819a559f493817f4a1000290","0x46ac49035a6db22be1eeca06f8b2f503f2683d6cf664ba0dcf269516a3f93b6d","0x5c2843b81f3a0d9c0157a6a8762b08c55ce7d200aa117a28c1b2b04d81434a89","0xb21e4618af987b8f17a7a7f2536f96f9a9aee39bce5c9264b9ed8ae07e8d65e4","0xfddb5d5acc03089f0c2385767a54b92ed83987458ac58bbe0dcdd8ace94e99bf","0x32e8f8212cafdedbf206678d85da9dcede4c146b6bd80a12b09491600642c744","0xdfcd54084e2d7ed0c85c8445e0946627c793fc1ad39a508bf241a519cf902e92","0x6f42eb5315075ab763ed0b19c507344d8b34071b00c7a69100c6cca4097b4f66","0xa704014f84ce83d5fb70381fd82896011afb18b109a00398f3fd32166f3775a7","0x27e1686bcbb31dc5c444e9a2ab27a3b806d66710c57489edea9bacb70e9f7664",null,"0x3c210a6df4b242b6d4422c48ea9eb252480a96dddd14717450f18341c7b67819","0xd61a5cc3411e0bf8c3d8462d3fc4186c451097195019769937ce3bfb79b5523c","0xda8b937e4c4dd0de883ee1e763e93d5912c3ffe1de6e4264bf5a4bb682964e99","0x10a80d3c02f43ac49b3de30613efde4d8307e0b0370a651c4fd1c1a2d7d8c813","0x308141c003800f768e7e00fde35bdace5dababaa1d555639fcdd417f34fd9684","0xb7659f42e30ec78bbf79d3a6443d30396a9ac79b7ecd085b08a09c4fc5b46a9a","0xf33dfed03c1eec54869a7185a3a56a8095d6f5b2e3f156d97a3adc0f1f88bb4c","0x868e79ef8a9610b587aad2b313f32a6582cf0fcfa9a68a2fd1e389a4913e9fae","0x0206b0e0671bf0999f754b6f26896d8deac7e3c3d94b19903fb7e0d1c1ca0d2a","0x726f2feef628a672758fda2ba595590bf1c8ab07d914fc76fd1c6d3a646caefa","0x75e38ca57f02f0ee1936f9e4f8bf05ecdf8e6de549d210ec19f8f5885330d2be","0x1e84ec1a67660d0e9472d41b4bb7b552d68519a0237f56281e0a17c6302ddf80","0xa2e4fc4186741f0d7b33a8e90929c22ee49db15e013f1344d1be174d4a183189","0xf21b8c5af080b5733073708fa197173664d57dbd1937a3265e6aa5ba53f4c19c","0x3dd4aae7a8843d67653d9aa611e4a7a749c88a78cfbcc05ad3ef3a1f0bc4eca7","0x39eeb6185cf36814b0028d8382b0dc615524a96b349c06bb8732dad6d1d0ab51","0x5e42311684b43e44b0c6317dfb4cf3e4cc37dd34e1032a5c26688c948ed3c8b6","0xae1e0df778a7df20277f8e23cdbe81d36d39c14b1917ca76b9358e0d3dab9a84","0xaeddb6ce6e12e605c405d22115ce8026f17ca92ac696f37fe4292830d3ce44d0","0xab7ab44af99e3eea080240da0ac83345f0da12f5f274c81f33b86300faf8c45b","0x3bd61e3761efa9aaa36bb51d3c109de657a3c514de3264103bd16b2282ca844a","0xc48a36e891140c550f248fc32d7ce288c0f28ca9362a673a7ef82553f141358a","0x912d0fe78451d35f652bb9c92b73968156159118223f0d992b4c565356d0f3ae","0xf269460127158a75f4bf4e21653b166041fd93dd9b3a11c0898736a3fe31628b","0x430364cc0feb5138d51aff67ef6e273c8afe1bf51ef9b5d11cb5ccc30d0d318c","0x11fd7c4738e099797b1f1bceb68f2e541a92fc473cf973018e5591223180d883","0xd616a94aa3edaaa85f39e9723d848db8f7ad0c5714db1c0606bf8744b9a2e095","0x30b8a81b3efffef3961ee37d318a7581aa17c215158604160233c4ea4747f94d","0x1246d11c9989d560724609676c336cc565807f108dcaf0d680961f07ac33b269","0x1a7e1f32b32442d1f0246d1cfcd938d47fd34e06611b6eb8ba1c5cc4adcaec36","0xee8309a89e99eecac3107c859a74bb1938b6812122976b36df55f75daa8335d0","0x21cbd3c803291155e7990d79dc92f6043cad8b6477713699bb27a93018c45873","0xa74078d0f325d867ef5571ea06227b109b974214983c76186f53ac602b5eaec1","0x26a79edc3043e8667d329d1b5d69475e16d1331736f3d3bd3e8c721db23cd89b","0xc46e396316855423b0c1c3012ca674e057232af0861c937ad0f25e747a606041","0xe197f9b56a4e25473f8f939cd2fd6bde12d1e4204caf4261d2f1fe0e65571e04","0x215a72960ebdd93b3a12f2698da0acb09779f2032bc0d636ef8d7a602b47630d","0x842f21aeebc3acb528680f325381469df3ca41a1180d47fad7287700be466417","0xa263ac0084e85a7cae92a50aaab4d1403ae98a8e54f4fa4c72274523208d91f1","0x0da36be2383d5e79e6ed2e71f221281db401924f22e6a92e92c8a3860a990b1d","0x47c0371c3d1cdd78ca130fc62b717baf63a8067f7e109998f4a5661d09ba6c36","0xf1fadb0d3c7ab9a9d35628392a39e8272b70cff9a0418cbfd10c6de434afc04e","0xaa9d0915a78e87ab796fd64f2050c8c49d3b852112daf56c2e53eb613bc881d4",null,"0x51092136cea8544fc41ad092da09d5657f593db54823b53cc05eb1179093efe3","0xf4a523abba0de93af668351218946d95ce6f4e7bd47f11a9c368ae668878b513","0xeef44b27d0b16ae15b017362b586d3374eca951125d9dc40f48318e13afc9e90","0xdcc9a648b156e9e49258e22f819de5c36c8854ac62fcc30d202769d00881fcdb","0xbedf7766b7b52a4090725164494aaf849fb2e0444c333735e18dd6df5a82c1bd","0xd96c135e258ab5ca8865915472c03b5952b689db210ccbdf4276403ad9ddc316","0xc7f30c6e138ae0375834fe895957d6fb41761c3be35f6d67a98543b0465ad36c","0xbda967a8fe766dcb8a5aef43d67af55bac03a94a6199fc6489c04901e068c9c7","0x9fc66cfe70e32a77f2f556e69c246b6a735c44f0b57e028030d0b6b1c831d6d1","0xa7f1b2ffc77ae6494fede0938cd558c8afb2df3842c31549ff083c78dc889c90","0x75aeb1228c8685d70196d9e0d9b856c74ff388e2f3e281ff262e6c3e99d653ea","0x6f8207f82c03f960c5563dab2c684c621716a223e7899e9f5ba72baf7b99accb","0x1c1ca4c4e65cd8a0e30b8f55405c419451282f33fc2a5fc29b6f52cea5e7e8f0","0x9370a00bc8bab543d1f9ac696ffc0f09388e1d9174daa909b6d13ef08008ede8",null,"0x9e0dced70fe3568cf6c1ad849936f3aa0c4c4a611471742c0a1c0068907534c9","0xbaec8ad8c46aac60c6eb6edd5bbda98c9c789b2da672a0449900c1393c7aa7b2","0x9c3ef625acca321b0639d7f7b6ada86cd09cc88a397f4701df42d416d9daf4a2","0xd83f76d21855267bed0e27974248dee4453152ad140be05a8cc54ae4a1e0d3ae","0xc2063a0902dba0ea6f49cce232210923c1296999adcd7fb4ff71d3f6d06f00c5","0x2db5f5e95f1f18b7e0803b6cc5ed129fb39e2124fac5716cbc48cb614560f3df","0x300f49e996034bac00fcd799561e606c1b26ba6a5425aea5222460780c60cf23","0xc3dad50cf6ab5fba9457436c5208c394ce82b0caab7ca02ded0ebf745bbdc79b","0x0f489862543ab93dec59599fafb18dc0c77511ea7afe55f0b31a568a163dfdbd","0xde7d5f60ff85cadba23b9b050d4a841080b99df5e94e45f5a642f874d575ef09","0x8a443dba3e40edc96875b9c65cb9a38d2ea18dc473e2f4cd7e2d4fed668c2fe0","0x11bd8187a960fe4998c1dbeb1f5cb90a46f3f842038fc7f16492f371128544bb","0xf7e714659566dc93fc388473dc6c48d60d06748e94cbf0cd67973564db6a8c1e","0x3b89854c7c8b054f9fe9cb19fc0e3f0d01aedd4f82c16a6054ec4fb2a9df7189","0xa4a61f30903515c8b2b6e28c77ad8ac6e560a9abb2004a8b459a02374cdaba2c","0xaa2796f92fa8ba27a124e5917496fdc3d8713f14d8316dcbb783906afba2cf69","0x33f3829d60b64e5cda05bfb69909a887fe775d62a1a441fd6d7472061737ed08","0xa7c7dae58340b9c3379e5f242b50baeba71ab90336c6caf758e7316b46ef96de","0x0f5745bf9d03c188ae1b20cab263e793e91c59004e712a70f6f8092cb1c9d332","0x6e2a28eae78f09d5d4370fab592551871348598e2bbf3a152d97c1db441ad6b9","0x27504ec57797d7ea3b914c034513d17158405031aebd0487341dd5d30cdd869e","0x9b189e2eaf4e4d7315f1bed86c3772bcbfa4ffada7d00d0e52aa7cb99cf2b77e","0x2bbaa9d12f4fdae9e7a37599e1c37f6d38bb121cf9a0c0e0c2546c6c9bf9552e","0x97db65bc056240d707b7c420fa6577b364a9a04b2025e0328e8c8167506f5521","0xce73c73d7fc46ccc367f0c87dfea27b16035437c6a7ad4d603d7f8070e530f0e","0x15af7be6a17fcd4e31b0de4c3a346e0e1f20b59599465a3136a1f478bd176c94","0x2e633dd07736f79947330d6c004f551be6005761bec3634c3186b9867a6c7a17","0x5fb7044795004f14c4fc4bd2816b763f6cd9a8a5d811d7ca5cbebff91ba12d37","0xf3655f886163fcadb096c9d7de74138e69b2e2b25c588b54af3d75ea6bfbbac7","0xc4cdf9b3f01c3ae594b8fc630b2690225b7474c632f76629e2d7ad5448993a15","0xe7885b9635ab84a34f399649988ef64a9466091deb40d5d99af921e8e9842173","0x8da184d460f92306850e229358bf3f7574370645cf68715bf64ddf9be12563d0","0x6d8c74f2ec0aab24260658991965b0451683dd87514b094c30d72bd8886ed283","0xe3a1a9201a2c5bb5aa1b3f5b9bb6bc28c9b795755f9b6191292f381144b4b515","0xb57887827409268ce7bc3df94114c2ab4d13be46d0af8f40d0ac5b9ab5e8dceb","0x0f991f6decea4fc9057dfe3a9a5fbf5eb7f1c68827566c2d4b303791d1d1184d","0xa78e0065a1f6a47771ea790486867f082149a2fc4241c152ad3dbcd24d616d8d","0x5ba88af139590f8514404ba30afccc61304ded5f6978dc35e932b778084691a3","0xf154c4af97dcee50b5ab45f47626ff266e36f6316fd779ebdc12ae4be4c74e29","0x97f9d0c72c1f98d988db050d51ffc26a27a951929f934651577285d444987745","0xd6ac5a8c6dbc44241be39ce6f1e4b5dcd5296b1d26e1572201a91f997f4966c5","0x06ab9664e5955843715d1a0e1e9f5ea5703b5e89fae00c11e4982ba20d41cc65","0x3fd503d5f9028c97ed7b11472f68f3ab6a9ae21b184717c208a0ecb0a8a8e23d","0x5a228af81a57545833cf0cd7b7772e77b627fced4c1f21571c082c15825a7f87","0xcdf944f8aa759c49bf09e2bf70ceed3a51a60eeba0a9d3f658c4154a28dead91","0x6369e274dec9ed795c4f858329e4d5cb66bc196c5cd681e47702d5cfa680a7b6","0xb7d0800f851e904b423a2ef87692d6b0f3d6f2ee6114337e3505e4789d17ef2d","0x114cc514f7a4630c20dccd4be867827f04a1b2455f38a28d470cda00209711a1","0x66e5ca1912f2a2fdf7e8c5da4fbd5bea4b5e258dd8ebe7fa6dbcfc1af794b830","0x1b807a22af1c2b8373c455482680538abf9c1172798d3bc1ce74fac4e707b9cc","0x2e90e1fa7880a69ac6fd5e72be2becfc5d9db412d75fde7ba621b76f6b8b321f","0x55e1480fb7250f8cf2ac887fa32a204387670a34afba0981ab41da106a84f2c9","0x826cefee8cb4b6abbbbad8b3a18f9a4b23402bd131f0ee7cc7e279a07e94f76a","0xb616ed5121b8c03c331ec663b9c403fbc85825d44bdf4f46b766417df0450431","0xd0e08a76c59b03301d87e534cdbabb457130cd64b1a1f6f4d98c130f8fa2a08d","0xf835e27794ac7a9d703cd343c2397fa0f73ab8ca7764f0e07d7ab531d5dd1921","0xb59e98b49990a78eebcbe85f533f15f1ae8dcb3844cbaf98a114aabefee7364f","0x37f70467dcb1e530537a3f9835e663658ee97d2f3c1b30c00de1c00c33dea370","0x705e2f1c6fe01f582ed7d110a2fb1796e87c8d6f00971e891fb52fca786227cf","0x9a301c048105bda72ec9a3e95b39c61283ec12dcb616398bb12b9915206459e2","0xefd6253591eb5289176cf00ecd161c858cb3eedb95431e01316b1c3ad880b9cf","0xf640960d685086acc059b0590919a6d91d8213a1321bcb038f5f33fb2251930d","0x3821578e42b620beaccd700fff3dcaebcf6e0ab187bd50af71681764a3cbcd86","0x7780edde7790f0a512ec0e9209beb7241b3cb1900221758da138bf3cb97f7f46","0x22a2905c076aa245f1d0488fe439ed7a76b7f08912a7195fa6709e3fba4f4a0b","0x2d914ed01a078d9da8d9e47f7670fe2910e295167a381cd1c919247fde6cb2f0","0x84cd032706049d042f062b6701f4c595c4ef5263373197fe6071d680b710910a","0x1884538b238c7b7b274cc3d7789de9115592369169579ad8ecf539abf25001af","0xb63fabc59426dce89b83671fdc89404af5e92f321512c533c979d78131acadbd","0x813bbd8e299af11f5f794e363edde0a294d00ca92690bc6cf36f568a6c37397b","0x16425a183c07fd032fd54da4269bbabae5bd417e1bdc03488c09ffabfcf8f619","0xf843f6779b10e0a3527b1e073f93d199a0e139bfa3eb211a468611c507bd0983","0x51a52f37c93222d6a811336fcee16f6a155581941349805f33f0756ccc2cd62b","0xcb73dd93bc01427d4a5677b059742aa175fbb3a8f01664410da49b52154807ac","0xcd46793ba2bb7c04fa9380a75118bfd2de6714da866590f77c33e19f893ab7ea","0x1a28fea0a84bc1c8015b85bfe3e06b2f6734ea08f92bd43911d93592ea287146","0x5c79d4475c7709c625b4fc1a0876347c89a9f3027472407f20263d3d6f2cf6c5","0xb7ceff076639f3ce4ec9da08e263a5ed4cd047e7fb805ae926d35ebf079f9636","0x51d781ecffb05e0ddb0cffa03ea7d0cb37ec05c3bbbb426b9db6b2970749bb57","0x103d6a8164369524f7a5cfcf8628e45c1e885985da1269333b665192734d54b7","0xbc694365fce384d0c826183a9025990c2a6561ea85da2f291b215b1f382c84f6","0x91fcbd82f7830863f4cc7c992f7bd76dfb4f5a0667f889c1e486962b75c98c49","0xb407e2e6e493617cb8bb18c109865b26c88add21547ae38d3624fc34fb3e382f","0x2ca07f6f08cc9cda40d67b685749f039ef3cdd4c6d61020889ed937c7018cc16","0x25897784c53887f90065da2fcbfa2931df73bac4cedaed7683984cd1c2424510","0x5ad0ecbaf15a69a94bbe036520b84cec4d4875e2ff271ea4bba27fc883941f9c","0xbd0c85566e3d0343397bced8be0e47ead3be74a5a3d4f8280e712603b0262e10","0x8b3197e9e812850e851856343526e96c4c3d902faebae11261fdb33914f239d3","0xa5a73f97a2dce83a51a421117d2d2390fc9b07faef0739f34ce60d1758662b98","0x9570c4f21cfe9043c3edee312499b24c68007b7048e3b40b477340266273089a","0x1809ca0a814e33fbba0276b3b7352ea817336acec2b2a0c252a57cc61b0f527b","0x6a568b9a685c0c4ea173117682d1d0a989fa88425ebc66353aff96faa4d110f0","0x5f36fc23b6879656ec4a5e3b5475795779478b4e34dbab799adcc0690a28d95d","0x19fed4ab8ef0a994fbb43f185ccd9ad3da5c17116bd69311e473c4ff7d53d00c","0xd810dfdccc3766a9119eef5c1149a9d446d9e82bc648918026f5250684e965bf","0x3c450f222c850f1c5236a7df4a969d05a7fc1e38132cea915004453c4e6be5c9","0xc923ff8b0e0a25e377124a37125e59ad3ad1fdebed661525f834e8425292b23d","0xf1cf567527910e6cfb18747a5742ba7218eb79a10da979a4dbaa1d969e866b42","0xd7a0ac5f8cc8182d7b91cec1390a49bca089c24f0090533b5b71295435585bb2","0x3564987ef4828b5a5757d181e6a3fdf58b541d0d74e449d4ba691319ad0ca578","0x94888fffbbeccac6f486800fa5ceca33f08a3ad8e6822d9506cd6e2457678480","0xb2ebe31e546eaae1be1aaf30fe6928044c2077e0221508b1f5af42c5353d4562","0x8f7a3f5d584b904f5e1a63182055129d9bf0b1d15b8f3ab207d9f0b43db912a3","0x9923540940bdf662281e34f41c6f7e19bb140e0f7d81bba3ec7d4b2cd5e39fd7","0xe3fa484db4417fd822d566cb59ef4676c595537ef8898072432933ce75c3fd81","0x1c69e15e65d2be4902b1264d034f5b6541bfd0fce86509e7c1f63e2e9705dff6","0xef248900f5c837256b8b2d0a174cc84ea57c57c466314e5e2a1f064fc2131d81","0xf6db1f2d3dd9f4c7393c038a26432aeffa99051b2a2a50d0f1e60994b62353aa","0x2fac1c5385835fbd43c264dd7f08f1e9c92a3a95c34b20a22d0bd1bfe53d2dcc","0xb17401d6d6e7621ee897f86ecfd8197066df8dab25fb08503c0276d64aa41c24","0x70e21135bcf57d5fcc861253357c0759428a3f0749b976e75603e3828374f25b","0xe6dabd8d56f72b53d93ca69d0ef1d0dd1e25f788f972384a051be04142cafd39","0x7384fdc90610ce92427b32166a9ca35347f3ba8ffded15f09857a3e3bb48f923","0xa2ecee0d67eae9a7bb5a8a067bbe9d7a2c95f27740fe390d3c4f96905806861a","0xcd96e6660b2d74d42e0e9838ed7d3b2d9169f83b66070e3aa12acc955f6281ec","0x762d8b29e82f4d8dd3a5963b2c8a5f59c91c668a54c41a2c8a95d9cdc8fee3c9","0x63a5f8926e5fb3871d42178fb08bb905fc1957cb94282f4591aa60e3fde82eb2","0x9414bde958ea4eeb5991be9ef52e9b84babfb42d97a6e3f483cfcf3d407f6697","0x4cba9052222d2638b6f7685d6f35105d55d23afbbf78798da99f960a15cc20fb","0xeade952c3eee0de252c04ae1c40f0f13b21a6de0fce99e6ffc670575c3ef4ba9","0x20e1097b386bb98679fd5f8a24787d2f3a89aeaf0124c06894b12eddfec04a9c","0x69cf154a650beb8f0f86d9b3e4b946311f6ec0818d143836f5ff87e791d519bf","0x1fb0d47590ed0929b7f9405912fde58b7fa70c4243f5286bc8cdbb6eb9a38f73","0x1a6375eb194150390fc3b143b7f74006760000c8e37672bcf9c97d1295b01b75","0x3c4e2436886692c1eb0bca44b42bc63bb08794d55ba5df934e80778ff3e3008d","0xd37ae401a92aebcaeee20f398b99357d5507777fc77ddbbb069dab6c1e3729df","0x3872e8b24f02052c4323af65df99d4ad0891c38f7dba70f775ad83ef5dd7a345","0x9c2018ceb2e9cec7795d47cd9a7243e22e1807c0089cdc0f241df5ad378420ef","0xa927061946a52f4518407a5c2d6274f9ca05f7ca71f3aec29662816ef6b47233","0xb7fc8a91259f0e482c20cb5b19d5792dc1eac84939e371a2b31ff80d03aff450","0xad28f8640f0b43fa57bee18c0076118b74f5d5b4e9dddc2fcbf97186f93f1e4a","0xa65cf0db5bcd83f9331646b28c747d4eb2ee4de492dbc3b5d57630c440739a2f",null,"0xc097fa6a91a0d5620993c189b6e05d55044d8df62033539f6b616fe5288e14c9","0xd10d1f66688dbd46c5d132227faf19225077c7bc916777d21030e33e22aa43ed","0xbc50ec1d9b57568211603d4441dcadc9a0fd6cdc327848d8a4394a58712219cd",null,"0x76283ebd3a01eed4c36bacb9c9f91afb38477e21d546b27d725e3e10e4b9d386","0x7502bdcbcff9be6de06534fb407b5d4cee2dcac295605a58fee0996433290e47","0xd1488603f6acd808caefbd311cb087913650adfe6deff304315860d93a3d3517","0xa8f758c4758810a70b004aa3a6003ff46aa270c91f2b43a708ca07c05cb7ffcd","0xc392796e9e943e5f5c15c040e657b98372f7143236a28ab61360da91cc05562a","0x53268807a54fa5e4db39d6dad59d7fe7e79267ff90a250ca5eb7b26082b3cb66","0x5fd069dc00bf0f5275ed6248df25cf11233e9f26727c4da76a8a1401f65d1164","0x57ac7ea962952d08096248726ddcfcabeb29c1dec4d736e111f1972a2a6c59d2","0xd359523536e633367f51f7aa50c1aed4dbfa73c8e2ba240442bc159c0ac2b6f3","0xbdb5982a7bb0c929272326fc4737558aab09ab7a42d5387f6dc79cbddd128988","0x851ba2b08344bf22da27b640467eff3cf15dbe98c5f416a3badb010ab74e04eb","0x5fadddb238d631e56f31c9ed8e178a24feb869540e678654df27b6dced48980e","0x5211064e73946b322ff7624a1f1f4995291ad0836573957dd725e49f2be8ba26","0xcc2bdff69af03bd7544a7f47684b501f2a1557f3c7a9c562dc77c83d4eebe915","0xe0849be981a66ae2fd89d4a1c300cd32e88cf84953b2950df3a34d2341811576","0xf9ba063bad19d9b2f58c16267c15fc2b3e6faca1f19676611ab3128147af15aa","0x584bf9ecfc3c5b087340739eb7441c8b229872a5e88014f46940f8af36690dd3","0x2cfd3ccabf4252829c008c0ead4b7e374a85a1627401fec4537e72f06bcda849","0xf79a3e319e26e58f663ad3d08e82e93e3350f56757883c4c010fa63e054e8918","0x4c2f3397a13eb9a9340f3adc034fec0813447c75a9c179d483ae1f60b5b7b700","0x89e14e70c712a4f924b75ce2bd01df9e6767dfc4a9c1363472e0ed87ffea5abb","0xb17ecc7b7959ae0470fa0a9cf5a913740e59ec0a9c3ae1225ad831c736619441","0x3404633110cc56939ce338206ca3b79898e26892b345c45e1a37300f40278fda","0xb88dfb268c929e063751c1f3dfbcd0850fbbb7312ba31f3d058952645b9ecec6","0xd99ac6c31b7b014bfca7181bd4b77e5e8a87c6110bb65c14187e08b2aa4f66c4","0xea9d7b2db5cc76fe5379c34606ba43ce2c68c69a15702cea1369827898d9405b","0xfbd0fe864e8f17acea40552b5596996e45ab75dade63dd37cde6987769a2871b","0xcaefa3185aa23e6abab29a88d0d226b423c2360e06bb19464e9a73f64f8adcae","0xab3fc2ac340851b049ee7465abca094a3968f2ae87c82a3105e7142ece8f5e06","0xa88de29ede66354d91b83d863fe97710b3ca60ee2dd2e8441193b95d11a8cecf","0x4d0ba188f6924bd5f1136b74b07a5bd15b8b0a0ea2ee79d3c782fe60d177c7ef","0x1d0fce694ae7037b121ca5057f5e9b04a2761b45227051929a7fe17196dce895","0xb5d2fb40ff41a82b276926ca7570553dee7517d6c3f8ded6bff38de9e1332cb7","0xddc9f4b402c8241d70699c3c5fa0e6c19d40536b3b46964dad085d7f07c4bde0","0x9c179f3b2d30e024d4d230c8f71e46084f550010b389237fe0614e3d029fa4af","0xe316960291a055ce1abb7eae785cd8ee12ccf2379b58177867cc18ecdeacd512","0xc1f226a5759a8bf5e19ceba5b2e832e0ca5177e7ee556486c12d4e30d5942a17","0xc35d25db32ba77058d61d399e9079df73c4d952f5256c95c9bf729d5688a53b3","0x72e28ea3a159d47e56fcdc5bcead888e8e92e5e62324afbfb2580773513484e0","0x4732468ea8330387d2eff55d498ae90a8f0a327df87777b358ecb38a4d8ade08","0x187c8607c5dac08a52412b5dabd81a6a487cdc99786722cfb83a8aeaf4448885","0xd7871591d1e02c147d30bd0b59aaef94337d82702835b4ea1c5eb9da93cfbd65","0x086490d73bd512bf6bee791e31f1bb80af2f3067c6b6d8b0d5f96a72f172b15d","0xb1bb91ff967beda555ec1f305054aa943700ab9fa390105a04ad2b085c96827a","0xed98b30ffc274cea030506cbca76ddd93748f06a5ef7d2230fab5273f824cb68","0x12d387b3f174d03055089cc128f0c768038d33271e5e5d0fb6698be80fc6b25e","0x6197e51bc3ec0c2a406094c028c6def9340270128d6b9bfe070f75af9912d9f3","0x074a9d37c93de42e903ba545811a783b222036cc2b8338453fb472ba933001b6","0x8a72d0070f590863f60196e1b67bde7099b797af97ebcbdf03e3dd6cac7b1c11","0xcedaceb4ed807e0dfd371f2d78b30f517e8371c2551a211aa64a93253a9946f9","0xe20e4eb62a71a248853797db111d7e6f839382ca4391984772827fa0223ac470","0xfe029cb6f23042379f99131384ce10f59a2910107a02afcc08e5637872943645","0x29284b4ee85edc711121dbafbe96b5b172a54b5947ea2733d4bbaa34fe9e1bb3","0x8123bfd3e2e1e77d518f8a529a757d38d6c989f22eb65fd8e9c91fffcfca4f34","0x656af3e6715648a5df2f1a458cd0a66709504c45c0925820341d06492f8b7fef","0xf2148ba10547cb54053ca44d29e57d69a9b73cb7e714c648132104cad5859feb","0x6ad2b0edea40f62fcfafd34d55b4e1588b45cbb4d1731321007cbc50ad181ffc","0x2b8866d64ed94a8a7f84e92ae7291ca5a43cd2a418e3cf693ee05a6bb1a7b9e6","0xa5390b17dbd09056c8034f4adca9fb1bec4ba179acf304a4156a130213b23d03","0x36bc8ca98e0da70ec698f4589be015aa5ed5b620ccdafcd4123675388651b1d0","0x65e2b702cb54340c5d1dccdc9c0afaeb9294c9c9021bd0a449fcfd773c5e7a88","0x4ddb0d1fa29782f5ebca621e81572d750442596dcb9587c298cabbf40234a255","0x8085f968a83a1bebded14e91cdc738e3195bd42ee21b6f15904105319395470b","0x16d385f4fd6aed085e81c1d4f6c2de2484da33f20a9e504a4e4c4af3166cf746","0x511caadf9888921cbfd9ad3087bc04259554afc0850ef132f2ea0a91de6d9bc0","0x42133c7ef34b15a42b8dccc2a9a0fc0c48cd858abcdff756357b33e1b5c43c87","0x37ad26adb004199f84aa36e96c0aca5a47d896becded789f589fa705e1fabaae","0x7ee8c8b0366e6be090d821497d40829a9cd4db4cdeebedad3f101f1ea76a0eca","0x85d8a65dad40a19fe806106478ad42a746601ce26f2484b796640660e188018d","0x2bdbc2e1fc305e6924207aed02d9aeeab783685d435f5b1cc77b4bc8833ea4fe","0x8c3cfdbe9d99bc57f436d67279288d69b996cf718f7511d76398a94b4ea48b79","0xfb33afd3c64b72b684349acc0468db7fdcf12308237e5f965d17bee946afc74a","0xf382e159ccb877ac8392f3493cd0a4c9dc6c37ecb06617d168988d691ec9e877","0xfe745b648ee851fdafc49679227d1d70e9329fcf57bcbf7ec7b4e25745d7ed07","0x82fb83495f60c2c1f5f28133b75d00ea3c186921ba756240b26941fce4a631e3","0x5d247bc24e2b7420dfc675130e7ee4690e4b28b235e56d6b1d938d6e69610e8a","0xfc9b7be7a62eb90f1da4b8e048785abcfec5e48cfd97e8d63d3c1452f95330be","0x7c8de2aea6c9f2741d89183152c3ad4720ec8c503ddf0149f2fca5d816a4cc02","0x81501c272b8a17a42fabc1e75b28c2e994d01234bcb97736e415ef2bc0079386","0x614611369254f6aba0781e6e47455daf3aa328d3fd71f7cc069f58a20ae2e99f","0x8d8a2334bc29d3339ce579c2cc46377c768241013792832dadc7e2241d7ea00c","0xdf68a42aa9dcc32135b976f05f2ea2bc5f4c75219fb4a54c7ddfdb75606d5b20","0xe9ad19bc50c19ae3c3917ab034571dd459f790a601025b9c3b099ae20ef4fdb3","0x3b6365ee1489737fff15fa15cac9b19f9aeb95262dde34f140d1ffaa4158ff23","0x168e4c1f773d41f3016459fcf366e44a7bfa367addca8e5997b1afc94717a945","0xc99b6d7147504739bb352b3d5e2e1fb0f20d975edcbbe29d8e8570453641e86c","0xf12c0d48c28c0447557ea16e1c2c586dcb38482377dca9c138d37e5ab5649314","0x2c56fbde68b6fcf73317d9ed14ba77ebb7b061125ec049e20f06d55d35cf2a25","0xcd4113f753261e86c7007711c4febff9c23740778c4c05d7dfe5bb47eae23164","0x73163073ad4a88557f66342533451221379e00c990d9074e4ea580d48228a74e","0x6822715eb037d4528b58e48ca1d00b903d46ac6c860ab201ee2c8b9572019971","0x27adbe8c0ed7f5d4d8ce0a6e89668676d4a5de3a000ec6e019bcd238947e93f6","0x9796c94d4e00eb6766c8b4da363ca88365528c1ea43c2302b3fa067d86c94b7d","0x0acf5c8c8979e71570feb834276303a551b5e81c92ac2b6de333abdff6000665","0x88893535f26087277149cb72ef8790fd8afa30a7d87add6c03383857cfce6324","0x7ff7dc7fc34d0e0c9362b1aebf82d7bf0348acba30205854b04d1f518e635eec","0x5fab7f9ef619f82270b9a1b196f2fac43a65b78b2012a43c22e042d0a363ca46","0xc9c6d45ee617c7c088e7e25d27b9bdddadf2d6c306f6b29d709dae2853895dfa","0x5d2022d9fe04b166b18c5b0856d12ba8a957d035e5c642857e0b853c3c9dee7c","0xe0b21ae2856d4ea56d9e3109ff9e5cff5a8dc3717c5c884d0efc0622de3f3c1f","0xc452438975d8693f324c8aad10ec5cefd49f5cb03d88a3c8d50766438035d4a2","0xb2a6aa13a54f33e0e78bf65b04e2ed75881255e724843cd20f82e95a0afc9d68","0x3201c28e9585c360fea5122424d0460e71dfe70ecbddde2b11147f620c84866e","0xefc2542d8fd3a5a008f9d796b04ad82c792beb7e34ece797c6a4f1f20139a1dc","0x4a0a61c7aa793d3155c16e57a62873442a85738fd994e2c0cf891b16c25f5c0e","0x49e7789c2224d38375164c003c374894b01046db14b0570b15ba410aec372435","0xf57a95a2afa751cf26c498b57353189c3bc63be77d96883b76b1a27434c404d3","0xc3ba0e3cfc4946e06995f0f826d8f63fc931502173f534e637854204d296b99a","0xaeffa3f864cd6d11979e1150f55be23071b70576f5f51e0e3fad8fcf57f368ea","0xed379c6e5310d543dacae886f36a94f0588a2b0ba7428e7c8e3b8deb0e95f88d","0xe55f43a4d21e6235cffc6e6468874272080fa2811b46f9a4221d122f7702232a","0x49b6ffe102cc6e5bccdced2bc692f0183eedc55a6ea32677706243a72f99a986","0x104f8d1c863bf9fed21854f671c34f751bcfc9cf283bdc11641ac49838e88627","0x94cd8e0a40acf64051448bd67d6d023ac05e824100c5dde0ee467c5b71ff344e","0x65fba77a902fe54d21728c45cf0fee963483e8a424c47637a689ee8f0da50505","0xc6adde3f304fe916ae33a80d81d17ae3ef62f34c592933b4830a4dfcc75aa98b","0x4799139a0b66b9ec93dbbaabc0dbd45e3135ba5849aae09a05a48e7e7d0a6e6b","0xb8563d3b7d3268770d0603c9b46bdfd5a9fef0b720b8d5b5642efc55ec6748b6","0x3e86ee548b9aa989552e64bd27ac50b1ba2e62de75f989b63222809a032b3ea0","0xed64c7c64a7cbd53a32369e64be81a3e9c231a95ca53a9ef7b7e3e9eb43c4457","0xa506791501a06c0359cdeba7b4b26c2981fd4dbcf20e74909e80e481ccb46e3b","0xba24c0b7b604d55ec4f4175c727740f12fd8d07bc5b555179c1022ff685fe4b2","0x4a7053d4fd0ce2ef3d58a4336f66f5081aa3345c0ebfc3846ed0223b5afbdc80","0x6aa8d817c45a15ee1694a9c82a29c0e94d5dec88eaa1a78966098648ea5db050","0x701b71262edf99df83e99f97d2d5d17560cf38ed6fcbecf609c15f43fb9dcac1","0x1f829cc31cd51b169f80a502cf80bd72943cd076f28a80169d77f5c772daf781","0xa59fd161121547451a371c06a7b2892eda4763cb125699e2be03d8284fd5d311","0x4276d5049a9e724a5a9d7a774993bf6bcd808809717ff276a8414e405ef9b7d5","0xdfc1357fcd46561988a90dee494c1bc3dc1dbc826561246a849a31d2ecf5dcab","0xb6f1eea4b929fabf9af34980ef3cf5e6f56d5f01b910be043b79b6b4d8b10dcc","0x5df854edd49ab66596159dfb216087b76c957f9e846018b26699009c92637e12","0x4f9bb7a7f2ecc62aa86c36849b7698b63d514acbda3b6eff8d17d060203abe2b","0x5032c8e7ecdbeeb84832144eb1c57dcfcff3efb7585404960d4c9d54061d437f","0x0c479fa5d6b172b5de061439b5f2316b02596aea7499666b9bb7f2f1678857de","0x6c7ed8d852b3f3ce172b4150fa3ef56341c9cc004f10a75f3de3e46b699c6241","0xc9794547c200f29d39009009fd255e5e50c3781dc634e30dbcdfaa34e0e5dd97","0x3010837b4b0824c40b013d4244da914d7e6079e7c8e80c02dcadd9c38088f20d","0x6541483dbb89a45d37e20fddf23f1cae9042c7ea72b556f7bce695f75c4d58ee","0x7db50e81ebb10ea4f2298000979e2931121dc3a34d2210e4005cef9cefcf99a9","0xa17aad4b5aba365e422f0805b6c3ae86552546e372f7883d15a60a22dea561b0","0xbc006b49a39c74bd563cd8047ac9ece1616304c0e778f67ecdc561e2463e463a","0xf2ef5050498b621dd8eed09fa9dfa3409e547e9bfbcf3da9f61ac547b86589e2","0xf423eae08a48ac44fc407ca477c2f0d683b8295917c8ee3b4f6a865879c34ab3","0x9381a5ead4674595521f74670057448f8f71f69bc679edbaf8c8b84723e2e2c4","0x58f272fa4f108bb23436bb96d6c57f7b651aa55bc8a5e497c0021b35d652e039","0x883f7abd77c510fc53b70df540355d9d3b9fb8d42ef83ca0ed598e3e92587b5c","0xe2c717c32c53eed1157f98d7eb78496d504f3694429e47972a609922768dda3c","0xb6fcbf374d3e1e4716e4014f677e6d9d2887cc6bbc314c513759d5f612e5a062","0xcb418a8cbbb5850a82b77a41ed3fbaec0b7958dc51ffdced4fc0b2a3f9d36903","0xaf11bf453830ec2f4d4b9ce95c8de1dbec56651e4d8bd06b6bdff8bf7afcad7f","0x9a960a951d7de606379d7b3121c568e0e25176af9901156870b432d5786d6ad7","0x29f4fe443cbc349912bbf4fb71b5eee276210385ec524fa5cb0c39e1cd7f32c6","0x5aecb8e5cad125c42fd9869af9ac45ee87a687590bd242dafe3de4ca55aae7d8","0xe43c59bdc68c30c0e5b220980165714a39f4afd992af4da13ad1e788d0451619","0xa70ada9c876dbc18a3e6cc424a4a992b2ebba8a89f7dc07515e495dd443a7abe","0xf4b07e8019e0768af9c7a37bbba65283f993751d34aa46c767188e948a8eedc9","0xc9ba7eee45f280c2f98ed79ec01a60228e44628f7300304e55855c14a2741a83","0xbf037843f7873592ba4a03cc3f5ff6894712b97e146bba9c7f53e7d1f55de29e","0xcb331e5cb641c17c6f7a4be8de84cbcefdb2527ef2b8c0bbe31b5f2893222968","0xa4f33d33715e84a8399fe1aed8b5fdf93a4401ca401ced6642e898f6933bf4ac","0x884076f8feb95dcace1c6a547740029ba922d56539e7ebe948c202a3b055eca8","0x245f84c543cc3bae2ccd2d47ead550eff4ee0860eaf929727e54301fac068e82","0xe40e4eb13b362bdbb2fdd63e04552e441cf1fd9126516b3c80b79acd3499b1f7","0x921585e4021b9d2bb2a78f6c80fc11224cf8c81abc759c5f5924211cfc554122","0x701680948b5c7b77e1a289aa2bb3d8ac989cb903b583e9b2b06acf91a337f157","0x0509dcac589d122dda61f167ff152041701165f15603d5fb398cb2b8fb119b10","0xb1145e0c93271937ff81df90e72df0d29c705028fd1d0de626d3a62893c38481","0xe4346545f6034fad30c080df75665827310323a01202f6374bd55b5268da2460",null,"0x548b775e6c38af91c1a159fd8422bd73bafde16f544fc2a615fec3930c961407","0x70680cab123f9dd191300b3d1596615219dcf0a5045f994617e0156f9c89fd6a","0x1de4b14b8dd3e39c3a7298af0a5b2db0086198e4d22a824cad5445b3d4870490","0x07e1eb8674c463a4245ed4237d7ac48c48bd34caefedf5382dac77a24f83e474","0x6d45e885bc5f6848ab36725753da1f40e7d2eb44737d4100ebbe3b7f4d2f31c2","0xccbb7d8e506810d907e3be4f8ad1c59809c37dd796bb0db39c1cf272e48e0971","0xc9d58fe9090a82514b9ef8d27a1d68ba9fc296fe0c8c6802fa3b47398722eeab","0xa4c3cb5e1b285144117240a3c628338aeddb82adee71939cd934059037304146","0xaf1826409d146e0c2ff7f12764e53cbd46e052de5c275c1552ea52cbae8a9e04","0x998067780b5381dac504aceaf219fc97cfee2f8f852d0ce722a01650557ac756","0x0e87ae6d9eb79d99dd43b88a37bcf392b5bdccda685934da851a3eaad4f8599b",null,"0xeaff18747ed22db39aff89f407f03bb8edf287c1c5b3810bb3dd2363632dc45f","0xbdfdd9d635b7f753f1aa5c2ab11a17f4d9577434d7977c031af32f562bf2cb6d","0xe6bc8e3a15484699342d6fdefe09c135bfacb6712cff48dd3fcd39fa03923351","0x607462288eba8c8980c666848237a3a2ce06b5f1e54294454a3354e17255cf0f","0x1f7df0398965971a179c12eeb69e813caf67e6cb15b4c7d37e5328fcd61d3794","0x0e19536c06aeb5810ca6eb17fdd1dd964053ae3c8560a6df3bad51c5492ba7da","0x617ed6aaecc83cf463e5bd55f81fdfd24db5e96ceff448981edeb4b1cb978998","0xd2115b4eabfefee36b26e0a792509ba3ab963b6364131f036e5cfdb25e245bc6","0x07631ab418c6f3b100f75179fd6233c9d18d2f256b390f0150c5c9f92b924dca","0x9cd2127c8a4f214d10f7192bc9294730b54055ce9f1c84fcf14960fef369f9f7",null,"0xda78fa37f2aaf34f2ca15604f0531c64157dc4ca5e7e59788a530f0bb97e2e53","0x5d3adadb457af59c2f8ac7694e47c61a41e2e70eded89cd196cffce9422e9566","0xb08cc0a4f1457d08fc2f3a552d89bce8cc122e5332490d25b2c9865f1a1e83f6","0x1ca49388ff2a626f4d0e964b0e557d720c313d2f76ebbde52e07671e8ba1b72d","0xae4cb1f04dde625fa206b06d1137d36cfcbdd86a21dc55bdbf8de5352621beef","0xb8d8a04220ae928c5db09fd6c308b1bd8d2078ccbd41f9471598703dd597ce6a","0x3f4b520f77e30a35f0ee1d762e1a2a5dcc79a3ac281ec7896bb3ec608fcc8e7e","0xb32f981c4bb0e3dfc110a9022b9f9ddf3002c2ce884c4dc66015846cdfcd0ecf","0xed036ca3d47d7a2428dd10be615af637f75dc19fed464d241dcf48266e2f7bac","0x3928e059a66902df3f11bb181645e97ff4d203137bb48baf794abb2e30df893a","0x4f6bd29a11ecdcd294e3bb79b9b91fdafc575a55fea941e45e36464f3ea67c2f","0x084deecddad3b6b099444dfd101158408d8a22db41ca1a6e954c0b25248391b6","0xb599b39ee62f4e606d8a7a467195a864707e007817ca5bd7d700480456e7f46d","0x2b2dc3aee6d6acf4ce76f13163e7252971fa53ff3a196aee511414ed1315a8bf","0x49ab1b1ed8f347ed5e13e534cac748e3b4c629650a7f1f41a734a55ff9aae10e","0x31561c725b2ccc03e303e97edbfeba6d619680830f5e772242ddaefebf9fd70b","0xddbe7faca53dbd7d3f6e4b160fa8de357349a9df89a88917f69da60434941e38","0xd48e90c006fda105e5b538e4020a160af10d70af093001091bda8fcaad0cabb5","0xd85a85b268e520d597c9229e46fadfec7b52c07b895db152c4fc9d0e6da6219e","0x53a315a67c73e9f770aa350fa3c10d44bca10cb51da9d337336a61948890b5fd","0x41ee0d8fa2601544407136beba45f02351aa957ea995326196d6f301b57a85ad","0x044090e2f958b1f9782769112c541768c42c70bc46dd8a60c5ded096ba7fc013","0x503a46a91ae68adda3f0eec5b337ac457406b82e2628085b656fc01034c4bc11","0x52fa9d65ec740eea67d261d36ee96a7f41a87432ecf95f6d94c361bbabf78009","0x51c43395b7a8adf452ead14b38c9a93547ada8bb9dc71cede93b136b83e52673","0xdd13b9c1f57cd91d74c2cd572dee182078bef1929b934fa041ced8a35fd13a79","0x0fb719d13a82a1dd87651a92da6d10d5d94d03989a7b6fe4415453ad8b9b7100","0xff88caabcb12e4fc6b0e7537f818a9bee2ac73a5499a0da654b559a23f25e395","0x9891b451132509e0875cb034d3add83db6d49bcbe77d458fc41146a6f26f2d43","0x2f03127bc3b7636993e7fdaab3854e367a8b2a88a8bb4039c0a9c2f0dc948267","0xb22f72923a3a1c1af3c1f99e88c2886ab1f8ae17df2aed983802b0f961436d13","0x795a15385baad0bce422bf8bf2c750e2d511e3df7625daad75418cdb8254183a","0x239953fc2764c57a6c1ee6e6362d32effbd69cdafbd0ebadf0db6a516eeb53d0","0xd2159280b2cf6603a15872998c7699a336398c41e14fe1e8c7e7692f5a476b51","0x3fbca1b1bb7a0983851ac8ddd69edb42a4902838bfe1c688b60b1ef06a052292","0xad8874199fa56214f36c1f4f52fbfe5bef0a5052a3e9fe6d75488842e80cc2e3","0x041516548e778df61dbb318b50f7ebc64a336e7a980ad105a8c74e84229f85d0","0x756febffab6116ff4f0c9ce6d9aaf35aaf8dd08d540dfc962f2fc256ab2e43aa","0xd2fd510cf43598b8af50eae65f48373e45e685c245727a50f6a72b1d9f9b1a49","0x210406fad09adb81f63ed54a08e3d12d5d56741d6fabda89b7a603ad322e4db8","0x579cea7259be20bd39a058de90990265cb82ff54591c9acd5d022a308f8a16a7","0x8fde97978def9ec804bc4304d26e73d7e536f2adc7adc984570ae8403bcf2935",null,"0xa26bef1f69fc9cd1d6e9a525d65f8515c1df28cceb7afac3770198e1fce06242","0xf675fea4bb3d72dfa0b1910e4991c45b63ca20b05076cc1174ba879dd832a6a0","0xae8d675637b1309615ff1b06d19d5510355232d4bb9b22cdd78f16cafd29efd0","0x1473ee011bd8bdd9a545026dfbd133dcd3a99eb717efe8344b73bf1d54884b35","0x0d505c32c8f4b39cdb05ecef99c3c970717d35e681a774887bb370f832d89640","0x95d5b8b02227684040011fcb8eed8750bffb5b1aaeea9893bfeb16440a79b8ec","0xe5e9ba71a32ccac3b737e716ace0d400a400eb8957f0bc20e17ed1d19f0172fd","0xdb1e3469b3c40f10ba181bdbd803537362bf3cab1598a69065ab805b5230eeff","0xb310db964d55b411cc157b41b7efa42d46d312723ecbafaa7bcb37fdd7f83857","0x2b47ec01f4a58e887d7c66fdcf671e1b90f03a958dcc481ac7fa0966264df7ed","0x8e0bf24d65c9d978bdd7ad3c57430d1d22dfb5dae85b404d8d282ab156e930e6","0xe498cc6f2a2eb9a52624d34fc6b4f95029a21ef99b0b24aed4c48b1d1c0d72be","0x862d96467bb33c26ea5abf376713ca070325b663f307d7a2f679bd37d32f70af","0x59477032501639d8e045e71b3890487412ac2e50c54d39fb39efca04e58d4024","0xcef6c2cfc5cef36987c51a60f0957d6c8f729dc3b30dcaf3c4a27b4454b97427","0xe17402b1a4112ebeac8fa8083636373af6bda330d74475fc6a024f023d1156c3","0xe60f31b9f393b2da50032565abc4eaf21296fe9b8bbc05e20058dd0dc8443738","0x7dda2897eb785e5f81d699fe52d807b7220f905bba9c085d260cad450dfaf2c0","0x6c856b48be9ce5816f95fb1f8a44493a633a0e4afca70db7c3d144992cf7791f","0xb43136740c40e0e0b8b8d2ed825dd3601c9894272ddd88d0348c500bcaf21cba","0xc42b98888856d9441ae469fbdf738938d53e1b0d6adc6f5b5fbba22aac181d71","0xfa807585e8a3e9db3e8db2bb195be3fe8264867736139fce9df22bf614306b39","0xa3f37bde0c70012c042ac479d308d693091d41a32eca668e56e04e828560338c","0xe8066348363715eec128ec591ec0f267371ba5502b057ba1054a1fd908cef9ae","0xd6a28a527c0ff41d63313d05de7739bf34d11c0ef34c58753558f5998fc4b514","0x295fb7431a009e10f790292ba51e48add75ce8cd019e6ef8a3fd37ac5f7d6a93","0x7ad6fa318b21ceacbd64ed86b794bd9723b539c9cff5745420be4420b4abc39a","0x6cbdec15fd5c946ed5e902b0ea33746e3020179cad308cf1a17f5555b1979617","0xe5fce39412179bb6af19bf77acc4ff866f5b9f8c485f0d219a0e2e355cafc38b","0x9fd076e140dd3faa1cf17798fb597a35e014b2b48aeefc60eb3407332cf2102f","0xfec9afc530f39cdacc7a82915e66df17740e6db068000ce50cdcaedb95dcd1d9","0x2ec904c3a92982efa64176961491143a1620293759dc2edb6bdece5b84db6c64","0xbac5115c9c2cab8f681e5cf986c05fd5c86d4751a03d87b8d3acdc476b5e3004","0x808ee214f59d808e2098307ad5ba07742b94c6dcfff87fb1809c8cb8bfdcc805","0x8d4d9c81f5b7e27ff23a67b39165b88df09e84b4f63dde1d51cb751861177528","0xd4d660497be9afafe0be31474565a971aeb767a8a57d1ee67d8ed5e20533c548","0x6748b9631b5e822779b9c189658d070768c795d1ae07535c2eb8b30ff737b65e","0x5bba8eb1c9252605026154bf2c6a364cce05f800b2391062d1e0886c95b61063","0xb600a1f4ab31ee6acdc1246b806fb74f0aa2f7a30a1aca3690c62f478ec9904d","0x550228a8714a8e4fa13c2ffec6bdc262c1de18a3fd29e99abf1673d0146d504f","0x36342f9f9297fa149d8a8ef35aa81954e7829b64c8269e2a5f7a57773016b17a","0x1324b642ef0f0f85142b4a919e4936ca7aa8f9c9bae3cf810545bdc0aaf3efb3","0x0f7723176a1506970693f2946bca0a0cbc91c55a3bee8b1d367bff08fdc88cab","0x4d13c5e208a40e6d368b554ea862c9d4f0e0f420f003a315908873648a1968cf","0xa25b7ac6281d73eb8fc3d4a13eb15eec3c9c82ca081abf767acfebdf13d79754","0xed1c4c69cfa483bdc7cdc33f38ee22cbcdda47e3a5c7485ac2f0b89653690553","0x6be194dc3d5aa19a6355e71a2bf96ffde72336f6f0c03c9238981632320dc597","0x87416c1b224f3207da9ae2091dda7e8bbeba5d912fe2f8dea8b3405b666389f1","0x4f705c5cc70016f24b4398e5c5d55dc1baeece8b2751c055ddb65649f9b3b9f0","0x08133189440930e3638c279726b7c8949b7720ac1f614522a159c5e5eaa0de25","0x7ad6cf83c45abdfa4d031fa211dca189c3ea94f7c40ce0f7d1c8055196649662","0x3fa8a0eccd57ad5c0867f45705f1f0f6245e5bad9f8a6d3015ab2540905602cb","0xa30518daa29193f2be9ff543cc6ec97010facdec0380c3714cc05ce335c966a3","0x3643c11b13b4a4179efedd0443055f4cc1e52a14c6af6bcdf1fecfa38caae223","0x19cbe8c826c3d362901e79f6b7c6f5373bb88dd614c031c065d4ff2c7072ac3b","0x0797e5d1d78be0bf903b8c54208d3178c7ca4af1429213b89c61ae47aa1b3194","0x6b1972be0ea324e583dc1df8297aff8ca71a30a0f9981a4f429cc89e23095364","0x59bccc690eaae8ef08a3ec3e64cc7b2561539c210dba689de78897471a72cc60","0x48e4307a2c76d9b13d839d75edc7119ef0cef0db1fde439e9f36415a78b7ce3f","0x85946bca5996707ba5f1d5b2b3b7f7d50cdf442adc4b2f7314370761cbb5afb3","0x3221d3e116f6a2e92b64ea7aed7cc0236939c877773b946712083d8f545d51a3","0xb34715fb15ac8ea2e408ada7c7c6d915e5f27b33de8450400a1903f02c88dbd6","0x1e6623d45cfa7b8dd67ecc0e91925549664b6ba9178c9630aa327c31a853374f","0xce3315d2d974fb565ea01db5f1106dc0a1f7cb15e9e7c2f8ffea937a15c807cf","0x9818f8c75232572837c44e8277335d35a337a8f281c574b942e906513a2ebb89","0x0fcb554ae14cc7502b99c725b40b0b18530bfb7efc186b17e2e14966cfd4978b","0x0a533770e4ee642b6fae235fc862e6e29fe99b3345653d9be8422c569c3c9d17","0xd33e2837434de5404dfa95db47f276591075bf3642b657518cdf3b0d49b00bdc","0xaa06566acbc1c42a307644291cbeb737371f9119c46b3e0e26bd75fe32cbd88c","0xe08e20de88c5cc8a92a5156a03c07815972b105e61f61daab5374a2c98aba722","0xd44f6b769afd912155fe3df405e11b0f11dbb918fb542ab71330694970be0ad4","0x35d85de5865099329af244a3acf15ba3b1b1559d810f5d0e3878693a1a492ea9","0xdb8189466b8af7ff91c7b28832188d87b9651fe3425d820e5ae2e165309662cb","0x663f3025a306f2e246f290e1d427394d85520d75bf0e6f29ed70b0a50be98b2c","0xe09396f9c46cc40b5977b55d779a8d28c7fcff9e56ba9c31393b684f264d5d95","0x12fc4960e057524ad2706a7fece48abec524a6451240b478ea6d1cc10eb49ce1","0x6edab61a8cd527e7196d5528710e17caef59a6ec406cc528f0c2f97ce207388c","0x636df4e1b7d8af6c38e66a20082915cf0ae3e723cd7aae942c45cc04a4c63828","0x0296eb00b74ddd0ebfafe5027c8c7f1b38360f4ae20a763741fe1af74638eb7f","0xc4a061d8c9d3262baf6d2a7ae8d8fa15236bd7afc7feef3afeccf27d50f90688","0x2f7ac28976eb6420a95ec39117b0371bc50b6c6fbb8b1761ad00c06cb1ec9ee3","0xa1e913de4e349638e220811a173c5b45c83661dbdc6624476fc2eb611afdf659","0xaf667d959ee7d4523cb7cf441bff99c3171b71df9b979f78323eefa6a235ffe8","0x235baabfea001604a0b1a26c26dfffdd1eaa830343d5366f7589c855f074e93e","0xea82ddb47de68eb56d3d8e805f3db0db8713231fe435d491a06f15297e36cf5a","0xf40eff14de79535461df56b0f9dfb320d7929778194614494cc55d7cebff7f29","0xd7eb66dd495cfc7024a3899750683fe6321d56179a26d91fd54b27b2b446a1bf","0xb4f8a26a65dc21a6d88ab1d2d2783dd716506dc6ce0de83f7aac18ce92b4ae01","0xaed9c8812e5366d2c477d11e3f63fd548a8174cb73e127c0c9a3341ea08eeced","0x4baab3638bdfc6928413a658ed0557c498519592111f02bb96b51097e7cd0869","0x519fd2843770ce9c114f38cbaad079045851385270c4d9039cdd67027482c71c","0xa7e08905c7d4c5941ab0efd21323dcd829ba61c8f74917574104c9eb0513dbad","0x55be25d087dbbd316814dea3766ef7f1b44e746f5e5454568db626e52fb472b2","0xa1251a51bac6bbbdbdb5a269d35a6226efa0186fbd37b3f12b37c0dc47becedb","0x29ce6d1a66c90b21bb07d5ec4edf75708f6b935014c22b6b388eb796f195390a","0xd2edc03b6d08a77b6c874be2fe68b101890a34fcbeb506266d4a453e77ded5f1","0x78cc38d1be6320f7529c7d870e10c16c314518ea1229f8470b340a8977022d2d","0x44583681231d17c7ad9a6fd4bee9e3680c89d6137088d87b29d37d67c6ce2624","0x2bbe761bc7e808e103ee3daf88d0172c2927cd1467bdebbcf52731873ef851c4","0x9e4f26b12fab56ca3e4fe74723db3e1bae21b86bf5cd7253cb1877170ea3b66b","0x2f010ce3d59e27ed9a5f40727ff433f20324317dc110e06c2ab2bc02c55e1a22","0xf5cad3fb08ae05769b8e3c251a3edf1079ea65000a665e74e6244ea4dfcb5093","0xbeb3b943c69fbd826394636c7a37334e6b81e0693b5c6a0db893aea87fca2cb6","0xf3c05d6cfcdcb27fc54e8eb8edf72999f6437316e88504a03fb3a256013be0d8","0x3f9c3d50fef538e5c0c473faf2eb17ddefd7782eb3d74db0adc8f0c438ccc0a6","0x595275a03e93d8b1be5b3a38b9881274e598dca5760100c7d9ad9e7a18d20f25","0xcbb8d82697806899c5edb1c8eaa9c3be364c7a91800857a811775a6abffb2092","0x181ee53074daab12b2594678c1495b426ed72dd78c7735fd97182782ce1a57ce","0x252bda51409d2473d37bd5c454f0cbd1fa17b187c804dac365dabf8fa06d10eb","0x974cff69672a484249e5916208d66e72367b9393b66a8afe3e2fbb2b5773bc17","0xd0fd60b496479c0b28d1433b9fca1de0a7fa7ca65984b96798021a6f844716de","0xc599d01652dff363502ccfbab9066d51dcec3b3fc5402aab01cc27f8d0ce3931","0xb4ed2c71322ce6b20fb0b11b670ddbf3ba8ba9994915f498b4efb5425a159b3f","0x7448e1d60a622f411c7f70087bf272985ec32a4ced960f7dbf95cc682e9dc3f2","0xa6c122788995e4a2e03c97aab3883a820232b0e80ea716998f3973264106e476","0x499c77600b77684709255b46179557da4c59dd4611ec00599ac21f05031f7607","0x56545d6b3aa1ad95cedaab3efc0dde82b3e87c4db5a351fa7fe6970f8ed64d50","0x0ad151662eb47bec396942c5e1da532d720a2e078b273a8a88b9d87841e0d2b9","0x1f2d3288bdf40131c58c6aa657fced18cd5449657a79ac546882390d411c25e8","0x1f8c715a8566c80ef21d4bafc4416c320b62ed88b513663af1d7eb25585a30c6","0x04b8f1a823b31c6cbec1b92c036061a09ae23cb655bacfe7a9a0df55f6b0b70e","0xa34008b10beabbcc1b66f45f613c114287426f1ef9b66965419427877b8b53b1","0xea122c8cc8eb120c2d5a863c5045338c697ebf05d8d3c4caf1384eefa2a82393","0xae0d4d31395e67985d269bd8e2b58a103ca63b1f315b7bfa04954f12c175a936","0xe4f47833cc02ac05c89f6aab583646d7e8cd952c568eedff42f0d9a5c110be79","0xa07daf56546d5c66945d6dc41916bf391ef84d5049da26af461a5105fe0cc7c4","0x9af4bba21d3e47fe8d3cf1480bd3760f5fb442d01195e47e0039c637e3d1f8be","0x4a93bb0c8fd2ebe9d5a0936da123aac7d813192823de20004159363870c14ebf","0x28956cbd139905595c279fe21f73cb4c03b840ba9c55a49d546d2e69980bd51b","0x7895d6a36e0139b8fa0794d9e86cf6bcdf99a1968bc26462e674bfb7c64fce8f","0x8b4d6d0a02e5c2bb771b688f8d7b041ae69bd69b5a9c36a15d54866a83fc88cc","0xf6e660dfcb18573fb3bd4e6bcf899179fb4002347fd771bd329bb774a3eb3b35","0x692b91d84ad72e4f5d7c76f96517f4904e7c4a70439565363a9abc59abd82645","0xb55fc09625eac0052b8e60fe9576c5d5e9a5b8ae2a82185509d1f290fb59540f","0x4656844be6b83554f267938d9226ac2c190c1e53dbdce1e9eff6031f07610218","0xf36022d80c036e3bfb210214b24610a3c56c743f1357d3e786cfcc07102d2bdd","0x3405e618ccd6632ce51d4786b066256dec3d04d0343f05955ed5ac17c3a1f518","0x5bd4ac3e1da24d873697bba29877c50bf575ec2227530ef42f16a25747a2da2b","0x15e9cc147a1fd4afa2fbbcf48bcd1cf072a1a50302f92e32707350552d4402a8","0x35141f2410346da3ca0151bcf3d5e95c4adf2f3bf8ea3f490a5723164506afcd","0xe4a400778b873fccaabbd6d79c2ff6d19375b220cd71ee99f59ac85377014070","0x30fe7770ed32d0626b7a7ec6e3f8650194e23d963b261052d5c05c4ff3a8f695","0x1a1ecf02b3d5481935649511cd68bb3d54e3df926831968a4b51ea1cd04ca1f2","0x5bdb3f0e8387e95d649d9e7be217922fe350a40acc57c14f36890db11626d61e","0xe0d1f0f6f6f334d4f849383a11ee8d3a34e4cf6305b4b69baeaeaa16acd5be59","0x983f4158864e1fb60cbb0dcad52c9d286d5b120da586e94076e7518943d43c33","0xca55793dea6fc6b4517ba45171edfacd89b05b7cc998c99cc8723de22ae3311e","0xcda01de18d87a7f8bec50c09f25d54aad015bfaae965ea3421213784d730a0bd","0x3a3d5d6350871e365271c20db63f83181d0e4865721e8a6b83f60768de74d494","0xca49131f9d98eae926ddef50e509ea830f35ff62da8bb81269c880650a8c1434","0xc4223c8156cd4c539ce10ef2dbb0608945901eacba30e8e3f54516f6c647cb03","0xe06d2d821d15f991b0fee3de88a9b7c2ac2d138d3596fc13c734e6766f95dac1","0x796670da62868728ba8a089c0ec30413e49c999dbbcf8b6718f9b71bba67ddd8","0x20a4fff92b113c6b03652cb20d695537b618d3066106e5a98f1736ae64172ef6","0x9968128a6d7eaa75807b7098b8a78dc7d7855d7d1720d49dcd00c14be9fd747c","0x3e7dd2b032b8276d870a297a4afd6e1ebe5bfa59537d327d54e245e4d6d37e42","0x1948b6c91bebc99f768a99eef0f36cf73a47a6d8bc985592895187abc3c96f34","0x0ad23c2034c281e092060e5ea60d8e33227d69458fd5fd5bb5d1561fbc448be7","0x23b30515adb9e579147e4b565448c0e7f0da95a81565517f51a617b6ae267003","0xa308270f3ca534892a4c652c26a0b5a729da44a1d7bce7504ae31c5806fd9ef4","0x5ebbf471e9c325e3b26cc93b5207a869d9cf4cb62fc87fe600b218035e6be770","0x4ad13de8e30bef83e9baacc44b19a4fb7eafb4d67e66c6d14b4d44d15d56cf65","0x2af217c3aad3df7f9cf121cc7c950bed0c49a00f46cd52989a0b4a34def4dfa8","0x676bedee2f043e057c5aa18f98f9d7f70cfc0944c0e275a6b8027b1dcc0a445f","0x5f49434ce00acaf7d98a900ab5a7dab53d449400b26568d75081faaab3e2aad4","0x4e6354ea4f71409c2d35d7c58f68079c9cb4dad8994707479c5cd6834df31d8e","0xaface5cddfb8976525e5ba4de8f4fa6312fb58b0fd3749a789d99a00afe17f18","0xada38225ea7ad1b22e9cd7bd07988fc8bbe87c3a3e5b92607854ae40496c8b8e","0x53bb7eaf065e2cbe330d8b89b2be1de436b6b9edfef293c4407a903a3fc59cfb","0xff6e5007ace4a475c4c1cc913438b202743a6d541b00bc3f02ecb178870b71cd","0x9296f6eb357c7b8c8f465f2bf14ca0c0574f838015875a987e517fe524a3af51","0x112d9c11169cf5d82487ad124a46252c66152a9d872d90672d8afd96d010f9f3","0x91d86818e8a1294d3e5dce87b35dcd50cc2ea3279fc677718c53c05a56edc421","0x7f8876ecea245a2975c1ed0822bc505d6d9921328ffe0d2c702123e28bf28e28","0x7b3829745c80349440ebc4cad5023e0aa0453bd979e8d674d07700e09bbf2927","0x84842f4a6391036f49e01409128d298e60b26cdaf92a75fb020df83356d71a19","0x7b94768da25042412acae1280cfbf2652877038ce5dc9a1cdb40bed1f3e68360","0x8ccf49aeb36b49fffb0b38934c919a4e2ed8ccf1bcebcbc66375d71641452be2","0x4d7c5019a2ae6c3fba7a4d09f50f8d6599ee376ff0be124c84d6c70fb053f0e8","0x95aa4f247f4efeb4e0530cc91758a7f65ea039787308bd526fad8c6456424845","0x90fadf47edae0b74a6815a1ca0613048783afdb0031fbac24c4884a70fdc5f0b","0x6d4d39ab338ecf34cce027a457837a28d486c2ac3b863c6c9ac61a430dbe36d4","0x71f290f012c43a8f9659ecc9c15eacf66e1203ee744c5c870d091ee74d57f4ab","0x25224e73a62ee59f4c0f4706de2d7ef3d47bca1b8b4a61f1549c60cce8947849","0xc59177f191969e728d292d9f337b90f1b23db748a538cb79141bb67b2494425a","0x8ab6d3d314ed3ec58ff5658b7d1e9af94d50126c0c03981143e35e37e6210577","0x1b8b2a074ae2c84357dea772a5c8600fa26661d260922a4c916123a3655e7950","0x11ed6ec6883bd1fa665e88cd52c1fbec2f1c0b9c2988e8f2c7ce83d79ee24a56","0xa6ae78324cc6553b878b91ff88bdd0302b8e5a102f44b688fc99ce495f110520","0xf2dc64d694677d32e1f1c7b0f24e3479d634ffa0e1e3112c9d6e9a96547a9e7c","0xb5118ca7951985ed591b2507229bd82a92c30d8d1a2e953ddb9f8b3bc9a998f1","0x4d145fd77d0072c9c3cb8fc7b49076ab36ee9e1203fa7e3e7fbcb9d3a90c2526","0x0eff332932ae434fadefc52f7617b4f725356df1b59b31337379cddd75aafb25","0x3b2ada2d42ab5ad141b2af0a3449f40ccaa0f0c15473bc40fcfeeeb775caba8e","0x82bc2b03a31a446438973aab21951348c40b4bf537457e88556dd7e6cfa40b61","0xe264491b32c11e52f69c08deedeeb12843f1890af2e1820ae24801f363aa7cec","0xb30d8a4ac278eb38fe61d7ec55bf29a1c4b84c91516b959400f8ba9d13379ac8","0xaa1472c8eb82f69fb4bec04c31d5b878a1ca52281c4ad9ba0bbedeec7302e027","0x363efc59897aeb29f3329a25bb30f896dfb42dd8d42a63e149a86610d5f5d620","0x44d27552583da0e3423b10799b4a572dc769c98bed24d21a5d33a521f49b8254","0xe026ae501ecf684eee1487d58e69c41fae5467f40345f6b778c938f6e0c9ce3d","0xed8971dc219759008dfe268577db3ec4aa21bb6fab419c12b9ad6d9776ee9d5d","0xc5153a5ee3ff5ee22275887ad7218580de1a193243d821b85166bbf981bb8887","0x538fcdac5ee56137d8ecd49d6772e07d941834d18e817d48d25fbffba5b9eaed","0x40b7c20706b496ce728313fb0037d01c82e175aea361aeebb51edc3cfc247e8d","0x55335e13adb9ea098ad551782b0e75d03a246d29c47d0c9c22c86b67787d5297","0x6add885bf84ef8c8099d4ffc32a3edc9c16a6454b72fbb4a432d523c5e2c5756","0xee48e07e275f12a6ae6a1ee8e3781faea1a197c69fc5f1ede45c6852445fc219","0xfa93da79d2f54509cd2e9a5c18ef48f78f7aa544b61695bfb09d2518240651e2","0xcdcaea5889dbe88713ea614759264222c001ec390fd2cf8e7adf753eab429bb6","0x051438e011220ddef814a035df65de71d415e9e949acb19f4e74b1235597576f","0x2df80eb232d4f24bb256f7f0f61ef5a72af409ae41de00fedfe8aa81917a3c75","0x13bf71e6d65c05c94f1d58f39c9718d27384d96ffdc66cbbc46ee3f14a85b95f","0x2dbb891a27b14088c6595d9fdf489fe2b0d99d268f58084cf04609ee21e0588e","0x619c57f000b6f0e5ed8767d05a1073c92faf28c4eef782378439260af8a655ec","0xd930257ee7ed2bf51f35d126889a695807388dc2bee4cbf7cd5e1c62da4c85ca","0xadd9d0551b16a21893fbd2bd75c3d41bb548de58f8f726be586da77b712f09ad","0x9edb0c59b9424121d754331d0c8f8dce26c82b3493044002d908feb5d0130903","0x59f7fa25bdd205ec1aa28fe152f95dc6c8d2ba14cb7308c6527d7d110baa48d9","0x554f4ceab3755d5ae3716abd40ba4004084703adbad9531fdb01ba2db366c018","0xa6e2034b846b0649a94f5e677dc1a497598cdca6264d244fa0cf56e4b9753e75","0x7030e5cb45dba12de44f50fb5f77b31ec82bd9f1d2fe453aa553d54e86b8812f","0xe4778c6610ffe6772d8532ea7d75761be7630845c11c0239461f8e6c2a7d4267","0x76d9c7ff6768b345728c2e844dc0765e6ceda6fc66001751cf88f4135be5cccb","0xe5394b8db2fa3502afdaebde5eb76e185ee555beb577159dc7095696e0cc6292","0x8c9d22925d2c72668ba6687345a861c87c20775b2d119fd53a0dc9defe1ee247","0x9433fac859d44a80f4251a225673988e69cafd4826c905c36f3fb2de6a608bd5","0xa20a8afa175a1737f8de03099e69f4378de49c19bf999e528111793e12cb8825","0xbda4095bafa7a06fe8c81d7ad1cbe52d0b54f0aa7c67cece50bf1a3fbd333c07","0x894a623a9b9da38b8f5f1f1189df089736154c622dbba93ce7cb64b37480612a","0xb2a5d574d6d34d0cdd5635ee7ca01e04bb5e07b8d17769ff4dd34cd683b16245","0xc9cdcac1c5664ead5f67699a2fa4a461eff52d478f46350bb11b874e8e7c807b","0x01842e9ae306398bcdf5234cdb7c1116ccf8f41944803ae7b0167b226a52ee10","0xf6e6732e75522b2e4d9ee5f21559db2c4f75cb4bd36126812514bcc349cf3be7","0xcf45e9a182e651fd7c739bb73e86a6414a52c372bc0edd26dcd322f5e1b5bd21","0xf51b2ba4940beab2ba90991cf8e4ef0a565342a8f0eae61775d6ae5e5c4c3283","0x88948eb8dd4ad67c960da29430849c4ce19c92f587120d5217063ab58b7de14e","0xc246eb3d1a9baef5084093e9553352a6d46f7de3baf437b5628c5a36b0e5335d","0x144105ff072d5c81ff6e31658e8ed932d11ee0ba762e83598cc5bff915e50a30","0xe92804dfd8c3b63759b93de79cc414884dd617d5bd9dddf774952c956c3b466c","0xeda6eae478f9210eae91d03d812dc53de793f993ca2ed537bf6620fa4f2b7fdc","0x56b3337100d19a0e212a4b97c69b19bec7e9559dd8c075cce6429dc39d14af72","0x6ac8d9a80c9d978926024f60d8ba9538f3ac967d22f6dc1802c8175ff59e36ee","0xadba8639073476bfe9ff035b38db0941fb687a9ea71b2307f95604a808bdac7e","0x7511ac63a9554cebe9aad384e860b16c0828615e9410d8ec0c672c5510ff416d","0x834cd4ac3a62462513d6d8dc4cfb23d3b19302667ce824d7609fc43310746d2d","0xb986be1e9065892dcac4e8303dc77b90de3d17d1d972e3d1307075fdc39ab017","0xe39b5bc786ff4d5e5065757b00e45a8d8870f646aef151c79869ecc6c79fedf7","0x08b6f733dcd6628933377edeba78e0d50bda913801bc8dac799d5bf92fc1a161","0x15e4fc5ab0a061866980a5bf9cd49a8ffc1a4ab9be9fb87887819bb5b0971373","0x1f8b081d2f474a1835676fdb901897c533ceace6ddd0d62162a6abd2f4350f87","0xc45113d76810c8f8823f7c771ba97d4d9ba8276592c3849be3ae88fc21ef32d0","0x105c2dc2a5e173148ad1dfb35c877a0c5722ef3d31d56f6cd1c677e993e84a64","0x9ed049608081f28824501ad66f5756880fa31cb10710c1fdc0f016ab456bdacb","0x99abca238c9ac5e1e39a227d1e683db17b7a3a93711f2f99c6269356d605d040","0x45b0d55f94c157d8f32bf6ef81177e2c96a730ce423eb5263ed95bacfb52813c","0xa75f6cf93d5e21cbe65ca3b35a148e010a24eecbadfcbb262ff3d7adef691995","0x60471e22a4412277d71b0160403e0ca05a103d07d7137e877fb1336f2e193c8a","0x42f05bbe37a39cc48ff62931580040d6c89fdce27cdbf034d20d05d39c447585","0xe17ac2a3b8ced1124a9a4c4aa057c549efb2e7a54b905a9cc8bcac24dfc43fde","0x84a692f06d0684ef48e66e83eff3c8bd10a836e5bc94a1328540575030d966d4","0xb8b2d53393e7146e940357761e97be2b242c0fb2c683259c6dcf745082cd55b0","0x684b0143a5254004d9059f79d9f7c050707fb1078c3921e5e96417110621deb6","0x56f8eac37acf2e21ef72f340d1c710c98a15fb00b045e3174ec2879c009b6dd8","0x2e83f13e8a961c0a14270ec761cde4cc6f285d732864bf20779355e05d9a5481","0x4a88aa0013df52144cb0ab92d9bc98153b1fc943d85b9c149fe46b996a68c692","0xa59535641f4086acd4067a22311e264e25900d5e159df56c995fe06cec33049b","0xe529366c1bb9770bd882efd2cac89134da3fabd0a19186b50c50f35e82dd6861","0xb1b137b4c39b768d39506d32892b2315965db25bb3526e3fa1b7266ef51b46d3","0xb1bc4bac9e493cb50d88e32a7a7daff94332e07d73a9e5892bcb3de838831673","0x85df23e3dab3f4a0c8a2c7e0af662036821eff3e1764e1f9910c14789bd1dc4e","0xa6e62279da387962edb93c44f38c2e1e89171494b1cac465a101af3c47e6dbd4","0x6c2a10b33569e67b0ed695bee2eb39aea96105fc3f152a0d30289d25b3ed75f0","0xdea3c2fa5868fc1aaecb76798e9448d403c895c40db9cfe49ab699fee7e3cd4f","0xebc244fb4a5efb1938e7b882b019ee54624d0deffb42a4057bd31d4f763f8bda","0xe6f1265961016a1a9cfcf0d4284c20bf85b88382261ffa956cee68feacf7c48c","0x2ba4b260d48c32ae498c84549a1bb90c0c53bb1290ff484dee250284eda55f46","0xf143e54372bbe815c1b627460e3c9f4f350be6cc2e8053961552d5c986597b7f","0xf02c5b46757389d684017a4053ea46588ceaad9f62c3b98920f624d5299f98b2","0x9bafd2f08045e9c9081dd79212437d0b566ba50b92a00561b3826c3fdf91e63f","0xecbc870c7d6baa6e6f0f8edac2bb9460832683a7362e24dfc49fe898e077d993","0x0b2f5140c6d6fa90d6bd41d770afc5b0be9c3449b5cd65f7029210eeea32b2f5","0x7ffe85da0b00b4b943a3ce628227aae0b6e5da5a4f06ad6d0f3699a23aaa5028","0xfb449e2b64e625c9e9740949aabc6b460a982645eea0fca27917696b25e9efca","0x66bcefffe97503a49c8c5a4e9361f4b2f7b8f8847a5602e411cfde179260d0b8","0xa8ac3713f360dad23affb1343f549c461803bb8b6c7df344e7bf4dbe3ce33cc3","0x1bc132c7f521750c30b480b7f2c05c314024adcdc4de87bb0e86693da5490331","0x8c4c4437bc6be48c7eeaa71554f2536b71936e0eb5ab25bf26617dbc8fd7edf5","0xb52843974876b3fbaebe96aa3485a33c0f485628b4ee68bf205a58078cc18061","0x67a5e17daaa87b484e82694ea508ff04cc9dcafa253c80dba7133b67986ee021","0x0538ec67b9c688952ecbc46357ff8d091e380e7aa05cd1d0d56cb6acf6c051b9","0x2dd3df69c8f3455a5330ca6c523da42bbdffdb12c2b9fabe813630732642b1b4","0xa36618444cd68f7350aec7f5a25969fdd082f4c7b831e603c3b2140613473e48","0x043fd055dcb3144399334ecf05761b69d5235c9a4b2af7ccd02c52ad35df8a87","0x4a71052fd147cdf9facf7479583ec614fc97c5cd7db0de293367389f7c378dc1","0x01d64f0a8690f1a20c50b5f185bb0a3281342ac00c878fb1236aeca694ac7b19","0x5eab60cfdae22833b88238f2f21ce7c87ae0e10581517ea97eb2054198ad6746","0x6e8b63a3d99065ed1dcb19b49d9ea5353d366aa1ddde403244968694439a2a78","0x0b56043d25264cb7b4510315badc70fa3b2fdbc1837a374ecf38d986cc7f7818","0x77e271686cef96693f7f442cc221980d031218f4ac3406229faf039e47ed3a5d","0x8f3ac77e6e60f2154ce95c6bbca697107bb0ec6f0114232d7674f25aa2e07bb7","0x464dd9efe9521622522459ca8d38325b7b6178ab6b784566f284e5f0c05bc818","0xe675da2566cd2661912c059acd072f63ec1485a60ed1df9cdc2d40ab02caf83e","0x9fcf81948ea04f10744de10c38a9d65d4cf1341cbb8b91018bbebbe78ad2e884","0x83e34df468d56018bba36090b3e2761dfa164ea0459359468e304c24d762456e","0xe93880511a9c8841fd2e689b003898986c10c6d3a91b092db2d2a8592552e4d6","0x5cd260cbee3a58c0a7e6d95b03cf6cbf1ecc68d5b4ece788e614865b4a1b4f21","0x1c416fa01d4ba43b85b23cf642b5f4c1bd1715ffc75962d629608399c556b216","0xb94f158da574b3f60665ca08f2eb8cfe834097750f5a2ce19867966f8ef333a5","0xdb5952934833e17efac50339788b4b35ad0563d73ff671b5b33fc2c11b8204c0","0x20a8b74b8a517de62eaa6edee1b2eea429ed8c21dbdf245069c23850d315bf25","0xa072ec6934087b9f3a53eeecdd0c9951e6199b74d779bf35c05cf3bfcb3252eb","0xbbdeca4903b6ab13e733c3a61152b10bff1c6c26325d9810a6ddaaef71ec9512","0x84142e0f127ef0f2601fbff8d43af96ac33201aa689360c42e984f8fbd504890","0xdeaff8dfcf67900df2f3f7b844b9c92ad39c0208fdc4f71d15e727675724464b","0x2eb4c0f0293437c8f48007ad40f42273de36d454e00d3112e12d5aba8353d064","0x3a046a6d0747bfa282975fea37befc2fc82e9678ec929302dfc354eb774b424f","0x5c6949eb6d08e9b0ec7addb64cef0136328f5bc8f08e6d5dc63127d62494a6ee","0xb11bddeebe95d378d0f823b9c219f5c24c33caaf670a9ebc957bf79954f97c8d","0x512edcf64021367946b7b497ee61a10d6bd5509a428252805346bbe654ce1201",null,"0x2bcb1dac0049e6f7c1c3b985d2fda58e76086235535e42a639285b50f991c2d8","0x8d2d208c47a0dc7426ba314f5ac09858bead0a4406f73195b42a742534351ca9","0xfabc32e0588d42c64e84e0b53ea0c1d15873e8fc9288edc7a4d14a27481c47e7","0xfff00475e1b49df876dd137c36d4f4aca56226cf34f82eace008fdef4d6c0123","0xa124e9d8d12fc5c0aa6c79961b37e60f3b510b1d46bdc6da200086b3ddf0bcb4","0x35ff11cfbc63c50634c37303ccbd5ab9852b95b8973508a89a3008ae15b4230c","0x647527342f2b65b95fc33497452cb7320c2a6701a0d509ac609075ddbb1684eb","0x447698529fbf5d025e32aaa4c8591e0654429a9f638b693afc217cf714894e5c","0xde4853a740fb55620fd199b47c837aef1cd511fbad84e88307384547a7d66169","0x5bb0c96174a3b55c28f8170d643d7f47bc5fa4c5c1a934eb20c0975f20baeeb8","0x108c08ddf885f58b4e94e09219bdc478ef844f12804daf07bf7741954c0b1973","0xec578775389c0ab3a89739085991fcbb37317d93f47e86d3433c2b7bbbab2f90","0x1ecaefbdf299f2bb13d485d81e5d79fe93d2955d090b02414e2aea5b7f07966b","0x74a66fc11e5c48b7aef5bd02d3dcab6dfebbca8ddac5270c7d10d9ef04db8ac2","0xb8c5fca2c3d1438356b6c9ad15b461c62c37ef7304f421a87751a9bc4b0657ad","0x0037f0f50841db4d5c591ca45a030cb79004185c2c22e700be045efd3743dda5","0x6993466a80c874c66ad9c90a76af4dbfe49558afa5a3f8a6d33f93393cb360a3","0x95da333d378ed9d6ca707254e3b4f6ddab253338dc34b342593c4e093547acdb","0x7a1e9e4619f524c213316b5e94361939c04ae63b687dd3f265c2006ac7dc72c3","0x71a96755e23c87e46f447ea1b93913fc2d6f8c0db860a293dce3dce5730b03e5","0x47fe36d223e88c158f323c96d65588af74be8aa99b820429f7caeabf9b604bee","0x1e715926775e057716b9acd673bed0a0c6af775ed88793400e3ca373768448f9","0x28d00c98973d994238130798867ca704e7f0c7cf5842e4912e10fcd3ecb2b7d6","0x6d13049bf0d0040e656d414b6e4667fb22b99ad98b744f577c2f77a20728307e","0x47cae99fdf51c07d0e19cff6b7b256280c35539757e10598c41580d99abb4ee4","0x8003ab677fe642c49130161ec2ae3af6efe142bad15734f2213884e125f3c7e7","0x330e474a9bcefeb6a211d78d444b046418fef1c89c2ca57c71442cb84849a6c0","0xe5dbc4c14a7d3381c9cef56605d169570ea032fc84fbe9fe3981f8201e63384f","0xc45eda02f6e3965268a1eebe24ea2314c46f340d791b9e70082c1d1c6d8afd21","0x8e225f5832e0a10f646c45229bc7e875d81bc1653e9d95498691e78564d23888","0x57a2f03f2d3b52ac23c37045d15bd78907d8bfa9ea3d42844fd4d7b28da56986","0x2b8280598b3d96e92a861125e650cc725d5e4ff2b48859c8dba22fcc93c83f0a","0xf46ac71e3104c3462549d9477b31c59cde632e288eef6de05996c2a364a8d020","0xe7edd7e1dcc87da655236c1ee9ff3c2e5fc69512416aa5d2acd5a68da334778d","0xfb1c3bdacfaf5394d1850b3759c87c6e9203f5ac8bf5dcaf8ce3778c4011a5d2","0x5485cffd80c6a762248ce355e3929a9b1c94973627f46fb8112f95368594c2f8","0xa2fe5427708fc22703ea81c3550b55b5a27534db4fb9f02bb029b9f7d50712c4","0x5861ee465d4bb44653454b8c578ca5098b81b200d88e0119a2ebddad01533262","0xc84b243ccce7f1cc84d18dd0a7d7f85975d7061f2fe91107691d7d7a2c680317","0x0c0ea9f7f0de1b85439953dd4206f841d74590905f105baba71911f136cb402d","0x8d75c533f8d4db14c8a6dcac8dd60b9a98aed03e26691fd1fb9e2fc3c3ba9690","0x1805d2f45a0aea97624bc88f1c8c031cf47bba677e0f6546a01e86d7f3d0f27b","0x1cfca5e5d2f85ee32c8dcaf9d4bf2568171d42d51f2ea508d0c74abf00affd20","0xd8d73eab42c75c86f731f4dad63d3e273af3208353b507fa6827238def364868","0x507c5683753f13b3e5a162376c209ab9b95a77d765cb623c2223cbf26dbb41a8","0xa3558980e2740d554c8c3c106515743259eb2b20416b0b573235e7059d360c7d","0x094cab84102dc294750749359d757cbefc020c94f46e6b58a3e447b3e5463861","0x4a4d25cf1216b4e7c44c8bdd421c4ea60db071a601f49c9a6f50804620139e33","0xf7b344c4e653acb060502990eb036725c8fe5dd4695a08c235577e31e549d365","0xa8b01d6a5865a472215abe47654b8f5bc79279de7dd358a12ee7302e3c030aad","0xde74059780236d70349c60d740b5e379cce944210139f8ea207f63b925f374d0","0xc338085ae3e56746aa2fd1775217d6a61ce03cdca0755ac9c7236132d80e0f2b","0x2577a72238110062555e9675db608deb1ccece299c2b494580317818491c9d52","0xe72a70155ca550ea5731fbc44a7470a86bd3aeb02742a89165fc009134015998","0x9c7166133e4218fbb0680fe0e85a6d1456ef12063e22c4cc718cd5d56bc69267","0xc24f00b34888632895913dae7e5ce0bfc404418abbec908223513a789c3ace0e","0xd908f7c39d0a704911406a51dfa9f10d995857cc7acd244205998cc27187f407","0xa073ddaa10bc1dac0e743686f209a6cea79a3f31eef0906b768cb9be375b683b","0x43ddb22beb4ad7998bdbe76757ce192e5611262d79305530da23b4f007b99181","0x5a1bb100cbb3f63cdbc1ab07f1812b6359bb65ef829f4cf7fc1e382fff19a133","0x5b22ec697601555d0110416750905431ec2c26080320c8d5f4896d9dab6fd546","0xc2404bfa71ce902525264a5f5a1df30e2a95c4950a0a6428a25fa4d3f5da431d","0x49a6cffa2638f22c8ad533ee349baa7e46b9f0b4bd7b712a6fa5ee3c37af0014","0x80c800ec7aff60aa09d04e28d14b2a526f04c3e3fe74e8967bd2889841f3c78d","0x845a7227e2dc00af7100eea450e8d7308c1a40fbf8d99d6096ea57e558c4dc63","0x3eac891f5ec9a67ca561674909a2df20951b9162236920c99d1cbc3510141f49","0xdc64a145629e00aa85c25d0fa4b6d3b6bf14248c47fae2e88330cf89e6fe0d90","0xa1c589c03d124ef3acaee29b4f9dd3dbbe69882e5d9269e6ee1629316da4ca1f","0x59e3360615f64e1d8c53ef5a1f140898f806d11327f00c14559cfcde947763f4","0xbf472eb8830cf405d0f56f066af380136054a4d2288af767e36175cbc23d1885","0x45d376181ab75e69753c0435cf33d43840946ead20be091554efd51c4fc09da1","0xcdc43ff20013a51c3e25c226896b344a431fc9491bc03e59b15be510bc5040ce","0x174e761747a67f017f6a44b9344b2a1efe259a27bd311e3c84c9baa6847f3199","0x575c38d498f1b5f81ab443774c492aff99d3af565aa9b2543260c34c2768d643","0x4e46557ede1ef04c533250419d52ae0b553800fb5ff7abab1ebd8364aef692a8","0x7ac2c41c765f0980ebe2b98b2bdd9817e95b685c25f074e746d33ddb0c57354e","0xd652d1c03bc6faedf042dd066169281940a89e759f002da4a93d9ed30b07032a","0x17b25876aa1a953c9df3974cea3d38b6975cbc01a124337ddd310f64ee1807df","0x3d036a6b1b0bfda9a1d75c2fa0bf8294c4a7a1c043af19dbc6a5a50db1dcf089","0xaf39012c8653e1a6adf979fb8f00f9195b1ee110e6914027548c8e63bcaa9731","0x62107d55df0ab2328ef2142acba8b8b5ff09310e71e8a7491c3706e090d4fec4","0x94eb484ece809e5bd474c3f6c10b323643c860d8851dfbc96982587afd03b0fc","0x3521b5e08185937bed30d87cf6679b6d16eb0019c5ba702d7590abc7aa73a839","0x76dddf7924254ec3287a43e6da1f6eab442adf1690e870c5e5ed126d5c3824c7","0x7d82d487d43b0a201077af754d8daede5159a40560e7a2d415010925f621d492","0x025c1b1fc3b8515145dbf6cf55081e753f0a0c600164684a9e85d4bb75a4a0e0","0x7e2aca5987f7c24ad618dfda81acde722f627ac8fcc198c585a314dc1ab586e3","0x9fba9f82e8cbdb182f958cd7f83d02bcf1c01977556b2f2a4c50aa500ae079d4","0x26237c2621408d01ead5a0be569e567a7562bc495c4ac26d79067b363a34936f","0x73d0f3491ee9673a3dec24ca34b620046fd10f6343f95d3c4751ae05dfa342e9","0x9e0d9b8db1902a7b96441b159e10962a0764ee35ff18a35e4bf1cc3a51b31063","0xe5bdcf42b0556e696f2068f79a9510ab221eebeb891799131580cebb1f03dfd9","0xa17cc5a0332aa76756e5191385eebf66d9bde71324a33c9daddd3744056c7364","0x53ed10c829fc77687ce39588be41b08a14b26277bd82a54cdf2feb0be32c6044","0xbd250c3a009001b173beefc6d1f63df359701bc788e9da68188dae835a39c191","0xc73e525c654db4782b61e1e81e17d0e8f1a82b6ed0586642ff7e9ec0cf441756","0xe8a6467c7e847d23b1b91fcf593e5d00d17a06dc08c26dab51449cc7c3870c28","0x62ee5af7174721f0aa452f3f54e97db420e8787c68096243e1058298008a03e9","0x9b52418dbe957d03ed9426ceabbc843c95e3a12a6b4a05c87a1b96380331ae3a","0xc5a4c55225dbea3d49386f0c6533d378e72a7869e3a5664ac4a282e49be9318a","0x0b36ffd90d50bc7a839bad4a086121394f56ed023acdc656472f5505c3c522bf","0x2598788d60db78387c206289dc2ce4e893ebc09b890db9084f3e411dd196c9bb","0x87e42d942934b9472c10ae34324c0e496f5b07fafbfbef0c3fd2724feb54eaea","0xea405a1f92ec35c01d2e994a4ad18439025b362ac8913c7022a2720c0abc200e","0x47ddbc96a2db686a9dc44f089df45fea261bbfa9e6fced594a34d5b1da441dcb","0x85f1c453f79c79702cc8977941139ae888a484336261d1a4e777581707bbe1a6","0x87e6c80bc425b77b436d8a252bedca4566f9c8f218579ca8df95e3b71d0a2342","0x0348009b4fbce90cba9fd937aefd73ef9a14f415bf01d348f0a75dd2e3efd471","0x5e94e01ae27e9d7e01ad4d735b07d2e101d269c0c2f86c653f8b0db2248f4290","0x11437f14bc0f61ac30cdccdb53bdf87cd81c5a49e0e267c41d10e769e92768cd","0x7191471b5057857674330ac3a6f6285c1b2bea73ccc0b56deec0714c1a29d7de","0xcd93157b1edf998ee8cd64084d26b5682b791afbed6e8e4459a6c56f0219c22e","0xe24917a2347e168ecd5aaee1c3ce82ae30d0fdcf89688966752e5efbf24d0922","0x921c9cff68ad8d73d895aa7c7bb1788e774a5892af1ab828cd8a98dcf5faa24c","0xce451941f97ee55c458800d1cd9b8fa1b3dd28749bcadcaad96fc1645d05bbe8","0xd43d389a6466399f4416002fdd67ebfcd491fea50abb060ff2f788429c102064","0xf80e9c448d875234ad974fcbbac40dd0f1202c46bc4f9a9d4a2ff2360c55e4c6","0xca848915da408944310d75dc17126b0098ec168cde00d874cf09378813c6c450","0x86b29e35d6e7c22755cc94f79335ee0d3db2a5c5527bd44b88aee006c7737bf0","0x6eca3663d59159aaa3bbdf69f71f8477f95a8e22681fec32ab7c175a72716e18","0xf744e305ff6ce10fc0fe150c4fde2cc67adf256ad1a0571a9cc8604a54b9bc62","0xf768dd4eca3f80539e3125d9f33c3225fb49d5e1e7bd67e26f40764def2ab60f","0x6be5aaa12c13b2599487d9df6cb2a2be003270596b36960e2845c19b7de752ae","0x159f6811001e644ab3f1b52a45769b092ec23b23e5c112e20082d564399a43a6","0xb3367024cb135ab988b5e7c58932c45d94e1df8705c4b518fdd58c2baa7332dc","0x896310658db5c4a7f8ee8ef72c8e2f751d8efb8b5894cdd3ae66237f9e845bad","0x05ad0040f9813b865719ac10f78a050aec33de0e662be8e6c370bfa46cd7cdac","0xa62ab26ed680ede0acfde85049ea7f05866b96780e1a4865683bfd466f9573ca","0x91c5f843aa1648185779880c7e6b71dfb034716286ed5acfa597343a8429f0e3","0x41dd21e99de807090edabfc37d73724b9dfb0d203143f0bc954d1a9b983bb394","0xf452b6d8928d7f56fa4ceeff724f4bed574d0ae1a6d199fdbea625ec2a3def07","0xdecdb93ad9ae939cc6d4b384b7b41519c23032f2f28ee2ddc45dc9a88b281e16","0x46e825f742d7c34300b33ef2f332d7f54f418d295a6d03e081728d3c502ba5a9","0xc01a6f098a88877e38ac850331653148cd986e06f67add5fdbbda4e106a6c5cb","0x0c69a1b4b3c2b2dabef7cc47b7eebfbc1f06848d9b9cff8cc90ff40e2a238e6f","0xaa26fe4d51559953293c73aeb41b7abed65922f20a595e6579a0a99adc630bc5","0xd36a27f3154216ce1007ea11a70b942fc9414c41b5a04f3341da59f188e0d42e","0x0d4657f3745d9c4d1e8ed11c33e48e4c3edcb6ad03db51714125388a94823888","0x2ac7ae5d3ded1624aa4334349b4e938f8c2e6069b31e8972589415a016752969","0x389375472455bd67110a1a96ae945b0ed3ca0e1a6e851dbf07db29f100f24c8d","0x6c3b9d791921fddf0dd71b0b42c84a4070ef65a00b2e9b93f185ac1d1bcf9600","0x61935fb16d1bb8c9c2ed136d6b7a52f8d117d078d18a43202e9c5588383a4f9f","0xdd7e593eaf3081945e037c243f1d82617832e7dcefead16fce97d63c4577b485","0xce1c9d2c60add0abd8c48a11055b5bfcb540ba6223222ff0f9bce3e37cb7e7c6","0x8a6d98d5a5d80a001aefd4933189ab9debf112eab39e6508283e6d91f6fe4d87","0x4d3188d98e2a27b6789effafab9a645c97c095e027dbe9f05bd82fbda0a76d18","0x85c1f7bb11f4e175374f9fdd8b7fe1cc3c38ac628047dd8065c32b76657584d7","0x861820d41d01a4765ff21bd837257390654e31a24140ab700c8db2e2374982d4","0x9e1181c95eed5198e437fc909d7c022506141fe3f8fd6fffe24550503ade02d2","0x1099b4d854252fec5b476a8584d82a02882ab93f6035fa0687127aaf717d4caf","0x3c098242a07cc9dee1c21ce0725b2e4a7dbc19c919716a8ad8aff2dadf9152d4","0xc5784412dfbbae99d85e1140f3eb87f06fa9a054553c538dfb87dc0d7670bd5b","0x2a54ed7e51367282316f66a7009e19c8cf0b0599d05df86c7c157daf15ea4109","0x5379f6173ed27034a1f0a1968c8f506d753ca7c24cf52ced4a3d39a02101bb40","0x1f813d6e60c7060d87ae9662e1c925afb3ad5d9a66705f955ccacdaffd3d6e61","0xe703f6f5949ef85ce155ecf50baa625de57313edaa8c9c8fe6b8a339142c5c20","0xac26d24611b406b65c66a84322498bb31e3956d7877243cf2efb45d417ea107d","0x9e87bdcb4d9c62453f9b7cb7379373c57b5b5fa147cb9be7ef06330096ddff11","0x96f975477ea0b052740a1eb1621fad911806a86a6f5c796b19aa107dfcfb366e","0x837bff3c4d242cbf1dd06e34e391fab21b459a0110b2b325e9698eec7fa6ca37","0x82f21406fbf872c76b4c9020ef2b3f1cd627cb9bb6536d8a85851ffe05e67780","0x41281a88c9033844362660118a8b1154dba01bdd1db6d91419ff09a8af8e7c62","0xad30e62c06904a8e96dc91db0c336cd64d95569ea8df012a21e7238d3e1004b7","0x6ace0e9b517fb0d74ce7a67068dec53351bd94025ed110c11aaf6bd6836f6b28","0x4a68029f8d5577136b53f1cb84af25401e6ea618352b6dc6638e1f7d872f017a","0xe1678e974b3622e24dc18c079b3dfb2e9f71f54fbf50e03c13f90fd3e3f2454a","0xf6a8c0e20646e98f2007bda73bd281357cb3e64b4422fe7c5ae0f0528eefe201","0x41ed971a64f06be1fec58fbdf6ad62052a7a21d196e380f781b71b35acdd395b","0xd309f236a7455fa26628de1a3ade0dd99a91aace36587cc0adcf18db8e85d97d","0xd1df80699298f439f226dee4f75359cdd031d4ed502ac0e662e227623abecfe6","0xac48526d2fba3ff5fa2191cf4faa2d99e47f66f3099c09c35c333430b3fede1f","0x41d62cd543f9297a93ba75d93e44db6aeb9efac842d035471435e54dc0eb1574","0x954573f9f0b33ce6855e090448f2835c6fde0aef9607f75ea346648e1d73e47d","0x704513f32910865e6367a581911827d609ab66dee6c92b9ca19de1f71baeede8","0x08ed021d3e243852c53dbf8489dad9c8b8164723a51523fd0ce25071b95b62be","0x78faac74e0347b99c7df83b049666b40d8511245d2d8df0ac41bf8945a0e0f8c","0xfad580dbd0f4f92cdaa2db6a6a863df69cfefe0b03abceee71d7ac9833239dfc","0xec34d2a27f6f45515177aa774f138278e9cb32b43440f0da27d6a66841e7dea9","0x39f4627640648ac6dd97245677699a0fe39da02375a0c5543ba2da6f7a0729a5","0xe09e222c2a1a1c2c0a0c8f53f57f0131f532d73dfc19bc8abca6855544d8c669","0xd6dab4fd69002f08ce66575a23790665c63dac065bfafc4b0644f397a38b3b9d","0x9d463191ac44b6ef1c0bc25204a5a000f6ec0f7e033ab5daed0c0dd5415d76a0","0x0d1dbc1862ba33f42cdc461a14655bed5ba717d6ede7e118a1e6b0089a2ab6ba","0x18015d87c3f9ff44b0329dd7448c9a03332da7636efa9db02189993194528f1d","0x844183dc961c678c3ba5692690e3b64e3acc552ab6844999d4b06dc595d11c7a","0xaa43081414fe097dc31837fbb20d7479a952544e9e83b950aeb0bf4b498b3328","0xc7e1074ff74519def16453ea53ec17600cddea4c120112314e02561635099119","0x7c1fd53ecc712b5de74f444a72689197f4b705588a4ba6e37d522a69c2d19f90","0x028c4ec9e7e048c3d498d295d06d3c3ef3b4561e575f8e1cb169d1691235599a","0x734ff75dca8db518e0bf8ae62b6dcf44ebba040172a066770835a3c7a16706cf","0xf46657e121cda26519bab098637c53b9fccfe5d425376f1eb90a2d2317aaf6fd","0xeee47ead5596f85e18099b30b9723a647489df7ad5649e695266e7e1a57330ae","0x79881d3b1063e2fb58b1eae7cb1b6715cea27d8f226363a2536da6e9831cfd8b","0x12c4f60766447675ea0f9dcd85ce4aaa0e32feb50cbc984cf00297822e9ddb47","0x0e5ed5adcc08ce30bb3c5058bf43eadd2c107e91102fde8a730db20e7972c2ec","0x32251160045351fa8e814223a07519a818c59fd6bccd34b8d8ba840b1206c9c2","0xec38c5d1b479144db68818cb94f6371c87883c0da199b3ed024c09e8f450c6ca","0x8bda80a6bde84f361dc6501158aa8ec8cf879314c4a0b5483b04636c0aac5862","0xd2f79b0e2c0b4d4010b1f01c6100a223e96d6dbbd42269c151d253106b926710","0xfb7adcc7a99dc683ef8404d7241657c1a25f4aac5b574a83a6113bb2c2e40558","0x5f5a4c4357c533ab8c75c2e84a9ca8dfcff9eaf8b1a6fb252e85f4dcb487e261","0xd191a54b2eb1ca68a58d55ec6cb002f759fc288737ff4721b0cadcd83125917a","0xa8f3416ce91d65b945568e642063f2791399ca17ce93f46c25157a22c6d9cbdb","0x808cc3f142b9964207a88826f2f23a989c34e01e785573b436977fa0de23d8cd","0xe9dfc4c2fd81906fe3ade76c36f0bdd6bc907ad6ec65fa454f8e992333dd1852","0x2bf732ae27fc927a36647c8505fd0696f9f58f41de1db2693f7f7c9781e1530a","0x526159798a6641441d87fdd08eaa3b81ebc53a443f33d60bd4e7029fb9f0c8ae","0x222a1d86b1fec98a62a2ee1421fceebf312cbb53766df9018701d8841a39aec9","0x776e199ffe9c16255ef69c6c5d350fecb21238f41d600836951a2c24f9c7f99d","0xe6a758c7acf353348e156370ab001a621ab8bb107f8757b812bed7527b7b708d","0x21eeaba4cbe2ffc140247b0a822c6df02a0bb6f60fa46007c9291a9170c56b1b","0xbf312a7a9f7262169dc7d3e92e9489616f13bbe22d41fa7b6dc5a2a3a82cfe7c","0x36277f6939844e3fcad79c2d45f6d048df23ff19e7eb6fc990e39ff7fa5653a3","0x9614f16c84f8cc629655497f4825b81d6bc3d0e5e445e73c8aa39cf15eae6743","0x026e67171fd870ab613efd3d1883b914149a2678e6bd9e4f1924a866202d8770","0x4326431aaa11075ce07ef90313b655e54ae44b90577ad34721c40cdb9d98b4df","0xb235c73ec058b0dfc7af10dc4785aa4640b49c7514e14bd279a08481b77e4a3d","0x81aa0a1304fa7c710f58bce2c0ec53120c9579584cec60c43f2d738794689be2","0xc29ca8e9febaef4a758090eacd1e922210bf731cfaa47ff05385c4d5f30a9ae5","0xfb8da604916346c9a37553e55500d06dd830c8e8c9d7521506dff7a08dacce8b","0x8f6faa6777eb5414cea0e32bd35bef01e03e4a89321c9b62b1aa2fd32dc8ddcb","0x1e326560a2e244ed1e8c5c76d9db22cf6233dfc0b2c6452ba4642cade131d86f","0x2ed7f9b1fb9fe1825487c6044029ad7c5aab95b6bf91fd8ebfb4cc2d1c9f2c62","0x80974baa9e8c5a70374c08384b0ab13c3cc5d313d2f60c035e8a66f16f9ddb16","0x462493b5e99e5a391dc936b216bd2ab2a353c3cbbfe82d3b56ada075bb4368d4","0x8ab4a785bd70707dcc8c42ac1a0285d457b5d61da19ebbce65197355d28660c0","0xfc01a97c66b3a9c5a9d333a1a46a19034d8c235b933ce3d189e8760a686c370a","0xbeccff40c301b3d07760712393df9a1359432c699a020535c3c122b5737e9698","0xf77756acd58701b4d2e0732110c4ce2e4917831009a561d3e2980d4dd8336078","0xd98b303406b3648a383725472ced57115305b9552bbd1e70d14f68f6b33ebaab","0xa2bc36fbb643c51cdbfe0152bee3d7eecf668caf46683fa21dd07759a1c3c0ca","0x5b9d639175473bf3966a2b1a4b5b78ad239e347821a0186e24a9328d8df5c225","0x6fb444c54f19afc28ce1f8e1e5af3f3cffc3d472e52c78b63ead9eb71241dbd4","0x7a67e7c5f3c153b94a9404813dc3f9d9879c6d9c6df41743e9acfda786d1fdbd","0xc8188aed0d329a4ec1e4ff8b5edbd6d54de4453f03349f4551cf1d013b4a29cf","0xa78445bbf86810a7c0e5622eb18849efcdd6f8f0c05db7c4db8d1040be01747f","0x31bc5fa16ad95f32fd51744802aad75aaf004a5989a54dd9b09508284d3e6a80","0x0b3eae30533ef3d7f567fafb394ac66133df4423ee5dca71c2c99f8de58d76cb","0x7991298bf451e42c7f5d7275d8107a68878869774f2cf3f1c4fbae4c568c220a","0x26f6a154defec005b882dbfa78211035d2f0ba7d62ff3d121f1f6a3f3d639939","0xbd2000943537698faf5e243eacd74212ff5acde55024289002fcb8c954d560a8","0xf3e0356b0b68761859bbc1d5eefac130a3b4a2e002e2cfb4f21be52d62506964","0x9d0700a6782f080a23245eb533c69b673efa95701a5b025729e9e56e1c8e3b48","0x3bd622584c5c945cb67edf403578a52f3ca3df329cb8a561f914a77f5936c3d8","0x6f87d2dead4c8e3a4018c605b7123d133689b7c454e2b864309d49382f4c7a33","0xc4e75de596fbcb22d28e16fb547ea741338ae1ef44085a5b742d28361282103a","0x87046fe264a1587caa3b706f9931e0fcc7a685a2c8410c3416e6bddb1726ec35","0x178d8b82f40bf08e78b01a42ee9bfc607278628a8a82fdfda240d86f08fafab7","0x14e62a0ccc9588be4152ba5ccbd355a67477d77dd9fb6c5ac5c5b317084f9abb","0xc540835528cdf58d5a44c63e33c7e1e6cefadd6f39cc892eda44da31bdc84426","0xa31e93e3205ee2a450e2f5829441bdecd91a45f5bd6c2a27c81e35a66157ac25","0x81320b13ea19ca902827d8b55891f7e0368f52de724e9bd9ae240785673cd9bf","0x49f7baf15effa6c2355182c1644ae0a7887b957dd5ebe08dd3556bd3051a02e8","0x21543fbe53921ed9faeb49818ff8a388d7931864c4b066babc4fa9e749a8ecee","0x20e14db79d546400bcbcfb4320d02a02b7d4840613785a858c17b447a53b3a88","0x7cc92cacabe2c1dae7b9b8e7ae1cd29bfe3f92f5485d5ee8a0742a91770b41f8","0xf1437b7f7809bc2cfa1ce3fb8eb8f2f9b8e4539af0a07010af1cfe021693e542","0x16e99cbdb6d89f9fafb26011b4ee5b415897204cc5d721c425c1614eef108df4","0xf9e9ce1f28d47fb692fdd07121aee150b353cb2aadc6e71baa0ea93d6c839c26","0x6db57ad98e5ad3a9a748c063d46ef89cd791d00b80bab1ff8013b2b791b98554","0xbd834b6c9ecd45872ee36dcb1c14ec86816739c8595ac1a01eb18982854a7620","0x29e3d3cf900a550c5f4ed3d9eb24eea9dcc6951dc83c0d0c79a37c79e5fc6fc9","0x20aec6bc2ac2fc666113b3ff25e12156dc40cc83d3c1424171d95b465ec758de","0xd9cd661fe0de26c64d832cdb41199ca4edc01fc9c4f359e02bb43ab42d0659f5","0xc5e85ed4b1af7aa4c64ebf66e9b362e7025517b66f012f4a366fb616b894ebcf","0x2fb8e762526a638b9e4ead2583b99c2790bd1197495a60a56696be444a22e823","0x1119b6db828c003051a4fba99b28adfc0073e82484fa1f81ded87d1f90929b35","0xd2b010cc5ad43184a5bb37d692ab3d28dc643cd558a7dcccd63a3c42e3d65cd5","0xd71c348a655651013873e8c1efa1516317094dcad24dc0ddc98d6503f43ede01","0x618851c3d51b199f6ebd29c7ea07570e0ed3ba9899e714c1f85a548349ff537f","0x9add1abe342d3f0d468020ae4b7bfbbc8e204a8d730bc16ea711d3b8afbf30df","0x0cdcec1c7558f1be30d09e69c47465411f60c9b998c87bbd968a138b9b60b958","0x0230cf6fe46021ae2984dc883136209358ed898a07731a04711045b8c61297d3"],"blockReceiptsHashes":["0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb7a8b41873decb21c12b636229187b289cef4e30d61bf9117fbd23ef4928652c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0754c161f5610e38042f317761b6ef9da5d2df33d1038dba06aad7e827d91c1e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xae4bca935757ac898b51973cffb912d1c05e6beacdbcb13b3849f3206d18b393","0x64378f2a848a060aefe81e7dda01fd82d0e2cae5da5b7b3ca841274043c7dbe3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe1859226b64c84d5905a7a80c86f2e5966771f48ed98f7ed1348825d76c3a4b3","0xc123a2ac05a62f40258793b2d82f185d2670ef59e55e76b595363b25f9fca060","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x56ba98f07a4e996ca2b367a6515470049becd547590341cf23bf3241fdacecd3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1949405d087973075bf20af12c19a9f4109b502b37fb2906d44f8c8f060667e0","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x30fc60b148a15a3ca57c371ca8254cbe4882b89ac882efcd2e66829c2a777301","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa362596a676512794b4489b78ac314a9f617dbe2927478713f85b3d5b442b877","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xcacb29c2024170b5a390b43c63dfb996a0e4ce6b59d519b5d6cca4b6b67e10bf","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf50f1ce200c5f1f5cfed15128d3280ea8a88ef6b068391964e7c6eb44b0b95c0","0xd3260ad6ab5b0aeb7f8ddf38e74638a1f6032da8ff2653dca23faa976a18855b","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x9b82c10a110352afeba39ac7e49d9ca62138c82ba0b87da7783fb6d7703748f2","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x70d4411252838bb09a0071a4b2dd47a2d5877c66590d75d9c663d6b1fc8be531","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xce398a799b8328202a8cd9d1ebf4074c3790654f1216bd3fe99ed42a38d6c72f","0x3cc1f5c8bb6530d63ffa77a50a904b4fe82bed71f3a2a6526efb0e8df41a9dae","0x685d0794f3d1b9f6f22c59a974d86cfd65f01ebda3c9bbac6f652cf7ac494b26","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcaec0a747bf0b9c4bad05ca24220c469c5d9473b5f98dcda9b5db9c370463f","0xea88b895e5af5d3b82a19a1684347e32365c220c154870dcab7229ad80b44322","0x2f45ac1781eec5818f28166862a46d9935158643af04bdd82408d442082546b3","0x0764ab562fd8af790540c84a970ba29080e09c04a5800ff6192762636b8d69ee","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xd1a9fabb56221b691860d0f770c4931c5c55f435c45edcda56494e45d941bed2","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0d60b8a1573cedb005f85b79631f838ae9c0653251cbd45b7583751a05e9a697","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x72f71136e23136c1fa1f9a440bb91f5b30b5cab3cf8f308bca807b3c185c1eb6","0xc27aea76b5814ed132cc58e4634afd51eef8318761ae94c78af7fadcc440c9b8","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4e648a342b676f8c46375daf30eee1941115efa64f6b9ebaf70b7e792c09683e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6ce6607583c26cacbe077ff74df36d4a959f2b3b8e89a071532905c9f2b54ae9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe30632ba24e74fdd9a5841db14330a81c785976af1fcb6fe5fd1d5f99c2c3aa6","0x1cb7ad496aa0e671c7d593068acc63116f271d9192218746791cb9b7b1b129b1","0x34604bcb9b5cac425654e078057395ee8ceea80102a7b7b24d3d43c8a37f1811","0xda219a53f6c62094bbe1c47fde21e1d75fd57ab75fafd8f8cd5c4d33f395ff29","0x37ef612248d8552c87d1389e5208fe5eb5d2991361668e0f035dc678eac6d8bd","0x8acafbecaf42496ada336e789100031e4505af0dad0032c5dd89226bdb5ebb15","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xded7f76a5ebcac1a1863eea11f1c7229be71301481f64edc91c57bb051d126d8","0x55afe68f17828a552dfc6159b8d1d60248b62294dbd6eb14bda03faffae323d6","0x81c3f9593457d442a77004f30f66b67c781ef3b7f5f516c72a96124dca5a3834","0xc3e2b52b08908a3da6679964f42a0acca9909ecf48bb503c39f3603e022fbb63","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x15fc47431c297565bdd18c7d3efaf6e82a5483c814f6cfb9ff4910ea8abdd7a6","0xf42970d21227ef4e12a5bdc9d6ce9fe20ab305632acc0832f1b61758409ce29c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6949739a78a4c354a8ea10084d21c1b369034c810d08949537517114f749fac4","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xca3e015b42a8502272ac15e778e5cb563875e4af15c4db13d4cf5c98b3227058","0x83cc291e240220943d3c8e80cf45d41cd28339ec0eba29bcad123e119bde8f13","0x310a95e1df94a86ced3580cc7529bee3b3746b30499b102a1bc6e3979caf7bef","0x39bf73ac949d703301817a45cf82aba9efbb116adb83ac695ed5425b64448912","0xa5c740318a8648412ea04fcb87d49fad4fc5159c86efb0ded02bf9a22ffc0783","0xbee113d2d6c8f9b24eb82044ac9348dc6f7640dd9a3459c5cf5b31323783b77e","0x925f322b59a477bf8819fb6382ded0cafcf7257f1366e3aed39773b586d7d37f","0x9d2962a6ec4b0bb6f2d1b26fdcc77506cefb6101cebf8f67003cef16b1cc920c","0x9460cffb5cf0206b026763a06fd23ba00f7b3ae3739e9bade8e4513280b64d7c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x65c5987e3b5fd8ce1afb61c45346f9996f71967de4af3f3086500f0a066d314a","0x1b91ab9d18f2c401640fa178855ca8fb97a868f56e15e3e2d2965ffdc65a487c","0xdd9a2cc715c94705b3c3e1c1ca368025023658f91935e44524ab16379614382b","0x18d28d773f7899920342d7bbba169c295eb1d27c805674629067fed04697bc6d","0x0a0c3ded28e9c441547045c881252a935ed60fdff9b72d0b46629f56d1748617","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x5ceed970a573ad47b1453a1263ddea44b432d068721d1d60ac4fdd5ae9377742","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x48642a5bb412c27bc80ef736d43268da73415c47dcf02e1080898b7e8c2bcea8","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x17a49a3897d5c1c6c7a50b951abdd1cddab83b77b33a176a365fdd724d8ba3f0","0x16aa7ff562bc69b2a13c95ec000c98dfec2cbeb66a63220ef84c8df48348dfaf","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x436b51ea4c875be7f093ddfa808eea1d1bebfb31979f8a86e4c6f5aa63dec7c4","0x1bef6198b145c84569a37891376b35f9f22c50ad413f9215d4b4df0783b7e5d0","0x18165bcae2c819b24d95ca9c4023703b25a718ceb487972ae864a39560eba478","0x4d5cb325142482a376a59b16c68951fe646391490b0db818668dcd7972e4b9d5","0x2eadce6c19449a59bda5dd5b525de79a8adab1ded3578a74aad72751cc8bdda1","0xca202729c83cb50058a227620663c497b05f33b96b73ea66033b7ccc617e53da","0x942a1814a61f8a0043a883fa1cdb53c50e2d8e9876d30a8f1e28d75689087f4c","0xc7a4e531ca68b574da29dc3b68a92cf645882791ed937ae3bbe4066644786929","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xdce7852295385d8f15af3803f68a943cfca15aece2da9a066533ccba1ca64c40","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1f77e249f269fa5e74e9db3d60bb065bdb1f863a85598037d6401a11b39546b9","0x14cfef5b80a73ee05faf6fd554f15ff5b0e13f93725530b6e4d1b720e69d64e3","0xba00384f54d9fec0b9fe7c915fdd088cd926984d03e5532340c1506cdbaf885c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x85e086a2ce0de231064e07b0218ed34228d040417af6f2b581a9607ea3f084f3","0xf1fe8703647b50b5b178944e9a8de1ff41c689f5ee41de6b0679bbed7cd7ff32","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x87e249982ed980fadf9035f5cd56cdef0b66ba03692981e48e6b6b43af47e799","0xe41cb623ecf13fc8d4049dcbe4247e35ddb9b55cd0665415e0d218cb59d067f7","0x54611e6faa683d6251fe19df4be75db2e22676e7f92c06088d955c2fc4962397","0x8ec205f51bc7fc1daee158ba8a373688de3e20c84316ee8f65a5dc96fe4db1e2","0x63d0959d120b87ae20de76a0beb996b9e4944d4db55d1de9d2102f37224f3492","0x3e7717a743b9e7459d059015c9a44364279ab592578f97277cac5ef87e22ad64","0x372839e0d5fad9ff606476047895c9450a160167ef4da744434aa4369aa6f6e2","0x661cc81d88c8bb5893270bdce152bb67d5d03d601556eb6e92d2e26c80ecffc8","0x94b26dee612ce051c5753d180478036c8caa811bc5c5277e07f34b33f78c99a3","0xd5423fd02f20ac5bcbaf77b548c2cd95fcf4ced49ec042d3a270db5ae73f8766","0x222eaba3e01cbbb4b23b43ad6bea242e5f814ac8ea3cd46f83198c6de585ffe8","0x58e92e4f1c391b39270d72d095b4ab496d212e0b04e3f336f63eec2ae5e746f3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x9747db5ef62b3e281f8f27a747f288eb0d7d17fbfd7f32de575036fb7099b22a","0xd470a4f07b1c7b81dbdfdcb0b3e8ee90f7c1587447832c8eb856ccba54fe18a5","0x4d7e00f9a305113e5bd81c724bd775cb6bf06768a4e322d2be20c99585e08ff0","0x704fed54a7a36b3f0e794a349692d40b275e2f6df0c8add9cf79bad0859bd04e","0x0e070e7c90d693135d6d6e2d26ee6dfde9e632dd7ae417d266931f915a30760d","0x119703e1e6b003819445eded53e6b4f9daf217938651f74265db28a33cd4e646","0x552ad7861620b80fcafd6e88598d004f4f429d4c325b889ca9732804f2892b43","0x68d5bafc3ec4b3cd8d8935164ddfd0de47c3c21db6490e0b99be875bcb6851af","0xdfe586f690b67036e6acf803dfb7879571d07b6fb685c8d9635c87a959c9f521","0x1372f7e3308672f58b666e23f3aa6b50bef8bc37d2fd1fab429c2ba2763c3ae7","0xf204b2d223dbacf94442165296767cc7e739ee144098547cf4cb022127bf29d6","0xa584b8484f4312f38d092b2c2334259adbcb984e1041cc29a8c6967fc289d22a","0xad3209274e88c93689cc38b383b2b4e82a9d376b004f34f2ee84ee8a2e411cba","0x0524ae1c3b0863b7215410d2289bb7af3c662ac706b5cd77e57f5810c1997588","0x97c25f90441f2d4a85109c3ba483bb2790a4e10e5fd6711cf57aa9c26faa1395","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x32e2cc88e68cbcde6082af246aa7fd3b7d46e72f537305c0961e0834f48994c2","0xba11d0ac91b57424f10cd2108762198f07fec3afa31723bba9a9a146211be751","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x9f16856b752f4c30784767a050e7ea6a7400c28f451f8e08142c66ddf65bbd98","0xe19d1ac0260380b5217517c8a51346dbb6bf478c7a76759da271fad5e031b259","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xc052f82a0665ab4bf337d309ef2bbdfe3b8be582c96d4f0a856e0ba779efb488","0xf32a6269dacaebfd833894c662248c32f8cf80a79b597a7f12a511ea174ce746","0xb6e1be0d5c8ee78a3eefce5c6026465b9c5c337d38d9cbdc05923a5028848aa4","0x2b1100a3131ed5202be95f1338c2a5faaf2debf973da8d8d03af28cae5caead5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3dd8ffb7a1693becc752acb23e9357341d153ff786bde107c15f573ebefa1a49","0xa82f506d59417e28e2f6c0ae2f00f6fffcd3aa2495ce826476b21352e65b196b","0x55c87b45f3713a97a1b92a770a7165a1bc1032dba2ddadfeb5b03d4af1ca5b04","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xc5a452640baa9e577b895d54d134c839016d985bcc05e2f9af265b9c5a57b660","0xdafb0147977a0bf74f0e2f6923b77968b6086eb0f357dbfb146e1e695c93faa5","0xf69b56ef15e631ec5240e392ed593740489d27aa484055e99ca6f04bbeebd109","0xf71b28bead43d7038652e5423bcf407630525825a38ffd4a90abe8df7ca38161","0xb8a6f7acf225856d310b8909e216934fabb351069c3408f41f36c90aecdf8c33","0x43937e92769f2844f44f90d9c620c4deac1def67adc63bfd392b217ceb9d2963","0x5e3340d91b86e23b96d6ebdc8eaf4bac1ddef0063b4144b3ee95a178f5c3422c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1361c2780c7332f47575f2b7e17a75b6a4a457b5dd0037697f9a77302dcf28cb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x407a76f8dee680796819905b0903dfc194cc54018b08d9d69a16badb75007b03","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x84096a473b9ebbb12eb2a948067ebedfd38acedb9c0d1d7b4c075def06022aa6","0x3350ef83c663e7d0d1a8bde920ab20bc4033e6076ffd0f0590fa046ccdfd5114","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0073e17dbdeb7800b3adce11a20a5e621b2587834f21825f8e767064d8a60cba","0xcc2739feed47689bef55f99f5d875646cd4019ecc2248be6af0dfaba3710b521","0xe53fc0f5396673fd13db83c30dd4e89a57809c7438315f3b85eac9ef19ea4cf7","0xf8379788e7aa54c1b83ea9aab542c8b8710fc64bc896b7adc8d7628b6c29ae9f","0x90de5dd44fb09fc4eacd94b4bb7b0703bd09f2d3d5b4ee007fe8e7edde011232","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe733b43b297ea19157b0ae11652a6827930fc532c9b6959aa8d6f9cd55934c24","0x5e38fe38a82814ea40ee81ff30eecb2ad01bd5d83e606c7ae418656099382b65","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb03cff9da6c3c2d21db3e92cbf24ecff56978dad93e1787b77b484555690f09e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6a71bf942f5acbd4f07c1a82e495498a9093db97148805ef53880eac521859ba","0xc3888eac0f4254e19098d3c8a7c1926b2257954bc7deae2e86f62fd46f2e5b15","0xa834c2c28f7ee201d58091b81614a1043fae7a14519c2d557d72347f48f03cd9","0x3c390f3c3dec7c3700287ed5d786592af360089e402fabd222afdd0b4f6715e8","0x6c6623d1c29d18b34bcd7cff66508eb226195a3ccaa7066abb14f911dc8c4a53","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe3b1ee5332d06cc94d11c89180c6da5740aa0d930d360bd5dabaf06759ee90e5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xbf6c0becddb5791373529b5d8c64d53eb0821c6c6d289d98effe5fbbbd383efe","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x692837a62017bab1c0cbc3870ef3d165cfbd0db5070f5aeef285f14a5edde050","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf5aa91853707bbced036bb1ae44ab6a14b68d184215c1a8cae4b13029e516fdd","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xbbaace2d19ec01e6a2ee01040a81ff410168fa5746a99c0b3d7c53473168315a","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x595284403a0a124b62131b369e9197392064323cb122e41445e9912297d0f84d","0xb3040790c5a64ccb0b30ce475db6fc30703d865fec7d182277ff9799cee5d3e0","0x59f227fa1f864194d129d580226e911a6ed7c857d8d6949f2358272fb3bc4e17","0x03fed081e2f599f328c91658dcacf894106be5d0aa2ed5486c7a316dc5bf3508","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x9b785dd253949f38b71c0d1c277ee6dd2e5e2c702bedbb132ff6adfe5aaef3ac","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x49dc12a1233cec6a94b729a47db86301422d4553e0ca53d730bd07b4f1b7236e","0x506d1a388c61a5cd13061a9a8cda3438373a4056a88e36e1ad6365e71553aa6f","0x971f92618c91510108b88c7b2cfe7a6178941b058d2cefec2d2402d9351c3e19","0x10c6ed40cb2394e11dbb70f3d78fc2b157b629ca33be43078e7767ff83cb3feb","0x9a2d6a57ef096648ba2910df920809a380b02b9fa1c3f188f2cae05c07b5108e","0x7e120e7aa940582dbdc7896dc08cbbbfc244b59cad14c58a5cc1bee43dd81246","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x992b7cf009be9bed5a0810721f0b5bdd084b085fc70e0618d0759cdd8a30e192","0x529ec5508e1e1730f8b0ad57388ea63586afc1f3f3f60f1e491957b7c56d5dd5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3e86c665482c602a5754bf950da23248da8d74400d8ecde12e686c3a8473f049","0xa3f2fa22ec5d6a2c72a048c9a9f6a34a72d41d9ae7c822fb36adbd86081e241c","0xfc576bbeeee567ce31be3cf0bba160f9dbfeacbf4cc335338e1d9eea864108a1","0xc2a546b67ea5348f8cd8b3b9fda4a32da7590c90efb2d27af277ef9db5dbef8d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x92fcb4ae950cc9bd1f447a50023efbc967763352adeea3592479a67df141b957","0x3d7ec7294b72ccce185e6647b9ff41453ee66a82d445cf0207c1018c9a1b26a2","0xf8e745ce8af43b900eae09802e4e03586c53c675fbcc28f84fe9681397fd84a4","0x4567ac1f50747e0861e08f3c64dd7ec7af5f322f666f8ec7b0b6572e8a991e79","0x2194a721d8c13df64765b60e51e9206f0172659c8a54edf4868ac7765641e5a6","0xd5a6942862fbd92322b921b7c4cc68ab06fc7a7e4a5b9faddda7edfb2b12391f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xaf883413b9d534a0ef089deb5f3075661c720d06e622b4f9fe735a27e1c9f882","0xa3f270b9e9c3a3649396959be004b2a562cf9aa19ca3194dfc1c7ec4698ca3eb","0x36d8ee452c8b85c6e3dc4fae6cf14315f8d5edf5af07474a8d0efb4a083a9e5e","0xed9b54f3283f9d39b96f4d7fb969051a93983d9daa436c47c2286b6325744dbe","0xd8ca487872d16922added2e58196d72b00b4cf454a74d056f5b0c36f51cc884e","0xeeed1b53d6e552579967751cf271da5edfc282422159c675030115229abb7a25","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x713aac332b98304403b9534e2604792e923a1923cb9955e4c244f9bff0348660","0xd7bcf8667c477bc082d45d5755cfbb6c03dd1707de553d55ee67d43cc386d8a1","0x112c6e92b4f1e83b2529a61958eb670bd151f12591033019528544554f989fd4","0xef8b2897aa5b112086bfe66642b50e3ed043cb480b73c98506e35c2299275679","0x6b1c07b61c91f8f90c684d72dfa77221ab7b71adfd4839c675c07367fe76ac8c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xaf38c67afdf0fb371a2e7885b47640e4a06afb02f2a2f9dbdbbacf9f3fcb365b","0xd206d0c116f3a9404c255e8a9d95096c2a5ad67d9f2bd281a5f6c1823dba21b6","0x439e41602bfd14d020ed77fce979d7af3ea9f36dc657e5810a45485c9a26f48f","0x10f8881823a1f24f05331f6980dc90b26e7f16bf5b6dad6cc78dc584b8b37ade","0x22fd9c625c18985cf711538e688f9fdf48e7341de0315c7275e15b9b4f6e9f45","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb1bbcae204204e6663beb17888a00b158af38ce7fc25721190e97a53d7d2fade","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xcf42fdd5be42a25f1858327ed7dc037690cd5886caacb1b50d0e8e085e731bf1","0x068a8df40e5617dcb8bdc7f3c2b05c4cf934e915585787cb6ca9deb246de894c","0xe3bfa15f3f43d899c399cf34956a331d6bb2c72861625d8d5e1cc7144905325e","0xe7dc1d5f19ee24876df9fffa721ea349ddc72053729a3e6c8907b2ef212bd507","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6a59f5e344a293a4f93f0c5819de486bedd685e85684c9155e545d09d5d8479d","0xff18be09310626c091e192506bb567cda4ade108fb0d526cdde336d11112204d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe5ad394504a0c04e3a1b393f90b0c4ceca301b881eb3ce72fefe21f31b2396a7","0x56648b2e3c1698aa00e66ec6cc9bd21bb1f7fd7e640e9f1eded405322563e769","0x46c6b7c26109a214838a5a5c374d2dd4db955db6c940c4a4feeca7e8abdad00d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf6b8ec5b6f97520dd9e5f365209276b0c824e300eef0a9fb09576eb74c7adf7a","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x540d4fce381957373368716201f13a71006e7a624a555e84aeb7828b79391722","0xcb991f3ed26951a2e202fa77450cd8dc13567c55c00a88293171b0af0f9aa8a3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x86ac66b7ff279338937e5424a2c1a508c87f004956cbb4be62e4961ed9a9a0a1","0x24c5698fc51aa54ea1705ec803f59fd02200970faad1a68ad1f37663d7d91f93","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe092b37712c8d32352baaff028b6726d5360b74ccb80d441edd4d3b5ae8e669c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x134bfe4847e658c98ec7542e6f9c21a333266bf11b9ee8ba4c5756cb85346ebd","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x097cf76e9ca984639dda484d9abb2dfdca67469f47b1fde71212cc93be7ce5bf","0xb383c864798c063b9f7bc6f63f44a0a9bf34313c807684cecf86915c5ca9d12f","0x676b51720af195571c5af827e1e6505a8cdda7f7fe3014da6fe5710e49821968","0x1ef2df87bd6b8e748cca0e94a57cae61691dfa9730d2b8930a8ae8a4ac85ad2e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2b989ed6faaa233d363fca55b6b2ec3faf247f37a018ca01575be17ee6985b1b","0xd7cfd5639b686a7047df395c95274a1e84b2c36326b30f1446552f32a1d7238a","0x4f611e4199d69ba1d126300fd4cf749b16762f8b4cf26493d7267cdcffde2407","0x4cc8317396cd055886f568588534d499be254bdf210b0ae4c6d8fa90be625b20","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x59521eddd1f1f7f683ae460ff654309146aca927a2013c4fccaffadfe0666d0f","0x6d334c2231685358a4d1439ab145dd0d28c13849fe92d2a1c2f720d1ed254da8","0x941689e8fbb27d5c145de0a5c2ba9806358e388a201fd75815d247ba98666ff1","0x661dfc176a046653b19af40ff0d5175861f0fc5a190b78244773cab6198efdd5","0xf5dc4fd9e509ac14380b0ed7e753348c87be29d3093754365536dfe1e4415735","0x78dc67012f34cd3e88335dbf1a03c6bf535ab0d9a72158f66510da1d2c7af1db","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf05bcd9c0b38e9dc6682846b44e8d283d60998b70762a360aa296d07f2f8ba1b","0x261f3bf76b65deb1d6d397193b0b58461d230f978085cec68608315cd9f1e082","0xe822b00f36641d1ea2f57819f304603666bbaaf30307b3f59faf1e76ce5c3cc1","0x0e6695735d022fefd32ffbf258a57ebd04c28c8ec0686fc3f834c756aeaf3c40","0x7286db868d80c4744158bb051cc03b3d757c16ed7ff76205c3febfa8859c99ae","0x0417e6cb111ece97c9d884f04b50d4db838d446c4aaafa162f586d2978289b7b","0x35c7e017a4768da1d29b85b584b87748f1798e36f63baf5b48d986629db3a8ab","0xc2f6718e407784c27b29660d9dc22db47136b1b61ee11682586a9d043ca50d12","0xbf4708f207a53a287876bfaec10337d12ff63b08b89dd4417887a42f5a673e11","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1081014daaeda22b4c8ee62edc6ddbcdeac5415a5ef930399ac1a9040f540396","0x860aaaf22f1d6044d97df3bab08fc3cd8771ba1f32a35bcb4b3314708bc1c9cd","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf339681f7360f99fee70253dd11c32dedf2786735d1687edf403f808f3b2313a","0x41cde1b9bb5b60bf21edf244069440227512bf1051d41b43beba380026684502","0x4774f9d9b4f79de312682638f5603dce69250fc6680fedcef489c4872307bf95","0x57e46e9066ce24db49f239dab006372dafd112dd3ccbc6bf80163a15bb9be2cd","0x7e1d21834e514a458699adf5ecab78291f71f889147c1320aeb80cb2092b8267","0xbe89dc4ec33249e90cadc27074400bb808353ba8c3174943647978600d2ca834","0x12bbc74109e856bcf2e580c8a5f7782a203cfe3b65ec2e4e5cb6fe9ede238da8","0x55835db46d146006e3393ad7546f9ecec5cd90bb7aeb6b90d845f4f3bfd1c17e","0x36aa76614547a5978bc1ca9657617a44bced319e709058d7aa3f65f24b1fe997","0xac115b82b923e000bab83698ffd50db62d8eee81d2ade80e49bcca9697c7eac7","0xaeb54d6ffbf458b2fb6738c3babc0c7c115ab7a54e8744b729612b25a55154e1","0xc35f303e6d1fd5581b5dabbb5abb86dae6baff7deb01ccecb5c06acf8d982b5e","0x231d0bcbb67db55b02aadbd5ff1692862314467a167b8ddcf66cc27990238aa0","0x3db0bd82891e64bae4ccb213fedeeaa9235362e3b2cb07406a5a420588845b89","0xde4727648f91fbed86dd9116f963ac71b220ee778cc78d8f184560bdd2764906","0xed88bced1b97a950e2fff26dac1d46c98a28b275460832efab74261524f8c5f3","0xb5fbee41f487d8d37d6e8512694e1dec93e28d70c6dcee4a323d401886bcce2a","0x67c786afb31e22c800823fe265b4d3585d012cd81ec2457813b91646d1124ccd","0x76a4bf696f9c1ce686c4d5f964a74855e6d626426330ddb6b8898315cc67f468","0xe15bf509b951deadd2c5bcf3ff0b04151195dfd413c1144e95e80c38210fefba","0xdbdd620b29124519c8542852dcfd51f75cad82e5d9321815be088735155342ec","0xe7343d6fa4217cfa7dd84c4aea52ed64c726a0ab1920e32bf0b40215b7b38fd1","0x82c5f6aac1660b72beff1983bea7aaa9fc42a52d4cc250465003d72b7c1dca66","0x1a7887a454e2589964fcec2a356f176d6326e1f7ba25985708b5c380c27f2c65","0xdc30460b5d0781114f1f141bc175f16a7d69419083e6c4dcc584714f46bf1a08","0xfc5ed4cf71f45d03374a65df9773a648fabd591d27f4c838c0e66fbb74bb9472","0xb5ed2228a7855926ca8c6d8b8ee873bbc3429d08d9b3cf5f31014002c3a22d45","0xc7f80f33a17994fa14c8eb4c1cfac3ed1c943dad618ee1a99f756501bbd02a12","0xbc892060cbc3f9175c1ba57dc46d562625ae271d3ec0d78e4f77fadedcf0db06","0x322855b7edcfc578215c9b5744de7bc0796c17becbefce5a9d242f6649e35a96","0x6f2f7fce4760c5ff2bdd5c146863d1948dd36031ad54640e659f543134241ab3","0x319f48b4282fdeca4d948c9c3eaadf7db2fdac42a863d403cd08a748e955bdb8","0x4f3c463c760bde9eb64c9baf0b2f797e4226a78b8442746941c9f585562ed490","0xb5337f0769411e66598b32bcbde33d0a13775558148c6f0f6a32837e5ff8e85b","0xc779ce56319af070c957ca47502f94b9dacaa4f519266bd81eec60906b50d260","0xdca4c5d95ca826b345491779df9e1355a83e1cc8419aeb487058cf7a17c6d8be","0xfc4a44b247e499380a1485522b907685b9fd34a9048978daf47519f25982985f","0x6ccc035ae78026fc8a79f793d2fb7cbad04dfadcebb2bf50a7920052d6d2cb04","0x830f5806b26d1b9fc6684bd12fac6fe016e5a140c84f0c6dddd219ab36d6fc2a","0x63ef129454ece654d2e2464f9f0844be69fa01fbf5322a10a65a9185f6e2ce9c","0x06aaf4ebed5b2f1bf5baafd7312b1402a1033f79ec7ac8ddb2e6b5a95e255627","0x7258244288c335639b2fce2ce2eea9e9a959b37eae4b839f06ff0ddd2f4d266b","0x267aadd11529a9335f4579adc6060473f96f3f5bd3265ec37dc2405b8ad6d7f3","0x0956c7d9c3cb7b108ee8a87a832f197601623d6ea4d1ec379787523cf178c0ca","0x5a184b7f46537b70f7a90286c7feb7db286c85a2d1dbb0602835a557c2fbb56b","0x0022126f8ec1aa3dc334e80ce3d0a39ac7f13ce6771ef604c6226e9cb7875b7d","0x38581fda1fa2fa4d386ba87155a296c525570db98a17c4e1ea4d439b45bc447d","0x301f5e8e95827ad8338a8dd768e4e072bd8fcd64f797839646af04e784a4fa78","0xaba5e81f9327aac67a3a2b850770fbceeeb2d319a58bc97c53d163b702bd7ddc","0xe469ae7b0a8bf4ef668158598b338e7a41456dde223e3898b8a9f45fc297f023","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf37674bd8b6bb7e0ef80d8bb064f89c57915ae50cc6a0e300555c2992e725db7","0x6c67695d769eb80fd6c508b8eabac922044093fccdec8aeffd2e8a0ecd4facbb","0x33510ee8c5644fed5b2af89ce068aac899e3e177166434bed9d72f98a7e64ba5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3618332d45265977f42bccb8cf912b57ac1bfdd1743b4451176d0d93081b98b2","0x546036a205ab50269c857ec690643b70c805a2ae5d75c96467eba372d6696025","0x056076864c5475b0384db87f9e5dfc424e1ff8f2a143defad526d73217de3352","0x7ebd0e6d382c99664eaa1f8d3a0530abb438a9176e1dae5862f05c4ee8d12702","0x05f9e2a0f28ecf6565162847e37e94e256bce4a20f6893db971a63ef4b56345d","0x77f0961145f3c23601dcf50fb156db6b5b444413944e82f37805462cc9de3f85","0xc4607c176771b7cbcb86bca4dbf4790b2e3883cd326b7fa3ab7160b1a3d487c7","0xdfc8d97ad0aa980895ddb053ec683fc0b89efe944003785d92e75aba4b9fae65","0x66c5153da55477c74b849efb70d1443720a9d554f9d3c307767714474754fb5f","0x3bddaeb454dbe2723d2f911b25e7bc981f7f4891a20169594028e29bb64d947b","0xb4327acac6bdcab6f894aaf3a56e8df00fcd0f55572eb2ee943b281f9aa7c5fe","0xa7493c16dc2bc9e04a652cc7307b7c49e94fc6d61324d68e03512d68369559bd","0xa2be1d44228623cd2a35f5b5d433ccff8d8d9bca9026d01780c6ea38ee15ef4a","0xbafb4bf6d7aec28a96818aca5d8e00bded42e523c818a05d27a6ca49dff86a97","0xe8851b34e88a3360a9fe9769572d0459fdf6600a1d8ba4eb329d2a64d72c7f04","0x97d70e8460a07ced3ac0d84e760a972725a049e4b33d67df2733f43ba6871188","0x399641a7078ba850d4775075487c593051cb5e8d70a0a023fb7022f13064316f","0xd5dd67392257c91843e3dca2ec11c51f25e219d84d51b8f5e82de4e2f38c9a52","0x3dcafe701b9579258c0bbbc4a34fc5df441aa5da24d522c2a0cb64d7b2906345","0x0965018552010afae284564cddc7685101a07c00ffd7184bcc3aa84888e91399","0x0dbcef964031167c71010bf4fcd7cac53533d44d9935a0deb4343fa0cc868aa9","0xd87d8ffca2e514fcd3d3eca4fae4a075c3cda1ff544ef3dbe7fe25cafbf1fbb1","0x51a0a9cd874f4f71d5049ba1770f72bc1f4eb0f745b745a3bb81845e056b1825","0xf236f255ddcc1d3becb640da80fdc15dbbddf30dff6392f28249c1100d6a5c43","0x839b0557628305805792f4c3d773e2430a78a1e443eb9f079bcee58c85087b2e","0x74dcf9a342c31c39b4588c2defe9130a250c667c3ac8d96f4625cd5a1c67000b","0x3206d989152b63cd3adde25c56f0fb419ebdf4fe416c92d777d3dc5f02853729","0x166d3e8a89b1dc5bb797f801b2a29ef3c91bdc5dcf05a0d78f7167534cc7bd7d","0x8344328ff94f5f761ea26e44357327eef0e426795144c289a3c87c15f8dc57b5","0xfab35c867a470ea969a6772cb13c14cf800f487e51f086b7aaa39ce2f0797c09","0xf3217905a73d8a4224be4808cbf6077818a021199daf61e02b299bd576c19766","0x5eb740ecab5e073f7a34e7f1379adf015ee8d62f48cd7d2210d5f69e5de1bc08","0xbd3d82a75fed5ee656dabb9089b7d8d60a754fefc5e149be5c16d5fed3163828","0x161dcbc86c5271f935917bfcb0a2c43a0bc4e0e76e75a77050365e1186758973","0xcce7c1dbe004ddc86355377fe21cb9ab0af999a9f619e7e324a85c02f73117dd","0xbcf889e206d621d2bd543769c841b0271e2fd396113fd31b6141cbd79390ac1f","0x7ea3d8ef03421acfb63fc492694ff2209edd44adc3b262c5fc27a26de684cb87","0xeb4205b0da049270c647a97075b864ba84541305735c4f26fd2c0f7baddc3b2a","0x40b28f1ca0768bc189a3af479c70ff4a405f384535454fcc41491bab3ae15b16","0xa67a666d203f5e55f44782cde2ad3f19a5095066dc9bbf5d11d6b5f6f842254d","0x48fe9b8b6441e9ec2d1a16192f126a11df12d7b634a99d06f9423facc5aa57d6","0x05161e61ef15fd673b58a90d08d13146c855fd1ebe138b437fd52d571c26ebb4","0x9337d48c4e902fee2de295d6cb0e2c726dbc7509a752366c5452547d865cb2f6","0xe3b0574fbf7e94594e88902435d0d331d2fea856c862130d8c4ea34cb047b299","0x2e74e23745d26fabbad5bc837f0c5451464d90d9c9b35ccdbf887d5543998042","0x10165334e56e257df026f1f25c2670871f30e5daf4e2d55c8148b9b1e28fe6dc","0x0967649d70b271caef1cad80365556291a612a0122b44edd0389a0036d870021","0x9e83ef263ce9de94e5888725194ba0f3727777fe8d36de6829fb48ee43168bcd","0x9e29e3901ff5ac205d753a58087cea7d25c58f39579cf0376bd304278d57b6f4","0x32532377fecdfaeaa09e1e314b3aab0b4d3564baaccc5cfef9d8e84dfb434d56","0xa81622ebc5fb9c236c180de445b2e9f03f47d3196b47fd517a69488c161c15a3","0xae67ec90cb374472bedcadb5911bd80ae1f4d0d220c65a92a082fb1b9fa73cae","0xd6cc7cc2b881b0590b1e0c9ac73f54a8f70e552666cd548f00c61a003b7bbc8c","0xb19cabc316bef6fcb10c1e8c882a0f0b603f8751f839aee46956f18a45f664da","0x7fa5c2d5d4f317f79ac97206d1e42eabc96622062bc96d5fa03e93e0268bb873","0xe3b53938494222ee8b2b9938e73a35ee79e603d8932b3910113b5747e06a9e56","0x96e7757521cd3fbea19ba4dc2afc67b2362bdb678d212cdad086cdc7331c948a","0x5aa021b60bdd1c85246f9608afc014f0a80fafa5601cb803f9c235f4c0d79231","0x264d23bd17fcc551f6d0d26d77834bde243f1d1b11d54ad43bd95d82585b5691","0x2a444da1b0dcc0fc4cd7f677d5e1778732d3a0dbad791dabbd556bdbba2e563b","0x3f9bfe3468f7dbd456bdd7dc02fd455766a26a01f09aa4845732c0c0e1d7472e","0xc873d28298bd995862a7b073976b9ab684fcb7f1cb30c97c33d4a8172028bd7b","0xdaea27163de310ab1522d32e0b9e8cbd7678537d0ef64c4141db703846ab24ac","0xaa41fcb6b482f7501ba0db786c3686e20448c195744abb93db6ac5fc884e5a54","0xcc2194b30e946db37440464b6ddd823b99f2c6271c83e900978fbb47b3172f31","0xc0422ac4398b74810ea04a8fbe6cae4df3d6b785d137f873a1ff9618012cff4b","0x3807dfe786bfe789beeec5c9ff571c74dd43aa7c992e5c37bf2af21e83c756b0","0xc7213749ce6fac4b08dfbaf8c82912defc952d8e2feb7fb288fad99639b0535c","0xc32e3340fad46f6439dedc8f8033889ceddeae4c088a49ac155af84e9aa198c3","0xce2287a0467ec92bdac8588c3738233fd5acf858a78dfee27dc07a41937a5e94","0x01c0a7ae259026b1828a41f6f7ed0b61195fdde85bb23779b6eb940a760dbcd3","0x9cae979755d9011768a663ef01a886fa6a1a85c77d0cc0217f6344508916bdef","0x03b18229076e2d6ea4869f35a5a773fef216928f403988476a2a4921bace491f","0x2fd47e2ed89839bf45e3dc4aedb83e2e07efa7ee611c0d5ac69b4c0f73e8457b","0x635e499335c8527b036437caa36dd0fb4c40a99993ed170820d2fffc41fb7e4c","0xd0b1c5b92779ae0a22921697d1f850b004b2b89fdf3fa43b3de8c5c572aa21b1","0x2b701ac13e0f952e5923185fae43f49dcc817865aa0034f9b8e4fae6c417bdf0","0x411ae32799117c0119adc3af394bcc20f97bbf6fe8ef5a55e0ce2b3ed60c656e","0xac5765fef59770936e20dc4edc549a75bdc37cc4d6bb89a0e2366f23448a9ff4","0x3fb0e1dc86dca0688e331f4802b227cf3c45ad2082ff759c514af04a7598540e","0xa664b1329e7410222a705f0abb297d207049dc8c78d472a619b356e42539c4d8","0x37fa5596e7853adc469f57346107e4517569f014318ae8de3b2df3789a18d59f","0x6dbccb8c132c105439fcdfaa1d11959f0e8e444127375e2809d637fffb14e3da","0x15abf5b895819d7485f5f676b2ac88aaa6cba63a4506f5278933ff906160e204","0x3f77beef111a5fadb8ce20a8832f28a5b503e56338d182341b4c0335179974ae","0x4b4e0e7b928421b27213be6c16e6d6dfa4b189a5bf823aabf2637e589bf1671d","0x1ab348df1b64ea6ac6e05229a0735936d6231664ddb456a47268bf86a6133f38","0x879019a2c037cc102b8f96c003f2960006d94be639bbec75783e7ab68e7d185e","0x300faaa1553da3e6ba2899c8e0378375f82545ea3deff9ed08f1168a6f60465c","0xcc8f1caf0e5f09a9dffb7302245a452fa2b90feb0f3b877fe7d11be918aec7e5","0x8d821fdfc47e14bdc9558e563d03fbcd0503abd0fcac97ad59ee864b15fa39b0","0x82f1a87216f8f064cf7ef956e6dc02399a5a6638e3aaa174a2b71c924affb39e","0x53d3dc1e279b07af27b1abf74bace7e13a8403daa58a2200e8efaf893dbfc5b8","0x27e98c8a1dffb22e61a674a0acc57a7eaa66339eb4e6ef9f50f0bd6e2a947e0e","0xda6732068f3867b392927ece242ada2aad44c953b5ca8e0e2b9f844bc1fab38f","0x8079c507c389bd5d6b20c84083d4393918daf1312561c9d3f7aef3d54eca9ca2","0x31a3cb9ab0a7cbe709fcc7f916c729349b43fe499ca349141dd09648d978c941","0xd03203f902855890f4f81d44399724c20123a1c3596fa9ef8b0cc31fcae2bd3d","0xb7a84ecadee30239769776d1d1d20cb90f49b57d87536deba18ae2a23d7e1461","0x5b960ab8a0c464c15bdae244916cc570dd8535780ca1a8f6a25abc4c1e5a07e6","0x1d4addc1e0b40a46081bf775450d254857589e534430b76c1f66924edcec5292","0xcf239ee191a3297b477df5f2f58f8a922078b73c638290854baeedf4019f90ab","0xb8c2c6ee0357cddc33cb19d93f432a0308737956ae2ad495f5dbcba814fc7cf9","0xb441c5c38ae4cbf63412aefb7d6b43c2503889497950087ddf3366995bd9e776","0x8cad12904d4df7db783b0d2c81fe3cffbc3378787b678fdde57153f8d48aa600","0x54ea1f74bd7c8d504a81e31867b1ee829199399935f4c8589f701445ac7314cb","0x44110820bac7d94d3d8f602541d897f0772c55d1705ccbfa2654a8e6bf6d011c","0x4c96d310e057b0ca453c4d1d300a0c796419fa6499fc0307d2a60ab9430915e2","0x36b157775c3d5af600adad5e2a09c7c6af13a1bc10d54d506c3450168620a178","0x4e9b336d96d99a77aeaa0aa23676bac4b856ce7d164bc4e50f1f28e880329a07","0xf5cf6b25cad38539dedd1b47ae860498853e7fc48f160e900c62e7f41aa38c56","0x58e2a4bd0cdcac5d888733f4dc7096b02ab99e4c1de1bc8e8e2dba5ad2c9e0f2","0x30ecf52578cba99721473b3ef4b300a588e6ce1692fc619eaf0ca41538082976","0x64be7f007bb113c3e6638ffd1d1f997b56e4e6fe66997398010e71bc45798531","0x1fb0ea7223d2cbdc2cfc7c6c3548f0aab49d40b0cbd1fe9b1d72c4652a7e9fd5","0x7b07aac49f3990f03e41a8e8ea2de96cba65f247a7a88ddc9b534e46fdb0e01a","0x2fd331fa589a2da6254521c03d710c393a81335fdcf4259e3c7fce69ac20dcfc","0x02dd616eba198faa2cd6633213a0008689fa833053db3c1e620c92d2b704fd5a","0x27ab64d0e6eb12a53d5c5a7ac0a01d2ea3fe2713c01e30969be2d96dd9408200","0x1e174d7a81356dc4a37febf5d7f4241624a4d47d551c8fc619d7d33d7b2f5199","0x4d6ca5e8919f83571c44ab2cd3f1e4daaa1c8f936ddefad0fb4a1c5108a1486e","0xef48048a7284173ee12d8d58c5fa0e7c27d96bdc3a02c4f9064beff61d342b26","0xee8ab10fa4cd1052fd58047abf6c6f99f0529355b1f4efa988c0056f6064db27","0x129ada99544b1b374ae4efc5fd5b4e87c517225db04096690aeb48131c90e8b2","0xdb7930ed8442666dee366c9252c45e3c826c94d1b622fad548d6673d6079707c","0x6ec0afce47cd7881c879f7a0401470f10a922d9568e92259d223a6992237a863","0x5366a1d24a78922483b0316c0ab708f4774d707831a03b15b49c1c258f7db6dc","0x6b444cf0066112a59a682dc1535f7267160ed92d75210b3b789f2edf62418138","0x0fb989e0a12d4f125a2f94f1adc653025ab9a3124588fc8b1e2cef256d0fd6ec","0x09d2b70d872f8919fae6e580b6cddea9bc1d320bf6a2ba013e6c846783d32fa9","0xeaa3e4b36401b820703f1540fcfd40409efcf4c1478c6fbfedc733697742f9e0","0xa7625adbce0f315c015c44e3e0a03197cad0e5217457327cb847fb22791b02ce","0x3dc693734a6d311b2d4ca880b08dd774b33ac4fd23bfbe2dfefab6dffd642313","0x430c491191fec63ca1ebcf31d18d8c921959cc56588731ec66a2842e3b41ca93","0x97d3b49af96ab900a4675806f627454203f9bfb3de611d9ef38a762a7208a4da","0x7a41a10ed26ac93fc1f1294dd1bab78d7d764e3d6d2adcef256485523f1cbae8","0x5b993b1e659f7551531af68299a1e084a448335cdc46c6d9db3845c9b7a2bcdb","0x21b66030fd6ffd0c06ccd58eb055330f23eeb0bea2eeb50a4c5ccb735e66b4d9","0x43f497bd6407ca4ecc5e661b6d871b7f7f4c2ea8c518031159a1fbca87759192","0x73f99b9896ca632123cccf869b49a6ce5c002d26a2443b86fd501648ecca620f","0xb615acdb450725500fc94f42abf9692e9a969365cf34c135e3738c39f98acaad","0xa0a75a1d11f971c0cd9ba7306472191cd1198d15cdaa735e7aa8d8e73d989240","0x0beda423b6a5894539068837cce23b9f6a69273cd2b4551cfacc2dfd6c3742ee","0x9bf515aa436e39f0bf8654f825220636612146ffbbe2f89db954d357d20338c3","0x1a3383f388b6ae80902738a8a405ef8990d0a4a3402d7a4bdf0f52db084c7dce","0x2e6ce617e59fae2494beef70287f3f0a7f7079cb50493a0867437cead6223e73","0xcf9dea513dd2d1d6cf7073163a5d93fb6ce50a888b63e875d6ea7cbeee6d4bee","0x834bfb469d2b1c7f4d16a3f1508454e740b183d8b2c13a6e1cb38a08a6dacd31","0x883d682728aa36b35e5d461119abd83eae7f60dc68707a773e0d06e50a6d1d79","0x0476198ee97f4812770ae3d3412612c1a0c173a8f50292365641dd983eac242d","0x4ab91c80f6773a4c9e580d4b26192feca9423684d2153b503876e7f010199aa8","0x96aac3afa17154fda353f140d069ef66ffe253fc185144a567864acf076a3007","0xf15098248383c7006e0310817a4cbca1248d1dc673665c66faea6f922238a338","0x06bf21bf6b31091e7fcb431761d9b1fa49cac2206324655bbfaba15642daff0f","0x2e94a08e2b0ee51c0581ec048733bde849a7b1940d3cea8027c2ef170e660757","0x0770110f0b8b21a479abe3da53f442bd90a791c07317cecc13859eec9a099884","0x51232d4cc24d11989e566d02d1f1c4b8580cc3195d765974cad50a4164df61fb","0x9ed1336053809f4d48b442fc109be21133171673d3da6ef262e94f47190e68d4","0x2a668ed6cb89712c5f207c5e7e0d8b527a0a443585105872a7670cc193ca3b77","0x05ec9d25222966738decb79bfb0776993c11e38f0b1acac0e33adeb21d807d49","0x2569a905e769d09e8a1725213168569001a0409cfc692e1c0a292c1f28c360a7","0x32b31f5735c5a41a4cc54bbda92ffd1d73d0f4e427a9554a9d2bd16c17ab8ed1","0xc792382c57d34dc3897fddf52e3e5a7d5135a51e7650dc9c2627f58b70715ab3","0x87e7bdd9e5d2b891ccd997de84341d374f4046b353667d5bf597d0cf2814e84e","0xf61d55071cb63922fc947977b03a72916ebe5ba5ef20b4e918be2ada2de4d00c","0xa8aa58d40ec8c015e955d8423bc000f76a04fb8bb352d8e80841147eb1d85f46","0xd8dc61c820c30ccd855292da616e7cf4860b5ffab840ef4f43115bcc1761245a","0x17d9b9e64f28cbaefe1a9a2c80e1e44c24556e3cf67cc5d6784bdc570cb82863","0x9a2adfc7715d28751712186567b4bf82c3f599f95ab24686a59272192ad72afd","0x40724765c40cd7053b0dc2fbbb6916b0969bae5b7e8f826a694886f45d55d387","0x8df3a8dda430a844d8676688107e73bfda9c5d2af7a118d292e1f163e75b9dfe","0x97cc43b56ef44217f4208510ec8fcdacfa2a50becf9c9c488039b644b22d5eaa","0xdac109477a27863b6fdc250689e47803949272290256a53b88af659b513e17d4","0x92e3e9cc6da630220228c309bb75673c25901c67f3acd13ed340f19b52b15875","0xacd71cbe36c541e49d640bf4807ad4dbb7cbc34ef6b3d5eedc8a90873579c14c","0x9f6cf37c960d59aa8779bb7acdd0b0665d4ad8d5963c64bdb020d8cfe67b905e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x39e4d07715a3ba427ca0041b35c4d44c6f9fba2ff99011f67e23751493102523","0xedfd773b889b82d1cc53116f07649efbc61cbcf68ef82556821be6558a573861","0xfffe6f92583ef21c756370e7cd2126e6e226ce7728f30f585e1c171e42e827b4","0xea8c886d074af11dd5f915e9262db27bec57c5060286c672e1111211e6e30892","0xa027c08f74ad968c6d001f095243e40622a62c4453b96f8bec4d76d1717618b6","0x351d2cf4a13fc6c3e0112a2d842e8b723841c1cf2ac7ac6a5afe129cad3969fb","0x8fd86e17508aab4541a8a9b83dbca8be9d1ab2006cb18be71fb22f34628a4239","0xcbdbecd7d9040da068629f27ddc71fcb0b932dea191dd209ece8ac9e638089e6","0x6ffdf2139c5ca454249bc15acfa488db44464f5482c7603264c6eea03dbc608f","0x41d7f1b09e2f6f9d260e5e94cc565bda988ead0eaf48062c1d34f611f9295fdf","0x7e62cb58165b7cfd26f1ad086e8e585f0d4383a0b75c5f2f3036686a6f51f36c","0xc394b2bc8888fe802f260e3bf1f237380f95d75a9df920294ab136be30390712","0xc0d44e527bd77451706484ef82c944b67b2a2f518688c35c3cdd56e5447b6f4c","0xcab402323bb078bb5a05f88afc8882053c31c0f973af87158e1d0680b254e9bd","0xb61989ae5a3f7cc31b91c840833a0b92c9bead28ceb830f594146f08d20e34c7","0xad0af96a100218e9703f7de4b5b8452304fedcaa9390903d106125a1772195be","0x183b7323dbc5b687ee6c72bfd81dcf0d3fcdc0bce42c9b00f63c15daf315fa05","0x87089b383425a0927d17736a6efe675505e54fd18fe558c92bef09fd5f6c1750","0xa63e57ced4badca232f86798e21556002ac075a4667c93f35f54f1f70a6614d9","0x7d39bb73e2d7e59257bccb34bc2940fc3155e1cb2775ccbed5c1d7d9d1100f31","0x0a72cc44353cd071f6d3a838adb98365597fb90654128e548679ecfd526028ca","0x65b755c5e9d6969fa2be17f2bffb034405a848e79260b1a7d39bc47971571102","0x62774cdbd424a47eb7a5f6544798d7262815c45c99775f0489ebdca121b7b622","0x4266bd66745ff2f942d226f9a90419a1d5fc5fd3acf9612dd09d92ce586b7f6f","0xdceb6e37ab5fbd4465bc34c24aaa5ff5e076fb69f8a626635d9b57e2477bd855","0x13112ff0f170aeca866d2cd31da20779d0a894ecf975051709d7bcf7609cbb83","0x43de270681a03742d96f37e1ef86cb7726acd57700fc94d102409c86d1380b85","0x9b4a698211958c6ba01bb9cb256643de742162914cb71c5741d4a87d7ef41c76","0x86afdd8916463ac766e746e26c125faa56f1118f4225d6d88c759f968266d960","0xa191f95f0afaf9dc5b8cf76325b2de5d5a2a7fb561caa097c675f8dc3b69833c","0x38f4f86597a58ae7e0f9a9c92c0b9f399092637ab5afd1801ffa14f1132ccfd1","0xbcb763601a8bc4e30262d86cda205746c0b61126ca64188b9a16091f0ef6b088","0x4d2ea500efe67c9880dcd4f8b4da0ce93c8d4ea10055e20a3d8af6da57143edf","0xca51e70744a9be1d62a71157faaf4b080a9e568f55d87499994cf694a7cf1e63","0xe66c3a163521e7be56ff27823e34b853126bdb60d67794e2d64ee4b52885bdd5","0xcf384f8c7f3f2d8356a170ebe003d992e56b52a0adcc7bf2841111f954c12692","0x607453b4776d2643bf4b84cf0203065157fab36b236da467bccc032a1b597130","0x883e5a9b276174039ca8014ca00fa800836925ae6e02e4b04fc7bd1ae647af23","0x2c938f7506f90af30c05a8311ffbaf02764e69fa6f12a04260153773dd25baae","0x721f3e49e33e54feeebe9074fd77cde0c928d712742cba07500f99cf995cc772","0x892aaf71faefaa0008d78c119f094f83e5dbe3a9877d861a0f597bbd1e655347","0x491b1c2192c211c32405c96a040193b247eee54fa916e551161f1877e201faa2","0x10310fa59208c11b8d0e13f04620f7562865b7b99c8dae8a3c93f554ada1b24d","0x349594ac151d2ba78a31cfcc1918d8014df45efcbe0e7bb3b3cfb495d9b361f3","0xf06d9c6dc33e9c6412d2da614f437effcd6922a48746685913c093c739ba9ff8","0xb6669f2fd3998814174c7583a3e45833e9daa6b68b81c7104e24b5d5f230f65d","0x543e8782091ec11308942b2939c9dfe4f5549ecb450723893d330df184f076ed","0xcabef69aa721dd78157b32733ad65fbfacff2011dd44fdcccd7a5e040a10ea48","0x1f0b5e40e7805e6952c4001574466ff3b2f3ab0576818a91ba32933abd58bc48","0x948bab0924e81514c4e95fdb9c3690db6ecb3dda5a038d01963b015666ff52e4","0xcd013597ceee9f4631c98c95190c78c5b8203e00530d337e0c6ca4265b9f9b0b","0x5cfe1aa3ec77173f232519f10e58ae6beeb784fe658c088bcb7881a64dcba919","0xff45e783888847a37ceede49facc22a91d54042c4f39ce8d0cfb21d83101944e","0xde1552c6c8aa54ca94cb3af19affbf34fb08041ea616c3cb38a7b85361f7b300","0x69e3d0534c277cb8614364297caef991c7e14dff014f80cd94dc79aa1849df08","0x16342a11f7a07c74be61d7c4e5ac4913f1eaaef1ca238f98bf5a1f45615b3610","0xbb7710289b1e6ac6356038f722f95d4da3692cab70636739074c609c50ed0ded","0xe6a13548bc1990390266625b029d31c26260b9bf75936091ef413e5e6ff38334","0xc01842b59ffd202e1d441c6d5f7a3e57f1ee774b00f7fa850fc044b7008b0a1d","0x852c33e658fe395d6e4e0f4b1eb3ea0a66f0882f0e124ce0a7c853c1b8cda304","0xcd673f16079eb7c3482bdae10a35493fb127dabe0b44450692ae586227472848","0x6846956433f4795a8451a2ed78a7e4235b922dad80fe2cb34a3aaa2346212908","0xf3597205b8d72c5faba80dd2a9e0f337595f446a3abfe4abc3db261dd0c7fa65","0x4cb661f257e8955a70f4404c80a57d27beeb86445f069055eafcdfbce5def207","0xa27245be555ec948d23177c7ae112bb109d220185154b1444f9beee970e21f02","0xf5b251ecbad0c643842f1734c80bf82427358c3ca72b1dcd7106afc565096fa6","0x300bb4f252f3865ac9baaa672555299d761b7c229ebb2b112e274aa295168c28","0xc7a8f06dcc4f46d8972b6faee3ca4144f9aa4984fb0ec599a9ffc37313830cc2","0xa3137c37e5bdfe7b1b7a7fea02c84943425e41ebbb6066d096e3008deabb3440","0x5b3f4d51dd2ec83f250f5806fbea8737bfe541546b054f07c587ced2914e4635","0x24ca81e5d7ecc92e84e1cd371198bbd54222f811b7e601a708dcdb0bd4ed3155","0x9bda4be5224b46a086f18da9e609f2b1a4a785f0868082a341e252c151a628a2","0x09f05ff7b012d22368a373ac0d1d337273f24308f3dd90a65b188cf94753906c","0xf9df5bfb4528bc999596b865237bd0c17edbe30844ebe1f470126633490bd237","0x42cb85f52ea20c289ff863fae08fc9f8dfdc84e7063e1a792b2b3d0ed30f3a7c","0x7212cbe1be54b47f15c44556b025c81dffe6d8a0813849218b7d23275733b658","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3be9c6ef2ba0f5e8c7d53dd2776ec8743bada3b416343b31b61b2ee5001c7b21","0xfa0cfe242977e7c9bc89697aec7d9f155e4b93c29420ac2a0b4e9ec66b2052ee","0xb8de69c251edf009b2350fdc4deb8d0efe6abd757160997b69b0474f231f018b","0x15b2513f2ab0c0992f259a0fc7a1d094b59d367c59de1bed291368e3b81bb066","0x41b19abfb0884386e7d758d5f85e47ee1e5cb69b935066cfa110d11393740122","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0d33475bcc4256d8ddeeccfe5f6f2d82480a3013644dcd26275551cbcf845bb5","0xfe2a0f9e1d00a9cee69c65bde6d2b150892f768f6002645ca7a07605845958ac","0xf182a47adeb12198d509266372fc8c30d87cdef7342064620ab07a3196135a2f","0x38cf534de9ffb9e5ac691dbe3fa8b8b0fe2012654bbc714236d3e635327612b7","0xa1fe2e7f0cfc8918c0709038ac9e069155519c688e8f81e12abd24dace8f1fc5","0xbbdf5a3a3ec666159424f70ea9570e943955a5a7c8edc50fc2cef7ec9d71c95a","0x5a9b72ec74bc297cbbbfadb733ab3303ace273ba0243bd19db9dbe05047fb561","0x8d559c10c33563185cf4c0fde0575103b3b9234459339bc245da2dcdbdcebc50","0x44629d9a1557652afdee997044a6d3888aca23702527ead15aadeb9b054542d3","0x86c3a541692af49ea64f8f9e1274d365cfb82a33298abe4f5b29b800e454134d","0x61a017fd3d1b40f0b9fca3e6f41809f816dcf86da52cef939ac5587f60a58991","0x111fb78063b2096e68400ed8cd47d02b573c9f39eacce5000574f23444acc6e9","0x8bf8f0456b97f9907b680985c4a17c2cc12579e9f70c9f085cb17a1459857d71","0x6f850c14575b5384a874cdc9cd73a619c8c41f57642e9d22bf9982b36aaee88d","0x31ef035edebecc89025129ad56ef8c6fafa562d66a380ebecaa9365e6cd8e502","0x762e52ecaa819a1135ddb20bff7511efd09737bb69d902eca77d95f235ba4953","0x6288c12db90d1eae8205805db372d0fa93dcdaa8900c59c0f1e6ebccceb045dd","0xe50a368f055d4cdff425c8a7b22c1bcae944457b9c6e801b5307db0f016244c1","0x54945a907423aa5b792dca09e58053ffd0ee933b3ea70db28d8afc73c698cc6f","0x603b48ab2ff97927bb9f299c2e1b10db7f73dcca770c2d2d02c377b2ca31f409","0x788fed99245ea640fcc719cd56ee197751a2eeb42fed926f9e413aee078bc5c2","0x2f58a16b307d2615bf0dc46182bf926b26bb27f55d936ee486e980ebb37a5e92","0x76c716b125f99c086745bfdea4343df2be1335ff7e3d267f3886ef4e7aba8776","0x943fa05ab3f04ae58aa1d0340c55b61cb2a63cc76c3860acefec2b45dbd501ca","0x5844f1b9d6619b111699b210bbf18c74b6f13e6a1638a5fb40f2a1c7f435d657","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2dfe917f42477274a33eb236fb8d805d504770b1448da3c06ac8568069ba72b6","0x4c96abc83ecfd88349a84ff33a9cf5966672e5bac9e27496876f89b81f65da00","0xd87e096f1861cbe58a484bad767abb4f1b8a47c71d84f137b36ea59e7fad81e6","0x307730b5a8e41727efc892024eb21bfe426afcb2d07f3e58c5ebc46367b9b2f7","0xf30dc4ba0028b27459886a519d0148d2ffa9f7214c8668639bc270b5f16f7d71","0xb429dbd71e910389ab38f6e8b668a1b3145b0892d8ecd4039d29d9422b61ce73","0x62ed4196cb09026101ca8ac469b54055c041446ce3ff7ef7dd8839a130a3aed6","0xadfb47b673552b33235e9ae282d1be14fb21ef3241b488efc9a844a2de2d6881","0xd4d5b715ef2d129b1dad105dcc0e8287e491a395293cef76e4323c8738b2ce9e","0xc5b91ce7bf7d26d36e3afbee5b5376e8c71d6349e9ccdd726b7be828c3d0a40e","0x5c2a7a43735e7b69e20e084210a386a8376e7ba1b28d29cfaf6426df201129f4","0x44816ecd9352d79a0d3c30d1ed806ca715b01d65b94bc7883524befc1c2c0b5b","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x82e9f6c647f69d3e36594674dae5e8f2c4f9173d3b85b8b008973d1bddc173f7","0xee0e790cb14f679cc384a23ea8f7cef6dfafa012836546c8a6d5699f66544b45","0xe8c6ce249b8172eab43d356574290ac10e334c118329e520ca10953af491d171","0x5bc92e47224cf915e7f16da7f08d1fd10bff33187c0b99bcf84df923de701a04","0xc9d9e972472f93f7d4a2ab0509c1cf309f404ba9af42256c757bb2dc00aed125","0xfd08d39bb51e19aebf3a938d40f228fd4409e3d0bf53892e3d6bc44d0b5816d3","0x7a38e4c291d64e01adc9a0ac65f1bf99dd73778ad2db7115c9fa11b6d27819fe","0x65edd017dbcd738acbac68f91ca885e983ee9a41493042ce92418586b3396537","0x943e3806388de248b437737aff2aeed966e837334441dc25945fe9ed5ac8fa1b","0xb26434fdf7a41977c84fcf73504bad121fa326e7e1ed39752331b7ba7290932c","0xf25c54087d20b41df47e5c735ef3b6b42ed283b1140b81538a7e00bf5014e9eb","0xeeb08371f1a64327237ce689f2217c676cf3804d40d360d38b9ef83d5cdc09ed","0x69c1bab6a49bdb9c993c484275aaf5740793291b65c065090dc805da653a53c8","0x7b8a110ad56836188b91acb44ea6e3caf55c8ea7ed47548d6d1841bdfe895919","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x52d7411accb58152440ae5903a578ce79ecb13512857ab7d582c1abbd3eb95b1","0x4ea22b03a4e925344930eb2a57a747c8f5b1935ea0ce05f6dd5e0f51dd1b8df3","0x00ed1629c16e4c05e655fed317cf6bdd487d7f0166018551df35bc1d2ee03ff7","0xd2558fd8ee323a84501af28bb33d289d526228839bccbd9ee2450ba0205ee559","0x0996e918a195cea48df2462af0e2958235e557356002c908b1f6bf6acf61ef53","0x64e02fc93f340a3658dddda3f351f0e5b2fb25f625f767cd0d3689797c20cab9","0x504bf55d2bdd322fc419659b1cefc79e43d0ee4c4e74ee51e547ec9667887c2e","0x5cc051d1e4606ebe4c8ae338c14278febe4ccde31696b368a958be4eae880dfa","0xadb6a5a6ef50a8020b4f669eb0c91a5c5a5922ab65067bf7b45db95227ecc93c","0x0e2d7adcfd7ee1a8bd96f20ca27c3c725b2ea68568bd5a814602d78bb9c123b3","0x43496c06a9636f3ef2d90f242c60cac2a2b8d985214e07088d68ea142b4d9a00","0x65f1477efa95a959796b2d68e0c3ce81921041badfc6c9b10e62c23e5045cd88","0xcfd09986b68972324960537bd2a1a3171b1e5c95f6a12159f0992f9e478db532","0xfbdac415d53eb2e95b411c078a07bd4a98b53f5d84b2e61a70c071f94eb2be7d","0xc44a217ca0f96a9f057aa040a84896a0192c252ed55107242a71870b0d879283","0x38762f19842a0d120399a85ea49fdc796c4f1f82c3522ecc0984e0e555af1216","0xe121f0e829d90cdc633d100bb1fd715fce66876771fd4d5e4317a49b1aaf4d2b","0x6e8ff43593e45567238e5f09f0b991ab9ea71167e251e9cc8b14323f21cfe036","0xf40c165e2e097e320b84ef5405c79bb493f1e5ee969056b99abb72cdf41b647a","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xce7f1ce2bb48d5afd79f5951a7c388a52f5b4954991d76f445ab04be59fbf71b","0x73321f026b8c99325c45d4d7a7d099cfe375f21790483ce40bf40d5ab31be504","0xe66ceeff1efc2975d4c75237b174b0e468db4175a554b3186bf252924cec14fb","0x47b13f17c9557b88305fbabbe95a3f2cf3e767eaa7665231fff1cc440e671c52","0xe5f2fc4605dacffd6e678680fceecdc4ec9a779f16538d86cb11e64f0667a796","0x6095151f977f6c18bbd04e1bc49cde600ab964ef25f4aa671fbb754199bb8b6c","0x5d2d6a0caa77a16f10bcbca938226175237260a743f735023fede5ca368ebf4b","0xa47fe8c3e7e2c199b210939cc9e905611f2efe1e0c9a6a22007b86fcd2098a82","0x8bd3eb786f3c354d9eccb71e9ac87c959a258d879afc093b6932446a4db5a409","0x26d566008562b7e16ffc67f3c8cc724e5e6fd018fb9b932b24e34aaacb706a4d","0xc74adbf23de0e6a39991124f97a1b72420b9dd6f561073307c3a06217d32e38c","0xf3ae8cebf66077a4ef1e85e89f2b728934857feb71cca5cbd9e80c301575b06e","0x573c850dbbb847717fc2394eb47de5d18a1c2cf24e6ff392dcb6f6ae0e5143d6","0x800f37886c0c441ff079e55a09b26468f120161a0390508071b66ae51ffc5e74","0xcdb57ca6b064c7834ef3460f112bae935728ee6cd602ca04c96913a61be62013","0xc589c9500148705ab35ce3c21fdc8cefd39ddb0ba6a40b51c165ec9fb344663e","0xf0dc28f1cdce967920589845862331db279e1106bf8a0f1c619343bf35e48e1c","0x349a65a905c08aea1fb976de88166d43dfea4567ab20a9e2eff1af62f81bc603","0xd377f7146ee6ed55bec820c13a5c34bbe40e4594e619340d31d381c139bb622e","0xd43aaf516b522358147ab5b1779894875b690d6fdbb39eda330605580f8b8074","0xfe50b6ccf3f7c07f9f1c2f8caac862268085c23b0bef08c84b043b061e07853b","0x5fa6398a37353c8afbd71613cc0cb3ed4ac94435d566cff847a03ee91000096a","0xb2b18299c6c5d1e06b1f217742a7f623cefe8e84d36e5c3c6d535cfc9bf261f9","0xfc512d500df71db33b1e93c6f83169ab8e1a00e8e57825f8b8e950b784274346","0x692f6302f4c499ef22650571a350a356baea15f4aa25f26c0739be5bdb38f505","0x8cda67f78d2753d19dc7d2de72227c1c2a907df67670b36bf213592743e2b164","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe7a8cb8c1ef6a658d34e090a614a212bf6061e298abad2a592f0e339fc832f4a","0x367445f8f2cd6375ddfa38134e186fca2df3d12e1b7ac11584e5dce4d815c88f","0xb1dc5df435c3e478ca4b2fc3b722ceb09bba808f79732b1c68258847f5e43b85","0x1943eb144a64a34bcaf1ee6ff1556079ffcbeb2b073c7c7dabb98e56491ee6f5","0x9f5464192ad4300ba8108ce13a56818bbf9505ee88e3a5657bdff049529c724d","0xe5cf189553084176b30b9e654ed4606df0bd480a198354e17384392a69ba7105","0xad8c7b446a9d8a2011b791d627a7e117bf8dc4f36192ea7f988789f9a598ecad","0x3de1be0e8351a492b2fbb3f0b1df634bd72383a8ef1e7f3248c23b60c573859b","0x1ee0987e0da8eb6db7c5cdc357b3d22c8bee48fc878dff98f38af731817be9a9","0x7ac880364eda2a247e297a917b81e710d893bce344d89425a0442cc9024a2ee1","0xb83fd07823aaabc4fbf89aff0ccfaf6297781dd0f08ab804886b579dac9ac952","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x080a849f15de656290f6a953b87a0b585dd14604bb54924b56061b7f6f326ae9","0xd6e7af92e64cc5a5394d9f0f39306b6a58c2023295cbc2ae6bc67648670aff8a","0xfd45c4ad573acdef07827e9e96d2579f0222f1a676fe8b6efcb44866de7e8854","0x45e2d9697811ece0fd0e820e72eca2808a1b0c109ccfbcb05800301159e8ef0c","0xb41e4b72b5e3d2f7dd5c6cfe5315238ade147ce3861174cfea14127562c01352","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xfee2b4291e98df5662de115ebc569fa3fc4f09dd23cae5e3a8ef806b9f235e5d","0x34a338a960555940279ee77cda42324f5df0570b27bdcdab5e4a068a6e53cd80","0x06ea52b57d240097ebec0a87ec6f3956a8c29ce3c9a6ff5cf1d9cd80af0f4718","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x635e12c6b0c13792ce57d8cbff8642e4dac78e1d6512fc4d2ea4c7ddb5f6c43c","0xf6ddde991248c3f5a4fcb27e36551cadda0b4c927a8c7f705d92de8a8899e90d","0x6a379fd8911aec42120fab9343bda18041ca0ead9f1e7e99c85c96d964d16681","0x952761b7888de6457b5314d0d8eb4e812c408ead46a0a39a07c34f1d041aa44e","0x4f49cd6cea57ecd78a2ddc8a017fcd32193920a6f6ae966684cbb72d58fae4a9","0xf0911693049af2ae4e6fe8a9a8149f24ceb84f978c83121a12b0aba3c0b2a6e2","0x1e58b50d324c61f2bca813635874f1ccb06c210161a5f6f6472386ba72ef8aee","0x7dc067f307973f18a09cf1215111075760938765cbae30fcbce79b063a8af01b","0x960dbba0917f5f9c5db0de580498e4e06b4d6481801213b47f7a854ea96d8a52","0xaba982c68d53e6d4c26f4334b347110bd9e8ce6cd43ebfe967108c0cdc07d0ef","0x352a337fc76f5e93b346acee9bfa6325806bc3e1a680be7a7f6754a20a3bb590","0x3c0767d8a0472639f5acd3199070e47c16fd76ef39b40f40f07cadac1864b5de","0x2bd8b784e8d5fcb83a14c156a2abd1a3f6552b183fd7e75daca131488c956ba0","0x475718051a644600e5de00b80730badedca46f2bf05bea36b03966e03142ca6b","0xdc4f2a48da0fdc8b3d5dbdec7a5f6e2310fb52c410f3be135584ee4b1c9d80cd","0x41f7424d734cc4c4972a23117367230a443a8d999d054c9e4eb1b9b491130e6c","0xcd2ef8451a68c2c1b036c3d19fb009ae0f90f7d9fdf99e2d18e80bc1bc8cf764","0xd05aa09a7a90e8ed959ae688760a6990dea1e7143d3f5d80eec9eef0bc603253","0x77c83998a7cf76709391e8a7a0fd46d8b206ec44e08391ab6132f673664066cb","0x2f5dd9ddb5e2320de20540b55141c7a9e8ece6753110e4b7da2d310e616fa25e","0x7a1b5ac811c27a39c958884926ed50f4407be56171186f0324fe5fda7a59be10","0xd36f3016489804b7b5940f06161323e4f032610de5e93cc578518b695b76eea7","0x1113e8e29770393632cf2cc7057217c6e2c9733c4ec4d6559a48f0ec714cea97","0x9e2a07e5c7f0764d38d9fe195301ff723f6a8fa8d9840b4cd99a43f69dde528d","0x2957e4f46028ecca442f6c29969c45c04813e107e684c5620a6a4b4e7dd444d2","0x72f77ec02f5689b05f9fe45616942509f8ef67f31d3d7a7414217c239ed7c13b","0x966b8dde40fcde6c1d3c05cd3bab64c093feb71f25b03ea56a1435a0d012fe81","0x8056c2bb5a539c8837b6b4acb4de07ef2ecd138fcaafc170615a68bf86773c0d","0xd42299356fced3450d4710f1000b3267a9be477666e4b8980747e1826163f5f9","0x24d3aa7dac2e6bfc24142e588c60cb961dac2fe271f09418860fd666ac322184","0x535c1dc0fe958b6cae3ea5d2d827c3419b7a169b5e0258f9e9f23e00ca0bcf39","0xda2f88487e385f5a67deef58aad0ddc91eaee8db2164f29966503e4801e8e313","0xcd3fb65f075791d26a4f30f2d65693d9a6060bf580eb7ca703bc78ea68419f80","0x929a69836972eade84ed15f5c56294f7cb81ff1a0e3006ba966806eb30d99e78","0x3d80d76a2a3295aae5b77119d45ccdef1d2d1a0d7b1e77b796a51b51fad4b28a","0xcdca7d06565b2d76ac31dd6ff8ea45440a1931a8252655d73807f2ec2e7181ff","0xd8fed9cd7618cf662586ef3473850db91ee6f73d7fba73a9f2db946481573575","0xf076b57c9bcfc6f2d65fc6902d6f8bc43e277684b7c9af9aac4ec673b5ca947c","0x954e14ae042dfbea39e3ee9c05c1e547d7e57c50cf19c47d603fff78307c25db","0xcad937da71a40a4a6988f30a382ef9caef6f0d009247df2d6360fd68f13f3088","0x2eb347a8b6f00b086b4d6412b9162599dae0f3eef94edc8ebdbd0c71a7ae03ea","0x7aee04b9a2ab0a519b7030bd92b89053a9c9475af0348a227e95c5aee17387f5","0x93486c1d21c8752c8505793eef0bbc30aa653a7b4da02441b8b2e9dd617f939f","0x852c2f9b67836e4f1e315e88cf34476670fdb57a66d80c31acf4d0ba17db3a5e","0x7c995111b81d33d0a7b96f9994f156e6492ada410d7fd35d45bf7969eaea3ff3","0x870ca4c1647e47f942d4b8c2490403e7b09ad2ae7401e63af7e05b48a2a65dbd","0xb0c12e7cccaefe46f019085eee1c33586ded721e2f5181fc68c2ef6ee20ba14a","0x7a07f3383378d57428bb75fe5f99bc1cea9d80e9b0cf58e7f30d726b6c9fc0c3","0xc208f7da00bf12ff87b3c289e3e4e6b44502b86a277d6194665236114b8a6495","0xe4cac4cf8861f9e96b45978c4f82fb434c54ae3c1cb77731a373a0fd3e06cc4f","0x62b3ffc84af57ec4f4f6c25bbef61a458298736a7f8391b977f76719edb8d466","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1b21ffb27f29df3e79330b24a3bb5505d325b2f8cc97123ac7237a7f93df5ac8","0x1a4f7d1f54f18e1445b30781f74c68ff44470103bf2103889c03176cb802f253","0x40e7bff3d6a5963f594751ad4baae59e53f336961a28b3c2b2ef1ce8e477256b","0x9788258580a0438add39052e133d1f2a2f29a107ebb1bb5ba98fd3ae3a31662c","0xe1726c544b3e24567c19c629808c59ab996e2cdfac0683d906201b678c8731bf","0xdeeda443e806dde1427dbbc2a1eaedcf7833640d593a7813dba897c0bed3218f","0x8bd545caaebdd14c868e86b4cd9da550625fa2b508677ad340f237fd4b4b9f37","0x2cde3dd8e6d8fe7a461e2cbdd091de6997b1951824d68fda0b37af5c17655a9b","0x966f0cf324f0319f8d8c9943d504e43d83346b956167ed758aa7911fc27ccb01","0xe9e30f0465a091880e8637c95a2f9247078e1eeb06bb97e3b398c5a2b81151f7","0x359f10e62cb80fdf888b7dd8434ea8139d2acd08c6a3999a012b2e2728253ace","0x2e75729fb89b6634c67ee47c8798fccac243d24fb3586daa3ec03da8711474bb","0x7b85f774689fffef7951c813d82fc0a60491e0ecf2ebdbeb006daf006c0878bd","0x6137a71ca9cf15429ad8b42a5283109739e973d1e3988102b69c7767a575810d","0x57f42ff00e4f30c4f6e9c1aa551b8666ad0e57518b32fdabbfa678e1ec69bd53","0x0bde2c19e9997d8131596a9c782f8d94173a416f8a849a10499fc657feaa9535","0x96befdee42fc8d070d45cdad76b08299577b35080673e69308c7e9b0f4ed30fc","0x0cce374d02d374b1cd2c0a13da1447ecaca441b74717d2f0728a57385aeb2641","0x9429d477c6e829cc6b5dcc750d7d88c41ac32f3edb7d7af0182729c83596c542","0x1453ccc64220074ae2a4cfc91e22f8a1a8cacc2d5549d9e3633eefbb96d92e3d","0x58c0012c7cd1d2ad9d5dae43596b502e913dabda2ffefd127b587527105e0922","0x1ca2e5080c79d796b32c8e8b37222533dc90843bde8f64a3ba8ced86359b4f69","0x7fe3689d136e3cd639d0151f0d04ffa8505801170bae5cb0d51d7cbaa520d5fa","0x3a0497866a2b51f67f062c841c351211040b0a0d5573c128a2b965c247c029ff","0x928ed2baa33e408379280b0d9eab521cb303b7d3e019b94b29511ba1797c1ca4","0x4a6f3c7f479f508e9aa853ecdbc55395285d767a8df87711050de04df6669cf9","0x8f15c8f8e962043f1d9611b4c56426b4d547801072291c52baf8f6b58d6be95e","0xcbd8907013eb6568679b57d445142e68ff16abfe9a861756b2582580c913a3a2","0x8361ef274c18a6cc96246da0ba09122a36dea6fd4391a15b41efd9065767abce","0x4d38526132f6b9d5407599f8a22da90757b427d5c1fa73deab5206bd45105bb0","0x129080e20cd250fe1154125bd05299eef3c5d916da068311eed6517816e84ccb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x49908c1ab4efc1d9bf32370663616e73b0c980824467bb7e042a3f8f2eaf44ae","0x90bb402d1f8121ec6c6437c6f618efb541389a89e86c40fb43e555ce35883ec1","0xdd558d12d4d7ef83a88196de5a736086dec7c15ac87cb0806704633b18e109bf","0x68f682b124835958d774d54650632f469325523538375e8c8e305a2509715523","0x015dbf0f7cc4929cff7a8fa5197a9b72f197d9993c2b3fef7d842d277c28a172","0x8461f88b02c01a17eff35044880bb6aada7ca89dc07d2091844b348ea9593e15","0x30ce3494f37f872379c283f9ea684a3b1f10cc33cdd6e0e7ca9bedcd557ec1b2","0x48292e38e73cb40679913ea029ea5735a352067c17ff03e2359b22baa3f46d1d","0xab9c634415f0afb9a8f5ccc85138c1748cc2ddef0922934aa8f49fd487dcb473","0xf03fad8896593572eec6bf1367d790f34dcca0ecd1a3040062e0c941dfacf5c9","0x1af0bcb5c46a2db9c9b4d50ebfc500d516d0c8b9966f18fb2ff24623aae05a63","0xc6162db3b736a8c3381c1fd223efc050100fa7cff68b252f3afada256dfe9996","0x607ca5ca1ef8032d9a9ae0cfb5071b19c9a793a4478e742cf7c5619e51443724","0x0593d4a32cec5a2d163a142a48ad464ef05de429594ce43bd114048dc3fbf990","0x45b085ca22d7f223c6af4c489369c739e5ca78dbc458a855bbe537aba20e33e6","0xadf6772ea699c30129122cd32fe57bff1951bb67a96423cef0bac6e9bf374d62","0x16eb0ae8db39c797bb8dc2fee13787984a6f11ee23bf0b6cd5b0475c0cdca4e2","0x00ecf504f68f0d7ca592dfdf6a8f109ae348ff9796f958647ea028c0009e6c40","0x971691ba78ff55f606591867da064c8ac68d826a06184a2c5bd28f98be5c962d","0x2b7ebdbec66bcca09ca4a3c04d52fa6fc754bac46c638520bab670398cd1991e","0x12877552f97feb0991d772739cd7cb979c863cb13650cb397e9abc93244ecc38","0xca9e74806272937259a5f60b3c94c0927ab84e8c08e1488fcaef68ba22d80614","0xbe4e6a05a2f7fcd002e72194cd7039603515a72e99f9d2a49858fc0aad5602dc","0x5af782ac461e8c47921f7688f26242fb7a808081d7b7d0c1e1bbdfb5a7e4d687","0x64ed5dd935fdd7b7ee08c46c733a5d1977a378ea32d69f382f3bd94486585b4c","0x05fd0b7f31113dee31e3d78a3e17030622215bd77faf7d48d752623aa3c5bc26","0x102f44e211e399d63da6d954eab167e4b0bda165e6d27e55a42a657ea7189222","0xea6e1408f40161deff5411c01be5a5b9a3a2b67b894a8bc438b77d5abcf6df9f","0x3777b8432f8d8b8167c4060bae9ac36948de3949c7d231f5bdc5c71be2e19bc3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xd375baaf5462d63f32903294dd16db378c5b00884f84fee2bb727ebefcd2e489","0x3f24bd57c93314beb7f87ab7830a055cb67ee80a13031d2b2b63a695f99f8ba0","0xc650924136f009826de8a127bc9ec467f63f0b28b60d130b262e54a187e61249","0x353ddb18a74d52a951c75fbb8d1b4a90c16c8b266a7bf61b4dbc7670a7beb516","0x35ff848d0cd3f28f5b6244e5fa0560e98a72d82d93594b13ae92cc15f3b2ca96","0x9f5978406ae269c6a6fb36de9fbd905014985b35e5f16f7bbf9cf0589e5fd945","0x59e39dc33f57ebbc169589abdc982a3181f85688209a618fa691f97143462f25","0xacc589be5f1bbf8983c4a4d86238a34ba3af5c082ac4292ae15e3da4a10ac6dd","0x4f6fff7c142cdd3dde8a1f58dd936c7e52c3f978bc986cc4bae22013cbef7eaa","0xf6419a6c67c75afada7b892e3416aecf34a38a74d396781f743494d92f7bfbef","0xaabf6cfcda3e18a3b78882369efeed228dfb382fe9373d0077071a7228a437bd","0x10750893e5a3b4ca6c0911b475d4fc43b60905b413f4ba1c5fd387345f6b71ef","0x3966f68c6ad23d9a30caa415784165635c292b415b935c1362fa0a29e1456b89","0x5cf556270bce6a9123e46aaa1f72ce6c1f856dd4ea90aa76c0c8971b6a64f1f4","0x939cfa69c059a6ca406eea7eac34777004b3c60e5b95ae14d541f6ad93b7bc62","0xe8b842c33f05fc44b4126874e9f67702be2d148af464d9e50ebe04295b5b3d3a","0x502eadfe84a5fa3a229bb55883fa9ced870a8dfd3ee098b4de678528acb50ea1","0x6512d50a70a48b96137f184651648aa46ae4b672c520fd575e8dcaff70950622","0xe66de027b9473e32e12b319ca684fb9d1ca35345ca08ba00a9e001ce7a1a2c7e","0x392b5b131cb7892966f9a7a4b73752cc9463f5ab8861e9b34928690ceb67f1a5","0x117e1c5b7e8bf3adeb985084abfc72d3aeaf6926a84c0bd481e5d227809a3704","0x1a425d4f61ee707f073c31cf935ad7e0c555942ddf0b76ec2f754881838ef853","0x46dd7886279cb3082a219de54e8ca8988cfd55bb86c9491180255c8644463bbb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0b580160ac7e98383d60bb0740a4c077a4cf05e7b37ef0d6ad7ec477048f8b8d","0xceb62e021959ffa8ac2aa7ab4027785254354ea262e3cb9fd66b5cd2c6bdb801","0x5a912589b7f5fe446f957e8cc65144556c23127ea55cd9eaad9c25029662ca37","0x1c20789ba7b3de06ad6051f4dbf81e68e7928db0b412f6c1fd757338735b8463","0x5322c58dc9639876efc01bdcd82f4a8835df46b576235e138737b5f8469bbeda","0x63832a5a1bce698179159b705328a0e4bb826d12a725cc46f3e4ca06aa7a737d","0x4ff4f0e1d01fceba67c4e7d55593e24886944b579867b8846dcb02c2ae69c1c4","0xaab5e551b9e4409b2f602a64d2a85b54ecc0c8e2ce84e676a06489d26aab391c","0x7a6dab5ebfca90a88be46af57c072bb1d9e6568fb994a51fd2daf16413d69fda","0x440090627bebf8f5a1ac3930b45ad813e47bdcd699c241e73d5f50f6d6541563","0x6c8340e1f519d67ae0e6dc7b77ef5ddfd222c62a5213b15dde2ef588ec238f68","0x43026c676964ae8351889479a4ad33a981703b2d3585dd55450a5ffea24f215d","0xd8e55574a86233fcf662316f352edcc2af630bd17342241b23ee49c888207b81","0x32fc7f4158a7afc721f228b5714f07d261f682e51dcedd5411e7ddd461c9a7db","0x4366fd11902e155069e5f22d0751e92d1442ffa5f49d1864c23400a985bc636c","0xaf2634b469ef3b4be6fa5fbb7bb7f6334cea8c3675ad0b1353072c673e01500f","0xa7c750510f26d8fea2f046dd31afc7d1c60309d1af971233ff0bd45a83fc3654","0x1ab0723880e898eeaefe7f65ffa5d86c1006d18d45db35a33a0b8d1206710a8b","0x3c49dea527815beb8c133830f38b381ef03bc9a353a6b7fcaa8d75a2b1645786","0x7ef0ce900a9c5953ff2b1181ab84cdc837cd97fdc2d419af04512b32748c05cc","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa16f56b99e0a947cc0ee5a7bfd335a2bd665db0f4207bc4d7be10aba8ec73c04","0x61162d4cec12e30aa508a59bd73ec1a9191bd9443404527d2711ab1d627f52d7","0xba7c2e0ba0b0f6db7c70a9f8b1681f55a40190a4d4d06b73b2ddcffc451d8ea6","0x41ae198fe67ae68d989c93e43d4cade265488ba6a24fb675f68cfbfb7cd41492","0xd5c8a0f13e97ec4fe85781ac8b89286275caea1268fc43cec586730cc3caf89b","0x4fba08f4b3c6bce8d90e4b9d9677eb924437352acb29a8289d7588d1390e7508","0x68c4b0b50f067137e570bb154c9a857829e97a2793f11190a3a28cdde52be7f8","0x95f142a2642b31cd6d315a75ff34720bd140b6e5b70ea84f5b0e2138871dea96","0xba219175c6367f7ec8ca7b8d248648ae00b329d051bb28e144d98f97a49b2e36","0xb213e13d820f917eeb53792facfc84f038abfdb744446c1afdce8dbca8687615","0x605ba33df1ba9c3aea5bc72daeb049ddd1c4930b3310c55f68d567988cb05081","0x220524c832b9294ea905351a957e4282aa06dd746134e93701d52dcda94ad051","0xfe1ad339d09e726aedffaf0821759f838d531bf9d45a090b9849054c1ed881dc","0xd7562062dce86dbc821a0de0282a8e1a65e881c4fe91ce42142b39ff0cc93741","0x337012abb9bb691d614700c4c2b556fc0e582738f414a9d576f2850e7be5d68b","0xd92017ff8a268e0c72b2ff3f97d507a1c453720e528ea9ad4c5d9718ef479d4c","0x7e04402807523d5d5334a5d41e140f490cf57c082ad0b9bb55b14f307ae3ebab","0x4e4176106bae3b1a23bcd36da638e0f49f0fb8f3210f448be7aec6b374df4aed","0x95d7e7ec6d13f30a8bc0f7779edf54bbc31d61d6da9493bdd12d9027e58bfe23","0xaca9d422403eb337982854d273b4769c1fa415d1fd84f61d2a0b143cb7d8ed03","0x7c932c3ae7d760c36ec3010fce9f22d26c9381fac1d625efa1694f4bf222ee19","0x6ce2ed89a4c5b352b3a58c92b5f876014dbe58620551f98c00fe32fd5bd7fc03","0x1f140f39fa39b28a05217c8d749a7656a777da362818855ee61ded87907b0966","0x4078028e8dba0d5e205a02ea3e02d71945bf0412ecbb59dfa547be3dfef72a7b","0xe1bd869ba0fdd467bb68b99030a3605652801376e8e55eeb78a6e18284706c78","0xdf3480941a0128c91229893c14a0aa4e54b3bb41307d63456613b6e3cd4b7944","0xd4e78266fa5e3a5026e5004c23558b35e004d6da1d580ad4c0da9c3fe4e167a1","0x6dbae8e06ea1a1c9dcd0bbe7647ed99e63c4067612fc277744493e7f077338d1","0xc1e82cacd33327715e794c779b6ab79a70d8b58f824ed6732d7fd3b2418d01c5","0x692ec9d1418b258fd553d7b7623c40681602b4c81d147678858565d5145903e3","0xb874fd21a2ceb92598cf6d4e70b61dce20d73eb1c83d6951c75fcf3043283bd2","0xc3481252f344b7fffd6a90f44280f7db90c13cd7655355101eeb5dfab3f4fa2c","0x514601a4722f396e849497641b2d737d163ed57384ad229654e2363aec09ce98","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2a721e145740e27d809da7c74f7d7777d0646f8823685130b6e5e3f88c4098da","0xda8c082c8bad2b4245852d2f73c5eca8bf9b6b5c1b98e9d51491b89a0bf1b31b","0x1d19155f5ba509e6f17e949341e5e07b33c73aceb5c96f2b1eafaff08137f827","0xcd6e9ac65ae2a6c098686a0568708d502549f6256f3d87d3e3321003fabeaee4","0x11fdcb2823b5320ece6a80f37a5c2a0f7986aa534748dccbabdb572f3aee695d","0x14d912c47cd3c87dc0846a20e19c908bbaac93deb4e744d5477f0366cbd200f3","0xbdcfafb1713d81430abf171b24151c42048da09803d0ebc0eb83adda840e7252","0x4fdbb31d6c497aec37e01da72187b90d9cbcada6f3f93a73e32b45a74f59e2f8","0xfbc8829e8bbe0816b8467748bfc9d5b4c31875f2627f1695d90b68ee49dd05d4","0xe5000309aae1aeecc2b3a7131275e6777477b209e44e8b9055b8e1dba327f4cb","0x70c535b47fef277831b459aedd25ed9112bc121aa0ab7e71713e19b6216350ef","0xbf73691204246b43d34db6e15fbab9d2daf7b9bb96568659a02abd767e5e0bb8","0x7e7d73b93f9c0d556a5d4575cba25be94178d25af002a9dc6a6c8e2ccf680759","0x8c045456146f5c66a3e1a31aff99a992df48d3ddff2b5723803c53d3fc6480bc","0xa6502af0372466864dd29aabe22d0a61d5d4afa6be582ed92aa5cb55f04d3eb0","0xa3dc817af97d3f14fd82e91be2dff57fcbfc65a5f3ab669a2cbd4360d500d743","0x63fb4d0f5c59b3eeead2c17f5c19d4f0803a55e9bba45c07613059b112814cc5","0x3f377babd9fdf9e7e59988eca2ba0d71b4c116c5182eeefa1e9a96659f95485d","0x7fa37de74604146c00404cac050464cbc5f921ea1dd5a6151528d0cb59ba3413","0xe27467f1d7b05f6fb33de6c6a1850f128f3036666d2b3f926566c32090b54c38","0xd9b644df984b7af9b24abaf18a5b2cd5075cca26687a0a243228a532449a9bc1","0x2f2fc270ab8c21d9f7aa01ce462638f331e8d7ce3ffc491af952a9d21a81e189","0xbdb4e600e4a3ff0e5f05140bac10c3fbd82920ee26e056fa5bfc2a2a5f5d2cf7","0xf8bcd43d8f8af468f01ebb7dcdf1c3f2a13975e8f0d02b9a5f9a75711db0d6bf","0x9df0f63089239f0ca17edeeeb75b4d421c7a951711112c8918977d5c786099b4","0xa56bb962d28f545f24f0cb1921b778f14f7b4e0150a182493f375ceb8e8f78ff","0x2f14dc8a4bd513fdfdfcc016bc9cdd1909076c942aeaab7aca9f44bcfe43810e","0x261ee3167dd7d55e3df273fd9ed93f3a315af7f8d58ff826a1e11c1b933c2a1a","0x13bfccc1859ae6543e3ad74384656b192159f7a914f5ed48ddb6aeffe848ca32","0x8610dde8c5ad4ba7c5b48baee604908c3b83807b8bf21e500cdb3e6a150693ea","0x3a00e53744d3353ae86017f6aded0833cb178156f16b6a925c6d751875995074","0x753458bd0f0e325a2c09e787a4521d0ff0a40c8350d677ed79e1399ee9e6e1a5","0x4653b23816bbce1e7cbd5cdb1aad36efdc75f97108c49af4f47f68dfa7a7e2be","0x6bfc73a48f9b0b372e56e38c6367e99578afbee2f36772444ba9b6a59a5e9feb","0xeba384bcdef2736212ce62d836caf24d5f40808d2cc4c1f9afbd2f5c026bdf71","0xa72b6379456435d76ebcf4a6f3d1902242303d976fd0ee02026fd13efcf58bb3","0x5f84bac3be0352127d76273ecb28e9b27b2baf1d1fdffd9995b4305c0c1177af","0x70f3c412e2d0c59ec3ce17b8dab0cdd5978a70c21992f0a47f32e3cec950cd02","0x7a47be4cc5b26e127bbef99386192396080f6b9cf1822e3ac3d5f1efc37c13ef","0x7e475aadbed64e097590b2afeba516f4aa624aa7ad78dff5f17d604531a32d16","0x36030ef05362f7f34ac9cc09235c925de60fb46065aad0ffaf2479a31de21aae","0xe302f5c19a5e666cfa6b5a73f240a6e210f4651f7cdba715ee6b60da75641c62","0xf204c7ffa5d2605206b2cb13a9eea13a864304e5726f4203e205e151f85612c8","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xaaed617aebccc70ae5b8bb1deb43893c407306ef768edff092a0daac698ffe1f","0x2dd37f28eb91878dbbc80e7beaa37610b615b07693f8444bc6d131dd0c4586df","0x1e7f5f485643294371895130984bb816ffbaa4756b6366aceebc684a08028e48","0xaa8c4ece551c896e667fdac3b10b28044308c583ed22689dd55425677d35ec5f","0x2a5c553fb92792be44b33398f18f65311eaffa856591017596225635e7c02597","0xf59da15b81492e56b8444ec9011c96d5158b9509cdd8cdedb46eb53820349512","0x801900f1f666cff20b3b5e342a2dc882cafc2f75c5b7290c2f3ec1355e783c2e","0x5a8625db19496c9366266641b2800483ca395027810bd9ff0f7b92a2830e8abf","0xb38047bce3a9cf77ff4185f82885b326159d065e68cef43fcbc071c7badd47d0","0xee59b7b8e0c60e7344e7dbbefbfcc7ea3734ab50eda7d3493d6ec023aedd5d07","0xd131d141def16b32be4dfa48df1db07831ab534230b6d4461ebdd123d739645f","0xa0b5e92b4224e86243b666efabeff2c10ce65fc0a6509a534c84d854842b2a2e","0x7c72a5089281ef9bf0556d7b27f5e195a18b137d3d93f727b337a0cff23a02ac","0xaea5757bd5e65d7a5f3cfefd4271c9ec099c39a81219d7fd6531e29cab2d0742","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x19b7701294ff85c98de01a1c0f300ddabb7d9d9b6ef511b879d3ca377b5bfdbf","0xffd21df69e6ccdbcd90aa7cd3325330bf2f94374cbce2c0e7a7566b872ce1966","0xe69b6372ebe586ac7d3854ca170315e62a814d8442bbf8b38c62d1b85d57a560","0xf6b73793ec619943deab6740f807042b2446dda2eadb6865fdf1e948038338f3","0x05f7ac284977be65abdd8e9240e6dfce863c7b59e2a09ff2d79dae68ca52dac8","0xfa6518d10872bddcf48c1ee4596c7f89ed1005e74d7d473f88039504e558cffa","0x7dc351a327c44a10370ddad241aacc4953f8279bbeaed9cc1cf6f8d85dfefca8","0x469e2b45bf3832fc74d77ad90f93a4f37ca28bb3b4279f0b2e327568075f9027","0xcad72d6265fd4ede118ad35a2b09a92bf03c73a90a05824de058d09a301acae3","0x599f8166fff81d4cfea501b46d0ebc659c0c670c370fd8742af9aa6ff45b9139","0xca21d232821cc2b81656cfe10156445bb85b6f6430911578887e65f261d5c3e8","0x0f0c4e277e3dc551363edcb3191c6ceb6f4e89857fbd9f56944b604d8a5d6ce8","0x98981689b3d7f1d1320f8db51ac8f7eb01726cffb4c5f0c8f035095ef04a9754","0x8e4b1637eca5253eecfd3b103ae7155d478fa1b043372c3dbcb62d97d0aa5827","0x9265149b4782bc96ae75e3e73ba026496049df2c712c6f55b78ea6cc4d87181e","0xbf4a3b419a4aa2863cb1f7031761748ae6c985d4e7885e716e76eec6c2f74869","0x11488b178cb08c054ada345b0970b21d378dbf28e3701a55a895c1e73c518ae0","0xf62e03aeec4417c1fea3b1f068d97bac420bb1ac110beeb16a74d9928cbc036e","0x631193699f5da6fb7b14276a87c7b34d287be661e0dcde28427b57d1ffc23607","0xe35c505cc3ebec38685edf24c39cf3ed9cc5d2e65965b1e44dd0529cd2f13bb9","0x98b107fd91450cc0ecffd79b7ea97197501ab4455a7c8ec08a1585db528480c7","0x3438ad0b5785a39b8da1c267b736432527dffc9b842346bb52ecf499c5fab451","0xf23e2c738e6db87544d71e5d9dd796afa40f4cbbdc3b53b60040def089a09bf0","0xb65c366f1801b8489af4215720235db59e75f2815cab0f9094151ade70c4da9c","0x94ad5f63edbd7d3b2f50c5702bbf6081053ecc2db95a4c080ce3d2286104e37c","0x605b3d4ff9a7ad82e7f66c7dd187d0983b375f3c446571022c4be135bc247ff7","0x3d3298558282f4e6ce6bde28efe89b4e48bfdafdca524c39aa47a2ee1ae71df9","0xb65fcc8f80e0f61128cab51d5397705c5b98d6d8e9593c118af764b65bd526e1","0x3f19520e06ee4b1ffb7a7683a1d21d8b9d0f2f6b7e843230a4f568b98eb57d88","0x91cf4d10dcbb4aa0e27e69633980760561f98b92119b628b86c9b829ffe9f56c","0xd81c9326671f2e4b2f54c09ddc5a3258e4f8777be097cdfdd9588d0c5fa502fd","0xae507ee8b03ea3b3b0c68ec0018654442f3b641e7d524cf364c1a70eb32ab59b","0x70c976a88fc09b44212898c123ab9c7467119a705b1e0a85d0d0b5157db07be0","0x27e8884c36f358c0b3fef3a838243a0e540eab636cf6d1845da3e794a8520881","0x90a67576182ae352fa4e46da090b9bff4d02e2ca69b7d2ebb6afd43fbc472f31","0x205d215752948cd0b34aa30d5eb81fbdd62440d86fb62532d3f3738318215dc0","0xd7b474d3662ee61273a3b6bbc76dd1bdfecc3c05e951139d07c0d5612d839bc0","0x6608011708ec76f7b1b0df13e122711cc5599b6baf8533d1873979f091ed7e9c","0x1a2f5ffca387484a03f3855485c6522acb9988abe9a6c7010b8b6f292e578ab1","0x57f38a919ab167d0de0e4b5d76be3857306e91f2760976fb1fcafbc47b2629a1","0xe260e7a2a02959b931fc467bc2bd32051c23e9ec4d03d239c003828b7accca32","0xaf394b4f650e9d3a285d5986173effdbec03adc436a7ff6a5b83ba88c3493c9d","0x1ca85e7770ff781c8a078f48d3e1ffe5b55d6d529701e22c57bdc87c80466268","0x86ff9e90381e142b09bc5d8d6dd10a0704d16c6906a6c18c77157077a419d6c3","0xb68c058935762e9ff1f437dcd782f68e0cb4702e8d949090d3997721dbe32deb","0x47bc1c6bfbd46897950e8946852df22b37b1c85909b6f3549437868a87d44b89","0x4dbc074fc57c396811f3308929f1d44bdd0cdbbc38d5e001e84513a1b40019e7","0xce4c4d108b68ab5d8341c8f0e98882fe437428d8e71a74622ea37f968add8862","0x6d363280632c9b4cf34d1d7f181fb515ea4d5b9b299c1236766056b935c9c7ef","0x0db272ce0a0ea46971754cd77c36b52fe4f31c837462dd4fb6077dda52a3f9fe","0x84f9087054c19eac6da2e94e9b1beb3cb88b0b1fa58334097c6f1faa6d4505e9","0x1f5f3e15159a98ad7f1594bff9b59a2da4f57d11dde127679a8b0f9132c8b380","0x990936c0899c956b4b829656b24c56ac76dc6f9c773e70bf73acbbcaf539d563","0xd40a555d86eca8ad82daa965afe34ed125f9353be36ad6bbdb723b9d69e66aac","0x571cf6fea91954029aea836a1a3e4b563d292fe34d58ebb7371068e5b53b9a30","0x0a4534ec8038d56f0c77084fd13d998e0e84199fade858946e546655e7887644","0xa9d9fbd4f02bbbba829e50e807d2d3bf400ccd989b1b67bd79f6e5d282dbfda6","0x48cdc2882dffaa2b651f7dfac2646c17cf99a348124f60b61e8e572a342600b7","0xd7203ad04f96f9f5229b39effb99984dcccb8045f03f9a1fe56ebb4ca70a87a5","0x85a3dd5cd6ba0b92c5c65a3c06cd7629b5067bc44508d1828dc7e1ff567ee7a6","0x8ed7bb5ab80e356b012c736e945a62b2fc21b4ed3605899900f45c52495ee6af","0x7c07bbf940d2152e6ac9237a2cd06d5092897545961ef543a02164bb405ec536","0xb3264228f3482866e05767fd2cf94a7eed7b6f024434796972e6942995fc6783","0xa772f749dceaf6e7ae18b0608400b62d15db37d030345da319af43d4faeb499b","0x8f60d39eeac57c4f89723ae16a8eee6b062a02495c0977e70789add038e9c074","0x180eb8306e39512caed5d84c4f50eeb959ffb47893e733a258a4ac312dbcdbf7","0x7b0008851eb3f79672419cff4f1182526269691d58a0db366f38d97d9ee61a31","0x741545b2c81346ce94b5de8c50718d6bc9ca454b1a4a44e33282b0ad2e561868","0x546e544c85fc125408f9af802284e19458f66fe2dc84529784b10e3d929cf399","0xacbcf1b85dad0d8a1681f36d10753deea5d623aab6a8c726e3a22bef138dc07b","0x329b8ae4f10b82ae0f022c293f7b6adb6fa1f0afae81469d2b6c2f9210a1f640","0x1d5142b05fab574c9c41b46f2550f3611bca57e4505677863774097ec99d1324","0xb9e5a61b6300e806708ee1697fa19ad18f474146f8ae8fc44c1ac5e344e08880","0x4e6cff77d2313061fde5ee48eac129f8221923318365ac508e64f34f8212d892","0x599b074dce8f29514c6d624523f7d265c2ec444cf002ab9331d5ae348cf98298","0xb58b0d67619b7fda3417bddf65f6ebd531e7ecdbbe9745013c19a2ccc434653e","0x9edc1a9701dba368045609d957e30520d71297f30c038be3fdc38356c4ef6df9","0x001d14026cc055b0adc7193bd63c1ab2856cde6a288baf58cb1f53abe9730911","0x86eef1defdd753a93025651edb8ab1a1b2d53639825e27cfffb48298bd687082","0x4c3ee837a900ac0892e651b8c161e8999159450d66846075ddfadf7127986043","0x077bb34206e7ea5d0da627771d9033500ec52ee9738ab234b73268ac93c3cecb","0x50546562d4cc1af436da33a9e004a27515c89e2ec8f22d994e7c3fc64f84ff87","0x5103e25f5d173de1ab9b7a0040cf16f3ec175e5b17a170c17b823bd0796bb303","0xb0770b589864f8f46394ed7b274ac79c82affa754bba2270dc490519983e9c9a","0x1f6c22dc8853a923bbc33911c810cba4324bd153f266be1c7235109d265f0cdf","0x76263b1ade9130f5730f93f16832973028e9c0d4ddec54f23e41472199b57821","0x204795ed4e93c4258e3014bc7e9ae179de0b36a26ce7b47ff0e43fede12ec504","0x657b47e3ca098a557717f7359a4704ce78a7c90c6a8d5ca792550748f619228a","0x2ffe84df86f8e33726530f9066f1f4299ca9ff2bf55f436113b7b37da789597f","0x9afbf12c114d2a171b7c139bd008b53319cd218c841a84c852c29837d2c2f271","0x40a88e9b83a25242e85ff45f56e55e43903d43cfcea9e2b839f13a6c29ed1295","0xbad22d75f6e2dec3377cc58fbe8e7dc369dde9182b909b399ebee9c2340723f9","0x96409a6618697aa91ea47b941316881ddf1bdfb66ddf553fde4faac601a5cebf","0xc5a4f9c4e110da7ee6cc101c85acaaa02c651254aff73f5e725fccdc5d4ca359","0x01ae24e0cda191175ba1053826b26e3c538ab57a3190be66407f3d54a1d69025","0xfaff9e538ecf06f171e8e3e7cd843d2ed7dec8f58808ab74d6ea5d0d00f8f5d8","0x1b3e5bf56d1fb976e2710e3f349aa9373633b9faa87e4934a6c43454b5b23b2a","0x68291e6f87524bdc4965cdb4f279a83d710088d3d0de432d25f1b44602998911","0x671524fa76db082fd99ecf0beb7a3288425be0e798e74b0eba5839c1c6d810a4","0x046d739aceb152476d1d8e108b238ad3e1786f66f11c29e263b5b4276a55a6a0","0x5c88c65f496f7f721492e64b623263d06a7baf2acd4b18dac4a6e5f12924ebfd","0x7296dc7022ceae57a3a3b0a9ea0ef3b11469ecd245ce9f29e7e0a3a0ff3853ad","0x68652a45e520077d5536f9a71604e63982746be23a11a42fdbd1cf0cc5f46e3e","0x7d88dbe60f7174f0428b5677268bbd77f87bb8cef739fa02b12b6c5747779ef1","0x47096fc51448b41f2106156d02e66ecf22fa8199a94698a1149f50cbcfc63a67","0xaa6a99c08b33d1628acf93e3d21017d798a5f1da4487d067f398cdae91ea11e7","0xf8360e4fba67fc813a8a483f53b15cb2564a91cb6233a8894961eebde4ed049c","0xd599864911a86771515ee7cf74daa8159c0aba3c9ae6e6237fa866ffe41f02d3","0x64554ba5ed2f21917334fcff42f6c660258f728a9ba5d350159bb6773675c51d","0xad035ca8c60908b47a7c7a55975d4dc98c4c6e57ffa41e4cbfab7977dee49b4d","0x5ef394b9eeb8309db873134a8a8c0cdd8de830fac0c4bd1279f6ebe3fd66e9fc","0x82b13839cdd3b942ddb5992a57345068f326c84e1675aaf3ce87af0fad6dcef4","0xc151ea1f678e96df6018688f0c0251ebcd082d45acb0b6c8bc13bd184532fcd5","0xecefc907e4557ea9a6c3340014db3cd212f81cf1452cbdba0b373182809cd6f5","0x26528c01967703eef8d1704093a8ea86ffb202c4385b8dea0e88cca17f728d3d","0x55c1e6b82acba841889e7dfa8fdbe5bdaa542e8019aec951fe4d0f8319315c9a","0x58b10960cafb14f072fd95ee550f4e490c22e9e813badd416ee5d719fba2bdb0","0x95b5129726dc04b1e8f6d6a057cc63a9d3382266d6279184d3d7a8dd6d391a95","0x06ca9d601971754637f73d10169797636e77e059918e6a7de32f8440ffbf344b","0xea51b4e8d24bd464eb403bfd504cd1b097649154233ee632c0b69fecffd8e95c","0xca2c15cd5f9c8fd2363b9903df5f8613662ac31105e354d32705bd61313b738f","0x7864bd24662b191a72a50cd9979186c4475207e5558ae9bb5192d529a5834e8c","0xd3b3309251caac58b9d4fc947def5f436d58008dcf1ce5f10fd2ac83e69a0d0e","0xa49206ae1754b2f6c24772b0ffd385889b48e87628dc8ea045ea7c4f579fb5b1","0xd5552f5218220df15630de993811f262829ab1b183e9126d83c5109ede23c5bd","0x85a8d0e5630293155af4181cb26fe25ec7c5e246fa4f86111c27e45537f424c4","0x7a5c8f490d5b4388abb933c6c74926a80eda1d098095b1690fb4ba41ddbecbc5","0x3c5f409de2fb052b40fac4c9ae230875e88912d4608f9e826541417fabde2797","0xef33a2119d9ec2a73f9cde0215d36398e35f3ec05d9c66ed477a46895381abae","0x7a1ee08fab58ef9f46c8807558c409e9bf414a7f95da81c965ffe5036adece04","0x76e8065a6fcc4ea4ee8d36d221bdff0aecba992bc65f6206dfb49ee73b8d4b54","0x4ae401a680c12eb5bfc3c6461b3f58be8ea4037217602713c0c79772692fc9e9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2e2c42eccead653fdd607f8ef2ae694da0e63c87f5a655f66953f08a63760ba0","0x87325f1d165c49c56760894a8a889cb5b3c10d3fcd6e0135ab41e2587002e45b","0xd363af114a43cbe7bb2f16f2a900cc01d8dff0d922d17fba9040c8eebb6b792c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xd502968da6a2c8d5f7df7acef2edf643a03a72b8ce19efc65a02a2db11abfdd1","0x99650da1dc7ddce021b909cc93461a68da461ce5bf4787fc0fe088fae95e1996","0xfceb383b98d3d320380755a981b8718a728954e23384cada0e6a168ca8efbbaf","0x7ba1df973e0bb57793b0d15f1c212ff34e12509ec9537b9a24d143e65bb36e23","0x07573bfe4c221d12b8d6c8ba26a7c78c3cabe9025ec423e957cadb2cf7f688a6","0xda3e68327aa2d1e4296fae3a05973f18ece3e453d0443575d5251cddb871b9ab","0xd005f6d5da1071d62d1dec652a757b6024e6f1c48553833367aeb8e9ff5bdc7f","0x5407f1e88ecff2490343b449edc2425773474251034c2d362aed1b7cdd8121f3","0xfbbc989b2d1f17c0fdeadd1842aa1a238c5624cdc1a527b8ea640b345135c2a8","0x15dbd0440e37cafcb6767c8998036ede9a60010582f0b8adbd0e02eb6f6cef98","0x08e74158d34a196635da6145c20b52b3fc0040191602d0bd17cecc450be22384","0xf48b5862ed4d33f67bd2b1ff3f47e565f1c4721fb62522e7daee52b09fca2fd5","0x25b779e64206279c86f6847bb324be225e0ea736577e99f647587fbb273000ab","0x710620297396a1d65ab36b2250a29c082e385a2a435c4c7da279aebcf3e534ac","0xace0b20de07d091e838c5ae6f7ecd0822add2384c402d5c346dbf278fdd212ae","0x8ecb8c2ed191d9e5a4a12944227366cd136795adc10c7743fbe1f2906ad4306e","0xb368a0c6f0b62f7c89584687bbbafc5799f32efc984b8b9805e93d97aad75b6c","0x5cc33ac74b27b41cb1681bf7a774c0921ee92c0f101e967079a6b879cfc775c1","0x44a6a46b5f6fb160916063914494699f8d1e2594d9907ee13aa97e8c1801a514","0x11eb8e008c375bd7cff2284b6a3a1b765cad86ae7c671db2b047d7575d249468","0xdfe14d157d66529824ade6b09b040951a708e106261b28cbe5b2d93cd12c1969","0x03d685a4f9ba6ba5b94bd158c719fb0fee1e0d370d68ca6caa6a151738625820","0x3115cc7903b910248fd3a25e857270abd47bf4e999ef25eec653af6ba2e201ea","0x946dbd95352c43c39675ccac0a02ee4622c8247915bb8df64c0cd934b9108147","0xefb656c39e008ad45c11bd364d7c3ffc555c0b775fd6d9db789918625d136435","0x820f4a2493b1d02f82ebe17c836c36f98355ca13e775e277b43c5982a7b508da","0x999ce987e88cea25958507f8e81ee2f252a21e75aa1843869ad3e66c806bfe19","0xa7684eeacdf665a94477b1eddc58e8915b98f53c75aa6fbbfbda0feca7209e35","0x2fcc84cb645219974005f3a7ff851c15b414a72c298c112483ed963d767c5852","0x53f3640f7aa5113d5c1683d81afe4d5f67f3a7b1656fe40f95d5355a632f555c","0x0f349e5af82ddb761848f59d277caf59964e716a5c9a277606414fe6670c2a15","0x5f18b3e8155961d5f027790cd92d758aa048392a735e199853a61c055c7e0148","0x1797378d21f30ab8f1d0d5f02bd0af694195733ab9d99ef60aa996562026a457","0x6787f4f18c766433112b7454edef427030dadc4e6d2378f581670c662c3b9f69","0x1ec5a2eb4e717f08aa2ee2bbc789b1928c36ad1e374df758575f4eda2a74ca54","0xdf590ecf74084bc78e0c8198711ff751a6fe14ca5e22069d74c1e35de89dcc99","0x02994da36ca85e0a2b5de4eebe1f9ac748f5a6f3a3a826e75c1243a1536cead1","0xabaf9d19e385c6f58aecf36bfcb4d402752f792cace10b5fe7d341c320dd2fbb","0x8d5d57a63dea4a6c0b28d41a8b8e8458ee7c794a2d0c7d41e3e3c062696a14c6","0x57ae83a5cd07d7cb028ed49f0af4b1c37178d42a8d24e7ec3722445a4756178f","0x7d394632145726694940f98f61187db36b9ce37be98faf0b99c26c44487fee0d","0x4bdb471249c02de6759504690cccd91626772eefb752bd252f2bc66f2d67d814","0x7195b1fa4494a77ef2739366ee08251213ab728fe5aaba0abfb365689a3a306e","0x621cbd0c441166bf4858c3232ed4400336218c88a936dd248806218cb9e7586e","0xf0f827b3b226cbd472bba592256e74427b20f997b359d34c40450d070b027bb1","0xdc870ceb8a357ad3be1534161d03ff9eb342c87ab812b2e0ea9fa982f4095c5f","0x8804ae0b41dc5a7b9dfda28da9dae0fa4dca401387053c3b9b3a57f50556c5c7","0x098f1b0f159797a4e1813cb6e810ce1f47896cd0c3b47dea9856c77a2084ca64","0x78d68fd40b04d78c7746b328f18c742fc1faaec169752c9a07fad2a8cd8f42bc","0x8af5dd5821f77de755ec1c2854e1a9bacb1ba5115868e0c244c4b7461d2d55ee","0xafcccf2019651e08bffeae9eb2df111c5484a3c3cb147764ec232397a07efe3b","0xa0bafffb3f839defb9006a1c96750d6ee55bb5be41af54fcb16d3b016336e952","0x74362c9612ed6e43d815adc178ad2c2c16e0da8998728f31f774a79782e6892d","0x5c27f74b8a41599a318df3fc6f3f695589c6ebcc05cd347fc0c8344dc23d4d38","0xd3520e73893b1ac38da20c48c159df54958345f9f78823557eec485eb3d31a4a","0x41b066e5107a561653ba2250bfb7cf2c207f1f705cc07782a22c54edc1b445e5","0xa3e6eb18f85778ff22a5e11336e00dd830195a85abca10046c4ad14f742c7dbd","0xfd6af6bad616a6c0156954be5dd034a170b3aff612dc0bb1fb73c394d498510d","0x02db06dc85612d6d463b7a661bcc9b53ce5856d3bb6d0c24d8169c0a55aa1f0a","0x79dac0272345cda80e128c81b9b3275b07e057243326f15f1b58f98c5cf8367e","0x85aa5edbfe2d785c0e8b7a9311c0b8142748cba5028c7925bb75889785562ffc","0xac28dc5bc833f665adb7afaaca000de9a310118fd9d77d21bb0b651e9dcd4b7f","0x8f5dbfa1132e1a60d87f92150ceb79b0e3e731f35e84cf0d761e4c8bb41db79e","0xd96094576797c3663d850c5a1158f53a653c46ce3c7ae01d238c8870af8d57bc","0x5ff2dacd355f9ffb7852bf05985a9876ea86a7afea30ff47fc84c04f1758ec2e","0x49e4d3386c594dc15a6e0043629706b05e4e09f11406d09f2804753c378ccc17","0x35a0f73a2b8690bf5d313640ba09c29e70f1177809c95e5c2435ba277ca70a9e","0x6e1f623ce83157133d26cd9ec6d2f2e18304d5638e98f7e267e0a2f77d3e7b31","0xdc3bfef5c4136de046ed22821c51d0100d04c69198042404edbf8a677470849c","0xf84447182e13da2e6d492b8a3f875f4b2f197550ae012c943fd25358f269cf26","0x0536db535501b47a14bd9ef6c39b437e2092fe54113b96bfc0463580d41ac030","0xdd8a527b5ba1ef234f7aff32d0f3fe25fca7a2eac8f376d2e2925feebc1c2648","0x6711289e0c195c0b1faba71bbe9224ae7c843acee3592bda5d22cfe7f456cdf9","0x314b55605b0ebc019bc5892f0aee1e528b70ad97fd6318d2d39fb201185b87fb","0x97dd043dca630574d7c504fd325cd06dea3809faea0852a4d63ebc81f452f488","0x31756a1330fa146f925d3548a6898141fafbbd3b173cd1843661fa4d25b1e6bf","0x9bd97a077b61a384410ce34b78c919506f09de71ae538f5a272a6a787277c46e","0x02133c34052c90f2ba8bc5cbad3631f794e615d5373d5ba60147dcf2e381dd70","0xdcacd01ca9297d71ad2a9ce6afc87ee26b6728aaf26172d0aaccb3a4b690a8d8","0x1c6b0debe38c80c853e3e24bfbe9c67898aacc81a8d1c362af99b7a6881cf58a","0xd90b72ca9d6fea6a562c9ee303264da9dd9e8cf977f14e0fb80a4a649a342ba5","0xd57bf70d420d621c132ed0a4c8f9a82a80b6aa7ad471e287f6c70897071d67b9","0x18731f231feb8edd5643a3cc7e8921827dbe5d1e91829598bf9d9ba31f976d9e","0xa7cf974c5b1a466edd281f4ad7b38310b316f99f0acd8b2cee3a96e534f5a419","0x6a081d88c38f2f7ef86337fc1e3a6321ddffda3b0c751b234b39f938b51596f0","0x2f1b44b0e8973cb17dde63c43e93f9700f8ebe8adbe1d731b0683ce44ed64dae","0x4c1596f0f9f877a8fd0b58e05ed70daf8faba061b88612da09fdfda51cdafb36","0x9cd48328685fd9a9e11ea75fc0a2ee1cf0cdabef0c02c068788225883f9dfb0f","0x83467143009f060295eaa98d83f6df0c0a1f1e30a69e1d6c24ded8b7efe251cc","0x17f818d947590ae83b035df93dc830575144a16c0e2cdecc252b01fbb9876d17","0x437d9a2d177e5533e02b4ec74c93cbd9d265f7b2655bc39ead25f6779a4bd3bf","0x1974ee99970a99a724bd2dab0f4ef428bfea2fd391f38b83943d5c3d43d46423","0x7a14b3db1aa5353ff3025ab05fcdde6d30921341ca9870875602f597693ceca7","0x559d698653cd8cfcae76c151e752a7d7fb060ef0457b2d3e7566bb2821bf5cce","0xd65b739136862e7c8e1345a20f991b1b68a8b3e9ce3ee97fde3b5ce482c84c30","0x92ee1dea9bcfb811b3edd517ba3f15ba3ec676f7e222494f0f94746bc67196fd","0x87e58ddbcb31920900291ec2d34a854a87cfd7c4fb692e0faed08427846bc62e","0x7a091e5673d923df1f9cbf5bd1a0d6ba965eb5791c531622d3408614af2c321e","0x600139324f3dee665878d6fae61c0b7766e49789cc4c51278da4d5a0bccb4fbf","0xdfcc55afeaeeacbd39b04c1c3b7270c9027a702ce97a95ad8a5f017a7b5823db","0xe62b3367ddaedbb6d2fe3fd41bc1df388f0353bdcf1ff7bc85099a3ebe1cd2fd","0x8e0f7cd103c8d2cbb9f7bfb93acb40a6e1bc649731fe9122969f3a36126cdf7a","0x98520cc21bf4a12fe3176fdf615cee07187bdd565030e71066193262877a31b4","0xab7a3e63692faec1f238a6e292d2ceceaeaf0532ccab51da0ea8b2686e5f0376","0x09aca83259d133cb474a9d3f5f474dbf3374ec450f969bfd280d801d8b6f51c8","0x2005d0e3e80d326f59b2800c89626c924cb58df1c4145ea8886251d572e75e87","0x7946e6bf1a65ba0b5ff3d6a848cdac235f5d8aa21ce5a6e7c31b31de470f1a23","0x36ba850cb5546aa7dc5c340584bcdb2c4b2e60ce357efda6c7b8aa2be104a133","0x86d0e1b14392a384f6389ace0e48f97a51baa14e2ea2b0724cb5c4a887380929","0x0f614b5160d16370c62b64f76069267a76e840e8401ec4b88c87e5e5b3d20f27","0xef945951f3b9caa7d77d842180fb409f6ab479b63054e756ea8e3c15929eee6d","0xb2a2dedbf9e9f882bfe44e99a84f3413560dde3839151f9b69fe6b09b99b46af","0x26c63f29322a7c1595e099b85c9736680b874cf9c934b6d42e2cbfbbb0ff99c1","0xfe434c7facb6060f14a2a716bce722e89e10dc319384d6184084b628a3baa11f","0x09acf6b7f073018904f34c2086ff3b139bb8cd7a0e086a6ca9ab9f3daec1c7e8","0x365aad9c52ce316fb91888073a47228de95be3b3c2b298009db9b0ec41ccee0f","0x794028d2f054b93f12ca4e747897eaa29c32451da922fcae8cf535892be490aa","0x9a9f28c4635c9fffcf598b536ae8ea5278746d38f389774a3f5f7909e0f0ed6b","0x87e1dfe6eb1a2cc5b1870894b687069fd03a5d120d9cc7e86d5792adf06f8852","0x17d6d8b60ea4ff830f18f9e185039bdbe6bfedd40599b5b824763c7f0b4f1f6f","0xad2a1ba83dfcbb3e2f01cfea221e3fe2a4fcb51e775d20cc8ea1aa00768cf634","0xb0f89f1f4f6d744e518d9be884ff75403ab133c88fae30216f7fefed33db2e39","0x16ebca101ec95f258b9580d682be29b5cd7945809a33ce15391514ae70e4d785","0x235499d2dd5d78ee272f51ed068b8a1e4c27e8d0a734a72b8615a2f6b84850b2","0xe7855d26300cb083bcb17c817781299611f795126bb0355152193cab61acf12d","0x2e177aa1bc50af95c6b4163ac88e51a2a1a031d4d45fe1e3542e822abefb0b4d","0x6814b282e03fb90b9bdd71681bd3bb17463f95d6af25ce77d165495584b6f1fb","0xe23d23ddcaf6c2e10b1c90d61e12d652442f4264684e7824db014179753b17ad","0xf3ff6951f14cafcac2eba1a84319068134a8d4bca11fe8aec13ee65d8f597f9c","0x3c7e964d32b2fdcacec28c47479ea873ddf034ea2d38bbac430b673f1d65e394","0x44730e74c5d47b0e7b23e0b995991a792850acc8b123b9399234f2fb46454a69","0xdc3db41d434ec3b84354d291f0638ad45a4531456913011dc94734194bd3bca9","0x787977b130ce38cb7f7374d06c5d2d2fb423866a98fb13b93613e3eb6e1c8fe6","0xc18391e3ea46d1091afb1741433ce91848a3f87c4db8efe57f70f3c0d465863c","0x942f2889ac61d43dfe650af9b3805949b75265f0eb6698d7e9f4be3ee0211f26","0x75b3899fa43894dac7b5a2d0d1f4d8386435c940aaddfaea646a6c4fb2da2ce7","0x6873724c8a6ec643a6350b1dccf4bd98cca018d36b8454f3293bff5436b71dc8","0x4764ec04302577e52092e456686e54ea613fdd4c6fc36688163edfb7b6f01e10","0xbe9cf03763582b017c0a5fdc8a38201f8a8d8fc4b3d873fdd8c6cf7876232fb2","0x3bf5135f5426f3f10410253ece7288aae8bd0bbb3d911ae30536f860e5f0d877","0x669a7dfda24ed9fecf9520bf4bad869fbbfa5fb437e7d3e82310801a66102458","0xba5876f2f5b9579293ff91ed2e11afb34c4324b068c4e072626280f263e1386b","0x8ee5bfbb1741f58ddfd0dedd34be75e95d39dc0bbf3f0484e76dffd63d4b8276","0xa06a84a39614349462c80602c6b0e397ce27191b64a32709acdd8ab90ccfa185","0x0e653e516a81cf43ba4a1c15da3468b8bbf4b0c5e49498dbbf4c2e76f2e6c65c","0xe7ac8dd7ee15c6179834593fa95791cdbf28284d2eabe6514ee0fe86eb8226a2","0xf4cdf27876144d80314d692ed659cc79bc579f5767be7b2713b13b0a1de6a76d","0x71d9fb55930c021d913926fa5eda52b8e886bdafdd94c61aaa8168d624dd7482","0x7039fdd58a9227a047447fbc86f04b786bb5087a3e3fd498981135fdad14d0ff","0x2cc8a69de5d9312e72287dfe5d4dc7715ee2deb45fceb9db436153b6d2f3f9f9","0x86e89634efb77ed0c30e0fd0dd212d6a9666645ed6899e6f7604357d0d07e309","0x6f7817a98345ab0b3064933fe6bfe5dbf890088c3b8d578725c27d5eba4ae99a","0x48ef9adb30ca176ba9be47123d47beb4af3b411f41f789c7a011189bdc070b6b","0x6e139174c4ca3fb6c830e27f907c3985bbf66c0c789ba852575c4b13bad3a0b2","0x07554a43beae8c824a9945a9f63d43e02a0253044a8f7e19c011c49df37c72c9","0xe036b0bd7d54464a54b2da6345251738906fb62f73a9a571ecf426f4cd8c429e","0x625e500bb89257ecfbaa99ca5b2119d2ea8aa422350486ea26c6ee0e57807cb0","0x03c3e0b9eb58793818b6f0194d50346fb0715be86e1e21882de30f7fda67ffa0","0x5d8bbbc977fa00c38e123e932e594f29055008ee76f82dc3847782b38747653d","0x4eb1978684af5af515b402352e4dd3066b72fb8003515f34c6de13f69cff2884","0x2eacf95091e97bd7d7960646ca68d378bbf323ac23284e6fcfa5ddd1c78c4f43","0xa1b856a3beffa790f4915bc4b2586462658cc587bc81393b92967b0362820755","0xcce1a255f73998607ab9491b2ec7826b0d0cef958830316a113f38cca17993ad","0xcbb205a3f5d969d21d19081de2f7aa731e53a4175d2bc4f0e6e3a65f47916ee7","0x34c1044b5be125aa4c37f33ee5e61fefcc70955290e3dc140c1962d6422c7bca","0x95b787300a045481c32ba18734ad6cb7b942c2d59c40805f80a1cdd7a5cb43f7","0x1246e933e60cb31d6a7164bd269c590eb4c4dbd0a75aea834cad0c717a307d20","0xcdde1aafdd422127999507522040df4023eb59a4c9fc23d7cfcf1016584210cb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x40db4f375ace854ebe54eaf170aff037c77614242193a18110da3c51737a4f69","0xbf32d74e89cc9141f7fac4271da021a773177055549881d5313121e31ea6c756","0x745db716f6d9adda8d8cfde44802bfcddebe797b45269a2cb58aa2494395178d","0xd61f991153b06ce2e77283462b772690f6f3d4b67d6eaa1c743c9423a08154b6","0x1ea8a3c559ef45ff4601959e1db02b0202ecba2679bc1bb620bf54b3570ff4d0","0x5e24ccf502bdd2fd521aa9870213896d4ed37ffc7a051b0909bf4cc7c9df5659","0xf46cfaa19960f1b77e78502b95ad75f10552442f831c167a7f4b1ee4c7073577","0x25e09ceff98be49d040cd5d1e6c180267f28a5598e7206809189383cde3a301c","0xedc9130dbc95523655259ee1d59619d6ecb23097da0de05bbd7de71c98d5f6a4","0xc52efb08b800cf6be56d9e5c4f2fee44c70d12f2f1518e4fa8b10c1e637777a4","0x55d4e90a01c0d23e4b93c191e64c5e12f80f76d1497250b86165a8e40f0418e7","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xc45479349b51241d85d5f92064c5a7f86ab665523867e0764a01049c5be57539","0x2d358ed97d5d7967078eeb90db2bab69ad2b992aefec1f68a149b2d06bf129e5","0x791f55cb287708c53b5ae5e0d4fdc4cc6649683c5daf05da3a43422d535b966b","0x7de4dcebaa9cb109b42dec24a53a55667cd93200c8c61e0ebd34e4c2867d9258","0x3760149edd7a8b51a67400f422db7cc214905532b812db8f0f94ce58ca68b902","0x39171fc56d2445101400d1fbed2332dca3c2cc2009887d25e1d96a08851f95fa","0xeeff7b03557aa5e269e1fd3ba6f1c33138b1c4045c01058d79c8e8e539394fb0","0x67380975bef8d53cfa1216451c591861cec73ca376d80cc1cfefe489c5a065a8","0x14faed502caadebb00c5e3ef6786e816d00c6a62b3e594e1226ca11b5c260377","0x92a61ca0e28d4c6e9ed0783014554972f6373448fe5df17c4e6b05197048b9d4","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x322d975849cb3493e711756cbff6c5040cc203434cd3eb8d5bf73e85ee989e04","0x6c054f3449cb6df8c3a43f33bc1ca7721e9ae483f8c621c81c7f2aa5982fc444","0xe8f5c5bc9a454459d7676b81cbd54cf93ca68a1ae85c082fae1f2779fdd0e019","0x65af2f5ce7da4772fc86387e07b1f4e7709b30411811307e8815eedb41b4e13a","0x45b1e466f32ee4eb8b4f6c9937a717f85ecd201e8d9b78996ca41a7eb31a559e","0xa0f9a6a93a32a477ecf585302f866d4d77ad5e2e3fbe33f2a976df2334437dab","0x12436c4a525f95cd1c9dc54019cf5791bdf88d2c94642a40ffe7c7eeb1ae011f","0x9a57c618673af8f7be3769cae217159ce885e689a4219efcf3d03b28118386d4","0x0beb6a91d12a92cc8e11444e8a71a0f318ab19912b5cd5efdf86e5fc932e93ad","0x07c9978d480f8f488e8ed0e62cf8531abc59dae639a281ecc4198342423bc882","0x8b927d8cac1b2708196ab94f13f2cc99f787b0f50671e5bf14d141029dc15256","0x58bf5903f71a0042af5ad02888fac84a313221d99926fe0fc78f54c77fec078c","0xd81102ddac5c6066862b986379f4651cc640b760a7e0beb901e138306cdc1ba7","0xfdb6ccd49352a32a5143fb1ef24243fbc282214333c9bb85d4f169002cd5df6a","0x182a7060a54b13faf9817752f15ebf5868e3d1e01281c71e2e42397a984324f7","0x50265ee271bc2da562277a9b535425f320877f8f1cfba05c39a1c83fdfe19b44","0x9b3983d8c718566f0efffbbe0efb61ea07bd7582d65632afebfd5fb3fa2fb6e7","0xb6ed8050accdabf950f9ec54b8adb59088210f7d336a560a0c64ea15e19f5c20","0xf2889d9261efe280142fad9dda311ba7f5fa4e75d7c9b00dcee3056ba9a8a8ff","0x10e001dac625a62b06be1e504605a5cf60afb7b9756799b011800cdef9d768f3","0x21f960eb7d3be120bdb642fb51757d1c31317273d54adf6b7621bc045bf1641f","0x3344c4d9efb98aaded9d30f5e8ad8f8f3af141cf0d62d47347660dc9f270dc6b","0x059378d127d9b9041ce178b1a1119ff42a8dd5f1b1add4c1d3b32e9146524faf","0xfd5263934afe074420f7ecbacd2e59b8b82afbecec9ae0c129a09f8923363c9d","0xae0926f078b13d3de7a68ede832e173f97e904dd6f18ce69667074ad1840937c","0x615d7e7b7267ac4f98929afc7a86d399fe0985e34e22812cc9a26e27471ddb3c","0x9d17cf1c1673d622a221dd70724139f9adac910eb192839fe734678122191fc0","0x75f2016536bfb7e185d6d486f5f376835cb6de18716d966dc4a8e824912cb848","0x547c7eda216b9c95b639a86567164fcc7e8bd9169273c2c703a10f3ab2974f18","0x92f15a41c5a1d6af7aa089735793558e80328687c5c2dcc419f53c7ef2fd30b6","0x25bc29f20c0ed7819d494f22dc8f78f42d6559f5aed76112adc30cceba6a5a23","0x4e510c46758ab6c5cd842e8c961ecdd47d2fc4c72ca71677cef184e1f95b6271","0xad369135dfbcf20c638505bae5df6ea0c20de8f18b5154195aeba51a1d9fbb9c","0x71fb616c9d080e3178b58ddf93cd997081e9389943812cb1e9101e51e81f6ca3","0x38bb45147c34aabc5b9f53b0db32d4272ec654d318051a100357f666a1594d8a","0xba38507c96ab6c6fcfe9a4b8911e94409b492eec113025d7b99cc90d4238f8c7","0x20cf0a3b334dcfe979017aca076537847534e6949a6bc61f11ef1acf4e607172","0x505c78bc85b4b835e27532e3625bdfa8d6708a04bf7213d4cfa4de5caf3229d2","0x68d63535b10d06cf5136a7d71e517875152e8ccd27965787a1c59f6c50ebbec5","0xfc4c944127871e21c06715bf3689292118c8ac461d2d55f8fed10d9fac6ef5dd","0xbe033f1883edd5850366a254d34a8d17fa44ccfc5f7a56ea42eedf7a869d38d0","0x91dfec2f6c6de5a1b2f3a441cf90b24c5d1c7c187fa0364834db93afef395703","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x019aaf2332ab053c4a86d066b6fb1ee5a8dc5346a0d65fadac3eb3f8647f1ac7","0x65bb3d762b698a441452e035d8c4cd4181f40cd0e07f3cba53c2fd48d530b588","0x2f78fca2d6b9054bb2dedf8880f1321817055af5818519b5e33d3fff99309e1e","0xbe04cac03173a37d0dce34980009a76165921764b86d528f6ba6ca95d16a3710","0x70a795ebeebeb4565240112012caec564c8eb387b9976f1894ab83de9fd996a0","0xd7fce8c2245f3a1894661635244bb1850abb2e378cc5ea7ee16494487296d395","0x08d6c6069d66455f1f5881a78f47a240fbfc898144c6ecd418a689dda5d258b9","0x326e1752141ec291c9f5f90fb9f85cea1f041a7e3f58526e9dc729ba2c65c83c","0xb78fd7a64b889488fe5015dbcc7d68465d917f3b7309308adc3f18a9acb49d69","0x11070df09d0e2568022320ac64c7f502e6ee9740697cbeb061027f57560e99bf","0xca65676545822d8ffe80ec284bfc3692aced8ed47bcab2bbe36e827f712c078f","0xda748b3beb34e83c2e1d218ad958c23c68fbeb18f1223a1213f591836230e211","0x594f15627213dedc496cd3ef1a1c9cbb1699959abd902376cb80e63304cb384c","0xd785ec11d482c65c60af299a4ac4ad29361a004686bd83f0fade24e11fd05b87","0x69911928c48bf5c592a0f9cbe5549460ca0946eaf673e2ae995b8ea963a77aec","0x8c71b78bf00fa11e8e0b8cb6a1e2b35230a20585da862c7a10f7c7d81a5e7132","0x78c8373a652d2a01f6e2f1318e305667149fa4a2d95928c43f9ab182391d503f","0x58d4f22ef27e09b0bc94d9356647aaaeaed30411214b0b2b3791c852670b10f3","0xcf6584aa116f6231c3ee48e814bedb08d4f180ada6a1cac172672c988fdc11ca","0x982c2d3acfa1bf01b41c4ef63821a640e2069e5786ce09f229f3f625c16e412a","0x5b2a3a3ac2494017fc5ffe0cd05ea790a9ae02a5a927eef7966a13bee3c0ffb7","0x1db2d4e92c400d02314e34d3ab999597d9c928c83972fb20579a55b46b6eb5ef","0x5186d0d06e33c83da1be241bdd9cca8961aed0f287c3a3a1c7ce0f572f34c3a9","0x9aead265ac7dbb68e80f664c5d6ca1c7ba44b42476d4d5cd55772ef32554aa65","0xb514eb5c61a058bc778d7dc9fa7f1ffb3387e957b4fdf5f055c867affa2fcaa9","0xe5f38c76dc94144ff3fe9c0c4e56e4c05a7eba6e578114077d2487f292dcf1c7","0x916a9d4dcbfbfaa48ff094220cebb45f6191d9b6764b3b34f86f5521fdc3511e","0x452c7f2be2d3f2c890aee15a62698b442b250657a66b32c09bcf148500ff9659","0xbcb82576a37024353af2788b7accd001c55c72f6df164dc827bfddb2eedfc2ab","0x3bb4523f676f0f0a80e34f9230482ef269bf1e237b6376d6390f7921f7c66082","0xad01d07a7a580ba24bf5d71b59970f02b8557a978a89b6ae1b9254471b4c10cf","0xfda0e61ba2e63e18fbc95a03557dae966fb4e251d82490029dce54b6b78a1bae","0x6d1ac618c8da6519ef2810ef6156035e207a4571dc95efcef2e647449988cd96","0xc8a9bd5da0b4116081b5654b809dbf6a4c8fbc427f73f8048ec587d54a5f79b2","0x3907d61fc43b86eaff3b920f6a014c962381c1b74a9840ded5358ea649a47502","0x595947c94969516fadf0a5ac05ec02da60bfb48efad246754908e95456843642","0x970b429cc431b247336d983d712634557ef57a73fdcf4ca646804c5db3be4054","0x4edf44079a86c8eb8b55f0fa714a8175567523a3c4a9e1dc0dc63d8ca65f2fa0","0x286c8af38613a3402c542322b3d8b05116c6925f812a85213d2e5ffbc78c3a88","0x603767351187c4ff840e0594562257dba3da0e48a6a75bf42c07ad43191e9078","0x66c9cedab50b2d0400d3039ef025e10918fe344ad1ef9a54e0b180a81eb380a0","0x2ba80b55339ddb7ff9fa5c7134a9bb03046e0ac43e86822c86a0421af9322ec8","0x312d080648a66ca2b6428455b9cc72a472bd1c21fd227647b3297d2af1eb97aa","0x0786c97cc534f669cdc3d60d13088fc874cfb24b48f81cad0dcbf790b36eff28","0x3c351f641dce3c743d6f05b6a8bc99d390f88f1ea1fd06ef3cd34453deb6c0bd","0x13901712a6c1e6f1b6037345d604ef24f4a35fea0c899e53b2d0477dc5d2ffac","0xc714f894a62478171d2b932ff29b6eaaf002671230c8ca413b0ed7881f67a127","0x8e2a270502b7f59f627e038b173da665a4bdc6fc8f577a98b8ea07f4c0f9a2e3","0x20b6d420cfac9bfb8038b07fa36fe304b5a10795834af6823c640d9bfed31131","0xfdc7959f892ca4c99955b4740956441ef16fe69f431c71dd885b1e2cf9e74132","0xe68064c79213becf647a8f2b9f4a5aa949f69c6266ba9a444b8a9f489ce86b15","0xcbf8ce43887f8478961821a107117c6bf2a7fc3b1f64c55965a3fd211cd84947","0x12c69b142eb84896eafb8ec41008bf8f811b3e0e870297a5d3f13a587d626076","0x2ab416582dabb34b31313bf14673a0475747ced0fb73a53dd22f3a713f4f5677","0xcd13c4c8e35e5c6538c43a83fc96e5166fc61b622f8c788552ac7b2f2df2b40a","0x55dd854a7ae55897e43787d99ef67c4e28457131e5c41a4a46e5f17bb71c05f5","0x084e023e5761ceea07de9cd279f5413e6ec88b83588ba6773301e8f3d4691fb9","0x42b3b89cc84c393f688edb6d9dba51be10e8bf534296f2601c204930fec4e70f","0xc740aa02d35d00a052a2571d1ebecce0ae7f2f1073a40c2b9f64e9a0da0d7185","0x879b18ca645dc8eb1e6bb7531e07d6f83bb2dcbf73db31a09293de2541f524e7","0x5b4fe188914ba6c2259960739fff5ca019a2725a378783a6795f17dc5a6bf154","0x16c2b6ceb71c93d091ce998b28f666d584b30d9eee4f3bb76fa706d313e3e790","0xd9715034b125a21627de2edf1feac77c495a0a53f684d515db289625401aec3b","0x1798f4ce1ccf2e324fc41a611660246750c508c83b808c0d48624f9e18ed708f","0xae8b1c4daea27bf9499c9cd3ce4ac10267602223e0d9b1625dff34bfcd0612ca","0xf9b45d2891125942508faa2ce81d9b1c5072e578a354536c878170b967b20342","0x43555b852cb38551262f268ad1f2036632ff28058fed2350e9347c96fcc09d86","0x31e4911da8d59afb70023d2d06871dd58f4f4f07c9bd583ad141b15e4757e075","0xa216ec2b06d9263a69ebe27cce275a2e14444b4de308a255e8a91edaa9f2fd34","0x4e1bbe1fe87d8d66091fa49703c588da64e9d55d21d04c696bb07897de4ec45e","0x5b8224b5b79fb95d339c914ec4f4105c4b557d840113e25220c1d2dda0ba1ed8","0x2e83bd0f1017b6fa80c0d3d1bada61c7bdde1dc974d12c8194cf3a4dc514b188","0x9dd90584b7e667e686ad6f1c175f589784128a507173e66ed195ea8f999f150f","0x99d086d09fe28b5d24368a00d05ac296ecd9daaf6a6f2f5e1956d1eada2eefd6","0x3e9f681c5badc46242dd11f593cc73cdd94c6dfb5df8fb148862d3fa0d7a3e2b","0xf79a94ce2b0992f8a4664a8cd169a65cc6950252a96f3389d90c682fc2d48914","0xb3d1c8a9eb253145720256ab1e0e8c28d81607fc1f4e0216b70ffe594754b46e","0x66ebf087bcdd58d3a7133c30c63df6a87d8dfc979d9fec79ad1842a270e8f2fd","0x1b3cbfc4c03e873f34d4f66def97fc52a1f871bee18cf7e43a1f0a7d5c850cb7","0x22fb01c07737411998314db1f4f3e1772ebc3d873a8d3dec6358a9ac58ed14dc","0xe86b1980117baef47516c21d6c1c5b33ece5041831738fdf6bc81a1872d4a557","0xa5fd232b6f42ce7c9963c47367aebe53a25a24acb741d8dd261f798fc48d09e4","0x5c3cbf000f7e06534bcc69ad66a398ef6f37361d5c096a77774d8b37904d7aca","0x4dd591aa04fd057df8283913409b7a668b046a819ce2faaa52d706bd31b2595b","0x2cb29a77ddfcf21a86cf8edf7d3838ccfb858b1ca18ff8d59b7a900d0a20ba24","0xcba2eaf80de66d5f09093ce6832d9ad541c4b2b4923a7ed6634872d507348d1d","0x88bb804009a54beabe06ac393980febcec6cbad725236b5209fb7601308924f6","0x9a09a69e96686c6febbb37feb2b43893eb610d36a1181923a47ef4052fae9892","0x1ee74a0468e6e1919f91c46ed0fd43310b139b8c7fd9f79e270ec236e27b21bd","0xabc034c5cf8f3fee817e900dae6e0612b3bdc9191509ec60408d8c88309bfb6a","0xe8a6717710a510cc62a31a78b4324200d6efa0dce9b5a42d540bfe3b0d860403","0x13cfb3169fea8e1d674aa63cb2015bbf2a82c427eb80f206cb43accdcad881e4","0x1573d9c8b90e03a40fa4520f459cde4cb97a268b54fa100dfbc7684bd82552bd","0x832d9049e5fd9b70ab3f64c3515c40829700d5c7cbd7309d3d484631d7120dc9","0x6b726aa356bb3dbdb9ea3502e4b882be333b895bb7d719231e7752285287d96f","0xa86a125316bb5b501f39f061db4e8eaeeb880b6e3c7e65f948aefca578cddc6f","0xb3b58f1344b3db2790678f6d3d44158a20347d28a658d19eee8639348718ad65","0x065345d4405fc25fdac3492392fee7588bce08b7c98d8ba644113b0970e6311f","0xb8d3fdc8c445ba5e908713b6e8049d1dd78f13b72a01530b3954e2f544835345","0xdca3f6453ab99724d21b1e76e046a1c47d288bf540ae317e8e1b0424880a492b","0x1cfbfd3fb52406d1b801892d82ab6113cef8575774d5b3cba43e9b31baa52317","0x48e0f7b1c51ee8b288ebc3eea7abf2fc5b8bf5ebeb7d23dd9e97bccadfe4b831","0x485f391366c4246ac44009b43bf131c016ec840e24639283798a420818602c29","0x68f8914c825ae354a239e36549dd80ad8cdb901d8f06014039461dfad4dc5d7a","0x86bb5d58cb1900a8dc04a375c929c105c822aa20a32e6bde7e4c93b7221e14fb","0x9ae536240c8aab43d1bd3ca24cd1e4e20a4f9318835e5df4927f78006e3abd73","0xcaa9a9fcbd250497bc6b0cf984b96a67643fe3ce476e6cfedcb43b452c3e543f","0x61812b050a1223e3cbaecbd0f091e5919fda15fd2b31cfdf93fce4ccbf5cbcbb","0x1f7cae5088522796ea8ebd7015976a47a3bb4a1d3cc5f0e2c1cbf0950a1236cc","0xf2e1e91aca4b173d3ea7c80eb6f22a0a34d5c4dcdfc8e2de53ac789b0ad384f7","0x4cc7f9b9785c08c5d02c95ddf198133b4556b6ee058cd7b5f357429649060e7b","0xab5ae0ad4baeb9486e79c35ec443bf271c24bbfb69ddda9400c2f0c3a8e6d74e","0x8eeb92afbf68e801de2bd0a4cdb21f6de5b9217a6cc5584ccad9a77ec9ed3112","0x383fcd80944b7d2316f25f8221484c7c9f2fd3431a13de9efa9273902a03c8ce","0x85fc7517c9d6193baea48bfd0981ae925d17f8c41aa4dc2e0ff0e9a04867dd32","0x4ddf3f430cd31fbe03e5a9d917bd4deeeb31eea53c3e8d85d862af179a250e3f","0xd6240920f499f7cc9705091221f997bd72e4c547c7d6faa9dd21f77f1bd6b4fb","0x93db5e6f8227f1dbff81e3de7d2240167706371274f0a42c5d06a7eb7266a333","0xa76e70993cdf8cf3b231ba8c63ed8fb680003bda0351e1a0f23d3f54f9beaa6d","0xbb4a3f97d104f5361924618fa2faee081443e43f203f844f9fa0cb912bd6c438","0xb8424e98abc144bfebee4648832775843401e4907f491c580c462df6115f5858","0x3213c9a64f65f508cbb2eda44980f96189b1800d541fff8269f2fa6f3f277705","0x5c594d872e6752127e0d5a8f09865369ea7febaa0d6ea5cd5ca98e0355b1c194","0x81a5cc6a1b47b178ca6d6efbdd63a20f142d2c0a919e68a3637b7d2f278362af","0x15273afb496b8959b315a53d7e285565b1a182ed202c8982fd3cea835d70757d","0x5316d610ad08c7669cbf15e66694a3bf1f6ef0aa83b871886c29abdac81980e4","0xf4cebbcf4ab4c16c621da246259c59d346a53feca8cc2b41734e926cfd1823a1","0xf4ba9799a011fe3fb6edccce442d8e58852feb82d2d8a3d507a8ea93a042baad","0x750d7122c1386d36df92bb1ec56128a5d33f5ec23db1279dd211298d8393a2d4","0xa96724a4d18ac7dbf551ce9755b8a7610c9ae3f537acec4d22e007c009b3bdaf","0x4b6e56517bdb83224f07b4cf9d4636f5c0e255e8b55ac9e2697183a6d9e5acfa","0x1bb4d8bf22b8f369779d705c79ed21774827c7dd852b7f08c7449f5f32a03d6e","0x12a742a9f743a2d791f6c7de1329dfb1de686540da8221416313d933422ba483","0x454d07e975e692e6632c97f9a2d7cf3a1348c5f390e8f1b474871f60483ce388","0x5d983a89ea47b7dd6defe7fc28498e444e836f9336648af2f04df67113b643c4","0x58a572c7f37887b5b6c0f1f9b3cd0045ac5a26995c5d8f304a3cd7fb7c631d56","0xa51544527b694126b8e349e526327cda6a565c7f95fa3991bd1f5e89a0a1f455","0xf2b8dde8029bc54d3b6b247356f6f69fd80486d5ef5eb1aa004b46e29c4398dc","0xdd0f89a4d917f5df509c0754f2c722e5e752ff35961cbcbffcb16c13d24cd176","0x8c5aefe2fa1efe244eb19ccc71099450d20adf129bc0bf67cf701f99ff746a7b","0x3f3fabededd2dd4b32bdf82782a1549828b1a5fd74e78882828333482e022fc0","0xa51de6f614c3b2ebb83d5ff6787721fc4d51447bab4ceb9dbe1608e7706caa7e","0x62d9d2f028593ae003e97e0f7237b7ba3e3d6f49fee8186d7ca85e2e9f1041e7","0x163cfa244aefcb728fdac595978e0a683f14b3a5b250c5246d433afda34af6ab","0x1809ca182ef2b641c2b3a81457a47e8fce99c616495d34093b10d563fa8c74a6","0x266523cfc8d93b52b2bef448ecbf2b2c586fe19f602408fe7582333a1443cd31","0xb77596b93d9d8c1e7ef14d68252a1be142d3b2fdd13a1b80330f4b9dd1bea798","0x8cf41a71509444418c0879c7ccc71037640f16b7914d8ee314f409db0b9965e6","0x67e0c11b94634a265f13922cde8f7ce0598e4921668c4636c672adcacd3f7eef","0x8e40f1273235268b7e1581e35a48e2578e5abc4bc9cf4cf6ff704e0344e2d5d7","0x0656d6d79ea8f442a83db22e6c41d15fa4f1f164aca2b6bba49cbb13d82a1305","0xdc6c53985604eedad2e53d34916eb56bc19db691d64f6b4297e1944c812878d1","0x6dd04116a9b10d657f5c786fd0e20d067a227decb45cffa9eab6d90884964eb8","0xd1cbfdebe3de2281345fbe6bdab9636a98ddbd2208145a269e1599fec5efef00","0x421012375fdc5555f4bb95828598bbc1d05d7fa87d01a57a7947b9b3e6cd71b8","0xb031fc8d0a3e086452a1dfd3a40c13423921e2fe498ec33e04f2489287570825","0x163f6210e5e1f21c2b943ec30fa52fef6643a89fcd68fec3a974cbadc55ec81d","0x00f5e51dab7ed6a704c254fafce56b79f648273e9fff46ca7728ce18d5c741af","0x6dd1855698c8572bafbc8c0339120dbf5915c165c885246b9aaf3cdbb98b3f02","0xd76183357045fb0c3eba32e5a08f345c77b5ec5717ff8e1e0d1933859082d9f1","0x0bd949fbac9f561f582a4c18a69dc74ad2cc4e65034c5877dbc96fe0294adf5b","0xd87296ffa2e015718f4fc9949241dda73d9155bb26635c36693e220304324f19","0xa76571842cb2adbc361aba977d859acad99db99fd618b8e6fe8edbcdafd2e212","0xbc12fffa1733493d62f0fd494dfba821ca584ca5594fc84f400d6eefd412697c","0x5af8aa7caee71d5e1e5e4f094f420841c0bb010582b289e353202c4bab6a2d44","0xe7be34d6cc33fc98ef23f5700c86caae01c81455e8797dd7695a53efc182be85","0x3732da06074303aa88f79ec85964fe440b4af8bcfc373bea30aa157eb1d6f746","0x9d12e9c5469a938127da3b6d6e00150a3420414cb2cfe0bae5475b48be7c0611","0x099cf0a7b4c6400fc8910672c44ff86d9a087081c5300b50ec72b146ba37d423","0x7b40a7c1f336c30b2ce0b56c8fcda78a34f068b47f5beca42c2c65b4bb9f8fce","0xdc2929a52c4a223f67cb93a2751947e84440d4bb4ff30407e25e66092b68b212","0x2b8a315f7b6725aed2e805171eb8a0cc9a10c8d2db6d6ba227c6e762ef835018","0x4f892d90911d81e5b1ec53708227ffaf377c64ecf5b01b905614349f077cc1b6","0xd3d61de8d6523c56efee4f3282d0afd945ea8564e45c274f111096a8f8b92a97","0xe6aa97f6a53115011e5f7868d067824e8f2eb3572209216812353937e97d82ea","0x0ea8b0e903703e45b3385ea40ebb27d7b7ce2ffda5dd35004b26ec6c88969ea2","0x5fee484892bf8e71773df37c018006fff9cef0f9f03aaf4382c35d832bc9a5bf","0xe3118e2fa7d6781c4d6c41e1fc9c01642cb4d4de349d95b94d07b9e322994d71","0x6c1a9a9aec3cee17cde5cc6cff68814a1a51fa1783ac184813f0b3576980c46d","0xd03a713e5b4d1769dc127b7a8179cf7252b603d6969bc2d2222cc2553073c818","0x03444d070b534dfd8cf7036b3c324aa09345e6703f3b4f723e4f1606b1514422","0xdfa992d1cee420f4c27af2f07a7c4cfd7e7696406c552e99723debb923c8e51b","0xcbded9de3915c38f23629c43cbaabf5193a0d2ba367380df0971e5889c3999e1","0xe095da928c32f9d79ec0f412b329edfe0162c2d9a27c911a1f27407d75baf305","0xdedcf3f1abe226f4fe5f26ec55523867ac604f7959c2d3de95d4a7ca73a88414","0x6f9b562c9a7a180090cd700b430f32f2d2b80652222e91dfa946e7c7314cce22","0x567bb572241d6d2d253f6ece8bfd46c3fc14a14c2eb58506b283f719d810228f","0x5506ec6a224cbe73467da2409a79521f40b2d1163aa291cb0214b29151c11e09","0x1ba18b28db450577ae68617bc769494db7dcb1a1e437a0c65b4ec6f8a280720f","0x35e9bd71dea7ec19af58ea90fbc674f0d113a67b7dbe8a46f7fadb8ef6925af5","0x20da585f550c546b5e10454ea9b468acaf0f204e4f14a5eb50ae9920b9168b3c","0xcb2b3d9d2e2f5ea4ce080f76f27be884713f1acee3a08ca197fee8cbcc264295","0x96c0e341b402cd74b560cc784b209c9dc59336604b0c05743e062498ee9185bc","0x88ef9b3d84ec8f45f950c0aed3a3bd536283f8f5e24dd87bd56b0165c076be3d","0x779eb3e7eb966f3fcb4eeea7c9f9111c4f5193b13339c0554f1b47c3a2648077","0x0cbfb9029d8fd902a1bb0567dc43213fa19ee968fbbd908ff5f670bd900183d6","0x09a42688ff1bc24dff8452c1f1486731c5f16631c03a4d5a6a2a3efef1a0fa26","0xed4d08ba33371a275b56ca7c8af3e09fa06ef7a9fd2f4f5e8a83d069985bf547","0xd7e2809760b0ced40e4835d9598e12a3a8117fad87d0cec213fcbe9fec9c5c6a","0xb71aa937e1271a097ae1d1b9a646c35cb6259a934587012632501d7c842df1c4","0x4b9472d0103e2373aeeffe3e939e064c1c46606cc832fd51c933f99f6537f90a","0x109e15e2d5bf360b5d18babb01ff91f817d770f9c97c2850cb415d8bc454f39d","0x03ead5eb373dfad7f5066f111ac750725e5d203429fc1988cc24c351ff76b06f","0xaa4729276263fac3b54c72ca8c3763f1659c5a6ecc60c87987e4c0e0516562f0","0x4a939dccd6388fcb0760dca06ee4e16f1972d4d49306abfe40446df1e49d9600","0x71e790fc8e329393a3773491d6168b6b1d7d2952bfe86e40f0c0e3e8047850b3","0x87af972c683e3fd487b8e4e196cc52b532124e75bb806384a934a1f67afd58db","0x0d76c561ea53f7a8e978781eaa5d98f62ddd33839491f2d88e73a35eab93d6b8","0x9fd4e95687a38cf8bd698530d4afb7b213648033c2d5fc7a27a97200a9001030","0x7cc5dbde2f20967ae3f4b94271d1eae0ba2cda1e91572b0b0f3c19e8dc8ae85d","0x6f4fd0e0e75cf783540a236e79afab0febf1e2c51e687a91b1e7eba00d5ae1b2","0x85381d0d6cf619a3df83f45336d0a288a3b1640a026793a7f5b5c8e0387c7a23","0x07630ae26834530d38756be88a9dd9a3535da843971f2a665c67c1b4cb9a4e1e","0x96dcb6e0fa16808871aa29ff7e52d30dd7ee0b0a08394fca32a13307c6d886ab","0x6df474daf136643699cdc6f506c749b70e4fea13630f239540490c122fe688c3","0xe98adc92c94f068fb529c5b83cbf3fe655c346f230b4632fd19c8f51eab4520f","0xe9337adcd8862d2227807d8bd062192f63e559dd95f3a6bd16de1cfb2d28c087","0x5e915a426084d070b802f66966ea1847a6b2d3d9efc61d15754c801824ba46b6","0x846b8744830465245857c9208af283e8c9bf97897977be884ff3e9e9988d7d7a","0xe284600619908ec409654e6132d55160fce1454b3e8c55a5893395db5e2e51f4","0x7f05ba28fa54b63ebe3b5e7acb4b3118d2a03ece4a02bbaf615c7eb559b3156a","0x52945e29a22345304bbfb3d8668ba93b9c534bbeb5b786bff002ba9de853a9ec","0x31da7e0e398f7c95f9274f041802f5a513ffcd237eba8ca8f541da64567ca6d2","0xe273c92535aab73f082ef07d493f90aed8e9624265faea582f17d73068cffa1b","0xa1b666b55d37aeee450f31f12f69faa52bfc3f83b5452dbd6e84947f20a0a063","0x560fced33725acbbe0a7d2d526e79dfb81a0a9c1c70ea5d055388f8ccde74890","0x1d9bc2293b97beef937ab31708959937e6d922baa33aeda67753e6de0c94fdb3","0x08bd6fffba51f8c6f76539595a660e0355c991fcc3072dc57f4f6d88fa3a3d33","0xbe556188873ecb66f458389e7bb7447dafc1ec40809f62cf048113ba418b60c7","0x5dd32c52024e4eabc5c46f09e76b8108346e5c298c112c7c791f734af1c89567","0x6e1e44db708b03f810f44de3f9644f366ffb02ed7906ed11049133ba9f492e8c","0x277c9bb5d963dbd1bb7ecdb24f40c256c1da083e1ff2435331f0f78213d220ce","0x3a205b2664301d8cd5d29fec11c7def10a34e5810d7a4fa77fe24e0eb7520ad0","0xe0675899b23624184bc6a754fed13e37599a47ec58529212f7c31111f4719d6f","0x2bf4253727b90cf2fc41af5cbd81bc02c86e905ddfb7efedd94027ddeeffec23","0x678d06c4b6f743687543b1041424738400eb039ffbf6a2c1dfcc00f1c309f359","0x9214adcc9359cd1fe52cc23fd8a8c67b7d5e2e098953c0e4191a1e7cec6b7563","0xbfdc89c0d9823b26c565d079dc8323b91a04998b1b740dbeb66e7f87e962b747","0xe495e77e2757365b995c3109693c40f510285728a3c7383882fe22d0c791bcfe","0x5fd1c9de2458afab6e9a127575ea5c940656ef33ecd426d1749a77f20d60f06e","0x7fbb43ff380003db1e09a97e137946302144ae09cd6541788c0cc87dd451e77e","0x3450b547a32ce4f8de2af4313f14d719d25a02075f42e26f0b92ee987bf100cc","0x6445b7c44fd00ab514ab05256d76e40f425e620774c476a8b272b60591f70c15","0x72613266dfb48d93cddbd137036d0bfb2012c3b1dedf1dfd801421c513e43105","0x7fa259463730ad702b64470dddcd69f9fd4bc3f9ecb4722a571a8bd2ef33dc8a","0x8115e765dd97fbee2e3e620e47753a95329be837dff338d03eda0a0349754803","0x60c9b0fdb8443f32d66a1eb8616865c95ce2524a98ff3e992233e0694623dcfe","0xc26e03ac61a8adfe52edef250450cfd1bbfc915c812de7a2ade7df4c51745416","0xf8fc8b5e510558f66794430944ef0d91658293aa63a97db1028e40333d0fbb22","0xec1791190d758abceedb8ec0c9c1b01ce38af57f77a07858a12b3245524e0b49","0x0a46b6cf7903a842c8b1610cde3f8321326cc433730e62d444de9c86d50fd0fe","0x9b3eb38d14cb3586d703049c8d5412b3b14411f8cee2965e48eee1c42fafd40a","0x2e3cc4a6648557aa2f95b15043c493530680f9444250fc8f6f3599d0f5f3f0be","0xea8ae0fc210a15ed64f46a35fa8b1556b76d09ec8f6d47ecfedca2f4ba6c907c","0x12fe9cf56bce887d2b6772e84aa422b1132bb655a59f06b3e2e40d5e20fcee89","0xab424e4f1e30fd5bf0e72253b22643942a13323336de9657af216f805362ce61","0x3ae8b9ede728261bc571e69d6c2c6b5a054d2702297cfb2f74c7958cec6c0bdc","0x838b4888060e36cb685cae32460f9a4d8b7e409a5bb893a291eb7dc3140dcb4e","0x6469b6e4790807edc5dd30541178cb9dbd61e21cf347fae396415c738246ec08","0xa3cea6465fcbcf8c4d2d52d049c01cebd16394034623a92647778216eccd2eb4","0x904f6dc8bc8c0800f77eb4c37762f905af93635d289ee0bb4f4f729cd11c0869","0xd5c16a13e3bbbf73d2d14745382a724fd9d7d56de117373055cf4bb0c3057c97","0x44a98e88786984c42c72b9492969327c67eba0a1406f9f5f764d4d3b221ffec3","0x4d0ca05b66a2e761aa85cbf7b21a789419f4e7e8a883e9ea8c7b49e03feba10b","0x3106a5580af05f9692315631b5436e2da0aedb2275a2be243557da308ae8f83b","0x954078b876e987233426e530fb7ad69aa9fd0fc02eec7b37764ecd56f938512f","0x045b9278d110a8b13bf13bffc6dacd9e3af08a07013222ac6c1febcf7d433e6e","0xf54d3a846e71e2811a2d75a63e2c99aac64dd2811cbdee04e3ab450604edd8cf","0x8fc2a5ad38c00b8a962cf7a2e17c1746cbd0bd97e0200182cc610960dfcf833f","0x9cf567b6c4bf1ae871ae0ec53e575bd62a7d60ba9970f2611cce6724a008bcbb","0xcd933afcbee4a9d5664b29577d8c9aa36f336f1b2e3683a757d0d4155cc4b55f","0xa6218af882961c5ea878b28bf2a034abb238b9144a1702f7e70c1cfa4d57fccd","0x40c4386d9999336e9b0b40400bd61b0f38ac681b4d72582af2037067d5419170","0x279b8f48adb0407dba92b12c2367ef3c72018c4ef3969b712139d70837655df9","0x1a9193431c64a989d9f707d33348ca0411fabaa270f45171ebe7bb80f8b3bc5f","0xd4d5cca39c760b9c7d5f375c3f33e73ae9c2c882d096e5d53d5378b051f2ac5b","0x4e797ffc1750e27a7fdda718bd02bf4a1b331f00e27f980508a5587486b580e4","0xfb26b2586797257db25c3ce75e95d74c994526e87e76bde330b0d8388b3d34ee","0xaca89094506473a40dac2f78b2da67d3cb6c12e11c5af1d7e040bfb834fa0c44","0x5bd97f29ebaf82b0ef965c289df51b29895626a47e69c954c3951fa759827a8e","0x037bf417887de2ea360a46bc7e8b31283b4758f6dadc768e6470831c6470ac43","0x1c95e7a721c532bc6c68aac86e35a0f30a102b079d7a8a18c273ff6b0bf6ddae","0x8ae011e7dd49c700fe1c9ff26848d9a65c74dd3dfe34dba0a37a957c60c63781","0xb2a0f9de786ea5da63c8a765d5c052a783aacd355044009e32f5df46236529a2","0x4a68062cfd6c26612a48fa96fe23e70b63b5fbedd7135664e595209dea45cc66","0xb73015448d4bde327e1d8cc01967acc4932c2d8efd71c6c823159ffab2b1819b","0x6ac02791f5590ab24321f20b32bd13c02ff13f21d843eec969873705d5983756","0xe0c7932c796483e35b20692617292fed1b4c5072bcd59b08e14df9411d88670f","0x451af5d30a1776ea43c5a8143c48205ab655aea5f0070d01edf3f9994a172419","0x0a918bf6e35aeb874245b42dd0528046c9638f20cb16c1f6bef03d0e4b50da7d","0x8adba58b9a83430a16f0ff56417ef6212bb7ab2bd5df73cbbcec46b591e7164a","0xe19503d31af286c679ed039b4bf63224f443b1e7aea58826aafcf78716119cd5","0xdd67f66abf9c78d07fd330e49ce52d27ceed9edf9ea329c1881693a0643a1337","0x23275bafedb4bd5d9542583773f00ae92d524f8dde496deb67207b9889710508","0x3f4eeb9960a538fb16a20c3f85338e4bee39871c474a25460b06422529af3a3a","0x37379cdac3d421da277f90e349a14935c37fd94eec7c38913aa7cadba635c527","0xb4e288a769860ba6fb1df1b5b769255aaec08430e9df2f2b82321b9dd9f68274","0x7127b4a6d81948b371d2144d365acf43440f7c5c303edcd00d7f1bcc4425d83f","0xa9564ccd010e8d4f6e3880f781d2bb77442f7d36e1d43d5f837dbb67e44ad75c","0x1c6a2067b57afeb51a4aab7bb294ad04ac988b47eb8674f67a0d9cd82e115b24","0xb8927e82150fd4836f593ebb27a6ad7b5ed2768134f23407031843febad1b3db","0x3466353f8ea1274dbec3607e058f4e6d3d20a017200eab4ed978651fa9ec5e9a","0x09adcacaacd75dcd20a1a187cdee4a4732fb3ccd8b633769341bcc0495c33d94","0x945355008a6b82eb2cc3798e6d922d7a7a18ddd601aea8e33d94cc0e6f0bcfa3","0xef7127b5d50420a9ff7d656067d615088a029a51b5ebe6a18e156fd1b928e830","0x35604e11ad486ced1c7784f13632a44b0e171fc75c3f813305abee466c78b93a","0xac0f4b25818aad74f331f1bf0ae00cf1c0fe1c93f38fbc23de7b7922f7d7ba37","0x69ade472e67bead8f74e205ae01d02d269de037e6b365a5156ecb43ab87564f0","0xa6b21381debf7a46bd60a3280138ab4618bd17e69991d6477db48f52c1d66c75","0x3cce4b9145d89cc2b82567681335cf603b3b568fc76f8c7d742aae9bdb59f098","0xb7210c3fb287201149b4aa58d8793dec28f09ccdeab3b3e96a3e7dcc488fa845","0xea8a02aef49a7982dc44aafd40ec7b4a339213127d0cb0636ecb29f0cb92c68d","0xfc5ab210cb528e7f19a3f70cf94ce39bc7b3da63bb63f05870b24c4e2ce981b6","0x76d327d8aec7d5d4acacd64b752356944367a9b9ffeff3a83f9cc9b8d05acc0e","0x5338f6c1d4717ffb8f1adf01f76cf4603fa3c12d9fe40e5ee50b6fb103293279","0x3a5c47e51a9b132eb81be6a6767a7446f2dee25e1b73e35f0f64a9b24cb9c249","0x554c618c062c7f7a1e548eacedae787316f62726a36db229474d161a33d945c1","0xaa0d5f064ad33e008aae37937f182ea56cda37f17699c6131e69ed2f8150c550","0x5067636b9acdd04bda39cf5edf0d4d4de14696fadd64845e71b663f9f5029756","0x12a68c66679edfc0e3b447311866877191253a92e4d1df8ab8016a4317fc2573","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0ebab3fa9caf754ca34a11069483677a133e3f9e9dbc8f37f7b96b639215a86c","0xfd3e6b6d84b621ad5a7c198a12abdd6d35619a22a6f46a0c5ce2ccd789c5615c","0xae21bc03162fd579deca3d23174e0e1a486dcde12164718471b2ae2e8e278cc4","0x6a20210af62a5762ea5bd32371a07a4ba440dd68e16dc17fb4b0f11a93eb5a0e","0x6324b2187b4f9c8aed48becba4265356c7f42703c3264e8b5f4a656d9a46c575","0x41dd75dcc4d45bdecfcbe298e6ae4e209a9c4f110da4a1abe67b316f79b02e19","0x06fdcf2db4b66c6c0e705d1e45ab8fb87456e96b2fedef0c16bb5422f5865ebd","0x0caa50818e4ba5222f71c7e1ec26bf8ef1fb804df203d91b7acff5a9a9bf8da8","0x69c6cfb99b885885410072d4b823a1c14847f2a5bce193946638ff9589e38027","0x1efc3d0b7a3a00cefe9d9a6edbdd16716ecf671a797e031df954d102fa33e475","0x1813df347507c6b7db2b6073736cfb16777caa8102d531d671618508d284b6ac","0x79e42d65cbda09e52d65197a6a3981cb65e77d049603a7eea190325aa7339304","0xcb481838351a2499ea0fa02059dba477013e77a80dacd966a1a456418bb049d7","0xbdb866cf7788a71a41c631f7fcb29457235c704cf506572aee00dbc98ae5b71e","0x31f1b85887eb2ecea458d5f793ab0877c70fc2900180ba86a2de21b8fcdd64e8","0xc0a18f7d20e157783f25b662e3461c4e10b0c4c5f23bf0dcac44d60e5b46f6e7","0xefbdab89274702e92196d3acbce99c7ed4f3afdddcca36e729a92a5c8c34fac9","0x926d13cd874db886b6e17a5a50ba9b7b52ab3b94e83be497b1a1818926635ee6","0xdb9ff3f1d38a29234cb5c285187365748136a14222a565e4f015897d5ea10576","0x874ce6eec5bb1afd92a1ce73ab39bbe9b57c80088b0726aff3bb7c4d83b5d98f","0x45bc05ebf59df1b405c593f4bf1a9369b1af4cd08b96366d860373b9118432de","0x2730a5b3a2e98e9f780d72050607ff1ee6175ab571c9a4a09ba0509ba863caf8","0xe7fe67a40d64460598407724226070d001f6e89460488feecb8ccf2a4ade8d4d","0x5150a0e4024dc8e9db68b971e7dae2276cd92a2fd6f3774d0c461d220760a8ea","0xc1206dd9d135024784c201ad1ee43c92e97306bf3c4cb2e494fa5c3070517bcb","0xd823f0883a1326d8b69dbefd35cd2cff4c5bfbc904bf591c94307e2544cdcef8","0x441c862454dcd3c791163a840d681fcfda61d9be37410b271f542075238fddaf","0x8d13b9f3da69215128231f08ab86f83f242550360a2bb1ed307bace57b6be50b","0x8661bc880e17f636eefc8ae2e10513e53a48e9812e8e0042a9385b9fe2143b0b","0x7efbe9e817f87a7b696292b2717b69b4a7383a308bf0a329a1c512effaf5405c","0x15ef021f136fa3484b0622960d83c922d1f936e17b6b4af111056165ff4d0b59","0x9e657fb5d28778d14bf0f1ad76a1bf0bf49a69f88d610693e2975c864551dee5","0x48247096b4f0161de943dbd85310b95f06bf1c97209a7ae2fb55c63ebcf28874","0x2c4fd23d0ed41e772a5249a1a3687831df50fa875e226097c3d281431adff04a","0xcc0fde14f3c1fbef3297859afc8e68726550a116b3b090d1d7b37160df592512","0x32e84941f25dd7af390fd0700534289675fbc492a32a626eaa2de47f251d1225","0x522bf7e1797d86cb1eb80b81509b9a63e23597fe080bc4aa0fff529998330299","0xf12b12523bcd49042abc53010ccf9346fdf3be20977bc44cb6dba618499ef748","0x893e6498eb52c869594df1cce89e955e49dc5e73a4a9e6f9d98818541778ba61","0x8b7d7a75b214d1ab1d508b77bd4eb9ff53f38e6c2f040040d49fcccabcb4ed84","0xfcbadad530e530fd6718308b0c301cd2ccc33e03504387ea2d39d9cbccf87e21","0x46275a040b45dd03b4bd9c8793c6abd8ee3928803f14f92d4e3f4f27eca2b340","0x516f19811155bd8b5ea78944f393d0dd8b1adf0f1590d1424c82ee1249f29818","0xd2edc7e07bdb6594fecf66aecd32c321eb6c5f7130fdd28032d8e8ec193cf7b6","0x038f0b57441772c6fd16e69cd9bac08d3e1d133bd8eccb725eaa88f136bcec98","0xa1f46e698d039a096d39a200a64d4843d91aca45857fe37042436c0bb7e7d1be","0x217985e443c685431fa8e0d5a187f3e5764305d50d52cc99424c187b8dba5199","0x97dbb21f685a28f294f987843a1685f92ef50fc70d739402785eec8ca10d87cf","0x6679573fbcf116d328337f4d9caf6377f466756e2374957b268227d282017fb5","0x026ada0ab6de333c3178904aaded6ae75c1750e4a748444b97407b450ebb0c31","0xecced645c7e330ab5c90d0a3b952e81b371e321c81acb8fbdf0d1b01da55977c","0xdbedc2f4c83591d8ee4d6be3b183cc955de68d93b2d97a692ebaf11fce1c358c","0x9630be5618bac33a3e79470dd9026afc34392e4250d11726dff670fd85e71df1","0x6adbbc57b2a78b93372a77eeaa56908bf0cd7181f0557d832aab3a5abff0ef90","0x5219701047b645d734d2143096eacf95ef28fe35572f95bea2386ec6cd05a40f","0x2fd2987bc2a52443e0a583a93eeb6898ac835979c627aace93520d30f324b2a5","0xbde7be8712ad7e14c69f81ea2eaf2c325ae3bf0fbf6707bea53ddf7383ce443d","0x63155ae112159a937c997660bf11a495b17b165c897c5367044ff904e4f6b6a4","0x67d92db7237938fc835bdaabba982095a4fd93c0c0f49781f2f9cc49a8850267","0xed78ae48272421ddadcc82232da16f3facecee7fed830db1b726710175ca9e8b","0xe65d5be696cf6cb56c64fc07aa7cacf1901aa4f3426ad6596de5562c1603988d","0x907a120592af2ac34e2ac1c72cf1f06161fc4a620fba65fe69144ed6996dd347","0x826178de76ffe4dc39c04287bb88bcd4d82d8cf300c76d76498b0e199443d127","0x22fff777354cdbddae22e27e9eb7b00496090d765727b753fe5b638b834a2339","0xff9153bfd019a11dad8e3dd5e7fbdf23480734028f56e5dd4f40b6a07f5e0bbb","0x61b9d980e71964752c0f84a8305a99dd18ec6fcc28885563ee3d87c7b57fce9a","0x5d4f953771ebf85cc2db14ff51b2a1477a06a1a2b0ffe3797c87e70d67c6e937","0x30086fb8d375088c80fc219c4e8a5b6fa0b7e2718d119d2e5736254eb625d0d8","0x49524f3f369b46c5e01928fff91a5a84367792e6e8a59b2a3819e55274d4dfe4","0x1d62d9c594c61bb567eb9c4d6227e0677d71aff94b671af4812eb2be0a73f3d1","0x1dac3c18c242a1cd60b3c89a32673b95290f8b6328f184475abbdf4b6f9db59b","0xa113b4f66cbfbda00ef4fb85c358304bbb2492ed79d0335e8081111f1f124984","0x0523c3ff37eece967cb89eaf9d320a02e72812d60cefe544b7bd2c4d5bc9b076","0x4fc28edde733479eb395df4003c2be4406419015c37574932a2e3239f66e6b08","0x1a4bbade71ace795f32ff1c36398c6ed8f3b559b705d1298b85863ee39420e80","0x621dedebe93a1e821c0575ffb60c0c3352bffa4ae1ab9e9f4b1186ea00be1ce0","0xee0858e479b33e7a65ffe1cfdf1174ba148a5fe5f7445b61e8701dfba6f29535","0xab893b43a44335510ba7201fb76b581e64ce6267508d0ef9a807216c98f8b2d5","0x43e6477d812ae6112d3e3f7f6ad3792cd5855f14913c539d7711bbaf52534f6e","0xa88a344c6a69266b56936a664cc95618584c52c32ca85c340e43859c59c133b0","0x2549ad82a8022ee1f145a6022a87b39202d921dfe235fd8edb7833f146d0de1f","0xc58342b8425c9e8ab13112e41647296e9b5a8fbbb530712ee394901210bd6119","0xbc47be4c05ee205248c6a95bef044be3ce30f082b44ebd973c22fc26adc1b53a","0x7340311f4760c119d73b5367dadbbdb99e457dccf8be4d869ff168943cc04014","0xf15c0675ebb9dd8eaf2c287294adaf47eeb05812c3e889f588084a764b23d7d9","0x54bd870df26fe986c756a9473eb85f5ca74407e3669621ebda59d0869e1be419","0x47ac7dec3f3d4a84974afd0f78e40915489cf036909a16a55f593fecc1f70d82","0x75186e75976e4e80674d4d45d959451041b23cd2f16d9c37e674b852d417d4f1","0x33f7f652084137b51256f9f091126df122c965803ce97bdfe0c2e0a3c404f393","0x9fd6d92eb4197b24dc5085658fdba94b23a1d6240d9cbabb2700490d5e587f17","0x1173afdbd256fe0396cb58568083b6bb76e132beb86693826d49cd924ba548a4","0x5d78a82df6a4d7e9e8f869f9069e88fc2c7162630dd751451ac20923f53670d6","0xe1289e3ed882008bfbe629c99ef4e87a0594f2a221525a4b332037ab29f2f502","0xccca76b275abc6a34d8a50371d8fc020c90c4d61816c81f2da9e1c3c669125fc","0x9095c83528a081c794b3de2795e25cbe0cc65e5064c93e065be3ebe9fcbe0fe9","0x6c9167c2a06fd708014d6ee177d8b011c3b14d63d452e76a25b6c6274c2d4c2f","0x98a84b96f90ecd92b8745c8605aaa4ef86478d1ba8e7d6f866dad1a72103c408","0xe29402ac7316b94bb4e2d6b831c8eed1030a260788648fc69ca0e489d8586852","0x17fa82a84f7df8e8c96e0cf9081668de9891b2b61156f1e9240d15fcb5cebbe5","0xeb999a6226f9355ed4559cf6ea25afff38b369c3e8bcfd99a0ff650d3701e599","0x7ed84bc4085139e5962483f4997ed5f8c6529f061f1c407a0bc928a363948164","0xca44491932176de008ebac2db54455015390c019704fd5c436bf2063e52b5045","0x88c3591b88c6c2e339a0c67c4db7a6e49556b79bac77d348c8c6ceeb254787ac","0x3239549a511c1196c09a1db1b0e3122fdaec828d87ea6b92858c2084b160db75","0xd77f4af3e98e05691eb66e4b4c3409c979c71eadcb17846c809fa53d03153571","0x289520f35c47d931d3fc54290eaad20ada7289b026bda1eb5b581652ce2e384a","0x09a565a976ea5c6d00b83662fc82435f55614999aacc5280b05f367aaae60dc8","0x8918ecec0902addd2e7555ffc89a7a98c2ea667c3232186d6a649d1bfe12ccb7","0xb671c1a016a926f1da02ef5462fb893f81b69242fd96516e89ecf1b653caef41","0x5c002cec8ee88755ec0d4fb44dce974d507243230804e0e9319d96ce2fb650d5","0x3986dfede11e3b5475ce543e67e0b3c28a6bfef75daf7ede3a6130c8fee37d07","0xd6074ccacc89b20a43bb37e86a4237f85a9912b844fc3f55d5a97dbadd464fe7","0xdf7115287ac8af491c99ebd513f1f54548fb0cea2643a6104acfd8bc3ed5cc7b","0xee52ef344c18a4ee3a2d5761d0dcc2340e2a949eb03baa241f55387f09435748","0xbc3ae81be6bbb31b7de5feedc136a0080b880a562875db5b2cc098ffd86ae683","0x2e937f79e8241040811a88c63875a476f402fb461cfb8b795c89c0ca74351973","0x6fa05484e53e674da54ff6736cc3056ec36606cedd9ad6cebd7a854f91dbacb4","0x102b65dc7ee9806f0a5159a38cd64c3bdea4cb633a8887cd183e7a4b350f7279","0xd49dae1b21ae37d06d482e1630e1f80ab72676919e772aa137c757e93bf42ee4","0xf799ff20def83ab97b5bfa3766ccf05cb36797f22bea4d60f24d4d845f61cdcf","0xb348828e6ce3bdfba409104f31d4548067019fe6ca932a7ca0ceae1d54878f6b","0xc5114f7251a785a4b20bcb5b1a34df6d581ef4ef2d1a63adf7cce237797a0883","0xad77415aca4681ef143b652c07dbaf4544e180effb7865a2064b8e9071845b9d","0xe1aeefec2c6d7dc4112cd71eb8723062f6408b83b96c4e32c863c484446b1d6f","0xea75fc0e6f056f8396f2bbe43a39d7a2aa9aa4c6683b03f9821b43204eb6da38","0xd3393baee58501e894283a5ae4d235282f16d4ed4fa69162da70a09e933d6af7","0x5e795e4c3c6965e637159b47ad39104af3056c960da7a87ff239d7e564f2858f","0xbcd83d89de9f6c4568ac72e271ec30e26dab1b1728389e1a608467d5d38e1463","0x9eb5f8aedf04a4f9c4264ae677f736b75e02e86b85c0872a8df5588c398dc1f2","0x3419f749361729bd6694908331e7e6a03637828ac65dae0ef9438c3ac9c2ed98","0x35e4f63963fa34e76738d307db8093d02b38ddc63b7ad0c515d3f005785444d0","0x98cd55db85a77e2415d4a22e7bdc54ad6f1841234b83ffc1b99bc4cfb5f35c17","0xa49bac313b11e33371789ce473ac7bca5826197fa4fb45c7dc64c7f2d518758b","0xfe92eb02d0b7a90d3b112b5c1a65bf76dba297c89033405bef9eec2db5e46cc0","0x4616c98ce98e5454b00b4e117aca06e74c6bca209cf4b3acd676b0a20ff23ee9","0x4de94d40aacc25478d73d716d69a80e67b077816f482abfb5ded9374c4e7021e","0x1de59cd2dd81527da4ec7adf9388d2fd3eb2c20c410342ed06fc3e5bd6b39e88","0x86d1b31502bcecc4c051ab1cd6a56e6fde457e36aac04edcd4bc9fbb8e52fa06","0xb6794eff6244b4ce40ef157529e418ae4dd60af2bafee910be32ad1452ea451e","0xd840648423f1b38daf97f477ece0de1791f8bcd935163fb6d11de2907633ba63","0xb2efd44da134c7fff51988cafe5f1e47719f48a0a2879a287eb54956e6e6c6b7","0x6097d26e842588c732c0b41734131d6dfb22294cbbfd5d058b7b0ae6bf69fbe2","0xdcf1a4c2bf89fbffe49d769e5d15f4d42588625b4b70930a3771217477f2382b","0xb8eaa7607b3f000da9131ff685b07bc71c365611e6e5ff2bc604b76ccd6b0dd7","0x65894b2a5bf92b01a2cb8f66f53b4b16906d8761fd0558e48d415e4eca14b4c9","0x418cca8895784ffe994ed1ea13838d83a19ad372763d65cd91617f633d371cb0","0x3f6c7e34aeaa5b77c8c002453eb7cf35783f1ede137d94834e241aba61bd8d08","0xf3899c5f2abc27b89066b391ab5ad02d8f093276da9bb36fd4f32c0b0f936857","0x7d7639998906404a31abecb601c4dae839cfceb47cb01bc98f913b8809e97d10","0xefca25804218c7ddfc3aaa52cef60e46cebd162a3b2d36152dd75a1b45b92a1a","0xb38aa179500d6f06e1d8bbdd505366459e35c21b3e5f5cf009b0c5349b3dfcb7","0xe37243c921eb07d02cadc418a8d631434438cf181b70333aaa9218e25f39584a","0x36a5c8559314b9d737230b3627938162d3b0f0ca649dff12b40bc1d18eef9941","0x9a8e4bb6a938129173e16f93ab75506d09b255a9e9b2d1dacde3948ad5c6107c","0x3f162560ca16d7a6a8f6731cf4aae82f41f36536956c3ff13b1ebb84371e097f","0x0cdd9e224c5fdeed83672f4148791439a94c35fb3a7719d0085cd5ff72d0b34b","0xd21d5fda2ad57cc96d13f19aa2d8fa49d32f38954996550616f6ac49155fbfb9","0x1da5c215cc86ce98e62684f92619d83ab6932425a502b3342d21f8e9e8b9e1ff","0x24d30ae661fa8f96f7413fe81dae84a7dbc7cef095874d6878a7d9a11a75f995","0xb92ffd8b340d2ffb009be8cc0a0a474f03c5bb569e97e173f64e4fcc695b926d","0x802c04474f2636e0a98b28dd13ea68004e3e65c0be2174faa10a415bd46d20e9","0x9d0c0ccd1c63ce9b8b55cfdbbf6c188ff66f71b8856a0e9f87e724ba1a3a5c50","0xc9e96dcaf5f23c627ac7b21ae329475736eac917a19d2cc63a91d03b8216aeb9","0x5f4198b367414bb080318d1d72b8084fa7900bf69856f68e2d41d5e60ccc1ace","0x3dccf57cc8ff20f7429e358bc9650029fe3be7ad6a7b877c8108d587cc7a65de","0xe8c95f65bc2950b3d1fc150326a5dc0807049c5a13d82f43a8a1ed532cb6964b","0x3165f7fba25e9608530eaa0de9fb7c7b310c6cd2e039ed2c1093aff4debe7a9d","0x0eea7e4a3be71b1e7d4adf7acbc628798de6b29d819cfcfcf1285546f78b574b","0xd31b91822f42bcc536e1a05b57bd531ae3f362d9072fa7e60175483488ad2be9","0x5456bf8a138557ed15c5e757ea79fe234a449cf1c1cd4e783d5e64257580148e","0xb11ebf57a9a8d1469228dd49133e9d730e4f4ec94af61fd609475bdb2cf0f385","0x8034c4810df18c184da64081f70b8c9f32df6edb332c30fded54ba08305709a0","0xe8ea046f5d98de82e1eb1bf10eeb337220a7963356b72f80c759cbc3cbae9ec7","0xa084a28740d1772d1aebd3084e95259512c1074e357ba80bf1724ceba70dd5b4","0xdb9ee6dc3160ecf29ef10e7468398cdfb381f2717d9736c060f074f51ee9afac","0x083ba7449aadaf3742e48dab01f9ae75028481c48cb3989541c3181f0d0c8ced","0x889a0ac2aecb3ff4fa3fceb5bf69b771d08814ade9e0f65154cac2b5aa619a0e","0x4384082f19e227ee879db5cf7dd69309ae25200779f800c6e02cdf7f14a51721","0xea703ead5d8d8c48688b75f0aaf4d32f95a08f3d3b06bbd3f6d689b173777e1c","0x3e3f37f943dd26f9f8af209b0157837a0eccd129e0b97d9d9273ac84e8512543","0xb0c2d0229002ccab30a033f0de4e1eba9247c7f51ade1356039835b390132dc1","0x16e9b4aa46b7239e0d3ee87c7ff28d8ffc7443e5478267f8ab7713f4bf6ac2b1","0x0c78adf8603f99eda1de4b35979d5f43798202880e1d4855b4a4cf55694e54fe","0x95eb40c604cce770d2b6d555b1e6c9b74e2b4a95b417bce29be5dc076fd6e997","0x6615bc11e36667f47164fdb4a631c606c025822324d070c99eec52295b6e10da","0x3f2e764cab495c3ce8b20e92deb6506b209274b331ef29a7b4af043a56109a48","0xb6dc48ea5fc198c84752c74bafd92db8ac3786b233161cd9be7061e3a4cb17a8","0xd0cf78d73d68a842e22a421b24145dac2e1c6ab1b6d3227e083dfc05d35fa872","0x4ae6cda25d262480658051a6226fd97b2d4d58a9e1186c558da814534f8d41c8","0x0ada8890995ce40da5dc3dacd0f1de348d06969a92896d7a951f03229bb6d7df","0x39decff4f532487c3326a124d6737ad76e373ee3e37257af395bff799af35add","0xe60b92f1a25a5e07f5d1fa773b5bcd4b0412652a4ab3a2519a64ddde31784987","0x2a305fa54826094013d777001c4761881ad4112f540f8959005cc8191eb793bc","0xf25d60d1ef516e18c31c288bfc7aca903ddfc6edab6f1123377d4e34ed0782b3","0xe777ea8440c9a60b5ce3556be8cda26963337191b91b846b2e4893ec7a5bf1ff","0x21f53eb2ae942d42b920513239e28511257130462813514ce56e42798d7539cb","0xe9c8d8da908c4edc540cc4c7940aa615e83b8b40f06cac2d37eeaa18d62c0f37","0xd0d4d5f56f200ec662943557b8fe6409da62799a50a4d68f95569f02aa5faf59","0xaac26bd407fc2b56d855afee83187aebdfe1deee0ade440803842e8c3052e432","0x7c614fcc7ec732a90353407659eeb13df766a92e8976b3036a9d864b4d92b126","0x76e7d0fb21fab3d4458f348c215abb7ef7049bc84d6f26ad557954571edaae9a","0xfcdb3a5c42f3247158caa81e5861f30bf169ab8289c3baefe5b8dab2ea545e5a","0xf213ba8cb47f9be8d18debc8b15e600d40785cc3ae81b7ba4539c0a4346dc6c4","0x322f395a2b47ccc094d1f0dc2521f09d31ce0544ea470b5a7ac8df65495ac3da","0xf6cc35a294a1b300159a88f7251ea97f28b94ff4cf625beb85b6bc2a4921d2b9","0x1894df21c97b6c77b319bc276b8c03ffbdd16432bb17a17170b8853df9fd0004","0xbdb6e4ca9c7fa40fe7a2efd9d737bd8cf9012b0f7dd4f7297db52a0d3bc05333","0xbc0a51da1c9e1bb2b6454a7af0ca8a2dc4627a806880d19333b243169e409f55","0xb9c18ea5166a0446e88ee04a5adb011cf85f0673199f81217e053747b2981da4","0x525798ec2fc9e62461cb85ac0f3012f33419a5c44b5e450fd9df366014d2bd5d","0xdbd5114edbaf2855ee94b2b5d8d440bd3bbbde82aa55b3baef3f9f28b7f025e7","0x569537c67868f3a3ffe95d304ba255cab3c667713fba21f5447591e8bc392611","0xa8dea14bbbf5005e51c332378263ec133859f1ad7b16fec00963f1ac5b1a527d","0x28583a386b43376c288f234997ba65277e86aa907cb1264144340676692dbb8d","0x0168e1b4ed0e88367b7fb3f96a302cc3c885ac12d18bab4123df9f124bbd3f6a","0x266803bd9fde92d08780378fb4bf767db850933e69295c2b66d1abc2e388a6a1","0x97b6ef288f152f3966966fb056473bbb5e1560e70b51bd336dc6d2124c4e298c","0xb88c38814ced588223402a85e9bce3bd25f1142a90d55d51831ff507cb8ec200","0x5eb27bf798e7a83da1a839e1517c71d35ddec075f16513b0e44d8131557166ae","0x6e42599a4f38fd0503870fbaf5378a6408188bcfbdb0538ab7b854d00e038a63","0xfcc572479981c262575f5e93d149398f4a30dd6d634b60f52006092ca322dae2","0x45f2acb59cba76c87fa112de958319b4cf739f42ab3ca5d3b9ff3ffdecdee3f5","0x73b76b06500578b3b969660b407a2f2dbe8f08067e3f09a91e2a7602b0818bd7","0x18b1be172e8cdd0448ce24329a0491a82313da5f7d069d4b5053f93b8928105a","0x72fdc38f7c3477548ea6f42afaee27400714a812a3571b07904264c3ce459d47","0xb236d39d36982beb08d0241dd052a9616cb95c22d5da787bf239109ba1676683","0xb4645a7b14200a267f23095bd453d6924378dc5df5fb3d0a6ad45de2a42ded17","0xc488d6f42f0ddc36a69af842672faf2be23b053ad3b580588995950f3a637829","0x182258555e4a8ad5c5fc3df3f9cf3fdb371adaea4af67cfaddba82356c8bf593","0xebfb2911e92c769638a2e58fde949c4e788c7cac8b9f16ba718df73b92a26318","0xe0191ef6f2a8d6ea81d6017f43ace34ebe4929760214f5122202b451bfda0f49","0x18a1522e467a0069120644a5c592695ba98c65ff139bbdf4e454db9a39793ae5","0xe1d2c447eaa41fca424f810b3bf8172773e1e13ce025a7b5b8aa2257e4031ec1","0x156706b2eb3fb2a08663ef05bd4894027960887e903a05ad321cdc66815bf6aa","0x289b711f9e64061f8321f70eebfb35e433b86327ac1fc75e2fc4099a5564cb32","0xb4c206e1b045055d5c840ee20a32914ca8b4765e843e6f7e44ebf07af5f344d7","0x437ebe7fefa45065137b1c73475430bc44b0d17d34428c101e8af200d51c1502","0xbd462190c8e814520efc2be38171ddfeaaa63ba6888e639423ac5c483caf0265","0x6c0b22711e9574f3349ab05d1c24a46d3b9c646f29d7cd386580fb014673b1a2","0x27ba165e9a5ee63cbcee254b33818e8bf50dade62ab01a19da024d80409a3f63","0xc55dc291bab50d6b060d0dc47872b12802c7fc9cf2a1b44a703237b071b38fd4","0xbc6aa369eb8c3d5c1a9cb802eed01d7934161095d4ae5f47d3da09f90d40f82c","0x03f1db8c5a713e4c72cc02bd73d93d799ad643e9c79d2615120e4ed821b1a1be","0x430c25d5d71ce628ea7fc09be3d2229db2baa9ec504ecb8c60b770f5f797703c","0xe9dc0f169551910bac9a4dde8dbc226f06b947f58eb35820069f0c1b8ff84c9f","0x3ee19c732b9d2b5fe7b9797b8651dfe19f70eb366346ac7d0167518866a980e3","0xe359c3a9fb1bbf5cdf221c4b3f07ea1ad3eeb407660940a34268aebae29e4f24","0xf8382abf91c8bc23fb27a929d08bff6aeff001aae58b062488cad5984d52d3d8","0xd2ea9116729935a4d3a55afe7308c804e0ee742e538657c189397ea0745c95fa","0x00f597323c668529ae4ba6f05a5899e3e419c943c87ab315107be95f166cc71b","0x4361cdebb3cc58f58d7b96a0df207ab8413bed1f484d05122b42939068b50805","0xda1d9486f368ac7a32c2b45b3a8e99241b9d76e76d62b4efb4d7d9711597ebdf","0x6e2d862010b81d26884a38a6343c9d04d0ed5c8751d2a333a18ddf9fd8deb282","0x7e7043e2c7b147bb9b81849e7d926c625be1ff61f78aa7142295627e817b2132","0x344950db3d11bef646e9f7ea0f0a2a38ae1776f00ebee748199dcb8055d8b2f6","0x66fda39e4207c43ac2f49c1b75b9278171c6fae1ef2f68717aa916898f371123","0x897aaf76286e8e77831537466f346950ebbcdfa6a41bc4f67e7c0db324f519ed","0xc6195bd2ef4c97b8e9aac11eb795b5b407da52da93a0d69ea48fcc1bc5ed57cc","0xa05970b103532874357cad3d0e7752b54be79ac28a62c3b8380e9abfd7f8734c","0x8653a1863ec56056f629b0444b580757b854797d80345225ef97448b47f2b3c0","0xaf2023f94823452108a9579d09027a0f88652895c9599990be4c00d20175a406","0x0e40e813219451fa9de8509be8ca8802fee6483624ae4ca20703e70a3abef6d7","0xf706032373d519621654e5d9171ac7cf3d40c5da2541c8d475a12307f8c5720a","0x97cd59aa046b42712ef1b16db8eb055b1aa2841d9d06498b9f5e9831cdc5aa45","0xcf4a61d34a1d19b936f336d251abe02e6bb5a7d9c89108839bc4ff1b9713dea8","0x2dd851cf467a5f4c0cf32eee0398933cd8c5a048e5c3f96af5073b7a216d06f6","0x6e10e843284bc5e07bc8b75cf2904cba84c2ec8e2a7baa9cb425ea74ebac5b46","0xcd8ef4f11a5648f0084b29bfbb5a2cc8448e8d019a9929f2b7bff0a8cf30d854","0xa7d7592c4a6755a62f3a5e6b1a8c06714ef7ea98f77c5de8664541b51f6638b4","0xe22f6dc9ae3e93b6ec448147497b22e30157f64b8d40386eb1d1ae10fd64aad2","0x22802f854169e0b0ce6e99a333fc45d8c4a58d1c1225d0e4001c681997314a7a","0x72d1ca69bb5d63a7d4f650464d4c0cb97b174a335c301b3489970f6ccaf7fced","0x6f4e21bd36d54f424d347b7c4cf29b1be37306aa195b08f5f652b21e57ee078e"]} diff --git a/cmd/workload/queries/history_sepolia.json b/cmd/workload/queries/history_sepolia.json new file mode 100644 index 000000000..cd2182b5d --- /dev/null +++ b/cmd/workload/queries/history_sepolia.json @@ -0,0 +1 @@ +{"blockNumbers":[0,3891,7782,11673,15564,19455,23346,27237,31128,35019,38910,42801,46692,50583,54474,58365,62256,66147,70038,73929,77820,81711,85602,89493,93384,97275,101166,105057,108948,112839,116730,120621,124512,128403,132294,136185,140076,143967,147858,151749,155640,159531,163422,167313,171204,175095,178986,182877,186768,190659,194550,198441,202332,206223,210114,214005,217896,221787,225678,229569,233460,237351,241242,245133,249024,252915,256806,260697,264588,268479,272370,276261,280152,284043,287934,291825,295716,299607,303498,307389,311280,315171,319062,322953,326844,330735,334626,338517,342408,346299,350190,354081,357972,361863,365754,369645,373536,377427,381318,385209,389100,392991,396882,400773,404664,408555,412446,416337,420228,424119,428010,431901,435792,439683,443574,447465,451356,455247,459138,463029,466920,470811,474702,478593,482484,486375,490266,494157,498048,501939,505830,509721,513612,517503,521394,525285,529176,533067,536958,540849,544740,548631,552522,556413,560304,564195,568086,571977,575868,579759,583650,587541,591432,595323,599214,603105,606996,610887,614778,618669,622560,626451,630342,634233,638124,642015,645906,649797,653688,657579,661470,665361,669252,673143,677034,680925,684816,688707,692598,696489,700380,704271,708162,712053,715944,719835,723726,727617,731508,735399,739290,743181,747072,750963,754854,758745,762636,766527,770418,774309,778200,782091,785982,789873,793764,797655,801546,805437,809328,813219,817110,821001,824892,828783,832674,836565,840456,844347,848238,852129,856020,859911,863802,867693,871584,875475,879366,883257,887148,891039,894930,898821,902712,906603,910494,914385,918276,922167,926058,929949,933840,937731,941622,945513,949404,953295,957186,961077,964968,968859,972750,976641,980532,984423,988314,992205,996096,999987,1003878,1007769,1011660,1015551,1019442,1023333,1027224,1031115,1035006,1038897,1042788,1046679,1050570,1054461,1058352,1062243,1066134,1070025,1073916,1077807,1081698,1085589,1089480,1093371,1097262,1101153,1105044,1108935,1112826,1116717,1120608,1124499,1128390,1132281,1136172,1140063,1143954,1147845,1151736,1155627,1159518,1163409,1167300,1171191,1175082,1178973,1182864,1186755,1190646,1194537,1198428,1202319,1206210,1210101,1213992,1217883,1221774,1225665,1229556,1233447,1237338,1241229,1245120,1249011,1252902,1256793,1260684,1264575,1268466,1272357,1276248,1280139,1284030,1287921,1291812,1295703,1299594,1303485,1307376,1311267,1315158,1319049,1322940,1326831,1330722,1334613,1338504,1342395,1346286,1350177,1354068,1357959,1361850,1365741,1369632,1373523,1377414,1381305,1385196,1389087,1392978,1396869,1400760,1404651,1408542,1412433,1416324,1420215,1424106,1427997,1431888,1435779,1439670,1443561,1447452,1451343,1455234,1459125,1463016,1466907,1470798,1474689,1478580,1482471,1486362,1490253,1494144,1498035,1501926,1505817,1509708,1513599,1517490,1521381,1525272,1529163,1533054,1536945,1540836,1544727,1548618,1552509,1556400,1560291,1564182,1568073,1571964,1575855,1579746,1583637,1587528,1591419,1595310,1599201,1603092,1606983,1610874,1614765,1618656,1622547,1626438,1630329,1634220,1638111,1642002,1645893,1649784,1653675,1657566,1661457,1665348,1669239,1673130,1677021,1680912,1684803,1688694,1692585,1696476,1700367,1704258,1708149,1712040,1715931,1719822,1723713,1727604,1731495,1735386,1739277,1743168,1747059,1750950,1754841,1758732,1762623,1766514,1770405,1774296,1778187,1782078,1785969,1789860,1793751,1797642,1801533,1805424,1809315,1813206,1817097,1820988,1824879,1828770,1832661,1836552,1840443,1844334,1848225,1852116,1856007,1859898,1863789,1867680,1871571,1875462,1879353,1883244,1887135,1891026,1894917,1898808,1902699,1906590,1910481,1914372,1918263,1922154,1926045,1929936,1933827,1937718,1941609,1945500,1949391,1953282,1957173,1961064,1964955,1968846,1972737,1976628,1980519,1984410,1988301,1992192,1996083,1999974,2003865,2007756,2011647,2015538,2019429,2023320,2027211,2031102,2034993,2038884,2042775,2046666,2050557,2054448,2058339,2062230,2066121,2070012,2073903,2077794,2081685,2085576,2089467,2093358,2097249,2101140,2105031,2108922,2112813,2116704,2120595,2124486,2128377,2132268,2136159,2140050,2143941,2147832,2151723,2155614,2159505,2163396,2167287,2171178,2175069,2178960,2182851,2186742,2190633,2194524,2198415,2202306,2206197,2210088,2213979,2217870,2221761,2225652,2229543,2233434,2237325,2241216,2245107,2248998,2252889,2256780,2260671,2264562,2268453,2272344,2276235,2280126,2284017,2287908,2291799,2295690,2299581,2303472,2307363,2311254,2315145,2319036,2322927,2326818,2330709,2334600,2338491,2342382,2346273,2350164,2354055,2357946,2361837,2365728,2369619,2373510,2377401,2381292,2385183,2389074,2392965,2396856,2400747,2404638,2408529,2412420,2416311,2420202,2424093,2427984,2431875,2435766,2439657,2443548,2447439,2451330,2455221,2459112,2463003,2466894,2470785,2474676,2478567,2482458,2486349,2490240,2494131,2498022,2501913,2505804,2509695,2513586,2517477,2521368,2525259,2529150,2533041,2536932,2540823,2544714,2548605,2552496,2556387,2560278,2564169,2568060,2571951,2575842,2579733,2583624,2587515,2591406,2595297,2599188,2603079,2606970,2610861,2614752,2618643,2622534,2626425,2630316,2634207,2638098,2641989,2645880,2649771,2653662,2657553,2661444,2665335,2669226,2673117,2677008,2680899,2684790,2688681,2692572,2696463,2700354,2704245,2708136,2712027,2715918,2719809,2723700,2727591,2731482,2735373,2739264,2743155,2747046,2750937,2754828,2758719,2762610,2766501,2770392,2774283,2778174,2782065,2785956,2789847,2793738,2797629,2801520,2805411,2809302,2813193,2817084,2820975,2824866,2828757,2832648,2836539,2840430,2844321,2848212,2852103,2855994,2859885,2863776,2867667,2871558,2875449,2879340,2883231,2887122,2891013,2894904,2898795,2902686,2906577,2910468,2914359,2918250,2922141,2926032,2929923,2933814,2937705,2941596,2945487,2949378,2953269,2957160,2961051,2964942,2968833,2972724,2976615,2980506,2984397,2988288,2992179,2996070,2999961,3003852,3007743,3011634,3015525,3019416,3023307,3027198,3031089,3034980,3038871,3042762,3046653,3050544,3054435,3058326,3062217,3066108,3069999,3073890,3077781,3081672,3085563,3089454,3093345,3097236,3101127,3105018,3108909,3112800,3116691,3120582,3124473,3128364,3132255,3136146,3140037,3143928,3147819,3151710,3155601,3159492,3163383,3167274,3171165,3175056,3178947,3182838,3186729,3190620,3194511,3198402,3202293,3206184,3210075,3213966,3217857,3221748,3225639,3229530,3233421,3237312,3241203,3245094,3248985,3252876,3256767,3260658,3264549,3268440,3272331,3276222,3280113,3284004,3287895,3291786,3295677,3299568,3303459,3307350,3311241,3315132,3319023,3322914,3326805,3330696,3334587,3338478,3342369,3346260,3350151,3354042,3357933,3361824,3365715,3369606,3373497,3377388,3381279,3385170,3389061,3392952,3396843,3400734,3404625,3408516,3412407,3416298,3420189,3424080,3427971,3431862,3435753,3439644,3443535,3447426,3451317,3455208,3459099,3462990,3466881,3470772,3474663,3478554,3482445,3486336,3490227,3494118,3498009,3501900,3505791,3509682,3513573,3517464,3521355,3525246,3529137,3533028,3536919,3540810,3544701,3548592,3552483,3556374,3560265,3564156,3568047,3571938,3575829,3579720,3583611,3587502,3591393,3595284,3599175,3603066,3606957,3610848,3614739,3618630,3622521,3626412,3630303,3634194,3638085,3641976,3645867,3649758,3653649,3657540,3661431,3665322,3669213,3673104,3676995,3680886,3684777,3688668,3692559,3696450,3700341,3704232,3708123,3712014,3715905,3719796,3723687,3727578,3731469,3735360,3739251,3743142,3747033,3750924,3754815,3758706,3762597,3766488,3770379,3774270,3778161,3782052,3785943,3789834,3793725,3797616,3801507,3805398,3809289,3813180,3817071,3820962,3824853,3828744,3832635,3836526,3840417,3844308,3848199,3852090,3855981,3859872,3863763,3867654,3871545,3875436,3879327,3883218,3887109,3891000,3894891,3898782,3902673,3906564,3910455,3914346,3918237,3922128,3926019,3929910,3933801,3937692,3941583,3945474,3949365,3953256,3957147,3961038,3964929,3968820,3972711,3976602,3980493,3984384,3988275,3992166,3996057,3999948,4003839,4007730,4011621,4015512,4019403,4023294,4027185,4031076,4034967,4038858,4042749,4046640,4050531,4054422,4058313,4062204,4066095,4069986,4073877,4077768,4081659,4085550,4089441,4093332,4097223,4101114,4105005,4108896,4112787,4116678,4120569,4124460,4128351,4132242,4136133,4140024,4143915,4147806,4151697,4155588,4159479,4163370,4167261,4171152,4175043,4178934,4182825,4186716,4190607,4194498,4198389,4202280,4206171,4210062,4213953,4217844,4221735,4225626,4229517,4233408,4237299,4241190,4245081,4248972,4252863,4256754,4260645,4264536,4268427,4272318,4276209,4280100,4283991,4287882,4291773,4295664,4299555,4303446,4307337,4311228,4315119,4319010,4322901,4326792,4330683,4334574,4338465,4342356,4346247,4350138,4354029,4357920,4361811,4365702,4369593,4373484,4377375,4381266,4385157,4389048,4392939,4396830,4400721,4404612,4408503,4412394,4416285,4420176,4424067,4427958,4431849,4435740,4439631,4443522,4447413,4451304,4455195,4459086,4462977,4466868,4470759,4474650,4478541,4482432,4486323,4490214,4494105,4497996,4501887,4505778,4509669,4513560,4517451,4521342,4525233,4529124,4533015,4536906,4540797,4544688,4548579,4552470,4556361,4560252,4564143,4568034,4571925,4575816,4579707,4583598,4587489,4591380,4595271,4599162,4603053,4606944,4610835,4614726,4618617,4622508,4626399,4630290,4634181,4638072,4641963,4645854,4649745,4653636,4657527,4661418,4665309,4669200,4673091,4676982,4680873,4684764,4688655,4692546,4696437,4700328,4704219,4708110,4712001,4715892,4719783,4723674,4727565,4731456,4735347,4739238,4743129,4747020,4750911,4754802,4758693,4762584,4766475,4770366,4774257,4778148,4782039,4785930,4789821,4793712,4797603,4801494,4805385,4809276,4813167,4817058,4820949,4824840,4828731,4832622,4836513,4840404,4844295,4848186,4852077,4855968,4859859,4863750,4867641,4871532,4875423,4879314,4883205,4887096,4890987,4894878,4898769,4902660,4906551,4910442,4914333,4918224,4922115,4926006,4929897,4933788,4937679,4941570,4945461,4949352,4953243,4957134,4961025,4964916,4968807,4972698,4976589,4980480,4984371,4988262,4992153,4996044,4999935,5003826,5007717,5011608,5015499,5019390,5023281,5027172,5031063,5034954,5038845,5042736,5046627,5050518,5054409,5058300,5062191,5066082,5069973,5073864,5077755,5081646,5085537,5089428,5093319,5097210,5101101,5104992,5108883,5112774,5116665,5120556,5124447,5128338,5132229,5136120,5140011,5143902,5147793,5151684,5155575,5159466,5163357,5167248,5171139,5175030,5178921,5182812,5186703,5190594,5194485,5198376,5202267,5206158,5210049,5213940,5217831,5221722,5225613,5229504,5233395,5237286,5241177,5245068,5248959,5252850,5256741,5260632,5264523,5268414,5272305,5276196,5280087,5283978,5287869,5291760,5295651,5299542,5303433,5307324,5311215,5315106,5318997,5322888,5326779,5330670,5334561,5338452,5342343,5346234,5350125,5354016,5357907,5361798,5365689,5369580,5373471,5377362,5381253,5385144,5389035,5392926,5396817,5400708,5404599,5408490,5412381,5416272,5420163,5424054,5427945,5431836,5435727,5439618,5443509,5447400,5451291,5455182,5459073,5462964,5466855,5470746,5474637,5478528,5482419,5486310,5490201,5494092,5497983,5501874,5505765,5509656,5513547,5517438,5521329,5525220,5529111,5533002,5536893,5540784,5544675,5548566,5552457,5556348,5560239,5564130,5568021,5571912,5575803,5579694,5583585,5587476,5591367,5595258,5599149,5603040,5606931,5610822,5614713,5618604,5622495,5626386,5630277,5634168,5638059,5641950,5645841,5649732,5653623,5657514,5661405,5665296,5669187,5673078,5676969,5680860,5684751,5688642,5692533,5696424,5700315,5704206,5708097,5711988,5715879,5719770,5723661,5727552,5731443,5735334,5739225,5743116,5747007,5750898,5754789,5758680,5762571,5766462,5770353,5774244,5778135,5782026,5785917,5789808,5793699,5797590,5801481,5805372,5809263,5813154,5817045,5820936,5824827,5828718,5832609,5836500,5840391,5844282,5848173,5852064,5855955,5859846,5863737,5867628,5871519,5875410,5879301,5883192,5887083,5890974,5894865,5898756,5902647,5906538,5910429,5914320,5918211,5922102,5925993,5929884,5933775,5937666,5941557,5945448,5949339,5953230,5957121,5961012,5964903,5968794,5972685,5976576,5980467,5984358,5988249,5992140,5996031,5999922,6003813,6007704,6011595,6015486,6019377,6023268,6027159,6031050,6034941,6038832,6042723,6046614,6050505,6054396,6058287,6062178,6066069,6069960,6073851,6077742,6081633,6085524,6089415,6093306,6097197,6101088,6104979,6108870,6112761,6116652,6120543,6124434,6128325,6132216,6136107,6139998,6143889,6147780,6151671,6155562,6159453,6163344,6167235,6171126,6175017,6178908,6182799,6186690,6190581,6194472,6198363,6202254,6206145,6210036,6213927,6217818,6221709,6225600,6229491,6233382,6237273,6241164,6245055,6248946,6252837,6256728,6260619,6264510,6268401,6272292,6276183,6280074,6283965,6287856,6291747,6295638,6299529,6303420,6307311,6311202,6315093,6318984,6322875,6326766,6330657,6334548,6338439,6342330,6346221,6350112,6354003,6357894,6361785,6365676,6369567,6373458,6377349,6381240,6385131,6389022,6392913,6396804,6400695,6404586,6408477,6412368,6416259,6420150,6424041,6427932,6431823,6435714,6439605,6443496,6447387,6451278,6455169,6459060,6462951,6466842,6470733,6474624,6478515,6482406,6486297,6490188,6494079,6497970,6501861,6505752,6509643,6513534,6517425,6521316,6525207,6529098,6532989,6536880,6540771,6544662,6548553,6552444,6556335,6560226,6564117,6568008,6571899,6575790,6579681,6583572,6587463,6591354,6595245,6599136,6603027,6606918,6610809,6614700,6618591,6622482,6626373,6630264,6634155,6638046,6641937,6645828,6649719,6653610,6657501,6661392,6665283,6669174,6673065,6676956,6680847,6684738,6688629,6692520,6696411,6700302,6704193,6708084,6711975,6715866,6719757,6723648,6727539,6731430,6735321,6739212,6743103,6746994,6750885,6754776,6758667,6762558,6766449,6770340,6774231,6778122,6782013,6785904,6789795,6793686,6797577,6801468,6805359,6809250,6813141,6817032,6820923,6824814,6828705,6832596,6836487,6840378,6844269,6848160,6852051,6855942,6859833,6863724,6867615,6871506,6875397,6879288,6883179,6887070,6890961,6894852,6898743,6902634,6906525,6910416,6914307,6918198,6922089,6925980,6929871,6933762,6937653,6941544,6945435,6949326,6953217,6957108,6960999,6964890,6968781,6972672,6976563,6980454,6984345,6988236,6992127,6996018,6999909,7003800,7007691,7011582,7015473,7019364,7023255,7027146,7031037,7034928,7038819,7042710,7046601,7050492,7054383,7058274,7062165,7066056,7069947,7073838,7077729,7081620,7085511,7089402,7093293,7097184,7101075,7104966,7108857,7112748,7116639,7120530,7124421,7128312,7132203,7136094,7139985,7143876,7147767,7151658,7155549,7159440,7163331,7167222,7171113,7175004,7178895,7182786,7186677,7190568,7194459,7198350,7202241,7206132,7210023,7213914,7217805,7221696,7225587,7229478,7233369,7237260,7241151,7245042,7248933,7252824,7256715,7260606,7264497,7268388,7272279,7276170,7280061,7283952,7287843,7291734,7295625,7299516,7303407,7307298,7311189,7315080,7318971,7322862,7326753,7330644,7334535,7338426,7342317,7346208,7350099,7353990,7357881,7361772,7365663,7369554,7373445,7377336,7381227,7385118,7389009,7392900,7396791,7400682,7404573,7408464,7412355,7416246,7420137,7424028,7427919,7431810,7435701,7439592,7443483,7447374,7451265,7455156,7459047,7462938,7466829,7470720,7474611,7478502,7482393,7486284,7490175,7494066,7497957,7501848,7505739,7509630,7513521,7517412,7521303,7525194,7529085,7532976,7536867,7540758,7544649,7548540,7552431,7556322,7560213,7564104,7567995,7571886,7575777,7579668,7583559,7587450,7591341,7595232,7599123,7603014,7606905,7610796,7614687,7618578,7622469,7626360,7630251,7634142,7638033,7641924,7645815,7649706,7653597,7657488,7661379,7665270,7669161,7673052,7676943,7680834,7684725,7688616,7692507,7696398,7700289,7704180,7708071,7711962,7715853,7719744,7723635,7727526,7731417,7735308,7739199,7743090,7746981,7750872,7754763,7758654,7762545,7766436,7770327,7774218,7778109,7782000],"blockHashes":["0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9","0x6a5e5dd0c78e0a5f1e7dac39c11bd6c7e3ca6bccb2498aa27a8b41c9228a8dad","0x56e8d2e17c6e23f0a4a0675d7553623dd40f9a1de4fb6a7cbceb8252e8bc0fb6","0x2d382397412eadbbbf39f7886bdb6e5da994ead4e149d5c05b6eb23ab7c5e751","0xaf5759e9bc2f63dd342e1996c603cf9c76c43bd34aa524c0c7674cda469893a0","0xe92c7a3ec123cc5b82ebafcb81cdfd5d626ec84643d6a51ee9a8d158de5f9818","0x73af17bae45c632fc8caabb1b22cd8ee4c849f9838634ff933b9ead1b1501102","0x9e23c2b94f844681194af7025bad29f4e3430017c851556c4da8002fb22ccc14","0x1bfbde79a1b433b2da971ca4acf3ccd48a1f6320676df628f2be26cf42245670","0x13eef2769e1306c8b5ed55118888e43090a2796d181c1a724d777e45465a9539","0xe056293ff26cc6d9786cb2fbbb939b7f622e80d6c68561a4ffdaf725500b5282","0xb5cea9ced2a6a8e77d0f5d2b83350709b4c15a2f4aa9f96a689e6335b4057bf4","0x5d97ae64d3ab2b79c6a644c730060d37680b99bd6e0b9a6877cacd512430f3d1","0xe8d655116a06920f346b90141cf5c87b7adfcd0ef3ed3210f670450299221bef","0xe7c355f7dbfb2f5b488f451d64c73300dac6ada83679b84516cd0ff469358163","0xbde250922bb26abfd64386f0a07b26e358f062addfa372dee24db61e2c811683","0x26ff48db3e388e2f415eb07f62397c1931c8f9da69bfedca74309ab88feaa497","0x9045a2d05676e015b3b9ce80e15e039683b1d8f7cf488aab82239e4fdfa9ebdc","0xde7fe668300229b05e2f92b02ac6df08659dd11327e8b1fb0d583b172e08c328","0xb5840dd7603f2dd85481ddf2d7f425b41a66bb74e08770749dae3bbbfdc5267b","0xbb7d85fe04f101c85a4e41a1127be5297d7cff1de0e7dda6a08ae863f007039e","0xd38800a1eccead6b9e310353811a21db0b7a67cfd413234521ecbdc9fe16a795","0x517f4eb0e3bcc5f14509ee5558fb660b2f656189f3891161448d5a954baa9934","0x55415e34a9d3b2db48dede7aab36d2d0fd2c31d2df5f819b63ae1910dd853ec6","0x0e0dbe1f90c7491c3e2eb879c3e9fa45d316dfec0f95d8ffcdfe9fb78a146c15","0xe2066616bbac04eb54453e820b4f211a7816e0aa36ef2a1569a01a2dc307caa6","0x0ddf0475bf16edca3ae84f4a834f494a07564d9ac1b03d4390c5050f11866888","0xfa41fc223ac8391fdb8cc256beb5be2d60b379d47fcc0aa4e326fb0b8a68b2bd","0x806ebc642c35fd389ed352337c7a835fb833c4d73d6885d4cbf4cfa6b098c19d","0xdbbe5d201f91e4b8ef7224d7379809d1ab97ec6084eb9acd37ecb4b77d342e59","0x17e7a7c82f3725f85f6d135b5f018a4a1329db4dcd5c65446b25825492e6255c","0x79ee935a172fddcf92b5479aa56f5de7daeae2fa6de6d2288e2ed4d7d5754ee8","0x4dfe6ad112a51fae4c63a21d51cca1e03f323b8ddd780ea420acd203dd556c78","0x4a7be2ff8078bc5a718e2670c1d3868192858580bf7066bc109967ac23a4fd65","0x1752155050371d1c024c336f0d7e3a9c57b0908f61cf24f96961ee3804344d14","0x886ec8ff26260a27e89d3d1b7b3a476aef3f546c34ec70aa2d861257d210d074","0xde0ff170dbd6aaf5952940c1dc5c9647e62ebb6467027891499bbbf0d7060219","0x76b4f5a9183f454b969f3b1f70ba94ff941525b518037ce856df338ae7665590","0xe549cb2c97c4313ab8e890914c3d39eb7cc1f13176b89dc3627d24ea68269205","0xe3e1ac6b827df008979a2fc7f3a1d58e3855167f167968a8f55d26ec9d319d6e","0x71d490ce01fb6770912c6f7da92389444bd47324e65d7eaeb905abfaa085ede9","0xdf2ff5c50b2e8d97ee294dd62f5962bf77792e05492f5c63be5c8f10c887bbbf","0x0b8afe11e930782860eb7338b9cebbddcb4173c37ca08a404cac63b0987827eb","0xa6b64078e93bedd8f3f46d94806211b01a084f21af4a19ed5567fac9595e4e57","0x65296e86d5bf3dc314197abb08e35c78d632cc496215fc4a9c43f2b057a5a536","0x120dca2ede53ffcae454c00aaad1cbe81ec7700e4811fae7dd5cfd4b39968b7c","0x8db730bae43afcd4fe93c27c999d3080f0ae82a5393e6c7d0b12a7968f8e0e56","0x69757d54a02e1ff2dd7c529c61d5768e70c649d1b9b610429ddd6f568f7cd3da","0xdbe1dc11bb3696803603348a6f134ec8a8011a58631bd8b8fcfce33b9ab17b5f","0x5a6520c2d86fe5f27c8c53c0492ab1cc6a23f5fe994585c0edb79c7dd59bec8f","0x9a2c404e659a916b900404b248d775dbc778fee16887fe3a528907edfb9addf9","0x1fb56ca23210109f99795c10ed0864c2e74fee53523e46b9700e9d39123ff244","0x9ba63b539669ee596d34289040e8d6b7bddad437faf031af580266d03d89044b","0x11cd367646ff57c2e1c9093b8d9ffc37062746db0a1a753b1646235da94ed41c","0x32bf3478839397768b5c3a2544afe66f532292cba4a68faccb542b4199fdb746","0x7cd1a84e64f4bc0914c9beeb7aee4b4a0b971b835569b5d0020c96a00e3e8700","0x79def0ca19bd78eae862cc933ba1bd50340d9e1ce57cb42b4d8ad24f5983ca0d","0x873f0effd9354d5b315aafa061f3803ec084b3d636d7f1bae5ffe93d97febcc1","0x4b0baef9790b52886567893c955ddae33fd4902bd4c74014e894e199f1fe7f49","0x034944e08cfb684d571a01ebba0f0c74377aa41e547082d328785d5ff7867057","0xda330e5d73a73f49ca60f7b1976ca33586471d361c9224b863dbff0d4e01b3f7","0xc91a1850203aeb85cde0541294280dfefaf0934872a6261194883464ce92e235","0x8ad9dc186f616ffce7a40fbf839946dc90c77c06cdf00729c1ec6e3576ba165a","0x4c42d58fef7e3d1362637c18ef1f788863f75da743ead992b1fa985b327cc17d","0x4bd935f1659d1a567232c5d57549ac46b2a906a236aadb440c5136883aa19f5c","0x00c22ba65d79f9a397edb65fbab417dc6c9500ce4df4140b5bcd67ae7732f0dc","0x238900afc196efe78f5d8729a021d3dd848f5279a65feeaf880503588c0b8b42","0x1970f3dadb7a2fac21e6299668ab50fe32900229cffe785e086dd3bb0b7a294b","0x140797a5d35c4c88a92135124284f2614afed550959d849da16a1bd268bc993c","0x1f60f3d4162b854a3f143b45960ffb6aaf72433840f6a8ccadc3e7f3abee72b8","0x20e63d2b8e6aa4cd017e4341906d8152bbde189edcafd2c73f42c15aab21335f","0xbd7ee5796e49360eea060c3b264d044655de534e52a2c215b76d92ebe868692c","0xb48518ec7e94aa1001de8e0c7c2ff2da6cee21eed2812dd2b04a549119721d42","0xe18a937341267e60008b5b11f3aa3c5dc083bdc9eab4eb397ee02c4b0644b849","0x425844a7df04f298dff19cb8184d382e5c2f9250b035b027cc8bca7e4ecf96d2","0xf3445ebbec41a2bc88fb830b3b45dfe2f9516459c215e570a151cfa0083c6ddd","0xddb06c193b7c9212fccbe2113217177a4ac5195a913786966e60725c8174cd3b","0x4f89efb55de40b6eed5a09cb9aa3c32dbc9048137554519258daa2ccb2821265","0x5f6ed1f259409eef13e9477ee4e3156b996129d91bfa3b3827d2532af9153a1b","0x6da7034676cee23c94650c031b919009d19b9bfaaca5fd59fc3f6c6a3a1a2ab7","0x4001e2d09200e0a017d3f5258894a76a4e00744602a149febfd6cf46a93d54e7","0x9f507eafee4feaa2684335eb11d77e3383560fc6f04d2363799197bf8a4a0957","0x58808a22cf58c18ace2a29f9057ed023f269d9b0a05a9f575b03d54afc4d00d0","0x9bf4104e502b6a9ca5c561bf77a2a214d5a13971c223adc4ceae4bed99336289","0x5707d846dd1b368e9c6ea0e9238f7a8a8559d128461a1769e3da71bc7427b247","0xeeb857fb70beb5cb37903b48e2b278c94542318f37a27d0e3311b32aa2e47025","0x6b7ffb29c96c75672a46428b64cee8c12d12a82c721ec0f59f989bec8f6e0533","0x883745edc53a273e2f164918651c88ae6d799a344c5cdff6af9e1dacfa66e43a","0xd7d55627e46030db89f6a8a2203e3f493a992937ebc8be7afcabd5867530311b","0xb92b2a5b6515ed3e26b916fa52d145f226148ec78a0cc5f9a756627c37d20172","0x993aaaea3962f0c249b8530f119844f88fe06d7bc2fbebaffb964af1643a803f","0xbc42f890ece3b81c84a810f546f558e5a450fa94da6b8daf1bd560695e6c88b5","0x71f14bf26b7153c15e447a43c5c8ef6932c73fa17f6a78085f02a9424e8d61f8","0x436d24afe666f58f4c8735b5d3812bb07e9a539edf2566ff9f444d9390d88372","0x8f4785e042a380cdc51181aa2c7646a07df15810b7c292708afcab9992a3abf7","0x4473a556b89cb6bbaab52bb19a53ab1704e5a641327d3e10f532a514f66c74dd","0xbddb2c0b98976e0b70113b98f086a50b043eacc2f2fa3da76335940110f1cdf0","0x79a2e78c2dbb5575c6044d709c4b8cc81131949e9c8c3b37f8d4e6ded4870844","0x3c9647cdaa30be4983b881ac4f4f326fc50d3164ac0f22e13bb710501e709afb","0xdcf9325fd02b68742924fef19aa3b2cd9b53e1c038448be9821e42e84453e093","0x3b6fa6c322d02c6e0d9d0bdebfb9fccc03449140c0d22bbbc51d63e4b7d5ac39","0xc4d359148d43b8ac64d9c21cd3a63d33437a32f28440345eaaaa53143e265b1c","0x367b480f4fc578f00c7810b2f1848cc7deab299eead79ad07d6dc720c2e98057","0x3bd80bb33eb73858696a9c4086f2382a82f197decaeb4f1a693a15cc274dd308","0x648aeb6426dd26b7f89c442c12a7617bc06719e682f64d463bc6b3a1a92d5a42","0xbc2505545baae5bf12c4858364372418ec47f39163536dd3389911f17a25f636","0x91ecf357ac1fc4ef104fbb53b9cb601a285b9848154b41bb4433d3bcfd611b2f","0x5c0a6ee68beb9fa0120017bcb6b39fd6285bf72b527f0f44443ee5d530525d3c","0x826b735fc8526f1d4fc187e5d0571b317281350df721cd3d796a1b2351702453","0x1211a5ff02d633b0c28db49b099e992cd0c76542d4591bb99e30a4cc3c56493b","0x7c0bcaaa05a216247bd475511f02910f537c1e257042c055b387d5faa587089d","0x8927c2bade536ec9b22fe3773e105f3b402d693223b14a00ad8223c381546cdb","0x53b0185bd9421a9dee71c47c809097fb81f6cf3dd9132d60a435f294c1db8c3e","0xf14875d8237cbe37a097e7cd619acd03c5e8cf87c06195f477f39d5cde5200f5","0x67e0c2d744571c503f82dd5f2ed9684c2a1f54bf810185e48852be4a4c6d314e","0xbbeba71a8127da480a1fa1871d19187e9fbfc1ed9758c02378cd76cb471f5f98","0x700520299639ad6c9484bb8e1ae39076e7211ab7903786a920f83ac67db527ce","0x8ba1f231d3616ce01704a204ead270c230da7bec8d2b7ae2ce5e02a45c617943","0x7b889f5761abbb56967474d10272c8c9793f938db63f9a9f2a9bb6738fb3e2ee","0x2750001a703c2e723ca0209aa84cebf1c6cc0dbd79a2f40be2a6c6c32cacae07","0x8f2509d14761459510cf516c08917f73c9ed944ad40069abc514944d344b096e","0x764287b8c7baec1868c8765be5d440b03cf99fed0219a037665d7e8dbf1537a8","0xc75096fb3413bbb962dd8edb9ef3118cf7e0f3a6f4747032e5b834f6ec1cc804","0x0aff4f2d4999d363863725f02d75d7545096bd694acf87299e1a77bc74a31239","0x59b659f0c7901782893280b6ba2aca4b636ba085481727d055c1340852dd313b","0x7e13927f4f3bc91384507aca45c6d09a8eca93a9f7182e9a0df01cb7398cfd58","0x8d5a1b4d786b27c24435ca650fdaba2ed5599d3b75b7008ec233d68d3a3a29fc","0xcb440c940d5062e0a296df840624e477d51dccf7676015960e3e18426c103324","0x40dc376bfd55dd54f19084d7e47b3c6123ec3a7b3e4ef9f85d0269c0474af630","0xd2a7072e8f4e39e446541c8aa3db3ced9c234bb8e3de7d9d8d57703370d40e3a","0x02d46155b1c8aeeede3b81ff8352e2a7fc72361b99cc9d30c986f65dc116c08a","0x5f227cb0a932cb1dd055619d1f4b6a943365a5c3c8bd13ebc6ff85b4e3f31c92","0x201d9c9482deace6516cb4a618044c4c81267e64ff0067e66dd3389382b00b3e","0xc2567edd06689fb8459c6fe70ca17cc5705edf866332fa9a05fba3846e0fa664","0x1001d5f65797eebf149925a4e2c6f98cf6372336275671e52f35650de165e0f2","0x6241be737c66770c9257007122dbebd22dc6e71fc91a905672370c8eb6bf8218","0x8ca68babf6dd415ecdf3b7c29b0cd4795d8fa921889712104b241e529bf2b70b","0x8a0b0a5b165e08cdff4b70c681ccdcbcda689eadc7917f5c28d43403437d0808","0x94ea6dbcf12a8aa351a18919810be4b589c812d845c3ef88b825b089e926d194","0xdef5d2c7ad5bfad8ceab130f96f4ab99d8f10da43e70e58e3fa16a93999c1103","0x23e4692a52f6520c981882e362424387c38834ddcc85111fb7389dc3679991f7","0xd6eabf3c58c9e07795a21779877a04e04d395358b3e3a8f3da4eec999a2ad554","0x8e16075267e12f477ecc0fbc1828be6ae5052734fe60ad26db32f3a52e58851f","0x56e91d613dfa7d4837faf609abb5fd2b1fc9a3caf2379fdb2feb4f359979c704","0xda196fc68db2440a157f346118181f887ae9c2ea5bbcda37102b5ca6cb712e59","0x0d3aa7257661ee45f790b752768ccf369bcb6f56a8daa4a2240be71c8b1f1b46","0x1d2935a309c72210fb057b9c3aeedfdafbce50fe3517fc16d88dba2632d53090","0xba36ea1abb70ad25d79956b63c7fb6ea2262a7ae4a0ce91cc26f775178bea0bb","0x7cea26d63f6be94e5f49bf1a0248ead0ebe6a772b4796afd997907721eb62b56","0x4df90f989db438656b79fdfbaa1a380fae096fb0da1e19f60a9843ea746737bb","0xa89c0a9cfc64d042544fa0dcba1f3c58a17df49f9124dfcc636b32ea470b1392","0x9d1696103f950e32f0f9aff2058ccdde0abcc6c8fc5abac4377ceab8d5d48f31","0xd858aaeac8af4d8e7ca50ece585f0c7c36ee6eaca6d3d844f80675e77331bcde","0x667a185eca6cd05471c0e41f9e74677c79be094f59c5e343b9877cf71bb77747","0x6df33b838e2c61b52e401e92c54e82602b26cc08abc1cccc7caaea884e15782d","0x6bbcfec4ee86743e11dfdfe93c90e2a3445fcebfbef81af6f84c455f680da2b7","0x619471d7f269123819a2f15bb4d89a184317ccd8e52173c67c6bce6929f5f9ea","0xac1fbd1bb252f851cc43647712730426243ffc0bd81844eb87751adc86af098d","0x16968efa489ef6bdd4c62d7dfa680c0999b888f44488ecb51fa25a84c02bb20e","0xc4929583a1919fa270e237172c552f593c100950a91401b8ffca7bbc33f9eabb","0xd2cecb07be9cb55b0978f6a9a7c1bc440bb69fb4240907a321326080c2471cad","0x6d248460ce1e99f1bda08fbcaf6d8e9ceb51d9556b4a61a93680e9545e24a877","0x60d3e56e6b4c8db208e6d4990e0c5fd56a73145a2afb8e4ed51ab5bc61d4ac0e","0x966c7c86066323cce2c6bf9be449d5c5b9fe1af9512b79fa52acaaad945b49e0","0x01124d20810818bb36514536e8ab46f26ac0ef7484986bf140be2fc3ca7055e0","0x11439b846ae8ad895c0a950a178a0a79ed32dd1e524273c4483373f72b248545","0x6848cc3689f522e1ec2f51f2eed00c1eab423ff99f8d7f0a217c2124a4b41c1f","0x3975f76ae8ef48de1d881d85411b15ec94ae6a7be53841f87d40a676cff67fd1","0xe42019efcdb940f7aa01fcc5ccefe9f95daf8f1b25babf07047c391f489fc695","0x5704786a9faf3832c08878b0a8a3dd55bde755c6a5fb9eb1460cad4bcb5aa6ac","0x028cba061b9bf842853b450e754d21caebf9099a877484ac56c944d34c31b1de","0x20d4311f7c91241c80a9e1fd44cb447087847d82560b72390538d40e4f1e8286","0xd1ac6c8e490b5cdcd552fc38362fb6536770a8eee63bb3b64bcddda963061bc7","0x8add5c34f3206da12c0b69e68b62b87baa4410fb146c13feb47caaa24ac9d45a","0x126ce8533624a4c5632aa3ef5daeb23c86a3d0fd0e644450499f9cf0db3c02b2","0x979bbde0ab37d1125e950f3a7ccde72805006927a7a394b51d1e68df8c2fb95e","0xbb46ebb76c7b0e5df80d41bf3ae2237107c879eb1cd0f2d0bc3a0f251f5a051f","0xd3c8a1f1bb55d5ca1c590f2824ec697f6f18700e1fc5df92ba98184013955767","0x013734d7d1f2291980b25b7ea1fa65e7ed036bada40b83cd5ce0faecacb6fb78","0x2640965949027e9546851a57910c7b062e21c57dcccd0465828a29fdb6658051","0xe06f963cb2f60b88fe4f9e417b7b93099792eae1fae00762959d475e114dcb33","0x7684acd1fa4de858ef1ab6107506123bfc81d35acc41a68ddf4deb2916495483","0x3a51e4f26072ac7630346e6c9fdde9480ea22ceb7fe32fd8803805ad4236ea73","0xb371b7535b5b51472d39ce08fcd1b7ca8c8f73915161faf4d132603eae889afd","0x3f0286711c4f86af6087e4f3005b31e43e459630a67d5500617efc8e2cb7767f","0x14cc8911a76345e22df3444955627ce0682b38897d62c5a4f1c5cd20c2da4099","0x776495a7e611ceb3dd4425e4751183f9bc6b2bed664e4fae82dce26e6ed464f4","0x3e0b2d9b08d8d098d9993061d9645c9940e79c73165226db0b8ae37aef96a77e","0xc0e34cadaf37effb86a31b097ec58f0e62c57edfe593ece974257eb30b0ef594","0x58d55b01ac9f32a4ef8d530b143b72e25894676788f6e12e8d50e772201f6c6e","0x665fb686582662b1437806e17398651927d7e008d6ca728e9f1ac6c0e54bc1cc","0xa2d32660a1d172d4cbdbd28ba539d8fb463dac8894fc953d1cee08be4a2f9fc5","0xa5e6014af0736129b032be53044e078cc566ada92f62c00c28d0154ac02cc552","0x0c70c064ab050b12a18b04a5cfc2d94dc24d283e88326726886dfe7e435b1a02","0xfac573c3856ff1eb798dc148cfb36cf8fcb560a56850007177560492e91ffe0f","0x6c830d778e5951a583ed9374cebad4122b46029dd5df5320347af44b1bf78675","0xff67d0f68da263f41e4cec55016a78075a8aa9f438e9229095a8e63935459911","0x112d770a2f52b6a5ea0d6f875bde92b9218a4cf4eb9dc4f8be96bb3db678bf9b","0xa19da52388df6fe762d3699a899babdbeddb0e9106679e0c8b4daf321619fcdd","0xebcf1da883f09b9a1569fe1fc9f66e7c3cfed1c96ae4841e4ed2a6c54fa27f4d","0xfdf0e44a5506a9c3c065f7691679ef090853b5da505c5afec3b060b89f8b7fca","0x5ad9824e85d11dc53d087b56580610d5754141899cb0d0285ecc88b749ea44c1","0x8192bf4bbf25981301e6068a113ed11b122228ddc9369c0d3cc54464fc83a104","0xc425c7ab1b4a6d29172897b6b77b05b90d69dee77cb2819f263bcaca6442b81d","0xcf7e560cb9597662b752aeac49f06570205beb6c0a2f33f96a4ba38bf3c7eef6","0x948018c536775723818936d02f806e236fd1b9dd6f13160bb812c15d7ef6191b","0x362c21c45d3d73b2330accb92716ab361f5052232dc4e4c7902350f0230f53de","0x560f31d04b81e8b690aaba7849f389da8662c762ef525e8dcd1f87f9989941db","0x30f5139cf627c85b895cf4f93d3fcd76c63c98819aa94fdce90b5e850f8574c6","0xed965260eb46c04a7cf45aaadeab9212d43ec595d206ecc8d6117789f2c72152","0x12ada731b4f45feed524de0b57b3549f420c01d033ba1efefdcec8109e897f5f","0x50140e58f3cb4353f99108a6a68cd2f98a744e0538af0e12803858bc4c919b4d","0x1c387e8c849699b1484c09218ca9208e54c1a1a225e4e6db789dc4bc3d97c1b0","0x6bc1cb0215bf4342d46f1e4409f6ac6ce1334d7084ef514c3f1b8d8e8870da1a","0xda6760f3429a4b014a1248508cc9c04d6bb0c73a6834f050ca0ea0df4a8666ec","0x67d83477d84148802a5cbb4e87d032250a19bf2c8af0c6c72ba2e74dacc11880","0x3ceaa55b8d99cadbcb6992d541d97ec96ed36f7037b31b47a2acb8fb9e7c5f62","0x71363238cf161171e5bed3c2be1ba915846864d058fbcb1d51f009ddcf4b473e","0x8c42cae018cbb1fd78c41a9d7df36df7260d8ce495e6bc649e210b20deca4d0d","0x0119aa1a3dfaa73d0d81b264633b5690505c83c144faa10a75673c45b60d9011","0xcd895ac194dc7e2ac2317648d049fee9042efcd9d805ffd03a430c3cdd7cadb2","0x7016e1b54afc7561d5ba579ae8590dbed7e5dbd059a88bf4d925fd91e2dd5e85","0x0d29d86c167fa921040270c53002404d6222c324a441002ffa3b0ef67ca82087","0xb2ecd182535a35364c23468391afb5695e6a7cbb048c8a3f535d70d661351c68","0x5a39d70df6ac72425309a0849e36b1b60d41cf64952625d69578196ff16673fe","0x77aebc75680ce3c2a1d105680e649acef6ddb29263e3893ccb9b9b07f4c185c2","0x10cb29027f689b2f7d009ad800aa42cbe54a15afabc43634e4b31fc97a6d5ef0","0x14333ff8f7b749c3a56a4f1ff4057409058a15894b4196b4e16e05c8827ee07a","0x9ad686d1b6a51c45adb8e91b6de0128425d1714d50f54227cbede89c197ee098","0x50400138df624e9fdf460d8745e4a47da8e0d2bafce3f4d674d535f07509d7aa","0x66c7abad9226c1936fb7fdfacef6e0e7d12f5d3e12353c34c0ecac02f3bc2e31","0xbb3de8bc462a7b453cb665a80a976367009b2b6a30ed924b82c8a7dff5529456","0x662dd5fe975d1a226b092579a6673cc3d5f248a3e9df3714469243e29da2053e","0x718f8e5ce1730af7a51d1176ba0182e6268339aa0724fd4035e9cf899db516a6","0x676460da6a84bd9066cd770d8afbfcb663d589bb54dc74d68c8cead0426fc17b","0x9fbbc356f7e50476445a7a4121832d4f174616a4cd4f11a5249e87540aaef0d5","0x2f14b6ffab8a03a65ecb5aa00a4a1994f15a2bc1e70830228a0aa67415ca3f17","0x388d7215b91bbb87f979cf76114fc208ff347b338560684432d7cdfae2e09ed0","0x5b13f1477c8c83b9eb6e5fca863688008c75355419925109a4849a24362b8651","0x5afae975204396c5e5319314fce5056c2d1640f8ebd196e12773c6ab30c3a40e","0x031fdcae1d54f0e883aaec0d25a220e4bfd692d6e2ccb975c96001d795e5dcca","0x369fd1c543604b9e7dae3774966e9cdb2baf1b4b834605d02ed07ca3b514eb62","0x2c0e8bc0d8307ec65292f3af2623bf62cd18fb9f046fdae54c6e06f7516a373f","0x5914fdb106390b8134ebd279d4205c8e08868a7a19ff1cf672587249eaea80c6","0xfbe06627531d8a31d0163d3c8bac149dad55c2e1da1f342116e4be71d67d4156","0x487f8979d2d8a8cf14036af3ef3924acd75a0386436393e0f5f71fee40654f90","0x63b0a2af4cb46d416330a9712f816eba4b480b0965b4cc515976ddfacf065af3","0x3d4ac834247cdfbe607893c34c098adef5238ae4634ae0186f3386f60b0a1395","0x65a82cbc554002f71c3830e8af743197b9d3d9412ee1902cbf08ca3fd7ab266f","0xc4306c37cf5b270b00dd9deaae838780cd6ccfc984f6b2bcc5740dbfb1cc5d44","0x3eee8423992c1c334c67e81b2850f3698a93d0538294470d7b67af8d53a761a7","0xb8f367bb3d2283aad86f2364565c14595a5d768b99c7fdd992859b0e85a67008","0x98ba5f1d192bc92520f0c6b218003bf4519820463ada6f20b38c61188145cbef","0x3dbac0f5bda32179d87a490a63ed7b7407656d8fd76d97db02a7b187c4e99448","0x5565531485dbeb1e02fa6199e127b3ea25deacb55e9ca3fdaaa3f5926d33a96c","0x2a655cee69fd20ec4b2238f78ef44b0e223fa42c312892f8f0b0a01b917a300b","0xb374500ea46262e780f82b9c2fdedc6058890a1ee07c1b53005ca67ce58857ed","0x4864b213d5ec68dbdd34df6e4f8342d773e2edc3f2db569fa49b21bf6a542019","0x349934858aeffdcf52d4b62641da96e4ab33faeb3012bc877b80ad98b3984c05","0xba30c29028a946f97d01f14216f0d61b6e103d0fb57daecdd353fc1724d4f4e4","0x6caae42b54779cec6142f8dcdbd99a76bcc373b9bebd1a80c121458fc152c6d0","0xbcd832da509ada11f251cc954691af4bbf8bdc3484d9af4a71b46989849c93d3","0x6685db5539fb45047061ffcdc98395a65418f4a04dd86dd4a3d3a195336ed116","0x8a032aa7a0214937ab90392578b82f5b1979cac064ea0c2b129cfa93e841299a","0x824d3563e197b827691282034ea30692c4ae68ed27b0af4e3ff0f81cc99f66c7","0xdeeb01313f472dc9430eb878a01c658ac17a7222978058ff5d2a8f1fa4c4e8c9","0xee5b331f34fbc42eafa6255e76650311a37786fa8eea7359b3141632de37da41","0x04a732c9ef1f19ba18a63cebb130c51132067a15c10c43531e32045584b08eac","0x2b40549f6b010dcc785297ec32354bfefc8843b802ee5e7f766c77055d78d301","0xbbd5198048a6d7dd2bb281524361c60ab5e91614c4b78ef803c8d01463827d1d","0x2b23015dff3d6164ca20307079e5afe8e8115d3744b9b9fd9d01cf47d49401e8","0x428bff92019d2090f6fd82fb5a3e26bc65dcd82e14fb823cf89fc217b1f0f9ff","0xec5d90f74e5a1c79cdf91de11a0ed1ebacfdb1bdc832f91bd9d57f2d5622bc83","0x32ab1acc631a488c8219cabb479e6898b74e942006d3099a78bcd34933923822","0xf8b978f013abe6fb8ab72f46206f085b97e1613a49cf36ac0ef8a256365578d3","0x5fb61bc623b4aa5761158a3d3194e6f1b7a7fe4fdb595c2235f44ebf7a7c691f","0x305cca1f22c1bbc6a81823174b82b97a44fd9a840e55b9ce1a870c917bf45bda","0x6bfda2b7051c92f0878a4e7ffe8ce19e5f81bbb1070b5c58fdd4cd6b206294a5","0xd6c82fba897300d87974014f9ad9b9daf01c1531f15888cdab955c8ec8c92440","0x425b9b77ef4d2a34ca3cdd1e061e5c3b7c5dc2a4bc2f8a44172760aa725b46fd","0xdd13d663c9fee2c7d42e495a2eb8bc295cc2fd1fe7aaf110a1a54c8c0e5b9165","0x7a5a256f0147e5a985eedab0eebd11523b97510e34c27c9064a57b75cae64c79","0x79a7ddc60ef73ca0dc49969393fca667d259c286f5a12aa229130f249c5fe27d","0xcebab0d740566931e78ce66f045191ce86c0aec4f75125fb934d50ea88c3dca4","0xd1f189d6e29f8c599a407524741cbbaa72c6bdd89d9c1c9c5c321d4a39ea624b","0x79c99d217344979ff2757834b3818131bf4d159876f3cf5ed6994bea2f3ca682","0x951ea4f2ded810f3b9d32d8b51cf0e72cd4fcfd007bd029031f0c47e33330b25","0xdf4f04409bb79c52452cb0b829e56cb91d7934340aa029cf25bcb76285a60cd5","0x2596613b981dccb0f4544838793f38b1bfb1adc4966e49fcc308a2d07175de9c","0xab2a9b0d3bdd9778a512f88acf2ca7f550a06f7010bd4584bf01f53415a8d9e9","0x6d65b196a9d028597d257067dc7073c5d2e66aa52f329575810d063e2701e64f","0x812ca21085b182163965ddb94687f9255d5cebadfe3009eea220e8ce02206ebc","0x9b4e59097f83642d8a0a483b25282fb3089b9e4fb378cdac2d145316dceb3769","0xa35d4c8b68f4afc0c68ffaecd45a27d5a04bd6db3e8c9903fac1286f9bbb24ac","0x4eaac2ab90144f0973ec5dbc69443e875e5de90b17425429f9cc691251f477c1","0x5d3bcf54be5de80cffa5ebb0bb319f4d42e9328f37d1f9a1ab1aebb388ee096d","0x5d35eecb0ed80abdb81c0c880b87c2edb4d3b5f00d4cb76dba233451fcbd8c85","0x64bf1730fa0ae37dd892e80d14f6376b5709fdcf35733c3d987beaad43a7190f","0x12b6cf8558b1847df7fd64b52c3943bb62c702b79d057dde34c95e0ceda70065","0x9170b26d855231713538f63e5a3c834773c8d4dbc3cc5c3885bc82919a95bca4","0x398a2b81c68c04707a558ef91245a83c3639fe578081af9ee207070d8366d0c0","0x4f90d8056cc11d5128600f6ffaa5a75973b7dbbfa4eeb69e3828631bd11af6be","0x1a2b330431aaefbe450778c1f3103db6f29cee79312e79493ab25ea836c9d356","0x3840bfd2481ba197177b71282d04f50cfc406835dcbc2accafceab28e9e42589","0xadcbd62c045edd69662c4b70f87c7b9a8f3b0eb982fd222851f3ea4bb9f10e07","0x72ebfb13fcc6314151942d6455a784f34ddaab13b81923885e2931c2e545c146","0xde324c0646e90a379f92ab723d1f04583be64ca0445d806329f4dd2f148fc1ac","0x83796345347b1bd1f9e46f5987ddaaa19ade23a1f0f7871d2ef0780dc7115962","0x3b2669869e0286be42a93e899308aefc855d122cf68741b4370fdfc7128078ec","0x1bab72a71911a86a746cdd053908a597b62e4292aa641876344699e3410752d1","0xf7b41b54da3c6dc76a0fbff19a6fde5fedc91f2bd33571a66899ddaa08f66bb6","0xe199992deffd70e1f906bb3deef6614ce3e073c4682b1bebe2ee67c9a57d4212","0xd8ebb990249e481cdf86fe9a0634f92c845959557a02734e6b6ef3bd8473bdc7","0x724e307f1aec4b9d72297f92321fc6828d884e2fbdab0220f6198822cffb7c0f","0x693329a6bd6400529a439aab86fc1a92f78e532d167796e8d12b39f24717f778","0x6e7405c6edb25cefed7f58998f29a2a3db6d9ff5acd5b26da7c2b54657cd2840","0x45917e2591474001460cce5b9a64b2fdfcaabf85563d6147e589fcc8a8182d71","0x03164c47f3691469d75d63a9c467b590b88d319c76f261f66eea076901eccba8","0x4bb98eaff8d338fe6cf84e08e03a769109a9e487d576890a2a90431529310aea","0x81c7b6de2aa44c5dffeb4d877cb335289e7ad8d90ef66d62987e8118df2641b8","0xd6090c9912181b1bed171730bba424404663b0f28e52502c7d07ecce920939dd","0x73afd4f8ad15f38ed9e7ebbf2628fd655c7f7115b5f54ba54ca1b7ad4092a393","0x65cbda1229cf69403eb62fd596ea814a8f908f55eebf269da63c67b6b06c95c1","0x64bcf0de8490c3124d032f7112504b58a412bca5bb264d97f81727a9be2e8821","0xc4fb5c12879893a76db17ae700e3ecf0ac261588702c6cbb3741e0c9b4e25814","0xecdba627f3bca182424f81a1c777a5af58d8353477d17bd5ba023df2f72b28fa","0xafc639dab8d41e74b0d9d5551ae5ff5197a1182a823b945a3494126d7ace7a9b","0x426e1d330c4791575f857b284e9e3a42b65660f0b69d3fd0c6355d09f4a622d5","0x87d28e6caae6b1ca02cbbf6bb3a1e57f554e3f6366185cc8fbb67bf5af61b399","0xeb9687a33ad8a0cced4bfdcaf962361a279fb77a764a2f95e2b640b52bb606fb","0x4c14806c0e25b282fcb9b228caafe4f69bc3125b5f5bb60d00cbe925e8cebd49","0x896136cf939c164c9f3112ceba37958dd32eff27c6dd1b2340f271c640cb2889","0xd3588fcbd30c3e1c428a31309aacaeb9ffae38ce2d3414fb41e50f33b00546ac","0xe04f1d4ffeadaa0c73b3e39e0a71ab7b85b2cb3e2596a525b13480333221e0ea","0x3144311751c9d4e995cb65a188354a200115f42fc86cc751de4a718cfd513562","0xc23fac7c5393376321b040b431ab6f67e560e8c2dc1115571848ca8a0772fd4b","0xf83f90dd30a333486eb30f0d0728ee4e1916e6a0413de0d2a3084391afd41ffe","0x5e78cccb340abdd2b0e5cf3841d20c58b8d60348d52b74a848fb88aa4e910da7","0x67bbb6151d2da8494cd93268a44772ac0a76172c94a21010796cab9a3f353352","0xefbb43cd011be9be1ee95c3a0eccee25fc3b758788b4730816d4ca5b6994e400","0xa36983fbffb6a6ba0e8f4f4650bfc0f4cda0569573fe7205e22c4a1419211b57","0xca28e768daf91e5db7ad0403c301212632af2ea40f4321a967ab9e7014f7ec8c","0xdc1911374f25381c83a037187fd1561240079bc1812694c7647865fab09edc3c","0x1c0cdceaa79e80728314bf631aaf2f9bce2ccd0e1e49af4fc94eb17828f3124e","0xfbaf2a771552199dc09b6e1cbb84c7d1833e07519f43a5b5af03636b38fd6daf","0x290c6589520dcecac8ba4a14dbc5db1fd417cac3bf40cca6afe77dd3a2dc1779","0x4ceb5c36f2614ca691dc9e68d9c62af410b842bfa80abc3caaa7ed088c895fc1","0x91d75195c299297794ec0e18417ce10b6c023a62ffb591655c739f5f349653b3","0x45ef88ccb488f23579a2b6b47a6428f4a393931670e80a55d9de6f34f0dd570c","0x3261e5f0b3d19edd8e9339312625b46bd2b21e767eeadacd971bd52678f1e6be","0x1e85bab561329ac239276537f9a2455936936ee1f2c7ddc843dcdc992dcceb9c","0x51d246c8139dfa442db2c4ccb12b7f4497c8ef8dcc2cc4e770e4ad70d5a4cd5f","0x6b1d33313a4136a89e7d9a48b886eb7b90f075dbfd68f0c93eccb951204fe7a9","0x9241997fac28a96ce8cdd5abef33c2fe8d6890b66529505f34fd2a6b2c763c3e","0x3a714fe5540716ba798468841e83be3080ec070b88031a4c717905a832f27c4e","0x4f3e27551f3507b1fa9db9ae4c5bb222149c226b5ff406c8eed3fa3f109cd555","0xc0fbac7afb11c099c42b40a53ec977c615af0426d0d454dc5c3e444f82bb6e0f","0x31fe3d608dccc0f005e575769f8050c4eaeae7477618053afbb78fc5630f4615","0xbfef673d6ac39978c5a3d9a7af4aa03ab1a7cc411314f77586845138f310bdce","0xd898a4b761480be69a89140605fdf73c5b91b3d4e61443ed46af3640182ac048","0xf0cd3224893b6856872334ba490ffcbd2b9796dcc214a568368c5800ce7cdad6","0xe253de057c0a8b9d2c753870676b33a4dff557b64d1ca581ef39f42b7221a8e5","0xb4830617cb5b2a846926017ac5a3444f75e69726d09f956f9c07c4d877461a98","0xe9bdce69f6a9fc0b19fee170831e5b36846a888495796b7b12c39666a80d080d","0x01b30d6ec5fa429a22e5d5f91727edbe51dd27d4846415e92ca0e29c6da9aaa6","0x2c0216c4bef33843190d82b8b82b43105e9bd1497c2c427179dc3886932cbf36","0xb837db84407cda7f4d6767461ea89ad4825d130cf592a54ed46b60e95c1e380b","0xee693532dd3f0a82d82f3cfd85acd74dba89a924d08c5a58639af0682a08921b","0xc6c5d717df097aea180ba824c46a8ea293bf7255f25d0ca663a35571dc67ec8a","0xc1b11360994bdea61c5c581a4dd3941a949cc58f661dad3d6e02b7a18a531f96","0x762b7f1724c5891c18a6853a27a3af9664e06885687c5b510c7562e5af41d4b0","0xf44da8eef7d30883d16c6aaf14e918cfbcd16ebc8fe0e47da7353887b5eb7e0f","0x93f95d594f97eb6a11f363ab5bd32bfe49a84a519e26fa8618659b0747da9b71","0x0aa409c8a70cd0bce3f37320a1b9983cf0af18e2c982996b0a66c35dfd2b6b08","0x1ed43bbaead24cd522bd4c0e05e1e14d04efe9ce4cdabefd8eba705638855f67","0x31f8aa44ad8b3b4e493709c0a85c3c85cca9a149a7a47762272be63e16ad7a61","0xdd9d0dae82f7e0871f23e27ea193c143c778fd0208266e10d04df23dff438df0","0x14b703cab02942512dcc376d907487fdccc667e661d14b5b2054998c9cc58e30","0x93601fea07bb6e98cc2aab5d47f34310dc8cfbbcccb61aaab8e6b29c5f774669","0x848ea26492df7e6284e2c588876cf424b93d9f5f566d0c55e399263d0dfc32e5","0x1af5beb9f8cc089107b767dced72667322fb603cb3d07d5558c1928a83733042","0x67b86b3a6d38b62b70fd0e1f6939fc13eae82f9d6cdf22272b5821d6983d9038","0x5c18d158000ba7ea8e48b5db5415437f14c4e9f1c48cf977e1592ed8742d3d63","0x3a67f3b64e16076c6d8e1177d24e4cec5ea90dd1478b5b0bebfa23a80f3caad6","0x7e350a333c954a3f793f78e3745a78b8d7a59f8ebddba769106dcf6654c9bb4b","0x1880211d1ea9ed32f557ad7906a2dad0be1842650a22ae8837b2ee0cd7f8bae9","0x913faf6cd341ef052e7a0a93058e0f0b572336226bcc266375ecce34182a7df4","0x9b20b9902904d2759210dcf5acbdf881bea9122066ffb0c0354e4c4d43d0061c","0x4de8380642a126a45e32ed06aef5f6cf29bc14922170ac5f03d0692f5bc8f631","0x5e0eddcbd95d939dbf5e49048481ce33ee93a2883778eba4cd00b6ab9b819d9e","0x0f28be79a4728ee05053d7de1144580eb772b012d7ab1821e6f3b570d4ec9535","0xe22352fb1b746132a5c39b6ecc01071eba287a5287e8ef2ce34591f99beabdef","0xe33dc9c58ed1431bebc658666463cea74365f3275f9fbe4ff51224901ae8a4d6","0x32588057ca0ba7100d56f3a08dfd0f3a9be78aed30c56e2c370575fe4aba46b0","0xd1b6160e4c7e1314dfa027121bd665710b6bc362d952779a4c2d77029da0985d","0x1dbd0d3a6f98e0425cb205b4aed2eec23b7ed3fa9fddd180adf0fd9d385a46b8","0x228c4995cf49701b9d4af4c18835d28f98aa3b8dac0bbea839d4965de972018f","0x0ab8d41a3e665e429624e963f4fa8ba0c03225f1bafd5a7a5a9b0fbcc179ea35","0xe1a34a0ee6970ed610d705b9fad300e9a73ac2017ba7d9412daff38bed590fb5","0x2b8285912a3dc4a8bdedec980a2a601c81eec4974e983f4e7512acc865cd8fe0","0x40ab4967736fe2f6f22c1a0f39cb7f413f83e9aa8080b3f5c6633310aeb3e8dc","0xe4038c568d80ba1cb9bb66dfffc05cac50b67149454e9ccf6d622bf3fb35cad1","0x534654910e663c9b010f768a5cea9c52f28c69be4b52597fc6188d9ee9ad5f44","0x012e32643f23c20c20f7356efb3856f6193e0f6e4fe8fec54df3f069649d2f3d","0x88277661a7195186b27494c9b7a0ce8de659fe5ca626c2486d30a5623e8cb2fa","0x1773e5239ab2bb02a8d80abd7250a82e7578ae0f183136159a84a774c7e5a397","0xb0f84c374ff513077f723e903a8c14ac0b2d101e10ac974e55e3dc444afb2e75","0x7265ae6b329e7ffffbb916954f624f7d3f3f22935bd08a4e818215da37bc4ef7","0xb7518a204a715520cb1b170d084e07906b58a9669bcdf8e52266b3952f788f06","0x7ccb01ff0749d990e12591a67d89395271e8c92464009b4bf66a2247f5945e83","0x92e42e3192f11a57643f56e2015651be05c7bed62fd02dd223a7a2f895d9325b","0xc18142d48b9370d0ee63d52f467acf167d14bde1a9a7edb706a9382c284f0c1c","0x9d00181ad7bd3d8b3d205e88e26a27802f6101cad456cdbaab6fd068d2590f40","0x391364b01aa87969f813c814503e355ee9010a4a7ad7e2deae7034a4f15028e1","0x945914a561b7dd53941099a96640f2e95127d29dd66a15190811a4ceba7803c2","0x3f8b20f86ec83c128cffa235bc35a0a4cd2aa8f3cfd3f486aa299da4ab756a8b","0x09c7e4266757fb0a82c22d63487ddcb936a63dbaafbe09824af9455e79ae373b","0x2ce86e7f13b59d572fa4d005138c34b0d9ab64ae731bd395b73193a74098566e","0x70546dcfd93172f621661f33607e230c7af4b1cafa306c640133f6b397e6ebfb","0x88d872b8a0039ef776a3ad839d4e36eef6f344394168c116916a31407a338b22","0x343f2b9e6eb1785910ef5d1991524c6e3f228eacb8a49960e13c406e78a61cca","0xcd6cf5da08b1b016dc14365ce59096afd8e49f0cc64478be7934f4a1dc7c0956","0xfbe05c2b05ee00ef7d11a74d7f153c24acf75faaa54ac64f93e432ace4d38c23","0x2a3e67901236fd57b990f2f876f6b33262dd4e77f83dcc05dbadc0ffa68ffd54","0xba31966f845491d51d3df4f685af22c7cfbf5725023b3870f3dcd9aaa3dd8707","0xe5099bd9f536f668756f770d20bd05f0182e4e19c1c9b561869754fca97cd277","0x1fa85cdcfbef02bb2457036d867419bd24299aaec719d022f65628acc0c7572e","0x6d286da0fb81627d8e5a34178a504497b3fc716a7599f9ecaf49cf921b3f1b92","0x64e77dec6a6ad44beebeed0fde054ce42566b562c137d615ebfdc24f38d5d27c","0xd0d62bb8dced36fa2fd85357e424da48d1b7b8c9ad8bb758f933218b1f7d2ba9","0xf01d46f6f9ef12587243aca92bc59ce04bd6532c318e83fcd32ac9a1da56f077","0xd004e6b412785450d3878b9fe17fdbf758192bebd45395a845397c0b3deb2763","0xaf04872a74f75eb28a42e6248eb1338e6ddb6aef8f550106c55a604fd29e7ed2","0xe5a2013b81ceccf2dac52d7f3a5d9b278609ee9852ca350f9866f580607bfe6e","0x7f08f54c36c3c8a73b8c0511b206c9cca5ebb99c2c27285e537fb22d53f9a0e6","0x04faadf65372f3cac9ae9fd8b4f25735a3028b272d51accd36b46db716124605","0x7155fded10d57c0d03be868ecd2a95135e613967c391a279bf2dfdf44ee83b2e","0xceac0864cb6199b451a7a81c17ee12348acbe19b92f80dd3161d6058eca890f2","0xfb65a17a2925cd88203b49e125d51f99d833a1aad0257de087be9dd84b0f8991","0x2b290eec7d5e81f09df32f3d834ae7fb0ce634c336c1fd82f2a50bd373d6f108","0x5cb5c8a1d132a180b8c7fd2c13f1ca20129b9eda7996bc6f83c14feb34ca82d7","0x36c50531109bea5ea5ff182850404f99a67554278da13e6dbc1067f559c71690","0xe4c3344a1aa39741418e22a4da0e972938fc20d83bec39068350adf3a512e93b","0xbbb33f926f23fcb6bf0f1f5d3b61ef38a245e25703e3fa6200a0f450598eaeda","0xf5a87fb645947dcc44a82437a54aa9653106b22a425c7ddb0742a86f3f2de344","0x64003a32f326ec25afaa947e9a07e71d456405ac1803a6f0ff624f7a055700d7","0x3ff2a2e3b6b4f76d12f1fef6f1d4f2fa0d66890e195112861e48a3547761177a","0x830caee0cb6fbe4492a5175caa95053b6e96c5ee2b79082df396d986736ad88c","0xf6d2599d2d7ab38885a4c34f51f0a85c5035844b562a6b72dc4b268946d0405f","0x732d01147dae3b590a5016d8345e70af8c8806f6a02cf0a5ffc4bfc9da2d3371","0xb02828a9bf8f535181439484e927ea28dd635ba6e14d6cbb11c2a578d4bc4860","0xbedf90ce1fca0952a35d13a029e9fc2ae41ac66556a9894ad4414ba64272a640","0x493c56bab9f7808f000ec0931b3e1331f095f8d0cde5ea5fdb9db4701d54a807","0xac23a8ede0acfb044a34bbd839315413145e5ecd3f3c21b68faa05a6bfafa2a9","0xca287c64eb9659aa21e760e659a60ff03406b28584fe843f097c991821ad67a3","0x8603bc20cbdc6fba4b8447949e66b8677ad51b1d6a3938b11a81fce212f5de2f","0x452b281aa082a786d75203a24b02cbc07a3d24c8f024ad699cf5d6462630fa57","0x4e250e3a78c4f73ed30e903a594aa042ef144b9a86dca256933b49328aec5d16","0x42a3006c19a60a6c7e19690a218dcf010d76a4bcede99f46b6a6d4d553cbd127","0xc720579d19c209db1b0d2e2ca2e7b3b7e29a66d33e18dc9dd0075eb2960529fe","0x3612371fc7110b7c2af3a32bcbb940544d5e4a64a964da74711d0335e946b5e2","0xd9abd66e121ca28c91d77ca55d2b3ac622540b7a21fc759dc143791a36978315","0x4259837a86d33c3142b644a6688dda4baf34d40d08efb543ebd53f00e55e6b88","0x934c1e1961010583cfdd39d836c37d0364196955c4a519ddd0f5c0c3208c831b","0x069b724d1ca254f45afd23934fdcd49d91be9c831bb1ee53268dc82f617f521f","0x6a35d944b0f6ba11c0cb03307c3f5b868a851996321de2d255a4ea54dda30a0a","0x22d5f8f0164aae4fffae159391fd5363942cefe40e3fbb7819ce22b13e3c4411","0x7033c02f270045dbb4344230a7acbce91a6277de314582e3bc3b1d43450a9b77","0x446a114212576cb151ac23a352fb647055a30c249a73f0e996340e109508d290","0xdc7fba6830f7398424f3ec0d069e6a68680e242bd9463e77e49c712f8f7effca","0xcbe0f272727a3beb466fd85606f4220c30a306fe0c658d53d67fa0b2481c8ecb","0x0a976c7e706f49be6ccc4ad1ea1c5263e3a3b3c4c52cd0140604915afc28d698","0x9ca899c143847c4919e22b3c3e5fcac46a96282404d2f9b53f2d50170d288877","0x66f1284fdd42de777c321eac9248564dda90b5a11c4fec608f7e028b89b70534","0xf79a37bc3605d7a38f46235e98007ade4c93c2d0ee4f9553b0e43e44f5c56473","0x20cb57f2c1cef9cd5be89a8c1d4ce613e898822aa0920bf5ca8288feaca84476","0x68b1d6c519011ffb40487455e7b417fdf075ce6443f3fb32b40487a025c32797","0xd4195d22ddb59554662cb43cbb85e522cefb039a0cfd5228019e42973c337a3a","0x4eb0e246b256572b5a4cee6134b97ef7cc268a278cb5f2641903f583df5f9837","0x68d7e23f1d8d167627862c361bc37e49f4990e936b6c4c1c884d69e511aecd81","0xbfbdd65025b500e8536b21c9d086d523084e6141011143ac79787022c74e6b25","0xaab9f4a485405a3ac4989687d92a0e07ea155b4b6e2a0f5783b0515a4ceceb89","0x9b935101f1bc9189bd0832d7d6d7bc8d220d13c891559264fa0300fbf4671540","0x0b4b1490017575c051356b1af9595bd55204fdd436467e995d490d1efa9af0de","0x3f96c24fb6d1752302cd812125fd73329874d18db15da837cda11e6944b325f3","0x7a03363cd86c306f6b650a00598a01bf350344305b81c17894f4c0388782200a","0xa2164a927c1b13d4c8036a82760d72751310af261875a8fff8e9476edec984d9","0x2c02e97b1cea0b910c07b4956243d5bcf54b52e0523313b5c7efbbc52fee26df","0xd1736801dc2c5dbd1200d8a68298bb53593f54f5299e45630dddf1c66e039104","0xb5badc31d9870393ffd4b97d748a0dbf78616e5dad55a188aafe04349964084a","0x7fa73be18dda5cb9f91db888d7753c0c9bc77f2cac2b8ce3fbf15bc2bfb76a61","0xbae30caad0bc3dfcac91d6ca9e3e7cee4790d9cf92d3cbe8d2cec4605caa2eb9","0xe03e901c32500fd4c829e890f60e82f2b6d40a44db7328f645eaedb1c3ea0ae7","0x8225ecd96fce1dd5accc0ede3b23d967926d33567d4c330db81e63295b439045","0x359bc008698521374345bbf51b9568ad1fd8cd50353409af51ba488b83292d20","0xd63626e5cb17fdca709133295fb92cfc30607431e8013f4b278fde959e293142","0x74c79bbbe1812fccfc0bd494ec65b19f777d2b2eb6f2c5c7f74cf90436be7d22","0x63e6cab6fcdbbdbcaef555b734da22e1e5e0d690a253bb9fd8723f12d84515fa","0xc025cc768c9a938ddd0f9abfca97e6bd046ae0648bdd97b52bb9471caafdfb8a","0xec84fc074f8df011ab566743d20358d033a579208acd63b9488b639eeb569d40","0x4bb6e1c090591979eec5ea2a1675171fc6b1ca31a27e36f55fd01ba93cae1641","0xbdcb929d8ece3c768b2ee506e733a25f23523f023d2bf753115d39e77688a5d5","0x00451214c93f11d0e6a0438fc9fdfacd56209ce7da19080aa9963b8a1cf8b081","0x2027c65c78b3aff09c35d7a118b07da8d6638d5a52498b40d37cb1bd994f46d2","0x233a78f482b1fc2954e06f37b045f073d4adf1ce6b81dc3e58bcd5fc5d9e7c71","0x162744e6ac92d36bac8ef4aab59cf96358cdf0f10d87478ec75e437e89c4f637","0x90c09ca9bc0db733dbd323d81636eeee506819f3d087a8ec7123f926d04ede87","0x4287addd1274f6be8e9d70ad3e57a23ae34e6f54f66571e0d39dcc1cc6db3336","0xa1e10359285ca8b468b9eaa40ed270b3437524e20bf21a145e68e7b2298017aa","0x13f7dc5b8ad7aea997ac0fcf542527f7949fb84c6630ccbfb4ad8a67202b1f3f","0x9e9597e2a51e18329b7850fd045fe1408b5346520ed77d8f6cf47b21fabe6d96","0x5d70da731375bdd1505f6cdac4df00368810d136117eb2570013e1cf2443d34a","0xe573f147f40f176a76cc922523c3f24662bf36f12767967426d435aebf043a39","0xb1149eda867aa293637fae3b0b8139e5092a7fbb1a6d24f0f44809c770fe72bf","0xe4097d7cf06deb6887e227e610afdfb016049a235593d7df6fb637b2eb3bcaf7","0x3c615cc9246be083c9228fae5063b728a215a9d85864fcc7f07385e7835a95e6","0xa278f9410e2b5fb9608f2359ed13053bfc7e2ced555cfe11776d1b6931dd1695","0x471fc146d2c670caaab91b7b1665731f45ec58bc9352bbba34e7a7983e34d459","0x4bf0e9d8bd15c48c6a542bc170ac28f28038afa57752b5cd012cd28de5f3334c","0x8cf8260af653efa2c98f5c0f935015e5a715fcb32143d306f6d2fbd2f507b46e","0x5884d65b0c43db9bcf3d530e987b03ba9c68d58317abae2b33ade04b2c2a6625","0x5beef99bb0924c4e892ab23bc8ef337415944b5b571439cd7bf1118721c42675","0xe2cc286c5b69b4b6497b4eb90e204ee921532ed82e1963d75a3a9756f2fd5c73","0x58cee24ea79de5f1bb917b3503660b0489357378e8584cd2a5e04bc0c29b7e8a","0x2c082892e308753588ceb4375fc12fb54b09e6e04e07f701c1fc91d336e5ae1c","0xcaaf04ca04eb06717898096c8baf1648aef7ba4d678ee6b32bad363a83fb19de","0x94aad413afbcdbbf57ff6f073e966c9e5b58b8b9ff247c20fc8216fa385b7b9a","0xf2d39daf851a1d0a79d2cbf227784211cce51f659f49e492e1697ef0d7074af4","0x4e282720c634ffcd7b56da0f8a54e4c33cffaeeb19baef787a006d71e369ea90","0x25bb92949de23132e854d298ed56033447ce3522bdc834a145361a1026007bfa","0x53648f4fb4fad6b048fd159d3f2643dae7d262b5224ce36b37086a88f2e7460a","0x2fd1ce784f112d45913205ba66510a2c39f7c8c11b48baa6efca7e2e54bf2ee4","0xbbd63dd567c0c89a43b49945fa6093ee7181b3c761b10aad6c3996d82ca6da5d","0xe116745f7c20ac1fed91b113e859fafb10ab9d4f02bd958dcd2543fec7a554f7","0x2947be7cf85b03517daa1ae20e8683b3c64c4a48bad8ca5b56c362a8a4a07b50","0x9ae7d491d62e835826a1b2f9cf938fbb70abf7e45dfecf0f849812b9347c92da","0x127863f69837a6ad0b542211f7ad938536a229232c176f0e49b7c2f01aba5fa5","0x69df2076170ab86228464fb719b464ace318fad5f68630e2e0d6cba3f733b3ca","0xf26aee559b7c2fc5027c4875e60eef91abbf80200fb18de4652701be31106211","0xf24a1e568f9b2077364ca88ac2788a844397b982b3c93cc2e1965caa95099a7b","0x2af363b3f4bea09119b42c7e0e93f4778da65a1a946e97ff7890019a0a8f80da","0x39d814da6f76aa7b44e2511357a0349c8dab3f4d5bb2b1c6db51ce4746958a43","0xb536e76078a9754a00737c46f388a0dc3459e34a928617832888b49e65dc7259","0xa72a685ba9a653431b6b2ee883a9d114f1107f000d01956d45cf81877592470b","0x6c959ebaf649c7e030fdc22717103fdba0cbdbfcc15af975de8a97615e7f2764","0x95c218be1bc88d314189d0f387498091e75cf67b351a9fab1173cd6d3c725dfd","0x6b1d6671e0be263a78e3f485d1dd17a30625623152371f322bf09aa6295ac21d","0xe13d7ca0047c806848e2153cc06466aae42b3bd94fba7fdf52dfb1571247a76a","0x63e724e121f35825a3532cf620e0aaa311e1d26bc8464f2e94438bf329b853fc","0x2d9436dd2d9b86613ae87abed29852f82f8e3f1261e6ad73e9f0c5eb8c04aed8","0xee48a90c694023dd758b37822c001cc6cee7712381f554f4e6d41ca03dc8ce73","0x0017401ba37434e4f6e39ddd2bc7fe8f664fc815514721e8e4665bce7bf24d19","0x88e7d1d3fba32691d12596cab3dea635371f7fcb7b7bd357c12a62c1c46dec12","0xe36d54aec1356300ca653f89457cdf79c08a9f8ca1cc58714f89a00b8131b7bd","0x2cd05e5f468e7b31fe8bdadb793fe3ff5c25c12227a43cff6e765af2c9b0e889","0xbd1f39ca368fa47c3b8fac65249e4cec2da5fdd391a6fb025d145c93fe7d9f59","0xbc113e0e1562e5add24d28ddefe1021c21f5f047221148849c89e8406ce7253d","0x2ed764fc49446b961d5f6d5da681ddc635c2ec0640353ed0bf88e1fbde8f7b8e","0xe51b91dc0d5ff17a36a14fb505c4ca7dd078ddfa616b124e4f5033c0902987db","0xd2021f3c67ee22ec148af728e62d12d8f3e833b480b38e2f731a7e7c08090f8a","0x46cafffa0c4fc127da1c6a132d010ccb36cc2586e755d2ecfac91e0688fea12b","0x2fa78aee361a93c223e12dbe3c57bdc24ab0969bcfdda654290ded3504118e2e","0x08ea6880d7e3b859a719d5c3966d8691189e257212ff17eaef624631a4b8e087","0x3c4752af1a5eaee495f830d7d40a57367b24988d61e920b76d64666280d9e7d2","0x75fd73684dd6f2afc49c2628d99a434a7ef8d982222799f764aa27680f94e7f4","0xb1fb8ce0895b3a9e46f49f8c6caf229625a430fd5ab7f1c48541688aea5e6efc","0xe56299e62ad7c6fb5e37284d2a29186f761ef64caf5a1b69093b52a3d2417ad0","0xefc63266b5a58192a90ab2b5c69baa99159ad5fee7033834cf90dac365b4a4fe","0x4b747b43399001781907b655c5800562591155a435857bbc4c2f6186f3f52002","0x58268028fadc53b60a10760dd847396ed9ad23aece53180e746df97477275b6a","0x0f3e2f46a163f00f169098d5b5b6b7e56374ee5df3088f4421fddc01cd528492","0x5dbd028788186ddc00d76fe68286b02418b2b791ee89b1fa32afe850766018a1","0x9f7c9c5f886612b9e0e2cfbd9f5003dbd6107876b65ead39a88a68a0e4e99eb1","0x6badac63c38be0da93e4d8040bf6ef83a406b7d8927526f4fa49a28dc6849556","0x079126a5fb75208fc264fe9823b009c784853b50270b4ab0b168d77e8c80554b","0x5a9ee8081c88cd75d662cb68bfe0cd5dcd50c7302ef6a9394700fee240510445","0x370e0976f862fd8a0fdb50aab4928dbca11782b29d55439580b5d5b92d608403","0xd49a5ed13b7d165c1cf4a3b3c59a90be7481045cb12760d4476156efdbb9329e","0xb018c416e095acf0c0a5b22f84003034402e2ff5c4198ef2cac638bd2fd975c9","0x49ef2bbe98f782d069438ae85f1a32da12c513ae3e24e2c0c117400ac1056438","0x6ef65ae36749a0c164b44bddc6a47fd7cb5041821b29a00b66acf8428da162fb","0x3eff008adf1013c391940c2cd42c606405c71c2bebacfc42ee7229da930f0082","0xeb9d0fea8720d6f8da2b7d84550441531e28d33195e106e4dfb6bf212def1e3d","0xd83c1c9aac6c81fb3b7a68e3aa89f537826f9daab828fb78646eec50d7c2e04b","0x049f0469d10b71b5990e1b8fc725acabd481c6c47b1a63c6b9849fcf6327a163","0x1d92741bf530cdc67d6daa9505cc9c6b618b7736cd7b8fa88aad6be05a5f3bf7","0x510332170b28137e7023fcb96c7d1592f73b6189858109764340f4ed3ea08a5d","0xf7092af93b4f0345d4b4e160ea8464a5241e99d1bb57be3195fb586d4fc7dbde","0x18e37b4595f6772e422d2c0658cdae5325a1d8221feb0ecb42ea9495131f3079","0xda85931c2337bc40b62b1964757b13abdbcad01765becaaee00ac180edd37222","0x7f517dc2e0cf520c3f08964436acedaa7976ea50733a352584b368a79d6914cd","0xe2b2df9db3c3379d145cf0cc8c589ea99d21909360dba161440440b9d83e8372","0x4f7557bc9765ca4d4192d240579f1f46a3a6e69a1f267fde041763c04354937c","0xd4b44ada44046b287b43db27c531dc5f62230889ce8c111c67ee27c98bb030ce","0x0bcda1f63542c486637ffdc45aa44ee248892621c155648fc84252b847fe7ef5","0xc6aa8cec743230fa452d86dc61829cb7999d1cbc6aff5019e9a764a80bd534af","0x70d648713237daf25c23781c9071f77b96e3a9d415cef0666d33f796ba75451e","0x0fce2ce2259b052b4974e84fc595e44e19fe0bcc586fc85e38d580fa39351219","0x1d0b8ebd01e95bd25f5fd09d6ada06dedc6b248f450991a613c536468860458a","0x1f201fb9b22d587e2b22f9778ed74c3b8fbd5d36382ca3cac8b39ff3ab9513f8","0x74249df47f1e30832c6038ae7b7be164c6910e04f5f15494fa50974d05bc51d3","0x4c7ede00793fee0b198f82914cc35941f1170e18144fed399dbce4226bb47f73","0x3a45ec5919b57a54ab513d429595d8c85550af16fc16aa11f4217ee5a51c0c26","0x63db625761e6a0b1da55322ffafc5adef071ec6bd6fbcde5479cf0d0acd5253a","0x3c3893d3dcbe99b984a36cbdb20ff2c2834643118e267738288396f7d8d90b28","0x5afc064cbadc8342a401c46b779e7bd3d5cfc6aea62b4ca9be4206f7fd9cd955","0x63b9ddaa34941ac2c692630b59191f8a1e2bd0924b5ebe9791c63dda5772a98a","0xe0f372363ad7fc8f596dda52357e20e5b3d98e02213dc977b7d3e88de1cc1577","0xeda8edc48edbf6f0ae5d3d21082772f21de7f36435a1b44541e4acca21960182","0xc138ebe55482de20cf836cc88e273f2bba3c2ad2fa005943aeb3861f2b8c99ad","0x6de15bc88473e3add803b80dee9f0844de247c0de7c1665104bf7dbcabf051c9","0x3fc61f0cfb106daa59de1c63fc1c64064a58e20394f3cf1c0431df79d21c0a8e","0xef9cc83fd22fb7837c563f4e46d9164314f35b0d31d9c520caa072f8d25bec9a","0x9fb86da96701ff837bc6fb3ca16e8301ddf81201794707b096ca69e97b8b6404","0xeef0078a7057cbfbb7a339f74a3749185eb6599d48a214f058eb9677f3a29c5f","0x2c4eb83f65f89f3364f160b1dc5115b5177850247ec7a6fd67a96f1203f189b0","0x93418d3ad89d7b333a9fb5640b270c7c414b84bdbb0347d99cf5c003306b12be","0xe332ca1c9a0e5b860b9832c223d470860dfb202a662b35f3ee394f8514c48652","0x79146f6e60379f3669a67147b217725f6cedbf80a94e3f511191ed35e8069969","0x2ee053465cde04dfb6d883ab0adaa0a1fbc0b02050cf0725b2101030f779ba39","0x69ff7667795e2b0c2ff04c0befe926a7bc02463f9e0122dd19b2160e6e40393f","0x63fee6bb55a91ed04b766bbf3331b6448d16e8ce073e6b4d2b18124397fdf22b","0x951aa88e9d5ef0fdf1682b7ddf9019904a5df91a24333f55ec606c329269e435","0x28a56a315231bb54de2c2da88c8ada6faa881b349a7915e81d199a7fe681c743","0x732da4de6ae0947701a9a74323a32992b02c0c398b38909acf56f59e3770a854","0xeb0d54299cb98bbf8723d2c143390bad6b83d1dd8b8d372fbb62879471d97882","0xbaced1c9304e21f5a9c779305b1ef3743ed98bee0149e0b041d13b91482885c9","0x7fa5d36ce1178086965d54305f5e6556fc119755455a4309c7fea47cb65a8d26","0xb5aae17f9eb36afd7317652ccecb6c2db22b42ea2edfc8b2f6dc3de0327c2a64","0x97c75da1e65178657bfd27d63ad90b37b98025ff171e95d0e01fefa8d9f48397","0xdef0556fabb32aa12cd2629a75baaf2495ade9fea19c8165e71cc71b8735b69d","0x250b4e6a7279d34b48955cb93cdcc0ae7c4a6a5fa52b8bc582df18975cb32585","0x51e850605157bb29eb01f2d7c4fdff450fac616e8a3f31127dcdd9eeff2c64a9","0xb1e50f7562fe87405a446873ea5e09daa2ec70551f7900daab75d7c6a40757ff","0x2c6cb1024dde17286a47f0c794aac199af6506fa46fa5306608672f4f19e2598","0x75052aa41fddef843104fc83cd91c48a406c93c1bbb4ab63ef127f508c25a25c","0xe20ac27d9a21c220e33413666cb9ff7aed2e877b008b19946af215f9d54cc6d2","0xf09a92548067c958b3e595e83ced61003de40ad02fa236087e9fc27687a68dac","0x0d2f15430e7c8abb445aab9e2e2aafd9df8b8e7e80920fde33f6670d4389ae8a","0x01d252ba724eb113906715cc4a3a1d55420a78778b88dcbc2af7a6957fa0d04b","0x0c1986f8e1cec8981a39a58154e523b035cb63d2da1ab4356d8162c9fca6537c","0xd37ad83fc49b0d95bd52143249996a170fa691c8f73c3338339ead0e1d763649","0xfdc3646a5cb5a6004dce783f0922d1e22c15f09602bc04be69eab5144372e9b6","0x956e79177cfed7d1b337029fb37a9eddddd2baa7cd1f1f9d0b89ea9b98130868","0x9b980005e8b5f02b54e65b8b9687118b10a8f74ca60d4f566a06d3f3b8878545","0x10778cd7b9fa15de79f083d05274cf1a7e15a899da0a5f8ba0b42cb0666e2c36","0x4c2bdbd066a7988d686ad6f1f8b94496c62b31f191f6faf5287104f602bdb9cf","0xd97b3071a0b29280cd443bba2b45a1763309d6f17a7981a5bc21d4a499f62818","0xede14672ab6f18ee04bfb639efa8327b6cd9e85edc96df6734b2a40b31054fd2","0xb120e2026dae0e5834ed0e63b4ce12ace5604bdc83c0dfa76f64ebe12744a052","0x6dc919108eb3eb9d3d2abdb8353cdfa3a34700dccddba3a6f4858a5b0d9fdc58","0xd759e9471b4ae35e361587aaab8b0aa00570d31575320b45be0df432f43e7133","0xe8fd51629d754b55925a753442fde46b3f24796764c206ac40ca9a97fa02d628","0xa4a9d70f6b702f96e7f50c99e34088782411543dd768a328cb42da7d39d22370","0xc97a4168cb621d4717a90d5d5e03dff4787519bb8ced2d5591d010a53c860e95","0x1c9ea1407efb9bf1c493973d3833509d654ceacafda16d5c072f234730432cc0","0x77c5f2ea47f5bc5705220dfde6279089a787d48ff1ae166b5a9752f51bf6cf8c","0xcf1b525521f3729ccbe2afd9fbda06b236c79369ab86808c12be1fbfe83f4883","0xa584f0acf0d863be9378b098ace6d4e3e78570ada56b4c5b3afa5289f88f762a","0x02b0f472d93aad23b3ed9d2a9af1fea23f976aa1502ca63c9f309d4ac0aeed8d","0xe96122dad349bfd1b3cdcb4860b29df519380cf4bf7f32fbd3eed7e9b609f8e3","0x90f8a0a6508e135767b12a938f0adfaf4be1f4014c2e42b9e5898379248ce8eb","0x1139ea7cc8f7bfcafff98e414ca7e536bb16ac6a2f8554a547b71e8f2b3cf8ef","0xbac1fcc889741610b9a719afb3cf3c65796df484c3875b389e7428dcb17b1fad","0x79798e7bc658f6cd5c8a32ca5fae33e002731eaa3dcf51ec15b88c0d66707ead","0xa22e820ecdecc0ce8f6cc2a0b888931e8d96b6ab0b6b8b4620804a89713ee255","0xdbb214c9af845a2c4b8aa04b00700c082da32c8e210391be4051331151c6dca6","0x6ca73b16528a8057967576c86c3d0c802d12b6af4b178893a6e2a237601ac49a","0x52cfeaaf8fdd717ca56f0d2475e1fca772be9b1031c8b8e43441b870ee0ed40f","0xcb8011eaa3c2c7d2283393196fa4e5d2d58682f0d89d969809194533c08252e7","0xdfffaf60b30860ca74bd3e1c409b25bb0928d0416766b2523af4516d276f0813","0x2af0d3f564a1bab1f39854dd1eff38ea5616b54bb1dc8385e731f244690b7340","0xdd4b5126aa424925564b95c63db17c2d02063b1c275ce93da96c9cd0322bb3a3","0x35233e7352c7fc6c91a4f36f82c11580296d5a918b214f20e89cc5aac7496882","0x3b7c359969b7f5f63c7116856d0873360f3f61e1dc0e04c5727d404112e03cb4","0xb0aaa0347644a4d483cef0c4fa5c0ab423092e3377b24514139cbaa5334c1413","0x82a483e38611213f0ec33fe9def471e54774ff630bdee102d98b3ad57cc13184","0x063dc6203307941a68dffec4dc5eeeb0f7a585158d8cee679829dca904d00651","0x7239a164757f898e863e7dce99cb01104b9a0bc4d825cefc693163ae6d00d1c6","0x2d734be2c4f66ffce196117b5114a7f9ba62f09511960654b665e8a3f1a2a5b2","0xd8f113964f1d70cd9e5b6e22163e14077c14421f14147ecb27038130ae4e2b7b","0xaa003af34982c0ce45bec3d0a4442ffc36bd483a2aec14dc14e51ad96167e883","0x6a38de8d7c5fce92e855dab3fbedad094b7f12be289696f4eec53aabfda15611","0x26f6922dbfdb2f426a0d1db0d9f4eaaaf1ff6e33dfd6bdb8c050262692c6b543","0x7995f55d174931e6e28df828ebb3c66987501e6eb5a707dd45ebe51da00718fb","0x8ad86e3c6c475f8aa50412bbd3d8a0f7fd09b7e741eaf9a262d6819b3d233e3f","0xb105d0e9b82a4cacd7b8b2400a675264b37940b7285e12aa4e6e9f0e57b76f0c","0x18015b9b8d6d877b1a7745e0e438faab97a1dade908a46367e9fb5e9d08404d5","0x29a3f3cecfbda4af6fd373c755f1622d10c8cf7516a56a6736d716084874c7df","0x084fdb18c58c3102ea0a964fa68c81164de04e350bec7e35ef204f78378655e3","0x22281ebc6f119413ab70556c037d7c546db6499894661d40d1ebe1ab59212cd6","0x656e2c54858ae1115a8944a732ed3ab0fe3ead2371c4a738a4e034e1208c7b4b","0xb0b04f854e42cf8e2a87f85fda3a25c00981b6f132ec49b74620c3deefbb87df","0xada021d761235a86b7dccef58110759cecf3d2fd553e542dc89005ed4bcf73fe","0xfdc9ec3c6b436a99c37f42533603576476f4cef8e6a2811e6d1d4df098f590ac","0x76737a0da4f50f65f5aaad9c94bbb2b623c1f935a45403f5f920fe5afb51d4d8","0x0ef7c2f14128e9f986ad9a6af3ea7bf1921798ed61af880458a1fe2b928fd83f","0x1903b1c1a6681d115a0a1c19558eb8a24f26697ad65970c2deff7964402af266","0x2a35c1b915928d548599d0f870db575ac110c9886a0aa763e04e740fae21594f","0x19838757330dcc6f31f8484ab196fc8ddbaa2068898b5951e7224e1b33dbdcec","0x78cc57c88b8f09c226e9ab4da76f2559b0a439d905f14f87401b2021aa0b24b2","0xc21d3e15e4a6ea79892ab7013d1d3b3fabc999a78e209ee03bb214b9706cf333","0x1f83b23d0898345fa8e48e371eb80b4dce3a50aed5cce7726fbd91b6ddc4d45e","0x61b8a6ba7f64d45a6ef2aa7a492b87a1e048cdc20817fb80652eed289a016480","0x4c0035da2e48306e5303fed26167a45279055c32efdb087460682f93dc9eb106","0xfcb3b0dffc60c082e09e22e67b80172292e5f47825d918c926904afd7e36d278","0xa7891aa7a73ff77135c0c2e6f0afae11d4c14897ae44c5235ff7730b42427512","0x159eaa1676c3c5f1a490d1e5792ab56790bd6c9cd4e05b223a10532712e5d602","0xdd6e689db4d4d8f4b125e50470ae37d60a3fa15a05111dba7445e7b93c413ea5","0xa165b30f550ffa41c62f05005bf70f6bdfdeb2f38fd43d1284d50a9cb42c82af","0x6c34b2b6b4d4f623508d163ad59d3e136bf57104e61a99708036c321b10d53d6","0x0a762f30b618431b994fdd9d163cf51fde570fdab6db6bc09014a345b225f90c","0x75c60abb18aa55e576f04e05e55875d5b147548a89652895c81426b4b7805826","0x190f7c7ec4f1acd8379213fe35208b88eccb168b34f4fb772bd6afe5a9b2ccba","0xa63738066ea51b0ff7d1eaa477828460b34746aaea22ff0f4d8726dc92fa777d","0xf0fdbe91b3f18c3dd8f3f1e2739589dfb6b637232e3b8f54467c9e54c5ff942b","0x08504d975844e943cb45900d468c9f20759030c787a01175185961936970aee2","0x1cc8e2621bba6e794110e9223d0a7cbb6b4c2211a0d7cb3a2df2d6058bcd2580","0x2168dcdcc7532714efb197a6c5686eaa017164d2833d8b334c8ec102590f660a","0x72318a967fcdc58cbcc5ad39a150c5999b0faa10e29461de9f0f49991cc6c373","0x2b8e8bd1cf3bf9f6e5a4cea607b0863c1f788a4ebfcb036c60b822fd3d3df0fd","0x4c6cc8f0c75a85f128382394494dec4bc252f8a5f5057f26a82f7302af7233f3","0x3f43ddb7398a7513aa05fa4a7178c1b6135daa2e05f49e025b2ca046724c4885","0x00bd68df6d4efa0cefcbeb6e8bc6ff973cd4b3030a16adc2667429d9ddfcde2f","0x6bbe524f29734dcd09e707338bc3c619c2644bb8b7119f967eca9107493d3839","0xff7660a27c80e7f53a6032ef5def475226a22197f20fa5572ebf548334385226","0x3153ab6ab05c8fea69a9a4d0f39badbbcf21108401840f28499ae4552b5c94e3","0xb8d270316c9f2ebfb1a2cd82b757f36abc6a3aebd55e4f0f43a7dba0ba5c3275","0xa0a2b57ae58c06ffb890fa851eb86579c50913473ad1f7085eb70d70aa94ca16","0x734d91ac86c52b1acced3c7101e67fa9c993c73752001d7270350a904e1564dc","0xbabf882c1bae98571b4a59df4daab29e9684003883afefbb89916a142056a24b","0x53bdf51765a7ee0d4e9f6dd2f154f8ff7b277495a002c9326779261c229c51a4","0xb30485ed9876102daf14e8aeaa48be0800adff7529a4c831f637f82ff99bde78","0x7e3bb45575fb0cf551fb47b26b130caa306cea0759678589f9482baca1dfcd50","0x9c6a2cf16fc8aae8b2d1b1e26bc6df2ad0377637cc3a6fece722a0631608cda0","0x5c16347e026125c78da3352074c9ba716c99f0960b1e6bf1ef3336e3e1eab089","0x01fc4e846a2ea3dbcadc98cbee4a65cb657a1d5b42aaff2b008b6095554ebecf","0xf549ed084b74512ea33a2ee9bb40bd1be5f4fc7211a9e0b92dde908e2a10f861","0xca7dc7f7b7944acc92db9ed8c1aa8587967f4e68ab7902035d97adca08c04e25","0x0d5bd7f65bcd950d124f3a6419cea3eb1180649df99a27936302c6ed5a8dbb3e","0x4375b27d0bb2a42ca8bf80e790db6803d327e911713072ded6395d680d528c00","0x4c4e951036358b27d06bcf1634a14be7f2b1ddfee3175c4034d22b4ed46d1050","0x4b3c449b89d084ecbed968c713711167af88f0395525ed3274d91951ce640fab","0x83c0fd8e1cf6477002fd8761ef17bc16f2490fe9aacac6428a81870ace9cd814","0x0398257c3dcb3f33c9dfa71fd94ff654737c993473ad8bc63e7de1eb43759c94","0x2c1c57ceadabb4fb79ab7909d71fb9919b1c6d34828b573bb207a19630248855","0xa8697e690112d8e147b6aa6f109024af1e348ff892c53cfbe76c5973f20a1f29","0x1e14b2f96e4e163284f773d7c74efde4c976552b77a0cc34ac4ce6ed0da7292b","0x084e403f6fdf4af24b7f541fec7dd6ee81be42c1c6ec3eb48ad9a4b048d4b54d","0x406b0ab09bb5dde5efa47aaedce4cbe2799432910da560827f3b53b5a5c819a6","0xd64cba5b9df3a13eddfb3b7b331dc4fc6738337e738466a6d0183accbc29ba9e","0x1fdb1a983800cc3bd5000e55436c430f4e53c3c6df9493226093159b87465074","0x934be4035c4cd2dd1ec160ee1bd46f23f84ba83bd0225d196afe79972ed76a43","0x64851734fd4c83256b057620936a34a5692cddab5c1f4bffafab7db070980f7a","0xf9fb986faed59f99ec09e792e413f179a6226872a2c3f3515542858b6d92c2d8","0x91252e0652484a4ec7f24db110ff0d7b7d3f501ef260a2751e386825d8de081a","0x0eeb79e146cac12218851d0f430fc840ee7e621d3eaddb21816e5b1290d552d1","0x2181ad1630e24d6e112ca1f551d0b8466985787590e9b814bc644a17e8a4f513","0xe0edfb61fc69e12f6561502ebeb3dc9b123f3f0a96cf129d4f0acb87a681381f","0x8ccd0bf0fac9088940b3210832eddd4e8b9dbc004ed15a0b42a546d1812f732a","0x2c0ba4d88bc073a656ba41142b51d69d691f975502a09f77d899928fb6880eec","0x68020ab38f07fc82e721f24a1623cfeffeb28bf7a629080d7de5b335720706fa","0xdb3134fbb98ff8e3e2a8401a241921ef6cbd4451184a4d94219e95d7e14ff96f","0x416e9a7c4366deca19cc0c928055c77d69c3205ccc1b406d86906b840dfd7457","0xf718181adfc39e06aa12c2c31804ab209840903a66afb0312add16390ad6e8f0","0x1defa2a94b40a1ad3ba60732b5ea76eac225e2101126f22eb23b30b8ae0352cd","0x2e4997febcb8388022fef93fbb481dfd2202242db741e4a1a47677b25bcdff39","0xd45b5aa687677f1d7a05986e9b706623c254bc1a1b7f1fa29bc877a300f6009d","0xff7d1f6cbc751fbc7af9aa8673b434b8401ffbdc6618ec95a0e0f5529ccbbe2c","0x3aff858cdb1057a91456d96b5d49125f9adba97d369dd5046a3489246bf68e42","0x74b95372ab8fb4a6e04e5d0f1186ebacbd528b791891b52fba5f6c75875977ef","0xb4ebb4ddb73064c59a9036c78df4c45e8ad7ed9458a119c0c10b6c700fc1329e","0x9ed700bf4aa36102b3e27066c5884cf96a6e29396008e2be028b7dd2486461cb","0x89d937bd80ca6ed953a875a7a01c4705c009e0bc8484cf999262f796e3d6d4f1","0x4e1c5011895ee668b9d13fd5682e75a7f147f983dd4323ae6e189f45f89ee839","0xc5dc1c71ce2cb79b37fdc36d2f46f2847a91242c6f130ae5e2d00d77acdef222","0xc261aa7f75f907add3b911780ff525d7cb65ca134271e2f2f3d8b48873d71dc1","0xb2825bf17d175fe89fa6611a49f3efb15f1cd8b8ef6573038bc8fe81728d1b09","0xbe5321a6b8f7ae05687bf2a6514a348fe797b2ac338eb88bb614f70b2ff26f9e","0x788ed7357b787f5796cc9910b8815611de22d1e95672f85cc69ba274ac39d451","0xf68f747835c6822909c3ae382b4129d97c921c2109a5b7330039ca0be3933ed3","0x9124afbbb2c908153dd709dd1e1c5b714e8c04b3bbf56d6bbc956dcf65a55cd5","0xf448e23cf7c6b1998329e09951cfc39fc77bc100ca268a7499427e4478ae6fab","0x9fa1e13cd4417ebafbec36538be79982b68b56eaa7e01c61e672083a749f0bbf","0x0b6a6d132e366eb64bfd4cd37ad52f729ced3de8680915a7dbc745aa4d266e56","0x294de5eb3ccb1b67c97f6cf7f6cf5d919ac4085c82d1e80b51c3a9fa2104af91","0x6b52a6ba051ef4ff9d614a4de8ebdb2cfe0d7a0163788de362bda8cc4dad4c18","0x8ce4d047160ff6cb9ec56e2ef3b0180e586dba3f5dcfec8001b4553ba76a8267","0x9ebb4b60b800d0b8416e4f46cc3300f9dd20fa74087183c1b7bb32f90783cb25","0x31de6e043e548d6a16dfbb3f7a7fe733268ffb9182991bf5dc37cf2223039ccd","0xb50b804bcb5d89148f08b17bb285b23c8e536b07b47f83a850f5a4bf26054113","0x10d75072f90bebcb84d5f4916730a5dba7ad80755e60a14b10ec1335f4ba60a9","0x340383ad4b746a6eb49ee7d643af6338f2711b43e1e74da18005e40b094a4a52","0x73505eb064140b1f12f59cd7af9a7badea65c2f799fe6854f1421317f4aa7e32","0x608bfec246043d0495da3d93be56566d00943c15669c8b6c0dfb269b143ef4bd","0x7922684b3a9037f486ef1856e794e220bd033efc15714005034792bad16b7843","0x2a55bdd87fdf42b27077efc1292405fcfa4337a9a0bab568a64094bc7d53bf14","0x594d4be60a490b283b823eb0fceded5696998a497b660dd03d692b375e96a7fc","0xd0e6acf76d158bfc4538889c2d89c6e52370c02dc1586dfe90df4233a2d7c592","0xf3f01227cf57cf2cc3c351f5dafa896b2ede4242f7563c6d8a4b9325c8e5fc5e","0x74d7e72074b3cc0a84d7d37b914ec20038255cd534ff636438c3e3f7a1740f04","0x479f3b24b1095a3e404e2a23af86eae7b7d8457b3a74b1f3a20f72b897b2940b","0x55852c63cf878869a8216d4f6a10bf71196e73e9a1e8ce8d6d191f0713b8f9d8","0x4cd7ce3379db00e614cda226dc7c07d819682fbd850f208f4e54960a6ac6df7a","0x3ac937f6cdfb6a002d0db49f8c9bca3b61fc343e9486744ddde534db678cd7d3","0x0be195af00182a7165eb802d54e137fde8aa58cb692271893f2d213b24e9aaa5","0x0831c732b97cfc5436d5d7e3a4c7e329d559c8af513517821f328fe08e85e522","0xc95ae109f5c0a9803f7b593fbea2ce580866b66a5ea91687e6b286599e2433bc","0xee2edbca136ae20a311688bbaa6a292affe7f027d37950d3628d75721aec889c","0x1f004b1486e72f55befa8ad6132de7930162a40d7239f1c644c8d22c1a9522d2","0x312c3797955310514b42419d02e464826a9bff899e2b2c7e42ef516409a7faba","0x6ca294b1b0b6e69f513bc5d5ee206cb72b87678141a70e3054b4dd96d97726c2","0x6b6cb6658c5f63edc9ee2a65b5a3cdd7d6d8a4d6aa00818bcf0e69479cb9a3d1","0xa3b4f3c9cbba969b13019559eb8d2d72f1ec73c08c721c4b569909c4eea3dba8","0xfa2cfcb95149c775afb4385a97d91a46276c622c3dc011cbfd9f01b449a9390d","0xa659360dc8407505d6e1b1a85407637512ba8230f1ae78072c0e53978430723e","0x8d544aa9dc77536424000ffed24ef68c8ffdb53c6b9e140c68e5270a92317b2c","0xb2e72cf2302b8c1530d3395cfb605e38a3f0a73bb45d5657e6df59685895b4e4","0x8e8032465d06c2d000185b7823de114af2cbede01910d19d86a41eacf2186a66","0xc1ab2bfb57611e9faf5bc0725c47f1d940538789753ab3cd390979295889009a","0xc6ebf673a8fc9bfd910f5c9b60c305a733f3f998793c4cd20bcd274136c5ea4a","0x8dceda30bc65a31cc1e44ec24b49fcffe08c488f7aba0c4eb768d1ee8d18ff6b","0x486715b6c4abc6991beb479e5fecd6d98618393c156ff1c4494d85af59923404","0x79e73d6a708ab95178e3b02ebc7e36a2b6a337c6ac2eea6d6c2b221e5dc7eb0c","0x360f363d8aa383c55190d7a73060256f8b1d17f722e3d9416000dc9010ae4eb5","0x8d9e7d4f0c67dfde3eff2fa01fa58d353567c623d1d6701ed252d63102f4adcb","0x8a46f55524090e9de8ce3abb1b27215dcd99466e8077ac1a9f74fa8dde832f8a","0xa4842af16b6d7fab5e61602dc708031b2eda15f31864501ce002c049b0b0fc5c","0xe218fbbe46f1cf15df111a3aecac40e5d3a84514fe111e3438d5526616490049","0x1889f4b312550d80c156d692cae704896b2738aaf16784e292ebcbe7c188aabd","0x8bbb3807a6f171e4847ea231e8f272eea7b6a566e148aaf5ce63e80dc167bacb","0x721487762665c5fbd35a13ff50b8f5139ee17d5002660fe1e075534183b13605","0x7b40c4e415815fb767eabf94b5a4b99cbff1965b9bcc5a8914de167c030aaa19","0x767230f3711fe414e639f52fafc73dea7f2694f676e72079cdc06ef470408061","0xeccc70cd752e84e04e7e5896b14b5af0875d7cb4d8492201d6d04c97a1070ec6","0xad6dbe9eab296f75442bb6a08ad7cb7a5481eea7902133ddabbf1edc488601df","0xe9c4f9569e6326fdeaaf40b179ba04e0b803b0698ef5ef0b9047c3f10d38a554","0x19b619ffedb098a00497940db49135ffe40be9eff1f347f391e583f930604711","0xf73da4bb5c5b5891d976e0b735ceb99b6298f2120fb68bbd5aafbdff74e0f906","0xd5acf175723aacbeae4cfb2be68f52fa1e35ce4470ac2ff027db1b6109800b16","0x18fcc42740d98328d5b511eead04038c4f423adf5cb052c95cf568f67b44cbef","0xc7bd4014074caabea47abee676d53cdf8d4b8cc72aa7cf2e24c3d6750e0dae15","0x0226f52030950d925e14c5a78d038e1a43117f5569cf6e681073fa150e42119e","0xf2800a7d5a39dc3570161e6efe6118a850461b46a771e222560506814fea2374","0x577e74825f71489e183c233545c6ee66c8f92eda00f1d0133165832fe63778f6","0x4fef97a8ab9a54f062478884c185599e0c764915c7133ba2f7aa9cf274b79fbd","0x51d867fcd378e23cdd4f693de4ab5c4c9db6ae5a72755e0a1e4713426ce41cde","0x2a131d181c2d6ef75e7033e68ed6f55b632543e3c6de88eb7f11bd25e46c168e","0x38fb045e50f89895db282a06126a31c8149369977adbd11f702d7d763f69ae78","0xf063ef21eec5e18cbe157e18939e981abf6dcf174b3e6d05bb1a526cc83d3379","0x108be562aaa97f0af74357aa1e72441322f997bf712fee4076edb0155bf8450a","0xee1126aad91d1cde28e943ae94cc963836d8c6c24395cfea30aaeb1550b7a03a","0xeff0e0ffee66315070bb22735e436a71c18f33fb320255a6eade58e28209e315","0x0fedf52565e3d2fd705858bfd45c2054d8fa5dc053151368b4f3908dfc27a8f0","0x6f1c64515b9a9aedfb525413c27edba4ea72f0a6893fbfb864d23bbf3d0ad949","0x653c34afc1d2e33b84e95f111a9909edf3087a9c56337c81c03162809383409c","0xfc86e77e7305e2fcecc5b36a0ba48b228fc7d240c78abdcf762147517e1475c6","0x24d8b9f552971a30cfd9590f84aba4dc59bee52fa3c9117ef492dee084ec6553","0x3f1272a78b62b5d9b4088fc59ba75ccce1aecb4bb03048fa266d645026165eb2","0x98a06fe45073aca1d458d142c5c795dc4f8d267fdc05e5a5109685b08102bd5c","0xfd292fafe278d626f632c20bff12981e391acc395efa1ba9a6782f90d1c274d0","0xa067d93613300762b2ff3d8c05f74475c74af4fce4de4ae37c6ccad10f12b5be","0x7cb6bae786eb3bfa1f7b6707e490332a989d859354932c4bf47506158e7901cd","0xd79864bb276712a8004300952fcbc037bfbbd707319966ad6ee1bda9e41aa8f7","0x3431c186d4c2cbf159bbb76fe9d2c0be95e13e3b318edef2d6456d9e54df01c8","0x097519a1e2559076578706d53d383f145198569135563d48c1b9b2d453a6dc0a","0xd1315f563d420377b84aa1b63c1fffc2c80e10621f075b9fba5d43de142a2d57","0x663dd76aa3a221a1aa22f757b5a48ef8b1fa79d951da8df930b8f1616b345084","0x0fbf279635dd7fdd3b7afd7063782efeafdc924ddf5af6c02873bab44c342396","0xa9401349d9a8e647b0dc4efc98486cc7629cefa85657f3c1e8d7162b1275a76a","0x1da5bc9ba6fbdd1dee87e8cbafd1767eef2595ab574bca4bbda8875420621658","0x1a1bd0e5a0066e07ac215df9718684ccb042f6faa84a592d09f043e42074fc17","0x22bdf0e03a6be9117a6a5c128f044a0439826da7dfad0bd2fa30579f20b84436","0x6d946f1298d2380da305bdf82e2e0c8bcc2f7ee053ee31b0c75484281992a21c","0xb030845e621ab70cbcffea849de336c34e11f7d3cf91131e53b9c88acd0f72e6","0x15273d47d274313b29b1cd2a05c77ba3a353e716a70766b584a323ea0f05bb82","0xd076da1d3762456c294d8a1682dd8f548e20b3760a8d4a0a0079fbfefe1d2d78","0x4250dd4c6e54e7434661b7e3557149644dfd6c16e802435a72cb24b20db04c5b","0x25a35332e51b2721054372ac15bc2d06f51092e82ae507d29d05bdc2c86c72d1","0xfb47d88ebbb8a621b4f1c99fb86b0b7d7af021ce4df29bdbda943935ef9a7571","0xf756af738b81b3eaae179136f63a0e1ec092b034c7b13005fb9ed1cc3eb0ef33","0xf6cf24af0e5cb6ff10e7f8d124b614f8cd4c232b54d3cc5765ab161376f50838","0x10d898a3be0b808a16052e26f9d3119a62f61020916890064db0e9a7551b3c16","0x23097524f9cd53b15cc6f331282f1c644cd107f06ee1c4841b3cc6856802773a","0xe632d0c6b699258d2cb84daac87486b6fe39cecb8fc26be47541d51bf09ef8b0","0xd8bf24215757e21808428b2c42ab94c9622194713e63025ceba7d003590d43bf","0x3ed20fba40550f5979ba353216539b7066166e0ce1bed7b23bfe568bb6322434","0xd5c16fba2f79be17339eb1d948c914e384e646b72b990628470155ed6d77ec98","0x6fc8aeada55b4b0f703f4df7a7c7e32199bbd34cba341d1a605cefce3166fab6","0xa1fd8e0353bbd3891f68180702429c571ce22281457bdaf2ec29a8af3bd70a0c","0x5d2e473898c98937f3e96956dc725befa99216ea15a78db32b0d9de21c934114","0x58f4ebbe13a1b147ddd751dd1a113dd6e746a9623e3ff635d4fd5a2af07e5143","0x63e623df1a273530e99210b29d50b52880de77e2db1d58893dd645cd64812b44","0x03a74871989d4e32f73eb109b6488067d9cc66f163738494f0ad78927d9f24d9","0xd27f8dc4ea624ede3668a7f68c04bab496733b3eacbfa792d245ae48334a25f9","0xda6115e2e3bc89c804458a90bee0b25917760aa57b46320343e2f69935ec53c6","0x445e015f04e38227da6d2a11382fc6b6ad50f35ce60cb5eaa85164aec3086986","0x35436f42c257950d3eb16aaeaa85ff97db1efb2878de9d2752a8729d6995ee33","0x5c9b213ed635ac84a15394c5ae8845b21f219e1f2822cf1d0c38c14875aa56b5","0x13a838c712f29c0e4e64b815b0357dac1c454469cf2aef060a63b3ca3c57d296","0xd212a6f65abc21e2827d727a5746d99cde017ff8f617f2583bbaae0894ebc6ca","0x80724b0ad8fd86d331d9a459275baf9fc92da49782aa6121b0065b2f654b9d76","0x4f03f998e9d35263bba40061da9c9f7443b48acbcc66e51e8bddac8539e1d741","0x62aeca33a3ab303d7666b5ab871ddb08c4f391eb2e694e15b011d1581f3c8b99","0xbbf0280eb7e05b9e22651a222d56bf40751a98ba961403491ceae084e1363fe3","0x58e36619b39a91077dd21b44e1f465cbc584fbc9ce1fcbd53cb07b25e8992f84","0xb48bc1130f931d526ab71d891fed4f92b283cc2b2b964284e1fd4e7005d4d7e8","0xa93a5a49a11d4f3f57339df3bd420903d7c4227f4bf555c6a5bfdf2a4edaa820","0xf0c6874d2aa9ff0744b802c3ab16e5ac8a243211b4550973bd779fec277c39f3","0x7906d532696b44cbef5d9dc0856785ffb04da20fb48866533acf74e05f77117b","0x5af534b5429b15fc5b10a4f4ca308a53ccf757e064c459e77db081303e2e054e","0x7b65d24fb22abd32deb4b1842d2aff90a12ffcaa1b6f2c79169ebb84d5c56117","0x0817803686fbf12cc2d6c2a908e561e919ffa25953350ce7c93ea66aa0d90179","0xe45997c446f3c70476c1de89cfda9c2342b76a992ca37ffc85f4c6887993b798","0xa7b5b27b3e981e4b096c348db49f81058ae992e92681b4bd56e1f487d02c9c25","0xe5ec169c5a165f63a67651ac4cda3729043445637853cbc87211311626cfe2df","0xb50eda759092ffea8381b05ce45171ba02b6ef42b1f965320b3c3ab0d7047285","0x253c530f0210910821439e7cbca2ec87fa743b20c80f50e8340531615a303963","0x553f2bcc4083e2bc4308136802022c3e08c9fd1b4d6d3aea19cea01ead8fbb38","0x75c0224d3e1bf3716cddd398e7ae9c19d0645566bbbcafefbd68d581d9398ec7","0xcad09fb9f9e337db88429be43654a58556ac6bab6b5c3ebc5708b01e42e59f1f","0x27b7e29071affdfb7f682d9f753ea70a5452183ed1d14cb2fcbc458e7079418b","0x8fcad45f834699d8a9bb11007874f5b878ea22e95f4623b6924d0d7d34243e8b","0xa3c0a849a96cfdd57eec34717600488715a81d0b5942b2ec7307a6a9a29ef20c","0x5128fae84a5b400b3d824a1cdaaaecc48c42280366b9220f62fd032956db61a7","0x19f6b4878e5ebeedaeb53fe4d05a63699553dcaa01e426c72f6f42a70eef0ca5","0xe1d31b22e3c62112115187f801d8080ef5f371b764b7eacc1e04a12061a186fc","0xb2e8f53a4ba6ab743954276e346e3701c4a3e2c334a29cfdfe7b0ea183067b96","0xdf40d82201aa77affb3e31ba95687bf19ba2a08db3adb1836b7d7b77d4b7ff30","0x8fb65428ee1b46f90aae0c3955c115b8cd7637b224c4a8c2d9bbff8329360080","0xf70f59bf0525451a7e3904cb897155aaaf77e69a5590f192837c0badba6a5c7a","0x960ec0f1a8a5fd8c9949ce8e86eb90be443c244aba086bb3b68756e79822d1b3","0x93a9ecb6f07b2c71c28fbe617cb72f23975b75ebfe5c0f6e61c3050a097fb1bc","0x2239e09ade09a90249440818e4f8f619920d390110331bcaa3e9bd5d8e515169","0x55715cd6c9648d8a8cca00bf95fb092d5e4d3d31a781e06c7abf1ccd116443a5","0x68ec0d9d198c8d83483c2a03d9824036f1d2d04e8d570690120f03428b01c42e","0x03abe96da447dd4aac88df7d591cb5cf8c61fd606412285e38ba54cde5977c35","0xd7da79aef804523fd26079396db9cff418ff944a269e57cbf28a6b02fa41e582","0x07e4873470173895f6e93e5894e41c5ea39a132401ee7d7c8417a7718427b039","0x82797ac756a1596ff47b9167abaef9cd0d915527445ef03492a2004c42828a88","0xeb9eaa5bc79504d45f7a6ed4f46e0f18219ea058b3ec9788e5d3d6eb1d856e1f","0xfb482f334a3237784b13494187e2c89b129e7b83ccd49af984221dcab513ec20","0xf831d307c339cc98f963224704754ffc8bd3c959e813f764a9f749d84aad67c7","0xd96f8cc6d0f1c62da3c47cec1306dd7147d7687e5bc36b57ce5c07a0fda9b0c6","0xc2f7fdd220f8adf170f29685dae241c0553cfc035a608f1ecbf0ce5e8abd807f","0x2b6b034b38659958b1f5f6d9044b689b42b8f34c7dd3a856abc678906c8339fa","0x63eb8303df35d5a4871095337c8f4a78b2e905940c5b32b848bc7dc5108298ce","0x2fa21e9d501d4c9b69f70e0fb74ce3bf8642ee900959da57ac95cd511697a511","0x749317ac69654af22471b631a1fa4ecb5885c86c6e0acb7f2e99df48a32a58b7","0xed7d5ead79be764de2044c0380853ce898954565738a3f470fa00396afd4a213","0xee0b39e8ab0a9b989f87a6491ce0bdd4c46313f332880b27bb8f60d761c62968","0x33b4c97fda937523ee6c680719aa6b42b4048b6716f6901651c2ac97a8a1d945","0xd0a52b0722174ca863b86329c9665a42db7f9e1b34c938b71f8dc4bd9d5b6eeb","0x1fa43408568ae53d8bcb329b7ed9baec11c01eb3290e290667169ba880083d0e","0xda69f9a7eaa3667001349923dc68bf7b530d272981dc63aabf14c75e46b1e7e8","0x52a314df2195ce1e49abbb7030e75015bfedfb5e7033eff1e33de72c1fd1e60d","0x8d8bd7eabf988edcc41498f5e1f54f746af257063ee866adfeffa599208324f8","0x1a3c4fc36033cff0a94632b2f9577e8465c91956825c22458d72e1b6e85512b2","0xd1fc048491e9416b06af8a5a3a208480f8b40ad41ffbc61aa32f6bc59c34550a","0x9e49ca80315582bdf927b8543814f69c74a11d6c00aeabd68db6225b7dc6992f","0xa9a43ff8dbb9b5a1d4b4e00f795a89c09b2c5a8e45bd00dfd40de22749451389","0x5192784e147adef99afcd0356746c764454b3572da111997aab15295a85cdf9a","0x1c17dce0872ff0ccfa2a2f4a9fb2f759e80ee9d5bb6dedd5d558fd51836fc229","0xbec8a18035297c3367d5af08f9f2c189069a4caac939d45cd3a622dcd40facee","0xe155949df941a2f795664ca7499cd3f72f02c5227439b66f084006ea3b3fc254","0x68d522a0ded47afde56de3382f15a077f845190cfa21998d3360c4593acd0ac0","0xee521ef0f5d09a88c3e39c89c470df1a10d17f0ff49b830aaf01fcc303f754e8","0xa22c58bd77c31f975ac27e4e2c12938983c1252bcb3848015673ebdb8db571a9","0xbf5120aec25360c4f57e94d98f606eeceaaa1969cf157475959f649981b2f8c3","0x564071515286fe3c8f6f690d41718a3a90083aa843d795e6084f7e03eb9fabad","0xe9264c3db80d1fd6e0d4d9e66b5b0115516edcdb2677cc0b009045a33f0e1c8e","0x8838bb5950c95c755deda6be602bc26c2421683975c629596ae58f5117fe6c3a","0x1f50ab49904ed93cb59265141d7eb39b589fb18a677f3c0688d42e9fd566a0e8","0x734fd6c898634e1caa9b679921d626421141804c23596973c96d8fd45a6fb3e1","0xa85eab60fc50ca4d1f2c3351d866932bd091de66652f45fe931a7145a79176cb","0x21a76fe05f4c66b2b205f9479c3ba85d8795789cc18b9f1b46b6f71178b58c3e","0x51babf3871e6fe6f1cdbbf1a78173c36d7b374ea2ce29803b28058dd5b5c99b1","0x600783ea929ef09fd57d2f3e12d6a51891d1ae20e3895e12ccd35cb271b470a1","0xdfff2a34e49d00d849f9c6def0e0a42816d18b8bddb12c5f8c2bffc5ce926262","0xd071e7acefc6b22ef40950b6aeb2842d7e8495dca672d7623a58a889daf52c68","0xf03cbc1ab47630842e032211efb5356c0bf988cdaf5f3e731dc56250cc24b459","0x8693434b59a2cb11acd3a09c355f5b101b25ee36b802140d62c3899a5513688d","0x9dc5bf1d3c076c46c9f66d60d01f6cee6a7a57c89dcc51a7200b96bc67fd0570","0xf9eca09b7c4213728d379ff8de18f496872ca73247b48964ee8e8e3275ee59ce","0x7ca5b9a5999e216e70f5ed60c530a4399f625eb10c105d85926ba41dc2f3a348","0x6f074df753a5dc51c5bb718075141c717acad10f7bac15c2fac33094f0f7db02","0x7056eafbe76a47f13cd687f818654fce70f804fdb81767c1b4a0751e2bd3c10e","0xb87e1fd47647336c88e79d0f22f81c4fff9c34b7fb40396eb2ada1692e6b1597","0xc48a001c0c6f86884493c7ed7e12726b05ff8d9d97109b7b8d1bc42bb9919fd0","0x3e9225175fdc69356b94fbb7ce77458e3dcab25538ddd540ad9f76b35bce4f54","0xba13c9da8ddd65d5f1a60ff5e6cde3ee46549a9256fd06f7cd2924e38cacd984","0xe407b7329bf511976163a5995166d3aaa4cd88a3b3902c46f1721690a5c0cb06","0x3e1506e58cd241b1aa920036af6db10d7e85195d53ccd733d38f9f813e1cac7e","0x4b5507bd36ee6a3dc7f1dff18c4e3c014b29a9dc60a9cc3f69748d66c3795f6e","0xa4f59869905df716d2ab70dba9e38df3985a33ef009a5a01ccad44dc9bee04f9","0x117a597a5868d40b819b935348ee0b02ba22e2a5617ea0beb86f4831b143d3d9","0x610cc907b7ca0567e891dde0cdd58f443bd775b56939ced609f1ca5098130036","0x8e4a57475ad01ed09ddd0477d20f5bb0de961584472fb7138d032e5d6ef6c86c","0x6ad9bff0d0bd77bec8feca96ec37dbfe7994cc20ee7efbb4bbb2a2f3f166fdbd","0x06325edb15564585a95039dfc6eab1effc752e67731564b8de03f0b3c492051c","0x12e977b7636bc3d0fb72d523370da5242fbae2596295b65ed2a4a783682e93eb","0xa2dc0f0f81cd7e764979110a340d24791c6224e791075b6afa1397714f999226","0xa024d0d35d27f3cf1a7a8bf31f603c8b9b6dd315f3b1c6723c576d00cb5a701a","0x81a6eb8926efcdeb1ab69cd151ea2217b18e6a5215c209aabb49716a807d1723","0x8a4c0b49953d87b1a1a2abb29ae21f735faa88134060f70cf303962d7719d54e","0x2528f8fbc83b13e9e7b70777a655ee387edd37ce791f59fcd403cb9b515f3d2b","0x45ebd5db8b31e7613e96923dc0a817a83f6671dddb697843aed14e448fa1ff78","0xd2527955424f26aab7e180c9ac468e10d96ef0a0977f06bdc1a12bf298370ee3","0xe4895a2223f4d677769ad0df3a17e5c84eebcb9d7bc16919aed480396ea68921","0x3eaa424270aaa01e48cbbf3d812a334a417fc3eb636616e11bc305d78d79cf0c","0xcb3e116ee44e18c87cf6cdf6788f69a1fa3a644d41c952e6c3e512e1ca2eb40f","0x508eb88b6ba8d79500dc5a215eb810fc49e494987de98c45a02dbad7c78e9d7c","0x769c9b8d53013c232f3e038fa5d961fee96c025b103f3ce3151a75bda49b0be0","0x038c4ae6a9e132b9e71347f69b2e92542ac8107af629ed2addecf25d4a44f873","0x0306acbbe53b2e9c00d3f671f7c7fd25ff563451d4c1e4a422c9566a2afdb268","0x621be262f1886267626974ec255211b0b6089f32c6d64d002031fa7dd947dbad","0x4415436affdc7b1c7db31150c55aaa5a86050f89e54233a051fcde362cf5b790","0x39824b7c1f28a9a4803535258fddac7ae6473a5a3e14439e4a2a06994ccbf31b","0xefcee2b0d0b45d9a3dd9781dfc237e51340d7c316af396adbf1ab5af494c4b7e","0x6d750089807c0fa6167dbe5bd07aef8677b5cf8898946e7b9b0b17e3273a8366","0xaa97cfca995f39cd1cdc4debbfa2cb8a5e04be54dc1a6774db5e8414e3b348fa","0x5bd54ce643481dd1118cc4b2654f9f1b7a2d7c8f693d97655e841031eb755b92","0xe075db3a454fd741267b12f98f11b0c2a73e9ca1b059801d25ee770ea9de97e9","0xc3b2c076cb2fbd9b15c049b1b564f42805acc3096187c5cb6bb3ec59885c253e","0xe5cf970ee188bc9957291be5cdbadba478f09a72f1c92c88c73d7b6e35b4867b","0x4ce69bdaf48ce7415f644b919369c41531b0aedb64de534232d185ffe16072a4","0x776a3cc2d1fd55997e53982cb20786722bdbac65b8c6e398b5c69fa515cf16e8","0x49a179542d18b676a5c039957dd5ae64b650728e30d8ea9f5a976af0670a18c3","0x1f4f4dfbb2e0255ed431cc8c1c579299a03e0e068956bb56023efb66465da158","0x3b57316fc17a8e8e256082d278ef87b03b23ccdfd3d230fd9eceedadb334f1d8","0xd4363790d98a1427b4cd95e85b252460316ed6e43f982c741512ff75d886e6b7","0xf0531cccb97efbf896964870e4b4c6a179d8a8d3e3fb0621cb18096f5251c4e7","0xebb28dd64df33a1711037e3af38c527f20ddc3c4072724403b908b65b4d2c76a","0x551c02dd1693394332c71926d2b0d0db2bcf382c1f442c6c4ee3f14cc4160c04","0x42d6cd660ffd127393c8eb49d958ae8dbeec657bef0446c139e19c0763311bf7","0x214093dff49d8efb0b7230353c2ab7c42771026716f1e69ce58b1f9f5b231c2b","0xccb9adb574412fea123beffb7ecdc1e5eff248dca3eac984b17c665368a35156","0x442aa11112466d9f1f5770f43fffffbd1496ef99dbc0595593c4e590c0ab09df","0xc8157849081c8de724e196554224776e52bd5779712739f43ffec2f492e8ba9e","0xb27a4474c95ac7b8e18faba3d9647da7f77dad741448dfb63f9d7a198758ddfa","0x6d0b4d26e479a57126af462a515cd43814780ea0a7ad58238289bf0f127253cd","0xd38d296c837866b99b5ce674cfa5fc17ec64312ff6d420a34fd5702eb6e4caa1","0x4ee07ad5c0181dbdde5bdee74d92f79961775e98a3212e242d639d07321a2df1","0x89bd85d7217324899278ab361afeb290c5cfcaa2bc2184b4221ac80fa7cb31e2","0x0a6a66138beade958f4a74dd2c923bc891b07721b2ec2d9673ac5cf55e509a89","0x9640e0821a6c8a473ce1f39905520879bbab7757f607cb0f8263af3f8eee8940","0x37b56eb61ab3d94497e527ff989cd708ae207ecfe9eeeea4e1bf15c42c19b7a0","0x2dc46e60e4579718414f7ed433b90530f2d236be89751dd6fa1ad7327073ecb4","0x776d8a910aceef3650c31270b34422e46af353a5c46001e898554d9a7d0466bf","0x50985502ebc181ac56761177befe8fb86f766ae949e6c7b0aaa6f37f3c02b414","0x11c0220e1b105ab816ede16c1c6f995071595b033dcc07ed8d812d483db0be5b","0x1f33b4417e3ad0e4b14b770a9ff95c4a774d1b6efc2156392023231a19cfe090","0x5ecee947526192e74ed64868da1de271b1b5b8803257d33b063a67cd6aba5194","0x4364a8653163ed438e3c3a446d0e8f68b84dfe4d12a3633c4894179cf5e41057","0x912c6bcd96671d3fb8e3d150dfd7e254d12c22375a00ec31eac96689ee549803","0x9fecde94b71131e0e736423bc0016d78e48b6c42accf61b848c283a17e5f9df8","0x1a9593cdf483bfc216fb6589e0908dffc00e0c42eabc8ab79d6a4145f2805e18","0x2c73eeaffc35a5f0db903f8a2c84cd066de3ce7b3404e178b52fce2dee6b7a57","0x57ff8d8b16ff11a39c2afb0ef2eb9e4914c465be0aaf7cf7a3011f6a29f6e7f2","0xd36dd85e1c0650a7eb8564229f3f99cf258bd7ea01b2afa97482f7747d46ab67","0xca97380afe562ba9af8bc450d9e05975add6d8d8b4537703bc8474ef6404c9d2","0x150d15792b1e229ba133a655e4d1e7b2f08245f520fa2e875d606e35116c4cb3","0xdcd0e686f0444535c84acb701b57aa5ca10dcb6f3ecf96bfb807e4ec0dc85ed3","0x243c84a96d982fb77042d8181f3b2b9efdcc71d23b0c3ddb5296f2cd80424b32","0x490745af81e68c65649d5b8ce25d11d0b818ff95db3637357b587be61e909b5e","0x796c5eed16335affb2423d17b88eaa4ef35290bb3ea9c42d57c0f71a86ad301d","0x5edd5c168cda981901c5fc5cf46763885d4d8d0399e0dfb15187f176622190ed","0x858425df36dc0e98a0b51dc3f8152453cce87f6ed4a63dfcf731612dc924f9ac","0x3c003ee6b303f9cb95aa4ff0a922e7a5d6121bdd32c6156f22a62b80a3a389a9","0x340320063459ac297512d4d1a37611fc1beaab03092edbc4202382c9beb47d3d","0x11e9be865c27a54014e97d85f3adc6bf49e09a99c8b12d80032b18397954dde6","0x82ccb5c6f6738f5cc58d2dda51cce417fc71ddd50d2dc9853610af27c4dc250b","0xb96b838df813d30eba8d1cef072e2d0726c93aa08a26f4379019507ecc4ad344","0xcc8c6928f44864293e946e4ffe3011409550097fe8f4c77bb0dbc8246bbd1cfe","0xc1ae7947a0c0005201cafbb82aa20b047d1ed5c0e593c601b7709e06c3f025b6","0xbe4ac43a7b87ccbb1006cb6278add51c4ec60133be7e3c677ce80dab214c2e2a","0xcb86db88b728d0280c6a78a5e005847415411008a428de7519d21142e9a91472","0x0d2b8e73bc6ff4ec6b7dca3ff81a52e6b3381110d13f47f6b4c511e9a221a8b1","0x41a48d473956f18726b48808c6f194dbef926012f815c453ec24a00244232457","0x9702680ee768ce63f3f8ab9910c63fcac3c237152842be823952ad7b16abf25a","0x718534c0e257aec8f2b075728fe41c4ca07820ba4b2cde87f1754bce5bc88825","0x9c3b29b2f2f88381c82c001d258b36dba2deacfd8060c531881744b25b856430","0x75bda6e4b3289d5ebde800ecd6210a661ff639df0988effdbf5e7aa25d4ec5be","0x369e9cd8cf5cf938d54fbf23e209139af25a259ed042cc8786bf4ddb89f23134","0x7ec7d409061c195a4f63c0b2e4998b3a46ae31264de7087eafd95e7e59366c23","0x4749a4d88746c5bd8a9654c8d0d686f309d5e6a032b31793132b42933a3cf448","0x668d842aefb6a3e9c77863ca859403399b7c2802ce559612d12db45fb490f8e3","0x884633c660c8af38165c5d449409d9ebee4475af13f7307843948535cf29bc9d","0x3cca534ea8f514165bc5853560b976273810d7daaa9cb1b96b6b43e2e79ed831","0x2b69b90460708297b80500b1b438da1db0c67bf4e4ca6092667034f62a81c459","0x73be22546c35f080770952a24ab540a455e97f0bdc16e10e889af9e5fdcf8688","0x21bc587d4f6e79f5c3ac15e4e06dbdb2578d3a855eb44a75245ef8503e54e3a8","0x4b72e3875be7b3e49734d635843ee3db28ac14c3e318fe01e829f32cc7fdc4fd","0xf52c0efffbac17717f0ce44d8afc5c81a75a18e67177827b4c9fefbac6b2ebc4","0xd3c8d12ddfcc7e4ef24f0fbaf9eea6adcd61d6270d7040a9ec4b13551ae765a0","0x635dd41935fce7d897450ec654793cdb2dd4a4f5c5d6c5e1391f8e97374d2665","0xf21195508176baaecb64a1b00d6342f254d6728c1cc2fe96273a756527d19197","0xc350ceac31c179d0e7ad3cf6adccb982dbb293e2fbdd94dafb85986bf0ff6caa","0x53ec4995dfc3c9ef865ec94b8c27f76d992e1e9851bfec5b48d0f90048f49179","0x4911c6606eb907f602e3546fd4f2ecbfdd4c65061098c6b8f007662a51fa24e4","0xe6102c90b5280c6d9df33114044bfc73ed32f51cd0b503f693509f9b205f76e2","0xff1c9161ba35daeaecf61cf4f5d1d5687c920c9e439b736adc71126d581ce181","0x1a3c7353b4ba3d79cc38dadced45b7e25df87f13499d18d5e1b29e4fc24b57dd","0x5d1df20f18bd0cec6b1c5944ab8f97a2ee5feccafbd2b9cdbf1caa45989a92ac","0xf9eea45b844f1020df6a884b44e623bcf72d512508c98cd12e2ef74d3516c0bb","0x93f704bcccbb9ba751408bcc8faeb083fd314b361b10ea0d6a9d307b7d0f39ef","0xd5691144905cdc8be0613dc03d99e89ffccc95de38607e5a5730cf64ad887dab","0x998b0efaf83d530480bc2f8486d06e49f4dd012bcfec2b14716bc8a2ab1108b0","0xae8c2e7b3bc51289c663afad884e6f6daca7cdcf99363bd0a09bbdf91f589d41","0x0418597080d1dfe5388465716304d1719fcb66dd9a63d3c2ae2d1c4a10b5ba2f","0xd627c4df9eb149f532e10c5f78fab4fde60618ae05f3a694d25389dc1db2bccb","0x9cc72dbf246616ec49df86bc82eae8b2214047a06138c91a9996bf9910b77e17","0xf46c684c040e80cf7564d8939d07937c1aa9abcf24d716b15077f910210347ac","0x62258a54de744bd892574121c17744d4f3b137c24687ae9a15819fe7c67acba3","0x71ed55cbcc39f8c10ed588c7f9a121cd484033a666efbe807288331a50f5699f","0x332b1e9529f32d413e230287d383a6ff00cea350a91baf248ad17dd7836a3eda","0x812934d4ede62c8472f675bc823db10d99bbebed7a1eed07faa519093f0f448b","0x86eae7c39e6d2e0b68dcbcc84a347b5dd75a34df2ff6a77f61ed35e313ce2101","0x0b7f6244b34fe19b7d042a3b1687cf68b3bbcbf7432a403d3f406c71ef03471b","0x14b934b4b652fca90078731a8680ed4e19e39e0687c4d8bef6379593d0fbf548","0x7794d9ea601178f32e704836b27c47262d071b3ec8e1f9c93eaea97e7c30ca03","0xb8c7f8110c79cd68e9123cf85fa8b394e082a03a6db4e7d2afd23ec8748c19a3","0x063fae9fe4fad23c9c6aadca32c12d39782b965fbe04bd95f4adae1b4765d01a","0x2a34281365a5574e41673ea33eb69c4203f82d12ea756d1a6281d1b62065356d","0x9609d126b065ae8d0a8361badcebf87ee1c3f451f2d9d8439ca6c5cda8ba2966","0x9f4eb5a6a433a1012e7e3e04f5267a4122a9cd457dcf81b6997f95370c465d86","0xccbe8a44e214c38085bc2fde4db6c91868b87547a1414b84b7885944324ec680","0xbc1c1f1145e262f113a58289b435ab30011c914ab890cb9bbd7b1113f7505d7a","0x23cace3a44637f1ed058daaba6ec3218606e52e268753cf9c318722a83a56bf1","0xe911c5d92346b2706f4d2c1c29fa42e2bd98bca889a85ec9143fb3e2fff29910","0x46138c0eb5885b798f9f7416c3ffec97a490ee48f308f8e548faff58827568d2","0xe72e3d34b1518d08da6467ecb6b9c9ffb4a0361912f4ed48a9a77ce35ab167d1","0xb6e86a592a081c97deab4a302e381195a7a94d44173d4387cecec10549e55336","0xa13ef24a63767412769453589601e58684ec37f3b8baf7c79931be757274d3c2","0x8bd61a94a537e9019174cd698977c184b9c4536c6991f30af6e2c10579e5b4be","0xd4bf2f56891e51908d400f95783214e8e5878cf7785d67a2840fa45f65914c64","0x45f46203b7d59dbc1e481d0ec070fb29cbae137c4e86421dced9cb1cfd1e3dea","0xaec73d95b30e3e7b1ff02f932fb8bd09bb4b74349f8977d703e178fb46fea8d2","0x8a277802c77066f8dc136d6630a1764a83580eb87868d40cadfa19d4863226d3","0x3cafb07d0cc5efc631d9be97f52745898379d03e1bd772c24401817825659071","0x27ea6cd603c1dd54e69170519b8ca8d5fcec3bc26fa5e8f103ef8552eef05696","0x231d9706ddbfdc149682425d5c47cbbb58c0473ee7317b3e899f171b686ae0d0","0x79e21ca6088ffddfa4138aae88f6c9d9ea9297e1dbb07d1fd1da615beda7686b","0xda19e931ba050a4b08f7bbb481ecc6f61fbc4de04b24e4f77e79f985477f4d18","0x2ca6a8b7c75db418098dcdff052a5b18bf2f1599714cafa29c5279792f8d8342","0xba2b5a45e44bacf3186e88baa07340d28dc9fde3d3d710a77e5904745c74c168","0x85f80c109b068dba30eb2a15bcaac103853f23ef6b65c7f623e08881558850bd","0xcfb8517726df78bf3a006257808324106db3aa46a269ab333ce6b38facfd221a","0xe940722be83899f393a6318b4a4a7c2c07b029b94ab50a16a3b444616296ce1b","0x59432f8a69c2df45d151af7d3269cf38df1e889f07c9926dd1643f1e945eb5e5","0x214edfeb8287e90b474a0fdfaed3af40213bb43da202b384b47d5bdc179c3e08","0x795f32940c5b55df29cd88e3919367c9585a83afa910fc40966d24e0cc47a22f","0x5102fb91905203317f040ee360ab2fb544c8c3e85a4cec980d1e3cba7614971a","0xfede991a4cd60cb5e46aab57ae86dbdec4ffbe9abcebb50c6074c5f1ee515878","0x2912cc4ea24f531983fdca42a02e54e8be806a346e1fdb382bd42458f367fa7d","0x59cfbf594898b5d548d2f94afeb35b2324b63b1247460640abd0e87f2b4bd6df","0xf2c077bfa08bcb5af2b2bf7d1997a80e326f227e4b0a2dffd91bf83e5c2cb398","0x0af36ae99dcfdfdd7d155755872775f67c2e1db29aa4e9ab0a165fb4433a5274","0xc0fc42747029236c000ff350a2155b619d43af6fee894e0294b419d729e9bffd","0x9c64fa2cbd6e4a433368bb84d020f5c48c995a7a7537035ffed644ea9b74c6cd","0x1e8de86a722c4e8255ce284fa851d4e843e4615702e0a32a30ae532a64147e4b","0x3ca1dcaa115534a4bdec23af46cafb5d7411648b274a14ecef41925c5728b3ca","0xc09e9f28205be5e5edfb5cdbe80ecc82edcf400c43ac9337605edd6fa5239d03","0xd7c9c8e53d6c5f0e1cafa1d5710ba9beb364559950ca6f23fc7c098d9d63b9f6","0x726480d0b9850c9763bcdbbf71993c30fcead707f8ce1cc40defefaaf314cc64","0x614c6d967839da737832367bb1c1035c152a971f14beb0a66a90d2e4f4ed201e","0x7a21def7921d2fb4f652a084248aa6a2383dea2184c577f1d9238d1fb78e94dd","0x92e466f6967dea9dcfa547e0cc98fe939a91d37353fb681d7f47111586273ccb","0x2cfb79e32b4aaca157f6dc480abb96d985e3c1e95b96b2a756aa89dca554431e","0x4c43278272932c202fbbf8e071cb49dd52a859d6be4c3f889ca5038aee62bf55","0x5a42462bb646064284fe6cf0f135233d7620f7db63081beb0744b37a06e4a372","0xe4adee5c472c7fd7f7d38edc2c2fe5938afa031d8e0b9ccf8c8543959a267674","0xfe74d7694f71a88cb3f63334d7be16ac78d68c0c6a155db9a8bb8fd521ed954c","0xd7699105cfa055cd9b54d27f5480126c8f8559807df8d941a008cad4fc2c8c31","0x03f8985d23b6bf5cebc265eb1272246f3479a6fbe46097ad3e35fcf23c58af86","0x6ffbf6bf4903f80a57ac34fe63f5db17bec6869b37e5a32b6acce782bf8693c4","0x4f49a9996b80ca8fb79702d9280be4770ca31861527e84472c2f8026803c7a47","0xaee03b03492e671deaf91b088f764d4ed1b6dfc4a48d2f6f134a7f761115dc5d","0x4d2e2bc06b144219241e46a68b819b5ece0cc40df50dcec0779b9287547d6fb0","0x3eb26a9fdd91d44f1a7096b90064d1cad3d869d65baa2f7c9db97c887c0be1ad","0x0a4c4971341057803e5da25f66c7f7ee885a71a2a790fa258be896c00a5b49f4","0x6f8ca64d8a2e60d253f82b00f99eed678016098414ce1f014d02324eec5d0481","0xb34a5d0cb4c8440ee94af010959ce075e5241e96d5204de73dade481a2d43cd3","0xece534c7987e175d5d727aa1d5ead60d797122cb33e7e20bdf76b255a282bbc6","0xec9858dd72d243cf7c797ec5fe14f0c2afa3ec8473a54a4a22901b54f38d5dab","0xdd283ca9478a9364d81a4712f7c6023e84f3eafa1cc06aed7fdfbf1f375d4396","0x64b63f42d3ca1348149cb1bcc6ff2f6f48c76ad5b3a70d3f577e67d6f9f9309f","0x877b925e747a60d56d8ef333efa5c69c1b6f3e5669adf1c899cb25dbfc78dc8e","0xb3e6b21fe48640f8e5ae4bb27d526a530b1d6be74ae40666ef5818b59e124308","0x7e7ae3ec301b6fa6d6e896b4f826f4652fbe344bf88aea371fbc9002c2c05056","0xd910261b85849ae7bdf7ca1b7bb28b4212115e37f9af4828c98c7e39bdb9fdaa","0xc7573a030fcca9c49470a29198c77a2011d3a903474a4922e59ec27f4e8aa500","0x0f8e8f52e682204dc518605307fd9f5bacb43ecd81ebd433d8b1c9a6685a43e5","0x55bf6f895be015d53945f26fb2c5efa5726a1a65f2d188acf117a24ed5adaf0c","0x06f7bc2f8051648ddf78497cd86b336b92ebbfabc6ba972d13b95258c294496f","0x793f218f30950493924b21c80dad85d164d60b22a7646006ebd754272dbb7ab9","0x2b94cb64f38b6a210cd79e99f738bb53f28367d9e667d7c2ef69eee09403e4cb","0x3cc22caf7d8b18481e1ae4582aa64a37f5ad64d96187f25f11cc233e63cda150","0xe130115cbfbb50e3c7ad2014fbe89932918824189a1e0f199669daac6f121f19","0xeb31a7fcb70b09493e95369d2204bc25e72d23200f9b0f02e43db3e0641d19c8","0x133c3196736cb099621d1e5c40d9f92dd1d1e3a47843b6171d4cc04c86829ba7","0x6fad3a3889d8a2603b8435cdbb40b5c8f67c4abb04972206f579b84dd8482bd7","0xd934101caa2cff7aad315bf5595f7c921542ce2f612243b307b769b96bd05d7b","0x5bb8b802a6deaf658306e0619f3fa95f242fc952f5bab963c97b58bb9580f16f","0xd8a1d0615c5eacd3284b20805211118b7d4034079bbb8b7c894bc9a1dae6894d","0xbd78757d526c677c1e54b181228654072379da6861c90f2e65937dfd3ddc3980","0xce7df53fa1fafbce4d9171690881a679907295bc778fa81738fe4bab4f66f046","0x0af2985e0812129e2bba16c28d4b5fc6dde3ceca1a58354bc53ffd4c4cf9429b","0x9c5b41e9b548ec6a49cabd67339afd81d672c4afd66c7508c0ff32c5e299359d","0x4444dec0eeb90bf5fdd94e4907f45ae68f786741950b210a6f878055b3cd490f","0xe19ea34bbde0fb2f93b1cb0045111adc76159deb4ea9bf1275fcd88d8ebf06c0","0xfc1ca6dca980e4958746fa7939c8443f5f8f21a76c3d35f22c910f8161431041","0xac72a22bb9e14ce1b1b4b334d45e844c5cb8d792c31383c2e31867c8d6991780","0xa73b8667899df0d80b3ac0b3d8fe68b43b5ba0aad9c9225c1c5de6ddef11df12","0x30bfade008f6b4de11440ffde43feb803df55282114a3692615d439b6641620a","0x19bf04db83467f3a64dd8186446c6f0722caf6e9c9ff6afed217632b9b3aed64","0x076641281dadbc8c0768c768f3feb93019d8b2a0fafec5047a5968cc4edfa159","0x89cdb9210b274fbbb2d7b741ed90fe40ae58e63a1ce6a4fa6169cb15ea1e7dfe","0xaf045f616f86729fce7a2c34d1f7fe73225411bb7400c8b0e5fba526e3d5cb4e","0xbfdb0353608ba4153fa1b1653b3fb1445f8bbd6422ea7a99f904ddd32c9b1cc7","0x3aac8cd56d596b0ca335ed9ed7a7fa04d7c121871db12618c5af3b2555e8526e","0xb4f44ee84b82d0337845d7a5d11a381ec9277500850614364ca3acfbfa358343","0x36f0def5ece9c817c5a125894227f1f87ddcd6c075c84463e010c2766cb6a03f","0x30aea76b76de68b241052a1303dd013074f4d46a53bac0563b0ed5f2f588ebcb","0xcf79b4b4f1bb3a17468a9f6eb9759bc490208467cd478b90d763c3060d83c8b3","0x95eb0ed42ad1b68ee9a6864b59284c05692b6d00506b80665ebd263905d12ead","0xd07efc5c0fd133ea1dd377be604164a1a5a6fa868b4d234d61581fb8eb579644","0x01c3429dbadc616ea98209b93a90786378105820246e56b0edba1fa3bf0edf28","0x741301fb915ff4bb26a2b85cb435aaac9a77023ac75cfe395b327f69a48a8f00","0xb8491f4ffbef407e8a836f2ff7a9db9dff5df5c8687cd968acb7164f94b2a64a","0x7e998ac5ae2a8cd88c8708e2e20f061a1b1bd3eb9b301a7494383d4b379fd8fc","0xcbcfe54debfe301a1b898864de3fbc44b96a56a4c639c449406d858cb06bb56c","0xfbbadd96b2fbc1275b7e316667a0a16854c803d41eb0ef89d6b86047b1468e72","0x035cbec590660c2aa6fa813fb8a7e68c8ef656d12c7155b7076d4160b53b99fc","0x0bcd106a24956d21c1591a26f3a90ec37f270afa412b5c1c882d98a780d86cc8","0xf7474c2219e0c5d54bdb828ffaa285bbfc779bbf3fc6d98da3bd9ec7e985deb8","0xbb918d75a120958d98c20e5b3a561a79edcbe64319cc30935d8ff69c1382fa70","0x6c46b65f88cba732b3b1863d560fc42b2daa4b0c8c35556472a27e52a25c2d54","0x49bd0e85b9cef873d50e62e10de03d4138fd425db32e55d17c1c4c0c79871c3c","0x27e05501152a8a98ee33ecdc7f342bafe8325424b7e7e065c88e08e9995c9365","0x0ed5062fb9b83f37e6ec9e370895fb0753f3c17e4ace08430c6b5e1a224ae9b6","0x947ce3f5e8645ab6144c6b04772a265f432a9b35b6e743b293e620fa3663ee9d","0x4097cc087fe194066400f2238106b4e5fe76103184c42b56eb6cb3cdf7dd5e95","0x73464e77a4f24df930e851df3d828ffa41aa5aa71a079ee3379fc803983e0825","0x22e92f9816374967bd53c0e3a732dbfea1098670926df4c9930641cd024b8e9a","0xf1d137505e6b923935135afc173e3d23aa5d7ad1386981a3fcd6b8bd65abd682","0x4cc947fceaf2206f3e353f93710e0325646fcdfbb1fce18ffb6dc11fd4226d08","0xa2831f9a921a66cb8d0d583f6b31ef7b9cc836b0a555246f9b91ae4c2e913d48","0x3a7a1e9e7bbe34bc7c138b718486c75822091d4a93bb71fb4342cb033961dfae","0x6d01238abb0b75d074ec72596208f0ff73a8546395fca91ebbbcd948734022f6","0xbb6cc516a6c43ccbfc434c07c24ca349904fc716397d65b117bdfb40e6d93dc3","0x3023970f347efeb893a1cd68464e09da304bf5702e8854978574098c7cd7fd72","0x9f4994c58c9e19b2e3feaf121b7bc6ea065ad3f66c5fd8ab86b4776f15ede525","0x87eccef7167fd2da8aa956e86f6fbd1e755be8334a47258847360ccb1aba1692","0x9c8d77ceb6eb3ce8a98c080fe06049bb117be95b1a65995736dee0ca17f6a32f","0x8d1b5c900e10ea92a6cdf211917a32e6b083f287cecf42739c3a4245a28e68f9","0xd40976ee053bc864f60e99ebd5f69f943177d115c0fce5b7a66671dd3dbc45b1","0x575eda10cc8b6426fdff71f16f86ada707b356282f167f560f50131c8a605695","0xe753dc176fcb4b236a94ae565a645233d1e30ce30f72fc54a40100c50809dd80","0xd3677f3b0c323f6937bfbb4f36e7cfe908a1e2e91dc4d95b6956fbde115e41c7","0x70ba6df851e9d5debc146293de0896cc4066c2939bae748c64f8f08aba04756c","0xdf10d44d4950477e40888bc470aae59e31848cfa9730fdb9216e0b8448f57d26","0xcf0a3ec5ab28b130282a3d55cc1e6163c256f7f8c7c4adf95106c5dec657bb58","0xa783f0deade8c4570c969b5023307ec6c9310b22abcdef3371f64a905a57d4ba","0x2041e6a458c2f805ac2190ebd187b376e9aca3cb70a16a01a76144bc1d1d752d","0x7d2e5b07c7d14cee0199ad938c0c0de8c71d2d48a692f2e180457c5fa21885d5","0x8420156c84aac3ecf51af03864b77015bb634e8e2b18b0f7e36a8bb765aba57d","0x42570a1a033ff0d1ab05c5951099bc2d8960b4124aaa448cd5c0f5e0ef883df1","0x8f4eba60d2014efc0485d2cf3f53b1816f57e0f7dcfd36a186212c70e1e84f94","0xd6fd936cd61f9db350262bb17c43bc6e04864ff5a65f3f8ad37a395d7b2e07ec","0xba391eebad41f6b5b9b261b21a25e87262fe80c4bd7123dbb2ce193a6790e88f","0x838006b3da890d00a279f7e5492f2092d0b1a6066b0caf51bd16a3af0a59077f","0x1e63840cab9f66c81a292aaa5587b57c3e29d20478333a7ebd22e40d848cbc6b","0x99fe8853d2ca4de5ee26ec72a40b335f94020ac2705f36b7c8d0a2447b657f4e","0x592000c4bdb50961f106fbd0de3abfdf3c2c50de70a5d6935acf970c9d808125","0x844b10c97c57e9004eb930886d7f4e856e8d70864a0fc725310a0dba46152d28","0x8693a533f98e32f55d4177299980fe56de9d4bf33062df3f47d8dda049993699","0x8d30bae931552ce82af666d8ccfe235ad0939dc4418d37394bf9afdd1a2da64a","0x2bd46e9aea7d27e03ef06eb34ed367588489f7d8586426b99cffb65e6b15eb81","0xea90d5e8c888649dbfcdabaa9c7af15b10fdd42c518d8a4c8068336f3989ab85","0x32463231176253c2e90d9a95245a638fe0794c282ffa4f1772875d67d54a0864","0xeed0af8bd3a6e5bad3d1d93aac0382592aad1496544e66c6ff1e7a85e1fb04ea","0xa93b4de10dd10bf30ca6bf19d74ea0d28615be16db646075ccfb691291e4ff76","0x9a11792f8618e3ea9be6b6532646c2b0fdd57f43ef21bab085d966585e6047fb","0x250ec792130fdd7fb7e0da04badc2688e4209e795a9a5be767df327e35b6ba00","0x056c99b1c97e224edea94979dd089d4a8081d4f823dd5062625ed7b1948826e9","0x3365ebd1efcea478e04ab6ab36f9a65695c4e4ddcd0c0a2556be7767fdcdf39c","0x998550e30a3300c7c17e97a34ee390e456cb883cdaf3c72e0eace5f52c3bfee3","0x12290422cec24330a31af961856fb8238c27a39e5d69c66b9baa6d44807dc023","0x0bafd953abd0b9d2be0ac141d06eed2604213f579dcabec80b877aefb5cb65c6","0x69273b35dcd1a591ea554f4a85f64610556f72c503617331badcda062d0400ae","0x0e4c0b0b1a3e304caca08bc7317762eeb82e5f17aa4dba6ff25c57a1319e8093","0x7f1e85ab58b6b89de26752fd94bb1f408ad7a3780f7615983ed9915a2cbdc23a","0x1dba8ba1c7f8383648aad985fd16da624e084c87b1ff8b99b7d5b1e943f41277","0xab37171a354c802978d777090d8ec933cb2c329965f9c201322a0365a7654e15","0x6b1b354fd45b9e93eaada21543f1fed6543ef07b07abf9020458a4e5db9ae14c","0x333c6d7cc679ab3cefbf033141991b3979b9e536ea7a9c30e5aa6d267c94426f","0x65cefe96081d1d3dcc771c60986dd1b8d874c25c5a96c48f8bf9378937e90690","0x9717ae0f1316082688e02a44dc41b52c9d00c5e6d2ce7d98cc57974659026210","0xc380c16e4ce49c9008e2f39619b683517ec81e2727a285057ae8cbc3559a7500","0xfea418c6abe35e70b7fee46cd52fa30734ac35576a7f37c67150e9fad743592d","0x58006003b437a3f6ad3a60bb52216e284ff4c5c77aa70a091a4665a069488390","0x3bd158fe1af6105962a956f76a0441d80b44b63596cba59a0a7147eb7edb3300","0x18953da788a6607764e8ff52b071c32a942256181689c16f7c6ec9cf17bedbe0","0x1fa6c5a883d750217a167cf1ab8fa84531c9284e66cee1d4429072457a8ccf71","0xf5b523f0554d179a93f8908fb944ebfef432e2bba0295dcdcd138cd07e33a426","0x14af1e46080b5a47d17a685f0965927ee8c13df3d8668395b533a6b5a9a0390f","0xd3098778bbb5069ac27928e321375392d97f1773cfee739aa093b4fcaebb29bf","0xf716a8394eb43b50e9def3fbaba8eeff510ba5bb72e06ddd7f233bc54b08daa5","0xee58add918e32a0cb0f5187aa24a0eafc72fea2a757155b8a05e18767fde6db0","0x405c9557051ea7912ada3ca08aa4a59a9a7623ffdcacb487749ae23284c2cbde","0x6ff6235095378c826a4ce70258b1d74f09df20987a5798d84b3fa06def926563","0xea685a126153833c88b7fcd78f425ee29b6e0e546149e50ef7d05c72d9d04a95","0x66c4d247d101ea3d49598f37e6f5d47e927fbd6fd50b2add107f6e21ae49a119","0xc0e780120e698a8e27393be9b1c360a50556236c250ba09c3b31665df6abe88e","0xbd1dc02c4c799a7aea89867d88b69412d66a4484fe178dc16e3fd90c68fd3294","0xb4c3c2fb699f60828b0dd6d3ca91d9cd65ec2398268824a4074720debe3caca4","0x92084c055834a7f9f09af784f1df456a917e85210b96b5fce2afb34e14c1f701","0x3490f6f435f9ac8ab2cb27d7bb7f0544a1d8b72819bd2358ee242455b54dcc88","0x7fd1e714d5ceadb00551841b228505cfecbdaedb0f130310a16d9273792eb9ee","0x1c68549adf9f4b2578b0cfa962e95c63244bcde78d10037f1adfc2d665d87a24","0xecd4764faca92522a8b70b28f9472e968215d65d638d0d21cc8ca456f9bb72f3","0xfeff41ac99d0242f3da62dc3e68744b0df83ad8da08173027d53a125366b842c","0x55d653fd6f8c65c4fd726ba36e687552fa8b2addd751022f96616efbb3437699","0x64b13d45fd4d452b29f2959d3d43c048d44c7085da1afdd6df0dc106244fb3ad","0x03dd4b0314f5c6f35da0df4b4bfb62bca6f202be3ee56cfc526c9c7e13aa20d5","0xe10c98785d368c0272776a63e8cace0908bbbe1f67c53961d93cfb7b03fd4456","0x377b5df49195db50c62c9a285b8560c89791d763c5acf30aa047494d3590eb58","0x55bc6f180e3d56e30ed37c582c50e64fee7e4368dd2b09103ae67df3bab1ebec","0x9fcaa55220f11b5a3f465c6574e44fb2e255a0322a62295b15c4c3b7349cfd8b","0xc7536cf9ff667f0da0c98bc24e2f5c9c2cb9ec1ba74dc85f7a724059338c30b5","0xd18a9f2ef3fa0c0b995376bda9965b6810f1ccdda51f4705230c330bc85c3d13","0xf93317de6f1c3aff210c7ea7817ed8ee220117c908b439a81ecea119ec6f49d7","0x405707142bfc88492f81483eb64affff21c6fb545ab62c71599886d10bce0d4e","0x21fdba7986344c07b2074fc3ab76a0bd3bf8581b15d77488ceac5cf5f8f34950","0x0f971c54e23e7d0cbe9b9791bb1b1eee3773084fc6e2daf1fe1b9d2a27d62f56","0x0e20234277899e8f6a338a812d99f1a46dfed9cbf2d8f9813bbd5e7d7820c0b0","0xf6ad62dfdd26d4bf3cc337d58e8f3e58e3c717528118561567ea9f6ce481de5e","0xb7845d048bfda10d313fe0f22da66bc0d4ff12286f6bf543525b12c3b258eb32","0x10ad9c4afc4a711c5625dc7dfc7e9bb2754d2484bc6645873c35a67707de2586","0x4413da1f1719d81029a746a339380eb03f43c529f69094554ae6d5aa12129940","0x99f5b5ef38f23f8d159d602b635f11c7a5d3515cb9395945aee695bcc9b1c5d8","0x80e1390f5d2904a8c2306723117984a00652cfdb60984404dc5b25463f91d593","0xe43eac4ecf74a2886822db50e973e2db720f0ad7cf681bfeae314b47ceb23236","0x2ababe47d12217ea4fe80659c4d4b866e7980d4c061b2cbc2482926764d0ef31","0x1db381b43fc25d4f3b759276c0db7d4080b2c339c28d4a31790958e43754b61a","0xeeada2cb14f6f88a3f61ae11c363fa1fadbabcec9c6af732d2775c2c0561dd6d","0x42cc7d72a08e76182ec97075098e8ea3c197e274bd286b3d174127a47872b7b7","0x6ff4423613dc373cfc0243bb37b6ba523ca44c9b32c94427994ccd2d8585d032","0x13f208a6df9bad7bd469c0bc5bcaa80fe9fc30566440d2babba0dd739a41e095","0x6bad27cabc9ebb35de4670505ac452ee7d1dcc3a1007387c1e10934b61b19d39","0x85ad3be922702ca859952261b2288f1d30512026e3133a4128a0909318cbd05a","0xeb11a6ec5947c9a4e46e0d178daf43c609295f30ad95ccfebe3b8f9224166536","0xbf725f90cb5f5dacc8e4a09eccf3d32f156cc8c050f440ac8b9c67ff5249188a","0xf306f6f541207f3f04a677a3ad3ee9f618d7d94e8c839376c74141a54d6b2b5f","0x69f6167967d8f599dba68067ff99a36b8809f6ccd4f0bcf9c7172ce4757a8c3a","0x532b77a431321056f44e027fa077a4e9a3858ced0c2942eaf28a182cfd7d8ae9","0x8fe7f22c99f97d6c12fa3d671879b812bfd3ccc9f0dfa52d02707ba53e15e487","0x2083141cb48e31c7969877add33f64c0d25765bc28cf5d5419eacf44d6432cee","0xf3e39ae597282c8ee36723e518b56267b81f601365e0869a3f14c5e6c8390e2c","0x356bce26f4dff62d738ad5b839bb4bfdf7cd56c7fc619fa93edddbcc0ccc7dde","0x8c58729c143be8e61f88f85b15bc8a6ab6f67eb1e9300e60c2badd883dfffabb","0x74d0adeb2b0987d9d34e298172b953c37eb6c31bc2e6eb0957e9cc1a0c30f7f1","0x6d0bc9644a0d0ae0cbbf6fd984f80e1575baa06bcc919a97bdf24ae20011b6b0","0x58023cd9d59adf5955512e608e4472c54e68ec6773ed2014a857e7cfe57cde37","0xcef7d3bbff7b82e730adb002b077308232ed508e9cbca1102beb26a8e0f63ba8","0x83b85c48a5b455e98ff4b70c2cdcba7750748fe9fc70f7fb283e1bd4736291c3","0x93dfb52963ad8a5df07daad7d5c9b8c9e9fbd6d240fa84df2804492fc0b441bc","0x4a0203da7bbf8cde458ba3bd8a0f9a30499ce39a1698ab79f7c23529b4356e5a","0x3c74eb2a4169c061acaf9b98d5ed8702f75da9f07114bd2d15eec81e651c1052","0x375cd56188807db8376943463724d559eaf2533cd4e8f2c9056698d91520b5e8","0x935707fbccaa73ff310f1b9897ce91c0ed7a9a33e7b89b3a2fa5bda5c64ef68c","0x4dac6a66248767131ddf6087af544add8a28f4272288ba15cbb0e1b87b97036a","0xbd5b7042dd2910d0d7c59c39534c23b00cdb2e5ef459a53897029ae4dcd01871","0x9671198981cc4f19420cb6a8faf432f2abdb78665bf914a209d413958c990b89","0x13da342988e7397b41636a4de5601792567a68638fcdf98c078b82f11fccd830","0x2b524d41f8cf3e8fe76dc91d000c13d9c58a0e131650fc51bd45114034187b06","0xd5b0deff2fcc040bab2f7e07fa24475e894ce38fe92ceb8bfc5b27db9fabc8d4","0x01498db3d8e69c1b72d1b21323caca06dd890341e6cd0451c378e2dc3d43a90e","0x63783b6ff3f0d4517dbcbd9d1a2ac54452e7f81d56c4f72138a3dd8f4d28a38a","0xfcc300872b2ddd967dd3780b632afe2ac3731dddc7a932e412391bb25fcba209","0x3026dd7974936859da2bd409e2fe659b8c7f99cf1276e9dcf5fac29c96bddd98","0x978bade55f7bb733b862b1ec9c2dbd96da018db1d317c646dfe771f54eb77c90","0x758175da3d08057c5ca7bb4ea9c333beda11f8b31c75bbbf0ce24f1aecb11f5d","0x48bcfe25b4145ab42be1c6a3983db29d09a569037a2bcac786c2f0271983fb67","0xc59b5345f90ec3b24cb5cdea969bf27ccabef6fc839b776a7cf1aef5157ffb2e","0x6c76cd87d97174f7b6c7a567eff75d74a92582b393c9a236f68de783d56cf54e","0x71cc21e84781a6ecf366d7d55121cb3ad7400580dd04283f496f78c3f13380a5","0x53b0e91777040fdfc71b39461d9523cd788959179f06e5a7b6f02d3a4f2a7f94","0x77f24bf5ecef8e05c36ee557ef559e8944867da0b255bb627b5bbb95342c683f","0x853a52782856127f5ebfb8ca1ce5bc8a7a3a5f43afaf3be22623641ef64af82e","0x03b45b3176f6740714037df6ca6fb6a8f39d6f805c6420a15a3e5d66abef1871","0x9eb3160d33cac300a964e324cb703bbcc81c024799e6708a59eedeb02b630cb5","0xce4790cd8dd098a5f368a938b93d3e7dfb929bca9a1f4a126c5d890fd20918ed","0xfce172131f1498e45891d6c02b5c40116090366ec4dfc48a8cde03b1f0585a1f","0x8c5584a6ad336031e742bc3cf38487748d333202d0ec8206af67d6e54facc027","0x0b25f6adb12cfb5e5b55199631f41ad8b8357dee6e6e346b0456545abb7ba3f6","0xc1ecc95d1202dfcc3e92e42baee443792fe3f1c35670473cd769b8182d0a6c20","0x7a00850794b4540da9feb4f8841f7ed7b946abc2ffe84698afd78fc13b7316ed","0x54b56e808b3b4c70b1018b985391d5a0673b19116935e27f7c88b0653610c92f","0xf729d73b37f5f52c870a2b28c5bbd3f3406d5404cca3711d6d1d6ee87ec9585d","0xa41a5f06541aaf2191b6464d8c7c0699726b05f5efe2e548ac889007424f7cb7","0x915b8c46bc0f38e0174a3b37785d1ee611b199816791107e70aa077efd239036","0x9e1c5143c9e57824b0ab942047bfb464425cebf4dc46c3e85da97ee82e32bc98","0x767b5cebf84008616e72eb71959d4fd9dce0e6b9f037b433578436ad73192e73","0x78c865c0f0e429776a1f0000585721e9d0e597b9fb0ddc0b0d5d2723dcc0b3b6","0x6974fcb1b8d8854b3547c047f4cba482dec74841ea511488672e95515968aa2f","0xd86c149c6239dd0d13134b17c1ac38fd945ab4dd9d8a93e46c210fa99429369a","0x799d3e42e518fa01f3a6547243d374ab7decd7c9a7dff9a18adf5494da044fa3","0x9d24fa061317f353601d5aafdaf5b0b98d4a7b102a838acb353cee5e649f5136","0xa39ffcc6f5ac1e4959e4d9f1164f25290996302b702282ad921e5adbd6623ef7","0x661838ecd840176ae35f14af8840577ae2abe389c50dd310498e0a7a90b4572b","0x6ae31aa75ca40c45380d9abd90ee8135c79fa2cc6574b95977797e92ff40b35c","0xf9ab8a45cd37ab4efa78c954232fbb9cd26286ed18018d04e1ed62ae1a6ced74","0x8f3f805ff2e573b0ce8b0220c33beb71b77c888fde00850d458ab69c6f4db67a","0x1025f47ebd2d1203c9f260c11a347cea637aed2a1fc6391d24f5d731b6fcce5e","0xed65690807d7f5fe11f340301e6f6362a0574586aa98604da0fab16fa8c980af","0x9debe3ddf4979f24ad5b81ab3268ecfb95e1ada8a1919b43743ffe4150fd73f0","0x68b506db0943d5aed4e2104ea3601da195ba3ce53b723da6fdda01d2e6d5ee1d","0x088f8087c8bdfe263d3f0327d6980a63e81e5b86dc1ba5d982f780d7326f8f78","0x8832b7fbb86fd128d9783b2eaed1414769e637426434245c3a751007839cba7e","0x2f17cdd13470d45d568ba9d87a64022c925b94f025e426891d8152ba43456ede","0xe021b75013707e422efff024d9c08726cbd4667c625133d69f40a613c981938a","0xb6bf7c5ede3af77edc09337f5153f082acfcf2c551e07822fe5a0675bd1af7f2","0x33aceb7505a0860e58a2a94dce591b17c0d599231be979936cb542980dbdd5c0","0xf6d7e70102790ae64223e5ae55d0f28fdee4c47e5023ff52a92143b6cbf7b0f1","0x9bd55674dcef2e9f0f1fee294a63aac1a99956a6557c8c8290880004b35a0463","0x82781a87fc1f270b61e94ef5bf7f6c0c514ed6d741b0d2c052f2868955f4564d","0xd3299ad5e8aad1feb222869c9df235d260b03281ee00e240656221d390e6a4e9","0x0fe35d2bc0274a89bee81ced0d35421e2113795a6803ab166afce9ecba10fce9","0x84e901d04b8746c688030e4c2c4b06fa239bd2bbd6ddf056dd03a7f131e5bb4a","0xa38d3793a74853792b560ec276aba89fab2f15f6798105445826789c84209277","0x7381fdc2c49af07ef9d9523d7ffa244ba14e8c32af7a3c679cd4e3a1862f2d5c","0x38049d6c52bd326628543eb4758f15478412ebe3956da7dae474ca06de63f72e","0xdfaf46eac5eeea128c4630ada92678184e00517aad8a786a55b6771b4250668b","0x606489ed6643ab1b64ddcb56fcccf0a3f4735fbb3d5211bf3f716f8085565232","0xd41758e6efdcbdf4fdb8e932b5480f8ef71dec7b9676a2add250471ed8a56a8b","0x322f9fe6d4abd7d52090efbbc454e7c3b316a438e0170ab19a30fb6fcbaae154","0xd8647e16c185c5cce5c0c60cbb92947ef82f2cd0212cd4a9a75a637922d76bf3","0xb1ef3d37ee7620ee5061f3b0ee354b5117405e4279155c5dbee65724aa4fe3c6","0xa77368ef021dcbbcd6b4006eed8b0d0fbe85a93421210bf46db9f4a60bf8de37","0xbac6b8cc57cc77f06fe65245b01eea2be0e3c5dfc0576d1806731f4301a2b6b6","0x91f139c095730f37fee3397551b1ff89f2643eb13aef32140a36e321ca16716a","0x099ac88ee3160859c2cacbbfca11f2db146d7b371c1820cf524cacdabb7132d4","0xf4586fc57a258ddc6a058d08b8d46c2672a0d01856f906acd87f7249f2431602","0xecc35a372f3aebeb1320262d911adf0b9a2b3336d3a471da373d13b8adb958e5","0xf473e5a53c426c05f154ee1aa6f33b252117e4c070a8894e6cd9affb99b49c4f","0x95dd7fa5a4412870513ce854ba0107a72a8f16d71527762c01c78eefb2c050c2","0x36b4a6fd91a17d621dd15e2ce0c71d9297f438529fb1f10f08f8a7f77b36598f","0xab2cf03df11690b869fbd5877d356057f046e72e675076b4e6aba48cc581f65a","0x85af6caf8bdfa5933f53ac450d3cc4c1985445a6cc7580a64c2e8c0b536d05c3","0xac6e377ee794df0bb55e6090e5d9340dee2be43b8c00a3072f78d9b8407059a0","0x3d9093404e7922807e0d1af7082fa7233585f01a6e1de27d890a04aa9c9e22b7","0xde531c6845a0874e9a21ae8fa0a628d2d7466fbc744815891b596e346d020e15","0x1cc1018c83b4f0084ac204e5c7d80b32336711812449996bf0794463fc644d32","0x130db35599737ac291505531e8f0930b570fd2023f28fda5d3600224e584c998","0x6ee194e08657d878380b036b1d31a40007cdafc057d4f1421df213f65fdb405d","0x26401ba4320c684847817dbe77e2e96ae1183cd80daa47c76fb32a0229d78ee2","0x580504d6cc84cbccd94dc21f0da53be5ed54fade8104d8d8ad477eac56ab30be","0xc94af78beceb32fcb6ce6fc0c1e135e5a9dad8ba098be00ccd557a08bf869666","0xe836dbc2efc8197c81411ee9466853e2bbc2255c456b582417d9d3e036400825","0xd10c7a46411e56a6df6bcfa23d9ae26fab2f9222b512b22add72a3eaab666121","0x36b0c785cc27d0ab9747d00939ac21c64fbd73dc81e5f834607d25aa05efceb5","0x1992aeb5232ac7a4a29ab7b44fc6e8fdc4fa5f660bbc338326b52ff96098231b","0x4d7dbf7410e8f07079f0621de528f3ce318a726d0c1412cbb71218238c51f1e9","0xf7b7de33dfd6cdfb647e13492c61e1c45cb42b7597821816f2e2ce81c02992d5","0x345a4db46e00db42163d3cd1bb6ad89147ad2630d23e270b2941e7e2d66befb8","0x8d81b3d9a75727df1ee48a6dfc4050355d5d8a340ac1cdafd964d306619240e8","0xf379cae5f27dbb36559377ee82ccea56b51a4f78e8f926cbd8b93afd1d8de31d","0xcc594b3c1993cfd54a732e7d3357dc94bf16d659bb801bf51dd803c8e5fab0dd","0x43276d6d7e3c0a2b7a1e420447fafb56899d4da57dedfaf3530fb89fecdb1c41","0x7cceb4e9878f89b31842293a4b9f42134e3755d26cff8db75f86ba578d5c714c","0xb40fb1b58db242cc704cda7e96f328df334437c378e321599ad2e02401ed4b24","0x42247ae24490ddf719f73865b318aa90e674564a463f0e91e5548447afc836d8","0xb76205c02e8e500b05792d067c6f0f975852c11134553a934553e7459e4c0603","0xe3a39a2da73255e6c5d49733a4ceb9a2b06292f142b5e70e7842e737eb827b8e","0x12de050c68c69bce7fa61e286ff29b81e7f4f1625fd250b30a24fac8ef6ef74e","0x3a4e1356d68facff2cbb0cc9125e0ed7cca0c547a1c0a687c3a59a2779c4861b","0x556afa2960b0d7058d8974570a405d56feff09811c8ad3e12e0c04fece076044","0xb281fd2e4abd64b0efc47bfd6d83a728c5123a31556bb604216dd91a6738158c","0x69fccfae2ea7da00cd820ae6f9e0b33611be16c0b3c6df4472dacb0bbade0bc3","0x9a1c36a86b2c41945e438773f9aa89ef5a6a209611a066f539cc84d636a23d42","0x1ed29569d1355a2c2f27e72ac58923270cb52f7e95a85eabd2289407762dc5ac","0x38874817fc27c9097063db96756a768d25bdebc4e6b7053eeb2765c01a2b9a0a","0x476dc302c0a19cf7af25ebdf7fae3b24dbbf916be825f9a13eb2302ce395298e","0xb26a54bc4e2855a411f30925b871426109b73c83a695137a01293013a060d4e6","0x6da20568896f483087095fbe15ac519a64304c81d30ce9af091c99ae246e157c","0x7d173f4bcd7512c6ebb2db68dee26f5d45039d5d256ebc22edc14d52110513f6","0x5a1fc69e56ecd48d90db569463e34996d3dc1d8f84d274f6e88fdfd7fd49663d","0x32e8b3e59cc9d3c0220d12e23290002091c8473ff924dcf6e48d50f43476d93a","0x1c07ddf9c14ea8a55039d8ec935fc6615de897c7fb7663a2d2cd4054fb83c7d3","0x455a5c2f4e25acb254b02bc50faea27fe55d54b3c33b57ce4b42b70eaf8ff8ea","0xc3271a6d195de6823f52ba8538b9e299ba99ad4c7b9e57eaf75ebb83fcc966a6","0x0474d35e4a970a99b991a2b967bd9ebbd6b41d5460d6dab9284ab6a45a9cba49","0xae1249ebb39c2417808681a3233ef46b610f11a6710a1afd649fc50f5afa3ea1","0x8f3fe9250b68c695f7c4782fc1513f22ef9597e8485bc8bd08166c839b3b8653","0x7c9a3f909565bf171b6de126b2098eb4bec42dd80b05ecfa5a439a5eb01e76fb","0x3c1fd41c8bacfaebe8ec1b778750849ab58d01d9f0a3b86b394a308384c638cf","0x42ab2662da4d36782f1ac11c2b57753e678ed2e2f8780c57f754ffa8ac06165d","0x2ec8a5e91c0a439afeb4c743c9bc6f52a70fcd5def0d05e60674e397179592c1","0x777d0c7b2267d5872c10454b27defe2668e216acd09b61cb9af5b5d016d0c2a1","0xed8a0394e59eea365c3e6282086e375a4173dfc7e394d453dee49cf56694cdb7","0x74b7b47a9ca1ad222d54c83cd997ba4f6d24d54a3e6384e8358644810537280c","0xc89323b59d9acf7a14dac08de4168cd875ccf23936a713b15de1a20bd19c276e","0x1fe086c212a547045b4cb13508e207269b7db3c0f0bdd79f928487923ac67d24","0x9e245f8522e309b022f2243ccce6661dc2ea021a20dd09525efbd1b0c1faa9fa","0x89b945bded8d0b708696bfd267f4ed75357577f2edf1eccf36052035703b6ba5","0xc3df6dbae87404695c9e62f890ccd25558182d6ab29748590e5fccd9a91f9f24","0x3d1aeb687d237c8656ae5038ae847bcdce29edc876ce4d0d7639fd6b50cdf2ea","0xe5f75cdd047efb22f166a1d3795eba4743719b266460f298e8a1120b90f3f9fc","0xa142282a0ba16aeb1e40176c752d0bf24b7f106a28082e8b325cc4767a892067","0xced3db91cfe5dab0639141e61bd87d4cb30d35b0a8f279f1e2b87c59693f7952","0xc27d6bd120f7a5050c73b281e958150115b78565f9577e58a7e389b75514a05b","0x92cf6b3b8b397ee56bcc787b0e7fcd27187ac7491834a68cfe714c83c598607a","0x4bfceba96e9f10872faedf26b3fcb8f8697dc71889e7af187b3ce732d911032f","0x2644b5d9e2c40c289d7142a6ba8bc9ef2a2ddb0b7d1b78629de61a83069ea622","0xd1adf6248bd688ef24dd31d553e3ae697ff29039dbab447bb61facd91997ec83","0x1c5688df0becbc051f2f56a01be1e3186c5c239413cd06247168c86e959d567c","0x4fb1952b4e2f7cefc9445c151e53b6dc1951fd628fe11b8e42beea2d726281d8","0x1714d07d7deb94468a76bc1142bc83fd966f7a3c7daacfcb391e44a8e9a50ea0","0x1200fde73fcf4913dcfb7be3b2ab6b35069da12b2b4d31337702271738f2dcfb","0x49c3238beb601934cde90145f3862c03f5036afe4b472ca1a5f9a9af605c5599","0x6379117844218ffacf054cdd9a0c101d0ff8e6302b5e07b7719358bca274a70d","0x0a13e4183bf2b25ff35ca3769fedfcc96361bdf630ee4ecd34bcb85f323e49d2","0xde69d715cb9444b1a94d814f652b36e0a80388f885e8a073a6f04620e32fa1e0","0x28d88645bbb8ee043e725fe68315811e88939320b43edc8fd63d7e48ce6cb48a","0x9ccee68199add3b525b505c092914b4866e979a44ada841d74a9265ad96123d7","0xe6e37f33778002023ab47a82206d73c33cc71128a76738b241fdf4207bb7d23d","0x05ac8705e6c7609013406c22db8d34c9dfd8ae51c0b39fa3e9f347d356077bcc","0xffd0c1fa852b4b57b104357dbc121f148ae88f23b92bdfb6f69ed2a186e1b770","0x4588ea9a25532a1d495f40a564246f706779021940fe5645907a48907e4dd70d","0xfcac120a3d6ec8b36a082f9b800d20129ea4c5bac516d2ba476cfefd3ee53a67","0x526b73eab095e2700844b5e18bfa4ff0c175a9a7d6a56806df557e5c398e8d91","0x3d1e0534535781547e0c6bea95f65b3b6b265bc9fc0e266d2809739fae6a9320","0x9400aa520b66d4c0d0eef3e8379efdd2832fa5ef3995d14842ee803ae6d52779","0x296c0606d21f1b1a294f2e6a5b516b7a0b8fc8d927e6327644961307bb03b95a","0x57ba0614ac611d4f63fcf18ef8fd263c1e6c7270e05c0cbe94a3e64ddd55a047","0xab12d3c4deda38fce175fa02ddd30262fa324dcf00ae81122ed40077d2774b5e","0x6e2b25959a77510247238e9cafc84b86ca9c47f821b03288c252793a1eaf6c8e","0x1253ddf8bbe4b80bf27e87c7ba9175c5bb03e7a0bd45b36c8c60d5b85edc6958","0x1d9efb9cac84747ba8edd382a54229ce0619b9737fab47e4b10d99e2e8cf334a","0x52ff9a0a4942058cccd8274f36c57a06fc03be80a98df46102ef00e7a31e0482","0x823f3a5cc8e703735aa9160c6a3640a7e49728c17c1422f66500a4d3c7af2c36","0x3b629e4d582f7223c0078ad40ac2fee05978bcd7ff3161aae9b714e33461e1d9","0xb6afbdc1d111acda09b2a1acc9627bca40b7e7d2e72cbc85d6bad442ae7a7dd5","0x48e2f4ace9f502e8160879814505761093ef45fc4c9958a5e51d333d1ef705b1","0xaeecb1b565159c5a232a530d176fc948f88cb41a9c327c4743072d750274bcd0","0x8ad9b661cc07c154ee201a4773a66bc9a7e04a301fc8b6ee1a4c1506810a9179","0x0fb2d26c3f2716b5c26ceac9b54e82bfb95b65772b5c9b5d39afd9eb02f7e6b5","0xe176d97372d0f74659b68e81ae95d986438ea5e93fe83e7d4853863311d72b4f","0xcb4058ecdc177755eb8e4683ace833fdd5d14857e92b7594c03b6f04deacaa56","0x4c5d21376855b97975b6f460ea6c2a5beae75d10e94be196df51faeac23b93c3","0x51a4d744c779204f8fde32b378660e0272d08bd57e5274362d3eed6bad4fc288","0x0ea8ecb85351c3f0447accda4466864e06d0b7cb9c137bb9dca593a3b4e5ae16","0x3009d81f68777df38c79328cb69f9e06c973b74f74febeb04f4b847908bd9888","0xfd3499a2c682b001811113cc7efd5eb6895f210d5df30270fb8d89d7221a641a","0xe462164532c9852917c0efd37e1a16b3ada03d23955ef569ab24cc428f269e0e","0x031528c841ac4b3d4c6e0af1830cd50c3419462276b19b695e826a445dd9ed32","0x3dccd82d2648e31368107e9305f43baee68e337edf4bbe592f8e7b61e1a2ff0f","0x30ac526092c7c17a4fc0b8ca2cd0d810d0f99137848ecdb66817f0207d926c44","0xf37d0e48522f881bc44bf3490ec29ae9d603eb9db24fbf02922ec41f780dcf89","0xbfbd47b135e4117422987e02d2c0f31a63877daaccedefa46fde99776f7459e6","0x4b56a66d32df282217d268019e0e2efabb6ae2023da379c666eab7760a842d1c","0x81ab47d205e286cf236b3524600950a6a61e3f2528ead524db689575dd63406f","0x6cb3b485eb526099b5d685bce56763d3c553c2b645be90701b17cb680fad25f4","0xa3e7649f6d28afcc47226babf1ac247200047593b3593750fcac8aa4710422c1","0x406a96c3c37df742c8b08a47f033b3f0cc483f6b781f4b41e457f912cdd6ac09","0xce5da6331514c5b9a1af4a7c894b6843569ae8024c1ab665be4ab246469d3176","0x6383be4fe6998c374a304e05dddce9949497e8fdb6728907d19dc1048d4adf9a","0x6df1d542b9852f82e92bf5533e72a3978b15be68c4d817f0ccaf27bf711585a5","0x7a01e98ee5c28487438ced66a671e8901636ca7f7e20e36edb79094807d20839","0xf8469b24ed726941e4639f2eef1a527f70e76774d13f2dcf1b07050993a7dbb8","0x9f2a3a65b4411097f7274fca3c8c9df3aabd2473a8bfe153a670dfb0e511dbf7","0x28da49c2d291616b567731b491aafd96a39c9cac706d1075eb37ec6dde86debf","0x89013b83b566e811ab2897926d2487902e1666dd04a7f48a1d2907195ddb8dcd","0xeb3eece4726082afd8663845e9203ef08a6b1d2d5c8c8536094ce8533d547293","0xc448c22f39d252ec50a58d745f86c15e2d009823856bd5e526aafe9104252e6f","0xf0afc65666f4597f5aa9143e29c7ccc0232bc784ae97bb70bce046739cb3c8bb","0xe32ffdcf7e1a538fe01755ce9dfab23a7b10d51cee7b2aed2975da206c2ce6d5","0x664552afc59b12366b20e7e992740f1d8d99677d9847524f1803bc7c93d81a1a","0xf7c240b1f68767b95086d69ff08ab7f29f11074def4fb845cd27c409f3075c42","0x9310eb21aaaef8830b90bf5490353cf111f97c6957a2228d9f2c68bcac79f579","0x03a73c6e02d68576a85bcf16db5ce80268a6120b2d15b6dbda10897f12477676","0xfe7f33dcf45149b3640b9d98c98eb2bfcfbffd2052fb0bb1bdbde23fc5bcb958","0x0c3d03b8b0fac2a487e56d20726f69ce84e3c3c211bdb3abda75e23c08c6909e","0x9f3bb68760132d6d6361bc333d9a974e22b7563ec21bbff94c4434be64170f15","0xe2e44d87f0669605fa9cede143268930bdf459d071a48ab00a4b09c675008d96","0x1b6cbeff4e7b6dd86ff2c124c83adc4a0ae28bd454d1843da486a455a77c361f","0xd26b9ea7906cc84497091d3a87a5bcfb6a42bfd12ec2950c06d8a550e03478b9","0x7a46bff5b25f955a3e830323d8d297948201ca41062ab5bcd5c822c5f844202d","0x1463d7402d8669c91d4b6b19e234fcd8f364a983c2e72cbd56d51ac12532ee90","0xeba59753a5f6fbedd3d8fe53ddb56bccd3e50d1ace67b87f71ce26b0a307a274","0xff80ae41e1ff8c4fb0831511f2b397e23811dbe39077f69117df4559e1773bec","0x089dd94660f18589d72a3d3e359d2c434c2981618448300e752e0d0c33f8cc8e","0x27a012950997e4bbb52bc30164095510a74356eb48a88c307a1fc16e1f2fce23","0x925b2b866e0641f3e8ae832b9c5dd4e426e416272a9147081eec6f18d5fc2593","0xaa33062e72d0207fc20fc372ad53e133e383e2955d3fee971f9cd5fb00f6c100","0xd27ab536231bcd369468748ff19d9dd446a7cf054cfca87d1fa03e315eda4b4e","0x9a16e545c02242f757d89345aff654045db7d5606ca9c379cfd577efce8948d7","0x7f7e334a29c9b919e0b83d83bcc486664488e75f156be518f467ad28d34101a2","0xe89d6693c63c4d692a3db0562126823c7f0a6af628691b6d3d5c4856cfcd042e","0x910f8d0f4a0b0e015799beebf17330c3e4e7465024b0070a20a3a0bff48b84a7","0xda7ea11e6a8ac8604acef3545f5434928210ee28cfb0feb4bca857f515458099","0xf85a861308d45f77f6d9c1c07c79e165a42cc066266a403714b8866a85feb17e","0xee830b21dedac570136450382bfd64c2ed5814c3b311ec65506c8da8ec30e12a","0xc87542b60970fa53e61cfffc3c52a2da70f160d1de8d78e9b5b7d863145a9cbd","0xf98efbb810af0b7aa419d0e8d8ecf0d79e3d1171d96d36d7c95a9074bb34a62f","0x5fd357ad40297480564148adf753a20388cdbb7c900c06696deec1b244055e06","0x2dcaac98165aa32992f0b42bd1fa2db4f7b923eb45d48b5be193c17bdfcc2b2c","0x790799a62c54124ff455bf7cdad6a777c35e205b16daf7093db0f0aebe51c9db","0x90a8fa19b3209cd6153b0edc3427ddd1e6291bc2ea6e0614c53cc752281f9629","0xafb38ac8e37797e8074795a26a43c64171e3a7dd3394dd7293c44e584e43d34f","0x27c1765dc7ddcccd653f127512ab4693593c6ccff1b8d367c6f8c2a0e4fa3686","0x9672be2b61eaa9db04c0e277055cd536699242d59a0a3822ac17b8940e424087","0xd9a5325ff091c3d55b79491ca43cd5ce976a2403e619646a4c11893459dc278c","0x8a9b2a6496b0e157b2b702b8647926b1d5e9915d19efd0513691d44b12567ac7","0x33530cdef6feaf386843cf707b0cdf001beae7d597ad342992e6c0755b92e495","0x04b9d19219dbb6ffd1334253615164dabf723491931e60b73eb2f16f2d3a0ec0","0xcc16c9dead0f723f756b687693abd7486b3e00a0b5f77cc1febadf9b098d2455","0x406c0fa0e16ffdd4f072442ba597b0fc455a4a79098f50365403a264edd11fde","0x75a4a90d9667ab1e9dcc9713bcf4015309d0e7c49844501700d2814b4442a938","0x1b1972182d6f98888ba38c1749c36fd4449ded453b079aa9a180a95ebc811cab","0x2ee1e420b917778780ac423652d7778ce6f3f5f93c8a9df8bbeb34cb9fdc886a","0x34b440e9cc22cb85a4270722088184325d6604166005071db24aa401e555e6fe","0x6de7a07a463de1a554ba0ab10ebf8946017e474a8b6a1c34033be092cb866dfa","0x1acfba75e9215bd4eb092ce418451929353ac8e66e52931c7f67ec0e94c1e456","0x2d20cdf3db5de0884deee20657b5018e489b19264b3b1d7aa46c932b737d2ccf","0xdcfef6615d289060939a141836c696a74526c1534d5aed7ca20b2efb27ce03ed","0x6dd3b4a8be51c48e50fbda14bea53594485eaf43779c4656f4b658cce2ebb2ca","0x72b2f51e2fda36f22ce81329f2522a3bf212db3b82890ce9b29279932056269c","0x9a6ae30879a69190aaef3af5b55d06d2087960c4def4055e73728837a3322998","0x42c0f10436a52055f1ee3a62e3f2e1cd5bf20f94d96648f98a21f29eb71fd06c","0xb28ba8f3b8dde16de4a893bf7dbf21d158fc292f3decc8feb66d567e5c23c77f","0xcea85cafd3be2d9fc428814faebe2001424f88c74a6c82b657cc4d4118bec9a5","0x2420d41f1e3e2c3a05310ffb4a8dfed6999c14a37889c28e6f49fd642b36531e","0xd81f42f8ff7983d95302f49d7e5275ade2ac3c42678e3391d99734efcecfd414","0x3193913198b07d2e583bef1eb21e225d8f5b08cd7b68b420f836a285f991391a","0x0ba1f132f7d457c923a7525ef50b69d9b2eba072001753ad1ee9bbb46f888e1a","0x1213f62435d39c9cac8ce5ea09987d60ab5cc442982eb551cb99ac9c87fe6937","0x2974aa6e364e6a56eac624447a01520a6c57e7ae8faeb7cfaf4312db0f2b445c","0x1293f9465b9abcc0f271b03c628f74bbcd2086aca528da19d68d7f49c42a8042","0x6828e8cbbc587ef00bc0608aab553e091acc93bb988ac27301047cfa68df6f16","0xc7d3372a890c4062d12dd4201514c3dceaa1c31be2e2254635d6a0bfcf3a6239","0x1ee94dd70da2d33769919177a3b670cbbf9a9265117c7fb5e1d1bfc2f329b125","0x8a8b491462a5db7f51b8558edd6aa7e651e872f3558ec4d1d3e6a2fef5fcd12b","0x2cc6ec35e6812a7475c1209ac2ffa2481e2d6f9c76abf06a6edac48748833ed4","0xf66b553360b40e3c841c02ab640f638ca9420afeb804f88b77855b1c7807b67d","0x10e2bfe6e7b22ad5c3feb71369da9a63d23350ca40e62ad3d654da11b36cd333","0x3092ac4897b5772b7da96114b4a74099fe926ce79d4d3d32605c570eecb58ea3","0xebe7cac903a3c4a6b2de47417dfba3e24ba1c0a735f6f926e4a57717d573872e","0xc5d8f8038e757eabd67cc360344d62dc20964c91d1ca5ee19bfb0fd1dc80d950","0x87c7b2b095389b66534eecb8c5eff1185e99d77d9445fdc9ac61a35c89bc5240","0x181b5f49eeb92d46cc06f66119f17bb7ff93ba30b6258b0dc64d72acff3e30d0","0x3ca8b0b5334682f088351ec554602ad40dc927eb80daddfab47828ee879af4cb","0x9834dca4de9a4cb203f6e3f464390c4ff81066396f5540d9042fa638a6d64c19","0x1fb5b0e56d20d6759fde48caa54bfe7282085460b254bc1c02719c4b5a517f71","0x08abc20a3c15ab60843e341b49361dbc7257ed8993a030191690a79dafc94202","0xe6d26373bc326091c4a394c9136661ecd46248c7bbfea24caa744aee2c2e6c0d","0x1273d0a600f49f01ea4bf9b499e2f774a097cdc4cb40a0130b1e5c86d586e9f9","0x7c67bb26d7db96729f9fd99e28705ac764d513d209d7708f1543391e2692989f","0xd95273bb3b44c590bc15897c6c8e6950651e3ac45d7cf96a2abc693630993bb9","0x8b5cccbe910791a389eadcad244da77008252e7aa4c8ffab1e9823f0caaf17ef","0xbb6dac441257db59282bd1222fe6f28bdc9c37d7733488eef5b111d1e9f81366","0x4facc9f81175074cb909d426c446a4e193dcc8f1c8891da32691ec20da92ebb5","0x8fe2ec6c3e47d89012e8fe93db45382da7fe3da51f2c01cdbddcef49bcc99484","0x702ea427bf2a52466a35bff977282315347d6b8f75a5b22884866873e103753f","0x84334c65385f01d3bbd605c919dabdfa047184883c5e71ed4cfef3639c3e6e58","0xe29a368f45eb43291f7a07fbe477e41f5b3f0417f5e2f289c4f51c4b6ca40e80","0xc74a179ffe3ca693c63508eba6eaeb4bfa401276c2511e41ac7b675358eede10","0xbe62956f6394f0be139d785f5bf6ff65dd4bddcfe064c35aa308245692103cc1","0x29ff4adc9f17346477c0306e5523e0014243aab5a73271d2b21bf4b953cd0c04","0x669af691f0a8bf2297529a967ad283e8335db1b6c2ed1654257c4babed85bccb","0xff52ca6bfec54d78a72219707cb90c5567ad379db7a681299c7e5d9e32813bc0","0x188d1925d0b1cf1f1ae0d4833cb95763e2cbeac7231f390c29f485aa7972f18b","0x131ee433cf51b6bd07ae25e6ab5a439816f784a7e22b4d9be558404f1db3148e","0xc1e5388599366156a6321920dc0240fe1017cea1a0eab5068b9a203650dbbdb0","0xfa79e3b5d9129e1fe240e33e27eb609f66cb37bd5076812995058d16b89bc55a","0x3249b20fa66e4acebad781b626bda0c986fa3cee0286a3e79ee538262a5ad1b9","0xee4062cfa099df64e89d38c06a1672d54b389b46fb7f1f9626e46eb864af08ae","0x8e8930783b776af44aad02c46e2de070038ca27163e040275c3c9520f035da26","0x7c84405b2a587a8ecba53da0be2432326140f908acd843a3ca63160273385252","0xacaa25054376343804fbe26410fcde47d6b17fd66d1fb3df9385d4d61e73dbb3","0xe46e476231118e643adfae18922b96c2f65357c840ec4837d10a871ece74245f","0x20377a7c6c60c0ce4ce145eee1af51696409583dc72265a5c544d5b93983ee5d","0xf850b5f13847675fa876ed61e919da028953f2603897698dc4e536e5b9ddb22e","0x0f82cfecfc04ab77f98a56ae2e2563cc085002267f36cbd5a50bd0d2c7ab353f","0xeb0a91114e52f9df441880325446eb4eeba034056aff85b9f2054edf3e641557","0x8de79566bde73ad2f26cd222289ec384e035a60321508c408b82fac7c1ffc9f8","0xde4ab1fc762f7fa0aded553dec2c38b84d2a7e6912cc57dfbfda7160f720d778","0x459135d3fc53663e2db17ec2d57841ebf868f769d69fc80b51fa62c976c18510","0x2e54f50b7c05a004be24748e737e5c49cb95252f3e2755b1db3622a25f5398d7","0x010826c9c3cfc8cf42206e714cc7fde20d7e83433110a9963a73f90102e48f6b","0xdff2f458d72d2ceef757e1a05b1dc20f4915a7fb38e96d21120564a46d44ccda","0x23b1966018e2f972303031b1b8d4ab1f80a9e122e8d757e9de6b487cccceca20","0x5ceefda51b6453e9ea2ac2141944232c8274b8812d551f79b92ea4bdc37aacd6","0xabc7adec9cc1ddf245a008fc8d5275d8306dd3247d596d7d83b3bac673aa1754","0x6f3a5183d9df7f7e67c83975b58a39d448e2c6fc7e7815aeb13e76280a48e560","0x24eb93ee8846a2e8538652306543ba03c6c53c58294b4e76d388b528ee1048c0","0xb09e34005ab7a41eff3a2a705608ec60a5d59cb985d4971feac284eea4aa816f","0x86d7552548fb7bb17a4d1d68e70d538a71092750cc42030ddcac3135258861c1","0xca047974f81202b99449e6f093b0fb6f74217bbf53c07981f5636bfdd7f958a5","0xecf50a7d2f834d47423083096698899e6798c3e95e3ab90a337ea3297f1959c1","0x204f284ce3b9514cfd6b22cecf788c9d5d8abd521739b0db71f70820e9001d1f","0x7c97be5dc908082df1a2377ac2ec16fdae1cdb43e2cf4a753e55d6fa17287119","0xbf928389b9b96e859c15d1303a3d29569d0f0df0e8f2aaaef59b2b28a0b4c37c","0xbbd10f236833b662e64f13694a3bee73ed09d61a7858590600921c0dba41d134","0xa11d1190dc40631edccd482864785e03fb65283bb039aeb9f6b6a8eed33c5a0c","0xadf511e597709f06728f93b51b1725ec9a17aa19418f031cac1e5cbbb8a7c976","0x21b28c98851a163b9fd7cca053911393e2cf7596d2d24757a34f3f824e0abb88","0xdebf4d7259adac256c0c40398743030ea43034be9ef2eb9978538015401d18ae","0x8f8e90bf8479b98c8f020ff8487029d28c91380b82699ef52c5a45e5ac1169c4","0xab108d817f4f3e69ac12edaf3382b3329f45ac02de9a7c4fc28a7023c322eb48","0x789e8105e992d10f8ce27dacae4cb3bf38479a92d43d268dc00304b0539882a3","0x37ecbcf49c71509a8304209621eb17b227b7aec55acfc987ae1f94f92ebe5758","0x33669d494340d6dce2e2f642005f14d4be39846a5769bc137f97bb68368a06b5","0x2cd2f7ecbbc37338bfafcb2088accd4fc055bea2d224822714d64354a4f9844d","0x4f77b84a1be890c717212d4990c39a13f8dae5b3276aab4a5d77c782c113ac65","0x3d5d0615687af7822a53116254dc90f4f462c6f672da09dde35f8b68ec53072a","0x947fe68719a48ff3c505905cc6665be654059c7e17369797d763f27babef47f2","0x599714596cd1c71bc738def808f52ae926315c15e48587cd12a9f1351ebc1a5b","0x33aa33ccdc0f7915970b99ac3394dc019c1690c17cba2418f13afa0dbe05ad37","0xff368a09419b5f8fe0a08e41c3282bb960fb8b8be6d7d6fe2ce16dd01691c3a1","0xc50b43e56ed5761dd2b6523b92b3eb87e2559892a64b615b0691502a6183dbf3","0xafdf467ea59bce46668433d1c21b23a51fba5b377a56ebeacf278775ecbcbc12","0xaedb352ef9b1b200494f02515b21b28d28b52dd6161491786eda563eec84f248","0xccc18dc1027b76a55b34feebc5a7f145c15f9755cb1d195a50dc191e69d52589","0x7dfb037df5cb4de4a4b7061cc71290465c0a833c9c08826e769fb52ff68f3542","0xa10d3b86c75e8826aa3cbf92e3c3562b08caa0a845eefcc941936862ba3c39f4","0xd1cf1fa89d2c40f5f6b9305a70a0ebe85cd203a195544b6b59aa7919f420cc19","0x4175a78e2972bd8762855db3644ec4348d2596e34b8d61f8cf9a96deaeb5d6e5","0xf4a3c05f4aa438ece315d90600ec1294ba59149573fcd3dd1511e646eb48d7c9","0x883c48a8149ecf8b0610fae214ad0c27613cd3fbd2cde826839d14a0e0a9abba","0x465077316b0054dd4382b1f0bb67b0865538da46a76823c0e34e161f00a1671d","0x08c3d94a6fdabd6c23f7a7809b8b47b9620ff4aeed5fafcda6262b5b01a1a1fb","0x94f87602745036002f88c5ba3be374fdf9382b38b523dfd813b680d41d76bbae","0xfa5c12b7013f866ebb72c79871f865f591c4262f7c54df70fe3d11d771f94862","0x7ca22fbca019edb8e85685eedaa9d331c9f045212b722ce60ec465275b7234ba","0x43403c007bb63dee6794e282dc3820cdb08c80e6bedfbf435260529e8b2b8117","0xb524becd722aca3fc44f4744f70fe17922171f5c695b9c13fc2b6431e4495c9a","0x24ca1b8ff08dfc8de94b003d30ad883c41236b889f15763111261637e2683e96","0xe2deb153ff982ae2d475a0860b5aa53145e36ee70675c104ef258f979618063f","0x3acea87f69db03a6ec4cc1b7280ccccdf18e335a603a7187547f831bf8102e4c","0x52d04559c7adc88cb89104cc8ded6aa7ac5098fba35f657eb5808fa859a0e639","0xc701bfdb148e688d07fa0edc4d5dfa0799bcee275f2d101dcb847a0f1e4a65fe","0x0382acb0ab1ec6fb3d2af5facf37be6534697642a90e3cb841684a5576ed4fb6","0x4b08251ddf77353610cb3a444774d0fcbffc540fa1e5138c9c8dec78aed6de4e","0xf807389f43fe4c582fb2fac24a8a1f33fba5deecefabb2bd3d8530091460e211","0x1a93db1f9b7b3601bd7d144a599dc25efd4b9fe6a60285a19fffdc93f0c91529","0xdf1c72c17c94641924854539840dce9bca463ed71b43bccaa892155576ddfbca","0x85f8f64b3df40f03955455f9082a511f4eb023fe7f9aa1aca8d1f2596bb2ddfe","0x470f0e07ee8d20c604f45f19d00288f3b83de16347add50ee098c0127d520843","0xdb923a438ab979024a232a769cbfc2fa4e5af48d3a8b50c621fb403d593c42a2","0xaa2cd37b719718e2d3cacd24949401381daca678917c6965e0a72ffa9f330052","0xa889d65e2f3f9a2324e7b68e8911319582d4836ad96bf5f87080131670cfaa8c","0xc5172d51d2a95ddb05de956b0ae2912eecdf77c195d581663266e501c394c474","0x401e24cc8fb19439190b620e25acd14042a0769a5a0f12d185063268abfbb277","0x96fe7de10ac0444b6d8917f54968c9cc1c49a1f4f646de9524d4aced59c07d38","0xd9a39a0a7b059ef9c5e08d4086a5d4f75321e0a02c4988f0b2066f014a854648","0x0c5674f282037b230120acd821d7255c3826dabaf5f19eb9ed93a90eefe6ae93","0x286e9ef69cc3895299efa6b7dfa2dc14c46c3022951f17faed6b479b987fa1dc","0x58494bbe205924c40223574435b09df7250015533cb2b8a0c9641c5c421856a2","0xbb98e02e61fe27ef43bc332ddf5e3379e3dadc4a1e9307bd415cf0341fef5d2a","0xcd1718d906b2bc05e2278f5567c4d0a90c72b63cbf32abc2c76e81ab471790ea","0xe22ff990846200072cc2cc538c78a72cf4934c4df39893b9bd372664d18cee7b","0xacb9f0c5f9fe2ac63e70c7357641fe26b1bf587fe88d17113b9759e1579c74c0","0x02310aabf48126e3a962c174ccc1e7e4bf4222cd8b73f002bea058914d364f9e","0x217402d0624b653500da8fa80f97ae7512b54198c53785542881416044fd1c9f","0x0973c5c99b5fd025f76981ce4004344e1ebfb3ea544d7eb291a35e66e4a206ea","0x42ba876cf902c108e5cd37ee418117683e4436bb584aa980be0190bfcf994374","0x66bd4a3904e4eaa11d51ecd1bdcb64bcc6c3620e311b9cc672ca57568fe4d030","0xb1ea799b2e3161901eb96c48af185b834259cec521128c31b828410fdc2c2af3","0xfb865b77b1d3857f98d188c3cd31db4c2c5a0073bca6c012a6ef95d56504b761","0x6c5bcd4d416b8c336baf1d82dfc89f0da7f2f6ab53a91505e446d6cc4ace6f10","0xb4ee766706587f3383838249619e1bbb4f95d9538af4a32fc0533620f07373c3","0x5efdfa61ce15c92ea06c6e758f78c32756f3e6f14639de7a0522f2d5fc64db1b","0xeca081d7a1d61db462e4dbd2c7a17255fe85252a3bbb73fdc006bb6d09443136","0x63cae914c833d15d1f44102fa0bfa2e55c20fe071e889de4256a755f9311ca60","0x96c4f245476f38242841c257c32e7c29a50b67219d63bbf550e6e9188a66ac2c","0x23d3293b2a39f073bb0e54c6a04b3d673776ca3c175ece4280c727c103d5e180","0xad4e55298eb748f865099dbb32d2c5e80e582c52515f44432dd7705c7d404b93","0x49aed8a79f730a9ef19f9fcfb265f45261955f43f1648b1f5a80822f511331e3","0xd9097fad564ce5c91f298fecacb4e6bda2b9895baafb42b83535069d66376b1b","0x5292e73e93c18487b724481421d927d88b3172cd1bb3fb44e9c8ac44a4a88aa7","0x754983bda64c40cf90a507ec20e20ac26e7d1a5e80a28e6d672d15e6b8fc0577","0x74a799fab01266689e84425766a7a098108f7f49ff5153e17058ec84416f87dd","0xa7ae7cee086d2eda097401ce97d355bb08de439e2f4cad69ad3c56953244fa89","0xa662762e3ebc5e0ad8f94de1378de2097b696417ea5cffaca797afe995ce089b","0x0e1e8f6d5dd687ab809c8d07117709b04f1f7ddcc90ef3bd059faecc890a4c9e","0xf4cb654af9c8d13a850d20c2485f8233f7377738fea3e81dc25255f33abcad45","0xd6414b5fc0170deaa6b4f4862ea1781e5f1eeca3a3aca43849ae7f892325eddb","0xa0481e3e26aadbc13db2b748953d4fcd545505960c67a1a2fd824ed2d79a6a3a","0xc466ec6dd74bd62f02a9925e245c5d7e7307210eeb5c103a2ca524baa1e0b665","0x84740f90f13c687a5d03796ae630b2d6bea5d58d29ed20268f5adf3e26d3ba9c","0x1b60513e1e54f3024e41a75825ac4a56777cdec60b8a5551f3339c5c1fec6154","0xf0e4476b287b225883eb2c89c7a470ab0eda9e64cc0b891ce4338d12f7368086","0x747ae3e9c128ba24ff31af96a143c461e27f7e7a0202b59ad9bb787dfea42c7c","0x58f5d44695cadcf541970663ca87d97f5e8aa94f7c49bb9e3260df499c61c9fe","0xc887c5c3cf55239233d88757841ba4a2d74d664e0ba253f8cdb0f9cae4b476ae","0xa6813bdf8fb3278da19710c5002b0496c5f9ac494d8518e53fab942e61ba7138","0xd1057a31ec3ee3f46e045241d5c3d409b21f9f37a403f5e909ac4e8fc5ae9de8","0xfc2e83068fe8f6dfa407aa4f4b2ff418f44c8577817f67dfb951cd3d9b47b037","0x9be0fe66fcd93866f8fdf2c25087ef5f35717f5606018cb02cc18a483000a4eb","0x0b06e078dc3f1565bcdd6f2d1d00ac3ecf55a56282c5fcd84433c42b54156f23","0xd4fa0e4ca6a63b9df96b940d54ecb80d09d3751af14b4b9b9624af02f6a5cdbd","0xcdecdc0dd7368f2efe2a325bf2fe4e566eaa1b8c07d9c18b69460a08172c5103","0x851b51d20e9181d528256feca0bd48955010638a7f478ad814a8cedd61371b47","0x679f356835f1915772600f689767221af1d69759f924b1d3c5d4413990545b6e","0x2d3c643d0cc0de950fabfbfebe695c6602e60cf6674fb9ceaaf5c30c89c2eefe","0x0f7b2c7203209862d31d3ad8fd7495b5fa3f6dbc68ff2919eaf78d6cdba87ded","0x314de33d4d920870b2d2196bbedeb6ad93552183912b1de38da084196fff39f1","0x31409a8271c94d29223f98ed13d2a2321a07973044bf4cdc01f8bb914a02476e","0xf73732d05351714a043e98ef23d8352df5d85e96b0acd6edab17d056ebe4be81","0x52d72dac8cde031dbc6dd9e3fb229a859903de62d273b0756bdee9246077c000","0x0761905c49e3f6e11490108da264423e61d5390db5f1a933c56ebe9d5b4e5065","0x4ba3c6194748f22aaefc9e59aee2329ccc3d90aae8e80413e574022e9b6181c7","0x5161e9772d51e5b7d388123557929223804291605260716b9c1d16b4eef5ab2c","0xaeb62858e12998b05625855f0eaa2391c3e738ea09abf8b036eaf360bd2bcdf7","0xf407bf7d695701ff44289ea1f75697984ca914d670987e373826a09c00107029","0xcdffe69d844deb681727bc2f3f4d1eb97ca6110aa56fd7d2e7aa60c8da06a80d","0x2d23f672c1a5f52cb102fc6a7be4a87968dda0e6cf4ce52cf4fe28017978292f","0x60f2f3fa68b11c832ddfba502cea08382e0ce82eaa59b612306b81d7acfea094","0x4389b179d0f60c19021b50ad52cd3d356733a27ae10e509d3a4d9fea3b66e7b9","0x3be3b394d5b12c4e3cf6224c137622f35eb6d47f3818bbe47dd5b5c342c883d3","0xfb49ffcd2e550c72c82ecd8a9f53d1807c13bf333663edb83f3fea14738ea956","0x2cbb88cf60b7748308e91091f1bcda2f4923af1388f1ea2fcf78decb0522a68f","0x80855e412bad43a3546a1452ce3819281d0b8f9d841313113d5654a1f9eae258","0xbe46056acab1cb589481f4d41b50a8dcb82e41ccfdece0fb3e4abd8e88db24ec","0xf70d43514b106ce6c9951a4df2e9fa7403f6a7097ede9c7340c6a1bb1ff69d38","0x3ae961ab4c8364018ddf3dbec6d1905e535817da0011ea50a8b82647b41b3c37","0x3d380e354b647bca2175fdc67120052fc3a0116a3350c205d9f8c8079691882e","0x2f0ed669d2635fbf8544fbab025124c515c8e08fad4a59e595d323bd3cd14f73","0xbb057c917c996b283bd9d023b16b57ece75a03277a5fd1dff64652c58844251b","0x7256b85117520e97912554841973cb9454a1ea94fbb2ae5c2b6e2279d8885c3c","0xc8752d5025a1697bc1cead4f886b0af330ce092897abc863c9f53879d5acd6c3","0x74646e8a3cfd4d8a53843fa533c796fead770af07792a79d5396db316474b6d0","0x13cb62e761d56079440fedba8c9d3f6daff6837f8c449f1718260358126b0cc5","0x494f50311d1486b534335c81fbe75169733523ef363b279fe35dca4214013e57","0xee8144e0322f1a1b2d793868de7c816dff73476982fe58a5f25ea45672b50667","0xdbda3a7234881b5fa34006813969f093e0dca1c96da56cae66e216475bf0c917","0x28cbee8d8ad625ccae689e6108686dbff58ec6cee5d05cb667f0a552ee630ca0","0xdeff18cfbb3d16a4e4cdd6c3b016bfc23bf9318f7d99a4017d3ae7a977d4cb67","0x39bf5832ae11c28af999948b6f14a6bf6b6475b37de0c276628f2f12f27e06c1","0x9a9de4412c206cf72b201e1494aabd3a11c1bc8293c2ba34175ae6fb25108ddf","0xfcbf322cf431042243d53460ec625a05e61dcb30845d67517516b3368302256d","0x6a012da687045355db009136193f96dc8e9863f65e29a5577a3d438193ce13af","0x2b42d0ccb5079c7a79c81a5f09c879356d3423c03ad294f1672c30f2a5f30b65","0x85216097701c3e9a2cfcd1742b31ab5934b6e911568187f68d5134a1b0a8360a","0x4fec77ccb6b6639c207901613ddb784a479583200baf54a307715a9edd45ca44","0x6673e187392a9f2163918cb6cd338107c51f8fd05e45852790c023cc38089a65","0x3b4b8b45062f31a8c3ab64f5dac9468c0949d1ee5b67c7a45a89af071f84ef10","0xb8a0b4c2e4e8b4379c916fbf00ac283eb385ceaf5442d74f821b466abf146f58","0x5a9c62a6aa940e242d84841dc57eb59d5f2988fc9278326aaae33dfa7653fb9b","0x1e78ea2b98127d00a0920a028d3a11298ef9d6a82536befd84b72c5e3428b70f","0x56e43d1a8871f80f8a22f283f94d5e2f6154079ddcbe71014597361e1698545d","0x4271657f32739bca342ff23a4c347150a5e61f127ca44b30b04738715af67d39","0x67d1da46e80f4a5973edbbb03a6aa4f4adf3897ee5c58f4138f576eea12e0a03","0x138fcd5c2e9217816aedbb4fb7dc0742c089974095f69e483a9b44d26c731373","0xc12fcb10293e372639e01007b6863b1dc3207c7b1c22687bd4134fa871666380","0xabbb84017205275b09972d2ba2eb417aa1cf2b8d9ccb6cc54d623d8f0f6e52c7","0x48492aafba9eb5c0ede5f599ce95c6dc901c975dd0162a08359cf856475f5d2f","0xe3202eca552d2e34c763b2ca3e48103eaf7797f8ac396b413733fde2d8ea8de5","0x898f46f6eda6c55b09feb6e1c3011d0fe5c802da6814df73f652b0bb0637b9a3","0xce30b442ff866b890d76082e1233902b3ace2d15c36585726212818db87d738c","0x678633c731a28ce5c49a3d2c81004012a2316261a01af5cbcd961f5f33b91c71","0x94f90744f9a01a16b2c2237a3da403ded52baa0b926282d2af0dc13627c51972","0xa05c67e4f7ad31ccc7cfe341cc54102874fca40717c11da0f26fe3ce19345702","0x890b3be6ab227ef66fe16c92fda880421e1c90933ce168a73c6edd80953bf488","0x6082e3646d09e3988cebfb01262ffb6803dc22f147f7e68ef4784abacfee514d","0xd628611be8da1668efc534f7388654622e136b3910b8c42229dbe130a1468ea1","0xfe1e0810d4ef73499b2ea12ca403b688d68e22a108b67e3b5d1cc8233a957068","0x1ad13ee5a8553740aa1bcf450434c66f21be26cb6c0071c60a2b29aa9b9bd672","0x56e5d8f7c8d814f75afc3ae55c8beddc360f7245f2cb5ac8d13f82465ed306c9","0x0a61af1aeb4111e3cf5fb285d3a91b4b8aff8dabf10435e43e9ea78b1aab4867","0x32c521768d596793a2dc7ebba5a1b89a11969b724aba2abe2bc263c26f20b761","0xc715bfa83e8820d9a5a4872e83850133ee7a8102d35c5616825377af099a9047","0x0e635710e64e837b2a0172e0bac698797cc2dbda5a659602f84574a86643aa67","0x9099412b510d20c66e447d6936beab74d60190a956eac474d376a9a356d683b7","0xa1f4c335aa74873e759b4111d63f40cc1e044d781583955b20d6f58c1fb2cb15","0xcfb7c805e53892eec620c4b00ae2fb47adcd386f77668ce20397d639def05cf6","0x92e10fed99e008020411dfc70f638fbcfea7711e5443a19365bfd8548f8bb857","0x659d48718593bfd1be3378bbf90d88ebad363cb20d8ac9f5bbc9f06cf33db1a3","0x9b20fca8603c15a5f15cebae0c3101a2bb0793b9e435941c2c3a917ac2f80073","0xd6afe8addeffe865f326ad7f38e7c53a65da25e0caf96ae0a888f4ba1c836457","0x36125cc945e0ebca21528b9b2f64f86df3773f6a1340ae3bfba3e806cd7aa8d8","0xd10d92e6e3060a3d9c7def74bbc403fcad253f597b10328eb1587a1a52e20592","0x2bac13f3c2fd28805f65dacf2cf4a141534f1477df6b00176568dd64c2d047a3","0xc0ad350615b89032e64a1c6ba2fac16bab5a34e269d6cc5e6f860fff39c762b4","0xca0ff21f9e8eb40fb3b7668639819b9221d27b59f351209920f5eabc3775262c","0x6c3e7ac65571b3bc221a701f641c2606460bbbd12d7e6e996801281fc03d416d","0x7a204c8f60359ce7dd486e8cfff13d1af7bdb75c9499945823a7e2b42933374e","0xb448d458daddddbd9209f229296add8e1abaf8ff2844c223c50f93826d359e0c","0xed9f352441cf0f1df5a5eccb2de92957c45244b9807a50b7f59ffbfae3f57857","0xc55051be25f883f7a593fb04b096f36f128a8533a12ad822bb04eecaa42e81b4","0x581ef4f7617f49fa2ed3b1d686dc31dd7068b8fa90dc916728a86feed528b10e","0x9c66036a83d1b3f72564869fd9d37ffa98ee35ce8938784c6028694ac9955390","0xc715c77ef31c4d26203d45862381b8c1d461e7f399cc6e58f2829744812e7ef4","0xb35be8f3c654845684a6740f388e11a3ca8740575f0b0ded1deb4cd40e173fbd","0x826da7a3d367de621f24a885932699a18d889f3f8ae276c4e14f63c71de4d14d","0x018622ad20f2e898efcb5f335b51f5c3334c29bd148f750484f060d63a38f0b4","0xb02831f8002fb4b25742b858774487449e51f9faff5af3a1c2097311600aa173","0x0d734fdb6e78ad04c4bcda1753c0c00e500286f4605a9913419fed3a656e438f","0x0e11f81dc12fc297e096494207f67e41caf98e5d8a5d1c20328dcf7cf29d749c","0xc1ca4281c7f20abad2e85f8fdf53fa602dbf9a8544642dcd5c0a348481fe5f05","0x9c97a8ca6deeb61570c92aa1fe3587f2773308ae2727241751a05bd3d349297b","0x653322977520301c33716af2bff63acf49e4155b0ccd624d2e598c34cc9eea1a","0x2d541b538a6ee4eb40fb90aa173fe9e27cfb3b4e6aec289fa7073001d8254dd9","0x9a01187a42ae0048e38b27723c0217287e9a688dd83701f2a96ccf66513dc69a","0xc362fa5e34a8cd9b4f5cbd981ef6a56ea5f7feb3cbc183b8e895967b6ec4c670","0x49c9f669ad2e67a7b609573c9cd3ff710a504096ef1fbad93172f3b6fdc22b8b","0x185dbc9bbd685d5ba334f5edeeb9b7fb76b3b510b995c286b4259f21afe0bdeb","0xe76a44a94cb0047d879b40311ae0f84a9f15878ae42300eaedfa7e807cb04fab","0x315a995c0069ee864b27e022ff6e94d664b7dcd38ebf163f1e4a8db8cb1964c9","0xfb03b2a0ff60e0c9eb4672db87ecf63457ff2df085b7084c4503ef893bdffc52","0xe88e460bb73611c88cb25aab8c4c536a0a32b060f5996433b9441df957a31daf","0xd44fdf0c7c8f333667fe45b9c8364a928445d20d7460bb2cc7e13ccf995afc73","0x2638f8b964c12f901c8e264db991d2e174994c2c3856a8b3ffe61d98b9ec22e1","0x37d40729dab6b28b909919d29df78c7717f690498d525cee90c29950d9ddf203","0xbfd8ffbe0996374b99a4018e8cdb66836758be4c1d1cf8945e070a1348df3590","0x333f331d20458bb4de31cc6dac71e87abda05fcb7c8c7f8ced209d6874f8729f","0x996088094f1328935246a670469aac99c415c8da81a461c7aadbbe5aae5faafc","0x3d8ff831aa1b5db3d58735d9374699c7e817ca3206ee574f3873e661cff480ed","0x646cf4247fe07b8009dc00a0761469e70c88de530ae190df708be2267ecd5cb0","0x606d8f8c6570ed1a1a79f85492e5b929d0052b03cd225d3be9836b5aae9058f4","0x148825b15722383076cbfa9fe92fd7c918b7b4fc6efec2f6333c34b5ff84fe15","0xb18238d6979bf5b21d5d7f7dff198a36573d7762a0be985b8395b99dd9e3d4c7","0x893cfc4e0d46f851ba213a95744c9e75fac53431b283efa34dc435ff728b2128","0x73534b292b2a67022eab8810316b48aaac18606c5e015c70ecd967bf7814f09d","0x59952c508327c6dda5e4cdf0acf86bee12faaa07659b3ff7eb9f400abda9bf16","0xaf80e279a4162d13ab52be4562c77bafc74b2cb02f18d499c8875f850ab33647","0x4b82373934127f794d22089eecf72032308fcd4cfcccfc674b5672ce593ada35","0x25609dc0e0fed6fc0644d6564743fcc5c8e3ee25406a707ed06379de9d4c2d89","0xa8b9f7342acee54e9faf37d5a42d7b2c88f25b9b251af8da7d04e76bcfa7578f","0xf2e8f4ffe51d08c96579bffd7b5867384dd6722ecbf944ee28710696bcb65721","0x131a8cae697e843eba360413c219c52071efb6bd0f7c4633367ee569a46bcd47","0x50e0e39b362d119fad04e1d59e9f96821e7055714434d3963438f5c7ae49e00a","0x776d742615aeb3806e4f5c0de3eb42245f2d66e5cc94fe58d55e2a53121c4080","0x2f64de440451fde3c58a95ac7d81524b6b57fbbfcb06e894ef953aa4b5cc0fef","0xcbd62a717f0a54152c235fd17d76b36cf6beff692d4cb1fb69b702bde465d7fe","0x701c8c5b66c25dee3cdccbc5bc432cd58ec5b531aa2184a1612305a94d5cc594","0x8c673ead936180d041a435074d92cb4fa3d58277a5fe48580cb60b50a090fd79","0x2b26a8edc6a8c49ceef6d1c39d1cfbb130b67bd9483fd17b80b863fe19b1e513","0x53a2e522e3a1f19a119b980709abf4fc702aeaae952ac6cb5acbd368ad44cd31","0xd70e277e85e081d2930aac49c6c1acf9ccf19c53eed11b82bad7412690c2cf72","0xa2e7053a230ca84bca570b95e3aa83fd7d9f173daeccc7a322abd12efa04a49d","0xad36e643c72d44f5068803af84013f48cc935b0b90aa283084a1854ad2de92b7","0x663675352659e9468f568fea22c4c20ead718dc512331735fc1c158382c55a6d","0xf4946042228c0737ae23ba31af5fe63b2f5a93a5d5dd56b858016d5268769465","0x8a1ac910d4ac04f6b6d9b3182c4803fd05669d55b97ff84791cb75e8d00660e0","0x22bc2d4115fecc11dc48e8db107c10261f93dc08d714405632c95fb81fe6f6a7","0xbeb169076fad8293bc8cdcb2cb584bd3278eb8e7da5f7e5d26990477d4e500d3","0xec6475d881c8e54becef0e1bd00c9043cdb9941a70cc144a109a7b9a919d1606","0x2301cb2f9910b65db9a99f16a8388a162588e8095bc5557aed2b3ddf5997c0f7","0x3600814a838ca1efca237db2f1a8b98dc12ccae523abab466a8bef675491fea8","0xac2941c0efdab04f96ffbcf905a6e586562922bd73c24d8b28a4a5a19767d582","0xc09fd58c76cd7fe945f98615ca7943b811ff7ce6181a827dfa8e77d0d48c12a2","0x700a0897b8e8530c571f0f8030e45048fb919799f91ee495e0f73f6769a965b9","0x219279d4db87be2ad59abc8d7ad73004f7c2486bc609594200413e9d4afca72e","0xa42f744a8d89c693604382aa7fa6b17530b664114ab4fd4112540308c6f684ee","0x89936cfe9ff4264d43f652c063d595d591f3680814638a6894431e968a7fba7a","0x6aa6757493b4d2f67598203d5fc190c49ce6eb87fd8b0b790aec186ae2e4b4e2","0xed11fe6e613f818dfbc22ef842401e77a457c86346396b8e6500576ea7458eb1","0x1ab8d507a234753850e05e1268ba9aec3c97e57341c7bfe568111c2fd3afbea0","0x8bf1970cb910a8e6a101fd88646077f6196a1bda1fc97749bc3c9c826f4885b6","0xc3e86cd688bd44c301070d47588dbdfbc1b83ef5a076deef5ba9f45089774d35","0xa9bc560144cca238199ee017f88958b1138194d526ad3695d8d834277c6722f5","0xfe6fdeeac0b7ad54a53cad6a988731cbe2ab211bbf49821d35264e2fc62deea5","0x6acc02b6ada5aa700813c6f839bcaa1ca78a2d088ea11193e3cd7496536ff9c6","0x15dabf513c277be5ceb144f52be97a938a028ba81c7e72229660b332750b8f61","0x4a9c022b22f78b700506d1af98e5a23f68bcd5b2ee107f62db135aa43516f1c1","0xcab783ed96e59694f2f5adf48666920bb4c6eb5cd6e26033b8f1ef7a2c3c1beb","0x27ca4825cc4f981f4730126a5f3ec4b064da429d46d32421bc8565016e05f95e","0x51df75988d8f66af149f44858b74a96a7d4b7ce1918372f94baf078a60524931","0x050ecaef8bf3ecb4cd6a6d34bdd95d0eec6bf879baa52e035430020bba208f04","0xf19fc017685d00952bac857dd0620757edff00db988dc35872304ee647b07904","0x570a917ef2735730c3a6e1781df7146009ff767f50fb2497f548b374cb2918b7","0x2aff718875d54e9f6172b2a784019bed8b00ccb02ec2b671b80af2f637ebe5b1","0xf32d037ac265f5fc3009020daef3d55ce45acdb110e89545cd85392c1b943a2c","0xe64bea4f5fc7272dbe9754629d4662f35ce544c118ab1072c3dcd576c2bb107d","0x61b8847acf442e452c889e764439ac64f37dab16fe52fd8f63b1d41fbef95057","0x99c1b2b08cc7cb88c132f06e2b601d720dabdef449d97c3f237f756cf3e4cd3e","0xe8584243d7e7872d172ad43c12769d124463889b271699d9d98ebf68cb07d7c5","0x8e3e3478c49e3ed0552e90f986f01f5b659ece694bccc8260f91a99adf503adb","0xbf9d498abee0fbb45e4ab9c9ef5b3c5bde705e5cd7010b31ab72a3b33bc26d1e","0x04b0a149e33dd90fac0b1e9d29c0f7e70d3c09a8492742a8b33a8d063b021553","0x16e4bb8856b434b5e50dfe2b699300c9c0d30d3ef40650e32a137e0c280b10e4","0x3ec93e37503d9b9abd4814913d3809dab9e7d914a627866b0c1972f400a580fb","0x1e4c5b750baa30962895b061d19c6c63f3bdb7d0dbc131947a4448c187141291","0x38ac11498194eedcf397aba10f1b7a6e4f79048108c079b3698b284348f931e9","0x72337de21b4cabae7a45c5559b2dbcba1530a775d4e6c70c5d7dc3ae360ccbbe","0x3f30ffb0c94bfb674a3c0f0761f119a7704d72efb07675b296e268fa673f2ea3","0x3d7bdde6d6fe785b9b19d506990cdb8348e88961df40e8095ebeaff01546acb1","0x503cfc268a3ed066951373e45d401ae4f73ac118ae5738746dc03d0b4571e09a","0x2001d5e00a5c78d105ba9e789c7cdaa2e3dfaac9740d7de6a1f8573f3e7cc035","0xfa32b559de18952af9465e623d3d0e670bdcdfcd8c34702b538ed9230615f723","0xf8879266ed024a03179296509f759755fe0df2bba825da328f2119749c4df364","0x057d2ada9b033c70100a5e897ca0ba69ca4e1049dd662529596443b52238afba","0xa6036d1299731bb4a97f1fd2ab9eb6b37f8094e10b0958eb591b3371253a5f49","0x04b977a5df0b1adfcf7e04d5ca69d0bebc19b812b17dc6c1b2b6cddf3d446ca9","0x52caf50de89f4455683abb159e3a2256285fe7f7f49a8dd74f5ee02b915eab67","0x3810f9bce373afa85167bb661721cf3263bff423443bf78f8639714a93c9e159","0xbe250e1647de6e85878627d423aea18f0c9bec678c58c88e2e87cce8ca265289"],"txCounts":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,11,0,1,0,1,0,2,0,0,0,0,0,0,0,0,2,1,0,1,0,0,1,2,1,10,10,5,1,0,0,6,6,0,6,0,6,0,1,9,3,0,0,5,0,0,0,0,0,0,0,1,0,0,3,1,0,1,0,3,4,0,0,0,0,3,0,13,3,0,0,3,6,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,0,0,3,1,1,2,0,1,7,2,9,0,0,0,3,0,2,3,2,0,1,1,2,3,1,0,12,2,9,9,5,3,12,12,6,6,0,6,19,17,11,18,0,0,7,0,0,3,4,12,0,5,8,6,2,0,0,2,3,13,3,4,6,2,12,2,2,8,3,6,14,5,12,9,3,0,1,1,5,6,1,4,0,4,1,1,2,0,0,4,1,4,5,1,9,3,9,3,0,1,11,10,1,0,0,0,0,2,1,1,0,0,0,1,6,5,6,0,3,1,1,13,6,7,6,4,7,4,3,2,31,2,0,2,5,0,6,39,0,0,0,0,0,0,2,0,0,0,1,4,2,3,6,29,7,2,3,1,0,5,0,1,0,0,0,0,13,0,0,1,0,1,15,6,1,1,2,0,0,5,3,1,0,0,1,0,1,1,0,2,4,0,1,0,1,0,6,0,1,0,2,4,4,2,1,1,4,0,0,0,6,1,1,1,5,1,0,4,2,3,2,2,1,2,7,1,3,2,5,4,6,2,0,3,4,2,0,1,3,3,4,9,0,1,2,2,2,0,5,1,9,1,2,6,4,4,0,0,0,2,0,3,4,0,1,9,1,3,1,0,20,4,9,1,1,4,2,1,1,0,1,1,0,0,0,16,0,0,0,3,1,0,0,1,1,1,3,0,0,0,0,5,5,3,4,4,2,3,7,3,4,5,0,2,1,0,1,0,3,5,1,1,4,2,2,2,4,3,0,3,3,0,5,0,3,0,3,3,5,0,1,2,0,0,0,2,1,7,22,3,0,5,1,1,3,0,0,0,3,1,2,7,1,4,2,0,1,0,2,0,4,4,7,5,4,5,3,5,2,5,6,2,2,3,8,6,8,14,4,2,7,4,1,4,10,8,9,1,7,12,74,0,2,3,3,1,0,9,4,11,9,8,4,3,7,9,9,9,15,10,20,11,22,15,34,58,28,28,4,49,8,19,68,91,56,22,424,25,106,36,30,15,29,34,15,29,22,24,35,13,21,34,12,37,20,64,39,22,26,13,41,21,25,17,19,15,8,24,10,40,22,33,21,24,29,19,21,12,13,21,33,25,14,17,17,21,12,16,23,18,15,18,19,0,15,26,41,25,43,42,47,21,0,32,15,39,41,66,32,69,83,62,39,28,12,39,16,31,73,13,27,19,38,70,36,72,40,28,98,10,22,17,67,13,23,113,17,29,17,16,23,30,30,22,22,17,43,72,42,82,0,97,133,62,88,33,118,72,113,87,298,109,127,30,39,55,72,94,44,54,75,0,54,52,113,87,65,98,37,49,42,54,79,61,45,42,102,81,96,59,44,70,43,0,71,94,35,101,112,30,40,29,30,80,101,25,64,39,26,55,62,68,32,64,90,44,43,52,65,27,47,0,26,101,0,51,55,43,65,45,25,60,46,40,48,28,59,65,49,45,25,102,35,71,40,42,97,58,0,0,49,51,59,76,55,56,59,68,81,44,0,0,71,89,66,89,144,218,0,52,43,84,36,53,41,82,47,31,0,69,91,64,64,103,34,61,97,58,43,52,89,31,80,31,30,138,239,57,10,361,53,60,0,56,79,91,0,40,21,86,115,72,25,59,64,67,83,115,59,37,91,55,43,164,37,76,47,70,28,28,0,68,71,133,68,63,78,61,86,38,34,72,68,41,79,38,79,90,66,62,50,74,36,141,40,0,85,38,79,34,33,58,62,0,77,84,50,53,38,49,92,58,67,102,74,53,173,115,77,0,91,27,53,52,36,103,207,112,163,36,69,50,63,18,59,59,57,0,64,77,87,116,32,94,79,43,66,49,30,75,77,61,78,48,54,92,44,261,116,52,107,83,84,88,73,46,50,101,145,83,102,72,190,57,70,109,95,63,104,62,57,37,88,73,80,67,66,44,68,23,61,27,54,39,71,68,195,126,129,69,48,41,80,64,71,62,50,68,80,155,117,110,58,92,118,162,127,91,114,106,74,109,114,92,144,122,111,91,117,107,122,90,88,130,89,83,111,81,79,79,108,76,87,102,51,126,169,91,129,89,83,110,120,127,88,154,122,69,77,70,67,361,166,67,60,92,114,78,99,233,105,73,79,41,121,185,130,244,107,75,45,66,148,119,81,117,95,108,83,129,188,111,0,82,108,134,152,303,116,131,161,146,104,134,63,103,84,109,139,147,109,101,92,120,124,254,54,114,115,141,98,94,110,158,134,252,88,61,57,79,171,118,66,118,117,52,180,0,88,58,61,46,73,105,100,84,70,72,119,76,91,55,113,53,141,137,100,80,117,82,133,96,116,103,83,21,116,77,173,66,89,111,81,152,88,123,160,74,107,55,82,132,261,99,113,125,63,131,84,86,74,103,91,78,72,71,83,81,132,160,58,50,39,59,82,116,83,62,68,88,90,92,56,89,45,60,53,113,139,133,88,109,100,95,87,29,93,13,101,0,68,73,49,98,168,80,69,146,89,95,122,87,175,82,125,82,67,90,107,160,78,138,151,100,110,89,4,63,212,84,85,127,97,77,22,86,79,79,108,164,112,97,84,96,28,176,136,104,125,96,0,0,105,81,140,143,66,108,80,95,120,64,145,118,156,71,111,81,177,190,104,92,77,102,106,60,127,123,116,66,94,117,159,56,196,149,94,132,131,107,88,58,90,55,116,70,101,95,70,108,111,52,80,81,109,69,78,64,83,91,112,96,98,70,91,111,82,155,90,104,139,114,144,104,72,73,104,176,66,48,87,79,108,101,115,88,114,55,85,93,92,145,39,68,123,86,156,52,123,118,143,88,388,91,76,104,85,57,86,75,75,61,78,117,87,105,58,98,56,84,118,58,109,94,84,79,73,80,119,80,81,88,128,197,60,72,73,51,76,66,98,72,79,81,91,96,105,164,55,38,86,95,104,70,77,77,66,70,150,74,109,160,72,114,61,34,125,67,80,47,48,104,155,52,71,131,57,108,58,107,86,224,122,157,72,151,61,316,107,111,17,126,128,117,130,130,155,79,125,74,445,341,82,81,163,72,73,123,119,179,54,66,51,94,108,68,69,45,84,76,47,46,61,70,57,51,59,53,20,51,88,107,106,82,68,79,54,200,149,51,76,69,42,93,81,93,82,56,58,67,59,66,90,75,68,93,65,89,54,72,65,73,88,112,77,44,146,47,78,53,63,154,45,81,88,72,70,64,89,68,191,66,67,78,70,88,83,59,86,92,44,66,51,72,117,63,61,73,96,68,122,73,620,155,744,236,36,107,338,587,190,550,397,620,273,492,228,264,236,214,525,284,107,221,230,318,327,179,255,431,66,81,95,92,72,125,116,100,72,159,138,73,101,286,111,113,108,92,118,104,1056,160,149,92,111,65,144,117,67,82,76,90,173,70,90,82,88,97,118,151,96,163,134,62,62,65,72,82,93,64,91,122,220,153,56,171,98,165,86,210,120,112,119,96,126,85,109,58,214,224,241,111,132,161,84,123,91,109,82,177,180,151,179,154,166,145,159,19,114,107,168,50,69,119,119,158,213,145,98,120,73,108,71,89,111,221,152,164,14,140,127,120,71,112,85,111,133,116,93,70,131,138,137,160,73,113,68,109,120,179,149,184,171,217,139,109,158,99,156,224,328,132,104,195],"txHashIndex":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,5,5,2,0,0,0,3,3,0,3,0,3,0,0,4,1,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,2,0,0,0,0,1,0,6,1,0,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,3,1,4,0,0,0,1,0,1,1,1,0,0,0,1,1,0,0,6,1,4,4,2,1,6,6,3,3,0,3,9,8,5,9,0,0,3,0,0,1,2,6,0,2,4,3,1,0,0,1,1,6,1,2,3,1,6,1,1,4,1,3,7,2,6,4,1,0,0,0,2,3,0,2,0,2,0,0,1,0,0,2,0,2,2,0,4,1,4,1,0,0,5,5,0,0,0,0,0,1,0,0,0,0,0,0,3,2,3,0,1,0,0,6,3,3,3,2,3,2,1,1,15,1,0,1,2,0,3,19,0,0,0,0,0,0,1,0,0,0,0,2,1,1,3,14,3,1,1,0,0,2,0,0,0,0,0,0,6,0,0,0,0,0,7,3,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,3,0,0,0,1,2,2,1,0,0,2,0,0,0,3,0,0,0,2,0,0,2,1,1,1,1,0,1,3,0,1,1,2,2,3,1,0,1,2,1,0,0,1,1,2,4,0,0,1,1,1,0,2,0,4,0,1,3,2,2,0,0,0,1,0,1,2,0,0,4,0,1,0,0,10,2,4,0,0,2,1,0,0,0,0,0,0,0,0,8,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,2,2,1,2,2,1,1,3,1,2,2,0,1,0,0,0,0,1,2,0,0,2,1,1,1,2,1,0,1,1,0,2,0,1,0,1,1,2,0,0,1,0,0,0,1,0,3,11,1,0,2,0,0,1,0,0,0,1,0,1,3,0,2,1,0,0,0,1,0,2,2,3,2,2,2,1,2,1,2,3,1,1,1,4,3,4,7,2,1,3,2,0,2,5,4,4,0,3,6,37,0,1,1,1,0,0,4,2,5,4,4,2,1,3,4,4,4,7,5,10,5,11,7,17,29,14,14,2,24,4,9,34,45,28,11,212,12,53,18,15,7,14,17,7,14,11,12,17,6,10,17,6,18,10,32,19,11,13,6,20,10,12,8,9,7,4,12,5,20,11,16,10,12,14,9,10,6,6,10,16,12,7,8,8,10,6,8,11,9,7,9,9,0,7,13,20,12,21,21,23,10,0,16,7,19,20,33,16,34,41,31,19,14,6,19,8,15,36,6,13,9,19,35,18,36,20,14,49,5,11,8,33,6,11,56,8,14,8,8,11,15,15,11,11,8,21,36,21,41,0,48,66,31,44,16,59,36,56,43,149,54,63,15,19,27,36,47,22,27,37,0,27,26,56,43,32,49,18,24,21,27,39,30,22,21,51,40,48,29,22,35,21,0,35,47,17,50,56,15,20,14,15,40,50,12,32,19,13,27,31,34,16,32,45,22,21,26,32,13,23,0,13,50,0,25,27,21,32,22,12,30,23,20,24,14,29,32,24,22,12,51,17,35,20,21,48,29,0,0,24,25,29,38,27,28,29,34,40,22,0,0,35,44,33,44,72,109,0,26,21,42,18,26,20,41,23,15,0,34,45,32,32,51,17,30,48,29,21,26,44,15,40,15,15,69,119,28,5,180,26,30,0,28,39,45,0,20,10,43,57,36,12,29,32,33,41,57,29,18,45,27,21,82,18,38,23,35,14,14,0,34,35,66,34,31,39,30,43,19,17,36,34,20,39,19,39,45,33,31,25,37,18,70,20,0,42,19,39,17,16,29,31,0,38,42,25,26,19,24,46,29,33,51,37,26,86,57,38,0,45,13,26,26,18,51,103,56,81,18,34,25,31,9,29,29,28,0,32,38,43,58,16,47,39,21,33,24,15,37,38,30,39,24,27,46,22,130,58,26,53,41,42,44,36,23,25,50,72,41,51,36,95,28,35,54,47,31,52,31,28,18,44,36,40,33,33,22,34,11,30,13,27,19,35,34,97,63,64,34,24,20,40,32,35,31,25,34,40,77,58,55,29,46,59,81,63,45,57,53,37,54,57,46,72,61,55,45,58,53,61,45,44,65,44,41,55,40,39,39,54,38,43,51,25,63,84,45,64,44,41,55,60,63,44,77,61,34,38,35,33,180,83,33,30,46,57,39,49,116,52,36,39,20,60,92,65,122,53,37,22,33,74,59,40,58,47,54,41,64,94,55,0,41,54,67,76,151,58,65,80,73,52,67,31,51,42,54,69,73,54,50,46,60,62,127,27,57,57,70,49,47,55,79,67,126,44,30,28,39,85,59,33,59,58,26,90,0,44,29,30,23,36,52,50,42,35,36,59,38,45,27,56,26,70,68,50,40,58,41,66,48,58,51,41,10,58,38,86,33,44,55,40,76,44,61,80,37,53,27,41,66,130,49,56,62,31,65,42,43,37,51,45,39,36,35,41,40,66,80,29,25,19,29,41,58,41,31,34,44,45,46,28,44,22,30,26,56,69,66,44,54,50,47,43,14,46,6,50,0,34,36,24,49,84,40,34,73,44,47,61,43,87,41,62,41,33,45,53,80,39,69,75,50,55,44,2,31,106,42,42,63,48,38,11,43,39,39,54,82,56,48,42,48,14,88,68,52,62,48,0,0,52,40,70,71,33,54,40,47,60,32,72,59,78,35,55,40,88,95,52,46,38,51,53,30,63,61,58,33,47,58,79,28,98,74,47,66,65,53,44,29,45,27,58,35,50,47,35,54,55,26,40,40,54,34,39,32,41,45,56,48,49,35,45,55,41,77,45,52,69,57,72,52,36,36,52,88,33,24,43,39,54,50,57,44,57,27,42,46,46,72,19,34,61,43,78,26,61,59,71,44,194,45,38,52,42,28,43,37,37,30,39,58,43,52,29,49,28,42,59,29,54,47,42,39,36,40,59,40,40,44,64,98,30,36,36,25,38,33,49,36,39,40,45,48,52,82,27,19,43,47,52,35,38,38,33,35,75,37,54,80,36,57,30,17,62,33,40,23,24,52,77,26,35,65,28,54,29,53,43,112,61,78,36,75,30,158,53,55,8,63,64,58,65,65,77,39,62,37,222,170,41,40,81,36,36,61,59,89,27,33,25,47,54,34,34,22,42,38,23,23,30,35,28,25,29,26,10,25,44,53,53,41,34,39,27,100,74,25,38,34,21,46,40,46,41,28,29,33,29,33,45,37,34,46,32,44,27,36,32,36,44,56,38,22,73,23,39,26,31,77,22,40,44,36,35,32,44,34,95,33,33,39,35,44,41,29,43,46,22,33,25,36,58,31,30,36,48,34,61,36,310,77,372,118,18,53,169,293,95,275,198,310,136,246,114,132,118,107,262,142,53,110,115,159,163,89,127,215,33,40,47,46,36,62,58,50,36,79,69,36,50,143,55,56,54,46,59,52,528,80,74,46,55,32,72,58,33,41,38,45,86,35,45,41,44,48,59,75,48,81,67,31,31,32,36,41,46,32,45,61,110,76,28,85,49,82,43,105,60,56,59,48,63,42,54,29,107,112,120,55,66,80,42,61,45,54,41,88,90,75,89,77,83,72,79,9,57,53,84,25,34,59,59,79,106,72,49,60,36,54,35,44,55,110,76,82,7,70,63,60,35,56,42,55,66,58,46,35,65,69,68,80,36,56,34,54,60,89,74,92,85,108,69,54,79,49,78,112,164,66,52,97],"txHashes":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"0xde30b088bb933554adca87ae9e7032e2ab7eaab1f591de4a12ee936c5939dad9",null,null,null,null,null,"0x2744b7d749cd94335ae5106e3ee2c987763443cfeca9a84b93abf1f4cc655cdd",null,null,null,"0x02938762fc30145268efb733110cc787d741471cca8ee5e8355fee853ef62d46",null,null,null,"0xc2f22dec73e3ef74ea82981e14a1ad09480fc0bc094ee5e9f9fdabb28e7d35ff",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"0x6f4032b030ecd98df08861345f19ad2c705f2c53229b36481621e57f70107a63",null,"0x2cc1d9190206f5b87d9f12d8d2ed05bcdbfe13dc7ffa3a0360f0a625f93d4ef8",null,null,null,"0x2fb86402249c84baa19141af3e059f2642fea96c7d91bc895dc318e0c7870d56",null,"0x3fe61b03b2a16a833c8cc69bd69eefd8ab68088235276eaf27926c1d6db3be4c",null,"0x008436ced114d691a47f10c7f5edcbbc455bfc29d348e689a3352c2a032f3e09",null,"0xbf98a5e0b303dfd4d26d095cb19e37f94844a1ae675dae9cbdc9f332e13eb955",null,"0xcb036a26b51bdde7b6e957afdcddcee7d3991d2719cb155b66b31a4068911997",null,null,null,null,null,null,null,null,"0xa672cb0b8c3c91d900441910f38b70418ed8e7a70f9feeb4f505fd407cef1de0","0x06ce359ce232aa3897d4277eacf8a4babb5876c7ab4fa83e056bfcb47b1829d0",null,"0x2425809eff2760946ed1e85a780be25cadd0eb9d17a80329144b47614155f8ee",null,null,"0xdb7b4bf24984b8908fe136ddb9ff0bcaf70409033bf5df439e4d11e9c1fe305f","0x5e1a222ddc918a84ddba43b4c0238c4eeca552b0b96abf9290a9451eda620d55","0x96d6b9d2e299d633854434bdd3d0e56c6b709a68531a99e73238e853ce63cbc6","0x23a3e7069a6a72decdd6976b6523c1a823dfc0397e8a2aa4e85a573f2be5de62","0x71ec4f8c69350eedcd10fa089b58a03e884e2445530d2f380c78f03ab9ef6d00","0x9fcbd97ddc6700b3358eda94e442641f19aac67bdb4a32de0bc4f6f03129372d","0xf4639b3fb48c71f96ea5df820651b41d6f06559c660e39fffc8de0ea98775064",null,null,"0xb8531cdec0cb8da6f11230a210dedacb9013a3cf04329a95365745f7dc56ddf1","0xbdcbeed389f6ef6561a668315cf374ee3da56ce2ac4d55e95a8f6339fc8c0171",null,"0x6c31f583dcfb358e66fb3a5118cc0fbf7ac0ca0b1e0a5780962ab4bd889cbad6",null,"0x0c52362dfbd7059e3b93078b9ed363ec20cdecb41be22f392c699217bd0ee5c0",null,"0x171ab39099645d285bcd9f920d9844bffac18e0a963383342cd2b48f51d5bc54","0xf7ba684f6a3a92ac7a1bf58723dc57f7118c65090986df78c880bc45d0e3b63a","0xf6e8eaf6e7d9072b5c9f36fee5b2d1624f193ae2b00c73888bb413db523f5c79",null,null,"0xb0c1aa925ad9d3af99b51fc09d52ac9458ad1903f38291c561154c801bc7148d",null,null,null,null,null,null,null,"0xd3c79d05824ba0927f458688c1b405d012e62f29392d0ae5cc9416b78a40e08e",null,null,"0x2a6e1bd3d516e507ed22fb50af74c9dfbc85a6cd94087cd90ef934c00f5476a9","0x0087d345c8d19af0f9b4e696b2c435a9284d5454f828630eea365d0ce60ff21a",null,"0x597fba081f985b806fa98600940e1174776464408b05b6b06a79e5e00d16c663",null,"0x0587eb1a0e935d7fe0f2b640944e102bb98cf9ddd84f557b67a094f23bb31b28","0x3b3377e166ef24616657b6a543bcaf740729b488627fa7dacfb594d74c0c8b45",null,null,null,null,"0x59262c7c5a8c956d8346d8f71445b59b74f09c6650d27c6d83567b7dae3d3f01",null,"0x55d88fa43d80997937110f5b011195e2f79456480b2f2c4f66b98aa2826e61b0","0x462b8494e24b689af5d90e2d656d2a5e26caac1af58220ee5afa758e23fe841d",null,null,"0x1f9941cd97133342a1e89dc52700fd35c8c9820610c57ef2c354f80f5bcfc8d5","0x90ddfebd08e5b0a12b56f643247fd2a6805fb63725b270d2a5c58dd3f2c891f6","0xe13938aeda0c029f83472b1297148653868ab40f0b29ef4763994d37f1da3844",null,null,null,"0x8c9cf938453de5b3579a281bbf4d94bd7595fc88a75d9506e95b7be0aaaee698",null,"0xe93cf4923a552ea75b5333a046889d49f498c53ae7e255829d4de0a4b86b43a8",null,null,null,null,null,null,null,null,"0x52e6553306efe2cf031d703bdc6bfb7dbfdafd39f785619578da1a3eb1281ce8",null,null,null,"0x8140a0c5d28da90315d5bdbae5525acde32c8806850edc21357f2253c8f0b762","0xe30e54cd3bd99874bd16ed300960831bf22d95aa882c22e9aa82b9b50c801631","0x508fe0dad4524ad719402fbbbad3bd6c592cc683a95b329b0f3397cae718f8eb","0x739db8837907972fbdbd5b7b333650c9821ad8e6761bc94e56121b10bb309b94",null,"0xef47541570bcae2508a4121083ceb8ff5d903c49a69d6e2f7b8131c5ed065eb9","0x3635f4310c91d4fdbbfc96d7042bbad7f9d50c13d01caa2d37ff4927a7873631","0xef389a0ab2be054fb56a2747e57742b14995cd94153ec8203bafaa13baa013a7","0x75d7a4122136d8e18e36406ca5141e07f0220bbcd403e9af4523084992a6bf82",null,null,null,"0x8ff645c4b1e101f9f30a2f1e858563db0ea881a834b13e9965081fe7a245c33b",null,"0xfee45f2ca767d52c46d82768c08b1a4412723147623a84de1f64f98a54c726a6","0x054893f6061bcb44485267390f8e847b7380ad6a17f17583ee5171fbd873c430","0x9b1ef1a1c9bf53cd83f227948a1892222f3d41100709d56416991c79d7f2a0ea",null,"0x8444d8bd1d66bd77f50e8275d60855ea28fb9111f14c39bf81a8a73ec5c06c34","0x170a8712f7d1ae1f24dd768f712ef641f9324540fa10d633484f673f4a9bea4d","0xa28e80a7168eec7be08f764f513a97adf845ed9fe3ee975573f8369ae7d267f1","0xfdc4e0acacb3b0e837dca7ffa618ee71f7f8df3a45c62399be48c276827a78a8","0xf50e91f202fb1843f2ea683a03356509f00186e05c083d1f3a5f82b34415a53e",null,"0x7f64b9b76e90e20889c19e728349828fd47004648052c347e30196ec4b50375b","0xe6fa4f93b2b13152d4c8e28bead558fbd853063f74a9ccfb7490cd004dcfa3ab","0x494cec7a70b910374710b569c51fa7fd63bd6022b43151e75da3bc92de488477","0xfe76b210f1af756df5ab89f42dd910f08cacc479b7f96e07c870c3cf9ed52ce2","0x1409ee8abf37b286c26381da32669e1ed02be0ea9dd9c9c27dd1f8ed74c54952","0xf25b0da11c6abb1bf486d0fa91ba01b6adedff65c95909c667de5846a7bad607","0xd03204eb11247e3e03bcdc6d783be8ac575e75329d516924b0363baf7077cb69","0x227cbd66dfd15314480e7db1fe1fdc8c3726da92afb1505aa1b43b71b48751af","0x109a260146baa4b69e3297d61faae0e10f3d3d2a579803ae87de19ebabe48211","0x5c8241a60f61d143541ad8cfa7550baea70d8d0989a9ccd959ca302cfd5dbc04",null,"0xd96ebc2317fcd274519a79e70485881443b067f2741e23d2822ff0d7b19537f0","0x5191140f66e7ce8f13edf89fc3f176cd0472d63364d628f4b7891be781fc0e5c","0x9d858eb89920ca369057b3ff03adb413840690d7b84c97dbae416b75a733e376","0xbe2973240bf13cd339900f0c7cc75a77f099cd25170706050ec81aa404f05a95","0x2556cf1ee66167e68c5af508786eea1a8abb68bdfca98d7a282ffd0df86c5a1b",null,null,"0x10e9456497768c65b02528623ec181d4feb3f5a0695af0e5c68f537b6b4f5262",null,null,"0x84dd00831d8284bd6359b2f2730a2029a736a88e93b28d973eb4bcf1e518091f","0x23f6dde1cb4ff7c5a5f8465c1f5419da027d39409e2da2690fa2a71390f59051","0x4d81a95117133eb50d62d155bfc68ac808605b044e39f633c4ffcc6e2f70bd97",null,"0x373a6bd1c821df070299f65816cc10a0a8dca3b8547e93cca48a31a1e72f7a2b","0x0161e703f56cfea22643ec2582faa5f6e68a637c8bb22164bbdbabcd34608159","0x36d8ecac5323ff0e1db3a8104d98517e886a977fb5dc4ac21cb81a8fe8bb3b50","0xf6e7ebcf59f58d9c985af385f33ece1b37fc4147029f7ab8b08829e7ac873f07",null,null,"0x171c0962dc8d4291e357e996b9efd31ca469aba5242c60025d623c55c286847f","0x538c9bbe4d4f77bcad9a17287112416584f20b187d43c676e57f967db52bec24","0x6c494d06b9f0c94cea3e9fe8a015c423beb4d18b0078cba5fc1d5805114721b1","0xf5a057fdbaa5a6d935d1a112a43d8f66714d74740d832fa0f7237104d363fbc0","0x4d18a9a634b2243e54f60cf0a9e82f0d3d51878bcb6834b6a7a14e5ed0594639","0x02b65390d7f2dc15a25173f6a50f5078005046660c0243fb3a00e05f724cca55","0x0b1f2e5f3e7f61baa4c20e110fff220da54b86def498cc925b0dfb4e0d776cab","0x44dc3249edb33307a7f3a88beb231995d46cb48331fd496304a21fc170f8c73d","0xc637815c7c97b99dfc19d807d8b77767cedbf2d1069c63343b0169241c314749","0x4d610e1eaf7d5f6d27e3381a14753fdcfb2d9946439067779dc131ef4a0d3e7b","0x701250b9b452384487d56921e2ef6f1233f73701e66ac25c813ad4dae37fb11e","0xa802e0674386639daa90c578d195aee4a271296ad95b86874b7a15b059161b40","0xa02d974de7daa132e58a5d30b40d8031bea1354082a898973728b659747f37e4","0x64b8b3c3b7f51ee24e176f87a5a82404e2e0d2c3c2a4c9416636508768f5661f","0x304fd83d58ebdf17db6f185c65d55ccc11b9079b2dafcff712d8eb7f4b16631b","0xa50dba9aa6e0932c833cf8065c90733a96a190c96dfef869a3612c7ebfcd37dc","0x91114c35f69c00bc075b43ea1643e757fddb6b367352fd4f374b842c7d7cbe86","0x496a61cfeee0de4d50c4be7bcbca4f7aa68d5acc1b523ac13bcc7a530095e5c9",null,"0xaa888ff7d54619794e9d9c5c9761d0d1040d10cb338d70eb1c781be8e8667c2b","0x0baa82b94e163f097789cc54509564f535ab5b1ba77dbff27000d6fc5681789b","0x6925aca058984946a5b2e2e8c4b7f9d68197f67c0b41d1098987cf9a83cf3dac","0xacbfeb29a2067ba50127e90fcb3b8c75b1ec4859ae3ac984d2513d064148976d","0xf6e8406dfd41d1f2415a60bb0c9d6e721e894edd507cced6f33fea80c7a4a156","0x3165a1468d346e3bdb8b5042b18dd3afc5359c956ba1ed1b6544447506e8a420",null,"0x9c895914daac05854c3628215ede6db1c0a2208c8d7990a718990361d44748c0","0xf81be0427adf4725d061c989f8795cb21d7cbfd5c46971805049a706b0d763c2","0x1dd3b2c261cce1d877c996cadffc49deb4131ef06dc93457b23792fab64ca6c6","0xbc48db3876ad3643b3c39f9383be13a1327380f4ea915e360353bae3c1f6d674",null,null,"0x17cada85a47e93d3def82b73c0d0b96ce008e54a5e9960914b2c51dbf134b45f","0x03e7a0544d81f31ba07401a29ed125e883044e45f57f0b84672e16c186f658c6","0x706a8a6eb6b35b33c770b57b2415258872ef330fc2b402c1e082cce7a63a6b33","0x06e91c18fe7223d9fe284ac37093b64e03631aa5f2becc3b30950b12000a71b9","0x31a0df7d8737f184640065aa002038153d7c7ec976764cc5b3cd8aa84977ee92","0x1886ffa60e269e804dbf7194c5d1c65411899d71e65f2fb7f416d2390eb7522b","0xcaec4da2a7967a97667f553e48df7925a155078623797ef963a73c0eddf8de1c","0xa353ad81576f8f7fbcb216214b0841099c15260ed8522c957b42e829d9fa09a6","0xdc337d24e58736172629e765fcc70d1ced4eed13e4c610788ab9646f73a46c60",null,"0x847206c92cfd7f1e24b02beec83214414e887a4e7b3dc471763243b0b047ef60","0x9a0d10b6900c18195344a448f1c337689e05638ae874c0f32fa9c72b14983d15","0x054dffc129a9cadd292bcfec3d16cefe24c6d5737fabb6106ce09c41006a8a99","0xf75220a27d9d072ab3463ec9c04961e6f183f080722dcf040accfcc4f211ae9b",null,null,null,null,"0x4dbde3684648cbdd9ade6cd91e42d4396d11f625fd39da14f4c3221609d127bd","0x254aadd82b64313309133bf23f6f5ecfae8c0db5d902aad2a26f04d3e979f862","0x9b707d63cdec358a293ceba39c0cca9eec359f2e2ea8a6a538efd6a1d83529a3",null,null,null,"0x9f8e0510e4d61341be6ff95db677d2034acd27ff40de4dd246c30d724b9513a5","0x9a74059a2bfc5969e3bedcd4f108440b99426ec12256bd1ae35d7a2a09838a70","0xa337bde20e26034c4b63e0d8893de4a7751dacce34ae0c475f5b2849c1d186b8","0x64c70ec8a01a6a1cfcff7dd02a5c794bae6d9741ca20a00d6e028982c5ba7ee9",null,"0x2142478ef53a919536f849163f8e3bb7c1efdecc105b42337507e1ddba5d54be","0x441696ee1f40763bc25239427fd9b31123aa9ac9d7aca995f8a2c9868131de36","0x9a5a9fb4ad399dbc7eef0558e73f2aa6f2ba0b74449e174d15e6e428dbb09532","0xdb9e6b1a7fff449dd37b37037dd2731edc85370c8df40c85fcfc09687fc80f55","0xc474d7732436c703b178081eae3a807bcde9025336f6cc2663a3c6cc4fae319b","0xa73485da13ca6436a91c0f1df4fd104b4a2077f3e5a68ae33854b97cb6f9ac3e","0x5912b67aa6ca6518a1a5fcae1e0852cb4800e46160fb35815fae58e415ee3a3e","0xd9562cda6c29976bde4e047506e243002c883319e109ccba2e9422763142f08a","0x7cd345046ce15a9c6e4937fd3306db5b88efc89fce7c3602d07cdb73dde8cf3b","0x8ddd7bde87d54d0e3e231bcaeed4072a0a984f7f689d2b6314fde370f7328081","0xed8e7117d84593f71313caf32c7c46849ac148946d23a9b612b202f3e81b8a47","0x1dde42476b6872737c8ce60ac445950306b5b81692b953c580917980cece64e7","0xebef5e882daf03f6b287e836237448a040d4c781236555ccc7909d8dc2d49c9a","0x64a3756faa824a7f2746bad1a5324aef4b7bdef1cf0baf45bff98bfd5443a0c8",null,"0xe13fb729a6c143151f58fe8bb2ae02313f0ecdd0f3c81d134e07f41b74b91b12","0xe492159b8005914f011618106d85d9deab9cd45a485dfb1211d64b61a0d1caa5",null,"0x8521732bc712e5a88bd1bd92d7dc7bd4649d2032445be123284ab280b8928976","0x4b6f4d246a4c48ce1bb7d82b15cf0c5020abdbb983e5c373360261fd70d93bb4",null,null,null,null,null,null,"0xdb4106bc4a68ab6e7ea7ad9c92dc94c52e4ca3328f5d3722dd1e9cff190e3de8",null,null,null,"0x9217a53b6d0696b9ed25e238128b260bb352750ab5fb35c6c47403757883ec1f","0x457a289047a69e07c0162b9cc8e3b32ef40c0ba0d6befa26a2b72b655b91d472","0x094c58bfad42beaec4a48463658d1bea42269411bac6309dc814f09e28520916","0xf96902637afd3307be7ef0ff70217e40ee75d3fad0685efe4052aef616c28d2d","0xd3aa73dbe913dbeac644c4ff333869763f33de05ee703d5decf9a7d196247db5","0x9282904493d747c8a5dc621d8199770c291f6e97817e229ec422e9c52ec017df","0xc54888a7c09fe4341325248c2bb6a34ddd8d4e474831c57b775312d9b291ee61","0x8c869b8cb0ffbaee48508cbedefb4ac16b14326f335e4f6d5047158fa19997ce","0x74fd2520eb62f557a02c0350c7f1f7d2ceb55c8faa24357fa6475f200e8024c9","0xe7cf01e3c4341ab8ca44210a227896d75c39b02da51af1d7b3b83d7c32ab3741",null,"0xab605d17676390223dd0447d97e94a787f22bfd4ebece3e91a44f5f5c8f2b35f",null,"0xc7517b359c05fbbf5654afbde387d2c6c260c7c8e5b33db086526a63480e090a",null,null,null,null,"0x6b023ca7480d4dec24050eef4452848e15a4eea6d5f5c4ecc515cdc75c96441d",null,null,"0xda1bca10186c1846789002167b6c5146bf17cd3e4901312cd2bd55b0e0df5eb2",null,"0xbd7e25b33e59e5efcc699955d261a4bcb703164513323b1527c42dcaa7d382d8","0x4d8242a7d1a9c2e4ddbafb2696d60f9ab828026dfe1d575bb24130e631d1bfaa","0x574a61d45a1a971f70f6491ffe567942531c232e588bb299c716ddf8f58badf0","0x19af7319af9cfdf485cadbebe696f1b682c82b10211462efdb8b14a416db0b28","0x019e207054521c0f7045f73452b57b90f13cb7001b65901072f13f6dbc6f6233","0x0a10a2947954e8fb1c8e4446456edc9360ac16e7d85a5774aab69ce842332279",null,null,"0xdb43cf6a04f93a06f729bf550123333ff0336b6b7c51141fffcb3520856e3247","0xc14a4675c75a0b05b3bd9ea34955c8dcdc25e52a19366ac3d18356114ac95226","0xba7bf34b5ba5a0a7cef54743143297085a028cbd9baa577b1bc8b02851e1fc9a",null,null,"0x49fe177cd7bdc4f7247424cbbe133133bd5c8c7f3cfc4f271bf173911f56c967",null,"0xa6d714ea692d485629cd16e53304abf77697f595505f6d4fb19d3d3f8b195a1c","0xca8d776e8bf30a5b2e897969bebd37ea405111e3f66df533eb77f689f5daae33",null,"0x9c17a80d8fc612b9426994fa58ad906595ceb462e02ef3e7986f42b097ab30c3","0x32104e6da4c2335f2c46035329e5ddb4d40f9d264243719c9dfe17257e45ce9a",null,"0xce0d541a0b7ed12946e0e7e86c3673a38e75484cde19b98754f1486b46271483",null,"0x3694caecebf33a16d67856573ca26c71decb72147dcd9457cad0e3bcbb36f045",null,"0xe81acb77d9d0748d672011c3d3e5376daaae55d0cd508ffe15e36bcd209db37e",null,"0x5010f07d7de6070b641710551658ba3296eb75c0ff0f164e844787cdfccfb43f",null,"0xab9a96ccb298bfce2471ec7a6d22702819bc78e3aaeafc3bfceeb199d520410c","0x688c48574f9aaee8ad96bef40b111db85e73c8c18e535dae2af986a25d64bda1","0x964b1613d93fc9cb086a1164101ac7500a6d07b502aea38284d28446764820a6","0xda1dac6d723c82b218926d0e8b07b62b310c074a9ef22022f70597fb4d5b521a","0x8056c9c87dae46697833b108aea6d4d529e015bd83de3e6bce8cee19a17e1b13","0x1162ebc60024bfb21988a60145c353ccb7bbc6c5b8d996f168b2a2f58a02c495","0x9233e1189cf0c2f8a39c9ac93e7e6f6a2bc8d2388c422c7fdbbb5510977406f9",null,null,null,"0xb244898654a270e23dd438ea55cf70aeca31ec9f44a4b9b592e80ef89370db53","0x66c385cae0926e53da6751fd5eda6b0d9d969673a5cfa13ff7ba9d790cdb7992","0x499a8103ea331550db0f28325a3c866fe88da65f52ab190e655036a027429885","0xf5cb0e35d7448869766cd989d072291b94498952da7749d4fcbd497327f812bf","0xe557c4db40aca5b9ee5422c8fc4cc2961b090935983ec79fd82b6a44afd41619","0x4b323866a37d67f821026966a701664219b6a1085e9e435a5cc281aa9924fb82",null,"0x0f00a58bb956135e617e315eae857866b982010bca4ddf4316dc782a7acccbb0","0xeb96232a88a255a9970227928153ce12c91671dc94739722eac87686366f17ba","0x6e2c8a7807ba62eec2b500d4ba718c581e13e67e0565e67d0d6ed3473edeae0c","0x4e8f1a2d85f00034dd1decdb0c7dadfac9d7c71b53d7ca1209d3d313805a01bc","0x9c456c913823ffa8203ba357a3254fb2dc1d870c7763f26bedc9b303f5515428","0xb7cadd1a00d3789a03e630befe8c494eabc551913c05c324e00e80f9b024e930","0xe2235d7f0319d531e3291966837050fa5df178b0fe6f299cf172e721b1f67354","0x6c2c94316c16a29928ed092ca9e1d3410e52a33d2377e4a05ead9a44ec1bfccd","0x1e23ba0d0a73a3568b5aadb26b71559b80057a51acef2a0e2338c5cf90b32525","0x4563eadaf3cf2e2c7d307071d2b86457f5af51a5c5e05d154994e688d9bd7d1c","0x18254ab55940444ec6693839f630e36a659f86749ee44c623c533914675e4d74","0x014e4d0f3dd2d3a59cbffa449bdfd2b582d63d787fb16c52037fa267ed9169c4","0x151dcb478ee6ec58fe7210cef066ccb993eb55def36ab947f86910975d5acaff","0x412179fbea1783bf0f92a559d738d3fb1e048e4ca5138354a25bd5d35df7b989","0x60f6b0f07a344c3391adf92845a5a7aba4e3dc9c6acf223d2df082bbb68d47af",null,"0x37ef3a63406a137d47b71b884082570e24fa2c93af2c4d5acc1b34d10ab87a60","0xf7f4e404737ce30fdb8b6973df989a3966a6381acedfbb3d0506ff893ae28848","0x6124f4f5f8f2aff8fcdb7d4cf411149ad99d4a8de967062d16a8545fd4abcf6e",null,"0x040d9be34aba041bc7df7a7261e97bd71a97791c5797a8012b4b5eaa93725bf9","0xfb36453d10085c9d432aebb97353ace1cc859f905f183d68530efa82586246c2","0xeb1961761e492f601e3d351e05515ebe544035c5cdd4409fe2855893835dfe59","0xa0f08bb0ba81864961ed1c5f2aff8c632602a9c3544d938aab6423637eeba9d0","0x55a9e8ae636be21da9ce6f4274d09847dde4f0faf1242a36d0c1cfaa35a3035e",null,"0x7eb7f099c56156033c0ce6b955a2e3a3734b5578f582041cceb7b0c8a7d31049","0xc44d4123928dd97b0d9765a264a214cb0376d6b6571b80453e1dd2a6feb770ea","0xa2a44c4ed6769216714f0b0a8b7af96c7131f1468a4230b924743c90cd05a406","0xc0ba7a6adc3a9705d5738ecf01da70dd695aeb8d3270c02024b6266387afdcb9",null,"0xf63a892a9932555a1a8820db7eff5c3fe96853e6c354cdb39ff61f18e4537d82","0xdadadef4768aeab6f653cfe3cf0710268495d8bd00aef4ecbcafa1c0b0c96041","0x91a47c44cfe9b46207403775ee80846b273eb1c481073d35766a32728f71b4c2","0xe7e64473d8f2570d1496dd2778f65dc295277e3db8ee4b19850e1bae5e7e8c0c","0xd1d8cfc5ba26b4250e656808831943cc0d79ecef85200a6ff09c4dc84ddcaed0","0x1ae56bfa8956e676932fe1ea14d0a8e0303efe39ca8558fe8f63a16b1955dff0","0x1e7c44f70ad9e2184e7e65f6d5ba89b8c719d14294283590ee8a2cad3d8565b4","0x624615f6959c9257490052c08657281acb47adf360f71fea8dcb5ebbf911ecfa",null,null,null,"0xeff43442e1eb16ba2626df06ff3348ecadcb2e93b0d005ba7f16b29cfc938b4a",null,"0x6f3c7669c46aedf92609c0f99fbea65bb60bbd1f033873a8552f037083c7b920","0xcf1378508157d75f54164dc1e15fdaf17098f094bd01ebccef3b5aa47394f308",null,"0x91b79e8258f8d6ecc7f1e64460b55c800dcd7352ddf9f3b84187b0a7ff1b77fe","0xd070b0e936be9066bba1b44b69ade361061415dea226809818c419eaac5fbdda","0x34d91758ce79f0426aa993b9a54957c6e5dd2828522898d53f54ff6b2182a1f8","0x253624fc9fc6207c93d4f635239ed7994633c9f3659a97f87d07b4624e84ee54","0xef0095e4adc906479f63b6bc562029f458b1845b92fe8b9f03d04baa1a93bca1",null,"0x4cf2eb6cbd4cae7bca612529c037f7787cc1ba0800617c1b288c98b9ca5783b0","0xb3a81c50632efb01f8633dd55657c1ba9bd50a60a84166ef31651b721a79a440","0x60e25134f227564cecb9269db84bde49cd2712b98bfdec2caea0bcee1ac3e362","0x820c828f531168a0cef1d97a9dbd6e87ea57e05d3c8781ec83e499341b34bde0","0x5eace2300df4a24bb72457040407447b9fd5abe67cdf47e77a758c8a05fb008d","0xb85867b3f6928dafc3d873278b8c19233d703a699a4b3c873ba92f56e1825721","0x39c7b24a0d085c3b48a7e0f0343937994046d16600e4d52683ba8bf8db4aef12","0x54d5111d85f7477e948d4177c6ff753ff3ed640e7780deb9dacd5f3abf606675","0x291721dd749eedd9aa69a89c2492b62404812eea4ab06f073fff0df4335bec03",null,"0xfb4483a698b84182bb1e9c5d0782022b77e643f1dc2401b9513e06d7fd5f8faa","0x4c005e7a1f2a46438e91d2db2a9b750c7ed634f98963286be7818015390cf763",null,null,null,"0xb0a0fb1516d491041da859d0480090e39060bbb6237833563b464073414f221a",null,null,null,"0x1ff270f3a6d9294ecf766141869d1e3358e5a1a2901d1bbb9c2d58540a3d9a26","0xeba787ffa66659048ea768d8aac3eb2cf0ab2446236b2a9c090b4ee85eb4ebbb",null,null,"0x9a151ba3f56744ec2626c60249202be66bbc31b2f1c0ff011e207a8185f86735","0x3d70a765ced16526ca2e0f874335331eb41d47b4c31bfc6b9f3befa995cbb78c","0x649fda0c51c110d6ba18b70ddb964c67c4a9a315d20089f0d2a157239d60837e","0x814c12ebe1b6f699402c669758cb995559882477926acde672bee7b65820f73f",null,null,null,null,"0x3c4b0360bb7e748250d450294dddfe58bf5366c4f2adaab051df20716fd2c054","0xb7e46865e80efb7ecaa20c4cae275738c9a53ca47b361c569ce3c85b0f2694ea","0x72f6d4a4a7ff7c992b549d2969a893f0dde74901978e77dd0b14e9b6c834ee03","0x0977f0d58fd83a07f7eeba5317582c64a59e59fde3112984e5b3400efa0c1c8c","0xec2f3a6b9b85550ed6cd179f280ac56d7e9198a3c1f29729577b71b0bbb49e4f","0x6e86eb97359194666b6dc3b5659e07c2890f9e62d5e168601e2817bf900840ea","0x0ce8449def205652b0baa846f0774e9024175de7156ab422a79796f9cec1728e","0xb0e4616ad1cf8ca988e6c8bb48e0c2eba6a71c9568d10c260076fe6caf194bc2","0xa98fd7f138b0c8c46cafa540d6d74d2aa7c9252c0628f23d172f5d4540c59f13","0x96ceff4f4057cba74a271cae2e6a4a6b8781dfb520aed30bb67319d746fcca4e","0x962225c34798db9ba1c6985bc609ff00b5e3fe824db8ed5dee5bfd4315044023",null,"0x729f262a234f3ff602d12ad470f783ccb63fc68532f2e7daf02464aa678d94d9","0x2a3f53239ebe27671b12a2f096c216faeae16fa394f6f993400c7ab500aed380",null,"0x2378fe3909cd90c9f17bb1f6fe684c620493da9887e7d71c3135ef704ef3821d",null,"0x09097a04570bd0d1fd6b3eaa232bbb8f1db9b6ffda307240e3d579cdaa11e13f","0xcbbf142749d181d339044d887269ad382c5bfc1c042d211bd1c49d7be3fab0c7","0x9e4de377ad1c63e2d02fbc0c7647083b5c658093a9b9ff22313979ec00fcb208","0x2ce0ec47a916905e2f73288c24fdd86b922ff15d090b36651cf5acc1497cd3b1","0xe7cf05e564ea3c8a8ea14d880cdd8b95c813257fc7269a29a4463fc2a1b7fbca","0x5f0f60c98a01e884cb8d2444508f308a273e33cafb8b6594f9bba4d2a3011120","0x7a1609582255c4df05df1f488a7b584e8263918b0d896310da55989dfe06a2e8","0x4fe416754ee082d1345e68fabcbc8cbe83afaa11bf5c509b28343a01d005c0fe","0x8a7c0eee55fd06f93e2abd0acc1e802af89812f518545ef08c22a7ef49cb3c31","0x9e49974650b80c4e3d6bbf1d9e7ce11b21d22f922e268bfce5d54dc960abfce6",null,"0x68de7038c4744908de9fb8e3abbee44dfcdffec4d71e37742c4cebb9e5a50cf2","0x7e8b31238bbe985ab81299e9acc3de6b2dca8c8b0b193c840334079b745044be",null,"0xcc1cbef3f0aae74ea105a80903d8742a20cd1733d59d1f5a62557335f7709327",null,"0x303c70a7576435ea2de70bbb52b97c3133f2f8a4e89d7cc8eaf7905d61dfaafc",null,"0x4bc46658d8ebef91a919f2e7bca7a621d83c49750e7430871558f88da39e5008","0x42d9f169c9e9572e970531992dc1fbd42000db261f06de3ccfc4fae745914ea9","0xe0fd7244e3293b6f5454ca1c8ded526017e05b65a19c3d97598ec034bd2afb77",null,"0xda1ab76009d188441b11a1a340f45212799aa81c531b48be9cf25a6995943490","0xcb954ef0e5ff97edf04cdb202f1034b283aedcd02520fef33539ea2ee2089590",null,null,null,"0xfb9c42d151c26f7af62e548ef313c126f06fb827f93fc32893a5183afca0e98e","0x27e0258ebdbed7a0f40a93efcc057e40c2b6f41f55ebb1a231d46fab21ffc7a3","0x2458b4f4a82b41dfd42daa2bda8f5e2de6549fa43dde01a31381bc9388d0880d","0xcb4f9f31daef1c1dd619c76f0ce80589f0fc4948b3299be4112d7de86d5d12aa","0xe6b58d17ce68ab6bf95a3b5ac128c2c8d985441acfbe6aa6a9fccb6503124335",null,"0x31ec7161ab719c601719a0161997fe479fe88f956f558ee446b18bc3129653e8","0x48c27e7317669aca5cef01d843e4383fe5c3a06ff5b560f92f6787b8c43f3010","0x6376d105e3660230e7e491aa4e1cdc479e8ab2094da7d60502fd99361a520e64","0x7ce89d9acaad1aaf05a4e56aa858fb5a074e9bdaba862b72d6758e1f6ff3ee12",null,null,null,"0x6f7ba6dc551e259bffc0923b738c17a76101725f26a60597cf751ae3bbe70719","0x6144c3cf453e5e67da8ee99228f715f36d7ea4912c7f6c3a0500a442ccc5b2b0","0xc4a0cd06d94b8e2e7eb92768eb9556d6178e50f7acf22fb7103eed54ebfe5252","0xb191720c6295ad39a4c6606e76d36e4e8af37a06e9640dc4c382c85a6c7ad6dc","0x663e7821e19eb5a211824a12fe611655564ddfa8f342278b4ad52ce7164eff30","0x1db95b3d3d1a1c41ddef33fca3d88327ba53258e75f48ec347967cd1dd761095","0xa68447433d33a493356797a44688e6dbfe6b4c58d9861fb7491ddf30a210d5dc",null,"0x6099a9dce48a3a06cbf39e31d21e9298428010675de5fef9e8630d01627e7b65",null,"0x4487ba8798d61355620158d607bab04a760e4a493dd5f977dc6efaa622a398ce",null,"0x4f59e43a4f083504fb7eb20dd3df68b2d5ccbb1b57ef63e4be14d1e7465b2ff3","0xb046bbdfc30f348fc1781cbf5729693b5e222c1fe37c582051515be618b7bd4c","0xd38e2e6a65142c7a25be2bdc021b3faf1268f08f466eb945ccf60e6b380bd40b","0x25e0a61f65788a05bc36e22c53b66f65c981af7ced60ede5ee495da5191bed23","0xaaa6d2bf132304e43d0a5f6c486cf3845889a274f50580a9d8d2e3e3cf053576","0x66c85dfe605a9de32fb1019a832e21b1364cc9271ccc6f8f98e1398a35a4cab4","0xe6b9a780deb26ef1138eae025e64089f829ef615c3481c04075e0a33ac482e2e","0xa6612085a306778017fc408230e12e1624889edb2b829f93f73547b88a8f7495","0x59c8af07038ccb3a137ea337b3e26f697a5541530376f4b79463a4c957254f04","0x97dfb0642f6828c88f5d983af399551dc0623f5d9aa694cbeb7650c925a28a2f","0xac519ea7952d5b497624473251fbb49c448c5d66f78520269765c1c5752fe292","0xac68b8907ec03a000b9f9255709347a1ee00a1680c2594a2d31411467f52a35c","0xaee7f2f195f49b22aff9c1dc92550a18c92da95960d6f88af90af6a8eec46f77","0x7f2e94ce7081829aa36769a9af173510ae15d086b73e01507b45c460470944d5","0xf44e552c7f37bbf682a2b202a1ca61d3fc80874104bd83069d228e3a92976610","0x4fdb3c6ecf9146cfd6f9977cbc179c19d5e56152f7f02c08ac010a34a859c265","0x692886b41fa4df1a5cd833ed5b5cde8a64edf5a796883545e25da6c7136997e7","0x20db6b507c6dde03ff3897f72320f3f38104a40027b451a1d569dfb4f04b25af","0x43ab962ad34cf63e81c8d267170af9c6774c62ff705f5b5b58a6811f93a09420","0xa330bf5738a2cb6d591237721bff1eac25d57b9a89f5dbb73c4f70f13ed80c10","0x8238952f8e59142a46ff4c676808b876309737349a7f3f0fc474f8a54779e8f1","0xf60425b1d24f335f1a39548a0052bca903276f3307e57bf55aa1d55af2d20546","0xa243c657acc6ca34dfaeda8838005a70a25174735ef6c45397d83857b4c76eb9","0x48c18db85574364572717d438d632ac1fc65e468d79d92bc58fecf85cb4b46bd","0x0e099cab3e4231d66b4988e911be8ecf4fb4ba75454e27d5683ee97083e10fb5","0x636697106ef1a5141556ff3c545753a1c1f137419d971a263ceae4c67ac6acbf","0xb38c98c2be7d4f9aa2e75f041934872adcd7038248f0a1ec46e5ea68d1e7314c","0x0f7877a68de05895bf34a4d735276ba87354dd01e565371aa72326d65aa1286d","0xa4d61df0e2d7758f343c15d38dc6633644a059665c607f34f3ac4ec7f21cfc80","0x1dbd162445ba3b56d4eb3aa6758a5dbb85312ae8fd8103113180cb3c2d607859","0x68ea17058cacd47c6e65495cefe7b05d820d856e74a3e80f59f88aa5394f45af",null,"0xc3820d941bd60be6582ee77359e93c2530dac2930d5193e74bdd1b81c6a56136","0x310b8491b867af02f50ccc6f0a8fb1030fb52ae8546a4ec89812407e34847043","0x7079c33589254a2ecff2c6f4dc76365ea610bde2d7cedc0e3906db7f330a525b","0xb193ae4d633f69714d73cf3fdbd3d5b15cad4bf2d339ad2a523ee09198231e6b",null,"0x4c98cf06a5e06d4e90dbba7a1416460a6b78ffb85cfe2bda89aaee8938db6d75","0x773781ce5ccd7845e400f9fa25c0e4464755f89df5b89973b420f104f285d041","0xa8e83c129f9efb299e54bfd9f1596a486510aa6a33e3dbc2dc2f8b1e67c473b2","0x46df3e8a07ad931b1499a40eba7594bff7694183c59d35354515b867ce65e97f","0x250fb20a8dcc1c52250618aa8d800308f6bab1a350ac3bfd19740113051737be","0xcad829de1a34c168c4da77e3301712a07440ea7580312ef1aa63c2cd0e395e58","0x699c39acf8f65515d9122d2ba8c6a03ae7bd42fc181d1370cb62d79dc96c7e8f","0x3b42919e56227f055772089e44cfe02447a68e92ed65e0b508d577986b8b7534","0x4a57509e44daa51208e64d518e72d37bf0f53b81d613c5dd5ff87f3752ade40d","0xe79dd2066d7de9ed5140ed0c5dab07243bd1d654693aa764f79ecbb2a9e4733b","0x5fa5d4172eedff4b73f7604690570cc138b3cf8e4a5ede449861a71924f48997","0x88b5d050ff99b60885fec3c5f4c557a1e07d4d97aac5b6bac221696a2122faa2","0x072831e79cac9a3b4b603cdf3f710cef708da77c59ade9f4ecc196f3e6da9715","0xf419f0222504488683f5bad1d364c5e5820417feff109bc81d3a846d3383f939","0x18a2001b293d79f86999d0261e609c4493a0e3996df06cad1159b2060150b7e0","0xd629104cdf516cc0f5725bb173a43e5c7d65210aa19f6bee7bc42fbe5f8afc1f","0x2389d632955be6d504abb9273fa0ab4ec35abc8001ff622b7429ea7731e25e20","0x1075d837bcfb58c4bc2454ee0ccfb4e5021471718fc83569dee5edfb6bc981ef","0x16e2da9d8e0fe69cd05bc14c72daf75a1523204015bb96c4e034977a6c95057c","0x1401c066bece2c4bce521b7e3f2089085de896a2c73788b8b6749ac14eb4e00d","0x1830426c0df4ca947e92c948bd255517cf3b85ac0a6632bc0a8c54a6b3547339","0x8202702916bc83fc98e75cbbfc869461e5d7771a3f49cc93deda0117057c6842","0x72cac20002149151b07edf881763800c3b5a7499e435286b7e1ccc58c310d930","0x977cf1b7aeeea9271c83e02b1bb588b61cb5ef3eddd01630fe513c5c25350295","0x3fe3e636de4158d370eb951ff2b2e3876cfeeffca19723ed908d0a2f3c237b77","0xb6abccd81828a3e641a61c2af422840659b76a0cef7cd1441514bd3ea9ad55d1","0x67304deb7c248f3f410894fe8ff1f316fb8d728e062ab9c56b7e50c774bc630a","0xab5a5e609c7fcbc6c2cc672919b18cc307ad79f10afa8848aeb5c0acdafe06be","0xfa94470bd62df1f22ab3a7e4016eea2e0ef4bc909f837041889223f6f352c080","0x87f1bb2750adefb8b786524191c0c624f67b5ec682262ce0eabc506459c8fceb","0x09185a3419ff3ed7bb1fcf6c588acb4c2f104e811a6616a118271793722bf073","0x818db5bd75c3655b81c1062a2e3527f4fa334ef10238a95253d4eb43bcf53099","0x998793c128533f40f7ec8be8019cc2828d81cabb8f66e7a9b99bbad6a6468d1f","0x6a5eb8ff8aecdefdb4709c6865c6ec00671400443bd6fa2810aa305dceae616c","0x043977a5487fbec6b52265f7e1e16fdae420c670a6259465d8dc41046e4935f7","0x9343f48aa047a9c34087bf519e2990902badfdd07b6eb2a16f64c4b07c325ed0","0xbb982725c495dceee9eb67874798f1cf66c55042d98a102754c937526ec490a8","0x619c3b65cffb29623813d1b6c8d50c581c970204a9e2e5b2f33bcaf256d8c95b","0xe5842e2935fedb28a21d87142b0e009f7211a3185f84d3d7f22d1d69f2063220","0xe4d7b0326e7a80cff294215d88992ec1cb8d56c7bfd860c89dd7350bd3f75b31","0xaca360c3bdd3b6d5645d3833ea920256e5ab5d26b791e05da2628674cfffba93","0x6e67a931aac0e6913dc68d1cd8bbd42a3562b013bffe0fb38758ffaca35aac6a","0x871c7a6cf39de7d0277a1ee6cd7a4ba47c6a7c80fa5e3622dd27cae97023e8d2","0x4a6a07f1ac52dbc59abb187c176ebf903304ceef134994cb30cc01bbb5cd79a4","0xb238399e06f481533b80564c9453b1bf8cbf6d1d93cf0d93d8194c9ff859013e","0x00787e48ed21f5d78a34c4951835e186e69bb16960128b0ba433e518db1971f5","0xe5584f36d6f42d5c54af28361a188536fa9a509cd34d355e88dfffcd3dc40a8e","0x489e073b989e88af79329092ea552595242628458f2a172d81dbf5b0bbadad3e","0x52dfe0df5135a9770d5043120d2410a20324737b5d0ac0e2c76a199fedce2e40","0xbde2ec34dbff0265b16b476e11effd92dab93d83dcbe54094885b9c8e4de36a2","0x8cdeb7828cef67883273796c1f161f89786aab14a5499619d2aa34e73313b28c","0x4b3654781ee10fa097e458eac5cc915ad849e74242e46570fbbd6f09585fd111","0xc8b1718a769e76c8dfd78bfdbe5c9c2450e2bd131a498afed3570467bcae90fb","0xc1aa7058bf87f661431eca0495c0775ebab737d18f9b136ad3a49ee46cb8c1da","0x675a9c9eac390e570167c7e8c0075fabdb5aced287d075b6613e1ec51c8fd9b1","0xfd6e8c1ef61beb57ed7871585ac3fe0923eca2046b32c3c92d82ef0552196a21","0x4f45d136f672a977735a5d483389f916eef77c01d089fa40a6e7077b42b93946","0xb9843cd5c44a69ce43dd47b367a29314b12a66109f9ba6325e44702a5cca08e4","0x5daf92eeb81631971e66cef64abc7592123f4590b0baeb30aaf1ba51890758aa","0x6627d30ae836b6f1729e57408eac01bfdd3585fca6fb1ba258ad02e5ebf8ed05","0x772f44b0d49291e3cf4bec5c2f4ba1b626ed40d7f6baccb346c642957809a0bd","0xf3754c8b2ca6824930dbb3a287f2bd89a11c160bc12b3a66d2b9eee6e0b7b63a","0xe83e861d738a966da8a1b2ae14698b492d563cb4bd9875da2a85e74bcd13b02f","0xb94bce8aa18f1d7bdb41e4064ee48e3a20203b9ab130c464540d39cb9bc5d29a","0x450dc8bcc87ee2de761fbc5c7e0b98ed645a5ce06a06ea5314c8e63d3ae4f7e6","0x7fa374369cf81a99c35e7315f749c8eaf4d4f0471c5835c9952d79dcc3c253b5","0x24f1c6bab535df80c4dc2e0ec0bf5d1c0e09f8a1a665a3ad33b8e6c8c348a766","0x3ad2b2cc43d13e0376bd93ce56bc1c33f217c79306dd8f4605a058729c7590a4","0xdf76c111be88cb9abb5bed32a7b9db413cdfc678f357c1860d9e160fd91ba977","0x682d8edf15ac49e185b0187cf2118407ca32b50ba8eaa5b2b796165d819937ba","0x8854f133f7ddb56c860118771a0e3de458457ea5c59ee429c126c34e391d0695","0xeb9dcd2cf95c4a745ce26e86aab68572d0c49d1172cd628ffa24fa4ee745df4f","0x50a382171eeba8291937e71ab808cbae206d68f392fdb421b4a02f8ca396d95f","0x9dbdbd4553dbf606e9133897b5fe873b70787725d25e3f7691a15bcfb0847ab9","0xdda3fa8a710a9b2791baf3ce0a9b7398f6aca490f0dbbe71403a1eb8c473e1a7","0x978ffec54e22cbf42a9ca9bc9674ebd70cd6453d1463a4ae5eb3e3e19043aea1","0x817e54ceb5000b6d5530a0c85992b400efca11392ff760962f8081c786c79352","0x8c411955a057644a548ef56e5956c201ec3a0dc8f7858b5917050c88b3097ae5","0xefc70ef3acad4fc1ade1df8ac59a21fea16c083843af3f72ecc0d132a2a1c096","0xf23d5d05183aadd88fd2302d3524f27d5807512e94d37544548b7539070b4115","0x4a78fa2661900a281f94bc878d5d80e2c423ddfb57f63d20bfe3ad35938e2dbf","0x0c7208cf618dacedbeeb2ffab90d60f387b3b9654b57f7523481d7995cdaf638","0x4647afb9c38bf78703f14752c759685ee15f3e038d8f9b2d3c9e96317f32233c","0xccc370490adc9cb8677d827f5fd24070af0b2b99ad91f1a833a75431873ec057","0x2fe0d037e9e08409f59bc88fff133162ae02e257a2880c3c9b957cc6df0f8c0a","0x0b9ba34ec37bc97ce9d2716fc6cf8f95ba8a9d2421eb065caa927d1e5c8932df",null,"0x87c850d3d28c770fbe82666897470a71626a257b2199a8d455790b1c353f0bfb","0x374ad7cb99a410d9b7f5bfa170789dde666c1956448f1ac99905f3424f80a446","0xa9f4f52fcc40989f12101829877d804726ebe40ce356e2aaf3efd9663a4359fd","0x9b732d9517444edff0a10e8c101b6dc7c339d582fadbb2ad9eb1504dbacb2bae","0x0f6d833339c5c1b2facc85709b351a5161395366b178f12e06eef81184655ba9","0x5aa37a08971964454521a0ffd0aa1fd1f140fa85f084f14cd2e6a968fc225f6a","0xfa6cfab0b5961609aa7af32646f13c7622eec9615da24062f5926887dc7be591","0x583441b52cf1d266464a03d927a5d8dc0411fa0b8a6ee821309b41e26ee21b00",null,"0x319d9b2d9b8ebe61297e5f4dbef0c4e24a055b01f52d1f4a99487c8d2b9e3bc0","0x7322a6bb1822f17a6883f693d819af51f4a9a48d9a9c236a18c105a3a9308e1a","0xc34dda095e6c57b1d658f98c04cb8502d35f2fd1a179ce3035380199743ec884","0x4669e39916dc47000aac2c5dff31a8fb1c8c0d804c4311cfc12c2017e16944bd","0x6984e34551823e14d027288a5a8b6f69357009fb5a717102aa80766a506462e4","0x6ec1edb45b0fbfa01aabf9f9289f106c21b734d1ad01d548e2c4dfab6c638d22","0xee28294d127018ce77fa209a00d4535348ec2963ee601bdb4cf677fca5fdbdea","0xf8045c1c169cf0042367250c8fc255098b6fb30ef25be109c7a9df7514da236d","0xc8338bf68bab4913b563732d6120af3d94e1d734d3885ae79613bda698fe0732","0x0de6e6183ecdd5c4d05da3e68c7c89f916b6a32e8a2c873600d117a6a285c482","0xbd644bffcac4f2fc9f87ebbb67572747bb27bb0a70ab9ab353230fee78bfc54c","0x830993a39c5e1d215a7a4e4f8005ad04f09a2ef13088639cfdb138a17c4cf524","0xb99ce89c7c88be0fa87412c013fbfb4209af467e584443f65dcbadb19485ef0e","0x29fda7ec43173e20eff53c6d55c8e286a42e9af1048a1946396f326b53289d38","0xff43be7da2f852fbf4b82c59bdb88edd65be78a398d3c3c99b5b2e8a2e85fc89","0x5782921dc4de76d7f9259121c2a7e5caeb30c5ca1c813d54e98936d4b041034d","0xc9ec2f8cb9f6c699f83058133d4ab016d2e916f2487f0aee827515f63d5eff74","0xfd20e9c56a0058f5254beb1d04e7d3c4412d63848e148437b3f971b653ac0785","0x3e0df92dee2b3f23a2ad011eeeae6cd73fbdcfaaecd4e9a4e1cbbcf648e74093","0xcdcc3c7213ed787c961b1f561acaf110c7a033d872e56eee606b0322aa624b4d","0xfd53ec6c3dd87ee75f4307f416e5eea071a8c39e5ea01fcf5d8f1b657a7d696d","0x5d2bf072c6f360c833cff6cea3311ffb2e1ff829413debbfa4fcfda5e9f7536a","0x81b7ea314805b108618534b7e704356588931c36fdcff40ed1f5b66ffe960e9e","0xd9416b5154f2c4d60a30a2fe282b2df899e0e25410245148df2687404e751d02","0xcaa45ae2a28f68dac36e2a8f564e3509abd12956e5842c9802eff41ca45860e3","0xf6cb34fa23538148c6f6c669338197935ddddd7b134169239ff9ef51017b7d80","0xa4f7208c5af3983fdb201f5f140e4773820b68c0cc4bfb06f16d977e36a7ebb2","0x5b8c0c5f6b4f619ef23799b6663cad67898dbb47bf85054cd37daf36c1a62350","0xfa91b22f00e251a3c1489e06fb781f59e49c21305e67dbae6ff5fd08518f0cd3","0x1d926bf79e34ccc7d1aa37732b1e0247f7d0ae53c99efaa57cd674514eb12b64","0xe8843a7546d2288e25857651f159cfc9a9a47c85b906012efa7611ba33b22402","0xacfd5ac00ea13f33978e3f60bbf2e8feb8268342fa5f751aed942dbaf5d086c2","0x9f8ddae8be5961f0a671eb6e86b868db183f8042bb8e42672d41c054d4e578c6","0x7c34b26b1db3d8bf925f143e7d6df7e117c65526c2130be8ea832b696ca9e0ee","0x2ddfca0e845e43b53188fcbc1012e98b8e1e06b0e3fb280f741789df0aa33084","0xbdfa436d7f7dcb837364c32ec57dcb2f3881039e06ee67e6ddd3b34dda6a3b3f","0x1b60e7680f67d7a6a37906d28ae588538e24a04b85571f50109bf1fdd8a659c2","0xd25773b3d1adc262406ec2b81b9c1b8688491ce1e667170b475cde5f442d9b17","0x44559d390064193a07cb6318a0727b20a93b7d772553b92be173b9cfd18c5af6","0xac83381b0b8185a2ba16dd9d44a442972f0f438f76cb071cf609632d3c0babdc","0x1d82598f3dead699dcae287bc008a1bba44f63b9802715f6d4f2b1938578cddf","0x85acf4ac53141b4c376df93a862ab2760b652597ea02f0317b4dc7cd14fa8236","0xa8f10e98c0ee7a4c4a5b9a2d5b90774e186a4faee03b36439e8566f8cb9f0084","0xda315bb8fbe6ce7502083e55168c273ffc9b1be23cfe67c1967bc42e851cea8e","0xb7a2160f183e04d589e52f1d82004142c69c156bcb3c6ec20ab80c90abf8f7d5","0x63fe304160bf2ec14eb99e86f427485fc842ce1f15364193f84c69c59a79baea","0x37a9cc635558cbc13f17a2368063c2a637daf702b2308dc7a8ac382438c35704",null,"0x39bbf2a079bf52ed77ea01daca7f2847af3c5bf454f004e05a5725eb8c5794f4","0x2d05b08f92939f62e5348ea38cb25ea5eb3705e735dd4024ed4a53a749fd9ac6","0x51fa16154514a1d6dff64df83f8b8eb09ab79025a5b94e63286a521231373f83","0xd98dddc7d59cb4d79d64135d7cebd863f506098c6bb3f3907a2f8c0b988531cd","0x0957181b0806681c4a8e4c2906098c9135d140fd4cef9092918f627c382363c3","0x309c76598105ea3511f3e2ba56eb32ea5016b4fa3f0b792e5dc61335cc06d7dc","0x5a8e537e7c466f364fda9b2adcf5eded4e2d4ec8e0bfdb0c2c37e6239c1c5b3d","0xbfdb89396d434ccf3793b362be9bdf503169ee922480d0c3b9ac9261af2b0b16","0x375808efd31d03800d30049bffb698bd30a1a1ed8845af5fadefd8b7c8027603","0xc8d022ee90309892e9aad7a3a7afd1e5b30cbc47c7444486ad9789fcd3060f13","0x71e8cce4d4d83469bd3beb8e670cc491cbed231ebc8e770eaa2426270d1a79c9","0xe9705cae2aeca465dd2207cf405bedf05131dec5c3619b36034a2fd7c6687c20","0xd0e9f05d04b1e4d4ad9e8aeda184836e3eb1372bff3c46d535b6bcb6cc0179ba","0x23ba830f34af6351056158c0d50bf6136cdd777a18da2e390a01b611ef19bb17","0x58a0dc2af071a81846b2105f663fbbf7d0947cf215d548eb706d4184a101f84c","0x2e89077f74bfdd8c3f0f322c68c9fab05c698d68a61bb7b41803e5b49a9520c7","0x5f8d8b80edaa5eab014dad2ceb6fe3d6cfa938ca4dda40f4131bea3d15848328","0xfa82e56016fa73aa864f07cb2746185e62fc686cecfe51c589b6358016d1db67","0x76bdef2e4ead9ead5c19670bbaea47a1e2d1662defde350ed0e5ff054248263a","0x2db8b45d47456930976a716d0f179c0549995b29bcdf0ce37ee3913b2e8beb61",null,"0x21831b4289aed1e9796c38cd3b65a741fa7a268cd21ef646811ca161192903d2","0xc896da627235d7e857680e3e3f671c883728e34daf92686881afaecc7add1b96","0xac27a75d780a5645a17a65128fedcb3ce1f63f03b7781b49122f0d7de71973e1","0xd046220a49343834b866c1628cf45db2130d88a46079ca64cdf725ade7ed5ef9","0x5672054a012c9a3d6fbd3456d3b7644b81a7991d881951a262961ce22e021004","0x6328ac102568e7939fe35989dabfc79bd20da6720616c6b0581577b36375d286","0x76ded901f8c4ee7620866d224d808cdfd56fdbb182c3b09f23e83b94030ed9b5","0x6d8b29e9cd09acf1ee6ab039113f16d940ee99997ee7ec4caa7d2347d1282cdf","0x3d1a31c1dff4b35ae92c6c5c28fda4a73d3549aac63ab99031134dbd6c36bc28","0x1ecf03701b080922fa71904453231083a40d5730f77fbae0f5ee97860f2c1c0e","0x9456078f708366e627120b7ffcd1579efa1c834a4ed59c6f1eba552f1aa4e125","0x4c6c836bbf6652ad48185c3b625b944d8469b0890f16ca93b57fcea12f6bb0f7","0x4aa09d18e6038614a710c3942b081147d6b9294927fedda0f3079ed87e677e13","0x95a976b5f97b6634ab6e87ce2bdf27e1a64a50973954f33a373cff939df1fcca","0x50470c8ab4b599342cafec378dd641c30a8c30f8f89d9032e7f3fa3d80c5ea90","0x306671d8acfb10452f2235cb84d5ffd087d228f5837769b68a22998d8a14c2e8","0xf071e559d20e316eb85a4d1e553f5bc34728aa1755c90876c0ab9f9716640725","0xc1bee7301b2e291c3d4007f7e079d497e1ee555ef796138d25ff949fa88d8d13","0xd0b115426b2fa9bfef0d6ff6b9e423a3c86898df2eb3b63ef79ccab4da9ef21d","0xa2c9dc8fa3a2531eb0d49d6b6e4ad436e721e2d3d9dedd828bd33dcdd337b39b","0xf63c3054746e7bf41ad668683c950d9f64475b646792f4e0ae7f5b201e592a23",null,"0xfd8b5bebc26417d6946c50a825d7bee705f4b9182c76d008b4892624f2618931","0xbea1012d55ebca8954c582c3899da94240f319035667d234a6877a2efa342ad4","0xdaf142bf009450b1f01dab8fe1efad1a51b32d3300cc75012fdb666715991835","0xde774ef3cfb4f0c21ea3377814dc0c658d91ac8d71c10408a67b66bfcfb185d0","0x4a912de108999b6d25d510488ceb4a80c223fa84a11e38403fe238e79c4ad08f","0x376bc6e2d18b827d57ecdaf089f4c0a88b11da9e25f458a9afb7943cbd7a7d2d","0x329acd9d020d2d16e2e9c21543146c5f329decd6a0631b37c9f38883714c60cb","0xf73a23a59f7ce8a4d5afc891c95a18fdba23e2bbfa5685094675c20e2149396b","0x4ebd1948759f0086038da448fa357f58dc77355d2a75d6ca9a8d322bd74763f2","0xf57ae96a7de83a826232addb9c3621d9156b417d12cf313d3b193010adb691a7","0x00935d1b0adc6dc0b613db6086b9af3b400797439817cc6bf05290ecc6b10a44","0x9aa904c64eebfcaff48ab2524c49cb146eb470dc6e6bcc95eb223d6448674608","0xf6fa20ff61ea6c5e6cf193af384fe8c965f556123cf0f64bbcd259859909d14b","0x3105bda1bbee140dfa64f88527450b0d2b8540ed3f2b26cda5790efaf1c2a721","0xe960bee52419503b0941468cc29403038ced7dc7a6c2f9a4a6475282ab2945e4","0xdaa24049fdb96e87b2bd35f0956f22a6b42285d79f459a439747e549107eb4c7","0x7d917056d0b79833f8b6576a4d55959300642cf0590439ae9b2e33064e422649","0x246bf80729716c02185a85a6b4f30c381e708e99eb4935d9a52e82146f4e0676","0xd50e72d305be9ee3e383e2bd2730b56f0f5d6506633475983159ee0f0f98f888","0x9c179260fe1ca7e19dcb9119efba20968aa554f32089037b109181cad7b7d64e","0x6feebf2f2b242beaa4f47576f3399596cfa6c23511846b123ba0517cd6589cb6","0xfcf2d237d1595bfbbc369c9900fefbcc6a8c36825d1bdda1a5095ecafbc36e8b","0xfa8d7a522153ad7294a86182640ab0029c7dde96043bdb7ce3f7275f86be33ad","0x4bc07c946472451b29205e292c8e91c6bcf2bb0956f6a1ff222febaf79248e07","0x1d5c96ca7e1dd8b2616c00c8b70b38dd68cacb42a76aed650f9227c40e4ddad7","0x2e31afa75bb00ae9117b14206943938e1ff4d716c7293dcc61a08f4f5b606ac4","0x4d99279ade93a491c53545f939b7864470f53906379c77c0f1b629d73a095f93",null,"0x3c6455ba9cbc2ae89e5e72ee85126890bbc79a478c474cdd75cf54930530de00","0x41175ba519ba46f499350b0cd5ac1c81bf5294d76bd7bc8c1fb23760ea9311a1",null,"0xca190a1c706c3b81a31a681a598ea1436f7748efdcbd36732478eee07534cb42","0xa39445ca3864b1c433a8bbdc3e78c3be5803fc1e7b103a942bdeb0dde50e934b","0x4ec90b17b539d7fbb463b43dec9cee3906fdc7e0acbcf1d31fdeee6f6d8c145e","0x2a2ccd6e08e180ef4f847f0f549ab60e17ebeb2585a7f298d1110d2577b43e39","0xefd90d374af1a4d69f0379ef959e4102487de02b6e20849ea22d21d35bdeafe3","0xc9f35e85a79cfbf559fa6152d0a4eead53f63a77b09bc7293861a00b00b87c7a","0xb8fd9f4d7f6a0a0af8f3a776632457e787dfbb6977223a015aaf2910522a4274","0xdb15613493f16dd4d1d47332d9c5c48c72c85ee56f71ce37e244a96bc592ee32","0xbc7eec584f1e66310c7c58ef1afcd9bca54ea8ed5853735c124f61c8f8e9bdf3","0xf765c83e6c4b4d4b403245798722bf65ff521032caae36bc478d71c004819f8b","0x8d16bd42b99c253a8172842d0fa602bd1c684b183bd646b7320b57f3907e114b","0x73fa56f4e3d00411f4d213c7076dfe9f9c16df36347a4adb7501090567abbe5d","0x7e49a6510729d47580f9b58409e6d23e19019a87c6986d7ab70bd583c8555207","0x583f718f371b55c9541bc8cc9b940c74b1d601460c1d5fd0bfae5d6179805dbd","0x892eb60931300b8c72b8952f1b3eb6f0b00be7e198c7e00b36b97b065fda8616","0x156f79fa63dba6ce94c2be32df27b416da9c204f8abc8407031956cffa1a75fe","0x7612281c80c6113f3cdf0067183845580b46474b01d3d98d8b0e54f088641735","0x0716cd1d603b127a61c36ec37e1bcc4a51633fe6fb011e2aa7a215bd5dac0704","0x602be61aca7ba52d7b57a13226580185bfb4597997dba8e15295c71dae78458e","0xdbc0a68a6640c26189af61f6dd2fd732d9c491c14728920b6334cfade6972c6e","0x4047bfe66a7f415d8828fed479c690b681ef2daf01f0bf19e7e68bb64e0709f8","0xe780fd37918dccac825dd0f0b1a33e5837ba70492bab094275dccac585c6c98a","0x0fad8d9a1d095b5b098f21751c46d37b1f3dde4a8864bf7cd5430728bf26757f",null,null,"0x0c427a497737be9c875007a75a1d77bbe776e78e5ca92e02d35bff2739d9937c","0xad65cf154c4fe73b8d4090f71b8e3d5b297536af74baea24f67a5719a8e31f52","0xdd93c50e94c444b311aa1c63c725afcc78bb27f9171f0957e212cfe7cc34bc00","0x0dcf138404620b9bb403721e266544c05088c0166b30a108af0351632ed164ab","0xc9eb95ee8f4daaee42d5d8f4097873e94cd2d4887589b7e60db2468159a5f995","0xce072962cde8359aac0a3c3196b84b8d493572a01fd201ce18b0c0cba4002b9b","0x074252e946f5fa3cbe2f4a2f6c71ab818acf839f490de11e2ae1d449da926f63","0x8b467aff31ac0fa6b61ecc31681040e4898161b17dff32a10f01d16f011d4079","0xf5e3c370bf9640780999960a64c153b43a4a1b7af9677fd9cc7f5117a8e24461","0x5a1ea2e53aa9adcc42796ec38c70b8a94b47ab697dbc3860e60db62231f47f27",null,null,"0x1ddf24b69d1e239dc2c7799b5aad1d4c3231fb10f54809a3c743041aad91fc6e","0xbbef88cb983455e96dc87625796edd6e2ca1a926c16fdf0977c01c7a46701f7c","0xfcbc45d9f2349bda5d8b7a757bb5bbf4e075e8f4173945e89e1d489019e37deb","0x5d89e6389676f055ecb74f875ea42d4d320122b54e0bc4659163e49110cd249c","0xad7b0fc50cc801a78db0749dafa2141c6248a1e4d3bb621c09078c700393c3a2","0xfd99fb3f26fba1450ce4aea87c2bca0322519fd2cefed346efb34fe4de2ee40f",null,"0x7c25b6404eb69c08dfe36911d33630b56866b688ad75f39c3a65f1dc1b1ee186","0x30dca4815ab9d1d600c5aca103e573ea602d2a8bd98aea263ee53d9374b48b7e","0xad7ab111704c9f21ec1087d2c289b556f5d1d8e05cc4d2d2af05fdc483d40aab","0x3d858c3ed815d0058903489a16c4fecde37fb266c7fd024fa7deff7a5b7b1d01","0x170019c24a30f19edb5ee7a64f4e7238c829cbb179f5a950a7113b0d4807b794","0xcc24816d170d05344539c16d5e1f93ea66bf6e3a3b5f2b985c48130df69df026","0x829a88ff0bb3eaf951753e162eba024d6e4a616563502c378b2f77a107bda141","0xedf8b6d86ece4005ed8eb8fca92b72cfbe15a59fd9982b2323b8d099d508790f","0x6a3616784af3ed8f45761712037567ace53fc628d16f3e8b32758263d4ce1d41",null,"0x67efd85c55af1108819a1bcbc933605e3b1ee35bf6e38644ace82834106d66ef","0x6f366885f84614230d05f665211b53cffb97299b487b926866ae3f8c796ba604","0xb8b1b409711ef231dc9b42d44ac1490d80f16c368601dbac18f1ce96a3dce6d2","0x082967a2f7b276f001ef9ac5d18c4186c066337bee0bb5850f187a516bbe95b2","0x9ec52d590113c88e0f3fccd75194eb04e642aaa2a781a99fcb6a93eb3c8e2bc1","0xd50b9d5d142af9d3287cbc5e3337f95493927cb1bea212390b8ce50174c4c6f2","0x3d587a05c07d4fe84f40fb221e97e973fa95714a04ae163b64cda90109c4e1fc","0x528f84a881c2bf69987b75f53e391d8974a868fb62a517935566750f04de473d","0xc298497c64273afe59e26e8e1133e89d3c5efe00aa19fa0d69f50bfc39cc76ce","0xce3bb375527bc23ac7bb3f395d93f7cb161b9caa6d595f6a8fd6a7d09db09256","0x00e79d375252b9688613265a1e790ab721d2f9354ab5b60bbf161feb8172109e","0xe0f9f91fa0aeccc5a8edc2a0d4e3b4821d03ac94c82025bc2c23f2b0fd6be3ea","0xc1049d138d651fdc3cb510fe4f6e68bbbbdf6d58955a22b880fd2f79b36cd3bf","0x3c665d4a38624a153c4a8dfdb906041b37d83371347a01bdad38317695d75fc7","0xb21f0077074050a4b54db5dce2e32be824b39c922f59bf5316b54c160fd0498e","0xc564fdfbe1e6652f21f544e5eb59a335a518ea7106edd3a745d61d4994f370cc","0x2918f3cfe35d0727d8432c50bc1a06dbc0ccf91043252da44dfb78a2c7dc7f81","0x845b228a29935fe3b314ee87fb27b1a7566da1d6a54a5970b6a68c77ddab3d51","0x1ecff2093e04c70929d6007e2c85179e61c57e7904f651daf13d11646adfd85c","0x35b3cd36d03bb133e896abce0a3f2f5cabfcf0e79579c7eff98327c0dd4ca222","0xc7d2fc42fd524d48a45f72fe96a138a6e9369ac74ad97ecfa0f43144d481127a","0xe5c374b27b8f94a8f87005f77f003d81404c489a96edc56925ca8eff4b4bb85d","0x7b0abde3e2280e0b0991730b69c9490b19d66dd07900fc2d51fbcdbb7ab80115",null,"0xf0f35246c2f80e09bbf434709f2ef9d2862e75f2c969f354d137bc56654756ac","0xb9567bca7062b8c2d0d61a35e4d17fcab2b22859f1ec3260acbee164b8b7b802","0x35a7fc6a6489d9cbe7d9d0cbbd53277a8040c707f0d800e44d8eb6bf56ffbd82",null,"0x1280a8ff23c2951d1cb084c81592562ee55240aca88f14cf5b1cffd017dc354f","0xee79ee300d0592d9e7be67cb773e5653e39ac028dadfbc1d665fba29ca70e7f1","0x8b83e7243025749f3ff20bec08bb1630df5659547b6a25ddce183dfe6afa702a","0xb937fb7c0de6f9c3f9c0f14151beb69758db79dfbc7d6a428cb06f3f46cc0405","0x47d004173f431f62d401711724080b8d1859230f163ed4df5544080dd804e7eb","0x4ec619fa05edcbb9499c5b5816dc710d1469d1670ecb29f76e0e0b09f654f4d4","0xa1d31778c15195a58c0429e001502f73d461ad37d63aae4114f433acf5fe8749","0x6cad139ed3de836e32f4fd02d866ab4d1126b872e00eeebaf2cd403a2156f3f2","0x6cbd6ef2b211b7ca1d0e420dfbcd56fc30701ddb831b9b2abc9692f7092b4fce","0xf7ca8c16ef76587e6d501a92d1da1d5c2773072540dc9047f0f35664541621d6","0xa14a605be1db136e13c378d666ab8fe02754fde38fa36feeade0c838d30b76d9","0xca75ce32c6ae096793ba6cc0be2e1aa08201a289f8d6aea838816ef89dc68c5a","0x9f85e81303d92515f69282c144331c568dce1aced0197cf71c20bb5c38a2e98d","0x19cde5cf264bc73b4d104002725acc89507bbf235df6bd6a1a21e40f316f10b0","0xf16c7d7cc3850aeec75e2c2b200f75ea78d558db5ce80aa9e609fe2b198e2920","0xc7c2651aed3d770382c5eed1dc50689f9a6ff0a81d54e5664750bac70554748b","0x147f7ffca10e30552bf1cd5bc61cf14cf7cf0202fef0ef02d017000b40bb8c2f","0x79c5d55685060ae9c4e930126e53e5c36768e0f5df093d7c6a5651c30abdd46a","0xf9b72a3ca3f5d1c79f9c7cf70eaed56fc3aa8312c77cceede8f5eb2bc50be679","0x9105203f200e896ecc0ae2a42ed4273a02bd08c7ce216709bdd3b32a213652bc","0xe44476103300d2c91fec579a5680a932b5912140d907ee2074b6fecdf5f04b47","0x103b9a22eb5efd8e08153bffd750b8e5f218100524709620cc6a90c5f954a9a3","0x990b162f160e47010b4d33fb3f53e0f4cfff2bfe9612b2ace8c4bf553d99b9e1",null,"0x5e0f91e972f58026248fc95d7d846c74994d93ae81245d412ce23f721f1f30dd","0xa6d5447f394e8427173e60f1af3902a5a9e80846200c1f776a3a3efc8efe5323","0x4180922a3845752dab68baa5ea802e9d162912c07b73a322e8458c12aff1d98e","0x90fa99752d65cebaf6092d76ff74ebf7f06fbf3666e0387a9b56819d80d6faaa","0xd5dba2432ef10bd9d21fcb04c5c92e893ab941672ad2bc5cb6d613a0b1e5a959","0x66f89a941936ca20415f07ec9ce22f8fef1f469c37a39bbba480d6016b330a82","0xa587a5bc8dc02ba468a6e0d4e7719fab19e35f1d6173d0906988eb062b082dee","0xe6a1e6a6cee9d0accb16d7d762edf45ee2eed72ae7dda9ca5ddc202f234daa08","0xdc84777bf6fa76ae4c981569494b289e44dca6ef43dac7c2acf14dbb0dca2d43","0x6451a4292fef53a96165e9bf35f024ba49fcc5ee90aea287f7648b98b76be965","0x2a3c033896c1e2a6026a97c80e7b0df5bb003bb11a622bc1be225085e554747d","0x488775b72fab86f1c84a1c234f74fe46578a33a26aed7c86950050c1155fcf26","0x33ecc85630dc1f691e2efb05afad8793aec2dd923a0c1b34e9761d8dc4ad2214","0x182572de2cd7690b1483dcbd3dc8c0361830c47d7a349277d9e9a701b39c2ced","0x4bc38c3e5c5a612c28bad482e72a8256ea828155da7d5e64aa5ba3a78a8e2824","0x63843693962d19bc13c37c50fbc7c1f690efc03115504a7c86dfa0be6600d80a","0x8dd112d733f08ddf0d14bce8f1ea70abdae85be2b67230df3c1b33fe48d4af67","0xd7d21e0b9a9696a36113665937c472f87a7ba42376f3431163bd17572f0272a3","0x5a5d6d7f91f3670fde98efec184e018b2f4c1af0649272d7460a17f1276b3045","0x95cccf2532a2c7bc23f5adf71416467d0978eb4d7e12b9d835fcd6f5e92aecac","0xe5d935a86d855ca98be40ba95fb941ad17cab26c5c8fbd72ee21e96cd2961baf","0x9db49b5dcb833762d1365eada5a5f1ddce59914b234371edb709fef6390a7507","0x50f790bf738c83a2faca4cefc24b5272ee4cc56122f1bf963eb411c735764a5d","0x9ff16c4c6024481745e5e7cb457bbe538351ec798f6ce999310a74e581551f42",null,"0x51293b81a2234d18d24de90c0640f4c6b9c538dd64729f8fce5e58955287911a","0x92176d7471ae7354e82e2864dbef817806d99eba20bd9c6e9570f5145d1d97c7","0xbe19cc2f3d364e9bd40cc35387d38799f6b45c01e799871db5ea097861109f8b","0xda72c6d9c566b60e9ff32bf1b7b32de34954c7f506dbcee643f08c83b58c60b1","0x1548fb59cee34a37c0b6b5b5bc4835b71a7da4f3c623a05501505fc969d6f866","0x74c030da5147eda7ff96e6d71e623fe008e9c058a0e001381a92fb8123269751","0x0a25b8b2c66dc6823ebf35f5c0be47a68b6811cdf8a5fe53450e7b5cbd2d768d",null,"0x2b51e94d15969895f893df9d99b7a4dd01009484feebebccb19f1c969adc937b","0x540a3360342e692e45a9ff879c1c587bb5ad4ea7979eaa5fdc6be439c4b0323b","0x2c6d4e2774649912551a6a70e50bfa33fb43632f2697ae03c6ca25dc31cc50a8","0x2c25237b81a618e3c1d1314eb9d84f2e879cb86d0b5116a44b356f2c2f226058","0x28594eca2414ef4c25d780e2d3199525150f7cb2cf8377087372facdde0fb380","0x5ecc2769ee72eed78c2fc5f5e72bad2afce23abbd07b39f63c8788f4877a70ac","0x0dc997f26663d48c1ef8f85cf1f6b96f83e31731a4074fe2a23a854051fab7f1","0xba8de3d2d07c54e27fba3565d87c02830fe685743ea7c362c30f829a8ad7ca97","0xa4b68e2150f9eb130a59e857d0760a74b49cc3d450b7b1cb90906e013e94e2a0","0x8aa5385d7d89e60c972ba291be7578d2d927432f0364ff937b32b150144327ac","0x591f5cf2eb1f6b1ec685211330a33b48e3c05c241418b3085e06a0c9767e0ffb","0x515e0941ad82a64e03e28bb9746e3487334d0d7b24fd94b29ea3874189e319d3","0xde1fb7823b07bb1ec2cb1d3fbe6582a754c65ea6e6fee5b10a23cdfa26be4fd5","0xefc36e59ea79bfa0e772a2fa6feeb12a82fe7a68fa86a8f07cf77060fa9639af","0x6c6e916f0eaa6731e5eb97ab031e15584ac401a74c0d647d7ceb6388ce3b2f2a",null,"0xf6facb5cd1d56dc783da6481001a2870a6b2b925dd1d6a5be87531a4459307bc","0x542e2e938d193daa9f00f609c2c2ad9c054913739188e500ac2e2bbce1061bd0","0xfb1980cf2e27f7704592ca8a0dc0c84037f44968ebc8c55e84efd7115fd772c3","0x52d351c93d94360e5ae7e16c969107c4d33103b43dc47e36efb07476737e8c26","0x9040b40795a28318394d9b3da03fbc1e51d9cd2c7154424740d6db75b3be3a29","0x13e66989f5fc4112ed24a95c6bfbeaa74c5f5173325636f5e699dd69834800f2","0x9b584e668c294227d713a8f45b5ab0513f0e3c419bd1c72a9bda0ef93aa6c520","0x048df354cd2c33d0a0b5f397dc1b28d6e4ca74edd7201eca8d1461c17ca60758","0x9be81f3e4154b016e3f01d889e98b0816c9510a6d8e52bb212986bdf72ddc4ed","0xdbcb352fe71eb2d6fe9e8e7d0b61217fa26a8568e807cdd7d8df962a5847cf9e","0xf4ec39a3e60c1e74b0769c0ce47540c8b0db68bbba177bfb26255996726f03cf","0xd012badf100af2923cb65183797851a9439feff51f6d1bb70a969205bf1eb5d0","0x6ed09693f6261ff64e5af8b8b0d1db682eb151ed1e3cf1821b0322543ab33a00","0xafc8fb2f9391bdf204a1cd69df5befbeafbf8301095f9a11e1e7e8840d918735","0x9857ef7fb4bb87e23080573e7da8effa9e6e6abc94f67f796c984ad46e4e5e5c","0xe779cfcfb52f7b55643a30bad460cfb3499edeeeab764169e340e9e640980b68","0x13bb07d041d3c99fea7aa58cbaac9916a50411946b54efdac2e1bf24e0503407",null,"0x96f5e6f9167c8cf4565c372a380e44b72c18fd65566cad2cb16c76b626bf686d","0x23fbe9aed25170782d3b098377ca9137bfa4d9e4e40006e13dfee3fe1d8689ac","0x7faf5505a27390a15a590f5a4fabebfd0b077241decf12ce0b345ca95bdfe3dd","0x044fb5486b14370a627903dc65950f585df40bd435e6c27276c5fcdb19846a08","0xd464c4c7119a6cb1fcc7e779e91d35d4a0542defca5cff8a658d6d9d0ece3aba","0xcdd1b244f0c23142d9e926033a3b0a9b9c6d459de64fe386a307ce94ef069064","0xb7368ce0075dea013a94ef4598fadc5c587301b0ec224a26a90ee82acd00e98b","0x26f4fa9808af45c8cbd93e752554d70d385717f8771d16a7d90444d67d9a0c9b","0x1bc2f64f6677913312cb9fecc81b0d2a305fb637c2d24ace74c053d7946c72fd","0x44b8fec3e1250ca79c06c40275843e8be479e01f1876afa96251ee7f8496dd3d","0x63f18b6d847c84a60fd1ac5842f39ab4768d089cb4c9d8e7e1ccb0b01b1e8438","0xc9c97711751ad1af8c7c65f0fb6ef2fd29cedcc3387d5163ea50d9cedbc6fe07","0xdf539a85d7d2de1c36fc1be3d6d2de986dd6b5b43e062bcbe575d71c8ee523f5","0x3c55036175471d2bd2df7d30c94a12797868ea4a5adc353ccc6cf8046622de06","0xc3becbfeacc4a3563587e6f5cac363aec39248026ef6d0bee84acb8938462729","0x4b5c00e59d6324304184ebd0526b8ebebc86777db78f4682a6ec662ad933a5f4","0x4f3a313bca1ccfc95bf07eedd564bb4de0f8df983123ee22bb8e76bb73d34d3f","0xf71cac822a8fcc0417a085254285eaec51f99fe9435ed256513005d7904919a5","0xe00b4cb20f37de54c45d2e8a4658a58f4b50bbb9bb1d547b33678e32cf81f8bf","0x86f794e1620e72752cfaec2e0a5ef2dd0f745e890409c62c5396a7b7b3fe8176","0xdd67c467efe6ac9b91c32d449d8a46330d9279517403c367a173e61d494570af","0x98af4a89b39c2a0ec71ab8b05d022384336b291bab692028df90fb32ac0ff7c2","0x932ba74c83f983fb6efbc5f34adfa96d0092e16c66121983e8ac3877ca716e92","0x650a9a21025f7cb9e4db088e3ec296debaa2f7311e16f814096db6b7c269c507","0x5443339adb7fa1bf8ca12c19533ac81483cdcac7e4280379cd7761884abace2e","0x0e028eaa0c716b695d6a34c229d03776d0fa2cc973f504b4f863ea914a851a5f","0x455ae79fb298b2476e58f74fc9e15ef677d82a7a01fa482b717479629b591829","0x7e394b667287040b9f99323cd01849d319c6a45bd39a19931e3bef0790a58507","0x608080bbadd361f3e097c7032591c64546b4e68a192e87956290cbd2abf5a2e0","0xbca829c61776848fcae9cc82da0613b9cb727582d55bb8730e9d79ffc37215c3","0x48d48ff5116a7358691341d748e2ef97c7d3e6a1a91bf3cc25ed07f64c39082f","0xeee791db0fda75f3ae5361e0ed73c2616c58f46aad26a279c86cf96943826932","0xd051a04493b8fa82cabd5a8bb927eb5e07ea87d8e39f8617d7b619d514cd62b4","0xad6ab2304ab2a0cc9e15895bf414d71f4c58a4c48b5f5caf071f0e5b72a8ec60","0x8be8b99d89e162e4920ccda137f18db720aa175c40015f5bc02aeae0fdb23ed5","0x758126e05215f9740433a7af695b619d675c51371142356fa32cd9b7f043660a","0x98b8644490481a65d7385ba706b61bf9aa5b9cc9d6f8576432fffcf0d18b15fc","0xb7ed85c36314963dde1aba3639c4de88e82d0ecf980788d1cc860d80cabbc9e0","0x5544c64752e9711806868c356b71b406cde150a8245e9e0e8399c35a2f1940f4","0x6902115a37fd3720921feb5a7da6abc33479948dc4d3f6655476f6a001dcf2a5","0xcc81bcf1164e6dcd36fea8beb8cbf066cadfd679319f88a85b78f76c02ceace1","0xd8d0b9fee8e77a2ef484824506838a9ca5dcb567fd7f19cc113efc1fbb6a7ae5","0xa90c4ce676a54722dce854ee8e06c5060657facd57576aa861583e10085573d5","0x15b6b9f4ef85da5792e59d03e75e045c1ab4c875d0dfb9dceac9d99b8daf0d45","0x75b22877e4830f4684ae080f789d5ddf114c8592ae29a1c4fc793efa2fc02976","0x27eb02826f5637a28fc8a1f2a37da11fc1335fc1946bb65b6667f026e353b24b","0xce2f1188d4982a6e5bd6332c3bd398c7068d5e2dba96add17b832542a759b544","0xf3289e3d7490c3755d4e8b187b50aed1359de26b208ca0541189d9c909f051bd","0x683638f2e06827a6858bf88ffc3ee1c2327803fecbe8715d8e316f21b08cadcb","0x0308145e52686419c224ff1788ca63ff562bd47125bc20e7c64558889e809720","0x23990d9d3e1dbc87b2f056c6250f19964eac49518622861eac91874b9b758e28","0x1959b41044d71eeedadc44cc259659284f2a8bf02f02861bc309607f52af5891","0x5a5d58a566755090f8619bfbdc776a2e140bb641a32fa4f29d1368c129eadc93","0xde463542576ff641fe973cdb4bcfb6c4aa86cbacd7f81b1c9eb2c9115bd54227","0x38463b79d3a7736104ffe2a50c62a2138d69d4ae0c4cc653edfbadd0cebb0b1b","0x35cf565b2292a4093ae89693e6605989cd1e611e1ea99598b3b1de6a0ac26825","0x2eafe5ce70a216dfdb6718df1c4f6646d291b6d784862815bb686c5372c0a07c","0xb87ca20f6f0286f72905e5e1a8f21c82f17c357e2397b099bb77a9f659c76fba","0xc8233bff15632243fd5e6f749af9ab3574c26d41026164a1242b7d41a7106967","0x10e5c008e888df758a10c5da1be9745c94ec9e0d414a7b410af886390cb6c394","0x69e367445c207ff983dad98ca39988d177edcaaf92d9c597b2c9f2076fa81927","0x374fee10440cefd0a690eed68f4e870f070b9509c7eb16edcd3bd74de8f44c03","0x389ec984b119bb5d1c2554424b07bffde2f617819b83696ab90be6f2aa3b14d1","0x4fb7eb48bf2119b00caad607b2ee2a0a851eb215be955ab77d92e8ac7109ebb7","0xd96a5c7bbb45862ee9422ab030626abdb17e57bc70339cbd48f5a14654a2fc3b","0xe64e66554c130ab194d0adf053f29dfb681faf6e92ada1698990d41be94fdbb8","0xc7cd59f09abc257dead0a39d2e750115124b93c5050c334fb48abd1512850759","0xd568d88136805f5602c7b20fc31d43f1b5fbc7b9dae5431887aec68a693f0bff","0x0b0f825bfdd1198365cc68012fae3b92cd5044d9b7bc5f66acd1e961fa48b980","0x504327e518f3cf75af73f0d0b12623d681ed40a83c7c678e435414e7237e3aa3","0xfefa75057400151df3bfeb55e8c4b66de780cfad1e012a4bcb0a93a54db7d64f","0x21d6e581658f7664fe0920517af65db871e280706817c0eb6ccf90d531137bca","0xcd0f42e9120309482aa226773dff1d1d09c6649555e1976ce5e47dd990a83430","0xcef0863e36bedb25fd6ef47261c827c302871ba3b108713188cfd31d28b02932","0xf849c7af2fed525b47f3416adf34223bd35709723367f911d3bb3d88455b5293","0xc3b6baa95f33871e3f3183f8343c536d9cd5e21ff8968a13407d2ba51d98aeba","0x2d5362f03404c17087848a99e717ec41f9888e4345edcfcf4fa8b460eef80454","0xa52c5efcb5fb9d023e7af2debdc34475d13e7e6522d5a7ca7a3a3e54a396cfd7","0x9be717d9487bea8c45c88d4146e011cbec021f1be4fff4cbbd2fcd182e477c8a","0xfde3d2ce46e1827e8df0177993bbed4a637212c51def1c8564fb03f3e27b4a6a","0x9625686c1be75318ef71e1e6be83167a0c3d5b188c12ab865c7519254a7f72b6","0xb25e8179c285ef91f2942f69e3c6db18179ad14ba702418433b5479bad7c43d9","0xfee26fd364fb99172b53eb6c2ca89c2ccb3675ebccd84909be920f80c2e47bc6","0xa696433b088df2313d53ef3d20caf7e4dba0fbf4837ebfb1645218eee6427256","0xd8c4c1e4672dacc10b17670d4b2c14efaad249a748b6ab14c1e3e2819c8c3a37","0x2553ca494bf4f257516a5600e5f008b807d0e49089658560a32ddd59003b7322","0xa6530df2c111b13619020685004ac43892384f0a77276c31fcca45c1530ae247","0x20fe4fdfcf85b86a5b26bbe6a7cd48fd542c95340105455c5a390b6ea7159c97","0xfd8c5c467ff9f0fc916d7c377907152fd6a2b9b8b5ceb5b1679cc9b8d0348604","0xfcc38d8f48d713cd29fac77ed84922f390b706db99f255951b10fe6f33a732b3","0x67270a2f2505d756e71d0977f93e44cb1f111ecc8eea37461461b9fabcb27a1f","0x23dec5cac45adde98fb8f11f1e19320b5ecca82691cd7fb0568be3b525ac3df5","0xa054ee1763403f519facdcfd0077f4831ffaf269b944cfb7e0fc02f33ffcce4b","0x24477a9d27f179fd26fdef6c69f3cdcba8bd5d745b479546ede515610d21ee26","0xf87f272ed958aa781f58c28b0064f7a035506fed632c5a96328660cc3465cdd0","0xce2b72732c9aa49c0758663ae7892ba7ea9b84111a6014ca8255c9d5152005f3","0x7f496a310514db2adaacc25f4c086cc03802e9ed6f287919eb392e66da35b546","0xf5a2b4312beaa09ba3b4c285bf6d6893f280620d4f614de106131154de05ab7a","0x73b912a2b9da433f18a96548ba207b83e1f3513a291a2cfe40879a102f876682","0xf6061d3830f036758534f2dde632a46151b1012e4e7aa63d9f415dfcff5a0268","0x79a80589ae3bcf5603bde39a4bddecbb490827afe04fac301314289a8ea902c1","0x8c2d3f1468b8e6f1d1d5abb965d9ac02cdbce6032f875dc89b8e4670fa157227","0x46394c9b2b1da88740db457eb1349f4a46be2ecb421a4dfccf37a9d1b43c355e","0x4e9252af4a22562df61c326870094e3d594e13759b0625b2def2e2aacb51f65e","0x5a88c96900aa77d9324f27dc5d50e3823785ffaf4a24ba389e76f41b09ce3f42","0x6bc932d2895776e99d2934005fd7de70cab294de4f920c22c759522cb0227df1","0x351eed0639e433ba5e653f493d53088e0b5f8cbc5cccb033c3d5e45bfaec60f5","0x429f983e9ec0b07b890a0f71145a9639b0187e74c4f388631208bafd2e178e6e","0xb046006e3eb70a5bcb5489e936346bd98d5bc1e1cbd9789defba01df77b82512","0xfe13da4271856db0a369d88fe908cbb44dcc851a51772b5f0fffe6f50d91befb","0xa99188badbd1bc0631fe63342e1f2d646b031eb84f83909d2d61518fde7c0904","0x7098182b3ee9dda03baf235674126427e6d12c915b3a8a028b188dd76bd3bfae","0xc68834a05f61caa0acb0dfdad0fcb410253477ac356e475ddd829f3017ccb21a","0x42efcde4f910f14896871d407a27668c1809116ed7434788579675f971c55eaf","0xa63afa58e88935fd38b213f60c6988f14d95cc41f3eeb0722823287d7ddbe330","0xfd0e3af67e38c4970699ee0d19dea29d18df9e3a59989fcfa03930a3909cb15f","0xdcb652fe731edc3a58ecb6e07c09be96885d7effedef6bbf28611366f2d6de82","0x20835c5e3d3780c2db4f48f5f1f56a3143495657e8e05d69ed80c93b52a7cc04","0xaa4b5eba13376aa772207b47435f5d17cc17ab1ff896cb0471895dd34f71aba2","0x6bb53641fcc3aeba1127db6e46e4835e72e83bcd7317c20e87e5a5e4cd6e0edf","0xd6a34183d179d5a05e5e988841717a388e7e13c96b977805c9af833b86813b8c","0x139d91f69979b162975afb21fbc141b30d4cddbc13fa2f400681bd6dafd0abcd","0xadd71ecfa8d73b807ec7f8b0a4ee8bea717cc7677d24661b0b7e8bf11de346ae","0xb0127e12edd401e9aaebd5f95931540cac19482108ce7c8164adf5a63d7453b3","0xadf0422437c54894a1a96a941685e40950b53fc68a5101c399f97a55899ffb99","0x2829a184b0da5c5b4ea1233c4d46ff6ce683f61adccf7b1a3018e3fc719ab6a0","0x891ff30060f68ab8eacaa52c87217bc51a5317a565d3d2696913f4a30d9d5f0c","0x5001c9f3658265e3a09147112bc4d49af1c31d552dad51146b5622f55408a66a","0x5aefbb7102dcc84715ecb92de7bc22202828bab1354d3a97596d9ee287c9136e","0xe05bc64a17ed2de7ad03f855d9c0dd9092bb60d52b089fe83beb7b22b6c511d1","0x1afc489f57b3b0b00c3be7e995791495e4d703c3a722b39c151caeaf9cb4e0c1","0x5f2b33e4a770155a5b15e877cf8c56d06d4d16192dcf09e403e92f64bf65304b","0x9c18829d583cc4219d8d90eb025b4fd4f5dce3eff41c7cf5f75a4962ab4983d4","0xd6bbee63b055b931fa3decced80d4ecbd595d692cec89a0bdf22058e1295c841","0x330cb35600f7622cb0fa664b9f3cf2ce76d32f7a20a589df7c4ede78ecfd3935","0x6c6928e84ca7db26789e4bb79bd396dc4eb8079f339b724fdaebaa082ef05a87","0xcf8619340a1abbd728aae1f9244bd1ac6d8cccb2a5f8e6d46e655c3b2186d724","0x7c536ba7eb4ade6ac25ac8a5d4f9e5db285205c58e21cd74c91f9d713c744bbb","0xe9946d4d54eb9aa84bcdc59f7613fd25b37d937590711cc0d4c7f04a5fd0df23","0xfd3f2f1030667a51f977ef8abb32bf2dad7aa5ee38fd9ed537a5a68de1ecac24","0x63fd4995b6eac808a629c108c3e339ced24d8d39e065882807a8918d61326a2c","0x74ffeb1f3439f3be0a0301188c1c7f42c53dcd73deff668b96f168a13033002f","0x721e8e30e16c4359b009c8a32cb1959bea7791b9bf499065b84ef2f4de30d256","0xdafa44a07f563fb926e9f6db5d9570b69d445b002826e229d03aa35b8efe65fe","0x5988d195af836ae7e52cbe624596b53c189cdc86cd6672f3bf3abb88de6f96ab","0xd0fbeca2ebc7572ba2d9902925ac59383c22337076666432dbb5d48723f10acb","0x7aaa816f4726a2b5fc0360e8c7ce28a7418ff77c74f453f2474d9a68b87d4a08","0x13d9d8ef8e3d6bb4b1e4884f97825baf645121b3fc56bc16453eef9f87d16cfe","0x967db698e478dd038e91ec3e581d77afa0b19864cc9d32589c5ce23d9d97df8c","0x12aa0ec5d482b3a63e778e5e37f4ac436fb6849027f7f307f9e86427b22700a1","0x6218cad91f65bb48697ab82bf3e5147e4e18beb278012abf9096acd65c2bc723","0x8ef3aeb0f03c36ee7300f22c22242f72bb539ef25778a5f7fe9fdf654950d7b5","0xae083ef33a17cab6ddd245051f5aa4fe18361b10ac0ae65b0a991e949714f505","0x767bf6b23cbe9214eca3caea28b2b857bf7f74e6cd0ce70ffbf92a0f3a067ab2",null,"0x4768ce56ebc897a60ac559eba1f868fdb7737941ed53a589a6953206b6480dd8","0x58ad5784fce55502dea701a564506c5e530a666679f7d12c4ad2a4a07b453626","0x995f4593b98956c478d88eb727bfed5e39ab61afa2f198ac525b954d9caef8b5","0x2059606cb2790503cafe49cafe3e2ee237313eba10a85a67bc4ac279e2630c7a","0xb43114d95c8e2c8f17101187f4322a54931886341da1c072518e35372c562985","0x52f6189f1e7f1438187a6e98f56a7080c5484682c6a192bf442533ffd9237c02","0xaa685a68605906d3d50cd67ddc24c8d7137d495d71c03fb3c1aecb7182dcb98d","0x54534accd524e807a14b9c8d0f916758da05a758ef68693fd360d221d0d0f883","0xfdb7c14ce1b6fb880f267c7b17e3360bd482ab2d3e3c6f762e99ec3aa34a3236","0x23acead0044846ee0b009f31e6b31899d8783bde0cce2d444b44d4aeea798958","0x6d9a5d528b351519b9a0355f19461567d3fb981ed6824a39daeac23100703a86","0xb897ce8b8581867d0d9dd4a9fbe15c2ac044dd8cad1af805edc436df1beb5532","0x3c58be5ec31cce77df1c9ddefa8e716b46e3ef1ee51531732da8bcba62e95052","0xf9832de22612b4ee7387b6cfe3dab927a8a87d28f38d5690bc7ef0b9b1a25f07","0xb8576b1a6921e16554b1bcf74c8d138fdcb3f79c36507b1b38a3514b8cf5c462","0x5dec4ef1913aa0435f774f526dcd4e37d33192e245073e5983d04b10a55cd129","0xc1accbd3cbac4b6cfe41ce60656bc4f598d8814b8632ffb610b14b3d2cb15087","0xb418a3e848b27ad3f6454ac03d0333966417404b7049c696a623d830aa3d9abf","0xc342033434882860e92a03ef351900a6d6a84f8f685a8d2d2b3a3637f48389d4","0xef61cdecb0c0b9d3980648398e0d590317b1ce0f6967515f4d7f0d2aef8190e2","0xcff4a7ea805d522b0d20cfdd973ac002d27fd2e3393378f4ec645afdd613a7e0","0x48d7a42b12b2464765fb1efce293d774102e713e3a303d0abc8726da80efc907","0xaf80d1bff6ae3409eb3228ae98a5a9f517cf03e198c514214aecb127ecf71bec","0x8ffbad511d1d89ce2b3c5d3bb94fe212dca57ac0cca4e8876fc131c43153f165","0x1c56b5e25b7a80d67b46f0f7990861033b28f3e807a08073fee6499986e97874","0x2fa05274a81ecd478b41bb233f879881613080c94e48a71c41d55217d976a36c","0x316cb665be07f32ffa31b938a65d9d8191be041747b3f01440104f65e8dbf2e6","0x623569b9f4dccf8ae3d565ff651d2505f73139fc5dcf2b24566e5f1285c7d728","0xa67ccc2b9c189820f222cce7168f8b797c1713938fb0383359a27d679e390c04","0x0f7eacd1cb24060f20623858c8cc5d44c6015c4446a39ef0b42d20f2502ca054","0x40d0e80f41bbd09acb9a8edc2b4b5f965f7c4e4083a55e680966c0c842c88aa5","0xa97fb99ea3847bcfd9d5509ee5ea22d30a206d6ebd9946ac8c94f6fac6935253","0x9dc045255fcd4fbfe845993bbc9a485aa692d87cdc38214304936f11a8a5b045","0x9637cbbb3a0108d3c29f4068ae5771b38c2169b09255e71c29b6f70814c67bab","0x5f64c5fe5b6223b1bfafbeb5573d03ca3bd979d360f230890c910c033227f8dc","0x287c6f31fa83d3c06b620510d864da2f0a2f4f3097caa95968e0ecb5a9389287","0xc268fdbfefb634ccf21f96e546fd3fa0c10190f8fb6b36506c2e385ec175f121","0x3ffea9084a6d6b82999db323d0e9a897ea4e0e7e4da0a4fa655710e5fe8e9783","0x017cbbc1db840435ba48d0f96c18dc96d55e154fa7b1275e787cdd99a383ba4a","0x90ff269de775f82fe1b450b1ff480e9f72ffb64f40769b06bf85fe26790f4a06","0xafc31a2f4889d70a5baac302d6241509fd10ccde3c1ef086ced98f265353560d","0x592649261464185dac1670503f28fdf110251b96219df4f028099a549df95821","0x00422d953cafcdb0bcc78d8dc9c11f77e84e2372d5f67b0db2c8fd327fead349","0xea9de18a278618ee844e4674332cf5dda2eadde9af811832b12213c138b26500",null,"0xc7b09f87de76d5c086cd98636be82772bb2428fec01233a4b68a63fff610d91f","0xfb8327a1d23d56ca27f87f999a2eb838c97e930c57529a19abad37fdb041bb27","0xf8e5b6f992bcf88a32889b002170f8ba35085c0d08e3854dd8b2729508d00295","0x6942d48882b20d08fcf3a04f3c95e2809baa1daec03a4a36b878cf037847ec48","0xd1e087e81f1d11e1c60e455d2fc128c1e8462bf423f14b0d5a85379eef1f91c0","0x6e9599631305d346ff889dcfb50c487494451e77517991f79dc10fa6fea54077","0xb11758823877f3fc26721b21d7fab2e8bf3796ea3383089231484aeef4b70b24","0xc6be87feac451cae609798b8b48171ebb26308223ce3239cfcf0013fedb60324","0xfb70b141d1bc32021fc4cd1a73bc2ce19d88c4d0db406fda558176a4f85a3bda","0x718ec68a3d0de12e7402364b8b4d521dc83cb69724c65826ead442ecbbbb4d7e","0x2a03dc2f2ff713c3d91bb8ad57ff9c4c2e9bd10edd41dd999fcb52e6dae70f9d","0x34637f8b30b5cfe8a4f6fc112811a7c48f3fa4f250674af4cc15b4bc0ae7ce1b","0x20b0b75d84f491cc673ee024781562eac32802524f1dbf366172f930c02d018a","0xfc5577bccbac851f677ecf9d4a0cc3c7af59a4095a92265dd07c246a8115e8cd","0x76be43b76732bc46ea8ef5d37123ddf2af59cad3249cd2d54c043a2bbf6213ae","0xfb18efc5fe0812ea61c4c5aac59710e0ff9b03b2321fcc703cfb12076b0b97ff","0x44987a3be75fd078b839849aab9d147576073f5d6cd21686ece3ba61d597508d","0xc94a11cd6cee13176d8f8a93189d32d9abc7a641d42ec244f6e9c78573e3f055","0x257a60ec4e4fa8cdbde6fe3d12678a1368d790d726a666a004d325b70f9f0929","0x5fe6947769ac37f79e9598a5d5a320525fc6899be60ce332fb2e111d0a3a89ee","0x4d35c701abae2b05dfa90516ea152b5ec7f4bae852af456a063c04164afdeeef","0x9496f40042cc8a1fe78979e777444f053e8ff98d0036f0caa0d6b30db925ebc5","0x3c399219f1f0c2d03ad730ecf6ddf7a307bfa0e0e34b3089634b6479d5a44d35","0x0c21e30916bc5e28513f69fc8b195c5f4cea8928abc85bd7528fac78bbd7f5e7","0xdc69234fc2ca9cc19cfa1ca926a2553639d5b002ba22e69585a2034075cdfe6d","0x035cfc4fc308b88620f43e8a9c2d51706e07e5ab875b591ed7c8c7aa6970c17e","0x9eab839dbad87b442284f2daaa162b62e10ea3ae695c720b060b298fc86f0604","0x3d8dd2d72e4565529f50f76c34697c5185700e62a403bbd0c88ec53589066ebb","0xc934e0841ece9956083e02a01cd029ebe0378199fdf2de4b3a784fb55b29d490","0x93d69e11d49a6ce6f6f07607a5190df78be08e996e6540168f80b3aa4a16029f","0xa57a11b051e4a07723055d60248aae689ee4abb0275cc7d0396c236384af95df","0x696e7e00d0abd44f0793c67394a46dadb19c7a2bbed1d4387e95e3c1d06682be","0xb2106c0cd991a4b91378691fa5b629402cdc2ba426d75afde7c4b034d4a1c467","0x14193b5f1949ce45b539fc94c9e235a844cbdadfea55df95084afc132d236684","0xd4db2605659c54789c05e920088c000b0e48cf549061e3e69d3bef1f114f34e2","0xab5dc5a90c718181b0a49ef0e24992ba944333cd115acc721e1f3988795a0cf1","0x5c227146b5152f82a800a927fd6d8df32ac0b490d6a33a6456688d9b7a5f599e","0x1ee8ae9a2d807e8073bdb1bbe38b65ca59d55bf613cd56e6a313e282f9dcbd31","0x9be0498d45043e6a40e1bb61a35e1365457d25b79ca73295a0e8c0e33f1f6231","0x82c1e1086b873f446c6333a8c6dd80a367e45defe53469bd77aff957d5f0833f","0x9126363981f06596273f77e3d4a1177005a63656560bc3f8591c8ea75f155580","0x1d9ddfc0eb5ae6a13ca2563cce57c1f3d7343eef4b610d869537a9192d87f95d","0x7cdce92887cb773346786af162ad1c8413cd3b20cc348644d06fa894a9e3bf27","0x56c235715d1c64aede8edbcaa9c3c6cce2a837833a20752a9f083b7e20459687","0x9633fd3ad0097740c09a6f73f937aded7225edb18358019b5d08edfb9a22febe","0x5fd837ecb677031a72ddd97a35539c20c24083436687f05fc94af60f9df95509","0x8b4f1772af124860d7c4816008aa6521d9d1682601ecaa7ac51dedf5f03a9efb","0x8349525e423c211a4dda752fc9600a265e6b4f8536701756f35fec16af4d3026","0x96250f70a9471a8144cc10b891d8043dc45bf558a35a0acca4a432e245e87cee","0x11983d872c5142922415715444f00ad9e430b422f32ec0c5f061d5e98873989b","0x11e658d5877ed0bf0561942e7b5cfa0a725e28cc16cfde63ac656cf0444d5389","0x442f4fd85115e4e0b60b516ec5f545242fbfd29c06d2b469c4c102ed48006226","0x5558f25d5dddd214258614de09035d50e7840e6214fd69b651f04b825a8121b9","0x5a7638ee527ca8a067493861600d7ab0b6a7beb74da6de680351dedb9b5da30a","0x9444b4e8ac878952b55455fb656e9ebe1808a704e86efd90e9560364177a1457","0x441a0ff78bf3a6f4ffd7a2c7fdfbc3da8d1f4d299b6e29da8173f7636d77b19e","0x3615262afaa7b70abd50c2bf70320c29a51f9a26e7a62eae8c408df6f7fdb8a2","0x3c68401814014d88f10d3964993e7cd25e51e756abb188a706a86aee62c26aef","0xe997c8e032bb46a481836131d6697ab144535ae4ab66c724ff18382c339ce54b","0x3b6da3db5a63dbd8bfe3a37b3187d78a2266a0b6b1c412db828a2b6318fa0c57","0x49ecc44263d03344dcc12eee483ac9f668d5cb06684bd0e7af4b3636480cf959","0xb29c2b7266f5bf5722a7bb2027d9d329d27faa719291182301620e7ab3410760","0xa710567783a5448939c8b434aff4284b20a4de603422ea6a908df201604b6283","0xe8d92eb6afec5b301a34bacec6b7ab571fb475010fb016f28a66bed17a95a034","0x8174c5100d940fcd2746948a32232b94cb63f70591ae5c34047b6e820afa0968","0x0bcbdc253bdec8fada32e0980dbde8654b306584294c7b26771f8e31aa072187","0x35a49c13868e0cf40eb512cf5c5b456691ba745f9c9b9dafc6eed1b4a6faacac","0x8986da8942286048bef75f6a2782bc233f4d5ea7d0c74a04fb3bf692c0cdc2d0","0x4886b3783237ee597bccb6ed42dfc3418645be5111384c940830a25c1b8e9e02","0xe31daef0f6e7e11506978e9f24bb7df2dffaaca0e98c55ad5bfb8bbf545907dd","0x248a4452a23ba3c3dc2e936511ecb02c746a741a33a04dcae8b8fc7e04653178","0x0ca74f37ff4e09f060289928f8ab9598637edecdffa7a69222cd19e944dff761","0xd1ca2b6e0cb2bd8f0f60eb0cd93e9f37b31db9bd79f82c4d32549d5ad3809968","0x39237d7be8cffef0c6ae7b1b38715b463775a83e9f2c8229c26e8e12f31bcd0d","0x123de0f5163bfcf4008b334dcefcce7893fa0fea3d14a46393828b145d2e112e","0x0d91aad009e52064be17f11365d6df09d7734fb740e1961564b61c54206f9433","0xe517d34ea4d4b4720978bd837f69091a319f3b7c3d616979afe386b3358d0f22","0x895f1d374dbd8a7777e18bd8b0408c2a09b109b9b13121854af301ccae1e603f","0x8e114cf9812502ecebe235e4afc1d921765c892605463391ba3fc9aea481c846","0x3a066ecb2d72a36711eaa2747ebed38ed222dcef7941fab62093e2b10c949905","0x34b7902489cd42c0376b723baf09db54cbf35843dee5360bc718f89e4556d6d9","0x7312a8dc6fe60a5a9a77540435b7c317ada95a6c09a87b3cd210525345d99001","0xf9b1798f8a445a4975bbad2a6c656f263c435f042fe9df1baad46044fe26fd85","0x3ca1686f31837be5b385d91bcdc709cb938968f45083f06f06301cfa0482813b","0x98c87886af2d2e861c3b35035bb6f00d071b5f802562a7697ace4173abe471f0","0x9e3d21ac6f6cdb65df03accf9f77024561c76cd54f6b8634f883865c62f0da62","0x7b37a5549d756131452c7901c8fdeb108035098a6f8503e554270370e87f3168","0x9adc30161e0af934262fc10ba0fa5609f01398a58943054f471df1c8a4cb3a82","0x1d15d897679e0d947e14cd3b9a25c0e8a61483fe7517382bcbb29c184a8cc4e5","0x43c523b0cf693d3e4cdab850bf70c92eef8671585c659bf640f3bab7734eb372","0x54377ad4b24a15360296ff5de98d4c46cc8202e5f6e3faabafdb57482b8afa44",null,"0x2db5da774717fce631d84ea572c0823a4be25821d878a9cc7b330aafe7ebc803","0x39d27bc8ef793023b3ce65aaeb25ae92220e84eca0c33b76c7287b4ae1c26623","0xac20989329223d4189d9dab890c1d438c9253ac8aebcf05eb27970aa763a5cc4","0x6629c7b613f10725450459a1562f33f47fdb5d43161264c03a7bfb30c7b6e257","0xaa4d337df5784ecfd976cff097f98c261bc89357fb9a9b30fc78a233c7ad4c66","0xa1771e82aedc25668b198c5edc6cfa3e78e20cf482e1c96e4358e0460556ad1f","0x87b43610d4c28fed0eeda889a467f1777bdc7fd5d9df120114bb013ceabfc441","0xe4383e46a6e1baf00eae95d0f61bf95462fe8e1dab21b0ba1ba3eb9ebf4d2b7a","0x193a8998e90bb6f337bfb191bd36a058361bf6571bf864b026aa43cad5301707","0x8bb5ff5822676eab50a914e7a036c1199011908dd27d7ab9c3799c97c748b74a","0x59786b20d1715ce671c8ba1068039ef0c1edc6905295f807ab0a81f34e49c4b4","0x616bfbb30566facab29afbabf449fa6e3ca09c1935de8b623e4320f6884eadda","0x30e51e8ffad82232ffeb4809a2d5f3b2657b29759647c441dbf648d8d323a9b5","0x313c809ef832ce7f2a3664345b45782f394e33ea461ce51c979a7c17a62a3e59","0xef2ec93ca714a23f91b108e7449166ecea7618ee832daf2fd32e2c1b6808e0aa","0x8ae9d3c7d2f0fc3113ae2379f121eda2200c22cbb0e4d16fc22193117cfe1439","0x22554eb649460f0fceb3589863b09d9fc012ebd5fd91e29e63677efa891727c6","0x36eebcd544fda9b2974e5089209f00778dad967e6f84cb282aba280bdc1d70e9","0x5b277103f731b5ca6f4716fd46b600c1c761f05837b58220d0946faa4d8c0eb1","0xe5ab91882408efaee83889e54c6b9efa9cf9ef588078e012e72e0515bbb9e41a","0x6ff360c9034eb9e8b0ff1034fe7d3f33a89153df8011197e48804422798dbaf7","0x085d0dfe016f707fcb23cb3dd4f7f61a887effa62525fb84eb7e2c47b11c32c2","0xa0cb2941bbf3596250e18741b2493c3bd4d139701aa44e2b5827263ea523a87d","0x28f303cae0a783e8666bb66c14ab13e09cdde1ab439d9ecdecdad12b66d99104","0x78b78fde565ea4be27c70efc411f7fe63065047024978c9c5fc5102e5cb44eb6","0xc3acc08764f553787e6b527f954455fd7ac24d89b6e52f39ebb1b874cd9b5021","0x8d5ba23e36fb4e626dcbead63d4a630adb2e1fa2def1c9594cfcea3fe51b51b5","0xa4de7902265fe85fe5df1bb729b7b4727f05e6c36b788a77f6d97dd6f61f0e43","0x9807a77c8705c5c57380a36e8b175497b30b8f63e72634ade948f23aa02967e3","0x36b70ff8147f3349f6e617d6c96771b115f94b460359ddb96677b5d1faec9cd2","0x77e353e2ffe6fea1dabbb02f76daeb3cea9f32a829a057602cc4647a51e5674d","0xe6147e9e15590817d48aec29da77a1386c65f226b218c019e767b1bd3b41ab37","0x50795a4341f5dee89896b2456bf16d13bddd933aabd2640520513736d36860d9","0x54d7087c0867b316163454e391880332d27f320566f6ff1e3059b61a2d981911","0x50df441e583b0baa8ea31b3f909a043641544b69f01de9309cc75b23716ee8d2","0x387ba7121ae3a3bc433c94f549e71112620cd2b5a2980d615e7e1f4bd0ce9300","0x72b072155e9900706d9a16c00f48857abcf3cf0bab275e0a93a4eefe9772011e","0xbb209f5da66fada437aefd46dabb93b2e82f25998292ffb804ee83eff92eaecc","0x25cdcc6df7072c7a69400c9a771a5309d0e5a82975f83dd8ab0c44bd742166d7","0xc286ec92d67876c6db3431cc8bfd1d3ad14334eb4486832410f349d410015c01","0xa550ca9a3e2873fba33a63ebae5bf735c3de48a34ea44880fc90cf22dfe23a1f","0xdb55cb875e3efcca0c255f75575d7eb8a1c314c9e6958d78321fb37baecbb5a9","0xec2846c8121d763ee5cdcaa7ce48ef4f2a29e541ea2cc6e935fcd5a6956bf5b3","0x2c460302196bb0cef00cd3d41b54e2cd5e514afc3575c922beeda2c3a996fac6","0x9793dff2717024c74ef2e6313f84587407a5ca668de185ba6fadae96449e691a","0x4abc3b276d96a08be0e06c6d115b8a081cf2a3983d1d3115396372b01fad1ed2","0x9f4b0b33ff50cc3cf453a15643201247837d5a45aa4ac076ff20abc13e61d8de","0x352c4949f7ee5052e33d62615fd9434ca83dff30696dc8103fa9e5fdad1901d1","0x63f15771997fa23665ee86c09b72f37ebbfa3f60aaa3c2a20323e8375aa557a2","0xef9994f577efe99a37718417f12bdd4d4b30f84de36e6729cca3ab140a665cca",null,null,"0x70d1bbd4513bba520f76ef2ba19c98ff5200a48de586c5e9ef06d1d1f79f5d90","0xddbf948ffa3842f2bd1795046f160d762b54eeda8f6732f76027572c32d046cf","0x705ffdf8112987ff93cf85f77703021e4b9d38d1cf75e76b3811896570debecc","0xcc36f86c1c1611218e1027bd130feac9800ebbfef0960d94dc0fbd256ed944f3","0x73cddd49bac97138c5b65053173ee79e94e32ed1a0cc88a1fc567218f8c7bf36","0x3aa25139612158bc8ec37cf77c2da53fef007070097b3f19ec3b9797090223a7","0x7a2d4319362b8f933870dacae993c26ccd1309c3e80b9af0d84a8b0975d6c2ff","0xbad0616a4d2b21c9808be765b79e373f84d302f4d9de111e87604772c01d278b","0xc20025cc32dc7495855fd3c9ff07f972b39e0e4f2cfd8b88e08a442d6ecbead7","0xb85907ca692c8bd66ee327c886ca7c1b3568fc70af726da51cf92d4c68cd5def","0x490efc6dc0f0ea800f79e1d226f60964be8335429d57be98b2451f745a7b301a","0xb1790ebe47879f016b9807641d7fb9d75171f9b1800145bf3b0136d9aa5ebd4a","0x720e768358b89f358bdfdc765c0aea13a7990dba73200d2e2aeac8fe34346d64","0x1dfdf9fb78b48017c3208fa6b1b2e953ab72209d624d66d4fda31891e3afb870","0xe216d43437184385262514591af42b6cd9694c4ae3db3b2856f7040156654027","0x9d551b438ac1ed40adddd09243edee699bb989e2b19236f4d2c0d6aaae70cbb4","0x3682e47c45c7c70a02959e2e23f92df821bbb5ef124dd061252f12418df520fc","0x2cb06c29686f16feeceebe89d79764e95bb03233bde18bcc55a392e43fa7c14f","0xae535c3de5548894f0c25a9937da1321cbe37d3b7a1c1169121bf236ac9a1b80","0x8db663fa57e69fdee0ca75e4c4d7571ffe1fe3b5de4330cff5abc425881df1b9","0x09ff335acc21c16977299a26cb9323da5be2bd6221ae1da9bbaeae6677585624","0x212e50e33d5245e5957c6e8c59b2f9e5df7e8257c31ec4299de4a237a50d0b10","0x06b4daf77caf7ebbee6e03a9fc57d919ac0973afb372c6ebcc356b17a656baea","0x7e7e7fd69588e39fd0003745049028b84616fb10f6b63abbbdbf81711c916516","0x121b98664fe2e0c1736407754cf55a6254108f9467ce40a86511910e8e289e06","0x3f5a75d023bead3ff0d39d54ec849507175e0692b64d1d3ed08ef33aef66c0ef","0xe8fc6bdb218f04a2cac14b882ce07b6a6330cc306059855bf6700d258f0b5ea2","0xf6f1fef8789745f0da9eecea4fb24adf1a685598f7c1d6f77a1eed00b1711b17","0xd09e4178d708013ed1c41e3febe8ad909103692ab26801e303ed154f4038fd68","0x702b6184de800c9f42ac974bb0478257e403c6d7a0183affce458b0672b76254","0x9288df5f2fb7bb432cfb3b126963f056b82cb0df42dd5bcb923978769bf425a3","0x6df0069b192f04cf818862bef82e2b80ee361963cbce89cdd7d996a7ac7e54dd","0x15abe9113309e2a219760a42eb25ddb9e81897b543fe15af0ec63c07ce8c13f0","0xb69b511a894f354395e491b5ab7bb1bf27a1e7c797c47d9fda3ecfefda18cdf0","0xbaa43375375ca2ea83615a1f1dffc8b9ac143ec48f4a777d61874de15287be2a","0x76bca5f2a6c3467fea7d710f72ef44e235bf31a4271da26388ebde59d035b533","0xd3b0521b76eb29fcfa2f0c34c4bec5ed8dd2d77a33bba084939755a22540d84b","0x7f41b313b0d9462f50768d18f3246c29e74532e0c74ee3833dba83e09aa8aafe","0xaad3d1afbde782f68a8ace29e902c4ff904fc034f1a41d33c21848fcd6746506","0xbbb7c1083dd8321db067f1fb677e0d5c2c7e1d68a52ada450204e88dd860bea3","0x45be7759964963ff81874cdc1145a678a265026adc7d14ac71afa2b6bb7c0bb6","0x1cd964d4a822241e4af5813687fa0de8e08d92127436c8b5c0e134ce063ffeeb","0x8f6e69e1175accaafe3aed4415b90858fcf65cb4957561bfe0d454ead8e0e7b4","0x83aea6c068777a5a66f27b878ae81232fd29236ec183a3d39e0519c36985c3ad","0x741f380f709de5b2314a0f1640e51fbdea29d1f1d7b83654b8ead13be4c4c95d","0xa861682dba921821cd18fe320ffafe26259d3de6427ef0392fd27204fb37b22f","0xd7b5fb94f751ae5b8d158b3986be40125b7e17faa0bd8c0bf907967e4106d64f","0x7b4b875ea0553f38a87a5400d71d0a5c3879e127c5ee1d051825f997c73f713c","0x3efae9076cd605d8f20e1a21a7c828b7147084b4f9938db069979f176917765f","0xf6dfe12cacab58c23177b7ca21dc89ee703ea016ae7145d7ce405fa102cca087","0x89e8fec9ce757a4b226433ac1cccad63edc12e466321f12721fa30a93f96881f","0x167a1d77f4623a5077d9eff4a4b75ed77b6428cbe5020a41c483ea82deb49ee4","0x7d948f25241091604b5a0ae398f6cfd4d821d27a884863ffb929831745ca06cb","0x1c0e1446b11969855dae51d8c1348d938c5218128466547f904f5077d5fc723f","0xc3029fd167e859ffdf74835681c6fa2f8b3af9011356f3b2d5974855f540100e","0x6e282321b57b8c6cc44e36c5b0c4b08c83211ac6c0814c698de48cdebb74b65b","0x92082098e3a62ad777c9188c087afa338c0c9de03a8ec67968f090be6a1b9457","0xb3a586e1ed21859189c70c4a2c8ce91908987d693e64a725bbdaa4a07cd0ea66","0x5af9a7689701995d233565c567c064f26fb4bbb2c4ab283cdfede42225d108c7","0xc0a67e164b70c69e941a111dc3f353e8bad7b257e07631e2b9147c33c1cf5f7b","0x488f27300b910f3b7fd54be6c8d52c2aa92282d77208103e54b1bebecc25ee82","0xd548862ba8d9a98d098e1bb9cb8db91b7a6687dab21c8d0c541eb749db8cc211","0xe222125196e405032b11aa957fd414c17e4d3f218be228f6fb69661aeefec9f8","0xe7c8d157a3b7ccb356e1c9817c0bd7919f9035d2f5955f92f879b8f259de65c3","0x2de230322d0ab40d82b48ba9feeca634d0871c9ee3382718d8955a2511031759","0x0b1e66c388322ea11711a978f38851609cba7e202e17b1e74fce343404c51dde","0xba5a522b5577a3ea466b0dc6b85f86c6846ac6e90fb2ad92fd7f273b04053d79","0x9417fb866eb2d67862fb0993088a7cab46f85e548881f2c2b660adc6054760dc","0x0ee32290bf81c1062ef98c6deb516a31d9f1955461a6cf69b548a45ee00c1943","0xfa83bb2300d8dc8b5b38bc96c3f3871c6dd2f6b714babf725ae45cd7f88036a1","0x1d08b888e3b5ec492b8dba10bbbad17c7cd44b6b78d1a248c19428fc373a3755","0x8c5be81af463b13e0f39df8cc0d7953e2bf8c129d6f7a594414601ec7b3f51dd","0x546a770aea4b3520f342cfa643eabc8e581185c8d2edb2cc472d973af9d1f56b","0xb47ff8681b36bbe9f2bcb0ebffac631680b2305d4b117f7507b9e4b63d3e9ea6","0x2f127df8dfaabcbe5e2944c0069a57ddf114b8685ec2e6457558e0e9e1ebea7b","0xd6969e9b14d1426403c7a846acf3029b3e0da75ebcebfd238f6ce98e55503262","0x8b8dff5d70cf120fe68f6f760303d6d9a4b5d128f7ce0c07eb31cebd696cc64c","0xc6cbf2fce2b6b976763a93e68c00cfe4847cef8359ff5178663844282b1af51a","0x2c7cb12ef5e852a027120bf4003876aea8c86bd1480ea505869a84a718a3ea52","0x35a183720357f2d91daa1e104a247ef70a2ef02cd50c3b802a0b3798a6ce6fb8","0xe7419f4ff8fe1071cb52b0b3f4a743f09cf4e41b9652d4547d485d11f1b8f57a","0xbbbd3ab490e0d2af9080d18b94d0de0e3b2eb66082f720b7c76c3e463aed3366","0x883b15bb7f4544f96823c4d1f6fe23d4baec493826ce2579cec6523bb910c34b","0x511c5a985d7e80e4d8cb24fa3277005d39f51db1b0ce869419c9e439a17cce31","0x3364355266f1233f92223279391c081428c04493b11eeff40637db2b0d1c52d7","0x9d91bc26b932bd1620b6255d3223cfcc5517b1e35c3b160a016872cb6a4ad0c1","0x50cb47633857706fc5544aa1a6c9f254051d747a4794d458539bf52ffdba4479","0x1eb1912cfffdb7fb0483c5afb1957a29e2f7006a93889b236f3d4cafcdb89f8c","0x3d3dd458bb904f430373bc008c2d77757718815f1c12739c0daca449bc8f7e17","0x1720b151061b204e064300b4b8e6e6536964a22999dd589432d1070e6024eaaf","0xb27efcce3dad630cc868da86c06d5af7769c48c08c9d6b9ff1598c98bf089c3c","0x96a834a53ec3dd824e29324ab39b4c0331d08ffde104eab1f7b224304ad52bc3","0x373c796e4da261f94dc60d97e7cb988a89516a1bcf7c92f996f27e4fc7a960a6","0xa36fed1f0ef01315379655bc584e722464b190bb970092b02920bc974a453911","0xf152fb2220e894018e274c20453e97e69e55e709285b7e6f432448bf0974f4ec","0x1483b47a4f52daf3fe5a2ab26845014373a7fdafe0f36d1a2bbf4640cf90238f","0x061054e890bb5480e35033921eb7286f7e31450da46d3a64f15cfe28ddc81923","0x91425a360206160312d8ff0d0b448d563e5639edf2cd15050f5527034bcb9822","0x7650bdbc8880dac33961041b91fa70b1a70627759a26fb2e13b5662454f5f2ab","0x4fa245ca94373ba7c9a042d94a62d2ab7eb07ec826e6f275d088e0b1c1ca1e2f","0x45540266cd191b9f1b4bdd44ffa9d1e02b5ece2919c9324f7213645cff8fb389","0x24a3d62da0e4a4736c62a3bd2c3ccf7b3cf56135f5c2a5f6192c4fde3cbb8f60","0x010a1047047cc029bfd502ac762733e6abaa7d5277e9d46a4193b1e6ede52200","0x0935fef2471ca9618b2a46ea676aef00b5135d17a400c41014eeebb7f55f8311","0x566fcb8da2d9af0af7553ac76c55a80aeb06c0823245a2008fe014be05b8afc0","0x4df7c8e95fb4f3de44dbf05d3f1f508ccdee80d8131525b414b10716549f6ea9","0xab3067c0c7f26dfc59363fbc7d31d2bc2fa13f6928cbe071f5387e3ae25b8fa5","0x49deef65ad34a890b2bc87c07a00435886e9e8d6d873dd633fef96a90cc0f24e","0xa90f1732e93ffba058f32f93d91d6e194857290e6625cd9155e95d318128e2b6","0x7d86ce6374176c14d13db5d9db13df85d057584ca0ad5f0de8ac9c39325d69a4","0x0c78ace4a43259a8c068bdda396f436aa74d134075a84c2ed1664cc4c08ee860","0xf146e970b89fde617257be622988f302688338f6144312b37a88699c73b59696","0x59ce95347081579239553638774076f3e30518d64b7b39f4e333dc10bfac9b2a","0xdba1c0f6d3a1c6ff6be2ee85572c5072b7a3cb024e958fda78da97caa7955baf","0x4edcc4d09d5bace441f7e5df0e94443c15041079c64c3f812ad2be903c967c59","0x652438a13a774504ba794ea7c837529e887dec1839c5b6ec1a87f059871f77e9","0x76147e1421a182e24f2ee2e39f89048543b736fbb6426a562f845a2529bd9b2f","0xd8f49d017361b5bfed8fd697baca9775c357b87488aaa65c8288bb7aa811a86f","0x4b2794488ab8e3eab5625694de928c9a1c23f6e3e6390b30ec68d57bdbb0e1e1","0x042069ac66d4e8a1c48e3befbf4ae1214e57832dc6496f7dfce9b6f6234f3875","0x7e827c96538b3728e3bff6481613a2f9b262babe1dc3badde204e58566b16fd0","0x58e2e925f3cad546f20c933019e9a3d30f3abb4aecedbb3664649f4194818ddd","0x5c2dc7c2109696756439d84a9d3f856b61ecb3e6e3b9cff95e336a92ab151e4c","0x0bbbb3553d6cf3404275e3794b1b385a1700f723b81e0589ea39969b5dd4e147","0xcfee61b9e62cfebd9ba41a547fb75c18f191d1ba5e8cd405156a8ab37bc58a66","0xc56abe21a8cf7b7f5819402bcc5889c306ab06b7a6528bb2a9c5fc6ca13d12af","0x50ac8bed9b2668b8bf080a2f803f33bc933c106412bfff5746d6e8d22c3110e8","0x04a576696f7dae825c93ac7ca044707b1817762235c17a8de5f6447ff80944a4","0x6459849602be946f4944f6e81fdd9d115900cb611bcab75f9f57e4018e452d91","0xd45d47bb384121b715182479e38ed960aebb78ec4d08d1e0790954e4cec4d61a","0x173c1a4bcbc7a0191f991f1bfd3d1be9e79b6d77867da37e4f1332f4e3975f4d","0x62adaa77141fbd495f8b2d461ce8c495358e5dc2b2d3ddc1c6f5438ed1c21f05","0xa354ea877d2ff0d5bed98b941498f7ee573f7fbe2155a3e761eb95bd3b90ee43","0x683d9a7ddc8524646681b625f315e066bbb68c2e38e9199ad6cb80585e008afc","0x82627e8e2c729ffa506d07c7a4240e3b3aab829951b7d79424bbcfb6217bf9a0","0xb2fdea09d2cb0f2e49bbec8b969c847149384926c270b82d1756a4a40bee0c8a","0xfda7819412938dbfa53302095fd6ea2df783ae01c584644a02baa6a30f744f86","0x78784d468d7b34d630da5055eacb2ba625a9587cbc21b528c4ca2bf3cc6634c4","0x9e706cee3510f33b5d5d583516e66b0164cedf53576b86783d3da401fb5a0b9d","0xc7c776f4df8f3f55fdd9a2c06c26e8c9d81d4a0c4c8471e4517a1932bd4a356e","0xa9ab8a55a445d4e4bc0d2327ec1eee4d1f4ec60e435c1c52ec59851a1c6175a9","0x5ff583252f0f553d11b6743fa374b5aa3c60bba2336c49c80c90585174482fde","0xab1707de7e1596c6ad847deecb7f041ef32ea062964f8724e65fedb110bdfaba","0x0a1e7be99bacfa9b65439bf6b881f89d9d700b7cfe1128dd35b69cefcbaf49ee","0x0cde78ac306bdde24f44fcc306e538ecc5922b6502d1ec2255eec13f282ec78e","0x145135145782195f3f1c6566de57552574c6212a3fc5013c5ddaf342f7586f47","0x0214e02087cc7fb3d93beebc87cf0cd1551149a7324f2e3778e4b4d1d63193d5","0x0c9c2710f894dbfb2f70c7fcef01a999fb7fdb6389d0f078dea16e567272f77d","0x92c5bee41786edeaadb3a1073966d4599a0e1743f37687217c960541cc32db2d","0xde93a7be1f496add4302f06f307f97479f0f12b6a69dc9a65ea2e9d838f53e50","0x6156e3b040c4c176f157170e4dcbfcabe630435a156e03cca54f558a14da5ff1","0x4300e3af24908b07be440028b42d6745680814159a6069cf32b0e7e9cae84ae1","0x799e881a53f85058efc37beaa2948b050a15c1b8a7f38e1bbc36c55e843b5744","0x25ae35c03826b4673549bbdf17633f1cd27d88d078c0d9fff5bdc2043823776d","0xd93c1c52acd857462848b95d8a0dbc36730f701a4fc8c6bf373cbc1f04b55d47","0xf200a477822fdbf20d87c1acb63c79424f4e6a1d930230297eec493bacd39607","0xcbd10e6c21170c26d44408298c80ccd45a9d36357dcb35a9707a73e8aae546df","0xf091ff79aab87f1dab1df460e75e0de45c3c77c8e0d83694f14a073e39e9c766","0x8d33fd12f9eacfe240eecfb1e636626ed25806acc5b2f7e6298482a0785defbf","0x33a1795429a7256a298fcf0ba7671fd8a1330e73b26ef87f2769a5c3c8d21da7","0xaf0d0691a67887cebe29a665ccb8fb54e327638990bcdf9c668089b8d537d906","0xed2b5044b57ab02955860e06a36f8dc350fcc244acd0086caa75b5758d6e0e0f","0xaaa16cbed18184378479d4183308390c1dbe9a2b07c93012a4440b766e01d375","0x77c0141a246d6ea20f6f6664ee6862610470d8c4801850c6881b81a90ceeaa1f","0x3c287ec4f09446adccf4099377dc2205e96ed8df5fd9e9e4168d5b9c43bef44d","0x5fb4b506815b8d782ca136780752aa43d48e0d5911111f7d058e137a1bf58eff","0xd8ca227b2c0f37ae285e6ecaec98b5edc5c192d6513c8e5439af9e334479ceaf","0x6f25e9941f699d44590e62d5e7b52e280c63464ea8983917cf76285bf6aaace1","0x9c48083dd5b084aa524a9fb1e951f9178be3d1d1c463fafbe5f28a8bccd563f3","0xb4683f6346db70287c689f611f919ab94e0db8b2f0c78d334c2a36e0880b074c","0x46b13f1e3b39fb4de55927ded03683800d03f74289e6622ec7fa8af96f839dc1","0xa050952cae44de8284ee19e9e945dec75e7a84f17bb56757ef148ec261adcc4b","0xd72e775965569e8c5c42064bc14ced4d502d83d50df65c8367d23603f3f4812f","0x3f3f14132c9cdb7c3415c2ca5547284123a20014ffa0f197b448e7e2cb81fdf3","0x4955fb2a02ea0c9fb63dee346baf4e09c67255f26ef31e3ce6d325203f735606","0x56e7821e6598748b8f24f866662b4bd11e7b4a6c5fe1f18314fd50ca77f75b70","0x1d0f2e949afdf930101c3e6344ebbc25d76ac28128a6937790cafe8b4e7aab47","0x69be4787446d2a6346ed3eaf49af4272368b32e593f147551253699c38478125","0x59ac82939a6915b3d35575008e01a8a73473a8c67debf8fca762be3ca23b3488","0x4b6c1290b575d40f249563d04cceef271b57bdb2e0f04344a411adcb719c8a83","0xf642acbfe5a62ffffcddb6092d08c081fe848d4da947e4ec34773a6f128563a9","0xb02100556faf37261ff2ac6c587daf94975f459ef3ff56284c664a924e67985f","0xc9dba13714d57caf0f09202ed9f6d44d79e8a4e7fc507b7870a7985e88276430","0x058c05a5a40342ba13b4d76891459be70ae863369a9293de60e2c4c502804628","0xd3d130caedfaf6f2dafef53174c2899cb543d3e213e35101ec142dd449ae674e","0x1fb8faae308a34874c57394e0baa893cdef203f82100fc0ded2b54046ad735a0","0x409719ef93807ecbe54704f418590baf2f80b7db363a7f4b33af54694c622023","0x9278bd49448bd6b4082986fd545529040f2c92928b363b003e3a9d61c551e614","0x065c3623d9c9e9f7a53464f83a43ca25e6072ac6bed28113b2944d9ce3b699ee","0x5402de2a31357131cd9608e9560fafd2498a0df08906eefae9c29e126559ebd5","0xc5c531b7d816f0b21a59aae3822e52156c37368cd8314e40328ffa94e42e6cf4","0x5a30dcccc2008a06acd4156d5b09fc9447b06f180da05c2bcd00b8ad143db8fb","0xe7aca709e5bd6a89652ddbb5696e36bae31b76e821c8f48e8875d5cdddad2143","0xa80a330dc65441cbee3b993f3ca0e57df9ea71ec7f284a2a8d5214f71baf6632","0x1515203e08cbf64760a6e3fdcb52308a333f4a10e5730c39a8c38fbbe826afe5","0x8e9d34b64c4ef0fa44c8d707363f685cb5d6975d42d61d50e9dc5eec08984bce","0x14ae854a07fe6e55ab254f6762d2b60f1bbd77f98ae32524eebc40ba946398d6","0xad1022f89cd8eacf8dd28f73b3c33f418cd876d1270b36b02ff8b078522c74d0","0x465dc0cbb323af9cc161c2f135082ee3fa6cc4b8f798d4ebbf2dd5c403f73788","0x2fb866b2bb94d693caa04d315c458792326c4324d8dd4a91447af1ed713f5c38","0xb23aa254fb14881d70258c843b6af26eb761498ee78dcd9ac551433d1032d34d","0x98879e8944b2487e850e0f10ecaab48301a7d064fc962a49009d9d33e9c5f860","0xc24c14a7da043727efcc10edb9dbfe56d6b6fa8909513af8dd3622eba06452fb","0x6ed6fddb8bbe70668cb9aa4a61b97ae8ab44fd9148892e6af387f18485683545","0xf6787bd10a31a70bd175b64ba58a40c7dd555e202496feb1aa3a0c4f5e2967e4","0xa555173b55eb557074bf21ef91026354d807d27940922cc859af9eaa9e56158e","0xdf38a8d6c879919160e21a3dd7e15527956e019b32f092f84357126bf2c15d7b","0xbfca11965a1480c465e6c6d88de54f56e0ba8d219454a6a5a4eeeba14a09ac81","0x703a87c78bb3159d59afe17bab4c2f9bb02d5d9ca99defa016c9d3e86a444b87","0x044a085699115894c9a434a29572c03f03b08ccfdb321c557e7b18c4bd6ce90d","0x5c19763dc9cda4049fc02de25ed2df7df1c35dc44f46c20ae6fd52e6551aace0","0x7f9174a6f787c02d84405f8c6fccc931fc1463876e4a2bb01d1323279f58f41d","0x45b93371e1d941d729b836cde29ba23ccf5571074d296fb36d174359a19c38fd","0xec57dc03713396709a95a2b7fe8d6c97461ff33789f5062927974fc42033a2c5","0x81d11ba8c02795130a349ac8a1fe61350daff49e11b443f162d09c9d06233dbf","0x83fc974f06884155166c61ad3e65eb03c2af9dfbbbd8b77e312fb1116158aa71","0xe5f3ea6bb87bb303bfa4b0895c11693ebe7eeb3aa418012621c2512512ae5f9b","0x5f9b3c2ceb63ff0de6b08834be2fe303ab06d50afd21f9e46c593716c2c75d69","0x2ee1d526647aaab1b163aa1f8c26d58fadf2b8181d6ab6fbfd5ed7e797f4cdad","0xc16604b4d9f9673f28f66321b4277b606f1473a67a1714df51e6291326563a6d","0xdea52a8562f5382dbc2dfc2e123fe04d6b6f93c264d419a32fdfe1bc3528bab1","0xcce98c3ab8484ae39a2d85b0f4f3ba8f9305cbd8ec3b247dd5c583bf3dbffff4","0x3b794fe216f2425230b759334430037593be9ca319a10daff00ad7cf02c08ca6","0x36f0a1d63edbd09932f376bd46516b4ad55d7e2cecfbadf4293358c7a0ba83e5","0xf4bf272fbfe85cee8a43b1ea1c30ca7a47a3cbb019025da449f4da9bf6d8c096","0x0474bfb60d16a62126c64f30812dc34c01ae8056e6cbb22a59eb2790cdbe9ec5","0x92e103597375c06504015e4497c0c741c1332044d3a31b7b520ae6e6b88645ff","0xcc12408aa9104371a7fbffce9318b66469d3eca4a25caff5d25fd6a6071b14c4","0x98cde37601aae4ceeaa2f51d2f26fe8458539acc391f3b236de20d5ac4452f15","0x4e92bb19dd0163ab64d5587f4805c916ffd4aa7626c794b689308b5c24dae7b6","0xf29106a9b7ee8658df6c6ce2aa517aa8a5d08a8dd7d95e411f0cea8083f5d6ef","0xe86e059f7083a1a281a3cc677419fc00dcbafb3f0676ccd0b8be426793ecd78e","0x44b99bd7f17bd76aecfc09f1da92cc6992764d8f917bacde6623654d24892fc0","0xd814e46d88169575562d7948efb40bbe3823cf3a83b8f7d04564170d46a9412e","0xc76fc21558838ee3a3dfceeba8857ebb0a40aa991b85ef622a2a2f3a407453e4","0x04ac5a3d4a68ccd33ab30c171c59faa22446d95e20dfa91e3e7d941472bf5e77","0x91d49f81e119361efb07b6ed4b75ed6292c33f656cecaece3f5b176d56448c7f","0x53d77b29f6b32eddfbeb00fe7bf70f2cb6cc9795b2c80327b4f86a5495c6f0c3","0xa06f08146b232729d3eeb13ba1a4719428d412a68051d48ecd3764bfd6efadd0","0x8cc34e86d30d35b8c07282bf791739bb1d7060bdf42e0aa84ce59fba873c463f","0xa0849ddc14410d7728e5fb5d65b23f94919729d34ae013dcd6ff0828022c4dff","0x9293272f55c0fd4bb30a49a0f9e8f73fbe3976a5b5571f138348322e17b6ddea","0x17e26ad3861a61c45cd963f99e14ce5fbc35f92d6887c57cb3cd48154d15c586","0x23ff30613cbb36dae4a8ae1d0f228ad17d3cf2359205bf5dbb25da2ef1c13fcc","0xfa0e12b6858bf19250acce9ab80045e04a0b56457e2487ca6dfb5bc7bf1843b9","0xec7194c0b446629d4a15f097ce2e9d935594e146440d155cc54ad31926022c40","0xd79a2688a8e15518be19daa0e06a42c386b7873422d47f1c4dc713b11635c845","0xae24aed06f9394f2a6e5a33e295e50df332257db4b1d2d623fc00e2416df4524","0x411ff670f9fef7b98a879494e50c4fd9d79e7cece7050ac406aab8bbb92cf62e","0xfb0a4c570cc2346a790bbd19da38ef1ca0f3e68e5cd86c7d7858037642401ff6","0xe1f2dfcffd13014d8460234fd6260ab5cb3c24e1647f11961e1b2d41493f82b6","0xe332ade004ad216cda39c4d0b52db5f020007d47aa4b0f13e5450a8e2fa98f4a","0x6c597bdab0e3650ed3fc9fadc0be46d1c08b5c993016d2c24dd2c19dba8eb1df","0x336b0e64bf70ce74d268b1be38d2036cba167cee374a01e7082734eb3a56c941","0x0d87261081e1e2ab733d8e692fd53aba987a0ed8306f9c84335755c6b901a9f0","0x0798f160bf9bcce4aad7595f987dc10bdc06262b1a1c1ed4fcefe56dc1cc5bcd","0x2929d4fd06d033cdf5b899565dd986b9860dc8013097e36249d4b41d2b053f74","0x7c99c0d6a71300fadf8aa59d7aec487745bb2738a716fc898f28651fdc03aae4","0x9838950d1507f01a5f0cee1f9864a2f3ad1d30b6c83b528a29bd37ee9a2b1916","0xf00fb6fcf4c2c8cabf34314af6c067ecba655c21afc64de2c664651c579933d1","0x9341bd7e3507b45f340fde48545be5556943000693acaf364b4d78ea53a15e56","0x10d79241a42095244724667572bd070676a9eab2fc653826944ec327d67397d2","0xc515e236b4d489e38065f941f3bd618a74f0f9ba0a2d6617fc9eb311901f6530","0x8bc990908d3727d0581c3aec81a07df241cb9cf501aa22408b0284178e5e272a","0xb41833b332e82a279f4d3ba1152b8e2a8f751fde909e6bfb9ec08d05146d5d98","0xb5dfcace304c7154996f42d2832d9df4430f22c270d7c7e750269ecb62776117","0x96021d71eccd5c9f4c7f6a59f22a4c46866ce98dc760a5167fc9b822d84f64e8","0x5275ce82c8addd098224b324dfec76f6d201e9c6fba25d6456a5ee06f7ab9c76","0x8a05f3dca3c6e7a174f9dc605b85e1ccc4bd3ca0eadc3213a97651975322fa05","0x29ebfdd7748442ec5e4a2c528b418af4c19ae1c90acb8b8e5befaee70b1c2942","0x3e0922d9b3032cc732a73ec5b8f495adde91d72916914f44995fe876b45a305b","0x3180b23aedeed703fc9a727395693970660933fbc6157699631694a648c34015","0x9e545d6070bdec0624d917406a33ff5a8c00cebcbb6cb9316cf684bc8b4c6727","0xf04c0860f4dcfec963058806e49e889cc542c66d9e9a72e8ab7a2483118ee946","0x46d27fbc22ff0695b275fc68c7e5783045f82dd392e73ccac8cb2810c67cc311","0xf91d29e75157af67e2e8b0a6598b771f91bd753df74120859ed8bc32dc4a5ed4","0x0e23f517e33064e6d5ba68c8ef0008715dbe59a45f18fc92ef0ff54f8f907256","0xfe5099f73f57c96a013773a4300fede30f9ca199e251c30910d3ea3c95fc5a31","0xbe0e666f0f94632947a2225e9ab78c54cc26fdd0915902d285a2a95ee83f315d","0x66e70871ec78c98683b62b799c410f6e3186b5aa500bf91839ca7458601a689e","0x34a20d0005534183cc4063be2fa79f182041d03ebce64b6b6cf9c34efc3777ec","0xcbdca9dda4f868d79f76e5543683f1b1295f0fc92db6f9b8af263bddeb5ed830","0xaf01ba0bedb927fc99c36c444822e58ff9fa6c8aab5350389e812324c3e2c583","0x69a4978bbc0ef842f0684efcc0919cd8ab4340cba18aa1a584ed66bbe6d97364","0xf76ba2b448ccc305ad23b8ea2848a1f012b1cbce5684591fef3017530a1a9d6e","0xb8a7e07f81bf41c492872175ec7e8d2ac39898531c96ea5266aac5f1a55f1869","0xf3dfac355ec404b9345df6a56b3c12fc83c3f22c9bd9327261f230575d48105e","0xf5706fee7ad7d0e31feedc8b123143dae6189b5e785ec3e66f31017466ad7c02","0x74b66cd9379ff4887eead3247623294a4b004aec9c11669fd97e287f773d6abf","0xaae435b0557a07b5a74c29b26ee8b59367f90fe89793b2c1fc86ca39129afc20","0x65f72de0717aed3b7644f0dee4f804d6b32f91834ce3d31119ffae6d8ed2a2b2","0x37ac16d4ef4ee195b4d1b16f49b4e62aba702a5b3880e3f6aeb999584876c722","0x7598b58ec15f784e1a6ead80c99663d4d2e6ec84804b46c266e7711af796bc32","0xc9179cde1f511d1d462873e69c7e30f7ef9898d9059df318302d800f03d413e1","0x08bb387ca126572d9ac0671b539b53a0ea1ca18063973271ececd5f57ad3bc2f","0x05de6e04575f55066fe34b22408b3d08595014af4bc46750f0304b35c32cba65","0x5904fb6926c9ac6b5ceb3fcfa5c6129c1285b4dbc01d4d539d9d1d6d1fe3065d","0x5d7cbee416c2825db5b9d21a2a571e51f618cb8136ec9e75e30f5496162bde0d","0x97cc45e873f399453e5e42c830f2ec2872d4821f70f44dc3616372d5115a9cbc","0x3b7f55a86190cb959f64947af9c42531fd8ab70db47a3c15a2d0664305abc40b","0xb2624435157712e6a38b8a2a53739765febb804f43306199bb674936f677401f","0x415a33f004d132dace1703602c446180166cd292fed5fe6f67ce308cc0123ed4","0xf7fe7a3d8ea48386d4b86b1f35b80b762b7361cdbf31396b2273e8279c47f1e1","0x7354d900121382ea496f1eb14e68d67103140ed90e42695777263904e636a828","0x6118092657923aeb9bf25050a385eb6f9cef7e3472df16e4c6478a6675e68922","0x1c64aaa0783205998c7d700f40c6216ec94836a304cf6edbcc4564b6693d7f40","0x64b72054fe44bfb5d2b6bb7e17bb87de63e0a4fc6baf82f01bc8eb9edfd85863","0xf12ce92f970def1408f8222f0edbd8bee86602ca4c154b48619c453010d61780","0x0208a39233a42724245e598a0f2603bdbf96a256d4794a6a6e93cd30e20a62f6","0xf6753da29aaa26720e63663b029745d3b443bb163746a4b936fff6e9b26a38e8","0xb5c914b2eddd03d72ba723ff381e56097edde1d8023a7df782fcabaca7d10e3a","0x206db29b4c7c96ca2ddf01d627b15606311ca3f16f4d0fcb3e168d4f85a34a56","0x753a32261a6f3388da2b7390040760bbc20e26efcf9b9db9756e175b019e1f86","0x253e9d2178a5a918a6056406063f39907b2ca730a18643e4888424ac70adb151","0x7e33bbf487b1174913b31c8d99c86bf1401087bcb400b20d782c8046324d26a5","0x92ca163d1cda1975aa95d44443a65927cf29237adc9ab5b66ce58dca30841c19","0xc817d132460b565b93e84ce2fd8b278add1f8f7234f3a367e79cfd88c6c74e59","0x2171a7e20b9ecddab50d6c8087f7b9c4c55509e3a5af10a9ee997133d08f79b9","0xc721a5ae469b0f61abf492225482a7c869c847b636f02046928d5d0c4626054f","0x300951118acd97d907b3cacf92a8c04f8b891716e3b825ee31bf3b0849ff5583","0x01b8c25c488e2c82f68668861af0373a02a06e691b3c5085cc293fb45f8327f3","0x60f19d278eb9b9c64058c7716814a96bdbe2b68c32b40dbcae8184b59a909962","0xd4b386ae8f4467ec67e43e93c181752ad314c30923cc0bc4caf39a22ccea0cb2","0x73f5f721b4effd50ed25504fc3c31a4531f92c808fb104b930fa9e5f0920c3d1","0x81d686ce50803d2edc066c33b3db26e0292df122c188ed3b7bd663c8df7571a0","0x55fea9c7358b66956b12b0238b7cb0499732e9d27df5a99cd18c8fdaf4182e3d","0x211ae933afba764f717c1ec53450b6db819c0a0e3c5b594bd460020047288952","0xf74c89901c10d21bedbaccfbdd735d3043fdbd160d4a7735a46c8cb12d18e4d6","0xa33362a8457369bef4c9c73f58873e4a8f4c1bcfe25ad2b479fa733b1c25f87d","0xcb81947205530ab6bdbbb86b21e9636adc1f76cff18cb2ac0f514b3ec99c483c","0xf5f9b361cd259c05fee818a3252242d0ff166332ef3f366286059a968c11bd97","0xff41b29870e3b070e0ab6fca0d3aeebe12836cc3df6c21618361c4c551d98338","0x1bc8291fc756846e8ace19e2220f76295659402ee9d34b1aa497e3a0e84bee58","0xa99ff49ab3637c633e5155a28cfc3c4234301ac891a29f9a79b4159167be68e9","0x09d5fe74f69306f051ba473486d107462ad7494a6c58a74fbf89cfa3dd45b839","0x29a11d0695b397f4c4a8cdcff3a0ff785397543a51742bf518d8ba3c20d83a8b","0xc9b3da580da360415b89a5b1140b8615d27a9d601aae8fa97278c521cf3abeba","0x581a2f6eae00447c2b6afa8b38c0256f8dc7b95be3f7f25ee6d6d0e69b516e0a","0x67ac015a54e461efc170780c5ed8d5e998c2657ff39598f628ffba471f288d6d","0xfc3ca636ee7974bc4c0a50d8e606dace2270f681a59ab71fbf9d1a16027b859b","0x5131199b01ddd908f06b964ada2e91ca8b7aaa7519d07dabbcc7efcbe4641392","0xb92f6a58cf42009cc05c92b1c2a4d04dc385fb0f106d56a9532ae2356fb9b6a0","0xf208050a3d495f303d13770e6adc6ea00642479ebb2504ddb98206ffa703d249","0xccf69961599a47138576f10e71b9d10477064b02a3091c585444c45be3680444","0x6789311f0ff37b64f6015558c1abb50b1411ea618a896db3f4275a7a267dbeaf","0x26bc2970482d270965f5d622c3974c0e4ecc61bc39d30d8339f34a99fae9f25b","0xc9e8ced121321f590937e8ebdc62f5af6d70265766b650441efde07c42789332","0x83119e387c365b7cedf7a972ba5775da008e63468d2ba63fba8a88d40342fd81","0xf631051da889aa0a28c8c8ab57ba194cd28319df80cd1e0f15d333bd3e8f894c","0x801fc4db58612f37b58aad909adb3d14135674302bd8e64a958214256f80ce87","0x2548f18d7e2c38c1bf130b4095f2a570e51cffe20494392d98dcce69f39560a0","0xe1fe163fab3d659b4ac445441418cc696cbd12397118374d26a45909e08e483a","0xca7a20faa0ac98db112080a638c2deaa40c4d26190d1277d44ff9c2ec5f71f97","0xee8120aeae60ea22dc8701f681ac2b09aaac27db2d06a7d86dff19862d2e5588","0x83ccabc17dc0a6e5d2d526ac33571085b846c63e7675166dcec3de52bd8e21f5","0x8190eb24de3f4a9fc2931efec7b82e96c7e7c4587a415ee021e7219e2dbc5ab2","0x33a78d59979fd3ab142f442ae317aaabf0ba363c2c8ff3be53c79b54ab6c4b2b","0x59ae6a315a1ce47f4d721135c0f7e9da0f977704a6d52f56009a10eb73c67213","0x10535d51751d685c1a05a4baf0875470d643ef3b24291b7058221270fe4c6d65","0x0a06d149544e17bab43427b92ba65c0779cad7e85e48619f3952f06311ad229f","0xf6e57092a3ccff78b9c9c5b2a66c3a4cecd2192fe968699cecc7df96eafa572c","0xc7a54c48307265fb3c4f5013d80148f5987d2703e73e2818b352e03eaca12e0b","0x866c3857006c36787820e633f95c05ab71cd107f908cff0cf3a0e096a3c6cfd0","0xe817301f2bc27f783d39f844b35d6c057bf4fe81b81fb447e302abcb4fe6d137","0x65ff4096f1840f96e447003b7b0bdb0d29504f9d08b3d1521dac29dfdccc764a","0x3a61a8e10f19fe9e4ee776bb780b5ef1b3284ec94c385003e885fd701299d787","0x61faeccb79a4011f6ee03fe5172a13d938eb768f5063683a0c83ef4e6eb0d432","0x4ac91d33e87560e3306308ce60eb056169cf15feb4b3608875fdcf8c1918802b","0x43cb4e41c399888930ae02cbcff21da21fff7e78670d1695c5badb49e51f0998","0xcaf6b2705f6f734226a4800c95b2ee8cea45d254b5534ea6f71ecb4d132e5de5","0x1396aef9e46402d6c6b895e37cf2e19a9952e5856bdc16448c7485e466072a23","0x0b678d3b986cc2a55a561d8b9423bd074894cf79a6f430d497d686a9e1ccc84b","0x835a480ad3c3fe81ba07208f42b5f8088f6a41cff8ba8d2fffac81cf3b21b12d","0x1b77696a93cea4f28588ae634260503ca3fa2be48dd6fc799d8bcda981745442","0xd6d9aadd366d3dace61688e9f4c18324178cfeab3ec91e39f3ad9bc9e22de496","0xfab4c5294749eb6f9077562bcd227a7c15fdaafd864b7fe533b620578992975c","0x7c86f60d754c07045ce69255e7e5ba837a4f5ab6bd82436212f9d671336fdd5c","0xe470f9784aebd58e7a11e97261e7e2739a42cc4e4b5e4b8df439af8532787418","0xd6e7fbe9d0ef56c07f31dab93ca6cc200dd94d6032cef3c4d0738f7b90eb6946","0x4ccfcf663e6ccd29886a48e7d69f1d76a568f217d29db63d663d95fc26c4e25f","0x75232d29db1f0ab581e5f5301ead18dd66f2f65f6127cb1abdee1650616d36fc","0x4da0b74266ed2c9b4500ad8e8d599333fcf73b5e11965dcf093ff05c191e558c","0xbe174b1261d0c6417abfad30a2b21546140614993bb6c901b179cf416511798b","0x3fef7d268eb000ea3078f4d9c7aac52988d22743e6a69659904583d296a5b227","0xfa1523805a24a080314cd65c2c200f229e970906a89c2cb9521e0dc424ab80ec","0x7c44decbcc10c5c676120f4bc03851b218e2204427b9965d9eed83e04d294e53","0x668233bd19ae3ffc034b79969158a791a89eb36620ecece6ae0ef740dc7bfe4b","0x45454e400aeffe713119ebf200ab8566e207986a2dba2b8a0d18b1a55de80158","0xfd945f870b9d055dd041463ad28d65c6716d3a041ef5a4593381a52ad235c83b","0x6bf988917e64f2f75dcf5d1c8ef9b4d88d27bdce7e0e49801feaf363303c6475","0x6797385ba0f5b0c6aeeff1c1467a426c207181662e38e7924ed74290d8f81880","0x115906a61cc63611008cd1af2d995ccab3c8fe5f9156240a29ffcc5ad4d7aaf8","0xf2b355108c3a2fedac5fce8014ef6a39b76fb1a0e35a30ba739577e45d5f74d8","0xffce9bca605a772caa286e78e65ccdd0ace57f338a914eeebf2c7567749ddcf2","0x045b394e61e5f241128c0514f6102ecfbf6d0cc6c29fa7eb3e549605a7eeffc4","0xd9f654e3499108bb10e0a2f86438f079c1dfbc12b7c48792961c9f5e9ff2b2de","0xe154c6e6aa0078cc434d3f3c05ebf407302f98a1f1bc510cf2bd2e7ca9056dce","0x8161fafe6ad06ec5835f0106ca6f79698b8f80075d082d12c301f68a36ab0948","0xe9863c730cb74b9c8738dd83bac34435b13f4ee2a9a4134783f68f40d8b9db6e","0x348afdab22a85b92cea0032ac6bb67ec43cb2474ebf96d3d8dc3f739291200fe","0x0ab7fb3b628d054c7db92ea60575d9eb574c258c2e2eaebe95b9af53e81413b5","0x57838d0d2831938401e70438bfac64f3721f8666d88eda5899b0e95e4ebb1e0d","0xf32d0d694d188130e9535b375db9dfbe244beb13b934f32fd6f2d5a5539290db","0x384dbc363c68e127aa70fa2288bd0f9b0e2915f13362f289751d3580945971e2","0xe500ec7ac9c41b4777e6edfea82594d8dc965e5fca77bb3654f8153340cd008f","0x43adda7e5b8a80ff13448dee3c6dc722ce921fe291df2523c6586ef889ff65f2","0x1e94a10f0a83e0317c69f81fa74c4c8b46cc7009f5501e36c3d2ad10099f343d","0x3868b32d610e5970bebc04280ffe49dac75ec4aa86f2a9b5d958950fe2f57146","0x6a4aebd382ce16712d1351094343f60e7242671cc513f5b609ecec8208f691a1","0x64c0362fcdf18ec038a89187af939989e12215922d711346e624f9c9f5ab230d","0x46dd8effdf91f0213c693170005b93212d3d6287366241eff8fa90ebd60b7c56","0xd1ac3ad8300aaeb5ab095f74e7796fbf0dba29b53e629443f8bf03424b956b7c","0xbe13e72d44e7865237b891dc2a5aef9908365d0516e8a3b7dab8e35b0a288dea","0x3181f994fb810129ae77c454f8fb2ae40f01c017ba657fddcd3b983bcb80f9f3","0x4dddfc70ad4a284ea93113be878fd34e13cce9316b86be06c2d4569e13a229d3","0x81757990b00a0a27ed7ce562b5fb6a5e3f85867ab1ba4d97e24bd78baecf9eb7","0x383a41690d61c7ca56d009330c937e5574ea83f93e7382c7416ca7e299403cbe","0x8d107251607a83e0001c10c1e9d8f0bef6911abba2ff8e63a34845d92db0497f","0x12ff7a1060a9615e4a586af0d35bbce49d5bbce2991fc3fe11ccccb4378cc22b","0xa060ec7bced6f20b33131683aa6420488f2efd2d75c0247b1232004a939dcf52","0x9e374e5ecca8aa0ae8ac2249cd8bef4c74fbad8eb0efcda9f2dd63d5f73563f5","0xcc741a0c36b2f84127d9c97ed2f93c9eeebfafed539d025e59f95b0e42fc1d7a","0xd263b817cad28923fd3678d9e0394890320b8fefbf2a84273d7d7753c6c2d719","0x72fe7cb27bc6104e4d087be842ba2eba7d08e0a562cfc2500e62e2a3cc019d45","0x3880783ca59fc48b5080b34038bafb757142368d63b889e7828721f4754645da","0xfce52cc70771e79f29cf5b9d0129dbe4318536015fe29fd910e87000b8f3bda9","0x1c1b2b3d76cb1db11be5830e9d78545f4183c9997d9f40dc40965bec97e0f24f","0xf01d0d84cf0e72cbf00650877a1f571ba97a063d7dd3628435a2820ea47b6eb7","0x02e93182eb972b7bddda9a455b37eb568f14c3d2d5374cd02d6705825c3992a5","0x88a33ed34d8f6443933eadf25cc3e2ead02f13faf0c6c81954e90e46287c75c8","0xa4affb7045bd7b0944e6f3c41166933391b0752aced1990553c4aececff1ad07","0x87690d79f53d64681ebbd3425242c5a5ee61a3c36093c646d23ae8200673997d","0x361e0d5d657eb276952b2f402d7b0caec2094dd3eef998332b67e7815f78f1ba","0x05cf9b25acd50ae3a753e00118ef9e3d4c9077c552175505a4b9d571d07f1495","0x9286f380ba28a52b491d247b79458be53c4cd5316c3654786d6e8f1eef1a0e61","0x50dbeb0ed30e6531c8a3de3fd4626a5a6e96e36061ea6752c149572cf57c4bd0","0x7f4c024240694f08c6bbf57e3d6eb563d3706453922560e03c1d528da90d96fe","0xf27ebc593f3c599dc1e39a818e277cf1eb034fe26b4be063f65589e34ee45d4d","0x1afca2ff03d0de723c2428a1c6452e759c15b4f0555f24d869b2d7b47058c95c","0xc0c78286aa657ee33ae477921a5040a8993c444fc3607e1d3afca055a17b9153","0xa14d3d9831d0c4749174178e14089d8756fb4a5d128b61a87824a4dac2050eaf","0x66adaaa5598b854c366df7cbd4c26d6d365bb9194c2d97340227eb6ef9f9a004","0xb6e2b7017446f46c6857467cbed2cb546cb7117241e3d392bcf3304281df16cb","0x64ee9124645d7e8fb7094f373496a7bb70844968ec60cdaddec52ec751c5b5f1","0x13b8273ea984b2740c53837ae8a1a6a6c0c9fee39cf56fb0e6dd2fec21b572d7","0xed79dd808e19b0d535b951fb2c244523d54d91928a78299acb83dbdd454c47b2","0xd1dc64cdbf1af9a0dccd554f6e3e01fca9537d4f683faa053b7af9c8314a165f","0xf8c5854bb4699a535ddfaefda2fdd450a427a58322e0a838b2cce5789eb48218","0x92d733cff2fcc5f6f0427ddf5aee11911c7bf6e1e3edeb3835293324e4e308d4","0xf9acc5457f341206a1a52bf6810359f5e0fe288aff94950a860ce48fb1b084e7","0xb6e4f7fce7f539fec0bcc2ef8af7be895a39e0fedb372a16d571581a39a803e6","0x579563ff17af75359fdf836f44a8eb21698dd3ab5324dcdd9d2cff0ed68815d8","0x99ebb96f1b15786ff0d3a615c31e0c1d63134516e2206bcbfb76846d72ec2bbe","0xeafaa87dec5fb5f3602e4462e232844b1e82bb1496f654c8efad0c5ac994bf81","0xc4cb880a2bd4127b5108d4738aedaacf7b2651d4316f664643072e45daed5518","0xc860a669e4c0285d2081a359bbe54f2fd17f68348fb230fa660abe25b93b5542","0xfa1c8080f6e9898f4122ec2aeb3570d5415205666871f96046a0617f0420f71d","0xe0872bbb130ce5ff9fca691fac97b4d67d9e10e06e3664669fae518c5fc523dd","0xb30b0763eb61c360b0ebce6aad52fc9966f1ae89481436d9db4786d79d723eb0","0xfc5e16bfa08370398880153523ff01aae080c9b73398ce06ae1154613707b2a4","0xed02d5492e51998f458b14f98050ae0aa966112ae4293efd8cba2bf75b0ad25f","0x2861d64adf30ed36d7baed4335d92e6ae7a0e923eef5ec47bd3899ca87d6564e","0xe6e7cc5c7929144011ed45f989e5dbb48aae189b1ae007cd0aa357c65192b570","0xa313b96e484941605302463c2e9c05e709f5f1aeb4a1c019a389b2a0bc8930fb","0x6bb0f167d28831a27f440501792261805cd050383901484ece1d6f7461d88cf1","0x0c20f73b5f2bf73f84a89c3e1a2ab48b52f085726f80e9f8ce649a8f3e606665","0x278a3b8e6ee885ab3170b4f89e2d48d3080a13bc2cb0a3515622d5e46e7c0ccf","0x5b6e7c71e4f765fd7cf7a47c6894aeb600f8ae86d99943e709c845b72be40ebd","0x23466c1f88a53024413267da8d2fb38ae08734401e50063f77262f2ef31cdef3","0x1bd7d951255807f12eb3d1f423c2b62dc2fa68a4754336a05cc93ffdec292b94","0xa0428386c54709bbe2a740a2f0410a2f84acddb2f28ff3527ab6f885f105a15f","0x62de190a839b3bf9b67dfa82da165435e6e582737ce39f5b395b33337f0ba22c"],"blockReceiptsHashes":["0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3a60d4c47fe84c103e8c03e82cb8daa375a9d8b408df380eed6c913d0425bf37","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x5ef7078ba514851776eb062038d33dc7554acdc4c49fb723494f9e5fabddf688","0x5ef7078ba514851776eb062038d33dc7554acdc4c49fb723494f9e5fabddf688","0x32fa90fbd8644f750b350ccd5708cbab86028c6b79a004c1a2d2b834f6bb30ef","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0xf72f9afe4a9d8964289a6472717676702485512b2b35e3c8e6b40d681f876522","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x32fa90fbd8644f750b350ccd5708cbab86028c6b79a004c1a2d2b834f6bb30ef","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x4205e0fd4869dd39d3d73be63c9253a91985e24b2939b54f14629029cb58dadb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xeb0e9ce8951acd071c7ff12745149fb00be00ccc12d7a902f147c6179ce15e9f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0e3078921751119cc2807f4ad98d17e8b9007e5fa56460ab086151ed093c6213","0x4d2eeabbad4aa4cb8ed10bbbdfb3cedb576c49c98cd1cc002a0873e359bafedb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4f38d6d71c4f08d87ea69950ec1bcbc2a10dc5466eff502041f570943ab3fcd0","0x0198c1117fe1378af5702733e0e57b9a1fcfad1b4cdc27d8dcfe3acb08271cd6","0x87f6ca65ad7fa9af7b8faf20c7ae850222c51abfa4d47dd5d07e74d8e94de11e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4b5281177096f4af59405e05c79feb4d0376a6afc5ce1dca49f3e7b877e31975","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1bd1865529966aa4432082c43725cc60967cdf941d2668f5c79aff1c0ef41ccc","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0xfd889595b243e5042dd27ad4cb68d6bcec6fb0d466adba455c29c431e92bff28","0x5cf9fcd32057bf18e1276afca626ccce9e1aa381af30eb495b53147dcdd684a3","0xfca5002b5730ba3db8b0d5e94469cce9751bb53d634f48b352a249c8402b79da","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa32dee43dfea50ab854a3603823beaaf6e166d47656fc08326356e29d289fcbc","0x6955772dc11114a5ad3c6fd398b882945e6b8e62474fa37d00d7f9f90b830412","0x14a531ff466036fc51a51185d64c975ea68189b105835d1782362f9d0994b07e","0x37bafd16031757a64182bb45d928cdccd6c342c41c3bca011147c463ca5e57af","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xbb9243a393e6eed5eae367e5a21a62144afbe5c85866759d97e2509d609758d6","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x55f965959f0e4adbfd0df29c8af092d0240bf5833fc1106c817637fab014b6bb","0xb987b0264aa7ac8f3aa4c2f14fb00a92ba2fa23e1c31d3d79544a57410b5ac16","0xa4e71c7ad60b9a64cc67be6c05ef2566705d60d3e17b3fb7f2e8d31725a10ada","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x59411fd128af01a4e0f15a9dbfbb4089ccfddb659f849966d1f47992b41cc0f6","0x64f51b9defa3a01a76933ad33a0e44f9a8620c05d205c7abe48b5f539df7493d","0x29fa7a2446ec695bc13fc9ce3c3ae4fe2b52cd484cdb9316fec3c44e0cdb83a4","0x442599b6b168d7f4565abb288531ca66668421db122fc60ae0dde6d612473cd8","0x06a8bbff6cdf6e6625988c3c0c2061dc6367e16a57c60b968197af4221032911","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xbded0862b6248c785cb813213ec630972854a39af56a9de0681288e7b2efbc38","0xc4fdaf8ce7dace69945efe7f76d7f6bfcc987a3938c38214352c7b7ee5b11284","0xaf1b4ef9c0f88e1c6061936a1aff73612dccbfae923cff7cde404e9232c12a98","0x1d2b09768292c03a91194015cd17db981db21a05901d9c28c41e45bf13d30d0a","0xf3659f017e1d89471e681429d7986a11c7b82b2dd64928161fab7defc1a60bdc","0xbf356dda60cb31015f199aa603bf1741bf22cd162cfead4549c5834c621a87f9","0x3e5d8f7fec6127592803a94c2ac53b8aeb2e6f4dffbccac97982acbea3c34696","0xbeac4a6d90e62adb930fc045e0348b364d717bd6cc16ecc94fe0ac2ea14f3b16","0x4363b5c68bc300d5374c457f4c203bdf09a49e00f495157b3d80e19d54f0db80","0xf6a4623dafa4280ea62ea58d5de87a30cfaf090e62bcb5fad95ffe679eaf0fab","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xdc9dc4591ca77989e16d887ff1838bfafb164a54dd4495eb7d8fc21e716e5358","0x0cb5be4fd2a1d140eaea3d033046aef772fd2822a9ca27883d0326de554b0a6a","0xfe21e3f4eacda8b96e617ad45a3259c95f4f5da008227ebd039a85ec9ad26bbc","0xb459d617d54b53a86ca7aa677fd096b9b408f975cae22378f8df67473b66ea4a","0xa9a630dff6ea46f8b6b13e8fba0f6402443e950b7536678cdf0a70f4c1833969","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb7e05f98282d031b4f9d595901ad26e2946f267a7d4208df532075edc3fdc73f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf75f6aa4851384fc4044b2811b2b838a4e4d1d5ded10aa91d5d3217904ee8f8f","0x678f3736de21f2ae5a1788283e8066da5c432d51bb0955ddfde84ad727cd3eac","0xccd33ffa8e6b723e6222323f1a753471721c6b702e29498499ee5a993df51248","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x20e72f0aede089f0f58d7f2733abeeabb1db27bcf060c35fee2ee8627c303a11","0x4f1bba2c727b209fde15851480049297fa52416021b0e3b133aee96bb829cc1a","0x9c3a97b4744a3553ac601634499df378e0757feb878739b4b8d68aed12c9db52","0xf36220f5c942a175e2afa4e22901ef71e855a906442a082478b7a74b7e1bf01d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xc2483789d987caf235d9c5c8124e5c188dc03881f45ae511872b424e4adc3117","0x46ba3d0a99565de583631f379263ad6cc4859398b71690a1367d22a73763897d","0x33d783b529dfead2b74a6b9ff9ae4d321e275f7ab432dce937780317a07f7ed1","0x326ce3be53b9183043d5608a9d8a153feeaf25747e9d462f95d8b46e6c560b27","0x2eaf4b19833b6a2ed3f7b7ba285e4a6ed0e4ae9c6754618ae09c0e4893bfc42a","0x1d77d27d119e1c5701888b4f237dd31be40ec65583f9637ac2a5903fe3e76f3a","0x76765e323500485fac3db2b4b925b642e0a316d80550a16546e3e46d1733e0ae","0xf4bd9605ba1a043b9c17d3ddd20712384debb5e80cd2148817dd7fcce66458dc","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0xd421269f0d1ce5fd5468e2144d74057f381d42218e2a09d80e660010d0cbf39d","0x2ad5b1d47a7e097c6817fba76d6a498441f460e2a82e8c26410d2f84013e1a79","0x0d6cb49597bdc7037f1e4911132fd8c160c32255328b19b94739baaaeee1aecb","0x49ff2278573cc4fabe4d82f80f716076b1488079c06c48f93c16d5ee2c43071b","0x4d1b7e3206b63a6711e6bd1bc70738c28244810503df28f9749cd6aaa73576e0","0xabfb2a82f76e6fe92290f9368eb6e5feb577cd5be5d3c0961dffa9575da01c5b","0xd4bb63c1bfa6cc539d795d804054678c0565b8ab0f2192b0fda61990ff1782c7","0xe9a62ba5256cd3fadd24866b51bcd3027b6f55446827d3f9d90572f7318112df","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xfb65d7ca739cc057e47de58a508569b10607bce1cffc11a9e63a16dc18b3a425","0xf4c5dabc51fc5dd32398811d0d78a59e87142e348a61bd31e8409950778788f9","0x113f8420d496586e12dcb55f230c4bb1596154d8967708e1f49b669e30a735b9","0xb37d06f44666461ddf8ada257e4666db754441a6313899f85e8031f7320e992d","0x159945cbc03d2f9ce01ac5c5ece6019dd08d6e613dc4bd99d60c4835673fb8e0","0x9d0aff717863e587d1a65fa33da7fa61233accc19c1f8b59ba85df8066cdf1fa","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2411f3869b9062bfa1a85d32347fcf37f75de7c75c9b05f6632fc2c4bbae21d6","0xe39b4d20f8185a8a9fb0150be378531e350f1496d6ae2680623867912d446dd4","0x2b414e186583470fb502070c1d40f7cc9b59aac326eb854c0c162e189ab00bbf","0x33699b50de3e02071ceeb0dbf5af154bed299295fc3153efec88eeb26ef78069","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2e063e081b3bc6e465e5a59ae0b73dc1f44c6a5f9c9dbcfca0fd07052a5fcef1","0xa49351377460ecb5575279548021b973cbdad8ea26f874d8a208772a0a67099f","0xeffba0cb0a4a2b3cb83d1d1949c449b6e45049edf6991445382cef718d64b39d","0x4cacf0457a19f9ba0eb65745b6c49cf7e843e32901fdc4a912c293f90ce4b4e2","0x65bd4a823842596f7fd6c29b18129def99df4a504d8b171895ee6b17f644b6d0","0x0ce60c34d07324c56bbe3774feb6d4ca263401a718363887f61f5e39ec7d6dd8","0x9740335e00fb3c5235d685f93b90c6b857e6f3f8613fe13ade8bc17e43d60c25","0x3c8b289c77afdb7e471be9ba46d5e9ee0d8e8e8e681f6673d3272118bd82e2e1","0xef9047dfa0701cf93cb13ed1d21e32ece4fa64983aa4136573391ffce4c755df","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb826fd7036e9a3a0167990b59cda5c5c3835d36d27d89decdd02277186dcc2a4","0x40b33833707e98ec1dc2ee256dfb9bc071203ad775920cdc3b2a4201e82c2e5e","0x7f9f8076452623430c22ec4e61929bbc574cbec7f0489d665f5af434a3b8d12c","0x14313a5bf0cb1403a84ce02a45765ac15bc717436fd3f250e95bec9e7b7b483f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x4bbcec817d50768c8e60679f988e878542fe48b95dba620b04cd7db2ac0b9154","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x32fa90fbd8644f750b350ccd5708cbab86028c6b79a004c1a2d2b834f6bb30ef","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x97a2e3f57874835ae0b2a71cb16454c914da1bff00f2b9c4bb8277002611a4b4","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x9de88cead7e1f7066a7c0281471db2c8a724f1e8cf9e2d4f7d7977a5e08be3aa","0x8c3cb7be14853ab903d49f37ca19a55db2ceee0457d688cb5436e4711bdaaeab","0xf421a5e59255ba9dbd15e1431484c5f4e2735bf6f6e631d46edaaeab9a67f947","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x4205e0fd4869dd39d3d73be63c9253a91985e24b2939b54f14629029cb58dadb","0xecc45abfffd95439753951ffe98a50a87d4ed8a1e3f0107e6daa695f00c4c151","0x4205e0fd4869dd39d3d73be63c9253a91985e24b2939b54f14629029cb58dadb","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x23fc4848729a8b9afef9409b93c42654aa664195d435dedb0b89be8a1e22ea19","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0x32fa90fbd8644f750b350ccd5708cbab86028c6b79a004c1a2d2b834f6bb30ef","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6985220d515221ec5850c7dfc333808bf40c0602de286077c88b07456899f951","0x73952818e1734c33e1b3e171b0d280f89335abe31de7daea8da0b6d08f6d569d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6c22eff81db28a478a15f2120237c0ea96afea42287aff4557b616937f1b023e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xbf000d0d0af21213edd5c2ffa167e5d9ad3620aca1685a8f7f1a3a8ef36e91d1","0xe448128860bddc51af98019ea3ef105ded78069b6ca76d4a43679326867815b9","0x1ebece4390ce30971127ed9d25d072cb3497f6506bace8ccb986bd024a403e6f","0xb29f5ea88828469b67d003b12f5989f954e0bbd4e6b0e03fadd93f56b033781d","0x974bc01b4cea5d53126847b4ff9009537b100eda6934a27965992307867395d9","0x104713feaa934b9891d26797e47d76bfcd9bc17ab2a572ee97d7123443edab7f","0x452883379244b17284c705e7533e939d74ef56be7d90e374bb23c20342b7c4d2","0xe5a92af3d6115e9a9c683649f650ba79fc676ce26f23a3c2203de8d98b8dc607","0x4a1461e4ef5496203b04b9baa13ef0c5438ad2f3dd455d93e4c1bbeab0855f61","0xac1b6f29254cf5e37655ba7afda28a9af20744c777b4fab088ef0067d1471cbf","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb9e740f6af0de2a027cff17bd434648a3eaa23e86a0eff3e25392889291ba4d4","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa36da8f7581285c555eb1072549cd0cb31434799d9523d02a5e89e363afdca64","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x7de898fef0c537c9f0b9e61f82079d7639e9b9108547005accfb953aa77b9d82","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa6687a2c5496438892d490d8bae2841058cba3b0110fd831f05b6329b9cf4441","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x1ad0152b6c6fb42a4975c4a780ec6a1237a7b13c31722b31e6d1a78020650ef2","0xf35d67bb412524157a31fa3821f7614de0c755da01bd8bb8a958626af1f75995","0x0b4c5cda4122d62c052ed6cf99be121422e64134821d1148f86dbd9dbb0681eb","0x94d02c46fb1ac00054ba46bffa3d11a5c343e538ce08be7ba4300d695bb37a90","0x1a275cb543c299803ea76dd18e616a54f8d665df1c36a3d48e6e377c104cca81","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x7765b7eabcb7f58ad00f9bacb48d18d59ff87f1e7fa37eec6058225c1710d464","0x04e38da345ad67b7fdd0ca4c53763d11ba0b1da5a53fad512ebd289dd1df4959","0xb15cdb271378c65df82add92c5361927b9edd9141487e0154afe9132dea74890","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x46afba54dc42513606e8a808e8c3ebb3e0cd7b31f970dd522a5415dc49f3e3d8","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x774863409459107792d9daeba7a647c1cec10bdb7653b6c1cb98ada7cb071b2d","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf2adb1f56a09f96923e14a4c13a918b5dcd87f5f5a0f8396c9e71d266c446ef8","0x285edc7a23d2f07888c8629856358643a51ed1b471a0d445eb52fa0b7921d25d","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3f144555a1633c267b40bde69d88a29181899640eb2958a0420f9a663c0d850f","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb486d3f692fd3859100f77329de385fe4127cb9c1bef587428d1983aacce0d2e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x7361b3fd5b0fe3b2e04c3aaaf167a2160e5af399999863c09639a9f923d7f9cd","0x0a1e4d898d91b45cf1381c2bc54e015839a4952732f89867a57c4db94adf27b8","0xfa63f4dc85291cd1afc10e46e1588693aef1b7e66686fa06860452936a8c3e31","0x414ba264b8bc0be2a8c689059d3e2e062a4f4fe1dd4931e034b05c440d6846b5","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x146ae426b0bd7ae90fa07baf7fc349bd3be46f93c1d531f97cc4ee7e4ab8bd5c","0x392d145e652442aac34846761c285db6c44ff2908cb2077e15dd38e7098b1fec","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xfb757af993a4d2f9390237aba8c0e17b406e7f7566919baf2588d3e5316e3aee","0x85595137bec1b940a5e12030866d6544a37fa18ed13a1858ae62b14d119aab6a","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0xc8fdf0398961569199ed0f1e393e84454ffefa9ba6854e6d15e770f6fff0cc90","0x9f337c9b4b7fd8d867759aacff616c3a9a68bbc585ceabbb871520f9dfce31e4","0x60459ec04d1eb8a0cbb4a43be569e80f5478e090eb337cd5d97f0116d445a0e8","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0f341332f860a9e16fe7ff0c5a6d4b1e66ef14afc15845b7334cc9f00c618232","0x4d386cc464357f951aa65859a834c377e7af6b9afe4264994acc140bb2597da1","0xacf6f6dfcdc2d68158d5c7aaa88630dff5f2c1f29a6b18f5ac3d448d1b8b3b3a","0x415bf742955397be45f4272ba53b4f92910d9cab38d6291f4f37befba00f039d","0xe0eba8622f5414cb6a326bcbe6ca1ef5f23f25658ca2912c4cec02dbfc9b972c","0xb1ba06d01d8bd47772aa92569183a48245f67c31ac1aea49c1498675153d6e9f","0x9c8d9670096aaff2bef9beeb7f3747b43749f0858abbf9a0123a500eed7a1174","0x3e40a09766c973d66757f3fec2be6fb9953d71a90ea70b74ed8150b3a8e4594e","0xe9f10d298fd82c9782e012e54e28e20fe3806a5a493fc6f30419df379950d6c1","0xbdfb8c9b2901536025755e0071f0fda04abe9720de9f8e8f316480abcbfe9ba4","0xaf2ba086db6253cc0f850668448a1061e1ea8701d29f7ea1dc97f95142fe8399","0xa8175f477f4b674328f2aa84edf9f5e68da844bfca0e632301c6abb722ce9fcf","0xcef5039a1d81220b17110c1ba60ab9b2e538b99c9e91b9a451a1d1edf6e2fd20","0x54d50f001d84c4cdb4044714e8718e8b3ef8778f955c5bfa37a443f21aca33df","0xee1062068c3ecc41b345692d779a7de7deff61af45d8d0d0659dddca530a215a","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x467bfa0e27234426d7c17d48d09531911745abc5b524d0a89cd6e1b65e7e03ee","0x83c98afe4ae212f511c56c57f0d3847d1b7e2bc2587eb6d3115361f9d04ef405","0x137d48a1f12d21c3451eb707449d03dd157637e6bb63aa1d98fdb39eb699d5e5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x64d2661a53bb86eda71efa55bf0b886157d10e281f086e456db58ca62e4debc9","0x028140595c3768b9284258912603b00c237a4b9abe56e5f7acd1864be5aead5d","0xd280beb2da2fa4773c921c465eaf3525fefaf2e2aa86ae175c8c76d2084eed67","0x6d531de46e824ee51023b426f9d1e9fe10d162862b248924c9999604480c09f0","0x38889eda7940604085faf9769f68fe6fb21f045960e3524ad3524b7d7f0c23cb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x28e5ad2d04d59a9348d7d64a4114c828c0c78d304d650abda86648581c7f5b82","0x513e8a8cbcf97b18c3304060b4206f6000b4bc6d9c1d302bca3435394b1fd15d","0x47bb5bdb11c3d9e4f210ccd684211010babdc37cdd27b2dd17bccddde67e98da","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0c809478254db470374384dca23e338fc7768cf4d13aa4e47b37b2bc002d0e1e","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x81fba72b4eebb60725432cd16e8dfba21562b8e1053fb9f99673441b06365b2f","0xba7929400b30faaa8eaaedb26f81dba5ae093f6727884fe6fba86b8ab7d35636","0xbafb138c79db208afbf9813dac16084497147c8935bc3626e60a1e1dae2cf56a","0xf54c84d21073c2455b6805590c28a95f104dde2cd0376a712ee1ff6f47e4f38c","0x8ec34953d7a3b48a6c613a9a75a2486c07c086fb67226cc1654e41d95cf7508f","0x0bb05deba75234ad173d461bbe32888c4a133cb44992d2ea45c198a72bdc5aa5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x62119aee424443b393c12ee412df20e761dc93cb1735024180239081bdc2f5d9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xfadc670ef7e5ab4d617ea2c71461145433f08ee561f08a4c0c2264c795c00ca6","0x8236fc7dc0f11b7db2188b1f24363a406b4fb39dbadc6f80047f8eb541bac307","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xba1f12cecc7244c49c1f9fffafb3f4bd2b6489117add695f5dcfff69c878c67e","0xe88242d08fac35dadf194b442d334102f720bfc7f42c8a1867e1b5f8b66c8a68","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1ca362ee511e531718657f5102750e7c631f83c423d30801a6cf307385485333","0xbd1e84f9c51d66b18266dbb292d388a319681277b4f87da0ff659cc3d1c69d9c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xae327c68dc5a04fb2bdde8118c9c874bd0001d5396a200fd02c8deddfa9c515f","0x84a0c46e9f1557ced825a7599a6370f0fbee36504ca11b83942c3b62bdb83d55","0x60a0cbcb2d5ae79f01fc8dbed757d26123f4e69f630c6a27da6067895e8ad282","0xae2b9d9c2a838d6704839992934257401ea5328b1be656e69ad66c40e770937c","0x5bb847828bf9b0d79f2d630d73b7ceadf11a0ea6bbc75607deed2b8ab55e91f3","0xa1dea7dd034ac395e0e7fc68771d0907d162555ea9e0f64b93bf12c0728231f3","0xd4e48b114b059e3492234c05cf02a74e60690ceabec63cdfcef8b1549eef6bde","0x33efdde4136a648f8a47be2b97bb1e3c45cd59687887767b5ea3c99c38b8ae8c","0x43559ee1cf6ab898ccd0c71a83f0ce0def53dd8a6e9c08e7f544775ce5c4cadb","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2256c40576208cee49dcc15613ae4677fca07fb78086ed6a4a948f1e97f8ea61","0xdb7350b373fbc9bfcd021e41b0136d9e7d6039bf9be1b6b2f7c78c70b6c989ae","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6c594a6bf00247ac4d90e09ada99749dac76ab0a77e98bc2aa8e2300fa0e1aab","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0924fb6c2de10ad7e129df3c018c23eb8505fb3143df11f7fd3b9a5d6773a882","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4fc8b18d9850b250628cb0d93c6307c52b2dabd101f315d5eb89de2ff3941916","0xd675081035c2b7a83d1e1d2a697f2a19e9cd5d2b7affa1f3e5c66863a75fa809","0xd8e1b2bba94ae45568d5c32598bcb103c764595772eb246a11de7949adca6e8f","0x78d92359b46b5f7690fdf0d7321d85e59fd114d029360337d6372d30c619bda2","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb848ad1fd8e0d4fd42b0110343a7ae8b726d4ee93522f43f8d9c2b5dc29b82d7","0x84c97f5cfcceff4039ffed5069aa7a6a33ec1cf87f47a5cd220c5d3aba82899b","0x9bfbf6e9fbe80d13176933c29d2591ccfeaa7b05f6c391af6c784c324d313267","0x6342bc3ac0a69345aec6d2d413a4cad2a5f3d78aa15dc1b379391be8bd66b2bd","0x776489fe3fb20a901bf9e8d495979d974b4242faaeddb907ba4c542fa02d6207","0x511ee093ccac68324b2127659909f40d55912226b135150ddfed0223ffdf6e6b","0x1cf3158fcc2281e77a952823d6266d2fb2fd60baf65b680ec9fef90758c9fed2","0xe764071dccdc79103765fd79e4a0be33774b456e2e3cffa52245b53e8457b2d8","0x033d9db99c95854529f75954b2c6a18e5d15fb6f92a47da1e70743968eeac704","0x930d499ee0446b7fdc20aac9351b19372981dbc32fe04a47df4e7052cec1e451","0x40993ba5a81c4c837ff10bcea4b95babe24ec1a1babf642d112d8d756453a835","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf98440c1de2c06f94afbe6118afa5cc73630b90cae4aebf481c0ea0d775d4e1f","0xed290663d9d96e2d927a1821d86afb5fd38794cce001c2d873ec139671b04210","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa2047cd96a9359c05d8abf109922bfc63abddefe599d5d5f1ff133b044878970","0xd81e538f983be26d9c1007f64951479538f1a62e50a86b964fcb645dd8ba8053","0x7b6d6a4bd1c867a2e8f45f8e711d530768399feccca1abdd955b33ec4229f226","0x81546113f5aa69fa84e4424bd092fb5fe4f093b7be8183ce57a7a5014d036223","0x31fd0d038a6d31a0c3657d33428074e8b6713f5c56c51cc150ef115463a4c7ba","0x5416abd2815f42a0af51dca684d9315e05e8dd6c1349d8c51176d3d41fdfadd9","0x51c1bfbdd709e475e0b8e9645e19ca8324f88a5f94626afd0e1c4b37ac95a6ac","0xaa859a3910b882454bfb2a1841aa94a7b0d3e44e496cba8c8d2db5f0a5cfece9","0x10612bf696a4f603811aea341ba0a142191d1a31d48dda0d59bb4cbcddf4244e","0xd370d65bca9a9d62d958bc85cdf455a13aad9fd7ddd7cde8b0991d719784f8c9","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x784821b1c17816490aa29b1a8e025fab2835fd16e0931e65313c7290260d3392","0x2e33a0ca5d9eec4c9dd47b9ef77cdf6fd37d720e592462b0aac2fbc78286d5a5","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x56ae68b59fe099d7502fd2f09624194151078dcd0ff70401a3efc2f64c1e8d8c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x2b3a364dd7a684edab17299efc0d7fa828db43b93cbdbc3e5f576d7ac9e75675","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4f1fb9e5a183f508cecea2fe02a9b22f7fa0d478172fd6468887cb7ee10e325a","0x37599d3239a28e2d5d325a37f3e98787758301eaf437be6facd808f5d2b04dac","0x0028c95b248e12d02a6261f968d12e6acea47e168b12a28ee32cd8f773068c52","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0xe48af58167f3f81ee6722c96790214805173218e4c6c9cefd860361267d96a04","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6d9165a83c7fb47e10a9a6920fae3c83c3007660d69b5f702c068c5cdfbac81b","0xfc8af0623b105a9a6f669a539b3a029bf429f27c9e3d55782d00b111046eae73","0xbe670472da0a1403c4e7742316967b6e259ccf69da9cd18fb10f888afc80b8e2","0xc617054d178a60665d58cae07630dad93b7c1f2d44c783d142a5275ed5022505","0xee50702e59f121083125217eacac44645ca2414dd38c44e4dcfdfe525205ec93","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb5a1185b44f1e59d2f8620f148c2b3643ac57889aa5f32ebd66279978b9e7027","0xbba5f9305fbe6787c6e1987070c3d436cf7960de9d2ef2ded0f1551af1442081","0x97f0b87df2328daf6df4c72fbecc74c053e306fab22cbfc403a3235b402ce53e","0x3ca58a9a221a52debc9cc1af9570df17148c84f328e04741706e00ee2ff8a908","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x451d6be17dd4c65be89b2078a82970911219ff679cd55a513e0429bc864d2eab","0xa3b9e233babdbe73880c39269fe84f535defc73940109d087a351aa960de843f","0x856cd1fd9a24a52ec5633142d7989abe5a1a1b5617db16fc8c6006f9b7b7d8ec","0xe3d38d3a19c6d9b58564b1800eed8d77424ffd2abb3fc70ad85fb8c9a0b00a86","0x26756e1a58e5cb6eafea2d218d9f4ef5db0cf2ea0381ae24582aca3fb76a8f83","0xdf8fa6269de18a16b96e5cdb91261b51a8d14bfc4faa4565cbe0ae5a85a400b1","0x60d5574b3ebffa80b79a9b48acbaf39ea2d51c3d0afee7857afc52147ffad355","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x402fa5f8e536195b208ac6d5ce0b3210126d17ab8a960584e9d59c4ce91bf90c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x095f8a395e1d62dbbc8d787c4a14543c408470ebe8bfb317321369d638a74baf","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x6334175f1443dec31ed0d899c8ac7c445ec6ed95670b3f0c0bd0c92a2144d651","0xcc7b344cd3214c5bb87b4ba3e8b34cf2fd30e68123d349d107e77a4cecad5fa7","0x0187f61951d5043610c573872ce0a8796f7144823398e6216a192a6a551be9ba","0x1f0fc2a876b9b156127472558956c1e990611294f619bdb7ff0f35312abd19cd","0x96bf1fe74baf7fe00f5b966498f67f6898805214638b9c82360e56bcff0a6589","0xc1c2f15a36e22ce5e3a9f491485b85966e69d4bbf29b0f1502caff13fef1ebf8","0x2d3bdfd05df910b4b61fdefb1cc560c6bcbe907664a13001535427832dd39696","0x32fa90fbd8644f750b350ccd5708cbab86028c6b79a004c1a2d2b834f6bb30ef","0x2e85982253fb08990d06494cd5220c86115a333230b9264de5df347d5ff5bbf0","0x5e0342d78191741472141968bb0c1c20e5b540341641103df8f8066d70126e3c","0x5f6be7547aefde617f81bf2a59d94c2d5412e51ad23d61d224a6f1feec0c67d5","0xb67f7affd145f82940c202e53708ce7d7942e4d67c92f0608dc3eb60db73f838","0x1663019ebadffca4feff035c217a00fd7e2c5078db1002bc1b74802fee89f391","0x0709670ba11c61612fc55ec3d27cbcdc46e1dfeda4a839a27d45b977561a7845","0x54d34a2a1e0530a065f1825fc048a6bcb6859e1e167da1e681b91da6ec9d1863","0xaba82cad36907bbb28f2df5fa9a45f59119b78e4c72de05a05e64cca87b9069b","0x43e6de6e044992633e1f9b80880008858b6f4e974d0102b41561ee3ede5cac3f","0xded4540c08efd814d7690a60cd692606063b6fa388892fefad60fda9addb4c5a","0x9222dd63c07557cae10a0d726594954cc447ce53b3c647578df287450469fa86","0x1fe3eab03bc0e2bd6a36e2d827881b8c4867c63a01bd08a446cd064d645becc7","0x0b69a75b6230a80e4356e3ee682905617b37e421f155238efd545f62af5df4aa","0xe74d4a6fd33065cb847febf730c5b8956feaa0ceea5d429af75e31ec1e5e4ca6","0xa0de21b90b7a8ac722a08edf51bf3b53908750e1ad09d0a2362cc6f18ddb9d83","0x4aa3e56a632a9db36bad99b87949af1e953ed45d4bbd3f0564992ba97ce1b973","0x07ddb73177940a8243ba9f8a830a05afc88cf44887665a2cabf183f4a2b28f08","0x50467c61bb1fe73b2bfed2834bb532846f9e1d06dcca868fd2f37e01589f22ee","0x29cba98674d391bc2bbfdb112d8356dd49ba3c712888858eb0b0c60391df9bd3","0xa3c308c9c1242687d33db3d7f39e278ed7db898bfec802305c778c73b3f575ad","0xc3d85296d916cd4fe8422049df424e46180524614fe852a4acd7c6f7c0b7fe25","0x8ce8e1792efcbc3318696c5ebaa8c69b924558784c5febbc77542658c9557132","0xd89fac6bacfc611ea2083f183042a8e8161573d18a4f1e571a84a8434faabba0","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x72faf8660f304e96744c647dd353cb57de5df9af5ac69a2eaa8b1f1635700232","0x47eb8d4b25fa6f9bb50553a10d2702f96fb855a0d2d1ecb177fbb511ff4fd6b0","0xed7a43b6b48b9bf7092ac131d8ccc7452acae8381a73e83d426fecf42d1dae44","0xc525d1e083727eb941b230bd414983ac531efeb059a06a90c05baa53691c7f07","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xaa2a696f0e685bc8cdea25601516236b983a364a99772539da5f8d0544dddc90","0xc71893c2e738ed1249e616128d51eb04da14268675b29418695e39c2bb63c4b0","0x0b35e5d3fc402e1d5822eb9a3f490536e8c0afd4b1226de04a77c6cb5f56ddfc","0x1b771782bddbe268527a38eca98a0538e9539754200275b4137b6ea209478914","0x947a82b710d98db4dbdc74ef7f0d197f83870d8211c982b46758d984f7890090","0xd4edb99e43ce929a35b721e120d9b32a132b1585112b7af79e442990d21baeee","0x0c5bacbedb7494db16f5bafc0b5879a209a3778c2f89b9659ed05980dd494ae0","0x4a8d89a0e54821a84d1be1433cf5a91a6a041791d50f03f2287e91fd4e88f276","0x3cab9d331d55b27ec639dc0c4e769ffc17a9bc7fe5ebb61e856c97d0ad75c60b","0xb045a7a5f813b818bf2ed1d1f39dc6672dd1cf1d869e4f483230b40ebf269587","0xed430395997feabee4092f58f6f21f1512e523a9ce9829247fc8988c57ef58b6","0x1d0ff72f4fab8100428857841bddc9d2376048b9e88a5eaee802aac355d9840c","0x92689bfed877e08bbb9dc2ea77a37fd068a7ef3948549f0a524baabaaed9f441","0x21d346023d7247062316a5ba112e1528a4c38cea10843097d8f07fb5763a176c","0x83d7c8759fe9aafae9b91ef83da3c78c137fb027ac41fd93471049e3d4f9d359","0xf9ddaadae7b87fcd1587c5e7cc2179c35a0a0c9f8a77463ebe9d7335e01213fc","0x0ee6af248f1df26484336b3e34535d336ce43286d8b57fb78a124ed5e664793d","0xca91cef9e67101477d95ab08d899e7b590ec46c2e9fa85ce2afe7deb81a664d0","0xac34b34d69baf4488a7cb3492aa7ba6fbd0ee331277124949ae0580e7bf1abe7","0x4eb9da69d645d45710a9cfc28991d09722938648aaf1a06bb43ed3d909f6042b","0x1035462193fb7f9ce06f42080b86c9b3c53efc53a94381fcf50b666a3350f728","0x09dd6d8f9650eae579757e57bb9b06803819ef9c3292020de5c0be6f4cb8dd07","0x8c7415896ad247c2a2955bd99ac3b5be169e251d9a32ed44850f7ff4340c77d1","0x9322cbe4d2ef0f6c2dc4546e7f00ee15a5e075db9c86ad29d7e30d943ad3e099","0x334700837da1c5bbad7cbac535a0f506042e3b1d9f7adcd5ba784c7beb20f3a6","0x81d8978b6863f96735ff01f0d988ed773cae3d49bfc6200b6cee0641061e801a","0x9dbb6a0cfa98ace94c7adf51219dd63c367928c93bfe8111d2b321fd54b429ef","0x0ecb6f2d84a8638c3b1b0fc37b83a6e552f80f92137bd036d3edaae2502a56c9","0xd58c0b603c103ac4eab5e02fcf952f9b8ca3246da417f41aca90b894f6180a97","0x15515451b9bb8f7c3896c5f517e2874fa9c1d3022e22266862e340d50cf218da","0xff269d349d0461588ea762822923ba20e13717aa3037743c63ac1d500fa31cf8","0x607acefcffb0c2b48ea1ea2b73c0d289e3016dc6766fbdf0c8ee0d46944a1537","0xb30d8b2be1c6c2e9bc015c36a7823b23f08706e0ff9f573354d893d74a9354eb","0x4ca9f1864aff3528a2b8e6e74efbc827371cd64d9832dbc88e63e75c095f8cf5","0xbaf41053fcf37e9c534638409b8a81e34ffbc13e89d04fd109b4f1528abd4eec","0x2b1943550a5af9ee2d9c64da6eb6de2fbb95aeccdc7ee973202ee75565eda366","0x9406d19e5d9c212c951353f187098bef00cb01df377e8646809a073393e23842","0xbd515db9ddf564006f53a2f6a4eb5948372010280109373b6f141c93a335aa8d","0x176dd039bdf4ff8f2fb95f1f8b663c18807f3c3a5e1d8cdb5e117e74a6001ba4","0x4a5eede5f3721eb7b04b944eec2d0a4ad7c73b124d09871984957d22b153c5fa","0x2e1dd8fbfe468543a57a94ab28b42a9c2e62d9c837e1c310f961bba81bf4a36a","0xcf70f206b8b308844aa49f41a0c67e20d72976c15f437c5f70d4fbec0b0d1a8d","0x86a72338f807ae7ff111c65964a8f6a9de953bff89d6468d888390f43a7a24eb","0xf3bd7b7406ecdd6fb6e5717a4e9a79cfc9f88acdd527afbd89097f4f4b85dd2f","0x8aea347d41e73d736ea2a7fa65f20da14082196ff86262f4410f96ad4eaddead","0x00a5df94e7493e9bbf0857a2e68fa7ed1066c1fbeeb6685c692c263b45d8e075","0xa63ec2a2244ea5da4dfc7e68331669c053ddaa82711afac98a3712a2b551e936","0xbda0baf8be5b4ceaee8036eed84fd86e1916ab617a3363e3c5c6c5fded2367bb","0x8592ca95afd92484f0087c943821931148ac4a8f3a51f9d06de78c48dc58770f","0xf8d7938de0036d9ad45f760276c365b39a16581378b2894fa70eddb41ae2d43e","0xa61fb4294c44dacf37d11e8c4917ecae83c7e25e4dee7631cd097527eee46bcd","0x566f2f317934080275b7271c53c8df434e9a3fce111ba059791b654c58cc2f2f","0xf8b99d16fcd8e663ce6f2546bea847e46914b765c04e0a1c1b22a2a3a466608a","0x1504183d9f4e21a95b19bb12343591a13e5a91372acb0fa9e6f0b5fcbdc1541d","0xeb637470e324a72d8fa1b8ba4057b013a8f781509b509a4097821b7511136a93","0xf39c31c3f1a322a963b8fdc17734ff390dbc4c64b86e2621d0a43fe2664d517d","0x70945814762579ad40ddead0224dfaf193f802a44c637345958f351c37d1c485","0x9559988e698fe5c7e90738ac2e22f5bcfcc99bb204534bd0a5d8066a18afb77e","0x697fd68a21ab3cfa339310e65bec503d2b1ae3d93a4d26925d8455302328499c","0xf6a89c7e64062e34e9a8cfbb5b852db78216844fe48b1da098ae62b6684875cf","0x6340cfb3562efcafa1a33eb567b47505813e1d6fd29265c2fb2a60038f6ebc85","0xd92689f7b5557821b376ca4610a5badec02cc1c4f45e596de50ad9783eea65fe","0xd4e7576420f771f812a731886343f947865b147daa2db28b7492dd1fd4f09a9b","0x40266cf54a89922316a684bf1e48e94bf60f58e29ffe272a035a0e877b456a1e","0x2a070fcd79a2ad603062558173cc75f7c07e4ce771a215c75c4881e3ece6b00d","0xc40688fce31318e25de572cf7946310420fc8c33d483f86ef9b694b755bfd9ab","0x8d5f95f68fa8b45367c43222be8d0621609dcea57b9e91a3668db9a34f95b8a0","0xd659eb18488ef3802423dab9ad30a999a34d8a397d0232dc16ed42ab81829882","0xf917bf65d362627abe06c4d9996d11a81b78e35187faf8ce540ad41f1fb6a025","0xec0577d726edecb2af09b451b563f011db447ccceaf95b597f3b29c7cf63b886","0x9a0c224c31d754ab41d58df51e3c27060c8e1f8f1d41474fb2e04f796dbc9045","0x10cfafcc64dc9ebbc4871d9c65dc6a74aa7c7c61fa129816e6f9b3913d083531","0xdb5e1507fb8413fdcedc4bf47c8e44572e68ef227b99eeb931bfffe28f76b33c","0xebd93015d2d769b85ab4de94f514df3bd6ea3b0b60ad6f15e612548ccd188d76","0x659778595b2a19abff3525f7f1d89367322dfe11cd0e9c58ade2333379a306e0","0x7b06bf879029303a3fd6926fcbe81558242f0d4b91394fbc14a60566adecbb90","0xa0e9b5c4dfdcb71013a1af8d9ad34b081c39b78953620481ac9c560c98009822","0x3ad408a1491e26e7eab61eab465f55049ec5419d0d868239c509d2d084faa900","0xff8a6bc1524e18de9335efcf9b4a7a013fbbf5033d0e834c61805c712642d1ab","0x8adccc3ce9c0df85ee0eed8d4b1e425864207cf40efce016cd5e0c70e8d890b3","0xc1ec345f7110287584ddc1877ddfba1d918d1ff4f32a0ed182425a03bfc61c41","0x1efb485383b93beb1621eb14a00b4a2b264555226ec83950d55389d9f4bd5c51","0x8af29cfcb80a88c9db51dde67dabfb7f4bef29641c21c1421f57508a0c19a860","0xa9036301b035452599b0ea2579d85f6cd037405b25cb2ca2633e21e781563ec6","0x425e72d6f4961c9e16b27bdf15e3a735f5963429ac41f6ba083f976f2b70965c","0x1385fad870bcb6633d3fb32c439f7a2540a1468bf43c33cc7b19e45c8351262c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xfe41fedfd7416e5fc0e123217088ae06384fd9bed0d20addb9c87e528c7de9a2","0x93dfc747634b3a7ccfa337b5e5951b0f8a21612c68e95c6dee6d70562bbda972","0x0a49cb8cfbd47e3b771929e710c279373f817e2175423eb5c0758c07f8cc8f04","0x0efab3e77519f75bae9334e8e3c4817e93fe8de8845dc46d90c1b4715f4233aa","0xb65be225879a43056bb1f6e5c799f057dc3ca771932b738c70ec4e14bdcfd6d0","0x9137f81551604b53e6308db5fb7bce1516040a11108d04acf98cfa9b3904c4e9","0xc5a479b591d801b0084df3c5bbfa93a888c2f64288ffc5e229f9c2304c803fd3","0xa01b91b2ac630b712ef51caba6c4759aa70a4e7c50ffa18be0b18e5419b6446e","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x13f01c1bd2436d5e3a159b778fba33ac7b5f959d8081f82eaac4536354731477","0x7e3444386045c9d3751a4329852a896d2ea90c5ead24da2b4ead242cdd89a3c1","0x0dfd219a4e13f4b05e55751367906ca9315e80f9408021f70685ffa9bd8f0c70","0xe1f1223d608f889c467f6a259d8065a3f39ab79fa4739c4124d6f25247c5d904","0x1152e8c21d5ece341bf89addebaa2f7c3a4577e766678d9c778fdc96213512d2","0x60c48faa19b14b0e8bd55aaf60ce660d7de3ce7a14f0abaca99fc4d19c744008","0xafad493694aeed148fedce4c634958cb43a6f595a9b924492b416dd360e7b057","0x17e3aaf767eaabd0841afd0c3090b6505c9a16ed0091b05650637a8818f05b0b","0xbd7c36be09cee1a021f1825ec08ba380639e2233c28ead9ab999e7d7811d325c","0x41c077959fd11ed4eae437d7c0ebc0780d8d1115a3add575a5be35b133be5ce5","0x7cb14abf8ec1d5a53e681dd6d978d1e5cfc2bbf2402ef627a4e986fff0ce91ef","0x9efbc64f8e2ffd2b17f97f15791ff04a7c56a229a4bac8240302ec38bb2e6923","0xefc5a74e1f34fc039664a7e362a800f02ae5e260cc5ba5472e4b23983696d309","0x576fda07e94d7e103ef13bbce93789a0cb283178bde3f0f14861a3c3c16e2700","0xce34413a2762a859cbf8af7498756d0e0c52b23f1d2fa03abdfe22d282b56c91","0x01f5ab15463a4694b03fe54e28588e0be9cbf5b5ca14d245c783bd5b2b6c9758","0xdaa463cc8e2da2f2ab5a2c1ee8ffdfb291952d7db52132d02442b7dc746bb5c0","0x8fde72a3ed52a2f170ba0570a85c953f372d5454c8f441b5ade7a3a19e0412b3","0x1004a55f9eae0e25337ca19ab2983ebebaaf20e19aaecb30eb5b466c3d6e3c9c","0x40802a49f961420286f127d21c021f3ff5d6fed6efb955fa991115353a25fd2b","0xa3bb444bdf30775ae7acbd26cf3f5edce88311a547e899cb073fbb3cb0be807f","0x3b04e90b9512099e348b486f9b52312a6742422ccb696af3cd123b36c2f30a0d","0xa253340c6c6a853a63d85148f40fc79242df8f051ad53cd118dfafbdbbacbee1","0x5bda9fd76669f49fd7fe878503627336ca4b76e02dcb9b2ef7675b8dfdb8a05c","0xb9f3c95b5e75d8cfb38afee6bb1ab2df62aaa9d0cb89b18be5ce4ba9439a0922","0x35177c264532127395ee72af306a7b1026732d201c46c9b4c9671409e16a4c72","0x8cced1e6c82a8c3a9472b911332a2c17b198cc3a064ee37c8dcbd9be1e311079","0x219370a3d37b4b1e634f5a687b90335871277eaeb322cbed73d5d359d7c206c7","0xae2cec360d3ab0d55062bb1993fb702c75edd99776e1917d7b2fa7681b50585a","0x635fb9e04f5bc0d7aad08c5267974fc132fdaccbc4a2d3f07361ea800662bab8","0xabc27da99592a5fe0226c6e3bcf08431d19642b7ae4281ae1e62953d08be8a5f","0x718712d96080d4cb98ef4725c2e3e064462ea7bd1952c9ec00d0f930ccc986f9","0x75c9a19003264571db0c695d696e6c8e18bac6dba01cfb544864d0b306458d8f","0xc7b619b099e5e41a41474c779c8d84883be029f7ad0afa2afb7566190b5f11c4","0x66ab905a431e117b3f720e4582af27cc3e4201111bb71d9791d344fcb35b626d","0x3aff0be63473499519fcb87d8a1ca4e4b45dec35a4bbe5476f37befbb53c6d3e","0xa598177492151ab044c1f47884dc0f40fe0f43de52b1fc77cbf5996138ba681a","0x8ea4f1932e97cb8f9f6483ef522b658caa39be8d468076c78b96237173f8de31","0xfa3533ab1c401cadf384ced1586acd582ca219f6c01a97ade245a9f79a54d8e7","0x4f97be9efe24cf7c54a976fb50065c5fe9565c9d60ac436850c7f0470ea603fb","0x154c61100db3817bd8b896a3289752a0698617b3775fecf419a48596cee3c14d","0x2bac90c3edc58808b379f9efa007e2fc56bb251decfb1647574a76a279def824","0x9a51d8ef5cb3ca25faad34c5826ea18663aaee8ea4c784553465f02e93742a2d","0xa34f0761e2d50d6619cfcdf7c682967ee27a0ac6f1bfc86ddb53560bfa6aea5b","0x5973dd8e8e906cf2d82d3dcf9a1e39c68a596822e23ee64e3bdb2c9762f39334","0x65799340ab4e1f6894b58d90b777a0841a294cdb2ec1ffe945ad37cfc8083b6a","0xc08a27d4f680bb0a8ed9864ad9b82b686acd2d96ec8e796f982288cff9a583db","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xffea42b163c9781fcf6b84aca7ad60591e3b7be06ca7a3247cf9b8764f6364a3","0x20c7b098f08de581af52374ba37b7678770d507113eb7ef8ad51b09a73c925fa","0xf4fad7392d0e15ad1ea77bfcd12cb2db636483bbff23e335d81cf1e9b8cb213b","0xe2334c8b677409c70fda60ffea1de56e0e3e3a7d34931c70e3b65090a158db33","0xce5aae54827589e9dcd13ddc638fb907ff9a24f98531da52c10e675ac2a368f7","0xdde53730c225a15c968595e90160d247c85ca738881f09a0f88f8cc9a6323ad6","0x365717faf952bb9c855ccbeff6547e6ce65c7ec885c0faa4d9e02f455dc85585","0x523f438b9c943e7eb24f3887152b84ceca197294fb497446fae4b926e8c9c315","0xe4bec56c32009a9cc124954316d48ba5650f43c89a115e047023291847480af5","0x9dc9fb9be0fbe5740fe4e58417463ea980be7ba98fb7c5a9b7868714e3a22818","0xa40ec930f14811e32be6cfca3e917b158325d79f3075e099f0690d6d965f9752","0xaacc366655609e6fc4e5cf4a39ee2c3566c9ce4074d970626f63920d32baea6e","0xb2473605091c64adbeaed1684ece6978a9c5db336640918c0c8bbfae430677f0","0x84b9711bfbb83c959f926656d9c034ca9ddbf2b7606aa7a47832aa566270fc42","0x8c966921be17b51c98182c22972d4e12403ce2b4b703a94fddbe02f7562cdbce","0x61cca6acf429b31e58cb015a88a7dac95655512aedf661f4a6ef8d190c0e847f","0x2ca79b477a9a7eb3fdc70501a333c6e99acdecf9a7887eeb866faca4c868cfb9","0x4808d109308340523d27f827f4daeb9489fed4840412f309a31aaae6081e0688","0x99d626269907d05e79fe1c3d7357b15c8a3b13c9b75588528415d24fbc8d3b98","0x2cfdb8ef164423a83cecc61b9e788e663613eaca9d8b29f2693b8718c49a5172","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x9cc0d0a69981951144b1299ea46791764b67a9140bd2032f6ba42d0e494931ce","0x67ca3a4e875ac1fd80d87f0a6dcc431c8183a166fec75199933ff6eebc831937","0xecf52574a33c717da0d8ebf3cf545f4dc0e28ec03581dcd1329141ea1f98515a","0x8d48fb976e984bc41ecc71b054af5a39f4bb3ce148482c59fd7e47fe0e69cb7d","0xb3b6c35eac3b4d9a981d525881ca0e93108f533d9415ac1cd30e43781aece8dd","0x9615f66c6c4b7b89a91b9ccd617c43e657b62ffc153ed9306e13921c782954b9","0x83135bc1b2f25afff2196ac12deb9631e4a53861bfa172733933b6aef9b3b510","0x11eb998ac32d1ccf5f98c329c48d62697a2b285ab415ee9cb63e2292dff52d35","0x3266fd05373d77c2de50e63629025632338e1b288f62e61329e1ea4b6e43251d","0x1dc5055fbae045b43e86df13c95871b77f394df8bd89f4e51dac49d24c15b4ed","0x638d973eb3a293487238eb36fee337530f6248a47344dd9e929816c93292ea2f","0x2301c86b9269267e302ea67d33d5663df01606b5a6883eed75648aaf525d07c7","0xedc4cf47c658cb5c1fc79cc728febd452fa2a439498fa361e59f1e53970edbc6","0x45559f26be88942181a852f25e5a207edf22d6366816e334089f0eeabe63dfb2","0xfba6e136b58795e1a0b2b8992bfacd8bfdd659cab5a0220185b381659e743564","0xda9d41d21b51d7b80489c928baf3c5a7213df59126403cc48ba4f26aa26e616a","0x3e2ad63c202d66e95cef17e48b8fbb0cd8b787e338af6c7292fce79e96f5f486","0xca5630d00b1dfb5def41c46c996c76e6e8de6999ea346e310837beff324db854","0x174df64465a54d1f0d4fcac77363be82bde56fd7b3da6a63b243b91af13efec3","0xd577308671a8aa209a926718237815573f235186e4413ccb41ce79e6f655a1eb","0xc90c8d37efd4c6e02caae122afcbb7bc45686ffa7d71456568ed38b26be582ae","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xd01df4f0b1e57d24e30f5b322c242dc9e25b6c59c3ab70037ad10bf9f0e2388a","0x8dae1c66a58e867e14add94f0f72afcf3e0aa2b14bb9552feb4538e6f766126d","0xdf006aa753f8a8415f49b6ae49d5311eb35da4f32209591b59726bc0edfbc971","0x638e13aee489fe54bde8c1059d68ac99749424937a30c9b26184321fb6d58df2","0x4c651cacac789c76bff78ec354db7e95b50d44e86b8b353e4c66c633bb708636","0x0a7822f1f76732e6a2c115bbe7b0eedb7f107951ca6193c9fffdbfddbbf2a3dd","0xbf6df6b1d50e14ab54e5235df517a5277f6f5c7f76d29463dbd3406eab2451b0","0x50aee9255c969693c9e448d3db8132edf7523575d00fdc24edd8a0f21c0931a3","0x04f9642125308d0d36a98e9eefeac2fe86a99748a74a5346d03cd31e495ffd59","0x462622fbedf61de09135a009b7eef79661a4362f0c71080c2f0b0518f05615f9","0x2eb559576fb3b3f9fd345925b69c4c5e11c3dedcacf37ceb0b340503432f596c","0x02578a98c0e15459b67454f5583c270a8f1e2ab6d5fc7ef9d6d32cf92958cf49","0xe0634620926a2e5d886fc442a7162760c8a048e98c7ab5b928d06f04589fa19c","0x8ec6f0b9fdd37ff9ae1b91a8640593862f05927e921b52923701c2166ad1dd7f","0xa89f2911d9edda4bb8c2fb531c0f0b8bf3d4f18f26e5355be297a81b736d5d2b","0x9a90e29717496d51cdf6969fd9bd9856147a8a061012dc528918a9bdf805f565","0xb4c7a844341d41448d3565db666b29bef7c353896204908c447486313d7e292e","0x2b145e3e2942b6ed45c378dc8570584e83fbecfa7293b69e3d81ebf88d418d71","0xd28b387b5baa36ad298ef5e2c8fb541e736309b1063dfa9c28778cc16a0f525f","0xf9675c833cfb270dab6431d879bcdc7886e9c2a54fcc15e16aa0cc720d2811b2","0x0b5f0c2d50ec1cb20bd8a0ab7ced7186375dc29f032fda5f4b8a16bc5126eb49","0x068ae4b0456648fc008cb36a3543f98b1449c477f3dda9c96ba58f27c70984e3","0xd4ceb76507865be62da0c3fcb0ec00eff8791f20e6bcd38165ce32cd5366dea7","0x071c1a81c261494b92b717bfb5fe9326aa3509ad69007f68d81d96c3495ac97c","0xf4ca21ebd4d3a29e9ac6a9b177723932e73c20539b228f6a11760ab14d9738f8","0x00be10cafe036276369d489d2527ebd801f55e779eac3952631ec0437abbc17d","0x6a1098d7b00d048cbed32ed68279136e6cc293a98d619e3c72da23f6ad0d0297","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xb51219bf29e01105d4dfc7bdd6f47eacb05eecce9a3d7d0c3c95abca5d0622ce","0xe353e0826192b4420726457649f7d91e330ef06ceebcb1b02488a452e8b01390","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1cae9d97ce10e83bb4da678744fc311912184206d2105be992d865fc2240a532","0xc8a9a74f7ae93f8e836b19336ca0ebcc67d242e25ddb84f17a9f389ce0a54839","0x5ed1cc47437a551dd4eeb68061f1035e2700f6d4474a8f1b9bcf6d63d5f79fa1","0xbc89557560bce1e1e3efecff5175fa7855146cf2bef942a929519b39fb40386b","0xc88506ab1b6838ed2bf5f24fbdf456c6012776cff9d1fa753803f4ecc47816b3","0x853d42019d0b0ef00df08874290ccefea0734702387761bb962fd27588a72bf8","0xddc8147cb0a7287af00846443da4564b0e3c7695bde9d084b31fe4dbcd5b0264","0x39846c873c850f9fae770c0ef34f49751555fb642490dd98c45fd11474a8c974","0x7af858ea7e83736bb5c3c243d8670fbdb4d8028dbc3891004e9a7923c4f53dff","0xb84d7162a9973000735eaf910896d5a1d83e3db4bb7e88017cd9dadac2b2a9fb","0x68d9410ba59eb69fdef5d6f352dfca3c8ecdcbeaf3431f58f24632866140f8cc","0x3bddcae1723a8a1a76858f078ebc13a183ed0a7d3ccb726e3b7b49791ff765a4","0xcde9c00864c0fd80b5d6d384f3d2308b2d06f0ad5438df26b8a89965326888cd","0x2cc6280d6a788bb630c0df2cc0fb82163a497089d56398fb1d9b36fe1ae5c735","0x44b09fb10343e3efa46147fbc21224a6263ed22dea81c2de3e39d3eb7bcc78de","0x28441dd932325f1d50d21c25f2e3171bd909fd911f197423fc6b0f797fc8d4a4","0x9bcb13c8052e2954e0463926fe0ff4701877c86e8fecf41ef9859ca864d0fec0","0xa63e825bea13d03e97315b49e6a2678713d0d207d34606d6974e9671d4cbc3f3","0x597fa398e99b236cdd224dcf0b6536a7dc25d06a6498f7d3066b4e41628a21ed","0x4016ac038b1d7be4688bb61bbf54c37007c009a95ea4b3330562f106167278ca","0x1ae029e0c72911da886bf0214e37faa29bdb651351d7c9096b91054883695c34","0x59382b04fa9a4aa18cdc3b182b0cd858e36eb9bf296112a2aabe322556017ba5","0xf9314f00f3360ac91c4d6b9b0c83a8781d769a60c02e2195a3d6976187e64ef3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x0e2ca134974a0dc8d86ca0267710293e329982bbf6babb142f07eefb06ac6a58","0x28498ef2d5644f72534f868cec1d1ea749a0a8df56542f7ba63b2c76e2a1eff5","0xbf73876d88835dc9cc73cb4b1ce445497d9279c0bf4c7ff35c9a404672502072","0x90d4231210c9b24be9093f25ef03cc675693e12b6ba5fae71534e35e39d3cd71","0xe972b7aebccb0ae7a938ddbeec3e227ab9d534f74ebaa543e10cfebc90f54b89","0x46a1787c9797261d1022b6c5ad2f98ce49602b121a237bf01a87d28118475c9f","0xf845b1e0ba618fd788f7017e85fb4fa29b2128ccb3bd85c5ba8605739c1d78c0","0x52423b91b6883cc8dbd4cf5c04f9eab15f1b142e086285c2b1057a58d3edece2","0x22487256d95e25ed03c78263814abff2a4d0f537f96ed6c54bc328433561d43f","0xbbe6bbbf9083aba2e283498435463f8e5d7a73a41a1239ffe50f0ad6bc17a934","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x7ee88d9a9fa653fb98a054e226f725da763206541130b8f51559bcce17a3acfb","0xe0fee7215e8c43f4c25ce84dc6d2eb9d0dec63e131f3f9e06adc3a9fddfba7ea","0xb166b62dbee0a168f8aa8ca6b20a935794e3e9e4ab91858d488cdbf220dda187","0xeb98ab6e9dcf49d9fb8c2e3ef140d2cdeae2b369131d30aa638b89650937fda0","0x0bdd44039305a7bb2ca0c97f4a2f5993baa2ee8a4121321d9f7941a725d1b611","0x3a03f9ff5b5835bc7bbfaa5b84d7c62f87368ada775f3c7724f6e23d403bb93c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x864f069c0fa0b86c2bbe0a4af7534aaa139c3df0a2ef32acbb8ccbb195cf5921","0xaa13c48b26126b719d227c9d1c8ba683d43b048a5d57a4e589bd2205cecc5c1c","0xc7ee065e67712e270ce7652969df0e5bb568657e2803c4a1debb1757f3f39706","0xad6b579548d34db048fbf80c4fdcd3c3487a1831f99807180ba8913c9e8bdd5e","0x0cf7c3bf20b68e057172fbb7d79cbe61024de3b5b10a3b2385118dfaa4f093f0","0x00609a63da8441178ad301a45ad5758001324e0c95a5c3a3caf3279def4835fa","0xc4daa5d2ec7eb1410339f21579baf3c06838cae23ea52704b53c32f0b922393e","0xef34588bcd2d1cb61ebe78ab263944899e41b53442479b079624fd828ba40363","0x9a709f675495045497973fb0045369920bb27c0ef6b32b37a85938b86ba7ca3c","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x748ad644ca2ed362e30f550cb91413ba07c566d2afd9a7ba683a6622b24a7f7c","0x63665819cc6c418365f04f7206f09458bb481025d190d77a37c010df00df1845","0xd2c134e5e9d5baeea73c9b1d20f32019a49ecb287a2a294c9e5ad53596a3bd3f","0x6b8248e715c2aea6fa291d0798e71017d100d90ff64acb9a5d74273a45b78ef2","0x1ba00c15c2c4211f532d6b157239cbdbd480ca699cab62ed0390d813b3c57f58","0x17b442ecfefa6ed81790e8aee3b0066a23fb0b725e1f33b28b5b4ad05709ae96","0xc39b0c395a1d1a45ef0adb8838e7ae5b3b98863fe36d46dc44f70575e8d43c67","0x9134cb6aebc62731ef6b5a56537c4b859580590bdc2360ec404114c218cc1570","0xe3e429e9a2fcaf69b58b95cec3e8d10365208dba30e2fa2e2118819e09bdbc9d","0x7dfd95acef5a91fc2163aafb84f1fc6be934c534b67a66a8af35483870486af2","0xc80660e7e6299286701b50511efbd14068c12a8d1f96881882d704dc92c51059","0xc30a457d012e51e02a01440e4948643d551348aa8c53745275653cd65580f9f0","0xbaf44e7c294cc5c43a30d4e21346dc2e0ee59e3e8f702987e952e8af3292d854","0x3fa188d7a6c35f6f1a4953ce0a39c9fb0f34981d425f104e97729a4694409f30","0x3c140aeb967c1affcd6a1763b9ce020f1d5c32adbefe681b3dcb5d50250091c5","0xbf930cd3cb36d715854fbe7f8d1b4348dae0f409c0a78f5e77e2b490f1031914","0x342e90ab9db6647b2a65a877bcdc5db3c5104d4bf7d68e3e778816151085c17f","0x3815c551210c05f4b4021e52d075e0f7be040c7e3f085723e091b165545abaf6","0x596cf2d485215a4b8d20aef01645afd35a5c65b5a54332f965ceccd453f58b79","0x849ca83a3fb9b4dc9ced612e681092086fb44c26581091a9d56e2fe860b92a7d","0x2d9f8ab1aee01cc81ead786261747ff48bfda35b1970e872e285f44a6be6ba07","0xbe79aeaa1ac2ec9b14f887100535600a40c55c92e717c5fd1b6e1f0d6402bd31","0x897bd12f2ab7a998da2788a1640d7558636ae92f1ec537a17f62a7a3d1cffaa3","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x7af60b0b2333a37aea60474e9f9cac3d47e1552c631ce7ba25b4d0ca19da6880","0x0c2085dc89308c3c0f742ec8355a3c701ab1bf4f17f658d076bc7261ef4cdab9","0x339d54d9083e512073596f6cea09166dc4c67eeb2fc4f08f405fb2d854b728f2","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x3bc0b2ec3ed0ea53a5260defe3918f2aa0576bd81597773e61beff7c325f3585","0x04535ccea69a31b85f86c784be2c3d90d830748f96b07446e271ac4af3fc49f2","0x9e35ec500c19834c0aa038efc48dc3a51c1818ecc5ecfe405bea197c8efed2ec","0xd4ccf215177b0b2804b8c48e08fdd91bcf97fcab82e2247c58234ec216458228","0x84c4bd06c457542d845c42f991046e8e00d6e4b9599a918aaa43525f3961df4d","0x9246c6eed34678a5ed81eafcf1975ee83c8184bfdc3dc837e02add987c2dfc1e","0x09ad8ec4196dd466ead179b5588d900e4fb14e1ca5d86760a7a213d5f0f5939d","0x6bb7461ab78e30c782b52d675b6d9994143f7084093e572dc82aad1d1bf225f8","0x2be9bcd9e5dce123c8d52f09dc63c5ffca69ea25797908652ee5711ce6f87b7e","0xa279a9fa86a058406fc88a59aa26c88eae3ea77f530a329f53cd0167072f9b25","0x59214e735b62e8c02466854d07de7f580e4a7cc1dba25301b90b937ad975b8c7","0x0e4f5d8f2bfc8bf459e2012232b2bd44595609dda8efad609b1c273515173dba","0xbaefea9a6252eff2a7c7149eeed929b1786abc47cdee367cbff9aa1a10b7a947","0x3f8863226063bdc38be1c251b3046ddade13e9f68793f181d80a73e6436eb765","0xfb33516a14a5dd26b75935776ca63583e99ff80e91a64658892654e9116a1826","0x235851c38ded9162ae6f61d98075c9648ca29306c0ab9cf85c553c2a7c92381c","0x5e0c3f3dd9ca01c1fdcca5a6509e14f44c0f94353ed9dcfa7c98d68a05a98a14","0xe0c50e513bcde99ccb272efee254c7337c609acf68b50a3626a5073c159ef7b3","0x259d5dd24f45227d751e3bb627e95a27a8598fd731c91266fcedb8a3e05f8825","0x034b6e4925090942f9b2a6ccfbe7b8c21afa171aa3861261d74f7f243a621c32","0x0491686aa0fdc4243b172b1ca479e00e3a776dd9b2788e0e92db238029802e0a","0x029eec68977a08531a2e941c3fdef8d64757c1a2c28f34ae36601449b4fa09c9","0x945ddfaa5bf6d8b550f1003dc09c383405c5bca982fa597f80da1ba0142d8aab","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x5fe0aa5b5a08b6223a608a6ab025168d4eef13d00bdd759ca2965ddcef9ea752","0xb55230432e0686b6ca2b652c3bdec1a991627b4d21eae5f29eefc8c3d75b7eff","0xc4e64457cf1df5423e9a67e686542efb87ba2e2a71de850c538b0d4f7a9195d6","0xaf69f78286225bda7049222b89edcc8d50f16cef946113f4d5c9a151272b2de0","0xbab3a69c57bdbf46ccf89ef8a18cb439b39a94e607e3de0541a2bc266971b258","0x56d2f1dd1b7df6a9809b89488c62094e1d19966109726010601de2ac049696e2","0xc66cd90d77bbbf1ea601d7d07b904013a44f9b4ce4b2ce432855baae7f42a91f","0x2c8b626f84ec4c1888fc08ba385f6df363cd507e34dde2d31e5d9a842a10da7c","0xb3f20b70da0b2fb713cb3fa9fd1863f6f25074004e53439c01aa9f16d0288342","0x9774a3eaee3d080c0a5208c61ca8e5cad172d05dee32c261c77f6c8675fadae6","0x4fde600e51e4c156eab6e79db53b1357ccd1d7408c4e71c283146fe8a90688ef","0x4836755231d2d42a9d274a4874092aeb4fe0228cce0e171da9a4a9f05941d680","0xd342e2a55a8be38ef0ec658550776e4c3d046b5925eb6d6bae47f04e5c3dec0e","0x96000f03aab163aa1ce294c7fa347ad469452b2519dff9c13c9134f6fbb4eaac","0xfe679e4540b6c1b0bc82ef5ff79c5cf82c2ff82b9f1b9713e01a4cbd1132ea44","0x1abb51fa313383b59fadb64a378649eac5f269efb6f0bab0d30fff8c2b3467c7","0x3e559fe794120c28865b66f79d020838c216af9843f3c1e336acd01d00facf40","0x0fbcf7a9304a33f9be55245badf03a3ce4fec149ccc1ec72aaf8f3b323a4a527","0x9a01a0f90456bd29337e297a9b5bea3d2c55d12875059509b58168bb09d16f4a","0xf0d58001c216569953b173af6229c4c0497f58eeb786e0b0c505058d40c0bfb1","0x431c6e402be2244b6e07ba3b5d50286138806900d882fa3f774f39564b1d3128","0x640463519b23b9529d6f13c5dc07b757ba30da53ace7a486cdd7d4baef2541be","0x2740c2054819c0dd540bc4209c369967a729eb0df20c241c49fbbb5cbe18cd46","0x629ba085f5ed80515a29aa4276a0a297032d3c96a88ae5e15b343538291a0cc4","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xf6501ccaf0fedfad6f93ad05557a6a402ef153c0d9d25395240175955b5ef195","0xc5eda0aafbc0ef758f001b17301bf64912593ba33e661a86762275fd2fc66e9e","0xd044eac034fe10890567684d00160977086bf3e941f331a092780eaac0718722","0x3a08a073f4f0eeb8abce5a1deeaa21ec8fbb89836019b334da75e34bf45b0974","0xe26b51f87eb7890328580ea8f04e36e5afb0f3f6be80f2fc900918d8f5087291","0x1e9114faaab461f4fa6a7879de39e86d3c76cecb53845f77fcbcf5aa4603ada4","0x13fa839d04da36cbf4d9ead820674db9401842635a20da6a36b64efdc207d456","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x4c88d8b70c9dcd07778b9a6eb5d101194ede3d4cc0cf1f72e89b8e510c7c745d","0x580d95cb49b984194dc5b5a3e4d47d5d20a47e568e05c91cc8a5db864753bec5","0xee2a8ccb8780f1a362d31a1e1053267fb65a02391f0fc50e958800141a6e5366","0x611c32375be273b3289f5313418e1f6e1871fdf619a91338868eaa057d98acfe","0x8d992ae2b6a1acb098efdba17385d817a6b2c566bfb144e502c253b9d3d97881","0x1f850c9ccb9a11d1cb3bd8706d7519baa5688a9ec6dc98ea06580be6d792e826","0x52af15e98d3f5ae0c0355cd45e88428de6f306dd092e428d8b258be413c4a4d0","0x9d12134e705c3d8bbd7a9437c8b8a869e17c6bd691fe79df69baef54d0a83660","0xe2ab568f1c9bc502395f43ba2abd3fb8bec82e3f9f232dd13d90d313c27155ad","0xdbcbf22ca53d69023d1c357b0cd7706c9d1274de6e5ee28a7ff4f529a8a9abd9","0x5c017fec8cbfd33d8c81065301ddd56f138c5633e1d3d55fc676522aff2ea288","0xc3db595d6f579a3f20d4e3281dd21323ed29090d0a1904f9267085217cf9a738","0xee9a1906b41e9e4624fb4865cdf90c9592350cae7b6891e684c9195626580990","0xce6c4ea789ca59066998c5d435b5217f866f0b50ea3a7c3a7bebbcd130eb4f46","0x93533b286c785710826bd7f91359039f8ebc33bdec044cfed754fc76945e7473","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xd12e78be62b27c4713ff60371819835d78641da3791039337cb2bc2060b3ff7e","0x9a3b3ff2a672b722bc24988b9f2dda64426d3279710d754af44c176e77be8d5d","0x5b7e0249f9caf1afb327a925921aa6e073de21a0f8f52ed3a631017037d39405","0xf7773a291feef285bfaa27d11edda3454bfe51fb1e058ff3a5f19eec81c196c4","0xc5003265ace4bfaa688cf295db18a066b119f158b7213484c7c743ca0dd9c48e","0x1970fe7c31b3f56351bbfcf0fcaeed509bb3b025165a93c9c5e796be35c3bd8c","0x962daf77542f7065d810d86db33f88cd3e95c084bd357275c54cecde4f3bdb7f","0x389128484670c338861947712a74acbf8b06bec718924adc4ff50eb6a5ebb6df","0x47c477afe2f2951653f32bef5aa9f617e13185e1ef90ee8012490538759f2a26","0xf3bc3eb393a3556133e411638008742a3fbfab39f8d5b7a18ee42e93453ffd30","0x89c69ea134c4a0d921cd634f1080b31c9bc7e0fa4b35afc0368a1b9d1293ddff","0x2e2873afeacc1b707fb62e319f94b8b76a701b18a580850c2d301aa4c7e95b3c","0x8281fd546b829e8ee8e60d7fc48133af6d673d09a7f6ffbd7157de219d0709ac","0xa40977f8eb3ad4d02d52493a6f836b72e2664d3571e164a16ea41d08c752dc28","0x2349d7af386e8b9783d56e413e153a67cd7bcb7b1c1e118e3893cf2b7ef149e1","0x2c2901753ceefd31d10f700dae0a27008616cbcb2a0fcd0d123505db1418e0ca","0xe29de3efdd5e51c749be4d62030f27a0e7dd791452d35cd27b2e136da07847bd","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xc2daae48251384e3b3f0d14dabdad05f485a09551006acc5b2b2aeb7fbfc0eb5","0x4abdbd9cc68b4e2e8e8d9bcf04dcd90fc01e1c715d67f2f385bcb6d6d6b45e55","0x66709b3c7f7e1c09558c2fc1cbe27b060dc7ecb68858bfc0041a7b22851a11b9","0x3356622526cd52e3af973322fcdbdb0eba637dc095b3e209017934e7c1c3d815","0xa05ae077eba4c1c8db61ed78fb6bae192eda29aabc2cb8093fa75f8c3ada2654","0x3caf8e1d2c09a8986778add0170c00936f30ff490254dca83906a1d0fd76810e","0xcb8064dcaeac44baae9f70ef659b318fcd3e9d4bc02cab0794fbe3914de0bd16","0x6d6ed59349bb4714d8de7860949febd8c352ca21763d2b6e56f03e3deba305c0","0x3f586fc6b7ba0253ea8ee634d63d13cdcb939915dc3e1c0ed4e717ddec843900","0x162d4a24fca0a6305536e30eb7239dab220a2de9f98368c1111413df13ddf608","0x2943a929cee6d374ba9c0e73fad56fc4d8cd6f36eb890e3c949dbe34067e7616","0x5936a74167c5ab7bcd00b14146d6420e853e208a3e0517552094182a772f812a","0x9b6a2e29b5a7abfaa0b1115e42dcb38ad7c16310100fc7507e4dd84ec57b4888","0x10cf768e7d84f9fb0e0f0b02c0077b7d4db40e6fc913bf9773660e9a7cf04c88","0x61d8e38bb8616640d4ec1071fd92cdccba8ef3d7db091d454a52c9b34a3434fe","0xebbc5ae325f1cfe92033efe587a240d826331190a29242bfb8ba496ff7fcd90e","0xfb05bb1ba8ac3e19d0e468aee4148fe2c45b1a889e2c7ab3e0ba8d9865b3a3b8","0x8b24734d93f18850cd7be7993b4c154317254da061cd3d8d521e241315560055","0x83699072acaa244beefaa0730b80103a35856cea0e1a064c7abb83847b626d90","0x33aed3626b1aa2c16a5996a0785c7583bed61730ff54243bb790aa85d87356d4","0x7e6696b73a2869b1d1796a3bbea5cba9c32d66d6030e3f8bc99615dedad94d65","0x89d4fca3cf2b534eaf3ad27f0e32f7afc312b91243537063a7b5accab3183d65","0x4804d2391ab8d2d51e0f080972c30e5eb416ec79053d753fb50e9653e051dd33","0xb16142beab8a230ab89b477490c4e24d6d65122815f9e08304d33a16f4083881","0x58c4b178f335db43059a93f3b4d2828099bdd8827f41d46477ae2ade9176dae8","0x81cbb252dd5ef6ded0ca36485071721eb2c30a6dc5e3f928a4befa9b844148b3","0xb4057a955a04b9f46fdcdf0a5b8f52a8f70c9b488ce3650a646155a73b847fb9","0x743f2f27321388078e992dd57e71bf13f1f068a024f657094a728171e82f28ba","0x0a38080a3419fa3b61c2e9596d8b43469e43164ffdb6e0cdd576105151615440","0x1ae9be1a489e99eb3026c1875534f436d20c7d9fcf2c72c75d711abdeb7693da","0x286d284351d4ec5b1f56d1405c0f2bad1f31832acf69c5176d3d80d3fccc7989","0x0a5da5aeab09246d7f2f5609039656ac8441a38d81db326f086b62a4405f10bb","0x46203ae8b3ba20022405566f84897e9d2f5254bc27b753d2cee64cd37def637d","0x83a7a5d881b0c96d9416f6a075c8656ec0a464cb068990361be56f1d74c839d0","0x69e1dc5ce230f9b2c9963b5a12759d6456aed7a3ca74129c8c1e4e435c4a36e2","0x0a847eba3f74ae0558707821fdbb066fefa77fa2dbb88f00354e1b8497eac0fc","0x923d78c7f1f2ec6eae66f2d5c8e956e4c129a6f652eed112038b232bac4b8d22","0x16f9284110b500db4435f432ec69a8deacb7d1c49cfbdb7b9f8fce38d6081356","0x43d551c0cb9976c54f45d8c29d645a38431bc8bb9cf854268cfb832e1a5b7c50","0x124cb81126e6335d4465b07a8283a6587bc0a554e2083b7f379ec08161c8cd1b","0xf032c2a4bac41ad098a6e9178f1268b88dd452ce2d41a619dadd92c2f9a3835b","0x7030a2b96d0f7fc9e17351bb8dd0f3ec117756e935c3a836ab049e580755eb39","0x2ea22426583f29bb0dd0ee65b431f4cd924f64057202fe853e3bcb73437e5f94","0x7f71d5e1b0d942f08e94798f90e8f6d2c7a30399744057cb2fdb3ab9b0f37dcb","0x37c20802e8eb7e569156da4345806015f2171f7ba424f116de89f5ec41bd480a","0x159dcdc3106b251298e541e29b9c2805f7bb1a82dfce72d16838c82c29708c5f","0xdf2df6eff4819db1e62931ecc9484d415f7c7041436f76467d52f1e7700d53be","0x226c94a2e0028caf7446dc6c095157595c441f4f9617c8a89c4f9e2beecdd69c","0x12468e22ebb76c4e482273327f50937a500ec5372db8651a01e0b2b8717f3bf8","0x30e13ab5b6a9f59e6c24645d7c91d38fa12803ca2f2b541b858a7f1f89cf76f7","0xb15c1bfb3724c119b40a0b7916d0dc0d2ee8f10ab958018c1b3280d8fe23036c","0xe0b003f8dac706281fc34fe59fec0934b8156b02815ca4ea25e87eab231b104f","0xbcfe6def46fd7e56554808449bf05a173c7d55e85d4c8136990db2e613841c35","0x1cac8370de2e68557bd5dc47e21c501946969403439edb897669392b97b243a5","0xb3d524a7f519cc1f0b7dbc41e1f7f7a1f38bb541da52e7d0825e1d7158e38ea4","0x16b5b328b84bcd69ad4a8feefae60f8ded7f7be9d4a36695dc033f89c936035a","0x865ca070d9b1104b3673b3b1514a424cf7a417a200d155eb5170e0c6a1515bbc","0x09debc693e216e816423bd496217503b3c57f5fda766b3d371781816f60b0f50","0x7c6b86726658329e97c03691abb1ae6eed180279b1a8d0fdb3cfc985fa81083d","0x4b111622a100d3148106688255e7a308c897255ff873e30f277ff71123f804e9","0xca69daec66e69381fcee933e06344989f098830211931077ef466ae0134e7ea8","0xd23114e7a9f6f6a2e10461b5d79adc55a07661d0f5708615780bf00a62c92809","0xa560304f00b16400bae46d4fb5deff46d48b65fd231fc05c9505553a5dbd542c","0x3c0cb73c969507dd7a7a57425abcc46db3feef73c96565726f404c24b53b8321","0x54f7db1d0e6119eb05701ea25a6e719197b8ec83ce122d3e730e1c1149b1a92e","0xc2692ba50325625b3f4667b47c66da5b1f35a839ab595b6e58947d2a95bd9aea","0x2dac9f8a4d6a730939f052d57c1c087917a085c9278af9ad6ab20657b7e31391","0x9152e102de4d5e0eb885f6a56d0070b2acffac99dee560aaf741f6411e933003","0x9c8ef9d2ea193718ae9aab63324bbd157ea694029a046c6a65d187c9752b0751","0xbe36c8514b3440238c9bb5629917bb01115afb81973efbb0539f5683d3fa4991","0xcff39e9b2d3464cc999d1c1b93ca1b04334014bf2206fd1841091a87d06fba7e","0x47c6040878f57b8ebc242eac67d1dd0c02e800b3b9a1ea86848bad67a8598769","0x2ca0947fb8ce1d082dd810a6e9111f4cbf5ee75b33d049a3e9bdd79bd6e9d1bc","0x69300477c4d9f37dbf319c076e5a8deaff98445e59019bbd22eb30f01379e222","0xad5fd1f0723b437473f0039c13f57df8a076fc8651060d669766646d0644c7f0","0xfb4f014b130318eb1004f6688d9ed11163a7b7a8b863896ea40e939fdbac29af","0xe4b48ec418bbc578a6484cbe4f09c1c9a8857cd9110defb8646d33e191df0bee","0x95e9ddb707dd5ea353d313d13aaf20dabe5914861c093b0003655ddb812c5134","0x77c41d28a2f76631b6be0da3bb362f7c77bed0787ef257356843b04cb793635d","0x2bcf0c05f8006d02215bd5af146ac755272de2a0766a85628a9e58505c3988f9","0x347a3a2ae8394c05ff2b733172afaefa6ea413c0decd544ee98ca01f5f9b6edf","0x6bfd808f126b15143db3493f5c99d8cb38288e0d268e6d5ab014c0d9df07fc66","0xb3285b8af7b2cfb604cca9b8681ffbf10524bfe0955f00409394872d9272ff00","0x48cc1fbc0b2e90ed12f637c78bd5ce1bc032f5aa3f3c0fd2c7477b5b9e2489f6","0x8ebed850c2f69dc1e83b322aba44bd84201b164f27c301aad9db5110f3161205","0xb97b90cf0d348de9b94eb607e172d6f7ea691d1558a2762962ff811024eb6bcf","0x4f6f199641d46a724ae27ba8ddf931d1153fe0be7dc8021d4ad63decabc2a9fa","0xcc054234f564935cc83b608fdaedb268d32707891e4b39b479d3c8d0fdaa56f5","0x3120581bdcfb3f4ae8cc133c9e92e792f42ee6cb949c448bb37d313ee2703e64","0x68e88de4ea7f6f15ab71538a762f0888e73fdeca52939699bb88554dfdae930b","0x54ede0c1a640a08b464945b43f366ca6f3dd3166d80deaecf2f2a6355d9de11c","0x66c5cb562822d3d99f37542304046ec04ff8298d27cfa92e18eba327adc4d821","0x85c0b690f1dedbb0eed754668a1c2f66120d305198e89e1f8dea768cebeaa2be","0x8c6746662aa0073b612477e030747858e73814630632b86133781c109a6768d9","0xf7dd8aa13fc41a666694249833d9b348312dc21763539904141348e74f473578","0x47175e1dbd13d56ceee81671104f517a6e5a3f950887b09fd0471aeaf92982c9","0x59773942f9a1effe59f267c60a2acc9df42c06ebfadfd4d0b26397769f2c93d6","0x9ae1e3c5ea689ebb100971c3e881c00c3fc88edf5a812ebcb06958de2a47d382","0x4abcc2fa3490d4c4d172a8c0c131f35bea754137a2e0e765e7e64f6073e54a96","0xc20b77980d6b85f16d7908a3e159ba42a64c86150045cf12f0a12d644589d728","0x22bc81e9a131b411ef94c593494937552d412ba72821e32b00936297f7df1134","0x80292d454aa391be33a82a36e6798480bfd9de4f583632b89483718f6a0c9a9b","0xa3eec11ec18012c1668f830dd645238430ccc881d752edc0e5343e5597731cdc","0xa82effbba1f9116dc4c78e4b7659c22c0bc715f3eea7611c46cd76d9ac368e39","0x8d8ce01a06e90d55694f788ecaf7d717c8bf8f90dc2394d46365abfbbd4ded3c","0xcd895333cc738ca4a5308c4692ea0dee3c30e13a6562849666ac86833197ca13","0xa7e11058250b01e8018bf2ed414c25a5b527a7040607f02c5e5ea1cb769391fd","0x9ba2429e19494103b2f5a1a8b83275b7019c953b66a73df0f232ff4d50bd54e6","0xad571bd32382b00d203491c2abc5869f1d480c537d63b8ee3f880852dab02c56","0x433a3d8c033c2ec8209e7c7cdb6b2b989ed45c3087ce9bea4a9112e000072388","0x8adebea35ab312596909c4a6fa0f8da9042b90c2a144db12daa5c87988583c85","0x10279a98b304badbed19eee10289fbf851dd25f9ed4b11ba510987b8b492fa41","0x90050f2f08cc39bbb1d02b1860b01d100e5ddad5cd7685729fee164d9ea5a9fb","0x3d53c9940d372e2311c0f228e08658db4405195cdc5e1bff31bc41b9b32f74fb","0xe1dee870eb1a9ca10d7d74ce448a4aad5d9ab7232de8a73a397d0d3b0d55f4ee","0x24e2194c4aa206f4cac6a69a425c6e92d47bea52094928888db1903898fb73cd","0x09f188dc3f46e06afde98f0bd8521040e006f8c91603dd63ea0e7d083e66f95e","0xf2a8ab9d571024d8ca8eb0c69452dbe954d9390d9479ce2410b9d259510bb79c","0x3e515ba0cb795113b99c56ee217fc886b6bb662f3bdb475cb26367e92137b99d","0x736edd7dadd5a85c3964b970d7283ae6fc14682f502e4bbefd43e3422184b493","0x5570f808ccd05cfb896679e4522520ee64b425adb30cd59471f5561b21bd715e","0x845ff32ac3821836a69b49b58e955e1d293944a6d5b0564ef453173e4ee1908a","0xddcd911a768ca4ab43f2e1f35bab04c17c33cfaaf46a24ad9edcff324af2efbe","0x75b996cd62e81ba0ebc78f077fb0402b6e5c4a9b8898449eed624ed58d8d269b","0xb05d4cdaf858ffca32156b25b624bc005113de710f06be93d8bc07c8406f395a","0x9b1b1a490f5028245bf8dfb245c03741ac92fe60c217ec91be8ea51e5a13ee08","0x328dfa27dc2693c266f4858716e513f7911caf7a8d144903c0bccf8799d20083","0x08acfd284804e3995016f5ec45ec548aa5da74c920ba530f2a5aee10a2272114","0x5208f5938bb46ef6277b6ac0a01cd51d7e5f6a98baffe025a675201add710bbe","0x7c04629888d5d78aceb956705b44087c800efdc17e8b94fc13afb32040191f6d","0x297834110cdd382fd9cd4d45459e2abedbc74a7672485cbb9220cff43e8beaa9","0x8d965b53386b7ae5a877faed813128aab718a95753aa4c74847b287c56411f69","0xaa372a7c27815fc1e60b84b59e9ec6507ac83a7451a7eb82589e5dc3c2383c87","0x08698eb62954ab41630ee3f94e4aef1e5155e406a2d36654defc499f8a465523","0x71459805e2ee30a5c45475e3c8b80ad86e87712abfe95477d23780b7885da8ff","0x5f5b5294f306fbb646a4f07b1eedb9063d7ca7a809b10ad02f290d4c6f5193c1","0x84c5ddfc74911468cc564a414d2edb30e8db08ee237b76d431d3d3ad9f09cf4c","0x2322678d634041cbab6e20139a985adb8314eb8af5bcb7ae7b1ad390eb57e5c0","0xdee5a698b875f8aba9e5f56ba449e26566b53bb73bbfd4677a43a19f30688e29","0xa24b749b5a27c6efc57053b7ac414bbd89e091415ce184332c95664c7f3cb2b3","0xb1d8d6b147b6aaa777e3de542367176156707895a8adc905440e9c6b6b7a944c","0x75d43b59699423d5a5adab1ba35c6225db803afe779d95a393ab16739a782f09","0x03117e787a4e0571e425705fcb7776e460a42e36a47881d5d28041cc454123df","0x98d75d0ed3702c7c0541866efe68f4c8b6a74900ae566f5cdf34e704c4bcc14e","0x3a7961c9cc7ea9ebadfedf7dd7c683002ac90f5b020b6204f9bfc6e74d541fc3","0x7a60c13c13773938ef1b4a1b83fea70a94d730f44ee56f7d0829dca5f46ef2de","0x1368c1fcb745c02d3c35083b2b9fe2d3ea9ab69e7632113a80165bc9bc961333","0x8f959546435bf38c80a0f2ac63e96356ae4c793561bcfa460e8e3fc35c5b41d8","0x2b65bb02d687782859dc9b17fe9861bde378f8b55cb00ade09d5f47ff8f442ae","0xaf14bdd99eb1331517982005909962aa47a3eeda30a3a4cb9188eded64bf22ff","0xae6475993b8b369e8566309d4279a0dfd7dc57e808d8ad9d671e2910012a25ca","0x7d272602088fe64d6538507b3e8b0d215667ed2e33a1761432a4b6b2f2ed8f6f","0xd4566e338d968cc880795049f45ea7cb988e50011e53cf69b0b9404da3a3c07c","0x050520508eec710bfb21be32e2eb1ba4c9a2ec5fd5883bbf5929a9abe9edc4d1","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xdd40c571dfadcec31c5097525c51bf8e7affa9c7ca8ac83030d41fe3a00d98da","0x6b4f878c6747eb63b7df28f43f5f043ebe43e13f56d93a0253ac6c8cb29a3483","0xb057d35ec1c47c0c6a59d08c7212198adafd67a1f6778b7019949d5faccac392","0x2b2a79a99253e8f559f4c46529d766e9a9dad4f927273c2afd1a3577e63309d2","0x0fd6d4b0e37d3426a8737e9487f5adeb3507915cbf58651a00c3f1cb86a866c0","0x567c48bbfc089d00768a6251ab1928331c0329b6ceaea54613780b2dd875ed28","0x4d0fd663e8b293da1c11c3365cab42c14c1fc71b7ce68e1a8518f7ace97b60ef","0xcf6128c0f6ef13c334d6f669e6a7f07f6197d745855043518029401d0a0d6606","0xa0b82e91af9cf3587e25c95f26b81aa8d7b55354374df1f9d2c43ef51d916155","0xee1efae95825ccfb8ce375229dfc5d94f1594bbc69de552e6eab57c409f275fa","0xa0b50351953115e434446be81c72b0c8de2e0c5a0ab014cd7d21ba69459422de","0xa613a51d815f10d74c4c6b2584e6926aa15b324cd818b5cdf5bd2e84ceb76bf4","0xfa4a8ab97e266875845367b1755f875d102a80c65f7dc8a346f8e0eef673dfcb","0x9fa72a38e313512378ecc6b4380c7d0373ff0d31d2142553bd6cef6eb8cbfc65","0x2e64a74b8ed42a201285f0869b8e9fcac34e4d1b7d9029690a98d9ee1ebc4ae6","0x5515bc07e468484103a87e6b1230a815c30bb69c25a1095a5d31d956e672590a","0x7c57553b0cae3963f9347435f1743e74e4e7b95e766f385c7160836e7c0ba8a7","0x1a335a8592b72f0a779f9dd14d7e77be9b8139b2d0782b4b8838d2b26534dc1d","0x170fa9eaef8ec9f09f108220492b0ed4dad5caea7b9a40098ea409bdeeac9ec7","0x38a226647e025d03d7f061784628d7c0bfd2bb19940609b7acae3e467e92a1a0","0xb322c789bc20dc0d79a695a9c987dfdfc3d603f75a628eec8895a2911010d113","0x9855f4297ec96c9385584c87715c7b0788b968a75a6a2684d48d83d1186f9de8","0x95548674c0b1e7a1d367f8ca21ef952a2905757f3313f5b781a57e76fb7aa184","0x92d977d0a9b6a9de16dc55371623eaea887e8a9cdb5e82b988214af852006f9a","0x217880d898c6ed5ce85c8359b77e426d6547c07135b232e5023e36ecae68cfdf","0x57d6771b6098129284ec5cf2eabd2645a6a2bba41e1c4131863134ef91022860","0x0513d460342b3ad68e016bc90d3250eadb4554d59c6cb2a5c9de7013ab69d582","0x9dc1dd78455ff6f4feb58781b842380669673d54715a13d0bf033293afadfb0f","0x754f5db63a2676ae1178e2fa81832df1885966ce4ce32739598be135cdd8aa6e","0x42349be7896548a874c7a39d55ab2184a2697a43886982500320618f8957a494","0xf5fdacb67e7fc07f878f7f94129502d1b1ff8fd258616805f155f3baee7ec267","0x0bd31038ef48291895d7332376300311624c273795997ee5428ad2b6e23bb79d","0x3a9550abb8659e35a843e36f8cb4b5787f1b4f837d4a7c4214219ff56cb4776e","0xe5f2f4d7ef915bb2aecc0cec10dde414a68b62a78824871a9c30240cbf7e20e2","0x4eb808762c19342cd92c229e6177091757fd7a6cb319bae82d176d03097a09be","0x17bce92618c714f8a47ea7f55213f24ca210eab82d0497fae558d28248299cca","0x3bdfc1dfde7741a0431cd188a7a9a9b855a1974b0e36384a1e949261666d94ee","0x408744359769ae6d4ca9580b959e43ef1e7bea33bbed5f39afd2ba6ae2a506c1","0xecde7914cbc9da89f1c8e0e614efeec75a5afd5b4a783a88580d1d4a2d768906","0x098c8b7bdfb651b416fe4cb19f4f1a30a57e00f83addda09850b7b212d9a4ef6","0xd0947c8d394a6027ed55220e32453b489ab0c39df14a43fc10b8968387d521ac","0xb2f14fcfe00fbee69dddb55d9d7c03aff7bee20ad0c4888ed320aadf21dd3e44","0x0f93fb68e4a4d35029c2e6e37e8fbaf0fcf7abde224b7fc389f65504b99f67c7","0x22c13a36b93394ece7661a1f75ca51e60c6816e05694bd4a4e6323e6a1db1c05","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xa82f8f6c958193d7289ca0c3250ae50a25d878f38631027e7c10e2804faae1c9","0xb6d95983488b9bdca7d72c530c85014667a781dedc42896c5cd748e22bb3bf2d","0x5b148b6a7dbda11ade8127e0dd5c018f6d96d22db378997bbc2bc6da244eb632","0xae7c2aa4fa74df0312437ae2e14b451c39e9c5fb19bcdc686e10a918ab10a831","0x3a5c88255bbb208d5e2f1bb75e933b63b4155445b4b68f1fb0a87b5f8ff8b2ee","0xf39be90df1380d738deef2f36616d604c23f4e665ca34a36593604b3ea23a08a","0x7da98b47b8f6a7ee012df836f61fcb1cee9264735aacf93a74a39c3f3e3d6021","0x9561c901e046dc2696f2511d0034be0b32c032284ab8fdee47cfddcfa6931454","0xea4d2c57e6b4c09ad5099b64fbf2d477cec37d2cb367d1626c7485325762ce81","0x768dda7da806ad37eaebee7b7c0134572aa2ce7103406a9a71f48de759284faf","0xbc1bfc80aa92d8f5edba8c44643ffe975868edbf40e2a692544f02c59559b18f","0x8fc7d3e0d4adf17cf9fcd566bbfe2821ba1490bc63142bfbf21b038fda562532","0xf7fd882955773e18f1ecb9a233c3237fdad1cea120eabe90b4f68ab03ef54af8","0xe14b5626f8ee15503a39f5096ef038ca2e0dde282ae82b9956d297fc3dfd79cc","0xd0b5f3dc60d761239a7cf49f68b6e33147cea58aad9ccb75b0bf70df4aa541fd","0x4137fe1caa71a1f553b7ea3e8a22e70a5bb93f1975f8bd0a0aae45ad00ee180f","0x9d65a5651319e1eda4e5ddf733557de6c2ec58db45994c49ec06d3933c717107","0xba6e3603dd280e0b99aad923d51cc928ba359a90ba9c1199313c3179726e5a9b","0x5cf7871cf0a13f284122eb79fc41452f05ad5e25f684f0011a1a83c32e1b0220","0xa4fe0282760e3e25e07fab81fbc453b63203e7505e4a38be415a54ae6e291964","0xe0f824531222f00708a5b9b081fe2f0a03df88281d7f65491632afd1e8b9e663","0x52d677dc199536cd2b4fddc9475e31a5464c6e23b3f2feb7c89373737cff3e90","0x88bd5df64cb37a9573ec9ffae600ccaf15fcc0fca6cd41c7828409a6851edb97","0xc6021566f5d3e8e769aeaa4e57bee3c87361639d738906669a751d6ec33ca981","0xad2ee8dca7d08bb06534008a93e02d1c5829d2c45d0a87341ae602ab515d1ba3","0xc2e148834ebbc2e5bfdbc049a826c2543d555e82ebba54d1d9ce364db2c0ad50","0xe6870b3aa61c98a3905ddafde7836f3a081d8adbcef837337c217e29e496ce8b","0x444ced68cd327f2eee01863b53c22ce1deaa8e8046db6956e5147291ee01171f","0x4875c6dcce08945f91dfc6b53916142c4c82f97160d298d56f26512428a02b81","0xab846ed785bff95b1a60d91187db61a88f0cbaf38338e1d98f1d4eb49ce7decc","0xe0bc0f406ce4d3a8db74930aee3abd81b81c456a861678c12f91e86be534cbda","0xaf79f765a2df3a75c262b8077c71eb4e600aba68f05428b3c633afe9fe5d55b9","0x4f5ed337600c29ae79efe049cd573c4de6341ba5cd685de386d39c590bba2239","0xe9796fd29db503c276aafb1211fb5da02e8a4f463e2c5c9900a4d88c382fd25b","0x7fdec04292b8a90a2a37ee58d1dbb0f09c822cccb87684bff17a2c6ea3db33b3","0xf73676f7bb4b088802290d52b635f16bacb5f7cb5c1eb3149fb8b062f2d68c05","0x6817d1954bbdcc485d09c8eca0686f68998df42da77b70e2b9dc28e1a8c595c1","0xa9ca3e05f5eb5bf3a5f1c5eed49510e86dc7f050463bf1b2db296a12622c119a","0x56d46472a23f33614aa8f6729385f3b4daf3fd70b6fb4b846b69e09d759a4f10","0x48077f71d3bf3eb989b2106987821a1c5f40a75e52ab1035da73ca095acfc7f8","0xa0f0dc8491364fa9a58873467255618c42aa0331e9088b52f7728238dcba3870","0xc12701148047b3edf57019d256e11858df76c5fb8d140f896b363ef94decf25b","0xdc17e1610ec216c8d266aeaf79e8be1d4ff543d41765c1f625241df279b14c94","0xa9166a2770cfa407b3401ea9808efd6edeaea6086bdbe46a0edb0db6ecd2a078","0x3025796c698b9bb886a802b544e118b883cb2f8140384cd157be6cea36f5aef3","0x560409ea037b031339e207a81a18f6787242a06b0c1147e7ca279689575b8eb0","0x38c9d0cbd98260d24ef9617bc570aceb503e812c4502732ecc5c311fe76e1cbc","0xb171fb27055b360175936b8d912fb7c47590543c521ea48ce374fd09cd21ba09","0x1cb548c1cad662b7ffa4ceb5ad1624598c24024ad22aca124a26c1d49e927369","0x2478f0065de69cd3e9ffd85833911bb84af60a20fc45f13cc603c09e6f77c21a","0x9fc5a9d7b7031914bf5c7d5b7c991ff7122ca72434eae78e66fd921a2c5bffbf","0xf3d8fdb79b927dd80d7bc58c015124a4a6d0a99198dc421469d83518de2c30c1","0x3653c61b8bdb29e0d0be0e3065f93877f0bb87073c5e8cfe3f66adcf4c68cbeb","0xd5a7742ba7ef81b70fe72e0f4e06004a86c8f8a3216b3991d61a4348fe2f0f22","0xd86e0f446e30dcd0cbcb35c47ff6ba8868fb0929aaaf730045158e52bea794b5","0xb93b8670c12b0e1bb171f22b28944418139df741c7ca8aabefbab564e43a7094","0x23018b2c1c6b3e676945675cd40a7db1962808d5df14af4fad36aab94138df50","0x691352a6856a3998a82ebe458a5d82b0d881983c0958432dd05a7676f35a3cba","0x58fa49d7b6222b59b4d8ce027ddde590af3d3a10ee8ec246b9137dc9e71f7332","0x174c0134e2d9a6afd7df7d2847e498e206f9438ca87147f813d36642728bf26f","0xea9eb5f9496c31c20e07dce6f81df20d463c138e4f151875bc9d438cd2054d6c","0xac72cf1d93a2cc5821a3174ccc14e82c6e6360c5acfbc67d8399bdafe6a99f4d","0x29c440a2d867d3412700ad5f7816604b5125072acc0f9811692b2fb349316de2","0x318d618b1210c4375fe75da93685f47f68baf0c4622217d79bda1df3f28fce5a","0x3415f2bd5932c2912793ed384ceb149246b1823fecdafba873f63d3d65e89a14","0xaae959db0b48e24776c0f059541723bf43bc620d970eb82f491b8c90c1c56d0a","0x80515004d7baea180abe9c214f981b9f0b99ec9dd7613e056e221291f7cec8f7","0x9d2a178ff8aeb382f67e15884aef97ae9aee21883d969c5647961bb5002c2394","0x29c64cc697ab17a3be4f1a721fc820d999d789072f9e6f0c81d787cfcee6eafc","0x77a1bda974d155f0f745330722a692342175241fe363ad23e20d774bef24174c","0xcfcd0ce0138db27843ef0a476080f464e71950dca6ec7bb74b92bb44d2b61af7","0xef4fa22b5a26f8f88d6266e463fc2e7f04293f64a111236d368ef5e0aa3fe488","0x44ac2f7b702f8941f6755cd5cd070aca5f2b9469c09114759759acc82062a745","0x88763860a5d78f5ba44023cdc436c5f640ad6d7ae051b19be96de423caf1cc85","0x732ffcf83708e8d4f3e68516a2730b004dfdf709f50a7aedfc417fa6b622bf27","0x5125b09318af74e008cbaa969b65e4d91a45f8f99dae9dacf8b684f84bc0a5f5","0xa482ad00921dff839fa1d4945c887ece41d25f004647b31d12b1a28574c1ff96","0xf8968edf99e5c3234191d67f0dd2cdd250ab4d3bec89d76d8e852c9e4cd271cb","0xb76e48858d5b763c02fa746dd3017b91cb52b59c4e525680aec0bb3ef7698512","0xdcbae81f0dea0be60fa28f6538254b1134a40b45e88b80dab37a279f53ca7217","0x7aba8f25440bae48b613f26acbf2cdc5e390d7a9958dca1c176a73d0c11d2c52","0x055fa17f95736571c07a74dd97f7b064102dc388dfd3582739c9d8de3b782482","0xdd2dad518be25ac60eb7c1dcccca7c0dd9407ea0af1325ebab767189f51b368b","0x96a5a577fbd8c282e1ae315aefe76c7eb22417ad036be163e3104085d8262b06","0x525599cf3f44efc9c530aea87a0eae04d0799ee00ff1c956f992a1d6e77597bf","0x29ebe8e1f6706f778c775962996ec927400fa5bb7ab0deb539485858f7a1ac10","0xb5d6ed0773871d096f4062e1c16ab9ade153a2b3312252b5fb6732c9652d28f7","0xba56ea085c5d7413b8fa616c5daa7894b160dfccf22e654c0ab1ccaed9cdff8d","0xeb37975d5924edd9c172bb29864caee1bd005e14132bd2e38193605bd28f7959","0x35b917e18551683da4b81c3c468e438b2a4e32320ab89ce85909861e0bfdbfad","0xad85ad4416e73ca654c426fe7e78a816fdfb5dca45ebaee8bf09e3c15f2b3839","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0xe16f31047334bd421de4ceb69e8e04282568827831614ccf9093c6b33fea8ee9","0x224ba3466dd657c02935333e7108fc002501af2b3a5a99a8acfc8c6e365fc186","0x5ef8582350e5016a695f6af4b1a5ee777bae557f1316a6f6b6fa3bcd70799a65","0xbce2db293de435d067f81fd1c263ee4868c2b2d0fe4669b6ca9bb3c437b49f0a","0xc373b31a2364380088d53662e03fe3f983ff2df9ad8dadb6c7491bddb6f05efd","0x9f501386e3a58265b504428aeee5c34018f86d6c55b8b846c5b54d8b0de24c38","0x5912bbd81e3eb490991e4f502108e76b64c2b658c860004027ad21dfea414aa7","0x54ad539dcf38bba01cbf00ffc2215f03ca24d40ad35e770f31662a08d3931142","0x87f2a7849aa8c7e3872749bb84cac043bfc80b43cba9fdf029fb9924383ae4e5","0x0104827d606e197b34ec441b7a9e6d8a39f97a1d210d2fff87e03a3db7500e95","0xa55aa0a938a010fa0cc3964cf00c208e2173f07fc63aad95cabeb726b5dcbf22","0x051ef00ecfcea3ce4e2f6e7443a2bb5d359926d553c66b58c1494bb2ba0f5f08","0xaa5df3e6e6997c7045d89f4e73fbba6b775aa58daaafdf7bdab1295525622db8","0xb6247e8f54fd74d4cf3061e3bb8fe010681d2f9a85fef3c284d68538e15e5d73","0x13f0aed9d610ee3bea7fa76043518b1538cae2fddcaae73d6a82cd3d0a2bb426","0x183a97e3895aba92027c6e8d1fba6ab8c11e4f78a9c59035879f155ee562d7f2","0xb46e7085e732c1fe4fd92baf980576002bb15cb9ea15c5d8cecfb3dbde7996ca","0x0234b29e1af0cae195751b2cd7b7b6176e403e021dc60167e21a4139b71e68bf","0x6d529bdb2d3c017fb3bc8e50804b57bf8ecd30aa3606fa58e90343c188cbba44","0xc9858404a04cd4161d5c58253992343aa413ee754558d3892f6c4b650a35334a","0x2b11944dd827bbee3b422c2a1c40c1e275b288e389188cef9c0b16a551f343b6","0xd636865649eb339e2eed9b413d3a75513d85ac24e7707f8b791b79ad6ecfd1f2","0xcb377e9e8a45cb159b8e3c36c37190df7a5721a2aa95e78eea10544a0909f958","0xd8842720651231728ce242b24da4d8187da8aadd079b315fe83994bb2bf0baaf","0x8cd9fcffa6505e69d04d6a20c9ef31316cad1bb8a66ae9ade7b9f0377ead2827","0x79b49900b45d2a3a402b767ece9a9443d313969673b46a778ef0fe9567247db6","0x4ada0230b5508a6169d396d7423d41d53fd6c07a253bb90d46320b6c6857296e","0x65feac569d89c741b6029aeba10ddb8f7f84dd574c0f745d6d33491de01e0a35","0x10d6e4c5010ac0940ac68355cc040e5e6134a8211719727096dffc6e46f05119","0x72bd073aac46639593424bd0b1dc7657f05f0330657706d8418e6286cecbe1d3","0x5c6deae95ab8a455642ca0814ad85a8bc6deb8f7ce15a549f009187b58a042d0","0x88cdfc07933f8b95791bbb4b90a06cb20f3c83c95ac2b53828001f46a436a1c8","0x5de673640df477305cac15d04bd75fce477b9250bd20a0925e4b435d104230cb","0xc634b705eccf47bfba0e72064d2594fbe3330db7cc0604a3496fe640b8ff5e22","0x8d62427706415845e763fa60cc9ae5836b38b080e7a3e54df0a43adee7b75106","0x39ee8b066d9369d19d875ea9898d434a7c534aad31178b0c2b9fabf5478312b0","0xa65c2552c891df00378ada9847250cd3e86d6be9fe8b017c8d40202f23e90cee","0xc8a89681552cace4788a8710026365eef7e733436bfc1cfde9bf693e84684190","0x5e45bd331855e36b7b503b2d3dd41cc54ce4276ede331b5c56509cb76418879c","0x027414f042f1bb32f6cd2b64c0cafc1bdf00fe0cac49d30ba12ca1a0038e7828","0x0f4fd8b92e6acd89bf51e0120cc93116edbe3fc5c3e69235c043f1b7bd791127","0xc2bad1eeb08f1d7b7555fef22838437c0434155d33563a30ebcab9b05e61f6d6","0x0e5bbc48e38893556b783a37f701947fe2a8b76c80b93f3482702165110a4367","0x1e0ebabec898c053365608a3cda324ca1273d965bf14bde6fa83a05b648b938b","0xce5490084c1fc9f2a7f68c261ca1477b6162dc730387b05bc6743447b9e558bc","0xd0cca87e47d22000e7703fea9361f423ea00f7aad9db469f24a89615497372b6","0x7c606d8e30e1c9dbc872ab2c1ac0f592482b7d47fcfe3b16a33a9fbf12101b65","0x3a475e87511b97028f68843b5469e9ccaf0cf2a722dee9604da068baea923a41","0xf3b4a1ba80cf06a2db72ad64d52573ae33bec1e1bb3fefeac08f536e669995b3","0xb8e6d03fab4fc0b2f01f0c38278a76b2809769b23e11cd736fbcce7558322052","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","0x40e2a23ad4e713184d92eec79926870473ab9647f69472b2abab4f4369b5ce65","0xf9b849834c8c3e5354f48ffa9fd72ed17963324dd28a5beac6dbd50dacf6a221","0x6647b59a4855bba01e2c1ee68cb5085c23b5ea5ad743eee0f371e2fbef26a4d0","0x589e270be40a2bf15fe2d454be4ae696edde1a1ebf4baa02b9c5d4cf97edffc0","0x099febc4c4e46c27879cedb03dc3f15f94a8b43da842e6029373d47e1a648606","0x7f963677048b3c328f06fdc56df4798c2cf96259b59f9d3ddac1cc1ee721357e","0x2c5dfedec06e936400f0640c661874fb6bad9119d021f75e7dbeb47bfeb3a7a8","0x2b104c84f406c73e7665b8fef04e21df2517fcea6802da75a47b245dea8abf0e","0x2cd71b707180cdce2811ceaa0aef420c1232df3f53b8983afeb1c906b561de9d","0x3ee467575ad2ddb0a7a8412958167785682494c53320dfac4d03441b042d4a45","0xc331502c1f16b6c835b6ff60f7f25d3ede877355acb9fb0db2893bef0f87bfd9","0xb7c111e2baec5e330480b6dcdbbfded1eab489b7b478c627607f96f5cc816d17","0xe7831238690b2d6585ebf083ad1b1653ac5300680e6e66346054a3bf8705e321","0x49b9696e7cf24eabcd013b3630a2cc26c69b55dbafcaa2438f2a5b3e8708821b","0x2c4acf90d7aeb9d7a8f8adbff5d9bccf80350c82bf1e5461f20364f2535f7020","0xa79fd047831f097f565fc04c31ef3e8737b75531e76a64e8dfa6e0364a676ed0","0xcec2b1aa69187520f5414347624f799554b796fc1907dbc43be0bde319110040","0x44794bb6a1256c80d535e8fecceeeb28f39eca91ad10b9aa085d0225f24f4ab6","0x9d47aac9ba7225f99e2a742ce6c293a1639292fb162246f341a206b05846bd0c","0xa6a736c8d0afb387bbfc8b3c8a4f7c4c7a5ad12d3553dcd8ec08f7c45f033039","0x7f3dc6cbb209360000e4cb5ea0af9ace288bbb54b58960af334dec60f6d2ff8b","0xa3686b5f0142b5a6bc36944c1501926cafe7bc4efe41ec332129e266fc993a50","0x00765047cc33f89e2ee6cbc3551b05dc88bc9e087f453d3ff93b309e2f586012","0x402f7c445c4d0e657c9cfa7a89ce1a6ddbf5428624400eba44c1babf70666e71","0x5a34bf9cddcd329002e958192c07604c3334755cb911f1067271a5c57e33d29f","0xa48e547ee4b912740ae1a2072dd668800cc12f45f61097333f0b9f7f77fc6e67","0x3a8e45428e383c76a2804ee3918f90e584bd2de90bc6ba0599fffcabc8e214ae","0x50408fd6a81aea9c5ed379fb14c6aa864d1d8b02a9be06607dd8e7944dbbb6e5","0x50f3b1fc72eb5da58b21760d89b68dbb6999d5688b2a743e62b4cfe2d239973f","0x1654d21aecad6fa136004a790892849cb59b009cf848987e3ea2cbe992d9cae3","0xa195c2e549b3e0d8dc7be9b7043464114874121a3b4198144d5b49893e2b847b","0xf073e4bcb3b28c5cb363c11bc3bae11dec5b3c1fff6e28513d0f8c03e6f6d4ec","0xdc8d8983c9180d8f561d6556cb4c03d16f791e2a2f627259c01c7f119ed731cc","0x1833f1363df995cf5bfddf55680c095504eb23f0067c7f214d146eb6a0b5d38e","0x2f0bb47b1cf4055a796baa68681e4ca55cc6c568cc6d8f7fe0faf913df775612","0x360cc4533829265910b0c07c39d4799b4d9c5ab68e3f4d31b0ea564ecf01ed58","0xef96d0787ea610e933a3453c7f3135b75437e9a2d14dd7e7d9a98e6a19e01831","0x75a7855588e219608b3c165e48cd8070a9d34f825fa29e6749af573e9eac64cb","0xd5256d1209aa84c2144d7df6372a946b968abdb3cf648d1926eb715368c74151","0x29cb65b70b3b5d1a1c6f0d181cfc144e690854ad5ba8bf295f21df167e826317","0xae4c3e058446dec8e1917cd94505cda71b5fc6246a925cfb3cb65045d77e0335","0xdfee6825c80fc8973c99e12d125b2632aaf64d1bc56fdda386af3521db9328d4","0x932f4b549adc4a39d5c8fc4a31df0a17e774aecf4286e8369929f42e60be4bb9","0x0aca6c5ad88ccfee16321bd51587e608fbedb6680d31dbcc1a01412d22f406a4","0xb6e12dcf6fbd9c2e0f1e21375b10c056906e29b3c1938856008876ef4b3d1fe2","0xa3e9e37471f71943d42affa441f647e424aa29038397d1018aad1a0911b26f86","0xafcce9564dafdf67e0e04f74395c49cfb702e061deb8e61ccc8b16932e6b24ca","0x155f452ddac58a5545e6d5e5b25c4382dbd0a55b3ed362056899dfe97ef22bd8","0x8fe1565357dbe3c12c3a9749267d9e40b862e4160891f927d46c9794f0d0be6e","0xf8490908a73c1fc342454a0a81fabaf3092f451600777262b2aa13926e72da05","0x8fc69adc2a52e6daf4159a98de8396f973ab9942cae107a8104ddeaec0f1e39c","0xc0c22d729c527e24137b77d48641e31849aedda5d87136a89010b98d2cd819e4","0xfad04b5e768fec60ccf0e6da69c9fef82358ebee2a2e7a8b16006cf5fa7e3da6","0xf066cc60c85644be4efe7778e7c7a8cd0fd629bf4349297793f5e0e7be8104eb","0xe20ed5d92f1ea5e83ba57c7b0128f6b81e8ea85c0a83214789c1ada22f5fa411","0x38fecc956fbc758dacebfd4703748172a0327961f96245850cac33a853421983","0x546216addb06a763743e245b2cf1ff42ad8196107edc51130bdab29c38cff0c6","0x684c10125db6783e7206c528d7ecd2dbbca5b7894b49c96c4570f7bb20f0e66c","0x198137865c1a17e737754e9a4dfa937de15bdefc900052b2619c91d04c6d7cc5","0x42a0dbc46f17f32e3b0245f1062dc95353a04b0a8ccc3830357f1da84b7919e9","0x8250779721f476f6d4036bd5507d30e624d21fabb17903bda297e84a1f599296","0x778b5462e591722b2774efc954a2fa1fa9312d87b78efa803c845e0324060759","0x9af6f768cb2345c202fcd65cd65823ff2eb190b748cc7933f2175098d832ef75","0x2cb601d26231d4fb7f68460e7596530bf6201106820f0dab4b81328e8a7a3849","0x2a1c1c5c32c000620d335b7e0b2dcb7a17b66b62f33191672def32af305a0a02","0x1f83f05556cfddd4cb6a2010bd5984e86c9262fd441790485b6d6602299c30c8","0x98b767c6f93e4e024ed57cac0f886f9d070da3e2e60817266520cd4a7a443563","0x8856ffae995150cbe278e4efc2c2845dddba0ea52f3417cb64f6ab204275124d","0x3285707930977475811401b21e2b266101440c22464e0378a55eb68ba632e638","0x637711fdbd12992ef674fe5ebd85a5dd85bbaa0c13dd655fa3a37d0676bbfee0","0xdf51433a7167d61b19b17565b4a659c8f542ad21ce0e38aed91a4d7c73dfa87a","0xbbf49948bb413d1efffa8fd05793b52697c6f6dd12380b4876119d01a4b4d90a","0x7fc5b732a968f5c0999e8abbabe1209aeeb6154aca22693d7608709087d54ee3","0xb4d21630151012a3dc9c3f531ddc1f00f51b886d3bcf8d3075d46d7b69177131","0xb800ea9cd255f888c1ad24ef164592129232c18adfd8316e35748a8d08fecd07","0x958c5c91d99a27246d1bdc773bee631c8f01f789a683a6bf107646abd0914029","0x04558d02c8f022ef2d6ae5f931f3ed01c3c106a1abc21ba5288cf79af199da7d","0x8f94d0293057d9135f69d55c75edfc1c5e3640f15178332acb25d31017470e02","0x832cbeaa9a46d710dbf8911e2daa1fbe7046dd5bdb8c28256d3868a47b5dcb67","0x5053a2f953afc7a322ce5a33b8026f4dfd2e7c5cf326d0969ccd5ef39c6ab412","0xe8a4f4c829059e99945cffceb6a9da3d5fd2828a3bd661c9a395e92d7066230d","0xc4c45051f182fb9ba2b345c301ccd341c79fbe8836e7103660d3e9ed5d8718fd","0xcda03d1a4fa84063d0b2c7ad643bbc020a8244a29a5ee572b04854292728f02d","0x7d9255d9ceacf7c7aca01869b07cb0974a628324038f861d5883d10369a33163","0xfed549d7d56e68cdc7d4edea483cc7c576e1daa86595d4eabff089249bf95844","0x3cdd58b6c41f289bb0c9e4b1932215e7e94ad490b5061e9d77b0f3eac38f8608","0x2bac1629a1f132b85633afff341ead96f7aca9a6d411de565d2e249bdbaa2c06","0x1aa3f5ae77c717dd3beb7d2fca5b0e6462c92a982508d8ed56d92f4c29270264","0x52c8dfa7473ede25c3813da8543a4777f543a053ccacfe24faf232726d6fe879","0xa6177868019f0a6fe37d37332cfaea05175ef3c59f1cffeb11bd106c758347c9","0x80018315eef32f867f52c95d228d1bf087977b81c666d1040d1796eb26655fa5","0x8babef9bba2e091f9351e15902a4a808d9e8413000a51495a9a073d7ccbba288","0xf88d274bb1e3c6b082a889591e4ecf87bdaf8dd4e837c53a19380ddb72ea70e7","0xa6868d24c93d5ca206dcfd517a22f2e40666deb0664f239ed89d4129e2770b05","0x781f8765d1745366290e1b94bf2c614bc06b363ba20cd2162f5f5af734f7ec4d","0x27c1a7ece0fdfddd6e0234f0277acf7747eef40d6918c7cfecfe8796dffa53dd","0xc40fba65744b78a02402bee1ae5dd4abbb4c479a84e754278cd7842f91f5cf3f","0x5df41c911768ed40455eb3ff3d2d4cc59e2d0b0d8866c88b1b7ed6cd30f73ca5","0xb08ed1a6de4362a4262dd134e96c19c801539c52565b6a73cd709edeb30ed0ac","0xd8b6a525c318d938392c5f41215cd2a9a47d385c2aea3f499de839ff26ff0101","0xfc92928104c6e2d81c8e1d9a8ab9bf33e74a893cc4a17464b4c7e40c3351e0b0","0xba426a9a5ce6cf404efbdc872a21ed3464640620ac8f5a4c32ce5c28cd72e9ea","0x3b0406885950d44e058a84455a53dc695f553746058db85de58b258e4a57a330","0x79e3f6e89314a47509a56461276e50ee944730ca14a3ddfc75623213eb138704","0x58223aa15414313950dbbf5455c056140f650f32b7aed23bb9ff461cf16cdfec","0x2be1559663f835dce564eed3d3026c20a2277b816ce466aaa5fa30e6fa9c5eb0","0x73521b8febea49b4b7560c7ece8ecda72f2fe0b849200b4d92ff034967b1da50","0xcc92e603b4ddb4d62b2af44fbfb7cd3b5d8a4818fc3d2c78fe5b61e58aa36999","0x05d590c1774d036d46a61a16bd02de46398c763f627d554200bce6458618eb2f","0x1f7487b4d0f113f2736a02b9003fe5583836c90fa7ea7ee76cec7e1a74978e54","0x47ffffed3d71e4fc09fa0c65d0d5391ac670a258e03d4d33a19564f44360fdac","0x848bd635f3d587da452233b7562b2dd6b826c0f0ef96874afd53a05be071e0f5","0xcf6d2b35573ce20691d60dd9cd00a1c80fe92a019f987eaa3b96c5df661b7e57","0xb2508a34b91eabfee8df2a894b2e9e37bf16818d530db9afb6e5043603c93342","0x50d129c6973ec79bd6ca326b59fe25c32e9948fc00eb81d6265c6a62328f0fc3","0x56f9591e5dde0013c0e63221aada50cf39fd0da67cbe28a36d596bd75458bc41","0x4dd628dafa5d34c4800fa8774a6fcfe58d2e4f1101d78460de5c57d65c6fa055","0x00d20bc57a97e0ed9c06da5bc22c76c7bd444a70a50f1370305e11750524979f","0x9f76d457c0b2c67a585bda7dd88f002e65a5153d733d59a76ad5423fff3d8909","0x4eae4ed06acf5810d2ae4400a613c39f88edd28f3fabeab388bd749a9ffffbc9","0x2c20abe1eaf4aeb34f198b54a84b799d492c9b26e5089dab7035eae2390af348","0xf3d2b5f6321f296457ecdad4bdc136c06c6f8cee636a027753e5a0d0aa508918","0x2254a6bd7bd74211bcf86a8c1c8ba1840cf32ddabad0b62aa3dedfdf18ced00f","0x0d64a6403d050cf944ced12f5a7aeccf9d6df304d4b7d7bd52af9a5c934d4499","0x37fa1302a2ab8c9805c3e34490c91ae469f487c3b198b535d3cef035395e61fb","0xb7ae12915c746f0808b773309e11096e539052978609e2d66fcc7e27a25f4a78","0x0a42072b341a582177298f018f1504c768486e06fb370e5b40c9cab772a6f1f5","0x203b28cd9a3d422a6eda9844728e51c81402145e620aa680aa11a3f85d9373a0","0xaecc28ee49a084e13b635fc2df3aa5c74081dcbf4a9be73596c980b639223734","0xe65da3059aa14ed1bafdb9d407eb4943e739f227984c77016c75421d1fa653ee","0x01c3b1838f36d2b08688ad45fdc8457736b9f287e76959c2893205f5fa84e47c","0xf58bceae272662442a9576e37cef33914341c250b97214035e486a8410066879","0xc3b7573045764dd8a5e6d9fc3112fc24019c529a6ed16ef2ac0bac10ec166e6b","0xd8eb6bfda8636f360da51d72e967a0452e64ac84c84695fde1d8a3606139e85c","0x8ddc955c089c95073afa63666d03609b572d2da3351aba6d22c6e080e9a77dbd","0x9d60a7d6132c49a46184b8272642ca51b9034284b3559e35e8885c2b48bac1fd","0xa6ad8d67717b6fb9e8da3fabcc024ff58177a60286095291f8b470572911de55","0xf91bed837404a9950ee43ca3dcd3742dc7008a5b006aea3cb5f17bcb7c0bb71f","0x70b984dd91ce3e1809b32be49229671c8d9447876bd838d3c8d7e47aa50232c6","0xd9df080079fc0b1eaea5c2a0616943e6fe72c1ea1ac0ec4b82e5b5c3a51fc192","0xfb49e158a617025dbcaaa7d4a0204148369f7cd0310cb155ec8f3e2878564e2c","0x955737eef711f5137e8b6189e640f15a30c34765f83787e2ffe48fdcb160824b","0xc0fd76c85e63728d98ff0c9c5d68ddb847068f973fb1f49e589b7b6f0f3b21af","0xafa018cb41326ff985405a86080e02c146e4f5b821d724db45c857ec0647c9b1","0x5aa5376ea4b7daa8055d1f2aa24765d12b5ea47d5df770d4d87b7e7e7051d2ca","0x8745115d75466bfbc1b4a6bb72d21bd0af4f90bc0b1a60bc32637702685ed8a0","0xc763b44cc8bf6ba2e6734c33f775a367584e5718bf95ae23b7dbe2c3e151f62d","0x9c7d4aaf5766955b3556c9319161b70f574fb896d38ef10041046902f3498523","0x0754930c5cdd227454a8576645af8ba56c78b9aaa29b9b35c6ad40dfc017672a","0xafab88997edb717977d19b6aa8a015a9272eaff1aae0e22c71241e7adc4d61a4","0xc41bc46dcbb258df45ea3b56343c67d7e6dc34d30aa518c954a725be288287b6","0x71974d95a7b4730baa6eeaf9c0208bb4f47c2c2884444b2d8478bac399e5b99f","0xd800ec704b1906a716a4eaee857583ad611f3af93bed6b80d031d59003291f6e","0xff0a97c17d8c97e368f3c6f9d69f255e565ee6487f1a44228fc2dd95068d52c7","0x9566b57bb02dc0790e9d6c38dbb7e288e09f82f75944c0acd8dac33ceacb10d2","0x2383edd984ff70c65b9cb187c9a3123218c5208b37a04e22dc1bbf6a041563ae","0xba6ce8b580ba6c53174573f936d6c24df97c654629f36e4b8029b957fc7855f6","0x39da91aa8f8a87d0a69394a10adffd258336646d1508f6732444d8f01baec7ce","0x8841ff8c79345854eaca21449b2a15e11657a6d90441e1a40ba39376135f4d75","0x5d7bb4852b4e1be7f1a04bffeb60033384ac73e04226b93c4adb079c7d9c9539","0xb45f1972dce352d5f0bf5b6828ef34fffa37520937f75fdc5cd3396c288e645d","0x395a33c68d098f09dad54aa1ab76611fa0854df332e79f8c63027cff9b4c1c6f","0x55b633be450c8c766fbdfab04f9debcdb68b63eaf770f933d32a6af44a519a95","0x1aa693c7a30ef3fa45b324edda8643ead5f8e8ad4ebf85f682616211f4866544","0x2655c31be6c66ac423a022b89f2de921b78c3c92a85ce24c460124288b51a19e","0x0e65e3fbaa858a2a772827ef4d1a8af0c38981ee2b8879cdf0a8277f80fd8d97","0xfdad0719051d3220b46c368790cff88fe21f49f2c7faefe561f3a06f189bbe9e","0x9c119bdfca36b4ea0ae3a05c5ba71d2102509395b1ce9c728a41fb64b5e2db68","0xa371ad6a57ae8c7f8ac46d722de3cff62020c3aa7203e54677d7cad04319d6c0","0xb2ae9a1a5c6e30e418f7ce3b3f253012ad3209f4e51b55db1cb47ab87dd1a0d7","0x3c7200638fd3d49506ca8fe823cdc2ee19743a8dc603c3516cedabc4170d9948","0x2d81b75ed86bf4f9f79bb566507514d1b2ec82fe37db510bdbdca03e8b6eb2c2","0x68f30288af7788a57b59e97ad6f8d03758e716e19eee73915ed92fc8ab1f07ed","0xb5e807ba64dd2fff7f5396430e5eb0d84d99f07f003e3c4b7117b350db5472e4","0xc4f593a4e6e679df31016da0c4f6b4e15f5536fa917fc10899bdfcce2c45b135","0x17b7be228cf9228b6da178bdcae95e158de17fbea2ffb85f651b452f37cd9036","0x515aeedd01e912a45b60070b9c0c4fc337488585bc1867503510a37db23ff6d5","0x33e4b3600c6ea976bc393f1edbb1be5b0ad8a11ac00c103f7eab36ee06a1514d","0xc1eab047d010883f76e2151e4fde936ba889df9a75a42c7bfb7c3e8440707fb5","0x2a239e48dda5794c2171ad5724c95cf07caaf1cac66c7cdd92754d79a3eec1be","0xbb6a058959d4f09b2728e7b58a83c393a6ea4bb5a16ae058dff64d144ed11d33","0xbcc55ae5431886a930e92958d2a242002647f0bc8f8412026441252bd8c6938b","0x621e7320de30bc72834e72d90a7f2282480e5067e13798a15b3f663fc5a49ad0","0x7d9c251c854c520058b49a874de2d9d52b8f95306ec828ff96c31dfc2f5d6b5c","0x920bc1943f4b94a00870f381569dd328e8b8f83f14dd97111cd9837886ae81cb","0x726bdec411fdc41e858b0956f224af45833feb8f9ce040f68734b768d6b01e8f","0xf5272e3d9c68885c1f51579ec867980759b5e4d3203ee747f2fecc2b95dd1cb6","0x9c924144014336a43ea64ad55913283a1b1b02c90f52be7aa528621963db643f","0x19c9e6dd698c04bc4d30197eaa4945ac1248aeba298aaa853aa1db55bcdb9d74","0x38d1aaa7ff493d057ff37bff8072b9929df45fb233461f34d08c6d7d41b03f2f","0xa4e3d1ca0461c84d2d8c8bff65d96c241d24b050f815859d91933ba56a7bd0a2","0x0148d9ca04dc1cebbac205379de33b01a96d84654040a27d5142c08f6dbf914c","0xfc0365683be62985b15470734b32ee459056675220634aac42bfa2f49cb7e4dc","0x1717ceb88df80d1d1bf9d715a1fbe47e06f4ab71da40db5e40000ab16e34f5e5","0xa249a20a0b375ea159b1d11c2bd53805d302a4d161350fa6e5825e27c1dfe1f6","0x661ca0d33feb485e90df25811dc24735c48b89857d08244530feba0c3875d821","0x365d7be036032ae7340c6ace6b3ca6c59aa72107e3146a7a6058aa9bd48d5f47","0x9783e6f208bb77190fce9f8086f07401ff1871b7e9f74b660b8cfe696f3dc40f","0xc6eb8dc8573e0c9fdc264b6b53eaaebe1d837a34c4e0fea87cdd54799480edb2","0xd45419ec1643e683ba41c269285cc107928376ab0893c314b993e670be9e89d1","0xb7ae2b1c5e8c3112f614a75a468c984adddaf05b00d5d1a077873b05709ae564","0x0ea37d0d653a954922c8b503d37b8411ea34aeada7e1c2924d129a30cebfaf7e","0xccca8fd93b35f5dfb75ce92c542861a9723cbf2401c7c68670a8735d36f697af","0x94a3ee635eca49f3c2ee3a74a04402924b7de0b17ff68d129e13d027578c10e3","0xde5a028aed34c5f39a5093af018c168233b55843c60f9b091243517a59a667df","0xfe9c679b9bf6e2d88cddad63f370e2388edf0ffad0f6276e0a20ba1c5c949c1e","0x5f6abf1147312140d460e94e00ca80a1a7513d3a6f400ccc1d40306d5ce46854","0x1b9216aba9e3f1a0332babd80c55e3e2f97669ee6e1c9d4c2f3343fc35de0913","0x8d0a5f6aedca916f2e110ddd7aa21e9230c1de47e49b16e59ec81a88dbd39126","0xabd9268628f02790e916b393570c5465d8961032c8fe399b647810419c59a80e","0x75e24f1bcaa0c6cbf53aeab172202dd42f2b2e4feb273af675c7220a384a1533","0x8ec13efc82e8353b063e5ae3c9a20edfe9f7d6c51e53c497a4582973c453c826","0xb9d98119f8a8c818393db4016b95e8d04ab6a745f33b94b99adce21dd0b5bf64","0x2c390f682947e8946635a1a0a993999a3828bd36ad73fb203aefd67e60d3e9aa","0x73fb52b6d5cbb5735a00919830a3e93a270eb8b28f59c26e3af56fe6237ad9b9","0xd3e888efbfb0dc910faee7daa9f17a24f0ac669fdeb94be737dfd0bfb12842b7","0x85664ac17435eac08dd55d7ce8916f72a0143b20f160330a81883725c6530769","0x7102c9cc716bf56312f1d46b0a9443f8ae0319de0cdc86b2c7ff06449429b907","0x56b47016eee0fd6cfeff5eca394abb7cb8d3cdec96026f87197356cf35f99feb","0xc5aac096f79648cd291f8b76b6b01dd4b7c5e8e7f079f755eedccc8cf06e32fc","0x4e6c392fe9c57f4bd433288811a2a69f24d3a69d9c16bc806020198caaf5fdfa","0x80e09558a6fce9bb2b50903a7dc6beb1a2c33a4ca1ace340976a19a508affa54","0x61f2db0c31de925bced566f8c393a4bc5b2a3cf804e9264dd146167b5545ae8f","0x842645ce0f6d1601ab8646c5a46b9b4369031fbc384da361a2d3698f6f3b4a02","0xa9482bfb8e714feecd506a107f45c09a74e8a521316d043c53e7bd45c1fef604","0xe28540adb069e3da6cc09a1913d9f21868ffaaabdef9f4e359d430caf89e692d","0xc3af623db94eddebd9f8508888f6c46e50f236df0730ac2fd484d8a9fb9c5e14","0xd00ef8ed6aa7aa328755ba307e759fed8232ff4729a6778d01eb4e2699b388eb","0x097e6486896336fc5a645a2e5874e7c2dc14270994d0c2b8d13c6beda52a2f95","0x78c67ea30a041293d527978d993c069f0e6aafbf6964e60eff6c8fa3077ff74d","0xd637df3fa059a8fe7f40ca67df5a559458489c15229581a017970c7f51546ae6","0xe306f85b9c1b121211cba68ef37e108cb63840449522fe2dfcd9101708a81936","0x3bb783fefd0c9ebebf6e4e39d948d8b48cc9dc23d1029b9f10969f0b702b6a28","0x29896937474611ee88d64bdff0e960897d2d635cfefc280512939c36e1965f68","0xcd2716a05d5222147b99fd1f215b63dddf7a7bcef7c54f1dbcb72f058c0b8f60","0x4fa5e4c1abba6575ae0ffb79372eca95f2eba06ce336140fc5b17ee18bb4e37a","0x30cd4177c685d01e29a9ac9bb375eda09b97314bb1978e29ab2c93788b34df05","0xa7f2b3165eea24d953a890aed065a52052afe0d67bf3a494316789a3fa08f0d8","0x6928433b6430635deec733bac0d330b1fa9e57f3a44290bf061296b7eed0d44e","0xaf7f0c5f6f1a80295cf63d915629a48d6072d142bbdd0198827cd147bf88dbb0","0x18b97662ff2fc142aa16f715937c271df6f6cb479a416c596efcc677875fdfef","0x878216fc585d68a4e815a66a753d4a0bcc2bfcbcd11c68a9a7c63acfe860a621","0xf82342521afb9758654503348af979e3fe6d6751a30f053b7f652c04994df00c","0x8c8e8cc663abf90015a9dd592b1918ec208ec6e7aa383be49e3315c78cb476c2","0xad30adbffaee3194232ea94d448f43bb354e6344dd2b29735acad20766418a2e","0x7ec1444303c179fcc2e1d9729954c4ba4063298a282f370fee4cb0d6bc807b19","0xe39c8f1b6c9cd39997db47e1e3121d65275d5ed965e134a4f030eaf6af846e6d","0x935ea1b4ccd21c413ed3ee5925c1f9a4f8bb94e266b8df2fa9b19911f1b531a3","0x7118c5159a8dcb8b1c43da32d4886a16c8c90313f6c1d4dea3073f5184b16b44","0xc7a65479d7c1b0701e1b3bd53939ba1f5b60af42d043c984123976bdcfa3c911","0x5fffa1a3ab8cb252bb3f45ba8740a19e4702fd93c87ed2d6e4001f3bf77a6aec","0xb26906eee1ce487b3d140ecbf768e6cce4d30396dd37cb79183442aecb656b94","0x573cc07660ef4c743ee741582f68720ee39af334bf41951f3d31850332fea977","0x97873357bbd3649eefe0dba687392334e2bf667b842be1261b62eb7276d09ec4","0xea3607e6dbba69537d4b50f8844f0e7c12ccb579740911b81fbf79aede17dea9","0x6cf3d0141aa99ad2b3c097d3e6216d71ce548cf1752567125e01411f54bb0844","0xa38421c6744fddfcbbebb8ed9cd38c34e1067eae0029609829d6424f982b0b1c","0x165d64cc3867c358d88cc9592a515b5226559a6b473324640985e59a0b6a4794","0xc12b323a05adeadb4510adad12fcf350c5370b0d2eea22b8b1780740219eda7f","0xa324b57f5c71230e0128a9c68cbed883dfda0637fc93eb58c54b6ffc714579cd","0x89f30ff7c6eb73deab9f41a612e37820edf1ea5ff326c07ffd216060e2186e2c","0x2d8f50edc52efa2846977f11ca965e54f8b7e471c0eb975d229b6ccce3461072","0x4d0436b15b63f76115bae2c7addf541e40661636d2803d52d63311f2b29cfa50","0xe67d0554951bf27c1aba6531b240170c34d12f1d3d7f33b48fa411c510c836eb","0x54a80278b8dc3db3651dd663d1579e2aec097fa93701b33ce7a7bc3e06885aa3","0x67218dddd3a46a9a19437e756fbf9b14f5869e02021fe4ec0605d07288937c98","0x5500632f0d4d04af6fb94493f8da5ccc9d5409a282ce12ac77838e288de0cac4","0x3b82d1ad73aded55861b637ea9fd1f0998999cdfce315c5b60c9b2cf4c49734a","0xaf3cb49b05aa7ee778f7f1aea8c62a5027125a01c986301e3210ef5add28f78e","0xa19baf29a3910652d52974aebc9eedf940076aa9aa66d410f4a76020e203dc5e","0xca335a86be1bfa7a0550022b0603f2f9445af7106ee70fa299088685fad00ae8","0xcbc40ca95e910f191e615c3c4791d8e42902c54763825b9cef999bac0e8a3e0b","0x6fb107a4978a3ce7a9e8565dbd780a74554f065cf7a2f46e99725f07706758a7","0x2a51df163574e60d882c05394250ef9f60963daf394ce0c37367937630a1bc16","0x25d45477dc0a653743144bdc113dc109dd05581db656e23c8575e5e6147ef5fc","0x5dbabe11ae67a32ad0e34823611375db17afa80fd4b295ec39a9a8008a35b248","0xc8e65480363fc3c4cb888484e225bb209fa7ce239909573755093e9c1556432c","0x71cea686dd01b3cb2339913ed451bd76dd835c6204c15636ab812bc33f6ca5e1","0xf9c1027caa7837f5f804d7642a47584a98f2160c5d6a2b246203bdd8d73b690c","0xb85536ec1873887890489130ce261d963b3fb19be805a0dc2a0b94e299347b13","0x39532307208686f090cfcd950ae0e47951033305da6ac1197df4d09048aedaf1","0xfe94bf8cd5fd67da3cb0ce7bf3d44e4f756eefc2145684aeb88b9c9830295f06","0x1777d2958eaa5ea1b6504d5399cf041f2b668d6f49a6422413862c43fc1f861c","0xb80025ad759df4a6beee0f4b4bebff15c6930a70c4c7bde7111adea33d0d9229","0xbbf1cc9b26ac6b012024541896fd7225ac31882c338331df5bd8d3bbda4929c0","0xde74a4133b556115009d16aefbf28c74294e3dc983c19e537cd109360ed18bc4","0x9943d3f09da7ecddcc487399dc2e88c68f391c5d4c0a7d70f44cb459eeec7732","0x7324714a964226b69e925c0d7c5ef131b5ae7781cb247008f291958172cb5aad","0x334220aa64c4c484962826df74b0a6a9ef3ee2d06235b97a62aa59d35e513b3f","0x0de6a71940101cabb29841e511b2c4976e1db7cb3408ee0f4ec1de8886dc2c33","0xea37c32900303558f718d5e40b5aae58b0e5e414ef2b7d7edc068112fc03f024","0x46ce7c8853e28c287ed1b39c615ecefe84eed4e4303b1ee0bd6b2213b0b123c3","0x36e94731d421c1a89dcf3236cd95932ac0e90a5facd4604340d4cd4df802d689","0x3f2e6c22a3221b69e6d383c8359eaba0a133c1388557b12c39a51d1a3d6e77f1","0x336d21df6cbba4ccb3c00774e8cc9df59339b96c5e765683b55e4909348c2d21","0x4c0cd42b134d8a0303e134a079ac333e370ddc602ec14428c890be3f39224505","0xdad2b34d6bd22b09ddf6f42e2d032c38413d70cef263eed28e4a6dcedbd0c5f9","0x895d6214ab5b383307045dfaf9b5dd761deb5a8f6a169160e86281b4cc883388","0x1b7873c0381eb9ba8cbf5b8786303694835cb3c9db784365c28cca90c285f0fd","0x71246ca5c291fb79bfa22c58ffdbeef659ae10431a9f7bb60a1e3df127aba29e","0xe9e837aa563502a8197e370feacfb345c5bad29023a0c43aead8ccbaa9775c44","0xfeb3b5d9aa4de4924d9c5da29612f02decfe21749e29c3f7f485b8afecc7dc12","0xe780e7d46ac1ceae19b9c38f18033a524ab04bc901d0e20d8188961c42ba354f","0x0a6a37937eec75a47b057860eba3ce828d1e1ec1ad57970b44c0fa0eedb49528","0xaa67e93c2c3e23612d5e0cfbcb079ee9bece0cdaf4f4c1414d0691d6f5c74d50","0xd12ee4c6ab53fadcf3ed97e1a7234b5b7cc6206be9273fa54c6957b57cf1f250","0xf3a84b01900caff5ba90d88b12662c90c035c80352c5bc62e76ceed6498324a1","0x08d0bca7086f9c26dc08cf76a2cab83f32300188cdebf60b087c86dabb75265f","0x2e55651579feb3bc915bf992dbe41e78ff3fb53a5b239d1912815c57b2243f0b","0x8c92ae7b4b1d74602df0dd8f1f8449b012c8afd8b7009047b04eefc7ac3dc618","0xd85958dbb82eb7a910731060e591beeb3b89322d783c60201dfdf788fed28132","0x32e219787c0357edf07967359b06c630777a8187e458795e590726b289aa9e1f","0x0932335ff3be287d07a9c175626dd9633fb0151b6fcbffde6cdb5c6ae9018132","0x6189d95b8221bd7498ac30d36d8064579075c664922135065260d63522b89254","0x77aa6632d2ee969968766553fcdf309ac342299163504c686bc8c86cc597290d","0xfd055313975340f9fd3ccf91fc7b11d86b9daf2d5615850242a2a82360a82897","0xeac446902e5b34298cdb75fe15f6014265836defa6133a03be7e4623663418b8","0x2ecc3e5eb101d26e7e1c916daf47b5bef9366bd30d67ca12850c12a5db16f0cc","0xffd3970b9e81171bd95f6921cc30e58268f0d5d61dfc551063ee4ef5f83edb8f","0x278e957a0999add07dac9bf876bb6d66938d0865501da4a9edf5a402b8b8df71","0xa1790121759242c8adc0d63b662dda07d15634f579417905c165e3d9aa31555f","0x83596f8849d6b6801863699926be27193ff1f21f5f8088a7708370f9a85b6010","0x3fb43edb9aa0483917bda82496a719a362a349980803627c087601d219f71cda","0x79e4935ae2843a9c4a3dd6219ff2252e2aa9a7b7735600dfb8a15bd03c0e7aaf","0x29caf1f44b856bc79de3a7d02cb075fa3b62b3ffdf2ceb228bb5c6d79609fb04","0xfa860a7f944779b48f953b4df6c0071eef71eb95402657ec2fb95cba289283ae","0x2debc26fc71d0c3e3bfff878c90064ebea1f44fbd1b0770152b8dd37b20c64e0","0x3c82986df01577a8c74b3c6d27564a8c6fba671437140ce8ccbb3d950b80e4cb","0xfbe8a2fab4963e6e737d42a37c1840684aa751a7d834f3e31ad7249046948a56","0x0183438f9b368d23486b492c3ae5f466f422eff106fc672a33d3af5d9657c857","0x9f0406d0eed28b2dc275c45ba07b8720d686b3ebbe6eabb7e5d2c3be39362502","0xf32fab0385373435d48d2c9df5a4470ff7b0029a0bae45ca039772862536bee5","0x0d304ea72c3df7344f9db7750729828f90cfceb05ac1362a99cf0e7fe7da3314","0xec273ddc09ff4c7c8d4394c7205ad712eb507a041a48137e50dcb5f069fd9f22","0x29c0482398c15f77d8992ed12279422bc41bf7f6b1b6748a73f685582f4d8c61","0xc2e7048eb87b758ff4378cda45af57861824d424b3235c1dc68755cc2612b0ae","0xf833fe225eca27066ecb9276543845193f786166a8ed9e9d8b98094bfc0cd27b","0x6b23c1d2f949b9bbfbc0692a2b526ef55c6b326b1291c6c1b95e99a0de12104f","0x925d0ddea0e6683e853e358ba1e948e9951db3eeb56168da76f5a0d7c18c1d44","0x78450836f2171c1cbb38cfc844bbc282ce8a4dc2e1348cda061b0cff68aeb416","0x6723813427354705f00fc11b9f7d3c583ae910ab23f3b9d0fa0b4f5c33773506","0x83dae1b66240659554a0e35d0da3d5a4c2f5af3faadb3b232182591a9aa1cc51","0xaebf55732b7fba9f2a9a7963125faf09f846f800ef796736e1426717d91e683f","0x41db2836828a985d915a16d8fdef2c92b8287a64efd815f2cc67643e26066101","0xfe1390db186e7abcf73b59ee1f06478ed309600e32547b2d6e4d0d1bdfc555b2","0xb22c860df7e2660a7223b440a451d56494a0e60074b88a563b832cf0b9921e48","0x9b66cdf1918eb57d412456ddb66097dc60253c9514597fb14e6b1ae2d64c958a","0x98d43ae5aae7385b25a3148250f30936be6607f78e0ea60f5b98656b14cfe9ed","0xa7bd9a2b030d405299ffc22372d557b11847037d99a9dc6aaec166d7af00c925","0x1202f3a3eaf7e10ce22f2ab95dfc64ca76460e933a6c0dcc0b73a222e8555ca3","0x4fb5889a30b3bf3228d63301ec472749d2b30a110edf8e833d1b7fac5a24c643","0x0db4b9c1d3b348311dfdd5b3660541b19a0ca3252d8a9c5d9b8d7622be616b4e","0x61169043a00be8ba948849027975091a71ded7fc93799e399d3d09466dae8a23","0x0dc5267f43067f3693c1e0a9c8462d1867026a9f40146d96a4d5579f3b634871","0xcd15d2c39f5b75d7a7efeb8aa30171899a6c560de43b10e0669e2bc28f462df2","0x581528aa17202094088fd6b28449c62b452bee83d924bf293226077eddc73199","0x17473546b0dbcda328660b10baef998276fb5274ad260f3e02253ba430a62f00","0x22f6bfc47206f532b214973f4808fb591df841bd30c3c24f86d6e4cbc9f12a9c","0x36c7af9b915fcbd574ed91e2fc627b33f78d60ff982b18e74c8737dfc2c3ff32","0x4ec5865a90200122c1c6299bb4975faca8f01a90533b3b1a2f037979638ce265","0xb2779a0fb84b87ab0173001a63a52231aa63e4d9c350b6f42c2510d8dc1337e9","0x4aefaec87f8dba01a017aa81280cc57a22e0a73e67625000eecc9c4b4b10d350","0xd35e627f8760a8fef78dd7255a1d7848a530daa4da05da70321cf4de9545c1d3","0xba0f33af763711d1a90028c33e4007d70342e2f98fbf2267c627ffcb1b09dea6","0xabcec94f3126a856cc1b1853ea551e3f5633cf00d33a711d15acb4619114cee9","0xfef5875bd12cd61043ee8d480e6075bb94d892a15e813155dd87ceeee20ee22b","0xafb19d84c5fe8185d67977554599c0c60ad4ca4ab7fe1b11578116e0d39885aa","0x6977de67b1cfd628e97646d66724646450bce5de3bef94d653c641662c728762","0x0eb63f4ee2126114530d9fcf2426636f89821f1bf179eb88c89e58f2cf739212","0xa66a45b277e38eab314bead2e56c0af773ccaeafc228969c16a04ee36321d924","0x54cca1662669d40c81c8df72fb0d8ad0d121112428e99325daacd69448c9870d","0xa909e789bae066068d62f53b9a67579fe4a260a2caf6a4bfff79f0d42484d930","0x06f975c1abe6fda098bfcf9220f5b6133f41dbc5464bf47df628dc77622de3f4","0x2cd8070b262763f886715177a0b3c904da8509d28e629632b2f3997e87276313","0x777b956d9ca0f1ff2b8560f100a528a4b275d2a371e8b0406fd3376f42adbe52","0x909299d313ce7d45adc26dac85f8886775c9cd6120137697ef34f50feee4a3b5","0x3200f7873fee4aeee582f429c43c238c0a5b24b225f523df96b79e99bc87f8d7","0x5cb1072e9baf169a504b29655f73c1d8d6cd51b988143bb171fb2469b561fece","0x6f9ec5eb8ed96e1ec8707b6fbf3879ff7bb8ab3800fe68d0de7d15bff8a482a7","0xe9d28b9356dff9d321d41fd3f98abeb65f0cf9d1b66b0d6dcde438ab7630e01f","0x810d66bb76b217f44a40f2fd59d8b0d27a250c26d32a1a277a678ab0e4f46487","0x0ab76fb685091db501750603922ada915b39b8acf4208ba3e88618ab50627bf0","0xcaadcd7e13eae697afffc7470142cf74c3eb5dd076e7eeb0a9c5d72548f4ffe0","0x521b789dae079dd90c4d7612b1d33fc7d4406f55d7a5c39d6b9529c6d759d99b","0xd5a05f12806d3e6a2cad62989ce32bdf0a95b249e6841b51e1c6d4e8901e943c","0x9e3d46e6c07cbe5d5a5a30b5266662368caed7ad3bbf6e56504b113fe0997cfb","0xca00c39335ed81430e93c59aba05d82629b06c8d245b3d7118827a896bc844d6","0x22078f053cdde84bd61bb49204efe2f6e633e9bef6c8ef99e618ac2a8e896105","0x7bcd656031d3caf1c0c7b425b6b809d0833428b8e23cd5b361f902954d848a8f","0x4ecee87c3511aeee4114d83b3b8423cf2dcd0d13f1969e96a0d92af5b41c38d3","0xfb7b84f230a772fa2f3e7076a9f48eeba5ad05dd98c8be7cf8dd7daf9104b314","0xabb59d981bc7fd2998cfa76ab2628efc8d417621cf32442863c62d8b5a81d50b","0xed6b9b695859c3991239067576f5d6a5befc8806e11ae089b713fc9bf2ea9dcb","0xcc955c4a7d563ac02f20290a9469fd2ceaf262ec68bfc8186b28f492df390af9","0x38daeb306fd9538758bebe3a096b535b705440d1ec56946d48b055cdba644060","0xfdf3dba57fee47ebde0606484ad55eb6b3c01ef81373f652ee8973e50cf10b42","0xa6ee4176ada9964f8fde83caa2c63b616bc9aa75dbb65732afdcbdaa32142ff9","0x00124e92b9bca541d1bc7aa49a6817f4309036e17be8d9cccbede9cce0ce1a94","0x74e3aca2d8a268827f3bb689b67b5ef6a0ae47f0314710b36f61eb391f2f5fd8","0x2a82a1fc43b3b68725b89cf5da4a0d2ebe75c619caf5d5d84b3959604ae63d4b","0x8df966bb185922c38bb1ae7b315e086d0add17860158495c49ba4bee39249a7f","0x0bdcd94a2ae80d770df1ae7def002a0ea9600c2674f9bd8c6f6fc0f28b403337","0xc3b763bb432bd3f9c0a5435736c3495f37a94f9c741857b4727b212015f388e0","0xd126630ed852f5e992ae6c5f2c1b76ae5eaa78b95c3a9f4ef5acc4e1a33c6c4d","0x7bbaaf49d7468159a17fcfa90dfeafbdfdd16997d83ee5fee753be54cfd5204c","0x1c6c114eea356fc42a6652e1c3371490d7114afeee4c0e6fcfa2c1ba8d3f3d72","0xdbf5d459db62a79ca29acdddb5fda453232f37e32ae24d9be8f6ed9e2ed23022","0x324b7365bacac084d2d6ab08276135e6bd3d77c15e6e7e64f74a533c72d98d01","0xc486d371a555f29e75bc0586960650b4eb4345dc96ea4d2edf4388a250abb590","0x33eebbe09761d0adddfe2422bd228fea072a36fd4ef4ad8d02d054ad5bde66ac","0xc49b07182157737bbf9fd915e6c0cf5fa8c791c818e226e8b48b4287dbeb8d5c","0x68c6a569375aea72cb45175f49be28679b193a269e539e3b4882288181599209","0xd2d80a7ab00870c22ef23264bf9c98c1e07a9bdfda680edecdd9903313dd39d7","0x4834ad2b63f7f82e73c0ca7b7633176cb1e7bea5a33599e5893dfc6baa2c9a08","0x0ae745c5bfa9f2cb49c7bae5e78f6338680e6ad8c54636fe90074ec2feb3b7c7","0x343075f46bf58e09be84a833c0efd5c94bf30d3a05aaba2d4c5aa68667540bc0","0x485a5f402781e3fbff51bd5d4f7e454831a2a781e24b7a7921492cf6738a5131","0x3f53d3a29232e70f563ba648c625e2cd5397280ebf0797e5cdc6acdeeeb62f78","0x58348ad9c83bcf9a6b146238b234eda145f8e295cf260d878b45fd406c4100c4","0x3abf7165d69a5d949d28ff1f0fe47636df7ae3c8f6f372dd863fd7fd0d68489a","0xee63b1f64713a2b7d2bde2d9f82d23e6913efb7e5eabedb0e4822c7322c2c0b5","0x6f63c32a3119af84ebee998dd40184df58405d8fc08ad61303a154d13778962d","0x1c44e98f008805ed1b35185d91080f79fc5d660045918fd478b652c4bd3b106d","0x0efdb2c38a513204d7b5832de618ebdca40e666ef6e6cb8952be20b8e525c187","0xe722b2a04794b88a583d2640bd67ff53893f059211743c3f926f31a603fd5324","0x7648385c131ce44135c86efad17329dd47cef6bec149c03dac366359c78f56aa","0xf3df795e3dc4e7c3dc83eec35c6160a969ceaaf5dd305731fc1660721ca1f45a","0x9b6ed541210630c9147c0921c6fe3841d3191caf42120cb9a1ec0afca7e03d25","0x48b6e76b0b838a98a9733b31aec01b94137a446fd78de75ec5cea9d56eb70b42","0x3ab1a3a836708886053069e725977d553136671f81d76b5c42acb0931ccb2280","0x7c2980aae96ecf82296edbe41bec10bc65a07bb28c74a6b3b25312043a3c3b65","0xdef249cadca268c30bc31f5330c74f271c37c3d0aae5529e5417c895abee3650","0xdf1cd6401bf0ad311e5becaf65c8bf094b29891d2ca1318cf87182a157e2575b","0x02f7fbd8f868a2407e8ae444f44d7b48753901b58d22770076a1ab7ec6bd5ce3","0xf47398d75f44af98002c1c6b9728ca601a72c7ae4fc040ab33a602b2dd73b323","0x6d868059a6c401baa6e505e2be09b6a67633c43a40028280ea670a6b65ce42c4","0xf1b0e6ee98515af11ae47be035acd820fa2f5eb13b2c01db163f637824c380c6","0x3998361394aaa101587e186d969975a31e2f614b9cfe35cf47cfc3472e4473a5","0x22fc8ae8825988b1760c944be5037486a5e16fab73aa5bb6b3def203e66c4592","0xd78c420007efb06486f1757ef18d5031fc15d0ba345e87632ae22c098884d2cd","0x540315e42cf0094ee66747f5b5841ebce93d34077ce50136c222ef370ffc027c","0xf325d7d8a1983523649b09a2b0689794066f781b10d07395259515b7d40f2dd1","0x0154f80a9d3d9eef37fb68da34e320f9d1b2bf5bac6c302b20dab6f11906b8a2","0x895a6bc6dc13ff335c4715309b78a42b0b0e1c7b6066c0ce526f9d2b5a84545d","0xd035823ac2128aaa628cbce3f68d65b69f4f95e776df27640054f6c65a715de5","0xe9317780986a3acc49fbbba57c0c56834f3ebc5f109182fd37b6cc083b15b25e","0x5ab96281057a7ae65b91f7a22e637d2f854bcae4f92cee2c9b18941348d3dd16","0xce72fee9b37434ea7900cacc74786580067edf131cd7a579dff246213ccd6bbd","0x95f1da6a097707031e922f5d6d9d7b2402f1ab60c97e9d5f918c27f7e531801e","0xb3a6220ad33d63f84085eb5275ebea3c7d18017b02d8f93b9b32041300a99abd","0xf6eee56dd73e63917a6f8374ecc4a0cab828d94f729701580c6f0c5db9d26f83","0xbf776633355811d4a8228b9ab40c2e52fff83c6c4c2a26b9273a98f5c81c3fa8","0x2d1b67a40f9f5f8c6b970f1faadc4d9492b5e86b8951e7119ba1ab4059144706","0x90fc859032bd5a248eefc0b250510863fa1d1fb2f585dfc8c2c618ae32096867","0x4caf443a9cd7549199d645325687c2981ea005865df5b07f76afcfb0fe936a79","0x80dc84da5603df4f83912e8dc86071da9b255f9797a912c5e0a5679f894321fe","0x464125e8bf0d383d37f2a52157e9cba9e902f40f0c69f584bddd3ad4a4535876","0xd9b9a3c2c1963e1144dbba0036a80de2d8d668f5f11ffb888da1ec0cbbfe3bb8","0xf372a2bcc3d6b684eb4ecb77800e467d7ab8d77a3d839d1b245dc8925b5045d8","0x61305ed5ad02d114519ba48786e1371e39236a54288e0fc6a30e284fbf49aa44","0xf03bba853af13c6d3b29fc59aca4711f4ac2af792095e904ea118b7dbafca9c8","0xb5299512ce88aa17bd8043a3f9ff344fa9dee79968f4c88b5c05da50a8fb7c62","0x52ece6748ef43a9a849241919cb648decb913be19ab7e6ddb612b6e034aa796f","0x20d7bd5dade8f0b6a248c337a398421f5deab2693cec73cab58a35d8f4d166b3","0x90d85bac070ec7a932fc3dc0582bdc9abe406a9bf7f83117869feaa2909a3fb5","0xc7e9bf5800f46439a36ce3b38b0c6189f0a0353d7a1939368dfb141e2c429669","0xeaf20452be64a379c527a54a8d56114137b7c95a24725aef0ccf90c8b8720a31","0xf434c5f0fd080e7a119df6fcb5f822a0e8e4d65a3a86dbe41747af1aebed8c11","0xe0aa2192fa41980296b947de91ff945d3eb445d5331f6642718acddaebe83538","0x923ba01d85601fd1df4a49539806387482551abd591bb9f69e876e73ef91a653","0xb714976b7454a9e9dd32f831efdcc8cc1af557e0dcbc89672e0a0e109cff748a","0x0665a61b3da153f1c9d8658bf246ce242d07372226030ff06eba0d8f27272083"]} diff --git a/cmd/workload/testsuite.go b/cmd/workload/testsuite.go new file mode 100644 index 000000000..3e3ea1d00 --- /dev/null +++ b/cmd/workload/testsuite.go @@ -0,0 +1,145 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "embed" + "io/fs" + "os" + "slices" + + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/internal/utesting" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +//go:embed queries +var builtinTestFiles embed.FS + +var ( + runTestCommand = &cli.Command{ + Name: "test", + Usage: "Runs workload tests against an RPC endpoint", + ArgsUsage: "", + Action: runTestCmd, + Flags: []cli.Flag{ + testPatternFlag, + testTAPFlag, + testSlowFlag, + testSepoliaFlag, + testMainnetFlag, + filterQueryFileFlag, + historyTestFileFlag, + }, + } + testPatternFlag = &cli.StringFlag{ + Name: "run", + Usage: "Pattern of test suite(s) to run", + Category: flags.TestingCategory, + } + testTAPFlag = &cli.BoolFlag{ + Name: "tap", + Usage: "Output test results in TAP format", + Category: flags.TestingCategory, + } + testSlowFlag = &cli.BoolFlag{ + Name: "slow", + Usage: "Enable slow tests", + Value: false, + Category: flags.TestingCategory, + } + testSepoliaFlag = &cli.BoolFlag{ + Name: "sepolia", + Usage: "Use test cases for sepolia network", + Category: flags.TestingCategory, + } + testMainnetFlag = &cli.BoolFlag{ + Name: "mainnet", + Usage: "Use test cases for mainnet network", + Category: flags.TestingCategory, + } +) + +// testConfig holds the parameters for testing. +type testConfig struct { + client *client + fsys fs.FS + filterQueryFile string + historyTestFile string +} + +func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) { + flags.CheckExclusive(ctx, testMainnetFlag, testSepoliaFlag) + if (ctx.IsSet(testMainnetFlag.Name) || ctx.IsSet(testSepoliaFlag.Name)) && ctx.IsSet(filterQueryFileFlag.Name) { + exit(filterQueryFileFlag.Name + " cannot be used with " + testMainnetFlag.Name + " or " + testSepoliaFlag.Name) + } + + // configure ethclient + cfg.client = makeClient(ctx) + + // configure test files + switch { + case ctx.Bool(testMainnetFlag.Name): + cfg.fsys = builtinTestFiles + cfg.filterQueryFile = "queries/filter_queries_mainnet.json" + cfg.historyTestFile = "queries/history_mainnet.json" + case ctx.Bool(testSepoliaFlag.Name): + cfg.fsys = builtinTestFiles + cfg.filterQueryFile = "queries/filter_queries_sepolia.json" + cfg.historyTestFile = "queries/history_sepolia.json" + default: + cfg.fsys = os.DirFS(".") + cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name) + cfg.historyTestFile = ctx.String(historyTestFileFlag.Name) + } + return cfg +} + +func runTestCmd(ctx *cli.Context) error { + cfg := testConfigFromCLI(ctx) + filterSuite := newFilterTestSuite(cfg) + historySuite := newHistoryTestSuite(cfg) + + // Filter test cases. + tests := filterSuite.allTests() + tests = append(tests, historySuite.allTests()...) + if ctx.IsSet(testPatternFlag.Name) { + tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name)) + } + if !ctx.Bool(testSlowFlag.Name) { + tests = slices.DeleteFunc(tests, func(test utesting.Test) bool { + return test.Slow + }) + } + + // Disable logging unless explicitly enabled. + if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") { + log.SetDefault(log.NewLogger(log.DiscardHandler())) + } + + // Run the tests. + var run = utesting.RunTests + if ctx.Bool(testTAPFlag.Name) { + run = utesting.RunTAP + } + results := run(tests, os.Stdout) + if utesting.CountFailures(results) > 0 { + os.Exit(1) + } + return nil +} diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index 170b67b31..fc84ae85d 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -295,3 +295,45 @@ func CheckEnvVars(ctx *cli.Context, flags []cli.Flag, prefix string) { } } } + +// CheckExclusive verifies that only a single instance of the provided flags was +// set by the user. Each flag might optionally be followed by a string type to +// specialize it further. +func CheckExclusive(ctx *cli.Context, args ...any) { + set := make([]string, 0, 1) + for i := 0; i < len(args); i++ { + // Make sure the next argument is a flag and skip if not set + flag, ok := args[i].(cli.Flag) + if !ok { + panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) + } + // Check if next arg extends current and expand its name if so + name := flag.Names()[0] + + if i+1 < len(args) { + switch option := args[i+1].(type) { + case string: + // Extended flag check, make sure value set doesn't conflict with passed in option + if ctx.String(flag.Names()[0]) == option { + name += "=" + option + set = append(set, "--"+name) + } + // shift arguments and continue + i++ + continue + + case cli.Flag: + default: + panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) + } + } + // Mark the flag if it's set + if ctx.IsSet(flag.Names()[0]) { + set = append(set, "--"+name) + } + } + if len(set) > 1 { + fmt.Fprintf(os.Stderr, "Flags %v can't be used at the same time", strings.Join(set, ", ")) + os.Exit(1) + } +} From 1df053b984fb2901c14dd632682f2265cdf0a985 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 27 Feb 2025 00:40:35 -0700 Subject: [PATCH 175/354] eth/gasprice: sanity check ratio values (#31270) Follow on to #31246. Adds a sanity check in the test to make sure the ratio value never goes over 1. Would have avoided the issue in #31245. --- eth/gasprice/feehistory_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index 241b91b81..d220027e6 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -84,9 +84,19 @@ func TestFeeHistory(t *testing.T) { if len(ratio) != c.expCount { t.Fatalf("Test case %d: gasUsedRatio array length mismatch, want %d, got %d", i, c.expCount, len(ratio)) } + for _, ratio := range ratio { + if ratio > 1 { + t.Fatalf("Test case %d: gasUsedRatio greater than 1, got %f", i, ratio) + } + } if len(blobRatio) != c.expCount { t.Fatalf("Test case %d: blobGasUsedRatio array length mismatch, want %d, got %d", i, c.expCount, len(blobRatio)) } + for _, ratio := range blobRatio { + if ratio > 1 { + t.Fatalf("Test case %d: blobGasUsedRatio greater than 1, got %f", i, ratio) + } + } if len(blobBaseFee) != len(baseFee) { t.Fatalf("Test case %d: blobBaseFee array length mismatch, want %d, got %d", i, len(baseFee), len(blobBaseFee)) } From 1b68aeaf9d6d4cdb3d6a0d9dd067b935568f1109 Mon Sep 17 00:00:00 2001 From: buddho Date: Thu, 27 Feb 2025 17:08:33 +0800 Subject: [PATCH 176/354] core/txpool: fix error logs flood caused by removeAuthorities (#31249) when remove an non-SetCodeTxType transaction, error logs flood ``` t=2025-02-25T03:11:06+0000 lvl=error msg="Authority with untracked tx" addr=0xD5bf9221fCB1C31Cd1EE477a60c148d40dD63DC1 hash=0x626fdf205a5b1619deb2f9e51fed567353f80acbd522265b455daa0821c571d9 ``` in this PR, only try to removeAuthorities for txs with SetCodeTxType in addition, the performance of removeAuthorities improved a lot, because no need range all `t.auths` now. --------- Co-authored-by: lightclient --- core/txpool/legacypool/legacypool.go | 7 ++-- core/txpool/legacypool/legacypool_test.go | 44 +++++++++++++++++++++++ core/types/transaction.go | 12 +++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index d033907cb..f44b20300 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1890,12 +1890,12 @@ func (t *lookup) Remove(hash common.Hash) { t.lock.Lock() defer t.lock.Unlock() - t.removeAuthorities(hash) tx, ok := t.txs[hash] if !ok { log.Error("No transaction found to be deleted", "hash", hash) return } + t.removeAuthorities(tx) t.slots -= numSlots(tx) slotsGauge.Update(int64(t.slots)) @@ -1933,8 +1933,9 @@ func (t *lookup) addAuthorities(tx *types.Transaction) { // removeAuthorities stops tracking the supplied tx in relation to its // authorities. -func (t *lookup) removeAuthorities(hash common.Hash) { - for addr := range t.auths { +func (t *lookup) removeAuthorities(tx *types.Transaction) { + hash := tx.Hash() + for _, addr := range tx.SetCodeAuthorities() { list := t.auths[addr] // Remove tx from tracker. if i := slices.Index(list, hash); i >= 0 { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index b2a068467..ef887041a 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -23,6 +23,7 @@ import ( "fmt" "math/big" "math/rand" + "slices" "sync" "sync/atomic" "testing" @@ -238,6 +239,23 @@ func validatePoolInternals(pool *LegacyPool) error { return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) } } + // Ensure all auths in pool are tracked + for _, tx := range pool.all.txs { + for _, addr := range tx.SetCodeAuthorities() { + list := pool.all.auths[addr] + if i := slices.Index(list, tx.Hash()); i < 0 { + return fmt.Errorf("authority not tracked: addr %s, tx %s", addr, tx.Hash()) + } + } + } + // Ensure all auths in pool have an associated tx. + for addr, hashes := range pool.all.auths { + for _, hash := range hashes { + if _, ok := pool.all.txs[hash]; !ok { + return fmt.Errorf("dangling authority, missing originating tx: addr %s, hash %s", addr, hash.Hex()) + } + } + } return nil } @@ -2381,6 +2399,32 @@ func TestSetCodeTransactions(t *testing.T) { } }, }, + { + name: "remove-hash-from-authority-tracker", + pending: 10, + run: func(name string) { + var keys []*ecdsa.PrivateKey + for i := 0; i < 30; i++ { + key, _ := crypto.GenerateKey() + keys = append(keys, key) + addr := crypto.PubkeyToAddress(key.PublicKey) + testAddBalance(pool, addr, big.NewInt(params.Ether)) + } + // Create a transactions with 3 unique auths so the lookup's auth map is + // filled with addresses. + for i := 0; i < 30; i += 3 { + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keys[i], []unsignedAuth{{0, keys[i]}, {0, keys[i+1]}, {0, keys[i+2]}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + } + // Replace one of the transactions with a normal transaction so that the + // original hash is removed from the tracker. The hash should be + // associated with 3 different authorities. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keys[0])); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + }, + }, } { tt.run(tt.name) pending, queued := pool.Stats() diff --git a/core/types/transaction.go b/core/types/transaction.go index 7df13e04b..4e48248b4 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -483,15 +483,23 @@ func (tx *Transaction) SetCodeAuthorizations() []SetCodeAuthorization { return setcodetx.AuthList } -// SetCodeAuthorities returns a list of each authorization's corresponding authority. +// SetCodeAuthorities returns a list of unique authorities from the +// authorization list. func (tx *Transaction) SetCodeAuthorities() []common.Address { setcodetx, ok := tx.inner.(*SetCodeTx) if !ok { return nil } - auths := make([]common.Address, 0, len(setcodetx.AuthList)) + var ( + marks = make(map[common.Address]bool) + auths = make([]common.Address, 0, len(setcodetx.AuthList)) + ) for _, auth := range setcodetx.AuthList { if addr, err := auth.Authority(); err == nil { + if marks[addr] { + continue + } + marks[addr] = true auths = append(auths, addr) } } From f0030f5afeb8525a7e4d2dd42add2d3dff20aaa5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 27 Feb 2025 12:07:36 +0100 Subject: [PATCH 177/354] build: update PPA Go bootstrap version to 1.23 (#31282) This is for fixing the PPA build, which has been failing since the update to Go 1.24. In Go 1.24, the required Go version for bootstrapping was updated to 1.22. In general, they are following through with always depending on the Go version two releases ago for bootstrapping. Since we still support Ubuntu Xenial (16.04) until its EOL date of 04/2026, and Xenial only has golang 1.10 as a package, we now need to build Go a total of four times to get the most recent version. I'm adding a step for Go 1.23 here. This should last us until Go 1.25, which should be out around 04/2026, and we can hopefully drop the first bootstrapping step at that time. --- build/checksums.txt | 8 ++++++-- build/ci.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 1646cc6c4..c8b742e44 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -114,14 +114,18 @@ fc43f8c95d6bec8ba9a3557a0bb63cf9f504137ce6d24cfdc4c330d46f7779d2 golangci-lint- # This version is fine to be old and full of security holes, we just use it # to build the latest Go. Don't change it. # -# version:ppa-builder-1 1.19.6 +# version:ppa-builder-1.19 1.19.6 # https://go.dev/dl/ d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz -# version:ppa-builder-2 1.21.9 +# version:ppa-builder-1.21 1.21.9 # https://go.dev/dl/ 58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz +# version:ppa-builder-1.23 1.23.6 +# https://go.dev/dl/ +039c5b04e65279daceee8a6f71e70bd05cf5b801782b6f77c6e19e2ed0511222 go1.23.6.src.tar.gz + # version:protoc 27.1 # https://github.com/protocolbuffers/protobuf/releases/ # https://github.com/protocolbuffers/protobuf/releases/download/v27.1/ diff --git a/build/ci.go b/build/ci.go index f50c29268..ef834ed08 100644 --- a/build/ci.go +++ b/build/ci.go @@ -848,7 +848,7 @@ func downloadGoBootstrapSources(cachedir string) []string { csdb := build.MustLoadChecksums("build/checksums.txt") var bundles []string - for _, booter := range []string{"ppa-builder-1", "ppa-builder-2"} { + for _, booter := range []string{"ppa-builder-1.19", "ppa-builder-1.21", "ppa-builder-1.23"} { gobootVersion, err := build.Version(csdb, booter) if err != nil { log.Fatal(err) From d941e22468fa31966d340938f94e9def6baf949f Mon Sep 17 00:00:00 2001 From: Shude Li Date: Thu, 27 Feb 2025 22:52:00 +0800 Subject: [PATCH 178/354] build: simplify go mod tidy check (#31266) This changes the go mod tidy check to use the go mod tidy -diff command, removing the custom diffing for go.mod. The check for go.mod/go.sum is now performed in the check_generate action. Also included is a change where check_generate and check_baddeps will now run on the GitHub Actions lint step. --------- Co-authored-by: Felix Lange --- .github/workflows/go.yml | 2 +- appveyor.yml | 1 - build/ci.go | 28 +++++++--------------------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4da92f243..78410aab1 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -29,7 +29,7 @@ jobs: - name: Run linters run: | go run build/ci.go lint - go run build/ci.go check_tidy + go run build/ci.go check_generate go run build/ci.go check_baddeps build: diff --git a/appveyor.yml b/appveyor.yml index 1543211ed..ae1c74c18 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,7 +24,6 @@ for: - image: Ubuntu build_script: - go run build/ci.go lint - - go run build/ci.go check_tidy - go run build/ci.go check_generate - go run build/ci.go check_baddeps - go run build/ci.go install -dlgo diff --git a/build/ci.go b/build/ci.go index ef834ed08..8684c332e 100644 --- a/build/ci.go +++ b/build/ci.go @@ -25,8 +25,7 @@ Usage: go run build/ci.go Available commands are: lint -- runs certain pre-selected linters - check_tidy -- verifies that everything is 'go mod tidy'-ed - check_generate -- verifies that everything is 'go generate'-ed + check_generate -- verifies that 'go generate' and 'go mod tidy' do not produce changes check_baddeps -- verifies that certain dependencies are avoided install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables @@ -160,8 +159,6 @@ func main() { doTest(os.Args[2:]) case "lint": doLint(os.Args[2:]) - case "check_tidy": - doCheckTidy() case "check_generate": doCheckGenerate() case "check_baddeps": @@ -357,22 +354,6 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { // doCheckTidy assets that the Go modules files are tidied already. func doCheckTidy() { - targets := []string{"go.mod", "go.sum"} - - hashes, err := build.HashFiles(targets) - if err != nil { - log.Fatalf("failed to hash go.mod/go.sum: %v", err) - } - build.MustRun(new(build.GoToolchain).Go("mod", "tidy")) - - tidied, err := build.HashFiles(targets) - if err != nil { - log.Fatalf("failed to rehash go.mod/go.sum: %v", err) - } - if updates := build.DiffHashes(hashes, tidied); len(updates) > 0 { - log.Fatalf("files changed on running 'go mod tidy': %v", updates) - } - fmt.Println("No untidy module files detected.") } // doCheckGenerate ensures that re-generating generated files does not cause @@ -380,6 +361,7 @@ func doCheckTidy() { func doCheckGenerate() { var ( cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.") + tc = new(build.GoToolchain) ) // Compute the origin hashes of all the files var hashes map[string][32]byte @@ -394,7 +376,7 @@ func doCheckGenerate() { protocPath = downloadProtoc(*cachedir) protocGenGoPath = downloadProtocGenGo(*cachedir) ) - c := new(build.GoToolchain).Go("generate", "./...") + c := tc.Go("generate", "./...") pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")} c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator))) build.MustRun(c) @@ -412,6 +394,10 @@ func doCheckGenerate() { log.Fatal("One or more generated files were updated by running 'go generate ./...'") } fmt.Println("No stale files detected.") + + // Run go mod tidy check. + build.MustRun(tc.Go("mod", "tidy", "-diff")) + fmt.Println("No untidy module files detected.") } // doCheckBadDeps verifies whether certain unintended dependencies between some From 4d07fdfe67ab7532fae4c7b8490b5a5b0de57a75 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 27 Feb 2025 15:53:52 +0100 Subject: [PATCH 179/354] all: drop x/exp direct dependency (#30558) This is a not-particularly-important "cleanliness" PR. It removes the last remnants of the `x/exp` package, where we used the `maps.Keys` function. The original returned the keys in a slice, but when it became 'native' the signature changed to return an iterator, so the new idiom is `slices.Collect(maps.Keys(theMap))`, unless of course the raw iterator can be used instead. In some cases, where we previously collect into slice and then sort, we can now instead do `slices.SortXX` on the iterator instead, making the code a bit more concise. This PR might be _slighly_ less optimal, because the original `x/exp` implementation allocated the slice at the correct size off the bat, which I suppose the new code won't. Putting it up for discussion. --------- Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/chain.go | 6 +++--- cmd/evm/blockrunner.go | 5 ++--- core/state/snapshot/difflayer.go | 8 +++----- core/txpool/blobpool/evictheap.go | 5 ++--- core/txpool/legacypool/legacypool.go | 4 ++-- core/txpool/locals/tx_tracker.go | 2 +- p2p/netutil/net.go | 6 ++---- triedb/pathdb/history.go | 10 +++------- triedb/pathdb/states.go | 8 +++----- 9 files changed, 21 insertions(+), 33 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 222c66d4d..f695d158b 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "io" + "maps" "math/big" "os" "path/filepath" @@ -40,7 +41,6 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/maps" ) // Chain is a lightweight blockchain-like store which can read a hivechain @@ -166,8 +166,8 @@ func (c *Chain) RootAt(height int) common.Hash { // GetSender returns the address associated with account at the index in the // pre-funded accounts list. func (c *Chain) GetSender(idx int) (common.Address, uint64) { - accounts := maps.Keys(c.senders) - slices.SortFunc(accounts, common.Address.Cmp) + accounts := slices.SortedFunc(maps.Keys(c.senders), common.Address.Cmp) + addr := accounts[idx] return addr, c.senders[addr].Nonce } diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 9a04807b3..31d1ba5ba 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "os" "regexp" "slices" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" - "golang.org/x/exp/maps" ) var blockTestCommand = &cli.Command{ @@ -80,8 +80,7 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { tracer := tracerFromFlags(ctx) // Pull out keys to sort and ensure tests are run in order. - keys := maps.Keys(tests) - slices.Sort(keys) + keys := slices.Sorted(maps.Keys(tests)) // Run all the tests. var results []testResult diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index dce4f79a1..28957051d 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -19,6 +19,7 @@ package snapshot import ( "encoding/binary" "fmt" + "maps" "math" "math/rand" "slices" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" bloomfilter "github.com/holiman/bloomfilter/v2" - "golang.org/x/exp/maps" ) var ( @@ -431,8 +431,7 @@ func (dl *diffLayer) AccountList() []common.Hash { dl.lock.Lock() defer dl.lock.Unlock() - dl.accountList = maps.Keys(dl.accountData) - slices.SortFunc(dl.accountList, common.Hash.Cmp) + dl.accountList = slices.SortedFunc(maps.Keys(dl.accountData), common.Hash.Cmp) dl.memory += uint64(len(dl.accountList) * common.HashLength) return dl.accountList } @@ -464,8 +463,7 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) []common.Hash { dl.lock.Lock() defer dl.lock.Unlock() - storageList := maps.Keys(dl.storageData[accountHash]) - slices.SortFunc(storageList, common.Hash.Cmp) + storageList := slices.SortedFunc(maps.Keys(dl.storageData[accountHash]), common.Hash.Cmp) dl.storageList[accountHash] = storageList dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) return storageList diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index 5e285e6c5..722a71bc9 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -18,12 +18,12 @@ package blobpool import ( "container/heap" + "maps" "math" "slices" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" - "golang.org/x/exp/maps" ) // evictHeap is a helper data structure to keep track of the cheapest bottleneck @@ -54,8 +54,7 @@ func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.A // Populate the heap in account sort order. Not really needed in practice, // but it makes the heap initialization deterministic and less annoying to // test in unit tests. - heap.addrs = maps.Keys(index) - slices.SortFunc(heap.addrs, common.Address.Cmp) + heap.addrs = slices.SortedFunc(maps.Keys(index), common.Address.Cmp) for i, addr := range heap.addrs { heap.index[addr] = i } diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index f44b20300..fbc16f076 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -20,6 +20,7 @@ package legacypool import ( "errors" "fmt" + "maps" "math" "math/big" "slices" @@ -43,7 +44,6 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" - "golang.org/x/exp/maps" ) const ( @@ -1799,7 +1799,7 @@ func (as *accountSet) addTx(tx *types.Transaction) { // reuse. The returned slice should not be changed! func (as *accountSet) flatten() []common.Address { if as.cache == nil { - as.cache = maps.Keys(as.accounts) + as.cache = slices.Collect(maps.Keys(as.accounts)) } return as.cache } diff --git a/core/txpool/locals/tx_tracker.go b/core/txpool/locals/tx_tracker.go index 41d5faa7e..b3c7c8768 100644 --- a/core/txpool/locals/tx_tracker.go +++ b/core/txpool/locals/tx_tracker.go @@ -18,6 +18,7 @@ package locals import ( + "slices" "sync" "time" @@ -28,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" - "golang.org/x/exp/slices" ) var ( diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index 7d8da8867..696c33185 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -21,12 +21,11 @@ import ( "bytes" "errors" "fmt" + "maps" "net" "net/netip" "slices" "strings" - - "golang.org/x/exp/maps" ) var special4, special6 Netlist @@ -324,8 +323,7 @@ func (s *DistinctNetSet) key(ip netip.Addr) netip.Prefix { // String implements fmt.Stringer func (s DistinctNetSet) String() string { - keys := maps.Keys(s.members) - slices.SortFunc(keys, func(a, b netip.Prefix) int { + keys := slices.SortedFunc(maps.Keys(s.members), func(a, b netip.Prefix) int { return strings.Compare(a.String(), b.String()) }) diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 6ba9aaf1b..c063e4537 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "slices" "time" @@ -29,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" - "golang.org/x/exp/maps" ) // State history records the state changes involved in executing a block. The @@ -250,15 +250,11 @@ type history struct { // newHistory constructs the state history object with provided state change set. func newHistory(root common.Hash, parent common.Hash, block uint64, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, rawStorageKey bool) *history { var ( - accountList = maps.Keys(accounts) + accountList = slices.SortedFunc(maps.Keys(accounts), common.Address.Cmp) storageList = make(map[common.Address][]common.Hash) ) - slices.SortFunc(accountList, common.Address.Cmp) - for addr, slots := range storages { - slist := maps.Keys(slots) - slices.SortFunc(slist, common.Hash.Cmp) - storageList[addr] = slist + storageList[addr] = slices.SortedFunc(maps.Keys(slots), common.Hash.Cmp) } version := historyVersion if !rawStorageKey { diff --git a/triedb/pathdb/states.go b/triedb/pathdb/states.go index 873a7ba61..0a83b2f2c 100644 --- a/triedb/pathdb/states.go +++ b/triedb/pathdb/states.go @@ -19,6 +19,7 @@ package pathdb import ( "fmt" "io" + "maps" "slices" "sync" @@ -27,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/maps" ) // counter helps in tracking items and their corresponding sizes. @@ -174,8 +174,7 @@ func (s *stateSet) accountList() []common.Hash { s.listLock.Lock() defer s.listLock.Unlock() - list = maps.Keys(s.accountData) - slices.SortFunc(list, common.Hash.Cmp) + list = slices.SortedFunc(maps.Keys(s.accountData), common.Hash.Cmp) s.accountListSorted = list return list } @@ -205,8 +204,7 @@ func (s *stateSet) storageList(accountHash common.Hash) []common.Hash { s.listLock.Lock() defer s.listLock.Unlock() - list := maps.Keys(s.storageData[accountHash]) - slices.SortFunc(list, common.Hash.Cmp) + list := slices.SortedFunc(maps.Keys(s.storageData[accountHash]), common.Hash.Cmp) s.storageListSorted[accountHash] = list return list } From a3585e59cc3d52a5785dc9feff41aa8e780f2e7b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 27 Feb 2025 17:52:22 +0100 Subject: [PATCH 180/354] build/deb: add step for new Go bootstrap to debian rules (#31283) Next attempt at fixing the build on launchpad.net --- build/deb/ethereum/deb.rules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 3287e15ff..5905ad50a 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -21,7 +21,8 @@ override_dh_auto_build: # requirements opposed to older versions of Go. (mv .goboot-1 ../ && cd ../.goboot-1/src && ./make.bash) (mv .goboot-2 ../ && cd ../.goboot-2/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-1 ./make.bash) - (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-2 ./make.bash) + (mv .goboot-3 ../ && cd ../.goboot-3/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-2 ./make.bash) + (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-3 ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the # entire dependency source cache with go-ethereum. From 820cc3ef873695809355d1027c0f7a41ae113257 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Fri, 28 Feb 2025 06:53:56 -0500 Subject: [PATCH 181/354] core/tracing: stringer for gas and nonce change reasons (#31234) --- core/state/statedb_hooked_test.go | 4 +- .../gen_balance_change_reason_stringer.go | 6 +-- .../tracing/gen_gas_change_reason_stringer.go | 52 +++++++++++++++++++ .../gen_nonce_change_reason_stringer.go | 29 +++++++++++ core/tracing/hooks.go | 6 ++- 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 core/tracing/gen_gas_change_reason_stringer.go create mode 100644 core/tracing/gen_nonce_change_reason_stringer.go diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index ce42e9640..f319b0e63 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -83,8 +83,8 @@ func TestHooks(t *testing.T) { inner.SetTxContext(common.Hash{0x11}, 100) // For the log var result []string var wants = []string{ - "0xaa00000000000000000000000000000000000000.balance: 0->100 (BalanceChangeUnspecified)", - "0xaa00000000000000000000000000000000000000.balance: 100->50 (BalanceChangeTransfer)", + "0xaa00000000000000000000000000000000000000.balance: 0->100 (Unspecified)", + "0xaa00000000000000000000000000000000000000.balance: 100->50 (Transfer)", "0xaa00000000000000000000000000000000000000.nonce: 0->1337", "0xaa00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728)", "0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000000 ->0x0000000000000000000000000000000000000000000000000000000000000011", diff --git a/core/tracing/gen_balance_change_reason_stringer.go b/core/tracing/gen_balance_change_reason_stringer.go index 4f094efb4..250b52119 100644 --- a/core/tracing/gen_balance_change_reason_stringer.go +++ b/core/tracing/gen_balance_change_reason_stringer.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go"; DO NOT EDIT. +// Code generated by "stringer -type=BalanceChangeReason -trimprefix=BalanceChange -output gen_balance_change_reason_stringer.go"; DO NOT EDIT. package tracing @@ -26,9 +26,9 @@ func _() { _ = x[BalanceChangeRevert-15] } -const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurnBalanceChangeRevert" +const _BalanceChangeReason_name = "UnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountTransferTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurnRevert" -var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400, 419} +var _BalanceChangeReason_index = [...]uint16{0, 11, 41, 71, 96, 125, 160, 181, 205, 231, 256, 264, 276, 303, 330, 361, 367} func (i BalanceChangeReason) String() string { if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) { diff --git a/core/tracing/gen_gas_change_reason_stringer.go b/core/tracing/gen_gas_change_reason_stringer.go new file mode 100644 index 000000000..e64be781a --- /dev/null +++ b/core/tracing/gen_gas_change_reason_stringer.go @@ -0,0 +1,52 @@ +// Code generated by "stringer -type=GasChangeReason -trimprefix=GasChange -output gen_gas_change_reason_stringer.go"; DO NOT EDIT. + +package tracing + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[GasChangeUnspecified-0] + _ = x[GasChangeTxInitialBalance-1] + _ = x[GasChangeTxIntrinsicGas-2] + _ = x[GasChangeTxRefunds-3] + _ = x[GasChangeTxLeftOverReturned-4] + _ = x[GasChangeCallInitialBalance-5] + _ = x[GasChangeCallLeftOverReturned-6] + _ = x[GasChangeCallLeftOverRefunded-7] + _ = x[GasChangeCallContractCreation-8] + _ = x[GasChangeCallContractCreation2-9] + _ = x[GasChangeCallCodeStorage-10] + _ = x[GasChangeCallOpCode-11] + _ = x[GasChangeCallPrecompiledContract-12] + _ = x[GasChangeCallStorageColdAccess-13] + _ = x[GasChangeCallFailedExecution-14] + _ = x[GasChangeWitnessContractInit-15] + _ = x[GasChangeWitnessContractCreation-16] + _ = x[GasChangeWitnessCodeChunk-17] + _ = x[GasChangeWitnessContractCollisionCheck-18] + _ = x[GasChangeTxDataFloor-19] + _ = x[GasChangeIgnored-255] +} + +const ( + _GasChangeReason_name_0 = "UnspecifiedTxInitialBalanceTxIntrinsicGasTxRefundsTxLeftOverReturnedCallInitialBalanceCallLeftOverReturnedCallLeftOverRefundedCallContractCreationCallContractCreation2CallCodeStorageCallOpCodeCallPrecompiledContractCallStorageColdAccessCallFailedExecutionWitnessContractInitWitnessContractCreationWitnessCodeChunkWitnessContractCollisionCheckTxDataFloor" + _GasChangeReason_name_1 = "Ignored" +) + +var ( + _GasChangeReason_index_0 = [...]uint16{0, 11, 27, 41, 50, 68, 86, 106, 126, 146, 167, 182, 192, 215, 236, 255, 274, 297, 313, 342, 353} +) + +func (i GasChangeReason) String() string { + switch { + case i <= 19: + return _GasChangeReason_name_0[_GasChangeReason_index_0[i]:_GasChangeReason_index_0[i+1]] + case i == 255: + return _GasChangeReason_name_1 + default: + return "GasChangeReason(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/core/tracing/gen_nonce_change_reason_stringer.go b/core/tracing/gen_nonce_change_reason_stringer.go new file mode 100644 index 000000000..f775c1f3a --- /dev/null +++ b/core/tracing/gen_nonce_change_reason_stringer.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type=NonceChangeReason -trimprefix NonceChange -output gen_nonce_change_reason_stringer.go"; DO NOT EDIT. + +package tracing + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[NonceChangeUnspecified-0] + _ = x[NonceChangeGenesis-1] + _ = x[NonceChangeEoACall-2] + _ = x[NonceChangeContractCreator-3] + _ = x[NonceChangeNewContract-4] + _ = x[NonceChangeAuthorization-5] + _ = x[NonceChangeRevert-6] +} + +const _NonceChangeReason_name = "UnspecifiedGenesisEoACallContractCreatorNewContractAuthorizationRevert" + +var _NonceChangeReason_index = [...]uint8{0, 11, 18, 25, 40, 51, 64, 70} + +func (i NonceChangeReason) String() string { + if i >= NonceChangeReason(len(_NonceChangeReason_index)-1) { + return "NonceChangeReason(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _NonceChangeReason_name[_NonceChangeReason_index[i]:_NonceChangeReason_index[i+1]] +} diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index e1afe22f3..41e39c583 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -222,7 +222,7 @@ type Hooks struct { // for tracing and reporting. type BalanceChangeReason byte -//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go +//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -trimprefix=BalanceChange -output gen_balance_change_reason_stringer.go const ( BalanceChangeUnspecified BalanceChangeReason = 0 @@ -283,6 +283,8 @@ const ( // once per transaction, while those that start with `GasChangeCall` are emitted on a call basis. type GasChangeReason byte +//go:generate go run golang.org/x/tools/cmd/stringer -type=GasChangeReason -trimprefix=GasChange -output gen_gas_change_reason_stringer.go + const ( GasChangeUnspecified GasChangeReason = 0 @@ -347,6 +349,8 @@ const ( // NonceChangeReason is used to indicate the reason for a nonce change. type NonceChangeReason byte +//go:generate go run golang.org/x/tools/cmd/stringer -type=NonceChangeReason -trimprefix NonceChange -output gen_nonce_change_reason_stringer.go + const ( NonceChangeUnspecified NonceChangeReason = 0 From c6a2685f1236cf9deb5f445cbbe1fc905afab705 Mon Sep 17 00:00:00 2001 From: Kuwon Sebastian Na Date: Sat, 1 Mar 2025 21:58:57 +0900 Subject: [PATCH 182/354] eth: do not add failed tx to localTxTracker (#31202) In transaction-sending APIs such as `eth_sendRawTransaction`, a submitted transaction failing the configured txpool validation rules (i.e. fee too low) would cause an error to be returned, even though the transaction was successfully added into the locals tracker. Once added there, the transaction may even be included into the chain at a later time, when fee market conditions change. This change improves on this by performing the validation in the locals tracker, basically skipping some of the validation rules for local transactions. We still try to add the tx to the main pool immediately, but an error will only be returned for transactions which are fundamentally invalid. --------- Co-authored-by: Gary Rong --- core/txpool/blobpool/blobpool.go | 19 ++++++++++++------- core/txpool/legacypool/cachepool.go | 11 ++++------- core/txpool/legacypool/legacypool.go | 11 ++++------- core/txpool/locals/tx_tracker.go | 26 ++++++++++++++++++++++---- core/txpool/subpool.go | 6 ++++++ core/txpool/txpool.go | 11 +++++++++++ eth/api_backend.go | 16 +++++++++++++--- 7 files changed, 72 insertions(+), 28 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index e4bd6c451..c880b6e17 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1094,19 +1094,24 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { p.updateStorageMetrics() } -// validateTx checks whether a transaction is valid according to the consensus -// rules and adheres to some heuristic limits of the local node (price and size). -func (p *BlobPool) validateTx(tx *types.Transaction) error { - // Ensure the transaction adheres to basic pool filters (type, size, tip) and - // consensus rules - baseOpts := &txpool.ValidationOptions{ +// ValidateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +// This check is meant as an early check which only needs to be performed once, +// and does not require the pool mutex to be held. +func (p *BlobPool) ValidateTxBasics(tx *types.Transaction) error { + opts := &txpool.ValidationOptions{ Config: p.chain.Config(), Accept: 1 << types.BlobTxType, MaxSize: txMaxSize, MinTip: p.gasTip.ToBig(), } + return txpool.ValidateTransaction(tx, p.head, p.signer, opts) +} - if err := p.txValidationFn(tx, p.head, p.signer, baseOpts); err != nil { +// validateTx checks whether a transaction is valid according to the consensus +// rules and adheres to some heuristic limits of the local node (price and size). +func (p *BlobPool) validateTx(tx *types.Transaction) error { + if err := p.ValidateTxBasics(tx); err != nil { return err } // Ensure the transaction adheres to the stateful pool filters (nonce, balance) diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index cef99acec..2577b47e4 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -360,11 +360,11 @@ func (pool *CachePool) Pending(filter txpool.PendingFilter) map[common.Address][ return make(map[common.Address][]*txpool.LazyTransaction) } -// validateTxBasics checks whether a transaction is valid according to the consensus +// ValidateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. // This check is meant as an early check which only needs to be performed once, // and does not require the pool mutex to be held. -func (pool *CachePool) validateTxBasics(tx *types.Transaction) error { +func (pool *CachePool) ValidateTxBasics(tx *types.Transaction) error { opts := &txpool.ValidationOptions{ Config: pool.chainconfig, Accept: 0 | @@ -374,10 +374,7 @@ func (pool *CachePool) validateTxBasics(tx *types.Transaction) error { MaxSize: txMaxSize, MinTip: pool.gasTip.Load().ToBig(), } - if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil { - return err - } - return nil + return txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts) } // validateTx checks whether a transaction is valid according to the consensus @@ -556,7 +553,7 @@ func (pool *CachePool) Add(txs []*types.Transaction, sync bool) []error { // Exclude transactions with basic errors, e.g invalid signatures and // insufficient intrinsic gas as soon as possible and cache senders // in transactions before obtaining lock - if err := pool.validateTxBasics(tx); err != nil { + if err := pool.ValidateTxBasics(tx); err != nil { errs[i] = err log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err) invalidCachedTxMeter.Mark(1) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index fbc16f076..6bbaed7f5 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -679,11 +679,11 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address] return pending } -// validateTxBasics checks whether a transaction is valid according to the consensus +// ValidateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. // This check is meant as an early check which only needs to be performed once, // and does not require the pool mutex to be held. -func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error { +func (pool *LegacyPool) ValidateTxBasics(tx *types.Transaction) error { opts := &txpool.ValidationOptions{ Config: pool.chainconfig, Accept: 0 | @@ -694,10 +694,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error { MaxSize: txMaxSize, MinTip: pool.gasTip.Load().ToBig(), } - if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil { - return err - } - return nil + return txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts) } // validateTx checks whether a transaction is valid according to the consensus @@ -1050,7 +1047,7 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, sync bool) []error { // Exclude transactions with basic errors, e.g invalid signatures and // insufficient intrinsic gas as soon as possible and cache senders // in transactions before obtaining lock - if err := pool.validateTxBasics(tx); err != nil { + if err := pool.ValidateTxBasics(tx); err != nil { errs[i] = err log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err) invalidTxMeter.Mark(1) diff --git a/core/txpool/locals/tx_tracker.go b/core/txpool/locals/tx_tracker.go index b3c7c8768..1d3f0c0a9 100644 --- a/core/txpool/locals/tx_tracker.go +++ b/core/txpool/locals/tx_tracker.go @@ -74,28 +74,45 @@ func New(journalPath string, journalTime time.Duration, chainConfig *params.Chai // Track adds a transaction to the tracked set. // Note: blob-type transactions are ignored. -func (tracker *TxTracker) Track(tx *types.Transaction) { - tracker.TrackAll([]*types.Transaction{tx}) +func (tracker *TxTracker) Track(tx *types.Transaction) error { + return tracker.TrackAll([]*types.Transaction{tx})[0] } // TrackAll adds a list of transactions to the tracked set. // Note: blob-type transactions are ignored. -func (tracker *TxTracker) TrackAll(txs []*types.Transaction) { +func (tracker *TxTracker) TrackAll(txs []*types.Transaction) []error { tracker.mu.Lock() defer tracker.mu.Unlock() + var errors []error for _, tx := range txs { if tx.Type() == types.BlobTxType { + errors = append(errors, nil) + continue + } + // Ignore the transactions which are failed for fundamental + // validation such as invalid parameters. + if err := tracker.pool.ValidateTxBasics(tx); err != nil { + log.Debug("Invalid transaction submitted", "hash", tx.Hash(), "err", err) + errors = append(errors, err) continue } // If we're already tracking it, it's a no-op if _, ok := tracker.all[tx.Hash()]; ok { + errors = append(errors, nil) continue } + // Theoretically, checking the error here is unnecessary since sender recovery + // is already part of basic validation. However, retrieving the sender address + // from the transaction cache is effectively a no-op if it was previously verified. + // Therefore, the error is still checked just in case. addr, err := types.Sender(tracker.signer, tx) - if err != nil { // Ignore this tx + if err != nil { + errors = append(errors, err) continue } + errors = append(errors, nil) + tracker.all[tx.Hash()] = tx if tracker.byAddr[addr] == nil { tracker.byAddr[addr] = legacypool.NewSortedMap() @@ -107,6 +124,7 @@ func (tracker *TxTracker) TrackAll(txs []*types.Transaction) { } } localGauge.Update(int64(len(tracker.all))) + return errors } // recheck checks and returns any transactions that needs to be resubmitted. diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 4e7d3aec8..4c4dbf6d2 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -137,6 +137,12 @@ type SubPool interface { // retrieve blobs from the pools directly instead of the network. GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) + // ValidateTxBasics checks whether a transaction is valid according to the consensus + // rules, but does not check state-dependent validation such as sufficient balance. + // This check is meant as a static check which can be performed without holding the + // pool mutex. + ValidateTxBasics(tx *types.Transaction) error + // Add enqueues a batch of transactions into the pool if they are valid. Due // to the large transaction churn, add may postpone fully integrating the tx // to a later point to batch multiple ones together. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index f1dfe965b..9f8889ac9 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -328,6 +328,17 @@ func (p *TxPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Pr return nil, nil } +// ValidateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error { + for _, subpool := range p.subpools { + if subpool.Filter(tx) { + return subpool.ValidateTxBasics(tx) + } + } + return fmt.Errorf("%w: received type %d", core.ErrTxTypeNotSupported, tx.Type()) +} + // Add enqueues a batch of transactions into the pool if they are valid. Due // to the large transaction churn, add may postpone fully integrating the tx // to a later point to batch multiple ones together. diff --git a/eth/api_backend.go b/eth/api_backend.go index 946b8eeaa..175cb215d 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -285,10 +285,20 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri } func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { - if locals := b.eth.localTxTracker; locals != nil { - locals.Track(signedTx) + locals := b.eth.localTxTracker + if locals != nil { + if err := locals.Track(signedTx); err != nil { + return err + } + } + // No error will be returned to user if the transaction fails stateful + // validation (e.g., no available slot), as the locally submitted transactions + // may be resubmitted later via the local tracker. + err := b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0] + if err != nil && locals == nil { + return err } - return b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0] + return nil } func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { From 551c5ddc608745b220858ec3da2c9b8373bd86c7 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Sat, 1 Mar 2025 14:10:38 +0100 Subject: [PATCH 183/354] eth: check blob transaction validity on the peer goroutine when received (#31219) This ensures that if we receive a blob transaction announcement where we cannot link the tx to the sidecar commitments, we will drop the sending peer. This check is added in the protocol handler for the PooledTransactions message. Tests for this have also been added in the cross-client "eth" protocol test suite. --------- Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/conn.go | 5 + cmd/devp2p/internal/ethtest/suite.go | 197 +++++++++++++++++++++++++++ core/txpool/validation.go | 14 +- core/types/tx_blob.go | 17 +++ eth/handler_eth.go | 13 ++ 5 files changed, 234 insertions(+), 12 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/conn.go b/cmd/devp2p/internal/ethtest/conn.go index b555b1478..a7bc70cbf 100644 --- a/cmd/devp2p/internal/ethtest/conn.go +++ b/cmd/devp2p/internal/ethtest/conn.go @@ -130,11 +130,16 @@ func (c *Conn) Write(proto Proto, code uint64, msg any) error { return err } +var errDisc error = fmt.Errorf("disconnect") + // ReadEth reads an Eth sub-protocol wire message. func (c *Conn) ReadEth() (any, error) { c.SetReadDeadline(time.Now().Add(timeout)) for { code, data, _, err := c.Conn.Read() + if code == discMsg { + return nil, errDisc + } if err != nil { return nil, err } diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 2f1731b60..8ebbe2a05 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -17,8 +17,12 @@ package ethtest import ( + "context" "crypto/rand" + "fmt" "reflect" + "sync" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" @@ -79,6 +83,8 @@ func (s *Suite) EthTests() []utesting.Test { {Name: "InvalidTxs", Fn: s.TestInvalidTxs}, {Name: "NewPooledTxs", Fn: s.TestNewPooledTxs}, {Name: "BlobViolations", Fn: s.TestBlobViolations}, + {Name: "TestBlobTxWithoutSidecar", Fn: s.TestBlobTxWithoutSidecar}, + {Name: "TestBlobTxWithMismatchedSidecar", Fn: s.TestBlobTxWithMismatchedSidecar}, } } @@ -825,3 +831,194 @@ func (s *Suite) TestBlobViolations(t *utesting.T) { conn.Close() } } + +// mangleSidecar returns a copy of the given blob transaction where the sidecar +// data has been modified to produce a different commitment hash. +func mangleSidecar(tx *types.Transaction) *types.Transaction { + sidecar := tx.BlobTxSidecar() + copy := types.BlobTxSidecar{ + Blobs: append([]kzg4844.Blob{}, sidecar.Blobs...), + Commitments: append([]kzg4844.Commitment{}, sidecar.Commitments...), + Proofs: append([]kzg4844.Proof{}, sidecar.Proofs...), + } + // zero the first commitment to alter the sidecar hash + copy.Commitments[0] = kzg4844.Commitment{} + return tx.WithBlobTxSidecar(©) +} + +func (s *Suite) TestBlobTxWithoutSidecar(t *utesting.T) { + t.Log(`This test checks that a blob transaction first advertised/transmitted without blobs will result in the sending peer being disconnected, and the full transaction should be successfully retrieved from another peer.`) + tx := s.makeBlobTxs(1, 2, 42)[0] + badTx := tx.WithoutBlobTxSidecar() + s.testBadBlobTx(t, tx, badTx) +} + +func (s *Suite) TestBlobTxWithMismatchedSidecar(t *utesting.T) { + t.Log(`This test checks that a blob transaction first advertised/transmitted without blobs, whose commitment don't correspond to the blob_versioned_hashes in the transaction, will result in the sending peer being disconnected, and the full transaction should be successfully retrieved from another peer.`) + tx := s.makeBlobTxs(1, 2, 43)[0] + badTx := mangleSidecar(tx) + s.testBadBlobTx(t, tx, badTx) +} + +// readUntil reads eth protocol messages until a message of the target type is +// received. It returns an error if there is a disconnect, or if the context +// is cancelled before a message of the desired type can be read. +func readUntil[T any](ctx context.Context, conn *Conn) (*T, error) { + for { + select { + case <-ctx.Done(): + return nil, context.Canceled + default: + } + received, err := conn.ReadEth() + if err != nil { + if err == errDisc { + return nil, errDisc + } + continue + } + + switch res := received.(type) { + case *T: + return res, nil + } + } +} + +// readUntilDisconnect reads eth protocol messages until the peer disconnects. +// It returns whether the peer disconnects in the next 100ms. +func readUntilDisconnect(conn *Conn) (disconnected bool) { + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + _, err := readUntil[struct{}](ctx, conn) + return err == errDisc +} + +func (s *Suite) testBadBlobTx(t *utesting.T, tx *types.Transaction, badTx *types.Transaction) { + stage1, stage2, stage3 := new(sync.WaitGroup), new(sync.WaitGroup), new(sync.WaitGroup) + stage1.Add(1) + stage2.Add(1) + stage3.Add(1) + + errc := make(chan error) + + badPeer := func() { + // announce the correct hash from the bad peer. + // when the transaction is first requested before transmitting it from the bad peer, + // trigger step 2: connection and announcement by good peers + + conn, err := s.dial() + if err != nil { + errc <- fmt.Errorf("dial fail: %v", err) + return + } + defer conn.Close() + + if err := conn.peer(s.chain, nil); err != nil { + errc <- fmt.Errorf("bad peer: peering failed: %v", err) + return + } + + ann := eth.NewPooledTransactionHashesPacket{ + Types: []byte{types.BlobTxType}, + Sizes: []uint32{uint32(badTx.Size())}, + Hashes: []common.Hash{badTx.Hash()}, + } + + if err := conn.Write(ethProto, eth.NewPooledTransactionHashesMsg, ann); err != nil { + errc <- fmt.Errorf("sending announcement failed: %v", err) + return + } + + req, err := readUntil[eth.GetPooledTransactionsPacket](context.Background(), conn) + if err != nil { + errc <- fmt.Errorf("failed to read GetPooledTransactions message: %v", err) + return + } + + stage1.Done() + stage2.Wait() + + // the good peer is connected, and has announced the tx. + // proceed to send the incorrect one from the bad peer. + + resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: eth.PooledTransactionsResponse(types.Transactions{badTx})} + if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil { + errc <- fmt.Errorf("writing pooled tx response failed: %v", err) + return + } + if !readUntilDisconnect(conn) { + errc <- fmt.Errorf("expected bad peer to be disconnected") + return + } + stage3.Done() + } + + goodPeer := func() { + stage1.Wait() + + conn, err := s.dial() + if err != nil { + errc <- fmt.Errorf("dial fail: %v", err) + return + } + defer conn.Close() + + if err := conn.peer(s.chain, nil); err != nil { + errc <- fmt.Errorf("peering failed: %v", err) + return + } + + ann := eth.NewPooledTransactionHashesPacket{ + Types: []byte{types.BlobTxType}, + Sizes: []uint32{uint32(tx.Size())}, + Hashes: []common.Hash{tx.Hash()}, + } + + if err := conn.Write(ethProto, eth.NewPooledTransactionHashesMsg, ann); err != nil { + errc <- fmt.Errorf("sending announcement failed: %v", err) + return + } + + // wait until the bad peer has transmitted the incorrect transaction + stage2.Done() + stage3.Wait() + + // the bad peer has transmitted the bad tx, and been disconnected. + // transmit the same tx but with correct sidecar from the good peer. + + var req *eth.GetPooledTransactionsPacket + req, err = readUntil[eth.GetPooledTransactionsPacket](context.Background(), conn) + if err != nil { + errc <- fmt.Errorf("reading pooled tx request failed: %v", err) + return + } + + if req.GetPooledTransactionsRequest[0] != tx.Hash() { + errc <- fmt.Errorf("requested unknown tx hash") + return + } + + resp := eth.PooledTransactionsPacket{RequestId: req.RequestId, PooledTransactionsResponse: eth.PooledTransactionsResponse(types.Transactions{tx})} + if err := conn.Write(ethProto, eth.PooledTransactionsMsg, resp); err != nil { + errc <- fmt.Errorf("writing pooled tx response failed: %v", err) + return + } + if readUntilDisconnect(conn) { + errc <- fmt.Errorf("unexpected disconnect") + return + } + close(errc) + } + + if err := s.engine.sendForkchoiceUpdated(); err != nil { + t.Fatalf("send fcu failed: %v", err) + } + + go goodPeer() + go badPeer() + err := <-errc + if err != nil { + t.Fatalf("%v", err) + } +} diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 5d041d063..8c44d50f7 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -17,7 +17,6 @@ package txpool import ( - "crypto/sha256" "errors" "fmt" "math/big" @@ -172,20 +171,11 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err if len(sidecar.Blobs) != len(hashes) { return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) } - if len(sidecar.Commitments) != len(hashes) { - return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) - } if len(sidecar.Proofs) != len(hashes) { return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sidecar.Proofs), len(hashes)) } - // Blob quantities match up, validate that the provers match with the - // transaction hash before getting to the cryptography - hasher := sha256.New() - for i, vhash := range hashes { - computed := kzg4844.CalcBlobHashV1(hasher, &sidecar.Commitments[i]) - if vhash != computed { - return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash) - } + if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil { + return err } // Blob commitments match with the hashes in the transaction, verify the // blobs themselves via KZG diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 88251ab95..32401db10 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -19,6 +19,7 @@ package types import ( "bytes" "crypto/sha256" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -85,6 +86,22 @@ func (sc *BlobTxSidecar) encodedSize() uint64 { return rlp.ListSize(blobs) + rlp.ListSize(commitments) + rlp.ListSize(proofs) } +// ValidateBlobCommitmentHashes checks whether the given hashes correspond to the +// commitments in the sidecar +func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) error { + if len(sc.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sc.Commitments), len(hashes)) + } + hasher := sha256.New() + for i, vhash := range hashes { + computed := kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i]) + if vhash != computed { + return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash) + } + } + return nil +} + // blobTxWithBlobs is used for encoding of transactions when blobs are present. type blobTxWithBlobs struct { BlobTx *BlobTx diff --git a/eth/handler_eth.go b/eth/handler_eth.go index a43dff9e5..1d6b9d4c4 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -79,6 +79,19 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { return h.txFetcher.Enqueue(peer.ID(), *packet, false) case *eth.PooledTransactionsResponse: + // If we receive any blob transactions missing sidecars, or with + // sidecars that don't correspond to the versioned hashes reported + // in the header, disconnect from the sending peer. + for _, tx := range *packet { + if tx.Type() == types.BlobTxType { + if tx.BlobTxSidecar() == nil { + return errors.New("received sidecar-less blob transaction") + } + if err := tx.BlobTxSidecar().ValidateBlobCommitmentHashes(tx.BlobHashes()); err != nil { + return err + } + } + } return h.txFetcher.Enqueue(peer.ID(), *packet, true) default: From 63aa3721c5300c687abe97ac2a806d798767e2bc Mon Sep 17 00:00:00 2001 From: Shude Li Date: Sat, 1 Mar 2025 21:11:51 +0800 Subject: [PATCH 184/354] ethclient: add BlobBaseFee method (#31290) --- ethclient/ethclient.go | 9 +++++++++ ethclient/ethclient_test.go | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index cefd4f61b..d633039a5 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -617,6 +617,15 @@ func (ec *Client) MaxEnvelopeGas(ctx context.Context) (*big.Int, error) { return (*big.Int)(&hex), nil } +// BlobBaseFee retrieves the current blob base fee. +func (ec *Client) BlobBaseFee(ctx context.Context) (*big.Int, error) { + var hex hexutil.Big + if err := ec.c.CallContext(ctx, &hex, "eth_blobBaseFee"); err != nil { + return nil, err + } + return (*big.Int)(&hex), nil +} + type feeHistoryResultMarshaling struct { OldestBlock *hexutil.Big `json:"oldestBlock"` Reward [][]*hexutil.Big `json:"reward,omitempty"` diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 10c75155d..5d13e5131 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -422,6 +422,15 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { t.Fatalf("unexpected max envelope gas: %v", maxEnvelopeGas) } + // BlobBaseFee + blobBaseFee, err := ec.BlobBaseFee(context.Background()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if blobBaseFee.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("unexpected blob base fee: %v", blobBaseFee) + } + // FeeHistory history, err := ec.FeeHistory(context.Background(), 1, big.NewInt(2), []float64{95, 99}) if err != nil { From 604a96f138a6e1eeb51553b5370a4999c9827456 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 4 Mar 2025 09:30:03 +0100 Subject: [PATCH 185/354] eth/tracers: fix omitempty for memory and storage (#31289) This fixes a regression in the opcode tracer API where we would log empty memory and storage fields. --- eth/tracers/logger/logger.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 596ee9714..02ff8146f 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -177,14 +177,14 @@ func (s *StructLog) toLegacyJSON() json.RawMessage { if len(s.ReturnData) > 0 { msg.ReturnData = hexutil.Bytes(s.ReturnData).String() } - if s.Memory != nil { + if len(s.Memory) > 0 { memory := make([]string, 0, (len(s.Memory)+31)/32) for i := 0; i+32 <= len(s.Memory); i += 32 { memory = append(memory, fmt.Sprintf("%x", s.Memory[i:i+32])) } msg.Memory = &memory } - if s.Storage != nil { + if len(s.Storage) > 0 { storage := make(map[string]string) for i, storageValue := range s.Storage { storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) From d74173301dcf2a9190b27bbbcad89ff19d93962a Mon Sep 17 00:00:00 2001 From: levisyin Date: Wed, 5 Mar 2025 18:02:18 +0800 Subject: [PATCH 186/354] build: upgrade to Go 1.24.1 and golangci-lint 1.64.4 (#31313) - upgrade -dlgo version to Go 1.24.1 - upgrade golangci-lint version to 1.64.6 --- build/checksums.txt | 200 ++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index c8b742e44..06e44ea2b 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,109 +5,109 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/fixtures_pectra-devnet-6.tar.gz b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz -# version:golang 1.24.0 +# version:golang 1.24.1 # https://go.dev/dl/ -d14120614acb29d12bcab72bd689f257eb4be9e0b6f88a8fb7e41ac65f8556e5 go1.24.0.src.tar.gz -5d04588154d5923bd8e26b76111806340ec55c41af1b05623ea744fcb3d6bc22 go1.24.0.aix-ppc64.tar.gz -7af054e5088b68c24b3d6e135e5ca8d91bbd5a05cb7f7f0187367b3e6e9e05ee go1.24.0.darwin-amd64.tar.gz -dee0ea64411a00b47ded586d5a8e30cfe3acf51564aa1bb24e039a6dca807a29 go1.24.0.darwin-amd64.pkg -fd9cfb5dd6c75a347cfc641a253f0db1cebaca16b0dd37965351c6184ba595e4 go1.24.0.darwin-arm64.tar.gz -b19eb6b7ae87f8371c3e7a84d129db67779a2883d2fffa6bb90412b0167df133 go1.24.0.darwin-arm64.pkg -d0dc34ad86aea746abe245994c68a9e1ad8f46ba8c4af901cd5861a4dd4c21df go1.24.0.dragonfly-amd64.tar.gz -4ee02b1f3812aff4da79c79464ee4038ca61ad74b3a9619850f30435f81c2536 go1.24.0.freebsd-386.tar.gz -838191001f9324da904dece35a586a3156d548687db87ac9461aa3d38fc88b09 go1.24.0.freebsd-amd64.tar.gz -ce6ad4e84a40a8a1d848b7e31b0cddfd1cee8f7959e7dc358a8fa8b5566ea718 go1.24.0.freebsd-arm.tar.gz -511f7b0cac4c4ed1066d324072ce223b906ad6b2a85f2e1c5d260eb7d08b5901 go1.24.0.freebsd-arm64.tar.gz -a1e4072630dc589a2975ef51317b52c7d8599bf6f389fc59033c01e0a0fa705a go1.24.0.freebsd-riscv64.tar.gz -7593e9dcee9f07c3df6d099f7d259f5734a6c0dccc5f28962f18e7f501c9bb21 go1.24.0.illumos-amd64.tar.gz -90521453a59c6ce20364d2dc7c38532949b033b602ba12d782caeb90af1b0624 go1.24.0.linux-386.tar.gz -dea9ca38a0b852a74e81c26134671af7c0fbe65d81b0dc1c5bfe22cf7d4c8858 go1.24.0.linux-amd64.tar.gz -c3fa6d16ffa261091a5617145553c71d21435ce547e44cc6dfb7470865527cc7 go1.24.0.linux-arm64.tar.gz -695dc54fa14cd3124fa6900d7b5ae39eeac23f7a4ecea81656070160fac2c54a go1.24.0.linux-armv6l.tar.gz -a201e4c9b7e6d29ed64c43296ed88e81a66f82f2093ce45b766d2c526941396f go1.24.0.linux-loong64.tar.gz -f3ac039aae78ad0bfb08106406c2e62eaf763dd82ebaf0ecd539adadd1d729a6 go1.24.0.linux-mips.tar.gz -f2e6456d45e024831b1da8d88b1bb6392cca9500c1b00841f525d76c9e9553e0 go1.24.0.linux-mips64.tar.gz -b847893ff119389c939adc2b8516b6500204b7cb49d5e19b25e1c2091d2c74c6 go1.24.0.linux-mips64le.tar.gz -bd4aed27d02746c237c3921e97029ac6b6fe687a67436b8f52ff1f698d330bd9 go1.24.0.linux-mipsle.tar.gz -007123c9b06c41729a4bb3f166f4df7196adf4e33c2d2ab0e7e990175f0ce1d4 go1.24.0.linux-ppc64.tar.gz -a871a43de7d26c91dd90cb6e0adacb214c9e35ee2188c617c91c08c017efe81a go1.24.0.linux-ppc64le.tar.gz -620dcf48c6297519aad6c81f8e344926dc0ab09a2a79f1e306964aece95a553d go1.24.0.linux-riscv64.tar.gz -544d78b077c6b54bf78958c4a8285abec2d21f668fb007261c77418cd2edbb46 go1.24.0.linux-s390x.tar.gz -8b143a7edefbaa2a0b0246c9df2df1bac9fbed909d8615a375c08da7744e697d go1.24.0.netbsd-386.tar.gz -67150a6dd7bdb9c4e88d77f46ee8c4dc99d5e71deca4912d8c2c85f7a16d0262 go1.24.0.netbsd-amd64.tar.gz -446b2539f11218fd6f6f6e3dd90b20ae55a06afe129885eeb3df51eb344eb0f6 go1.24.0.netbsd-arm.tar.gz -370115b6ff7d30b29431223de348eb11ab65e3c92627532d97fd55f63f94e7a8 go1.24.0.netbsd-arm64.tar.gz -cbda5f15f06ed9630f122a53542d9de13d149643633c74f1dcb45e79649b788a go1.24.0.openbsd-386.tar.gz -926f601d0e655ab1e8d7f357fd82542e5cf206c38c4e2f9fccf0706987d38836 go1.24.0.openbsd-amd64.tar.gz -8a54892f8c933c541fff144a825d0fdc41bae14b0832aab703cb75eb4cb64f2c go1.24.0.openbsd-arm.tar.gz -ef7fddcef0a22c7900c178b7687cf5aa25c2a9d46a3cc330b77a6de6e6c2396b go1.24.0.openbsd-arm64.tar.gz -b3b5e2e2b53489ded2c2c21900ddcbbdb7991632bb5b42f05f125d71675e0b76 go1.24.0.openbsd-ppc64.tar.gz -fbcb1dbf1269b4079dc4fd0b15f3274b9d635f1a7e319c3fc1a907b03280348e go1.24.0.openbsd-riscv64.tar.gz -33b4221e1c174a16e3f661deab6c60838ac4ae6cb869a4da1d1115773ceed88b go1.24.0.plan9-386.tar.gz -111a89014019cdbd69c2978de9b3e201f77e35183c8ab3606fba339d38f28549 go1.24.0.plan9-amd64.tar.gz -8da3d3997049f40ebe0cd336a9bb9e4bfa4832df3c90a32f07383371d6d74849 go1.24.0.plan9-arm.tar.gz -b6069da21dc95ccdbd047675b584e5480ffc3eba35f9e7c8b0e7b317aaf01e2c go1.24.0.solaris-amd64.tar.gz -b53c28a4c2863ec50ab4a1dbebe818ef6177f86773b6f43475d40a5d9aa4ec9e go1.24.0.windows-386.zip -f07677013cd7861c5e16067b0a82144c23c4bf72c139c762e142440f4c926f61 go1.24.0.windows-386.msi -96b7280979205813759ee6947be7e3bb497da85c482711116c00522e3bb41ff1 go1.24.0.windows-amd64.zip -4e78016d889431eb16aa0f87868cf52479b90059791c94a4ff45872d0573089e go1.24.0.windows-amd64.msi -53f73450fb66075d16be9f206e9177bd972b528168271918c4747903b5596c3d go1.24.0.windows-arm64.zip -4f9780158fb7996dcbcbc7c7ef208f880b5e8c1f2792ba3ede0c75050c1bc23a go1.24.0.windows-arm64.msi +8244ebf46c65607db10222b5806aeb31c1fcf8979c1b6b12f60c677e9a3c0656 go1.24.1.src.tar.gz +8d627dc163a4bffa2b1887112ad6194af175dce108d606ed1714a089fb806033 go1.24.1.aix-ppc64.tar.gz +addbfce2056744962e2d7436313ab93486660cf7a2e066d171b9d6f2da7c7abe go1.24.1.darwin-amd64.tar.gz +58d529334561cff11087cd4ab18fe0b46d8d5aad88f45c02b9645f847e014512 go1.24.1.darwin-amd64.pkg +295581b5619acc92f5106e5bcb05c51869337eb19742fdfa6c8346c18e78ff88 go1.24.1.darwin-arm64.tar.gz +78b0fc8ddc344eb499f1a952c687cb84cbd28ba2b739cfa0d4eb042f07e44e82 go1.24.1.darwin-arm64.pkg +e70053f56f7eb93806d80cbd5726f78509a0a467602f7bea0e2c4ee8ed7c3968 go1.24.1.dragonfly-amd64.tar.gz +3595e2674ed8fe72e604ca59c964d3e5277aafb08475c2b1aaca2d2fd69c24fc go1.24.1.freebsd-386.tar.gz +47d7de8bb64d5c3ee7b6723aa62d5ecb11e3568ef2249bbe1d4bbd432d37c00c go1.24.1.freebsd-amd64.tar.gz +04eec3bcfaa14c1370cdf98e8307fac7e4853496c3045afb9c3124a29cbca205 go1.24.1.freebsd-arm.tar.gz +51aa70146e40cfdc20927424083dc86e6223f85dc08089913a1651973b55665b go1.24.1.freebsd-arm64.tar.gz +3c131d8e3fc285a1340f87813153e24226d3ddbd6e54f3facbd6e4c46a84655e go1.24.1.freebsd-riscv64.tar.gz +201d09da737ba39d5367f87d4e8b31edaeeb3dc9b9c407cb8cfb40f90c5a727a go1.24.1.illumos-amd64.tar.gz +8c530ecedbc17e42ce10177bea07ccc96a3e77c792ea1ea72173a9675d16ffa5 go1.24.1.linux-386.tar.gz +cb2396bae64183cdccf81a9a6df0aea3bce9511fc21469fb89a0c00470088073 go1.24.1.linux-amd64.tar.gz +8df5750ffc0281017fb6070fba450f5d22b600a02081dceef47966ffaf36a3af go1.24.1.linux-arm64.tar.gz +6d95f8d7884bfe2364644c837f080f2b585903d0b771eb5b06044e226a4f120a go1.24.1.linux-armv6l.tar.gz +19304a4a56e46d04604547d2d83235dc4f9b192c79832560ce337d26cc7b835a go1.24.1.linux-loong64.tar.gz +6347be77fa5359c12a5308c8ab87147c1fc4717b0c216493d1706c3b9fcde22d go1.24.1.linux-mips.tar.gz +1647df415f7030b82d4105670192aa7e8910e18563bb0d505192d72800cc2d21 go1.24.1.linux-mips64.tar.gz +762da594e4ec0f9cf6defae6ef971f5f7901203ee6a2d979e317adec96657317 go1.24.1.linux-mips64le.tar.gz +9d8133c7b23a557399fab870b5cf464079c2b623a43b214a7567cf11c254a444 go1.24.1.linux-mipsle.tar.gz +132f10999abbaccbada47fa85462db30c423955913b14d6c692de25f4636c766 go1.24.1.linux-ppc64.tar.gz +0fb522efcefabae6e37e69bdc444094e75bfe824ea6d4cc3cbc70c7ae1b16858 go1.24.1.linux-ppc64le.tar.gz +eaef4323d5467ff97fb1979c8491764060dade19f02f3275a9313f9a0da3b9c0 go1.24.1.linux-riscv64.tar.gz +6c05e14d8f11094cb56a1c50f390b6b658bed8a7cbd8d1a57e926581b7eabfce go1.24.1.linux-s390x.tar.gz +5dbb287d343ea00d58a70b11629f32ee716dc50a6875c459ea2018df0f294cd8 go1.24.1.netbsd-386.tar.gz +617aa3faee50ce84c343db0888e9a210c310a7203666b4ed620f31030c9fb32f go1.24.1.netbsd-amd64.tar.gz +59a928b7080c4a6ac985946274b7c65ce1cecc0b468ecd992d17b7c12fab9296 go1.24.1.netbsd-arm.tar.gz +28daa8d0feb4aef2af60cefa3305bb9314de7e8a05cbca41ac548964cdfe89b7 go1.24.1.netbsd-arm64.tar.gz +b7382b2f5d99813aeac14db482faa3bfbd47a68880b607fa2a7e669e26bab9cd go1.24.1.openbsd-386.tar.gz +2513b6537c45deead5e641c7ce7502913e7d5e6f0b21c52542fb11f81578690f go1.24.1.openbsd-amd64.tar.gz +853c1917d4fc7b144c55a02842aa48542d5cc798dde8db96dc0fdbc263200e04 go1.24.1.openbsd-arm.tar.gz +6bc207b91e6f6ae3347fb54616a8fb2f5c11983713846a4cef111ff3f4f94d14 go1.24.1.openbsd-arm64.tar.gz +4279260e2f2b94ee94e81470d13db7367f4393b061fee60985528fa0fa430df4 go1.24.1.openbsd-ppc64.tar.gz +6fc4023a0a339ee0778522364a127d94c78e62122288d47d820dba703f81dc07 go1.24.1.openbsd-riscv64.tar.gz +b5eb9fafd77146e7e1f748acfd95559580ecc8d2f15abf432a20f58c929c7cd2 go1.24.1.plan9-386.tar.gz +24dcad6361b141fc8cced15b092351e12a99d2e58d7013204a3013c50daf9fdd go1.24.1.plan9-amd64.tar.gz +a026ac3b55aa1e6fdc2aaab30207a117eafbe965ed81d3aa0676409f280ddc37 go1.24.1.plan9-arm.tar.gz +8e4f6a77388dc6e5aa481efd5abdb3b9f5c9463bb82f4db074494e04e5c84992 go1.24.1.solaris-amd64.tar.gz +b799f4ab264eef12a014c759383ed934056608c483e0f73e34ea6caf9f1df5f9 go1.24.1.windows-386.zip +db128981033ac82a64688a123f631e61297b6b8f52ca913145e57caa8ce94cc3 go1.24.1.windows-386.msi +95666b551453209a2b8869d29d177285ff9573af10f085d961d7ae5440f645ce go1.24.1.windows-amd64.zip +5968e7adcf26e68a54f1cd41ad561275a670a8e2ca5263bc375b524638557dfb go1.24.1.windows-amd64.msi +e28c4e6d0b913955765b46157ab88ae59bb636acaa12d7bec959aa6900f1cebd go1.24.1.windows-arm64.zip +6d352c1f154a102a5b90c480cc64bab205ccf2681e34e78a3a4d3f1ddfbc81e4 go1.24.1.windows-arm64.msi -# version:golangci 1.64.4 +# version:golangci 1.64.6 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.64.4/ -f31ef6e20c62acc31eb7b851d611b4bd10256d1b1d8be38f0cceec300b5b60db golangci-lint-1.64.4-darwin-amd64.tar.gz -bb4a9ece7ef66ef49bd6de873f5f5ec801cf93dacf58efb360cc939b4fd37c47 golangci-lint-1.64.4-darwin-arm64.tar.gz -fd8f9046150356e36ad8af31f99219515d5e0ff6e8e9f4204182312447018fcf golangci-lint-1.64.4-freebsd-386.tar.gz -bbae940caa31cb1d2d8d26abd867666cd92746d2ddc63d6917d128c456d715ef golangci-lint-1.64.4-freebsd-amd64.tar.gz -86eb00cbdc5e277857a380d556d78a42b3edf8aae5991de8767dce7da337d73b golangci-lint-1.64.4-freebsd-armv6.tar.gz -c0f7d50f4fcd39ae8bda181c127b078a79d87c885ac472c4cce5b01134dde5bc golangci-lint-1.64.4-freebsd-armv7.tar.gz -31d264fa26a73a583425bc9b39c18de70a330e346fe800e80c277ddb5f8477b6 golangci-lint-1.64.4-illumos-amd64.tar.gz -3dccc18a6b1a0f2518196190ed56277b1480b381231605936eca6b862426b83c golangci-lint-1.64.4-linux-386.deb -b95f3e757c59ada75144bd086478ab63bcda83c2b2a935e60d8f39aff20fbcd2 golangci-lint-1.64.4-linux-386.rpm -8fa58af0022ae0487162c02d08075e2d869c9b5f8613a64b85fd769a2a2d2b93 golangci-lint-1.64.4-linux-386.tar.gz -fa80d2ad920fc74b85a0b93ad1671fd27c9c4d6f22e167cc4e1da758d72dd893 golangci-lint-1.64.4-linux-amd64.deb -8bf2e3c82504a893a12e84ecbc8071f787075d2fdc1ef946deda3d29aae1afad golangci-lint-1.64.4-linux-amd64.rpm -7de8f80a12cd3052610e6be21f08f2220805b1f3e43b3b6ec843f14a12140de2 golangci-lint-1.64.4-linux-amd64.tar.gz -ade222b9ae997a2875e44ed53ca5a129f24944b232132d0a5898f101381d3bfa golangci-lint-1.64.4-linux-arm64.deb -8f9f8617ed0d8b8f62c8dfe69877932c0d85f0d83a9ec3250b04777c7133ada1 golangci-lint-1.64.4-linux-arm64.rpm -debf1f73e71f1dd288957574eab4e7515b1b04c4ac2f127192181da8a42f0e8e golangci-lint-1.64.4-linux-arm64.tar.gz -3f616caa4a16738114ad29076a333c62bb0650fe4846b438c341d235f78ee5aa golangci-lint-1.64.4-linux-armv6.deb -6a7c9d7b7c57d7d440e1e3f133e18e4b5b703604d4ae7f7862fb9ea461887a8b golangci-lint-1.64.4-linux-armv6.rpm -d7b9e3c89af93d98c6b5a555ef48e25bee24f84d7825a29e343e9966404d5b4d golangci-lint-1.64.4-linux-armv6.tar.gz -18179ecf04ace3051450852424b31a4d26644a3912e759cd595e624eee0174bd golangci-lint-1.64.4-linux-armv7.deb -f669fce85d3edc3d557d1e64e2241d895f1ee676f79d139874bf76693cc447a2 golangci-lint-1.64.4-linux-armv7.rpm -9bbaa13b474ecb1560fb05aee0a8cab3e9cc327d41632bee8b553b766f2bf756 golangci-lint-1.64.4-linux-armv7.tar.gz -b5a2725adba2a1b04a5160ffa0730ba30b88c1ee99ecbc65dd7075a8d70f3730 golangci-lint-1.64.4-linux-loong64.deb -28ac00afb3f6407808fe7c15a6002e5fe6b3b461df3fe0223603542e6f9b974a golangci-lint-1.64.4-linux-loong64.rpm -121170309fed82cb64d6fae5020ef2b194e591a53156370c221a80121cc4aa08 golangci-lint-1.64.4-linux-loong64.tar.gz -aadfaab41380f53ada8f7ad4fa9af784bb882eaaa1e3939e048b3a5ea8f2c13f golangci-lint-1.64.4-linux-mips64.deb -6fecbff69086e316dd028050d3ebf82fc466c7f4dc0f6084307054621101c202 golangci-lint-1.64.4-linux-mips64.rpm -430c48034527af028dc608c115166f47b6b67c8cb83a317d9d44876b9753292a golangci-lint-1.64.4-linux-mips64.tar.gz -432126af2bbbd639dbbcc2c265337f104cc613a7b4c5a8fb5e49f182b428f077 golangci-lint-1.64.4-linux-mips64le.deb -cfa663eee0fae721510d6dc31e61db4be51b4e4244eb7de2b6a9bc6d475551e5 golangci-lint-1.64.4-linux-mips64le.rpm -2bacfac65182893c5ceb67b61d5b9d2b24da47726d84cb87d734a6e32f040148 golangci-lint-1.64.4-linux-mips64le.tar.gz -66d86e47d68420c03045eff0698e9acf9f82d97cd1f07d7e52837a6e544eceed golangci-lint-1.64.4-linux-ppc64le.deb -05466bd2d8e82f7245b838e29d0c90cdbaf67375b2b5bc980d8510d5edb206ad golangci-lint-1.64.4-linux-ppc64le.rpm -e013b6980f7140712af0aedc9a661265e1d3c6adc7e9d045734e3686a3601acc golangci-lint-1.64.4-linux-ppc64le.tar.gz -753980d2fb421d35292b71b51f9bb0552f18de2eb181ccf692ef79e086ad2304 golangci-lint-1.64.4-linux-riscv64.deb -73a33a883020298f8c652a4ace4f6888103d80d411fe3e9b77ce0a3b36ff7d3a golangci-lint-1.64.4-linux-riscv64.rpm -020efd09b894dc75012f43b1d4c58e69e5446ca3f79845b5e10a02588def3e1b golangci-lint-1.64.4-linux-riscv64.tar.gz -4d99a16bc9ff5cea5e4ae3568c6254390fbdad8f1d370c287744409112bceff9 golangci-lint-1.64.4-linux-s390x.deb -6e63374a9f95fc09f2bb9501059eb18b8107e08416722ba7b561ae385d80b33b golangci-lint-1.64.4-linux-s390x.rpm -62a6febb892b26eee84a32cc99d04afe90bf62d0970774b1bab75e36b66f53b4 golangci-lint-1.64.4-linux-s390x.tar.gz -5ba4d235f9abd60d2d280f9fe4228c6ddab11ae9fe48d253b7e477046675f1f6 golangci-lint-1.64.4-netbsd-386.tar.gz -061643bb4370a52010e5e76f88f5b5220e51058df50af86b45286263af92b321 golangci-lint-1.64.4-netbsd-amd64.tar.gz -12b2be6c35bcf7a36374e952c7efec7905a17fa3ebe6214924ba8721b766c4af golangci-lint-1.64.4-netbsd-arm64.tar.gz -553a71a677751dccee082ed8afe24cf58bef725f72aa02aedcc6758dd8f44125 golangci-lint-1.64.4-netbsd-armv6.tar.gz -74a5a5a7b8c8cd11dccdec303ee6592d904b09836782e6d658be359737f300ef golangci-lint-1.64.4-netbsd-armv7.tar.gz -b3ceea2187843f9ba6510303141a72465621e3f190a262c0b48707b9e983ea9a golangci-lint-1.64.4-source.tar.gz -fda4de312fcb0b4853b03bcdfb31ac631a68fa0b966f6aa010eb30d14427180b golangci-lint-1.64.4-windows-386.zip -8fc60bd809f86c6431ed8f3d1f25917538c0ebc93e670cfb199f25bbaa56e602 golangci-lint-1.64.4-windows-amd64.zip -b9058c9d2ae8d75048c6ad8885d11e5ac0a6c40be2af85bfa6605e48d69d3eb6 golangci-lint-1.64.4-windows-arm64.zip -809b0131adb1aa8b359becd13222df367b505bc2955bb3b1d2d0dd6f07347b13 golangci-lint-1.64.4-windows-armv6.zip -fc43f8c95d6bec8ba9a3557a0bb63cf9f504137ce6d24cfdc4c330d46f7779d2 golangci-lint-1.64.4-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.64.6/ +08f9459e7125fed2612abd71596e04d172695921aff82120d1c1e5e9b6fff2a3 golangci-lint-1.64.6-darwin-amd64.tar.gz +8c10d0c7c3935b8c2269d628b6a06a8f48d8fb4cc31af02fe4ce0cd18b0704c1 golangci-lint-1.64.6-darwin-arm64.tar.gz +c07fcabb55deb8d2c4d390025568e76162d7f91b1d14bd2311be45d8d440a624 golangci-lint-1.64.6-freebsd-386.tar.gz +8ed1ef1102e1a42983ffcaae8e06de6a540334c3a69e205c610b8a7c92d469cd golangci-lint-1.64.6-freebsd-amd64.tar.gz +8f8dda66d1b4a85cc8a1daf1b69af6559c3eb0a41dd8033148a9ad85cfc0e1d9 golangci-lint-1.64.6-freebsd-armv6.tar.gz +59e8ca1fa254661b2a55e96515b14a10cd02221d443054deac5b28c3c3e12d6b golangci-lint-1.64.6-freebsd-armv7.tar.gz +e3d323d5f132e9b7593141bfe1d19c8460e65a55cea1008ec96945fed563f981 golangci-lint-1.64.6-illumos-amd64.tar.gz +5ce910f2a864c5fbeb32a30cbd506e1b2ef215f7a0f422cd5be6370b13db6f03 golangci-lint-1.64.6-linux-386.deb +2caab682a26b9a5fb94ba24e3a7e1404fa9eab2c12e36ae1c5548d80a1be190c golangci-lint-1.64.6-linux-386.rpm +2d82d0a4716e6d9b70c95103054855cb4b5f20f7bbdee42297f0189955bd14b6 golangci-lint-1.64.6-linux-386.tar.gz +9cd82503e9841abcaa57663fc899587fe90363c26d86a793a98d3080fd25e907 golangci-lint-1.64.6-linux-amd64.deb +981aaca5e5202d4fbb162ec7080490eb67ef5d32add5fb62fb02210597acc9da golangci-lint-1.64.6-linux-amd64.rpm +71e290acbacb7b3ba4f68f0540fb74dc180c4336ac8a6f3bdcd7fcc48b15148d golangci-lint-1.64.6-linux-amd64.tar.gz +718016bb06c1f598a8d23c7964e2643de621dbe5808688cb38857eb0bb773c84 golangci-lint-1.64.6-linux-arm64.deb +ddc0e7b4b10b47cf894aea157e89e3674bbb60f8f5c480110c21c49cc2c1634d golangci-lint-1.64.6-linux-arm64.rpm +99a7ff13dec7a8781a68408b6ecb8a1c5e82786cba3189eaa91d5cdcc24362ce golangci-lint-1.64.6-linux-arm64.tar.gz +90e360f89c244394912b8709fb83a900b6d56cf19141df2afaf9e902ef3057b1 golangci-lint-1.64.6-linux-armv6.deb +46546ff7c98d873ffcdbee06b39dc1024fc08db4fbf1f6309360a44cf976b5c2 golangci-lint-1.64.6-linux-armv6.rpm +e45c1a42868aca0b0ee54d14fb89da216f3b4409367cd7bce3b5f36788b4fc92 golangci-lint-1.64.6-linux-armv6.tar.gz +3cf6ddbbbf358db3de4b64a24f9683bbe2da3f003cfdee86cb610124b57abafb golangci-lint-1.64.6-linux-armv7.deb +508b6712710da10f11aab9ea5e63af415c932dfe7fff718e649d3100b838f797 golangci-lint-1.64.6-linux-armv7.rpm +da9a8bbee86b4dfee73fbc17e0856ec84c5b04919eb09bf3dd5904c39ce41753 golangci-lint-1.64.6-linux-armv7.tar.gz +ad496a58284e1e9c8ac6f993fec429dcd96c85a8c4715dbb6530a5af0dae7fbd golangci-lint-1.64.6-linux-loong64.deb +3bd70fa737b224750254dce616d9a188570e49b894b0cdb2fd04155e2c061350 golangci-lint-1.64.6-linux-loong64.rpm +a535af973499729f2215a84303eb0de61399057aad6901ddea1b4f73f68d5f2c golangci-lint-1.64.6-linux-loong64.tar.gz +6ad2a1cd37ca30303a488abfca2de52aff57519901c6d8d2608656fe9fb05292 golangci-lint-1.64.6-linux-mips64.deb +5f18369f0ca010a02c267352ebe6e3e0514c6debff49899c9e5520906c0da287 golangci-lint-1.64.6-linux-mips64.rpm +3449d6c13307b91b0e8817f8911c07c3412cdb6931b8d101e42db3e9762e91ad golangci-lint-1.64.6-linux-mips64.tar.gz +d4712a348f65dcaf9f6c58f1cfd6d0984d54a902873dca5e76f0d686f5c59499 golangci-lint-1.64.6-linux-mips64le.deb +57cea4538894558cb8c956d6b69c5509e4304546abe4a467478fc9ada0c736d6 golangci-lint-1.64.6-linux-mips64le.rpm +bc030977d44535b2152fddb2732f056d193c043992fe638ddecea21a40ef09fe golangci-lint-1.64.6-linux-mips64le.tar.gz +1ceb4e492efa527d246c61798c581f49113756fab8c39bb3eefdb1fa97041f92 golangci-lint-1.64.6-linux-ppc64le.deb +454e1c2b3583a8644e0c33a970fb4ce35b8f11848e1a770d9095d99d159ad0ab golangci-lint-1.64.6-linux-ppc64le.rpm +fddf30d35923eb6c7bb57520d8645768f802bf86c4cbf5a3a13049efb9e71b82 golangci-lint-1.64.6-linux-ppc64le.tar.gz +bd75f0dd6f65bee5821c433803b28f3c427ef3582764c3d0e7f7fae1c9d468b6 golangci-lint-1.64.6-linux-riscv64.deb +58457207c225cbd5340c8dcb75d9a44aa890d604e28464115a3a9762febaed04 golangci-lint-1.64.6-linux-riscv64.rpm +82639518a613a6705b7e2de5b28c278e875d782a5c97e9c1b2ac10b4ecd7852f golangci-lint-1.64.6-linux-riscv64.tar.gz +131d69204f8ced200b1437731e987cc886edac30dc87e6e1dcbd4f833d351713 golangci-lint-1.64.6-linux-s390x.deb +ca6caf28ca7a1df7cff720f8fd6ac4b8f2eac10c8cbfe7d2eade70876aded570 golangci-lint-1.64.6-linux-s390x.rpm +ed966d28a6512bc2b1120029a9f78ed77f2015e330b589a731d67d59be30b0b1 golangci-lint-1.64.6-linux-s390x.tar.gz +b181132b41943fc77ace7f9f5523085d12d3613f27774a0e35e17dd5e65ba589 golangci-lint-1.64.6-netbsd-386.tar.gz +f7b81c426006e3c699dc8665797a462aecba8c2cd23ac4971472e55184d95bc9 golangci-lint-1.64.6-netbsd-amd64.tar.gz +663d6fb4c3bef57b8aacdb1b1a4634075e55d294ed170724b443374860897ca6 golangci-lint-1.64.6-netbsd-arm64.tar.gz +8c7a76ee822568cc19352bbb9b2b0863dc5e185eb07782adbbaf648afd02ebcd golangci-lint-1.64.6-netbsd-armv6.tar.gz +0ce26d56ce78e516529e087118ba3f1bcd71d311b4c5b2bde6ec24a6e8966d85 golangci-lint-1.64.6-netbsd-armv7.tar.gz +135d5d998168683f46e4fab308cef5aa3c282025b7de6b258f976aadfb820db7 golangci-lint-1.64.6-source.tar.gz +ccdb0cc249531a205304a76308cfa7cda830083d083d557884416a2461148263 golangci-lint-1.64.6-windows-386.zip +2d88f282e08e1853c70bc7c914b5f58beaa6509903d56098aeb9bc3df30ea9d5 golangci-lint-1.64.6-windows-amd64.zip +6a3c6e7afc6916392679d7d6b95ac239827644e3e50ec4e8ca6ab1e4e6db65fe golangci-lint-1.64.6-windows-arm64.zip +9c9c1ef9687651566987f93e76252f7526c386901d7d8aeee044ca88115da4b1 golangci-lint-1.64.6-windows-armv6.zip +4f0df114155791799dfde8cd8cb6307fecfb17fed70b44205486ec925e2f39cf golangci-lint-1.64.6-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # From 7e407af6d8fc94643704e823ff0ced37de4326ff Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 5 Mar 2025 11:04:24 +0100 Subject: [PATCH 187/354] core: match on deposit contract log topic (#31317) This resolves a situation on the Sepolia testnet, which has a different deposit contract. The contract on that network emits two kinds of logs, instead of only deposit events like the deposit contract on mainnet. So we need to skip events with mismatched topics. --- core/state_processor.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/state_processor.go b/core/state_processor.go index 4708dddc9..132366d58 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -323,12 +323,14 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte *requests = append(*requests, requestsData) } +var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5") + // ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by // BeaconDepositContract. func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error { deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type) for _, log := range logs { - if log.Address == config.DepositContractAddress { + if log.Address == config.DepositContractAddress && len(log.Topics) > 0 && log.Topics[0] == depositTopic { request, err := types.DepositLogToRequest(log.Data) if err != nil { return fmt.Errorf("unable to parse deposit data: %v", err) From a09eacbae171c5fc1520feabbd5ca74d87bdbe79 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Wed, 5 Mar 2025 19:51:53 +0800 Subject: [PATCH 188/354] build: fix execution-spec-tests sanitycheck URL (#31314) --- build/checksums.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/checksums.txt b/build/checksums.txt index 06e44ea2b..5ccb85bba 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -2,7 +2,7 @@ # version:spec-tests pectra-devnet-6@v1.0.0 # https://github.com/ethereum/execution-spec-tests/releases -# https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/fixtures_pectra-devnet-6.tar.gz +# https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/ b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz # version:golang 1.24.1 From 73c9b2cf279543ead5eca828bc2bc04cfdb57b39 Mon Sep 17 00:00:00 2001 From: Delweng Date: Fri, 7 Mar 2025 18:23:19 +0800 Subject: [PATCH 189/354] core/rawdb,state: add preimage miss metric (#31295) 1. The metric of preimage/hits are always the same as preimage/total, prefer to replace the hits with miss instead. 2. For the state/read/accounts metric, follow the same naming of others, change into singuar. --- core/rawdb/accessors_state.go | 6 +++++- core/rawdb/schema.go | 5 +++-- core/state/metrics.go | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 9ce58e7d2..adc77fae8 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -27,6 +27,11 @@ import ( // ReadPreimage retrieves a single preimage of the provided hash. func ReadPreimage(db ethdb.KeyValueReader, hash common.Hash) []byte { data, _ := db.Get(preimageKey(hash)) + if len(data) == 0 { + preimageMissCounter.Inc(1) + } else { + preimageHitsCounter.Inc(1) + } return data } @@ -38,7 +43,6 @@ func WritePreimages(db ethdb.KeyValueWriter, preimages map[common.Hash][]byte) { } } preimageCounter.Inc(int64(len(preimages))) - preimageHitCounter.Inc(int64(len(preimages))) } // ReadCode retrieves the contract code of the provided code hash. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 04b5d0d6d..17aa9e280 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -145,8 +145,9 @@ var ( FixedCommitteeRootKey = []byte("fixedRoot-") // bigEndian64(syncPeriod) -> committee root hash SyncCommitteeKey = []byte("committee-") // bigEndian64(syncPeriod) -> serialized committee - preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) - preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) + preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) + preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) ) // LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary diff --git a/core/state/metrics.go b/core/state/metrics.go index fb45bc4b8..dd4b2e983 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,7 +19,7 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( - accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil) + accountReadMeters = metrics.NewRegisteredMeter("state/read/account", nil) storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil) accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) From e7b14c5045e292a50532b96ad1f394056bd9d784 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 10 Mar 2025 14:10:16 +0100 Subject: [PATCH 190/354] cmd,eth,les: replace Cancun override flag with Prague (#31341) It's that time of the cycle, should have this ready to go for mainnet Prague release. --- cmd/geth/chaincmd.go | 8 ++++---- cmd/geth/config.go | 6 +++--- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 6 +++--- core/genesis.go | 6 +++--- eth/backend.go | 4 ++-- eth/ethconfig/config.go | 4 ++-- eth/ethconfig/gen_config.go | 10 +++++----- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index bbadb1cc1..eb0dda095 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -50,7 +50,7 @@ var ( ArgsUsage: "", Flags: slices.Concat([]cli.Flag{ utils.CachePreimagesFlag, - utils.OverrideCancun, + utils.OverridePrague, utils.OverrideVerkle, }, utils.DatabaseFlags), Description: ` @@ -212,9 +212,9 @@ func initGenesis(ctx *cli.Context) error { defer stack.Close() var overrides core.ChainOverrides - if ctx.IsSet(utils.OverrideCancun.Name) { - v := ctx.Uint64(utils.OverrideCancun.Name) - overrides.OverrideCancun = &v + if ctx.IsSet(utils.OverridePrague.Name) { + v := ctx.Uint64(utils.OverridePrague.Name) + overrides.OverridePrague = &v } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 9b1f2d0c7..0d8b6f03c 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -184,9 +184,9 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.IsSet(utils.OverrideCancun.Name) { - v := ctx.Uint64(utils.OverrideCancun.Name) - cfg.Eth.OverrideCancun = &v + if ctx.IsSet(utils.OverridePrague.Name) { + v := ctx.Uint64(utils.OverridePrague.Name) + cfg.Eth.OverridePrague = &v } if ctx.IsSet(utils.OverrideVerkle.Name) { v := ctx.Uint64(utils.OverrideVerkle.Name) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d9a37e99e..8c596731a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -68,7 +68,7 @@ var ( utils.NoUSBFlag, // deprecated utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideCancun, + utils.OverridePrague, utils.OverrideVerkle, utils.EnablePersonal, // deprecated utils.TxPoolLocalsFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index dd7c4eac1..173bb6626 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -234,9 +234,9 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverrideCancun = &cli.Uint64Flag{ - Name: "override.cancun", - Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting", + OverridePrague = &cli.Uint64Flag{ + Name: "override.prague", + Usage: "Manually specify the Prague fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } OverrideVerkle = &cli.Uint64Flag{ diff --git a/core/genesis.go b/core/genesis.go index edc270ff5..cbe50751d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -258,7 +258,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { - OverrideCancun *uint64 + OverridePrague *uint64 OverrideVerkle *uint64 } @@ -267,8 +267,8 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error { if o == nil || cfg == nil { return nil } - if o.OverrideCancun != nil { - cfg.CancunTime = o.OverrideCancun + if o.OverridePrague != nil { + cfg.PragueTime = o.OverridePrague } if o.OverrideVerkle != nil { cfg.VerkleTime = o.OverrideVerkle diff --git a/eth/backend.go b/eth/backend.go index 91397017e..1ec153db5 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -229,8 +229,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // Override the chain config with provided settings. var overrides core.ChainOverrides - if config.OverrideCancun != nil { - overrides.OverrideCancun = config.OverrideCancun + if config.OverridePrague != nil { + overrides.OverridePrague = config.OverridePrague } if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index ad681f688..0de8f3ca2 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -150,8 +150,8 @@ type Config struct { // send-transaction variants. The unit is ether. RPCTxFeeCap float64 - // OverrideCancun (TODO: remove after the fork) - OverrideCancun *uint64 `toml:",omitempty"` + // OverridePrague (TODO: remove after the fork) + OverridePrague *uint64 `toml:",omitempty"` // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 0ec0eadde..84aea7cd1 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -49,7 +49,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap uint64 RPCEVMTimeout time.Duration RPCTxFeeCap float64 - OverrideCancun *uint64 `toml:",omitempty"` + OverridePrague *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` } var enc Config @@ -85,7 +85,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCGasCap = c.RPCGasCap enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCTxFeeCap = c.RPCTxFeeCap - enc.OverrideCancun = c.OverrideCancun + enc.OverridePrague = c.OverridePrague enc.OverrideVerkle = c.OverrideVerkle return &enc, nil } @@ -125,7 +125,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - OverrideCancun *uint64 `toml:",omitempty"` + OverridePrague *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"` } var dec Config @@ -228,8 +228,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RPCTxFeeCap != nil { c.RPCTxFeeCap = *dec.RPCTxFeeCap } - if dec.OverrideCancun != nil { - c.OverrideCancun = dec.OverrideCancun + if dec.OverridePrague != nil { + c.OverridePrague = dec.OverridePrague } if dec.OverrideVerkle != nil { c.OverrideVerkle = dec.OverrideVerkle From d1736e7edef05fa929b78fbd43e973111323bc1c Mon Sep 17 00:00:00 2001 From: Austin Larson <78000745+alarso16@users.noreply.github.com> Date: Tue, 11 Mar 2025 11:00:50 -0400 Subject: [PATCH 191/354] core/txpool: demote error log to warn (#31332) This error log in `legacypool.go` isn't necessary, since even though the behavior is unexpected, it is handled correctly. A discussion on issue #22301 concluded that this should instead be a warning log. --- core/txpool/legacypool/legacypool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 6bbaed7f5..b9291e074 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1729,7 +1729,7 @@ func (pool *LegacyPool) demoteUnexecutables() { gapped := list.Cap(0) for _, tx := range gapped { hash := tx.Hash() - log.Error("Demoting invalidated transaction", "hash", hash) + log.Warn("Demoting invalidated transaction", "hash", hash) // Internal shuffle shouldn't touch the lookup set. pool.enqueueTx(hash, tx, false) From 567d3f224262e58067bbb97c8531c389679e04ae Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 11 Mar 2025 16:15:07 +0100 Subject: [PATCH 192/354] core: prefund pectra precompiles in developer genesis (#31342) Prefund the precompile addresses for the new precompiles in the developer genesis block. --- core/genesis.go | 26 +++++++++++++++++--------- miner/worker.go | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index cbe50751d..edbad8a10 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -712,15 +712,23 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { BaseFee: big.NewInt(params.InitialBaseFee), Difficulty: big.NewInt(0), Alloc: map[common.Address]types.Account{ - common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover - common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 - common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD - common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity - common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp - common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd - common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul - common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing - common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b + common.BytesToAddress([]byte{0x01}): {Balance: big.NewInt(1)}, // ECRecover + common.BytesToAddress([]byte{0x02}): {Balance: big.NewInt(1)}, // SHA256 + common.BytesToAddress([]byte{0x03}): {Balance: big.NewInt(1)}, // RIPEMD + common.BytesToAddress([]byte{0x04}): {Balance: big.NewInt(1)}, // Identity + common.BytesToAddress([]byte{0x05}): {Balance: big.NewInt(1)}, // ModExp + common.BytesToAddress([]byte{0x06}): {Balance: big.NewInt(1)}, // ECAdd + common.BytesToAddress([]byte{0x07}): {Balance: big.NewInt(1)}, // ECScalarMul + common.BytesToAddress([]byte{0x08}): {Balance: big.NewInt(1)}, // ECPairing + common.BytesToAddress([]byte{0x09}): {Balance: big.NewInt(1)}, // BLAKE2b + common.BytesToAddress([]byte{0x0a}): {Balance: big.NewInt(1)}, // KZGPointEval + common.BytesToAddress([]byte{0x0b}): {Balance: big.NewInt(1)}, // BLSG1Add + common.BytesToAddress([]byte{0x0c}): {Balance: big.NewInt(1)}, // BLSG1MultiExp + common.BytesToAddress([]byte{0x0d}): {Balance: big.NewInt(1)}, // BLSG2Add + common.BytesToAddress([]byte{0x0e}): {Balance: big.NewInt(1)}, // BLSG2MultiExp + common.BytesToAddress([]byte{0x0f}): {Balance: big.NewInt(1)}, // BLSG1Pairing + common.BytesToAddress([]byte{0x10}): {Balance: big.NewInt(1)}, // BLSG1MapG1 + common.BytesToAddress([]byte{0x11}): {Balance: big.NewInt(1)}, // BLSG2MapG2 // Pre-deploy system contracts params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, diff --git a/miner/worker.go b/miner/worker.go index 879019df4..e24cfb1cd 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1312,6 +1312,7 @@ func totalFees(block *types.Block, receipts []*types.Receipt) *big.Int { for i, tx := range block.Transactions() { minerFee, _ := tx.EffectiveGasTip(block.BaseFee()) feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), minerFee)) + // TODO (MariusVanDerWijden) add blob fees } return feesWei } From 0c9e3382dd231e2fc879cd00e959a9adba15599b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 11 Mar 2025 17:17:47 +0100 Subject: [PATCH 193/354] beacon/types, beacon/blsync: update for electra (#31243) This updates the blsync base types for the Electra fork. I've been testing, and it doesn't seem to make blsync fully work on Electra. But I'd still like to get this in to make some progress. --------- Co-authored-by: Zsolt Felfoldi --- beacon/blsync/block_sync.go | 7 +- beacon/blsync/engineclient.go | 7 +- beacon/light/api/light_api.go | 14 +- beacon/light/test_helpers.go | 8 +- beacon/params/networks.go | 6 +- beacon/params/params.go | 52 ++- beacon/types/beacon_block.go | 63 +++- beacon/types/beacon_block_test.go | 21 ++ beacon/types/exec_header.go | 8 +- beacon/types/exec_payload.go | 7 +- beacon/types/light_sync.go | 18 +- .../block_electra_consolidations.json | 194 +++++++++++ .../testdata/block_electra_deposits.json | 305 ++++++++++++++++++ .../testdata/block_electra_withdrawals.json | 232 +++++++++++++ go.mod | 2 +- go.sum | 4 +- 16 files changed, 899 insertions(+), 49 deletions(-) create mode 100644 beacon/types/testdata/block_electra_consolidations.json create mode 100644 beacon/types/testdata/block_electra_deposits.json create mode 100644 beacon/types/testdata/block_electra_withdrawals.json diff --git a/beacon/blsync/block_sync.go b/beacon/blsync/block_sync.go index ff689a922..a6252a55f 100755 --- a/beacon/blsync/block_sync.go +++ b/beacon/blsync/block_sync.go @@ -156,8 +156,9 @@ func (s *beaconBlockSync) updateEventFeed() { return } s.chainHeadFeed.Send(types.ChainHeadEvent{ - BeaconHead: optimistic.Attested.Header, - Block: execBlock, - Finalized: finalizedHash, + BeaconHead: optimistic.Attested.Header, + Block: execBlock, + ExecRequests: headBlock.ExecutionRequestsList(), + Finalized: finalizedHash, }) } diff --git a/beacon/blsync/engineclient.go b/beacon/blsync/engineclient.go index c6569fdbd..77bee83f5 100644 --- a/beacon/blsync/engineclient.go +++ b/beacon/blsync/engineclient.go @@ -100,6 +100,11 @@ func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) params = []any{execData} ) switch fork { + case "electra": + method = "engine_newPayloadV4" + parentBeaconRoot := event.BeaconHead.ParentRoot + blobHashes := collectBlobHashes(event.Block) + params = append(params, blobHashes, parentBeaconRoot, event.ExecRequests) case "deneb": method = "engine_newPayloadV3" parentBeaconRoot := event.BeaconHead.ParentRoot @@ -135,7 +140,7 @@ func (ec *engineClient) callForkchoiceUpdated(fork string, event types.ChainHead var method string switch fork { - case "deneb": + case "deneb", "electra": method = "engine_forkchoiceUpdatedV3" case "capella": method = "engine_forkchoiceUpdatedV2" diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 91f66c08b..f9a5aae15 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -43,7 +43,6 @@ var ( ) type CommitteeUpdate struct { - Version string Update types.LightClientUpdate NextSyncCommittee types.SerializedSyncCommittee } @@ -81,9 +80,9 @@ func (u *CommitteeUpdate) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - u.Version = dec.Version u.NextSyncCommittee = dec.Data.NextSyncCommittee u.Update = types.LightClientUpdate{ + Version: dec.Version, AttestedHeader: types.SignedHeader{ Header: dec.Data.Header.Beacon, Signature: dec.Data.SyncAggregate, @@ -206,7 +205,7 @@ func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) { var data struct { - Version string + Version string `json:"version"` Data struct { Attested jsonHeaderWithExecProof `json:"attested_header"` Aggregate types.SyncAggregate `json:"sync_aggregate"` @@ -259,7 +258,7 @@ func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) { func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { var data struct { - Version string + Version string `json:"version"` Data struct { Attested jsonHeaderWithExecProof `json:"attested_header"` Finalized jsonHeaderWithExecProof `json:"finalized_header"` @@ -289,6 +288,7 @@ func decodeFinalityUpdate(enc []byte) (types.FinalityUpdate, error) { } return types.FinalityUpdate{ + Version: data.Version, Attested: types.HeaderWithExecProof{ Header: data.Data.Attested.Beacon, PayloadHeader: attestedExecHeader, @@ -355,7 +355,8 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientbootstrap type bootstrapData struct { - Data struct { + Version string `json:"version"` + Data struct { Header jsonBeaconHeader `json:"header"` Committee *types.SerializedSyncCommittee `json:"current_sync_committee"` CommitteeBranch merkle.Values `json:"current_sync_committee_branch"` @@ -374,6 +375,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types return nil, fmt.Errorf("invalid checkpoint block header, have %v want %v", header.Hash(), checkpointHash) } checkpoint := &types.BootstrapData{ + Version: data.Version, Header: header, CommitteeBranch: data.Data.CommitteeBranch, CommitteeRoot: data.Data.Committee.Root(), @@ -395,7 +397,7 @@ func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconB } var beaconBlockMessage struct { - Version string + Version string `json:"version"` Data struct { Message json.RawMessage `json:"message"` } diff --git a/beacon/light/test_helpers.go b/beacon/light/test_helpers.go index 7bd19ca0a..50e554b3d 100644 --- a/beacon/light/test_helpers.go +++ b/beacon/light/test_helpers.go @@ -39,10 +39,10 @@ func GenerateTestUpdate(config *params.ChainConfig, period uint64, committee, ne var attestedHeader types.Header if finalizedHeader { update.FinalizedHeader = new(types.Header) - *update.FinalizedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+100, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot)) - attestedHeader, update.FinalityBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexFinalBlock, merkle.Value(update.FinalizedHeader.Hash())) + *update.FinalizedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+100, params.StateIndexNextSyncCommittee(""), merkle.Value(update.NextSyncCommitteeRoot)) + attestedHeader, update.FinalityBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexFinalBlock(""), merkle.Value(update.FinalizedHeader.Hash())) } else { - attestedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+2000, params.StateIndexNextSyncCommittee, merkle.Value(update.NextSyncCommitteeRoot)) + attestedHeader, update.NextSyncCommitteeBranch = makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+2000, params.StateIndexNextSyncCommittee(""), merkle.Value(update.NextSyncCommitteeRoot)) } update.AttestedHeader = GenerateTestSignedHeader(attestedHeader, config, committee, attestedHeader.Slot+1, signerCount) return update @@ -63,7 +63,7 @@ func GenerateTestSignedHeader(header types.Header, config *params.ChainConfig, c } func GenerateTestCheckpoint(period uint64, committee *types.SerializedSyncCommittee) *types.BootstrapData { - header, branch := makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexSyncCommittee, merkle.Value(committee.Root())) + header, branch := makeTestHeaderWithMerkleProof(types.SyncPeriodStart(period)+200, params.StateIndexSyncCommittee(""), merkle.Value(committee.Root())) return &types.BootstrapData{ Header: header, Committee: committee, diff --git a/beacon/params/networks.go b/beacon/params/networks.go index 1204e0176..eda225e0f 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -41,7 +41,8 @@ var ( AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}). AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}). AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}). - AddFork("DENEB", 132608, []byte{144, 0, 0, 115}) + AddFork("DENEB", 132608, []byte{144, 0, 0, 115}). + AddFork("ELECTRA", 222464, []byte{144, 0, 0, 116}) HoleskyLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"), @@ -52,5 +53,6 @@ var ( AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}). AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}). AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}). - AddFork("DENEB", 29696, []byte{5, 1, 112, 0}) + AddFork("DENEB", 29696, []byte{5, 1, 112, 0}). + AddFork("ELECTRA", 115968, []byte{6, 1, 112, 0}) ) diff --git a/beacon/params/params.go b/beacon/params/params.go index e4e0d0093..c6600cee5 100644 --- a/beacon/params/params.go +++ b/beacon/params/params.go @@ -29,18 +29,46 @@ const ( ) const ( - StateIndexGenesisTime = 32 - StateIndexGenesisValidators = 33 - StateIndexForkVersion = 141 - StateIndexLatestHeader = 36 - StateIndexBlockRoots = 37 - StateIndexStateRoots = 38 - StateIndexHistoricRoots = 39 - StateIndexFinalBlock = 105 - StateIndexSyncCommittee = 54 - StateIndexNextSyncCommittee = 55 - StateIndexExecPayload = 56 - StateIndexExecHead = 908 + StateIndexGenesisTime = 32 + StateIndexGenesisValidators = 33 + StateIndexForkVersion = 141 + StateIndexLatestHeader = 36 + StateIndexBlockRoots = 37 + StateIndexStateRoots = 38 + StateIndexHistoricRoots = 39 + StateIndexFinalBlockOld = 105 + StateIndexFinalBlockElectra = 169 + StateIndexSyncCommitteeOld = 54 + StateIndexSyncCommitteeElectra = 86 + StateIndexNextSyncCommitteeOld = 55 + StateIndexNextSyncCommitteeElectra = 87 + StateIndexExecPayload = 56 + StateIndexExecHead = 908 BodyIndexExecPayload = 25 ) + +func StateIndexFinalBlock(forkName string) uint64 { + switch forkName { + case "bellatrix", "capella", "deneb": + return StateIndexFinalBlockOld + default: + return StateIndexFinalBlockElectra + } +} +func StateIndexSyncCommittee(forkName string) uint64 { + switch forkName { + case "bellatrix", "capella", "deneb": + return StateIndexSyncCommitteeOld + default: + return StateIndexSyncCommitteeElectra + } +} +func StateIndexNextSyncCommittee(forkName string) uint64 { + switch forkName { + case "bellatrix", "capella", "deneb": + return StateIndexNextSyncCommitteeOld + default: + return StateIndexNextSyncCommitteeElectra + } +} diff --git a/beacon/types/beacon_block.go b/beacon/types/beacon_block.go index e4cd1340e..a2e31d5ab 100644 --- a/beacon/types/beacon_block.go +++ b/beacon/types/beacon_block.go @@ -17,16 +17,21 @@ package types import ( + "bytes" "encoding/json" "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/protolambda/zrnt/eth2/beacon/capella" zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/zrnt/eth2/beacon/deneb" "github.com/protolambda/zrnt/eth2/configs" + "github.com/protolambda/ztyp/codec" "github.com/protolambda/ztyp/tree" + + // beacon forks + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/zrnt/eth2/beacon/deneb" + "github.com/protolambda/zrnt/eth2/beacon/electra" ) type blockObject interface { @@ -43,10 +48,12 @@ type BeaconBlock struct { func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) { var obj blockObject switch forkName { - case "deneb": - obj = new(deneb.BeaconBlock) case "capella": obj = new(capella.BeaconBlock) + case "deneb": + obj = new(deneb.BeaconBlock) + case "electra": + obj = new(electra.BeaconBlock) default: return nil, fmt.Errorf("unsupported fork: %s", forkName) } @@ -63,6 +70,8 @@ func NewBeaconBlock(obj blockObject) *BeaconBlock { return &BeaconBlock{obj} case *deneb.BeaconBlock: return &BeaconBlock{obj} + case *electra.BeaconBlock: + return &BeaconBlock{obj} default: panic(fmt.Errorf("unsupported block type %T", obj)) } @@ -75,6 +84,8 @@ func (b *BeaconBlock) Slot() uint64 { return uint64(obj.Slot) case *deneb.BeaconBlock: return uint64(obj.Slot) + case *electra.BeaconBlock: + return uint64(obj.Slot) default: panic(fmt.Errorf("unsupported block type %T", b.blockObj)) } @@ -84,9 +95,12 @@ func (b *BeaconBlock) Slot() uint64 { func (b *BeaconBlock) ExecutionPayload() (*types.Block, error) { switch obj := b.blockObj.(type) { case *capella.BeaconBlock: - return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot) + return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, nil) case *deneb.BeaconBlock: - return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot) + return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, nil) + case *electra.BeaconBlock: + requests := b.ExecutionRequestsList() + return convertPayload(&obj.Body.ExecutionPayload, &obj.ParentRoot, requests) default: panic(fmt.Errorf("unsupported block type %T", b.blockObj)) } @@ -99,6 +113,8 @@ func (b *BeaconBlock) Header() Header { return headerFromZRNT(obj.Header(configs.Mainnet)) case *deneb.BeaconBlock: return headerFromZRNT(obj.Header(configs.Mainnet)) + case *electra.BeaconBlock: + return headerFromZRNT(obj.Header(configs.Mainnet)) default: panic(fmt.Errorf("unsupported block type %T", b.blockObj)) } @@ -108,3 +124,38 @@ func (b *BeaconBlock) Header() Header { func (b *BeaconBlock) Root() common.Hash { return common.Hash(b.blockObj.HashTreeRoot(configs.Mainnet, tree.GetHashFn())) } + +// ExecutionRequestsList returns the execution layer requests of the block. +func (b *BeaconBlock) ExecutionRequestsList() [][]byte { + switch obj := b.blockObj.(type) { + case *capella.BeaconBlock, *deneb.BeaconBlock: + return nil + case *electra.BeaconBlock: + r := obj.Body.ExecutionRequests + return marshalRequests(configs.Mainnet, + &r.Deposits, + &r.Withdrawals, + &r.Consolidations, + ) + default: + panic(fmt.Errorf("unsupported block type %T", b.blockObj)) + } +} + +func marshalRequests(spec *zrntcommon.Spec, items ...zrntcommon.SpecObj) (list [][]byte) { + var buf bytes.Buffer + list = [][]byte{} + for typ, data := range items { + buf.Reset() + buf.WriteByte(byte(typ)) + w := codec.NewEncodingWriter(&buf) + if err := data.Serialize(spec, w); err != nil { + panic(err) + } + if buf.Len() == 1 { + continue // skip empty requests + } + list = append(list, bytes.Clone(buf.Bytes())) + } + return list +} diff --git a/beacon/types/beacon_block_test.go b/beacon/types/beacon_block_test.go index d5920e805..05aeeaaa1 100644 --- a/beacon/types/beacon_block_test.go +++ b/beacon/types/beacon_block_test.go @@ -33,6 +33,27 @@ func TestBlockFromJSON(t *testing.T) { wantBlockHash common.Hash } tests := []blocktest{ + { + file: "block_electra_withdrawals.json", + version: "electra", + wantSlot: 151850, + wantBlockNumber: 141654, + wantBlockHash: common.HexToHash("0xf6730485a38be5ada3e110990a2c7adaabd2e8d4a49782134f1a8bfbc246a5d7"), + }, + { + file: "block_electra_deposits.json", + version: "electra", + wantSlot: 151016, + wantBlockNumber: 140858, + wantBlockHash: common.HexToHash("0x1f2637170986346c7993d5adbadbebbf4c9ed89c6a4d2dff653db99c8c168076"), + }, + { + file: "block_electra_consolidations.json", + version: "electra", + wantSlot: 151717, + wantBlockNumber: 141529, + wantBlockHash: common.HexToHash("0xc8807f7a1f96b0a073ff27065776dd21eff6b7e64079c60bffd33f690efbb330"), + }, { file: "block_deneb.json", version: "deneb", diff --git a/beacon/types/exec_header.go b/beacon/types/exec_header.go index b5f90bae2..ae79b0084 100644 --- a/beacon/types/exec_header.go +++ b/beacon/types/exec_header.go @@ -22,10 +22,12 @@ import ( "github.com/ethereum/go-ethereum/beacon/merkle" "github.com/ethereum/go-ethereum/common" - "github.com/protolambda/zrnt/eth2/beacon/capella" zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" - "github.com/protolambda/zrnt/eth2/beacon/deneb" "github.com/protolambda/ztyp/tree" + + // beacon chain forks + "github.com/protolambda/zrnt/eth2/beacon/capella" + "github.com/protolambda/zrnt/eth2/beacon/deneb" ) type headerObject interface { @@ -43,7 +45,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er switch forkName { case "capella": obj = new(capella.ExecutionPayloadHeader) - case "deneb": + case "deneb", "electra": // note: the payload type was not changed in electra obj = new(deneb.ExecutionPayloadHeader) default: return nil, fmt.Errorf("unsupported fork: %s", forkName) diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go index b159687df..7b81f2fbf 100644 --- a/beacon/types/exec_payload.go +++ b/beacon/types/exec_payload.go @@ -34,7 +34,7 @@ type payloadType interface { } // convertPayload converts a beacon chain execution payload to types.Block. -func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*types.Block, error) { +func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root, requests [][]byte) (*types.Block, error) { var ( header types.Header transactions []*types.Transaction @@ -62,7 +62,10 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ default: panic("unsupported block type") } - + if requests != nil { + reqHash := types.CalcRequestsHash(requests) + header.RequestsHash = &reqHash + } block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals}) if hash := block.Hash(); hash != expectedHash { return nil, fmt.Errorf("sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) diff --git a/beacon/types/light_sync.go b/beacon/types/light_sync.go index 3e9b13d0e..128ee77f1 100644 --- a/beacon/types/light_sync.go +++ b/beacon/types/light_sync.go @@ -36,6 +36,7 @@ type HeadInfo struct { // together with a proof through a beacon header and corresponding state. // Note: BootstrapData is fetched from a server based on a known checkpoint hash. type BootstrapData struct { + Version string Header Header CommitteeRoot common.Hash Committee *SerializedSyncCommittee `rlp:"-"` @@ -47,7 +48,7 @@ func (c *BootstrapData) Validate() error { if c.CommitteeRoot != c.Committee.Root() { return errors.New("wrong committee root") } - return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot)) + return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee(c.Version), c.CommitteeBranch, merkle.Value(c.CommitteeRoot)) } // LightClientUpdate is a proof of the next sync committee root based on a header @@ -59,6 +60,7 @@ func (c *BootstrapData) Validate() error { // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate type LightClientUpdate struct { + Version string AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee @@ -79,11 +81,11 @@ func (update *LightClientUpdate) Validate() error { if update.FinalizedHeader.SyncPeriod() != period { return errors.New("finalized header is from different period") } - if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock(update.Version), update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil { return fmt.Errorf("invalid finalized header proof: %w", err) } } - if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { + if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee(update.Version), update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil { return fmt.Errorf("invalid next sync committee proof: %w", err) } return nil @@ -194,6 +196,7 @@ func (u *OptimisticUpdate) Validate() error { // See data structure definition here: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate type FinalityUpdate struct { + Version string Attested, Finalized HeaderWithExecProof FinalityBranch merkle.Values // Sync committee BLS signature aggregate @@ -223,14 +226,15 @@ func (u *FinalityUpdate) Validate() error { if err := u.Finalized.Validate(); err != nil { return err } - return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock, u.FinalityBranch, merkle.Value(u.Finalized.Hash())) + return merkle.VerifyProof(u.Attested.StateRoot, params.StateIndexFinalBlock(u.Version), u.FinalityBranch, merkle.Value(u.Finalized.Hash())) } // ChainHeadEvent returns an authenticated execution payload associated with the // latest accepted head of the beacon chain, along with the hash of the latest // finalized execution block. type ChainHeadEvent struct { - BeaconHead Header - Block *ctypes.Block - Finalized common.Hash + BeaconHead Header + Block *ctypes.Block + ExecRequests [][]byte // execution layer requests (added in Electra) + Finalized common.Hash // latest finalized block hash } diff --git a/beacon/types/testdata/block_electra_consolidations.json b/beacon/types/testdata/block_electra_consolidations.json new file mode 100644 index 000000000..421b55422 --- /dev/null +++ b/beacon/types/testdata/block_electra_consolidations.json @@ -0,0 +1,194 @@ +{ + "slot": "151717", + "proposer_index": "20165", + "parent_root": "0x0b968237e4cd877e1b5f146da849d5a228cba9b9020c10095cdf177ff0cbdca9", + "state_root": "0xc99af23f66c2b3c964b5301f314ffae1add20b1d88b3a9d8a95c72110b06b2fd", + "body": { + "randao_reveal": "0x81126bf1b4491dd0906c2d82615b34b8d3f779096bcf0a5f0ddda2a6da2b6c1858d3359a0b70cf66af69fc649bf6683e0520b3b14edcde3d6bd75b394d0812c5fd232350e6e3b5e9e6b262219c788ca2e74fa15a1e02e034b091d6c694aaeccd", + "eth1_data": { + "deposit_root": "0x8654042dec994aa6fc1a36fd0f4ebb2a49d1b27ada9460b045e2ea2a15718cc2", + "deposit_count": "10010", + "block_hash": "0xb358182abdc706e4a7ca709816043ebb23f3d93e943ca0becdfb9202abecd2d3" + }, + "graffiti": "0x6c69676874686f7573652d676574682d33000000000000000000000000000000", + "proposer_slashings": [], + "attester_slashings": [], + "attestations": [ + { + "aggregation_bits": "0xfefffffffffff7ffbfefffdff7ff77ffffffffffdfe7ffffffffbfffffff7fbfffeffffffffffffffffffffffffffffffbffffffffffeffffeffffffffffeffffffbfffbfffffffffffffffffebfffffffff7ffffffdffffffffffffffffffffffffbfff7fffffffffffffffffffffefffffffffff7ffffffffeffffffffffffff7fffeffffffdfffffffff7ff7fffff7bffffffffbfffffffffffffdfff7ffffffffeffffffffffffffffffffdffffbffffffffffffff7ff6fffffffffffffffffffffffffffffefffff7fffefffeffffdffbffffff3fffdfdfbfffffffffffffffffdffdfffffffffffffffffffffff7ffffffffeffd7ffffffffffffffffffbff7ffeffffffffffbfffdfffffffffffffffffffff7fff0f", + "data": { + "slot": "151716", + "index": "0", + "beacon_block_root": "0x0b968237e4cd877e1b5f146da849d5a228cba9b9020c10095cdf177ff0cbdca9", + "source": { + "epoch": "4740", + "root": "0x75198e06e7a0fe301a524212e6376d2222e421fb3cfd1ef0dcb637bf6d20deac" + }, + "target": { + "epoch": "4741", + "root": "0x8bb6fe4f7ea104312914c88ac84534e4da2ff8207790060f4ba903aaf231678e" + } + }, + "signature": "0x9138d56149037ae150d8c544c8b609a250fe5e3d66cb36e5d2dd618a642dd79bfa45ec1da014f24872410ddf9ecba28907bec2ea0e5581694871746fbeba9c4e5a553725b03feba05272a11a327b02bae60da8144d333eb019568cf64eb8a43d", + "committee_bits": "0xffff010000000000" + }, + { + "aggregation_bits": "0xbdfffffffdffffffffffffffffffefffffffffffffffffffffffbffffffffffffffffffffffffffbffffdfffffffbfffffffffffffffffff7efffffffffffffffffffdffffffffff7ffffff3fffffffffffffbfdffff7ff7ffffffffffffffff7fffdffffffffffffdfffffffffffffffbffffffffffffffffbfffffffffdfffffffffffffffffffffffffffeffeffffffffffefffffffffffffffffffffdfdffefffffffffffffdfffffffffffffffffeffefffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffefffffffdfffffffffffdffffffffffbffffffffffffffeffffffffffd9ffffdfffffffffffffffffffffffffbfffdfffffffffffffffffffffffffdfffffff07", + "data": { + "slot": "151715", + "index": "0", + "beacon_block_root": "0x3fe0c30d4be1a2e83c5109a35fd811fe20f783952199e0d10b485985510edafa", + "source": { + "epoch": "4740", + "root": "0x75198e06e7a0fe301a524212e6376d2222e421fb3cfd1ef0dcb637bf6d20deac" + }, + "target": { + "epoch": "4741", + "root": "0x8bb6fe4f7ea104312914c88ac84534e4da2ff8207790060f4ba903aaf231678e" + } + }, + "signature": "0xb1653ef5666f3ec1ef9ba39036cc6a361b96b3b82ae9ccd6aa7c83c63e358843c054de6022915421360c04ab343b4cee104f2d5d357454f0ca5d86bc24f2524520f27621624c3e78b0e0915a59cd3ba583eb380dbf984265ffe720eef9201b04", + "committee_bits": "0xffff010000000000" + } + ], + "deposits": [], + "voluntary_exits": [], + "sync_aggregate": { + "sync_committee_bits": "0xf7f7fffffffbff6ffffffbfffffffdffffffeff7ffdf7fffffffffffffffffffffffffffffffffffffffffffef777dffffffff7ffeffffebffbf9ffffbffffff", + "sync_committee_signature": "0x99a90d385ef2a1c8d7c8d96bdfc9aa03065532f4415709efbade179de42a8b1c9b736a5d08377c3f9d3a9c220dcd95c61986ba9cc0b735b2c23ac6b8128fc5851e4057c7c469b94ae25c2d0c560793b12021dfb29d34d78e085b8cb8a952f4ba" + }, + "execution_payload": { + "parent_hash": "0xdeab769383aabae234218751c24b5c286c54b7e8545308767217c48ee8a66a03", + "fee_recipient": "0xb9e79d19f651a941757b35830232e7efc77e1c79", + "state_root": "0xb1a9669102c2f7d49af01c4831923cb6f030c6a98b334ecb4d307b6c0c7698a7", + "receipts_root": "0xcd85cea85d138342fef326c1c73eb4fc4479f1fc567e7687c5757c39b5a20c34", + "logs_bloom": "0x00200000000000000000000080000000000000000000100000000000200000000000000000800000000080000000000000000000000010000000000000000000000020000000010001800408000000200000040000000000000000000000000000000000000000000000000000000008000000000000000000000810000040000000000000000000008000000000000000000000000000080000004410000000800000000000000000000000000000000000000001000000000000000000000000000002000000000000000000000000000000000000001000000000000000000000000000000000010200000000000000000000000000000000000000000000", + "prev_randao": "0x1e00579f0d5b1861c9e0978a213dc67e0fc4296458f392e378d06b4b85b4a8c3", + "block_number": "141529", + "gas_limit": "30000000", + "gas_used": "207715", + "timestamp": "1740424464", + "extra_data": "0xf09f90bce29aa1f09fa496", + "base_fee_per_gas": "7", + "block_hash": "0xc8807f7a1f96b0a073ff27065776dd21eff6b7e64079c60bffd33f690efbb330", + "transactions": [ + "0x02f9017b8501a588771083013b2285012a05f2008512a05f2000830249f094d27d57804f09a93989e290cf12cb872c39ad2ad280b901040cc7326300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000005693ed58622afdb000000000000000000000000b3db4f6329df01ac317a70200f6614e1cd0db6f7000000000000000000000000fc7360b3b28cf4204268a8354dbec60720d155d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000d0ada425f6835193b8507d7de3a77ec1bd6c5377000000000000000000000000c8ae6c2d3f6695e41b5cb149beae76600f4ac97dc080a0ee5a62cc99129e5aad3d6b2de4f169dbcfc3b17878bfa9e944879f2899f5d16ba013bc53a251af668e24bfd2157c52a7168e5cbc235cd3615b6f5f733e0bdfc5c2", + "0x02f8d18501a5887710038459682f008459682f0e8301395c940000bbddc7ce488642fb579f8b00f3a59000725101b860aa01b02b16b7a56850cc9b7e1275e8d49e16fc12bd30b4bdf2ef68b5543822b2466101cb541b8815b5ca1721120e4f9da3dc91086418a5680fe3037dba62dda3de79dd22bb41036719c3771f140b419586ae7d9bdf3b10d88850909d4556b19bc001a07ce67cc0fe3ce5e16083414de6c422bbb8d61e2f345b25fc60c8bf58af8a52d3a024b28ae0bae9e75bb588466a4a0ec84d27b4df8127dc58a50cf80b2edc5add54", + "0x02f8708501a58877108219a7800782520894f97e180c050e5ab072211ad2c213eb5aee4df13487025494cb85b9c880c080a08a3568a5f66c85d336f3b98586760753bf3960dc22b5a7edb7551fed54637727a033e49b70c561443b3cccc06e8656e4ac23820f1911800473776d92c0a6014f1b" + ], + "withdrawals": [ + { + "index": "491304", + "validator_index": "71416", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491305", + "validator_index": "71417", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491306", + "validator_index": "71418", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491307", + "validator_index": "71419", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491308", + "validator_index": "71420", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491309", + "validator_index": "71421", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491310", + "validator_index": "71422", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "59212" + }, + { + "index": "491311", + "validator_index": "71423", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491312", + "validator_index": "71424", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "59263" + }, + { + "index": "491313", + "validator_index": "71425", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491314", + "validator_index": "71426", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491315", + "validator_index": "71427", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491316", + "validator_index": "71428", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491317", + "validator_index": "71429", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491318", + "validator_index": "71430", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + }, + { + "index": "491319", + "validator_index": "71431", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "67541" + } + ], + "blob_gas_used": "0", + "excess_blob_gas": "69468160" + }, + "bls_to_execution_changes": [], + "blob_kzg_commitments": [], + "execution_requests": { + "deposits": [], + "withdrawals": [], + "consolidations": [ + { + "source_address": "0xb57a360b34e22c598a9b0da37c5b9a7825da4db6", + "source_pubkey": "0xaa01b02b16b7a56850cc9b7e1275e8d49e16fc12bd30b4bdf2ef68b5543822b2466101cb541b8815b5ca1721120e4f9d", + "target_pubkey": "0xa3dc91086418a5680fe3037dba62dda3de79dd22bb41036719c3771f140b419586ae7d9bdf3b10d88850909d4556b19b" + } + ] + } + } +} diff --git a/beacon/types/testdata/block_electra_deposits.json b/beacon/types/testdata/block_electra_deposits.json new file mode 100644 index 000000000..46dd0a44b --- /dev/null +++ b/beacon/types/testdata/block_electra_deposits.json @@ -0,0 +1,305 @@ +{ + "slot": "151016", + "proposer_index": "27017", + "parent_root": "0x2f135d2fe887c6012e78b25b8adecc33bc268c8057e444422f9fbdbb02730a30", + "state_root": "0x62a65efc3b24c02a29c4fdab5edf076329024a05dfc944b35f920a38d07b24ac", + "body": { + "randao_reveal": "0xb765dc7a976fb26b7cf8df404055cbab5e7665dfc1106ed4373709840d99312fb5f782a44c25294cece2f55e0cde6d1515504693574ddfb9bbcfb47c21763efed46b91cb47cefb5a14c78dd53f491d51e40b36eaf26e23e1edc49875e8c734cc", + "eth1_data": { + "deposit_root": "0x8654042dec994aa6fc1a36fd0f4ebb2a49d1b27ada9460b045e2ea2a15718cc2", + "deposit_count": "10010", + "block_hash": "0x28f59400e7becd79cfe3b14f36dd58fc27826849247dbfd1e4d09448806f8955" + }, + "graffiti": "0x6c69676874686f7573652d6e65746865726d696e642d33000000000000000000", + "proposer_slashings": [], + "attester_slashings": [], + "attestations": [ + { + "aggregation_bits": "0xff7bffdffbffffffffffffefffffffdfffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffff7ff7efffffffffffdfffffffffefffbf7fffffffffffffffdfffffeffffff7ffff7efffffffbfffdffffdfffffffffffbffffbffffffffffffffefffbfefffffffffffffffffffffeffbfffffffffff7fff7bffbfffffffffffffffff7fffffdfffffffffffb7fffffffffffffffffbffffffffffdf7fffffffefbeffffffeffffffff7fffffdfb5dff7fffffffdffefffffffd7ffffeffeffffffffffdfffffffffffffffff5fff7ffffffffffbffffdf7ff77ffff9fffffffffffffffffffff7fcfcffffffffffff7ffffffff7ffffffdffffffffffffffefffffffdfbfffffffffafbfbf7fffdff0f", + "data": { + "slot": "151015", + "index": "0", + "beacon_block_root": "0x2f135d2fe887c6012e78b25b8adecc33bc268c8057e444422f9fbdbb02730a30", + "source": { + "epoch": "4718", + "root": "0x6567f31ab5ccc3a0b0cd5d27abf183ed36704f817d09cb9dbe183da83cf07bf2" + }, + "target": { + "epoch": "4719", + "root": "0x49ce68a9103d485d81d74d0c744a3fde20657c4cb81fb13b12cee75a2a29804f" + } + }, + "signature": "0xb7ad39b499b0e5b8a22849b068c98a08fe611d45a2f43e30fa449e657436e685e9e2a9bfae3a3128baf939f4394c0f2717835b0756e3177cb38d58775618ff6607fb68f362d60b9f865daff0ac239da49690e8fe439aa0dc27e2d4196beac98a", + "committee_bits": "0xffff010000000000" + }, + { + "aggregation_bits": "0x0108000000201040400000000000000208", + "data": { + "slot": "151015", + "index": "0", + "beacon_block_root": "0x2f135d2fe887c6012e78b25b8adecc33bc268c8057e444422f9fbdbb02730a30", + "source": { + "epoch": "4718", + "root": "0x6567f31ab5ccc3a0b0cd5d27abf183ed36704f817d09cb9dbe183da83cf07bf2" + }, + "target": { + "epoch": "4719", + "root": "0x49ce68a9103d485d81d74d0c744a3fde20657c4cb81fb13b12cee75a2a29804f" + } + }, + "signature": "0x833659ce0cf0ea303c1df6d0754f5303392789c91498635bcd339f0056c496e770072f025eb962793105137c424d80af05a6ebe8d6e7f9de48121fbc362b91d1644f23ce3728ddfab680ff2c064fc73a049389116a56409ae35d675b37c59e92", + "committee_bits": "0x4000000000000000" + } + ], + "deposits": [], + "voluntary_exits": [], + "sync_aggregate": { + "sync_committee_bits": "0xf7f7fffffffbff6ffffffbfffffffdffffffeff7ffdf7ffffeffffffffffffffffffffffffffffffffffffffef777dffffffff7ffeffffebffbf9ffffbffffff", + "sync_committee_signature": "0xa7be0f119fee5d9f9409d508b2291e1d8d81d3b9edd64d7a68d12f9b1a84bd50230618e4db78ef6e7f1e2f3e6aa56e2807985b25d52750a56b9d1b087ae3bca80c3a0b091e52c3797d82778acdf877e42b8fb18598d9fc56e9e469ebdd5c15e1" + }, + "execution_payload": { + "parent_hash": "0x52ad968c44fe260e5bb67b63c3ede2ade269a23641d27fcceba237065784c89e", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", + "state_root": "0x34ecb1a20d718e06f69e4ec6b6ad86c75603149a207480b03a077d0231668805", + "receipts_root": "0xd2da2f149a53d2c26982187652ecdf1114ae5301359c0ee6752c2b78dd97ea02", + "logs_bloom": "0x10200000000000000000000080000000000000000000100000000000200000000000000000800000000080000000000000000000000010000000000000000000000020000000010001800408000000200000000000000000000004000000000000000000000000000000000000000008000000000000000000000810000040000000000000000000008000000000000000000000000000080000004010400000800000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000000000001000000000000000000000000000000000010200000000000000000008000000000000000000000000", + "prev_randao": "0xb45479ddbad8fc0733b7762aed1a5b5861712b29bc20c2c0e34dc5e6722e82c9", + "block_number": "140858", + "gas_limit": "30029295", + "gas_used": "2383293", + "timestamp": "1740416052", + "extra_data": "0x4e65746865726d696e64", + "base_fee_per_gas": "7", + "block_hash": "0x1f2637170986346c7993d5adbadbebbf4c9ed89c6a4d2dff653db99c8c168076", + "transactions": [ + "0x03f901198501a5887710821dd184773594008477359407830186a0946e8d9c2108be0894bd30c8525c71d1bbcb31912e80b8808b177fd73255e0d6bd6e8a142b0572ba8f34d66075cf829e3fab19009fb1a8a5d057276080527fd8fff3f3f4d3b02314aa185d801e8d378d88992aa540c8b093c1e4264b68777c60a0527f69df553e04f0a6a7435a5650668958d47f9d4187d2ff2e72a91d8d9f74928c8c60c0527f8d8f0c90c68115c209dcec644ae93d4d05c0830f4240e1a001359c559c4114b7919abca725d032f48ab4519d2857567795ca4f49345e65a280a091007fbb893a18315106cbcb53bf044d6a5c0ea7098e0b6198727c3983ebc628a06c9abb0a1ded37b6305a5711831f03fce5e467a70dbc9c0c724ebd18b200a202", + "0x03f901198501a5887710821ae084773594008477359407830186a0949ae53a8e1ac8eeab1feece735b3d840634e30c4980b8807fb45278a2777c8ecd11eb2c2052276fd12c86bdb2373aa59d293c6b0ae1e8df076051527f8c9bb0742b467c164d5aad3087f92355c3f8cd0c291ca87b086e86fffa73780e6071527f8b11001c065ced40db4a5b2c43de47fde7a3b22f8919b39acd8d0b309df8a40a6091527fa49bf4a805c16f59556bec2665b647e02cee4fc0830f4240e1a0019da1702b651bd92e079ca2e801671cf22f3d3b6c097a185275dca50784123f80a039e483afa3751d7d758f2273fb19ac2143e5ce225eec49244f0aa358dc9fcb13a02e4a552312d68db400acc3898835e0aa32f46b8ef786ad6e2fbb0d933c51c551", + "0x03f901198501a5887710821dd284773594008477359407830186a0943c9f26a8f3c71bd76665e89a50f5f70d9953901e80b880605c60fe5360ce60ff53606f61010053604b6101015360fc6101025360396101035360e36101045360b36101055360926101065360e061010753601461010853605261010953607361010a53609561010b5360c861010c53608a61010d5360d261010e5360bd61010f5360ff61011053603461011153603761011253609e6101c0830f4240e1a001f8b21450b076ae1037e2e42f8a6899f01f793a2bee9f59e00ee520af66d56a80a0e97e75f469a7478d725c078e7d5b6979018753556850a61cfcd01cd2c87f02c8a024a8247013e502c09f4d7981f912995c44978f9680c261829bb3f0ec86627ea6", + "0x03f901198501a588771082398384773594008477359407830186a09401abea29659e5e97c95107f20bb753cd3e09bbbb80b880600060335dc61f7ffede24c98d6f2e886373c1dd99c824ad17b93cd6cca65a8856cd72972eea737960665260b3608653601a60875360f660885360ab6089536024608a536043608b536001608c536038608d537f15db390ca3613b231b40c801210901ec898c67f53aa7864f903944c3e3568817601b527f23a5a30cb6c97aa2c0830f4240e1a001c543c4e8d14cbdfb690f66b63b8b4c4fbd3963b1a555c6ab3ae43b08367b7880a065b7869dd9655457013e3e88c7866205124bec055f51b41e1fa92acce78b994aa07b83ebb8f12ba28df90ebd3eda8858204f2ff0eccb7ad8be10fafcb249bb3fdc", + "0x03f901198501a5887710821ae184773594008477359407830186a0946a5e2c588bb18c17cdadb44f82d22a895da0d62480b8806000632a674ca35d600060f15d60e249603c49604d496097497f8474c6950d31f88091bd7bed171350e494e797be9c933f1288dabacbbb84810e60c1527f84f66da36ef2af9007aa316630acc16ee30260d66c55ec449fdf03fb20860c8660e1527fba2768ed15416619a048e1b79c81583af46d1f3ff8141279fd98cb2326e0c0830f4240e1a0018ddeb1837db4291ad48990f90ac5bca82d10b9d3d73eebf1aa5c314cf91abd01a010004635691cfef330e4bb27701074e719e65c037e4182be65becc5e1945522ca02cb00278eb15a555f9ce56dcdf783135e8aa6c852816497d389190e63ae304e6", + "0x03f901198501a5887710821dd384773594008477359407830186a094000f3df6d732807ef1319fb7b8bb8522d0beac0280b8807f9a8968ca7a94768406d68b36a066e74dcadc49bc3605fdb95370ae9040470a4860eb527f0d8c1c38ee4b5dbf2b28f10ecc705f9cd2a9a36cfeff6c433efb8bd7c99626e061010b527fbbc1026522b0e497dc9722fc477fb7344969fbb16d66e31cc6e03de9a23178e361012b527f63ed37d8ac0e69b5609744b3ada8384a1dc0830f4240e1a0014cd492e6c4d129d4d3b22182ea5a5a632f3320aebbb6251d0ad724a747391a80a0c07736c5db2bc49a29ac00df7b32abf94978bcea15e65423b5cdd7d35df126dfa06b3f8c10978fc3e1cd60753975ed21762bf99a59fb29cd8e0a970321ee72ba9d", + "0x03f901198501a588771082398484773594008477359407830186a094dc547f9b829e446d70566195aecc6a5977e5860a80b880600060335dc61f7ffede24c98d6f2e886373c1dd99c824ad17b93cd6cca65a8856cd72972eea737960665260b3608653601a60875360f660885360ab6089536024608a536043608b536001608c536038608d537f15db390ca3613b231b40c801210901ec898c67f53aa7864f903944c3e3568817601b527f23a5a30cb6c97aa2c0830f4240e1a00150e9783b2dae0fabae7243e90ddc1dbab17e6a0934ba2434aac62f27cdb2d001a0ad1f8b4409159784a76bc7abe3a89003139274ff8215bfb50da2ffaa8b312cc8a032aa53063bbae96713f93714c830c536949c843cc09a3dde8cb2ebdfcfe5d613", + "0x03f901198501a588771082398584773594008477359407830186a0947a40026a3b9a41754a95eec8c92c6b99886f440c80b880600060335dc61f7ffede24c98d6f2e886373c1dd99c824ad17b93cd6cca65a8856cd72972eea737960665260b3608653601a60875360f660885360ab6089536024608a536043608b536001608c536038608d537f15db390ca3613b231b40c801210901ec898c67f53aa7864f903944c3e3568817601b527f23a5a30cb6c97aa2c0830f4240e1a001bae560947db14e3ed438ca8504783d40c9047191f49933b1d5e1ec8208583a80a0237ae7f13f17c0f994513c83636e1ac7e4d7c722221b51778352dfab41864310a036cba8ec5a2d31e6342f6afc914e3ba9dbfad0db22d29cb74e46e170ae2b09a9", + "0x03f901198501a58877108236ff84773594008477359407830186a094000f3df6d732807ef1319fb7b8bb8522d0beac0280b8807fc51dcb985e3563ad803460f85ed4746c57bf060d8e2259116646a0002c898fb360ea52606561010a5360a761010b53600561010c53604861010d53600761010e5360a661010f5360986101105360a96101115360b06101125360dc6101135360e6610114536071610115536060610116536091610117536084610118536041c0830f4240e1a00118b3d58c9a58f76bb27cff8ee97664f8b88ea8ec955abc1463805d2b96428d01a00eb390be8ce5900249b939af5bf2ca243ed1902ea6b1bc3bf372f8028b95861fa048dadfa661c274595edc2cf2797b9ec4dc873cd6a75d7329293f873c4335438a", + "0x02f9017b8501a58877108301391785012a05f2008512a05f2000830249f094d27d57804f09a93989e290cf12cb872c39ad2ad280b901040cc7326300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000ee86442fcd06c0000000000000000000000000000b3db4f6329df01ac317a70200f6614e1cd0db6f7000000000000000000000000fc7360b3b28cf4204268a8354dbec60720d155d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c8ae6c2d3f6695e41b5cb149beae76600f4ac97d000000000000000000000000d0ada425f6835193b8507d7de3a77ec1bd6c5377c080a0bb753e1df11f4e15f7b1f44c04d738b30e0849b804bb786f7fba10edc3d7668ca05d7151817aca075c8d7bf9ba2b74e9294d28de1c4b8d3e5b138669e89324885c", + "0xf873836181cc847735940782520894fcb6e353ad4f79245c7cb704abcffe2f4868424188058d15e1762800008085034b10ee43a031323a053c2013914ed32e251907c3311e4218561cdd8c25eaf8672355e66720a046900db9b5826610a5208c61a6e0c9f64178a76caefd64037db69b997295bf5c", + "0xf873836181cd8477359407825208940d3de4256d6322683fdea9ee23765ccbfcb83da488058d15e1762800008085034b10ee44a0cde1811bcf855221edb3b337e6bdd6bf26b11c9387768fba8597daff950ad5cca07867720bce30276937c2d806024791f158a64862ec35a036ff1dbb01d16be959", + "0xf873836181ce8477359407825208946021752d8d9b2f221d4fea4349dea34ddbcfce5088058d15e1762800008085034b10ee43a0f833125f6025471a4f351c2777d5841a23e4f6002c51161855004820fb91eaafa01722b78eba514ac450c0459568b4dc9521bb797a7c601c5c8825cd5e006f71a7", + "0xf873836181cf84773594078252089461e296d527edc89e831cf593ec341f16197eeafb88058d15e1762800008085034b10ee44a0151e6c4bedcf29fafb9ef50f81f7e573d75ba42e00c46e91b9761de3e13cdc37a047bc54be6c3493ceb0949a3324ee1cb93c8058c9db71fbfb5c16ffdb472c0fed", + "0xf873836181d0847735940782520894cf7317ee7a3b497ecf634b94bff60ff91b92574788058d15e1762800008085034b10ee44a0c6e018c4eb28bab20355104705e0570a371c157dc592e503713bcce730953d76a0279412202acdd26ab9d03c2edb129aa974fc39c86a0ecbef410c0a69d27789d9", + "0xf873836181d18477359407825208947e7b519df31f77ced83eea1b16aedb6dcb0f0b2488058d15e1762800008085034b10ee44a08fe9e5cd6238d8e3e21ab280bca46ce43c23620b1f81b386265efbcbdb106385a018945e95e62a6148cbf35649e1e2ec4835491b4e4b6216e316c4932c96220ecb", + "0xf873836181d284773594078252089488a075e0fb1c9309a200a8bf0a88b214bf7ceb8d88058d15e1762800008085034b10ee43a090b175e1335dc2c4450dd3a0543e19e2635aebea5675c94eac1cce52c7ce3d64a021aab7cccb861a1c30d876526a4ef0b7e217d784fc89cbd02e8c6d63ad35b0ba", + "0xf873836181d3847735940782520894c8d7cfb58f3ac02568e6505bf3fb5eb6f080703988058d15e1762800008085034b10ee43a06d530baafa0a899792978df61bf5adc6028be85be12f55c687e44f1740dc22ffa06d4196c744ecfed500c4ad0fa17947c12238227155acea265edb7c7461571259", + "0xf873836181d4847735940782520894e0132e8d7b1b766e0ade5543d6c6c0b2d5a2f01d88058d15e1762800008085034b10ee43a007e42562bf3a9a058fb1803d7c423ea0d7113fc98788be2a6b4d982210066139a02a24a9efb9f88cc53ad464b62601af3e54fedd8305e1b98670bfc8dab223c596", + "0xf873836181d5847735940782520894eb674c0411db79654afdc1e131f3b6e734baee6c88058d15e1762800008085034b10ee44a0e197786db41e4d21914f319e669aa504f1e821d2cd17b39a396b1b85b5348025a00b1efe1355fcb919642f14f7609893afe70017eaa999d531e6f77fbdc5d28029", + "0xf873836181d6847735940782520894dc07c60993cf689438b8c85f86b0ed938dca77ea88058d15e1762800008085034b10ee43a0f00a06c5148f52c55b2f65668a757c9d0011e7924032b88c771e3934e0bab6a4a0480e37e4cd116cedecd7de44cdb91c698ad896abbd3b08e2651773dea497e8e6", + "0xf873836181d7847735940782520894110ddc93db59ed31a03518510221ec2f35d28f2f88058d15e1762800008085034b10ee43a047c9b1fb51b626b40cb2707269a8ad6a7391c467864e4423efa3b4ede8bf6d3ea028314d010ef79d04027fec9c0efb0bbad7ef386e110bc8e07797e78f484cb51d", + "0xf873836181d8847735940782520894b599a876aaac824cfce21bdf15627c9fd8634c3088058d15e1762800008085034b10ee43a0630d66f57eae656309cdcf02dbf20db3bf960c77fa0c66b72de13b7852b0c8d7a00541603caf792d410387983650ec5799d9eaac5761296b3ad09f26fbe40fe251", + "0xf873836181d9847735940782520894d36e5540dd71acbd6416d60252c4d7c34a3c824588058d15e1762800008085034b10ee43a0dd6a775844cc76e89ab1b2bd43d266b3b1b6e34a8d129cc1c1f7ce28c44b2439a01ab09f383573d80274ed64053a079902796c2e6e4cc19abf0271d37e2db4a0d0", + "0xf873836181da8477359407825208943adeca35af56206a74987a8fe13c669365c770cf88058d15e1762800008085034b10ee43a0a8f36c6870413fdea217d52c0b6bb3d6b55a837e7907ad2a3979da577f9f1763a0646ed9c93233cae748988a3a33debd3411706a2a88c3349d2702da1b5a728cea", + "0xf873836181db847735940782520894d77b95acd12f7b4b5692b55717b7bbca1165195488058d15e1762800008085034b10ee43a052069ecf399b7323e46892858d2d99668d7554b581245656d97768972f533683a009824b000ffa65ec5acc5210674b12ec2b92f45214e2af2c541a9da825baa9f6", + "0xf873836181dc847735940782520894f388bf5766b5ed5d4e1cbf15772e677dbfa80b0088058d15e1762800008085034b10ee44a0532fcb541538ee4041bd97e09c0f86fde22760d4d3e3922b48d2fec22c41503fa00aab5d1fc4438ea787d42f08508c82cc8c9940583217eaf25e9cd12e53241b4b", + "0xf873836181dd84773594078252089435d4996296e58560e6ef47787d51b55f1e2bd92a88058d15e1762800008085034b10ee43a01c2172f632447d91029c0bb197b6f29c6f16be40ddbc45637132aae1734dfbf2a06c7e9868cb7e95d72edd545e173887a45d405e3597da99067985d8e7343ba224", + "0xf873836181de847735940782520894a4c3b77b898e53d6095f11c53a1ce272cff9af3188058d15e1762800008085034b10ee43a02ba7caf4ef662c4a459f11d2ff90c970c8b4d5ab27e201b8f80e12d763a46f57a02e1f114037a153d9ad303e5633753785bd7c73c5cb0b9f3bb8159312eb0692a4", + "0xf873836181df8477359407825208946e84f6113fc1919714f0266705813fb81a17181f88058d15e1762800008085034b10ee44a07ac801acd1375d7bc7d5a7e54553be58976519169de1e2e14186494087a0b4baa043a9a4311283cbcbca29255de9e3bf1e688d73a0e4e20ff8d8b5a2e16b6e630c", + "0xf873836181e0847735940782520894e9ae1a806004e1452baae0493920815aadd8479888058d15e1762800008085034b10ee43a02fb8319f5613dbf37419d177b132306a7c55b2d72d04522d6eceab27ddba4f82a03f1b125a7c93ff5e6c278df26ebf8411fd9317112424a26dabc5a23557712272", + "0xf873836181e1847735940782520894fe1905d8ebd20e037274eef441283c811ea82c1688058d15e1762800008085034b10ee43a0224ee510dbb1e0ef70a7a016bd1512039fcf3af0af9a34b9b1cc2ee90a002339a02b7a11a1ff4a20c1253069e4b899ef0aa2f2702c3c4460d478f92a9a43e00b67", + "0xf873836181e28477359407825208946adece88e477f53a143a4c29d97940df2ec768e088058d15e1762800008085034b10ee43a08590ee9e8715492a2e5c1390f4e389143c410e1d416f5202994b516f51e7eafba03159c4853aeaf69bf1c44c4e6cc8e449bc7d42eba79384cd8b133659d38159e5", + "0xf873836181e38477359407825208940d34d140a7376892c4593fcea3ae26f5d6f202d788058d15e1762800008085034b10ee43a01a115564422f4e9fe3d1e51202e25ad90705509c2b827423bd9a766d67e6c6d1a00fbc0b850c9835c6a75a4baef78f29458f592ca83447dbe1c5f14c38724a86d0", + "0xf873836181e4847735940782520894d1c7fa75b9bc55d041fcdf215f3e3a351c9f9edc88058d15e1762800008085034b10ee44a0f1bcf05bfdd6d0d2a4345f86c2875dd7bfa685745427754fd3b524a69664114ea0674e3c62d1e0b5ac4d79cbc972ea51e2183201f879e17b9061671107089fcdda", + "0xf873836181e5847735940782520894418ebe350a8c6387bf5e42f3502742af8e0781f188058d15e1762800008085034b10ee44a02b5935a36f3240d235d2574f6a0d97f432aa4443da752e1101479a9392b124d3a0674f43bb33455d22e08224c584a2f206cb6ac4a86aa312f8d63b75f99fef5764", + "0xf873836181e684773594078252089484914d2770c711d27888c775c547b1d933b48c4788058d15e1762800008085034b10ee44a0c94d55923ef4bd2e4c0a83f31e36dc49f2ef84bda5a4dba429795ffe33bb6574a04101d4d64e212019cdeb93c8e2ec7488405c2f716acb64e5ab70ca4689c4a370", + "0xf873836181e78477359407825208948f51e560b85edf2e653c689c4e9fac02ce0556b888058d15e1762800008085034b10ee43a081e8fb2724b676b50ed6a9dd02a3dfdbeb1cd715cbe485cfa98a204c5a7a35dea04d7f13607047239a65d798a199a66460d89f3334a79f49587fbb58ad499e1a1b", + "0xf873836181e8847735940782520894ee2503205c24dc66346e356f13f333fb8782d35888058d15e1762800008085034b10ee44a098b33a8231bf024845d5bf52add950edc4b1c53f23b03b8b5439ffcbfa034522a03dced7a7342c7d2eb201d8225009a41527dd98f7a6475a8a65660feb4c68d6d6", + "0xf873836181e9847735940782520894096ba6c59bd667a0fea9a356bcc988e4d9f2d8eb88058d15e1762800008085034b10ee44a0c3a8d920e1f80f5139f70822ca6c899edf0bc17c8fb3c7f3a1318ddea7d62c7aa054e14fb1325f2a23214fc6ba3abf11ea547e01a1d95a3e490c3b1f9af277ec90", + "0xf873836181ea847735940782520894da0adce4f1dc7debe7b2b52e8fe9ace6c7ea9c6688058d15e1762800008085034b10ee43a0755d9805b1d15d1392d860e86df05834fd94a61d18c22956907ac7c1bc982892a063de885856b515242c33c31f9cee81d23aee55fd632b88d86fcdb3f8566af3ef", + "0xf873836181eb847735940782520894af7d412aeab7525c0541dc3aa6c1085cfb8c909988058d15e1762800008085034b10ee44a0b91c06dd7e4010c5d7b3f66285f4c139e22480773fb053409950ffe5bce7b720a0397f1b6ef9424dd5e30b07c110fa5b009cf86bfe92a98e994427d595dd9586fe", + "0xf873836181ec8477359407825208943cf8c0d567261eaf4ac0872d33a9f48af361769f88058d15e1762800008085034b10ee44a0828618325c9586073c8199d866e9001a7b9ae129a29cc60cb43aca355175b13ea07f885bfcc7b096b6c47e0122bef7f0295712f0810a78ab4f0b53112561d2c84a", + "0xf873836181ed8477359407825208944779242587ba9e828999249eadd82984430f484388058d15e1762800008085034b10ee44a0dd150d77fe8d9073a20510992f5eb8c70380327f5483064a6f42fb547465ccb3a04cb3406733b1e7318315255edccbad06adf0e6a3fe13f01389c5c95245cc8150", + "0xf873836181ee847735940782520894ea531cfe2de357ecff3855b88dbd07f60b03cdca88058d15e1762800008085034b10ee43a08c72279cb318e4dacdfaf265959cd7f31002a1521113bc7e65851ab8ac2aed06a008340ab82a4a61f91d3e5f4594629b6a422fe11e8d6b39b2a145eabf15f3bbf8", + "0xf873836181ef847735940782520894d00b5f53ea2a66ad33c3fee304bb22857dfb8a8788058d15e1762800008085034b10ee44a0ebb567f7d111eb54667984476e3a271c99220942e20e96f713ef9b4ae5728404a040bae6c5b88e58b0e02d1218df7ae41d9b3b99d2180eddf8ba770976852de483", + "0xf873836181f08477359407825208947ead29f6616f78f21a951c9686dd257be7b8efe488058d15e1762800008085034b10ee43a0f749f26b7f700cb7bfbbb6e37206553e64ae70307f33cb60455bee1da135d4a6a072467439050b5a0d411d90c92fe6fb17676189d3fa8a0ad27ec4dbcdc03c14cb", + "0xf873836181f1847735940782520894d503c13ee55c1ea128357d4018ec58d0d5e5c3db88058d15e1762800008085034b10ee44a0adbe9e31e5a740ee0b52a69b0cc85a718c799309df72991bc856c364f9b85f28a051a55333b441a7255a63e0fe6918aff4b6269576ef99763190c784624f8f7e45", + "0xf873836181f28477359407825208944ac670d8760faf780468638ef80034876ed8918d88058d15e1762800008085034b10ee43a0636ee52b3e021114085c7413cbaab77013b432fd41cbf0a88dbd8d145e8a1125a02d15ffe159ec762142907b2e8b5e04b804361a399b23ff335ee4b996f7ee0a81", + "0xf873836181f384773594078252089424ffb8c97ce443f8d3265ba3316defcfc07c659c88058d15e1762800008085034b10ee44a03c4c9d42c3a76c275f8f167cc846e62a16e2d4f54418b0303f64f0a1f2122fcda034d0cd15b9d14b118eb7a2e5bf9a464043e5b1935e740ca557fd05b47328b092", + "0xf873836181f48477359407825208940c5cafc547ab98c9ceaa1c07fdd6bf7820aeb95488058d15e1762800008085034b10ee44a064728de799b66a56f3f634bca37944e0027ab9be12419d2e976bacfe295c5854a03a4b830c50b7c1cf39511b592ac20634bb54e6afb795dddbfc6c322bf6ac85fb", + "0xf873836181f5847735940782520894db8d964741c53e55df9c2d4e9414c6c96482874e88058d15e1762800008085034b10ee44a0d56eac7a793978c4a8356bf94024e3fe292d9f61f594c3bc847a49c4c94df56fa059b143fedac3f768e936b63291180c1fe34415d27888e1b90326d28b4567fd53", + "0xf873836181f6847735940782520894ba85bb35ae6ff7a34745993fcf92b9afd34124f188058d15e1762800008085034b10ee44a0b368c25c6edfe52749b1377664c2886a5c09f89d12c63078ba635dad22ae3ec7a004d02d8cec691a288092fd337f4a9c18eb4d15493cd512cb963a3be9cd9c0b04", + "0xf873836181f784773594078252089458871015f5a2d3948264f7c16ad194c80ffd531d88058d15e1762800008085034b10ee44a0c6ecc87a4c18d2476757ca03080992de68e24b16826e35d0a26b6d137a4b6be8a065defc8e1b910d228675e323898baf81d24633cf57549021e64678e4e41bb78c", + "0xf873836181f88477359407825208942a90af45df70b0031f218cc122598ddf3e10469f88058d15e1762800008085034b10ee43a010c9e461dbdac507e73c5c2092f83c780fd91de482b1db746544dca8adbabb9da05f1c695251e7fcb4fa0a655f5d64845e597fb3f2a948326dda2e7a87fa74ea50", + "0xf873836181f9847735940782520894761bbaaea6ceb265f5262c3b559adc2ad3ed2f0988058d15e1762800008085034b10ee44a01e238f26c7ed2a54504a1ff05ab2cdffd5306c80281f61e3a93f950b2c965014a00739c6e4e75c3c312636bef62ff6fb8a1c0d0c71dd34f117e19bc58fd9353e1d", + "0xf873836181fa847735940782520894dfe86f51c5e603f1420d1f0ab366bd3bfe23d2a788058d15e1762800008085034b10ee43a06994565ae218ce6ce28078aa4924a01207584026a892fd82b4bc8c187d8bf1c2a02b44cbe2120bbf57c777b2321e2b54e3d8015a6484e109bf761e07e38b22c9d9", + "0xf873836181fb847735940782520894d616547158b05ab5079106dc0336d72763a7287188058d15e1762800008085034b10ee43a01559edc6eb87baba522ba21cd45da85f76be8adceeca311a378035d723efa31da063253dd048dbe7e7c7285a5b1b23dfce7655e060c5b9523f56c6de6b7fa30ec0", + "0xf873836181fc847735940782520894dc68cd278cb7f5f666ce7b0a3a214a8540ed4dfa88058d15e1762800008085034b10ee43a067f63eb982417af7de349aa9cf07889ed0d7423407995926b8044fe7525154eaa00417db33f88ae9c142950ef84ae18f47445fa7c26b6a482df6ffb5e13ca89cad", + "0xf873836181fd84773594078252089411f8107da05b6905e8cc0227ca3b0c6eb764fac088058d15e1762800008085034b10ee43a06594ca7cfdb0ee036f1735bbd3f2971be1da00edefc122a0214807828a7ead31a075a11a79283bd39456153246494d408c61f18f27022c4bb888b5742e1c66e3ef", + "0xf873836181fe84773594078252089404da906545679850a7ee0ef6836e183031bedc8888058d15e1762800008085034b10ee43a062c55b09cc71c0c3e34bb97dc8e3d9e9918929f0c9490309090bc430bf6eb722a05f733500640bd0f6e61952424a3d9bd5dfde0ba3cda5be598489f0859df6c919", + "0xf873836181ff8477359407825208948bdc25c43c010fd3db6281fcd8f7a0bed18838e388058d15e1762800008085034b10ee43a02518ed9188048e9a9666de8a3983dd208c2e582a18720a2605baaaffdb2ef4aaa0510893d599ed7e303b7027e9c9453a8f25409735ae782faad9fb3afefe4e458a", + "0xf87383618200847735940782520894af16f746b8a834a383fd0597d941fee52b7791eb88058d15e1762800008085034b10ee43a0d8b4839aed9b334066a24ef5295f456fba1d0fc6d783b7d18012cdb2c18861e2a07a74bd5a40d360c32bceb00be00d3e6e608f39b04a13ecc3ed4672900f5c54b3", + "0xf873836182018477359407825208940c5c736600f8ea58ccb89aa72e3f3634651fd55188058d15e1762800008085034b10ee44a033c53fbdc9c86cf60777c5d2bd192f57d36628c672a7ca61352effbe7fa781f4a01943da2502b48ee6b3b936769270da655c8d955c9a390e0c186ee5d3646d1d27", + "0xf873836182028477359407825208946f475e0f0e9eda58556fddc04de9b1a9b6a4cfb488058d15e1762800008085034b10ee43a00a00563e58ee9203cba306e432af000938b1e2e2daebbb7d06210c0b3cdac601a05d0f1492b63df3df5ac1310fccbdc3e0863d8c3c7231186df265d32abe00f87f", + "0xf873836182038477359407825208949b2e76498a695c4dc7d0890069cffa84a9581d2488058d15e1762800008085034b10ee44a0cb83570f01c24cdef394144b462fd9b7753337794a84fbb89c68e40038491487a03cb5dbc916553e4534921cc0c0d7e9d3c12afc7bb345ecf88e030c8d6f275a1c", + "0xf87383618204847735940782520894e2d2b2069f4a54fcc171223ff0c17adbd743c28588058d15e1762800008085034b10ee43a01e6d349911a4261a944c289ec6594cb1d6414fbc96240ea5d0a134cb75cf5ff2a042dcc7cfe31d1260bc5093627e0fbace0f87812d37cfbcffe7beff500dfff385", + "0xf87383618205847735940782520894386bd49f04322544f3c7178fa5ae1a24b947b45488058d15e1762800008085034b10ee44a06e76a8890665419b746548fd24bf999efa9eda82b509a2a13dff3c8d8774d239a00c54e75e6280c2368a3cc742f1c6c6d4853cdff6aa71afb3b59939283a70ba70", + "0xf8738361820684773594078252089400af839c3fc067fafc2e0a205858d6957f0dd18d88058d15e1762800008085034b10ee44a06e90bb215dedf42450c3529ecacc852df6fa5c4d76b04b673d2dee5162f77afda061c0f17a6fb4eaafd5c1792bd780e256ae93b8197eba1f739d3483b6018b34c8", + "0xf87383618207847735940782520894ebb6d32a650afa9221b55a11c6a6de52b6f07cd788058d15e1762800008085034b10ee44a0bb5b7a794279609699dcfef3544af96e2f36e1a080d9df5ae2f0d065d897e7f6a020b02a03622daf550239dbffa1d81c3637dfcc4267f19ec86deccf77005c7b3c", + "0xf87383618208847735940782520894011d26a3a9adc9203c8943a6a77aa8657af5242088058d15e1762800008085034b10ee43a0033c85b6bc49bc1122163ed03061ffd5a580e70621a77877108c975f6280374da03a2ebd53fa8a5b2c0676e05e87ce8ae0f64f2a1304c1c01fb0a353ca084123f6", + "0xf873836182098477359407825208949c85bc61a89fb5abd957e6c819c653fc1aa0d11b88058d15e1762800008085034b10ee44a02c511d53e802a2653fe1284802c56362ce7f36936030da8f2afabc9369812b8fa02ca196683edf5a07038d65d12d23b607d331558f8e8bbe1bb3638b3f87ed1e5d", + "0xf8738361820a847735940782520894bd8e8435b7897d87cf7cedb5cf8c5dd865dbf72088058d15e1762800008085034b10ee44a0dc65a971d20e6b631f9ce091c891068600846b80a519b897dc90d85cf493b67ea075b4159b6bb958d789c05bfbdab2f58bffe006f1bc6481f5e5fbd0c0de87e0ab", + "0xf8738361820b847735940782520894adebee2e3ff041078b62380d001c6e51b4f1559888058d15e1762800008085034b10ee44a0dc5c31ab6d48576b337145ca3480f20403342d4632db7e3c58a5c2a3722aad36a0088bee3e8da14156e74abd4b830ce7dadd9aa5acc682b0a5f441e2c579930dd5", + "0xf8738361820c84773594078252089471e94c459c9f05085fc0d34b5f21e648e05dc6b388058d15e1762800008085034b10ee44a0cc7dd758523571aa417ca7e92ce18fa344eb09ae4030cbe67a20749a5f25cfa6a079260f268e88f5349a96d339a543c81800ddac65ded5bf66ff69bb8d2cf6ac8a", + "0xf8738361820d8477359407825208947c1fe317db82c9298b87c56c3194178271b621e188058d15e1762800008085034b10ee43a03670f304b0cfec63bbb48f6adea22daabf97cb5066464b66dc8b0c5062547c94a046ff008a93f3ce2964b77be87730cd5e4fe706832955148580869189edd18d1e", + "0xf8738361820e847735940782520894e069d1c9abf5127bdc3a164fb93b96bfa9f74ce088058d15e1762800008085034b10ee43a0118c5332b8e96e0938c49205cd48c34651dac16e06b177fe9ccb3c4a5714a818a0335ee8a457a31e10f6ece6faa85587e2527e69e7287f9cbfcbe977033091d5cb", + "0xf8738361820f847735940782520894b9bbddd1eb6ef8fb1bdc6a853d5ad7486a9487dd88058d15e1762800008085034b10ee44a0fd2a39184707e76817b5132d4f680f58b814ae07053bff5444341964029676bfa03a96b5d6be262592e72f19bc64ca930f1e76a6655d89ac3640aa927ea066f679", + "0xf87383618210847735940782520894a804387cdaf986d45831e8074efb2115af053f7a88058d15e1762800008085034b10ee44a03809b662c3a9d240d7b7f9e2cb4fb8d50b1e421b4548180704aedea809b2218ea063c9d8136461e93058f75ae91000d4e6f0cf21ff74d5c91c340209c1d04f0bff", + "0xf87383618211847735940782520894f23501d784a041fc911b4c86c2bfb1f63ec170ea88058d15e1762800008085034b10ee44a02af9b021ce8467c713e9ba2dd9a948cdc1d67dd04117868b6897831a4c9b2448a06bb0aa527519e251ec40b747f25dc7c7c2ed689022ac4dd80c4a40c37efa06b3", + "0xf873836182128477359407825208943928be2a7058088313c0fb3294014e88a3c5ed4a88058d15e1762800008085034b10ee44a098ea195f842b013d76e62b19cb989e3d853ca5b84602bad0b777ecdfebc2f0dba0540fdd9b2a2ddcb4a634bf63186c80987bcb9c19d0025ca0cbefba565e4afbbb", + "0xf87383618213847735940782520894196aa07204141478459c14106ef5e5282efe995788058d15e1762800008085034b10ee43a0b817d9e63a606c505074d41ce01c53612ba083cd4b39adaff884c869d539fd6ca06dd3bd03aefe17446e3354dcf4864a712e4ac2e4c59701a41a4f7ffbc937adcd", + "0xf87383618214847735940782520894763cbf89560e2da270000822abda9584db693fa388058d15e1762800008085034b10ee43a09b856c0c79b5f977db2d9c26992f9e2a113e86dfde2fa684ae4a28a45fdf7dd3a078ac54eacbdc28a7b98176c5c79becb1ebee800186c48b664a643ae760cf0318", + "0xf873836182158477359407825208947feaea0ff70ffc9eec2104f57f7136aff4dea68088058d15e1762800008085034b10ee43a0a5d30ceced18dbf6684a5ce409f654f359ad2d6105ca8cfb6c66d0ad18fa840ca06a3f64c8d043f06d2b0d26fde83f003aeb24904226fea3712af38e2c7c805a96", + "0xf87383618216847735940782520894e5466aacd9dd6d3bb35060a1ccc76a438de88ca188058d15e1762800008085034b10ee44a0b2646589ce46644bddfb0bbe5f5dfe9700a82accbc4ef29997094913c1ad85a1a01b65a1ac0f935af862b93dd79559b685d2c6afdf93795e70fc3cf174f95a7d9f", + "0xf87383618217847735940782520894f670980415cfe8c4f8d10645ecf974c9a2fea00e88058d15e1762800008085034b10ee43a06f2d0bca0b319a77accb02cf01e2edf5fff3f5cb38fc99d25a2d19642027e359a05223e3bce8700a92b7770fe92d7c50527505230cea7a5ab05e90c5a7959e0cc1", + "0xf87383618218847735940782520894a29115bce7829ffdd989b7cf1bdd1eac06a2cb3688058d15e1762800008085034b10ee44a09377c8d9a2e30c4c08b6d81fb5b645b6c4938d4047858668cbb6ddd3d67b2433a079e9b9182f4c0c6291a470f6dde8846b0aa729676224081d29940f0c319c54a0", + "0xf873836182198477359407825208948f528aa67dc1846c893465fa1c8c26556bc5fe1988058d15e1762800008085034b10ee43a00e35ce7ac258b4230bbc01045e9b5e1789543dbd324e975504c0c60e9cb5cbcfa057879da45fe069aa050ff7734b6e59b5e127db0f1921b973885ff3ef6aebe3db", + "0xf8738361821a8477359407825208944dc4ec6ac43c8c45777292db987203c0248e17b788058d15e1762800008085034b10ee43a03b63fd365340ceebecdb997d2b4bb41b336683c02eb1139cb1791d286ee13246a003ea3888ed23e1f986d8d3b9d560281d3484dd2fe974c25f7216c90568208b45", + "0xf8738361821b8477359407825208940d2f39f251cb547cba567a31e5e9f93c19dffa8588058d15e1762800008085034b10ee44a050f14998905eb10dc8e53395da51b21b0eefde3bc103b615d6f97d7b44f26e36a008ae2d148621eefa13ef0e3fb6ce1d259c62c8e057180ed49d761fab9d312b93", + "0xf8738361821c8477359407825208949eb31fb94ce5111e2a04cb9d156b513887ccbd0088058d15e1762800008085034b10ee44a07e88781530f943cd64ca63c2b7133bf8ed704356622be4b54f08751b54bf1d2ba00fa89ce3cc8f773cc83a72b7d58327740c41c95679e7003522c489ab9f66f88f", + "0xf8738361821d84773594078252089404b88ef83f8c41b1465d360a1e82f07ae190892a88058d15e1762800008085034b10ee43a096a28917edd16daee0707b0459a228fb5e006a5b9714a5d9cdac681a6960836ca02bce226c902887909a8bba3ad618153e90ff2d93e3825a42b72181bd18154d87", + "0xf8738361821e847735940782520894af23e04b04fbe15630eadd32a6f27a5a65ea554a88058d15e1762800008085034b10ee44a01dd4f73c1317ed5bd565999aa5fc130e388378ccd9f9641ed6a213d357d7bb7ea03e94fdad16c029234002c3ee24d382fae242f60bb58340c2a45488e57ad1bcb1", + "0xf8738361821f847735940782520894746cdff371e3f1e905b3ac52280078bac2dec7dd88058d15e1762800008085034b10ee43a02a4b086a715feb49bb892f026c3995f4235ced4da4a500bd3c960af2c3853ecfa03c14793e2606d25e7b5469a04bca55f50af24abe997afa154ef276ebfc7a6e6c", + "0xf87383618220847735940782520894c33e5155bdbf1a0a7ceb1b80f8586c5cda5c378188058d15e1762800008085034b10ee44a0b23359e18485b91d7599425b986ebb19cee52960533f993c24998636ec169a82a028d4cd7d4bc768fe29a6a3f32065b0a59188239808fbe5bb39e90ccd8eb43989", + "0xf87383618221847735940782520894e7fdef5f5219068f3d0f88a7445005574c66279888058d15e1762800008085034b10ee43a0101fbd3be6b8fc9c5a7f5c8f3c9fec2abcedbac8ab3c7247df2c98e6b968af38a019c11ee7058d8a6eeceb2e8cb45492f442eaaaa7fff37cc7fdd9d17e92e3bfaa", + "0xf87383618222847735940782520894f0a81a63c5e09b0bd08e027de48058e377d3732d88058d15e1762800008085034b10ee44a0f0e999e581df579e31fae928c52a7df96a1524d38f2e41bf4893ae7c4a083a48a022e1d07f18385e6d2f9fce94a25d042f4dee7eabb2df53d9ef694ba27869bb29", + "0xf873836182238477359407825208949878ab34dc3b4a63c80fdb733491472c11d59a5688058d15e1762800008085034b10ee44a0d719bfbbfbdbdab38420d454322ccf418defe93e5d81dffc354e0324d4ebd5dda05859b730b918a46f7e58bc0858aee845eeb07e64a6be8df0357a18b519b3c00b", + "0xf87383618224847735940782520894912859bebae3086ac7a062dee5d68aa8ed2d71ec88058d15e1762800008085034b10ee43a0a73cddf5a57016d0cf7e7f91e0e6e419f1a3e6485159868817ff0383fee03b4ba02a0cbafef77b725e6e3adf60c14463316b2d6780536e29d411044bf9d4a0518f", + "0xf873836182258477359407825208945a0b737ed85049410e5ea61f444d07d5c8c0359f88058d15e1762800008085034b10ee44a06cea82c78f91a7e463a6493ae9aed4039cb220686ed4b650c89e4160835d1a30a062d3191502b312090301ea3dd63b6b29f4e64622639a6e080d4a15a1b2b22ae0", + "0xf87383618226847735940782520894305a5dfd46e6128abce28c03b3ad971f4e4915ff88058d15e1762800008085034b10ee44a06ee9ca5a35966737addbde05c3702020db87737e2f3fe6f783023e69ef49c84da067ac4e87f6f02258d33cc1507006ed81501d1398428016f0b99eac2bd23f54d2", + "0x02f9021e8501a5887710808477359407847735940782dfad9442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200eabd7137c45a0f283d7839ca69f6bbcee6adc41416bc9e01c31e8ca86b767390000000000000000000000000000000000000000000000000000000000000030a3dc91086418a5680fe3037dba62dda3de79dd22bb41036719c3771f140b419586ae7d9bdf3b10d88850909d4556b19b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020010000000000000000000000bf3da697ab02552a5da95f267075cbe495d1ecb30000000000000000000000000000000000000000000000000000000000000060896bccd536b4a30c4c3ce5877544574c624dff09f100abcb2df38df7c797069aed3213f1320fe77e4cf89907fb23fe4601a9008fdbac478412f8d6a5eb4c53b12c3848c29ced5ded2a7e3fbeb1e1dc4f58a563d761f7ea80c06088126e0dd9eac001a0ccca64755c8eae02419698251ccdc9e3691d2caaf5a104cf9542383c1a548d2da00ac0d62ff682d5edf5746aa633e34a5e8e789ec3eccdbd63b8d12fb80862d80c" + ], + "withdrawals": [ + { + "index": "481571", + "validator_index": "71016", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481572", + "validator_index": "71017", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481573", + "validator_index": "71018", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481574", + "validator_index": "71019", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481575", + "validator_index": "71020", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481576", + "validator_index": "71021", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481577", + "validator_index": "71022", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481578", + "validator_index": "71023", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481579", + "validator_index": "71024", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481580", + "validator_index": "71025", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481581", + "validator_index": "71026", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481582", + "validator_index": "71027", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481583", + "validator_index": "71028", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481584", + "validator_index": "71029", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481585", + "validator_index": "71030", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + }, + { + "index": "481586", + "validator_index": "71031", + "address": "0x7bf8bca0ccd13d04fd466539989efe2adcb0ca7e", + "amount": "34197" + } + ], + "blob_gas_used": "1179648", + "excess_blob_gas": "67895296" + }, + "bls_to_execution_changes": [], + "blob_kzg_commitments": [ + "0x92549576706cd5a855ea6a82537d1c7190c8d7d439f4dcbcf4b9b2bd34c4712d14f4ed041644bca5659e1826570e58b8", + "0xac58961e240bb13fd49d4cd60ace53bf3b6205ab7aee98987f3e589680fbe9d3febf3991150dd2ce0a785b9c7ceb42e2", + "0x83945613f3af6994e24c48b02a39a7c0e9c98f168c0c12ce3bf1d5bc267236ed6770c9c8a1fd7d7a9152066ccfa7147e", + "0x9334f6af7b93b7c1ee1cbac56bd38e9d9d6e50dd110bcee546333ec3ba0702c4aabe16b332ebc657967c66e9789a3a69", + "0xa43089b05e5987070bdbc3b8742bb30d7c34ea0e81518dc26ccb3f3a97c23df6d96f2cf1000ff985b494cc04743c5e2a", + "0xb45aefd32b12b74523a1082102de20e6965b31fb493228a12247e85165346087be8e54f435a60e9c96c1af716d4477c9", + "0x93c5be3093d114302d2dbd86f132c925d7de78bf977c0fd47e0e2c2dff528af381989fe0e50dc82e48d7f5c34d02f6ed", + "0x8a6a84e0ad21a30bacb75e8d0d5c3cf9fa89bb4d72a3cb4462a771cc533227aee35a21030258bb6b5869bebb3075be69", + "0xb54c1dd86ee3f132994ed666988cbdfd9a2b775697ce3e17139850cfe6ab2a5f250a1e2e9103fbe241582eca35d26b25" + ], + "execution_requests": { + "deposits": [ + { + "pubkey": "0xa3dc91086418a5680fe3037dba62dda3de79dd22bb41036719c3771f140b419586ae7d9bdf3b10d88850909d4556b19b", + "withdrawal_credentials": "0x010000000000000000000000bf3da697ab02552a5da95f267075cbe495d1ecb3", + "amount": "32000000000", + "signature": "0x896bccd536b4a30c4c3ce5877544574c624dff09f100abcb2df38df7c797069aed3213f1320fe77e4cf89907fb23fe4601a9008fdbac478412f8d6a5eb4c53b12c3848c29ced5ded2a7e3fbeb1e1dc4f58a563d761f7ea80c06088126e0dd9ea", + "index": "10011" + } + ], + "withdrawals": [], + "consolidations": [] + } + } +} diff --git a/beacon/types/testdata/block_electra_withdrawals.json b/beacon/types/testdata/block_electra_withdrawals.json new file mode 100644 index 000000000..68c67b680 --- /dev/null +++ b/beacon/types/testdata/block_electra_withdrawals.json @@ -0,0 +1,232 @@ +{ + "slot": "151850", + "proposer_index": "38060", + "parent_root": "0xcedd94fbf2ebaf371384911b85bb3073eadcca25eeb4ab29d14acd95cd88bcfb", + "state_root": "0x611fa0d96bedd90a2474b2e67f93f5a5edf82af93443079b58658c6739207a30", + "body": { + "randao_reveal": "0xa69041c990d2c6cab84d979be3c9db5081026874c8e37750c4274a355a7acf06f7fbc88857db3c20c84309f61026b20917a99fc826123ae930dba33dc92ced07ebdd57b45b1760fa08309c67fef843ee33ffef518e2ce9cb3c41da9e65d6f6f6", + "eth1_data": { + "deposit_root": "0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e", + "deposit_count": "0", + "block_hash": "0x1b60b6c9500355aa0ff7e1654482fea15eee29f2d52a25aeae859df953c0f7d4" + }, + "graffiti": "0x74656b752d676574682d3420544b656466343463616147456230323761393061", + "proposer_slashings": [], + "attester_slashings": [], + "attestations": [ + { + "aggregation_bits": "0xfffffffffffffffff7fefeffffffffffffffffffffff7fffffffffffffffffffbffffffffffffbfffffbf7ffbfffffbdfff7ffdfffffffffffffffbff3fefffffffff7fffffdfbfafffffffffffffffffffffffdffffffffffdff7ffffffffffffffffffffdffffdffffffffffffdfffffffffbf7ffffffffffdfffffffffffffffeffffffeffffffffbfefffffefefdffffffffeff7fffffffd7ffbfffffffffffdfffffffdffdbfffffdfdfefffffffffffffffffffff7d9ffffffffdffffffeffffffffeffffffffaf3ffffffffffffff7bfffff7ffffffeffffdffdfffffffffffffffffffffdffffeffefffffffffffbfffffffffffffffd7ffbffffeffdffffbfffffffffffdfffffffefbfffffffffbfffdfdff7f0f", + "data": { + "slot": "151849", + "index": "0", + "beacon_block_root": "0xcedd94fbf2ebaf371384911b85bb3073eadcca25eeb4ab29d14acd95cd88bcfb", + "source": { + "epoch": "4744", + "root": "0x810ed886bb9706fc2df193e2272e3a864eae69b43ca5797789f865b562cc3456" + }, + "target": { + "epoch": "4745", + "root": "0x9a8e0a72cf9f99379750c1c8b403c6daed6138c4577610e36d4b405f4f7e307b" + } + }, + "signature": "0xaffbe8cdd9c06cb23046969189e66e3c825ac6d0d7170334d9a5d8e7797d47069dbf96f391a86f0eb4b1c6d2eca55b34123567907c3342b4bbe31e520a0e0be813d5986f2d679a2b1f9ee0072bdbde35bf56affc060fd33556733e57103ca4bd", + "committee_bits": "0xffff010000000000" + }, + { + "aggregation_bits": "0x00000000002000000000000000100000000000800000000000000000000000000001", + "data": { + "slot": "151849", + "index": "0", + "beacon_block_root": "0x2bafda2b58819919eb49363290dfc50050f3f57cd6a0112ab4b5d4a42ba7c821", + "source": { + "epoch": "4744", + "root": "0x810ed886bb9706fc2df193e2272e3a864eae69b43ca5797789f865b562cc3456" + }, + "target": { + "epoch": "4745", + "root": "0x9a8e0a72cf9f99379750c1c8b403c6daed6138c4577610e36d4b405f4f7e307b" + } + }, + "signature": "0xa56ae375f437178909c0bf4ea632b94dff322f63bf383c816693c6f9841fb24fa7de3440fbc749cfc0c0d55e341c466b0f019dc77758dae97362c23ce1f8f71d8aab12f7491874d2d7c3e197037f313c840646da75c40577ebc0cdd239524f1a", + "committee_bits": "0x8010000000000000" + }, + { + "aggregation_bits": "0x0000000000000000000000000000000400000000000000000000000000000001000000000000000000000000000040000010", + "data": { + "slot": "151848", + "index": "0", + "beacon_block_root": "0x85f3e44f8ea07968ddbca17eafd5b6ae402560a120ce96ae8ab9f06fe9bc2deb", + "source": { + "epoch": "4744", + "root": "0x810ed886bb9706fc2df193e2272e3a864eae69b43ca5797789f865b562cc3456" + }, + "target": { + "epoch": "4745", + "root": "0x9a8e0a72cf9f99379750c1c8b403c6daed6138c4577610e36d4b405f4f7e307b" + } + }, + "signature": "0x93c1542a02328cda2a26b7a2bdf02480fc244608c232d8239a6519ab5899588b531cc383f1a6462e37167ab6b85eead40296ceda75a9da55805bffd8631642b2197cc3c2684070b68f2543ad406ff992a9f9a3f852f9a4cce664400f4a0850da", + "committee_bits": "0xd000000000000000" + } + ], + "deposits": [], + "voluntary_exits": [], + "sync_aggregate": { + "sync_committee_bits": "0xf7f7fffffffbff6ffffffbfffffffdffffffeff7ffdf7ffffeffffffffffffffffffffffffffffffffffffffef777dffffffff7ffeffffebffbf9ffffbffffff", + "sync_committee_signature": "0x86b38c811f1415024af4bdc7b60bbea76e938f326595aa7238ca047bf336ff74707e9da3052d3d376766901b2d097fd5140de9bd4a9c0a5fbd4f12e0ac6ae472d8493a87e6e9bd69590d39ef6f142f7b2990938cd56e54e48bd9a9a55e1a40a1" + }, + "execution_payload": { + "parent_hash": "0xef54f75df413929ddfa60638b93feab47a0ad57e7585069308dc3b31beb42e05", + "fee_recipient": "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134", + "state_root": "0xa694a1983a7427b1ee0524a1619573db4e8f48368d13dde2a1103142e1e77cbb", + "receipts_root": "0x72a0eed2e520b8f791fc8dcafa8a94c3e411cba82097af3fb0287d3698c7bf0a", + "logs_bloom": "0x00200000008000000000000080000040000000000000100000000000200000000000000000800000000080000000000000000000000010000000000000000000000020000000010001800408000000220000000000000000000000000000000000000000000000000000000000000008000000000000000000000810000040000000000000000000008000000000000000000000000000080000004010000000800000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000001000000000000000000000000000000000010200000000000000000000000000000000000000000000", + "prev_randao": "0xbad3a8687ee866a509e9b22c4bd16d16ac2fc5a134fe8ce3477552604e5870c6", + "block_number": "141654", + "gas_limit": "30000000", + "gas_used": "2716694", + "timestamp": "1740426060", + "extra_data": "0xd883010f01846765746888676f312e32332e36856c696e7578", + "base_fee_per_gas": "7", + "block_hash": "0xf6730485a38be5ada3e110990a2c7adaabd2e8d4a49782134f1a8bfbc246a5d7", + "transactions": [ + "0x02f9017b8501a588771083013b8485012a05f2008512a05f2000830249f094d27d57804f09a93989e290cf12cb872c39ad2ad280b901040cc7326300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000056e915d8da78e50000000000000000000000000b3db4f6329df01ac317a70200f6614e1cd0db6f7000000000000000000000000fc7360b3b28cf4204268a8354dbec60720d155d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000d0ada425f6835193b8507d7de3a77ec1bd6c5377000000000000000000000000c8ae6c2d3f6695e41b5cb149beae76600f4ac97dc080a0212407d77d016985f42a043805a755a10b29c905c7e104c4c0f4bc00f0128ab0a0153258c0796acf19214c28c4554d82022c0f5b14c324068acc895d6e365a43fc", + "0xf873836202478477359407825208946177843db3138ae69679a54b95cf345ed759450d88058d15e1762800008085034b10ee44a0797cebc48b0b84885aae6d7be2e45bb148b09f6a58c7bc35f6d4b0ed4218d4c1a0671bebb2c27f37350c18bc626f7096e22233e8243828efb5831d8de85e230f15", + "0xf87383620248847735940782520894687704db07e902e9a8b3754031d168d46e3d586e88058d15e1762800008085034b10ee43a003a4493dbfa34810445419bea223d56ef71737f28a1c821a46862b173c3a06e8a01fe9f6643b5054a85e45ae0413118dc1c0de71ead60704241fa40ed8ecb432b9", + "0xf8738362024984773594078252089415e6a5a2e131dd5467fa1ff3acd104f45ee5940b88058d15e1762800008085034b10ee44a0c8c7a7b76c6525400c1ce5d7dba14548060d36d2bc4bd846a7a7425217d66957a025449e02d5bcf26d422dfbf41bae2de5e8468d7399043c12da8bbb7f5fb02eed", + "0xf8738362024a84773594078252089480c4c7125967139acaa931ee984a9db4100e0f3b88058d15e1762800008085034b10ee43a01ff07f88e3ef809a7326f7912323ddbed12184b573230d4f269969a48602a5aca052831c32b936474c7e200297135e951b8948130a61f0064ef5bce0fd8ff421f2", + "0xf8738362024b847735940782520894d08a63244fcd28b0aec5075052cdce31ba04fead88058d15e1762800008085034b10ee44a01fd39c5fc58bff2729959025ef99dda0614160f06289efc56e6ccb0b67bf209aa002ec26712f5595db24e57dbef108c3f4e8b1863d71dc0a6746d944c10353f209", + "0xf8738362024c8477359407825208940b06ef8be65fcda88f2dbae5813480f997ee8e3588058d15e1762800008085034b10ee44a0095291ad41e987063ba52692f06dbb29612393dcb40ae89ee3571e660c65db81a07a59182d51c5d07fcd8fc48adf3667a50d9b39185619c52938c741303603609e", + "0xf8738362024d8477359407825208941cb96c5809da5977f99f69c11ee58bae5711c5f188058d15e1762800008085034b10ee44a065c2371b3cded7aee9ffbd9383f86970b06b191d93b1485991f3d25686d86c38a0067905277c21e7402e8af63e6ae6b577d9c669db4a78f61c887cb7bd4c8b117a", + "0xf8738362024e8477359407825208942aa48ee899410a6d97c01b0bb0eeaf1771cc435b88058d15e1762800008085034b10ee43a099694c115ac14278bbc982204081457ec7b12404a86010dfc6877b87a3571bffa0117d6a284e25bda56b7fa75d26ac4429c38659a8f339280f1b7df051fcea84ee", + "0xf8738362024f84773594078252089407b9d920dd8e8d83dc1125c94fc0b3cdcdf602fb88058d15e1762800008085034b10ee43a0b7068fc0a17b7f6dbef5a97f10202748f9f45be2d47a54658d0c4d7da0f0d653a03362d98c11472ab5dad42e39de5175cf756d9fe022a8d0628f5d6da7b5b7525c", + "0xf87383620250847735940782520894fcb6e353ad4f79245c7cb704abcffe2f4868424188058d15e1762800008085034b10ee43a0ed028a4990f492396d8e86f9b0b58f934a8ee54938cbed8f83d68c29752f0bc3a062ce81c4edca14179ec5ce4d046e5d612c23d59f6744599bfd6ec71deb4ce2cf", + "0xf873836202518477359407825208940d3de4256d6322683fdea9ee23765ccbfcb83da488058d15e1762800008085034b10ee44a026d858e4cee789dfedcce3d7f52c8b1e5553a59c41894652dad1fec3f2dfe7f6a04935cb6ee45e295ecbd0d8ece2860f6697786d439c1f8e066e8ceca802bc705b", + "0xf873836202528477359407825208946021752d8d9b2f221d4fea4349dea34ddbcfce5088058d15e1762800008085034b10ee43a0d68f1b33afc775f5ee8e35d72a2abfa5966f6fc6f24cbc74498cc49163554898a02c8fbf6de58c657a47db2deb478659bcc31d92ab1697b336169010d3d937409d", + "0xf8738362025384773594078252089461e296d527edc89e831cf593ec341f16197eeafb88058d15e1762800008085034b10ee44a0cbf42d8ee53861132879567876c2d3d4361a2bde5a8a03d673e8a9e02e2f2198a0315ae79bef63a5105373ab4bc82f4d981674ddf22f555a414394252de873bc7a", + "0xf87383620254847735940782520894cf7317ee7a3b497ecf634b94bff60ff91b92574788058d15e1762800008085034b10ee44a033f4bfc7c5f798824317332a8e1cbc5dc6c3008aa09cb66dd090aa3c2a5cca1da013d43f1901fe898eab79bf8491a7eeb84373a187ec4d181ff1d2e5815cdce8f7", + "0xf873836202558477359407825208947e7b519df31f77ced83eea1b16aedb6dcb0f0b2488058d15e1762800008085034b10ee43a0268a7ead7124d86048cc864fc1ae417c5bc72d569c506a08bfd95abd1a3869eea02ca3d7363cb6f6507d81f070784cb74edb060228c93f740815fe96aa7d884574", + "0xf8738362025684773594078252089488a075e0fb1c9309a200a8bf0a88b214bf7ceb8d88058d15e1762800008085034b10ee43a064a8c228105a6a32632607e256ebb266a1b4ee37fd624ffc1f1ba939cef76066a0221b7fdbf2e6eba0742990b2b6d715f813599ec7ff01cd839901424230e5b0eb", + "0xf87283620257847735940782520894c8d7cfb58f3ac02568e6505bf3fb5eb6f080703988058d15e1762800008085034b10ee449f9df05b5989b41018aae438d7cf6eaab197ac212e434f3c4d97b08a2490b802a02732feacef45e05a73bbf32caf062f0d84bc2daaef88a9527b1ffbcb44a17a21", + "0xf87383620258847735940782520894e0132e8d7b1b766e0ade5543d6c6c0b2d5a2f01d88058d15e1762800008085034b10ee43a029a831ae211d616087569490c670fe44a681465a30144626e9787ea7174d0e01a05fc1c4037e8b7ffc15ced7750833ec8771f1b4d65d1e68381c68cf9523e44c98", + "0xf87383620259847735940782520894eb674c0411db79654afdc1e131f3b6e734baee6c88058d15e1762800008085034b10ee44a01064ff856cbb0bfbcc61383cae3aed541f6fe1e011e86bb842efd25e88429539a046a0b8db35289c2285d917ec68ca78cc2ee7492d8ef7c1e11e63b64d8530c121", + "0xf8738362025a847735940782520894dc07c60993cf689438b8c85f86b0ed938dca77ea88058d15e1762800008085034b10ee44a06f9e81bd4cdb2847e729b1ef1a331a663fc7531ed74a09e59ad02920db531f2da058e52df9092b08b45e4a9b961f431af4dfbb0bd86a48cc162c3e2f0d56d5658a", + "0xf8738362025b847735940782520894110ddc93db59ed31a03518510221ec2f35d28f2f88058d15e1762800008085034b10ee43a02eade5940ccc8290dc553ef3027d086985b03a19cd97928e258c3f4f7b1523aca0549d6ef116c9932490e49144b0287b6bbb702584a17576291241ac15ffc94bb5", + "0xf8738362025c847735940782520894b599a876aaac824cfce21bdf15627c9fd8634c3088058d15e1762800008085034b10ee44a03cd476a5d252e0b18d8d0809f26fe3871b62091cfb43d08dabd0c5874dce3590a063b5231c6c7190ac4e87985d997d46ef4c8bf3177953272fd1d0df9de95a506c", + "0xf8738362025d847735940782520894d36e5540dd71acbd6416d60252c4d7c34a3c824588058d15e1762800008085034b10ee44a07d9bd59a5a4480d84722885e29cd6d33f1cf04a98dcd8e3dcf7321f0fbcbdd74a0354eadbc5e2cac079487f00d57f5fccbcea7936010a7509e6712f8ce39806dbd", + "0xf8738362025e8477359407825208943adeca35af56206a74987a8fe13c669365c770cf88058d15e1762800008085034b10ee43a0a7df3bd9baf87afa5894782cf23385baebd8128d2ff7a1a971234ecf3e6ac7dfa03c811122700ebe14becfa56791483c58a1810dcb7cdd7b3ac3e2ff0b0e1e042c", + "0xf8738362025f847735940782520894d77b95acd12f7b4b5692b55717b7bbca1165195488058d15e1762800008085034b10ee43a0d1b54826d1311a0903886ef61521910679cdaa3cfa70f14b672ea803a955c15fa05e881bdf984a03ba04042f26b46c82cb55662cb3eb23c40618e17cfe1e91d80a", + "0xf87383620260847735940782520894f388bf5766b5ed5d4e1cbf15772e677dbfa80b0088058d15e1762800008085034b10ee43a0ab360b7a78ca54508f199cce95ea4c443482716205c32237b2be1dcfd1cb011aa02fc48513039fd6fa6bd608c9dfbb1965d2e15e70ab6cd67b781ba486bab2d093", + "0xf8738362026184773594078252089435d4996296e58560e6ef47787d51b55f1e2bd92a88058d15e1762800008085034b10ee43a0621eee5a891fdd819305e26ee2a6152e752381b29f7e2af5597bca6ed0f9c441a0747cdd3922479fd516c01172d6562a238576486d0fa084b9f3e603f304b4edea", + "0xf87383620262847735940782520894a4c3b77b898e53d6095f11c53a1ce272cff9af3188058d15e1762800008085034b10ee43a0a73f452201074e6cb8fb75a74da059a7e0928fed9ded27dd17bc4cfd93a22443a0674b3c5006a65687aa6802133fd29c77e68cef8a315175f677e9b6b0dbab56b6", + "0xf873836202638477359407825208946e84f6113fc1919714f0266705813fb81a17181f88058d15e1762800008085034b10ee44a0f054fd8871770486554e18096985f02ee95c032b9be137a8e0026f619b55d2c1a02a4855957e29e3d20223cc41194d0be22f7ef7cf436df2783754147bff8a5c04", + "0xf87383620264847735940782520894e9ae1a806004e1452baae0493920815aadd8479888058d15e1762800008085034b10ee43a0b475580a478780d91e262e2b1697d1faa216effee65d00d2b6357acb47b1ac54a015abc88732edd4be13376b6f910c5b5c6c1929210bf25f384a49fcb48aeb069f", + "0xf87383620265847735940782520894fe1905d8ebd20e037274eef441283c811ea82c1688058d15e1762800008085034b10ee43a089466e0fb9624d16c977ac2d64276e4700c47ef9ff4c8cfce8c801109e8b0b77a05c6b093850d7e34da5d445e203900087275573e83681eda656e3638ec3661547", + "0xf873836202668477359407825208946adece88e477f53a143a4c29d97940df2ec768e088058d15e1762800008085034b10ee44a071f1a5b69f6c8ae0393c4390adb7a3271f99af0c01524e277690ea199dcc2da1a03e887397647eea176bb4d7f7743a0f812a1223da3b465134e4f7b47a267379ef", + "0xf873836202678477359407825208940d34d140a7376892c4593fcea3ae26f5d6f202d788058d15e1762800008085034b10ee43a044af0ef032fe68acae258743e7a913b65bb1bcecd04e3ca23ff4b1c35f8ea248a0180e9622e1cbc136d45607eed1371a21adec0f1e76c9f60ce48de13798462ba4", + "0xf87383620268847735940782520894d1c7fa75b9bc55d041fcdf215f3e3a351c9f9edc88058d15e1762800008085034b10ee44a08b91903cf64c5ea1ef70728d84f3d6c3460e9b0373e39e25e5601a859578388fa059180173244f606fb86eb64187a39db3e6eea697b8eb725d44a348523e1a48c3", + "0xf87383620269847735940782520894418ebe350a8c6387bf5e42f3502742af8e0781f188058d15e1762800008085034b10ee44a084bd185a547656a0e4d8cc84cb47b77509f857bd5de7d6c56182c143665bb7b5a068b10a9e4d24f54d7af772976d4c9806828af12e763207efa4c47e1352590719", + "0xf8738362026a84773594078252089484914d2770c711d27888c775c547b1d933b48c4788058d15e1762800008085034b10ee43a0dd2129a3c3b56301435d67d5da0e8b4e5eaff46e6d30f49608c5b5d50c5e9dfba037b1663d9a8a20bf14f205817728934e3c6f0ec10642c2d24b54e46c0e3160b5", + "0xf8738362026b8477359407825208948f51e560b85edf2e653c689c4e9fac02ce0556b888058d15e1762800008085034b10ee43a009ca07e74aa8d418f7888718ed9014b539c60efb053116aa8e02b0cfc9930e7da05eb1a866237575f7f7de2051f622a8e45192cf7ef57c143eeffac1a54dda4082", + "0xf8738362026c847735940782520894ee2503205c24dc66346e356f13f333fb8782d35888058d15e1762800008085034b10ee43a0f02a886b4bd63232f0c1247c969d3d80c4881b5ea9fc1419564e38dd67f1831aa067f136cfa69edd0fced8be030956974d94a08e3ddbdaf29129e65ebb719dbdb9", + "0xf8728362026d847735940782520894096ba6c59bd667a0fea9a356bcc988e4d9f2d8eb88058d15e1762800008085034b10ee43a0a6b9529f9e732c69e23688f6c5644dd7a73162e427eb9356a1dcf1759a6fee3b9fc127e4986c286784fde59cad6c3f1efd1c7f6d4f7e5088f5c7a74d386b0949", + "0xf8738362026e847735940782520894da0adce4f1dc7debe7b2b52e8fe9ace6c7ea9c6688058d15e1762800008085034b10ee44a0734e8f035d7479da4857ce0e09202d497d831594ec24ff722106c8c7608963fea00a1f8a360c43f0b5fd58a71a2c2c5afe895aa5a15320b052baf1b44434cfe6ac", + "0xf8738362026f847735940782520894af7d412aeab7525c0541dc3aa6c1085cfb8c909988058d15e1762800008085034b10ee43a099e288225e6dbbdc77753aa08f3efbb9f0b96d7def768d9854e855fe01610cd8a034f2d3aae0864b7afd5e691f33bc2d28083110f0111112936da8f45d98319630", + "0xf873836202708477359407825208943cf8c0d567261eaf4ac0872d33a9f48af361769f88058d15e1762800008085034b10ee44a00f20fba4abb6ee417a1f0bdbf776b0d5dbaabc81ecaaba9c58f45360208e33c7a05dde3f3f6b92919e408a0aa72937c33523734a0a2cca772fa2147273d7be1c3b", + "0xf873836202718477359407825208944779242587ba9e828999249eadd82984430f484388058d15e1762800008085034b10ee43a09b5e17f912c9fb7f803b43c2c1397b01b8ab205ff682a4423f0a8214a2e79197a0521997071cda90e04ca276220e6f7dcff723c5d27224528fa3601ef3a2221494", + "0xf87383620272847735940782520894ea531cfe2de357ecff3855b88dbd07f60b03cdca88058d15e1762800008085034b10ee43a0022fc439ceef6778c85bcb9b86eca5cbfa6ac349baa54887159c8585af0e6ecba01080d90e6b555cccd88b693af79881d7f17247b01b3ca62c281c7ddf200ecc79", + "0xf87383620273847735940782520894d00b5f53ea2a66ad33c3fee304bb22857dfb8a8788058d15e1762800008085034b10ee43a042e9e53473b2553d37080c3a8836b183ec8f3b41f47e9bbec02e3aebb7dcdfe1a070bafb99da6e92cf4090bff7eca3c3c8044cb46a9f05f544a0b56a521255d324", + "0xf873836202748477359407825208947ead29f6616f78f21a951c9686dd257be7b8efe488058d15e1762800008085034b10ee43a0a04cae14d43584a0fed384fc6d981238e3cd2302a7fbdbc5245192068abed008a05aef32306b51b2320199e8f3f11280bae5f677b99907b6244ba892d1d441ec12", + "0xf87383620275847735940782520894d503c13ee55c1ea128357d4018ec58d0d5e5c3db88058d15e1762800008085034b10ee43a0e280df73654670e3cf5ae5aeee1e1931e98cf29ff874ce7d32790f8233d5b287a01892f9b5e6902f7dde4411566c1ed3c499703b0801a0c4b1a9dc1b023d6443a8", + "0xf873836202768477359407825208944ac670d8760faf780468638ef80034876ed8918d88058d15e1762800008085034b10ee43a0514dcddc1910947d09fa8a6c0e6f6cf7d05fb4d5bf158bda354d2e6c6348d581a0047981492e9b9eff0ea70bacfaecba069aa2b2c5269c8469cac42d9b11d19383", + "0xf8738362027784773594078252089424ffb8c97ce443f8d3265ba3316defcfc07c659c88058d15e1762800008085034b10ee44a07fc741180d071dead819a84ba1be1f2eeb518caf707ceadeaad03ea9edecc80aa060eccb7fc130827b061d57c5fb3e168a30dccc1fd4ba6b69df65cf82f78a6bba", + "0xf873836202788477359407825208940c5cafc547ab98c9ceaa1c07fdd6bf7820aeb95488058d15e1762800008085034b10ee44a0787e06914cf15a0d5c805c92ee953eba7efc3f9ba09ca62d0ed2f3b6167ffa60a014fa025423178902bb480a1823bd9cd17a55f7c2fedac8a42f81b834c4f5b547", + "0xf87383620279847735940782520894db8d964741c53e55df9c2d4e9414c6c96482874e88058d15e1762800008085034b10ee43a0ee3e494f464ab6384f2a856e3e4a82b581b60dff1494c5d31d8ffac33133c4dda00fe28dc8352736880aeb0df3b34c846d9e48e056f0ee34115866abd2e4cb9cc9", + "0xf8738362027a847735940782520894ba85bb35ae6ff7a34745993fcf92b9afd34124f188058d15e1762800008085034b10ee44a0697c551925faba103e19343af9b1373c15a915c94c2c2b2248754707ba6753efa0195134d1de635393b68258bbc3a6130da2f6f28e3a21f53cf7c0d309e8604a91", + "0xf8738362027b84773594078252089458871015f5a2d3948264f7c16ad194c80ffd531d88058d15e1762800008085034b10ee44a065fd5136b42302cd12e08ce81d4bbbac0bedb774eb07df3ec89e10d1bd0e3eb3a053ef3a9a4b6b0fc0afc2aa8f0fd6eeeb0f8d79df5010395e68401b34a9c1b932", + "0xf8738362027c8477359407825208942a90af45df70b0031f218cc122598ddf3e10469f88058d15e1762800008085034b10ee44a0b8318c8dc899f7a1c0c57fbe9199901c927788d51460a971328870dd05516748a02811349e21979f97393c1c0707f508bcc9edf7e8932a2058c62fc503c6e298f9", + "0xf8738362027d847735940782520894761bbaaea6ceb265f5262c3b559adc2ad3ed2f0988058d15e1762800008085034b10ee43a0ee810426bf67a8873cc6dc0f41887bc6dcaff093a620b980db51343e80b828a6a05fdaf2729c1dee2029a5bc9174920d1bd16a253e2a20ab69fb4cce9a22bbcb44", + "0xf8738362027e847735940782520894dfe86f51c5e603f1420d1f0ab366bd3bfe23d2a788058d15e1762800008085034b10ee43a053c6702a09db8bfbc3560bc380816ed7c119a95700fc9cc7cb44c631637876aba02bddd96beafe8592027d38a9596efed58b08361c863a905fabf4dac4b6fc22da", + "0xf8738362027f847735940782520894d616547158b05ab5079106dc0336d72763a7287188058d15e1762800008085034b10ee44a05fce463f3ede6e6ea82f59b0e2f1356aa6cc9e4a2092186ff4eeac6144f3d70ea05870f706fea0bb3e813e3ecdacdaa82ad6234cf8cc051d15b0aa5fc041943aff", + "0xf87383620280847735940782520894dc68cd278cb7f5f666ce7b0a3a214a8540ed4dfa88058d15e1762800008085034b10ee43a0e376459fbce80ca4941fdeb313efbe587a7567cf3a34c477df38b7409b043e69a03ba4f66d19838df4276344d1c44253d83789e1c77ee8a40d4c8c447789723386", + "0xf8738362028184773594078252089411f8107da05b6905e8cc0227ca3b0c6eb764fac088058d15e1762800008085034b10ee44a03bcb59ba309b004c55ba3df3eec064e22fcfb5a57c8e5ca0ff146bda02774a75a07ed6d73ad8a0daa1f1c98430ad5e5fbdb4748554c8ffa0233638077e79deac03", + "0xf8738362028284773594078252089404da906545679850a7ee0ef6836e183031bedc8888058d15e1762800008085034b10ee43a0094da8f36bc9c6ebb5f92ed23a48067f0efc5307094da7c5890a942f654748c2a05883676b2416160acf153351fc86c771a56bf4251aa134897a73cea3c3f4f7b2", + "0xf873836202838477359407825208948bdc25c43c010fd3db6281fcd8f7a0bed18838e388058d15e1762800008085034b10ee44a0dac96e3d17998ae7886f80455c92444fc078f832b424e31c7c4d1cc1c09d5d2ba07104abf0bbd8433c357d0ae0d9ddfaa3e7d8dea15644912d51931b448bbfdada", + "0xf87383620284847735940782520894af16f746b8a834a383fd0597d941fee52b7791eb88058d15e1762800008085034b10ee44a0294814d951013410c28b152df0361a6bdf245cc987ab30a7304251188641d609a05a530ee23d27f69768191325ffe65582ece63791bf09fe197f504fa57bfd5146", + "0xf873836202858477359407825208940c5c736600f8ea58ccb89aa72e3f3634651fd55188058d15e1762800008085034b10ee44a0c1e93262c0f669d8dcafbe0b69d6fa444595b9991e0ab2d643ca82c32bb95779a07890187282502da60706b81047b42099ec2fcf12f967cada17ea595b8d2d50bf", + "0xf873836202868477359407825208946f475e0f0e9eda58556fddc04de9b1a9b6a4cfb488058d15e1762800008085034b10ee43a02954b5ef28644f34235fa8a78138f8a20f451ee904bbcb557ee0d6a57aadebbda01e380d4925b3eeafe722cffec0811d4b546f2962dab2415247a609d017aa6830", + "0xf873836202878477359407825208949b2e76498a695c4dc7d0890069cffa84a9581d2488058d15e1762800008085034b10ee43a0c4c1ad80c72b77662bdc60e5d9d2f8a7d4f7d5e591f7d36bf75792603c350a48a075948e3ef779497e000693a717ebd926dc2f1040a9fe108067b827470250cb5f", + "0xf87383620288847735940782520894e2d2b2069f4a54fcc171223ff0c17adbd743c28588058d15e1762800008085034b10ee44a0c081205b252b273039c2e97df9831d3f3660a5d9c6432de2d9005d24bc1c949fa015a60d2b5a33cbc1d41626d844ab093695cffb1d445a7059bc30a0ee70130bba", + "0xf87383620289847735940782520894386bd49f04322544f3c7178fa5ae1a24b947b45488058d15e1762800008085034b10ee44a02a76823c284c6d383ce1605f433ee24e9d25755d9914355e7ec0a2e747a31aaca023bfe68b343ec5da856c221a08e42325e2fd465cafa52872885e471e87a26783", + "0xf8738362028a84773594078252089400af839c3fc067fafc2e0a205858d6957f0dd18d88058d15e1762800008085034b10ee43a02dd6ac183d86166f2d48f9e5798998beb2492203130dc29a8ccd60d682c68241a060f45d781a16584462adde0ca311cdd99a0c46c8e96c772e10dec6e21958ca64", + "0xf8738362028b847735940782520894ebb6d32a650afa9221b55a11c6a6de52b6f07cd788058d15e1762800008085034b10ee44a0d7d9588987d423ddf1180b35560d0cc8c350c4eddf3b4f04d491bd952d1ee939a07b95e674b777c204738e34c332a4c96e067d1fd530ca4e17196c9c8a2a84428b", + "0xf8738362028c847735940782520894011d26a3a9adc9203c8943a6a77aa8657af5242088058d15e1762800008085034b10ee44a0780c40f1a71ed2631a01df292f842ee8a8dc98d1b80d0685d92ac22dfc2fffe2a051a4e8f7bae167c3124d47938c54639fff25e9b159507881f6b9d891eb50d805", + "0xf8738362028d8477359407825208949c85bc61a89fb5abd957e6c819c653fc1aa0d11b88058d15e1762800008085034b10ee43a0f041d0b9537468ebf005b0fad79296b1b74e63af050e13f31999737130346deba02d50794faca4b4e1515287ae2690e4d7b7855f29a56a6d644f8c828b6d30a997", + "0xf8728362028e847735940782520894bd8e8435b7897d87cf7cedb5cf8c5dd865dbf72088058d15e1762800008085034b10ee439fcc0821fc19eab1c1e6e15d7447aed84f079a3d178cbc9e865e6009a58b558ea006d296a4d03301ff9663336813b95368dd3553f88d2635ec7559416445f214b4", + "0xf8738362028f847735940782520894adebee2e3ff041078b62380d001c6e51b4f1559888058d15e1762800008085034b10ee44a0e67f178fbd1a91014a87c50bf50898474c1fd80cc782aa05cc2d7efc427d5c13a045ddd298df67dfac72dab9b255066e81b4a1a7988e61b6c3b0318b788733e0fd", + "0xf8738362029084773594078252089471e94c459c9f05085fc0d34b5f21e648e05dc6b388058d15e1762800008085034b10ee44a0f16ec0330912b815ea3ad0d955766eebe92031c7a2d64bf786b7f55bb4f63798a03d03f718b4de0f491a08315e6fac7fe9ee98098ceb3d27ec4128da1f4b4f8153", + "0xf873836202918477359407825208947c1fe317db82c9298b87c56c3194178271b621e188058d15e1762800008085034b10ee43a089edd1266f626652a65dddd34bcecd33cf0975ad6664cec15b706910d41d23b0a055f7752a91aa4759e5c84a4bb2180ac78810ef99246e52e8974fea996efaf8d4", + "0xf87383620292847735940782520894e069d1c9abf5127bdc3a164fb93b96bfa9f74ce088058d15e1762800008085034b10ee43a00a809e015ed5159d60be66d8b65efa57f72be941e9928d889c6be888096896e6a0724239814c01e730b19dd093cee6384864964e59d34d84cf1e9a8116a11a7155", + "0xf87383620293847735940782520894b9bbddd1eb6ef8fb1bdc6a853d5ad7486a9487dd88058d15e1762800008085034b10ee44a08717c8d1194e516264fb1ea3cb78b73f5dd507d17823eff675c97bf304a90b2da05a96d1bfd29677fa4e97fd37bc4e4962a9ab6f99fcf1c74bf4749a97adaf0e3c", + "0xf87383620294847735940782520894a804387cdaf986d45831e8074efb2115af053f7a88058d15e1762800008085034b10ee44a00d92c86dad2165ddae28c5081638c3eea7a54bf7c15f75d2e3a0d52af40d3c97a043c833c190d2e78ce01fa96a331e475fc41f7b51622bf4f081e4831de49ba07e", + "0xf87383620295847735940782520894f23501d784a041fc911b4c86c2bfb1f63ec170ea88058d15e1762800008085034b10ee43a05d27e028f1ef0555f022f214e222a33266971b98098643ba84578f70598781f0a0548bd8b2ba26f7f4b96bea6187981f5af5c36cbe0c57558d6144eb7590668a70", + "0xf873836202968477359407825208943928be2a7058088313c0fb3294014e88a3c5ed4a88058d15e1762800008085034b10ee44a092c573d072e4fbd59fbe85d740fb99b1cc94a97c0896020b1eb4c50a0c1194b2a07edd4babced9ec70bb660fefae771aaf3244341da1e3123b42e6885a933c3d2d", + "0xf87383620297847735940782520894196aa07204141478459c14106ef5e5282efe995788058d15e1762800008085034b10ee43a08d6b3fa7173e77e69d0c9a851396dd8b457d32e15a916082002f367acc0605bea06c7319e1eabe15b1887633080dac1be3e3611861e2ead80487a0858b24f2f9ee", + "0xf87383620298847735940782520894763cbf89560e2da270000822abda9584db693fa388058d15e1762800008085034b10ee44a06a92950880b902296ea1c6d8ade6011d7249107a520c4935dee51dd59de41389a04701288ac10e1ede1468e197258e7b38a5157ed96cffdde2c99314fc9e64e260", + "0xf873836202998477359407825208947feaea0ff70ffc9eec2104f57f7136aff4dea68088058d15e1762800008085034b10ee44a04d90fec69d1b3ffa4e21a81a12bde21223baf92be9c972ec983454d8271870a0a0159b7c2b5238c515755b3f7812afbb5d4726a957a9c9767c3d4c044f83274185", + "0xf8738362029a847735940782520894e5466aacd9dd6d3bb35060a1ccc76a438de88ca188058d15e1762800008085034b10ee43a0837538d8e417194bed46f36eeba282fecbbb58bcbefc6f7e018c42a73ae81345a038b1d65f0d27ade5bf1d263fb67c758e76d1ef797cca936f3412e355074fb994", + "0xf8738362029b847735940782520894f670980415cfe8c4f8d10645ecf974c9a2fea00e88058d15e1762800008085034b10ee43a0ac3f8bba9b19c4d9a3a0d03ed515f81da94b6ac72284b4d8a27c4922aae659c0a078c566cccfde53296c238d408e0ab3dd4a07df1199c12b673be05e45195bbc4e", + "0xf8738362029c847735940782520894a29115bce7829ffdd989b7cf1bdd1eac06a2cb3688058d15e1762800008085034b10ee44a01edd6db1f63d1c384edf6bfc0c3253fb8bdf175c913b62fc5d0c76dd2c7bd411a004a5ceb0c53728dbefccd21e5342f25e90fc4e3de69661a96a2b6e8eabe99580", + "0xf8738362029d8477359407825208948f528aa67dc1846c893465fa1c8c26556bc5fe1988058d15e1762800008085034b10ee44a0b8eaa2b524d2970d341996da7babffdaf92160c755e9b4ba6e453e800a93c5fea05b0bf41c26aefc1fa29539c34d32f42174fe27846ef4ea8427f9f64414ab2994", + "0xf8738362029e8477359407825208944dc4ec6ac43c8c45777292db987203c0248e17b788058d15e1762800008085034b10ee43a061f4bd7053ee4bcc8d1a3edf748d9d3a585134c1fa61129951a094d5069705a6a03e45012ff902405e6c78e0e7d8be2abbc079b8c79af32022f3f6ded85a023a22", + "0xf8738362029f8477359407825208940d2f39f251cb547cba567a31e5e9f93c19dffa8588058d15e1762800008085034b10ee44a0bcc76559b8384c5f31678d1efe17f1c7c9267ee4e50c688421fe269a18ff8ab5a07ededd086d4f210c05ac901c987a1b30106cd76e7cef0a6723bb1dc1b20ccd30", + "0xf873836202a08477359407825208949eb31fb94ce5111e2a04cb9d156b513887ccbd0088058d15e1762800008085034b10ee44a0deb981e565672e01dcc8cd6514c459fd3936380d87f7fadb2660f7c350ac2e51a014849dcb352073dc9663c0a289710145efd7428cbe0c88213611432761ad93b9", + "0xf873836202a184773594078252089404b88ef83f8c41b1465d360a1e82f07ae190892a88058d15e1762800008085034b10ee44a07e3e84ca883d7d8d4e51f36454609b4e6b313a98ea8d226d47682612ae87f812a052687dd82b4f62e8449f7c0034b950e82c78aab8a5518592ba5b652c72b36017", + "0xf873836202a2847735940782520894af23e04b04fbe15630eadd32a6f27a5a65ea554a88058d15e1762800008085034b10ee43a0b90c86c8c6d5254ebdb8b82640ab629ccd6eb9acebfcf53b931949872d9aa6d9a02cbee4611a01bc2d694b3a3b86070ef762b497fbb2b9a9c3bca6b8c0112f97d4", + "0xf873836202a3847735940782520894746cdff371e3f1e905b3ac52280078bac2dec7dd88058d15e1762800008085034b10ee44a0751ea5aa4636525bec891fd848390f6e032587d1bbda675c0e393e410844a1d6a032fdeac6961819450d3059c61f97b60f5cd50e27a18c392539719af3f194f53f", + "0xf873836202a4847735940782520894c33e5155bdbf1a0a7ceb1b80f8586c5cda5c378188058d15e1762800008085034b10ee43a02fb25f3cb803a573ca57d7782a90267f5e2e92fd018f01fd7c5152beb3e2e179a0732710f218d2b8fa87143dd9c10e239aa7269da3dd08ed081cdef99fc28f2561", + "0xf873836202a5847735940782520894e7fdef5f5219068f3d0f88a7445005574c66279888058d15e1762800008085034b10ee43a0f06655172c1d09a30c06930a24caadcd736beba5b63aa137ef0701e57820bceaa01821754fd8180b0ff357c500232f2008e703d2ac6b6fe0a14c202a1c039bdcc7", + "0xf873836202a6847735940782520894f0a81a63c5e09b0bd08e027de48058e377d3732d88058d15e1762800008085034b10ee43a0443ce407a5a49665e5b7847293b62446a2bf6d5885309b75c72c93cc715f8202a05151017b926df1bcfff2c3309e4771f2310b5ed0ded4503e6c4e57d78cc2b380", + "0xf873836202a78477359407825208949878ab34dc3b4a63c80fdb733491472c11d59a5688058d15e1762800008085034b10ee43a084ae376d4ecb7d0e23df6dd426999005f05fbcfffb8e1916d13e53f492fa058ca03b42dfaf1fcff5912e20d3bc9d0e26f61ca37a0c2647a62d20e443db23ebf400", + "0xf873836202a8847735940782520894912859bebae3086ac7a062dee5d68aa8ed2d71ec88058d15e1762800008085034b10ee44a0e9172415691d94476adc2c2fb0b5d68285ce83ab024dc53166f870decec3a4eba07e5f2f8a52145948789e57e3311da5edcbf563307ff0987342424f4e23055673", + "0xf873836202a98477359407825208945a0b737ed85049410e5ea61f444d07d5c8c0359f88058d15e1762800008085034b10ee43a0db10a0538cfe66a2152e6ed531eb5be016ec5f1cead127b91b8f123e54efd8e3a046c6477c90bae429b65e594b254a396bfddfdc15e1e3cec9ffa26a46a4884ccf", + "0xf873836202aa847735940782520894305a5dfd46e6128abce28c03b3ad971f4e4915ff88058d15e1762800008085034b10ee43a074cf4ff900d6170b4266deced030c14cb92d9872837e9cbae3b768c3f561d1c8a0252ba383431d7108ac2402bc6f8f807177496bd9997643994a9c33dfeda303b4", + "0x03f901198501a58877108216c784773594008477359407830186a094dba34be211bf539e27107cbe7e6893770280aec580b880297fb846f12a980aebe1d5b1187b2e6660f3e68f457379b59395a0411b9859c25842606f527f16e565e886e3afcd0ede18e04e3c827adf9e5c54db37870db32c31a18813d44c608f5260b660af53605b60b053605760b153603060b25360f060b35360e760b453600060425d600060c95d600060895d600060e95d7f25818248c0830f4240e1a001b7f74a7d5bae21aaf16e7b2d2ca7f47c800636b2a3f8b519aabb4b3541708801a0faebdfbd5a7832abed65c7fe25ffdb498b0c19c70cd53a1ec53e3de6c25ca0eaa03690227cf2f99e38b48a44f739fd63b00482017bee063657b418d85e68cd2094", + "0x03f901198501a5887710823ba784773594008477359407830186a09409fc772d0857550724b07b850a4323f39112aaaa80b8800a7f9b44ddad8f17bce75dceb28c1eafa80fbfaf4e0d793fc9fc42489c913ffec7906023527f0d1debc2884eec1a57d882e7085ae952d5d76b3e168370cc9af6294ccb55a7ca604352606460635360d96064536042606553603a60665360f1606753609160685360cb606953600c606a536055606b536043606c53603b606d53c0830f4240e1a00159f296fad44019f3cfa307df01412afa1643a67ccafae96c83d43b6758ffe080a04b6af5cfdca885787b508751e15ebeddc4ae4f5e88035002a72fe720ed9c1808a07781ed6c6f1778c74f692c9b966d1c27185045042cf386eab20543852afd7d9f", + "0x03f901198501a5887710823ba884773594008477359407830186a094000000000000000000000000000000000000000080b8801660f660ce53604b60cf53601260d053600b63df83d68853600263df83d68953604f63df83d68a53601b63df83d68b5360b263df83d68c53601363df83d68d5360f663df83d68e537f93ad362c9daf922157be015981847c3d63de3a139a88e7824d2c62693233acba60e4527fb97203d3cc1f05cb5b3a18ba38b93d6eae2675c0830f4240e1a00125c14e94773c0f2504208d25925d0def274e4cd05be154b64484cd55068b9401a01f25239f9cf530e73210788333c06832ede4d25811fbd5288f1c6ec09626a848a0142054f5501636d093d1f8fd9a18991a035ff8272ccc4b732e618929c5ae60a1", + "0x03f901198501a5887710823ba984773594008477359407830186a094000000000000000000000000000000000000000080b8807f1c1e1707ec5a3c08643377106467f9d8cf7343cddde951134184de69c4a0ab5f60cd527f496d383985b30e2192e37082533c4040429f17d2d8066cbbb0df4ce5f1bcc72760ed527f934a6a5a54f24b814ed3df79092d3215e14b5fe7c1ae730e377b17777e7d3afc61010d527f324e451356f8780882a2abd81a56fa0ad656c0830f4240e1a0017fde88c70f2ed440c9dbdcee3973e4d7b85d3a65a7d3db7289a2a16db2f00480a0064a83db9cfa03f6af8b2e48c5b383d57f3de72c1a556bdb89f84ac5a33ef294a07a99426dd140e3f729bf681e9493c93b9f5466afab8bd43b08d44b83121e2c66", + "0x03f901198501a5887710823baa84773594008477359407830186a0947a40026a3b9a41754a95eec8c92c6b99886f440c80b8806000603d5d6000605e5d7f2a4466d55bb88fa289d012628a52864aca1c1e1707ec5a3c08643377106467f9606d527fd8cf7343cddde951134184de69c4a0ab5f496d383985b30e2192e37082533c40608d527f40429f17d2d8066cbbb0df4ce5f1bcc727934a6a5a54f24b814ed3df79092d3260ad527f15e14b5fe7c1ae730ec0830f4240e1a00122ad5c899f52d21eba94a21044753587639cf91301db410de58f73d740feef01a02d622199b408f02048f237a3cee8de1cbe7c79de5fe0342f1a6cba7d9d5c53cea012cae1d118329a17eb3cef8d2a24ce1a96afdb6ef7c0fd58f11041f9ebb458a6", + "0x03f901198501a5887710823bab84773594008477359407830186a09401abea29659e5e97c95107f20bb753cd3e09bbbb80b8807f1fcc4bfabba1d810c2e9750fe5f9f3c70adf76d7a54bdf886617f1a099584d2860d8527f410b6d3e2670b1d7b668f22f9b6d1e5bb1b4d12d4bc198e2b642cd9eef1ebf4e60f8527f753d66f7de6d60873b96cac74055a2c05f1822dd662fe1e18b5962e191d8cc88610118527ffd19563f4930341b9ae50f37f40c3519b4a8c0830f4240e1a001ff78fe5af972c7cce1be875aba37ff8b7367ab34a0879d0fde2873c1c34e3301a013580cd6864dabb7ae62de736772696075a507b26d352eecea97581662b11762a03a47f80d8b09c0ed5686c0082aeaa569bd7200bb6cd4a89507c391da4aae8882", + "0x03f901198501a5887710823bac84773594008477359407830186a09401abea29659e5e97c95107f20bb753cd3e09bbbb80b8807febcd375a4548f911bbf94fb20a71723f2bcdf90b1893dede0d86ea0086c94f4663ded9bec5527fa75fc1bbd45e9a2357080a88f65a12c678ad697d56a558ddc54d4bb74c6c6d2663ded9bee5527f75eaa5150042917e755fc935fc3a8af87bf91944c7e3f00eebbf3a6574e80f4663ded9bf05527f27014ac42049105c03fbc0830f4240e1a001466f18955590485e681c566fab7923ffc11c44febd37dfa460e4ae57b2bcc301a08ac71347df4693d6fd98be1cfbdc5b7cc1ddc75f2512d1b85df24c9e1c754563a02145852bc429244eb4311fa25b529d4245e0a1b79581e829e251f92edaaf209a", + "0x03f9013b8501a5887710823bad84773594008477359407830186a09409fc772d0857550724b07b850a4323f39112aaaa80b8807f9e664ccecd377f7cccdc8eacb44927d06ad21fa62b767c61a984a997b503e76a6021527f9884bb7e3c5262eabd6dc6f0daaf38581cc4e7387f25237ef70b3765d9f7f69d6041527f263c0b0f9697916d24f51e6443f9ddc9c00ee8795c6563b153305d4e889ff9336061527f3a7664aab6aa9ff375049c342739cf230af714c0830f4240f842a001148d696bf857b798a51d3cf76e1f30c0ff18dbdb67b4e4651ceb9a81bfe319a0014516a223e4dd099c56e3320d0f6b50e061e00a6548964a52ac15bba57028ed01a05077e103e2aabb0f6f8712c96fdee81a4a4b8b53404286535eb188b02be775dda021063c5abd0394b12c6935dd209bdc413472f558539469806e5baffeea1d00ef", + "0x02f8a98501a5887710078459682f008459682f0e830137a19400000961ef480eb55e80d19ad83579a64c00700201b83882586e0c10f84614733e5752428cbbe809e3699d9a3bc5bc604e81169e6a59304352237e39c8e6644acae5f595f1a8640000000001312d00c001a01d67ab7c6569f238adca00963a31b5bd856960affb9d738ceb78085800ba29e1a0495ad28ef784fb388e2145af0778bfc08386cb0695d1c0ca1022fabff8ccd9a9" + ], + "withdrawals": [], + "blob_gas_used": "1179648", + "excess_blob_gas": "68812800" + }, + "bls_to_execution_changes": [], + "blob_kzg_commitments": [ + "0x82b6012a3307f01e0ec06ce5768f093c75b731e81aa16f08afe60e2e457e2f4370f13ea15baac9c10ad8956cb1599f47", + "0xa758a4d6c5dd35ec363c80f21dbee519db19aa0f69c1318b70dc01738555b97f7607793d072946019e4050b8b8e5105b", + "0xa49b025f2a1c657f4c07df7cb04d430aeafacdc1cf9afaf841cdcb019ba3f61d6151241fcda0b2851f9d5adcd2a67bdb", + "0xb909fcb4f35d2bdb684643f0dc3fbaae73024b7d2e771656cc0117fe34143aa29d882454285d340dbb1c6dcd1cff2d0c", + "0xb9c826af3dbc163bddc7bcd0230b87f57193bf567ee7fa35fc17f970dfe620dee074c61776fb37fc19958996e5cf585f", + "0x8ef3c784f8070d96f4a834640b6d76e589508ac121177a323f49b3a1073b9592d23464487a31a36974c8e571d8573d46", + "0xa8ddab3b3301512e74e7d83b472af200f35d4b8a4df6ea783363035e2250a90ba473f31ea382c4c275e9c37621098dd0", + "0xa33e2ae43573502a30c5f98a9a33c8a6879333f96d24fdff686544fd01b99130114d741e076ff873fb649fe44ab5e81d", + "0x8f01d73cad9ce715598a653f48e9b9003abf2d2084890fc722c1eab65a4678146e81618b84d227652513723f4088cda3" + ], + "execution_requests": { + "deposits": [], + "withdrawals": [ + { + "source_address": "0x4b6C4667921A132eE6eD26a2DE7654adaE481E4d", + "validator_pubkey": "0x82586e0c10f84614733e5752428cbbe809e3699d9a3bc5bc604e81169e6a59304352237e39c8e6644acae5f595f1a864", + "amount": "20000000" + } + ], + "consolidations": [] + } + } +} diff --git a/go.mod b/go.mod index bd27a56e8..2f5f7a3fa 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/pion/stun/v2 v2.0.0 github.com/protolambda/bls12-381-util v0.1.0 - github.com/protolambda/zrnt v0.32.2 + github.com/protolambda/zrnt v0.34.1 github.com/protolambda/ztyp v0.2.2 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible diff --git a/go.sum b/go.sum index 67779bd92..053e13aec 100644 --- a/go.sum +++ b/go.sum @@ -482,8 +482,8 @@ github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/protolambda/bls12-381-util v0.1.0 h1:05DU2wJN7DTU7z28+Q+zejXkIsA/MF8JZQGhtBZZiWk= github.com/protolambda/bls12-381-util v0.1.0/go.mod h1:cdkysJTRpeFeuUVx/TXGDQNMTiRAalk1vQw3TYTHcE4= -github.com/protolambda/zrnt v0.32.2 h1:KZ48T+3UhsPXNdtE/5QEvGc9DGjUaRI17nJaoznoIaM= -github.com/protolambda/zrnt v0.32.2/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= +github.com/protolambda/zrnt v0.34.1 h1:qW55rnhZJDnOb3TwFiFRJZi3yTXFrJdGOFQM7vCwYGg= +github.com/protolambda/zrnt v0.34.1/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY= github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= From b589e0f73e69e58a8f761396c258ccdf5eaf38fa Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 12 Mar 2025 05:30:02 +0800 Subject: [PATCH 194/354] ethdb: no need to check the metric nilness (#31353) The metric always has a value, no need to check for the nil. Seems this code was first introduced here https://github.com/ethereum/go-ethereum/blob/054412e33528e53f6deae940c870217b614707b9/metrics/meter.go#L45-L48 As the `nilMeter` was removed, so this check seems is useless. Signed-off-by: jsvisa --- ethdb/leveldb/leveldb.go | 32 ++++++++------------------------ ethdb/pebble/pebble.go | 33 +++++++++------------------------ 2 files changed, 17 insertions(+), 48 deletions(-) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 1d88ed460..7f47523b8 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -368,29 +368,17 @@ func (db *Database) meter(refresh time.Duration, namespace string) { compactions[i%2][2] = stats.LevelRead.Sum() compactions[i%2][3] = stats.LevelWrite.Sum() // Update all the requested meters - if db.diskSizeGauge != nil { - db.diskSizeGauge.Update(compactions[i%2][0]) - } - if db.compTimeMeter != nil { - db.compTimeMeter.Mark(compactions[i%2][1] - compactions[(i-1)%2][1]) - } - if db.compReadMeter != nil { - db.compReadMeter.Mark(compactions[i%2][2] - compactions[(i-1)%2][2]) - } - if db.compWriteMeter != nil { - db.compWriteMeter.Mark(compactions[i%2][3] - compactions[(i-1)%2][3]) - } + db.diskSizeGauge.Update(compactions[i%2][0]) + db.compTimeMeter.Mark(compactions[i%2][1] - compactions[(i-1)%2][1]) + db.compReadMeter.Mark(compactions[i%2][2] - compactions[(i-1)%2][2]) + db.compWriteMeter.Mark(compactions[i%2][3] - compactions[(i-1)%2][3]) var ( delayN = int64(stats.WriteDelayCount) duration = stats.WriteDelayDuration paused = stats.WritePaused ) - if db.writeDelayNMeter != nil { - db.writeDelayNMeter.Mark(delayN - delaystats[0]) - } - if db.writeDelayMeter != nil { - db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) - } + db.writeDelayNMeter.Mark(delayN - delaystats[0]) + db.writeDelayMeter.Mark(duration.Nanoseconds() - delaystats[1]) // If a warning that db is performing compaction has been displayed, any subsequent // warnings will be withheld for one minute not to overwhelm the user. if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 && @@ -404,12 +392,8 @@ func (db *Database) meter(refresh time.Duration, namespace string) { nRead = int64(stats.IORead) nWrite = int64(stats.IOWrite) ) - if db.diskReadMeter != nil { - db.diskReadMeter.Mark(nRead - iostats[0]) - } - if db.diskWriteMeter != nil { - db.diskWriteMeter.Mark(nWrite - iostats[1]) - } + db.diskReadMeter.Mark(nRead - iostats[0]) + db.diskWriteMeter.Mark(nWrite - iostats[1]) iostats[0], iostats[1] = nRead, nWrite db.memCompGauge.Update(int64(stats.MemComp)) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 8d6fcd2d5..b87ecb259 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -465,12 +465,8 @@ func (d *Database) meter(refresh time.Duration, namespace string) { compReads[i%2] = compRead nWrites[i%2] = nWrite - if d.writeDelayNMeter != nil { - d.writeDelayNMeter.Mark(writeDelayCounts[i%2] - writeDelayCounts[(i-1)%2]) - } - if d.writeDelayMeter != nil { - d.writeDelayMeter.Mark(writeDelayTimes[i%2] - writeDelayTimes[(i-1)%2]) - } + d.writeDelayNMeter.Mark(writeDelayCounts[i%2] - writeDelayCounts[(i-1)%2]) + d.writeDelayMeter.Mark(writeDelayTimes[i%2] - writeDelayTimes[(i-1)%2]) // Print a warning log if writing has been stalled for a while. The log will // be printed per minute to avoid overwhelming users. if d.writeStalled.Load() && writeDelayCounts[i%2] == writeDelayCounts[(i-1)%2] && @@ -478,24 +474,13 @@ func (d *Database) meter(refresh time.Duration, namespace string) { d.log.Warn("Database compacting, degraded performance") lastWriteStallReport = time.Now() } - if d.compTimeMeter != nil { - d.compTimeMeter.Mark(compTimes[i%2] - compTimes[(i-1)%2]) - } - if d.compReadMeter != nil { - d.compReadMeter.Mark(compReads[i%2] - compReads[(i-1)%2]) - } - if d.compWriteMeter != nil { - d.compWriteMeter.Mark(compWrites[i%2] - compWrites[(i-1)%2]) - } - if d.diskSizeGauge != nil { - d.diskSizeGauge.Update(int64(stats.DiskSpaceUsage())) - } - if d.diskReadMeter != nil { - d.diskReadMeter.Mark(0) // pebble doesn't track non-compaction reads - } - if d.diskWriteMeter != nil { - d.diskWriteMeter.Mark(nWrites[i%2] - nWrites[(i-1)%2]) - } + d.compTimeMeter.Mark(compTimes[i%2] - compTimes[(i-1)%2]) + d.compReadMeter.Mark(compReads[i%2] - compReads[(i-1)%2]) + d.compWriteMeter.Mark(compWrites[i%2] - compWrites[(i-1)%2]) + d.diskSizeGauge.Update(int64(stats.DiskSpaceUsage())) + d.diskReadMeter.Mark(0) // pebble doesn't track non-compaction reads + d.diskWriteMeter.Mark(nWrites[i%2] - nWrites[(i-1)%2]) + // See https://github.com/cockroachdb/pebble/pull/1628#pullrequestreview-1026664054 manuallyAllocated := stats.BlockCache.Size + int64(stats.MemTable.Size) + int64(stats.MemTable.ZombieSize) d.manualMemAllocGauge.Update(manuallyAllocated) From e73db7196c560616b50bcd00fbefd3a32e5cdba3 Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 12 Mar 2025 19:20:40 +0800 Subject: [PATCH 195/354] cmd: ctrl-c to halt the whole import process (#31360) When I press Ctrl-C during the import of multiple files, the import process will still attempt to import the subsequent files. However, in normal circumstances, users would expect the import to stop immediately upon pressing Ctrl-C. And because the current file was not finished importing, subsequent import tasks often fail due to an `unknown ancestor` error. --------- Signed-off-by: jsvisa Co-authored-by: Felix Lange --- cmd/geth/chaincmd.go | 12 ++++++++---- cmd/utils/cmd.go | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index eb0dda095..c30927d9f 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -103,11 +103,12 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.StateHistoryFlag, }, utils.DatabaseFlags), Description: ` -The import command imports blocks from an RLP-encoded form. The form can be one file -with several RLP-encoded blocks, or several files can be used. +The import command allows the import of blocks from an RLP-encoded format. This format can be a single file +containing multiple RLP-encoded blocks, or multiple files can be given. -If only one file is used, import error will result in failure. If several files are used, -processing will proceed even if an individual RLP-file import failure occurs.`, +If only one file is used, an import error will result in the entire import process failing. If +multiple files are processed, the import process will continue even if an individual RLP file fails +to import successfully.`, } exportCommand = &cli.Command{ Action: exportChain, @@ -319,6 +320,9 @@ func importChain(ctx *cli.Context) error { if err := utils.ImportChain(chain, arg); err != nil { importErr = err log.Error("Import error", "file", arg, "err", err) + if err == utils.ErrImportInterrupted { + break + } } } } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index fc66e11dc..13b20b518 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -54,6 +54,9 @@ const ( importBatchSize = 2500 ) +// ErrImportInterrupted is returned when the user interrupts the import process. +var ErrImportInterrupted = errors.New("interrupted") + // Fatalf formats a message to standard error and exits the program. // The message is also printed to standard output if standard error // is redirected to a different file. @@ -190,7 +193,7 @@ func ImportChain(chain *core.BlockChain, fn string) error { for batch := 0; ; batch++ { // Load a batch of RLP blocks. if checkInterrupt() { - return errors.New("interrupted") + return ErrImportInterrupted } i := 0 for ; i < importBatchSize; i++ { From 2d9966a787dc202f48b891704eed9f2885e4d8c4 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 12 Mar 2025 12:21:50 +0100 Subject: [PATCH 196/354] crypto/secp256k1: update libsecp256k1 (#31242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the libsecp256k1 dependency to commit: c0d9480fbbf8eccbd4be23ed27f6f2af6f3b211e PR: ``` BenchmarkSign-24 57756 21214 ns/op 164 B/op 3 allocs/op BenchmarkRecover-24 37156 33044 ns/op 80 B/op 1 allocs/op BenchmarkEcrecoverSignature-24 36889 32935 ns/op 80 B/op 1 allocs/op BenchmarkVerifySignature-24 41163 29207 ns/op 0 B/op 0 allocs/op BenchmarkDecompressPubkey-24 318624 4062 ns/op 304 B/op 6 allocs/op ``` Master: ``` BenchmarkSign-24 34509 35330 ns/op 164 B/op 3 allocs/op BenchmarkRecover-24 25418 47725 ns/op 80 B/op 1 allocs/op BenchmarkEcrecoverSignature-24 25735 47591 ns/op 80 B/op 1 allocs/op BenchmarkVerifySignature-24 29108 41097 ns/op 0 B/op 0 allocs/op BenchmarkDecompressPubkey-24 294747 4143 ns/op 304 B/op 6 allocs/op ``` Performance seems to be improved significantly: ``` Sign-24 34.86µ ± 3% 21.66µ ± 2% -37.86% (p=0.000 n=10) Recover-24 46.14µ ± 3% 33.24µ ± 2% -27.95% (p=0.000 n=10) ``` --- crypto/secp256k1/ext.h | 4 +- crypto/secp256k1/libsecp256k1/.cirrus.yml | 101 + crypto/secp256k1/libsecp256k1/.gitattributes | 2 + .../install-homebrew-valgrind/action.yml | 33 + .../actions/run-in-docker-action/action.yml | 54 + .../libsecp256k1/.github/workflows/ci.yml | 890 + crypto/secp256k1/libsecp256k1/.gitignore | 42 +- crypto/secp256k1/libsecp256k1/.travis.yml | 69 - crypto/secp256k1/libsecp256k1/CHANGELOG.md | 177 + crypto/secp256k1/libsecp256k1/CMakeLists.txt | 405 + .../secp256k1/libsecp256k1/CMakePresets.json | 19 + crypto/secp256k1/libsecp256k1/CONTRIBUTING.md | 109 + crypto/secp256k1/libsecp256k1/Makefile.am | 275 +- crypto/secp256k1/libsecp256k1/README.md | 158 +- crypto/secp256k1/libsecp256k1/SECURITY.md | 15 + crypto/secp256k1/libsecp256k1/TODO | 3 - .../build-aux/m4/ax_jni_include_dir.m4 | 140 - .../build-aux/m4/ax_prog_cc_for_build.m4 | 125 - .../libsecp256k1/build-aux/m4/bitcoin_secp.m4 | 134 +- crypto/secp256k1/libsecp256k1/ci/ci.sh | 149 + .../libsecp256k1/ci/linux-debian.Dockerfile | 79 + .../cmake/CheckArm32Assembly.cmake | 6 + .../cmake/CheckMemorySanitizer.cmake | 18 + .../cmake/CheckStringOptionValue.cmake | 10 + .../cmake/CheckX86_64Assembly.cmake | 14 + .../libsecp256k1/cmake/FindValgrind.cmake | 41 + .../cmake/GeneratePkgConfigFile.cmake | 8 + .../libsecp256k1/cmake/TryAppendCFlags.cmake | 24 + .../cmake/arm-linux-gnueabihf.toolchain.cmake | 3 + .../libsecp256k1/cmake/config.cmake.in | 5 + .../libsecp256k1/cmake/source_arm32.s | 9 + .../cmake/x86_64-w64-mingw32.toolchain.cmake | 3 + crypto/secp256k1/libsecp256k1/configure.ac | 762 +- .../libsecp256k1/contrib/lax_der_parsing.c | 22 +- .../libsecp256k1/contrib/lax_der_parsing.h | 30 +- .../contrib/lax_der_privatekey_parsing.c | 13 +- .../contrib/lax_der_privatekey_parsing.h | 29 +- crypto/secp256k1/libsecp256k1/doc/ellswift.md | 483 + crypto/secp256k1/libsecp256k1/doc/musig.md | 54 + .../libsecp256k1/doc/release-process.md | 94 + .../doc/safegcd_implementation.md | 819 + .../libsecp256k1/examples/CMakeLists.txt | 31 + .../libsecp256k1/examples/EXAMPLES_COPYING | 121 + crypto/secp256k1/libsecp256k1/examples/ecdh.c | 121 + .../secp256k1/libsecp256k1/examples/ecdsa.c | 138 + .../libsecp256k1/examples/ellswift.c | 122 + .../libsecp256k1/examples/examples_util.h | 108 + .../secp256k1/libsecp256k1/examples/musig.c | 261 + .../secp256k1/libsecp256k1/examples/schnorr.c | 154 + .../libsecp256k1/include/secp256k1.h | 720 +- .../libsecp256k1/include/secp256k1_ecdh.h | 68 +- .../libsecp256k1/include/secp256k1_ellswift.h | 200 + .../include/secp256k1_extrakeys.h | 250 + .../libsecp256k1/include/secp256k1_musig.h | 588 + .../include/secp256k1_preallocated.h | 134 + .../libsecp256k1/include/secp256k1_recovery.h | 85 +- .../include/secp256k1_schnorrsig.h | 190 + .../secp256k1/libsecp256k1/libsecp256k1.pc.in | 1 - crypto/secp256k1/libsecp256k1/obj/.gitignore | 0 .../sage/gen_exhaustive_groups.sage | 156 + .../sage/gen_split_lambda_constants.sage | 114 + .../libsecp256k1/sage/group_prover.sage | 89 +- ....sage => prove_group_implementations.sage} | 163 +- .../libsecp256k1/sage/secp256k1_params.sage | 39 + .../libsecp256k1/sage/weierstrass_prover.sage | 45 +- .../secp256k1/libsecp256k1/src/CMakeLists.txt | 176 + .../libsecp256k1/src/asm/field_10x26_arm.s | 19 +- .../secp256k1/libsecp256k1/src/assumptions.h | 87 + .../secp256k1/libsecp256k1/src/basic-config.h | 32 - crypto/secp256k1/libsecp256k1/src/bench.c | 280 + crypto/secp256k1/libsecp256k1/src/bench.h | 194 +- .../secp256k1/libsecp256k1/src/bench_ecmult.c | 368 + .../libsecp256k1/src/bench_internal.c | 517 +- .../libsecp256k1/src/bench_schnorr_verify.c | 73 - .../secp256k1/libsecp256k1/src/bench_sign.c | 56 - .../secp256k1/libsecp256k1/src/bench_verify.c | 112 - crypto/secp256k1/libsecp256k1/src/checkmem.h | 102 + .../secp256k1/libsecp256k1/src/ctime_tests.c | 267 + crypto/secp256k1/libsecp256k1/src/ecdsa.h | 18 +- .../secp256k1/libsecp256k1/src/ecdsa_impl.h | 147 +- crypto/secp256k1/libsecp256k1/src/eckey.h | 20 +- .../secp256k1/libsecp256k1/src/eckey_impl.h | 55 +- crypto/secp256k1/libsecp256k1/src/ecmult.h | 74 +- .../libsecp256k1/src/ecmult_compute_table.h | 16 + .../src/ecmult_compute_table_impl.h | 49 + .../secp256k1/libsecp256k1/src/ecmult_const.h | 39 +- .../libsecp256k1/src/ecmult_const_impl.h | 550 +- .../secp256k1/libsecp256k1/src/ecmult_gen.h | 156 +- .../src/ecmult_gen_compute_table.h | 14 + .../src/ecmult_gen_compute_table_impl.h | 108 + .../libsecp256k1/src/ecmult_gen_impl.h | 443 +- .../secp256k1/libsecp256k1/src/ecmult_impl.h | 983 +- crypto/secp256k1/libsecp256k1/src/field.h | 374 +- .../secp256k1/libsecp256k1/src/field_10x26.h | 48 +- .../libsecp256k1/src/field_10x26_impl.h | 474 +- .../secp256k1/libsecp256k1/src/field_5x52.h | 53 +- .../libsecp256k1/src/field_5x52_asm_impl.h | 502 - .../libsecp256k1/src/field_5x52_impl.h | 463 +- .../libsecp256k1/src/field_5x52_int128_impl.h | 299 +- .../secp256k1/libsecp256k1/src/field_impl.h | 494 +- .../secp256k1/libsecp256k1/src/gen_context.c | 74 - crypto/secp256k1/libsecp256k1/src/group.h | 152 +- .../secp256k1/libsecp256k1/src/group_impl.h | 872 +- crypto/secp256k1/libsecp256k1/src/hash.h | 49 +- crypto/secp256k1/libsecp256k1/src/hash_impl.h | 160 +- crypto/secp256k1/libsecp256k1/src/hsort.h | 33 + .../secp256k1/libsecp256k1/src/hsort_impl.h | 125 + crypto/secp256k1/libsecp256k1/src/int128.h | 90 + .../secp256k1/libsecp256k1/src/int128_impl.h | 18 + .../libsecp256k1/src/int128_native.h | 19 + .../libsecp256k1/src/int128_native_impl.h | 94 + .../libsecp256k1/src/int128_struct.h | 14 + .../libsecp256k1/src/int128_struct_impl.h | 205 + .../src/java/org/bitcoin/NativeSecp256k1.java | 446 - .../java/org/bitcoin/NativeSecp256k1Test.java | 226 - .../java/org/bitcoin/NativeSecp256k1Util.java | 45 - .../java/org/bitcoin/Secp256k1Context.java | 51 - .../src/java/org_bitcoin_NativeSecp256k1.c | 377 - .../src/java/org_bitcoin_NativeSecp256k1.h | 119 - .../src/java/org_bitcoin_Secp256k1Context.c | 15 - .../src/java/org_bitcoin_Secp256k1Context.h | 22 - crypto/secp256k1/libsecp256k1/src/modinv32.h | 43 + .../libsecp256k1/src/modinv32_impl.h | 725 + crypto/secp256k1/libsecp256k1/src/modinv64.h | 47 + .../libsecp256k1/src/modinv64_impl.h | 780 + .../src/modules/ecdh/Makefile.am.include | 6 +- .../ecdh/bench_impl.h} | 47 +- .../libsecp256k1/src/modules/ecdh/main_impl.h | 92 +- .../src/modules/ecdh/tests_impl.h | 147 +- .../src/modules/ellswift/Makefile.am.include | 5 + .../src/modules/ellswift/bench_impl.h | 106 + .../src/modules/ellswift/main_impl.h | 592 + .../modules/ellswift/tests_exhaustive_impl.h | 39 + .../src/modules/ellswift/tests_impl.h | 436 + .../src/modules/extrakeys/Makefile.am.include | 4 + .../src/modules/extrakeys/main_impl.h | 285 + .../modules/extrakeys/tests_exhaustive_impl.h | 68 + .../src/modules/extrakeys/tests_impl.h | 483 + .../src/modules/musig/Makefile.am.include | 8 + .../libsecp256k1/src/modules/musig/keyagg.h | 32 + .../src/modules/musig/keyagg_impl.h | 291 + .../src/modules/musig/main_impl.h | 12 + .../libsecp256k1/src/modules/musig/session.h | 24 + .../src/modules/musig/session_impl.h | 816 + .../src/modules/musig/tests_impl.h | 1143 ++ .../libsecp256k1/src/modules/musig/vectors.h | 346 + .../src/modules/recovery/Makefile.am.include | 7 +- .../recovery/bench_impl.h} | 42 +- .../src/modules/recovery/main_impl.h | 82 +- .../modules/recovery/tests_exhaustive_impl.h | 148 + .../src/modules/recovery/tests_impl.h | 287 +- .../modules/schnorrsig/Makefile.am.include | 5 + .../src/modules/schnorrsig/bench_impl.h | 104 + .../src/modules/schnorrsig/main_impl.h | 271 + .../schnorrsig/tests_exhaustive_impl.h | 214 + .../src/modules/schnorrsig/tests_impl.h | 982 + crypto/secp256k1/libsecp256k1/src/num.h | 74 - crypto/secp256k1/libsecp256k1/src/num_gmp.h | 20 - .../secp256k1/libsecp256k1/src/num_gmp_impl.h | 288 - crypto/secp256k1/libsecp256k1/src/num_impl.h | 24 - .../libsecp256k1/src/precompute_ecmult.c | 91 + .../libsecp256k1/src/precompute_ecmult_gen.c | 101 + .../libsecp256k1/src/precomputed_ecmult.c | 16456 ++++++++++++++++ .../libsecp256k1/src/precomputed_ecmult.h | 38 + .../libsecp256k1/src/precomputed_ecmult_gen.c | 1779 ++ .../libsecp256k1/src/precomputed_ecmult_gen.h | 26 + crypto/secp256k1/libsecp256k1/src/scalar.h | 83 +- .../secp256k1/libsecp256k1/src/scalar_4x64.h | 16 +- .../libsecp256k1/src/scalar_4x64_impl.h | 661 +- .../secp256k1/libsecp256k1/src/scalar_8x32.h | 16 +- .../libsecp256k1/src/scalar_8x32_impl.h | 425 +- .../secp256k1/libsecp256k1/src/scalar_impl.h | 553 +- .../secp256k1/libsecp256k1/src/scalar_low.h | 25 +- .../libsecp256k1/src/scalar_low_impl.h | 164 +- crypto/secp256k1/libsecp256k1/src/scratch.h | 44 + .../secp256k1/libsecp256k1/src/scratch_impl.h | 99 + crypto/secp256k1/libsecp256k1/src/secp256k1.c | 632 +- crypto/secp256k1/libsecp256k1/src/selftest.h | 32 + crypto/secp256k1/libsecp256k1/src/testrand.h | 46 +- .../libsecp256k1/src/testrand_impl.h | 205 +- crypto/secp256k1/libsecp256k1/src/tests.c | 6772 +++++-- .../libsecp256k1/src/tests_exhaustive.c | 522 +- crypto/secp256k1/libsecp256k1/src/testutil.h | 148 + crypto/secp256k1/libsecp256k1/src/util.h | 400 +- .../src/wycheproof/WYCHEPROOF_COPYING | 212 + .../ecdsa_secp256k1_sha256_bitcoin_test.h | 1564 ++ .../ecdsa_secp256k1_sha256_bitcoin_test.json | 6360 ++++++ .../secp256k1/libsecp256k1/tools/check-abi.sh | 74 + .../tools/test_vectors_musig2_generate.py | 656 + .../tools/tests_wycheproof_generate.py | 115 + crypto/secp256k1/secp256.go | 15 +- 191 files changed, 57887 insertions(+), 9764 deletions(-) create mode 100644 crypto/secp256k1/libsecp256k1/.cirrus.yml create mode 100644 crypto/secp256k1/libsecp256k1/.gitattributes create mode 100644 crypto/secp256k1/libsecp256k1/.github/actions/install-homebrew-valgrind/action.yml create mode 100644 crypto/secp256k1/libsecp256k1/.github/actions/run-in-docker-action/action.yml create mode 100644 crypto/secp256k1/libsecp256k1/.github/workflows/ci.yml delete mode 100644 crypto/secp256k1/libsecp256k1/.travis.yml create mode 100644 crypto/secp256k1/libsecp256k1/CHANGELOG.md create mode 100644 crypto/secp256k1/libsecp256k1/CMakeLists.txt create mode 100644 crypto/secp256k1/libsecp256k1/CMakePresets.json create mode 100644 crypto/secp256k1/libsecp256k1/CONTRIBUTING.md create mode 100644 crypto/secp256k1/libsecp256k1/SECURITY.md delete mode 100644 crypto/secp256k1/libsecp256k1/TODO delete mode 100644 crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 delete mode 100644 crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 create mode 100755 crypto/secp256k1/libsecp256k1/ci/ci.sh create mode 100644 crypto/secp256k1/libsecp256k1/ci/linux-debian.Dockerfile create mode 100644 crypto/secp256k1/libsecp256k1/cmake/CheckArm32Assembly.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/CheckMemorySanitizer.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/CheckStringOptionValue.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/CheckX86_64Assembly.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/FindValgrind.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/GeneratePkgConfigFile.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/TryAppendCFlags.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake create mode 100644 crypto/secp256k1/libsecp256k1/cmake/config.cmake.in create mode 100644 crypto/secp256k1/libsecp256k1/cmake/source_arm32.s create mode 100644 crypto/secp256k1/libsecp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake create mode 100644 crypto/secp256k1/libsecp256k1/doc/ellswift.md create mode 100644 crypto/secp256k1/libsecp256k1/doc/musig.md create mode 100644 crypto/secp256k1/libsecp256k1/doc/release-process.md create mode 100644 crypto/secp256k1/libsecp256k1/doc/safegcd_implementation.md create mode 100644 crypto/secp256k1/libsecp256k1/examples/CMakeLists.txt create mode 100644 crypto/secp256k1/libsecp256k1/examples/EXAMPLES_COPYING create mode 100644 crypto/secp256k1/libsecp256k1/examples/ecdh.c create mode 100644 crypto/secp256k1/libsecp256k1/examples/ecdsa.c create mode 100644 crypto/secp256k1/libsecp256k1/examples/ellswift.c create mode 100644 crypto/secp256k1/libsecp256k1/examples/examples_util.h create mode 100644 crypto/secp256k1/libsecp256k1/examples/musig.c create mode 100644 crypto/secp256k1/libsecp256k1/examples/schnorr.c create mode 100644 crypto/secp256k1/libsecp256k1/include/secp256k1_ellswift.h create mode 100644 crypto/secp256k1/libsecp256k1/include/secp256k1_extrakeys.h create mode 100644 crypto/secp256k1/libsecp256k1/include/secp256k1_musig.h create mode 100644 crypto/secp256k1/libsecp256k1/include/secp256k1_preallocated.h create mode 100644 crypto/secp256k1/libsecp256k1/include/secp256k1_schnorrsig.h delete mode 100644 crypto/secp256k1/libsecp256k1/obj/.gitignore create mode 100644 crypto/secp256k1/libsecp256k1/sage/gen_exhaustive_groups.sage create mode 100644 crypto/secp256k1/libsecp256k1/sage/gen_split_lambda_constants.sage rename crypto/secp256k1/libsecp256k1/sage/{secp256k1.sage => prove_group_implementations.sage} (72%) create mode 100644 crypto/secp256k1/libsecp256k1/sage/secp256k1_params.sage create mode 100644 crypto/secp256k1/libsecp256k1/src/CMakeLists.txt create mode 100644 crypto/secp256k1/libsecp256k1/src/assumptions.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/basic-config.h create mode 100644 crypto/secp256k1/libsecp256k1/src/bench.c create mode 100644 crypto/secp256k1/libsecp256k1/src/bench_ecmult.c delete mode 100644 crypto/secp256k1/libsecp256k1/src/bench_schnorr_verify.c delete mode 100644 crypto/secp256k1/libsecp256k1/src/bench_sign.c delete mode 100644 crypto/secp256k1/libsecp256k1/src/bench_verify.c create mode 100644 crypto/secp256k1/libsecp256k1/src/checkmem.h create mode 100644 crypto/secp256k1/libsecp256k1/src/ctime_tests.c create mode 100644 crypto/secp256k1/libsecp256k1/src/ecmult_compute_table.h create mode 100644 crypto/secp256k1/libsecp256k1/src/ecmult_compute_table_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table.h create mode 100644 crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table_impl.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/field_5x52_asm_impl.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/gen_context.c create mode 100644 crypto/secp256k1/libsecp256k1/src/hsort.h create mode 100644 crypto/secp256k1/libsecp256k1/src/hsort_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128_native.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128_native_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128_struct.h create mode 100644 crypto/secp256k1/libsecp256k1/src/int128_struct_impl.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c delete mode 100644 crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modinv32.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modinv32_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modinv64.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modinv64_impl.h rename crypto/secp256k1/libsecp256k1/src/{bench_ecdh.c => modules/ecdh/bench_impl.h} (54%) create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ellswift/Makefile.am.include create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ellswift/bench_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ellswift/main_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_exhaustive_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/extrakeys/Makefile.am.include create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/extrakeys/main_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_exhaustive_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/Makefile.am.include create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/main_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/session.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/session_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/tests_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/musig/vectors.h rename crypto/secp256k1/libsecp256k1/src/{bench_recover.c => modules/recovery/bench_impl.h} (58%) mode change 100755 => 100644 crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_exhaustive_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/Makefile.am.include create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/bench_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/main_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_impl.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/num.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/num_gmp.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h delete mode 100644 crypto/secp256k1/libsecp256k1/src/num_impl.h create mode 100644 crypto/secp256k1/libsecp256k1/src/precompute_ecmult.c create mode 100644 crypto/secp256k1/libsecp256k1/src/precompute_ecmult_gen.c create mode 100644 crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.c create mode 100644 crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.h create mode 100644 crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.c create mode 100644 crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.h create mode 100644 crypto/secp256k1/libsecp256k1/src/scratch.h create mode 100644 crypto/secp256k1/libsecp256k1/src/scratch_impl.h mode change 100755 => 100644 crypto/secp256k1/libsecp256k1/src/secp256k1.c create mode 100644 crypto/secp256k1/libsecp256k1/src/selftest.h create mode 100644 crypto/secp256k1/libsecp256k1/src/testutil.h create mode 100644 crypto/secp256k1/libsecp256k1/src/wycheproof/WYCHEPROOF_COPYING create mode 100644 crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h create mode 100644 crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json create mode 100755 crypto/secp256k1/libsecp256k1/tools/check-abi.sh create mode 100755 crypto/secp256k1/libsecp256k1/tools/test_vectors_musig2_generate.py create mode 100755 crypto/secp256k1/libsecp256k1/tools/tests_wycheproof_generate.py diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h index e422fe4b4..1c485e260 100644 --- a/crypto/secp256k1/ext.h +++ b/crypto/secp256k1/ext.h @@ -109,8 +109,8 @@ int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, unsigned char *point, ARG_CHECK(scalar != NULL); (void)ctx; - secp256k1_fe_set_b32(&feX, point); - secp256k1_fe_set_b32(&feY, point+32); + secp256k1_fe_set_b32_limit(&feX, point); + secp256k1_fe_set_b32_limit(&feY, point+32); secp256k1_ge_set_xy(&ge, &feX, &feY); secp256k1_scalar_set_b32(&s, scalar, &overflow); if (overflow || secp256k1_scalar_is_zero(&s)) { diff --git a/crypto/secp256k1/libsecp256k1/.cirrus.yml b/crypto/secp256k1/libsecp256k1/.cirrus.yml new file mode 100644 index 000000000..81a4f0432 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/.cirrus.yml @@ -0,0 +1,101 @@ +env: + ### cirrus config + CIRRUS_CLONE_DEPTH: 1 + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: -Werror -pedantic-errors + MAKEFLAGS: -j4 + BUILD: check + ### secp256k1 config + ECMULTWINDOW: 15 + ECMULTGENKB: 22 + ASM: no + WIDEMUL: auto + WITH_VALGRIND: yes + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: no + ECDH: no + RECOVERY: no + EXTRAKEYS: no + SCHNORRSIG: no + MUSIG: no + ELLSWIFT: no + ### test options + SECP256K1_TEST_ITERS: 64 + BENCH: yes + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: yes + # Compile and run the tests + EXAMPLES: yes + +cat_logs_snippet: &CAT_LOGS + always: + cat_tests_log_script: + - cat tests.log || true + cat_noverify_tests_log_script: + - cat noverify_tests.log || true + cat_exhaustive_tests_log_script: + - cat exhaustive_tests.log || true + cat_ctime_tests_log_script: + - cat ctime_tests.log || true + cat_bench_log_script: + - cat bench.log || true + cat_config_log_script: + - cat config.log || true + cat_test_env_script: + - cat test_env.log || true + cat_ci_env_script: + - env + +linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER + env_script: + - env | tee /tmp/env + build_script: + - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" + - docker image prune --force # Cleanup stale layers + test_script: + - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh" + +task: + name: "ARM64: Linux (Debian stable)" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + matrix: + # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU + - env: { CC: 'gcc-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS + +task: + name: "ARM64: Linux (Debian stable), Valgrind" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + EXTRAKEYS: yes + SCHNORRSIG: yes + MUSIG: yes + ELLSWIFT: yes + WRAPPER_CMD: 'valgrind --error-exitcode=42' + SECP256K1_TEST_ITERS: 2 + matrix: + - env: { CC: 'gcc' } + - env: { CC: 'clang' } + - env: { CC: 'gcc-snapshot' } + - env: { CC: 'clang-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS diff --git a/crypto/secp256k1/libsecp256k1/.gitattributes b/crypto/secp256k1/libsecp256k1/.gitattributes new file mode 100644 index 000000000..30efb2244 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/.gitattributes @@ -0,0 +1,2 @@ +src/precomputed_ecmult.c linguist-generated +src/precomputed_ecmult_gen.c linguist-generated diff --git a/crypto/secp256k1/libsecp256k1/.github/actions/install-homebrew-valgrind/action.yml b/crypto/secp256k1/libsecp256k1/.github/actions/install-homebrew-valgrind/action.yml new file mode 100644 index 000000000..ce10eb268 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/.github/actions/install-homebrew-valgrind/action.yml @@ -0,0 +1,33 @@ +name: "Install Valgrind" +description: "Install Homebrew's Valgrind package and cache it." +runs: + using: "composite" + steps: + - run: | + brew tap LouisBrunner/valgrind + brew fetch --HEAD LouisBrunner/valgrind/valgrind + echo "CI_HOMEBREW_CELLAR_VALGRIND=$(brew --cellar valgrind)" >> "$GITHUB_ENV" + shell: bash + + - run: | + sw_vers > valgrind_fingerprint + brew --version >> valgrind_fingerprint + git -C "$(brew --cache)/valgrind--git" rev-parse HEAD >> valgrind_fingerprint + cat valgrind_fingerprint + shell: bash + + - uses: actions/cache@v4 + id: cache + with: + path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }} + key: ${{ github.job }}-valgrind-${{ hashFiles('valgrind_fingerprint') }} + + - if: steps.cache.outputs.cache-hit != 'true' + run: | + brew install --HEAD LouisBrunner/valgrind/valgrind + shell: bash + + - if: steps.cache.outputs.cache-hit == 'true' + run: | + brew link valgrind + shell: bash diff --git a/crypto/secp256k1/libsecp256k1/.github/actions/run-in-docker-action/action.yml b/crypto/secp256k1/libsecp256k1/.github/actions/run-in-docker-action/action.yml new file mode 100644 index 000000000..74933686a --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/.github/actions/run-in-docker-action/action.yml @@ -0,0 +1,54 @@ +name: 'Run in Docker with environment' +description: 'Run a command in a Docker container, while passing explicitly set environment variables into the container.' +inputs: + dockerfile: + description: 'A Dockerfile that defines an image' + required: true + tag: + description: 'A tag of an image' + required: true + command: + description: 'A command to run in a container' + required: false + default: ./ci/ci.sh +runs: + using: "composite" + steps: + - uses: docker/setup-buildx-action@v3 + + - uses: docker/build-push-action@v5 + id: main_builder + continue-on-error: true + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - uses: docker/build-push-action@v5 + id: retry_builder + if: steps.main_builder.outcome == 'failure' + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - # Workaround for https://github.com/google/sanitizers/issues/1614 . + # The underlying issue has been fixed in clang 18.1.3. + run: sudo sysctl -w vm.mmap_rnd_bits=28 + shell: bash + + - # Tell Docker to pass environment variables in `env` into the container. + run: > + docker run \ + $(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \ + --volume ${{ github.workspace }}:${{ github.workspace }} \ + --workdir ${{ github.workspace }} \ + ${{ inputs.tag }} bash -c " + git config --global --add safe.directory ${{ github.workspace }} + ${{ inputs.command }} + " + shell: bash diff --git a/crypto/secp256k1/libsecp256k1/.github/workflows/ci.yml b/crypto/secp256k1/libsecp256k1/.github/workflows/ci.yml new file mode 100644 index 000000000..54b2fab1c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/.github/workflows/ci.yml @@ -0,0 +1,890 @@ +name: CI +on: + pull_request: + push: + branches: + - '**' + tags-ignore: + - '**' + +concurrency: + group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + cancel-in-progress: true + +env: + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: '-Werror -pedantic-errors' + MAKEFLAGS: '-j4' + BUILD: 'check' + ### secp256k1 config + ECMULTWINDOW: 15 + ECMULTGENKB: 86 + ASM: 'no' + WIDEMUL: 'auto' + WITH_VALGRIND: 'yes' + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: 'no' + ECDH: 'no' + RECOVERY: 'no' + EXTRAKEYS: 'no' + SCHNORRSIG: 'no' + MUSIG: 'no' + ELLSWIFT: 'no' + ### test options + SECP256K1_TEST_ITERS: 64 + BENCH: 'yes' + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: 'yes' + # Compile and run the examples. + EXAMPLES: 'yes' + +jobs: + docker_cache: + name: "Build Docker image" + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + # See: https://github.com/moby/buildkit/issues/3969. + driver-opts: | + network=host + + - name: Build container + uses: docker/build-push-action@v5 + with: + file: ./ci/linux-debian.Dockerfile + tags: linux-debian-image + cache-from: type=gha + cache-to: type=gha,mode=min + + linux_debian: + name: "x86_64: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' } + - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128' } + - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' } + - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } + - env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes' } + - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', CPPFLAGS: '-DVERIFY' } + - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } + - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } + - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 } + cc: + - 'gcc' + - 'clang' + - 'gcc-snapshot' + - 'clang-snapshot' + + env: + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + i686_debian: + name: "i686: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + cc: + - 'i686-linux-gnu-gcc' + - 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include' + + env: + HOST: 'i686-linux-gnu' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + s390x_debian: + name: "s390x (big-endian): Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-s390x' + SECP256K1_TEST_ITERS: 16 + HOST: 's390x-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm32_debian: + name: "ARM32: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: {} + - env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' } + + env: + WRAPPER_CMD: 'qemu-arm' + SECP256K1_TEST_ITERS: 16 + HOST: 'arm-linux-gnueabihf' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm64_debian: + name: "ARM64: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-aarch64' + SECP256K1_TEST_ITERS: 16 + HOST: 'aarch64-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { } # gcc + - env_vars: # clang + CC: 'clang --target=aarch64-linux-gnu' + - env_vars: # clang-snapshot + CC: 'clang-snapshot --target=aarch64-linux-gnu' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + ppc64le_debian: + name: "ppc64le: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-ppc64le' + SECP256K1_TEST_ITERS: 16 + HOST: 'powerpc64le-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + valgrind_debian: + name: "Valgrind (memcheck)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + + env: + # The `--error-exitcode` is required to make the test fail if valgrind found errors, + # otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html). + WRAPPER_CMD: 'valgrind --error-exitcode=42' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + SECP256K1_TEST_ITERS: 2 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + sanitizers_debian: + name: "UBSan, ASan, LSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 } + + env: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + CFLAGS: '-fsanitize=undefined,address -g' + UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1' + ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' + LSAN_OPTIONS: 'use_unaligned=1' + SECP256K1_TEST_ITERS: 32 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + msan_debian: + name: "MSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: + CTIMETESTS: 'yes' + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g' + - env_vars: + ECMULTGENKB: 2 + ECMULTWINDOW: 2 + CTIMETESTS: 'yes' + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3' + - env_vars: + # -fsanitize-memory-param-retval is clang's default, but our build system disables it + # when ctime_tests when enabled. + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -fsanitize-memory-param-retval -g' + CTIMETESTS: 'no' + + env: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CC: 'clang' + SECP256K1_TEST_ITERS: 32 + ASM: 'no' + WITH_VALGRIND: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + mingw_debian: + name: ${{ matrix.configuration.job_name }} + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'wine' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'x86_64-w64-mingw32' + - job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'i686-w64-mingw32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + x86_64-macos-native: + name: "x86_64: macOS Ventura, Valgrind" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-13 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install --quiet automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: Install and cache Valgrind + uses: ./.github/actions/install-homebrew-valgrind + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm64-macos-native: + name: "ARM64: macOS Sonoma" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-14 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + WITH_VALGRIND: 'no' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install --quiet automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + win64-native: + name: ${{ matrix.configuration.job_name }} + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + - job_name: 'x64 (MSVC): Windows (VS 2022, static)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' + - job_name: 'x86 (MSVC): Windows (VS 2022)' + cmake_options: '-A Win32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Generate buildsystem + run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }} + + - name: Build + run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount + + - name: Binaries info + # Use the bash shell included with Git for Windows. + shell: bash + run: | + cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + + - name: Check + run: | + ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) + build\bin\RelWithDebInfo\bench_ecmult.exe + build\bin\RelWithDebInfo\bench_internal.exe + build\bin\RelWithDebInfo\bench.exe + + win64-native-headers: + name: "x64 (MSVC): C++ (public headers)" + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Add cl.exe to PATH + uses: ilammy/msvc-dev-cmd@v1 + + - name: C++ (public headers) + run: | + cl.exe -c -WX -TP include/*.h + + cxx_fpermissive_debian: + name: "C++ -fpermissive (entire project)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + CC: 'g++' + CFLAGS: '-fpermissive -g' + CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE' + WERROR_CFLAGS: + ECDH: 'yes' + RECOVERY: 'yes' + EXTRAKEYS: 'yes' + SCHNORRSIG: 'yes' + MUSIG: 'yes' + ELLSWIFT: 'yes' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + cxx_headers_debian: + name: "C++ (public headers)" + runs-on: ubuntu-latest + needs: docker_cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + command: | + g++ -Werror include/*.h + clang -Werror -x c++-header include/*.h + + sage: + name: "SageMath prover" + runs-on: ubuntu-latest + container: + image: sagemath/sagemath:latest + options: --user root + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + run: | + cd sage + sage prove_group_implementations.sage + + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck + + - name: Check installation with Autotools + env: + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + ./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa + + - name: Check installation with CMake + env: + CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} && cmake --install ${{ env.CI_BUILD }} && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa diff --git a/crypto/secp256k1/libsecp256k1/.gitignore b/crypto/secp256k1/libsecp256k1/.gitignore index 87fea161b..bffba8cb2 100644 --- a/crypto/secp256k1/libsecp256k1/.gitignore +++ b/crypto/secp256k1/libsecp256k1/.gitignore @@ -1,17 +1,24 @@ -bench_inv -bench_ecdh -bench_sign -bench_verify -bench_schnorr_verify -bench_recover +bench +bench_ecmult bench_internal +noverify_tests tests exhaustive_tests -gen_context +precompute_ecmult_gen +precompute_ecmult +ctime_tests +ecdh_example +ecdsa_example +schnorr_example +ellswift_example +musig_example *.exe *.so *.a -!.gitignore +*.csv +*.log +*.trs +*.sage.py Makefile configure @@ -21,6 +28,7 @@ aclocal.m4 autom4te.cache/ config.log config.status +conftest* *.tar.gz *.la libtool @@ -29,9 +37,15 @@ libtool *.lo *.o *~ -src/libsecp256k1-config.h -src/libsecp256k1-config.h.in -src/ecmult_static_context.h + +coverage/ +coverage.html +coverage.*.html +*.gcda +*.gcno +*.gcov + +build-aux/ar-lib build-aux/config.guess build-aux/config.sub build-aux/depcomp @@ -45,5 +59,9 @@ build-aux/m4/ltversion.m4 build-aux/missing build-aux/compile build-aux/test-driver -src/stamp-h1 libsecp256k1.pc + +### CMake +/CMakeUserPresets.json +# Default CMake build directory. +/build diff --git a/crypto/secp256k1/libsecp256k1/.travis.yml b/crypto/secp256k1/libsecp256k1/.travis.yml deleted file mode 100644 index 243952924..000000000 --- a/crypto/secp256k1/libsecp256k1/.travis.yml +++ /dev/null @@ -1,69 +0,0 @@ -language: c -sudo: false -addons: - apt: - packages: libgmp-dev -compiler: - - clang - - gcc -cache: - directories: - - src/java/guava/ -env: - global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no - - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar - matrix: - - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - - SCALAR=64bit - - FIELD=64bit RECOVERY=yes - - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - - FIELD=64bit ASM=x86_64 - - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit ENDOMORPHISM=yes - - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes - - BIGNUM=no STATICPRECOMPUTATION=no - - BUILD=distcheck - - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC - - EXTRAFLAGS=CFLAGS=-O0 - - BUILD=check-java ECDH=yes EXPERIMENTAL=yes -matrix: - fast_finish: true - include: - - compiler: clang - env: HOST=i686-linux-gnu ENDOMORPHISM=yes - addons: - apt: - packages: - - gcc-multilib - - libgmp-dev:i386 - - compiler: clang - env: HOST=i686-linux-gnu - addons: - apt: - packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu ENDOMORPHISM=yes - addons: - apt: - packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu - addons: - apt: - packages: - - gcc-multilib - - libgmp-dev:i386 -before_install: mkdir -p `dirname $GUAVA_JAR` -install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi -before_script: ./autogen.sh -script: - - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD -os: linux diff --git a/crypto/secp256k1/libsecp256k1/CHANGELOG.md b/crypto/secp256k1/libsecp256k1/CHANGELOG.md new file mode 100644 index 000000000..05222e5ed --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/CHANGELOG.md @@ -0,0 +1,177 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.6.0] - 2024-11-04 + +#### Added + - New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See: + - Header file `include/secp256k1_musig.h` which defines the new API. + - Document `doc/musig.md` for further notes on API usage. + - Usage example `examples/musig.c`. + - New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command. + +#### Changed + - API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal. + - Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++). + - Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility. + +#### Removed + - Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API. + +#### ABI Compatibility +The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed. +Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x. + +## [0.5.1] - 2024-08-01 + +#### Added + - Added usage example for an ElligatorSwift key exchange. + +#### Changed + - The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly. + +#### Fixed + - Fixed compilation when the extrakeys module is disabled. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. + +## [0.5.0] - 2024-05-06 + +#### Added + - New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order. + +#### Changed + - The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations. + - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB). + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.x and 0.3.x. + +## [0.4.1] - 2023-12-21 + +#### Changed + - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one. + - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.0 and 0.3.x. + +## [0.4.0] - 2023-09-04 + +#### Added + - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. + ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See: + - Header file `include/secp256k1_ellswift.h` which defines the new API. + - Document `doc/ellswift.md` which explains the mathematical background of the scheme. + - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. + - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). + +#### Fixed + - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. + +#### Changed + - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. + +#### ABI Compatibility +This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. + +## [0.3.2] - 2023-05-13 +We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. + +#### Security + - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. + +#### Fixed + - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. + +#### Changed + - Various improvements and changes to CMake builds. CMake builds remain experimental. + - Made API versioning consistent with GNU Autotools builds. + - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. + - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. + - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). + +#### ABI Compatibility +The ABI is compatible with versions 0.3.0 and 0.3.1. + +## [0.3.1] - 2023-04-10 +We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. + +#### Security + - Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14. + +#### Added + - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases. + +#### Changed + - Increased minimum required CMake version to 3.13. CMake builds remain experimental. + +#### ABI Compatibility +The ABI is compatible with version 0.3.0. + +## [0.3.0] - 2023-03-08 + +#### Added + - Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported. + - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory. + - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target. + +#### Fixed + - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning. + +#### Changed + - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) + - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. + +#### Removed + - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags). + +#### ABI Compatibility +Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions. + +## [0.2.0] - 2022-12-12 + +#### Added + - Added usage examples for common use cases in a new `examples/` directory. + - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. + - Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms. + +#### Changed + - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`. + - The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API. + +#### Deprecated + - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. + - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. + - Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`. + +#### ABI Compatibility +Since this is the first release, we do not compare application binary interfaces. +However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. + +## [0.1.0] - 2013-03-05 to 2021-12-25 + +This version was in fact never released. +The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). +Therefore, this version number does not uniquely identify a set of source files. + +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.6.0...HEAD +[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0 +[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0 +[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 +[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 +[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0 +[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93 diff --git a/crypto/secp256k1/libsecp256k1/CMakeLists.txt b/crypto/secp256k1/libsecp256k1/CMakeLists.txt new file mode 100644 index 000000000..aba6e5125 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/CMakeLists.txt @@ -0,0 +1,405 @@ +cmake_minimum_required(VERSION 3.16) + +#============================= +# Project / Package metadata +#============================= +project(libsecp256k1 + # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of + # the API. All changes in experimental modules are treated as + # backwards-compatible and therefore at most increase the minor version. + VERSION 0.6.1 + DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." + HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" + LANGUAGES C +) +enable_testing() +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +if(CMAKE_VERSION VERSION_LESS 3.21) + # Emulates CMake 3.21+ behavior. + if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(PROJECT_IS_TOP_LEVEL ON) + set(${PROJECT_NAME}_IS_TOP_LEVEL ON) + else() + set(PROJECT_IS_TOP_LEVEL OFF) + set(${PROJECT_NAME}_IS_TOP_LEVEL OFF) + endif() +endif() + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 1) +set(${PROJECT_NAME}_LIB_VERSION_AGE 0) + +#============================= +# Language setup +#============================= +set(CMAKE_C_STANDARD 90) +set(CMAKE_C_EXTENSIONS OFF) + +#============================= +# Configurable options +#============================= +option(BUILD_SHARED_LIBS "Build shared libraries." ON) +option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) +if(SECP256K1_DISABLE_SHARED) + set(BUILD_SHARED_LIBS OFF) +endif() + +option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) + +## Modules + +# We declare all options before processing them, to make sure we can express +# dependencies while processing. +option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) +option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) +option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) +option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) +option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON) +option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) + +# Processing must be done in a topological sorting of the dependency graph +# (dependent module first). +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG) + message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.") + endif() + set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) + add_compile_definitions(ENABLE_MODULE_MUSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) + message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.") + endif() + set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) + add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) +endif() + +if(SECP256K1_ENABLE_MODULE_RECOVERY) + add_compile_definitions(ENABLE_MODULE_RECOVERY=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_compile_definitions(ENABLE_MODULE_ECDH=1) +endif() + +option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) +if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) + add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) +endif() + +set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]") +set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) +include(CheckStringOptionValue) +check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) +add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) + +set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]") +set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86) +check_string_option_value(SECP256K1_ECMULT_GEN_KB) +if(SECP256K1_ECMULT_GEN_KB EQUAL 2) + add_compile_definitions(COMB_BLOCKS=2) + add_compile_definitions(COMB_TEETH=5) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22) + add_compile_definitions(COMB_BLOCKS=11) + add_compile_definitions(COMB_TEETH=6) +elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86) + add_compile_definitions(COMB_BLOCKS=43) + add_compile_definitions(COMB_TEETH=6) +endif() + +set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") +set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") +check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) + add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1) +endif() +mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") +set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") +check_string_option_value(SECP256K1_ASM) +if(SECP256K1_ASM STREQUAL "arm32") + enable_language(ASM) + include(CheckArm32Assembly) + check_arm32_assembly() + if(HAVE_ARM32_ASM) + add_compile_definitions(USE_EXTERNAL_ASM=1) + else() + message(FATAL_ERROR "ARM32 assembly requested but not available.") + endif() +elseif(SECP256K1_ASM) + include(CheckX86_64Assembly) + check_x86_64_assembly() + if(HAVE_X86_64_ASM) + set(SECP256K1_ASM "x86_64") + add_compile_definitions(USE_ASM_X86_64=1) + elseif(SECP256K1_ASM STREQUAL "AUTO") + set(SECP256K1_ASM "OFF") + else() + message(FATAL_ERROR "x86_64 assembly requested but not available.") + endif() +endif() + +option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) +if(NOT SECP256K1_EXPERIMENTAL) + if(SECP256K1_ASM STREQUAL "arm32") + message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + endif() +endif() + +set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]") +set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON") +check_string_option_value(SECP256K1_VALGRIND) +if(SECP256K1_VALGRIND) + find_package(Valgrind MODULE) + if(Valgrind_FOUND) + set(SECP256K1_VALGRIND ON) + include_directories(${Valgrind_INCLUDE_DIR}) + add_compile_definitions(VALGRIND) + elseif(SECP256K1_VALGRIND STREQUAL "AUTO") + set(SECP256K1_VALGRIND OFF) + else() + message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.") + endif() +endif() + +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) +option(SECP256K1_BUILD_TESTS "Build tests." ON) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) + +# Redefine configuration flags. +# We leave assertions on, because they are only used in the examples, and we want them always on there. +if(MSVC) + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") +else() + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Define custom "Coverage" build type. +set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING + "Flags used by the C compiler during \"Coverage\" builds." + FORCE +) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used for linking binaries during \"Coverage\" builds." + FORCE +) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used by the shared libraries linker during \"Coverage\" builds." + FORCE +) +mark_as_advanced( + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE +) + +if(PROJECT_IS_TOP_LEVEL) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + set(default_build_type "RelWithDebInfo") + if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING + "Supported configuration types." + FORCE + ) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING + "Choose the type of build." + FORCE + ) + endif() + endif() +endif() + +include(TryAppendCFlags) +if(MSVC) + # Keep the following commands ordered lexicographically. + try_append_c_flags(/W3) # Production quality warning level. + try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +else() + # Keep the following commands ordered lexicographically. + try_append_c_flags(-pedantic) + try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. + try_append_c_flags(-Wcast-align) # GCC >= 2.95. + try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. + try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. + try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + try_append_c_flags(-Wnested-externs) + try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall. + try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. + try_append_c_flags(-Wshadow) + try_append_c_flags(-Wstrict-prototypes) + try_append_c_flags(-Wundef) +endif() + +set(CMAKE_C_VISIBILITY_PRESET hidden) + +set(print_msan_notice) +if(SECP256K1_BUILD_CTIME_TESTS) + include(CheckMemorySanitizer) + check_memory_sanitizer(msan_enabled) + if(msan_enabled) + try_append_c_flags(-fno-sanitize-memory-param-retval) + set(print_msan_notice YES) + endif() + unset(msan_enabled) +endif() + +set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_CFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}") +endif() + +set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.") +if(SECP256K1_APPEND_LDFLAGS) + # Appending to this low-level rule variable is the only way to + # guarantee that the flags appear at the end of the command line. + string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}") + string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") +endif() + +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +endif() +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +add_subdirectory(src) +if(SECP256K1_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +message("\n") +message("secp256k1 configure summary") +message("===========================") +message("Build artifacts:") +if(BUILD_SHARED_LIBS) + set(library_type "Shared") +else() + set(library_type "Static") +endif() + +message(" library type ........................ ${library_type}") +message("Optional modules:") +message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") +message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") +message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") +message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") +message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") +message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") +message("Parameters:") +message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") +message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB") +message("Optional features:") +message(" assembly ............................ ${SECP256K1_ASM}") +message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") +endif() +message("Optional binaries:") +message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") +message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") +set(tests_status "${SECP256K1_BUILD_TESTS}") +if(CMAKE_BUILD_TYPE STREQUAL "Coverage") + set(tests_status OFF) +endif() +message(" tests ............................... ${tests_status}") +message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}") +message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}") +message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}") +message("") +if(CMAKE_CROSSCOMPILING) + set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +else() + set(cross_status "FALSE") +endif() +message("Cross compiling ....................... ${cross_status}") +message("Valgrind .............................. ${SECP256K1_VALGRIND}") +get_directory_property(definitions COMPILE_DEFINITIONS) +string(REPLACE ";" " " definitions "${definitions}") +message("Preprocessor defined macros ........... ${definitions}") +message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") +message("CFLAGS ................................ ${CMAKE_C_FLAGS}") +get_directory_property(compile_options COMPILE_OPTIONS) +string(REPLACE ";" " " compile_options "${compile_options}") +message("Compile options ....................... " ${compile_options}) +if(NOT is_multi_config) + message("Build type:") + message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") + string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") +else() + message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") + message("RelWithDebInfo configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + message("Debug configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") +endif() +if(SECP256K1_APPEND_CFLAGS) + message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}") +endif() +if(SECP256K1_APPEND_LDFLAGS) + message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}") +endif() +message("") +if(print_msan_notice) + message( + "Note:\n" + " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" + " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" + ) +endif() +if(SECP256K1_EXPERIMENTAL) + message( + " ******\n" + " WARNING: experimental build\n" + " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n" + " ******\n" + ) +endif() diff --git a/crypto/secp256k1/libsecp256k1/CMakePresets.json b/crypto/secp256k1/libsecp256k1/CMakePresets.json new file mode 100644 index 000000000..b35cd8057 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/CMakePresets.json @@ -0,0 +1,19 @@ +{ + "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "version": 3, + "configurePresets": [ + { + "name": "dev-mode", + "displayName": "Development mode (intended only for developers of the library)", + "cacheVariables": { + "SECP256K1_EXPERIMENTAL": "ON", + "SECP256K1_ENABLE_MODULE_RECOVERY": "ON", + "SECP256K1_BUILD_EXAMPLES": "ON" + }, + "warnings": { + "dev": true, + "uninitialized": true + } + } + ] +} diff --git a/crypto/secp256k1/libsecp256k1/CONTRIBUTING.md b/crypto/secp256k1/libsecp256k1/CONTRIBUTING.md new file mode 100644 index 000000000..80890fb70 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/CONTRIBUTING.md @@ -0,0 +1,109 @@ +# Contributing to libsecp256k1 + +## Scope + +libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library. +The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem. + +## Adding new functionality or modules + +The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope. + +It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable. +Contributors are recommended to provide the following in addition to the new code: + +* **Specification:** + A specification can help significantly in reviewing the new code as it provides documentation and context. + It may justify various design decisions, give a motivation and outline security goals. + If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. +* **Security Arguments:** + In addition to a defining the security goals, it should be argued that the new functionality meets these goals. + Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security. +* **Relevance Arguments:** + The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. + +These are not the only factors taken into account when considering to add new functionality. +The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design. + +We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality. + +## Communication channels + +Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board. + +Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic). +The channel is `#secp256k1` on Libera Chat. +The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1). +Chat history logs can be found at https://gnusha.org/secp256k1/. + +## Contributor workflow & peer review + +The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md). + +### Coding conventions + +In addition, libsecp256k1 tries to maintain the following coding conventions: + +* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations. +* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)). +* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). +* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. +* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). +* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)). + +#### Style conventions + +* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures. +* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting. +* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block: + ```C + void secp256k_foo(void) { + unsigned int x; /* declaration */ + int y = 2*x; /* declaration */ + x = 17; /* statement */ + { + int a, b; /* declaration */ + a = x + y; /* statement */ + secp256k_bar(x, &b); /* statement */ + } + } + ``` +* Use `unsigned int` instead of just `unsigned`. +* Use `void *ptr` instead of `void* ptr`. +* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h). +* User-facing comment lines in headers should be limited to 80 chars if possible. +* All identifiers in file scope should start with `secp256k1_`. +* Avoid trailing whitespace. +* Use the constants `EXIT_SUCCESS`/`EXIT_FAILURE` (defined in `stdlib.h`) to indicate program execution status for examples and other binaries. + +### Tests + +#### Coverage + +This library aims to have full coverage of reachable lines and branches. + +To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): + + $ ./configure --enable-coverage + +Run the tests: + + $ make check + +To create a report, `gcovr` is recommended, as it includes branch coverage reporting: + + $ gcovr --exclude 'src/bench*' --print-summary + +To create a HTML report with coloured and annotated source code: + + $ mkdir -p coverage + $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html + +#### Exhaustive tests + +There are tests of several functions in which a small group replaces secp256k1. +These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)). + +### Benchmarks + +See `src/bench*.c` for examples of benchmarks. diff --git a/crypto/secp256k1/libsecp256k1/Makefile.am b/crypto/secp256k1/libsecp256k1/Makefile.am index c071fbe27..a95b4809d 100644 --- a/crypto/secp256k1/libsecp256k1/Makefile.am +++ b/crypto/secp256k1/libsecp256k1/Makefile.am @@ -1,13 +1,12 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 +# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo +# which does not have an explicit foo_CFLAGS variable set. +AM_CFLAGS = $(SECP_CFLAGS) + lib_LTLIBRARIES = libsecp256k1.la -if USE_JNI -JNI_LIB = libsecp256k1_jni.la -noinst_LTLIBRARIES = $(JNI_LIB) -else -JNI_LIB = -endif include_HEADERS = include/secp256k1.h +include_HEADERS += include/secp256k1_preallocated.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h @@ -19,29 +18,44 @@ noinst_HEADERS += src/scalar_8x32_impl.h noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h -noinst_HEADERS += src/num_gmp.h -noinst_HEADERS += src/num_gmp_impl.h noinst_HEADERS += src/ecdsa.h noinst_HEADERS += src/ecdsa_impl.h noinst_HEADERS += src/eckey.h noinst_HEADERS += src/eckey_impl.h noinst_HEADERS += src/ecmult.h noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_compute_table.h +noinst_HEADERS += src/ecmult_compute_table_impl.h noinst_HEADERS += src/ecmult_const.h noinst_HEADERS += src/ecmult_const_impl.h noinst_HEADERS += src/ecmult_gen.h noinst_HEADERS += src/ecmult_gen_impl.h -noinst_HEADERS += src/num.h -noinst_HEADERS += src/num_impl.h +noinst_HEADERS += src/ecmult_gen_compute_table.h +noinst_HEADERS += src/ecmult_gen_compute_table_impl.h noinst_HEADERS += src/field_10x26.h noinst_HEADERS += src/field_10x26_impl.h noinst_HEADERS += src/field_5x52.h noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h -noinst_HEADERS += src/field_5x52_asm_impl.h -noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h -noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h +noinst_HEADERS += src/modinv32.h +noinst_HEADERS += src/modinv32_impl.h +noinst_HEADERS += src/modinv64.h +noinst_HEADERS += src/modinv64_impl.h +noinst_HEADERS += src/precomputed_ecmult.h +noinst_HEADERS += src/precomputed_ecmult_gen.h +noinst_HEADERS += src/assumptions.h +noinst_HEADERS += src/checkmem.h +noinst_HEADERS += src/testutil.h noinst_HEADERS += src/util.h +noinst_HEADERS += src/int128.h +noinst_HEADERS += src/int128_impl.h +noinst_HEADERS += src/int128_native.h +noinst_HEADERS += src/int128_native_impl.h +noinst_HEADERS += src/int128_struct.h +noinst_HEADERS += src/int128_struct_impl.h +noinst_HEADERS += src/scratch.h +noinst_HEADERS += src/scratch_impl.h +noinst_HEADERS += src/selftest.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h noinst_HEADERS += src/hash.h @@ -49,17 +63,28 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h +noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h +noinst_HEADERS += src/hsort.h +noinst_HEADERS += src/hsort_impl.h noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.c +noinst_HEADERS += examples/examples_util.h + +PRECOMPUTED_LIB = libsecp256k1_precomputed.la +noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) +libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c +# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree. +# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). +libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES) if USE_EXTERNAL_ASM COMMON_LIB = libsecp256k1_common.la -noinst_LTLIBRARIES = $(COMMON_LIB) else COMMON_LIB = endif +noinst_LTLIBRARIES += $(COMMON_LIB) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc @@ -71,102 +96,186 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) - -libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c -libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) +libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES) +libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_sign bench_internal -bench_verify_SOURCES = src/bench_verify.c -bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) -bench_sign_SOURCES = src/bench_sign.c -bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +noinst_PROGRAMS += bench bench_internal bench_ecmult +bench_SOURCES = src/bench.c +bench_LDADD = libsecp256k1.la +bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) -bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) +bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES) +bench_ecmult_SOURCES = src/bench_ecmult.c +bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif TESTS = if USE_TESTS -noinst_PROGRAMS += tests -tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +TESTS += noverify_tests +noinst_PROGRAMS += noverify_tests +noverify_tests_SOURCES = src/tests.c +noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +noverify_tests_LDFLAGS = -static if !ENABLE_COVERAGE -tests_CPPFLAGS += -DVERIFY -endif -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) -tests_LDFLAGS = -static TESTS += tests +noinst_PROGRAMS += tests +tests_SOURCES = $(noverify_tests_SOURCES) +tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY +tests_LDADD = $(noverify_tests_LDADD) +tests_LDFLAGS = $(noverify_tests_LDFLAGS) +endif +endif + +if USE_CTIME_TESTS +noinst_PROGRAMS += ctime_tests +ctime_tests_SOURCES = src/ctime_tests.c +ctime_tests_LDADD = libsecp256k1.la +ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif if USE_EXHAUSTIVE_TESTS noinst_PROGRAMS += exhaustive_tests exhaustive_tests_SOURCES = src/tests_exhaustive.c -exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) +exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) if !ENABLE_COVERAGE exhaustive_tests_CPPFLAGS += -DVERIFY endif -exhaustive_tests_LDADD = $(SECP_LIBS) +# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). +exhaustive_tests_LDADD = $(COMMON_LIB) exhaustive_tests_LDFLAGS = -static TESTS += exhaustive_tests endif -JAVAROOT=src/java -JAVAORG=org/bitcoin -JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar -CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) -JAVA_FILES= \ - $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ - $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ - $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ - $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java +if USE_EXAMPLES +noinst_PROGRAMS += ecdsa_example +ecdsa_example_SOURCES = examples/ecdsa.c +ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ecdsa_example_LDADD = libsecp256k1.la +ecdsa_example_LDFLAGS = -static +if BUILD_WINDOWS +ecdsa_example_LDFLAGS += -lbcrypt +endif +TESTS += ecdsa_example +if ENABLE_MODULE_ECDH +noinst_PROGRAMS += ecdh_example +ecdh_example_SOURCES = examples/ecdh.c +ecdh_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ecdh_example_LDADD = libsecp256k1.la +ecdh_example_LDFLAGS = -static +if BUILD_WINDOWS +ecdh_example_LDFLAGS += -lbcrypt +endif +TESTS += ecdh_example +endif +if ENABLE_MODULE_SCHNORRSIG +noinst_PROGRAMS += schnorr_example +schnorr_example_SOURCES = examples/schnorr.c +schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +schnorr_example_LDADD = libsecp256k1.la +schnorr_example_LDFLAGS = -static +if BUILD_WINDOWS +schnorr_example_LDFLAGS += -lbcrypt +endif +TESTS += schnorr_example +endif +if ENABLE_MODULE_ELLSWIFT +noinst_PROGRAMS += ellswift_example +ellswift_example_SOURCES = examples/ellswift.c +ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ellswift_example_LDADD = libsecp256k1.la +ellswift_example_LDFLAGS = -static +if BUILD_WINDOWS +ellswift_example_LDFLAGS += -lbcrypt +endif +TESTS += ellswift_example +endif +if ENABLE_MODULE_MUSIG +noinst_PROGRAMS += musig_example +musig_example_SOURCES = examples/musig.c +musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +musig_example_LDADD = libsecp256k1.la +musig_example_LDFLAGS = -static +if BUILD_WINDOWS +musig_example_LDFLAGS += -lbcrypt +endif +TESTS += musig_example +endif +endif -if USE_JNI +### Precomputed tables +EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen +CLEANFILES = $(EXTRA_PROGRAMS) -$(JAVA_GUAVA): - @echo Guava is missing. Fetch it via: \ - wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) - @false +precompute_ecmult_SOURCES = src/precompute_ecmult.c +precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_LDADD = $(COMMON_LIB) -.stamp-java: $(JAVA_FILES) - @echo Compiling $^ - $(AM_V_at)$(CLASSPATH_ENV) javac $^ - @touch $@ +precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c +precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY +precompute_ecmult_gen_LDADD = $(COMMON_LIB) -if USE_TESTS +# See Automake manual, Section "Errors with distclean". +# We don't list any dependencies for the prebuilt files here because +# otherwise make's decision whether to rebuild them (even in the first +# build by a normal user) depends on mtimes, and thus is very fragile. +# This means that rebuilds of the prebuilt files always need to be +# forced by deleting them. +src/precomputed_ecmult.c: + $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT) + ./precompute_ecmult$(EXEEXT) +src/precomputed_ecmult_gen.c: + $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult_gen$(EXEEXT) + ./precompute_ecmult_gen$(EXEEXT) -check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java - $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test +PRECOMP = src/precomputed_ecmult_gen.c src/precomputed_ecmult.c +precomp: $(PRECOMP) -endif -endif +# Ensure the prebuilt files will be build first (only if they don't exist, +# e.g., after `make maintainer-clean`). +BUILT_SOURCES = $(PRECOMP) -if USE_ECMULT_STATIC_PRECOMPUTATION -CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function +.PHONY: clean-precomp +clean-precomp: + rm -f $(PRECOMP) +maintainer-clean-local: clean-precomp -gen_context_OBJECTS = gen_context.o -gen_context_BIN = gen_context$(BUILD_EXEEXT) -gen_%.o: src/gen_%.c - $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ +### Pregenerated test vectors +### (see the comments in the previous section for detailed rationale) +TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h -$(gen_context_BIN): $(gen_context_OBJECTS) - $(CC_FOR_BUILD) $^ -o $@ +src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: + mkdir -p $(@D) + python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ -$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h -$(tests_OBJECTS): src/ecmult_static_context.h -$(bench_internal_OBJECTS): src/ecmult_static_context.h +testvectors: $(TESTVECTORS) -src/ecmult_static_context.h: $(gen_context_BIN) - ./$(gen_context_BIN) +BUILT_SOURCES += $(TESTVECTORS) -CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java -endif +.PHONY: clean-testvectors +clean-testvectors: + rm -f $(TESTVECTORS) +maintainer-clean-local: clean-testvectors -EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) +### Additional files to distribute +EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md +EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md +EXTRA_DIST += doc/ellswift.md doc/musig.md +EXTRA_DIST += examples/EXAMPLES_COPYING +EXTRA_DIST += sage/gen_exhaustive_groups.sage +EXTRA_DIST += sage/gen_split_lambda_constants.sage +EXTRA_DIST += sage/group_prover.sage +EXTRA_DIST += sage/prove_group_implementations.sage +EXTRA_DIST += sage/secp256k1_params.sage +EXTRA_DIST += sage/weierstrass_prover.sage +EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING +EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json +EXTRA_DIST += tools/tests_wycheproof_generate.py if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include @@ -175,3 +284,19 @@ endif if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif + +if ENABLE_MODULE_EXTRAKEYS +include src/modules/extrakeys/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORRSIG +include src/modules/schnorrsig/Makefile.am.include +endif + +if ENABLE_MODULE_MUSIG +include src/modules/musig/Makefile.am.include +endif + +if ENABLE_MODULE_ELLSWIFT +include src/modules/ellswift/Makefile.am.include +endif diff --git a/crypto/secp256k1/libsecp256k1/README.md b/crypto/secp256k1/libsecp256k1/README.md index 8cd344ea8..f7a59b2b9 100644 --- a/crypto/secp256k1/libsecp256k1/README.md +++ b/crypto/secp256k1/libsecp256k1/README.md @@ -1,19 +1,27 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) +![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) +[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1) -Optimized C library for EC operations on curve secp256k1. +High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve. -This library is a work in progress and is being used to research best practices. Use at your own risk. +This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose. Features: * secp256k1 ECDSA signing/verification and key generation. -* Adding/multiplying private/public keys. -* Serialization/parsing of private keys, public keys, signatures. -* Constant time, constant memory access signing and pubkey generation. -* Derandomized DSA (via RFC6979 or with a caller provided function.) +* Additive and multiplicative tweaking of secret/public keys. +* Serialization/parsing of secret keys, public keys, signatures. +* Constant time, constant memory access signing and public key generation. +* Derandomized ECDSA (via RFC6979 or with a caller provided function.) * Very efficient implementation. +* Suitable for embedded systems. +* No runtime dependencies. +* Optional module for public key recovery. +* Optional module for ECDH key exchange. +* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). +* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki). +* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). Implementation details ---------------------- @@ -23,16 +31,18 @@ Implementation details * Extensive testing infrastructure. * Structured to facilitate review and analysis. * Intended to be portable to any system with a C89 compiler and uint64_t support. + * No use of floating types. * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") * Field operations * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). - * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). - * Using 10 26-bit limbs. - * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). + * Using 5 52-bit limbs + * Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan). + * This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community. * Scalar operations * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. * Using 4 64-bit limbs (relying on __int128 support in the compiler). * Using 8 32-bit limbs. +* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman). * Group operations * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). * Use addition between points in Jacobian and affine coordinates where possible. @@ -42,20 +52,126 @@ Implementation details * Use wNAF notation for point multiplicands. * Use a much larger window for multiples of G, using precomputed multiples. * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. - * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. + * Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. * Point multiplication for signing * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. - * Access the table with branch-free conditional moves so memory access is uniform. - * No data-dependent branches - * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. + * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * Optional runtime blinding which attempts to frustrate differential power analysis. + * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. -Build steps +Obtaining and verifying +----------------------- + +The git tag for each release (e.g. `v0.6.0`) is GPG-signed by one of the maintainers. +For a fully verified build of this project, it is recommended to obtain this repository +via git, obtain the GPG keys of the signing maintainer(s), and then verify the release +tag's signature using git. + +This can be done with the following steps: + +1. Obtain the GPG keys listed in [SECURITY.md](./SECURITY.md). +2. If possible, cross-reference these key IDs with another source controlled by its owner (e.g. + social media, personal website). This is to mitigate the unlikely case that incorrect + content is being presented by this repository. +3. Clone the repository: + ``` + git clone https://github.com/bitcoin-core/secp256k1 + ``` +4. Check out the latest release tag, e.g. + ``` + git checkout v0.6.0 + ``` +5. Use git to verify the GPG signature: + ``` + % git tag -v v0.6.0 | grep -C 3 'Good signature' + + gpg: Signature made Mon 04 Nov 2024 12:14:44 PM EST + gpg: using RSA key 4BBB845A6F5A65A69DFAEC234861DBF262123605 + gpg: Good signature from "Jonas Nick " [unknown] + gpg: aka "Jonas Nick " [unknown] + gpg: WARNING: This key is not certified with a trusted signature! + gpg: There is no indication that the signature belongs to the owner. + Primary key fingerprint: 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 + Subkey fingerprint: 4BBB 845A 6F5A 65A6 9DFA EC23 4861 DBF2 6212 3605 + ``` + +Building with Autotools +----------------------- + + $ ./autogen.sh # Generate a ./configure script + $ ./configure # Generate a build system + $ make # Run the actual build process + $ make check # Run the test suite + $ sudo make install # Install the library into the system (optional) + +To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. + +Building with CMake (experimental) +---------------------------------- + +To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. + +### Building on POSIX systems + + $ cmake -B build # Generate a build system in subdirectory "build" + $ cmake --build build # Run the actual build process + $ ctest --test-dir build # Run the test suite + $ sudo cmake --install build # Install the library into the system (optional) + +To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake -B build -LH` or `ccmake -B build` to see the full list of available flags. + +### Cross compiling + +To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. +For example, to cross compile for Windows: + + $ cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/x86_64-w64-mingw32.toolchain.cmake + +To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): + + $ cmake -B build -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 + +### Building on Windows + +To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. + +The following example assumes using of Visual Studio 2022 and CMake v3.21+. + +In "Developer Command Prompt for VS 2022": + + >cmake -G "Visual Studio 17 2022" -A x64 -B build + >cmake --build build --config RelWithDebInfo + +Usage examples ----------- +Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. + * [ECDSA example](examples/ecdsa.c) + * [Schnorr signatures example](examples/schnorr.c) + * [Deriving a shared secret (ECDH) example](examples/ecdh.c) + * [ElligatorSwift key exchange example](examples/ellswift.c) + +To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. + +Benchmark +------------ +If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build. + +To print the benchmark result to the command line: + + $ ./bench_name + +To create a CSV file for the benchmark result : + + $ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv + +Reporting a vulnerability +------------ + +See [SECURITY.md](SECURITY.md) -libsecp256k1 is built using autotools: +Contributing to libsecp256k1 +------------ - $ ./autogen.sh - $ ./configure - $ make - $ ./tests - $ sudo make install # optional +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/crypto/secp256k1/libsecp256k1/SECURITY.md b/crypto/secp256k1/libsecp256k1/SECURITY.md new file mode 100644 index 000000000..b515cc1c8 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Reporting a Vulnerability + +To report security issues send an email to secp256k1-security@bitcoincore.org (not for support). + +The following keys may be used to communicate sensitive information to developers: + +| Name | Fingerprint | +|------|-------------| +| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | +| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | +| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 | + +You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/crypto/secp256k1/libsecp256k1/TODO b/crypto/secp256k1/libsecp256k1/TODO deleted file mode 100644 index a300e1c5e..000000000 --- a/crypto/secp256k1/libsecp256k1/TODO +++ /dev/null @@ -1,3 +0,0 @@ -* Unit tests for fieldelem/groupelem, including ones intended to - trigger fieldelem's boundary cases. -* Complete constant-time operations for signing/keygen diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 deleted file mode 100644 index 1fc362761..000000000 --- a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 +++ /dev/null @@ -1,140 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_JNI_INCLUDE_DIR -# -# DESCRIPTION -# -# AX_JNI_INCLUDE_DIR finds include directories needed for compiling -# programs using the JNI interface. -# -# JNI include directories are usually in the Java distribution. This is -# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in -# that order. When this macro completes, a list of directories is left in -# the variable JNI_INCLUDE_DIRS. -# -# Example usage follows: -# -# AX_JNI_INCLUDE_DIR -# -# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS -# do -# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" -# done -# -# If you want to force a specific compiler: -# -# - at the configure.in level, set JAVAC=yourcompiler before calling -# AX_JNI_INCLUDE_DIR -# -# - at the configure level, setenv JAVAC -# -# Note: This macro can work with the autoconf M4 macros for Java programs. -# This particular macro is not part of the original set of macros. -# -# LICENSE -# -# Copyright (c) 2008 Don Anderson -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 10 - -AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) -AC_DEFUN([AX_JNI_INCLUDE_DIR],[ - -JNI_INCLUDE_DIRS="" - -if test "x$JAVA_HOME" != x; then - _JTOPDIR="$JAVA_HOME" -else - if test "x$JAVAC" = x; then - JAVAC=javac - fi - AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) - if test "x$_ACJNI_JAVAC" = xno; then - AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) - fi - _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") - _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` -fi - -case "$host_os" in - darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` - _JINC="$_JTOPDIR/Headers";; - *) _JINC="$_JTOPDIR/include";; -esac -_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) -_AS_ECHO_LOG([_JINC=$_JINC]) - -# On Mac OS X 10.6.4, jni.h is a symlink: -# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h -# -> ../../CurrentJDK/Headers/jni.h. - -AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, -[ -if test -f "$_JINC/jni.h"; then - ac_cv_jni_header_path="$_JINC" - JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" -else - _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` - if test -f "$_JTOPDIR/include/jni.h"; then - ac_cv_jni_header_path="$_JTOPDIR/include" - JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" - else - ac_cv_jni_header_path=none - fi -fi -]) - - - -# get the likely subdirectories for system specific java includes -case "$host_os" in -bsdi*) _JNI_INC_SUBDIRS="bsdos";; -darwin*) _JNI_INC_SUBDIRS="darwin";; -freebsd*) _JNI_INC_SUBDIRS="freebsd";; -linux*) _JNI_INC_SUBDIRS="linux genunix";; -osf*) _JNI_INC_SUBDIRS="alpha";; -solaris*) _JNI_INC_SUBDIRS="solaris";; -mingw*) _JNI_INC_SUBDIRS="win32";; -cygwin*) _JNI_INC_SUBDIRS="win32";; -*) _JNI_INC_SUBDIRS="genunix";; -esac - -if test "x$ac_cv_jni_header_path" != "xnone"; then - # add any subdirectories that are present - for JINCSUBDIR in $_JNI_INC_SUBDIRS - do - if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then - JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" - fi - done -fi -]) - -# _ACJNI_FOLLOW_SYMLINKS -# Follows symbolic links on , -# finally setting variable _ACJNI_FOLLOWED -# ---------------------------------------- -AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ -# find the include directory relative to the javac executable -_cur="$1" -while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do - AC_MSG_CHECKING([symlink for $_cur]) - _slink=`ls -ld "$_cur" | sed 's/.* -> //'` - case "$_slink" in - /*) _cur="$_slink";; - # 'X' avoids triggering unwanted echo options. - *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; - esac - AC_MSG_RESULT([$_cur]) -done -_ACJNI_FOLLOWED="$_cur" -])# _ACJNI diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 deleted file mode 100644 index 77fd346a7..000000000 --- a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 +++ /dev/null @@ -1,125 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_CC_FOR_BUILD -# -# DESCRIPTION -# -# This macro searches for a C compiler that generates native executables, -# that is a C compiler that surely is not a cross-compiler. This can be -# useful if you have to generate source code at compile-time like for -# example GCC does. -# -# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything -# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). -# The value of these variables can be overridden by the user by specifying -# a compiler with an environment variable (like you do for standard CC). -# -# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object -# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if -# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are -# substituted in the Makefile. -# -# LICENSE -# -# Copyright (c) 2008 Paolo Bonzini -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 8 - -AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) -AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_CPP])dnl -AC_REQUIRE([AC_EXEEXT])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl - -dnl Use the standard macros, but make them use other variable names -dnl -pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl -pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl -pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl -pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl -pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl -pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl -pushdef([ac_cv_objext], ac_cv_build_objext)dnl -pushdef([ac_exeext], ac_build_exeext)dnl -pushdef([ac_objext], ac_build_objext)dnl -pushdef([CC], CC_FOR_BUILD)dnl -pushdef([CPP], CPP_FOR_BUILD)dnl -pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl -pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl -pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl -pushdef([host], build)dnl -pushdef([host_alias], build_alias)dnl -pushdef([host_cpu], build_cpu)dnl -pushdef([host_vendor], build_vendor)dnl -pushdef([host_os], build_os)dnl -pushdef([ac_cv_host], ac_cv_build)dnl -pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl -pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl -pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl -pushdef([ac_cv_host_os], ac_cv_build_os)dnl -pushdef([ac_cpp], ac_build_cpp)dnl -pushdef([ac_compile], ac_build_compile)dnl -pushdef([ac_link], ac_build_link)dnl - -save_cross_compiling=$cross_compiling -save_ac_tool_prefix=$ac_tool_prefix -cross_compiling=no -ac_tool_prefix= - -AC_PROG_CC -AC_PROG_CPP -AC_EXEEXT - -ac_tool_prefix=$save_ac_tool_prefix -cross_compiling=$save_cross_compiling - -dnl Restore the old definitions -dnl -popdef([ac_link])dnl -popdef([ac_compile])dnl -popdef([ac_cpp])dnl -popdef([ac_cv_host_os])dnl -popdef([ac_cv_host_vendor])dnl -popdef([ac_cv_host_cpu])dnl -popdef([ac_cv_host_alias])dnl -popdef([ac_cv_host])dnl -popdef([host_os])dnl -popdef([host_vendor])dnl -popdef([host_cpu])dnl -popdef([host_alias])dnl -popdef([host])dnl -popdef([LDFLAGS])dnl -popdef([CPPFLAGS])dnl -popdef([CFLAGS])dnl -popdef([CPP])dnl -popdef([CC])dnl -popdef([ac_objext])dnl -popdef([ac_exeext])dnl -popdef([ac_cv_objext])dnl -popdef([ac_cv_exeext])dnl -popdef([ac_cv_prog_cc_g])dnl -popdef([ac_cv_prog_cc_cross])dnl -popdef([ac_cv_prog_cc_works])dnl -popdef([ac_cv_prog_gcc])dnl -popdef([ac_cv_prog_CPP])dnl - -dnl Finally, set Makefile variables -dnl -BUILD_EXEEXT=$ac_build_exeext -BUILD_OBJEXT=$ac_build_objext -AC_SUBST(BUILD_EXEEXT)dnl -AC_SUBST(BUILD_OBJEXT)dnl -AC_SUBST([CFLAGS_FOR_BUILD])dnl -AC_SUBST([CPPFLAGS_FOR_BUILD])dnl -AC_SUBST([LDFLAGS_FOR_BUILD])dnl -]) diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 index b74acb8c1..048267fa6 100644 --- a/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 @@ -1,69 +1,91 @@ -dnl libsecp25k1 helper checks -AC_DEFUN([SECP_INT128_CHECK],[ -has_int128=$ac_cv_type___int128 -]) - dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. -AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_DEFUN([SECP_X86_64_ASM_CHECK],[ AC_MSG_CHECKING(for x86_64 assembly availability) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]],[[ uint64_t a = 11, tmp; __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); - ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) -AC_MSG_RESULT([$has_64bit_asm]) + ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no]) +AC_MSG_RESULT([$has_x86_64_asm]) ]) -dnl -AC_DEFUN([SECP_OPENSSL_CHECK],[ - has_libcrypto=no - m4_ifdef([PKG_CHECK_MODULES],[ - PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) - if test x"$has_libcrypto" = x"yes"; then - TEMP_LIBS="$LIBS" - LIBS="$LIBS $CRYPTO_LIBS" - AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) - LIBS="$TEMP_LIBS" - fi - ]) - if test x$has_libcrypto = xno; then - AC_CHECK_HEADER(openssl/crypto.h,[ - AC_CHECK_LIB(crypto, main,[ - has_libcrypto=yes - CRYPTO_LIBS=-lcrypto - AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) - ]) - ]) - LIBS= - fi -if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then - AC_MSG_CHECKING(for EC functions in libcrypto) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include ]],[[ - EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); - ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); - ECDSA_verify(0, NULL, 0, NULL, 0, eckey); - EC_KEY_free(eckey); - ECDSA_SIG *sig_openssl; - sig_openssl = ECDSA_SIG_new(); - (void)sig_openssl->r; - ECDSA_SIG_free(sig_openssl); - ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) - AC_MSG_RESULT([$has_openssl_ec]) -fi +AC_DEFUN([SECP_ARM32_ASM_CHECK], [ + AC_MSG_CHECKING(for ARM32 assembly availability) + SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="-x assembler" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + .syntax unified + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .text + .global main + main: + ldr r0, =0x002A + mov r7, #1 + swi 0 + ]])], [has_arm32_asm=yes], [has_arm32_asm=no]) + AC_MSG_RESULT([$has_arm32_asm]) + CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS" ]) -dnl -AC_DEFUN([SECP_GMP_CHECK],[ -if test x"$has_gmp" != x"yes"; then +AC_DEFUN([SECP_VALGRIND_CHECK],[ +AC_MSG_CHECKING([for valgrind support]) +if test x"$has_valgrind" != x"yes"; then CPPFLAGS_TEMP="$CPPFLAGS" - CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" - LIBS_TEMP="$LIBS" - LIBS="$GMP_LIBS $LIBS" - AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + ]], [[ + #if defined(NVALGRIND) + # error "Valgrind does not support this platform." + #endif + ]])], [has_valgrind=yes]) CPPFLAGS="$CPPFLAGS_TEMP" - LIBS="$LIBS_TEMP" fi +AC_MSG_RESULT($has_valgrind) +]) + +AC_DEFUN([SECP_MSAN_CHECK], [ +AC_MSG_CHECKING(whether MemorySanitizer is enabled) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error "MemorySanitizer is disabled." + # endif + #else + # error "__has_feature is not defined." + #endif + ]])], [msan_enabled=yes], [msan_enabled=no]) +AC_MSG_RESULT([$msan_enabled]) +]) + +dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) +dnl Append flags to VAR if CC accepts them. +AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [ + AC_MSG_CHECKING([if ${CC} supports $1]) + SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="$1 $CFLAGS" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no]) + AC_MSG_RESULT($flag_works) + CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS" + if test x"$flag_works" = x"yes"; then + $2="$$2 $1" + fi + unset flag_works + AC_SUBST($2) +]) + +dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode) +dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled +AC_DEFUN([SECP_SET_DEFAULT], [ + if test "${enable_dev_mode+set}" != set; then + AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]]) + fi + if test x"$enable_dev_mode" = x"yes"; then + $1="$3" + else + $1="$2" + fi ]) diff --git a/crypto/secp256k1/libsecp256k1/ci/ci.sh b/crypto/secp256k1/libsecp256k1/ci/ci.sh new file mode 100755 index 000000000..3636deafa --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/ci/ci.sh @@ -0,0 +1,149 @@ +#!/bin/sh + +set -eux + +export LC_ALL=C + +# Print commit and relevant CI environment to allow reproducing the job outside of CI. +git show --no-patch +print_environment() { + # Turn off -x because it messes up the output + set +x + # There are many ways to print variable names and their content. This one + # does not rely on bash. + for var in WERROR_CFLAGS MAKEFLAGS BUILD \ + ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ + EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + EXAMPLES \ + HOST WRAPPER_CMD \ + CC CFLAGS CPPFLAGS AR NM \ + UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS + do + eval "isset=\${$var+x}" + if [ -n "$isset" ]; then + eval "val=\${$var}" + # shellcheck disable=SC2154 + printf '%s="%s" ' "$var" "$val" + fi + done + echo "$0" + set -x +} +print_environment + +env >> test_env.log + +# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang). +case "${CC:-undefined}" in + *gcc*) + $CC -v 2>&1 | grep -q "gcc version" || exit 1; + ;; +esac + +if [ -n "${CC+x}" ]; then + # The MSVC compiler "cl" doesn't understand "-v" + $CC -v || true +fi +if [ "$WITH_VALGRIND" = "yes" ]; then + valgrind --version +fi +if [ -n "$WRAPPER_CMD" ]; then + $WRAPPER_CMD --version +fi + +# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0). +case "${CC:-undefined}" in + clang*) + if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ] + then + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + else + case "$WRAPPER_CMD" in + valgrind*) + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + ;; + esac + fi + ;; +esac + +./autogen.sh + +./configure \ + --enable-experimental="$EXPERIMENTAL" \ + --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ + --with-ecmult-window="$ECMULTWINDOW" \ + --with-ecmult-gen-kb="$ECMULTGENKB" \ + --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ + --enable-module-ellswift="$ELLSWIFT" \ + --enable-module-extrakeys="$EXTRAKEYS" \ + --enable-module-schnorrsig="$SCHNORRSIG" \ + --enable-module-musig="$MUSIG" \ + --enable-examples="$EXAMPLES" \ + --enable-ctime-tests="$CTIMETESTS" \ + --with-valgrind="$WITH_VALGRIND" \ + --host="$HOST" $EXTRAFLAGS + +# We have set "-j" in MAKEFLAGS. +build_exit_code=0 +make > make.log 2>&1 || build_exit_code=$? +cat make.log +if [ $build_exit_code -ne 0 ]; then + case "${CC:-undefined}" in + *snapshot*) + # Ignore internal compiler errors in gcc-snapshot and clang-snapshot + grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log + return $?; + ;; + *) + return 1; + ;; + esac +fi + +# Print information about binaries so that we can see that the architecture is correct +file *tests* || true +file bench* || true +file .libs/* || true + +# This tells `make check` to wrap test invocations. +export LOG_COMPILER="$WRAPPER_CMD" + +make "$BUILD" + +# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool +EXEC='./libtool --mode=execute' +if [ -n "$WRAPPER_CMD" ] +then + EXEC="$EXEC $WRAPPER_CMD" +fi + +if [ "$BENCH" = "yes" ] +then + { + $EXEC ./bench_ecmult + $EXEC ./bench_internal + $EXEC ./bench + } >> bench.log 2>&1 +fi + +if [ "$CTIMETESTS" = "yes" ] +then + if [ "$WITH_VALGRIND" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + else + $EXEC ./ctime_tests > ctime_tests.log 2>&1 + fi +fi + +# Rebuild precomputed files (if not cross-compiling). +if [ -z "$HOST" ] +then + make clean-precomp clean-testvectors + make precomp testvectors +fi + +# Check that no repo files have been modified by the build. +# (This fails for example if the precomp files need to be updated in the repo.) +git diff --exit-code diff --git a/crypto/secp256k1/libsecp256k1/ci/linux-debian.Dockerfile b/crypto/secp256k1/libsecp256k1/ci/linux-debian.Dockerfile new file mode 100644 index 000000000..241bfa971 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/ci/linux-debian.Dockerfile @@ -0,0 +1,79 @@ +FROM debian:stable-slim + +SHELL ["/bin/bash", "-c"] + +WORKDIR /root + +# A too high maximum number of file descriptors (with the default value +# inherited from the docker host) can cause issues with some of our tools: +# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662 +# - valgrind crashing: https://stackoverflow.com/a/75293014 +# This is not be a problem on our CI hosts, but developers who run the image +# on their machines may run into this (e.g., on Arch Linux), so warn them. +# (Note that .bashrc is only executed in interactive bash shells.) +RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc + +RUN dpkg --add-architecture i386 && \ + dpkg --add-architecture s390x && \ + dpkg --add-architecture armhf && \ + dpkg --add-architecture arm64 && \ + dpkg --add-architecture ppc64el + +# dkpg-dev: to make pkg-config work in cross-builds +# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces +RUN apt-get update && apt-get install --no-install-recommends -y \ + git ca-certificates \ + make automake libtool pkg-config dpkg-dev valgrind qemu-user \ + gcc clang llvm libclang-rt-dev libc6-dbg \ + g++ \ + gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \ + gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ + gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ + gcc-mingw-w64-x86-64-win32 wine64 wine \ + gcc-mingw-w64-i686-win32 wine32 \ + python3 && \ + if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ + apt-get install --no-install-recommends -y \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ + fi && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Build and install gcc snapshot +ARG GCC_SNAPSHOT_MAJOR=15 +RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + mkdir gcc && cd gcc && \ + wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ + wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \ + sha512sum --check --ignore-missing sha512.sum && \ + # We should have downloaded exactly one tar.xz file + ls && \ + [ $(ls *.tar.xz | wc -l) -eq "1" ] && \ + tar xf *.tar.xz && \ + mkdir gcc-build && cd gcc-build && \ + ../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \ + make -j $(nproc) && \ + make install && \ + cd ../.. && rm -rf gcc && \ + ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \ + apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# Install clang snapshot, see https://apt.llvm.org/ +RUN \ + # Setup GPG keys of LLVM repository + apt-get update && apt-get install --no-install-recommends -y wget && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ + # Add repository for this Debian release + . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ + apt-get update && \ + # Determine the version number of the LLVM development branch + LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ + # Install + apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \ + # Create symlink + ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \ + # Clean up + apt-get autoremove -y wget && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + diff --git a/crypto/secp256k1/libsecp256k1/cmake/CheckArm32Assembly.cmake b/crypto/secp256k1/libsecp256k1/cmake/CheckArm32Assembly.cmake new file mode 100644 index 000000000..baeeff029 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/CheckArm32Assembly.cmake @@ -0,0 +1,6 @@ +function(check_arm32_assembly) + try_compile(HAVE_ARM32_ASM + ${PROJECT_BINARY_DIR}/check_arm32_assembly + SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s + ) +endfunction() diff --git a/crypto/secp256k1/libsecp256k1/cmake/CheckMemorySanitizer.cmake b/crypto/secp256k1/libsecp256k1/cmake/CheckMemorySanitizer.cmake new file mode 100644 index 000000000..d9ef681e6 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/CheckMemorySanitizer.cmake @@ -0,0 +1,18 @@ +include_guard(GLOBAL) +include(CheckCSourceCompiles) + +function(check_memory_sanitizer output) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_source_compiles(" + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error \"MemorySanitizer is disabled.\" + # endif + #else + # error \"__has_feature is not defined.\" + #endif + " HAVE_MSAN) + set(${output} ${HAVE_MSAN} PARENT_SCOPE) +endfunction() diff --git a/crypto/secp256k1/libsecp256k1/cmake/CheckStringOptionValue.cmake b/crypto/secp256k1/libsecp256k1/cmake/CheckStringOptionValue.cmake new file mode 100644 index 000000000..5a4d939b9 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/CheckStringOptionValue.cmake @@ -0,0 +1,10 @@ +function(check_string_option_value option) + get_property(expected_values CACHE ${option} PROPERTY STRINGS) + if(expected_values) + if(${option} IN_LIST expected_values) + return() + endif() + message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") + endif() + message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") +endfunction() diff --git a/crypto/secp256k1/libsecp256k1/cmake/CheckX86_64Assembly.cmake b/crypto/secp256k1/libsecp256k1/cmake/CheckX86_64Assembly.cmake new file mode 100644 index 000000000..ae82cd476 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/CheckX86_64Assembly.cmake @@ -0,0 +1,14 @@ +include(CheckCSourceCompiles) + +function(check_x86_64_assembly) + check_c_source_compiles(" + #include + + int main() + { + uint64_t a = 11, tmp; + __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); + } + " HAVE_X86_64_ASM) + set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE) +endfunction() diff --git a/crypto/secp256k1/libsecp256k1/cmake/FindValgrind.cmake b/crypto/secp256k1/libsecp256k1/cmake/FindValgrind.cmake new file mode 100644 index 000000000..3af5e691e --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/FindValgrind.cmake @@ -0,0 +1,41 @@ +if(CMAKE_HOST_APPLE) + find_program(BREW_COMMAND brew) + execute_process( + COMMAND ${BREW_COMMAND} --prefix valgrind + OUTPUT_VARIABLE valgrind_brew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() + +set(hints_paths) +if(valgrind_brew_prefix) + set(hints_paths ${valgrind_brew_prefix}/include) +endif() + +find_path(Valgrind_INCLUDE_DIR + NAMES valgrind/memcheck.h + HINTS ${hints_paths} +) + +if(Valgrind_INCLUDE_DIR) + include(CheckCSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR}) + check_c_source_compiles(" + #include + #if defined(NVALGRIND) + # error \"Valgrind does not support this platform.\" + #endif + + int main() {} + " Valgrind_WORKS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Valgrind + REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS +) + +mark_as_advanced( + Valgrind_INCLUDE_DIR +) diff --git a/crypto/secp256k1/libsecp256k1/cmake/GeneratePkgConfigFile.cmake b/crypto/secp256k1/libsecp256k1/cmake/GeneratePkgConfigFile.cmake new file mode 100644 index 000000000..9c1d7f1dd --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/GeneratePkgConfigFile.cmake @@ -0,0 +1,8 @@ +function(generate_pkg_config_file in_file) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix \${prefix}) + set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) + set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) + set(PACKAGE_VERSION ${PROJECT_VERSION}) + configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY) +endfunction() diff --git a/crypto/secp256k1/libsecp256k1/cmake/TryAppendCFlags.cmake b/crypto/secp256k1/libsecp256k1/cmake/TryAppendCFlags.cmake new file mode 100644 index 000000000..1d81a9317 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/TryAppendCFlags.cmake @@ -0,0 +1,24 @@ +include(CheckCCompilerFlag) + +function(secp256k1_check_c_flags_internal flags output) + string(MAKE_C_IDENTIFIER "${flags}" result) + string(TOUPPER "${result}" result) + set(result "C_SUPPORTS_${result}") + if(NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "-Werror") + endif() + + # This avoids running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_compiler_flag("${flags}" ${result}) + + set(${output} ${${result}} PARENT_SCOPE) +endfunction() + +# Append flags to the COMPILE_OPTIONS directory property if CC accepts them. +macro(try_append_c_flags) + secp256k1_check_c_flags_internal("${ARGV}" result) + if(result) + add_compile_options(${ARGV}) + endif() +endmacro() diff --git a/crypto/secp256k1/libsecp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake b/crypto/secp256k1/libsecp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake new file mode 100644 index 000000000..0d91912b6 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/arm-linux-gnueabihf.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) diff --git a/crypto/secp256k1/libsecp256k1/cmake/config.cmake.in b/crypto/secp256k1/libsecp256k1/cmake/config.cmake.in new file mode 100644 index 000000000..46b180ab1 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") + +check_required_components(@PROJECT_NAME@) diff --git a/crypto/secp256k1/libsecp256k1/cmake/source_arm32.s b/crypto/secp256k1/libsecp256k1/cmake/source_arm32.s new file mode 100644 index 000000000..d3d934705 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/source_arm32.s @@ -0,0 +1,9 @@ +.syntax unified +.eabi_attribute 24, 1 +.eabi_attribute 25, 1 +.text +.global main +main: + ldr r0, =0x002A + mov r7, #1 + swi 0 diff --git a/crypto/secp256k1/libsecp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake b/crypto/secp256k1/libsecp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake new file mode 100644 index 000000000..96119b72d --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/cmake/x86_64-w64-mingw32.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) diff --git a/crypto/secp256k1/libsecp256k1/configure.ac b/crypto/secp256k1/libsecp256k1/configure.ac index e5fcbcb4e..c62a391d7 100644 --- a/crypto/secp256k1/libsecp256k1/configure.ac +++ b/crypto/secp256k1/libsecp256k1/configure.ac @@ -1,203 +1,290 @@ AC_PREREQ([2.60]) -AC_INIT([libsecp256k1],[0.1]) + +# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of +# the API. All changes in experimental modules are treated as +# backwards-compatible and therefore at most increase the minor version. +define(_PKG_VERSION_MAJOR, 0) +define(_PKG_VERSION_MINOR, 6) +define(_PKG_VERSION_PATCH, 1) +define(_PKG_VERSION_IS_RELEASE, false) + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +define(_LIB_VERSION_CURRENT, 5) +define(_LIB_VERSION_REVISION, 1) +define(_LIB_VERSION_AGE, 0) + +AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) + AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) AC_CANONICAL_HOST -AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) -AH_TOP([#define LIBSECP256K1_CONFIG_H]) -AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) -AM_INIT_AUTOMAKE([foreign subdir-objects]) -LT_INIT - -dnl make the compilation flags quiet unless V=1 is used -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -PKG_PROG_PKG_CONFIG +# Require Automake 1.11.2 for AM_PROG_AR +AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) -AC_PATH_TOOL(AR, ar) -AC_PATH_TOOL(RANLIB, ranlib) -AC_PATH_TOOL(STRIP, strip) -AX_PROG_CC_FOR_BUILD +# Make the compilation flags quiet unless V=1 is used. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -if test "x$CFLAGS" = "x"; then - CFLAGS="-g" +if test "${CFLAGS+set}" = "set"; then + CFLAGS_overridden=yes +else + CFLAGS_overridden=no fi +AC_PROG_CC +AM_PROG_AS +AM_PROG_AR -AM_PROG_CC_C_O +# Clear some cache variables as a workaround for a bug that appears due to a bad +# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe. +# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421 +AS_UNSET(ac_cv_prog_AR) +AS_UNSET(ac_cv_prog_ac_ct_AR) +LT_INIT([win32-dll]) -AC_PROG_CC_C89 -if test x"$ac_cv_prog_cc_c89" = x"no"; then - AC_MSG_ERROR([c89 compiler support required]) -fi -AM_PROG_AS +build_windows=no case $host_os in *darwin*) if test x$cross_compiling != xyes; then - AC_PATH_PROG([BREW],brew,) - if test x$BREW != x; then - dnl These Homebrew packages may be keg-only, meaning that they won't be found - dnl in expected paths because they may conflict with system files. Ask - dnl Homebrew where each one is located, then adjust paths accordingly. - - openssl_prefix=`$BREW --prefix openssl 2>/dev/null` - gmp_prefix=`$BREW --prefix gmp 2>/dev/null` - if test x$openssl_prefix != x; then - PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" - export PKG_CONFIG_PATH - fi - if test x$gmp_prefix != x; then - GMP_CPPFLAGS="-I$gmp_prefix/include" - GMP_LIBS="-L$gmp_prefix/lib" + AC_CHECK_PROG([BREW], brew, brew) + if test x$BREW = xbrew; then + # These Homebrew packages may be keg-only, meaning that they won't be found + # in expected paths because they may conflict with system files. Ask + # Homebrew where each one is located, then adjust paths accordingly. + if $BREW list --versions valgrind >/dev/null; then + valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null) + VALGRIND_CPPFLAGS="-I$valgrind_prefix/include" fi else - AC_PATH_PROG([PORT],port,) - dnl if homebrew isn't installed and macports is, add the macports default paths - dnl as a last resort. - if test x$PORT != x; then + AC_CHECK_PROG([PORT], port, port) + # If homebrew isn't installed and macports is, add the macports default paths + # as a last resort. + if test x$PORT = xport; then CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" LDFLAGS="$LDFLAGS -L/opt/local/lib" fi fi fi ;; + cygwin*|mingw*) + build_windows=yes + ;; esac -CFLAGS="$CFLAGS -W" - -warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $warn_CFLAGS" -AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], - [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_RESULT([no]) - CFLAGS="$saved_CFLAGS" - ]) - -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -fvisibility=hidden" -AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], - [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_RESULT([no]) - CFLAGS="$saved_CFLAGS" - ]) +# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS. +# +# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as +# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user +# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS +# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag). +# +# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by +# libtool for compiling helper executables. For example, when compiling for Windows, libtool will +# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure +# proper operation of uninstalled programs linked by libtool against the uninstalled shared library. +# These executables are compiled from C source file for which our flags may not be appropriate, +# e.g., -std=c89 flag has lead to undesirable warnings in the past. +# +# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. +AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ + # GCC and compatible (incl. clang) + if test "x$GCC" = "xyes"; then + # Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported + # flags will succeed. + # Note that failure to append -Werror does not necessarily mean that -Werror is not + # supported. The compiler may already be warning about something unrelated, for example + # about some path issue. If that is the case, -Werror cannot be used because all + # of those warnings would be turned into errors. + SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" + SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS) + + SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers + SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. + SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 + SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 + SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only + SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only + SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 + + CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" + fi + + # MSVC + # Assume MSVC if we're building for Windows but not with GCC or compatible; + # libtool makes the same assumption internally. + # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. + if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level. + SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". + SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". + SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". + # Eliminate deprecation warnings for the older, less secure functions. + CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS" + fi +]) +SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) + +### +### Define config arguments +### + +# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. +# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. +AC_ARG_ENABLE(dev_mode, [], [], + [enable_dev_mode=no]) AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), - [use_benchmark=$enableval], - [use_benchmark=no]) + AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [], + [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), - [enable_coverage=$enableval], - [enable_coverage=no]) + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], + [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), - [use_tests=$enableval], - [use_tests=yes]) + AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) -AC_ARG_ENABLE(openssl_tests, - AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), - [enable_openssl_tests=$enableval], - [enable_openssl_tests=auto]) +AC_ARG_ENABLE(ctime_tests, + AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [], + [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])]) AC_ARG_ENABLE(experimental, - AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), - [use_experimental=$enableval], - [use_experimental=no]) + AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], + [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) AC_ARG_ENABLE(exhaustive_tests, - AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), - [use_exhaustive_tests=$enableval], - [use_exhaustive_tests=yes]) + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [], + [SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])]) -AC_ARG_ENABLE(endomorphism, - AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), - [use_endomorphism=$enableval], - [use_endomorphism=no]) - -AC_ARG_ENABLE(ecmult_static_precomputation, - AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), - [use_ecmult_static_precomputation=$enableval], - [use_ecmult_static_precomputation=auto]) +AC_ARG_ENABLE(examples, + AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], + [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), - [enable_module_ecdh=$enableval], - [enable_module_ecdh=no]) + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) AC_ARG_ENABLE(module_recovery, - AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), - [enable_module_recovery=$enableval], - [enable_module_recovery=no]) - -AC_ARG_ENABLE(jni, - AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), - [use_jni=$enableval], - [use_jni=auto]) - -AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], -[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) - -AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], -[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) - -AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], -[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) - -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] -[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) - -AC_CHECK_TYPES([__int128]) + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], + [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) + +AC_ARG_ENABLE(module_extrakeys, + AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) + +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) + +AC_ARG_ENABLE(module_musig, + AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])]) + +AC_ARG_ENABLE(module_ellswift, + AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) + +AC_ARG_ENABLE(external_default_callbacks, + AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], + [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) + +# Test-only override of the (autodetected by the C code) "widemul" setting. +# Legal values are: +# * int64 (for [u]int64_t), +# * int128 (for [unsigned] __int128), +# * int128_struct (for int128 implemented as a structure), +# * and auto (the default). +AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], +[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) + +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], +[window size for ecmult precomputation for verification, specified as integer in range [2..24].] +[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] +[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] +[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.] +[For very large window sizes, use "make -j 1" to reduce memory use during compilation.] +[The default value is a reasonable setting for desktop machines (currently 15). [default=15]] +)], +[set_ecmult_window=$withval], [set_ecmult_window=15]) + +AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86], +[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).] +[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.] +[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] +)], +[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86]) + +AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], +[Build with extra checks for running inside Valgrind [default=auto]] +)], +[req_valgrind=$withval], [req_valgrind=auto]) + +### +### Handle config options (except for modules) +### + +if test x"$req_valgrind" = x"no"; then + enable_valgrind=no +else + SECP_VALGRIND_CHECK + if test x"$has_valgrind" != x"yes"; then + if test x"$req_valgrind" = x"yes"; then + AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) + fi + enable_valgrind=no + else + enable_valgrind=yes + fi +fi -AC_MSG_CHECKING([for __builtin_expect]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], - [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], - [ AC_MSG_RESULT([no]) - ]) +if test x"$enable_ctime_tests" = x"auto"; then + enable_ctime_tests=$enable_valgrind +fi -if test x"$enable_coverage" = x"yes"; then - AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) - CFLAGS="$CFLAGS -O0 --coverage" - LDFLAGS="--coverage" -else - CFLAGS="$CFLAGS -O3" +print_msan_notice=no +if test x"$enable_ctime_tests" = x"yes"; then + SECP_MSAN_CHECK + # MSan on Clang >=16 reports uninitialized memory in function parameters and return values, even if + # the uninitialized variable is never actually "used". This is called "eager" checking, and it's + # sounds like good idea for normal use of MSan. However, it yields many false positives in the + # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and + # we're only interested in detecting branches (which count as "uses") on secret data. + if test x"$msan_enabled" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS) + print_msan_notice=yes + fi fi -if test x"$use_ecmult_static_precomputation" != x"no"; then - save_cross_compiling=$cross_compiling - cross_compiling=no - TEMP_CC="$CC" - CC="$CC_FOR_BUILD" - AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([], [return 0])], - [working_native_cc=yes], - [working_native_cc=no],[dnl]) - CC="$TEMP_CC" - cross_compiling=$save_cross_compiling - - if test x"$working_native_cc" = x"no"; then - set_precomp=no - if test x"$use_ecmult_static_precomputation" = x"yes"; then - AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) - else - AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) +if test x"$enable_coverage" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" + SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" + # If coverage is enabled, and the user has not overridden CFLAGS, + # override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up + # with "-O0 --coverage -g -O2". + if test "$CFLAGS_overridden" = "no"; then + CFLAGS="-g" fi - else - AC_MSG_RESULT([ok]) - set_precomp=yes - fi + LDFLAGS="--coverage $LDFLAGS" else - set_precomp=no + # Most likely the CFLAGS already contain -O2 because that is autoconf's default. + # We still add it here because passing it twice is not an issue, and handling + # this case would just add unnecessary complexity (see #896). + SECP_CFLAGS="-O2 $SECP_CFLAGS" fi if test x"$req_asm" = x"auto"; then - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" = x"yes"; then + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" = x"yes"; then set_asm=x86_64 fi if test x"$set_asm" = x; then @@ -207,287 +294,224 @@ else set_asm=$req_asm case $set_asm in x86_64) - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" != x"yes"; then - AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly requested but not available]) fi ;; - arm) - ;; - no) - ;; - *) - AC_MSG_ERROR([invalid assembly optimization selection]) - ;; - esac -fi - -if test x"$req_field" = x"auto"; then - if test x"set_asm" = x"x86_64"; then - set_field=64bit - fi - if test x"$set_field" = x; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_field=64bit - fi - fi - if test x"$set_field" = x; then - set_field=32bit - fi -else - set_field=$req_field - case $set_field in - 64bit) - if test x"$set_asm" != x"x86_64"; then - SECP_INT128_CHECK - if test x"$has_int128" != x"yes"; then - AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) - fi - fi - ;; - 32bit) - ;; - *) - AC_MSG_ERROR([invalid field implementation selection]) - ;; - esac -fi - -if test x"$req_scalar" = x"auto"; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_scalar=64bit - fi - if test x"$set_scalar" = x; then - set_scalar=32bit - fi -else - set_scalar=$req_scalar - case $set_scalar in - 64bit) - SECP_INT128_CHECK - if test x"$has_int128" != x"yes"; then - AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) - fi - ;; - 32bit) - ;; - *) - AC_MSG_ERROR([invalid scalar implementation selected]) - ;; - esac -fi - -if test x"$req_bignum" = x"auto"; then - SECP_GMP_CHECK - if test x"$has_gmp" = x"yes"; then - set_bignum=gmp - fi - - if test x"$set_bignum" = x; then - set_bignum=no - fi -else - set_bignum=$req_bignum - case $set_bignum in - gmp) - SECP_GMP_CHECK - if test x"$has_gmp" != x"yes"; then - AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) + arm32) + SECP_ARM32_ASM_CHECK + if test x"$has_arm32_asm" != x"yes"; then + AC_MSG_ERROR([ARM32 assembly requested but not available]) fi ;; no) ;; *) - AC_MSG_ERROR([invalid bignum implementation selection]) + AC_MSG_ERROR([invalid assembly selection]) ;; esac fi -# select assembly optimization -use_external_asm=no +# Select assembly +enable_external_asm=no case $set_asm in x86_64) - AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1" ;; -arm) - use_external_asm=yes +arm32) + enable_external_asm=yes ;; no) ;; *) - AC_MSG_ERROR([invalid assembly optimizations]) + AC_MSG_ERROR([invalid assembly selection]) ;; esac -# select field implementation -case $set_field in -64bit) - AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) +if test x"$enable_external_asm" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1" +fi + + +# Select wide multiplication implementation +case $set_widemul in +int128_struct) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1" + ;; +int128) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1" + ;; +int64) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1" ;; -32bit) - AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) +auto) ;; *) - AC_MSG_ERROR([invalid field implementation]) + AC_MSG_ERROR([invalid wide multiplication implementation]) ;; esac -# select bignum implementation -case $set_bignum in -gmp) - AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) - AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) - AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) - AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) - ;; -no) - AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) - AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) - AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) +error_window_size=['window size for ecmult precomputation not an integer in range [2..24]'] +case $set_ecmult_window in +''|*[[!0-9]]*) + # no valid integer + AC_MSG_ERROR($error_window_size) ;; *) - AC_MSG_ERROR([invalid bignum implementation]) + if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then + # not in range + AC_MSG_ERROR($error_window_size) + fi + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window" ;; esac -#select scalar implementation -case $set_scalar in -64bit) - AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) +case $set_ecmult_gen_kb in +2) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5" ;; -32bit) - AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) +22) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6" + ;; +86) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6" ;; *) - AC_MSG_ERROR([invalid scalar implementation]) + AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86']) ;; esac -if test x"$use_tests" = x"yes"; then - SECP_OPENSSL_CHECK - if test x"$has_openssl_ec" = x"yes"; then - if test x"$enable_openssl_tests" != x"no"; then - AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) - SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" - SECP_TEST_LIBS="$CRYPTO_LIBS" - - case $host in - *mingw*) - SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" - ;; - esac - fi - else - if test x"$enable_openssl_tests" = x"yes"; then - AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) - fi - fi -else - if test x"$enable_openssl_tests" = x"yes"; then - AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) - fi +if test x"$enable_valgrind" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND" fi -if test x"$use_jni" != x"no"; then - AX_JNI_INCLUDE_DIR - have_jni_dependencies=yes - if test x"$enable_module_ecdh" = x"no"; then - have_jni_dependencies=no - fi - if test "x$JNI_INCLUDE_DIRS" = "x"; then - have_jni_dependencies=no - fi - if test "x$have_jni_dependencies" = "xno"; then - if test x"$use_jni" = x"yes"; then - AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) - fi - AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) - use_jni=no - else - use_jni=yes - for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do - JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" - done - fi -fi +# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). +# We don't want to set the user variable CFLAGS in CI because this would disable +# autoconf's logic for setting default CFLAGS, which we would like to test in CI. +SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" + +### +### Handle module options +### -if test x"$set_bignum" = x"gmp"; then - SECP_LIBS="$SECP_LIBS $GMP_LIBS" - SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" +# Processing must be done in a reverse topological sorting of the dependency graph +# (dependent module first). +if test x"$enable_module_ellswift" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" fi -if test x"$use_endomorphism" = x"yes"; then - AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) +if test x"$enable_module_musig" = x"yes"; then + if test x"$enable_module_schnorrsig" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.]) + fi + enable_module_schnorrsig=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1" fi -if test x"$set_precomp" = x"yes"; then - AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +if test x"$enable_module_schnorrsig" = x"yes"; then + if test x"$enable_module_extrakeys" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.]) + fi + enable_module_extrakeys=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" fi -if test x"$enable_module_ecdh" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) +if test x"$enable_module_extrakeys" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1" fi if test x"$enable_module_recovery" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" fi -AC_C_BIGENDIAN() +if test x"$enable_module_ecdh" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" +fi -if test x"$use_external_asm" = x"yes"; then - AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +if test x"$enable_external_default_callbacks" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" fi -AC_MSG_NOTICE([Using static precomputation: $set_precomp]) -AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) -AC_MSG_NOTICE([Using field implementation: $set_field]) -AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) -AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) -AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) -AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage]) -AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) -AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) -AC_MSG_NOTICE([Using jni: $use_jni]) +### +### Check for --enable-experimental if necessary +### -if test x"$enable_experimental" = x"yes"; then - AC_MSG_NOTICE([******]) - AC_MSG_NOTICE([WARNING: experimental build]) - AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) - AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) - AC_MSG_NOTICE([******]) -else - if test x"$enable_module_ecdh" = x"yes"; then - AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$set_asm" = x"arm"; then - AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) +if test x"$enable_experimental" = x"no"; then + if test x"$set_asm" = x"arm32"; then + AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) fi fi -AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) +### +### Generate output +### + AC_CONFIG_FILES([Makefile libsecp256k1.pc]) -AC_SUBST(JNI_INCLUDES) -AC_SUBST(SECP_INCLUDES) -AC_SUBST(SECP_LIBS) -AC_SUBST(SECP_TEST_LIBS) -AC_SUBST(SECP_TEST_INCLUDES) +AC_SUBST(SECP_CFLAGS) +AC_SUBST(SECP_CONFIG_DEFINES) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) -AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) -AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) -AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) +AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) +AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) +AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) -AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) -AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) -AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) - -dnl make sure nothing new is exported so that we don't break the cache -PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" -unset PKG_CONFIG_PATH -PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" +AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) +AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) +AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) +AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) +AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) AC_OUTPUT + +echo +echo "Build Options:" +echo " with external callbacks = $enable_external_default_callbacks" +echo " with benchmarks = $enable_benchmark" +echo " with tests = $enable_tests" +echo " with ctime tests = $enable_ctime_tests" +echo " with coverage = $enable_coverage" +echo " with examples = $enable_examples" +echo " module ecdh = $enable_module_ecdh" +echo " module recovery = $enable_module_recovery" +echo " module extrakeys = $enable_module_extrakeys" +echo " module schnorrsig = $enable_module_schnorrsig" +echo " module musig = $enable_module_musig" +echo " module ellswift = $enable_module_ellswift" +echo +echo " asm = $set_asm" +echo " ecmult window size = $set_ecmult_window" +echo " ecmult gen table size = $set_ecmult_gen_kb KiB" +# Hide test-only options unless they're used. +if test x"$set_widemul" != xauto; then +echo " wide multiplication = $set_widemul" +fi +echo +echo " valgrind = $enable_valgrind" +echo " CC = $CC" +echo " CPPFLAGS = $CPPFLAGS" +echo " SECP_CFLAGS = $SECP_CFLAGS" +echo " CFLAGS = $CFLAGS" +echo " LDFLAGS = $LDFLAGS" + +if test x"$print_msan_notice" = x"yes"; then + echo + echo "Note:" + echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS" + echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this." +fi + +if test x"$enable_experimental" = x"yes"; then + echo + echo "WARNING: Experimental build" + echo " Experimental features do not have stable APIs or properties, and may not be safe for" + echo " production use." +fi diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c index 5b141a994..bf562303e 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c @@ -1,11 +1,10 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include -#include #include "lax_der_parsing.h" @@ -32,7 +31,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } pos += lenbyte; @@ -51,7 +50,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { @@ -89,7 +88,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { + if (lenbyte > inputlen - pos) { return 0; } while (lenbyte > 0 && input[pos] == 0) { @@ -112,7 +111,6 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ return 0; } spos = pos; - pos += slen; /* Ignore leading zeroes in R */ while (rlen > 0 && input[rpos] == 0) { @@ -122,7 +120,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ /* Copy R value */ if (rlen > 32) { overflow = 1; - } else { + } else if (rlen) { memcpy(tmpsig + 32 - rlen, input + rpos, rlen); } @@ -134,7 +132,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ /* Copy S value */ if (slen > 32) { overflow = 1; - } else { + } else if (slen) { memcpy(tmpsig + 64 - slen, input + spos, slen); } diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h index 6d27871a7..37c8c691f 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h @@ -1,8 +1,8 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /**** * Please do not link this file directly. It is not part of the libsecp256k1 @@ -48,21 +48,27 @@ * 8.3.1. */ -#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ -#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H +/* #include secp256k1.h only when it hasn't been included yet. + This enables this file to be #included directly in other project + files (such as tests.c) without the need to set an explicit -I flag, + which would be necessary to locate secp256k1.h. */ +#ifndef SECP256K1_H #include +#endif -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Parse a signature in "lax DER" format * * Returns: 1 when the signature could be parsed, 0 otherwise. * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the @@ -88,4 +94,4 @@ int ecdsa_signature_parse_der_lax( } #endif -#endif +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c index c2e63b4b8..a1b820007 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c @@ -1,11 +1,10 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include -#include #include "lax_der_privatekey_parsing.h" @@ -45,7 +44,7 @@ int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, co if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { return 0; } - memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); if (!secp256k1_ec_seckey_verify(ctx, out32)) { memset(out32, 0, 32); return 0; diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h index 2fd088f8a..3749e418f 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h @@ -1,8 +1,8 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /**** * Please do not link this file directly. It is not part of the libsecp256k1 @@ -25,20 +25,25 @@ * library are sufficient. */ -#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ -#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H +/* #include secp256k1.h only when it hasn't been included yet. + This enables this file to be #included directly in other project + files (such as tests.c) without the need to set an explicit -I flag, + which would be necessary to locate secp256k1.h. */ +#ifndef SECP256K1_H #include +#endif -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif /** Export a private key in DER format. * * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: privkey: pointer to an array for storing the private key in BER. * Should have space for 279 bytes, and cannot be NULL. * privkeylen: Pointer to an int where the length of the private key in @@ -87,4 +92,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( } #endif -#endif +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/crypto/secp256k1/libsecp256k1/doc/ellswift.md b/crypto/secp256k1/libsecp256k1/doc/ellswift.md new file mode 100644 index 000000000..9d60e6be0 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/doc/ellswift.md @@ -0,0 +1,483 @@ +# ElligatorSwift for secp256k1 explained + +In this document we explain how the `ellswift` module implementation is related to the +construction in the +["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759) +paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi. + +* [1. Introduction](#1-introduction) +* [2. The decoding function](#2-the-decoding-function) + + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1) +* [3. The encoding function](#3-the-encoding-function) + + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates) + + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses) + + [3.3 Finding the inverse](#33-finding-the-inverse) + + [3.4 Dealing with special cases](#34-dealing-with-special-cases) + + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1) +* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates) + + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1) + +## 1. Introduction + +The `ellswift` module effectively introduces a new 64-byte public key format, with the property +that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally +indistinguishable from uniform byte arrays. The module provides functions to convert public keys +from and to this format, as well as convenience functions for key generation and ECDH that operate +directly on ellswift-encoded keys. + +The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$ +and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on +the curve. + +**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$ +are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid +x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function). + +**Encoding** a given $x$ coordinate is conceptually done as follows: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements. + * With probability $1 - \dfrac{\\#L}{8}$, restart the loop. + * Select a uniformly random $t \in L$ and return $(u, t).$ + +This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full +$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates). +The algorithm finds a uniformly random $(u, t)$ among (almost all) those +for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for +almost all x-coordinates on the curve (all but at most 39) is close to two times the field size +(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field). + +## 2. The decoding function + +First some definitions: +* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$ + * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement. +* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$ + public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square. + This implies that the order of $E$ is either odd, or a multiple of *4*. + If $a=0$, this condition is always fulfilled. + * For `secp256k1`, $a=0$ and $b=7.$ +* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$ +* Let the function $h(x) = 3x^3 + 4a.$ +* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$ +* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$ +* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below. +* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below. + +**Note**: In the paper: +* $F_u$ corresponds to $F_{0,u}$ there. +* $P_u(t)$ is called $P$ there. +* All $S_u$ sets together correspond to $S$ there. +* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there. + +Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right +hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$, +out of the three right-hand side factors an even number must be non-squares. +This implies that exactly *1* or exactly *3* out of +$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$, +at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception +to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate. + +**Define** the decoding function $F_u(t)$ as: +* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$ +* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square). + +$P_u(t) = (X(u, t), Y(u, t))$, where: + +$$ +\begin{array}{lcl} +X(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{g(u) - t^2}{2t} & a = 0 \\ + \dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0 +\end{array}\right. \\ +Y(u, t) & = & \left\\{\begin{array}{ll} + \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\ + Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0 +\end{array}\right. +\end{array} +$$ + +$P_u(t)$ is defined: +* For $a=0$, unless: + * $u = 0$ or $t = 0$ (division by zero) + * $g(u) = -t^2$ (would give $Y=0$). +* For $a \neq 0$, unless: + * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero) + * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$). + +The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$ + +The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where: + +$$ +\begin{array}{lcl} + x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\ + x_3 & = & u + 4Y^2 && \\ + z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3} +\end{array} +$$ + +### 2.1 Decoding for `secp256k1` + +Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is: + +**Define** $F_u(t)$ as: +* Let $X = \dfrac{u^3 + b - t^2}{2t}.$ +* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$ +* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square. + +To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case +$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$): + +**Define** $F_u(t)$ as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$). +* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$). +* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$). +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square. + +The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice, +but the approach here is simple enough and gives fairly uniform output even in these cases. + +**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there. +We wish to avoid the need for callers to deal with this special case. + +This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and +in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate). + +## 3. The encoding function + +To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process: +* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$ +* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$ +* For each of the found $t$ values, verify that $F_u(t) = x.$ +* Return the remaining $t$ values. + +The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$ + +$$ +P_u^{-1}(X, Y) = \left\\{\begin{array}{ll} +Yu\sqrt{-3} - X & a = 0 \\ +\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\ +\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u) +\end{array}\right. +$$ + +The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions, +it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the +$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected. + +Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$, +the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid. +This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of +$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out. + +Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as +$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square, +and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined +before those values are computed. + +It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would +take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take +precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$ +values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder; +any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder. + +### 3.1 Switching to *v, w* coordinates + +Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and +$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$ +* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$ +* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$ +* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where + +$$ +\begin{array}{lcl} + x_1 & = & v \\ + x_2 & = & -u - v \\ + x_3 & = & u + w^2 \\ + z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3} +\end{array} +$$ + +We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$ +expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable: +* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions). +* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions). + +### 3.2 Avoiding computing all inverses + +The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the +set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary. + +Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a +uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8, +picking a uniformly random element from that, restarting whenever $\bot$ is picked: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Compute the set $L = F_u^{-1}(x).$ + * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$ + * Select a uniformly random $t \in T.$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly +random element in it, so we do not need to have all $\bot$ values at the end. +As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account), +we can associate every index in $T$ with exactly one of those formulas, making sure that: +* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$ +* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check). +* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those. + +The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting +to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases) +for an analysis of all the negligible cases. + +If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas, +the loop can be simplified to only compute one of the inverses instead of all of them: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +This is implemented in `secp256k1_ellswift_xelligatorswift_var`. + +### 3.3 Finding the inverse + +To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula. +Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression). +Ignoring the negligible cases, we get: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas): + * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence). + * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula) + * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows). +* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas): + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise. +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$ + +Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly +50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen +with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$ +implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered +and $\bot$ would have been returned already. + +**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4). +The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to +have the $G_{c,u}$ be deterministic, and capture all choices in $c.$ + +Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$ +transformation. Furthermore, that transformation has no effect on $s$ in the first branch +as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down: + +**Define** $G_{c,u}(x)$ as: +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a).$ + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$ + +This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input. +There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values. + +### 3.4 Dealing with special cases + +As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs. +For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness +we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that +do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same +$t$ value for multiple $c$ inputs (thereby biasing that encoding): + +* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$): + * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves. + Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve + fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square). + This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$), + the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the + encoder anyway as there will generally be more than 8. + * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence + as it can deal with $g(u)=0$. + This is again only possible on even-ordered curves. +* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$): + * When $s=0$, a division by zero would occur. + * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases. + It is equivalent to checking whether $r=0$. + This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition. + A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first + it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero. +* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder: + * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve. + * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$. + +**Define** a version of $G_{c,u}(x)$ which deals with all these cases: +* If $a=0$ and $u=0$, return $\bot.$ +* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$ +* Depending on $c:$ + * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$ + * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$ + * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$ + * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$ +* If $a=0$ and $t=0$, return $\bot$ (even curves only). +* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$ +* Return $t.$ + +Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once, +for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached: +* All cases where $P_u(t)$ is not defined: + * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$ + * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$ +* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch. + +These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves. + +### 3.5 Encoding for `secp256k1` + +Specialized for odd-ordered $a=0$ curves: + +**Define** $G_{c,u}(x)$ as: +* If $u=0$, return $\bot.$ +* If $c \in \\{0, 1, 4, 5\\}:$ + * If $(-u-x)^3 + b$ is square, return $\bot$ + * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square. + * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$ + * If $s = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$ + * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$ + * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$ + +This is implemented in `secp256k1_ellswift_xswiftec_inv_var`. + +And the x-only ElligatorSwift encoding algorithm is still: + +**Define** *ElligatorSwift(x)* as: +* Loop: + * Pick a uniformly random field element $u.$ + * Pick a uniformly random integer $c$ in $[0,8).$ + * Let $t = G_{c,u}(x).$ + * If $t \neq \bot$, return $(u, t)$; restart loop otherwise. + +Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them. +While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$ +combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity. + +## 4. Encoding and decoding full *(x, y)* coordinates + +So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding +for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information +in $t$ as well. + +Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are +mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$ +being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order +of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead. + +Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode +the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the +four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$ + +**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit. + +To encode the sign of $y$ in the sign of $Y:$ + +**Define** *Decode(u, t)* for full $(x, y)$ as: +* Let $(X, Y) = P_u(t).$ +* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$ + +And encoding would be done using a $G_{c,u}(x, y)$ function defined as: + +**Define** $G_{c,u}(x, y)$ as: +* If $c \in \\{0, 1\\}:$ + * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only). + * If $g(-u-x)$ is square, return $\bot.$ + * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero). + * Let $v = x.$ +* Otherwise, when $c \in \\{2, 3\\}:$ + * Let $s = x-u.$ + * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square. + * If $c = 3$ and $r = 0$, return $\bot.$ + * Let $v = (r/s - u)/2.$ +* Let $w = \sqrt{s}$; return $\bot$ if not square. +* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise. +* Depending on $c:$ + * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$ + * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$ + +Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$ +This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$. + +In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation +of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where +$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$. + +### 4.1 Full *(x, y)* coordinates for `secp256k1` + +For $a=0$ curves, there is another option. Note that for those, +the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to +encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get +as decoder: + +**Define** *Decode(u, t)* as: +* Let $u'=u$ if $u \neq 0$; $1$ otherwise. +* Let $t'=t$ if $t \neq 0$; $1$ otherwise. +* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise. +* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$ +* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$ +* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square. +* Let $y = \sqrt{g(x)}.$ +* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise. + +This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$ + +The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$ + +This is implemented in `secp256k1_ellswift_elligatorswift_var`. + +Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points +where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in +[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift +in the first place. diff --git a/crypto/secp256k1/libsecp256k1/doc/musig.md b/crypto/secp256k1/libsecp256k1/doc/musig.md new file mode 100644 index 000000000..ae21f9b13 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/doc/musig.md @@ -0,0 +1,54 @@ +Notes on the musig module API +=========================== + +The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`). +A usage example can be found in `examples/musig.c`. + +## API misuse + +The musig API is designed with a focus on misuse resistance. +However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation. +While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes. + +Therefore, users of the musig module must take great care to make sure of the following: + +1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`. + See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that. +2. The `secp256k1_musig_secnonce` structure is never copied or serialized. + See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`. +3. Opaque data structures are never written to or read from directly. + Instead, only the provided accessor functions are used. + +## Key Aggregation and (Taproot) Tweaking + +Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`. +A plain tweak can be added to the resulting public key with `secp256k1_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `secp256k1_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341. +Both types of tweaking can be combined and invoked multiple times if the specific application requires it. + +## Signing + +This is covered by `examples/musig.c`. +Essentially, the protocol proceeds in the following steps: + +1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`. +2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants. +3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`. +4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers. +5. Someone (not necessarily the signer) aggregates the public nonces with `secp256k1_musig_nonce_agg` and sends it to the signers. +6. Process the aggregate nonce with `secp256k1_musig_nonce_process`. +7. Create a partial signature with `secp256k1_musig_partial_sign`. +8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`. +9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`. + +The aggregate signature can be verified with `secp256k1_schnorrsig_verify`. + +Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed. +Whenever possible, it is recommended to generate the nonces only after the message is known. +This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios. +However, it does require two rounds of communication during the signing process. +The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing. +Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5). + +## Verification + +A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7. diff --git a/crypto/secp256k1/libsecp256k1/doc/release-process.md b/crypto/secp256k1/libsecp256k1/doc/release-process.md new file mode 100644 index 000000000..a64bae0f0 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/doc/release-process.md @@ -0,0 +1,94 @@ +# Release process + +This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. + +We distinguish between two types of releases: *regular* and *maintenance* releases. +Regular releases are releases of a new major or minor version as well as patches of the most recent release. +Maintenance releases, on the other hand, are required for patches of older releases. + +You should coordinate with the other maintainers on the release date, if possible. +This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release). +It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3. + +This process also assumes that there will be no minor releases for old major releases. + +We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core. + +## Sanity checks +Perform these checks when reviewing the release PR (see below): + +1. Ensure `make distcheck` doesn't fail. + ```shell + ./autogen.sh && ./configure --enable-dev-mode && make distcheck + ``` +2. Check installation with autotools: + ```shell + dir=$(mktemp -d) + ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa + ``` +3. Check installation with CMake: + ```shell + dir=$(mktemp -d) + build=$(mktemp -d) + cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa + ``` +4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. + ```shell + tools/check-abi.sh + ``` + +## Regular release + +1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that + * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by + * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), + * removing the `[Unreleased]` section header, + * ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and + * including an entry for `### ABI Compatibility` if it doesn't exist, + * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, + * if this is not a patch release, + * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and + * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. +2. Perform the [sanity checks](#sanity-checks) on the PR branch. +3. After the PR is merged, tag the commit, and push the tag: + ``` + RELEASE_COMMIT= + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that + * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, + * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and + * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). + + If other maintainers are not present to approve the PR, it can be merged without ACKs. +5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +6. Send an announcement email to the bitcoin-dev mailing list. + +## Maintenance release + +Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists. + +1. If there's no maintenance branch `$MAJOR.$MINOR`, create one: + ``` + git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1)) + git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR + ``` +2. Open a pull request to the `$MAJOR.$MINOR` branch that + * includes the bug fixes, + * finalizes the release notes similar to a regular release, + * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` + and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt` + (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). +3. Perform the [sanity checks](#sanity-checks) on the PR branch. +4. After the PRs are merged, update the release branch, tag the commit, and push the tag: + ``` + git checkout $MAJOR.$MINOR && git pull + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +7. Send an announcement email to the bitcoin-dev mailing list. +8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/crypto/secp256k1/libsecp256k1/doc/safegcd_implementation.md b/crypto/secp256k1/libsecp256k1/doc/safegcd_implementation.md new file mode 100644 index 000000000..5dbbb7bbd --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/doc/safegcd_implementation.md @@ -0,0 +1,819 @@ +# The safegcd implementation in libsecp256k1 explained + +This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. +It is based on the paper +["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) +by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. + +The actual implementation is in C of course, but for demonstration purposes Python3 is used here. +Most implementation aspects and optimizations are explained, except those that depend on the specific +number representation used in the C code. + +## 1. Computing the Greatest Common Divisor (GCD) using divsteps + +The algorithm from the paper (section 11), at a very high level, is this: + +```python +def gcd(f, g): + """Compute the GCD of an odd integer f and another integer g.""" + assert f & 1 # require f to be odd + delta = 1 # additional state variable + while g != 0: + assert f & 1 # f will be odd in every iteration + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + elif g & 1: + delta, f, g = 1 + delta, f, (g + f) // 2 + else: + delta, f, g = 1 + delta, f, (g ) // 2 + return abs(f) +``` + +It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop +keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until +*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a +"division step" (referred to as divstep in what follows). + +For example, *gcd(21, 14)* would be computed as: +- Start with *δ=1 f=21 g=14* +- Take the third branch: *δ=2 f=21 g=7* +- Take the first branch: *δ=-1 f=7 g=-7* +- Take the second branch: *δ=0 f=7 g=0* +- The answer *|f| = 7*. + +Why it works: +- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper): + - (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*. + - (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even). +- Neither of those two operations change the GCD: + - For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a* + and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has + common factor *c*. Reasoning in the other direction shows that no common factor can be added by + doing so either. + - For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove + it from *g*. +- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3). +- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the + gcd of *f'* and *0* is *|f'|* by definition, that is our answer. + +Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at +the low-order bits of the variables to decide the next steps, and being easy to make +constant-time (in more low-level languages than Python). The *δ* parameter is necessary to +guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look +at high order bits. + +Properties that will become important later: +- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*. +- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we + do not need to worry about rounding. +- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N* + bits of *f* and *g*, and on *δ*. + + +## 2. From GCDs to modular inverses + +We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=1 +mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is +prime and *0 < x < M*. In what follows, assume that the modular inverse exists. +It turns out this inverse can be computed as a side effect of computing the GCD by keeping track +of how the internal variables can be written as linear combinations of the inputs at every step +(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)). +Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*. +Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x +mod M*. + +A similar approach can be used to calculate modular inverses using the divsteps-based GCD +algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping +track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*. +*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M* +and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M += 1*). + +```python +def div2(M, x): + """Helper routine to compute x/2 mod M (where M is odd).""" + assert M & 1 + if x & 1: # If x is odd, make it even by adding M. + x += M + # x must be even now, so a clean division by 2 is possible. + return x // 2 + +def modinv(M, x): + """Compute the inverse of x mod M (given that it exists, and M is odd).""" + assert M & 1 + delta, f, g, d, e = 1, M, x, 0, 1 + while g != 0: + # Note that while division by two for f and g is only ever done on even inputs, this is + # not true for d and e, so we need the div2 helper function. + if delta > 0 and g & 1: + delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d) + elif g & 1: + delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d) + else: + delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e ) + # Verify that the invariants d=f/x mod M, e=g/x mod M are maintained. + assert f % M == (d * x) % M + assert g % M == (e * x) % M + assert f == 1 or f == -1 # |f| is the GCD, it must be 1 + # Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f. + return (d * f) % M +``` + +Also note that this approach to track *d* and *e* throughout the computation to determine the inverse +is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the +entire computation is determined (see section 3 below) and the inverse is computed from that. +The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to +be faster at the level of optimization we're able to do in C. + + +## 3. Batching multiple divsteps + +Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)* +to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper): + +``` + t = [ u, v ] + [ q, r ] + + [ out_f ] = (1/2 * t) * [ in_f ] + [ out_g ] = [ in_g ] + + [ out_d ] = (1/2 * t) * [ in_d ] (mod M) + [ out_e ] [ in_e ] +``` + +where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is +taken. As above, the resulting *f* and *g* are always integers. + +Performing multiple divsteps corresponds to a multiplication with the product of all the +individual divsteps' transition matrices. As each transition matrix consists of integers +divided by *2*, the product of these matrices will consist of integers divided by *2N* (see also +theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay +them: we compute the integer coefficients of the combined transition matrix scaled by *2N*, and +do one division by *2N* as a final step: + +```python +def divsteps_n_matrix(delta, f, g): + """Compute delta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 # start with identity matrix + for _ in range(N): + if delta > 0 and g & 1: + delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v + elif g & 1: + delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v + else: + delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r + return delta, (u, v, q, r) +``` + +As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this +function to compute the transition matrix only needs to see those bottom bits. Furthermore all +intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*, +*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit +integers could set *N=62* and compute the full transition matrix for 62 steps at once without any +big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs +to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps. + +We still need functions to compute: + +``` + [ out_f ] = (1/2^N * [ u, v ]) * [ in_f ] + [ out_g ] ( [ q, r ]) [ in_g ] + + [ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M) + [ out_e ] ( [ q, r ]) [ in_e ] +``` + +Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f* +and *g* will be multiple of *2N*, and division by *2N* is simply shifting them down: + +```python +def update_fg(f, g, t): + """Multiply matrix t/2^N with [f, g].""" + u, v, q, r = t + cf, cg = u*f + v*g, q*f + r*g + # (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero + # bottom bits. + assert cf % 2**N == 0 + assert cg % 2**N == 0 + return cf >> N, cg >> N +``` + +The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2N mod M*. +This is easy if we have precomputed *1/M mod 2N* (which always exists for odd *M*): + +```python +def div2n(M, Mi, x): + """Compute x/2^N mod M, given Mi = 1/M mod 2^N.""" + assert (M * Mi) % 2**N == 1 + # Find a factor m such that m*M has the same bottom N bits as x. We want: + # (m * M) mod 2^N = x mod 2^N + # <=> m mod 2^N = (x / M) mod 2^N + # <=> m mod 2^N = (x * Mi) mod 2^N + m = (Mi * x) % 2**N + # Subtract that multiple from x, cancelling its bottom N bits. + x -= m * M + # Now a clean division by 2^N is possible. + assert x % 2**N == 0 + return (x >> N) % M + +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + cd, ce = u*d + v*e, q*d + r*e + return div2n(M, Mi, cd), div2n(M, Mi, ce) +``` + +With all of those, we can write a version of `modinv` that performs *N* divsteps at once: + +```python3 +def modinv(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" + assert M & 1 + delta, f, g, d, e = 1, M, x, 0, 1 + while g != 0: + # Compute the delta and transition matrix t for the next N divsteps (this only needs + # (N+1)-bit signed integer arithmetic). + delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N) + # Apply the transition matrix t to [f, g]: + f, g = update_fg(f, g, t) + # Apply the transition matrix t to [d, e]: + d, e = update_de(d, e, t, M, Mi) + return (d * f) % M +``` + +This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem +because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps +increasing). For variable time code such excess iterations will be mostly optimized away in later +sections. + + +## 4. Avoiding modulus operations + +So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of +`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the +sign of *f*. These are relatively expensive operations when done generically. + +To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range +*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus +operation at the end: + +```python +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e] mod M, given Mi=1/M mod 2^N.""" + u, v, q, r = t + cd, ce = u*d + v*e, q*d + r*e + # Cancel out bottom N bits of cd and ce. + md = -((Mi * cd) % 2**N) + me = -((Mi * ce) % 2**N) + cd += md * M + ce += me * M + # And cleanly divide by 2**N. + return cd >> N, ce >> N +``` + +Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|* +never exceed *2N* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have +outputs whose absolute values are at most *2N* times the maximum absolute input value. In case the +inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming +*M > 1*, the multiplication results in numbers in range *(-2NM,2NM)*. Subtracting less than *2N* +times *M* to cancel out *N* bits brings that up to *(-2N+1M,2NM)*, and +dividing by *2N* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that +to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be +counteracted by incrementing *d* and *e* by *M* whenever they're negative: + +```python + ... + if d < 0: + d += M + if e < 0: + e += M + cd, ce = u*d + v*e, q*d + r*e + # Cancel out bottom N bits of cd and ce. + ... +``` + +With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the +output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de` +invocations there are. In what follows, we will try to make this more efficient. + +Note that increasing *d* by *M* is equal to incrementing *cd* by *u M* and *ce* by *q M*. Similarly, +increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write: + +```python + ... + cd, ce = u*d + v*e, q*d + r*e + # Perform the equivalent of incrementing d, e by M when they're negative. + if d < 0: + cd += u*M + ce += q*M + if e < 0: + cd += v*M + ce += r*M + # Cancel out bottom N bits of cd and ce. + md = -((Mi * cd) % 2**N) + me = -((Mi * ce) % 2**N) + cd += md * M + ce += me * M + ... +``` + +Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this +increment, and the decrement that cancels out bottom bits. The second one depends on the first +one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce* +at first, and using that to compute the final *md*, *me* values: + +```python +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + md, me = 0, 0 + # Compute what multiples of M to add to cd and ce. + if d < 0: + md += u + me += q + if e < 0: + md += v + me += r + # Compute bottom N bits of t*[d,e] + M*[md,me]. + cd, ce = (u*d + v*e + md*M) % 2**N, (q*d + r*e + me*M) % 2**N + # Correct md and me such that the bottom N bits of t*[d,e] + M*[md,me] are zero. + md -= (Mi * cd) % 2**N + me -= (Mi * ce) % 2**N + # Do the full computation. + cd, ce = u*d + v*e + md*M, q*d + r*e + me*M + # And cleanly divide by 2**N. + return cd >> N, ce >> N +``` + +One last optimization: we can avoid the *md M* and *me M* multiplications in the bottom bits of *cd* +and *ce* by moving them to the *md* and *me* correction: + +```python + ... + # Compute bottom N bits of t*[d,e]. + cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N + # Correct md and me such that the bottom N bits of t*[d,e]+M*[md,me] are zero. + # Note that this is not the same as {md = (-Mi * cd) % 2**N} etc. That would also result in N + # zero bottom bits, but isn't guaranteed to be a reduction of [0,2^N) compared to the + # previous md and me values, and thus would violate our bounds analysis. + md -= (Mi*cd + md) % 2**N + me -= (Mi*ce + me) % 2**N + ... +``` + +The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same +range. That also means that the *d* value at the end of `modinv` will be in that range, while we want +a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the +conditional negation of *d* (based on the sign of *f*) into it as well: + +```python +def normalize(sign, v, M): + """Compute sign*v mod M, where v is in range (-2*M,M); output in [0,M).""" + assert sign == 1 or sign == -1 + # v in (-2*M,M) + if v < 0: + v += M + # v in (-M,M). Now multiply v with sign (which can only be 1 or -1). + if sign == -1: + v = -v + # v in (-M,M) + if v < 0: + v += M + # v in [0,M) + return v +``` + +And calling it in `modinv` is simply: + +```python + ... + return normalize(f, d, M) +``` + + +## 5. Constant-time operation + +The primary selling point of the algorithm is fast constant-time operation. What code flow still +depends on the input data so far? + +- the number of iterations of the while *g ≠ 0* loop in `modinv` +- the branches inside `divsteps_n_matrix` +- the sign checks in `update_de` +- the sign checks in `normalize` + +To make the while loop in `modinv` constant time it can be replaced with a constant number of +iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit +inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is +sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of +*⌈724/N⌉* times. + +To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise +operations (and hope the C compiler isn't smart enough to turn them back into branches; see +`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a +divstep can be written instead as (compare to the inner loop of `gcd` in section 1). + +```python + x = -f if delta > 0 else f # set x equal to (input) -f or f + if g & 1: + g += x # set g to (input) g-f or g+f + if delta > 0: + delta = -delta + f += g # set f to (input) g (note that g was set to g-f before) + delta += 1 + g >>= 1 +``` + +To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the +definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As +*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows +that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then +*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*. + +Using this we can write: + +```python + x = -f if delta > 0 else f +``` + +in constant-time form as: + +```python + c1 = (-delta) >> 63 + # Conditionally negate f based on c1: + x = (f ^ c1) - c1 +``` + +To use that trick, we need a helper mask variable *c1* that resolves the condition *δ>0* to *-1* +(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by +the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see +`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all +numbers in range *[-263,0)* to *-1*, and numbers in range *[0,263)* to *0*. + +Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write: + +```python + if g & 1: + g += x +``` + +as: + +```python + # Compute c2=0 if g is even and c2=-1 if g is odd. + c2 = -(g & 1) + # This masks out x if g is even, and leaves x be if g is odd. + g += x & c2 +``` + +Using the conditional negation trick again we can write: + +```python + if g & 1: + if delta > 0: + delta = -delta +``` + +as: + +```python + # Compute c3=-1 if g is odd and delta>0, and 0 otherwise. + c3 = c1 & c2 + # Conditionally negate delta based on c3: + delta = (delta ^ c3) - c3 +``` + +Finally: + +```python + if g & 1: + if delta > 0: + f += g +``` + +becomes: + +```python + f += g & c3 +``` + +It turns out that this can be implemented more efficiently by applying the substitution +*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing +*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1* +computation: + +```python + # Compute a mask c1 for eta < 0, and compute the conditional negation x of f: + c1 = eta >> 63 + x = (f ^ c1) - c1 + # Compute a mask c2 for odd g, and conditionally add x to g: + c2 = -(g & 1) + g += x & c2 + # Compute a mask c for (eta < 0) and odd (input) g, and use it to conditionally negate eta, + # and add g to f: + c3 = c1 & c2 + eta = (eta ^ c3) - c3 + f += g & c3 + # Incrementing delta corresponds to decrementing eta. + eta -= 1 + g >>= 1 +``` + +A variant of divsteps with better worst-case performance can be used instead: starting *δ* at +*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs +(which can be shown using convex hull analysis). In this case, the substitution *ζ=-(δ+1/2)* +is used instead to keep the variable integral. Incrementing *δ* by *1* still translates to +decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or +*~ζ*. Doing that conditionally based on *c3* is simply: + +```python + ... + c3 = c1 & c2 + zeta ^= c3 + ... +``` + +By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to +also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of +`divsteps_n_matrix` is obtained. The full code will be in section 7. + +These bit fiddling tricks can also be used to make the conditional negations and additions in +`update_de` and `normalize` constant-time. + + +## 6. Variable-time optimizations + +In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time. +Constant time operations are only necessary when computing modular inverses of secret data. In +other cases, it slows down calculations unnecessarily. In this section, we will construct a +faster non-constant time `divsteps_n_matrix` function. + +To do so, first consider yet another way of writing the inner loop of divstep operations in +`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use +the original version with initial *δ=1* and *η=-δ* here. + +```python +for _ in range(N): + if g & 1 and eta < 0: + eta, f, g = -eta, g, -f + if g & 1: + g += f + eta -= 1 + g >>= 1 +``` + +Whenever *g* is even, the loop only shifts *g* down and decreases *η*. When *g* ends in multiple zero +bits, these iterations can be consolidated into one step. This requires counting the bottom zero +bits efficiently, which is possible on most platforms; it is abstracted here as the function +`count_trailing_zeros`. + +```python +def count_trailing_zeros(v): + """ + When v is zero, consider all N zero bits as "trailing". + For a non-zero value v, find z such that v=(d<>= zeros + i -= zeros + if i == 0: + break + # We know g is odd now + if eta < 0: + eta, f, g = -eta, g, -f + g += f + # g is even now, and the eta decrement and g shift will happen in the next loop. +``` + +We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever +there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as +well. + +Observe that as long as *η ≥ 0*, the loop does not modify *f*. Instead, it cancels out bottom +bits of *g* and shifts them out, and decreases *η* and *i* accordingly - interrupting only when *η* +becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to +*g* to cancel out multiple bottom bits, and then shifting them out. + +It is easy to find what that multiple is: we want a number *w* such that *g+w f* has a few bottom +zero bits. If that number of bits is *L*, we want *g+w f mod 2L = 0*, or *w = -g/f mod 2L*. Since *f* +is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before +doing more) or more than *η+1* steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but +apart from that, we're only limited by the complexity of computing *w*. + +This code demonstrates how to cancel up to 4 bits per step: + +```python +NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n +i = N +while True: + zeros = min(i, count_trailing_zeros(g)) + eta -= zeros + g >>= zeros + i -= zeros + if i == 0: + break + # We know g is odd now + if eta < 0: + eta, f, g = -eta, g, -f + # Compute limit on number of bits to cancel + limit = min(min(eta + 1, i), 4) + # Compute w = -g/f mod 2**limit, using the table value for -1/f mod 2**4. Note that f is + # always odd, so its inverse modulo a power of two always exists. + w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) + # As w = -g/f mod (2**limit), g+w*f mod 2**limit = 0 mod 2**limit. + g += w * f + assert g % (2**limit) == 0 + # The next iteration will now shift out at least limit bottom zero bits from g. +``` + +By using a bigger table more bits can be cancelled at once. The table can also be implemented +as a formula. Several formulas are known for computing modular inverses modulo powers of two; +some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pages 245-247. +Here we need the negated modular inverse, which is a simple transformation of those: + +- Instead of a 3-bit table: + - *-f* or *f ^ 6* +- Instead of a 4-bit table: + - *1 - f(f + 1)* + - *-(f + (((f + 1) & 4) << 1))* +- For larger tables the following technique can be used: if *w=-1/f mod 2L*, then *w(w f+2)* is + *-1/f mod 22L*. This allows extending the previous formulas (or tables). In particular we + have this 6-bit function (based on the 3-bit function above): + - *f(f2 - 2)* + +This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in +`divsteps_n_matrix`, gives a significantly faster, but non-constant time version. + + +## 7. Final Python version + +All together we need the following functions: + +- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function + from section 2, but with its loop replaced by a variant of the constant-time divstep from + section 5, extended to handle *u*, *v*, *q*, *r*: + +```python +def divsteps_n_matrix(zeta, f, g): + """Compute zeta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 # start with identity matrix + for _ in range(N): + c1 = zeta >> 63 + # Compute x, y, z as conditionally-negated versions of f, u, v. + x, y, z = (f ^ c1) - c1, (u ^ c1) - c1, (v ^ c1) - c1 + c2 = -(g & 1) + # Conditionally add x, y, z to g, q, r. + g, q, r = g + (x & c2), q + (y & c2), r + (z & c2) + c1 &= c2 # reusing c1 here for the earlier c3 variable + zeta = (zeta ^ c1) - 1 # inlining the unconditional zeta decrement here + # Conditionally add g, q, r to f, u, v. + f, u, v = f + (g & c1), u + (q & c1), v + (r & c1) + # When shifting g down, don't shift q, r, as we construct a transition matrix multiplied + # by 2^N. Instead, shift f's coefficients u and v up. + g, u, v = g >> 1, u << 1, v << 1 + return zeta, (u, v, q, r) +``` + +- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time + changes to `update_de` from section 5: + +```python +def update_fg(f, g, t): + """Multiply matrix t/2^N with [f, g].""" + u, v, q, r = t + cf, cg = u*f + v*g, q*f + r*g + return cf >> N, cg >> N + +def update_de(d, e, t, M, Mi): + """Multiply matrix t/2^N with [d, e], modulo M.""" + u, v, q, r = t + d_sign, e_sign = d >> 257, e >> 257 + md, me = (u & d_sign) + (v & e_sign), (q & d_sign) + (r & e_sign) + cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N + md -= (Mi*cd + md) % 2**N + me -= (Mi*ce + me) % 2**N + cd, ce = u*d + v*e + M*md, q*d + r*e + M*me + return cd >> N, ce >> N +``` + +- The `normalize` function from section 4, made constant time as well: + +```python +def normalize(sign, v, M): + """Compute sign*v mod M, where v in (-2*M,M); output in [0,M).""" + v_sign = v >> 257 + # Conditionally add M to v. + v += M & v_sign + c = (sign - 1) >> 1 + # Conditionally negate v. + v = (v ^ c) - c + v_sign = v >> 257 + # Conditionally add M to v again. + v += M & v_sign + return v +``` + +- And finally the `modinv` function too, adapted to use *ζ* instead of *δ*, and using the fixed + iteration count from section 5: + +```python +def modinv(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi=1/M mod 2^N.""" + zeta, f, g, d, e = -1, M, x, 0, 1 + for _ in range((590 + N - 1) // N): + zeta, t = divsteps_n_matrix(zeta, f % 2**N, g % 2**N) + f, g = update_fg(f, g, t) + d, e = update_de(d, e, t, M, Mi) + return normalize(f, d, M) +``` + +- To get a variable time version, replace the `divsteps_n_matrix` function with one that uses the + divsteps loop from section 5, and a `modinv` version that calls it without the fixed iteration + count: + +```python +NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n +def divsteps_n_matrix_var(eta, f, g): + """Compute eta and transition matrix t after N divsteps (multiplied by 2^N).""" + u, v, q, r = 1, 0, 0, 1 + i = N + while True: + zeros = min(i, count_trailing_zeros(g)) + eta, i = eta - zeros, i - zeros + g, u, v = g >> zeros, u << zeros, v << zeros + if i == 0: + break + if eta < 0: + eta, f, u, v, g, q, r = -eta, g, q, r, -f, -u, -v + limit = min(min(eta + 1, i), 4) + w = (g * NEGINV16[(f & 15) // 2]) % (2**limit) + g, q, r = g + w*f, q + w*u, r + w*v + return eta, (u, v, q, r) + +def modinv_var(M, Mi, x): + """Compute the modular inverse of x mod M, given Mi = 1/M mod 2^N.""" + eta, f, g, d, e = -1, M, x, 0, 1 + while g != 0: + eta, t = divsteps_n_matrix_var(eta, f % 2**N, g % 2**N) + f, g = update_fg(f, g, t) + d, e = update_de(d, e, t, M, Mi) + return normalize(f, d, Mi) +``` + +## 8. From GCDs to Jacobi symbol + +We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an +extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we +make corresponding updates to *j* using +[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): +* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). +* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). + +These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied +very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this +calculation is slightly simpler than the one for the modular inverse because we no longer need to +keep track of *d* and *e*. + +However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for +positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative +values. We resolve this by using the following modified steps: + +```python + # Before + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + + # After + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g + f) // 2 +``` + +The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 +and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm +will converge. The justification for posdivsteps is completely empirical: in practice, it appears +that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a +number of steps proportional to their logarithm. + +Note that: +- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. +- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. +- We need to update the termination condition from *g=0* to *f=1*. + +We account for the possibility of nonconvergence by only performing a bounded number of +posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not +yet been found. + +The optimizations in sections 3-7 above are described in the context of the original divsteps, but +in the C implementation we also adapt most of them (not including "avoiding modulus operations", +since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate +Jacobi symbols for secret data) to the posdivsteps version. diff --git a/crypto/secp256k1/libsecp256k1/examples/CMakeLists.txt b/crypto/secp256k1/libsecp256k1/examples/CMakeLists.txt new file mode 100644 index 000000000..c9da9de6b --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/CMakeLists.txt @@ -0,0 +1,31 @@ +function(add_example name) + set(target_name ${name}_example) + add_executable(${target_name} ${name}.c) + target_include_directories(${target_name} PRIVATE + ${PROJECT_SOURCE_DIR}/include + ) + target_link_libraries(${target_name} + secp256k1 + $<$:bcrypt> + ) + set(test_name ${name}_example) + add_test(NAME secp256k1_${test_name} COMMAND ${target_name}) +endfunction() + +add_example(ecdsa) + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_example(ecdh) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + add_example(schnorr) +endif() + +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_example(ellswift) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + add_example(musig) +endif() diff --git a/crypto/secp256k1/libsecp256k1/examples/EXAMPLES_COPYING b/crypto/secp256k1/libsecp256k1/examples/EXAMPLES_COPYING new file mode 100644 index 000000000..0e259d42c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/EXAMPLES_COPYING @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/crypto/secp256k1/libsecp256k1/examples/ecdh.c b/crypto/secp256k1/libsecp256k1/examples/ecdh.c new file mode 100644 index 000000000..67b8c2047 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/ecdh.c @@ -0,0 +1,121 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +#include "examples_util.h" + +int main(void) { + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char compressed_pubkey1[33]; + unsigned char compressed_pubkey2[33]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + unsigned char randomize[32]; + int return_val; + size_t len; + secp256k1_pubkey pubkey1; + secp256k1_pubkey pubkey2; + + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return EXIT_FAILURE; + } + + /* Public key creation using a valid context with a verified secret key should never fail */ + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1); + assert(return_val); + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2); + assert(return_val); + + /* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */ + len = sizeof(compressed_pubkey1); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey1)); + + /* Serialize pubkey2 in a compressed form (33 bytes) */ + len = sizeof(compressed_pubkey2); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey2)); + + /*** Creating the shared secret ***/ + + /* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified + * seckey and valid pubkey */ + return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL); + assert(return_val); + + /* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified + * seckey and valid pubkey */ + return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf("Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf("Compressed Pubkey1: "); + print_hex(compressed_pubkey1, sizeof(compressed_pubkey1)); + printf("\nSecret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf("Compressed Pubkey2: "); + print_hex(compressed_pubkey2, sizeof(compressed_pubkey2)); + printf("\nShared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/examples/ecdsa.c b/crypto/secp256k1/libsecp256k1/examples/ecdsa.c new file mode 100644 index 000000000..ae16c180d --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/ecdsa.c @@ -0,0 +1,138 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "examples_util.h" + +int main(void) { + /* Instead of signing the message directly, we must sign a 32-byte hash. + * Here the message is "Hello, world!" and the hash function was SHA-256. + * An actual implementation should just call SHA-256, but this example + * hardcodes the output to avoid depending on an additional library. + * See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */ + unsigned char msg_hash[32] = { + 0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4, + 0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64, + 0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34, + 0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3, + }; + unsigned char seckey[32]; + unsigned char randomize[32]; + unsigned char compressed_pubkey[33]; + unsigned char serialized_signature[64]; + size_t len; + int is_signature_valid, is_signature_valid2; + int return_val; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return EXIT_FAILURE; + } + + /* Public key creation using a valid context with a verified secret key should never fail */ + return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey); + assert(return_val); + + /* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */ + len = sizeof(compressed_pubkey); + return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED); + assert(return_val); + /* Should be the same size as the size of the output, because we passed a 33 byte array. */ + assert(len == sizeof(compressed_pubkey)); + + /*** Signing ***/ + + /* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a + * custom nonce function, passing `NULL` will use the RFC-6979 safe default. + * Signing with a valid context, verified secret key + * and the default nonce function should never fail. */ + return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL); + assert(return_val); + + /* Serialize the signature in a compact form. Should always return 1 + * according to the documentation in secp256k1.h. */ + return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig); + assert(return_val); + + + /*** Verification ***/ + + /* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */ + if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) { + printf("Failed parsing the signature\n"); + return EXIT_FAILURE; + } + + /* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ + if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) { + printf("Failed parsing the public key\n"); + return EXIT_FAILURE; + } + + /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ + is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey); + + printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); + printf("Secret Key: "); + print_hex(seckey, sizeof(seckey)); + printf("Public Key: "); + print_hex(compressed_pubkey, sizeof(compressed_pubkey)); + printf("Signature: "); + print_hex(serialized_signature, sizeof(serialized_signature)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static, + &sig, msg_hash, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey, sizeof(seckey)); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/examples/ellswift.c b/crypto/secp256k1/libsecp256k1/examples/ellswift.c new file mode 100644 index 000000000..d58e96b05 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/ellswift.c @@ -0,0 +1,122 @@ +/************************************************************************* + * Written in 2024 by Sebastian Falbesoner * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the ElligatorSwift module to perform + * a key exchange according to BIP 324. Additionally, see the documentation + * in include/secp256k1_ellswift.h and doc/ellswift.md. + */ + +#include +#include +#include +#include + +#include +#include + +#include "examples_util.h" + +int main(void) { + secp256k1_context* ctx; + unsigned char randomize[32]; + unsigned char auxrand1[32]; + unsigned char auxrand2[32]; + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char ellswift_pubkey1[64]; + unsigned char ellswift_pubkey2[64]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + int return_val; + + /* Create a secp256k1 context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage. See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Generate secret keys ***/ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return EXIT_FAILURE; + } + + /* Generate ElligatorSwift public keys. This should never fail with valid context and + verified secret keys. Note that providing additional randomness (fourth parameter) is + optional, but recommended. */ + if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1); + assert(return_val); + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2); + assert(return_val); + + /*** Create the shared secret on each side ***/ + + /* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail + * with a verified seckey and valid pubkey. Note that both parties pass both + * EllSwift pubkeys in the same order; the pubkey of the calling party is + * determined by the "party" boolean (sixth parameter). */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2, + seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail + * with a verified seckey and valid pubkey. */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2, + seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf( " Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf( "EllSwift Pubkey1: "); + print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1)); + printf("\n Secret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf( "EllSwift Pubkey2: "); + print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2)); + printf("\n Shared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/examples/examples_util.h b/crypto/secp256k1/libsecp256k1/examples/examples_util.h new file mode 100644 index 000000000..3293b6403 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/examples_util.h @@ -0,0 +1,108 @@ +/************************************************************************* + * Copyright (c) 2020-2021 Elichai Turkel * + * Distributed under the CC0 software license, see the accompanying file * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/* + * This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems. + * It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below. + * + * Platform randomness sources: + * Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom + * macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html + * FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 + * OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom + * Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + */ + +#if defined(_WIN32) +/* + * The defined WIN32_NO_STATUS macro disables return code definitions in + * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. + */ +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS +#include +#include +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(__OpenBSD__) +#include +#else +#error "Couldn't identify the OS" +#endif + +#include +#include +#include + + +/* Returns 1 on success, and 0 on failure. */ +static int fill_random(unsigned char* data, size_t size) { +#if defined(_WIN32) + NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); + if (res != STATUS_SUCCESS || size > ULONG_MAX) { + return 0; + } else { + return 1; + } +#elif defined(__linux__) || defined(__FreeBSD__) + /* If `getrandom(2)` is not available you should fallback to /dev/urandom */ + ssize_t res = getrandom(data, size, 0); + if (res < 0 || (size_t)res != size ) { + return 0; + } else { + return 1; + } +#elif defined(__APPLE__) || defined(__OpenBSD__) + /* If `getentropy(2)` is not available you should fallback to either + * `SecRandomCopyBytes` or /dev/urandom */ + int res = getentropy(data, size); + if (res == 0) { + return 1; + } else { + return 0; + } +#endif + return 0; +} + +static void print_hex(unsigned char* data, size_t size) { + size_t i; + printf("0x"); + for (i = 0; i < size; i++) { + printf("%02x", data[i]); + } + printf("\n"); +} + +#if defined(_MSC_VER) +// For SecureZeroMemory +#include +#endif +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static void secure_erase(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is + * pretty efficient, because the compiler can still implement the memset() efficiently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +} diff --git a/crypto/secp256k1/libsecp256k1/examples/musig.c b/crypto/secp256k1/libsecp256k1/examples/musig.c new file mode 100644 index 000000000..bdb8fced0 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/musig.c @@ -0,0 +1,261 @@ +/************************************************************************* + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the MuSig module to create a + * 3-of-3 multisignature. Additionally, see the documentation in + * include/secp256k1_musig.h and doc/musig.md. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "examples_util.h" + +struct signer_secrets { + secp256k1_keypair keypair; + secp256k1_musig_secnonce secnonce; +}; + +struct signer { + secp256k1_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_partial_sig partial_sig; +}; + + /* Number of public keys involved in creating the aggregate signature */ +#define N_SIGNERS 3 +/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ +static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { + unsigned char seckey[32]; + + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 0; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { + return 0; + } + if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { + return 0; + } + + secure_erase(seckey, sizeof(seckey)); + return 1; +} + +/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache + * and return the tweaked aggregate pk. */ +static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) { + secp256k1_pubkey output_pk; + /* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP + * 32. */ + unsigned char plain_tweak[32] = "this could be a BIP32 tweak...."; + /* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as + * defined in BIP 341 */ + unsigned char xonly_tweak[32] = "this could be a Taproot tweak.."; + + + /* Plain tweaking which, for example, allows deriving multiple child + * public keys from a single aggregate key using BIP32 */ + if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) { + return 0; + } + /* Note that we did not provide an output_pk argument, because the + * resulting pk is also saved in the cache and so if one is just interested + * in signing, the output_pk argument is unnecessary. On the other hand, if + * one is not interested in signing, the same output_pk can be obtained by + * calling `secp256k1_musig_pubkey_get` right after key aggregation to get + * the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */ + + /* Xonly tweaking which, for example, allows creating Taproot commitments */ + if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) { + return 0; + } + /* Note that if we wouldn't care about signing, we can arrive at the same + * output_pk by providing the untweaked public key to + * `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey + * if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */ + + /* Now we convert the output_pk to an xonly pubkey to allow to later verify + * the Schnorr signature against it. For this purpose we can ignore the + * `pk_parity` output argument; we would need it if we would have to open + * the Taproot commitment. */ + if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) { + return 0; + } + return 1; +} + +/* Sign a message hash with the given key pairs and store the result in sig */ +static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) { + int i; + const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS]; + const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS]; + /* The same for all signers */ + secp256k1_musig_session session; + secp256k1_musig_aggnonce agg_pubnonce; + + for (i = 0; i < N_SIGNERS; i++) { + unsigned char seckey[32]; + unsigned char session_secrand[32]; + /* Create random session ID. It is absolutely necessary that the session ID + * is unique for every call of secp256k1_musig_nonce_gen. Otherwise + * it's trivial for an attacker to extract the secret key! */ + if (!fill_random(session_secrand, sizeof(session_secrand))) { + return 0; + } + if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { + return 0; + } + /* Initialize session and create secret nonce for signing and public + * nonce to send to the other signers. */ + if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { + return 0; + } + pubnonces[i] = &signer[i].pubnonce; + + secure_erase(seckey, sizeof(seckey)); + } + + /* Communication round 1: Every signer sends their pubnonce to the + * coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends + * agg_pubnonce to each signer */ + if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) { + return 0; + } + + /* Every signer creates a partial signature */ + for (i = 0; i < N_SIGNERS; i++) { + /* Initialize the signing session by processing the aggregate nonce */ + if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) { + return 0; + } + /* partial_sign will clear the secnonce by setting it to 0. That's because + * you must _never_ reuse the secnonce (or use the same session_secrand to + * create a secnonce). If you do, you effectively reuse the nonce and + * leak the secret key. */ + if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { + return 0; + } + partial_sigs[i] = &signer[i].partial_sig; + } + /* Communication round 2: Every signer sends their partial signature to the + * coordinator, who verifies the partial signatures and aggregates them. */ + for (i = 0; i < N_SIGNERS; i++) { + /* To check whether signing was successful, it suffices to either verify + * the aggregate signature with the aggregate public key using + * secp256k1_schnorrsig_verify, or verify all partial signatures of all + * signers individually. Verifying the aggregate signature is cheaper but + * verifying the individual partial signatures has the advantage that it + * can be used to determine which of the partial signatures are invalid + * (if any), i.e., which of the partial signatures cause the aggregate + * signature to be invalid and thus the protocol run to fail. It's also + * fine to first verify the aggregate sig, and only verify the individual + * sigs if it does not work. + */ + if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) { + return 0; + } + } + return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS); +} + +int main(void) { + secp256k1_context* ctx; + int i; + struct signer_secrets signer_secrets[N_SIGNERS]; + struct signer signers[N_SIGNERS]; + const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache cache; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg"; + unsigned char sig[64]; + + /* Create a secp256k1 context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + printf("Creating key pairs......"); + fflush(stdout); + for (i = 0; i < N_SIGNERS; i++) { + if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + pubkeys_ptr[i] = &signers[i].pubkey; + } + printf("ok\n"); + + /* The aggregate public key produced by secp256k1_musig_pubkey_agg depends + * on the order of the provided public keys. If there is no canonical order + * of the signers, the individual public keys can optionally be sorted with + * secp256k1_ec_pubkey_sort to ensure that the aggregate public key is + * independent of the order of signers. */ + printf("Sorting public keys....."); + fflush(stdout); + if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + printf("ok\n"); + + printf("Combining public keys..."); + fflush(stdout); + /* If you just want to aggregate and not sign, you can call + * secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL + * while providing a non-NULL agg_pk argument. */ + if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + printf("ok\n"); + printf("Tweaking................"); + fflush(stdout); + /* Optionally tweak the aggregate key */ + if (!tweak(ctx, &agg_pk, &cache)) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + printf("ok\n"); + printf("Signing message........."); + fflush(stdout); + if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + printf("ok\n"); + printf("Verifying signature....."); + fflush(stdout); + if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) { + printf("FAILED\n"); + return EXIT_FAILURE; + } + printf("ok\n"); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite secret key material with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + for (i = 0; i < N_SIGNERS; i++) { + secure_erase(&signer_secrets[i], sizeof(signer_secrets[i])); + } + secp256k1_context_destroy(ctx); + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/examples/schnorr.c b/crypto/secp256k1/libsecp256k1/examples/schnorr.c new file mode 100644 index 000000000..49baed24b --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/examples/schnorr.c @@ -0,0 +1,154 @@ +/************************************************************************* + * Written in 2020-2022 by Elichai Turkel * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "examples_util.h" + +int main(void) { + unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; + unsigned char msg_hash[32]; + unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'}; + unsigned char seckey[32]; + unsigned char randomize[32]; + unsigned char auxiliary_rand[32]; + unsigned char serialized_pubkey[32]; + unsigned char signature[64]; + int is_signature_valid, is_signature_valid2; + int return_val; + secp256k1_xonly_pubkey pubkey; + secp256k1_keypair keypair; + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Key Generation ***/ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!secp256k1_keypair_create(ctx, &keypair, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return EXIT_FAILURE; + } + + /* Extract the X-only public key from the keypair. We pass NULL for + * `pk_parity` as the parity isn't needed for signing or verification. + * `secp256k1_keypair_xonly_pub` supports returning the parity for + * other use cases such as tests or verifying Taproot tweaks. + * This should never fail with a valid context and public key. */ + return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair); + assert(return_val); + + /* Serialize the public key. Should always return 1 for a valid public key. */ + return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey); + assert(return_val); + + /*** Signing ***/ + + /* Instead of signing (possibly very long) messages directly, we sign a + * 32-byte hash of the message in this example. + * + * We use secp256k1_tagged_sha256 to create this hash. This function expects + * a context-specific "tag", which restricts the context in which the signed + * messages should be considered valid. For example, if protocol A mandates + * to use the tag "my_fancy_protocol" and protocol B mandates to use the tag + * "my_boring_protocol", then signed messages from protocol A will never be + * valid in protocol B (and vice versa), even if keys are reused across + * protocols. This implements "domain separation", which is considered good + * practice. It avoids attacks in which users are tricked into signing a + * message that has intended consequences in the intended context (e.g., + * protocol A) but would have unintended consequences if it were valid in + * some other context (e.g., protocol B). */ + return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + assert(return_val); + + /* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */ + if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) { + printf("Failed to generate randomness\n"); + return EXIT_FAILURE; + } + + /* Generate a Schnorr signature. + * + * We use the secp256k1_schnorrsig_sign32 function that provides a simple + * interface for signing 32-byte messages (which in our case is a hash of + * the actual message). BIP-340 recommends passing 32 bytes of randomness + * to the signing function to improve security against side-channel attacks. + * Signing with a valid context, a 32-byte message, a verified keypair, and + * any 32 bytes of auxiliary random data should never fail. */ + return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand); + assert(return_val); + + /*** Verification ***/ + + /* Deserialize the public key. This will return 0 if the public key can't + * be parsed correctly */ + if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) { + printf("Failed parsing the public key\n"); + return EXIT_FAILURE; + } + + /* Compute the tagged hash on the received messages using the same tag as the signer. */ + return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg)); + assert(return_val); + + /* Verify a signature. This will return 1 if it's valid and 0 if it's not. */ + is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey); + + + printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false"); + printf("Secret Key: "); + print_hex(seckey, sizeof(seckey)); + printf("Public Key: "); + print_hex(serialized_pubkey, sizeof(serialized_pubkey)); + printf("Signature: "); + print_hex(signature, sizeof(signature)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static, + signature, msg_hash, 32, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + + /* It's best practice to try to clear secrets from memory after using them. + * This is done because some bugs can allow an attacker to leak memory, for + * example through "out of bounds" array access (see Heartbleed), or the OS + * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + secure_erase(seckey, sizeof(seckey)); + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1.h b/crypto/secp256k1/libsecp256k1/include/secp256k1.h index 76af83969..c6e9417f0 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1.h @@ -1,20 +1,22 @@ -#ifndef _SECP256K1_ -# define _SECP256K1_ +#ifndef SECP256K1_H +#define SECP256K1_H -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif #include -/* These rules specify the order of arguments in API calls: +/** Unless explicitly stated all pointer arguments must not be NULL. + * + * The following rules specify the order of arguments in API calls: * * 1. Context pointers go first, followed by output arguments, combined * output/input arguments, and finally input-only arguments. - * 2. Array lengths always immediately the follow the argument whose length + * 2. Array lengths always immediately follow the argument whose length * they describe, even if this violates rule 1. * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated - * later go first. This means: signatures, public nonces, private nonces, + * later go first. This means: signatures, public nonces, secret nonces, * messages, public keys, secret keys, tweaks. * 4. Arguments that are not data pointers go last, from more complex to less * complex: function pointers, algorithm names, messages, void pointers, @@ -22,20 +24,25 @@ extern "C" { * 5. Opaque data pointers follow the function pointer they are to be passed to. */ -/** Opaque data structure that holds context information (precomputed tables etc.). +/** Opaque data structure that holds context information * - * The purpose of context structures is to cache large precomputed data tables - * that are expensive to construct, and also to maintain the randomization data - * for blinding. + * The primary purpose of context objects is to store randomization data for + * enhanced protection against side-channel leakage. This protection is only + * effective if the context is randomized after its creation. See + * secp256k1_context_create for creation of contexts and + * secp256k1_context_randomize for randomization. * - * Do not create a new context object for each operation, as construction is - * far slower than all other API calls (~100 times slower than an ECDSA - * verification). + * A secondary purpose of context objects is to store pointers to callback + * functions that the library will call when certain error states arise. See + * secp256k1_context_set_error_callback as well as + * secp256k1_context_set_illegal_callback for details. Future library versions + * may use context objects for additional purposes. * * A constructed context can safely be used from multiple threads - * simultaneously, but API call that take a non-const pointer to a context + * simultaneously, but API calls that take a non-const pointer to a context * need exclusive access to it. In particular this is the case for - * secp256k1_context_destroy and secp256k1_context_randomize. + * secp256k1_context_destroy, secp256k1_context_preallocated_destroy, + * and secp256k1_context_randomize. * * Regarding randomization, either do it once at creation time (in which case * you do not need any locking for the other calls), or use a read-write lock. @@ -47,23 +54,24 @@ typedef struct secp256k1_context_struct secp256k1_context; * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + * If you need to convert to a format suitable for storage or transmission, + * use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To + * compare keys, use secp256k1_ec_pubkey_cmp. */ -typedef struct { +typedef struct secp256k1_pubkey { unsigned char data[64]; } secp256k1_pubkey; -/** Opaque data structured that holds a parsed ECDSA signature. +/** Opaque data structure that holds a parsed ECDSA signature. * * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. * If you need to convert to a format suitable for storage, transmission, or * comparison, use the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_serialize_* functions. + * secp256k1_ecdsa_signature_parse_* functions. */ -typedef struct { +typedef struct secp256k1_ecdsa_signature { unsigned char data[64]; } secp256k1_ecdsa_signature; @@ -101,35 +109,62 @@ typedef int (*secp256k1_nonce_function)( # endif # endif -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline +/* When this header is used at build-time the SECP256K1_BUILD define needs to be set + * to correctly setup export attributes and nullness checks. This is normally done + * by secp256k1.c but to guard against this header being included before secp256k1.c + * has had a chance to set the define (e.g. via test harnesses that just includes + * secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the + * BUILD define so this condition can be caught. + */ +#ifndef SECP256K1_BUILD +# define SECP256K1_NO_BUILD +#endif + +/* Symbol visibility. */ +#if defined(_WIN32) + /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax + * for MSVC compatibility. A __declspec declaration implies (but is not + * exactly equivalent to) __attribute__ ((visibility("default"))), and so we + * actually want __declspec even on GCC, see "Microsoft Windows Function + * Attributes" in the GCC manual and the recommendations in + * https://gcc.gnu.org/wiki/Visibility. */ +# if defined(SECP256K1_BUILD) +# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT) + /* Building libsecp256k1 as a DLL. + * 1. If using Libtool, it defines DLL_EXPORT automatically. + * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ +# define SECP256K1_API extern __declspec (dllexport) # else -# define SECP256K1_INLINE + /* Building libsecp256k1 as a static library on Windows. + * No declspec is needed, and so we would want the non-Windows-specific + * logic below take care of this case. However, this may result in setting + * __attribute__ ((visibility("default"))), which is supposed to be a noop + * on Windows but may trigger warnings when compiling with -flto due to a + * bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# define SECP256K1_API extern # endif -# else -# define SECP256K1_INLINE inline + /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static + * library on Windows. */ +# elif !defined(SECP256K1_STATIC) + /* Consuming libsecp256k1 as a DLL. */ +# define SECP256K1_API extern __declspec (dllimport) # endif - +#endif #ifndef SECP256K1_API -# if defined(_WIN32) -# ifdef SECP256K1_BUILD -# define SECP256K1_API __declspec(dllexport) -# else -# define SECP256K1_API -# endif -# elif defined(__GNUC__) && defined(SECP256K1_BUILD) -# define SECP256K1_API __attribute__ ((visibility ("default"))) +/* All cases not captured by the Windows-specific logic. */ +# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) + /* Building libsecp256k1 using GCC or compatible. */ +# define SECP256K1_API extern __attribute__ ((visibility ("default"))) # else -# define SECP256K1_API + /* Fall back to standard C's extern. */ +# define SECP256K1_API extern # endif #endif -/**Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ +/* Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ # if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) # define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) # else @@ -141,50 +176,147 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_ARG_NONNULL(_x) # endif -/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +/* Attribute for marking functions, types, and variables as deprecated */ +#if !defined(SECP256K1_BUILD) && defined(__has_attribute) +# if __has_attribute(__deprecated__) +# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) +# else +# define SECP256K1_DEPRECATED(_msg) +# endif +#else +# define SECP256K1_DEPRECATED(_msg) +#endif + +/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ #define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) #define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/** The higher bits contain the actual data. Do not use directly. */ +/* The higher bits contain the actual data. Do not use directly. */ #define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to secp256k1_context_create. */ +/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and + * secp256k1_context_preallocated_create. */ +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) -/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ +/* Testing flag. Do not use. */ +#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) + +/** Flag to pass to secp256k1_ec_pubkey_serialize. */ #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) -/** Create a secp256k1 context object. +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 + +/** A built-in constant secp256k1 context object with static storage duration, to be + * used in conjunction with secp256k1_selftest. * - * Returns: a newly created context object. - * In: flags: which parts of the context to initialize. + * This context object offers *only limited functionality* , i.e., it cannot be used + * for API functions that perform computations involving secret keys, e.g., signing + * and public key generation. If this restriction applies to a specific API function, + * it is mentioned in its documentation. See secp256k1_context_create if you need a + * full context object that supports all functionality offered by the library. + * + * It is highly recommended to call secp256k1_selftest before using this context. */ -SECP256K1_API secp256k1_context* secp256k1_context_create( +SECP256K1_API const secp256k1_context *secp256k1_context_static; + +/** Deprecated alias for secp256k1_context_static. */ +SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); + +/** Perform basic self tests (to be used in conjunction with secp256k1_context_static) + * + * This function performs self tests that detect some serious usage errors and + * similar conditions, e.g., when the library is compiled for the wrong endianness. + * This is a last resort measure to be used in production. The performed tests are + * very rudimentary and are not intended as a replacement for running the test + * binaries. + * + * It is highly recommended to call this before using secp256k1_context_static. + * It is not necessary to call this function before using a context created with + * secp256k1_context_create (or secp256k1_context_preallocated_create), which will + * take care of performing the self tests. + * + * If the tests fail, this function will call the default error handler to abort the + * program (see secp256k1_context_set_error_callback). + */ +SECP256K1_API void secp256k1_selftest(void); + + +/** Create a secp256k1 context object (in dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see secp256k1_context_static and the functions in + * secp256k1_preallocated.h. + * + * Returns: pointer to a newly created context object. + * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). + * + * The only valid non-deprecated flag in recent library versions is + * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality + * offered by the library. All other (deprecated) flags will be treated as equivalent + * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for + * historical reasons, future versions of the library may introduce new flags. + * + * If the context is intended to be used for API functions that perform computations + * involving secret keys, e.g., signing and public key generation, then it is highly + * recommended to call secp256k1_context_randomize on the context before calling + * those API functions. This will provide enhanced protection against side-channel + * leakage, see secp256k1_context_randomize for details. + * + * Do not create a new context object for each operation, as construction and + * randomization can take non-negligible time. + */ +SECP256K1_API secp256k1_context *secp256k1_context_create( unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; -/** Copies a secp256k1 context object. +/** Copy a secp256k1 context object (into dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_preallocated.h. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy (cannot be NULL) + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). */ -SECP256K1_API secp256k1_context* secp256k1_context_clone( - const secp256k1_context* ctx +SECP256K1_API secp256k1_context *secp256k1_context_clone( + const secp256k1_context *ctx ) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; -/** Destroy a secp256k1 context object. +/** Destroy a secp256k1 context object (created in dynamically allocated memory). * * The context pointer may not be used afterwards. - * Args: ctx: an existing context to destroy (cannot be NULL) + * + * The context to destroy must have been created using secp256k1_context_create + * or secp256k1_context_clone. If the context has instead been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the + * behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must + * be used instead. + * + * Args: ctx: pointer to a context to destroy, constructed using + * secp256k1_context_create or secp256k1_context_clone + * (i.e., not secp256k1_context_static). */ SECP256K1_API void secp256k1_context_destroy( - secp256k1_context* ctx -); + secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an illegal argument is passed to * an API call. It will only trigger for violations that are mentioned @@ -200,20 +332,40 @@ SECP256K1_API void secp256k1_context_destroy( * to cause a crash, though its return value and output arguments are * undefined. * - * Args: ctx: an existing context object (cannot be NULL) - * In: fun: a pointer to a function to call when an illegal argument is - * passed to the API, taking a message and an opaque pointer - * (NULL restores a default handler that calls abort). - * data: the opaque pointer to pass to fun above. + * When this function has not been called (or called with fn==NULL), then the + * default handler will be used. The library provides a default handler which + * writes the message to stderr and calls abort. This default handler can be + * replaced at link time if the preprocessor macro + * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build + * has been configured with --enable-external-default-callbacks. Then the + * following two symbols must be provided to link against: + * - void secp256k1_default_illegal_callback_fn(const char *message, void *data); + * - void secp256k1_default_error_callback_fn(const char *message, void *data); + * The library can call these default handlers even before a proper callback data + * pointer could have been set using secp256k1_context_set_illegal_callback or + * secp256k1_context_set_error_callback, e.g., when the creation of a context + * fails. In this case, the corresponding default handler will be called with + * the data pointer argument set to NULL. + * + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer. + * (NULL restores the default handler.) + * data: the opaque pointer to pass to fun above, must be NULL for the default handler. + * + * See also secp256k1_context_set_error_callback. */ SECP256K1_API void secp256k1_context_set_illegal_callback( - secp256k1_context* ctx, - void (*fun)(const char* message, void* data), - const void* data + secp256k1_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an internal consistency check - * fails. The default is crashing. + * fails. + * + * The default callback writes an error message to stderr and calls abort + * to abort the program. * * This can only trigger in case of a hardware failure, miscompilation, * memory corruption, serious bug in the library, or other error would can @@ -222,23 +374,26 @@ SECP256K1_API void secp256k1_context_set_illegal_callback( * for that). After this callback returns, anything may happen, including * crashing. * - * Args: ctx: an existing context object (cannot be NULL) - * In: fun: a pointer to a function to call when an internal error occurs, - * taking a message and an opaque pointer (NULL restores a default - * handler that calls abort). - * data: the opaque pointer to pass to fun above. + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores the + * default handler, see secp256k1_context_set_illegal_callback + * for details). + * data: the opaque pointer to pass to fun above, must be NULL for the default handler. + * + * See also secp256k1_context_set_illegal_callback. */ SECP256K1_API void secp256k1_context_set_error_callback( - secp256k1_context* ctx, - void (*fun)(const char* message, void* data), - const void* data + secp256k1_context *ctx, + void (*fun)(const char *message, void *data), + const void *data ) SECP256K1_ARG_NONNULL(1); /** Parse a variable-length public key into the pubkey object. * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, its value is undefined. * In: input: pointer to a serialized public key @@ -249,8 +404,8 @@ SECP256K1_API void secp256k1_context_set_error_callback( * byte 0x06 or 0x07) format public keys. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( - const secp256k1_context* ctx, - secp256k1_pubkey* pubkey, + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -258,65 +413,94 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( /** Serialize a pubkey object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * Args: ctx: pointer to a context object. + * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if * compressed==1) byte array to place the serialized key * in. - * In/Out: outputlen: a pointer to an integer which is initially set to the + * In/Out: outputlen: pointer to an integer which is initially set to the * size of output, and is overwritten with the written * size. - * In: pubkey: a pointer to a secp256k1_pubkey containing an + * In: pubkey: pointer to a secp256k1_pubkey containing an * initialized public key. * flags: SECP256K1_EC_COMPRESSED if serialization should be in * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. */ SECP256K1_API int secp256k1_ec_pubkey_serialize( - const secp256k1_context* ctx, + const secp256k1_context *ctx, unsigned char *output, size_t *outputlen, - const secp256k1_pubkey* pubkey, + const secp256k1_pubkey *pubkey, unsigned int flags ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Compare two public keys using lexicographic (of compressed serialization) order + * + * Returns: <0 if the first public key is less than the second + * >0 if the first public key is greater than the second + * 0 if the two public keys are equal + * Args: ctx: pointer to a context object + * In: pubkey1: first public key to compare + * pubkey2: second public key to compare + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp( + const secp256k1_context *ctx, + const secp256k1_pubkey *pubkey1, + const secp256k1_pubkey *pubkey2 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Sort public keys using lexicographic (of compressed serialization) order + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * + * Args: ctx: pointer to a context object + * In: pubkeys: array of pointers to pubkeys to sort + * n_pubkeys: number of elements in the pubkeys array + */ +SECP256K1_API int secp256k1_ec_pubkey_sort( + const secp256k1_context *ctx, + const secp256k1_pubkey **pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + /** Parse an ECDSA signature in compact (64 bytes) format. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to the 64-byte array to parse + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to the 64-byte array to parse * * The signature must consist of a 32-byte big endian R value, followed by a * 32-byte big endian S value. If R or S fall outside of [0..order-1], the * encoding is invalid. R and S with value 0 are allowed in the encoding. * * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail validation for any - * message and public key. + * S are zero, the resulting sig value is guaranteed to fail verification for + * any message and public key. */ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, const unsigned char *input64 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Parse a DER ECDSA signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the * encoded numbers are out of range. * * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is + * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ SECP256K1_API int secp256k1_ecdsa_signature_parse_der( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, const unsigned char *input, size_t inputlen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -324,71 +508,77 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der( /** Serialize an ECDSA signature in DER format. * * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the DER serialization - * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the DER serialization + * In/Out: outputlen: pointer to a length integer. Initially, this integer * should be set to the length of output. After the call * it will be set to the length of the serialization (even * if 0 was returned). - * In: sig: a pointer to an initialized signature object + * In: sig: pointer to an initialized signature object */ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( - const secp256k1_context* ctx, + const secp256k1_context *ctx, unsigned char *output, size_t *outputlen, - const secp256k1_ecdsa_signature* sig + const secp256k1_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Serialize an ECDSA signature in compact (64 byte) format. * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array to store the compact serialization - * In: sig: a pointer to an initialized signature object + * Args: ctx: pointer to a context object + * Out: output64: pointer to a 64-byte array to store the compact serialization + * In: sig: pointer to an initialized signature object * * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. */ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( - const secp256k1_context* ctx, + const secp256k1_context *ctx, unsigned char *output64, - const secp256k1_ecdsa_signature* sig + const secp256k1_ecdsa_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Verify an ECDSA signature. * * Returns: 1: correct signature - * 0: incorrect or unparsable signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig: the signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * 0: incorrect or unparseable signature + * Args: ctx: pointer to a context object + * In: sig: the signature being verified. + * msghash32: the 32-byte message hash being verified. + * The verifier must make sure to apply a cryptographic + * hash function to the message by itself and not accept an + * msghash32 value directly. Otherwise, it would be easy to + * create a "valid" signature without knowledge of the + * secret key. See also + * https://bitcoin.stackexchange.com/a/81116/35586 for more + * background on this topic. + * pubkey: pointer to an initialized public key to verify with. * * To avoid accepting malleable signatures, only ECDSA signatures in lower-S * form are accepted. * * If you need to accept ECDSA signatures from sources that do not obey this * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to - * validation, but be aware that doing so results in malleable signatures. + * verification, but be aware that doing so results in malleable signatures. * * For details, see the comments for that function. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context* ctx, + const secp256k1_context *ctx, const secp256k1_ecdsa_signature *sig, - const unsigned char *msg32, + const unsigned char *msghash32, const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Convert a signature to a normalized lower-S form. * * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: a secp256k1 context object - * Out: sigout: a pointer to a signature to fill with the normalized form, + * Args: ctx: pointer to a context object + * Out: sigout: pointer to a signature to fill with the normalized form, * or copy if the input was already normalized. (can be NULL if * you're only interested in whether the input was already * normalized). - * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, - * can be identical to sigout) + * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) * * With ECDSA a third-party can forge a second distinct signature of the same * message, given a single initial signature, but without knowing the key. This @@ -422,7 +612,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( * secp256k1_ecdsa_signature_normalize must be called before verification. */ SECP256K1_API int secp256k1_ecdsa_signature_normalize( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); @@ -431,147 +621,279 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize( * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; +SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. * * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * 0: the nonce generation function failed, or the secret key was invalid. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig: pointer to an array where the signature will be placed. + * In: msghash32: the 32-byte message hash being signed. + * seckey: pointer to a 32-byte secret key. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used. + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL). If it is non-NULL and + * secp256k1_nonce_function_default is used, then ndata must be a + * pointer to 32-bytes of additional data. * * The created signature is always in lower-S form. See * secp256k1_ecdsa_signature_normalize for more details. */ SECP256K1_API int secp256k1_ecdsa_sign( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_ecdsa_signature *sig, - const unsigned char *msg32, + const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Verify an ECDSA secret key. +/** Verify an elliptic curve secret key. + * + * A secret key is valid if it is not 0 and less than the secp256k1 curve order + * when interpreted as an integer (most significant byte first). The + * probability of choosing a 32-byte string uniformly at random which is an + * invalid secret key is negligible. However, if it does happen it should + * be assumed that the randomness source is severely broken and there should + * be no retry. * * Returns: 1: secret key is valid * 0: secret key is invalid - * Args: ctx: pointer to a context object (cannot be NULL) - * In: seckey: pointer to a 32-byte secret key (cannot be NULL) + * Args: ctx: pointer to a context object. + * In: seckey: pointer to a 32-byte secret key. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( - const secp256k1_context* ctx, + const secp256k1_context *ctx, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Compute the public key for a secret key. * - * Returns: 1: secret was valid, public key stores - * 0: secret was invalid, try again - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: pubkey: pointer to the created public key (cannot be NULL) - * In: seckey: pointer to a 32-byte private key (cannot be NULL) + * Returns: 1: secret was valid, public key stores. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: pubkey: pointer to the created public key. + * In: seckey: pointer to a 32-byte secret key. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a private key by adding tweak to it. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or if the resulting private key - * would be invalid (only when the tweak is the complement of the - * private key). 1 otherwise. - * Args: ctx: pointer to a context object (cannot be NULL). - * In/Out: seckey: pointer to a 32-byte private key. - * In: tweak: pointer to a 32-byte tweak. +/** Negates a secret key in place. + * + * Returns: 0 if the given secret key is invalid according to + * secp256k1_ec_seckey_verify. 1 otherwise + * Args: ctx: pointer to a context object + * In/Out: seckey: pointer to the 32-byte secret key to be negated. If the + * secret key is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0 and + * seckey will be set to some unspecified value. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( + const secp256k1_context *ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( + const secp256k1_context *ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead"); + +/** Negates a public key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Tweak a secret key by adding tweak to it. + * + * Returns: 0 if the arguments are invalid or the resulting secret key would be + * invalid (only when the tweak is the negation of the secret key). 1 + * otherwise. + * Args: ctx: pointer to a context object. + * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is + * invalid according to secp256k1_ec_seckey_verify, this + * function returns 0. seckey will be set to some unspecified + * value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add( + const secp256k1_context *ctx, unsigned char *seckey, - const unsigned char *tweak + const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead"); + /** Tweak a public key by adding tweak times the generator to it. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or if the resulting public key - * would be invalid (only when the tweak is the complement of the - * corresponding private key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation - * (cannot be NULL). - * In/Out: pubkey: pointer to a public key object. - * In: tweak: pointer to a 32-byte tweak. + * + * Returns: 0 if the arguments are invalid or the resulting public key would be + * invalid (only when the tweak is the negation of the corresponding + * secret key). 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: pubkey: pointer to a public key object. pubkey will be set to an + * invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_pubkey *pubkey, - const unsigned char *tweak + const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a private key by multiplying it by a tweak. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. - * Args: ctx: pointer to a context object (cannot be NULL). - * In/Out: seckey: pointer to a 32-byte private key. - * In: tweak: pointer to a 32-byte tweak. +/** Tweak a secret key by multiplying it by a tweak. + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: seckey: pointer to a 32-byte secret key. If the secret key is + * invalid according to secp256k1_ec_seckey_verify, this + * function returns 0. seckey will be set to some unspecified + * value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0. For + * uniformly random 32-byte arrays the chance of being invalid + * is negligible (around 1 in 2^128). */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context* ctx, +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul( + const secp256k1_context *ctx, unsigned char *seckey, - const unsigned char *tweak + const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context *ctx, + unsigned char *seckey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) + SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead"); + /** Tweak a public key by multiplying it by a tweak value. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation - * (cannot be NULL). - * In/Out: pubkey: pointer to a public key obkect. - * In: tweak: pointer to a 32-byte tweak. + * + * Returns: 0 if the arguments are invalid. 1 otherwise. + * Args: ctx: pointer to a context object. + * In/Out: pubkey: pointer to a public key object. pubkey will be set to an + * invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to + * secp256k1_ec_seckey_verify, this function returns 0. For + * uniformly random 32-byte arrays the chance of being invalid + * is negligible (around 1 in 2^128). */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_pubkey *pubkey, - const unsigned char *tweak + const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Updates the context randomization. - * Returns: 1: randomization successfully updated +/** Randomizes the context to provide enhanced protection against side-channel leakage. + * + * Returns: 1: randomization successful * 0: error - * Args: ctx: pointer to a context object (cannot be NULL) - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). + * + * While secp256k1 code is written and tested to be constant-time no matter what + * secret values are, it is possible that a compiler may output code which is not, + * and also that the CPU may not emit the same radio frequencies or draw the same + * amount of power for all values. Randomization of the context shields against + * side-channel observations which aim to exploit secret-dependent behaviour in + * certain computations which involve secret keys. + * + * It is highly recommended to call this function on contexts returned from + * secp256k1_context_create or secp256k1_context_clone (or from the corresponding + * functions in secp256k1_preallocated.h) before using these contexts to call API + * functions that perform computations involving secret keys, e.g., signing and + * public key generation. It is possible to call this function more than once on + * the same context, and doing so before every few computations involving secret + * keys is recommended as a defense-in-depth measure. Randomization of the static + * context secp256k1_context_static is not supported. + * + * Currently, the random seed is mainly used for blinding multiplications of a + * secret scalar with the elliptic curve base point. Multiplications of this + * kind are performed by exactly those API functions which are documented to + * require a context that is not secp256k1_context_static. As a rule of thumb, + * these are all functions which take a secret key (or a keypair) as an input. + * A notable exception to that rule is the ECDH module, which relies on a different + * kind of elliptic curve point multiplication and thus does not benefit from + * enhanced protection against side-channel leakage currently. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context* ctx, + secp256k1_context *ctx, const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); /** Add a number of public keys together. + * * Returns: 1: the sum of the public keys is valid. * 0: the sum of the public keys is not valid. - * Args: ctx: pointer to a context object - * Out: out: pointer to a public key object for placing the resulting public key - * (cannot be NULL) - * In: ins: pointer to array of pointers to public keys (cannot be NULL) - * n: the number of public keys to add together (must be at least 1) + * Args: ctx: pointer to a context object. + * Out: out: pointer to a public key object for placing the resulting public key. + * In: ins: pointer to array of pointers to public keys. + * n: the number of public keys to add together (must be at least 1). */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_pubkey *out, - const secp256k1_pubkey * const * ins, + const secp256k1_pubkey * const *ins, size_t n -) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -# ifdef __cplusplus +/** Compute a tagged hash as defined in BIP-340. + * + * This is useful for creating a message hash and achieving domain separation + * through an application-specific tag. This function returns + * SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash + * implementations optimized for a specific tag can precompute the SHA256 state + * after hashing the tag hashes. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: hash32: pointer to a 32-byte array to store the resulting hash + * In: tag: pointer to an array containing the tag + * taglen: length of the tag array + * msg: pointer to an array containing the message + * msglen: length of the message array + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256( + const secp256k1_context *ctx, + unsigned char *hash32, + const unsigned char *tag, + size_t taglen, + const unsigned char *msg, + size_t msglen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h index 4b84d7a96..4d9da3461 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h @@ -1,31 +1,63 @@ -#ifndef _SECP256K1_ECDH_ -# define _SECP256K1_ECDH_ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H -# include "secp256k1.h" +#include "secp256k1.h" -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif + +/** A pointer to a function that hashes an EC point to obtain an ECDH secret + * + * Returns: 1 if the point was successfully hashed. + * 0 will cause secp256k1_ecdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * secp256k1_ecdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to a 32-byte x coordinate + * y32: pointer to a 32-byte y coordinate + * data: arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ecdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *y32, + void *data +); + +/** An implementation of SHA256 hash function that applies to compressed public key. + * Populates the output parameter with 32 bytes. */ +SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; + +/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256). + * Populates the output parameter with 32 bytes. */ +SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; /** Compute an EC Diffie-Hellman secret in constant time + * * Returns: 1: exponentiation was successful - * 0: scalar was invalid (zero or overflow) - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: result: a 32-byte array which will be populated by an ECDH - * secret computed from the point and scalar - * In: pubkey: a pointer to a secp256k1_pubkey containing an - * initialized public key - * privkey: a 32-byte scalar with which to multiply the point + * 0: scalar was invalid (zero or overflow) or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key. + * seckey: a 32-byte scalar with which to multiply the point. + * hashfp: pointer to a hash function. If NULL, + * secp256k1_ecdh_hash_function_sha256 is used + * (in which case, 32 bytes will be written to output). + * data: arbitrary data pointer that is passed through to hashfp + * (can be NULL for secp256k1_ecdh_hash_function_sha256). */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( - const secp256k1_context* ctx, - unsigned char *result, + const secp256k1_context *ctx, + unsigned char *output, const secp256k1_pubkey *pubkey, - const unsigned char *privkey + const unsigned char *seckey, + secp256k1_ecdh_hash_function hashfp, + void *data ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_ellswift.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_ellswift.h new file mode 100644 index 000000000..0d1293e94 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_ellswift.h @@ -0,0 +1,200 @@ +#ifndef SECP256K1_ELLSWIFT_H +#define SECP256K1_ELLSWIFT_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module provides an implementation of ElligatorSwift as well as a + * version of x-only ECDH using it (including compatibility with BIP324). + * + * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by + * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding + * uniformly chosen public keys as 64-byte arrays which are indistinguishable + * from uniformly random arrays. + * + * Let f be the function from pairs of field elements to point X coordinates, + * defined as follows (all operations modulo p = 2^256 - 2^32 - 977) + * f(u,t): + * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, + * a square root of -3. + * - If u=0, set u=1 instead. + * - If t=0, set t=1 instead. + * - If u^3 + t^2 + 7 = 0, multiply t by 2. + * - Let X = (u^3 + 7 - t^2) / (2 * t) + * - Let Y = (X + t) / (C * u) + * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an + * X coordinate on the curve (at least one of them is, for any u and t). + * + * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian + * encodings of field elements u and t concatenated, where f(u,t) = x. + * The encoding algorithm is described in the paper, and effectively picks a + * uniformly random pair (u,t) among those which encode x. + * + * If the Y coordinate is relevant, it is given the same parity as t. + * + * Changes w.r.t. the paper: + * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point + * at infinity in the paper. Here they are remapped to finite points. + * - The paper uses an additional encoding bit for the parity of y. Here the + * parity of t is used (negating t does not affect the decoded x coordinate, + * so this is possible). + * + * For mathematical background about the scheme, see the doc/ellswift.md file. + */ + +/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X + * coordinate along with the encoded public keys to a uniform shared secret. + * + * Returns: 1 if a shared secret was successfully computed. + * 0 will cause secp256k1_ellswift_xdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * secp256k1_ellswift_xdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to the 32-byte serialized X coordinate + * of the resulting shared point (will not be NULL) + * ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * data: arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ellswift_xdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + void *data +); + +/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses + * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte + * array pointed to by data. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix; + +/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with + * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the + * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent + * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to + * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh"). + * The data argument is ignored. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324; + +/** Construct a 64-byte ElligatorSwift encoding of a given pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to be filled + * In: pubkey: pointer to a secp256k1_pubkey containing an + * initialized public key + * rnd32: pointer to 32 bytes of randomness + * + * It is recommended that rnd32 consists of 32 uniformly random bytes, not + * known to any adversary trying to detect whether public keys are being + * encoded, though 16 bytes of randomness (padded to an array of 32 bytes, + * e.g., with zeros) suffice to make the result indistinguishable from + * uniform. The randomness in rnd32 must not be a deterministic function of + * the pubkey (it can be derived from the private key, though). + * + * It is not guaranteed that the computed encoding is stable across versions + * of the library, even if all arguments to this function (including rnd32) + * are the same. + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_encode( + const secp256k1_context *ctx, + unsigned char *ell64, + const secp256k1_pubkey *pubkey, + const unsigned char *rnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decode a 64-bytes ElligatorSwift encoded public key. + * + * Returns: always 1 + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a secp256k1_pubkey that will be filled + * In: ell64: pointer to a 64-byte array to decode + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_decode( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *ell64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute an ElligatorSwift public key for a secret key. + * + * Returns: 1: secret was valid, public key was stored. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift + * public key + * In: seckey32: pointer to a 32-byte secret key + * auxrnd32: (optional) pointer to 32 bytes of randomness + * + * Constant time in seckey and auxrnd32, but not in the resulting public key. + * + * It is recommended that auxrnd32 contains 32 uniformly random bytes, though + * it is optional (and does result in encodings that are indistinguishable from + * uniform even without any auxrnd32). It differs from the (mandatory) rnd32 + * argument to secp256k1_ellswift_encode in this regard. + * + * This function can be used instead of calling secp256k1_ec_pubkey_create + * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret + * key as entropy for the encoding (supplemented with auxrnd32, if provided). + * + * Like secp256k1_ellswift_encode, this function does not guarantee that the + * computed encoding is stable across versions of the library, even if all + * arguments (including auxrnd32) are the same. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create( + const secp256k1_context *ctx, + unsigned char *ell64, + const unsigned char *seckey32, + const unsigned char *auxrnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Given a private key, and ElligatorSwift public keys sent in both directions, + * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH). + * + * Returns: 1: shared secret was successfully computed + * 0: secret was invalid or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * seckey32: pointer to our 32-byte secret key + * party: boolean indicating which party we are: zero if we are + * party A, non-zero if we are party B. seckey32 must be + * the private key corresponding to that party's ell_?64. + * This correspondence is not checked. + * hashfp: pointer to a hash function. + * data: arbitrary data pointer passed through to hashfp. + * + * Constant time in seckey32. + * + * This function is more efficient than decoding the public keys, and performing + * ECDH on them. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh( + const secp256k1_context *ctx, + unsigned char *output, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + const unsigned char *seckey32, + int party, + secp256k1_ellswift_xdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ELLSWIFT_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_extrakeys.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_extrakeys.h new file mode 100644 index 000000000..48c98693c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_extrakeys.h @@ -0,0 +1,250 @@ +#ifndef SECP256K1_EXTRAKEYS_H +#define SECP256K1_EXTRAKEYS_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structure that holds a parsed and valid "x-only" public key. + * An x-only pubkey encodes a point whose Y coordinate is even. It is + * serialized using only its X coordinate (32 bytes). See BIP-340 for more + * information about x-only pubkeys. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, use + * use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To + * compare keys, use secp256k1_xonly_pubkey_cmp. + */ +typedef struct secp256k1_xonly_pubkey { + unsigned char data[64]; +} secp256k1_xonly_pubkey; + +/** Opaque data structure that holds a keypair consisting of a secret and a + * public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 96 bytes in size, and can be safely copied/moved. + */ +typedef struct secp256k1_keypair { + unsigned char data[96]; +} secp256k1_keypair; + +/** Parse a 32-byte sequence into a xonly_pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, it's set to an invalid value. + * In: input32: pointer to a serialized xonly_pubkey. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *pubkey, + const unsigned char *input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an xonly_pubkey object into a 32-byte sequence. + * + * Returns: 1 always. + * + * Args: ctx: pointer to a context object. + * Out: output32: pointer to a 32-byte array to place the serialized key in. + * In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key. + */ +SECP256K1_API int secp256k1_xonly_pubkey_serialize( + const secp256k1_context *ctx, + unsigned char *output32, + const secp256k1_xonly_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compare two x-only public keys using lexicographic order + * + * Returns: <0 if the first public key is less than the second + * >0 if the first public key is greater than the second + * 0 if the two public keys are equal + * Args: ctx: pointer to a context object. + * In: pubkey1: first public key to compare + * pubkey2: second public key to compare + */ +SECP256K1_API int secp256k1_xonly_pubkey_cmp( + const secp256k1_context *ctx, + const secp256k1_xonly_pubkey *pk1, + const secp256k1_xonly_pubkey *pk2 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey. + * + * Returns: 1 always. + * + * Args: ctx: pointer to a context object. + * Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key. + * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that + * will be set to 1 if the point encoded by xonly_pubkey is + * the negation of the pubkey and set to 0 otherwise. + * In: pubkey: pointer to a public key that is converted. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *xonly_pubkey, + int *pk_parity, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Tweak an x-only public key by adding the generator multiplied with tweak32 + * to it. + * + * Note that the resulting point can not in general be represented by an x-only + * pubkey because it may have an odd Y coordinate. Instead, the output_pubkey + * is a normal secp256k1_pubkey. + * + * Returns: 0 if the arguments are invalid or the resulting public key would be + * invalid (only when the tweak is the negation of the corresponding + * secret key). 1 otherwise. + * + * Args: ctx: pointer to a context object. + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. + * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. + * tweak32: pointer to a 32-byte tweak, which must be valid + * according to secp256k1_ec_seckey_verify or 32 zero + * bytes. For uniformly random 32-byte tweaks, the chance of + * being invalid is negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Checks that a tweaked pubkey is the result of calling + * secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32. + * + * The tweaked pubkey is represented by its 32-byte x-only serialization and + * its pk_parity, which can both be obtained by converting the result of + * tweak_add to a secp256k1_xonly_pubkey. + * + * Note that this alone does _not_ verify that the tweaked pubkey is a + * commitment. If the tweak is not chosen in a specific way, the tweaked pubkey + * can easily be the result of a different internal_pubkey and tweak. + * + * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the + * result of tweaking the internal_pubkey with tweak32. 1 otherwise. + * Args: ctx: pointer to a context object. + * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey. + * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization + * is passed in as tweaked_pubkey32). This must match the + * pk_parity value that is returned when calling + * secp256k1_xonly_pubkey with the tweaked pubkey, or + * this function will fail. + * internal_pubkey: pointer to an x-only public key object to apply the tweak to. + * tweak32: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check( + const secp256k1_context *ctx, + const unsigned char *tweaked_pubkey32, + int tweaked_pk_parity, + const secp256k1_xonly_pubkey *internal_pubkey, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Compute the keypair for a valid secret key. + * + * See the documentation of `secp256k1_ec_seckey_verify` for more information + * about the validity of secret keys. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: keypair: pointer to the created keypair. + * In: seckey: pointer to a 32-byte secret key. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( + const secp256k1_context *ctx, + secp256k1_keypair *keypair, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the secret key from a keypair. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: seckey: pointer to a 32-byte buffer for the secret key. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( + const secp256k1_context *ctx, + unsigned char *seckey, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the public key from a keypair. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to a pubkey object, set to the keypair public key. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Get the x-only public key from a keypair. + * + * This is the same as calling secp256k1_keypair_pub and then + * secp256k1_xonly_pubkey_from_pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair + * public key after converting it to an xonly_pubkey. + * pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the + * pk_parity argument of secp256k1_xonly_pubkey_from_pubkey. + * In: keypair: pointer to a keypair. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *pubkey, + int *pk_parity, + const secp256k1_keypair *keypair +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Tweak a keypair by adding tweak32 to the secret key and updating the public + * key accordingly. + * + * Calling this function and then secp256k1_keypair_pub results in the same + * public key as calling secp256k1_keypair_xonly_pub and then + * secp256k1_xonly_pubkey_tweak_add. + * + * Returns: 0 if the arguments are invalid or the resulting keypair would be + * invalid (only when the tweak is the negation of the keypair's + * secret key). 1 otherwise. + * + * Args: ctx: pointer to a context object. + * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to + * an invalid value if this function returns 0. + * In: tweak32: pointer to a 32-byte tweak, which must be valid according to + * secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly + * random 32-byte tweaks, the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add( + const secp256k1_context *ctx, + secp256k1_keypair *keypair, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_EXTRAKEYS_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_musig.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_musig.h new file mode 100644 index 000000000..11b8f08c8 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_musig.h @@ -0,0 +1,588 @@ +#ifndef SECP256K1_MUSIG_H +#define SECP256K1_MUSIG_H + +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** This module implements BIP 327 "MuSig2 for BIP340-compatible + * Multi-Signatures" + * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki) + * v1.0.0. You can find an example demonstrating the musig module in + * examples/musig.c. + * + * The module also supports BIP 341 ("Taproot") public key tweaking. + * + * It is recommended to read the documentation in this include file carefully. + * Further notes on API usage can be found in doc/musig.md + * + * Since the first version of MuSig is essentially replaced by MuSig2, we use + * MuSig, musig and MuSig2 synonymously unless noted otherwise. + */ + +/** Opaque data structures + * + * The exact representation of data inside the opaque data structures is + * implementation defined and not guaranteed to be portable between different + * platforms or versions. With the exception of `secp256k1_musig_secnonce`, the + * data structures can be safely copied/moved. If you need to convert to a + * format suitable for storage, transmission, or comparison, use the + * corresponding serialization and parsing functions. + */ + +/** Opaque data structure that caches information about public key aggregation. + * + * Guaranteed to be 197 bytes in size. No serialization and parsing functions + * (yet). + */ +typedef struct secp256k1_musig_keyagg_cache { + unsigned char data[197]; +} secp256k1_musig_keyagg_cache; + +/** Opaque data structure that holds a signer's _secret_ nonce. + * + * Guaranteed to be 132 bytes in size. + * + * WARNING: This structure MUST NOT be copied or read or written to directly. A + * signer who is online throughout the whole process and can keep this + * structure in memory can use the provided API functions for a safe standard + * workflow. + * + * Copying this data structure can result in nonce reuse which will leak the + * secret signing key. + */ +typedef struct secp256k1_musig_secnonce { + unsigned char data[132]; +} secp256k1_musig_secnonce; + +/** Opaque data structure that holds a signer's public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_pubnonce_serialize` and `musig_pubnonce_parse`. + */ +typedef struct secp256k1_musig_pubnonce { + unsigned char data[132]; +} secp256k1_musig_pubnonce; + +/** Opaque data structure that holds an aggregate public nonce. + * + * Guaranteed to be 132 bytes in size. Serialized and parsed with + * `musig_aggnonce_serialize` and `musig_aggnonce_parse`. + */ +typedef struct secp256k1_musig_aggnonce { + unsigned char data[132]; +} secp256k1_musig_aggnonce; + +/** Opaque data structure that holds a MuSig session. + * + * This structure is not required to be kept secret for the signing protocol to + * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing + * functions (yet). + */ +typedef struct secp256k1_musig_session { + unsigned char data[133]; +} secp256k1_musig_session; + +/** Opaque data structure that holds a partial MuSig signature. + * + * Guaranteed to be 36 bytes in size. Serialized and parsed with + * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. + */ +typedef struct secp256k1_musig_partial_sig { + unsigned char data[36]; +} secp256k1_musig_partial_sig; + +/** Parse a signer's public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse( + const secp256k1_context *ctx, + secp256k1_musig_pubnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a signer's public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int secp256k1_musig_pubnonce_serialize( + const secp256k1_context *ctx, + unsigned char *out66, + const secp256k1_musig_pubnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse an aggregate public nonce. + * + * Returns: 1 when the nonce could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: nonce: pointer to a nonce object + * In: in66: pointer to the 66-byte nonce to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse( + const secp256k1_context *ctx, + secp256k1_musig_aggnonce *nonce, + const unsigned char *in66 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an aggregate public nonce + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out66: pointer to a 66-byte array to store the serialized nonce + * In: nonce: pointer to the nonce + */ +SECP256K1_API int secp256k1_musig_aggnonce_serialize( + const secp256k1_context *ctx, + unsigned char *out66, + const secp256k1_musig_aggnonce *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a MuSig partial signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: in32: pointer to the 32-byte signature to be parsed + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse( + const secp256k1_context *ctx, + secp256k1_musig_partial_sig *sig, + const unsigned char *in32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a MuSig partial signature + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * Out: out32: pointer to a 32-byte array to store the serialized signature + * In: sig: pointer to the signature + */ +SECP256K1_API int secp256k1_musig_partial_sig_serialize( + const secp256k1_context *ctx, + unsigned char *out32, + const secp256k1_musig_partial_sig *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Computes an aggregate public key and uses it to initialize a keyagg_cache + * + * Different orders of `pubkeys` result in different `agg_pk`s. + * + * Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort` + * which ensures the same `agg_pk` result for the same multiset of pubkeys. + * This is useful to do before `pubkey_agg`, such that the order of pubkeys + * does not affect the aggregate public key. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it, + * this arg can be NULL. + * keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that + * is required for signing (or observing the signing session + * and verifying partial signatures). + * In: pubkeys: input array of pointers to public keys to aggregate. The order + * is important; a different order will result in a different + * aggregate public key. + * n_pubkeys: length of pubkeys array. Must be greater than 0. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg( + const secp256k1_context *ctx, + secp256k1_xonly_pubkey *agg_pk, + secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_pubkey * const *pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4); + +/** Obtain the aggregate public key from a keyagg_cache. + * + * This is only useful if you need the non-xonly public key, in particular for + * plain (non-xonly) tweaking or batch-verifying multiple key aggregations + * (not implemented). + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: agg_pk: the MuSig-aggregated public key. + * In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( + const secp256k1_context *ctx, + secp256k1_pubkey *agg_pk, + const secp256k1_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding + * the generator multiplied with `tweak32` to it. This is useful for deriving + * child keys from an aggregate public key via BIP 32 where `tweak32` is set to + * a hash as defined in BIP 32. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following BIP 32). + * + * The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after + * the following pseudocode buf and buf2 have identical contents (absent + * earlier failures). + * + * secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...) + * secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache) + * secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache) + * secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...) + * secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32) + * secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `secp256k1_ec_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `secp256k1_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the + * generator multiplied with `tweak32` to it. This is useful for creating + * Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP + * 341. + * + * Callers are responsible for deriving `tweak32` in a way that does not reduce + * the security of MuSig (for example, by following Taproot BIP 341). + * + * The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in + * the following pseudocode xonly_pubkey_tweak_add_check (absent earlier + * failures) returns 1. + * + * secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...) + * secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32) + * secp256k1_xonly_pubkey_serialize(..., buf, output_pk) + * secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32) + * + * This function is required if you want to _sign_ for a tweaked aggregate key. + * If you are only computing a public key but not intending to create a + * signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: output_pubkey: pointer to a public key to store the result. Will be set + * to an invalid value if this function returns 0. If you + * do not need it, this arg can be NULL. + * In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by + * `musig_pubkey_agg` + * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes + * `secp256k1_ec_seckey_verify` and is not equal to the + * secret key corresponding to the public key represented + * by keyagg_cache or its negation. For uniformly random + * 32-byte arrays the chance of being invalid is + * negligible (around 1 in 2^128). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add( + const secp256k1_context *ctx, + secp256k1_pubkey *output_pubkey, + secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Starts a signing session by generating a nonce + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. Each call to this function must have a UNIQUE session_secrand32 that must + * NOT BE REUSED in subsequent calls to this function and must be KEPT + * SECRET (even from other signers). + * 2. If you already know the seckey, message or aggregate public key + * cache, they can be optionally provided to derive the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * If you don't have access to good randomness for session_secrand32, but you + * have access to a non-repeating counter, then see + * secp256k1_musig_nonce_gen_counter. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same seckey for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In/Out: + * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this + * call to secp256k1_musig_nonce_gen and must be uniformly + * random. If the function call is successful, the + * session_secrand32 buffer is invalidated to prevent reuse. + * In: + * seckey: the 32-byte secret key that will later be used for signing, if + * already known (can be NULL) + * pubkey: public key of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other public key. While the public key should correspond + * to the provided seckey, a mismatch will not cause the + * function to return 0. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen( + const secp256k1_context *ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + unsigned char *session_secrand32, + const unsigned char *seckey, + const secp256k1_pubkey *pubkey, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); + + +/** Alternative way to generate a nonce and start a signing session + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * This function differs from `secp256k1_musig_nonce_gen` by accepting a + * non-repeating counter value instead of a secret random value. This requires + * that a secret key is provided to `secp256k1_musig_nonce_gen_counter` + * (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen` + * where the seckey argument is optional. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. The nonrepeating_cnt argument must be a counter value that never repeats, + * i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with + * the same keypair and nonrepeating_cnt value. For example, this implies + * that if the same keypair is used with `secp256k1_musig_nonce_gen_counter` + * on multiple devices, none of the devices should have the same counter + * value as any other device. + * 2. If the seckey, message or aggregate public key cache is already available + * at this stage, any of these can be optionally provided, in which case + * they will be used in the derivation of the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same keypair for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In: + * nonrepeating_cnt: the value of a counter as explained above. Must be + * unique to this call to secp256k1_musig_nonce_gen. + * keypair: keypair of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other keypair. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter( + const secp256k1_context *ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + uint64_t nonrepeating_cnt, + const secp256k1_keypair *keypair, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Aggregates the nonces of all signers into a single nonce + * + * This can be done by an untrusted party to reduce the communication + * between signers. Instead of everyone sending nonces to everyone else, there + * can be one party receiving all nonces, aggregating the nonces with this + * function and then sending only the aggregate nonce back to the signers. + * + * If the aggregator does not compute the aggregate nonce correctly, the final + * signature will be invalid. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: aggnonce: pointer to an aggregate public nonce object for + * musig_nonce_process + * In: pubnonces: array of pointers to public nonces sent by the + * signers + * n_pubnonces: number of elements in the pubnonces array. Must be + * greater than 0. + */ +SECP256K1_API int secp256k1_musig_nonce_agg( + const secp256k1_context *ctx, + secp256k1_musig_aggnonce *aggnonce, + const secp256k1_musig_pubnonce * const *pubnonces, + size_t n_pubnonces +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Takes the aggregate nonce and creates a session that is required for signing + * and verification of partial signatures. + * + * Returns: 0 if the arguments are invalid, 1 otherwise + * Args: ctx: pointer to a context object + * Out: session: pointer to a struct to store the session + * In: aggnonce: pointer to an aggregate public nonce object that is the + * output of musig_nonce_agg + * msg32: the 32-byte message to sign + * keyagg_cache: pointer to the keyagg_cache that was used to create the + * aggregate (and potentially tweaked) pubkey + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process( + const secp256k1_context *ctx, + secp256k1_musig_session *session, + const secp256k1_musig_aggnonce *aggnonce, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Produces a partial signature + * + * This function overwrites the given secnonce with zeros and will abort if given a + * secnonce that is all zeros. This is a best effort attempt to protect against nonce + * reuse. However, this is of course easily defeated if the secnonce has been + * copied (or serialized). Remember that nonce reuse will leak the secret key! + * + * For signing to succeed, the secnonce provided to this function must have + * been generated for the provided keypair. This means that when signing for a + * keypair consisting of a seckey and pubkey, the secnonce must have been + * created by calling musig_nonce_gen with that pubkey. Otherwise, the + * illegal_callback is called. + * + * This function does not verify the output partial signature, deviating from + * the BIP 327 specification. It is recommended to verify the output partial + * signature with `secp256k1_musig_partial_sig_verify` to prevent random or + * adversarially provoked computation errors. + * + * Returns: 0 if the arguments are invalid or the provided secnonce has already + * been used for signing, 1 otherwise + * Args: ctx: pointer to a context object + * Out: partial_sig: pointer to struct to store the partial signature + * In/Out: secnonce: pointer to the secnonce struct created in + * musig_nonce_gen that has been never used in a + * partial_sign call before and has been created for the + * keypair + * In: keypair: pointer to keypair to sign the message with + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this session + * session: pointer to the session that was created with + * musig_nonce_process + */ +SECP256K1_API int secp256k1_musig_partial_sign( + const secp256k1_context *ctx, + secp256k1_musig_partial_sig *partial_sig, + secp256k1_musig_secnonce *secnonce, + const secp256k1_keypair *keypair, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Verifies an individual signer's partial signature + * + * The signature is verified for a specific signing session. In order to avoid + * accidentally verifying a signature from a different or non-existing signing + * session, you must ensure the following: + * 1. The `keyagg_cache` argument is identical to the one used to create the + * `session` with `musig_nonce_process`. + * 2. The `pubkey` argument must be identical to the one sent by the signer + * before aggregating it with `musig_pubkey_agg` to create the + * `keyagg_cache`. + * 3. The `pubnonce` argument must be identical to the one sent by the signer + * before aggregating it with `musig_nonce_agg` and using the result to + * create the `session` with `musig_nonce_process`. + * + * It is not required to call this function in regular MuSig sessions, because + * if any partial signature does not verify, the final signature will not + * verify either, so the problem will be caught. However, this function + * provides the ability to identify which specific partial signature fails + * verification. + * + * Returns: 0 if the arguments are invalid or the partial signature does not + * verify, 1 otherwise + * Args ctx: pointer to a context object + * In: partial_sig: pointer to partial signature to verify, sent by + * the signer associated with `pubnonce` and `pubkey` + * pubnonce: public nonce of the signer in the signing session + * pubkey: public key of the signer in the signing session + * keyagg_cache: pointer to the keyagg_cache that was output when the + * aggregate public key for this signing session + * session: pointer to the session that was created with + * `musig_nonce_process` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify( + const secp256k1_context *ctx, + const secp256k1_musig_partial_sig *partial_sig, + const secp256k1_musig_pubnonce *pubnonce, + const secp256k1_pubkey *pubkey, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const secp256k1_musig_session *session +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Aggregates partial signatures + * + * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean + * the resulting signature verifies). + * Args: ctx: pointer to a context object + * Out: sig64: complete (but possibly invalid) Schnorr signature + * In: session: pointer to the session that was created with + * musig_nonce_process + * partial_sigs: array of pointers to partial signatures to aggregate + * n_sigs: number of elements in the partial_sigs array. Must be + * greater than 0. + */ +SECP256K1_API int secp256k1_musig_partial_sig_agg( + const secp256k1_context *ctx, + unsigned char *sig64, + const secp256k1_musig_session *session, + const secp256k1_musig_partial_sig * const *partial_sigs, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_preallocated.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_preallocated.h new file mode 100644 index 000000000..f2d95c245 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_preallocated.h @@ -0,0 +1,134 @@ +#ifndef SECP256K1_PREALLOCATED_H +#define SECP256K1_PREALLOCATED_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The module provided by this header file is intended for settings in which it + * is not possible or desirable to rely on dynamic memory allocation. It provides + * functions for creating, cloning, and destroying secp256k1 context objects in a + * contiguous fixed-size block of memory provided by the caller. + * + * Context objects created by functions in this module can be used like contexts + * objects created by functions in secp256k1.h, i.e., they can be passed to any + * API function that expects a context object (see secp256k1.h for details). The + * only exception is that context objects created by functions in this module + * must be destroyed using secp256k1_context_preallocated_destroy (in this + * module) instead of secp256k1_context_destroy (in secp256k1.h). + * + * It is guaranteed that functions in this module will not call malloc or its + * friends realloc, calloc, and free. + */ + +/** Determine the memory size of a secp256k1 context object to be created in + * caller-provided memory. + * + * The purpose of this function is to determine how much memory must be provided + * to secp256k1_context_preallocated_create. + * + * Returns: the required size of the caller-provided memory block + * In: flags: which parts of the context to initialize. + */ +SECP256K1_API size_t secp256k1_context_preallocated_size( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Create a secp256k1 context object in caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, which begins with the call to this + * function and ends when a call to secp256k1_context_preallocated_destroy + * (which destroys the context object again) returns. During the lifetime of the + * context object, the caller is obligated not to access this block of memory, + * i.e., the caller may not read or write the memory, e.g., by copying the memory + * contents to a different location or trying to create a second context object + * in the memory. In simpler words, the prealloc pointer (or any pointer derived + * from it) should not be used during the lifetime of the context object. + * + * Returns: pointer to newly created context object. + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above. + * flags: which parts of the context to initialize. + * + * See secp256k1_context_create (in secp256k1.h) for further details. + * + * See also secp256k1_context_randomize (in secp256k1.h) + * and secp256k1_context_preallocated_destroy. + */ +SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create( + void *prealloc, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Determine the memory size of a secp256k1 context object to be copied into + * caller-provided memory. + * + * Returns: the required size of the caller-provided memory block. + * In: ctx: pointer to a context to copy. + */ +SECP256K1_API size_t secp256k1_context_preallocated_clone_size( + const secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object into caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, see the description of + * secp256k1_context_preallocated_create for details. + * + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). + * In: prealloc: pointer to a rewritable contiguous block of memory of + * size at least secp256k1_context_preallocated_size(flags) + * bytes, as detailed above. + */ +SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone( + const secp256k1_context *ctx, + void *prealloc +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object that has been created in + * caller-provided memory. + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using + * secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone. + * If the context has instead been created using secp256k1_context_create or + * secp256k1_context_clone, the behaviour is undefined. In that case, + * secp256k1_context_destroy must be used instead. + * + * If required, it is the responsibility of the caller to deallocate the block + * of memory properly after this function returns, e.g., by calling free on the + * preallocated pointer given to secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone. + * + * Args: ctx: pointer to a context to destroy, constructed using + * secp256k1_context_preallocated_create or + * secp256k1_context_preallocated_clone + * (i.e., not secp256k1_context_static). + */ +SECP256K1_API void secp256k1_context_preallocated_destroy( + secp256k1_context *ctx +) SECP256K1_ARG_NONNULL(1); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PREALLOCATED_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h index 055379725..93a2e4ccb 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h @@ -1,13 +1,13 @@ -#ifndef _SECP256K1_RECOVERY_ -# define _SECP256K1_RECOVERY_ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H -# include "secp256k1.h" +#include "secp256k1.h" -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif -/** Opaque data structured that holds a parsed ECDSA signature, +/** Opaque data structure that holds a parsed ECDSA signature, * supporting pubkey recovery. * * The exact representation of data inside is implementation defined and not @@ -21,21 +21,21 @@ extern "C" { * recoverability) will have identical representation, so they can be * memcmp'ed. */ -typedef struct { +typedef struct secp256k1_ecdsa_recoverable_signature { unsigned char data[65]; } secp256k1_ecdsa_recoverable_signature; /** Parse a compact ECDSA signature (64 bytes + recovery id). * * Returns: 1 when the signature could be parsed, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to a 64-byte compact signature + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to a 64-byte compact signature * recid: the recovery id (0, 1, 2 or 3) */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( - const secp256k1_context* ctx, - secp256k1_ecdsa_recoverable_signature* sig, + const secp256k1_context *ctx, + secp256k1_ecdsa_recoverable_signature *sig, const unsigned char *input64, int recid ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); @@ -43,45 +43,48 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( /** Convert a recoverable signature into a normal signature. * * Returns: 1 - * Out: sig: a pointer to a normal signature (cannot be NULL). - * In: sigin: a pointer to a recoverable signature (cannot be NULL). + * Args: ctx: pointer to a context object. + * Out: sig: pointer to a normal signature. + * In: sigin: pointer to a recoverable signature. */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const secp256k1_ecdsa_recoverable_signature* sigin + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const secp256k1_ecdsa_recoverable_signature *sigin ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Serialize an ECDSA signature in compact format (64 bytes + recovery id). * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) - * recid: a pointer to an integer to hold the recovery id (can be NULL). - * In: sig: a pointer to an initialized signature object (cannot be NULL) + * Args: ctx: pointer to a context object. + * Out: output64: pointer to a 64-byte array of the compact signature. + * recid: pointer to an integer to hold the recovery id. + * In: sig: pointer to an initialized signature object. */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( - const secp256k1_context* ctx, + const secp256k1_context *ctx, unsigned char *output64, int *recid, - const secp256k1_ecdsa_recoverable_signature* sig + const secp256k1_ecdsa_recoverable_signature *sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Create a recoverable ECDSA signature. * * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * 0: the nonce generation function failed, or the secret key was invalid. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig: pointer to an array where the signature will be placed. + * In: msghash32: the 32-byte message hash being signed. + * seckey: pointer to a 32-byte secret key. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used. + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL for secp256k1_nonce_function_default). */ SECP256K1_API int secp256k1_ecdsa_sign_recoverable( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msg32, + const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void *ndata @@ -91,20 +94,20 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable( * * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * Out: pubkey: pointer to the recovered public key (cannot be NULL) - * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to the recovered public key. + * In: sig: pointer to initialized signature that supports pubkey recovery. + * msghash32: the 32-byte message hash assumed to be signed. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( - const secp256k1_context* ctx, + const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msg32 + const unsigned char *msghash32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorrsig.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorrsig.h new file mode 100644 index 000000000..013d4ee73 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorrsig.h @@ -0,0 +1,190 @@ +#ifndef SECP256K1_SCHNORRSIG_H +#define SECP256K1_SCHNORRSIG_H + +#include "secp256k1.h" +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** This module implements a variant of Schnorr signatures compliant with + * Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1" + * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). + */ + +/** A pointer to a function to deterministically generate a nonce. + * + * Same as secp256k1_nonce function with the exception of accepting an + * additional pubkey argument and not requiring an attempt argument. The pubkey + * argument can protect signature schemes with key-prefixed challenge hash + * inputs against reusing the nonce when signing with the wrong precomputed + * pubkey. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to + * return an error. + * Out: nonce32: pointer to a 32-byte array to be filled by the function + * In: msg: the message being verified. Is NULL if and only if msglen + * is 0. + * msglen: the length of the message + * key32: pointer to a 32-byte secret key (will not be NULL) + * xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32 + * (will not be NULL) + * algo: pointer to an array describing the signature + * algorithm (will not be NULL) + * algolen: the length of the algo array + * data: arbitrary data pointer that is passed through + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the key, the pubkey, the algorithm description, and data. + */ +typedef int (*secp256k1_nonce_function_hardened)( + unsigned char *nonce32, + const unsigned char *msg, + size_t msglen, + const unsigned char *key32, + const unsigned char *xonly_pk32, + const unsigned char *algo, + size_t algolen, + void *data +); + +/** An implementation of the nonce generation function as defined in Bitcoin + * Improvement Proposal 340 "Schnorr Signatures for secp256k1" + * (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). + * + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * auxiliary random data as defined in BIP-340. If the data pointer is NULL, + * the nonce derivation procedure follows BIP-340 by setting the auxiliary + * random data to zero. The algo argument must be non-NULL, otherwise the + * function will fail and return 0. The hash will be tagged with algo. + * Therefore, to create BIP-340 compliant signatures, algo must be set to + * "BIP0340/nonce" and algolen to 13. + */ +SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; + +/** Data structure that contains additional arguments for schnorrsig_sign_custom. + * + * A schnorrsig_extraparams structure object can be initialized correctly by + * setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT. + * + * Members: + * magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization + * and has no other function than making sure the object is + * initialized. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_bip340 is used + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL). If it is non-NULL and + * secp256k1_nonce_function_bip340 is used, then ndata must be a + * pointer to 32-byte auxiliary randomness as per BIP-340. + */ +typedef struct secp256k1_schnorrsig_extraparams { + unsigned char magic[4]; + secp256k1_nonce_function_hardened noncefp; + void *ndata; +} secp256k1_schnorrsig_extraparams; + +#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c } +#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\ + SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\ + NULL,\ + NULL\ +} + +/** Create a Schnorr signature. + * + * Does _not_ strictly follow BIP-340 because it does not verify the resulting + * signature. Instead, you can manually use secp256k1_schnorrsig_verify and + * abort if it fails. + * + * This function only signs 32-byte messages. If you have messages of a + * different size (or the same size but without a context-specific tag + * prefix), it is recommended to create a 32-byte message hash with + * secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows + * providing an context-specific tag for domain separation. This prevents + * signatures from being valid in multiple contexts by accident. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. + * In: msg32: the 32-byte message being signed. + * keypair: pointer to an initialized keypair. + * aux_rand32: 32 bytes of fresh randomness. While recommended to provide + * this, it is only supplemental to security and can be NULL. A + * NULL argument is treated the same as an all-zero one. See + * BIP-340 "Default Signing" for a full explanation of this + * argument and for guidance if randomness is expensive. + */ +SECP256K1_API int secp256k1_schnorrsig_sign32( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_keypair *keypair, + const unsigned char *aux_rand32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in + * future versions. */ +SECP256K1_API int secp256k1_schnorrsig_sign( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_keypair *keypair, + const unsigned char *aux_rand32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) + SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead"); + +/** Create a Schnorr signature with a more flexible API. + * + * Same arguments as secp256k1_schnorrsig_sign except that it allows signing + * variable length messages and accepts a pointer to an extraparams object that + * allows customizing signing by passing additional arguments. + * + * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32 + * and extraparams is initialized as follows: + * ``` + * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + * extraparams.ndata = (unsigned char*)aux_rand32; + * ``` + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. + * In: msg: the message being signed. Can only be NULL if msglen is 0. + * msglen: length of the message. + * keypair: pointer to an initialized keypair. + * extraparams: pointer to an extraparams object (can be NULL). + */ +SECP256K1_API int secp256k1_schnorrsig_sign_custom( + const secp256k1_context *ctx, + unsigned char *sig64, + const unsigned char *msg, + size_t msglen, + const secp256k1_keypair *keypair, + secp256k1_schnorrsig_extraparams *extraparams +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); + +/** Verify a Schnorr signature. + * + * Returns: 1: correct signature + * 0: incorrect signature + * Args: ctx: pointer to a context object. + * In: sig64: pointer to the 64-byte signature to verify. + * msg: the message being verified. Can only be NULL if msglen is 0. + * msglen: length of the message + * pubkey: pointer to an x-only public key to verify with + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( + const secp256k1_context *ctx, + const unsigned char *sig64, + const unsigned char *msg, + size_t msglen, + const secp256k1_xonly_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SCHNORRSIG_H */ diff --git a/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in b/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in index a0d006f11..0fb6f48a6 100644 --- a/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in +++ b/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in @@ -8,6 +8,5 @@ Description: Optimized C library for EC operations on curve secp256k1 URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} -Libs.private: @SECP_LIBS@ Libs: -L${libdir} -lsecp256k1 diff --git a/crypto/secp256k1/libsecp256k1/obj/.gitignore b/crypto/secp256k1/libsecp256k1/obj/.gitignore deleted file mode 100644 index e69de29bb..000000000 diff --git a/crypto/secp256k1/libsecp256k1/sage/gen_exhaustive_groups.sage b/crypto/secp256k1/libsecp256k1/sage/gen_exhaustive_groups.sage new file mode 100644 index 000000000..070bc1285 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/gen_exhaustive_groups.sage @@ -0,0 +1,156 @@ +load("secp256k1_params.sage") + +MAX_ORDER = 1000 + +# Set of (curve) orders we have encountered so far. +orders_done = set() + +# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups. +solutions = {} + +# Iterate over curves of the form y^2 = x^3 + B. +for b in range(1, P): + # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all. + if len(orders_done) == 6: + break + + E = EllipticCurve(F, [0, b]) + print("Analyzing curve y^2 = x^3 + %i" % b) + n = E.order() + + # Skip curves with an order we've already tried + if n in orders_done: + print("- Isomorphic to earlier curve") + print() + continue + orders_done.add(n) + + # Skip curves isomorphic to the real secp256k1 + if n.is_pseudoprime(): + assert E.is_isomorphic(C) + print("- Isomorphic to secp256k1") + print() + continue + + print("- Finding prime subgroups") + + # Map from group_order to a set of independent generators for that order. + curve_gens = {} + + for g in E.gens(): + # Find what prime subgroups of group generated by g exist. + g_order = g.order() + for f, _ in g.order().factor(): + # Skip subgroups that have bad size. + if f < 4: + print(f" - Subgroup of size {f}: too small") + continue + if f > MAX_ORDER: + print(f" - Subgroup of size {f}: too large") + continue + + # Construct a generator for that subgroup. + gen = g * (g_order // f) + assert(gen.order() == f) + + # Add to set the minimal multiple of gen. + curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)])) + print(f" - Subgroup of size {f}: ok") + + for f in sorted(curve_gens.keys()): + print(f"- Constructing group of order {f}") + cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1]) + gens = list(curve_gens[f]) + sol_count = 0 + no_endo_count = 0 + + # Consider all non-zero linear combinations of the independent generators. + for j in range(1, f**len(gens)): + gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens))) + assert not gen.is_zero() + assert (f*gen).is_zero() + + # Find lambda for endomorphism. Skip if none can be found. + lam = None + for l in cbrts: + if l*gen == E(BETA*gen[0], gen[1]): + lam = l + break + + if lam is None: + no_endo_count += 1 + else: + sol_count += 1 + solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam)) + + print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)") + + print() + +def output_generator(g, name): + print(f"#define {name} SECP256K1_GE_CONST(\\") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(")") + +def output_b(b): + print(f"#define SECP256K1_B {int(b)}") + +print() +print("To be put in src/group_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +for f in sorted(solutions.keys()): + # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers). + b, _, _, HALF_G, lam = min(solutions[f]) + output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}") +print("/** Generator for secp256k1, value 'g' defined in") +print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.") +print(" */") +output_generator(G, "SECP256K1_G") +print("/* These exhaustive group test orders and generators are chosen such that:") +print(" * - The field size is equal to that of secp256k1, so field code is the same.") +print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.") +print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.") +print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.") +print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).") +print(" */") +print("#if defined(EXHAUSTIVE_TEST_ORDER)") +first = True +for f in sorted(solutions.keys()): + b, _, _, _, lam = min(solutions[f]) + print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}") + first = False + print() + print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};") + output_b(b) + print() +print("# else") +print("# error No known generator for the specified exhaustive test group order.") +print("# endif") +print("#else") +print() +print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;") +output_b(7) +print() +print("#endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") + + +print() +print() +print("To be put in src/scalar_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +first = True +for f in sorted(solutions.keys()): + _, _, _, _, lam = min(solutions[f]) + print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) + first = False + print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) +print("# else") +print("# error No known lambda for the specified exhaustive test group order.") +print("# endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") diff --git a/crypto/secp256k1/libsecp256k1/sage/gen_split_lambda_constants.sage b/crypto/secp256k1/libsecp256k1/sage/gen_split_lambda_constants.sage new file mode 100644 index 000000000..7d4359e0f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/gen_split_lambda_constants.sage @@ -0,0 +1,114 @@ +""" Generates the constants used in secp256k1_scalar_split_lambda. + +See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations. +""" + +load("secp256k1_params.sage") + +def inf_norm(v): + """Returns the infinity norm of a vector.""" + return max(map(abs, v)) + +def gauss_reduction(i1, i2): + v1, v2 = i1.copy(), i2.copy() + while True: + if inf_norm(v2) < inf_norm(v1): + v1, v2 = v2, v1 + # This is essentially + # m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2)) + # (rounding to the nearest integer) without relying on floating point arithmetic. + m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2) + if m == 0: + return v1, v2 + v2[0] -= m*v1[0] + v2[1] -= m*v1[1] + +def find_split_constants_gauss(): + """Find constants for secp256k1_scalar_split_lamdba using gauss reduction.""" + (v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)]) + + # We use related vectors in secp256k1_scalar_split_lambda. + A1, B1 = -v21, -v11 + A2, B2 = v22, -v21 + + return A1, B1, A2, B2 + +def find_split_constants_explicit_tof(): + """Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius. + + See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on + elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2 + """ + assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10]. + assert C.j_invariant() == 0 + + t = C.trace_of_frobenius() + + c = Integer(sqrt((4*P - t**2)/3)) + A1 = Integer((t - c)/2 - 1) + B1 = c + + A2 = Integer((t + c)/2 - 1) + B2 = Integer(1 - (t - c)/2) + + # We use a negated b values in secp256k1_scalar_split_lambda. + B1, B2 = -B1, -B2 + + return A1, B1, A2, B2 + +A1, B1, A2, B2 = find_split_constants_explicit_tof() + +# For extra fun, use an independent method to recompute the constants. +assert (A1, B1, A2, B2) == find_split_constants_gauss() + +# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. +def PHI(a,b): + return Z(a + LAMBDA*b) + +# Check that (A1, B1) and (A2, B2) are in the kernel of PHI. +assert PHI(A1, B1) == Z(0) +assert PHI(A2, B2) == Z(0) + +# Check that the parallelogram generated by (A1, A2) and (B1, B2) +# is a fundamental domain by containing exactly N points. +# Since the LHS is the determinant and N != 0, this also checks that +# (A1, A2) and (B1, B2) are linearly independent. By the previous +# assertions, (A1, A2) and (B1, B2) are a basis of the kernel. +assert A1*B2 - B1*A2 == N + +# Check that their components are short enough. +assert (A1 + A2)/2 < sqrt(N) +assert B1 < sqrt(N) +assert B2 < sqrt(N) + +G1 = round((2**384)*B2/N) +G2 = round((2**384)*(-B1)/N) + +def rnddiv2(v): + if v & 1: + v += 1 + return v >> 1 + +def scalar_lambda_split(k): + """Equivalent to secp256k1_scalar_lambda_split().""" + c1 = rnddiv2((k * G1) >> 383) + c2 = rnddiv2((k * G2) >> 383) + c1 = (c1 * -B1) % N + c2 = (c2 * -B2) % N + r2 = (c1 + c2) % N + r1 = (k + r2 * -LAMBDA) % N + return (r1, r2) + +# The result of scalar_lambda_split can depend on the representation of k (mod n). +SPECIAL = (2**383) // G2 + 1 +assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N) + +print(' A1 =', hex(A1)) +print(' -B1 =', hex(-B1)) +print(' A2 =', hex(A2)) +print(' -B2 =', hex(-B2)) +print(' =', hex(Z(-B2))) +print(' -LAMBDA =', hex(-LAMBDA)) + +print(' G1 =', hex(G1)) +print(' G2 =', hex(G2)) diff --git a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage index 68882e936..bb0929536 100644 --- a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage +++ b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage @@ -3,7 +3,7 @@ # to independently set assumptions on input or intermediary variables. # # The general approach is: -# * A constraint is a tuple of two sets of of symbolic expressions: +# * A constraint is a tuple of two sets of symbolic expressions: # the first of which are required to evaluate to zero, the second of which # are required to evaluate to nonzero. # - A constraint is said to be conflicting if any of its nonzero expressions @@ -42,7 +42,7 @@ # as we assume that all constraints in it are complementary with each other. # # Based on the sage verification scripts used in the Explicit-Formulas Database -# by Tanja Lange and others, see http://hyperelliptic.org/EFD +# by Tanja Lange and others, see https://hyperelliptic.org/EFD class fastfrac: """Fractions over rings.""" @@ -65,7 +65,7 @@ class fastfrac: return self.top in I and self.bot not in I def reduce(self,assumeZero): - zero = self.R.ideal(map(numerator, assumeZero)) + zero = self.R.ideal(list(map(numerator, assumeZero))) return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) def __add__(self,other): @@ -100,7 +100,7 @@ class fastfrac: """Multiply something else with a fraction.""" return self.__mul__(other) - def __div__(self,other): + def __truediv__(self,other): """Divide two fractions.""" if parent(other) == ZZ: return fastfrac(self.R,self.top,self.bot * other) @@ -108,6 +108,11 @@ class fastfrac: return fastfrac(self.R,self.top * other.bot,self.bot * other.top) return NotImplemented + # Compatibility wrapper for Sage versions based on Python 2 + def __div__(self,other): + """Divide two fractions.""" + return self.__truediv__(other) + def __pow__(self,other): """Compute a power of a fraction.""" if parent(other) == ZZ: @@ -159,6 +164,9 @@ class constraints: def negate(self): return constraints(zero=self.nonzero, nonzero=self.zero) + def map(self, fun): + return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()}) + def __add__(self, other): zero = self.zero.copy() zero.update(other.zero) @@ -172,10 +180,34 @@ class constraints: def __repr__(self): return "%s" % self +def normalize_factor(p): + """Normalizes the sign of primitive polynomials (as returned by factor()) + + This function ensures that the polynomial has a positive leading coefficient. + + This is necessary because recent sage versions (starting with v9.3 or v9.4, + we don't know) are inconsistent about the placement of the minus sign in + polynomial factorizations: + ``` + sage: R. = PolynomialRing(QQ,8,order='invlex') + sage: R((-2 * (bx - ax)) ^ 1).factor() + (-2) * (bx - ax) + sage: R((-2 * (bx - ax)) ^ 2).factor() + (4) * (-bx + ax)^2 + sage: R((-2 * (bx - ax)) ^ 3).factor() + (8) * (-bx + ax)^3 + ``` + """ + # Assert p is not 0 and that its non-zero coefficients are coprime. + # (We could just work with the primitive part p/p.content() but we want to be + # aware if factor() does not return a primitive part in future sage versions.) + assert p.content() == 1 + # Ensure that the first non-zero coefficient is positive. + return p if p.lc() > 0 else -p def conflicts(R, con): """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" - zero = R.ideal(map(numerator, con.zero)) + zero = R.ideal(list(map(numerator, con.zero))) if 1 in zero: return True # First a cheap check whether any of the individual nonzero terms conflict on @@ -195,20 +227,20 @@ def conflicts(R, con): def get_nonzero_set(R, assume): """Calculate a simple set of nonzero expressions""" - zero = R.ideal(map(numerator, assume.zero)) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = set() for nz in map(numerator, assume.nonzero): for (f,n) in nz.factor(): - nonzero.add(f) + nonzero.add(normalize_factor(f)) rnz = zero.reduce(nz) for (f,n) in rnz.factor(): - nonzero.add(f) + nonzero.add(normalize_factor(f)) return nonzero def prove_nonzero(R, exprs, assume): """Check whether an expression is provably nonzero, given assumptions""" - zero = R.ideal(map(numerator, assume.zero)) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = get_nonzero_set(R, assume) expl = set() ok = True @@ -217,27 +249,27 @@ def prove_nonzero(R, exprs, assume): return (False, [exprs[expr]]) allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) for (f, n) in allexprs.factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True - for (f, n) in zero.reduce(numerator(allexprs)).factor(): - if f not in nonzero: + for (f, n) in zero.reduce(allexprs).factor(): + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True for expr in exprs: for (f,n) in numerator(expr).factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: ok = False if ok: return (True, None) ok = True for expr in exprs: for (f,n) in zero.reduce(numerator(expr)).factor(): - if f not in nonzero: + if normalize_factor(f) not in nonzero: expl.add(exprs[expr]) if expl: return (False, list(expl)) @@ -249,8 +281,8 @@ def prove_zero(R, exprs, assume): """Check whether all of the passed expressions are provably zero, given assumptions""" r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) if not r: - return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) - zero = R.ideal(map(numerator, assume.zero)) + return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e))) + zero = R.ideal(list(map(numerator, assume.zero))) nonzero = prod(x for x in assume.nonzero) expl = [] for expr in exprs: @@ -265,8 +297,8 @@ def describe_extra(R, assume, assumeExtra): """Describe what assumptions are added, given existing assumptions""" zerox = assume.zero.copy() zerox.update(assumeExtra.zero) - zero = R.ideal(map(numerator, assume.zero)) - zeroextra = R.ideal(map(numerator, zerox)) + zero = R.ideal(list(map(numerator, assume.zero))) + zeroextra = R.ideal(list(map(numerator, zerox))) nonzero = get_nonzero_set(R, assume) ret = set() # Iterate over the extra zero expressions @@ -274,8 +306,8 @@ def describe_extra(R, assume, assumeExtra): if base not in zero: add = [] for (f, n) in numerator(base).factor(): - if f not in nonzero: - add += ["%s" % f] + if normalize_factor(f) not in nonzero: + add += ["%s" % normalize_factor(f)] if add: ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) # Iterate over the extra nonzero expressions @@ -283,8 +315,8 @@ def describe_extra(R, assume, assumeExtra): nzr = zeroextra.reduce(numerator(nz)) if nzr not in zeroextra: for (f,n) in nzr.factor(): - if zeroextra.reduce(f) not in nonzero: - ret.add("%s != 0" % zeroextra.reduce(f)) + if normalize_factor(zeroextra.reduce(f)) not in nonzero: + ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f))) return ", ".join(x for x in ret) @@ -294,22 +326,21 @@ def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): if conflicts(R, assume): # This formula does not apply - return None + return (True, None) describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + if describe != "": + describe = " (assuming " + describe + ")" ok, msg = prove_zero(R, require.zero, assume) if not ok: - return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + return (False, "FAIL, %s fails%s" % (str(msg), describe)) res, expl = prove_nonzero(R, require.nonzero, assume) if not res: - return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + return (False, "FAIL, %s fails%s" % (str(expl), describe)) - if describe != "": - return "OK (assuming %s)" % describe - else: - return "OK" + return (True, "OK%s" % describe) def concrete_verify(c): diff --git a/crypto/secp256k1/libsecp256k1/sage/secp256k1.sage b/crypto/secp256k1/libsecp256k1/sage/prove_group_implementations.sage similarity index 72% rename from crypto/secp256k1/libsecp256k1/sage/secp256k1.sage rename to crypto/secp256k1/libsecp256k1/sage/prove_group_implementations.sage index a97e732f7..23799be52 100644 --- a/crypto/secp256k1/libsecp256k1/sage/secp256k1.sage +++ b/crypto/secp256k1/libsecp256k1/sage/prove_group_implementations.sage @@ -8,25 +8,20 @@ load("weierstrass_prover.sage") def formula_secp256k1_gej_double_var(a): """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" rz = a.Z * a.Y - rz = rz * 2 - t1 = a.X^2 - t1 = t1 * 3 - t2 = t1^2 - t3 = a.Y^2 - t3 = t3 * 2 - t4 = t3^2 - t4 = t4 * 2 - t3 = t3 * a.X - rx = t3 - rx = rx * 4 - rx = -rx - rx = rx + t2 - t2 = -t2 - t3 = t3 * 6 - t3 = t3 + t2 - ry = t1 * t3 - t2 = -t4 - ry = ry + t2 + s = a.Y^2 + l = a.X^2 + l = l * 3 + l = l / 2 + t = -s + t = t * a.X + rx = l^2 + rx = rx + t + rx = rx + t + s = s^2 + t = t + rx + ry = t * l + ry = ry + s + ry = -ry return jacobianpoint(rx, ry, rz) def formula_secp256k1_gej_add_var(branch, a, b): @@ -45,29 +40,26 @@ def formula_secp256k1_gej_add_var(branch, a, b): s2 = s2 * a.Z h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if branch == 2: r = formula_secp256k1_gej_double_var(a) return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) if branch == 3: return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 + t = h * b.Z + rz = a.Z * t h2 = h^2 + h2 = -h2 h3 = h2 * h - h = h * b.Z - rz = a.Z * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) @@ -85,28 +77,25 @@ def formula_secp256k1_gej_add_ge_var(branch, a, b): s2 = s2 * a.Z h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if (branch == 2): r = formula_secp256k1_gej_double_var(a) return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) if (branch == 3): return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 - h2 = h^2 - h3 = h * h2 rz = a.Z * h + h2 = h^2 + h2 = -h2 + h3 = h2 * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) @@ -114,14 +103,15 @@ def formula_secp256k1_gej_add_zinv_var(branch, a, b): """libsecp256k1's secp256k1_gej_add_zinv_var""" bzinv = b.Z^(-1) if branch == 0: - return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) - if branch == 1: + rinf = b.Infinity bzinv2 = bzinv^2 bzinv3 = bzinv2 * bzinv rx = b.X * bzinv2 ry = b.Y * bzinv3 rz = 1 - return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz, rinf)) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) azz = a.Z * bzinv z12 = azz^2 u1 = a.X @@ -131,29 +121,25 @@ def formula_secp256k1_gej_add_zinv_var(branch, a, b): s2 = s2 * azz h = -u1 h = h + u2 - i = -s1 - i = i + s2 + i = -s2 + i = i + s1 if branch == 2: r = formula_secp256k1_gej_double_var(a) return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) if branch == 3: return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) - i2 = i^2 + rz = a.Z * h h2 = h^2 - h3 = h * h2 - rz = a.Z - rz = rz * h + h2 = -h2 + h3 = h2 * h t = u1 * h2 - rx = t - rx = rx * 2 + rx = i^2 rx = rx + h3 - rx = -rx - rx = rx + i2 - ry = -rx - ry = ry + t - ry = ry * i + rx = rx + t + rx = rx + t + t = t + rx + ry = t * i h3 = h3 * s1 - h3 = -h3 ry = ry + h3 return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) @@ -162,7 +148,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b): zeroes = {} nonzeroes = {} a_infinity = False - if (branch & 4) != 0: + if (branch & 2) != 0: nonzeroes.update({a.Infinity : 'a_infinite'}) a_infinity = True else: @@ -181,15 +167,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b): m_alt = -u2 tt = u1 * m_alt rr = rr + tt - degenerate = (branch & 3) == 3 - if (branch & 1) != 0: + degenerate = (branch & 1) != 0 + if degenerate: zeroes.update({m : 'm_zero'}) else: nonzeroes.update({m : 'm_nonzero'}) - if (branch & 2) != 0: - zeroes.update({rr : 'rr_zero'}) - else: - nonzeroes.update({rr : 'rr_nonzero'}) rr_alt = s1 rr_alt = rr_alt * 2 m_alt = m_alt + u1 @@ -197,21 +179,13 @@ def formula_secp256k1_gej_add_ge(branch, a, b): rr_alt = rr m_alt = m n = m_alt^2 - q = n * t + q = -t + q = q * n n = n^2 if degenerate: n = m t = rr_alt^2 rz = a.Z * m_alt - infinity = False - if (branch & 8) != 0: - if not a_infinity: - infinity = True - zeroes.update({rz : 'r.z=0'}) - else: - nonzeroes.update({rz : 'r.z!=0'}) - rz = rz * 2 - q = -q t = t + q rx = t t = t * 2 @@ -219,14 +193,16 @@ def formula_secp256k1_gej_add_ge(branch, a, b): t = t * rr_alt t = t + n ry = -t - rx = rx * 4 - ry = ry * 4 + ry = ry / 2 if a_infinity: rx = b.X ry = b.Y rz = 1 - if infinity: + if (branch & 4) != 0: + zeroes.update({rz : 'r.z = 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + else: + nonzeroes.update({rz : 'r.z != 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) def formula_secp256k1_gej_add_ge_old(branch, a, b): @@ -292,15 +268,18 @@ def formula_secp256k1_gej_add_ge_old(branch, a, b): return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) if __name__ == "__main__": - check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) - check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) - check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) - check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) - check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + success = True + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge) + success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)) if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": - check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) - check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) - check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) - check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) - check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43) + success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)) + + sys.exit(int(not success)) diff --git a/crypto/secp256k1/libsecp256k1/sage/secp256k1_params.sage b/crypto/secp256k1/libsecp256k1/sage/secp256k1_params.sage new file mode 100644 index 000000000..68f95adec --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/secp256k1_params.sage @@ -0,0 +1,39 @@ +"""Prime order of finite field underlying secp256k1 (2^256 - 2^32 - 977)""" +P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + +"""Finite field underlying secp256k1""" +F = FiniteField(P) + +"""Elliptic curve secp256k1: y^2 = x^3 + 7""" +C = EllipticCurve([F(0), F(7)]) + +"""Base point of secp256k1""" +G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) +if int(G[1]) & 1: + # G.y is even + G = -G + +"""Prime order of secp256k1""" +N = C.order() + +"""Finite field of scalars of secp256k1""" +Z = FiniteField(N) + +""" Beta value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" +BETA = F(2)^((P-1)/3) + +""" Lambda value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)""" +LAMBDA = Z(3)^((N-1)/3) + +assert is_prime(P) +assert is_prime(N) + +assert BETA != F(1) +assert BETA^3 == F(1) +assert BETA^2 + BETA + 1 == 0 + +assert LAMBDA != Z(1) +assert LAMBDA^3 == Z(1) +assert LAMBDA^2 + LAMBDA + 1 == 0 + +assert Integer(LAMBDA)*G == C(BETA*G[0], G[1]) diff --git a/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage b/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage index 03ef2ec90..be9cfd4c7 100644 --- a/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage +++ b/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage @@ -175,24 +175,25 @@ laws_jacobian_weierstrass = { def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" F = Integers(p) - print "Formula %s on Z%i:" % (name, p) + print("Formula %s on Z%i:" % (name, p)) points = [] - for x in xrange(0, p): - for y in xrange(0, p): + for x in range(0, p): + for y in range(0, p): point = affinepoint(F(x), F(y)) r, e = concrete_verify(on_weierstrass_curve(A, B, point)) if r: points.append(point) - for za in xrange(1, p): - for zb in xrange(1, p): + ret = True + for za in range(1, p): + for zb in range(1, p): for pa in points: for pb in points: - for ia in xrange(2): - for ib in xrange(2): + for ia in range(2): + for ib in range(2): pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) - for branch in xrange(0, branches): + for branch in range(0, branches): assumeAssert, assumeBranch, pC = formula(branch, pA, pB) pC.X = F(pC.X) pC.Y = F(pC.Y) @@ -206,13 +207,16 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): r, e = concrete_verify(assumeLaw) if r: if match: - print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)) else: match = True r, e = concrete_verify(require) if not r: - print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) - print + ret = False + print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)) + + print() + return ret def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): @@ -242,23 +246,30 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): for key in laws_jacobian_weierstrass: res[key] = [] - print ("Formula " + name + ":") + print("Formula " + name + ":") count = 0 - for branch in xrange(branches): + ret = True + for branch in range(branches): assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + assumeBranch = assumeBranch.map(lift) + assumeFormula = assumeFormula.map(lift) pC.X = lift(pC.X) pC.Y = lift(pC.Y) pC.Z = lift(pC.Z) pC.Infinity = lift(pC.Infinity) for key in laws_jacobian_weierstrass: - res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC) + if not success: + ret = False + res[key].append((msg, branch)) for key in res: - print " %s:" % key + print(" %s:" % key) val = res[key] for x in val: if x[0] is not None: - print " branch %i: %s" % (x[1], x[0]) + print(" branch %i: %s" % (x[1], x[0])) - print + print() + return ret diff --git a/crypto/secp256k1/libsecp256k1/src/CMakeLists.txt b/crypto/secp256k1/libsecp256k1/src/CMakeLists.txt new file mode 100644 index 000000000..f31b8c8f5 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/CMakeLists.txt @@ -0,0 +1,176 @@ +# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. +include(GNUInstallDirs) + +add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL + precomputed_ecmult.c + precomputed_ecmult_gen.c +) + +# Add objects explicitly rather than linking to the object libs to keep them +# from being exported. +add_library(secp256k1 secp256k1.c $) + +add_library(secp256k1_asm INTERFACE) +if(SECP256K1_ASM STREQUAL "arm32") + add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) + target_sources(secp256k1_asm_arm PUBLIC + asm/field_10x26_arm.s + ) + target_sources(secp256k1 PRIVATE $) + target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm) +endif() + +if(WIN32) + # Define our export symbol only for shared libs. + set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT) + target_compile_definitions(secp256k1 INTERFACE $<$>:SECP256K1_STATIC>) +endif() + +# Object libs don't know if they're being built for a shared or static lib. +# Grab the PIC property from secp256k1 which knows. +get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) +set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) + +target_include_directories(secp256k1 INTERFACE + # Add the include path for parent projects so that they don't have to manually add it. + $>:${PROJECT_SOURCE_DIR}/include>> + $ +) + +# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, +# see below "Calculate the version variables" in build-aux/ltmain.sh. +math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") +set_target_properties(secp256k1 PROPERTIES + SOVERSION ${${PROJECT_NAME}_soversion} +) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_target_properties(secp256k1 PROPERTIES + VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) +elseif(APPLE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) + math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") + set_target_properties(secp256k1 PROPERTIES + MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} + MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) + unset(${PROJECT_NAME}_compatibility_version) + elseif(BUILD_SHARED_LIBS) + message(WARNING + "The 'compatibility version' and 'current version' values of the DYLIB " + "will diverge from the values set by the GNU Libtool. To ensure " + "compatibility, it is recommended to upgrade CMake to at least version 3.17." + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(${PROJECT_NAME}_windows "secp256k1") + if(MSVC) + set(${PROJECT_NAME}_windows "${PROJECT_NAME}") + endif() + set_target_properties(secp256k1 PROPERTIES + ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" + RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" + ) + unset(${PROJECT_NAME}_windows) +endif() +unset(${PROJECT_NAME}_soversion) + +if(SECP256K1_BUILD_BENCHMARK) + add_executable(bench bench.c) + target_link_libraries(bench secp256k1) + add_executable(bench_internal bench_internal.c) + target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm) + add_executable(bench_ecmult bench_ecmult.c) + target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm) +endif() + +if(SECP256K1_BUILD_TESTS) + add_executable(noverify_tests tests.c) + target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) + add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") + add_executable(tests tests.c) + target_compile_definitions(tests PRIVATE VERIFY) + target_link_libraries(tests secp256k1_precomputed secp256k1_asm) + add_test(NAME secp256k1_tests COMMAND tests) + endif() +endif() + +if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) + # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables). + add_executable(exhaustive_tests tests_exhaustive.c) + target_link_libraries(exhaustive_tests secp256k1_asm) + target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) + add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests) +endif() + +if(SECP256K1_BUILD_CTIME_TESTS) + add_executable(ctime_tests ctime_tests.c) + target_link_libraries(ctime_tests secp256k1) +endif() + +if(SECP256K1_INSTALL) + install(TARGETS secp256k1 + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + set(${PROJECT_NAME}_headers + "${PROJECT_SOURCE_DIR}/include/secp256k1.h" + "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" + ) + if(SECP256K1_ENABLE_MODULE_ECDH) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") + endif() + if(SECP256K1_ENABLE_MODULE_RECOVERY) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") + endif() + if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") + endif() + if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") + endif() + if(SECP256K1_ENABLE_MODULE_MUSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h") + endif() + if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h") + endif() + install(FILES ${${PROJECT_NAME}_headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(CMakePackageConfigHelpers) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in + ${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO + ) + write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMinorVersion + ) + + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) + + include(GeneratePkgConfigFile) + generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() diff --git a/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s index 5a9cc3ffc..664b92140 100644 --- a/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s +++ b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s @@ -1,9 +1,9 @@ @ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: -/********************************************************************** - * Copyright (c) 2014 Wladimir J. van der Laan * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ /* ARM implementation of field_10x26 inner loops. @@ -16,15 +16,9 @@ Note: */ .syntax unified - .arch armv7-a @ eabi attributes - see readelf -A - .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes - .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no - .eabi_attribute 10, 0 @ Tag_FP_arch = none .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed - .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 .text @ Field constants @@ -35,6 +29,7 @@ Note: .align 2 .global secp256k1_fe_mul_inner .type secp256k1_fe_mul_inner, %function + .hidden secp256k1_fe_mul_inner @ Arguments: @ r0 r Restrict: can overlap with a, not with b @ r1 a @@ -522,6 +517,7 @@ secp256k1_fe_mul_inner: .align 2 .global secp256k1_fe_sqr_inner .type secp256k1_fe_sqr_inner, %function + .hidden secp256k1_fe_sqr_inner @ Arguments: @ r0 r Can overlap with a @ r1 a @@ -917,3 +913,4 @@ secp256k1_fe_sqr_inner: ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + .section .note.GNU-stack,"",%progbits diff --git a/crypto/secp256k1/libsecp256k1/src/assumptions.h b/crypto/secp256k1/libsecp256k1/src/assumptions.h new file mode 100644 index 000000000..796100535 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/assumptions.h @@ -0,0 +1,87 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ASSUMPTIONS_H +#define SECP256K1_ASSUMPTIONS_H + +#include + +#include "util.h" +#if defined(SECP256K1_INT128_NATIVE) +#include "int128_native.h" +#endif + +/* This library, like most software, relies on a number of compiler implementation defined (but not undefined) + behaviours. Although the behaviours we require are essentially universal we test them specifically here to + reduce the odds of experiencing an unwelcome surprise. +*/ + +#if defined(__has_attribute) +# if __has_attribute(__unavailable__) +__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function."))) +# endif +#endif +static void secp256k1_assumption_checker(void) { + /* Bytes are 8 bits. */ + STATIC_ASSERT(CHAR_BIT == 8); + + /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 + without signed overflow, which would be undefined behaviour. */ + STATIC_ASSERT(UINT_MAX <= UINT32_MAX); + + /* Conversions from unsigned to signed outside of the bounds of the signed type are + implementation-defined. Verify that they function as reinterpreting the lower + bits of the input in two's complement notation. Do this for conversions: + - from uint(N)_t to int(N)_t with negative result + - from uint(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with positive result */ + + /* To int8_t. */ + STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55)); + STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34); + + /* To int16_t. */ + STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322); + STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678); + + /* To int32_t. */ + STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B); + STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789); + + /* To int64_t. */ + STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL); + + /* To int128_t. */ + STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)); +#endif + + /* Right shift on negative signed values is implementation defined. Verify that it + acts as a right shift in two's complement with sign extension (i.e duplicating + the top bit into newly added bits). */ + STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA); + STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A); + STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48); + STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL); +#if defined(SECP256K1_INT128_NATIVE) + STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)); +#endif + + /* This function is not supposed to be called. */ + VERIFY_CHECK(0); +} + +#endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/basic-config.h b/crypto/secp256k1/libsecp256k1/src/basic-config.h deleted file mode 100644 index c4c16eb7c..000000000 --- a/crypto/secp256k1/libsecp256k1/src/basic-config.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_BASIC_CONFIG_ -#define _SECP256K1_BASIC_CONFIG_ - -#ifdef USE_BASIC_CONFIG - -#undef USE_ASM_X86_64 -#undef USE_ENDOMORPHISM -#undef USE_FIELD_10X26 -#undef USE_FIELD_5X52 -#undef USE_FIELD_INV_BUILTIN -#undef USE_FIELD_INV_NUM -#undef USE_NUM_GMP -#undef USE_NUM_NONE -#undef USE_SCALAR_4X64 -#undef USE_SCALAR_8X32 -#undef USE_SCALAR_INV_BUILTIN -#undef USE_SCALAR_INV_NUM - -#define USE_NUM_NONE 1 -#define USE_FIELD_INV_BUILTIN 1 -#define USE_SCALAR_INV_BUILTIN 1 -#define USE_FIELD_10X26 1 -#define USE_SCALAR_8X32 1 - -#endif // USE_BASIC_CONFIG -#endif // _SECP256K1_BASIC_CONFIG_ diff --git a/crypto/secp256k1/libsecp256k1/src/bench.c b/crypto/secp256k1/libsecp256k1/src/bench.c new file mode 100644 index 000000000..149f25fce --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/bench.c @@ -0,0 +1,280 @@ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include +#include + +#include "../include/secp256k1.h" +#include "util.h" +#include "bench.h" + +static void help(int default_iters) { + printf("Benchmarks the following algorithms:\n"); + printf(" - ECDSA signing/verification\n"); + +#ifdef ENABLE_MODULE_ECDH + printf(" - ECDH key exchange (optional module)\n"); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + printf(" - Public key recovery (optional module)\n"); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + printf(" - Schnorr signatures (optional module)\n"); +#endif + + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n"); + printf(" ecdsa_sign : ECDSA siging algorithm\n"); + printf(" ecdsa_verify : ECDSA verification algorithm\n"); + printf(" ec : all EC public key algorithms (keygen)\n"); + printf(" ec_keygen : EC public key generation\n"); + +#ifdef ENABLE_MODULE_RECOVERY + printf(" ecdsa_recover : ECDSA public key recovery algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_ECDH + printf(" ecdh : ECDH key exchange algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + printf(" schnorrsig : all Schnorr signature algorithms (sign, verify)\n"); + printf(" schnorrsig_sign : Schnorr sigining algorithm\n"); + printf(" schnorrsig_verify : Schnorr verification algorithm\n"); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n"); + printf(" ellswift_encode : ElligatorSwift encoding\n"); + printf(" ellswift_decode : ElligatorSwift decoding\n"); + printf(" ellswift_keygen : ElligatorSwift key generation\n"); + printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n"); +#endif + + printf("\n"); +} + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +} bench_data; + +static void bench_verify(void* arg, int iters) { + int i; + bench_data* data = (bench_data*)arg; + + for (i = 0; i < iters; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +static void bench_sign_setup(void* arg) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_sign_run(void* arg, int iters) { + int i; + bench_data *data = (bench_data*)arg; + + unsigned char sig[74]; + for (i = 0; i < iters; i++) { + size_t siglen = 74; + int j; + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; + } + } +} + +static void bench_keygen_setup(void* arg) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_keygen_run(void *arg, int iters) { + int i; + bench_data *data = (bench_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char pub33[33]; + size_t len = 33; + secp256k1_pubkey pubkey; + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED)); + memcpy(data->key, pub33 + 1, 32); + } +} + + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/bench_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/bench_impl.h" +#endif + +int main(int argc, char** argv) { + int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + bench_data data; + + int d = argc == 1; + int default_iters = 20000; + int iters = get_iters(default_iters); + + /* Check for invalid user arguments */ + char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover", + "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec", + "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode", + "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"}; + size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); + int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size); + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return EXIT_SUCCESS; + } else if (invalid_args) { + fprintf(stderr, "./bench: unrecognized argument.\n\n"); + help(default_iters); + return EXIT_FAILURE; + } + } + +/* Check if the user tries to benchmark optional module without building it */ +#ifndef ENABLE_MODULE_ECDH + if (have_flag(argc, argv, "ecdh")) { + fprintf(stderr, "./bench: ECDH module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); + return EXIT_FAILURE; + } +#endif + +#ifndef ENABLE_MODULE_RECOVERY + if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { + fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); + return EXIT_FAILURE; + } +#endif + +#ifndef ENABLE_MODULE_SCHNORRSIG + if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { + fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); + return EXIT_FAILURE; + } +#endif + +#ifndef ENABLE_MODULE_ELLSWIFT + if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") || + have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") || + have_flag(argc, argv, "ellswift_ecdh")) { + fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n"); + fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n"); + return EXIT_FAILURE; + } +#endif + + /* ECDSA benchmark */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } + data.siglen = 72; + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + print_output_table_header_row(); + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); + +#ifdef ENABLE_MODULE_ECDH + /* ECDH benchmarks */ + run_ecdh_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA recovery benchmarks */ + run_recovery_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + /* Schnorr signature benchmarks */ + run_schnorrsig_bench(iters, argc, argv); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + /* ElligatorSwift benchmarks */ + run_ellswift_bench(iters, argc, argv); +#endif + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/src/bench.h b/crypto/secp256k1/libsecp256k1/src/bench.h index 3a71b4aaf..232fb35fc 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench.h +++ b/crypto/secp256k1/libsecp256k1/src/bench.h @@ -1,50 +1,115 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_BENCH_H_ -#define _SECP256K1_BENCH_H_ +#ifndef SECP256K1_BENCH_H +#define SECP256K1_BENCH_H +#include +#include #include -#include -#include "sys/time.h" +#include -static double gettimedouble(void) { +#if (defined(_MSC_VER) && _MSC_VER >= 1900) +# include +#else +# include +#endif + +static int64_t gettime_i64(void) { +#if (defined(_MSC_VER) && _MSC_VER >= 1900) + /* C11 way to get wallclock time */ + struct timespec tv; + if (!timespec_get(&tv, TIME_UTC)) { + fputs("timespec_get failed!", stderr); + exit(EXIT_FAILURE); + } + return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; +#else struct timeval tv; gettimeofday(&tv, NULL); - return tv.tv_usec * 0.000001 + tv.tv_sec; + return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; +#endif } -void print_number(double x) { - double y = x; - int c = 0; - if (y < 0.0) { - y = -y; +#define FP_EXP (6) +#define FP_MULT (1000000LL) + +/* Format fixed point number. */ +static void print_number(const int64_t x) { + int64_t x_abs, y; + int c, i, rounding, g; /* g = integer part size, c = fractional part size */ + size_t ptr; + char buffer[30]; + + if (x == INT64_MIN) { + /* Prevent UB. */ + printf("ERR"); + return; } - while (y < 100.0) { - y *= 10.0; + x_abs = x < 0 ? -x : x; + + /* Determine how many decimals we want to show (more than FP_EXP makes no + * sense). */ + y = x_abs; + c = 0; + while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) { + y *= 10LL; c++; } - printf("%.*f", c, x); + + /* Round to 'c' decimals. */ + y = x_abs; + rounding = 0; + for (i = c; i < FP_EXP; ++i) { + rounding = (y % 10) >= 5; + y /= 10; + } + y += rounding; + + /* Format and print the number. */ + ptr = sizeof(buffer) - 1; + buffer[ptr] = 0; + g = 0; + if (c != 0) { /* non zero fractional part */ + for (i = 0; i < c; ++i) { + buffer[--ptr] = '0' + (y % 10); + y /= 10; + } + } else if (c == 0) { /* fractional part is 0 */ + buffer[--ptr] = '0'; + } + buffer[--ptr] = '.'; + do { + buffer[--ptr] = '0' + (y % 10); + y /= 10; + g++; + } while (y != 0); + if (x < 0) { + buffer[--ptr] = '-'; + g++; + } + printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */ + printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ } -void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { +static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { int i; - double min = HUGE_VAL; - double sum = 0.0; - double max = 0.0; + int64_t min = INT64_MAX; + int64_t sum = 0; + int64_t max = 0; for (i = 0; i < count; i++) { - double begin, total; + int64_t begin, total; if (setup != NULL) { setup(data); } - begin = gettimedouble(); - benchmark(data); - total = gettimedouble() - begin; + begin = gettime_i64(); + benchmark(data, iter); + total = gettime_i64() - begin; if (teardown != NULL) { - teardown(data); + teardown(data, iter); } if (total < min) { min = total; @@ -54,13 +119,70 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v } sum += total; } - printf("%s: min ", name); - print_number(min * 1000000.0 / iter); - printf("us / avg "); - print_number((sum / count) * 1000000.0 / iter); - printf("us / max "); - print_number(max * 1000000.0 / iter); - printf("us\n"); + /* ',' is used as a column delimiter */ + printf("%-30s, ", name); + print_number(min * FP_MULT / iter); + printf(" , "); + print_number(((sum * FP_MULT) / count) / iter); + printf(" , "); + print_number(max * FP_MULT / iter); + printf("\n"); } -#endif +static int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + while (argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +/* takes an array containing the arguments that the user is allowed to enter on the command-line + returns: + - 1 if the user entered an invalid argument + - 0 if all the user entered arguments are valid */ +static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { + size_t i; + int found_valid; + char** argm = argv + argc; + argv++; + + while (argv != argm) { + found_valid = 0; + for (i = 0; i < n; i++) { + if (strcmp(*argv, valid_args[i]) == 0) { + found_valid = 1; /* user entered a valid arg from the list */ + break; + } + } + if (found_valid == 0) { + return 1; /* invalid arg found */ + } + argv++; + } + return 0; +} + +static int get_iters(int default_iters) { + char* env = getenv("SECP256K1_BENCH_ITERS"); + if (env) { + return strtol(env, NULL, 0); + } else { + return default_iters; + } +} + +static void print_output_table_header_row(void) { + char* bench_str = "Benchmark"; /* left justified */ + char* min_str = " Min(us) "; /* center alignment */ + char* avg_str = " Avg(us) "; + char* max_str = " Max(us) "; + printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str); + printf("\n"); +} + +#endif /* SECP256K1_BENCH_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/bench_ecmult.c b/crypto/secp256k1/libsecp256k1/src/bench_ecmult.c new file mode 100644 index 000000000..172292d57 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/bench_ecmult.c @@ -0,0 +1,368 @@ +/*********************************************************************** + * Copyright (c) 2017 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ +#include +#include + +#include "secp256k1.c" +#include "../include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" + +#define POINTS 32768 + +static void help(char **argv) { + printf("Benchmark EC multiplication algorithms\n"); + printf("\n"); + printf("Usage: %s \n", argv[0]); + printf("The output shows the number of multiplied and summed points right after the\n"); + printf("function name. The letter 'g' indicates that one of the points is the generator.\n"); + printf("The benchmarks are divided by the number of points.\n"); + printf("\n"); + printf("default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n"); + printf(" batch size\n"); + printf("pippenger_wnaf: for all batch sizes\n"); + printf("strauss_wnaf: for all batch sizes\n"); + printf("simple: multiply and sum each point individually\n"); +} + +typedef struct { + /* Setup once in advance */ + secp256k1_context* ctx; + secp256k1_scratch_space* scratch; + secp256k1_scalar* scalars; + secp256k1_ge* pubkeys; + secp256k1_gej* pubkeys_gej; + secp256k1_scalar* seckeys; + secp256k1_gej* expected_output; + secp256k1_ecmult_multi_func ecmult_multi; + + /* Changes per benchmark */ + size_t count; + int includes_g; + + /* Changes per benchmark iteration, used to pick different scalars and pubkeys + * in each run. */ + size_t offset1; + size_t offset2; + + /* Benchmark output. */ + secp256k1_gej* output; +} bench_data; + +/* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */ +static void hash_into_offset(bench_data* data, size_t x) { + data->offset1 = (x * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) % POINTS; +} + +/* Check correctness of the benchmark by computing + * sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */ +static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset, size_t* scalar_offset, size_t* scalar_gen_offset, int iters) { + int i; + secp256k1_gej sum_output, tmp; + secp256k1_scalar sum_scalars; + + secp256k1_gej_set_infinity(&sum_output); + secp256k1_scalar_set_int(&sum_scalars, 0); + for (i = 0; i < iters; ++i) { + secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL); + if (scalar_gen_offset != NULL) { + secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]); + } + if (seckey_offset != NULL) { + secp256k1_scalar s = data->seckeys[(*seckey_offset+i) % POINTS]; + secp256k1_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]); + secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s); + } + } + secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); + CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); +} + +static void bench_ecmult_setup(void* arg) { + bench_data* data = (bench_data*)arg; + /* Re-randomize offset to ensure that we're using different scalars and + * group elements in each run. */ + hash_into_offset(data, data->offset1); +} + +static void bench_ecmult_gen(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_gen_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); +} + +static void bench_ecmult_const(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]); + } +} + +static void bench_ecmult_const_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); +} + +static void bench_ecmult_1p(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL); + } +} + +static void bench_ecmult_1p_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters); +} + +static void bench_ecmult_0p_g(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters; ++i) { + secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_0p_g_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters); +} + +static void bench_ecmult_1p_g(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int i; + + for (i = 0; i < iters/2; ++i) { + secp256k1_ecmult(&data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]); + } +} + +static void bench_ecmult_1p_g_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, &data->offset1, iters/2); +} + +static void run_ecmult_bench(bench_data* data, int iters) { + char str[32]; + sprintf(str, "ecmult_gen"); + run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters); + sprintf(str, "ecmult_const"); + run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters); + /* ecmult with non generator point */ + sprintf(str, "ecmult_1p"); + run_benchmark(str, bench_ecmult_1p, bench_ecmult_setup, bench_ecmult_1p_teardown, data, 10, iters); + /* ecmult with generator point */ + sprintf(str, "ecmult_0p_g"); + run_benchmark(str, bench_ecmult_0p_g, bench_ecmult_setup, bench_ecmult_0p_g_teardown, data, 10, iters); + /* ecmult with generator and non-generator point. The reported time is per point. */ + sprintf(str, "ecmult_1p_g"); + run_benchmark(str, bench_ecmult_1p_g, bench_ecmult_setup, bench_ecmult_1p_g_teardown, data, 10, 2*iters); +} + +static int bench_ecmult_multi_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) { + bench_data* data = (bench_data*)arg; + if (data->includes_g) ++idx; + if (idx == 0) { + *sc = data->scalars[data->offset1]; + *ge = secp256k1_ge_const_g; + } else { + *sc = data->scalars[(data->offset1 + idx) % POINTS]; + *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; + } + return 1; +} + +static void bench_ecmult_multi(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + + int includes_g = data->includes_g; + int iter; + int count = data->count; + iters = iters / data->count; + + for (iter = 0; iter < iters; ++iter) { + data->ecmult_multi(&data->ctx->error_callback, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_ecmult_multi_callback, arg, count - includes_g); + data->offset1 = (data->offset1 + count) % POINTS; + data->offset2 = (data->offset2 + count - 1) % POINTS; + } +} + +static void bench_ecmult_multi_setup(void* arg) { + bench_data* data = (bench_data*)arg; + hash_into_offset(data, data->count); +} + +static void bench_ecmult_multi_teardown(void* arg, int iters) { + bench_data* data = (bench_data*)arg; + int iter; + iters = iters / data->count; + /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ + for (iter = 0; iter < iters; ++iter) { + secp256k1_gej tmp; + secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); + CHECK(secp256k1_gej_is_infinity(&tmp)); + } +} + +static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { + secp256k1_sha256 sha256; + unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; + unsigned char buf[32]; + int overflow = 0; + c[6] = num; + c[7] = num >> 8; + c[8] = num >> 16; + c[9] = num >> 24; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, c, sizeof(c)); + secp256k1_sha256_finalize(&sha256, buf); + secp256k1_scalar_set_b32(scalar, buf, &overflow); + CHECK(!overflow); +} + +static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { + char str[32]; + size_t iters = 1 + num_iters / count; + size_t iter; + + data->count = count; + data->includes_g = includes_g; + + /* Compute (the negation of) the expected results directly. */ + hash_into_offset(data, data->count); + for (iter = 0; iter < iters; ++iter) { + secp256k1_scalar tmp; + secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS]; + size_t i = 0; + for (i = 0; i + 1 < count; ++i) { + secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); + secp256k1_scalar_add(&total, &total, &tmp); + } + secp256k1_scalar_negate(&total, &total); + secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total); + } + + /* Run the benchmark. */ + if (includes_g) { + sprintf(str, "ecmult_multi_%ip_g", (int)count - 1); + } else { + sprintf(str, "ecmult_multi_%ip", (int)count); + } + run_benchmark(str, bench_ecmult_multi, bench_ecmult_multi_setup, bench_ecmult_multi_teardown, data, 10, count * iters); +} + +int main(int argc, char **argv) { + bench_data data; + int i, p; + size_t scratch_size; + + int iters = get_iters(10000); + + data.ecmult_multi = secp256k1_ecmult_multi_var; + + if (argc > 1) { + if(have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(argv); + return EXIT_SUCCESS; + } else if(have_flag(argc, argv, "pippenger_wnaf")) { + printf("Using pippenger_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single; + } else if(have_flag(argc, argv, "strauss_wnaf")) { + printf("Using strauss_wnaf:\n"); + data.ecmult_multi = secp256k1_ecmult_strauss_batch_single; + } else if(have_flag(argc, argv, "simple")) { + printf("Using simple algorithm:\n"); + } else { + fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]); + help(argv); + return EXIT_FAILURE; + } + } + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + if (!have_flag(argc, argv, "simple")) { + data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); + } else { + data.scratch = NULL; + } + + /* Allocate stuff */ + data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS); + data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS); + data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS); + data.pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS); + data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1)); + data.output = malloc(sizeof(secp256k1_gej) * (iters + 1)); + + /* Generate a set of scalars, and private/public keypairs. */ + secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g); + secp256k1_scalar_set_int(&data.seckeys[0], 1); + for (i = 0; i < POINTS; ++i) { + generate_scalar(i, &data.scalars[i]); + if (i) { + secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); + secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); + } + } + secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS); + + + print_output_table_header_row(); + /* Initialize offset1 and offset2 */ + hash_into_offset(&data, 0); + run_ecmult_bench(&data, iters); + + for (i = 1; i <= 8; ++i) { + run_ecmult_multi_bench(&data, i, 1, iters); + } + + /* This is disabled with low count of iterations because the loop runs 77 times even with iters=1 + * and the higher it goes the longer the computation takes(more points) + * So we don't run this benchmark with low iterations to prevent slow down */ + if (iters > 2) { + for (p = 0; p <= 11; ++p) { + for (i = 9; i <= 16; ++i) { + run_ecmult_multi_bench(&data, i << p, 1, iters); + } + } + } + + if (data.scratch != NULL) { + secp256k1_scratch_space_destroy(data.ctx, data.scratch); + } + secp256k1_context_destroy(data.ctx); + free(data.scalars); + free(data.pubkeys); + free(data.pubkeys_gej); + free(data.seckeys); + free(data.output); + free(data.expected_output); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/src/bench_internal.c b/crypto/secp256k1/libsecp256k1/src/bench_internal.c index 0809f77bd..8688a4dc7 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_internal.c +++ b/crypto/secp256k1/libsecp256k1/src/bench_internal.c @@ -1,382 +1,437 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include +#include -#include "include/secp256k1.h" +#include "secp256k1.c" +#include "../include/secp256k1.h" +#include "assumptions.h" #include "util.h" #include "hash_impl.h" -#include "num_impl.h" #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" -#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" -#include "secp256k1.c" + +static void help(int default_iters) { + printf("Benchmarks various internal routines.\n"); + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench_internal [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n"); + printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n"); + printf(" group : all group operations (add, double, to_affine)\n"); + printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n"); + printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n"); + printf(" context : all context object operations (context_create)\n"); + printf("\n"); +} typedef struct { - secp256k1_scalar scalar_x, scalar_y; - secp256k1_fe fe_x, fe_y; - secp256k1_ge ge_x, ge_y; - secp256k1_gej gej_x, gej_y; + secp256k1_scalar scalar[2]; + secp256k1_fe fe[4]; + secp256k1_ge ge[2]; + secp256k1_gej gej[2]; unsigned char data[64]; int wnaf[256]; -} bench_inv_t; - -void bench_setup(void* arg) { - bench_inv_t *data = (bench_inv_t*)arg; - - static const unsigned char init_x[32] = { - 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, - 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, - 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, - 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 +} bench_inv; + +static void bench_setup(void* arg) { + bench_inv *data = (bench_inv*)arg; + + static const unsigned char init[4][32] = { + /* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0], + and the (implied affine) X coordinate of gej[0]. */ + { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }, + /* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1], + and the (implied affine) X coordinate of gej[1]. */ + { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }, + /* Initializer for fe[2] and the Z coordinate of gej[0]. */ + { + 0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d, + 0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44, + 0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38, + 0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7 + }, + /* Initializer for fe[3] and the Z coordinate of gej[1]. */ + { + 0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e, + 0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68, + 0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3, + 0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5 + } }; - static const unsigned char init_y[32] = { - 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, - 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, - 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, - 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 - }; + secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); + secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); + secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); + secp256k1_fe_set_b32_limit(&data->fe[1], init[1]); + secp256k1_fe_set_b32_limit(&data->fe[2], init[2]); + secp256k1_fe_set_b32_limit(&data->fe[3], init[3]); + CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); + CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); + secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]); + secp256k1_gej_rescale(&data->gej[0], &data->fe[2]); + secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]); + secp256k1_gej_rescale(&data->gej[1], &data->fe[3]); + memcpy(data->data, init[0], 32); + memcpy(data->data + 32, init[1], 32); +} - secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL); - secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL); - secp256k1_fe_set_b32(&data->fe_x, init_x); - secp256k1_fe_set_b32(&data->fe_y, init_y); - CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); - CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); - secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); - secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); - memcpy(data->data, init_x, 32); - memcpy(data->data + 32, init_y, 32); +static void bench_scalar_add(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; i++) { + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(j <= iters); } -void bench_scalar_add(void* arg) { +static void bench_scalar_negate(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 2000000; i++) { - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]); } } -void bench_scalar_negate(void* arg) { +static void bench_scalar_half(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; + secp256k1_scalar s = data->scalar[0]; - for (i = 0; i < 2000000; i++) { - secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); + for (i = 0; i < iters; i++) { + secp256k1_scalar_half(&s, &s); } + + data->scalar[0] = s; } -void bench_scalar_sqr(void* arg) { +static void bench_scalar_mul(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); + for (i = 0; i < iters; i++) { + secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } } -void bench_scalar_mul(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; +static void bench_scalar_split(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_scalar tmp; - for (i = 0; i < 200000; i++) { - secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]); } + CHECK(j <= iters); } -#ifdef USE_ENDOMORPHISM -void bench_scalar_split(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; +static void bench_scalar_inverse(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 20000; i++) { - secp256k1_scalar l, r; - secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } + CHECK(j <= iters); } -#endif -void bench_scalar_inverse(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; +static void bench_scalar_inverse_var(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 2000; i++) { - secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); } + CHECK(j <= iters); } -void bench_scalar_inverse_var(void* arg) { +static void bench_field_half(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 2000; i++) { - secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_fe_half(&data->fe[0]); } } -void bench_field_normalize(void* arg) { +static void bench_field_normalize(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 2000000; i++) { - secp256k1_fe_normalize(&data->fe_x); + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize(&data->fe[0]); } } -void bench_field_normalize_weak(void* arg) { +static void bench_field_normalize_weak(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 2000000; i++) { - secp256k1_fe_normalize_weak(&data->fe_x); + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize_weak(&data->fe[0]); } } -void bench_field_mul(void* arg) { +static void bench_field_mul(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); + for (i = 0; i < iters; i++) { + secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]); } } -void bench_field_sqr(void* arg) { +static void bench_field_sqr(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_fe_sqr(&data->fe_x, &data->fe_x); + for (i = 0; i < iters; i++) { + secp256k1_fe_sqr(&data->fe[0], &data->fe[0]); } } -void bench_field_inverse(void* arg) { +static void bench_field_inverse(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 20000; i++) { - secp256k1_fe_inv(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); + for (i = 0; i < iters; i++) { + secp256k1_fe_inv(&data->fe[0], &data->fe[0]); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); } } -void bench_field_inverse_var(void* arg) { +static void bench_field_inverse_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 20000; i++) { - secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); + for (i = 0; i < iters; i++) { + secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); } } -void bench_field_sqrt(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; +static void bench_field_sqrt(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_fe t; - for (i = 0; i < 20000; i++) { - secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); + for (i = 0; i < iters; i++) { + t = data->fe[0]; + j += secp256k1_fe_sqrt(&data->fe[0], &t); + secp256k1_fe_add(&data->fe[0], &data->fe[1]); } + CHECK(j <= iters); } -void bench_group_double_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; +static void bench_field_is_square_var(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_fe t = data->fe[0]; - for (i = 0; i < 200000; i++) { - secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); + for (i = 0; i < iters; i++) { + j += secp256k1_fe_is_square_var(&t); + secp256k1_fe_add(&t, &data->fe[1]); + secp256k1_fe_normalize_var(&t); } + CHECK(j <= iters); } -void bench_group_add_var(void* arg) { +static void bench_group_double_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); + for (i = 0; i < iters; i++) { + secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL); } } -void bench_group_add_affine(void* arg) { +static void bench_group_add_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); + for (i = 0; i < iters; i++) { + secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL); } } -void bench_group_add_affine_var(void* arg) { +static void bench_group_add_affine(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); + for (i = 0; i < iters; i++) { + secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]); } } -void bench_group_jacobi_var(void* arg) { +static void bench_group_add_affine_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 20000; i++) { - secp256k1_gej_has_quad_y_var(&data->gej_x); + for (i = 0; i < iters; i++) { + secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL); } } -void bench_ecmult_wnaf(void* arg) { +static void bench_group_add_zinv_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; - for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + for (i = 0; i < iters; i++) { + secp256k1_gej_add_zinv_var(&data->gej[0], &data->gej[0], &data->ge[1], &data->gej[0].y); } } -void bench_wnaf_const(void* arg) { +static void bench_group_to_affine_var(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < iters; ++i) { + secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]); + /* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates. + Note that the resulting coordinates will generally not correspond to a point + on the curve, but this is not a problem for the code being benchmarked here. + Adding and normalizing have less overhead than EC operations (which could + guarantee the point remains on the curve). */ + secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y); + secp256k1_fe_add(&data->gej[0].y, &data->fe[2]); + secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x); + secp256k1_fe_normalize_var(&data->gej[0].x); + secp256k1_fe_normalize_var(&data->gej[0].y); + secp256k1_fe_normalize_var(&data->gej[0].z); } } +static void bench_ecmult_wnaf(void* arg, int iters) { + int i, bits = 0, overflow = 0; + bench_inv *data = (bench_inv*)arg; -void bench_sha256(void* arg) { + for (i = 0; i < iters; i++) { + bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A); + overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + } + CHECK(overflow >= 0); + CHECK(bits <= 256*iters); +} + +static void bench_sha256(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_sha256_t sha; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 sha; - for (i = 0; i < 20000; i++) { + for (i = 0; i < iters; i++) { secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, data->data, 32); secp256k1_sha256_finalize(&sha, data->data); } } -void bench_hmac_sha256(void* arg) { +static void bench_hmac_sha256(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_hmac_sha256_t hmac; + bench_inv *data = (bench_inv*)arg; + secp256k1_hmac_sha256 hmac; - for (i = 0; i < 20000; i++) { + for (i = 0; i < iters; i++) { secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); secp256k1_hmac_sha256_write(&hmac, data->data, 32); secp256k1_hmac_sha256_finalize(&hmac, data->data); } } -void bench_rfc6979_hmac_sha256(void* arg) { +static void bench_rfc6979_hmac_sha256(void* arg, int iters) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_rfc6979_hmac_sha256_t rng; + bench_inv *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; - for (i = 0; i < 20000; i++) { + for (i = 0; i < iters; i++) { secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); } } -void bench_context_verify(void* arg) { +static void bench_context(void* arg, int iters) { int i; (void)arg; - for (i = 0; i < 20; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); - } -} - -void bench_context_sign(void* arg) { - int i; - (void)arg; - for (i = 0; i < 200; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); - } -} - -#ifndef USE_NUM_NONE -void bench_num_jacobi(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_num nx, norder; - - secp256k1_scalar_get_num(&nx, &data->scalar_x); - secp256k1_scalar_order_get_num(&norder); - secp256k1_scalar_get_num(&norder, &data->scalar_y); - - for (i = 0; i < 200000; i++) { - secp256k1_num_jacobi(&nx, &norder); + for (i = 0; i < iters; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE)); } } -#endif -int have_flag(int argc, char** argv, char *flag) { - char** argm = argv + argc; - argv++; - if (argv == argm) { - return 1; - } - while (argv != NULL && argv != argm) { - if (strcmp(*argv, flag) == 0) { - return 1; +int main(int argc, char **argv) { + bench_inv data; + int default_iters = 20000; + int iters = get_iters(default_iters); + int d = argc == 1; /* default */ + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return EXIT_SUCCESS; } - argv++; } - return 0; -} -int main(int argc, char **argv) { - bench_inv_t data; - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); -#ifdef USE_ENDOMORPHISM - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); -#endif - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); - - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); - - if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); - - if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); - - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); - - if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); - if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); - -#ifndef USE_NUM_NONE - if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); -#endif - return 0; + print_output_table_header_row(); + + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10); + if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters); + + if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters); + + return EXIT_SUCCESS; } diff --git a/crypto/secp256k1/libsecp256k1/src/bench_schnorr_verify.c b/crypto/secp256k1/libsecp256k1/src/bench_schnorr_verify.c deleted file mode 100644 index 5f137dda2..000000000 --- a/crypto/secp256k1/libsecp256k1/src/bench_schnorr_verify.c +++ /dev/null @@ -1,73 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "include/secp256k1.h" -#include "include/secp256k1_schnorr.h" -#include "util.h" -#include "bench.h" - -typedef struct { - unsigned char key[32]; - unsigned char sig[64]; - unsigned char pubkey[33]; - size_t pubkeylen; -} benchmark_schnorr_sig_t; - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - benchmark_schnorr_sig_t sigs[64]; - int numsigs; -} benchmark_schnorr_verify_t; - -static void benchmark_schnorr_init(void* arg) { - int i, k; - benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = 1 + i; - } - for (k = 0; k < data->numsigs; k++) { - secp256k1_pubkey pubkey; - for (i = 0; i < 32; i++) { - data->sigs[k].key[i] = 33 + i + k; - } - secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL); - data->sigs[k].pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key)); - CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); - } -} - -static void benchmark_schnorr_verify(void* arg) { - int i; - benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; - - for (i = 0; i < 20000 / data->numsigs; i++) { - secp256k1_pubkey pubkey; - data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen)); - CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0)); - data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); - } -} - - - -int main(void) { - benchmark_schnorr_verify_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - data.numsigs = 1; - run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000); - - secp256k1_context_destroy(data.ctx); - return 0; -} diff --git a/crypto/secp256k1/libsecp256k1/src/bench_sign.c b/crypto/secp256k1/libsecp256k1/src/bench_sign.c deleted file mode 100644 index ed7224d75..000000000 --- a/crypto/secp256k1/libsecp256k1/src/bench_sign.c +++ /dev/null @@ -1,56 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include "include/secp256k1.h" -#include "util.h" -#include "bench.h" - -typedef struct { - secp256k1_context* ctx; - unsigned char msg[32]; - unsigned char key[32]; -} bench_sign_t; - -static void bench_sign_setup(void* arg) { - int i; - bench_sign_t *data = (bench_sign_t*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = i + 1; - } - for (i = 0; i < 32; i++) { - data->key[i] = i + 65; - } -} - -static void bench_sign(void* arg) { - int i; - bench_sign_t *data = (bench_sign_t*)arg; - - unsigned char sig[74]; - for (i = 0; i < 20000; i++) { - size_t siglen = 74; - int j; - secp256k1_ecdsa_signature signature; - CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); - for (j = 0; j < 32; j++) { - data->msg[j] = sig[j]; - data->key[j] = sig[j + 32]; - } - } -} - -int main(void) { - bench_sign_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - - run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); - - secp256k1_context_destroy(data.ctx); - return 0; -} diff --git a/crypto/secp256k1/libsecp256k1/src/bench_verify.c b/crypto/secp256k1/libsecp256k1/src/bench_verify.c deleted file mode 100644 index 418defa0a..000000000 --- a/crypto/secp256k1/libsecp256k1/src/bench_verify.c +++ /dev/null @@ -1,112 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "include/secp256k1.h" -#include "util.h" -#include "bench.h" - -#ifdef ENABLE_OPENSSL_TESTS -#include -#include -#include -#endif - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - unsigned char key[32]; - unsigned char sig[72]; - size_t siglen; - unsigned char pubkey[33]; - size_t pubkeylen; -#ifdef ENABLE_OPENSSL_TESTS - EC_GROUP* ec_group; -#endif -} benchmark_verify_t; - -static void benchmark_verify(void* arg) { - int i; - benchmark_verify_t* data = (benchmark_verify_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); - CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - } -} - -#ifdef ENABLE_OPENSSL_TESTS -static void benchmark_verify_openssl(void* arg) { - int i; - benchmark_verify_t* data = (benchmark_verify_t*)arg; - - for (i = 0; i < 20000; i++) { - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - { - EC_KEY *pkey = EC_KEY_new(); - const unsigned char *pubkey = &data->pubkey[0]; - int result; - - CHECK(pkey != NULL); - result = EC_KEY_set_group(pkey, data->ec_group); - CHECK(result); - result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; - CHECK(result); - result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); - CHECK(result); - EC_KEY_free(pkey); - } - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - } -} -#endif - -int main(void) { - int i; - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - benchmark_verify_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - for (i = 0; i < 32; i++) { - data.msg[i] = 1 + i; - } - for (i = 0; i < 32; i++) { - data.key[i] = 33 + i; - } - data.siglen = 72; - CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); - CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); - data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - - run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); -#ifdef ENABLE_OPENSSL_TESTS - data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); - run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); - EC_GROUP_free(data.ec_group); -#endif - - secp256k1_context_destroy(data.ctx); - return 0; -} diff --git a/crypto/secp256k1/libsecp256k1/src/checkmem.h b/crypto/secp256k1/libsecp256k1/src/checkmem.h new file mode 100644 index 000000000..7e333ce5f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/checkmem.h @@ -0,0 +1,102 @@ +/*********************************************************************** + * Copyright (c) 2022 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* The code here is inspired by Kris Kwiatkowski's approach in + * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h + * to provide a general interface for memory-checking mechanisms, primarily + * for constant-time checking. + */ + +/* These macros are defined by this header file: + * + * - SECP256K1_CHECKMEM_ENABLED: + * - 1 if memory-checking integration is available, 0 otherwise. + * This is just a compile-time macro. Use the next macro to check it is actually + * available at runtime. + * - SECP256K1_CHECKMEM_RUNNING(): + * - Acts like a function call, returning 1 if memory checking is available + * at runtime. + * - SECP256K1_CHECKMEM_CHECK(p, len): + * - Assert or otherwise fail in case the len-byte memory block pointed to by p is + * not considered entirely defined. + * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len): + * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode. + * - SECP256K1_CHECKMEM_UNDEFINE(p, len): + * - marks the len-byte memory block pointed to by p as undefined data (secret data, + * in the context of constant-time checking). + * - SECP256K1_CHECKMEM_DEFINE(p, len): + * - marks the len-byte memory pointed to by p as defined data (public data, in the + * context of constant-time checking). + * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len): + * - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer. + * + */ + +#ifndef SECP256K1_CHECKMEM_H +#define SECP256K1_CHECKMEM_H + +/* Define a statement-like macro that ignores the arguments. */ +#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) + +/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan. + * Choose this preferentially, even when VALGRIND is defined, as msan-compiled + * binaries can't be run under valgrind anyway. */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (1) +# endif +#endif + +#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE +# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +/* If valgrind integration is desired (through the VALGRIND define), implement the + * SECP256K1_CHECKMEM_* macros using valgrind. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# if defined VALGRIND +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreserved-identifier" +# endif +# include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic pop +# endif +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len)) + /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck. + * This is more precise than the RUNNING_ON_VALGRIND macro, which + * checks for valgrind in general instead of memcheck specifically. */ +# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0) +# endif +#endif + +/* As a fall-back, map these macros to dummy statements. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# define SECP256K1_CHECKMEM_ENABLED 0 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (0) +#endif + +#if defined VERIFY +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len)) +#else +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +#endif /* SECP256K1_CHECKMEM_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ctime_tests.c b/crypto/secp256k1/libsecp256k1/src/ctime_tests.c new file mode 100644 index 000000000..f81bdb922 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/ctime_tests.c @@ -0,0 +1,267 @@ +/*********************************************************************** + * Copyright (c) 2020 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#include +#include +#include + +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "checkmem.h" + +#if !SECP256K1_CHECKMEM_ENABLED +# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" +#endif + +#ifdef ENABLE_MODULE_ECDH +# include "../include/secp256k1_ecdh.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "../include/secp256k1_recovery.h" +#endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "../include/secp256k1_extrakeys.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "../include/secp256k1_schnorrsig.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +#include "../include/secp256k1_musig.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +#include "../include/secp256k1_ellswift.h" +#endif + +static void run_tests(secp256k1_context *ctx, unsigned char *key); + +int main(void) { + secp256k1_context* ctx; + unsigned char key[32]; + int ret, i; + + if (!SECP256K1_CHECKMEM_RUNNING()) { + fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); + fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); + return EXIT_FAILURE; + } + ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); + /** In theory, testing with a single secret input should be sufficient: + * If control flow depended on secrets the tool would generate an error. + */ + for (i = 0; i < 32; i++) { + key[i] = i + 65; + } + + run_tests(ctx, key); + + /* Test context randomisation. Do this last because it leaves the context + * tainted. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_context_randomize(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + + secp256k1_context_destroy(ctx); + return EXIT_SUCCESS; +} + +static void run_tests(secp256k1_context *ctx, unsigned char *key) { + secp256k1_ecdsa_signature signature; + secp256k1_pubkey pubkey; + size_t siglen = 74; + size_t outputlen = 33; + int i; + int ret; + unsigned char msg[32]; + unsigned char sig[74]; + unsigned char spubkey[33]; +#ifdef ENABLE_MODULE_RECOVERY + secp256k1_ecdsa_recoverable_signature recoverable_signature; + int recid; +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + secp256k1_keypair keypair; +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + unsigned char ellswift[64]; + static const unsigned char prefix[64] = {'t', 'e', 's', 't'}; +#endif + + for (i = 0; i < 32; i++) { + msg[i] = i + 1; + } + + /* Test keygen. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); + SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + /* Test signing. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); + +#ifdef ENABLE_MODULE_ECDH + /* Test ECDH. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* Test signing a recoverable signature. */ + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); + SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); + CHECK(recid >= 0 && recid <= 3); +#endif + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_seckey_verify(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ec_seckey_negate(ctx, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); + ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* Test keypair_create and keypair_xonly_tweak_add. */ +#ifdef ENABLE_MODULE_EXTRAKEYS + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + /* The tweak is not treated as a secret in keypair_tweak_add */ + SECP256K1_CHECKMEM_DEFINE(msg, 32); + ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); + ret = secp256k1_keypair_sec(ctx, key, &keypair); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); +#endif + +#ifdef ENABLE_MODULE_MUSIG + { + secp256k1_pubkey pk; + const secp256k1_pubkey *pk_ptr[1]; + secp256k1_xonly_pubkey agg_pk; + unsigned char session_secrand[32]; + uint64_t nonrepeating_cnt = 0; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const secp256k1_musig_pubnonce *pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_keyagg_cache cache; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + unsigned char extra_input[32]; + + pk_ptr[0] = &pk; + pubnonce_ptr[0] = &pubnonce; + SECP256K1_CHECKMEM_DEFINE(key, 32); + memcpy(session_secrand, key, sizeof(session_secrand)); + session_secrand[0] = session_secrand[0] + 1; + memcpy(extra_input, key, sizeof(extra_input)); + extra_input[0] = extra_input[0] + 2; + + CHECK(secp256k1_keypair_create(ctx, &keypair, key)); + CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair)); + CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); + SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); + ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); + /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ + SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); + CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1); + + ret = secp256k1_keypair_create(ctx, &keypair, key); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + for (i = 0; i < 2; i++) { + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); + ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + } + +#endif +} diff --git a/crypto/secp256k1/libsecp256k1/src/ecdsa.h b/crypto/secp256k1/libsecp256k1/src/ecdsa.h index 54ae101b9..4441b0839 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecdsa.h +++ b/crypto/secp256k1/libsecp256k1/src/ecdsa.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECDSA_ -#define _SECP256K1_ECDSA_ +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H #include @@ -15,7 +15,7 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); +static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); -#endif +#endif /* SECP256K1_ECDSA_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h b/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h index 453bb1188..ce36e85e6 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h @@ -1,12 +1,12 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECDSA_IMPL_H_ -#define _SECP256K1_ECDSA_IMPL_H_ +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H #include "scalar.h" #include "field.h" @@ -16,17 +16,8 @@ #include "ecdsa.h" /** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 - * sage: for t in xrange(1023, -1, -1): - * .. p = 2**256 - 2**32 - t - * .. if p.is_prime(): - * .. print '%x'%p - * .. break - * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) - * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + * $ sage -c 'load("secp256k1_params.sage"); print(hex(N))' + * 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 */ static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, @@ -35,81 +26,81 @@ static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST /** Difference between field and order, values 'p' and 'n' values defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) - * '14551231950b75fc4402da1722fc9baee' + * $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))' + * 0x14551231950b75fc4402da1722fc9baee */ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { - int lenleft, b1; - size_t ret = 0; +static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) { + size_t lenleft; + unsigned char b1; + VERIFY_CHECK(len != NULL); + *len = 0; if (*sigp >= sigend) { - return -1; + return 0; } b1 = *((*sigp)++); if (b1 == 0xFF) { /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ - return -1; + return 0; } if ((b1 & 0x80) == 0) { /* X.690-0207 8.1.3.4 short form length octets */ - return b1; + *len = b1; + return 1; } if (b1 == 0x80) { /* Indefinite length is not allowed in DER. */ - return -1; + return 0; } /* X.690-207 8.1.3.5 long form length octets */ - lenleft = b1 & 0x7F; - if (lenleft > sigend - *sigp) { - return -1; + lenleft = b1 & 0x7F; /* lenleft is at least 1 */ + if (lenleft > (size_t)(sigend - *sigp)) { + return 0; } if (**sigp == 0) { /* Not the shortest possible length encoding. */ - return -1; + return 0; } - if ((size_t)lenleft > sizeof(size_t)) { + if (lenleft > sizeof(size_t)) { /* The resulting length would exceed the range of a size_t, so - * certainly longer than the passed array size. - */ - return -1; + * it is certainly longer than the passed array size. */ + return 0; } while (lenleft > 0) { - if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) { - } - ret = (ret << 8) | **sigp; - if (ret + lenleft > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. */ - return -1; - } + *len = (*len << 8) | **sigp; (*sigp)++; lenleft--; } - if (ret < 128) { + if (*len > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. + (Checking this is the responsibility of the caller but it + can't hurt do it here, too.) */ + return 0; + } + if (*len < 128) { /* Not the shortest possible length encoding. */ - return -1; + return 0; } - return ret; + return 1; } static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { int overflow = 0; unsigned char ra[32] = {0}; - int rlen; + size_t rlen; if (*sig == sigend || **sig != 0x02) { /* Not a primitive integer (X.690-0207 8.3.1). */ return 0; } (*sig)++; - rlen = secp256k1_der_read_len(sig, sigend); - if (rlen <= 0 || (*sig) + rlen > sigend) { + if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) { + return 0; + } + if (rlen == 0 || rlen > (size_t)(sigend - *sig)) { /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ return 0; } @@ -125,8 +116,11 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char /* Negative. */ overflow = 1; } - while (rlen > 0 && **sig == 0) { - /* Skip leading zero bytes */ + /* There is at most one leading zero byte: + * if there were two leading zero bytes, we would have failed and returned 0 + * because of excessive 0x00 padding already. */ + if (rlen > 0 && **sig == 0) { + /* Skip leading zero byte */ rlen--; (*sig)++; } @@ -134,7 +128,7 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char overflow = 1; } if (!overflow) { - memcpy(ra + 32 - rlen, *sig, rlen); + if (rlen) memcpy(ra + 32 - rlen, *sig, rlen); secp256k1_scalar_set_b32(r, ra, &overflow); } if (overflow) { @@ -146,18 +140,16 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { const unsigned char *sigend = sig + size; - int rlen; + size_t rlen; if (sig == sigend || *(sig++) != 0x30) { /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ return 0; } - rlen = secp256k1_der_read_len(&sig, sigend); - if (rlen < 0 || sig + rlen > sigend) { - /* Tuple exceeds bounds */ + if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) { return 0; } - if (sig + rlen != sigend) { - /* Garbage after tuple. */ + if (rlen != (size_t)(sigend - sig)) { + /* Tuple exceeds bounds or garage after tuple. */ return 0; } @@ -200,7 +192,7 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { +static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { unsigned char c[32]; secp256k1_scalar sn, u1, u2; #if !defined(EXHAUSTIVE_TEST_ORDER) @@ -217,7 +209,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar_mul(&u1, &sn, message); secp256k1_scalar_mul(&u2, &sn, sigr); secp256k1_gej_set_ge(&pubkeyj, pubkey); - secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); + secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); if (secp256k1_gej_is_infinity(&pr)) { return 0; } @@ -235,7 +227,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const } #else secp256k1_scalar_get_b32(c, sigr); - secp256k1_fe_set_b32(&xr, c); + /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */ + (void)secp256k1_fe_set_b32_limit(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), @@ -276,6 +269,7 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_ge r; secp256k1_scalar n; int overflow = 0; + int high; secp256k1_ecmult_gen(ctx, &rp, nonce); secp256k1_ge_set_gej(&r, &rp); @@ -283,15 +277,11 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); secp256k1_scalar_set_b32(sigr, b, &overflow); - /* These two conditions should be checked before calling */ - VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr)); - VERIFY_CHECK(overflow == 0); - if (recid) { /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. */ - *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + *recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y); } secp256k1_scalar_mul(&n, sigr, seckey); secp256k1_scalar_add(&n, &n, message); @@ -300,16 +290,15 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(sigs)) { - return 0; - } - if (secp256k1_scalar_is_high(sigs)) { - secp256k1_scalar_negate(sigs, sigs); - if (recid) { - *recid ^= 1; - } + high = secp256k1_scalar_is_high(sigs); + secp256k1_scalar_cond_negate(sigs, high); + if (recid) { + *recid ^= high; } - return 1; + /* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature. + * This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. + */ + return (int)(!secp256k1_scalar_is_zero(sigr)) & (int)(!secp256k1_scalar_is_zero(sigs)); } -#endif +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/eckey.h b/crypto/secp256k1/libsecp256k1/src/eckey.h index 42739a3be..d54d44c99 100644 --- a/crypto/secp256k1/libsecp256k1/src/eckey.h +++ b/crypto/secp256k1/libsecp256k1/src/eckey.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECKEY_ -#define _SECP256K1_ECKEY_ +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H #include @@ -18,8 +18,8 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak); -#endif +#endif /* SECP256K1_ECKEY_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/eckey_impl.h b/crypto/secp256k1/libsecp256k1/src/eckey_impl.h index ce38071ac..121966f8b 100644 --- a/crypto/secp256k1/libsecp256k1/src/eckey_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/eckey_impl.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECKEY_IMPL_H_ -#define _SECP256K1_ECKEY_IMPL_H_ +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H #include "eckey.h" @@ -15,16 +15,17 @@ #include "ecmult_gen.h" static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { - if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { secp256k1_fe x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); - } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { + return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); + } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { secp256k1_fe x, y; - if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { + if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) { return 0; } secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { return 0; } return secp256k1_ge_is_valid_var(elem); @@ -42,10 +43,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p secp256k1_fe_get_b32(&pub[1], &elem->x); if (compressed) { *size = 33; - pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; } else { *size = 65; - pub[0] = 0x04; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; secp256k1_fe_get_b32(&pub[33], &elem->y); } return 1; @@ -53,18 +54,13 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { secp256k1_scalar_add(key, key, tweak); - if (secp256k1_scalar_is_zero(key)) { - return 0; - } - return 1; + return !secp256k1_scalar_is_zero(key); } -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { +static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) { secp256k1_gej pt; - secp256k1_scalar one; secp256k1_gej_set_ge(&pt, key); - secp256k1_scalar_set_int(&one, 1); - secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); + secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak); if (secp256k1_gej_is_infinity(&pt)) { return 0; @@ -74,26 +70,23 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, } static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { - if (secp256k1_scalar_is_zero(tweak)) { - return 0; - } + int ret; + ret = !secp256k1_scalar_is_zero(tweak); secp256k1_scalar_mul(key, key, tweak); - return 1; + return ret; } -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { - secp256k1_scalar zero; +static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) { secp256k1_gej pt; if (secp256k1_scalar_is_zero(tweak)) { return 0; } - secp256k1_scalar_set_int(&zero, 0); secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); + secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero); secp256k1_ge_set_gej(key, &pt); return 1; } -#endif +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult.h b/crypto/secp256k1/libsecp256k1/src/ecmult.h index 20484134f..326a5eeb4 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult.h @@ -1,31 +1,61 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECMULT_ -#define _SECP256K1_ECMULT_ +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H -#include "num.h" #include "group.h" +#include "scalar.h" +#include "scratch.h" -typedef struct { - /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ -#ifdef USE_ENDOMORPHISM - secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#ifndef ECMULT_WINDOW_SIZE +# define ECMULT_WINDOW_SIZE 15 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value") +# endif #endif -} secp256k1_ecmult_context; -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb); -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE) +#endif + +/* No one will ever need more than a window size of 24. The code might + * be correct for larger values of ECMULT_WINDOW_SIZE but this is not + * tested. + * + * The following limitations are known, and there are probably more: + * If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect + * because the size of the memory object that we allocate (in bytes) + * will not fit in a size_t. + * If WINDOW_G > 31 and int has 32 bits, then the code is incorrect + * because certain expressions will overflow. + */ +#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24 +# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24]. +#endif + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1L << ((w)-2)) /** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); +static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); -#endif +typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data); + +/** + * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. + * Chooses the right algorithm for a given number of points and scratch space + * size. Resets and overwrites the given scratch space. If the points do not + * fit in the scratch space the algorithm is repeatedly run with batches of + * points. If no scratch space is given then a simple algorithm is used that + * simply multiplies the points with the corresponding scalars and adds them up. + * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) + * 0 if there is not enough scratch space for a single point or + * callback returns 0 + */ +static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n); + +#endif /* SECP256K1_ECMULT_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table.h b/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table.h new file mode 100644 index 000000000..665f87ff3 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table.h @@ -0,0 +1,16 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_H +#define SECP256K1_ECMULT_COMPUTE_TABLE_H + +/* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */ +static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen); + +/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen); + +#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table_impl.h new file mode 100644 index 000000000..69d59ce59 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_compute_table_impl.h @@ -0,0 +1,49 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H + +#include "ecmult_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "ecmult.h" +#include "util.h" + +static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) { + secp256k1_gej gj; + secp256k1_ge ge, dgen; + int j; + + gj = *gen; + secp256k1_ge_set_gej_var(&ge, &gj); + secp256k1_ge_to_storage(&table[0], &ge); + + secp256k1_gej_double_var(&gj, gen, NULL); + secp256k1_ge_set_gej_var(&dgen, &gj); + + for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) { + secp256k1_gej_set_ge(&gj, &ge); + secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL); + secp256k1_ge_set_gej_var(&ge, &gj); + secp256k1_ge_to_storage(&table[j], &ge); + } +} + +/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */ +static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen) { + secp256k1_gej gj; + int i; + + secp256k1_gej_set_ge(&gj, gen); + secp256k1_ecmult_compute_table(table, window_g, &gj); + for (i = 0; i < 128; ++i) { + secp256k1_gej_double_var(&gj, &gj, NULL); + } + secp256k1_ecmult_compute_table(table_128, window_g, &gj); +} + +#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_const.h b/crypto/secp256k1/libsecp256k1/src/ecmult_const.h index 2b0097655..080e04bc8 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_const.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_const.h @@ -1,15 +1,38 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECMULT_CONST_ -#define _SECP256K1_ECMULT_CONST_ +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H #include "scalar.h" #include "group.h" +/** + * Multiply: R = q*A (in constant-time for q) + */ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); -#endif +/** + * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point + * only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is + * returned. + * + * If known_on_curve is 0, a verification is performed that n/d is a valid X + * coordinate, and 0 is returned if not. Otherwise, 1 is returned. + * + * d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero. + * + * Constant time in the value of q, but not any other inputs. + */ +static int secp256k1_ecmult_const_xonly( + secp256k1_fe *r, + const secp256k1_fe *n, + const secp256k1_fe *d, + const secp256k1_scalar *q, + int known_on_curve +); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h index 0db314c48..0d78f7c3c 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h @@ -1,239 +1,399 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECMULT_CONST_IMPL_ -#define _SECP256K1_ECMULT_CONST_IMPL_ +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H #include "scalar.h" #include "group.h" #include "ecmult_const.h" #include "ecmult_impl.h" -#ifdef USE_ENDOMORPHISM - #define WNAF_BITS 128 +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because + * the tables cannot have infinities in them (this breaks the effective-affine technique's + * z-ratio tracking) */ +# if EXHAUSTIVE_TEST_ORDER == 199 +# define ECMULT_CONST_GROUP_SIZE 4 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define ECMULT_CONST_GROUP_SIZE 3 +# elif EXHAUSTIVE_TEST_ORDER == 7 +# define ECMULT_CONST_GROUP_SIZE 2 +# else +# error "Unknown EXHAUSTIVE_TEST_ORDER" +# endif #else - #define WNAF_BITS 256 +/* Group size 4 or 5 appears optimal. */ +# define ECMULT_CONST_GROUP_SIZE 5 #endif -#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) -/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ -#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ - int m; \ - int abs_n = (n) * (((n) > 0) * 2 - 1); \ - int idx_n = abs_n / 2; \ +#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1)) +#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE) +#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE) + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * The resulting point set is brought to a single constant Z denominator, stores the X and Y + * coordinates as ge points in pre, and stores the global Z in globalz. + * + * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE. + */ +static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE]; + + secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a); + secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr); +} + +/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point. + * + * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries: + * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its + * bits are interpreted as signs of powers of two to look up. + * + * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is + * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15], + * which means we just need to look up one of the precomputed values, and optionally negate it. + */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \ + unsigned int m = 0; \ + /* If the top bit of n is 0, we want the negation. */ \ + volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \ + /* Let n[i] be the i-th bit of n, then the index is + * sum(cnot(n[i]) * 2^i, i=0..l-2) + * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise. + * For example, if n = 4, in binary 0100, the index is 3, in binary 011. + * + * Proof: + * Let + * x = sum((2*n[i] - 1)*2^i, i=0..l-1) + * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1 + * be the value represented by n. + * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise. + * Case x > 0: + * n[l-1] = 1 + * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1) + * = sum(n[i] * 2^i, i=0..l-2) + * Case x <= 0: + * n[l-1] = 0 + * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2 + * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1) + * = sum((1 - n[i]) * 2^i, i=0..l-2) + */ \ + unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \ secp256k1_fe neg_y; \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ - for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ + VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ + /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one + * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ + (r)->x = (pre)[m].x; \ + (r)->y = (pre)[m].y; \ + for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ /* This loop is used to avoid secret data in array indices. See * the comment in ecmult_gen_impl.h for rationale. */ \ - secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ - secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ } \ (r)->infinity = 0; \ secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ - secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \ } while(0) +/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed + * formulas/constants. + * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */ +#ifdef EXHAUSTIVE_TEST_ORDER +static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER; +/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */ +#elif ECMULT_CONST_BITS == 129 +/* For GROUP_SIZE = 1,3. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul); +#elif ECMULT_CONST_BITS == 130 +/* For GROUP_SIZE = 2,5. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul); +#elif ECMULT_CONST_BITS == 132 +/* For GROUP_SIZE = 4,6 */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul); +#else +# error "Unknown ECMULT_CONST_BITS" +#endif -/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) - * with the following guarantees: - * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) - * - each wnaf[i] is nonzero - * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w - * - * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar - * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) - * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 - * - * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 - */ -static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { - int global_sign; - int skew = 0; - int word = 0; - - /* 1 2 3 */ - int u_last; - int u; - - int flip; - int bit; - secp256k1_scalar neg_s; - int not_neg_one; - /* Note that we cannot handle even numbers by negating them to be odd, as is - * done in other implementations, since if our scalars were specified to have - * width < 256 for performance reasons, their negations would have width 256 - * and we'd lose any performance benefit. Instead, we use a technique from - * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) - * or 2 (for odd) to the number we are encoding, returning a skew value indicating - * this, and having the caller compensate after doing the multiplication. */ - - /* Negative numbers will be negated to keep their bit representation below the maximum width */ - flip = secp256k1_scalar_is_high(&s); - /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ - bit = flip ^ !secp256k1_scalar_is_even(&s); - /* We check for negative one, since adding 2 to it will cause an overflow */ - secp256k1_scalar_negate(&neg_s, &s); - not_neg_one = !secp256k1_scalar_is_one(&neg_s); - secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); - /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects - * that we added two to it and flipped it. In fact for -1 these operations are - * identical. We only flipped, but since skewing is required (in the sense that - * the skew must be 1 or 2, never zero) and flipping is not, we need to change - * our flags to claim that we only skewed. */ - global_sign = secp256k1_scalar_cond_negate(&s, flip); - global_sign *= not_neg_one * 2 - 1; - skew = 1 << bit; - - /* 4 */ - u_last = secp256k1_scalar_shr_int(&s, w); - while (word * w < WNAF_BITS) { - int sign; - int even; - - /* 4.1 4.4 */ - u = secp256k1_scalar_shr_int(&s, w); - /* 4.2 */ - even = ((u & 1) == 0); - sign = 2 * (u_last > 0) - 1; - u += sign * even; - u_last -= sign * even * (1 << w); - - /* 4.3, adapted for global sign change */ - wnaf[word++] = u_last * global_sign; - - u_last = u; - } - wnaf[word] = u * global_sign; - - VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); - VERIFY_CHECK(word == WNAF_SIZE(w)); - return skew; -} - +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) { + /* The approach below combines the signed-digit logic from Mike Hamburg's + * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309) + * Section 3.3, with the GLV endomorphism. + * + * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a + * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n), + * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define: + * + * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * + * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A + * = (2*v + 1 - 2^l) * A + * + * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the + * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table. + * + * It is appealing to try to combine this with the GLV optimization: the idea that a scalar + * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that + * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the + * secp256k1_scalar_split_lambda function which performs such a split with the resulting s1 + * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting: + * + * To compute q*A: + * - Let s1, s2 = split_lambda(q) + * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A) + * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A) + * - Return R1 + R2 + * + * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n) + * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting. + * + * To make it work, we want to modify the input scalar q first, before splitting, and then only + * add a 2^128 offset of the split results (so that they end up in the single 129-bit range + * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick + * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to + * compute it from q: + * + * To compute q*A: + * - Compute s = f(q) + * - Let s1, s2 = split_lambda(s) + * - Let v1 = s1 + 2^128 (mod n) + * - Let v2 = s2 + 2^128 (mod n) + * - Let R1 = C_l(v1, A) + * - Let R2 = C_l(v2, lambda*A) + * - Return R1 + R2 + * + * l will thus need to be at least 129, but we may overshoot by a few bits (see + * further), so keep it as a variable. + * + * To solve for s, we reason: + * q*A = R1 + R2 + * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A) + * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A + * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A + * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n) + * <=> f(q) = (q + K) / 2 (mod n) + * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n) + * + * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of + * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE + * that is not less than 129; this equals ECMULT_CONST_BITS. + */ -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge tmpa; - secp256k1_fe Z; + /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */ + static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0); + secp256k1_scalar s, v1, v2; + secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE]; + secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE]; + secp256k1_fe global_z; + int group, i; - int skew_1; - int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; -#ifdef USE_ENDOMORPHISM - secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_lam; - secp256k1_scalar q_1, q_lam; -#endif + /* We're allowed to be non-constant time in the point, and the code below (in particular, + * secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a + * constant-time manner anyway. */ + if (secp256k1_ge_is_infinity(a)) { + secp256k1_gej_set_infinity(r); + return; + } - int i; - secp256k1_scalar sc = *scalar; + /* Compute v1 and v2. */ + secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K); + secp256k1_scalar_half(&s, &s); + secp256k1_scalar_split_lambda(&v1, &v2, &s); + secp256k1_scalar_add(&v1, &v1, &S_OFFSET); + secp256k1_scalar_add(&v2, &v2, &S_OFFSET); - /* build wnaf representation for q. */ -#ifdef USE_ENDOMORPHISM - /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); - skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); - skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); -#else - skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); +#ifdef VERIFY + /* Verify that v1 and v2 are in range [0, 2^129-1]. */ + for (i = 129; i < 256; ++i) { + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0); + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0); + } #endif - /* Calculate odd multiples of a. + /* Calculate odd multiples of A and A*lambda. * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * in global_z. Due to secp256k1' isomorphism we can do all operations pretending * that the Z coordinate was 1, use affine addition formulae, and correct * the Z coordinate of the result once at the end. */ secp256k1_gej_set_ge(r, a); - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_fe_normalize_weak(&pre_a[i].y); - } -#ifdef USE_ENDOMORPHISM - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r); + for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) { secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } -#endif - /* first loop iteration (separated out so we can directly set r, rather - * than having it start at infinity, get doubled several times, then have - * its new value added to it) */ - i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); - secp256k1_gej_set_ge(r, &tmpa); -#ifdef USE_ENDOMORPHISM - i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); -#endif - /* remaining loop iterations */ - for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { - int n; + /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A). + * + * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits + * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2). + * + * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal + * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2. + * This means that all we need to do is add these looked up values together, multiplied + * by 2^(ECMULT_GROUP_SIZE * group). + */ + for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) { + /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */ + unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + secp256k1_ge t; int j; - for (j = 0; j < WINDOW_A - 1; ++j) { - secp256k1_gej_double_nonzero(r, r, NULL); - } - n = wnaf_1[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - VERIFY_CHECK(n != 0); - secp256k1_gej_add_ge(r, r, &tmpa); -#ifdef USE_ENDOMORPHISM - n = wnaf_lam[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - VERIFY_CHECK(n != 0); - secp256k1_gej_add_ge(r, r, &tmpa); -#endif + ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1); + if (group == ECMULT_CONST_GROUPS - 1) { + /* Directly set r in the first iteration. */ + secp256k1_gej_set_ge(r, &t); + } else { + /* Shift the result so far up. */ + for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) { + secp256k1_gej_double(r, r); + } + secp256k1_gej_add_ge(r, r, &t); + } + ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2); + secp256k1_gej_add_ge(r, r, &t); } - secp256k1_fe_mul(&r->z, &r->z, &Z); + /* Map the result back to the secp256k1 curve from the isomorphic curve. */ + secp256k1_fe_mul(&r->z, &r->z, &global_z); +} - { - /* Correct for wNAF skew */ - secp256k1_ge correction = *a; - secp256k1_ge_storage correction_1_stor; -#ifdef USE_ENDOMORPHISM - secp256k1_ge_storage correction_lam_stor; -#endif - secp256k1_ge_storage a2_stor; - secp256k1_gej tmpj; - secp256k1_gej_set_ge(&tmpj, &correction); - secp256k1_gej_double_var(&tmpj, &tmpj, NULL); - secp256k1_ge_set_gej(&correction, &tmpj); - secp256k1_ge_to_storage(&correction_1_stor, a); -#ifdef USE_ENDOMORPHISM - secp256k1_ge_to_storage(&correction_lam_stor, a); -#endif - secp256k1_ge_to_storage(&a2_stor, &correction); +static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) { - /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ - secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); -#ifdef USE_ENDOMORPHISM - secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); -#endif + /* This algorithm is a generalization of Peter Dettman's technique for + * avoiding the square root in a random-basepoint x-only multiplication + * on a Weierstrass curve: + * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/ + * + * + * === Background: the effective affine technique === + * + * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to + * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as + * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as + * the curve b=7 coefficient does not appear in those formulas (or at least does not appear in + * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2 + * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf. + * + * This means any linear combination of secp256k1 points can be computed by applying phi_u + * (with non-zero u) on all input points (including the generator, if used), computing the + * linear combination on the isomorphic curve (using the same group laws), and then applying + * phi_u^{-1} to get back to secp256k1. + * + * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply + * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z + * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic + * curve where the affine addition formula can be used instead. + * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is + * (X3, Y3, Z3*Z). + * + * This is the effective affine technique: if we have a linear combination of group elements + * to compute, and all those group elements have the same Z coordinate, we can simply pretend + * that all those Z coordinates are 1, perform the computation that way, and then multiply the + * original Z coordinate back in. + * + * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to + * other curves too, but there the isomorphic curves will have different 'a' coefficients, + * which typically does affect the group laws. + * + * + * === Avoiding the square root for x-only point multiplication === + * + * In this function, we want to compute the X coordinate of q*(n/d, y), for + * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention + * we pick whatever sqrt returns (which we assume to be a deterministic function). + * + * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3). + * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2. + * + * The input point (n/d, y) also has Jacobian coordinates: + * + * (n/d, y, 1) + * = (n/d * v^2, y * v^3, v) + * = (n/d * d*g, y * sqrt(d^3*g^3), v) + * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v) + * = (n*g, sqrt(g/d^3 * d^3*g^3), v) + * = (n*g, sqrt(g^4), v) + * = (n*g, g^2, v) + * + * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X + * coordinate n/d, and this holds even when the square root function doesn't have a + * deterministic sign. We choose the (n*g, g^2, v) version. + * + * Now switch to the effective affine curve using phi_v, where the input point has coordinates + * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there. + * + * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X + * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve + * a square root, but as long as we only care about the resulting X coordinate, no square root + * is needed anywhere in this computation. + */ - /* Apply the correction */ - secp256k1_ge_from_storage(&correction, &correction_1_stor); - secp256k1_ge_neg(&correction, &correction); - secp256k1_gej_add_ge(r, r, &correction); + secp256k1_fe g, i; + secp256k1_ge p; + secp256k1_gej rj; -#ifdef USE_ENDOMORPHISM - secp256k1_ge_from_storage(&correction, &correction_lam_stor); - secp256k1_ge_neg(&correction, &correction); - secp256k1_ge_mul_lambda(&correction, &correction); - secp256k1_gej_add_ge(r, r, &correction); -#endif + /* Compute g = (n^3 + B*d^3). */ + secp256k1_fe_sqr(&g, n); + secp256k1_fe_mul(&g, &g, n); + if (d) { + secp256k1_fe b; + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d)); + secp256k1_fe_sqr(&b, d); + VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */ + secp256k1_fe_mul_int(&b, SECP256K1_B); + secp256k1_fe_mul(&b, &b, d); + secp256k1_fe_add(&g, &b); + if (!known_on_curve) { + /* We need to determine whether (n/d)^3 + 7 is square. + * + * is_square((n/d)^3 + 7) + * <=> is_square(((n/d)^3 + 7) * d^4) + * <=> is_square((n^3 + 7*d^3) * d) + * <=> is_square(g * d) + */ + secp256k1_fe c; + secp256k1_fe_mul(&c, &g, d); + if (!secp256k1_fe_is_square_var(&c)) return 0; + } + } else { + secp256k1_fe_add_int(&g, SECP256K1_B); + if (!known_on_curve) { + /* g at this point equals x^3 + 7. Test if it is square. */ + if (!secp256k1_fe_is_square_var(&g)) return 0; + } } + + /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has + * corresponding affine X coordinate n/d. */ + secp256k1_fe_mul(&p.x, &g, n); + secp256k1_fe_sqr(&p.y, &g); + p.infinity = 0; + + /* Perform x-only EC multiplication of P with q. */ + VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); + secp256k1_ecmult_const(&rj, &p, q); + VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj)); + + /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to + * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate + * (X / (Z^2*d*g)). */ + secp256k1_fe_sqr(&i, &rj.z); + secp256k1_fe_mul(&i, &i, &g); + if (d) secp256k1_fe_mul(&i, &i, d); + secp256k1_fe_inv(&i, &i); + secp256k1_fe_mul(r, &rj.x, &i); + + return 1; } -#endif +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_gen.h b/crypto/secp256k1/libsecp256k1/src/ecmult_gen.h index eb2cc9ead..43dd10c38 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_gen.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_gen.h @@ -1,43 +1,143 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_ -#define _SECP256K1_ECMULT_GEN_ +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H #include "scalar.h" #include "group.h" + +/* Configuration parameters for the signed-digit multi-comb algorithm: + * + * - COMB_BLOCKS is the number of blocks the input is split into. Each + * has a corresponding table. + * - COMB_TEETH is the number of bits simultaneously covered by one table. + * - COMB_RANGE is the number of bits in supported scalars. For production + * purposes, only 256 is reasonable, but smaller numbers are supported for + * exhaustive test mode. + * + * The comb's spacing (COMB_SPACING), or the distance between the teeth, + * is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers + * COMB_SPACING * COMB_TEETH consecutive bits in the input. + * + * The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1)) + * secp256k1_ge_storages. + * + * The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point + * addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a + * conditional negation. + * + * The number of point doublings is COMB_SPACING - 1. */ + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to control these values for exhaustive tests because + * the table cannot have infinities in them (secp256k1_ge_storage + * doesn't support infinities) */ +# undef COMB_BLOCKS +# undef COMB_TEETH +# if EXHAUSTIVE_TEST_ORDER == 7 +# define COMB_RANGE 3 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define COMB_RANGE 4 +# define COMB_BLOCKS 1 +# define COMB_TEETH 2 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define COMB_RANGE 8 +# define COMB_BLOCKS 2 +# define COMB_TEETH 3 +# else +# error "Unknown exhaustive test order" +# endif +# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1) +# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))" +# endif +#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ +# define COMB_RANGE 256 +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +/* Use (11, 6) as default configuration, which results in a 22 kB table. */ +#ifndef COMB_BLOCKS +# define COMB_BLOCKS 11 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value") +# endif +#endif +#ifndef COMB_TEETH +# define COMB_TEETH 6 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value") +# endif +#endif +/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */ +#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH) + +/* Range checks on the parameters. */ + +/* The remaining COMB_* parameters are derived values, don't modify these. */ +/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */ +#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING) +/* - The number of entries per table. */ +#define COMB_POINTS (1 << (COMB_TEETH - 1)) + +/* Sanity checks. */ +#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256) +# error "COMB_BLOCKS must be in the range [1, 256]" +#endif +#if !(1 <= COMB_TEETH && COMB_TEETH <= 8) +# error "COMB_TEETH must be in the range [1, 8]" +#endif +#if COMB_BITS < COMB_RANGE +# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low" +#endif + +/* These last 2 checks are not strictly required, but prevent gratuitously inefficient + * configurations. Note that they compare with 256 rather than COMB_RANGE, so they do + * permit somewhat excessive values for the exhaustive test case, where testing with + * suboptimal parameters may be desirable. */ +#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256 +# error "COMB_BLOCKS can be reduced" +#endif +#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256 +# error "COMB_TEETH can be reduced" +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(COMB_RANGE) +# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS) +# pragma message DEBUG_CONFIG_DEF(COMB_TEETH) +# pragma message DEBUG_CONFIG_DEF(COMB_SPACING) +#endif + typedef struct { - /* For accelerating the computation of a*G: - * To harden against timing attacks, use the following mechanism: - * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. - * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: - * * U_i = U * 2^i (for i=0..62) - * * U_i = U * (1-2^63) (for i=63) - * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. - * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is - * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). - * None of the resulting prec group elements have a known scalar, and neither do any of - * the intermediate sums while computing a*G. - */ - secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ - secp256k1_scalar blind; - secp256k1_gej initial; + /* Whether the context has been built. */ + int built; + + /* Values chosen such that + * + * n*G == comb(n + scalar_offset, G/2) + ge_offset. + * + * This expression lets us use scalar blinding and optimize the comb precomputation. See + * ecmult_gen_impl.h for more details. */ + secp256k1_scalar scalar_offset; + secp256k1_ge ge_offset; + + /* Factor used for projective blinding. This value is used to rescale the Z + * coordinate of the first table lookup. */ + secp256k1_fe proj_blind; } secp256k1_ecmult_gen_context; -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); /** Multiply with the generator: R = a*G */ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); -#endif +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table.h b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table.h new file mode 100644 index 000000000..bd41803a8 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table.h @@ -0,0 +1,14 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H +#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H + +#include "ecmult_gen.h" + +static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing); + +#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table_impl.h new file mode 100644 index 000000000..6aa8d8408 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_compute_table_impl.h @@ -0,0 +1,108 @@ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H +#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H + +#include "ecmult_gen_compute_table.h" +#include "group_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "ecmult_gen.h" +#include "util.h" + +static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) { + size_t points = ((size_t)1) << (teeth - 1); + size_t points_total = points * blocks; + secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec)); + secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds)); + secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs)); + secp256k1_gej u; + size_t vs_pos = 0; + secp256k1_scalar half; + int block, i; + + VERIFY_CHECK(points_total > 0); + + /* u is the running power of two times gen we're working with, initially gen/2. */ + secp256k1_scalar_half(&half, &secp256k1_scalar_one); + secp256k1_gej_set_infinity(&u); + for (i = 255; i >= 0; --i) { + /* Use a very simple multiplication ladder to avoid dependency on ecmult. */ + secp256k1_gej_double_var(&u, &u, NULL); + if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) { + secp256k1_gej_add_ge_var(&u, &u, gen, NULL); + } + } +#ifdef VERIFY + { + /* Verify that u*2 = gen. */ + secp256k1_gej double_u; + secp256k1_gej_double_var(&double_u, &u, NULL); + VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen)); + } +#endif + + for (block = 0; block < blocks; ++block) { + int tooth; + /* Here u = 2^(block*teeth*spacing) * gen/2. */ + secp256k1_gej sum; + secp256k1_gej_set_infinity(&sum); + for (tooth = 0; tooth < teeth; ++tooth) { + /* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */ + /* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */ + secp256k1_gej_add_var(&sum, &sum, &u, NULL); + /* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + secp256k1_gej_double_var(&u, &u, NULL); + /* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ + ds[tooth] = u; + /* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */ + if (block + tooth != blocks + teeth - 2) { + int bit_off; + for (bit_off = 1; bit_off < spacing; ++bit_off) { + secp256k1_gej_double_var(&u, &u, NULL); + } + } + } + /* Now u = 2^((block*teeth + teeth)*spacing) * gen/2 + * = 2^((block+1)*teeth*spacing) * gen/2 */ + + /* Next, compute the table entries for block number block in Jacobian coordinates. + * The entries will occupy vs[block*points + i] for i=0..points-1. + * We start by computing the first (i=0) value corresponding to all summed + * powers of two times G being negative. */ + secp256k1_gej_neg(&vs[vs_pos++], &sum); + /* And then teeth-1 times "double" the range of i values for which the table + * is computed: in each iteration, double the table by taking an existing + * table entry and adding ds[tooth]. */ + for (tooth = 0; tooth < teeth - 1; ++tooth) { + size_t stride = ((size_t)1) << tooth; + size_t index; + for (index = 0; index < stride; ++index, ++vs_pos) { + secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL); + } + } + } + VERIFY_CHECK(vs_pos == points_total); + + /* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */ + secp256k1_ge_set_all_gej_var(prec, vs, points_total); + /* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */ + for (block = 0; block < blocks; ++block) { + size_t index; + for (index = 0; index < points; ++index) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index])); + secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]); + } + } + + /* Free memory. */ + free(vs); + free(ds); + free(prec); +} + +#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h index 35f254607..070a12130 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h @@ -1,140 +1,239 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_ -#define _SECP256K1_ECMULT_GEN_IMPL_H_ +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H +#include "util.h" #include "scalar.h" #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" -#ifdef USE_ECMULT_STATIC_PRECOMPUTATION -#include "ecmult_static_context.h" -#endif -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { - ctx->prec = NULL; -} - -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - secp256k1_ge prec[1024]; - secp256k1_gej gj; - secp256k1_gej nums_gej; - int i, j; -#endif - - if (ctx->prec != NULL) { - return; - } -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); - - /* get the generator */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - - /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ - { - static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe nums_x; - secp256k1_ge nums_ge; - int r; - r = secp256k1_fe_set_b32(&nums_x, nums_b32); - (void)r; - VERIFY_CHECK(r); - r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); - (void)r; - VERIFY_CHECK(r); - secp256k1_gej_set_ge(&nums_gej, &nums_ge); - /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); - } +#include "precomputed_ecmult_gen.h" - /* compute prec. */ - { - secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej gbase; - secp256k1_gej numsbase; - gbase = gj; /* 16^j * G */ - numsbase = nums_gej; /* 2^j * nums. */ - for (j = 0; j < 64; j++) { - /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ - precj[j*16] = numsbase; - for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); - } - /* Multiply gbase by 16. */ - for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase, NULL); - } - /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase, NULL); - if (j == 62) { - /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ - secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); - } - } - secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); - } - for (j = 0; j < 64; j++) { - for (i = 0; i < 16; i++) { - secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); - } - } -#else - (void)cb; - ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; -#endif +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) { secp256k1_ecmult_gen_blind(ctx, NULL); + ctx->built = 1; } static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { - return ctx->prec != NULL; + return ctx->built; } -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { - if (src->prec == NULL) { - dst->prec = NULL; - } else { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); - memcpy(dst->prec, src->prec, sizeof(*dst->prec)); -#else - (void)cb; - dst->prec = src->prec; -#endif - dst->initial = src->initial; - dst->blind = src->blind; - } +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { + ctx->built = 0; + secp256k1_scalar_clear(&ctx->scalar_offset); + secp256k1_ge_clear(&ctx->ge_offset); + secp256k1_fe_clear(&ctx->proj_blind); } -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - free(ctx->prec); -#endif - secp256k1_scalar_clear(&ctx->blind); - secp256k1_gej_clear(&ctx->initial); - ctx->prec = NULL; +/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to + * secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn + * from (before applying blinding). */ +static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) { + int i; + + /* Compute scalar -1/2. */ + secp256k1_scalar neghalf; + secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one); + secp256k1_scalar_negate(&neghalf, &neghalf); + + /* Compute offset = 2^(COMB_BITS - 1). */ + *diff = secp256k1_scalar_one; + for (i = 0; i < COMB_BITS - 1; ++i) { + secp256k1_scalar_add(diff, diff, diff); + } + + /* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */ + secp256k1_scalar_add(diff, diff, &neghalf); } static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + uint32_t comb_off; secp256k1_ge add; + secp256k1_fe neg; secp256k1_ge_storage adds; - secp256k1_scalar gnb; - int bits; - int i, j; + secp256k1_scalar d; + /* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom + * 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256 + * avoids the need to deal with out-of-bounds reads from a scalar. */ + uint32_t recoded[(COMB_BITS + 31) >> 5] = {0}; + int first = 1, i; + memset(&adds, 0, sizeof(adds)); - *r = ctx->initial; - /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ - secp256k1_scalar_add(&gnb, gn, &ctx->blind); - add.infinity = 0; - for (j = 0; j < 64; j++) { - bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); - for (i = 0; i < 16; i++) { + + /* We want to compute R = gn*G. + * + * To blind the scalar used in the computation, we rewrite this to be + * R = (gn - b)*G + b*G, with a blinding value b determined by the context. + * + * The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section + * 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg, + * https://eprint.iacr.org/2012/309). + * + * Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of + * the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0) + * or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are + * covered. By manipulating: + * + * comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1) + * <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P + * <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P + * <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P + * + * If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that + * + * (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G + * <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order) + * + * We use an alternative here that avoids the modular division by two: instead we compute + * (gn-b)*G as comb(d, G/2). For that to hold it must be the case that + * + * (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2) + * <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order) + * + * Adding precomputation, our final equations become: + * + * ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order) + * ctx->ge_offset = b*G + * d = gn + ctx->scalar_offset (mod order) + * R = comb(d, G/2) + ctx->ge_offset + * + * comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1, + * depending on the value of the bits d[i] of the binary representation of scalar d. + */ + + /* Compute the scalar d = (gn + ctx->scalar_offset). */ + secp256k1_scalar_add(&d, &ctx->scalar_offset, gn); + /* Convert to recoded array. */ + for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) { + recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32); + } + secp256k1_scalar_clear(&d); + + /* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the + * (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions. + * We rewrite our equation in terms of these table entries. + * + * Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1), + * with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11, + * COMB_TEETH=6, COMB_SPACING=4, we would have: + * mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20, + * mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44, + * mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68, + * ... + * mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260 + * + * We will split up the bits d[i] using these masks. Specifically, each mask is + * used COMB_SPACING times, with different shifts: + * + * d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) + + * (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) + + * ... + * (d & mask(0)<<(COMB_SPACING-1)) + ... + * + * Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for + * b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on + * 2^COMB_TEETH distinct values). + * + * If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i + * iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68) + * would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2. + * + * With that, we can rewrite comb(d, G/2) as: + * + * 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1))) + * + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1))) + * + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1))) + * + ... + * + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...) + * + * Or more generically as + * + * sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1) + * + * This is implemented using an outer loop that runs in reverse order over the lines of this + * equation, which in each iteration runs an inner loop that adds the terms of that line and + * then doubles the result before proceeding to the next line. + * + * In pseudocode: + * c = infinity + * for comb_off in range(COMB_SPACING - 1, -1, -1): + * for block in range(COMB_BLOCKS): + * c += table(block, (d >> comb_off) & mask(block)) + * if comb_off > 0: + * c = 2*c + * return c + * + * This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would + * be possible to apply an initial offset instead of a final offset (moving ge_offset to take + * the place of infinity above), but the chosen approach allows using (in a future improvement) + * an incomplete addition formula for most of the multiplication. + * + * The last question is how to implement the table(b, m) function. For any value of b, + * m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have + * fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables + * which contain a value for each such m value. + * + * Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating + * the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) = + * (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m). + * Because of this it suffices to only store the first half of the m values for every b. If an + * entry from the second half is needed, we look up its bit-flipped version instead, and negate + * it. + * + * secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index + * is the relevant mask(b) bits of m packed together without gaps. */ + + /* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */ + comb_off = COMB_SPACING - 1; + while (1) { + uint32_t block; + uint32_t bit_pos = comb_off; + /* Inner loop: for each block, add table entries to the result. */ + for (block = 0; block < COMB_BLOCKS; ++block) { + /* Gather the mask(block)-selected bits of d into bits. They're packed: + * bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */ + uint32_t bits = 0, sign, abs, index, tooth; + /* Instead of reading individual bits here to construct the bits variable, + * build up the result by xoring rotated reads together. In every iteration, + * one additional bit is made correct, starting at the bottom. The bits + * above that contain junk. This reduces leakage by avoiding computations + * on variables that can have only a low number of possible values (e.g., + * just two values when reading a single bit into a variable.) See: + * https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf + */ + for (tooth = 0; tooth < COMB_TEETH; ++tooth) { + /* Construct bitdata s.t. the bottom bit is the bit we'd like to read. + * + * We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f) + * but this would simply discard the bits that fall off at the bottom, + * and thus, for example, bitdata could still have only two values if we + * happen to shift by exactly 31 positions. We use a rotation instead, + * which ensures that bitdata doesn't loose entropy. This relies on the + * rotation being atomic, i.e., the compiler emitting an actual rot + * instruction. */ + uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f); + + /* Clear the bit at position tooth, but sssh, don't tell clang. */ + uint32_t volatile vmask = ~(1 << tooth); + bits &= vmask; + + /* Write the bit into position tooth (and junk into higher bits). */ + bits ^= bitdata << tooth; + bit_pos += COMB_SPACING; + } + + /* If the top bit of bits is 1, flip them all (corresponding to looking up + * the negated table value), and remember to negate the result in sign. */ + sign = (bits >> (COMB_TEETH - 1)) & 1; + abs = (bits ^ -sign) & (COMB_POINTS - 1); + VERIFY_CHECK(sign == 0 || sign == 1); + VERIFY_CHECK(abs < COMB_POINTS); + /** This uses a conditional move to avoid any secret data in array indexes. * _Any_ use of secret indexes has been demonstrated to result in timing * sidechannels, even when the cache-line access patterns are uniform. @@ -143,68 +242,100 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25 * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, * by Dag Arne Osvik, Adi Shamir, and Eran Tromer - * (http://www.tau.ac.il/~tromer/papers/cache.pdf) + * (https://www.tau.ac.il/~tromer/papers/cache.pdf) */ - secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); + for (index = 0; index < COMB_POINTS; ++index) { + secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs); + } + + /* Set add=adds or add=-adds, in constant time, based on sign. */ + secp256k1_ge_from_storage(&add, &adds); + secp256k1_fe_negate(&neg, &add.y, 1); + secp256k1_fe_cmov(&add.y, &neg, sign); + + /* Add the looked up and conditionally negated value to r. */ + if (EXPECT(first, 0)) { + /* If this is the first table lookup, we can skip addition. */ + secp256k1_gej_set_ge(r, &add); + /* Give the entry a random Z coordinate to blind intermediary results. */ + secp256k1_gej_rescale(r, &ctx->proj_blind); + first = 0; + } else { + secp256k1_gej_add_ge(r, r, &add); + } } - secp256k1_ge_from_storage(&add, &adds); - secp256k1_gej_add_ge(r, r, &add); + + /* Double the result, except in the last iteration. */ + if (comb_off-- == 0) break; + secp256k1_gej_double(r, r); } - bits = 0; + + /* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was + * subtracted from the input scalar gn). */ + secp256k1_gej_add_ge(r, r, &ctx->ge_offset); + + /* Cleanup. */ + secp256k1_fe_clear(&neg); secp256k1_ge_clear(&add); - secp256k1_scalar_clear(&gnb); + secp256k1_memclear(&adds, sizeof(adds)); + secp256k1_memclear(&recoded, sizeof(recoded)); } /* Setup blinding values for secp256k1_ecmult_gen. */ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { secp256k1_scalar b; + secp256k1_scalar diff; secp256k1_gej gb; - secp256k1_fe s; + secp256k1_fe f; unsigned char nonce32[32]; - secp256k1_rfc6979_hmac_sha256_t rng; - int retry; - unsigned char keydata[64] = {0}; + secp256k1_rfc6979_hmac_sha256 rng; + unsigned char keydata[64]; + + /* Compute the (2^COMB_BITS - 1)/2 term once. */ + secp256k1_ecmult_gen_scalar_diff(&diff); + if (seed32 == NULL) { - /* When seed is NULL, reset the initial point and blinding value. */ - secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); - secp256k1_gej_neg(&ctx->initial, &ctx->initial); - secp256k1_scalar_set_int(&ctx->blind, 1); + /* When seed is NULL, reset the final point and blinding value. */ + secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g); + secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff); + ctx->proj_blind = secp256k1_fe_one; + return; } /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ - secp256k1_scalar_get_b32(nonce32, &ctx->blind); + secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset); /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ - memcpy(keydata, nonce32, 32); - if (seed32 != NULL) { - memcpy(keydata + 32, seed32, 32); - } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); - memset(keydata, 0, sizeof(keydata)); - /* Retry for out of range results to achieve uniformity. */ - do { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - retry = !secp256k1_fe_set_b32(&s, nonce32); - retry |= secp256k1_fe_is_zero(&s); - } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ - /* Randomize the projection to defend against multiplier sidechannels. */ - secp256k1_gej_rescale(&ctx->initial, &s); - secp256k1_fe_clear(&s); - do { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - secp256k1_scalar_set_b32(&b, nonce32, &retry); - /* A blinding value of 0 works, but would undermine the projection hardening. */ - retry |= secp256k1_scalar_is_zero(&b); - } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ + VERIFY_CHECK(seed32 != NULL); + memcpy(keydata + 32, seed32, 32); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); + secp256k1_memclear(keydata, sizeof(keydata)); + + /* Compute projective blinding factor (cannot be 0). */ + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_fe_set_b32_mod(&f, nonce32); + secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f)); + ctx->proj_blind = f; + + /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_scalar_set_b32(&b, nonce32, NULL); + /* The blinding value cannot be zero, as that would mean ge_offset = infinity, + * which secp256k1_gej_add_ge cannot handle. */ + secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); secp256k1_rfc6979_hmac_sha256_finalize(&rng); - memset(nonce32, 0, 32); secp256k1_ecmult_gen(ctx, &gb, &b); secp256k1_scalar_negate(&b, &b); - ctx->blind = b; - ctx->initial = gb; + secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff); + secp256k1_ge_set_gej(&ctx->ge_offset, &gb); + + /* Clean up. */ + secp256k1_memclear(nonce32, sizeof(nonce32)); secp256k1_scalar_clear(&b); secp256k1_gej_clear(&gb); + secp256k1_fe_clear(&f); + secp256k1_rfc6979_hmac_sha256_clear(&rng); } -#endif +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h index 4e40104ad..0b53b3fcb 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h @@ -1,17 +1,20 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/****************************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + ******************************************************************************/ -#ifndef _SECP256K1_ECMULT_IMPL_H_ -#define _SECP256K1_ECMULT_IMPL_H_ +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H #include +#include +#include "util.h" #include "group.h" #include "scalar.h" #include "ecmult.h" +#include "precomputed_ecmult.h" #if defined(EXHAUSTIVE_TEST_ORDER) /* We need to lower these values for exhaustive tests because @@ -19,39 +22,57 @@ * affine-isomorphism stuff which tracks z-ratios) */ # if EXHAUSTIVE_TEST_ORDER > 128 # define WINDOW_A 5 -# define WINDOW_G 8 # elif EXHAUSTIVE_TEST_ORDER > 8 # define WINDOW_A 4 -# define WINDOW_G 4 # else # define WINDOW_A 2 -# define WINDOW_G 2 # endif #else /* optimal for 128-bit and 256-bit exponents. */ -#define WINDOW_A 5 -/** larger numbers may result in slightly better performance, at the cost of - exponentially larger precomputed tables. */ -#ifdef USE_ENDOMORPHISM -/** Two tables for window size 15: 1.375 MiB. */ -#define WINDOW_G 15 -#else -/** One table for window size 16: 1.375 MiB. */ -#define WINDOW_G 16 -#endif +# define WINDOW_A 5 +/** Larger values for ECMULT_WINDOW_SIZE result in possibly better + * performance at the cost of an exponentially larger precomputed + * table. The exact table size is + * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes, + * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can + * be larger due to platform-specific padding and alignment. + * Two tables of this size are used (due to the endomorphism + * optimization). + */ #endif -/** The number of entries a table with precomputed multiples needs to have. */ -#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) +#define WNAF_BITS 128 +#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w) +#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) + +/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ +#define PIPPENGER_SCRATCH_OBJECTS 6 +#define STRAUSS_SCRATCH_OBJECTS 5 + +#define PIPPENGER_MAX_BUCKET_WINDOW 12 + +/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ +#define ECMULT_PIPPENGER_THRESHOLD 88 + +#define ECMULT_MAX_POINTS_PER_BATCH 5000000 -/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain - * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will - * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. - * Prej's Z values are undefined, except for the last value. +/** Fill a table 'pre_a' with precomputed odd multiples of a. + * pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements. + * zr needs space for n field elements. + * + * Although pre_a is an array of _ge rather than _gej, it actually represents elements + * in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates + * can be recovered using z and zr. Using the notation z(b) to represent the omitted + * z coordinate of b: + * - z(pre_a[n-1]) = 'z' + * - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0 + * + * Lastly the zr[0] value, which isn't used above, is set so that: + * - a.z = z(pre_a[0]) / zr[0] */ -static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { - secp256k1_gej d; - secp256k1_ge a_ge, d_ge; +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) { + secp256k1_gej d, ai; + secp256k1_ge d_ge; int i; VERIFY_CHECK(!a->infinity); @@ -59,170 +80,76 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, sec secp256k1_gej_double_var(&d, a, NULL); /* - * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate - * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + * Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z. + * The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve. + * In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C). + * + * phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C) + * d_ge := phi(d) = (d.x, d.y, 1) + * ai := phi(a) = (a.x*C^2, a.y*C^3, a.z) + * + * The group addition functions work correctly on these isomorphic curves. + * In particular phi(d) is easy to represent in affine coordinates under this isomorphism. + * This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise. */ - d_ge.x = d.x; - d_ge.y = d.y; - d_ge.infinity = 0; - - secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); - prej[0].x = a_ge.x; - prej[0].y = a_ge.y; - prej[0].z = a->z; - prej[0].infinity = 0; + secp256k1_ge_set_xy(&d_ge, &d.x, &d.y); + secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z); + secp256k1_gej_set_ge(&ai, &pre_a[0]); + ai.z = a->z; + /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a. + * Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z. + */ zr[0] = d.z; + for (i = 1; i < n; i++) { - secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]); + secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y); } - /* - * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only - * the final point's z coordinate is actually used though, so just update that. + /* Multiply the last z-coordinate by C to undo the isomorphism. + * Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios, + * undoing the isomorphism here undoes the isomorphism for all pre_a values. */ - secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); + secp256k1_fe_mul(z, &ai.z, &d.z); } -/** Fill a table 'pre' with precomputed odd multiples of a. - * - * There are two versions of this function: - * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its - * resulting point set to a single constant Z denominator, stores the X and Y - * coordinates as ge_storage points in pre, and stores the global Z in rz. - * It only operates on tables sized for WINDOW_A wnaf multiples. - * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its - * resulting point set to actually affine points, and stores those in pre. - * It operates on tables of any size, but uses heap-allocated temporaries. - * - * To compute a*P + b*G, we compute a table for P using the first function, - * and for G using the second (which requires an inverse, but it only needs to - * happen once). - */ -static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { - secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; - - /* Compute the odd multiples in Jacobian form. */ - secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); - /* Bring them to the same Z denominator. */ - secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); +SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) { + (void)n; + (void)w; + VERIFY_CHECK(((n) & 1) == 1); + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); } -static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { - secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); - secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); - secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); - int i; - - /* Compute the odd multiples in Jacobian form. */ - secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); - /* Convert them in batch to affine coordinates. */ - secp256k1_ge_set_table_gej_var(prea, prej, zr, n); - /* Convert them to compact storage form. */ - for (i = 0; i < n; i++) { - secp256k1_ge_to_storage(&pre[i], &prea[i]); +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + *r = pre[(n-1)/2]; + } else { + *r = pre[(-n-1)/2]; + secp256k1_fe_negate(&(r->y), &(r->y), 1); } - - free(prea); - free(prej); - free(zr); -} - -/** The following two macro retrieves a particular odd multiple from a table - * of precomputed multiples. */ -#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) { \ - *(r) = (pre)[((n)-1)/2]; \ - } else { \ - secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ - } \ -} while(0) - -#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) { \ - secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ - } else { \ - secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ - secp256k1_ge_neg((r), (r)); \ - } \ -} while(0) - -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { - ctx->pre_g = NULL; -#ifdef USE_ENDOMORPHISM - ctx->pre_g_128 = NULL; -#endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { - secp256k1_gej gj; - - if (ctx->pre_g != NULL) { - return; - } - - /* get the generator */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - - ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); - - /* precompute the tables with odd multiples */ - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); - -#ifdef USE_ENDOMORPHISM - { - secp256k1_gej g_128j; - int i; - - ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); - - /* calculate 2^128*generator */ - g_128j = gj; - for (i = 0; i < 128; i++) { - secp256k1_gej_double_var(&g_128j, &g_128j, NULL); - } - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y); + } else { + secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y); + secp256k1_fe_negate(&(r->y), &(r->y), 1); } -#endif } -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { - if (src->pre_g == NULL) { - dst->pre_g = NULL; - } else { - size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g, src->pre_g, size); - } -#ifdef USE_ENDOMORPHISM - if (src->pre_g_128 == NULL) { - dst->pre_g_128 = NULL; +SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) { + secp256k1_ecmult_table_verify(n,w); + if (n > 0) { + secp256k1_ge_from_storage(r, &pre[(n-1)/2]); } else { - size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g_128, src->pre_g_128, size); + secp256k1_ge_from_storage(r, &pre[(-n-1)/2]); + secp256k1_fe_negate(&(r->y), &(r->y), 1); } -#endif -} - -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { - return ctx->pre_g != NULL; -} - -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { - free(ctx->pre_g); -#ifdef USE_ENDOMORPHISM - free(ctx->pre_g_128); -#endif - secp256k1_ecmult_context_init(ctx); } /** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), @@ -233,7 +160,7 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { * than the number of bits in the (absolute value) of the input. */ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { - secp256k1_scalar s = *a; + secp256k1_scalar s; int last_set_bit = -1; int bit = 0; int sign = 1; @@ -244,17 +171,21 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, VERIFY_CHECK(a != NULL); VERIFY_CHECK(2 <= w && w <= 31); - memset(wnaf, 0, len * sizeof(wnaf[0])); + for (bit = 0; bit < len; bit++) { + wnaf[bit] = 0; + } - if (secp256k1_scalar_get_bits(&s, 255, 1)) { + s = *a; + if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) { secp256k1_scalar_negate(&s, &s); sign = -1; } + bit = 0; while (bit < len) { int now; int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { + if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } @@ -275,127 +206,139 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, bit += now; } #ifdef VERIFY - CHECK(carry == 0); - while (bit < 256) { - CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); - } + { + int verify_bit = bit; + + VERIFY_CHECK(carry == 0); + + while (verify_bit < 256) { + VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0); + verify_bit++; + } + } #endif return last_set_bit + 1; } -static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; +struct secp256k1_strauss_point_state { + int wnaf_na_1[129]; + int wnaf_na_lam[129]; + int bits_na_1; + int bits_na_lam; +}; + +struct secp256k1_strauss_state { + /* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */ + secp256k1_fe* aux; + secp256k1_ge* pre_a; + struct secp256k1_strauss_point_state* ps; +}; + +static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *state, secp256k1_gej *r, size_t num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { secp256k1_ge tmpa; secp256k1_fe Z; -#ifdef USE_ENDOMORPHISM - secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar na_1, na_lam; - /* Splitted G factors. */ + /* Split G factors. */ secp256k1_scalar ng_1, ng_128; - int wnaf_na_1[130]; - int wnaf_na_lam[130]; - int bits_na_1; - int bits_na_lam; int wnaf_ng_1[129]; - int bits_ng_1; + int bits_ng_1 = 0; int wnaf_ng_128[129]; - int bits_ng_128; -#else - int wnaf_na[256]; - int bits_na; - int wnaf_ng[256]; - int bits_ng; -#endif + int bits_ng_128 = 0; int i; - int bits; + int bits = 0; + size_t np; + size_t no = 0; + + secp256k1_fe_set_int(&Z, 1); + for (np = 0; np < num; ++np) { + secp256k1_gej tmp; + secp256k1_scalar na_1, na_lam; + if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) { + continue; + } + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]); + + /* build wnaf representation for na_1 and na_lam. */ + state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); + if (state->ps[no].bits_na_1 > bits) { + bits = state->ps[no].bits_na_1; + } + if (state->ps[no].bits_na_lam > bits) { + bits = state->ps[no].bits_na_lam; + } -#ifdef USE_ENDOMORPHISM - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&na_1, &na_lam, na); + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + tmp = a[np]; + if (no) { + secp256k1_gej_rescale(&tmp, &Z); + } + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); + if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z)); - /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); - VERIFY_CHECK(bits_na_1 <= 130); - VERIFY_CHECK(bits_na_lam <= 130); - bits = bits_na_1; - if (bits_na_lam > bits) { - bits = bits_na_lam; + ++no; } -#else - /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); - bits = bits_na; -#endif - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - * The exception is the precomputed G table points, which are actually - * affine. Compared to the base used for other points, they have a Z ratio - * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same - * isomorphism to efficiently add with a known Z inverse. - */ - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); + /* Bring them to the same Z denominator. */ + if (no) { + secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux); + } -#ifdef USE_ENDOMORPHISM - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + for (np = 0; np < no; ++np) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta); + } } - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + if (ng) { + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_scalar_split_128(&ng_1, &ng_128, ng); - /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) { - bits = bits_ng_1; - } - if (bits_ng_128 > bits) { - bits = bits_ng_128; - } -#else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); - if (bits_ng > bits) { - bits = bits_ng; + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } } -#endif secp256k1_gej_set_infinity(r); for (i = bits - 1; i >= 0; i--) { int n; secp256k1_gej_double_var(r, r, NULL); -#ifdef USE_ENDOMORPHISM - if (i < bits_na_1 && (n = wnaf_na_1[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_na_lam && (n = wnaf_na_lam[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { + secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { + secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } } if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G); secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); + secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G); secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } -#else - if (i < bits_na && (n = wnaf_na[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#endif } if (!r->infinity) { @@ -403,4 +346,508 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej } } -#endif +static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + struct secp256k1_strauss_point_state ps[1]; + struct secp256k1_strauss_state state; + + state.aux = aux; + state.pre_a = pre_a; + state.ps = ps; + secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng); +} + +static size_t secp256k1_strauss_scratch_size(size_t n_points) { + static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); + return n_points*point_size; +} + +static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + secp256k1_gej* points; + secp256k1_scalar* scalars; + struct secp256k1_strauss_state state; + size_t i; + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + + /* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these + * allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS + * constant and strauss_scratch_size accordingly. */ + points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej)); + scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); + state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); + state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); + state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); + + if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + for (i = 0; i < n_points; i++) { + secp256k1_ge point; + if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + secp256k1_gej_set_ge(&points[i], &point); + } + secp256k1_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for secp256k1_ecmult_multi_func interface */ +static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { + return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); +} + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) + * - the number of words set is always WNAF_SIZE(w) + * - the returned skew is 0 or 1 + */ +static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) { + int skew = 0; + int pos; + int max_pos; + int last_w; + const secp256k1_scalar *work = s; + + if (secp256k1_scalar_is_zero(s)) { + for (pos = 0; pos < WNAF_SIZE(w); pos++) { + wnaf[pos] = 0; + } + return 0; + } + + if (secp256k1_scalar_is_even(s)) { + skew = 1; + } + + wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew; + /* Compute last window size. Relevant when window size doesn't divide the + * number of bits in the scalar */ + last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; + + /* Store the position of the first nonzero word in max_pos to allow + * skipping leading zeros when calculating the wnaf. */ + for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if(val != 0) { + break; + } + wnaf[pos] = 0; + } + max_pos = pos; + pos = 1; + + while (pos <= max_pos) { + int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if ((val & 1) == 0) { + wnaf[pos - 1] -= (1 << w); + wnaf[pos] = (val + 1); + } else { + wnaf[pos] = val; + } + /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit + * is strictly negative or strictly positive respectively. Only change + * coefficients at previous positions because above code assumes that + * wnaf[pos - 1] is odd. + */ + if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { + if (wnaf[pos - 1] == 1) { + wnaf[pos - 2] += 1 << w; + } else { + wnaf[pos - 2] -= 1 << w; + } + wnaf[pos - 1] = 0; + } + ++pos; + } + + return skew; +} + +struct secp256k1_pippenger_point_state { + int skew_na; + size_t input_pos; +}; + +struct secp256k1_pippenger_state { + int *wnaf_na; + struct secp256k1_pippenger_point_state* ps; +}; + +/* + * pippenger_wnaf computes the result of a multi-point multiplication as + * follows: The scalars are brought into wnaf with n_wnaf elements each. Then + * for every i < n_wnaf, first each point is added to a "bucket" corresponding + * to the point's wnaf[i]. Second, the buckets are added together such that + * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... + */ +static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) { + size_t n_wnaf = WNAF_SIZE(bucket_window+1); + size_t np; + size_t no = 0; + int i; + int j; + + for (np = 0; np < num; ++np) { + if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) { + continue; + } + state->ps[no].input_pos = np; + state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); + no++; + } + secp256k1_gej_set_infinity(r); + + if (no == 0) { + return 1; + } + + for (i = n_wnaf - 1; i >= 0; i--) { + secp256k1_gej running_sum; + + for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { + secp256k1_gej_set_infinity(&buckets[j]); + } + + for (np = 0; np < no; ++np) { + int n = state->wnaf_na[np*n_wnaf + i]; + struct secp256k1_pippenger_point_state point_state = state->ps[np]; + secp256k1_ge tmp; + int idx; + + if (i == 0) { + /* correct for wnaf skew */ + int skew = point_state.skew_na; + if (skew) { + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); + } + } + if (n > 0) { + idx = (n - 1)/2; + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + } else if (n < 0) { + idx = -(n + 1)/2; + secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + } + } + + for(j = 0; j < bucket_window; j++) { + secp256k1_gej_double_var(r, r, NULL); + } + + secp256k1_gej_set_infinity(&running_sum); + /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... + * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... + * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) + * using an intermediate running sum: + * running_sum = bucket[0] + bucket[1] + bucket[2] + ... + * + * The doubling is done implicitly by deferring the final window doubling (of 'r'). + */ + for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); + secp256k1_gej_double_var(r, r, NULL); + secp256k1_gej_add_var(r, r, &running_sum, NULL); + } + return 1; +} + +/** + * Returns optimal bucket_window (number of bits of a scalar represented by a + * set of buckets) for a given number of points. + */ +static int secp256k1_pippenger_bucket_window(size_t n) { + if (n <= 1) { + return 1; + } else if (n <= 4) { + return 2; + } else if (n <= 20) { + return 3; + } else if (n <= 57) { + return 4; + } else if (n <= 136) { + return 5; + } else if (n <= 235) { + return 6; + } else if (n <= 1260) { + return 7; + } else if (n <= 4420) { + return 9; + } else if (n <= 7880) { + return 10; + } else if (n <= 16050) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +} + +/** + * Returns the maximum optimal number of points for a bucket_window. + */ +static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { + switch(bucket_window) { + case 1: return 1; + case 2: return 4; + case 3: return 20; + case 4: return 57; + case 5: return 136; + case 6: return 235; + case 7: return 1260; + case 8: return 1260; + case 9: return 4420; + case 10: return 7880; + case 11: return 16050; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; + } + return 0; +} + + +SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) { + secp256k1_scalar tmp = *s1; + secp256k1_scalar_split_lambda(s1, s2, &tmp); + secp256k1_ge_mul_lambda(p2, p1); + + if (secp256k1_scalar_is_high(s1)) { + secp256k1_scalar_negate(s1, s1); + secp256k1_ge_neg(p1, p1); + } + if (secp256k1_scalar_is_high(s2)) { + secp256k1_scalar_negate(s2, s2); + secp256k1_ge_neg(p2, p2); + } +} + +/** + * Returns the scratch size required for a given number of points (excluding + * base point G) without considering alignment. + */ +static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) { + size_t entries = 2*n_points + 2; + size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; +} + +static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); + /* Use 2(n+1) with the endomorphism, when calculating batch + * sizes. The reason for +1 is that we add the G scalar to the list of + * other scalars. */ + size_t entries = 2*n_points + 2; + secp256k1_ge *points; + secp256k1_scalar *scalars; + secp256k1_gej *buckets; + struct secp256k1_pippenger_state *state_space; + size_t idx = 0; + size_t point_idx = 0; + int bucket_window; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + bucket_window = secp256k1_pippenger_bucket_window(n_points); + + /* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If + * these allocations change, make sure to update the + * PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size + * accordingly. */ + points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); + scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); + state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space)); + if (points == NULL || scalars == NULL || state_space == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets)); + if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + + if (inp_g_sc != NULL) { + scalars[0] = *inp_g_sc; + points[0] = secp256k1_ge_const_g; + idx++; + secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); + idx++; + } + + while (point_idx < n_points) { + if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 0; + } + idx++; + secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); + idx++; + point_idx++; + } + + secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); + secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); + return 1; +} + +/* Wrapper for secp256k1_ecmult_multi_func interface */ +static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_ecmult_pippenger_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +/** + * Returns the maximum number of points in addition to G that can be used with + * a given scratch space. The function ensures that fewer points may also be + * used. + */ +static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) { + size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS); + int bucket_window; + size_t res = 0; + + for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { + size_t n_points; + size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window); + size_t space_for_points; + size_t space_overhead; + size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + + entry_size = 2*entry_size; + space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state); + if (space_overhead > max_alloc) { + break; + } + space_for_points = max_alloc - space_overhead; + + n_points = space_for_points/entry_size; + n_points = n_points > max_points ? max_points : n_points; + if (n_points > res) { + res = n_points; + } + if (n_points < max_points) { + /* A larger bucket_window may support even more points. But if we + * would choose that then the caller couldn't safely use any number + * smaller than what this function returns */ + break; + } + } + return res; +} + +/* Computes ecmult_multi by simply multiplying and adding each point. Does not + * require a scratch space */ +static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) { + size_t point_idx; + secp256k1_gej tmpj; + + secp256k1_gej_set_infinity(r); + secp256k1_gej_set_infinity(&tmpj); + /* r = inp_g_sc*G */ + secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc); + for (point_idx = 0; point_idx < n_points; point_idx++) { + secp256k1_ge point; + secp256k1_gej pointj; + secp256k1_scalar scalar; + if (!cb(&scalar, &point, point_idx, cbdata)) { + return 0; + } + /* r += scalar*point */ + secp256k1_gej_set_ge(&pointj, &point); + secp256k1_ecmult(&tmpj, &pointj, &scalar, NULL); + secp256k1_gej_add_var(r, r, &tmpj, NULL); + } + return 1; +} + +/* Compute the number of batches and the batch size given the maximum batch size and the + * total number of points */ +static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) { + if (max_n_batch_points == 0) { + return 0; + } + if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) { + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; + } + if (n == 0) { + *n_batches = 0; + *n_batch_points = 0; + return 1; + } + /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ + *n_batches = CEIL_DIV(n, max_n_batch_points); + *n_batch_points = CEIL_DIV(n, *n_batches); + return 1; +} + +typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t); +static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { + size_t i; + + int (*f)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t); + size_t n_batches; + size_t n_batch_points; + + secp256k1_gej_set_infinity(r); + if (inp_g_sc == NULL && n == 0) { + return 1; + } else if (n == 0) { + secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc); + return 1; + } + if (scratch == NULL) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + + /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than + * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. + * As a first step check if there's enough space for Pippenger's algo (which requires less space + * than Strauss' algo) and if not, use the simple algorithm. */ + if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(error_callback, scratch), n)) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { + f = secp256k1_ecmult_pippenger_batch; + } else { + if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) { + return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n); + } + f = secp256k1_ecmult_strauss_batch; + } + for(i = 0; i < n_batches; i++) { + size_t nbp = n < n_batch_points ? n : n_batch_points; + size_t offset = n_batch_points*i; + secp256k1_gej tmp; + if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + return 0; + } + secp256k1_gej_add_var(r, r, &tmp, NULL); + n -= nbp; + } + return 1; +} + +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field.h b/crypto/secp256k1/libsecp256k1/src/field.h index bbb1ee866..1f6ba7460 100644 --- a/crypto/secp256k1/libsecp256k1/src/field.h +++ b/crypto/secp256k1/libsecp256k1/src/field.h @@ -1,132 +1,350 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_ -#define _SECP256K1_FIELD_ +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H -/** Field element module. - * - * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properties into account: - * - Each field element can be normalized or not. - * - Each field element has a magnitude, which represents how far away - * its representation is away from normalization. Normalized elements - * always have a magnitude of 1, but a magnitude of 1 doesn't imply - * normality. - */ +#include "util.h" -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" +/* This file defines the generic interface for working with secp256k1_fe + * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). + * + * The actual definition of the secp256k1_fe type depends on the chosen field + * implementation; see the field_5x52.h and field_10x26.h files for details. + * + * All secp256k1_fe objects have implicit properties that determine what + * operations are permitted on it. These are purely a function of what + * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at + * compile time, and do not depend on the chosen field implementation. Despite + * that, what these properties actually entail for the field representation + * values depends on the chosen field implementation. These properties are: + * - magnitude: an integer in [0,32] + * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. + * + * In VERIFY mode, they are materialized explicitly as fields in the struct, + * allowing run-time verification of these properties. In that case, the field + * implementation also provides a secp256k1_fe_verify routine to verify that + * these fields match the run-time value and perform internal consistency + * checks. */ +#ifdef VERIFY +# define SECP256K1_FE_VERIFY_FIELDS \ + int magnitude; \ + int normalized; +#else +# define SECP256K1_FE_VERIFY_FIELDS #endif -#if defined(USE_FIELD_10X26) -#include "field_10x26.h" -#elif defined(USE_FIELD_5X52) +#if defined(SECP256K1_WIDEMUL_INT128) #include "field_5x52.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26.h" #else -#error "Please select field implementation" +#error "Please select wide multiplication implementation" #endif -#include "util.h" +#ifdef VERIFY +/* Magnitude and normalized value for constants. */ +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ + /* Magnitude is 0 for constant 0; 1 otherwise. */ \ + , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ + /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ + , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) +#else +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) +#endif -/** Normalize a field element. */ +/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p. + * + * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. + * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. + * + * SECP256K1_FE_CONST_INNER is provided by the implementation. + */ +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } + +static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul +); + +#ifndef VERIFY +/* In non-VERIFY mode, we #define the fe operations to be identical to their + * internal field implementation, to avoid the potential overhead of a + * function call (even though presumably inlinable). */ +# define secp256k1_fe_normalize secp256k1_fe_impl_normalize +# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak +# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var +# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero +# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var +# define secp256k1_fe_set_int secp256k1_fe_impl_set_int +# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero +# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd +# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var +# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod +# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit +# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 +# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked +# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked +# define secp256k1_fe_add secp256k1_fe_impl_add +# define secp256k1_fe_mul secp256k1_fe_impl_mul +# define secp256k1_fe_sqr secp256k1_fe_impl_sqr +# define secp256k1_fe_cmov secp256k1_fe_impl_cmov +# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage +# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage +# define secp256k1_fe_inv secp256k1_fe_impl_inv +# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var +# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds +# define secp256k1_fe_half secp256k1_fe_impl_half +# define secp256k1_fe_add_int secp256k1_fe_impl_add_int +# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var +#endif /* !defined(VERIFY) */ + +/** Normalize a field element. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has normalized=1 and magnitude=1. + */ static void secp256k1_fe_normalize(secp256k1_fe *r); -/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ +/** Give a field element magnitude 1. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has magnitude=1. Normalized is unchanged. + */ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); -/** Normalize a field element, without constant-time guarantee. */ +/** Normalize a field element, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_normalize, but not constant time in r. + */ static void secp256k1_fe_normalize_var(secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field - * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); +/** Determine whether r represents field element 0. + * + * On input, r must be a valid field element. + * Returns whether r = 0 (mod p). + */ +static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field - * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); +/** Determine whether r represents field element 0, without constant-time guarantee. + * + * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r. + */ +static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); -/** Set a field element equal to a small integer. Resulting field element is normalized. */ +/** Set a field element to an integer in range [0,0x7FFF]. + * + * On input, r does not need to be initialized, a must be in [0,0x7FFF]. + * On output, r represents value a, is normalized and has magnitude (a!=0). + */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); -/** Sets a field element equal to zero, initializing all fields. */ +/** Clear a field element to prevent leaking sensitive information. */ static void secp256k1_fe_clear(secp256k1_fe *a); -/** Verify whether a field element is zero. Requires the input to be normalized. */ +/** Determine whether a represents field element 0. + * + * On input, a must be a valid normalized field element. + * Returns whether a = 0 (mod p). + * + * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires + * normalized input (and is much faster). + */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); -/** Check the "oddness" of a field element. Requires the input to be normalized. */ +/** Determine whether a (mod p) is odd. + * + * On input, a must be a valid normalized field element. + * Returns (int(a) mod p) & 1. + */ static int secp256k1_fe_is_odd(const secp256k1_fe *a); -/** Compare two field elements. Requires magnitude-1 inputs. */ +/** Determine whether two field elements are equal. + * + * On input, a and b must be valid field elements with magnitudes not exceeding + * 1 and 31, respectively. + * Returns a = b (mod p). + */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); -/** Same as secp256k1_fe_equal, but may be variable time. */ -static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); - -/** Compare two field elements. Requires both inputs to be normalized */ +/** Compare the values represented by 2 field elements, without constant-time guarantee. + * + * On input, a and b must be valid normalized field elements. + * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers + * in range 0..p-1). + */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); +/** Set a field element equal to the element represented by a provided 32-byte big endian value + * interpreted modulo p. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a (mod p). It will have magnitude 1, and not be normalized. + */ +static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a); + +/** Set a field element equal to a provided 32-byte big endian value, checking for overflow. + * + * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. + * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned. + * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting). + */ +static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a); -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +/** Convert a field element to 32-byte big endian byte array. + * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. + * On output, r = a (mod p). + */ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); -/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input - * as an argument. The magnitude of the output is one higher. */ -static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); +/** Negate a field element. + * + * On input, r does not need to be initialized. a must be a valid field element with + * magnitude not exceeding m. m must be an integer constant expression in [0,31]. + * Performs {r = -a}. + * On output, r will not be normalized, and will have magnitude m+1. + */ +#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m)) + +/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); + +/** Add a small integer to a field element. + * + * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. + * a must be in range [0,0x7FFF]. + */ +static void secp256k1_fe_add_int(secp256k1_fe *r, int a); + +/** Multiply a field element with a small integer. + * + * On input, r must be a valid field element. a must be an integer constant expression in [0,32]. + * The magnitude of r times a must not exceed 32. + * Performs {r *= a}. + * On output, r's magnitude is multiplied by a, and r will not be normalized. + */ +#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a)) -/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that - * small integer. */ -static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); +/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression. + * + * Should not be called directly outside of tests. + */ +static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a); -/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +/** Increment a field element by another. + * + * On input, r and a must be valid field elements, not necessarily normalized. + * The sum of their magnitudes must not exceed 32. + * Performs {r += a}. + * On output, r will not be normalized, and will have magnitude incremented by a's. + */ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Multiply two field elements. + * + * On input, a and b must be valid field elements; r does not need to be initialized. + * r and a may point to the same object, but neither may point to the object pointed + * to by b. The magnitudes of a and b must not exceed 8. + * Performs {r = a * b} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); -/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Square a field element. + * + * On input, a must be a valid field element; r does not need to be initialized. The magnitude + * of a must not exceed 8. + * Performs {r = a**2} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** If a has a square root, it is computed in r and 1 is returned. If a does not - * have a square root, the root of its negation is computed and 0 is returned. - * The input's magnitude can be at most 8. The output magnitude is 1 (but not - * guaranteed to be normalized). The result in r will always be a square - * itself. */ -static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); - -/** Checks whether a field element is a quadratic residue. */ -static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); +/** Compute a square root of a field element. + * + * On input, a must be a valid field element with magnitude<=8; r need not be initialized. + * If sqrt(a) exists, performs {r = sqrt(a)} and returns 1. + * Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0. + * The resulting value represented by r will be a square itself. + * Variables r and a must not point to the same object. + * On output, r will have magnitude 1 but will not be normalized. + */ +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); -/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be - * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Compute the modular inverse of a field element. + * + * On input, a must be a valid field element; r need not be initialized. + * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its + * inverse). + * On output, r will have magnitude (a.magnitude != 0) and be normalized. + */ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); -/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +/** Compute the modular inverse of a field element, without constant-time guarantee. + * + * Behaves identically to secp256k1_fe_inv, but is not constant-time in a. + */ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); -/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be - * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and - * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); - -/** Convert a field element to the storage type. */ +/** Convert a field element to secp256k1_fe_storage. + * + * On input, a must be a valid normalized field element. + * Performs {r = a}. + */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); -/** Convert a field element back from the storage type. */ +/** Convert a field element back from secp256k1_fe_storage. + * + * On input, r need not be initialized. + * Performs {r = a}. + * On output, r will be normalized and will have magnitude 1. + */ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +/** Conditionally move a field element in constant time. + * + * On input, both r and a must be valid field elements. Flag must be 0 or 1. + * Performs {r = flag ? a : r}. + * + * On output, r's magnitude will be the maximum of both input magnitudes. + * It will be normalized if and only if both inputs were normalized. + */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -#endif +/** Halve the value of a field element modulo the field prime in constant-time. + * + * On input, r must be a valid field element. + * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is + * the magnitude of r on input. + */ +static void secp256k1_fe_half(secp256k1_fe *r); + +/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. + * The value is chosen so that it is likely to trigger edge cases related to + * internal overflows. */ +static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); + +/** Determine whether a is a square (modulo p). + * + * On input, a must be a valid field element. + */ +static int secp256k1_fe_is_square_var(const secp256k1_fe *a); + +/** Check invariants on a field element (no-op unless VERIFY is enabled). */ +static void secp256k1_fe_verify(const secp256k1_fe *a); +#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a) + +/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */ +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m); +#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m) + +#endif /* SECP256K1_FIELD_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_10x26.h b/crypto/secp256k1/libsecp256k1/src/field_10x26.h index 61ee1e096..203c10167 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_10x26.h +++ b/crypto/secp256k1/libsecp256k1/src/field_10x26.h @@ -1,21 +1,36 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include +/** This field implementation represents the value as 10 uint32_t limbs in base + * 2^26. */ typedef struct { - /* X = sum(i=0..9, elem[i]*2^26) mod n */ + /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is + * normalized. */ uint32_t n[10]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^26 - 1) for i=0..8 + * n[9] <= 2 * m * (2^22 - 1) + * + * Normalized requires: + * n[i] <= (2^26 - 1) for i=0..8 + * sum(i=0..9, n[i] << (i*26)) < p + * (together these imply n[9] <= 2^22 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ @@ -32,16 +47,11 @@ typedef struct { (((uint32_t)d7) >> 10) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint32_t n[8]; } secp256k1_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} #define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] -#endif + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h b/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h index 5fb092f1b..ea14c2731 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h @@ -1,46 +1,56 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" -#include "num.h" #include "field.h" +#include "modinv32_impl.h" #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); + int m = a->normalized ? 1 : 2 * a->magnitude; + VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[9] == 0x03FFFFFUL)) { + if (d[9] == 0x03FFFFFUL) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); } } } - VERIFY_CHECK(r == 1); } #endif -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { + r->n[0] = 0x3FFFFFFUL * 2 * m; + r->n[1] = 0x3FFFFFFUL * 2 * m; + r->n[2] = 0x3FFFFFFUL * 2 * m; + r->n[3] = 0x3FFFFFFUL * 2 * m; + r->n[4] = 0x3FFFFFFUL * 2 * m; + r->n[5] = 0x3FFFFFFUL * 2 * m; + r->n[6] = 0x3FFFFFFUL * 2 * m; + r->n[7] = 0x3FFFFFFUL * 2 * m; + r->n[8] = 0x3FFFFFFUL * 2 * m; + r->n[9] = 0x03FFFFFUL * 2 * m; +} + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -87,15 +97,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -119,14 +123,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -174,15 +173,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -211,7 +204,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; @@ -263,52 +256,22 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { - int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<10; i++) { - a->n[i] = 0; - } -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 9; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; @@ -320,53 +283,69 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int i; - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; - for (i=0; i<32; i++) { - int j; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; - } - } - if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { - return 0; - } -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif - return 1; +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); + r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); + r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); + r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); + r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); + r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); + r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); + r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); + r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); + r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - for (i=0; i<32; i++) { - int j; - int c = 0; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); - } - r[31-i] = c; - } +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { + r[0] = (a->n[9] >> 14) & 0xff; + r[1] = (a->n[9] >> 6) & 0xff; + r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); + r[3] = (a->n[8] >> 16) & 0xff; + r[4] = (a->n[8] >> 8) & 0xff; + r[5] = a->n[8] & 0xff; + r[6] = (a->n[7] >> 18) & 0xff; + r[7] = (a->n[7] >> 10) & 0xff; + r[8] = (a->n[7] >> 2) & 0xff; + r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); + r[10] = (a->n[6] >> 12) & 0xff; + r[11] = (a->n[6] >> 4) & 0xff; + r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); + r[13] = (a->n[5] >> 14) & 0xff; + r[14] = (a->n[5] >> 6) & 0xff; + r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); + r[16] = (a->n[4] >> 16) & 0xff; + r[17] = (a->n[4] >> 8) & 0xff; + r[18] = a->n[4] & 0xff; + r[19] = (a->n[3] >> 18) & 0xff; + r[20] = (a->n[3] >> 10) & 0xff; + r[21] = (a->n[3] >> 2) & 0xff; + r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); + r[23] = (a->n[2] >> 12) & 0xff; + r[24] = (a->n[2] >> 4) & 0xff; + r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); + r[26] = (a->n[1] >> 14) & 0xff; + r[27] = (a->n[1] >> 6) & 0xff; + r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); + r[29] = (a->n[0] >> 16) & 0xff; + r[30] = (a->n[0] >> 8) & 0xff; + r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ + VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); + VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; @@ -377,14 +356,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -395,17 +369,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[7] *= a; r->n[8] *= a; r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -416,11 +382,10 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->n[7] += a->n[7]; r->n[8] += a->n[8]; r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif +} + +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { + r->n[0] += a; } #if defined(USE_EXTERNAL_ASM) @@ -431,11 +396,7 @@ void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); #else -#ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { uint64_t c, d; @@ -465,7 +426,8 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t VERIFY_BITS(b[9], 26); /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9) * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. */ @@ -1041,38 +1003,19 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } #endif -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1084,17 +1027,78 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (a->magnitude > r->magnitude) { - r->magnitude = a->magnitude; - } - r->normalized &= a->normalized; -#endif +} + +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + uint32_t one = (uint32_t)1; + uint32_t mask = -(t0 & one) >> 6; + + /* Bounds analysis (over the rationals). + * + * Let m = r->magnitude + * C = 0x3FFFFFFUL * 2 + * D = 0x03FFFFFUL * 2 + * + * Initial bounds: t0..t8 <= C * m + * t9 <= D * m + */ + + t0 += 0x3FFFC2FUL & mask; + t1 += 0x3FFFFBFUL & mask; + t2 += mask; + t3 += mask; + t4 += mask; + t5 += mask; + t6 += mask; + t7 += mask; + t8 += mask; + t9 += mask >> 4; + + VERIFY_CHECK((t0 & one) == 0); + + /* t0..t8: added <= C/2 + * t9: added <= D/2 + * + * Current bounds: t0..t8 <= C * (m + 1/2) + * t9 <= D * (m + 1/2) + */ + + r->n[0] = (t0 >> 1) + ((t1 & one) << 25); + r->n[1] = (t1 >> 1) + ((t2 & one) << 25); + r->n[2] = (t2 >> 1) + ((t3 & one) << 25); + r->n[3] = (t3 >> 1) + ((t4 & one) << 25); + r->n[4] = (t4 >> 1) + ((t5 & one) << 25); + r->n[5] = (t5 >> 1) + ((t6 & one) << 25); + r->n[6] = (t6 >> 1) + ((t7 & one) << 25); + r->n[7] = (t7 >> 1) + ((t8 & one) << 25); + r->n[8] = (t8 >> 1) + ((t9 & one) << 25); + r->n[9] = (t9 >> 1); + + /* t0..t8: shifted right and added <= C/4 + 1/2 + * t9: shifted right + * + * Current bounds: t0..t8 <= C * (m/2 + 1/2) + * t9 <= D * (m/2 + 1/4) + * + * Therefore the output magnitude (M) has to be set such that: + * t0..t8: C * M >= C * (m/2 + 1/2) + * t9: D * M >= D * (m/2 + 1/4) + * + * It suffices for all limbs that, for any input magnitude m: + * M >= m/2 + 1/2 + * + * and since we want the smallest such integer value for M: + * M == floor(m/2) + 1 + */ } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -1106,10 +1110,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 26; r->n[1] = a->n[1] >> 6 | a->n[2] << 20; r->n[2] = a->n[2] >> 12 | a->n[3] << 14; @@ -1120,7 +1121,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1131,10 +1132,101 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; -#endif } -#endif +static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) { + const uint32_t M26 = UINT32_MAX >> 6; + const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], + a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; + + /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). + */ + VERIFY_CHECK(a0 >> 30 == 0); + VERIFY_CHECK(a1 >> 30 == 0); + VERIFY_CHECK(a2 >> 30 == 0); + VERIFY_CHECK(a3 >> 30 == 0); + VERIFY_CHECK(a4 >> 30 == 0); + VERIFY_CHECK(a5 >> 30 == 0); + VERIFY_CHECK(a6 >> 30 == 0); + VERIFY_CHECK(a7 >> 30 == 0); + VERIFY_CHECK(a8 >> 16 == 0); + + r->n[0] = a0 & M26; + r->n[1] = (a0 >> 26 | a1 << 4) & M26; + r->n[2] = (a1 >> 22 | a2 << 8) & M26; + r->n[3] = (a2 >> 18 | a3 << 12) & M26; + r->n[4] = (a3 >> 14 | a4 << 16) & M26; + r->n[5] = (a4 >> 10 | a5 << 20) & M26; + r->n[6] = (a5 >> 6 | a6 << 24) & M26; + r->n[7] = (a6 >> 2 ) & M26; + r->n[8] = (a6 >> 28 | a7 << 2) & M26; + r->n[9] = (a7 >> 24 | a8 << 6); +} + +static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) { + const uint32_t M30 = UINT32_MAX >> 2; + const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], + a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; + + r->v[0] = (a0 | a1 << 26) & M30; + r->v[1] = (a1 >> 4 | a2 << 22) & M30; + r->v[2] = (a2 >> 8 | a3 << 18) & M30; + r->v[3] = (a3 >> 12 | a4 << 14) & M30; + r->v[4] = (a4 >> 16 | a5 << 10) & M30; + r->v[5] = (a5 >> 20 | a6 << 6) & M30; + r->v[6] = (a6 >> 24 | a7 << 2 + | a8 << 28) & M30; + r->v[7] = (a8 >> 2 | a9 << 24) & M30; + r->v[8] = a9 >> 6; +} + +static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = { + {{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}}, + 0x2DDACACFL +}; + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv32_signed30 s; + + secp256k1_fe_normalize(&tmp); + secp256k1_fe_to_signed30(&s, &tmp); + secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed30(r, &s); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv32_signed30 s; + + secp256k1_fe_normalize_var(&tmp); + secp256k1_fe_to_signed30(&s, &tmp); + secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed30(r, &s); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv32_signed30 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi32_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed30(&s, &tmp); + jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + secp256k1_fe dummy; + ret = secp256k1_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52.h b/crypto/secp256k1/libsecp256k1/src/field_5x52.h index 8e69a560d..f20c246fd 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52.h +++ b/crypto/secp256k1/libsecp256k1/src/field_5x52.h @@ -1,21 +1,36 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include +/** This field implementation represents the value as 5 uint64_t limbs in base + * 2^52. */ typedef struct { - /* X = sum(i=0..4, elem[i]*2^52) mod n */ + /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is + * normalized. */ uint64_t n[5]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^52 - 1) for i=0..3 + * n[4] <= 2 * m * (2^48 - 1) + * + * Normalized requires: + * n[i] <= (2^52 - 1) for i=0..3 + * sum(i=0..4, n[i] << (i*52)) < p + * (together these imply n[4] <= 2^48 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ @@ -27,12 +42,6 @@ typedef struct { ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint64_t n[4]; } secp256k1_fe_storage; @@ -44,4 +53,10 @@ typedef struct { (d6) | (((uint64_t)(d7)) << 32) \ }} -#endif +#define SECP256K1_FE_STORAGE_CONST_GET(d) \ + (uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \ + (uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \ + (uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \ + (uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0] + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52_asm_impl.h b/crypto/secp256k1/libsecp256k1/src/field_5x52_asm_impl.h deleted file mode 100644 index 98cc004bf..000000000 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52_asm_impl.h +++ /dev/null @@ -1,502 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -/** - * Changelog: - * - March 2013, Diederik Huys: original version - * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm - * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly - */ - -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * r15:rcx = d - * r10-r14 = a0-a4 - * rbx = b - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - - /* d += a3 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rcx\n" - "movq %%rdx,%%r15\n" - /* d += a2 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d = a0 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c = a4 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* d += a4 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a0 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* t4 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a4 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* u0 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a1 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a4 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a2 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a1 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b2 (last use of %%r10 = a0) */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* d += a4 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rcx only) */ - "shrdq $52,%%r15,%%rcx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rcx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "b"(b), "D"(r) -: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * rcx:rbx = d - * r10-r14 = a0-a4 - * r15 = M (0xfffffffffffff) - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - "movq $0xfffffffffffff,%%r15\n" - - /* d = (a0*2) * a3 */ - "leaq (%%r10,%%r10,1),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rbx\n" - "movq %%rdx,%%rcx\n" - /* d += (a1*2) * a2 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c = a4 * a4 */ - "movq %%r14,%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* a4 *= 2 */ - "addq %%r14,%%r14\n" - /* d += a0 * a4 */ - "movq %%r10,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d+= (a1*2) * a3 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a2 * a2 */ - "movq %%r12,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* t4 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * a0 */ - "movq %%r10,%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a1 * a4 */ - "movq %%r11,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += (a2*2) * a3 */ - "leaq (%%r12,%%r12,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* u0 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* a0 *= 2 */ - "addq %%r10,%%r10\n" - /* c += a0 * a1 */ - "movq %%r10,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a2 * a4 */ - "movq %%r12,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a3 * a3 */ - "movq %%r13,%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a0 * a2 (last use of %%r10) */ - "movq %%r10,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* c += a1 * a1 */ - "movq %%r11,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a3 * a4 */ - "movq %%r13,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rbx only) */ - "shrdq $52,%%rcx,%%rbx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rbx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "D"(r) -: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h b/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h index dd88f38c7..46dca6b98 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h @@ -1,57 +1,46 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" -#include "num.h" #include "field.h" +#include "modinv64_impl.h" -#if defined(USE_ASM_X86_64) -#include "field_5x52_asm_impl.h" -#else #include "field_5x52_int128_impl.h" -#endif - -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, - * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element - * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations - * accept any input with magnitude at most M, and have different rules for propagating magnitude to their - * output. - */ #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + int m = a->normalized ? 1 : 2 * a->magnitude; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 2048); + VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - r &= (d[0] < 0xFFFFEFFFFFC2FULL); + if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); } } - VERIFY_CHECK(r == 1); } #endif -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { + r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; +} + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -86,15 +75,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { t4 &= 0x0FFFFFFFFFFFFULL; r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -111,14 +94,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { VERIFY_CHECK(t4 >> 49 == 0); r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -154,15 +132,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { } r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -185,7 +157,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; @@ -226,52 +198,22 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint64_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<5; i++) { - a->n[i] = 0; - } -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 4; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; @@ -283,142 +225,199 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int i; - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - for (i=0; i<32; i++) { - int j; - for (j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; - } - } - if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { - return 0; - } -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif - return 1; +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint64_t)a[31] + | ((uint64_t)a[30] << 8) + | ((uint64_t)a[29] << 16) + | ((uint64_t)a[28] << 24) + | ((uint64_t)a[27] << 32) + | ((uint64_t)a[26] << 40) + | ((uint64_t)(a[25] & 0xF) << 48); + r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) + | ((uint64_t)a[24] << 4) + | ((uint64_t)a[23] << 12) + | ((uint64_t)a[22] << 20) + | ((uint64_t)a[21] << 28) + | ((uint64_t)a[20] << 36) + | ((uint64_t)a[19] << 44); + r->n[2] = (uint64_t)a[18] + | ((uint64_t)a[17] << 8) + | ((uint64_t)a[16] << 16) + | ((uint64_t)a[15] << 24) + | ((uint64_t)a[14] << 32) + | ((uint64_t)a[13] << 40) + | ((uint64_t)(a[12] & 0xF) << 48); + r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) + | ((uint64_t)a[11] << 4) + | ((uint64_t)a[10] << 12) + | ((uint64_t)a[9] << 20) + | ((uint64_t)a[8] << 28) + | ((uint64_t)a[7] << 36) + | ((uint64_t)a[6] << 44); + r->n[4] = (uint64_t)a[5] + | ((uint64_t)a[4] << 8) + | ((uint64_t)a[3] << 16) + | ((uint64_t)a[2] << 24) + | ((uint64_t)a[1] << 32) + | ((uint64_t)a[0] << 40); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - for (i=0; i<32; i++) { - int j; - int c = 0; - for (j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); - } - r[31-i] = c; - } +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { + r[0] = (a->n[4] >> 40) & 0xFF; + r[1] = (a->n[4] >> 32) & 0xFF; + r[2] = (a->n[4] >> 24) & 0xFF; + r[3] = (a->n[4] >> 16) & 0xFF; + r[4] = (a->n[4] >> 8) & 0xFF; + r[5] = a->n[4] & 0xFF; + r[6] = (a->n[3] >> 44) & 0xFF; + r[7] = (a->n[3] >> 36) & 0xFF; + r[8] = (a->n[3] >> 28) & 0xFF; + r[9] = (a->n[3] >> 20) & 0xFF; + r[10] = (a->n[3] >> 12) & 0xFF; + r[11] = (a->n[3] >> 4) & 0xFF; + r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); + r[13] = (a->n[2] >> 40) & 0xFF; + r[14] = (a->n[2] >> 32) & 0xFF; + r[15] = (a->n[2] >> 24) & 0xFF; + r[16] = (a->n[2] >> 16) & 0xFF; + r[17] = (a->n[2] >> 8) & 0xFF; + r[18] = a->n[2] & 0xFF; + r[19] = (a->n[1] >> 44) & 0xFF; + r[20] = (a->n[1] >> 36) & 0xFF; + r[21] = (a->n[1] >> 28) & 0xFF; + r[22] = (a->n[1] >> 20) & 0xFF; + r[23] = (a->n[1] >> 12) & 0xFF; + r[24] = (a->n[1] >> 4) & 0xFF; + r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); + r[26] = (a->n[0] >> 40) & 0xFF; + r[27] = (a->n[0] >> 32) & 0xFF; + r[28] = (a->n[0] >> 24) & 0xFF; + r[29] = (a->n[0] >> 16) & 0xFF; + r[30] = (a->n[0] >> 8) & 0xFF; + r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ + VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); + VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); + VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; r->n[3] *= a; r->n[4] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { + r->n[0] += a; +} + +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; r->n[3] += a->n[3]; r->n[4] += a->n[4]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; - mask0 = flag + ~((uint64_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -#ifdef VERIFY - if (a->magnitude > r->magnitude) { - r->magnitude = a->magnitude; - } - r->normalized &= a->normalized; -#endif +} + +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + uint64_t one = (uint64_t)1; + uint64_t mask = -(t0 & one) >> 12; + + /* Bounds analysis (over the rationals). + * + * Let m = r->magnitude + * C = 0xFFFFFFFFFFFFFULL * 2 + * D = 0x0FFFFFFFFFFFFULL * 2 + * + * Initial bounds: t0..t3 <= C * m + * t4 <= D * m + */ + + t0 += 0xFFFFEFFFFFC2FULL & mask; + t1 += mask; + t2 += mask; + t3 += mask; + t4 += mask >> 4; + + VERIFY_CHECK((t0 & one) == 0); + + /* t0..t3: added <= C/2 + * t4: added <= D/2 + * + * Current bounds: t0..t3 <= C * (m + 1/2) + * t4 <= D * (m + 1/2) + */ + + r->n[0] = (t0 >> 1) + ((t1 & one) << 51); + r->n[1] = (t1 >> 1) + ((t2 & one) << 51); + r->n[2] = (t2 >> 1) + ((t3 & one) << 51); + r->n[3] = (t3 >> 1) + ((t4 & one) << 51); + r->n[4] = (t4 >> 1); + + /* t0..t3: shifted right and added <= C/4 + 1/2 + * t4: shifted right + * + * Current bounds: t0..t3 <= C * (m/2 + 1/2) + * t4 <= D * (m/2 + 1/4) + * + * Therefore the output magnitude (M) has to be set such that: + * t0..t3: C * M >= C * (m/2 + 1/2) + * t4: D * M >= D * (m/2 + 1/4) + * + * It suffices for all limbs that, for any input magnitude m: + * M >= m/2 + 1/2 + * + * and since we want the smallest such integer value for M: + * M == floor(m/2) + 1 + */ } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint64_t mask0, mask1; - mask0 = flag + ~((uint64_t)0); + volatile int vflag = flag; + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); + mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); @@ -426,26 +425,98 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 52; r->n[1] = a->n[1] >> 12 | a->n[2] << 40; r->n[2] = a->n[2] >> 24 | a->n[3] << 28; r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); r->n[4] = a->n[3] >> 16; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; -#endif } -#endif +static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) { + const uint64_t M52 = UINT64_MAX >> 12; + const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; + + /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). + */ + VERIFY_CHECK(a0 >> 62 == 0); + VERIFY_CHECK(a1 >> 62 == 0); + VERIFY_CHECK(a2 >> 62 == 0); + VERIFY_CHECK(a3 >> 62 == 0); + VERIFY_CHECK(a4 >> 8 == 0); + + r->n[0] = a0 & M52; + r->n[1] = (a0 >> 52 | a1 << 10) & M52; + r->n[2] = (a1 >> 42 | a2 << 20) & M52; + r->n[3] = (a2 >> 32 | a3 << 30) & M52; + r->n[4] = (a3 >> 22 | a4 << 40); +} + +static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) { + const uint64_t M62 = UINT64_MAX >> 2; + const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; + + r->v[0] = (a0 | a1 << 52) & M62; + r->v[1] = (a1 >> 10 | a2 << 42) & M62; + r->v[2] = (a2 >> 20 | a3 << 32) & M62; + r->v[3] = (a3 >> 30 | a4 << 22) & M62; + r->v[4] = a4 >> 40; +} + +static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = { + {{-0x1000003D1LL, 0, 0, 0, 256}}, + 0x27C7F6E22DDACACFLL +}; + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv64_signed62 s; + + secp256k1_fe_normalize(&tmp); + secp256k1_fe_to_signed62(&s, &tmp); + secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed62(r, &s); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; + secp256k1_modinv64_signed62 s; + + secp256k1_fe_normalize_var(&tmp); + secp256k1_fe_to_signed62(&s, &tmp); + secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe); + secp256k1_fe_from_signed62(r, &s); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv64_signed62 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi64_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed62(&s, &tmp); + jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + secp256k1_fe dummy; + ret = secp256k1_fe_sqrt(&dummy, &tmp); + } else { + ret = jac >= 0; + } + return ret; +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h b/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h index 0bf22bdd3..f23f8ee1c 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h @@ -1,22 +1,22 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H #include -#ifdef VERIFY +#include "int128.h" +#include "util.h" + #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif +#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { - uint128_t c, d; + secp256k1_uint128 c, d; uint64_t t3, t4, tx, u0; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; @@ -32,130 +32,129 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t VERIFY_BITS(b[3], 56); VERIFY_BITS(b[4], 52); VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) * Note that [x 0 0 0 0 0] = [x*R]. */ - d = (uint128_t)a0 * b[3] - + (uint128_t)a1 * b[2] - + (uint128_t)a2 * b[1] - + (uint128_t)a3 * b[0]; - VERIFY_BITS(d, 114); + secp256k1_u128_mul(&d, a0, b[3]); + secp256k1_u128_accum_mul(&d, a1, b[2]); + secp256k1_u128_accum_mul(&d, a2, b[1]); + secp256k1_u128_accum_mul(&d, a3, b[0]); + VERIFY_BITS_128(&d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * b[4]; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a4, b[4]); + VERIFY_BITS_128(&c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (c & M) * R; c >>= 52; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 60); - /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)a0 * b[4] - + (uint128_t)a1 * b[3] - + (uint128_t)a2 * b[2] - + (uint128_t)a3 * b[1] - + (uint128_t)a4 * b[0]; - VERIFY_BITS(d, 115); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += c * R; - VERIFY_BITS(d, 116); + secp256k1_u128_accum_mul(&d, a0, b[4]); + secp256k1_u128_accum_mul(&d, a1, b[3]); + secp256k1_u128_accum_mul(&d, a2, b[2]); + secp256k1_u128_accum_mul(&d, a3, b[1]); + secp256k1_u128_accum_mul(&d, a4, b[0]); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); + VERIFY_BITS_128(&d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (uint128_t)a0 * b[0]; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a0, b[0]); + VERIFY_BITS_128(&c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * b[4] - + (uint128_t)a2 * b[3] - + (uint128_t)a3 * b[2] - + (uint128_t)a4 * b[1]; - VERIFY_BITS(d, 115); + secp256k1_u128_accum_mul(&d, a1, b[4]); + secp256k1_u128_accum_mul(&d, a2, b[3]); + secp256k1_u128_accum_mul(&d, a3, b[2]); + secp256k1_u128_accum_mul(&d, a4, b[1]); + VERIFY_BITS_128(&d, 114); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 63); + VERIFY_BITS_128(&d, 62); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 115); + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); + VERIFY_BITS_128(&c, 61); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)a0 * b[1] - + (uint128_t)a1 * b[0]; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, b[1]); + secp256k1_u128_accum_mul(&c, a1, b[0]); + VERIFY_BITS_128(&c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * b[4] - + (uint128_t)a3 * b[3] - + (uint128_t)a4 * b[2]; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a2, b[4]); + secp256k1_u128_accum_mul(&d, a3, b[3]); + secp256k1_u128_accum_mul(&d, a4, b[2]); + VERIFY_BITS_128(&d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (uint128_t)a0 * b[2] - + (uint128_t)a1 * b[1] - + (uint128_t)a2 * b[0]; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, b[2]); + secp256k1_u128_accum_mul(&c, a1, b[1]); + secp256k1_u128_accum_mul(&c, a2, b[0]); + VERIFY_BITS_128(&c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * b[4] - + (uint128_t)a4 * b[3]; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a3, b[4]); + secp256k1_u128_accum_mul(&d, a4, b[3]); + VERIFY_BITS_128(&d, 114); /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3; - VERIFY_BITS(c, 100); + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); + VERIFY_BITS_128(&c, 48); /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; + r[4] = secp256k1_u128_to_u64(&c) + t4; VERIFY_BITS(r[4], 49); /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { - uint128_t c, d; + secp256k1_uint128 c, d; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - int64_t t3, t4, tx, u0; + uint64_t t3, t4, tx, u0; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; VERIFY_BITS(a[0], 56); @@ -169,109 +168,107 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t * Note that [x 0 0 0 0 0] = [x*R]. */ - d = (uint128_t)(a0*2) * a3 - + (uint128_t)(a1*2) * a2; - VERIFY_BITS(d, 114); + secp256k1_u128_mul(&d, a0*2, a3); + secp256k1_u128_accum_mul(&d, a1*2, a2); + VERIFY_BITS_128(&d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * a4; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a4, a4); + VERIFY_BITS_128(&c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (c & M) * R; c >>= 52; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 60); - /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); + /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + VERIFY_BITS_128(&d, 63); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ a4 *= 2; - d += (uint128_t)a0 * a4 - + (uint128_t)(a1*2) * a3 - + (uint128_t)a2 * a2; - VERIFY_BITS(d, 115); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += c * R; - VERIFY_BITS(d, 116); + secp256k1_u128_accum_mul(&d, a0, a4); + secp256k1_u128_accum_mul(&d, a1*2, a3); + secp256k1_u128_accum_mul(&d, a2, a2); + VERIFY_BITS_128(&d, 115); + /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); + VERIFY_BITS_128(&d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (uint128_t)a0 * a0; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a0, a0); + VERIFY_BITS_128(&c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * a4 - + (uint128_t)(a2*2) * a3; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a1, a4); + secp256k1_u128_accum_mul(&d, a2*2, a3); + VERIFY_BITS_128(&d, 114); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 62); + VERIFY_BITS_128(&d, 62); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 113); + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); + VERIFY_BITS_128(&c, 61); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ a0 *= 2; - c += (uint128_t)a0 * a1; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, a1); + VERIFY_BITS_128(&c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * a4 - + (uint128_t)a3 * a3; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a2, a4); + secp256k1_u128_accum_mul(&d, a3, a3); + VERIFY_BITS_128(&d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (uint128_t)a0 * a2 - + (uint128_t)a1 * a1; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, a2); + secp256k1_u128_accum_mul(&c, a1, a1); + VERIFY_BITS_128(&c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * a4; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a3, a4); + VERIFY_BITS_128(&d, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); + /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + VERIFY_BITS_128(&c, 63); + /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3; - VERIFY_BITS(c, 100); + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); + VERIFY_BITS_128(&c, 48); /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; + r[4] = secp256k1_u128_to_u64(&c) + t4; VERIFY_BITS(r[4], 49); /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/field_impl.h b/crypto/secp256k1/libsecp256k1/src/field_impl.h index 5127b279b..896507a3a 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_impl.h @@ -1,41 +1,40 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_FIELD_IMPL_H_ -#define _SECP256K1_FIELD_IMPL_H_ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H +#include "field.h" #include "util.h" -#if defined(USE_FIELD_10X26) -#include "field_10x26_impl.h" -#elif defined(USE_FIELD_5X52) +#if defined(SECP256K1_WIDEMUL_INT128) #include "field_5x52_impl.h" +#elif defined(SECP256K1_WIDEMUL_INT64) +#include "field_10x26_impl.h" #else -#error "Please select field implementation" +#error "Please select wide multiplication implementation" #endif -SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe na; - secp256k1_fe_negate(&na, a, 1); - secp256k1_fe_add(&na, b); - return secp256k1_fe_normalizes_to_zero(&na); +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + secp256k1_memclear(a, sizeof(secp256k1_fe)); } -SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); + secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); - return secp256k1_fe_normalizes_to_zero_var(&na); + return secp256k1_fe_normalizes_to_zero(&na); } -static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) { /** Given that p is congruent to 3 mod 4, we can compute the square root of * a mod p as the (p+1)/4'th power of a. * @@ -46,7 +45,11 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). */ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; + int j, ret; + + VERIFY_CHECK(r != a); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: @@ -130,186 +133,325 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal(&t1, a); + ret = secp256k1_fe_equal(&t1, a); + +#ifdef VERIFY + if (!ret) { + secp256k1_fe_negate(&t1, &t1, 1); + secp256k1_fe_normalize_var(&t1); + VERIFY_CHECK(secp256k1_fe_equal(&t1, a)); + } +#endif + return ret; } -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; +#ifndef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; } +#else +static void secp256k1_fe_impl_verify(const secp256k1_fe *a); +static void secp256k1_fe_verify(const secp256k1_fe *a) { + /* Magnitude between 0 and 32. */ + SECP256K1_FE_VERIFY_MAGNITUDE(a, 32); + /* Normalized is 0 or 1. */ + VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); + /* If normalized, magnitude must be 0 or 1. */ + if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + /* Invoke implementation-specific checks. */ + secp256k1_fe_impl_verify(a); +} - /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in - * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - */ +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + VERIFY_CHECK(a->magnitude <= m); +} - secp256k1_fe_sqr(&x2, a); - secp256k1_fe_mul(&x2, &x2, a); +static void secp256k1_fe_impl_normalize(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); - secp256k1_fe_sqr(&x3, &x2); - secp256k1_fe_mul(&x3, &x3, a); + secp256k1_fe_impl_normalize(r); + r->magnitude = 1; + r->normalized = 1; - x6 = x3; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x6, &x6); - } - secp256k1_fe_mul(&x6, &x6, &x3); + SECP256K1_FE_VERIFY(r); +} - x9 = x6; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x9, &x9); - } - secp256k1_fe_mul(&x9, &x9, &x3); +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); - x11 = x9; - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&x11, &x11); - } - secp256k1_fe_mul(&x11, &x11, &x2); + secp256k1_fe_impl_normalize_weak(r); + r->magnitude = 1; - x22 = x11; - for (j=0; j<11; j++) { - secp256k1_fe_sqr(&x22, &x22); - } - secp256k1_fe_mul(&x22, &x22, &x11); + SECP256K1_FE_VERIFY(r); +} - x44 = x22; - for (j=0; j<22; j++) { - secp256k1_fe_sqr(&x44, &x44); - } - secp256k1_fe_mul(&x44, &x44, &x22); +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); - x88 = x44; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x88, &x88); - } - secp256k1_fe_mul(&x88, &x88, &x44); + secp256k1_fe_impl_normalize_var(r); + r->magnitude = 1; + r->normalized = 1; - x176 = x88; - for (j=0; j<88; j++) { - secp256k1_fe_sqr(&x176, &x176); - } - secp256k1_fe_mul(&x176, &x176, &x88); + SECP256K1_FE_VERIFY(r); +} - x220 = x176; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x220, &x220); - } - secp256k1_fe_mul(&x220, &x220, &x44); +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); - x223 = x220; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x223, &x223); - } - secp256k1_fe_mul(&x223, &x223, &x3); + return secp256k1_fe_impl_normalizes_to_zero(r); +} - /* The final result is then assembled using a sliding window over the blocks. */ +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); - t1 = x223; - for (j=0; j<23; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<5; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, a); - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x2); - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(r, a, &t1); + return secp256k1_fe_impl_normalizes_to_zero_var(r); } -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { -#if defined(USE_FIELD_INV_BUILTIN) - secp256k1_fe_inv(r, a); -#elif defined(USE_FIELD_INV_NUM) - secp256k1_num n, m; - static const secp256k1_fe negone = SECP256K1_FE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL - ); - /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - static const unsigned char prime[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F - }; - unsigned char b[32]; - int res; - secp256k1_fe c = *a; - secp256k1_fe_normalize_var(&c); - secp256k1_fe_get_b32(b, &c); - secp256k1_num_set_bin(&n, b, 32); - secp256k1_num_set_bin(&m, prime, 32); - secp256k1_num_mod_inverse(&n, &n, &m); - secp256k1_num_get_bin(b, 32, &n); - res = secp256k1_fe_set_b32(r, b); - (void)res; - VERIFY_CHECK(res); - /* Verify the result is the (unique) valid inverse using non-GMP code. */ - secp256k1_fe_mul(&c, &c, r); - secp256k1_fe_add(&c, &negone); - CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); -#else -#error "Please select field inverse implementation" -#endif +static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + + secp256k1_fe_impl_set_int(r, a); + r->magnitude = (a != 0); + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); } -static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { - secp256k1_fe u; - size_t i; - if (len < 1) { - return; - } +static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_add_int(r, a); + r->magnitude += 1; + r->normalized = 0; - VERIFY_CHECK((r + len <= a) || (a + len <= r)); + SECP256K1_FE_VERIFY(r); +} - r[0] = a[0]; +static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); - i = 0; - while (++i < len) { - secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); - } + return secp256k1_fe_impl_is_zero(a); +} + +static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + return secp256k1_fe_impl_is_odd(a); +} + +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); +SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + + return secp256k1_fe_impl_cmp_var(a, b); +} + +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); + r->magnitude = 1; + r->normalized = 0; - secp256k1_fe_inv_var(&u, &r[--i]); + SECP256K1_FE_VERIFY(r); +} - while (i > 0) { - size_t j = i--; - secp256k1_fe_mul(&r[j], &r[i], &u); - secp256k1_fe_mul(&u, &u, &a[j]); +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + if (secp256k1_fe_impl_set_b32_limit(r, a)) { + r->magnitude = 1; + r->normalized = 1; + SECP256K1_FE_VERIFY(r); + return 1; + } else { + /* Mark the output field element as invalid. */ + r->magnitude = -1; + return 0; } +} + +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); - r[0] = u; + secp256k1_fe_impl_get_b32(r, a); } -static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { -#ifndef USE_NUM_NONE - unsigned char b[32]; - secp256k1_num n; - secp256k1_num m; - /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - static const unsigned char prime[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F - }; - - secp256k1_fe c = *a; - secp256k1_fe_normalize_var(&c); - secp256k1_fe_get_b32(b, &c); - secp256k1_num_set_bin(&n, b, 32); - secp256k1_num_set_bin(&m, prime, 32); - return secp256k1_num_jacobi(&n, &m) >= 0; -#else - secp256k1_fe r; - return secp256k1_fe_sqrt(&r, a); -#endif +static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); +SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(m >= 0 && m <= 31); + SECP256K1_FE_VERIFY_MAGNITUDE(a, m); + + secp256k1_fe_impl_negate_unchecked(r, a, m); + r->magnitude = m + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); } -#endif +static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) { + SECP256K1_FE_VERIFY(r); + + VERIFY_CHECK(a >= 0 && a <= 32); + VERIFY_CHECK(a*r->magnitude <= 32); + secp256k1_fe_impl_mul_int_unchecked(r, a); + r->magnitude *= a; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + + secp256k1_fe_impl_add(r, a); + r->magnitude += a->magnitude; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); +SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 8); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + + secp256k1_fe_impl_mul(r, a, b); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + + secp256k1_fe_impl_sqr(r, a); + r->magnitude = 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); +SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(r); + + secp256k1_fe_impl_cmov(r, a, flag); + if (a->magnitude > r->magnitude) r->magnitude = a->magnitude; + if (!a->normalized) r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { + SECP256K1_FE_VERIFY(a); + VERIFY_CHECK(a->normalized); + + secp256k1_fe_impl_to_storage(r, a); +} + +static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); +SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + secp256k1_fe_impl_from_storage(r, a); + r->magnitude = 1; + r->normalized = 1; + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + secp256k1_fe_impl_inv(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + SECP256K1_FE_VERIFY(x); + + secp256k1_fe_impl_inv_var(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + SECP256K1_FE_VERIFY(r); +} + +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); +SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + int ret; + secp256k1_fe tmp = *x, sqrt; + SECP256K1_FE_VERIFY(x); + + ret = secp256k1_fe_impl_is_square_var(x); + secp256k1_fe_normalize_weak(&tmp); + VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); + return ret; +} + +static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); +SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + + secp256k1_fe_impl_get_bounds(r, m); + r->magnitude = m; + r->normalized = (m == 0); + + SECP256K1_FE_VERIFY(r); +} + +static void secp256k1_fe_impl_half(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY_MAGNITUDE(r, 31); + + secp256k1_fe_impl_half(r); + r->magnitude = (r->magnitude >> 1) + 1; + r->normalized = 0; + + SECP256K1_FE_VERIFY(r); +} + +#endif /* defined(VERIFY) */ + +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/gen_context.c b/crypto/secp256k1/libsecp256k1/src/gen_context.c deleted file mode 100644 index 1835fd491..000000000 --- a/crypto/secp256k1/libsecp256k1/src/gen_context.c +++ /dev/null @@ -1,74 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#define USE_BASIC_CONFIG 1 - -#include "basic-config.h" -#include "include/secp256k1.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "ecmult_gen_impl.h" - -static void default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} - -static const secp256k1_callback default_error_callback = { - default_error_callback_fn, - NULL -}; - -int main(int argc, char **argv) { - secp256k1_ecmult_gen_context ctx; - int inner; - int outer; - FILE* fp; - - (void)argc; - (void)argv; - - fp = fopen("src/ecmult_static_context.h","w"); - if (fp == NULL) { - fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); - return -1; - } - - fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); - fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); - fprintf(fp, "#include \"group.h\"\n"); - fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); - fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); - - secp256k1_ecmult_gen_context_init(&ctx); - secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); - for(outer = 0; outer != 64; outer++) { - fprintf(fp,"{\n"); - for(inner = 0; inner != 16; inner++) { - fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); - if (inner != 15) { - fprintf(fp,",\n"); - } else { - fprintf(fp,"\n"); - } - } - if (outer != 63) { - fprintf(fp,"},\n"); - } else { - fprintf(fp,"}\n"); - } - } - fprintf(fp,"};\n"); - secp256k1_ecmult_gen_context_clear(&ctx); - - fprintf(fp, "#undef SC\n"); - fprintf(fp, "#endif\n"); - fclose(fp); - - return 0; -} diff --git a/crypto/secp256k1/libsecp256k1/src/group.h b/crypto/secp256k1/libsecp256k1/src/group.h index 4957b248f..992ff5c98 100644 --- a/crypto/secp256k1/libsecp256k1/src/group.h +++ b/crypto/secp256k1/libsecp256k1/src/group.h @@ -1,16 +1,18 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_GROUP_ -#define _SECP256K1_GROUP_ +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H -#include "num.h" #include "field.h" -/** A group element of the secp256k1 curve, in affine coordinates. */ +/** A group element in affine coordinates on the secp256k1 curve, + * or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6. + * Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ typedef struct { secp256k1_fe x; secp256k1_fe y; @@ -20,7 +22,9 @@ typedef struct { #define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} #define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} -/** A group element of the secp256k1 curve, in jacobian coordinates. */ +/** A group element of the secp256k1 curve, in jacobian coordinates. + * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve. + */ typedef struct { secp256k1_fe x; /* actual X: x/z^2 */ secp256k1_fe y; /* actual Y: y/z^3 */ @@ -40,44 +44,69 @@ typedef struct { #define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) +/** Maximum allowed magnitudes for group element coordinates + * in affine (x, y) and jacobian (x, y, z) representation. */ +#define SECP256K1_GE_X_MAGNITUDE_MAX 4 +#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 +#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 + /** Set a group element equal to the point with given X and Y coordinates */ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); -/** Set a group element (affine) equal to the point with the given X coordinate - * and a Y coordinate that is a quadratic residue modulo p. The return value - * is true iff a coordinate with the given X coordinate exists. - */ -static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); - /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); +/** Determine whether x is a valid X coordinate on the curve. */ +static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x); + +/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */ +static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd); + /** Check whether a group element is the point at infinity. */ static int secp256k1_ge_is_infinity(const secp256k1_ge *a); /** Check whether a group element is valid (i.e., on the curve). */ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); -/** Set a group element equal to another which is given in jacobian coordinates */ +/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); +/** Set a group element equal to another which is given in jacobian coordinates. */ +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a); + /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len); + +/** Bring a batch of inputs to the same global z "denominator", based on ratios between + * (omitted) z coordinates of adjacent elements. + * + * Although the elements a[i] are _ge rather than _gej, they actually represent elements + * in Jacobian coordinates with their z coordinates omitted. + * + * Using the notation z(b) to represent the omitted z coordinate of b, the array zr of + * z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len. + * The zr[0] value is unused. + * + * This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]). + * In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the + * a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is + * implicit. + * + * The coordinates of the final element a[len-1] are not changed. + */ +static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr); -/** Set a batch of group elements equal to the inputs given in jacobian - * coordinates (with known z-ratios). zr must contain the known z-ratios such - * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ -static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); +/** Check two group elements (affine) for equality in variable time. */ +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b); -/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to - * the same global z "denominator". zr must contain the known z-ratios such - * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y - * coordinates of the result are stored in r, the common z coordinate is - * stored in globalz. */ -static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); +/** Set a group element (affine) equal to the point at infinity. */ +static void secp256k1_ge_set_infinity(secp256k1_ge *r); /** Set a group element (jacobian) equal to the point at infinity. */ static void secp256k1_gej_set_infinity(secp256k1_gej *r); @@ -85,7 +114,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r); /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); -/** Compare the X coordinate of a group element (jacobian). */ +/** Check two group elements (jacobian) for equality in variable time. */ +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b); + +/** Check two group elements (jacobian and affine) for equality in variable time. */ +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b); + +/** Compare the X coordinate of a group element (jacobian). + * The magnitude of the group element's X coordinate must not exceed 31. */ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); /** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ @@ -94,17 +130,13 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ static int secp256k1_gej_is_infinity(const secp256k1_gej *a); -/** Check whether a group element's y coordinate is a quadratic residue. */ -static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); +/** Set r equal to the double of a. Constant time. */ +static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a); -/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). - * a may not be zero. Constant time. */ -static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); - -/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ +/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); -/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); /** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ @@ -112,16 +144,14 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const /** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ + guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); /** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); -#ifdef USE_ENDOMORPHISM /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); -#endif /** Clear a secp256k1_gej to prevent leaking sensitive information. */ static void secp256k1_gej_clear(secp256k1_gej *r); @@ -135,10 +165,48 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge /** Convert a group element back from the storage type. */ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); -#endif +/** Convert a group element that is not infinity to a 64-byte array. The output + * array is platform-dependent. */ +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a); + +/** Convert a 64-byte array into group element. This function assumes that the + * provided buffer correctly encodes a group element. */ +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); + +/** Convert a group element (that is allowed to be infinity) to a 64-byte + * array. The output array is platform-dependent. */ +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge); + +/** Convert a 64-byte array into a group element. This function assumes that the + * provided buffer is the output of secp256k1_ge_to_bytes_ext. */ +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data); + +/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. + * + * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the + * group, and this function returns always true. + * + * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a + * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this + * function checks whether a point that is on the curve is in fact also in that subgroup. + */ +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); + +/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ +static void secp256k1_ge_verify(const secp256k1_ge *a); +#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a) + +/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ +static void secp256k1_gej_verify(const secp256k1_gej *a); +#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a) + +#endif /* SECP256K1_GROUP_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/group_impl.h b/crypto/secp256k1/libsecp256k1/src/group_impl.h index 7d723532f..c668fb240 100644 --- a/crypto/secp256k1/libsecp256k1/src/group_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/group_impl.h @@ -1,104 +1,165 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_GROUP_IMPL_H_ -#define _SECP256K1_GROUP_IMPL_H_ +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H + +#include -#include "num.h" #include "field.h" #include "group.h" - -/* These points can be generated in sage as follows: - * - * 0. Setup a worksheet with the following parameters. - * b = 4 # whatever CURVE_B will be set to - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (b)]) - * - * 1. Determine all the small orders available to you. (If there are - * no satisfactory ones, go back and change b.) - * print C.order().factor(limit=1000) - * - * 2. Choose an order as one of the prime factors listed in the above step. - * (You can also multiply some to get a composite order, though the - * tests will crash trying to invert scalars during signing.) We take a - * random point and scale it to drop its order to the desired value. - * There is some probability this won't work; just try again. - * order = 199 - * P = C.random_point() - * P = (int(P.order()) / int(order)) * P - * assert(P.order() == order) - * - * 3. Print the values. You'll need to use a vim macro or something to - * split the hex output into 4-byte chunks. - * print "%x %x" % P.xy() +#include "util.h" + +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ + 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\ + 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\ + 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\ + 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\ +) +#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ + 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\ + 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\ + 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\ + 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\ +) +#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ + 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\ + 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\ + 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\ + 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\ +) +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +#define SECP256K1_G SECP256K1_GE_CONST(\ + 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\ + 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\ + 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\ + 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\ +) +/* These exhaustive group test orders and generators are chosen such that: + * - The field size is equal to that of secp256k1, so field code is the same. + * - The curve equation is of the form y^2=x^3+B for some small constant B. + * - The subgroup has a generator 2*P, where P.x is as small as possible. + * - The subgroup has size less than 1000 to permit exhaustive testing. + * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). */ #if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 199 -const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, - 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, - 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, - 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED -); - -const int CURVE_B = 4; +# if EXHAUSTIVE_TEST_ORDER == 7 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7; +#define SECP256K1_B 6 + # elif EXHAUSTIVE_TEST_ORDER == 13 -const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, - 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, - 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, - 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac -); -const int CURVE_B = 2; + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; +#define SECP256K1_B 2 + +# elif EXHAUSTIVE_TEST_ORDER == 199 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199; +#define SECP256K1_B 4 + # else # error No known generator for the specified exhaustive test group order. # endif #else -/** Generator for secp256k1, value 'g' defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - */ -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, - 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, - 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, - 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL -); - -const int CURVE_B = 7; + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; +#define SECP256K1_B 7 + #endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ + +static void secp256k1_ge_verify(const secp256k1_ge *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} + +static void secp256k1_gej_verify(const secp256k1_gej *a) { + SECP256K1_FE_VERIFY(&a->x); + SECP256K1_FE_VERIFY(&a->y); + SECP256K1_FE_VERIFY(&a->z); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); + SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + (void)a; +} +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + SECP256K1_GE_VERIFY(a); + SECP256K1_FE_VERIFY(zi); + VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->y, &a->y, &zi3); r->infinity = a->infinity; + + SECP256K1_GE_VERIFY(r); } static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { + SECP256K1_FE_VERIFY(x); + SECP256K1_FE_VERIFY(y); + r->infinity = 0; r->x = *x; r->y = *y; + + SECP256K1_GE_VERIFY(r); } static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + return a->infinity; } static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GE_VERIFY(r); } static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; + SECP256K1_GEJ_VERIFY(a); + r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -108,78 +169,99 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_set_int(&a->z, 1); r->x = a->x; r->y = a->y; + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); } static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; - r->infinity = a->infinity; - if (a->infinity) { + SECP256K1_GEJ_VERIFY(a); + + if (secp256k1_gej_is_infinity(a)) { + secp256k1_ge_set_infinity(r); return; } + r->infinity = 0; secp256k1_fe_inv_var(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_mul(&z3, &a->z, &z2); secp256k1_fe_mul(&a->x, &a->x, &z2); secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); - r->x = a->x; - r->y = a->y; + secp256k1_ge_set_xy(r, &a->x, &a->y); + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); } -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { - secp256k1_fe *az; - secp256k1_fe *azi; +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { + secp256k1_fe u; size_t i; - size_t count = 0; - az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); + size_t last_i = SIZE_MAX; +#ifdef VERIFY for (i = 0; i < len; i++) { - if (!a[i].infinity) { - az[count++] = a[i].z; + SECP256K1_GEJ_VERIFY(&a[i]); + } +#endif + + for (i = 0; i < len; i++) { + if (a[i].infinity) { + secp256k1_ge_set_infinity(&r[i]); + } else { + /* Use destination's x coordinates as scratch space */ + if (last_i == SIZE_MAX) { + r[i].x = a[i].z; + } else { + secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); + } + last_i = i; } } + if (last_i == SIZE_MAX) { + return; + } + secp256k1_fe_inv_var(&u, &r[last_i].x); - azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); - secp256k1_fe_inv_all_var(azi, az, count); - free(az); + i = last_i; + while (i > 0) { + i--; + if (!a[i].infinity) { + secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u); + secp256k1_fe_mul(&u, &u, &a[last_i].z); + last_i = i; + } + } + VERIFY_CHECK(!a[last_i].infinity); + r[last_i].x = u; - count = 0; for (i = 0; i < len; i++) { - r[i].infinity = a[i].infinity; if (!a[i].infinity) { - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); } } - free(azi); -} - -static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) { - size_t i = len - 1; - secp256k1_fe zi; - - if (len > 0) { - /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ - secp256k1_fe_inv(&zi, &a[i].z); - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); - /* Work out way backwards, using the z-ratios to scale the x/y values. */ - while (i > 0) { - secp256k1_fe_mul(&zi, &zi, &zr[i]); - i--; - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); - } +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&r[i]); } +#endif } -static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { - size_t i = len - 1; +static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) { + size_t i; secp256k1_fe zs; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + SECP256K1_FE_VERIFY(&zr[i]); + } +#endif if (len > 0) { - /* The z of the final point gives us the "global Z" for the table. */ - r[i].x = a[i].x; - r[i].y = a[i].y; - *globalz = a[i].z; - r[i].infinity = 0; + i = len - 1; + /* Ensure all y values are in weak normal form for fast negation of points */ + secp256k1_fe_normalize_weak(&a[i].y); zs = zr[i]; /* Work our way backwards, using the z-ratios to scale the x/y values. */ @@ -188,125 +270,193 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp secp256k1_fe_mul(&zs, &zs, &zr[i]); } i--; - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); + secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs); } } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + } +#endif } static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); - secp256k1_fe_clear(&r->z); + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + secp256k1_fe_set_int(&r->z, 0); + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_ge_set_infinity(secp256k1_ge *r) { + r->infinity = 1; + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + + SECP256K1_GE_VERIFY(r); } static void secp256k1_gej_clear(secp256k1_gej *r) { - r->infinity = 0; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); - secp256k1_fe_clear(&r->z); + secp256k1_memclear(r, sizeof(secp256k1_gej)); } static void secp256k1_ge_clear(secp256k1_ge *r) { - r->infinity = 0; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); + secp256k1_memclear(r, sizeof(secp256k1_ge)); } -static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { - secp256k1_fe x2, x3, c; +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + secp256k1_fe x2, x3; + int ret; + SECP256K1_FE_VERIFY(x); + r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&c, &x3); - return secp256k1_fe_sqrt(&r->y, &c); -} - -static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { - if (!secp256k1_ge_set_xquad(r, x)) { - return 0; - } + secp256k1_fe_add_int(&x3, SECP256K1_B); + ret = secp256k1_fe_sqrt(&r->y, &x3); secp256k1_fe_normalize_var(&r->y); if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); } - return 1; + SECP256K1_GE_VERIFY(r); + return ret; } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { + SECP256K1_GE_VERIFY(a); + r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); + + SECP256K1_GEJ_VERIFY(r); +} + +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej tmp; + SECP256K1_GEJ_VERIFY(b); + SECP256K1_GEJ_VERIFY(a); + + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) { + secp256k1_gej tmp; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) { + secp256k1_fe tmp; + SECP256K1_GE_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity != b->infinity) return 0; + if (a->infinity) return 1; + + tmp = a->x; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->x)) return 0; + + tmp = a->y; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->y)) return 0; + + return 1; } static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { - secp256k1_fe r, r2; + secp256k1_fe r; + SECP256K1_FE_VERIFY(x); + SECP256K1_GEJ_VERIFY(a); VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); - r2 = a->x; secp256k1_fe_normalize_weak(&r2); - return secp256k1_fe_equal_var(&r, &r2); + return secp256k1_fe_equal(&r, &a->x); } static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { + SECP256K1_GEJ_VERIFY(a); + r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); + + SECP256K1_GEJ_VERIFY(r); } static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { - return a->infinity; -} + SECP256K1_GEJ_VERIFY(a); -static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { - secp256k1_fe y2, x3, z2, z6; - if (a->infinity) { - return 0; - } - /** y^2 = x^3 + 7 - * (Y/Z^3)^2 = (X/Z^2)^3 + 7 - * Y^2 / Z^6 = X^3 / Z^6 + 7 - * Y^2 = X^3 + 7*Z^6 - */ - secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, CURVE_B); - secp256k1_fe_add(&x3, &z6); - secp256k1_fe_normalize_weak(&x3); - return secp256k1_fe_equal_var(&y2, &x3); + return a->infinity; } static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { - secp256k1_fe y2, x3, c; + secp256k1_fe y2, x3; + SECP256K1_GE_VERIFY(a); + if (a->infinity) { return 0; } /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&x3, &c); - secp256k1_fe_normalize_weak(&x3); - return secp256k1_fe_equal_var(&y2, &x3); + secp256k1_fe_add_int(&x3, SECP256K1_B); + return secp256k1_fe_equal(&y2, &x3); } -static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. - * - * Note that there is an implementation described at - * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - * which trades a multiply for a square, but in practice this is actually slower, - * mainly because it requires more normalizations. +static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) { + /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ + secp256k1_fe l, s, t; + SECP256K1_GEJ_VERIFY(a); + + r->infinity = a->infinity; + + /* Formula used: + * L = (3/2) * X1^2 + * S = Y1^2 + * T = -X1*S + * X3 = L^2 + 2*T + * Y3 = -(L*(X3 + T) + S^2) + * Z3 = Y1*Z1 */ - secp256k1_fe t1,t2,t3,t4; + + secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */ + secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */ + secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */ + secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */ + secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */ + secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */ + secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */ + secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */ + secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */ + secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */ + secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */ + secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */ + secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ + secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ + secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ + + SECP256K1_GEJ_VERIFY(r); +} + +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + SECP256K1_GEJ_VERIFY(a); + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. @@ -317,8 +467,8 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s * the infinity flag even though the point doubles to infinity, and the result * point will be gibberish (z = 0 but infinity = 0). */ - r->infinity = a->infinity; - if (r->infinity) { + if (a->infinity) { + secp256k1_gej_set_infinity(r); if (rzr != NULL) { secp256k1_fe_set_int(rzr, 1); } @@ -328,46 +478,24 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s if (rzr != NULL) { *rzr = a->y; secp256k1_fe_normalize_weak(rzr); - secp256k1_fe_mul_int(rzr, 2); } - secp256k1_fe_mul(&r->z, &a->z, &a->y); - secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ - secp256k1_fe_sqr(&t1, &a->x); - secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ - secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ - secp256k1_fe_sqr(&t3, &a->y); - secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ - secp256k1_fe_sqr(&t4, &t3); - secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ - secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */ - r->x = t3; - secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ - secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ - secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */ - secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */ - secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */ - secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */ - secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ - secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */ - secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ -} - -static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); - secp256k1_gej_double_var(r, a, rzr); + secp256k1_gej_double(r, a); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { - /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ - secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GEJ_VERIFY(b); if (a->infinity) { VERIFY_CHECK(rzr == NULL); *r = *b; return; } - if (b->infinity) { if (rzr != NULL) { secp256k1_fe_set_int(rzr, 1); @@ -376,7 +504,6 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons return; } - r->infinity = 0; secp256k1_fe_sqr(&z22, &b->z); secp256k1_fe_sqr(&z12, &a->z); secp256k1_fe_mul(&u1, &a->x, &z22); @@ -384,7 +511,7 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { secp256k1_gej_double_var(r, a, rzr); @@ -392,28 +519,42 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons if (rzr != NULL) { secp256k1_fe_set_int(rzr, 0); } - r->infinity = 1; + secp256k1_gej_set_infinity(r); } return; } - secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); - secp256k1_fe_mul(&h, &h, &b->z); + + r->infinity = 0; + secp256k1_fe_mul(&t, &h, &b->z); if (rzr != NULL) { - *rzr = h; + *rzr = t; } - secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&r->z, &a->z, &t); + + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { - /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + /* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + if (a->infinity) { VERIFY_CHECK(rzr == NULL); secp256k1_gej_set_ge(r, b); @@ -426,15 +567,14 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c *r = *a; return; } - r->infinity = 0; secp256k1_fe_sqr(&z12, &a->z); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); + u1 = a->x; secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); + s1 = a->y; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { secp256k1_gej_double_var(r, a, rzr); @@ -442,32 +582,43 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c if (rzr != NULL) { secp256k1_fe_set_int(rzr, 0); } - r->infinity = 1; + secp256k1_gej_set_infinity(r); } return; } - secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); + + r->infinity = 0; if (rzr != NULL) { *rzr = h; } secp256k1_fe_mul(&r->z, &a->z, &h); + + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); + if (rzr != NULL) SECP256K1_FE_VERIFY(rzr); } static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { - /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + /* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + SECP256K1_FE_VERIFY(bzinv); - if (b->infinity) { - *r = *a; - return; - } if (a->infinity) { secp256k1_fe bzinv2, bzinv3; r->infinity = b->infinity; @@ -476,9 +627,13 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&r->x, &b->x, &bzinv2); secp256k1_fe_mul(&r->y, &b->y, &bzinv3); secp256k1_fe_set_int(&r->z, 1); + SECP256K1_GEJ_VERIFY(r); + return; + } + if (b->infinity) { + *r = *a; return; } - r->infinity = 0; /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to * secp256k1's isomorphism we can multiply the Z coordinates on both sides @@ -491,42 +646,53 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&az, &a->z, bzinv); secp256k1_fe_sqr(&z12, &az); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); + u1 = a->x; secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); + s1 = a->y; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { secp256k1_gej_double_var(r, a, NULL); } else { - r->infinity = 1; + secp256k1_gej_set_infinity(r); } return; } - secp256k1_fe_sqr(&i2, &i); + + r->infinity = 0; + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); - r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_negate(&h2, &h2, 1); + secp256k1_fe_mul(&h3, &h2, &h); secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + + secp256k1_fe_sqr(&r->x, &i); + secp256k1_fe_add(&r->x, &h3); + secp256k1_fe_add(&r->x, &t); + secp256k1_fe_add(&r->x, &t); + + secp256k1_fe_add(&t, &r->x); + secp256k1_fe_mul(&r->y, &t, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { - /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ - static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + /* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */ secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe m_alt, rr_alt; - int infinity, degenerate; + int degenerate; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); VERIFY_CHECK(!b->infinity); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - /** In: + /* In: * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. * we find as solution for a unified addition/doubling formula: @@ -540,11 +706,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const * Z = Z1*Z2 * T = U1+U2 * M = S1+S2 - * Q = T*M^2 + * Q = -T*M^2 * R = T^2-U1*U2 - * X3 = 4*(R^2-Q) - * Y3 = 4*(R*(3*Q-2*R^2)-M^4) - * Z3 = 2*M*Z + * X3 = R^2+Q + * Y3 = -(R*(2*X3+Q)+M^4)/2 + * Z3 = M*Z * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) * * This formula has the benefit of being the same for both addition @@ -577,82 +743,104 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const */ secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */ secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */ secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ - m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */ secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ - secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ - /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" - * case that Z = z1z2 = 0, and this is special-cased later on). */ - degenerate = secp256k1_fe_normalizes_to_zero(&m) & - secp256k1_fe_normalizes_to_zero(&rr); + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */ + /* If lambda = R/M = R/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m); /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. * This means either x1 == beta*x2 or beta*x1 == x2, where beta is * a nontrivial cube root of one. In either case, an alternate * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), * so we set R/M equal to this. */ rr_alt = s1; - secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ - secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ + secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */ - secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); - secp256k1_fe_cmov(&m_alt, &m, !degenerate); - /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */ + secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */ + /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. * From here on out Ralt and Malt represent the numerator * and denominator of lambda; R and M represent the explicit * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + secp256k1_fe_negate(&q, &t, + SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */ + secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ /* These two lines use the observation that either M == Malt or M == 0, * so M^3 * Malt is either Malt^4 (which is computed by squaring), or * zero (which is "computed" by cmov). So the cost is one squaring * versus two multiplications. */ - secp256k1_fe_sqr(&n, &n); - secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */ + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */ secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ - secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ - secp256k1_fe_normalize_weak(&t); - r->x = t; /* r->x = Ralt^2-Q (1) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ - secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ - secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ - - /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ + r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ + secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */ + secp256k1_fe_negate(&r->y, &t, + SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */ + secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */ + + /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity); - secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); - r->infinity = infinity; + secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity); + + /* Set r->infinity if r->z is 0. + * + * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false, + * which is correct because the function assumes that b is not infinity. + * + * Now assume !a->infinity. This implies Z = Z1 != 0. + * + * Case y1 = -y2: + * In this case we could have a = -b, namely if x1 = x2. + * We have degenerate = true, r->z = (x1 - x2) * Z. + * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b). + * + * Case y1 != -y2: + * In this case, we can't have a = -b. + * We have degenerate = false, r->z = (y1 + y2) * Z. + * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ + r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ secp256k1_fe zz; - VERIFY_CHECK(!secp256k1_fe_is_zero(s)); + SECP256K1_GEJ_VERIFY(r); + SECP256K1_FE_VERIFY(s); + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s)); + secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->y, &r->y, &zz); secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { secp256k1_fe x, y; + SECP256K1_GE_VERIFY(a); VERIFY_CHECK(!a->infinity); + x = a->x; secp256k1_fe_normalize(&x); y = a->y; @@ -665,6 +853,20 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; + + SECP256K1_GE_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { + SECP256K1_GEJ_VERIFY(r); + SECP256K1_GEJ_VERIFY(a); + + secp256k1_fe_cmov(&r->x, &a->x, flag); + secp256k1_fe_cmov(&r->y, &a->y, flag); + secp256k1_fe_cmov(&r->z, &a->z, flag); + r->infinity ^= (r->infinity ^ a->infinity) & flag; + + SECP256K1_GEJ_VERIFY(r); } static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { @@ -672,29 +874,101 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } -#ifdef USE_ENDOMORPHISM static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { - static const secp256k1_fe beta = SECP256K1_FE_CONST( - 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, - 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul - ); + SECP256K1_GE_VERIFY(a); + *r = *a; - secp256k1_fe_mul(&r->x, &r->x, &beta); + secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); + + SECP256K1_GE_VERIFY(r); } + +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { +#ifdef EXHAUSTIVE_TEST_ORDER + secp256k1_gej out; + int i; + SECP256K1_GE_VERIFY(ge); + + /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ + secp256k1_gej_set_infinity(&out); + for (i = 0; i < 32; ++i) { + secp256k1_gej_double_var(&out, &out, NULL); + if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { + secp256k1_gej_add_ge_var(&out, &out, ge, NULL); + } + } + return secp256k1_gej_is_infinity(&out); +#else + SECP256K1_GE_VERIFY(ge); + + (void)ge; + /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ + return 1; #endif +} -static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { - secp256k1_fe yz; +static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) { + secp256k1_fe c; + secp256k1_fe_sqr(&c, x); + secp256k1_fe_mul(&c, &c, x); + secp256k1_fe_add_int(&c, SECP256K1_B); + return secp256k1_fe_is_square_var(&c); +} - if (a->infinity) { - return 0; +static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) { + /* We want to determine whether (xn/xd) is on the curve. + * + * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square). + */ + secp256k1_fe r, t; + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd)); + + secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */ + secp256k1_fe_sqr(&t, xn); /* t = xn^2 */ + secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */ + secp256k1_fe_sqr(&t, xd); /* t = xd^2 */ + secp256k1_fe_sqr(&t, &t); /* t = xd^4 */ + VERIFY_CHECK(SECP256K1_B <= 31); + secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */ + secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */ + return secp256k1_fe_is_square_var(&r); +} + +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) { + secp256k1_ge_storage s; + + /* We require that the secp256k1_ge_storage type is exactly 64 bytes. + * This is formally not guaranteed by the C standard, but should hold on any + * sane compiler in the real world. */ + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + VERIFY_CHECK(!secp256k1_ge_is_infinity(a)); + secp256k1_ge_to_storage(&s, a); + memcpy(buf, &s, 64); +} + +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { + secp256k1_ge_storage s; + + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + memcpy(&s, buf, 64); + secp256k1_ge_from_storage(r, &s); +} + +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(data, 0, 64); + } else { + secp256k1_ge_to_bytes(data, ge); } +} - /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as - * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z - is */ - secp256k1_fe_mul(&yz, &a->y, &a->z); - return secp256k1_fe_is_quad_var(&yz); +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) { + static const unsigned char zeros[64] = { 0 }; + if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + } else { + secp256k1_ge_from_bytes(ge, data); + } } -#endif +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/hash.h b/crypto/secp256k1/libsecp256k1/src/hash.h index fca98cab9..6d903ca7e 100644 --- a/crypto/secp256k1/libsecp256k1/src/hash.h +++ b/crypto/secp256k1/libsecp256k1/src/hash.h @@ -1,41 +1,44 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_HASH_ -#define _SECP256K1_HASH_ +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H #include #include typedef struct { uint32_t s[8]; - uint32_t buf[16]; /* In big endian */ - size_t bytes; -} secp256k1_sha256_t; + unsigned char buf[64]; + uint64_t bytes; +} secp256k1_sha256; -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); +static void secp256k1_sha256_clear(secp256k1_sha256 *hash); typedef struct { - secp256k1_sha256_t inner, outer; -} secp256k1_hmac_sha256_t; + secp256k1_sha256 inner, outer; +} secp256k1_hmac_sha256; -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash); typedef struct { unsigned char v[32]; unsigned char k[32]; int retry; -} secp256k1_rfc6979_hmac_sha256_t; +} secp256k1_rfc6979_hmac_sha256; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); +static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng); -#endif +#endif /* SECP256K1_HASH_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/hash_impl.h b/crypto/secp256k1/libsecp256k1/src/hash_impl.h index b47e65f83..956e0ea48 100644 --- a/crypto/secp256k1/libsecp256k1/src/hash_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/hash_impl.h @@ -1,13 +1,14 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_HASH_IMPL_H_ -#define _SECP256K1_HASH_IMPL_H_ +#ifndef SECP256K1_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H #include "hash.h" +#include "util.h" #include #include @@ -27,13 +28,7 @@ (h) = t1 + t2; \ } while(0) -#ifdef WORDS_BIGENDIAN -#define BE32(x) (x) -#else -#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#endif - -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; hash->s[2] = 0x3c6ef372ul; @@ -46,26 +41,26 @@ static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { } /** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { +static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); - Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); - Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); - Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); - Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); - Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); - Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60])); Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); @@ -128,47 +123,66 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { s[7] += h; } -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; - while (bufsize + len >= 64) { + VERIFY_CHECK(hash->bytes >= len); + while (len >= 64 - bufsize) { /* Fill the buffer, and process it. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize); - data += 64 - bufsize; - len -= 64 - bufsize; + size_t chunk_len = 64 - bufsize; + memcpy(hash->buf + bufsize, data, chunk_len); + data += chunk_len; + len -= chunk_len; secp256k1_sha256_transform(hash->s, hash->buf); bufsize = 0; } if (len) { /* Fill the buffer with what remains. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + memcpy(hash->buf + bufsize, data, len); } } -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { - static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t sizedesc[2]; - uint32_t out[8]; - int i = 0; - sizedesc[0] = BE32(hash->bytes >> 29); - sizedesc[1] = BE32(hash->bytes << 3); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80}; + unsigned char sizedesc[8]; + int i; + /* The maximum message size of SHA256 is 2^64-1 bits. */ + VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61)); + secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29); + secp256k1_write_be32(&sizedesc[4], hash->bytes << 3); secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); - secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8); + secp256k1_sha256_write(hash, sizedesc, 8); for (i = 0; i < 8; i++) { - out[i] = BE32(hash->s[i]); + secp256k1_write_be32(&out32[4*i], hash->s[i]); hash->s[i] = 0; } - memcpy(out32, (const unsigned char*)out, 32); } -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { - int n; +/* Initializes a sha256 struct and writes the 64 byte string + * SHA256(tag)||SHA256(tag) into it. */ +static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { + unsigned char buf[32]; + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, tag, taglen); + secp256k1_sha256_finalize(hash, buf); + + secp256k1_sha256_initialize(hash); + secp256k1_sha256_write(hash, buf, 32); + secp256k1_sha256_write(hash, buf, 32); +} + +static void secp256k1_sha256_clear(secp256k1_sha256 *hash) { + secp256k1_memclear(hash, sizeof(*hash)); +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { + size_t n; unsigned char rkey[64]; - if (keylen <= 64) { + if (keylen <= sizeof(rkey)) { memcpy(rkey, key, keylen); - memset(rkey + keylen, 0, 64 - keylen); + memset(rkey + keylen, 0, sizeof(rkey) - keylen); } else { - secp256k1_sha256_t sha256; + secp256k1_sha256 sha256; secp256k1_sha256_initialize(&sha256); secp256k1_sha256_write(&sha256, key, keylen); secp256k1_sha256_finalize(&sha256, rkey); @@ -176,34 +190,37 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons } secp256k1_sha256_initialize(&hash->outer); - for (n = 0; n < 64; n++) { + for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c; } - secp256k1_sha256_write(&hash->outer, rkey, 64); + secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); secp256k1_sha256_initialize(&hash->inner); - for (n = 0; n < 64; n++) { + for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c ^ 0x36; } - secp256k1_sha256_write(&hash->inner, rkey, 64); - memset(rkey, 0, 64); + secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey)); + secp256k1_memclear(rkey, sizeof(rkey)); } -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { secp256k1_sha256_write(&hash->inner, data, size); } -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { unsigned char temp[32]; secp256k1_sha256_finalize(&hash->inner, temp); secp256k1_sha256_write(&hash->outer, temp, 32); - memset(temp, 0, 32); + secp256k1_memclear(temp, sizeof(temp)); secp256k1_sha256_finalize(&hash->outer, out32); } +static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) { + secp256k1_memclear(hash, sizeof(*hash)); +} -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { - secp256k1_hmac_sha256_t hmac; +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -232,11 +249,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 rng->retry = 0; } -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); @@ -247,7 +264,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 } while (outlen > 0) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; int now = outlen; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -263,13 +280,14 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 rng->retry = 1; } -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { - memset(rng->k, 0, 32); - memset(rng->v, 0, 32); - rng->retry = 0; +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { + (void) rng; +} + +static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) { + secp256k1_memclear(rng, sizeof(*rng)); } -#undef BE32 #undef Round #undef sigma1 #undef sigma0 @@ -278,4 +296,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 #undef Maj #undef Ch -#endif +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/hsort.h b/crypto/secp256k1/libsecp256k1/src/hsort.h new file mode 100644 index 000000000..d54995caa --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/hsort.h @@ -0,0 +1,33 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_H +#define SECP256K1_HSORT_H + +#include +#include + +/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This + * is preferred over standard library implementations because they generally + * make no guarantee about being fast for malicious inputs. + * Remember that heapsort is unstable. + * + * In/Out: ptr: pointer to the array to sort. The contents of the array are + * sorted in ascending order according to the comparison function. + * In: count: number of elements in the array. + * size: size in bytes of each element. + * cmp: pointer to a comparison function that is called with two + * arguments that point to the objects being compared. The cmp_data + * argument of secp256k1_hsort is passed as third argument. The + * function must return an integer less than, equal to, or greater + * than zero if the first argument is considered to be respectively + * less than, equal to, or greater than the second. + * cmp_data: pointer passed as third argument to cmp. + */ +static void secp256k1_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data); +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/hsort_impl.h b/crypto/secp256k1/libsecp256k1/src/hsort_impl.h new file mode 100644 index 000000000..1c674ff1c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/hsort_impl.h @@ -0,0 +1,125 @@ +/*********************************************************************** + * Copyright (c) 2021 Russell O'Connor, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_HSORT_IMPL_H +#define SECP256K1_HSORT_IMPL_H + +#include "hsort.h" + +/* An array is a heap when, for all non-zero indexes i, the element at index i + * compares as less than or equal to the element at index parent(i) = (i-1)/2. + */ + +static SECP256K1_INLINE size_t secp256k1_heap_child1(size_t i) { + VERIFY_CHECK(i <= (SIZE_MAX - 1)/2); + return 2*i + 1; +} + +static SECP256K1_INLINE size_t secp256k1_heap_child2(size_t i) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + return secp256k1_heap_child1(i)+1; +} + +static SECP256K1_INLINE void secp256k1_heap_swap64(unsigned char *a, unsigned char *b, size_t len) { + unsigned char tmp[64]; + VERIFY_CHECK(len <= 64); + memcpy(tmp, a, len); + memmove(a, b, len); + memcpy(b, tmp, len); +} + +static SECP256K1_INLINE void secp256k1_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) { + unsigned char *a = arr + i*stride; + unsigned char *b = arr + j*stride; + size_t len = stride; + while (64 < len) { + secp256k1_heap_swap64(a + (len - 64), b + (len - 64), 64); + len -= 64; + } + secp256k1_heap_swap64(a, b, len); +} + +/* This function accepts an array arr containing heap_size elements, each of + * size stride. The elements in the array at indices >i satisfy the max-heap + * property, i.e., for any element at index j (where j > i), all of its children + * are smaller than the element itself. The purpose of the function is to update + * the array so that all elements at indices >=i satisfy the max-heap + * property. */ +static SECP256K1_INLINE void secp256k1_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride, + int (*cmp)(const void *, const void *, void *), void *cmp_data) { + while (i < heap_size/2) { + VERIFY_CHECK(i <= SIZE_MAX/2 - 1); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size <= SIZE_MAX + * 2*i <= SIZE_MAX - 2 + */ + + VERIFY_CHECK(secp256k1_heap_child1(i) < heap_size); + /* Proof: + * i < heap_size/2 + * i + 1 <= heap_size/2 + * 2*i + 2 <= heap_size + * 2*i + 1 < heap_size + * child1(i) < heap_size + */ + + /* Let [x] be notation for the contents at arr[x*stride]. + * + * If [child1(i)] > [i] and [child2(i)] > [i], + * swap [i] with the larger child to ensure the new parent is larger + * than both children. When [child1(i)] == [child2(i)], swap [i] with + * [child2(i)]. + * Else if [child1(i)] > [i], swap [i] with [child1(i)]. + * Else if [child2(i)] > [i], swap [i] with [child2(i)]. + */ + if (secp256k1_heap_child2(i) < heap_size + && 0 <= cmp(arr + secp256k1_heap_child2(i)*stride, arr + secp256k1_heap_child1(i)*stride, cmp_data)) { + if (0 < cmp(arr + secp256k1_heap_child2(i)*stride, arr + i*stride, cmp_data)) { + secp256k1_heap_swap(arr, i, secp256k1_heap_child2(i), stride); + i = secp256k1_heap_child2(i); + } else { + /* At this point we have [child2(i)] >= [child1(i)] and we have + * [child2(i)] <= [i], and thus [child1(i)] <= [i] which means + * that the next comparison can be skipped. */ + return; + } + } else if (0 < cmp(arr + secp256k1_heap_child1(i)*stride, arr + i*stride, cmp_data)) { + secp256k1_heap_swap(arr, i, secp256k1_heap_child1(i), stride); + i = secp256k1_heap_child1(i); + } else { + return; + } + } + /* heap_size/2 <= i + * heap_size/2 < i + 1 + * heap_size < 2*i + 2 + * heap_size <= 2*i + 1 + * heap_size <= child1(i) + * Thus child1(i) and child2(i) are now out of bounds and we are at a leaf. + */ +} + +/* In-place heap sort. */ +static void secp256k1_hsort(void *ptr, size_t count, size_t size, + int (*cmp)(const void *, const void *, void *), + void *cmp_data) { + size_t i; + + for (i = count/2; 0 < i; --i) { + secp256k1_heap_down(ptr, i-1, count, size, cmp, cmp_data); + } + for (i = count; 1 < i; --i) { + /* Extract the largest value from the heap */ + secp256k1_heap_swap(ptr, 0, i-1, size); + + /* Repair the heap condition */ + secp256k1_heap_down(ptr, 0, i-1, size, cmp, cmp_data); + } +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128.h b/crypto/secp256k1/libsecp256k1/src/int128.h new file mode 100644 index 000000000..5355fbfae --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128.h @@ -0,0 +1,90 @@ +#ifndef SECP256K1_INT128_H +#define SECP256K1_INT128_H + +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct.h" +# else +# error "Please select int128 implementation" +# endif + +/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo); + +/* Multiply two unsigned 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Multiply two unsigned 64-bit values a and b and add the result to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Add an unsigned 64-bit value a to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a); + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n); + +/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a); + +/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a); + +/* Write an unsigned 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a); + +/* Tests if r is strictly less than to 2^n. + * n must be strictly less than 128. + */ +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n); + +/* Construct an signed 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo); + +/* Multiply two signed 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Multiply two signed 64-bit values a and b and add the result to r. + * Overflow or underflow from the addition is undefined behaviour. + */ +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Compute a*d - b*c from signed 64-bit values and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d); + +/* Signed (arithmetic) right shift. + * Non-constant time in b. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b); + +/* Return the input value modulo 2^64. */ +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a); + +/* Return the value as a signed 64-bit value. + * Requires the input to be between INT64_MIN and INT64_MAX. + */ +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a); + +/* Write a signed 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a); + +/* Compare two 128-bit values for equality. */ +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); + +/* Tests if r is equal to sign*2^n (sign must be 1 or -1). + * n must be strictly less than 127. + */ +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign); + +#endif + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128_impl.h b/crypto/secp256k1/libsecp256k1/src/int128_impl.h new file mode 100644 index 000000000..cfc573408 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128_impl.h @@ -0,0 +1,18 @@ +#ifndef SECP256K1_INT128_IMPL_H +#define SECP256K1_INT128_IMPL_H + +#include "util.h" + +#include "int128.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native_impl.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct_impl.h" +# else +# error "Please select int128 implementation" +# endif +#endif + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128_native.h b/crypto/secp256k1/libsecp256k1/src/int128_native.h new file mode 100644 index 000000000..7c97aafc7 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128_native.h @@ -0,0 +1,19 @@ +#ifndef SECP256K1_INT128_NATIVE_H +#define SECP256K1_INT128_NATIVE_H + +#include +#include "util.h" + +#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +SECP256K1_GNUC_EXT typedef __int128 int128_t; +# define UINT128_MAX ((uint128_t)(-1)) +# define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) +# define INT128_MIN (-INT128_MAX - 1) +/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ +#endif + +typedef uint128_t secp256k1_uint128; +typedef int128_t secp256k1_int128; + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128_native_impl.h b/crypto/secp256k1/libsecp256k1/src/int128_native_impl.h new file mode 100644 index 000000000..7f02e1590 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128_native_impl.h @@ -0,0 +1,94 @@ +#ifndef SECP256K1_INT128_NATIVE_IMPL_H +#define SECP256K1_INT128_NATIVE_IMPL_H + +#include "int128.h" +#include "util.h" + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + *r = (((uint128_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r = (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r += (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + *r += a; +} + +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a); +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a >> 64); +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return (*r >> n == 0); +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + *r = (((uint128_t)(uint64_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + *r = (int128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int128_t ab = (int128_t)a * b; + VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r); + *r += ab; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + int128_t ad = (int128_t)a * d; + int128_t bc = (int128_t)b * c; + VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc); + *r = ad - bc; +} + +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { + return (uint64_t)*a; +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX); + return *a; +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return *a == *b; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return (*r == (int128_t)((uint128_t)sign << n)); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128_struct.h b/crypto/secp256k1/libsecp256k1/src/int128_struct.h new file mode 100644 index 000000000..6156f82cc --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128_struct.h @@ -0,0 +1,14 @@ +#ifndef SECP256K1_INT128_STRUCT_H +#define SECP256K1_INT128_STRUCT_H + +#include +#include "util.h" + +typedef struct { + uint64_t lo; + uint64_t hi; +} secp256k1_uint128; + +typedef secp256k1_uint128 secp256k1_int128; + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/int128_struct_impl.h b/crypto/secp256k1/libsecp256k1/src/int128_struct_impl.h new file mode 100644 index 000000000..962a71d13 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/int128_struct_impl.h @@ -0,0 +1,205 @@ +#ifndef SECP256K1_INT128_STRUCT_IMPL_H +#define SECP256K1_INT128_STRUCT_IMPL_H + +#include "int128.h" +#include "util.h" + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ +# include +# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. + (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64, + which supports both __(u)mulh and _umul128.) */ +# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.") +# endif +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + *hi = __umulh(a, b); + return a * b; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + *hi = __mulh(a, b); + return (uint64_t)a * (uint64_t)b; +} +# else +/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */ +# define secp256k1_umul128 _umul128 +# define secp256k1_mul128 _mul128 +# endif +#else +/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */ +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + uint64_t lh = (uint32_t)a * (b >> 32); + uint64_t hl = (a >> 32) * (uint32_t)b; + uint64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + int64_t lh = (uint32_t)a * (b >> 32); + int64_t hl = (a >> 32) * (uint32_t)b; + int64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} +#endif + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + r->lo = secp256k1_umul128(a, b, &r->hi); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + uint64_t lo, hi; + lo = secp256k1_umul128(a, b, &hi); + r->lo += lo; + r->hi += hi + (r->lo < lo); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + r->lo += a; + r->hi += r->lo < a; +} + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = r->hi >> (n-64); + r->hi = 0; + } else if (n > 0) { +#if defined(_MSC_VER) && defined(_M_X64) + VERIFY_CHECK(n < 64); + r->lo = __shiftright128(r->lo, r->hi, n); +#else + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; +#endif + r->hi >>= n; + } +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return a->lo; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return a->hi; +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + r->hi = 0; + r->lo = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return n >= 64 ? r->hi >> (n - 64) == 0 + : r->hi == 0 && r->lo >> n == 0; +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + r->lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->hi = (uint64_t)hi; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->lo += lo; + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set), + * then we require that the resulting value also be positive (the sign bit is not set). + * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi += hi; +} + +static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set), + * then we require that the resulting value also be positive (the sign bit is not set). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi -= hi; + r->lo -= lo; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + secp256k1_i128_mul(r, a, d); + secp256k1_i128_dissip_mul(r, b, c); +} + +/* Signed (arithmetic) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64)); + r->hi = (uint64_t)((int64_t)(r->hi) >> 63); + } else if (n > 0) { + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; + r->hi = (uint64_t)((int64_t)(r->hi) >> n); + } +} + +static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) { + return a->lo; +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */ + VERIFY_CHECK(a->hi == -(a->lo >> 63)); + return (int64_t)secp256k1_i128_to_u64(a); +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + r->hi = (uint64_t)(a >> 63); + r->lo = (uint64_t)a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return a->hi == b->hi && a->lo == b->lo; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 + : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java deleted file mode 100644 index 1c67802fb..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bitcoin; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import java.math.BigInteger; -import com.google.common.base.Preconditions; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import static org.bitcoin.NativeSecp256k1Util.*; - -/** - *

This class holds native methods to handle ECDSA verification.

- * - *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

- * - *

To build secp256k1 for use with bitcoinj, run - * `./configure --enable-jni --enable-experimental --enable-module-ecdh` - * and `make` then copy `.libs/libsecp256k1.so` to your system library path - * or point the JVM to the folder containing it with -Djava.library.path - *

- */ -public class NativeSecp256k1 { - - private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - private static final Lock r = rwl.readLock(); - private static final Lock w = rwl.writeLock(); - private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); - /** - * Verifies the given secp256k1 signature in native code. - * Calling when enabled == false is undefined (probably library not loaded) - * - * @param data The data which was signed, must be exactly 32 bytes - * @param signature The signature - * @param pub The public key which did the signing - */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ - Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < 520) { - byteBuff = ByteBuffer.allocateDirect(520); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(data); - byteBuff.put(signature); - byteBuff.put(pub); - - byte[][] retByteArray; - - r.lock(); - try { - return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; - } finally { - r.unlock(); - } - } - - /** - * libsecp256k1 Create an ECDSA signature. - * - * @param data Message hash, 32 bytes - * @param key Secret key, 32 bytes - * - * Return values - * @param sig byte array of signature - */ - public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ - Preconditions.checkArgument(data.length == 32 && sec.length <= 32); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < 32 + 32) { - byteBuff = ByteBuffer.allocateDirect(32 + 32); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(data); - byteBuff.put(sec); - - byte[][] retByteArray; - - r.lock(); - try { - retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); - } finally { - r.unlock(); - } - - byte[] sigArr = retByteArray[0]; - int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(sigArr.length, sigLen, "Got bad signature length."); - - return retVal == 0 ? new byte[0] : sigArr; - } - - /** - * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid - * - * @param seckey ECDSA Secret key, 32 bytes - */ - public static boolean secKeyVerify(byte[] seckey) { - Preconditions.checkArgument(seckey.length == 32); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < seckey.length) { - byteBuff = ByteBuffer.allocateDirect(seckey.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(seckey); - - r.lock(); - try { - return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; - } finally { - r.unlock(); - } - } - - - /** - * libsecp256k1 Compute Pubkey - computes public key from secret key - * - * @param seckey ECDSA Secret key, 32 bytes - * - * Return values - * @param pubkey ECDSA Public key, 33 or 65 bytes - */ - //TODO add a 'compressed' arg - public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ - Preconditions.checkArgument(seckey.length == 32); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < seckey.length) { - byteBuff = ByteBuffer.allocateDirect(seckey.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(seckey); - - byte[][] retByteArray; - - r.lock(); - try { - retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); - } finally { - r.unlock(); - } - - byte[] pubArr = retByteArray[0]; - int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); - - return retVal == 0 ? new byte[0]: pubArr; - } - - /** - * libsecp256k1 Cleanup - This destroys the secp256k1 context object - * This should be called at the end of the program for proper cleanup of the context. - */ - public static synchronized void cleanup() { - w.lock(); - try { - secp256k1_destroy_context(Secp256k1Context.getContext()); - } finally { - w.unlock(); - } - } - - public static long cloneContext() { - r.lock(); - try { - return secp256k1_ctx_clone(Secp256k1Context.getContext()); - } finally { r.unlock(); } - } - - /** - * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it - * - * @param tweak some bytes to tweak with - * @param seckey 32-byte seckey - */ - public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ - Preconditions.checkArgument(privkey.length == 32); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { - byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(privkey); - byteBuff.put(tweak); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); - } finally { - r.unlock(); - } - - byte[] privArr = retByteArray[0]; - - int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(privArr.length, privLen, "Got bad pubkey length."); - - assertEquals(retVal, 1, "Failed return value check."); - - return privArr; - } - - /** - * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it - * - * @param tweak some bytes to tweak with - * @param seckey 32-byte seckey - */ - public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ - Preconditions.checkArgument(privkey.length == 32); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { - byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(privkey); - byteBuff.put(tweak); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); - } finally { - r.unlock(); - } - - byte[] privArr = retByteArray[0]; - - int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(privArr.length, privLen, "Got bad pubkey length."); - - assertEquals(retVal, 1, "Failed return value check."); - - return privArr; - } - - /** - * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it - * - * @param tweak some bytes to tweak with - * @param pubkey 32-byte seckey - */ - public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ - Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { - byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(pubkey); - byteBuff.put(tweak); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); - } finally { - r.unlock(); - } - - byte[] pubArr = retByteArray[0]; - - int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); - - assertEquals(retVal, 1, "Failed return value check."); - - return pubArr; - } - - /** - * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it - * - * @param tweak some bytes to tweak with - * @param pubkey 32-byte seckey - */ - public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ - Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { - byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(pubkey); - byteBuff.put(tweak); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); - } finally { - r.unlock(); - } - - byte[] pubArr = retByteArray[0]; - - int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; - int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); - - assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); - - assertEquals(retVal, 1, "Failed return value check."); - - return pubArr; - } - - /** - * libsecp256k1 create ECDH secret - constant time ECDH calculation - * - * @param seckey byte array of secret key used in exponentiaion - * @param pubkey byte array of public key used in exponentiaion - */ - public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ - Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { - byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(seckey); - byteBuff.put(pubkey); - - byte[][] retByteArray; - r.lock(); - try { - retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); - } finally { - r.unlock(); - } - - byte[] resArr = retByteArray[0]; - int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); - - assertEquals(resArr.length, 32, "Got bad result length."); - assertEquals(retVal, 1, "Failed return value check."); - - return resArr; - } - - /** - * libsecp256k1 randomize - updates the context randomization - * - * @param seed 32-byte random seed - */ - public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ - Preconditions.checkArgument(seed.length == 32 || seed == null); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < seed.length) { - byteBuff = ByteBuffer.allocateDirect(seed.length); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(seed); - - w.lock(); - try { - return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; - } finally { - w.unlock(); - } - } - - private static native long secp256k1_ctx_clone(long context); - - private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); - - private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); - - private static native void secp256k1_destroy_context(long context); - - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); - - private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); - - private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); - - private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); - - private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); - -} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java deleted file mode 100644 index c00d08899..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java +++ /dev/null @@ -1,226 +0,0 @@ -package org.bitcoin; - -import com.google.common.io.BaseEncoding; -import java.util.Arrays; -import java.math.BigInteger; -import javax.xml.bind.DatatypeConverter; -import static org.bitcoin.NativeSecp256k1Util.*; - -/** - * This class holds test cases defined for testing this library. - */ -public class NativeSecp256k1Test { - - //TODO improve comments/add more tests - /** - * This tests verify() for a valid signature - */ - public static void testVerifyPos() throws AssertFailException{ - boolean result = false; - byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); - byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - - result = NativeSecp256k1.verify( data, sig, pub); - assertEquals( result, true , "testVerifyPos"); - } - - /** - * This tests verify() for a non-valid signature - */ - public static void testVerifyNeg() throws AssertFailException{ - boolean result = false; - byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" - byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); - byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - - result = NativeSecp256k1.verify( data, sig, pub); - //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); - assertEquals( result, false , "testVerifyNeg"); - } - - /** - * This tests secret key verify() for a valid secretkey - */ - public static void testSecKeyVerifyPos() throws AssertFailException{ - boolean result = false; - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - - result = NativeSecp256k1.secKeyVerify( sec ); - //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); - assertEquals( result, true , "testSecKeyVerifyPos"); - } - - /** - * This tests secret key verify() for a invalid secretkey - */ - public static void testSecKeyVerifyNeg() throws AssertFailException{ - boolean result = false; - byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - - result = NativeSecp256k1.secKeyVerify( sec ); - //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); - assertEquals( result, false , "testSecKeyVerifyNeg"); - } - - /** - * This tests public key create() for a valid secretkey - */ - public static void testPubKeyCreatePos() throws AssertFailException{ - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - - byte[] resultArr = NativeSecp256k1.computePubkey( sec); - String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); - } - - /** - * This tests public key create() for a invalid secretkey - */ - public static void testPubKeyCreateNeg() throws AssertFailException{ - byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - - byte[] resultArr = NativeSecp256k1.computePubkey( sec); - String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); - } - - /** - * This tests sign() for a valid secretkey - */ - public static void testSignPos() throws AssertFailException{ - - byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - - byte[] resultArr = NativeSecp256k1.sign(data, sec); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); - } - - /** - * This tests sign() for a invalid secretkey - */ - public static void testSignNeg() throws AssertFailException{ - byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" - byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); - - byte[] resultArr = NativeSecp256k1.sign(data, sec); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString, "" , "testSignNeg"); - } - - /** - * This tests private key tweak-add - */ - public static void testPrivKeyTweakAdd_1() throws AssertFailException { - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" - - byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); - } - - /** - * This tests private key tweak-mul - */ - public static void testPrivKeyTweakMul_1() throws AssertFailException { - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" - - byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); - } - - /** - * This tests private key tweak-add uncompressed - */ - public static void testPrivKeyTweakAdd_2() throws AssertFailException { - byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" - - byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); - } - - /** - * This tests private key tweak-mul uncompressed - */ - public static void testPrivKeyTweakMul_2() throws AssertFailException { - byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" - - byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); - String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); - } - - /** - * This tests seed randomization - */ - public static void testRandomize() throws AssertFailException { - byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" - boolean result = NativeSecp256k1.randomize(seed); - assertEquals( result, true, "testRandomize"); - } - - public static void testCreateECDHSecret() throws AssertFailException{ - - byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); - byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); - - byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); - String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); - assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); - } - - public static void main(String[] args) throws AssertFailException{ - - - System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); - - assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); - - //Test verify() success/fail - testVerifyPos(); - testVerifyNeg(); - - //Test secKeyVerify() success/fail - testSecKeyVerifyPos(); - testSecKeyVerifyNeg(); - - //Test computePubkey() success/fail - testPubKeyCreatePos(); - testPubKeyCreateNeg(); - - //Test sign() success/fail - testSignPos(); - testSignNeg(); - - //Test privKeyTweakAdd() 1 - testPrivKeyTweakAdd_1(); - - //Test privKeyTweakMul() 2 - testPrivKeyTweakMul_1(); - - //Test privKeyTweakAdd() 3 - testPrivKeyTweakAdd_2(); - - //Test privKeyTweakMul() 4 - testPrivKeyTweakMul_2(); - - //Test randomize() - testRandomize(); - - //Test ECDH - testCreateECDHSecret(); - - NativeSecp256k1.cleanup(); - - System.out.println(" All tests passed." ); - - } -} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java deleted file mode 100644 index 04732ba04..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bitcoin; - -public class NativeSecp256k1Util{ - - public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ - if( val != val2 ) - throw new AssertFailException("FAIL: " + message); - } - - public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ - if( val != val2 ) - throw new AssertFailException("FAIL: " + message); - else - System.out.println("PASS: " + message); - } - - public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ - if( !val.equals(val2) ) - throw new AssertFailException("FAIL: " + message); - else - System.out.println("PASS: " + message); - } - - public static class AssertFailException extends Exception { - public AssertFailException(String message) { - super( message ); - } - } -} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java deleted file mode 100644 index 216c986a8..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bitcoin; - -/** - * This class holds the context reference used in native methods - * to handle ECDSA operations. - */ -public class Secp256k1Context { - private static final boolean enabled; //true if the library is loaded - private static final long context; //ref to pointer to context obj - - static { //static initializer - boolean isEnabled = true; - long contextRef = -1; - try { - System.loadLibrary("secp256k1"); - contextRef = secp256k1_init_context(); - } catch (UnsatisfiedLinkError e) { - System.out.println("UnsatisfiedLinkError: " + e.toString()); - isEnabled = false; - } - enabled = isEnabled; - context = contextRef; - } - - public static boolean isEnabled() { - return enabled; - } - - public static long getContext() { - if(!enabled) return -1; //sanity check - return context; - } - - private static native long secp256k1_init_context(); -} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c deleted file mode 100644 index bcef7b32c..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ /dev/null @@ -1,377 +0,0 @@ -#include -#include -#include -#include "org_bitcoin_NativeSecp256k1.h" -#include "include/secp256k1.h" -#include "include/secp256k1_ecdh.h" -#include "include/secp256k1_recovery.h" - - -SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone - (JNIEnv* env, jclass classObject, jlong ctx_l) -{ - const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - - jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); - - (void)classObject;(void)env; - - return ctx_clone_l; - -} - -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - - const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - (void)classObject; - - return secp256k1_context_randomize(ctx, seed); - -} - -SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context - (JNIEnv* env, jclass classObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - - secp256k1_context_destroy(ctx); - - (void)classObject;(void)env; -} - -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* sigdata = { (unsigned char*) (data + 32) }; - const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; - - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pubkey; - - int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); - - if( ret ) { - ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); - - if( ret ) { - ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); - } - } - - (void)classObject; - - return ret; -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - unsigned char* secKey = (unsigned char*) (data + 32); - - jobjectArray retArray; - jbyteArray sigArray, intsByteArray; - unsigned char intsarray[2]; - - secp256k1_ecdsa_signature sig[72]; - - int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); - - unsigned char outputSer[72]; - size_t outputLen = 72; - - if( ret ) { - int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; - } - - intsarray[0] = outputLen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - sigArray = (*env)->NewByteArray(env, outputLen); - (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); - (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} - -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - (void)classObject; - - return secp256k1_ec_seckey_verify(ctx, secKey); -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - - secp256k1_pubkey pubkey; - - jobjectArray retArray; - jbyteArray pubkeyArray, intsByteArray; - unsigned char intsarray[2]; - - int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); - - unsigned char outputSer[65]; - size_t outputLen = 65; - - if( ret ) { - int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; - } - - intsarray[0] = outputLen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - pubkeyArray = (*env)->NewByteArray(env, outputLen); - (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); - (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; - -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* tweak = (unsigned char*) (privkey + 32); - - jobjectArray retArray; - jbyteArray privArray, intsByteArray; - unsigned char intsarray[2]; - - int privkeylen = 32; - - int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); - - intsarray[0] = privkeylen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - privArray = (*env)->NewByteArray(env, privkeylen); - (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); - (*env)->SetObjectArrayElement(env, retArray, 0, privArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* tweak = (unsigned char*) (privkey + 32); - - jobjectArray retArray; - jbyteArray privArray, intsByteArray; - unsigned char intsarray[2]; - - int privkeylen = 32; - - int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); - - intsarray[0] = privkeylen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - privArray = (*env)->NewByteArray(env, privkeylen); - (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); - (*env)->SetObjectArrayElement(env, retArray, 0, privArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; -/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ - unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* tweak = (unsigned char*) (pkey + publen); - - jobjectArray retArray; - jbyteArray pubArray, intsByteArray; - unsigned char intsarray[2]; - unsigned char outputSer[65]; - size_t outputLen = 65; - - secp256k1_pubkey pubkey; - int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); - - if( ret ) { - ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); - } - - if( ret ) { - int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; - } - - intsarray[0] = outputLen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - pubArray = (*env)->NewByteArray(env, outputLen); - (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); - (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* tweak = (unsigned char*) (pkey + publen); - - jobjectArray retArray; - jbyteArray pubArray, intsByteArray; - unsigned char intsarray[2]; - unsigned char outputSer[65]; - size_t outputLen = 65; - - secp256k1_pubkey pubkey; - int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); - - if ( ret ) { - ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); - } - - if( ret ) { - int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; - } - - intsarray[0] = outputLen; - intsarray[1] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - pubArray = (*env)->NewByteArray(env, outputLen); - (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); - (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); - - intsByteArray = (*env)->NewByteArray(env, 2); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} - -SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine - (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) -{ - (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; - - return 0; -} - -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) -{ - secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; - const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); - const unsigned char* pubdata = (const unsigned char*) (secdata + 32); - - jobjectArray retArray; - jbyteArray outArray, intsByteArray; - unsigned char intsarray[1]; - secp256k1_pubkey pubkey; - unsigned char nonce_res[32]; - size_t outputLen = 32; - - int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); - - if (ret) { - ret = secp256k1_ecdh( - ctx, - nonce_res, - &pubkey, - secdata - ); - } - - intsarray[0] = ret; - - retArray = (*env)->NewObjectArray(env, 2, - (*env)->FindClass(env, "[B"), - (*env)->NewByteArray(env, 1)); - - outArray = (*env)->NewByteArray(env, outputLen); - (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); - (*env)->SetObjectArrayElement(env, retArray, 0, outArray); - - intsByteArray = (*env)->NewByteArray(env, 1); - (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); - (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); - - (void)classObject; - - return retArray; -} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h deleted file mode 100644 index fe613c9e9..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ /dev/null @@ -1,119 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -#include "include/secp256k1.h" -/* Header for class org_bitcoin_NativeSecp256k1 */ - -#ifndef _Included_org_bitcoin_NativeSecp256k1 -#define _Included_org_bitcoin_NativeSecp256k1 -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ctx_clone - * Signature: (J)J - */ -SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone - (JNIEnv *, jclass, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_context_randomize - * Signature: (Ljava/nio/ByteBuffer;J)I - */ -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_privkey_tweak_add - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_privkey_tweak_mul - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_pubkey_tweak_add - * Signature: (Ljava/nio/ByteBuffer;JI)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add - (JNIEnv *, jclass, jobject, jlong, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_pubkey_tweak_mul - * Signature: (Ljava/nio/ByteBuffer;JI)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul - (JNIEnv *, jclass, jobject, jlong, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_destroy_context - * Signature: (J)V - */ -SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context - (JNIEnv *, jclass, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;JII)I - */ -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject, jlong, jint, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_sign - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_seckey_verify - * Signature: (Ljava/nio/ByteBuffer;J)I - */ -SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_create - * Signature: (Ljava/nio/ByteBuffer;J)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create - (JNIEnv *, jclass, jobject, jlong); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ec_pubkey_parse - * Signature: (Ljava/nio/ByteBuffer;JI)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse - (JNIEnv *, jclass, jobject, jlong, jint); - -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdh - * Signature: (Ljava/nio/ByteBuffer;JI)[[B - */ -SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh - (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); - - -#ifdef __cplusplus -} -#endif -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c deleted file mode 100644 index a52939e7e..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include "org_bitcoin_Secp256k1Context.h" -#include "include/secp256k1.h" - -SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context - (JNIEnv* env, jclass classObject) -{ - secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - (void)classObject;(void)env; - - return (uintptr_t)ctx; -} - diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h deleted file mode 100644 index 0d2bc84b7..000000000 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h +++ /dev/null @@ -1,22 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -#include "include/secp256k1.h" -/* Header for class org_bitcoin_Secp256k1Context */ - -#ifndef _Included_org_bitcoin_Secp256k1Context -#define _Included_org_bitcoin_Secp256k1Context -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_bitcoin_Secp256k1Context - * Method: secp256k1_init_context - * Signature: ()J - */ -SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context - (JNIEnv *, jclass); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modinv32.h b/crypto/secp256k1/libsecp256k1/src/modinv32.h new file mode 100644 index 000000000..846c642f8 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modinv32.h @@ -0,0 +1,43 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV32_H +#define SECP256K1_MODINV32_H + +#include "util.h" + +/* A signed 30-bit limb representation of integers. + * + * Its value is sum(v[i] * 2^(30*i), i=0..8). */ +typedef struct { + int32_t v[9]; +} secp256k1_modinv32_signed30; + +typedef struct { + /* The modulus in signed30 notation, must be odd and in [3, 2^256]. */ + secp256k1_modinv32_signed30 modulus; + + /* modulus^{-1} mod 2^30 */ + uint32_t modulus_inv30; +} secp256k1_modinv32_modinfo; + +/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). + * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of + * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. + * + * On output, all of x's limbs will be in [0, 2^30). + */ +static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */ +static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + +#endif /* SECP256K1_MODINV32_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modinv32_impl.h b/crypto/secp256k1/libsecp256k1/src/modinv32_impl.h new file mode 100644 index 000000000..981d2abc6 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modinv32_impl.h @@ -0,0 +1,725 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV32_IMPL_H +#define SECP256K1_MODINV32_IMPL_H + +#include "modinv32.h" + +#include "util.h" + +#include + +/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and + * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + * + * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an + * implementation for N=30, using 30-bit signed limbs represented as int32_t. + */ + +#ifdef VERIFY +static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}}; + +/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */ +static void secp256k1_modinv32_mul_30(secp256k1_modinv32_signed30 *r, const secp256k1_modinv32_signed30 *a, int alen, int32_t factor) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + int64_t c = 0; + int i; + for (i = 0; i < 8; ++i) { + if (i < alen) c += (int64_t)a->v[i] * factor; + r->v[i] = (int32_t)c & M30; c >>= 30; + } + if (8 < alen) c += (int64_t)a->v[8] * factor; + VERIFY_CHECK(c == (int32_t)c); + r->v[8] = (int32_t)c; +} + +/* Return -1 for ab*factor. A consists of alen limbs; b has 9. */ +static int secp256k1_modinv32_mul_cmp_30(const secp256k1_modinv32_signed30 *a, int alen, const secp256k1_modinv32_signed30 *b, int32_t factor) { + int i; + secp256k1_modinv32_signed30 am, bm; + secp256k1_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + secp256k1_modinv32_mul_30(&bm, b, 9, factor); + for (i = 0; i < 8; ++i) { + /* Verify that all but the top limb of a and b are normalized. */ + VERIFY_CHECK(am.v[i] >> 30 == 0); + VERIFY_CHECK(bm.v[i] >> 30 == 0); + } + for (i = 8; i >= 0; --i) { + if (am.v[i] < bm.v[i]) return -1; + if (am.v[i] > bm.v[i]) return 1; + } + return 0; +} +#endif + +/* Take as input a signed30 number in range (-2*modulus,modulus), and add a multiple of the modulus + * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the + * process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range + * [0,2^30). */ +static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int32_t sign, const secp256k1_modinv32_modinfo *modinfo) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4], + r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8]; + volatile int32_t cond_add, cond_negate; + +#ifdef VERIFY + /* Verify that all limbs are in range (-2^30,2^30). */ + int i; + for (i = 0; i < 9; ++i) { + VERIFY_CHECK(r->v[i] >= -M30); + VERIFY_CHECK(r->v[i] <= M30); + } + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ +#endif + + /* In a first step, add the modulus if the input is negative, and then negate if requested. + * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input + * limbs are in range (-2^30,2^30), this cannot overflow an int32_t. Note that the right + * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is + * indeed the behavior of the right shift operator). */ + cond_add = r8 >> 31; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + r5 += modinfo->modulus.v[5] & cond_add; + r6 += modinfo->modulus.v[6] & cond_add; + r7 += modinfo->modulus.v[7] & cond_add; + r8 += modinfo->modulus.v[8] & cond_add; + cond_negate = sign >> 31; + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + r5 = (r5 ^ cond_negate) - cond_negate; + r6 = (r6 ^ cond_negate) - cond_negate; + r7 = (r7 ^ cond_negate) - cond_negate; + r8 = (r8 ^ cond_negate) - cond_negate; + /* Propagate the top bits, to bring limbs back to range (-2^30,2^30). */ + r1 += r0 >> 30; r0 &= M30; + r2 += r1 >> 30; r1 &= M30; + r3 += r2 >> 30; r2 &= M30; + r4 += r3 >> 30; r3 &= M30; + r5 += r4 >> 30; r4 &= M30; + r6 += r5 >> 30; r5 &= M30; + r7 += r6 >> 30; r6 &= M30; + r8 += r7 >> 30; r7 &= M30; + + /* In a second step add the modulus again if the result is still negative, bringing r to range + * [0,modulus). */ + cond_add = r8 >> 31; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + r5 += modinfo->modulus.v[5] & cond_add; + r6 += modinfo->modulus.v[6] & cond_add; + r7 += modinfo->modulus.v[7] & cond_add; + r8 += modinfo->modulus.v[8] & cond_add; + /* And propagate again. */ + r1 += r0 >> 30; r0 &= M30; + r2 += r1 >> 30; r1 &= M30; + r3 += r2 >> 30; r2 &= M30; + r4 += r3 >> 30; r3 &= M30; + r5 += r4 >> 30; r4 &= M30; + r6 += r5 >> 30; r5 &= M30; + r7 += r6 >> 30; r6 &= M30; + r8 += r7 >> 30; r7 &= M30; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; + r->v[5] = r5; + r->v[6] = r6; + r->v[7] = r7; + r->v[8] = r8; + + VERIFY_CHECK(r0 >> 30 == 0); + VERIFY_CHECK(r1 >> 30 == 0); + VERIFY_CHECK(r2 >> 30 == 0); + VERIFY_CHECK(r3 >> 30 == 0); + VERIFY_CHECK(r4 >> 30 == 0); + VERIFY_CHECK(r5 >> 30 == 0); + VERIFY_CHECK(r6 >> 30 == 0); + VERIFY_CHECK(r7 >> 30 == 0); + VERIFY_CHECK(r8 >> 30 == 0); + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ +} + +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int32_t u, v, q, r; +} secp256k1_modinv32_trans2x2; + +/* Compute the transition matrix and zeta for 30 divsteps. + * + * Input: zeta: initial zeta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final zeta + * + * Implements the divsteps_n_matrix function from the explanation. + */ +static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { + /* u,v,q,r are the elements of the transformation matrix being built up, + * starting with the identity matrix. Semantically they are signed integers + * in range [-2^30,2^30], but here represented as unsigned mod 2^32. This + * permits left shifting (which is UB for negative numbers). The range + * being inside [-2^31,2^31) means that casting to signed works correctly. + */ + uint32_t u = 1, v = 0, q = 0, r = 1; + volatile uint32_t c1, c2; + uint32_t mask1, mask2, f = f0, g = g0, x, y, z; + int i; + + for (i = 0; i < 30; ++i) { + VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ + VERIFY_CHECK((u * f0 + v * g0) == f << i); + VERIFY_CHECK((q * f0 + r * g0) == g << i); + /* Compute conditional masks for (zeta < 0) and for (g & 1). */ + c1 = zeta >> 31; + mask1 = c1; + c2 = g & 1; + mask2 = -c2; + /* Compute x,y,z, conditionally negated versions of f,u,v. */ + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; + /* Conditionally add x,y,z to g,q,r. */ + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; + /* Conditionally change zeta into -zeta-2 or zeta-1. */ + zeta = (zeta ^ mask1) - 1; + /* Conditionally add g,q,r to f,u,v. */ + f += g & mask1; + u += q & mask1; + v += r & mask1; + /* Shifts */ + g >>= 1; + u <<= 1; + v <<= 1; + /* Bounds on zeta that follow from the bounds on iteration count (max 20*30 divsteps). */ + VERIFY_CHECK(zeta >= -601 && zeta <= 601); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 30 of them will have determinant 2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); + return zeta; +} + +/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */ +static const uint8_t secp256k1_modinv32_inv256[128] = { + 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, + 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, + 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, + 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, + 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, + 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, + 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, + 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, + 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, + 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, + 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 +}; + +/* Compute the transition matrix and eta for 30 divsteps (variable time). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final eta + * + * Implements the divsteps_n_matrix_var function from the explanation. + */ +static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { + /* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* We're done once we've done 30 divsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */ + VERIFY_CHECK(eta >= -751 && eta <= 751); + /* If eta is negative, negate it and replace f,g with g,-f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 30 of them will have determinant 2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30); + return eta; +} + +/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) { + /* Transformation matrix. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 30 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 30 of them will have determinant 2^30 or -2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 || + (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30)); + *jacp = jac; + return eta; +} + +/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. + * + * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range + * (-2^30,2^30). + * + * This implements the update_de function from the explanation. + */ +static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp256k1_modinv32_signed30 *e, const secp256k1_modinv32_trans2x2 *t, const secp256k1_modinv32_modinfo* modinfo) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t di, ei, md, me, sd, se; + int64_t cd, ce; + int i; + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ + VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ + + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ + sd = d->v[8] >> 31; + se = e->v[8] >> 31; + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + /* Begin computing t*[d,e]. */ + di = d->v[0]; + ei = e->v[0]; + cd = (int64_t)u * di + (int64_t)v * ei; + ce = (int64_t)q * di + (int64_t)r * ei; + /* Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. */ + md -= (modinfo->modulus_inv30 * (uint32_t)cd + md) & M30; + me -= (modinfo->modulus_inv30 * (uint32_t)ce + me) & M30; + /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ + cd += (int64_t)modinfo->modulus.v[0] * md; + ce += (int64_t)modinfo->modulus.v[0] * me; + /* Verify that the low 30 bits of the computation are indeed zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cd & M30) == 0); cd >>= 30; + VERIFY_CHECK(((int32_t)ce & M30) == 0); ce >>= 30; + /* Now iteratively compute limb i=1..8 of t*[d,e]+modulus*[md,me], and store them in output + * limb i-1 (shifting down by 30 bits). */ + for (i = 1; i < 9; ++i) { + di = d->v[i]; + ei = e->v[i]; + cd += (int64_t)u * di + (int64_t)v * ei; + ce += (int64_t)q * di + (int64_t)r * ei; + cd += (int64_t)modinfo->modulus.v[i] * md; + ce += (int64_t)modinfo->modulus.v[i] * me; + d->v[i - 1] = (int32_t)cd & M30; cd >>= 30; + e->v[i - 1] = (int32_t)ce & M30; ce >>= 30; + } + /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ + d->v[8] = (int32_t)cd; + e->v[8] = (int32_t)ce; + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ +} + +/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv32_update_fg_30(secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t fi, gi; + int64_t cf, cg; + int i; + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + cf = (int64_t)u * fi + (int64_t)v * gi; + cg = (int64_t)q * fi + (int64_t)r * gi; + /* Verify that the bottom 30 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; + VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; + /* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting + * down by 30 bits). */ + for (i = 1; i < 9; ++i) { + fi = f->v[i]; + gi = g->v[i]; + cf += (int64_t)u * fi + (int64_t)v * gi; + cg += (int64_t)q * fi + (int64_t)r * gi; + f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; + g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; + } + /* What remains is limb 9 of t*[f,g]; store it as output limb 8. */ + f->v[8] = (int32_t)cf; + g->v[8] = (int32_t)cg; +} + +/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. + * + * Version that operates on a variable number of limbs in f and g. + * + * This implements the update_fg function from the explanation in modinv64_impl.h. + */ +static void secp256k1_modinv32_update_fg_30_var(int len, secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) { + const int32_t M30 = (int32_t)(UINT32_MAX >> 2); + const int32_t u = t->u, v = t->v, q = t->q, r = t->r; + int32_t fi, gi; + int64_t cf, cg; + int i; + VERIFY_CHECK(len > 0); + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + cf = (int64_t)u * fi + (int64_t)v * gi; + cg = (int64_t)q * fi + (int64_t)r * gi; + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30; + VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30; + /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + * down by 30 bits). */ + for (i = 1; i < len; ++i) { + fi = f->v[i]; + gi = g->v[i]; + cf += (int64_t)u * fi + (int64_t)v * gi; + cg += (int64_t)q * fi + (int64_t)r * gi; + f->v[i - 1] = (int32_t)cf & M30; cf >>= 30; + g->v[i - 1] = (int32_t)cg & M30; cg >>= 30; + } + /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + f->v[len - 1] = (int32_t)cf; + g->v[len - 1] = (int32_t)cg; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ +static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ + secp256k1_modinv32_signed30 d = {{0}}; + secp256k1_modinv32_signed30 e = {{1}}; + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; + int i; + int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */ + + /* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */ + for (i = 0; i < 20; ++i) { + /* Compute transition matrix and new zeta after 30 divsteps. */ + secp256k1_modinv32_trans2x2 t; + zeta = secp256k1_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30(&f, &g, &t); + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point sufficient iterations have been performed that g must have reached 0 + * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || + secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo); + *x = d; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ +static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + secp256k1_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}}; + secp256k1_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}}; + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; +#ifdef VERIFY + int i = 0; +#endif + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */ + int32_t cond, fn, gn; + + /* Do iterations of 30 divsteps each until g=0. */ + while (1) { + /* Compute transition matrix and new eta after 30 divsteps. */ + secp256k1_modinv32_trans2x2 t; + eta = secp256k1_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of g is 0, there is a chance g=0. */ + if (g.v[0] == 0) { + cond = 0; + /* Check if all other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= g.v[j]; + } + /* If so, we're done. */ + if (cond == 0) break; + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn ^ (fn >> 31); + cond |= gn ^ (gn >> 31); + /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + if (cond == 0) { + f.v[len - 2] |= (uint32_t)fn << 30; + g.v[len - 2] |= (uint32_t)gn << 30; + --len; + } + + VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || + secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || + (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && + secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo); + *x = d; +} + +/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI32_ITERATIONS 25 +#else +#define JACOBI32_ITERATIONS 50 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 */ + int32_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0); + + for (count = 0; count < JACOBI32_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 30 posdivsteps. */ + secp256k1_modinv32_trans2x2 t; + eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ + return 0; +} + +#endif /* SECP256K1_MODINV32_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modinv64.h b/crypto/secp256k1/libsecp256k1/src/modinv64.h new file mode 100644 index 000000000..f4208e6c2 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modinv64.h @@ -0,0 +1,47 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV64_H +#define SECP256K1_MODINV64_H + +#include "util.h" + +#ifndef SECP256K1_WIDEMUL_INT128 +#error "modinv64 requires 128-bit wide multiplication support" +#endif + +/* A signed 62-bit limb representation of integers. + * + * Its value is sum(v[i] * 2^(62*i), i=0..4). */ +typedef struct { + int64_t v[5]; +} secp256k1_modinv64_signed62; + +typedef struct { + /* The modulus in signed62 notation, must be odd and in [3, 2^256]. */ + secp256k1_modinv64_signed62 modulus; + + /* modulus^{-1} mod 2^62 */ + uint64_t modulus_inv62; +} secp256k1_modinv64_modinfo; + +/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus). + * If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of + * x and modulus must be 1). These rules are automatically satisfied if the modulus is prime. + * + * On output, all of x's limbs will be in [0, 2^62). + */ +static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */ +static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + +#endif /* SECP256K1_MODINV64_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modinv64_impl.h b/crypto/secp256k1/libsecp256k1/src/modinv64_impl.h new file mode 100644 index 000000000..548787bed --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modinv64_impl.h @@ -0,0 +1,780 @@ +/*********************************************************************** + * Copyright (c) 2020 Peter Dettman * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODINV64_IMPL_H +#define SECP256K1_MODINV64_IMPL_H + +#include "int128.h" +#include "modinv64.h" + +/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and + * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. + * + * For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an + * implementation for N=62, using 62-bit signed limbs represented as int64_t. + */ + +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int64_t u, v, q, r; +} secp256k1_modinv64_trans2x2; + +#ifdef VERIFY +/* Helper function to compute the absolute value of an int64_t. + * (we don't use abs/labs/llabs as it depends on the int sizes). */ +static int64_t secp256k1_modinv64_abs(int64_t v) { + VERIFY_CHECK(v > INT64_MIN); + if (v < 0) return -v; + return v; +} + +static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; + +/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ +static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) { + const uint64_t M62 = UINT64_MAX >> 2; + secp256k1_int128 c, d; + int i; + secp256k1_i128_from_i64(&c, 0); + for (i = 0; i < 4; ++i) { + if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor); + r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62); + } + if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor); + secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c)); + VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d)); + r->v[4] = secp256k1_i128_to_i64(&c); +} + +/* Return -1 for ab*factor. A has alen limbs; b has 5. */ +static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, int alen, const secp256k1_modinv64_signed62 *b, int64_t factor) { + int i; + secp256k1_modinv64_signed62 am, bm; + secp256k1_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */ + secp256k1_modinv64_mul_62(&bm, b, 5, factor); + for (i = 0; i < 4; ++i) { + /* Verify that all but the top limb of a and b are normalized. */ + VERIFY_CHECK(am.v[i] >> 62 == 0); + VERIFY_CHECK(bm.v[i] >> 62 == 0); + } + for (i = 4; i >= 0; --i) { + if (am.v[i] < bm.v[i]) return -1; + if (am.v[i] > bm.v[i]) return 1; + } + return 0; +} + +/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */ +static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) { + secp256k1_int128 a; + secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); + if (secp256k1_i128_check_pow2(&a, n, 1)) return 1; + if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1; + return 0; +} +#endif + +/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus + * to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the + * process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range + * [0,2^62). */ +static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) { + const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; + volatile int64_t cond_add, cond_negate; + +#ifdef VERIFY + /* Verify that all limbs are in range (-2^62,2^62). */ + int i; + for (i = 0; i < 5; ++i) { + VERIFY_CHECK(r->v[i] >= -M62); + VERIFY_CHECK(r->v[i] <= M62); + } + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +#endif + + /* In a first step, add the modulus if the input is negative, and then negate if requested. + * This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input + * limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right + * shifts below are signed sign-extending shifts (see assumptions.h for tests that that is + * indeed the behavior of the right shift operator). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + cond_negate = sign >> 63; + r0 = (r0 ^ cond_negate) - cond_negate; + r1 = (r1 ^ cond_negate) - cond_negate; + r2 = (r2 ^ cond_negate) - cond_negate; + r3 = (r3 ^ cond_negate) - cond_negate; + r4 = (r4 ^ cond_negate) - cond_negate; + /* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + /* In a second step add the modulus again if the result is still negative, bringing + * r to range [0,modulus). */ + cond_add = r4 >> 63; + r0 += modinfo->modulus.v[0] & cond_add; + r1 += modinfo->modulus.v[1] & cond_add; + r2 += modinfo->modulus.v[2] & cond_add; + r3 += modinfo->modulus.v[3] & cond_add; + r4 += modinfo->modulus.v[4] & cond_add; + /* And propagate again. */ + r1 += r0 >> 62; r0 &= M62; + r2 += r1 >> 62; r1 &= M62; + r3 += r2 >> 62; r2 &= M62; + r4 += r3 >> 62; r3 &= M62; + + r->v[0] = r0; + r->v[1] = r1; + r->v[2] = r2; + r->v[3] = r3; + r->v[4] = r4; + + VERIFY_CHECK(r0 >> 62 == 0); + VERIFY_CHECK(r1 >> 62 == 0); + VERIFY_CHECK(r2 >> 62 == 0); + VERIFY_CHECK(r3 >> 62 == 0); + VERIFY_CHECK(r4 >> 62 == 0); + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ +} + +/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). + * Note that the transformation matrix is scaled by 2^62 and not 2^59. + * + * Input: zeta: initial zeta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final zeta + * + * Implements the divsteps_n_matrix function from the explanation. + */ +static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { + /* u,v,q,r are the elements of the transformation matrix being built up, + * starting with the identity matrix times 8 (because the caller expects + * a result scaled by 2^62). Semantically they are signed integers + * in range [-2^62,2^62], but here represented as unsigned mod 2^64. This + * permits left shifting (which is UB for negative numbers). The range + * being inside [-2^63,2^63) means that casting to signed works correctly. + */ + uint64_t u = 8, v = 0, q = 0, r = 8; + volatile uint64_t c1, c2; + uint64_t mask1, mask2, f = f0, g = g0, x, y, z; + int i; + + for (i = 3; i < 62; ++i) { + VERIFY_CHECK((f & 1) == 1); /* f must always be odd */ + VERIFY_CHECK((u * f0 + v * g0) == f << i); + VERIFY_CHECK((q * f0 + r * g0) == g << i); + /* Compute conditional masks for (zeta < 0) and for (g & 1). */ + c1 = zeta >> 63; + mask1 = c1; + c2 = g & 1; + mask2 = -c2; + /* Compute x,y,z, conditionally negated versions of f,u,v. */ + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; + /* Conditionally add x,y,z to g,q,r. */ + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; + /* Conditionally change zeta into -zeta-2 or zeta-1. */ + zeta = (zeta ^ mask1) - 1; + /* Conditionally add g,q,r to f,u,v. */ + f += g & mask1; + u += q & mask1; + v += r & mask1; + /* Shifts */ + g >>= 1; + u <<= 1; + v <<= 1; + /* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */ + VERIFY_CHECK(zeta >= -591 && zeta <= 591); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial + * 8*identity (which has determinant 2^6) means the overall outputs has determinant + * 2^65. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0)); + + return zeta; +} + +/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Return: final eta + * + * Implements the divsteps_n_matrix_var function from the explanation. + */ +static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) { + /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* We're done once we've done 62 divsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */ + VERIFY_CHECK(eta >= -745 && eta <= 745); + /* If eta is negative, negate it and replace f,g with g,-f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = -tmp; + tmp = u; u = q; q = -tmp; + tmp = v; v = r; r = -tmp; + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2, the + * aggregate of 62 of them will have determinant 2^62. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0)); + + return eta; +} + +/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) { + /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 62 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; + + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1)); + + *jacp = jac; + return eta; +} + +/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. + * + * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range + * (-2^62,2^62). + * + * This implements the update_de function from the explanation. + */ +static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; + const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t md, me, sd, se; + secp256k1_int128 cd, ce; + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ + VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ + + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ + sd = d4 >> 63; + se = e4 >> 63; + md = (u & sd) + (v & se); + me = (q & sd) + (r & se); + /* Begin computing t*[d,e]. */ + secp256k1_i128_mul(&cd, u, d0); + secp256k1_i128_accum_mul(&cd, v, e0); + secp256k1_i128_mul(&ce, q, d0); + secp256k1_i128_accum_mul(&ce, r, e0); + /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ + md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62; + me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62; + /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me); + /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62); + /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ + secp256k1_i128_accum_mul(&cd, u, d1); + secp256k1_i128_accum_mul(&cd, v, e1); + secp256k1_i128_accum_mul(&ce, q, d1); + secp256k1_i128_accum_mul(&ce, r, e1); + if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me); + } + d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ + secp256k1_i128_accum_mul(&cd, u, d2); + secp256k1_i128_accum_mul(&cd, v, e2); + secp256k1_i128_accum_mul(&ce, q, d2); + secp256k1_i128_accum_mul(&ce, r, e2); + if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me); + } + d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ + secp256k1_i128_accum_mul(&cd, u, d3); + secp256k1_i128_accum_mul(&cd, v, e3); + secp256k1_i128_accum_mul(&ce, q, d3); + secp256k1_i128_accum_mul(&ce, r, e3); + if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me); + } + d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ + secp256k1_i128_accum_mul(&cd, u, d4); + secp256k1_i128_accum_mul(&cd, v, e4); + secp256k1_i128_accum_mul(&ce, q, d4); + secp256k1_i128_accum_mul(&ce, r, e4); + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me); + d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); + /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ + d->v[4] = secp256k1_i128_to_i64(&cd); + e->v[4] = secp256k1_i128_to_i64(&ce); + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; + const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + secp256k1_int128 cf, cg; + /* Start computing t*[f,g]. */ + secp256k1_i128_mul(&cf, u, f0); + secp256k1_i128_accum_mul(&cf, v, g0); + secp256k1_i128_mul(&cg, q, f0); + secp256k1_i128_accum_mul(&cg, r, g0); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); + /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ + secp256k1_i128_accum_mul(&cf, u, f1); + secp256k1_i128_accum_mul(&cf, v, g1); + secp256k1_i128_accum_mul(&cg, q, f1); + secp256k1_i128_accum_mul(&cg, r, g1); + f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ + secp256k1_i128_accum_mul(&cf, u, f2); + secp256k1_i128_accum_mul(&cf, v, g2); + secp256k1_i128_accum_mul(&cg, q, f2); + secp256k1_i128_accum_mul(&cg, r, g2); + f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ + secp256k1_i128_accum_mul(&cf, u, f3); + secp256k1_i128_accum_mul(&cf, v, g3); + secp256k1_i128_accum_mul(&cg, q, f3); + secp256k1_i128_accum_mul(&cg, r, g3); + f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ + secp256k1_i128_accum_mul(&cf, u, f4); + secp256k1_i128_accum_mul(&cf, v, g4); + secp256k1_i128_accum_mul(&cg, q, f4); + secp256k1_i128_accum_mul(&cg, r, g4); + f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ + f->v[4] = secp256k1_i128_to_i64(&cf); + g->v[4] = secp256k1_i128_to_i64(&cg); +} + +/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. + * + * Version that operates on a variable number of limbs in f and g. + * + * This implements the update_fg function from the explanation. + */ +static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { + const uint64_t M62 = UINT64_MAX >> 2; + const int64_t u = t->u, v = t->v, q = t->q, r = t->r; + int64_t fi, gi; + secp256k1_int128 cf, cg; + int i; + VERIFY_CHECK(len > 0); + /* Start computing t*[f,g]. */ + fi = f->v[0]; + gi = g->v[0]; + secp256k1_i128_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); + /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ + VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); + /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting + * down by 62 bits). */ + for (i = 1; i < len; ++i) { + fi = f->v[i]; + gi = g->v[i]; + secp256k1_i128_accum_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_accum_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); + f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); + } + /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ + f->v[len - 1] = secp256k1_i128_to_i64(&cf); + g->v[len - 1] = secp256k1_i128_to_i64(&cg); +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ +static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */ + secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; + int i; + int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */ + + /* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */ + for (i = 0; i < 10; ++i) { + /* Compute transition matrix and new zeta after 59 divsteps. */ + secp256k1_modinv64_trans2x2 t; + zeta = secp256k1_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62(&f, &g, &t); + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point sufficient iterations have been performed that g must have reached 0 + * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g + * values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || + secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo); + *x = d; +} + +/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */ +static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with d=0, e=1, f=modulus, g=x, eta=-1. */ + secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}}; + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; +#ifdef VERIFY + int i = 0; +#endif + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + + /* Do iterations of 62 divsteps each until g=0. */ + while (1) { + /* Compute transition matrix and new eta after 62 divsteps. */ + secp256k1_modinv64_trans2x2 t; + eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t); + /* Update d,e using that transition matrix. */ + secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of g is zero, there is a chance that g=0. */ + if (g.v[0] == 0) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= g.v[j]; + } + /* If so, we're done. */ + if (cond == 0) break; + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn ^ (fn >> 63); + cond |= gn ^ (gn >> 63); + /* If so, reduce length, propagating the sign of f and g's top limb into the one below. */ + if (cond == 0) { + f.v[len - 2] |= (uint64_t)fn << 62; + g.v[len - 2] |= (uint64_t)gn << 62; + --len; + } + + VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of + * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ + + /* g == 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || + secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || + (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && + secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0)); + + /* Optionally negate d, normalize to [0,modulus), and return it. */ + secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo); + *x = d; +} + +/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI64_ITERATIONS 12 +#else +#define JACOBI64_ITERATIONS 25 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0); + + for (count = 0; count < JACOBI64_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 62 posdivsteps. */ + secp256k1_modinv64_trans2x2 t; + eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); + /* Update f,g using that transition matrix. */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; + + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ + } + + /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ + return 0; +} + +#endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include index e3088b469..7f7f95f1f 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include @@ -1,8 +1,4 @@ include_HEADERS += include/secp256k1_ecdh.h noinst_HEADERS += src/modules/ecdh/main_impl.h noinst_HEADERS += src/modules/ecdh/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_ecdh -bench_ecdh_SOURCES = src/bench_ecdh.c -bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) -endif +noinst_HEADERS += src/modules/ecdh/bench_impl.h diff --git a/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/bench_impl.h similarity index 54% rename from crypto/secp256k1/libsecp256k1/src/bench_ecdh.c rename to crypto/secp256k1/libsecp256k1/src/modules/ecdh/bench_impl.h index cde5e2dbb..c23aaa94d 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/bench_impl.h @@ -1,25 +1,23 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#include +#ifndef SECP256K1_MODULE_ECDH_BENCH_H +#define SECP256K1_MODULE_ECDH_BENCH_H -#include "include/secp256k1.h" -#include "include/secp256k1_ecdh.h" -#include "util.h" -#include "bench.h" +#include "../../../include/secp256k1_ecdh.h" typedef struct { secp256k1_context *ctx; secp256k1_pubkey point; unsigned char scalar[32]; -} bench_ecdh_t; +} bench_ecdh_data; static void bench_ecdh_setup(void* arg) { int i; - bench_ecdh_t *data = (bench_ecdh_t*)arg; + bench_ecdh_data *data = (bench_ecdh_data*)arg; const unsigned char point[] = { 0x03, 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, @@ -28,27 +26,32 @@ static void bench_ecdh_setup(void* arg) { 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f }; - /* create a context with no capabilities */ - data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); for (i = 0; i < 32; i++) { data->scalar[i] = i + 1; } CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); } -static void bench_ecdh(void* arg) { +static void bench_ecdh(void* arg, int iters) { int i; unsigned char res[32]; - bench_ecdh_t *data = (bench_ecdh_t*)arg; + bench_ecdh_data *data = (bench_ecdh_data*)arg; - for (i = 0; i < 20000; i++) { - CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); } } -int main(void) { - bench_ecdh_t data; +static void run_ecdh_bench(int iters, int argc, char** argv) { + bench_ecdh_data data; + int d = argc == 1; + + /* create a context with no capabilities */ + data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); - run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); - return 0; + if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); } + +#endif /* SECP256K1_MODULE_ECDH_BENCH_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h index 9e30fb73d..842b5359e 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h @@ -1,54 +1,74 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_MODULE_ECDH_MAIN_ -#define _SECP256K1_MODULE_ECDH_MAIN_ +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H -#include "include/secp256k1_ecdh.h" -#include "ecmult_const_impl.h" +#include "../../../include/secp256k1_ecdh.h" +#include "../../ecmult_const_impl.h" -int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { + unsigned char version = (y32[31] & 0x01) | 0x02; + secp256k1_sha256 sha; + (void)data; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, &version, 1); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) { int ret = 0; int overflow = 0; secp256k1_gej res; secp256k1_ge pt; secp256k1_scalar s; + unsigned char x[32]; + unsigned char y[32]; + VERIFY_CHECK(ctx != NULL); - ARG_CHECK(result != NULL); + ARG_CHECK(output != NULL); ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); + if (hashfp == NULL) { + hashfp = secp256k1_ecdh_hash_function_default; + } + secp256k1_pubkey_load(ctx, &pt, point); secp256k1_scalar_set_b32(&s, scalar, &overflow); - if (overflow || secp256k1_scalar_is_zero(&s)) { - ret = 0; - } else { - unsigned char x[32]; - unsigned char y[1]; - secp256k1_sha256_t sha; - - secp256k1_ecmult_const(&res, &pt, &s); - secp256k1_ge_set_gej(&pt, &res); - /* Compute a hash of the point in compressed form - * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not - * expect its output to be secret and has a timing sidechannel. */ - secp256k1_fe_normalize(&pt.x); - secp256k1_fe_normalize(&pt.y); - secp256k1_fe_get_b32(x, &pt.x); - y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); - - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, y, sizeof(y)); - secp256k1_sha256_write(&sha, x, sizeof(x)); - secp256k1_sha256_finalize(&sha, result); - ret = 1; - } + overflow |= secp256k1_scalar_is_zero(&s); + secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + + /* Compute a hash of the point */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + secp256k1_fe_get_b32(y, &pt.y); + + ret = hashfp(output, x, y, data); + + secp256k1_memclear(x, sizeof(x)); + secp256k1_memclear(y, sizeof(y)); secp256k1_scalar_clear(&s); - return ret; + secp256k1_ge_clear(&pt); + secp256k1_gej_clear(&res); + + return !!ret & !overflow; } -#endif +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h index 85a5d0a9a..3c3acdaf8 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h @@ -1,76 +1,87 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_MODULE_ECDH_TESTS_ -#define _SECP256K1_MODULE_ECDH_TESTS_ - -void test_ecdh_api(void) { - /* Setup context that just counts errors */ - secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + +static void test_ecdh_api(void) { secp256k1_pubkey point; unsigned char res[32]; unsigned char s_one[32] = { 0 }; - int32_t ecount = 0; s_one[31] = 1; - secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); /* Check all NULLs are detected */ - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); - CHECK(ecount == 3); - - /* Cleanup */ - secp256k1_context_destroy(tctx); + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL)); + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); } -void test_ecdh_generator_basepoint(void) { +static void test_ecdh_generator_basepoint(void) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; int i; s_one[31] = 1; /* Check against pubkey creation when the basepoint is the generator */ - for (i = 0; i < 100; ++i) { - secp256k1_sha256_t sha; + for (i = 0; i < 2 * COUNT; ++i) { + secp256k1_sha256 sha; unsigned char s_b32[32]; - unsigned char output_ecdh[32]; + unsigned char output_ecdh[65]; unsigned char output_ser[32]; - unsigned char point_ser[33]; + unsigned char point_ser[65]; size_t point_ser_len = sizeof(point_ser); secp256k1_scalar s; - random_scalar_order(&s); + testutil_random_scalar_order(&s); secp256k1_scalar_get_b32(s_b32, &s); - /* compute using ECDH function */ - CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); - CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - CHECK(point_ser_len == sizeof(point_ser)); + CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); /* compare */ - CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0); } } -void test_bad_scalar(void) { +static void test_bad_scalar(void) { unsigned char s_zero[32] = { 0 }; unsigned char s_overflow[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -84,22 +95,58 @@ void test_bad_scalar(void) { secp256k1_pubkey point; /* Create random point */ - random_scalar_order(&rand); + testutil_random_scalar_order(&rand); secp256k1_scalar_get_b32(s_rand, &rand); - CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1); /* Try to multiply it by bad values */ - CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0); /* ...and a good one */ s_overflow[31] -= 1; - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); +} + +/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ +static void test_result_basepoint(void) { + secp256k1_pubkey point; + secp256k1_scalar rand; + unsigned char s[32]; + unsigned char s_inv[32]; + unsigned char out[32]; + unsigned char out_inv[32]; + unsigned char out_base[32]; + int i; + + unsigned char s_one[32] = { 0 }; + s_one[31] = 1; + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); + CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1); + + for (i = 0; i < 2 * COUNT; i++) { + testutil_random_scalar_order(&rand); + secp256k1_scalar_get_b32(s, &rand); + secp256k1_scalar_inverse(&rand, &rand); + secp256k1_scalar_get_b32(s_inv, &rand); + + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1); + CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1); + CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0); + + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1); + CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1); + CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0); + } } -void run_ecdh_tests(void) { +static void run_ecdh_tests(void) { test_ecdh_api(); test_ecdh_generator_basepoint(); test_bad_scalar(); + test_result_basepoint(); } -#endif +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ellswift/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/Makefile.am.include new file mode 100644 index 000000000..8251231ea --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/secp256k1_ellswift.h +noinst_HEADERS += src/modules/ellswift/bench_impl.h +noinst_HEADERS += src/modules/ellswift/main_impl.h +noinst_HEADERS += src/modules/ellswift/tests_impl.h +noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ellswift/bench_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/bench_impl.h new file mode 100644 index 000000000..b16a3a368 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/bench_impl.h @@ -0,0 +1,106 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H +#define SECP256K1_MODULE_ELLSWIFT_BENCH_H + +#include "../../../include/secp256k1_ellswift.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point[256]; + unsigned char rnd64[64]; +} bench_ellswift_data; + +static void bench_ellswift_setup(void *arg) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + static const unsigned char init[64] = { + 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68, + 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e, + 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79, + 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21, + 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f, + 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30, + 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85, + 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc + }; + memcpy(data->rnd64, init, 64); + for (i = 0; i < 256; ++i) { + int j; + CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64)); + for (j = 0; j < 64; ++j) { + data->rnd64[j] += 1; + } + } + CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16)); +} + +static void bench_ellswift_encode(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16)); + } +} + +static void bench_ellswift_create(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + unsigned char buf[64]; + CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32)); + memcpy(data->rnd64, buf, 64); + } +} + +static void bench_ellswift_decode(void *arg, int iters) { + int i; + secp256k1_pubkey out; + size_t len; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED)); + } +} + +static void bench_ellswift_xdh(void *arg, int iters) { + int i; + bench_ellswift_data *data = (bench_ellswift_data*)arg; + + for (i = 0; i < iters; i++) { + int party = i & 1; + CHECK(secp256k1_ellswift_xdh(data->ctx, + data->rnd64 + (i % 33), + data->rnd64, + data->rnd64, + data->rnd64 + ((i + 16) % 33), + party, + secp256k1_ellswift_xdh_hash_function_bip324, + NULL) == 1); + } +} + +void run_ellswift_bench(int iters, int argc, char **argv) { + bench_ellswift_data data; + int d = argc == 1; + + /* create a context with signing capabilities */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters); + + secp256k1_context_destroy(data.ctx); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ellswift/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/main_impl.h new file mode 100644 index 000000000..745a96913 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/main_impl.h @@ -0,0 +1,592 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H +#define SECP256K1_MODULE_ELLSWIFT_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_ellswift.h" +#include "../../eckey.h" +#include "../../hash.h" + +/** c1 = (sqrt(-3)-1)/2 */ +static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); +/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */ +static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee); +/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */ +static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef); +/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */ +static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41); + +/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */ +static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) { + /* The implemented algorithm is the following (all operations in GF(p)): + * + * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852. + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - If u^3+7+t^2 = 0, set t = 2*t. + * - Let X = (u^3+7-t^2)/(2*t). + * - Let Y = (X+t)/(c0*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate). + * + * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get: + * + * - Let c0 = ... + * - If u = 0, set u = 1. + * - If t = 0, set t = 1. + * - Let s = t^2 + * - Let g = u^3+7 + * - If g+s = 0, set t = 2*t, s = 4*s + * - Let X = (g-s)/(2*t). + * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u). + * - If x3 = u+4*Y^2 is a valid x coordinate, return it. + * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This + * means X and Y do not need to be evaluated explicitly anymore. + * + * - ... + * - If g+s = 0, set s = 4*s. + * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + * + * Simplifying x2 using 2 additional constants: + * + * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - ... + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - ... + * + * Writing x3 as a fraction: + * + * - ... + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ... + * - ... + + * Overall, we get: + * + * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40. + * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee. + * - If u = 0, set u = 1. + * - If t = 0, set s = 1, else set s = t^2. + * - Let g = u^3+7. + * - If g+s = 0, set s = 4*s. + * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it. + * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it. + * - Return x1 = -(x2+u). + */ + secp256k1_fe u1, s, g, p, d, n, l; + u1 = *u; + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one; + secp256k1_fe_sqr(&s, t); + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one; + secp256k1_fe_sqr(&l, &u1); /* l = u^2 */ + secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */ + secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */ + p = g; /* p = g */ + secp256k1_fe_add(&p, &s); /* p = g+s */ + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) { + secp256k1_fe_mul_int(&s, 4); + /* Recompute p = g+s */ + p = g; /* p = g */ + secp256k1_fe_add(&p, &s); /* p = g+s */ + } + secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */ + secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */ + secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */ + secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */ + secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */ + secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */ + if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) { + /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */ + *xn = n; + *xd = d; + return; + } + *xd = p; + secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */ + secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */ + secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */ + secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */ + /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed, + * which we already have computed above. This could be deduplicated. */ + if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) { + /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */ + *xn = n; + return; + } + secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */ + secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */ + secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */ + + VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p)); + /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */ +} + +/** Decode ElligatorSwift encoding (u, t) to X coordinate. */ +static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) { + secp256k1_fe xn, xd; + secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t); + secp256k1_fe_inv_var(&xd, &xd); + secp256k1_fe_mul(x, &xn, &xd); +} + +/** Decode ElligatorSwift encoding (u, t) to point P. */ +static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) { + secp256k1_fe x; + secp256k1_ellswift_xswiftec_var(&x, u, t); + secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t)); +} + +/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x. + * + * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also + * fewer, or none at all. Each such partial inverse can be accessed individually using a + * distinct input argument c (in range 0-7), and some or all of these may return failure. + * The following guarantees exist: + * - Given (x, u), no two distinct c values give the same successful result t. + * - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var. + * - Given (x, u), all t values that map back to x can be reached by combining the + * successful results from this function over all c values, with the exception of: + * - this function cannot be called with u=0 + * - no result with t=0 will be returned + * - no result for which u^3 + t^2 + 7 = 0 will be returned. + * + * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then + * using the low and high bits to pick signs of square roots) is to match the paper's + * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through + * c=7 are copies of those with an additional negation of sqrt(w). + */ +static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) { + /* The implemented algorithm is this (all arithmetic, except involving c, is mod p): + * + * - If (c & 2) = 0: + * - If (-x-u) is a valid X coordinate, fail. + * - Let s=-(u^3+7)/(u^2+u*x+x^2). + * - If s is not square, fail. + * - Let v=x. + * - If (c & 2) = 2: + * - Let s=x-u. + * - If s is not square, fail. + * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. + * - If (c & 1) = 1 and r = 0, fail. + * - If s=0, fail. + * - Let v=(r/s-u)/2. + * - Let w=sqrt(s). + * - If (c & 5) = 0: return -w*(c3*u + v). + * - If (c & 5) = 1: return w*(c4*u + v). + * - If (c & 5) = 4: return w*(c3*u + v). + * - If (c & 5) = 5: return -w*(c4*u + v). + */ + secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q; + int ret; + + secp256k1_fe_normalize_weak(&x); + secp256k1_fe_normalize_weak(&u); + + VERIFY_CHECK(c >= 0 && c < 8); + VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x)); + + if (!(c & 2)) { + /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or + * c=4) formula, or x2 (if c=1 or c=5) formula. */ + + /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips + * back under the x3 formula instead (which has priority over x1 and x2, so the decoding + * would not match x). */ + m = x; /* m = x */ + secp256k1_fe_add(&m, &u); /* m = u+x */ + secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */ + /* Test if (-u-x) is a valid X coordinate. If so, fail. */ + if (secp256k1_ge_x_on_curve_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */ + secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */ + secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */ + secp256k1_fe_mul(&m, &u, &x); /* m = u*x */ + secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */ + + /* Note that at this point, s = 0 is impossible. If it were the case: + * s = -(u^2 + u*x + x^2) = 0 + * => u^2 + u*x + x^2 = 0 + * => (u + 2*x) * (u^2 + u*x + x^2) = 0 + * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0 + * => (x + u)^3 + x^3 = 0 + * => x^3 = -(x + u)^3 + * => x^3 + B = (-u - x)^3 + B + * + * However, we know x^3 + B is square (because x is on the curve) and + * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m) + * test above would have failed). This is a contradiction, and thus the + * assumption s=0 is false. */ + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s)); + + /* If s is not square, fail. We have not fully computed s yet, but s is square iff + * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is + * nonzero). */ + secp256k1_fe_sqr(&g, &u); /* g = u^2 */ + secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ + secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */ + secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */ + if (!secp256k1_fe_is_square_var(&m)) return 0; + + /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */ + secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */ + secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */ + + /* Let v = x. */ + v = x; + } else { + /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */ + + /* Let s = x-u. */ + secp256k1_fe_negate(&m, &u, 1); /* m = -u */ + s = m; /* s = -u */ + secp256k1_fe_add(&s, &x); /* s = x-u */ + + /* If s is not square, fail. */ + if (!secp256k1_fe_is_square_var(&s)) return 0; + + /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */ + secp256k1_fe_sqr(&g, &u); /* g = u^2 */ + secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */ + secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */ + secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */ + secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */ + secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */ + secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */ + secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */ + if (!secp256k1_fe_is_square_var(&q)) return 0; + ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */ +#ifdef VERIFY + VERIFY_CHECK(ret); +#else + (void)ret; +#endif + + /* If (c & 1) = 1 and r = 0, fail. */ + if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0; + + /* If s = 0, fail. */ + if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0; + + /* Let v = (r/s-u)/2. */ + secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */ + secp256k1_fe_mul(&v, &v, &r); /* v = r/s */ + secp256k1_fe_add(&v, &m); /* v = r/s-u */ + secp256k1_fe_half(&v); /* v = (r/s-u)/2 */ + } + + /* Let w = sqrt(s). */ + ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */ + VERIFY_CHECK(ret); + + /* Return logic. */ + if ((c & 5) == 0 || (c & 5) == 5) { + secp256k1_fe_negate(&m, &m, 1); /* m = -w */ + } + /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */ + secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3); + /* u = {c4 if c&1=1; c3 otherwise}*u */ + secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */ + secp256k1_fe_mul(t, &m, &u); + return 1; +} + +/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt). + * + * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness. + * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a + * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */ +static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) { + secp256k1_sha256 hash = *hasher; + unsigned char buf4[4]; +#ifdef VERIFY + size_t blocks = hash.bytes >> 6; +#endif + buf4[0] = cnt; + buf4[1] = cnt >> 8; + buf4[2] = cnt >> 16; + buf4[3] = cnt >> 24; + secp256k1_sha256_write(&hash, buf4, 4); + secp256k1_sha256_finalize(&hash, out32); + + /* Writing and finalizing together should trigger exactly one SHA256 compression. */ + VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); +} + +/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate. + * + * u32 is the 32-byte big endian encoding of u; t is the output field element t that still + * needs encoding. + * + * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */ +static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) { + /* Pool of 3-bit branch values. */ + unsigned char branch_hash[32]; + /* Number of 3-bit values in branch_hash left. */ + int branches_left = 0; + /* Field elements u and branch values are extracted from RNG based on hasher for consecutive + * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64 + * cnt values that follow are used to generate field elements u. cnt==65 (and multiples + * thereof) are used to repopulate the pool and start over, if that were ever necessary. + * On average, 4 iterations are needed. */ + uint32_t cnt = 0; + while (1) { + int branch; + secp256k1_fe u; + /* If the pool of branch values is empty, populate it. */ + if (branches_left == 0) { + secp256k1_ellswift_prng(branch_hash, hasher, cnt++); + branches_left = 64; + } + /* Take a 3-bit branch value from the branch pool (top bit is discarded). */ + --branches_left; + branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7; + /* Compute a new u value by hashing. */ + secp256k1_ellswift_prng(u32, hasher, cnt++); + /* overflow is not a problem (we prefer uniform u32 over uniform u). */ + secp256k1_fe_set_b32_mod(&u, u32); + /* Since u is the output of a hash, it should practically never be 0. We could apply the + * u=0 to u=1 correction here too to deal with that case still, but it's such a low + * probability event that we do not bother. */ + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u)); + + /* Find a remainder t, and return it if found. */ + if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break; + } +} + +/** Find an ElligatorSwift encoding (u, t) for point P. + * + * This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p + * as input, and returns an encoding that matches the provided Y coordinate rather than a random + * one. + */ +static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) { + secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher); + secp256k1_fe_normalize_var(t); + if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) { + secp256k1_fe_negate(t, t, 1); + secp256k1_fe_normalize_var(t); + } +} + +/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */ +static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0xd1a6524bul; + hash->s[1] = 0x028594b3ul; + hash->s[2] = 0x96e42f4eul; + hash->s[3] = 0x1037a177ul; + hash->s[4] = 0x1b8fcb8bul; + hash->s[5] = 0x56023885ul; + hash->s[6] = 0x2560ede1ul; + hash->s[7] = 0xd626b715ul; + + hash->bytes = 64; +} + +int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) { + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(rnd32 != NULL); + + if (secp256k1_pubkey_load(ctx, &p, pubkey)) { + secp256k1_fe t; + unsigned char p64[64] = {0}; + size_t ser_size; + int ser_ret; + secp256k1_sha256 hash; + + /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using + * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ + secp256k1_ellswift_sha256_init_encode(&hash); + ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1); +#ifdef VERIFY + VERIFY_CHECK(ser_ret && ser_size == 33); +#else + (void)ser_ret; +#endif + secp256k1_sha256_write(&hash, p64, sizeof(p64)); + secp256k1_sha256_write(&hash, rnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + return 1; + } + /* Only reached in case the provided pubkey is invalid. */ + memset(ell64, 0, 64); + return 0; +} + +/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */ +static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0xd29e1bf5ul; + hash->s[1] = 0xf7025f42ul; + hash->s[2] = 0x9b024773ul; + hash->s[3] = 0x094cb7d5ul; + hash->s[4] = 0xe59ed789ul; + hash->s[5] = 0x03bc9786ul; + hash->s[6] = 0x68335b35ul; + hash->s[7] = 0x4e363b53ul; + + hash->bytes = 64; +} + +int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) { + secp256k1_ge p; + secp256k1_fe t; + secp256k1_sha256 hash; + secp256k1_scalar seckey_scalar; + int ret; + static const unsigned char zero32[32] = {0}; + + /* Sanity check inputs. */ + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(ell64 != NULL); + memset(ell64, 0, 64); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + /* Compute (affine) public key */ + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32); + secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */ + secp256k1_fe_normalize_var(&p.x); + secp256k1_fe_normalize_var(&p.y); + + /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), + * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */ + secp256k1_ellswift_sha256_init_create(&hash); + secp256k1_sha256_write(&hash, seckey32, 32); + secp256k1_sha256_write(&hash, zero32, sizeof(zero32)); + secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ + if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32); + + /* Compute ElligatorSwift encoding and construct output. */ + secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ + + secp256k1_memczero(ell64, 64, !ret); + secp256k1_scalar_clear(&seckey_scalar); + + return ret; +} + +int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) { + secp256k1_fe u, t; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(ell64 != NULL); + + secp256k1_fe_set_b32_mod(&u, ell64); + secp256k1_fe_set_b32_mod(&t, ell64 + 32); + secp256k1_fe_normalize_var(&t); + secp256k1_ellswift_swiftec_var(&p, &u, &t); + secp256k1_pubkey_save(pubkey, &p); + return 1; +} + +static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + secp256k1_sha256 sha; + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data, 64); + secp256k1_sha256_write(&sha, ell_a64, 64); + secp256k1_sha256_write(&sha, ell_b64, 64); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ +static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash); + hash->s[0] = 0x8c12d730ul; + hash->s[1] = 0x827bd392ul; + hash->s[2] = 0x9e4fb2eeul; + hash->s[3] = 0x207b373eul; + hash->s[4] = 0x2292bd7aul; + hash->s[5] = 0xaa5441bcul; + hash->s[6] = 0x15c3779ful; + hash->s[7] = 0xcfb52549ul; + + hash->bytes = 64; +} + +static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + secp256k1_sha256 sha; + + (void)data; + + secp256k1_ellswift_sha256_init_bip324(&sha); + secp256k1_sha256_write(&sha, ell_a64, 64); + secp256k1_sha256_write(&sha, ell_b64, 64); + secp256k1_sha256_write(&sha, x32, 32); + secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_clear(&sha); + + return 1; +} + +const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; +const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; + +int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow; + secp256k1_scalar s; + secp256k1_fe xn, xd, px, u, t; + unsigned char sx[32]; + const unsigned char* theirs64; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(ell_a64 != NULL); + ARG_CHECK(ell_b64 != NULL); + ARG_CHECK(seckey32 != NULL); + ARG_CHECK(hashfp != NULL); + + /* Load remote public key (as fraction). */ + theirs64 = party ? ell_a64 : ell_b64; + secp256k1_fe_set_b32_mod(&u, theirs64); + secp256k1_fe_set_b32_mod(&t, theirs64 + 32); + secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t); + + /* Load private key (using one if invalid). */ + secp256k1_scalar_set_b32(&s, seckey32, &overflow); + overflow = secp256k1_scalar_is_zero(&s); + secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); + + /* Compute shared X coordinate. */ + secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1); + secp256k1_fe_normalize(&px); + secp256k1_fe_get_b32(sx, &px); + + /* Invoke hasher */ + ret = hashfp(output, sx, ell_a64, ell_b64, data); + + secp256k1_memclear(sx, sizeof(sx)); + secp256k1_fe_clear(&px); + secp256k1_scalar_clear(&s); + + return !!ret & !overflow; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_exhaustive_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_exhaustive_impl.h new file mode 100644 index 000000000..839c24aee --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_exhaustive_impl.h @@ -0,0 +1,39 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ellswift.h" +#include "main_impl.h" + +static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i; + + /* Note that SwiftEC/ElligatorSwift are inherently curve operations, not + * group operations, and this test only checks the curve points which are in + * a tiny subgroup. In that sense it can't be really seen as exhaustive as + * it doesn't (and for computational reasons obviously cannot) test the + * entire domain ellswift operates under. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_scalar scalar_i; + unsigned char sec32[32]; + unsigned char ell64[64]; + secp256k1_pubkey pub_decoded; + secp256k1_ge ge_decoded; + + /* Construct ellswift pubkey from exhaustive loop scalar i. */ + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(sec32, &scalar_i); + CHECK(secp256k1_ellswift_create(ctx, ell64, sec32, NULL)); + + /* Decode ellswift pubkey and check that it matches the precomputed group element. */ + secp256k1_ellswift_decode(ctx, &pub_decoded, ell64); + secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded); + CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i])); + } +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_impl.h new file mode 100644 index 000000000..3c314c9b5 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ellswift/tests_impl.h @@ -0,0 +1,436 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H +#define SECP256K1_MODULE_ELLSWIFT_TESTS_H + +#include "../../../include/secp256k1_ellswift.h" + +struct ellswift_xswiftec_inv_test { + int enc_bitmap; + secp256k1_fe u; + secp256k1_fe x; + secp256k1_fe encs[8]; +}; + +struct ellswift_decode_test { + unsigned char enc[64]; + secp256k1_fe x; + int odd_y; +}; + +struct ellswift_xdh_test { + unsigned char priv_ours[32]; + unsigned char ellswift_ours[64]; + unsigned char ellswift_theirs[64]; + int initiating; + unsigned char shared_secret[32]; +}; + +/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against paper + * authors' code. */ +static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = { + {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}}, + {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}}, + {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}}, + {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}}, + {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}}, + {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}}, + {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}}, + {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}}, + {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}}, + {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, + {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}}, + {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}}, + {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}}, +}; + +/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324 + * test vectors. Created using an independent implementation, and tested decoding against the paper + * authors' code. */ +static const struct ellswift_decode_test ellswift_decode_tests[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0}, + {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1}, + {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0}, + {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0}, + {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0}, + {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0}, + {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0}, + {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0}, + {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0}, + {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0}, + {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0}, + {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0}, + {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0}, + {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0}, + {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1}, + {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0}, + {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1}, + {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0}, + {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0}, + {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1}, + {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0}, +}; + +/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating, + * taken from the BIP324 test vectors. Created using an independent implementation, and tested + * against the paper authors' decoding code. */ +static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = { + {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}}, + {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}}, + {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}}, + {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}}, + {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}}, + {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}}, + {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}}, +}; + +/** This is a hasher for ellswift_xdh which just returns the shared X coordinate. + * + * This is generally a bad idea as it means changes to the encoding of the + * exchanged public keys do not affect the shared secret. However, it's used here + * in tests to be able to verify the X coordinate through other means. + */ +static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + (void)ell_a64; + (void)ell_b64; + (void)data; + memcpy(output, x32, 32); + return 1; +} + +void run_ellswift_tests(void) { + int i = 0; + /* Test vectors. */ + for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) { + const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i]; + int c; + for (c = 0; c < 8; ++c) { + secp256k1_fe t; + int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c); + CHECK(ret == ((testcase->enc_bitmap >> c) & 1)); + if (ret) { + secp256k1_fe x2; + CHECK(fe_equal(&t, &testcase->encs[c])); + secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]); + CHECK(fe_equal(&testcase->x, &x2)); + } + } + } + for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) { + const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + int ret; + ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc); + CHECK(ret); + ret = secp256k1_pubkey_load(CTX, &ge, &pubkey); + CHECK(ret); + CHECK(fe_equal(&testcase->x, &ge.x)); + CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y); + } + for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) { + const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i]; + unsigned char shared_secret[32]; + int ret; + int party = !test->initiating; + const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours; + const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs; + ret = secp256k1_ellswift_xdh(CTX, shared_secret, + ell_a64, ell_b64, + test->priv_ours, + party, + secp256k1_ellswift_xdh_hash_function_bip324, + NULL); + CHECK(ret); + CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0); + } + /* Verify that secp256k1_ellswift_encode + decode roundtrips. */ + for (i = 0; i < 1000 * COUNT; i++) { + unsigned char rnd32[32]; + unsigned char ell64[64]; + secp256k1_ge g, g2; + secp256k1_pubkey pubkey, pubkey2; + /* Generate random public key and random randomizer. */ + testutil_random_ge_test(&g); + secp256k1_pubkey_save(&pubkey, &g); + testrand256(rnd32); + /* Convert the public key to ElligatorSwift and back. */ + secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32); + secp256k1_ellswift_decode(CTX, &pubkey2, ell64); + secp256k1_pubkey_load(CTX, &g2, &pubkey2); + /* Compare with original. */ + CHECK(secp256k1_ge_eq_var(&g, &g2)); + } + /* Verify the behavior of secp256k1_ellswift_create */ + for (i = 0; i < 400 * COUNT; i++) { + unsigned char auxrnd32[32], sec32[32]; + secp256k1_scalar sec; + secp256k1_gej res; + secp256k1_ge dec; + secp256k1_pubkey pub; + unsigned char ell64[64]; + int ret; + /* Generate random secret key and random randomizer. */ + if (i & 1) testrand256_test(auxrnd32); + testutil_random_scalar_order_test(&sec); + secp256k1_scalar_get_b32(sec32, &sec); + /* Construct ElligatorSwift-encoded public keys for that key. */ + ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL); + CHECK(ret); + /* Decode it, and compare with traditionally-computed public key. */ + secp256k1_ellswift_decode(CTX, &pub, ell64); + secp256k1_pubkey_load(CTX, &dec, &pub); + secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec); + CHECK(secp256k1_gej_eq_ge_var(&res, &dec)); + } + /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */ + for (i = 0; i < 800 * COUNT; i++) { + unsigned char ell64[64], sec32[32], share32[32]; + secp256k1_scalar sec; + secp256k1_ge dec, res; + secp256k1_fe share_x; + secp256k1_gej decj, resj; + secp256k1_pubkey pub; + int ret; + /* Generate random secret key. */ + testutil_random_scalar_order_test(&sec); + secp256k1_scalar_get_b32(sec32, &sec); + /* Generate random ElligatorSwift encoding for the remote key and decode it. */ + testrand256_test(ell64); + testrand256_test(ell64 + 32); + secp256k1_ellswift_decode(CTX, &pub, ell64); + secp256k1_pubkey_load(CTX, &dec, &pub); + secp256k1_gej_set_ge(&decj, &dec); + /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we + * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works + * because the "hasher" function we use here ignores the ell64 arguments. */ + ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL); + CHECK(ret); + (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */ + SECP256K1_FE_VERIFY(&share_x); + /* Compute seckey*pubkey directly. */ + secp256k1_ecmult(&resj, &decj, &sec, NULL); + secp256k1_ge_set_gej(&res, &resj); + /* Compare. */ + CHECK(fe_equal(&res.x, &share_x)); + } + /* Verify the joint behavior of secp256k1_ellswift_xdh */ + for (i = 0; i < 200 * COUNT; i++) { + unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; + unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32]; + secp256k1_scalar seca, secb; + unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64]; + unsigned char share32a[32], share32b[32], share32_bad[32]; + unsigned char prefix64[64]; + secp256k1_ellswift_xdh_hash_function hash_function; + void* data; + int ret; + + /* Pick hasher to use. */ + if ((i % 3) == 0) { + hash_function = ellswift_xdh_hash_x32; + data = NULL; + } else if ((i % 3) == 1) { + hash_function = secp256k1_ellswift_xdh_hash_function_bip324; + data = NULL; + } else { + hash_function = secp256k1_ellswift_xdh_hash_function_prefix; + testrand256_test(prefix64); + testrand256_test(prefix64 + 32); + data = prefix64; + } + + /* Generate random secret keys and random randomizers. */ + testrand256_test(auxrnd32a); + testrand256_test(auxrnd32b); + testutil_random_scalar_order_test(&seca); + /* Draw secb uniformly at random to make sure that the secret keys + * differ */ + testutil_random_scalar_order(&secb); + secp256k1_scalar_get_b32(sec32a, &seca); + secp256k1_scalar_get_b32(sec32b, &secb); + + /* Construct ElligatorSwift-encoded public keys for those keys. */ + /* For A: */ + ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a); + CHECK(ret); + /* For B: */ + ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b); + CHECK(ret); + + /* Compute the shared secret both ways and compare with each other. */ + /* For A: */ + ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); + CHECK(ret); + /* For B: */ + ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + /* And compare: */ + CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0); + + /* Verify that the shared secret doesn't match if other side's public key is incorrect. */ + /* For A (using a bad public key for B): */ + memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); + testrand_flip(ell64b_bad, sizeof(ell64b_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */ + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (using a bad public key for A): */ + memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); + testrand_flip(ell64a_bad, sizeof(ell64a_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that the shared secret doesn't match if the private key is incorrect. */ + /* For A: */ + memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); + testrand_flip(sec32a_bad, sizeof(sec32a_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); + CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B: */ + memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); + testrand_flip(sec32b_bad, sizeof(sec32b_bad)); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); + CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + if (hash_function != ellswift_xdh_hash_x32) { + /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */ + /* For A (changing B's public key): */ + memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); + testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); + ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); + CHECK(ret); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (changing A's public key): */ + memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); + testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); + ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); + CHECK(ret); + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + + /* Verify that swapping sides changes the shared secret. */ + /* For A (claiming to be B): */ + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); + /* For B (claiming to be A): */ + ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); + CHECK(ret); + CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); + } + } + + /* Test hash initializers. */ + { + secp256k1_sha256 sha, sha_optimized; + static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; + static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; + static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_encode has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag)); + secp256k1_ellswift_sha256_init_encode(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_create has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag)); + secp256k1_ellswift_sha256_init_create(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_bip324 has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag)); + secp256k1_ellswift_sha256_init_bip324(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + } +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/Makefile.am.include new file mode 100644 index 000000000..0d901ec1f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/Makefile.am.include @@ -0,0 +1,4 @@ +include_HEADERS += include/secp256k1_extrakeys.h +noinst_HEADERS += src/modules/extrakeys/tests_impl.h +noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/extrakeys/main_impl.h diff --git a/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/main_impl.h new file mode 100644 index 000000000..0c7e26677 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/main_impl.h @@ -0,0 +1,285 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H +#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../util.h" + +static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) { + return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey); +} + +static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) { + secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge); +} + +int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) { + secp256k1_ge pk; + secp256k1_fe x; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input32 != NULL); + + if (!secp256k1_fe_set_b32_limit(&x, input32)) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&pk)) { + return 0; + } + secp256k1_xonly_pubkey_save(pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) { + secp256k1_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output32 != NULL); + memset(output32, 0, 32); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + secp256k1_fe_get_b32(output32, &pk.x); + return 1; +} + +int secp256k1_xonly_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_xonly_pubkey* pk0, const secp256k1_xonly_pubkey* pk1) { + unsigned char out[2][32]; + const secp256k1_xonly_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pk0; pk[1] = pk1; + for (i = 0; i < 2; i++) { + /* If the public key is NULL or invalid, xonly_pubkey_serialize will + * call the illegal_callback and return 0. In that case we will + * serialize the key as all zeros which is less than any valid public + * key. This results in consistent comparisons even if NULL or invalid + * pubkeys are involved and prevents edge cases such as sorting + * algorithms that use this function and do not terminate as a + * result. */ + if (!secp256k1_xonly_pubkey_serialize(ctx, out[i], pk[i])) { + /* Note that xonly_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1])); +} + +/** Keeps a group element as is if it has an even Y and otherwise negates it. + * y_parity is set to 0 in the former case and to 1 in the latter case. + * Requires that the coordinates of r are normalized. */ +static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) { + int y_parity = 0; + VERIFY_CHECK(!secp256k1_ge_is_infinity(r)); + + if (secp256k1_fe_is_odd(&r->y)) { + secp256k1_fe_negate(&r->y, &r->y, 1); + y_parity = 1; + } + return y_parity; +} + +int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) { + secp256k1_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(xonly_pubkey != NULL); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + tmp = secp256k1_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + secp256k1_xonly_pubkey_save(xonly_pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_ge pk; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output_pubkey != NULL); + memset(output_pubkey, 0, sizeof(*output_pubkey)); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + secp256k1_pubkey_save(output_pubkey, &pk); + return 1; +} + +int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) { + secp256k1_ge pk; + unsigned char pk_expected32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(internal_pubkey != NULL); + ARG_CHECK(tweaked_pubkey32 != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey) + || !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) { + return 0; + } + secp256k1_fe_normalize_var(&pk.x); + secp256k1_fe_normalize_var(&pk.y); + secp256k1_fe_get_b32(pk_expected32, &pk.x); + + return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 + && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; +} + +static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) { + secp256k1_scalar_get_b32(&keypair->data[0], sk); + secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk); +} + + +static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) { + int ret; + + ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]); + /* We can declassify ret here because sk is only zero if a keypair function + * failed (which zeroes the keypair) and its return value is ignored. */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + ARG_CHECK(ret); + return ret; +} + +/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk + * and ARG_CHECKs that the keypair is not invalid. It always initializes sk and + * pk with dummy values. */ +static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) { + int ret; + const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32]; + + /* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's + * invalid. */ + secp256k1_declassify(ctx, pubkey, sizeof(*pubkey)); + ret = secp256k1_pubkey_load(ctx, pk, pubkey); + if (sk != NULL) { + ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair); + } + if (!ret) { + *pk = secp256k1_ge_const_g; + if (sk != NULL) { + *sk = secp256k1_scalar_one; + } + } + return ret; +} + +int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) { + secp256k1_scalar sk; + secp256k1_ge pk; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + memset(keypair, 0, sizeof(*keypair)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey32 != NULL); + + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32); + secp256k1_keypair_save(keypair, &sk, &pk); + secp256k1_memczero(keypair, sizeof(*keypair), !ret); + + secp256k1_scalar_clear(&sk); + return ret; +} + +int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + memset(seckey, 0, 32); + ARG_CHECK(keypair != NULL); + + memcpy(seckey, &keypair->data[0], 32); + return 1; +} + +int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey)); + return 1; +} + +int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) { + secp256k1_ge pk; + int tmp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(keypair != NULL); + + if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) { + return 0; + } + tmp = secp256k1_extrakeys_ge_even_y(&pk); + if (pk_parity != NULL) { + *pk_parity = tmp; + } + secp256k1_xonly_pubkey_save(pubkey, &pk); + + return 1; +} + +int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) { + secp256k1_ge pk; + secp256k1_scalar sk; + int y_parity; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(tweak32 != NULL); + + ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair); + memset(keypair, 0, sizeof(*keypair)); + + y_parity = secp256k1_extrakeys_ge_even_y(&pk); + if (y_parity == 1) { + secp256k1_scalar_negate(&sk, &sk); + } + + ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32); + ret &= secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32); + + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret) { + secp256k1_keypair_save(keypair, &sk, &pk); + } + + secp256k1_scalar_clear(&sk); + return ret; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_exhaustive_impl.h new file mode 100644 index 000000000..645bae2d4 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_exhaustive_impl.h @@ -0,0 +1,68 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_extrakeys.h" +#include "main_impl.h" + +static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parities[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + int i; + + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_fe fe; + secp256k1_scalar scalar_i; + unsigned char buf[33]; + int parity; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + + /* Construct pubkey and keypair. */ + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); + + /* Construct serialized xonly_pubkey from keypair. */ + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + + /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); + CHECK(parity == parities[i - 1]); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Compare the xonly_pubkey bytes against the precomputed group. */ + secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); + CHECK(secp256k1_fe_equal(&fe, &group[i].x)); + + /* Check the parity against the precomputed group. */ + fe = group[i].y; + secp256k1_fe_normalize_var(&fe); + CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]); + + /* Verify that the higher half is identical to the lower half mirrored. */ + if (i > EXHAUSTIVE_TEST_ORDER / 2) { + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); + CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); + } + } + + /* TODO: keypair/xonly_pubkey tweak tests */ +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_impl.h new file mode 100644 index 000000000..ab4ef4a74 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/extrakeys/tests_impl.h @@ -0,0 +1,483 @@ +/*********************************************************************** + * Copyright (c) 2020 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H +#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H + +#include "../../../include/secp256k1_extrakeys.h" + +static void test_xonly_pubkey(void) { + secp256k1_pubkey pk; + secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; + secp256k1_ge pk1; + secp256k1_ge pk2; + secp256k1_fe y; + unsigned char sk[32]; + unsigned char xy_sk[32]; + unsigned char buf32[32]; + unsigned char ones32[32]; + unsigned char zeros64[64] = { 0 }; + int pk_parity; + int i; + + testrand256(sk); + memset(ones32, 0xFF, 32); + testrand256(xy_sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + + /* Test xonly_pubkey_from_pubkey */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk)); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL)); + memset(&pk, 0, sizeof(pk)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk)); + + /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ + memset(sk, 0, sizeof(sk)); + sk[0] = 1; + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); + CHECK(pk_parity == 0); + + /* Choose a secret key such that pubkey and xonly_pubkey are each others + * negation. */ + sk[0] = 2; + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); + CHECK(pk_parity == 1); + secp256k1_pubkey_load(CTX, &pk1, &pk); + secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk); + CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); + secp256k1_fe_negate(&y, &pk2.y, 1); + CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); + + /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL)); + CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); + { + /* A pubkey filled with 0s will fail to serialize due to pubkey_load + * special casing. */ + secp256k1_xonly_pubkey pk_tmp; + memset(&pk_tmp, 0, sizeof(pk_tmp)); + /* pubkey_load calls illegal callback */ + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp)); + } + + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL)); + + /* Serialization and parse roundtrip */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); + + /* Test parsing invalid field elements */ + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* Overflowing field element */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + memset(&xonly_pk, 1, sizeof(xonly_pk)); + /* There's no point with x-coordinate 0 on secp256k1 */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + /* If a random 32-byte string can not be parsed with ec_pubkey_parse + * (because interpreted as X coordinate it does not correspond to a point on + * the curve) then xonly_pubkey_parse should fail as well. */ + for (i = 0; i < COUNT; i++) { + unsigned char rand33[33]; + testrand256(&rand33[1]); + rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; + if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) { + memset(&xonly_pk, 1, sizeof(xonly_pk)); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + } else { + CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1); + } + } +} + +static void test_xonly_pubkey_comparison(void) { + unsigned char pk1_ser[32] = { + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[32] = { + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + secp256k1_xonly_pubkey pk1; + secp256k1_xonly_pubkey pk2; + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0); + memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0)); +} + +static void test_xonly_pubkey_tweak(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + secp256k1_pubkey internal_pk; + secp256k1_xonly_pubkey internal_xonly_pk; + secp256k1_pubkey output_pk; + int pk_parity; + unsigned char tweak[32]; + int i; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak)); + /* NULL internal_xonly_pk zeroes the output_pk */ + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL)); + /* NULL tweak zeroes the output_pk */ + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* Invalid tweak zeroes the output_pk */ + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + + /* A zero tweak is fine */ + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1); + + /* Fails if the resulting key was infinity */ + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar_tweak; + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); + secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); + secp256k1_scalar_get_b32(tweak, &scalar_tweak); + CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0) + || (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0)); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); + } + + /* Invalid pk with a valid tweak */ + memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +static void test_xonly_pubkey_tweak_check(void) { + unsigned char zeros64[64] = { 0 }; + unsigned char overflows[32]; + unsigned char sk[32]; + secp256k1_pubkey internal_pk; + secp256k1_xonly_pubkey internal_xonly_pk; + secp256k1_pubkey output_pk; + secp256k1_xonly_pubkey output_xonly_pk; + unsigned char output_pk32[32]; + unsigned char buf32[32]; + int pk_parity; + unsigned char tweak[32]; + + memset(overflows, 0xff, sizeof(overflows)); + testrand256(tweak); + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak)); + /* invalid pk_parity value */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL)); + + memset(tweak, 1, sizeof(tweak)); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); + + /* Wrong pk_parity */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); + /* Wrong public key */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); + + /* Overflowing tweak not allowed */ + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); +} + +/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 + * additional pubkeys by calling tweak_add. Then verifies every tweak starting + * from the last pubkey. */ +#define N_PUBKEYS 32 +static void test_xonly_pubkey_tweak_recursive(void) { + unsigned char sk[32]; + secp256k1_pubkey pk[N_PUBKEYS]; + unsigned char pk_serialized[32]; + unsigned char tweak[N_PUBKEYS - 1][32]; + int i; + + testrand256(sk); + CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1); + /* Add tweaks */ + for (i = 0; i < N_PUBKEYS - 1; i++) { + secp256k1_xonly_pubkey xonly_pk; + memset(tweak[i], i + 1, sizeof(tweak[i])); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1); + } + + /* Verify tweaks */ + for (i = N_PUBKEYS - 1; i > 0; i--) { + secp256k1_xonly_pubkey xonly_pk; + int pk_parity; + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); + } +} +#undef N_PUBKEYS + +static void test_keypair(void) { + unsigned char sk[32]; + unsigned char sk_tmp[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char overflows[32]; + secp256k1_keypair keypair; + secp256k1_pubkey pk, pk_tmp; + secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; + int pk_parity, pk_parity_tmp; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + memset(overflows, 0xFF, sizeof(overflows)); + + /* Test keypair_create */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk)); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Invalid secret key */ + CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); + + /* Test keypair_pub */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* Using an invalid keypair is fine for keypair_pub */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); + + /* keypair holds the same pubkey as pubkey_create */ + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); + + /** Test keypair_xonly_pub **/ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + /* Using an invalid keypair will set the xonly_pk to 0 (first reset + * xonly_pk). */ + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); + memset(&keypair, 0, sizeof(keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair)); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + + /** keypair holds the same xonly pubkey as pubkey_create **/ + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); + CHECK(pk_parity == pk_parity_tmp); + + /* Test keypair_seckey */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL)); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); + + /* keypair returns the same seckey it got */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); + + + /* Using an invalid keypair is fine for keypair_seckey */ + memset(&keypair, 0, sizeof(keypair)); + CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); + CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); +} + +static void test_keypair_add(void) { + unsigned char sk[32]; + secp256k1_keypair keypair; + unsigned char overflows[32]; + unsigned char zeros96[96] = { 0 }; + unsigned char tweak[32]; + int i; + + CHECK(sizeof(zeros96) == sizeof(keypair)); + testrand256(sk); + testrand256(tweak); + memset(overflows, 0xFF, 32); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL)); + /* This does not set the keypair to zeroes */ + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); + + /* Invalid tweak zeroes the keypair */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + + /* A zero tweak is fine */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1); + + /* Fails if the resulting keypair was (sk=0, pk=infinity) */ + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar_tweak; + secp256k1_keypair keypair_tmp; + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memcpy(&keypair_tmp, &keypair, sizeof(keypair)); + /* Because sk may be negated before adding, we need to try with tweak = + * sk as well as tweak = -sk. */ + secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); + secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); + secp256k1_scalar_get_b32(tweak, &scalar_tweak); + CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0) + || (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0)); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 + || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); + } + + /* Invalid keypair with a valid tweak */ + memset(&keypair, 0, sizeof(keypair)); + testrand256(tweak); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); + /* Only seckey part of keypair invalid */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair, 0, 32); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + /* Only pubkey part of keypair invalid */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + memset(&keypair.data[32], 0, 64); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); + + /* Check that the keypair_tweak_add implementation is correct */ + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + for (i = 0; i < COUNT; i++) { + secp256k1_xonly_pubkey internal_pk; + secp256k1_xonly_pubkey output_pk; + secp256k1_pubkey output_pk_xy; + secp256k1_pubkey output_pk_expected; + unsigned char pk32[32]; + unsigned char sk32[32]; + int pk_parity; + + testrand256(tweak); + CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + + /* Check that it passes xonly_pubkey_tweak_add_check */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1); + + /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ + CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + + /* Check that the secret key in the keypair is tweaked correctly */ + CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + } +} + +static void run_extrakeys_tests(void) { + /* xonly key test cases */ + test_xonly_pubkey(); + test_xonly_pubkey_tweak(); + test_xonly_pubkey_tweak_check(); + test_xonly_pubkey_tweak_recursive(); + test_xonly_pubkey_comparison(); + + /* keypair tests */ + test_keypair(); + test_keypair_add(); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/musig/Makefile.am.include new file mode 100644 index 000000000..796443c93 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_musig.h +noinst_HEADERS += src/modules/musig/main_impl.h +noinst_HEADERS += src/modules/musig/keyagg.h +noinst_HEADERS += src/modules/musig/keyagg_impl.h +noinst_HEADERS += src/modules/musig/session.h +noinst_HEADERS += src/modules/musig/session_impl.h +noinst_HEADERS += src/modules/musig/tests_impl.h +noinst_HEADERS += src/modules/musig/vectors.h diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg.h new file mode 100644 index 000000000..a0b37252f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg.h @@ -0,0 +1,32 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../group.h" +#include "../../scalar.h" + +typedef struct { + secp256k1_ge pk; + /* If there is no "second" public key, second_pk is set to the point at + * infinity */ + secp256k1_ge second_pk; + unsigned char pks_hash[32]; + /* tweak is identical to value tacc[v] in the specification. */ + secp256k1_scalar tweak; + /* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is + * -1, parity_acc is 1. Otherwise, parity_acc is 0. */ + int parity_acc; +} secp256k1_keyagg_cache_internal; + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); + +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg_impl.h new file mode 100644 index 000000000..0db4fce85 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/keyagg_impl.h @@ -0,0 +1,291 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H +#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H + +#include + +#include "keyagg.h" +#include "../../eckey.h" +#include "../../ecmult.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf }; + +/* A keyagg cache consists of + * - 4 byte magic set during initialization to allow detecting an uninitialized + * object. + * - 64 byte aggregate (and potentially tweaked) public key + * - 64 byte "second" public key (set to the point at infinity if not present) + * - 32 byte hash of all public keys + * - 1 byte the parity of the internal key (if tweaked, otherwise 0) + * - 32 byte tweak + */ +/* Requires that cache_i->pk is not infinity. */ +static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, const secp256k1_keyagg_cache_internal *cache_i) { + unsigned char *ptr = cache->data; + memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4); + ptr += 4; + secp256k1_ge_to_bytes(ptr, &cache_i->pk); + ptr += 64; + secp256k1_ge_to_bytes_ext(ptr, &cache_i->second_pk); + ptr += 64; + memcpy(ptr, cache_i->pks_hash, 32); + ptr += 32; + *ptr = cache_i->parity_acc; + ptr += 1; + secp256k1_scalar_get_b32(ptr, &cache_i->tweak); +} + +static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) { + const unsigned char *ptr = cache->data; + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0); + ptr += 4; + secp256k1_ge_from_bytes(&cache_i->pk, ptr); + ptr += 64; + secp256k1_ge_from_bytes_ext(&cache_i->second_pk, ptr); + ptr += 64; + memcpy(cache_i->pks_hash, ptr, 32); + ptr += 32; + cache_i->parity_acc = *ptr & 1; + ptr += 1; + secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ +static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0xb399d5e0ul; + sha->s[1] = 0xc8fff302ul; + sha->s[2] = 0x6badac71ul; + sha->s[3] = 0x07c5b7f1ul; + sha->s[4] = 0x9701e2eful; + sha->s[5] = 0x2a72ecf8ul; + sha->s[6] = 0x201a4c7bul; + sha->s[7] = 0xab148a38ul; + sha->bytes = 64; +} + +/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */ +static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsigned char *pks_hash, const secp256k1_pubkey * const* pks, size_t np) { + secp256k1_sha256 sha; + size_t i; + + secp256k1_musig_keyagglist_sha256(&sha); + for (i = 0; i < np; i++) { + unsigned char ser[33]; + size_t ser_len = sizeof(ser); + if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) { + return 0; + } + VERIFY_CHECK(ser_len == sizeof(ser)); + secp256k1_sha256_write(&sha, ser, sizeof(ser)); + } + secp256k1_sha256_finalize(&sha, pks_hash); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ +static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + + sha->s[0] = 0x6ef02c5aul; + sha->s[1] = 0x06a480deul; + sha->s[2] = 0x1f298665ul; + sha->s[3] = 0x1d1134f2ul; + sha->s[4] = 0x56a0b063ul; + sha->s[5] = 0x52da4147ul; + sha->s[6] = 0xf280d9d4ul; + sha->s[7] = 0x4484be15ul; + sha->bytes = 64; +} + +/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and + * otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys. + * second_pk is the point at infinity in case there is no second_pk. Assumes + * that pk is not the point at infinity and that the Y-coordinates of pk and + * second_pk are normalized. */ +static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); + + if (!secp256k1_ge_is_infinity(second_pk) + && secp256k1_ge_eq_var(pk, second_pk)) { + secp256k1_scalar_set_int(r, 1); + } else { + secp256k1_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int ret; + secp256k1_musig_keyaggcoef_sha256(&sha); + secp256k1_sha256_write(&sha, pks_hash, 32); + ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); +#ifdef VERIFY + /* Serialization does not fail since the pk is not the point at infinity + * (according to this function's precondition). */ + VERIFY_CHECK(ret && buflen == sizeof(buf)); +#else + (void) ret; +#endif + secp256k1_sha256_write(&sha, buf, sizeof(buf)); + secp256k1_sha256_finalize(&sha, buf); + secp256k1_scalar_set_b32(r, buf, NULL); + } +} + +/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk + * and cache_i->second_pk are normalized. */ +static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { + secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); +} + +typedef struct { + const secp256k1_context *ctx; + /* pks_hash is the hash of the public keys */ + unsigned char pks_hash[32]; + const secp256k1_pubkey * const* pks; + secp256k1_ge second_pk; +} secp256k1_musig_pubkey_agg_ecmult_data; + +/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */ +static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) { + secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data; + int ret; + ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); +#ifdef VERIFY + /* pubkey_load can't fail because the same pks have already been loaded in + * `musig_compute_pks_hash` (and we test this). */ + VERIFY_CHECK(ret); +#else + (void) ret; +#endif + secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); + return 1; +} + +int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) { + secp256k1_musig_pubkey_agg_ecmult_data ecmult_data; + secp256k1_gej pkj; + secp256k1_ge pkp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + if (agg_pk != NULL) { + memset(agg_pk, 0, sizeof(*agg_pk)); + } + ARG_CHECK(pubkeys != NULL); + ARG_CHECK(n_pubkeys > 0); + + ecmult_data.ctx = ctx; + ecmult_data.pks = pubkeys; + + secp256k1_ge_set_infinity(&ecmult_data.second_pk); + for (i = 1; i < n_pubkeys; i++) { + if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) { + secp256k1_ge pk; + if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) { + return 0; + } + ecmult_data.second_pk = pk; + break; + } + } + + if (!secp256k1_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) { + return 0; + } + /* TODO: actually use optimized ecmult_multi algorithms by providing a + * scratch space */ + if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) { + /* In order to reach this line with the current implementation of + * ecmult_multi_var one would need to provide a callback that can + * fail. */ + return 0; + } + secp256k1_ge_set_gej(&pkp, &pkj); + secp256k1_fe_normalize_var(&pkp.y); + /* The resulting public key is infinity with negligible probability */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp)); + if (keyagg_cache != NULL) { + secp256k1_keyagg_cache_internal cache_i = { 0 }; + cache_i.pk = pkp; + cache_i.second_pk = ecmult_data.second_pk; + memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + } + + if (agg_pk != NULL) { + secp256k1_extrakeys_ge_even_y(&pkp); + secp256k1_xonly_pubkey_save(agg_pk, &pkp); + } + return 1; +} + +int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_keyagg_cache_internal cache_i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(agg_pk != NULL); + memset(agg_pk, 0, sizeof(*agg_pk)); + ARG_CHECK(keyagg_cache != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_pubkey_save(agg_pk, &cache_i.pk); + return 1; +} + +static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) { + secp256k1_keyagg_cache_internal cache_i; + int overflow = 0; + secp256k1_scalar tweak; + + VERIFY_CHECK(ctx != NULL); + if (output_pubkey != NULL) { + memset(output_pubkey, 0, sizeof(*output_pubkey)); + } + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(tweak32 != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_scalar_set_b32(&tweak, tweak32, &overflow); + if (overflow) { + return 0; + } + if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) { + cache_i.parity_acc ^= 1; + secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak); + } + secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak); + if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) { + return 0; + } + /* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */ + VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk)); + secp256k1_keyagg_cache_save(keyagg_cache, &cache_i); + if (output_pubkey != NULL) { + secp256k1_pubkey_save(output_pubkey, &cache_i.pk); + } + return 1; +} + +int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0); +} + +int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) { + return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/main_impl.h new file mode 100644 index 000000000..a1311e419 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/main_impl.h @@ -0,0 +1,12 @@ +/********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_MAIN_H +#define SECP256K1_MODULE_MUSIG_MAIN_H + +#include "keyagg_impl.h" +#include "session_impl.h" + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/session.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/session.h new file mode 100644 index 000000000..d6d76bc6c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/session.h @@ -0,0 +1,24 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_H +#define SECP256K1_MODULE_MUSIG_SESSION_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_musig.h" + +#include "../../scalar.h" + +typedef struct { + int fin_nonce_parity; + unsigned char fin_nonce[32]; + secp256k1_scalar noncecoef; + secp256k1_scalar challenge; + secp256k1_scalar s_part; +} secp256k1_musig_session_internal; + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session); + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/session_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/session_impl.h new file mode 100644 index 000000000..dde380858 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/session_impl.h @@ -0,0 +1,816 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H +#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H + +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "keyagg.h" +#include "session.h" +#include "../../eckey.h" +#include "../../hash.h" +#include "../../scalar.h" +#include "../../util.h" + +/* Outputs 33 zero bytes if the given group element is the point at infinity and + * otherwise outputs the compressed serialization */ +static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(out33, 0, 33); + } else { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); +#ifdef VERIFY + /* Serialize must succeed because the point is not at infinity */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } +} + +/* Outputs the point at infinity if the given byte array is all zero, otherwise + * attempts to parse compressed point serialization. */ +static int secp256k1_musig_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { + unsigned char zeros[33] = { 0 }; + + if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + return 1; + } + if (!secp256k1_eckey_pubkey_parse(ge, in33, 33)) { + return 0; + } + return secp256k1_ge_is_in_correct_subgroup(ge); +} + +static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 }; + +static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, const secp256k1_ge *pk) { + memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4); + secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]); + secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]); + secp256k1_ge_to_bytes(&secnonce->data[68], pk); +} + +static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, const secp256k1_musig_secnonce *secnonce) { + int is_zero; + ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0); + /* We make very sure that the nonce isn't invalidated by checking the values + * in addition to the magic. */ + is_zero = secp256k1_is_zero_array(&secnonce->data[4], 2 * 32); + secp256k1_declassify(ctx, &is_zero, sizeof(is_zero)); + ARG_CHECK(!is_zero); + + secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL); + secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL); + secp256k1_ge_from_bytes(pk, &secnonce->data[68]); + return 1; +} + +/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ +static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) { + secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag); + /* The flag argument is usually classified. So, the line above makes the + * magic and public key classified. However, we need both to be + * declassified. Note that we don't declassify the entire object, because if + * flag is 0, then k[0] and k[1] have not been zeroed. */ + secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic)); + secp256k1_declassify(ctx, &secnonce->data[68], 64); +} + +static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 }; + +/* Saves two group elements into a pubnonce. Requires that none of the provided + * group elements is infinity. */ +static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, const secp256k1_ge* ges) { + int i; + memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ges[i]); + } +} + +/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't + * properly initialized */ +static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_pubnonce* nonce) { + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i); + } + return 1; +} + +static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 }; + +static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, const secp256k1_ge* ges) { + int i; + memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4); + for (i = 0; i < 2; i++) { + secp256k1_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]); + } +} + +static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_aggnonce* nonce) { + int i; + + ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0); + for (i = 0; i < 2; i++) { + secp256k1_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]); + } + return 1; +} + +static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 }; + +/* A session consists of + * - 4 byte session cache magic + * - 1 byte the parity of the final nonce + * - 32 byte serialized x-only final nonce + * - 32 byte nonce coefficient b + * - 32 byte signature challenge hash e + * - 32 byte scalar s that is added to the partial signatures of the signers + */ +static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) { + unsigned char *ptr = session->data; + + memcpy(ptr, secp256k1_musig_session_cache_magic, 4); + ptr += 4; + *ptr = session_i->fin_nonce_parity; + ptr += 1; + memcpy(ptr, session_i->fin_nonce, 32); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->noncecoef); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->challenge); + ptr += 32; + secp256k1_scalar_get_b32(ptr, &session_i->s_part); +} + +static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) { + const unsigned char *ptr = session->data; + + ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0); + ptr += 4; + session_i->fin_nonce_parity = *ptr; + ptr += 1; + memcpy(session_i->fin_nonce, ptr, 32); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL); + ptr += 32; + secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL); + return 1; +} + +static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 }; + +static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) { + memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4); + secp256k1_scalar_get_b32(&sig->data[4], s); +} + +static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) { + int overflow; + + ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); + secp256k1_scalar_set_b32(s, &sig->data[4], &overflow); + /* Parsed signatures can not overflow */ + VERIFY_CHECK(!overflow); + return 1; +} + +int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!secp256k1_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) { + return 0; + } + if (!secp256k1_ge_is_in_correct_subgroup(&ges[i])) { + return 0; + } + } + secp256k1_musig_pubnonce_save(nonce, ges); + return 1; +} + +int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!secp256k1_musig_pubnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + int ret; + size_t size = 33; + ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1); +#ifdef VERIFY + /* serialize must succeed because the point was just loaded */ + VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif + } + return 1; +} + +int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(in66 != NULL); + + for (i = 0; i < 2; i++) { + if (!secp256k1_musig_ge_parse_ext(&ges[i], &in66[33*i])) { + return 0; + } + } + secp256k1_musig_aggnonce_save(nonce, ges); + return 1; +} + +int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) { + secp256k1_ge ges[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out66 != NULL); + memset(out66, 0, 66); + ARG_CHECK(nonce != NULL); + + if (!secp256k1_musig_aggnonce_load(ctx, ges, nonce)) { + return 0; + } + for (i = 0; i < 2; i++) { + secp256k1_musig_ge_serialize_ext(&out66[33*i], &ges[i]); + } + return 1; +} + +int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) { + secp256k1_scalar tmp; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in32 != NULL); + + /* Ensure that using the signature will fail if parsing fails (and the user + * doesn't check the return value). */ + memset(sig, 0, sizeof(*sig)); + + secp256k1_scalar_set_b32(&tmp, in32, &overflow); + if (overflow) { + return 0; + } + secp256k1_musig_partial_sig_save(sig, &tmp); + return 1; +} + +int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0); + + memcpy(out32, &sig->data[4], 32); + return 1; +} + +/* Write optional inputs into the hash */ +static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { + unsigned char zero[7] = { 0 }; + /* The spec requires length prefixes to be between 1 and 8 bytes + * (inclusive) */ + VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8); + /* Since the length of all input data fits in a byte, we can always pad the + * length prefix with prefix_size - 1 zero bytes. */ + secp256k1_sha256_write(sha, zero, prefix_size - 1); + if (data != NULL) { + secp256k1_sha256_write(sha, &len, 1); + secp256k1_sha256_write(sha, data, len); + } else { + len = 0; + secp256k1_sha256_write(sha, &len, 1); + } +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */ +static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0xa19e884bul; + sha->s[1] = 0xf463fe7eul; + sha->s[2] = 0x2f18f9a2ul; + sha->s[3] = 0xbeb0f9fful; + sha->s[4] = 0x0f37e8b0ul; + sha->s[5] = 0x06ebd26ful; + sha->s[6] = 0xe3b243d2ul; + sha->s[7] = 0x522fb150ul; + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */ +static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x07101b64ul; + sha->s[1] = 0x18003414ul; + sha->s[2] = 0x0391bc43ul; + sha->s[3] = 0x0e6258eeul; + sha->s[4] = 0x29d26b72ul; + sha->s[5] = 0x8343937eul; + sha->s[6] = 0xb7a0a4fbul; + sha->s[7] = 0xff568a30ul; + sha->bytes = 64; +} + +static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { + secp256k1_sha256 sha; + unsigned char rand[32]; + unsigned char i; + unsigned char msg_present; + + if (seckey32 != NULL) { + secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); + secp256k1_sha256_write(&sha, session_secrand, 32); + secp256k1_sha256_finalize(&sha, rand); + for (i = 0; i < 32; i++) { + rand[i] ^= seckey32[i]; + } + } else { + memcpy(rand, session_secrand, sizeof(rand)); + } + + secp256k1_nonce_function_musig_sha256_tagged(&sha); + secp256k1_sha256_write(&sha, rand, sizeof(rand)); + secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); + secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); + msg_present = msg32 != NULL; + secp256k1_sha256_write(&sha, &msg_present, 1); + if (msg_present) { + secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32); + } + secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32); + + for (i = 0; i < 2; i++) { + unsigned char buf[32]; + secp256k1_sha256 sha_tmp = sha; + secp256k1_sha256_write(&sha_tmp, &i, 1); + secp256k1_sha256_finalize(&sha_tmp, buf); + secp256k1_scalar_set_b32(&k[i], buf, NULL); + + /* Attempt to erase secret data */ + secp256k1_memclear(buf, sizeof(buf)); + secp256k1_sha256_clear(&sha_tmp); + } + secp256k1_memclear(rand, sizeof(rand)); + secp256k1_sha256_clear(&sha); +} + +static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + secp256k1_scalar k[2]; + secp256k1_ge nonce_pts[2]; + int i; + unsigned char pk_ser[33]; + size_t pk_ser_len = sizeof(pk_ser); + unsigned char aggpk_ser[32]; + unsigned char *aggpk_ser_ptr = NULL; + secp256k1_ge pk; + int pk_serialize_success; + int ret = 1; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + + /* Check that the seckey is valid to be able to sign for it later. */ + if (seckey != NULL) { + secp256k1_scalar sk; + ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey); + secp256k1_scalar_clear(&sk); + } + + if (keyagg_cache != NULL) { + secp256k1_keyagg_cache_internal cache_i; + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* The loaded point cache_i.pk can not be the point at infinity. */ + secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x); + aggpk_ser_ptr = aggpk_ser; + } + if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1); + +#ifdef VERIFY + /* A pubkey cannot be the point at infinity */ + VERIFY_CHECK(pk_serialize_success); + VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); +#else + (void) pk_serialize_success; +#endif + + secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); + VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); + secp256k1_musig_secnonce_save(secnonce, k, &pk); + secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); + + for (i = 0; i < 2; i++) { + secp256k1_gej nonce_ptj; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); + secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj); + secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); + secp256k1_scalar_clear(&k[i]); + secp256k1_gej_clear(&nonce_ptj); + } + /* None of the nonce_pts will be infinity because k != 0 with overwhelming + * probability */ + secp256k1_musig_pubnonce_save(pubnonce, nonce_pts); + return ret; +} + +int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(session_secrand32 != NULL); + + /* Check in constant time that the session_secrand32 is not 0 as a + * defense-in-depth measure that may protect against a faulty RNG. */ + ret &= !secp256k1_is_zero_array(session_secrand32, 32); + + /* We can declassify because branching on ret is only relevant when this + * function called with an invalid session_secrand32 argument */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret == 0) { + secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1); + return 0; + } + + ret &= secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32); + + /* Set the session_secrand32 buffer to zero to prevent the caller from using + * nonce_gen multiple times with the same buffer. */ + secp256k1_memczero(session_secrand32, 32, ret); + return ret; +} + +int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const secp256k1_keypair *keypair, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + unsigned char buf[32] = { 0 }; + unsigned char seckey[32]; + secp256k1_pubkey pubkey; + int ret; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secnonce != NULL); + memset(secnonce, 0, sizeof(*secnonce)); + ARG_CHECK(keypair != NULL); + + secp256k1_write_be64(buf, nonrepeating_cnt); + /* keypair_sec and keypair_pub do not fail if the arguments are not NULL */ + ret = secp256k1_keypair_sec(ctx, seckey, keypair); + VERIFY_CHECK(ret); + ret = secp256k1_keypair_pub(ctx, &pubkey, keypair); + VERIFY_CHECK(ret); +#ifndef VERIFY + (void) ret; +#endif + + if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) { + return 0; + } + secp256k1_memclear(seckey, sizeof(seckey)); + return 1; +} + +static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + size_t i; + int j; + + secp256k1_gej_set_infinity(&summed_pubnonces[0]); + secp256k1_gej_set_infinity(&summed_pubnonces[1]); + + for (i = 0; i < n_pubnonces; i++) { + secp256k1_ge nonce_pts[2]; + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) { + return 0; + } + for (j = 0; j < 2; j++) { + secp256k1_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL); + } + } + return 1; +} + +int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { + secp256k1_gej aggnonce_ptsj[2]; + secp256k1_ge aggnonce_pts[2]; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(pubnonces != NULL); + ARG_CHECK(n_pubnonces > 0); + + if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) { + return 0; + } + secp256k1_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2); + secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pts); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */ +static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x2c7d5a45ul; + sha->s[1] = 0x06bf7e53ul; + sha->s[2] = 0x89be68a6ul; + sha->s[3] = 0x971254c0ul; + sha->s[4] = 0x60ac12d2ul; + sha->s[5] = 0x72846dcdul; + sha->s[6] = 0x6c81212ful; + sha->s[7] = 0xde7a2500ul; + sha->bytes = 64; +} + +/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ +static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char buf[33]; + secp256k1_sha256 sha; + int i; + + secp256k1_musig_compute_noncehash_sha256_tagged(&sha); + for (i = 0; i < 2; i++) { + secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]); + secp256k1_sha256_write(&sha, buf, sizeof(buf)); + } + secp256k1_sha256_write(&sha, agg_pk32, 32); + secp256k1_sha256_write(&sha, msg, 32); + secp256k1_sha256_finalize(&sha, noncehash); +} + +/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */ +static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ge *nonce_pts, const secp256k1_scalar *b) { + secp256k1_gej tmp; + + secp256k1_gej_set_ge(&tmp, &nonce_pts[1]); + secp256k1_ecmult(out_nonce, &tmp, b, NULL); + secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); +} + +static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { + unsigned char noncehash[32]; + secp256k1_ge fin_nonce_pt; + secp256k1_gej fin_nonce_ptj; + + secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); + secp256k1_scalar_set_b32(b, noncehash, NULL); + /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ + secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); + secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj); + if (secp256k1_ge_is_infinity(&fin_nonce_pt)) { + fin_nonce_pt = secp256k1_ge_const_g; + } + /* fin_nonce_pt is not the point at infinity */ + secp256k1_fe_normalize_var(&fin_nonce_pt.x); + secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x); + secp256k1_fe_normalize_var(&fin_nonce_pt.y); + *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); +} + +int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_ge aggnonce_pts[2]; + unsigned char fin_nonce[32]; + secp256k1_musig_session_internal session_i; + unsigned char agg_pk32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(aggnonce != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(keyagg_cache != NULL); + + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x); + + if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) { + return 0; + } + + secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); + secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + + /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ + secp256k1_scalar_set_int(&session_i.s_part, 0); + if (!secp256k1_scalar_is_zero(&cache_i.tweak)) { + secp256k1_scalar e_tmp; + secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak); + if (secp256k1_fe_is_odd(&cache_i.pk.y)) { + secp256k1_scalar_negate(&e_tmp, &e_tmp); + } + session_i.s_part = e_tmp; + } + memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce)); + secp256k1_musig_session_save(session, &session_i); + return 1; +} + +static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) { + secp256k1_scalar_clear(sk); + secp256k1_scalar_clear(&k[0]); + secp256k1_scalar_clear(&k[1]); +} + +int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_scalar sk; + secp256k1_ge pk, keypair_pk; + secp256k1_scalar k[2]; + secp256k1_scalar mu, s; + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + int ret; + + VERIFY_CHECK(ctx != NULL); + + ARG_CHECK(secnonce != NULL); + /* Fails if the magic doesn't match */ + ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce); + /* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls + * of this function to fail */ + memset(secnonce, 0, sizeof(*secnonce)); + if (!ret) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(keypair != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x) + && secp256k1_fe_equal(&pk.y, &keypair_pk.y)); + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + /* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the + * specification. */ + if ((secp256k1_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc)) { + secp256k1_scalar_negate(&sk, &sk); + } + + /* Multiply KeyAgg coefficient */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk); + secp256k1_scalar_mul(&sk, &sk, &mu); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + secp256k1_musig_partial_sign_clear(&sk, k); + return 0; + } + + if (session_i.fin_nonce_parity) { + secp256k1_scalar_negate(&k[0], &k[0]); + secp256k1_scalar_negate(&k[1], &k[1]); + } + + /* Sign */ + secp256k1_scalar_mul(&s, &session_i.challenge, &sk); + secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]); + secp256k1_scalar_add(&k[0], &k[0], &k[1]); + secp256k1_scalar_add(&s, &s, &k[0]); + secp256k1_musig_partial_sig_save(partial_sig, &s); + secp256k1_musig_partial_sign_clear(&sk, k); + return 1; +} + +int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) { + secp256k1_keyagg_cache_internal cache_i; + secp256k1_musig_session_internal session_i; + secp256k1_scalar mu, e, s; + secp256k1_gej pkj; + secp256k1_ge nonce_pts[2]; + secp256k1_gej rj; + secp256k1_gej tmp; + secp256k1_ge pkp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(keyagg_cache != NULL); + ARG_CHECK(session != NULL); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + + if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) { + return 0; + } + /* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */ + /* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */ + secp256k1_effective_nonce(&rj, nonce_pts, &session_i.noncecoef); + + if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) { + return 0; + } + if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { + return 0; + } + /* Multiplying the challenge by the KeyAgg coefficient is equivalent + * to multiplying the signer's public key by the coefficient, except + * much easier to do. */ + secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp); + secp256k1_scalar_mul(&e, &session_i.challenge, &mu); + + /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. + * This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e" + * in the specification. */ + if (secp256k1_fe_is_odd(&cache_i.pk.y) + != cache_i.parity_acc) { + secp256k1_scalar_negate(&e, &e); + } + + if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) { + return 0; + } + /* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */ + secp256k1_scalar_negate(&s, &s); + secp256k1_gej_set_ge(&pkj, &pkp); + secp256k1_ecmult(&tmp, &pkj, &e, &s); + if (session_i.fin_nonce_parity) { + secp256k1_gej_neg(&rj, &rj); + } + secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL); + + return secp256k1_gej_is_infinity(&tmp); +} + +int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) { + size_t i; + secp256k1_musig_session_internal session_i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(partial_sigs != NULL); + ARG_CHECK(n_sigs > 0); + + if (!secp256k1_musig_session_load(ctx, &session_i, session)) { + return 0; + } + for (i = 0; i < n_sigs; i++) { + secp256k1_scalar term; + if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) { + return 0; + } + secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term); + } + secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part); + memcpy(&sig64[0], session_i.fin_nonce, 32); + return 1; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/tests_impl.h new file mode 100644 index 000000000..ce6ae1784 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/tests_impl.h @@ -0,0 +1,1143 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_MUSIG_TESTS_IMPL_H +#define SECP256K1_MODULE_MUSIG_TESTS_IMPL_H + +#include +#include + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_extrakeys.h" +#include "../../../include/secp256k1_musig.h" + +#include "session.h" +#include "keyagg.h" +#include "../../scalar.h" +#include "../../field.h" +#include "../../group.h" +#include "../../hash.h" +#include "../../util.h" + +#include "vectors.h" + +static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *pk, const unsigned char *sk) { + int ret; + secp256k1_keypair keypair_tmp; + ret = secp256k1_keypair_create(CTX, &keypair_tmp, sk); + ret &= secp256k1_keypair_pub(CTX, pk, &keypair_tmp); + if (keypair != NULL) { + *keypair = keypair_tmp; + } + return ret; +} + +/* Just a simple (non-tweaked) 2-of-2 MuSig aggregate, sign, verify + * test. */ +static void musig_simple_test(void) { + unsigned char sk[2][32]; + secp256k1_keypair keypair[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + unsigned char msg[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char session_secrand[2][32]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + secp256k1_musig_session session; + int i; + + testrand256(msg); + for (i = 0; i < 2; i++) { + testrand256(sk[i]); + pk_ptr[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + if (i == 0) { + testrand256(session_secrand[i]); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_secrand[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); + } else { + uint64_t nonrepeating_cnt = 0; + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[i], &pubnonce[i], nonrepeating_cnt, &keypair[i], NULL, NULL, NULL) == 1); + } + } + + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + for (i = 0; i < 2; i++) { + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[i], &secnonce[i], &keypair[i], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[i], &pubnonce[i], &pk[i], &keyagg_cache, &session) == 1); + } + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1); +} + +/* Generate two pubnonces such that both group elements of their sum (calculated + * with secp256k1_musig_sum_pubnonces) are infinity. */ +static void pubnonce_summing_to_inf(secp256k1_musig_pubnonce *pubnonce) { + secp256k1_ge ge[2]; + int i; + secp256k1_gej summed_pubnonces[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + + testutil_random_ge_test(&ge[0]); + testutil_random_ge_test(&ge[1]); + + for (i = 0; i < 2; i++) { + secp256k1_musig_pubnonce_save(&pubnonce[i], ge); + pubnonce_ptr[i] = &pubnonce[i]; + secp256k1_ge_neg(&ge[0], &ge[0]); + secp256k1_ge_neg(&ge[1], &ge[1]); + } + + secp256k1_musig_sum_pubnonces(CTX, summed_pubnonces, pubnonce_ptr, 2); + CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[0])); + CHECK(secp256k1_gej_is_infinity(&summed_pubnonces[1])); +} + +int memcmp_and_randomize(unsigned char *value, const unsigned char *expected, size_t len) { + int ret; + size_t i; + ret = secp256k1_memcmp_var(value, expected, len); + for (i = 0; i < len; i++) { + value[i] = testrand_bits(8); + } + return ret; +} + +static void musig_api_tests(void) { + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + secp256k1_musig_partial_sig invalid_partial_sig; + const secp256k1_musig_partial_sig *invalid_partial_sig_ptr[2]; + unsigned char pre_sig[64]; + unsigned char buf[32]; + unsigned char sk[2][32]; + secp256k1_keypair keypair[2]; + secp256k1_keypair invalid_keypair; + unsigned char max64[64]; + unsigned char zeros132[132] = { 0 }; + unsigned char session_secrand[2][32]; + unsigned char nonrepeating_cnt = 0; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_secnonce secnonce_tmp; + secp256k1_musig_secnonce invalid_secnonce; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + unsigned char pubnonce_ser[66]; + secp256k1_musig_pubnonce inf_pubnonce[2]; + const secp256k1_musig_pubnonce *inf_pubnonce_ptr[2]; + secp256k1_musig_pubnonce invalid_pubnonce; + const secp256k1_musig_pubnonce *invalid_pubnonce_ptr[1]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce_ser[66]; + unsigned char msg[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_pubkey full_agg_pk; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache invalid_keyagg_cache; + secp256k1_musig_session session; + secp256k1_musig_session invalid_session; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_pubkey invalid_pk; + const secp256k1_pubkey *invalid_pk_ptr2[2]; + const secp256k1_pubkey *invalid_pk_ptr3[3]; + unsigned char tweak[32]; + int i; + + /** setup **/ + memset(max64, 0xff, sizeof(max64)); + memset(&invalid_keypair, 0, sizeof(invalid_keypair)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_secnonce, 0, sizeof(invalid_secnonce)); + memset(&invalid_partial_sig, 0, sizeof(invalid_partial_sig)); + pubnonce_summing_to_inf(inf_pubnonce); + /* Simulate structs being uninitialized by setting it to 0s. We don't want + * to produce undefined behavior by actually providing uninitialized + * structs. */ + memset(&invalid_keyagg_cache, 0, sizeof(invalid_keyagg_cache)); + memset(&invalid_pk, 0, sizeof(invalid_pk)); + memset(&invalid_pubnonce, 0, sizeof(invalid_pubnonce)); + memset(&invalid_session, 0, sizeof(invalid_session)); + + testrand256(msg); + testrand256(tweak); + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + invalid_pk_ptr2[i] = &invalid_pk; + invalid_pk_ptr3[i] = &pk[i]; + pubnonce_ptr[i] = &pubnonce[i]; + inf_pubnonce_ptr[i] = &inf_pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + invalid_partial_sig_ptr[i] = &partial_sig[i]; + testrand256(session_secrand[i]); + testrand256(sk[i]); + CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); + } + invalid_pubnonce_ptr[0] = &invalid_pubnonce; + invalid_partial_sig_ptr[0] = &invalid_partial_sig; + /* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test + * musig_pubkey_agg */ + invalid_pk_ptr3[2] = &invalid_pk; + + /** main test body **/ + + /** Key aggregation **/ + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1); + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 0)); + CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); + + CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); + + /* pubkey_get */ + CHECK(secp256k1_musig_pubkey_get(CTX, &full_agg_pk, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, &full_agg_pk, NULL)); + CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); + + /** Tweaking **/ + { + int (*tweak_func[2]) (const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32); + tweak_func[0] = secp256k1_musig_pubkey_ec_tweak_add; + tweak_func[1] = secp256k1_musig_pubkey_xonly_tweak_add; + for (i = 0; i < 2; i++) { + secp256k1_pubkey tmp_output_pk; + secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); + /* Reset keyagg_cache */ + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, NULL, &tmp_keyagg_cache, tweak) == 1); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + tmp_keyagg_cache = keyagg_cache; + /* Uninitialized keyagg_cache */ + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak)); + CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); + } + } + + /** Session creation with nonce_gen **/ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + /* nonce_gen, if successful, sets session_secrand to the zero array, which + * makes subsequent nonce_gen calls with the same session_secrand fail. So + * check that session_secrand is indeed the zero array and fill it with + * random values again. */ + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + /* session_secrand = 0 is disallowed because it indicates a faulty RNG */ + memcpy(&session_secrand[0], zeros132, sizeof(session_secrand[0])); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* invalid seckey */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + CHECK(memcmp_and_randomize(session_secrand[0], zeros132, sizeof(session_secrand[0])) == 0); + + /* Every in-argument except session_secrand and pubkey can be NULL */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); + + /** Session creation with nonce_gen_counter **/ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen_counter(STATIC_CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, NULL, &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], NULL, nonrepeating_cnt, &keypair[0], msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* using nonce_gen_counter requires keypair */ + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, NULL, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + /* invalid keypair */ + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &invalid_keypair, msg, &keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, NULL, max64) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt,&keypair[0], msg, &keyagg_cache, NULL) == 1); + + /* Every in-argument except nonrepeating_cnt and keypair can be NULL */ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, &keypair[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[1], &pubnonce[1], nonrepeating_cnt, &keypair[1], NULL, NULL, NULL) == 1); + + + /** Serialize and parse public nonces **/ + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce)); + CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, NULL, pubnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], NULL)); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], zeros132) == 0); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_pubnonce tmp; + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); + CHECK(secp256k1_musig_pubnonce_parse(CTX, &tmp, pubnonce_ser) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &pubnonce[0], sizeof(tmp)) == 0); + } + + /** Receive nonces and aggregate **/ + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1)); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, inf_pubnonce_ptr, 2) == 1); + { + /* Check that the aggnonce encodes two points at infinity */ + secp256k1_ge aggnonce_pt[2]; + secp256k1_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); + for (i = 0; i < 2; i++) { + secp256k1_ge_is_infinity(&aggnonce_pt[i]); + } + } + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + + /** Serialize and parse aggregate nonces **/ + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, NULL, &aggnonce)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce)); + CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, NULL, aggnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, &aggnonce, NULL)); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, zeros132) == 1); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_aggnonce tmp; + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &tmp, aggnonce_ser) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &aggnonce, sizeof(tmp)) == 0); + } + + /** Process nonces **/ + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache)); + + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache) == 1); + + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); + /* The secnonce is set to 0 and subsequent signing attempts fail */ + CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + { + unsigned char sk_tmp[32]; + secp256k1_keypair keypair_tmp; + testrand256(sk_tmp); + CHECK(secp256k1_keypair_create(CTX, &keypair_tmp, sk_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + } + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session)); + memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, &invalid_partial_sig)); + CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], buf) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, NULL, buf)); + { + /* Check that parsing failure results in an invalid sig */ + secp256k1_musig_partial_sig tmp; + CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, max64) == 0); + CHECK(secp256k1_memcmp_var(&tmp, zeros132, sizeof(partial_sig[0])) == 0); + } + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], NULL)); + + { + /* Check that serialize and parse results in the same value */ + secp256k1_musig_partial_sig tmp; + CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); + CHECK(secp256k1_musig_partial_sig_parse(CTX, &tmp, buf) == 1); + CHECK(secp256k1_memcmp_var(&tmp, &partial_sig[0], sizeof(tmp)) == 0); + } + + /** Partial signature verification */ + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session)); + + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); + + /** Signature aggregation and verification */ + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0)); + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 1) == 1); + CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); +} + +static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { + secp256k1_scalar k1[2], k2[2]; + + secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); + testrand_flip(args[n_flip], n_bytes); + secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); + CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); + CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); +} + +static void musig_nonce_test(void) { + unsigned char *args[6]; + unsigned char session_secrand[32]; + unsigned char sk[32]; + unsigned char pk[33]; + unsigned char msg[32]; + unsigned char agg_pk[32]; + unsigned char extra_input[32]; + int i, j; + secp256k1_scalar k[6][2]; + + testrand_bytes_test(session_secrand, sizeof(session_secrand)); + testrand_bytes_test(sk, sizeof(sk)); + testrand_bytes_test(pk, sizeof(pk)); + testrand_bytes_test(msg, sizeof(msg)); + testrand_bytes_test(agg_pk, sizeof(agg_pk)); + testrand_bytes_test(extra_input, sizeof(extra_input)); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = session_secrand; + args[1] = msg; + args[2] = sk; + args[3] = pk; + args[4] = agg_pk; + args[5] = extra_input; + for (i = 0; i < COUNT; i++) { + musig_nonce_bitflip(args, 0, sizeof(session_secrand)); + musig_nonce_bitflip(args, 1, sizeof(msg)); + musig_nonce_bitflip(args, 2, sizeof(sk)); + musig_nonce_bitflip(args, 3, sizeof(pk)); + musig_nonce_bitflip(args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(args, 5, sizeof(extra_input)); + } + /* Check that if any argument is NULL, a different nonce is produced than if + * any other argument is NULL. */ + memcpy(msg, session_secrand, sizeof(msg)); + memcpy(sk, session_secrand, sizeof(sk)); + memcpy(pk, session_secrand, sizeof(session_secrand)); + memcpy(agg_pk, session_secrand, sizeof(agg_pk)); + memcpy(extra_input, session_secrand, sizeof(extra_input)); + secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + for (i = 0; i < 6; i++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); + for (j = i+1; j < 6; j++) { + CHECK(!secp256k1_scalar_eq(&k[i][0], &k[j][0])); + CHECK(!secp256k1_scalar_eq(&k[i][1], &k[j][1])); + } + } +} + +static void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) { + secp256k1_sha256 sha; + secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + test_sha256_eq(&sha, sha_tagged); +} + +/* Checks that the initialized tagged hashes have the expected + * state. */ +static void sha256_tag_test(void) { + secp256k1_sha256 sha; + { + char tag[] = "KeyAgg list"; + secp256k1_musig_keyagglist_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + char tag[] = "KeyAgg coefficient"; + secp256k1_musig_keyaggcoef_sha256(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/aux"; + secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/nonce"; + secp256k1_nonce_function_musig_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } + { + unsigned char tag[] = "MuSig/noncecoef"; + secp256k1_musig_compute_noncehash_sha256_tagged(&sha); + sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1); + } +} + +/* Attempts to create a signature for the aggregate public key using given secret + * keys and keyagg_cache. */ +static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) { + secp256k1_pubkey pk[2]; + unsigned char session_secrand[2][32]; + unsigned char msg[32]; + secp256k1_musig_secnonce secnonce[2]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + secp256k1_keypair keypair[2]; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[2]; + const secp256k1_musig_partial_sig *partial_sig_ptr[2]; + unsigned char final_sig[64]; + int i; + + for (i = 0; i < 2; i++) { + pubnonce_ptr[i] = &pubnonce[i]; + partial_sig_ptr[i] = &partial_sig[i]; + + testrand256(session_secrand[i]); + } + CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); + CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); + testrand256(msg); + + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk0, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk1, &pk[1], NULL, NULL, NULL) == 1); + + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, keyagg_cache) == 1); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], keyagg_cache, &session) == 1); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], keyagg_cache, &session) == 1); + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, 2) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), agg_pk) == 1); +} + +/* Create aggregate public key P[0], tweak multiple times (using xonly and + * plain tweaking) and test signing. */ +static void musig_tweak_test(void) { + unsigned char sk[2][32]; + secp256k1_pubkey pk[2]; + const secp256k1_pubkey *pk_ptr[2]; + secp256k1_musig_keyagg_cache keyagg_cache; + enum { N_TWEAKS = 8 }; + secp256k1_pubkey P[N_TWEAKS + 1]; + secp256k1_xonly_pubkey P_xonly[N_TWEAKS + 1]; + int i; + + /* Key Setup */ + for (i = 0; i < 2; i++) { + pk_ptr[i] = &pk[i]; + testrand256(sk[i]); + CHECK(create_keypair_and_pk(NULL, &pk[i], sk[i]) == 1); + } + /* Compute P0 = keyagg(pk0, pk1) and test signing for it */ + CHECK(secp256k1_musig_pubkey_agg(CTX, &P_xonly[0], &keyagg_cache, pk_ptr, 2) == 1); + musig_tweak_test_helper(&P_xonly[0], sk[0], sk[1], &keyagg_cache); + CHECK(secp256k1_musig_pubkey_get(CTX, &P[0], &keyagg_cache)); + + /* Compute Pi = f(Pj) + tweaki*G where where j = i-1 and try signing for + * that key. If xonly is set to true, the function f normalizes the input + * point to have an even X-coordinate ("xonly-tweaking"). + * Otherwise, the function f is the identity function. */ + for (i = 1; i <= N_TWEAKS; i++) { + unsigned char tweak[32]; + int P_parity; + int xonly = testrand_bits(1); + + testrand256(tweak); + if (xonly) { + CHECK(secp256k1_musig_pubkey_xonly_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } else { + CHECK(secp256k1_musig_pubkey_ec_tweak_add(CTX, &P[i], &keyagg_cache, tweak) == 1); + } + CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &P_xonly[i], &P_parity, &P[i])); + /* Check that musig_pubkey_tweak_add produces same result as + * xonly_pubkey_tweak_add or ec_pubkey_tweak_add. */ + if (xonly) { + unsigned char P_serialized[32]; + CHECK(secp256k1_xonly_pubkey_serialize(CTX, P_serialized, &P_xonly[i])); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, P_serialized, P_parity, &P_xonly[i-1], tweak) == 1); + } else { + secp256k1_pubkey tmp_key = P[i-1]; + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &tmp_key, tweak)); + CHECK(secp256k1_memcmp_var(&tmp_key, &P[i], sizeof(tmp_key)) == 0); + } + /* Test signing for P[i] */ + musig_tweak_test_helper(&P_xonly[i], sk[0], sk[1], &keyagg_cache); + } +} + +int musig_vectors_keyagg_and_tweak(enum MUSIG_ERROR *error, + secp256k1_musig_keyagg_cache *keyagg_cache, + unsigned char *agg_pk_ser, + const unsigned char pubkeys33[][33], + const unsigned char tweaks32[][32], + size_t key_indices_len, + const size_t *key_indices, + size_t tweak_indices_len, + const size_t *tweak_indices, + const int *is_xonly) { + secp256k1_pubkey pubkeys[MUSIG_VECTORS_MAX_PUBKEYS]; + const secp256k1_pubkey *pk_ptr[MUSIG_VECTORS_MAX_PUBKEYS]; + int i; + secp256k1_pubkey agg_pk; + secp256k1_xonly_pubkey agg_pk_xonly; + + for (i = 0; i < (int)key_indices_len; i++) { + if (!secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pubkeys33[key_indices[i]], 33)) { + *error = MUSIG_PUBKEY; + return 0; + } + pk_ptr[i] = &pubkeys[i]; + } + if (!secp256k1_musig_pubkey_agg(CTX, NULL, keyagg_cache, pk_ptr, key_indices_len)) { + *error = MUSIG_OTHER; + return 0; + } + + for (i = 0; i < (int)tweak_indices_len; i++) { + if (is_xonly[i]) { + if (!secp256k1_musig_pubkey_xonly_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } else { + if (!secp256k1_musig_pubkey_ec_tweak_add(CTX, NULL, keyagg_cache, tweaks32[tweak_indices[i]])) { + *error = MUSIG_TWEAK; + return 0; + } + } + } + if (!secp256k1_musig_pubkey_get(CTX, &agg_pk, keyagg_cache)) { + *error = MUSIG_OTHER; + return 0; + } + + if (!secp256k1_xonly_pubkey_from_pubkey(CTX, &agg_pk_xonly, NULL, &agg_pk)) { + *error = MUSIG_OTHER; + return 0; + } + + if (agg_pk_ser != NULL) { + if (!secp256k1_xonly_pubkey_serialize(CTX, agg_pk_ser, &agg_pk_xonly)) { + *error = MUSIG_OTHER; + return 0; + } + } + + return 1; +} + +static void musig_test_vectors_keyagg(void) { + size_t i; + const struct musig_key_agg_vector *vector = &musig_key_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk[32]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0); + } + + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_key_agg_error_test_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(c->error == error); + } +} + +static void musig_test_vectors_noncegen(void) { + size_t i; + const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector; + + for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) { + const struct musig_nonce_gen_test_case *c = &vector->test_case[i]; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL; + unsigned char session_secrand32[32]; + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + const unsigned char *sk = NULL; + const unsigned char *msg = NULL; + const unsigned char *extra_in = NULL; + secp256k1_pubkey pk; + unsigned char pubnonce66[66]; + + memcpy(session_secrand32, c->rand_, 32); + if (c->has_sk) { + sk = c->sk; + } + if (c->has_aggpk) { + /* Create keyagg_cache from aggpk */ + secp256k1_keyagg_cache_internal cache_i; + secp256k1_xonly_pubkey aggpk; + memset(&cache_i, 0, sizeof(cache_i)); + CHECK(secp256k1_xonly_pubkey_parse(CTX, &aggpk, c->aggpk)); + CHECK(secp256k1_xonly_pubkey_load(CTX, &cache_i.pk, &aggpk)); + secp256k1_keyagg_cache_save(&keyagg_cache, &cache_i); + keyagg_cache_ptr = &keyagg_cache; + } + if (c->has_msg) { + msg = c->msg; + } + if (c->has_extra_in) { + extra_in = c->extra_in; + } + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk, c->pk, sizeof(c->pk))); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce, &pubnonce, session_secrand32, sk, &pk, msg, keyagg_cache_ptr, extra_in) == 1); + CHECK(secp256k1_memcmp_var(&secnonce.data[4], c->expected_secnonce, 2*32) == 0); + /* The last element of the secnonce is the public key (uncompressed in + * secp256k1_musig_secnonce, compressed in the test vector secnonce). */ + CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&c->expected_secnonce[2*32], c->pk, sizeof(c->pk)) == 0); + + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(sizeof(c->expected_pubnonce) == sizeof(pubnonce66)); + CHECK(secp256k1_memcmp_var(pubnonce66, c->expected_pubnonce, sizeof(pubnonce66)) == 0); + } +} + + +static void musig_test_vectors_nonceagg(void) { + size_t i; + int j; + const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->valid_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + const secp256k1_musig_pubnonce *pubnonce_ptr[2]; + secp256k1_musig_aggnonce aggnonce; + unsigned char aggnonce66[66]; + + for (j = 0; j < 2; j++) { + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]]) == 1); + pubnonce_ptr[j] = &pubnonce[j]; + } + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); + CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce)); + CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; + secp256k1_musig_pubnonce pubnonce[2]; + for (j = 0; j < 2; j++) { + int expected = c->invalid_nonce_idx != j; + CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pnonces[c->pnonce_indices[j]])); + } + } +} + +static void musig_test_set_secnonce(secp256k1_musig_secnonce *secnonce, const unsigned char *secnonce64, const secp256k1_pubkey *pubkey) { + secp256k1_ge pk; + secp256k1_scalar k[2]; + + secp256k1_scalar_set_b32(&k[0], &secnonce64[0], NULL); + secp256k1_scalar_set_b32(&k[1], &secnonce64[32], NULL); + CHECK(secp256k1_pubkey_load(CTX, &pk, pubkey)); + secp256k1_musig_secnonce_save(secnonce, k, &pk); +} + +static void musig_test_vectors_signverify(void) { + size_t i; + const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_valid_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_pubkey pubkey; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[0], &pubkey); + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[0])); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) { + const struct musig_sign_error_case *c = &vector->sign_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_pubkey pubkey; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_musig_secnonce secnonce; + secp256k1_keypair keypair; + int expected; + + if (i == 0) { + /* Skip this vector since the implementation does not error out when + * the signing key does not belong to any pubkey. */ + continue; + } + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + + expected = c->error != MUSIG_AGGNONCE; + CHECK(expected == secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonces[c->aggnonce_index])); + if (!expected) { + continue; + } + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); + expected = c->error != MUSIG_SECNONCE; + if (expected) { + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } else { + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } + } + for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + enum { NUM_PUBNONCES = 3 }; + secp256k1_musig_pubnonce pubnonce[NUM_PUBNONCES]; + const secp256k1_musig_pubnonce *pubnonce_ptr[NUM_PUBNONCES]; + secp256k1_pubkey pubkey; + int expected; + size_t j; + + CHECK(NUM_PUBNONCES <= c->nonce_indices_len); + for (j = 0; j < c->nonce_indices_len; j++) { + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[j], vector->pubnonces[c->nonce_indices[j]])); + pubnonce_ptr[j] = &pubnonce[j]; + } + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, c->nonce_indices_len) == 1); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msgs[c->msg_index], &keyagg_cache)); + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[c->signer_index], sizeof(vector->pubkeys[0]))); + + expected = c->error != MUSIG_SIG; + CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig, c->sig)); + if (!expected) { + continue; + } + expected = c->error != MUSIG_SIG_VERIFY; + CHECK(expected == secp256k1_musig_partial_sig_verify(CTX, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) { + const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + int expected; + + expected = c->error != MUSIG_PUBKEY; + CHECK(expected == musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, NULL, c->key_indices_len, c->key_indices, 0, NULL, NULL)); + CHECK(expected || c->error == error); + if (!expected) { + continue; + } + expected = c->error != MUSIG_PUBNONCE; + CHECK(expected == secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + } +} + +static void musig_test_vectors_tweak(void) { + size_t i; + const struct musig_tweak_vector *vector = &musig_tweak_vector; + secp256k1_pubkey pubkey; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_secnonce secnonce; + + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonce)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_tweak_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + secp256k1_musig_pubnonce pubnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig; + secp256k1_keypair keypair; + unsigned char partial_sig32[32]; + + musig_test_set_secnonce(&secnonce, vector->secnonce, &pubkey); + + CHECK(secp256k1_keypair_create(CTX, &keypair, vector->sk)); + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + CHECK(secp256k1_musig_partial_sig_serialize(CTX, partial_sig32, &partial_sig)); + CHECK(secp256k1_memcmp_var(partial_sig32, c->expected, sizeof(partial_sig32)) == 0); + + CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]])); + CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session)); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_tweak_case *c = &vector->error_case[i]; + enum MUSIG_ERROR error; + secp256k1_musig_keyagg_cache keyagg_cache; + CHECK(!musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, NULL, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(error == MUSIG_TWEAK); + } +} + +static void musig_test_vectors_sigagg(void) { + size_t i, j; + const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector; + + for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->valid_case[i]; + enum MUSIG_ERROR error; + unsigned char final_sig[64]; + secp256k1_musig_keyagg_cache keyagg_cache; + unsigned char agg_pk32[32]; + secp256k1_xonly_pubkey agg_pk; + secp256k1_musig_aggnonce aggnonce; + secp256k1_musig_session session; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + + CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly)); + CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, c->aggnonce)); + CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, vector->msg, &keyagg_cache)); + for (j = 0; j < c->psig_indices_len; j++) { + CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + partial_sig_ptr[j] = &partial_sig[j]; + } + + CHECK(secp256k1_musig_partial_sig_agg(CTX, final_sig, &session, partial_sig_ptr, c->psig_indices_len) == 1); + CHECK(secp256k1_memcmp_var(final_sig, c->expected, sizeof(final_sig)) == 0); + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &agg_pk, agg_pk32)); + CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1); + } + for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) { + const struct musig_sig_agg_case *c = &vector->error_case[i]; + secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))]; + for (j = 0; j < c->psig_indices_len; j++) { + int expected = c->invalid_sig_idx != (int)j; + CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]])); + } + } +} + +/* Since the BIP doesn't provide static test vectors for nonce_gen_counter, we + * define a static test here */ +static void musig_test_static_nonce_gen_counter(void) { + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + unsigned char pubnonce66[66]; + secp256k1_pubkey pk; + secp256k1_keypair keypair; + uint64_t nonrepeating_cnt = 0; + unsigned char sk[32] = { + 0xEE, 0xC1, 0xCB, 0x7D, 0x1B, 0x72, 0x54, 0xC5, + 0xCA, 0xB0, 0xD9, 0xC6, 0x1A, 0xB0, 0x2E, 0x64, + 0x3D, 0x46, 0x4A, 0x59, 0xFE, 0x6C, 0x96, 0xA7, + 0xEF, 0xE8, 0x71, 0xF0, 0x7C, 0x5A, 0xEF, 0x54, + }; + unsigned char expected_secnonce[64] = { + 0x84, 0x2F, 0x13, 0x80, 0xCD, 0x17, 0xA1, 0x98, + 0xFC, 0x3D, 0xAD, 0x3B, 0x7D, 0xA7, 0x49, 0x29, + 0x41, 0xF4, 0x69, 0x76, 0xF2, 0x70, 0x2F, 0xF7, + 0xC6, 0x6F, 0x24, 0xF4, 0x72, 0x03, 0x6A, 0xF1, + 0xDA, 0x3F, 0x95, 0x2D, 0xDE, 0x4A, 0x2D, 0xA6, + 0xB6, 0x32, 0x57, 0x07, 0xCE, 0x87, 0xA4, 0xE3, + 0x61, 0x6D, 0x06, 0xFC, 0x5F, 0x81, 0xA9, 0xC9, + 0x93, 0x86, 0xD2, 0x0A, 0x99, 0xCE, 0xCF, 0x99, + }; + unsigned char expected_pubnonce[66] = { + 0x03, 0xA5, 0xB9, 0xB6, 0x90, 0x79, 0x42, 0xEA, + 0xCD, 0xDA, 0x49, 0xA3, 0x66, 0x01, 0x6E, 0xC2, + 0xE6, 0x24, 0x04, 0xA1, 0xBF, 0x4A, 0xB6, 0xD4, + 0xDB, 0x82, 0x06, 0x7B, 0xC3, 0xAD, 0xF0, 0x86, + 0xD7, 0x03, 0x32, 0x05, 0xDB, 0x9E, 0xB3, 0x4D, + 0x5C, 0x7C, 0xE0, 0x28, 0x48, 0xCA, 0xC6, 0x8A, + 0x83, 0xED, 0x73, 0xE3, 0x88, 0x34, 0x77, 0xF5, + 0x63, 0xF2, 0x3C, 0xE9, 0xA1, 0x1A, 0x77, 0x21, + 0xEC, 0x64, + }; + + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair)); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, NULL, NULL, NULL) == 1); + + CHECK(secp256k1_memcmp_var(&secnonce.data[4], expected_secnonce, 2*32) == 0); + CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(secp256k1_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0); +} + +static void run_musig_tests(void) { + int i; + + for (i = 0; i < COUNT; i++) { + musig_simple_test(); + } + musig_api_tests(); + musig_nonce_test(); + for (i = 0; i < COUNT; i++) { + /* Run multiple times to ensure that pk and nonce have different y + * parities */ + musig_tweak_test(); + } + sha256_tag_test(); + musig_test_vectors_keyagg(); + musig_test_vectors_noncegen(); + musig_test_vectors_nonceagg(); + musig_test_vectors_signverify(); + musig_test_vectors_tweak(); + musig_test_vectors_sigagg(); + + musig_test_static_nonce_gen_counter(); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/musig/vectors.h b/crypto/secp256k1/libsecp256k1/src/modules/musig/vectors.h new file mode 100644 index 000000000..8407c2a69 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/musig/vectors.h @@ -0,0 +1,346 @@ +/** + * Automatically generated by ./tools/test_vectors_musig2_generate.py. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ + +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; + +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[4]; + unsigned char expected[32]; +}; + +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[4]; + size_t tweak_indices_len; + size_t tweak_indices[1]; + int is_xonly[1]; + enum MUSIG_ERROR error; +}; + +struct musig_key_agg_vector { + unsigned char pubkeys[7][33]; + unsigned char tweaks[2][32]; + struct musig_key_agg_valid_test_case valid_case[4]; + struct musig_key_agg_error_test_case error_case[5]; +}; + +static const struct musig_key_agg_vector musig_key_agg_vector = { + { + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, + { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 }, + { 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }, + { 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, + { 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B } + }, + { + { 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }}, + { 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }}, + { 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }}, + { 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }}, + }, + { + { 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY }, + { 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK }, + { 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK }, + }, +}; + +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected_secnonce[97]; + unsigned char expected_pubnonce[66]; +}; + +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[2]; +}; + +static const struct musig_nonce_gen_vector musig_nonce_gen_vector = { + { + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } }, + { { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } }, + }, +}; + +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; + +struct musig_nonce_agg_vector { + unsigned char pnonces[7][66]; + struct musig_nonce_agg_test_case valid_case[2]; + struct musig_nonce_agg_test_case error_case[3]; +}; + +static const struct musig_nonce_agg_vector musig_nonce_agg_vector = { + { + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 }, + { 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 }, + { { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 }, + }, + { + { { 0, 4 }, { 0 }, 1 }, + { { 5, 1 }, { 0 }, 0 }, + { { 6, 1 }, { 0 }, 0 }, + }, +}; + +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; + +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; + +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[4][33]; + unsigned char secnonces[2][194]; + unsigned char pubnonces[5][194]; + unsigned char aggnonces[5][66]; + unsigned char msgs[1][32]; + struct musig_valid_case valid_case[4]; + struct musig_sign_error_case sign_error_case[6]; + struct musig_verify_fail_error_case verify_fail_case[3]; + struct musig_verify_fail_error_case verify_error_case[2]; +}; + +static const struct musig_sign_verify_vector musig_sign_verify_vector = { + { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } + }, + { + { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }, + { 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 } + }, + { + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 } + }, + { + { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF } + }, + { + { 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }}, + { 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }}, + { 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }}, + { 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }}, + }, + { + { 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY }, + { 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE }, + { 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE }, + { 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE }, + }, + { + { { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY }, + { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG }, + }, + { + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE }, + { { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY }, + }, +}; + +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[3]; + size_t nonce_indices_len; + size_t nonce_indices[3]; + size_t tweak_indices_len; + size_t tweak_indices[4]; + int is_xonly[4]; + size_t signer_index; + unsigned char expected[32]; +}; + +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[3][33]; + unsigned char pubnonces[3][194]; + unsigned char tweaks[5][32]; + struct musig_tweak_case valid_case[5]; + struct musig_tweak_case error_case[1]; +}; + +static const struct musig_tweak_vector musig_tweak_vector = { + { 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 }, + { 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 }, + { 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }, + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 } + }, + { + { 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }, + { 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 }, + { 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 } + }, + { + { 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB }, + { 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 }, + { 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 }, + { 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }}, + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }}, + }, + { + { 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }}, + }, +}; + +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[2]; + size_t tweak_indices_len; + size_t tweak_indices[3]; + int is_xonly[3]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[2]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; + +struct musig_sig_agg_vector { + unsigned char pubkeys[4][33]; + unsigned char tweaks[3][32]; + unsigned char psigs[9][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[4]; + struct musig_sig_agg_case error_case[1]; +}; + +static const struct musig_sig_agg_vector musig_sig_agg_vector = { + { + { 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }, + { 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 }, + { 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C }, + { 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 } + }, + { + { 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C }, + { 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC }, + { 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 } + }, + { + { 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB }, + { 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 }, + { 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 }, + { 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 }, + { 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE }, + { 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 }, + { 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC }, + { 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 } + }, + { 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 }, + { + { 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 }, + { 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 }, + { 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 }, + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 }, + }, + { + { 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 }, + }, +}; +enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 }; diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include index bf23c26e7..156ea690f 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include @@ -1,8 +1,5 @@ include_HEADERS += include/secp256k1_recovery.h noinst_HEADERS += src/modules/recovery/main_impl.h noinst_HEADERS += src/modules/recovery/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_recover -bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) -endif +noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/recovery/bench_impl.h diff --git a/crypto/secp256k1/libsecp256k1/src/bench_recover.c b/crypto/secp256k1/libsecp256k1/src/modules/recovery/bench_impl.h similarity index 58% rename from crypto/secp256k1/libsecp256k1/src/bench_recover.c rename to crypto/secp256k1/libsecp256k1/src/modules/recovery/bench_impl.h index 6489378cc..57108d452 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_recover.c +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/bench_impl.h @@ -1,27 +1,27 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#include "include/secp256k1.h" -#include "include/secp256k1_recovery.h" -#include "util.h" -#include "bench.h" +#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H +#define SECP256K1_MODULE_RECOVERY_BENCH_H + +#include "../../../include/secp256k1_recovery.h" typedef struct { secp256k1_context *ctx; unsigned char msg[32]; unsigned char sig[64]; -} bench_recover_t; +} bench_recover_data; -void bench_recover(void* arg) { +static void bench_recover(void* arg, int iters) { int i; - bench_recover_t *data = (bench_recover_t*)arg; + bench_recover_data *data = (bench_recover_data*)arg; secp256k1_pubkey pubkey; unsigned char pubkeyc[33]; - for (i = 0; i < 20000; i++) { + for (i = 0; i < iters; i++) { int j; size_t pubkeylen = 33; secp256k1_ecdsa_recoverable_signature sig; @@ -36,9 +36,9 @@ void bench_recover(void* arg) { } } -void bench_recover_setup(void* arg) { +static void bench_recover_setup(void* arg) { int i; - bench_recover_t *data = (bench_recover_t*)arg; + bench_recover_data *data = (bench_recover_data*)arg; for (i = 0; i < 32; i++) { data->msg[i] = 1 + i; @@ -48,13 +48,15 @@ void bench_recover_setup(void* arg) { } } -int main(void) { - bench_recover_t data; +static void run_recovery_bench(int iters, int argc, char** argv) { + bench_recover_data data; + int d = argc == 1; - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); + if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters); secp256k1_context_destroy(data.ctx); - return 0; } + +#endif /* SECP256K1_MODULE_RECOVERY_BENCH_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h old mode 100755 new mode 100644 index c6fbe2398..76a005e01 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h @@ -1,13 +1,13 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_ -#define _SECP256K1_MODULE_RECOVERY_MAIN_ +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H -#include "include/secp256k1_recovery.h" +#include "../../../include/secp256k1_recovery.h" static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { (void)ctx; @@ -40,7 +40,7 @@ int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* int ret = 1; int overflow = 0; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input64 != NULL); ARG_CHECK(recid >= 0 && recid <= 3); @@ -60,7 +60,7 @@ int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(output64 != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(recid != NULL); @@ -75,7 +75,7 @@ int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_scalar r, s; int recid; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(sigin != NULL); @@ -84,7 +84,7 @@ int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, return 1; } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { +static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { unsigned char brx[32]; secp256k1_fe fx; secp256k1_ge x; @@ -98,7 +98,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons } secp256k1_scalar_get_b32(brx, sigr); - r = secp256k1_fe_set_b32(&fx, brx); + r = secp256k1_fe_set_b32_limit(&fx, brx); (void)r; VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ if (recid & 2) { @@ -115,73 +115,39 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons secp256k1_scalar_mul(&u1, &rn, message); secp256k1_scalar_negate(&u1, &u1); secp256k1_scalar_mul(&u2, &rn, sigs); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ecmult(&qj, &xj, &u2, &u1); secp256k1_ge_set_gej_var(pubkey, &qj); return !secp256k1_gej_is_infinity(&qj); } -int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { +int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { secp256k1_scalar r, s; - secp256k1_scalar sec, non, msg; - int recid; - int ret = 0; - int overflow = 0; + int ret, recid; VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); + ARG_CHECK(msghash32 != NULL); ARG_CHECK(signature != NULL); ARG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - unsigned char nonce32[32]; - unsigned int count = 0; - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { - break; - } - } - count++; - } - memset(nonce32, 0, 32); - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (ret) { - secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); - } else { - memset(signature, 0, sizeof(*signature)); - } + ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata); + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); return ret; } -int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) { secp256k1_ge q; secp256k1_scalar r, s; secp256k1_scalar m; int recid; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); + ARG_CHECK(msghash32 != NULL); ARG_CHECK(signature != NULL); ARG_CHECK(pubkey != NULL); secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ - secp256k1_scalar_set_b32(&m, msg32, NULL); - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_scalar_set_b32(&m, msghash32, NULL); + if (secp256k1_ecdsa_sig_recover(&r, &s, &q, &m, recid)) { secp256k1_pubkey_save(pubkey, &q); return 1; } else { @@ -190,4 +156,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk } } -#endif +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_exhaustive_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_exhaustive_impl.h new file mode 100644 index 000000000..6bbc02b9a --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_exhaustive_impl.h @@ -0,0 +1,148 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H +#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H + +#include "main_impl.h" +#include "../../../include/secp256k1_recovery.h" + +static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k; + uint64_t iter = 0; + + /* Loop */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + int overflow; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k, &overflow); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + /* The recid's second bit is for conveying overflow (R.x value >= group order). + * In the actual secp256k1 this is an astronomically unlikely event, but in the + * small group used here, it will almost certainly be the case for all points. + * Note that this isn't actually useful; full recovery would need to convey + * floor(R.x / group_order), but only one bit is used as that is sufficient + * in the real group. */ + expected_recid = overflow ? 2 : 0; + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) { + expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized); + } else { + expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized); + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k, NULL); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k, NULL); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) { + test_exhaustive_recovery_sign(ctx, group); + test_exhaustive_recovery_verify(ctx, group); +} + +#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h index 765c7dd81..7a28a3ce6 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ -#define _SECP256K1_MODULE_RECOVERY_TESTS_ +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { (void) msg32; @@ -25,22 +25,17 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c } /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ memset(nonce32, 1, 32); - return secp256k1_rand_bits(1); + return testrand_bits(1); } -void test_ecdsa_recovery_api(void) { +static void test_ecdsa_recovery_api(void) { /* Setup contexts that just count errors */ - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_pubkey pubkey; secp256k1_pubkey recpubkey; secp256k1_ecdsa_signature normal_sig; secp256k1_ecdsa_recoverable_signature recsig; unsigned char privkey[32] = { 1 }; unsigned char message[32] = { 2 }; - int32_t ecount = 0; int recid = 0; unsigned char sig[74]; unsigned char zero_privkey[32] = { 0 }; @@ -49,105 +44,55 @@ void test_ecdsa_recovery_api(void) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Check bad contexts and NULLs for signing */ - ecount = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); - CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL)); /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ - secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); - CHECK(ecount == 5); + secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL); /* These will all fail, but not in ARG_CHECK way */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0); /* This one will succeed. */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); /* Check signing with a goofy nonce function */ /* Check bad contexts and NULLs for recovery */ - ecount = 0; - CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); - CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL)); /* Check NULLs for conversion */ - CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL)); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1); /* Check NULLs for de/serialization */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL)); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); - CHECK(ecount == 7); - /* overflow in signature will fail but not affect ecount */ + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5)); + /* overflow in signature will not result in calling illegal_callback */ memcpy(sig, over_privkey, 32); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); - CHECK(ecount == 7); - - /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0); } -void test_ecdsa_recovery_end_to_end(void) { +static void test_ecdsa_recovery_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; @@ -161,52 +106,52 @@ void test_ecdsa_recovery_end_to_end(void) { /* Generate a random key and message. */ { secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_scalar_get_b32(message, &msg); } /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Serialize/parse compact and verify/recover. */ extra[0] = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(memcmp(&signature[4], &signature[0], 64) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); memset(&rsignature[4], 0, sizeof(rsignature[4])); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1); /* Parse compact (with recovery id) and recover. */ - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); - CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); /* Serialize/destroy/parse signature and verify again. */ - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1); + sig[testrand_bits(6)] += 1 + testrand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0); /* Recover again */ - CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || - memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 || + secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); } /* Tests several edge cases. */ -void test_ecdsa_recovery_edge_cases(void) { +static void test_ecdsa_recovery_edge_cases(void) { const unsigned char msg32[32] = { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', @@ -215,7 +160,7 @@ void test_ecdsa_recovery_edge_cases(void) { }; const unsigned char sig64[64] = { /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 0. */ + * and secret key 0 (which is not valid), resulting in recid 1. */ 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, @@ -242,14 +187,14 @@ void test_ecdsa_recovery_edge_cases(void) { secp256k1_ecdsa_signature sig; int recid; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32)); for (recid = 0; recid < 4; recid++) { int i; @@ -294,40 +239,40 @@ void test_ecdsa_recovery_edge_cases(void) { 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 }; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1); for (recid2 = 0; recid2 < 4; recid2++) { secp256k1_pubkey pubkey2b; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1); /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); } /* DER parsing tests. */ /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); /* Leading zeros. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); /* Damage signature. */ sigbder[7]++; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); sigbder[7]--; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0); for(i = 0; i < 8; i++) { int c; unsigned char orig = sigbder[i]; @@ -337,7 +282,7 @@ void test_ecdsa_recovery_edge_cases(void) { continue; } sigbder[i] = c; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0); } sigbder[i] = orig; } @@ -358,36 +303,36 @@ void test_ecdsa_recovery_edge_cases(void) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }; secp256k1_pubkey pubkeyc; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1); sigcder[4] = 0; sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); sigcder[4] = 1; sigcder[7] = 0; sigc64[31] = 1; sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0); } } -void run_recovery_tests(void) { +static void run_recovery_tests(void) { int i; - for (i = 0; i < count; i++) { + for (i = 0; i < COUNT; i++) { test_ecdsa_recovery_api(); } - for (i = 0; i < 64*count; i++) { + for (i = 0; i < 64*COUNT; i++) { test_ecdsa_recovery_end_to_end(); } test_ecdsa_recovery_edge_cases(); } -#endif +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/Makefile.am.include new file mode 100644 index 000000000..654fa2e5a --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/Makefile.am.include @@ -0,0 +1,5 @@ +include_HEADERS += include/secp256k1_schnorrsig.h +noinst_HEADERS += src/modules/schnorrsig/main_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h +noinst_HEADERS += src/modules/schnorrsig/bench_impl.h diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/bench_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/bench_impl.h new file mode 100644 index 000000000..93a878ede --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/bench_impl.h @@ -0,0 +1,104 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_BENCH_H +#define SECP256K1_MODULE_SCHNORRSIG_BENCH_H + +#include "../../../include/secp256k1_schnorrsig.h" + +#define MSGLEN 32 + +typedef struct { + secp256k1_context *ctx; + int n; + + const secp256k1_keypair **keypairs; + const unsigned char **pk; + const unsigned char **sigs; + const unsigned char **msgs; +} bench_schnorrsig_data; + +static void bench_schnorrsig_sign(void* arg, int iters) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + int i; + unsigned char msg[MSGLEN] = {0}; + unsigned char sig[64]; + + for (i = 0; i < iters; i++) { + msg[0] = i; + msg[1] = i >> 8; + CHECK(secp256k1_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL)); + } +} + +static void bench_schnorrsig_verify(void* arg, int iters) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + int i; + + for (i = 0; i < iters; i++) { + secp256k1_xonly_pubkey pk; + CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1); + CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk)); + } +} + +static void run_schnorrsig_bench(int iters, int argc, char** argv) { + int i; + bench_schnorrsig_data data; + int d = argc == 1; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *)); + data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + + CHECK(MSGLEN >= 4); + for (i = 0; i < iters; i++) { + unsigned char sk[32]; + unsigned char *msg = (unsigned char *)malloc(MSGLEN); + unsigned char *sig = (unsigned char *)malloc(64); + secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair)); + unsigned char *pk_char = (unsigned char *)malloc(32); + secp256k1_xonly_pubkey pk; + msg[0] = sk[0] = i; + msg[1] = sk[1] = i >> 8; + msg[2] = sk[2] = i >> 16; + msg[3] = sk[3] = i >> 24; + memset(&msg[4], 'm', MSGLEN - 4); + memset(&sk[4], 's', 28); + + data.keypairs[i] = keypair; + data.pk[i] = pk_char; + data.msgs[i] = msg; + data.sigs[i] = sig; + + CHECK(secp256k1_keypair_create(data.ctx, keypair, sk)); + CHECK(secp256k1_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL)); + CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair)); + CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1); + } + + if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters); + if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "schnorrsig_verify")) run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters); + + for (i = 0; i < iters; i++) { + free((void *)data.keypairs[i]); + free((void *)data.pk[i]); + free((void *)data.msgs[i]); + free((void *)data.sigs[i]); + } + + /* Casting to (void *) avoids a stupid warning in MSVC. */ + free((void *)data.keypairs); + free((void *)data.pk); + free((void *)data.msgs); + free((void *)data.sigs); + + secp256k1_context_destroy(data.ctx); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/main_impl.h new file mode 100644 index 000000000..2ed7be677 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,271 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H +#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_schnorrsig.h" +#include "../../hash.h" + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ +static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x46615b35ul; + sha->s[1] = 0xf4bfbff7ul; + sha->s[2] = 0x9f8dc671ul; + sha->s[3] = 0x83627ab3ul; + sha->s[4] = 0x60217180ul; + sha->s[5] = 0x57358661ul; + sha->s[6] = 0x21a29e54ul; + sha->s[7] = 0x68b07b4cul; + + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ +static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x24dd3219ul; + sha->s[1] = 0x4eba7e70ul; + sha->s[2] = 0xca0fabb9ul; + sha->s[3] = 0x0fa3166dul; + sha->s[4] = 0x3afbe4b1ul; + sha->s[5] = 0x4c44df97ul; + sha->s[6] = 0x4aac2739ul; + sha->s[7] = 0x249e850aul; + + sha->bytes = 64; +} + +/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 + * by using the correct tagged hash function. */ +static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + +static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; + +static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + secp256k1_sha256 sha; + unsigned char masked_key[32]; + int i; + + if (algo == NULL) { + return 0; + } + + if (data != NULL) { + secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha); + secp256k1_sha256_write(&sha, data, 32); + secp256k1_sha256_finalize(&sha, masked_key); + for (i = 0; i < 32; i++) { + masked_key[i] ^= key32[i]; + } + } else { + /* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */ + static const unsigned char ZERO_MASK[32] = { + 84, 241, 105, 207, 201, 226, 229, 114, + 116, 128, 68, 31, 144, 186, 37, 196, + 136, 244, 97, 199, 11, 94, 165, 220, + 170, 247, 175, 105, 39, 10, 165, 20 + }; + for (i = 0; i < 32; i++) { + masked_key[i] = key32[i] ^ ZERO_MASK[i]; + } + } + + /* Tag the hash with algo which is important to avoid nonce reuse across + * algorithms. If this nonce function is used in BIP-340 signing as defined + * in the spec, an optimized tagging implementation is used. */ + if (algolen == sizeof(bip340_algo) + && secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) { + secp256k1_nonce_function_bip340_sha256_tagged(&sha); + } else { + secp256k1_sha256_initialize_tagged(&sha, algo, algolen); + } + + /* Hash masked-key||pk||msg using the tagged hash as per the spec */ + secp256k1_sha256_write(&sha, masked_key, 32); + secp256k1_sha256_write(&sha, xonly_pk32, 32); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, nonce32); + secp256k1_sha256_clear(&sha); + secp256k1_memclear(masked_key, sizeof(masked_key)); + + return 1; +} + +const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340; + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ +static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x9cecba11ul; + sha->s[1] = 0x23925381ul; + sha->s[2] = 0x11679112ul; + sha->s[3] = 0xd1627e0ful; + sha->s[4] = 0x97c87550ul; + sha->s[5] = 0x003cc765ul; + sha->s[6] = 0x90f61164ul; + sha->s[7] = 0x33e9b66aul; + sha->bytes = 64; +} + +static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) +{ + unsigned char buf[32]; + secp256k1_sha256 sha; + + /* tagged hash(r.x, pk.x, msg) */ + secp256k1_schnorrsig_sha256_tagged(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, pubkey32, 32); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, buf); + /* Set scalar e to the challenge hash modulo the curve order as per + * BIP340. */ + secp256k1_scalar_set_b32(e, buf, NULL); +} + +static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) { + secp256k1_scalar sk; + secp256k1_scalar e; + secp256k1_scalar k; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_ge r; + unsigned char buf[32] = { 0 }; + unsigned char pk_buf[32]; + unsigned char seckey[32]; + int ret = 1; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(keypair != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_bip340; + } + + ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair); + /* Because we are signing for a x-only pubkey, the secret key is negated + * before signing if the point corresponding to the secret key does not + * have an even Y. */ + if (secp256k1_fe_is_odd(&pk.y)) { + secp256k1_scalar_negate(&sk, &sk); + } + + secp256k1_scalar_get_b32(seckey, &sk); + secp256k1_fe_get_b32(pk_buf, &pk.x); + ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + secp256k1_scalar_set_b32(&k, buf, NULL); + ret &= !secp256k1_scalar_is_zero(&k); + secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + secp256k1_ge_set_gej(&r, &rj); + + /* We declassify r to allow using it as a branch point. This is fine + * because r is not a secret. */ + secp256k1_declassify(ctx, &r, sizeof(r)); + secp256k1_fe_normalize_var(&r.y); + if (secp256k1_fe_is_odd(&r.y)) { + secp256k1_scalar_negate(&k, &k); + } + secp256k1_fe_normalize_var(&r.x); + secp256k1_fe_get_b32(&sig64[0], &r.x); + + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); + secp256k1_scalar_mul(&e, &e, &sk); + secp256k1_scalar_add(&e, &e, &k); + secp256k1_scalar_get_b32(&sig64[32], &e); + + secp256k1_memczero(sig64, 64, !ret); + secp256k1_scalar_clear(&k); + secp256k1_scalar_clear(&sk); + secp256k1_memclear(seckey, sizeof(seckey)); + secp256k1_gej_clear(&rj); + + return ret; +} + +int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { + /* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */ + return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32); +} + +int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) { + return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32); +} + +int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) { + secp256k1_nonce_function_hardened noncefp = NULL; + void *ndata = NULL; + VERIFY_CHECK(ctx != NULL); + + if (extraparams != NULL) { + ARG_CHECK(secp256k1_memcmp_var(extraparams->magic, + schnorrsig_extraparams_magic, + sizeof(extraparams->magic)) == 0); + noncefp = extraparams->noncefp; + ndata = extraparams->ndata; + } + return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata); +} + +int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) { + secp256k1_scalar s; + secp256k1_scalar e; + secp256k1_gej rj; + secp256k1_ge pk; + secp256k1_gej pkj; + secp256k1_fe rx; + secp256k1_ge r; + unsigned char buf[32]; + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(msg != NULL || msglen == 0); + ARG_CHECK(pubkey != NULL); + + if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) { + return 0; + } + + secp256k1_scalar_set_b32(&s, &sig64[32], &overflow); + if (overflow) { + return 0; + } + + if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) { + return 0; + } + + /* Compute e. */ + secp256k1_fe_get_b32(buf, &pk.x); + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); + + /* Compute rj = s*G + (-e)*pkj */ + secp256k1_scalar_negate(&e, &e); + secp256k1_gej_set_ge(&pkj, &pk); + secp256k1_ecmult(&rj, &pkj, &e, &s); + + secp256k1_ge_set_gej_var(&r, &rj); + if (secp256k1_ge_is_infinity(&r)) { + return 0; + } + + secp256k1_fe_normalize_var(&r.y); + return !secp256k1_fe_is_odd(&r.y) && + secp256k1_fe_equal(&rx, &r.x); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h new file mode 100644 index 000000000..601b54975 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -0,0 +1,214 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_schnorrsig.h" +#include "main_impl.h" + +static const unsigned char invalid_pubkey_bytes[][32] = { + /* 0 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* 2 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 + }, + /* order */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF + }, + /* order + 1 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF + }, + /* field size */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F + }, + /* field size + 1 (note that 1 is legal) */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }, + /* 2^256 - 1 */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } +}; + +#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0])) + +static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg, + size_t msglen, + const unsigned char *key32, const unsigned char *xonly_pk32, + const unsigned char *algo, size_t algolen, + void* data) { + secp256k1_scalar s; + int *idata = data; + (void)msg; + (void)msglen; + (void)key32; + (void)xonly_pk32; + (void)algo; + (void)algolen; + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { + int d; + uint64_t iter = 0; + /* Iterate over the possible public keys to verify against (through their corresponding DL d). */ + for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) { + int actual_d; + unsigned k; + unsigned char pk32[32]; + memcpy(pk32, xonly_pubkey_bytes[d - 1], 32); + actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d; + /* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k. + Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */ + for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) { + unsigned char sig64[64]; + int actual_k = -1; + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + if (skip_section(&iter)) continue; + if (k <= EXHAUSTIVE_TEST_ORDER / 2) { + memcpy(sig64, xonly_pubkey_bytes[k - 1], 32); + actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k; + } else { + memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32); + } + /* Randomly generate messages until all challenges have been hit. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + unsigned char msg32[32]; + testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + /* Iterate over the possible valid last 32 bytes in the signature. + 0..order=that s value; order+1=random bytes */ + int count_valid = 0; + unsigned int s; + for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { + int expect_valid, valid; + if (s <= EXHAUSTIVE_TEST_ORDER) { + memset(sig64 + 32, 0, 32); + secp256k1_write_be32(sig64 + 60, s); + expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && + (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + } else { + testrand256(sig64 + 32); + expect_valid = 0; + } + valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]); + CHECK(valid == expect_valid); + count_valid += valid; + } + /* Exactly one s value must verify, unless R is illegal. */ + CHECK(count_valid == (actual_k != -1)); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) { + int d, k; + uint64_t iter = 0; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + + /* Loop over keys. */ + for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) { + int actual_d = d; + if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d; + /* Loop over nonces. */ + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) { + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + unsigned char msg32[32]; + unsigned char sig64[64]; + int actual_k = k; + if (skip_section(&iter)) continue; + extraparams.noncefp = secp256k1_hardened_nonce_function_smallint; + extraparams.ndata = &k; + if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k; + /* Generate random messages until all challenges have been tried. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; + unsigned char expected_s_bytes[32]; + secp256k1_scalar_get_b32(expected_s_bytes, &expected_s); + /* Invoke the real function to construct a signature. */ + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams)); + /* The first 32 bytes must match the xonly pubkey for the specified k. */ + CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); + /* The last 32 bytes must match the expected s value. */ + CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parity[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + unsigned i; + + /* Verify that all invalid_pubkey_bytes are actually invalid. */ + for (i = 0; i < NUM_INVALID_KEYS; ++i) { + secp256k1_xonly_pubkey pk; + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); + } + + /* Construct keypairs and xonly-pubkeys for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) { + secp256k1_scalar scalar_i; + unsigned char buf[32]; + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + } + + test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity); + test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_impl.h new file mode 100644 index 000000000..2d716a01f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/schnorrsig/tests_impl.h @@ -0,0 +1,982 @@ +/*********************************************************************** + * Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_H +#define SECP256K1_MODULE_SCHNORRSIG_TESTS_H + +#include "../../../include/secp256k1_schnorrsig.h" + +/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many + * bytes) changes the hash function + */ +static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { + unsigned char nonces[2][32]; + CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); + testrand_flip(args[n_flip], n_bytes); + CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); + CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); +} + +static void run_nonce_function_bip340_tests(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'}; + unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'}; + size_t algolen = sizeof(algo); + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + unsigned char nonce[32], nonce_z[32]; + unsigned char msg[32]; + size_t msglen = sizeof(msg); + unsigned char key[32]; + unsigned char pk[32]; + unsigned char aux_rand[32]; + unsigned char *args[5]; + int i; + + /* Check that hash initialized by + * secp256k1_nonce_function_bip340_sha256_tagged has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag)); + secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + /* Check that hash initialized by + * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected + * state. */ + secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag)); + secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); + + testrand256(msg); + testrand256(key); + testrand256(pk); + testrand256(aux_rand); + + /* Check that a bitflip in an argument results in different nonces. */ + args[0] = msg; + args[1] = key; + args[2] = pk; + args[3] = algo; + args[4] = aux_rand; + for (i = 0; i < COUNT; i++) { + nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen); + nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen); + nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen); + /* Flip algo special case "BIP0340/nonce" */ + nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); + /* Flip algo again */ + nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen); + nonce_function_bip340_bitflip(args, 4, 32, msglen, algolen); + } + + /* NULL algo is disallowed */ + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + /* Other algo is fine */ + testrand_bytes_test(algo, algolen); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + + for (i = 0; i < COUNT; i++) { + unsigned char nonce2[32]; + uint32_t offset = testrand_int(msglen - 1); + size_t msglen_tmp = (msglen + offset) % msglen; + size_t algolen_tmp; + + /* Different msglen gives different nonce */ + CHECK(nonce_function_bip340(nonce2, msg, msglen_tmp, key, pk, algo, algolen, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + + /* Different algolen gives different nonce */ + offset = testrand_int(algolen - 1); + algolen_tmp = (algolen + offset) % algolen; + CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + } + + /* NULL aux_rand argument is allowed, and identical to passing all zero aux_rand. */ + memset(aux_rand, 0, 32); + CHECK(nonce_function_bip340(nonce_z, msg, msglen, key, pk, algo, algolen, &aux_rand) == 1); + CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); + CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0); +} + +static void test_schnorrsig_api(void) { + unsigned char sk1[32]; + unsigned char sk2[32]; + unsigned char sk3[32]; + unsigned char msg[32]; + secp256k1_keypair keypairs[3]; + secp256k1_keypair invalid_keypair = {{ 0 }}; + secp256k1_xonly_pubkey pk[3]; + secp256k1_xonly_pubkey zero_pk; + unsigned char sig[64]; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; + + testrand256(sk1); + testrand256(sk2); + testrand256(sk3); + testrand256(msg); + CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1); + CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1); + memset(&zero_pk, 0, sizeof(zero_pk)); + + /** main test body **/ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL)); + + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams)); + + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0])); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0])); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk)); +} + +/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the + * expected state. */ +static void test_schnorrsig_sha256_tagged(void) { + unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_schnorrsig_sha256_tagged(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); +} + +/* Helper function for schnorrsig_bip_vectors + * Signs the message and checks that it's the same as expected_sig. */ +static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) { + unsigned char sig[64]; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey pk, pk_expected; + + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + extraparams.ndata = (unsigned char*)aux_rand; + + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams)); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + if (msglen == 32) { + memset(sig, 0, 64); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand)); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + } + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); +} + +/* Helper function for schnorrsig_bip_vectors + * Checks that both verify and verify_batch (TODO) return the same value as expected. */ +static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) { + secp256k1_xonly_pubkey pk; + + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized)); + CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); +} + +/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See + * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ +static void test_schnorrsig_bip_vectors(void) { + { + /* Test vector 0 */ + const unsigned char sk[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + }; + const unsigned char pk[32] = { + 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, + 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, + 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, + 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char msg[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig[64] = { + 0xE9, 0x07, 0x83, 0x1F, 0x80, 0x84, 0x8D, 0x10, + 0x69, 0xA5, 0x37, 0x1B, 0x40, 0x24, 0x10, 0x36, + 0x4B, 0xDF, 0x1C, 0x5F, 0x83, 0x07, 0xB0, 0x08, + 0x4C, 0x55, 0xF1, 0xCE, 0x2D, 0xCA, 0x82, 0x15, + 0x25, 0xF6, 0x6A, 0x4A, 0x85, 0xEA, 0x8B, 0x71, + 0xE4, 0x82, 0xA7, 0x4F, 0x38, 0x2D, 0x2C, 0xE5, + 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47, + 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 1 */ + const unsigned char sk[32] = { + 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, + 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, + 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, + 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF + }; + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x68, 0x96, 0xBD, 0x60, 0xEE, 0xAE, 0x29, 0x6D, + 0xB4, 0x8A, 0x22, 0x9F, 0xF7, 0x1D, 0xFE, 0x07, + 0x1B, 0xDE, 0x41, 0x3E, 0x6D, 0x43, 0xF9, 0x17, + 0xDC, 0x8D, 0xCF, 0x8C, 0x78, 0xDE, 0x33, 0x41, + 0x89, 0x06, 0xD1, 0x1A, 0xC9, 0x76, 0xAB, 0xCC, + 0xB2, 0x0B, 0x09, 0x12, 0x92, 0xBF, 0xF4, 0xEA, + 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C, + 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 2 */ + const unsigned char sk[32] = { + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9 + }; + const unsigned char pk[32] = { + 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, + 0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, + 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, + 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 + }; + const unsigned char aux_rand[32] = { + 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE, + 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC, + 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C, + 0x4B, 0x0B, 0x62, 0xD7, 0x98, 0xE6, 0xD9, 0x06 + }; + const unsigned char msg[32] = { + 0x7E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig[64] = { + 0x58, 0x31, 0xAA, 0xEE, 0xD7, 0xB4, 0x4B, 0xB7, + 0x4E, 0x5E, 0xAB, 0x94, 0xBA, 0x9D, 0x42, 0x94, + 0xC4, 0x9B, 0xCF, 0x2A, 0x60, 0x72, 0x8D, 0x8B, + 0x4C, 0x20, 0x0F, 0x50, 0xDD, 0x31, 0x3C, 0x1B, + 0xAB, 0x74, 0x58, 0x79, 0xA5, 0xAD, 0x95, 0x4A, + 0x72, 0xC4, 0x5A, 0x91, 0xC3, 0xA5, 0x1D, 0x3C, + 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E, + 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 3 */ + const unsigned char sk[32] = { + 0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81, + 0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0, + 0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54, + 0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10 + }; + const unsigned char pk[32] = { + 0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25, + 0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD, + 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, + 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 + }; + const unsigned char aux_rand[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char msg[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char sig[64] = { + 0x7E, 0xB0, 0x50, 0x97, 0x57, 0xE2, 0x46, 0xF1, + 0x94, 0x49, 0x88, 0x56, 0x51, 0x61, 0x1C, 0xB9, + 0x65, 0xEC, 0xC1, 0xA1, 0x87, 0xDD, 0x51, 0xB6, + 0x4F, 0xDA, 0x1E, 0xDC, 0x96, 0x37, 0xD5, 0xEC, + 0x97, 0x58, 0x2B, 0x9C, 0xB1, 0x3D, 0xB3, 0x93, + 0x37, 0x05, 0xB3, 0x2B, 0xA9, 0x82, 0xAF, 0x5A, + 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27, + 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3 + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 4 */ + const unsigned char pk[32] = { + 0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12, + 0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83, + 0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA, + 0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9 + }; + const unsigned char msg[32] = { + 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, + 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, + 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, + 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, + 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, + 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, + 0x76, 0xAF, 0xB1, 0x54, 0x8A, 0xF6, 0x03, 0xB3, + 0xEB, 0x45, 0xC9, 0xF8, 0x20, 0x7D, 0xEE, 0x10, + 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93, + 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 5 */ + const unsigned char pk[32] = { + 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50, + 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21, + 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, + 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34 + }; + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); + } + { + /* Test vector 6 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0xFF, 0xF9, 0x7B, 0xD5, 0x75, 0x5E, 0xEE, 0xA4, + 0x20, 0x45, 0x3A, 0x14, 0x35, 0x52, 0x35, 0xD3, + 0x82, 0xF6, 0x47, 0x2F, 0x85, 0x68, 0xA1, 0x8B, + 0x2F, 0x05, 0x7A, 0x14, 0x60, 0x29, 0x75, 0x56, + 0x3C, 0xC2, 0x79, 0x44, 0x64, 0x0A, 0xC6, 0x07, + 0xCD, 0x10, 0x7A, 0xE1, 0x09, 0x23, 0xD9, 0xEF, + 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E, + 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 7 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x1F, 0xA6, 0x2E, 0x33, 0x1E, 0xDB, 0xC2, 0x1C, + 0x39, 0x47, 0x92, 0xD2, 0xAB, 0x11, 0x00, 0xA7, + 0xB4, 0x32, 0xB0, 0x13, 0xDF, 0x3F, 0x6F, 0xF4, + 0xF9, 0x9F, 0xCB, 0x33, 0xE0, 0xE1, 0x51, 0x5F, + 0x28, 0x89, 0x0B, 0x3E, 0xDB, 0x6E, 0x71, 0x89, + 0xB6, 0x30, 0x44, 0x8B, 0x51, 0x5C, 0xE4, 0xF8, + 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35, + 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 8 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, + 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, + 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, + 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, + 0x96, 0x17, 0x64, 0xB3, 0xAA, 0x9B, 0x2F, 0xFC, + 0xB6, 0xEF, 0x94, 0x7B, 0x68, 0x87, 0xA2, 0x26, + 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C, + 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 9 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x3D, 0xDA, 0x83, 0x28, 0xAF, 0x9C, 0x23, + 0xA9, 0x4C, 0x1F, 0xEE, 0xCF, 0xD1, 0x23, 0xBA, + 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC, + 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 10 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x76, 0x15, 0xFB, 0xAF, 0x5A, 0xE2, 0x88, 0x64, + 0x01, 0x3C, 0x09, 0x97, 0x42, 0xDE, 0xAD, 0xB4, + 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9, + 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 11 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, + 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, + 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, + 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 12 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + 0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03, + 0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7, + 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, + 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 13 */ + const unsigned char pk[32] = { + 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, + 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, + 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, + 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 + }; + const unsigned char msg[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig[64] = { + 0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA, + 0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F, + 0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96, + 0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); + } + { + /* Test vector 14 */ + const unsigned char pk[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }; + secp256k1_xonly_pubkey pk_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); + } + { + /* Test vector 15 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + /* const unsigned char msg[0] = {}; */ + const unsigned char sig[64] = { + 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB, + 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18, + 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC, + 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF, + 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62, + 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64, + 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27, + 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig); + test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1); + } + { + /* Test vector 16 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { 0x11 }; + const unsigned char sig[64] = { + 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24, + 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A, + 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35, + 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03, + 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD, + 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96, + 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33, + 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 17 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, + }; + const unsigned char sig[64] = { + 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B, + 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B, + 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52, + 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70, + 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8, + 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC, + 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51, + 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 18 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char sig[64] = { + 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34, + 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63, + 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F, + 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8, + 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7, + 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23, + 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0, + 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67, + }; + unsigned char msg[100]; + memset(msg, 0x99, sizeof(msg)); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } +} + +/* Nonce function that returns constant 0 */ +static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + + memset(nonce32, 0, 32); + return 1; +} + +/* Nonce function that sets nonce to 0xFF...0xFF */ +static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + (void) msg; + (void) msglen; + (void) key32; + (void) xonly_pk32; + (void) algo; + (void) algolen; + (void) data; + + memset(nonce32, 0xFF, 32); + return 1; +} + +static void test_schnorrsig_sign(void) { + unsigned char sk[32]; + secp256k1_xonly_pubkey pk; + secp256k1_keypair keypair; + const unsigned char msg[] = {'t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'm', 's', 'g', ' ', 'f', 'o', 'r', ' ', 'a', ' ', 's', 'c', 'h', 'n', 'o', 'r', 'r', 's', 'i', 'g', '.', '.'}; + unsigned char sig[64]; + unsigned char sig2[64]; + unsigned char zeros64[64] = { 0 }; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + unsigned char aux_rand[32]; + + testrand256(sk); + testrand256(aux_rand); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + /* Check that deprecated alias gives the same result */ + CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1); + CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); + + /* Test different nonce functions */ + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + memset(sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_failing; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + memset(&sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_0; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); + memset(&sig, 1, sizeof(sig)); + extraparams.noncefp = nonce_function_overflowing; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + + /* When using the default nonce function, schnorrsig_sign_custom produces + * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ + extraparams.noncefp = NULL; + extraparams.ndata = aux_rand; + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1); + CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); +} + +#define N_SIGS 3 +/* Creates N_SIGS valid signatures and verifies them with verify and + * verify_batch (TODO). Then flips some bits and checks that verification now + * fails. */ +static void test_schnorrsig_sign_verify(void) { + unsigned char sk[32]; + unsigned char msg[N_SIGS][32]; + unsigned char sig[N_SIGS][64]; + size_t i; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey pk; + secp256k1_scalar s; + + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); + + for (i = 0; i < N_SIGS; i++) { + testrand256(msg[i]); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk)); + } + + { + /* Flip a few bits in the signature and in the message and check that + * verify and verify_batch (TODO) fail */ + size_t sig_idx = testrand_int(N_SIGS); + size_t byte_idx = testrand_bits(5); + unsigned char xorbyte = testrand_int(254)+1; + sig[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + sig[sig_idx][byte_idx] ^= xorbyte; + + byte_idx = testrand_bits(5); + sig[sig_idx][32+byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + sig[sig_idx][32+byte_idx] ^= xorbyte; + + byte_idx = testrand_bits(5); + msg[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + msg[sig_idx][byte_idx] ^= xorbyte; + + /* Check that above bitflips have been reversed correctly */ + CHECK(secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); + } + + /* Test overflowing s */ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + memset(&sig[0][32], 0xFF, 32); + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + + /* Test negative s */ + CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + secp256k1_scalar_set_b32(&s, &sig[0][32], NULL); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_get_b32(&sig[0][32], &s); + CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk)); + + /* The empty message can be signed & verified */ + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1); + + { + /* Test varying message lengths */ + unsigned char msg_large[32 * 8]; + uint32_t msglen = testrand_int(sizeof(msg_large)); + for (i = 0; i < sizeof(msg_large); i += 32) { + testrand256(&msg_large[i]); + } + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1); + /* Verification for a random wrong message length fails */ + msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large); + CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0); + } +} +#undef N_SIGS + +static void test_schnorrsig_taproot(void) { + unsigned char sk[32]; + secp256k1_keypair keypair; + secp256k1_xonly_pubkey internal_pk; + unsigned char internal_pk_bytes[32]; + secp256k1_xonly_pubkey output_pk; + unsigned char output_pk_bytes[32]; + unsigned char tweak[32]; + int pk_parity; + unsigned char msg[32]; + unsigned char sig[64]; + + /* Create output key */ + testrand256(sk); + CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1); + /* In actual taproot the tweak would be hash of internal_pk */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1); + + /* Key spend */ + testrand256(msg); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); + /* Verify key spend */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1); + + /* Script spend */ + CHECK(secp256k1_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1); + /* Verify script spend */ + CHECK(secp256k1_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); +} + +static void run_schnorrsig_tests(void) { + int i; + run_nonce_function_bip340_tests(); + + test_schnorrsig_api(); + test_schnorrsig_sha256_tagged(); + test_schnorrsig_bip_vectors(); + for (i = 0; i < COUNT; i++) { + test_schnorrsig_sign(); + test_schnorrsig_sign_verify(); + } + test_schnorrsig_taproot(); +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/num.h b/crypto/secp256k1/libsecp256k1/src/num.h deleted file mode 100644 index eff842200..000000000 --- a/crypto/secp256k1/libsecp256k1/src/num.h +++ /dev/null @@ -1,74 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_NUM_ -#define _SECP256K1_NUM_ - -#ifndef USE_NUM_NONE - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(USE_NUM_GMP) -#include "num_gmp.h" -#else -#error "Please select num implementation" -#endif - -/** Copy a number. */ -static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); - -/** Convert a number's absolute value to a binary big-endian string. - * There must be enough place. */ -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); - -/** Set a number to the value of a binary big-endian string. */ -static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); - -/** Compute a modular inverse. The input must be less than the modulus. */ -static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); - -/** Compute the jacobi symbol (a|b). b must be positive and odd. */ -static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); - -/** Compare the absolute value of two numbers. */ -static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); - -/** Test whether two number are equal (including sign). */ -static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); - -/** Add two (signed) numbers. */ -static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Subtract two (signed) numbers. */ -static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Multiply two (signed) numbers. */ -static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, - even if r was negative. */ -static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); - -/** Right-shift the passed number by bits. */ -static void secp256k1_num_shift(secp256k1_num *r, int bits); - -/** Check whether a number is zero. */ -static int secp256k1_num_is_zero(const secp256k1_num *a); - -/** Check whether a number is one. */ -static int secp256k1_num_is_one(const secp256k1_num *a); - -/** Check whether a number is strictly negative. */ -static int secp256k1_num_is_neg(const secp256k1_num *a); - -/** Change a number's sign. */ -static void secp256k1_num_negate(secp256k1_num *r); - -#endif - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/num_gmp.h b/crypto/secp256k1/libsecp256k1/src/num_gmp.h deleted file mode 100644 index 7dd813088..000000000 --- a/crypto/secp256k1/libsecp256k1/src/num_gmp.h +++ /dev/null @@ -1,20 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_NUM_REPR_ -#define _SECP256K1_NUM_REPR_ - -#include - -#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS) - -typedef struct { - mp_limb_t data[2*NUM_LIMBS]; - int neg; - int limbs; -} secp256k1_num; - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h b/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h deleted file mode 100644 index 3a46495ee..000000000 --- a/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h +++ /dev/null @@ -1,288 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_NUM_REPR_IMPL_H_ -#define _SECP256K1_NUM_REPR_IMPL_H_ - -#include -#include -#include - -#include "util.h" -#include "num.h" - -#ifdef VERIFY -static void secp256k1_num_sanity(const secp256k1_num *a) { - VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); -} -#else -#define secp256k1_num_sanity(a) do { } while(0) -#endif - -static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { - *r = *a; -} - -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { - unsigned char tmp[65]; - int len = 0; - int shift = 0; - if (a->limbs>1 || a->data[0] != 0) { - len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); - } - while (shift < len && tmp[shift] == 0) shift++; - VERIFY_CHECK(len-shift <= (int)rlen); - memset(r, 0, rlen - len + shift); - if (len > shift) { - memcpy(r + rlen - len + shift, tmp + shift, len - shift); - } - memset(tmp, 0, sizeof(tmp)); -} - -static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { - int len; - VERIFY_CHECK(alen > 0); - VERIFY_CHECK(alen <= 64); - len = mpn_set_str(r->data, a, alen, 256); - if (len == 0) { - r->data[0] = 0; - len = 1; - } - VERIFY_CHECK(len <= NUM_LIMBS*2); - r->limbs = len; - r->neg = 0; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); - r->limbs = a->limbs; - if (c != 0) { - VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); - r->data[r->limbs++] = c; - } -} - -static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); - (void)c; - VERIFY_CHECK(c == 0); - r->limbs = a->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { - secp256k1_num_sanity(r); - secp256k1_num_sanity(m); - - if (r->limbs >= m->limbs) { - mp_limb_t t[2*NUM_LIMBS]; - mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); - memset(t, 0, sizeof(t)); - r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } - } - - if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { - secp256k1_num_sub_abs(r, m, r); - r->neg = 0; - } -} - -static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { - int i; - mp_limb_t g[NUM_LIMBS+1]; - mp_limb_t u[NUM_LIMBS+1]; - mp_limb_t v[NUM_LIMBS+1]; - mp_size_t sn; - mp_size_t gn; - secp256k1_num_sanity(a); - secp256k1_num_sanity(m); - - /** mpn_gcdext computes: (G,S) = gcdext(U,V), where - * * G = gcd(U,V) - * * G = U*S + V*T - * * U has equal or more limbs than V, and V has no padding - * If we set U to be (a padded version of) a, and V = m: - * G = a*S + m*T - * G = a*S mod m - * Assuming G=1: - * S = 1/a mod m - */ - VERIFY_CHECK(m->limbs <= NUM_LIMBS); - VERIFY_CHECK(m->data[m->limbs-1] != 0); - for (i = 0; i < m->limbs; i++) { - u[i] = (i < a->limbs) ? a->data[i] : 0; - v[i] = m->data[i]; - } - sn = NUM_LIMBS+1; - gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); - (void)gn; - VERIFY_CHECK(gn == 1); - VERIFY_CHECK(g[0] == 1); - r->neg = a->neg ^ m->neg; - if (sn < 0) { - mpn_sub(r->data, m->data, m->limbs, r->data, -sn); - r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } - } else { - r->limbs = sn; - } - memset(g, 0, sizeof(g)); - memset(u, 0, sizeof(u)); - memset(v, 0, sizeof(v)); -} - -static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { - int ret; - mpz_t ga, gb; - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); - - mpz_inits(ga, gb, NULL); - - mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); - mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); - if (a->neg) { - mpz_neg(ga, ga); - } - - ret = mpz_jacobi(ga, gb); - - mpz_clears(ga, gb, NULL); - - return ret; -} - -static int secp256k1_num_is_one(const secp256k1_num *a) { - return (a->limbs == 1 && a->data[0] == 1); -} - -static int secp256k1_num_is_zero(const secp256k1_num *a) { - return (a->limbs == 1 && a->data[0] == 0); -} - -static int secp256k1_num_is_neg(const secp256k1_num *a) { - return (a->limbs > 1 || a->data[0] != 0) && a->neg; -} - -static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { - if (a->limbs > b->limbs) { - return 1; - } - if (a->limbs < b->limbs) { - return -1; - } - return mpn_cmp(a->data, b->data, a->limbs); -} - -static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { - if (a->limbs > b->limbs) { - return 0; - } - if (a->limbs < b->limbs) { - return 0; - } - if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { - return 0; - } - return mpn_cmp(a->data, b->data, a->limbs) == 0; -} - -static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { - if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ - r->neg = a->neg; - if (a->limbs >= b->limbs) { - secp256k1_num_add_abs(r, a, b); - } else { - secp256k1_num_add_abs(r, b, a); - } - } else { - if (secp256k1_num_cmp(a, b) > 0) { - r->neg = a->neg; - secp256k1_num_sub_abs(r, a, b); - } else { - r->neg = b->neg ^ bneg; - secp256k1_num_sub_abs(r, b, a); - } - } -} - -static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - secp256k1_num_subadd(r, a, b, 0); -} - -static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - secp256k1_num_subadd(r, a, b, 1); -} - -static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t tmp[2*NUM_LIMBS+1]; - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - - VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); - if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { - r->limbs = 1; - r->neg = 0; - r->data[0] = 0; - return; - } - if (a->limbs >= b->limbs) { - mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); - } else { - mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); - } - r->limbs = a->limbs + b->limbs; - if (r->limbs > 1 && tmp[r->limbs - 1]==0) { - r->limbs--; - } - VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); - mpn_copyi(r->data, tmp, r->limbs); - r->neg = a->neg ^ b->neg; - memset(tmp, 0, sizeof(tmp)); -} - -static void secp256k1_num_shift(secp256k1_num *r, int bits) { - if (bits % GMP_NUMB_BITS) { - /* Shift within limbs. */ - mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); - } - if (bits >= GMP_NUMB_BITS) { - int i; - /* Shift full limbs. */ - for (i = 0; i < r->limbs; i++) { - int index = i + (bits / GMP_NUMB_BITS); - if (index < r->limbs && index < 2*NUM_LIMBS) { - r->data[i] = r->data[index]; - } else { - r->data[i] = 0; - } - } - } - while (r->limbs>1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_negate(secp256k1_num *r) { - r->neg ^= 1; -} - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/num_impl.h b/crypto/secp256k1/libsecp256k1/src/num_impl.h deleted file mode 100644 index 0b0e3a072..000000000 --- a/crypto/secp256k1/libsecp256k1/src/num_impl.h +++ /dev/null @@ -1,24 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef _SECP256K1_NUM_IMPL_H_ -#define _SECP256K1_NUM_IMPL_H_ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "num.h" - -#if defined(USE_NUM_GMP) -#include "num_gmp_impl.h" -#elif defined(USE_NUM_NONE) -/* Nothing. */ -#else -#error "Please select num implementation" -#endif - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/precompute_ecmult.c b/crypto/secp256k1/libsecp256k1/src/precompute_ecmult.c new file mode 100644 index 000000000..021fe3940 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precompute_ecmult.c @@ -0,0 +1,91 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#include +#include +#include + +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" + +#include "field_impl.h" +#include "group_impl.h" +#include "int128_impl.h" +#include "ecmult.h" +#include "ecmult_compute_table_impl.h" + +static void print_table(FILE *fp, const char *name, int window_g, const secp256k1_ge_storage* table) { + int j; + int i; + + fprintf(fp, "const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); + fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", + SECP256K1_GE_STORAGE_CONST_GET(table[0])); + + j = 1; + for(i = 3; i <= window_g; ++i) { + fprintf(fp, "#if WINDOW_G > %d\n", i-1); + for(;j < ECMULT_TABLE_SIZE(i); ++j) { + fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n", + SECP256K1_GE_STORAGE_CONST_GET(table[j])); + } + fprintf(fp, "#endif\n"); + } + fprintf(fp, "};\n"); +} + +static void print_two_tables(FILE *fp, int window_g) { + secp256k1_ge_storage* table = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); + secp256k1_ge_storage* table_128 = malloc(ECMULT_TABLE_SIZE(window_g) * sizeof(secp256k1_ge_storage)); + + secp256k1_ecmult_compute_two_tables(table, table_128, window_g, &secp256k1_ge_const_g); + + print_table(fp, "secp256k1_pre_g", window_g, table); + print_table(fp, "secp256k1_pre_g_128", window_g, table_128); + + free(table); + free(table_128); +} + +int main(void) { + /* Always compute all tables for window sizes up to 15. */ + int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE; + const char outfile[] = "src/precomputed_ecmult.c"; + FILE* fp; + + fp = fopen(outfile, "w"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s for writing!\n", outfile); + return EXIT_FAILURE; + } + + fprintf(fp, "/* This file was automatically generated by precompute_ecmult. */\n"); + fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n"); + fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); + fprintf(fp, " */\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#include \"ecmult.h\"\n"); + fprintf(fp, "#include \"precomputed_ecmult.h\"\n"); + fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); + fprintf(fp, "#if ECMULT_WINDOW_SIZE > %d\n", window_g); + fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build.\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); + fprintf(fp, "# error Cannot compile precomputed_ecmult.c in exhaustive test mode\n"); + fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); + fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n"); + + print_two_tables(fp, window_g); + + fprintf(fp, "#undef S\n"); + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/src/precompute_ecmult_gen.c b/crypto/secp256k1/libsecp256k1/src/precompute_ecmult_gen.c new file mode 100644 index 000000000..cd0fe70fc --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precompute_ecmult_gen.c @@ -0,0 +1,101 @@ +/********************************************************************************* + * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *********************************************************************************/ + +#include +#include +#include + +#include "../include/secp256k1.h" + +#include "assumptions.h" +#include "util.h" + +#include "group.h" +#include "int128_impl.h" +#include "ecmult_gen.h" +#include "ecmult_gen_compute_table_impl.h" + +static const int CONFIGS[][2] = { + {2, 5}, + {11, 6}, + {43, 6} +}; + +static void print_table(FILE* fp, int blocks, int teeth) { + int spacing = CEIL_DIV(256, blocks * teeth); + size_t points = ((size_t)1) << (teeth - 1); + int outer; + size_t inner; + + secp256k1_ge_storage* table = checked_malloc(&default_error_callback, blocks * points * sizeof(secp256k1_ge_storage)); + secp256k1_ecmult_gen_compute_table(table, &secp256k1_ge_const_g, blocks, teeth, spacing); + + fprintf(fp, "#elif (COMB_BLOCKS == %d) && (COMB_TEETH == %d) && (COMB_SPACING == %d)\n", blocks, teeth, spacing); + for (outer = 0; outer != blocks; outer++) { + fprintf(fp,"{"); + for (inner = 0; inner != points; inner++) { + fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32 + ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")", + SECP256K1_GE_STORAGE_CONST_GET(table[outer * points + inner])); + if (inner != points - 1) { + fprintf(fp,",\n"); + } + } + if (outer != blocks - 1) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + free(table); +} + +int main(int argc, char **argv) { + const char outfile[] = "src/precomputed_ecmult_gen.c"; + FILE* fp; + size_t config; + int did_current_config = 0; + + (void)argc; + (void)argv; + + fp = fopen(outfile, "w"); + if (fp == NULL) { + fprintf(stderr, "Could not open %s for writing!\n", outfile); + return EXIT_FAILURE; + } + + fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); + fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#include \"ecmult_gen.h\"\n"); + fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n"); + fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n"); + fprintf(fp, "# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode\n"); + fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n"); + fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n"); + + fprintf(fp, "const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = {\n"); + fprintf(fp, "#if 0\n"); + for (config = 0; config < sizeof(CONFIGS) / sizeof(*CONFIGS); ++config) { + print_table(fp, CONFIGS[config][0], CONFIGS[config][1]); + if (CONFIGS[config][0] == COMB_BLOCKS && CONFIGS[config][1] == COMB_TEETH) { + did_current_config = 1; + } + } + if (!did_current_config) { + print_table(fp, COMB_BLOCKS, COMB_TEETH); + } + fprintf(fp, "#else\n"); + fprintf(fp, "# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build.\n"); + fprintf(fp, "#endif\n"); + + fprintf(fp, "};\n"); + fprintf(fp, "#undef S\n"); + fclose(fp); + + return EXIT_SUCCESS; +} diff --git a/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.c b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.c new file mode 100644 index 000000000..cbd030ce5 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.c @@ -0,0 +1,16456 @@ +/* This file was automatically generated by precompute_ecmult. */ +/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and + * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. + */ +#include "group.h" +#include "ecmult.h" +#include "precomputed_ecmult.h" +#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) +#if ECMULT_WINDOW_SIZE > 15 + #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting precomputed_ecmult.c before the build. +#endif +#ifdef EXHAUSTIVE_TEST_ORDER +# error Cannot compile precomputed_ecmult.c in exhaustive test mode +#endif /* EXHAUSTIVE_TEST_ORDER */ +#define WINDOW_G ECMULT_WINDOW_SIZE +const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)] = { + S(79be667e,f9dcbbac,55a06295,ce870b07,29bfcdb,2dce28d9,59f2815b,16f81798,483ada77,26a3c465,5da4fbfc,e1108a8,fd17b448,a6855419,9c47d08f,fb10d4b8) +#if WINDOW_G > 2 +,S(f9308a01,9258c310,49344f85,f89d5229,b531c845,836f99b0,8601f113,bce036f9,388f7b0f,632de814,fe337e6,2a37f356,6500a999,34c2231b,6cb9fd75,84b8e672) +#endif +#if WINDOW_G > 3 +,S(2f8bde4d,1a072093,55b4a725,a5c5128,e88b84bd,dc619ab7,cba8d569,b240efe4,d8ac2226,36e5e3d6,d4dba9dd,a6c9c426,f788271b,ab0d6840,dca87d3a,a6ac62d6) +,S(5cbdf064,6e5db4ea,a398f365,f2ea7a0e,3d419b7e,330e39c,e92bdded,cac4f9bc,6aebca40,ba255960,a3178d6d,861a54db,a813d0b8,13fde7b5,a5082628,87264da) +#endif +#if WINDOW_G > 4 +,S(acd484e2,f0c7f653,9ad178a,9f559abd,e0979697,4c57e714,c35f110d,fc27ccbe,cc338921,b0a7d9fd,64380971,763b61e9,add888a4,375f8e0f,5cc262a,c64f9c37) +,S(774ae7f8,58a9411e,5ef4246b,70c65aac,5649980b,e5c17891,bbec1789,5da008cb,d984a032,eb6b5e19,243dd56,d7b7b365,372db1e2,dff9d6a8,301d74c9,c953c61b) +,S(f28773c2,d975288b,c7d1d205,c3748651,b075fbc6,610e58cd,deeddf8f,19405aa8,ab0902e,8d880a89,758212eb,65cdaf47,3a1a06da,521fa91f,29b5cb52,db03ed81) +,S(d7924d4f,7d43ea96,5a465ae3,95ff411,31e5946f,3c85f79e,44adbcf8,e27e080e,581e2872,a86c72a6,83842ec2,28cc6def,ea40af2b,d896d3a5,c504dc9f,f6a26b58) +#endif +#if WINDOW_G > 5 +,S(defdea4c,db677750,a420fee8,7eacf21,eb9898ae,79b97687,66e4faa0,4a2d4a34,4211ab06,94635168,e997b0ea,d2a93dae,ced1f4a0,4a95c0f6,cfb199f6,9e56eb77) +,S(2b4ea0a7,97a443d2,93ef5cff,444f4979,f06acfeb,d7e86d27,74756561,38385b6c,85e89bc0,37945d93,b343083b,5a1c8613,1a01f60c,50269763,b570c854,e5c09b7a) +,S(352bbf4a,4cdd1256,4f93fa33,2ce33330,1d9ad402,71f81071,81340aef,25be59d5,321eb407,5348f534,d59c1825,9dda3e1f,4a1b3b2e,71b1039c,67bd3d8b,cf81998c) +,S(2fa2104d,6b38d11b,2300105,59879124,e42ab8df,eff5ff29,dc9cdadd,4ecacc3f,2de1068,295dd865,b6456933,5bd5dd80,181d70ec,fc882648,423ba76b,532b7d67) +,S(9248279b,9b4d68d,ab21a9b0,66edda83,263c3d84,e09572e2,69ca0cd7,f5453714,73016f7b,f234aade,5d1aa71b,dea2b1ff,3fc0de2a,887912ff,e54a32ce,97cb3402) +,S(daed4f2b,e3a8bf27,8e70132f,b0beb752,2f570e14,4bf615c0,7e996d44,3dee8729,a69dce4a,7d6c98e8,d4a1aca8,7ef8d700,3f83c230,f3afa726,ab40e522,90be1c55) +,S(c44d12c7,65d812e,8acf28d7,cbb19f90,11ecd9e9,fdf281b0,e6a3b5e8,7d22e7db,2119a460,ce326cdc,76c45926,c982fdac,e106e86,1edf61c5,a039063f,e0e6482) +,S(6a245bf6,dc698504,c89a20cf,ded60853,152b6953,36c28063,b61c65cb,d269e6b4,e022cf42,c2bd4a70,8b3f5126,f16a24ad,8b33ba48,d0423b6e,fd5e6348,100d8a82) +#endif +#if WINDOW_G > 6 +,S(1697ffa6,fd9de627,c077e3d2,fe541084,ce13300b,bec1146,f95ae57f,d0bd6a5,b9c398f1,86806f5d,27561506,e4557433,a2cf1500,9e498ae7,adee9d63,d01b2396) +,S(605bdb01,9981718b,986d0f07,e834cb0d,9deb8360,ffb7f61d,f982345e,f27a7479,2972d2d,e4f8d206,81a78d93,ec96fe23,c26bfae8,4fb14db4,3b01e1e9,56b8c49) +,S(62d14dab,4150bf49,7402fdc4,5a215e10,dcb01c35,4959b10c,fe31c7e9,d87ff33d,80fc06bd,8cc5b010,98088a19,50eed0db,1aa1329,67ab4722,35f56424,83b25eaf) +,S(80c60ad0,40f27da,de5b4b06,c408e56b,2c50e9f5,6b9b8b42,5e555c2f,86308b6f,1c38303f,1cc5c30f,26e66bad,7fe72f70,a65eed4c,be7024eb,1aa01f56,430bd57a) +,S(7a9375ad,6167ad54,aa74c634,8cc54d34,4cc5dc94,87d84704,9d5eabb0,fa03c8fb,d0e3fa9,eca87269,9559e0d,79269046,bdc59ea1,c70ce2b,2d499ec,224dc7f7) +,S(d528ecd9,b696b54c,907a9ed0,45447a79,bb408ec3,9b68df50,4bb51f45,9bc3ffc9,eecf4125,3136e5f9,9966f218,81fd656e,bc434540,5c520dbc,63465b5,21409933) +,S(49370a4,b5f43412,ea25f514,e8ecdad0,5266115e,4a7ecb13,87231808,f8b45963,758f3f41,afd6ed42,8b3081b0,512fd62a,54c3f3af,bb5b6764,b653052a,12949c9a) +,S(77f23093,6ee88cbb,d73df930,d64702ef,881d811e,e1498e2,f1c13eb1,fc345d74,958ef42a,7886b640,a08266e,9ba1b378,96c95330,d97077cb,be8eb3c7,671c60d6) +,S(f2dac991,cc4ce4b9,ea44887e,5c7c0bce,58c80074,ab9d4dba,eb28531b,7739f530,e0dedc9b,3b2f8dad,4da1f32d,ec2531df,9eb5fbeb,598e4fd,1a117dba,703a3c37) +,S(463b3d9f,662621fb,1b4be8fb,be252012,5a216cdf,c9dae3de,bcba4850,c690d45b,5ed430d7,8c296c35,43114306,dd8622d7,c622e27c,970a1de3,1cb377b0,1af7307e) +,S(f16f8042,44e46e2a,9232d4a,ff3b5997,6b98fac1,4328a2d1,a32496b4,9998f247,cedabd9b,82203f7e,13d206fc,df4e33d9,2a6c53c2,6e5cce26,d6579962,c4e31df6) +,S(caf75427,2dc84563,b0352b7a,14311af5,5d245315,ace27c65,369e15f7,151d41d1,cb474660,ef35f5f2,a41b643f,a5e46057,5f4fa9b7,962232a5,c32f9083,18a04476) +,S(2600ca4b,282cb986,f85d0f17,9979d8b,44a09c07,cb86d7c1,24497bc8,6f082120,4119b887,53c15bd6,a693b03f,cddbb45d,5ac6be74,ab5f0ef4,4b0be947,5a7e4b40) +,S(7635ca72,d7e8432c,338ec53c,d12220bc,1c48685,e24f7dc8,c602a774,6998e435,91b6496,9489d61,3d1d5e59,f78e6d7,4ecfc061,d57048ba,d9e76f30,2c5b9c61) +,S(754e3239,f325570c,dbbf4a87,deee8a66,b7f2b334,79d468fb,c1a50743,bf56cc18,673fb86,e5bda30f,b3cd0ed3,4ea49a0,23ee33d0,197a695d,c5d9809,3c536683) +,S(e3e6bd10,71a1e96a,ff57859c,82d570f0,33080066,1d1c952f,9fe26946,91d9b9e8,59c9e0bb,a394e76f,40c0aa58,379a3cb6,a5a22839,93e90c41,67002af4,920e37f5) +#endif +#if WINDOW_G > 7 +,S(186b483d,56a0338,26ae73d8,8f732985,c4ccb1f3,2ba35f4b,4cc47fdc,f04aa6eb,3b952d32,c67cf77e,2e17446e,204180ab,21fb8090,895138b4,a4a797f8,6e80888b) +,S(df9d70a6,b9876ce5,44c98561,f4be4f72,5442e6d2,b737d9c9,1a832172,4ce0963f,55eb2daf,d84d6ccd,5f862b78,5dc39d4a,b1572227,20ef9da2,17b8c45c,f2ba2417) +,S(5edd5cc2,3c51e87a,497ca815,d5dce0f8,ab52554f,849ed899,5de64c5f,34ce7143,efae9c8d,bc141306,61e8cec0,30c89ad0,c13c66c0,d17a2905,cdc706ab,7399a868) +,S(290798c2,b6476830,da12fe02,287e9e77,7aa3fba1,c355b17a,722d362f,84614fba,e38da76d,cd440621,988d00bc,f79af25d,5b29c094,db2a2314,6d003afd,41943e7a) +,S(af3c423a,95d9f5b3,54754ef,a150ac39,cd29552f,e3602573,62dfdece,f4053b45,f98a3fd8,31eb2b74,9a93b0e6,f35cfb40,c8cd5aa6,67a15581,bc2feded,498fd9c6) +,S(766dbb24,d134e745,cccaa28c,99bf2749,6bb66b2,6dcf98df,8d2fed50,d884249a,744b1152,eacbe5e3,8dcc8879,80da38b8,97584a65,fa06cedd,2c924f97,cbac5996) +,S(59dbf46f,8c94759b,a21277c3,3784f416,45f7b44f,6c596a58,ce92e666,191abe3e,c534ad44,175fbc30,f4ea6ce,648309a0,42ce739a,7919798c,d85e216c,4a307f6e) +,S(f13ada95,103c4537,305e691e,74e9a4a8,dd647e71,1a95e73c,b62dc601,8cfd87b8,e13817b4,4ee14de6,63bf4bc8,8341f32,6949e21a,6a75c257,778419b,daf5733d) +,S(7754b4fa,e8aced0,6d4167a2,c59cca4c,da1869c0,6ebadfb6,48855001,5a88522c,30e93e86,4e669d82,224b967c,3020b8fa,8d1e4e35,b6cbcc5,37a48b57,841163a2) +,S(948dcadf,5990e048,aa3874d4,6abef9d7,1858f95,de8041d2,a6828c99,e2262519,e491a425,37f6e597,d5d28a32,24b1bc25,df9154ef,bd2ef1d2,cbba2cae,5347d57e) +,S(79624144,50c76c16,89c7b48f,8202ec37,fb224cf5,ac0bfa15,70328a8a,3d7c77ab,100b610e,c4ffb476,d5c1fc1,33ef6f6b,12507a05,1f04ac57,60afa5b2,9db83437) +,S(35140878,34964b54,b15b1606,44d91548,5a169772,25b8847b,b0dd0851,37ec47ca,ef0afbb2,5620544,8e1652c4,8e8127fc,6039e77c,15c2378b,7e7d15a0,de293311) +,S(d3cc30ad,6b483e4b,c79ce2c9,dd8bc549,93e947eb,8df787b4,42943d3f,7b527eaf,8b378a22,d827278d,89c5e9be,8f9508ae,3c2ad462,90358630,afb34db0,4eede0a4) +,S(1624d847,80732860,ce1c78fc,bfefe08b,2b29823d,b913f649,3975ba0f,f4847610,68651cf9,b6da903e,914448c,6cd9d4ca,896878f5,282be4c8,cc06e2a4,4078575) +,S(733ce80d,a955a8a2,6902c956,33e62a98,5192474b,5af207da,6df7b4fd,5fc61cd4,f5435a2b,d2badf7d,485a4d8b,8db9fcce,3e1ef8e0,201e4578,c54673bc,1dc5ea1d) +,S(15d94412,54945064,cf1a1c33,bbd3b49f,8966c509,2171e699,ef258dfa,b81c045c,d56eb30b,69463e72,34f5137b,73b84177,434800ba,cebfc685,fc37bbe9,efe4070d) +,S(a1d0fcf2,ec9de675,b612136e,5ce70d27,1c21417c,9d2b8aaa,ac138599,d0717940,edd77f50,bcb5a3ca,b2e90737,309667f2,641462a5,4070f3d5,19212d39,c197a629) +,S(e22fbe15,c0af8ccc,5780c073,5f84dbe9,a790bade,e8245c06,c7ca3733,1cb36980,a855bab,ad5cd60c,88b430a6,9f53a1a7,a3828915,4964799b,e43d06d7,7d31da06) +,S(311091dd,9860e8e2,ee13473,c1155f5f,69635e39,4704eaa7,40094522,46cfa9b3,66db656f,87d1f04f,ffd1f047,88c06830,871ec5a6,4feee685,bd80f0b1,286d8374) +,S(34c1fd04,d301be89,b31c0442,d3e6ac24,883928b4,5a934078,1867d423,2ec2dbdf,9414685,e97b1b59,54bd46f7,30174136,d57f1cee,b487443d,c5321857,ba73abee) +,S(f219ea5d,6b54701c,1c14de5b,557eb42a,8d13f3ab,bcd08aff,cc2a5e6b,49b8d63,4cb95957,e83d40b0,f73af454,4cccf6b1,f4b08d3c,7b27fb8,d8c2962a,400766d1) +,S(d7b8740f,74a8fbaa,b1f683db,8f45de26,543a5490,bca62708,72369124,69a0b448,fa779681,28d9c92e,e1010f33,7ad4717e,ff15db5e,d3c049b3,411e0315,eaa4593b) +,S(32d31c22,2f8f6f0e,f86f7c98,d3a3335e,ad5bcd32,abdd9428,9fe4d309,1aa824bf,5f3032f5,892156e3,9ccd3d79,15b9e1da,2e6dac9e,6f26e961,118d14b8,462e1661) +,S(7461f371,914ab326,71045a15,5d9831ea,8793d77c,d59592c4,340f86cb,c18347b5,8ec0ba23,8b96bec0,cbdddcae,aa44254,2eee1ff5,c986ea6,b39847b3,cc092ff6) +,S(ee079adb,1df18600,74356a25,aa38206a,6d716b2c,3e67453d,287698ba,d7b2b2d6,8dc2412a,afe3be5c,4c5f37e0,ecc5f9f6,a446989a,f04c4e25,ebaac479,ec1c8c1e) +,S(16ec93e4,47ec83f0,467b1830,2ee620f7,e65de331,874c9dc7,2bfd8616,ba9da6b5,5e463115,e62fb40,d0e8c2a7,ca5804a3,9d58186a,50e49713,9626778e,25b0674d) +,S(eaa5f980,c245f6f0,38978290,afa70b6b,d8855897,f98b6aa4,85b96065,d537bd99,f65f5d3e,292c2e08,19a52839,1c994624,d784869d,7e6ea67f,b1804102,4edc07dc) +,S(78c9407,544ac132,692ee191,a024399,58ae0487,7151342e,a96c4b6b,35a49f51,f3e03191,69eb9b85,d5404795,539a5e68,fa1fbd58,3c064d24,62b675f1,94a3ddb4) +,S(494f4be2,19a1a770,16dcd838,431aea00,1cdc8ae,7a6fc688,726578d9,702857a5,42242a96,9283a5f3,39ba7f07,5e36ba2a,f925ce30,d767ed6e,55f4b031,880d562c) +,S(a598a803,da6d86c,6bc7f2f5,144ea549,d28211ea,58faa70e,bf4c1e66,5c1fe9b5,204b5d6f,84822c30,7e4b4a71,40737aec,23fc63b6,5b35f86a,10026dbd,2d864e6b) +,S(c4191636,5abb2b5d,9192f5f,2dbeafec,208f020f,12570a18,4dbadc3e,58595997,4f14351,d0087efa,49d245b3,28984989,d5caf945,f34bfc0,ed16e96b,58fa9913) +,S(841d6063,a586fa47,5a724604,da03bc5b,92a2e0d2,e0a36acf,e4c73a55,14742881,73867f5,9c0659e8,1904f9a1,c7543698,e62562d6,744c169c,e7a36de0,1a8d6154) +#endif +#if WINDOW_G > 8 +,S(5e95bb39,9a6971d3,76026947,f89bde2f,282b3381,928be4d,ed112ac4,d70e20d5,39f23f36,6809085b,eebfc711,81313775,a99c9aed,7d8ba38b,161384c7,46012865) +,S(36e4641a,53948fd4,76c39f8a,99fd974e,5ec07564,b5315d8b,f99471bc,a0ef2f66,d2424b1b,1abe4eb8,164227b0,85c9aa94,56ea1349,3fd563e0,6fd51cf5,694c78fc) +,S(336581e,a7bfbbb2,90c191a2,f507a41c,f5643842,170e914f,aeab27c2,c579f726,ead12168,595fe1be,99252129,b6e56b33,91f7ab14,10cd1e0e,f3dcdcab,d2fda224) +,S(8ab89816,dadfd6b6,a1f2634f,cf00ec84,3781025,ed6890c4,84974270,6bd43ede,6fdcef09,f2f6d0a0,44e654ae,f624136f,503d459c,3e898458,58a47a91,29cdd24e) +,S(1e33f1a7,46c9c577,8133344d,9299fcaa,20b0938e,8acff254,4bb40284,b8c5fb94,6066025,7dd11b3a,a9c8ed61,8d24edff,2306d320,f1d03010,e33a7d20,57f3b3b6) +,S(85b7c1dc,b3cec1b7,ee7f30de,d79dd20a,ed1f4cc,18cbcfcf,a410361f,d8f08f31,3d98a9cd,d026dd43,f39048f2,5a8847f4,fcafad18,95d7a633,c6fed3c3,5e999511) +,S(29df9fbd,8d9e4650,9275f4b1,25d6d45d,7fbe9a3b,878a7af8,72a28006,61ac5f51,b4c4fe9,9c775a60,6e2d8862,179139ff,da61dc86,1c019e55,cd2876eb,2a27d84b) +,S(a0b1cae0,6b0a847a,3fea6e67,1aaf8adf,dfe58ca2,f768105c,8082b2e4,49fce252,ae434102,edde0958,ec4b19d9,17a6a28e,6b72da18,34aff0e6,50f04950,3a296cf2) +,S(4e8ceaf,b9b3e9a1,36dc7ff6,7e840295,b499dfb3,b2133e4b,a113f2e4,c0e121e5,cf217411,8c8b6d7a,4b48f6d5,34ce5c79,422c086a,63460502,b827ce62,a326683c) +,S(d24a44e0,47e19b6f,5afb81c7,ca2f6908,a507668,9a010919,f42725c2,b789a33b,6fb8d559,1b466f8f,c63db50f,1c0f1c69,13f9968,87b8244d,2cdec417,afea8fa3) +,S(ea01606a,7a6c9cdd,249fdfcf,acb99584,1edd28,abbab77b,5104e98e,8e3b35d4,322af490,8c7312b0,cfbfe369,f7a7b3cd,b7d4494b,c2823700,cfd65218,8a3ea98d) +,S(af8addbf,2b661c8a,6c632865,5eb96651,252007d8,c5ea31be,4ad196de,8ce2131f,6749e67c,29b85f5,2a034eaf,d096836b,25208186,80e26ac8,f3dfbcdb,71749700) +,S(e3ae19,74566ca0,6cc516d4,7e0fb165,a674a3da,bcfca15e,722f0e34,50f45889,2aeabe7e,45315101,16217f07,bf4d0730,de97e48,74f81f53,3420a72e,eb0bd6a4) +,S(591ee355,313d9972,1cf6993f,fed1e3e3,1993ff3,ed258802,75ea8ce,d397e246,b0ea558a,113c30be,a60fc477,5460c790,1ff0b053,d25ca2bd,eee98f1a,4be5d196) +,S(11396d55,fda54c49,f19aa973,18d8da61,fa8584e4,7b084945,77cf032,55b52984,998c74a8,cd45ac01,289d5833,a7beb474,4ff536b0,1b257be4,c5767bea,93ea57a4) +,S(3c5d2a1b,a39c5a17,90000738,c9e0c40b,8dcdfd54,68754b64,5540157,e017aa7a,b2284279,995a34e2,f9d4de73,96fc18b8,f9b8b9f,dd270f66,61f79ca4,c81bd257) +,S(cc8704b8,a60a0def,a3a99a72,99f2e9c3,fbc395af,b04ac078,425ef8a1,793cc030,bdd46039,feed1788,1d1e0862,db347f8c,f395b74f,c4bcdc4e,940b74e3,ac1f1b13) +,S(c533e4f7,ea8555aa,cd9777ac,5cad29b9,7dd4defc,cc53ee7e,a204119b,2889b197,6f0a256b,c5efdf42,9a2fb624,2f1a43a2,d9b925bb,4a4b3a26,bb8e0f45,eb596096) +,S(c14f8f2,ccb27d6f,109f6d08,d03cc96a,69ba8c34,eec07bbc,f566d48e,33da6593,c359d692,3bb398f7,fd4473e1,6fe1c284,75b740dd,98075e6,c0e86491,13dc3a38) +,S(a6cbc304,6bc6a450,bac24789,fa17115a,4c9739ed,75f8f21c,e441f72e,b90e6ef,21ae7f4,680e889b,b130619e,2c0f95a3,60ceb573,c7060313,9862afd6,17fa9b9f) +,S(347d6d9a,2c48927,ebfb86c1,359b1caf,130a3c02,67d11ce6,344b39f9,9d43cc38,60ea7f61,a353524d,1c987f6e,cec92f08,6d565ab6,87870cb1,2689ff1e,31c74448) +,S(da6545d2,181db8d9,83f7dcb3,75ef5866,d47c67b1,bf31c8cf,855ef743,7b72656a,49b96715,ab6878a7,9e78f07c,e5680c5d,6673051b,4935bd89,7fea824b,77dc208a) +,S(c40747cc,9d012cb1,a13b8148,309c6de7,ec25d694,5d657146,b9d5994b,8feb1111,5ca56075,3be2a12f,c6de6caf,2cb48956,5db93615,6b9514e1,bb5e8303,7e0fa2d4) +,S(4e42c8ec,82c99798,ccf3a610,be870e78,338c7f71,3348bd34,c8203ef4,37f3502,7571d74e,e5e0fb92,a7a8b33a,7783341,a5492144,cc54bcc4,a944736,93606437) +,S(3775ab70,89bc6af8,23aba2e1,af70b236,d251cadb,c867432,87522a1b,3b0dedea,be52d107,bcfa09d8,bcb9736a,828cfa7f,ac8db17b,f7a76a2c,42ad9614,9018cf7) +,S(cee31cbf,7e34ec37,9d94fb81,4d3d775a,d954595d,1314ba88,46959e3e,82f74e26,8fd64a14,c06b589c,26b947ae,2bcf6bfa,149ef0b,e14ed4d8,f448a01,c43b1c6d) +,S(b4f9eaea,9b69176,19f6ea6a,4eb5464e,fddb58fd,45b1ebef,cdc1a01d,8b47986,39e5c992,5b5a54b0,7433a4f1,8c61726f,8bb131c0,12ca542e,b24a8ac0,7200682a) +,S(d4263dfc,3d2df923,a0179a48,966d30ce,84e2515a,fc3dccc1,b7790779,2ebcc60e,62dfaf07,a0f78feb,30e30d62,95853ce1,89e12776,ad6cf7f,ae164e12,2a208d54) +,S(48457524,820fa65a,4f8d35eb,6930857c,32acc0,a4a2de42,2233eeda,897612c4,25a748ab,367979d9,8733c38a,1fa1c2e7,dc6cc07d,b2d60a9a,e7a76aaa,49bd0f77) +,S(dfeeef18,81101f2c,b11644f3,a2afdfc2,45e1991,9152923f,367a1767,c11cceda,ecfb7056,cf1de042,f9420bab,396793c0,c390bde7,4b4bbdff,16a83ae0,9a9a7517) +,S(6d7ef6b1,7543f837,3c573f44,e1f38983,5d89bcbc,6062ced3,6c82df83,b8fae859,cd450ec3,35438986,dfefa10c,57fea9bc,c521a095,9b2d80bb,f74b190d,ca712d10) +,S(e75605d5,9102a5a2,684500d3,b991f2e3,f3c88b93,22554703,5af25af6,6e04541f,f5c54754,a8f71ee5,40b9b487,28473e31,4f729ac5,308b0693,8360990e,2bfad125) +,S(eb98660f,4c4dfaa0,6a2be453,d5020bc9,9a0c2e60,abe38845,7dd43fef,b1ed620c,6cb9a887,6d9cb852,609af3a,dd26cd20,a0a7cd8a,9411131c,e85f4410,99223e) +,S(13e87b02,7d8514d3,5939f2e6,892b1992,21545969,41888336,dc3563e3,b8dba942,fef5a3c6,8059a6de,c5d62411,4bf1e91a,ac2b9da5,68d6abeb,2570d556,46b8adf1) +,S(ee163026,e9fd6fe0,17c38f06,a5be6fc1,25424b37,1ce2708e,7bf44916,91e5764a,1acb250f,255dd61c,43d94ccc,670d0f58,f49ae3fa,15b96623,e5430da0,ad6c62b2) +,S(b268f5ef,9ad51e4d,78de3a75,c2dc89b,1e626d43,50586799,9932e5db,33af3d80,5f310d4b,3c99b9eb,b19f77d4,1c1dee01,8cf0d34f,d4191614,3e945a,1216e423) +,S(ff07f311,8a9df035,e9fad85e,b6c7bfe4,2b02f01c,a99ceea3,bf7ffdba,93c4750d,438136d6,3e858a3,a5c440c3,8eccbadd,c1d29421,14e2eddd,4740d098,ced1f0d8) +,S(8d8b9855,c7c052a3,4146fd20,ffb658be,a4b9f69e,d825ebe,c16e8c3c,e2b526a1,cdb559ee,dc2d79f9,26baf44f,b84ea4d4,4bcf50fe,e51d7ceb,30e2e7f4,63036758) +,S(52db0b53,84dfbf05,bfa9d472,d7ae26df,e4b851ce,ca91b1eb,a5426318,da32b63,c3b997d,50ee5d4,23ebaf66,a6db9f57,b3180c90,2875679d,e924b69d,84a7b375) +,S(e62f9490,d3d51da6,395efd24,e80919cc,7d0f29c3,f3fa48c6,fff543be,cbd43352,6d89ad7b,a4876b0b,22c2ca28,c682862,f342c859,1f1daf51,70e07bfd,9ccafa7d) +,S(7f30ea24,76b399b4,957509c8,8f77d019,1afa2ff5,cb7b14fd,6d8e7d65,aaab1193,ca5ef7d4,b231c94c,3b15389a,5f6311e9,daff7bb6,7b103e98,80ef4bff,637acaec) +,S(5098ff1e,1d9f14fb,46a210fa,da6c903f,ef0fb7b4,a1dd1d9a,c60a0361,800b7a00,9731141,d81fc8f8,84d37c6,e7542006,b3ee1b40,d60dfe53,62a5b132,fd17ddc0) +,S(32b78c7d,e9ee512a,72895be6,b9cbefa6,e2f3c4cc,ce445c96,b9f2c81e,2778ad58,ee1849f5,13df71e3,2efc3896,ee28260c,73bb8054,7ae2275b,a4972377,94c8753c) +,S(e2cb74fd,dc8e9fbc,d076eef2,a7c72b0c,e37d50f0,8269dfc0,74b58155,547a4f7,d3aa2ed7,1c9dd224,7a62df06,2736eb0b,addea9e3,6122d2be,8641abcb,5cc4a4) +,S(84384475,66d4d7be,dadc2994,96ab3574,26009a35,f235cb14,1be0d99c,d10ae3a8,c4e10209,16980a4d,a5d01ac5,e6ad3307,34ef0d79,6631c4f,2390426b,2edd791f) +,S(4162d488,b8940203,9b584c6f,c6c30887,587d9c4,6f660b87,8ab65c82,c711d67e,67163e90,3236289f,776f22c2,5fb8a3af,c1732f2b,84b4e95d,bda47ae5,a0852649) +,S(3fad3fa8,4caf0f34,f0f89bfd,2dcf54fc,175d767a,ec3e5068,4f3ba4a4,bf5f683d,cd1bc7c,b6cc407b,b2f0ca64,7c718a73,cf71872,e7d0d2a5,3fa20efc,dfe61826) +,S(674f2600,a3007a00,568c1a7c,e05d0816,c1fb84bf,1370798f,1c69532f,aeb1a86b,299d21f9,413f33b3,edf43b25,7004580b,70db57da,b182259,e09eecc6,9e0d38a5) +,S(d32f4da5,4ade74ab,b81b815a,d1fb3b26,3d82d6c6,92714bcf,f87d29bd,5ee9f08f,f9429e73,8b8e53b9,68e99016,c0597077,82e14f45,35359d58,2fc41691,b3eea87) +,S(30e4e670,43538555,6e593657,135845d3,6fbb6931,f72b08cb,1ed954f1,e3ce3ff6,462f9bce,61989863,84993501,13bbc9b1,a878d35,da70740d,c695a559,eb88db7b) +,S(be206200,3c51cc30,4682904,330e4dee,7f3dcd10,b01e580b,f1971b04,d4cad297,62188bc4,9d61e542,8573d48a,74e1c655,b1c61090,905682a0,d5558ed7,2dccb9bc) +,S(93144423,ace3451e,d29e0fb9,ac2af211,cb6e84a6,1df5993,c419859f,ff5df04a,7c10dfb1,64c3425f,5c71a3f9,d7992038,f1065224,f72bb9d1,d902a6d1,3037b47c) +,S(b015f804,4f5fcbdc,f21ca26d,6c34fb81,97829205,c7b7d2a7,cb66418c,157b112c,ab8c1e08,6d04e813,744a655b,2df8d5f8,3b3cdc6f,aa3088c1,d3aea145,4e3a1d5f) +,S(d5e9e1da,649d97d8,9e486811,7a465a3a,4f8a18de,57a140d3,6b3f2af3,41a21b52,4cb04437,f391ed73,111a13cc,1d4dd0db,1693465c,2240480d,8955e859,2f27447a) +,S(d3ae4104,7dd7ca06,5dbf8ed7,7b992439,983005cd,72e16d6f,996a5316,d36966bb,bd1aeb21,ad22ebb2,2a10f030,3417c6d9,64f8cdd7,df0aca61,4b10dc14,d125ac46) +,S(463e2763,d885f958,fc66cdd2,2800f0a4,87197d0a,82e377b4,9f80af87,c897b065,bfefacdb,e5d0fd7,df3a311a,94de062b,26b80c61,fbc97508,b7999267,1ef7ca7f) +,S(7985fdfd,127c0567,c6f53ec1,bb63ec31,58e597c4,bfe747c,83cddfc9,10641917,603c12da,f3d9862e,f2b25fe1,de289aed,24ed291e,ec67087,3a5bd56,7f32ed03) +,S(74a1ad6b,5f76e39d,b2dd2494,10eac7f9,9e74c59c,b83d2d0e,d5ff1543,da7703e9,cc6157ef,18c9c63c,d6193d83,631bbea0,93e0968,942e8c33,d5737fd7,90e0db08) +,S(30682a50,703375f6,2d41666,4ba19b7f,c9bab42c,72747463,a71d0896,b22f6da3,553e04f6,b018b4fa,6c8f39e7,f311d317,6290d0e0,f19ca73f,17714d99,77a22ff8) +,S(9e2158f0,d7c0d5f2,6c3791ef,efa79597,654e7a2b,2464f52b,1ee6c134,7769ef57,712fcdd,1b9053f0,9003a348,1fa7762e,9ffd7c8e,f35a3850,9e2fbf26,29008373) +,S(176e2698,9a43c9cf,eba4029c,202538c2,8172e566,e3c4fce7,322857f3,be327d66,ed8cc9d0,4b29eb87,7d270b48,78dc43c1,9aefd31f,4eee09ee,7b47834c,1fa4b1c3) +,S(75d46efe,a3771e6e,68abb89a,13ad747e,cf189239,3dfc4f1b,7004788c,50374da8,9852390a,99507679,fd0b86fd,2b39a868,d7efc221,51346e1a,3ca47265,86a6bed8) +,S(809a20c6,7d64900f,fb698c4c,825f6d5f,2310fb04,51c86934,5b7319f6,45605721,9e994980,d9917e22,b76b0619,27fa0414,3d096ccc,54963e6a,5ebfa5f3,f8e286c1) +,S(1b38903a,43f7f114,ed4500b4,eac7083f,defece1c,f29c6352,8d563446,f972c180,4036edc9,31a60ae8,89353f77,fd53de4a,2708b26b,6f5da72a,d3394119,daf408f9) +#endif +#if WINDOW_G > 9 +,S(90a80db6,eb294b9e,ab0b4e8d,dfa3efe7,263458ce,2d07566d,f4e6c588,68feef23,753c8b9f,9754f18d,87f21145,d9e2936b,5ee050b2,7bbd9681,442c76e9,2fcf91e6) +,S(c2c80f84,4b705998,12d62546,f60340e,3e6f3605,4a14546e,6dc25d47,376bea9b,86ca160d,68f4d4e7,18b495b8,91d3b1b5,73b871a7,2b4cf61,23abd448,3aa79c64) +,S(9cf60674,4cf4b5f3,fdf989d3,f19fb265,2d00cfe1,d5fcd692,a323ce11,a28e7553,8147cbf7,b973fcc1,5b57b6a3,cfad6863,edd0f30e,3c45b85d,c300c513,c247759d) +,S(57488fa2,8742c6b2,5a493fd6,60d936e,a6280b0c,742005ab,ce98f585,5ad82208,31b3ca45,5073bea5,58adbe56,c27b470b,af949ae6,50213921,dc287844,f1a29574) +,S(f1133cbe,6be8bbc8,dc8df2b8,d75963c2,d40ed616,c758cdc8,4edbc5eb,4899447d,57fc2447,2225b23f,5714626d,8d67d561,10bd3a60,dd7a1687,cbbb893,f652f50f) +,S(95083e75,3301bd78,7f8989c7,9065bb81,3f3d69bf,f3e42505,f4e0417,5bbe89c0,844adb5c,e7d10de9,4617c73c,a77040e4,ee4e92e0,156b3c70,cc593fa4,94b33482) +,S(1a908355,cbb75675,5e576ed2,9c99af63,8668c7b3,63c8d973,62100443,bc5c75c6,d765466c,6e556e35,2f778722,25627d80,a7353807,4b44ff27,57ad22e,2f2454a2) +,S(c5922f74,bd343d5,aa867308,fad97f9f,8a2d1f63,c5f31db4,f04df3be,f349b648,77b1f068,7cfcdbe8,812605e5,d8b752c,da811844,236a4c43,77f53c94,6e7bd648) +,S(64e1b196,9f910297,7691a404,31b0b672,55dcf31,163897d9,96434420,e6c95dc9,c16f60c7,c11fc3c9,eb27fa26,a9035b66,9bfb77d2,1cef371d,dce94e32,9222550c) +,S(33b2e76,687744ed,6c521bad,3333dd37,c602f8a7,549e9ce7,808fb7ea,7ce08de,e1bcfe7f,c8ed8ae9,5cf6c243,7fdd94bf,d742e8ca,a6de7811,4c25112a,86988efd) +,S(20f18f4c,866d8a1c,c2a31033,17b4ac31,89fbf30f,f294a75c,951473be,45e4f294,8d6857c9,d08ef7b4,fd888336,3d37bee7,fe8529f,7173f589,43fcae81,d2d0ea0e) +,S(4d1623c9,44c9c716,a0eb4c68,5e2a8b9d,2df34653,54643bef,d1444176,d7b69a8b,ddf1b9fe,8744ad03,f996bf6b,96ec3496,2b601bd5,ed952f78,54f58388,8917be80) +,S(a901b0db,e8ab292d,280d6b36,85894785,4faad0a4,dd0da7e2,d4ad0ff5,3db079e0,3f27e7e1,834f1a61,af6f04dc,61e7ae64,716bc5e0,a6b063b3,1d0e60e,47298a9d) +,S(7e0af071,30218ffd,50bd66f4,484645b1,2f42a24f,7c80889b,3031c9a6,ebfc9a70,50bc23f3,926cd0c4,9f53fbb2,35eb1e89,d579517,f5bdc3ab,2416db78,5aaedb3f) +,S(7ba8187e,1a7b25a2,c185d335,440a9038,b47f0528,546e9da4,ef82aab0,5aebf20d,6e6aee6c,9625370a,f866c25c,7ca5dd78,527efbc,e7d8b3a3,9ab24930,9a185187) +,S(8c050fc3,4d83b279,b6000816,e18fca38,9767b796,e926772,55b84a39,d93a6807,986314ef,75b68fb2,827c2965,4198139,5d699fcd,81cf23ce,7019bc41,35174870) +,S(53b7849a,78e4df86,25860583,a5249948,9d7201a2,cbf50620,2a7b8b1b,c99c2ec9,4e31ea12,ac607d07,5de4b22d,e1be2c52,e0a44d25,4728d2c5,44d2ddf9,e3e469c0) +,S(9bdf9e67,a5d0c995,6a075a01,fe762be,b6335004,31dee78e,febc527e,53313b33,94264621,a5960e0e,e24c2792,6f16cad2,907f2636,762e8d5a,17e94afd,8e9d2bb0) +,S(7caa72b3,7a8ab3bd,bac031a,47606f89,17d9f42c,6ec2d2fb,429fd990,4a381f34,5b5853ab,7ee5de8d,34e3d6be,b201094f,ff8fbd1e,682f7f1,ef87ddd6,5d7303c9) +,S(2ef29b9f,9827975,79c0295f,c3f48db7,925d62c7,5532493d,de16b97e,3993d81a,496c944d,d9875ba6,a537ef9,6bf4c714,a0afff24,387d95e8,9b42337a,33110753) +,S(df157cad,95b07875,573c1860,ae5d02c6,4029e952,ec354e6a,9e5c34be,97317ff8,f2eccac7,75922b50,899c979a,2b3cc30,b629e62e,85693ba4,70f6ee38,1284c162) +,S(dd55c150,a29ca526,b6182e64,3b9eb544,e651d236,b71920e7,b15a9870,16454b1d,44c757a5,42f4ea2e,b39605d4,268c2510,ac685aab,d77a8f5c,4d95e23f,4c2e9368) +,S(16886cf4,6ed42c79,19147763,63d3256,c4d5d393,87f01723,25b9e4b8,98227f27,7421a220,7ee73299,d46192fc,93ca03de,c824ed8d,e2f48367,ec538317,a17fffb) +,S(6ff180fc,daa30618,8e8b306,d6f0acff,27968c22,484ff45e,56aeaa7b,2b60732f,7d16d654,f0c2aff0,fc254dad,63761a2,6c8d4022,ea85b8cc,22f3ea1e,f69961a9) +,S(3ea4511,a00dc2a0,3eb4f51f,40ee677c,aa912b55,39f685c4,f8bcc8ea,dc395e36,6c9ed1f1,528b0215,93a39839,340ddb53,a2f2e36,5290c498,24b035c6,73c9259d) +,S(b82cd70,dc3de9ea,b38742d8,f32dfb8d,53e4150a,835e54b6,3c7cca20,f253081d,e8bcbfe,1f7f6e75,d32e2049,9329765f,2effc56,a922f268,60d4bc0a,add0e24d) +,S(fe2fc3e0,748745,84ee23bf,105a69a6,6d056f0,17327d49,b7b38b57,a196c77f,3e18941c,c3c6d297,cc9a32f6,95807b1c,7da8561d,e4fde71d,4f9bbdb6,e9bf3916) +,S(4b90176,cdaa3693,47e8778b,12db9d6e,e8b00114,46ea35ec,845dbf57,4bb7858b,f60547ab,6e9c5fd3,eca6e349,b85880c6,1fdad0fc,2f7ab155,295caaec,b973c154) +,S(35f38251,1d34600b,4b8c86a9,f0dbc9ed,defc4272,f59528a0,cd3ec10a,5944c6d2,29a835f6,ef7fa1e5,f6f37a80,cf96ca98,43762bb1,b12a0dae,ae83234b,d0b5ccd5) +,S(1d74b297,311b7ff,a1027e26,587d3f5b,e1d0e9ac,3f0111cd,f3cc2371,722cb94a,5c7bcf8b,57f114e0,b73bcfb8,10f5c60d,35dc99ae,9dc7f0e2,606cc1f7,28c2071e) +,S(50a094f3,9c6f956,b020737,b9ec722e,4f75d1b7,c41593e6,f934a68a,98450428,a286e222,dfe10cfd,9689eaba,6a81f044,89c86db6,869aa1b5,54a90f1e,83778eee) +,S(9b65bb81,2129157c,dfecf12e,275ec38c,282dbcd9,14b48105,99b0a6d6,27c63db7,c582db1a,3f0f2242,1913b2e9,51e98a78,660b4c40,ad08fd65,528593bc,18223188) +,S(8b4544fc,1fdfa06e,456c1115,a1dc831c,85e7f1c5,e620eca5,1c20802d,36a4bc6b,e3e77c41,288f2602,e722af7f,4b70e64d,e4116fb9,955b03b0,6ea8b19f,7a20350d) +,S(6c709880,b959eb7c,5179b29c,c5578fdc,6cb2ae13,ddcede29,d5f81d95,de0ab4aa,c9e33fae,bd8eba42,6736c0c7,6f3deaba,ee2b59c5,953fb43,c2dcc513,9e7c4bdc) +,S(77760b51,37ba6a71,95d891f7,94a087a0,76fc9d67,802b81e7,85b5677,3d537806,f5202cf5,aaeea58b,f4f58c7e,df4417be,1b87ffde,e68e77f0,d7e81abe,158e3a25) +,S(1a8bd783,6a0b0c82,e9a904a8,a8c91a67,e23cd4f8,efd625d0,df4c426e,7e163102,61fe64ca,b0952cae,3c574f28,2f74a87d,c2a96316,b7009f2e,4e9c5fcc,12285844) +,S(fe217db6,59079913,fb1e453e,d24d91d6,a3fb3099,e69471d7,53db5390,864abc30,5dcf9abb,a9625ed6,80b0f20f,b1f047d5,93a0c61c,53969253,8cdf6b03,4d730b58) +,S(2504d637,54afd5eb,c38f58b6,5ead696d,7e3abd7,48cb6c5f,212aed49,f5b33b91,79a6bf43,75f1469c,4f5321c6,c72fbbf4,ba7cec10,5675f437,b5e013ad,7b5d75d4) +,S(b06f702,f47b22d7,89a9bd3f,687105c3,6160abbf,5cc8976b,7fbddcaf,db197b5c,7669bbd4,19a4d491,f592a35b,6aa3dfe4,5bd2fe7f,d179c778,1cd5f918,d732f63d) +,S(803b203b,b31f9cf9,4034eeb9,31b54480,a6f3f99e,bd23d0ac,bc2128a6,d044e23,308abc8d,f271f759,59b20c5c,7fa62baf,bfc9ccbf,49b946a9,54e5381c,1728d1c7) +,S(266a9cb4,c5f5cead,bb50e5bd,a03a7312,e52de1de,8e95a8dc,d57289fe,302749a,9eea970b,a856b2fa,a3e82877,cc84ed4f,3dc0efba,1e7c3baa,8b386ffc,46e0ae7e) +,S(fd8a9d95,d80c7ad5,2599a7ab,98163df3,64c4c141,e9abea35,5d7360bc,f84eba94,a9fb1702,100953b3,59b2e268,8ae7fd33,a30377da,47bfda71,3e2d7d73,dfb1030c) +,S(a7322df3,9f28f23,59fc339a,8b2c80be,6e84acc5,b7b0b8f8,f2cb6f26,f9db0a7d,22f6fe9d,21749501,7fdb7f5b,2f12fa57,95f40e1,31714885,c12a2ea1,6edb6be6) +,S(82a8c10f,336a6649,63a104dd,bf7f0f18,bd4c461a,ea569ffc,82c3c7e4,cb052d36,737ceca2,c0ef7227,8b90501c,cb71b671,5e5c31d4,cd0478c1,18fe1287,95f1dd0c) +,S(9b50d1b6,8e3bf795,7cd12f,5a60c26,6c4ef2b7,5ba5c516,c54784a9,4f15d6df,2afc8d09,b79176d8,d003fd2a,4f18d526,403fff27,2d47e778,7376feb7,cbddd8fd) +,S(3f9083dd,c8b423fe,7de3a822,81d3056a,b8dcb9d7,ee82cb80,6718595f,bae08d32,cb13c152,fd511d91,a9e0ed90,afa021a0,81f77f6d,20cc1376,e2195ffc,f28fa758) +,S(c75c85c1,ee17c1a2,56eff6bd,592666cb,c9231706,59d50bfa,dbd1074e,f2167faf,1ab4eabe,5e09409d,75cca892,2647f48d,bd698a16,d4f7cc85,96daf169,40023a52) +,S(c5341fea,f8a0f5d3,b4d0cf0d,2f7aad7c,60ea8e2b,3d4b7fb9,5c68d576,98656045,95f9f4e9,7e5b9f,a48fa422,a26ab982,dc48a4d5,4d712398,6e6d3ab9,74e88915) +,S(83acda3e,2a8997e0,d52bd4c6,8705dd22,220852b7,752d67fd,8967a032,60c2d89b,dce1bae1,d655ba51,7f5b5580,99711757,a77cd3b,dd4b8e8e,330e9779,1bc31df0) +,S(5b819146,8b299074,5b9c4164,e29d594c,f1c0d571,6c5d3962,5bd279b3,25237b,cc3636a0,3fddddfa,bed88daa,b081f359,1c48d2ca,71ba34fc,f6989f4a,f7625d8e) +,S(64778122,214e38ef,f8041796,166104e7,32f5f664,d38d7721,9b89045e,2c3b0e6c,329cf049,7e15eec7,b8eafc4a,b8a7d1c,d8b63203,8d4aef81,974cf984,4611a32d) +,S(ed4d826a,fe5762f4,79509909,9aee8664,2b475a9d,6da1017c,43d0cb9f,1af12323,8c6f81be,3fafa5ee,c8296f92,8ac7919d,c4d88c9a,59442274,d0531b7b,f7e48e78) +,S(38b42924,419aecc3,acd6f551,346fd61a,4d82ac2b,55f7afe9,7a06eb40,cd109c4a,7f42c096,2feb2f73,b2b0965a,1f359a6a,de49d768,a2ce6b07,b5acb92b,73e05583) +,S(c3cad4a8,d8bb94a7,b434cf70,183e8615,bb2a8f62,24f216e3,446ac2e9,82138911,f649be27,8cad9764,20742ce3,82dce3a1,420e372e,f1b25b27,59a8ed38,7282765e) +,S(2d408ff4,d3d236fd,54fae40d,ce3ea9ec,d9212e57,36591a9e,55588e4a,54bd6538,d596adf0,e8692a06,bc6284bf,299bef6,85e2a171,585aa132,4b9a05b5,ce815b7) +,S(ee7adf6d,247f25fb,76e90cf8,13f888eb,d67423a3,a3c6fdae,bafb7eaa,7a33c854,e077184b,4ae8f705,6c10dd9e,f541689d,143f6871,789e1801,deaefc1d,527a8fb4) +,S(2f9457c8,a9ffaca1,3d91151d,c4c5e89d,dd5d37a3,7c9a864b,7c811f3e,1144b34,eb4c9848,9093d573,a295407e,1d6fc48a,787120ce,b3d3dcfb,b40634e0,e75e221d) +,S(d3f332b8,a0f11582,1ce3478c,efe18de3,60120483,ef531c27,7b30c46e,b7fec294,ea75b9b2,5d717861,d1af1c01,9c372941,c8968b90,ef134f9f,323215e1,bb0b2155) +,S(183408d3,38b05aad,3521fcd8,6ef36dd7,5f3ddb86,66b52f7e,9a4cdf1f,8e152b91,66998520,6edf4ac6,f39be21f,20c98824,210e204c,e4499809,5de35537,1641218c) +,S(283fec5d,b1145e53,ba8f1f0f,f9cf89a7,21faffd6,c2534686,3d395609,5f40374e,70b01237,74af550e,68e68e5f,65ca6e98,8846e03,cf39af77,8511be82,bc32fefe) +,S(ce7570a,4f943cfa,413bd249,d8e7dbfc,ebc73579,770fd6da,f54a0dfb,dd52fa62,e115b14b,ef4695cf,fb85bdf9,8ba3985c,bd5e5b89,83e05390,7c36f9ce,8b75d41d) +,S(7e9c4f19,c8f4ec3f,1269f648,cd919525,df790315,74cbeb15,37794a4c,838fd470,e9d9dbfe,8cf5f5cc,a855d6cc,bd11f480,60fafa8d,ad6bd3e9,c86df5ce,b0fa5270) +,S(e2a9bbe6,d5d5bfe,a7c7f919,df2309f9,ba04f4c,722a3ec2,3bf451b4,64cb001b,e4177ce1,c3cd6ac7,78925bd6,7e72cb77,d1925b91,d06a7f16,98411a47,86393fb0) +,S(504512a4,3e17ef50,e43bf37d,42a94990,f55e641b,1558c265,e7099002,75271012,954a5fd8,57ba3acf,2d4b1f41,e8e1f2cd,1f21c4b9,6899781b,742a49d2,e61ed18b) +,S(81d1f013,a6bb325f,4b2d1d51,ba72c721,859945d8,a17b3411,cd5cbe87,285f850d,2d5d2fb1,f0c30855,3b1fe249,298b2059,259d3d49,d4d7071a,dce4bcc5,dc937193) +,S(5b66c2df,c1d28266,18a87276,7e66c33d,d90dd514,14a3b87c,a733383d,1d895022,9bd0178e,38189569,2217267b,7407e987,27fcaeda,12d8cf54,49eb5472,d554e0ff) +,S(aeb5f70e,98ec5e38,dbd2d544,bdbff8ab,99b583d9,af58c597,afaf8688,20381186,618bd6b0,d25ca70d,f08b7692,9336e421,691b0973,f2f5a05,2e7adc17,3584427b) +,S(b289eff,e841943b,84761e3c,67a9c02a,557679ca,76ad753a,707a9821,2505052e,7a981f0,c21862a8,53b4f895,dc62482c,530ed738,5e5d1e33,cfb9d0f,e879992c) +,S(abae3945,8b12199e,6b0c8360,cfd28288,3f585917,e44e1200,f81bd356,f619291c,adb23bcd,b3d069c5,e83be30b,2469b068,b2a81b7,b667e934,233b75ef,b5753f28) +,S(4a9583a6,485b5a5a,81ac224a,518eb29d,1e0f658c,8d91b013,9419c809,55fbacaa,d8003c9e,e3c842f5,ede375a8,a7768db4,803ecf11,9b7b37de,cea15631,b4e8dbca) +,S(d52f630e,dba6f7cb,65fcf465,44ab0d9e,ea236ac1,460f17ae,3a210102,10ebc169,21155748,9fa93b88,3e5bea50,da005c53,68e21a0c,41bc83d9,145c13e1,370d26d0) +,S(bdc5237,82c75858,f5c50fc0,52e4c1e9,c74a2a63,35bca9bf,8d10e120,9add6a4d,abb1d9f8,74637668,e214efba,fbf529d3,12ff023b,c1d5723e,58540436,6834f189) +,S(44770a33,8bf0aab8,3bb64e47,6eb6167a,88156d16,8f13ce86,26ee0912,e59ad087,5b5930f1,2e9c40bc,b3393a89,5c2d6457,6a3abd23,b7291b99,c965c33d,ef60a55c) +,S(b15e7b32,2e404aee,319ac203,23e36672,6503108d,8ee8e1c8,3e32d924,515e1679,5246a819,bbfb291,5f82ed56,50796f50,5ced5c25,87347d57,a873ceaf,3d997e7a) +,S(a1ed7557,5225cd0,f2c50f75,8a1c1df9,665ae108,d5e04190,27bbd9ae,ddb00f22,3c83145d,ad9f8748,7b97e746,4850ed02,d71dbd04,93281a1,3d212776,6a791ee2) +,S(e8aaf361,6a1bc60f,d9bfc43c,2c60580f,479e9ec9,c23a37a2,3cf8afb3,1d918af5,6ce693b6,4a37c672,7e141041,ab9a0d58,9ab9c303,a5ac3d3e,c89b6f27,9e79827c) +,S(5dc6f8cd,2c855e63,52a4a4ef,6187a6d6,759c043,38a3db76,c5a3aa37,54c20a3,f602c342,8593a9a8,d671d1bc,7c1d8834,fe9f5f5,2e6a7f0f,bb870146,4e6f4838) +,S(63327311,67bed8af,68a063ef,22aa489c,f6563620,461af26a,5f1a07cb,6b42f3a6,b8f7c3b2,20701320,f20ca036,761d3e56,bf94a700,9a919f1a,3ea0cb81,b74424a6) +,S(8a40d925,9a393b38,2305c201,7e8654db,ad66e50a,d798a0d3,535230f9,48080263,afb6a74d,9849454e,dd7f703a,5c6616d1,43f9cbcc,9a9a5d6f,6a7b5d1f,9d9fcaff) +,S(e7147107,27c7420a,f517fd3f,9a05b7de,a6a02c8b,cc20b17d,cdfdeaf8,2078645a,da7d67cb,c1ede9d4,fedd5dcd,c96b04f9,a3561ba0,2581b055,eaa144eb,4217daca) +,S(6131291c,d95fb878,1e42a68,553952c2,9922bce8,91c026c0,cae1f69c,9661c82d,160e1c1c,13342fd4,59d4f989,8ae632b8,42b89479,13733b89,384fc104,2d30bf01) +,S(4bc4f845,b6764692,d0a9bfa8,1788809e,fc5e2aa9,da5003bf,b782bcf1,d1ca4951,87092dcb,b9c3d254,e3b055ff,3a76ec05,64c4a7c5,7fb1783c,efdc40fc,10b751f0) +,S(45a880a2,7bbee9df,29f9bff5,c985f364,52865b5d,582a201f,698e6eca,a2be67df,fe49a6a8,b5e46bf1,ef679714,dabd590e,a831d46b,8ee94eb6,13132ba3,7855fabb) +,S(6a826a38,317c0c86,64d6847a,220145d1,877e5495,b21500d3,f21f1a0d,4af4f2a4,4521954e,fcc98263,df2f14e0,e6e6b47a,f6b83f0b,bc20722c,15445f87,e05f4513) +,S(15356506,f255f7e9,6cc8aa1b,9dce572,8bd860de,7c6cc75f,613e8a34,366a23a9,cd15abbc,d744d485,d5e401f,1f89a5df,122f37b4,e362b4ce,e3e53b1c,110bf3) +,S(f3bc12ae,f53d9f5f,6b865178,2dac2ec,cacff3a5,cca6443a,2b5e1ca0,f2b89b91,cfd4d36b,eb2e11f2,41fd0f36,7a0737ad,303e915f,f247f131,368ca509,18e00957) +,S(7e3c8c6d,fa04a536,f7a26ef1,8b387649,22320bef,58453373,6f728297,335c0fd4,72ea16b5,32a7336d,3332400b,303c0236,b6a1294d,88ce7fe9,15571284,d1f7c189) +,S(198cbfcf,a0575fc2,c161c696,d85155fe,6943ab9b,d6e17223,d8844608,ad0369d8,d5e6268b,30952422,be59fe0e,fe7ba2e7,3215994,827a46c2,f2972b26,153cf7ae) +,S(1e056e89,b68cf35a,22183c08,9089b90d,5a147caa,780b1fd6,3aeb1350,afb0e5e8,b8241453,abc44c57,ddad6ff3,86d416f4,3e258a39,c6f8837,9f80472b,943f32b9) +,S(dc7ff974,8d827e7e,a6173b2f,1a646d47,d8108144,ce7f98fb,3fac729e,72faaa21,c1fdac5a,ef4c6f0f,fcb8e1c5,c4417c71,3e3d5f07,146daa1a,aaf2e7fe,e70c4914) +,S(71b95efc,c4981e07,5354bc1,1cdfbc48,36b2eff0,bf8f8ec2,9a99da1b,2fd28e79,fd5a3197,6fad6aee,c304752c,c3ebbc51,1f3695b0,9a737fa3,af42cc6,efd684cc) +,S(43854caf,29dc2bd6,c9f3e8ff,a25bba83,f6b96121,897044ae,6876883a,de542b3a,56365176,897632f,8dde3167,7a24f558,34c5c9a5,5c1cbf36,fd8b4480,3c9c6c81) +,S(2adfe17,90e9f9c,708c9b73,d5fd084,b6eff990,fb877961,45c2ecf2,d427b222,b5ce3160,5d6dd9c6,22cae425,ccd28912,c4439820,c06950cd,4c86d9b4,53abd7ed) +,S(a123452c,2b7eaf31,15b3a534,3b3ff31a,9f70c54,ae33c620,471e3e82,27a9d6f9,933d3483,78a71f44,3788194a,afc545e7,f53e37a6,f779f96e,8fa14ccd,ede3b4eb) +,S(9b89a3c2,ca995a81,86c15217,61348737,aab166ae,7decca60,3d06e32c,cec0a6ab,2a7d3701,a8724b12,bd7c4830,224ac083,cbea83d0,543b5414,80ba8c8a,e7731232) +,S(64dd7457,e7d9d739,8e2b9a0,dc45272b,384b0433,9ed8b2ed,c9079646,11e9e9b2,ea90f8aa,e214ee16,ed608a72,36699899,4e311dc7,780ef885,b29290c3,823c470e) +,S(59227431,be607c6b,d327fd71,4eb71c87,20abba42,1c7f550a,6b35767d,6fa2176c,cb7571c4,71c5527,65bd289e,a3cf3f38,796da2b1,2c953d0b,8705125c,4861d598) +,S(53d765cd,adb26e9e,1c80ddf1,99374363,843b7d08,a7237bdc,8c5106ef,795fe2c2,7bbbb198,eb39973b,76d87f81,94d45150,a66d4f3b,128a40be,c989a405,ad7c287b) +,S(e507de9e,c16b3bf3,523a989c,f5ff6c1,452ee90,9b66ffc1,6d7b519a,57bb66af,a2f2f02a,8272de6e,3dc8b395,8959ad2,51b6d3d0,4c81952,59a501e2,8ff7892a) +,S(16f48c6,eb84fb2,81903b8c,b9f60b7a,65601d76,e2a57983,5569c983,39b4a6f2,8613bb84,8398681d,66f1e75d,5b6ef44f,d827b629,f4956a4,41d8f503,dd32b289) +,S(650471ae,774265e3,270b5132,33d12d85,bb98e38,2a3b3af9,cab6339,e1446056,838e7793,34aa6fe6,cae90a62,d359c339,187b4032,15d97cda,4e62724a,a5a50306) +,S(15dea416,fa34584f,cc90e19d,69825fae,348d1ba1,fd7ac821,559aac2a,bc21dda8,1fcabf2,1e19ce68,ee12a3d2,84bd1304,10fa5f5,d45f9c15,d4070243,a8433047) +,S(b42b2495,4f1f70ed,3db90087,8357ba46,ee9d6a07,b4f7c751,dc5cba07,b05b46e2,e15723eb,e0bdbe6,d6f28d6d,a0443c63,4851f5b4,c551bec6,9f9196a0,969ed71) +,S(8e9e4f5,c6aeac31,1dab1125,dec9b460,6ab10b7e,8e250960,a17fc57f,c0230f83,ffb0e211,c79fbb79,78bd4e53,a05a267f,f1e32c34,d6287dee,64576d31,ab959ab2) +,S(87be7323,73bd4b73,8627fb63,bd4d50bf,d6f2bb81,f804b528,29549fe9,3fe1ac2e,f6a9186f,f147b9b5,ffc844b2,ec0e255a,1ae5537d,75624288,ce8421f8,7e94e1a4) +,S(43601d61,c8363874,85e9514a,b5c8924d,d2cfd466,af34ac95,2727e1,659d60f7,8791c000,7c09c94d,b328034b,88c5bbbc,11333536,6679eb09,9a5e75b5,83bc2c2a) +,S(341b1580,f83071c5,365f0bcb,ba66af96,6902e394,2a2560ac,a0daafa3,2ab49d0d,4b985b13,c5499026,7ff564d2,d4649c6f,7e8fdbe1,ba101d94,1c034e14,64877b20) +,S(175e7cb3,ce4a3a43,7c7181e2,c79fb154,33ac1aa8,e56492eb,57627171,f14dad95,31ce61a8,7834f52e,fcf8703f,93696f42,58130155,63ca5d9c,e92d8fc2,81135b0d) +,S(5ad430cc,64e61c61,e3b3c848,2ca3ecac,89c1e495,4c80ba98,249e45c1,307165ad,bea2a060,505c13bc,317ca083,c5a8b85c,9ead5f6e,1ac23fbe,ac7cecea,9251c791) +,S(41dce0d9,6dace318,988602df,7fa84c1,80f0ce3,dd7d09f2,8aefefa6,db8b837,74962c3f,ed9a6e9c,896635ea,855323b6,8850091,f84dee33,3cdff8d0,d2827928) +,S(a5ef4498,87104dda,103c1dc2,52067643,9aed2d5e,432fe5b,a23cc142,39961bcc,1cbcf83e,a363e0d9,3e6ecc32,8653ba7a,a165c526,765b09f0,696b0d61,f122db3a) +,S(4da26ece,9ad46003,38bdf68b,852a2cbe,18225f2e,2d6d5e62,6db57235,fb3a9d45,d10b5a63,7ab546bf,cc610e2d,1c3d61f4,61b0a806,e7ba29c7,3d3de909,e9fae659) +,S(6e621e6f,53d2408e,488d8eb1,6a19a4f7,e9d95585,11e69111,29dedc69,f98f4763,7b148ef2,73e1b131,341ad477,9342c7bc,7b945a2c,b52c448e,4bb5fd50,3cea1a19) +,S(ebaf5764,5bed7469,9b57ea75,8a395a90,66bae20a,8f082ab6,da4554d5,278be83b,5847f4e0,6c653033,5e29ea94,389ee3e6,d916314a,60126028,650ab9e0,bfcfbba7) +,S(c0f88a71,711b632d,24b55dbf,52b15d2,faa38ca1,1438c17a,6a6ff635,3310182f,2cbfad4d,16c07021,86611eec,408082fb,fb2e9898,141a5248,1c59e44e,cd0676ff) +,S(5d9b6c18,84b79498,c6244fbf,262922c6,dc1cddb7,3cf70ae0,1b5287b0,5b5c6350,328e831d,2f2b162c,4abe1644,bb54cc85,18db178c,5b6ae97e,5e85110c,7d7fdf1d) +,S(d1d1360f,37ed6e69,d4f214c6,323a53b7,e57d7595,55904016,654c49f0,4e02e21c,627eea93,c6c9b53f,94559414,40a8b100,6eba68d4,6c922b6a,1521f394,6dd15e4e) +,S(efc987cb,f1023af5,58acfa18,97b1b2b2,ace29a83,65674703,e4969ccb,ee411731,195a6a65,d3790bec,71642986,3bcef432,e38242fc,9f565dbb,e159bc42,f5740c69) +,S(f3026b97,163df3bd,61b88b78,73864480,968d1d7b,83ef6b01,31090faa,18284ff0,177c3a61,682363ab,bf281615,d59f06ff,5f87644c,84d670e9,a6c56ac1,b611509b) +,S(5d34ff5f,123b5b69,92ac92c6,8c9cff46,deeecf9,68ff830b,5622090d,682c5873,2d1a0b9c,8eaba065,43204df1,48eb1618,25443efa,80f8aff3,d49b6626,c5955ac8) +,S(cbf9ba17,94a95247,c39da065,84308cc8,e0ee591d,31a9b0bb,dac67280,468447f4,549b18c3,10feaea1,225fade,934112d3,4058101d,74f00538,1b82796a,d0461736) +,S(920975ba,9e2261b,bf5982a6,b57a7344,8e7747b8,368d7a53,79acacd4,c7dcd31f,e95e0508,81af550d,9221f5a,e9541031,6367d24b,d545bdcb,434e7638,acb46dbd) +,S(815b2ae4,6fdcb55d,926cdce8,2b4f25d0,39132312,3bc180ff,33fcf132,7eeca64,62f637c6,7d886374,8f1e2e26,865118b9,99285b87,55f25512,c968b4fe,49b8c971) +,S(1bb9a6c2,8e28d4ba,30ea8639,7a4d387e,27ca8025,da231926,de3c454,f7e0b16e,a0cbc016,5e32171c,8184265e,ac7e0147,206349d5,41035a94,f56efc49,dcd7ab93) +,S(6f0153fe,dffd83ea,b099d29d,dde278f1,9c05a4ba,78eb4c3d,34d337c6,da68bc22,a532d00d,35013f85,9f4041d3,aa231f2b,9fc49967,e0e2f82,4d5051f9,e7f0c626) +,S(3454f73b,3bee77a4,d00d384,71bf555a,ed23e5e6,c6dae855,2e9cb7a9,1b20258a,92c20846,cfdf1e8f,3fe5bcaa,6bdedc3,9926833a,3f40d28f,23a8f952,d8d18dde) +,S(367807c9,a3606b4e,1b8c2616,ad528030,1dfcf686,40eddf02,fc59317c,230e9a86,1f023f2f,a2bbece7,3dba14c,124095cb,fdc4f92f,281a14,8304a412,c16ecae6) +,S(8ec4fdc3,9891f6af,1374e06f,c44b815,1b82541,75fc4909,acba5941,201af62b,2dc6cae5,cac2d887,83dca0e5,3c798f8,fe067bcf,5fc29751,13756cf7,ef4e5f1b) +#endif +#if WINDOW_G > 10 +,S(5cc24a6d,4c5b24f9,14542f91,e5fa937f,ffa08551,51b8b842,8729b06a,9178a263,b1da8635,81531a1f,bfb38a4e,419fa1fe,ca8d55a8,3ddbcb98,da19d5cf,fb7da472) +,S(83905926,c03905c3,a9644a6c,da810dd2,92602a50,50c52a21,9134fc4d,e3599e9f,4293260f,e8af6792,a20b115e,aa837638,9094298b,21d9de16,cf20e0c5,7a46089a) +,S(944b097e,4721e9dd,f8204ac3,d3878fa,e8fa6c14,34ae4822,481b2985,6589b6c7,5fc47565,30e9b095,f8b79643,1e745b99,1525bd4c,4764e8e,e8af4b96,9bd6ddf6) +,S(ab0b4a3f,cfb7c134,e1caaf04,a63a7331,17327a1e,5fa90301,7b5ebbf,3423b73d,e1e79263,a5bbba8a,cd78c92c,faeccd3a,b84944d3,785c0781,3763bf1a,ce96c9da) +,S(57a344b5,220f2b0e,f7bf7fbf,5a2e4e7,1aa2c3d8,7bf090bc,f803dfee,fe8b85f,f82b7d0e,8ef9620,e48c9f13,53a72a95,a9e11a3c,1678cf10,576e639b,b1a7d04e) +,S(6e053e1a,800b7c4c,51f8c4c9,5cf0f4ff,3608e396,ec46188d,a1a9263f,c8d81ac5,86389e98,e3c823c9,e1b5384f,fce428c3,62e36579,7202fdba,dc3d8c49,395e7473) +,S(62d76406,1804717f,b30d4a7c,7567b545,48a289ec,7f083f1c,59deae25,ce485cb7,f1d6314b,661d1f8d,8531d57b,9470fb53,d1509b2d,a626a0fc,4cafc941,b668be84) +,S(e5db28f2,219fb2aa,830cf108,bd2449a,5c4d0800,82d34658,9e347f31,dd29250f,c296e646,32f97dd5,ba3b7012,ead44b6f,324fcfd2,f35f8b24,8e58fe68,888bd453) +,S(4725b3e9,a3d00de4,8a53177c,9fff831f,733ec89b,c2994ab2,3fe815f1,9b32729,ac3b7747,de38c00f,145fdb74,1482bb52,324127cd,2979ee12,d4a9e689,b9f8e778) +,S(d0d3afb6,492c72e7,394ed918,7013e347,b036b65e,a76e0569,bbe9e346,41d72b3e,2dd3a45b,94aafe07,53061caa,a28560,bd952b0b,2f63f13,96f42fb7,8e02fef3) +,S(7853e735,d717c857,97b85654,a24acff3,104143ed,cf4b4b4c,7869068f,c304632c,a873d9,e70fd14a,c2777a8f,b5a02922,bae3a31a,14938e69,cb535355,de1efadd) +,S(6db26b3,7d4fdc59,13a1a01a,14c92356,ee44e2c9,7f9d72ca,7789de33,8ee904a4,14fe2225,bf2ba0cc,28c1c409,e9849c4a,d8adf792,63869b68,54a28ae9,631941fb) +,S(b52f0869,bb98af3c,b2f7f5c,669fa43e,538e400f,63a9cce6,99aa2ef8,eb2848df,24566b24,55bc454a,e7b378cc,a0e57b6a,8b821c8c,a76fb858,bb616e17,8907be5a) +,S(8614dde1,1ee6af03,eb34a9e9,970fa7c3,234152c0,1384f7e4,c1e1f93a,197b448,2a1125a2,ac996870,2ba22b5a,d230c40e,4e5c7e55,d8ba6ba1,5e54d3cc,7b72f3cc) +,S(982a37ae,625f6e5b,78e71c18,f20bdd0,8b3308eb,59d0cab2,dbc20937,938c1cfa,671fe16f,a65128,591249e2,b5070bf,2a689e2b,dd6c57dc,18e5309a,b6a40d0c) +,S(6bea9305,26b4829c,ec99742f,c9231c00,627a09af,22ca9d9b,4081a2fd,4c3e703a,aec5402a,54517b4c,1f344d14,b1943e69,d7541f10,c45bd483,2b02b059,499a6cc1) +,S(b5724781,8694487e,7cc188b3,36d116b0,54016a99,20731920,ba7bd29,96583edb,5cbbd186,1f80a4bd,3d58262d,ebc58ffd,1d278fb3,b4d7fec6,208f6286,77845cdc) +,S(de1ade62,7ba00e91,786f4f53,18ac5392,4df5a534,704edbb6,2e0e9e2d,997c5412,7ef486c5,bf23bfb,fc6dc15a,41c0673f,a9d003e6,e1d09a8e,4bffee9d,ae2021e0) +,S(3738a57c,b1721c41,9f9e465d,fb80e1d7,33720398,bc01166d,d476d36f,3398c0a0,e1f25bb2,1662b16d,6d28a629,ad84385a,43df566c,52924bfd,11854a78,b70c22f5) +,S(4cae21c1,6b2a1239,a85575f1,2ddf6daa,1955feb8,b7502e37,6940006e,7a81885d,2affe855,388660d8,27671e89,c82832b2,25fa2c9b,29d559e2,37af565c,b4dc99c3) +,S(4c511a1f,ba8a0be3,6e37cf55,85bcc3a7,97bfa7ee,1baa6039,5732faf8,dcc2bd7b,ea69f794,5c6babff,23400fd4,a95d6833,abb27269,887c372d,8a6a45ca,b25651af) +,S(d811d8c4,323b4370,2607c25a,de936c0a,c2e4a44b,2ba51f83,20c5179e,745a7e29,6ff970a2,17bf47f8,da0aeab,cb490e3b,46c6df3f,69f9e93c,3c4dd94a,e7c05345) +,S(101eb5d3,b5e5aaff,e39bbafd,f13b5ffa,33db68ae,1fb09b0b,1cae25e6,16c43eee,9d6a5514,9867725a,607a1c96,eb03120c,a4970939,34e0cf4a,1631a63a,bac5ddb3) +,S(89eb1152,b8dde45f,e141f21f,62fead1,ecdc7f70,eff8f968,de21cf8b,72480519,f8a337c4,3181e3d5,69ec99d7,f2bc4770,cb6703a8,63fbd95b,41fdb07c,b697b447) +,S(53d633f3,f48ea44d,273d8f1e,455019a9,49d95eeb,68de70cd,bd1e964d,9ad0dc16,1b26ed76,964dcf1b,3f7fe6f3,2e6db7e6,8e8ff4ee,48fe63af,48ffd33b,cd1645fe) +,S(de106910,49891106,59a94d26,b9cedb64,6ce3db4b,8398ad1a,92f8f95f,d8d9be6a,87640b41,dbd99d16,578a3d06,d23d4088,8768a4e6,dcf83e7b,5b9d9133,5eb43d32) +,S(40ed1e6f,b9ee245,ac189a9a,7809da10,cc6daa7b,41a163ca,f761773c,6af5bea2,ffed1501,7298fb9a,78eb7bdf,1430ac04,82bae82e,a7197adb,50bcc1e1,fc217b2e) +,S(55faaaee,59a20b9a,3784d171,9ea529cc,1b7ab3a3,29f26dfa,a3b11bd6,67ba15c1,a9f8939b,52ac53e3,5ed4771d,8e47065c,d7f2805,a7e5475c,37353ddf,182f4a65) +,S(b51de64e,21cf88af,2180ca17,24956d10,a95ac607,f034fccb,a53bd02b,fa8af3fb,175d9b70,1c652ebf,46b99f1f,6e66c4a6,9b840019,a48b1ac4,878b386c,3b7f81e) +,S(5156b0dc,bcd91e82,4bb235be,9367cf40,7b8927e8,cd874171,556f997b,7b07b143,1d457c0f,a29d4c3f,e65ded19,1127016d,d40ada90,cbb0d8de,c2af4bf8,20cc91dc) +,S(3bf51d72,60b4973,161fac55,88e441a7,f1993c06,791b6bcd,e11d8e,96dd63d,7bc6b470,90a7afdb,fc63905d,df698499,73e1e4e2,af74f126,63eae8a4,f4722d49) +,S(d2971091,20088102,1154f4d3,ba6f2da1,22fa74c6,4faae05a,d76db7b0,9ad61fe5,7350ebaa,f2ccf3c8,f940cc14,151c23c2,bc33cb73,65528156,92648f6b,628e3fc8) +,S(c2ee47ca,8e17112f,a255a520,21ffd30b,6d7a3b7e,2341526c,559b60a9,c768013d,2e6e8b6b,d83b7f5b,1dc8e83b,edb3b23a,80d9ff08,2029831a,45305016,2bece448) +,S(559998d6,9ddcce0d,9e0da39e,96cc4c00,c5ef444b,561dbaaa,e475adbd,3e70b6cf,c49c2a00,95aeee5b,8deb5e8c,db4d21e4,cf0f3173,1af2fac5,25c534c2,34ffb328) +,S(4b4b02c3,e4c8badd,e45305c3,9721a98d,7c1955dd,90dcb2f9,e9d54901,6bbaf363,a0b67b7e,be8f59b3,c25d546e,3dc304d,d22a6a64,615bcfb9,25b685e3,18d43468) +,S(fbafe7fd,7836b427,51cf897c,5d42897c,7650ade8,ee1ed01f,e0d7dd2c,aac549c5,2f511943,52d07e51,7b7841f5,8eda5225,229a7e28,9a453aeb,5e70110e,12668436) +,S(ccd306f9,c65b8a0,7884e620,b73ac4e6,81b21bd0,2a4b219f,954de1b6,7076c06c,823fa47f,a7b0b50c,907056dc,73e04574,3f68a7,5a4c8566,8ab5f5b1,5657510b) +,S(bafbd838,995a691d,3b5a870a,7847452d,9124155d,d89a9980,820b8d56,18195a3b,8df4c9fa,c94829ee,fb0e7f52,1020b5b0,4f05f4d5,839c8687,4e893e7d,8ad92a3) +,S(d125cc3a,8073156e,a166af8,ff940a64,713d8f37,b86919fb,157cc380,224f458f,a030e8b6,ac4e37a7,df01054a,ea23a78e,1bb7a22e,f26052a3,a034ecbc,bc35abde) +,S(7d491f28,1b5ddaba,ef2c6433,be22e42d,f2d1bbfd,8a7e8866,8cbf278e,cb8187c2,ca18161d,70360966,ca381ea3,f760b2fe,28b040c7,ebc82af9,bea27ba6,f4dfe8ed) +,S(31ccda33,9f29123a,86c2995c,6a9f4979,6d70a595,5079b961,6015f07b,cdf8c39e,aeb27d0b,edf61fac,99528a9f,f060d1f2,376626b0,bc807a19,561c2e4f,e8b49f65) +,S(79e64c7,f45f9189,6c92073e,71b76fb1,e5ec912f,de11ba7,d7439f4a,297807ba,57d93436,b354963c,5891abe3,825d89b4,d17685bc,c9632e7e,fe85ded7,5823c921) +,S(d6232edf,fccb3868,71ef057b,60bda43f,69f422d2,debce06c,78a31f6a,8c42274e,13daefa0,b2e2e09d,36f472f2,29b5f7d1,58a18f63,ac3dc4d6,d62cc7d7,ec0ef826) +,S(21c0f298,b2d6e3a5,3738fc00,c8289458,722d78d2,48a33ea6,a7ebb667,446e368e,867553ec,17d2fd95,b895eede,15da569e,cbb3f25a,e5f334a2,b20660df,df062383) +,S(1d1a3d01,dcbf799,d551621c,54f74720,eaa2311c,3fd9b1d0,f4f2caee,4c3196c8,d5a7a115,9900f90c,879b1a30,13945d8c,5453bf1c,7e5e33d,6f8faeae,439734eb) +,S(57488680,8fa99ede,ca97d1,8582a151,62e26d5c,7753a561,4f4bb1dc,28e76735,debda859,7117ede0,dcc0ecc5,4ec1a494,b3bbee34,95db2b1e,ebaa1db9,2fc17c6f) +,S(b6dd34d3,4ce1dffa,4e1e820c,4c8bde9f,607194d3,1c1ce07c,9f6fadc8,9791715a,8bf48868,e405d533,2adc0ec9,49bc7cf,1487e554,3a043200,71786521,8a39cc9d) +,S(90f9ded5,69088772,ca2bc887,1522df9b,5821df6c,9e20b160,f3504bd,4a91d0de,d17e64a,dd534a6e,fdd0af26,b4494339,f76b3c1b,126397f9,a2beba76,eaf902ac) +,S(c55f34e8,58d19353,9106e4a0,c3002873,db07b239,9b10299d,260acc65,6b2cfa59,7d9f38d4,74b5a22e,72949f7f,e2cefb34,9a8fe1fb,c16b8dda,11f162de,30e50f5b) +,S(6ae44192,d38981c5,9b3f8452,c4a2b627,f39c16d2,b6f52575,c5f1722,56b8ecad,9bbba8dd,7c49204a,9edc4b91,e38e4973,fa61de1c,eda6ad61,603d9715,7f0b099d) +,S(33a7d639,423e1b36,6a93ad99,eab6444c,bd0c251f,6cd8b79a,e0344eef,6fdcffbc,c26112cc,6dca2a,fa52684f,c9ed22d3,2f067891,d5bac2c0,2bb86e3b,9411c61e) +,S(48471331,eac48670,28fa6642,a76ca6c5,3380c1d9,f52a4b2,ea640d47,f159af0a,b4ea8546,93fde01c,fb903a31,18bb61f5,c5047b94,705a714d,5b586d47,a0142704) +,S(565ac39,9ae731c0,4cffaab7,43d24b71,72defd79,beb8ce86,d46012a5,c2587917,deb56aa5,d45031ea,fc411fec,e09a9646,14664989,fd4f40d7,79c02981,98bbab48) +,S(964838b5,3b6c2b7d,6a8d017d,c5a32fc,99549094,6dcbf773,eaa7085c,98314c0b,2daf9f3c,ec44034f,c8a71ee0,ee76bd77,ac6fdc9e,fa042a2f,6caf9c5e,fd130b97) +,S(bc00da90,7b8d078b,9d83522d,ae548b14,6f9bff0d,2ef887c,4aae2f1e,c4eb88d5,6bd0fd11,f9e2db73,65f21dd1,34cb29f6,fef4d7f,b419abef,eafe15a4,20ddb152) +,S(1a59f855,f89f0c,f13dd8ae,9f5e550c,a2082bb3,27fb111d,75455ab,dba7bea4,7ea2fb40,d460adff,c9e25c53,a65c508,e77e6e76,e2e435c2,150c870a,7600c823) +,S(7a3b611b,d3bffc6a,d4508162,45695024,452706a3,279a6fda,d88598a5,4eccc764,16e09589,68066e52,c873d6ef,e549d3aa,83d30bd6,a1d730d3,68aa1ad2,32233145) +,S(2fed5577,9cbe0a5a,786fa95b,5c56e27a,a0a1cc28,51112bef,4cd5e1b7,15d6d91,7eeacc27,b2297fb5,63d691fa,36dc650a,f66fd3e6,6fe5e637,9959d46e,2d4bddfa) +,S(267ad217,952edf65,673efaea,6bebb44b,18326dd,f1b36d02,f0154a0d,774a9558,77593cc0,7e9d5e5e,688a7b33,bf54a01,703cc9b7,a0485e6d,907515bb,11a13fef) +,S(eb6ed62c,239b99c8,6978ccec,a5f32145,e0d341b,ca7eab10,6fa05ee1,7f6687e8,ad899e22,50f6a8e8,ce29b225,83ad8755,2a6e6ab8,9061d33b,6629fbfc,52c0a241) +,S(ca5cf17c,e03d214f,b4ef33c,41686c4f,5087a59b,f88ca7b1,891094d,430a9e5b,17e44eeb,473f75ba,cffae683,c8ea0299,e1935180,7257803e,f9963ad3,d0989ce9) +,S(4c7bc29c,acf0642e,63f035ec,a93e6b6c,c82f21cf,46623a2f,e4c7215e,51e82f7c,7c55e76e,8756796c,143f64e7,e40a402b,eb537be4,f1f5322,e59d2be2,82776875) +,S(57cab8e9,b42289f0,503e5013,acf4dd7,79783184,2389fd20,80b61bc3,671058e3,78225318,6671273d,a7b0b884,e72e9bee,2b048c45,9430d2ca,7c398aaa,9fd9e2bc) +,S(3c2bf23d,f1120c34,de813a82,a56843f5,abf3d272,ed2e6c27,53ff6310,9bc4823e,1759db63,88aed233,ce0c5b47,ec9dcb88,76740928,e12fe9d0,d08eb759,2d3f1990) +,S(c010a9ac,83e0742a,d3348dc,3dcfddd2,34170aa2,28d36856,d8581b1a,eab38d2,634c97ed,644a68f,e1f1da1f,190cf920,2b2dc810,446b78ea,9cd27684,3c76aafd) +,S(a4abd9ee,548ba468,e4cb632,b3d9c8a9,4f1b773f,ba3a9660,5504593a,92071994,3a14266a,ba263297,fc6ab00a,8403565d,c9390b48,ebffcb61,11b5e8ef,c8f87182) +,S(dc02c852,efc115f1,c5c08540,deceffe5,d68b82e5,99b78711,5a7a333d,e8dda172,e4e6593a,8e1ae842,ca7f4eae,d8cccaa2,8a35f8dc,cb8549ba,2367faf5,5f6c29c6) +,S(ee4769e8,223822ff,c28a5a4b,5f29fd7c,a54fc81,72175cac,1b6db5a2,91ec57c8,fca2c6bc,4076c8eb,a0978b9a,2b0158c4,33890514,28094619,38413fe6,c020385f) +,S(f3006c1d,34910c0f,d435a6de,cf088c38,2cf990cf,3124f2ab,b11d2727,d93ef066,7629f5,aa367f51,a29ebaf1,235cf267,f8016a6c,88dfcd9b,82d36904,c949eae2) +,S(7cfb203d,7bf5669,129f0a3e,325c3fd6,b1b9c804,4932f0f3,794b9357,1e7313b7,4f76b9fd,24339c38,c88c4217,387b016d,e4ae08fe,67182d39,82a45bb4,e82bc60f) +,S(cca3ce0,36e00993,9d30be8,e70455ad,efeabe71,83aeb206,a324d0eb,32312c0a,9674ae58,fe947c6d,34c63725,2058c88c,91b437dd,98da58b2,efd7e8d,1615b9e5) +,S(9fb64148,81cd5c27,82da071c,1f98d71,d9815fd2,2389d212,c66ace66,ab0d9c8,4c25454,1a513742,5f75e515,c04f1c73,d11d5047,9c76b09b,ce23c13e,d1813251) +,S(1dbbebf,3e3d459,10d39de2,32560b4d,eb5d2ad8,6aa1542,c2c070b6,51558b25,ec68e71c,2e94e490,4194753f,d7484ca1,940eae51,69831876,877b9ce7,2d0b9db1) +,S(7751d219,92f47421,7742856b,4c84d41,5a890ee9,24185e21,5a210a3f,a46bb5f7,2915a9c5,b770c86c,edd32749,3f698c17,6371f6a1,4cac5a22,73a3c648,1b237fef) +,S(39a849a0,5b189c3e,20782983,ecf664b1,e7b89c96,4e11d737,70797fca,ecf36a2d,d3e6f8f1,6191db06,be2274d1,56685895,48e69253,54f41114,f43b5ed1,13690c5) +,S(67e56125,b29ced20,f9f95522,d412d67c,80e3d628,b8bfddea,768117cb,e79b25bb,608dfc15,7e3c23f4,4aa0fd88,3d02d293,3c83edcf,66ea57f,9167b712,8d03da21) +,S(a51aeda,2f7d59d,d31eec20,e95839f6,ecdd01ef,529327bb,5cb229b7,b78f1525,704967df,93fb862b,3d38b18f,4c6818ab,6621c7d0,80d92cdd,1f0092c0,d7847903) +,S(c980693e,73a1cb46,f5eb71b7,73b00389,f8bcb36f,fb489e7a,aae64c23,6ac1745d,bf3b808e,fe6b7efb,771853e5,6fbba6e8,b3b21fef,706bd4,274cc058,b6fae474) +,S(c78df930,bcf54c1c,28e27aab,2975e9f3,94167bd2,948d4713,6b17a374,a1391a9,9a424f36,6d3a79be,55bb5e9a,283be1e0,163bfe22,1bc65e5e,318f0de,304d9ae7) +,S(9a75f7bc,c6d2f3a9,e6168ebc,8f7f1e50,a998b1e4,e67316e5,fb242fc4,6d284089,cb478e6,dff8b9aa,3ad06c6e,8fc7e35a,39bf6ec3,787977bf,d40f3159,bf169e01) +,S(76b2131a,db0bb3e7,db48277d,95ce73e4,7eba1e7c,b6f801c0,d20b71a3,8b6e6224,32e3cda,ef60e55b,a9e36e6,cd287737,196c5af8,120c47b2,f79d2492,9979263a) +,S(21898361,4ec5971d,f55f96c9,3da89483,cdcc4c46,deb8de68,f32a42b3,5c1384e1,2c396c50,44a4953a,b22a2d22,47769741,c5eda54a,d9c9ac97,d6486b5f,126dac3e) +,S(ac0b0a49,4e9d180d,101dbe1c,a528fecb,a08449a6,cf5d82a9,aa14f875,e3db8adc,26d1d412,25a1b583,2dd53b9c,56a6a8e8,371dd19f,31462dd9,b2aefe3e,70412554) +,S(f869b58c,851a65f,bd6d3329,75f596a2,9d1a78cd,bbf04a1b,6dca6c27,30e04625,40dee344,fc6f5c72,c18b1603,e149949c,a0cfb31b,b8b91b09,c3cbabb0,c6a5bff0) +,S(f74f02db,2406250f,8984a5f2,273c63ed,a640a43a,8e7d72aa,ecf78d6e,b9544c3a,882e3a6d,cacc1e92,8a3c1a61,85f2bcf1,5e364f7a,1eeeaaea,1c0af593,cf86185b) +,S(c0613eb6,1d6755eb,2ebc9284,a0aa69d2,88c39050,4b7e869f,f3d943aa,67ea65d,72f61ae5,27b5c82e,4afa8966,55d9289d,29931c1b,f0d36c09,fe4213c5,27848cba) +,S(eb66ff98,60ba08a6,3c0fd8c4,7117aeb0,ae0dbf63,524307a7,eb739f08,f31285db,c3142ca,54bcf2ae,8b05dfb9,4e40f4ba,7d3662f3,774e616,55c7515a,87ddc5d5) +,S(3a7108e6,a1256061,fc25d58b,ca534602,e41c6b15,156c15b8,71a516f0,ec4a861d,daae2d02,41cabb2,191b5be,c17e7e88,957bfcd7,66df1226,a183064e,3c4393a6) +,S(d17e3a58,c83169d1,33ee7371,7b205f2c,ea1a2ff3,4e744958,949e9403,b8f89d5f,98c35f7d,69e5d98b,920ffafa,6d15d349,2d75fcb9,81ca5022,5ac7ff32,618b1a20) +,S(d6e32892,cefbb8ed,14350cbf,2618e2fe,98caf6d4,f7679385,fff36bab,bf6541c,7175462e,be0f5ec0,7872b55,356f2498,976196bc,edbe021e,8081ebd,b2636298) +,S(318d49ff,60e900ae,6e8e2182,f38ec006,82ddc8ae,93aa6291,86d5ddf8,affef75,6e97ec27,dd7d614d,c1ed4fd8,fdf6aa70,8dcc3eb,be288831,a9888166,66333b2) +,S(fd6f9e30,1772db8b,a68ea5ae,b585abbd,c075e72b,68d6f67c,5a2f8144,98cf6346,dadd16e7,64775bd5,ca5c5f51,35843556,d7608230,aaff4125,4d4eab38,1d28d2c0) +,S(8fe25b38,a2c74761,a90ed08d,4bce768c,f074282a,e9560d31,566ae43a,182ddd36,6ee1e84a,77c6ab78,a2cda1b3,2fbdfe2e,51d66843,271d15c7,3f8e1a82,1e4c23a2) +,S(37cf0ed2,88ed8fef,4ae17bcf,f6bfb815,3e12bab2,a46d7e5d,2e6feb99,9793bef8,92e7a57,18eb0751,c99254f4,ddb5c278,e17a417b,21793339,119a146d,bbe3e0d3) +,S(688c2061,6b9d0c8,76deb812,b60000e8,eca0e04f,531ed1e0,9158442,7bf403c,bab4b2ba,41ba4d53,df512e76,32200bdc,11d8583,f2ceb5bd,a8b7eb14,5ccc01fe) +,S(4b4caaaa,f5399535,d822371d,63965216,d1b53584,d89a84e9,d868395a,70b3d804,3ddd27af,cd18049a,3b01d043,7761e4ea,652fbd91,115c470a,e4c7bd40,51ee73d2) +,S(6f5acbc4,4135da60,758ed9a5,18b39b5f,47cca398,24e20e56,1444dd52,e2fa1d2e,5dc9d46,e5f6d94d,48af2efc,2f197a2,f729f1d7,335fa569,524d37c,4acd58c4) +,S(79d2d449,3dffcb91,6fda527b,f8b6b622,661d6f23,738288c6,ce94313d,c267fc42,b2683bf1,3fa8f7fc,be302823,dfbc9153,8d902791,d5d6dde1,d2805f37,a0c08db) +,S(33a8e87e,246b7b9c,9c77a6b0,7cc67d41,f3915dbc,2180118,c0800b33,f9f95524,baa8244c,584fd05f,2655e36b,e2e5c459,207d30ef,dcdb2294,70b34333,9d16ff8f) +,S(9a169132,f3887df8,20561a7a,e4bd5461,3235ddb2,fba7a19,3f4daaba,79868e95,686fc317,995446c4,42945216,1a96595a,a233b100,e5f8bbc0,71990229,44630bcd) +,S(790b74f4,8405ce3f,9abdc7e9,439f2f5,c859989e,2ca5e6fc,29046104,8783ac42,8961c913,562385ca,990593a3,77111a5d,1dc6762b,b1a928a6,6ebb304b,8a24a701) +,S(e2a3d0cf,ae1fc2d9,87caaeb6,9f32fcd6,95471785,f524e438,b5487aa3,72f9e49c,9cc24205,ecf2708c,357edb54,308ce452,11f7dc03,98fb48db,4982d337,14c93046) +,S(cb30c43,5992c195,76d372b1,96f2ae68,cfd2653e,63e3ba7a,2b3c21ec,960bcbea,f65735b9,708338c9,acc9cba1,4b491b8a,fb683058,266a483d,4987cdd3,89ccd0b4) +,S(1faedc95,d6310bee,6298ffb1,6fb3e6a3,296ca66b,7c995d2d,fe924381,10e8b46a,35039e3f,8201e904,e5378d03,2bd8b766,26d9f0ce,4425d2ce,e7bbd24f,b8725089) +,S(a646cf5a,2be8c1d1,3f05410c,ed51b3f5,8e93ea53,1e28bf31,8f6c750b,52b3e8f9,58c58ecb,7727a920,b47a7e78,e1e51d11,e427d7e4,465429bd,a01f4650,a4c102bb) +,S(32734727,18537d38,e9b8c397,a5cc322d,1c77c0c6,15eded39,dcebc020,debe2205,c2debc89,58c3f60b,d4c7b072,d475a7d5,c1ea784b,c3e532bb,72c02490,9a42d65) +,S(16a1a718,855a212,c068c095,d930a270,9906dd22,e7db3f4d,4ce2f393,d572827e,d389d64b,b30ba9eb,6ce80335,cbe8f7dd,b1ef3016,a8b74660,2196b724,d115605c) +,S(b4bf4d14,5de25571,33694b86,76166e90,eeb1ebf8,4a7402e9,a61af4cf,23687596,49db20a4,d82397e5,6318640a,6b605e96,37d38961,a58ae3db,fac2fc11,bbd11242) +,S(d4ed67a9,ccf4665e,418a0de0,8d9380cb,fc311413,e90a964b,bf367b9b,b892630,8ff7e57c,e79a0883,1fe8a972,92493764,7472b77,61b055fa,37105d18,b51df131) +,S(8ad256f1,9f413ef2,eae906f,c1c2ca4,44d5dfdc,f916d366,b32f1f47,f54fe70d,bdeeeb41,8d2c4dc5,82547f65,91c97219,34778f5e,d25eff4,94e243ed,a6d34da7) +,S(8dd3e2fa,fe55b5f1,f13723e0,1a5587b9,c67d22ee,21f1f62f,7f62a15,31f17f8e,aa23d2a4,7d6b717e,55d7c6b6,5d9c46c6,8f2db41c,ba66960b,4b4bf93f,5fc88cb0) +,S(44fd9e28,2a8e30af,ac34db01,a7b0e939,3c13917,554d9a67,8e577a5d,4b3d0f6,cb079061,353319b3,a1669d59,295bdbe2,18927d06,ccb1290e,4840cc16,911a61d0) +,S(5d249a02,4464ed65,831d2aa9,c9645f46,2db7c9f4,e5a46477,746b1a71,88b7aa42,2bff7386,527d6b5c,2c595f80,e08b4d20,23bb8dfb,f294da12,b54f8b14,77281d0) +,S(d98eb458,1edcd51d,465e123c,d891c481,ddd18b54,b9408ca,85ac47c8,e10fb23,15bfd3be,d3756ac6,f2f1f9e6,f254c9b,2b153717,1b265081,6a2cc21b,78b4dcf2) +,S(2f12c369,19a2aeb6,2132134d,2e85150f,6edb486e,9d672eb5,876804d6,44db6082,c0111edd,3b4d28c4,edd264b8,dc2bd0e3,20834dc7,bda82dd0,827133c5,7f8cf73b) +,S(4d949684,7099c9f8,421d35df,ebce57aa,71326034,8f07e3e6,f03017c3,144b4624,9afb5a57,d71369c7,28db308f,b8b07da0,b91f954d,b182eadb,126b1fff,ddb673da) +,S(cf1db910,5e95f1c8,e360b39a,752ab17e,fca8f24,d9ddc8b2,a9768700,e2af2466,e7c99f66,c49c8674,a6c1b94b,4b964019,5e645ca7,b3d2e004,ad8dc73,f647ca5f) +,S(e71eb425,7d2ffa8a,b79d63a2,42c67585,d4b1747f,5b27f22,a9ee4284,6aa62b85,a906aeec,f901a376,7d721f45,da53e342,3bc0a779,870e33c3,d10f6426,6a2c8865) +,S(bcd987d3,b2575f4,3bc5c3e1,b4a299bf,21c58b6c,a27ebb21,8f9882ab,30559887,403804c9,4339ae27,2bafd894,e63a4eb4,690c1b4c,9289db00,761e9b3a,1d483f65) +,S(b74d5cf7,48af7162,395d2d5e,8a69f740,7a2bebba,69564042,ea9c7e34,b1f8cab0,b5c5fddb,332bfb59,835e9a23,4afa4543,5728dfaa,7dcfca3e,a3c57deb,e849b336) +,S(46f3def5,9835c9ae,1a7b3b13,a920bea9,e9bc12ee,633b3edc,57251b72,3560837d,587b2e1f,2e8eb9cb,37aa6977,870214ec,818fb71c,1035eeca,91d53e68,150ce67b) +,S(8d3418fd,eb3f0968,de51f4d7,cbb60299,a50ceba4,1915d8b6,5774cfb7,7667d572,cee79910,16a28462,aa9da7c0,f67b4c7,e8b3dd38,f4b2203,9d05115a,ac661db8) +,S(98cb0f09,4510695d,78a0a672,eb67253a,30f4327b,7864fbcf,529cf212,ad6f7c10,25952dac,4e1b5035,9b47e9b5,52852d1f,300fde75,a6bd532f,9fd56af,2a0ab333) +,S(96045e4c,ca075fc,4a5383f3,f03de105,a34c7c4c,b030ceff,b58b98e1,2b39a3cf,f527b8fd,92234151,ba11f24f,7bd5dfed,6ebd03e3,a5048c6e,8f2d5231,7201bafe) +,S(f262e891,42addef8,cba26a9c,ad779761,c3f4b3e5,5990a93e,703bf56a,99cc6030,275cc764,86c86a90,f597dd6,7092ecff,5382c7b7,33939ca1,d1f3218d,6f0b594b) +,S(cd79c02,ee175336,5f9f7900,be51bb2b,ad75ef81,3c6c5634,7cc717db,156d17fe,b5ebe8ff,b30de5bd,a5326044,16abbae1,4ff9198e,b491794a,c4500031,947a985d) +,S(28b4bf22,5b1d40dd,e0122e03,e630830a,d9ba4629,cc51c9d2,80a225f9,48f858f4,24756189,98bb414d,4a534c6b,e300297b,aadf4ffc,b10e6795,4ea36e25,2cf3cac0) +,S(f018f206,7dd55df3,9c53344b,c6128a5f,cc765c36,c7b0bea0,16c8465c,c6ed2ff7,d9fc5ab2,cd619d4a,c66c1cd2,251504cc,cda34a76,86c5661a,960a00f8,e4aa7e66) +,S(496968cf,8086d02,9a5dd5c7,4f47cbda,7f661ef1,488b3942,18ed886c,424a7a13,d7d8df98,442060e0,f17a363,579c6600,360b5124,2774e2df,c8d4b787,1e1874e7) +,S(242d4c59,e9113b77,68e48574,93600da7,b984355c,a1d07949,8921016b,22efedab,470dcfd7,b0c8c2ed,63a28074,a505573b,42f50920,6b0ae577,27a8b796,7a0f42b1) +,S(b6b804cc,1a1a59d3,84c4afac,c5e5050f,466280bc,d5ab1586,1d20f4dd,1385e8c7,2f789346,2a636a9,9ba2a1d2,32829f41,39b57967,bb26d0c,898798bb,6521d439) +,S(dc30a3d0,7ecc5fdd,38b8048a,f281024b,46904b2d,2a4c51ca,d1b49b7,1d918a4e,326409b0,70550e97,58f53698,7936a54a,b701f7b6,78a7d10f,ebb511a6,c18cc917) +,S(e1fe434d,345bf330,83abb628,f4f44ac,5fb22934,977813c2,c015f2b,43d3fab8,1b251ca5,2af897ac,4c08df48,ce3d1607,d3b31b2c,2dcd7f7a,59a95b07,774c4d83) +,S(a8ed88da,e08ac5e2,afbe4a40,ee775645,82c2f513,cfd72060,bd1fd5d1,76fb8d08,f4fb60b0,74419630,fbaf5b53,717b2a6f,5cc2d98f,1d29481b,77b1f9f3,84175729) +,S(b52cf828,de1e9cd7,c95c083e,ec50d228,8e770713,a0e2543f,76fa5790,2c7c6481,635a3953,46fbbf,903dc729,d3e3b52b,43eebdc5,3748ed83,3c95eaf7,1b75790f) +,S(702079ae,f76d9bfd,ccb957a9,4aad93fc,b1297c54,d634978e,4dc78292,161d5e83,4983c08b,f2d81c52,d3b3a202,e0c6ddb9,32a43a45,c4b95f82,c8c10642,5a783b52) +,S(4638d4d1,8e9de1ce,ef4fe8cb,db4378e2,3ed3dcb9,513cc9a0,dd73ee2e,be57bbf5,561ee032,45cc3066,968853f7,51fa36be,cb50740,a5951e87,cf77ef20,cb27e110) +,S(eeb34eb7,5facadde,d561dc5e,e3d0a039,d98e4880,910439cb,ecfb22d9,3b386bfc,f2b23cff,5ebdc8c,558db8c,1c311a94,e9d8f63a,d1cf4af4,c21c2349,a6e57c4c) +,S(7f2c6e5,becf3213,c1d07df0,cfbe8e39,f70a8c64,3df7575e,5c56859e,c52c45ca,950499c0,19719dae,fda0424,8d851e52,cf9d66ee,b211d89a,77be40de,22b6c89d) +,S(6ec76722,1ec5d27c,f7e11064,d4f8b016,3cea090f,6a950f81,85623303,23e53647,9b03c757,9704e839,c8eec7d0,f063c4fd,d0aa7ba0,5ad75254,984b1703,ae69a3d6) +,S(98f6f69d,320d5eca,1f184b0,378f67cd,b44a707a,c5b2af54,99e9f8a4,524dea7e,26ef6b3d,7b037663,979333fe,56bc33a,ca54a3dd,78c9244d,79ef5426,f2b69a02) +,S(cf1ef445,58b82c76,5d77ac99,8c0170c9,2d308668,2d9ed7af,2961cf05,5b47e390,8bcc1d05,fb880ec7,8762d8f3,f5afefe8,f4345bd8,36397d23,befdf446,498511c3) +,S(10e01651,efa26f2e,f88cc5c1,594f378,9ab62b82,5a0875aa,37c280a1,8c6f07e8,2e6a15e1,1f776335,30fb2cdb,788aaa98,83105da3,7e28c0a,8fad503e,b9779df2) +,S(b94e2fe0,41ce209b,6efd77d7,44983130,af90945,120b9a58,5427966,e93eee4a,8f7abf1,103e92f5,5dcb1dde,746df10d,a86bfb8d,2776a0f0,1d07142d,c9bca443) +,S(cf9e7d02,c671a9ea,145d233e,244d8af6,6d71cc34,e17f2ccc,1225d2b3,16d41154,82eeb8a1,f0b966f,bbc3858a,3878f969,a853e2bb,e1b60c4e,e13eff85,d2d2ca7) +,S(da3a3c29,94ad3b91,319d18eb,dcf4b934,df8e4f2b,e052f436,6d539aff,4bd48bb2,28f9d653,c4042478,831ccfe7,bec86663,5e0d32ed,f6db4f54,25669a91,d1dc0193) +,S(ab812818,2b80378b,d914c9fc,d2831f30,a0a095c9,d0e52450,d4ba27b0,f1eec101,5abc582,274876d6,3dce366a,fbb1d80a,2286dc2a,dc0c078f,1424d45e,26666b3) +,S(ea5b82a2,bf02caa5,d5d64391,c0965c53,f0edd967,f8df94ab,831408f7,e5c4977a,81fe8299,f320837,acddd504,7b888e6,2518d53e,897dacac,5d28bce8,ff3d9339) +,S(50605c0b,ab201d7d,3dd618b,e3da2d29,318aeac1,7df58d2c,a95b8fbc,fbe70fa2,e50b1e,7b5693,c4ecc160,d928cd6e,d4c978fc,6c2a68af,c03f397d,72a60383) +,S(f76c50b6,6d7dcace,f45409d8,854f79b6,51356661,108b7168,31b58b25,ea1191dd,7d055b74,b0195140,bc0e2e93,a97f07b3,a3040148,7720df86,d3bd1810,6df3cc72) +,S(de5053ba,d716047c,cc2367db,272e4e11,41312690,2bd79b32,f6d3d959,93260e7d,1c54a2d3,9c34b0db,deb61b5,b5f46033,b1e4c581,5113bf3,d3f38de1,c97cc7e2) +,S(ad3e719f,180e946b,1b98a332,bde18e54,437f1a24,949d712,1aff7c8d,fa06499d,b458d7f1,390fa4d7,d2473863,abedc063,ef310adf,7ca2f2c8,82bcad3e,2f1b554) +,S(270a0234,5560af6b,6310c867,332f8b79,839a3ae7,6e2666ec,b46c840c,c36bae4b,8daab84b,92157d16,ca0f160,99877a1,ef7ef072,1bdb5bc6,89d16a19,4ebedeaf) +,S(eb5ed17e,3027c9c4,c87ffdb2,94a84ff7,25ba2b5b,2bf72d30,f98334ee,68624621,39fffcb3,8f74d471,9be8d1a2,14c61ad3,df4a91bf,d599c3ae,3b54b4ec,860a942) +,S(b9c11df2,8a0b98cc,623f4e80,75acd469,fb1f6621,a7572d6a,7bac135c,2ce0a5dd,5bfa8a78,d42b95ef,327eb0c3,692b3ba9,5eb506a2,4e2fca1e,391ec545,40a76278) +,S(eed17043,80abe259,fe661106,6eda0408,f60f1399,3c49a21c,a8a6310c,ebe74b5c,6dcb6276,cbe37b91,162a243f,57afcd9a,8cc2c661,652c324a,567d5db7,22a0d750) +,S(8e4b0f6f,5f5b9cf4,68e5524a,4adf62b6,8c68e310,5ee374c2,5265000c,53aa97a7,d1f880ae,c18d0191,b74578c1,6d0418f6,c7e59f2d,157c0d56,e25137ec,c1b7f74a) +,S(77ae21bd,fc6596b9,ae85ce9c,93112b1d,a7f393da,1238d76e,90cf59c8,caa5ebbe,f4484581,1e3266cd,f4625390,e729154f,51694717,3206ef9b,9106c547,ff4a21d1) +,S(1d379ca8,71c02ef4,59a8bd35,f5066265,92922533,f0503999,e16d6b07,dbd2346f,c0550b9a,72899a7b,42197cfe,d195c704,a6333d5e,178d91c1,d50b772,4140cad0) +,S(625017f3,28fc16ae,99367199,5f02772a,5c7ea721,7d47c296,cbad670c,3fef1ccc,1b44e253,af3b214f,edbeb4ac,50110df6,d7056d06,617c2bf3,6189a74d,64450603) +,S(c7a4fe49,6bdc3509,3ae3f508,d43877e8,d1019d16,740a5eb7,8eaa72b8,638412d,1b5b12a8,95fb7130,e8792406,74b8f735,6730938b,675996fb,a30a9744,960febef) +,S(cff9f83c,e8f9c4ef,3e80102c,bc48c409,b65c6166,b74f052f,a5628348,b2441d3f,4cc418f8,2180207e,fc846a41,ed6973f2,814ceb07,a8bd252e,338e32cd,e352ee6f) +,S(84027710,45b8c295,c938ae98,a9ea11dc,2fd23ae5,7ade6ef8,2c604721,66700541,72946592,d3c11404,881b972c,eba81d4f,f3f80dcd,40b15da5,f56e0723,841e4f99) +,S(f7ab1330,e00cb9ec,61a346b,d8f5522d,5e304a4e,a94f84af,b5c70614,d2e0d2c,5d4ac851,89350a54,af58def4,6f3f3d69,2ef0f6a3,9dd4ef86,6bb1101b,df5e6144) +,S(a7c84e19,2303b778,8c1a4d5b,786c9829,d0da4ddc,c13f692c,7851884c,6fd4e618,56e32e5b,8fc2db2f,21d64bad,35e3f115,65928533,a829d744,939ba456,bb1774fe) +,S(b8b0c884,a680dac0,363bc55a,fa677a72,c65f4139,7f5cdcc,f199d80d,ac98c43a,43e4188a,c92606c1,cd6bec5b,a4edb045,6569f87a,625db932,d0f8e71e,516b8127) +,S(816ec443,d0576135,5a3bc33c,1db4a179,c5bef98e,943af8dd,ac250482,a65e0df6,89a7b2c9,e9f3588d,990f6fa1,96e366b6,54f9a30,1218a2a9,c9b87c48,55f0b360) +,S(8ded2103,823d07d5,33fba24f,7fccc47c,b101960f,3b717fd2,af39d49a,a91e28a0,3f03ed1f,be1a661e,f43ef9f7,d753eaad,e3e1a391,2a682ad4,fb19526c,c0011728) +,S(b1c4b39c,e874d478,bfbdf9e3,ce8c3165,ff4f7c4,bee20c87,4849aeaa,d0d6260b,38af8b61,30701881,fbbfe724,5396adc9,32c25b84,dfbc4dbd,a54bd236,c04b4fde) +,S(7d5bce3b,e5953eb3,a17f657c,fabc8209,f011bcf2,7e10b90d,e75dad9,fab2c971,7380d686,5f5fd782,b0708b3b,62c39e49,864b2ba7,4066167c,bbcede2a,b0f84787) +,S(2af5111a,422af2cd,14e7717f,bc7171c4,96af178,8b229497,a54d2b87,4c00f285,4468bf1b,ee43f100,7e800b68,b7b3b243,2f3445c5,c8aca59f,7534beae,bb771f41) +,S(b46e29c0,6dc8ddef,f8bdfb65,f4043b61,fe010dae,a2d0955d,c81a7b49,637af766,62777495,ae16314f,d7d0cef8,24a27a9f,748c5c9b,9c51645,9c1ec9dd,9d7b59f5) +,S(105786d3,f44ea40f,71eb3bd5,339cd514,aef6d8fa,5923b4a5,89b219c,fba6b1ea,2a4ea7da,c87522cb,7d92c450,8e86d0b9,39fad024,9fc2cf15,1ba005cd,b743d0bc) +,S(1f3c0c81,be856e30,18934573,892ceb22,d2d2d8ef,f08b7857,5c624f48,16adb23f,7321690,de24499c,f52f4840,89c4d7b4,11158d52,d32731c9,faaea567,8bf6072b) +,S(16dcbae3,a95a95fa,912484f,f833ba0e,e437876b,f16f9c9f,5abf46aa,468bd2b3,56727c07,247b12d6,c1ade473,3c691700,30e5582a,cde14034,3449f241,59ffa44d) +,S(114be56c,d6723c8f,924ff3c0,f5edabc6,e42314a6,49edbfff,1c794438,dae70726,984dd72,855cdeae,7c580046,b32cfa7a,45b61b75,944735e1,d5fd9065,268ac521) +,S(8d0cb2e6,1f98472,e169dbac,7f5babff,51766b3a,8d74e17d,747b7eac,d903fdaf,d1593bf5,b9e793f7,25cea368,2ceabb11,f06b36ab,899e160a,f1f736a,80bc9b92) +,S(5b420754,188c82e4,db72f3a2,c8049691,34e3b43e,484b45ca,ab4727f5,31714db3,4a89307d,27d7f360,7acd1643,719be148,1c7eed5c,77598883,8bf6cc13,a4723d9f) +,S(91e3761d,95761d96,8d856a72,800fe0b5,9f01c62e,1cc446ed,18c1b58f,88cbf74b,b5ab61e3,96f88376,28f3389e,9999ef55,b73a58c0,d33debc7,25812530,2b96c772) +,S(31380b83,dc77e5f2,9c2f5548,abe052a,16e0f1f,2d8aad3,5b05d29c,5c1a4655,23ccafae,cc84ea72,3c434342,b839cd0a,b42173bc,1aa1db20,1073fe26,6593403d) +,S(ae40198c,bcd54264,904b44c7,c9019553,8f3f3727,a0c9639a,764cda80,b21edd27,3a57f08,ffecccfc,cd9a0e7c,827d98a2,ffceea9a,6c39d200,5cfae623,34eeba8f) +,S(f4729787,abeac0f1,249b1d3a,c19bb025,5764a854,727b415f,73e24c88,a8a981c8,e31161a5,68d81328,c7f9783f,de146d07,b51aae15,bfe719d,ab4e9e,ae65d172) +,S(f92f02b8,34148934,f7059b61,7e84d0a6,f52d3b8c,a7d7b69,ce4c8175,7ed5884a,faed7ef8,82733020,888eb530,5c6dea4b,cacd208f,fbb66b7,6f3cf41,a8864080) +,S(a2bed8aa,e93bd682,be8cc4d,d1f84fc2,9efe4022,b2b0dec4,9ed3ce17,7cc93363,287ab9c9,62126fb7,e0340f29,9edeb89e,7bf235b3,b3f08213,d630c9df,198ada1d) +,S(5a42cfcd,3d1811d1,99b09dc8,9308134,cf6219e2,e029598e,899418f9,b7af4724,95ce721c,39929d76,b0ea83b1,80bf25c2,e301413d,60fb8717,2e0ee8f0,593f8423) +,S(1d27ab05,67e8bf19,323f1eca,44175085,2e768a6b,a1436789,40ba2b94,5b0e530f,18439939,496d29a1,58a532be,76b04932,a23e3ddd,d51a1b07,c6c33e6a,11e1afa8) +,S(592bf859,22c05bf4,4b42fcf6,e4cdf3fd,bbbf8088,b7263d31,9bc74914,6eab4326,84cbd8c3,8dccf0ef,de3946f3,ba2eac25,3aaab976,8f7f601e,7d95bc74,4c7f65) +,S(66730a70,5ae3dab8,bfc01f4a,deeadc41,d4df156,d03c4fcf,1dd9e16f,9359d5,c04c7cc4,4ea1d8b2,273b9170,19b9efb3,6e8f422c,4863f718,582f57a0,778273ee) +,S(3d002600,532420ac,9fb246d,84e48560,1ce6897b,979491ae,7c5914e,dbb7fe83,5bd73264,2f16d4e7,7bcc4855,72494523,c221fa1d,321c552a,53241dd7,94c7d98e) +,S(d42ae36,2b5dd22f,d2089d37,d22e2c2a,750395ad,710aa1c0,61ed4275,43a24487,84439e00,1571e1ea,53bcc24b,a11b6f7c,ded0a649,b2a12fc9,c2a618fe,cb39ada7) +,S(37c761ca,486fabfd,b306d,c18e9074,409e101e,5bdd1670,edef1253,aa253743,e53840e3,1110db1,89ec241a,e7b2cb89,29669da9,5c07f3d0,6277f667,b90cad12) +,S(4e672ef8,bbafbc8e,eb819f37,15ac0d6c,2afa9781,a197345b,2889ed0a,f3b0e788,9c10f0db,bb16d807,4680133f,e62e0eab,130cb0b9,51937852,4afcf4c,38814061) +,S(c1f2943b,23c07929,e9c635ae,66f62949,8e1df12,f35aba68,ed8791d6,8fd51fec,3376b6c8,93ad5ec5,991f7ef9,6a6b1105,2f2262c6,680045fd,fc4d4bfe,ea64ae75) +,S(3df2461e,739cd984,72cf10cd,f663e651,351e826d,7afdcffc,e17602ae,c0370be6,5e48fcb3,3ed9c0ec,3594eeb0,81adaaa,bd5ec5a5,7eeaf01f,c9f00d02,c692cb06) +,S(d4d3d528,f98b92d5,f4c4ecfb,ab60fd85,50f12327,5b63b3fd,5518c1f3,d62a82b7,64496d50,85435de6,991a838e,d984bc09,2554053b,54b05a2e,490d2ce,da7d5b76) +,S(ecd8399b,4aa3368f,1a7a4113,63ff03a7,ad644847,e225108,b3ee7d02,1209236b,2e1209fb,a7921c29,e351e61,73c02cb5,c629d88f,4ca51af,30f37123,75355213) +,S(d5990be5,7e6a0da9,333354a,fb344d59,416d1a70,785cdae3,8c332e09,cdf78722,b2a2cd8b,73f76f3d,1079198d,34441008,278f73c8,93979ece,eefc5911,7ba17814) +,S(7598ab65,1d8ced00,af3d5978,661d801e,b57e9089,287bd74f,85ef042a,90374b1b,589fc426,9466b1ff,b9c0cbd4,b022e9ee,7edaae87,8f4cc240,b60db60d,6c28f04f) +,S(fd071417,b12d2d31,852048b7,61c5301b,be088cfd,98ebce7d,7e0922cf,41f694e7,2d9c53f1,ee63b93,2adf679d,96b548d8,d47d8f74,58ef8b45,9664da23,be32c363) +,S(5a5b4990,e290868a,d1d571ac,8e9347f2,b1e513bf,cbc2b8d1,5e56ce01,2b72ca0e,c76852f5,7159524,541569f6,3c4c9c7d,424285e7,e83145d5,e5161998,efebf968) +,S(93deec24,3cd4f146,42f5a415,f6ea6f36,25c90081,5f3d20f5,9728c056,fde7f2bd,88f919be,b9993a16,61f78145,f54149f4,6abfa859,1907736d,d5e85f25,bf2dc7cb) +,S(9224d17b,a65ad967,969104c9,3068d439,9c9bec7e,7613a602,f5c9917e,46df82b6,346c98e3,2bc2a4e8,c7689e54,eeb1064c,1b5691fb,cf5a4710,55cefbcf,18a32f65) +,S(851acc91,24ddff9c,14cf054b,87347a71,cfc91637,6e559189,f055143,3b79c38e,d959bdf0,58d21cc3,430527e8,cc49dc56,2dd20bf1,30f0e13a,55cc69cc,1e116f35) +,S(ff6c1303,b7c111c5,87e01ef,44829510,eff0a612,931f9212,2b71075f,2cea4d96,24f09bbf,7bcf50aa,ca239be,b925505e,7e99d0ff,5a959574,5370eea1,7b4841f6) +,S(f23bd9f0,55e7bd1d,433fb51e,c8b6ecb6,fd5014f,4f4ca9d0,6a4bc636,435fdac0,9652b458,9d269ad9,68ee7012,aee47447,25ba917d,f120bda6,9d2194ee,a56d7b60) +,S(9d622c56,ea6d5d19,7b823e60,1bbd4af0,1fe070f9,391bb564,2a05527a,49f46ff7,8061bb94,d6485fe,d9fbd557,66db3dca,c648c7c4,2e025494,e6c3a91c,fd5c609e) +,S(9494efe4,cff5d5e7,6394b67c,407b9961,2915afde,56933b80,370d0adf,2f020c13,ab0c7e38,c85ee1cc,27964b2,de42372f,fd86ecb8,fd3f0a81,84f5af38,58a7e4ea) +,S(a8e4d7ba,ffbc52fc,a8cb6c,2938a01c,e028c259,97403268,dbe1600a,952e1a86,8d5b83d,dc3022c,4f79723,c6f16722,cc7eeeb9,c964496f,c9f67c29,351a0bed) +,S(83841f64,938e460f,eff191ad,4d72d7a5,203c01af,1519cdf1,f17c3bb5,e4927ac5,f5868f2,c2e87249,21373397,40415c4a,ecb1f30d,b204fe41,80e01d79,eb536800) +,S(ee8974d9,5ef03f8a,860dcba6,7b597fb2,af2a2df6,950aeacb,d623c883,20612f6,5cf10d74,3085dd7,cc695145,3f9f763d,6596abfa,eb7cf216,34ee07f8,a4f141ac) +,S(68e88d8c,23616ca3,b136e5fa,3427628d,a92dde6b,2691d857,b2d01a60,b6579606,5a9090,3766d6eb,c58c5d60,9b6a5675,e5ec7b73,86a17c41,2574d179,a0fd5450) +,S(fe34dd8a,c62ec8b6,20dbea79,44ccca40,cfe6ab5a,ce3b2e7c,50ac589a,9522345b,88cf0055,adf1e122,535611d7,bd3e00a7,30c9edd5,898d25bf,f0abb9bf,6bd6c8c0) +,S(423a7a9c,c0f81489,aaa62479,c1317368,9989366,fd18bff7,f6a5f235,8251bc1f,c926b3dd,519241d,2e776ea,16112e41,259ce896,472ce71f,de4261bd,29c678ee) +,S(7fa60bf9,7cbf54ff,e61bb840,b2e08d91,ffb0eb4,727c0e73,ed4f157,ad0b98f4,d5b1aadf,84d387b8,fddc7b26,a7f736a6,7e296fed,7978e81f,6e7b3b09,e94d733) +,S(9e53cb0e,f1eddebc,77edf8a6,6917f915,8294815d,eef898c,f1e77433,60153a66,5358daf2,60fea2a1,b9a4c6f1,b8bebe09,4983499c,fe5577a2,ed8f817f,46b41ccf) +,S(adf93641,c616c677,99b44ad5,354332c0,1404718e,8ec91e96,31e69552,3ad6f119,da3c66af,e4cfb3df,f55f6761,5c6ac42a,8dc17241,5ad38619,dfe2a13b,7e42ff9e) +,S(701e3ec,485db367,b0687ddb,2be15f4b,5b6242c4,396f6f0c,9726ecb6,474e4ca8,1098fa76,13dce1c5,29f7fea,30740377,691aa3cf,3d13cf94,6f2d8191,2d3b9e83) +,S(d8fc5ba5,d3ecaa05,9e9a7e04,2c52500a,d513645e,6149e84,aac0d910,f8ccfefc,72724b4d,eec94da,7494b4d9,83a2df06,df96ee83,e578d920,c2597089,7b4b3d8a) +,S(7bc88f9a,8279ffb7,658a186,faaa5f0c,c900cb9d,4a33b8dc,c9eea83e,ff71398e,cdcd21df,e5ed8151,1a2d8c77,e08b76f7,4939d39f,1f5581b0,aa956066,fa14a7c) +,S(8578d531,bc79e1f,6e219bc7,7f2172a3,e5fb92a5,efbf9919,f46ea11,6f5ef0e5,fcd1b2ac,39c262c6,94eef5e0,52338f9c,cac2d04d,ed17c290,768759cd,13b7d550) +,S(98bc22d7,3ea2661b,545eb5f4,37e1cc0a,d4124020,44bb9093,5cdde758,a8020a62,143c7dde,d33ba5b,c2ac8d83,cc462f94,2607bff2,a1aa32d9,f32e14c2,82232226) +,S(7fcf821e,95d2176d,d088106c,a5bf0855,9980f265,ea3c401a,aca44b0a,d5e8ee10,27c341ae,87e7afee,f8af4598,e8e27cab,c127b054,1b389cfb,266ec9d2,fe400284) +,S(898a39b9,d440ef05,f87e195b,6a334f93,67acd67a,1fc76ca8,316292ea,216a5f1,eb642fbb,fe3274e5,2fd1cae9,744fabfa,c0db80e6,2bd4f7c3,fc2ca43b,18ce52ef) +,S(3ee974a2,8918c216,a962480,1f18bf9a,87d6a627,83323e3c,bf138bf4,3f2192a4,f5b386df,ac71eb35,499d5b2a,960fd20e,fde39fc,10dd5c63,dc50b55b,cd660d9c) +,S(bdd10d2f,de76df34,9ab753ee,d06c1251,9766bbf4,2fb610a5,7ddc3f36,4047c14a,504532ed,34f97eb9,b8b27664,ab440032,2b8b47f6,9c403bbd,6bc74330,16923dec) +,S(2c179437,39784124,4ff9a4a0,eb9ff292,477a5148,c4176b23,c000a1ce,3bedd63d,a367b584,4f9b7b2b,a82fccca,b9a12a8c,2c1ca5f7,3e630173,e37e600f,f2fcfb6) +,S(282ef30e,f2d61d13,6f71e6df,6ee97ebd,a83036a3,2d3cd841,36289798,b3e71580,90b0cd33,c350ea2e,54c25264,7a3fc91f,5b4f9dc3,1f58e86f,c47825dc,e3d0f43a) +,S(a42b4d55,42acfa7c,b54ab3d5,ee0bebd,85bf6ea,db138ef7,1ea38c73,899eff23,17e38880,f10b9927,764c4997,326b0b9f,63d0e03a,fd2f0bd,b1ff3cca,1f566bb7) +,S(b23acc64,c5b00c8f,4b580d47,49589559,a06fcea5,75f3d38b,1a02251e,ff7ef00e,66bb180a,7eaa64d8,4bfe6a17,d457f5e7,73964ac,ff908729,3bc540aa,1cb6464f) +,S(942dce6,96aeb063,4681ce7a,407516e9,89df029c,ecc77023,411a628f,75885ea7,e208be8a,88be7b3f,6b6b06ce,a3aafb45,c439f0ba,d517a784,ba13f80b,707caf14) +,S(b8a6a2b9,52194ec0,8238e4db,e71eb948,23e64a94,e10ea0e1,610465ab,88392d16,f8029f31,b8e5ee3f,77a758ae,343be258,34c7bef4,c1b555c7,4cb63d51,cba5fec1) +,S(a36d3369,a1ee05f7,b1fdb083,ea614cb6,f15feac4,17a416d9,cc83fc2,868fc20,e4abd7f9,fe40f27d,5b7b7651,6a9fd714,aacd2ae0,5f0a1f10,e94327e3,76f0af52) +,S(4ea30108,3d711ae6,ffccc89b,9d6fd4d5,6f03bd68,f4508cc0,ebef5e43,88dda1d,81e9997a,8b1c5949,6554bcf,154166d3,40f9ea5f,ce55ec83,eed793d5,5ca3e513) +,S(20228716,1c1c89c7,64742e62,e427b712,fee118f,406a175e,ce2f424e,2affdc55,7837965e,cf26a7f3,428d2864,41e1d09a,91eaff0c,5ecd2c28,bc817766,67fa35b1) +,S(d3c072fc,8e4bf160,5790d429,61206123,95be9092,f166784c,f5adb7e8,6070d20c,72688262,594c75bb,bb55c0fa,af7991c8,f412e0eb,afd1c0c,f5bcab82,d8daf31a) +,S(294dac7c,e307fa7c,cf0e8f34,28a354d2,94003dbd,ca763dad,3e6df60e,530ec82,479fc222,a7bcaa62,aee807c4,ba6309e6,cfbcc783,afd49ecc,fb9b45f,cf84673d) +,S(3956ca5c,c09fe8d9,e4042a8d,67b276fe,225de609,ea24575c,7075d9ac,4e732fae,1c965fe7,a8219052,9d25ee0c,e1fd62f3,7196431d,7bd78302,e287a26a,2eeaa23e) +,S(24d2e396,da144b48,e736eb06,84940175,4f4109d6,6d87a9e6,97ee82bf,91fb3def,bb79e772,24b02fcf,dd1e3c9c,edbad212,ea875c75,1fe7c81e,76d7d0d9,a372236e) +,S(638d4042,f16e5c07,fcbf9619,dd9c2f91,18852889,3e12cd3a,b49e2b9b,99a2aa5e,d0d97842,4f0010a4,df9eb8b,8e5d8147,f618da43,74b8a4db,222e4ab2,b32b3d92) +,S(f91ad5b,a99972ba,bb323a1f,d3032e1d,94202d88,63680c5c,d7d67828,8f0d866c,60b66d45,a693175a,3a38bb4f,efb32dac,1cb558e1,b0d13571,e24a14d5,9452bdc0) +,S(3154137d,779c25f1,4ff1fb88,a6d0370b,9e6af48d,88e7fc39,c6417272,eaa69b7c,eb3bd91e,9c09178a,398e112a,9264484e,c1980c19,b1993b13,560d39fb,92295f7a) +,S(f8821e1f,dfdf9fc8,1e3acb3c,1d1d7a65,f710be2d,94a19355,721cb93,61549597,bb507868,c1e05282,51b635b9,dcf28e5a,c5770c05,c7afc2a3,f4b4c45b,7d8993ec) +,S(8409463a,521404a5,a2d8aa90,50e3ad8,ec5d6faf,870333b0,6dd4f63e,8354a655,cc99452b,85092ca5,39cc1b66,83b7ab37,1b8a6525,269a1ecf,91b857be,e1db3bd4) +,S(96802411,12d370b5,6da22eb5,35745d9e,314380e5,68229e09,f7241066,3bc471,ddac2d37,7f03c201,ffa0419d,6596d103,27d6c703,13bb492f,f495f946,285d8f38) +,S(9d1abaec,9f5715a1,5c762824,4170951e,f85e87f,68ca5393,d3f9fc3f,a23a69c8,f21ee700,50dbb61c,238c89e6,29423538,71b010e7,98867bdd,149ad28b,3f28cadf) +,S(1fb96691,8db3af46,c37234b6,a4b04371,9886d6a0,5859ba32,f72742d6,141f7ae6,8bc13ecc,207efd91,f7f4c442,6e9a425a,a17b5578,20404eca,b09d5582,d41f7379) +,S(22d9e364,b9274dab,98bcb23,e0428e8a,416d54f0,5a781281,ee221db6,9e1ec7b8,5dc23258,f93d7db5,e5799195,b74e9519,4c300a91,28f924c1,c1e4865e,2d8407d) +,S(625fa450,aed083fb,30166766,d5874131,adb168c0,247cbff8,3987297b,f873e45d,720a8104,473dc904,65585ed2,1a0244f0,fbb5a286,5b8e5117,5a21f644,8776bb7b) +,S(24acb1c1,9b6dfc25,defb01c2,e2681ae8,2deacc0f,f21ae8ff,1f82f37,a6a2147f,f729d335,210e8061,8a8abdcd,b71aabe1,93f50ada,dfaf7d52,783991dd,d3ca5d4b) +,S(d2856803,a99d30d4,f3a328e3,bbf7db3b,6c6d1896,ba5b339f,33c1302c,f75ab555,9649994d,64705b87,62c98bbf,1b41b725,2b814a89,3e780fdf,5689c9da,692d6ff) +,S(80529e65,9d196884,b15e95ef,871e5fd8,8fb5298f,3bc7831b,50a0bc98,4cb5fe0a,868b3e4f,9ae4bea8,efde50bf,c5a5b268,b74b4a8,74e86de6,e9ae476f,10b3b778) +,S(7f9199aa,3b8201ed,5d288e49,49c43277,e0bb316,953f1dde,d0674d7e,8728e183,1aba673,d0372029,546c174a,3a72268c,ee9d7e41,dd97de2f,fcbe1f9f,1a5288b9) +,S(7d32c885,8e959f6,48c4674c,dcccb191,29b4566d,644d2fb7,6d0c8966,2c29ecbc,d90e94ec,b50bfee8,c951afb8,e65c7386,875ea99e,31f553e8,66e00342,6d39698) +,S(f2b961c0,9291ecc8,576ce67e,bbd1bf01,1f1727ff,ad9eb74c,bf8819e3,2d1abfbf,ebfe5849,5a1e6a36,46c38220,8656f638,ed0aec0a,d40c0524,1707102,3126f795) +,S(d9a0c689,95283291,972d6a72,897181b2,6b4ae317,4e98a676,f75bbfbf,81be876e,d36ae886,a0acbc9a,d1564d97,4d3f0309,e9039b93,bb350d92,2b7f8c7a,c6bfa042) +,S(c7a36324,6aeb7c8c,991b2aa7,10abdf5c,fff29912,30b3a69f,be2dd481,7c7c3e0a,1298fdd7,e448d2d,79986302,6b4b2d49,2b32148,d6d1e5f8,15f5b0c0,5c9e21f) +#endif +#if WINDOW_G > 11 +,S(635cd7a0,5064d3bc,66535a0,4dbf563a,640d2464,c7fe0ac4,8304214f,e4985a86,e40265,913e77f6,46735cfc,af9e2f30,e8d5f047,f3281a4c,e0453e27,e9e3ae1f) +,S(5da624f,38edea25,37f5b632,695b481a,eca54bb7,2169cadc,c5b91e10,989ee5f5,d3ea6dba,a1080300,fffaeeb2,43a5256e,48c28822,37b16505,a220d771,ca721779) +,S(aa4f64a2,b19775ec,92c1f687,1fe4b6d5,ce05278c,2976c80e,fe19284f,e87d4d5e,f39f117e,95fce0fb,6976e949,9583a66c,224ea028,8396518e,293793dc,3ed4f240) +,S(9b6518ea,99ff1b42,22a93f26,62e05551,d60969ec,ebe378c1,477b5c36,427e0641,2e9f1655,8650fb3b,43aea9dd,30532ff9,bebdf7c5,1d421656,27b7487d,8f93165a) +,S(6c9b9aa2,b5972e0f,a1e01138,1ddcbeb8,6547f47f,fb101159,4b193d00,ae97b562,af09d91c,8d4c71d2,be523d0f,9d205bda,a6e78eb2,67476d3b,1624a038,6275e27d) +,S(a2a1c880,3cdc95c5,5e636541,c7112a0,cf80aec6,a37e5f71,f5366612,db467cbe,c4cf570f,3638f040,ffe5410d,50d4b175,802e2e1a,c422fc2,73eb9b2d,4e23fc09) +,S(63d3750,c961ccd6,34a5af10,48897366,13102bae,20f2c8a9,ca8437e5,ab650427,87415332,74b39a76,72de90dc,698742a1,f21125f0,71393fa0,6d670045,8e339248) +,S(8d070e66,e4428255,a53e8fb,5845d14c,bcc97dbf,19b6930e,1f5160b2,52bdd04a,4bc98c82,4f2b4f04,c9884099,f173cd22,48cdef90,ceef4bb2,497da8dd,99487ecd) +,S(f1fe56a7,2e5f008b,b5014395,cc1658f,e3f3d4df,7b361456,175bfd2b,4a91c8bd,be5ffebe,e57a7da5,d01e302a,d3688567,a19caa5f,fe8a57b2,be2c866e,f5f275f2) +,S(802c9adb,d2eb969e,9ba71a95,675bcc7,b412399d,5aecd635,7476a1fe,73554b21,42132026,f547ce69,66e6527d,370f9c0e,cc3344c9,be1047ef,b7422e13,6772bc5e) +,S(95b1b6c0,9d6ced22,f0a5cd,abc7a594,9d24cda4,f178a745,c718204b,1493db56,bc143681,53033d16,ac8ce5e9,a6cf240d,27b2331d,36cb23dd,f69009d4,b6adb01d) +,S(eaed529,1f94eae,183b2aa4,e17022f1,7b79a06e,d76b169d,2d6483a6,a6ede35d,53d5b276,91c5899c,ddac1efa,3ad6baf0,bc6e377c,99ac7f8f,9cb27fb9,5dd559b3) +,S(77c44fe5,9f6f448c,72eb485b,6ef3f7f3,906d690e,367beabe,ac7b7359,9c27d770,bcd75022,6c440f80,2ccf0360,4e3d6b38,e6629c9f,facc49d3,83322eeb,fb1102fd) +,S(e863b2e2,f00f0a46,b6752002,cd936a88,11b6279,5411944e,fadae5fb,e40a0306,b5c79ba3,6da29f17,5b9caff,631e8ead,c2ed937d,66008358,b36fe044,67243a5f) +,S(226f5bef,93df71d0,b2feedda,4ada3098,3883adb4,f3dcedec,2721e72e,eef8f191,a09204b5,2bcebc14,8a0a08fb,e8458618,f966078b,d75ccfbc,c13233ce,741707c3) +,S(aa222fb0,8c1e7c53,9f3a82b3,9c6f08de,c33beda4,aff7c46e,3a4e9036,83467184,41105cf,21cafd39,821a7c3a,a6dff931,c1653d29,906b5d4a,c5dd6431,7c1c3765) +,S(1879c2cd,26ef4ed3,dc5220bb,397b1501,f94482cc,1236da82,239754f1,e1fec96a,912d5f35,75eade14,91fb1609,21d63042,4fc68951,cb73d351,464725b7,71f0d67d) +,S(be39e4a4,e7eed88b,f4a4cfc5,970d4b7e,6df6211e,bdc2bb76,7657ecb1,ac9902e0,d8b1e4f1,13fca7b7,6306d9a2,b4cf5a49,32ae54a4,5615c899,f94cc476,7e27cb4e) +,S(1ea72fce,33378c3d,d0302836,86c3f8a8,1c2912e4,7cf44631,d3fbdc2f,752d5786,e20f4558,fe1cdd14,ccff261a,fe506b78,cb6e2b0,807fc7c9,aed0b888,3748906e) +,S(56e33dd,67bff57d,e8c638e6,f32bc396,2d0ca011,b74db242,3ac662fa,da036806,4039c0cc,165e7130,9317d4e,41de57bf,50d78ecf,3e14ee2e,fbb3b93f,c393f461) +,S(51981691,a5f1d8df,1cafb95a,738b9e3e,d036ce54,f10a7447,c470cc2,e80f37ad,9fb9047,67cf2a99,766e3c2,6e97f045,d03fabdc,471ef664,d31aa662,c5972261) +,S(ef3a5685,77a59783,6b0be7f9,5f927996,b90db9b9,bcd57f30,16ec5979,98869dbd,51cfe457,ff22749e,949782c6,ae1f4783,fabe1136,4bb524d3,72ac3d8c,1b7c5e07) +,S(efc652a1,8c3a85ba,7ee9e0b1,6e3c6433,79a66882,5304a22,523c060d,af196415,8a656c14,cef91af3,1db2498,f5987083,8fcee71c,98c09d49,737447b3,54f7b2a5) +,S(cdda1fef,f4d5ce2c,d9802198,389880f1,8adc7962,c04a95de,f07370a1,884bbf82,8bc26ffc,b0c9dc05,d799174b,4a478162,4417f9ab,8536235a,e55c9b0,49e31d6c) +,S(6f3f3985,3454aa13,134b76d7,77dedd40,d46bb6ac,dc3a3a3f,93886847,b96cf0d4,a8ba499c,4f7ca1b5,ae7e5192,ea408344,b6e32491,e5649637,e4eec5c9,2cadba81) +,S(e52d11af,91abfb83,ea842065,ed8d804f,a2a3627d,85149ee8,61cd5df,e54b13e4,59f3106d,619e5672,cb21f6ed,4e73285d,2e132a3d,e3ed069,46838e12,a9cfff97) +,S(89fec736,f0de1cb6,45654d13,b32b3cab,8fb91869,c30e2ac0,66c0cfa3,9e7256ff,f9417ae8,4d3e1a6d,b6ab938d,9dfde62d,73e708db,b58f5ded,46b455ae,7e44274) +,S(5140f56,91b10553,ce86ce73,3028749f,52261520,a8903f75,31bdac09,22b70b29,91a1962b,9e02c23d,61f4ce,21c0ce90,ad0acf0b,fa250afd,dd67d72,aa2dc024) +,S(3c16130,93109917,1075e199,ed32f94b,579d0eb,85520d09,c0f90fc8,7d267b5c,d50d04df,e4040db9,3aa0010,7693ac01,e9f156ca,5e800e51,a5f7d36b,78ac64c3) +,S(fd87690e,63a50237,258b8a58,f0240552,a2d0b952,911d1fa8,be13eeb8,9be8bac9,406dc1ac,ccb968f5,6fa3ee35,247fc66b,b40f04e3,ac512474,58e4fea4,8a1b9225) +,S(8e4d1de,17e78f3,2ce8ad59,973b328e,99005ce0,6a8d9347,ebc7434b,d5a12a81,c6348f3e,744ca65d,744c843b,4bbf0d8a,992bafa8,8c31b6da,42919401,b1a2a8ae) +,S(382c7bcf,ea62c678,173b6eeb,ba58caaa,f4988104,1677bff6,ea739a0c,6c7743c2,190a5da,77e64243,53df7f27,e01c0f6a,67e9addc,afcd3523,7cf5539a,69c5eb7d) +,S(f56a8b4e,74b84807,539fa471,bea50795,25b0dac9,53bf5d29,e87d90d5,f914ed0f,5456d908,da57e612,3ab881c6,56a6ea24,8f9f201c,13915a48,c50151fb,c096db8b) +,S(908e9ffb,6a5e557a,1fef8ea2,b16b80c4,3af3652c,55f12a04,4ecfdb06,17965b80,beae28c9,d1b14cf0,f8182ca0,7ebc3137,b9c01094,ed6b6043,562de75a,878bc2ce) +,S(a6c30718,433381fd,16b22533,52934eb,3fad254b,99d41e78,7ef2e6e9,bec86ef4,47a9a286,a60d5102,4d129e4,e0309c72,9e266f82,5ee26f4,4bf90057,623fb818) +,S(948bad86,6c3e2c26,2d46163,52be20ae,30a652e3,4a299361,4766eb7,98b3e903,30d30622,ad478a2b,99c43b0f,915de0c,4321da4a,76a18d33,95b4c484,d9c35164) +,S(d6c92b9d,cb8a17ae,77788125,18782d36,9d536edc,f96d2c9f,c9e84d2,1cf6a3f2,dd9367a0,93518377,97b0ae88,1aec5d4b,ed68624,8ec2207b,9e0104af,2ade09b9) +,S(f9ff3d7b,7d8b13d6,46c641ca,64df802f,7b082209,a75ae328,54cef0fd,65566abd,ac58619e,1f192095,f7223022,43d811d1,b9269d28,a18711c8,c84e5960,32deec98) +,S(3dae1dba,3a70e0f7,209a920,42837ed5,7f4e767f,834d14e1,c3528f6e,92c8d5e0,7ae2468d,6ea1f2cf,e1fcdfad,3ffe87c9,5c7816d9,ea99332e,8b4d055,280f797f) +,S(27045105,6fcc937c,9cbffe13,f2aaeb0,8ffd227e,dbbc7ca,d0b4b01d,19b49937,11766a54,6c24fdfe,220d3724,661d6c75,bbd801f5,c4286ad4,d08a698f,1ffa4397) +,S(f9d95ff9,6c3260ee,cd434075,262fba81,2024c556,649c4865,bb90d65e,20defd22,37cbf7fd,8f741411,80a632ba,8304730b,a89d54a,1a5b1dda,24b026bc,17a13c2d) +,S(4e8df18,f90f67e9,fed8c6d5,b66cfbe6,ff0a86bb,db990214,48ab57c5,c5a7021f,7e69f8c5,ccf56413,453a2b1b,3b34843c,e9badfd,3a83729e,a2293fda,f2a621f5) +,S(8c2a4d2a,710a7fb2,1ba78383,63c66458,ab3d32bd,3be35821,c8a5b779,d2ffef9f,d532447d,27e42583,46171515,71bd6577,f82d8f91,ff39d205,caa5aac6,365511d6) +,S(28b7f3a0,19749cce,6fc677af,a8fae72e,c10e811e,d4b04e19,63143cef,87654b75,30471eb,3245ab39,1597c881,e71f4a1d,e241ba31,a678fe39,2ced5a63,845ec782) +,S(cb474d0f,fcb8e72c,257b5acb,999ec8e,d89f6494,cf4b008,8f6d7db,59be416b,ff7cd0ce,fc293cbb,8ab9a950,8759f856,9a0e59b3,effc00c7,e3a3051a,a16622fd) +,S(c33e6982,5dbebc40,265567fb,ede2a4a5,1a180034,2e9963f5,bd57b35f,4055b36c,22ff3ff5,7ce265ce,253b5061,599ab066,82c0cb5,91a51e0d,b798ec2c,c546be18) +,S(84bfc106,44d37123,71a441a8,4444a9ab,257e0745,b3d0ca0e,ee341838,19bd2237,7cbe56d5,7b7af706,c33d13ff,b3e4197b,afd7f421,1ece235a,e1c2187b,289ef6f1) +,S(9c312ec,d53b244e,fd40f003,f7e0835f,6063028a,5b0488dc,73599653,f97b713a,11bcbd0f,58fc77ef,854d0b16,188b4e8,59698ba5,fee41fe6,165449b1,4eb76d14) +,S(5c06af59,a22d6f2d,cd83bf4,e3bbcf21,d474f61a,e01d0433,2d0a82dc,af15cefc,476b4be9,f1c265fd,a8c6d70d,6c669aaf,41fbefb1,425e2be2,9048165a,4322aae8) +,S(777259c6,81a3ed43,b4c0eb54,7af39ebb,f44f0d71,c84602bf,2d6d45b3,f1b6bdcf,8a9d3753,5481858a,eec44851,4c834667,d6742b9c,f563ebba,22fde187,fb3bf754) +,S(b370601e,ae1fc1d3,14e4328b,4d0244de,174b8c4,766283c,e3820c50,41266842,8ef05079,2174c3b0,752a9abc,8d980ee3,eda7b5aa,4042a932,3e136834,bc125ac0) +,S(5af94ac0,7f8d6492,a472ad40,67097206,78086856,b01528bf,8248ac8e,dafe6584,8a54c7ce,57eade51,1d5f32ef,cef5f56c,b40dffd7,8cfe5655,2a9c3966,e62daf1a) +,S(8fe3c19c,e2e87055,385d4f23,c5832f37,4f84b41f,3f945945,81acb8e7,5b0586c6,f923099f,d16f44c3,a4314d49,1af193c9,2f5e2017,156f860,674f5ac,91728c28) +,S(d580961d,2642bd1e,5f9211b3,9b65eb5,e531d17f,a37bafc3,b5f288fc,13ac9a71,500c0554,337e8b43,36e50a6e,b12fa86,d9678cdc,5b38f650,e4f897e9,1b4185cb) +,S(255dced,529fa623,49e46033,86790c32,234e7967,5a9c5405,256cfbf1,4295e82b,7eeda9c4,7f3e1c7b,fc3253d3,faa46317,5dfba7cd,94f6cb10,c8f4b4a,7d799815) +,S(4b7ebfa7,9240451f,ab8476a4,ae48e55f,1a27c338,a8dd8458,bdbe422,ec891557,dfb260e9,f89135f6,fca23cf,ad7ed812,c12622d7,e4285284,8c63d83e,85b59085) +,S(919d0780,9e6092a9,a3b5819e,c67719d,3119569d,3bd14c7d,8f47f555,1f2fbf28,ca0b6af8,76d70f2c,ecbb2fa5,98d6118,c204d3d4,a30e24fd,cbcaf283,843d8094) +,S(466867a9,de89a944,5bed73bd,5ae342a4,9b8c896b,59eebf42,393dd536,8c70ee78,2a5d9707,b3e15823,79bd6ca,e8b7ed09,9cbb9f93,4ee96029,385d5678,aae042e1) +,S(71274d08,c8784517,8921526f,cf71258d,fc740d5b,be655f3c,d985cba2,c1db3f7b,e0af0130,a5be1434,f8d652bc,4406177b,3cdd2ca6,6abe7f56,d848def,fb4b25e0) +,S(a46e9048,2d25241d,13c693c1,f4e6068f,b6e8256d,1fb3111f,a0ae0e37,7ebe2bcd,7567700c,f22aab69,8126e7ac,961726ad,fdd708bf,d5ae5111,40f921be,94474eda) +,S(f7590b91,f2431126,85873b0f,77be6851,10ea918b,a26d3b5b,aec02bfa,a5e84abd,481848f8,594c94d0,c9b5d6cc,858dcbc8,2d25128d,5ea28e2e,ded935a4,62708999) +,S(2d7aa8e5,1282e1da,dad39d64,398f0790,4f966edf,aff5e3bc,9a22edde,428c2edf,12b2133c,42032099,eb33ea24,f1755f9d,a30b4da1,708cdfb5,7635b61a,335d9d79) +,S(91313f40,3302c47f,d9f113a5,581f135c,82280927,5f658607,99550fa9,7236d0e3,f8b6ec07,5e7804bf,461daee9,1f21285b,aa9e96c2,2e0cff27,c323f627,90838a77) +,S(da248119,9d385a7,8468e86e,1b146fbd,e0be031c,3a19d0de,2f44a1d5,6c6743cb,c07c897b,5f76f6ee,f2c62511,19b37c47,5d418b6,1d2cda66,6d39ef67,40348cbf) +,S(95e36a24,b1bc2e3,fb5e6082,de9ed432,760ec3f9,6f01dbd6,2e820268,dde82220,be6990d7,3abc4a3a,8f03b209,dcb4202b,52a74a87,1e1e3d01,7665e9d1,1ce1cb63) +,S(8b05b060,3abd75b0,c57489e4,51f811e1,afe54a87,15045cdf,4888333f,3ebc6e8b,1d10f881,45db40fb,889e2ddc,e81bda7c,27f5b615,acd6179d,bb30f4fe,7f40fb39) +,S(ffabca3b,764a327a,750bbb2b,a1cb8329,d43ec0b7,dcd8f728,55a9d30c,f3020f54,93970a65,c90ba260,5b2fb393,a4e994b4,c791965c,b60a1302,cf585443,6dd0f05a) +,S(b3a85aef,ef35e4a9,8f0f05fa,9752998a,d3514868,b133e7c0,a18fb053,b866c72,30115ee1,c21e5b9e,3d6b36c,54e700e8,9ee78c7,e88a2752,38f46d1f,5b6005e2) +,S(a4f1fd5f,4c233cf2,b9c5659,f666d51,5b78fc32,ebcb52d5,d155250c,c95b7ab5,91d19f85,726a1258,444419fe,c5219c7,33754325,89d92d52,c363d61c,81faa0da) +,S(97b84b4b,7baecf13,94bf3923,2b58b5ed,9eb14637,d29b3c98,bec3e624,15bbb0a,497db4af,be8e7b3a,13493d73,ca92b4b6,5eac7f30,d86dbbf4,8b86f495,2d162435) +,S(2ceba0d9,203e3666,75e78e96,51b5b57b,a9de5f82,3cc8569a,1c274d19,946312b3,d4c2fe86,f042cfde,41f0a88a,6d77c188,b7805db6,c6ab440a,488a75c3,8ed2b437) +,S(ab8b1930,6cddaca2,8be57b78,b4836998,912391cb,c6a41e10,e91b86a2,3f2b7009,fdbbabdc,79fba1ae,9d8472a1,7a648206,7abed651,36892a03,35128650,374172cf) +,S(2763029,1ff140b1,57eac2b5,9938f26b,c149705d,aa2dacd,6bb0d305,1a15b394,c2b6b32a,38dcb9e2,f4640838,c52f5ca0,55359479,86ecd875,a91504ac,49374ee6) +,S(22d1edbd,1cc1514c,7f91d793,3e9dd124,9e703fd0,8c65ed8e,6cc79eb5,cafc78c5,7453e7ee,a53ae741,13024fca,208a3816,a93942c1,2378ff7a,5e65678,c0a85efe) +,S(70d869c0,c5729e94,270fa559,bdb3fb8,b6146527,5ecedb7c,c8e7c9bd,acffe222,4bfcad32,8ce78fb4,617baec8,48c2c3a8,f8d41474,9c131657,115dcbb8,f6ec30c5) +,S(a25b45de,da8d5782,64f60dcc,da97bd28,ed9039c0,6bb7c97d,d4a24eb8,791b1647,8fd84983,fd2ad956,32376555,4c43a664,f306f11e,2f030c7d,fe1c68d8,aa43db8f) +,S(823fcd6c,9b237c0d,5aa38336,6737066f,3e77fa14,b975a5cf,39ca8a74,3b1024b8,e691a44d,29a4f2dd,e99c2ba3,bb6d4345,d1433e4b,d1c65d72,198f16b5,4424dde0) +,S(39a5a63,8244aef6,432b1247,d394d305,ee594bd2,6ed2433a,3a96c4ce,5a158d0c,147ced39,dd8b8494,d57ff37e,a24cb108,ee4b9f43,50c556cd,32df8b27,626a8023) +,S(8f9febb5,b85bb2dc,74aaf7b,81b27796,2a18f6bb,4879f5f8,de94aa56,b3206487,48daebd6,d4175a00,e37dbde,c2b57b3d,dc7474f2,ab6a093c,32a86acb,f610c2a2) +,S(fc16fb14,2f500856,4509158a,5f6b4e35,6a08db53,36e9d3f8,4f7a03d,9143f60c,8e9326f2,7e02b73a,10f4ada5,9db85fe7,4027584e,6b32aeaf,58bcf804,dc1f7a36) +,S(7db09ea7,17446f6e,9115d8f0,987eba83,eaecae01,f4201d78,8e292486,85c5a281,b4469cee,426d455d,f736b2ad,c12fd17e,79fd2167,c5a6f864,2733e327,c215742b) +,S(d45d1bf5,28baef1c,3ea56fda,b1f8d3c6,3df7caf5,c7ecb0b8,564fbc94,a4d9a57e,91e26984,64830e89,1cd21d3d,81ad7000,ad0c84d1,3c05a191,c1a172e1,16aeccc1) +,S(3faf0b75,1b6f85d8,550a9ffa,a7a26bb1,6a4d9c99,ae97678a,d43a1a91,75f03901,8a5d062a,a4e43cf6,5caaa39f,6386311c,be775d14,3b8d9368,b555c436,1844328f) +,S(54608cbe,8e08a472,79cc5e39,c65e1ec0,1eefdba3,3b127107,4926b06c,76efd121,a7695bc,40def81e,48ec5f91,cc98fc2b,9bdc2776,71d05afd,cb789e20,c540f038) +,S(559a0d89,50dfcd4,364e6955,23b56972,e8a201da,4e196d46,64dd580d,909823ec,7bf8e1ad,d6528b90,cedb8d5c,87f5953,5641e32b,6a6a7b4,c46e8052,e8dc71c3) +,S(166e8858,b5e2b9f2,b1648c34,41e5fc28,bb305ea9,b0679c3,1a996b94,acf467a8,9c9b306d,ff82fb42,acd8a6b9,108f9994,dc1b7c37,dd0c9d2a,f64205a3,92e5bdb2) +,S(40e29e8c,e66e83ba,a94ec5fc,3ae438ee,e5284f94,c5efe5a8,d41da738,38fe1941,7c71f71c,c01e7868,1cf154e2,73a23d0b,84ae684f,b0e709c3,9551884d,39acb2dc) +,S(6829c8f9,eb659ce6,7f87fc76,4661b400,6aeb8b3d,bf674408,1a844380,72d4ee7e,1d35530a,8332dc05,54e82522,5e9ff30b,6647fcb3,304fd908,ea506945,ca22913b) +,S(4a3fe05a,322e9fd3,93393b13,6e2af237,e25a2540,42d10e7a,dbb35d41,13658196,859a41f8,d4527641,a93c40d9,ef0ab175,78dbdc45,7edeaea1,f147018c,7901574c) +,S(de5817c9,a675eb2e,c1567ad5,a6467cc2,9e9ddec2,177f382,25a5e101,9aa44f94,4050ebd0,5413311c,df17e625,6d4bf102,71b45e17,4c8fcaf5,ec36567a,ccf723a4) +,S(fde29245,4f07f411,abdf1a2,6f3d8f38,daa7b9b3,1b51fe7a,155da5eb,5662a108,f2a4e6d3,7b39e929,ccf347a3,ac6c719f,f09d1756,e407371e,d98dfdc8,b727808a) +,S(f28d3cfb,6eb98ba1,76fc536d,6a772861,b0917415,d08c22e8,a43a90ed,eff42436,4508be2b,b328250d,e043dc82,d8894aa4,1971fe8c,42e6cb61,e9d02735,1279d1bf) +,S(c7655c30,4d1cb5b7,d0992afb,119a6df7,7bb65496,420f78c7,117b951,7f16e3ee,898162c2,cdb730dc,4b986b1c,b0de79c1,a348b0be,51b9070d,2e427e2d,e71dfdfd) +,S(e57d97c7,2fa3ee66,71d67936,eb62f4d8,53ffba74,f2158d0d,7ae3eca0,7b4b147,b1e3012c,a3d92975,91ab80b9,a668ca13,1ed42660,47c34958,c07c720f,e1fecd64) +,S(eada8642,155025bf,c0644f92,fe014ccb,6cd3d37b,76686a44,bccdf8c1,e22b0c01,89035d7d,71d71bb0,117c37c5,540f82a5,7152aac,af79fe91,6aed7d2,9dfeeed) +,S(3e76267e,3f172198,9f9d7e8e,11fa3ff,62dbf8f9,77503e27,5567ec84,e60d0e25,a1835790,9631c6db,a453001e,c7e3973a,416f8bc7,e2fe0871,82d8a236,6e1160b6) +,S(a11d97d8,9c262f35,2279e69,2d66be7e,5de7235,18e6750c,6972d250,91a3df70,d18df8a3,dd6fb016,df2e48fe,ab889165,44768d77,e9488b71,fd31c6db,d52a69dd) +,S(b16e3f75,cefec06e,edd54bf8,dae7cc29,a5ab5208,fd58d787,922f4221,f5f20651,57fbfeb4,5a6e32ed,74fc1989,16909891,233ae90,c539b81d,a758761a,a6d0eb2d) +,S(37de800a,3f73ea6e,9eb564c2,faf147a4,837339b3,44a33d9f,beb25784,c74628b2,59339259,9da55803,196b7e5,3596aad7,e33fc96c,fa2ae0a0,2f41ec13,e6254050) +,S(6f68412d,65b3abaf,6fcb781d,8b6e6baa,4ae57fb0,9325a1f1,9beec438,cbd68055,884fd59d,406171bc,b31042,21abb5d,27dc1433,ef49af08,ec031543,2f8d3bcc) +,S(91479a9e,6bc5e261,24cf0ce2,b52f070f,980f1f9a,f60bca79,572902d6,cb6e4366,2304f70a,22de4435,99f6025d,4b13be27,47932524,112f64a,ef935d1a,9c2f5288) +,S(8ba6b0df,36ac8708,8c1e7c1e,4177dcc9,4cceabc7,4a6c7701,8358c194,4d19bd8a,e96b720e,e9d515e2,922abe8a,177ac755,989dff1b,789a85ba,ad17f859,62ab9ed4) +,S(ab152195,871f3fcc,58f59a8c,a35514f0,f11b8a69,54e4ec9e,f4aacb7b,29d567cc,c1ddad48,623ebda1,42899ad1,75f88ff1,965ec1ca,651b419c,3c8ea037,f267fb4) +,S(7eb23f48,5eb92bd0,1c0e6448,e19adc22,6ca45c46,d4d5c756,e552ce7d,551600c5,953e9b12,4278b939,7b3de07,63e30c55,a300ef97,a8587328,b3dc27b1,a7c57ac5) +,S(b23f4c2b,a4b2700d,c7520a92,25890491,e0212fb7,eeb1f0a,2f624905,4e21ee17,a38b6772,9e95b3af,2cc7d5a5,c10386c2,8a2c287e,6349f811,457ae0dd,8b598530) +,S(85d2e723,387e55b6,a2c1a02b,96cfad64,67a6c12e,b75424a9,a10ab77,2769c2a4,727abdac,223898af,1b077fb,7d481434,ded380cf,21a131d0,db845150,c8e4d303) +,S(27c1715e,8dba4cc,41383d59,e669f66a,54ae6901,88a794be,9fd8da6c,9b09273d,2767ca54,306e6ca2,3517d884,1e7f30f3,e16e22c5,cf2bbf9d,998d5cd4,b5b1a266) +,S(e70b8cd3,7f9a5e8e,9e0c4fb5,6f85a6ab,42cf4042,4080350f,4465cf8b,95eed89,2e3d8c58,94788d1b,9734e93c,7508cad,faacdf06,319854fe,5ec4b0fe,6b0cb31a) +,S(e23dd455,24058396,98c81a39,f3f076ae,93932c61,d0e7f65e,e2c2013c,dde956b9,6c53cbd0,cd8ab8,bf5cef85,a8aa0b64,52b57e79,cb53315b,1dcdb68b,78cf77c9) +,S(5e923f81,ccc49813,11a09f2c,47677cbb,9aaf0832,10c683b7,d7a07399,4d919c9f,604d7112,e64cad06,fe0e64a8,af7054fe,7059667c,fb5159f7,738b97f4,38306873) +,S(23d9f253,1a9fa278,e02b71d7,113fde6b,1380e543,633286a5,60037ab7,70142507,55dc8247,b6eb6119,a6ef49f6,bb4e85e3,a9fd201,4f696564,42d3372b,fe44a9ac) +,S(eeb23095,ad2551ef,15dbb281,5ef6d252,886c79ef,12c7318a,50f5d89,d73b8f24,d1a71b94,b9810ce8,eb0c3896,3e7cfb90,56a80f82,9d384eac,67d9859b,11ba1ddb) +,S(64a6de7b,57bdf7e2,54beee53,6efeea9b,899a8436,e421e3c0,e7a2682b,54b7c21b,6427936e,2e344fca,c402e2d,2902fc6f,181ad190,e3f0d537,cf40c96f,27b4755b) +,S(9e4676ce,d76daf3f,1c1aad5e,51e700b8,8207fd45,3cec846d,779f02c2,cc270073,5685c781,1d7610ad,4655019,5d8a844b,6ffc4acc,eb458c38,d9d74f4b,cbdc9e42) +,S(95ee1228,80616ba1,76e0ee23,14428c7b,1d83c635,6ec843e5,d134b359,8d645473,7be34c64,41914c07,58081278,9b254c71,49a60d13,c6ee3a3,7d12e29e,a3bf4054) +,S(e53ffeef,d92081a2,f91df506,6453cbdf,d0b1089a,c598da9,94fe4c03,fc6516ad,560f02c1,4a600d02,a2e70b28,5164618f,5dcd1b67,ac071929,ecc1d891,e4c59c2f) +,S(9c332744,7c75488c,5a14f1ad,fa3d9974,90d4eb10,63afba83,fafcc3ea,62a7b68,9cc759fb,9a7fc3b,4d0ff7d2,24d0cc54,cacfb78f,5590eb8a,d689b6ee,19791c63) +,S(e826d500,2f4315ff,77eb22b0,c8b74142,f1d1037e,81e3c58e,4ea39430,973d3c45,3a466e58,82f971f4,3ab9316d,fc7d53a4,e8ab16e0,2ae75045,5d8d1999,bc8b65de) +,S(ced4df0e,af93b5c4,8dcf196c,6e9b16bc,dd38a87b,3fd67512,d387b388,115e13c7,fe08a63b,dd149dca,b4f2c930,99cd11e1,8c754271,cedd597e,910462c6,d68b74cc) +,S(b056ed27,88ea50df,2b220182,df38f54f,8065e36d,e0218b27,ee8c5416,db7eb33d,97338375,cef457f9,ebe43aa8,28e9a1e9,8d514d9f,fc300a6b,a1a83db,dacf6409) +,S(35dec74,2fef94a,7fe60b66,7341f6a3,eba030c0,4061d156,1c9ee288,5b7830df,2599121,39c810fd,e7f02fe6,eb6e9221,3eb8be6e,4d8f045c,aba1f058,789b933e) +,S(3f23cc8,7733213f,d2e15cb9,942af44f,d7981e97,37c5af1f,81addfb,324e020b,24e8ccc0,d43ccde3,4e392455,dcdec100,7ffc0c61,3b5f865a,c8afc051,756e8f83) +,S(9ba96c76,c0805cea,d7ecfa43,dba0d86f,c8471dcc,8bce9bc1,e06537ef,2bbabbdb,c1a3c433,1c2ae04d,be2f8e3a,8f4f07b1,622d9820,607ee3ae,e93bc37,f943def3) +,S(83c1479a,31475395,8d510396,5decc9ce,1d414f41,610e2ac5,c2e887d7,d16a3815,84d4d018,1354cd46,e5f39bbf,f9fffbba,c123d470,d07c292c,7f085740,289b5b7a) +,S(bacf627a,2db11d88,76e6714a,2857db8,a8d7010d,7b349ab1,fcb5ebc7,efe0a32d,a287dc0d,a44c448e,68b777b7,36ace20a,14b3e586,bab7ef5e,d57ae303,e8c83129) +,S(73063c55,30129f79,10bfd2d3,a0147167,4ca888d1,d64d24d4,619c5cff,2776ebd7,d57941d9,44ccf8c8,2fab0362,b14986c5,9d71906c,d28584ea,368c4bb2,2c159489) +,S(4ee8632,df55ad15,12ba4ce3,4ddb403e,a3f51a12,d445a011,4d08a00b,3b5d6637,c29f7199,dc30275a,39ff01a3,19723d19,91687901,9616fd81,88ae6c45,92b14820) +,S(fc46e66d,68bbd41f,98b18a16,a23efaca,8f5345ef,b567786c,cd42afe7,d7e7ef28,8b42a2df,abf8849d,53daf38a,4a4c28b9,a0238231,ec8f69d5,d702715,a643c18a) +,S(a71ad1b0,158d7978,7eece5e,2a3907b1,3f9b6b98,aefc7963,8a9de618,b3a7dc13,6fd7e86d,a956c464,e538a864,41b9b7d2,ccfc5c44,e80a66ea,4375e6a1,ef08bf90) +,S(602185f3,6075a67f,d7bb9957,60c6af59,61a7c553,d51d828d,ed37768,f1860a3a,90d312db,706b835e,647a027c,e7a89d39,2265cd4,dd52e802,165c32bd,4d10b2e7) +,S(db0fca83,76729191,b9d9976d,37dc62c3,36b4437f,943706b5,98e7b7df,607a77ca,23dedd6e,8eba7ebf,e0c9f0b3,2a1802fa,78699a68,99507dd9,c4f4841d,82efc29d) +,S(6919b861,598d4f09,2a159909,fff8de82,237d0aec,339d884,7618f257,a4a54939,ab9f82fe,1fa53aa3,b85c0784,59a4e191,27a1a214,392c3ff2,f3e1cbdb,6f34b90c) +,S(f4a7d2e9,f1f51ba7,c3cf0a5d,5d53a00e,877ec118,f7e39e39,299efb2e,8074bd59,9f050900,6aa6ace2,da4e6380,cbce7983,c9bea9d,99741be0,ef17e190,2c5bd257) +,S(8a5d7210,d4f1de13,1091ae23,2fffbd96,3927317e,54197656,366b2e35,cd453da3,9aff8a1b,5b71da0e,a6558a05,a9306adb,4cae1004,e532aa98,abcd1644,b0580a54) +,S(99eb23dc,e40d7159,b0a0406b,ea04b87a,2c9195c2,2afd79f3,f938018e,b8e86f16,2ef21938,a66efdec,7ff6cdda,a79fcabf,b1f17fde,9e80db37,82b47d41,64ecff66) +,S(3bf16e84,1a874418,ac7f0d0b,9abbe781,611ad0e4,7acbe904,a99ba65a,b4d37472,1d3cb9f4,e1948cb2,fc88c0f1,9277437c,7d1138b2,8aef4355,1fb35121,a3e714ad) +,S(a3ef83ff,19eb394e,b87c133,36388a86,561811ce,5449895a,f459fe4f,e7f01f3e,1955dd39,8bdcaccb,cdc7ddb4,711d08e1,9d687ccd,d335a4a1,45d13a4,8178cbab) +,S(26816f51,da9b4e81,3edc024c,223dd6b4,5a344d11,f5ade552,63ef17e,70b1af90,46278e1d,1d6b67a3,57280967,6604e897,65611b7f,bbccfd30,22007a60,294aabd6) +,S(5e1653c0,d640f148,ecbb14f6,97940b0f,1d47dcc9,48e7525a,909e8444,afdea823,9b8b81ed,e7cb8350,ecfaef22,92bdc528,8e499cc9,6feedc86,cd45cccf,4cb092c7) +,S(1bd88e45,b0d3694,56348c23,125b12b6,b7725d6f,addc08f2,47fe9dbd,e828de9e,182939e3,2d8bddda,577dae7c,a1d40164,9f6faf68,69808fe2,98dba2f,b8a95db0) +,S(4b03fe06,3adc4e40,315e754f,bebb7802,b80ab716,d4201fbd,31b12c5f,d9b73c02,a864d0a8,e2c5e519,ced537,e03f98e3,a5623c31,ea4a430e,73e8cf54,1c80fb06) +,S(e20a515,7818f33,1ed927f1,3c46f3b5,2146860f,d085e68c,5884f1e8,45d35f61,a1c12002,1a79d6c5,89e466c4,3fd48f66,a924e9a0,a3d20db0,484875e6,96bcf328) +,S(e3d11a4e,74a1e1cd,8be24d87,4885e1eb,4aaecea1,c802ba73,2db925c7,f81e37be,8f1ec01e,a1ef01f,63806787,b8831d4b,22b0a9c,7b44bc7f,73d2a3b6,861645f5) +,S(8a233215,57fe0dbe,e8e92b58,4729b163,da71fa32,f400617,d1e2a081,3e37f6e5,af5e471a,bb8c7505,aea1ed74,bd7798cb,267dbd29,61c35f5e,93889056,aecce950) +,S(3bbc0a2c,b43f4683,151070e0,7015cd6,997e8dfa,99685cbe,99f9a76d,6851d20d,9a1dfb8e,a5f14c40,b9968e88,b6083111,fd140843,96fa8278,bb0e351b,7cb4f97d) +,S(8c04d781,82d83ab,e8c59dac,9407b4b9,65380f38,39431184,811e133c,911d1deb,4d74e493,fdb22316,fcf21340,88039534,c0a3e098,7198ceab,4a65260b,4c0a3db4) +,S(467d4d0e,72312cde,df0aa7c4,62e03644,1ed9f915,c9e7e8c8,5770a4d6,d6a0291f,83db40a9,d7c2954a,30c624dd,f11d565a,f117e240,183a81fc,d4dda1d,70a1ce32) +,S(b62f60cd,8e55a101,ab060186,941cbd52,ce73ae2d,e19ac195,d55f498c,45a3dc8c,59da48b0,7c6d2562,eeb0ed09,158cd20b,4a5108b8,fbf6fcef,428cc301,b314ef41) +,S(6b5d6210,f98aee61,df36d7f1,9546efe9,166e88cc,6492183,379dd1b5,cb9e681f,dbfb1748,59c88a6b,72c8afca,830045c2,7c6de87a,c47228e7,7f246e6f,698a0d76) +,S(88744d04,e8c7842b,68d2cc9e,f58977cc,548768db,48d3c286,49ecd0a,22300c97,84573aa5,1ea3c51e,5a0b0e42,5c7c90b6,149d2993,91085bc0,393f58a2,8fb9c38c) +,S(fdf2c824,40f2ac58,19b06571,216ad938,d0218ba5,be4d3d4b,ada80e32,c32e37c8,c2abc4b5,9e961ffb,e48c6f20,58602dfd,9172031a,740668b5,5876d5aa,5d538f74) +,S(4d2fdf64,1f5a883b,322273bd,24755405,15178ce0,9b4ce8a9,36648957,ef777559,22ba1d01,210bf31c,6421b89b,9b3217ae,b2837f01,c344a9fa,bed0b385,4aa41b11) +,S(ec7cbca1,e743bfdf,81af3fae,a5c64a8f,5a54dccc,2afca269,9c461592,34ddc633,9f193da9,ea76a050,7b528c05,e5a10107,dc5263e4,98fcee29,5f57816e,4eab0917) +,S(ff2fa113,771998b8,b801e779,3cb804c,da9cd6df,9d371943,c7fabbc0,44b44fdf,962127f2,1ac57670,c79d966d,b8cd6f0a,2aec6824,22cac54,23746bcb,2df6093c) +,S(6d1b406b,2dfb02d2,34ec21be,c436d6af,4fd418c9,29f175ee,6475e77a,8a57580,b8945668,9dba8e2f,8f0693d6,d3e7b602,f157efe5,38b9ef07,b2dea23d,bce895eb) +,S(4abb9dfb,449e00ce,46476727,dc6b96,317bff7,74c21df5,87bef539,644d7963,6086f2b7,c016c69b,2ad80786,89af1c98,4d6dbba8,7545d8e4,9c2c58bd,f86e6407) +,S(db0c51cc,634a4096,374b0b89,5584a3ca,2fb3bea4,fd0ee236,1f8db63a,650fcee6,7ec0bd2b,aea1ae18,4bd16fd3,97b0e64d,5d28257f,85836486,367fe33c,c5b6e6a0) +,S(ae6f6dbc,d0664919,a65e02ed,646de704,6996a382,21aa8e74,4954d22c,37fdb287,abe70eae,f8ae7404,11931379,19f9102e,c5bbb2f5,f5fefd1b,b76fb6a1,c3f2f201) +,S(aea3eb97,cb321f30,bd0771a9,17fc9770,f4079a62,fac51fda,63dd3ac8,d35f6227,b6a53416,398515c5,e9133704,a287dfdf,878145a1,4416b525,6f1ae46,6abf39b6) +,S(90c9f8cf,711d50de,81f7234e,f6c13af8,39355c06,3e891ded,51bca1c,852233be,8d95778,18f19649,f2d3d452,81358783,17d2c32e,aa01551e,d7fe21c8,3421bff5) +,S(5ad7ece5,ab1d0344,5528dcde,34b48efe,fd954aab,920260e2,1495ed8c,86d976e0,2df2163b,2c3c63ab,bef274e9,3c46b6e0,62ac9444,b17843d8,70014b03,f78569b0) +,S(b6ba2e2c,8e942ef0,16e6d3ee,13ab0cac,1d80ae7d,588a831c,b7844e8e,3bd28d9a,41180a35,f923dfdf,501b6b06,7d241160,a2ebf453,d00b501d,855ddb7,1bef7fb4) +,S(7e409bc9,bba26c7d,fabdd450,bc84589c,799555a9,c6809cc4,13a4c674,7ff5f37d,c518961,9cc5afe2,e41c4260,481d8fdf,6066b034,19fe030c,e423dee7,79c9e6b1) +,S(9486cd14,70b2f2ee,28d01060,6c7c4c22,2c72636a,a50b64e0,3008516e,de4f602c,886ccb8c,fc5b006f,df931785,f732367e,c062e9a3,49f452ce,aacfb74b,deb467af) +,S(e7c11d7b,c8b07205,1e1af6d8,745ba05e,94b1ee9c,5482d83b,1af9ed8b,21338d2a,fdc4d293,828cab1e,fc9062aa,192f35a9,6ad4683d,797fcf79,c74852de,d75c8e50) +,S(dfe627b,ff315cb0,1b1b67b2,776ded35,19b1a85d,8e802217,c98000f0,93d50bcd,993c55eb,bb65087b,6fdd2480,c9d68e6b,ea0f69d1,b95efc28,5f32a8ee,55f9e773) +,S(a0f0cc17,fd00a2cb,5fc7c981,860f02f3,eb31c26d,54841dde,189eac65,a446f516,bfae884c,31d58a3b,f11077a7,d3edd37e,14bbe4ea,bd30fa74,ff5c295e,4b3b8969) +,S(c1dbb6bc,bc14286e,d6eef926,c946b52b,d37e7f53,91fe1dd9,dd7b72ba,a3e37338,67b02d87,bd336882,f4b6fdc8,1a3a88d7,aa5e2735,139e1bd0,e793e6a6,12df7bf0) +,S(20b9065b,c7d495c4,c92cb1f0,6eedf5ef,7025511,10343eeb,e82505bc,bb4bebb2,a6987316,5c231d92,bd21a4f9,60242d9,4fec71a7,4b24fbd,55d51246,10756835) +,S(7bedfdd0,c4d8c38,dda9544d,38fc8786,55ab9a66,4f8dbf2e,3c54810,eda69190,9994f0b0,d4f52de,6ead0049,172fee05,365556e5,3c9d4591,690715a6,f8af77a1) +,S(26762eaf,997983f6,ac63815b,720e97cb,5adcadd2,419d368,df4d385e,6b5918e0,81f5448c,e11b4dbc,24be2e9,be5620fd,25f0c0d6,76aae549,2792188d,5a27e6be) +,S(7148cae7,ee18e152,c3354ff5,dda86e13,ea14f175,92d0d3d9,a944f4cd,f387bb79,bdb35fa,f6f86e90,41465efe,dac6bc0e,ffd42a0b,eee83365,93dcb4de,2310b18d) +,S(27e45dd9,33ae2c33,a69ae00b,156845b5,bb4d8f06,593c2723,5038ce17,87bdbc90,a2bce33f,a93579a3,f8d9c75c,9271a2b1,7dfe36a0,590f2db1,f7cabfd6,51801ac9) +,S(af0c7215,5b28ae8c,2a2d79c7,d81e603c,d0539c11,fed2aa98,fa2bf2b2,d7d6b7d7,ae6bdfcf,a25109c0,b80bfc,71cfac3e,3b5b26e1,e4f2c856,40d2c69a,a7ac41f9) +,S(7b63c408,d4f8d34f,314e609b,21e8e372,de0f5a19,1accabec,7ecfe02a,63cbabf4,aa08009a,78fa96bd,8ceb6f65,e88859b6,236925d0,bccba7c,e0db29be,94f16327) +,S(ab768853,14f3e88b,d63cffb6,8f4f3232,4f4b4801,41aeff93,94d58f9b,85c6890c,1a71c833,d6d96bc1,c33610e,d7ff1481,c9ff9841,157c59e0,5d3a036f,cf7f192c) +,S(641437f0,7ad75112,f8375487,cc0ed859,ccd308da,4b25e5a9,953e351c,9e3bd32e,3c58f7e6,b255346a,f50f1ba8,3f008662,7d2ec950,84c326b0,ccc3a388,81a9b131) +,S(f532fd2d,600ed478,c1dcceaf,fd01ae87,60f7ecc8,7739580b,9b4a7649,67a082cb,7393514c,71117d7f,7cdbb4d6,c803c9f3,221847ad,697c945e,440bcfa1,1285fa96) +,S(33679959,2c4bab44,d89e6f60,8f882938,db73dbd4,75f0dc3e,e1fbd075,b1c7631,4c1f8004,6fe89cf3,6d078251,5ff57cde,17125d62,5cf675aa,1fd70163,49694fbc) +,S(e184c16d,2a34ca57,b06b5396,28cac285,6f18b7e0,32970a5b,e2221a07,be56c9cb,7dffc17b,51ef9c4d,f16ab068,8c66df57,d646cd34,46b509c7,7f85e03d,e2c5bf73) +,S(f8a97d16,2fb49d55,bb8de990,9a20c1e3,4f6ce6d6,efb8c68f,e26c884,6415d419,3cd3cc53,4dbfca01,9492e161,61f2e86c,5f20a83a,866874a7,ded4c2e4,42061146) +,S(9eb6aa2f,6c6ad821,d46dd612,38d3dc53,28cfc406,ad71964e,b32de0ea,12475781,14501a83,79d32e09,3664ce34,1a419b28,53dfe3e8,fbc204af,cb33e347,6c45c299) +,S(ebc2566a,68e68955,e1e42740,323fd401,7c40315f,ceba7642,5f887a3c,3602668a,75e8109,96ff56e2,655f9f85,ae9ec9a5,fab3bdc1,42ef063a,a06931e4,d4c7ea39) +,S(55646438,a966ce5c,2fa5b29d,ba4840cb,ab9c5e4b,4074a9fd,674b7eb2,f52bc392,34631a86,76034a89,cfc3f68a,45cd52e6,2987d80c,e9a8e28f,a37020f,981c8d66) +,S(b87f8309,befb81f3,313257b8,c7dd914c,82eff5d,6729f2e7,eceb0337,7b16575e,bea66832,59e4002d,6fbdf03f,b80bec1b,eda5e1c2,cc55c630,deedb7fd,a96ea298) +,S(45957585,b440d63e,acf598b2,16e435e,24b6cf15,2892c8d7,953471df,70a0a93e,f4cb6260,776a4f4f,23ac366a,565067fb,b29739fc,233493a0,b3eaaea,c4b71427) +,S(2c90f64c,8d9c42bb,1824c821,8f9cc057,3fe8d648,b960ee11,1487bbe4,9648ca87,829bcd57,ac643cb6,9f000a9,f22fcf57,69bebf7d,6b1d8ab4,da21be41,d3c25a8a) +,S(eb327ac7,779c9abd,9546a3fc,c7731729,2e753912,2ba9f7be,36db0548,144b5efe,21ac2c85,8d2fcd38,8c32c594,d6e74803,2cbbf365,238565a0,8c439190,518c9435) +,S(95ec7e2,272ccca7,aa2b07fd,d37d0f08,daa35418,1ae30e6a,dba0cb1d,2c6d007d,733786ef,59df6050,552ac913,c10b8890,2d589e7e,4f740f33,75f78fc5,2ba12b5f) +,S(4b7a6698,8b4fa080,f27c845d,7ff17371,91104a29,2c6195f5,fc367c69,fc0cbbd1,8b043bd0,a3605612,87b38fd4,d99b29e4,8e52494d,8241207c,9284581b,63a85b8f) +,S(89b2c58b,6df581df,352ab28a,619027c0,a9233792,fc6525e7,47dabd31,a342e6b2,300b1b34,d459e65b,e265edea,203b74bc,9b053feb,888e81f4,10045a10,d7f53a2b) +,S(41099b5d,9f6a28d0,e4a7ff0d,b75ec487,1c926327,89f0c800,7ada8114,9bc43cf1,2a0aba96,2e2b92b6,e949253b,e06588d1,3e07919a,3594b26,995c15b7,7a62cae5) +,S(bcb0fc64,9ec508c3,507396b2,9a663555,8825ea9c,1389c817,af7fd616,7229be4,168c7992,cf3bf5ab,6c3a12ae,922e647,13664db9,2d7bfe5c,2c746933,3a07d606) +,S(7a3fc958,5a6256af,9e314ca7,55a8096,9cd3b3d6,f70349a5,ec719cd,ed8b762e,fe8b280c,29cd0716,35288526,b7179d90,dadecd78,39128f22,17d445cb,d3df1346) +,S(377093e1,b968a35e,e0f229e1,e656da9a,7583c1e6,d06fe1,c89e3f06,61a8176a,e7c0860d,f6c9f461,7e6a4dd0,b8c0d800,6aba8e88,20aeb82,e6e0f8a0,c2c601d9) +,S(c5eff3da,f4a5cccc,f1f27a93,361301a1,919b1dd2,5a98ea37,5ba63f14,4aafecd8,34e11634,26f983dc,18c8a02c,2222c2fd,a94129f,4e3f1d67,f424964c,dcb97a1c) +,S(fc7919,eb560d33,44230f72,8368afcb,3c0fa6f1,52ec54e9,84ea9ccb,e63ffb27,1c7d3782,af766ff9,bc1cb838,8e4a7dd0,a04bc4ce,adad3fa9,4132842a,9859a6b3) +,S(2783d7fb,49386d72,54434cd6,edc6f46f,b3118322,43d381c6,287d8b24,861ca5bd,a3aaf271,b806ac0,e3c45026,28f89c79,e4c68574,81710111,a9316e38,c7fa5c70) +,S(7407a478,68d4e0d0,f77f8949,5e5bbf95,88f54a6f,fd35d229,8ad4b30f,2d8a02f3,1250d562,96e18cb0,aa5b393e,a933297e,debf3d94,59ac1ce,24cc11b5,87fdec9c) +,S(c2d2cce3,2940ecda,77ac108e,71544079,c5899fa4,f8461df6,cc54dd21,a861a321,f0beb1fa,40bb8071,928b05e3,ecc8545b,a919eaa,e830db72,9e6de85b,f05a1909) +,S(8cf6b189,c5051956,6a94e1f5,ab5e9530,d459a935,4cb13eb,349fac3e,ade8a56f,bf6a9d70,32e52886,ce6d06d3,b22d47a8,327aa788,1621338c,1606054b,cfcf9c96) +,S(d6b07586,ed9f8471,f96ac5f,53277d1e,2deeaa2b,7fd09d51,ece6766d,29a94968,dab4d4b4,ce5655cf,4aef0d0d,5e3fa292,2f79041e,d2e23c9c,75be83f5,f09c5326) +,S(a720b733,60a03edf,f33a0921,90795834,9e661d33,44da800f,b857227b,ef4d647,1f213c6a,721c2d82,6037e3a5,a0f4867f,13d79dff,bd44f5b1,1bb5c0b5,4884ea63) +,S(558a5698,3b03c6c6,717db862,e59dd075,b39f9ba2,ca01b0ac,95a69cec,1f3a5ff7,7e07c752,db21b68b,21738458,a045fc60,fe3ae869,887fd557,92ecc6c7,d4ffb1a4) +,S(b927dfc3,278668a8,c5329941,f11d0e0a,a7c2d9d7,f8d6c263,9cab5550,10e14ca4,3ce83725,9954227b,b420e35f,77705225,72f4d854,999af552,4b8795c2,b723388c) +,S(2b70d499,1085aff5,88e23ed5,ab55a374,3c35f71c,651c0165,13f98ecc,4f0e6da8,df413b4d,aa1e5c9c,a2398469,7d82762f,a701413,1cae25cd,1a94f02a,506a8b06) +,S(b8836cdc,f72f6e00,99a9181d,94ba77e9,e1368e54,a62e1144,1421f2ef,2daefe56,9ad452f,e31f26d,cad7014b,68ceaeb6,1beecaa,5394c359,afa52209,e50427ce) +,S(252b297b,65f0e23a,9788b48,f33809a,ec66b445,cd90db00,4dcb6a80,c4af93a7,8cc4e0c4,3c346211,736a3bcf,c24a58bf,9f77c7d0,c53350e8,6cb0de2,60916838) +,S(9f3d30ca,1c15cc66,8efd5fa0,3d6b7bdb,d34f2704,cd729892,aad9171c,debe6330,448b6434,f95ee7a,bc056974,f1476171,353d9b98,4e22057b,38662327,b23211b0) +,S(8225e16e,5bc9add9,ff8a771b,5bc7bce1,653b545e,4e54b9e6,6e2d2985,2fd35e49,6254c5e3,aaefa2c1,6ca4e1de,87f09d94,df836b9d,d100612c,7174aa75,7d0570fa) +,S(a7dcee48,4d6e99b1,b72a80b7,4de255b1,74f4767,4d3c5799,4669ca6,aad02ebe,1d6f0cfa,76a2901f,4861f541,bef7a948,78586178,8c7c42a4,2db583ba,1c170a7) +,S(a91445a8,5d4ce90e,98d3372f,d2c664b8,9a6baa2b,a396fd1e,210e315e,809976b4,adc4c68b,99b072b1,b51d1512,cd94007c,72deacf9,4e7c5449,f1d83876,78b1d100) +,S(7462c9ce,907c9655,75c41096,3510e00f,6f6ea6ad,886cdc79,ed685ee2,2a7ce1f1,4ffa41c5,f02c2299,c42df5ac,79cc4140,47a854e8,332f8f2a,e67ffa20,bb71c7df) +,S(d42895f3,dea495bd,af8e36bb,6a79f234,dfd85544,965a8506,5d38ca86,28cd4f40,2fedeb18,13a11c42,e7869b20,7bb8486c,9821710f,a80d9bbd,59c92ae0,b50d9cf5) +,S(ef9b6b62,ce85588a,f13434b2,7ef53d12,e8291e6d,76a65669,c29d99a1,4d388adc,159f5fcf,9af0c962,ed907955,e91407ca,80261255,45b6938a,db18aee0,9bbf912f) +,S(4003f1a0,bc659daf,df5fb7bd,bc96afff,92877c7e,2a693f39,2afb06c8,fdbc9f32,ebffcaa1,7458f0b0,28ff1dcb,74be865d,7faeafa6,c2707cc9,ea685eb5,7961fef9) +,S(4390488b,6b03d851,648786f0,7486f5cd,aa9ae1d9,4867de,bed7036a,6ac09a8b,78329de5,a10db56b,1c35b88a,21ddf393,452001c1,29a0bd6e,5dd76a63,8682f07a) +,S(ae6da0d2,9ea3fb66,b6006c56,5dff8b41,6074ee16,f9ff86b9,60574067,abfadea1,74caaa63,dd012a63,e76f0916,f370614e,29e3f01e,b88b49c0,5ca33234,c11cdac7) +,S(78f879df,98614721,b7c65652,4e806f6,35942e0,950514fb,2fad8a86,bbcfc72a,4194e58c,478ae80b,fab661b7,ffb85cc7,2318aad3,88d61c68,a755296d,38281ac6) +,S(80684365,4f41b0c6,d6cd51cc,838355dc,352e028,7b1c1d1d,edd2f96e,5fc97e01,8b0c223f,13c61b4e,1e141a0d,35f29a7,7546bc7e,3b1e5c45,262033eb,92b62461) +,S(29509d9f,4fd975f4,6efd1169,1d97d0aa,f83b5934,9c797010,5cb3908,4b87466c,1477eb75,69a0af96,c9cfccbe,135e3c86,a33de585,2ead38da,8a0eba6a,6d0da81) +,S(191d1443,3d9c722f,c1532fe,33c63a9c,4e3d5741,6ebf799c,2d8ffeae,df1dfa4a,5bd00409,b6b571ad,745ecf83,91884eed,a5e3c7b6,65ec9706,eae4b4dd,703a2cd8) +,S(2843d42e,d2738168,5eed65af,eea82bf2,a50f0e1e,3db201e1,ebf8b159,1b0155a8,807cea66,c0fa9f53,b47e6e2c,232cb225,77edafb8,99a6f98,ff87d091,bbc63ee8) +,S(5568b7b0,9656d36f,5347514b,8e8212f8,e96ed02d,4516c018,4d653bd1,2bc8f644,5b44eba6,54836dc4,3fbda30d,7ea36406,4960459b,a4128911,8b2d8638,50e60d87) +,S(5b84e0e0,809e44a6,9e8d81ab,595b32f8,4a7dd421,c073fd6e,5f38ec5e,b145e803,1a65a2d0,fa791ced,72fa1522,ae431155,7e6109c0,fe934243,cb43d3ef,ad13d398) +,S(ef42c56b,dd241071,47e1519a,18d32910,675ba842,92cc8ede,900a64ea,bedfa672,70151747,33359977,611e0c25,4addbf6b,26a618a2,31474e3c,c9e7bcd3,8bff75ac) +,S(48dff2dc,b50d4a56,4be6ed00,3b1415b4,adc653ec,87eae94c,92b7c129,5656eb63,a9be97fb,53afecf6,f0bc59e9,8bfad542,fa29e63d,f701f6b5,f0f66081,8d643928) +,S(672e90f5,246ad174,10c9a2df,c22b098c,d1923bd4,19fdc337,f881e4fb,4ae938d4,73fd3380,1fda6db6,883e678b,31e5f09e,f331b624,5617ec9e,97aa28b9,a1781f19) +,S(59cdb9b1,71fb819c,909e094a,95dc15de,dbfe5521,4a7cb723,ee7cb761,4b315cde,55ac212,670b4a63,ecf3f8e7,3082009d,7f2d38d9,e490ca18,7a6db01b,e88351a2) +,S(5ce38d0a,357a58ab,134db879,b99994c4,6b827f82,8e1ce8f0,43108de,ad2ddb18,5e816202,d9c1d86e,c2f84b33,ddbcc51b,94748c67,1089c9c1,745a14d9,3b97f716) +,S(c982196a,7466fbbb,b0e27a94,b6af926,c1a74d5a,d07128c8,2824a11b,5398afda,7a91f9ea,e64438af,b9ce6448,a1c133db,2d8fb925,4e4546b6,f001637d,50901f55) +,S(383cb084,79e61bec,dca81d29,7796d00f,60bfbcc2,83c83d31,725f5329,839ec818,26e26fa2,49008933,8bde0498,15f34d9,bbc3426,ad8644ff,db1a190f,79dec91e) +,S(e6945731,2ad4f14a,71917b52,448011df,28b88c9b,6ac84550,248ca4fd,102f612b,30ed2082,51fc701e,5ebeddda,c9eb0b44,c81cc86f,9706889c,1b1c3386,4d76f53d) +,S(2d0071ba,8f799352,212168d2,1262a729,250809f2,24fa58a7,f283c4c6,bb9976f7,cdca6901,4e4873f1,16945544,800079d,ccc118f1,a5709b03,c872b017,5f1dfd8b) +,S(c82b9457,65b74fbf,91cf35f0,679877b9,da35c2b0,8437d789,8d748f22,1e927e,2e504dd1,bb06bfc,7e057dae,9aac8f07,b57a0f2a,39b1533d,9313d9f2,45fd6a2) +,S(9c1a4c2e,7eac21a9,fed135ed,e737dd19,2654eda2,fb3a4227,63cb6328,75bbf0a6,f3134b6c,12f71c58,226c9128,9b7b5a06,80eb6646,e9da2e60,20008efe,10e9197f) +,S(971d3d9b,bc693222,ed8bd645,e80b7cf9,9b170a36,2d57753b,6a2ac27e,8d6c9b28,d63d49a,e296dc2c,6c4a73af,7fc5e86d,e2039433,f3858980,80a36f7f,91d22e2e) +,S(f5493a73,86bc1151,23f29f2a,e0619e05,660a317a,bf5ac23f,a67802fa,8b917d2b,e6adbccb,8b780530,2b305157,b427b8b5,38455e02,80133e23,9642306e,65e0f1d7) +,S(831f123e,500e0a0a,e497a321,5ebde2ad,763244fd,40b386da,dde05537,99b6e014,35616862,2ff588ac,552fa508,ceef5ef9,ac04af0a,9db6b950,f44719c8,cb221d6c) +,S(9b8ce06d,18474c,3394c334,2ef385d6,7a338c22,98e92975,f1728c87,897cfb35,76940220,b8dc3e04,7cda50c4,c1f53747,7ce8757,a4a3731d,712cea05,42a40d72) +,S(f70a916b,a98d2bc9,60172410,42bf3e14,14f06cad,dffa7cb,1e8137a7,3fc5b855,f1b8c1f4,70d7896f,f39a3fbe,997a88f3,b5426d84,43c4023f,ff98fffb,280275a2) +,S(2d2ab7bb,c44e7fe4,ab283661,2f621d05,a64d6909,fd94e599,92d52afa,c0763d56,53450e00,2a6991c8,68fe044e,8b61c2d3,c5fec8af,3605728a,e57d32cc,c55328e8) +,S(8178deb8,c516978c,ea25423f,3a913157,321ff7c5,5d8058f3,dc9b9d46,f4d10005,16a71b2b,46c9d303,f4ae6a28,235249bd,f9c00146,a26b6bfb,5983bfb6,8d6ff4bc) +,S(b470bb76,d012ba7e,67ef9c32,add59940,1f700ca,16003011,26e6a692,36b56a64,f7d093e0,7d179861,871f36f1,58d26987,1775f082,a2fbfa69,27cc2272,614fd95c) +,S(164f2aba,837cac12,19b48eb3,30f02141,d3a89921,1cdb3f78,fe17133f,e2de29ce,3bc05608,95f7d034,4a9ec79e,b821c06,c2837c50,66925197,2c076374,871d28dc) +,S(c77a3a04,2a86d2e,f512268b,35cbb89d,e6a210ea,883e2283,ec59fec5,12e725f4,2ebcd56b,edf1a07f,e587e592,8ed602b3,6d1db4e2,5b49e914,8dc9eedc,131cfba2) +,S(e2defa1,f714cf71,557a3f1d,71c6abe8,11df5504,da38e9f,60ad335,3b11349,5ed64303,7a53bbc7,2f41912e,a657d944,c5107da,3b9ab54b,d88b545a,e045f229) +,S(ee2d12cb,b4cd9e4c,163fca1e,5a4330af,35280ce9,cc1d57b2,d2112443,b6313e3c,e28b1dc1,a4377c65,838ecafa,bfffb696,4057fb6f,dd4baf08,49f9223a,ee153262) +,S(4392c96,73e6deca,f3c39c34,f5be7c3d,a2109b45,2271467c,78f256d6,7d9e28bd,7fe4c183,ae352533,b049edd5,343a6bb4,747d63d7,d0f406fd,5902a886,110c50) +,S(5972e2ee,167374ad,93a655f1,6008f49a,f5586b2,f81197a6,712ff31c,a0d6960,6d70fc55,d0a57c74,8a2e485a,d903bd72,779343fc,7c090847,bc3dec1a,6f7c71d6) +,S(a85d800a,fc2c0315,889f1faa,29e5766a,a180f31a,400e3c19,85589af0,302c78aa,7429d7f4,903c76a0,a4437b41,92865b7a,ff5aca7a,52dd32a5,8f8b00d,b97ec85e) +,S(c9836b0f,d594fcc,9a89e85d,7d506386,ccee3f38,72759cdc,9548569f,a5f1c245,9f0b1926,93b7fed6,2f1a7d06,fd716727,bed1c2c5,9bb431ed,943b7082,d094fac0) +,S(ca2184fd,b2b84654,d0348e5f,6d963193,75f2c441,ae64622b,588cae7f,d202bd3b,d1222820,3d657aac,493dbb2,fe9729b9,e2563cc8,1f671626,83c4f0fd,726a4de9) +,S(9e0515c6,3c9b9664,8762704,80605d56,b5dea0cc,c7a4c66b,44a2e605,36941fd8,29de3224,a2eb2d86,afef789e,2dba061e,95f0b762,117ede50,6d4b21c9,54be831a) +,S(42042c25,33203a7f,c22cf7a,fa5f3d79,8a3447da,51d66f60,53a8f000,af5dc1cc,f075a67a,6d6c3872,315420d5,bc13d13,c54f3c1d,61f73d9d,ff688da7,f5e6c05a) +,S(6645a1bd,4eab02be,45884ffd,288955fe,3f5a68ca,9ae431bc,cd3967c7,12295b96,231f79f9,1d264ed4,28ed4b30,f0e92c4c,bf902865,24050b67,30cccd12,bb84cfad) +,S(4e281e6d,2c316e88,231482ab,1587de37,6898f3a8,870f475f,30bd1ee8,d4b32f9f,f48cadc8,1c119edd,e5f78062,cddc3416,c3f708d5,f37e4910,11ef7581,c065602c) +,S(77236414,96e41e9f,f13c7ffb,c7a66203,4fbaf7d3,e432ce02,fcd54ef0,4aaf5136,222e0174,d6cc01e,fb4b4bf2,9000f697,98bec7a0,657f328c,80083074,242dd218) +,S(3f2b704c,8d467859,ada6070c,b1221840,18ab009f,f7b5ebdd,af31d977,dd45860,a47167a5,146aeb5e,8c38dd21,5d61a2df,e2b6ab8b,fd05ea9f,b59faea8,3b4dd88a) +,S(794ec130,d243d811,2ebb70f0,35f983db,84b3acd0,ae4c5b51,640b9e92,ecad4146,49edecbe,95c25c7c,eeca537f,937aef5c,658f2dd5,d8c0de71,c80777aa,d07be84d) +,S(750ff9ec,e363e12b,79b04cf4,a7b1c0b1,49c554cd,6e9fe3ba,808c9614,95a96aa3,5a28269d,d1c5a3ed,f4e70f14,9a060b42,2d4474bf,1e4c6dfb,2de1502f,7a1d59a9) +,S(d65c05d7,df6668ec,b96c9ec1,fd129462,263b082c,9b7f4169,6335fb2a,b66272cf,d7728c5,1c10d42d,242cc5b7,fc77fdad,7e48be06,6b2f7c37,891ba4f0,de188839) +,S(d3804cb6,8cb2e9e9,b5b9d270,db9a172,aecffe39,72a3d2f6,1225bef5,595190c3,11fb350c,9568648b,30af4131,46053428,2879023e,6ff0d613,482c2471,b5e30d5e) +,S(f762de26,35c6349f,6cc95c61,9ecf8d37,6a938241,1106db3d,b34e9e84,70351bf6,dc67f9e0,c8a50f9e,e753352d,a99112e4,ccfe22d,3e88410b,1cadc0ba,bc9fd814) +,S(ab18b4bf,a827ff4b,17ee163e,d17e3927,d7dcecee,ba87ce7d,ac5e5767,53b87a71,6db83bd5,73e40926,c882bc09,c4d07f72,29706d1c,d2b1ded5,b57ea9b9,2b0da919) +,S(f754c248,fec21ae8,da343a87,459622a,b12478ad,8f63ad8b,f5c66695,198c95e,2cfb76a2,5f9c8776,b848d8e6,7f544774,e056ca7a,32bbae52,93b27992,6052b1bd) +,S(f8d9473e,3c3f0798,f893ecdb,716bca16,103516c3,1341c8e2,c2462d4f,9a46c51c,55f0065f,a422fe3a,26b314da,c7547835,5c53bd3b,e11b4686,9e05be92,d7924e02) +,S(8639942,d294cbc8,9a75fa22,5b29fda9,2f7c5ab4,bfbc4395,352d050d,754eb741,3913ea2a,445de35a,36d79abd,db3ed7cf,741da883,4cb81c29,6779d8a9,e7d11e4d) +,S(2a588c6c,706a388b,f1719230,b5a71b4a,6857282,83aec61,794d1a78,bb95d5c2,af25ed77,1a56f6d9,6407f07e,a7e11f97,61f458ae,bfbb1b00,96842c4b,6cc47592) +,S(137bd1ee,8931b9a8,b26dba4a,d9a5edb0,a5459717,22e1fe3,37ee8d54,20a0cb6,cde9fb7b,8197c77d,273e9f0e,e87d76a1,eaea105e,21154b7f,f5848a30,17ceea62) +,S(46580345,c686313c,97152371,13af2c2a,f9b5fea,a1e0bb48,d21bbe32,d2de2bbf,75bc5d7b,b6329ffb,2bfbc79d,b66f4c2a,7edade8e,a16bb051,a3a8ee9,ec92ef64) +,S(4a149252,afaf5acd,982fc491,c26af545,2ef93d6,1b282a85,56d5ef64,391bd233,fbc100bc,10b55b60,96656ea3,863f5d4b,bb9e83fc,5a25e59a,3b53d78f,60cfe285) +,S(894ebda6,fc0bcf8f,e025131,3475d64b,95bdf089,7d9753fa,ad0f92f2,15a01f18,b25f3150,155772cf,c69d0251,97d37ae0,1e4ede02,e2994377,9fae26cf,5f5ec056) +,S(e70d8a93,a91b891,30def1b2,bfd720ac,2deedca6,f9e5a85a,3c2a6eae,45eb032e,bd3aee53,a3b0ff6b,45fb96ea,4911cb02,fe102681,878a1b0a,693fdf11,4cd9f9cc) +,S(7cb1fdc3,e5ccb1dd,4a16765b,f9546b6a,1189883f,135d447e,eb245fbb,4eb36852,90ee0d6,becf5ff7,b80edbe1,75dbf258,d1889008,a8fed4e0,1968e2ca,8fca582d) +,S(51278ad8,331da17,8fc90a21,432b9058,b39f57d0,31210685,bf9bfbc2,87b9bfc1,5aaf547,f39ce678,8c3ad759,b25db3e5,7bc1f9e1,f75bc040,536ddce9,d3a66b6f) +,S(f0eeaa1f,c52b3068,48b56308,22fcf0f3,fee5008,54e276ce,e9fe9904,54f59cdd,90ff89b,944d70bd,eb5e5e01,6afbeb30,d51cf7fa,81182e63,ab3bb2c9,f2124f02) +,S(36fc9bf2,8bf90fd2,613670c2,27b51c00,df5b4caf,252b5df6,648ddb6b,3aeea71,887c3876,f1ac6c28,606c8161,4ddbbbe7,d975ecc6,9fd9075e,13d0e3a3,e7836683) +,S(6e31e26b,cf9436c,e14d2d04,1c29f62e,135c549d,5e65bacd,ba4df2a8,9b91b68b,2389684,9e63bdaa,b5f7d9f7,7a778b31,94c1af87,d09a9a85,85896188,acd0e7ae) +,S(c5044649,a4b1c2bf,ac6a8a1c,ead33aa0,3da9fad8,4f742eac,35792672,1d98e864,6d2602d2,83e696bb,717d1327,cc1143b,45fdc84d,b8d400af,537b201d,a7a1027b) +,S(a933e71,f13c44d5,bda8e963,b5a007bb,b9b2e84c,c45211e6,eca804ec,6a99ca28,931bf3bc,ec45e2f6,e6571207,31d42fdc,c3ce0279,542114f5,c1c0f659,f6200faa) +,S(9003f61d,840c2d62,1ba98884,e117038b,b8559d0,b132a1aa,83adf65d,f8e4a58b,50c75124,f72b3952,9feb7ece,cba26854,1388a1ac,73631532,b67f56dc,e8d30895) +,S(fc807c18,3cb370cc,8638abdf,c17281a6,914e21a9,e9f3e2c5,33fb7c37,caa0a886,3ac79d3e,75ac1d5b,a9af7263,9d564256,1ccf6fd0,6b8d2cde,e9d24a1b,e8af00ba) +,S(3d072ae4,aca4ac23,b43b608f,150bcd4b,cd780dae,7e4073c1,86293cce,dfee9cbd,6d9e443,f721c9f8,a98fc563,8d7627,f9c60414,67da3857,92fd55d2,7e65d9b6) +,S(d0cb8594,7061b4a7,d2bc5eed,522faf8b,ba6e26bc,7acb1d3d,106aabd9,a7f80dc0,fbfd0f26,e9d0dcc1,a0107b82,d1a9876b,8d7562f1,41f0892c,9b739e47,7b012e0a) +,S(e4edc0ab,6416c644,1e59f46c,c7221cc0,267aadac,242cee32,41a6d25b,635bc9fd,f41c3ae9,cea7b4c4,4834482,980807d1,c496fd4e,bb06964,b84c1fc3,4fcdc71e) +,S(6233b50b,2d3d9101,8f5a83c8,84be0f5e,ffb80641,1b0b5271,557d32ab,dd7eb4b2,8dfaad24,ffdd2ac2,5770f21e,328588b1,34a3a2b,dda40399,7911ef19,855dbcc5) +,S(6ca00162,e27265e2,27b4e544,7e981f6b,c427e65e,bde295df,9434b7dc,52a19ab5,d33f5f63,a8f227e0,a43fe297,babb3a07,223e8916,e153a5c,e0f57e65,1154cce1) +,S(c01205aa,5d2a8d5d,c0d328ae,7ce7cb16,d6c9d992,8b6105b3,cd68666e,36fefcfc,b65e5f99,c4f48095,e1bd6f6f,6af8ba7e,cf2988ab,ffa9bb45,3ad01859,e831d3e) +,S(e3965393,e6268cb,61d6fb19,58050f39,7b8a597,4a6c4abb,4e0b78d2,dae0e155,1f78ad46,2ed6e1d9,18004892,85383b2c,3f971fa5,cda0c828,a2f289bf,80731737) +,S(27bfd0f3,702a9d43,50c1a6,9fd990fd,3dc03af8,50bd84f8,1248222,6cb099ce,22e16b60,e8caaebd,19b0c0bc,e40be7c0,c49fd3f0,d9094f39,fec1b1c,bc643de8) +,S(8210fbc0,23319565,9eec1777,12997a89,2a37172c,6f75e3c6,cbf080a0,6f96a2f0,1ddd7792,101166cb,bb11d552,85e1eeb3,bfacbb25,6d1a5097,16dea91e,46afee8d) +,S(15cc66b6,5fcbbd80,df15298a,25e2ff80,ae4d5065,f8befab0,89cd21a7,4e347b5e,944b47e9,35748296,deb324c9,f5616d28,7b225b34,488fb34b,6ddacd32,7937c97) +,S(eb7b7aa2,45960169,1ea1a482,a9e6c35e,c7bb08fc,726c2c4b,ff801ae0,94c97976,4d2e9570,cc187791,fcbd20e9,3f0656a,f5596f4e,104c3f2,27c23f82,2ed1b1f6) +,S(4598fafc,ed29e844,c22436e0,996a8469,18e7c106,b40a5ea1,5fb0e7df,5e9ba12c,e73d96b6,d292ea2c,39779dfe,7f716609,978a8555,e5b09629,7dce228f,f35e6093) +,S(49835a86,3612e594,572a2591,76f90e18,e57d4dfc,1910c705,8e37eeb3,1a8600f7,3b7613a,fbd2cc1,cc23b147,e0e80d36,464c08a2,e488d7b9,8250ed37,dfcfa531) +,S(3a6d6fed,1fcc8067,32a3177b,4dbdc33,3cbfe0b7,d19305b9,965916f7,ce335351,cc3f3d8a,314d617f,148a6706,d7f10641,11eb2b56,1bd1dd0d,f2986925,5a6624ea) +,S(21208586,6860fe30,ce92d2ef,b2035b74,f672a024,ee7baa78,fb0d6c7b,3ad7a9f5,aaf145be,51b1ec,3fee8be1,1f6e9d73,96ff0ce3,41f25d7c,e1074a09,78bebbb7) +,S(f819132a,c9bb2f09,663d609c,51cb11b9,833ac082,6ceffcc8,67cda04d,266e4e06,b1fde638,ec6a305c,aaffd1a0,6404aeec,c52f48ef,7646abb3,7e227239,4c891de5) +,S(536c05d8,8786640c,43734d72,aed62d9,168385a1,213c4428,423a9437,c2ec009d,7f4be100,d827de18,68bc2b43,c83a08c5,fd84ddee,1fa9ef13,4b489325,db6df0d5) +,S(4328123e,c4c6db76,37ee3ed3,42c8a859,9de2fb1,a39a24bd,650b73ba,a1df722b,81c002ea,1277753,e6a22fa7,1b4f86f5,4ee11f10,f5d5b15,94c9d7e9,63a40857) +,S(f3e156fe,f8529951,86a9e536,f985c1,6a85fc32,d50e9a08,1550da68,112a5f17,91ffd66b,56ff0e6f,65d67e83,c362b853,a2f441ce,7418d091,5d5dd09a,b48892d2) +,S(32ba7359,84e13f42,d2e8a716,a54c40ac,6645a1af,eaf030e6,8242a8d8,8b456cc9,67ffcf1e,1c32b150,a82ab317,8ef24c93,f055765c,9e7e6200,f868b183,bcb4c6f5) +,S(cb9c2b3a,43d105e,518674cf,64d8b4aa,9c868b93,18abbddd,ccabc0ac,59829311,1fc67ef2,233f076b,ded3ac47,99c859d1,834bea5f,bd2bd5db,242607ee,842b691f) +,S(e14f2858,b7bf7070,32349695,e09bcd3b,5effa957,abc19e85,6efa31bd,2e9234f0,3e04e49d,d3f3fd39,883cbc25,80d5ff06,cf8cbf0d,4a895761,f3cd15e4,dce08bdb) +,S(156beb7b,1c27b8e3,cc78113,c97ff026,74810dec,58409e01,d7b7388,87550d82,c711730a,80216ec8,352adf2f,d5939991,3a8e92c6,c16c17b,16e27a91,90bc5371) +,S(de5ea7e6,b9b46864,4b80e495,9a2ddaa1,a24a3399,f8039355,7b798b5b,2c55d600,8901a027,e6a823d2,dc0a9d24,e182cd52,b9b1de67,22b7f7d5,3a03c615,8cd48ee8) +,S(8eddd368,8bfaed46,25b7312e,7b2bf0ec,aea07414,a1281ade,b79b9e3f,ec17c3c7,2db43af9,26171d34,d5ca48a8,9223e57b,59b885b1,5c4f7231,6d8edb6c,7955da7b) +,S(5c971b6a,665ad1de,8fa489ae,22237ed9,87872e0f,ef95eb85,fb2ad3d7,f0b1d4e3,4d71f598,37c2af6f,af32ff7,42ba01d9,aa8d4d7b,302d39a6,c4fc693a,5f8b1f66) +,S(edfb253c,28212b6a,d5b66589,a2a8f1cd,bd3586ef,34254768,85cfb70a,46b9e228,3e5b6608,b7e81f69,b8cb26b8,4f306292,594e42e0,25134c1d,7f7b2a24,b2616c00) +,S(4395f24a,e127772c,db163dd4,e22574bb,d2373cc6,b2c67384,737c56b7,dd525c13,bac6e725,4c800c2c,64896913,df739574,676581dc,1b4447a,819be64c,10103526) +,S(81100ad5,73a766b7,f8913b64,b5f5a87f,8c782353,5f62a3eb,182f0ff1,946866f5,52cac16e,325b0899,9d068f7d,51dd9d5,c6afb8ba,9870a9c9,d28b4170,e9a00c73) +,S(fd3a0551,41168146,6ae358c3,aa14216d,dee3a05e,e5ddee40,7f72347b,eb95120f,2af2f30d,45ceb12a,b89b7b88,b7e04b20,11a3c607,58ce7250,e4c7bcd3,da8ee5b7) +,S(17a55b58,a7eceefa,3ff05b6d,fa17d6c2,76d1a032,abd198fa,4e3fc3ef,e6435ff9,d7273958,a3ad67c1,fdcee72,e71f0536,418f35a4,57e06240,bc99bf71,b9574d4f) +,S(870cb7b8,e2ca5ea0,8c5c73ae,e15e8b22,793fd005,5ed7003b,c49b4089,3b789b6d,c33c8b40,7b701caf,26d7a9bc,e22644a9,4badbec,ad509cc6,a7b0ee04,1be67aa3) +,S(f951c5fc,dc46ef00,adc53c89,a50ca0a7,ffbf7c36,d80e4897,5452cc1b,4e71f8a7,6ae2f821,7849cc24,30864d7d,24df9e59,c1705b92,5792e648,75120738,c792c95f) +,S(aeb8077f,3b92c676,ae11bb06,a18ada3f,6cbd832a,1637ed61,31e4902c,96a0caf1,29f41d1d,f5d4a430,94e75fb9,8bf317ff,6c8a6d7d,b37ccfd,e0232e1e,afcc1e35) +,S(d46f4d97,5d2f2e58,6d18a7e,5d8587c3,8482b78b,595de60c,b9d2035f,313b78f9,95d781aa,3bdc1176,396154ef,31fee42,f704e199,4316e33c,1053491a,e86392f0) +,S(6afb44,4b4bd89f,2e21b54a,c49b9ec3,af810b97,73c76eaf,4f3a5f1c,7a29b201,3502901f,d7d3b4ce,134ed90d,1388ab37,64db460d,bed334e,af061822,6ebf932f) +,S(5f02e582,a38b1703,a7bf6086,9587af5d,e6634954,cfaf8394,932f7ed,ebd86976,a0487cde,92f3a796,b24b06bf,740b8fe2,ccfa5d0c,a2b68a7d,ef46a005,2d7afec2) +,S(26427482,60432ced,5a07b885,f354667f,ad70eb75,9c556e33,c6652d3a,a0599fe,119238fe,2560382f,d76ea737,9340453b,a63867cf,6e044c62,949f858e,b828ce85) +,S(6b2a3e5a,d327adda,52b19a7d,d5e837ed,4f03a5a7,e1e5b7ff,2cd66660,469f91dc,2f9f4526,6b482fa,f336560,1da9e945,354ed265,e8d7e57a,22f04bce,8a54c6d9) +,S(2588b88b,7e214fba,ab10934d,def13e8a,e5fbaf77,d7497dc4,fcc0345c,435daa79,3e5cf90b,d3ba6d4c,8d7f142c,ef1a51da,61ca644f,acba35e1,51ebc114,c5435bbf) +,S(d9484146,92852eef,fa8178b4,a01404a,e4e3d846,c20c3fcb,cff5cff9,de551a93,d5b0fd7f,e628c427,434a1219,6ad99862,13ea0abd,969864cc,dbb8258b,96a6d5a4) +,S(5cf81fdc,3a2f2087,cb64b1c,9b6f4754,5ccc1e78,67cee5eb,9fe9c4ea,3b0de2ff,e0b0ab1c,f6bb8e5d,f7ddc700,5ec73471,e7ff3125,daf113,1b78fb8c,15bc0d7d) +,S(41b4ef7e,b719fdb5,704b3f17,4132c694,f8ed2471,1677a320,3b866660,dbe879a7,a6fe65b1,cbae2235,cda8b459,eeac19a4,9f44c2aa,1c8a881a,e12093b8,3621c85f) +,S(43ed572c,41f691e2,a8dd1691,86404ec8,7a4c0a3f,406f3bdc,5c2709a9,bb117af7,b7b9e1b8,90b40334,6bacbbab,7be4d477,90a2b093,dafbac3,fd4d2073,fa481da3) +,S(4e010a19,223086a6,314bb526,2f1955e,81722b41,e85fae42,1c338e46,1b397de3,f0d3f11c,3475ed8,44876e7b,3bd0bb8c,283b44e3,70c46ec4,a6159a27,eba65fa2) +,S(b3609cbb,7fc86bcc,4dbc385e,81edcd84,45e15d2a,7d355e22,41dd442f,ee11f36b,8607e5ac,a3df34ff,804017dc,977bba88,c308911a,aa1698e2,e6190c8,dc9c5f68) +,S(445e60b2,543fbd3,7bd68cdf,6db1125e,d1bdd6b6,b27249d1,df96e43e,df965b4e,a5fa458a,8c4ab47a,bebfdc7c,f922e713,c65f8b52,287a65b0,b5dcf0b,c7715fd1) +,S(709f8227,9264c99f,86b59a7b,ef14c189,be875b49,e00cb64c,f9dbb643,10f50fc9,168027f0,cd28d2be,8a69064b,468e4de5,3d4903ff,faaaf628,83f15031,58960d10) +,S(62aa200d,cbd1240b,a252e725,a333f21c,8a2e9d5e,fbf18cdb,e1567ff9,29fb4ba3,19aafd6c,7017bdbc,4b906b46,843e41ac,1ec3282b,12dee1b7,b18e3f28,9e0a1347) +,S(2ba73958,8ed54646,fa9f2389,802e2ab9,e123987f,c881ae11,f38f10ac,b882c09e,f37daa1c,9c0a98ae,f86cc45d,34801353,d8f8a193,77518423,721f3e12,375a25a6) +,S(8672b9cc,e8fbb69a,ae5c0f54,9b59dfe1,e266e9e0,3592a397,7314e6f,79005de8,20d8476a,efb61c79,adcaac68,fbf9eae,c411e875,a66b5aa3,99a97a86,9b05af65) +,S(334cb002,84202999,79fdbac1,5ee5c17,1f32bee6,133300ed,a26571e8,bdab6ab5,8827d99f,3da7878f,46b45bfd,579c5cb8,e4e972b6,49d6438d,96e5a188,5aa574d4) +,S(32b30e07,d260ec07,354cad6a,2f64f81c,e9f25f4e,47bf1afe,602f229a,35ac6d4d,71ffcf0d,64ee9078,6f290418,1126c44e,5c5e3688,f3063941,85660874,3c3c0427) +,S(e5099658,7a4b4e63,43e401ff,299e9bfb,3b5ce402,5c38fa05,761e600,a39a8451,7b0382a8,65429a86,94eacccf,5c6b3380,683a3916,70fc7241,f132c465,b3bb2ece) +,S(b3872c4c,2bf539bc,e0aea035,3b3d786d,ca684121,29db66ab,d316e930,e5d6477d,7ce04af,e4c8c86f,3b37ed1f,a9dd4161,59391c71,22d0f4f9,2424d090,901e285) +,S(d2b56fdf,9156e3ab,2e414d96,49f4c418,6095e74,a2df8908,f3b406de,9935d07b,443c2c1b,67668c56,a84b4925,946a8e5f,b06a33af,371552aa,adc3b500,efe3b23f) +,S(f69867e,1074c765,923f32e1,ec9f41b3,4e8288fd,62b0a081,15db15a9,f37fbacb,fd6c6e25,2a11a516,9ce04c6e,d719c22b,68709be7,6fdd0e58,cd0505c6,413fca16) +,S(bc1830b4,a9ab11c1,ad8778c8,688fccec,cae23898,555b6579,62670d8a,b9e64988,b6244089,f3c46133,1979a0fa,f3d0c8f2,8e95cdcb,12db9ea5,b6d95ac4,c22e3c81) +,S(fabaae21,dc729fda,98c4bbe8,3cd5fb92,126cfa1e,a21f43b7,445e4b47,f38dbafc,1b569775,64465832,c73513b3,ed6aed9f,177ce1ba,b2c09fbc,c4c33600,582d8cdc) +,S(93386101,4d5d4c3d,f912497e,a248d8e3,bcd3fc03,216dd57b,5473d96d,791f8bd4,3d8fc96a,c141163c,4ff3add5,44a6ad71,9e57f22b,8e806d95,1d630fa3,6c936725) +,S(c5312d5f,85c42820,59546b8e,ec6b186e,da0a4324,d30147f2,94a83fe,a6fd07f8,f8ae6e2a,79ba0756,523be12c,8d544734,332898e8,b35b651b,edaf806c,45d2992f) +,S(a08f2496,52c52f40,6db75c4d,da022f41,b73b1128,11aa7388,558480b5,f203b057,a396c7de,9ab5e1d9,5e9aa925,1ecfe3ca,191d7a25,37c4cccc,845dc745,2f3eb2e5) +,S(93d5330f,e8df6fa6,a74b34f,a251a6,a036e0b5,89b8a05b,c525e4bd,40f634df,ca15faea,10f424e5,5d6774f7,7c87da28,c4df567,7d153a08,f5ac560b,71838756) +,S(4622bcc,dfcab72b,e850a994,1f652110,5c35b813,f05a4f6,17055f92,aab51fa2,d960702d,31eeb256,d25cd245,695b53c8,e883d2a4,60965a8c,d29b41e9,d7ca2d4f) +,S(a326036c,7dd885d9,94ba5872,8138c30d,fb6c83e,d17c8d88,7aee086,e0ef9fe5,b465ce69,3719a155,31caafcd,e7689a17,456a6ce1,c75e5a53,4893cd67,32cb9bf7) +,S(2354417e,19637e79,71b0c887,bfa5c553,f3d5e7a9,84a6c946,b1d20b5a,7eef77a5,815a9721,b6ead3cb,b254fbf9,9f34f409,ea740053,3cf4ed4d,2169f48b,29f4bd4b) +,S(9d346d6d,fc53174f,5cda746b,23810d7,3a407819,ddd5df9f,2b07cc8b,b7ce6fca,9b6cc06b,64293e5c,a55a8ff9,f1e90551,4a199b03,df08e9b9,8512b357,9776c806) +,S(73c82b8e,c643a7b7,f95f000a,debe210f,bba638b4,5508564,bb5a3330,fd48dd01,fff15699,a0885c61,fe35f61b,84cb2bda,7d2acf5c,df0d6f07,5fff1369,805b614) +,S(902469d5,a0b2d5d1,cf931672,88506b95,f2d29bf,6ca291af,c9b39cbf,fc798ac8,356d011,d71c769d,342378bf,fcafe4ff,cd78addb,abe8b0d4,fa63de89,1fc3ade4) +,S(e670a0fb,3a0c86f0,53523afb,819b8944,dc4013e9,fd500371,b1efe23e,1f110637,869136b,cd13dcb2,157db5a3,d07e59ef,272557e0,9dcb250a,9bf659df,260b31b8) +,S(f3fef06d,526581e6,b0f68e27,cfb9cc9,b57f11e5,849545fc,b9ad3d5b,8a05c395,32b2e997,144420ec,c4c45176,efa5fbbd,570752d1,4b092f4,ff375544,19b8f553) +,S(72a37663,3958d844,560fc28a,8cc19d88,f942c09c,471d2cac,70ca5d39,396a05bd,de9b1b0e,6e121070,f684b3b8,402e8d8d,729ce846,d2f7ba8,503f4548,735ee1ad) +,S(38b78ad9,c43b7def,4119c3a8,190cde68,4172894f,a84cdae2,2b637bd8,805300b0,a181567,6c4f5f51,87204f17,5bff32e9,de7cc69,dc851c84,23de74a8,b3d01e6f) +,S(db968ac8,1d2e7c53,6c66fac9,e194fb23,540e2e89,8cbd3af,68e158ff,2b34752e,4d5c57ab,79d9972b,ac6b4af0,a6347271,4179e8e,fd14c769,a24e5a73,aab48a0a) +,S(2ace1679,2d3a4d83,71114f28,c1ed35b2,505dd4f9,97c72435,a145d367,a8aad318,5314312a,246874e4,cec63b87,f685f6d1,405b0ef,a1ae3539,cc88e73f,3626f625) +,S(32d80e69,c390ded,db8a4600,862727c4,bb1fda18,2563277e,852f93af,3dbae108,3c7d96f,ea89d06a,6d3cb3f8,181f7cdb,bc1c3e12,3d9f1d08,cbd557a9,60dc7c07) +,S(3ef49e8a,e7fe6b40,628e61a2,945db3cb,f1bf050d,e525d521,d8e8a408,76ee3908,4381c75c,62f45fb2,4d431b54,d63115af,3ff72d27,58c3c92b,d3d1de08,1a123f2) +,S(853808d5,cdb82cd0,39b517d4,1c88d7b0,e280ee6,59e5c640,5aa27542,3c9722da,c1677c44,9b2a9626,698a652f,81722242,3ed18d03,92d4200f,b4dc229f,5f7e8f5e) +,S(572fd483,490c05fe,857520bd,8861fccb,306ee4f3,29adef49,58c1db78,1fc8584f,82acc906,10392302,cf0107c0,6b3b6194,d38e9155,b31ebca0,be300036,3413f4a5) +,S(b1cbabb2,9aa8ca31,75aa9a2d,d4d956e4,fa771344,d4592481,38c93583,376e1386,888cc0f1,7f9afdf0,6ba1de03,41409c1,265cb2f6,c015fc,bc58d2dd,66292ec9) +,S(f856cb92,42393134,7580a65a,149a6e81,2c5c960d,670701a1,6ddbbb98,2f6bab20,c33511ba,192c00e9,991f580f,65c111df,77d9d6c2,d5d63869,c5595011,48536674) +,S(e1601cd4,773e129e,2c042887,b56bbb3b,9eed92fb,6c128e23,fffc3a7,ee73920e,180748c8,a38c7796,ee247c71,49ba1fcc,a78648c,a0508ec9,6f4a016f,301054ca) +,S(98ee20d4,5ffb6177,5ca206a5,b0cbf1d8,e8b37cab,97489534,a98928e3,367c7e72,2df4ace1,ea42db51,68ab5e6e,88fc405d,854b70e0,4521bc30,6978e465,6273c610) +,S(4796ca57,acde905a,31dcfe95,bedd1e13,5417bc41,f5acc246,ec0ad4ee,ddfe179f,7413f522,395a3802,b37637e5,9564c239,5bc565a3,463f815f,8ff962a1,f0a367a8) +,S(b367c864,38adb0b8,d5b627fd,56c7df9f,cfd55536,9abbdd40,6c68bdd,1a341200,c0364744,b99e816,7982f365,72268702,b4986cf5,c9c5749d,fd22499e,2e8fba51) +,S(db36884b,723ddecf,7e2244c0,20de844,e740760a,4f27d386,a747f4a7,88914d29,8ae487cc,2a743a3c,2a1e0750,7def0f2b,fef90e24,fda0e3b4,e5f3333,7d79e023) +,S(65971818,f71c212b,a8e45821,31eef4f9,76b4732e,6c6c3123,ccf5c6a0,99a316c4,415f6791,353350d3,3b087f39,13761119,526a2831,c70375db,4cd07754,e13604db) +,S(f2f4eb3a,13a8f4b2,42182a63,97eb6cd9,9053903f,961a1338,fcbccac7,60ebd65a,a575d67b,667e94d7,20adc8b7,4eab8ebc,18811b3f,3a3bcb6e,7950cafe,8ef9ca8) +,S(a24e7a0d,a058f0c6,3328fa51,fd3c927f,884b3f77,cc068a47,e8c6b4d3,1d113a49,be8db830,79aca569,9eb2fe3f,829719d5,bcee615,645e4c81,a9a7212f,450ef78b) +,S(e59a3ccb,77e11797,7db6cc32,5ebd5981,42212da7,48f0a4b8,981db72,41efad5a,a8e07545,fdda2668,cc0a10a2,2389a2d8,d6903416,a4a05299,9d4c2d4e,4a800d9) +,S(3191b263,a3c70be5,bec721f9,3dabe9c9,fc6c1a75,aaa94e9f,daf6060,fe4b8f32,339192cc,1c7a9bc7,2a9a87c4,ea3cbab0,c7af7b27,53e74491,717b1f99,5df38a96) +,S(63dd5fc6,4f9ddb0,8fd47e27,5e839b20,12f408e5,3c139463,8b97874f,9187023a,1af048b4,2e8b7e6,d456cccf,d12ef7ef,67e0910,4162239b,84f35cbc,8504bd9a) +,S(a92e457,cd8312ec,cb87229b,7f751c4b,2e1d8640,c2b8e5c1,2d3dbf4b,671bcf13,d7aedb56,5447eb5d,18449241,3a07d672,be46ab4f,3d5b4b3f,551f292e,5ffba768) +,S(1ee6b970,b9e09d22,2b20f02,14f00bb4,4789f55e,585f35ba,6c0dd6f8,39b10495,7c910fec,eff9eef5,d1a3c8a0,46252885,9dcf73bb,d4a0b2be,3f8d10e0,dc9e9462) +,S(b19c23b9,c2ac1957,5328d7c,43d04870,1abe9e97,30285ceb,e4fd1659,8f06a76a,79a811be,c07c8b70,6f380f8c,fe369e45,c605607c,d08c8a49,2745b283,37a38398) +,S(3c20db9f,9ed35fc2,7c0888f5,e266a455,4f3fbf98,b8b2a016,b1e9aef3,14f49a5,bb3ac294,3f29e63a,f610815a,4a1e5a12,9327c1b5,ccf489ea,7d8950e3,5bfbc4d5) +,S(fd1ccdba,b4746e9e,44eb5904,d338244,efa29ffc,8ce8014,f6b922c5,2eea4389,e1065546,52146f90,fa52439f,c43ce4eb,73961a52,10f6c040,97a82032,9a8df06e) +,S(e30fd18e,abdeb8a6,ef252dc7,3c2b0d75,83641a29,8db37ab5,1e2da099,9b64020c,49663672,1824f481,962bcab8,6716eb41,8e195d29,6afe9704,cfbc24c1,28dce88b) +,S(4bc1f789,26ddf930,e1aea784,83a9dc09,5cd72300,5540548,e6e217e7,515bda37,966b32b6,95dc1b00,8dcbfa2e,734bd9ab,36d8a26c,2a52c471,63a4cfcd,d200ca69) +,S(23d3e27b,9c864b8b,40f0f7d2,6ece9bc4,9004f98e,d46b539a,affffea1,54f036d4,be4617eb,f680a27c,cc4143d6,ac150d51,b3dfefbb,2892a6c7,1b36c794,8ac0b05d) +,S(28adcbd0,14cd3b70,f46e0a89,477b5cc0,4a513091,cb6c1aab,56de4894,3e6009c0,7c49a838,75204cca,38f250b4,608cfe4c,25040dc7,3ded4fda,f4a92cce,fce31601) +,S(776084b8,a86f0823,a5044ab8,70d84f60,ea52ec7b,a545ea0c,c86f219f,1ca29d08,60bbbecb,1048d250,b410bc38,49e567db,def17272,58570b2c,d0834532,581c60db) +,S(45df2e0f,fd32ef48,95d9667b,c6044951,e3db94b9,ed6af5fb,d4fe1e7d,228f2350,a732464b,1a8cfe06,69e4076e,d4164b98,4de155cb,68bb3994,73fd7918,63eaf095) +,S(6904976b,46a5fd1f,a74bff80,c493a2fc,8ae9bbe8,783cfebe,7f69f0e1,be7dd7ea,19d071b8,df9d1436,6241a22,1a00b340,30f1df45,5e66fcfd,5ad621ae,ca2c3e64) +,S(849d8728,f977d075,a8de805c,8e80980f,e01def35,1ee80f0b,ef528e85,29aef659,d84955c4,6c886283,b9d7adad,bc069d0d,8042dd9a,ec7246ff,edf31594,ae5bf428) +,S(e3d64b4c,234506e6,e7facec,8d7534ac,54588dc7,ea685281,e27c6746,472d58eb,4a32ad3c,cf822a84,74447baf,68aea598,11a9c839,4c9970ef,bc61f363,ae5a36eb) +,S(f41c7928,57d15a31,19b6f132,3b67639a,889877aa,e9213ece,c787d53,5463bbaa,73cfcd0e,c84c55,4d007594,152d9ddc,630c458e,7ea456d0,7cc60503,794d9328) +,S(e1d21747,47ab84c,e47a4a02,caed939f,e0cba1c,41e7b21d,67f52fd7,79186079,17b0b628,aa4bc0a3,ed9728a3,e24a8101,fb26da66,9ac92f63,af81aafe,7db2b668) +,S(a8a0018a,f8f86795,3189da2d,d52b4db0,5d7ddb4b,8d290c80,95a8e7dc,d86ef1d8,8bb9606c,84b88a1e,df980c7e,9360823e,25b927d7,9cab4c17,fc8aba7d,6826518b) +,S(7383c671,6ee05e44,daba57c0,50ebda60,e4e0c0e1,3df338f4,cd8d627f,736fffed,3bdcb946,5f164a74,638cb973,fc77daaf,38eafd48,9521cba0,4ad896c,8e89f0e0) +,S(61fa7e1c,8bc8ac97,96be6431,20858063,1ca36af4,520cc1e,858f90b,ad372dfd,3f0d6768,36c3e694,32287909,c8841de0,a5f646b0,94b0c207,8d634486,c3eba33d) +,S(86029e2b,ca0ac601,99092def,cf4882a8,b4f14349,43bf116d,3cb310a3,b2c4a740,b8be906e,cd9056f0,f3261cff,d12216c8,ef5f1553,dd708480,15463b7d,241c2f7c) +,S(e172f7e5,912aa487,589d6c4c,d0d6b9ab,48c4a6b0,5fc5f90e,2f6474c0,4fad95cc,edbd23c1,2b0a0ed3,b899920c,e8b64d7d,d7bfd79,5009c290,ea0673dc,8acc401) +,S(7986ba8d,322efc24,8b7b22ab,f838de93,2d931c78,cd6a8616,d1f37dbe,32873494,693eab22,4c750592,319b7544,d29fe0c,2420a5d3,d3b7e01e,e6ebc968,12a13634) +,S(ba594138,4a727673,7600a6d8,8d36b133,400bb5d3,6a8a9d46,3e8c65c,e1e00383,746f4e28,bc1b812b,227fc953,531058bf,d9c68545,2f6219bd,86799dbf,3c2ce557) +,S(45ff41c9,92d6b117,c86eeb77,bb17789f,6bf96cd7,2cf0c6b9,802af869,20476c8f,9324f5bf,6422e3ae,2010c9e1,27167d8,4f522e86,87fc95cb,ec3d6972,2002b59f) +,S(bad79e35,487a4da0,7171c282,e8666ed4,d00bada4,d9576a7d,9a93ecc3,c16ed68f,19397a2e,efb184a4,31a02e12,91db0cd4,5b153517,9038a920,7a6d50dc,787b57d2) +,S(ddfe2107,2d8875ec,60c4d583,59755bfc,22cf890d,d3665b79,cfa403bc,9e3c8a41,c62bd917,491d0a8a,9215674c,28c28872,8dbe0d3f,87c10d90,ce22b608,473f62e7) +,S(925f6a53,c07f923f,968ccadf,bef9d95c,d7594269,a3d9fa64,b1180edb,667eb299,1080e8ff,1f918e6,6f08b26b,7f9cee48,58f00038,b8ca50b7,b2939960,b1e7809c) +,S(c28e49dd,a75f0283,38e5d2c7,d1f03af0,12768bd0,6b0e0d0d,87878ba8,2720dd80,670f8989,c941a49b,cc512c5b,4987e167,ec5ae6b4,d7f68a98,331845ab,5d0db12b) +,S(7a9053e,95035be8,8188c196,d5e8e05a,b21dae48,d59406f3,7b9f86ca,2c837cbb,40ee088e,8e7694b7,994774e7,9d097d76,6de026f6,f7fbe352,e7f2bd0f,443a7e1c) +,S(33af78ea,bfbb00c5,4d88ef81,e9661b16,e0b32c85,a1b61b95,6c6a79fd,e036aa2,713e7aaf,537a796,c4d79644,c855d0b,15331988,5ef4629,d8048c69,d3cfd3c0) +,S(c588d014,5a3f3d33,29695573,96d674c3,1326dfa4,797d63d,f9a0c720,49583bd0,b5c0cfd1,6c67cdad,ababaa8f,cfd2cd76,7f747024,8caf60d7,37531c66,ac53cdfa) +,S(96b3d5ed,b93742c6,7c48ef12,c649341b,97223f22,1f0edd5a,2f2ab523,8038d29e,db475caa,38a3a05d,3719a2e6,4ce7b4ed,bf25fe57,4b28d6aa,9961ec0c,b0e44c4e) +,S(412f4b6e,3d894ee6,fb0cb00b,14662a9c,1eea3a42,5a286782,a62da77f,5644f0c7,a84ef636,ab9bc805,bffde813,93874429,a8503e89,8c03f1d6,f139af86,f6a676fe) +,S(25f0a785,c7b43028,52f1421d,a32c418d,32fdfdc4,89c39049,3794e1fa,e4563252,efeb090d,457190b5,89c953a3,aebef406,da716af5,1dc6e334,a0226883,6004e4bc) +,S(50fd4ab7,f367faf4,acb4403a,49ea3e7f,f02fed58,4327acfd,e0bd58a4,ed741c6f,78abc1a7,3c9dcd48,6520cb52,adb1c3a,2d08abcf,a079607e,a56307c6,3d46dd5f) +,S(157583d4,cfaf7f79,33b8fa66,430f107e,c357621f,4b94f313,bbcfbed1,46a477a,9aa6b235,ce8cd1fe,60cd4355,c46d4859,fe35ed8d,659d2aaf,fc09cdea,297e8db5) +,S(3c44bb62,5d262603,e44affc1,65b35976,f2edcedf,8be6b494,f4b3bc4a,5b3300be,88b1c561,67973ab8,5ecd4594,90598152,1ef0e8c7,1ff707b9,79ec2bf,3cbc2535) +,S(31d4264d,e1606b97,f2f71d19,33f23cc4,8fc5d9c6,e087dd93,5ee25b8f,ba298958,460609c0,a3aa1d26,2865180c,98555b98,c8e41db6,2e62b2c4,4ae01190,718251cb) +,S(1f551f0a,8ff14724,60ab206d,3dc1834b,352d1d1d,80a8fb78,a87247ae,5d03ad2f,24253c06,a4c8b148,db944f81,802bee34,fcb97ab6,50957b32,eccea33e,c116a6e3) +,S(de2c4e1d,27f08407,31334311,9ff5a8c4,206a1f73,2aaec3a8,7aab6bb5,c1cf333e,dc813ba1,40fecd3a,31ff4a8e,41fa498d,9226ca2a,cb2d5a71,c5a5cfe2,8195170d) +,S(6fdc5db2,adf54ac8,132c4a22,c382c2f0,c1f54bd1,8aed5620,a54bc4c1,18a95612,db3fa4e5,f318e94d,c0c11053,61d21643,cf60b0ca,a6dc4d26,944e8915,970e221e) +,S(c7eb76c6,ea0e1c51,a3aea6f4,dd7eba10,bb76650d,85df0fc,7fd77b73,53680603,5ae1c1d7,b788092a,3c41c3d,7bc32ef2,a4f4a39,a82b53e0,e6f47712,df5bf655) +,S(c81505a2,b7e78b5b,64ce048e,6312bfba,1a52c7b7,8219d857,b4813a98,c8aa89ed,46db2842,6d6ce211,5e1e49be,459f033d,c222be7f,96b247fa,87d5dfc0,df096806) +,S(cad75255,15f9c3d5,8705ff0d,83ac3508,f7dec312,bdc71c9,a17eb9e,78503bf8,32b36a02,76cfdb97,ecd2ddc7,638e4d61,6231be5,25b6b4c5,2d19c12c,6e6bd719) +,S(94d22144,e22b7e30,56eca8a4,7d6b15d8,f17f3c65,82533fab,c70e900d,be4cdd25,12c0760d,5fef2f85,d89dfbbd,bd0124cb,828bf72d,79b4ae5f,6121a84d,47d93bf9) +,S(325c5c23,ef00601f,ddf52040,7721bde2,13cba19f,c0f2e225,3b112b8b,916731a3,59d3cb98,c09c1643,993f3dd3,64c7d29,5cb38cb2,45d8f70e,9628e5ee,d62498e0) +,S(9c907089,544b8316,4a251516,81bdfda6,7d187438,3e7f4a7c,da96d861,91ee2318,f639dee7,e7010630,364539eb,5c225059,547117de,9fbe4911,d9718e6f,8372d20d) +,S(34f14807,ede9c06c,4cb2a1d8,97a4fb81,ec5544dc,eac1bfc0,f32f9835,302b7a82,78437a8c,ec6aa228,f5f18813,a68bde68,3c54c367,5d6be482,8d01f2a4,96d9c57) +,S(9498d30b,3f080828,e03d459a,fcb81fdd,490b47ff,c344d75,3887b600,1639788b,7a5c8305,b97abe3e,b241627d,c5187a9c,677865b3,567cfd2e,ce136852,e42522f7) +,S(eba08f6f,efd36e37,aa53ec32,d3cef88e,5d4f36ff,ebb978c8,76d452f5,7754f226,fe0e66b5,43aa54ca,7afeade9,b38cbe0b,39e17178,4d029470,608c7e38,bd2015c1) +,S(555d4bc2,bd21729,f6119b77,ae8c9bce,c8ef49bd,992cde50,4c794484,7240091b,cccebdb8,69521e33,2ca86941,593eb4a7,6c9052ff,a54f8315,d30119cc,7f437b54) +,S(33729b9c,19da3474,42f33833,d1723d45,3f3060ec,c692d823,679f087b,ffe8872,a94b6a4f,283af604,eb885405,6bfb8044,fac2f007,d7ebc800,b4abd64c,5c34fc30) +,S(2a1a889f,afe64678,647b060a,73ab92cf,78124ee0,d44c7c32,d8ae15e0,df1dc11,626f963d,3bf11f8e,686ba46b,e6dbbf0e,75aba0d0,7ef91218,98605ff3,fc8b75d8) +,S(4702854c,a303e6fc,ffc62f70,258bb2f5,639148b3,4e3927ff,f2dbcb0b,7c197d6f,7da261b2,8513257c,d1475c2d,e059372e,2da76eb3,f3b2c51,95c44447,d71e1156) +,S(7002edc5,a0cc23a0,65015cae,6e49e7b,51d90cfd,7da04e03,4857c596,cd319c5b,6f2845bd,6b7aa58,7ad2d2ae,19fd6115,78c47b56,84fc6975,db63e230,c3db73bb) +,S(273294d4,483d610d,b2169f05,71d5450f,f4cc5bc8,725d8ae6,7c1adf0b,6f48d485,99b241a2,ffec9e0,a039a003,18239aa2,a71e3cc1,1cfbb6d3,7268874b,67d942b1) +,S(1beccf82,3055b440,fad26a53,5a852a5d,710c72a,c4d28e83,b0335e8f,e98c9a69,f3ab566,ac0eee20,7c8ce0a4,d471eac,2c5db716,5e24b489,e2fde03f,7b8aecfc) +,S(dbe4eecf,4f033d53,5d949cae,c8fe672c,a1902323,77892197,fae8e192,53128160,b3f50bc7,927f0e5b,56241c72,24960fc5,896fc806,1c0a8a1f,5fd3d47c,d5aa566f) +,S(6643fc75,bed80c69,4591887a,5dc573ff,caf7f484,b0ae2631,133ecf4a,39bd1e20,4701285,f7ac7c93,bac1875f,dc4a26e3,8ec1e69c,293c3b7a,1f8b5c5f,878d58e5) +,S(99f90bde,cf1dcd5e,7158280,53f820e7,ef19d936,bca63f14,516342fe,5422a21,a04dfd30,6dfc615b,5390a86,8bebead6,5cfd7719,33f91e2a,180d2d79,b99cd4fd) +,S(54e7ce48,3184b7fe,45fb4e35,192b5678,bcf71f7e,49c033e,aad1dd32,86e33433,cac2833b,65ba9cb7,83a8b85c,b7f4e4e2,4d4f8546,3c6a2c3c,4decec88,14c0e8ef) +,S(cf864a4f,fb60993e,444f4e7b,8f4a9973,4705aa16,295627d3,1f7686b8,4bf02e08,7a98d20f,b736eb4d,465db874,ce98bdf1,6b8a1951,7744aa51,af276c7c,db6f1bde) +,S(6ff160d6,516fff91,5ae2cd45,7a98afe2,a2569345,60a7f26,c9e07212,6d59d1ae,5d1f1355,bf1410ac,e4f8b415,350f9c75,7db5d5ed,1f34de,aff5c197,b4eedc4a) +,S(9adba62,aefd2690,1d77f2a2,c6287da9,a56fe35b,3702da46,f231fe4c,9f5dfcc9,ba58ec45,cb4a359b,7126af,fd2c4bdd,2e708d43,41d96e7e,4825f153,abb04161) +,S(204ea41e,bbdcdc48,cd4ea945,72c10dfe,b5d90060,e9dcf5d6,52c0e2aa,14a2402d,7b2889ac,a1952f3c,b2c5db8a,9924a6fa,fb0b9e32,3ec09809,789f780b,ac36ae38) +,S(f7d6c669,364d3114,225a6826,c20d26ba,a4b4f190,e842696a,82aace97,5fc8ba22,15abb177,b42538c5,67d160,cb3c761b,1ff47cf4,4b0cbd16,36f67a5c,879d3470) +,S(7bc4d30a,87dd28c7,8b066e00,c02bd221,e50a7e64,45b57f0d,cb466f27,7d352587,f4ed4854,2e7e0164,da66e0c9,fcb04a1e,6efbc9c1,206b552e,c68cab96,d0c294d4) +,S(55442584,b046bee6,c245dfb9,59f20629,c200eb21,b42509d7,8564943b,1e316ef1,2e2aa971,c8111ed9,6666353a,103f2e4e,a29c4162,d19da280,905031a9,48580d82) +,S(8e7df8c0,de88903e,71224c97,3a8ca65a,923f872,841f2dcc,bcd69e64,b1dce1eb,e4153083,9ae86d51,e7147873,f1fba8db,c31205e2,34c94662,52ae43c1,25d2a0cc) +,S(672321dc,69d8aa18,25569d06,65fae079,b84a9bc9,35bda491,5d546f51,c651de8f,8ad6430b,8708897d,be809ab1,803a6eee,f977b1f1,6b34c188,d333d6f6,e7ef005f) +,S(f4e2bbc1,43e99b00,52032718,285d7698,1b8beb9a,f693dbfc,2d20f472,89ac3abc,e54990f5,dc330eab,2e722b7f,70cd426f,6d80e93e,205eba89,7eabf0b1,5d651a2a) +,S(5aa3aa5f,c6d2258c,907c7275,805c160a,72694f46,6b5fdad8,9134f1,d39ffff,22d72170,617eafa5,b843e82b,5f670cc2,3146aa98,cb07644a,7f4c0600,48ea9531) +,S(34752ff9,d2bf499a,c6b3acbd,1b78633c,9e9a31ea,45c34383,be3eb008,7be2e7ef,b53ea374,2cf3d886,51f7d076,3f67c8bb,39d73ca9,8306bedd,91a6db47,2c1104f8) +,S(d6502624,2ea44f7,d9b4c9b,5069e1c5,88977062,db2bad6b,51735366,27047327,52f5c99a,f2f2a8be,c034db3f,b573757e,d8014321,86db2c28,8c7151fc,4ab16f2d) +,S(52b3aec6,553d025f,d164a0e0,b1f39abd,915d4a9,ed5db2ac,b4593c30,11f4cc9,51547402,1c17b2bb,9d401683,931b25d7,77af18bc,e0e7bba2,432a7717,f4e2f8c9) +,S(8cbb677e,f7979224,12728418,68b79c12,eaa0ec6e,ba4f9b17,4d99547e,827ef9ca,a32809b8,b07e1312,b6a40ec6,411b60be,92974f98,bfedce19,ae590f98,40183f2) +,S(d8f55de0,e2eef17d,e94b1564,d74734b9,3f89f2d6,c317a248,7f1724e3,d531d47b,e9fd46f5,da576370,e0416f71,f271e64c,fa7dc64c,5e086930,523e92c,9ab7d770) +,S(fa6fc9bb,faa2b31f,f9d57301,4777169f,a4ddb8ed,ed4bab79,d0f4cf62,356b6fdb,b6ff57cd,dfdd790c,7aefd1e4,d4b111d8,43a2adcf,9f781b33,1b4420e0,f57d494) +,S(239f028c,e748edd9,69f752d9,abad0498,f9359017,653e6ae6,bb93f09d,61b58e9a,17dffeb7,8831f6ba,7ba463b7,bb7b142d,d55c8aa2,91bdaf7c,644e8ec,14f8b516) +,S(2ef6cbfb,728d976f,99c71db0,5389bba4,ecad3c14,8f2597bd,99af8f74,965e4f3b,19a27ba7,a382078c,3f1ebe8c,1d93a37b,deeef542,cf174273,b411b60f,79b0fd00) +,S(972d732b,9af8315e,88f042f1,3377871e,1a429247,d8537436,98b975d9,33064a0e,308153ba,ba4c3b87,40a380fe,e4bcbba2,a5c2ae3f,25fde1d4,f40af4db,aa4fd28b) +,S(3d378b34,ba4998f1,833aa295,185414be,e788bced,af422ed3,3c4f2747,6e062a4c,46a4559c,9217f919,80887b50,29f75c01,3c3d5238,d3758170,93eda1a8,f2c4c8a3) +,S(fbb2003b,1fc1b3aa,fd32b289,abe3b362,b13d70f2,7d6451e3,76bf882d,395c3087,97c866a5,c462362a,4ceb96bb,9c17db03,f28e5b1d,4e418a81,653a315c,4dfdabd) +,S(28fa94e,8eeab1fa,bd27a9,258e26c4,295efdb7,afb5a47e,6e14de8f,877a0471,f7619d0a,f2eee8f3,c0c7b5e2,8ce9d0f,62221919,4d1762a5,5145a909,9d23276) +,S(4708a285,7eb9c115,71627ede,6fa8fe29,4be27233,8798f25,c12cca0e,f9308ae9,f35f9964,2e773990,b2e0ab60,1a92cf56,85403466,87a8c35,50e36b91,ca4fa449) +,S(93408097,6ff4b874,d88903dc,b3ceed6e,a82427cb,36b62c6a,6364f2f8,9848a62f,e25a6962,d4e26764,9ab2d4fe,a0babf7,daf64d48,98bc60ae,ff3cfb63,e95f3c6f) +,S(f4a42ba0,818201ca,e3195da9,3a566623,9e0d24dd,256cbcac,3959dbc,720ddf9a,8fd26fcc,be3eff0,75d194af,e7391285,10bd4c8e,7230f96a,60fd27e0,a000f86) +,S(c5ada616,e65bcd40,cf39ef6,197e0a97,791cacef,b41b0991,9c51b166,e3a6240c,e4c65d68,fe41c62d,c85b0b32,39106ae9,cc26787a,60d351a0,4a7008a7,f96eb8c3) +,S(7c193ec3,d3f1d91b,cbd7c62e,5061a5a5,e8b1fa48,561102ba,ca2ae100,80c640e7,cc7cf895,511408f3,e400ff31,8a53685,3b8e068,1d4b333a,26b59cad,97873ccd) +,S(77542543,8e7cf128,32165629,3e6a1c19,22b76355,1ec716f1,d96002b0,ad1bd3c3,3747169d,212c37be,1906eec2,8860af9,edf7d932,c187c4,debbf800,8bd2137f) +,S(92dd5399,fa75e786,fa5c0f7f,90abd1a8,bb48ff43,e54dac5a,3b9990f6,27d90992,5cb1be8e,f93783e0,c2e5c824,ac6c5348,ee493231,9932e9a4,6e54921,3f11b7ba) +,S(c1770828,468eeb90,10b55053,2a532fe0,4f66e7a7,b7a1cb37,6eb6ddef,d693157d,da5643d,a0147d47,fd29e262,f61ae4a2,70e5e9a,77a76bc2,d2e7d24a,819a2e11) +,S(1372e116,e90ae522,4649a534,111392fd,a8baabe5,be8a8ad5,33cfddcc,af6378c8,5efbd4a2,695775bb,dc38c2aa,f8da6f45,1d0a1cf3,2bc584d6,e9b2b6e5,c8346af9) +,S(2bbdf21e,9fa1a2b2,bcd52009,7f30929d,5e2b7fa,e1038c00,8f32d86a,65dda936,51b78998,6008bddc,616c0dcd,2a883361,1806ebcc,5843b64c,b0ba02c9,339d45ec) +,S(36694ca4,d0495ed7,78230d49,e6f21217,9b63cc7c,26ee3f7f,6a7438bd,753005e1,2e49e3f3,bbdcb133,3ff1e17d,b18d5267,a87f48b6,95b5f907,5f5aa0d1,70bc0af8) +,S(243d84b1,dc9ce143,a6913bf8,d13c4aaf,6fbc1373,6bb8a7e8,5e648958,32013b8,39317ad,b6bec71d,ffe3c2dc,6dec5e10,21a3dd83,2dffeb91,108abd5b,6e7f28bf) +,S(1d888387,5255f3f6,838eab82,1a12a8fe,ba6dfde,f190585d,e039542b,2d91ec92,a9d38be2,e919f815,5d633538,d2f0aef3,9ccabdad,dbd912bc,46c2037f,3324b489) +,S(39a21f75,4c0d3376,f7560e2a,a743751d,5512d628,7a480955,6456f9ac,b1be3765,3cf324a5,2a7fd79e,3bc188c4,d55bb449,ef4950b1,3a4531bd,e0b2ea9d,4035e005) +,S(a10ff60c,d8e25df2,a1d394a9,52c67f6d,18ab0a1f,a56569e9,48d9278e,b42e21c8,b45f2d63,3ce82ef8,1dc0c0bd,4f891473,89fd2b35,f02cb237,bfd4f502,df9e991) +,S(bc269792,d5042f7,1051f7a6,46b971f9,bb801acd,dc24a2b2,5bbc459e,b7bcbcb1,b70445fc,1c032061,61b01530,c9205d7e,c7fab6de,1d83f1f4,78b35bd7,71235665) +,S(3d7279fe,fd5a3682,a82a7f95,d1db4442,5f0ef448,f6bccda9,9a61c240,9037cb95,df5226ca,e6365b7e,22b42cca,2ba2494d,9a2ea193,cd92162,2de6602f,70159740) +,S(e0c56d30,ef92af00,b936c2bd,951b3d51,bc439ad0,e4216e2f,d552c2d5,e8dbe588,c2bd177d,2a75c44,40dbd186,27669a0f,f35189c7,a4873e0f,6484b3b,68555fee) +,S(9bf960e5,2b7bbf52,fd839830,634baf1c,f0d6e332,4272bc15,d9999ae2,7873315b,b28719d,20e01dcc,b0016cb1,6a453739,551862f7,d9cc81c9,6662387,1d8d0405) +,S(20df196b,e60ba71a,e617a6b1,44757e0e,87fffb45,d447d9dc,d5480a0,34351198,9c722d43,c0d071b,a07d4953,9ad0abaa,f12ba358,42fee0ae,9960ce1f,26eb07d8) +,S(843c136,208b40b,9459693d,8154980,455a5f71,23b5f633,a26661d,ca9bac17,d5b5bd8d,9095fc40,d2d1820d,31dba542,d0c74f23,86770ede,c9b4df46,f2f12078) +,S(9109b4df,702c1ea0,dea4ee0c,ab46d6ef,708a3fcb,72f9dc03,e05bc722,408d11a0,75baa2c1,8be5801c,b5315195,4c2c3024,7348e9c7,913bb242,cf4ecc8b,96dc507a) +,S(f10cd1f5,c960a9bb,12adff03,c203c59d,8e51552e,3727edb2,329eef3c,5991113c,a84ac8e1,6f65daa6,16574689,8fee662c,9d2e03c6,4796151b,8f3f0bf1,5e8c465a) +,S(9f07713c,ffd3602f,ad077b69,a8a5f539,ae0d6d0,df58ba07,1eafe6ad,10e747a8,adfcc873,42b59083,cdc3d735,782f8ec1,cbb4ea3a,57970afe,58cd5e5c,8fee867b) +,S(6d1d9d0e,32905734,13b2b870,fff8978c,5ce9ec6c,b120d9f3,64063342,cd95801a,650be4a8,95d3b602,4d745f7c,23bbdce3,25a3f597,922e50ef,ba154f8c,6831018f) +,S(497185a5,6b3acc94,7a27791c,7e1fb149,5c649f99,dc767fa7,12820cc6,6cdcbd82,7d511b7c,11dae1b1,7e4078b2,fe7565a0,f33ce5bf,74181c3d,f5b6a951,fe6568c) +,S(fff738f9,848eeb9c,4ddb8bc7,52cd87c1,9a35f7be,14a470a2,c3154ff3,100a743f,106b8a55,cd913c97,76837cdc,f45c58a0,211b979a,17085df5,7bdff373,2f2c38ec) +,S(320391a4,8d3546cb,4466876a,37d60015,41899ef4,5dfc8e38,ccb9021b,981b4830,46f63030,b4559411,e742f303,25707b4b,23fa2d7d,e633800f,9c71205,6651b102) +,S(be44ce40,a925e88d,26937f7f,b7631f18,55879106,122813f9,adf16e00,5d85fe9e,1755ade7,d22e6dc6,7e6806d4,bf44b6e2,ca6948ca,9a418893,24db0266,2b6e1dc4) +,S(8d3f06b1,58ddd609,f83b0531,466fc2a3,da6aa80b,433a92dd,eeb20435,cf33ddae,2d554a99,efde513b,b8b6e5f4,dbd2e942,f1d0a641,98c3df2c,4c74705d,4b37af63) +,S(f814a79c,f258f553,255c1cb3,a054fcc0,d0c71d74,742b6627,210ea846,91596729,119fc95,be48b4b2,23c80c42,fd1f3d45,271ce8a,edeb82dc,31813f75,a32d867d) +,S(95e8fd46,1c37f1db,5da62bfb,ee2ad305,d77e57fb,ef917ec8,109e6425,e942fb60,ddc28b1e,dfdbcda1,aa5ace31,60b458b9,d3d5b1fe,306b4d09,a030302a,8e2db93) +,S(c06543fc,47e18816,bc720604,cfc20826,6f4e5cc0,f436e149,e2dab0e8,a7981e77,22070465,f3a4a7c2,1134819a,c194cc9d,28185431,17ec634e,e6634831,97021441) +,S(4983d95b,3716aefa,4a14d116,bded84e1,fd5b050,bd6001ca,a2b97086,b4d5c68e,1373426d,a2efcd14,333d47bc,ebd3befc,f5e609a6,6fac1b02,80cdae2c,7f0a279) +,S(a2bd5cc6,92e84b97,3ba2cd09,25e0850f,ad8054ed,e6b73ef6,1fdcc958,3eafe6ab,cca6e78a,f9141b1e,6159011b,99f8024d,33d8d797,9795aa4e,4f0b2767,e6a5ce2b) +,S(61c99231,a18f4e73,95076281,b367d084,b8f85226,3117ab60,bf698d4f,6b6d741a,82314b97,9e7f1d30,64861609,a08c019,af886db0,67d49929,9d340814,6e6cbfe5) +,S(4a5acfef,32c55299,3a7114fc,7913321a,d4072a2f,6c6bcdb7,3ed60bfd,6ab34304,7295a29,c06859b2,69bf9f29,64b26dbf,1323e89,4affa4da,9f61b056,9a0c03c9) +,S(e0467755,866f494c,2b36dcb6,c65ecac6,604e5013,4216ad48,7d4f5b68,bb7f4023,dead03c5,974dfa1b,f532f955,826189ad,ae945975,28ece029,d9e5a42c,30b336b3) +,S(686fdf05,c9265fdf,5b54ca74,b5b1e231,c4e8be60,20844596,40dc0d2b,bb215ea7,f4d43e1c,edf9b974,aef950e,bff3677b,c93723f2,c5901710,b6561e53,d57ea7da) +,S(12476985,f9b20c,ea62b7d7,b0d96d2f,e2bcd924,d1f15cb9,fce5ecbb,8bd21253,d3437cb3,9e904fc6,43a7b356,b4389c0b,3f1950f2,43dd7842,e32de16d,2b522004) +,S(656bdcec,9a87c9b2,e5b32291,9f657b,b5eb1e1e,d2fa724e,45388026,2ad17b1b,c7748d0c,47b6e4f7,f63f704b,3fdc08ff,cdfc830,d17c1d11,6aa3dce2,f92fa64d) +,S(5b7f710e,f721612,ca79b24,483ced12,7a3d403e,60ebc04c,3aebeb96,b483e4b5,1b5157a7,f0688aee,634196e8,de5a9eec,11db4b72,bd96b86b,698f7284,bfb08080) +,S(bfca66d0,552ba6f5,5795bf18,40f90d85,2545213d,81d2cdea,bc8d3d04,a1e6b4da,4910b0cc,290d4257,c04c4638,30cb3a10,223043a0,bddd8690,84b6dd1a,f1754e75) +,S(663fa68f,b79dcbbe,4798f8ef,2057bd14,1447c11b,cec70924,7f566032,88496f16,3ace2efa,1f3bbd23,d885598a,91d1f420,a42597a2,ab30f951,f2b27aa6,83c41786) +,S(27cce333,8a3db8f2,1fef2f86,ede68a25,7c1675ae,80cf004,6085f1de,495c4321,7156bd8c,8babe472,eb144a00,263d4fdf,7aefa69f,da2a9c29,4b16a82b,24d373ae) +,S(d49c06c4,52ec5c09,be27940e,13c575ef,b727be4b,1c0e8ce3,5aa5bc4d,64bd9560,2c653518,b298100a,72a66469,f9a03635,5d7ad789,546df3c2,f5175238,e78d18b0) +,S(6960807e,bd028026,d3cecd25,140d3bd6,3d7bf4fd,10afd129,cfa017f7,544ad08a,a785044f,28befae7,2b7cb546,5bda6bdf,6f9a6383,aa9abf4c,f7baeac0,920e7c7c) +,S(8382bf36,54b63a71,a3b75abe,ba57dbae,fc9263c5,5a54faa1,edeb5325,3df8faa1,e05eb9dc,c319cb53,4461da26,9627661e,dc9bef3d,945766dc,b6d0fcf1,849b011) +,S(803b9379,30ec876e,78c8cca9,fa932f22,b7e7059a,f605379a,cc45a3d1,4ab0bffb,7db2341c,5202d1c2,c6fec7d0,b7869471,cb90d1dd,17cd1152,b52af046,55e5790f) +,S(cb4db129,ab6ae9f,11165ff4,f73fab02,cb78fb0e,89647e08,f998ba11,d2c5292c,ccaef9a,1776384b,b5a80ad6,5bb366fe,745c2408,d754ee9e,f6154188,d7d1c9c2) +,S(fab28757,50e9f672,3838be8a,fc070fc7,8fd6af7b,84c9579a,a8152acd,ecd115a2,d59fe028,89cd562d,5397d3b8,3ae85303,764ee931,d9c6e495,6c311490,c0b3f065) +,S(dd879eba,f870ee3d,f6e3f03,60833e12,fbdf844c,d6a5b76c,19802485,6649bbc1,e7bb04c3,a99a5c11,dd7a324c,1d5696c8,b041a12a,c6a538f7,3094716c,9943c55a) +,S(7aa4afbe,29b06a1e,da9319d5,72572b13,1df68f74,1b5f8d8e,d00ccc04,80f8016e,15f79a9f,b77b8587,7f02e3c1,3202b972,423fd00d,937c0d2d,c9d94b17,53fe7130) +#endif +#if WINDOW_G > 12 +,S(9145f3f5,876a3265,5d7fee64,f2d6e660,c34354e9,1571d68b,a19e4cc5,8c39f890,45e0a95d,cf369fd0,5bc9ba7f,da108d6f,37650c1d,5766b6c9,98ecda28,b285d8ff) +,S(5450b752,36fb010d,1ef37afa,2077f3dc,a5a7f6c8,91a21317,13df740f,4511ac9e,a7c7ed57,62bef86d,4de1084d,3ded2d7b,13ff563a,67109ef0,8b6f0180,fe6ba175) +,S(ba6c0d72,5e48de2c,cb8256d6,7417d075,bbf2766f,d13501b8,4c32cf88,c0666a0f,cd2a9132,7137299f,50eda669,3a599032,bdecd64b,91bcc640,5ed186f3,e525e442) +,S(b94821ff,1feeebb4,6fd1006b,798fbdf5,d25a649d,aad58b05,53adb7b3,9605c921,21589ba0,79bb92a2,c7c3d950,c574afcd,f45ccfae,eec4365a,72dc58ab,f9077c05) +,S(46436446,497f7c76,b70e0d7a,5a963cc8,432f14de,93d61f81,98f8879f,da0681d,29344a4e,90c4d810,10da8aab,5ea25e5f,48c367e5,b3ec9239,8a3e608d,49c83a5f) +,S(bd8e5ac6,a2e210be,4959185b,7bcb0cf1,bd3be917,5baa0d08,2bb0b38,e4c1ae1d,6b381be4,6dcc9755,da7773a5,eec888a6,69c6f71a,7c3ec0a9,4edf08aa,2db1fa19) +,S(c27c1e1a,c428a7a5,f4c3405,58ace76d,7fb64593,b3942319,74cd18ff,99f22493,fc95d661,c12f7b3a,1cb1884c,fa9f5994,25108af3,c05e04a4,9544f919,c59cf57c) +,S(a1765561,837e4ca5,5268168e,ed90466c,44c17c01,4040fc02,9e53af22,77eb30d5,8a2dede2,b8d488bf,cd655d0b,30e6e2f7,3032c775,d0fa15ae,cfc8b66c,b6c28eb5) +,S(2bf6930d,35cacc91,87e9279f,678ba368,e9eea737,8300ef93,b03e98c1,81ddbea9,8a2d4d43,3aaa8bb0,3ffee538,38ca8e16,d0f3f930,c35d0db4,6e2fa069,e625209d) +,S(766a7725,9cc5aefd,90f005f4,d6755924,a36d085a,3a5856a,6a066a70,6877c8d7,db3fac97,4fd9e2e7,f05bfad1,5e938ef0,90b46d04,bf40bdc4,171c1e33,48049190) +,S(d25a60cd,953f21d4,5fcc333c,97329da,134196e3,9a913242,88792ff9,18461268,89bf2be8,bd04835f,dbb874e7,12352980,a07ad598,9035270f,397f24ce,790c7863) +,S(c7b28e9e,8b7125b2,6721f467,b665eafd,9bf56986,8ca180b3,60dfe429,cad95d68,ac28d58,b3a7b61a,71f947ed,8bca4768,9ec7bf34,7646a167,b37c3aa7,9e95c398) +,S(e2a5208a,c61f8c29,ada2d7a7,4cfce985,20c29160,f1f7a97,ce8b34dd,7c59bc24,de8ba14,49708a04,ccb4483b,4e90e383,a152ce27,777fce4a,880d9f5b,3dc70830) +,S(e1e8e4cd,2e8df95,d3b2b152,a540967d,6976e001,88287ca5,3e844adf,12e205b1,a5dbc6f9,cdc7547b,cb3f0091,8233723e,d34aa97,f546a491,a77d8cef,43bfc9e2) +,S(b20f0a51,4a684e55,2b228480,3f3b1c2a,3c3143b3,b895f75b,ea454bf0,9d2b6512,bc3db380,676d0d14,9c0b0c3,1941a07c,f7c95585,cd44ec31,e0edda96,e80d02c9) +,S(b71a6923,b1adbf77,94cd9d8d,407ac96f,9582cbc9,b9748949,9cfa696a,c29d3ec,75182389,9d59558f,b93113c8,d38c72d2,7b6d75ee,7679fb1c,89bfce1a,64b4f151) +,S(ca47adac,68ba38d1,8ccef76c,7565788,a82f415f,d9dda65,2004d5c6,a7d3bb3f,bd598ab,1b783382,44035385,e165fd5a,ccd8454c,3969d378,42fad050,4a8701df) +,S(5fade148,aceee9ee,9fb4eeec,edd5e4c9,4fb989c4,d99f65ee,a45f99d0,2d40e441,ba6fca3a,e82e5581,ac5104ca,c8dd2c00,15afd1cb,3943f1cb,5e61dd4c,d73831f0) +,S(767dc9d2,14fccf00,900ba01,a1cf30fa,e834c851,e633849e,8adada63,fe5f84e9,8c650911,aca30e56,2d6b97a5,2fd7cbfd,1a5bcd1,9ae197d6,9ee3215e,64404639) +,S(27f8f961,445e2a20,5daa7648,fc3c06d9,523544d7,477e686b,91d7178b,7e4f06d9,39110b27,82cd7be9,75596bce,6b79e5de,37933242,21be8172,427cdfd,82a73a60) +,S(8de0485b,343b5e4b,ada4070b,f79dde48,8a1b2889,839735bc,6a403165,3f3de668,90305767,6f43e0f7,d7d1c1a4,4c59124a,12fbba72,8302e143,1c2cfae2,ed5729d) +,S(5e43db6c,8770e8ae,8ab8d318,8e700c28,5b6af8a1,eec95fe1,b68e5cc5,952df0ff,6882628d,d85fbcfe,3a2a1091,15e59c78,9aeebb3d,37075f90,ae02a439,506c7aa6) +,S(7db2baab,4bf4300d,e7caf4e3,52df1423,6102863c,edfeb7a0,89311f42,59a4ed54,387561a2,fbbb44be,303fbbcd,685909cd,e553a84c,a3d4c0cb,d33026fe,178e8a84) +,S(96da8525,39106887,d1fdf9e8,232db3e4,cdbefdcc,abb90bbe,fc04d10d,b996c6f1,65271a31,49127341,9fb5d651,3dc33287,45948c92,b7fcc509,4023d300,9bf9edcc) +,S(84eff1cb,14eb1284,f5ba51fa,838b485e,64cd4c0f,acb97b00,81ba7848,add50613,926c9c8,a6540a8d,7b1e602b,6ce818c7,609f4511,32f284fc,7f578c52,a6febd9e) +,S(1eb96371,8e2a2a0f,f5ee6000,7bf94a00,416e6a92,25d59705,7fe19941,e2adfbbe,4870aad8,9635ddfa,dc3d4011,500639aa,d3cf0523,cff0dbb0,9c9f6a1,3005b855) +,S(2994a36a,6ea3f307,1bda8696,baf193df,c75fd4a1,f7683fd8,d454dcb8,77bdc098,e465e8ee,a7273d4c,d786bd0b,e96fd3e8,9969bf03,1b76aeb3,fc82c4c4,bf856766) +,S(25e7fb70,f3d357a2,c29b115b,5e2d97d9,d2b68fcb,b7f2fc00,237758d5,9d26c414,4959a370,a3bb895e,bf530fa0,13a86ab8,206b7330,efaca631,fed26773,f356c4f2) +,S(fc387f98,80bf6bbe,19f0481a,2d66bc5b,c3945c52,588860ea,dfd5893,347c0623,89d7b80e,83caf032,9c9d07af,734604aa,7ba33274,c1081ff,16e663eb,b49d67c4) +,S(c50af368,c25fc9fe,10220fa8,2f177720,ef5c00b4,85fa99,e2f03294,fe01e1d4,c3777b26,41983094,912b80d,9e94af7b,27d9f10f,978c931b,a4294cb6,b97579fb) +,S(a0f9d109,d524d9ba,a2e00362,941a5f20,d7015c48,554f5bea,7c97617e,10041f94,28c51c02,daa5e108,3e77ff2,c64560e1,2eae923a,3a699f1,daf3c62a,710e9ad0) +,S(41d12627,58b708,58727138,908004b3,2138bc23,cbcdfa28,5da862a3,48316de1,6277029,153bcec9,5c95f451,3d515d90,341d90a4,90eb2999,d29df4f0,7c1b9673) +,S(944c58ce,fe6cf543,d93afb77,e33adb3a,5774448c,d61d621c,fb80f856,6e99ca87,c071ec1c,9b7fc717,ca91c557,66bcb222,3294958a,b7d7b056,e7473170,284d66b5) +,S(3307ab12,e06d71ce,9c029bf1,88eebb58,9a27be59,17290635,f2babebf,be437145,889c3cb9,28cf9091,4748dd9b,f89e9809,4a6966d0,97d854c3,c6b6a949,c861d213) +,S(42baf011,1eb2224e,4ca03abd,24307b6,72b74572,2db6a8ac,dee1b7f3,45cb9ae6,bf32e128,d608dea2,4b564bec,38d22c5e,879515d2,7379cb11,25695faa,2e12ee06) +,S(856baabb,be7b4bd0,49fbe898,110d1175,166c69c0,a2bc86bf,e734c854,c402c621,24a323c9,b6d31fd3,cd424161,be229e89,1f825197,9ed4721b,943d7418,4912ac0c) +,S(38dbc18e,d998143d,874c224e,de83834d,95aeeadc,805cac1c,3216d830,d24a9cd4,273ec126,f7e85778,ea38e2ea,a90ab5c5,271c6eee,7f934a03,570891e5,167eae4a) +,S(359dc85b,ffcd2329,3166bb20,c8374af1,5e24c065,a5f48d92,c981eb81,4988dc59,de5dedf7,deef588b,90237d06,e437bdfe,c4a05703,f77b584a,e58162fa,bfbf39c6) +,S(e1068065,e2e91c88,3de2f73a,6a5f3da7,1d872a74,9d7f283b,b1ca35b7,c63666ea,810c3a52,b5df0851,87928afa,a7685035,a7e155fa,c8dd4523,c5ed1f01,73752cd9) +,S(50767f71,37e7c9a6,6e317183,cddfdfc,b564956d,cbd5f3c7,fd8506d,dbb19d83,e1c2dd5f,5e9d5fed,807d24dd,3f2e0ae2,393b6167,563db9fa,5e338664,a0d4fff8) +,S(44cecbf0,cdf88355,f1216d0d,efcea137,5e01275f,f53d8a72,5a0b5980,e6e65864,469568e,5094e9b9,ee290550,e67bc636,e8e3f022,f15c8d2e,25c3ad6,f51cd40e) +,S(1830c8ea,43cbb07e,fa2fe597,6afca2bb,87ed8a92,602e05e8,86ce3447,96aa18b3,df551328,e064aee7,67f56203,7fa31c11,3c8ce2fa,b5445d65,8bf1dd84,2f1da49d) +,S(58d54b7a,473a7ab2,51c33417,a41f4ee4,708245ea,c4f8eb79,9bf90aa4,bd9326c6,a191f338,15e2e07c,ca4c331b,fb1cb2ca,a1692093,faf5e789,1ce45a2e,c49b2a85) +,S(f0dce604,9507812e,603af104,42fc9861,70a18b6e,44e81af7,ba192b55,12c6792c,c221a221,b5e86ed6,23e48df5,5cf0f560,4cc60eb4,c54d95ce,3ada7b09,bbb966e4) +,S(42fb09e5,72c0302b,286aaa04,644b26ae,e4b958cf,ae5293d4,d7ba505,59dd2ab5,79c10573,a00e6888,fbc7ec76,983e7d17,f46e1ba8,27494099,43781bd5,19f2299f) +,S(7adf1551,ddae0c9a,8628db25,e0dad10c,935465bc,88b005de,ea2d0412,f3502ecb,657c0ba2,143cea92,c9ef5c3,69d110a1,2e031e67,9d945a9b,b3c5886f,29acfd20) +,S(dd5a48b9,56fdf6a6,d6271310,afc2f5bd,3a7bfdc9,28125345,4dffd91c,282c7a5a,7390d037,2e067f36,fab52107,29590464,2ac6b0cd,91a161e3,85df7cc1,7ca52657) +,S(631850b5,15374594,be1c783b,104d2ce0,13ac763b,1d36301d,2936c2d8,8a1466fe,2490ce1e,a9b67e44,a9241416,c5729ace,2016d202,b77efa85,78bf3228,c590882e) +,S(332e39e4,d6732229,aed85cd5,83a3ccc4,24466869,bdc6a8e0,741b0e06,f3a0bca5,90840f03,60db52ae,a58b1b4,74ad65c,b66ac30d,f4d465aa,60244d48,5d7578e7) +,S(de019556,f0c7e1c1,6567224e,826532f1,d72c0eb2,91e70980,de7513a4,362f0c97,39a3d79d,1cc98840,4162227a,66382529,d75fa5bd,64977e47,9af0aed8,68411ea3) +,S(4c44c0c8,e675da80,c6ffbf2,61b82e46,4f81b76c,a3f902a6,8094a2cb,24ed859f,59e1ee88,1ecc45de,d8ff2800,243ab8ac,c5497897,1a3a2246,63b2b593,e45ac34) +,S(e60339b8,481e19e,5c1f4d1a,85ddcec6,a4e0dcbe,113e7d28,2793654f,309286a2,9a1eeacc,a607941f,b51c7998,ed2a5a98,bc58e3f9,4737f72d,1b08a706,a49d9d59) +,S(10f42ee3,e7292f3,9f4bc472,708ffec5,c6ad955,c5285be0,d44d02c3,d8a25e66,6f365f0,53ebe28f,db9d5f2b,c967cf14,183e130d,f01a5106,34a975c,ec916a25) +,S(7e0931ca,d1286687,7d2fb0f3,1c58d74b,703af3ae,593a9548,b6d53d86,6729c445,5e4b9fc,75eab41d,663caf7e,8056f4c8,a9c34af9,22773ffb,f5a12174,1f6b0b0b) +,S(36313f7e,f9613c6c,ff14cd1a,78362f7d,b7f1acc0,db278f1c,6a011435,57963f22,1e6946ab,2a94231,4ac6627f,5494205c,33960a91,ba663a69,8641bab4,43d7edc2) +,S(223eeed8,8eedc265,b2e18a63,ceaa2e9e,83f9ba59,2fc8f3bb,55cec574,2869fe01,72122173,4ae29bfc,f3632cc8,92d72d10,5593f7b8,d687e5ff,eff21095,c1bbd71c) +,S(b6bd5ec9,33302c5e,3fb9b32,18795a11,60dbb2bc,f9a9b5fc,31b7a5a6,28b3ec20,fb9f87f2,98a8e5fe,b15f051d,63b48bac,34f373f3,9b42a42c,d0f1d2d9,c99dd495) +,S(a365a760,3b1c24fb,157f69ce,8fd57ae,5a802dbf,3b8f92c9,8f0a8b01,4ce24668,73e6422b,7746abda,2a38cc7,298180e6,578005b4,1b0d3760,6f2bec3f,5c0a89f9) +,S(e86f8fac,43e436f6,f4adba30,9d446a07,e24bac1e,d379e13a,a235ca1e,d7cebe6e,1e7bb4ef,aa75a9bd,713a592c,42a01134,930b7402,77cc1cd4,a913d6db,f4a166af) +,S(f5a57dfa,d2b25571,dad09304,cfde1da2,5cab3e2,e85895cc,9933e868,eb9bd5ac,d265de5e,8fc90e41,d518dad2,68997a24,8eb90906,becba9b0,c768c5e9,877c1ff6) +,S(e1dcd17a,7259374,7e6fd8ca,b2464a9d,6656607c,a2bf10f1,45c45947,75f76c7b,efa2c310,23f86d2,6489feb6,1232bd44,dff819ce,6b95678a,130de640,4af9a20e) +,S(83f8abdd,84996ad,1be74b80,a05da9ab,cb3774fd,cca40c3b,afd386cd,cfa801ff,267ebd64,329fb10e,56ee792d,966868d8,1c85ff37,6aa24287,3d37c63a,4bc3f63d) +,S(54cc9d79,6ca85a90,27487c71,6511485b,ca324b1a,f34fe454,ea9ba54b,4f259fae,18c39071,ef0b861d,7d016e9e,deb6e83a,3c6ce8c1,517ce0f2,e201da0b,fab2da2a) +,S(9d12a52a,e0091654,e2875ac1,b11f8744,1c3f65ac,940e6a51,6351c219,31402ba4,5ffbb334,276219af,418d17f3,9f5fad63,c6d7e42d,d53f6e52,bbee2f01,38e81d2e) +,S(659bfdb7,66821a91,cd030917,ff21aea4,488007f0,b7ef3824,4f23b665,e6496998,2ad708bc,4506e85a,341ef96b,78bc247f,d7321a8e,bc21f9db,8444e7ca,254784e0) +,S(e2cc4e33,d4a08374,4866a253,81549a6a,76ba1b4f,57312413,d601296e,5eb4670b,528b2b25,347e7f34,7b79780e,a64c3718,80497f0b,a3b28e18,79714089,a4672476) +,S(529c0b9c,9e21c36c,9b2164c0,fa505601,e8dbbac4,cfcac131,e248e103,e6edec68,7fa44821,72a0ca01,33669e6a,bd2e0386,6cb74f5f,9cbb7e4,96770129,567125f4) +,S(289d6baf,be6a7d1c,154d6532,a80fb65b,3d89e57b,eb2f1dda,654d3553,683b63a1,801f4863,d3ce8d61,60e2c62c,55267877,db149ff0,c3cdbb53,38893168,7d005400) +,S(d16a84c9,e3b36660,7c005bb3,425ab432,2eab9b58,58d1899e,51f2ecf0,790f14a1,2c6f5dab,10715328,f9ffc5ea,4ad6e0f1,46ec79cf,19cb2313,79bb5198,5156dd07) +,S(d03cac39,4fdabfbf,440a6893,e410dab2,a7062df3,ecbe1aff,d30703b1,6b6348f1,152313ce,f530b317,70d85c08,7de95b1b,5dc4a86d,38e4040a,e5d1ba34,449d19f9) +,S(b66b3c6c,a673c4a9,77ca7d85,1f969858,d4c4b604,bc497101,c89207b5,a863379b,54ba2563,771c6aac,482c63cb,7156961c,4b00faff,187f0560,9a470b06,31624da4) +,S(be684644,11c47cd7,dfd3127f,4e7d7308,2a43fb68,79c5e86,236e4516,a98c8c45,79290f83,c61d368c,2e395aae,b9cc50e9,7d78ddc2,fdee9f19,a15fae85,826733da) +,S(478ac3a0,9f34f463,4d61de70,9ee01878,4ca421f,91d20e0c,5c62bfb7,afcbde9b,f752f3b2,ccbc1096,1ae7526f,5574b5f6,e4bc7d4b,f77edc34,f6e37655,7b0988bf) +,S(745f355a,f2ed71a9,9d4d7de9,c9bd4a13,7271a2a0,c077c796,e7064179,8f3dcfc8,18ea61f4,6b0c87f0,9ed05816,c31e1992,d4fe8826,630c5f6e,67242063,86e288b9) +,S(54e7bd6f,9878a8b0,909aede5,9286427c,a3157a8e,38ab94b2,18db520e,86760ce0,d7b7d80d,c1eab448,d1f3c638,675dc0b4,e04bdba5,340d3f2d,dc1d24f3,dfb8e49) +,S(ff56afb6,55eb431e,f3c6f5c7,fcc6febf,99b018ae,3dc95208,27e4a01f,a07d510e,9bfabdb8,42d7b1c7,9f4388b4,49a28d6,ec723210,ea27509,655e9b44,2591e371) +,S(c2bcc099,ed298fc8,679d0250,6d8ea790,ea511b41,5ff3ebe3,82d39d21,fe9cda72,6c7bf2c4,35ecf773,5b6c31a5,82fd38c4,825de4f0,58efb070,aa1ecb58,530f971f) +,S(2383f144,9811331e,6c54b9a1,19c681fe,c8549e36,890b80f5,99a80187,8e2ec4e,13ab411f,d846b6b5,938a999a,704470f0,d8fff03e,9dd35cb1,44860a0e,3533a1f9) +,S(2f2271c0,d4fa1d8b,f8a44584,ba4f5266,9953f72,89de16b8,17d6bf0c,6e096048,646ef05d,b40e50e8,b6f32c22,63ef553f,a957173d,a6f14ab5,7cd60b60,2fb42fc4) +,S(b7b49b1b,f067a27,eedbe55c,bb011eeb,809e7ada,ada5d08,9bf1f26a,25e951c7,fec760ac,a8160525,ad6ec95c,7cb0329,4a9b7f20,45907331,5b2dee2c,7f7c33ed) +,S(36c8e1ca,d9933e5c,971866eb,12daf81e,7765d4cb,9f0af557,94181aa5,e5409223,895eb6d0,a0252282,d71cc730,9116ea95,22f2e35f,52498853,e291932a,dc8b8fdf) +,S(3cbe9127,63283592,13173e01,8cc2b0e0,fa5b8a11,5684cd6a,6ee7bde3,bc1ed523,7b2d3dc9,22f96c9b,9970aa9d,c75f1e15,c5149ab3,d0993055,e4df30cf,ce44dc81) +,S(76e94d41,c4639419,23448d38,8b239e6,fe0aec99,314ed16,4e67e97b,6247213c,8ee4a6c3,2f010749,103460bf,d75fa38f,f9efe4e4,bf283cb5,a3bc186b,21fa1278) +,S(493925cb,12c0e7e7,a15749e0,7fe9dba,5b265d27,8eec0c08,506f3433,4b1851ec,70900c6b,3960a465,6cab318f,9f730a66,e4a2400e,d819da9a,1f5b16bc,4c62b193) +,S(b37fdaba,d1a1393d,79820eb4,a4823d38,3873306a,a9f5e6b7,51173aed,c43cdcbf,8506f0de,57fad139,e20df67b,e30a75a7,dfd325f2,9e35652f,28fec608,f27030a) +,S(4451960c,48e95c49,32b0c90e,9f90724,8f2b7023,9c6c703,3c29f4a5,b0a5e8c1,83553a18,d9ce9f66,961c9e1a,47766a4e,28bc404f,bef524de,53b1b687,d4d7490c) +,S(9b0ac1a8,697c69b9,80cab20e,b3f98718,7857721b,c869c704,caf63b80,dfea3449,210e4c53,bf1bbf3f,71e32a58,22809853,61b61723,72e845d,65b5661d,fa7e60e9) +,S(e6697355,ccae4f7e,122d62de,1c00dcc5,32eca4fa,7dbd1ceb,e92684b4,781e0851,1f122cff,dbe5ef3c,944353f7,18806a82,9d3ded91,427bdda1,736ba236,e9bdc3cb) +,S(ffa890f1,1a1aa4ca,1f26f86,1288bac7,ad480a4e,1cc47f2a,fe39f260,f167201e,1688dfc4,1716fc3d,473c4149,77d0ee8c,ac569cda,b01ab5d,69d449ca,85439cb4) +,S(9088d4f2,6ce238cf,63eb09b1,5c04a04c,c41fcc57,946c6c14,cd3b1b4f,54b6bf47,9e380417,bc61004e,3d5c9943,b3d359db,2ae4ec81,2b70e909,bfe265d5,e4d2c2b9) +,S(a3395dda,c1e760e0,fe7f7e5f,e3296bc2,99949ca2,2c034707,67c08ffc,d9576a91,4f8a879a,54036d17,16f07016,23dfcfba,3141850c,de003870,6ee940e7,452393d3) +,S(11e54d64,54aac1e0,58cef234,51f686a9,1a77300d,75330ecb,d208678b,2b8ad651,749b2960,5a8419f9,c5521dfe,f552a24d,aaa53f45,908d2679,6e08b396,c9c020f2) +,S(c8f13cdf,7b41e822,ab6d5a70,7c701d29,98f5f0da,8e4c9746,75e808fc,64327f30,489a69df,17c09c1c,dec329d6,a1f34f60,445d7aad,d609d94d,44168947,c3199404) +,S(9175e6dc,cf674838,a94c628c,3e1a9dc2,9487f394,8a25e50c,d463cf6e,92d84442,8705713f,ed377125,51e37e51,78ca7a7,c13e193b,1b83c729,8cb08186,8fde1c22) +,S(8eed492f,b6d5f0e9,ee78f6b8,953ac0a0,5df8b9ec,db17a09d,22863bf4,3620099b,23a45742,17672e98,d9cf8b94,62439ec8,82e1acfd,40db9d9,9ece889d,1e0ff1bf) +,S(cb95ce23,dbac06ef,79793f54,3105f5d7,5cde90bc,651b7756,bebfa367,d5c2dd9,9612a6ba,c023b0c0,73b5ed99,271ddeb4,57d22d74,f7ecea4f,c618be5e,164a9a48) +,S(667218c8,bbd3ff37,d42a8ebf,8b5a7791,d8fdd493,9ce447c9,15dac906,67a3c980,dd401179,9e19afdd,46b44aab,1055b554,452a21e7,6750f2a,ce98083c,8cec26c0) +,S(884799c6,ded4851,ce53e855,dc429698,c7627b5,a0ed3852,19b59af8,32f76e5f,238d75ed,84e6408c,79cd2d37,152cde78,22e34377,fccf05ac,3afda662,c21c4a6b) +,S(8d98f36b,5fc0082c,597a05ba,e24ea6d2,2cc8bb90,3a6bf96a,256eeead,6911d143,26e8ad1a,fc902a6d,505b2fcf,80168177,de7df931,b1dc1516,f2ad7b38,e0ab3cd3) +,S(ba9062ca,c0ddc6d3,27f2cbc2,8d2efb1f,d1db2388,c86741ae,7403f4b8,3fd70ad2,473b335b,3036e754,d9d71ccd,53814455,674539fd,7b73d9f7,8f24bb0a,668b38c2) +,S(4a2d36d7,3bf0e609,7a69be67,55621051,7453ca53,11e288f0,1ff1dc03,acdca29,ff691e7,a90331cd,44e83ac6,c298f5fa,9d694a81,48db01d8,595a4386,b2ca8f83) +,S(e868f28f,d99c4b16,b64fb0d9,32c325c8,6b365136,e0055c4f,cd362e1d,cf37d0c4,ad3346c1,83401034,8e8e0440,e889109a,40e5fa11,37d94bca,2742adec,4cd4a9eb) +,S(6c5e8689,830a6ca5,12d77e56,62239833,ea77e696,da40feea,99da3519,2babbf3b,c29e05f1,5fd00b60,7bdc333d,d753647f,56b9830d,46a597c1,2bee9465,ad779540) +,S(b3a172a5,6ebf2dff,aeb91cc8,6b9d5a91,c317adc6,250ae210,e1a25bec,1c046344,28f6dd79,9ae40d6d,bd31fff9,9a4c2fa,f06401c0,de7a5d11,9fc5faf8,3b4ac3d5) +,S(198f05d2,e2f9d779,a50aed67,39468a8c,ac4a22ec,71a3ab80,91a94e2,100d8f47,cc6a183f,c9813173,caee3baa,f3fcb223,39708968,360c02b3,cbf899e0,b7cd0414) +,S(78b2178f,a943a791,4bc7703a,e850b07b,41ae77db,79fc39d8,9f0f50aa,b077f48e,85fd3e34,f2cbb092,8bb89004,e1801be1,d78fceec,c29eabeb,11b9cb15,625274e7) +,S(6f70df00,1d4c5175,f997a795,170e28a4,23828ef9,d5f72dcc,cec43fb8,d9943f3e,26315213,b77183e4,5979c34b,e730e2a6,956a66c2,a8dfbee5,f0f1eedc,ce8315ce) +,S(ab813144,3c946d29,d05509e3,b45b5926,e3964b2d,1cd0fbd0,9cfc359d,b5a9dccc,aebdf315,c1273af,a0c5e587,6c6c6132,16b7710b,3f505062,6336ca9,4f5c5ac) +,S(e72b3791,dd751127,23723e62,77e5e6ed,6b94569e,ba3321a2,a3e883e,5473ad3,131b3074,2dbcaaa0,fd3109ab,5e3a2847,9c2091ac,8830b19f,d4df4c82,9b28a3d8) +,S(ca5a3296,ecdd5e50,38fdf77a,fcc507da,bb525d7c,56b50c74,61928432,ce3ded63,8bdb6794,b7e177ba,9027258e,42b365bc,5a14209d,2bdce54b,3f865fc6,ffc4ab9e) +,S(eaa3be9f,26ae8cff,cedbe59d,cc03b202,e7d2e815,a7269819,c881a700,e31a9222,1b5a2cd7,a367d34c,60ef8026,51df2d3b,36ac2816,7cd7eacc,735e45c1,9524ec1c) +,S(ebba882d,3ab4ff6a,e162076d,56791554,35a011e6,74872206,582b03de,e8e97728,94222a05,3d8dd2cd,cdaf2ac7,69ed8c65,8a004c58,7bdfd0ed,355be474,65be16ac) +,S(ca0d97ea,537a5dd1,147cb784,eda20601,ba88e0d1,68e8df44,6d8923c8,353aba86,874ac858,89eb86f1,88ebb979,a4490e65,96c97892,874b5b68,167ca99,f68fba1f) +,S(51de2965,34807454,7e798f98,c5fc19c5,84a90a0b,e1dda24,7718cfb3,ebb797e1,81374e3a,ad04e6b9,55c1952b,fcdf9a7,ace0ee4b,99e487bf,87ceff58,3f7c54d) +,S(69d611f,3136be2,cce39bd,a1d48fb6,87b52135,365b8df5,151c6ec8,c1387509,75e2d820,563b64ca,c4d127e1,a5c29720,fb84c0aa,6b271fa7,e9da2c22,3195bde0) +,S(31163083,558660f,23220456,1dcde218,6fa4a4c0,de450a9c,b2f57de1,3a8aa135,25d6d496,b1341688,3008c636,ae1d8b76,29e14207,e5fbb817,539ddbf6,ff46eae2) +,S(84e342aa,efa9cd4d,4d82e5b4,4d0ad9a9,11f4623d,8684c274,cc3cd561,2c7ac334,fb90dbff,260f9997,c84f0a32,4fe5d2f6,f552affb,50aed654,fb8f660,2a92a70e) +,S(95efc402,969db115,22446814,3d4e3aa0,fa812aac,8867a5bc,64d66692,67bf6562,315bcc31,6149252c,56f3f00d,445255fa,e4567d9f,d77ab4b3,e82c1359,9f371883) +,S(5223623c,f87e9da0,bd289993,a55bb9be,55b40149,bb501507,e3d5c9e8,d78d07fe,6bfd0a21,dd2df437,9b1c16,b0076f88,832e921,db3cbdef,fa5808fc,ac613b56) +,S(f212d199,a6b707e,61d87ab3,109e1178,ea180f19,66b0a55d,f5f4cb97,c0cb0a4f,3280446c,7edbb64e,e47c3142,7c0ea113,7f511422,19ec3824,12f6b069,a0f7c84b) +,S(6b55063f,f25d76f8,2154431b,20058f96,e1e19ce2,210e1b50,835cf58c,31cfe8c9,5427dd62,36450762,46e99707,6f60ffed,558a82a3,dd7e31c6,492088da,9069f8bf) +,S(2539e5cf,a09690c0,12ae0c12,9e6f8b27,c9388d41,a82e1e96,47219d57,9b23045,94cb83f6,1e26a4dc,d1b93000,e5113347,31d804b4,a259e24a,77c457ad,d9021ac3) +,S(aa9b6ad3,4aaf1c30,71aed31e,8f28c3f7,9106421e,f0e53fb6,297fae54,a47d51d,dc0958e4,9fe4ae00,98b4e7db,10ab4d99,58cbd87e,ca443d3e,d1c9de77,83544c47) +,S(a850a313,aad224fb,f5ed6e63,5a3f6b0f,e08964e5,e9ca262f,780532f6,13487ad,7e476ad5,4cbc55c2,3b9708ca,eef3479,d9a5e570,26f15a4c,43b83363,ed4ccbe7) +,S(314fec33,f4fd0c96,d04889fa,b18e29d2,5da44132,6477b28c,7418d4ae,5fa09c1a,a2c9513,a98ffb7,9b5dd4f5,49534fdc,d9b4b8d3,1aa6a4a9,76b7b94f,ebd25f42) +,S(6e7dc3c8,9ec57e79,ae1581ae,1afbdcef,183998b8,cf52dc85,329afa35,4f3d0963,6b636805,6d5a8e9f,9651e3a8,2598ab1b,8f057830,fccac964,a83515f8,9d9f87d8) +,S(596df693,fc4ba2d5,20497a50,7d1841c4,38b6cfc0,58c274ad,9557d400,573337c5,6609ede9,1c97b09b,3a171723,e9ec5cfe,74b75c33,d5ccb3c6,bd03fd04,b37f4ff5) +,S(235f8dd4,10de7800,58550e8e,77bd42d4,ee3ba259,97bcb4ee,13cf0a12,14e8afb7,bf6e0ccd,b8e8e136,800f8d59,510a4455,53b72c33,824b71bd,189e158b,6cfa6712) +,S(a9d8ba97,b259e91f,125fbb28,c80e81f0,3f03906a,ef692279,4c9cc23,13db8b47,e668b954,19b580f2,67472afe,221f5895,5e6ce6f6,45ba737b,f14754ac,ec048656) +,S(53b44dc6,4f74c170,142bc629,51349b88,c4e2cc35,b7d9a7f4,827b07e8,4a288e5c,4aff13e1,404562c4,d8f006ea,dfee7b5a,32216187,d8c96c7e,5896e157,97075d4) +,S(76e6e038,a6baf9f7,1acb56ca,1494486a,a9187279,486f62f,947b5a02,580af1a0,51a5d110,66884076,44c18348,be045910,3b57e0d7,2266ffd4,465e6b4d,e1f0f0fa) +,S(7761ff19,2fc70129,10eda284,dde864bc,1c45b4c7,1bec7870,2bcf53bf,9bc1e6b5,80980f70,a82f7196,61f7e1fd,fc3e7d37,e0bb75cb,b1ab47c1,d947dac4,296e11b2) +,S(8199c9d6,1224f51f,e6dcdc33,3869d860,95c0bd8e,210d2d7f,8fed2804,a89aadf9,be89724f,5cbd2384,ae9bbd73,f030dc74,a158ee7d,2a9d292d,daae3057,4b1ec89b) +,S(15c279fc,760a2556,bbd62680,3bd779d8,8bd4dcb,e508b3b7,99d27405,91c55c0e,fd5038bf,ed80c963,4915d352,bca040fd,ea0b9b0,67215dee,3373e4d3,53390c39) +,S(fb3f8d06,b2804047,6f7b46a3,ecc2e7ed,9724ace4,14831a8,3c111615,f8a39b46,f9250cb6,ff851b61,3b3fd70c,63c1bd72,3177ed50,ac991185,4fbfb3cf,6bd2154e) +,S(39b2b547,3c964125,da2723e3,97c3fde,f9faf415,db0b389b,5eac9a6e,ba012edb,8ac1c2a5,a586f413,bd68aedf,1f65f231,6bce7bae,ddf9564,2882f2,1bfb7547) +,S(42d5dffa,e476151a,1d3f6d0b,bb24e8cd,bf72d73e,ac87e848,20cff44a,47f1552b,631d9645,d941c001,627ebe3a,f403bcf6,663f6e46,17d86ee2,922fadb4,b8847ee4) +,S(84dc96c6,24ecabf0,a5edd071,1e922d9a,630a0bd2,6d9c6158,e311fb7a,e6e0bd8f,40af318a,16b7324d,2acff10a,8bd2fc25,c795cc71,c0aa5a8,2cc8eae3,ef8703c6) +,S(636e760a,797bceee,11b812af,37bf7cbb,4663ba02,c36d93bf,1873983,4bbf505e,ed5c5e4b,6cc8cf76,436dab98,104b9458,69924f40,57d92ff,d74f703a,65f724d2) +,S(137fd025,4bb5ee78,669ca6f4,ae278064,7d32bc0f,f6175090,d4ff7580,98d06ae4,282d6aa2,25eaaaa0,e9b186a3,36e92e7,e07ec23d,e9ce4bc8,8fb7f09,328d0fd4) +,S(218ab848,39e49256,b55bc7a5,cb250fc0,df781f60,17abcb61,1b6734d2,12459e92,7eb14f56,b53fb0dc,430c49c8,d32f39f0,1a7212fc,701ca444,c994b3ce,4d0e1599) +,S(6b3f7ba0,106f22f8,df69e3a7,8f137605,1b2f0a99,ebb4f4fb,61915495,5f8eda65,c5788c4,4c946bef,86d9a4ab,481e8873,6c831000,5d36d3b7,aaafb7b7,2330d299) +,S(9b414ecb,a2de1195,196fdf19,62eb5b86,131ad1ca,f7fefd08,c5de31fd,d9e8ceca,38e6f31f,9550df40,80db0626,9da9f4e6,51e94e85,95e74797,639225e,a725a637) +,S(436b07a1,857425e1,86933af0,d1d444d6,156a4a8e,f3f2df8e,cbaf661b,26940653,94a52f35,f124ebde,ca642713,724fcc63,c6822dd1,bce4c53a,ce155b31,443f2d44) +,S(cc0a9338,9b25f82,33419bd1,87b5e290,b8d76f28,2099b4d1,fff32cd5,128fbc6b,cc7e86d,ec7ac7a9,448cb627,875500e0,e713ad7a,430ee9ec,220bfe87,6e3f458e) +,S(5a1b316e,aaf877af,cc7b1907,eaf8dcab,7ea684ea,72fbf888,8f21fe83,c3a19858,4af0339a,da08846a,6b6b3466,da69412e,74411094,22dbc450,cf7424ce,cd81e7e1) +,S(faf89165,74444bb2,1fe1e411,40398b25,ac4a5725,2f9ff274,e7d409,6d6c53ee,cfa7795f,af75547f,5dcb6426,3b16c9c5,d87984ac,81083cb3,99714f6c,99a43100) +,S(39e5fd8a,ca141623,1840c68c,6c6cb028,c94cd22d,49619e33,aa9e4dea,d174f248,f8121f65,7083da65,74013e78,88f66276,a8d3686,528aa105,61d10a6f,8c3c1ff1) +,S(20a135ec,147d0cf2,ccd3cddf,6fbe1356,a64b8ed4,219bc0e9,25743098,325cbc1,b17514ab,ea1a3725,4c101fd2,675d30a9,fa1d170a,811f06a7,15622ae6,ee82c013) +,S(a181a1b8,af48f73f,a13d69e2,ac75b13b,9903ca11,8a8851fa,b461c2b4,2c72320a,c96c8467,3f487e62,3d72c432,ad5887a0,a66fbd3a,c43aa5a,219c84b2,97a6df20) +,S(395fc031,720a5da2,faf5d76a,9516de8d,eb462695,5eb87fc2,752462c7,7db3ee4f,4aebc86b,53783895,ab4e14e7,c3ec449c,962ac869,9b340523,1288bf41,c759ad6a) +,S(a36de9ec,f6df2b96,87d632a6,1bb6337d,3fffce5,71b9fd17,4246b33d,1b64fa6f,784e4c4f,a133d140,1b212e14,77deb40d,620fe29f,d0f05ea9,cdbdc862,651999f4) +,S(8cb5a899,ecee4430,f7381820,4535f57,e55a3ab8,3dbdc359,d04746e2,9840ba8c,12a7282a,e9c3a3c1,2c1df0ec,c3d28b4d,731dedb1,ef02cb2c,b92da5de,17ff59a) +,S(de441e1,4d9c9ba1,90e37201,22fd1fbc,4cee72d8,b26b1f29,9c450b66,60b60985,add1a30e,d12ddd33,d4f740d4,427fbeb6,2927b3c6,75032110,508e2114,271b63e) +,S(88e38b56,b5e5544a,f2f3c1b,7128d118,520646c3,97295067,4078207a,9b9fbab7,8833208e,d44e9656,e5bac529,cbdaf184,dc8ea020,a2d8f4b7,8101d8e6,1000e5e3) +,S(a4f0f992,f5616420,b9ffa3d1,58d2d729,3ee217c9,60f5266c,6c5f3374,f4640a7,da6741a8,437a86bc,40ec9188,a1af42fd,b131a8e,81289e71,3d80e201,f82e6ddb) +,S(5f00a8cf,f2d1aaae,604a40be,e451d8d2,86899fbf,37f96ad7,efe52407,1c5c945b,135fc8b6,9ea76d6e,39d1549f,b4692d5b,b48ead3,ae6c662a,424b63d2,b59deb12) +,S(59351a0e,bfd6fca2,ee04c799,838ddb8f,9d168967,a9e6cda0,b416ce31,88f99218,6e01a267,3184f4a8,28e27b6d,4291e7c8,fc4159d,73a465b6,4fe3d4e9,d50fdb34) +,S(175ee35,f5c533b3,de87387a,5f263d0c,6705ef73,e77f39f7,2c796f91,2cb1aecf,a3792715,4540e426,1e0d40fc,4c5fbd60,5fca3b63,3cd7b506,a80d0280,b9d9513f) +,S(75189b41,597b18ac,9ab6362f,a7905ad4,5655951d,fad033b0,2047dfbb,f347b8fe,f536fd21,ffa10ea,57c023de,256a59ed,aa246842,845afed5,b0177b77,21b2527e) +,S(91af9ec3,2522d65c,70bd2a31,57efd23a,43885573,6b5a1c72,49a414,a19bd4ae,312007c3,8462b858,6b44898e,d0b4419b,31c9cc19,a2ca6d6e,6436bb08,741a32de) +,S(ddb2fc8d,41fad5d0,5d109443,2f283c5c,732273a4,1a14db04,712a1d84,a4565c27,4f7e30c5,2cec6f4,201673a0,9893d092,8f6ac9b6,d7f2da38,d63ba2fa,d69c1d0a) +,S(9ce65d22,d7240dc3,50144936,ea412539,ad40a907,f2b04f96,f7ddc1df,f63641a6,af93e587,7f25bc64,2460b425,76062f54,c3037e43,80542340,cf927609,79d97c8c) +,S(7dc0d0d4,1fedec58,91c3932e,b0bf492d,5489f1b0,1e7f95f5,4936d76f,776e9a2b,d55a279e,760c3c13,bfa1c7a4,93831a14,1e9bbcf5,a535934f,a5269995,b107c47a) +,S(d01215c,b6b4d728,9dd8d351,f3e4aa7e,f190d40f,3281c8c1,63d03a95,4c0e5ead,ef98344b,ccbd7eee,723ce7fe,641854d,c68be6c6,99eea25,48b2c881,b0fdc662) +,S(d4d1c31,a9faef8f,5991b0d2,9bdff3d4,bb6498c6,2933eaf3,e1d06767,8d7cb92f,98f3a848,ac6b91fa,85bccd42,f2185e46,715faedb,a4f6590a,4df5f862,ae6a4831) +,S(cc659ecf,42abf24c,3da2d83c,84b1e32,3d718f0c,41a1b5a4,9fad2f24,c6080839,7bbdfd55,4d843399,b6edf249,ae795758,c7aef094,3f84ccbb,f0f2761a,c81f963c) +,S(19ba1567,d5cff385,9d074e94,478bef34,f0eb4775,6708d04e,594d1641,71ea4b04,34ea281b,d536b02e,da858311,4e59c110,30555c91,c8b90ed5,d4f53485,4a820f9a) +,S(3f0f02e3,1a6e5907,631960e5,fd52d2da,e825d8e7,529586a5,437798f5,d7bbc30f,b93e27c3,3aecd4da,59079ddc,be2cd6a5,62a3bf29,7b40519a,3509061,e3e63c3b) +,S(9884c48f,35f63fd9,5a9dd895,b0f382b4,8d0fb096,e5fab23e,df07924,149ab12,5688c266,7070437c,3d5e321f,58b6f41b,e011545e,989feaa0,13f241fb,4180eb44) +,S(940f2a93,79bc9c55,3082e85a,c2f83e5a,bb4a6fe0,2b23cb47,4489bb7c,c46c7b4d,b4b82380,77ba9d8f,51e7c735,cbc6a784,2aa7429d,2cae2284,700c0e2c,7f21fd9d) +,S(a9a7699c,e5353d9f,41afeccb,b5343ea4,5f4beb03,42f9001c,e0742eb,58b782f0,3c759eaa,b3e18cf1,a4341f77,8a601ac9,b0536fbc,5fb498b4,c7ca9597,9587c994) +,S(a21e348a,9cdb00,56e36cc2,82d0112a,93f4da1d,23f274af,b1522263,b218913,141543fa,652f9506,6ecb8e28,a701e663,c70b1873,b1e778da,588c1f4c,7ebe89ed) +,S(d6d54d95,1121e118,52b298d6,18ce738,e8142906,306a5ca4,1f048fb3,5a5fd383,897dccb8,de891fe2,304fe9d0,38d8eed2,8f76c8f3,535a2912,41253445,828a7a83) +,S(7e0a635d,c937eafb,488c7f7b,5efb12fa,6232b464,a3a47ebe,21cc0f1d,c31e6cda,d2d1d4a,75525e1d,2ce5b34e,3adcbf36,74489c86,ced61e82,2d63ac63,8de921e2) +,S(4ce2080f,66a21c68,428870e8,36b3fae9,55bafa14,fac200d3,afea00b8,d451a659,29e1fa26,565b02fd,318d0f3e,f0df93ae,f0ca1b92,73e31b1d,891f055f,6c7da4c4) +,S(dab86b87,b633bf65,59cd5caf,1b89e815,e6d4b7b4,d8f58f7f,c091f542,712bad2e,8e49b109,d79a55f3,8d8159d7,f55bd930,4506a634,7e57bbdf,8fd15eb3,53c85b5e) +,S(c6a14ac2,90fa32e4,e8b5386e,a7672d39,ba16224a,152897a5,6ae29001,b365aca9,42aadcd6,dcc588fe,2421967a,42ff615e,45cd5f2d,fa258164,b2c0eac7,735dbc67) +,S(2599fa40,880b108f,28f24400,4f3458f6,63510bac,c8a1041d,e694e214,ea450a27,54792ad,4ae1cdf4,6a7a973a,1a02bfd2,a424c46e,548c13e6,951d94c8,7ba57a01) +,S(f6ab0cb4,a6afa8f7,aaed8fe9,e79ec43d,31265533,6fa4553b,bf3d7476,8ed9f9ff,4ea12589,c4ba0090,48c1a476,1907fcd6,82e913bc,57af13f9,73fd9746,845026ef) +,S(f51bd48b,ab8f020e,2d97ecdb,d3ff4da7,72738ff2,bc71dbeb,dfdd48b2,707f1dfc,6b168ba0,947f47fa,8a7fe7bc,e7ef90f9,b361c752,248bde43,8c93f3f,4a697c40) +,S(b601f114,6c9ca90c,af798f2b,1d0bf7d2,a50b286,53521362,5c898f0a,4a2a3443,a6ca3041,36b6b675,5f317a11,59f0f110,6877fed0,fcc167ed,f0cf2391,c61f87dd) +,S(792dd67a,e5957c04,76f0511f,c5b7191,5be6a158,f2871ccb,37e90651,f85f974b,9b7f5cb9,bec59f69,3a44774d,d2f463e1,1a4c1c5c,84ac3bcb,94175809,4b1dd44b) +,S(7d884669,33b6f4ad,b3700eb4,f02514ac,4c29c420,33c34377,93101302,8bb093f9,2fc8c35e,674500db,5287ead3,5e46c306,2ebeb5f8,a5134885,a2f9461f,b5e2cb3b) +,S(9c76eb91,6d0f860b,21b82038,77089435,ead4bc41,df82c249,10edb80,692a5351,72badbf3,38800156,1e235a6d,a8c7769f,e51d1e0,d6de06b0,d9998290,f5c88b62) +,S(a49b5638,3d8a93e1,55e52a2a,a1e47c33,8fef18d8,2dafc24e,cf5bb0f3,1fd807f9,1bc271b3,9bf34c4c,ee4b0760,bc934646,9dc392e6,1fce976d,bee58e8d,901d3ae0) +,S(4d3135a,675bb0b0,ca9d5cc9,68f1c72e,a704c9fe,77aea9e0,a4d6247c,dc634460,ae5d7cbe,72f5f4bc,f2f1ffea,cf02b13a,cb74bcef,68cced38,395a76ee,280cfc4e) +,S(59572fbe,17dd6e38,fc0421b9,b42f192c,eff95583,a9204e37,11f33089,9e53f588,57134640,a8cb3f9e,6a1ab805,1d60a047,a01c8f2f,9b72782a,39c45421,de1c7c24) +,S(73cccc6d,49b4780e,caaa1c61,228d2e9a,a5fff08,f5605a5,cb5ea1e6,712d9511,463a8d74,f986c8f1,1c12ea8b,59b158d3,6a52c06d,6a85b08e,dbb2cd4f,e3752cf4) +,S(b6c8ebfd,db620aa9,476f7280,e8fdcf6e,ae3885f1,87683d1e,e503c2a3,8c4c1e46,9a6faed9,f0210048,be575c2a,c8194a5e,76a25d55,f3215dde,b4091060,e7d39802) +,S(b4162e0f,92de5493,da996c53,93067de3,b9cc4a8d,4c21df7e,b507fc9c,4c5e392e,ccce10d0,c9211d36,46397873,3060d982,eecf2217,7b8ed120,a4052561,6a3b385b) +,S(46bf2566,ca4235d7,abe91955,2a0b8d40,a581008d,6544d9b7,a2a469d7,8d2b33a2,6f66fd6b,b8278841,92d82e39,cd0bc9d5,285b5cf0,2171ef1,b77c87f,c6785040) +,S(78446da4,e869a9cf,8badfcd1,b89c135d,b5422a68,2a9ef6b7,419a914e,3d59ab2f,4215b131,db7e46c1,9e03c051,f33bebde,3f5f31bf,2d428983,27d2b586,5a8c9ce3) +,S(86886a05,511080cd,42bdc762,95eb8edb,fa2b01ca,5cbd1d1f,4bebf001,5605f3b7,c71b69f3,5579c0dc,7078854a,83add404,f9b753ed,597a77d7,67507e77,f7914466) +,S(a02e675e,37f8fc43,fd38675a,744406e0,36d5fafc,b28a7371,e16d94bc,83713388,d6f9a541,835c80d4,eae16251,277e9eac,4ee66bd5,a1899c36,de3173de,fc41239e) +,S(a16b6aa8,432c6ced,cd110096,697bc04c,9b299777,ee287f14,ea4cc889,8492bf26,5c11a70,ef9e42ac,d0ed644,6ea7e14e,1e734da1,89ef1ace,d2fd7241,4e0db298) +,S(66a3f2fe,775fe5e5,d0ba1205,f7b81fca,12d7fc2b,f8685c5c,97114b98,e0f45b5a,5059bd14,a49ad49d,550daad0,30b4eb21,e626e2,95ed01c8,c1823050,5e5e3eaf) +,S(9a47a3ce,bf9a04c6,755c6321,61150ba,a1f09460,ea855785,96213784,5314b3a1,22da5ece,8f387e6a,f37c7045,b9296927,efd3a3f2,2b95eacb,c6cefc0e,ec40a80a) +,S(1c014014,9027b9a1,e3ce3c28,8f18fa87,12b25a53,49f9ac6f,97af6273,5b6628c5,672190fc,d048d3d6,b78bc34f,f160f978,87b49934,5753bd35,3a456c96,e448a4f) +,S(c2d9670a,1de5e876,5ac965cd,497e0765,8d137400,9e4ea31d,57effe5,2e8d84cc,ff818647,a6ddfbb1,3ab56b58,52956d08,b97a2e8c,f852379,cc7a7271,f13ccdf1) +,S(1a9fec47,16fd6a69,70ce094c,4141d68f,d21339e5,5396a691,e01b1e5,c996ec1d,e38eb2eb,6c8373fe,94f7639b,595de291,d29b8738,11f5d40c,24006d8b,93f8557e) +,S(b7df52ed,15e91a6d,40e9e500,6b1ab26c,53a51466,98d63bae,77856afb,1d8c464,ea60f1bf,d915fd8f,99d0706f,ff180d51,705c360d,a5fdac1,162ec530,b6e21254) +,S(2f95cca,bd092e2f,bdc86a53,40353350,918ba7f8,8488b9d1,295f9959,d7db6b5f,31456814,fe6ced86,59ea9c3d,f09bf38d,d5b0f893,8db1ea7b,5234648d,a1693ad2) +,S(763926c8,64dfe4db,6a1a432c,a37e4022,3b6ae1a3,7def3fea,883a6612,bd8a7c1c,f34d5b72,4378d10e,bb4b3e63,d80f1f98,a3e741e5,b9e4fa41,bd3f0a5,c361bd1f) +,S(2e43be7a,12916cf6,f312a513,fcb6c98b,708ce2dd,18dc4ebf,72a807c9,c8a31b0d,db919224,ce1b7e57,16e57b6c,ed514cd0,a3a9dc09,8cb59c5,971e99d0,dc24acfa) +,S(7d65e48f,1a867d28,76731984,afc6873c,2d1acdfb,13a5adf9,a56960c1,cd4a5561,9c73b955,f0957ad2,ff0e2d4b,caf795d8,bc992436,be7e69da,7b97ccbe,d983ebfc) +,S(1c6becc0,3131b772,cae166f0,4d715390,6b132c87,c5c76b7c,10b94a71,7819d725,2c3c64ff,94998533,97dd26c,dafdf608,41b84a22,cfb4906e,318c4d24,b23280ad) +,S(f5042a5d,5d118102,32ac83c7,d7edf079,aff339b0,7e9d20f8,198b2a64,13347675,19c10fbc,e644fc6d,2f238802,a045052,b2723f57,5a8bdd20,b597dffd,79a3e4c8) +,S(7c387866,c2c0353e,6e00c887,240e084f,e0ee9f0,2de12539,b4833588,bd4be300,ccc66f94,587fc58d,42fc49c6,d074800f,56f08855,6caf4ab4,c37b43,ef2b8f79) +,S(ece8ad23,d33adc2b,6ce38194,58ba2ede,104b35d1,1691f4e0,b7b206e4,eab3c140,eec976c0,7fa1d3f5,f3c245a1,2c9b728f,1c7e672f,53665e7c,5c6a408f,7c0c0a88) +,S(822b0926,a274dc38,c9eefecc,7d021774,b951cf19,3e2cbc56,a1baf58f,19d12b9d,48bcb10a,f9cac375,8314d2c4,9fcf0512,3638f008,510fe63f,1be0c2de,44118313) +,S(d26a3a03,6ef5f428,fa058d25,7ce62fe3,401dfe47,80c468a8,5cd2e77b,f85b8c3,98c39762,3a644329,7d5c6759,a308c2db,62f1bbcf,9bae4ba0,10fb1175,126a6fa7) +,S(7febb81d,8aa0cbbd,3002ab6,ca247d1d,24c8fcdf,bb1664be,b5b3c346,93019090,ee625bcb,12ca6da7,544ca6c0,2a84b9bf,966dc923,d8b23b44,6cfa4604,a6c3ec26) +,S(839e44e7,2d43b6bb,e6f63a75,cc3644ba,b7aa002a,6de2c087,33df2b0e,51d3473c,8368f635,26f41422,a563806,d775bf68,2d876d98,542b3da4,3e591e31,340fb9a9) +,S(52e947da,1c96e07c,9e2c84f3,23f2eed9,7e049b97,86d21135,ea958eac,db0d7afe,6bcfdec9,e0c70d3d,39de19a9,9fa72ba,bdbbe50e,dc44897d,9fa670e6,d473a831) +,S(72ec5426,5e4a743,1d7f6dd7,1c8e9e4c,c8b22074,cfcb00ce,db18c6b4,c67f3603,ddb9360b,7f9def94,f5ea6d71,51eed4ba,49455cf8,15bc9023,6156d4fa,786b5ee5) +,S(370a3f15,59a55689,16bf9ba,f2863d11,2ac051e9,d6a90f36,af39add3,1406c849,854cbda6,8517cee6,95ab5d3,20b1067b,ee80d993,235d1dda,ba3a0ec6,1f005840) +,S(12e57888,60d2fbdb,cb3af527,577ef6a1,41d1cf0c,f719ac6a,714f9a39,9bef5dc2,f5af7aca,5dd8126f,7dbb79ea,d5a4b475,a094969c,64adc821,ab46c5c1,86bd9ea2) +,S(b494abcd,b2fa5de,17b1abad,757bf9d2,8b7905c8,aca0a5bd,fe2ad8c3,30a2b722,c397ffd6,dad8619d,9ff8d8ae,e401a4f8,cbacf710,c6409adf,bf991d72,9294cb87) +,S(2957692d,900d0b94,b208245c,f71bdcb,118ea6e4,499dea83,1064605e,8ab9d89c,a3c55447,9284afea,37e94,fc24d50,f129342b,7ebbaa91,857d655a,40444a7b) +,S(61101879,f325e072,bca13642,dc14a5e7,1969aed3,2e49ccda,39cbf723,a1bd20eb,4e199c82,4816e4bb,d5b67269,e9d8eb0b,e5c2483e,d66757a9,c1d59847,e443b3) +,S(9eea48b2,99f3474f,8aa8c648,c2721fbe,c65f6ad4,990ab4e4,29a9c41a,ba55ab18,13954697,35ced1bc,7e857049,7f2b5a1f,b6802892,fbee0654,c1d7d89c,1f234443) +,S(dbb054d7,8ba7b707,ca475982,6a36808d,3fff42b6,31f1bc5c,c9df403b,518bd97a,396ef6c0,96343a55,dd404885,427e781f,a55a1f8,1ab95d4a,89d87975,611b923a) +,S(dba95bd5,7fdd2ef4,9dbcc0ea,35c14dc9,b2f62541,5b08e75c,d70f3caa,b61bbcf1,2af0965e,b7a17e46,18b6dba8,415159ba,b8f76ac,ae9384cc,64a90e32,d20a3d) +,S(6c312c9,7979bb0f,e72d8feb,c3c755db,bf1a132,722f6ef5,297beafb,8ad0e5be,36366388,db74739d,df78d5ea,3d8fab54,6c435961,71f78643,8be00718,8202c6ea) +,S(65eb7057,a494bc8f,549b8638,e18cd717,ad987030,aa3161e5,b9fe31b6,dc8825cd,458202a1,67f285e0,9196b4ac,f87068e2,160b7b42,2095bc92,7656694c,2fa80312) +,S(a0696917,b0e868da,ed5db7cb,d2aebd1e,c1117426,d842c0d6,b567e2b9,4effa7f6,c874d20d,a1bb4dc8,f01cb828,be8bda8b,c797ec3e,37feb0f5,ba55675c,41ecba78) +,S(4191bb82,19372a13,2dd37830,1086b64d,10874479,1d3b7879,3b27c65,782cced2,c74907c9,8ce4d218,d1ee52bf,82e130bc,49335279,2497b4a,34892fca,67dc3f2c) +,S(75f37d33,721293ee,5923b9b2,b95c958f,945e3f2,909c38f,3c3e7f5c,79b218c3,ac041f8e,c6b222a7,a2f28e18,1cf11aa2,a7d2fda1,1f402a33,9afdeace,a5928be7) +,S(cbc3173a,b58b2f29,20b3bef,6f18a84a,6004d1f7,1dd6c65,78571afb,96fb154e,c413a0b7,6f264414,2d3c166d,e9577ee1,b8f36ec9,618e8892,26de4de0,f9fd5c37) +,S(64e56b09,a139fa59,69688832,419cd1bd,64f212f4,5bf4cdd9,2a5e4370,dae226cc,a9194eee,f2429016,4b41eb3d,b429415,d10915a8,62a02fa7,671bc19e,50fbbbe) +,S(e33795c5,e2886cf2,9a22c2fb,8e02f913,34e13350,9cfc14f,73bcfb49,355285a6,7890fd21,f33d48c7,24e580cb,7b4bb065,f7c575d0,c6cdf5e1,5c2d6423,1afb304) +,S(7975e6b,7a73d0a0,d1543d2c,76c79233,6e6a0994,35eb7699,8f25ce75,a6b0b6dc,10b160ae,c68993ed,d5e48d5f,7562bc24,8f16eb10,a27f7115,121ce2f,f63eb06f) +,S(6d0d13cb,f9c13967,92e093d0,801f441b,c1ca4484,92ce3ce0,2ad71cdd,d1580f6f,17ae4238,84caf022,bbddcfe3,37a44309,4bdb25d4,71da56f1,bae4bf2c,ebb45746) +,S(2195f14a,23af2b59,c9fd3f90,42608037,60d39867,3fbd0856,a974a20,1bdf0154,fc05b38c,9a44ef01,f4db3a10,b500a372,5ff1aa58,86ff6111,da53ee14,f8136a8d) +,S(47679c73,60acf8b9,d1b54e16,7d1dd1a2,1f558288,3844fc4d,ac2a7fdf,8b713628,82a02225,f3b8e81d,e4d4bbde,94f7cd97,7ca0180a,ff3a4751,a93f6ca,17803ea7) +,S(b0bd02f5,1636a69b,23ffe514,cc2166bf,8cb4ff2e,2f7c8655,ac9aa7c9,de30831a,73fad62,48bacbc5,2a7ffc51,fbeba3d8,f4843b3f,ba6c8814,48add0d0,8fd5f518) +,S(dfaeffd6,bfe9f81f,ed3f81af,adbec5b8,aab5f15,23cb7452,c689b01,a3660158,3f54d105,c3ef4814,e6ca4bf9,ccb5b54f,30c4bf80,10d7b24d,f3b5f3da,c9240583) +,S(eb016abb,da661e49,8f53d2e7,96fd6be4,80dffae3,eb7e4ba7,46ae06b,f40d42ed,310d6dbb,aa7659a9,6cd4d50a,dc2e5e85,10f005ed,6d29d1f5,18bf83a2,7af895be) +,S(989e1bc4,3c0880b3,6d35b5eb,137f8e61,7263784c,d2f35173,e517afb0,c99fb2ed,4c4ceb5f,110cccc5,3a35963d,11df77d8,999b3bb4,c2cd92fe,b53b7476,9dfaa1d8) +,S(beb0170,be4a7bbf,1f65bd40,776d5efc,dd801d6f,909250bb,fbee1198,c2033811,1356b98a,1d329a38,57a99820,26d3ce6c,f52349d,fcc59644,ff4dcc13,8486461f) +,S(2d90bc1,986f9a4d,6f75e596,96c4296a,ea9bc55d,5b60d12e,337cb42a,ffc0b145,7d57cf64,734d1997,bf84b721,e67eafb6,b377ccbe,d2ef3b5b,48dc9f06,f71a0c4c) +,S(6b7a6a54,c9608062,de196848,dc3673bd,59fd53f3,fee72481,e829ca77,789f51bf,6a9ee208,157b8a69,f0879f30,c58afbe3,dd4dc42b,43cbf21a,5795224e,6c09af23) +,S(c99244c7,32cbdfe7,68df8fa8,7b7e7eeb,16faf0e8,8870fa8b,f4abcb68,368e8393,20ad1b55,53ba2ad2,40563453,b2dae2e8,58cc9b8c,c6a49951,bc0c0fc2,875620ae) +,S(553fc07b,402a8dc5,5f1cf4fc,609a01fd,350fef26,9c1f93f6,d2871f94,70f01b6b,3b518c75,39616def,fa7cd0dc,7d7d53ab,9b310217,7e470290,9c199137,34e5a824) +,S(c5930378,6ed8a7c,b3cdfc80,a34c85bb,721fa927,9492e369,a4e4bec0,c0fe2f69,3699e469,8a3e9129,3796dea6,213fd702,d7580e67,9f446300,1e1c7a53,3717c149) +,S(cb6f1118,f4d59964,b8f4613d,8c349d74,8cda0e7f,f1d11c6a,79dbecc8,911e7eb5,62b0ae88,98b0d5cf,723cc88f,48257c47,ca0fe3d,7de676f4,cf4835c8,fdde20ee) +,S(da2cab8f,8c26668d,d9722ae6,1decb99c,78b5d48c,966889a9,46fc522a,31a26db9,6a03377e,234f949,4a614cb7,c93b131,1808496b,12485ad8,fc21e1a7,6d0c7e98) +,S(fc6a4d42,3f9be3c7,fe337411,f03eef,fa595b83,9a6eca82,b228d5e6,b43b7d86,6c089544,eb8fbe1a,3dc78fdd,ac253fa8,27dfbd6e,269196f5,bb476865,a298beff) +,S(73c9a91a,b9c6e0d0,773258e8,3ca9460c,3d09fb49,9426fe09,db73756d,e3dee882,8b314327,efc0508a,d5a90259,c9ed876b,52040a10,45d06224,78cd635f,e571d2b3) +,S(a69f061,45b8cd1c,343e6127,14b80996,2bc02848,ae976762,933744ca,3b4516d3,87518d90,b4503741,ec16caf0,18615e27,96b6d91b,47f649ae,a86da209,d70ebe3d) +,S(1cbe4a25,70df40b7,1cddfb2a,c15ba441,376a430f,446a2572,fc95235f,28ed9691,12554ecc,f262e1aa,cf2a2d10,ab3953ee,c8ac69f3,99c5380b,6ef5d202,5613de85) +,S(8dea49c7,406dccfb,4305ac85,ba08b191,4ee2f11a,8827852f,d13c837d,b788e27d,c73d61a8,3b517c3e,bab8b15a,b7a0506c,2b6071e5,697b4056,d902957b,cfe9d9b0) +,S(de926377,b175cc3b,1ecab5af,81d38d6a,5e4b717d,55bc94f,6e4c43a4,86d0ade5,29d5f3e7,9169d974,d4289115,d8d4b8b1,6be387ac,e60d1cb9,73c387d5,17d0e11f) +,S(6e76eaa7,aeb37ab4,ab455a2f,3d525140,f6e8a9cc,5eb18fa3,8a9a25b0,d3b41497,7e3cc5a,78909d15,bbffb936,a47aabd9,44c40a3c,d690908a,89f193e4,95e066fa) +,S(37131ecf,22d57f0d,a662b03f,c9891f99,4678539d,37f5ff8f,9eed0f8,bc607574,c03b2d21,69d42968,f611d596,e173d4b9,281323aa,6abae6ac,c177a1c9,1249f3b3) +,S(72088814,82c89957,28e76633,bcdf0ebb,65155c8f,4979a4e7,66713f37,4a5d8152,6783c59f,8c0adc8b,da8e26f8,1990a00c,588a7974,b48aee92,d2a762e5,c974eedc) +,S(1b8263df,baca44b2,a7fa7a7a,dbf9d3ce,d4567fcd,144d9e8a,db712365,d3241864,1fc7e3e,24f01143,1944b98d,b2dac036,edf36680,80196785,783a41be,d788606d) +,S(7a372de,27ca7f2b,8199714d,bd583edf,ea41bae0,5a1313df,f1a8c260,cef5fd43,a0e3216b,b32c5785,b5c60f22,f5e4ed5,a5d3ab64,ba0eb2e2,916f1b9,b6281142) +,S(71815daa,55254491,c8bb9432,755ac1f0,c30f22fd,79d4232a,72bec0ea,8cd02300,8b341392,8de15c16,5fafcc68,84ebe3c0,3ade0918,4c463804,876f1600,c76471b4) +,S(1a54b7a,d3cfcc64,b62d866a,9f2056e,5535d4c,12c89c78,5d1c5c53,ff654d2b,b7c77ae3,9f4b87bd,22c77395,a91ec307,e9f5aef9,dd2892e8,41d8390b,47a12f19) +,S(85cb4457,1fc973e5,dcb0b695,3d75a2ec,22cd2820,74039987,7262b7ed,999c44a6,efdd1df3,bd13fe66,c0d4ef02,8e142093,58037a7a,bd06ed53,280d3318,9d0f6aa5) +,S(98e8649c,64a010c9,424b305a,2407a36a,cd72df8e,138df962,c35bdf75,fcfd4e4e,a804c569,34395d7c,549f7770,4c3faed1,624a8cf6,fcce08ef,cd3aa486,d5a6c60b) +,S(1eac47e6,a297e5a8,8f433895,874fac8b,5019a164,69c6a881,7e500b94,74a5a72b,8b7daa6b,784ddeae,f380bb1f,fe64b9ed,43a10a2,95c30325,f519e4ae,da11105) +,S(f079ac65,91f27363,17e9e0ab,6a723e25,e29950c7,a02a66bc,96c4ae68,44f42f5,ea87d1bf,c99f4374,4acc3ca0,214a1ef7,490186d0,3d924562,24981469,c432dfc5) +,S(d6d09d79,bf1f30e0,f011c3ad,a077b1d8,fa0d94e8,8683186e,ba471caa,32539643,8770bc64,fac8f541,f730494d,cdad2d48,ef510037,466bc049,876f5cc9,7caa8adf) +,S(376e4bd9,f8963368,7059565,68313f89,d6416ca6,b1e4e91e,3aff3ba0,b8351f65,ba436de5,67248f1d,5e99e8b9,6447cb28,497deea,47fae95b,78a5378d,e65f13f1) +,S(270f3a18,4b42c799,a2193dae,c96f834c,b17cb53,bba1610c,6578c741,b9f20d7,ccceb12b,9ab98bbb,a0fb0d0,1673377e,3a7054a9,f4a3b000,21b67328,57e7e5bc) +,S(ae271b64,1a1e5348,29e47a8a,93b496d0,b055d2b7,fa98ade2,f505a5d,ec1a599,14e9552f,39b481f2,522a9a23,f87afa9d,5847908a,53c1581e,45dfb244,7fc2bdd3) +,S(569eacfb,177d8a74,a9288ad6,4ee5390e,db36a93a,943fd6a2,5ec869b5,a7f28c8c,1cf62c32,9127642b,99a7508a,a6f4f136,bfda9af5,45f52844,cb9c71b,5f732f7c) +,S(77c7f27f,fdc4e7ba,a326a246,89790f8c,41bfb5ed,6d365e46,f277cf81,5f15b558,4d3440dc,138be5d9,566a6828,852c2ec0,e0f970eb,4501a43,25af933b,821c3007) +,S(d66292db,f1730306,a87f67e9,b044fef9,7d46761e,7b8301ed,132ed7d8,94adbb25,ceef7755,8ceca4ed,92145f23,8bfcb32b,3d36db14,6fc50209,cb0e58f6,2c8b83c5) +,S(1c42832e,12ea6f44,b77927ef,7ebb1f3,8769e3bb,f5507a49,25e8565e,a77ed0d6,8b9383a4,b31b4f5d,a717917d,9e1e41da,786a62a3,327be11e,280e538a,9c29d5ee) +,S(63e57eff,942262a8,cc362911,fb98cf30,60832435,3cd394cc,5d6abf77,b21f7968,9e3c1e2d,fb9083f2,4c344e7d,322ea530,146062e2,a25fb6b0,4502ea35,59b009be) +,S(be233fa1,86f38a5c,72c88e59,19094ea8,cf3ed3a9,b4ea3f9b,2a51489,97b83c90,402eb2b3,362fadb2,6e389ef9,edc537bd,40bd48ea,6296956f,efd19d0d,eddba564) +,S(636ddb80,4e7c74fa,9c5f4d06,5a730fce,f2cc6956,4a24b579,aaa0c3f1,61844b78,6a4a3569,583212c6,22feb59,897eac8a,6aa31ffb,916262e7,deef47eb,e6a2496c) +,S(d251c1d1,7250d87f,f7b5af1e,ee2f2566,215ae7c2,b6e69e60,5bdd6c2c,dee1c5e7,245accf5,7df52fa8,cab5c986,2b96658c,5de60d06,c84584cb,f554b518,7fb4ae78) +,S(405d4cb8,c62f133b,7051cbe0,54b06f42,9055f917,3ba8248c,c3bdc744,198ed407,8463df10,a8963cb4,298e8031,bd2bc3ed,523553fc,60746720,1a9abba7,305deb54) +,S(97f05aee,9ab33a07,e14a0314,4fda5be4,ab329394,1ce8f003,546ed8e3,9be983b8,59e62a26,7fd9138b,c4c70b15,533782cb,d321f120,1e3d1a7c,3be4ad5b,eb849261) +,S(3388161,18e125c0,6a9060f2,6b9ad691,c99fdf8d,4309553d,ea160749,eb91ac8,583e918b,5b8e1a68,c053af0d,245a9902,a571788f,dbdc0c88,7281767d,9404384b) +,S(ddd20c46,6bbe6a25,9f706b1a,ddc3b607,8cf65366,3369fc31,dc8f7fd3,3d17a9f9,b2df7b29,b4ea9868,bbaadcf4,6621ccf1,7833e159,acb43daa,7cf78e89,c1de5a99) +,S(923c6d2f,71ae0ee5,596c26bc,31389cbc,eecd0712,e8df91cf,dfe00172,3bdfc9f7,6fdb28ad,27c41243,6a41ae96,99a03d40,5ff2ed87,3207f082,414a4370,34be948) +,S(6d42a6bd,28d57e87,66a12461,b8a7d111,a448876c,149071a7,fde9df18,dca09e65,4df07ab8,1dbe97c,3585554d,f0226234,dcdd2826,747f2775,640bed6b,95fd28bf) +,S(7fd42961,59f9f259,d3c3610d,8539ece1,70efe104,31c9a3f0,4b9630ec,21d761ae,fd695441,b8ce2bf5,1037d00c,4d50e640,e85b6001,6d5d26dc,787f1df1,25d7e280) +,S(48c1050b,128d97df,e7900a01,70559990,944045dd,f408d8a7,5b59bb25,ea6770b5,8f7ceda0,4b6e319c,1cc61b31,53538a09,d450e49f,8863061e,f9b017c1,6cf66559) +,S(54462d9d,a12d62dc,96abaa1b,4883c67c,b3214c40,de5a4a09,689658f7,dee2a686,7673ad6f,916011d7,fd33bb5,eee819e,6a3f0016,d51ae37,bcfec2e,59ccd957) +,S(698534c4,e4e11d89,82a5a46e,44b771f0,95c5fe47,54d7a261,44373982,1e6435e8,36d602ac,b2720c71,8d619a8a,5e7d6873,9faba099,f71c1137,6a8f41d4,e1cbba18) +,S(4493f759,51c681c3,bb376b0d,7c88ecd9,d0bc2a21,26fd341a,d8c4832a,be77ecc,e553e21d,d4d99aad,97f15857,4bfd54be,df7143f4,e829c12a,39109892,c120351e) +,S(b054daa9,330080e1,89784cf5,f917c024,6c06325e,687e6ec8,cf8be248,ccf8313b,51f04715,5c9ce55a,c755f2a4,602420d,4ed52a5a,1dee9a83,b0688b1d,b767d866) +,S(4b4272a4,fa996b1f,9ffe6796,e6519db2,c1f8cfc9,606fbc57,1fe03713,c029583e,9526f2d0,dce7c53d,5cb36f8c,fcbc517b,cecde833,4384d10c,f5fc80a6,ff0edb83) +,S(d61eb681,c69de82e,caed8e64,7d1a3948,6cf63f83,f1f04bff,46a04aa3,63e29604,9b5a92fb,156d7b8f,37c6d9a4,30ae28eb,f62fdf5d,5bf441df,aa386259,721f08b8) +,S(bf8f002,57f979c0,9f973c8f,3dc15eb8,8349e340,efd8d57d,5763e4e0,c2bf507f,561d862f,1041e670,fdc265a8,36d363a3,43346739,f4f177d9,f66414a0,820614fe) +,S(63b254e2,a7a6fad6,4d9ca03f,7293a86f,b471fd45,51ec72d5,eb03e289,774cb498,f4145111,3a4ce922,dc7b3819,a2de49cd,f5be7d53,6befd880,837bbe7,51948c8b) +,S(bae6facd,e1da6ed8,63491f33,c4c9efe7,50fdd908,6b93c09a,e0418a29,d3968725,7c7dc955,e483176,f6bdf74c,6654e6a2,e4ca46c5,2526349b,b4d66090,6ea30533) +,S(f56285f8,ea15aa08,f3ed8139,59c660b0,d30a6317,5380429b,59584623,aceb34af,110033c1,a202194a,40703c9d,ea2dcb9a,d9a0f6da,7b99b8ee,31eb1ce9,55a9eb9) +,S(876c7c95,3de3d451,edb9191c,60e8e36a,eafbad2,198ec6a5,40d72633,8151d87a,95efff74,72ce0c6c,4010d17,7e52a859,cf55011d,1005bd27,df54e25e,972279b8) +,S(e956c7ed,77c7bd5,68096902,4ab1c758,a024d86d,ba3f30e3,fbfd83ac,940a6d30,1b5dfca6,f0d19ab7,7a57a9da,259a564a,5aa5759,ce6826b,45c71771,7aad9da) +,S(f53fde61,abdb4543,1456e9c0,65048cd7,ab743b5a,81a468bd,8fe2ffaa,99dd3f16,1d28b539,47ea22b5,178e86b,ab3561bd,a65ac78e,e0e2a6bc,1a26b64e,d790222f) +,S(b91a8681,52eb435d,475b9103,936a7c62,5e49b0b4,f7bcc3b5,f5d36449,c8043ad9,c758d17,56939bc0,61696f3d,11dd1bd5,722dc90d,1e8be88b,b3430062,a13aaa75) +,S(5a87bc70,23e32927,db4c55d0,abc97536,61f5adcb,b24c2897,b16f08cf,8d8f8cc7,9ceaae4b,aa6a0d5c,46d2120,fbff74b4,9d1ac32d,88a89b2c,3d2aa6e0,6f731e54) +,S(ac0b1b43,e54eb354,3bca80b9,efc5cdb1,215622a8,66b66e80,de979f79,71ceb034,a891575e,5731e152,17bc2b87,197da9b5,439477fb,d2bf07f6,9bd13f3,f4638d8d) +,S(d3c41ebc,2017cd82,76f4d6f3,f6ba2370,e84f1949,df3abdc1,45073467,e85ca915,52ab1d52,8be55945,1f6b1e91,610fcf35,bc1e9576,3ba3ece6,9da5e4d,8cdcf7b7) +,S(68cffc57,f4c82cc6,f7900d00,fe1b0f36,ab842e4f,49ee9063,4d1ebe95,47923b02,729955bf,aac10741,c3fda281,c18a306b,367ba904,baed26b2,6fe6a485,9ab1d8e2) +,S(7e0f58e1,246299ee,e08566b3,35324a66,579dc765,343f874c,d30f2553,8c177d9c,39652583,587293f0,809af7b,5d366740,86b9015,6a05928d,cd340196,8821447c) +,S(c72abbdb,d1816498,eb53d4bf,1b325fd6,5dc45086,73257bbb,97a15eb8,e4c9b542,3c8fafa5,5df5f3d2,88441ed3,e46cd318,841a068c,b681b782,88e77afb,2b25a7b9) +,S(74747f5d,3eb09144,1f64d76c,ef690378,943654ca,73fe15a1,b720abb5,d2363d0d,12c6724,bc7e8f7,321f993a,5caf0547,bf54c1a6,41f959b9,746fad7c,1c443649) +,S(f2a702d1,ab1de7c4,34cb5d71,dad689a9,29db862c,d1fb06e1,212ffc8f,91b67067,5b91e2c,c730ac9a,cb7452bc,7fb4dcfb,1d5ec11a,bd146429,62c7bd16,37afd854) +,S(a92d4f08,14e76b46,5fda87b6,201c46e8,c2535b3d,4be91e1b,530b5634,d00d9340,4d829a8f,3c02fb40,569fd9bf,e754dad8,38d96dbc,2350f0be,6f4ba065,5cd0277) +,S(79e30cb1,ac06c3b3,f90ea320,60a80fba,df5ea142,84a15746,2aaf917a,26f205a1,ad220a0a,81459495,5ac8a79e,d0cba974,7f17364a,9f6168d5,3521f276,c8d5c82f) +,S(6d55dc53,d412577f,463252b,e240fa32,88c8d6a3,babd6ff3,20231b6,8c9401d1,83a41c96,aa3b32c0,59155345,2679f056,c98e17c8,a0a5e154,d732fd3,7b006eb3) +,S(cf9c9f1f,604eb909,b37ea5eb,4cb8a0c2,11ef14e2,d3e2f48,7c83b56a,49b3f20a,2b90b9f6,4e649988,77260b5b,ecb441de,da24eaf9,df56ff93,dd3d1c8b,a247dff8) +,S(60d4299f,29ed994a,b3367780,9ef6fcac,e30f435b,ba9a8346,a2fd925e,186b35dd,df69b88,b8aab4c5,8ff86ddd,2d8e424b,40d51a4,9d189437,37b23695,4760331e) +,S(d93a6edd,1b674a60,6b6bbb85,4114a3bf,7de3be59,82cd2122,887c5376,d9493540,87da37d7,dc79197b,c0159006,4f921ae7,acfdb08c,447ed230,423c51bf,f9e5f7ff) +,S(cf8c3d37,7e108d98,b72bb6b3,1cb7b5f5,fd5869da,1a06fc60,25d9191a,bd652962,6f5cd02,bb96ad02,db42b034,321b3cae,fc54271a,879edc93,afc9c8b1,34128fbb) +,S(6ca99247,4637ecf9,827ab65a,c7b9ca0c,715b9048,f24c42a6,90847e68,8cdf29eb,51378da5,fefa454e,d96a446e,dab57c3e,8bb6160d,d015c1f6,d93983e4,feb55439) +,S(6f7d2c04,3cb813d5,dea67758,cacf2e3f,3cc3064d,7b9f08c5,58ed686d,28d17afd,4794e278,13ecec48,33f9106c,17c5e161,b590a5f2,ac293c8,c65a6cc6,5233bc6f) +,S(f8aee0d0,bc9883f,ab6a82b0,184e9199,e818d01a,7d99f475,d2ca8a24,e924f3e1,acf9cb2b,69135df0,9426bfa,c6b1b3de,44f1055e,5cd21b8a,b526f34a,839442b5) +,S(8b00fcbf,c1a203f4,4bf123fc,7f4c91c1,a85c8ea,e9187f9d,22242b46,ce781c,61e9e58a,3e81e690,ec026428,ee5442a,a8de699,dadfbcac,478985cc,89d35bc9) +,S(fbacbb07,8e84a2b2,c201ebbc,1cc3212c,a7278523,e984bc1a,b0eb7fa1,39d6dd4d,2c6c9dd6,f5eb0899,797df675,ccbbaa25,4e557d5f,d16c6083,3aa84a7e,4c3a0f52) +,S(1556875c,2f32f053,8d28f993,53ba2804,5ba601bb,3df8a175,bfa33dac,ac5c0611,53623050,c3da9464,8e9fb540,5888e387,d2eb783a,10e45cf8,ebaafe84,a4e240b7) +,S(b602b095,7f5b5e98,ce3e690e,c683f803,49a8ced0,5985f79e,2e972bb0,2d93d77,78868390,ddd6b821,e30046ac,b1bb7b31,ff358838,af5b89d9,60d39b4e,85435227) +,S(2a110165,23a5244e,89d66f8,a06f0553,7a846216,75fe4377,24f51501,da2dd17a,24d3b525,e1ca62e9,b02de498,30737f3a,b881d078,7d2c2bff,938c53a1,b8825159) +,S(7314759,1148f9a9,ce326a8e,4f43d2d9,a13edb92,56fc9d38,35a35da6,457efce0,b195cc94,80d0aa04,d3ac7cfa,45766472,1ad5adf0,3060b790,c7fb0ff7,77b2d8b3) +,S(a36e4fe4,c7e23d7,16362979,c5a9d8e0,525d864,37d96e3d,b2f45edd,b36206fc,56ace785,a428db4,a8a70de8,708339a4,346699f,697a6707,c745635e,66844751) +,S(97864be7,a2c54118,5d61b61d,5a2494f4,85b877d7,e8864402,3444d778,f43cac9a,43332a78,a85b8391,551dcd90,e93e71c,3a6c5428,71b980ab,138eda2,b9f2ff69) +,S(34a52dbf,2449eea6,da2c92c8,45dcd47f,daa7ca41,5ff02458,b74eb996,8519893e,add41829,900f26c9,f7ba8d55,21f3bb23,b3545a35,699d41b9,4270547f,e303ece4) +,S(e250aba9,94eea617,5fb7b2b4,8631f5bb,d8bdbbb,799f6fcf,5afde8a6,2ff3d629,803f34f5,9db0fa86,bcb6fae,689530fa,2e92c4ec,bff1757,409bd836,8143b0ea) +,S(18356a6d,b5946e2,1149347a,4558e116,7953042e,e3b2a372,869ae29,b871ae00,56ef0971,6b176f81,e1f98ec8,dca127c4,ba6de23,ba8c1f08,f19e9abb,995385cb) +,S(35a8ebf5,e5306084,365ef3f,30c29e56,ca5932d6,f73d688e,ed3cf2a9,10205533,9eae5d95,42954de,23d41032,5ada759e,20d30fd5,c2d058c4,53a18520,7f259958) +,S(37e06f5,25ea8fe9,ea862b92,53a965f,7b3dbe90,9ca487bd,a705041f,e6a4e1b9,83919fd3,5e489bea,23f13b60,41a19940,3f2f6568,fdcf60d7,3f57fb6,1fceb97c) +,S(abbbe697,ac6c002f,11062947,6e4a6ffd,48316646,718d8713,1a4dec19,5e131c27,b2c926cb,9d5122ff,7f8d8a24,a20eaf4e,fd704944,9aa48300,92971572,b12f9dcb) +,S(4df36acb,1484dcc3,f7c29c8b,78915315,5a1a3636,aeaca043,68a585a4,69b05878,fe16fe6f,c08af026,3fc417fb,19564534,aa059f4b,b7fced09,d4fc20de,6a41c41d) +,S(5ff14ee3,10256a0a,889570e5,ebdaf6af,c8f49c60,dc7c4731,23a7d29b,e799d0d7,96ff1538,55eb2fac,8f2a923e,ead9851a,95382d6c,56cfd0d8,9891d2bc,f7e65d7b) +,S(16a12c52,c1d422f4,791281a1,b7ab7186,a24dbac8,36af6810,4f62dea2,855d119a,7a6ef272,f67356de,46996cb3,8bbaaba9,d36a4bf4,60e3b2a,b3a81723,24c17478) +,S(8f4c9c33,83688920,a48b3d15,4fd567e4,5fcdbac,bea44eda,60600ffa,a1489ef5,2bb5bc4d,e06444c7,b2bc0082,d629e2e5,a4b0abd4,8cbb9b4e,37d564ca,db885717) +,S(498bf39b,7547010,854ca399,e50399ca,19236d2f,d05f5777,6abd6d2a,aab83310,8e2debff,cb58e36,bcc7beb5,8a45d4ba,b5edcd46,2c355d0c,4dde51a6,6afd691c) +,S(78147e0a,2978d396,b22247d1,74958336,2ba51d90,11e89c11,71e6e136,eefb5996,a66b7b0c,a73b661b,e71bf0fb,2eb4410c,4c75bff5,b8b05fd4,1d830d27,ff85989) +,S(351298d9,fb236c7e,5477aea1,d2df0048,47e112a2,e16adf66,3f4d77dd,828d4927,6c9c91af,8b6f23a9,d15c3884,e618ae51,241094d4,5878ff20,67f2ac81,dcfe00f9) +,S(fb5ffc0c,88fb609c,24cffc14,848549ad,c1814668,9e5f8a67,a342bcbe,16399d10,a995e13f,9ced94cb,90feff32,8e92e978,88cf5791,c885ca09,46f46e5f,b8229ab3) +,S(8352b7c4,4cc09c5d,717bd197,40dcaaa0,89565e94,77cd76b3,6c7a4fa0,4832097b,9507c998,fa25d9,758ca78,6774ae68,f91c8fab,694c5e23,6f8af6c7,7d0fe6bc) +,S(1be65c0f,273a2746,d6d014d7,6bb1c595,5d5ed1db,62ad940b,d8204115,85919f4a,dac98f30,2a38f839,a3d470a8,3ef83ae8,f044e93c,80b23552,da3da359,5c09a3f2) +,S(7107f3a5,2f4be227,eeb65037,ae800f64,8de14d89,ebf743a7,ed65f98c,b58418e,bfcf1c09,bd1af327,d14e429d,18eeae45,927b2df2,aa15ce60,69f6a74a,69fca7a4) +,S(117284b,e8edae5b,1ce54a13,3b1f9d98,983389cc,a4ccff,9dd04973,97312e3e,91e48c1e,724fed49,8bf51999,4c84d0b8,84e3af77,86e61539,638b45c3,8212b03d) +,S(a08d86de,b1ff9ab4,651f1cd0,d89b6714,41c243b6,c7e655de,d31b44a7,b00de54e,4d0fe7f6,344d39d1,57764fee,f74cc949,a72ed8d4,c2dbc12c,ec2629c,830f0d2f) +,S(9c44c1ce,df67418a,eef2cbf3,68d48a08,98cfc633,de711550,3f78ecb5,a4e8c25f,3cda2020,86d3f096,31da959b,9f9870c3,de3d3c6d,e4c1b35f,81f64dbe,31e743fa) +,S(d933e475,5215c065,bab118da,6f24d714,f8597949,a52ae319,250338b2,2339f149,5fb0f28e,313af04d,de3abfa6,4981287,e277e39,d2f19dcb,547d6fc,88baec45) +,S(7fe1f197,ddd0532c,a2010528,9f243bc6,4c2f9e53,65aad5ff,63c0f1d3,188a42cb,813b133f,a1869218,ee361828,6561e75d,a9ec6bac,6ba2ac7c,d3f5678f,fe472af7) +,S(e3568521,89612102,7ad0789c,72dc6d57,7ba412ae,b3d7551a,96aab952,c507f79c,7645c505,8e2ca8ac,ae5fe225,eddf4d45,7d820114,cd5e69a8,4966465a,423e3a30) +,S(c56afd46,8a5644a2,abebcefc,3b6a9da0,c667a183,b822780d,146ecf82,b6ebece4,9e41c655,a80e2844,89fc587c,b686549a,2915ba14,1c691e75,cc635f9,54f1a8d4) +,S(b242eb39,60e6a8f0,73b6042e,1095f0e1,440f9f8f,d1abed56,ad1f26,a1589345,944da76d,f063f0a0,3602decb,696f2a34,378579ad,e8469ca4,bb5041e5,876dfde0) +,S(3a52fd66,6d2e2e2e,888a43f2,fce68703,78f835a6,b5c3bd42,af57b107,323bb827,12e51177,a7b37a46,2755cea0,18f4f29e,96c7d6,d0e434cc,4874da99,a7af91c7) +,S(b77d5615,c8831ad1,147072d2,598a8c6b,4a71c0fe,967a6cf,70877aea,24d28f53,25d5b7cf,a068a665,deadf83d,5f793605,f5cff2c3,36a8d176,d18c634,9ebf3132) +,S(e4420c3b,61e435a8,53784728,8426aa27,f23d224f,4ff7a14d,79898369,c08530dc,422b04b4,857984b9,9bebd74e,1588ad96,9b3c67a9,89b119a7,f7cd2c84,ecca8572) +,S(888bfdbf,c6ab299e,3ba0fadd,a614fb01,236e3c44,98ad07ce,cae08105,630aaaea,86e7253d,58cfe580,628fb94a,a1a8f40b,7ada97c9,d8713453,f06f4773,3770eb3c) +,S(f74d258b,f7d78b30,ddbde398,a1398164,d850f2d,48616cce,8ef4c436,10ef419c,d13d49af,1e6dadfc,94332213,cbb12d32,5d60eb6,d48cec9d,fcaa7ff2,53029204) +,S(a8b33e90,98d60483,a7009786,11b92257,65cea0d4,b7ac0ae0,67914110,5cda6df0,58cc238c,c08d957b,1172598e,96ff4762,1182b6c0,652c9ddc,650f3b51,3521c553) +,S(5af8b154,7477fad9,8e5dbbe3,d4a1a15e,7a4a6cb6,5ae13cb8,9699470a,1a3ef1ff,525ed201,d0c61832,36c8fac1,366e8173,3c0a8c15,b6ef7672,cc84b1a3,7d6f25bf) +,S(155c454,6d4c5c4a,21d14383,3df8662a,fa71e665,ab7ff0bc,8119f29e,3bec21c,20e99f67,2f641185,cdceaefe,8fd7247f,63842282,edeff6d0,378966bf,50411aae) +,S(53918586,ee182d66,e7c22aea,5a663770,c8fd7f0c,6738d473,1010660c,7425a56e,c7fea092,3052ec1d,7e2564a1,e70b8924,cdbf727a,7212052f,abc58d9d,1856152e) +,S(f7964dd9,a0fab716,74804abb,a7740f4d,cc52d7f2,8d5acd4f,67998bba,3bad6414,6a989f64,aba0f60c,e7bdc5c2,aec11de6,d469a122,f1bbfccb,31cac834,89f62c59) +,S(741c8c8a,f514f2de,7880a909,b327c6ee,ffd72ee2,b5b1658e,72059edb,cd663183,f35d276d,e5de1460,dc53532d,48afe736,e40b6b31,fb6fdb49,1224544,a487b2ae) +,S(de8c69bf,6cc2a28a,fc6ea9f1,26ef4f22,606e55f1,312177e9,b2ef8835,8b47945a,8de62853,6900d614,780e2fec,b4ff7066,70d84742,3b1c852c,8b85ca4b,40a48a02) +,S(81e16f39,619bb41c,d8a523b2,d3dd0135,d6a8d5fd,9a8446af,cd058ea3,6f57c537,6786fc73,7cd2ecca,d146de9b,951deec4,375c434d,7dbac32f,2395c265,bbf4b31e) +,S(459e9589,d079b22e,8c5625b8,a725b30a,e70f7f04,8ab21a20,f0123aae,7a6f988d,a56ede93,5b71a292,c4ad26ac,cc3506cc,915de21a,4557512e,e767e8c4,33f38e08) +,S(b079d755,4faba7ff,20818806,a70b4ead,f2e5bb51,d1abb758,2284f385,868ebddd,495ddc2d,552f174b,210f6577,3e434fa9,20b6c0c4,574601dc,fcf5b701,fe74dffe) +,S(75391bbb,5983fb21,41580de1,dd5b10b4,bb30af17,3f05c100,569abd2c,674f288b,57c7a6ba,c9154ab9,eb66032f,2135a52a,b319f534,d1f1c80d,b58a4af7,de958d67) +,S(71436957,f2848f75,fc461069,e4fc691f,5bda94f7,32fcbe7d,5a89e136,41524db4,1287f852,ef4fadd5,65a2813c,51b93c81,95658a5a,5cef224f,e92511db,df3f0007) +,S(b9038b33,fa75d097,dcc74c9,e25970ec,94ad076b,7279f785,3b7c98f1,41543f9c,a28c3169,69295ed0,3fbc1bf4,8e39c8d6,af59cef3,d6f66660,73470ab0,dbcf838e) +,S(b2c63c28,a9fbd900,fbc664e6,36dbe0cb,f259bdb9,d67c34b0,83b8af17,a5f86196,a8f050fc,69c63c4,67308421,89510ca5,b7920723,6f5c12b0,ee7103ee,cd49ebdd) +,S(cdd2a5be,a32b2195,f4a7edfa,dfb7c785,d06bf346,f38e928a,5c92cc7a,2417f39c,ab66e78,ac421c36,3203ee7,22b380ae,2133864c,83829f04,d2daddd6,b7fa621b) +,S(825d0864,b079a737,acef03a8,28838ec5,a27d740c,724f9c39,780cfa61,9f3db80f,bf3ee8b7,749e44a6,7f27e427,fe05eba5,c2154fad,bc2e2b43,a877219b,461071d3) +,S(37b79e3c,bf6bf402,c96930a8,79f4ce3d,d0c36477,f0b0e218,608b890f,bf5e24c7,d97142c7,cec5630b,a090ff4c,9213c2f0,c32a5bb2,f7b0ee29,2045ad03,10f66f1d) +,S(fba64ad0,678ea75d,409105bf,5b452ebf,89560b0e,fbb079d8,aed22c33,552b6135,e665362d,e4e637a8,a85dd844,1a806ad7,5c628f19,7d6dbe3b,df63c0b2,d1f938c) +,S(76787b8e,77ed36f,9d84897d,e84c476f,d3bd490d,184327a8,59ea3f97,ecd9cf72,cf79f14,1a3f38c3,cc126011,d1d78dfc,e3ba228b,33d64158,210cd942,3980a9b3) +,S(26babdd0,ffb3a334,85e6ba1c,5661a551,f16a129e,42f9fe8a,3691a50d,157b31,1b3a4ae2,b1cf1a46,fb666e33,a20370b2,e66a6c71,27edc8ee,e4c4072d,8c2c530d) +,S(15aedbb7,7a2fa1e9,7a6aa864,7729f28,7ca4d3f2,36046008,c1b031d6,9f76307a,3342a142,bf8b2360,6a574643,9c05f36b,f9408878,5354c788,a6dcfd96,ff073649) +,S(98ece0a3,9bb7cd4f,df4d5767,c6ef4cc1,c2b072a0,dfde5fb3,de100f57,466fe467,c4e924a8,218c93e7,eb829d0f,839556c6,1e679d29,6a0a6bba,6f4f463e,ab227e28) +,S(7d867505,fc213eed,4cdffafa,b067bb71,8a48cda2,fb323304,1989b6a8,3ff373a9,5df51ff0,3c212078,197c417e,f4a4014c,96e167f8,8cea0c1b,9199ef75,7c97d47c) +,S(f24f19d7,43578e1f,be3ece8b,7b00d5e2,bf269a48,9d76d17f,410b73a2,95b3001f,644a43ff,55448b66,7b048bbb,b34f4c79,16d2b547,5148020d,53e53627,623631f) +,S(93853304,5c22296e,1e911281,ed4bea22,1fd1061d,2039a27b,923dd3bc,800efd59,22988cf6,cd2d15,f799bbf,e4cc905e,2607da21,e9fad162,8c2fe699,8beb7040) +,S(f090c705,39834f16,253b14ee,8e4d2685,b91ff4ec,9897df0d,af1531c9,46319743,c1171885,1d30271d,a8a08391,f53a02b6,28c59c8c,9af3ad2a,bf158341,280bd522) +,S(e8fc8ec,ab5bf3b7,4a0234ae,b2a8eafc,df9bb08,a90078e6,7fb6cd3e,fea78c6e,b08165,34ce9bb7,46efcd71,362e0a75,a8397c0b,490e75c2,9b007b28,26ddabe5) +,S(46258cd1,87cb43e7,3003cef6,94af37e3,c7426dba,c8033aa0,9b0a0d71,9f126785,846141a7,5f060822,764dd82e,2c369821,75576ebf,7082c6d4,601ad237,55ad4fc4) +,S(e7f38b3b,db3887ef,529d27c3,f433410b,94109bf3,45f9b7a1,e65bee6a,cca3e430,f52440f1,5eaec702,90adec0c,b07e8ac,ab1fafb7,adbc8f81,9fac349,2acd589f) +,S(2d29e833,1472798d,75fd5b75,1f569da,fa9a0167,f73fc62e,da5b03a5,2f537aec,52d3dd1a,b117b9fa,a17c58cf,c0593603,d9e2f55f,5a230001,d18976e9,792d2be6) +,S(a3b2ec9c,abf7a7b7,77fb44c9,c7552dd8,f47609a4,6f943c7c,8ac97d1c,3891ffb6,6ce38c70,f091381f,53093385,22a5ad66,4d528061,5b01b417,d559cbbf,3cfc19de) +,S(afcb3c1e,7582a56c,e6504dd,ab3d1a8e,6cefe762,58543015,a21f65d3,3100f473,6baf1f9d,fbeb8499,8a6afc61,8e193103,67edbd87,57b2c4a3,8e5a76c6,8b171af8) +,S(88b2f212,dc899567,bf62bbea,9466a8c2,6650f74a,490b86ec,cdd35625,d90e2ac8,73fd757b,def6153f,d7f6d4f5,da1723e2,6ecd6c42,d994a08e,7e458a64,d18c30a5) +,S(bfdea9f,4ca32916,651c971d,7da6a2a7,395c5945,5c4940d4,93d991be,1dadef3c,82747044,7ef3f684,4200adea,5b8077cc,4166bc65,1f6d4a17,578b64d8,21bc20d8) +,S(5d45cb81,aa765d69,ca52e386,9491ecf0,e8fdf6a6,3d64e65b,5213647e,e4973ae5,a4a4a32b,51a76d77,773517e7,c103a7dc,fdab36fe,3cafa2bd,b17f82b1,2fd019db) +,S(f3a503ce,e14e9994,aa34fa53,1c43e5db,6d6fe092,45d2f3ae,87d06753,7ae7109d,2b1714c0,a24d50b4,20722daa,d1951b63,568aa5ba,7325785,ac555e55,f3ec49e8) +,S(94c3a76d,6f812ed2,454c225e,ab8e6b8a,4261953,37d1d2d9,b666ade3,88cbeeb5,bb89cee6,aa406746,dd4893b9,5bf1818a,3d1351fa,d66e104c,bc8d63a1,efa953e3) +,S(23dbfe81,5232403,39d5a662,51fda5bd,b9a2d3d1,181dea3c,c0c908c8,f0f4c050,caef3a71,229f10ef,488f8385,c79ed0e4,b5c16899,d40ab679,4e45b84b,4deae6b2) +,S(3907e3d1,20ef8619,c11dc69d,c57935f5,d2dcbeca,1b4bbb88,e4629ec6,acbbf1d2,438f96b7,d74e2b9d,cc17b0a6,c936844,e6aad1bc,58a20055,ba298446,1415e853) +,S(c140b19,3eeb04fd,80aa6a37,3407f591,651c944b,33788b71,e6f05e1,672b7d9c,949bfd15,59e24543,9d5fef6b,70763b63,899450ef,430d2e64,1f7077b9,29e44072) +,S(977cf05b,c96a39c8,1dd2fe26,930f75e4,2563c3b6,b06e28d1,740a547e,f2ea56c,3802e3a,8508164c,36e95e23,46ca468b,7e15878,36a9edc0,e70c0e6b,9aa10d52) +,S(1069c0d6,3995e0d4,cad51e5a,9e4e57f6,795a7bb3,9ee3c376,1e827b20,d8a034e3,e1aa1487,9c0e4c65,581d89c4,7abb5e48,47963aac,788fe804,1d2c194c,5a7fe33b) +,S(ff78c680,c3414181,ff3ab10c,74e2a755,42419af5,3527a45b,ba3825b3,c93e3682,eeb70adb,f05390f3,76b2382e,20b2dbed,86c8c574,df2f256e,1fc4a376,24d3615e) +,S(5ec9eb03,3acd3d6a,9c04c3ff,5838a6a0,2b0cb26b,d5c37d05,9056afd9,86bcddc7,92a287f6,eed0df0,17c0bed1,ed9445c3,e39d92b4,8c3a9c8b,9ae26749,732aff03) +,S(eaa206ba,792dd34b,7ee67e14,d8dbc7e8,bef0a54d,a7dc7ee9,339d8ec8,471b37d1,5577e65e,be719ca0,7fef2530,c40c1617,55e00d21,1d78e5e2,695107c6,8d1ee92e) +,S(26d062f5,6034012a,3d76789d,455cefa2,689ef08e,d3d87f54,af952afd,ceb3ed7,5eff1dac,ef6f5877,99c340c5,f0d1f6dd,dbe6faa2,5ace9109,4e7b5836,d1323424) +,S(800d415a,e50db62a,4f49e449,d11eda8e,1a2413f9,c341bbd1,492f2271,1e602d48,569cad6d,5d19b5d,2299ec5c,fd12d9f3,d5c8cb0e,756036fb,dc5957f5,7c02eb50) +,S(6c01a352,bc16dc19,973aaca5,f1a21676,e1531fbe,f8586bb,9853c627,9c9a1c90,833dd742,c9596a0f,2767226a,b2548139,a39a17d2,d64d6765,4c073b18,f8cc04e7) +,S(3accc922,f1b3ff0c,504e7c4d,4738d1ad,f0b914b8,d08ef8e8,a54e431,37742c26,aa9cd483,27d60b34,304dee26,c52b2979,52a2d118,82e10b17,86a09acb,3cb0ad7) +,S(a0df5c72,828b73f2,a380f75,3f8e6352,f8d978c1,ee6ebedf,2ec70ff1,d0f8ec72,b230adbe,f1e0bd13,1e622689,379e7232,b1327db6,eb0ee306,80d7a89f,a4ac6670) +,S(9d5f0d94,9776ec98,607a8dbb,d54865c6,d4bbc970,d3ff85a4,49d57b97,33b52c73,ff08efba,f4893add,54b8a056,ff60d345,ad7faf15,7d11acf2,2cea0f2,afc1a8) +,S(def5d92d,9ea1822e,dea5b293,58a51ec8,228f54b5,a6738917,fb7f2108,6dd3d84e,b6c740d,b94aebc3,138d3ad0,202bff37,9d5bc20a,d7c0307a,479599ee,8b3129) +,S(fa90b105,cdc8d74e,3f87136c,f4d075f,643fb0f1,ba6eb832,73642e65,84df33de,3e6b28c3,73f58eba,49e9e852,f0f0e244,3a180d92,52624c27,3c079dea,50bba36d) +,S(8212e821,ff2f7b90,c01c8461,3d4d9df9,ce077cb2,9706a349,575b8cd1,a3d0eb52,d59c05db,2fa3e756,fda56e8f,33540639,d24bb5ed,2c8aeb5b,8f8e43ff,703185f0) +,S(ee340cc8,1d1f71d7,4b1a641e,101d15e5,24f155b7,2afb4e49,f9cd8b20,ec61220d,915d833f,25355fd7,f1efa796,4a8e8b04,86f8141e,f5811438,f0083382,ae286f37) +,S(2c535525,dd2e3d83,740b257f,bb7223e2,302b5009,7f8366b5,aa26f65,442afee1,1cd4514e,f945b668,4f38f966,2f3b5402,92d43a79,7f73f947,67272713,b61cf765) +,S(df7763cf,8b57a288,cf4a9083,a2a5f977,404b9e1d,6e814f2b,aae9ad45,fa67d94d,4f7dc336,31fdb48c,612276bd,d388ee9d,bf05295c,1a92709c,b4fc33ac,b1580ce2) +,S(3514c240,d6d0f218,11374b92,8cd6d063,8ff99b8f,4d5e4da1,8fd126a0,ecdcee60,2a0d1f4a,1a1baf80,3c98421c,7777ed1a,ac17abb2,720975ce,e530a5c6,4197fca2) +,S(3de75d9,e58bcb81,94dde551,ab541d54,237a1b58,d935f60a,b54bd3c,6ae40a27,9ada14db,be2db058,c6bad8c4,86f25037,3ec422da,fdd5bddc,455b2b8d,25d97c75) +,S(a728ce0b,1804355b,c5c144f8,1d5eb1c2,90ad3d52,f502c5dd,ae28a08a,6de0420f,4387cca8,f72b51a0,cfb4893f,a85491fd,42cce3b9,ec3344f7,ac93d001,47ddad3d) +,S(ec3c9a8a,5b844c0,947b22e0,2503a815,1d8234ab,aa94032e,16c1d874,5551c39b,7b08bcef,45f0fa93,660845ca,44edfae8,c8ac51ce,e836b043,3825e410,8ebd7fa6) +,S(b0173d56,24945acb,3bab7e6c,617532cf,e619e7cc,e9872e93,26a8ec55,a24761db,78d27b5f,3e9a0761,d0feff12,198dcb11,72a81df3,1320f10d,44591ae3,5f1b381) +,S(d9eb3bf3,cd43dc8b,977c3890,ed3a4b8f,4e04bd11,f95963a7,970d9600,40cd73f6,98196b5c,c42e808a,3f1db718,98c50048,510b9e4,c9b69c41,e7f5b2fd,63b23044) +,S(fbda51af,8a40230a,c7602606,21f92b38,29bbf1b0,1c027f10,7ca54c08,65a84e74,64833994,aa453bd5,4c8729e4,e9010fcb,8fd427ba,3bbe7c71,e812513b,fcd6ccf5) +,S(ae4b9a7,51be1966,f564661,61262faf,472b14c5,f0532cf8,8af872f,ba583f9d,8b2c248b,aa9d7e5a,6f0c6eed,9ad3ab5f,e2bd4078,da4fa281,f4b672e4,9695ee5e) +,S(58040152,6088026,1668c6a2,e462845c,f29764e0,31edf6dd,a40b6e0c,4ccf6ff5,d2f96ae6,4a83c04d,a072f9a4,e39976d8,a2e5f88f,fed070cd,5fb1a701,db329485) +,S(4c28d686,57380f81,639abbd9,fafcf47f,cf477e26,1c46a03b,57ca7326,4c7e029e,694b8a9c,4fa75e14,56a67e8,acfac16,3122a941,150da022,59fb024e,ced8a70) +,S(de205ab3,9e005587,f23b51a7,3d806f81,6984fc77,7179a6b9,465a92c,ff25c9a4,ed84325e,12efc1c2,db42cf1f,eacc12c,48f68e42,9aec9135,5af5c327,c5273d83) +,S(5ea82868,c2cb0a7,4b658dd5,721e6571,b968f589,6d22a5f1,b3ec6b69,594273f4,88d10eb0,8db264f8,13adecce,636f6c58,e1828539,1e538ad,6e2237d2,384a9499) +,S(189cf7c8,64497416,420bd98a,3e3db4e7,c3b0dd46,d7b9bc9c,37f2d036,324998ba,bb3409ce,d46dff28,36601b1c,f7dd606d,7422118d,723f7da2,4d25802,1edaa083) +,S(70a17187,38f50d43,8868026,58100245,3c3c41d7,8ee5e14d,3cf536f9,bc82789f,15c95120,e112537e,41f33870,18f09d1e,101dc445,a9f36296,2b9462d7,bc27c1d6) +,S(578ac0ff,622adb6e,8c20eed,f3011085,8e4271aa,46833865,cff46b9b,fb3a368,f711a1dd,f5f3172d,2b9b2f7d,9d50818a,6b0ceaf5,1d67e15f,1f01ca5b,bbd7f851) +,S(dc9fbc03,476aa747,d64738ba,ddce8a5b,5887f177,fa6cdaea,3e3b05e2,8d840071,c0f6752c,8087dd25,f8d94a19,d294e550,8bd26774,cf4e7ab9,515f0a4e,89eee1b4) +,S(9749acff,a348cd5f,2e84dec0,b3d73151,4bb817dc,4596d78f,e0295215,47b0294d,df667dea,35e54810,daeec20b,e0e7d203,d89856c9,94501167,23de84e0,5781a1c6) +,S(e39fbdcf,2fd2730d,c3359f21,fa815478,ae8e7a98,d6b132e8,e92d343e,32657d85,bafe9881,70a78596,76a6ae3e,364885a2,62441578,8c31c283,20a06b0b,e5b5e01c) +,S(6009014e,27f13712,c00bda4,dc913516,e04b692a,ea32b89,e0fab8bf,91402c09,34910894,f6bd1cd2,cb796f58,8ddba661,eb4006a8,6cec32e5,7086099d,42359f6b) +,S(bf04f247,d02e46d8,2fb9bec4,f76b3eef,b644c92d,43622162,d419488e,87f2f773,d646f4e8,bb3c2e4c,f19ab00,4674e354,302e125b,c1ed684d,32b1cebc,7c2172f6) +,S(9609f7ec,b122b353,85871efd,915c6d99,3e5468ab,c30e9acf,f5b4dfaa,31e5e3c3,106bc52e,b933f0b8,71578ac7,74e2ad89,ebb4d9f9,eeb95592,5d6b50dd,988f9a27) +,S(b690cc3a,e1ebe25,a07440fb,5cbdf56f,f5ae581d,4dec7366,8da2ad62,bab9abe,83cd0023,fd3a3ddb,2cda9603,2b6c1657,35e5f9f6,249a535f,b9666a97,e049dbd1) +,S(72da508c,ed507744,1aa2bc11,4a9098d8,2c947948,395bf38d,6cd00977,91d326d4,165baa93,3433ea2b,e978036,4fec922e,e5d743db,b8117e09,5eafb467,3f668457) +,S(e0fd116e,540a3009,2954322f,5125a72d,1133201b,985d1017,29b1c9b7,a9851c37,c6bc7276,48aa707e,549e899d,630d3155,a516a06b,777997ac,8509045e,e5b88a92) +,S(9d4b8bea,85d4e412,ee0d6389,e883f9db,297f01c,d0695c13,abe2b682,94c10af1,5e2280d7,3f7c0832,d9ae62fd,6a884973,5bb66ebb,e68a38d3,8a95258a,97556181) +,S(eef84395,aa4b6e04,ddc56123,cd5eb31d,69f1255,1c216d25,5057a2d4,388e08ff,45098aa4,34e14364,40d8b26c,73179c48,87797e6d,59963928,b1d6b61,d62d2376) +,S(66fe5c7d,56e38e48,6134371e,76ef427,b4652daf,6e60cde7,39aa1165,c90d7654,2d72926b,b6edc93b,7e40ad43,3cbb6c4d,96d4c384,966ca582,a108a84d,c11a2fba) +,S(5135f9cc,1818caec,cc55a304,aa983c98,82f9e1c2,939f27af,dc2c6df2,c08ea2ed,5a526dd2,7dfe1750,4f8baf4e,115ae1b4,2619b5e1,47986954,27ca3621,e03f22d6) +,S(1a37c089,af7f4a9c,2ffa2bc,c22a3e29,82e3318a,ce1ae29c,3fdf9b62,3e6487ca,d389c033,8522230b,a96b33d2,373672cf,509b0312,35d2ec18,3c955ff0,3d2464a5) +,S(49f7a5ff,15daaf40,913c68df,c9016f95,ed1edb22,22fb1576,e4a11848,47a248a0,f9b55b01,3d637bc9,e9794246,fa6bbef4,d5ebec82,1a5d7f61,1a18c7a7,b9abd8fd) +,S(8247845e,5d9ef839,207f0f1e,26eb0470,3b87f835,ac3af130,253aaf88,1e641ed7,577d790c,1a23984e,7f1b1947,4cb42ad7,b4409c8f,23f391de,3e2440a9,e53c5f1e) +,S(8295984e,cd160241,ace92ef6,10853e8e,57b7823e,25eea4fb,8f118593,d90e0749,635321a6,6798d5f7,39a450e7,67b1c38a,2c5dac96,780c83c1,4c38dbc8,c0ac8353) +,S(d4c32bf6,d8fcf5ff,be0ba34e,770c68b5,fb5db412,b1341537,7b2e9c80,3dd75461,b3c73602,e23845b3,2c44272b,4eda70b9,a1a71e51,66d13353,74153f66,4485f93d) +,S(1a08e32d,4a968e6,a44703af,6b526a32,3babe7ca,6882cd84,9fd3f769,6cc897ff,46ed98bd,b77bed4a,25c2e19b,e2b14a8d,3fdc8209,70344b39,9a6b2a8e,afad4141) +,S(8559be0e,96723f04,4b05965,da8c9777,6b40e1ee,ce49de82,e7cfdc34,354f4af7,63e24b88,854e20d1,2c3f049b,2dd0906a,ba4db6de,aba42dc0,5af03dd4,91333ef6) +,S(e0e0b223,fc7a478a,849c0ee3,f2ef2a6,edd0f08d,e8ccc8c5,5e28bdc6,5e211e8,ca38832c,3aaffac1,206d38e1,25b8847a,6609a5e,d1288d1a,511d6037,9fca60fc) +,S(a237be98,2d8ed250,75801eaa,5917582c,265c3424,5679b4e2,34539ce,68e40a19,f4cd227,976a3780,454d5de4,7026d668,dc1bfc32,9003c87c,f48982a5,5a231318) +,S(28a84882,1eb08d07,f03fe770,5a16f2bc,5edbd0d6,b4367ef2,474f9b60,1205ccf2,9067d3e9,e7d77628,ba0526b1,71d23da9,162551bd,f00fa301,eecb5fc3,f856a17c) +,S(142fe8d5,42bd6b5d,325b8fdc,3820de5b,cc83e2ee,13d59d16,f4c69adc,98c1d5e8,2973f278,32533b9,559d1421,38d7fa60,1b66d106,1bf9c453,9c8310a1,dc75b150) +,S(5b3b611c,5d20649d,19bb00a,11b4b928,8f3d5ffb,700fb6b9,9c97b012,98ad87d2,849059c8,cde0e12,cdfa7621,9ed70bb4,192ead87,5a22c58f,8ebcb58a,f2519182) +,S(248a2249,5d4905a3,f61f74c3,5f35f6f5,2edbdc63,9454cf6b,192c7ce,50beb8af,b5a6f3ff,b707c108,1cd97b24,38867a1d,61eaf73e,9b89b5c3,b1136ac7,bbfd4c83) +,S(8a474a2a,292b50e9,d4d1fa99,a229023e,31ea2093,2d3a5d2,875384d3,dbff075c,7745285c,7d5341b1,e5c39289,16cf8fd2,45b5f045,d30d5dc8,721d6b65,ef804dd9) +,S(3fa01255,7fc042ea,67cbe4ea,86637313,826d10d2,48d5bb22,8ca8d113,5015ffec,10b9d325,f59b4b8e,ecbdca5a,58c48e18,162d436c,a3228b25,e3f75f27,26a937b3) +,S(b77b5c0e,7b94f1a4,dd88f007,1af049b3,6b778d5f,c8a828c0,46ac2195,9fd65648,31246bc0,6722bbea,8c9d5722,26edd609,e2b65d2e,9df6c21a,d54cb157,faaeccc5) +,S(2635f482,67e82b97,6c2ccad7,89bd4bb4,5671846e,d5d1d8e0,8f2c41ff,8535b44a,7edc804e,956091fb,667f9e4d,47b7353d,d2ce39c,b53234d,afb6d5a7,a72b8def) +,S(2306b52d,ae0952c9,c6b6f39b,6d1ea36b,ed0012da,18d77238,4a4e0866,361b474d,438250b8,8d7b8f6b,9a63688b,b2cefcf4,bd767472,bcd21221,582b56cf,325486c0) +,S(caa866b8,dde8284,8f586f9e,ed5a1d1f,aa5604ee,a8c0016e,248d897b,a9f74b4c,2818f140,349f78c4,572834ce,b805a424,e33746a7,d58fb8f2,9954a55f,dc09c341) +,S(818def5a,a0793d50,5f5e9cc4,29c01ed3,fb5e577b,b25277cb,b74c70fe,88bb1641,da9eee80,f7621031,80e2d54d,796367d1,f48ea2b4,93a1445f,bddb3ee2,ee4f276d) +,S(2c62cdfa,568d412f,cd764ed0,1bcac5bb,c36e11c3,5a295bf0,8b12df92,447bf736,e8b8e025,58117062,705ef985,9aba6418,ee73eabf,195325a8,f82c051a,3ec31979) +,S(28ab54d9,9db06e8c,d4a2f7cd,517d049,4e477f1a,b6eb3416,59bce807,e1f04adb,993b5319,a5cb9602,be656276,bf3e7d84,4fb00304,1ecbfb08,72aa29e6,7494541c) +,S(493e7c16,2254a40c,54b4eca4,223a8241,d6c2abf5,f15ebbb6,3ea4814c,512b6061,56387f7b,588d9d4c,fee36b59,7ae8f21e,5fcf817b,f097ec89,7def80ba,3ceed628) +,S(672e11be,e7439165,4fe118dd,a2c5d389,8922a68e,222c9bce,902d2062,b9c51d4f,3555134a,2382a9d,b4bcfbca,45e9d62b,db6bbfa,bfce7c5f,c5102dc3,23dc36e1) +,S(8f8d0f6e,e3b86889,8de86c06,b59f8e5c,27524b2c,2959e701,38b2c3,8eda550a,e7def281,9e27abc5,9940fed6,687bcb3b,f364296c,26bf1fd4,5d417103,49212f34) +,S(da8c5783,4a11f0a5,797cf4c7,9179f30b,118f2802,1205d495,e8213fb5,78b293e3,6ecfe35c,6f663975,86bb1c3,ab5dc518,7c7a0ce1,b6338d28,a2c01df3,89c35f91) +,S(4953e0f5,3b1965ff,3efec2d6,fa99ba0c,fbce09b3,83e20ef4,2657faa1,49681955,c210c78d,9d1635b2,3e468324,7980766,3c28fa97,18d0ca39,fc09b541,975541c6) +,S(5491fdaf,48a0e1e1,be21f7fd,be910bd6,5cd3e0c8,16da38db,6c742042,3775f293,65273688,5d1c5338,a3be9b29,9b51f4f3,9c82de96,318643e,3d34ecd2,fc7ffae7) +,S(b9c4afa8,42363b9,fb583885,8f17d1b6,b0a8529,43c907f0,af3ec9b5,abc168d1,ebd3106b,1b75ebed,5d013aa1,eca7d8d5,e24d511b,6d4178e,514fe156,4b550d9a) +,S(918da36c,444847a1,b5f9826d,eab809d5,d6802e73,3abca386,24237683,92d2bd62,6e6237af,d7cc87e6,15e14113,ab38989e,889d5e6e,6166eeca,abf1ddc,8a53e218) +,S(777d2994,da1f514a,800240e,59b743cc,748eb42f,4572ac93,a2e42e37,1d3392a,6193d7,e9eb3195,2cab96f4,14e1d24f,9d92505a,9d21f864,5e6dd3a3,8a9680c6) +,S(108e6ea0,9a08c5c5,e27b8b3e,af24ef55,3988c650,34ef954c,4d17f232,5723bf3d,1a8b974b,86db6bb4,7c314ebf,f811937a,b8a0dd76,e824dbe2,88fde1bf,fc13b2eb) +,S(36d9dadb,65a54d49,1198a486,8deae1fd,3c2dcef4,4a682839,b5dac54a,456bf185,25e84356,d93b5d86,25eec306,565bef19,1edd9bf8,347dcd8d,785024b,2147bbf7) +,S(3e0ebab1,43ece776,729d8a9e,302726ce,aab89654,23292fe3,ab2e71d3,66531fa7,6e7b2608,556d6236,8948f32b,2fb04b34,8e38eae1,3d9abd5c,691383d9,958d41cd) +,S(923dc76a,f315f31a,a1de9521,a13ee9ab,ab08ab42,157f483,2babdb5c,18fa3728,7a8f17b6,7439857b,3141bfca,6d89e649,7facf685,6331003e,f6bee07c,ed3ae47) +,S(f87fff32,2dfeae3,4ce9cb81,51ce2e17,6bee02a9,37baac6d,e85c4ea0,3d6a6618,74e49037,aa726e0a,357ace25,603cdbfe,7c14a4cc,2e1e4e13,c7176121,585a03e0) +,S(1388065d,dd7f69a0,11dec106,b539f7e9,e00b5aff,7568820,e33f9c1,18881ed,acab1d8f,140661dd,422f72a5,5ab4242c,65d1a932,23fe732c,92b32317,4d13408e) +,S(e5476b1e,a99b6a08,83731542,7a3751b8,3d685b34,acc5201e,59e9b623,ac4b6941,57d5b2f1,c4dd795a,323c794c,aa8fa754,bc86dd67,3cc8577b,b418b2e9,5f3b4e21) +,S(f938ff60,f1e8ebea,4c229d89,4c98418e,90c14981,4ed7909c,3dd47cb0,15cd1f15,d7172212,1a0cc646,a0576e29,372bfbd6,37fe2c5,b6ed6821,4da50318,eebb13e1) +,S(b31bd410,7c4a5108,1795544d,5854f9bd,180b494f,a08878ad,8ad5a3bd,98a30aa3,94261097,6bd58962,5e941aff,a007eab3,d33828f0,e12b31c1,8fb6f5c0,50519e82) +,S(b3ed87ba,83210d01,1a2df141,b9a6c6d3,33abd692,55da3af7,b4447d03,f4c1cb2f,949dd379,29c757e1,a970273c,b6341e66,b90be71b,347e747a,be0914aa,4dd632b3) +,S(60e6c240,1ea790d8,4bb95e78,731bca08,89a57c0e,38b87f46,668ee16d,31221e17,f247bf35,c722098f,2a5c800a,571eaf0,36738704,4050d98c,c03bd146,ca9465c2) +,S(2ae806b0,4cc8d047,e7dd8d37,713cd71,eaf3e16a,f74c3b87,994afaf1,c3750a80,a8d978ac,b29771b5,1a87fafe,605ca0ee,6facf6a2,41aa135a,e38de4eb,b2e2e954) +,S(9af178a4,bbba2d29,e7a0bb15,51f6f3a9,d2384386,3779f439,58a424c2,29bb5c47,c1031fba,a0238857,a487ac85,72fbb3d1,4052a4ba,adcdf259,78101a21,ae79abd3) +,S(9dd6a721,e9cb27af,2e7da097,c9e8a250,fd78a531,330ecb2c,3a116d99,6008f523,e6837b7d,647309c9,4712adb1,4bc65787,fc4e975d,f4e82173,57dc9d3f,e7f36080) +,S(cf5f16be,d7a1a1e5,3b3e3f1d,e44efbb7,fcb717b6,9a28bf0f,e31a1da,a5e91c52,9549ebd5,4d87207b,c63912c9,99920cf4,b0c80a0d,8a69d4b1,4852834a,c4487497) +,S(c6794890,810954d0,782466a3,c52a0149,de577cfb,3a2001af,d45e905e,dfa64722,4a4fdf51,deb64031,bfca5fbd,5c827829,8621b625,1be69187,fcc2460d,f75ca468) +,S(a25fffcb,bee9e0ff,1659c1ea,41406aa,b03b4920,fe1a63e4,442d5241,30599713,176b9e06,5a821189,ac3fc28a,fb72a1ba,40fab791,4de987e2,1236f244,bf41486a) +,S(6079a722,fd5d923b,16acfafc,7248e329,128cab6a,cae9e5ec,dca49774,e0c5bf71,c09972de,99ca5a45,c4f6f1d9,10337efe,23f5292,bd5ecc45,df0f7aeb,d18c4bcc) +,S(188cb43d,9d4078e7,18fffc42,8b16723e,f64b950f,cab7582c,8139dcb9,2b66b403,a038fa37,ec9ea240,9a2879,9556916d,fcc8c2f3,358ab14c,140f7f1a,23af5404) +,S(e310fc40,cb575c68,f5792506,65567ec8,c445ca34,68cfd02c,d781b27e,f819bb30,31328a65,5ba312ee,5e901def,66e7b946,e0c18336,a0f1784d,df66b89e,2abe625e) +,S(dd86485d,1c8245dd,d940bdeb,1f462cc8,f15693df,246c3c8e,52b574bf,77dea4ac,cd6bb7c2,56c9a270,4c690175,ba298a09,8963a8b4,7e743b48,33fc09c6,9966ce2) +,S(1b7ed20c,f81567b8,6f7dc67c,ab69e197,dba77399,9b36097b,de85d02a,7019aef,f814e92a,d1cb4386,550d89b5,9a4bc378,df428d54,d314d531,be6fc35e,f0e3d1bb) +,S(a15587b,2d528338,ed146a03,670b3f1d,9b41cd0c,a0645897,a0f719a7,b5ded284,2aefe34b,5aba1a4e,e30d225c,c4023ee7,12fc1522,ad6b452b,fe6ea727,122e925d) +,S(57bb9f9,c99da691,98cfcf20,9a0940ce,8d19463,9e4d1054,484953e,936a5484,63d0fba8,d90226e8,2c7be5e4,1d77bf0f,700dc57b,d8d3079e,9a6a47c8,331660e4) +,S(224295b3,7fa1b4a0,d7d7f7a1,2113b21,291f84fb,8fa4b746,bab925d5,93bd262c,d60ac40,b1e4b0da,7563eb74,c222660a,46ed388e,c4517ddc,ea2962b9,38195796) +,S(2434eae6,a34ec53e,7c031b2,9e74354e,d6101ca0,f228055e,53b39a6b,5453b0e3,2ff5ed61,d57a04bb,138f3956,33a20e60,8b04f775,6476d0ed,6ce7a382,743ce23d) +,S(448de592,907c1113,bdb04c64,9fb22b05,ef2e6ab6,36d0a03b,700a5871,89885ce9,d7aacffd,6ab35068,debe6dea,25b02930,63af8b10,d4592880,3d0421cc,a879eabc) +,S(8405cf73,5aef7674,7feb92e7,1aa3ba0,defc0a1c,c1da698f,7c2a3718,6393dd76,5795d006,49cd10a0,4a661c78,3f4a8711,89c9ef2f,ba86853f,c7955258,e6c407f2) +,S(698974c1,e5c1487d,fe9349aa,371eb86,9318accd,72c66d5,581211cd,6e08efc9,37c2238c,dc8f4bf5,1f76536c,2ab9af61,bcec872a,bb84ce15,90bc1c0f,ef84509c) +,S(8a37857a,be3cabc6,7197781d,f315f78b,e6548c61,1b846d8d,ce2e5732,643fee05,29882f68,9154cd0,7e455e4d,9e3866d4,5e28e99b,21dde0b7,8b87698b,4cf674ed) +,S(a871b34f,5cdd39fe,13104c96,87a8a717,25ec8cdf,fa60846,793bce03,2397eaef,84f96417,9de103c0,9f7e2dc6,86c9213c,642312de,8de6cc5d,f3ffd7a2,c387cb28) +,S(49bcafb8,9f78a7f5,a8857905,e99e74ac,9ec66ec7,aeab8fb4,fd964ce6,8286f44a,e7db8ccb,5641ab74,a791d2ca,7bd193ea,71124a61,2716d94f,4eae407c,ed9eff6f) +,S(d5c7d92f,2f05c9e5,8f586289,dffe8499,40d9b84b,79feb686,c3f71300,f68b6df6,a68b2a5c,219ea38e,a04b272c,e1cf42bb,6fcb2b2b,fce36043,4f1802af,1d51c08e) +,S(2ac2fe3c,fea4cd7b,9c74a249,cb0c8ed0,6a825cbe,2826c56c,fe4a8db5,3b286696,7d90a659,b008a51e,ca2f6031,c6ca6078,505bb46c,f00a3834,a67e7804,b60f43f) +,S(7c09acbc,62827ecf,4f63a85f,5a0eda7a,5b0069ef,b03b51d9,2f61c5aa,10a39234,e07d2539,c29128c5,685f8641,45fdc318,854b56f2,962b001,5a96c688,69624836) +,S(e886dd56,7e1b42e7,69941ae7,13b2fad3,3bb4ff02,34a27a7f,2c496bbf,6ffbf9f0,d4b2277b,abeef80f,371c097f,df4e5de,5a4666f3,c630b010,81d1172d,c667a877) +,S(edf65cc8,e83983,c5a178f0,ff60bb1b,8ca8a6e5,85344464,73a199d,59c2dc,a2426713,f0c5309f,84a4710a,2de1cdfb,118a4db,1070d23a,92c76244,89ab2d5e) +,S(29c12f04,b78a6ebb,9356dbbe,5b152323,435ad7bb,a3d2d036,a746af6e,d26d17f8,8399275,bf6211aa,78ea211f,39ec451a,b3336d27,fa059935,8b7fcece,216eae4a) +,S(d5db8b8c,280e9914,f0a034ac,3e0f9fcf,169f2046,4a618789,994f8a79,6663c3e2,41163c3a,85a0039,f5e5635a,819941f7,98f27078,aa65ecbb,eb60d577,c263412b) +,S(990a4fa5,630eb00d,958e57ac,8bb4f7fe,10e1055a,c547d165,7000a17c,d9135f8d,f25ee025,491fa289,446a0364,68c71217,eb252414,f8fcf291,2ecb23d7,4bc9653b) +,S(d784ecf0,1c7849dc,ec901c3b,3315cf53,4e3049ec,c68d71b7,41637b57,9e9c0935,5de98d22,cc382aed,d8c82a84,1ec6fd46,30672008,8567dde,6b2d64fb,6b4205ce) +,S(6576cd0,58850cbb,aaf53b67,bdf3c19d,9b4d38e5,19c99338,3204cd35,6ce38193,a329993e,92d1e56e,31c1fbeb,27648fe3,d984960e,30bf3420,658f74c6,5710eaca) +,S(957788e5,f675c0c6,4649a808,1c4549ff,20ccb177,3d26e4d8,bb94844e,bc35efce,7ea4431c,dc4bee37,d95c3948,615e17cf,1d32906,9bc10a8c,515aa0e,521d9b5b) +,S(8af7ca80,5053b537,ec501abd,78c13ff0,da5549f3,b045096b,1452c05,e39e4a2e,25e86225,aac042e4,cfb235e6,da40543,6a436206,e9d67fb8,e1b5836a,2d7e8402) +,S(49bf0393,e16e634e,202ff642,ad79c179,e6eb7456,637b2ba2,623937d0,e215236c,8590613f,401de0d4,1cc0ce1e,e9a13441,41e5f80c,179ac722,d603e697,a431a85d) +,S(c82e2a25,2572863,527b6858,18c9b6dd,df3653ed,a264b5af,dc5ebd19,d4192063,3b86f800,cd87c1bd,3d70af04,47f9e939,c2717ff7,376f91c7,b2675e3e,39a6de8c) +,S(9ce43920,2b9a8f7c,3aefc9c3,fe4d227d,42ec1355,158b2041,a3712dfd,d8eedbf3,dbbb5b05,859aedd3,faef15d5,9a939ff9,53a54bb3,dc2ee6e2,6d5a20c9,ff5b52f6) +,S(e07009e,49de05ca,52d20221,3ecab4b8,baa707ad,96ef24a,168bdb6b,16fe6227,6a35b0bf,e752ba26,81b865b0,ade8d4eb,2583833c,a1523b2e,4178f9ce,6cbc33c9) +,S(eb4dcdb4,7e09af61,e4694814,79612715,d588615f,f4c23fab,65015bd,821da888,63e38168,584602fa,1e06536a,d4c8115c,86305c,41040083,4a55d153,e9661b8f) +,S(be5f8681,2bf20113,1d257015,dd29dacf,a2c65907,26078f7b,f864f339,10e49db6,d0f420e4,56174aff,5995a92d,a73fa511,43c4f1b8,c40e9f30,8f04011d,956d9da7) +,S(3b32dc39,10e75f9d,98fa1318,edd7e8ef,db214a5c,b31d5ed7,4a61f881,355b99a8,1a12de86,19c2e9e5,9fddf756,e752e54b,6e4e0aac,572fbc42,18baf1a2,a3a18bc5) +,S(95ac5dce,5c06e885,65d2922e,a3f386b7,dde10735,169729d0,a3c3e7a4,86e04db1,1a22cd87,ab1b1821,e3c49e85,616b7b49,680edb77,251969fd,e77b5b27,3ef39838) +,S(6e4ed0fb,a4b0f13e,335d1b74,a5ed295e,7dad591e,a8dc5cc,d301836d,7ce708eb,9056166a,c61c4e09,ed988e6e,59cd9ab0,16a2ef99,e99c1a54,ac37f152,a34b931) +,S(8b7c3394,208e0ee1,374925e1,7827d849,ea8d9a79,91d2d859,898eba2c,23a42e10,b6ab9237,96720bcc,910e6440,75ef3ff,2c8bebf6,2f21ad0d,3abeb2,7043d193) +,S(fda7b47,f6690d73,884965b9,8b6f5dca,dd48ab4d,8f96edcc,8e20584b,b0f871c6,9b402435,a272cc6d,28b487e8,b54b473c,30929222,55e47560,e18b8e6b,ca926c5d) +,S(f15da0f5,395a5a1a,ef8beb53,4c0e9aa3,6e63018b,cc91a55d,ad6106a3,3dbcb217,28cf69ea,bb3b0151,917571ac,48609723,80be252f,bcf98f6d,db6ebf76,578a8f1c) +,S(c6e266dd,2c7817e0,c92378e6,38709a97,d9a208b8,7fa832f4,abfd881b,bcaf9253,2af100c1,fa9bb3a3,c8e95e3,5d0bef58,5ffa7adc,93232082,84291ee7,cb769626) +,S(4bf8aa02,fdd201e,488c21a8,33925687,7f5a727a,4fdab13f,d133d08,b6e28753,58812658,ad9c4d59,a15c6bd7,9e6c622,d8fe5f05,95cbdd88,f39be9d3,cd5fc8b8) +,S(aa985f28,6dd485a,5589fc39,da77fb95,5cda673,db61e48b,972fc129,7cd0a6d3,abb0f897,2f1163b3,29a5a92d,a1ff02e0,7c277710,10e24a04,e1e5f60d,1e4b75b2) +,S(8174d101,ec13a1cf,4eb9f88d,88c14121,6c2fa04b,ced197c,8e1732ec,61c41c9d,c6765dc2,31b02e7f,eaf7a662,5a639b00,c6e5d94b,1a791bbb,46f6a758,8fd79aa7) +,S(f9f64ea9,d6039297,b728fe09,85a9a3a2,92573aac,fdbe6cbb,8702f04f,6df3d876,4146c7c1,406067d0,160950f2,1172e879,188069fb,d87eef9b,1a67d2c9,9a4ca01a) +,S(3e643a70,5a6885eb,3d34454a,2a5de925,f8067cbc,1ca92951,d8865ecc,a8f1b3b4,2deca704,5525534e,de9d54d1,d777a996,8b5e5882,7162ef11,b0fe08b7,e2fb0355) +,S(444df411,fcc3ac07,7e95d200,d6f76d03,caae45d2,b87a882e,4c0966f3,376c63c5,b4566598,643d964a,a7cd1a4d,f2decf3d,ec520c93,ac6e32bc,64350aa5,5416cc23) +,S(12a2f61f,58be35fe,314a7beb,1a6810a4,19cdaa6a,8424d465,bbb7a87a,646946a0,9a7bdf44,94c2cc8f,f1953946,1a69fbca,48410b31,95d79069,8dfd535d,290ba47d) +,S(bdd72692,462573c7,3d48af94,b687bd22,511b2b7a,93f48793,3d52b2b7,e264cb9f,56e6c4e,b794fab0,bd5ac992,3f7469aa,858e6df7,dc40f4ed,955c0df7,a2123874) +,S(e1bd5558,77c3f55d,12b4f156,ea4da9ef,c974bd29,d7d043d6,ec7fe56,a4066bdd,8dcd9b99,fbe7436a,2382bea5,6c5a32f7,789cbf1b,1c44433f,f5a95075,c3233170) +,S(a7c68de4,781c8294,bea46609,f4a1f550,fc064eb8,b071985d,804351d2,60132ad9,a08278b6,3d9efeb5,1062b240,d45989ba,6f6bbf9b,ebfa0766,8428862b,adb42c32) +,S(4f3a8769,b4c6e369,cbdeb90f,5137d07a,5fa0d66,3d8ca79a,56b3c70d,2a9aa855,f6c051c,5f701e15,348ed9f2,c4707584,b9d6db2c,b62bf93e,35b6486e,ea6ea169) +,S(deaabc1c,8089ebfd,841cac66,d8a6bb58,36fd047f,cb435a8d,74463dde,f444f232,fb7cc4ba,49c26e7a,a826e654,7c8a6d64,ccd14a49,62a6d4f9,f50c293,c228e8a1) +,S(c411af61,547b1b38,12551e1f,4ef2b32e,fd7f33ab,7cfce378,8b5b8f93,319c0695,d2bee7d7,3d50f82a,e9266d21,2fcfbb76,294ace4e,f6222ab4,797bbf88,558cb66b) +,S(d0ff6a94,485bdda8,d0c28494,5b9dddc4,4a35f101,d0a89637,8210bdea,909ec5e7,ab3f60fd,2923a8f2,d02b7e83,d8f953c4,cb1910ff,83a92a65,e2121f22,364f620f) +,S(a0d05cc,9555ed92,2851baea,35ad6cb1,6f2744,b3fe424,98235aa7,1f08c0f1,843b1105,237158a7,bd7e67c,a20b2705,50afe2ad,318077dc,4714c7c9,d6339948) +,S(bea08445,eb295fba,5c83ef6,7d909978,7d599642,893fb9d0,568e5920,1e3f5d32,2a81a7ff,b3f7f453,d78bb2bb,41d12ed1,e26594d6,bd4f5cc7,908f322a,6cce10e3) +,S(e8ebcc4c,431be689,9eb5aea6,f6ab9700,551c3098,c5acece3,e822c7de,e6f0d5f0,ef99a461,760ae4f5,8fbd511f,59a2ae79,6d65db64,eaa0d61e,97d0a3b,31fa902e) +,S(4948606c,dd73dc44,ecf1db77,c796d8b6,806bab5,85877cd1,d9630bce,966e8fd2,3c67333f,786c8c67,841630aa,639446a8,cb8c13ed,f3db9123,bc64b925,beb95f80) +,S(4f259b32,40d9efba,4e3e40cc,a66cd494,fb5a19a6,5b5c8a16,5c18792e,9ea778c2,fdd88087,78c26999,c4a00605,49f4ea2c,b1590f7f,4748cefb,1b68eaae,4d17446d) +,S(f303a493,e14d7f52,f276e2b4,3e118eeb,1e7e918d,e7aa7f33,7e350fa4,7adfcc29,c49fa46d,befe53f,5f5bc49d,aa6ad265,453f7977,c5fe4163,cfa1bd4b,69141b57) +,S(e00c4b17,f4c0800e,c1b11859,c40a560d,58b9fdfc,29df5a41,ea4b2f53,c1df595d,62441a66,c3ec4d29,d18d0d95,7b4ccd18,a72a1003,d34832fb,8c81fb75,9763b99d) +,S(484b8486,1af6af52,a47603bd,2b754be7,ca16bef2,21581171,4cfb2301,db72ce70,36f84ff5,a0ac79a3,fe696865,2a0a6759,cf72e5c5,8c76359,d477e72c,4d32fbc7) +,S(88be58ea,d8b51f44,a1be6a8a,7cbc149b,ca07fece,11a7adab,210467b8,4cd93f14,94c10caf,7037fbc1,71cd6cd6,a0697b19,8ebbebf4,9f00c67d,4d46ebca,92687fdc) +,S(abf6ceaf,9fddd7ef,44a75e11,b10119b7,7372a3d4,7c163b77,384de944,47da781b,5cadb30c,6320c67a,e9dfe2f3,b9bb4ef5,41718392,81c4a59a,7960eccc,6795d290) +,S(e8c26522,9ef665b2,67fcf10a,17c6c3cd,4e221e0d,95663deb,74f8384e,b89d173a,9a69fbad,f9b050ef,d231965b,30d91646,bec7ba26,9fcd0934,35ae11f,ca2aeeb3) +,S(66652bd8,bf72ecb9,5e670a24,e8683155,e031f3ea,91fff58d,f60fa4ff,d9c6c23e,4844ec08,3f182b73,22c2fbb6,6f6630a6,5fa6901,52dcfb3b,4b65a3a9,30be994e) +,S(207880c2,d8421040,dc8202c4,45bf6d58,75cac841,532aaf0b,adf252dd,4c2c0964,2b1819d7,3eb24de1,ae4ef316,7c92a7b1,a562d93,80fdc54,e916d1f0,c1860cfd) +,S(46b9bde4,53d0692e,ec933485,ed0dff68,7e8f262c,7d9270cc,763fd959,2013f581,58af9be6,3ae599c0,f499b0d6,3085b7d5,394cc786,9f2fe225,6ecabd2c,a14f9bf7) +,S(5d9b2574,dbebe5d0,9756e2f,29af3aa,a2fa2555,d629a78b,82b1d679,75ea3e11,ed9f40ac,aa6ac68f,cee3dd50,7629758f,f3a64190,1658f0f0,2b87b645,ee59263) +,S(ecb5ad82,8b986425,9a76a649,1774338b,dc598fd7,77cfec52,d086c172,6e590e4f,2b78936,73c6d87e,a954b5bf,52f8212f,65d33ea7,ccc4b4e3,1d98df2,c9887886) +,S(b32b64c1,5e711b8a,1d174725,de55c,ddd62e99,fc90e96e,8f3ca532,3924ea67,af5d61d3,6dceadf2,34a7a94d,e7e4be1a,4d81b84d,e0fe16a5,403b0c24,a6ac2083) +,S(5137f71b,71582334,a6d57aa1,5cf6ab3c,8b7f6842,a800b4ab,1c308fc5,820cd364,f7ea5fec,c9b17dab,c6a248d,49757711,e4a3b38,95658381,efa652a4,4df1eab4) +,S(b9bb0e1a,390b5889,3e113a89,801c3f5c,25f94e65,63161539,e7c56297,ce9ea866,d8db3c90,3c3d35fb,ae4e14ec,e81e4e31,247f60a8,2539880e,6b66951f,8324a11) +,S(3f091967,6da40ec2,4691c21,1c42f47b,88cc1192,ec1827d3,17beb468,924fe9af,f1b44826,3e882c1f,18ae6a81,238d0724,ba4c04bd,d3fcd395,8775df5c,16bb8de9) +,S(b5fa25f1,dad4600e,8d55e7af,c70a1b2c,3767da47,d625ced8,d55ac88,d893b4fe,7575f661,f2ba296c,7ed3a190,8a49d099,83e49503,ba17a70e,1d6939b2,8ad22347) +,S(a0371ce2,dc6a025b,78db797e,90373069,e4ca06ea,6b1cc018,3d4c6f7d,680d17b0,92b5a8a8,9a5005ce,e851c521,4599b774,24f0ff74,5c4af6bc,6937c432,e859919d) +,S(5aae6e90,a49107,78863967,d7d42020,cd0a9828,da25ac8c,7b19942a,1ee2f210,ed9cc20,82a54f3f,fd7218f7,b79ec399,7e82fdc4,cd783957,5760e4f7,b7ee8fd7) +,S(54e7daec,f4a9b6f4,b100f964,850deb65,64efddb2,e6ce7b05,3fed2a28,1a0841a0,d9ada32a,54773a81,d5a857ad,8b34d96,70d46785,70943dae,cc83deca,97c9c63d) +,S(e9b29910,d8bcef46,b48d8be0,c7649b84,383ed752,391ecd7a,bdb454c8,8fbf44e8,eb268094,f669e91f,a5173965,50e4c40b,d7a26792,9a8df3de,b84c703c,261d6b69) +,S(43f95222,f254a513,1977c589,577d1d9d,3f537a1c,9fe14ef6,384e1779,da546a97,d7d3c653,43345c47,f245b305,b662a2df,eef80b3,97b3f5e1,4b0eceb5,71cb18cc) +,S(9fb45fd5,3999fb92,830bc090,216ae485,6723385c,7224b1d,cc91294b,a6c3b103,5b47081b,dbfd82d3,90d7bf7f,39a494bb,6731b506,b827213a,277f7ac9,febdf451) +,S(dd92282b,835529cd,3295919b,2eb466f5,9ca840e,20ad87f2,3cbc824b,b71dcce9,ec45f6e7,bc59d668,b1ef4a29,d1e23bcd,f3796268,3b58fb7a,d58a9e1c,5f726371) +,S(7482f012,9fbdd7,bf99def4,f3de23c5,fe29036f,c1ad5c38,686c05da,dc16348d,a43c4a0d,5497f6f0,bf2b2a20,b65bad11,73fc0dba,c24e65f8,db1663a6,b840abd1) +,S(fa4cfd95,97fd6278,1dd2f587,a5b03195,537fca30,f7a9a377,a69a6869,70ebd9a5,4568b6c9,9ddbf778,bd31d269,be18a8fd,e2a35031,a30505c,1b8ebe1d,c7ae823a) +,S(51e0d3da,e7763e8e,81905e1b,4f1ffebe,2f1078d3,27944c53,d9b7d110,3fa60b9e,118da0c4,ab572fac,cf9f20b9,2108ed0,1da673a5,2395f3f7,bfa2ff2a,36da6740) +,S(7d8e567c,c0552335,38c3b857,289e96f4,502fc674,f40ebf86,c482a668,dbc9530,76c3fc46,c6446a,4b9fe552,ba8b2614,7484581c,585c8ad7,600c2ea6,8eb37571) +,S(d924c6d3,b400196f,dd1f216f,dfa18c79,1c316d67,9ef4c0ed,8d12b94a,cd1dfb1f,ec33cee,881c04b8,b11eb3f2,88dd9b92,90b9d119,26c692e5,9d82aa80,4febcea8) +,S(8dcb330b,6f629c8,d18d28b9,7a99d82b,3965cb1a,bf953b8f,33074457,5e93c0db,3d8a2d19,8323902d,1b129b57,313f81a8,b58b7340,f6f7c97a,b6d74f37,a46857a3) +,S(dd1c4a3b,94b06378,8cf86797,ddaeb671,57910f1d,35a32e80,d3f749f6,bea5d2b5,efbec0c7,5a69583d,643e5be9,ab78cb78,3d2afebc,73d7c64c,869bede,b3230777) +,S(2b03de34,1dfad7f7,395f6ec4,84d292c1,ec0275f2,bc762dab,7658a885,37f5e772,3235e8fb,3818582c,55bd48bb,49f78e5e,803d7d1,ae49bbdf,97166a76,c3c0d0e3) +,S(3a795b0f,ba145bc9,7e7a80ef,a6b77132,677f06bd,4c3e7f39,47978c83,1428dde2,f4125b9d,df038a26,37cbc9e1,eed40aec,81af644e,a3f1352b,526df579,44914691) +,S(ecf813b,a133d6cb,9c46c081,b0a851db,121f5c21,788d1e59,ef8c0588,684fcbbf,69e0daf2,a7b7b473,7f2becd0,789529c2,597e3915,ebe12093,ecd7738,13e53560) +,S(637c4982,c14163e4,1037191d,d4e09d3f,74383245,5368cc33,57669186,d6217d5a,da5a2ab8,fd83d2e3,25baaa5c,a378318,f6fb3747,5ac64b77,a74da573,deecb410) +,S(19fe73a2,d8875b57,dcff5fac,20530da0,54255658,1251f7c6,b198b3e3,71b90e87,3b03ac18,2ccc2518,c367a77a,1fe5e8b9,a3264681,28fc1ad3,5a39f7a0,d8151ca0) +,S(16ea62a,d4cdc00,9d151b3,b6680b0,c68b4cbd,f144c234,71d55b7f,3bb7ebb2,8cac4a1c,53672e59,338612a8,995980c1,35f02060,2e3b9f6a,8fffce9d,e53fa629) +,S(6b9d68b5,454c6d21,678e5413,279f9a28,e1eed485,fbf512e8,49f35394,22a40970,b63f5044,98ebe37d,af9e6969,da888eb7,907f8565,4b05d472,fa4b1b27,ae365482) +,S(1fa20c8c,8f0812c,2e7dc948,afb7ec92,32c3c27d,23165d05,868dd127,b5ed3e6,c5257f4d,82133642,7df68606,2c229fea,6cd16857,280a60cf,ed84deb6,29838076) +,S(73a83c92,7daeb4de,1cf1df6b,31d8f536,af15bb38,be506263,e8e8a6a1,bf6acc86,a08acbe4,cd6c30b,82b4e24d,e8c9b891,26a21dab,e4df40ab,2fb7ad6a,82eb8adc) +,S(3a995664,924e2dee,ca278cf9,3ce265e2,85ba90ce,fd2a55a4,8e1761ee,7588bdbe,f3221adc,99eb33d3,52465d93,91caf18e,d011a1bd,3b7cf39,dd48d45c,44cbbb0e) +,S(7c65ee19,b032f5cc,1d45cd9b,9c160e86,5ca516fa,b4f88596,5e07f269,3d429c26,47c7faf9,e3df277,d31076ae,4be2224d,8cc54a5e,3743e287,ff9572a4,23704c5) +,S(c010694c,6750dbbd,bd953118,dccb8d03,2f05e6d9,65db8fb0,3dc00b22,e4d397dc,3b4914c6,dd6c5441,59dfde10,a196f132,5a5e6101,52d41be2,39583b80,6c8e730c) +,S(e255848e,d28d8b6d,6f95a12b,92136131,a33dcb2c,a723fae7,5e317cf6,62519d57,62f7d5aa,1757dad7,98207dcd,18183b24,377c9ac0,1e106fe4,d36d9264,3fcfb7b6) +,S(f31418e5,73232992,3a878dfb,f1de30d1,a9669da7,76effc45,bd1a56d0,2c236ed9,e62ab884,dce0d946,55e34c8a,630b5aef,16a1eff6,1f889552,af7234b8,ae56b84c) +,S(9adb945,b876313b,ac9c290d,47c1e6aa,1f3f3c9a,e8c67770,61512c2b,bd703181,b21fc142,b4632616,4820b82b,edddf2b2,51531d0e,df0f0f86,50f74d1e,9f0908fd) +,S(c4682b2b,9d4a63a1,855132e9,b35b390b,ca04b846,b83bf36,1726c3c5,808da322,f25a906a,7100ba32,1b659762,23e36f04,14e9075a,835ce5a2,6eeb5d03,d35f6972) +,S(ebb0fd6d,60f49c47,8167c405,597c765e,559159f3,ae04003d,a99a1066,ea80d63a,eb37d160,667ac862,1da2ffcf,28b431c8,c4202f67,706f4350,afdc868e,6aa0b0f7) +,S(78f12d20,70d8bcb4,267cbb,bff637f1,65ffb098,95f5734e,3551bcbc,9a5597a,42976ab3,36621756,1bb574d2,c87d99cb,7419a3e3,39973740,7de17090,2bbb78f8) +,S(3dffc4a,f6214b63,9839fbc2,b949621a,35ae41bb,e7679eee,5798afbe,85919f69,58174b6b,1b4021ae,22dd15a4,29d97502,a13480fe,902860e9,36fead8,57f2c456) +,S(410c9393,a4ed42ca,2115198f,4db76eb8,bd16bf0d,324528bf,55d5d745,b55a15cc,404ff4b1,df71b89b,c14c2cf9,bca25176,83c2981a,731fc3d7,59faa0a,5ed58306) +,S(6b4d5156,87d6b079,3df36632,6fe6977c,b93e6569,66797196,6c16c495,be4e3649,647a4894,bbac207f,5d2a0315,2db1760c,1a25560a,95511c81,5d6c11a5,e969f4e3) +,S(58ffad7a,e87d5986,f0bccfd8,5005d9c1,6f0d8724,6be4dfd9,4a771c5b,a5f34247,ad8b7ad8,f9ab15fa,f50d6f93,ec8629c3,b33fba6b,ee36ace5,e505cf00,f0069817) +,S(e6d3e41d,1835fade,af27738,23e883b4,adb95669,72892c72,b310eacf,a6a757fd,a136c88c,b580ece7,cef03e42,5dbdb8ef,d6395cab,b427ae61,45a0ef0,21359c15) +,S(fc47c62b,43aaa030,ac104479,21bc1026,3b561b42,a2d32a5,573ae947,d953b35,5d318d1d,65fc7806,732b5810,40a1f511,62723626,b393b29,50230600,246224f0) +,S(ceae2867,cbcb37bb,8e78da9,3553866,d0a1b8a2,933cb1ca,36bacb7c,6fdb251b,48bf2c7e,c163aa95,79417b37,343727b7,956cc629,3a188c16,d4c2d1dd,abb3dfd) +,S(abb12378,c84735b5,c23408d8,2516d887,9195fb74,c8972d78,daa8243e,1befeab0,5a0bf64b,da5a465,d9d0be91,3c8a56d9,ce901c36,67041a02,abb591b3,3f66698e) +,S(d7781e39,8330c7c9,2185302b,e116316,1a576ce9,43a4824f,274ea700,3159eeaf,6341a432,4e07c5c7,3ee7398d,d1be3d7d,261aed99,96f6f310,fbb464af,d06651a) +,S(a6918dcd,46ec2045,72d71646,d2a21df1,6f3ad133,dfd41a6d,be5b7684,7e4c760c,c0e51aba,378d498d,9a70e4b5,3521397c,1d6c7cfb,2f6634e5,1f056e7d,932fa9c) +,S(413a4ee4,fbb5de60,392b340a,65fd9706,7785e2e0,248d2770,6ef044ca,83d1a204,a0362506,c18a8f34,3bebc668,d1b08fd1,6595a674,51db27c3,43af172f,8a3dd197) +,S(e1a7bc24,de8b0920,f6c4aa08,2fbd1126,87fd8766,237311a8,9681581c,5e04001c,3e3ba9fd,d0a2873d,149aeea2,61a55c65,3a3d90b1,efa8e49b,29bab100,1a6bed16) +,S(ff9292a0,a147ccc4,b5ae077f,8a337e05,ab1dde9b,1795942d,8a9a0fc3,dd333a75,e50f027c,5f7a3463,7654b412,25ad5dfe,b555ea2b,8305c7a4,3b6f5b78,7a23a166) +,S(eae56623,437c9dd3,9dc7a36b,45c2d3,afe849c6,1980140d,900039d4,4ccb9c0c,f1b8c9e9,92847436,dcab5a9b,22fe7e78,55e62e40,372d77be,39f68974,dd32e043) +,S(7dd20cbe,3467a3df,e1eda0f3,48c39e5,7f9c6004,bcc89227,3d002cb5,54bd5282,ec4d2f23,f035d2d5,4cf4c3f8,31772a46,ee922582,8ddfd4c6,4eb6a689,7c1485d0) +,S(359811cc,5acf1291,547b8870,33bda3c3,e4e245eb,db0dbfc7,3a02da3f,12a877eb,ed2f5087,8b97a3de,6ff916f,511c3a27,7702d1be,2b683a59,bb6acd98,e908a792) +,S(fb33e89c,f2bcca4e,4ead57ea,1a24d1b,5a6c76ca,bc605a2,c031102e,49a71c24,c75e02f5,ca602705,7ab5b958,42a9272f,d7fca940,c26e980e,192861d,2f1c9f45) +,S(a1cd33e,5eed74a0,1534f836,b05a5129,b7b2970e,f293b606,9d1ebb56,e5f687aa,f90d1ab9,ccfc345,3b2b60cc,1e4380e9,bdefc37a,896a1abc,c9978d08,1ec4a6b0) +,S(461696b9,3643b7a,bfb383cf,ced8ac92,5d9f169e,1db30999,b8553504,c4213614,674f5c77,5f300fa0,c8f40a85,9aebffd3,ee91c4ce,695998d6,de0d59a,3033bc72) +,S(6c6aaa22,1b589f6b,ccc885ae,93f7e8aa,1fd5cdf2,27471727,f390d5bd,e14ab025,a77c5e03,40e1b90d,1ad64483,fb50fa76,aeb84417,88ca415c,9f8d2cbb,aa077538) +,S(c918d391,927f3310,d032c7ee,6e729e6d,792eff1a,72acc268,3874fcd7,4e61c38b,58fd746c,346048f8,eda1bed0,e5b6cb58,fce24a72,6e27f965,74243c80,780dfb5b) +,S(48679e16,1ca0a3f5,e4ac2654,213c494d,9240c3f0,33fbe2c2,142ec589,6dea5918,556f93fe,300cafe3,e93a2966,767840e3,b2a19fe7,9cf204a9,a30d1f1e,3e1d1a41) +,S(c68c05a9,e46b6440,a72d6eed,eaac085a,5e945659,ac46a584,69968a30,c6e7b858,b8b4b5dc,35d4ff80,be3d64a1,d036a117,c768746a,4d2bf2b6,1b126460,15de450d) +,S(d133ef10,6358489f,8f976dc4,b6c54699,21e3dfe3,6f326dc9,f0538757,9d444e6a,2c66abc4,db690d2c,272b0f57,afd66a6e,327ec3eb,e32b45be,cbf3c502,baf968cb) +,S(53544f59,8d759dea,b10766dc,48a7e2da,61ca0a60,a201d193,92dad05b,3df976ae,449a205e,61cb7aef,204e3f0,3a199ad7,993d711,537e17e8,79a42bfe,2869cd47) +,S(3108a074,fda5133,39e26385,14b6b7c0,9254c65d,ee374a62,2fe34acb,83b8b331,42edc90d,54263fea,8b1a473d,ac2f2244,d6fc05d1,f59e115b,5d930132,268b6243) +,S(1666c40d,52c1c04,d9e95099,aeb55861,2ee58ac0,6b22f962,154cd8ca,7cb4b23c,5065bb41,ae046638,aab55923,e0752954,abafc247,d201e84f,b6c444b1,93a82fb9) +,S(c96d07eb,d3eee6a8,f001290d,f76b2d82,ed80fa90,bbd5ead5,3a572457,ee47722e,d3d69c04,447fb7e9,a3416af1,798b749d,13ba06e4,78a432c8,d00dc2cc,7e20baf3) +,S(a9ffc39,b11b5b05,78769a9e,8ce7542c,647fa7bd,7b2c3479,fce84d91,1d81b49d,bec21248,82e928f7,e98894dc,25840712,80a64449,38e53747,375d2122,68bcbee7) +,S(52ca128c,cd4c9380,8e55d3f5,29320fd3,e825787f,1a600f27,37fc5fbb,f7af0632,846e8a80,95a98cb7,b4ebab01,4d9dbfb9,37ffa493,83676ec3,70f42cde,3135f7c4) +,S(ff92aac1,77fd9927,7b8abc41,e49f7c94,698525,2329b9ae,8e0fa34e,a9407c20,af0d8cdd,5aaf5273,ebbbf2a9,b7230373,dafd9a93,42a47331,a3379f45,8ffdcfb5) +,S(a692a73e,d3c10a3c,38163c97,314d02fa,5fb653b1,d729ff09,a541d01b,27991e0c,722f55a,3e5bd3e8,d863d00,6b82415a,aa05c949,9a537809,cff9be69,e468b905) +,S(d9e59c3f,7a629a93,e32fc4cd,2c98d480,6b813ba6,315ce4e2,e2fc7fed,4120aefd,24ce2594,23073119,4f5bf658,909a47fd,3234be39,13aa8d30,eb08e14f,af0214bb) +,S(74e5270f,7771b109,64991ef7,9abcf05b,4dde8d5a,605ab587,14b8e534,4a0f6ff,2ad861a3,a4a83f09,687a285f,1356b1e3,71ced066,69154887,14bb0461,b3b1670f) +,S(b9169230,1c43f7e7,61a85615,7957c3a2,744668a4,8587ff58,7a201f59,31d4420c,bd36065b,c1268280,4cd818e0,c6515a5b,659ea423,f5b23e5b,ebe1f74e,5819536f) +,S(37faf253,864568da,972d7211,505b7fb2,cd01fdc9,5953bcd8,79239d90,364d51ee,b69ae2ce,749db3e7,e6aea736,a3bc961,d8c12523,6f7be823,65749ead,3bc15f85) +,S(e194114c,4a1c138b,34882477,f0dcd065,1c379f98,c198614b,43b087bb,a20cf8d2,7a3afb4b,b90ae22e,3b182cf0,6514a998,889f2ad3,d71d4d67,89e3758a,e898a93b) +,S(2ce2db01,d3fb451,7388e4b3,c81588d1,1c8b13ef,917333c,ca054379,fa17ddaa,9232da9d,af0e76a9,85e1529a,ed1a5568,74285cb3,8010c922,e2c30d77,367bbbc0) +,S(c292ec48,4bdb7045,3dce2e82,1fea7688,bd66c6e,59635f49,98618f9f,3d6f051f,210a74f0,6b81e69c,4d0af49b,fd153247,12b77736,126f4887,2b119ec8,97b57d6d) +,S(15bcc9c0,97618aef,697b423c,cd83ad3e,933db83,d77b42ad,3e132036,a5acfeee,e9fc7ef1,1bb996fd,bfb3c490,14912ca1,a1bb98a9,e9611c,1a83a806,b88a7a33) +,S(46119caf,50f13bd7,97be45fe,55f2d298,848639c6,99d5b113,fd24cb24,6e1e7785,6a203f91,f4c56eb9,7762cf8f,9ef932b4,ba301501,5aeb1215,b1327a93,842ea3b) +,S(f3a17794,3e4df182,a9549a3d,2da1f9fd,cf141094,5e6b3a64,9d9df885,b6f9ecf4,b34eb7cc,5e82ad39,fc2b6619,859f8328,444a1dff,c82ee115,c80cec10,6ecf7e8f) +,S(cef90a74,84a7f468,db9cbd45,f5b9a0c5,fa98bdfa,50297d67,536075c6,b7913fe4,d090eead,2a43fbc2,86702946,52507875,fb79a555,e5c55737,30fa40a2,6a301815) +,S(21d8a214,987aa938,ec4b88b2,4bfa5661,26c528b6,b9060b06,833c6ed2,a35702ce,c354340d,5b65a23b,c628167c,8a2830,f736dfe9,a501fc8e,94b66f26,d84579e4) +,S(6b18ff27,9049be4a,62a04f6c,f82dbd24,e19196fa,46e0761d,5d139518,3a1ca53e,ef806f0c,52c01367,8f81e9b2,6698fa32,6343f0d7,2522f8d8,6cacfdb2,c5ffa3b7) +,S(7d8ef4f2,452cc04,d5332afb,ea3e673c,bab07c36,c081a0ee,850ae31d,cb466e6f,32461667,55a2ceef,273367d0,df10f6c9,d224da47,f19117bc,137a6244,2cfa0c0d) +,S(c7de1821,55d15649,f5bb6327,65ac74a2,3413560,b1d31afd,6994b488,20d12cab,d9965856,c5fb2c0f,c93b8659,5c3240d8,7fbe0136,11d7e844,48252ce7,96eaa23a) +,S(4cecb33a,915e2c3b,189eb6ee,45fa4eb3,eddeff09,729945c6,f893bd,4381b294,cf17f112,b5e61cb8,44625035,7b700cd7,3534d6e1,3310b6ff,d1bbbd8e,1ea3aeb1) +,S(826cf464,bfce606b,b4c3ab5d,4cf00fe4,1c9bc72b,285c8c10,204aa658,66255749,6ba3b431,527d285b,5156fabf,b150aa2f,6d7ca564,b18011cb,b878e235,7b6849c4) +,S(c812dac6,f497d245,5192ba92,2d6fc10d,de51d608,d82e828e,b2187e7,648f8f62,d02e8c7,73630680,8126ee1a,efaf53fc,2be94dd8,7773e8f6,1ba6b4ab,b08b317e) +,S(5269550e,bd967f47,e45eaa8b,c9f14ebb,aa45926b,6e38cd1e,3c6d5d3f,e0ff8851,a1597d20,26e3eced,443422ff,cd1b3fd1,b45963d0,3086a95a,38b8661f,99a7455b) +,S(7fcfcb29,80e652cf,bc42721f,cdc40ba8,c7c2ae6d,54a51e9b,af1afee7,e84d7676,abf72d90,4a408e34,ec6bcbaa,ac8f19d6,a4d044f5,66a9cce9,f95debf8,882cfcdd) +,S(85f01aa0,4597e104,848e18a2,132a6a07,3d5f25eb,8baa857c,79dc4b6,64a9f451,f7463ceb,8a058187,7bbb71ab,35bcf456,5398cec1,cb4e0132,4b4ec47,e5f081af) +,S(95b4a1a,7dcd860f,ac3fee1d,10febeec,dc1a5fbc,224035fd,a01f8dff,92885628,2a0cdf9c,5bd94467,efa9dfa6,94c6ee3e,1f80bced,23738d97,f70406ec,bef7f772) +,S(4f624a6,24dddd0b,b254b38c,e37753d8,8cd95cac,ec4709f0,49b90ecd,7f6c51c5,874a9a83,2efecd9,2a20dcd,8ccfd454,668de4eb,1b976bd0,70ce584b,c77a4fa5) +,S(39e06912,e18b537b,ce440f58,545e9c6e,a2914d85,698d4043,437dd66d,7506b48d,eff20e0a,16e93096,abc80153,c128aa12,f06c6d,4695bef1,8db7a167,6f352e0) +,S(52edc132,66d67831,74ff4f59,cadb979,4c1d41b6,5efb9310,7a717b46,78f1ace9,e569e202,c6781e3f,e32c0bf4,9684d7d3,cb07cf55,8f46927c,3af6bbc1,c4d402d1) +,S(e3764b48,964b8107,3e287f07,c915fc8d,e4e9458d,6f2a8d3a,1dfa43f3,4328465f,bde2a64b,fb13e0ba,351b460f,6d0d7574,5b7261aa,53a79b6c,3ad5c8f3,4cfdb023) +,S(80efe507,7c77698e,3ec38768,ef81732b,e1c81aad,9c42cebe,75627eff,bcf513e6,690c671b,c54391e9,695e6059,953d3d9e,a9df2e17,5aed4bc3,483f104a,388b709) +,S(484ac7d5,ebcc497,a2f2bcac,87cd23ef,19b0bf7e,93f8e728,5173f70f,c908b641,1d9570e6,f3b17236,9f2b8551,653f3271,5bc8c995,14c2aeb6,1b44ea5e,90ef371e) +,S(9c989e3f,bf1fbdd8,4dfca53e,4415cdfa,adf26c26,3801ff65,36b8fb5f,77e3d124,a34ae61f,5755163b,964b3b80,28fee3ac,2993c442,d7f16dd4,c79aab0c,88212a38) +,S(8b8fb0f,601afe7f,6456570f,19e37f80,32846dd2,97b0d8e0,9308c57d,75a5066b,7858afe,ffc4e6c9,b2e32f10,fd67a1,d6166c72,26f03b3c,240b29e0,e848c9e7) +,S(e37d0e74,ee1d79a,981baa79,e0a5d807,bce0953a,211c00ef,451d9d60,7ee78177,d28a1285,2ad25f4,df1b5625,bfe59875,a07d0593,aab4ee6f,4bd23ebf,b09f8f9c) +,S(80c8577e,9a003683,ad658e75,47657b1f,281052d5,54cd0e19,4b2a9e70,1325c147,b3fd0cd,7ca3a2ea,ec7ba8a0,d7297347,fe2baf99,bcfbbfe4,32a6346f,564d945c) +,S(e7045d6d,34121e5,536f7902,67ae01a9,50f6ba8d,2d05349a,ddeb3833,3ea8c6a1,7306a8db,326994df,e15571d9,c2a5dd24,60b37c2f,e97559e4,e7d88ab8,8a181fba) +,S(55d2da4b,850a47fb,6b3af0b1,3c03889a,d87554f7,cb346980,4f2978c8,652e0d71,6ac0f982,c861d0f6,cd20b7b4,f22eee5d,189a56d,5cc46780,72361e79,dfe16e7c) +,S(ce562e09,55a22f7f,c83a5ff2,11500c03,a1e86d1c,404019f5,5bd1cdb0,b1a38d2f,91de004d,b4aac47b,c6b0a165,edc5f82e,47407032,6f1ced31,4bd6d96b,521bb865) +,S(74e00e1f,596af05,7f91bd64,53107f1d,cd0eb8,6b93b6fe,cc7592e3,7854773b,11ca88a3,38e52a53,eb311867,b10a146d,6fa9f015,11791374,e13fb749,d8e1d217) +,S(ae8f0b6b,c194f6c9,1d83e400,ac92ed97,68214d39,95868530,a2e99f9e,2104eb48,e973fc42,dc0a930,36127de9,eb57cbf8,d4aa8f73,14646362,c855ceec,d7ce4cf2) +,S(40a8c06c,8df83675,e108e0c0,565f33d3,7854e722,6f76b674,1582fdcd,ef891ae7,16ba7850,b5116afd,3d29e0b0,40faabed,b8ff9c09,83af624e,a100555d,887bf7ed) +,S(61ea9e54,5c57f6fa,a2ab410f,861f1fff,926795b0,4d240e48,7f6df1bc,6df83b33,c69ec12a,e0b217c3,72e1791f,7d4529f2,b9063e67,38a8c03c,49071581,da79ed15) +,S(1c889cd4,440caaa4,fcdf55f7,2145fc17,d73e25ec,264831cc,30a0cb5e,c1d37632,41b5246,131fa67c,7314a223,7db5e4b0,574f5b86,11560166,ee55bc94,22d72fdf) +,S(ff295890,791d87e7,982a99d3,ab50bfa5,c58e0d06,25392abb,4ab166a1,8e49525d,a09664de,19951364,19649baf,88806fbe,c370879f,efbe4a58,e619a01a,19454570) +,S(5eb2eabf,cfca1fd0,7c939e5,b8f890cd,74e399ae,d9bdf785,7bca8767,84e95f99,4c42e970,1c9a783c,201aff12,16265d8,1f46f25,fe110f63,31fb8fb,f72c9871) +,S(43e5508c,dbccc93b,5b3f8ce1,7a071c1b,3b17bf4d,8153f61f,cfc7b6b4,f6cbaf91,b5ed8f78,438ba71e,509ec388,d09a5307,c853bb73,db240638,15a07343,9bdfdcfc) +,S(f5d16930,23cb20df,c8607261,cafe533c,eb513f87,7f6e2c99,5b0c0f75,fdb56f53,e539b168,1528332,f7fc4bf8,73e2965c,2557dd40,6eb2c8f4,92ce0dc2,126ece68) +,S(db9d66d1,5dc5a918,46180a62,d662a2eb,72313c6f,ba511eb6,c7fe0c0f,78aba2a1,c96de8a3,61f0dc5a,9e2762d9,2257857c,3cfb46b5,81c3f0b1,f89a20f2,a1517227) +,S(e760d3d8,46fd63bc,4f565bfe,7bf5133b,56ffce08,27b99ab6,833a64b8,868ecdf2,60ee6685,8be2eb4,1821cc82,54062e01,2c1c1e12,285c8381,e60e5d4,12f102ce) +,S(2bdb2299,caca7ab,d22533e7,12e37004,e3a956b0,31da4d99,1351d790,5c33e026,64675cdf,c2738105,dac3e877,e27d00e7,80193286,24cbbf82,a784713f,b6e44731) +,S(1cce0bfd,5992134,b7813773,9fd6c844,7be48d20,e001bbbf,c3c87b9a,8166bee4,2d4a8ee5,1ed7fe30,c3a1253c,4cd9e83e,b5eeb73e,c166f4cc,42788bbd,cad37057) +,S(6d6be3c3,7f5dae7b,ff5b5bd8,ec6b8c65,ec8405c5,bb6575bd,6ebf89a5,77641075,4fd3cc1f,5c6fd3bc,6011507f,7c4eaf4b,24d1938d,35159b80,39246ccf,ac9c2c7f) +,S(d82c180,d96e781d,783fb1ca,8758fa1d,b3c67f2f,143e836c,c6007d8b,bdb22351,3802f669,952aada8,93b3e9a9,74a43218,37415af6,7964b1e1,51a7b8e2,7ad0c7d9) +,S(4ec61edd,7e03fd34,f91dfed1,b546f1b8,fbf9fcee,8c73e343,b228ce18,3db3cd71,e1199709,b5b2e2ec,8af90340,de9ec3c6,db7d948f,aa941cff,b1984856,b03ba9a9) +,S(31aad469,73aea11b,a54744d7,bead13ee,a8df7a8f,8e735643,add781e9,e17a034b,64676f41,3e49f606,3f68bdf5,7ced7486,a94680f8,e60e2913,f13b674f,84b37adb) +,S(a9842189,2fccdb8e,f6515903,b589ea62,1f946bd,97e2931a,5eb1ce4d,4d173e02,50be76ac,3b2dd7a3,a3370e13,3cd6fb37,7ea266d,a566049,abe488a4,89a3908b) +,S(822b54f3,3ec00433,7a6cfa09,277540ce,fee79b08,a50695e3,f8fe0ece,b7bef099,393623c6,20d3f604,7343ddce,d8805bf0,7405d336,fda8c712,8d044851,236bf7f6) +,S(100f6b55,fe3d7000,c5f8de14,ebfc5d7e,15793d10,e99dea3d,33adf25c,15065e0b,d1bb44f7,58c4dde2,7c928267,6d6c1114,a352ffd0,dcec8e51,9b2cd74a,4eecb4c2) +,S(ca5d8318,6a09c227,481aa6ec,d195d094,6a54257c,5adb71bb,2d4e8836,d6142f7f,d890847f,b9747a0a,f3ba0c38,84ae057f,878d8d31,fc73933d,e014f4d9,2677b42d) +,S(e91c25f4,2234d20e,2931a352,f98ff610,e8ffe53f,101b56ca,fa5da12e,24bfbf14,b1ec15e5,441ec52b,c71740f6,d60e99a7,7a26bcf5,143ceb41,872b4a22,964dbb86) +,S(57a8c8dc,310902d8,8569b290,22e99ae7,acb54547,2ccf7065,9e9d42c,1ae34445,85224541,442e09d,f4e92db5,64866aee,50e7cc3f,b8c20acc,b9c6161e,30ab1fb7) +,S(232b8c67,2502d16d,badd0d41,28c02b6f,55a8531d,a6fe87d9,581045b0,7104500f,38110a0e,9e7d8587,227c476f,6549492f,4f5255d9,e618cf39,9a7a40f5,85f93fb9) +,S(7d0be68a,d71f69b3,4f5d4876,319f7e7a,750d5c7,e3dc876,187627fe,77004fec,3e72a050,7d0af3e6,1d6f5402,8a5b971e,a12b1d18,2ca45e67,ca09efcd,45124633) +,S(4dd85f0b,77c2a271,c95fa436,90c43485,b70b02c4,9a46cd83,6ba7a2d2,7af93292,843642e5,c9554d98,48ab6ff8,5dada7a0,f139e64d,2081978e,8c9e3bf5,1c11d597) +,S(537a93f5,88f02004,70b531a1,74ba9a7a,3eb2e5c1,eb767214,9e264e2f,712e52f8,b0d9b3a0,dc009266,8e25f06,71895af3,94efa1f9,78257ebb,3f839b61,340e161f) +,S(13faf471,325b1e57,98ce60a4,6f82bfd1,ab346590,82588ae8,b972b331,9ee48684,a6720384,e84eb529,e22f2585,79b2201a,dce7ba18,845b8bfa,49a21ade,7634f743) +,S(691e24ed,5861b344,e015dbea,809dede7,ca17c482,22d9e06b,e1be4405,cfe8acb8,e3564adc,c197b0f,cc520d90,9d9c6347,5ad00294,3d0f3f96,6f49b76b,91c529ab) +,S(36543b91,aaaea850,15aa394f,fb334923,b754b3f8,9047f73f,423c15dc,7d3d7ea2,73b4693,b79b800e,8e48c838,9218094b,9dff44fe,5a1fafd5,2d68a2f1,bbbe5799) +,S(ff25abe0,394180cb,1e045045,5320ea80,e007bb0,fe3bc8a2,24f20b07,8433f05b,a512b109,26dfe650,e6dbd678,ad9db412,938f69e0,8aee6c2,f903631e,530b7e51) +,S(1dec07b,5faafdaf,51051f57,cd0247ac,cc607bc1,70c53222,72d389a1,7d87e443,7e77e937,382b2bc0,5a2207a9,2598dad4,d870ce67,d0e138d3,bb35094b,9fa9a325) +,S(2f10f776,f62f8632,ea20147e,d14e0919,485ab78d,fc636236,29c2994,9f413c32,3b2c5fc6,e760462e,b9d8c8b,5aa6b1f6,35c23668,33e7ef5a,d25269ec,68d2184a) +,S(7974f394,e61c2cdb,acf09681,4bcafb4a,ade31943,cc180188,31160022,dabd73ca,e1b34da0,3bc1aa66,87df854e,813ba451,2be4cde8,310e4056,73c83600,89e98309) +,S(54c5f39,3c5cc416,56577469,84aa3695,32af1ede,3a51b14,436748cf,1701c332,3dc67b49,49769cc5,22b0626a,eeab6ba,ddbde8ac,ef78a0cd,800c1b6a,5043e4e) +,S(199aa296,f047c7eb,1d8a972a,318585ae,8092e905,e555915d,81c1a3b,425f3783,f5823679,64d17a96,b4ca7946,dfd3a266,585154e1,cee02e2,b87e8fc7,eb46c262) +,S(d15d39d6,fb616dfa,6c292a3b,a1fc58e7,cbcdf0be,7976be87,9a7f088a,9bb7f299,4c8ae97c,4e37f837,bdbd4912,f43bfc79,679dd418,b57d061,f705ba60,2bd7a900) +,S(76d65134,880e7dfc,81a332c6,a04b82bd,bff26eca,9a5aedf5,a6f6683f,364ef58b,b71ae708,bbd22d83,a1ec9048,6975b9a2,7b4aa5bc,5bf1246a,6464406b,401507e7) +,S(1eb4d2a5,d4dffe36,30ae9ead,792ffa9b,452ef0e1,94c06a02,a0308143,dcae51b7,88d978c1,e6ab8e79,9a286af4,58cb3eda,7cc94b67,589b144c,9a55cdbd,6ff47b0b) +,S(dee03251,35708790,361c3451,6710623d,e474bdd2,4513562f,95512f0c,dddf571d,d22dbcfd,cbf6d809,2c68a28d,c118ffec,496d9623,b20667c3,7fc487a,1690f565) +,S(2eb0272d,c98ac6bd,ff68f0d5,5f13f509,bf1dbd9d,f36385ae,ef02356e,56d4760a,f80d4355,4aaf4eba,27aa1832,90573687,5c69ad44,7211f746,111ca02b,26a04277) +,S(eaf62e69,7509672d,8ff6ff7f,c7788822,b75853ea,27636b5,c39b0321,ab0eabf3,442e56aa,1c8fe22d,71b88b96,90733f1c,8614e160,35070095,6effdedb,2e0a3b7c) +,S(2059070a,13d96fd9,6bdc442c,236ef463,cbc70185,b8799d3b,15ef72ae,4592858,bc9042e8,3f259ae8,f6221d7f,46ae56d8,f426fbfe,901b94a2,80da34bd,14961ec8) +,S(ff2ef7fd,9e7f3e7e,6f7b4cee,a44ec281,4b8b4a44,208c462a,f925d27,ad2f52fe,6ace74fb,fa6f72b4,8156cb52,a67f5137,956a447,6b69fe3b,233ce4f3,df0a5e24) +,S(e3e5cef6,fc4553fb,d337a7b0,4357ff1d,d8fd0de6,4df17bf6,20f7f9d8,9d14d83,acddfda1,baa7b60f,d0d1863f,769a475f,e667b6fe,8a047365,1b84f44d,238f0460) +,S(97a8726a,41c02880,e9942341,a66b9c21,a0c64577,bde3c54e,c11119cd,bf57a6c3,b5f37cae,27023d07,78cc5c7,26d845e1,fe160aff,3459d164,681cc38d,8b67b4e8) +,S(ab01e6e9,4862f943,8639484a,119eadb4,12fd9002,1d7781c4,1b020450,9dcc81e6,6ae50c32,101b5c3a,51fab05,2ed79e5,48853cf4,15a30043,6b11ee05,7483b14b) +,S(c464410,da2dcf6b,2e6ba5a,c8d8479e,58ed9a4c,a8c2b0d,5a2ea15f,7673668f,3698c590,62392c7d,e597f333,cd3ce45b,eadee944,5209d361,adbbc386,b499945) +,S(17eacc68,5f721f3e,2013b0e6,76c10795,ee49d524,26edbd86,48f098f4,17867534,cc3116e9,cb19f49,bbf7214b,b3ab76fb,fec0f856,e994a01b,d6b63ece,189ef300) +,S(c040dd40,2908ef17,539b77bd,5befd53d,3ed2e8bc,d7d3608f,2b114dea,d4c00d73,7a6384ae,55ec2580,4d1403d8,45113dce,b2053ecb,6ce0d3d7,427835b4,15279c00) +,S(a5963498,3658f70c,2ec25fed,6659a290,41bf2ba2,ba92db93,41b03e39,2ebddb42,dc114caf,260ec4a7,a8e8bf4,1695785d,1ce7c2d2,82359600,a950ade4,d79f4872) +,S(44fe22d4,51dcf63f,c7e33d09,533836c7,66382372,339de279,9897cea1,1b29aa0d,1718c4e7,3d4bd434,929e9ffa,e2496f79,4f3bf80f,ae805a9e,53b577cc,4c4279b3) +,S(8bd718aa,1358c15e,fa3b246d,e244bfd8,4fc6b5f3,ed5ec91c,ff466a11,2c71647b,172f1a88,ba6c11f0,1b7deb8d,e4002793,65a0a3c8,443b2fa5,f406dfe8,4bd737fa) +,S(8ebdcc25,bbe6aa23,809aa53c,3ff3a7a5,d7ad4cd5,5dcf3cfc,d9ff8ce1,738680d1,5c563b26,af86adfa,c3728c,f886d83c,5be64766,78ac5872,cd798875,45e5641a) +,S(5cf54e1f,688faabc,99742fb8,be896cfa,b469e5d2,feb72f4e,9dbc67e0,e91713d2,d82d6590,d06330d8,2f86393e,190155b3,4920e8a8,86324b18,5694786b,e4fd09c5) +,S(6c0d96e4,3f01a1a7,2ec16ff4,e04571ed,387185c1,4c8a2f8c,db4c187a,85845f1a,f399a14b,763ec2ec,f3415c1b,b9bb6f70,abcf013a,3117ddd6,e55a96a6,b0798c08) +,S(eae928fe,fb6a2fdc,d05f1515,5726a133,9a15ef0b,ea716ad6,90d32dc3,92b74046,bdf87ad9,f086339d,cbfda797,8d6ed40e,f6fd4626,60d6db09,84ecc577,14c76bc) +,S(e5e5e30c,bbe72fde,d9f0dbbd,e08dda,b61d5cb3,1aa688f0,d572008e,447b3a21,9fb4adb8,f80b6e67,47c6ec03,d5171ce8,5de65682,a105435c,5610065a,85b248ae) +,S(711212ac,c9e26bb7,c5ace176,26b300bc,78df6b0c,a79a0b79,7dbcca,138223ee,dc68858,4ef44ddd,9e6b343b,c4c73fe3,6b873239,18e11cbb,dc3aa72a,ef027757) +,S(3b52ebb3,531aa4f6,ddbb9ea3,fb5e5784,c4cf11b2,a4c67d50,6b6340f0,21c5e22c,3da3eebd,dc0046a1,3facf02e,46818640,b698c8a6,3c5fb9de,55a9996b,b190938a) +,S(30f28481,110345e2,7dee7292,fe1c7a56,45294a17,e96cadf9,1eb76bdc,cf56b78b,70c610fc,26ece34b,f047864d,25116fac,3c149164,a1deb08,8e6d702b,77abb049) +,S(4a844a8,12c55b6,4e4d37b6,1ca4a1f1,5cfef527,699d5ab5,edf1564d,e930ff58,49874548,508de6e4,dbbe6bd3,8d0a9ff6,5826f9c0,63274cd3,f3189d59,683dfa3c) +,S(a5ca561e,a7c8484a,642e0fd9,a999e14c,5ce2b5d,edc51026,4519e6c6,7868b06f,cc917942,a5e2eeea,ac09b00e,affa7f6b,7abe386a,241de5a4,7a7c43a3,85afa7ed) +,S(f61b7ed3,1e16c456,c3851a68,e10f614a,1fa547c6,456e57ef,3c1f8ee4,dfd6e72c,cb26d0b7,fc401865,91f5fbdb,4d17bfa6,a0c5a811,4d099a54,734a3280,5f622f2b) +,S(f8e4d462,889700c4,b52859f9,e766fbe6,55976866,a22207fc,aee56185,15f678b2,30bb039f,c1b16fb0,aa09c271,bfbb76b1,6791e95,9dd51ae,6f01aa4e,bac77554) +,S(89cafc1a,5d25915,b2f6f71,71814a2f,d5d97a06,a717a91c,a392909d,332ab653,1a24a0ab,b4e4858,d29c0055,714f34e1,5eac02da,60e87ce1,6fe2f144,257ab76e) +,S(d285370b,d04f5dcf,caa01dca,7a2ad510,33c5b555,6aea60bb,4a48d97d,477c4f20,d4b427b7,32e885d0,13a2adf8,ec705145,c61386b2,c6981b41,6c44d202,4693b9d4) +,S(3c532f2,d9bdbfb3,219dc90d,17aba269,fd335066,e1fd4974,9026f66a,4df217c0,86fd5e7c,a6c97fd0,2c33c7b4,28413977,2791a6f9,f8c80576,75b3e306,66ac5d59) +,S(24d1950b,fc35706a,21b17a16,53037226,2984453e,37e26924,b730314c,cc8ac1ee,4d22a45d,6a31a90,bb247c68,59ae9a75,b05bb9e0,8b57ded8,4b9c1ea9,c9f918ac) +,S(cc6ab0f3,6227b1ab,149f8ace,ea036fc2,d8505341,ab67d44,59582b36,4e7615a9,f9ad93cc,40b1258,67c806b1,20fa6f21,bac918af,54a0f7d7,107680a3,83761cb8) +,S(de24a954,f36e94b6,ca816bcf,f730b99d,6320f20d,9b141cde,f08ff71b,25318cf,3e34b1d9,1ac24a49,b982d235,44afd62f,8475c35e,a48394d9,67904a41,db899933) +,S(77ab04c3,4900aba9,d83a12c,7953cfbd,5f8243db,48fab618,f83ff252,5a1ffec7,6265ac27,3bcd77ff,496265af,75a8db31,231c871a,30a32bd,ae873efe,bcac2f00) +,S(a47af706,5f4699e5,e0079885,d19580a2,51ff8dee,1dab741e,ce84ad51,16e78209,393cbbfd,f1b1f78b,a563f7cb,3465ab97,5b786088,3daffabf,bb8f34b9,7a257440) +,S(a9f5f9fd,c55c7b7,4dd170fb,d0322026,93d709e1,d52a37ea,8a545e9e,9cd7016d,98717925,4badf22e,8fd847b2,e9e80ab2,54f0d327,f6b6162b,8734b105,f1d5e0e1) +,S(d57e9ebc,96b938a2,8fa200c4,e586e7e1,ba866864,a947b71,6cc7cd63,4e18ec38,9aa0d2ef,68239110,5b4c8b7c,b412df87,25de16ea,f28596a3,62a6aac,d1b6bd36) +,S(7463a8d8,fb4dc14d,5618e66c,aa85d73a,e27ccc1c,ab820611,9f506829,faa58e9,82fd6ab2,275af504,aa0645a2,8438db86,ae7990c4,b4c389f,569aad0,68d4829f) +,S(2e7a708a,29c44831,9a02d03e,4eb331b1,3927ae64,534db2fc,a3c6e7cf,d53bf412,84f3f199,73500cdc,aeae0073,f39b3b2b,ebdf6824,ec018160,fd2e3b3d,4b1e11d1) +,S(8707b0bf,540bc058,faf2f3c2,e8ba304e,180d094b,b7fa8dda,414d30c4,d9dd5e03,70b61175,fb791033,50c6bd25,aa0594d7,18db5ee9,9667c25d,fbb49c20,f100b915) +,S(3fdb370c,3ce6cd02,886070a7,28e66749,22f67dce,1b6c08b9,613aa2d6,53ca842d,163518f2,474a0344,a5c4c5ec,10b1efef,5d3a5ef9,94010063,17a486b0,c8e0dafc) +,S(c37da302,412cd549,a01411e7,6f58d4b,33077960,94b31af,2a283d89,48472f62,aa08f287,16c642f4,8702d1da,aa0a82bd,ca849000,b8ad1d26,801c6fe1,3a21f92a) +,S(3eba0550,381ab0f9,251f923b,5c7a339,60ade9ec,2b0b47cf,25726fc7,a5e08a1c,1427b0eb,b681dd3a,88639652,5afc4e00,492a1ad9,a0c5a396,55741a5f,cf0fa7d9) +,S(96723ea1,8ce5d5d4,bf64628f,7754fa0e,e43f20a7,85356e01,94eaf8e6,bb50cee8,5ad09fbb,b9bbbf10,e86eef51,2d448aed,6cf51b5b,b28c8e8a,713066a5,81f49bdd) +,S(d7645211,7ecfb6cd,3a09d346,55d5c58,ab822892,67910f13,29f8d604,a3663748,ab7cc104,d20fde08,2c889dbe,2baaa9cf,bf2c9b10,c225da46,eebb8031,c28540f7) +,S(1f6b23dc,7e0ab136,20d907af,ad4bc944,8c866065,b4ac7e43,4dca8906,d0ada5e6,8c37b25d,6bc639da,ad092040,5daa9eb1,56041440,e48f6602,398ec256,763e247c) +,S(46ff04bb,aa06a168,79479e64,bc0e8ed7,6abb5a12,8afd1f9d,9bd80d50,75459945,b1104ec2,6af2ba0e,39133bb9,e47a61ab,e7e9d229,41d71764,91ef9da4,f51bcd4a) +,S(ca1b3c25,38888069,3b076e54,58bb0451,3bcdffb3,d824af86,f3f4a883,2a597ce2,f02916fb,dd1b6dc4,76109d11,bd9e81ed,dfc9d6f5,79847622,51bfe2,a1e0285a) +,S(c961e9a,adb69ec4,8efec7fe,dcdbdfb0,5fad1277,2b801763,ee747a10,99ece6b4,469a6c33,e0b253e5,270bb70a,d16c4b70,56bb9b3c,35f0a2a9,84e2f269,9d8fb6e4) +,S(3a2ea279,1418cc94,d3f81708,9d44e777,7b3132f5,b9b67393,ea4f28bf,939d99dc,15805143,c035d921,be217dc7,18d13e2e,b981bf8e,6525f88,31a96c65,6bf164be) +,S(416dcdf,b3a1f0be,1a3fd6ad,52fb1c03,4e24d48c,cf34d189,e7dedea6,b65a7a4a,76909ec2,bbc93359,ac177781,2132db31,47e90a0a,3c6ca35b,ebadd113,60c204c3) +,S(b397c245,9aefc175,8ba5177,2d4b3ed3,2ed9d1c4,85d2a2b1,7318545b,93c63eb3,a106a360,30763676,ab418ffc,692043ee,22813574,e3117a7e,4471ccb6,f5e71748) +,S(75c5589b,efd61646,329dbb75,5e809b2a,c1bdb8c0,d29a3065,32ef3909,d40637df,26f3e1e5,1492105c,90ea19dd,81fce6bb,95e60295,a1fe347d,cba27adf,a3e6f631) +,S(2eeecd12,a3517432,17d5158c,439a9046,e4b0dc80,119e58b6,620e6f08,969135a5,e1deebd0,48c58ed3,1b53d753,9c4c5791,13606467,14147707,806f491d,2daaba4c) +,S(a981f091,5d39d650,66b1d52e,5addda67,8cab860a,c75ac124,aa100593,9cbe65d1,4cb09fcb,7ab60293,2d98b23c,96e5109,88d4f149,4f334e7b,66c60040,7d3ed069) +,S(1a19fae3,a7e81d02,a1260c9,a759e79e,545cd869,2666b31a,9aa4c0a0,9bd4ef62,2807d657,8af25c69,e29bf7bf,d877dc7b,79714df0,68ae0707,89c5b72a,b0937902) +,S(cff8696c,1ee7d196,d76f139,2662e776,9b0f4314,99d30567,1952813d,2420c61a,8497e013,8a399690,25c04b1a,136bb816,3581f122,b62b70c1,47fc52c5,e6d16df8) +,S(6817a420,4a8b3479,caaa9582,4d48eb04,9669115a,9e5a5cd6,6cc905e2,1e27ce8c,9585468b,c3377a5c,98725465,35c8385e,8182a0c2,763226fd,95e72937,7b3052ad) +,S(9ceffc84,6e0ecc26,af13eb99,579478f3,7d114b19,59253233,bcd33d6c,8dd9d58e,e01aca1a,5cf8fa1b,67c4d4a,fef1c7ec,51060234,3ea64426,856d0aa8,fa5d2582) +,S(6a6e1dc6,f203f7fd,d9796589,2301e5fb,995a3731,8c410543,835f0edc,d3456c49,2a072b98,98b93e9e,b05f9ad8,6a97546d,83b579bf,6efd3482,f93baca1,3784496b) +,S(7e7bae1a,588d761b,5158b4f0,fb9186e8,8ba3a521,89ac36d2,4dd31d7c,d2a9129b,5198f63b,37995cc7,289e60e5,7d0f8738,17e6bbbc,d40d29d,cc4856fa,ab3dbdd6) +,S(13fc3a8,63deab2b,ed54966f,fa85e553,ffa15863,ee12f9f8,5dc5b35,6bd253,e31c3245,91275056,ffca59e7,6e76a957,a8b77c82,702e5d58,b3b5b577,73821459) +,S(ffe28deb,3f39d917,f6b6dbed,ae89ea4b,e5650326,d148ccb,becbc6d1,16e9c167,8d8a52b3,b878444d,e5385760,4e02b3fd,383c4be1,128c5b2c,262aaed6,9dbb988a) +,S(28ed423,9bf26de7,d0379a88,30fa0ecc,481c4354,1dcbc3cd,44483b0f,5cc57be,192122e2,ea018e67,4520d860,b4b8d859,2d560872,19bd0ac3,7bc0405b,10ce126e) +,S(7bf3827c,7be8c484,52acc00,eee769da,5aa4ca38,2f806d72,76c72c8b,bf8a708,925f3eee,e505529b,45c601fa,1d71d706,24a75d07,1ad29172,6bb243e8,a559eebe) +,S(cf1a7e99,21a01c3,f8ede862,71f7b6bd,2acb5aab,330a17a4,a7be1380,6fce7000,21365a83,7b3ba611,16a3e740,33a3463,5f1e70a3,f38a878a,7c3a155d,59d3d673) +,S(e779ea37,d1517cc4,e36c812,1bd0a986,af3bdd67,52626944,afcbcae9,11bb29c7,32c635ac,4b19775a,a04e2c6c,29c6f42,6472bb6d,45c1bf81,e8ac8015,d78a8a2f) +,S(10309d2b,76b54210,1599785d,6c381d52,f9697728,8e0182a1,638b7f68,f26c2a92,21edf83,4c859870,efb9b37,7f931316,f3abceac,c19b6a1a,438d020,658265a9) +,S(79927b09,701e46d4,2eb2240d,e9132036,f2b6b311,a7140701,813e721a,533a27f9,fb7c6513,a81886c1,a4c75640,36136104,8a0f47ee,b8d2b905,3b3d84ed,3b58920f) +,S(743b4e33,77da3429,9f593e68,3ce24e3f,85b1de0,4a3dd37e,fdd8c73,1528849e,37900069,b5ee63ec,7b3f178c,aae73281,fbba7de6,849e14f1,8164d6b6,742f3216) +,S(d73cd2e1,ce1bb7f,1aacd9b4,9951fe6a,e46064fb,a73acbf,49868605,c4f04da,e6a762e4,4cc6e71f,f5887fcd,6a33ff1c,cae7f84e,2f22a096,14b7f4ad,b253dde8) +,S(3e1c00d3,f563246b,3ff318a1,77b3ebf1,ba632481,47c073e8,ed32d697,95f6fa68,df2b60cf,87d5c129,1036aecb,80e381d,18ce2e00,c23fcef6,b4a72f0d,2d0776d3) +,S(96e07f90,92da1653,e5cf10e6,87526db4,ed90c2e4,c629b221,a32fdc6c,d968053c,d65c1c3b,b8a2ea6b,9ee20ea5,bfad3b9a,1f8517fe,2e5e3616,4ab20787,4dc2bd66) +,S(6d230440,26b1ee02,531cc124,b2e0796a,d27a7652,33862854,d8e177aa,afe1debb,f3a8f995,faa14689,50fbde47,1e4ec008,e3dc6228,a8cfd2c2,5983bc09,ed79bbd3) +,S(8dda9f5c,1f949dc0,314e43c4,9e716138,ad7d4511,a4b06d9d,c76fcef1,e5707781,d0563faa,7585b0a5,12b674f5,db737435,ad9d9bef,ae5ba77,5c78a582,6801310d) +,S(5070613f,98667363,f5eda369,fffda417,b4bf17fa,b4c276c4,e5aa357b,bbde97cd,b20eff,4fe77ea3,4185751f,9b16db86,eb40e47e,486a4817,8a0cf09b,dc34ebc2) +,S(3a4a70f0,bfab1456,b9b8838e,ac1aa188,4986d74,6a9b3a8e,fc792eb0,af16bce7,e4524a93,19168eda,a1832980,c04e8423,843b3e89,82381e24,8bdf5a3c,adc4f3e5) +,S(2cdcf892,183159a9,da9a82f5,4630773e,db5fba99,3bcdda38,b5291230,aab33532,c88ea6ea,c9113f32,85e299e7,42abce8d,fd95692,32292044,e0a35870,757677b9) +,S(1a85928d,f8f15f61,12e0cd6,f33199ea,2b7fed02,98c203d,781a2dde,28955c99,1b3986b2,821c76a3,fe13a6b0,30725c29,534a124,51ebe945,5682ce39,74db4299) +,S(86d14da1,d6b03065,a1520663,41b9f010,dde01966,3e622c1a,6b66b84f,1da1d388,679514ec,764f5cc9,e884a6f9,f38042cd,cfe5683e,1f6e5055,fd1380c2,8399b2de) +,S(e41f754f,bdfc879,43334341,5a5078e3,30045999,7c245441,565d0357,16201cc2,dd059641,c21d191e,dfef119f,492ee9b4,743f5e0,bb3cee47,dcbb0fdd,790e8e8e) +,S(b7ec9268,45b5bec4,79668d8f,4e444643,2946e17a,8338e2fc,756996d3,4475cae4,ab4a18b,b7539e90,10e210f5,779476b4,d945e350,978ec2cb,7cc62e71,4fdda53b) +,S(240fd9dc,f1eade19,1662554a,a25850b,bf3ecfbc,83249d4,56b769d4,b7518912,af03fa5e,e0ba3908,853a3a62,eaa6a804,5318a897,31352207,76a06b08,d104515b) +,S(353c4ec,ee7d3114,979e39d2,88cc3faa,2b88aadf,8f1cc129,a5c57237,875bb769,9fa7ec40,90af4e12,e940118b,ad70ab8e,28e607b8,5ae33cf0,2a0da4fc,d12d147e) +,S(f4eed58a,a8556688,11606ae1,1628fd1b,89340988,cbe0482d,39e80376,2bd933de,4278cf64,fe74e070,d071969c,a8ceb40d,18b40bfa,52d7feb9,1606f0f8,df3b3d44) +,S(698ffae2,e2d02660,434c17d5,b5552d4,b284f0a,736bc0fa,1a1290e,266ef1ce,1966cc8d,7845b74,1da7e53a,496fc12f,8bd50cff,b0bd143f,ab608198,e1ffc970) +,S(b53b596d,5c88c140,d6e0587d,417c8945,22d884a0,4fb596b,5957121a,65314098,ddff60b9,9befe76,c87de485,76c32eec,25deeb70,4cc19a56,77197ae8,8f2c745a) +,S(97604b21,d4393bf9,d6e4cba6,7e9f2768,79151865,9f626d65,52712fb7,1a13066a,e7aef384,e1cf7f7c,65c5b0d1,7357f266,7d871c54,fa027616,36062623,4a8d17f8) +,S(7a35c9ba,6edaee60,312b234c,1062f7bd,3b38760e,da1d47ed,b63484e9,51bb8623,33897a7b,a4546761,6ae92b58,6ef704a0,769f3a57,86ef8245,7ebd6a42,4d84a5b1) +,S(86d40c75,f989115d,ca26e0cc,9263010e,c9638b17,86707e01,b6a20d95,d1e2804,759bd762,4ffd8c1e,e71dcc8,a846b5c9,dddf2842,c4170410,c0f38742,ec315ca3) +,S(603bff47,9a4bb79f,663ddea4,93b90e5d,fc77f6e9,b2a401ce,3e8deb31,609badb7,62879fc,65281aaa,6aeeefff,cd33a02f,358c86dd,dc03720e,e1e23998,9da4f4b4) +,S(5c8b8f3,c7dc7a7d,721e0bbf,8a75a36c,fa13ebdc,14987d7b,5dee68b1,32203ed,6b601f38,2bc4c6bd,7d9d304d,88fcd6e5,3faa43ca,141bd90c,e7749340,ce08e7d3) +,S(313c1ec5,a91694c2,41e7a55f,f83b7378,25a6f27e,90090505,a7963ce8,7544fb05,9c3153ff,9a4365fa,fb644699,bc4462c5,1ed858e,24752e59,82566037,103c6384) +,S(51aca51,4616aefb,30268cb2,968e0fa0,150b4bd5,a79746bf,98b01543,a9d923bd,7c51f9b4,73a7747,bfd63ca4,f4e2b361,a0a66ec4,31df41cc,203457a7,4ee028b4) +,S(4ae8d399,27ea0648,4936d3f9,2bbe97a9,353071d6,7743ca12,2ab7b6c3,2619677d,f9dc519b,c251bce8,38ea332b,9110538,f350f5e,4352e7c9,19e677d4,3c8a47a3) +,S(6bd1c95d,3f9cb5a0,8c1a054a,884d4bbf,b100c289,c4af257b,aa0784de,a256dcca,7936283b,de39b12f,6f71fc40,1b07de78,80192357,a8887e71,39654ef8,6b803b5b) +,S(e2278a29,4642caad,ae370a62,e07fbbcb,5737f700,9ef9e8ce,19bdd283,aa49480e,43122fcd,f3943ce7,35b570b7,ed82f61d,87bc8b5,83d64f77,b36f143b,4837dd01) +,S(68537cd5,9f9469fd,d104bb01,93335830,8d24fb2c,b22471f,feef4ac4,fe96c644,765360ef,41107a51,dbf99ff3,26e3b19c,4003ab45,979de4a7,32063c81,8400050e) +,S(5ec9ffc6,69c99f9f,8f8a0735,fc088824,70be08ef,3f81bb54,b1290a07,765af330,abb54008,e76f8716,78c3229,56b47c0,1f4f1cdc,dd1cbb38,1a421397,1163b222) +,S(4e00188e,5d4930fb,a9471aba,465154a1,1a330f6,15cae31d,b2399874,704dfae9,7e76f30,282436aa,73f656dd,35b40209,5ed3fe29,d2086bba,57fbb81d,4d317868) +,S(4ae347a4,d480152e,ffd39ede,b4c2f3fb,a2659ce4,bd3b6e3c,8aaddfd5,f15ed984,383e2f46,d44cfdf,4fab8ba7,ba72c635,65bb6ac1,f35c7307,ca2c5c3,62d4e523) +,S(32cade24,a8d3ac0e,f96d90fc,86509a5e,35fd09c4,d8f7719c,603ce1b8,9c6665ef,87273873,5c63b137,5b63c5aa,6ca89f9a,266939f2,e0c936af,55c10d0a,fb8bea36) +,S(8e4ef195,60147576,6ace6891,f87c22f,20c703c3,d4f7204f,5f422444,51cfcbee,2fa72e3,89d97c1b,79eda0af,c00fbcfe,cd5b9d0c,c949c666,459706e,6ed47af) +,S(35fd575c,4adc03f6,c4d54991,18607a01,559d7316,9efc2509,aae7e7ff,a4a2c30a,f9a5779d,274881e7,cb700926,dcd10ac7,dbf3eecd,9c948aa1,3474add1,ca48e000) +,S(932e4c50,7fd02595,148929a5,2c4126c7,efc12f5f,5f5db287,3c635fed,c90a9cf6,ce6bca21,bbaca19c,29f6b1b2,4d1982c0,9e84effb,cdbf1f28,75f61ef9,ba8ba783) +,S(cad8de44,22a051c1,be36a37f,2f459707,55d3e2ad,35debfb2,11a45d73,49fbea11,48b0df1d,4f6669f2,80a41c90,34f86f11,308eebd7,8a9fd3e0,53323a66,f01c347a) +,S(9fc7d304,c847fae7,d016aa64,6cb36383,1919ffc8,fceb757b,462fbe90,6c9594d6,dd17c0e1,3bc6a187,cda9dd38,a7afdca4,1963676c,e4d4bc9e,516e3a45,d9860ff) +,S(41ba6cdf,10d4a05d,c6865453,894debb8,8300e4f7,4c17c0b4,c8935761,988b5849,7eb62b15,8c3f0965,e571e278,b2833321,ece57e84,cf153ac5,9309841f,e47ad4c5) +,S(1ff9fe5a,aef36ae6,a2d74248,cefb8693,d5bbf30d,f057e884,b227ba44,11c7377b,6ba24b6c,585c0038,49c9cf41,fcb55f09,50690850,5be64692,16520575,f1e74278) +,S(299d7c44,d706d29,e6d9d070,4856c272,6d134814,1f8f7ebd,893f38c6,cbf5d660,e4a74f3,4d0374e0,ca9b4887,76de9acc,62f7d1ff,9b494040,fc85eea,2d03ff32) +,S(a0333ed9,ec1c987,6e318ceb,83d6e93a,b607c2d,cea512d6,9f7b2bfd,72e3a67d,da7dd365,5f51769d,35b37393,21fe7b50,19f83e3b,b6b8941e,d685919,fba0539e) +,S(5a4412a2,2e52a330,534093d0,ba96865f,2821cf01,564ea0d2,e75b84fa,404251e0,6a4788e0,7e6c570e,8390bc0a,b06d293b,3675ab27,54eb700c,7cd4078d,8f0e4313) +,S(d772ec4c,3b141dc6,e534ea6,a69f9b65,783351d,c2fe7cdc,3e823cf6,32b7b0b5,bd93400d,1036487e,7090979d,ddab3821,c9ccd92f,db89bcfd,da929be6,689ac0df) +,S(949782d2,c7694c3b,ffb3e1cd,6e40f807,d4452fa4,eca1321c,d04a2367,6df89336,e7c5e67f,b8ba22b5,4372e5db,bcd63c55,9f4e2c14,c97bc930,b68d459c,bad436dc) +,S(7ee7d5f5,75e6f59f,3e0a9e4d,4c49c71f,6d9ca0c8,6177470e,2334f616,a457e6de,4462da9c,76123e66,c9074add,76fa310a,9cbbbe02,d6a07d01,97e732ee,d7d9f3ee) +,S(7a4b630a,e08d47b5,b785ba7c,15417951,8a554847,bb8320b,50faebb7,b13f843e,ca24e44f,b86801e9,7163a524,db4980de,69a3b219,7f9e5dc,6b5d7076,9d937c00) +,S(d2d90a42,428ac40a,40aa5503,2bb623c1,3a18eef3,2994f793,9c31c6cb,1aa82b96,75852e33,2367d59f,30039e06,40b1e0e1,394a3b6e,582dfb66,7464d5a3,f234972a) +,S(d92499ab,6206dfb3,da1b5606,62ed4f2f,a4809b5c,48349b91,340e0b16,e95d13e0,423544ed,26a4fe1a,8f940074,993aba60,fa4dfc64,be002941,11f29b2a,b271be38) +,S(ec0c1ec2,58875e66,d24e2d31,5b7ff87a,bba6f2be,6c6bf4dc,8d5830f5,c5d09a23,e526a7f1,648abd18,1c49a237,e608bf79,8b798c98,75804d7a,ee8ba416,28591421) +,S(69380968,835b5989,885b4805,290ea050,3a6ae508,17798c2e,f30e1009,6bba8863,71bea39d,80f0ba63,45297137,a14d07c7,7522df75,8192f345,a6170f5e,2f11e5f4) +,S(d66b1da1,9fd1637e,44cfe8d2,e1ff2fed,15a40a5d,f596c62b,ebbadc8d,fca9ab23,68cf64eb,bd2b4bb7,1ca17c4e,607b3315,5cc5d91d,26583b68,78a69476,586b9946) +,S(9dd98ca2,c6fa62cb,92750d70,c9931641,5036475c,a6b59695,a510dc88,3298c95f,55a88bb8,53b99cd6,f8d278b7,e63b31db,40750905,d98ffc81,87a0e07d,acfbe821) +,S(1b66bc2c,842cf1bb,ea4ecccd,c1e2d71,4efd848c,db7a9b92,5b9a9ade,d141bfa2,fe0b4701,55fe82b8,af43d88b,68423cb6,402b3501,8831ca89,ddb9a70,83673bea) +,S(b280dc4,8a9231de,d396a61c,2922e003,c7d2d5c9,f0e8312,c1c075ca,c8eb688a,81b745a6,a2f8be66,b32cb3ad,62babaf0,498c8261,531cfff7,da9ce306,d2738a74) +,S(7bc5951c,9eb3ba1c,828125ad,510e2e92,413e906c,f015680f,8cf1cdc5,f18a6b5d,41b905d8,480ba8bd,b8a6fc7f,49adc6d4,fbda2f0,ee229a1c,d43af5a6,98352a07) +,S(69ff74d1,2318548d,76a53095,25ca8695,11647908,dc4f2ea3,4ed2c53b,f6eabfc1,f3a3e628,8eb99f78,12eaca1e,b3adf5fd,1d617397,dcc95bde,d4be775,afde2419) +,S(5fe6dd3f,1f6d3a5,9fa8f8cd,de7f689a,ffa46098,aa0f03b9,2c552e1a,c84af209,9eeae901,acb8d022,4ed197a9,15510eaf,f356cc16,274a1aac,d6dbc74f,60dbfb55) +,S(469e9122,cb0475db,7469fafe,9c53f911,d3b52bc7,8cce23b1,21d22e59,c505f5f0,fe7487a8,38b2ba6b,f5a5825f,a4d22c26,80d8a580,9db637e,cb84e2fc,1058d812) +,S(1f4a3ebf,6b62923,b2df816e,8b30f8e4,72a5e718,70c1cc1c,6d63b4d,9160e6ab,98da1295,7602ae19,89938bd4,298a67d,1ebeebde,88706d39,b77c6a61,4dc89e2f) +,S(d8ea95fe,1c12ff0c,cec226ac,26f510a0,4117222d,d0fa4773,c2f78ebd,53b86b0f,155bef9e,dde6f293,b88bebb3,ce92c249,f154b59b,a01d7f5b,25fef472,8c6288d9) +,S(1ad8a3c7,97b38071,2214b2cf,87045300,2bb36f5d,dc7f2527,1797bd4f,1227cac6,680a77aa,3755237f,15418957,6fcf51ed,58398c5d,4d56a1c,cfa3c05f,4857814c) +,S(ffea7104,5d1d26e,d942646,9f0b0f88,355540b2,c32aa92a,3fdec318,24fa7d66,eca244e2,2d8da06c,44ec8db7,5702edd4,81f67af,2ca64ed4,cb5d04c2,2434eac8) +,S(4ac55ba3,f7fc8898,54a141c8,cfd6f675,d3abe9ba,55d90f3f,c1764ac8,b959d8ab,9c7b2b91,f135fb7b,fd252d14,118b104b,714821b4,1bd879ce,15bbc93b,f8be2bd2) +,S(5f814467,7aa9a4ce,f29de0eb,865b8a02,bc7061a9,ca525536,fe27af50,bb718ac4,bda965dc,4062b26f,e6434071,6301fb02,2b8cb894,73e39b36,69acf101,90d9c042) +,S(f372cb04,37917498,4b29f213,5981f32,da5f96a4,d1acb903,88beb154,75dd88bb,82d68f5c,1e62d500,1a0a0ea0,7694194c,7ceda2ec,e32c4efc,b2a0ab46,1a367d89) +,S(fb12bc5,45760478,36313375,3fbfa4b2,878ec6f2,243e2692,7a3c5320,bb59b128,3f820118,67dae1b5,bb5ac0cb,a24ca681,96193077,fd7bfe17,a926be5c,4953aef5) +,S(3d9759ac,918a4a34,f4307560,17a9747f,4adafea1,b0a92447,316ff819,60c0ea07,cd9dbcf,6d6a330a,b671d5dd,aa96497c,caa317a6,77bebecc,6fca559a,56018aaa) +,S(eae0aab3,699c521c,3fb49be4,669bc7dd,9f476fdf,58e42909,84455c82,fe3e00ce,badce8dd,450ee7c2,99b77b56,25e808a3,62c7ef1e,11e30bdd,9777fae1,4f17259e) +,S(fed252ee,c2c0ceaa,57625d0e,925ee5d3,43718a7d,24ca3384,55e0abed,451eb851,66bbb6ae,56ceefcc,21d66b27,70756f64,dd07211c,5cf0bb4c,457a5a8a,e82c648f) +,S(da639ebd,22ac3c1,417fb04d,3bab0b22,2362af2f,9d3013c9,bc08793a,2d7f9dbd,83f27620,55f1e9f2,fa74ed0d,536bbe54,3627aaea,3e7a031c,10aa7b4e,822466d5) +,S(524d24de,d77345af,4d4d3ac6,7c71df91,32ced2a6,acae682c,e097cfc2,7eab90dd,e4cf5cf7,c6927c5c,31b6f55c,90fe7cff,2d010a00,887b3b01,b2f7a074,fab7f5c2) +,S(7dac2ed5,fb52b60c,35c7cde0,c28617b4,28672da4,5fbc21c4,b24c5268,54ae4f94,cc6acc7a,e9168866,70b5c4a2,bd2466c2,f6cc11b6,d282b09e,a578ee0f,e7794038) +,S(5f46b64d,da61f59f,6b99d10d,e9291a,887e5d9c,a3893ea6,f7c51cbe,e56083ae,6043d055,da252655,506dcfb9,c5572929,9bfa6ba,7e1b582e,5ee1f3d9,e283a8ae) +,S(8863ec33,b6a25f21,6e641ec2,b8c5df0f,48ef0fc2,38a7f635,175961a1,7de14aa3,9d6618f3,1e52581c,2f829277,7490655b,45b2a583,da0ff7a1,17dcb12b,eb42541) +,S(85403446,3ac459ce,6d8184c7,ef26f91f,b377f3f7,3e92ea03,a1bd6a68,33a2f9f4,2d1f1296,8ac56499,b252a5b1,8313fe35,8f7719f2,3b0c9430,438f7278,c5b399cb) +,S(bf6b3f6,217e412b,fe651dbc,362266b4,6a325d27,5eb7f201,379cadd6,5e223c7f,a1160954,c14aa455,fb041e7d,ceee3ded,ebfad90d,6af1beaf,a9b1aef,97ba748b) +,S(4b20202d,3c186135,4aa079ea,409aa4cf,860ca219,8ba1bffc,77124e5a,bed9e59d,9f684503,c107c0b0,ba5d858f,2f11d904,7703eb45,510602ba,b555e8a9,f5b8873) +,S(4087f880,6d679a4b,3a24f533,127b5931,99c050f2,627cbe28,2686a5aa,6421dd2,4838ad84,b3d9d488,33c8c883,698f5a59,69880041,589f921b,5a5707d2,bd88e8b9) +,S(15a79287,cb2e7406,a2db91e0,5a4fc34,53877504,c790eac7,66d9131a,fe97b79c,9f4ef322,76572e3,d3fce497,c2c6160f,1bd597cf,b96a83fa,df2a41a6,b94a238a) +,S(1c4fa063,c0524bc4,ff233d61,bcb3d40a,404fb10a,7e222812,2739b343,e3bcecbe,2a8561ec,a2d82eeb,97209e9e,bd730b2b,d39c90b2,bf4d0353,3aa8c73d,62d48bd6) +,S(a0708ba7,43c1b2c5,267936c1,85312f2a,bb50b8a6,d4886c26,56d163b5,adf2a636,958f45f1,916988cc,6c9b8155,12e1d2c,7dc66a62,359a4324,5845e94d,371a20ea) +,S(d7960b4d,f01a42e6,e109d71f,2e33ffd,9b79754,b129a858,c213793c,e8acad7d,8caf19aa,5a841d2b,61c3d0e1,dc65730a,33566193,63118707,d81c1e19,dbdeb920) +,S(7a03dc6b,f8ba70d5,96e25ba3,8fca1b32,a7c4506e,6e8a3789,daac3240,bf8ba611,70f19e22,292d6856,5a63e378,b773e170,48a3681,d096b881,fcb84a4f,7f7d9028) +,S(53a9a662,a8fa3411,c3989850,c6c83aa5,da516ca0,726fddba,c2f38f25,c7443b97,5deac250,6179c31b,f313279e,844d1e5e,2adcfdc5,b803036e,140ff59e,3945e25) +,S(86b946b6,3dbb0d86,ffe69af6,3c1bbaa9,b7ee99b2,876836f2,a450d9c,feb2cdf7,44407783,d3d0e2a6,cb18ea1b,a1e4f133,7cbc39c0,19997a62,ed74b598,f74b1fa) +,S(ce81cf5,cb884b46,f6956726,20d2423f,6b28c8ff,ba71d9ba,bef152e6,ef752d8e,75afd973,8120644c,349bf924,c04c1aaa,979177ff,2890c926,2d0b5404,5ea9248c) +,S(41106e41,3a464d2d,9f86cb9e,47d57d47,7b791d43,133a2b8f,bc6ce92d,e1172ed9,e2ca44c2,30e920b8,5601a2,773a0f88,2ce4e42a,7379b374,d2ec6fa1,f76741c6) +,S(e9c1f2a0,4e830a12,e546541e,c7ac6f6b,bca3f1ca,2052c152,4e141b4a,20b49777,51df3843,8dd12c2,29973fcd,516712c8,5ca73721,f5d50308,86b91f9b,32a58124) +,S(8bb9e12d,c5e8ff3e,4ba25775,f1552e3b,9be21f27,4250d511,fce5cf15,e73bbf2c,8a822b7a,273c3730,1c24fcf5,c19c4de,b4d0968a,bc23962f,91ef11a8,d00d1152) +,S(b0058ef1,da227791,e4694c3e,ef66e031,697f3f3e,297d139,9ad597a7,acb6bd0f,7f5bab4a,5793814,d8c0bee6,8ffe8025,e5deb644,7d2ba978,c805b2f0,be205a2a) +,S(1dedd42d,8df5fdd6,52e02b78,4dfcab0,6dfc3557,4b8725c8,db95368c,ac2522a5,3055a449,23730d25,18ff4a8f,983b61b8,24b918de,f357654f,5b46559e,b6bca540) +,S(761a5248,c6794ba9,3f45b0b5,12bc39db,e471813d,9d5c5f7d,a46f2ef4,380ea544,185ded30,c4f5ceac,5e18d0a3,95ba8ed6,9f703408,5fad1fc5,c60d10b0,832c1292) +,S(f1d5b60,e515d0cc,8dc20982,a13c1b5b,a1749687,501a4f2f,fefab898,e3aa5caf,55fd766c,395fd8c2,173a9e4,8eb63f07,ee6f9ab7,54994708,e42ed9cf,78a0d91d) +,S(569cb44c,9b7900aa,576ba0bf,61c4455a,fb09ff4b,c30242d7,fba993fd,bb37425f,dfdeb8d2,ff1ae3d4,1e78f646,ac7dda3d,c1131de8,e2566d0,d3340272,cc350b1) +,S(3e59b69a,d99839e8,51947a78,7d8f850b,9c2dda11,7dcd0776,d22c787c,ba1851eb,732cd2a4,8bfeb030,6bdd9358,37ec4f27,7050745e,b2c9f6d4,34cd8834,592e20b3) +,S(a46d6621,7b45682,98250240,3fc0886d,81acec57,32c3087b,e6ea4c4,95296967,140cccf4,29a5b062,24097a73,f9a8208d,46147884,e6127464,51acef,b9763d33) +,S(b920e59c,f25c53ba,7c00c427,d1575c9c,4ad70efe,daeb7927,74d16c46,5079ab1c,606160f1,d4ba888d,1d5435a6,1656b937,9201ec5f,37f585c9,d43197c1,f045b67f) +,S(12cf1ae1,e7d837b9,eafda1ef,db270db6,3b88b6d9,8d05c713,896e06b7,f8bfa8c5,e0d66613,181b934b,9f23d7b,e9cfd8b3,c4c1d66d,485075d9,1e8cca69,39c99c0f) +,S(6aad27ae,a4eaca2,e60620e5,a328154e,eb93a900,be13a302,87ff39d3,8dc0ec1f,932155c5,caa21539,e27e8cd2,dc57fd7a,d4681474,342c0811,2fe626bb,94a1f46a) +,S(134cd94e,7cb166be,82b48916,6c06c1b8,8d168bf9,21f75c36,ce9343ec,acf870a0,42a673c5,e956fd45,e82a51cf,ff09a399,2f7c8fe7,e73d14c0,fab88c3b,9453236) +,S(d5dcd58c,7b7cc786,8c42971f,a1c85cee,429b1d18,dca68e2c,56d9f5b5,5a3989ee,e0ca4130,ef1bcae4,ecda0529,7a338bc7,45bedd0a,f0bb75c5,e316624e,21208100) +,S(951d6534,c344908b,905fa4cd,b691f33b,3e3567bd,1538a861,f66ac9d0,e0d8c8e,eef35922,eb847928,6681a990,345255f6,95a5f691,9a7d79f9,d575f306,ed7046f1) +,S(cedba44b,25f7964d,76d84c9c,9b521156,690af0ba,966ede27,b33665cf,c1cdd0fc,806a9049,cb8e9af1,d187b6b6,493316b6,187e7124,91a8f7d9,4c21b79a,87c79e7e) +,S(4ff03660,d1306bee,29abd39d,32beca15,d1c7d2d1,14492a20,49c6f4aa,d8a10b54,c2c75e69,8fd89951,e36e8bc8,be71f689,4990f25d,d2ff1893,d99e2773,6d1e574) +,S(c08bd508,8dbd6465,e87b7702,dfb7200,c78061a2,683b9824,389042ce,ce2e0ca7,562019d6,1343497a,b1640884,23a9f171,1db329b6,8c63e78,41793255,f88d7307) +,S(48dfdcaa,6fd2ceb2,3b85cdd2,28bac318,955bdda8,274a1e3a,7afd5db,4bf9857d,2a46622e,896167ba,5154e76f,ce429554,af60f4b5,1431d171,d55ffa2,ea0287ce) +,S(40420900,d81af883,cbf76b47,17025382,802c1479,a33a3cee,bbfacff3,16a1f236,866044e0,dbbcb53b,308f50fa,2b54255c,7831e96e,f19e1b4b,e4168d1b,7b85e3f7) +,S(96a3747b,23b667c7,70ec2018,4e99208e,ec1e3142,3b1156f,8b12f37e,322bdc42,67b0b3c8,df8c4647,3310b04b,ad325d6f,dc7545f4,a4a07af7,98c7cd86,3cf22ab2) +,S(cf07017d,e4037969,24361f0c,b151484b,f1db3e91,a8d16784,5039132b,c8460182,b7a1b107,62f29e30,d0f6e762,f6940638,e2eb60c9,e65ad067,99b1bb39,3797939d) +,S(12b5b8b2,5b0bb6f7,ad1b90de,d75fdd5b,93507aa3,dd7276dc,805cf5a,218beb15,5d3d4767,8cefa19b,80ed6368,d40ca199,5a5bc165,b3609ae,e89b56ed,b78933da) +,S(879b449c,e866e6d9,3998b9ac,e18b6f19,77ecd299,bd9b727d,cd99c37a,13a46765,b0c480eb,758cfb12,acf50c4e,91a8d9e5,f0c45215,f03e6bae,c6c13a83,63781c63) +,S(2ec48783,e9d3a01d,d1fa401d,d3fef249,e502280c,cb36d21d,d2b7b90a,cc7dead,fb029124,78f9e2ca,1a5e6150,5eb469a2,83fd8f81,6798703,ca2f0c7e,85a67fce) +,S(79cca258,27bedb07,39fe8fcd,2145956a,5b7878fb,bd873a83,aee22093,437c3ce7,ff488a93,d82e8750,14cb7c48,3eb74b30,bee990b2,2c1915a8,d3381cea,9cac467e) +,S(c444a4ca,3d2b8b7a,826b9eed,40616aa6,8e146a80,d49a9cd9,3e93cdd5,5adbd207,4d1368a9,63d504c2,541ae338,1ded0684,ac00ad0f,b8fc3231,9d1fc273,92d0f18) +,S(3ee47c50,cc0e44b2,5864e205,835e8d6,dbed328a,60493c26,7ee5529b,cff3e7a8,fa555339,56ea87b,c3249640,145e243c,b6229a30,3d1b91f,84e1ca9e,90a5f095) +,S(e963c987,3036bb7f,422251a2,9f9b0f47,8e69e2d9,2d1920a8,1c012d7d,c809980c,ff95bb0,779bbf2f,1242bfa4,880b173e,140f92d6,c7f8e5e6,18027a3c,55c52fd6) +,S(aaf6075b,b6a1b8b9,afe4b747,a46fa394,23738e50,e686c8bd,3f711cc6,548fc07d,4cdb0aec,6d11ca1c,1e85bd16,2eb411ea,53ab326e,bbdf898b,1bbd5219,aaf2b0cb) +,S(691e4817,d8e9756d,8e174a18,d5d708aa,842b44d5,ea921298,6e4c7585,4157ac0f,9eaeba0b,3bfa7ad7,80d0eb15,72f92873,4bb9a8df,29f508c2,d1ff4076,a0c0c222) +,S(c3e6fdbb,45af4a48,941c9d4c,583dad8c,c77dbfb3,1caf3fd8,1d9e087f,e744996a,ca998d1e,65ab29b8,fee07bfd,1ac4e979,b869474,b5498a73,e642bc9,608366f2) +,S(edbd6320,a55d25cf,21f2630b,e7c5c996,923eadf8,333d386,8cec00b3,940701f,d65192e7,afcef5e4,c88cd12b,fe28f94a,5e3d3d50,f6b2c3e3,f7a14243,4de4889e) +,S(c959ed83,a80ae0b8,ac2fd249,43c37412,b29684ed,9d4d85da,d7cb4c34,ea95d336,80c1dabb,8dccf252,ad8b0e97,25970c1,4de5f58e,12f7e5f,8b59a2e1,a72b168b) +,S(778cc574,471004e9,d88c9022,4d2d5cfa,2c5bc6ed,da64a312,74e3df83,3eed9237,eea23d31,6b2a1c02,7b92e502,db921d9d,675720fe,51cc3609,46b2dc93,92916c17) +,S(a1f87438,8c3656af,43f299f8,1d98d2c0,173e7e46,d3fbed9a,5c2afc96,63b42055,10bc8443,820d6c5,b3150e79,b9936785,5d874afe,dc72a84e,abb987a7,d56f4afc) +,S(c8ad7f0b,2d5f8b8a,cd9a1839,c3d043ee,8f7fa583,7540f6a3,d002091f,68224a5d,3018b580,eebe5b9a,2d1507cf,18a7fe4a,2a1cd4b5,1157dec3,8e65f191,c7aebf8b) +,S(c25d5264,b93fd7b,b7e4e426,1ae767f7,1ecf3840,a2a7ad20,bea810db,4820055f,fa15c8c7,6e3f2b0f,a29fffbc,eb48ed32,bf331aec,3a147524,c349e8e2,465ad684) +,S(d0b972eb,7e4cbfad,baf224dc,cb2d873b,28316877,88b5f2f2,ccc62bf5,e978f92b,ef5d3ca1,606a5852,aafbcb4c,f23e787a,75610b31,8420bf56,e94e420d,f7ab8e3b) +,S(f8b44c83,58564479,6448791a,b98132b6,d393e851,bbc294ab,56c8042b,1b0a2d07,c28242bf,42040be,e9851362,fc8e764e,2dbe0c01,d5bb0ed0,b8e1edfe,e870a27c) +,S(e7cb8901,6f72aade,39410adc,12fd1234,5d942419,51a6d36,8acb7c83,da5666b7,de367522,46b6d9d7,efd4ee6c,53a1656f,f0c87e80,cb0f8f63,95341c35,d6b21697) +,S(8b2128f,14e3f4aa,92e89478,64c5eaf5,f40f93e4,95cce167,fb2c7424,c279d87f,e7ed384a,f469b4b1,1812068,a830303e,699926d5,b8304c11,cbeb0e49,cf5d246) +,S(f34db5db,3cbcd586,38b6a5f3,ab5b31f4,1f3f631d,785e8317,658408f5,93b4afb,dfce7372,bb2c8466,fa31a1c7,4ffc1ac4,5bf11263,4c98ef2d,56e30fd5,c3dd3d9) +,S(c3689e09,a445d685,daca48ea,bca533b9,10b4fee4,dd251c86,a965d5c2,ecaabdb8,7804d05a,6a263fbb,c33efbe4,f4075d1f,d62e187e,3a5917a1,55c1f22f,1679e3f4) +,S(7ff995ec,f776a10d,7a66d62,6095892f,f1e47d4a,2b47ca78,d708a0cb,3f005cbc,edcdc774,5f17e430,cdca4d11,56d08288,e3911d0,e92999f5,cd5c5eac,ca6ea90d) +,S(3662a262,62234bf9,69b18351,2423ebb5,db78bd6,1cfca8e4,1c0253ec,427d4d27,88a62042,f07e69c,f40f671,ccaca36b,d550ef9b,79b4999f,c41cabac,1c2e1b09) +,S(2c127c2e,6d9c42e,970e66ee,24a07388,b6b4ebe9,1614b951,1763b414,3f54e8d1,a4773eb8,dacbadfa,afa26c8f,f4adae30,856be023,6022d93a,aae59c9d,fdd6629) +,S(c420ffa6,116f161f,fd94863a,9fe30b7e,b7dfcb0b,8cf9acb3,7f6d6515,4ac17802,e6cc469c,25c68f6c,8499e9cf,95eda8c1,7fd76d97,2ee8fbc0,79b143b,e50a028c) +,S(77896743,220343dd,58c2f06f,d3217468,34d386a7,e7fc969b,50c77847,eae3de0d,4350d59e,4408dcd9,710bcd7d,629e92a8,cd906759,627921f8,57054a4d,21fd9369) +,S(cf7ea42c,1a14dcb4,3334f9b,636ff0f7,7147688f,19133c83,dc127139,349f5827,b9c02c80,166bf9dd,139c2846,895e4aa6,ad1a689,66460a29,f8e951dd,d99e6d9d) +,S(d1793439,ab1fabdd,ada8ab1b,33c9f96e,417b1c84,7f753630,9d815fa5,a673a91f,ac13d659,3b5941b2,3b19f6f7,f9a67d0f,b429add2,5a40d05f,9bc0d1cf,ced3b3e0) +,S(bb1568d6,727dde70,c52f5863,133dc9e,54722577,4a74026b,e9864f02,9e92b420,b5654756,268d74c6,cc6adf80,ceee29c0,9e137d2b,e15aafe7,b170c95,22af3992) +,S(732912d7,83e8a5a3,a7468177,231ba93f,ce07c42d,778dc205,35cdea7a,db877dcc,d34b8388,1b128d23,e68ffd7c,29c7a945,1664f5d3,fed3dbab,6f78c8e,77df80a2) +,S(c74f0f71,fb8532e8,2c3e1865,1684d3b7,4927b6dd,22504afa,9084688c,7297074c,9da5ea61,c0bd178e,8bfe5a92,dd040c6e,35984bd4,1102806a,53a9f1a7,bd006ac1) +,S(bd4fa939,8bda5a0c,5a4e9e49,43060d9b,1785a613,3c970aac,91fcbc68,9e3283b0,631d4fed,b6614b49,459be1ca,ccbac0d6,e79cfdbb,f14de95c,5d2a5cda,30e433a) +,S(9fa65462,733f13d3,2483e0c8,15cb6bd3,e9bc2d79,7b89ba72,f2465c64,a341cc8f,7051fc5b,afc5b18d,748ada32,c4a27151,443505fc,2f14f130,10fa02e2,6a12db04) +,S(eaea6f7d,ab3dbf1e,816434a9,ddbe53bf,715168fe,2c1ebd4a,6cd40744,c35e31aa,b96962c2,4f202b96,c2080619,ff4ba905,a594b9b0,1f709e6a,76a1a7ab,9784d61d) +,S(b3df7ab6,3b947504,f33e6d5b,7b8e2553,9a117c8a,497f8751,6b97bfc5,3b17a2fc,72df7500,a35ae6ce,d6fa6265,1a759dd,f11f00ea,9152a5b5,ec51bbc4,9d758b9b) +,S(ef875ecc,46da48ae,45619be9,950e294f,4341df09,726417fa,3a8d1ac6,c3281bbf,7ab9e204,af4c05b6,d6d0eb6e,8306c987,51ced2c2,b9e8dbc2,8a642bb3,7f1c72f5) +,S(74c3c446,576a8a3a,5082f234,afca508b,3d748757,4cbf14e7,fc26f36c,70024fdc,73d57916,4ddb6fa8,72dd2afb,f9d8a307,b6ccac9c,94a4eae8,8c4fe8e1,dc136506) +,S(959c4b2c,409f2e3e,6c020493,33ba2f18,c06b7182,5a664e1a,cf33846d,cf39274,17cab35c,7401629f,b73cd398,dc5bedd,d319919f,1a3995d9,45f42f68,2c9aad47) +,S(404f0dd6,94195313,1953b53c,67fdfab7,f67c24bc,92fb4d69,a9479a9b,6c9175fb,857c75e7,f40a48d3,ab156085,1d42b037,7e7d3e79,86efd570,147917bd,f24d87b3) +,S(3e040511,233b0f5a,53df4d5a,b0854137,2db4ecef,170b566,807c4923,6ce82075,f9337271,dd443843,77a35ebf,56753b22,1fda08e0,1b790e02,b9603827,600df3d3) +,S(942ea853,10dfdc3e,1f7993e7,47bdac04,ecc8692b,94847bd3,e044cdf2,2cd77e6e,bbf2f7c8,e688b6e9,b4510bbe,58c41b1d,f33e9afa,5428ce51,e02e624b,9ea155e5) +,S(1e577a74,9883a5fb,85593809,7d0180a1,dce21791,e10b2c0a,3fe6cea1,cd03b532,a147662f,856f5e15,dba53000,7278e878,7b575612,d5dcd790,19417ec3,ac41c003) +,S(ebc9d95a,8a237b64,212e9dfa,607fe4a3,7a05fbfe,7c5594c8,ae472c4f,6ffeaa5a,39406dc0,e311a47c,cf15fb45,8f8b48d3,8fec2fd8,6b4afc05,b1747957,e7f1162a) +,S(c78eaf60,1afdfc20,2123d228,8496189,b9081637,1fb2c475,2773faf0,63cac063,95325b1,e0c22dc5,df6e84c5,16d396f9,bacb42cf,6c1fe9c7,6df83b3f,3eb42de7) +,S(b5918719,a1d504d2,b44a3d0e,117c2798,4f2e536a,3571db8,752685cf,df6d34a0,9b01e8cb,585cb7c8,fa29828a,ac899050,16beacb2,5e62ea35,6d54e9a6,18184abe) +,S(8706a73e,b59fc9d1,92907dfd,cc6f75b6,454f1045,4a5e9584,bdac978e,8e0042cd,8b1b5f56,6f1f78d6,f528405a,2b6a87e8,4265e2dd,1e34c1ce,7109286d,5bdc3a49) +,S(93e9256e,4ddb4bfb,6f4a9289,6e2ad04,793e5642,3a22230a,e645529d,712d6ca,83b242db,d9b3dfec,3640ea62,f0e3989b,d874f247,90a75cd6,9756a8ed,6eafdcea) +,S(2dad49af,8702f39b,cb353956,a1d5601b,a24fffbf,58ab527f,e9ac6ff9,ea2ac295,b5af68b8,e6040762,55c0704e,2cace8c0,ed403611,40dc02fe,2773a625,27e4675b) +,S(5ffc1899,4da42fa4,54962719,5ebe332c,86a2c364,f43b14f7,59710c54,4f6950a0,22eac0a8,79815faa,220e6141,9db053cd,4542ad2f,9ba9f63f,4331ad5,c2c9bb88) +,S(71be09bb,1832a799,c4e21bb8,a2bb5ad0,324c639c,e6e62b6e,69fa60bf,d41c51ba,c5227fc5,719a5b8f,28c40767,b54eb249,950588dc,c15e1656,e4ff238d,54dda472) +,S(4f94305,f92799f0,a64a3cb3,7df2bac4,56d661d6,44568277,bac0ed6,6a587212,4c48691f,bd8683d6,b94ddc7c,ad8d1d7e,6baf796d,6d00f344,511fc13,13c054ab) +,S(55ef868b,6fc2923e,e624fc09,65f61852,b3aeb38c,e2c6b3bc,54b86b3a,60f0ab81,ec198aea,ab16b4cc,5354d0ad,c66051fb,76cff6df,22dc1a0e,72ce6e79,1622efab) +,S(26ad5590,46e19dbf,e60953e,d40a3958,a357f6bc,23642279,cbcc355,74fdab68,af6fc5ef,906721c0,553c6a74,60bc6894,e5bb77e7,4dbc25e2,184fb3f0,fa795508) +,S(739fb43a,b1b07155,39c0b0ae,43901bf2,bc051a69,8ee8d503,84fcc1f0,ec37312a,c1223704,3c882226,2d4abe33,1de6ab4d,ff90d6b8,4c0b59e7,a193e763,6c6b7e28) +,S(2144649d,508cf5da,a7b422f8,22e9125f,d5a10965,a9d32c6c,c299bad4,6616771d,1153178c,e33c445,f03ef96b,35067ceb,76ddeaca,d9ddba1a,74acd229,d01ca76e) +,S(62cc463c,16ee8e8f,16ea8517,5508278d,4d5577e3,556d3580,ec8d90e3,bbb97072,cd294843,e299c500,846a6c91,c913395b,56b48efa,2f9ab3fc,b81863fe,8a6a891e) +,S(1196301,33edf190,d14fdb00,640f74cc,4317e1dd,b9dff1c9,707eac33,53ef9c21,f16ab4e5,e3a3ee6d,74385187,6da07034,caa4f519,6106a0c8,3136d21,5420494c) +,S(b250bf86,3fdaf93f,28f15bae,d9555287,777d4e34,2673c16,2b4a6319,2289adcd,295c05be,de343d28,87d3543f,6b40d5f9,da1e06ef,39fad6f8,28ad5ac1,39b3d2c1) +,S(93a40bbc,ae584739,9f10945a,72c199b1,27ef008,14e87e69,6f4f46f6,483e7c6c,81ed70c0,29809674,f5f289a4,5926864b,f088e2e0,af66173,89fe8cbc,aa858a09) +,S(b9e6761b,4e909d75,b17e76b3,4e9825e0,19ff7ddd,4faa9f90,eff8c0c0,f60978cc,640c1503,5fb91270,8881b70f,bf2c8575,65c75e3b,c98d211b,76279090,7b5aa117) +,S(4dc22812,fe3d9ba4,687e260c,f5b2dc08,ae454751,b022b9be,ebf4360d,10cfec24,9c35ef4a,56858135,552e986d,a4d68056,27f0822e,43031c43,5b2df5f,7f9a90d1) +,S(431276b3,1127f9c2,406b94ba,683d2d3b,e198e225,23663540,9348286c,4c9deadf,2265ed84,c7f1df86,4b46280d,ddc8cbee,c26d39c8,ddd5b743,13938c4a,e01efb3e) +,S(75c5b6c3,c99058f4,2b4b81d7,6cfaa917,328f1736,b8788360,aa810acb,3683632a,549f009f,def17b7f,70a309ef,49a890f1,4a5aaa1b,a80f0464,affdb5c5,a8f719d) +,S(3c900027,205af742,976b1a37,7a4801df,26d4d4e9,12ea757c,815ef99d,cea827d7,e28cff3,37eca7de,2387fa7c,339dab2,7a2446,fe7184c,83c578b1,8649cc0) +,S(5660f31a,3676b95f,9fa8ab0,d5c23f30,c89637bd,3a8ea97f,3a87aeab,3310d9ff,d6069cd6,6bc4ca0a,7d892ff3,e4d9aff3,955bb76c,2ba3f839,efbd786c,b11c568b) +,S(2b8b68a4,1b45dc86,7f7979ce,5b71d778,e6733cd4,79af6f61,8cd786ff,5f3babe9,7c831244,d5441b33,c20923f6,3ad9a093,840f89c4,6c1421ab,40ac52c5,8de4097a) +,S(8635004d,b817bcdc,4b357886,96b3fca0,1d369d4b,303e9290,44229cea,89c18610,2472da40,2bd46e6b,e2f84cc0,5158da1c,7e9f3512,1fc4b00c,4c3ec329,6eb909e2) +,S(6c991a6b,6eeb4f97,9b7afbde,46e1eccd,b0d39d03,dc64fb69,3a56a234,88cb28d0,1e5df74f,c2cd6350,50277188,d3eb4473,e0b753e,4cd41372,2bc119ef,65c95620) +,S(acdac19d,4283cc91,b9698ed7,e92288b8,554569a4,962ffa0c,a52a197e,9f41570c,fa536d87,523c8541,f530c6bf,e71742ba,451d41a6,f97d9afe,ea03a520,c6d7b66e) +,S(b1496ba3,f696cbb9,548b107c,3d28a7cb,85bba7f0,aeb50abb,a3e2a596,465fc6c0,77fb6cd5,727a4a6e,e0fc8f8e,ae807827,487740bb,ff5cc57a,8572ef3d,c86318ad) +,S(3fd97db5,6098e9ca,fccab31,d6d128e6,c2c9f878,adb07ec9,4d854034,d9b09126,1bd77c36,1494e374,fc45127,38b246f7,24e37d4b,27e14a2,2c0401f3,222b4578) +,S(5e8df855,f2a468ed,5476d5c4,409c7cfa,eb174cff,ad793338,8982ae2e,c2aefce9,52e73a82,3bb8ca88,a0977184,38701841,d50da8ec,c46f357a,17eb8cb1,36a6845f) +,S(99f106eb,1417cb69,e95e6fb0,a0fb932c,62021a1d,b940c661,3f814086,c64672bd,9e7fb038,e1e70011,6a926e6,a1c27fe5,e484d843,d184d533,7e9825ff,f7a6501d) +,S(686fc498,5526d87f,fd11d686,4ff0e208,68bb14fd,4a5c71f7,ac43063a,7e51ef8c,1d28f532,d793af85,bc96dd6b,2e0f23fe,4137dc5f,5b3d6244,22f60919,44588e5b) +,S(cfa5df56,cc450bca,914f3a85,b370f864,e4c83600,560bfb20,93df96bc,bff6b83d,cefb9a46,bab7ffc9,1b1d96c7,48f81706,61cf56f0,264e203f,78b05f3b,8d37604b) +,S(991b6b4c,3fbb9693,f7641eed,534e7cbe,8937606a,962a83e8,b39089e4,713e404e,3ffeba6b,be556688,d3b8a0a2,f4b92b8a,98dab79,d5847c71,13bb60ee,be3f8d3e) +,S(d104c5d3,b9b0121c,58a1fa14,f226c513,2955c4e3,56938bcd,6891bb92,13c8c0d7,8c8399a,814d7cfd,32cea21,85c77738,91ddb00,a091196a,3d90d056,b0caa6e9) +,S(76192853,a45c3648,749c9a40,719424eb,415a06f7,c74b31bc,ad93194b,e355dfce,31139287,3cbb5012,d7ebc934,52613c62,b5517b37,91475ecf,84ef3745,324ad2fc) +,S(173304a8,509c1f4,c05b1de5,c51093b2,10c7f9b9,81a7d6c8,8059fb1a,e5070725,43bfbd98,c8e08394,543db2e9,c692297a,800cdc8b,398c13d5,f9e21f89,341d353e) +,S(aca057e1,d28c5514,107f5b6a,9e46fc95,9eaccaa8,b14d4c4,6b7ae515,bda104a,e17f1717,70bd76ff,18095be9,a4b72b8c,cb00e6cd,23f6d702,4dcba433,e6bf6ce8) +,S(fb202550,e0098fb1,c30a7385,900a7dc3,85b2945f,60e6eb04,b7e8489d,3476dbaa,1aaf8420,3f72c68d,bd3bc98c,77f473cf,cedda922,dfc3c996,45e4f565,ef9a0f28) +,S(e95b710c,a0227ab8,e5b66c66,c2958be3,af1aa298,422c501c,8f879bc,e11ae7ac,e645f4e1,ab5cf4b7,da909022,cedd01f8,c745a968,d9ca30a2,c5525d50,9f97cf19) +,S(6db4525c,3589bff9,605cf203,cced45ff,ab136c6c,ce77ea15,14766f3d,e844770a,e6b7f403,f5f7584b,2331d295,82c0698b,799cd7bb,3c59c903,eb5d6848,72658c81) +,S(8893aa9e,49daeae7,15fc2959,e4db9c45,1690438a,6964a2c8,fbe73133,35085eb3,70fbd83e,ae803f3b,6377a4b0,265f62c9,bd15cec5,baec8c10,d01c7094,e5987cdd) +,S(be57f6cf,ac6e8cda,871e3ece,8aa78bc9,2cd9e2c4,8f3adfd5,6e39414d,8e0207a0,78170872,99abf89c,fdcd141d,899aa7ba,8893eedd,36bb3aa1,58120f2b,ee93d5f2) +,S(77fa6d2,85a01129,c5e05ddd,8d02b5d4,a2f69bf4,5a9e7562,6718cb54,20b34925,315bb23c,13a3d218,ce886288,ec0edfeb,37a2da99,e017b97,ce04db45,326455cc) +,S(2fed7bfe,8414dc33,62c834ca,767ffb0e,61094ad,978ddd00,b2ea09b8,d1f4dc03,14e5e8f7,aa0b3d31,565e434f,11c61b,63332a60,b6c4cff2,a6de2c5,98117e01) +,S(9f4c2cd0,5a871ba1,fcb43df2,bf03ee3f,7f8af242,ce8ee6a1,1aeac89,b4d66c6,eb421f52,f2427887,8ff8a2ab,dc384e23,d0fd7df5,fc341acf,83bc5940,be922920) +,S(53c0e0b6,824a04cc,b7203ef6,e37383f0,15f0a48b,bbc1d3ce,7c8fa7ca,5dbea647,6a9b598d,9246ca1a,539729f9,be809397,13c59d5e,105a8e91,836fd3a1,4d618cf9) +,S(dbc0cc82,d7906b84,b6b7bba5,433d68eb,bb20fdbf,7b4eefd5,c0a3ad8a,ad17d714,5ebc1f86,23ff2c3a,6f81b090,4e5e6338,8aee42e2,85306e37,a4fc7676,2dcd7211) +,S(7862af32,a3c08e04,7b1a8cbb,8131d55e,ca93a478,40c52165,af20aa6d,248f5f0b,bb5f6607,6b10353c,8a367a64,587b3bf9,7e8c272e,8da92684,f1efdc33,8bfc15d8) +,S(d3571fc,800158b7,6ed2bad8,15c93b1,f8238fc9,b8753752,4e44c0ca,931049ee,162dc9e8,3e6630aa,9d0872fa,915af449,70a9e6f9,526bf15f,4d26bc74,82a44bc3) +,S(a851c894,cebbc758,642b98e5,5df3584f,b9f531da,88faea26,e908b0b7,88589d9b,74702d5c,adfac1ef,71df3898,3ae433ad,1e1af1f9,b5fae0e1,151258e3,b375b422) +,S(a92e43f4,12effaa,e0978a08,cdb2e885,2d9af1f9,1f0931e,972016ce,da58012d,d8f5a09d,5560170e,b35d7bd1,28252096,535c687b,23bc13c6,bb903b95,d02fb668) +,S(75cafe44,8b4369c8,42e658c6,4760ecda,bb29e129,d283c24c,9007fb5,f3cff6bb,ca0e12e2,43c73553,1e2affab,51d4738a,db1ea5a2,fba215f5,3c9477b1,b55dc39) +,S(ab0066,4db959ec,2f17a233,78023b5a,c48c4177,7b6e6b56,a2148453,8c41d006,8cf9e2fc,35545169,f46762fb,940758ad,e3d3387d,eb72e9b7,b5d37175,9f5d8b31) +,S(27510ef8,2e4b2134,180855bf,469d1f0,f89b9afd,573f2781,4a1bea50,9db7ecb7,20fe00e8,86b54c06,1fe07355,5be99fd3,b0a1b20c,dec68aeb,90055c34,acfb87e1) +,S(773ff5a8,d388277b,7921405c,99c9c207,f4a6c2ee,3b59ac1d,7452c8ca,4db16d3a,cf45e631,f51cc65b,afc806bd,87318e3a,f75caf,3e734284,8d7435be,f8a52f8e) +,S(2f8f2c98,e69ebfc3,b7277e35,9da1a8ef,4293fc37,2e24386f,e14cc455,1ef45746,f85d23ec,c4dcaba0,23c3e406,604aaae8,8150a6c8,feea2c36,42ccad40,9968ec06) +,S(1878acda,ab8dd0e2,a0884952,26356ce5,74575678,64da41c0,61a83de9,6277f67f,412c868d,64e092c,ade96f05,bfa48af3,ecbcc128,e6d09bb,9684565a,d5477020) +,S(8cf281a,eac4e4e2,7ec4f3cd,d1373f62,c5a17b0f,49cf69c4,cad8c4bc,4f5618c1,2f17f995,29c9ea27,cda3911e,de33029a,7dbf09db,64ffa625,cd9fd86f,29ed5973) +,S(3a597c9f,f165369e,5d90d191,3dc2aefe,a0957936,717f1ec3,9ea20698,d08939f9,8c2203b2,90c9a2de,5b464b0,988e07,a7b48c86,f5891926,da462b4e,b00a14d4) +,S(cbe3205,96f10ff,5de9c861,55290393,b9ceec90,bbac68ac,5054facb,950ca15e,446cb06a,b76aba12,c32b4855,716001cb,9bf7c72c,ade16bd0,5472b947,4fee27f4) +,S(4313c9cf,8224e70,18413b09,e6544731,1cde7100,5ee60bd5,3a8db041,56fed594,dfaf359d,d3045a8c,b181021f,9a025208,e80bbd4,abc4a331,7ab9d735,1b329a96) +,S(cead2b51,f8d8adec,2d89651b,2da5ffa5,1f5cbfab,19fb7688,2bdf0faa,bf73c60e,ab2a2480,6992f0e8,c73e7932,2bf144ae,6dd3bda7,ed2d221b,f8451ca4,56a25897) +,S(9ce75c8d,848762f,645164b8,45ee6eee,98e34dad,9f8be0e5,2d8f27ae,4a7b79a0,e0556d4f,e11ba906,6b97c04c,8b742a26,9f627559,b9163571,d0a29dbc,9aa30a05) +,S(6024489c,621de255,f92106bf,8c23847b,10214b83,1d653a9,6ba00889,326741d7,950eb24,80a90200,ec932621,6b82e5e,abf63e08,6626faa9,b1fd8e2e,104ea858) +,S(d3c746f0,108f6bcd,406c2638,c07255fd,1f55e1a3,c6845e11,546d22ed,5f08e51d,d124dbe5,d349c739,e641a776,c57ef3db,35ed4e1a,6ffc165e,25d0bcce,438dfab6) +,S(a1eb5f5c,d85dc222,f97b9e11,e08594dd,a69c69f9,bcfa4c63,52cf2717,136514b8,46ed3d35,a393e017,76247ddd,7dda3ba0,ff5e3f76,30253b68,750a7c,f8a15fff) +,S(2b24a357,fa3ac2cb,faa5f1c6,1c14147c,e4406556,b82c7639,721f7561,485a8736,d67219bd,707aad55,1a8fd7ae,d5721d45,ad192a5f,5d0b643c,18330cd,1bd73ade) +,S(9901a1ab,9dc60159,63cc9cfb,42ecb41a,ab6a623e,62e9f306,126a4f6c,fd87b2ec,8f766594,17cd7f2,fff7a3df,6cb414e7,eb5950c1,ee265730,633ccd8f,f0339317) +,S(311e8445,5890e2f1,e1d8e600,37d58c83,28a2a4e1,b21c3763,4aeb9965,8477e8da,cf593f67,6cc75762,a1b0dd00,f6703bc1,e017e927,1e61c829,a0459056,ecce030c) +,S(905f72e3,97140f6e,298ad8b8,c8faf66f,122d27e4,6fee88b3,67a8ecc7,9e83bb77,c03f155d,bde9c265,d90b94fc,1b5b253a,2d98528a,a12e19b4,698714a6,f1b65257) +,S(61df77a5,d5940001,2fcc2f02,199cbb4c,39eafd33,27dc85e,4a3f55b,a339350c,27c88b7d,de9b3f,73b0603f,2d6e40f5,f3664020,8d6dc05f,684626a2,d9049161) +,S(e1f8e199,886d4b1d,5dd6af90,6eec06c7,de36dd4,ef026129,5bc42bac,5df18c28,502c12e9,b956eaf1,2865bc4b,ae7e6348,56a98db5,4c65a5e2,9ecf8ab7,51ca45a8) +,S(ade2f5b8,3804a21c,7dfe6a7,7044cf96,9180e154,79a4aac1,9b686076,fbb8565a,d0d65e1d,7c8168c,308985d6,f5d267e5,98a9e6f6,45715eee,3751bc26,ef066aca) +,S(c55820bb,154f972,ac345dd5,c62880b8,9f7f6b85,a1755b88,ea5821de,6f268187,911b0fea,1e6ca659,263b698c,8a17488d,4dc35f5a,d817e7a2,1241e56b,cc613086) +,S(ea20966e,321020f4,53964352,b8ccc2d2,1285888c,152ddd08,9f7039c6,6c7778b5,c942f591,cdc81e52,6abdc9bd,643429c1,66f5476c,dde18d39,59e29f26,9f4fc18c) +,S(3c57552d,9c2dfe5a,67301bbd,3e1ef84a,220c908a,8e80c707,9f9f4df4,607e2bf5,d49fa0ff,bc4a6397,3e71a0a1,7265ff65,6fd34754,ed508522,b9f0200b,e71f39e3) +,S(f188ccc6,e1043ec0,59e8e133,94ada165,a3fd5c0b,cf7f071f,eb5a0951,9bd4e1c3,5f1f371f,e53e79d0,2d6fb190,8207649b,db045c41,a2fe1cf,94486053,7bfdbe4) +,S(a0145fd2,7e72232e,8055a146,aa7bfb49,447112a2,d1ca53ca,d4835e42,c11c8c6a,7bc018a0,e5e70ccc,c4bb675,f0709cb0,ceb874bf,22c7ecc5,243e49c,3de679cc) +,S(53400de8,c221153,1fb85706,b558185,c17b7bd8,b17416bd,9c93df80,f16ff48e,e1228e47,3ba565f1,e50840b6,a36ea970,2df87320,8a66a44c,89cd33da,41a6cc6f) +,S(82115d2d,9d37e3,50ce3482,1d59af85,cc8960b4,52b99904,8c6c6674,ce64b1ac,98deaa09,659a0c24,4aadab0,3b9d1881,bffc1b3d,e9226f05,e75fb9ef,b61eb048) +,S(273d8c18,53d86f1c,c49e6e9d,450dce26,8669cb7c,3083968,1fc17894,59fe7c3c,6c5531aa,8ad026c8,174c25a2,51efbadb,14974e1f,7f7f88af,2e16d101,c2ea00) +,S(616e16,a7e38191,70e33f4f,bf428fcc,41e68ccb,5b059bfe,4036751b,ba5ee319,7dbcad21,182a3efd,b99173f5,cca99374,7c7dc3c7,3e8af2ea,ba84b0e4,f506748a) +,S(6761896a,76a39812,1f773402,d033f210,dc566610,275f6774,52c37c01,60b82812,7fdd01cf,1b40939f,8091184c,8e2c8ce5,11848df1,a23607eb,e760782e,67302c9b) +,S(77f7abaa,e97605da,12535bd9,e177b6b0,bd6eb020,92345fe6,dd4a6d4f,89e508b9,fb04996c,cc7b830d,fcf5fd19,bb7c9332,dbf20fa,10d61231,889e4b65,cc7f0b9e) +,S(c12f6717,3a2e2bba,3da97378,501f9cf1,bc4b4a8a,67b0c5a4,a0d8caa3,98bce311,de930986,44d31401,510012aa,3b6cb541,97cd133,6e583853,a330319f,779a47a8) +,S(6553a2de,19c7552c,8db9d268,ddf3a034,4afe8ffa,a76bb304,ee77ef95,c18e66aa,91a72010,7c180bb7,2af4dbb7,752d374d,69f95bce,c9bbb7f5,37377060,70edb93c) +,S(f54b4be,353f4185,22e2e936,3400caa9,bba98023,e6a3d3ee,c1fc5046,b7b834e3,96be786c,bdd5f1f0,a835afde,219745ab,ab6f78b4,577d3a5,1246437c,8e96f17e) +,S(c2d317c2,a0fa6522,bbc806e,45b4dc8b,f86be37c,4b677c64,c0d5b4b4,eadbb2a,c5710969,bd68cabb,718cb16d,fc9994a7,100f078d,4a3aeaf5,8e8eb35e,d313ab6a) +,S(52a567c6,a5b8a64f,dc74b9c9,57f5d472,cc43e143,4136fcce,fe1ff313,1b89f384,332631bf,a314298a,dd45f7d6,b8192956,d7de27e9,7d835d48,5c16f7a2,9c9e8f53) +,S(f7dc086c,891a4412,88543527,831247bd,3530f0f1,99b4c5e9,8d24a207,1dba4e20,734ed712,452e59ae,b0ef5f75,10485860,da055003,ff1067e7,b82de345,b74444aa) +,S(954f9fa9,7bb6dbc0,cbed8d8c,de6f8f75,b3f2ae51,e512cd3e,90520d8b,22ec06c6,b65b43bb,8bd9660f,4bdb3017,bb4f8214,5426f614,8f04378b,f65c39db,185dd9bb) +,S(20e69b98,41416588,20b66947,f775cd96,6def2dbe,416b545e,8188db14,2604e87e,e6514659,bd12b9b,35ae45a3,d43f6023,dcce04d,87df1f51,caa67f89,28632539) +,S(5cde5b82,2dc42f04,44187fb5,33029577,71bed484,2ab39dc3,709e7c57,c72ed1c,a0f7bad8,64e405b5,94416e7,53fd6137,cea3dcbe,7625fe41,b4929299,a9a0ea9f) +,S(b586cb4c,6ba6b0dc,2aafd03f,49d4d6e8,45b20460,5de71c34,6e73b131,fb26421f,ced613e7,c26ea3b2,a31de623,506afb86,6767b469,98bb116d,2b4ac9ab,58948744) +,S(7d3f6170,35803a82,c8e13dbf,a8d601c5,4e192a54,377e4a8b,2a2a5de6,90ba6ede,138e810e,62f413c2,fb56477,80c0bcbd,77eaf84b,e78e900f,1969f4d5,2ec6cb15) +,S(e7a314be,fc4af863,e7fe6713,5304ab81,c9fa32dd,80fa9b41,d8577ec2,8f7eb925,cd978600,f0e04acf,fa99b6d0,7da970c1,13ec94ce,c50808fb,91a44f4,80f3eb1f) +,S(179c3be4,9f41902e,e21cd8e8,10f0dfc8,ba5fc0ad,9e454231,ec090263,d3c6a577,75f9f60e,fb9b9aa0,29eb03f5,a50b7e4e,64021689,a4e889dc,5b9ff0cb,4c9cf184) +,S(10a55871,464bc182,b957808e,25754fa5,8d76269,5cf8c6f,e50610b0,91e6401f,d36493b9,6d2bda2c,e305c679,f906ba9e,99a787f2,aa8cb8b3,29516a3,41b56ff4) +,S(4a903722,5e858c84,15508d45,b31ec7f6,585827a2,f3a9c99f,96af3e9a,e88e555e,da4d45a7,fb9e44d0,cc52463f,20fcde14,31c9a477,d02c464c,70c7d132,3247d145) +,S(6d109d8c,2505808f,7b4052d6,b170ec80,c68373bb,e02f2b62,1cd29773,a96acb3e,c8dea0de,511f6e40,5141088e,cb023bff,200c870b,9cb952ad,c5038b28,eadc9a57) +,S(9c219898,6d202467,c055c734,73557505,6105b3e,2874dbf2,8f7f0c39,66e1af88,8637496c,8eddff12,f9dd4146,36565e0f,efddf5cd,52d48455,ec9fb2d,8dd0914a) +#endif +#if WINDOW_G > 13 +,S(22ca5039,e660f60,1036dd75,2bb973b,dcd104b5,dcb8f2e7,4de8edc6,c292b03a,86fd4471,1ef6b81e,4416449a,708fa0c9,cb6731ba,c403e58e,da5e915f,646b11e8) +,S(cfc18f02,cc004640,f2116fdd,1f6ca202,2e39be25,df75e27c,80bde842,e6b6f938,d62b58df,4f79d0e5,97ba2923,f708cbe5,c09236a4,d9d01398,6451d684,6290df7d) +,S(3388bcc2,3425458e,991f46ca,6235c50a,57490556,becbaf25,9d3c14f9,9a80a087,7d4aa2f8,6f65783,1c22316,6958fbf3,6c3dca5,d4ac413b,3102e13e,a645c016) +,S(d26bd013,1b8c12de,3dd8fefc,136d9f95,44ac963d,4cbcbaa8,2ba941e,f0b46a19,66f89ea3,31b6795c,6b694872,4cab492a,d045a7d,a6780653,cb10ac25,b68d3a99) +,S(dcd3370c,db67e8f2,163960ed,fef5f66b,465a03d4,d447f5ca,1d99d29e,57d1fdb9,8b93747a,320abf87,2cf8d448,393bf732,8a9eb4bd,9b64ded9,922616a7,347084ef) +,S(74074d05,e602ad56,337105af,59c63819,21d449bb,3fe0806f,80589f3f,4f8d8e7a,1a4d4bd4,adee80ad,44fd515,a1dd5236,bf0dd8f6,c44782cf,e19b8414,b03d574d) +,S(a89cc81,f3a23ebb,6a8df438,a78092a9,97120394,d6bb4dd,732373a8,2f05c174,4b6f83dd,676df063,4e5ddc9f,db979dec,326a9ce7,5707fd77,873a9644,a3c4fda4) +,S(8f1a10ba,fa913f0e,1902ae36,b07f964a,6443c540,b60ace03,7dda380f,6616424c,1028d644,45c177c3,24416ad4,e740f31d,14e3a462,d5a0326e,86998555,5de5525f) +,S(ad8fda79,14f9a236,a7957268,ada499ad,9154a2f8,478fa6d6,f4c74048,89e27b51,9ca1d2ab,1f7da6c6,f76deffc,5c3c933,703b74f0,26063834,6174e4be,320e82ae) +,S(6c6e990a,797b2970,4408cc24,6f238e2f,2192700f,e4fb3c87,4d15e32c,fd67fbe7,1ffc1798,f355659,9fa5b32c,c040da31,39811b87,93d4d9e1,be83061a,3f91dac1) +,S(202b13ea,31ad2abd,9635351d,e09f237b,9f86f75c,a340a47c,edc1f9a3,25118969,c52fb505,a14e37f4,d5111184,ebc81873,868a4521,700004c0,fe3cc535,181bcba0) +,S(5355f0a1,25142fa,b0dc7c7c,f9855953,34053c6,12326f5f,d2284291,d7b748a5,75bbe36a,553501f6,c1c8ff9d,e60ee3ef,9cddd36a,781c518f,4b1ccf17,7e281949) +,S(b8852d78,eacbdec9,d1cf1664,4a83aec2,79a39ab1,34706235,f913aeac,c29829d7,763bab50,52b3c61f,ae42735d,2e89ec3b,8d51eed0,f729e0fa,eb431613,df183156) +,S(cab2e44b,294df78e,1c17d4d6,a09ecd0d,696d18e8,b0f188b,eecced5b,7057ae2,f351b09a,501a499a,ced49607,c55b506e,de28bfad,5b20ed5,4059a068,19ff2f43) +,S(1400b9c9,9c6d555a,2bd2355e,b54b756b,b16f9f36,b9b86658,9d46853c,57056b31,8b290816,62f41167,a0a6993b,3d4211df,5709b91f,96f24436,e569c32a,dfa077a8) +,S(52ae372e,973e9c1c,687ae7a9,a111446b,b3d31b19,5588d8a5,fbec6e6,bfd9141e,f982b40d,e6d0e42d,b9638721,a4590db4,1f87cfcc,d8ece56b,71ebfe0d,82351ccb) +,S(3d14ffbd,40824625,be241e14,850dc030,1139b708,b937f2e0,fe5f65db,61899c24,b10a64fa,477ee047,4d9cf16b,8d2213a2,799882ef,d3766872,981fc761,88a1dfb7) +,S(c6f52adf,54e0c197,a8bbc270,d4c987b,e7ab3fd1,a95fe46e,82415ecd,baa48930,7524c06f,b53873b4,9050281c,99fa44b,b9ef9193,2adeba8f,77e5afd9,3856811d) +,S(90089264,bdc47cb6,7a3c838a,4c79c1c0,5f2d1dd8,6d18f55,9fe60a3e,c944c1aa,18963846,d70b3226,6a9d582c,c430e4b6,ca140bcb,91de7064,eea0fb39,d2ee04de) +,S(e27c24ea,478b37c1,6275b2d4,ce8212a5,2db74166,96f3c6eb,c1bf7091,efda0662,27ec5279,c3a267cb,fad532bb,5031791b,bb99f4da,fc3b7b7d,8537cf09,12783de3) +,S(ca5daa12,9cf1d6eb,70025d85,7955d3bf,2549b8ee,6064092b,917eff84,c40a3eb2,682d4905,500f6f7d,33e7c7c2,7d420b4b,7c4aa5f2,77b89e9e,f6a84259,de7a9811) +,S(9069ec0f,2b2ac688,46623fb5,c89d1424,6c98ac5b,4250c170,4871699e,fc877f55,cc500ec4,eff83712,16c0617e,e2407dfe,a6c3c3a8,c8b80266,975d3a56,e71fb05e) +,S(5fe1feeb,bd5ee1b,6ba742d3,c5e8aba0,536393c,592650f,b8cb1391,c3bda16c,db11b327,1ac64ed,3425ba06,8072f76f,ea02ae6a,4375daf5,3bf942b7,9865a34b) +,S(a4a91a5,f168f883,49035b6c,f90e4e0a,6bf2602a,85e0ccb8,31866c4a,ac1b2c34,5bfeea8,fe36ed1d,18af2ff8,e2b898aa,ff7265a9,c08f4857,ce082030,7f837596) +,S(f4135f36,f0c35b52,4a870505,4eaabe4d,43f5366e,d3c7d9e3,5f06f746,fa884849,1c6707f1,b8b6c078,b4d9d0ea,43075d75,ba1a5d30,c3a9c52d,d55fc4b2,650c526b) +,S(d5a8998a,9363fbae,d2b44992,883e84b8,14a504d,92b41e0f,dcc3a9f3,94380203,96016b03,6fddc805,8bb8ae7c,6d46cd7f,2f20c5af,a62abd4b,bf9b3da,ea60e9fb) +,S(8804ca34,4b30dbd,a07fb62,210c1938,d50297e7,9910dfa8,cc38b9be,4bf3d176,5b64bee5,79927c63,7788c55f,f3871631,eb65db50,b11cac91,24caede7,57d37b0d) +,S(8691c1fc,440c21b6,bc48e78e,78bda5a5,c947c74,7d098e74,ac5dbf6,2b811021,fd8ec1c5,35f51181,556c330a,f02a7110,682f4539,f66c1c09,3d48bca,d7b1787e) +,S(445fc1f6,343be2e1,fdebfe3f,894e9293,c3ee5fab,b0ed01eb,58a40637,ef093229,857f17fe,6737f853,d04aa1b7,3eded13b,c3c087f3,48da90af,32907bdb,7d85b605) +,S(5c397fde,a657d1b0,b2e3aaf9,5b88c4d6,af1a5555,a1dcf966,7d1c5001,a76493b4,9ce74820,7b6f3c75,2d736aee,6a9fc54f,ce5cb52c,f487fd32,de79a06f,df0aff0a) +,S(9b5565cb,28d7e028,361d2bc5,bdfe1912,d9f53584,372d30c1,d7e36fa4,c7fc1b7e,7d5cfa8d,2de2a832,58a57f05,4e3f6c6d,a23af075,d98b062d,82799b11,63879eea) +,S(afbdec63,1bbf870d,3971b165,71bb195a,a5229a9f,1012bb4b,89654da3,c9194f1d,cfcba749,b9492525,f9874ad1,bbb0a267,83fe5714,1f54316a,773c2453,8f27e296) +,S(7712abcb,ca3a5347,5cbc6160,5e9e9ec7,a7cc11c6,2c4b3f4d,e01d688,acad916b,7b91c9bc,eb12555,ad2b43af,8c3bd332,b57cbbfd,1ffefead,c68f0a2,6a4b82fb) +,S(3c452346,f2935e41,2e5fe506,fdf5066b,11b43a11,66e75c9f,7a2d38b,1ca2b7e2,fd3f6de1,27f96829,3af532f8,d4811fd9,e02038a,352b6696,2c608c7f,f59cd800) +,S(bd8582f,b4dbda3f,c7da53d6,70c994b8,e04eda44,ddf0b054,7d182db0,aa48b7be,799e2769,c18268bb,8c16b282,ee7d0828,ef0dc4b7,9767033a,d6de8c63,45285c68) +,S(c41010a7,8dd9dd40,62bfb71c,1691338f,befe03ea,d99eb719,74dce6cf,b2c84112,5008c39d,e71ebc22,3b1c5dbc,f824a63c,f270f807,3143e08d,29b162da,42a2ff83) +,S(e89e807e,6cf4ba27,6586a6,a509bc8f,f786bc5d,dedb5f4a,1b6253cc,2521d311,aadecb79,7c4948de,9379fcfc,4c040029,2228f9c1,c099117a,ad6d9949,f2fea2cc) +,S(363df1b3,be2dbf90,64137919,51218c34,84091f73,866f3fdb,dca1b90f,dcb08577,aefd04e,5634e36c,49621493,f7e76f20,f9ea5b64,6309a605,7e3bdf0f,75848bae) +,S(5c8d1638,83d2824e,48121322,85cc44bb,ca8fe33a,34d5c3be,cd4a3c8b,c78ea16e,f66f91d9,c7ce66c0,89500591,49f7525a,355347df,8f31a685,872aebae,1ac0456f) +,S(10ac6676,83583ed,d837789e,ed9254da,4181dd58,be75dff4,8085e87,eacbe126,6d3eaade,23f3e7bb,7465acb,c6b25af,72e0dba0,1815ea1a,1f57ebe,bb17d22d) +,S(1e79a1ea,7bb65540,44567796,2208ea3e,974c4c0f,9b61f7da,8dba697a,8c153048,b63e3d79,20a34888,68987406,4a8008eb,e07d35be,33a055dd,394ef2a5,f0787fc4) +,S(db0d1c73,97b0a23f,508df2ab,b00ff13e,11699118,11d6476a,7bebcd09,53fa9a5b,1c9d0877,3ca74f1e,d1972431,2b5c8eef,2f85fd41,6629cdc9,d0b9e328,4900dfe8) +,S(e1fdd7b3,481ece8d,266bdc22,92e775bf,96904223,e620f622,3a03ed,cb385f27,3cfab39f,28953ff7,d6dee65,83fdc6a7,d9b31f93,e2103e6d,9e4066a,970a4c77) +,S(96797134,2b69bb8f,3d6701c9,22130c8f,9ed85fe5,bf189880,3b2df11a,a223ffd3,2d43343f,630b6f9f,7c4b6d93,cd29a3e6,632c0dc6,c095794e,5997e47,e631d31) +,S(dfb40218,6e27d494,c69d2a0f,399dd480,ec0a776d,9a99fba8,cba81417,d9c33efc,332d91dc,e9f93273,15e45bcb,79603050,9bd8501c,17820f48,61f7b12b,5d37796e) +,S(6b65c5eb,ed13dca4,51608da7,b5c1a331,171de004,7fbe35e5,189b8468,c27681ec,afd0ee8,e0aebc0b,2f246b51,f6fd4f85,3e71fc4d,f5bb9f43,e2679c8e,89a34f62) +,S(bc1c3da1,60b03965,e26396aa,5d426df3,21e5c22,fdfcd004,80a390f5,28c4b619,fd657174,65e4fea9,ad7862c,422c11b,86ad94cd,35acbbc8,76ed464,aca31640) +,S(589b1d17,96d6ca35,53f8a6a8,cbc587e1,9026406,c2c6f8e2,de613dfa,8c05913a,e655d5ec,ac254f46,e279365d,e3bba2a4,3c7b6469,da45ec87,9742cbae,503fb3e0) +,S(9e726385,6d1e6c2a,94dc2ef5,c92d94bd,6ada63cf,cea75677,6125bf98,78ae4ed5,8c238df5,1e5b38f8,b628a48e,dc7aa2b,a83bc40,43c91896,69f5341,60e304dd) +,S(12269d78,14e0f74f,ba40c551,b2080e00,4f9bd3af,255218d5,7eab5dbd,c6764263,f0f70bd,6584975c,106febcd,bbd16920,daee58c7,c22dda70,4a95f864,e385b3d6) +,S(d3212f2f,cc509014,e0c48cdd,6273effc,5c73fdbf,1676faa3,15e9173b,573088a6,39af39f1,673f51f,362618c8,49c6934c,ff59b6ea,853fafc0,9db64084,4832df82) +,S(c535f72b,9bcc0bad,44014e72,4f649623,4ef288fd,9f42adcc,dae45a20,84250052,3f79985b,6fb7631b,62814a17,f7ce829a,88447302,293000a7,4655c7ee,4a271022) +,S(4f5b7126,9b169fa5,8602bb18,60ed0df7,271e3912,ec0d7c12,1c80fad3,93399605,b60fc104,7f2a58ea,9102c6cd,b97c932a,576f63f2,6204fb5,dbe41363,cdcfd0a7) +,S(cb459b3b,244c38b1,af2c2863,e0029c14,ec70e7d,737a7851,de9c8f1b,b7d5d065,7b67b15d,3c0376c8,2f646241,1e890b3a,a888bd15,692c90ea,53a74a4f,1957fbd0) +,S(787d61c7,ebde0c5,18f121bb,7f434196,d389f563,d1a46597,ea72a1fa,4e19054e,5baf56f2,5fcf8cb8,c271cf39,6b3d150b,f42e9ebb,d72b54ba,4b93bcbe,ae72a658) +,S(c38afc2a,31d0b0c9,4b77d97c,bd639082,3373538a,602352ba,cc93b6eb,c5f6115c,b925dfca,b138fcc2,4b9a26a4,c645f8d5,875e098b,d2e58469,d842688,43ee529f) +,S(37661e3b,8e606e95,b9dc6ad5,e5b9b25f,39a5dd0b,8ab7a82a,d6ec879a,ff406d0a,ab735e5d,430d8fce,1317e07b,d6cf9441,60d8bc39,132382a4,df1b1638,a7e9b977) +,S(e5127851,b8c22b47,c3d8e934,8dc0c677,88ea5ad9,f64e6062,abd68a16,51e256ba,5847f77e,349eb7,90b4b7dc,5537ffa,5b1e7d4d,b87044b3,f947f387,270405c6) +,S(f3c7f45d,a6b8a8a1,3713e7cb,7380fe06,127a3698,520bb41,955647b9,ad7382e9,2acf9a11,eb1b9d31,f71decd0,90093677,4b469301,719d4a51,ddfe5fbd,f63e7c87) +,S(86de4047,e8d5b252,523733a1,848a990a,79125f95,3bb0e4de,ff4b2f0,84d745ba,71e6a472,dac005d,2b284cf7,d5de92d3,56921105,1a9ee007,4279a746,71bc969a) +,S(c6115c30,72259d66,d960cd96,3f3aa16a,3029d9ca,c0c5ec63,5e2875c2,f3f57504,18d690d0,b33fdd78,d797f56c,23c821a1,ced02401,3443c770,50d12850,9f7a712f) +,S(cb545099,8b43473b,91838cbd,76929b05,8bfae0f1,e2bfbc6a,c61d3674,42f53c5b,4119d74d,79e34f08,cd7684b4,f9b9df55,c00ba8ba,7bfb4ddf,de38db78,91572bbf) +,S(d0dce704,b9362bb4,fb1771e2,660a98a2,a333b73,c6d09372,5a752f28,52922d2a,f92c3b70,7947ce0d,f1f3891a,259cc2ee,124d3f54,a4c518ff,de5a3915,96e37e47) +,S(db93e238,e5aa5986,38eab857,655cc53,d4270259,e7d73a96,249a19bf,216b20a4,8d19dc8b,670e8eb6,50b4f60c,d26ef657,3ab17895,c62fc94c,815d7eb5,fbbcc7c5) +,S(c387c37f,d8cebef8,29e07e54,b0796129,4d6c6cfc,bbf11835,ba85d4ef,68c3f486,852580d9,ae7eb300,6ca0f7d7,f12d7fe7,c8e3ae0d,b6258897,994fe78e,11ddeda9) +,S(ebb58d34,f04de551,37c01b5b,192bb4b6,4d3b22dd,23ad9092,f943749c,7606c232,1b979d05,9c99f9d4,db1d3e82,905abc9b,d92ae72c,509c912b,c59488fc,ddd1ae16) +,S(7891cc66,acfda29b,765810b1,730cad13,2f13178a,fbf238d8,2525ce42,96e38e6b,22193729,20188c6c,462987ad,7ecaec3,a21ff6e7,db00adb9,72facf65,367caaf1) +,S(c0b02542,e4bc1e8d,2c2578a5,3793fd8c,acec800,c0a311f4,72c50de3,5814d081,24bdc71,f5917c0,1ae6bb5,71c09197,76b1a884,ebffd673,13698bc1,b57f8371) +,S(ea15d574,b8704507,f12fd9a3,e40ea603,c2000cf4,4eb3d4b2,f07a36b5,c426d2dd,b6596d4f,4d8ca39f,4e0faf58,ab7e3894,c5cdc16c,589a524b,6ca25a51,8a30944e) +,S(77d387df,c35a6af7,b88d5726,a249d34e,70877698,1358c672,6e51b779,cf9604de,e5daeecd,2d70a962,d2d3c235,14fa2b1d,45916506,de017249,93fcd9a4,f08b4a87) +,S(a92742cb,7d1a24fb,c1a4dc2f,9d6fefbb,1064f9d4,c3152db8,3296a9dc,9dccd7ec,665a9cf9,8cdaf0a4,ec346df6,823f3c6,66d4f163,b3e7225a,d9d18e42,31679f76) +,S(253e54f7,9f0c393d,5d34053d,37b55304,f62de9da,29e0eb6f,36cb105f,a6316a46,54e168cd,ed78ec0c,32a9417a,c5b27ef0,67c8577f,8fe0bfd7,b2ae33eb,ce7155e0) +,S(d13048e0,e9c38720,6179586f,9e38029a,55fc01c7,b33d8443,4ee45cc0,3fbf2,7c4466db,94502477,85490689,7b251c39,af257840,b9bc61e3,64075080,84743f37) +,S(e9234110,387c2122,2887d079,7bdbc9aa,a632b237,2a5632c8,8e604653,70a284a2,2b98b08c,4ca3521b,4ffb3afe,66f98ed9,839a2651,f740f63a,e80b0cfb,6f6523c4) +,S(302e03a7,ab6978ef,73891a5a,7bb25764,7428341c,94f8a713,32ba9dad,83a29be5,4abe0adb,210c35be,b2ee850d,2e56bb3f,e8430db,644082ee,a98a2f83,5710120b) +,S(53701389,44400f30,dca0571e,eb0f8c7a,4fea8bdc,31d68859,8d7cd156,11665368,ca345664,39c1f221,a5731bbe,5a9a36e1,a712e2db,f16a6d19,71b1a74f,eaa97cbe) +,S(8c0e8186,645d7cb8,fad2b6f7,a5a2d399,656aaadd,5423cff4,9579529a,f28383cd,2ef275ea,14c44981,9307319d,18fbb482,63c6d24e,c94e18ff,cdcd7757,4c48d27f) +,S(64a70831,26baa3c9,a11615c4,5ff8ca99,adddc512,c697901d,afc43d7a,5fad8af5,ba43c48b,59a65f6a,c3a45c35,4bb17968,148efe4a,288f742c,43253e70,aafe29d5) +,S(fdbd066e,82ff8e24,b2f785e2,e166245f,63559acf,b4f56680,51db47aa,5d438e06,60dadcf,a19ed8c2,376a5d38,28b9499e,875731d5,b2417def,144e2a84,12973d63) +,S(b287ccb8,1ff90731,19ddba01,d9461512,82cf15cf,2dcb3e0a,f1b26f41,eead174f,6ff15339,7a9a0bee,4b38a463,5db66ed2,36d1beab,c0039bd1,acfbdc09,fb74e090) +,S(18047a48,b65234a4,fa5f2188,8b3032fb,3b3f8457,1bdec3c,962d5cd7,fd068116,13627669,18198832,306c5444,6cea5681,80134209,101a117b,1f34e15a,624574b) +,S(f1d3b54f,be4e2ce5,88a2dd32,8a41e136,6b74ffe9,5bd4aaae,ce7e7a8,235f914,37c25d41,300e817e,b4ae1471,e8486232,c0c21165,97efe33b,e86d6277,a8a3981a) +,S(9b0da9e9,5046dfab,7ff509a6,10ad56d,9770da36,c5e22a83,9ce3a36d,853bec4a,27d60345,30c25a36,e80bbc3f,f43829cf,df757c19,1a2924d9,6da77503,38135faa) +,S(d0833bd9,5155d18b,be55d40,3717568e,2d3e4d24,f2eb65f9,f13d8d65,d899c5cc,e509aec3,b5044ab5,11fb1e4c,56db7146,ffeefb82,ec4e9de1,3c473bc9,964741e8) +,S(8c41627c,185f17e4,28a01b40,27980e6b,ed62ad62,17c9f8a6,26c329e2,2fc37117,75ca226c,3316a552,37e8a1e7,483f73ee,a36da441,c732dca7,7d95b7b9,3a3662f7) +,S(371f0105,e43aaa30,5cc7099e,9a13b97c,2d75c26e,5b50b11e,7cc6283b,27728d27,c969dbe7,d0976d68,8cc64312,4538ead,b1194426,cedf149b,293b80c,6ab3ce99) +,S(5102f59a,4238a358,f8b4d3a1,85d864c2,d94aeb83,7a8f3e03,541ffbdc,2ccb1710,9e14c4f9,adb63c3f,4cd30606,cd41cabd,bbffdc3,89e996ce,91522093,85ef1445) +,S(ca21b6c,fd40403c,78353c7,836162f0,a7f57eaf,bd4a8cc2,6df2baa7,1ff08beb,108a3c46,47eba55b,3fd9f2ef,751edb0f,d6b68482,1424bffe,e6ae3e58,1f7f12f9) +,S(d9cd44b3,ff40d19c,e8368bc8,200e3dc9,7ec3642c,acc40769,7c94e68a,31d775d9,b6b6fb6c,683ef701,d4cf7101,79de4af,fd7c4a1b,5babf3cb,85c95eb,485f0901) +,S(9a1354b2,cbcb6888,bb564426,71bd4904,510da508,3fcc61e1,4fbdf44,15a10360,3f5f5291,707c48b4,4da3a2a8,93e24037,bc4927f3,81dd9b9b,710e8b82,874f953a) +,S(c5e55e0f,271a81c4,ae7deb0b,ceb0fdbe,20fc60c5,38692941,bd50ab9d,ad0fdf79,138a0f35,eab49301,7a53e7c,c62ae93a,85ed9e7d,708a00ae,cb10776f,fdc83a63) +,S(5ebc2f64,7f66bd3d,2290e4dc,6cc5f662,7c67ea72,599d2c6,9a004aed,9060f919,68f7dbce,df2085e2,27cf7920,65369637,3ec1e860,b10c8f1e,56e996d6,854659c) +,S(4f28eb9c,7d060dd0,5051a5a7,9a79c960,161d7081,d3a58b2d,a421075c,cf966e03,ec378861,5434741,bb2aeb8e,4a2afe78,44849f3d,2cf12a6c,2eff3e05,d267fafc) +,S(f50e20d1,ce113e09,850c7a9a,10b347c9,9fa039ee,57ec85c0,efe15b4a,1a83fe8f,4db7c231,90df41a2,8218595f,61407f20,cee46478,27d54aa9,4db9bfc3,fae975be) +,S(cce6b2d0,1adeab95,dd78cdf2,b55882bc,79de945c,d4249e76,ab2841a3,abeff5ef,1d690674,1312140a,fdf764bb,560b1bd5,bab1dbaf,9fa26bd5,604427e5,34626e52) +,S(55a65174,fb10557d,2ecc7312,15afcec1,e4830be5,2d34bbbf,bc80ed6e,9f2d8475,c69795f1,de1e537a,970dd412,65493806,3f0623d4,e7353eec,611c8917,278012c0) +,S(78221cfa,7b4db3dc,7e22779e,97ac8d46,d0c1d819,76594ab0,267ed28a,6127f290,8ddcd5ed,fd8e8c62,4883a158,2eab5652,ace0660c,2e358b66,3ad53e90,cbc46a54) +,S(9b985039,441ee434,ed4da39d,6010782c,9006cce2,8f92ff96,2b2d6fa,986ed178,e1cf85c8,7b537b2b,78bf67d2,2d9388c2,8a50dae1,73f003bb,85fe5f9c,12c6cfa4) +,S(9aa2ffb1,4a9e48de,57db9d78,d9b6757a,6c27e7b0,291dc4f3,8ae9f204,f7edf20,771c7be3,78e0f794,fe0066ef,8592952d,8f80d7d5,2772ca11,5ff8b7f6,377d1040) +,S(d1059083,66a0b463,17c510cb,40922a0c,949de251,6d80ec02,1e359a89,c6937e1f,84053a25,c9ea4414,a897155c,c45e0da,e5e6f2f,aec780ac,99c41545,fac8630e) +,S(1f3ecacf,7456984a,fedc2d81,2a81f7f,1ac58ad9,c70ba7c2,3e7a2ff1,f9c5d066,c6add8fa,2bfd24f1,73f4539e,f21681f8,15f1f362,e0f98d94,cd435d80,71a23e54) +,S(a312c709,a16d0cad,25551ece,86c8f947,5e504d06,eb3524fe,569cdca0,da2c4371,865ecc2a,ea04c5da,2089ea2c,66b5bb84,8c1fc29,ac7bf969,c778039,b3ae7b03) +,S(f21c4675,e829ba78,fbcf6410,9c2eed38,8c3493db,1017d69d,953f32f6,744197af,fd2c673e,43377caf,5db0ee06,1a37b03d,43d9373,482d3ef2,b37f74ad,98b2f57) +,S(116174ea,2a029a02,fbcb2eb6,1851ab31,f4836933,a73bd426,8feed7c0,18865692,2123d027,e1cead9d,b5fca2a2,d6f5d1d5,25cf3855,44b64352,ee772d4d,d70aaefd) +,S(358e77d0,919e4c6c,f64a2117,357e72d6,2334fcd0,f5e7e60a,962335fa,73f9d663,7ef8d620,6f99f403,10781985,988ac7cf,dcf5cdaf,a086a0cb,8b5b6eb6,7837bc08) +,S(509f7e0d,9e81f146,39157e20,3165faac,8056deb3,a813460d,b86c6daa,baa33fa9,55148e1a,340eb6c4,e6a8645f,93f1ad3b,fd12165f,c3bff090,a095b8d2,a0db6ea9) +,S(358e325c,185f0e26,1e9e30c4,9346f21c,a15c95bd,438020b9,ad9c7e6a,d2a4ed09,5fcc074,c97715b2,812ef690,3b3d6185,54aa11bd,34789b3d,97f9b65f,2d18c4b8) +,S(1e1c712d,bc00af2d,37f37e4e,a2589e02,e314c310,47890d26,8d36be3,dda2fc4c,4898f9a,e3136bbe,36798cf5,ad30b38b,974e7e75,42d4c14,5bfb1f6a,490655dc) +,S(a6516f9a,aa3f79b0,ff3b794d,c80a9590,64e31720,7361b918,bd797b57,23ffcd1d,c5934c6b,59f3b830,53f77b07,47c7c312,812373dc,ebdbcf9b,ed550300,3a54f5d4) +,S(e46b48d8,8b1e1b84,b9fab824,3044469,50cb5633,da599b79,295011b8,b1098155,43e9ba24,4a339976,e342e551,25974350,3e7c8a80,cd950a80,a5d79365,b0c94f51) +,S(ca7a5099,97a9c2e0,625105b,1df9e714,e1cc2d40,1227400,e583370d,3f65aa0b,dd8ca4e4,d2eecd1a,20d994fc,ef7cb0ef,19c61844,cd2ce039,b7a1eafe,66e1f071) +,S(326b5ec0,d29b576f,111352d4,b7786c40,8486599e,ec01ed0d,a390d586,96313f08,f4a3f171,a4ac654b,e7aa6063,3d5b2a0d,c2d5d3a0,3da4d264,95e828a8,1011d384) +,S(b762982,54f5c75a,a557038d,bfe9bad9,7c5bf8ee,e512fe2b,39293228,e70d306d,8b808f9f,b36e3e86,2c75bb2d,d7de8be,cc85c75,398496fb,f92db3db,143606c5) +,S(8bd624e1,2b1d36ff,dde50a09,6f1a811b,ae66f1a5,790654f5,ef79a21b,872286ca,6687ea2e,f4538961,b6731c74,744234af,8bf6a2a2,170544d0,fe9b8057,ad1f02df) +,S(ed25eac7,2a9f9290,bd414cc,cf846c65,509d1c33,d5573da4,2d78d25d,5de48a9,556fa9ed,2710fd03,b6d1583c,682cd7bd,8705a9d0,1f73a8b9,8f3a1eb5,d89eaa) +,S(f1943b6c,9ed76a84,9c67bc94,c755fb30,e8facc1,de280060,df4b9e7,8bc02bf,98c7ba08,85dc4e0f,6acbb646,42cb876f,a3156232,df1f84b0,4818ca56,882a40a7) +,S(c5b60b14,2de3ab8f,b0c24276,dcedae7b,83422821,6ac8ef39,1d351832,a5e9e5d3,ce86e4da,1174e609,f55e10d9,14d4a5e,33259578,e07c1260,e912acdf,9eb5cd69) +,S(b06638e,706cfe63,3359647b,253f99e1,c7778200,c168d4f5,92e2c409,493755ab,e6401fab,1b4d5229,136e2493,39f95357,e16dd37b,87e7f69d,3e88a383,cb44bbd5) +,S(cef8c1b5,486dacfd,29650ea5,432fa563,f0ec5fe4,6814bcd8,9f539b7d,264b14cf,80cc2c1,8d0b0be3,939ea,761d7281,5ed4fd2a,b252d66c,9316aac1,1a5a2fcf) +,S(f616904d,f868f2a1,5fcdccac,4198b1c1,62defb40,269754f3,8e546da2,4b85d7ce,fb971012,344024c9,f0bb93e0,b73b31cf,de8b4d37,aaeae3e4,7f62633a,7b8255b3) +,S(97386144,bc7e4a7b,33a51697,902fef4d,1613d8e5,ed80a599,a59f62c3,f98632e3,bd12d584,58429939,2dd834a9,5431af27,8e56065,ba79bb6a,5a806d36,cfc16b4) +,S(946f130c,7a70fa00,f403a56f,6656b279,1eb08ddc,561311b,551ce437,bb0200c8,acd698f6,a5037e60,7f5a923f,3af05784,186d9794,a7bf7105,7a66949,e1945b8d) +,S(ee0cf184,72c453b0,c38c064,fc0d2589,d5f1afc3,3423687d,91740bdc,c3929230,d817775a,7fecd397,e954db12,fca24990,8c773c28,b36e991f,79c78264,9fff8dc8) +,S(f335f7fe,9542a587,9d48b4f,4ab1287f,ef007289,4d93bc21,23463a77,7d535d7b,336e49a3,2465d29,35389c06,d8eafb4d,7639dae9,a6b19bf7,45518502,e3350283) +,S(55bf8179,4fb37f8d,dcc200d7,b76a9040,b1326d6c,559d7f06,f0eb0e0f,c97e7739,ca33cf00,79155cc1,e902ade6,f7d703ed,3053f6a4,f49d0866,32e930a2,afe69bfc) +,S(dffccf81,6143da46,5ee2195f,abb6d943,1033b901,2fe0c623,49b7d6f6,29de29b0,9bfdf3f6,e1dc4ae7,dc29fc06,f85e1588,c04bc39d,5fded90b,bfe75b9c,74f0aff7) +,S(b9748c94,25fc6fa2,fe5c1395,b556bb12,c435bc11,2e8f577f,3c5e7d82,3539dec3,f5238bb2,b995d23b,5e96b233,6d5141ec,f76d31bc,63aa96e3,dfaca8a8,c94007a2) +,S(92c43c54,e951b157,38f29e33,5f52ad9a,2c5349e5,fa6a39a3,fb615878,ae97f7ca,7c7a6b73,dedd1bca,308924fc,6364b62a,bdc4ae79,d68a62bf,71bb0195,612b4a17) +,S(b1937ea,25995e55,ee1ef139,d7a58923,5677afe9,f4726d96,40b66b0,d21eb272,d0f95a57,544ac7cf,e6c3e0ca,5e44494c,5585c503,a8ea9919,5a993180,cf043dd6) +,S(2c1cd64d,bd7ee24b,2bc5a6b7,2009b788,e2a5047a,8d10dfc9,4a46d807,c133f457,fe8a63df,ce7d7a4b,e7c31a1f,5e68826,7a9449fa,9e9ce30c,fd8684b7,660aabe3) +,S(4ff10a78,be6ea8a2,b6830649,b0a403d6,6d544368,6cc854ed,447f53fc,45004834,b3cb30c3,56d50596,2e81cf5b,f4e2db0d,e43384d7,28f5d8bd,b362d287,e58765d8) +,S(33f55b66,6c90665a,b60a7c2a,c714591,f877e8c8,517344d,9da03558,f43d28de,399848ab,6aa95ed5,8ae0ea80,c93931a2,af146754,385edce0,8c2a4f64,2d5163f6) +,S(b9712359,5a7237eb,18b7cc15,ff2d6be,408da66d,5885a636,20887ab,340d3e04,a283a3bd,643ac5a4,1b3f0ab8,fc693146,dd125f88,fa87cead,817788b3,be72363a) +,S(d20f9067,6efa9435,f602c1e9,fff7338f,5a4204a5,4d984dcc,f0ba5fc1,60a1035b,ac3a3c7a,452003f8,7244406c,ea315175,ca1af26f,6645486f,3faae77b,8f404139) +,S(322d6ea3,157c9f0d,444b2d0b,d072e192,81d8b3e0,3ee2ef5,4e294b53,fef41f2d,838147f1,9dc12dde,676a9e67,6a638c42,6e096df6,ea62ba97,ec359b4d,f92936b3) +,S(95925c08,68341b6,b7564ea7,bae00b0d,1d2bfacb,94aae4cf,8f29ed9e,fa0c26d5,c63edb9,13152232,c255557b,2207c2ec,edf14cfc,bdd246d0,2b46f7f8,76b92130) +,S(7592aab5,d43618dd,a13fba71,e3993cd7,517a712d,3da49664,c06ee1bd,3d1f70af,554ee877,af74284d,5ac0aef1,ccfa8ab2,7a9222ae,977a1b45,7d79d386,16eaa410) +,S(ed9d298b,e13eb71f,8631ad31,1b391680,8062574a,6053f503,671d9a59,1209e0eb,97a9abc0,dab8886d,9a07caa3,f40d87d,7b479efc,d500eb6f,e54ba1b8,9d85c3cb) +,S(cdfef636,a5900bc3,bd28daf3,308d469b,78ae69a2,ffc39fcb,9f8e4942,fa355fad,f8338fcc,54c0ef4e,a46a1c25,591607aa,f4f6c7c5,378f2d51,79f80e46,520db6d7) +,S(f638cf22,ca3bd6a,ca7a8fc4,26d9f5db,dbc0943d,6a587584,8ca52e6a,7949db49,56a267dd,8309eab7,90b49003,9d595141,653a7926,9fd1f732,f3691e0a,41675295) +,S(4340fef2,9b1e43f5,3c76cab,163920b3,7a66163a,bc942e1e,6387a2b1,8f14bd1c,2d5a782d,6889d353,c6c908f0,b6f7a9dd,59ff2f15,8bbb9eb6,ad62bc2b,832210a0) +,S(78af8680,5e3db13,cd2c01f,beeb826c,1aa83296,c6ed1a30,bf2822f1,a9b80991,19c7ca36,37a6ce91,2680d95b,6b94f835,ec458cdd,86206a2a,49d41af6,248c3725) +,S(d87e590f,e6a4bef7,54a831c0,13b3d561,72064279,38b96d49,58a2ae11,c9c41ef4,3928a93a,c9b43489,f1fff97f,f8ed4ebf,53b97aa1,b50896b3,e30b40b9,be1d1dc6) +,S(b59d19f3,69c547e9,4155cfd0,a0b9076e,85ea8569,195b8a7f,630a8446,ddc54c32,b8f5588a,ffe7abe0,e2b83d55,28162c5f,2d50827e,c44a4357,f81ff085,da661865) +,S(34f643da,7cd59b00,3aa64cd,81c143ab,662726bd,5eaf543a,6d83d30c,60f3ee78,41574cf2,91a7f573,5a0bd29b,3ee5a36,91906c1e,3fa47b22,d5204446,f4501ee8) +,S(56ef37d0,583e9de4,33f78757,dc31c968,fd007bf5,6b05db4e,cac395d6,233dbbf3,a140e01a,b5c898f9,10ae2807,53ba14ea,ba8cb5df,b9e9629a,92c14b9a,df5c9286) +,S(1e43f34,815b568b,1139ca5c,b3a5dd42,fc54dd76,78454fc8,7e3dd00a,edc957d7,5cc38274,ac96ee20,78a82d9e,64dc2bdc,8e947afa,d043302c,85d724f7,7e334cc8) +,S(ce79e49,35d2db7c,d9a9046d,3d81b7dd,f8b06c82,98f78eab,ad93062f,c339a952,fc2f6eee,1b90626a,5ad8c494,3bc3cf5b,8765c8f5,fdc05dc7,fffa08a1,b84f9686) +,S(b4144804,ca862c26,70cc3365,e1a00cf8,f6766cc3,4b3dce2c,76c40c31,86fe4fd9,e4368a1f,ca9b6e00,a3f752f0,3a00fd4,29cbdaab,5e2a04b8,7175b9ad,51b2219c) +,S(eaa29724,7406f824,8e79cf65,ced49d39,5416341e,c1bc46a7,b71d422,1f4fd39f,68e7f81b,e3b75cc3,de4d9932,85e21842,d0d4b6cf,38a1d46,248dd28b,a97c14a6) +,S(4e2d10ff,1f7288bc,3b8c6caa,3dcbfc72,eb7371c9,f42c6999,e7a2ec50,30f5b6a5,68da3c5c,df2a4fb0,a93515ca,3e417d00,6ba793f5,eb678f82,be88200f,a5a8774) +,S(834f21e1,114dec96,2a8a4b45,c67c2894,7d073b94,457c1adc,e009dda2,230659f1,e9fa61b6,edb5a0a0,2f7acb27,d04a67c3,39263adb,6320ca6e,f78ac7fb,25adc89c) +,S(a84b44ac,a0a64455,a97268d7,cd3d68fd,c43caed9,f9bdc381,ece7139e,30c7d0c7,2f903f3b,74e702bb,d2fbde43,f919af7b,d1267879,3882cd6d,a05af259,bbf6b74) +,S(21219e06,98bcb977,47b1df66,f9e0fa6e,600cbe7c,bb432cbd,d413481f,241d6789,7a4388d3,c8961874,a897d968,8b5d3266,2e6970be,324bb736,aefd1892,70954055) +,S(fa514e1f,93bfccf6,88b4bbdb,e4f49879,7b946549,82a27562,6867b22f,9baeafd4,ccd48215,52572b4a,9e087b51,8c930e09,2c2f6156,c26a730a,478f257d,a4f91b74) +,S(b60afbf1,643099f0,c0533a4a,99bd8c2d,2204d4f5,3f2fdffa,4cafa02c,79451ffb,fed8f90,1a029926,cd4b3bd2,76bda6e9,d321e006,3eef3f43,886eef8b,4b21294b) +,S(f29cf9a3,196ce34a,86efcca6,554694e8,17c2b765,39c6cdef,c74850e8,a7ed76cd,5130863a,f7c333cf,b37f1bf6,2db5bacc,994b2977,9951e8f6,2471129f,88c9c5f7) +,S(9cd9e23a,cb00bfc5,1a3af34b,3e23f1d,d8fe314a,322254ed,563b9275,c5084e4d,ecf0235c,c66ea710,151d6c1a,17b31705,4f31bd4c,f8d2a77d,4d36fc4e,1298e1d5) +,S(56f889b0,2cfa048a,f96d99a6,be56a282,18ed6691,ab2b25bf,f3d3b6f5,f6e5d65c,352b20ea,4a2372af,f674f824,8dc8fca1,bb8ecc29,ea0c8d92,1b7ea07b,241fe4bc) +,S(de32beb7,f8fad8fc,16d69a7d,d3def556,8e2366e5,246bfdea,16c936ab,5dff2a08,d731f11c,93a71c22,46c2bd06,fe265fab,eaa216cc,b0de1acb,a7c004d4,249e145f) +,S(85ec7dc1,dc1729d8,c03dfa58,fefaacdb,7d12dc3a,f984a693,968895e,2a6ba256,523038af,8e9aabcb,f98c73b5,afba31dd,89e4b9f2,ba1a841b,194b0b45,9a4a747c) +,S(f7948995,60528ec1,ed7f5efe,42db8bf6,e223280e,2b26d4ab,e23a5caf,41e2e141,9f7594e2,96ed1f98,86837e9f,da8d6d9e,58871e56,16cdd2fc,dd6fcb7b,80c6ff98) +,S(588d6fd3,b4208825,3d76e8ee,f01a93be,866bd53a,e228c137,62199ce0,f3454f10,a5fc9653,3e41208b,ba3f29ad,e31b7e32,6320b81,ad0ded2c,6d922a4b,b42af573) +,S(186fe08d,bbe5c8a7,56f87d4e,8976777b,b01db294,e834659c,bf423de,1ccc7443,d99ded39,a46f7820,3437a93a,435fd0ca,29f12e26,a6449bdc,a256f99e,9bdfbdc0) +,S(e549cb08,3055abf3,3b7eac38,cee13336,2af22e98,2f576bb,5a06d5de,59bd3d25,cdf37f20,e7b51483,6641c7f7,afc35ae5,5ababde4,34a945fd,4fe0325c,7d332381) +,S(a4e42afb,fd7f5158,5c86108f,cfe84b58,b930df79,f53a86e1,8ac93389,224422b,e9f8e1b,3963102,b58d6177,f915d7ac,541e551c,bbea3e2f,1ea47960,ce1e30) +,S(5f7ed844,42022f42,6b09e9cf,b7750fa4,4755fba9,7199fd4e,d09efdca,d803dadb,91d5ded,d06a8eb0,9c9592fc,c9096f1c,e852d9c3,9bfcdadd,ccbe1bdd,2b76ffad) +,S(3fac4743,32f064e1,b33fa22,3f67bd15,91dcf7f9,afa38f1,868e180e,c2938d66,45744e67,6b203799,3386d10a,b11730bb,eebf270f,9ea65920,6f93da61,e2aabe5c) +,S(5fb983ff,f058d214,2e4d13df,97d8e784,d4b10e0f,6a18c6b1,90e64bdf,fb7a7aa9,33394601,8dc540cd,eb73f73,a9733d74,ec581181,8a6d58e8,3460f1a6,8ddabd6f) +,S(baf35c3,fa939a2,db15eec1,ab083664,9c6e941e,19d3e0e0,43e0f5e6,df41f88a,42583cd3,e53fa1bc,4eebdc3f,e3b8b069,9de41445,54fed966,214108d2,f68e9201) +,S(97641f5a,a51e7ff0,f1d86183,a3fb3d60,4266c4d9,acdb9f9a,c704a05,809a8602,134ffa32,aa9fbdbe,d8d82fc9,1cfa78f,1ab169fd,459da39b,5b0d3287,ad9517dd) +,S(96a3711e,acdaf6dc,5adaa8fb,4be05c37,f59febca,1a876a5e,e23c6b55,2727292e,8fb0cfb9,681ebb7b,5e1fce0e,67ad5d81,34be9123,56100e96,b82ecd3f,a5da4392) +,S(ae64428b,8e540c6d,28d38892,6136320a,9f9f16b0,3e9d5e2a,14faadef,4f154b0a,db202e5e,b9bf73cd,b9ed5193,b0ff59e7,cc68aded,6fe6c2e4,d5b79493,fc118aeb) +,S(2c5932df,65c0c2c1,14b532cf,15b48433,e16424ff,ba87438d,42229075,6cc984fb,161ef8c4,b908a056,d395deec,38b9ff4d,1c643628,2ceb1e47,f59a2c24,c7d29130) +,S(76e21c78,6937ba69,18252d56,3ebfcbfe,2415389d,bc692071,f9c48f55,7aecca3e,de7786fe,9db47d61,e3b61d0d,49309fe9,ca634d28,8d71aa77,a3fa4efd,4533c8e6) +,S(7170dcef,ca8a138d,1d20b346,6afc6a46,99df363,fc964a36,eaa70805,b267900f,196bfd39,476f1455,98f89f7b,f870f8f8,440562e4,623fb203,3b36d5d,d8c0bb8d) +,S(98eddeb0,75bdd245,aa1fb466,ed1e89f7,61a95662,e35836f2,e6907c5b,691b6ccd,af3fb5f6,b59124b8,c9c2ddc2,108a3a2c,bdbcdc99,ab296814,731a841f,570c91be) +,S(bf42f806,59ae606f,a5e36fc5,c58379c1,8dd1c34e,fa98e67,68bf6da8,ba8e8849,d343fb70,6e4adb94,46f49578,26bae8c4,ca74a0d1,21cee98f,26be68f8,7555b8af) +,S(40c1c4a5,891e8dc6,29075c36,56249fc2,c42fd65c,8c338a0,d82df955,4662e1cd,667223d0,e68ef6c3,7195d819,2bcc12b3,f2025327,3a05703a,e5aa10e9,cc689ec3) +,S(162dd310,c8e3fe4,8384cf1b,1a0a2d6f,bfd3ef3c,5492fc92,b921133e,8f883dc1,1f2311d5,c82f02b9,f7197685,cf490e1c,3d0ebf4e,86ea0e21,a653c8e0,db5cff0) +,S(ff0f8146,89eaae3c,f3f302e5,1089ec58,5d63c4fd,5157bb3d,bdfc7e40,cc6331cb,4dc1fdb9,4eb529e3,bae54973,778d1daa,f8814cdf,5a3b0c2d,ac2b5647,551bf2e) +,S(143ae674,b011b557,2f472b22,44c6d9ab,14b3e641,54f4a033,c3ea3917,4607b78e,1528d582,faefba2,6018820c,a03dfd7,ca20298a,e199c99f,db9cb421,3601c35c) +,S(f3adce28,8fffd45f,96fa0efd,32974d98,4115a80e,cd6b86f3,5e17b017,8d9009a3,20202f00,96329bb0,69a0915e,494a586b,805580a4,eabd4ba7,2d20665b,4916a20e) +,S(d2270829,e2730d0e,2c8e6bc6,fa4c2247,4904ad22,f44fb2f8,5ad07558,c4d8cccf,d5a6b4ac,9d5bf669,5989741d,f262e412,27c66c7a,ae067a93,c6302f5e,8879a3bc) +,S(26d17eb6,7d9bf2a8,45c57a94,82bb2f3d,8347538a,65c9f567,56ecadf4,352964a6,954af3d4,7d67c345,bcfc4a52,a49aa70,b8703d1a,fcd21c6b,7f7719c1,e2068fb2) +,S(e4437f8b,e104c899,5cd1618c,e5ee7d10,36a52d99,31346476,bf68f21,e7fac74b,d6c156d5,b8256e6c,1a820dbe,3b56fc8c,f9b015bd,b81c756e,27b70db8,d995cb81) +,S(8932e04e,96db6079,662b63ed,29b5a39d,ac5bb51c,d1ec70,851474ef,a2d3c1d4,5437e77f,e030225d,53f5166,8c3551c9,fc912a0d,a3bd336e,c0587544,77e58541) +,S(fe776976,465b86c0,5b2003c7,36c8141c,933ed0e4,5c6dfd0,c7c82517,16617b26,b279dc5f,d576d506,d302b0af,359ddd50,94364d3e,255102aa,472e6d9c,c52aac39) +,S(6c60a4ff,b2a29224,5c84ecbe,1633817d,f69eb73c,a6b9f72c,b86fc91c,535b45f1,278dee6f,814bcc1c,70301a51,f9c7853,6489af2b,d23d6223,1b55cd29,2a2a0a2c) +,S(3132e58f,625f902a,98d556c5,ec9e8617,a955beb4,6e9c2a81,e121e473,9c9af04d,a5880964,a2443c5e,14db9220,446904c5,cf0a957c,945c5006,9438d869,45a9e461) +,S(b05cee36,361a9bf6,eb9003fd,c8d38587,640e180a,9de822dc,57e5012e,34903f6f,fb473886,29519a28,b745ce16,d625d85d,26fe21a2,30d798c5,305d8e82,545c9a5a) +,S(e202120f,5659e580,7a14e68d,e3aad7cc,23cd2f6c,abd86739,3a05f16,12005e83,49928b05,b66af992,d937cb4d,c05fbaf2,a70e8fac,7c081544,849d55e,fada136) +,S(57a91d89,2e5409e0,b07e68f0,450614cb,9a9bf0cd,8c5b3459,2f198633,c7a796b,47905cce,59018fa8,baa612c3,124b1192,1dbf7706,c5d8d16b,bd5c1e9f,8498e7fc) +,S(e092c40a,3ba465c2,d59e7c5,8265ddde,91c0468d,67428ee1,dd153b64,a5a7e8da,83f4e2b4,bdfc4248,2d4ab1d3,13b097f7,baa51411,134eb042,feb26f71,5bffd39b) +,S(73a3306e,7baa4fc4,a081a9c2,c335d3df,7c1ee84f,f5a46554,f78a6009,1de0ab38,1f68c8f9,2022c326,e37a7043,9552191a,3d93f684,3af0a235,bce893d,eda1f938) +,S(7c7a79f8,6e904961,73552caf,4a1401db,e99883c5,a39e493a,6a6eabbe,5f3a4434,85ceb252,e4883931,96c8ce8a,c0b596cc,a2670981,2c293554,15e17f8e,26e869bb) +,S(6a9df561,ce4ff772,b37054fa,e513657f,19f03086,eda93918,623a1c47,84a37788,bcf0274a,d9b3bf58,331ba398,a6611fed,fe719867,106eadb4,2b25b623,fdb65280) +,S(fe7bb24d,47b3adff,1c545d2d,ad2c6aff,81934cb5,bf2299ee,f3f8c53b,ff91c950,7fe65f86,9d2623c,930c27d6,f0a292cf,a881738b,4af0c5b,efde5c40,8a574e7f) +,S(26d1d2f2,7944b77c,290ba60e,17d05347,82ce2b64,ae815453,1da42907,30407d3d,ec3c5024,3106000b,d0b2372,53581384,51b768d1,d5aa206f,4d1055b4,b4f0f495) +,S(f00e51f9,38f91573,4ac563ff,8ea44de3,fb85cf4d,8f034806,e6c096d,8e73e2b8,7b7bffed,3a39a491,d3ab6a13,6fd88e0a,5854081d,21380c70,3c596771,a22c727b) +,S(73e15472,f42f8750,93abe811,a4d4bca8,8bd179d1,4e3e3b30,9e011e27,37cfc4d8,392ef4ae,58321768,1106426c,9b00b4a9,c53c826b,84bcda34,b5d0609,f85b9231) +,S(ed4667a9,aff30464,c851d86e,479df8e4,d29d2348,edaf8333,a7faf560,a9568092,77367875,6892d42d,469a9ab5,ff577e0,6d9f4fda,679882e4,3dadc7e6,3d49bb0c) +,S(d6ec16ab,10811cbd,dcc346a2,64dbfe0f,51066f2c,79034d74,af5b0ef2,541dde26,981f1cab,7ac7be22,9a91b733,6c0b89bf,4763b01e,4a1b715e,f4857e9e,4ad0527e) +,S(284ef47e,691931ac,8241d92d,2ee5b717,3f762ef2,bd1f48e6,8dca4b53,ab4c593f,ab739ee1,e6a7be47,83e1288,7ffe1b6b,b53a4d2e,3bfad3e1,c7ac5415,1bcf5e82) +,S(530f9e7,5a267d0a,fc3ba53a,c49018ef,44b490bc,835774f6,c6cc3f87,8d505c3,630c481e,44e5e9cb,cf6d7fba,8f7fded4,bee9fa70,4b88a8d3,6e2b3bc3,4e85e3f1) +,S(66a9b4fd,81d0165b,6737a4b3,8025d2da,ef9c4d20,3c49a2bc,1ba4d59c,eaa905f8,2770c44e,6a4dead9,7dd7311c,195d3051,12c86bca,257955f1,21b7b1cd,4e525e8c) +,S(25812e7e,dca47b64,9b18d739,7474de25,39bb7898,96ddb94f,60192135,23a289be,4bba3d83,72aa76e,6ba76f7f,18cb8644,788d3ab8,b58d0e5c,795c6213,6f17e2da) +,S(3c81be70,af162448,170f88b5,8fbf587e,df1a0e8a,3576cfd7,24acba77,dfb29608,ab16e48e,da59f480,7a0b5250,7102e9ba,ed9dc9fa,e0de8700,27bd5ff4,2aee13d4) +,S(ab626dcd,a5142933,ece82c8d,125aada8,39626e90,85c57525,2fb24f76,e0d6e39d,8add774b,34fa4b1b,d571f2a3,4d8ebfc2,bb7be73d,dab73cf,e7eedc01,764abff6) +,S(47f25106,120720ff,8cad6532,1a3e2873,aaaaed57,98e3933d,e1ccfe0b,f36bd85d,f6d472e,729512e4,ecb74ea3,f96583ac,cb44e013,ecd0bc60,c38b16f9,20585b60) +,S(6fd30299,f7398f1b,3c538d59,71b8bb0,e1640926,752d0842,36148b9f,23c26b1b,3b8d6166,a79ce235,1a2e9c4d,c5c89ff5,7810bef0,277f3d33,372e05bb,ba6799da) +,S(dd5b07c,784e1cd6,58c51ab7,45c4a09d,49db1287,dd7871e3,f449bd66,4a02e040,b26dad8a,62a491b8,dcced2a7,c0feed9b,6a04597c,d8a0f857,a4731078,d68d8659) +,S(3cf5836,104b4227,aa275e5f,16b84bca,15b61a8a,700b56b7,dff2adf2,167fcdad,1cc6f65a,2cb579fd,f6812340,88018dc9,445af726,2db43b5c,e9e49e4a,ce00c9fb) +,S(683b5455,8b9421c,c3aea163,d74c043d,d4cd804d,23857f41,3e01d28d,4919bb58,1bbe4576,2cd5c056,8add6943,8111cfed,691e2369,55022da,17cfddbe,79a11f0a) +,S(d78661b7,897a40dc,5f42f7ec,4202ae53,e83ff0e0,d73ce7d2,19503279,e43b724c,465299b0,e3f478ec,fc3db82a,61d5f290,aeead2fe,d0ec4a02,6652b29d,cad20b21) +,S(1258c664,fc15e794,e64dbb87,b4eebf1b,32e89e7d,50ec114a,1afa5506,19e15a21,327c4a92,81a73880,70d1a7de,c2a0e5c7,28c5997,bbc21571,94b0521a,141be0b1) +,S(f2d04fb5,1cffe2bd,c6e43cdf,ae7314c5,387f4dd2,4bf7fbb1,a6ccd627,86e8be00,89af3f8d,435f2152,8d32ee47,a86a2ae1,78d3a7da,c27ceb37,93250a8c,27061c9e) +,S(b67bbec1,4ab23ad8,e52cc402,def0083b,d21551a1,92a9df6b,b335481e,3f0dfb08,d6ca6bd1,93838993,5284528,56587554,3757cc13,fee01fe6,698b30f8,10a64a23) +,S(1baef1b9,fa401fd6,a053ce90,f2d661b8,8a466584,83a8489d,90d48312,2b79235e,28a19a14,a2f7817d,922b3872,cba558ad,bc1a69c6,c0b65ee8,3352494,a31699d7) +,S(6c0f066b,23623a48,b2b6a746,801baa85,f58de56c,e5287c79,c3c10ff1,b851aa8e,ec837256,84cb0f8,e528bd94,e1c86327,2347a479,2059f357,4ccdbb93,15ff0868) +,S(fbd5bb09,65bb9d22,bea6d6cb,7aebcf28,a0c815d6,18b79c0d,94913dd9,f63619d7,3303574d,5e605e5b,fe298f77,e20f3f6c,60ccc063,37a29c7e,6612dfca,3f00b924) +,S(2246042a,c4b22334,af6c81ac,8106bd1a,f8bd5f2,8dad88fe,7e568fa0,b35b1739,1da0d8eb,9c10116f,ce29bd9,61f92e36,9e538282,345a4f79,7cdabc70,5aff6e7c) +,S(470a914f,2fff2d37,835b3caf,542cf50b,9606cf6d,fd294c51,5632d9f3,4182bc4a,6b3805a8,d2c74856,a5be3cc9,e9c6a8eb,4398c606,81ce12db,b3a58660,1d426e) +,S(4e03f50b,ffb6d933,4282153b,a3f909d0,44bb7a11,50300c1e,cc8027b0,321b4be0,596c58ae,963e71ec,f1fe8f9c,b4de8cbc,9149b125,31e83e0,95f6e5a,b08c504c) +,S(5a6c4fea,b806bb76,191567e9,139dde28,188a26b4,a1803b7,d999278,fc57455e,6e81d07c,6505366b,c28ea476,a718e5f7,353d73c4,2f551459,d59a7d7,82e6ce49) +,S(ed73c9b2,9adf52e2,1280bb1b,ef63dd4d,74f4e09d,1be56c3,a246dc37,9b29bd5f,e9917b6,19ebe0ac,c7d1fa5b,7c4b7c52,e272ad9f,2df62161,59dc87b3,f913828b) +,S(68c6145b,38cbf9ed,4af10608,503ca13f,710dd34c,2386fa99,bdf93b69,c01c04bd,c963585e,607d9eac,5016f884,df535a9e,e7cb74d2,2e0c1e9d,e928d7ca,3fedc73a) +,S(1b651863,927317bc,1dc6094c,3f5c91cc,92269a12,59879b6,a8439a77,b0454126,31c6125f,8ac3d09b,d8c1fe92,c31bf13,c42b1915,e7147cf9,1371dc01,e8f5009f) +,S(45593ccc,dadbde3d,456b74f7,a3b705de,7229ff20,90a0df0d,38166d4e,6a09c52c,13d6657d,89fd0205,3c2b9a31,1ee964cd,e14634dd,20d85866,a43a4ea9,bc0bd737) +,S(1409c06e,d6f2fa2f,cd532983,d28c2109,e4dd7c1a,4ce77960,566d3eb4,37927da5,dc05f98d,4206fdba,e3b69836,e694b71e,fbeda304,537bc623,90edcad1,460984e4) +,S(d9e08c6b,c307b056,d4323921,5426febe,5d6e5cc8,4eb73707,4e2f00dc,e85f4580,a23c1647,c6b47a43,a3ab52ad,da32605d,172f4de4,201834f9,15d5a4b6,292c632d) +,S(7df319f3,d3c2b6b7,3533a916,64d5fa26,5ac0f18b,bbd5e8ee,1aa15dba,bd62fb32,9120f6af,e023bb98,1d6d8d96,31de0814,a9bd169b,a91af0b7,9c3db58d,2bc9f8c0) +,S(1a94e587,38b9fd1f,93146232,e2165798,11d74244,9bad3711,a373445,6986d7a5,332a27b3,17eee7ae,fb4604b,197f2db2,fc32549,ad86765a,74820428,abe4352e) +,S(dfa2cb4d,6db266db,2a82ef8d,fc0cf871,4aefff41,895ff691,fa0781f9,1b619a47,c5e5dbab,3a28a6c1,8cf20fef,4cba62f9,d2a1a0f7,6ea7056e,45acfe4c,49ad8b19) +,S(c2201007,be6bf76b,5e82c135,2a6e053b,acf4e2eb,c10a417b,f35e4c79,3a876730,92408aec,b9ae4d74,3af97c15,9c387343,9a735de8,90d1abe7,c8d14dd,fbefa581) +,S(d45632d2,ab087f0f,9d0d4d85,26730742,2f25c794,efa3815e,33e8285a,1bd7edc3,b7ce3697,c4994fa8,2479e99f,9c9e4b1d,814e7258,da7ba569,5543d6ef,8d5ff44f) +,S(8cef362b,cdc292b4,885f34ca,923a171a,df6c25b8,f6b7cded,c9003b71,cf5df93f,b3910f34,ed8b7fa2,bfa4f1c1,9d41d99a,d702e13b,5dab6bdf,2608186d,d09aaf5e) +,S(247f7be1,874c2831,17d60431,8184878d,3a415ae5,59595bfc,7f17583b,3cbf9838,90e235e6,a779b4fc,f9521da,65f65091,efd513e8,df338464,2f8a7cc8,f1f30eb8) +,S(b8c0cef1,c8703adf,411dd0b0,acaa2b82,f2609348,e36aac56,b0148ad8,981cf568,a0419411,47019aa1,4b8e74a8,1d49a97b,45e7aaa4,54c0f916,a33472ae,1275f14) +,S(8e55776e,6e1c791,2aa6b43a,4dd1bd17,a35ab0d,aad792c0,ab51bd86,8208cf09,dfe4ccc3,a025abbf,c2d12bc,6d462e6a,cec7307f,6daa9c01,2c8a7ad8,70822d56) +,S(f1cf6d3,fc9d9824,4e122790,de390241,db813b70,c48b667c,5f05846a,c3ad1ad,4925c6ab,3952d1b2,35ef1ec7,7ae7a84d,75006993,b173a6f6,c8b969af,c3984799) +,S(b49dbf88,dce5ee49,2b4495ab,9db762c3,81164147,cacbc00a,9e56670a,edb9ea31,c0f92f17,ab5797c7,758d703e,fd288a46,8971f7c2,de8923fe,b8b7acfa,ffa9ef2a) +,S(d6afe2ad,257b57ed,15573c50,a25f7dcc,399e2643,9e64acab,9a8c9f75,d8ca362,5df236b8,6919b56b,17140249,16282b11,38d355a3,561c5b42,b47ac6f3,8d35749d) +,S(bb0284c5,f23365fa,5972a439,fcee4b4b,45b48a9e,6844a44b,53e12004,1ae8e89f,684bcc0d,e09e5932,79018fb2,aed55329,53221dca,6f14f493,6ae76099,ba265300) +,S(57e95714,8a409697,1b8be621,98a04177,c4779627,ab5a77e4,6e82d847,e64467ec,714bd1b1,14ce2580,7c6d3a8,f12a5375,fd8e7cd2,5e854c12,6bb519f2,cd443f13) +,S(b0c82f60,b33c3b47,523ef2a3,de804521,a1e14478,eb637757,d17526d9,1e713094,cfc8d1b9,d763f52e,6522f70a,c93f7fd9,23d163d6,5a82b2ee,ac1af994,a2cea63c) +,S(2ba76170,404785bd,5932c185,c6d98ed0,667d8324,ff7f85a3,5c24a4bd,553e1ee3,1810790,74262af5,607167d6,b55164d1,e56aef19,f3e2f307,205d5603,eeea35b9) +,S(5bd54e13,d508b920,fb1d15c8,27e0ca59,3eb1c85,a7228895,b5c9235c,6ed3e88c,d65d35fd,5607e193,ea70ab1e,4ac7d822,878017ac,ef3bd6fc,2b1933af,660cf0c9) +,S(b0bbc2d2,753bd89a,b2bf1664,e6cf212c,a590d65f,5664e694,7ccdf977,3ea8d09a,9057b6c1,a1078bab,a1419065,4cc67052,7225741,1f34d47e,47f09bdc,8f993c23) +,S(c1701203,3cca38ac,ddc0fe41,95452129,b38b4630,20e8c459,224e9dc6,cd3133a8,c495d87b,1cfb6f67,46c07188,86c08616,624f78b5,ebf4fb14,fb6b636a,f5557e9a) +,S(1e0bd20e,5f1e49ff,32287961,7fbc28c4,7c9fa4dd,d93532ea,74930a24,5fa21bda,2d407400,e98f15d,e5da681b,2472fa11,b2a5869c,66be1cd5,7038e160,43dd6177) +,S(5cfc223f,ec4c6618,ff12a974,8533a70,f39defa3,bc05f88b,3a1b158,317ec15f,7d928bd4,89e3719e,6386ec22,6c738b09,eb4468f7,b6718cf9,3da33544,aff21411) +,S(f506560a,bebd668e,57e514e,bad47a84,5da345ce,50ac0e88,1cccc2c,81efa67d,e2ff0bf7,c9c2a99a,bc3580ad,17f64a26,63111fd8,15bdcd63,9d9a7d3a,ca0fc7e9) +,S(8448fe98,ec887485,45a46e4c,449d0168,1d00dcae,5bf96ef8,306e7bd8,26c54f45,d0f07229,17500322,2dda8271,33481376,85b20045,f69d656a,66aeedab,ea6f0407) +,S(c9a6857f,db037c2e,36d5ca71,32942f34,2480cf28,a98644f5,6bc455ba,97cffc55,a69e08b9,8f678e61,6c0b8326,ced6f97d,f742d974,b68cd1c6,b798e367,8faa149f) +,S(b5d13f5,c611eb3b,c82f7db2,d89ab19f,b8fc286d,8e4699d5,3dc664d,bac4011d,27eb1650,7cdc0fdf,5b92493f,f2487d0a,ef2692d8,9c702bb6,259808b1,324b7adc) +,S(bf9ec5f3,2e0ed4ac,c001b887,18c29c6e,90218471,d7f1afad,75abb34e,da35ce44,13846488,892b4065,b79224ed,368c47a4,a1734f68,7386546b,dd837a80,467ef2d1) +,S(2c3812be,4d3b1c13,aed1f6bd,1ca6f5b8,893c5a87,ad6a8f2e,d6d92ac1,3a526e19,366b82f1,45d551e0,b7bcf877,db340bcb,1b11edad,1466baf3,24a94cef,3433aece) +,S(77bdef28,dc8ef6c8,7fcd0a13,c08a26e5,9fd17253,8d8bd3a6,f21c5c86,ca33f572,da66b0c7,bf3bd49b,ec1fec,aa580a51,6977ba8a,83f957ef,8167f69,ea3c3a1b) +,S(bc4a799d,3185877b,cd86503e,3f34c606,8693bac0,654eeb15,4effd116,8b71afe5,53fcd7f8,99a8190e,a7159c99,e261525b,f59abf6b,d331be66,4f7f7757,7255569e) +,S(301fd884,733dce05,6190e4c7,d0375078,6fccdb6f,2e13f9dc,e275c188,2efcd040,79e4f9d5,185b9f51,fd835cef,64be607c,312c910c,e25cb73,5de2c88a,51e25cb6) +,S(241b4a9b,be5e7e54,214d0bda,13719c42,133f8377,e50db2f3,87b6018a,814adb70,c66edc08,fa4fd22e,1f76bca2,7fcc00cb,a8ce2100,248b3959,3c164847,b410bdb0) +,S(be6f1639,68191289,3c5c1351,d633d51d,dcd28c16,f3294981,56ea1602,d8c79585,6f674a7e,1a65539e,a7f8a966,8f5fe5e6,1ade5da0,a543335a,5f7a71e5,fbafff21) +,S(c8b5008f,79c69e2a,7e209ef6,a2d14b9,b3f7bfba,b7fcb285,e237cb31,3dd3a283,1dc79348,6c3cf7e0,bc36dd7,46efcb36,3cea15ca,a63008f5,2d83ec0a,6bb54bb9) +,S(5014af9e,aad5ed62,4e997ec3,a796ad1e,b038edac,77cf27d4,eeda7ff4,c06c0998,e01d786f,b8faa1c5,2d44a77a,987b4b6d,91143953,34977151,1a488602,3189dd7d) +,S(6ffefde6,2c40643e,da2d4f28,4f28fcdd,b0845ec0,8d882d2b,45dadd8c,a7bb989a,8e2b183c,782d3a9e,2229e4bd,9a2becbd,ff0a5480,6a6f4471,7fb6fe5c,8411cc0e) +,S(ac762bbf,190e1374,d32a7e5d,b4c0c36,ad0140f,c1e92290,4aaff1f1,487d463f,ccd79f18,31016b40,a381bfec,5db6b12f,bc34d850,ed81aa7e,435a513e,5f3adefe) +,S(973496d6,3ec05c75,93244e7,b737b1db,d791a5cd,e828f342,7968eae0,e811cb24,4b2c9bc0,44e3351,f637ff52,5c3f34f3,d7420b65,2f57bb7a,bf573e67,25647533) +,S(a9d89166,5f77bc30,74357753,9ea39e36,c39ce300,6fa03429,1a799b34,84a15d32,d09c3a17,fdedb8fc,f4f9ce98,20635a50,56dd884f,ccfaa96b,8d0813b8,4b80e213) +,S(108a8ffd,aa2b544d,8b8a7419,f2421bae,cbab636f,60d6ef76,9eca9a20,a0c5710b,ad3e9fc,ab04ad58,a265776a,75f0e389,cebbb273,9df328d7,b125665c,d4e0249d) +,S(ef969d7b,c8843c57,bfc0ac6d,f5e4495f,9543878d,95120a36,de8c5bed,727c5fb5,5ab81bb2,26738036,b145d81a,1deaada5,d1d4d653,7b80b02a,fc1cf85c,361f16fb) +,S(ab825bc2,4d505453,f12dafb2,8f70b245,d74200f2,410f5162,b0ba3096,43c39b62,789e7df2,23774415,da7e31da,277a81c9,708098b8,d455594c,6f9cb065,b1281a1d) +,S(4984a4e5,2c173c02,ec79198c,f8496972,eeed4e39,9933bac0,59856bb0,48bf2622,4596b67b,79be2e61,a0887a9c,2cc3ccf6,f199e924,3991f434,8e7cf897,acc5df3f) +,S(285c6ff4,93c1be13,f4f60d0d,8aa7cb24,4bf0f76a,23f3efbc,cfa4a132,625f7272,39dfe9a5,cf9cef28,d5cfd998,49db9b23,c4caace5,e8a27c12,12d7b3d9,d3ed49d3) +,S(1e14b1d1,7e721971,e9266717,13100aa9,9bc6e506,c278ac7b,348b708f,843db340,63a239d,d705f627,347fe464,c4d4143c,394d7dfc,5f79ea11,64d05f04,4ce41cee) +,S(b8f73b9,ed71cd1e,f61dcf30,9cd48587,3b1394c0,4cf318fc,10140bb5,be17c8aa,8af5dae0,bd66ec85,2ff4823a,a1be65ed,745676a,5ac42ec5,827107e6,776f665c) +,S(7e0c7297,e878fcf6,cb636776,d15afd0,49c995d3,1cd49d15,e624bf6e,8714540a,df5795f7,4c512043,f48b7568,bb271a00,ffd59530,a0280e5,8aaaf0fd,aeddd658) +,S(9f0ed1d,465bed9f,a2b51133,fcddfe48,10999011,b754acba,de5fd027,6b798545,7005ec9c,73bb0e00,64badde0,12aa99d9,d85b6c38,e63256e9,21799990,14a8459f) +,S(2d556f5e,b5c5af0,160608d,80e23cef,cc8e4000,b1e35b12,5a0a51aa,9c8e12bf,7600144,25bc3baf,1dc7f6fc,1fd86f41,d24d4488,f80ab8a9,4e4422ca,15f12000) +,S(2617667d,7637e02c,b479524,d9c7dcc1,2cc14ce5,4149928e,e8d81bcc,835ed3f2,521573ba,2cd809eb,8f5496be,478ca639,7a2c4e16,1b299ba,bc6ae419,4780884b) +,S(6247916c,5b519a64,7b76e10f,8810a3f3,4cae40cf,ed05a492,ba1b061f,d9aac10,ffd02570,535ba978,906a193c,500da1d4,602b0969,c3e9f4ca,f2d33026,eee7f098) +,S(c40b27e0,8ed50a88,60017e78,ececfb9,ea14c64a,95137db4,fa55d4cf,9a3c52af,2415cb8c,7d025b84,fd9d1e97,7105aa54,c4149fb8,30ea801b,a86f1acd,e07b6493) +,S(ba5aec8a,54a3a56f,cd1bf17b,ceba9c4f,ad7103ab,f0666974,8b66578d,3e0de12,348dab11,abecc4bf,3c7474d2,8ea5ba60,a705de60,39f9b70d,c49d58b0,6d57ffbd) +,S(ba14e658,f8dd294e,1331262c,ffb3f31a,c1e9e504,e55c7f67,5c002248,94076268,ced74905,fc43e55e,c70cb36c,66dd9a10,c221b0e3,a326e365,9b96de4a,c81aa1dd) +,S(3375af69,8880c7fa,29e718cb,4139ab30,f9c1d00e,a1c22d4,cfbdfa16,a7f4aff4,cfa8b491,a83be5b1,b66fa0b8,5e26c68e,8d27db79,ce55d726,ddde67ee,ce295a27) +,S(68d2614b,306cfdfa,e9fa109a,2c4b276f,5b9a8ee2,f7d502d5,efc94aa4,bd9f01fe,148c36bc,f04365ed,7ddf54e8,4d40fb59,ef9e1d48,8408c8f3,661386c8,5f48550e) +,S(93facea5,597703b0,ad2990d7,1d63387b,900ece6b,6c3677b,7fc47b7f,1c533edd,3c801bfa,8fa114e8,b5c19985,39a1f6c1,c20bbe44,d8ee7179,7454797c,942ad5f4) +,S(f11dd4a6,72f73118,95775ae1,76c90b2a,5a0a61f1,6ca205d6,eef6c275,75054277,bc06a16d,2ef2ac0f,7ea2083c,ac18d0d0,6c307d45,51e0a0e8,3f59b568,b9556ef6) +,S(42ebcc5d,710ba454,fd29a94e,f83c8004,b71fe85,9725c010,f10ca39c,864204f7,f8aa84eb,643101ed,4c7d5cdb,271d067c,e633c17c,dc698e40,279064d2,d65f223b) +,S(d40877dc,d96d5a94,87b6fbc,e89d19a0,549e96da,13f1fb2e,67e9e3e1,85c80e52,be9bb9b3,85f20fcb,8e57b59a,ffc01442,c0be8306,f5d9087c,837e234c,5e789444) +,S(c18b2c98,cd2110ab,888ec934,239240a7,aa40c1bb,ab8d7e39,8fa74358,2562931f,d9621034,9147d74c,75df18cd,1066c40b,b83f189c,937c01cb,24c2ce97,155773f8) +,S(154d6b22,1a44f841,1cf4fa0c,4bb4debf,6fe94658,c648f9e4,d14f88e3,e05c0bd1,df0bc307,c705332f,328bbb6a,dd94e63f,7c1074f3,ebc55976,de552a59,5875559a) +,S(a38259e5,629f93b1,a397d228,59842dbc,24485d59,c3ab86e0,a9326a35,e1a26f15,69b5accc,2fe52a63,b3874932,e8a79b8c,1713274f,f435d892,367bb9ea,91f783fb) +,S(9d729eee,e91e3493,9925a7d5,2eeded18,14827029,6f822013,d4db2a3c,763fcd19,6d832154,3cc8621,166f731f,2d874fb0,9cadc09e,4e330339,657aa2f0,e3e89a1f) +,S(2674f008,86307c7e,576cede7,944a9f9b,46398c93,8a0f8b39,b25701b3,67751e3a,3e9eb42,6ac9d1ef,837638d0,7b0f1f4e,e31bdec7,a9d22fa2,12a666b8,193f83cf) +,S(b2a06d5e,adb1b856,dd28e9fd,bb626c0f,b7c1642c,6f70c2c2,743f3451,4e237f41,5d4caf8b,8673b268,227baed4,481ad60b,de579a98,4d005f5f,f3bcead6,3bf664d3) +,S(20b27d64,d61debdc,ec3e4ec9,2040f05d,2b278c0f,1415ba60,f0bf23e1,222d713d,481d85e7,ff5c2df3,5cd26488,6056750e,c8c5c809,bb3afffb,41e447b7,a4e516a3) +,S(4f4a610c,450eaa25,f60d7c15,20c551f7,5270930f,45a7c51b,fc7cd5c5,3ce3f2e5,df1e8e11,db416228,672d8d8e,f9d68ed,e824234e,fd7de39c,2b32fd90,3a47f328) +,S(9b375ed8,504358,25570b4b,e359bc07,bc06c989,14659e9e,776fba36,a8aceaa9,3d056593,385c0069,915de5b1,f59c3483,22683440,86dcdf26,d1e6ae22,35e90927) +,S(43640804,5d432c87,31f865e7,2390b7ff,c13aff87,37fcfba4,60c0192,2ec9d1be,e2338eaf,6fc73fe1,e3df2aac,54bb4fbe,5aff2a92,5b8b16eb,2346b220,6070cbeb) +,S(a6e59c4f,24461172,4161f35c,fbe88d4e,59287f2e,f2b9ea39,4c476127,f41e0b66,75c70747,f5dd75f9,41cfa470,c4cf718a,57a8ae2b,2e7ab277,5f5ec5fe,7d9f334d) +,S(ff639617,ae7351fd,977bf1e8,46a6d33a,5293a959,74b296ed,7c9a007b,25322d51,e6123dab,fa2355f7,653f81ff,ee798353,e21dca71,ef40639f,79d73116,53dac457) +,S(77914840,1710d8e6,8a37cbc,5ad5e284,c254dfee,1c8b043,5f8ddbe9,4ef4faf3,d97f44e9,9ef3d4c7,4075dc3,894d2a6a,623be446,32c98eca,a54b8ed8,e0611414) +,S(f68910aa,29254aa,10551c00,adc135c4,947cf1fc,6dd8ee5,d42579fb,79484aad,40bdfbdb,33a56d63,ad587ea,fc9784de,69f9f5c4,3f5c7c94,1b9b59e4,c052c1fc) +,S(15be8f81,473d4cef,719c7501,1d560d84,f2d4d8d2,def1d696,29f62464,1b6e0fd3,7e66f926,fc991b41,c451ead0,6d93267,64b85ea8,849047bb,1d28eeee,70fd9a2a) +,S(e113d5a,2e22302e,f4327297,7c41c8b,d0c5c26f,9a0bd9db,9091abdd,8a84e9ca,2e4862d8,34c6dc45,17a6b70b,2f1b2c5b,b54941d1,cb803530,26a257ca,f5574dc0) +,S(96b10770,485bba67,7f620d9d,ec0d1be2,2c94dab0,57d6d595,aa78dfe7,47bea688,e060aaae,222726a,c1a1bd58,fc779d9a,ff854ac2,4a4996a5,2259e9f1,bbdbf30b) +,S(81742f00,5555954e,17e5e899,d2cfd8c,57f6f7c7,5a38e183,de878934,2405545d,a1763fc2,e5f705f2,e6f2fbb0,73578fb0,a8d742c6,8f92236e,df1ee03d,2ed2fc0e) +,S(17c19f13,96988f62,77cb72ea,f90d37bb,86bc7a0b,e16c1c17,fcc481ff,bb78a480,cb1290d5,210164eb,621c2642,ae3e51b9,3f430e60,718f9fd9,c5ec3bb6,53c78833) +,S(7b0f06,e8746ec9,c6648b2b,bb861548,bfeee507,63c01c3f,40319beb,a2497a3c,c6949378,84297d8e,308b318f,1caa0c7b,1634b758,9d6e8c6a,2fdb778e,d6a70020) +,S(715c2b06,2414183f,9a67d8c2,8a89b754,55a80517,cb1b8134,5f56e91,12c5e8b3,f89b89c8,9a795dc7,1e2d4cca,7f84b4d5,23167f03,97787b33,9205773f,2520370b) +,S(e0d0ce00,f974fc78,76777662,efe5dbf5,57aed09,dd89a4c7,8f1f40dc,8f74d3b6,acc5be65,ed704847,94bc7f05,c4c5511f,c253befe,7cb3c0d3,e85704e2,e3e3eb56) +,S(37553289,76fbb8b7,9a5aaf75,ecd9d2a1,bdba9a87,5bad6222,e770ab1f,d26432a2,6dbbe233,1b7e064b,d80bc7d0,12b2a088,1087e7c,2c5c1d77,eb016108,c2ced92d) +,S(2e95c3ef,51ea9036,8683f6b0,8b2afb04,f46ca651,2abdc699,446ab3a0,6fe3d3ff,905ea87,b1d8dfe0,48463b94,c61dbc62,1556c66,b2b498,39cb40c3,299b554a) +,S(25310e1e,721f3245,7f35c67f,b73553f6,6467580d,b5916cf4,fe7d75a,c4ff8eb5,9c5e52f9,be42eeb5,425a359b,87dcab1d,46ecd662,c17eb041,16b5430,786b4ace) +,S(25932b1b,2b24fc2d,d7877911,7d7cb506,27a23b7d,7faf53b0,cf707f51,b7830b7b,7e8e23b4,acdb26b0,1d7969a6,ddf3a2ae,2215e206,109cf3e,4e32d91,df536765) +,S(7d232af6,251f7667,ba69ba44,397f5b8a,892e135e,b09b684e,22b16a44,73c5ed3e,a3e8f638,c8a589b5,8cfdea61,d9824f1c,131b9045,9509b92c,1cd26571,a6d8356e) +,S(4d56caa0,1b65ea87,ba3e05b0,a4495606,6afc8645,4847633,cb9e9755,c8c720f9,14c34678,36e65197,ca3f1ada,936f0348,7c1eaee1,977ae08f,50f41771,77537330) +,S(71abd165,ca6ff8bb,775c81f4,2c722ed7,2615b503,3727dc2c,122efbd9,c500a88b,79ba2467,7284f86,2fb1c46a,e11ac4b9,a5969352,64224eb9,c39ab884,492620f1) +,S(8462fccc,c3810519,cc449634,5c5d9e56,30215e74,c41179f4,2002e906,56a48965,535a966,cd7fb998,bc548a7e,29fc4640,f0eb75a7,5c3c05cb,64d09048,a7787d4b) +,S(f68eac93,fed751d0,b578b5c,665684a8,b9c2b104,6fe45ae3,286e9351,36c09826,98e0c32b,98b0a8a2,8f119ff2,fa50e54b,66f7d8d5,732a1831,7334fc45,fd48bff5) +,S(61447250,9a8d935,9c0e4014,f6ff569a,43467dc7,e4940b16,15f442b2,d9f72041,fb7177f,c7f57ee7,deea7108,dfbea888,fa58f209,2aeb2d2e,b2f33141,7ac8f807) +,S(ea69ee11,4ffa1bd2,e2259a26,e2d88cf1,c9846ac9,379a1497,fc28ecc5,4b15614f,589b81b5,1dd6d750,91014108,3dd6cf3d,63183d1b,809b62c9,b17b768c,5ce4e2de) +,S(34727b24,3404de96,641a1ce0,d7ff150b,38e6aa15,c51fab78,1464c660,4e5d5263,9198326b,cf56ca77,35b9baad,dc0069d3,1920bff2,d5bbf804,435289d4,d827d4f2) +,S(952452ae,613778dc,29e2d275,6e98b4f0,eeebf4d9,526cead9,52f8d0d9,9e217461,c08b3a28,c195fb5a,f9a50eb1,1b1411b,c17f6582,dc14b5ff,797175b,2ad486a8) +,S(fbca3f18,dc4a8bc7,7e9afeba,66610306,401b8342,bde2dbfd,2d4a156a,e78e49ff,2b829d6d,6027b2de,eda0db7b,c76b924f,4cf75573,bb9329b6,c7b7e443,f94129c9) +,S(c7ddf11d,7ddc643a,957dff64,a08a4a70,5302bfff,b940882b,57bc4c15,5bd8c141,e9ca11f1,ac93b018,3fe8146,839be79b,b3711ee1,8a3daa88,89d55669,6e708e20) +,S(71043a30,86e3063e,b831f7e4,4e682181,1b3f2353,9cb6efa2,cd0ee4a6,70ce31b8,4db3f338,ef9fd273,4aa9cc92,55e2984d,9334c164,5320b411,ebcb7cb4,89322c9d) +,S(6de4ea40,15347cbb,d9349d36,80fa375c,5d70f044,799134c3,dbb6a776,48602585,3b76588,65ab52db,eea8d839,47025cf2,458a3243,38c73d70,f1d77df2,7f960418) +,S(29faa79f,467cecb7,ea17e23b,6f7ba03d,db9a0cc0,e1fa6215,bc425696,ba4fecbe,e5aa691f,c42fbc29,c1f027d0,46bdf106,64a2245e,d2ff1154,e50ffa1b,48f34838) +,S(ff880bfc,25ae5b22,78e5f15a,2bf8f5b,d750f8b8,74910f79,c8c42f93,16aafc99,9535f70a,728f79,37825bd8,1bb502db,60e7a166,bc8a0b10,5eeeee82,3a5747df) +,S(b781b6a0,3837f6f5,8520c566,352e8c09,60eff0b2,42524eee,f6a6bd2f,a4a2a378,acd7b7d4,6c683dd9,43722ee7,3c12b69d,cbf8389e,62755e4f,c44fffbf,4cdbbb62) +,S(6d976593,e8bac5d0,da732c64,82e4ac2b,b3f19062,59045990,ee540a3b,467406db,30c353e4,af6d8161,6c0bb9c0,f2a4aaed,6cbc1825,9a8b9658,3bd7e9c1,2f2a8b6b) +,S(18ed676a,4dd3e0db,46212112,9fad1e13,683ec782,2a6d9401,5d0866bd,6cdc3032,c86b06e1,5dbfa82a,5f7b9762,65e03670,6f9a6e7,7ee319bb,8ef26b16,a51bd5) +,S(3138e38,e9440ffc,c2cbce4d,aefd4b8d,d1e859d3,b951d18c,eb3540ca,db5ce2a1,df8ab1b2,a11a8667,dd660a13,490c6e6f,fef4bc40,94efa9a3,430e28c9,6895c241) +,S(757df4ac,2025c9aa,b8ab1e76,149a9762,163ce608,f4903c3a,91571cf,e8b00c95,ff0af5fe,ab36c5d8,47d15ab7,65000765,c56bd7cb,4d0fd8c4,a37d4ecc,dfa03430) +,S(8a697a52,7156589b,d13319a0,81e3b2f2,ce09de8,450b95cc,9aa70409,884c27e1,9eeb93c,b6029e9e,37f2815a,d332d5d9,5a5edde6,bbf03ca1,3df09f86,ad51f39d) +,S(b0bb6987,36f9e0b1,6cfc2198,e37a84d5,d35eb89b,d4f4c0b1,650d60e3,e58c721b,33d5b200,ce25b501,6f09808f,b38e82d,b855615,2f48c1eb,b3b6363b,ed6e00dc) +,S(1ca0edde,5dde4634,2637882a,d2f8ff7,ef6d6f5e,906ae2d8,d9f1b545,c837efed,19efb5ae,4cff683d,a7d5d4c0,f5eb9f3e,4c4d3a4f,ac58ee41,acb9ebda,a82863bc) +,S(780e5b0e,b9a4e57d,66a84931,1e1b765,d59ad11a,de4e921e,d90fc422,4d474aa7,5ebd9ccc,58cc5f21,2da579f4,c79aa3a4,1d8f34ff,418516a3,d339320c,133ab811) +,S(f7e92ce9,39808505,2d2af620,cdf210a7,30ec079a,54bf1468,edf686da,34eb4c9d,2c559dcf,e113a961,58fd54c0,32f14ada,57c23496,7a88b585,7b1f7ab9,78f93666) +,S(3c3afa20,75bb20a7,8f9ff809,20d80d61,3a5688a4,269336f5,4bc7da5c,4a89f938,7ef38308,1dd235d6,e563a9f5,46435f22,3bd836d9,3f1d132b,978f3f9c,7b888c8d) +,S(71d6f01d,ee60f9b5,75dec59e,7e56123,89fb9edc,3019115,af4fb155,f22097ee,e1ccc245,4a31a35c,52854091,fb414321,38da4fd2,eaf1680,2ef0470e,1c80bfee) +,S(9726660f,5705ec80,908a77b2,8e6257de,b107fc31,c58ab6ea,1f5f75b9,38c4fa2d,94cc07ae,3102d1e9,6118c213,b6db0c65,d3636fe7,8ea40c6,90c86949,b48cd4c1) +,S(ace5d0c7,54b2a1af,691a1a2,97e8b632,297fad12,ec1fc4b8,7fd02ac2,b2802719,924f9f24,8d3e725c,eba491f0,5f188d6a,7fc843ca,d24d0858,1f4c9485,8b9f85eb) +,S(fa51306b,34800ff0,ccd778f2,838a4a2a,8200eafd,622e98b8,8fa566b3,85943f64,b60ee616,6b144873,a1cee030,fc92b50d,4b67757,ad34d5c8,5f05c871,4296e293) +,S(85df9018,329d25a6,79c097ee,458eafcc,b716a59,611730f1,7c19d584,2dbea60a,c555d5b6,46d211c,e99ad7c0,9e787774,b7bc64c6,f2f6980a,e62e8911,897ab0fa) +,S(2f77c00d,c2024467,ab461b52,ae634a99,337ff5f4,780637f3,efb989ce,24af5e3a,c7f4a678,ebcbfabd,870c52b0,be7efba6,c5d28e7,aef2b253,3f0e7fa,905e3e39) +,S(52d8a23a,720050d6,ff6a499,7b802bf5,1f238df5,b0ef6001,58fc48c2,228bb34e,98ae81a7,861b8e1a,162d29b5,1c30c786,cebb1812,c91780f2,ccd302db,803d9136) +,S(a7f3e479,eaca0049,22fb8320,47555b5c,701daf22,407462fd,37b0edb1,7212b211,80f6190c,8c4ca7c1,7ba68498,d1bac039,3e33767c,c476fae8,e926500b,9fbdaada) +,S(31ef3150,e67bd326,61bbf4d7,942382af,73db5799,8f4880,ea04607c,a2356103,7db8f5d6,655d28d1,93b50bb5,14b16ed5,bc03c46a,e3d2c954,631834b1,a8a9a8ee) +,S(ee82f155,469c0299,39ad1ee3,52edea30,599b0cd3,868131fc,eabee245,3b8b058d,fd0c0d4e,2d77c2c4,2add9ed6,cadb898c,32de9398,f0394400,eed2ff30,5092b10c) +,S(dec7c7a,bfcedd6f,a9f7d45,8a071575,27354990,b456873e,206d1f7e,556b4586,af841ab4,cad597f4,186f0912,b79fe320,2c7626c7,b85cb276,73c18010,747200c4) +,S(c28e3370,48cd6fe9,7591ba40,5519bd80,2bf34f12,ee48762e,526b34d1,f4d2369d,e00abdd,da456731,7f486dba,6976ba13,b8640f52,39325a64,7d50eb17,f0636e8b) +,S(47157ca9,2c275f65,c29e9d,b0f23531,37027731,1cf05a93,7145123,df222195,648b17fa,c911fd25,af87e9ed,441cc874,9fefeb72,b34f8dc4,f430e0ce,89cbef6e) +,S(84d11702,745c53ce,d81b5503,79ff1947,9a0a9253,a7ab3868,f5471a64,6ca73241,4f16b6a2,c3c087a,4efb1353,644e64cd,fc593ec1,d8d656b6,2c0e0bc2,25f858c5) +,S(3bba3022,196060b8,6b2b2f28,ea8811c7,c74e8128,8e91adcc,b7fbe2d7,97d63fc9,7f34054a,f0945373,a77c5aa1,2ea4f54c,879d3f98,b6e7ef3a,9d73d2a2,a734e286) +,S(85637f4,7a2c6143,2437485a,b3d40e70,b9f74606,aa8538f4,425e8a06,98651c6b,bc6a95d5,6fb42b1e,67b07576,83a5036,f76e8531,a30d0096,c3500ad9,93396054) +,S(25302e98,5e75019a,21ed1605,dd3c543e,e8021a42,a40a967d,8ea6ed31,4dbbd123,849ccbe0,23097591,d46f9b4b,a13713f9,c0220639,11fdd0f3,267a4d8e,66797a83) +,S(e59a30bf,88e393e3,c08d73da,ba720ae3,485fde0f,b6b85f8e,4117f5e4,f43bea40,6fd7824f,e222cb37,1a0fa6bd,33e4bf83,83ebbb64,87872fb4,42284498,6197dfd5) +,S(c5902df6,97981a60,589e9bc3,b935de2e,de05331d,2c1365bd,a83f8183,f6247e4e,c67eb14f,5af551ef,1ab5ecb5,8feb7ce1,21d0736e,b93dac91,f865ac7d,2d75fe3c) +,S(df8bdac7,fe27127e,c679a9b4,74e3c809,b8b6409c,2e6c4c1b,277ab4e6,d5e66ad,3ff26fe4,9f0b3896,54d802ed,72eb4708,2738256f,c0266dc7,645b1027,717d43e1) +,S(1d55404e,9c7cb8ca,c39c7c02,b810d5f0,9eff9125,9166cf3,f1e8cf76,2c65a82c,c1787023,f6a1c8a3,5c499f64,a2fc4d23,e5a760ea,9a04707,c24bb9bd,b2a7632f) +,S(35f390c9,b035fdfb,68506073,d585e450,2d040e96,67a1b4ef,804ee088,df43b44,6a85cd88,86aad8b7,7dc36fec,50eb9754,4c3cad2a,da43d038,3c55da38,bff512a2) +,S(fbb0840d,ee888fa6,f26d7005,b2449cfd,1d22786e,d43d06d5,88f744c4,c5e059b0,6460514f,d89a70f2,3a4ffa21,9f651bae,203b05f4,bd3d45a6,508d2b25,cdb8d3bf) +,S(24056cf0,1c2275dc,44608ac4,66931e91,61fa0ae1,3353cac9,ce481271,a34d78d7,43ebd3c6,7e7381d1,bf03088f,434a5275,965a3fa0,d86a51bf,7dda1b63,cbc7751f) +,S(3b1043df,e8447c78,8e07c938,cd72f6b3,54f9f745,d7e71297,e7791972,70f9cd78,28e028c4,abf0d511,126c29d4,b2b185c7,b67ba361,e16c50c,34af129a,5e40d6fc) +,S(aef909d1,41793638,80d75b23,6635805c,8088b08f,5c577a81,a5bedd20,69a040e6,cbb4c6f,de26b6c,5d0c2b43,df40a3fa,93350cc0,1c497382,d8a1bb7c,8600dc51) +,S(c8d494f7,386331cb,6ff59aef,5f229bc7,913367b8,10f407ac,2c9f9d3,ca833f28,cb2c76f9,4b6285d4,d39afdac,bd3ef114,c7b85027,8d62da67,e70aa74b,b10de4d2) +,S(25afcff7,af14ca32,3dc74443,71de7b5f,c1b52e17,6fe5f3f5,f4f39139,34f75b28,d867a4a4,7f9d7e97,6cb1f57f,8d505a66,5010cdfb,4af4b781,75271722,6942b789) +,S(2436c86,f773930d,872c220d,c8bd72e5,d407682d,7708e2f8,19ad9632,3d32e2c7,6e396dea,92af663c,c44de690,24e1407f,20a95887,37f01662,bc89cdea,88ab67a5) +,S(61ceebd5,9e5733c7,910bcb86,e19159ee,57638bb8,7f3cc56b,d0f4d25,147f349d,2a850545,e9b0ed08,fb63082e,741a30ea,7d85218f,86282aef,3e74b15c,f2fadb9e) +,S(5a1133b5,d45d0071,42b91a73,79e2a46f,dcbfee6,e102d16d,d77e817e,b4b6c187,2ffd96ae,afd6d9c4,3c9c0517,133a4b7d,34c1c2e8,f398f81f,f6f0305,28d492e1) +,S(b74a3849,8b701b41,29eb5abe,8dcb13b9,fff0f191,314dd293,9c38d0f,4563c8ac,9d844e57,e50a20fd,864d6f7c,5a677855,689be528,f8431186,ffa96679,9cb9014f) +,S(c35c9cd0,4afb20b4,3fd1c337,5a952ad4,8e9a806c,a64aa4b7,52fcb204,5f89d26c,b041c6aa,4a83efcb,dee79d84,19e195b2,48c765c3,f069d5a4,b7e87792,79a9c65a) +,S(9a85aa58,753868b3,f04b2af4,479141d7,11703dde,e5b6e5e8,fea8ad37,d0b82b96,465c70ab,aa16f03b,d24b8075,233ec626,4e062041,3bf485f2,551d9952,7bd75d27) +,S(3ec71bcc,e051f3e5,12d83c14,cbd23f49,b3e825a3,cfa4c61b,d12eb057,5c86fe14,f198c21d,e2daa56a,55294c5a,b033f1aa,45caba3a,9a950007,db35f05e,e9915bdc) +,S(ee1cbe22,939e1ede,9010e23,535bf33f,6b09e579,3737db45,aea48f00,b359ae63,bf604026,d4444df6,27f7d297,1dab6a91,acecb6d9,de53228d,47178017,921b90a5) +,S(ebcbf3e1,71de3a62,ef47677d,1ff4d027,5a8cd92b,bc889ee7,8dcf0c99,6746073e,878d63c7,bc9c7224,914a3f3,2dadeb9,95c6d890,a3823f98,5c3f574,9ef6ebe8) +,S(e4e92ee4,ce72ef15,b87c57d5,259520d9,b6066430,c090dae5,6e81b2fd,ab9db797,3faac465,4a03a753,559f47db,f5877452,6d21838c,9c1f8217,ebef6965,655f944c) +,S(fc1ce758,8e292b03,7b4ef743,12eb1f67,cf275fc6,7c1e3d63,5bc42dd0,deac1cc1,176b79bf,44f7d9af,7f7c791e,8cafcb7a,495bc392,c23899b4,2fe7963d,e65186d7) +,S(f1f5bfff,179e6a6c,692a86b2,1c95ef85,49482b3a,b97a491f,9e9c7056,ba94fc56,389257a8,a2cd3bc3,fb4f0620,5c2aae70,67041512,10c62093,13a2584f,8a39e143) +,S(980e7414,61c3e001,ba6bfef8,d175a141,2c7aaa2e,748c3323,ac744fd6,ab793eb9,6e37ddae,29e05e83,b3cdde28,d4286005,34cbb33a,636c4259,c7fa7625,1b31826c) +,S(f519cff7,686a5257,71986dc,7e6c1955,adb7faa6,a6f7a07f,66a257ed,a1b1c179,3e803eb0,8c765c98,7941d008,a93b8503,174ed4ed,1c31e97f,9eeb8f2,a55a807) +,S(2dd8d9ea,3851fea9,1ba9bafd,bcc5cc0,9011d939,10edceee,144e2755,ba8f8061,6147f1af,d4224689,37cd058b,4ef52618,7adfdea9,ce970dc1,365fe04d,1da52ae3) +,S(860c4262,9483537,47ac0c41,5aa00f63,2854f88c,d7d09b35,edefd780,1454a4ae,a2a7a22a,7d826d25,8e7dfc56,1eef0d85,d15378a2,80535cef,95ce6e2e,d73392f4) +,S(e76b20ec,17d82c3d,987d4ea,20535209,e0697f90,2c964b28,ae97ad0b,aed732a6,c97844b6,85f6613b,fdb7cec9,cc47f701,32bc1137,d997f8f4,ad182492,67f54bf0) +,S(26731d0d,12fba582,636862b1,62a417b7,718ec9cd,e3d047a6,50455efd,910ab88,3c10efb3,b464a61,6e2023b,b0736d6e,8d298609,47ba5714,3b1a71fc,9b542192) +,S(50cb4878,52db811a,87fe46f5,ed014db0,3fc4570e,8b2d8ea8,9865df9d,a224dcde,bb8488a8,7937ae89,88f572a0,c100e450,c69db48d,303d06f9,5d54bd83,8b39621d) +,S(fb69453b,1d67ffdb,670f9fb9,2b3fae5f,64b0c4d,cb28ba0e,7ebeeb21,ffb02a60,b0fdef36,92d881b6,3ebb1387,984120f8,d1ba17af,477364ca,41e303ee,a4fd2c39) +,S(a8f1280b,4b720226,19faec4f,ea3f784d,3f4061a,56dbbb99,38c7706d,8bb249b4,ebb3b571,ac505913,4572e501,4be7be33,a97e12b9,bc1fd9d4,484703f4,6e39b8cc) +,S(4292ce09,df305790,f17cb3be,30996016,420f83c1,bc19abb8,78b49027,6eacaa98,1b14d94c,bf2b1d1d,82cf1873,3461b76c,f32c8d5b,6746e2f9,aa2aa248,1c745d36) +,S(ac241177,f16f747f,b796750,49c83f8f,8e1a062c,9796b05b,8c5a5587,a4c9464f,dd057503,8261d044,ec84eb03,73065687,266b695c,ef5cb41d,1cba3b5d,9176cf58) +,S(692eca73,26bf2da5,7fd9d640,acf7f846,78e75c9b,86b18e7d,d7fd2545,751823d3,17d6d462,548ea78a,18557320,289d61da,14c3850,4ff03347,8f17fdd3,71c8e97f) +,S(d01b1a44,55ef5011,e4ecf946,ec02e6f5,d0e129d4,d2f59889,e823cc5b,6f10e216,84a4d89e,55e33edd,d54f38f2,1649f5fd,807879e3,388df988,34556ae6,57f91a0f) +,S(1eba61f2,96a788d8,9273a67,18f2a0cf,fb0798c2,393330f1,2f890bc7,9bfc1e9b,89f298cb,e8471046,2df0a6a6,b6c4b6af,505da2c0,9ee13266,bc47cd5d,2ddc9661) +,S(26dff8da,94603121,4649fe1f,721edcc1,a2300ca,b1a6d548,9c9b68d7,415980ea,d8264a21,55e1bbdf,c3b65862,efb9548f,3c4a0a5f,97f5b713,9d3da15c,90004e60) +,S(4e642b51,425e1822,1275f64f,283e9eb1,a3116adc,a6e25047,cee3bc0f,323fe676,f28b7d65,9125468c,4951db0a,bc35d4dd,65b9c5a0,ed27d742,47a68a23,89eafbb2) +,S(354aff5c,ee9a27db,37e7c97b,4cea476b,b4f3700c,e9c26b21,e94d2e1a,78f448a2,8d6907d1,624b79e5,6392d008,2f6a794e,99b4c4d1,6ca78dd5,97709c86,2930fcdb) +,S(5286d074,949369fe,8f69f020,c0b65f75,e76995ee,5f49b9dc,d570b956,8ffbdc3d,255ef2e5,3dd2c40c,1e462a45,27e6ee00,e0a23d3e,b16b05e2,2781de6,879703ab) +,S(b84a8346,c86e2299,9acc8ff9,1a893592,6bddeeb8,6fde121c,266d5f60,3268add7,31179a8c,79f40238,e1b80c87,81e46597,29f5c8d3,d8bea0a3,f65b403b,ef20789f) +,S(1e7bd5e6,63fc9a50,2258b9f1,14fc51c3,1b9dfc27,9022c67e,fde7872,dd12bb94,6287a9b4,555b146,7d250f11,e77ee8b5,7accefe,6d91cb6b,927611f2,c2c1b84) +,S(7ee68a21,37289ebe,7a5cfde6,be672ca6,9d28acc4,54d6b8da,9c96b2ad,37d2bc81,3ec34064,a6c3ca,f2a8aeee,9b24e023,3d7dcbe,b7acddcc,8a53db84,c570c83e) +,S(29d4b10c,f4be3bfa,a9d07fdd,da6ba7ae,f3adef75,67c3c33f,8d4d914c,f8ce570e,b6a74385,96a4f40a,40d03c25,2c7070da,2ec79e08,dbef71f2,422392ce,1058bf4c) +,S(7907c5d9,5c5cd647,e312a43b,42c3f053,50218f10,da6279c9,895516d7,328c359e,6c65a9e1,ec062a1b,f2abca52,fdeeac18,26888378,58f985d4,c8f1c987,64d6a625) +,S(cc436eae,ce11bbc3,36014fe7,bc68fcfa,e5bc2c55,c53430ad,fc994b8d,959d31b1,16160de7,d6ffbf64,d644e608,96052985,6b2bd539,66d7edb3,a50c924b,fa9706a2) +,S(cf023d5d,278d4201,ae659d55,6239dfa2,1b5fb30b,14adbea,7351b620,150ec1f0,d6007395,ffcec07a,6e71c26e,7575cdb4,34c473b7,57d4574,9e5154e4,d4990741) +,S(1a2a093,f718c59b,d4d35b73,2c547b61,12b6a257,e807a38d,71b04125,e7746a21,2674b542,652fa39a,1a2cadcc,3924796e,16c0f8b0,5d83f919,f8b93547,98fd4c95) +,S(534ed420,4b8ac51,7518fdff,224ffae,f712e4c7,6a84215,fac925b7,eeb799d7,35e5852,3ea6199f,b9fe497f,576dfae8,fa30782f,d24cd439,c0708118,dbd82155) +,S(8d31e4ad,9e6f30ae,6c78ff18,8f4b0457,e9ba646b,3a26138c,f11d84c1,4a00d08e,f0dbefc1,909396c1,3a1e36a4,844b2a87,e4b0b1cd,4b30e996,47839bcd,4dd5feb2) +,S(81748452,267405a,bf664379,16ff7f73,c418439f,86b73159,54c15fd2,2d2b3412,13d1209b,435b50b,1409389,9961f5ae,9f6f95fd,280beba7,cb3f3f5d,a0f19bbc) +,S(bca87f72,e604e885,64552b,edf380ca,45842270,57efe12a,6cc23847,658aaa3,ee508af5,28b77125,72c123c6,276ba23f,af26538d,5752d84b,54ee82ba,df9e3d0e) +,S(de2baa9,a19652f6,c0c0365c,d6e78cb9,d527e546,1240fc52,e8c59183,7fcd3fb2,aeb418ef,466c32fd,4cb5f2be,571672dd,86573941,a9cf9bd,73377aca,1ed38905) +,S(7b8ce1e9,14df7919,b54a0591,c077135e,556f6cab,c7665e5a,c0004390,22acca9e,a60a3ff3,9cd8ad49,c100b72,4338a54,d06a96a9,f3fdc7c2,fb8ae598,c0b40628) +,S(cd71c179,13fe7443,19bc80f8,205d7617,4d6d44fd,a6ac3d1b,402279b,eca50e75,9f1e73bf,cf3438d0,1f01d1a9,3f633929,ae385812,528ad211,967bf38c,71419064) +,S(42cad02e,32dc8dc3,4ba36161,d0816af1,619b70e,117da444,f4f1e454,73ca8fe4,97cb2134,5a259cff,8870823d,fe11031a,79e59d7e,dd2593c6,65128a8c,36e75568) +,S(98a89130,4f0652c6,2986644a,62a1dfab,48331756,c8b9e1f6,d473c03c,b98ff8c7,c130f2ce,cc506903,9ca49b3e,534ad484,b277e0ad,7b2a8733,98864000,e9a824e8) +,S(23c45c76,84762aa,7bfd39ff,284403b0,d7a4a128,6bd7b455,22c09d2e,df8a4328,f4ab7317,95c46f47,c3d46dc7,cb0d43de,d57cb274,ff0c350a,f0d79548,bb303cde) +,S(8b700037,d584c4f2,f65416f2,dbd37c35,9e6a7b83,108dad34,3a6c4d0c,6a21d856,8371ec03,9ed0066d,4e8e7d86,69169f9a,5a172cf6,c324c2b,ecdfc76a,c365ca35) +,S(da6164a8,d0fb4111,ca1d78f2,83e8180,4f4ae8,50ae8596,cdb97d9a,a30f8a7b,f9a8463,717e4f17,a77caf4e,10c11101,1cc0b5a1,c788307f,c7aba482,2a9a342d) +,S(49f37d65,a9d1a54d,1929b9c2,6db7d7e,c45924e2,9e6010fa,2202d47d,eb5fd6b7,f9b9b785,28f62629,7bd0dbba,9340c142,1e64895,b1befa94,ca677de7,686aa51e) +,S(8755f088,e26859a0,1a56b78,ba1898ab,12d80837,308677cc,b38e9c53,e36efa10,5d67013d,1eec7a88,215b4768,f55f83f6,434906a9,f2f6a9a9,de5df75f,6ef7e478) +,S(35321796,b7aba6dd,873550fc,5a35e081,a4e6d134,a127c534,69ff777,c609045c,47ff0f43,efa93f4e,f197a680,4f1e1133,c5c8301c,b49de8ba,6fe10167,f0a1e832) +,S(3abedd2b,644bd2bb,e77ab5ea,2823b42,83479fec,df2b3421,56fe9ace,612559b3,4269b08e,6c13b818,131824ba,11e3369a,87bbccfa,330e408f,17985b21,e5e32b06) +,S(e30112a2,2c23462a,a803dc53,e3277d7,c14b62cc,92787f77,5be98ffc,7c956de8,d0c7e3d0,dbb10e8b,7a9f4e0f,f93e7581,99d90f6d,d869368a,8d2ad369,4898da40) +,S(6250858,439c4b4f,30d47f6c,b9259103,bcdf497b,f09d3762,f1073f5b,973cd06b,3437f5e4,84ce4258,5584407a,fb0e4383,87e4c930,2fcc902e,cd26b721,5075328e) +,S(77ad4485,b8c94cfa,4e904bc3,90e93e3f,66838d50,fb16e09b,dcb39ad6,88f826ea,4dbc505a,9798879e,137c8444,750ec3c3,34c2ecb5,485bab73,6b0b9bbf,806001d4) +,S(5dcd3e92,e413601d,b9dce337,7a8e67e4,3852b8cf,ac41066c,ad579199,3ac0b7db,acccd081,35efb43a,306760ed,ec278f7f,36996ed0,d6367f85,417754cb,a4e997c9) +,S(3a26663b,adce051f,c41d2e6b,9b931851,e65ca385,15f59737,fc8c27f5,caff788d,2d647eab,af01d846,70110e,7272cb4,9b9db0b8,88a8113,bab5f89b,90abc2bb) +,S(f57cceb9,51dc98fc,712fe9c2,c024031f,4e3b0f02,5067ac4,b8bb0096,e4b1aec0,696093eb,7a8aebed,a751455,782f99fb,ddb2c66d,438a7bca,9c4df301,b7a1ea25) +,S(a89a4778,bca06e14,bdbd46c,948ccd36,df47c83a,2dbba9b0,93589406,be9b4a0c,f4224dd6,9d08262d,22b98e2e,4e781e6e,939d69ed,d59f30d1,d23f9ea1,6ef366cf) +,S(64738381,84fe8247,2b463f4c,7ff04a6f,6a3be92f,ba295d72,adf065b8,10b962a9,bcd100c0,d09f6e93,4fe9d58d,d58004d0,9ba164fa,324010bb,c973709a,2ce32de) +,S(4a683a38,21261e28,2e0196ba,d9f8727a,f7bcaa4c,afd5e686,6c7cffaa,3adc7774,b5aba4d0,ec3d9aa4,39b37f0b,15f40fed,913af371,b1b94f20,2cc93378,954ff3b0) +,S(1025e16e,fdaeccd4,436cfd9e,b8ee1614,53fee046,e420296f,53cc2e5a,bb5cb3c7,f806b96b,67ce92a3,e159b807,58f38f73,704e4d8,3bd611c2,25314400,f0c48f3b) +,S(6149d809,675a5353,6fe2217b,7f6777c7,60039cb3,5a0840e4,552e2ac6,db6650d2,e4ae636c,9a9808aa,4f49b03f,bd12f786,c72f07f2,9e397a11,68154505,b1a96ca9) +,S(ba24112,43888342,54ee8327,4bb03dd3,2fff3edb,4d607047,d8c141d4,c3fec47f,8a6bf123,29c3fcdd,38e6a18d,ed28c8a1,3717e997,9d0c366d,aa640dd,bad5c35e) +,S(c20df096,3c7cac7e,9dbaa259,538af550,35c00550,94ad4993,2190688e,7856a961,491e995d,16cf7ae9,85b8dd8d,6a5890b8,fb4f2c42,aea7c33b,ad84835f,b245d40a) +,S(6f53d8ca,4dbb4d72,d9ef3dcb,93dd2ec1,aac9f38b,1b4cb2a5,c76449d,4faf0c50,6784a02d,f449beb7,24156de2,486753c0,77bbecc3,27caee12,f7888687,4e7ae24a) +,S(e57e78bd,71a08f60,51c8a046,184757eb,6364ae0f,8eca86b3,51317712,737bdda3,a0623c7e,8a535f66,57116c82,da77554e,31a1d263,28ec0e8f,116976d0,f4385342) +,S(f52f6f29,aad496ab,9e0abd0e,a7cb53a7,7853e8e1,a6e5ffff,285e97c4,f7ab099a,3df7c1fc,6d5c5e81,8b5de4b7,66f2995d,c361511c,198a68e0,b7196204,559d55a3) +,S(da74f5fb,5c0a6d09,6fb26268,b33d9c86,ec5cf08d,8bd65fe2,59f836a7,3efb0dc3,7e50e989,de5e2847,7e31c816,42a51edd,8d0ea031,35423f3e,ffea07a9,48a62c47) +,S(2a2c9aa8,7bd45217,f341d35,9a9d2de8,35d14414,cfd3eed8,a2337a64,e051f4ff,bf9efdeb,99335f68,a01fd7e5,d8aec9f9,49688221,59d18bf8,a466c6ef,9648a1ce) +,S(2a3440b1,91dc5314,c6d0da7d,b07e2cf3,7d13bcef,1ebfd23b,492ad632,92022266,bdec24f5,c993a020,2f2fda24,e8707947,e4c1e9f2,2c34efc6,dd1e62d3,e2ae2b40) +,S(a3a9bd74,3d1d36ad,fad36e8b,d5544500,e0accea,d53d081c,28740109,e10942a2,cc33decf,f8cae7d8,dedab1fc,ea1b4c16,2cb71104,ff75c16b,66db334f,ec794ca0) +,S(5b83d48f,70a2f212,93dc724,77f4d87f,80db7eac,2b08d70d,308953d1,88804950,f78c0488,a10c66c2,e11368d7,690fcc4d,982ecdb4,7ed539c3,30d4b14,4248b545) +,S(dd5b46a5,6e3e4a22,39e210,a871db8e,d901ab96,3c6fec29,4140d77b,be9736a,d9b76eba,ebdd45ac,35c52268,ccd35df8,9e7136ef,879848ce,ae647c13,d421d46b) +,S(2f74db5a,25486127,6236bc5b,22214097,d1ff781f,3798f64,62cc6dcb,3f61a6d3,b6d635ed,256f6d2f,a91b868e,a3014db3,64647147,ac89248e,ca983c09,53149c1c) +,S(32adc0c4,1f7c939a,58640b8b,fde1c8ba,119bff26,dfe4b0be,c5058ddf,23ab2e09,cf317248,7f0bb297,d7d7772d,2a01d917,40beed83,3a35a293,66bbb0dd,3946ae3f) +,S(4fe53ca7,172da8,272a152e,d74c07ed,4e336cb5,85cb2ae9,36f9f301,87c6cdce,81f6d1c4,bd711c16,21cc2986,916578c6,baf42870,58b84843,27e46e98,81e3a8ce) +,S(601934f5,577fa2a6,702f316e,b4dfed9a,3b08dc06,5d3e58ae,63f8548d,9fb2569f,6df7d882,4360fd7f,b5f96f68,93b1f1de,55e19690,f6acf954,362074d0,30f714cc) +,S(79da708,8ff4806c,64492ee5,2e9dda2f,e1bec3c6,79fa3129,8173c0f7,aa79d321,2b1eca29,76f2884a,35167e8a,bd2055af,44be734b,b0e0847f,f90abe8b,17f9a47) +,S(602b8209,c39f299c,bc208b51,ca8bf691,5b8d4fc8,d8399186,7e589dce,79262974,f8b6cda,5d7ca83,6aac43f9,4791a5d8,a5ed1f05,af90f5f2,267cd9da,567f5555) +,S(57a4f368,868a8a6d,572991e4,84e66481,ff14c05,c0fa0232,75251151,fe0e53d1,d6cc87c,5bc29b83,368e1786,9e964f2f,53d52ea3,aa3e5a9e,fa1fa578,123a0c6d) +,S(4f9b48f0,ae9df110,70c4c5ae,2b012cd6,4599063e,5bd32b54,43548b78,6a06db2a,d5a7a0fe,3cafc78f,66f563eb,f6fe42ae,980cd621,bf18aa15,7bdeded7,dd5ea016) +,S(e46a5308,4b11349f,44661589,38bb663d,e1910aad,35de0708,5a053b5f,6c5e7375,da46da88,9583632d,fbf923be,9f07ace2,cb8c3d2b,fa6bfc47,9e1a7d32,e1183ce9) +,S(3643d766,b94b161e,323e64de,3c925040,d62f2ad6,2b60a674,15c8b962,1c071ea,faf69af1,1f2b9e05,db29dcff,a020f6d4,80835d4f,83d35a96,7aff1b5b,9f16fa98) +,S(96769694,c026152,1bbe1b48,544e05dc,e6bea57b,7fa31478,f6ff1b1b,bf497dca,4eb5a6fd,7d0dae14,9673b033,bd97c08f,8210fd12,c759293c,40782702,b3e30b03) +,S(2e41def,2c479931,89be0ff4,b4110e28,7f80fda6,f4134ef6,5c867e66,59a24d07,26a14d7b,b8388b12,a3ba1f50,e56ffb3a,69bde3c1,17441f52,158531d,c874c313) +,S(f39d941a,f6eafe0e,9a44fbf7,71eb63e4,db94cbf0,854a837d,b7f284c5,ac03c29b,1ffed770,dac4d12,2241f8b5,507e04b0,72cd5934,c03b0183,d8b62e73,8cbd7b73) +,S(90900d34,4576beea,911f8dc,c2d90625,1cdac045,28017d1c,59576449,50136419,60d38bbb,2a338102,da044498,a2b2c5c,1457cee6,eb34d666,b0c0956a,48161ad6) +,S(3a5e4627,1007f4a6,2e744226,f1d2b782,44a523e3,97b6509e,e3e1a513,d8ac2e06,50f01fc1,74cfc3f,256dee2,fa415f35,bcdfcfe,57b79d90,f75226ba,e8202449) +,S(f66ea256,f6d711e4,1ea5492e,f6f6e46a,b13ac258,a8f0eb87,a06b6c3f,13e24355,fb8a1c47,980ea6c,87ec2401,4c0f6d2a,8f32a2a0,6f3fd0b5,7fa00307,26243841) +,S(cada0520,19a16ccc,fbb6d4ed,6c7436d0,c946a485,ab3362a8,5c62580b,d3038fa0,e249940a,34804324,ac706963,91ae7393,421de971,af0f203,2b5f2d21,7d32ae6) +,S(d16f5b5e,820b7295,96bd5192,9dd830b2,ce208413,5c2db712,2c4e75fa,cb759cf1,70edb084,cfbebcd7,ddd36380,75e05147,6ecdd585,e228749c,e61e3784,6a448ed8) +,S(bbccce8d,dc6bae0d,cb6e5149,8c666f31,3dc31ac9,d4d949a4,84751134,d5f71535,4da772fc,63ff92be,5271b479,68e7bbf5,c8941f68,989fa6e,a23ce5ad,23f91eed) +,S(515f28f5,cd8b75c4,325e940d,6821eba,e7d5d2f8,e836b291,5f606152,ed4243fe,a13143cc,f5d2b8fe,14a09f46,68229258,e1855a82,6f7db2a2,4ba2f1c4,63668b47) +,S(bd2f46ae,a78c462d,8691ed6f,9d381278,68d356b5,b8fd7f79,df6ed845,21233837,8f645ed3,f3cc803f,7eb32f70,ed7d6fe2,84ddd9ae,62ab8324,b92bd7c8,79c4af11) +,S(8576f13c,c3d32122,69e10b51,2011a450,4f8d7d3,92e0f133,47d7d65d,f9e37dfa,fbbf2048,3fa0e131,2309eb8c,19eede8b,86ff9028,45b66195,8d19d903,f68b1a4f) +,S(70be1e91,8fdf4e47,d73f262a,bf2361fd,763a83f2,d31cf41a,23b8c9f3,8309db4a,82f80575,e4246ef4,c13fa48,8892943b,a1897ac9,dc3ef188,29f3f708,428bc573) +,S(bb8a093d,1d586b53,9bf54a46,1a353af9,173529a,12312361,c8064e91,4b41180f,460e0ed7,8456a251,cd68d66b,ccf5de7e,28707540,d221d65e,72334d85,af478269) +,S(7817ae4f,34d9194c,f4b30628,7071fa1e,7b976a84,754c1860,6dc4a124,bc5c2e69,25f4ec56,c4e3b1b5,bc6ed346,e4f8b340,6afe1c0c,f84ad7b,481be5dd,2cd55cbc) +,S(85c760dc,411f59fa,6feed8e2,a0e5bb5f,e72af5f1,2734c9a5,bccfed11,bf66abcc,92583db0,b57c9c71,bf0f1248,23a67e5b,89a8910e,6500e8ad,10666b26,cbcb8cc4) +,S(20d80d35,4d9d762f,f2c739e3,b1e7377b,d9ee7123,47ea979a,d4c81abc,5d5086c3,6e191d7b,8017a675,e8123b7f,1f1351b5,ef6ed6b,1b225cf7,48941df7,62f0efe5) +,S(3306922d,43f2c4b0,65f6d9c8,d1289804,ec26cefc,97090fde,86dc3e0,fdba5657,98a8cc9f,c93dd7ac,7079f76e,fa1c4065,86f0e941,9f87cd88,1b865c30,13c7efc4) +,S(b35c7597,54d37f12,440f7703,39223681,8a1b9aac,b085fc1,8acde6c7,3b2fb001,484b90,69b08485,95c58ffb,df5968e,2ea789b4,6f93d660,a7af6b75,13cd649d) +,S(9bd41b53,7f8bc303,6cc9d010,45922b1a,5c647f8,e90fd587,86ef0975,474e1f33,590afbf6,55ece125,da486bfe,1ff389a5,8b866776,8d2013ae,c25d03bc,bf0274ac) +,S(2a3a672c,a9b3aef0,bce89703,a38e0dcb,6950d93a,7359420e,5278f160,541ded42,4c3a94b6,13f3383d,b908ebef,6b62bab2,c95f850c,f88aea5f,c6af3b89,c2693d8e) +,S(31ba6af2,a2d94f8,d4df3800,353806dc,c8db945f,16dc5bf6,93794382,58f74d3d,ad19dd02,b290eb1c,ba5d915e,f60344c5,fc1e6a82,c5427f4a,236238cc,2329df5a) +,S(fa2199bd,74b014f0,5df0f9b8,ebf44a98,587c0251,e9c49bb0,5bb12952,bc869720,4328917d,6efdf5f4,b0f5c483,860e1e9b,41ab6ee,b1f5631a,66d2d213,b163f45e) +,S(417b9046,c7f53c0f,5ccf2847,692ab63d,8aaac02,e3bfd99f,30a469a9,8be22d52,78c15e65,5f309788,dff6eae6,91706e00,7aede9a8,3bdb08e0,d495d6a4,863b82c0) +,S(56ac91f2,47d51fd8,8a0e6eca,67a69ffa,6158f498,1714964,f33e43d5,6f18bc2a,351b7d5c,9e1b1a4b,717c518b,37b81c64,429beeae,26e7a740,c54b1a66,dd0680c7) +,S(aeba32f8,83307ef3,152d835a,a0babec9,e164ae70,10c90250,68507d65,37215f8a,8d747d39,35cf5f2e,6ff16557,7ccef843,7ce7e3c6,a41cc40f,dcde2ae8,582c4e21) +,S(42c7b219,9af00c97,693d6bcc,256ed047,79ee10eb,e4dbe63,d47d681d,21db5813,a15fb708,1fb1c7cb,2ce44a4d,f8958432,a5fd875d,1fcf7c75,c3c4865b,b219378f) +,S(4337b297,ecf365a8,88bfe19d,1bcd5fe,25e0dba2,9c39e2c,36ca116d,a24e5d98,49c723ab,c6541edb,cbc83348,5e06db73,28d1ef8b,c9cd9722,915415bb,2242b7ad) +,S(18998c76,1481932c,e968af0c,eb84b250,aeefbf25,27e4ef84,a2519a1d,b7f857bf,455ebc85,64518443,5cac9ae7,7f3289d0,91133054,d0bf9ba3,9b7c8128,26c97fa2) +,S(64c76320,fa24572a,590516f,1bfd8b4f,87767b64,1e65588e,69cb895b,6a49b2b,a39a2a5,c4795095,a03ae76f,86825ec1,78366c8a,8799d395,d39fe8cf,74b9603f) +,S(41657405,e35eb87c,a5ba5f2d,3c6f12a6,dea917a3,3b3b44e1,ebbd3bf4,812b0ad7,8e2169ae,36f1452b,4577fe78,7adccb53,4d0ed75c,2096b491,6b68dd6f,95ff815d) +,S(aa200fa3,768a4b89,16e110c8,f4a6315,7bfd4a11,2c10cb6,8b76e30d,c0391f6e,567bd959,28b21555,dfec898b,d7d198a8,c49b79d4,6905afde,7fb3534e,a584695b) +,S(7aa78328,841d2f54,b843ba48,c8c9c623,eb529bd6,9e584966,555f9bba,77131599,6b4a2715,e4b8478b,24da7e7a,64e2f6f1,32711246,29a583ba,1bb44af3,69f698ed) +,S(94b1a7bd,6a2767ff,459234f,c78fbbbe,48446b4f,64bbdfdf,dae34475,396969a1,8f3065ef,2273a871,dd29320a,8b9aa41e,e77e2178,e8b8854f,df1e88cf,991cc33d) +,S(6b957ba7,1bfeebf5,294c8cb2,7681e0c0,5407df71,37a34710,35fd98ce,d526573a,67e4808d,3fc1853c,5e5cd4ff,6efb5092,35c6df0e,c0a5f7f4,583fdb88,7a2724a0) +,S(8b274330,ea34100,3be93892,ab1fcb2b,f9a6dfb6,80bd9cb2,b8aa6916,43717f7f,54fa2abb,77855883,e627f828,49c71389,4ed141aa,9c9cda3,c99afaf1,7998db90) +,S(d3f64f9b,67362339,491274de,77ac665f,3b686372,499a12e7,5d145e26,7b58db05,c06116c8,52bd15f4,145284f4,3899faa8,9bea5850,4018310e,5c82a050,c9a52449) +,S(198926f8,ce0e4329,1bb9280,390f795e,870d071e,801b4d4b,c4aeb555,f237ba79,76125bd9,5b8d07e7,5e27658f,a0dcf10f,5d6c10d0,4548dd76,a833f206,d2b3d34e) +,S(1bbd4d,595152f8,39746cfb,6ddc2584,ee4358fc,6f878309,9adca58b,cf01a13f,18f534de,cceac5ea,7083cdfe,3de5ebdf,ebdc70fc,4f0856e0,b587e9fc,df8d7733) +,S(88737f45,b2639272,37cb551f,52022693,52457f,21db398c,1312e275,f5a3132a,79a5672c,2895e1e8,4b1a7b22,21ba0c5e,e3e61cfe,c95aa029,b2a179d,e0c496ed) +,S(cbf3e18b,1f277773,34cca35e,8fe1cfa9,2d68497e,46e7a252,4e14bf,cccb1e83,db00c395,65bd456c,3c9d242a,5f24748c,7b91f770,926ba9a4,1ff5c94,86bc3f99) +,S(8070ef0c,f186efae,5f9c8846,72a93a98,8ab65b20,2720893c,40b1a641,c7022f70,da9805b0,46946a05,46824cf5,a87fd838,cc85c853,a745d8ca,a249d881,127bd9e5) +,S(acaf984b,8fa45dbb,e84c5064,8b6fe23,5c57dcb6,21243e21,90286980,c3f71eab,46f4ec16,8259fa2e,f144dfb0,bbae2907,801b8c1d,f17dd0b5,d1db3bd1,2ceb278e) +,S(2893a05,91f9ecea,735e8a32,a57e3d25,e8916252,52a44099,4eeda971,fbfdc965,6ea29941,91e4b123,12b5186,efb7d255,372aa6c2,aaf12a1,8c3b15a0,7bcfbb6a) +,S(64974631,68f0cb60,9c926e28,5ed12df0,cfccab0a,58f11b39,dc05b644,c2be951d,ea74181b,2fa885e2,4344bb21,9f2509c7,d432b5a9,c178b406,160489a,31eafb7c) +,S(b938443e,513394c8,b2d4f7c2,9811039,918621c,5d3a86e2,d1bf0e88,ba1faeef,af47f2a8,c7d98642,50784f38,45ff9414,c52473c8,9b669be0,96387daf,c353fc85) +,S(bd1ee245,ad10f50e,9f8fd4a7,876346b9,24f4758c,cf69bb8d,42f6dac5,9d2a5320,776e2e3e,69d88d5,c26477ac,74ffe92c,134ce443,64b39518,af787348,e0039605) +,S(cb7ec68,805e855f,17e7dc05,4279d8fb,6d8e1320,67a486a9,7d49df43,c660650f,f50790b2,84c04103,11f302eb,71525fd,b12d7339,6d259b5a,91ce4fd8,229e903c) +,S(ef07cf7e,affbb5a,29e22a1c,7c84cda7,1968c615,fbde2a15,e1c1211b,ab30cf83,98f4a6c9,422630d4,103fc2fe,e4c80f2c,2ca5565e,25859979,815c425c,70ef574f) +,S(4ffc1948,4d7fcc59,ccce4ca0,d11400f1,13dc5064,8626781,4eec26ad,3e7b8fc6,be9ebe07,98ff3d83,cb5ac107,5dc87f12,d94b65e3,937ee669,61b4e587,7fb75aa9) +,S(cbdd5373,339ed493,b8cdf0ef,ac6371b0,fad1ad6b,2da4db63,b4ed68bc,61d18396,527de487,c3212d47,1f538b6f,f709c130,3784a7d7,c803e5fa,c77bfa1a,d6bdb13f) +,S(ea035b2b,d8a1d7e9,db7f6b06,5e003f99,4e650aa0,e3035fed,65e7bf5b,c67cb5d2,aecb4370,2219f488,86772e91,afe81c6b,2cd57e96,2a3b0edd,dbc64608,8c3761c4) +,S(de1a4fd6,c1d6240a,d6e9dda6,b2d43fda,911648f6,901ed0cd,99ba8ef5,99f8db89,effc94d1,61c0ff41,d1ca6085,371e2e62,f85f90b1,542d2cd,3a4223ea,884da03e) +,S(2e644141,e8d87ed6,e1215787,8bcffebc,d75e118a,f00fb7f0,e58cf5b7,e6a076ed,4aa858dd,f2ba62d8,6b8a7011,26d22c2,b45c240d,f65f85b7,320e80ff,cb34b8d2) +,S(3844386a,90d6b878,90fb78ad,8f2d28e,47ff8879,2d275c3e,956883b3,71b73a33,f7f5df12,1a8149c0,75f6bde1,2ca8ee89,ff284557,f17cd57c,714fd474,b365cd18) +,S(e1fe9b32,1b91d362,2b618cd8,9ae8203d,bde185e0,bab2fae8,ff7e96f0,74358e42,c590fe90,1797132e,a25eff10,f2bf2a76,cef4f064,acaba1d5,f8537b4a,ddf3e1c4) +,S(560a00da,2f57d821,b6a0144d,45898af0,aefbbded,a1e08a49,9cc727c4,b27a3c0b,64874e4e,39db1377,3bcb79ff,983b152e,5db86d63,4dbbeeaa,a8b0112a,e795e208) +,S(9f33fba7,7ec8de2a,c1b16424,856e2814,1afe9b1d,bd0cd1dc,e5cbb2f2,f379094d,97cb8cd8,1838e2a7,26034f19,b5decd61,d972abd9,bffe3848,92fb0a9c,26fe94b0) +,S(98822fa8,24057512,48f9da04,2a0cfb15,e46ee253,e06a1226,da75047e,72d7a1b9,3e9eea35,7bc54ac,da547561,1f9590f3,db975d4c,ce7c4cc2,a553df14,feb19285) +,S(b814d1ac,4b757268,6ad88327,32f0f84b,bc72875e,7e21707c,c4086a06,ac1dbd88,b6364488,3749a122,401b8ab3,c4a7b8a8,c03462ff,18d69c36,cf145299,f18a98) +,S(246484c4,1e42113c,cd39f7b7,eed9dfcf,b39cf842,85c28cd8,6233c1a2,bd043e97,f35025b0,2e31bdd8,41d36f7,9d0b75e6,80f431eb,44a50502,3877f5d0,eb9552d3) +,S(9f330365,7b41b2ec,d87fff0e,4284e4c3,bbe8c524,91d358e,847afb98,ff51db91,4b9a7bcb,221c8870,de176a43,d4f7cce5,adf519c1,75613dad,317f4337,72d5e70d) +,S(c2e78e9b,3c75433c,5f5623a,8f5a4dc2,b0e71951,4b16161c,225b9bca,9d529d25,1e75c8f1,938376ca,c6387b20,9b24a2e3,e794362a,d62441b9,50588a3c,ab9079bb) +,S(89340ec4,b6e81b7c,855c9636,b548aeae,2125c40d,2907f86,7ce5e6ba,a7695391,f739a94e,263e796d,df1cc2c1,3e2bc10,2b2a9c9d,55248671,575c3ea3,792c72c6) +,S(9204ff15,f1443cc2,78facd4,8d38a6c3,5d66a93d,8fd8e2da,a7e2bbe2,d6629d22,2b9de875,456b50e9,6205020e,c293ff3c,13120555,82727253,be10263a,7559c019) +,S(f156da10,41122fd7,ce6b518d,c325f5de,61fad9e4,a7bd684d,7abc495e,ebff04d6,c73294ab,f4f2adfe,dcbaa78d,2031a5d9,7f2c404d,739f5703,76e46a0e,1b631d4) +,S(771a2d78,37d6413a,13099861,6050c362,2c379a55,26506265,9fa7da02,3280fa75,8b6bc39f,5cfe1f5b,82bef0b0,f6c8dd1b,e4270304,d5bc70f6,6b600b26,5d4c9aca) +,S(14cd58e0,36bb2c59,f63b52b1,f40e51cd,aec29f0e,b1cc0401,8e512366,85a18f69,79c254fd,ed354641,744c7262,39ea4e8f,ea15b19e,746b372e,f270c8d9,9c5e2006) +,S(e5f54077,1060072,5800bff1,390a67de,cd539cc9,52b6b43c,22bff27b,1a8633f1,d6e1c6c3,9baa86c7,5838e691,f9af8a06,80274da9,b0f54b5f,4c3b2028,8d666367) +,S(b0eaaf42,9c072037,fbfd14ba,79693d93,6791344b,3d37c3d7,5b8eaf8a,e7429197,d72661e,4a171b65,4f124d9b,d0201710,bc237382,6a2f0341,51051716,9b7af26d) +,S(e022d70b,44edaed,35957383,284e4ea0,5380f92e,cf62ce88,3c2e11e6,604d67c2,423c55d4,3ba0ed0d,1455228a,3153e9c2,7aed89b,2c3ddc71,52d2b11c,91ab4143) +,S(92a2d73e,b2eaaaf2,65a70f07,b949511b,af1a3eda,9e5d8651,349a665a,4bc5ab5f,4492d419,4794d254,9a089fff,53a32631,5f1703c,5ac34049,92d68121,e00fa973) +,S(43409686,de50a9c,cf35ac44,47a9ceeb,b12f102e,3ee6003e,c96235a9,8db9cb30,2f781040,952e1017,8e4e38ad,bd9c6c8b,c8e1e898,7f316cb0,37d2cddc,4e10bba9) +,S(d349dd1b,643f8d4,1b83aa5a,d735dc4e,94542643,3888a4e1,aaaa0ade,2394cd12,67f2f057,1da2b6ac,295c71c9,ea00efe9,cf082257,ece35bc6,72adece,433249a5) +,S(9a909a95,7fb87ebb,35f6834d,272d8ce7,babad39d,8f8323d9,c6813781,66dd10e6,ce3ead1a,32771a28,7f624835,2a2f6001,c12f16d9,f7093cec,86386572,a2ddbca1) +,S(f38b1e18,df2a2a64,9a3be25d,3686b5fb,1d77f971,1214d452,a67bccf0,ac07fa0b,5c9e9a,7f71b201,ba11ced5,9c0a4623,419a20d8,c488f9d4,591671ef,71e65ea6) +,S(42360fca,26b8d095,df52738b,c2762ed2,7b909784,c12b79a6,a86e06c8,31535a67,6b6f4ce5,e43ec003,be88bc43,2bddc453,db93aec1,657f6f66,5dec1912,468345e4) +,S(e3d7198d,a7c5e3b9,997993ea,a32377b1,b87325c0,5a002a94,53404c36,303f4a1e,72437218,ece6148c,df742be8,35fabfe4,a05f19cf,3205e65f,5c813781,2053ef4d) +,S(39412945,a8301110,6b54f625,8191529e,2f93db5,bd68db48,d6bc6d9,687cb59b,b8db822c,60f5c319,18b05784,40a958b4,e08b0a80,a1015d9f,d2826506,f250f08d) +,S(4d275f7,7e0ee98e,76b857c7,ed9368ce,d93dc914,d54ad4f4,21d2c097,cd241fc2,ecb803d4,9b502911,f619d361,f952ab13,935448e8,90cc2f05,277e48ab,a39d7473) +,S(29364876,c1db9cbd,a3efcd5b,6599ed59,160b145,3c8a9e03,c013f807,869556ce,2bdb4af4,cc44950c,84f56237,95941f7e,43ffb56a,77df186c,2dc31910,f23f6ede) +,S(7531f4a9,63dccdf7,ab83ef10,d3ba1333,6febcf41,f4b21e55,d380ee6d,e4878034,4753da9f,91d56bc2,1e9628ca,2d6269b1,e1dcb1bb,87c55e,9c44034a,1ba36ae8) +,S(8266d626,3d12feca,440dce7a,4bdf8ac1,6050ca28,5bc16777,a3d9450c,5c286e08,2500f2bf,fb8a4eb6,6a5e7e36,399f633c,96d908e2,5cda4877,5455df2c,afe2328b) +,S(66480001,4f339f15,8c39b26e,84389f87,6d5e62aa,59cb63d6,9eaa86d1,4bc589e9,a0699b3f,e3eb5a37,9f078526,375ac319,f145ffc1,da8a42f5,96c7016c,4ad92e2a) +,S(f8efcc85,8b9c0fba,605921b5,e6c89343,f641e2b8,e1f45134,86b77ab6,4cc70d49,ba97202f,7086f0d9,af5a0ae3,35d9a3c,5f4de2e2,79278834,f8b1d875,50a9d607) +,S(a5c1227d,254324a3,b1ec627c,93abfb3d,6f2485b0,1d8e2e73,6c542e09,9c992540,c9189db4,8a163bb5,6d99bed7,f38a7f7a,64cfef45,cf977da5,a1d16dbc,86ecc7cc) +,S(271b2619,a5b253df,fbb655d,7702dec5,6c85bb00,9260d893,8e050606,b8bbaf3,58ccf3fc,22cb8f27,dcdbd174,6abe5591,72bca7e5,d5af3bd8,d86c9a49,3ecd2ce5) +,S(c9e1382b,20c79741,d81800c,e721d4f2,1202ba30,92cac36a,d90c1dfd,570ae16,7eb1fcab,2a47cea0,3a92f707,d799749,6f7a0dfb,f9a43f6,90d213b8,1231e5b2) +,S(574b25,65232a04,1d58cb75,12b48945,45897e6a,8bd47dec,b1e0941e,309f2,bbfb86a9,567d74bf,93fbf2cc,6a9c9dd3,474db8fa,c2b5fb72,38b3af8,fe4615a9) +,S(9efe86ac,a6305eda,4b520e00,4dff6c56,1135e7ec,6953d2b4,a988d508,63046c38,4f92a291,32cb0818,af7cbe67,ec3b4d8a,7afa4f79,91a9ae42,551ad831,aae9af70) +,S(82ea48a0,ff76fa17,374bf4c3,d0918e6a,df26cafa,33d87284,13aa2dcb,d813f254,6a029539,9bb555aa,39de1ca1,417a8950,49b4c2d6,26ddf8e4,a7086b1d,bf2ac9f2) +,S(c289483e,817bb06c,31352a24,ba60adfb,e3af2feb,de329f4f,5fbde755,bdd2baaa,3b7ee90d,8b4aecef,62b6854a,1feb595f,9c49945e,c19685c0,4b13a1ce,1c780a53) +,S(6bde46cb,b5580d58,ea68deb3,1b0587b6,1698660,d78a8300,1c740b4,96e12cc4,3188a6a7,c1cd166a,4894ce75,c79d076,a41cc5c,d142ed91,e096eb32,e9293292) +,S(d1d2a3ae,2844615e,57f0a11d,66fd7571,176738f,a066cbdf,4519ac1f,65827cf4,7c0cfff7,c01c196,8b7697d7,c51562eb,8271f936,5c7daee7,f963122,67f603db) +,S(b74c0c87,4d195557,3b551c85,2abf9a5c,e276b088,cfaa0be8,f6515ed7,ba27370a,f0cb0e,380c571e,fe5e307b,ec4ed8c2,6f0c325e,114d71b5,51e0f1f7,45a662ab) +,S(a9a71b9a,9f126c3f,a17c3041,2317e118,84950077,baee298f,47d42609,f9015874,c05f3ffd,b31bf0cb,7fa4be1d,f634cecf,f1b1137f,551220f0,8f34c2a6,a42e0586) +,S(d6de1153,a161f27,ddb51416,2b3f823b,2b1b99fa,3fa21c25,9b02274a,80dbc68c,6c620863,659785a5,eec15d25,9acbdefc,714fab61,4e766215,348c80bd,bc59764a) +,S(dcaa1dbc,3acdca5c,51f8c22f,359487fa,73a7dc36,2a796df,11292a74,776b73f1,dc4131fc,c22c607b,4833719b,1715179,b4b4d49a,958c7514,7c8c4a8f,cc85159) +,S(135537a0,c4be13,1c3aa93c,677094d5,5f3a1300,95499d21,2206a244,5ab6c,7ef69f1f,d2d3df67,335f0d1d,dd52370b,8f3ebcf,e3483330,48c2f045,64fb0f69) +,S(28f1d817,c23262e6,4cd572bb,e3fd99ae,751dd6e5,5e9e804a,fb3fe9d8,39de93ac,24f5861,987e3da4,2dae0e89,67c835ac,8f5dfe8b,d41e5cb0,97029b48,39e2cb7e) +,S(f7c4ef83,6e8fb7fb,8eb31155,c08102df,e0779b87,9ad641e2,5f8ce135,44294289,7f9a781,db339621,d6150f09,16eb9682,16470d23,6957a0d1,3629964f,1f6bce2c) +,S(f1f5ae5e,1ddc9b35,18b66f7e,25a735d4,ddc8d018,5112faed,a8da8f66,1a28b3e6,9dbff12c,97924d80,50a4a8df,24fe7a8f,5c5c3486,3edb7cb4,1c6d9ddf,b9ad4288) +,S(95f83173,d170ce9c,1ca0dbc7,4578b639,257c10a1,eb65827d,c2afbd73,8b654f,63a83ebc,8294a88,413c3c91,c6918a31,7d5ab83b,7bee35b8,b75d1cbc,3412487) +,S(f4ada65c,9f095e11,eb88c8e3,77d60553,96474935,91be3a7d,f8c83c09,6a3ff750,e7683f28,a38545b2,e6cbc87c,3dbcc4a5,2ede1676,1b0dd78d,3ac51a5c,ad861ed3) +,S(41afac96,f714db3b,1b7bcd59,1dc7bc24,40b82756,d9394fd0,3afe7ae4,299e5fd2,9c2e9c6a,3292ff12,426e98ae,ac654a44,61c52d00,5da7af20,474e9a47,499fedc) +,S(37f30b1b,2cb81c9b,61941fe9,cca35f0d,e1b8dffd,c42f3ffd,ccaa16e,e8487405,92bf7a85,e3401d51,d9fdd08e,1086b649,8086bb3c,a4c9a2bb,61b1d54d,8cb88a0f) +,S(2f577166,646e7eaa,21531202,2ce0c8eb,605a2199,454c205b,9d760716,584fb3ce,f0d7326f,e43dcead,5ae0dc68,4d04b969,af32e8da,ed624ee0,98567dff,3d5f446) +,S(8abbc780,92c5512b,5eba0af9,4affdbf8,3c2e24ff,bf9fe7d,fd57e5ba,64b5150a,58f5998f,c2ec19a,a495b974,ffeccf6d,bb87dec,49152327,91a167d7,f6896b75) +,S(e41ace8f,a01376b3,27c73fe4,7e57cfc,f6da7cf5,c2810aed,219dd065,c147571c,b590aada,3c2a714c,322d0459,272f98e5,715d4545,196127a3,7d8a94bf,776844a2) +,S(300c9877,8b6355ee,ddd80f7f,4124789d,7c0c84fc,9d9ebb5a,be714cd9,890f1d88,dac2ba62,c5718731,c8f5c7a,4e1a7b80,68c5076c,834dd385,20f5e93b,e39c9002) +,S(69e339d2,19d40f84,25a072c1,f7876c3f,dcdb6623,26ca1b5c,87681707,12e24c61,8d439150,59a44700,2157e849,9b535921,4cd47280,937405a1,bad0b86d,38babc50) +,S(e56493df,8e47a99f,8ab3ccf6,41fab7b4,cddd779f,51fc746d,a2fdd484,cbbdb909,68dba20a,559e14fe,d0806036,d41c18b5,9745319d,758c1145,b6e49ca3,e3f5ee59) +,S(37a91c57,8998511c,d39c11e5,86e00eb0,f76532de,574d9c61,1a34d38d,e7f50587,e3a188af,d2d8a24,735975dc,9da895,feac2710,ab9d381e,e5d1dc43,b3145f18) +,S(c5f059fb,5cc262e1,12c629c7,194d783a,6224016f,65e4d24a,86c52742,dee88c1f,1c85bf52,1a96a95a,5177792d,590b46d5,8c090705,1efa0623,ab15578f,b38c890a) +,S(566edecc,d605ceb1,a298c59d,78401acf,c6323c63,f2845827,62678924,9b8716a1,ee0d1373,5adf6f20,789f85b9,32d332ff,8c40b3af,c02010a1,5ad062d4,5a44cc90) +,S(327e7033,c6ef4f87,52e33d,bccb4642,3e6cf4e2,c3ebb4c8,db69ccde,db2c7c7b,fc49092b,2be0f29b,4aa3e266,709aeb1c,12266239,f7bd9263,4aae16e9,53e8db36) +,S(989a7f69,3ac0ac86,55f29704,ea6caff6,84ef5ae2,8c5f5e1a,1eae7009,97778024,573d127b,3396458e,74bb5bd4,4acfea64,e8eb1fd7,3b0b292b,d1b7b642,80dadfd0) +,S(9ca7672f,14f27f54,ed1cec4b,74f49a57,7ce313fa,4a665976,9c22cc61,b30fc94,f920c4d7,31d52a4a,30803f81,82df8d30,6ab14104,eeec11dc,d2d6ca0f,3904e4a1) +,S(db100645,654fe8e1,95831687,17e2721a,6097850,ed2ef0cd,e1d5555e,7847f5f5,2b2c3ece,a9c90ecf,34fcdf89,5f76c8b6,619287ce,e745014c,96281928,31056567) +,S(4e2a0c9e,82743b42,5e6110a8,f3bff14e,418a34fa,65269c07,bb94d00c,d53295a9,512ac2e3,e00bb04b,6b4b9059,a3ac69c,8a34e5ec,8dfa14b3,d98b2c4e,3cccca7a) +,S(c12b3f70,24ea8acb,5136f98,185fb1cc,60c71a77,2943b68d,7334352f,66ac77f6,b799f99b,6f4b76f0,1f09f5a7,bfbe2526,d67a195,83327323,9c07bddf,2544803) +,S(64e5a2e,daf34e1d,ebd7c0cf,616413ff,d6c09b82,bfa783fe,aa755464,8ffd7e58,e020e09,66f032e2,e905d611,adf0926e,7509a2a4,b51844ff,72651f34,3c2f4a50) +,S(2b0b8b55,fa734380,f6ad1857,e03f02dd,3d66ec57,2cfb3b9f,ef040895,3f0a838a,ac897251,a9146597,8e0b45ba,e1c880a4,147ce01c,3408e476,5bd9013d,9e73a61a) +,S(ae0e3d30,a2026133,d3a54529,965a9679,6523e8b4,1efd4c5b,d6778930,2a88525e,fb6918ff,85632d24,250be67b,339ab260,c80c087d,da1efee9,7ec5dfb5,38f80552) +,S(2ff9c711,4dfea166,ffae46cb,1f44c3,3bfa1530,edf23454,a83de862,8fe00dd9,53f667a,4441817,a3e38351,78195c5d,acb0d707,bd20e759,9b5e82c4,6f318783) +,S(cc027014,88b959c6,c043f60c,c42b1449,9e2614e4,c19f5726,3edb116a,4e7bf695,eab3f590,9b22f677,666ce655,149a5f07,7b5325c,2036dfe2,e572e64a,5bb6007a) +,S(1801efd1,3c8035a6,5efe3b47,68495d27,f9dbf45a,f019d455,84d68be8,28a945d5,dff2d19e,fcb5968e,f4ef49d5,9a82f8b,f44a5abc,e0b68568,1acbda1b,fa59c4fe) +,S(6da2a9d5,7b60962,357c09de,4c7ababd,5b698fe3,6e747f8b,e6ab78fc,3cdd7cbf,1e274e70,4aeb8ae2,295ac9f9,b37c0af1,71310b82,99acc378,d505bdcc,e275060c) +,S(7e8fc96f,6a9215dd,3bf9e8a6,ea944ff0,c7dfe23a,1a99f44c,832a11ad,bafc82e4,e9a4fbe1,e0c26ca7,f739ed00,c63f3886,57d09503,a808ed51,ddc872e3,b1342bff) +,S(a6362f3a,77d6d6f7,fe266ab3,78707641,9f53e133,718ccf27,559bb448,7e0caf64,c01622da,3fc2385c,60a5cd86,66f751b,e29d8539,f473cd70,8784d61,d2cc787e) +,S(51865222,28b47493,a3da19b4,7076c1a9,8582bd55,37c25557,44970075,9b37d2b3,f0f0b979,68638d9d,93fca65b,f40cb8ce,826558b8,52451ad1,7d0afbd0,44287be1) +,S(a2a0909b,a9f1b9c3,8c714ff4,f71995ab,4d80212,9e8ee8e6,7e8bc3d1,81d472ce,4123900b,d45ec7bf,71bfdf98,ec453392,8b364d1e,cd925a6a,1e8f5c5e,ec40068d) +,S(da518122,454e7f36,a63f5ac2,a1bf979e,f1357bea,f9f0c921,2b031f87,b83aef2d,bf877efd,d415e80,c828c5e,1b9dd8b9,6cb7f3f8,b9a0cb32,b6bd8f37,686da722) +,S(41c40c54,1a983125,e59aa572,910c5aa4,8a698306,d483f82e,6cbd7506,3947a87d,76dabb65,6b89910a,bba9f129,ffbdf5e7,ef840033,c30f4c81,4e86f101,a3bfc57f) +,S(c49fde83,87f2e464,6847c980,acc50d88,28745e4c,88a41318,709099cc,9aaddbfd,a65bc512,dfd07bd3,79cbaf9e,628be7f8,c7ddb4ee,6611fa94,bbb48c7e,ae7227e1) +,S(85b17d61,b6ee743d,4df21940,6d7b7426,3a6c6b88,e8c51071,7a1f0183,e0fceae,22b9e8a2,74c71feb,5046ce02,2f4bffbb,ebddc53e,704f6be8,92d3092e,55868fef) +,S(c8e1d37f,e6d677f1,3e752189,505639ee,3914afc2,c8d4e43e,883f5c54,f117964f,b0cacd18,d08f5a91,af46ba55,91f99497,ee4a7ab4,36ab48e4,f88ad5ab,39bfc21e) +,S(dfec0030,7d25888c,5a7d6f83,33112995,1a30baa0,b97add9,866078a7,e483836b,4e5a8a06,bf2e9447,ef466416,82af8e44,f407ca0b,6fb97809,56e13a90,bafaa00d) +,S(eac6c438,7c18d8c6,eed7618d,c9d3076e,c842ff6e,5f4d4b20,92594d7f,7f0be9d6,19d69bbf,fc0c1b82,ba71802a,c0feebbd,77a86a67,d734a163,4e823a6b,2265b8d1) +,S(9ff38c4e,4dcddec,a4824db7,97f6ac80,69432c15,9cbc99b7,4d642011,b3424cde,f72fa660,b7c1bbfe,df45b0c9,3cc84b81,266bd041,b94f54f9,1d26221b,51619ebc) +,S(5e78593f,3a5a3293,5f9e4f8c,4fe28555,9153f69d,d44b2c1c,146fc644,a5313f36,9d9d5844,dc63bdd1,b2d95b70,5d63c97,58cbc5a6,1b2d114b,89da9b9a,8afd9c47) +,S(a107c7a4,89284b6f,b01ba38b,3e221c2,ad31a48,77af9b32,d22c8544,71009ae4,66072d4,6be46591,ee386cd5,bc0f9f2b,653b580b,c515d4c4,a0fc369a,27d9f6b5) +,S(241f1d0,308d9845,fe2445ba,67929976,ff98e88e,cc23a8f4,190ce5fa,41b02af1,886697ec,d413a88d,fa15723a,daf91d32,9c881ee,c5ac9c74,366b7ea8,a7e194a9) +,S(319ee8d2,627f906e,83d5c6d2,6eac3b42,34186016,8b9a9283,c8790c6b,e48a72fa,59e496ed,a67816e0,3409f849,1cb458c5,76034453,65fb281,9d0cc427,3e9eaa57) +,S(1866811a,fdf9bd,937f4f7e,96985759,e0100866,192878e1,a2614625,bfca4822,215e0465,e85f9c88,2783a131,6b65fa7c,585f0319,1a642501,72e51269,d5b7ae19) +,S(7effbed7,b949000,5db429fb,8cf64099,3989675a,f7394ce6,9ff2f769,53992f26,6efbb5ba,28f26d4b,5256affa,cbf2dc0b,616d8b6a,c6cd2aa7,a1d09ac8,40c7c749) +,S(d8c72bd0,e59315f2,1fee45c1,937952b2,665c8d66,70f14bf0,957a4d25,2b168867,64c02d62,fdd40a6f,d11e2cc3,a73fc60a,8a2da31b,2c99ae6e,5a946c61,be56fbcd) +,S(710ec622,ce64f381,43b96bbc,b0b0d691,87bbfd51,fab4d47a,bcf18308,18d0db4b,edfd1086,526c3af0,c2e9b961,890f531d,3d275c36,beabb0c5,4963314e,4534d994) +,S(9427964b,9aeaedd4,9c168e76,38086ddb,70574f27,9e4c3348,68e4c595,30d51ca6,110b41cf,2a6b0067,eb3b312e,928583d9,e0026bea,684c57af,7300a611,5c4e2dd8) +,S(aef79435,a8b3ed9c,9eb515c0,6db62165,c5a2e816,5eaa4a5c,46a59b39,8f55565f,6616e8f2,1274c425,c50cb93d,8942aab3,3653511,3c3552a0,118b17a4,5584b91d) +,S(3ebdd832,3546063a,68f40193,59d72f26,f49f0ce,4a5af994,a4ac67f3,3074b5a3,12367d4,b29549ee,d0eba318,f395d712,db7962f2,c8e2d9be,ed895006,78460238) +,S(a38d9e5e,c52b0871,d0bc6bc3,b673c848,19af86e2,534d60dd,729b405e,426aeff2,ebe46771,d9ae6c5d,13895538,3c8de4d5,f6d13428,8ac36a1c,b01c75e9,f32cad02) +,S(e7d29f82,619cbb19,90c407f7,b452cb8e,334369a1,16901b0f,9f4ec342,48a7d624,7595ced4,618b5160,6b8ce230,45d7616f,15b6ce14,aa8eee07,42bec5b5,9fc4e614) +,S(ec869eb0,279227b9,4ae333e2,6018f00c,7523de5c,e3e8c4ed,f81cefcf,4043ceae,a421aa55,2c89c841,a48bdd26,4e67d82b,ca3fe577,64101556,ec6ba7dc,711ac92b) +,S(4549d908,e44a8c8b,6fc5c057,144a352a,6f07523c,e026fae7,c070ff35,c6ec5e71,71d8e320,7707e04,10208c19,e2c8dc79,64b48600,1a6d640f,44c1138b,7ab5dd7a) +,S(51bb6e9e,fef7b8c9,b0a4f381,3e1406b3,2cc7a53d,165b385f,f98144b0,a5b070b2,65282be9,dd794fd0,8a31de11,d46df7cd,5268eedc,aadf3bef,de5956b5,a467044e) +,S(7cdc3297,4c7caa82,44203afc,d48e625e,aa2027d4,d91613e4,5a83eba0,696d001f,b92b9943,3b1a55b3,b78027a7,a289e5a2,6060a411,6c2cca36,19253490,83519565) +,S(3ca9c6be,b8e989b6,a67722f6,d817a6be,aa478fba,10146fc9,3099575,609c9314,5502ed7f,f4b81bc3,8386bba3,4124ca30,74c6e0da,bd148e4d,6bb7f096,ceca2c0f) +,S(aa2abe6c,45edcada,f01bc1c8,38ed5e63,90e1a229,cc920436,864111e8,ad354d0c,1b8229c6,6f91304a,24c61251,f1ba2b26,95bb3da8,87154d47,c44dc9f2,f824f6cd) +,S(b52cae3d,f28c9d59,319f226d,ef73b60f,75466aad,fbe6f75a,2ab6936d,8e3bc7ee,ebee735e,22c091d,cc873848,8a7c958a,421e0759,2e17fa3a,4462db88,8bcfe220) +,S(c1085703,62a6dcb6,13da6283,23496169,635469c3,47b65661,838d9053,3821ef54,fe6442c8,c1e6a8eb,2dc2cac1,40ad4c7c,44511cdd,82b79cde,c38cf9b3,4ceaf517) +,S(f09e9d1c,fcaf127f,59d45476,56422907,83477fcd,2fa6c768,d5a3965d,af08c11d,f01a722,1f44fb15,bf428fc9,c5d7efd9,a5b2e663,cfecc9a2,7e8f964e,8bc15d10) +,S(602462ef,1e473ebe,d88b3b17,9d71b597,fd3e805f,e03d341a,36c277f,495c4527,f91db461,71411dce,aaad9f23,53f2159e,fed2a9b1,eb9d2ce2,844e1f6d,63a079c3) +,S(273a881e,8e0d99fa,104ae355,8126a20d,6b828d13,96bbc70,720197fe,9bb582d,5bb26c58,14a7b914,cd3b2f72,7f76b6c0,d1b40775,79a2c3da,29534a1a,684b0d5d) +,S(7c1df346,616cb72,b42f4172,36fc98f9,e8cd0504,1da47d9f,566c8df2,e80cd54d,ad3e7e0d,d602b9be,45ba8d45,6bc12558,73153c2e,c16773b9,390ad630,4fc41dd7) +,S(796e2634,657ff114,7394551f,3ce800b7,9ad644b0,539786d3,c62c6551,3d942f94,b65bbe38,ed587111,c480eb9,c30081a4,1e8ec66a,8400db11,bb1cc7c2,a14f1c60) +,S(5e2761fa,9985f68a,a469953a,2a6642c8,62b0565b,602fc206,193bded6,1a302bd1,5ba09b70,9db24f5d,2f47c07,51367d0,3715c9da,b7d430b4,713dbac5,7253e274) +,S(46458c92,fd341a0f,eb1ab038,5a246b40,5c004c22,98db90e6,164126c5,4fabe794,859d68b,345341b8,58afc324,263f1ca6,9d018fae,eecf33ea,f02a3dd8,d7446725) +,S(fc481830,bf817c1c,ffc9ddc3,d6f4e624,a410e134,cbfb952c,5c7379a5,81153265,a188b228,bd3d7da1,44a48e89,fd9db4ab,8dfe385f,ace8e169,a43a2787,59322551) +,S(42d9767d,9771a550,3c702742,ce2aedbf,3a780466,804ad901,7792610d,5eed03e6,df69432e,9764f337,3a2c782b,e02d2433,d2e0f568,d0dd83ec,e89ea1c2,5ad50417) +,S(37122c49,993ab297,72e60222,615ed912,462deefd,d28e04dc,dc72f4e1,b9477148,627ff4f0,924cfbc3,aa0422cc,36402b8e,410b3ede,a552408e,f1d3820c,5996e39d) +,S(9c548182,94bafcbe,743e52cc,a76e1ead,3619a557,a5cb8bb7,3140ea1a,5c6896c3,5fcc472e,b88e8528,ec71dafb,f70504c2,ec0478b3,209494c5,b53bf05,b38f7fcc) +,S(7b9d7ad7,aa5b1f69,75c4e025,17123608,a59277f,d63f2a07,7ae69b80,f65a2db9,6cde1ee8,714aa229,d01c14d6,f514ecae,c4a7f15c,a756812f,abfd61fd,d7d1bf8) +,S(af5ddaf2,c985560a,d656d948,e41e082e,6990e950,6c77d53e,171cdea,58a9a102,e348451b,72896ff3,c4839ff7,6ce16b59,1f685348,eff943f5,fd4581f9,eca5b505) +,S(42667f18,e957bd19,5fab366,2e0d1565,d26394b4,14e2a9a3,95becb69,2111293d,288dd2b2,69e9bb63,4e7fb16c,1fe25797,3c0076b1,aecaa2a2,e57020d5,66bbc7a5) +,S(5e9c7a1d,50ab8326,74c2a5a6,f32665ce,9be97161,5e59b618,587541b7,40b276d7,92283461,1f39af42,34292c61,2c70744a,ec466418,ee08b5b1,a298456d,5fa11f17) +,S(98c60ffa,f486b582,2b4d9ac9,7b320b97,8b52b506,8b46bc48,9a2a4f28,dfed8b2a,a1c26113,c2534955,812f42fa,306edbe5,70416d84,aedc132b,5807b29b,745280f9) +,S(92bfa982,1ed52cd9,3c286e71,f350e5a7,f309481f,d866516c,f0a7599d,c385babc,a3fc9796,c71ab4b1,b7a54e73,8dfe24f7,6f527692,9516bcb8,2fae9ed,b2c1ddb4) +,S(9be27408,bd8eb59f,ace413e8,402b0c37,7b7798b9,3bb18c4,ec197382,fa5b865f,11085580,19646a39,68eed2c8,1bb92dde,def3ec29,5024c027,f54e8bfd,a67a2f61) +,S(27cd6a6c,b7bab059,6b791ce3,8c0918bf,7751bc59,db9e5827,5b1b9c46,976350bc,890d5167,8fce2ac5,f13761df,68651e7,2f41d04d,4feb4011,a16f80ee,83faeda8) +,S(e896e14d,aaf96139,4c8f6597,a0c66463,5f22be3c,96f30e1f,5d8881ce,f468f2eb,beb004b0,512c1ab1,dc4d971a,fd88baca,efea7e84,dadd2726,bb9f2b3,b196030b) +,S(24e2d269,ac485401,634b3779,efab2c0f,a9dd2389,850bb3da,54ec0d67,e53f8ec0,de702ec2,642bd4c2,3bca2ca,663a05a3,f5beda5b,e41fa460,8929aa58,219e525) +,S(97a627c9,48c1c9e4,5d50159b,4b121a50,9b5c4d01,de0a7db9,5a9d9c09,681d1676,19bd095b,55399c29,fcad4303,7f5d5c21,8d5f3cf9,a7c90b9f,fef7ee92,6f3203d9) +,S(a70d8251,e604ec5f,777234c7,f9d3c850,33ed6760,1fa0814b,40bd5370,7195b08f,df28d907,74e23de3,f152c016,ac710d43,85325a89,6a859f4e,e126d50,acbccc4f) +,S(2d676c43,4b276472,ce01a007,13d78b17,27743a97,36f3412e,a7c8c15a,fa42f42b,be28cde4,6ef5d32,403b8f94,1082b684,52fa703c,339498ea,24c08ff,c9fa7312) +,S(f66c25e1,75167275,5db857cf,cf27c036,46c89d29,b4a0d729,28fd42b4,b29cf5,3ee23ad4,22c4a884,4c049150,cd9c18ca,8d2a0231,bad69b6e,5926de9,c7193201) +,S(dba47c4b,9d39d87e,ef44f81d,24e8e005,ce6e77ad,8e4fdc6c,29393d7d,2427060,2d5c6492,e53d000f,977eedd,4dc3b5c5,5240f28b,9fcfb597,338edbbb,3d8d7622) +,S(a17601d9,4f627dc5,5895aeda,e91da3b6,94788f65,f083b01b,bfdf8815,27e10f0f,74089fc8,cfea1b15,afb025bd,99905b3a,baded5b,45e30890,fa3d8403,360a1183) +,S(dd70309f,b84afe90,7e261a12,5fb7ac8d,1c24c6c3,54eb83d5,188f3a13,4d80e141,32014ac0,ac93a77f,9d35b786,2c88ddde,4bdfd566,f6555868,2a836535,44bed563) +,S(79fd503d,e746baf9,701253f0,4c6a2f3,cadefb93,920c83f7,83b57768,87037afd,3c5cb658,63180931,3fa20c26,647a523e,86a4e600,8e8b17f,1e0d690d,eca61b93) +,S(d1aaf37d,77c7d63b,1f4eb896,16a29a4a,1e72658a,93560956,6b92c122,ba0ff6a0,e535b7ae,5cfbba07,2bdf0e0b,bf435bdc,c7cac39d,9d9ae32e,cfd13945,3ca93bec) +,S(68ff1b82,b351d94b,9b6b74fc,2cda4345,fe525d58,d6599644,5c752757,aad93c4f,abbb0ef1,c422ac08,d06194aa,c5d93bdd,9186e374,8518192b,79818f3a,b465a13c) +,S(22785c97,18063e5d,5db73bc,f4ca6487,14393ea2,62ece24a,5c41c059,9610552d,9c08026a,d7a7a80c,24c5e75c,8a75cd6e,1933e64a,25cb98c4,157181aa,ae1d8774) +,S(626cb5e7,563fb757,5f066258,3fc21762,e2678063,a77d8580,8891f244,4f5ffebf,8369ff6,72c3c3f2,43516184,5a9851c1,953a6da2,5662e11c,ce170cbc,668498b4) +,S(a99f0ef4,d6f46105,80ffa430,b88a4f28,61c8c4e4,b6fadac5,5e668f5a,80d12d2a,972adf29,39db0083,77802c40,6ae2aef6,4e2f064a,f8304d3e,28fff33e,b1053d06) +,S(b243ce27,2ff0b2db,cb80a3fb,dfbe94ab,784afe3c,cab3fe61,1931de9,c7f02645,db2ead19,fbb8c820,c7233df8,fea51836,3e85b858,4622be9f,41a0448e,360b7559) +,S(c74e3c9d,685cb62c,6a71b21a,a1dff5,43efb264,543222f3,f8bdf570,4363deb3,987d8261,fbf23d05,a38358ef,c4efb61a,5cd550b6,1e833ed4,38734486,edc4b2ec) +,S(ff2f64a7,fc984d4b,d1c885f3,4c096e9d,d34710c2,43dc3047,8886ef0d,ddf71c47,14c06258,fd5e2fdf,1eec9125,7690c0d7,9eac60d,785f2497,65e1a85a,a06e906d) +,S(7d92c4e1,3f4cab24,d36e8a8b,140f743a,6819b514,f6a19bad,ec162141,bb712085,606b5762,2ec7d7d2,a9b19330,9da686b8,3e0dc920,e6be33d1,b726f416,81b698c8) +,S(3a43d4d,9ef45289,89c9487c,77951602,4ce0cc20,ffbcd518,a0bd2546,fe13b6c,5f24d325,5768905e,6ba28d61,e6b126a8,eedad2a1,53499912,dfba3fc0,d9deb36e) +,S(8e72f02,80105e4d,15cc67e7,371d0c5e,6e59fd05,b3c66308,67342a6c,eea25f8f,94ddc51,58fdb86d,f09870da,47b79b03,1eada5ad,9bbdd509,9ea1d9de,96b368e) +,S(b89cfc23,6dc02762,ca77f9d1,8343f12e,ab8789b0,e5872d6b,fd9d013c,ccef54dd,9c9a7285,45a5996b,4a6ce6f9,df860d11,c3ad135c,f1f7437d,2ba7b904,411141cd) +,S(e85ee008,979868b4,bb190b53,5624b3b5,6744a43e,2c473ebb,c64e4910,41ccb59b,d3afe70f,9edec50c,227e3b3d,7eddd1d,e1c9a8b,f842d723,a8075a52,12cbd6a2) +,S(d8dd6bf2,774d6d15,93cc8e16,d5134066,f7f90651,39915b3b,fb0d5d93,b6cb97b5,5a203094,5f734f3f,11431862,b85e9f8b,25f7e6d1,91512b2c,6d256f4a,535e26f4) +,S(77e081c5,328fbdeb,45fbd554,5d133d84,33968ef,98d36aec,3e6385a2,76aa94e8,2ce853f7,ca25f2f8,45a6291a,3e080504,ba597fb7,91a21669,c0cb6be1,14c2959a) +,S(510786ea,e8a49682,6820b82f,549f07a2,b5b9203d,b1ad18c4,fb9c479f,67c904ab,dc130385,4e4dc69f,f63e21ae,71dc8674,b39382c1,eab1d8a8,fbd96867,af9cd96b) +,S(2fbafeb3,fbdad5b6,4c121056,e080d0c2,1169e433,3abc0dda,bb642789,a242639d,a85d82f,d9e6a14d,e599ef0a,11d3eb39,5ff199c9,5ea5f1c9,2f3f8a7c,14405cd3) +,S(200dbfeb,6e6e463c,1f3fbbc2,6b5f00c6,aec80809,1e28eae6,73b2b5e4,7b12ae0a,4852a219,bdaa3d97,83e1f071,15491827,83212776,fcd1b44a,c59dc01c,bba95ecf) +,S(27b140f6,259f7dc,93d46b6,e52cdb85,3ec22572,54218ab4,1acff2be,24b8a3d9,3ceed09f,70cbadba,d40054c4,f130e312,28bb5d63,71a74f7b,c85aa7ff,c0583387) +,S(fe4941ee,535c5311,8222ec35,14c2b02c,e175cca,d728ca0f,cd1d64ab,e95b7e71,e9cdc9ae,286d651b,d89cb442,2a64ada3,748e0ade,585cb70e,d357004e,e51f56f6) +,S(317d209b,4cae94bd,36f443d7,65be2f17,ce47ced,59935d88,5a03925e,75ff1cdf,c191495,68fe571c,ff945af,4b6a801e,c942a5df,78a62864,5434a5eb,8a262d72) +,S(f951a777,764e30e4,7705f8ab,150e9ab,df32e80b,593cecea,d9f9a143,cc93f9ea,efb951d6,25f2223e,e6ccc6b8,b12cddde,6ac2613b,11ae3052,65570f15,23afd925) +,S(71adf0eb,f5fd8e8b,f0f229a9,ffe496aa,4f251af6,6e5a284d,3091f344,3389c8ef,13f47463,293a5536,674dfdf7,2dc73add,98ed5672,e7676425,39ce655f,6b6969f4) +,S(2ea0406,58c0e80d,499cff39,ad463412,c3fbab1e,81f6eea5,911c45,236be75,be52c74,6073721,f09743d2,9a0a4e3,d82c08ed,feee2234,29163bc8,954f923f) +,S(42352390,4b3e80c2,750c4222,33f0b1f3,a373442d,96278935,d9b7e51,b6182aea,7f582349,b27b5166,30c8e48b,a9603224,fe09e8f,814fa966,395fed67,d9221d91) +,S(524d3c82,a92b285b,96064bf8,e9abe0b5,7702a29e,dc08ce53,771fab9e,fa7dda91,a47a0217,fdc6b2dc,d4b68e05,331bfd5c,366a8477,d3ed894,ec747240,f0f29c3a) +,S(f6ee1e08,5ce04de6,6aaeb5f5,f232329c,fc83caf,d16bcc48,776bae16,c056f7e8,3328b26a,7e2bd49a,aa193977,4947d7b4,ccbc955d,18b27c75,c2f6ac6d,bccea4d9) +,S(9c2f7d2b,b88f1417,722b5d11,95077d20,2ea84e6f,9bd93dae,3134d16b,17273978,1089f003,66c8b435,ce73c592,7c5e56bd,d338a4ca,ee5307da,a571be3c,2dab2a3a) +,S(593a1eb6,730fb6e5,1fd24f15,253ae1e7,5897b7b,48efe28f,9b9813c6,ca99cc3c,fcfb7820,fbd22d91,bc03a630,f74e519,9e35c1a,a3b1cace,40433001,7744f079) +,S(62ba10c3,83a7bacc,bcc4bc60,37f87a5e,8ec0eaff,de5a39f4,ef352b1,51f957e3,c267a1b0,dc84a161,a565fa19,aa0a2501,9fd01e0e,d7a660be,c2a7e9fc,cc7bdd45) +,S(1de2ac10,deae62a1,63f641fe,3a4a9da,39e12390,14a77c6a,6d73c619,5f731f64,60f43c95,b6d7969d,427b5ad,782214fc,a512b75f,a6f50006,d7141a89,dbc8d2b2) +,S(f11a5552,709083c8,83d08612,31772f18,c48e9271,6acbaa6d,a43416c2,fd4e1d3,a6d0ad64,7cf48c41,b6ce397b,38d5b3b0,2be51554,da2f3f4c,df593514,a2d742f4) +,S(f4454640,d75697e5,21d5cc01,fca5c7f5,3dbad43f,116c243d,2aeae96d,7cdc33fc,42972cef,46fe7704,5d6d7053,1a74ec87,6b25996b,c4cf66cf,b3784f79,66549102) +,S(2bfaf073,97be067c,1b7c20fa,3b319fad,10905b8d,8ecdad4,cad2ec8d,a1b8780a,ed526499,ea97c967,3d28bdee,9970f4fb,9077deb1,5f823cd5,775cc526,4e590285) +,S(fc1abc81,2b5fed90,bde3ca16,3422f73a,6df6e058,8ed69222,cfec54f7,4cf5f73b,db1c6edb,471cfcbe,468481dc,4b1cd1c4,7ac68f6f,4fe9dd8f,af0d1136,972b975f) +,S(d838c2ac,82e02f9b,a376f92d,293c02ad,b717d65f,be31cc76,12476e6f,4c506a8d,d87a3067,388f8e0,3c176f6c,a7eab123,532dd1cb,3e0f6ae2,51d7b31a,35189377) +,S(4b3a82ff,7295749,a259d54c,a9a5e539,32c53ff1,33a1c4b9,2f697e06,b13ee38c,44372b41,a788456d,3f66a0c4,6c815210,bf60734b,e570a290,32db3075,ba8d6265) +,S(d77cbbf3,6731ad4e,325eaf6a,9bd52f70,8e79d290,e379c2f2,b8d6ad3,fce411aa,ee466d25,f07813c7,91a81237,748bda9a,51f4266,4a385b50,5259bf84,ff8372f0) +,S(3867f6b2,58920b82,6eca75dc,953ac307,bed1872c,c0f1c6ec,84efc6d2,eeea1483,cc6a6adc,e6078097,a013ff18,dca9c5c9,254d70f4,68ac1cf4,b8267135,af88aee3) +,S(7b008875,e85fc84f,618ea7df,f20f7f17,2123fe98,c07b5279,930b52ef,cc1b0a9a,3f3b30bb,8dbc9169,a5c55a1c,4150772e,331f7834,b50bb904,a8c56600,bf075f90) +,S(ba5b44d9,16304a49,87579560,4d4b796,907e9b7a,4da49a5,ba7a1d77,8e34ef3a,16b49baa,48219e3b,9bae124f,dcd4de,4d47ea76,3ed39e13,f874c75b,cf333661) +,S(691eafe2,7fe4120d,852b3a23,b5bfa646,910fe521,355a3594,342d629c,e2b8d9df,43a06097,42184dca,7c294fd6,a5227dbd,bd71ea1d,c4bca878,1887f9f8,b6c71d85) +,S(13a6cbb,c9f5a86f,35173e38,a45dca65,551377d7,c37542d8,44006e48,54a54123,ecf3809c,9a964d9e,ffdcc2e6,2e8faf9e,8a43d38f,3023c4b8,84d18948,8488620) +,S(33fd2af3,fb595cd2,93d731e9,1b4f0e5a,da665420,2dcc36ce,b712e8d5,e6f10e45,e26a307a,a8bdda4,4b981bf9,808cfa3a,80ca5331,b3a94c31,f6331e60,98ed2cf) +,S(75954033,59e47f78,76b3ba57,5a758493,b0033298,22f4e44c,15cbe58b,34b774f6,7ee9a040,70b8568d,b0a99855,3442c000,b6e6651c,a7ad1253,f8e703de,5e0458a9) +,S(79199fb0,c3b17e68,4e815e7e,8414bef4,b3dd3665,10d032f3,6505da59,6f5b9480,95bca973,f358c9cf,ef3aacba,54a055b8,abaab383,4191a1b5,54ac3ee,53d9a0ab) +,S(9705f4e7,962ece0b,2e7ed64e,a33fd40,6edd0bc1,ac8997b5,d6d70000,a51aa352,4d4ce757,ad4547a8,a126193d,8921d6d8,58f40855,f71ab99d,b2bdd728,499ff347) +,S(881af067,b841ab5f,30560b98,3376674d,cadeeb75,b8b16e12,df7da3ce,312fd777,ccc13fd4,512ef05d,7c10f62d,8b144b1d,7588be3d,1a3a3701,9accdec9,3483b84f) +,S(fe8f7a44,33c2c9d8,f42e14cd,97ad0794,41bfc3b7,2fd412fb,1f6d5f5c,10e99621,e5b576ee,cf34374,96dc4ee3,a846c79b,4c8babf3,cc46a657,2a93fdd4,b6b3b2a9) +,S(ff43c8da,18e08b38,3f92f832,3c34e83,84f40064,9e0506cb,91893abc,5c4d798f,a575a059,23a9da02,c0c9dde1,981dbd86,f5a75433,a4bb2fd5,2427db01,7ddf2e7f) +,S(4715056,b97f4e21,13485242,74bb1b33,d8f9d841,73678a42,ed3c6fd5,28db276b,b4c0d146,3521f1d9,fe8cd71e,fb98aa28,73a18bee,66fae12f,cabfa201,854302b2) +,S(85c9d808,c5f51d5a,c2a51394,cb83e7ee,acd85eeb,31a88814,9744871c,271fff51,2a7c3bf,23829b88,66991454,d6ec7f5e,185050d,1982deb8,b4992bbe,5b666a7d) +,S(c02b94ef,8b1e368e,3cb4b25,903445cf,f46b60c7,6d6d2f24,529997f9,7d70dac9,bbb97d29,bcff81e4,8d417825,ade1d28b,10fadba2,acf961d6,80a343c1,e725f3a0) +,S(4b1593bd,28e26f7e,431ac439,3d353a1e,fcb8b63,fee7adb3,e29472a8,38241df6,8a67a728,f4966855,26225b11,3ac9d858,3f184f8b,3ccc8ef0,d6e4e34e,f2fdcc56) +,S(f640755b,ba51dee3,ad650555,9d52869b,7a8e7f6e,4b9dcdd2,31d1cd4f,26a64dd4,7387f800,a53e290b,d4c29f6e,ec24ac07,91e0e3c8,55d14882,a48d0539,6e87e1c8) +,S(949346a9,436836c6,3df6f42c,d708cef8,16d0a522,914a606e,2276979,7789515b,a903932d,952a0201,ef65c847,b8754174,31dd41d3,ede5c073,31383b9,a8e2b356) +,S(1824099e,c769edfc,2390b1f6,698c22f2,cdcc9783,c5cbe45c,de46008a,67f91a60,f8405fa,81e04dd5,6ce051f3,bfa088e2,804a8780,37892ae0,adf42767,311bd1e2) +,S(e6b46fd8,e4633d92,8805f34c,ce95f3dc,683aa792,139c62f9,2ec8acd1,d601d341,533db813,f3fea63a,528faf4a,7cbf58d8,d6c0bea4,c28391d1,6391d300,cc1d824a) +,S(63799b30,dc19b18d,d48d150d,3d4139d3,a04c6252,f176015d,60a436cf,ff992b93,26205112,5ebf4dee,d00e72f5,ff064178,7f485cb,2ba35507,3c3cdb0d,16dcc41b) +,S(8cd02f5a,b1d5a02d,e85b88d3,ae370b0f,7fac5324,9f1fd676,670a29f1,2ead7338,358b42ac,ceb689d6,612cb70f,bc9bba7,511d56ee,c4390627,8e2f0961,bcc0d8e4) +,S(d5e167e6,d48bd1dd,e95aba41,bf33b065,f7612766,4a0a8991,d3ea1a9e,ddf82fab,6cc23982,d653cdf4,fc4ec9cb,3cd86ae2,aaf45f62,38257d70,849c2686,ae71d1f7) +,S(c4073500,6987f2df,1334f09d,97f00c19,d72b1942,5864b0cf,4ff19dcf,7c9bfdba,f6566846,6b461326,a9b366bf,30378f82,b760ff0a,ca568ca8,2bf0c9d3,ff7ff262) +,S(9df1e71,9c501bfb,8a21db2,a838318e,29a7c2c0,fb2deb91,1840c7aa,f0c4fde2,cd628cae,6d0e0c02,b0315ae5,4901e703,e977c75b,43defea5,80a5325c,fad00fc0) +,S(95176429,df73c309,23108ee,6922c597,1c91c249,ad7165b,7d08b84d,2a4c696c,3ecffc49,3b62dbcc,82208470,375c929,1994fbb7,240740cb,dd8086cb,e9c0fbe4) +,S(708c48e8,692b0d35,e13a7e0e,94be8fb6,f57fe187,34f5556d,a318f600,c5628c6e,9534e302,deee1d1f,27e0432e,9f6a2f00,5af7e601,3f7da9bf,e1cde320,a105a664) +,S(2775e17a,b82dc739,b5d62079,4b26be15,46275ec0,9d32622b,2991cca1,4e5b4c09,3aa6ee7c,80e8359f,deeb52c2,8da1328f,338ab228,8744d52e,8a9b7908,1b1ccddc) +,S(47c1aac2,39c4f31,cf334959,b8fb48a0,44da6b34,3c383270,be19229c,30192da,5dad651c,5ba6c21d,845cd402,59a051c4,e5813f5a,21228355,1fde158b,600d7cc0) +,S(f80f445a,4b864c96,1bb2bf5,9cfa25f1,eef459d4,fa28ac70,d77daa1b,b8bad15e,a383de04,6b8c6996,6d0b9da6,ce9f88e5,83cd57f4,a5f12c88,63f7ff70,b374ff16) +,S(2924e7b9,1ad33619,a8df436d,578b7172,b2208125,9f2d5bf6,f9cb903e,bd4d2f66,b8642169,e2319f54,348e4f3f,e15d1f06,afa41255,ad62ceff,a768bdb8,48841875) +,S(37d6087b,91a64ed2,8341854e,3a2b9ac4,4310785e,77e32e2a,f13405f3,76dc4d83,35a23917,e068bccb,a823092f,32e6fcdd,a3ac9f09,2c251b1f,9bdb9971,3df25003) +,S(d748a96d,c79f1be0,6b43691c,bcf84b4f,e000d2ce,8294cfd8,391dcb92,10f4fab2,75b4ade0,65da902e,ce57e5c0,4b817228,975c0927,aafb76c8,223c4da6,f05bf51c) +,S(d05d2a25,eb5084ff,262361ea,33b6fb97,9492414e,c255fa8f,a0233d06,e42cc30c,14bbbeee,cecdc8f3,85b51429,8aa03d9,ba57a198,5ba98f4e,75efab60,69a6f2d2) +,S(69ba995b,d137edbe,5aff3906,764eca9c,b4684bf5,e8a8c302,78c89d97,483ff793,2b1cf451,b6226596,9833e864,91c5db95,a79ad96c,701580b2,46de1936,5bb63e32) +,S(7f01e9a1,5d0ecf28,fde0342f,f506104b,3a50aff2,f1ec997d,9a82ff71,54419461,1c3c9594,a6b8d375,361e25d1,fedcab63,d2704065,a83470e5,e03dcc43,ad12dc68) +,S(719232fd,193b9041,fd201bc4,7184e4cc,f2413d03,f0f8619d,813a409e,56e48cc6,161fc718,7dccb053,5337ff60,9eae05ab,12fb55a0,65f82d1e,68b19d3c,ae29a953) +,S(15b84120,155f7310,3386009a,57bd28bf,9a63bcfa,46c8bd08,2f53dc86,76e78c27,47dd637e,c9017e2f,e9804e0c,840aca4f,188171a0,ea9fb605,1402c503,31737816) +,S(ff429d97,bd380047,7db52ed4,eba69914,4a95ce2,7414da2c,74c074,bbfec567,7b3a6fbd,6e635bab,34973f62,4df77c03,6708c00a,cbcb8f25,69a5aa01,d57b3048) +,S(ccd705b,16be74c,cf1f476d,12c77e81,37917404,b2611ed8,858b1e55,d50a6ee3,8741ade7,5cc7b252,4dd55e17,897f78d6,946cb4c,31ad9f1f,737affc3,40e87c01) +,S(65b61a5e,24b3c57f,91678e81,8300ecaa,94e4b406,8d499534,d54c37d5,bb65b27,90d75e28,aab97b82,f1b86fda,2ae0851e,f65ac4c7,a5c664fd,79c16a76,75ed0c40) +,S(671529df,8f4073d9,43f82bdd,758fb8e5,4ffe0487,c1a38cf1,73c1419f,7ba06ef0,c46d9f2d,1f23349a,dd1121e1,d51ebe4,454fd141,c7076950,4d854cfd,14fede59) +,S(2af8a76,e7a1697,7af8e70,30bbd2c0,73da3fdd,4c6735b6,8e823cff,901b0440,55565be7,9ada7153,c7165976,91ee33cd,7c34f5ad,d65f543f,72ffd026,26c3c1cb) +,S(acd81d6f,c5ffbb87,4fcb3b1f,b7cc730a,4def3fd5,ef59fc4,2fb9472a,6f575707,8e319a8e,c8b8ea9e,11ef47eb,5071b696,b87c0ec9,63e851cc,e0929646,1d181a3) +,S(ab77e7d5,3ab9e8bc,2052d0bb,360aa7f2,ae062ca9,9b91441b,d60ce8db,80ffb912,5f92b6d9,cb0ab95b,9eb992e5,e1d70412,aca90998,b5d6ed8f,dfa4c752,2df96b5a) +,S(798b8195,1a6a8c7e,f8beda09,b06a2303,1d7efaf3,7b663265,e0188ab3,78124046,9592da1b,baea430,3644a7e5,4e67476f,d91382b5,f1181de7,a1bf9d44,e02b1bf6) +,S(f2486aae,c3be77d,8dddea22,488aeb4c,9dbff93a,24ff6f29,ed6d528b,9777b096,8e2b2d50,fe75c847,7c50327f,e36afb0b,d8409b62,8d83a8cc,41325aa8,4829126b) +,S(222e3d09,3b8aea8b,e0f64ee3,3aeeee72,d16ca088,264f4333,f9397488,146d2d54,eff500f,bfe6bbc4,1c2dd16e,8a0ebd79,37ba1f78,ccb098a4,351b539d,cacdcaa9) +,S(6768d3fe,7ca93476,245a18ee,ab53e002,4f99241d,9c321bd0,165b7d04,c121c1c9,402c9d73,c9b99722,2319ff1d,9e1c778,c4dc825,d030a43,823aee8b,90272877) +,S(6eb6740f,b2f0880c,eff25697,bfd7815d,b0b62884,cf8c8ef2,5137f098,f22dda79,cf7e8531,c12f5713,c302061c,1f42e6ac,79c4b695,e458db68,5209f03f,1485c86f) +,S(7101f348,4eb05a7e,aa0f385f,367b6a7e,5ede8959,71729ac2,950006aa,965fe51b,8d1fb913,a040fb75,778fff9f,c71afc2c,2605595a,1e44944b,e264f893,10d5c3f3) +,S(75a9e45c,acc6a25e,3fe4b25f,12030362,a0de03ea,cefba87a,11c8e6d3,e886579,52a85995,e91986d9,26a02cf3,1001fd82,854c49f9,55683f7a,dbe7c02b,cff69c6e) +,S(31194d92,bad76572,98bffc54,27f99ade,ceac14f7,830ac1b2,954d6730,3737dcbc,99e81c45,f5318eee,9d2449fa,33cc5bc6,8c556ebc,dac2ef19,a2d1ff3f,5fdd2832) +,S(904fa3fe,76fd6f43,86ac6138,70b4cce3,c1d743c3,8457d23c,522958ac,bd505af,94273262,1adf4633,79e929e4,54c70595,8dae9bfb,3957a304,5c8aae41,a7c1763b) +,S(1d1861f3,1a828b32,3699aede,f3fa265b,40de142,78a7df26,b5fa93ff,a4a8e0fd,b9657781,f13ffeb2,8e1306e3,b84bb965,3ffc30c2,63a65f61,1995f44d,d899f7dc) +,S(3bd33def,6de1a5d5,e5ef0289,e8565dce,aac95922,8443c09b,73ce545e,6819ad64,993f0109,eb560bd4,97436627,9a70e9bf,8bc9851d,f52441c2,97535ed5,d4f9c810) +,S(ca1b7d45,2a39aed2,a7f27b24,8e5a07c7,e4c257eb,7150e61c,7bec7f6c,58958634,ab11fe1b,c0357c37,b7da9804,39fb5481,179c0f7,442af2c7,298facda,3c4afcff) +,S(273a95ca,dee8386b,53ff29a3,6ce7d9ac,df145f7d,5f928f61,da6d57d1,8671aa58,88a6359d,bb06537d,1a6c6d83,24065284,315a031c,73c53ac2,adb14f95,1a5bbe2b) +,S(7ea4c0fc,a139bbac,553ad79c,d3921c01,c06923f5,29446279,d0f910f9,ac5561e6,bd049d47,45830e2,f31e7982,2639f198,2eb71c37,71aed93a,54dfa0bb,296dec96) +,S(71f1801c,a2babe5,d4793240,15ccc684,d3823f68,fcd12ce8,bc49607,9607d336,41ed07d0,8384e54,209b7de3,7e8fe7a6,14430c0e,439dca6c,f5ae6ddb,1ff1b4b1) +,S(b2838873,652ba1ee,ae8aec51,55541a3d,7000ffd9,6279cf2a,1c90582d,21cd8828,47ff155,73f5e3a5,245faf65,86afcc31,ee4d19f2,a1efc79d,2a0b4811,d27dce5e) +,S(34ca8da7,22634bc1,6873fbdc,c089224b,d9f8164a,6bf0acb5,b68d898e,b55a3e21,d8afb760,36a9c91c,7769055,d85a3ff7,1f041a90,5192df4b,73f9100c,e5c5d986) +,S(212cb397,d97341af,ca0cf5b2,ef6d796b,4b76eb87,89c3915a,a0e72337,4b19cc8f,f06e2cec,5f29f06f,97685f50,1126c50d,ff17e273,2f78de64,875c35d6,42f170a1) +,S(bc0367f6,43bd13dc,32582dfd,e7893f69,d5f29d2f,ce4b42e9,ffa8091c,6ca6228a,9bec6c89,d1251f06,4aff3e44,ab59ac32,c1764179,7b96f73f,527ff429,74556e78) +,S(8fcb1423,5d8e8894,5ab169bb,4d198e4a,5e489e33,cdeb69d8,dec100f1,a9bd5672,fa1cb396,bab390b2,60302a46,b4408427,c45ae320,5b1d1f5f,e52db790,e7fc057c) +,S(70ad8505,6675ec20,cbc43e80,11df60f4,d4917e84,cca25044,e15c2fa,e51e64ae,f4a51356,af9fa7c9,a5e62475,df5b713a,b63d68e0,cbef44e8,c004fa61,1d5a800d) +,S(ada7af47,48074168,86e6df81,f9718c06,bcf6e6d9,846fa880,3ede1f6c,b9695842,f66d51f,50f427d4,dc748bbe,771d952,98369c91,c41dd,575b76db,988a582f) +,S(f1b87d8d,7323ebb1,1bb8108f,9d34f8e9,bf1e977b,a527c52c,7f045d8b,1102eeee,bd95703,51ebe7a0,9ede5842,47b755b3,7e2aa0e7,7e380b7,9bddf768,b4346556) +,S(93659d5a,d55264ea,c900c301,cfed7b83,1fbf7c51,766cc833,cc591356,492a0553,b69389e9,646d0165,afa137df,1c1d02a3,519ff65d,8856c89c,cf46de05,c0154beb) +,S(e9d2bc49,2a9b4ffd,c482f54a,415beeec,409a62e5,d1781f48,b1738f7d,8ed4ffe2,893e4652,2dccbf80,ddde313,f4f25383,8d639208,36150631,60830408,44305df5) +,S(1424160a,7bf1ad91,18103eea,372da6a5,825e0bc1,a8760744,229e2af7,906cb210,c94da226,96a75d71,1e6f1d0e,10b23e96,4f1519e9,1f63743f,209ef8a1,3996af23) +,S(7f902712,402e4bd4,aabe434a,eb5fa7e9,8686d058,e6f26300,c458cee8,9c9efd87,bc00460b,2aefb418,b16cdcdd,c88446a7,1b8b018c,15261602,669188ac,62f95fb5) +,S(d327ce7c,66cb0f53,e86e5f16,c8dc2936,2a133f6a,38147c01,255c61f5,6f72745c,4dc1498a,c3cb39c1,6908b85,b8c52dca,618cc6d4,1c6f95f8,353758a3,86bea436) +,S(f044eb19,c9d81106,13803b,e8bbfc31,137dffce,547bfd1a,d5396ad,e32db3b3,5ad4428d,9c4c3e66,7f8551ce,ab282cfe,8128a8de,ffccfaf7,c102b9df,7e526f2a) +,S(7a6c5237,b95d19be,af46a81e,bdd54403,d135bbb7,f3c03d55,f67c5cbc,e18daf4,62a2e8b8,47fceb5c,484fc6e7,4ff68fed,bd492c66,8a70c1d7,cce2922,a204385b) +,S(59c7fcdc,b069c0b7,bb772afa,f5c20846,ffae949b,47589bb5,80495bc1,b59f82f0,82ec588c,6657566b,71ba4d79,ac8e2c7a,c09b3652,f24d46ec,3358eeba,126c38ad) +,S(f8cf3c21,1ed4558c,c40d3dc6,dbb85e54,81d99fdb,cdf27ae0,ea01bd4,6b6543d7,bd8049d0,1c3df630,8951f5db,dcce3043,5506a5c3,e0a8bb20,54de9dc,87a9778b) +,S(3855d764,b2389d4f,1ff47189,33aca82a,4d2dd23f,cfd13764,2782ce71,524504bc,82c4ea25,4af2abd0,2724ec34,6aae3aa3,b14a71ee,df13df95,9446c0bc,759ef72d) +,S(77644b31,1de4f0d8,d30b1d73,35553dab,6d3e0e6d,af7e6ffa,48cddd1a,52de5431,645e17ce,c0a0735,737730f9,92bb7431,7581c930,695829b4,cdbf5214,f45916b4) +,S(a4d4af43,afd6afbc,b2a511da,a6537abd,56bfc0cf,76659d34,56530663,d9ca138d,be6c9fd0,dd2df31b,b907f073,7d63df34,88b5db5f,3d5ff747,a25a2beb,73bb09dd) +,S(417ffa3f,e673a081,f72c3d64,5e64bc61,2da352ca,fb66d1aa,aa8fc060,74a75be5,9ab8be2f,90849474,809472af,d5a7490e,cfd9ca4a,7f738be1,de093e0,68c50151) +,S(78175154,93115041,6cbd772c,c74212c4,4f19eb04,95e88622,f75ee838,caef73cd,37d4d5c8,ffec3650,26381b91,d7cb18de,fdaf2cb0,a5d94ac2,dd7bf7fd,34d0d3e6) +,S(365c560c,3acc28ea,f560c66c,7e76625a,3c2ee7a4,8f62ef0f,736253fa,b1b5121,25cbc6fa,96c0f15e,38b03f88,338f8dd1,6990aa15,dcec58d6,4517d37c,5b74868f) +,S(c945ad25,1010023e,9126b6cb,3a19a925,6c6757fd,d88cf808,a94fa182,8f5bac7c,c9a8e90c,b4ac43bc,ef08ae3d,fc66f6db,99df4abb,2679de5b,174df92a,d654e2bb) +,S(4aad85ac,45e6d57d,73822387,632863de,ac8c3fb7,b7d3beec,629c0e1e,2c2e0213,38eee8e1,9e81bf64,9641c192,de53a071,29c03689,376f6595,2130b63c,fd6a2708) +,S(2bc10248,b0f6596,adcf9f66,3f624461,907e37ea,7d35367f,24b9f69a,26a291df,e0ac3ed3,3016b37a,91a780f6,b90b7743,24ad0c30,50812b2f,4f35426f,4311c79) +,S(cdc05991,abd28f93,e81a2c0,9a04e1fa,eca89400,81fcfcff,eb91c8d3,93ddfde2,dfda4ac4,4458e2b0,3feb9852,d1a8822f,8bf90a4e,bc79ab32,afc9a1b7,580193a5) +,S(5a24eff0,af2dc429,ff4ea857,f8aab10,31d285ae,9c8beb7d,793bf9d,db46a047,179db914,59739160,897f40dd,b7af0b8,a98b6f61,6aef7327,b53b6005,9c4c8f9a) +,S(16c1e53f,51603ca9,374aae6b,57d15fdb,e7c1d2b0,b0545467,636fe2ac,7838183a,bf858ef0,56e09bbf,5d8af50c,7e0fdc90,8d1f6c1a,570594b,a5368976,63a183e3) +,S(792f1eea,71b92f9a,d893a116,ac177801,a2f2405b,1c6846eb,c3a6559,eb01ccf4,bc062f0c,c610ef39,311ecf87,a7866b9c,52c0df0b,be1e0129,3ccd0b7a,2832a79d) +,S(1b399c40,f057719c,f544dc51,51137fe3,917dabac,f0804dd7,335ba65d,a57378e1,4d6794d3,b6e8a085,41de872c,1dd333a2,bfdd0712,aa846f6d,380a775c,600b425f) +,S(138b313e,b9c45ced,e0cd8219,b888c51f,9f8cd278,abe16ede,c210bffa,ba238e4f,a199a357,cbc8042f,4b6d4951,2f0acd26,13f0f76d,cd6dbf7f,d9e8723c,e6ac56d6) +,S(3e06c311,9c765664,d0068b24,cf4ae1a4,8f401811,17c93122,84ffc24d,eb542338,63a65596,e5607f1b,6a9c4596,39a90d06,93b08ab3,2807b696,498e7557,673624f) +,S(3f32f9b,49c88932,574e5455,c179e9de,80f0f6de,ed1ed25f,8a3de8b4,bbf8bd2e,a2d2bb1a,5fc96f89,ef490257,bf42a9dc,91f49ce,e2b86472,8551fa6b,6a589f17) +,S(89adc417,ffccc50f,a129602b,f5b1b82a,2c4f5efb,e3382b04,1fe77299,46414ec5,4ce7e75c,291b751d,155c291,5aa619ef,6c3daa28,25da8bc8,e2c7ef54,8c253215) +,S(f33fbd62,6bec8c9f,6597d486,2f54f65,e9f208fa,7c1d619,a13feaae,5ce4e9b5,c8f0602b,ebb9f152,87fe2eda,3050b032,a6f43c8b,7726825e,df02b424,51593774) +,S(eccc8ab,7b90e2f7,e45f7703,a0e97406,117fa04f,4512071d,568e3e64,a4a7d6b8,8456f705,a9c4a0d8,f2f3c233,3c8bb367,fcc8a645,f1fc560,48e1699a,58a1b6f4) +,S(f6962b33,a7ad862e,58181c75,42743ed0,e6e31d5,4df1fdfc,a4e3e95a,157de915,af3d47fb,48515ceb,f9f7e8ad,2a0159aa,55c155a,83359cf2,9ee3202,ea9e6605) +,S(3f1f3c6,7996fb10,65ed5df0,2095926a,5c45d2f2,38ff59e8,42b9d234,daace24d,d585c9e4,f0a29f0a,28e3c30b,22228dab,73750706,5690811f,1104bd4a,6d0ea28e) +,S(fcae019,36290e43,d8bf93c1,6ad2cd5e,dc33592d,4081b0e3,4aedd451,6e6e589c,8e98579e,cc42a444,2dc710d8,8cd09996,c8acb958,b9702c24,3a207ba1,471165cc) +,S(548f27ba,355229d,23b7922b,5fc8efad,abc4247d,baa312c6,d89570ab,151f522c,e5597d8,bbb47cd7,c8cba774,ff37c81e,b7b63c63,39b9600a,cb77f1b8,86ab6fa9) +,S(e2f64914,e8bf347e,d465cf1e,f086b7be,49797db8,611803ab,6e439bbd,5c146fa0,8e69e76f,7c641e4f,15248257,77aef9b,88b27a94,72d565d1,d2ed7463,fc6ae76e) +,S(8c532a0,2d970c0f,1d8f9762,2298b40d,c7d362c8,f38cd122,2cdbeaba,2c13db1d,90f8a2e9,428d66d,9e8ffc9f,bcb7606f,568251b6,2dec2768,1b6ffa8,7062bd0e) +,S(64646efe,e3c51972,f6af7e0c,8052aec4,6fc0ed97,af566f6d,3c323218,62291a23,9e29e150,f6ca370b,36a76ee7,171f2ddb,a10eb88a,986ffc50,d6c8f4f7,287a69fe) +,S(6e8ba4da,1df8dff7,cbff69a,6ef65c9,329199bf,9a67d1b5,1eb1e1f3,473be659,ae7562c8,959441a7,35ff2188,3e537bd7,eb5a34a2,7e144a06,f674679,815d852a) +,S(8c21abc8,f7812c0f,6de0d7e1,cadbf1f6,c94c871c,d5b8e9ca,e76c1f33,2b6bcaef,5a7c9cc3,13be03e2,5410ed03,7e0cefe9,5a36d6fe,68ff46b2,663a0ca9,747ed53e) +,S(ce0e383a,7c487e14,26636ff7,657a28f0,10ce5102,1eb89fea,3426b269,2f9f6353,3f95a465,d43f7804,2804e9da,4c73c8ec,97fcb9f6,fdace280,532c0c0d,6232e03a) +,S(7e33097f,51477c4f,f4459848,34673fc2,8078b6c7,c01cb700,80a37ee,1d698eb8,c1275bc0,7317c679,d881d274,e49065a2,e282b7e6,970065ad,141c1ca5,ca2d75a7) +,S(ef4d9cd6,b1487e61,fb31cf42,9eff2731,d686eb66,cfb3f867,9317b0e4,116837a6,c4f6beb4,280ddd5a,24f6461a,6ea1eba2,3bd2ff58,7ff612ec,d118b76a,3d63be1f) +,S(f3edc145,2ee49324,f7890bcb,9a5f8ba3,ce53f4a2,df0c94b9,92c573b2,f3716290,995446ab,fbc9b27a,8db301f0,87c2ae93,5c390565,491c0dbf,552a9820,d3fb2f2d) +,S(c1f62251,7398e914,d6134160,318d20c6,87d17427,2bc62c92,bd170ca8,2bcaa975,1c85ae27,36735b76,d5328d59,3292f718,f6d6da52,1c75cab,fcb06720,87769e99) +,S(a7e81df9,605f0881,d4856153,3e310715,b206c601,9a55b889,7141321e,463dea8e,3ae220fd,1f361be0,f0b70dbb,a7df796a,eb23deb,5c5440ad,aa16fef9,7cae8a4f) +,S(1b69bf29,8f5df296,7a3ac028,87d4ae5e,f46af5ac,5a8cf326,2fe7282b,e46a536b,c9c624aa,2d99a71,ea375c68,419b38a2,d7e9d7fd,8880dc60,28c24f2e,a846a91f) +,S(cddfef74,31763b9,8df15cb9,6b3b3127,b31c9987,fd17251d,b56122ed,dbbb44bb,972fef4,2e935aa3,4c679ce2,6a32a38c,225f0867,8f780b65,854459e7,f24869f5) +,S(32fe1cef,2c8a5163,66b47d30,9ef01e20,ee07f235,e7c0129c,fcb70fff,60e957ff,9e861731,bd376124,8b33babe,c354ea,3d13b2c7,c45b436f,e754edf2,4fb4588e) +,S(a382fbe9,f4914119,d31d0ccf,6afb61fe,4a759657,26556908,505225b8,79c24b0d,aa300360,39a1bfdc,273e0287,c7c222fe,cdde6318,c9838a55,5136cda8,d2111857) +,S(b53b5439,9ae330ea,e13e2467,7c0344d,59e305a7,96a228bc,6d6914ec,1a80ef88,99809053,8dfc6c5d,748f43cc,8ba8a8e2,969d8d1c,47551a36,8f30ee30,d5fadc7a) +,S(621b5253,f11cfec3,fb4bbfed,98b0ad9c,710fe2af,6aedb8d,f521d0da,fb64169a,2a234dc4,8b716af6,22dd025b,63e05c5f,3b93005c,13614bb3,abe0dbe9,260378aa) +,S(83332b6c,cc9c3c7f,3163f442,80f5758c,1e5979fa,b9a500be,d5b315e0,f9435b04,85360612,258c1f1c,bda41025,c402dd84,60c77df6,8762d2d4,16aa16af,dcd30ea0) +,S(27c8d8e3,91202622,2f72d926,da01b10e,fd54e21a,7a4746b6,68aa868f,dbf6538a,88768e3f,b8f2484d,56c9fe83,fde0fff7,4d0c0a81,213ac090,e90d2b42,22d6eb91) +,S(f349c70b,bcd82005,2fd2e05a,c42556ef,6ee768d4,f08b7a91,55d1ebfe,60067e5,6d595c19,4011d050,c7c3c4e9,e7aea90a,93fdc5b0,71d6c9fb,9f621a4e,750c6604) +,S(4966567a,b2029966,62b1368b,ac3f89e1,a0183b20,173a7156,edb827a7,13b24f90,6ef89436,c2bb3bb0,94910ee7,6c083e35,a097b859,16658947,1f59c33,37e21ab) +,S(4909501b,491da13f,78645b84,9bc63fea,75611b76,5ff6eb6,9a7414bf,913e0886,2c20c6b6,f2ee070d,c1dd4c95,6822ac5c,38b1acf7,5e093f17,c54b65aa,81014df8) +,S(1ed2e667,f5a2d140,18cd3ee4,f4163f7,bd5f898e,ee3dda72,bf84e356,10cddb76,bb4970c5,64fa4cea,e204babd,d869e36e,934810ef,68a22794,f9919e3,26db8e7d) +,S(c47bab41,a0bc37f,addf9c8c,7de86d68,c15d1a0d,85257d57,2a1d60d,4612f17b,e52acb1,36f47de1,1128091a,1a3cc3e0,e84ce767,cf8395cb,b09eea81,a2db09e3) +,S(e21068c1,4993cfc4,35490b52,5ece7657,f70825f3,dd2138c1,8f5ec6a0,c67a7394,cd610137,d48f8d9b,2bf99755,35fab6fb,65360fc,9db04a12,43027083,c732da) +,S(635f547d,47a72f5e,b069e144,6508a46,bd6a6f,11eefb87,da07e4f4,3ffaf917,8ea0a9f2,3da273b4,f324c8ed,81cb0bf0,21fecb57,54eaa642,21736923,2be64128) +,S(24632c0a,8648b4b1,fff2f79a,b3f8e64d,3837b6ae,9329eaa8,48565f02,45bdb47b,9c6d0788,c9e155d3,3c260360,862ab236,177ff875,a3823179,8146e442,f66e0426) +,S(43748dc3,cfb229d4,8549cc56,ecbcb01b,146541e1,5d2c3b5e,d59fbf7a,6b7bf503,9975a1ed,23a09906,3b87ea7f,2ccd88fc,b20607e,1aded9a9,265f34c1,45fb9c5c) +,S(8f848323,b8c41d68,31603b40,69be1dda,bb8750d0,11527a58,4bffdca,c3ae3ac0,77a8ac87,128260c2,86f5805a,b17e5a45,be81f83a,2a575c6e,2c88288a,c2d1b37f) +,S(29ebc368,b54d846d,bb5e8be4,81c19c80,2d8907db,c54412cc,6e2952ba,2948422c,e6b793a2,81d59d90,53aeb2d6,f79cbd1a,426f79a1,6860310a,ec72fe26,37c7e845) +,S(9414cbc4,ccf4012c,8c0cbe21,eb714953,d84bc602,9f8e4810,5ba79967,23ed345,ad1eeb92,89e4a109,2d132790,ece35cbd,da45bb64,bb6ae72b,39b9eb80,d57fdeee) +,S(1bd8565b,769d0024,613ab814,90f214c8,bea90a5,db1e75d4,11ec3dc7,288f756e,c050a46c,fc781e91,b79cfcb0,2abdae50,b69c2cd7,dcc56b13,1df2175d,c1d375d8) +,S(4f7584c,35ad66be,3d409154,eb8ded67,14ed0ae3,288593f2,76cec90b,629cb01,f4be9248,232a120e,11ccf1b3,e9c5a17e,1520fee1,8f1da048,fb01eb3c,17712bb0) +,S(5b0009de,7e85b317,ab127401,fd2f3ced,cffd1684,c4772b35,2b9c783e,1dd9f13b,f4585704,f531c34e,3377cb7c,e672c78d,cb8839be,ecfe048d,bb412328,b973ba64) +,S(c66f31c3,79396f01,2ea5fdbc,4222df38,37f85353,3f3ed9c3,ad13bcac,63b32815,7d7b808,4ae5e9cb,c123ca86,1b505242,4113ee84,bbac5ca3,ea1cd3da,6eb22668) +,S(33097f5d,c8b09934,26ba51b3,ee99e696,3d7ba455,e91a7af1,a57c85e6,5e63abd6,fbd26b3b,200c189d,c8b9e120,61869766,987401ed,66e4ed80,63835922,c270d7c4) +,S(1ace5245,a3b7ec60,b9a922d5,ffbbe43d,aa71cf0b,84e395f8,c37dd2a9,c85ffff4,72c0ed67,94708f9b,f29c51cb,b6cbb69c,6ad3f4d,10d62987,1c444da1,bb25084f) +,S(bc197b9e,4cce4c2c,bfb22524,93f9202c,6ed54e32,cd52f512,692a5af3,6b0c4471,d5137663,5182065d,a4d6be56,cec50889,3cad9b95,4d5d17df,adb084fb,dd673f70) +,S(66997931,334bdbed,174cfa73,3ecad896,13c6f500,b79a7fab,76ad0bc8,dcc7df70,fdbd3301,948e198e,ee3e7d3a,504ac560,ab00afdf,26940331,d49bd2c,6599435a) +,S(3ba86cdf,b38d82f9,7c20b962,103f79a,5637422f,370b08b3,89083cc3,1a6eb4bf,acec9811,76debb13,9bd7f981,9b476e1b,5377e32a,bdecafee,33dd6ad2,3258dfc8) +,S(f62432f,9db971d8,4c3acdbd,c2d915d6,6395199f,76e81243,fed930db,ef1603cd,ee89cf3d,177b4cc6,e5856acd,5de8757e,82269f4e,eb11a444,c2e0c797,4a7b5f28) +,S(84b41bdc,6a6dea46,ad6e650,5b280a1,b6d81250,794e0b1d,688aeea9,c067bbaf,9f78703c,b535b4bb,2b88cdf7,b5f0f0cb,e452fe6e,5cd0f2b2,ab8c2439,9fc00e7c) +,S(8e2dfea9,3ea64a14,e28f4883,98b8d455,48c52ac,a5399f88,28a42c1a,c89d4c67,fec01549,cda53605,335df10d,d8ed04eb,e09d7474,f69deff7,5935a499,f2781271) +,S(c3bc6dae,5401ac1d,3fd75e36,4cbc2fa1,dbd2f6a2,40e912f1,18b27759,9b105e0b,170fdcf5,5b739326,fd234506,303700b1,9c5dba48,b6f0cc34,a650c3f,3b63d6b4) +,S(33093e93,1b1e52e7,ac5a289e,27ff810,c2defced,e935795d,a10ecc89,a3c14691,7fbba584,5bd55ebd,a67dc842,1ae10fb9,2114f0b,d68bc47a,7ee87a7f,70deec38) +,S(21b35438,b6d1a3ce,6c765e,dc78dd89,3f121132,ecbcc208,a36fe734,d8141ef9,f6115a5,ed237dc8,f61a82b3,66fb508d,e2d516be,3b166a7f,2566bf06,eae300d0) +,S(ced66583,aa1bed17,30248edf,28e9e4fb,ade70821,1c2e48de,3782fc6,d3892df3,4f43ad36,f29da03b,f0fe634e,3c441c42,c3a81835,2407f1b6,cb38e738,18fdec96) +,S(c5a74420,f541a8ae,b0673122,29fbccaf,37f6eb7c,ccf2bec0,23a8573b,ee6f71f8,ae634c02,44263d36,c00a6e25,d25fa592,1612a535,4934d709,6c864865,60adb259) +,S(304a048b,f30f6b4b,2a725521,15b15ea4,8311c51f,c4cd212e,f0a4bac1,48b9de9e,8f935900,3d6ebf0d,129cb5dc,8a953fab,11ceeb85,b2123fec,154b065e,63bb3cd) +,S(ff96b5ae,7eba0af5,ac9875e,97811e91,6ecb66f1,3bb06519,72ebfbcd,5b9c2048,24af2186,bca71cea,e58a0b1d,b56aed1b,3de89cc8,70fd4e3c,31919e2f,6352a887) +,S(5909ce1c,df732eed,4147243,76fdb3ce,8b6d38b9,4a0b35d0,50bdce27,b1b701a3,2e44944,665e761,825cf223,90383a3f,7d3731bb,bf7792b0,37fc05e0,b224dfdf) +,S(ff6b771f,86d66610,6fa032b7,92844548,8ef9974,caf05ad7,cfb6b30e,abd1d527,6abd2a9c,9393e91c,ff77e055,7e9f6a86,9fcd0bae,3544bf50,b25f0427,908ba4b3) +,S(943ccf04,94dd1fad,1efda48a,12d9ace7,be919685,7e7fc5f4,befd7d23,3a1aa8d9,4f08b4cc,2dd93f8b,3751a23f,ca7e4f10,6014e01c,58791c52,3d01134c,1a0a7bd6) +,S(a79a7a7,a89e1cdc,908e0968,bf26c341,47a4638b,1d9cb5b3,ee6c49f7,405f172c,cb53d967,14b5be3a,e5497f34,ec0325b3,ebadcb76,b9838cd1,b3cee90f,f3bb8ceb) +,S(28ff2efc,71176efa,a861667c,d173f78a,4f548b36,aa33db2f,a50c0515,1c7b89dd,475b3707,db4ba15f,1485e165,68d7dbdf,8e67cdb3,37d79988,dc6e2249,d6fe4941) +,S(85b2c332,16a86885,c0704fa2,55b4ca00,223e897a,f0ae7557,f8687eb3,b1012968,a1f58d45,ba664056,efbcbe7a,f0ef479e,1f2bcbe7,98d055c5,7045d735,d657ea11) +,S(e9fc2d09,eefb32de,4068e2ad,d7bd3692,7a02b3e0,d354dd47,c2a70c9a,5cbb8778,ee009aa5,1216d068,3ee219b,bf53ccf4,f249d7ec,bd8c9cdf,80d0ec5a,5b65c312) +,S(da2dcb50,afd510d3,26e38af9,5a22850a,a1cc88d0,620fed65,763042f9,a0005d9e,1eef47b1,c3700963,5e16af23,f1308de9,ae0eab9a,b16c9443,6d501ebe,133eaeab) +,S(20daa29c,c6b166eb,ce717402,70873566,327891d3,ff7b6f08,b9b7da3c,1eb352e0,2ff6982c,ecd6fa4d,ec1d6692,92c3a326,a30cb526,4dc27a4,299dd3f7,7ae8a3fb) +,S(e16b08dd,2ae5be13,67547a53,496f9f4e,3aab8440,6cc34bdd,71b2ebf7,53674d9b,b70f724b,d9522b1c,8e43d60d,6357b5ba,48a1afc8,b7136c1d,9317a1d9,1ba06846) +,S(888a2daf,2d69db34,ff9485e,b06d44,c59670ec,3c68475,80753567,e56b93d3,ddbe4fa7,792e0b82,ac4753f0,5b271aba,8e804384,b7949a9e,9ba79fb6,31d4e3f5) +,S(747768e2,9090fdd5,2c22e308,131f97b2,ee6d8e0c,bf43d704,d50d60c7,616abd12,eaa75f40,8d1ce0b4,bb52879e,5ee7ff36,27b26645,c8ce3840,99dbac60,9cb61058) +,S(8569f2ac,1c7d131a,8d337cc8,87c00c1f,80897a58,f9131143,5a17d79c,fd8d6eda,504f0b44,252d06e8,2f8e700a,746a3393,85e43baa,a4e5da8e,dda7ed6d,83eacf71) +,S(4f15f3f9,a67221dc,4fca1d68,429b874,c4418df8,be480591,e57d6841,e11860c9,982c0d56,1783a9c1,a16bda10,87d29061,3f1154bc,4cc62a82,b795c54,a496b7ed) +,S(21e51a20,1f226e1e,3ebd56ce,6f7258d6,4e4f9db,aa425943,9e1bf7c0,144a92ce,4c47a801,b6a5a4ad,25c1486f,ec9bd0aa,428f3167,45136359,18d47079,75aac869) +,S(fac7e42e,8865ec0c,d0b4c4f9,dff6bf8b,e0f28336,395bdf2e,d5e2a118,9c0211a0,36812d9c,8337199e,fb1fece1,1997307a,ce656fb7,3bad65c6,41e6bba2,c4dd695e) +,S(a147839e,c91bc77e,cc568671,442d29ee,57f0f42d,7b9cb469,91064549,1a26d225,f404350e,bf7267f1,86120257,fa29fc1a,fc0d064e,2f14eeda,b730770a,c85bc5a4) +,S(d1212cf9,e5086804,44883c1f,4158f3e3,44a7900f,716ade2b,df19e41c,18636b8c,720b851,7b91665,128183a0,f3235c6a,2f9c21c8,e8c6ec0,5553acb0,27fc0964) +,S(13d5f334,a7ab2578,977c125,1a07d7a,2e4852ca,8927ce7,2dd9fe90,8b948975,973869e2,d1d0abb5,1ce31db1,ae8c3816,ff998753,479fe82a,7d87b6eb,798773ca) +,S(1f066961,6dae9e8e,76a9bec3,26bc2136,5ec754a5,34c787e6,b9abdfb0,e463507d,da48070e,b4ea111f,881f9fc1,2993a9bf,c6f99974,b3353ce,b5bd1cd1,c75b262d) +,S(729e187,38681dc3,c4ad9a49,59f975f5,907b15d0,114e029,8d4aad5f,69150269,dbf2ed8e,c60ea01b,6de0022c,8b035a7e,c1901c82,9e8d83f2,4560659f,8d455442) +,S(e92fcbe9,61353477,4d42435f,de190c26,8e3692ee,c2042fa0,2ee21687,1dfda12a,a75b5c0e,3f5280d6,41e36957,5e6ec5cf,585b1451,1f01da84,fb852cc8,2d64f2ff) +,S(85c2e61a,c69f8d39,e9c4dfbf,93f6b904,1ad35bcd,7f2b5c1c,789812d4,c8da36df,ca6d9187,694429e1,a5ca50b3,332ab11a,575264db,bf297752,f38fabb3,c0b53f45) +,S(10d17632,c33cc6b4,f5c2791,b5ae4f00,3adf9958,879c24f,10f147e1,bd1bc05c,e15ee734,f1ddec6f,45dbae00,88e4c5c0,be8464f,31205718,a8b2c929,939a687d) +,S(a6942345,25938972,f39820bd,27ea0bbc,92511dd6,827476f0,28fec86b,e25d609a,e06b3616,870f73f4,93f6d1b6,6256cb48,af49ee6c,b5296bd,ea73083,4f11d6e9) +,S(b4a7d8ed,2b3dae3f,43eba052,45b6c4c7,c401a675,6bb0d906,4f66d88,df94d8ac,ffc81c63,1a2cdb5a,fd7def11,9d07af35,74dcb04,e10a5ecf,d2b0a46d,90963456) +,S(5aebe21d,aebd3c57,285cb660,d9aa55d3,f84fb2ff,584f1266,3031e2ab,dda6fd17,22ea513,6a51b532,d178c40,cd5c8453,8f5994ef,7b35cff6,d9dcd999,daf1abe8) +,S(ac684664,194388d5,b796d64c,b4563aa6,69388d0d,83861c51,278316e7,2c8c7f87,cb9426d8,2dc90b01,97bf114,3f693e93,4d710988,26586e5f,f8913ab3,9ef41ac1) +,S(6f94bd49,f89e621,874c58c2,f27ce8a9,76ad2764,1627e835,6b82157c,24955250,d24330ce,4a54dc7c,5c7d9cf6,8f8622f5,e3633a85,8ec0d2ec,d8df3f9,bc7c5614) +,S(3f96c8c,e149947a,6d9ec5c,9ac5ff44,775e068a,785a2fa9,d0940905,a008f137,a91dcfaf,7111a506,3cf613d4,e360c9fc,9b7d9e40,30e00ce2,b120eacc,805f3f40) +,S(d805b05c,dfd675d3,b862a4c1,74909974,405a5b61,9b2a73c8,f3470959,779c707d,a68b544c,c7279f2d,e3a2abdb,fbb7fcb1,84366ef1,3cc3a66,b6d8cec8,3c3b6865) +,S(d2293c0b,d4189cb6,6be0efa7,874abe9b,59142233,6f2f71d4,808be34e,79df0e4,5fbc3248,87c54960,b9bfe70a,5cea3871,7f24f79a,3fe0d313,18cc068f,212682b1) +,S(931f090b,e22623fe,7ad49d26,e76b3c5d,e3f107fb,556f9657,facad9c,5b209d5f,cc255e79,d2a89899,865daf74,81aea395,848f57c0,1850c144,d5ad1a17,4b1cc087) +,S(118a6283,6707ff6b,c8ea72f6,285403a4,6e4e690a,db340987,a0359732,39e5ddc9,91f00fe5,e65a9058,36f9d447,d96af84,b6f5a18d,85c127ad,72221980,f7ff818b) +,S(81096ceb,5b6cb49a,d014ba42,d1d49e1,b811ca2d,2e6614be,1891c6a4,1f6a985a,da051c5,f8f9f3e5,78050a3c,1354b674,3f494860,6b04b8f5,b4dfe970,b7607e5d) +,S(9a80a438,5ff45ed6,2dd3559e,783eb47c,351b7e43,6ddc468b,9f410989,300cae06,845d1f99,21b69c5b,4628aee8,b0c55398,bee65659,e3e41cad,30e57bf8,b804b6d0) +,S(6a3168f3,b89955b9,7fac1d59,61e95fea,2143954d,fbbb6090,81c2408f,46747906,5b5f1f88,6778f108,3ae44a3f,82c901b6,12c741e,811d5403,c483c572,8cccc005) +,S(9a03ab11,78d165ba,23bd4298,58bc8ed7,797710fe,f4f8d8a7,3db0a90f,e1214af8,70888ce7,e61e4bf4,91512f2b,fa556f51,59a5550a,1d50a65c,a652b5bc,89e85665) +,S(8c90c18d,78b8d9e1,59a61575,48c14971,296c8c41,991dce25,e7878ef6,f4ea2f5d,2a5428cf,de628e51,a1644a5e,5dbb7227,2b97c0f9,b6909a68,2814882,cb1ca074) +,S(2e9bab7f,3062024d,84f7a5da,a02c9ed0,93327923,339fdd43,b68d6dd3,508a8957,c9af80b7,3f3803c9,f21e21f1,9523b2df,ea7e4f8c,9a376aca,4a147530,d2a43345) +,S(2734bf2e,718ecfef,64a95e7c,1fbe6a37,e2129898,343af84d,b5c17671,9a466322,f530098a,9f115f0c,e36a0ce3,4697312c,7d0a1e4b,df8a3ca8,f0a63631,e684216e) +,S(ab9ecaf9,500e4a4e,6e81b997,579b5214,4af3257b,8c8f40d5,e21c2a51,d56aab58,f7d38746,8e081844,9bd5e9d1,938a8859,d0aaede7,5743dbc3,ff30d51c,3de0f047) +,S(ae25f546,a4c09ef2,e5a9cd3e,85baa880,292b4d4d,4e8440c0,1696435a,cb1af368,46a2b3b3,7373840f,b739a9f2,2953c6c4,80bd59f2,11013d59,e051055e,f7f3da84) +,S(54285da6,4ef21cda,f597efaa,884fc00f,4e35abb2,bec04ace,54a83dc1,c12e6142,483beb2,144d7b5b,a47c2dc2,9225dd5c,b962a849,d46ff6e,5220b6c3,20cdbc3d) +,S(bece8434,4bc231f,60ad542e,d6a7857c,35a627ee,a2914874,c8deb661,37dca65e,a229fb80,2f9e72f,8e477fb8,de081254,fe1c93ad,a4d3b4f8,e9c2f4eb,3e2f6a95) +,S(3d55747,b148b857,472fe5af,1e820bbf,89994a2d,ae6c326b,26fd9cb4,fb5e81d1,dedeca5a,e86728a4,f635bc4f,1b2b162f,c9ea7dfb,efd5852d,b90001cf,bde465df) +,S(13c68219,d1633c73,59f6361a,88bf6a72,1846b520,33475715,fbc97dcf,75cde5d4,ce8a3cc2,39fc7f20,96abfe7c,52d79e9f,bddf0ce2,ab2b6e55,935413f9,37f83af4) +,S(e9e40ae1,a8041a47,274c481a,dab52f18,36690a29,be837433,43650126,d5b0a6ac,c19958b7,9c9839b8,1371f314,749147cd,9a22fa22,a55da9a9,577646f2,38c6bb7f) +,S(2e3b4553,7460a1a5,f7353a53,78db61c9,13af4371,9a268eea,6321b4c8,a1493068,f7ba5e56,104966c8,4959d3e2,290e5501,5ccf5cf2,b6fb5bb6,e0452c5d,cba54dcf) +,S(9855bc82,b9214b00,67eaa40e,bf670dce,6a59f3dc,4cca491e,db1f0f48,b4c62b8,a7d93f6e,3be6c73c,e9e37d6b,5b071603,87184e21,38478009,8d4c1c80,ccfcf435) +,S(37f820a9,b9342913,6d44bee2,69cf27df,67486bc5,233b8866,982f8476,15253979,fdcaea9d,aa629d37,7f345a5a,37c566a5,50dd893b,9d7ba88b,2a568a28,7870ca15) +,S(e82d2c98,a92a3b0c,690f6ba2,8070c59e,3e0cd0a2,a384d3b0,3cba9d1f,ded41a98,31e73a32,32d85b36,14833d34,4c7d502d,d09d7ecd,614b060,95c86be0,c8501460) +,S(bd492fc3,6dd4c906,6a071182,7eaece3b,ad46901e,b400bf3a,24b93799,9a923419,caada3c5,1e1fd5a4,6676dbd0,a7fd4049,8b93da93,bcd25af5,fdc6a0c9,1dd7798) +,S(6c8b46da,42d1ec4f,3ca2c4dc,15a69c80,cd8f0d99,7bdf3964,1cded32b,8629577a,d3ad4f62,729e42e0,f72ef596,5bcbc239,cbeb988e,e62b30a9,7f124004,c718c956) +,S(78b1e9e6,799bd3dd,854a25d3,4d356b4f,effee71a,ad0c8f05,ea9ebcc0,f8f5dd62,31503ed6,a26788dc,c07d7005,7a300665,d726ce2b,702e65c1,dd25f892,3931145d) +,S(f2ed02a6,63c5523e,3c68cda6,bfa4ab6b,cb53fa5c,15f0375,c8974eea,5aebdccf,3bde5c3,afdc0320,e3b92241,3220ad32,937720a8,d1477b67,773e725a,3cf36382) +,S(7e43f643,a45800bf,7e54d83,5ff6ba20,f67ab101,5d1aaa60,cde0967d,42caffd3,1f456eda,f473399,b57fbb37,807b5269,58600d12,b556879a,76e21459,5798d68a) +,S(df15e177,5eb73697,aa4c0a62,4b4d2ce9,7ccde2ca,66555d07,6430b656,61319be8,496cdc,f1543818,c2173dfb,8a60ee2d,8397cca,b16e4e53,b35079cf,b27311ad) +,S(edf1d706,295bb20,12dc1648,7940e84b,6707a3fb,91a14fce,ef37f669,c782e2ae,e3a0f2f6,fcd76c97,b20b2dd6,8e888eaf,9ed8f598,f08e4d7d,239a8964,fe019a2e) +,S(c15022b2,6b15821f,3be3c313,73d0464d,fd92cecd,6ba87c2d,9b18fb5c,16f8f6c0,78cd2370,d94e2842,e07961e6,92e9fa04,65d57f25,a80feda9,327581bd,ce136c2e) +,S(bd4df6b,b6ae15e0,109886a2,8a8f8c90,c6cc2bcb,b52dd105,e277da7e,c76001d9,499659b2,b0b4cb96,5b8e5029,96ced2e3,a6f6fadc,da01b875,72f8727d,8ef1446f) +,S(dfcec232,873894ce,525f9b4f,162f180e,1e2d6eb4,c846bed4,b2109700,8fbc0b76,afbc761b,f4c88e71,9c318f05,9a10ab3c,5a477ec5,33243b95,3f8ef006,69b4f92e) +,S(b0076c4d,e3c94fae,23659b00,5b8b41fc,b8473935,764e48e1,a9eb1fef,f5c94e54,e1eb3255,3c55a687,6f42ee5e,44830a09,fe17fda1,b84e8551,f3ea2308,f9c7d4f) +,S(9a1fe9c,17c4255c,c11e9fe3,3d66787a,fe9ebb0,99be88be,94b4c3f0,da2d0c11,e6aef709,99a8e739,6e23e1aa,c7ad1cab,25f6fd6e,62df02b0,96af568d,e88e8379) +,S(1d89a934,126bbc15,d9b99b88,b6c65106,e1d8b16e,799630f2,2576e9e4,15212899,b7e32256,92db0722,e9a79ef,7d95c509,37d64644,ed36cfd7,56780d59,a6f8f4eb) +,S(c60f5c68,b67b3796,3c462d4f,7530edfa,34546956,21bc80a6,ac2be433,700c7fa4,88f8b071,97fff0e3,a19b5a67,60dc92d3,b5507b53,5cec02c6,53f75a60,bf8a7e08) +,S(52cd2b6f,d9b2699,1b76499a,d301be43,6205761c,f768eec9,e6b7d6c2,52d9d949,d127cc66,1fa33508,a0d11a3e,ac782b26,26356382,f547e4aa,13802138,30ec835) +,S(1e44499e,a639835f,f384f107,fd16bb19,c21fbea5,cf4e3be9,20a34024,6d05dda9,41c6a8e9,a9042f9,950d12db,74fd0f21,8f8adf23,e961488d,27412c2,f2d1f53) +,S(139144f0,a56394ba,d1e53bae,360136eb,984ecc56,56a05cb1,c6727543,fc6861de,70394737,ff37e9b2,1bf174ab,6c042bb8,964f3d01,6ea1edc1,25ed3b4,2ed0742a) +,S(934ca02a,2454df18,61fcb954,6634e685,34fe75c8,b6db6eb7,5a2a74f8,654a2280,779e9784,266cfca0,b83caee,74fd24f1,6865ce3a,6be78be4,375fa15c,db195761) +,S(a64f047d,9e1c2459,77da8c32,9d35ecd4,af913baa,2d4b679a,7acd326d,886a3be6,e11e830f,f3b4ed6d,102145e3,b24759de,3210f309,8ec57581,e6014818,79112b2b) +,S(e1c688bd,cd629088,8d8820cc,df15fe8f,cfcf45c4,b8bd434e,2a15428e,818757e1,bc10c6e1,71e7c8e0,13b8e00,e77bb745,a34e7d1a,15267600,d130f6f2,18c77f7d) +,S(b1a30c95,123170f2,d9456de6,827afcc9,ba2bded,d955354,c6deeaac,68137358,9c76a0ab,c16c1caf,d3844346,9040373e,a678797e,dfa1b298,5a17d410,b04071f5) +,S(24cc27b5,fbb0291c,3468ba23,58f5e253,4c7cf99f,699af4d0,d6892bea,e6166e85,eaf369af,2516ba42,673c52e3,ff0768fe,d51aabce,2312b8dd,d7aa1ed8,cf9f71d5) +,S(8bb4017a,6166d1e2,f7fe8921,cbd31cee,bacab577,84da8a92,217aab2d,948f6a57,c899740e,6c476986,356e34fc,7182996d,a09cad72,93d78c8a,5c30d56b,88dc331) +,S(55d8b7dd,d82fdd96,e0ec17dc,20b303fd,e6dafef5,a527368b,ec99a33,60497f6f,fd624511,78bd66f,4361709e,44e72e9f,f4f29230,d1fff657,bbf84762,b7b8beca) +,S(82aa2def,5a5531af,519cbfe6,105dbde3,109d4626,ec47a845,5dbe2852,34c94df3,61160bea,9f83a2e5,8c2df91,925fbb25,8d1e60fa,6a147c4,ebc0ee38,cd811511) +,S(36c1277c,c6df7ff8,47c2cfbf,3cfa9198,804b03b0,c28e1636,ad3438cf,2cf6f7f4,2304fba2,74f81c74,5455d821,ea58e047,a7bb3b60,e32f020,aee5a2a5,16fe4833) +,S(f376fdcc,5b44cad7,e16c9e86,c00b366,d57b8925,fa49b18c,eb8856a,e0cd9119,2d6acd32,e4dee81f,489e3ef,11acfc8d,c3d0e7ac,bdf5c6ac,74fe7aa0,50a028cb) +,S(ea4e10dc,5372e9f5,d96e8ecb,907d3a89,97150b6c,39ecfd1c,c7aaacca,5dc5030b,b0896ea3,93b626bf,c2f486d2,9fdeb897,36d6be60,144fc3f9,5206666c,36d96ff5) +,S(74f392b4,b2664a17,9d3f0a2c,71b144b8,a376ea19,f1a9d91a,d181ca3,a6fdeb08,9bd4db21,428d588f,64ecef67,99b46735,c9523036,406d2636,c6eee083,e09e1fc0) +,S(3a36c842,59ba7774,a41a17da,f0e4c821,11c13a6b,58b82774,ca6962ef,cd4855eb,6ddad1ad,9ede928c,d65720c7,15ef39e5,f35e46ba,45d8ff48,2f095d2b,e0fa5e3c) +,S(9d77b2ad,5636a44f,16e73981,46b17ea9,7635ef18,8f32764d,eae50d2a,5c98c019,532dd027,a775861a,b9392b8a,cb2db097,eb5936cd,9d2f7234,f30c371a,22ee3eef) +,S(2e7402e9,450e2f80,e05168a0,f0c5f1bc,deb6117,ee46ac1b,39aae7e7,bea3c4ab,41e8f36b,5606fe2b,8ed6b3fe,f8821013,cf85721c,f242eb60,34b82afa,cd82fc3b) +,S(aeb2cb25,4ed0b5bd,81b33d35,e8f00a5c,6a6806f1,5314b320,de0c376e,533ebe6f,6b8116f5,2d7bfa2c,b3028249,fc83f317,5d761c0f,76833d0b,142c4d6a,29b9d59c) +,S(c86224bd,55d62c97,a00adabe,3a797929,4cca663a,ba3a3655,fbbcc3f4,5cca7895,a319a3b7,104f7935,36693adf,a6009db4,1d857353,fa950c21,844323bb,cd1cc214) +,S(1d1164cc,2c576a0d,d7b5a28b,cfdce6f4,d53ddde0,534b3a66,aaccfbba,3eefe561,b85890de,aa25d897,fccba694,7c470e45,ec600989,243ea91c,4670a,b44995a7) +,S(2b54fab4,13b915b5,ce76620a,5c493ccf,5e7f0f41,8bcd793b,92f26118,a440e3c8,8aff8d25,56fead8d,7e9bdfef,bddddf37,7a61ce4b,2effcdb,30ad0016,4f9bf5d1) +,S(1f1f2a24,a4e72a1f,609428ac,853e46d7,a9718c25,f2df9887,9a3aa60,5729b340,450dca4,f4920bba,bcf94f39,26871032,b631120,4b217170,991df216,2c421cbd) +,S(412f658e,e6777e4d,24e5682c,5007e057,83fbc559,f22f3200,f185ee52,c8ebd4e5,c2e0b64a,9d9394fe,b930b3d7,afa64cb1,c8399e3,27690e32,887b789b,6571c8f4) +,S(8495dcb5,567791de,976fec9a,367e250d,95102ef9,f92c11fb,f561f854,4cf4912b,65f809c5,7d3d824e,f5e63f19,153bda4f,542e511f,464e11c5,e2a9c32a,2a152443) +,S(f8e7bdc0,d841c95e,3a945b8b,c85ca4c7,b4a18a9,7a5646ee,1bb4ff08,5956cfde,cd0ac83,f93a3679,37c9d28c,24b9fc08,6d6660d6,15df5011,1b4edd5d,f0ed6d42) +,S(8324625a,4e4c1071,24876751,7df28ad4,8c8c5648,76e4a131,64f2f730,62854c94,761b1960,49922825,609c7ec3,70626025,de65e2cb,240b8356,1f5cc230,1f9bfaeb) +,S(8b1c49ff,99f87e22,af4b6bef,d353df1e,16a8e160,3023f2cf,213ed859,13ca04d4,cd4513d1,e178865,2d1cff72,822de250,6abbf975,7e2774c0,2ca1bde3,23ad6c23) +,S(e2ad61a1,20d24d80,8c830e89,d630b466,59deacf2,87aeb790,bcaacb82,96f4f138,51cd19dc,fc1c4867,daad2940,5acdc7ca,91849769,6003321a,bf5dbc6f,b2186291) +,S(e8dcd7e,a9a9a6f3,16a6aa91,53105601,e10356ce,7f4793ba,9eae3ad0,34c197a4,c835bad7,91f3aaf5,d32e2a99,e71c4add,95f69892,6a68695c,2e61ca85,38ea6b5e) +,S(f0b748e3,5875b8ef,361bba69,cfb05c4,d8643f95,9b207556,e46908e9,bcf81233,6a264e51,5d163a7b,678765f6,c29ca61,c1c0aeab,a9ff423e,91e9401b,2dd6e908) +,S(900de96f,9975a16,766dd305,bffe2423,e6eef8ae,93ebd796,2ce97d53,39af3a87,894ab2ec,d9c058a3,a331bf65,dbe69a49,f33f8e9b,12121439,650aa700,4d164478) +,S(8cbe7930,d2ea2342,730e306,7e9ecf95,ce7fbda1,e6d34645,a6e214a0,ed88aa53,867b156b,f875a67d,ae27f2c8,e232c934,85092c70,ec071ac9,919ddd85,70186b83) +,S(a0cbb1c9,5b35d243,945a65c0,fc5706d4,e79237df,c13583e6,9a292fec,9a25e68d,b6d7e9d1,3cd61a45,f81c8a55,40dc06e1,3c6d7024,5e850a40,55ba4eb1,82047e4f) +,S(148aac72,a3fa8cb5,aa6d3bbe,5e987fc,d8050c3d,63b47f4c,832a4488,262463cf,7f29de49,a6e24485,5aa45f6d,36f2e2bb,72749f91,8258c0b2,92a33322,677e4a61) +,S(3b9fed07,3a1afd6d,e6ecaf7e,fa20e2e6,c28616fa,25a218ce,fb07cf33,66f3977f,f0a85b3c,5084c964,a1f0c936,e96ad3e3,4fa9e7a1,348ed0fe,ac7003c,12c65fc9) +,S(7de45ced,5228bfd9,557b443c,30fa431a,7c9cbcea,dfbfe0fe,cc565ac7,ce3537aa,515ddd37,69107033,bcb794f3,ac55062d,78e0118a,60c98fc1,1999cdde,fa2686f0) +,S(9cc1a35a,534f562,98010274,74f3a857,c17cf99c,eba1d5aa,251e61b2,55913dd2,c092cda8,f30fa4f9,96115da3,7bf8e12f,c653e243,af2bc7cc,c691684c,3e433ae5) +,S(d82f1968,759b3b9c,c76ad729,828a7283,10fc71fb,22258562,920b690,7ab52ec6,54cd0a05,26983b0c,73808f8c,ae1c9d81,1b372082,dcac3306,c470af50,8818c607) +,S(16e6a947,3d95a95,c31bffc,c291b60d,1f9c548,85e5a498,24195ead,b87b7586,19e29938,581b6b8c,2e50d365,5a957c04,80ff4c8e,4ed73276,f882c558,dbd8aafd) +,S(d07e7af3,ee4f24,e46b4670,477c3463,ad57a74e,57a17197,ff098e52,3b5cd237,fff34e0f,43c91656,69b1019b,ef618888,d4d175de,b6f20b1b,c696f24c,135d0e20) +,S(2bf644e5,6dc027fc,63a118a3,43faa4e9,8ffe42b9,c983014,50a1f4d9,e5665380,bef5c175,77be1fc5,f8f66fb7,a06b55f7,eb84ca5f,66ea4477,c924f925,5a262ec5) +,S(518f0d37,db1db93,48c80101,442597c6,7a88107e,5e25fa3a,b97ed524,fc5cb045,dca8750e,a4e9ed01,66f113a1,44974250,6eb9f3f4,df8ab741,8dba0397,694d7294) +,S(bd48eb6,c50774a1,2be9893f,8c21f624,57bf54ba,8799928e,9a9c725d,6f0554c7,200a6da8,cd8f0300,6774bad9,769f738,dd58f350,632742d2,e2cfa787,f570f6e1) +,S(ccc8d93a,871169e3,69336622,b64fa1c0,800c5b45,e3c0b130,2aa99e34,db1517e2,40ee7e4,d45e6478,efa11f1b,c4548668,88837309,4809f056,11efd6c3,6d01d845) +,S(86f6392c,75877992,311d2e9a,27be9ea7,27e8d01c,fc27dab,8f4527f1,dbf6bd1a,7ee29611,b647aa2a,3d2b1304,c49ee690,57150518,fd46add3,e7caf34d,10f7922) +,S(e034f4e5,927b0fa6,c3794105,338751f9,9bb5a381,6da1dc1b,bfc41d83,b7d7fdfd,dc9f02cb,838242e4,13282b05,cbedcab9,e902567b,b279fb6f,f2248e75,41a5f89d) +,S(8fc36a16,a9dbf00,5ee3a66a,b825510,75eadfef,b86e1062,837b49cc,6ab51045,c7ee2c40,9605981d,217d9957,a004a4be,66a88527,9ec9f74a,70594999,23d200a6) +,S(d7bb40bc,54077d96,d6489b71,e65dcfe3,997130de,b517d12d,9c10adc8,e73278e0,e2096366,2f64bae4,5aa0706b,d96b5cb6,5897c0be,3a8a9b46,8ce9074a,a68b0a4b) +,S(d7357685,8054c714,1147d2d6,c265ce40,3c882681,157b07e0,b8be0a88,63bd2ac5,94f8754b,2fc94239,c254099e,9cd5804d,d2ce03a5,380c59c2,4f42ebe5,85a9932b) +,S(5b6f8aae,d9353ffa,71da7e99,bd3fe165,3e720ffd,657dc2b6,669ae0da,858f8392,4eeafd05,369c6eed,fa6f85ec,34e245f3,e4966840,30253c10,6e74f473,418f9089) +,S(39444d12,67cc29e4,384b4f4,9c4f4886,ab4076a0,19a0fb39,f7b72c4e,42222000,65c2502a,af90ee2d,8de48adf,35388eb9,329f3057,1b77d0ba,50ea01a1,ca83d771) +,S(53de00db,f1efb0a3,c159c4a7,dbc9888e,16ebad95,cec2d003,a18488b,1b0752c7,328ecbd9,99475dfa,752d6228,5e7bc51a,87dc6166,4d14a6d3,3a556322,5e2fbda) +,S(48a3baf,9b4f7213,e280eef0,d5fb6033,194d1bce,eb48d9e3,d4814a4c,bd5ead39,3b4ac9c9,e04a3852,bbc6f7fb,cc94b20f,7e749eed,44a9a9ce,7099a8bb,28334186) +,S(f00d7630,503c1ced,3c418237,27e22d7,acccf406,fa16eb6e,b524707e,5b3ac541,9a1ddd3f,ec177626,b1254605,df8ed593,c9e2bcff,db7d0404,f47571b7,31ca95b5) +,S(e1ff1994,3ce7eb59,e570858,2e8c21a0,c4f8eec8,40815ee8,9a482658,8941eaac,528e5572,746e72e6,ce61b53d,78aa57e9,dbf27e3e,bc36c3dd,3b4972,d7353b7e) +,S(e4f13c20,c48e750e,e15a665,275c27be,23b3aa04,5915ac55,2562bef0,7459bd49,bebc7ece,c6e51f99,a2e6b9d6,a7b1bbb3,63901053,362a9ebc,a2d21cc7,6e87ca30) +,S(e36e8cf3,824b66e8,7083d371,60cf2719,598c6c04,ac693ea4,d2dd5c83,886f5f20,4ea0e193,8afe57df,3db74910,481a54dc,f5be9fe8,64f249f6,c88d0cbd,a086c60b) +,S(51e1f319,3286d2fb,29cb4a06,84d7c547,797ff5dc,fde9572a,63dd1e0d,2646365f,ac470e3c,6f30ecc6,31a90d7e,6c4c3d43,b8640ced,b9465cb2,ace2cc87,52370e3a) +,S(8e82daa9,c40d4e72,605dadd6,45bc26dc,22277f41,56d2a248,29bcf79c,d5a5fae0,7f8155fd,be9057b2,2b191dd7,233e291b,b01b961e,32a124d7,33ad99b8,167c53ee) +,S(79e56744,273c7aa4,34ffd5e9,525fa788,38bea674,64e2a595,9881b359,3e2c41e3,625089a3,c50defb9,f00ec764,b47122d7,eb786a20,f278bc33,e806e7cb,f385ecab) +,S(a97e00e2,d19c1957,51deb891,84e24a22,af7fe156,f2f1e068,79ded3f6,62743f79,881d7ebd,8bcb2c49,354726bb,c44ff91e,f3f5835d,ea73b282,944a5097,cd8284a0) +,S(3bf10546,7bbf5c3,14e1c3fb,40542378,9bc52fbe,8fb38aa8,f4a70727,b338542,e789586c,fad5b7ff,6dc68e5f,ef840e05,9a87ba51,e58462b6,39042c64,24f6367) +,S(80296c77,58791dff,39b4ee87,ecf3406a,49cce0cf,8437fb2e,1f4880b,55d9cc5d,3b06be11,3c7f781f,ce28753b,708bc514,902e4834,bdb09284,846c4ddb,90152dcb) +,S(48e2cb7a,a3eedbfd,f6a9cc12,359c4ff1,b7b0fe4e,87e57023,59896506,20ba52fe,dc78417a,fa909bbc,594411ba,87f72ee0,a0a45631,3cff4aac,7ad564b0,9ee8ed1b) +,S(dc91351f,cb775488,286b482a,a187d79c,31a3db2e,99730b6b,7b4805a9,73403d46,ed720e0d,2d13192e,8c180ecd,5e09fa5f,fc52e35c,4e509b2f,fa93ff96,f7adb1a3) +,S(5d37c139,48ceb4fa,9cd05b15,1fb344e9,3a2b2653,5b052b9f,1797319,e990a670,f790933c,2590ba48,7a832ad,6b940634,b62e16d2,7c9e748a,1856d53a,1974cb01) +,S(98bcbab0,f8d69b22,6fd7eece,a848ff4,15c8e325,ad9e8157,708eca17,77070aa2,7671e3b3,db715487,e6affd61,5218a7ef,a08aa949,9bb10206,e2de58d,ea150212) +,S(60e2c1cb,3de9486e,fa594384,d5903340,12ce308d,2247a18,8fa5c112,3f35b1c5,6de7031b,9767c66f,5c3c11a3,853bf722,4d58d086,b68e08fa,63942f2f,9369d1bb) +,S(814716c5,aa8256b7,50bf2f70,2e2f9bcd,aaf513bb,329eb467,d873ea72,304885c7,eca644ee,8fa96189,13fba31e,23533de9,eb7efac9,a0fcb58,6300a42d,c7d297ee) +,S(25789f3f,1db412ef,af60f7b,636686d5,9fb71586,200e8e3b,e6d934fb,72f8de77,e5222798,99d1e21b,5734a6f7,7881a686,863bc03b,8c58cce9,633c8302,2c7de0ac) +,S(5382f40c,98bff8e5,646a87fd,f3fcb6a6,27f2a91e,780a1527,ef18cdf2,a0f1bdcd,231d01de,e41ca3a1,da068ce1,39d97a16,39c027d8,38c7879d,9a1e85c6,4a32b502) +,S(448cfd20,9db2fadf,fcaab14d,8f57dd01,67d9ecb3,f18e9dc6,e573238b,a11d1f2b,bad8e2e5,5a4f56c2,435e8d18,14d2824b,2ba1bb67,9520587,5a11c315,9166fea6) +,S(d917ca4b,fe6335f,5012b69d,5444bbf9,f6c4893d,eb612ab5,667afbe8,2e5653d,3fde9a4b,e6a49756,27950f1f,f17ce5f0,aeabc055,3102c33a,4bb85bae,f32bad17) +,S(c7ee9f5,17a883ad,733de053,be3ef583,1dd974e6,a4e8570,db35f24e,91ba8f72,8db7738d,26d367bf,657d2a31,c6a08ce2,e06a7e4d,2df39f3a,2bffd062,79bba44) +,S(83f0a19d,983ed6de,7a2b173,77c843bc,819a77b8,a32acaed,b7085e0,94d9a30b,d2ab3e96,67be4473,d8748b63,6113be60,880acd47,6d574e00,c37f4875,2cafe6a7) +,S(f3f8aa6a,61687c40,98fb56bd,e74d83dd,59674079,7c52f2e,2b299277,2313989d,3a690c9d,98503a3,2d201ff9,a896365c,caa1b54c,36857a21,ad63994f,41a109fb) +,S(4c1a11ca,a30bd6c7,d95d6e8b,3ebcb4e7,914fdd40,4384716a,283ee1ff,5032249e,e7e718c9,4653ef40,d214c604,e65339d0,6598f17c,37f82880,9b7e5215,b9424da0) +,S(2941b952,3419a018,53f3bdb0,420f3182,529ebbc8,5a1c8f6c,1d922c19,3ee5477d,377f226c,29ca66a0,aaa05baa,7f6c1ede,80482b51,8982763,864392dd,3e628413) +,S(9d04d07,aad49af8,65bb3eb1,8c7078ac,4b5f25ef,e18572c3,3842161d,8591a6a1,f572968d,ec2ca89f,b45ae02d,119644b6,779eb0ca,1d48f724,f8512ba2,2c83cd34) +,S(4401f767,c3c3a101,b99a983c,9a622824,d660c50,177bfef4,a2646b06,43d26e20,7952faf7,8e1b114e,16429309,1d0669e6,999f8bde,ee980c0b,b7d669de,86d4e342) +,S(94b6f427,fc4017d3,b328665b,acc863a8,ab8a1c4,7b283fa6,8d7b7f0c,1bbba31f,1336067d,35f0d2d4,6ec8199e,99dd07a9,9cbe7725,a9981868,e09a0217,df40d85a) +,S(41621ba2,92c79bbd,463b87cd,de75574b,f2fba59f,92025445,7389b4a2,4de7288f,355337d5,b6f30b78,81389951,fe67b943,3bc70a07,b294d11b,717ca2e1,a2cd3188) +,S(b0838415,6256c1d3,55900dde,6126818b,8a9b27ba,ab14d73f,c33c399e,fda3594e,2aaf9190,55b162e2,91cc5371,b6a4285f,843ef8d1,5069ec7d,c5d68475,c5a954a5) +,S(cc99a14f,ef418fea,5de9f437,7ccc1426,7d910f13,e8448fb,8ba92746,6c0dc9bd,2e30b64,7c01c12d,d42f164b,ac0c9bf2,22f7b3d9,2cffd7f5,c77aebb7,18536f28) +,S(8d2bb24a,dbec1858,d565d59c,1d805d8e,7b21d6b5,b967dd50,a2f420dd,5764e37,cdc6d730,e78daeba,712537c7,8a09322,fc371d0d,6a5645ef,e7014bf8,999f712f) +,S(63cee6de,f18cf4a,e6ca1871,7750e328,dbb94c6f,27422192,3b233a3,e50f7c9b,81230dad,ad2d233a,1b631b8f,7a885828,ce005031,e1365436,7ca34173,1efdfeb8) +,S(62084e9c,1dc6dd03,9a68d5cb,fba19dda,b2e4d07f,b8f46114,926a59e6,92755a0c,6dbeb4f4,62fb1af0,dc273a,aa827e0a,cc9c7f1a,fbcdf02c,c4bd98b7,5061a26) +,S(110c0eba,f65b6280,14e368ec,17072acc,3f34a937,7df79238,c2773625,5d8dd827,1a4ba716,6f236258,961d5865,b020b83b,c3c3e74,2dafaba9,649ff85b,2ae75c6d) +,S(d848a51e,50fb234b,a807306c,fab97405,baa50a5d,23cd12b6,8927c9e6,f1c87e00,9db9be62,88fb00c8,4cae4b1c,c99449ed,51fdb49f,3cb7aadc,16a72b6f,a96a4fd8) +,S(42311893,a2706ab4,52547f3b,3901b9ee,a8cf2660,581b0023,96bc9a7c,e14c2b5a,750f86db,9ba6222c,199c2a9f,77609a47,d6129a1c,e9ef4d70,daad3d2c,ae4165bc) +,S(4439c4ee,471adc41,32f45496,77ca1e32,6b252f1e,5f17f741,9fdaec0e,3834d37f,bd75c32c,22c5c3de,62f16ab6,6f86f93b,617c9565,b3859195,81a00ee5,75897e87) +,S(4dfce3da,b19231da,648b0bbd,8c52fdb6,e02e9e79,9806fbbf,36bacafe,c113b053,de8c5f1f,4b727fba,440a1c3e,147cc1a2,9d647c59,42feb42f,69d45a2a,13042c3a) +,S(3bba2b2e,e8e72736,f54f9158,281f6c14,9d0ba6f3,ec6d89ef,cddeff9b,8117dc9d,ff087274,77897e56,e5e93f94,7af6ca0f,6f9a2186,a6a60d2b,af690a30,da16ab24) +,S(a2fede43,37bc6b2,482d92ff,f55ab0c,e239a00f,4fbb0595,27f7d67d,8317deae,2a791508,43beffd7,ef08e195,d0ce022c,f780116,2f1852da,98c3638d,45869ed4) +,S(221c4e2f,f503eb4c,4a1aa8e6,77370085,b3d64d09,8430a185,2cb1cc3e,304bc0a3,c3c37b1b,f954e79,c124fd70,ad3f8765,a70a7929,4a262de1,99e11dd1,95b7ae41) +,S(a0c32f80,f7e4ba05,caf945b,49b91306,f909c8bd,559e4bfc,a58ef3c5,14740ed0,d3eb8f01,46ab4700,41de4cfb,dced45c9,966aa1c6,38a42c90,41ba1891,36f9562a) +,S(762e7a18,b4fe627f,1e1ca7,57740811,bf33395,cc962aa1,dff79be4,18da85c6,a0df0f46,50461c0f,4f8a743c,3455b842,5875f795,4af56b93,dce93234,c4f51ec5) +,S(2f02d935,cd95caf3,d56cfbe4,4337b1f,78389f34,1146f561,b8d632c4,b93a29f0,173470d8,23f190b4,f8008872,b23f1a32,9c45441,c12fe87b,e74e927,18f44569) +,S(c9f877d7,2eb816df,1c5adbd5,9fc98a39,c5877d6e,24ef1612,314e6392,e7eab212,14ce9917,88cf7eec,5a5a52b5,8fcaa9f5,88bb0052,754b3ad1,b0858e4,6a067c4c) +,S(cc4dff69,18a05cb7,a6f296df,6cbf5d0e,d6dd1c23,ae76c5df,239d2179,a0baa172,1cd438b1,b8471750,261b0650,663b4a56,e4dda0ba,b5390cd5,b7869448,654a4dc6) +,S(faaac74b,3ed2713a,29c10219,a78acd51,ca015a8a,65646a5b,cccec828,efcbfaa1,adcad43b,dcc2ec0d,bd65c46b,7fe79549,b2e74cc9,13fbcecb,f8bf661a,7d30d934) +,S(171356c9,30fa9bd0,da1444b7,35be6c0e,8a0025f2,3d1a2480,dd0aefc4,44fdbf46,770e9edc,991efb9d,ab44361e,d2398e54,62e2464d,2ee2a14e,b2e149bb,9c9bce3f) +,S(933f56a,e0473763,d2d491af,55f9fb19,c055017a,7a81b43,b641007b,e5680214,66059c47,481cdb63,481ea647,f494e541,ad1d70ff,93b1eba9,f85a9cab,a0ea76ad) +,S(a300f22,b182ad37,d7e44691,bc9c9c9,8a397f76,1ec1acf6,64ac1fe0,5bbb6b34,bd6f2ffc,a90974b9,460de269,4722f215,684abe44,6228b500,7b42bab4,5433593d) +,S(fc5e57ed,6e901355,f97c1d62,dee4d630,878b79b5,528e3fd6,85d6e3ec,af8fe1ea,1122127a,6c21cbb9,e598b1b5,68507bee,bc7c8549,345c9d49,8c4a9b2b,2f5bab01) +,S(5a2f40e2,7a64811f,bd4721c1,99019523,899e956,ea340bff,f3f452fb,5231ef3d,6b2bf95d,12578c79,74a06d26,39d71c31,d8c4a53a,6279886c,20a122d3,2093d547) +,S(59783333,df0b99c5,be76610d,67d7ef62,fb15757d,8dd1f310,6f9179b5,64f2084f,f2a9ea80,dd3d170c,813f4623,ba7583eb,7d309d97,c34f4c4f,a7676694,7e5b7f5a) +,S(cf61124,6b513fc8,73f72bb3,87a29c2d,a1c8bed7,4ca7ca08,1546db1f,37672d95,d23c3c76,697f0443,9ed1d1a5,661fb0fe,1e182cf4,2e07c787,3eff7abc,2f8c70ee) +,S(edd14f05,133a1480,e26eb7eb,8063f8eb,1cb871c9,606957ba,ac14b173,2ffe7d52,d682f280,d295d528,4c1b3aa8,445c274e,ee603308,ca4792a,61b5f8d6,34b1b70a) +,S(f9b0fce9,cdc8af3,8b26e790,2c95926c,33cb8d30,a5de80d1,75fd95c7,fc1a1713,ec7e8df6,f3d163d7,181083cd,c8cf4a89,df958b8b,d6fce2b5,d4752240,f2a3e6ac) +,S(ae906599,54187f57,89306981,7417c566,d9ea4315,f07094e4,e46bfd24,1746a3b7,2241bdad,c09d3313,e9d006ff,2a04709d,17335573,5be5b10,6775457f,231a129b) +,S(55f0f800,76492f7b,f5e134cd,e581ae3b,f68fe9f3,44107540,c54b350e,47d956e9,22a0891d,e68488a1,dfbb4b8a,35fe9835,e258dcb5,c70ccb98,2c8a48cb,c33956ff) +,S(90c8ab06,86fb40e2,31923bb1,df86647c,6cb7e3c4,c451d0c1,b871994c,19663bbb,dc748cd9,570eeb2d,c6fbb2c5,c417979,cb30d718,94c8e463,e3b7be3f,fcc80ab4) +,S(cbf47c2d,6b21ebb9,fb268e73,56ea849d,3e476d6b,ac09eb60,4bb2e27c,84a4c694,f0288fe6,8042894a,39abf8bb,e5962421,416ed9df,dab081cf,16e86fba,7abb2873) +,S(7c30885f,c18b68b2,8fff758,2148d738,d8f1bfb2,46543b16,37e9fce9,7d11fe80,3e2d1cb9,31a11c15,b26c6d37,8c886e10,52c06718,a63e621c,7ea51c76,3c013f2f) +,S(ad614919,d1bcba0,dd2a9da9,de9207db,e137c772,37f333e6,4f11433b,f66d7753,fcaea18b,3512a188,9d604619,2ba759b4,190b72d7,ec53d0b,aad9e01e,d239753d) +,S(8df7041b,af8c9c15,70ab50a8,1ed335b4,a7bc4171,a3939715,a295ca7c,4e5e29a2,e892e43,82677bdd,f3566b24,c7ddc6dc,e12eabc3,84a19a13,99b64ba4,bdce02e7) +,S(9f4c1e57,61c8520e,9a751891,ac1bb5f6,217f4e77,7dd88fbf,2a127804,2cfdadd6,fda210ad,c6cee889,c35831e,b3e12c7a,ed4b6963,9f3d4860,9d9b960f,4e7d0f50) +,S(a436f4dd,23ac70a2,c093bacf,91de3093,174de618,7525947c,2ee8ccab,a515acbf,c0e9d9d9,2a615b9a,9439a450,927bc128,5879e8b3,7d460ec,9fe57eff,7e19afb9) +,S(a38eed16,699743d9,16d8627c,5039695c,37497c67,c59547d5,67bdfa20,b86f1930,6e3e3ed6,effc3b5a,c9b5b5fe,3f26c91d,3be89bb1,48414c18,bb0e5454,49d9d7fd) +,S(5f4590d2,d4043a1,faf659e3,36b0f24c,b6f1de5,88e92586,83361eba,e2fbf3d6,250c0a73,42ceec0,3ec1af11,764e7ff6,ccc833b7,240466,15890be0,55197db) +,S(7565860d,c6ebb900,68ed16ff,8f7282a3,d52beac7,73cebc55,1be51f44,34cf56c0,4b56ecbe,526ed458,5428ad7d,e9d7f3eb,9b84687f,e01e1346,c32461f0,bae24c26) +,S(3e7c7fce,3a56ef01,cabad50f,2003a5a,77292742,be80b5de,c537b50f,95a9320c,98cd94b7,926e7111,f3778904,599fa9d9,d5dc342c,c495b914,a32d2722,93dbfaf1) +,S(131eb457,14cecf84,abf1aaf5,ec4c62ab,2ac91a0f,6af57552,2eb07274,b7cda208,a93aed4f,f0512604,46c61393,faec55aa,9b017a13,60d13031,27bfd897,e320839e) +,S(371bc601,e46963d7,388bff6,9c4b5f42,a98e68e0,2db3e6f1,637dd24e,a2a11ec8,e2fbeef1,932fa241,a9785238,c1b89269,21bbc7f1,3aa6bdd3,7b39d94a,49f84622) +,S(4770db04,92ca73e8,a0136bc2,2c45185,b4d45934,e4430237,1bcf5045,cae47d6d,e1af748c,25b1d906,ab77e080,d21df4bf,99a92f7b,4b1d790a,f1aeef36,2d41ec22) +,S(b31a8643,5af5db57,759dbae1,67ce3af5,e8e2ae34,20786fe0,da82812c,9594bfff,3793425e,860dc99a,a96a85a2,585b06a4,f5aaabd0,551fe0cf,3c743be3,c09aa4a2) +,S(e05eec52,84a2501,fddfe6dd,1619c374,a94121bd,7d1c99bf,9b2e665,bd3631f4,c0115f17,2122f806,99a24ea4,bd742425,4d883d77,6d269ed4,f6cc5626,ffb8e622) +,S(e55ddc84,ee407d3,45b84305,d97d3f57,e57810ef,bff3b35c,e4d8a325,2973d5c8,71f77bb5,b0fa6141,7e43e425,78ebb13c,abb87a6a,fa0cd1a1,26e8936,427ee677) +,S(ed7b6ab1,a5c8a9aa,284bf3ea,5501d33e,1aabbe76,f26a9f0e,d46dd23e,decd788f,2280bb54,19d1a620,18454a4b,cdfd82fb,824027d8,c51770d3,77233e01,1d0db63e) +,S(d4e331fc,3da4d8ae,e13a3329,acd4ee69,ce5cb71e,224f2001,f9606714,8090e79a,895141aa,2f63cd30,9f4a6b42,d6a88112,77821e51,6d08c52,1ae8e158,655e10d6) +,S(4f0ada0e,a8ec1ffe,6682545a,bd8152c7,2654718e,120d3d54,d648b487,896d4417,a603b9ac,6026ab46,47f5acf5,5a9fbaf7,20aaff54,56c88cd4,dc5ec7f5,935aa591) +,S(a2d13541,b08eeee2,4f086a9d,20df7528,a884cc05,4106b1b7,543eae3e,fdca84,5ac0b166,294d6b91,527a5249,7fd605ca,4bb67c35,85e002d1,74503b7f,5c803a45) +,S(4c1d520,14a0459,2b8887fd,afa945ff,cbfc4722,2ce008f,64fe8123,b5b6c8a4,243c4280,17b7918e,57d06597,f348efd4,ebcebff4,3950a608,3bb3e334,50ed738d) +,S(5f9e5a6,7d13e9b4,cc35b8e6,b2305cb0,fc2f5b7d,ff32ac55,1a5970a9,2bc54390,74808637,96965f7d,bc45833c,e8bedf00,85eb0cb7,26f3276b,30d9543b,7395ff6f) +,S(d76c6f80,95381b17,80ad28a8,80e29ab4,4447c297,34a4d286,98534bca,8954575,44b6c3f8,6b30e01a,61205178,90e429de,aa8273f1,277bc498,59c87300,a561b27b) +,S(7577729f,f78775af,703a9eae,b5864a18,6ad19f1d,dac658,e7a8a05b,d9df3344,6b519916,cceaaa53,92d2f822,98e7ecf3,3fa7c5b1,2e705345,32ec3f99,2f0afec9) +,S(50378f2b,457f04ba,d0b19425,86ada992,78700c8b,36bba67,fca916c5,8edc17db,cbd1451c,26bdcd49,1adbf40b,ac5338cf,26957364,f82fcad0,5fea3c2f,76273fc1) +,S(3748dc68,64365160,26384ba0,ec078ff2,7606eb44,e3d62b50,b9138be8,cc9ba86c,6c04e414,f624ae9c,ddd005a0,4e01828d,6e7bfb81,d350d271,96583c99,6611d709) +,S(b23a59be,8ea8d561,fbdeaea4,49eac729,3402f342,d05fd404,7f9c5d1c,57eea53b,bea47c68,f2d35b82,ce3c359c,83f5fa1a,95d40eff,702ed9c4,2fef0e84,406dfb9b) +,S(e4b451e8,7b42a5be,5c5f443,5701d2bb,9538fc06,925ccb49,ebfd71c1,16a64770,2af84669,9a790749,48efa86b,2b79b985,4cb261a6,8a9081e9,e1467b77,2f156da4) +,S(864ac6ec,65b8b086,346e671e,8651ddf9,de74a215,64f3da12,42ff7548,96dff165,f35738a7,7ab48555,91ca5103,c8d2bebd,b2cbf902,dfa93188,d68eb600,271a8730) +,S(b7d04a3d,a6a863d9,b7809022,56643864,fd36c5d7,9a056ac4,ecb27257,f02ecab0,cc40634c,6ba5dc23,e59e4e3b,fe6a07c0,1519abbe,7530f1a1,5ec7ef70,6f83b0c1) +,S(ddfc1af9,b51eddd8,2020de0c,4a8377cf,bd6e2531,ebc844c,7ca8fca2,714c1a0e,cf77c8c,1742c4e8,b22d9f54,a25daab9,c30f23f4,da3e1ad9,57b9660e,3ffe3951) +,S(78fcfe69,d5bb91e3,a13de26a,614d8479,e00c828f,8868fc30,ea75b47c,d51fcbe3,9ec67963,6b7053ba,b0cb231a,ac28143a,98021b48,4340f060,66da6e72,47f2d47d) +,S(dcd918de,16961d71,8222b4f8,19e76ecb,138c9884,7833a8fc,d4204dda,1115863f,abc3d8ba,c8d808cf,ca12318d,d13c2932,3ff7fb0d,813a5ed2,f5e52aba,cb23bb04) +,S(39ce2ef0,5de08106,93294eef,537bc212,e6f64fa2,96ccd2b2,94a0806c,c6c3177e,25eaf4cb,b7697a3,97a0ca92,6f3a266a,bbb5dda,78943492,39fd29db,78730556) +,S(495e4db6,43d4e89e,df50e937,e97ac4ba,1464514f,d3a46b5a,bae6a53d,3157a04,7d327e18,b2960d69,ebe4251c,f8c416b4,f84bb81b,a20ce6d4,6e6b1c57,e6ec1701) +,S(91c17e8c,b6357c0c,1c36dde5,29f9e6f7,a6cb6e97,f5b67dbe,fcaf5b96,637c33c1,2fe52097,fedb8ac2,efde2692,20f586af,f07b76e0,f685ce85,c965ec1b,a54c39ba) +,S(e3c4f480,3dffed44,6291f11e,cc5c9590,1c28749b,d6ae18d4,c0371221,d5ecfdbc,5a2e7102,571e27ce,974ad71d,acef8b28,4e7fb827,5453e40c,65b2be92,cbdc62d8) +,S(b3ee17f5,a0e81e7b,48814377,af9dcbb8,59ae7bea,5680f33a,cc15d8ed,75c25073,135a3c0c,9a6d2825,a6035afe,139ede23,b46332d5,5739ecb,6d092e7d,6cbfe86d) +,S(e4cca844,2bc91bed,342628e1,f6492335,7ca6e8d9,5e5b5732,29866066,eae76b75,dd55a555,39b5670f,f70b42b0,f319ac72,409f74e2,31d9cec,ecc8d90e,516f76b9) +,S(ab39cfc1,81c96089,998c02a4,64eae7ae,e517e4ea,962b6359,b5ebfbf7,da223b2c,def6dc57,b4dcbbe2,e6dcfec1,8281a189,72ba3b50,f996096,a22e4ea9,77d2fc4) +,S(22a32663,9e6e0469,fe4cad40,964f081a,677572d1,94b3ae01,f8e45c84,dfab402a,1c9c9d95,bd4e0ef0,5acf6148,44c98fcc,db44cf50,5d42af26,1b855f98,40d2b437) +,S(2bc788cc,eff94bf0,307c5ead,4fbc4dea,db269da1,7790a903,7c2fcc24,21f9cae9,172f3461,648c5520,44081c43,a8c78c3c,ccecb248,9d60d384,aa703e4e,24bc4b41) +,S(b930dbd2,a6720601,35a75bb8,8bbe69e8,3872c636,9fbcfe4,c622a300,2052729,9983f03,a872e8b8,2830e7f9,a7438b39,ff3f6836,3334debd,83940ff5,ae06f366) +,S(b435738a,2aa9ea40,702db448,da6f186f,29bcd03e,872a3466,f33b2e39,7514e3d3,5828d246,2d3c671f,85617e55,bcc34905,1678cb8e,f61c74e,92c54473,9098636b) +,S(c91f2e81,3acc9baf,2c52df27,d4180dd6,ee1fe67f,9db6223b,532dffb9,3072bd25,1c9c57d6,96c12f13,13afa0c2,b377e1e2,b027350f,bd24f455,69c15f07,85b73c0c) +,S(bb0946c2,8099ba93,8f28068f,416d9003,bad0d06,f8c7d31d,2b995f00,5c8d36c8,8e3878d9,3b575fe9,78fe1a62,1e978f28,1560421f,7782c164,8673906b,ed76da4a) +,S(485e3aa1,2e823374,cd506521,a707f367,5298dbf7,cb44f398,c31a06a4,8f085c8d,a12c8af5,7079b2b1,5a339d4c,302fc262,af0153e0,dfb4f878,a4b60017,86ca9a61) +,S(850f9448,d3282256,940da03f,e8a96eaa,f21d02a,78867db3,e8a9fb9a,713e844d,4551e4fe,3201ba2c,a74df3a,f58a820d,3a67836,a5a8d82,59ab2442,3bfccb7b) +,S(a74816b3,f66c1fe4,9f8e51b1,8eaf51d9,449cd4c0,54b6dc43,682c853b,be39884,4e7d5fb2,47ed7ea1,45af0cfd,c4cc1059,396626e4,80ec804f,15ecef7e,b372f7fc) +,S(2af5c56f,c71da217,79abcc1,73412016,e1eb702d,6b98af77,85ead6b7,7b20136d,7f3110a2,c6a82623,b2c49e95,a31a6b8e,783911d9,b532932,1b651541,86b706bd) +,S(9291ec91,a61adf1e,90d63135,fae60edb,1a313714,97260903,9684fee4,339b5834,d530506b,e8b0dbb3,fc09649f,1832de93,feef42bc,ade2de09,bac1dd17,bdd03884) +,S(160ad3c3,659a7816,4e9cb47,4e18ff6b,a8581fd1,823ce8e1,14444292,cc605b54,1618464d,5f28d719,a61f939e,b1eb91d9,a59f2c1,818dbb58,b6e1f426,a4d141fe) +,S(352599bb,8640920c,2d85a5d7,673dad8d,ea4280f8,6358a572,b4071934,60ba9d58,a78a591b,e8064f2b,22d7707a,d3c95cac,aa2ac3d8,638d564a,50f7d1c2,8b538d0c) +,S(ec20efbd,9a8c634d,92f7a728,1e9e15d5,adb37ce1,2236bf33,4d12c4fb,7b6ba527,acdb29bc,2a5a3115,3919315e,27af9d8a,e8c54792,fd5421e2,a9a57b3b,d51b70d) +,S(40d1e4da,8bdac6ec,55ee847d,c59781e9,bbd38785,1863c64c,5cfad460,e2dbebc3,c630581c,b7c92e68,a67c7d5b,dba3ec18,4e3755ff,27fb53ac,d3a2655a,316e9ab0) +,S(fbe12740,2faadf2e,2b1ac1c3,98b66df4,81674c2d,f0ffb512,7dbba444,e7d08c7,d00edcd7,f97914d0,3ac87182,14491698,f3dfee34,e6e8587c,52f2f7b8,b7f412d6) +,S(d781b5a7,47d191fb,8850fbd8,fb1e123,4070d9d6,2643008b,b0cd930d,c191eb03,a4aa95a2,5c74ab55,f95f2924,519b2911,9762ef30,248db792,d906b18f,346afa11) +,S(6472fc42,d926bc7c,115045d0,395b5e9,22790c39,ee520529,44a446f0,9ccf02cd,512014,a92593de,e2264e37,633c842b,45d1ab5,e2ad068,63db7894,4605a99d) +,S(eee180c2,e09601e8,6a517a93,54607a2c,5fa6cf26,4c80ffd2,c5715ed6,395e0c21,c8cba798,221d6fc5,b4fdaff7,f785ca3,49490af1,ae655711,e0649669,7483e7ea) +,S(900b262d,a172ad41,15bec071,c5763077,9103bed4,db500ab4,fad4b750,45ada2d6,316457f2,bbadfe91,3f418e7f,b3fa34d4,82c4c1d8,516755aa,371423e0,51e2cbaf) +,S(7e93db87,4e1e5070,772d3371,b9ef29d1,5d5e03b1,e66bce20,420801a2,13a34c9e,cdeaa624,750032a6,f5faa0fe,e00cdc10,63f3ec47,b5bfb56a,bc2c2339,e38465a8) +,S(461fb424,65f3a55d,e66761b8,44abfe3a,d172877a,3edb1f5,da98c82f,89a379ca,768261fd,ba032718,f5501dad,c05e41c1,1f584aa6,6b8e732b,7f15285b,18e815d9) +,S(1d9f581a,f0f61a0f,e5d0f0cc,91ba4f93,6de28aa6,5f35059e,997de778,9419e09f,7fe9c98c,7d59dc56,160302e1,89676f54,3f02db1d,622251f8,adf369b4,891bf6cd) +,S(8cd70b52,904b2aa7,240f7a70,e4efe379,66386dff,3ccdf62b,e2343821,767542c6,b3c3d03f,4c7e0b1f,f08bb2,f72bc6ba,e9e293d,886541f1,ff86bec9,b5ddc2f2) +,S(a0b547ea,9c08865b,99a5b8b3,800daefd,99097b23,4e442a2e,819aa628,eb4a5261,607ef115,e585100d,c003cb4e,1a27eb60,fd9d1e18,f2d23a22,80cddd89,f2ca2952) +,S(ea8a60f6,547038e3,683a649c,27e81ab4,192406f5,5fdbd775,78dd6360,4344d289,98afcac0,b05ad5ea,8fcb9f3e,3bc22f16,881b5fcf,5060c691,ac10f746,79822fb0) +,S(e6051a9d,882f9ef,77d488fe,55bb7829,48bce506,91350755,1a8cd4a,14b0a711,1c9cdabe,9d9eb555,cb9257b8,a60af75c,c1ec0c82,4d933498,ffaa14f6,2e920fce) +,S(600876c9,c50fd337,6ce5efb,c07e0e5b,165338c5,4f8eaa4b,39a525e9,88765674,401a671e,f52b21f3,83df5da0,aa0b215b,b044202e,606a746a,213796e4,dbea4189) +,S(3b045b9c,5ef6fdd0,9b3efe12,169e0414,3c0eca56,5b7e0185,274f1e97,f6b2ff40,aa5773ac,b21107c4,2a8085d0,5d6914c3,a135a47b,cb136dfa,d20e6813,62780a28) +,S(dce98d32,ee0b55e0,4d67807f,ded9cef5,f9504b1d,e552a2dc,643ee7f4,b1f0f1b6,d03ac27c,9e992497,cbb746d6,7acf5427,aba058e2,801df1b8,d435a1de,1f3fb086) +,S(365b1148,6e8a60fe,8a91c07a,93686787,dd5aea7f,22fa1449,58be984c,e378fd76,2c7f5217,319e5d50,4c5ecbbc,bdbb8ec1,b36e2767,54f405c3,f852b761,ef01c9c0) +,S(2e37935a,4dc465ed,ee8dc3ca,d4ede356,3c3720e8,57c986cb,b9c73b2e,ab6b5806,bd0873f1,5278f46d,802dc7f9,d7f81a4a,839cb690,10c6d522,c0e3945d,4bce346b) +,S(49b68e1,93745ad7,b60ddf92,70d71958,81cd8585,6e47b0bb,fbae94,f1647568,ca1d4bf0,13e43ef,53bcb2d0,5f4b85be,1dc82d31,f4a7795,755693c0,72819dc1) +,S(6df53d6c,c79c5a88,2c2b6f66,e9ede075,6c8cc6ba,3e60620c,b8130fcc,fa744564,48c3d6ed,3b2b7c59,2472f291,41a61495,4597f77c,afb576e1,729804d1,26431344) +,S(d99f8f06,9104e3b9,26163672,767145a2,2f9467c1,c8e32b8b,d28e170d,bf4865a1,ccfc46b0,55aa5d93,64e67c4e,2c06cb18,c2b43333,e4111479,fd1bfe50,52543d7f) +,S(77727c17,ebbf8338,ba807572,8558a059,e23af7fd,c68c342a,538ead93,e59930d1,a037dc7e,2cde1802,fe3bc65,75f50ca4,ede75194,133e7083,66de0338,40c629ea) +,S(1d40ead8,563a4ff7,c14c84cf,ad1339ac,36ae3789,99ec2663,77e0ca2f,6be22604,8497b443,b093917f,ee65a5ac,1c4dfb87,3a6b0c2d,a968d713,a711ec12,20d1face) +,S(2a39f41,adf5ab33,71a27c20,51840d37,e3226999,17a3d0ef,40590710,406bfae0,cdaf7a8,58e99fb8,23a36b04,8e844c18,8dd1a49e,c70488ed,155f2ac6,905c27c5) +,S(aaae4b1,d8b08cc4,8971cc92,fd974a21,66f5ea92,b6ce215e,28137088,19c684e0,9237995,c10a348a,84fd5cd5,5151e33,c63739d1,3a425bde,a34d78e9,e3cd8f0c) +,S(a5b0c042,591a53b6,334939d2,9ac2c9e2,11315a54,831ef440,965fdafc,e6477d40,ac3e7cfd,5d1f0248,b362b206,b3c7dd60,bc9904c8,d2a416d7,e117a5cc,4a62ca6) +,S(c1b7164,e6166a96,a8f643b4,7f094be4,3c16e3b5,3ebf5a1,2782e41f,27c63f0b,8469161a,4ffaf1ff,5b50ba81,1de3ac79,e34810bf,73ed1207,fcc0f01e,75663a98) +,S(98fd825,4b7963f0,4d8e0f2c,8eb26dd0,342e605d,8fdf28b4,57b98e14,adca63bc,e297a80d,213f6664,77f9dba6,5cbcb99d,2dc14325,be12098f,22061115,b1a192d6) +,S(f1f08649,71b6ed49,2d34127d,8c2e6f19,48c464cd,816acdc1,63eb3aad,594c3281,26ae2a0,f9e04fa9,13b8954d,85602e6f,506a0de5,2fdec31a,346338ab,f31f5c) +,S(ff470cd,c324d2ac,a63441ea,c0506fb5,b63af83a,61a23a91,17240e23,930dd197,e601f66b,b18e77e8,4607a772,a1efa73b,30734b4b,8fd31eba,5a5260d2,5627788f) +,S(90eabc6d,968aa196,b5808127,baabbaa8,ad0f82b9,332ed6dc,d04442df,bc6c63a6,d6df0f67,ffb23cd7,2dffc4be,44476b2b,2faed3e3,dcdc30f9,4c1fa4ee,bb5038f1) +,S(e217b126,acc507a1,b41e0826,b300363e,bc0a43b6,feaf3866,ecd4b8bb,cc7e11af,7eb28def,83db33d5,8b8eb733,2b27a386,921e3a5f,b0321ecd,a8d1fc6e,49e98f30) +,S(2a196fd5,82b85d5e,1772bc21,84d8aad2,b5d008ee,c795628d,20de68a9,fce1d184,994b4657,ee9ee3d4,fdf8dc8c,cad2ff1f,68526c67,89d82230,c3399f6,62201303) +,S(bc9e3bc8,3a6eca7e,8a9897c8,1118f7be,ca770cbd,7e66c2e6,1321d026,7ade4342,9d7ef7e2,d544a561,ab899291,75f35d24,e2b07661,2f84b0a3,f346542d,714f3f4b) +,S(ff2813f3,842a9f84,fea9e367,6f12f209,7e76b8ed,e691ccdf,6f6512aa,b2f198b3,206e3bd6,66d0c161,ac6de438,809f485,b8b6682a,f402bf76,18a484a2,c3fe1949) +,S(6e7599df,2d38d63e,be142321,769d7ca,34a50bbe,4e0adbaf,6c7479b8,d1af05f7,233dcf1d,4b0e4d88,4a9ed56e,b6b4946b,25614345,ecd182cd,5556faa5,e3654c8d) +,S(1edd9cd5,6c82eb28,14d844d1,a9e5c167,8397662e,b576f9f9,ba250719,33666146,a00f4a85,b2ee83e,949b5cb0,4d16820e,39d48ddc,95dd965f,e24251be,3df43f4c) +,S(2723de06,1f794cd7,76a4a090,738a81ea,818a2f73,92d7ab07,18d79fb6,407324af,35c7a9be,f9810c50,3c53429e,344ab888,38daad72,77cd0e78,3db1c1fe,c6bbf41f) +,S(4c4fb244,4cb54def,6d9659ee,b43c13c2,3874ec2b,a7c6b53a,f469ca26,ab9a213d,bbd2eafe,56447a9f,feb9ad15,349b338f,d4a1aed8,5a356472,82751e5,5b8efa3d) +,S(736359f7,347995a8,8e306977,1fb3fbcd,12847ed2,8e4e612f,25095720,667593e3,23bb37ed,4bce0512,35a215ca,6b8f9868,e303fda4,80d655f9,72c95bf9,12bd3741) +,S(15cb9594,ee936bd1,4b981394,60879bee,6f33b0f7,c0ccb293,825794d9,85f595be,aaad772a,2ec81ab6,13775e9,edb274ef,e2e133e6,5e58949a,c7f25429,fb1bb152) +,S(3b5489ab,97e5cf1e,84a90eb8,20b8772a,df574777,a61f0a9b,41e6c567,6be78fa4,145d13c8,e9674a17,ccecad63,f113d64a,d59a1eb,bbb10cf9,e7134cf6,562219be) +,S(78d1b99a,a6f9d385,b09bec7b,b59ce26b,23323e4c,3a259c56,68417597,a29dd2f5,1c8d11f8,e883b210,cf54369c,e9f6a280,a6b890ce,15b4a0ef,3cd8837b,7e16a122) +,S(385e4e8c,5ceffbbd,3a813e3f,938912e,d2fd2d18,2be81210,70cd15fb,39661e85,f4a1c414,9f5cfbc5,213ceb21,c1cc08ca,c9b168e2,58cdec70,36e2dacb,ab68069c) +,S(310f8c70,d8e46c6e,48930df3,c53e9292,a7c87230,292d6b1f,c28d9711,951aec6a,6fe319d3,c92c07b2,56715154,d5d7046f,59d92d5f,6dcedefd,b0386f5c,3417146f) +,S(764f3c30,23d1d50a,e170b80d,48d58923,c1f91a96,42210912,94066585,d7c70bbb,bd92fb1a,becdb4a0,ed941146,878c99cf,c3ee9eb8,c8f2b8e4,b547cb40,e3dca724) +,S(3d5d23ba,b357a37f,1bd3c86f,84010b8a,b37a8075,3c47b1ab,36f7ef72,a3e68126,2bbd1841,bdcf0265,838893c5,f5f9c0dd,7ccbb461,93068e0,8211595d,6b34255b) +,S(a70431ad,cdfc7b8b,febd2aff,d6759e94,6d4ddd7d,50f50dc0,87e256b8,2a7f8a1e,3ca4362b,9362b2ea,c33d77e8,befeccb8,23163921,86ff5f20,384247f5,9147f593) +,S(2a388212,2c1b2ecf,3c800432,7c5dd403,2263e9da,245dc697,bf7d63e6,300e8a7d,ac96d188,53b87bf0,3dc5f2fa,fa9b73a9,a339c0d9,a7245175,fd72c822,12f6ff78) +,S(e99c59a4,ae3022e,b50bc545,f57e3013,56b49bff,33069a9a,b4d17c0a,424b5451,29b24b79,fe55fab7,6c3737b5,61505916,b4fe1a98,20837349,baf445d6,2e9bada0) +,S(a0a42ed1,bd5ac5ed,f63f1a3c,3c3fe2d3,c0be26d6,b0da384b,f19c034e,83306d4,c39ff3d2,d4442374,7a293e28,8c320ee8,8aad0879,672679e4,e5bcf611,5ca0bbc3) +,S(b952e5d6,9ba9f063,f1d1670e,1419730f,5cc17e87,b6f0b01,c0b86ebb,c09e0053,c1e8099f,a230b8da,6e71c9b5,bbf250ae,273a4f9a,f53cd0ca,fe8f0c7,2dc46ae0) +,S(3aee273a,130f5f4e,463892b4,512621c9,be83c18c,655d5a2e,620f83fe,95a4e904,edf475c6,921fb6dc,f2c3c6a0,b93f9470,9237b035,9e8c9131,eb7eeb0f,bf0af7e7) +,S(96ddcdc,dc65af06,acb10d91,b87827fc,aa2f9e65,d28d0449,65ce255d,ba66ceac,2e6d0368,17fd4024,c830d4fe,310bbc23,9e2bf37e,60203584,215f852e,d100ab39) +,S(fd50f406,c757ec9d,b10e111c,32941fa1,e0d07ae7,9e3584d5,af45fae4,d30334a3,71b77494,d49c068f,c7db1d36,4f8db288,ed9ccb0e,c6137348,324f4bcf,d53fde6f) +,S(6f2d8268,11954523,614915c,9568ab9b,bd061112,bca3ba77,d3c64f91,6ba097d1,abe41199,849ca7c4,d317fe72,2a5647a2,97261d68,d025f5af,e880ef78,34787a87) +,S(d88c0db7,6dffb62a,27683d2c,e832a312,9c5099db,e2623c9d,3f064247,21cc1400,5134f15a,df6d7e92,5d81726d,f08732b6,ba5aa289,431bb4ea,542e6352,8dcec51f) +,S(a8de9ae4,ddde3f28,ead01363,2202fe4c,b6c0fd4a,a71d5562,d95f557e,747105fe,179e946b,5a71b614,90bc39a5,17dc752a,53682043,6efa907e,383e3da,a3be8803) +,S(626c6827,f7dc3d40,9daa4811,80e65b0d,799c94ef,e48077ae,6eb250aa,8fcd45ac,3d659db,87cf7b28,32e4a2db,8db88e5e,b30b7ea1,7819c00,fcec5d63,31bf2f32) +,S(28a3a2c,f00efa47,db4b2ef6,9f56cf02,1666ebef,b5220495,5b5484f4,2ca77d02,8dd00ed,fc9870ed,99ce90fb,927086c7,fc16837,9794db01,f7799b16,8393c82b) +,S(df0b029f,27c46405,245d0dc2,f178a48e,c3b67275,7fb92bd5,dbb29370,c1545786,f133ed05,c7e159a8,810a5ad4,e1019f15,757b474b,fea1679c,6ccd18a4,2a1099a) +,S(dc6f57af,9c1e0be5,2d2162a4,e8a6b63a,c549783,4c7c2c8b,421bbc5f,dc1a49ef,6f586aaf,e610fe5c,962ee20d,9b389bab,66fca44a,1c19379e,9e97e104,10f1a0c4) +,S(db796ea2,e0d2c690,19adcc0f,a81c1d93,8162472e,a0e3eac4,bf13b398,b255cd15,2e60c6a7,32e1fb44,641e0766,2191e28e,79375420,43bdb3e2,9474313c,7d05ac88) +,S(569b669e,72ea98fd,a5ba3efc,e74f88ce,881fe269,30b063ca,59fe369,35633a2d,badd8eaf,2551f872,5db3f740,6eb5e376,220b6a6f,ff4f8ca2,f76b7755,f8ca0c8c) +,S(36132420,1f9a33bb,d4b6b6f0,e2d175c6,ec795111,85fd2451,421ac333,78468ae4,f47b56ce,f7bc7366,6eeba135,14756486,62a58e17,d955dee,2821618f,fb3c4314) +,S(cdeb2037,1e4d2014,918fa243,182db0ff,855a0783,c92fd5b1,b604ed33,494a469c,7d3c7718,6829381d,2fd0098b,c84ee506,970a7ed5,5518b393,a83c6f79,d8dfa7d8) +,S(6035cfa9,d750c5ec,d3b721,ade88fff,ff6c4d74,f8db7755,c8717cfc,171598ef,fe1798da,160b2436,412dcde6,5482d202,9bb129d7,d58c9cb7,49f9fdb6,7dd675a) +,S(b1f52e97,e49998e4,e0e75b0c,47178f4,bb250b5d,97d92ac1,8dc9e41a,3b79c0f7,d83f3d65,4e4cfd8c,5f24370c,a2651c5f,de484cf8,1024f33d,8087a50a,d3df795f) +,S(aa799b53,4c73da0,9f011395,dd5f709b,f1a5e056,42536477,d7862b21,6df1b641,3a327047,b5e95b64,593f6887,9f38aa86,dd592007,cbbe7338,a003d2d3,33248646) +,S(da4a1964,45bdf4fc,479e56b6,6d339a45,262d629b,dd8c63c1,8d35e9bb,a445aa03,7b3a5eda,25cc63a4,66cff29,634d5eca,353376e7,26c2c6d5,63f3f92c,b69cb70d) +,S(c300b4ad,c2346d0d,433eba80,f0eef071,7e620d46,a07b384c,231e733f,a1b8d656,32083bb9,48d27ac7,f36aa439,a100b95a,f73448da,454de356,6f4a8771,e3cdba42) +,S(c559a528,67937244,d639bf7b,90df2b2,ed64a907,e20cebe7,6a358b2b,94359f04,9fcac1aa,5c08c983,20d671b5,63f4434a,806d78da,15964474,d2470cd,49bf5977) +,S(39b10147,a46dbf4,f074bca9,a83c10b1,b0911ceb,d3e795fa,9b96333b,dfe83540,ad35dcc8,c3b22743,4daaa313,cd6334e0,168da417,d162855e,64294196,2d308278) +,S(39c9cab7,d2dec601,7f840597,19994c9,4129ab2e,a2779d6b,34774a04,2f7d6d42,c73ebd6b,835a8a13,354cdd45,37ddfb3e,72ca72b4,c8049362,3afdce9e,43781845) +,S(1a625998,8a30b462,adec6097,2e218ec3,f8f81c4d,44131466,fc7b5eee,eec679ed,739beabb,1a97c9b,bf6776e6,2e213bd7,3651a39d,ba042037,bf5f8cdd,334114ab) +,S(396ed910,cd35c308,d412761e,bf283a98,85f33ecc,3ef643bf,3f422dfa,ea4c4308,721cdda6,a08a614a,4dc48cf8,442a46b1,3945e158,83671b7f,556d19e1,144dfe57) +,S(a50e06e8,a2e8ccfd,94aee96a,b0bd831c,83e15340,25e3abec,af7b7af3,9b299a47,593205b2,59a18063,fe5a4575,e8e085e1,4521fc1a,3ab5e14f,3fcd64fe,2bbeba52) +,S(4a9f8023,17b0d1c0,e62c8bcf,7393fa34,dbe15cd6,46e8f4a3,dc3f26b7,11c3e1de,40eff6d,915fff,cdb30c24,434e8928,239867c3,962655ac,2894bea9,f7c6bb71) +,S(8ce5e20d,9decb7e6,10b18562,e2ffbb88,7f323262,55ed9f05,5d2da2fc,8d608b73,eb69b6c,f363e164,e92371,b592727a,63f024b2,aa7011b5,4f1f698e,1ac720de) +,S(f32695d7,9b53e9e5,1f2525e2,8a5540ed,84143ed6,3700be0a,36726f9b,b483f24b,e8d36488,eea2055f,6592ca1f,6fe23493,1d81bd16,1c61523e,f1ee1907,c08471c8) +,S(3826fd86,3bf6592e,5b51ad14,6e02089,d9274881,25d25959,4856de1d,d6c34d07,ea86f1e6,a29035c7,43e82058,a7ff9f82,20da001,a8901e97,26583b1c,ffe4cc83) +,S(7b1afcd3,2e32b0f5,1ba09868,4ec72762,ae8611a8,98e87ddd,dc6410a,40ccd551,deba6ef7,79e10931,8036ee3,9bb6d0a8,a3ce0eb0,bc5620ef,c70828d3,d2e37884) +,S(3eb1fdfe,d2c27587,540d39b1,b66a36d1,8dedddcc,7f7f7b63,348460c1,35a91bd4,b8aeaaca,536ae794,619506cc,a812a67a,642c5345,8cfcf7b9,eb898f96,d26b36cb) +,S(9d61dac8,aae9fc5f,532290cb,683eea2e,b71b4d9e,901b7c45,c214beb5,9b56da8f,2e7caca4,2ea1b22e,7024fc3e,e267ce99,280a8f1e,78a2a271,7938762b,3a446036) +,S(2db372dc,3167faa8,e8e1e37a,85ed5546,e91a43ef,fddba39b,e38d0eae,3e11c7d8,16ab6f61,bc1abd6a,16e79697,fb59f0e8,84f00534,b7196380,9b06e10b,59707ffe) +,S(98f7cef9,f7a2b538,538e83cc,9ad3132a,5b03dd67,f7fc4030,2ff023d2,8805dc80,3b40f823,2813e6c6,bd56df89,1e96a175,468bedd3,f9518dd8,d658105f,aeb98943) +,S(eeab2e6c,c8ab0d24,d5df5852,8a89db42,c48f0861,4d488c7a,363cd195,edb62548,607c41ed,65d3328d,72be2503,f5edf14,523a7f74,402822cc,1709927,c82649da) +,S(955feeff,b2161c70,3469a9d6,c5fb31b7,b7cb5ed1,ada6b537,6d935705,b3db942a,a9195a48,a561c342,779c984,6a710059,283fcd0a,682cb5a3,fdf48ee4,15c0864b) +,S(219a4d2d,70d2ee9e,d3c8f541,1cdac36f,4db23bdd,a981a5c9,d44ce5ac,dccd85a7,67441968,43008ec1,71284aef,2c64f7dd,3dbfdda9,5c6c8e4,70a564f5,c4ef53b4) +,S(4976290d,7794b161,2e2f5cbd,282c1036,d594571,722e28a5,ed542972,f91ddb23,4cfd95f1,60fc5655,2fc8354b,446dc510,23571c24,56f57aec,79004616,ce17ebc4) +,S(472d53e0,268ead1d,bbbb99ed,599f5676,1866e0b3,c14d4a4b,5c44d722,b072b1c1,e9b9c009,6115d4d4,a8ed42e3,1d967b89,e4dfe82b,ec642db8,e31693ec,c2831232) +,S(2a6f5b7e,7a4db95c,af875d61,75a6e1b0,3f3462fb,c0dd5d50,da3327b4,70ab18ef,91b247a3,92aadc19,7d9f5b78,f0b013ce,c9f3724e,a2f37347,9ade7e03,8659d506) +,S(dc1815a3,bf48d81b,b5e5e654,fe0c8c3c,7431a62b,9d1065ba,17df9c45,23146c19,fe20729a,311550f0,e47e2af7,4747effa,d837c5f7,b08c8f36,d0fbdf2f,d594be8f) +,S(8e7953ec,ad8feeb8,97a95db4,f03ffb98,a8b47ecf,3e68bc4f,1df0b6e6,98397776,5dadf2ef,81b21cc4,26c40a39,51f31462,12f7c6fc,dabb5157,893b1637,c141ac5d) +,S(a4d91e6b,49d5724b,9e899fe1,c6686c89,faf96a05,6e666a74,72ee44cc,119b41a5,abd68615,e296498,f5abb820,cbdcfc26,fef10b2a,ba72e474,14ae9de1,960a4893) +,S(b97081a4,f3e426b9,d3a66dd6,8e0e442,754c4922,acae141d,d0294843,6b00eee9,558f6c83,99214bb4,baa9cb64,11550b12,2c8c2f77,8e28a4f1,ea61ed6c,b8f153da) +,S(6882b6ed,82279bce,70a73c6e,f6412c54,b873a5a6,b634a25e,a8c34210,fb825848,c6fdeee9,c8233e39,2ea79c61,6689e8a3,1e3a3b09,21f2b5ae,d6b9e14b,9ff21b3b) +,S(9c542731,1c715709,cabbf11f,a4fdeb3d,1a0dba80,ad50d1a4,62c7ee1a,44717fe8,aa041b10,78163458,c446bd40,ca77f760,ef4b6471,c4f2058d,7ea42975,d1f2b045) +,S(73a14da6,776b5c12,e838779d,e3be58de,4a5ed917,3b195d9,3577330c,780cd32c,c4068ffd,e98ec4d5,a7467bb7,e8bf2c89,ceb58574,cccb3a78,b0ce4a70,7ad2c49c) +,S(6488a286,27d26c4d,bade9d26,1e6ddb7e,8748d835,d9def8eb,fdc6c576,b6af91b5,27f8b1f0,b0501191,8af0916a,945bb07f,3c7f0695,5ada697,b5c601bd,3d6d8ff3) +,S(96546e7a,5b544c98,db9ee2ef,47dcfbce,cca1d38e,1978f71b,d8c9d4d0,5151046c,d04fe32f,8fe9ecff,220f07d2,2095c982,3b10f772,b261189e,84160ca7,5f4309d) +,S(ba046f56,4598b143,a02cdb90,972022ed,e769986c,82d28066,761463ed,8cfecdf8,fc6e23ab,d42457c1,5407d37c,d3d9daa,3e57bc0d,778dd68,53603232,3e27250f) +,S(39554751,e633ca7d,df6d82ed,86a8204,5e76557f,b13ca7df,310b80af,5ad0e4ec,a456ba84,f040f20e,977df5e9,5faa3f67,cdb2ba3c,2fb9bb4f,89486b02,a06d3b1c) +,S(c5f550e7,5fef9fd7,d96c924,11046c3d,ba56b8d7,e1b17c,d46a68a4,989c22aa,548582e0,3aeab617,556a987a,cee7d0fb,8d65ea42,dc8f2cc2,173c3636,27ac3fa9) +,S(2ccc1610,a48d8db3,9a80b2a0,ee063a43,26d4ba75,79b2727e,b999aacd,6e5fa050,de6dd7db,2114002c,8dcb17b,179e5843,fa205d69,4928eb70,a073f97f,f8348c84) +,S(93b07ce7,3e941c84,1e4089ff,2d8e6464,3ae59cf8,fe6e92c5,add89e10,f7084b3f,a6c0476,c5a7267e,54ec362d,3629a1ae,533efcfe,e18d3634,cb5a80e4,4018fa63) +,S(453c01f0,55c14679,5e3aeec8,26859b16,b0ec2707,61cbba3e,438c0566,5a91e7e9,f28eaec9,b9d3c8a2,2ef73843,6088425b,e14ac99,e52e73d9,8745bc49,a56766b2) +,S(3c6df1fd,ac078c28,a0a148fa,d15595b8,c1d09a4c,4a96794,6f8d6465,e80f12f1,4619a84d,4eaa134b,a06a6821,2e7ed292,d443db5c,150b54f,6dfcf267,82a5b58d) +,S(1b7f6968,39959785,30542989,59020dbf,f12054f9,2705efd6,dcc583,11b98630,279dc63e,e3e8fa8c,fbd731c9,b88ec6f0,67ee9e15,d0c14a37,372d9c20,c645c25) +,S(e1b7b953,9d49d0b9,9b90a642,74d2276c,6256f2f6,9cd03006,97ad842f,bffccc19,2b23b96f,51dc6569,8504628b,19e81534,f2acfedb,27f93316,fd0dd8d0,d5f9500f) +,S(404cf0c5,6fbf4233,4bd5f79b,ba97464f,9ce5525f,a56212bf,4bc817c8,af54f911,b5920609,88300588,5c61a6e0,75e3657a,23c04b5,79897c0f,2e22ca64,1f1ef662) +,S(43f1d986,da626bd8,efee817f,a09a3440,e7819aec,17ea971f,43fe2ec9,caae0c1,c5fa5ace,ce891aa,d2811f51,8175179f,3e93f438,2b3ab583,e51a200b,2a74f9ad) +,S(a18845c6,b3209951,16a183b8,1b762112,7bbcaae8,b67ee8fc,d23ecaf6,c5b9c1f,980ed5d9,d7e07e6b,2cfc5350,e818671b,8f54e7f1,5cebbb02,dfcc2951,bbef1f44) +,S(4d9c7eb,af99824,605cc17b,e03c929c,254c38ad,c026d5aa,2a304920,e7ac01ed,c64c5b35,bb0dce53,2273cf00,f3360f74,97065bb9,9fa9b1c9,70d41c19,53e781d3) +,S(e18d22f2,fbc3db09,bcd31783,3e8aa605,55953ef7,4c64814,edaeadc8,97e7c25d,cc258a81,71152072,24f7989d,fcaa8700,f15b8b2,85700b59,53ef2a22,efc7e07e) +,S(160575f9,f220904f,8d2ec9a6,c1417e8,35083aa7,9bc37d5a,3c8bdbe5,2a47879d,1e56b4a6,127e978d,41191c60,ad439fed,2c38704b,309d34ce,d655f93,5279a5e5) +,S(3b651bc7,57b1d626,4d6b7ebd,d3c5355b,4c3c9f6a,a1437e53,f9aa0372,5192d514,977a8774,95990312,ff1d8ec,5dc8a49e,5feb285a,8a1e2e4,19e56186,80231c3f) +,S(9085bdef,56facc02,76025015,498ab286,a9660e96,1fd6bb0c,d9579a8f,16ba532a,fd05d108,a557559c,5e7f791d,90e80e7b,68364c16,8f6b93b8,c55510f1,7ae9fe89) +,S(4224306d,f64a3862,fd33aab8,c1f0ace8,67cf1b25,76e1cc21,fef45448,e40569ec,8740b667,5279bc1d,ce887c2d,c59e42e4,63e72395,ff967249,8bd13d58,f60661bc) +,S(b7376697,4a512e31,a6f806b3,5bc55ee6,e0e2b2c0,ff5a0918,2f83ca35,dc22935c,d350c820,2676fade,ee4152a2,48fd5cbd,890b3e03,9d688462,51c2a082,85420103) +,S(73ba4f8e,d3b5d4d0,a7c505ab,1c1a7486,bb82e068,cba81574,557424da,4d0eb97a,93af3914,552dc360,549b4a2d,863d3f9,3a58ba9b,72541215,adca4bfe,26188271) +,S(285a014e,174724d9,8f0576c4,5694b052,ae93540,6bce1bef,524be03,6fd3d8ea,6fdad1d8,d2ce7757,e6ff5213,f91d4db7,9d406765,968ce8ca,b393e7c8,6a9af7dc) +,S(b0934dd7,27bfb54b,a2a5cea7,c6f8c0ab,84c2fd78,eca0d180,963869de,c28e768f,dcaf0d11,56029f31,4bebbb26,edb09913,484c94f7,d14d71bf,2bc709d8,f0b982c6) +,S(3b627add,8b69a9dc,b751c8bc,cef15d0a,ffcb49cf,357bb65e,c45c8c0f,5b681561,bda1980,9e380b7,2da13364,9d27cff7,693cd2bb,a77215e1,536296fc,dc46d19d) +,S(7e48fdec,1f2289df,a052e3f9,a4766daa,e4593876,5c8aa7c9,a62a369,52cb5ac2,e87af87a,ac116885,66e1e10c,5bedb49d,68449b8e,612939ac,61e384b9,bd8cb5f2) +,S(4031f08a,5de33bba,b6a2c267,feec2e40,d094d890,caa1008b,181ce43e,263ffd9d,cfdc4fd9,9737a5f0,9a789beb,91dfef45,a8f23be3,11b946b5,8a79b7f0,51b0be07) +,S(ba652b7c,61dddbb5,bf6e656f,4d441cc0,ec00a22c,7b900b1d,d5407ebf,931ed764,87fcb392,d1228156,a330b5d8,d3c67e00,1d207095,9a590088,a3b44d07,29556) +,S(fb936572,d1017653,ac7dd95d,2d8c30f3,62c967b9,ba0d3b1b,ffdc1ed0,6590e72d,adfa37af,db6b6a31,a779965,9958be2e,94038246,6b4a4587,b0879882,4836d8ed) +,S(294473cb,5e7c0852,f7c6fdb7,8861129d,b97ff328,19685148,99198870,b03bae7b,bd905536,f991867a,78a09f95,1bd5b4a0,78463e5a,6c767617,246eec38,7d90c86a) +,S(2fc0f44f,73a633fd,91737ced,1683b74c,7687dc8c,6d3a4c09,44a6c873,c5bc574e,29917cee,ffa063f9,4e949991,2ae373eb,ac572f50,9a451184,15e07354,1d22ad1f) +,S(811fb251,882c5a7e,f59d34f2,c8ed8a31,8da210dc,83bb8c40,b9ac0251,116d569e,74df6547,2cb55afa,4ee04ad3,f940de6a,d480e407,5c3cc00,ad291918,d8a0c55d) +,S(45a9e17c,c1d6cf09,1f451894,ad4e7e53,c47996c5,82fdc57b,a9e7e614,b7fc5d07,5169dc4f,2661f5,fb2d1920,89832b7,4e19196d,c37fdbbb,16d1caad,7b069be1) +,S(d577f7fc,45cda7ad,4743d96a,ab5c7bd4,abd06538,b78c0102,645d09ae,b5588e67,55172b71,7ea257df,ced1db61,88c78cea,765e2c2c,30bfd25e,52107128,303be07a) +,S(a6429a95,8098aa6e,39b71e08,d4b0cefe,4fb22d8b,777a59c0,650e11b1,9b06e44f,af494e62,5587055d,cac440f5,786240ab,36ab1825,f2c3a7dc,f6aa64b1,947dd2ed) +,S(f77c304,b89314b4,258b1c80,cf478ee8,50bca37a,63e20679,7396967,a39a743d,c487a176,29d914be,60845213,60f40f19,1c32f414,558e2c72,7e78637f,8dc1c7ee) +,S(41c6f2f6,15981247,71ff0a82,e1ededea,cd76ea2f,fb2f9f5d,ef766165,96d1c988,58a0f544,146c1a07,5ff9ed4f,f9b687c6,3642770e,45dbf1d3,407b52a9,5accb68) +,S(c8724ec8,c13d37af,9eaaacb,35765e3f,7ac2d2d7,1fdb5916,cdf66ed3,2eb968d0,70ecf721,42103e6d,e7d4bbf2,42bd9a6e,6ade66ed,a7862989,5ecd255e,44d81221) +,S(e2888c46,dd58e36,be2204a2,b75fab66,3b139e4a,e070c650,653ba9f3,ff1fbbf2,715910da,e1393b8a,b7d88879,720bd601,bc158498,9522108c,3312b353,2342509e) +,S(f1f4c384,d72d80b8,6b5999c9,aaa66f99,f56cf736,11ea9ec1,c14ac36f,66d834dd,b5543bc2,480142c8,ebb8527a,3c9aa786,2198388a,696b3c44,835e7375,24cc7e3f) +,S(487477f5,832fb7db,768d412,6edd7f5a,17aec3a6,3419de73,f61812b4,31940a5b,90322dde,4203fa98,bc44e3dc,32a6d56a,284f556,36db7c54,c5f78d5e,1b2608a7) +,S(a726963a,583167e2,4b8f957e,b3ee9f5,c55df02,9fe1229b,ff8af037,14ca75af,8fd7a984,d68929c0,81154d15,6b6541ff,4a636925,53a5a32d,99f6516d,c08f7449) +,S(d4c20db4,cf80eb1c,9d93a231,e699a68c,baa763c2,e2013033,8762ac5b,8b99e97c,ba1c77ba,2555a50c,84aa2071,39190a35,f5abc50e,589287a,426c6f9f,6ceca01f) +,S(7cf9c53,89ae702b,bedb5a55,ad8d0f36,5159ba1d,ac56fafa,fa59efe2,3a748168,ece3b324,338c7bbc,a2cec347,c31348ef,489bee0a,6ea4296f,6ec38502,b72336b8) +,S(920108e3,c1ebd4af,3979f9c3,326806f,eec92833,b4dbaf49,6992541b,44b73e55,3e22b133,d8adc483,4f03f348,eba48e65,6cf8f478,524f5395,ba92e200,95f466fc) +,S(1566af8a,98c48762,9b361337,2ad32a53,fc760538,49566a8a,4feb69c4,26479e90,2848c566,4bd72be4,c797db98,62fe1c7b,da5d3ba,eb3f7926,daba8516,da997796) +,S(a4db5e71,2eb8ceb,c7d7a704,12b0a8b1,d2f6d9be,271ef044,c0f76abc,af61723c,663e16e0,75a73ddd,f604bc0a,27a9407b,272f5f2a,f2b9f6a5,6958c8ca,c42e8ca4) +,S(d0c9cf53,8bbdb8f9,625d110,6c79cf1b,33d90e77,60778c13,8493bca7,8d53e5fb,b6ecce0e,8b9fd407,cc0a2125,b8bd30c,9975ad88,7dc1bd9,68379063,8a1d9a60) +,S(765fba92,480f57bd,70596d67,bcf3a389,4a58d514,54e3a04c,e657ce78,ffd8391f,5cb1dbba,1035350e,5a3b552e,3f41ab4c,50879bbd,5f3ae3db,af6ec902,1e18302f) +,S(9f9da9e8,e846702b,4aaa7b9b,68b652f8,9bd3f88e,5af4a503,2c51ee6f,8bfb4a5e,5dbd499d,7ecf17b0,eb17320c,a0688aca,1d8da08d,d2c0684d,edfa2d7f,5696a0f6) +,S(af86c83b,db95894b,72fb1a16,61aef5f0,ad949c9c,b465a5bf,b1192022,13fdd3f4,ec06827d,55410119,603d2b25,cc41c26f,4a7bb9,b1b88e55,123f3c12,d799e117) +,S(fbb48993,2fccbc8d,772b3fc,c80be33b,64c8e3b2,2ccbb09c,d94fa350,fd587e77,f9cdd24,279333da,b3451abd,634075a6,58598ad4,257bbe04,81111b6c,d8c0b858) +,S(40ecb1a3,ad97c2af,62b15eca,e2adc9c0,621f36f8,90a9269b,ae6edc1e,7ed60684,ff9ec194,fa3a617d,920e3e2b,32301fb9,9a41f4b3,ed9845f2,88daa005,3558b32e) +,S(31f892f1,c762b42,fcbd9014,bfe0238f,39873c30,c7d3b691,9736009c,18878f52,d9bd5005,f31f7345,53131066,ef6b92c1,5cd610b8,f7d4fff7,be536734,95718c95) +,S(ba122529,e9f6051e,2d94d150,c5d7739f,921f8193,8cab68f3,1c696fc8,24886c5c,c33c071f,7e9bd539,1b0577d3,37ac9c20,7c02859c,c396bc20,d9c7249a,856b1ed1) +,S(35316412,9a26d311,c993ecbc,5b9a0263,ef45d993,d58158c5,30c215f,2924cf03,86a620d9,521623bb,9ce3e2d9,c5b6385b,f92ef06f,91834e3f,6a9c6d35,7a3a9742) +,S(3024770b,e4134aa6,35ece92c,a4ec7f9c,4a4aa7ac,7851b3eb,f9718a21,52c8e462,1fcfafbd,72147afe,16dc1579,ce7384e4,ab3f8faa,f818d225,bbceb050,ffc8c8ee) +,S(f5ba313d,a40ee86c,5b6dbf16,9941d8e2,533c1ba6,4dd0871a,672d01c8,6bda6564,10a910d,b9697907,c96e95ec,15557649,8f965282,437f58c7,2944bbad,b800647d) +,S(685e17e2,972ccd05,34f7f426,b18c9518,e485a23e,132c18eb,b33b59c5,7264e2f1,96545b38,be84aac1,a77a3f47,51156daf,470fd42d,dea0fa0c,b930144e,b9f291c6) +,S(e01285fd,facc9822,a59e1bca,7e91c07d,fdd481dc,61d268e0,504f65d1,9bf119eb,ae82153a,2479daba,ef83615b,a7202b99,40bf5b5e,41c65063,f77d6e5,9dc39909) +,S(c61e4586,327710ec,784d6720,93201e4,93798a93,7635f220,b5421cb0,55839601,e461fbf5,aa5b64e7,a1e3e016,3ba555ca,5d42fcf1,7433c26d,cdeb8cb2,746c04ea) +,S(1c427acb,4e5890b6,e24d8ca2,513b61d9,3106fc34,90029af3,be87d65f,1fd192d4,1d96e025,1518528b,9bb04fa6,ec3430a1,84935ad5,ee8ae3e9,c9cec0c4,36cf29d0) +,S(5e577bfd,6d51897b,4b6ddb3b,a7d470b8,5a932619,b5982f54,431df6f1,f12fd8e7,c1a17292,9734c19d,3a836e90,8a5a7fd0,123cb044,c7ad1ff9,203d4d79,211c6eb4) +,S(cc78b333,1f968a40,bafaefc8,dfbcadf2,adc6ae76,6d3ea8a6,8173b40a,28237b30,5b7691b2,a5bc068,ff1ef04b,41238cb4,dfc2ce7c,9436f8aa,14eb0a40,45857d42) +,S(3855c437,487b44f2,9e5dc288,faf3ecea,c445372a,95adc16a,b1830a4,ec919fb6,df2e1e9a,48cbfa28,54fbcd5b,308bdbd5,ed1949f5,e1a39519,11c287c8,289359d2) +,S(c05233b4,a83356f,c5ffcf6b,97db3d6c,dc62cb21,b7de7c92,8f158466,b9d16b19,b1bda39,ce78847,3fa0eac6,51e8de54,956616f5,16233275,25ee3bf7,9e54f500) +,S(6c064d3c,f34226a7,d9a00024,5901f355,b736c1e,6561810b,455e7dec,99dfffb,160d9442,d25ec1a1,f80f8fd2,a1c5c42e,aa544477,28d242e9,925824cd,609eb9a7) +,S(9658eb89,70bb1aa5,1b61a93a,de6a7d,b3e20772,4789d009,bf37ba9d,8b714cf2,cd4ba4af,f7da8f8b,7821a903,f40d89e0,96be8949,997d5ff7,a58301ea,92c51cc2) +,S(6e023910,a5546f70,91f2b0c4,c3f996f7,5cf1f969,a71c31b8,7a3e7ea6,4bb4f0c8,f6ed65d7,90ec734d,d9ed8cfc,7d8921b8,7faa9b36,651c3589,99b9addb,34c459c5) +,S(3a35ac98,e9700499,f903528e,330537f,9262901b,d60c7a14,1e68f899,54c7ff6e,913d9516,da631c30,5394ac0c,9eda3824,1f247ff8,a7644eb6,c4d38da1,972069ed) +,S(d089fa51,15dfaa45,a8b6def3,b1948be,2317c66f,249763db,7350e57,76af212,4e6ae973,f326fac4,77a5120c,f3ffa113,a18e5dac,4a190f6a,b12fdc83,18a6da9c) +,S(e733c52f,2aa62ab4,748ea0f2,33d9531c,5b9cd9d5,f790b6ab,45bb2c2,d8cf2ef,701155c9,3c677293,acb23ab2,8d7ff753,36ac4885,70c52d89,fb80ddf1,d582a291) +,S(4b6f7b7d,c006684f,e64aa6f2,42babf86,1eb4770b,b8195b9b,e8caf763,e7f14c7a,6c58b780,ac757b33,c1805d8,a53a04c9,7bfaea05,d8f21d5a,2b0645eb,2194e00d) +,S(1b520402,cd1fac0a,c4d7aeb,8c552e73,44ff51c2,3b4778b4,81126e5f,e267f79d,8ee0d00,56649304,a0c4ee94,39add4d8,30b252f1,93d93c1,9e8ec375,37db1a39) +,S(8936e6d5,d7f1ed85,fc2da4c6,38a885e6,3400cc3f,43d864f5,bf9af2be,b97139b1,29812a20,b4b932a3,770cdc8a,6fd32625,8879f217,a5bd7c47,78d2b041,829b402b) +,S(6808ae7f,4813554d,aa36c043,a55d9171,aebd396f,5ba1a1ee,c4f11045,c96b518f,6afcae6e,88728ddc,578e85fd,5f41575c,f581b983,7c749c22,31b993a5,9c425810) +,S(586c6694,44c73f66,1211bba7,601d8009,93e23293,55a9b10f,2367924a,35a2cd1c,74b0901f,f6eba3cb,408f5507,d37cb7c7,873537dd,ef0671c8,862012ac,fe5416c7) +,S(789c825d,deadf1e0,4c788453,e918541e,b183aa5,99ccc66b,7897be8,1ff89e11,8106aa6f,641bb13c,6be7480b,89f98a9b,e40cc357,ffe9903c,b8f78938,e46cb5ab) +,S(d7ab80bb,fd26faa6,620d0ddf,97f64bca,e520426e,e1d8e076,acd7cfbe,a9419797,26af9f72,a6d1b103,aef4a85f,5139d14e,6e50a58b,9f32eefb,c7184537,90c5a823) +,S(18f712d4,4daf1ab8,4612b311,b1ebc418,bddf0f33,ca02b315,4c256d2f,36f67f7f,c40b1950,f92fd4ce,edb3c3f4,34ff7bf8,6b06d8d3,215d3ee9,f2d9bda6,77d25bc) +,S(8873276d,9f6d188f,78e2a7cb,f998bcc6,fc399d32,21de85b3,eb9e6ea6,c7e5a06e,297e8137,8ee9b9e8,ee820a3a,7e566178,dac97743,c04b6b4e,54a7081,e7c9e1a6) +,S(101b8101,5bd217eb,c08f57cd,fdf431cc,30fadd66,4df79157,1452ca66,c688e0ad,fa6c1b2f,ad203831,185816d4,a8f8dc9,4c7542b4,6c94dab3,39b73718,5d179e6a) +,S(77b3c157,76c31460,11e520a8,cb2071fb,abe3b3ca,2984bb6c,d81d4c53,7f42dd57,8d0bceb1,dab601b7,1c084c9b,443ef5ac,40cce5d,14f0c244,92589905,fc4a645a) +,S(151f2d52,56ac60b6,ff7aca33,8ba66f12,fbe2c189,33c805d3,ecf6a6a0,fddaec7a,d2aacd77,10cd4bf9,917038d6,49e94235,c4833c88,9cd57ea6,74ece9f0,764f62d6) +,S(dd75cf27,f41e417b,46338dbe,24b46df8,9508811c,111bd1a2,29a3809,171d32c7,e328b855,a3389b80,4ab03c33,cc91d86c,ee22170c,d8fb53dd,46c32224,19b67be5) +,S(faa1feb,bdd1d9c4,9de366ab,3f661b1e,6a3f6b76,335b428a,494d7eee,791d7a83,df361d4f,8fce02ab,8c248ee5,61e46555,948bb29d,81a569c4,13b5713d,b825d572) +,S(3cc10dbe,5bc2bb31,fddee65b,66789594,a4cadadf,8c6a7545,671dafed,4d8f8be5,802d45ef,8c66ad6f,e692a3a,9d42c974,7101120a,ea42510d,bc08e657,7039c2df) +,S(9544e725,325dec1c,914dee7f,752802e1,856cc485,35e3a1e,af576bec,a7b93ba2,cec7dba6,81513c04,ebf39b03,717338cc,aaf137dd,e5087686,aad83115,deeeeb49) +,S(94a0fbdc,d5d06236,7b17ff8b,4dcdf6c1,54eec66e,2779deac,38be37c,9f83a964,f25f34fd,5ef06c81,b7223e16,9a42e2e3,fea74213,5a2a30e5,76f29ef4,cfefe82a) +,S(989e29b2,c3fc7e2f,695fbd4b,f217ba43,14f67c3b,9f77633,100e84b3,c6b579c7,608a6d28,cd00297,2b4f3e9,917daaf9,ed003a43,1c22771,17250efd,b621c888) +,S(c38c5fc4,4295a59d,3b0e979b,5934ac2,49b4bd5c,e94097f1,c81064bf,73494a5,16240bf6,d354b36a,648e471a,e0ebc167,1d1dbc71,7cbeeecb,7600462d,61d1e2fb) +,S(de9cf667,35c4046c,58b41d8c,5c658efa,7dc656b,7ad877e1,546c138f,fa7a63b,2fc2824f,ba9162e3,e2372927,5448010b,ecc19de7,d9b94cb7,57586de3,506639ac) +,S(24cfd37,e56708b5,79d84b3,88c33c9f,f1dd9e08,4675a3c4,c8c440c0,f6c06522,1cbcc8ea,9820157,b4b4d289,55ac8672,1aee676a,cdb7df00,7383ac79,c42af897) +,S(9d6e3108,6ad8b9b6,2f4414a9,5e091e9d,2b275d8f,62641ed7,26421639,e87cc121,b924700a,6792a67d,4dab59ad,5a743cf0,43c46ab4,de751bca,757979b6,ead3abe0) +,S(52a89ae,28b28395,739c21e5,38ed38df,74aea22d,d2765d38,673be080,8609354d,c183ed57,9b65830b,d37cccd2,76b2f61,469b06d5,987b5708,89c5b1e,d8334e51) +,S(2ffd3272,491d1807,243f5d31,d727caf5,cda3bf8c,2c172550,46bd3420,da27571d,812e8fbd,6f38b334,a31e48be,6deaef58,599934b5,d3419d52,131cc9a6,535b6ad5) +,S(5d60c609,4269a43a,35e51b66,db193b16,65df689c,270662f2,eba959c5,9c973fca,f591324f,d1afd619,2b31bb7e,3f40cd40,6d3b9285,969c448a,3aff1f48,850efadc) +,S(23e0c40a,bfe53353,f4426340,e1c1b560,4c86daf9,85784d0a,e6da6b4b,3d12ff75,e90844b5,fc86092a,91baf68,280ca144,f19d5a79,9bacf827,f9921511,28191d9d) +,S(945818ab,5d4a1c12,ca6f20d7,7f37da80,50e67d79,30bd2bb1,155885ce,7c6094f6,b5f2c1d0,e2f9ae6d,aa669c96,9ededb60,32ca8163,fafcbb6f,9a11cd56,4a695e03) +,S(d1f4db7d,2586bf6a,187a469c,a0cd7bcd,5043be5d,6206d24b,c41ecd8f,d8724c8c,64054f82,77c4774b,bd480ce9,b2929c66,b1525eab,1c6f365,a1ca5ace,12206839) +,S(4f5c4d4f,24586e9c,1a85f2d5,b42a3d11,158b4f2a,5cf75e18,60f7f4ec,ec14a18d,57576e71,6d547960,6953be2b,e7ffbec2,1e48bb9e,970fb350,986b4a31,b0efdbe5) +,S(c13b605b,dcb31443,d8a3cf5c,5e4f903d,3f8edfc5,1e9a118,c3840cb9,4998150a,8dce2eaf,99f1fbf5,2e62a8ea,948b01c0,6c368e49,f41922b5,2f603cb2,16cb8435) +,S(1937b32a,b66f254e,4964a5b5,a1ceeb5b,a3df2466,e2669753,39174cd0,2429cbb6,9712b0a0,6f1b075c,bbceabb0,53fffb1b,181e079,813e022b,b5701738,ef2e385) +,S(e4a5333f,2f1772f3,84ef386,c3be1f58,d757bbdb,7ad2c4d7,47e61b07,419ba2e4,e84f7da7,2ec2e4b9,389b717,8bc15642,132571cc,9bc14c7c,5af14a7a,cb6b6f56) +,S(2f8a38b0,a3f42a8c,5080a0cf,5cc1085d,d57a8341,ae154dcf,fc7fdb4b,5606cca6,8764c6a5,2c301db6,56408d9c,4eed6294,2fa2a72e,1b1264f1,134f38c6,8e4681c1) +,S(3d2bdc2,c51c2d77,b6c585b6,3ceab5fe,acd14599,b841870b,8735712a,81a55ff7,33f749ad,bbe263df,a99a808f,f0476e44,92246036,a3e8b5e9,496b8dcd,b6d3e9e0) +,S(fc87f808,d6764ce3,376b9acf,62bfa3e2,1ecec215,22dbdb3e,6e5f3cc1,efab7d3a,ce75eb03,c1f4f937,70815dd8,750a4ac1,c0343024,ce1bc581,717cb971,2835176a) +,S(7f81b85c,62dee11e,be8885dc,cc98485,32354952,1c7e6cb4,374270bf,5b1e68d5,b7adef7d,6a84db61,c15ba062,d96cf739,1750aa4a,ed5c97f3,ad70d2a7,6a9c4558) +,S(d618d43f,7afd3ae5,e8dd8f47,f62ef91e,33cc8f89,3c21688c,8268b903,e1fd5557,6180817b,c8ab9b0,82b21267,9900c7e4,42ce9e8d,fc8c3fb4,fc5bcaa6,e0cd34b8) +,S(ba5a4c4f,f2379b06,daff540f,c8383b9b,694430bc,df76c931,ccf94cb,896e4940,3a221d1a,b138e6f,4ed309b2,4f2e9333,25299de5,534a528d,b91075a8,fd07b1f2) +,S(c69189b6,bee3746,88359141,5b35bac3,80136395,c83098ab,cec29fa3,18cfdf56,a185dbc2,b862da3a,cdc232fa,7e3407b1,9795e61e,29b7a79c,5828bd49,d739268c) +,S(51f67d44,32fb401,ab863423,b99d403a,70dffd86,87e5ad71,bcd3732c,1cefae12,88b17485,a2c404a3,2bcae68a,3cbf2166,403e23f,8a64df5c,a8eb2d94,61e10e59) +,S(cdacfe09,e5585f8d,4346fb69,a94b8b65,6001e117,ed3cca36,fa8bee6d,eb7c4bd5,ddf1bc5a,993131d0,15812176,206699d7,af5fc403,59455ece,fdb84492,6e028542) +,S(8129e771,e1fce476,9c701d70,cce90888,481eaaa1,d1661be3,19f33c93,8bf0e769,3eb5713d,a864bc56,39ed8b6f,974966af,8a4db189,b5446d70,d40a816,f045c6e2) +,S(b97062ef,6d415bc0,f302fc0f,8aa730d4,f39c14aa,f82889ad,a68132bf,5abce3ab,8ad70688,cd76c93c,fd8dfdd3,8522247c,6644c9e5,51116829,490f313,d53db3a6) +,S(19c3c98b,4e811b5f,ea5d6af8,c4e86be6,50de67ec,5154bca4,22a6a14f,4f0bd913,bc523f96,48bdc993,30e1b5c7,385097cb,c18b9d5e,924767bd,d5d746fa,a190a109) +,S(b9ef34c7,3616ee74,b1ebe43f,889118e2,ad7697b,efe63559,67a9b3c2,b5b42b9c,12f1cddd,d55b1ac1,b89be271,5e623952,e8dc05aa,3570e254,3b70ea68,5b661bea) +,S(7718e34f,58e2cdb5,80f9c39a,96d84dc7,59dd2a3e,bdebaca8,6e8edb97,f503c34a,a6d105fb,dc0841b8,12dcd8f9,6c4bd17d,cf5e3728,8e0e3093,13567b10,3e96df7) +,S(dab3884b,8e6de737,63bba89b,8d35a369,e259c1b1,8afb6ed6,21fcc871,c77e8dba,f44b6f29,c59a2d42,2babd4b5,edb4a009,c9316e09,2aef953e,e503a278,14a11577) +,S(cb3d0e10,1139782d,e5e6a897,8b5be6df,a6736751,e847ca18,76aedab1,e67f4366,27fe888d,d227943e,67969b33,be48f1d9,572aff67,69c150cf,189f9709,bd57d3ea) +,S(eb1b1ff8,55619d41,8d193db,bf62b4b7,656ea564,6ea2e79f,cca7fb3b,e8c3c6a0,c27fa0c7,5b73d5c1,d7113741,40384565,d36ae93a,49b327a5,cedd03c9,62282ea4) +,S(5d5079e6,bc40f11,f75a1117,3ab6bdc,bee8f9f3,d2e57aeb,58709786,1c39c5dd,14ae112b,a40db9d5,dd65829b,4be7bdf9,4d8435de,1872bab,80581221,446e46d0) +,S(1060ef7,6beb6af0,6d28acd2,6b214bb1,b708098d,e0300502,384fcc0a,a1a7b38e,ce40f39f,f6c6c642,9585464d,aa2183d7,34252c05,5207e2e2,75d0ec48,c3bdf9a3) +,S(9651c463,c001f731,8947c271,ac274529,e7bcc894,70d63e1a,fd723873,aa170695,4e362e7f,e8ff06da,73d6d17f,e8b63c99,3b16ba7a,5a9b154d,21837fb0,e654eaf7) +,S(5c422b76,592821b4,2f6822cd,cb428b19,895cda4c,d224400e,e0928f27,1f363dcc,2fdb4f4f,9e4c77ca,3448258f,f6c07f5,4cb6b4d8,15281484,44e5fcf6,492b9400) +,S(db147d2b,5d98250d,73a3ce51,9452cc4a,ab3868a6,cd4f43d2,b7224d93,a9faba2c,73254380,ad3c6acd,fa343227,a7299684,9fdebffe,64c4925,8a391a7a,50ed0de) +,S(9a6763a0,f97abfd1,65223767,8881e899,e1beca26,ed84d384,a41d16cb,e5454b4c,bb51407d,b6aa5817,32f1a3d5,51082908,e7952f75,92c8bcb2,737a01d3,3890306a) +,S(36fe7933,e9108af4,f4e5c889,ef94f584,7b45a9e,8c520000,7db6a00,e5daea8,d024a5ba,ecdd5a21,c8c3a0f4,a71e15c3,1943c7bb,66b459e2,7fc85bb4,25227ee5) +,S(40dae663,f04f7e68,ce782fb,87529681,44c749ea,5b7386af,c445568a,3bc784e7,49a463fd,ac6bcdd0,2458c85,423cf252,cea2ab47,44b16bb9,47811176,5755050b) +,S(ba1616d,c8fff3b0,8e8c6d10,b15afd9d,da55faba,79fa8a75,42c5c9cb,adc5b8d1,ef096c42,a6233c66,1965a3ac,eca095b2,7710455e,5f0e1019,7641ab25,b0a786ff) +,S(30486f67,23a54952,4d68c948,dbc71273,d69b4a05,5fb9e7d,a702d027,619c4a66,38ca4d4d,279ec9c0,85ea6369,5470a4b9,fd6acc6d,9a049ab6,5743ecba,c2444c76) +,S(1b83ee94,95ead1d5,80f67174,dec2a026,d6accd93,9a89d970,90f25bc8,d9e6932a,196d448,fb5e4851,e1b73d6d,a2e7d0eb,3d263034,9c2b3e0e,34584bc1,d6e20196) +,S(4ea9dc2e,edfa5a11,2fa76671,5c1579d9,328b6132,14ee64f,2e30f10c,b7517396,7414efc9,6ef83e29,5883f0b1,4019b41c,d4a192d9,d06cac9c,21e8f0f5,b06e50c2) +,S(4166c19d,bee9ad08,83b217aa,3b657436,87677792,d5cb9b31,1a097fcd,2eb033da,62c5065c,5fae6aa6,932b4d29,ab375ac6,b80e113f,d38d81f8,abc236eb,7eed541c) +,S(b17567eb,b112f54a,69c511a8,7d3d2f96,bbbc6686,af8e3f31,a2bbe0a,85a74899,f6676341,3788be54,ae3fc693,4b8936df,a6936721,c671cbb1,bdbfd72d,4c9f52c2) +,S(cd2b6515,2ab97f34,89d81fd,f3513131,a6df0685,5022102,12c2b8a9,be8095a5,cfe7952f,9ca41935,15ee40c7,2d44d023,22afff84,b8700bb4,5f492e31,e78f6a53) +,S(375603c4,9f33140a,3241a72,907ac0c7,2086c979,3aeaf74a,44732097,3618229f,7bb740f6,6322a773,e11ddb46,300975db,de08ba13,84480699,6681637b,eb85e837) +,S(102067d4,390a3dd9,6d83c176,f341dde9,7e10955d,2e001632,978f202e,efbb7432,7cf6cfd5,4d28ccc3,a7019f11,b6ba9df6,1d8b7eef,7e70722d,afa81a2f,839ba83e) +,S(47617e73,e3fbc53b,a703042c,f8b48fad,374ef42f,e8c2dd54,4fb7625c,de63081d,1fa4f423,c92a95b,b2c40f07,f43caaff,50cbae67,87c3e2a0,e4782f39,c1d439e8) +,S(2c431baf,57f75062,9f57aac0,8e28a060,46b814bd,318d74ca,82e1174e,f880f84,ddb9e7bc,68574b32,c1004108,9853f41e,62755a52,ac58badb,b8ee58c6,f209de50) +,S(91963643,8143b6e4,19b86b1f,79b708ab,3f4df44b,d774b41,338570dd,8343d599,9034ee17,7171a0d2,9fb91d68,26b87bbc,21be334,90f44049,69622a8b,76312f0d) +,S(bf28c201,af656c7b,838d42db,95683b06,2871859,2b016ddd,a4a4f7f7,c4b7754e,bbd4f04,dda510d2,a8a66c2f,46ab0681,ce6ffb5a,ac320e20,c50b6df3,a345d109) +,S(fcac7386,21825f4,4e1d531b,f598e40b,1aa4262c,a5aeb5a1,babb4f35,9518b137,3b196b7a,957bbea1,f3f2d1e4,1ba37eef,7dcca7fe,87e7c593,6ffff685,52e67b64) +,S(9cfea1df,caaee192,141f0278,e467f809,8ad89cc9,b47ed982,3029c1dd,726e9331,72d81e4e,7f30ee05,8fd0b646,95086e30,96a071c1,5b75df47,b10146b,18db211d) +,S(548d3f42,123553c7,965c7f21,f2802c30,455c5151,99b98e20,1e966f34,6a1334da,612ea25,cebb03d2,89538eeb,15b94686,8c0afb1,311278a,42694a0e,956418ae) +,S(e5be619a,ccf84c26,9b5c545,e8c4990e,ebd46756,c628de22,a6c8bdd6,74295bc0,640864a5,7d841af7,ad83aa74,fa858b91,89e246cf,9b361837,a742e2a0,71b08bf3) +,S(b560933e,3400ed4a,eea8f733,d2368c8f,a260460d,f734e209,e194e9ae,a1ac668f,5438f93d,31337853,9feab182,6cf17bbc,ac0975f4,de29a886,1b1c0c02,2c5f9da3) +,S(21dd9a97,baca3e79,77ecf7d,d74433fd,dedf2d96,8c3153c0,2c652aa2,1ccf60b1,de6e60e0,e048b0b7,b699bbd7,cda0c0c9,b851c4cd,34f4b8d9,17c07cd0,2684797e) +,S(5cfa560c,6d39439b,4c9b0a52,f9bda301,2f147874,48c9ff37,bcaf2900,fd934bbd,c7927a63,cc1959b,f3556998,ce936f29,29d5a5d3,3f0dda32,35affab9,a5b11b06) +,S(4a3b95bb,5adcd41,5036204b,394fcc95,6377afe7,b4902f49,461c4b6,866d4fc6,d59e3ee2,f1bd1e4c,c089179a,4db9387d,8d6be47b,df708023,2a0d00af,a8e84f2f) +,S(cc49a313,b4c69c9,13c06b7b,add06f17,404edb0a,dcdb3d4a,81c4b765,35f4671f,4bd722ec,c35e525e,af36c194,3d375592,ba483715,2c7a91b2,4dd57a89,687bc278) +,S(9d75085a,7426a69d,9ccf4f90,d8b4ee0,e07fdac0,18df3d37,40b264cc,d4146d98,5991253,de04b32d,4772f44,de49467d,ce174ae9,3f941ae6,a4f6e3c2,2cc4b0a9) +,S(dfd064df,737bdadd,2eb12cf5,d9f1e192,caa87c0e,fad20d18,b95b0d06,83210fb8,519f883d,a5bf8d33,50b1d2b,89012fd5,9f317299,3eae1226,13d81b92,9103805a) +,S(2b50a35c,d2356c35,d609013e,a66318bc,1cf20582,685c12e3,bf618102,807eaf9a,7d0b51d,303aeefe,b81f5a77,d9b5829e,fdf4241e,435380f6,ce74abab,1dc76335) +,S(e26e8f4b,2cf175e7,c76e2a59,459cd45e,f3202f3,3027f0c3,70481fa8,685abbc7,4c82e7ba,aa0d5161,53076702,997c34dd,716e5fe2,460eac0f,194f72fc,3ac2013a) +,S(5903db7d,54f4d857,6a584057,ce78dc07,1fd90e51,f825c959,b46d3483,5d0f87fb,c55e2fd3,e9ce119e,47c00332,9d18d6f7,febf9440,a18de0f3,81608011,1e9e99c8) +,S(4bbb0ecd,342a82d,c8b881e9,635241b6,1040e6ee,28b98204,fde953d4,4d25e9c1,12eb090,f3445b7,52abee8d,604e8784,82e97e9,b44d2335,8211a8c8,2cb0ef04) +,S(4a2455a,ae87bf97,c6e6eb38,fd3279e2,7029967d,41b9575b,647550f9,4bc4e8d2,5a340ac4,ffe3bee6,2d52bea1,e276178f,9af3422,f9c61c47,4a595550,73936074) +,S(f086d68d,c8ca19aa,54c329c4,c07b530f,94470abd,dce244ad,1decaf87,53477623,911c49d3,84a16af1,65be4161,cc4869ab,4d9e8ba2,808afd80,20d30971,b4bdbd08) +,S(4f1b177e,83b76c4e,24a53f91,2095f1b5,d4b7cdf7,29788cb4,c989f921,b7ba856c,a5568c4e,b060909a,fc3dc2ff,5bb9534b,99debb69,dc0b811,e1044705,7d80eaf2) +,S(eba87899,29a7e45a,23d2fcbc,884778d,c4fb5ae7,fa67954c,76534303,97db5823,e6f8c729,b3570917,9fc46b4,7f03af9e,801b26a6,1724aafe,e730217a,2dcbf68f) +,S(df117b13,34c9a5a7,92d58084,4444559f,130ee539,89cc6e7d,87723b63,a82282c2,dd87ca57,8eea3c51,2aec5492,ea55111c,1a2fc55d,4e2335a8,c9be5641,516f7120) +,S(d775543b,3e68ab88,36eaa1b,df5f6a06,1f5768e4,baa01a68,621321c6,e6ee82c5,70221b05,47c97398,3cee7a26,c4197f9c,27a2bf46,10506e18,493a9ee,1881436e) +,S(a7f10dd5,5a231ae5,abc5c611,68cd58ca,5e006f7f,fdf064c7,1482febf,4578515d,492a33a7,b66b9694,e225eb38,d1d99399,b2c24af2,d69c31e,b4797a9e,703c13b0) +,S(c79545ef,3119abd9,11336c86,c6b74846,801c6b3,812da05b,5d36e9c,620120ec,24c8fcdb,95b6eae4,51473f8e,f7dea06c,738a33c4,f1214382,bd7204dd,d3c28718) +,S(98bab5e,744f888f,5f843ba2,9e2104a3,afa14dd6,6a2206ec,8e783e0c,52c2cb11,83b5699f,e5e87ed8,c51d929b,8146bcd6,a7abaed4,636afcbe,b2c30d2,bcb94df6) +,S(6dce2828,7b6fa44a,c8213053,d39dfff5,60d84a84,ac264110,547752ef,dcac586e,1e1eb62a,b9d60cc4,5ab2fa8d,d065d1a4,c79be399,53578a5c,adcfc629,e237ed66) +,S(e386a59,287a73c9,306b091b,5b24ad8f,db06a9dd,8f6f0c1,b7fb0ace,623dfa83,4a7e73da,663b64a5,e624ce89,9e16fcd5,c0d3b221,42284ed6,852960a9,d05b34e6) +,S(8fdff782,e62fbe31,98c283fc,9b9543ac,cea0a318,2626d180,4beaa27,ea4fe4d5,fef8f471,9fe0d95b,673ed650,8107e887,a4f5301f,4317c708,c5222d2a,ac086675) +,S(4c9093ae,7842b148,1bbb8b8,4ea564e9,36ed1cc4,35c89089,a10e0442,292eaa37,2d683334,93d245fa,e5ac0903,fe9356f7,8642362b,f85a7426,ea2950a0,a65298dd) +,S(cc0634c5,5c5c52a9,d92b80f9,be072a35,56318c6,fd76cf2f,e866d5ba,33103a1b,750b7d41,b13cb69e,6d236eb0,87fc8600,4004aa77,1b699e88,7e8f0b08,d07f0b32) +,S(9749a673,41fa7ac5,8bd33f5f,9cca4ad9,1d53c7ec,cff76656,9a56f71e,3b918255,b685f1c1,9dc7d6,7692a2aa,fe37d9da,5e68fd69,cfa58d87,ec6ced8,68916068) +,S(b04abcef,b57862f2,5a57fdc,b7da0b1b,a25bd253,72bd91bc,9e0377b4,697d8e75,50479a64,66ad4be3,489b5869,d8b9bbe,62dcb8af,da8e7d42,78b5014a,19e168f6) +,S(d11f7de8,5481fbed,f1a3b395,785f00d6,295059b7,c8049768,22624e85,45c78902,1d163368,be0c1290,1a7369d8,11266982,b48928cb,448039c3,17333658,6f5c3416) +,S(a21c65f4,65c4c7a4,93225af,73b63cb2,fd615160,b29b2b90,970b880b,5756fd4b,69a26b89,394de60e,7dde3476,7048a295,57f1e3e2,5f7a586c,7666aa30,9345ecfe) +,S(53c626fb,b080360e,9243d399,9a58ced0,36ccda8b,186c76a4,fdeefee1,6a497a1f,ad926008,62a7ff1e,519106fb,933616a8,8264d7a,c40476bb,eda7e1b7,742ac9b7) +,S(cf67b587,1b2a3ad8,d0364fcc,8741f10a,11d96933,11b72870,60116c4e,74e6ff0e,2c963b7c,10ccd74e,f68ac068,cce1e30a,7be6537f,259abcae,6d36d29d,22b68422) +,S(50216d8,8cc8700,29da89a4,b34cde0d,36428829,de9f58d7,31ecd6a6,c90b4bc7,920c1df0,96bc4891,8defce32,2a512d5a,36f65d7e,65525e0c,123d9fa7,49e38b21) +,S(1d845594,f4686fbb,7b0cc62d,af790aff,3d6000bd,e26ec1a2,67766c3d,93d1aef3,eae11ba6,bd9dda02,ef134035,1847dc6c,92450b36,cd6a9734,25c09f9f,3134d260) +,S(11ad4f50,b6c5b97d,767d590,859e2ab5,2e7750a5,6f7e70c3,d5c52bb7,9e4785e1,2c2bba36,8725d9c5,2152496,f14cfa71,1826e846,fbf7e7ac,4e263db5,a8023b94) +,S(3568d27c,d72373e1,29a4a519,86082a1f,f76ee425,969d6e3d,12b242b0,bd49388c,e36dfa9,6d094047,16e35668,10a8e57,8eff108d,839cf3da,f04c76d5,8754fdb3) +,S(3772ab35,45e09d0c,5d2abb91,97007742,46310f72,bdc0b8ab,afaa2c17,f17801d7,25229a8c,eae0c746,2d7a50cd,a8b012e0,775693af,8edb7260,5340042,a78884e) +,S(8151b24f,72c4701a,e4624779,c8b93ad2,44f3b299,d1ee131f,a13054e5,c29274f2,58938307,25ffd619,de73fca0,50c28d77,73420724,4d2e4c99,86ed5512,b8bb6429) +,S(46a4855a,d4101f8c,60c59705,e537080,1b57a81d,9227f4c8,69234946,5d539c9a,8fa66dcf,21117195,e2c117ae,e2f20bb,9517ad24,5fea8864,beed3e68,89e36b59) +,S(b81bd54,3e654f3d,eec15001,c38bd2a4,efa7c45f,4ece2d4f,fd893c6,15803d16,15c3f7aa,31299a76,34431622,8f93b6a3,2b3947fe,5a894c4a,75d2ba01,4e9d3e75) +,S(3e169a1c,f2a0324d,2478c054,94d58801,423f10f2,4cfc9fab,a5cd5cad,12e7706,20405bdd,d814ac7c,53469075,a700b4bf,4d454b,fca920f9,86923562,19389135) +,S(74283e4a,b161b33f,f67a1b8,cde619bf,557f39b8,5443efdf,534bdd2d,4da65956,22296be2,89785c04,6773ad2b,c881744d,380c1717,1c77b159,bfee3689,d0b3df3a) +,S(62715786,cb76bc9f,b65da0a2,3b7954e6,1a617fb4,de828092,bde3da39,ea6b756e,3c27bbe3,8829a150,3b563337,bf995110,eec54d58,21e1f17d,34a5fd90,52c2db32) +,S(96200105,db23b893,84336bc9,d5596740,2c93aee2,ca35df73,9c55a000,6f7c8aae,3192968d,400a2604,c80307c5,d9865f49,ea41cdd8,e3fd3b19,a2bdfa17,84a6ba26) +,S(bd477798,bd2691b0,8cc52fb5,cbf8b2c5,31787535,541b5c31,3aad9696,b71d13fb,be2b51c9,a4ab0033,c21dae50,c4e7b2b,51978b39,4a66d50b,6be7e140,abddfc3b) +,S(fa149388,e46ff849,bb5490e8,3aac6788,70da101a,f52dab05,9039c305,475289e7,8455577f,a8d85674,3b32080a,dcd26a1e,c75af3d1,c184d5e3,7f22030b,8867b2a7) +,S(4228db83,af1ffb1,d4bbfae7,3781a70a,8ab50d3c,47200e86,ff436ae0,3391ba90,45db1d0a,b0e6f0a1,801560b6,419bd2e3,2413ddc9,4b4ad637,d4071d8c,b7a270a7) +,S(a97ab279,fe0df5a0,3d494c02,eb69c686,1dc3a39a,fca2bd49,f4161ff3,817c85c,5006c8bf,f128de17,3d72f99f,7cd6deec,5d4b7441,6b1ca290,e535c8d,c59bec7d) +,S(c0d46c57,6bdcc661,4e1a3a1c,c19fba37,9f27dc45,5135eb63,f8d44666,904c668f,396b60a3,b28b250,2c97d7cc,f93c7609,3d19172f,47fffa71,f190936d,cb215f58) +,S(73c5d7e0,4599fa7d,e09b8c2c,25c5bca2,b7ae4c6,e1b88e63,6de3363f,b1a8dbbd,1d9ed08d,558bd642,9e986b0,c431d67,9229adf,6fa8dea3,faf17da2,747bc617) +,S(370481d,a2ef4843,8d897c6e,f1a01750,b4788c65,62ad3ab7,bbf3c89e,e24827a7,a88b3876,c2051901,1d84acc3,3000f0f1,ccf794b4,5385aaaa,190e435c,760fa7b1) +,S(2dcbe303,3006f0a4,99dbb7d8,d34790be,f2b68cbf,649b9d54,eda8819d,637807ec,b82b46e3,c7ab329e,b915de2d,f3fa28d6,92cf43d,584f9bda,5d6f58f7,1a90c1e1) +,S(f45f3ca9,16db45c5,de35d957,c24f7a59,44052b64,f8f423c9,8a442f6,17bb4b7,79ddf02f,b3154d6c,da1d6a79,5c64de61,5b4a0ff7,810bbfc1,dad68e60,229b5a96) +,S(500caa8b,cad0567a,465c99bc,c4802553,ee17346b,e3a9ae93,4fe7e95d,e787605e,40847ed0,75dfc8d6,ae19dccf,73ddd256,4e1beea4,7f822a58,f0570c62,f238370a) +,S(30562986,a23962c5,5b746191,e23b893b,7bcd8b87,6fa85557,c525eec4,d64c3aff,2d5abe,41c45383,1b60c034,7bb55464,e19d8d98,8a5d5fe9,37337507,80577a53) +,S(f687d51a,32526b72,9ed3f690,be1e6205,ec72382b,6a30478f,63a18e0e,b48e422e,efce1b35,19c94f7a,fc54da2e,d36b15bc,f197e2ce,a0c2d680,211e12ab,7d515704) +,S(104a63f0,d385351c,c9ce207e,500ae7eb,22199ea7,dea65018,472884cf,a1ca505d,69c21887,50b20b3c,5af1600a,a2a2edc,a6de0be9,33d2e67c,e05ac4a8,30239cc5) +,S(50966099,4b7b8ca1,abf963e2,ff4d295a,eb3d59bd,43029c03,5e6ac9a3,ea80fc6e,d48589cd,40d019b1,81211674,854aea3e,56be56a7,bc8ae519,72963adf,327287b1) +,S(3106d6e7,94e5e135,1d788e85,eb0f2c7c,7ac22e9f,d1c86a0d,d22cf88f,54513c95,c05e593c,4568cc2,992849d8,4006ae18,4ad2888c,82ce8dfa,dbf984bd,2fa2bca0) +,S(4c967d1c,9977bdce,84f76ac7,13b9e5cf,d1081b43,de681235,e7914f6e,2059fdce,866470b2,a3e99b74,15c2cb09,83a5c7dc,fcc10d02,a28e90ee,206be515,e88968cd) +,S(96319099,ae8d7741,1d8bbb7f,bf58f62d,b4027b02,ff5e32b2,e4aff910,3a781a52,6c110074,daf2849,a3b148f8,dbba2f0b,d776eb4d,b787ced4,22edc5f5,67947389) +,S(7c93bb23,87a36cea,9dd7406d,95af56f2,b972242b,759728b3,bdf30fa3,58247ee7,21e4de98,33487c86,6da01e16,895a0e24,17cb34f6,e3d64e01,8f7c4d99,9e989942) +,S(c65e4a03,88de1618,6d9db143,387a3229,c764dabb,7c6ddcdd,c3ba9195,7f1e074,d586d143,8005b28,cea25a45,7c45c1fa,2137bc2,fd78417b,daa499bb,cfca658b) +,S(d895a924,90c28692,bcda380c,71d8d1b8,381b1fb1,a8108f35,4d9a17d8,64d674d5,d30bda25,a63013f,79ef5728,dbbcd259,c7cf2ba2,b00af73d,9804f758,7fde17f5) +,S(90467c3a,5b36b9bb,faffa164,63d1f70,c892e23a,3c7f1132,27bff1e1,5fdef988,4ec70191,40247d9b,3cfccb41,ba22ad76,20522577,1e33d568,946c8081,ea9b15a7) +,S(5cd03d63,d0e025a,7af268f7,8f53efc7,b4d38e5d,58da5981,abcad74,3e294c7e,c3729f6e,5517d41c,ab1510cf,ee4e0e48,f168e043,34dd8781,1a10b70f,b42dfb3e) +,S(5130c49c,652bc5ce,a3dd7629,bf362294,8bf69c02,f9806988,fc700a25,c7e964b,7e46e219,4bc9dbd3,99f98c7,b7a44313,a027ef23,1abe336b,7381c215,6f2cf563) +,S(95899c2a,33b8d4e9,13947306,6b924812,261a3155,e5a7ddbc,c5447796,8edd34da,8967be99,84240292,9ea7277b,5be0d045,bac79fb4,93a08a41,d4dc5991,da6b7cb3) +,S(3928013,8cb3e93f,7c4650c8,8184dfcf,6e55d238,2e75e604,9dd6e40e,f489745f,70b25e98,b897f3a1,c89bd6d4,72f2555a,56bdf04,6fb43799,58709471,f8006a52) +,S(a47e1331,b5fdbedc,e490497c,bff1088d,ba72070d,3cfc7997,fa388fc3,2f80b451,ca54b8be,fff00465,4086c75b,da3ccb9c,6244746,522124ec,ec22666e,a9576b19) +,S(cc1a608e,16c57528,3cbbb134,4083cfd3,f1b325cb,b48df6c8,2d50bed1,e0cfb96a,5b8aca44,67d9b224,413b0c98,78e09213,591b8f87,b024bab5,55120a83,38cc6734) +,S(d8354bc7,591ebaeb,7ae4d1df,2db3bde3,b7438d1d,69b5991a,5d70f6c2,c3fc3cea,efc89693,6765f03f,29422703,97591bed,7d95afc7,29807a31,fe266f08,9eab5ad3) +,S(6ac1c963,ceb2740b,212ef42e,6da07647,481ee21c,4e3fdd6f,f2ae3da2,8ddef8aa,4fc8817,1b6d5ae2,45453c94,f5f2031c,c52140d7,a110d9f,b1bbf3e8,e5164281) +,S(be130f59,b52e4148,f9c47469,778fb36e,74d4da3d,a00f5c4,dddd2e47,6f18b42d,16dcd9e2,f739a58a,22a7d76,1c1cdf61,c5b9f8b9,46449516,9398dc1,fbc47069) +,S(685db8cc,39864a55,68b56e59,96265bb1,24ee71f9,1f9f4f3f,fc3c79e6,c063bd2f,730a7141,8e5b2f7c,2d333b8e,5be3021,22b396bf,9a75f493,37bae5c,86b50f29) +,S(39f41ff3,89f74c1a,e25e564,b9bc189b,f31f9af,cf0ee4ea,aad66ee6,55d743ae,fbea0f6d,e25d4fee,53f0aad0,9338f739,26fdaeb2,edf9d8d8,8e1e520d,d66c8622) +,S(d7a69574,41bc9639,994737b3,d483bc0f,c29b1b62,cbf59f28,b12b208c,4c20ed1f,ce44e2da,cdf8158e,9c07ca25,1b9a3d06,91eea29f,41f824ce,ef2d631b,65ba8cb) +,S(85bad160,9139cbb7,2be86793,42b37884,22f5981c,5fdf30ba,4914395e,c1eaec9a,99fcd461,29e576b2,b25c57e8,8e3fe3ea,362055c7,843838db,4196a485,cf14dfec) +,S(2380bac4,d428a159,23c2ffbe,8f17da09,74d986fe,4210b72d,51a1eb80,23ea49e5,f4af7313,fde4c7f5,e45e38bf,c4d44bbb,3ca1015b,d209065e,5a6ab074,5ed6f54b) +,S(c0561359,b7d61dd0,e359108d,f221202b,97c1acfb,894f4e9e,46fc29fd,364f9cf2,3c377d80,1c72a9f6,2cfea5ff,350ceb32,75b16103,cecf492e,2901327,d27d83dd) +,S(72c499c1,b8f4f2a,eb9181d3,9bba5b2,76481c04,a588fc6,4ed438c4,920c2a06,6c994c8e,60825314,2a34867b,1f82bc1a,f05ff8ff,b3045e7a,72d01243,b2b1ce53) +,S(8de84cbe,2b66209,f8f8e2f3,f06feb45,66e02c9c,b5df26f8,84e20454,ffcf477d,c7f2f680,c4d07d88,69348e98,6a3b7ac2,ac9e8542,a019f379,6410b993,742a34a6) +,S(dbfec9d8,6581d762,e5ac8048,886b9d2e,9a2d02ee,63c5f442,7d02d12e,401710f2,6e611ff9,827bb1ac,a885acb5,906648d9,b46496a8,98a13c90,48868d,c0daafea) +,S(9dd651f8,6099edd1,b3d0ade7,82aae6b3,9588dc2a,291577f9,f2456f23,d1d0453d,4f6db617,f0d7860e,18be81a,dfb6d773,cd3f905f,98611845,5f5a0b05,ee715ebd) +,S(2fd8161a,c869de35,e777a885,ee608f96,356445f2,fa2f33d1,926260bf,9bd66a15,1d2c21e9,674c2d92,b64163eb,12de6347,98c6e7a2,9787daa,7c6b4c80,fd307f25) +,S(3f25bf89,24f505b2,3f1538ce,4940edf4,8b6d8765,f88778a8,495e8a84,a29dc391,70253583,e7e0782,18ab0252,52c613b8,34438254,9dc57c30,afd47297,2c8164f2) +,S(3c0f0359,d5f72344,f8f3d2fe,28458f30,467dc770,b55eab47,ff2e1ee2,6c773f0b,49583a39,459f19c4,5ac50d78,74626524,b9c25030,e45f2c7b,12729ca8,1edb33c7) +,S(56380666,ec1b5df2,36045855,fa0dd93c,87e38d70,fb170dd7,3be5c308,36b73a15,700690f0,b210ac6a,9aa91252,c8af8f60,b5cbbf93,8291fb11,7bce1f0a,759921a7) +,S(71ca710b,b9a5f7f,ec6b228a,af3fc47e,25f90201,fbe3c673,8bc6d2fa,9c9298bd,7dd2528d,c0750899,b1891287,170159ae,c759bca3,51e243f8,fcc9efe3,2f9abc89) +,S(78ddec3c,c938850e,7c2ec20f,98e1be3c,6ed87fae,827c9102,5112d0b3,5d264575,19072951,766a4050,c8585048,d6f19e60,22b9c163,f1799ddf,d486dedb,3d680321) +,S(9aaebafd,8852857e,8c670950,93dac29a,5813249,ed03e67f,3226ab3c,7b4ed70b,8c6a2acc,b541bd51,65e13bc,a3c4d2f3,2457bdcc,406ba71c,7b9cecd3,4705fffb) +,S(586eca74,941180fd,da16c7b2,8b9bf139,a3096a6a,20ab9bcc,6d12be5b,db2f79e2,b3b1d12,361609e5,afc5a7f8,26a21ea,ac4bfde,56016ad5,bfde6f93,a3488d71) +,S(1857bc3e,dbe4de2c,86fed7d4,cc3ee63,c0e0b6b1,36acf97e,e3638183,8d50ddf8,ea5e807b,e7a588cd,ec759c67,3584675a,8a7fbdb7,cc5a1835,119a4f64,8c275363) +,S(aa4cc744,7572c62,22a6cd,bcb8813b,64206796,27f5f7ba,863d8566,78e5b01a,ba969ac9,d259244a,9a3b7f9b,b3821a61,a4a97b8d,af7e08bf,f39f099f,8fa2f836) +,S(4588ec09,59174367,6885fad0,a43d85cf,d6f736b,cb276179,e794da35,204f36aa,fb835e7e,cdc681c6,ee1c89d1,dcbae3b,a9511692,a54c9c37,2f86f4b,cc7c62e) +,S(867acd03,7a3e5f86,99e33f22,72f7b1fc,25ce6622,5020a4e,ca3b3111,e880653c,e9112ac7,57d3f905,3249ba3c,ff64640e,639cd94e,5d6cf946,d8d7f3ad,25764646) +,S(5e0a4169,e4f81dc2,28ae4663,9ae3bd4,b527814f,4616fc13,318fd5db,26df370b,5bd335a8,fc23934e,bee2e32c,3bacad4c,c38cd624,8cb34ca9,e58f8add,3140d001) +,S(90053469,39df2418,1b5b2e57,82a82f15,542a55a3,adfe8263,663b4fff,b101c0f6,4ff0d589,973985f6,858f3837,89c3a5e1,74460778,3a1b1476,e3f1ea51,37e3d991) +,S(a99439a5,53df33ba,6a32f33,d90b1500,4e2db077,22a73561,8f4c3b0d,63cec63f,198e0929,f11fc777,ea9cd8a2,e4e6987e,6f9c1fc5,f703ce7e,7e6423db,39656cd4) +,S(51f2a136,1381ba14,c8fab71d,f82aa2e7,1c7789b1,b78c355,a0e2fdf1,5f085282,fd5f129f,ca15fea4,d6f23bbe,43197a3e,6e2b7b26,84934ea5,a97197cf,eb2d16a2) +,S(3a91f81c,8b064b2c,99509777,864c5b4f,bed208b8,f541f68e,82053158,2ea91d3a,9d59003a,d4ae39e1,95077329,e585a8e8,a542b594,b6010404,8573a01,23a513c9) +,S(71e99d50,aa22fa17,3f026dee,e728c114,5e491e84,e140b462,1056af19,9736c5c8,ff3e4f77,68588846,7c662729,1d947e77,699806e3,9bb0bb26,53f67ec4,176a4995) +,S(ad149e93,3a0344f7,3fb53286,ace2f3cc,46f7450e,e859980e,6d392001,7c8aaa39,7dbf4798,85a4f354,b4f14060,39a83789,65a5ab3f,f1157e3f,2a4f6fae,909e81bd) +,S(44f0a37f,5ad78f6c,4a40ca20,7969105e,86e79ed7,7ebbcc32,1a247f91,751ccb01,f404d867,911eb3fb,efb1e559,66b5128,70836d9a,12891905,af649555,c353044a) +,S(4f77dcc3,de8de08c,4c0a4a8b,29717868,50f5c0e3,b271ec1d,c0d38a61,b30ad5d,73c7424f,8ae80ee9,2118aa5a,b0aa65b3,58dc7300,806ef2fa,55836a39,4df57c69) +,S(794a108b,102a0923,6366efd3,8ef658c1,6d6d5c24,e5e2dc0d,38d71371,e6005555,871965ef,efd79050,69acf0fd,c1f84798,7c9e304b,5fdcbf75,1a6f6737,ce46ba2c) +,S(f1988561,234b863a,df5bd49f,5a0b1252,a72e297c,ea3083a8,22da48d7,14e8e594,7adba507,d0ab51a1,8c036612,dfda3f8f,abd2f573,d31aa03f,ca6eb361,a83fc418) +,S(48bed556,c07c99e0,71249b8f,7790aaee,f3fd27db,f82d1c75,491a18bd,cc3f4a80,9dae5280,21be418d,1b4dd08c,be5dbca8,46cf0122,d4943543,8561e555,66316e94) +,S(bbfef3fb,e53779d3,8f376fef,974bac74,ec8449bf,c2dc8a1f,3bfcb33f,943ab9c1,bea5b772,ee798aff,c610e849,5be0ea8c,ed462563,848030b0,8006c6cd,e312551b) +,S(42af3415,27b3cd52,3806b04b,ecc175c4,156839af,eebc212e,b74bd6,95b7f06,686e5fe5,ebf16ff6,2376d096,188de980,f91a5518,25bfa137,e7b46df,59dcef4f) +,S(3c56d78b,74ae87c4,6efea376,d58b7d5e,30749726,40c24d69,38ade127,71ce10e6,ce97decc,f9d1e215,d363b36b,6ca2bc6c,39fed00b,511bf883,50732752,48d54a41) +,S(4b122599,1944ef0a,ae6404a9,e48f69ce,67b52a1c,da4f291d,33afdb09,b789b61a,5c8be350,27a3f992,5377932c,b6d92bc0,62b1bc80,78e4611b,f3ebbe66,b6089571) +,S(9e42867,c02c9314,a3658f18,14d8c59d,71674955,2b00be9a,cd37350d,18d49db5,5d26d035,1ff90d73,d783155d,afe20cf0,39f65b1e,6d8d5d0d,831977c7,17a8c761) +,S(9643390c,5a95345,2a027d0d,47bf6fa8,306ab31e,5dbd8b94,402db973,275359ae,b354d7f7,1019e9c1,d23560d0,50fbd4bb,abbf492d,f595c0ce,a699721a,b27a3933) +,S(8b4916fb,86f77deb,505374f9,1f15782,1b6f7884,feae9f77,bacf5620,7e126b69,9a83c0,6d86db13,55c3d59,cbc87fae,ce6d2af3,64f9c213,816cb326,28be1fd4) +,S(d29df4b,109782c4,1f5ee9ab,b8488f7c,11de8efe,9552eff3,7ba3cf0c,d0054b9f,1bf06237,ea242c4f,bbe08f6,a79b6808,d1a5a444,1989fd1c,98a60981,40ca07a8) +,S(2aaf397b,a5405044,539167d0,55113acb,d4a20265,206ddede,203b8ea7,21dbd41d,374e32c7,1132bbac,91e4b4a8,aa32f308,13a81c2,4f7b3c66,63d8821e,9ef73081) +,S(2239b3d2,23eace6b,8ebd287c,8b6a398c,1ca58a94,5d8b7b81,7b1133f9,cf57ef48,fda880b7,4b54a8b2,8af4b26,78e03f28,f01d70fb,3e4ebbda,94ccbd43,e2b4cd46) +,S(8b3287bc,f47e72df,7edc9178,51edb145,b88ee233,9f254f62,e86ec624,a7c7e365,54a06bc0,9f60d54e,5f900868,c0c3d37c,db6d9969,1eb605be,321f0f20,9fecabb) +,S(d9accea3,3e3cfee9,10d7e1ff,3e87539d,ace742c7,24d6d36d,d8d981ca,984f7993,6adc974a,a901e5d2,d8cf5a05,a20bd02d,62947f81,5425e690,565638a8,427dc88b) +,S(d7fc57f8,34c348bd,e6692b50,474ee038,4af245da,40b8f6b3,8df2ae5,a8b3206d,b253e4b,41fd9fea,9b28e04b,a6db0324,231edb1,1f9af406,e38d2b30,244e2d19) +,S(25808fe0,ec4a1409,36b34e16,595021e2,b815f660,7a23d505,9ad5b5c3,14d9588a,d0664ad5,b1d46ef8,8c8a1eef,bb9df1ff,a75bc16c,e8bbcec6,6f4798f7,c58e7b96) +,S(e4474780,113955d6,72152fa5,70da35a7,59e67a76,29a39ecc,3226ea13,99927914,493cc170,aa2f0486,da6834d3,3566c78e,ad4eb3d2,837ef5ea,c1adf3f9,43793bee) +,S(c5040dbe,2af9d706,76ddd900,d00f1046,44e2b985,82d46f11,47602b91,126311ad,840aab11,a2316171,cc9b6466,778a9ce5,a7cabc1b,1077586b,91a8d280,324ddb15) +,S(23391baa,316d33eb,3a7ca123,6c47d4e4,8116cd4f,93bda3a8,12a228eb,437d9f14,1d81341d,9e6d76fc,1ca69af,f6d8d119,bc97c79,c7cb8b7f,1ebb54f5,cb7efd4d) +,S(13211756,3de3ba72,2fc6682c,beb39494,8aeb8fd8,c0b95eb9,45eab34f,bc39ac38,9b772721,8a4b0823,7c961431,e26cbfb9,aa527905,41b753df,89eb9ad8,8d74f006) +,S(3b8bb898,b27a2fc7,a1cf896b,bb5cd7e1,708b943b,afee896d,2ff77a95,ba789708,d81e541c,668003e5,5a1e13e9,6a1635de,7fdcbf79,c34068c9,248100c8,9d36c1cb) +,S(e1d70a2c,9af5c4ba,c505e4f5,5c0040ff,d94f162c,815a2e21,c7ce899f,e0217b4d,b25630d6,d20e0e4b,3686d66d,e2b1e53d,eb063b99,e79c212c,2fd3cfec,97a4532e) +,S(1b1e3823,a51778fa,d38f0c56,e2b36dff,a7e681c8,30fb41b5,ff1aaa7b,d912de1c,f2e99a90,a951201d,ce725855,6bf7fd27,bebe1626,8328116c,d593ff32,2584d4c1) +,S(1e31d838,94f56191,2c134817,55e467e1,8745a91c,d903102,e48f7282,21bda7a1,11dcef88,35dae18f,3c02c6d9,7f80896e,477a7b27,41203aee,5048c94c,7cd610ce) +,S(cb9ac34,795cbc99,bf67a7ff,2bc3b497,311f687a,51b5028c,422b0301,8ab7100e,5e5f0621,c804b35c,e01e95e9,a8dc13f7,e5ff32dd,8a44f320,74e44836,3cd0db1d) +,S(afc34ac4,67dad38,a0e326fa,1a656c48,24dcb884,f00a20ce,56c73835,b4e11c1b,c8b1c404,3f6d647a,382ef031,a02c10cb,77a033ae,bfc6dde1,d7508136,28bdcb96) +,S(3a6fc160,ca85aba1,619430bc,ba14e12,3330f636,7a78273e,603f85fb,e270aa81,594a2b72,86dbb390,945a7a48,3707bc32,cb72cfc9,19c241bb,61774dba,222bc0a) +,S(a840f695,657c9c3a,3f64f56e,af18debd,bdc1e4a8,e3eaee43,46b19601,433ce7d4,8a8a7ac0,ca41e2df,461eae96,bc00131b,1a77b824,7273269d,7a41f49f,ea126fbc) +,S(c044e01,70ec6914,c39d08c3,4a293268,65cd7762,d6e0f3e5,5f69d80a,e80a39d6,7bd63082,7ae51516,25ee0b5e,c2f97b37,6dd5fd7b,9205852a,92dbf922,3a0b4657) +,S(cb90135b,352b969b,45eb5c6,7cfdd288,2bf9271a,41da4b2a,a89dde94,eaa00b3a,14cbeca0,762d9b11,fe4b6d26,7277a8f7,b4dac82c,52634b49,2a84b616,2d79be93) +,S(fa7bc437,a24dab0f,21c7c063,3aa4a8ff,c8216676,75ea6963,c58c84d0,b182a0e,e24267c6,d7300c6b,6dd09326,c49359e0,fdf72114,401f244b,383eee54,d1a5aa35) +,S(e6354cdd,3f503d25,37b2bef9,91533ad8,35e95657,3bc8afcd,d0c1c05e,57b3299a,d6c17b70,6291c8a1,989955b9,ae9ef9c7,cdc2b6f3,f5cada0a,3c4d0b86,859ead7f) +,S(9da36530,7e815e3,df0dce9d,50d7d812,132ec23d,2bf0453b,483af1f,bb45cce8,bb374566,98a28ace,a86a1b10,2909ae91,3bbc4b23,22f4d09e,bd298e51,d067a8dc) +,S(dc457a1e,1a19cdc7,6ed1c3b,a416a886,13b25788,22d691ba,76319b8a,38c9d4db,39f93f66,de5a650d,d49919fa,294638a7,85e25bd8,f8285776,dfce813f,bbdc3b58) +,S(b2377b1f,1b1a0e98,5ff57bc6,64ca456f,ec216c6e,b7b389a9,62b9d82a,ccf0374d,383a5580,d723509c,bf114e74,b3eb9746,7a040fc0,6232adb5,dac199ac,77578c1a) +,S(8b1a6446,755d3a85,3851fabe,b95c24d8,2a5a86ce,5e5df65,78051124,acfc7e50,42b885d4,cb632a67,51a88aef,192a5bfd,ed1cd461,438cb623,1caf3346,9655cf75) +,S(9408819c,bacf1a0c,9e5f1416,23a907a7,c3a7efa2,30a15b3e,7d5a6ff2,5103f5b1,a9758ec9,d6f84f73,fd107451,f0ab79a2,1df08c30,cbb2456b,d6c68cb,c506f98) +,S(8bfef047,7b3f8cb,99d7c933,a884da4e,9ce6d473,c243d3ee,9c319870,b06ce25c,8bbcbd87,d06af17,550d17ee,83017c58,627f1d84,e8a07e37,ca73c12c,f7e5c498) +,S(2a857f0,c12202e1,1dcb84b8,adf582f9,8eff647f,c3803cc0,dc1d294b,414bdb61,9bac456d,a7fd9318,244af8c6,48ea23aa,62c8ae1d,af7fa9af,e430efec,46db6548) +,S(937b8c5a,90485ed3,d06b224,2ff53e6b,b94b1ee6,a493c835,25e3acb6,5d5cb5ec,d37b136f,f9fb374a,50f5a311,ae366ca6,c9c3d867,e9b7e788,da3b2766,a7ccd808) +,S(5f544d53,e2bfd6be,d9150ff3,6a1e5c5,22b24933,489201a0,65a0e0a0,3a43c77a,ba9c20e2,8c47cd98,1752c413,70ced32,8f4c847e,20165562,c3137e0b,12990f51) +,S(67b63388,90bf8baf,a5b64fa7,eb9fa4c9,e3249cfa,81a55cbd,9c297e7a,a7c807b9,dc185675,2d94b811,42b54577,edf808a5,d871ec1,6c8ba567,62061dbe,ae7625e6) +,S(587a9dd5,99cb448f,9f92ffa3,d6328032,b76604d8,386a2e2f,bd324628,98439442,496998e9,a893faa7,a49e73ca,2dbbf533,488aa687,51ffbdee,6b6d6dcd,dbae9870) +,S(36fb7b1e,c576ff9f,81077312,35d18612,18dfe51a,58642a56,8f80294a,63c29b38,34a45ac9,b82cb1bf,2c96fc1a,67de8a63,5c1a1589,61baf8e8,a2f01572,1566c4aa) +,S(87b71c8c,a0afecd2,dd8f49c5,109ff434,ab8a273d,4e4efcae,f775624c,71f4ba95,8519151f,51122588,76527c56,e1e6d9c8,5b3626a1,bd6ad0b8,1bc382cc,525676f9) +,S(acf65cf2,805c370b,a3bed962,c3ba3b0c,56c98,b81a696c,f433a0e7,a463e040,f093929b,f45be16a,f962762b,52f57ef2,dc7b0e23,cd68e3d6,63b3b402,15692d5b) +,S(e092bfed,8b010c85,b91f1674,1cdfb1d,e3e045ba,81297f44,8990475f,2147acf1,e0bb9842,ecc8683d,e4016072,86070da9,8c4d18af,8bdda91b,65770a98,77902c37) +,S(9bdfd7b9,8260bcbf,17812735,c70501db,ba386b7f,28ece691,97c871ca,610a52ae,9bc65398,3f8c4cce,731e01ba,a5f509f4,887d9a78,40620d9a,ffbcfdeb,5e371eeb) +,S(3db22321,d9311589,5c85587a,9095421c,afc8a80d,86a4240e,9a4a2f82,8643545f,42af30b8,2c57868d,e0f23c9a,fb19947e,fdd6bb45,4efc68bf,ddbf7349,8fb78eae) +,S(e9d3f14,a6a77ffc,f86decbd,c5e43fa3,c3757a64,22d37da6,25627961,622b3e5f,83ac0bed,1e2a714c,c6ed0764,da92cc17,fd18ee84,36d667f0,2f90f818,30e67de7) +,S(412486e4,f29b4887,e1448af,ad59599,b31b9085,8682580f,891d51e,9842f2a4,c31c5931,8c0d6790,c2fbbb03,9c2e761c,bc5577b,53161a8f,80d397f,de7ee3d) +,S(e9deec71,41ed506f,e2dafbe0,c9ab75f9,609f8422,a4b2da26,7c529d92,36b4ddaa,8728544,d8463bc2,d846029e,5d2a0a40,8dfb767f,9adb79eb,2209478f,6d94a21d) +,S(5a0a2292,553c46a0,823a1761,2b8925e1,bbf01c2c,5bcb7173,5f0fd6ff,b264218a,3097cdf0,adda0f10,a261f897,6447ff9c,12de696,8f05009c,e90d1575,e55dbae2) +,S(49cb2a37,8b681ad1,ba1dc23d,8d12f186,563a40f9,ce0ffd00,5bade11a,4928d1f,f235e2af,c0f65fa0,ff15a938,ad804a3c,fbecc5b6,e276bbd6,32a06959,3d6732d6) +,S(d4d71cb6,36881177,b05ad510,a621cd44,3dd1afd4,84d177cc,f99abdb9,1615feb3,3ad65378,de3eb9b1,606f385f,a950d533,5316c363,fb076c02,ac7f12f0,7562645b) +,S(591b2e1,4bdd6e00,64f798c3,14e86cc5,529c99b8,3f47d148,b7e3e642,35bfab2f,4f686266,fd2a4c66,4d6bbaf1,2a368d59,12a51789,5d783aec,a986a568,a8fa59b0) +,S(ee503c85,c984bc49,3d7b63c2,92eac9de,be253400,f4988086,970be236,47356876,bd828abb,6f9e89cc,741704e9,614d6711,39449bb3,a7ebdccb,976c573c,4bdaa47e) +,S(2f9b4fa7,2e5a1fc,ca36a3f9,8987c3af,756e78c9,77fd5697,758c95b3,14b3f89e,9668615b,3d5b3c74,4ea2e1ce,e909d9c3,956657f2,1a65fcf3,3f0ea150,1ca4a15d) +,S(18b6d06a,a34124f8,5f92b204,e2a010aa,a1f4aebc,6e13a62,34eb1c92,7afd46c3,66cc31b9,bdf600b0,7e624bf,a3e079f3,258b0ba5,5437264f,b460481d,1f4bef4e) +,S(3bc07963,bf758dd8,fff37d0f,30db6eb,67662a4d,65395688,1cc30340,ddb44ba0,60e11ef2,68209a1c,2df9a3c2,276db6f8,8e6dc1ec,b74548a3,57d770c1,ad057e5d) +,S(bf585d6,5b325423,afd49af3,c9fa68a,91498b5a,f0ee9e3d,d089b288,53a46a8,2f8944e9,ea484b9a,51256e2c,fa9e5396,4c000c1,3451cc05,94bcf6ad,e38e66a6) +,S(887c0a2e,be7a0257,5d5b59a9,11f40ef8,f0cf1438,d7f05a7f,64e9c133,cfb69294,45f334c8,4f9bc66f,50fde594,94175491,9c37c30d,d20f6a58,40271e71,60aec5c9) +,S(9dad7af9,a73325c,59a17700,fc3dc6bc,3718e79f,804a2116,1bf9a36,622f7d4f,2b7c225e,99c6a94,c7e326ec,b89eb8dd,40644bad,1893136,6442985a,e6159525) +,S(847e4f95,72bd29f7,4f3e9a2e,d73cdfcf,63bcb61c,9caf8694,7cb84594,a7dd551b,ba6ed282,e0a92c62,fa86286d,370cb344,f6f1182,a101c4b8,1ea89a15,b393ee16) +,S(25213205,df1c3600,4673c4b4,49256c70,b5d8c62c,cdd3d580,2684af47,f047a593,36dc81de,5af4709,fae2a47a,8a205647,95aabfec,42a79f3c,54763d67,ef096837) +,S(75228cd8,4866df7a,4713a25e,f2fb29fc,95ebfd70,5d73229a,b170cbce,1058e87a,fba4879b,cc02d3f4,fd25f056,c0854415,68a47355,929bb812,a7dbb30b,c012fe6d) +,S(74945539,22867c08,6d02fb07,c0424890,981a1337,42c63fe4,b6adadbb,59b68568,7d774917,8df8b19c,8af0bf0b,5247e751,3e3b8d04,46465180,341ebb54,1d1af3e2) +,S(69db7f53,2899e39c,fa0cbadf,c29946f2,71d28ce3,57f47f7a,609e0fcb,ffc9b04f,cb0243bb,103255da,ad423ffe,e1d50f9f,26da7cdd,764a11f0,a6694b63,199feabc) +,S(727ecdc1,fb4a0dbe,fd2fc37,8902f922,ec4aedf5,53dae225,1d173c29,2929f8c7,ae5bb2ed,13778d60,66446ee5,e5754db2,bfc4f7c1,64bc035c,224d495e,651f453b) +,S(903ced8f,ec2544b,e207f5c9,e2c7f2bd,91213873,5eebc382,b129e334,7ef25b72,2117ca29,ee13d31,5e89bf33,afa8b7db,ff75c795,6be40c8b,b2e41cd5,943190a6) +,S(c4d467ef,5149e117,3638a5ad,6fd36373,1c8906f0,80336ca3,3a6bbb99,1a03f33b,ea5b5b24,4c536bcf,ce3d437e,abf2fcec,431ad80c,ff975b63,bf398163,629b5c7) +,S(16b577a6,5f6d09f7,b23b2b7a,dd80a2f1,cff7a8a6,c36bfcf9,d325e37c,ea37326f,66ba8e2,14674e5e,228a6576,a52a791,84d98be1,db1a2dcb,e9073934,d09f15c1) +,S(ad4bcaf2,e480adfc,e1e45384,6bd7ddf7,67fceedb,d2bf1f5a,6768531d,9b63412f,51fa0360,47810f59,11b1b3a4,525ee72c,c4c891b7,56737f4a,a61a380,e9e741ac) +,S(b249eb38,52d2e787,4a52d776,d1bcb399,51ca65de,dd9e9dd5,87d73362,c33b571a,3e260824,14e4ece8,83cd84e,b177096c,62dd7706,a79c31d9,b1103232,53a66258) +,S(634192c7,696a01ae,81310d3a,59d2c53b,74dd0560,7e3be9db,ccfd1ec4,bde14a65,455b4850,e366e077,d86dcd70,9c787b18,4fd4cce4,4b92954a,dcbe5222,57b0e00f) +,S(ffbecbf5,d433f80,49e159cc,c14b198a,acc3c5ed,fbb1ace6,fd295dcc,4a2f5099,422e7aba,1ec66cf4,36489acf,9c03ba33,dd68d368,8a48685c,aaa1de52,440be3c0) +,S(65b4c4dc,1067e823,9cf4f1a9,d0632da,b6a8c83b,509a75ad,8c133dd1,5c1868af,f7cf5d9d,d7654618,5183f8ae,7f42a03,20c67817,9d5226d8,40dac1e5,f94d260e) +,S(d380ecce,9d603502,d518dbed,405b8d0c,8de48dbb,35d5b559,24c1a560,9bf9c67e,1ae84480,fd18ab10,9eb0ac15,265c609f,8b241b4d,a80b13ae,50c35f8f,db64c128) +,S(17189d28,b5ce1bbe,d78a1d96,15dd1a50,3fce43f7,19d042df,63484ff4,ce44511c,fbca28f4,7c7b3e39,4121b948,ba561289,85c53298,8db2fbb5,7596a473,a782350d) +,S(fbe332c2,e2a8b07d,a85ae4e6,1925bf3d,be685e4,fafcdee7,3f558382,80c2e84d,aa917342,5e187da0,e3f8c6d7,79b42cbe,b11c43e0,6b594eb3,e1a5797,ea4e29ca) +,S(8b9e8a87,8b5e725f,8b4bd518,22e9cd21,2100d1f5,cdaaf210,2d7963b,a0bc834f,331fb31c,c28f56bd,5ff1d6ad,80b65702,b2e873dc,4552c563,bed77a08,cc3ed659) +,S(97e92411,a3c0bcad,17a798ac,eca61ac2,34e1a68a,b668aa3b,d730cc8e,8de111ca,b0f170a4,bac15e17,2e75fb75,93c21a41,4794976,bafc7eb,7cdc4bf1,6947f48f) +,S(20358813,33a13c6e,cc8c76f8,2c279577,49aa3c1f,d4d51691,9cd23b25,d044eea8,480afaa4,8c86af0a,ece2f951,7df0f344,259fc4f1,4d9a5c0,ee73c891,780c7f29) +,S(caa1eccb,1575740a,90155103,9849befe,617579e6,22b7c343,a665beb7,a67dbcff,aa695bf9,f1c972ff,b6fd3451,1bf042d9,1aee5113,9c1ea577,e0bd52e0,a4e0a20b) +,S(8e7c2ba2,36f7a8e,fdaa212a,7fd6b883,f331049e,6e8f2bbd,138a3adb,c2620719,bd03702f,1434fb3f,5846c4e2,e779f8c0,d9b6e031,1feced02,20a618f8,2eec105c) +,S(e07dc033,6dcd04c1,fcfebf09,40c07783,88fbad11,8e4eb3b2,4dd637c7,baace975,b13bd0a0,e5eecb0,762ccf31,1bd53156,ef6f9268,50044195,10d6616a,b32a2c2c) +,S(6606c825,2679af01,9d8a904,4db0b28c,95aba791,d1c33072,97afa2df,bb8ce0cb,7505e59c,a9807993,5710de77,747868fb,10fe6c57,36ba2054,6477cac8,8e1d3cc) +,S(9fbf4cdc,ec48226c,b45450f,b0de5dae,2b31f935,2b99e0b5,22ab9935,1de6f061,f2e4d0a2,3da020e8,60a0d58a,2362b7dc,e9c5b646,7034ec91,a7dfa601,1ef850dd) +,S(e06d697,5195ffc2,988b0403,e977d32c,b7cc8167,e800db1b,976f6186,286916bc,8015370a,27d3d221,7af80e04,a49003ea,68302bb,c1a5c83,63244c0b,c30bb8bb) +,S(adcd67ab,21d2aac,65112fd4,e6e16cd7,ff792577,e9785a6b,cf4a3f0a,9293a6e2,6527b620,29062aaa,5058608,f5cc3bad,8e4f40d4,9b5be93d,faa5c2b,57fd7fb8) +,S(1d9069ea,b43a64cb,1187e963,d96809b3,5a447317,68910e13,3e0bf7a2,e1f2bd38,ab03dede,854b8fe9,4ad2f9a6,8ef5415c,fc78c28f,a4ec33bb,f15df31a,91e29108) +,S(f1f6b776,b8ec892f,148168ae,8ce83f4b,603206f7,2a38140e,3a422e67,a20a768,892ba036,3413da21,17d9b11a,7bb25cd9,e7136a7d,82a7f45d,14abfcb2,b9bff25a) +,S(a884f94a,ce79f4cd,f3a8d1b,f8a2dc3b,c21d1c23,433a7fb0,401c5df,1efab379,5f53356c,6e45248c,ec282fbe,ef03ddf7,c611affa,5d0d3082,dd630f80,dea05c96) +,S(b1988430,197a8800,e1016564,b48d4f7,1fb2be08,35e9efe9,81a80f10,e61da9ff,d5c7864d,ea7d12d2,5be7ace5,86e141a0,e515a41,5ec70bdf,44a68d8e,4dd849b9) +,S(15b73aa7,529d5b84,bd5c1db8,2b6c93aa,46985aae,942f6d4d,1094434e,d27fedb,297e32a2,bc8ad13c,42011259,b1ca3d40,632ac6de,f2fca262,75dabc8,ee721f89) +,S(339a76e0,443c1fb1,65992630,116e523f,8e35cc7a,16cd0f3f,57f7782c,7d97d40f,8990652e,fecd784c,33e75620,13b52e6f,914f0f6b,c413aa22,9e5bd773,cdfe9659) +,S(bef26cff,fb80ddab,9458312e,9b09044b,b1c535e1,84f4e51b,f64b5183,b67adfef,3818929a,ef076a83,58f20518,c5b310f5,2c6943f2,1675bbb5,ba1bde45,9d37490b) +,S(cdc56c81,8dafc273,4f4dae10,84f91b08,3dd40d86,23125894,c71d9243,8b2427e,f4b309d,e9c828b5,44542569,45579f91,b4376935,3f586c71,f07107f0,1f503cca) +,S(3ddefe81,b1f38479,ec9be80a,1961c5fb,a09312a6,2a775911,cd65200e,7d75bc6d,75d83edd,1eb9b479,4effae4e,ba8007d2,7c7e2d51,a9e95d3,a1e58358,56df055d) +,S(da7c6776,99032cbc,4c2bae12,59212cf2,a18879d2,63aaf99e,76339041,10576826,2e7a6d88,360ac45b,9871f779,9e80698e,4314cc3c,3f1cb1d0,c07ae9f3,38553f08) +,S(2611b435,e0bc20c5,88cfaa80,17f4555a,b8aba4c4,ae1c0385,9dfaa911,aa80d927,eb58f81a,e51dc504,465ff8c1,c0529fac,e47549d2,429e5b41,7ce0cad3,7d4508d4) +,S(b0fbe548,36f07c4a,a715aa08,806b71d6,b8f4c09,6945a7bc,3defec7b,67962961,cc60a224,66e7744d,c58668f,ede30ca2,1c1749b0,45ee50de,2a881a53,83e5abe0) +,S(1a03336f,dc51ee75,facb7688,b4603c86,77d371eb,5ededa9e,b50bb49e,c9020581,3fcf1b03,9c0edf8,99855fc3,6acfdbc7,bd507145,9be7e18c,e9f715e4,98daa7d7) +,S(763a1215,c8349155,aa849b20,f2f68a36,cf72892,49e4d3c3,810ee72f,78c159ed,37826a1c,cf30e1ed,a1795fba,d1f2f227,7b68d5c6,9ffd390b,d7dde5e6,58482684) +,S(7fc7b4c2,30183e37,dce0a586,a6f0188c,f7e664d8,5fa05eff,63f2c27d,cada4edd,fd7a780e,6ea89a06,f0649343,abe7bcf,6338d2fa,fe457f50,ac415c91,2bed6a8f) +,S(222807c9,b0686f55,d9eb7d7,412588f,dc543bfc,f016c8d7,74726135,dc65ddd8,b9670902,456c22ef,cb36d155,319393da,9a34b2b4,301c898b,43d957b0,a56cc2ab) +,S(79d8eb36,98d8d06e,6ca33f69,ca04d3c6,db636346,abfd603,ed0189f0,fc5fda77,bffc97e1,1b0234a9,8dd1d460,e19db522,931fd49e,26d7ab28,f1326517,23d955f1) +,S(a2366618,8e72e1b6,d5ab7713,decf6e3,1f801a6a,ac88ddc5,d464d127,ebadd34b,ef23da36,f3e71913,2774cd1c,d150ffb0,70e99ac8,5193faeb,b1736abe,77d60ed1) +,S(b6bad04d,dde6816d,9123e8e7,43fa46a5,b1fcbdb3,fa1f13be,480fc1bb,49dd9612,585fae09,a290b273,a68b7f34,645b80b1,850c6507,d959b546,7f1b0100,b6a4e511) +,S(2bf21c25,3353e715,283113db,8bb5018d,33fcbd58,f3d6face,b491e1d2,f4c3dfbd,e3a033a7,4e8a4d5b,c8c49121,43a47b07,b9fec4d8,a0d5b3ef,569c44c9,cf8d896e) +,S(64c27a41,e978e35d,63f3a90,e71091f4,41e9ad26,6a05edda,358dddd2,5d842744,fcbb625e,8fda695,988aac9e,cfe67c16,bed76802,3b527d27,521c1339,3dae32d1) +,S(620a1ef6,fdfe5b5e,9a4ef435,63cd7c8,af62acad,a02fb399,b7542d2b,6481a58d,b0b79e3c,550393a6,fa07f105,c547e203,a45fa7c5,ec825ae5,7bec305a,ddb8054f) +,S(1523f131,7cef7154,347ef68b,424ee0c6,15e71251,a06bf8a1,ecd74675,307b95cd,c72554cc,1d8ad664,dc1fe67a,3f11e5b4,a55806c5,53dc2612,bf5516ff,f0743b1d) +,S(d765303c,a9c8794,c00d4d8c,2cd73fcd,b43f763c,b753700,f66d7294,4eea0cfd,bafcaca5,204dd77a,a3a17b73,da3064dc,35b4cd22,ae01a623,781603d2,57bc267b) +,S(a75eb61a,fafce965,65198759,c25cbc41,ffbbf87b,61839a8e,a17f04ad,64c468b6,99802893,240f48aa,53c49b18,1a6d50e7,a8eba321,64d587b8,41497d9,65869873) +,S(7fa41b4c,d0bb91b6,c25813c7,1241e691,e7053f7d,beb0bcfa,4084e06b,bce59f2a,a0941779,755a695f,8317e7e2,f6a2c57,9431e22c,4aa09f,7e583b1c,e184aec7) +,S(816c0db7,2240f12a,d8deb440,8ae2276f,3bfa1bfb,d820bd6f,cc5ccff6,16e4dbf5,2a52c93d,d91ee658,9449dd4b,bf70255e,e57acbd0,a981ac9f,67c16604,3f7e52d0) +,S(33f635f1,317f1425,51390ac7,346905e0,ddbb3d87,b0c1780f,bb7dc950,c23414f8,7435a155,84eb1988,b974d570,bbc2b2c1,15123580,2bf93bd,b626a543,e54bfbcb) +,S(d2943ad7,4b0bb03,35307185,fbc438a7,bdfe11e,7b5e0eb3,e94bec46,a251999c,2dca8fcf,19aaa314,ebde41de,fff6e9fc,b6097d6b,3bfec06f,19aa4941,676d577e) +,S(26aa1fbf,c54375a6,fec54390,b5e44a0c,fb524b65,c10d1516,b0112525,9dfb1da6,49eceaa6,4c575ce,337d0b6,ee7e8198,83973c6f,abfa2f,d4b24e03,99a91b02) +,S(780aec1a,f866a030,5ca6d7da,1948f2f6,ab18717d,e82300cd,65eb58cf,a7d28d20,da650041,e45a0e1e,a9075b6d,107b6f7a,414b3a02,18aaf929,92cf2978,bc08b91a) +,S(1dcff259,8e59dd4a,3e515853,b3cc41e5,ef98113f,29ff7b3d,5eed6d50,2cb88b67,d7978630,7c6871e4,5654307a,e3836e07,aed86cbe,a9ab92f2,8c680172,1ab77271) +,S(b19af4a2,77321937,93e367eb,5ece1c63,8f336f3a,9cdb4b01,e2488ee4,373ff70d,a3ea8839,a5105a2d,4277f27a,26a8ee73,b9e73fcd,d54f641d,c214d5f7,9c821dec) +,S(1c8c1f29,548a9df6,f28b6126,b9324972,35f24e2d,a488e066,acf782f6,b4f6755e,1a79ab52,6a1e1aec,5ccc7e2a,3196a07e,78108b23,a86630c9,1795ef96,11ff432d) +,S(b6ff8dda,1ad6c3c2,3c8a10b7,b4313968,e4d70075,12c421d4,f0b1153e,bd5716ce,4d3869c6,b7b74167,ca0d21e4,edb3e01c,af8dbec2,aa87a32d,7c9306f9,a5ce61b8) +,S(dceff4ac,f61ba84a,81821932,9fa0ad60,ec08cf9d,830e6ccb,375488ce,d0f47b5c,949aece1,92bc61b4,883d5508,aa4a4aa8,fb1b8db0,385613b1,736a6eb5,c137d6f9) +,S(5561e7a7,b709689c,97c4aa18,9a3ce841,843ccf98,be851c8b,131eeb37,dca5ebef,4b108c17,f298be36,430e6b7f,26b414a2,33b924a6,e65dd5a7,9a1f15b,a99a14da) +,S(4d989577,89b01595,8e5d5bb,2e064e9d,9c56a254,5b3c8802,7ca0c997,a395a257,aaebaf33,ac950756,c5b200c9,f5b009c4,506964ce,5b706675,7951f221,40b6e0d0) +,S(82b58e6e,6373c4b,30ad55a9,d66cc804,e9da512f,bf4af668,1246a12f,e33bfc8e,8378122d,98dc1e37,2c33b5c2,1ff4c429,d6d7577d,2ff353d3,87cc0478,1a5ffb38) +,S(f49fa88a,a773784b,fe57d880,9efac44f,714c3d75,3669463a,d1199be8,2c6cdf3,41aff6c0,2164a411,c8be7281,493483be,aa9855b0,49820772,b96aa39f,9a18b3f4) +,S(67d485db,ac8445a1,8c1b97a7,8c1852a5,ce910f0,d78b073,969c58ce,c0efd78c,71dda92a,24ff2b31,5fcaa5a8,28bf07d9,596f49b9,cf19f4be,44e6f320,84981e97) +,S(9145f6f2,c19038c3,cff99883,b5a71760,30a46f7e,8b5d350a,db2a9610,4704d4cd,9d9179e7,852ac5fe,1d4664d5,4d778b3b,6c8e422b,b6e78add,56700dbe,6a22b0bc) +,S(492d5247,efc2f5f1,1cf3848c,e0719abd,53674089,808de4b3,5503e23f,46b2631b,374b0762,7812c898,7ed68877,c995a4d4,9f021d0b,29270863,d50b8c40,808fd750) +,S(5b8ddfb8,bb811678,9298d231,72bdb9c5,25c6610b,46187549,a381ca6,17dd1dec,b47d3764,fce3218d,17d0dee0,133d4f3b,c7ae170c,3e8831ce,a92a3531,7b1f7568) +,S(88db73ba,25a61641,af5e603c,cd54c6d4,63c6feb,da11ec5c,6a35d30f,e406c65,39b06f7b,1c1dd7b7,884c67a,e295f8c0,9b8b5be1,c14456b,4027bf1b,4800a753) +,S(3495cc9a,a23c1eb4,2cd85070,bb095563,2a7037bd,e330f721,fb38091a,9c382451,7feabb21,6f3982df,74429957,3c7557bf,b82ff4f,462fc64d,d9b3e10f,b69799ef) +,S(e8a5cea6,970e10c7,93f75666,9d2309b1,a4f7b52,c19db4f1,cd69a652,c445d7a2,daacdabf,bd5259bb,96d2dbf3,668e8c16,fab47624,294d9982,b961f0ea,32402b96) +,S(6e8c78a,e81a7ade,3989c483,7d9efe50,51af33f2,b2b2ee32,b5700b43,67931f9a,e5664504,751b41a1,45b5412c,be10a782,7d1d5193,30dd69ca,47be2975,2c291d35) +,S(b8f520a3,10c5b2f,8291722b,1e3a92ec,b9551db7,744dd208,ab4d1709,310a539e,65901c3a,b6712ded,8f66451e,1915113f,a96d3d1e,d9074790,9e291d00,970f3d75) +,S(a0538458,64459815,888bd917,3a2c16fc,ae0deaa7,cb804adf,e49dec0b,b2d8005a,27882f00,23dcc9fb,890dab73,f98925d3,e712608b,3d6069c8,ca58ca6d,de0d7a67) +,S(41280416,aa7f0924,1ed8b631,fc2959be,2117cf03,9c12f600,1faf8a05,15222144,c2fef80d,fd8e8433,ee55c363,c43f7e06,613f354e,32aef8e1,808817b1,af7f58e4) +,S(c4b8ff36,cbf83d10,51d130b7,e3d613b2,8b536f0e,b050a41a,7dd8f8aa,18c7a1ee,87d3c44c,8867337b,466ba76b,47512399,f6cf6c14,ad4977fc,276d67ec,5e7b4d47) +,S(40eb693a,7cb938e3,a6b85010,6b7cd257,1de630b9,86da02a9,3b7a7f5a,a0a51ac1,27b875e0,14d3417d,cbc3b770,c4cb8805,c7ede7a4,efa9f89f,a51e36c3,af6d8d18) +,S(f7491902,54e30180,75365d67,5f2ddf24,ac0c9d84,df371fb8,6e94a9bd,7f81dad4,6a271b36,c549080f,dc9bf1b5,ad275d62,68af0cc7,2ec68c7c,17ac24cd,5c5a6e46) +,S(cf13261d,e4ce19da,14e6996c,97a23f8e,f16388ac,c364f2e3,6a053254,849f287e,5568858d,be1a7447,f7e4ab51,bb872a78,8218c483,c771ab7c,4a0a968,73adac10) +,S(9c6bda62,9dd087df,d5516606,62226847,94cfd517,72c72a81,7263c761,ad3e8cb3,2c77dc7b,9c7fca7e,bb35628e,d62ffc79,9e5fbcc5,e25bb0be,5b1b67a,10c0eb3) +,S(d8d1035f,64439dec,20ecc9a5,5b314959,c1526d7b,d15b1922,bb7ab7e5,b9d26bf3,ab7e34d6,ccfdfea3,f607f697,b941bbf7,b922a436,b9cb4314,3eb1b948,ccdbbe30) +,S(c6f40a23,b8227a60,de32e104,7080f087,7d53aea5,b00a22a9,39cbc228,d1c1d424,e16bc58f,cf4b8c5c,9106f1f4,b8b2374a,63a3136b,e5a8c64d,7fe6bd0b,c1d80345) +,S(3a69da22,9477d3a5,7147c2de,cce22de1,d1e007cd,61d22509,49400b8f,63a43536,c79c4fd5,c4ba6062,c7cc95e1,c9b79cfa,46b98cd7,389cbc39,25cc2fbe,49a0e284) +,S(1b5fb8e5,492fc48a,46b7f6fc,a658f218,814c3d82,90aa339b,7bc7b794,325fc9d,a6290b12,4c9e0819,2b6f49f4,c4935b01,d2ca4235,8efea982,1646fbe7,dc7fff39) +,S(fdba0f02,b004b4ea,dc9e1c37,d1a7fa7e,8a755922,31f054c7,47bbe8ec,349a3845,42da61c9,e96471c2,6fedefd7,e30c43c9,6c3c09d,d72d662a,e2b82022,391646fe) +,S(c39391bf,cb7b9662,be7279f7,6338988,7c166343,2faf1760,f38f0cb3,a35140df,ea14e034,53dc82cc,484b8b3f,ff79d81b,449f9f81,d7a52d66,4c5b563c,9af556e1) +,S(254ff13d,c716cb2a,1ac0e36c,c6cb20c4,19aedd0a,2219321,675e1744,859cbcb,2644cf3,916d26af,9e36bfe3,247f5be8,896e02cf,83eb3701,c400ad2b,92e35921) +,S(24e4aa60,e9b464ad,a2c8974e,98568026,1769d35d,aa7c8c5b,71c9f57,28930474,9df7c2d1,82a94fe0,80a2244b,ccc9406f,6ed37c38,d9cbaaf7,8d973538,e8479f8e) +,S(7ad9bbad,f906685c,3efd81b3,8599fc02,fb19a4c1,8bff1ef8,702c4f6,d17543a6,9878b970,9c4018a4,f713ac8f,d8a533dc,da45e243,44926df0,133aad64,c5246f95) +,S(97d8fcd9,383a8717,e0c9eb2d,f7dfbaa8,c6e08339,be5fa2b5,1d12565,62d8ae53,1879ca4c,f5784f86,7f8363e1,5d85afa7,b1f114ca,7f8f474c,4a2c028f,7c6a777) +,S(3e0fc785,5a08c32e,1e14d1a9,2c56ffac,2af1acef,505ed72c,b8771ddd,8afe7572,6d79b7fc,fd1e8894,f0844fc9,da30b555,bb1768f3,df15a0b5,884e5b09,6e149390) +,S(d9da17db,b132d864,1da3a9b5,389d6f5e,fda483e7,fc7577ec,55b7ecfb,65602562,80e471e4,5feb0d70,2ee7f9e6,3f8f23b0,33a4f35e,8a0841a7,b67f8c63,c623b70b) +,S(1848f766,afcd1e34,82935daa,7b71212b,f38e2853,9d6fb9ec,a3d9809b,6fca18f3,ca9a7882,645d54f2,49d35df6,3748ed94,5f9196f4,a93d4b7d,ee70f44d,b6f5884) +,S(ed3744ae,9a7dac76,5ad65b2d,4fc2d15f,1a9d0047,f72c6be0,a849ca04,497a9f2f,3cf76d2e,d4e5c6f7,e4b23d03,23c477ef,2fdc5248,7066ef36,b763444f,6ab5fb5b) +,S(c4607b73,edf3545a,b10a3a65,e0312707,91212acc,a86226b7,b1ccfefe,5f3676d7,31ad465b,8595f783,d5c0cd03,6230e3dd,2628ac9c,45dc6d77,28c42093,3d7eb3ec) +,S(1c0962ed,2aaf69d7,8b20af04,93a3fa50,bfb9ad1b,64eb0699,641e4b0a,bc0e96f0,49f11af6,e088e3a2,a429c5b0,a87a7f6a,591b5a60,a397c123,2d56a4a,adaede44) +,S(6a0476c,9a41959e,98dc6ca,fb7b4381,82250e1a,ae62445b,1f09a098,ddc19454,56842c97,8ae3c4c9,2c266cd3,7c8e3514,ab4288b9,ccc7e33f,be552ec6,f511c7e1) +,S(24da0f6,53a30aa0,a6b14999,329f03c6,cdb59a80,e9ca68f6,b9367830,a0191f1c,83e79080,aa78bcf5,b810683a,f061c614,cdbd3b69,9e200b53,d1a2c757,2c138235) +,S(6c3483,22479d07,f5871901,3264402,a078728f,227c75f,6f33743f,9a1a7764,a377af74,4a125408,6bf128d8,45bda458,be779210,f0d85bff,eb192c0b,a0dcc4c6) +,S(212aabbb,4d14cb26,b26cf249,882b36e1,1cdc26f4,a1494905,15478f99,d5c43baf,e9140a0a,81d1582b,98eed57d,7ba8e584,11c22ea3,fc265148,ca1d6050,3847e281) +,S(a27478f1,2afca20a,8d46824e,5b0ba272,f26ee0c4,24a951ed,f371425a,b343b10e,51e74b86,a7fc97aa,5a3bdecb,67818d7a,70ad0ba3,7c7cd759,8ec80a4b,bc4036a3) +,S(e1c1269a,7171f9eb,a2e2fa7e,8f55e0e2,b9b8a507,e8cdbfe5,716f711a,572e293,41cfa170,8953242,f98d8e24,2e827684,5562c4a7,6d034848,e639335c,32afba46) +,S(204d544c,19418e19,bb328e1,ecc0fbd8,62f0f78b,24208780,4d5827c0,f5e09efb,c66098e3,1f5d1587,10a3799c,b4f980c0,18cf4ed4,534e49f0,6d057059,93d52fb7) +,S(16eddf0a,11a6f2f2,df230de2,f78b4cf0,980138b2,3ab196ee,361486c5,7a5172ad,e3db358f,ed8ab3c1,9204a792,6102c420,1327bdb4,fb81718b,b39a0ce2,b5992684) +,S(7c9f7831,2298d96b,65e6b7c1,2315379,3df7001a,79cb080e,af6829d3,2b8995f1,2037cc3c,90e3a0f1,b242018f,c53cb32e,b2481dd1,bbb700e4,a6019546,edf51e5c) +,S(129c2d46,1dbeb8f6,c1b913a5,b2d69602,63aee7e9,530c6dee,21168b16,6198fb1c,29ffeeb9,61c027f9,a2a14b72,a287d566,7bbd80bf,7cea0dc1,747ac25f,55137964) +,S(8be2e565,30d4932e,f6d1f9da,a3225b52,de204927,e0633b12,570a049c,1f6175aa,364b4e87,1a130cd1,40007056,e3c0951f,fabfe4bd,6a687404,23cc1800,505510c8) +,S(40b43f08,42ae9c67,ab0ceb62,453b4c41,42a6e12e,5f880c5e,27c90997,6252fa6c,6d1ac6c5,de1b2e5b,b225e46f,2c5a2d2c,248f11fe,d123ecca,4432a04b,cea2068f) +,S(47e2238a,2f34df3,cf1caa55,93c49db5,4c2cba9b,e3724f17,87473a0,5ac669df,4d04cfa2,3ee255f,eca104a3,60a52f7c,acfc6127,608dd908,9399be82,9cf31f3a) +,S(17286c55,3a45c6da,b4843323,84c565d7,b3de474b,5df8ed60,7c7a5c9e,e1cfc35a,6172d347,75a45151,60b104b2,79543107,5b194d24,793340cf,6d8723c9,6320007f) +,S(3451af9d,3c1492ca,d090bd34,45632ac5,a3e96c9,4d9ed258,b7fb2042,8dd7bb31,dd493383,21236e06,e7284fd7,84c1a3b0,7687c513,927cc79a,cc5f8b41,b14974d6) +,S(b00aa481,eccc5e7f,cb5bee2d,a6e0ac44,ed9afa3a,5b2a9619,d23d0252,14e5ce2,687b486,1f0032ce,f42ceb7,441f81fa,10d732a9,e7e76242,4a2ca8fb,e88866a1) +,S(53ec8e9c,c75bc91f,f248a239,34d735b2,ef706d4,c0761e2f,a8a55c7e,a0b23311,1b11dfc0,63c4b1ed,1b5104e0,15d5c5a8,c352f54b,9fd82768,8b5104f6,45d45919) +,S(1ecde1b3,9c072c9a,3b3eddd8,d71e3383,2fc80d78,7abb70a4,cdc9186c,a5efab66,4f5aec7,5a799762,b70cecb1,82049cd0,239f0c30,948a25f3,daae0bc,ae6dd626) +,S(1fe2fc3,702b558c,7ab9b479,fa08efa5,1e90239d,677052e6,5afc8754,9bb1394e,f6b586ae,3a395d3a,c216df2b,66d48fe6,11a64c0c,8a7db26d,30fbd720,c6845c2c) +,S(b53d0b2f,b8ac2ad5,582ba0c2,f031c7b,76e64cc5,28a5b9ba,872718b1,e06d5dec,8984e589,51ab87aa,64bb034c,17d23252,4101577,9476887b,351f034e,92e3a289) +,S(54e516,3bc2366,673fe5d8,1f335d81,a06ca310,a2116ea7,bc0ade12,8f37cf95,f471c826,9deb2c2b,f1b7206d,6e817355,9236607a,4b9930b4,c5b3a781,7312bd4a) +,S(e7efb772,a1d423a2,d39e2224,4c8bab91,3b8087ac,65d51f59,8c4db283,67b29a7b,f2dfb586,31d08b0,bf2b47f4,17f6a18f,704a39a0,a152e3bd,587e45c7,93a9b6e7) +,S(5ec59daa,e8a263a8,2afb4309,79ef0321,b163f2a,dc083e67,3446b98,d0b519fe,2eab4cc3,6a3deae5,30dc6aab,94e5584f,a8a5316f,5c05b04e,84215ea8,79ef82b9) +,S(427b5cd9,20589dfb,dae975c8,efc1f098,1119f69,c40d1216,58ccb903,d4bb62f5,d055e6e3,b8794842,4162803c,35fca878,6500b5a3,6871b18,d9846866,56d1213d) +,S(54954b15,fc594f3d,8f422c7,9dd42cb8,2cc30dd8,c0d10736,554844ef,9d05bcad,86a7cc65,73569c20,2aff8e04,21a00e4a,9c6b88f5,ebcc3975,64b4734c,f735373a) +,S(ff6f8f8d,23670fbf,2a1aa7b3,39568653,573eb480,67a2a1f0,1b55a1e6,b1f32559,7a53f1a6,c7cabc57,d731552f,9fd9447,36cd33f4,3f8f57cd,2d4ac1dc,1ac7e218) +,S(74d725e9,9021c210,e82d852f,41e0cb8a,3bba8efb,8a01552b,8420c265,958a2381,4ee69646,aa9f70bb,883d6ca4,e1016dd9,92f18de6,26ca27c,aeb5854,f5bb2bb0) +,S(e9439f7e,fc0342c9,c2d68fbb,c58d85d9,feca0570,d77448d7,6d3c3251,e49c845b,27da0d98,1b7e257a,eee90b45,9d0d7065,566667e7,a9287592,2031be02,3e233916) +,S(9684a48d,81a60856,6dd26622,b3ffd133,5facb32,9f2c4f1e,2c055cb0,a5c0b911,92038ad2,50adfbaa,5d587c31,f5e7b4e7,294bbd25,e7af1816,1be3532b,f24e68b2) +,S(1d003af9,469e26e,c7f0f121,4dc58728,9e4cf837,5f9d19b4,16277c97,1a0e7609,99c7c3a5,30822c72,b31dad8,146d2604,ed795f1a,7c37e139,c84afe9e,f71e5123) +,S(f96468f8,73cfaab7,76c32fa5,89f72c09,d680abf,c601642d,1c649ca,e197a149,1ffb4bc4,8495d31,b24a7ff3,353857e3,b6708186,c18936e9,9793e4d4,fa083b1d) +,S(b6ad4106,e30294d2,bcac86a2,131150bf,d93c14f6,51ec65f5,32904412,b3f89d32,19a366a6,74279641,d055201c,c4c42b43,4fa40792,90c1c3ee,5db2a4e6,38d228ce) +,S(875472f7,190bf305,9120fec3,ebb69fb2,2d47828,6cb1c108,a977e7cf,e45b9b9a,1adeffc5,f5dc59ad,e15d163a,95f8049f,a172d8e,30544562,50a7898,55a97c21) +,S(5445a9fa,f4245414,e64f7ae2,a1cb1b1f,54bb6fd5,af4a7407,4d9eeb05,9a27a670,496c5207,7da2e082,3e48978c,a3fb7a1d,3bdf07ea,61fde94c,e87741c4,e9418018) +,S(dae18625,704bac88,51f35026,7856830f,74d3a8f9,7c1f662b,f4c4cc3d,7814d138,abc059fd,7ba90619,83988ee6,35ec835f,c20f62fb,c68e2bff,373bda91,3be6f87) +,S(8a088f12,e8523de5,c7ce659c,107e1929,3d009b81,1fe94d02,deeca893,9d9845c9,4251212a,fb8ebb76,5d2d703c,bc18b208,41f8df47,fc5e44ba,ef7b0f76,7e29114a) +,S(d78f46a8,8f3b08d1,334ed25c,78f57910,716755cf,2bceaf6e,c25b52e4,d7af6d01,eb1855f2,29cb2010,f20b3f01,9cbf1b2d,929046d3,242446ee,5c9526ef,5b06f44d) +,S(1e0b4312,78ae0e27,5e55c4ca,cfefcdd6,f589809c,6faaefa8,3ec0d5c5,f99b034b,f38c53c5,544d3ab4,2ebd74ed,b8348503,fb523fae,9d73657,8bba2881,904918a7) +,S(f03155b2,9edb119c,f411f14,4a588f34,ab02d7f7,c415638,cd534465,ed7cbbd1,72d153e3,ff4fff14,b41d07cd,31960565,31736749,7f9c6495,599d3f06,b8e85813) +,S(f61fd68,3edc7fb4,d14c84fe,3416654b,8df66578,6d0bab41,53a96e39,e5de4c8e,952db567,cf0913b1,885d6884,d260fe4e,e11fc139,f58da12f,d38472e3,d42e5f92) +,S(78310e7a,29e437b2,5cb00e3b,13a4d86e,1ede6d8,4b1f344d,7ee9c7f7,e017dd77,26ff358a,4d5629e0,4c20f700,97c202d4,7030bd3f,43134a51,a7d101b6,e182f2d2) +,S(63ae8c4d,6b7329cb,a61509c2,d0b61ebf,4e6ac94b,c8a096b9,7a4027e1,1f781a3a,a8e954cf,bf407857,d19629cb,338a93a1,af16c929,ef8b96ce,2e483e95,dcd14f88) +,S(948d592a,594b354e,e2d03961,6338574c,ae662f26,ff79afa9,16579725,7cca739,37ff98e2,5ea0396e,89d3992f,773bd6d5,ce02758a,4ee25557,edc867b,2f1876c) +,S(653cf16f,a3140368,50b04de1,8bfee880,660a4161,4dc67a55,398e2d34,46100f45,acaaaede,5ff1e552,6766741a,ee43105b,ea4d3419,3e615c36,49c1db35,125a9202) +,S(46fb6882,8a5edc8b,f24fd1ee,e6a7789,141e1888,64508d2a,f3c511ff,8e8cc782,9d4ae53f,d52ce9bd,6ac9ff4a,e82c2e36,f4d26698,47ec90cf,ef383e01,37fd8887) +,S(5f11a0c7,23ea2a71,7c1face2,b4b0f28a,4ca44208,7a2ae0ea,e24c2005,7138c0ed,5ecaec84,ad97612f,ba7925dd,f126e4e6,3906eacf,6f991d5,bb273316,b80c8452) +,S(b9f49e1c,929bef7a,6d6b6b3b,deb10890,dbf2ba3b,3eba62c0,320bdc84,c2a9039f,98729e76,7e4f8b7b,bd0ecc1c,534aa030,6e1b684c,6f42d15c,2bf6820c,b501e558) +,S(ec8a102,e7d2905f,f273eea7,6c9a4608,965dc2b0,3631d2dc,63c38e72,15ade2c3,d8c899e7,242d96cb,49383686,8f671612,706ffe5c,368ccb6d,be5a3edc,f74371c0) +,S(107f02b3,c351805a,6c92a3c7,742a5259,582c5b0,39cf6daf,cdace604,2be236c6,517236bf,1ab47601,57d74685,8dc724a7,c5c2d55e,82c4a3e,685f389c,a99bfb9f) +,S(f0fb14a1,a5c1c016,d7b8c1fe,a8317872,b10d637a,daf6f6cf,b9860653,56298971,e1d9ed14,d33e65d,4258e87c,7280001c,c40b89ff,b3164337,92fbc547,964540d1) +,S(a5371adb,ea784ede,f6cce83c,ebde068,78a1c80a,ff83b47a,333f9b35,44489459,f5780572,127f5d74,773acbe7,b2a22cbc,7e3d09bc,ccd13edd,48ece3f2,c8129224) +,S(3c031e5e,1b0ba576,13c10971,5fa7d92e,2bbbb817,9603d3b9,99e4fadf,be17300d,d275a3fb,392036dd,474e65a2,cd7b6cc4,79cb40d7,1c363e6b,bf9c272e,ae9c83f3) +,S(87b5899e,685db530,a0969a68,9392080d,f8a1b9ae,523ce18b,2171c69c,5a5318f,6ae3204,e3f0afa5,a2d40b01,a42e84d1,1b1166fa,f99cec08,1f5af48f,fda775d4) +,S(d9f077dd,c002c16d,f9d8eedb,56b7e7b1,ea00d04e,3fe838dd,2ae40501,9b8bf74,6518d51e,503118e2,53cfc486,f70cb9ee,11c27302,ee5512f2,78f21265,af3ffeaf) +,S(9c09ab63,8d15acc9,609ce305,32277f63,7558a492,aefb98e,c9bc721c,f8921af7,b2cac58d,535abc10,8bed6ab3,165225f1,bf2f84a,9fbdf3d9,1caa4b79,e0f6fc) +,S(6ed1ef8b,4c2d9232,5cf8948a,5c369a24,52ab250d,ed0e48ae,1676dc73,9a8a7fc0,c1b7a08c,2cfe5154,fca74136,863da75a,5c6423bc,1c904585,f54ac87e,f6742008) +,S(882e8d70,154b7f6c,279f71c1,e2ba6087,cfc458a9,3079d8f1,3fbd3be2,506928d1,8949b22e,97c41872,9094ac62,e67ac1f2,8b31565,edbb3d1d,9b23a73a,6fe64131) +,S(708472a0,24c86ea0,7119d0af,b2509814,516840e9,fc23246a,a6da139f,b37aba52,9809b7a5,1d551532,a5b378d6,594a3665,3a8b057b,80cd530d,b7a53fbb,128fe5ac) +,S(3a44fad5,9a8b708,4ada1250,d8d08353,769d573d,71a225eb,d87a8cc3,af9fac3e,f29f4551,1250d0d0,a1974bf8,46124813,f9186e45,2d3c5c85,cb0c69fb,4b7f20cd) +,S(a3519dd8,e09e1bd4,160564c0,41c23362,36ba4c84,5899f90a,fcc370b3,cdfb9f30,64cff159,7c910711,d0199faa,6c74d08e,7150088e,34fce674,72dd3ec6,1b881d7e) +,S(5af16ce3,765f5c96,4eb3513f,19d99ff2,bea1affa,d68f829,1c4f0767,5cfcf1dc,864eb5,3bd711ed,4a842db6,b0164a78,511ff7b8,a87aa3dc,1f2402eb,a3815daa) +,S(1ff9a522,19cae5c2,5de1ec08,2641040,18848bd1,37a5949b,4021c2d0,563d54a8,546d634c,122276e1,b5cfb919,a5374309,8f85d7dc,149b14d4,791c83b0,1718e031) +,S(d7a6dcad,72a51ed8,f84926eb,cfab368c,7f02fcdc,aa66482a,c6b6dd6f,43d3e938,9a273cd6,3ea6ac86,5a68f378,e4466ae9,8598a058,6c97278,bde63b22,14e41c96) +,S(154f63e5,5bdccc7d,a696dfb5,2b6cd4c6,3c874b93,1f221282,3f4a8d19,1f32d797,e98f9722,17bca1c8,ea7269b0,d2aa6bc6,f0f29d7d,b340c67a,2df59135,77f76fae) +,S(f6ade08b,8513615c,ccd29095,c21bbdea,dbdbb7da,87ce9991,c27ec758,4c399bf1,98c81be0,19fccaba,131af074,b28a6311,3fc1c5ca,1318e96a,f037ad33,8f234ad1) +,S(9661cec0,3b2715f6,c6d29048,65fec2bc,b786b3f6,943a883a,3e51cb2c,c747637e,eaa1f7d9,9b34104b,74a8056a,9ec739f,cb9c3735,95f0b254,7fe75620,4f5358bf) +,S(e0a5323a,27d608c7,34c03465,f03705c3,480520cc,f5ac777f,53d498b4,655d19a1,1f727d78,a8b8c562,ebc60679,8462975f,63d88eb5,8e7cbaee,836bd629,260cc606) +,S(bab82efd,4646f2,f281980d,5250c6af,8206e95,dece4118,c24ce31d,282f6409,2a60b1dc,26a20126,8df8375a,5656c55f,cafbdbbb,46b7977d,137cd584,8d1fb82a) +,S(389e1399,ebbe958b,1806e9b3,ee51baef,2d7edd20,79e6a2c2,21e814ad,e1eb2631,6c158633,1f3cfe45,9e71fb4d,112a624c,e48adabd,435e6fd5,2c9459f6,ce9ae2be) +,S(b78179ca,c0dc553d,19f08174,7fa4511d,87d8961,1ba44045,8c307727,729d4515,7020be98,c496a50,6e4caa5a,94577d71,ce0a80c9,bb974c97,a6892351,e83e0de2) +,S(867ecd3d,d170f9a7,123d13fc,fd90058e,baa6a6f4,12ecadc9,f1e14d55,ff104306,3c0db3e1,bb91ee23,8fb27689,79f2b543,d698c5e2,fde48dc9,e2535e4a,946759bb) +,S(be71654c,26a1025d,41fd4d08,384b2ccb,db25bb2b,c15704e5,697be2f6,d4eecd38,316ed20f,c37a2dc7,a0af8d18,e4da0efd,2dcdaee4,44b2c1df,cdfaf6af,49406afa) +,S(5a8e1cb0,24d62685,e755b9a2,ad1e0165,41690544,7963dfda,6b6deba9,76e9079c,4c793173,743330de,7a8f4351,68dde95e,3889db2a,91de0a27,d088a222,f11ebba7) +,S(3bfad00b,2347bd0c,f13a761a,d0630453,bb884d0f,ae3d31f8,57216412,b82e6131,ef33c560,94157fec,3f7fe8e6,36d48183,71e3cbab,6f5b0518,96ebdb42,aa545f61) +,S(2447ede,684dce09,c896c2d2,b5c68cb7,60e02635,3b4f2dc7,428191ef,5d2c1961,ad38a82f,e80f860b,62b39e55,44438242,5ad6cb54,d6e7f377,62427f30,1ef7bfcb) +,S(a5eae321,eeb4b9f8,e8807e49,ba8de764,e7685f07,417c5239,9d857d4,8bcf985d,2acf8aa9,f5c1b7d3,2ad5f523,39e65595,17881d,48a7696e,ed3b1023,ab4def1d) +,S(97de995c,5337d938,3cca5b97,3ab05e8f,dc035e11,5c435251,7e575a,e890b13c,4fb2d969,2e308a29,34c3fb4d,c4dcef50,9202505b,cd891f79,e8f91210,e069e6dd) +,S(b8caf25f,a864918a,f803dad8,d0abdf95,25b70f44,546b1f3c,c6b1726c,4438f479,7c51b5fa,c0f56eb3,6ffa8c5a,76c074a,c30e2f36,b069ed79,23663da,c9c05c9) +,S(b5bc868c,1b96e2a1,b24f3001,af140107,b2cade8a,5b1f3443,44521764,ad07b2e6,8d6cfe29,4e929f33,d5aaa456,f545c33b,672a8c07,b214a6f2,38bba367,4938d639) +,S(5f51587c,242a3b22,10db666b,f2414c28,32ea2662,1f13f6e9,784a8a1,373ff602,2c3b260f,ebf20a4e,b853950f,99ccbb9f,1b39418a,66adb427,f5886944,8b46c858) +,S(1d0be0f9,5009a2b5,12a52e17,e044f3f7,4f08e695,60d0dfeb,822b4674,7a2bcfde,c3a82bc3,dbd81877,3783181c,f7b81ddb,a742c3b2,4f866538,9335ce4d,8f3a159b) +,S(3ef0ec28,b8003331,a6621bcd,6ce30ed2,9e0e62d5,b492592c,cecaf4bc,8d22fb8a,fe2c84ad,77d40e86,c92a03da,e43cc7f7,512fd363,98db0133,7d929ba7,a144b16d) +,S(84c29a24,a4ec04da,c76bef42,732a3648,f62f12b0,e7f0ead3,2ef9649,b7555fc5,e7620ebb,283a54a7,10eb454c,f22e49fb,929ec453,38e457ec,b18a7f0a,794f970e) +,S(6bba6634,e75d5fe9,21f40f4e,5f1c177b,a309cd73,107f1e9,28331573,eacf43a8,33ffe08c,42168243,1f086b44,12209c56,5b47fdea,54671a97,9d86be36,fb421582) +,S(13b67af0,51b0c01b,c49a6046,d9e5b6ea,488f6298,9559dbfa,47cf1674,6def0150,d0e8914b,1c1bf0b,5337cc35,d84acacb,a54add59,2321509e,e29f1d93,a0237608) +,S(161221bf,b5dcb62a,ebeabc94,6ccc4a26,fdf779cb,63640720,2c5cf13e,93af9300,d3fde2c5,dd9d6df8,70a66bd3,2b5213c,d1a212db,61aec7b7,2a49b7e9,2cf83b2c) +,S(30c5360c,c62f5846,3af60277,2b52201,7eda1fbf,866dc3d3,9a590bf8,e2eb508b,c8e91af5,9b9a2b,8837dbe8,edeac615,6c30e8c0,1b7679f0,1aab4a81,cac44efe) +,S(c0659a7f,dd9151f5,ea67f38b,7249727e,640364f0,87371007,a38b800b,ec3576,a6f648cb,6fa131c3,5458b5a7,77440361,8c57faae,1ca33ded,648f1601,a5cf47e3) +,S(3215224d,b795a892,446472a,8e1ab1cb,7d50fe95,a6844be,43e2787f,2679386,25750662,97f28d86,690c7eb5,92cffc5f,faba831b,efc3e38c,c5e501f9,358a9bf0) +,S(257654e2,a87a7048,3bd15445,da5c554f,fe776264,998975b3,b19a68a1,a1871145,fcb9319d,c67f14f,9d7fc4ee,fca05b18,9efe2430,96691043,9c28c88d,32636ec5) +,S(a4786a01,e504f154,f3d7926e,6e6908a8,17c8a66d,6db33e80,ce98b17,82f1b49,576e4d42,fc2e4f9f,e81a2967,8b7cfa7a,7f86e8e2,662afbfd,b028612,d323a2fc) +,S(5140f7a9,260c9856,4493ae62,a8af369c,90b484f7,e82e1e38,3c5a59a6,62db1e71,4e5172c2,b0879dfb,63a6aa92,cebf9153,94ddcdc0,985261fe,2f64714d,350bae86) +,S(f559d60c,f0f50b7,9c7d6d90,18a579d7,b781fe13,5210d342,31e6cf32,4ca66dfc,12d9ceae,8e5852a5,ca95fb56,abda8e42,5f1f05dc,ca29e08e,2052bab0,8d4eed15) +,S(88907ff5,fa2d01b,c970e0be,53a05354,a4fb73df,9a337857,cc869a1,b0547e7c,f5853b56,cc1211b6,427145f2,6fca6aaa,5b26401b,c00db73d,ab9157b9,7fa3d2f5) +,S(cc1e4bf6,4541506d,8e91fba3,1e1d8ffb,c8ac82f2,4def27ec,fe4b3ea6,e58c45ca,7617497d,a875183c,684585a6,306956d,1efcf1db,2753fb77,5902a63f,38d27592) +,S(7ee2c437,ef744210,5b6a6f9e,f1edde01,6c39557c,93454dd4,eca10daa,cbca99d5,21754734,5eeff5d9,f30503f6,9515da57,3e6d7b70,dbdee5b1,8274968f,6f3772d6) +,S(72feea2,39f9b4a9,a3f3af3e,f6bf420c,3605ba4b,b42da90f,6539e05e,33e2465c,a036ff,df7adedd,c8c2ad9a,d029428c,85482cd1,6b0cd20a,36d2aed9,e9f553cc) +,S(363da33e,94a0dd00,669b627c,4d7a3a6f,c8a0cbae,2641707c,938c8f5e,99914a,9bda9a77,ef1307a4,e236099,c1506f47,a2f936dc,d478b59c,3d0e98c0,7af58bd9) +,S(76540864,c8394290,9af4a48b,bbe05fdf,93af0f8d,1ec9b6e1,a7e91860,f2c133fe,f06923d7,738ceb02,2213a236,daf3d6f1,b3cc98f5,a5ed4845,83ce5c3e,54a3ecc2) +,S(573f0821,7a318a9f,8bd945c1,62e9a4a2,51e38189,34709606,c94cb401,f2b239c4,7e78e4f2,7de69e4b,948b105f,ec3ebd14,496cc128,d7c73fbe,7ca1d53a,b746bef5) +,S(8537981,89234b93,b5009656,f57e5ed6,f90d2184,819a5467,213a934e,22b01f5f,c94a79e8,cc990998,e1c69bbe,89ccefa2,9281fc0e,c99fa820,ed26f01f,62e475f8) +,S(53388512,29890336,3b1ccd4c,1cf0ed85,6f00a30c,78004512,57f6132c,edeb6041,d56e2a52,f856d1b9,a4f8feac,dbc9a844,dd22f55,469bf722,fd78b44b,6983334e) +,S(41ede48a,750ef7b6,5c49f913,afb98961,c5cb478c,39c4c85,2f33aaae,b0e4796d,d74c7bf9,4b6c4680,18892ea7,f04b53c9,4bdfe9c,d1a4c65b,8de2409c,32559de4) +,S(97e931f3,6596f736,992eece4,eed6a9df,fe762139,3acffeef,b6dd3b53,e5f08148,3da89933,53b9c52a,9e76ce7,7404fba4,39a24614,b62d42c0,9b660e2a,14dd5f1b) +,S(4caf4eea,3ca8b104,39847633,5252b37b,5c55b664,cc4979a5,4db00937,b222579d,c266732,a93bdc0,7cf88580,771d58a3,45a19100,4c0d1464,62171cd6,291607bb) +,S(857c1e90,5b3483c3,3ab24ee4,e51e3839,b52960f8,21a8706b,b7ea7c84,9e7b1ca4,8d6e9d0c,7a578771,b358380c,4a2e6bc5,1c6b09fd,e9b40c01,be5915ba,fe69dd80) +,S(410ef70b,e0dbf7ad,a68fc124,8dcba3cb,10ec39a4,9686b22c,1e7ed2c1,bcb5a182,d26e9ea3,331a56f5,cef074ae,e0b4a5c0,e6925d79,808ffdb3,b7cb9423,247f9e94) +,S(8caf87a8,c831eb10,817e5ec3,7aa431a,89dff6f9,a7e63f7a,30710419,5751029f,3f0bd6e1,c8dda6c3,c8e65ba0,7c3a4649,13aad207,3c5da058,bfe90872,67c8890a) +,S(eedee2cf,e92d2483,54a6a8a3,9d314fb1,b35ca18b,ffb9b779,8c16d5fa,fef10e8e,cb515ab0,21f0befe,4b31181f,3f9ce1dc,9fcd12c9,6793d624,c1eb35aa,e514c4c3) +,S(8cbf7ac7,1e77b7f7,7bad6a4e,9116db52,48bb2a75,744d4312,f02eecaf,2aebcee1,765c4b31,f67b26b5,3d17f97c,30d09636,b6f6697f,db6b799,169a2c05,779b7320) +,S(70cd45b4,cd449aaf,34ff0627,f0e01122,715dc6cb,98642dfc,c19fc672,54995db2,82e59456,761497b1,84320eac,3ada16c6,ee184ad9,10b60c41,20f0c538,2f535c8e) +,S(cfe217f9,783fcfd9,1e79d558,e37bec3f,50e5146,e0f442ea,702fdfb,6c7c45d5,537cbd0e,86453fbf,c57d70d8,78c7c3ac,da225186,17bb4dfc,7b6f7079,95c419d5) +,S(9826c0df,6486bb8e,2bf3d4f7,4cfafa71,ccabd2cb,12bf317e,651790f,48579d52,3dbf3586,f86d6253,d3749c05,2fc36d16,ae3bb457,8d4eeda7,34f172dd,b9c57342) +,S(ea18fcef,381b4bc2,c6b3fa3e,3744e9c4,a13e13df,576c8e74,d0f4f596,e28a02c4,c3e6bf9d,2bc445d7,87103c7f,e595a30a,41c9aa4,c41d1874,d7ffe69f,ee09f397) +,S(6de2c465,c09d5a54,61c618be,c9c16ffa,21b82e5d,673033a0,e88cf90c,fe6d8f4a,367acbd2,8950882b,428a8199,d3b21f5b,e1c4ccb0,3280bf5d,28b65cf2,bc4ee2ba) +,S(d6286e13,ee10c7d4,5ae50f80,3d1a5417,cecc9c68,9efd2847,6ffa73f,1a183f4e,7ab92bb7,55204e89,c7e3ca41,1c829e41,e965ab93,57db88ad,37f13e93,6aa56f56) +,S(7526e6fa,ea67460a,25525962,fdb6f209,73f0c861,ef3c364d,fce83df7,23c3bf58,2c76a8e0,d5a8611b,d3274411,cb323751,25a21fac,12e35ae8,f008f48c,18e3a674) +,S(fccaaada,56d64a3d,6d1d5d89,719f51f6,e737c803,893e8b2a,b785070f,8879308d,8262c566,3facf792,efd750ef,a969fab9,a2ee95d3,fe6e7d7d,8685c6a8,479362d1) +,S(b60d13b8,eb8a5f43,cc448379,7a397847,bd6d91a8,b3a6888a,fef4b115,59b57fe3,abf73ebe,5d2b8585,76104acb,ec885f1f,8405b053,3755b8ae,94ecf838,60ebaa54) +,S(332d4b0f,4a0dd872,ffd6d2c1,4379f925,4250fd66,dfaa2d90,127e6ce8,c377f8be,37f3143,47c2350b,f4333d7d,9e0b17eb,110dfacd,d87ce354,b7887cf3,1bc6232b) +,S(e99b2ee6,2ce6d633,1e0e880,37bd138e,5d021620,b555b94e,52def87b,4cc5788f,c9ea06fe,dabcca9f,6df1df26,8bb3e550,e2858dc2,b91a7c6d,2c048416,4e5546bc) +,S(89ead438,2a977aee,7fe692a1,d7199bdc,5af24191,e80573b1,dfb056dc,49c54353,b572ddce,db2d776c,2a967f70,6b7010ad,7fec43b,ebe5f19c,2de0f9af,d9994ece) +,S(cdad98e,529b413f,b46f6fa,98c74058,4777baff,b090d488,59587b4e,d598268f,d405a95e,543e639,470f10db,821f8786,ceabc281,788b0cac,3efee830,bfed034e) +,S(5096ef41,1cc1332b,e67f69ad,3cc3140a,c269849d,5e0f4f5b,e41290e4,86ee2cc3,7f33869f,ccd4b06b,ed61f312,30a7b3f1,49ef34a6,f2d46bb4,18c45343,73f8268a) +,S(bc0bea70,a0966734,8607253a,2c8be987,8c4d59ed,638ecdbb,8b9f60e2,a4a5be61,e19111ac,3c2b4e0b,4a86129,e6c4c275,54d1ff0,29ddf320,873e20cd,16873b78) +,S(2d166569,ac8f5a08,e0674d3,8aa7d747,b024bb8a,5c8407a7,dc451403,87223ec1,48af1b38,62216a5f,12a7d92d,4eec4e59,445c1587,e22238f7,3dd1bd77,e19a597a) +,S(b8cbcfae,bb8b1150,ddce37b3,26ec77b5,2947cddf,e3cf1d40,f27e8b7f,8145ba30,d5234cab,8b2ad2dc,8630ec02,2868a1e8,ffc2c3fb,cd5f5a05,62b6fddb,34823ca4) +,S(fb396092,563f12f4,ddddb9c0,f1ac19d9,fb2e3ebe,608eea22,7a9aaec6,dc960ee7,65e565df,fda1a394,3d27f661,c2eb01e9,646e88bb,6943953,58c9e62e,c9823c45) +,S(1c6e9d76,b8dcdfa,90625150,db2274b2,f8da06ee,21000225,80affa54,a414b297,706b450d,9ab0b0,5466edcb,bbed8b10,85679fb9,78d74057,607bc2ef,a5666255) +,S(2e043dc1,46ecff0e,6e566b13,d985cecb,77f55a0d,555e0277,dc660351,b9fca1c3,1c4f1ca,f75ceaf0,a051103b,90a7abf,665da500,2aac4e14,28a71e45,726d8398) +,S(5ae17b0c,a1bf8e90,e663ee12,d97d7855,9549f9ee,2d89592c,b4b0bc9a,585f482f,bb0df734,931700bc,73c6966c,1e8e5a77,a71806ad,88d731c7,16f236bc,b4fc8111) +,S(fa8bf342,6a24c3e5,d3c11c46,e75eda94,fca910df,c906a71c,1b08f468,a7caafc4,ca69817c,db07fbd9,e35e6c84,65b3cf05,4e2884f9,e57c0043,5dcada4c,2f5954e2) +,S(2cdff1c1,846dd7f7,b9df67ae,a3f4394d,1e1031b5,de7083cb,f905afb,991a88a4,4bbd724f,3827e42b,7d0530fe,de304711,6ea0d88f,8e564d3b,507ff3e2,ef76f39e) +,S(6fadbc00,55ca49ec,afdf82b2,96504f89,c5bb8291,ca942df9,5f5b3322,9d3b6905,f7671184,33a8326,a56f9472,8c411917,911a3053,f593e868,c06f57ef,54b7df62) +,S(c514695a,2f26aa40,dceb15f5,5d5ea8d2,6f4a1e06,12591fca,2f5a00e4,b8dd0841,5056ba08,2e78b06a,90937567,73fc4ef1,652905b1,16d8fa6e,8005283a,b113266c) +,S(83dcb8d4,93474f85,54c368dd,3e188c11,aad758ee,fdd1f064,66c11e16,cb7ff933,104e5b3d,4e57192,7c67a029,e119e79f,d6ed6fb,e61e288,e9f8bd84,630a53c7) +,S(bc65cf8a,cf9a0b26,43b69089,565f9a9,5f9ae882,2e2b1127,a8bcabb1,fcc8a93f,fdf9716b,a31ddd06,a080ac90,f6699b78,23ff28c1,155a79c3,ae9c292a,14fb2143) +,S(48778fa9,520b12a4,12d74b47,65ad37a2,695e37d6,4070d53c,1e09cbd2,4c9f140b,cdc64805,bec15940,387b4c02,bc51b469,446dd3c5,b2e35b39,fbeca21d,769c373e) +,S(9db2c42c,6a735886,8edc8831,2ed6873f,28077bb5,32d186e8,41f67ddf,a301dc25,e01cb235,ec9db45e,e1193e06,46a325b0,aa0ac5d4,786d0ac8,56990262,bfb3a0dc) +,S(cbcff58f,62bf025a,43a1ef44,256b27ff,37c6c8f,2496d2ae,fb280734,9cf8da6b,4fd99ed5,2da32753,3a9251f,e1e136bd,28f5331b,c1101da2,818de6e5,3bb1896d) +,S(9d520b97,87e68c45,817a12a2,93b1df96,70cbcf3,91788270,93367253,6f4f3639,615e115d,2b539895,d91885ca,a325625,41fec07,9d8fb6bb,22d9ecef,b6bc0f14) +,S(c648ddc4,57c2bc,bc23d182,8cc6d6e,4b0bfd3d,f83b2e7b,3ef6a341,9225dbbd,ac9a863,38dd1966,9bb47e99,e67a3d9d,ec16fe61,dc17ecaf,209a7fbc,518ab3d8) +,S(ae11f835,ea96f767,afde3f1e,79221dee,b80ead29,7b45e29a,7e596461,e82137dc,20453bec,b65a62f2,8996e1b5,f1953acb,4c5dfee5,4e5f9a15,c2a2178e,4c452596) +,S(a35549ad,56f8a64d,d23b9293,d8ef5128,699f6fe,365c0fec,29280d0,a364d46f,c84041cb,a38c9981,3015ffce,17ffece0,8f55a292,3c64868,f11cd6e1,bfbbe75) +,S(75877029,af5575e1,8dbfaef,37dac89a,2aad8308,d473a64,9c347097,e35f8077,843b0497,d19851bb,ed243762,177cc69,603cd674,216cd65b,2e5a85cf,5fc2b8b6) +,S(44ee3168,ca7ffd50,c467b1f6,83e532c1,ae00b9e9,f2eb1ca,917607fb,32d4ea99,10a20ea8,120b5a13,beda9f9a,9110eef,22564e3,9b96c141,1e73eb7f,c92c3270) +,S(9a013c89,8dafaf0b,90678f92,f3bb98c9,461e4595,42cb07d6,477b6f66,7a5337d4,11f8485a,c96623a4,e6c9b773,f5cd9fcb,fec396f1,ff53205e,8774ba1f,da3c2a73) +,S(b45e28a1,44d54182,20819a61,5f50b349,3fa12d17,2b8b5bea,83e73d69,b6b47d5c,d987db83,ccdacd21,dfff1dec,43997253,fb1c2092,95bcae4,5b76c306,92c29f4b) +,S(9e7d6a53,49845888,a8865d07,310192f8,9a659205,1d2a603,cdc03d35,a641a0c9,ca1774ed,ace29fa7,f57e5690,b4d1c0b2,ce5f1fbc,b21fb323,3c001498,54f462d9) +,S(113a1429,be1b613c,567b306d,5805c163,e433a940,8ef14b01,b9afea43,54991f47,225ee5fa,6d26cbb8,49191ec1,a51e385c,321e801,9152a3c7,50014567,7b928697) +,S(32ec8dd1,2cf85df,931e2597,f6b005e9,6d6eb0a6,d0dd7964,77655d71,418d9181,fd718dd0,78b3e4a5,9bef7f4d,9c430764,3423bc05,e1aa22ab,dd7bbb,aff9d8b9) +,S(ada43267,f2cedae4,5e1a5f1,46151f89,b145db70,ef477865,b1218e91,72e9246e,d148bee0,4d1f4d29,f9f15c57,8b047469,16e39686,c2b2ca54,1f3e0d4b,247cf82c) +,S(818a0abe,debd74a6,91fe662b,edba1a52,65f5ca07,2017c6bb,bf7b9847,95bf0cbe,e7b2d06a,1872c73,6988da9b,ce273b7b,ac0f03b,90903bc8,da719ce3,89c0a53) +,S(2f49eb55,ef77da10,804c1a1b,f596f09e,ae76026d,f2d12f14,d80be810,7d0b3c94,6a225810,2f1118,eb689aa1,e6d4ced1,1a79036b,802caffa,5694e383,3e038b83) +,S(7fe54d70,54cb025f,6bef8029,bedbd15e,bf66d5c7,986c678b,a5cc5353,7afaf74a,fdc617ec,72ac6632,6d16afb6,69188554,a47a82fd,db757695,2296c10,b4ad89b0) +,S(84f59366,2b8284a0,c9db8675,db9c55d7,411ec9ba,deec1319,56aa3f75,8eed2689,836e65d9,6bef6ed7,825119c4,c4511c89,48042592,f41eddfe,4de98e83,acd0d88) +,S(c90aa830,1a84820d,e06eb6b7,1ccc9bfc,a46b1612,5e2b5f52,da0a6fb5,4185ee1b,ea86d7c0,b285d82,9331e05c,d99c58a1,cc213449,d9226efb,16135237,f90dc8df) +,S(ffb4d576,abae49be,69f047ef,636142a9,8669b2ad,9cfdcadd,c057d96e,192ef100,3740cd14,b2d5e018,33a700e4,c80f6a8d,3d95966d,a5238120,80a9101b,b7ec6c7a) +,S(408a8d89,67ad6bcc,eb7ebb61,89afefff,12c24b5d,2c33ca3c,8b78fca,cd403de0,3b761fa6,378cc42e,a28fb66f,f1d8171d,4acd3557,fd6313a2,cdcbce47,e1caecf3) +,S(580a33f6,153109db,fdde27e3,f1b0ab04,6c80c04f,18326712,3e3482e8,7c53b787,bb8073c3,fddc81e0,e99ac5ae,69702ff6,f70a33a3,5639add8,1d353c0,e428431a) +,S(2d310a94,7054ccca,c46b1100,88349ad1,4c7860db,38c698c2,505e789f,8344130f,1ea2069c,3c6ec90e,9c11be0a,913d90e,2df1875a,2e26aa9a,5d28dc81,3e3db697) +,S(2874282b,e7b11cad,3f22f2e3,ab835aed,5d82b424,24697b32,985231f8,6a7aa450,286332d,b2e1b922,222e3860,e41d90ba,cf39ce03,21f26b74,cfa23171,f0415c42) +,S(af9e779f,f77bf3a0,10af5e41,82b77981,6940f85b,9530eea4,8b36e401,eb6231cf,9d3d4350,dbaf15c9,269d958b,86d6b88f,4deb7083,ab1ff389,c13f7541,98e84c67) +,S(445edb8d,515ca735,26fd2757,73b2778c,bc93ad8c,a661b35,4471d035,688c1ef3,94917a3c,fde762f8,3b774361,1f36a13e,e94b759a,455382f5,55d64f25,7090dc49) +,S(e010c20a,370d5306,f89993c,f7ec34d1,3e76feba,2b6612aa,dc75012,701811b4,cb45172d,280d9be0,52d57a21,4cb3cc47,798a6426,f215e3ce,e3af64ff,106fd8af) +,S(d34277ca,4625c7e5,b1134080,cfb44cd2,ef548b3b,67bb73f9,eed42352,ae5af8f9,a35f5779,7a628f7e,bb37bd60,9e3f44ee,c391909a,ce27ab44,1ece58c8,d7e4a4df) +,S(be0b9399,3bd54241,b684977f,ea4733e3,d96182c3,c9fb1c5d,d665eeca,cb1d628d,37904353,744ed26a,df76272,8ec41898,13218b0f,5fb09da,dbf5be84,fb7fdb8) +,S(308295f1,ed4a21e9,1ed9f48f,d6b42829,edd9bd34,e812f09d,c3b2c319,fd8f3980,6835c34d,5c360e1a,49a14c31,4ee4cca3,797d434,897c4181,a8ba5d7e,aeac0230) +,S(66cfeb51,61aa879d,fd791604,e10f5fa5,c2e07a5e,66a37b41,2b88db32,dc495b1a,a0e07a9b,f8a2fc01,3e229602,b483bc26,5ffba9c5,fb6ebfe3,f9ff9c9b,3252a1e1) +,S(f42b8fb,849cea70,4cfb3d9d,334a4a11,bf7b3aef,9b55f648,ec885a2d,6fe39ba4,b60621e2,a36d4aff,9f75db65,dd381ae1,f5b0fb4a,bc9f19a7,36d160a,61e8b22f) +,S(429c1785,22906323,2ecfdc46,2666f8f4,c57b7fda,608cc8e3,85a31254,bfab034f,e190ba59,1a868f57,40bbfcb0,481aa04e,50b3969e,abc941f1,8e69816b,2962af35) +,S(c8939d7c,94789a0c,b95e4237,fb378ee4,9895b985,6fc67d7d,fafdf7b8,debf611,143aff62,6e94617,c36d05e2,3062d2d4,47feb77e,9b15e2b0,4370f81f,1cad3682) +,S(5e4155bf,56303243,24e15ae4,142ad81e,2b82aeb7,8dc3ccfb,1d36f3cc,4398ef94,6801f527,2325a3b9,a9f3807f,216d7425,b9083364,203f3b75,ed6f4ff5,eb5da55a) +,S(1196b198,53f093be,7bbfa851,a7114e23,eb01c530,6078965b,5e9dbd3f,8d1b573,794cf0,54bfee20,d80dea44,d183db44,fe79dced,fef0a97e,5c557fd2,bc628795) +,S(d818d920,74bb737b,7db8fcd0,168030e3,39803e5f,6b76ba1d,ea836ed2,c73a6094,6ac7dbb5,1f63118a,80cd2aac,fb5f086e,ff15d51b,fb4ccafe,9d96f179,176e504) +,S(c0276b4b,f5ccabe9,ed9a433e,eae5c989,7039042d,b273ed88,51db464f,b06c6204,489270ae,6349ac81,d481a582,a8581520,972593d4,9b3facc5,fd52efca,24f4756b) +,S(94b2a1c,ca23cd30,eb9b300b,43d0b24a,b898906,1c4d8a7a,d3343d7,cdd83307,47c5ed56,b709bdca,5b960801,58338b9e,e6e74683,99a50640,6075302f,9e481df1) +,S(f2aee379,df2bf54e,e4a1c385,c28fb64,9f157d2b,d345995a,66868876,ae7d5108,ae766bae,9c90a1f9,c9079d35,1676eefb,19a7bf8f,bd56a311,13f2dd56,35c8ef08) +,S(fc8fe44f,3dbdc4b2,afa9cd04,3601c6a9,e81e4da0,456ce222,8306bb85,ba9833ad,6a321b78,a98f52d7,64330a52,ea5082b9,2b07655e,ce8c5094,ce307538,6d56fe15) +,S(d38cdd79,19a4f3cb,fbdaa3eb,e2ddc10d,7444d04b,5830eb7c,5b8b464e,4c255c14,6a0f1ef1,823a2fdb,94a311fe,cdaebe7,e1904095,1ddaae6f,1a565551,2c8c15fa) +,S(ac02e6f6,13d8690,d0c71943,a26b5e9f,916ea119,d7773f4c,14247538,9a4b41f,eadc499e,436b4eab,bed9c5e7,68fd2f67,72659819,437708f3,99531ba6,c05ea2b1) +,S(3948b1a,c36bd462,ac7b5cd0,7076f9ce,dc6d1a75,1ff65177,d7d9b701,d06419c8,ca91fceb,a01c03c7,ab141ea7,1cceb61f,72d5d18e,77964bd2,732bb95d,191765ba) +,S(4c7dbc8d,21d600da,6dd4c0c2,cffd8842,ea9e73d0,5dbcb554,35e31971,7e706e9a,86a77f44,b87b7abd,29c2f412,97f7e859,6db46ebd,8cdb442d,35dc17f5,278230fe) +,S(75228daa,b3825e2d,9f8c2f7,a0743b0d,b7dec731,d9df5e06,98ee11e4,8244f623,963c2987,e122f107,dba37bdf,ed282ea4,75e33665,260a5aa4,51021a88,780a1676) +,S(aa3a86b3,2ed2161f,8f6ea92c,71b7a47a,b584a73f,102c0147,632d2c2b,e80a579,b8fe249d,2b4ec64f,dd345d3,210244d7,f7e517ff,7722c2ab,bc4601ad,ae4e6cb7) +,S(702b912d,9828039d,a58b992f,7d6f3af9,4c03227d,3d3c368a,bcfd3164,193f22f7,25892c49,3a32cd78,130a4e14,c714cc7e,b576ccba,396ad36f,71de5c42,c6bac387) +,S(4ca10c88,6d44bfa6,2a221dfc,10c57011,269f703b,8f6f3567,829d3b5c,9c90ba75,3323eab2,9282e358,d4de6f27,72d77db3,95b04a22,7f0374b9,dac3ecfb,4ffde3e7) +,S(1619ea36,30da6972,2caa436,2c174efc,f3601c35,2e946d34,2da56738,92b9c325,22ad140e,13b8679e,a6d88dd6,148ded7b,a1c12697,91c7ede4,b98a72f9,f0e881e) +,S(21dfdc38,18debfb4,9cd409a8,a302f8ac,64d589ba,b65074c6,365bd398,d34d3032,bbbe7ec2,e835204,a786ddcd,bb6026e6,106d193e,21725c45,79eb17ce,784099a9) +,S(60fbe5dd,802f1ab2,cbae99aa,12cce0ef,36a472e,bbb1bd1,c0ddbd40,85069fe1,ea83b59,2dd304d6,82fd07a6,85408f0b,99feb1b2,b78b1316,7f9be524,a7349dc3) +,S(c804b465,fdcdc5bb,a848ee97,559405d3,dd7c2479,4dc4866a,e29676cc,1e147f96,aa4a2eb7,1fd82b70,ebebf43a,9b828e4f,fb10cca2,cf9bb522,3a7eeef2,5badc5a2) +,S(77a6e3e5,51373b55,dc51b338,3c32f6c0,5c74cfbb,3192fb7b,d96d9d3d,d50336d9,21d2326e,86efac71,48e075c1,ffcd573,5de35d6e,3856f2b6,7d358b6b,c6f047f) +,S(86ddc187,4a72eed2,666706ff,26a4ec65,a89d82cf,64e3d8c9,4731d62d,d5f7a5a,51f7cc40,ce45a123,a9217816,ba3e6dcb,40507b5e,4cde95c,443ce5ab,4f0cc29c) +,S(cf49d0f8,db8eeac4,6c108675,a155e327,8c80d5ef,84ea28ce,4a596f3f,c7d3beca,6ffdc741,ebae75c3,ed82dcd6,a6191d68,7cdd64a5,c3146d41,235b96df,420086fc) +,S(1d75ef89,57eb6722,2d60e872,1e126cec,c9f5c851,5fe18381,518cb54,b75875f4,82c5dfdd,9288561d,dbe4ae2f,5fa1d429,c2076625,7765b3e3,7b99dc66,b78dbdb4) +,S(bea4b735,f62e6122,9d8d9466,69503348,5bb5b7e3,c6ddb6dc,a292ca89,e7ad0689,90e3278a,8ea9e10,e7d9a451,7b7c01f2,7cda5836,f52a011c,d8e20ad3,7a08901) +,S(e85b0ade,a90e5170,18d0aaa2,75d5989e,577f5cf0,b3acb728,1af396a9,6169f2bb,d42970cd,3ca175c6,3916fec5,757b7f5a,30ef1269,d4083358,667f599,e650aaa8) +,S(d97592dd,24050526,e41ed550,fcf7cc2c,82ca5584,c0228f5e,3ffe42d8,a3928934,eac6c169,6bf01c3b,759a3852,a0236f4e,4de0db45,26f2d26a,2174dc4e,fe2d102e) +,S(e023ea4,50b620e2,378e60a9,a8c65778,fd772575,5aeb53eb,edd35ee1,666e00e7,4e4ed850,6dbdcf89,b060f0e7,8915f506,6bdd544c,e37e1e30,6a966353,6894797e) +,S(615b5c95,5cd4fd6e,a581b9f7,e6a857be,a7c0ec2d,c302dc9c,c8304ec2,d935e5a,c221c766,2602325b,bcd845bf,f5d754d9,46fc8074,f36a78d3,6e421b14,fd5f4d46) +,S(b1dfa434,2e12021,b9ce34d6,1391bdb,fa2a0d85,a004985b,c2cc7358,96ec13a7,fa3d115a,8162f828,1dbb7e9b,6f818b4,13c2a5cc,58993ead,d103ef59,9748438e) +,S(b64b601f,afbe47fd,ac675b83,5e4ecdc8,68c7e1ab,32598974,36ba3c9c,bbeada7c,af78c039,d2315746,feb60662,462dbc9a,652ae90d,573487d8,5ea52374,e9dbe68d) +,S(5429d346,fda1d9c8,6c5027d4,e94d7565,b0981f23,52715336,4a0f3264,6bb579cf,5b8ce197,dfecd92e,390754dd,2d74636e,162d6659,51464f37,ac696a32,995b1880) +,S(890694f2,56d6718,b040bb78,1041749c,20e21669,f3787f94,ff954b16,2a6f005b,d966934a,890dbbfc,bb90d7b2,26afd0f8,7bf505b7,31b94df3,5df1c141,2d753341) +,S(3ae75292,cd0526b7,fa6987a0,5fe060c8,269b5d1e,44a2867c,cb92c2b6,743cc117,10959cc1,5a74a82d,8f7d5416,a33256bc,f004eee9,87b82871,d22a2dd5,f2416a94) +,S(9d745a9b,ff717d55,5a353fd5,f1b9fa1d,347bbade,8a4abce9,3bb5dc7f,299b0707,cef338ae,d513c60c,7304f615,ae734de6,10461cff,ade0f69b,bac28e6,7ede8134) +,S(699e9c2c,8130c939,105ce7f4,f922c060,abf1b896,648509f0,aaab9519,d144f166,882b490e,1fb9f944,95d14583,83809d69,bfb7da29,97d244a4,38da39ed,7c3a19cd) +,S(e3a01cc1,dc520509,a91ea704,bcbfe298,ae79b4a5,4f433550,3884a1a7,85591f87,f3c641f3,68d19d57,fca87e54,6ddaf495,2480a891,37490b96,6617fd4,1edcc64e) +,S(5d150dc3,d9df375d,46dd2362,34498514,cc7ccee6,fd8ff5f1,ee5ee38d,6ac433d1,2c091250,d2e2ea0e,7d80263f,18401092,399a83fe,bfadc061,a32316eb,52ab0316) +,S(49fb9761,bb12ba3f,644aea5b,5e011f80,ec477880,58a6eb16,c100c5c2,e0996a66,7134220f,b7208914,58499caf,21654c5c,d9086b1b,92978370,89cfd06,d655e23c) +,S(34c55eb3,a4512dfb,de799021,1adcddc0,bdea055a,1f4f7b13,d530c945,2a44738e,258cc688,beff401f,9a910e26,d0c979e5,fdbb695,323321f2,ba39a4c5,4f98fd16) +,S(7068fcf0,7c3efe00,4ff7b82c,2af0c9cb,9b1c39f2,30dc602a,b2508d42,30a3a98c,e48730d8,844578c5,2e7657bf,202b5df5,2fe50679,7e2e1d77,aaab197a,e37ef1fc) +,S(e1d8910,a987aaa1,12ba1f95,ae8e346e,f49e5254,a2b01909,f73b874f,6b355a1e,8ad0311b,cc4947d8,999c2c14,9fd5c59d,d4a56a20,a0b90235,d7bab907,fe3cdb8) +,S(92509b88,ba8631b,16c6b2d,c60df45c,6bdf06d8,ed4dbd57,c10ac3cb,72d2caf2,3ea47a31,633b6299,a9f95651,b95f1411,ee6f0f33,35ddb8c3,3978af58,746a3ccf) +,S(90fd402a,e8d505e9,96aec994,db7d29a5,6446471e,34dc7512,6a356ac,1a66a519,68c0ff7,bcdc36e0,ada31816,ec4f0e67,9a6dc658,46aaaa62,e1958ba5,bada3b6b) +,S(b380ecb,7d9bca8e,1e35b0dd,d412b128,4cbc77f,c66c5f5,eb390d9f,a9400704,fd2a2092,77d9b783,9df69a7,229d55cd,18fa71db,e1f5f8a7,d78f450c,846a01a4) +,S(40e2e041,aecbb6cf,6f866140,b6149257,f3d029ef,ccf2a752,d3ef7b0,32b83f0c,122710a5,3c83888f,54e26679,417f2329,e1eda641,8e525326,704744c6,bc2291f0) +,S(8e609fc4,3f4e30c9,3893a38e,9aeacceb,7d254eb9,f77b49c8,c99c20a8,aaa03583,947c4c6e,9a821504,7f259a86,b1d70378,837fb57b,e0d696d,66a3dc3,7ac1a3e8) +,S(b871c5b2,2bfe9fd1,6898d00,1af89a8f,8d9c9324,52fce0bb,2ecc0835,f435f5ce,e302e5a3,ecbd0ee9,9f87226b,6f038003,507fe8ee,60b64,cd656f26,8f1d3078) +,S(526daa7e,39e891a,bb524170,96fff4d5,c6f80f57,cce87f83,2ac07cd5,50841682,69f04499,4fb7130e,758fd397,5ad40f68,c477bc9c,cc5c5f43,c5f5a554,b3d210df) +,S(c15c244a,514e3057,ce67cc07,3fb66fa1,5c031f51,8add9ba2,edc12f94,861ad25a,db1021ac,ecc3c897,8de34780,bbc9a8fc,16449ddf,5cb05b90,1ba39598,72846c50) +,S(37e20b19,466a038d,b3b63873,50dd3dc5,d3494876,cdb7f344,3e234173,eac1d388,b80a24,546541e2,ecabcfa2,7db57aba,5ea5bb79,f69ecf25,2d68ef63,fc3b89f0) +,S(6d091f28,feae0142,b311cd81,f57958a5,6a0da5c9,7ff5eab,c598e4fb,564ea528,48bc97f0,4d7ea6c1,38189719,6c85dd22,6e9d9f7c,5a8ba74c,27c29063,fdd07906) +,S(3bdbd416,a76efb56,ed01664f,b819dbfe,d3e545cd,3edd48d3,5ca635e0,bb54fd71,a6954d72,3ed7253f,ef301621,91fbad8f,9a63a893,82b98d26,a6bf36f5,2ceb0639) +,S(cd4e36a9,f111b55f,8c05d41a,4bc33ef0,c4109540,d9871237,4018b2e4,7e9d61ce,478dfa16,52632e69,6ef95ec,452df807,abded9bc,264e6dda,df0c6215,454e3e57) +,S(f23cc4a,9c59c0e,3bf21413,170ac67e,24845771,2e77f1c6,272a9f11,2df24efd,e933bc72,99b6effd,5cf58fc0,72f7a466,dc71cdce,74a3d3da,9ed5e7dc,577fa4b2) +,S(d98c6585,8c97eb35,b6846840,cb6db623,d7a349,435d4989,31a695ad,ed3c33e0,443fea24,ffe8825d,eb6c953c,70627395,ba13781a,164f2eb2,a85b862d,e3114990) +,S(2269daa6,c055dae1,b6d2b9d1,6c74a9bd,65325ddc,a249085f,a946e66b,6c744225,159d01f9,a61f0456,b08f0fe6,a42efdcd,30e14ff3,bb47fdee,2352dc9b,f5bfb3dd) +,S(335044fd,8eea8792,8de3880a,546b01ad,eb4d75b4,23ae7ba4,87740c03,167c48d5,69e503f5,26266bbc,63b0f2bb,757b3be8,cfe1d9c,e63d8226,8187a309,ceda1cc1) +,S(ee7a263d,86f9a83e,54cee87b,7bcae75,a601da9b,637aba50,46bc5f9a,3ff6c512,9fdd3192,203268e9,2388ac1c,840e7635,22271483,161f8f60,42d82909,41373d56) +,S(529b33b3,36f1631b,6c7b6111,ef44a888,bf95f344,766a2d97,6c5e5d5a,53f44245,12856106,93da6f4a,2fabc1a0,3280249f,6f29f9ee,9ccd7000,4cf0a857,ea061099) +,S(f2b3346d,a6cee9f5,1a933718,2d655a88,6a251353,8ebd243d,d3e3cd65,abdf1849,d41df628,be7703fe,9e866526,2f6278d3,55aaefcb,324df2e1,f483b0f7,77b77da3) +,S(535e9dbc,f03d98c6,70d03d04,5d638c7d,1db7a12a,22f3837b,3f559b70,4582befa,2c233228,bad897c5,bd4fa98d,67f8384a,62ea4761,4f64e4e7,40bc1f65,9e358392) +,S(c131688b,70da6ac6,5ee3172d,dff34624,b019bf78,85033970,8253b4a0,b299a7f1,fef187b6,e0e748d9,69a11d82,e9f996f8,d6e1aff,8b84d20,7dd78519,dce5f3cc) +,S(75dc84d3,f7ab7985,10ceddf3,da6bf832,a984d00c,98726a64,5dc71b21,754d3ba9,f5d9edf3,5e110491,2cc5e4d2,82eeaa53,84f62deb,1dc2a183,af5b232a,e3841c50) +,S(591dc7bc,9136c38e,ae727310,25c5fd52,82c6dad7,6f98c648,78847ed4,f32a36c5,fccfa4c4,f81cd382,e003aabb,4cb6c5e8,8d4875b7,21d44233,95397268,d7a421a0) +,S(83a59c89,2a8392ba,e7548fad,b87acf7a,d2c78db6,4c588f0f,b14753ce,12712596,7d00ac1a,33b12065,d67c598,8822ff3c,46f090e3,15cf919b,e3e5030c,e7c5873b) +,S(e9b0dfa5,8c52b2f4,a9c1b8c3,76391eff,6608f968,ec45bfc7,6ca93e2c,ba6f6f83,6449b28d,5846de0d,27489124,feb3f3fb,5c1f0839,a7809be2,e5cb5def,2e0a7c8d) +,S(16cd2f9,67b090c3,d151c002,d3a3d25c,c76adf50,d55a6f81,b1b9a650,b72bc03b,c592601e,2fe77090,39ccc091,bd78458b,a23db74f,848ee06f,50ffe4c6,8ad63a7b) +,S(f347d3fd,1bcde363,69e3d9e2,44d6e5f5,d80b8dba,7b1866b6,f584a38a,3aff1cbe,1c435ab9,ae38a13,98dcfc6d,64125e8,c7349f81,1584fa97,66dc4d24,7e87977a) +,S(5b190d87,d644854c,90c49f11,34921545,f349edd2,b4e9926d,534374cf,da428b1b,8a4eacc3,63efd6bb,5c93ab25,65d2c157,9c1d3176,b2713ea8,56bc97be,fa5401f3) +,S(a7786cb2,d7314ce8,f21e9665,bccacad,c49e78f3,7772c3ab,105f67d6,1c30834f,4fc7acd4,18982e3f,2fb1f911,cb70bfc0,6c4ea71b,a05f6371,46e96bd4,a9441953) +,S(d3654f53,e9071a18,8c5faedd,c0ef3616,abf74d26,f073ddcf,545a01fb,2fbf33cb,a56f20c7,213c0394,5978502f,c4a716f3,77c7a3d9,26c3cde1,880f103b,432f4383) +,S(e1138a87,400acbda,69d8ac3,bb6db4cd,27d03176,ee88994,2039a93,7822399c,f29a8fbf,dd3f6d46,5c640de6,b6853e40,1803cd95,f5e012c,9ce967d5,13a162c1) +,S(d29eb63c,91c0f4e5,b3c49c6,9c9ca952,5714730e,76bb87e7,374ac995,86317708,4ad93702,4e9180a5,9d22ab4a,c856de6a,d9d38c9f,1cb3fdd9,d73aff61,fea5f1a1) +,S(a9d403ba,a6717fd7,6577da1,d8b8ecb3,d2124b30,d18df147,ca48b482,26ee49f8,1eedfe7a,8c5ee1ee,50937bca,d9591144,56f1e49e,db74133f,f45176b7,26d5323b) +,S(ff7b58e8,dbb6055a,eeac6bfd,112d89c9,8d8f3763,98e41e39,ca076bd0,9ef57528,4e4e39d1,ad7a51e7,d6cb57c,836c0685,8e39f1f5,bd41aee6,cf5d250a,fc381121) +,S(43c50a9d,f7839f61,e1b6db23,4e2f146e,1672ea1d,566f5613,1e7bafd1,bd362979,f20fda98,81541a8b,a83e908f,69e05218,1e215885,f60cfbd6,1ada74ea,83f449ae) +,S(f608a9b7,1c91298,75662ae1,6be6d043,5803a9d5,29d3be53,9843f227,174ac30c,5ef364fa,e919dd42,1bad3243,413bb565,d788d266,d7b508f2,83c486a,327ad5bf) +,S(c913e029,dd1ef043,f9bc48d0,c267657,3cc11722,5cdad56,8d013327,445a117e,97573f0b,9c31cbb3,7bdcf07c,13526a04,32a38f18,43e26d8b,ace85a50,19a83049) +,S(aae0c49d,b17e7bc1,66c0c58a,cca847f,61318bb1,3482f63c,ce7dc55c,82a7d728,41170bf3,f68c3dac,22051aae,658cdc0e,810396ff,9d5d9251,6a7e6377,5c6be0b8) +,S(f2805f1f,45a0b622,59b9b15e,3de4a05d,e306c8b5,ebc5ac96,d35aa388,ebc846c8,f5d72739,6ba37244,57725cdd,912fa38,b36e201c,26409dc9,9789d087,6b8d1267) +,S(6969e4e6,e150d12e,4a230e59,37d865a0,f7d2323a,781270d8,7b0a7a90,fa4f39,c71c33d6,d323ed0c,3e77ebe0,8595dc9f,e030a0db,aae16f88,8dab7187,5e14de3a) +,S(aec2bf0,7a0e257a,be4fbdb8,e872dfbe,2aa0643a,411943e3,e4cef039,8d988f3e,d8e9f557,e686c380,c84bc528,fff0a830,bcc3b6a2,724d9df6,ef21d545,c8c931d0) +,S(9c6ff99a,13dfc35c,a502890b,69d91dd5,198f561c,790bf322,6bb243bd,4926f710,2aef920c,84a4f5ad,9d88f541,1ff46839,2f7f4e63,3422b11e,9b683403,f7ef849d) +,S(fa43745b,37a5e238,df0246d6,7eede652,ade75aec,b5dd8aef,afb8e6e0,96d7f1c2,df9d5aa4,2a3c6540,3793c8f3,fef939ee,48aba7f8,59fe9ead,dc44e82d,a98689b1) +,S(694a3288,6c4e26c7,eb3b84d0,9e777f96,ce3b74e,58658741,27643dda,a78d46b9,a54d6c6d,7645e5,6e8909be,922cc5a,a700d932,cb1318b0,1446a9e1,8bdfe67a) +,S(65499597,5be06b28,b4c339a2,b126210d,930fe920,7cc72be4,3d4ad17a,c08f38a0,bdee23bb,467fdce3,2d2cd92c,e81e3f5b,d29fe8b0,8b35abe1,c684443f,72f7900c) +,S(3791c8f6,75bb14e4,b7d4f084,483aec44,ea38eb2,9b108137,400099b0,799f0bd,2dc8f74a,da5e5eb6,f3b96ddb,cbee5ee5,8b2a3f45,c31cb16d,15a4e918,eef7bc76) +,S(d5e41065,eaf890e9,e9046936,acf6a43,59795c7a,1939d8ed,42941a8c,6ef31364,191ec4c8,a559fd4e,7abbb6b8,f2e4c32c,bd2f30cb,d06ff6d,21f156cb,f65bbcad) +,S(16ce2280,fa0b404d,28a29acb,62058b99,e504e6f2,eaaa3ae8,b77ad650,2c970dec,3d4683f4,486addb9,e54bc252,74e590c,b6eaec5e,7f96e9b8,8174b81d,56efb09b) +,S(a6b0ab30,6cdfb1f3,90e5b447,816841b7,e08f997e,d7d47016,bf3b501,c6107d07,2a62842f,b67e2794,92ed337f,d72abc9b,94e96e4,a10f658d,9cb9a4b6,a80abf7a) +,S(d7ca6d38,760b320b,21cb779c,d709f376,52b9d08a,8ff6ad90,21e00628,56033583,d6c05f72,866d59b9,6b91b6cb,b1401619,5e2d1cfa,9982db04,6d672fff,849e7bb5) +,S(78ab0563,2d3f707e,738cb134,7121c73f,e162405d,61a0bef3,75f6cb45,f5609d33,fe1a390c,10c7cb4f,297a4b42,4baa5c50,350eba49,55fb74f2,1094ec5f,ee75a6b0) +,S(c053553a,5b9fe803,65fc5a9,60e48fd9,218e2128,28935879,bd1072c5,180d6f04,e02da774,214dab04,e11c45cf,57be2802,7d0d28dc,51cc08a4,7528869a,3e719192) +,S(bf85d713,e2a995c3,ef98d403,30fc1fb3,5faf8e95,81385b4e,b65d5ebd,23f02d03,a5d45947,58d7b0e1,a8542a6f,21ddd207,dcb68e96,88284bbd,6b940748,b3e59b18) +,S(fb73b6c9,2be578b8,fe2ee0d,eb0aeec0,13816905,9e55031d,69a4d0f1,1bd280a,72ce7893,9bf5a55f,d4430bd2,55bde818,e15bbc98,37e3dcf3,e31d22c5,9614cd16) +,S(56496e5a,ed338dc9,201b04f7,8f4b6c2c,d9928135,83360dfc,1e2f370c,1628aa79,81dbf48a,824fca70,12315d3f,a56d5150,92ffa54,d1300725,86c8a476,be8c2db1) +,S(d698e395,9e81f098,485edcc6,2f2a421a,aecc0a79,58c9f6df,7905c931,b7a2130c,5903debc,e61eaa39,dac01a8e,3e970a39,79408bbe,1d0ffba4,5ce78c9c,79563d27) +,S(84b32e40,86709450,b32ade00,d3404b34,7fad8d7b,9387d931,780764e4,c566ff80,4c80d078,56cc4296,2b7941e3,195c5350,9bb5b0e4,325c24,4aa3a581,bb1cfdc8) +,S(7129c799,2a3689b4,c1873a45,f1ed3327,6528e243,28f30cf0,5ac38a61,8db2ed6,362b4fe8,482125a5,d4d15456,79009aa8,44f86619,cf3fca68,ce38995a,660810e4) +,S(93164c87,fa48b6ea,6b6cac08,8c991c34,5f8cad7e,f68c5b98,78139d28,d180d824,a3ac0d5c,c91cf0f9,cb97771,d16396ab,bd183221,c8d36a87,2785e847,b5d9e26b) +,S(4f90e8e2,37c4937c,a384c7b1,f929f329,94744d5e,8b89ad94,808ed9b0,9f305a68,cde776e0,2b6b484b,83f417c,fceed07a,ce725e00,343c4e70,14748f08,992430b8) +,S(4d9603bc,9f40716a,e6913fae,253eccd3,4442f6a1,3c058ed6,a10f91b6,75f716a1,92b679fc,278ce355,97165827,aa6fb450,9c52a412,284aa493,c6654ee4,3924add6) +,S(8b6f651f,91c54143,12c94f3b,c1632e13,f90cd718,67f906a5,aed13c4c,4ab17203,88c159a4,b80f2556,bb4e2b78,c126c40d,9ded995,bac6ac13,bf83655,210c7066) +,S(6f58b852,cab98347,e86448f0,78d49916,1909e1eb,60556ee9,8cdc20bd,b25ec256,3a4c05f,233d9305,e6abd30d,da0cebea,1681dab2,ad805cd3,2fa7023c,98239885) +,S(6be7f6a8,4021411c,acb710da,3ffafa32,8bb6ca91,59a91008,6cb98071,100c44bd,bf64a6f9,d461dfb4,581c8d59,b5fc1191,86f339ff,320e968b,b5810145,4836bee9) +,S(b2fcd0b,b8ea9e66,f2cfdbe1,3ecff9aa,99661f0f,2ac1844a,b3983d2c,ae102d39,a046989,bb3b8fa3,eb2cbba,d3a7e810,27c38cb0,ea33ec74,1444e8ce,7182bb86) +,S(a1d6ed0e,ab559b29,edf7770b,50cc5913,3916826b,6d99ef12,91bf744a,79a6fd96,bb91657e,c9255ae,173bf93b,51848094,2f17df30,ac6b391,df2237b4,c04ab69b) +,S(28f6570d,ed7130d7,35366201,e9ab639d,440da5e7,e1c9701b,d08a811e,912a9575,39191f60,119c59b2,3e91a7c7,fbf4c2c,e2216e5e,955db62e,dece6adc,f2d2884a) +,S(14c8ced,dbb83de4,218b089d,101d7b6c,31cfce22,49637853,b9c804f,90271fa3,48052d2,a5d02e71,135cba3d,24c7894b,de1293d,44a2f84d,7a8fece4,ea9a41fc) +,S(eaff9f05,fec737d3,d2a28fa1,bc8450a7,a75f563b,9221bca9,eda2f8fa,e12d489b,d6d4419b,5c9873d,7d3349fa,520f463a,2ad9f348,1a111c3d,d3fb70a9,23b8c139) +,S(e8ee4c6e,b42a3712,85b52457,52e7fc3c,ce0757e0,96932a43,d92bed15,14b35e95,d86bd4c,27ef1831,f107ff4e,6246cb7c,ee55abfc,cbc5de2d,5f230a2b,6a3b748a) +,S(98c61909,8213b06,6b70759,1c88a51a,d5e90922,6778386,a0776e6a,ee41e7e4,eb3d2e2c,f98bb904,42e90e2d,38ce4c53,fd72da8,1a37fefb,fc241aef,f65d4c8c) +,S(d4f66b81,f5d62986,c57a0dbb,c38bcb5d,89319806,4e28e17d,946cf7f3,f946dd29,c1930f8d,eedf1a00,cb7c5579,d814b5b8,2a12298e,530bb32,867821fb,7b7a5fc2) +,S(14d73ce7,5f8919b,55d54369,69866f0d,a13dd4c2,ad447c4e,b9879060,1411087f,69b94622,b9cb0d3c,5d106df2,caf4208b,b71c48f2,629d467d,16ee06c6,93ededf8) +,S(57efc935,59c7a0c,6ac51105,8a50a8d5,5646ab40,8a711711,5bc34c20,23da3aec,fca9329a,60b855c1,74bfba0d,92ae5529,27f959f0,5332cc4b,26272c02,b5c5dfd1) +,S(91f13a86,63da80d,a90b9458,55a9f3e4,171213f5,3683873d,cb6372fd,95b3677f,7405e0d8,6734f110,c329a7ae,92055639,e0332ece,134156d0,3cab4efb,419a90ea) +,S(dcc84d0b,46145e25,a83dfd64,b40dc5c2,c3322716,d1337767,5f9d6aff,a1607592,e46a4cf4,8e4dfeac,8df1526,f53246a,51b95161,a7030adc,8bba8ba8,1d2d6c66) +,S(28ab06ac,d5a6f432,116011e,6bf3c6a0,df0bfa1f,df16adb0,54250174,3348676c,51272a1c,967f49da,e9d1d6b7,a4ffcfef,cc31f42b,e0da52d4,27e56b63,97b0cb9a) +,S(7c01b21,f8d1dfdf,d3f2adb4,5915c636,d9c2a92,320c2d00,beff0f45,21d8b240,b4a48fcc,99906d81,fc6f78fd,aaa96b3d,6e7ffd62,d36d1aed,f76fa25c,542c8b48) +,S(f94eeb78,30f8e95f,2a362423,9c0e8fb,a0d3279b,e0cb5f5b,428a99ac,d14d98f1,c96d5b64,69676b9c,a5dc91be,8bb4a93f,7157221d,9513cd23,5cfe3ca,43649527) +,S(ea4674e4,7788cda4,bde0dd8,5f5e32d3,9a6d6477,30e9045b,d406f5f8,11ec35ca,769bf79,a9b9122,3070032b,a18bd769,fb622a61,424e9a0f,e1a46230,a75a235a) +,S(da5a7419,7f8f8685,1317260,682bfe28,19b7b38d,376745d1,7283c250,1fb40112,a60b5eec,5871e18,1325ef5f,5d6373bc,b5a19f41,2107290c,eb663e3b,95c37a39) +,S(c1017fa5,52560fda,18c6820,ded7b76d,a75ebcec,23b8fb6c,22ff72f2,26e9d41d,e947b19d,af2647f9,167da3b8,dff05897,9b5dc1da,6782929b,1b078114,349fed39) +,S(be7c0e1,4e814476,78a15238,b5809a75,1b964658,19bf0b16,4b3e914b,29216a7f,a30ebe97,f64219a6,f0b072b1,5d648e81,880840b,8a36204e,4f1627a0,feb392e) +,S(6758eec1,a4d6c0fd,cc118405,62fff82c,59e0fff2,cf80414f,cb53b139,97007cea,4653bc66,20fcd852,422c8898,862631e8,a0149bba,d0b9cedc,b4fe3eaf,7cb316b3) +,S(9cbb51d3,f88f4d99,9d80cf05,9e8735b3,11014de,69acddae,70d850dc,405b6116,dfa2e748,cad75b52,800e0ed5,17efc4d2,47c6381,9190a3d6,e2510bb,25902360) +,S(63a5aae7,b170792f,17350229,eaa5ad18,65328bd5,3421cdea,3d6e1510,d8bf0bc3,1125afd0,f25d5f49,f7e6250a,ed3634c2,12a261d7,8ce58ea1,95afb883,52da1010) +,S(adf96249,3e5f0328,ebae11fb,243da21,4e036d24,1da62430,b0fe2c89,b2f10657,509834ba,fcd8ddb3,2d018b16,d17d4b5f,219a29de,8a03f7f7,84f34b57,9b1ea1e) +,S(a0d8f5b,7fb44a15,93583364,e04d7225,bfdfa549,c2b25f32,f00765d9,e34d472f,61eab66,f84c2687,949da99f,3d97fe3d,630b6c22,f9f7c48d,d539b122,ef998ab2) +,S(b98308ea,9596a2db,adcdbf81,56d8025e,7a3ee0d2,5b27c33e,f686690b,ae61fc1,cdb4e317,7566a4ce,b4cc582a,3cfd259,445bae6e,586786f5,1250cd05,27ddbd37) +,S(e1a64f1d,37e3d6cc,119eefe3,793ba303,cf3969c8,db4abf63,7f0232af,70b98134,588d7ad8,885dd2f5,ec4d2084,b3f581b5,ddbd3567,8f4ecfc2,f955ced4,1c3231da) +,S(fbd5dfed,e8543aa6,e72253a1,bd711911,318929ee,7af14eca,49c2276a,65fdaaed,317cef0a,432c3516,3c405d51,65b8c310,f234891a,dbd0d6f2,f76cfbf0,193b78bc) +,S(fac4b7f3,b0a39510,84f1a882,2f7b6f20,30b87c4d,c0178a2a,e3077ce6,84da6bc2,7029b920,9e9522fc,160a5c54,a628fdd4,386ce0d1,55f19fae,390b2995,bc867d75) +,S(ca8643de,834fcf50,802c0296,41b5fc7d,3c29fc51,5c75c53e,e64a8185,43ef7c2b,907a6c27,111e296e,2436fd4d,ad9d9fa,f8ecea31,cee714c3,b26fa964,afcf17f9) +,S(71873649,d700ea1,7ea26b19,efe4b48b,a4a73b22,bc54066b,1202c96c,f3315f1f,f6cd8447,4bb374b7,753fc614,de5cf429,51512748,2042215a,bd82c11d,87ded2fd) +,S(67e738ff,21c3c732,26e57482,677c63f0,175b768f,776cbe6f,15ac3c53,48c5e3d7,14e5140f,2343dd72,577a5064,47cf6093,ebd2854,5d1326bf,ac79350e,eaf2bdb2) +,S(514b3f31,f875253f,205339f6,434ee17f,6c5a5c42,662ce934,280f55f1,9a198893,4eb33993,a2fbec70,4cd1c538,ce7cde4d,a61c0fc2,dca9669f,e469807e,4ae9a090) +,S(426acfa6,eab03e75,6ab30a41,418a0392,ca53c216,f84b3586,f9858501,8bc2dab3,c3d63eab,21cc10c5,c0a06682,d0573bb6,d34944d1,749da74,acb59aad,f1083926) +,S(b946bb46,68c05737,ffdcbee,94597c85,b8ad4a72,c58205ca,d420e8f7,a2d7a09c,cc700ed4,12633826,567e63a5,e65bc603,969ea13a,49feeb2c,dc723bad,1e3401b9) +,S(e6a844b3,f6c8b45f,511d7d3c,ccd75df4,1d1e38f8,fb28adcd,80335b95,d98e33ac,7f24789,3939890c,74a3268e,e1f717ab,6c4aa109,cc9257e2,c0b176c2,ec58cce2) +,S(43e62bbf,d9e052e8,c1636b41,5524b98c,493e903f,2313dcd,117d140f,96458001,f481853d,a90d528,30999300,dcff31d,ebee23bb,49ecbcec,8e147799,a63b352d) +,S(c44ef40e,3427476d,42e23e1c,41ddb9bd,e555a844,9125aad9,e94f44b8,8047f817,bedd4313,e43ee593,f2818e14,776f4ae2,38f664b2,db84c9d2,498b9ea3,8e236fac) +,S(a1b35313,dcc11895,c096f93f,5f8e4997,7f58f2fa,afd9b7e8,d408bde0,53212385,bd7eb25a,bf0d50c3,7309f9cf,5093d817,135a9ec0,20262c55,bdc8e8a7,a3079f5) +,S(48a6f3f9,fd6201c9,a37f2f0c,735bd98e,1382229a,d1589c91,b6748a92,1b5e964e,1b545155,3d41a8a0,64862c81,fa9d5966,2c73e039,53a5dc91,9712c50c,5b4481b4) +,S(8e01f574,651db06e,8a19181d,c8eecf1b,75f050cd,c5b2354d,b06285d9,a4061e9f,9d156ea0,9800e7d5,b6c6e90a,2eecada,7d7ba964,ba1f0cae,256fbfb2,275e108b) +,S(4bc0f8db,9e6db576,3eb68b19,5a79f8e6,28e375f3,1694a58f,43da4dca,fa05345d,c6a70789,a1e6b164,bba380e8,126a4a69,6338053b,6a32d9d9,8d0f215c,43a5b555) +,S(966fd0cb,5f5edead,d6230a66,50b7dab8,f4c7ee8d,b00ce55f,32d54a23,ba97a768,9d644e43,bb4f9b65,f5819a1d,ee0a16b8,1e8929c,a9e544e1,6546cf79,811a994b) +,S(6ab519ad,49522ea6,592dc7c7,4438e337,20d50eb8,862467f8,2962c510,857b0d8a,c5ba3a34,2b7250a2,62b67ec3,554c21ee,e82653a0,378ee0da,8a809151,a3ae44d) +,S(f8b0b8e4,3e5060f5,39bd0a0c,d076e163,e55f18a4,25327856,d526d6ef,aa76c62f,743de052,a65853fa,58cf29c8,62839aa1,7d5c95ba,43673ad1,fe1ecf6f,d4d48ba4) +,S(c4509ef8,579d8ff0,ab585c0e,5223d5fa,967e9763,9d15b0e1,6587a125,3ed18bad,7b91f7e8,ee979a58,5a36d8d3,574b8ae7,81199dc0,86f11cf9,7fe58e4f,1db08362) +,S(9a00135a,6ff450f8,e2207c53,894c0e4c,4cef732,cfab43c3,aacb00fd,ab42379f,393ec748,3684c5b1,4760902a,28cabb90,b481596e,8b847d59,4dfb8ff8,1fa9975d) +,S(3d775bdf,173f8d7c,de90c17c,25d3dee2,a484d331,4e525e3e,aa4a405b,6f488601,7e6b08bc,a560f6a,5bf287f5,59d74e25,38a4025b,89972046,b3de98c7,b30e51d4) +,S(cebafd3e,a60118b4,513380a8,d10a29a,a95e5002,d703d7b8,f5d0e983,7b03b529,19477ab6,46f59f61,ff603594,e33ba046,5f6d8b1b,f55290c0,fd61534a,87b74b4e) +,S(ae8a3cac,1ff3e3e1,ef01ac16,2e49b237,7ecbc963,f58adde1,58cb1987,cfa731b2,5a4b0675,2052b749,733f6af9,e8dc773a,ee26fd2b,114a7ac2,baca1e9e,51531efe) +,S(d74d38bb,8bd47123,5c118ede,e477ac4d,fd39b635,d0fbeb28,30843753,ade3b38e,f3e505b6,f17a2839,7a985084,31ba6de2,1ec0a0fd,3936dc32,5d66bb37,7cb54451) +,S(f4287675,7780785c,d14dc1be,fe075d1d,4d4f0b33,b0ce9db2,49595b14,f6beb2a8,a3df2231,eefc62dd,c658bf6d,a361ad6f,950f34d5,3ff25536,4eb1e1d8,60514b38) +,S(e91d576b,da19ad62,76bcaaa8,69cb2099,e6277688,3ca1d454,50dc9401,46378e94,b57e2038,c8da2cb9,9ac313db,83265d8c,20e7918,37e75db8,7acca971,3840779c) +,S(269944e8,7d77e176,3791b53d,af2aaa43,e035e1dd,f3c7daec,7e830cfe,38c66ea2,cb011764,34bdc7fb,528ca43,9b323c9,56764145,7b7eeea7,39ace76c,193707f6) +,S(ed41e68a,8f0b3681,1aa61c68,57bb1765,fb099317,2ff6ea5e,e94e01fb,644a3d1,f2cc907b,880cbe04,26ba1e44,83d95800,71c918e0,8cc085dc,1dd0deb8,c508231c) +,S(6947664a,96cfcba5,e2e36e4f,53a33d69,538192f1,3322113a,b0b79642,dfec0de,6481d1bc,5b65b6fb,a91b76c4,d6ade333,25610195,decf5dc7,7f95dc2f,a38fb6cd) +,S(aa3e187c,e22b63df,6a80a42b,ba9265b0,4379012c,70e8ef66,8ea85c57,1e27fb03,a638dd6b,98109fd1,96ffcab7,3010543,e8732f48,e5cdb29c,38fa91ff,8d011be) +,S(5de4e1,a4bef94d,b4a9fbab,6543fd6e,bfd5ea37,9124e1c5,eff9be18,f84a944b,21c4a282,693be294,b699513,f7744761,58f8aed1,a7ec7442,9679ba9e,7957e2d6) +,S(6533dcc7,2c87b477,81c96c79,3af0af22,fdd18fee,a33a30a0,9646c2b4,287a7ce5,7f03e5f2,3d82f9bb,ce9589fc,23442174,482748cf,a3aeccd3,f8c37058,837ccc51) +,S(139e5f3c,129e584a,bda008ab,85343531,c5109f23,a70b9871,a5ebb00a,64fdf354,497b7e57,41fb8eaf,a53182ee,98352b62,6bf011e4,826ac9de,6190a2f7,773f0a98) +,S(493fe9cc,f7e1e950,83cea991,8d8f2561,3ce57b81,81915f0c,7c779aee,8161f7c3,e69763fd,62fce1d0,454aff6a,6a3bb448,639ab615,8bcc2f40,88cbe4c1,67020cd5) +,S(ed675fdb,d8dd70b8,641ac2fb,4903ca77,900e3c15,766ec8a7,446e6b36,52a064a9,a61bb379,85cef5b4,6e0669b4,b0188ae,23ccffb2,5ce777fd,1f26f313,68416de9) +,S(173670a8,9a769e3a,797c14e3,15393d52,b6d48444,3861cb83,136b0ca9,9a260a4d,4dd43921,c1ba4d2e,95ea1b28,e4908410,d140b3f7,7dd82bc6,d683da27,c7bd4904) +,S(d5a5e3a0,8f87e154,6f11e05a,c106e80,a1da933d,2cca528c,df9e1f09,635d1610,7c6c55e0,daf3c092,8d0a9c6f,2c1ffb0d,aa20df74,20a35167,2552914e,5d175352) +,S(54f5e9a0,4ab321c,692f2e2b,94d6697d,a0a99932,74ee4ebe,4175a338,daf6fa2a,58cf13d1,75fa6e47,34aeb761,4f828dda,58a7d9ca,855ff42b,5cbd66d8,89f2de21) +,S(d6682898,154de995,62e5544a,442622b2,fd9a632d,94445d4c,9e8725bc,7febe6da,98091e3b,9ba3b857,50e02c50,a7971aa3,b2d5045,f760c1eb,d1371dc6,3190f206) +,S(253019b9,2af2c4c4,8d9f6e1a,82decd36,610becff,18c908ca,fef49bf6,cdc2da08,617d335a,d9509d74,e5eebdce,810872e2,3ffbdd3b,da53aa5a,495b86ba,397c680a) +,S(56f64ca,461bebde,560d2bcf,ac08f292,ced72574,50e44f16,bab67cd5,104da6cb,5b2085cf,dc278328,a992bca8,f2ee8142,757cb553,b903a3ee,bd83bf3d,593aee44) +,S(f39c9571,1e153a9a,f0e5c192,87e3ee38,5a31a1e9,bef312f6,4dded245,8f553420,4cc94ac1,1c206b9f,7879df90,8498c132,e742ef62,48bdfa97,4b882930,e3b0b1cc) +,S(437eaa8,cbdf873c,32d3dad,95c5aae5,b2f3034a,5de0c536,8c8ddd62,c13128b5,27d8ea0e,b00310bb,59424599,3d60da59,2f8d1b2d,df0c1fcc,721e3080,993c59c6) +,S(ade1a589,3f5d6798,4490ae62,11c57534,3f13e7a6,14ef71f,a79eb4b,a880e9b2,bd49c17c,537e6a3b,ac7404d8,c3c1b429,e801882b,7f241304,9022e262,3791c715) +,S(936275d5,c3091a5a,b9f57d97,7a4e1b6c,a87ef978,c7ad198f,d16e2d93,3ac1224e,6852690a,d8bd84c5,eab75d96,c6e224d0,ed598851,b17b857e,5aa01207,df6b9f32) +,S(29e55fd,3e8fd5cd,e046db20,5c80b9d3,e294971d,76b5e8c,c33fb5a7,6b9b786e,769e57a,7eb934b9,4578312f,720ce44,2bbf3e2a,d61a6f57,af6cde49,8c010a0d) +,S(df8362a7,350185ff,198b5275,45e16f78,3ae37804,7647c584,168b159b,809051ef,afcb3446,fbd4a3bd,e826b604,84b16c3b,735ece80,ee48da26,3a6cae0b,62af6bab) +,S(5f443123,9a35fe0,f9566037,96cc619d,b9a01e83,96cf433c,25415ece,58a427e,385c2812,fc0aabc5,29272b60,56aa9c17,37d81c72,48fafc90,6fd7d4c2,b0901ac0) +,S(c19c4215,53c6037c,525b77a3,1693fc4c,8c5323ff,5d3dd63f,4b7e3448,15dd2de5,9f76ea8a,879177e1,27116189,6d9e6b20,a19d2255,92c99822,159c8ec1,a93900a4) +,S(8abf3a1d,d1e02332,ead62fdb,36394246,14d19d92,a82113f1,d62a1423,af2d45ac,325a967f,dcf5ec3f,75e7a984,ecc2d9f2,defc2941,6dd507ec,7de1b598,a7e36dde) +,S(c8bfdf90,b93161e6,c4d4a58f,a71ea84a,57c1dd76,c0607b94,33fa3cdd,f759ae7a,23dc38a3,d172fb63,ed47efd3,c3e5aa3c,fd7990cf,1535ce5,b51944f3,270b20f9) +,S(976666c,35c55997,a759e7ab,85f90d7a,a26ccc40,5b77b8b4,43c7e86e,2d2c78d,6d342c3e,44facf25,bf2db2e4,e20cceef,92c52cfe,b4370f89,60551614,381ed0ff) +,S(e7790ba7,7737e4e1,c7bb8e8a,5bd89c3a,1fd65b6c,feb2273a,1c12a8cd,f963252b,2635e20,1534b58f,70e754ea,db28998d,f7138ff2,a9e92e1a,810259dc,ffbdba42) +,S(42cb817f,6bfcec83,f60e3ecd,5b986ac3,b471cec9,975f3efe,37577d81,4576fb0d,ed35e128,b2f9bd90,f2162050,a5737909,144a8596,5075fcce,2708a4de,c45cf49a) +,S(a0886870,1a239333,ffc60397,ae11f145,31902428,a4fd58f0,2450e0f,412f3cbb,c8486f37,1ad6e034,8e51995,b4887ebb,fc6002c9,9cc00ad6,d8a81f99,1883af52) +,S(a40cca41,9f101b8b,40fd8e8,b364a52e,e6a9642c,22661aab,3486f25,732c4bb3,f421b69,3ec096f0,2d1e611d,f0701cc3,b0655b9b,95009285,babb150a,9445a910) +,S(90aef978,bbb0472c,5a75b70b,c9f5755e,c532940f,141a350f,efe604a4,35beb721,f9f05c70,737cf6e4,ca88cde9,2e478ea5,93f58510,9479d187,a5f87e11,e14bbf0d) +,S(ffc23a81,a0f61f39,600292f6,8db9acb6,d73ae433,bb827f1a,7bc6997,ac3407c3,b76a0612,bce5e139,277c7463,d47cce0,4f313b37,a0746803,6865f284,574d4b66) +,S(d3ca7b94,40bdf990,4262bc16,298425a6,742c852e,df99ded,2ab0ff50,20a112a5,9daecbac,ca7e825c,4f44281f,9813ce2c,5ef191b7,341fa2cb,1f9780ff,de4d637a) +,S(2a53a2bb,720ab31c,2a6b7589,ce0e1ac7,469b21ac,d55eeb41,b23b3cca,51bb9f06,11aff933,ffde9646,7a4d0f52,220d06ec,27f7810d,ba44b256,c21a57e3,d451f84e) +,S(487e5356,80c40287,a6fd2f77,bb8f5cbf,22b2fc71,7fb7487d,5a08474,ada1ac96,53bd7fd5,46070d63,77b65326,d5130445,29c9625,520c3a73,1e990d0d,5aa849c8) +,S(3e5a5fcf,291da0c1,fc332cfd,62f4b629,cf23c0b4,8209fa29,63de5b99,667b3e16,86987f2c,43389a1f,4b028df,773bb130,8b33d7ef,7f55dc97,b060ded0,fab86825) +,S(4f90afc5,15a847c2,2c42493d,22dd5704,601840fb,57086b8e,d5f7d779,e3e256f,46e31958,ac2e6892,335f6b08,9ac0d3c2,4ef93994,2b585e33,226ded0f,aab831be) +,S(be07392b,40be3ea7,a6a73807,121be982,c2ff4b38,a4585a17,82c585c1,e23601fc,3a158457,657c9e8e,7bd775b8,1dbe2109,43172771,e66ec38d,a57a8216,f1f258db) +,S(86c274e5,2140375f,222f9e6d,47c24e06,ecc2f741,51b5a603,e0563412,fa1108ed,4a02fab9,4065d590,32eb90b6,4c98987d,2703f276,f92c03a2,aa009692,40a96ef8) +,S(4fd3a6b,e7923898,127b3056,1dac13fe,287277aa,21127626,2678e04f,3573cf97,6498a1a1,63cfecb6,c6cf4b4b,43bc7e96,f07ebea2,3b4380d2,38c0342d,f11173e4) +,S(cfa435ca,5423bdd7,8aafe78d,1fccfd07,cd2a5f86,ba81918c,b68c7695,dd117c94,bf4c891c,2dff79e,35b77854,66845389,c399b53b,4a9f4cef,d7d68357,10ce1fe8) +,S(aa5acb1b,79533cc5,9b29e927,77469afd,414119e6,1f3c90c1,cdf93e2c,3e1d446c,b0df29b7,8713c001,fb6d3854,e183767e,8b11bf10,9c75dbc2,6bb408f4,22a498ab) +,S(1b93c2ec,c21bf558,ddbfa1c4,41bca52f,435c09f5,4d06d175,6353e0a1,545c3d15,56c455ff,718190e6,5ace8a5f,d5c6d263,f72e67b1,a20dcc4a,eb53fb4a,33195ed2) +,S(1744cbf0,2566d20b,f639438b,55f72b0d,c8480092,246410ac,d8551498,2fb91760,7e77a7a2,32b0b5c5,9d1d5da5,7a7d2570,68dc0f8,4bda1f6c,683f5229,df4c66f5) +,S(a0be98a5,ed448c02,8c2f8ffc,607b316,1b9cb9a7,a2291bed,d24a8407,ff02582b,e7cc2c6a,2393525,b4d44462,cf6ac8f,76b86981,ddd369a2,274c1971,11da6ea) +,S(e0e593f5,dab5f7a9,562b2591,d8d75ea3,8b2f2b19,cdc8fe71,14891006,7b845882,9088c762,15e35db5,b3bc2614,1a42ce2c,b5464dc6,49f469c7,e785f5c2,cad67334) +,S(7824d895,a4982eab,d6f1b928,de7b0d65,ffe5796c,5e492b40,8b9fc879,c29290f5,ae175c68,8e428528,38a2d8bb,fc232c60,d6bcf117,57cdad44,8a4af01a,bcc7ee88) +,S(49d2e57e,e0b611dc,214e4a2c,d019ae2d,2aa51393,e976cb5c,4211cf10,f9d96e66,ffa0c4ca,88011f72,779b7919,829bb9fb,11c81e4f,a78154d2,5cfa3cb2,bd5b770a) +,S(da605f6b,8f701a85,86012e8f,83898aea,eeb3de32,e9c7bee8,be2139cf,c75ead00,5ba0c12c,e98a1c1a,89f0ca5e,a93f50fa,5a24307c,6751f633,d699e5ce,9411d246) +,S(aeeaabeb,cde94e6d,5a1de2bd,1d9c380a,9307be3c,1c32e785,652ffd9c,bac16ff2,30094755,8510ecde,500a52b,f107093f,b62e491a,c2596460,6641abaf,d50bf840) +,S(62f1892b,35f3fe64,b1ad1e1f,4305f9e8,66ca0a0b,e5cb778c,b0e1feb1,a10c40b7,1a44205e,e600bf4a,2e287f09,c5bedbf,f1f89052,2d14a883,8e1813a7,3f5780d) +,S(c2091ec5,46772d69,28ebe9f5,50a68083,3a567b33,dae25e94,4ac4d589,96979382,599a765b,d2e89d31,735fa722,a1fe1946,eb610c69,2d5a82b2,3828502d,cad4b31e) +,S(bfd7c15b,19519235,700e1b23,79fe7c22,e50a2455,5f83dba5,97d00fdf,1b242367,ac6de7de,545ec735,ea127213,fafd287,f4cddac4,8d6fe694,372bd46,bc66b17b) +,S(d4d4e784,3cabfdf7,903d8507,3831da81,9581629f,74f3cfd1,16b5f635,132ddc7f,1e49611d,582cbacb,fce65a28,44755cb1,d1cd6d4e,2b8f082d,219742d4,61758a6) +,S(1e575009,c378b34d,f3b434a4,95dd8c31,4945b4f8,df617d02,cddc11c8,8f908fdc,5ce37fa2,810c95a1,2697458c,b8f209cc,10bf2123,3ffa8565,5bd8587f,cf6cdb7) +,S(b5a66a2e,ac237eb8,a1f5e690,ffdf65e5,c9268c6d,37104ee1,108f95c3,b9408fd0,99005ac0,aaa4f6ea,60842ba8,68668c6f,f8cc3280,307630de,3c43ef28,cbf72798) +,S(1da39d35,2599593c,66c90b06,3baeaf8d,66bc3a30,21e3f6e6,cfc3ee6,7f26fe0d,9272a05e,b6b0151b,5470d076,c01c3000,f7e58aa7,8fc7fe48,9f285b85,c941311f) +,S(7f3b10b6,b10000a7,652862d7,21f428fe,4e900c5a,f3844500,2b374434,b5a971b2,b94a2fe0,7907ee33,113bd4c9,256fa08,8c4a4f74,df3c3a9e,1f5d205c,a2ecd385) +,S(426107c6,61850f9b,f6beb61a,e200c2da,e5dc368a,3f5d18cb,baf84cbd,7a4eb2e0,e1fa7c78,a9e6ed0f,8d713488,bd3afea4,857cece,8e8e54f5,40f8c70c,67e511af) +,S(555e2656,708fc4c4,312093c2,1489cfa9,d6c94099,680f53e2,fa374a43,45be9697,f5efb7,1e3bb76a,22566e06,c674ba11,a7822422,c6f44cb0,2f2e2be,284db6e7) +,S(7170b17b,5736e07c,262a927e,725b709d,3360625,4642a8b3,af8fdb12,917dd290,ef437ea3,f8998813,b5ad86e6,9a77ce0b,98b2c6a6,b6df5608,627ae735,30973b1) +,S(1ca8ab3e,66fefd13,49e329d0,72a44f1,eb4de646,c8930172,aaaec311,5a5c2180,6fc641c9,2a87d776,81dda2a0,f4984ed2,c70103a1,5531b274,fd20efa6,3b0a3c49) +,S(8352546a,f6d42e82,bf150c1e,41c1a72b,85f057d3,487b4797,7d5e4f8d,c05366b8,76be5ab2,7ca25b12,a888d7e7,21c2b1c9,ac92b0e6,ea0c484b,1383a835,86c5fdb1) +,S(2f112f7b,1730b9d5,63f988ea,765c48ef,353123a1,4d92e44c,3e988459,9c904cd7,eb348e97,f6487d5a,32f70b16,d2ad1740,27d7a8bd,41a031bb,743a6825,2e34a44f) +,S(e84023c,164dc6c7,1d72494a,d410a5e4,2eb6fd09,16a70f1d,5192508f,3ea5648a,634f3585,29be0328,89b2f510,622816bd,225aa031,ab145b8a,48a6fc80,1ef4462d) +,S(951c4d17,45daf527,b803929,114d57f4,4da40342,31c669af,d6e40127,8e28fc6b,f9083b11,a8b30fbb,2c696f60,8ae82627,b9592ef1,c72fc921,bb2ae4ad,5a27f0a7) +,S(adaa9457,f60b9f3e,e0a5548c,51f945b9,78845841,51ae87fd,689b892f,8ccb19f4,834657f9,2145fefb,8df9b047,55674997,f899b951,40ce5830,2e468588,1761caa6) +,S(649296b3,9800a3b,516ef3d8,52d7fba4,597f3e35,1d303397,7495fdee,619e6ef7,44ce9c90,10215167,fdc5f078,e2edfebc,5c8b441d,d88cf853,5c78533e,d61df105) +,S(2c1d7e97,908575bf,38afe2ba,7875f1d6,9f1e9db6,b11f92ce,4bc94d3f,6006266f,9eb250bc,30abd08,bbbb4e4b,bc09cb03,8c6c8ec1,fd1a6ff5,ba23726,da2cf7f) +,S(b130ff8b,ed4ebc32,78293b10,52fa197,b44adaa7,d1bbd74f,f6d56f9,744647ec,4a0a45e9,b785c7f6,76fd0a95,66e4228,136f60b,dcc1806,212590ff,eea5eb33) +,S(4f2a5997,62ecb2d9,31ae9c74,ccd71cc,29bf684a,d68f0117,32a0cd50,cb0e6231,debf8db4,5cfc7083,fa700dde,7309edc0,fc44216,cf7bc237,377c0bf5,7ccf17de) +,S(97f9e9a1,7fbe6e25,e41419a1,8a5a24da,a178c0b,a99e30d1,cab0d2de,7a23c0b,1ab1226b,cceb480,fb4fdc8,70fb5386,6cb622bb,e71d3c0a,4ddda232,57559128) +,S(e17f3fe5,e9f5d17e,40182067,3b710940,bfd486f1,ad3ef4c,bb93b47d,9d9d8cb,f1126a52,615d3a8a,6b360b26,305124af,44ad7d62,e03ed96b,59c2903b,b5272f58) +,S(1a39f846,7d638182,900c3e94,538a0fe3,3ae66853,aac36688,7a5a8bb6,7b2fa2de,ae7c1399,5a625a4e,42b4dc01,9d7c7501,18492f3f,bb4567bf,28ddef5b,82903aa5) +,S(8a5ddc61,27f6fa44,90a93e52,f4faffb8,baa60581,5142be68,cd18692e,b42f5320,5eb62325,853dddf1,a42559eb,bd5dfcc0,328e69a5,fc787389,74c80d1a,896b0d8e) +,S(117dbfb5,74b7d6fc,d47dc17d,56f5b5da,b864906f,f08d190f,7afe1f9c,fe38c299,4acd2151,30b7144e,437bc923,302640a8,c504712f,6b903b26,bd5db8dd,5d90196b) +,S(b0c31228,431c7eb5,7310706d,950a2a60,eec84ec7,418199f3,f2985a39,8a70a537,a7de9b34,792876ff,e98c3237,260d8237,85e47c,438fe419,a1048b00,b064ff78) +,S(7c210cb9,f493275a,e17e6d5b,517606be,736cbc86,5a5897e0,8d1d1f03,f243946f,17b07523,a8bd185c,ea4a92d8,7af1f1dc,920a7fac,30faedb1,c38e3529,1759c63a) +,S(172e5167,578bed44,6397b519,2b0eca17,177b14b2,f4570aa1,38771610,6ed6e650,9c15752e,4776b805,d63de803,83c73ad3,9d3ba817,c1f88cee,1737cd85,33830ba7) +,S(161afc40,df25fda1,3637317,3dad8046,c95a6ef3,aa9c19ca,47e9ce2a,20030686,5e6fd083,c1265f76,b4b9c819,3a45e0e8,9926f160,b6257759,ab90d6f0,126089ce) +,S(b991f2a8,e18aed33,4d769cf8,b6e39144,2d194e90,ee1518d9,459d3ec3,8a16a85f,1d2ba9a6,b89f71c8,ea169d3e,923d2c1,7e6e590e,21b28e8b,1a0d0cd6,1bcab7b0) +,S(dae0689f,5a6cee77,f796f488,1fb3647c,7d623348,7d5ab502,6f1ca30d,44ca8afc,ee67b670,f730bae2,a15e6964,33be5b95,43ccc1b0,314cdfa8,c6cc8873,c39c329c) +,S(47a58ccd,75f89c15,46a17ba1,4629fb5b,d72805a4,16a12e61,aeafd8ec,8a7e4e41,c15e7fed,1bbb810e,b4be60bb,61fc1f0a,a4bc43b9,73d94767,9b954f3c,29fdd889) +,S(f7ae2fd0,2e3b6ee3,30c0697c,94ef65b6,d7582f69,5c509698,cef09b44,6b040e3c,ade9f8aa,c527139b,c54d8e6d,ddd41ac9,5eb49565,79934ea3,6a9dd8ad,d419ca03) +,S(155f9ea8,9be2ae20,8d7e9c21,4c244a58,ae61cf24,5d5f8dc8,b6c448d9,7c12989d,1204f5f3,840cd19a,fda04abe,6cbf4490,cf5ea60f,4cd17680,8c1ce9d3,65b009ff) +,S(a83cc9c3,933b5f14,fa5348a0,e0d3ee39,e35057b9,13c5a51,89a61663,1e9d74f6,40aa66d7,fad68476,1e2a9c78,e1fbe478,52b91d11,a283e1db,e30d4baf,f072a74a) +,S(ca4951cf,c07b5c23,298a20e0,fa44b554,d7acefbd,bf2a6cce,11fc3ea5,67b5f5df,186a8bd7,6700cafa,c79791a6,b28c799a,35aac545,78586050,b8012c4f,9f4afc2) +,S(cf92dde6,1bad101f,5e71f2a0,dbc2438d,d6760ba5,b84791a9,ae0ce712,9eb6787c,a7d351b7,f3e31e6b,cbcc1f05,329458e2,6c9d8a9d,1137d595,28f53e23,5c3bcbd8) +,S(b1ab0b3e,cfd8283a,3b79df9b,e83e8b37,b06154a9,6e2a687d,8f51985,129c1179,cdb7f2f3,4bab534a,41f4cd97,b812900c,99e97395,3837f058,12d5d0d6,e9506bbf) +,S(a1743329,9cd4c9e8,4fb99295,f3febad9,197296a2,98b30354,24e9524a,e1789ce,40994ef4,4cf53577,6f078088,adcfa6d7,5bee11a4,4f2f3fc4,4282f5d7,f77e1afe) +,S(241b486,4efcac7c,3c7b946a,61a55317,38b31846,607f1e0b,d0a1a2b,d9c0573b,5cce8848,eec61cd3,325f3ba8,fbca403c,2f980159,bad3997c,832f5c98,1fa0d574) +,S(81f88209,64997984,699559ad,f799ab0b,e3efd354,d258137e,d753e3e4,de91b387,8f9fedb8,5bfd7061,1b9e5caa,5f3cc8da,43bda599,afa29967,a32c71e6,aa26d15c) +,S(49d64231,bd2c2145,200793d6,4a2ec254,c22da96b,655706fe,8fbf5d49,464e5a5b,faec8eda,b0d72cad,81df8121,671c6dd9,bf986440,3f1a702b,548d4333,c751e825) +,S(74c14c32,4fad3a41,1c7e1f15,9b740980,6daea24d,9476e938,7e77db6d,66e0ae4,af795203,1fbee5cb,f031a2cb,946e6b65,3ee0165d,abdb89fd,5aa73880,e0641a41) +,S(88bc209c,7342d94c,be3f4215,81383c6c,930f9c19,d09d91b2,a984b6d7,12a1e7c3,acb7d745,76dd8723,89a88866,e287610d,b817ebe6,1581aa23,46ac994c,4c5b3e08) +,S(486c8c68,c81ca88c,df7b93c8,5a1525f4,9bee242,676aae77,c1bd85ce,2a6eb3f8,e0fec94b,35fa97c,d5e64870,6f5e6849,d6249004,fb33e34e,c1add26f,4fe52d54) +,S(4a1efa11,6c588e23,7b5e30fb,5d0ddf37,ba39043d,6e5faf14,e28ceb90,4a681a3,bb196737,3c907165,a8937dd3,1bce476f,65f2acc1,41bd8d53,8fcfbf1a,997b64f4) +,S(d7745c06,c69609ed,db17f30,8efe7bb4,2632e85b,7f7f792f,8da44294,78eb28d2,7575a75,4d1b2bd5,5fc46e11,b1addb1a,5371f007,f702a97c,ad13f082,39b96a73) +,S(bd752f2e,a3db27c6,a6a08ced,df74a87c,dc333d50,fd9995f4,9ca7afa4,2be68def,378f8aaf,67478d20,ba4725ed,26d50c62,ef5c576d,da9c24d7,91dec38b,a5e9491a) +,S(ef588333,15a3c7eb,c6602bff,ace00d5c,55eb304c,7f3301f9,4be457b0,1f224d21,56eb3aab,6253dfbe,3d9a95f7,e843751d,eb52e054,cb5a523f,f46a0c12,b517abd) +,S(2c1de374,7355825d,a09beea4,f42df241,6b495ce,7edf1f1f,c1dc6043,5253727a,98593660,9082f5d8,8f9986bd,f77672a8,5ff92cd0,28d2c588,73a3b1d3,87a150c2) +,S(49f8d71b,23e60140,f50c9001,6f39b2e8,b78e2a22,a88f2535,324ff50f,280daf99,f66bb665,4807e7dc,330ec339,3f6fde20,308111c8,1fe42546,22b93a86,b58b04ec) +,S(365c9f85,754b61ca,2b2a30f9,954f3a52,d18fdf78,db593ceb,6df617ab,189f37be,c43fefe6,aca56bcb,ffa6aced,60a32794,7681b601,22369a3a,f1405a41,5132825e) +,S(1cf2cfe9,e89668ed,c1a446c4,da311cf2,7e2cb53e,1984a310,8e24e8bf,21f1b5af,71e56dac,43c53094,7b78f104,1a685f23,aebc7b12,e2caf803,6731ef5a,20c966b7) +,S(f3303479,62660226,f391c26f,a7e87796,219694f8,e01cbd52,25dce636,b48ca3ec,7dea0bf4,c110e945,dbb59ab8,74f83a42,afa585c8,56a93002,6f48f8fa,62762827) +,S(b689244c,4bc16c88,398664f9,2297ea0,8756a969,1ae7adf0,587c3253,e4b27154,9b488748,1357368c,c97f89a9,b4a75a0,bd7483ae,5c700364,c27d19a8,e450c856) +,S(bf34fcd2,d6b4371c,fef2f874,5e4be021,a78b4302,240d4517,f3eb1140,638cbe41,ce6888d2,7e326eae,8e772914,e1b43bc0,1ef6a238,27f67546,5464e195,5f97ac02) +,S(c2097a6d,231bc796,ce85a594,44c00250,d51ffe63,c45b9cd1,10ed4821,118d74fe,58b06413,fc4ac173,e1e3a85a,ca674885,d1f92b3e,5b99f72b,1350b6a0,bfe4ac87) +,S(874a6222,3d8804f3,a11b1de,3c647aea,e3e81798,40db2618,4d46a330,417afa81,4132a5f6,7986e622,976b181d,5c98f356,b31668e0,ef70f8f,6b13a0ed,af80b429) +,S(ac7c6e8a,1a05d592,8142227a,b0c3ed46,1f28463c,ccaa3b85,b9784e0a,f5bc605c,1a59a195,581e3397,eba60a0a,963f5c71,c107a9db,68794da4,a08b14b3,118a2186) +,S(3f13e2d8,d825a3f6,8875c01,a1715a5f,44bc12b8,2f254a65,575b163a,3333342c,baff6882,fb2c2611,ffef76a6,8b5e2293,6a2e6ecf,d7ba6724,3393fa1c,5825e3b7) +,S(1ebeb354,515e7f39,dc3e2631,51d0630d,aa7e400f,4c9f7cec,4d5f95ec,bfa8fe2d,a2e35cef,c2cdcf,384a2473,c185f3a4,c70724b9,84c72dac,a6ca11f7,ae5c85cf) +,S(c2dcdb65,b211e765,e6c59218,d12b45d8,b47d8f9c,e22b99a0,d2d19a1d,de02b2ab,e0aa5b9c,a960117a,7289326e,9259f886,8722e032,c96b5237,b146f50e,24f3be50) +,S(495d69f7,e2a9d144,8e2ed8a9,c038f6c6,7f360b8,270c9b85,841e8791,64bc0d45,5fb3fe2a,1dabce7b,83b4465d,74fac6f7,c48584be,134283e7,bdf59e0,957088d2) +,S(ceac4569,2139e4f9,701be43d,8da3f515,270a9477,bad5969d,2037ac87,3453bab2,bd1fd9d8,15f4e872,b602f2bd,9604b6b2,f385ea40,d5520b3b,ca32c160,44908070) +,S(7ed1d0b9,3196b8c0,1cd284cb,c0a206af,4e6dba1a,d6cd406,82f55897,9407e0d,e95a3ac9,6ba60be6,22f4ee73,2d75a9c5,11018ec0,d840ce0a,f1bca18a,1d2801c5) +,S(72fb366,4f42cec8,940fd436,5ba7cc97,ac5fe4b2,131250fb,a24b7178,a1040b04,c182b1a,93a211f5,f5de5c9b,4b52ce90,63d551dc,a21ee9bc,dbba2653,c47dce41) +,S(dd06cd8c,9ca91e45,d6720043,d3e6d857,4690192d,59154309,2160f04,6008beea,cdc17327,6eebea3b,f9fa8a7e,e83ebd81,4189705b,900b3ce2,72b85dc6,c41e7ecd) +,S(80f6129,e90a7f0f,1e650439,8bfedb10,3c708c43,2e2c743,da8a9a99,3978cd13,74d97812,145feff4,a3ef594f,85b644a6,d95a3082,3828c00f,e7226d4f,39deb82a) +,S(56af34da,f56b508a,eee970af,bafb9dd2,b48f83c,4c051b24,f5bc27e7,105995b6,d41dfe52,9e788e19,89105a4c,c219dcd3,decca65a,dcc5f34d,8a3ab0de,d1ae68bf) +,S(820225ba,795565b4,c45e29c,4689d91c,148cf693,a1a1c1f6,ca33c44e,4e3f91ee,3622ae5b,c89b9c2e,66bf5a3,17826928,11a0f4f1,4b387334,b24028be,ba4b7db4) +,S(7925fdbf,cfcc202a,895a1b7c,a8c7f09f,ad388db1,5652b703,3bf232be,a2ea57d2,46f7ef01,c9cb7dc9,1559cf5e,c6d3f5f2,1ebcc21c,a8414d0a,9dc37309,4e90525c) +,S(4b224b6a,f38ae731,5b316eb,8dbd2b1e,6638794a,9bff79f6,1027f60d,5d81808,3143ea08,b1633002,bbb2ad2e,11ffe5b4,b6dc6888,1fc669d4,23ff9cb1,595c3dac) +,S(2c0767fa,4135f4eb,602a1a36,e6ce488e,2c1bdd64,aa4113cd,28daf20c,687380ee,ddc3effc,e78d3061,7cc2da71,1373de0,6a65d2b,1050b89a,5f71be3b,fbc16a7) +,S(83837d3e,e7179a84,ef6ed2d9,41a9f835,37b5a2c2,5d511ef1,982d9bba,50a7ae7c,62201e16,60957b4c,a86f1a49,5a6027b5,fe2294f2,7946c8d8,556024b6,e3b66dbe) +,S(cf075b34,e560f057,53a8e011,835bf1da,25e50d9e,1d70dd9b,da427109,5895387a,c73209d0,330ff4d2,38e19f6f,33df38d7,2b11d8dd,180d6a14,4b07184,a2127018) +,S(d583f8ff,9b1875d1,ef468030,e3ebb7,9d06ba2c,1008329d,cb01b883,7c8931a4,f8cfcf1c,3f092ba,6bfcfcc6,9596b508,aaac7c9c,333ba58c,d55be53c,6fae3292) +,S(551fe9b6,21d2389b,fc185372,342edb1b,27568bb2,da1fe220,3431b792,43eaefaa,6c76904a,e48563cc,c6aff505,7f31119f,ff48e5fe,971223d8,c3badd02,563c24e0) +,S(1bb778fc,74062f24,b0962be7,bce7c990,51f06394,bc8e6da9,a9d63f6e,d16a80b2,2754f53d,2f4ed167,3d2700b6,8ff036fa,60e9352f,1dd7bbdb,14be1740,61d88318) +,S(a150af7,1261582f,8949f1a9,3ff8d539,aa0744c4,e97cfbe6,e4a3fe10,e7e364aa,e22a1afe,a68671c2,f9e12471,56e1bf47,100737ed,5f96fab9,9e0df721,eaea4773) +,S(c94ec3df,727fdf91,d7963a03,8e93d68,835ed2bc,2578780b,7242e15a,e72e2a9e,a476a0e9,7bda53c5,46312b35,f0fad09e,11b2810,b3f570d5,a934d21,7152009c) +,S(3366b9db,ebe13231,7c542739,4235a72a,f186bda1,784c7f25,5f8b65f7,f146875a,5ea2478,95f52889,42321383,5439195e,6b620619,20171862,eea32726,1345d3cf) +,S(616c8e6c,e52265ec,cb85ef36,5092b2bb,58bec6be,444c2373,974c38e5,e0e8ba25,4d3d5543,3d6e258c,d8b286f4,5f41249a,724a9890,2f1ef3ca,ba049bf1,cdaa0970) +,S(74df2177,2e38e84e,8b81d86e,f45dc4a7,2617b3a6,32094b1d,432291f,6a651827,4c32baf,30f09527,fc4abc6f,9c9b9a57,2a9ccf1c,6a1b360c,48746d8c,22e01334) +,S(1814a1bf,76b74532,979966d1,5ef42faa,532f8dd9,bee0cce5,d68fc500,21accbd1,5f5df5ff,da9d439,b2205ad2,5fa93b9b,7af1746e,9b2eef3,154bfbad,acd46bdc) +,S(28911e94,98ff7526,badf2287,8e85fbdb,5f444d66,c422a975,c7476c02,b98625cc,5a341cf3,5cf26006,9d869542,fb221ba6,eac150bb,e3809ada,5e4c903c,1e638537) +,S(d5acff71,e82a455c,3a1ce292,689e8686,f441ce1b,e644e79a,bd6d0efe,29270865,aac6d48f,1b46e970,a044971a,ad13f033,ca8cde96,958d870e,dc7d80,1d26d5e8) +,S(5cf51c1b,2210d85,9d765e17,32109514,8f03fc57,51004b6a,91f098e2,e2711596,1eeb19e0,610df459,2c31e58e,aa2a2148,17fe9ee,a3995838,f395bdcf,26d5c3b3) +#endif +#if WINDOW_G > 14 +,S(21456873,b58e3687,52c75800,8d3bcae,9efaf1f5,c5727842,25e3d854,8fd421cb,a2f2d10,c85e8a0f,4a136ad0,5df991ce,7d3c5585,a263d5cf,da50a4f4,3db76cb0) +,S(c10de5c0,51ae2d73,28ac06ca,cca840b4,ed7ab204,21c6122f,1d68fe7f,7893d38d,ee30e086,a891484,2ad4041,f9ab9c57,cff1a315,f0642d31,b31c2914,faac99e0) +,S(be778032,f12c1b77,9bba3d9e,d290ca90,30ac7050,bdd77a2,7eac09be,eea65c0b,8657348b,a1e27a63,1dd2a54b,e2d5270f,4cca817a,219c5378,4d4f73ba,2c932e63) +,S(a05e7551,f8f090c1,bfc8ffcf,fbf7fd57,9d033163,67d5ee64,b85c4f69,33d0ff6b,8eba561a,f42d43c4,99e1fafd,43b49698,a8f3babc,c9c94c4c,4822cbed,a741b309) +,S(6e4d47f6,b17501b8,f3b220d3,83cf5f11,a395c0a,f0023988,c4e7b8b0,ef66ed23,e01c4330,16e3e6a9,535f1d40,905e9b3f,8be9f05c,b53e6143,e81091f5,4b76b57d) +,S(f626750e,b7eacac1,7cf24afd,43345019,c6c32292,c72503ad,d4125d40,67b7e66e,d669f903,67f407d4,5307578c,ee91fa01,f030bb9c,b66c7111,34b91757,1c993f4d) +,S(437acc60,c555f7c4,778595af,db4676a2,1fc8b3cf,2c8538f,cecbae12,811511f1,985fd2c0,7385fba8,4cf25a1f,46cd2c3e,de8dd359,1c6d20ac,584b4a8d,8a65dd67) +,S(8d50555c,6245e43c,a619fb76,ce45441e,dc585c7c,4fb2f33e,1c07965e,d4e35f5c,ea828c37,331ad0aa,44d168ce,c328a9f1,c7deaa35,47ee4757,c776fc46,439ea5d2) +,S(87f5f6ae,580ebfe7,1b2c19c8,cfe770ce,cf8d4223,62718914,eb853f1b,7f4cbaec,eb61df09,12e06f58,ed6d85da,7240dd72,aad00c3c,6a3a9c11,1f378664,cf359386) +,S(c1cfcacc,b95e6577,4e2a7d12,3cb0071b,3325c27c,5d58beb6,781a30d,ff6306d3,fa9ba55,cd95e721,12d98a19,8e3769ef,8cebb355,dde5b62e,e6f3b8e8,52a3e81d) +,S(d68bf50c,89f25969,a765af90,854bdb89,d67acdf8,f1e16bff,64868338,8b88e311,b62d1866,55835dcf,8064e13d,aca1e896,2157576,a02e178c,78d27c99,9cce81a9) +,S(b8d7c25b,8c20438e,702197cd,a3bfc05d,c6577717,c9b6a527,15ef84a0,2c0df867,316b527d,4be0e62a,2015f15a,17a412fb,72ebbffd,b02e53ab,6e5e9791,b771b45c) +,S(d98b3403,a299106c,9c6fd52a,8abd9ee5,cea9ab0f,17a15b4,7eafc809,c34e356f,bebcd24a,9300c739,9bb3af8c,12fa813c,78c6838,dbfa00a7,4ab09669,4df9700c) +,S(dcd15a1a,7cccd53e,db08c2b2,c6367126,de55cc46,a4eaf5d3,335ccff2,1238bbdc,7de57d26,bf74764d,bcc7e15b,72ec272c,58061f47,cc0715ec,48bcc032,60e63a81) +,S(2f6a844e,e758e3cc,8f299e01,ba5753a9,d35e6c51,6a87a683,8f5ce28a,fca17c62,5c29172f,f907c0ef,95e78768,2625c8ff,27e26eb2,cd86df92,b9371203,8b332e73) +,S(e63add7a,e511eed6,93f62498,17f89221,c7a3a909,253faef9,23f37a64,9e2a2f67,c392df22,5ffa1438,c3d10c6f,813c3956,4f94367d,6fa26c63,1d562049,99a77e0a) +,S(f9955ec9,20fc68b6,cfcd163f,34bd033f,4ed7dc8c,30da7f16,e41adb,908c9b7b,4dfc49e4,ab583975,90bdfae8,56ce97af,91c92f60,a17df9fe,9ee923b9,9fe2cf14) +,S(d974d713,bce1db76,c5ea1143,b63ace02,5a2362ae,fe6b84b0,ebb0c49f,22341d7c,991181fa,3ae5f188,38a94047,9ea9e4dc,e8ff9366,78583189,bc340d2b,40481577) +,S(4f0af691,424d441c,698dfa3e,c3e56bea,e2c52fa3,bfd9ca45,763d7805,33a3037e,caac2486,81590630,b0c67160,89db929d,26a4e15e,b06aa9a5,2e19c92f,a9f9817e) +,S(ef6300a0,70060df2,3f9818c1,6ff4d315,fb1c7d4d,fef41e85,c96760d1,3cea49e7,a0622360,2def9738,d87803e8,6405bc00,88afa82e,39666246,10f5d935,993334fd) +,S(fef30954,1cd2a90e,1d473ae3,699ea7cc,ef69fe75,54f7d710,33b1f23,c9e96886,c2479c48,59423c87,5d76f6b1,5c671ed5,c9489af7,79266341,4ca68675,cab64fec) +,S(457cdf17,b1230409,c3d35a88,390f1bef,859994df,3ba21d2e,ba5f826b,6dcb4fc6,5aff71af,708863df,3074c236,446ddd33,5695c0c1,a45bc482,e0787788,a0e4ede3) +,S(a66e86f,fe0e9cfc,686ab0fa,11b641f4,28499f3,450d69a0,dbce1895,6181ea39,de0cb1e5,ca720556,7c6756ce,868df6b,5174887a,61afd354,653e759d,b3e3ec64) +,S(ddad5a09,c37f0de6,67eab59b,fa2cb47f,b79bf6f5,b8b0403b,f689acfa,627f1014,8aed1b91,c9e567b1,9806082c,79ec433e,1a152279,69df00bd,239fd8f3,f8e8d385) +,S(45c5156b,f1439eaf,16a43b39,5c0a393f,a674e17f,76f96d53,9aa6c99b,49042c42,c9bcc2ed,c5b5c8c4,b17d633c,90d45b9e,1583898e,41bb9d90,1d1b5097,57f5f516) +,S(c83b3c9b,564906dd,60049c3e,9f6ed0fa,b848366c,3b93650b,7923e9ab,8172a8d7,5709dd74,1326ab97,8853304c,a02315f1,1f0bed5e,bffab6f,467816b4,4c60a332) +,S(a857354,dd08dc83,ce7b0324,7594e4c6,99692c95,9a4887e5,344cd0a8,7970174e,becb7001,ddafd72f,1f845579,ca8d56d7,2145c8a9,be816924,957ba324,3c396691) +,S(8bba6b47,88259a19,578adb4b,6f7f51f8,d09eb70,ea790d62,abb2ed45,84f94f33,afa42da3,8526a485,60919f12,d30549e7,1d19608a,81f4cf6e,8e49cb00,2492b143) +,S(bb4d27eb,412e73ca,d2697d6c,46a143ca,e4420ec9,30440025,47aefb71,c99a53d0,9ec07a19,842a1e5c,9cf9f76b,55ad98d1,9485e683,b6b6700b,c905e190,bd9da19) +,S(af6f6827,d197688,f00dd3f5,ded1849c,11fc2abd,f90fc7f2,18b33776,e5753277,f9227693,c9405a2b,10e9b725,aac7ed35,eef4281b,ca04e,bd75b143,89323646) +,S(40453814,445cc67b,e7a4b71a,55e0b993,2b8b3477,f093df6b,f27f55a2,8bad2e1b,ec71d7d5,4e823687,d01d7558,6de9a1a3,7edc927f,e221941f,46051747,a69baab4) +,S(f35a6c29,bd596f0d,93cabc3d,c07b5f68,300f6ab,8ecde5d5,da8299d,112c7bcf,73fe2c46,e1b13112,718526f9,7a39f1f0,3d47ced1,84a2e4cf,1e32c168,1c470121) +,S(ecc7ce7e,bbe5da1a,596bf41c,4d19b51,b77f7019,bc431aba,e5ecea57,b095fa93,1ab89d03,9e7c6ddc,7751c9bc,4eb84ed1,b077cc8e,dc828ffa,37426609,e089c8aa) +,S(559820d6,bb3e47e,f68f48fe,1259da06,cd0b380,1f6bedb7,970c079b,7e373bd9,2373137a,a4d88574,151540cd,ab8cbdbc,5831fb7c,4b901c27,8c9a593,172a64e0) +,S(9c9b7e18,4e76bd16,856addae,9352590e,310d653d,809ec800,415f3c64,149be4a0,182cd167,55eedfc3,21d71199,7543b26b,d08047d7,c9363e23,20bb9516,da37a146) +,S(88e4e3d2,2cc3e6f6,19e62ffa,c7a4aff,63b16733,202e5410,52cedde6,9cda2733,ec6e32aa,498a7a30,e1c47136,5671d356,bf174630,d1b984ec,d9453e24,d275e067) +,S(7f2f8043,8e7d7fcf,593e337,a91b06ad,3ad1c461,fcee7bd5,82df516d,cb1c198f,2cb484f7,5a4472b3,230369f0,79f5e654,8dfdce60,98c4e561,a1310224,13dc1d80) +,S(fe0c5945,c5e67d74,ed498120,dae194cf,33a3fe5b,ef0f1ac,2c64c292,59827d7c,4ebff1a1,7d59c8c,469fad0c,79ef819a,8a897ce4,c0fa1121,741c03f6,cab0f659) +,S(ac0662e0,1be37c28,be457bc9,4af19e72,34a9d3e0,8667c009,ec58ee79,7e539642,b3adc375,bdc81a76,8385c9e7,2ecec61e,9b2b21d2,55f65450,c5956187,837f3767) +,S(15e0f7bc,d74e77a,af933c13,6cdc5b1a,1622de61,251090a8,f8509b05,d7dd527e,4d51a063,1fb81f2,fa1ef534,5fa306c1,a0c64f94,66961cc8,b574b06e,646767ea) +,S(e4119d0f,b79bd8c,e1687abd,4ad63790,814f9972,50fac9a4,f1b52d71,93ce282c,cabde097,8f9a566e,32ab229e,63bdfbd3,89f01378,c7d27b0b,f101cc3b,36bf3fe6) +,S(27a5b030,2005a21,5d89c0b3,4e4ee323,5e94742c,262a89b9,29e286c0,ab8e3c24,4548d58c,3792f7fb,18238cfc,993fdb26,f755379c,e0ed1b0,4df26132,8f987a02) +,S(a18ec59f,7621c8a0,59bcad5a,12d3f536,142d5c94,4c7a54d8,b9206132,d993e08,abd8204e,867035ac,8cde70cc,f7daa29b,d47b888e,1faa9be9,b20744e6,ec5a43a) +,S(9bcc19a6,71b787cb,9da72c91,8d7b2264,b9497ab6,313de85d,c3efbeaa,2f492219,4bea790f,67b8100b,9ad9a301,61e3bd9e,583daec8,b77f4628,568ed554,70894bbc) +,S(7ccb2731,cc3eb3a3,36d36af7,f44a0a64,e23aa0b1,12ba0e6a,11280c5e,1ab36205,8d60552,1813ede4,dcfcbe46,c75c5aef,7ec40c69,99cf301b,28b0e875,3031c6af) +,S(94107245,fa13427a,7d21f7c7,cfe0c4e3,2943821f,da0f77b4,23fde091,ba596939,89846c62,7868b1c7,4c546492,dd4821d0,cfe15fae,36896af4,547deea9,295ccf84) +,S(959bf7d3,989d3460,5f4b8f3c,cd12ed86,cd0a2a93,a8d4e1fa,aeb5d6bf,24f1115d,7cc703f3,5417d7b2,b7229626,558be68c,66a915fd,7cc52829,dc98c81e,c0162b7f) +,S(8e92173,ff2de4bd,f468e2cb,fbf6264c,5fff8f23,2fb57e1d,2a07ee75,3b45e7ac,2655133c,8833040e,4ef4c98c,e5c75818,be781f42,cc0b7314,7baa3ef7,99cc017d) +,S(4acbd2e6,98f349cc,42998c5c,53de7b6,3dc29b1,c2b8a569,48cd3489,190f0255,8837f8d4,15b3551,4544878e,1a71922a,ba4a0790,22c74b60,325c6f49,a411b978) +,S(f79cfd2e,b63f6be3,bf0f12d1,fea3524b,1188959a,425f5e38,fa569648,df433fce,9e412cf1,698805e2,a92114de,5694a925,17c31f49,ddca7e0d,b2d83d80,74d92b2b) +,S(41910c81,78f7a61d,7957c065,5d7e2596,a0e6d5e9,a0a9cf23,28f23569,5d818c76,26b318c7,e8a880ec,94c59a6b,d6f1cad,84031d0,e62ded95,1e265ba8,c3603367) +,S(5a864466,9fd276ac,ad8782d3,51bc27b4,9445835b,75f70a80,2ef42a0b,4885cfe3,b2510d98,60be4e66,edb8c935,3c8ff8d,2e008c37,6dd271b0,1f77276b,f3a5a48b) +,S(5e3974b8,1b87348e,e3ae5c83,2dc56d1,85004b16,90445b74,1b8e262b,ecfe0e01,63f644bc,397a1809,a4d57ba8,f18f0372,cd4fd083,1c3d3449,1ef2a654,46275568) +,S(154e9c88,589ff342,6fe2eb5e,dd6e1db,e253498b,2c0b3e0,52e84211,caf9cc4e,3a897093,df7d31c3,754f84c2,68b0594e,85cfd4a7,c2731fce,e01cc3bc,2bbc383e) +,S(b95aa134,e48967f1,bd3a7a48,d89d550e,3c3c3c6b,3c73de48,f2e6fba1,81c93faa,b6f2d3b8,8d0821b0,6b1134d7,ddc898fc,e84898fc,4719f8aa,e3570daf,168b03e8) +,S(316564c4,ff00502c,f159db79,62984516,4d6d24c9,1f20ba73,66669808,95e58b92,6110a6d5,39ddc,d4185b72,cc576b7d,a4577e80,3dd47a92,d4bf346d,ec5905f5) +,S(222b179c,29ff89ee,d6f2a0d2,d38c6246,33237c5f,7803d8c5,e4315f93,6a9bd225,8bddc333,6eeb3cee,a0c3ac01,e7caf4f2,f44a50f2,587e3e31,7046c85b,a57cb6f4) +,S(10347fab,33fb4ee5,6cbf75ac,6cb768dd,f51f9b0c,5498466a,6679439a,32048904,a351f45e,30f32caf,e10d99f6,9e9e4be,c3f4aa22,5388984,bc45bb78,c0c5148e) +,S(7048c0f3,1e600042,4544e9f6,e26783d7,baeb411b,a2c29c7a,5aed8953,bf831629,4683ad69,1d9f14a3,f67131bc,55d28c61,1b78b2aa,329668fa,8fc41736,c95840f7) +,S(a65f7371,b35de05a,78b71171,40ea9e02,7b777785,13fdcc3b,484ad9a0,4bcfa1a3,41d1268a,77b31744,5a270f73,956bbcfa,3f291770,d248d1e3,364b4aba,72b961c6) +,S(dfa35552,8518d1da,ee31f04a,2673d053,11db4eee,cdc81f15,bce79c64,3267a315,19ed047b,4fa52430,18863cd1,d8ade0d7,dad60ecf,10b767ab,52f5cef5,9eea9a8a) +,S(663ec2a0,80564f1f,943a25b7,2f60d3a4,17b62130,3015e17c,85782460,c601a48d,fce25852,5a4dbb52,4057f8fb,a4393116,ebcffea5,5ae3459d,3d8b19b6,a0387232) +,S(cc714eaf,26f9960a,b2cb139b,d2fa0928,7a309c9b,ea852537,e10b6333,2912431a,c1c5c0c,48c98ea9,b57eb13c,fa64146e,67a95569,b45b8643,7752b037,9269d070) +,S(a6ceed6a,bb8f1ac6,13799527,38a19b35,ece44537,e74e9185,a4ce3939,c14f8e77,c0090ebe,d410f2e0,2e56b4b6,adfd5495,488c2930,2c5e7a61,3926880a,88beedae) +,S(e0b0c34c,8d4f77f1,dd09ea34,8b0ec683,cb5ca777,6720546e,27ffcf55,a5e5bded,ed4adb20,ab5da65c,2d1d5d68,9ad63ebd,90170904,65f7ad03,1bf3d811,f407d09f) +,S(2362ff0b,9a2d0f7f,d779a83,8b26da93,65730d32,bc4411ef,fc4fd182,d9e486a6,d3eb4ee4,42bd6157,557e4e9a,dcc9c103,892ca05f,5c5af804,f736ecee,d8a6fc3e) +,S(2f1636ab,a1516634,a00a464b,aa30c507,af25e83,3f7f6fdd,ccf0706e,d5fb57a0,a664c955,c24a54ee,d56f1aaf,fc853c2f,6a81c53f,1ee36c48,46b26452,fcbcc054) +,S(243a8fff,6230829c,73368eed,fb4d62f5,bf478b4f,1752400a,91ac177f,70c303ac,29318b21,9f371dfe,4048c4b1,2f5317cc,b2e9c44f,ed72b537,a2f56d06,65229235) +,S(b17182a8,5f442a65,839230ca,5cc8f67e,835e54b,e0296c6d,e2b62298,74ae804e,11a4fbcb,9f6f8775,9d131a81,939e0125,7f7b4fca,e36ea644,4da3cc16,a161e5aa) +,S(5c9abfd1,9cae1a47,bebdd324,d11cf758,a1224471,6e83795,e42ff5f5,a8142a6f,38a38db6,f64d9d07,4a08a909,28768bdd,adbdd858,79ec847d,28c94dd3,a122e0d) +,S(44a8a4f2,ec3dd02c,226ae0af,d73a12b9,726e03c3,2a41099e,b70cdce2,767e390c,b7e18dd1,e6adcd88,1d1dbead,e1c83ed0,1f1d7b2e,50246539,b6bc2811,d63233b7) +,S(8e477766,c4de01c2,5cc17218,7f3cb6f0,dbc8eb54,fa888911,33131b7c,219e6e13,ba8f447f,10286c86,d1330c82,2647a999,b4b60e56,4131986,a6c05128,a480d83) +,S(c5f862ce,dd253879,8100eea2,92e860fa,321d7709,596a4dfd,6faf6345,82fcd3ae,81ab1260,684fd3d8,1b47c5d4,d5f0c319,93ae7db4,fed1a781,61d9d9d4,50ff831e) +,S(a674db01,836fe328,8566d977,753ebc2e,d55f0116,5ebf0349,51caecd6,ebf899db,12ae8327,737f7db3,56e26fb4,1ab306e0,2294136d,71206f43,78300b95,60f580f) +,S(b0cf999e,f11dea14,3e6b6254,aedf30aa,ba1e8e92,96c500f5,481eee45,a0e15adb,e4970d00,e02adc6a,be5e2433,7e017dab,17a61de1,d977ee99,969591,91a5563a) +,S(b3615f09,29f9b2a0,6a4c68ef,c844ae5,54959ffd,f03f9266,f918f16a,b517380b,31a7675b,83677cc6,ca87c525,27fbba60,d06ea317,fefb17a4,7d7a4242,3595f1d4) +,S(7be97bde,b271f807,96930353,b82c3cd2,c6cce373,198572c7,d289511d,7cf262a1,1af89a8b,cfa4a399,bce5bc21,e26c97d0,5126f8c3,211d8051,626c4f2e,c6f128b6) +,S(692e447d,df9c77f0,2db1d34,101bc355,519d40b1,3fff2cbc,aafeb555,29473d4d,d21950ec,fb7bb723,4e4e48c1,98b93a10,8a85bb5d,5228116e,da6f5cfd,8968fda) +,S(61b6fe3a,21b0bbd2,dfccad11,5123db4a,98058bbd,4f8a61b5,e416b03d,b1414243,75d3dabe,f3e2266d,65d408ef,af6b32da,7591f08c,7fe7de,ff20b9d6,7a3a8a8c) +,S(fe0f9f,aa49555,2afe97f,8462869e,e8a584ac,3c3fba4b,886208f9,fe260ec2,a9c0fd7b,cfa239a0,299afa47,e2861197,f382a331,7607e129,967bb22d,3ae3077) +,S(7f7c9a0,a240180d,c645e77e,c628bff8,fff90d48,c85d2fdb,faaf76d9,b93e26a2,1b12ec74,f801fbe3,ddeeb37b,c940c605,84b0ef14,85e9d888,f3f81c05,607d1222) +,S(3e444ef3,b77b49c2,75aa0524,77da59d5,a68dc6ee,6288e2ce,140512,92e54c60,e211ba3c,6860a898,9e1ee04c,ea9ddf52,25ed88a2,c6ecd9fe,3c2fd500,88367b7) +,S(4844747d,d33f7e4d,39aee79f,138b5fd9,223b4e51,c86e4894,c917a3d4,746d824,68cd147,2560b5d1,6b9bf538,b7f1e193,d2f220f9,ed9f742b,d36a003c,28e2357c) +,S(f0211c1c,8f87fb96,bd591255,6a799865,7382380d,6b5b020d,9095f482,4e8f531d,649112c5,9cf7a8cf,7f9d920a,6b6d1102,d92441f1,1bde7561,9cda8eb4,a26d7493) +,S(918118dc,15520a31,c715adcb,3e02ca4a,4d77c92e,310ef057,3f9c7a4b,d5d2d54d,37d2c580,337de379,925506ab,c6b7d9,4a61584f,4cb2179d,560d3a7b,406873af) +,S(78734d5d,833a5d24,5546e5bf,9d3e5ce5,61f818c4,a4c90fab,c8ae4630,a2c307f4,4b150c27,e054fdad,73506310,80eb5308,b39c6861,23b851ba,aa2349f2,c26b5981) +,S(ee988075,34a02de2,9fda41b1,c821c41d,3ddd5d85,9c5a4ce0,d14ad743,25943f13,ba7fda65,4389494b,40a9fbbb,4b72739b,6f85effe,245b895c,b8c7e423,8d6b7973) +,S(4a821b26,bd1326a8,26be6fec,b90229f7,d7a37a2a,c49e97a2,5bddabef,e854e509,8a645892,37ea07bd,929aee46,6fad63bb,5612de36,cb951200,b9faaec8,b11bfdd8) +,S(23658500,fe8b5ddb,93dd3b50,a46f9914,d04af9d2,2a786be5,9c0fa7be,7c3eb2bf,840e5cca,f9f3e8bf,fe51c1d0,a84de234,d7122cef,fa1f0ed8,9f1701ff,d17c40d3) +,S(71dccb97,7f8e77f5,a03c8e8d,e4b2a30,11d01e13,549949ff,42af13cf,d7ecf208,b70ad10a,5f03ad94,dc8d91dc,e7797eca,6ace74cb,4715bf6d,2b628bd5,f767f34f) +,S(6174a230,e15b2584,7a25217b,9d95f07a,e183f2e4,74d0503e,108994cd,69d20e6b,18cda952,ccd68c2a,5d78060c,6849fb21,e2379b48,425003c0,6f148a34,bf876efb) +,S(57cfc1ee,38d905d2,897dee9d,105fd4b6,90967618,2a2a5d3d,70781cc,9134bb97,bf6b5fa6,4de9110e,7d26e67f,65cd2765,fcedc182,1627243d,a85bc955,2bdcac33) +,S(26605be2,e03705ea,7f199cad,d4d6e711,9805453d,6d4feea5,ec2ae3f8,cdba59c,ced5f775,b62bddf,5935acd,9786847c,e7825da1,5807b117,7459f51b,72fe5774) +,S(6d89e2a6,9ff96c49,a3110a5e,7e17421c,4ca2d07e,6e807a3a,98d79954,7fde2457,4835767c,8f96da1e,78f1788,d9764dea,e4e4a0cd,238ff35d,851ee7d0,9c915df3) +,S(e3607608,338f4229,d77c51fa,cef2697e,f6010c8d,5138e0c6,2b724ad5,6ae79a74,da6a0617,a42d6ccb,44155f27,7c56c58d,42d6037,d234f1ee,ffd720d9,2ae23373) +,S(c8cf20c0,c12de1ba,1ad4dd44,46f76533,7cfefc3e,213c426a,e0cd25ee,2e8bea9a,ef7285a5,ea7393a0,cd78ea31,ef74f605,3d3312ba,f17bf6a0,77b919b2,33227ed2) +,S(f3d2870,fe782b7e,26a1a4f,9c7c3ba9,30e0ee0d,df6593f1,9bf11509,1fa63477,e470c266,ae26fadc,b2780985,9b9d60ca,fcbd9de3,5dfdfb67,9f4fd450,4ed6f3fc) +,S(702a6778,bdf2f3bc,4ee954d8,1e7acda3,1df7127e,a7920e59,a7028253,9019c6c9,2ce19ef9,10d773d0,cc32a503,83f9e968,ca3e407c,c1dfb652,377d08dd,1dca5b96) +,S(ea85cddf,4f79d7d2,a5db06ff,f1c1e3b0,87b0242e,1d7de713,53d8f73e,1bc83888,3806d40d,ccd867c2,2d166056,77d2d64f,d7433dd4,b1e83e25,91860599,2e66fb83) +,S(d0631e8b,30ef6467,de6af60e,61b99112,1949b324,786ff1c2,fe633249,a832aec5,deaf31e3,703df166,b0f92ee4,eff1cc02,684911dd,40054bed,4b21d4da,17f4c05c) +,S(b56cb88b,617a7104,c205e089,b83320c0,5dce438a,50411e5a,d342e9,8b258a3b,757edc72,52d76fbc,24a5515e,417625ae,11db0072,24c02fe1,1e249064,b5127800) +,S(e91ffec8,bc3fa3bf,b0a600b6,89db92ea,7c3ad411,d025a42,95570596,f44702a8,38fd56ef,1f7b476b,2e36aff7,73e190b8,61ec6370,f6ae524,d5dea16d,cc4833c1) +,S(4cd9e6c4,8bf7b1ea,9f855b14,fc904ad4,5e3bb71a,5745b449,e1ab3165,3bdf53b1,b5a075d5,ca9060b7,7d3a00c3,6fbc6404,88df6846,c712afdb,1115798,f382b4e9) +,S(abb07ce9,c4b711ab,d01a12ba,45f0040d,e3ff5a4,e59140d7,cf4ff289,42b5cde0,a8a0e68,350a88b2,397a162f,fc969d28,ed937f60,4704dcf5,2faf755b,d21f503b) +,S(95fac51a,c9deb5d2,b794423,a71cd282,b0604afa,bb3160ec,557a8b74,c578f18b,da99fcf2,abf21cca,c6f4e89b,de2a6e9e,ad199cb4,b97f4122,4f68bb47,b7caead8) +,S(2ecd3e62,b79b4f69,609f33f,2042b56,bad2a9a4,18e2852e,9e8f0d41,1fba8ab9,ef964275,95061068,478e11ec,942b6a2d,99e5b557,830ed0c2,c4291305,41104046) +,S(437d446a,d139d88a,b5437f06,6fdf8acf,7b538798,6baf9551,a414fd4f,101a6440,6c532bb3,38a34a07,28d3273f,e9d9c70,aa79c484,6cb337ed,b41f6029,1e2caa13) +,S(63149b01,94b4955c,1b7e9d51,24e7e7d0,4bb5d902,7e86e63d,f3add9c4,8ab2a44c,c867234b,b4ed27d0,dcdf544,be060a12,4c460c5,7a9312b1,46d2bb61,fdfa6c1a) +,S(78e509ae,99e6469c,41c44dd6,868ee402,8fda1cf8,2c83be01,9fdf912c,1e638bfa,ff3b584c,5ffcb1af,4980e2b3,ace00f12,3be630be,cd91d045,4e031120,245e92be) +,S(cb1d5bf3,f97b2bc4,bb33babc,72de78ea,34cd0a0c,e841cb55,7b3dbc98,61e1544d,e619e8a,dac79a61,eb46add0,96bbcbe1,31d33a6e,b6c99220,123dc9ac,3f27df60) +,S(3247eaa3,9ed5b604,d3038127,9661f350,53ddad8b,8e29d0fa,5c27ed6f,551cf374,1d29a713,d7dd351d,87175b49,afab518b,f268ce81,7fa39ccb,f08b3c58,de1e5378) +,S(d493ab52,8d6c627e,aa3dbd3c,8d809ba9,8a9fe920,307a0c66,2917f8cf,f68b3941,30e4336d,e1621a2f,fe7247ff,157a37c1,edc4f83b,e9fbd84c,af4f96b,8997c7ad) +,S(8dfac8d8,b65eec8a,a65f96b5,571830d9,22469450,42fb2baa,f76a4db2,ea5258c6,c204e9c0,72f643a4,1f53d8fa,dc66e3f0,fdf0d000,c27a5492,6323b2bf,b376af16) +,S(331ca867,1098b530,1b1e6f12,d231793c,de67de5c,640f0a1b,fbfe485e,5d2adff9,b52fb89,3a466c80,ae61d534,cb03fde5,95078592,1da21e0a,a8103d7c,c2e3d8f3) +,S(f34a338b,bb05db6d,55beb49e,526c9d49,fd515792,f407397d,3b520fda,3ffcf26d,6a6921c,4831df6d,91e7cafe,869c4274,faada27d,9d09175e,e86a0b9e,dd70910a) +,S(56d97dfb,284c7417,2e08fb73,3a2d0305,ff774495,2f229bed,cd36e7ff,6058e75f,3775df48,aeaafe14,a8005434,dfc19538,2d10ca90,d05bcba8,edddb2ce,4a4ed7d1) +,S(70e668b0,e854cd8d,d3469cc8,ffab1709,2d9341c4,4831196d,72d9673b,43dfbf7a,60567ba3,5546cd93,f2c356e3,927dc89a,c43fdf50,5e33ca9b,52552587,c905e311) +,S(675af615,9fb50100,56ebed3f,4c9784d1,17538d58,afc5ec75,fa93ee00,29d32390,c501aa90,4f9dfa9d,78107844,983e17b4,34872e3a,a94e37fb,6677186c,fa1abdc1) +,S(99f8e5cc,86ac5587,81a67270,3059442,88b19703,551474a9,9d433d6f,37672d90,30148ff0,9fa33b4f,f4410d57,9afcb705,c1146663,bdbd0fbc,8434f4f8,eacb09dd) +,S(8dcec207,3d74b9bb,bd47f52c,394b263b,e71881af,363bcd80,9adc345c,b9ce9892,d8bc1ef1,79ac54e2,68a685a4,db35e3cb,5b6774d8,e8d6b738,f4d65b66,86782a5d) +,S(d83f7e8d,adf27d5a,f8502d8,3ab81001,a2219805,d942cbfc,76db2764,c4235773,48472e1b,2609f81a,8b12326b,1b19b422,763b0ed9,d6fd67,51751c2f,8aa46c2) +,S(e6f8bcf5,d9ea8209,cb46ab60,643555e0,d0569f3a,dc62ac76,edc09a43,e02fea2a,7974cbc9,5a9dde1f,34560043,7b628eac,3641498e,612c19d9,9a79ae4c,cbde2d82) +,S(d2f30716,e4c1a665,a37d0606,3987d0c5,c19c072b,f1cca8ae,cd0e4d8,6a9e8c1a,e26e6d9,9fbd198a,ab83d0aa,ea53228b,539efd37,ee7ee791,365cabd3,8850eb29) +,S(d7a891eb,551ae5ac,baf366b8,65755a56,edc7bbce,7304a806,2729655c,f7f61cf8,8a7d915c,3a9a1500,616205eb,798915fd,9b33d7b0,6671e9ab,cf02b5f4,667173ab) +,S(5bb03484,f02ef87a,fa07f852,e3ec0664,67ffdc38,39fa28db,de0da07,2fc31246,e0515751,c377266e,ff95f755,f9c9373d,226ccb66,3678e8ef,176af5f,2fea3504) +,S(58716b31,48a0cac1,2024760,60d3734d,ab066ad8,c0f8d8ed,cf5824ea,83e111ce,71ae487,701d16a9,c1d2ab68,1ec7c8b5,8367a4f0,179dfc18,6778579c,553cf608) +,S(4a344869,db8d561d,96944c8,94a3c196,8d649fcc,bd430c7d,4a66ef0c,dc2ca550,285433f1,ff0e7dba,5bae081c,1b33c762,6f30224e,dcacfe66,46787818,da0f810a) +,S(3ecc369b,e7789b92,cf1448ee,28c0448e,ebc5d277,a8bdb5bc,a22d3151,5e246f7c,a5532e1,47848951,cf11e065,3f0627c4,6530436a,5f3773f2,b02c9bea,c1b60e78) +,S(28a5d794,21db38dc,8d7c8cf9,d120a3c9,97eea170,f0f6ed43,7222bf4e,27f170be,88cb09e5,ea40b566,39cce9ee,1245384d,2f02f983,3b3116b7,31ae5576,daed7cf9) +,S(4f54f945,b3afc07,c38e1aae,16dafcbb,b7c5097e,4895a789,e70e0993,cbc905f,6ba69303,24adb3b1,2fc1f8c7,8ea58729,5115adad,52bb1138,7281b9b2,997fa597) +,S(f490bc4a,20f1ecbe,ac2dbbd0,56f2bb77,d258a914,9b0732a,f29aef2f,7ec25f47,aec6fa89,74c124a6,576475a,60931a6b,533d0da6,4e621fe9,c298f03c,a894336) +,S(73b2f8d0,e91e2516,d2ebe348,85b973d,4a0c7919,1ac857b4,74f713d7,348d343d,9dd7a951,efdaa060,19ec71b,e41b294,d047ab97,d0cef4ce,25a607f2,f11bbc26) +,S(d911f5e9,977489d2,847aeb66,8c3cdc6a,ffbc7b5f,4a5aff62,1761ee01,567c5647,3ee4afd0,2ef6d3af,a2b16d34,b59444a4,2c70b3d,4db17788,ad3aac57,184e02da) +,S(87b695f1,5c5d7852,88218586,96bca8c1,9c5a6f3e,f23786d1,fe010fd,d063b0c3,21b54a,46ee82fa,bb5ffe0,e3137892,31623502,9a8e0505,645a9ec9,29984895) +,S(39de5a90,4ba6989e,5d16dda,a7ff67b2,15e08f3f,b593d7a8,4b6babe2,ca25c658,eaf5e6c4,1e1e2fc8,c1581f6,211bc8cb,34dcc08d,58f570a6,e6719626,7124c019) +,S(18c1f673,ca19f805,c426162f,11e7eaea,c675974b,6b4cf0f5,9eb03288,83bb0af1,ad1690ae,65783091,27f602fb,93652b59,d7507414,e76d9b3a,82fef166,68b7aecc) +,S(8d70ebda,893e8d03,d15fbd68,67528b7d,308ddee7,b2620698,15e7f3c7,332d42a1,254be26e,d9e9009f,e4aceb8a,b97020a9,9196a9be,60777fb3,a9d1243c,66df1707) +,S(c32fa0af,ab39b1c0,c96852cf,8e2382e3,93e5b59d,2e83ed50,d5307a0,14ea330,381e8afb,85d47c3d,dc5da037,d6bd82aa,ff2324ef,ab0e48d5,5da3fcca,bf0ee3da) +,S(c350235f,e5ad084a,1aaaee80,d156b302,d34ec03,360a7c0d,3a883cb5,19f4b27,e5ea7c5d,3184e9,b62fc3a9,6c8bb9ae,72535fc0,497f1b58,67bbae06,672a1f79) +,S(8ef5e1f4,8d905df,dbbba4b2,d4b22162,db839ba5,b28c755d,46bc2f00,e25e20d5,6300d9e3,11971dd8,a3e88192,84f3a228,9986270,45b901a1,80f831b2,4153103b) +,S(9b3783f9,c638a6fc,166aa2a3,3a40d95f,35a4e7a6,c8cb5fb5,1e596b9a,f285279c,41b2dd9,c3abce77,fcf798a9,159f36c8,94b55ac6,7c917de8,75b18cd4,e70dcaf0) +,S(c262215d,720180ac,669f0bb6,885dceb1,2c941730,93e561c2,660a4a1e,cdf0a244,7fea7ed7,f654741c,c67b12b9,f115aa40,ce427cb3,8c6498f3,8bd291a9,d73e9f2d) +,S(bb72f723,f0a16f09,7716272b,b905a111,c290c229,94f400dc,c6a24814,f41816f9,52a83ee6,53214a5,3ed2b13b,a367324e,e5606fc2,e3dc05ae,7ce0cf05,ccd6c36a) +,S(d896a5a9,a833d66,51b17632,70b03d36,eb423236,bf3b2b7b,6b2ba97a,f9282a03,e8a823f,ecec375e,280e0d50,49625dc2,1f48e269,77ab5eb1,b467d3e8,a0fccb37) +,S(198cb33d,9a2b790a,2d6fa355,58733bc7,f64cad76,e3921dbd,8d7a1f,8db52b64,c7e93702,ad7df0a4,94fba344,8a8157bc,eba10ee2,8f66f000,7e7f7655,8e6b4a74) +,S(4354e475,81d63d84,df19bd08,d98b2315,67a55550,477e1c53,cd425854,e67cd81a,a612c262,74d79c46,89734884,5b87ef50,29d0f87b,4a06e4a2,8ab36bee,ae6a6ce3) +,S(d956c71c,1c8b110e,19f96ffe,5709f2b2,83a095ad,977878fe,287de35f,283b2606,7c029c97,9a807375,bb589c12,a20ce37c,75178be2,5d5af713,f4fd4070,429c8d0) +,S(2c04b299,1775ae36,ed7d5b1b,d9b0e65e,fb2bff8,ab99dc97,2cd860fe,19b1789d,8b3f3b00,6d63c81a,86f225a,bd8e658d,c9c4c1d6,6787678b,6fa4a692,bc7f78e6) +,S(c7897c17,debd6456,a81f8d96,c0ea580b,db5daffb,5fc8e8e8,9c8612b3,7b229f7,f7334550,d20a1a21,c422f73e,d23fb159,2fb3d9b7,ca61d7b,6e124fa4,147ea63c) +,S(3b37b93e,ff554f0c,7e7f36b1,864ecb73,7b33a93f,6ff31d6,9ea18aab,a9487505,50ccac12,e071f469,3f5e5339,462a0cb8,66bde539,5842ff44,620f7acc,aff09a71) +,S(4584ea49,8a2785e0,b12c86d5,2b839212,f21b2e33,3b64bb0a,9713674e,66216547,2851de5a,b67354cd,6610dd4c,91aaf4ce,b75c4c97,26d524d7,69ae0ba7,997ad79c) +,S(c0c971d9,f5644eac,851ae8a1,d87b4f09,a802ae07,32d9b5a2,d9589051,f139963c,83e07a5a,2b7614c,c064b4f,815b8a76,6df7eeb6,449fdd50,5c43faaf,b0bd075f) +,S(370e8fd0,858c6fbc,f479deed,f35fef5e,80cd2338,90d4b227,1867ea90,6cd15b5f,ef382477,fd2dec6a,fce439ba,9b341a21,17d6ecf4,c8c8d63f,b5775094,6cedcaab) +,S(ad402a30,99c5d5dd,c7ad9631,b592d5a5,862e8d3b,5ed47dfa,c288193d,69366625,b8c0d468,5d0eadfb,9f7e4ce6,11c61f5,7098da29,aaed61f7,6a50961b,b45b7c5) +,S(ec16de3f,32ea8f58,c1dc93da,d1cabecb,5ca33ce2,e3fa3bfe,bf0ee989,f3ebf5f9,aeec3532,c5391ce6,1e23bea4,5b7b5847,2c36cb8a,6c5f1363,e457c003,b18824fd) +,S(5a51f9d5,f5c48520,dbd826b9,49f62f67,c299a228,259e09cb,b3bd6fe2,f4b0e60b,3c498d86,225a83a1,f506eb62,a2e530f9,511c56a2,eeed77a4,18ddec4f,4404b9f5) +,S(9696865f,64523eaa,456ea65c,40ca6e0b,12c6e6a0,211cf8dc,20963f03,7980b684,8f879d8b,491f11a4,1f0025f7,b35dc8e7,c71e420d,7d7d9001,bf5da111,9ad6c2c7) +,S(80c43c8f,6325cc30,8065d4c8,6e3d7bec,6ed85f74,412f6127,4fc3ae49,b1e185a5,31dfbe69,a48f1f39,a0cca355,f3d68f28,cbf3e14f,7d47cfc7,d9e82e25,19bdc292) +,S(54940550,ec4a6ca7,561946c0,65769b4d,d4683f1d,11dfda66,4aa2f8cb,8f1ab2d7,f41aef26,64466fa,ecc076ed,cd383d3f,132b4fe7,5a17f16c,c394b6ec,e4079378) +,S(a9787f8,42b3549a,9a3bea8e,4182555,99addeb6,416118bd,901afd9d,ad4c134,4efc4f67,65c7cf5,ccc2336a,e9eb14c5,a1361067,7632ce89,68033d57,4bc686b0) +,S(fa83e81d,63b85491,92e800e9,7a422ca8,35c03bb1,5579bc05,bdb4367,198a24da,779940b2,ad301a1e,205c0504,fe3ea104,cef6a459,e0479849,90fc94a6,871954eb) +,S(ae9a8d1c,a8a560e4,8a373666,544a7b9c,84bf0475,9de1a63e,4a20b55a,2f25c132,b9b0bd66,4c46edfb,ca2a0bb3,a94ff043,c00c1441,9f1df886,2aaadc02,e25017dc) +,S(a2f47145,296dd22b,3a6f5185,47ab0957,4d3487b6,8786f87,6758cbe3,5f4c0ae7,2ec4171c,15e7a82a,f6ace24a,60176f7b,6239561f,3c369a9e,efc80d52,3fd216e8) +,S(1bdcf82f,a7dd441d,91332a11,35f50be8,4d275358,f95df300,25187f2f,9828f219,99f12980,92a3ecf3,dbeb290a,67d72aae,6acd9cfc,c21918e8,9ff7ad4e,548d3510) +,S(b73c91e1,ae33767b,11bd329,361fdae6,36642d92,6c2792b6,e19b6e3f,947a5be7,b6502357,11ffe955,be5798d1,467eafdc,94df5911,29d2aaa9,b747a2ec,befa9d7) +,S(b23b4ad2,e983e556,e941a35b,b84846a4,40cd25b6,82487f37,a3a30eef,eef15d1,7010f10,88749d1c,f95e52dc,eae1a379,b87762fb,55593d32,a65ef0fe,dcba2485) +,S(e3aad2b8,96fe34ef,9d775743,6e70a70c,b3bb0c6b,8436e616,a23174ca,985fd8f7,5d6edc38,89beb099,dd191564,eaa83c14,3ef0b74d,7789590c,d6083704,61c6676f) +,S(2f22a14a,f69e6257,b909e3a9,50aab3ea,dc09c281,ec52e47,8c578f49,68910244,4ab723e2,43c71baf,d2aead8a,479a1a2e,fd2aba74,800b5eff,56ca46d0,532e81d7) +,S(93806026,554bae5e,9b91f534,f864b79c,81e581f7,bdf3b2ef,dd007e32,dd6872f0,800f8162,a6836801,d052871f,6892ba33,b2f60f82,89a658ea,a8af25fb,f9d9c444) +,S(8895d121,ad1f2be2,3c578faa,1e33656a,e9403ddb,a1f1aea6,1cc7bd03,817a46d9,4f7577d2,420d0d0d,7cc9ed68,ba3645b8,f9466f59,570ddf16,ba168de2,8cfec881) +,S(1838c15c,3bcf1189,546a9e3d,69fb8a73,de39c862,f5faa4bf,423e1dbd,29046ccf,49484789,1b67ea0e,2e7f7eba,4a596d66,b3ed9842,3ffc54b0,e9292a4e,bd6f5487) +,S(111e8eab,d9cb3ec,5eb63cd4,14ecf59e,3a3f0d56,70959226,ec8f203d,947204b0,4ab9b3bf,dc853571,2c0db9e1,5fc2832e,4560e420,af96b043,e587d1de,d996e38a) +,S(80369d1,ec5ab7c6,492db1f9,aa2fa368,ec083d86,75d6c1,e7262e73,a612e493,cbb28c30,db7f7d03,6b8dda93,7e0c4e18,6a09f1ee,2407e55,7f6dc54b,a8c0553) +,S(903c9034,dbd3f982,41351979,c9306a8,42b88892,48cace15,c3e3a8bd,aafe1ffe,d55adb43,d0142740,71499c92,e9b851d8,e6ece26f,f82ceaff,ba63a003,14960f38) +,S(d6490ce4,74bd1e80,82c99e87,a0510a2a,c2c2772b,1921cda7,dcdcd5e8,6ecaacc,85a1fcc6,de4b93b8,b2314da6,31d7abdc,f96b22e4,b44a5545,f274f941,454e98f4) +,S(12f2342f,aa8b19a8,bb0e080b,2ed3487a,14ddd1b4,83e0bfa4,9ea08484,157d5306,eee0b9e4,30a51a3a,49da893e,50360ba1,21660b4d,ebd3ad8f,82805416,10f4b7fd) +,S(3bf1ef66,57bdcbba,a9d9a23,36c75429,c4df4a86,1d71a767,2d7e956a,deff234f,fa98467e,83dd1ca2,2a85cd8f,f12be1f,53d5a939,352f4046,a626a208,601ef6b5) +,S(d0d0f8b7,9a04ac8e,b6e010fa,3608926f,3b5bd886,f84c361a,8e1d9dd4,b01ff717,9bb32b90,6d7de56,c75bd202,b9353128,b6440fb,42dae8e6,74ade0c8,fc96386d) +,S(19507738,80caa9c1,f042f8b5,d1594a12,161635b5,a83e4675,35ffe51a,fcf631fc,9280d033,f7a8efc3,ff22f501,6a6ddfd2,f78159bf,1f13be4c,f758b150,21126ba) +,S(f4f50c3c,eb750a04,95973b47,53b96ec7,22cef833,f4ee7459,a51f884a,f9a251cd,41f554fa,d3d521e9,65fb0768,66caeac7,d9f5c6eb,ba7ba7b1,d1d38c9d,c06d85ce) +,S(8b669c9e,22452528,57e20692,2726f045,e97b8cf2,1154fb74,e199f49d,11951b84,550c47fa,c46060df,4d893afa,9f08713f,cc8e719f,a369e90b,fa8846df,7938c65b) +,S(941cb4b0,31edf346,64dd5e7,92ca135a,1d6cc6f,55341322,66644493,aee5fe32,cfa91a79,29b3b47,d73b8ae6,77cf64eb,cacf9408,3cdc76f1,79e25631,d574ff68) +,S(557e36b1,27307c56,72232c6f,6e92e4f6,f5da9d22,1567b464,8e79d97b,bf589023,ab741e35,109a0313,e7adee7a,2cec2c10,79d18d72,6c27f1c6,5a808b98,8e99b523) +,S(d8081ed,9e7cf1cb,e1ff07c0,b8ef3f9c,c7eac02f,1cf1c6ff,833f4b74,b2a33269,efa297d7,10fb71c8,43e358f3,e04ac308,53027f00,eea43d03,9b87c3ca,2b0fdd2e) +,S(b5e4fdf0,7a443146,263f6539,f6c8d991,7486da78,95b4ba7,fb4c9f14,78324d44,a3ef979f,93ec1a0d,602950d2,ddc400c8,4f018643,229cfba8,7cd9e3,f2fe657b) +,S(1a573259,a5100c21,d75efcc4,41d5a834,a81d96b,f4149731,eed4ae67,508bffcc,8a993dcf,49f94f6b,bc71766,9d37ebfc,614a45f4,1d70a1ca,f4da8834,5711223d) +,S(33d9f9f6,c9ba653b,f9c52166,c29e9c06,2cb7700d,ea2f40cd,28520bf,237b4558,dc80f57c,fc0e73ab,bdfc4a8f,f7e8f4c0,3353e889,bd54cf84,6361c1a9,af5a0a79) +,S(e4ca84fe,307c9237,4d39b2bb,b017b5b9,e478b26b,95236b8d,5bdfb220,f44419d,c0cfc7d8,92271c95,7ef235f7,2f310c7c,7d0ac297,97d42ffc,ba37061c,83775507) +,S(8f1f2d2d,cccb07a2,a8716b77,8c74f3fe,22990d36,b951e6dd,92f5896f,51bc23aa,9eaa792b,426d3400,31a862ca,b805d0da,ed9a4c73,591c204f,c5179b17,22aef870) +,S(20f7f6da,86eb5ae6,6a1b7818,43fd7fe4,c458e3e7,bfb590c8,76afb601,257b2ee0,6dfcd6c3,93e7e9dd,32c7e826,42f90d69,ff1e1ffe,18988de2,bc1cb9ba,db246fbc) +,S(3a3df365,8d65d718,2dc05797,8bc48fe1,5c5eb6d8,6bb241e5,9e178ca3,9cf9a010,ffb89791,7435e8c5,4865bc79,52fb7bd4,1578af51,6f611c54,1f7cfd5,651b293) +,S(7aa435,7dbbc5b9,a01b5f94,6b0240a1,36daa942,1ae1a1c9,b50f66c1,c7f15e48,4640c8d1,ace8f69,6b08ba1f,9a46d04c,f75c5914,3339d5a,181a7dfd,bfc92c0f) +,S(198e4848,8176664d,40fc14c7,acca9eb9,aa22599b,b2370959,5856d78b,5e932e94,fb9dcfdf,b27d062e,8ea5246,275d80e5,6fc7cb09,e81bf066,dfca888a,8df1de6e) +,S(25da8876,d3215051,75694915,c25056e1,2c1329b7,7795b7ec,1d4b66f9,3c911cc9,b8cf4a83,db78787a,6d80a157,c7c205f1,3664a71d,a6e78db5,b52b012b,930c4583) +,S(893d2e9c,3b6fa8e2,136994e6,14121842,bb82e577,89826ccb,eef51fab,de32c0b,d7cb9b4a,1d49b34b,f3f743f2,10c32a25,cf8df45d,8552a7f2,1268e270,ee6fed67) +,S(dde2e8a2,988fd777,4959457a,5c14384f,c8248d1b,a32c7ce1,a727af27,7b217688,1fe0272,137e4c9b,1c6df618,41a240a7,be3b5de1,7b93fa24,ccc055f0,e7972b1) +,S(52a73b51,5326198c,81bd988a,3033e1db,abd9ee27,9a91a434,e7a76813,453e27c1,c23130f,c4b8990f,ee308443,1cbeff25,62963b1a,4a5acb4b,a1319b4e,d77c745b) +,S(1b5afdc6,4598bfee,4ef31904,f0d06796,17b0149d,ac19e7ef,a1d4f19b,c5385490,fcc0c62,47d96d4e,430ae0e9,c19dfa2a,3719e66c,ce25a2cf,d7428d4,4c91e96e) +,S(76da558b,d533e761,4d97b7bc,5a1a98d2,af043ce1,1f2b323,185377da,c0e0abf0,f8dfecd7,94b3d069,ec22f01d,8418bd90,27c3dfc0,62beb597,e352bb70,271d3cee) +,S(17f01b77,d2417d97,e3c14f10,18af67be,c12c31a3,58521f6d,203f101b,227cdbc0,fe16d66f,a194c800,e3c14bb3,f1df0a2e,3ec319a8,66c69d9b,3b492d96,327bba04) +,S(6010e0a1,2cacb745,6e3a8f73,d5219a87,cc14dae6,54be7265,ffbf70c8,c4d5433,7d5f0faa,579afe50,2541a2de,4d525bd4,e7b950fe,2b2dcdb8,d67d3d9a,7b11da54) +,S(91e938c8,3f319320,baa876fa,23773a7b,d0fb81f9,bf9d99bd,13180560,bfdfad6f,b662f401,7a4fa2ff,6603864d,77a6b930,181372f2,5fd6a67e,12a1df6b,f75509ee) +,S(de2ef2ee,633355c3,3d259357,efca96a0,5b669f13,b515e64a,c0bc467f,2abd665e,d3d6254c,5c30daf4,64843190,7c2a8c1a,51baeb23,13605a58,b88c9a78,a6147c73) +,S(186151f0,dc37e48b,3178bdaf,900e7bab,49cf251f,7a2a1b8a,76da8750,2dee93a6,2a240dc,acbbfc19,876c3680,fdbd7ee5,d1085b79,96317e4f,db73d5a1,9f097f8b) +,S(6f19619f,ace0c63c,4dda566a,9a1e78f,a9568db1,1c46f3e9,771756b2,7d8a5c1e,4716efed,7166e06,722a744a,af89d145,4ddd2f0,f7652862,cc38eb3a,2beb1925) +,S(a0e450d6,fb8a6da7,e8f6e62f,7a08c2c7,277a832b,4e5c6dd1,8cbed37c,37db23a2,775223c6,3f81b2be,1bdf0831,9ed65ab8,d3e11c56,38830851,d55a8893,730979d0) +,S(6337ffcc,64f5d358,d90fad1b,646d8d7,46e2fb7a,2a6cc378,9b55ec52,3824de5,98286287,578bfd97,4c161a01,55f9a2ef,707858e2,a32c3fc7,319416f8,5a6e5427) +,S(914a8565,cc1bcf80,19e1eef2,87c9467c,bc42faaf,726d4399,6485efe4,6f99e32f,846c42d3,b1dd8c20,3a744f5,560396e9,b9a92380,2fccffba,c6ee22c7,65bffde8) +,S(dd79a02e,2460ef86,cb4e9ba8,3ee7e231,e99b3303,1d4a6d7d,6dee8b1f,b0050daf,d6a75b67,ba13f76b,172ae0e7,d63b20be,db3e54f9,e54a96d2,aebc326a,131ea271) +,S(b2776e23,3e759f8e,38c52394,d50fe177,c6842acb,f238eb56,c7638549,174c1b2,e18c89b2,dbb6453f,7b610518,8bf090c,f0410e51,97885d52,b50b2507,ffe4dc81) +,S(e0716c4c,c5e84f7c,282adc42,f294a36b,56bb26a2,58cef4bc,c36a7f53,1d5283e1,1442ddf1,57491db5,1692c7ea,5c92976b,8a2488b6,6aa6f38f,7a62946b,a24fc5bf) +,S(2b10c9f1,bfdd659d,9d1e073b,faaa4b13,2a08b678,f757ef39,a137e53c,b291df70,7d22ac48,f4e0aa71,8cf7882a,57a46746,94e0f456,f2cc3aca,30a3f8d4,2b240dab) +,S(fa762181,26a4813e,e97f2718,c6eed96d,da9f6912,ac463af6,a52f3aff,f80f07e4,8c8a04b,f38e2599,4cfd8905,27ace017,e57e3f8d,d378b205,2e767954,80dd5701) +,S(6b893eef,bea81e30,7ece156a,e79abc26,d9f0ca5a,b2dbde11,bb0d8192,f138e58e,510a308b,9fc47167,f72bbc4,f92eebb9,88a6512a,b1679102,f9016b0b,d82c559d) +,S(6cd9b970,332f421d,1aba33e4,75f26a4c,5c5fec37,4a549ac6,d8c10fa6,cbc40032,b57dbee6,68bef693,67188a54,52e3b4d2,cf1c8c25,8e36bc09,432b4f4a,dcc24086) +,S(ba4847ad,40530fc5,f77ea79e,ef7a1c0b,821b5285,5ec4ab8e,d238ce46,48a09fa6,627ba437,8e0f2044,20e61431,5f3d110f,2da9cbe6,2025bbdc,5bc1cede,c36030c9) +,S(92837329,4f59a142,ba84f897,7acf2e7d,9df06a27,74ad88d8,98689900,3750c513,4e938012,b6e55d6b,6f7871ae,c34511c8,40912a1,1a32012f,3bdd27b7,90f86c37) +,S(470c19f7,9aeb9a7a,142ba010,10ea4929,3de57e25,68658d45,42b5a626,864600b9,2e99dcc4,b93d9a36,7544b842,ef4a3085,2e24bc41,e98ff2a2,d9aede05,da703225) +,S(2496996d,c38e4bbc,851f9bd,f9a21b42,5fc7ce2f,2b06993e,97604a0e,db555c34,b6e02a63,f0e2e54e,1cfb9d28,7607bae5,8a68ae6e,a8300ee1,c1170f0a,9e567323) +,S(92366ed3,23ded4df,f4029e42,685c51fb,a8a916d1,999c42c0,a90feb44,4112a78c,88dc8af5,f6d1d14c,5c09d216,8af0e752,3fad76a1,5b311021,7ead491c,12b63191) +,S(ff9760e1,ce161564,22c4962,4962d89c,37e66e64,cd7f8e94,4125fd00,c05974a8,8ca4457c,a5e52e23,d70639c,a9a26f3,12312451,8f0de070,86d385b6,777a63a8) +,S(50d1d5ad,79f919b3,d23c16b1,428d971,5deb186f,2b92b64e,7a1ea1fa,dfca4981,ddb07de,d4ad81b3,cfefe726,33521be1,c7418c5e,aa759440,20dfe92e,b4653ce4) +,S(4934f753,29844b23,80183df0,254d1c7d,342d7d27,9fa5e804,68dbee16,4e9c2c6e,a4f8aba6,7a488a33,40e8e943,14f7eed,5cc25487,5acbaedb,afecfc2d,5405609a) +,S(d7b99142,9cbdf755,5cadf030,7b2c4a91,c0d25710,a0553511,eac6afb4,c544ff81,17bf03a6,83b1a0f2,366b944c,aabe57d4,eac4d86f,bfabd006,66693983,e0241420) +,S(834b036c,145d6905,58199bc1,e7a7bfc2,4831417b,530b0b97,8cc1fc16,af00b966,4a45a9eb,299f24a0,1c520751,2cbee44c,bfb75d0d,14a7eb08,b1668b58,ae58c47d) +,S(d7a8c30b,fd7b8aaa,78dd23bb,86ef2624,5a363857,6ed69739,25ea9d9,194bfb3a,7b5f9ce6,380abb91,6e041388,13baaf24,229ece27,3541f4ca,2883ad77,9e501fa6) +,S(ea4c7ed2,7ced8b13,4a2ccb2d,3828d29f,f80c4825,e5607597,3faace04,d2fb7763,a8454c9c,be19ec44,8a3234ea,97b8fbb,b256a148,11ba0ede,becd8641,42684d14) +,S(a2cb70b,f80d9f6d,696ceaf8,fe8052bd,e59215a9,99d4b92c,ce806a19,71d555c,997bd94c,e5cb12ff,886c1cac,bd21c3c,e2f144f0,3af644a2,c2aaba2c,825f75b5) +,S(89a91f5,c7c8700,175ab017,8c4104f4,a927af06,f269645,36cb78d0,19f8b8f2,6a2f8ebf,e1258b4e,31bf9a5c,31c51a3f,1cb58aea,6e18582,3e87920c,3df8e7e9) +,S(27d7191a,71ecb0eb,71b43dfd,5840079c,bd368c0,5ce62fdf,2967dcca,78f5a6d6,11120002,d0d0fa9c,8db51506,4e1fcc2d,92d8fa9c,8b454294,bfd01c64,889d5e6) +,S(cefb996a,d36deffd,c3c7ddbb,11a5013b,70baa98c,1057adfb,185b4c9,62f3384a,c93cab46,7523b0d2,baef4425,c9ff048e,c586d4c8,69c69cff,3ab9d72e,e3d80f83) +,S(5a8ff765,84746f42,4e06b557,77986825,e91312c4,4f79003d,c1b381cd,4fe5ce8f,3946177c,3c741458,7bdb9506,85ad0c73,b422a8b2,5cc3ad3a,cd486e76,99a42f08) +,S(b179dac7,d2f400bc,bb039f32,91e813e6,f9a7331,80a1a5d0,db51aafb,af582fb6,89a70304,d70cbb61,ffb3a499,1815cb17,458404fe,e43f09bf,d630d480,5978b1dc) +,S(6e14a53f,ab32be84,4eb14242,a3b6a86e,e178cd7,51dbb7a2,b14cb763,ab2fe6de,a22ed4a6,d98c59d8,ca85e111,cce0efcc,60e20df9,6b06615d,69aa3cfb,206494b9) +,S(12ac42bf,d8f919d8,c79a8138,1aae69ef,b789a573,f58332b5,79694dfd,27e7ff20,4ebc3b7e,4b0136f5,19a8df5f,baa7ff59,17f4f632,f85ab1f2,ce502fee,bb3a3a87) +,S(87bf22af,5e9dc061,eabb01c4,eaa867c3,4656599e,da744da7,774fa8d9,aad68630,d34f530d,fbea0d52,9d2d64d1,323fa44a,d80cbe01,fa2806e5,ff069e6b,fc0ce729) +,S(33fe6bd7,ebe2b197,76251415,8bf866cf,b6d3ad5e,1f68519b,edb513fe,6076c96f,c5970cce,f44aa84e,f95a56eb,588b7a8e,d9164f5f,5a2eed83,1f70d308,2320e9e1) +,S(5fc2f44c,fc0f7ab9,9f03b67a,d7b6ee99,d73fa9cb,d74eb5ba,6d931d9e,26ba51af,8b1fbfe9,de201400,6c07da02,4bbcf53e,13bb9f2b,ff3dd6d9,5135a6fd,5842f0f0) +,S(38fb5cfb,e4f348cc,1fa7f9b2,ea600daa,e8330aca,53308f09,b6a7d8b8,5ca8a88b,ac1bf91b,7f53e824,d845c0f6,9534291f,cec2808f,95acf58e,4afba07c,fc735be9) +,S(3ec2457f,fc848504,6f74912b,5c58b270,1be6eeb6,f88da0b3,c5cc4454,48750875,b63209d2,641c65bb,7105af10,61d7513e,409f153e,5d1b5073,232eacc6,f76dde22) +,S(32fe812,e67ef62c,687d248f,e75ef399,48fe8ae4,a01ae10d,ed65264b,fb5050fb,d9c85369,db22ddeb,baf7682f,53642962,cfec2afd,3a20de77,588e7473,18044f6f) +,S(97d7c69b,2aa0277d,2b20e9c7,bb1066a2,be6f443f,d0a428b6,d78c5fc9,6ff71b57,f84ba781,70837aa1,f75936cb,fc50c444,c40c9fa3,22d90088,ac6889f7,e7c0f861) +,S(3621a4af,4d698e4b,60e7f497,6e0c10e9,ca32834f,ff917aa0,6aff912b,2ad80cd,22cfd248,a17886a,ae5d0e11,53621e9b,46289acc,ecd8155,a1bd6372,120c4da7) +,S(ae79a6e5,848b1dc6,cb64958e,87b737c1,858442b3,63d4a2,e9f04561,7d73f8c7,c147238c,59885f2d,dc5dec63,de421eb1,c5a19438,ed0600b3,4c77f4e0,e7aa557a) +,S(36eec623,700e51e7,723a632a,55370ddd,d6b1f917,6ea39a2e,54a2a1ac,52598c35,29698c0e,56b4e2b5,5389dd9c,3d8b509a,e0b87f99,4872d865,3fc74269,7f5bb7c) +,S(50f70061,804dbeab,cf2ab4a9,87ebde2,1f5496c9,a4cd28a,4dd9da7b,310e876f,77e27710,edf831db,6ba9e64c,545f03a7,eb390842,8d9cfa3,3d0e1c87,61371706) +,S(c2ad6b2d,e84bf60,7fe77b8f,a9fe26ff,bb5e1906,1494e469,8da44a33,25843844,17b92ad9,d3938fef,7a17f543,a169a7ad,8ee65dce,36eeedfb,5e3c0c8e,a1b24fc3) +,S(a53504f,e2286269,427fd2fc,fcb64827,bdefdfd9,feb89d50,12651d2d,c60ae99e,6b9d73e7,e046d11d,ce78b114,8aea837f,770d8267,6642dac8,f3b3c035,c10eab45) +,S(5410db61,40a77b31,9f19c969,34a8364a,4881ab60,ad76a6c9,34f317c1,1b658dec,ac45bb6e,2e5fe23d,57297370,cd04ffdd,dd89a9,15a1e9ad,15d7f9e7,6d8b3aeb) +,S(882cbd69,fbd3e262,5093385e,ab82fc9e,7597c38e,45fa5df7,f98c94a9,3bf25467,2083f00,b25b28b7,f92b040d,a4294dc0,8a3d97e3,d951e724,da0e692a,5737a87a) +,S(3141e0d1,22b4c136,f7793c73,9c48f308,c5ec8043,19db116d,64eb14f5,aee83942,9c2d06cc,d765c6c3,cee09b70,247f8806,227d0178,13becbb6,96c5a344,b68b33b1) +,S(1b2f3686,5a63df41,65caea4e,305d8d66,1de6ccc1,c2a28cf5,2373527e,27cecfc,1239d8c8,d60fdcb9,fcf3f5d4,63305037,6d47fd97,4cd6bc64,99e0e951,2d2209a9) +,S(725168cd,9fd59e41,14918b77,6ea96fc9,6315b4f0,86672dac,1eaf59a5,e61ed25f,946f03a9,84a6735d,e72acb38,dfd21905,fa2358a5,e66e7b0a,2f8836a1,8f5d73c3) +,S(4207faa5,c9dc9622,9644df1b,a099a84d,654ec6d2,aa69efcd,a4a31a3c,61f2e1d4,ea72a92,836d1597,5275c18a,900c0e7d,d0502610,d97b6f79,1f6a28c2,1b3ddfd7) +,S(53900d38,a4740830,a6129a11,9dc90f6d,30f32847,708d48d4,20b77764,ff5b9cc7,66822ed6,ed941eb2,20aefe94,4325daa7,a619dfed,5c76bf75,1fc25342,8178d3fa) +,S(d0204932,a3fb8d33,9779851c,d69f6adf,be1a9957,59fcfce1,b8d4f047,e4e4dd2,8ded18ff,bbfc663a,9c658ae9,286f82e0,9ee9381b,3291f5c9,efabf0d5,fae318f) +,S(3ed8ce15,2d34e621,94b8b16d,55605766,41fb2673,14a08c91,d916fa14,f21abde5,48490fe3,9769c60e,38996370,27b57df7,230060c,2505f414,5a1c7f1,4ba16660) +,S(b7d57614,9b5e2ce5,edef3c30,b8cce79e,6f122c70,351d04fc,ed2b67c7,f5cb2aed,7c8fc1c6,bd42b25d,d45e37c2,5cb06f0a,bd2f7051,4a50e6e1,2a67c0b5,b199eda1) +,S(2489e06c,c8f0bfed,9d5ea722,c07ca795,e9ab40e5,45b036e0,f0c11f28,53c0d35c,dff65f5c,20766078,9737f1fd,5af05ce8,3b8edf91,37002b19,f5e1599a,e76c48bd) +,S(9b2140e5,509817c4,465e6689,a3bdadcf,b79c1803,883d493d,4e4e99cd,55f30a29,86374501,705fabc6,62e8c869,a22d2813,f7106006,ee09b6bd,b582b690,50186688) +,S(48d6fff7,d5c37c30,11c9e63b,b3342f92,776060a6,dd179e3a,e2c6bb69,d2f88b3e,783353e,adb6daec,536d37dc,76ae3ff,8dce14d9,65d21d3b,7a17515d,7d3341aa) +,S(35d46a17,b6951355,a055e253,42b4244d,8ce65459,c630f2fd,4708687b,e6a49e7d,13bc21d5,7cc2954,62927cf8,bc31ef3b,5407021a,62c5253a,5950e8eb,b9c735d7) +,S(17ba438,24168f06,274b2f5a,d080fda2,3c0dc34b,f77e81c3,c4413cd2,f594575d,e8b34f9,1ef09f92,7b5d9e51,662216a1,30ef8f87,2e0febe,3f5cce8b,318fc77a) +,S(2a09e4bb,4f6d6b40,f59d0299,93eeea7c,755eb00a,5eba0477,3fc0c796,aee68a07,cbe72772,e5d8b761,15ed6f92,f20028b7,cd06aea6,74e10667,899e78a3,df403f0e) +,S(f3838250,e9a03da6,87139583,2bc6b35c,2d427b60,4cb7d25b,149b6816,235b0e4c,164b211a,60562190,d415bcc3,87d1a147,66e45f14,dfbeda44,833ce45f,b815598e) +,S(b307de85,c4c2e8,4e076d19,647bd205,8c1a3c96,a0261481,322e73f9,f4a2e94f,5af7f6f5,ae7f65cb,b62f021,608473e6,b68d032b,4835540a,f265049a,e506b2d8) +,S(ff92c7ba,5f89d3d4,5273688,907ab9bb,794e5622,f8f300fc,804934d3,b5820e00,3b2e2d1c,420fafaa,e53c9da4,957e22b2,bc76ccbd,99f323d,763fa1ef,f92ea71a) +,S(49630ee0,a8ddf91d,ea678a3e,1dcb623c,688b7c3b,9e39196c,b578d30e,196e63b0,4c1aa073,d1375475,11d81776,e2e59404,aa08db5f,95b80e56,c39613be,fc2bfcdb) +,S(d41ead31,f2fac884,e762ccac,85825cbc,6ab2f8df,a069b2f3,fce3c6f3,d5c95a33,f15e3e23,e19baea5,677390cb,acf97180,86876f96,50fac740,9b6e62f8,b6d40652) +,S(5e62e95d,27ba07d0,781ad685,75a7a11d,df9f2776,48cb5cb0,869ba586,6ff02869,291717d,1a1ff532,e92f0311,881fe2d1,6c8844a,6f5ad7f3,b1ced51,e5088302) +,S(dbdd4f57,1f6d01cc,8a1025ce,3b92ce3d,56d396d9,635e456a,fd856239,27b53bd5,b929d5dd,816bcdd7,78abd34b,c15f2fb9,deff3f9a,aa44de0b,9f7b46d8,b8d70373) +,S(63a8349e,1a891037,9a74a60,babb68a1,4c8cda6f,c2cbc0e2,1a5aca7a,fff7a19f,38858c42,9cfb1e49,5fc90633,ce07abf5,b7c4a4fa,22b955ef,e2c137df,143ec70b) +,S(1805ec70,2cbb1e4a,5da4841e,9e24afcf,b84a3e45,dd6c39a6,cdb6a661,d5c6b1af,193be01d,d3f28479,e352f164,de99d21d,1b3fe8c4,b0af8587,8f21c858,cdadc27) +,S(2d6ff24d,fcfeddca,ab3b19ec,b6a79793,7f5c5d3d,373b9df0,6ec68549,6d075423,b8bbca01,551b2b3e,f6ec3a37,ff020f3b,6b1f5456,69bd8b90,f8a55216,3fb48fb6) +,S(3aa21099,52cf0464,4bfe5de8,69cb2d4a,19d3c4c4,661d6782,967dad8d,cc353a24,68252574,69dd7940,fbdd26a2,483149f0,f71a4b12,fd25b063,73765c52,d45985af) +,S(d6422a71,443b0e37,cbc06f90,4ba1f62d,c2351b7f,e4e0b909,5fc227a1,7f8f551c,ca92a69d,2c9aa758,46c2518,f1ae03c0,d7138170,447b55d9,37108604,f71b9feb) +,S(51e297bc,46529246,a36f8460,f285d713,b1e9ed67,2027eb35,37806d5c,7e756177,5d56e447,63bde166,b456531d,94be0d,7057081b,edbbb89c,be8c4732,13eb0ad9) +,S(378a552f,c061e796,c9ddd101,63851ea0,663f09f1,3fdf852b,ddbafd7b,bf6c258a,6396c9f2,a26b62c6,f33b73fd,98824958,8cbc7c10,e679bd4e,ea0f4ab1,dbf38f72) +,S(bd85fb00,1db4f2fe,95c61f1e,825e65c3,80761832,37be8a86,a20f6fc0,7a586daa,52c21cd8,9bf874ab,7d7e0f4c,d0095d7,6e8c737b,e2ba9d1,a21fb795,d968f61f) +,S(fe68e6ec,3c8e681c,e7230a92,e8762f0,af3e206f,f3b0afe8,be61ab34,2ca076b3,f8683d06,af0c88f6,93a0a6b3,1200cd25,ea2c7e9d,2b8048f8,b983474b,b1dc20fc) +,S(83e55d38,bbe2daa9,f8147b1e,674be115,d919445f,70d2b3a6,cb917a4a,9ff284d1,92d6c7f6,dbbcdee5,8b11a244,34cbe7c,9f9fc0dd,c93f6fa8,b6354a06,5bf90ab7) +,S(fc9cbaca,ed0e1df5,e9d8120,6bb55f26,67e114e7,30347030,8b333554,d0735ad0,d41fc02f,2d4b3f74,f4e9ec00,7a879540,54d12fc9,3d53242c,a45bd38,c75deb9e) +,S(7adf7a3d,12268d0f,c2568d5b,ee296d61,fafcd739,f081e5a1,7b39fe7,40132b05,51aeb855,a84f377b,899392c8,a7daa18b,70ec2a94,7929c93c,67ed8217,41adaa21) +,S(e9631ea3,7da9e68f,eb61f9c5,6eb91bb0,2fdb4d58,d99874c5,2c4af40f,9716aa0c,51d5a6ea,1a5fffae,39c598f0,158272ec,bdb48c4d,faa93da3,89af20a7,d2a1b8d3) +,S(e892f70d,15639bdd,ab70739e,83ab9f04,963e1dff,e2bd81eb,e075173e,6bdd116,2e78cfa8,30b68c55,68f635f1,b260d823,55f38ed3,f5f43c33,b178be12,dc006b4b) +,S(6f3ef2e1,e8d4fd02,2533f4d7,410778c6,ccd9a7be,aaeb3c8d,d9f01699,89598def,c4388130,c278f8f2,7a9947ed,4948f8e4,febe81bb,88bf873d,2d565b4e,3481b86) +,S(cf24cd64,84b07e12,37640f0e,da7e776e,3d4db192,6da8e929,19b36383,15de412e,a353cd6f,a796c46c,49f34c72,64d36df8,6d53f556,a36f430f,7f3f6ac9,3527ca7f) +,S(a2e98e5,36d517d6,528d6353,8bc2be93,4eeae1c1,cd8dcec7,a60080d3,fed33749,205e752c,49a09b0c,8804cba0,62b28ec4,6d9e8f37,9cbcacd4,a7cc9049,47bfb296) +,S(e5ef194,498445cb,718f7c77,6aecd0f1,949a4a49,73e32ce9,a4915867,dc27139c,fc774f2e,1e51f03e,71e637a4,158a0013,5aef5a18,b15ef0b1,e5696338,82bb513b) +,S(311b36a7,1a1d13b8,29c78813,6a989c0e,1b7039d4,d75110b6,ba97f000,749a8d06,2f441c15,6b80f4d,51dce0d9,bceca566,2f3fdd9b,965a0d84,55f6d154,3a661f7f) +,S(324420fb,a5076214,9be852e5,ffb88d20,d1120e1d,2eb9c132,32bdb13f,403a5f6c,378f5d4,1dc1011d,1fd338d,b6073df8,903fb4c1,e17b2122,bdad5eaa,496965b) +,S(7cf4998f,5095c102,a0db72bf,9935ca91,eac814c5,4120eb0a,262f246e,ede142d4,73e6db13,d6db9486,fc870698,7be096f7,7440dd35,67064888,e61dfeea,e98c1fb3) +,S(d6fe26df,d501241b,f8c5e74f,e30714da,7d690be0,91cfbe14,68ed6bbe,23598f7a,102c4907,60fed9b7,239c0443,d01f2742,fed0a0f0,fd7ab9f6,9fb1c58d,c5752fe7) +,S(805ee58e,66ab8020,c9c32afd,4c7fe30e,960f4c3,ae51e94e,da9e5242,af09c6f,19154d86,59fb1837,3d0adf6,daedcfc8,3937af0b,ef9a7d15,f990f60a,c5457617) +,S(491717b1,f22f93ba,d0a3cce4,fac57160,8ad7a746,ba73d375,1713e605,8bcd8450,9c38b3e5,4c89d38a,2307546f,f46bbd68,d4e4ad08,cc45bcc1,575fd120,acdacaff) +,S(a8e23e38,27c54d4f,ae2589ba,cf3c4e1,93f97e59,b11506f2,2016fbe,a9fc2522,ffaa8b74,22b50822,dadd781f,d31b5a31,eb384c50,2fa0bc2,89252665,1c602f3e) +,S(9fee31c6,88b0f7f7,78a39786,a84567e8,34da7ffb,350cfdc8,95d65c4a,afdf69c4,2116e31c,2a0d25f6,48a3ab47,1c897484,d71dd9e5,c678af4a,292a6388,d9e45e94) +,S(6256ced3,f08f1812,ca7ad618,383f1542,baa2bb06,332d4c1f,72d862c2,318854e9,9ae0bbd9,d2fd51d2,9347aa62,12b6c0ca,be530b55,bfd8cf18,6732be1e,c66ced06) +,S(ca1cf364,a5e1f47e,cd0ab0e7,52e785fd,935b8c37,964c5654,2cfb3249,a136d669,17412d75,2f350795,30db27a1,7394c362,45fa376e,d20583fe,b9f7a7a1,2c3b67f3) +,S(19004a4b,28e5352c,7c74def,cf129ca1,cb5c7dc1,5099b37f,dfdb0d5d,1e694400,68ed1edb,9ac650b2,965a4034,2812a692,23b3cf6f,24ab0a05,2e1b8eba,f7335020) +,S(c605e97f,27199d86,18fca176,54e44c9c,8dd20994,aeae0466,dbdbbf0e,ffd1b3c0,606955ce,33ff7b6a,cc6de4bc,4ef80b34,bdf6ea17,b29dada,4ee54f06,f61e9d22) +,S(3e89970f,15e79b51,fba90202,a16da6ec,3d3d5d53,72218d72,bbed0626,31affdfe,5d9e27d0,bdefa8cb,b02ca682,a062ccb0,61a8fc47,b2cc72a3,9b687b45,5f83182e) +,S(c077c861,575ab0d2,944f8e65,8a9dbe54,9fc1172c,6b7b7428,476af472,e625d5cc,c01e7abf,6a3abe2,d2aa2457,76068afd,9ba78fb4,fa39e531,8155597a,90fededc) +,S(8567c87d,c12f1479,5f351d1c,807604c6,636c670e,11edb286,92552ab,382ddaa5,71f0be2a,12ebee63,8a63e848,fc4d8116,e2dcbf99,ecdb15ae,1f4ec6c,84f359ff) +,S(9f1b7785,7421626f,87978ee1,780d0,1e9d0b28,df34c2ad,15332b8a,d94d8dfd,6df504cf,66144d9d,ed530e2a,1436a4df,634a84c6,9de752d8,42e076c9,1f129b8e) +,S(f45c2c6a,2754fc31,c5770e3d,38b19e72,47b0dd1e,5ade8ed1,f2f3219,ea7accce,ee07ec18,8190ce54,e736ffd2,912075a1,128d24d9,b178a7ee,72aeb6e4,9b593f4f) +,S(51a5441a,f3446fb4,cc63ece6,c9650a87,2fa5567c,4918f5b4,ec8668c4,ddba6e0d,413186bb,adad4943,6abc46e9,280a1571,a97ed7f2,a839cad2,935675b9,d167a54a) +,S(adee3e1a,e9a2ab1b,da34fd5f,afd3b3e4,f51255f3,5dbd94c6,8efb994d,afdeeade,f330f0cb,973fd732,eda39ebb,82dcc589,4c148165,428adfa3,b4ff865,1ea83e24) +,S(a8946504,eb084214,d0153ac9,c3437fe7,3ff5696,16e01672,413a62ee,27c97db5,3dd63d46,f74a56c7,2cd5d45b,5bd6f2a8,d913300f,b4ce536a,e504d4b1,b2e311dd) +,S(e34ce586,990e48c5,febc2fd4,70770cf0,4c81c782,3702cb5f,289be0,f4a97205,d1774a35,cdd7cc54,dc68827e,f7c723d7,5c167982,c314dc62,bba17478,611f5854) +,S(7a8a5d9c,edbc4c76,1fdf2958,8289bea,d524edd4,f7cad978,deaeca8a,de47435,559d473f,3a9a7ee3,4ee0a1d0,4acdffc5,6766db36,94fbf08a,5ccef8cf,31e25b6) +,S(848cd57c,62c67249,d84710a1,5c7abc27,93fcba46,497a6b0e,b23c2ad,f8acaac8,a48424a9,59922131,31a763ed,30369b72,b331d9f0,cf46f8a2,a15515ed,6726f735) +,S(6afbce14,1f2d2c4a,c52e7e05,5ba6ea60,7612a590,d74a2a5c,1344cd5b,c49f2f03,910d69d1,cce10aca,bb1593be,2d4d4d28,9745f97a,29fb78a2,a1eb6f0c,a58e4b61) +,S(61f3727d,718644a9,2e08ab04,814c4446,c5dfae82,c26540cb,44fbd310,a5315a11,56665e3,ee6edadd,a154563b,11fdc203,fe4365d1,ac36879f,a30778c2,badab836) +,S(582962de,e00668e7,91741dda,8e86ddb7,b8ff7773,ac1ea51d,1aac139e,a810f3d1,6bd353b2,e004d66,f1e90cc0,7c68a0a5,b532e709,75a7bc58,7a6b1c67,71022f6c) +,S(5c4426f9,f6071fde,a9304e6a,4a2374a2,e2591225,28b62d20,5fc3016,c471b636,ff6e8c71,fccddb0b,5cff9e2a,10c606e7,c571245e,8f5bb5f7,77e0a7d9,733560a1) +,S(ee02633f,c6b41f01,c3c24c33,719db7fd,a9e04b1f,7070395f,e8898a0,efbf6af3,ecdab00c,83cb3465,1d48a696,6a8e4f03,ebecfba6,f73a66ec,4d62a668,48f14798) +,S(fab36b80,e5bba465,63c9078b,b727e0af,c9bb0af0,2e394f9f,2c90e0e,fe9fb816,75173a7f,f5599da0,ab84519,c7c25be4,1f10172f,fea39762,8e7dab7a,3ecbcfa0) +,S(68a89a2,62015a57,5f882215,48c6d3a7,b4ad1f92,f5665980,367107a9,f4cc37a,43ea7b7a,79397dea,c8354436,d53e7731,c94773d1,5b067063,b108c559,c05bc46f) +,S(fa6e2972,87a0e97c,35454378,4a76fb0b,56106727,136474d8,a3edf8b4,e03f95f4,1e80751f,9c127fff,ce28ae,8ce5afe2,eea1c566,fb0a9f20,8030cc96,e1197725) +,S(25474cb7,805d22f8,7a641116,34628321,f086d1a0,40404c47,ebee913c,e9e02a6,2b3aac5c,85ce9672,61757c61,d6a72dd,4ff81e00,87f0b8a4,999b927c,7b069609) +,S(6f7051ef,10fc1485,a9c80ae0,8683397d,c0af15b5,f78fec70,fe4c456f,f33b6689,625086ce,ab7a9173,d9c370c4,c336c63d,2aa85ac7,b8391993,7ffe4118,f6a7b849) +,S(f4720462,2f579de0,701f1e90,558c74b4,ab634664,197c03ed,a85b0fe4,50df4951,c66a490f,f9b588c9,2d17b80f,7f66e5fc,a65187b6,d965e81b,c16039f4,477fdb54) +,S(3b718764,7e722fa3,de42fca9,e3ba181e,de982728,5b8b006b,d51a58e5,ed898c8,bf872047,f3cd3ea,d7a439b,9d4f7776,7175f940,d6cae8fc,930aece7,e1b92202) +,S(5255ba09,df1e199,4c99bf21,709849a1,cd7c4f58,a283e344,6b98872d,a416c40f,a1099eee,e3ad10d9,6bce7a58,839fcaee,1b43e0fb,29ac0300,4e0eb15c,63d1f604) +,S(f4b64a08,16dfe224,595d3a15,8173df8a,7d941a4e,968ac02c,bf87d9d8,93954805,e5585209,2d0cf600,b8b2342a,8371894,f422e3b6,68ec4078,2379a60e,944228ee) +,S(236d83ad,b789d7df,5fde69cd,86d45d5c,f20c5867,b7f2b398,b9373960,b22b29ab,9758044,d3e06295,e33bebaa,befc5776,5db45475,b3aab963,5fea8dd6,77a478cc) +,S(42071659,65af2fda,c9e87319,6dd0c723,e7d61bf9,b71e5e70,667c9858,6371f3f2,fddfce02,588c1d4a,b744301c,6117e504,8f9c2636,5ccafafc,8a6e19a1,ea7b1b37) +,S(7d0c2917,aaa71cf2,e79f1041,5e5e583,ff01b24b,65f1f409,240f794b,d346a452,1e857dbc,c86c1032,e748d8e7,c8f5839d,57295223,22e6bdb6,187b00f1,f489576e) +,S(f0609605,d6e39141,e5e4f0e0,6bb6d55b,9ea2ced0,6a58d4e1,7c46a3df,18257255,e6d54c0b,10826de6,e95553ac,e4689fa4,cb03b959,65472e65,a085988b,d045374c) +,S(86e66299,819b0807,af30c89,228447f3,71fad56b,75f238b5,30bef3e0,b1123204,de635715,b1997f4e,c367bcf2,8f8def4,7a7a2069,3a555b5,396dbe4d,19b1e8ff) +,S(7710dc40,f72bb934,f5f9328a,1284efbf,fad3518a,70c2a0a4,55028bb3,a8b87e9f,d2ebdd39,7dd91ec3,7ffcd8d1,a9b412c1,78f6d228,5e099162,76f9e8f4,a6a28e02) +,S(3d377c80,25607e9a,fd512e8e,7c37a2f2,8d316701,dff7f318,eb24cc34,348d935f,20d2d95a,e8503a11,de19db36,5bb62213,6cd55735,966c25cb,2a56f07f,19cb2664) +,S(812a4ad0,d004003e,fb190ea9,336659d9,7b7d6df0,29f29f97,bc9c8d68,f284a696,6303a024,b2d95d18,f04fa94c,df3d0749,60ed45df,584e16ca,d60a0843,551f94e7) +,S(51cb80b1,9c0dc55a,888421e2,411baddf,6c0eb167,ed9bd04d,294623ed,1bb61dad,d14f756b,f905da5b,6466bc6b,26685501,1fc90892,93633c74,479afacb,c34559f5) +,S(837afe72,82af09de,108711a7,998dd45c,36654f3d,a3cb392d,c46bee0a,b43cfc8d,88b0ae50,5c30a2b5,72c0f69,8e7ecfea,87ea1253,ec133fe7,fb2aff9f,6adc2e15) +,S(ab967cb8,463da438,ad360a8b,3e066669,231fbd,cd590904,fe827ecd,dff3cca7,d82043ef,c614db53,8d06f6d9,9fae98e1,ee6f5065,31b05822,ed2141f3,25ebe544) +,S(5a0b6177,50d828ab,fbf4fbca,576ff8ff,5bd19330,bd357eaa,a5564e39,c718eb49,f6e8d743,e528429c,2cacc478,368d7226,823a45bf,358d9128,9da334b8,5a1b4426) +,S(351b4334,83fae045,ce964f04,f63af62a,6964e0b3,5c1444ca,68d09edc,9a43c9ea,f571f442,7b308ac4,83bfdb4e,87987455,a2a49f77,73220511,dfedc616,20bc18a) +,S(fe64fb54,727ce446,c00dc3cd,5de496e8,2d5a0e9,b13a9a7b,99a96a49,2d0d288d,452c4c9,aee35675,33ce8cbb,e444590e,f5756f14,33865ba0,efd00c4d,26db7d8d) +,S(9403ea3c,773544f4,4eae3cb8,91457ac,89b11f1b,66c3c397,aea8d816,ccab1d49,46ec1e05,d13b40a5,f21ce743,b2ac9756,8ba98b2,8fe1443b,3b0c9cc8,f8a49deb) +,S(e81a5512,2af7093b,b361ab58,534df80f,dac734d,7a863ad1,b080d691,c4396dde,fb33ea54,fbc0c05,f9854f1c,49cfabe,90e259ce,9aafae3,353e8f51,594d49f8) +,S(b7511df8,fccf50c8,192dc3cc,bd79985b,15eaa528,89c4d01a,e21767e3,96bec9ee,c937db57,ddcf0997,aec742e9,cd522c10,d4a52b27,b50104e7,b59c441e,3d0fad4a) +,S(5625f122,4406dbff,a818d98,1e88b5d4,80039f5b,415acc20,ae69ae7a,704dead4,aed9f73d,5265c976,760d094c,e9ced8dd,722122cd,e0b1b34,a8296fb1,dccacfe7) +,S(1b89696,dca54369,27bcf0a5,de32ff1e,e79f6ea5,6f6ffeaa,bce6190e,bc7e2c8a,52bdf0c7,52cc3e5b,1cb9b5df,adccaca7,929046b,bb67daf3,10ba793d,9369b358) +,S(4ef2516d,796d1c0d,9baa8491,7c2db149,e7b89f61,a8f8fb95,e14116bd,473d730d,9a0063bd,6e25255a,70479159,d3089a75,834e54a0,a28c5c61,ea3c33a8,7ab20969) +,S(b36c8db5,51fabcb0,c3fa59e5,9faefed0,1a53b4d,5470ce15,937c889a,a93faecc,1be63f1e,7f85bfe7,2e782cd8,22776567,e3b58794,5f37e2d6,b137da7d,42c8cc10) +,S(7db8ebbb,88c7c04b,fed18b7e,1830df41,490028a2,2918098a,9b34b8eb,c110457b,73fe3f91,f0f8a43c,490f4cbb,f8bab5b,9a6569b9,22a69e9,93ab910c,520fa9c2) +,S(47bb0b5c,c207ef1a,db28a389,7606661d,e5d4c740,3b2858f3,209b7dc0,cac3021f,150e2ce4,44f541ff,7883cf31,79befa4f,5df9c3e1,9da098f2,1d73c37d,1ca48b16) +,S(7803d64,d7622ab8,70a8b927,74e012c6,ab97fad8,4bedfc7b,ac4ce6a,74dad4e6,2662e4c6,1a60a1ff,5485bb34,c1d41d29,3a09a69f,7fe8a049,95245e2a,7770cbe0) +,S(61a64d4a,9a801549,4fa670f8,85988b67,7d317b9f,9b75e3eb,fc6d734e,fe3d3aa4,ff25af65,16e639b2,b6b0dd56,c0e12610,b1b00c3f,d8c59cf1,3fbb1b74,6282d91d) +,S(f2de8cdc,ce609b80,af8b34ca,1c1166c4,3ae0ab9b,e742b510,2ecdd5d,2e94307,d624709e,79346b3e,81b98871,84bf252,949c7f21,861fe6f6,666ef5e7,18ec5be8) +,S(8c740f9f,386f5a0a,228ea52,18a43461,142f744f,87511e9,67080dd0,f3c65d2a,a641bdc8,ae1d4051,a15b1083,27581bf0,22e92b26,a5bbd186,86fb4e59,79f7cd06) +,S(b15a4b19,17448b75,df927416,2795eb5f,60cdb4f0,e657afa9,989e5133,646ae240,e09f731a,226189fb,429c76cf,1ed9fe62,2c148475,92f26b50,c2c45344,ddc73370) +,S(44a65d90,26bbdbc9,89b0dbfb,aa645860,d7a15652,5286a9e8,c67b5a3c,e2dde08b,f2f23e44,bb6cd570,f58ec2b7,b90eb66c,30775109,81279b50,2fc90762,3f12b52b) +,S(60bc8123,92f1e7a2,4eafd5f8,ca0d8fe9,c5880133,209f17d8,6b95cdb2,c9df479a,4d39ae61,cf4368ef,279231ca,b72be100,cfee501a,da7c873c,3db18742,82076a98) +,S(ad5b9079,36391697,61edf9bb,6ed7ae2b,f7e852d4,bae22afd,655a5ed5,754f3618,bdb40449,723089b,ad8221c0,8a46824e,cefe4899,d5e073fd,8606524e,a81a35e3) +,S(c8166cf6,97edc986,6f824df3,82a515f,68ef5d13,dba7e0d,43e85727,c6e15911,86804e47,8118c092,3ab97ef1,ab9dac34,2bc48c7e,3fe24e6c,fbaa74a2,2390f4d6) +,S(3e0a96a,94dcdcb2,9f0df535,970146d9,7f0fd71d,7a4196ed,cd626903,aafbff06,5f6eda99,4651016b,86d28c9b,39efdb4a,b8ad08a8,5c87b230,eaf7ba70,6062a8ce) +,S(e72351db,dcab669a,f1df2767,f5e5f05,ca80608e,29ac5f09,b1ff76ad,43178a5a,552249f7,7a8b3462,c9a268f0,fee20713,5cc14ccb,15914be9,2cd16d99,b2520af1) +,S(a08e1278,71ec784c,4f80099b,5d83c5f0,91978e38,7b0b37e1,f4622c15,80fea335,48e6aef5,349f25d7,40ffc9c2,5de543c8,7e0553f0,54990aef,fec51f0a,9b3585a) +,S(ffb6f3d7,92596141,f7d15157,d1a42bb9,e9b51e21,61a8e297,5aa05688,ba67617d,aea9ba56,8aa7cd30,b9940c75,29cc1e7a,dd60a5b6,8911498b,9fff470,bc4453df) +,S(9c644072,318933ab,4d1459b1,d684c066,d3df3371,d7659a82,fd396bdc,a9fc9e,a115ce28,5a7d9bed,a2a962db,5041cace,9d3b2a3a,12149b05,ddbae7de,30cf52c3) +,S(5cd3475d,8a6fee1f,a6e3800e,911de939,a7568762,4f0a6e69,26ea6160,4ddec04,20063702,1d1d525a,f250876c,c4b49590,9ca8b39d,74603979,8c8b4b39,fa07c17f) +,S(28519616,c035ec81,4e851ef5,191e0545,5f0bbb57,12fcacf3,2b36de77,1c351f88,42ed56f5,5c51953a,6a367398,815963e2,64363681,f9a0723e,7b622784,5cc939c1) +,S(a4e11f70,b3554f05,d0634209,86549001,53d2ed50,1f09f787,99b83308,4dc894b,331b9d59,4260e0fe,381176a7,1873a66d,a7a3b9f6,2a930e0f,696f68c8,6939755d) +,S(c5d7c22d,7a8cc553,7ed85a85,46adde7e,ebddff6a,f7e8a6c9,96f50df4,248a4ddc,dd4749ec,bc029503,1106812a,cee59bb7,acf41451,45883a71,3256912f,be9ee03b) +,S(b56ad6a5,c6fab0,934257f2,9e266052,cdba0bc7,8c8aded9,f0e08490,71770c7e,6aaa84a8,99a4f8f6,3ca8dee1,6df7c090,264e644,de1e58e0,49f99fb5,fd5f4c34) +,S(16c4dbde,37e8df54,aff88810,678f4707,310f29b6,e9e5fba0,384220b8,4f0dec11,4fbdd92d,56a3f76,56b4dcfd,8be6b589,eb02c645,8a247c9d,264fb65e,c84a3a3b) +,S(15e63d71,f02f6bd8,1899f95b,d3051871,84b68d93,6a2ac10a,d29c39c8,d5ba9748,20204657,ae0e1078,6df04a71,938055c,ae208105,ef1beeff,663d8cc1,df478ed8) +,S(3c07006b,8a1e1fe6,fcbc3a6f,fbb7a780,a0008ed,513c9967,853a8cd2,5827dcc9,b2fe428,d4c8d974,72066ca5,ddf32e99,18b5e79a,e81fd6c5,e00b8142,566ce904) +,S(c7f2ddf3,b3dcfa04,91846f0f,2341b1c7,81ce2cd6,ec20acf9,a304fa5a,7dbe73ab,595d0b02,faae2b6c,f6e84bfe,1183ab9e,dcfd6c9f,411d7125,dafbf9d6,60ec5d01) +,S(4c239c01,c05d9c11,3d25dad3,3d14ab28,f94742d6,8c9c748f,1773b739,445bb643,dab0d447,de6a8c79,6809563b,e77c89e7,956f6c9b,ed930d18,f25696a2,e436ebf4) +,S(9e1a100a,c44c33ca,543ae407,f98fef31,28bd1755,6a16e5a7,c1390792,187fac5,540a4e2e,9864a32e,3eedd96a,bb08fe11,b499a551,497e0c83,cdba140,3b303821) +,S(c3b4d7e1,bf3485e4,d028e424,81608ab3,9fe37649,de75733d,78f725f3,63255d18,8f8b00c0,2210cd63,c04f07a1,e10b1a50,f05ad863,b8cbbbff,9b73c84e,c59b5ab6) +,S(dc226233,8dadc96e,5feebb65,b290ceca,f8f5bcf3,e1794f9f,6ade4eaa,b89f3372,25bebe7,cae8b7e8,d755862f,dbb929cb,872e1c88,6b7d03cd,b32303a3,b8b5ab9d) +,S(184b11c0,a52865a4,5f530101,24cb353,dfbc2d26,bdb3af35,d5f029e,6bfe53c9,237a79d,b53bcada,f0a96804,d8072832,4f59f03e,1dc7a76d,ac5fcd01,3838b110) +,S(4ab97ea3,943e8157,3cfaa8ca,680252f6,577ff2a,a93178e1,e1a3dcee,242b460c,b8a6293d,f316c9f1,5fb8850a,87bce47,27d2a38a,d1f5f63a,39d08c92,e9d6d242) +,S(a531936,799791f3,cfc8bc58,4a2967ea,66328c66,98ebad8b,5e5fe8ad,8cd025b,c24d6ae0,8fac8028,a3e0e079,426b94ee,2ca7c845,8efffe1,58f6cb2b,c9046c3) +,S(37cc3686,a6e75e4c,8d7375a9,f291ccaa,937c833,f9e16d77,2591e74c,787b1f7f,557c1bb0,a7c7ed52,93e44cd3,75b04a47,7788181b,b20dc1f1,f6704c10,5a8e399c) +,S(94fab00a,9418e31a,9a229706,112f9386,d537bff,f5f0c4f1,b241c475,4d7336ed,14bced66,1c6eb134,7684cf29,6a303e0f,fa5abc38,ad569011,c09cbfb7,8316540d) +,S(14b851dc,c6b4382f,ca64791c,74a3faf5,adbefe65,b36de8f3,74e12e6f,e3c20e1a,6353d0b,ceff99b8,53557d0f,a893df50,598e0335,249f96c9,4e7a46a,3c02ce1f) +,S(d08e3027,5e05da0c,22991340,8317ec6c,e4362dfc,45b946aa,41e6b541,92c7589a,9553748,22228787,2ae61975,d0969373,8cb346dc,15d07e23,68800ab4,deb5d463) +,S(365ab0ab,6d51bff8,d4bb479e,a666e110,9a838863,2a5f8cbc,b3241bcd,5ba88ed8,bca2f90,ef0d4145,90cf9add,2a9d6793,d678f981,1ad851b,b2f54b6e,6bd093d3) +,S(879e8da9,e1363822,b113e70a,b8072081,f0e34a99,49d698ed,a0f55b4,6704089c,d5091dc9,d33861e3,daec5550,1f52378b,65b25a74,27a04483,c862e0a2,dc1038da) +,S(17006515,8ceda656,b23941e6,33ab3ab,ebb527f9,52ea9876,a8341600,24dc10e7,39a7ce82,b0afdbb6,33e74517,5fef5165,cd44c8c9,d81be0c4,56ee0251,6410b0f2) +,S(574a4f4f,67e294f8,2055793d,e94bf7f8,aa7106a7,f7ef0f2c,3bcbf2a7,352f017e,eac4aaa8,f4b4cf2d,ed8c328a,99b24623,16ee6e08,8805f1ce,783c4cc9,eff7baf3) +,S(4ab81205,32603ea2,9f88ba75,f2f0c4ae,330bb5e8,7f371806,de04f87e,69d5e6b2,1f1967ff,cd42f9fd,1f892f43,f8ea945c,c0135544,acb8010b,8285403d,5e621456) +,S(9a4e968,82b11f0b,5e431867,80dd208a,ba25b3fd,1350ed84,f34f2b43,f03c4378,15653ab8,375c04c3,d7488006,1acf13d9,c5d669f7,bbf70490,44dba189,372f611b) +,S(267b8cc8,3ed6ef12,47a93f07,b4f1195,2fb1de83,6c3e3fa6,782b5e82,80cbd8b8,19bc5752,1a41c7a2,a9dc29b5,cafc66d,7e2016a3,334b4be0,e2811ee2,4ab8599c) +,S(69a8b170,876bb1aa,2faca2d0,a4ed8c02,44d2cfee,a849293f,5ffb4243,256a1017,f77d7a37,5315381d,97ce835c,296593b2,80c395db,a5311a6c,c7fc2c98,d314b4fe) +,S(88aad570,3a4365c2,96946510,5a3a7fdb,6e1f3e66,618c3fbb,ee4c4e13,f333b1ca,10ded35e,c15df656,fabfc4df,a1140b09,196d10af,e1e99b3d,7e1113ef,f7fb8670) +,S(50709e9b,8620f7f7,7b8b6c69,1360062b,cfbea4ef,6448917b,471c3485,55691440,3946b364,3cb1bd81,818b828c,77c771d3,833a1d4d,dc509705,2e5db99d,6cde2137) +,S(1ac1d530,7cf465b9,8f1140ea,bbe7a939,df8155a1,bd656168,55ae128e,bd3959e1,eb02a759,82bfa30,1f9fe87c,75b9dd8b,fe2d64d,7ea89836,1aafe22d,448b418a) +,S(126a8f88,e7f59ac7,3226f2c8,8851773e,873f1ea7,a87342fe,da5d9795,3a1dc956,1ce623ab,abb29b2b,b9fcbde6,a6a6f12b,ec68bfd7,aa98733d,f2452860,bf9349f5) +,S(592fe608,92c09243,20fb32dc,39e7a42b,1f5125ad,1e7d6790,9978ac10,5471427,c4d6ed82,4d33f52c,d975d34f,b9df5698,968a0c57,9b44bd19,8a67fee,9935d310) +,S(babab912,e526a92e,d903a942,ae8ad2a8,930ea5c6,17cbf913,7c074060,6462f0bf,76c7ced2,4318c1b6,c7295d9b,52bbd4b6,707a4170,d020e7dc,1c7b5e92,aee7a4c8) +,S(6554e9c9,bdb1757b,408164ad,1cafdaff,4642a3bb,cf64e785,42c324c7,5be1a903,439d023e,f6c63252,311cf494,4c46a8cc,a3d684a1,d66556e5,dc488d40,e5ddd500) +,S(79ad3f8f,4c429721,281a9b17,d9c05463,f26bdfd9,c856451a,1050b3f7,805304f2,3be5cb37,da868333,4f9a4def,aa8711a0,adb6721f,d4b2bd38,5ad7298e,940dbb87) +,S(fe559c8b,e982e801,7427d308,e50e4d94,d7094aa0,635e553c,c591181b,c9593015,9186fd9,c9fbecaf,f4747597,22b34b72,49fb72f9,f02a67a7,627c1562,ae80485f) +,S(d2b4bcca,38d1b073,5248b4a,7f43f277,8e03f46c,8d7f3a33,ad2dd9f1,70ce0af0,fe0bfaed,846a3f80,10fca999,d0c3b0d0,b54e2fd8,7a0bf751,ba40f560,9eb952e6) +,S(f6b9ecb9,631c784c,8b33a7f6,3fd0903d,baec116b,3dfd2414,4865b297,5c290faa,95fa4ed7,e67b828b,4c685850,4b003928,8ad9e27c,da175b4c,81730fc4,5b063355) +,S(3e70eafc,653ef528,aa12ce46,59c90ee4,32979f0e,9df260fa,b9063f3,d30de2ee,e240ec33,b224a5db,3761796d,2c1285d8,9cff64b0,7c36a184,996cdca4,839a0a65) +,S(dcc76f61,46d05c0d,67bdb161,dc395c83,663ebd48,6bbc6e62,f3576335,a8ee0c59,e451ed85,a9ae624d,4617f11d,67552eef,7279811,6767a29,59708e,3c21208d) +,S(3bb03660,430c43f7,e3b68acf,fe692b,5ed6703c,c808d7a7,503b3536,381180fe,c84c669b,2822cee3,627d4ff7,7c01c9c2,57c57e80,f35e4fdd,eab84a6f,b96fa1ba) +,S(5e266477,dd106005,6a59fc2f,df36b540,e051bd56,c9120b9a,41471c46,b1c5c60f,d6a7ff4a,ee4abbe,cee617,1ad01373,d7916899,5370031f,66f62229,1057e6d9) +,S(c1c13157,56ce83c7,93ca3a0e,12dfc0f7,270a0bf5,38177522,8850863d,37e5e537,750dae34,9090f275,5487778,5a126ea0,f3c2c0b,e3cb9241,326a863d,3179af7e) +,S(c03ae6f7,96692287,4cd10b76,d06ac08b,578511cd,c502762a,cf14eac6,4f1a913a,b3ba2ed0,6cd40752,dc97e450,10699cba,90f38f65,cc4623b5,44d7a57f,250640e1) +,S(5938d249,4edde81e,6fd50332,d81342eb,6cd0d938,f1f02ae,562d1305,cc665bf7,b585c184,1e17e6fa,9924361f,8d06b172,89782433,1d65b3c1,7f2a109c,8be27b13) +,S(e3457146,bf3f5667,e0621ccb,500854b7,a08836b1,e4315d4e,6479b3af,e5c2bcac,3de9142a,5c495249,14d3619,a92dc5e9,f20e4603,5cbe2c8a,95a8e683,bb287fc3) +,S(4187afe,4918d05b,74a969cb,14f54b70,95387e68,c043a581,7dcd1d80,4ca917a3,4e1c19eb,b38f0a15,36afd31d,bda30d09,3c776545,f2d8d823,bc3eae61,35585569) +,S(60cabe6e,ffbc3735,dcc19c15,1abfdf4b,cf082768,e62a1176,f056c4be,ff04640c,7b0fbd84,ee9d787,2896b9c7,19448412,c68a1ef4,e5c6cff2,51ea823f,76d6c4df) +,S(fc6883a1,231355da,115af629,4f06eef7,83447185,edc19e62,b53f3156,e0f540a9,73805d95,d8b2e4f9,d0fb36c7,9f09780f,c315c1b,724c5de6,98d96861,c521a6c3) +,S(90f37677,e738ee2b,3abc9d42,54085349,9cd02836,474624c3,9513950b,c325b66b,90884e24,a4171613,da7fc192,f1bc913b,31bda925,38fc0501,6a55af21,e08bb960) +,S(55e68c72,f76925a8,52d38e8,172e6340,3966f148,2a212131,cfca2497,ca40db3,ebd22c3a,1388485a,e4b48b4a,8b69b98b,755084f7,9f9018e,36769d5,d78cb7e7) +,S(c74f257e,e1bd81f4,fcf512a1,f866b9a2,19586a3c,62e7abc1,112b5946,d5b90e8e,aebcdd14,5555164a,bfa127ab,9f352034,f31a19a1,d36cda02,f51a88ed,9662f44a) +,S(bc63fc6e,d1963da3,7fa064be,f7a371a1,fb471ded,5bf084d,946a6eac,fdbb8d36,a26a6ee7,e178a31c,4ca535e8,e3d1dfc4,dadee69e,140a37cc,a306546c,26a75a2c) +,S(9d11ff44,5e331ca6,fa99f29a,78f5e769,44fbebc3,e3b45a6c,d46ad17,74a1f29d,2f007088,110e9ec,66e5f134,b6d61ae8,70b14741,e9b6259b,ff06753b,fcbfbccb) +,S(5aa47205,f01abec,79b52b1a,2625b773,659166f8,1e300d9f,46bbcdd8,532599e2,f56747f5,c7431031,5b630fe9,b162fa49,26757780,c6ba59e3,6e91c29e,c82fd357) +,S(14dafde6,c8818744,2059563d,1e2cc095,f4bf18e0,f7e41b9e,97a74089,f678ce60,6f6a348a,a4f72e60,9a44b01c,b688ea96,cdc7c3f5,e559ed8e,d9a1c7bf,cf1747b9) +,S(ad8cb71f,1a3739c,afc8a4e1,ea77bd9,f5703d4a,55812381,c5a04847,e85e9950,238d1945,cd5d6094,dee8c6f9,41a19b48,d1eb88,5c986dc4,b8f3908a,508d46d1) +,S(e88df4e2,8b7cb050,aa81792e,ad108c4a,d95e735,6443dc11,f77d70b0,5968de2d,9541f907,f29d79ef,83c25f29,fdfbf819,49f21604,adb5a5df,e939afe7,511cdcd9) +,S(d6b6549e,1ef4fecc,ab56860f,c7a8a549,a354d9d5,63b9d459,9bbfcd71,7631c879,df7a0e04,18a86774,ba87bbe6,132028e2,927985e3,b1319c83,4e1a400c,7b0ae231) +,S(d919b999,faaa7cba,99c79a2c,febbdc68,6d94e07b,3edf8350,6e9a729b,f0f834d0,4b19faba,9b6041f3,9d33a21d,285fbf7d,638f3a07,63e2b15f,df102131,49b94ed4) +,S(b89d011c,57cfd499,fffd2d1,8734f604,83df00a5,6efd43a8,35d5983d,573d902,977f7c06,ed8cb0d4,980c3160,b152a7c9,294d489,2c90fb88,1da40f39,adfe2825) +,S(264873d1,cf9f6f35,d6bbff5,a2405f40,a5568a80,2fa35069,ce422c61,d9f2146f,36b8e9c6,e73044dd,b9b9753e,c682db1b,550d8310,7e3ea3ce,e8ecf031,500b3c31) +,S(d4c388e0,950d24ad,6cc1dfef,a3735bf,bd9e729d,99fafc8f,e4fb5266,8816dde1,3d583de6,27789a58,fd4afbe1,af3f931f,5d12df61,7f5adfaf,95830cb5,4b13743f) +,S(80a2e2fa,40aed900,a7a55f84,d4965f0,2c5632b6,1317e801,b83ec659,cc06e35,9e61e863,69c8a367,72d6a4b4,c2b7bd89,405fad38,4f99514b,485974d3,2342f47) +,S(e36eb1d7,72d5d498,3cdbeed9,b64fa04,1da7f1bd,e324f1b,a734323e,9f5331ea,6c879df5,4a96d33e,6a66895b,f4d12fef,46d5fe48,8d62f073,238fdbbf,d94126d) +,S(7852402c,a08ff966,44a4c1a9,3f7186c1,43f0e1fa,203b5991,d3fda009,1e0a4e76,a9b15d95,3ce9b219,a53da27e,e1b03aee,5431e26c,f035fa1a,a067f1d2,d36d5402) +,S(5d33032f,f7bf3996,14a08ee3,a5b67ff4,850f37b5,eed88e4a,675b020b,90cc4ac,ff5c96f0,5ba73287,f3279907,ebd0fb7,9e0b4866,c32f6fbc,2541d8c5,cbe12112) +,S(138d3701,98eb6569,17b3fc46,c2a3a1c2,3f7c95d9,d355d51e,c85b6062,4675030d,94314f22,6581dec4,3518cd7,61150f31,51ccd59f,3ecf79af,482c4dde,8a24e28e) +,S(3f6ddeb3,4756ed69,de83946,b48281b,c2b60882,d0cd721c,5d76c5d9,ff898c2,be8b8841,12fbfe09,9af67a96,8f4bdcdb,db4469d2,34d64d96,99c6a575,518c48d2) +,S(74676fc7,cf3bce8f,c0c4a774,89b320c4,736b9ed6,171d0b42,17a1433,eeee384e,fce3cf3f,630452a8,1cf3fb72,63c1b5,b66df4fb,864d4b39,7e66c69f,2913c54b) +,S(e0d1a049,cd49ee87,d71ebd9a,95eef0a0,b1d7450f,617841b,590eab0f,3e883eca,99e00118,42e6a78a,d4c3ec3f,f7a61bea,a1a5f8ec,2f4e9066,978e96d0,cbaef51c) +,S(531b455c,c6051fc5,f0f3190e,9523aa5d,2d0485d4,3901600a,aaf207dc,7d2b1fdd,b95f8c0a,b0e63acc,542df948,4b112b2e,e49f53fa,7f3e1dd0,307d9161,7c0f313d) +,S(b86ba09a,2b05e91c,c23db107,9b34807a,778749c0,ed725437,69ff6c17,316e7db7,a91c815f,f8a3b2b7,e5d44357,20e3a513,32cf405f,7501ca3f,b1aa1f59,a01c10ab) +,S(b63b43c5,af63f2ac,3f6e004b,c790404f,a146ea97,94b1bcfb,c4d0544f,2ca3f33,31654108,481b7dac,cbd48e8,c20de95,11406381,ef38fe6f,950b4321,4b145093) +,S(63a09087,e237e0c9,686f2a79,af977ba7,26d77118,29c8ed91,4f99dc43,90c64d08,7771ce4,a5e7d43f,e12b5e8b,c819506d,3b85f52c,fdb0f9c2,92c22bad,790d3b93) +,S(77640a42,4ebd84f7,71734050,7ba400cb,9e8462a6,a91fd0a0,b8f152a5,f5f7868b,516688cc,f422e660,15afa46,b5889331,3cf2d622,d6c829b5,f1d11386,bce41640) +,S(963ae02d,62739bbf,e75965f3,d1b7786d,c3dc6fc,5667aebb,5544db3,157f8a17,b3a109d1,b56570cf,2a5e5056,fd9feb05,2e8f53c4,f2ced1a5,27c3311d,87ba9dfb) +,S(81324144,454cb304,36f365d1,c78ea5f8,9a73706,acc49d5f,125fa282,c28ebad5,77a71aa5,54c0da45,31ed307c,c7fdad32,ab82a4b7,2f2a5154,cc405a2a,fddd3cc3) +,S(eadb105,e80bf2d7,cba9b468,6f6b88ad,34008c85,a7ac4d53,d3fff09d,dcd566b4,199ebce5,872f9dd7,6c14821,622fd343,2b7b6437,3484fe84,714b137e,fa782bee) +,S(a030450b,52b387b3,35cfe8ec,683fe625,884ad73e,2fc1c728,c8d9629e,dd2024ed,895545be,a9009f2c,dcb20441,33f2fad7,ac704ab4,9435fffe,b92836f5,57a114fd) +,S(57e8022d,816255a5,f4d577dd,867d65bc,7d7fdfe9,ed8f993e,d9b30531,fa36888b,9b0b7929,3cef66be,c21b6fca,140e6fe7,9b9f2e8d,48555338,868b6c78,d300233b) +,S(74c14e1a,d52761b1,7206b61f,fdff526,f7008f94,b3707a5d,e5c2a600,97b0dd29,18778822,89711679,c5e41fb0,41b1a806,9b12b709,b526ca1c,44839d5e,3b51e72f) +,S(5a9ce7b6,6368077a,73c09869,38656705,c017faa9,2d9cd40c,69d8e57e,63f8e229,f716b144,cebe2907,928f4618,821af2fc,9de249c9,5ac61bd5,99a550d5,e97363d0) +,S(f0fe4fd9,99c66687,3ab4c904,b9b7c0d2,7f033a0c,7e6c1b6b,4488097b,cdb49fdd,1f4643f0,6f700657,90aa51b5,911b4866,c286128e,de489dc2,8e2d6b64,972738e9) +,S(e86c729d,19347238,a9e97433,355530c8,7b701aa7,d710d26e,6b15ebe7,4796857c,d6260d35,466dbe3f,58d2aab2,1c8d76df,18271247,9715bacb,2a76bb95,5b75730d) +,S(b4e3a39c,8fcb0dc,5a23610b,bbb564a6,765c0135,1a8b666e,d680291f,c97df351,3f1eef0a,7a235130,b5236a2f,f8c9d2a5,fe5f1cbe,22326ba0,54557513,82ec651d) +,S(a9c8482d,a54adc98,4db2d7ac,8fac659b,51c1237,eaf1d524,9bcfcf1c,4ae601b5,446ec925,fc148900,8ef10348,ee167a63,a10686f0,7a01772c,10f7592a,2a544a9) +,S(17adc7b2,c36b1ff9,ea40b398,53246d71,bb973bd8,b469f7dd,fce49aa5,e77b8c06,fc3111a3,8dfc5219,7f41ea77,1682bd8,618f9825,bb2f842f,c7de15bb,224bf573) +,S(328e9a6c,e7397c45,617aefee,130cb6a1,dd26e727,efcfc30c,3d8f415c,187d23b5,6320e80f,e4a57574,1fed0624,c0f956f1,d5b30914,b5da88d5,f63e17e5,64f8b927) +,S(22188680,f765065c,360c52d2,851f3081,b2d3eb5,4201dad0,60b536bb,a45a1a41,b1107c8d,430df246,3b3e91fd,904883b5,cb877b,c10b6f,397a0cf1,c4b6eb35) +,S(620f5772,5919db4d,53b8f89c,5669fc6a,5a3f3846,c31faee1,1e93e53f,b1d20bc7,7d739bc7,4becbd29,2784be81,294185fe,db047d4c,c16c764b,678f9d00,6d27feb7) +,S(49b1228b,b624c71b,2c23e334,b098e84e,d3d8fca0,56303057,49dd39bf,5296666c,3f316e5e,ca9c1aa1,fd5d23a2,613e756f,8ac5e819,8ac16650,a9dff05a,1c8d76d7) +,S(97ca98cb,fedaeddd,b13b86cc,4b6bd7d2,140fde57,dae7b847,c51b118e,e3d6b8c5,1b95c9f,1d6c808f,397c3ec2,a2a2b220,6fdf546e,8c70ac2a,78086ad5,ebe28142) +,S(a679e7e7,3df904aa,e80270b4,d5d57dfe,f5ae819,f240369,b773fa3c,609a1ed0,93201a4b,17286928,be5fdfef,473565be,879cad73,24124c6d,6e1614b5,4e6e5124) +,S(fe17af2f,70887958,1b9b176,4d45d76a,afac0afc,ff50ac8d,9179e53a,c5e3777f,f59728d8,67c3ab63,6d387352,a029b5d2,e9f2d531,7a508894,9a0f6515,f5c4d61f) +,S(f7601ed6,fd64cf22,57cc15e8,e554dc8a,e19e4f4d,ad3fb3ea,a7e819f1,98b3946b,a3292ed3,ff088c22,e9a62b85,4ec87dbf,394cd681,501184c0,b841656b,def0fa3) +,S(3dec302f,cad72c11,54c6b588,ad7f77b2,9368557e,77a723ba,6dcf9357,82d9d917,6484365f,537611ff,49f157f8,6c4bbf07,25094f7f,d8db9a2c,b318ab4e,632cbfce) +,S(a847783e,46ccf334,d7b15f1e,d3aa7dd8,c5b3ef4a,7ced2501,c26d1dd9,4358adbd,7c56f1f3,323a500a,a3496729,ace84a91,6bc6dddf,90435a09,8ca51f6f,5fe5fa99) +,S(dac6ee37,3c655763,b01c5012,fe01518,c3ac1b52,543cfd7e,9ca24d6f,42e4bcfd,6b861af2,f2a82f0,d4c458f2,2d264d82,54f16f46,87e31cce,7199f061,bdbc941f) +,S(27dc7253,90de6a8f,6cd9918a,e3b2f33a,8ca4307d,ca4acf6b,f9c5d0ad,f01b4dd,2a0798f6,7e583426,cca8ab26,e6742692,ee790f21,cb3560af,271b0a09,eb9f8b31) +,S(1c6a5d3d,10983673,5e27dd2e,ff04adfc,7bae277a,870eb4c6,d6379467,de2dea5b,92658db0,8b6b85d8,5c20ad21,f3ad33c3,8de02319,4bc54d0e,4d758093,b4e8695a) +,S(cab35e2c,b731cb9a,402f77ee,44565fa,d6623951,be9deb97,88da09cd,d5abb56e,37bdbec3,638594e2,59018bb,9145c4e7,dfb55b13,bda50c6a,c33e975e,6c5d96a6) +,S(97e4cfd,9e1ec85e,cc49cb90,ada87b99,bcaf8160,9b04417a,70fa66e9,78bf54b6,7423ded2,bc56ddb8,11db577d,f1863fe7,dc758999,55989e4a,d344ed4d,5faa9ecf) +,S(f2a9b193,6f63e9f1,8333cc3b,745fb2ab,7b3749a6,c59e7d6c,42e387b1,1e9d86fe,3c6b6bf9,1c2c4a,859538c9,db95a2c7,abbf8c37,b6e172b3,cc2be8f0,f18b5484) +,S(49024a25,11bdedd9,6c84aeb0,707b5b70,f027afb5,8b4053e5,234a9312,771160c0,22ab8282,914e69ad,8d573e7b,841e9eec,2fdfb939,c76ff330,fb2fa5b4,14a4523d) +,S(781c9886,4bf29760,c44e1f98,9a5266e0,4d25c6c5,f941e2b5,cf92b958,99ecaebb,994a771d,eac92f91,58ecbeae,6227d2b0,4c09df72,c5ee4439,509f0b2f,6e361509) +,S(8f7e703a,ae008b13,590ccda8,b70d2cfc,4c98480e,2a5032bd,dbd5edeb,aefb7f8b,54226771,863fa87f,ec101303,9238da1c,74f9f446,26b50f07,f35d6b59,bb7ff81c) +,S(ecb2e955,ed796695,3eb1ee21,564125e6,e860935b,20fb99da,91556cd4,e5e57bbc,75103469,9b958e18,638f4e00,654d6eae,f5631483,4c890ebb,7e2d93e6,9f4d8bf7) +,S(971cd7f2,9ce90bff,4c46eef1,9df001f7,afa6af09,b553e8c7,792f4ae4,d3f82cf9,d4180c19,7a579e31,f27874df,f29cd17,98e5740a,36380349,6f7dd211,59bda50c) +,S(7ad3b286,3952489d,42cc8394,413545bd,90fc63d9,8558323c,feb8e7e2,50ececf5,5c566bdb,5efc3683,2b22aac3,c0b81f6f,bf656c11,5514ac9d,8a223071,168f139d) +,S(c905b52c,ad0e0281,a90eead3,3939c836,ebd591b9,26787a4,2983804d,e658aae8,df2a40ca,f95aa72a,181f3424,98024f72,f1b9e46a,3816cf3f,ba5ac699,5b996fc1) +,S(e2517e6c,84856497,8ac94585,5c80bdf5,7c074b6e,fdb01cea,e93c17dc,ae4b3ff3,373ede93,2f369807,56afd100,e2f65794,69247690,61a597da,80d10fb6,bbadd3a8) +,S(4d52a8e7,2f3cd95,2e25c8,175e82b2,726a8d95,b735c8d8,a0f1805b,6d94ad78,248b7174,61287611,8000136,dc92b841,de63ef18,a7c9ff71,a10a662,af76ff17) +,S(58e5b42b,e614cca8,e131cbea,24b3debc,9d9390af,469df700,35a01957,3307ac,be4a397e,7809c9eb,2113246e,7812c403,4d42d8d0,c353d841,3001280f,db6bc220) +,S(3f177142,a6e6eb65,ca5e1609,cc89df40,3e3c74c9,e5b291cc,49fb0d8f,eff86ecc,2a445bb0,b648487d,3b962bfe,dc74e4da,d1d98845,cea5f4c8,d2f0c4a8,2bc4c514) +,S(3389c700,9b2b0c6d,a25a9610,4660a164,172a4c21,d0ddaada,c6902bd1,c9f04b38,413344db,77b83806,80647da0,d6086ea4,d1b8394a,a0047a9d,4c21c667,ade67a90) +,S(ecf3f933,4b2b656e,24ea0b14,7528c490,c3a566ea,c4c51885,d3ee94f5,7370b218,3c07fab9,b6404f24,77e4605c,345d3a93,adf9a06b,649206a4,b369712f,7388af0) +,S(a090739b,58310867,5e460a26,7e29f228,effc954a,137f358c,12be2fb5,8011b2bf,a3563d1b,7f242a1f,7ff5e505,280c3898,13251c4a,d9392d82,d3b12a07,e22271f3) +,S(a251cd29,357e5300,5a8600e5,bb9d56f4,c8251f6b,46b4d99d,5dca7b2a,31f8201f,51764fe4,596059a3,b1eb06de,56c6e21b,d58e7194,8e1b6e65,51e53333,5f9721b9) +,S(1f9aafb3,eb39814d,7173b85e,b027ad41,be210c3e,e5c857d3,56288b3f,3b05c5a6,d34526cd,16e7d3fb,76ecdfc8,c11b1bc6,38762bda,b03c1c07,94565cbc,df41febb) +,S(dbd4b724,1fa4769b,db161472,1179fdf2,6df4372c,d3b0c4d5,1e37fce5,317e7e42,7e9bca3b,bda0e211,5f2e69cb,8fcfc333,fc1b8b85,70123816,802b22c4,9634219a) +,S(9ce40b75,7a257205,fdf51545,7d6f9691,7e54a5dd,32b76230,4ec50c2d,3b89b06b,9b128748,851dbe81,255f60f8,1e5e9de4,6b20a545,afec40f0,38beb9a3,f7402e88) +,S(12f6c70f,46efbb73,2150f775,5f597fd9,2a527a33,7039def6,5533cfb,18df3406,7d9f18a2,4988ea,a41a1364,2a1555c2,bc9bfce0,dd62ba87,fa628b84,850e92b5) +,S(3132e530,9b169a3b,7401651a,351f7fce,43471b19,7ded3d1d,cb0b768c,5620fc5d,3e377f54,92c99dab,84f4e45a,7cba38e,9b589fa7,77dfb334,849310ce,53294287) +,S(87160125,8a8a69ed,d52986a9,25a54ed9,51f561cb,8ee9e1ca,6c58b826,495b9977,c5484596,8ebfc8c9,5f317681,78379b88,2e9c2548,b3c579eb,f6da5186,5d51f36d) +,S(82674b33,ef500391,2dfd5f2c,26722df8,19fd265b,3b6e4cbe,239bea50,298653f6,bb6d0457,2adf23db,86b07019,f2f59fa7,ebb4fd2a,ac36ff16,6b22e92c,3952245) +,S(2efc1011,28432933,56af99ba,ea2628de,a518fe02,c5b0eddb,3688c8ea,39d4b07f,d54a087e,bef0923b,6244b21b,f260eccf,e7d590b5,cf98be51,856347da,ea48779a) +,S(f2164194,5de0542c,de90f1c,4be955cd,98f6bb14,ff30ab44,92691985,882fad46,a87f6725,e89afd3d,6f24db13,39fafd45,5f578c9a,104f6509,c83d0694,ef795dda) +,S(72d2c60c,6f9bf0e5,5de82932,88c298b1,4d851deb,6ba7421e,ad22f3d4,2b47ee88,29626eaa,712e6d76,d85b9f7a,7a17461e,132c9bb7,a2943379,c5eee30b,1ffeb1d8) +,S(9bc6dede,ebdbd843,a5534fc4,71212480,ecfba4d,96acfbf7,25e980bb,8a509773,24ef23cf,e1580173,797ffe5e,baff2fc4,3cbd3161,e87e32bf,463333db,5ca904ef) +,S(20ea6c3f,51565fc2,bd5b8eb8,1ccd20fc,f3aafee0,9ccc9de0,733df6ed,8caa9c81,78328fb1,ff260b0f,cea69e1b,77b35679,d6663513,8f136c59,127ec2c7,d9668dd4) +,S(aaa2ee28,a4724d91,f37044a1,3b264ea6,9dd9123a,b3b7b300,999564d1,73057339,250b6164,2ade568b,8a56ae82,4488e740,b9a65f7e,a2b95f3b,4b11b6a3,1b49fddd) +,S(a1e54535,4a8976a9,33c04366,f0361775,824383e5,2c3aff3a,357788b,38014ab1,a6a306b9,b0a7d3c3,d6530094,9efb038f,a0a2cd1d,79bd495a,487a95f6,ef2b7a7) +,S(f2b0c76,18fc3ca9,f9ec5d65,2f39b6e0,158598b3,cb90b20a,53fdaf97,ac58f7d7,1d63cacc,7e8e46ab,47ce7e4a,e5a3336b,8d3d9bf0,f05bc428,f6f769fc,7ec6cd15) +,S(91843b8a,90a43571,4d7500de,fff102a2,fdb53914,2bab12bd,d3f23576,75a9d62e,3cc6365c,7dc3813a,d51cb2a3,d86491c2,c4e38f2b,10a33181,374bb0c7,ac90237e) +,S(f73b2226,8122a4e1,a440f891,14fd8d72,19cad2c2,9798cd0e,3631eeaf,6b125a92,bc14e84f,ed149aa8,ac261f96,6b192168,26f5a2b7,cfb997c8,3f293101,e758aae5) +,S(e87cfcb7,1f2b1c9e,8506b0e5,c56b14a6,52201397,1bb4c53c,855f1de,45644ff3,7e3399af,b4a9f70e,63907a29,c02e4d58,b2e76517,e4f2f2cf,a3d2fdff,808d5b08) +,S(b9657f0a,6de5cebe,47151293,de1fc3fa,b2745a18,bd5c4b8c,62282f26,84404f21,89590e9f,a787f41f,79a0b8b7,682bc353,1ad60107,771233d9,ec303830,e8e8dad4) +,S(b62d02b9,de395843,eb69e8bb,4d974590,7c8d3b26,cd4b13a5,6b4a0e27,44f449d5,173cb5ee,60d3999c,7e795607,bdadf8b9,acf9282a,d7a68ee5,6a204eff,ce5fe751) +,S(b6998e3c,31e9cca5,251a9d89,1aeb5384,fa86c92,74a0f027,8f2dc67,34b5f8fe,7658a71a,fe032a5b,ccb80a1b,1516faf1,5a3e8638,6f74b2b9,b6d17cea,61c3ac5a) +,S(864d4c66,4db88b56,6471852b,eacce0b3,52b55404,46444cbc,afad4f17,204a0170,7001969a,fb35a3ad,fc553e00,b6faeb21,c8fb1af6,135e86c7,f7e91397,a826346a) +,S(22a0ec9d,ecf7a2d4,6f550ff1,5a8f1c8f,6efeff9d,3ff65d47,97512980,216c025e,9d60fca8,97662f4e,947c962b,48522cda,c7ba956c,5a23c3b9,67f46073,af0980cd) +,S(f1be1f63,769f74f2,947eb25a,194171a3,9f9096af,cd454ad3,35809b17,d7e69fb4,b78b3a16,b734c528,c1911d95,895bf873,fcab1440,b62211c,25aa247c,161af243) +,S(7b196c23,1a7650a5,9db8faa7,39b7ffea,488b3623,a0bd7a2c,48b51c97,f5726c76,56e84642,2c430157,bfab8821,9112124d,6bb968e9,3ddd6b77,7ee08228,9a7e1241) +,S(6ad31b05,5a1f1a65,f4e554eb,31e3e048,8570032f,8af2891f,4436c640,9420849a,edeafdae,d10bf173,5de8ffe8,41871909,79f6377b,4cb566f6,3386534d,89bde755) +,S(fb0f3da3,a44c0921,85d90b80,1e7f5aad,6c85d5d0,b9cc4575,ad95ab34,4fa6aa7f,7857f22d,6f9356b7,96020384,919e26de,b9abd707,4dc6db0d,768f630d,b3589b18) +,S(c39b4ddb,edb892fb,2394e875,7c7815e2,f487f81b,45c60749,1c314350,c929d96,530f0c07,68e66dde,e10f0d95,bd66c07c,ba10f165,dade7bb3,77f8b7ad,ac4a673f) +,S(c50b3ae6,d14b11b9,a74dffeb,a5bfb9cb,73652cdf,a2bee6dd,6cc3c912,c312e537,85ac82f8,e3aad88f,9af29cb7,ba66f8a5,8c340d03,a1f32654,2071ba6e,99705377) +,S(a763e636,4e4959d8,9d3047,bff6fbb1,912d99f0,c092fe62,947d4385,2427ec02,bd799a82,a3cea8e1,db94946d,c7d32236,13b008b,da8eca4,921c985c,c022622f) +,S(2abdc992,b2ba838,1da0c2c6,2b35d3c4,ec1a1e39,516b6afe,81fdc7c9,cf3715cd,8115c826,d214c36,36a8fcca,37e89dcf,4be7f34a,2cce7357,3a6c42ea,9e084a66) +,S(2cb83bfa,ef83ab3e,53216500,944b2db0,e8cdb6a2,caad1eec,c9e14c33,a16a07ec,5b1b1199,6e84c17c,13c070a7,99dc0975,3d374018,6f9ce89a,bced7539,7121ec7) +,S(2687de95,b368b07a,7808ebf,e45fde24,d66fdc81,a02744cb,3e96e847,f0a3ca41,5728b8fa,aec73963,236ca282,d1a8946a,b2a26f28,a239590f,9d38bdda,d05a846b) +,S(b143029e,7f32bd1b,a381fe82,8da79713,b53550e,f3cf867,4ef1e952,d4dff9d,a44a622f,ff5fb466,83b69803,c6ea5c16,8d86c673,3ed94058,81aff0a,2a8edfd2) +,S(4c54d53f,cefac583,6fcf3b87,7202afc4,ccd68695,567c7fe7,6068546f,aa9070d,7f42728d,78193fd5,946f3787,6ab124f9,b1045ae7,45df58bc,cab6f59f,a27c6f18) +,S(6b625111,556e3ff5,db9cd8f3,7f610b3d,718220b,e459f546,47314b04,b2ba9d6e,b3ae66ca,fc58bb7,5a057767,8bf806b2,c204b90a,fd114ae8,4ed51378,53b30a78) +,S(b3fb12d6,e16e4279,5fcdc1ee,23d42f9c,198debdd,56217af,5b76989a,271b473f,d38adb77,4ce1d0b5,e41b65c,7c973a27,10c5621f,594e6f70,d235f5e,a4a89386) +,S(9c7c908,6976b590,ba9c80a5,fe12c5f5,ce6bbdb3,5a4058a,3cc59899,82073ae4,399687af,4d3e221f,6168ded6,31644c35,e41606e,94583429,34693221,9322da67) +,S(28cdf6d0,f0374a35,4dd169a9,1c3beef,fc88dea0,4922f841,401ffe91,8bfbddb2,2b8f1d3a,6f001d60,95aab0d9,d6248cef,cf3b97a4,850d1a43,ad2bbb3e,d2ea4518) +,S(1974b196,a25b6446,2ceda38d,d99662b9,7dcd0d7d,15299c00,9b8d14b7,f139e7af,c685622d,96fd6379,6bfc3f2b,6eacd54f,83281ef3,50d2fed0,2507a157,9fcdb74d) +,S(3beafb9f,4cfa3570,3d3346f1,afa48acc,25909889,a60b76c0,6e7774c2,acfe4367,6c8c09ea,7233ce1f,cacc82fc,9c1dd357,51021b92,fb86d6ca,3749bd58,6dfa369f) +,S(b5cf157c,4586fdda,16a111c3,9a500daf,b1aefb07,e32f78ac,a23664b,cef3be73,1d273f45,58e7c2ed,6f46ed71,e297dac3,59489934,b10afdc2,cf0f4270,ad6fd53e) +,S(9bd52baf,cde37895,9439aba4,b1fd4080,84441657,c2b1b36,c45446a6,7b661d6c,87f63761,6dba07e5,96d71dba,f86df28d,c506a123,c6f082ff,47886a93,da068ebc) +,S(20cfa2f5,b391d687,b89cad8a,a4c5ac8d,8624d4c1,ebc94cd5,d47999fd,3278febc,1bd4a896,4641d8cc,f6926323,8b1be2c0,49141736,ee780ba,d2110f27,a674239f) +,S(e54db30e,e18cff40,56473478,2c61d437,c79adc23,51739315,ba845adf,c7e8b6cc,ef631e42,9529a407,cb3f832f,6aee6fb,a26b125c,fd28f43,b9f07e4e,ad8b0632) +,S(588f13bc,3dd3b927,7508ca9a,82ffe280,fabd5cb3,1413e848,2a2aa4d1,78a290b0,95c81a4a,44e6af9,5d8f6fbc,ba3884d6,d6a54057,1835184e,50f5db88,d08517b6) +,S(1927e8dc,ddc7ed4e,62a32a82,bd4a0977,fe24a571,10b1acf3,78826484,de7e757c,e0a9674f,76122a18,dc6004a7,ebd1da86,f98e896,5585518f,bc5f91d0,4699719b) +,S(7b82c663,aa2201cd,71dd7c2f,b8303264,8639f9a7,9de52706,e2deb38b,85dfcc36,90dd6e59,e98c611f,a7162fdf,8fc503ce,71b0ad1,dd150698,e4c21916,d5ded962) +,S(a15fa4f5,97086036,9e9c3946,5f16a458,c7b36ec6,6ad384db,7803ce19,555a2bbf,bd406283,43e40d18,25a02557,6bbf752,35e34400,dfabf022,6cf2bd3d,8fe80901) +,S(2b6199ea,7c42b7b4,2230da51,a895ba86,83950dd9,d4d5ecef,80512976,a0df55af,26ecea05,16faa497,3fb9865,16415ebd,93ce4a6b,e4b5cf11,3507d3e6,6a70b692) +,S(35ad2f4b,b5ba61de,364e8198,f5404ecd,4cdbf26d,7072dbed,d9892804,364b43f4,5481372f,7d1af5e,9e60cb02,ae8512a,6bcee9c,eab1344c,6ac5898b,aeca2e94) +,S(f4eeca4e,2ab38839,8a459df5,b94cf98c,68017522,353aaa98,bc606bf7,5008c6a3,e016b7f9,aba6e910,6a647662,1e7a5b7,12ab97f6,498f451c,21902e0b,9b6c2c2) +,S(6c488180,aeb6c444,78ef24de,21a47431,b2e26d9c,bbf059a5,84631829,a75ec053,ccf084c9,38491cfb,8cf0349f,fe80a315,71bbe0cd,dad9a7d,a4434cbc,9160baae) +,S(a52e5bcd,2214d405,57360828,10ebe384,a94f79a6,579a8966,6f1ef7cb,bc80f4e,c28bb594,e15c47df,9bf4ef2,2666fe4b,d916dd9b,e62b60d3,49c2ba11,506fb79d) +,S(c55414db,3374563e,5c79d9b1,1103ad01,7b7c04b2,3afb5431,8c469cb,49ea9754,f54a4335,7bbaf088,4d18bd70,6f3d69a2,44f4d527,a6dccf5e,52f468e3,752a998a) +,S(b7771609,335ac0ee,1e82539,3fd3cfad,5cb4b06c,98a05bb9,95966e4b,6fc1f24e,f305d878,33f95e99,ff6a3b4a,2b77ffa2,4cddd5af,d253ebcd,d60abb1,438e0745) +,S(da220e1c,c66af350,10736e75,483e2573,91f6d2e1,d355d05b,8471cbcd,4b64832d,bd028d5,5db1c54b,86f6f123,bbabe6b0,f3e52e02,ca48d92d,464311a,aaad3cea) +,S(1a680b36,991edb40,ada892dc,6c102b0b,186bce17,280f9850,ca50eae4,6951ac7a,f03d7958,b0789cc1,43d61fc5,11b70f9f,1ef17239,dd6a057f,ca394f62,225ed9f6) +,S(af8ca10d,b1975668,b8071ea9,5d474b5e,424d461a,e98b5ab7,bc240cc6,44da9c57,e74ea4ca,59f926fd,89bb2bac,61790ee0,50d746af,5e30019c,5b53130b,9cb9786) +,S(e6014570,2ad63dd0,5d98c576,c3d5158d,162857f,7b83045e,d91865ac,bb347922,52931836,4a9fe323,40f13c0e,15c955fe,f718ec64,4b45b141,33fa2edb,c65baa18) +,S(56eedaf1,fec96ae,c2f1e051,9a1c4a76,dc0ccd67,1781cfbf,7804d215,626dd5de,adb8a791,b73aebc9,c6406e2f,83e611b6,286761d1,a6c759c1,de85658c,a4788923) +,S(43c5272d,a3dc8c2f,edb0f5bc,a5bd5f40,fea4bd48,9f367675,cb578690,636fe0ad,52c62fe5,1cc2dbbc,57de501b,839cad13,b94c9e12,12b1cf30,d8463605,f7871c43) +,S(66e76528,7cd0ebb1,9d9e0d76,aaab4230,1aa87367,c3a3f96a,101c6125,84f816da,39a4d3ef,8d263217,3a3a8c3e,d9c1b460,e240cdc6,9c9cbaf9,89535604,a2f28edf) +,S(1a274502,31f1b5c4,9df7564b,f311a7bc,d5123e75,2471c243,65c0e142,d3b292d4,5eb550b4,ffcb5e1e,c695f22c,dafada32,1e967ac3,7e1fc20b,e0e695c4,324c1131) +,S(36f1c3b2,ab6a692b,5d3b1e10,f53b43c7,7d5c4e76,90e089dd,9e70eac2,773c3620,5553cea3,8e56a7dc,384458b,84c419cf,2d493246,1f75f16f,2d1a547a,6fdf0289) +,S(1ff0f8e7,8318fcb0,2b23a1d3,61015c67,6b1a446e,784bbdcb,c088b241,3da40369,39db7b2c,6923a1a2,379b58ee,cb91ad5,554ed5c5,60d5ddba,225c0074,e9fa4415) +,S(c5d7b7f5,d6dddac5,2a2021e8,437f771c,216bfb43,24c57ba2,e8b43a0b,dfd17e8a,78fc37a3,9586cdd2,f1145cd6,f9beda83,43e8ee5c,854c256d,419fdb4,1c9d2bc0) +,S(4af5a3c8,cf107e16,fdf3522c,47fff7c7,b2fcff70,c6c8b36b,7d66a3e0,4b107250,b1b6e5cf,de869937,45ae8632,c5e2860c,76a5f481,ac24ac86,ad135136,e9ff4e04) +,S(37b59d45,86fff48f,67ff3ea3,f31f721c,3daee8f1,a2ff960e,3f77b793,3e35b50,73a7d048,2c93b9eb,4c2f6359,3ce61497,ed455970,9b2ad7af,2d0f834d,6f070d98) +,S(6e9dd180,d5b7c41c,5f529439,e46534ae,b80bd802,b8b12e0c,ccf532ad,a99e663d,e981b043,e936da7f,ecef09e7,cd118646,5bdeaa64,45a00a59,1139eb9e,5628004e) +,S(fde9062a,9f7e13dd,39117543,be4aa5a8,fa10b810,a2285661,720b4586,68acc236,fa39cd20,a5eee1cf,3727df99,32c5289a,96b1409a,5721b9bf,1ad8f42,ee35069b) +,S(d7ef4012,ecc74538,16c392d0,4d1ffdac,76a30992,4c1489e5,159149bd,84847835,b2f5e699,9883a21b,edda98cc,ccc1ee2f,258fe291,c508cee7,39619659,e18c9720) +,S(8355ef2c,f0e37956,56b77adb,5f700f75,47e2c14a,b5f6a0ef,8716c99b,a919612d,d75dc6c2,fdf0260c,6682b16b,42d022f2,f03bdd1b,1e6ef520,da295465,a1988eee) +,S(cd49e795,63655bfc,87bbba18,b72a0c50,52568a26,53bc0543,3661f3e2,2ff159ba,ab28dd46,696b7414,1365316a,c8cd8dc3,2c2f5e01,6ae34302,d103cac7,4e37d25c) +,S(8f93b20f,28f89a46,1afdf08d,7550964a,dfa8df2e,ba2c00e9,9d351b84,2d6e0b78,92ffb09,812b6970,7746493c,c833bdde,6849a2b6,ee7778b8,2b41adcd,62b5620e) +,S(a7b3fa74,4621cc50,f6719d0d,5fd3f2d9,6acd3163,4dad1114,3ece3db5,d114ab2,948a3716,9394841d,68e5b64d,2f86798b,d78c8530,bb8d4d61,f82b5f51,ed0f56c6) +,S(e16b540,d62e3237,361ba514,a11f2ccd,ff72ae57,b37e58c5,d4c3c49d,2cc8fb7a,67efad5f,f02c36ac,a0c0ab0f,ee5e5135,fa7bb3c4,51472d37,abd0711c,6618a7ff) +,S(589645ff,5c3dc06,9d2ff542,5278a51c,c4fff14c,3de96036,b773497f,8940d240,1ea7ba1a,95f65259,c30ce21c,a95b3b95,83d11b10,3c8e633f,6dacbd2a,fbe44116) +,S(d551239e,3448ccc8,9a83b8dc,41396df7,d3db0c3d,f79490be,9d44636e,f5f0d0d6,779118ae,a8db8a05,f2231b5d,923e9d97,5e69a462,5c2ad551,5a8e7777,b1b25899) +,S(c45a22f2,9f611893,d8577d7c,9c1cd46d,82f41b48,a7c18628,ddb609e5,abc434f7,515624f8,5776268b,5a5c74fd,8d87f8e3,3e47648e,2eb8c2e8,27e9b57f,7fee5a1e) +,S(fb8e4546,639d9571,90f2840a,2f72ba12,a72063fd,85f160e7,18477d01,26132b85,3cead630,f8bf75c9,31d19cd9,6f4f3718,1efc4854,b937ac31,c3e0dc6e,363db575) +,S(ec51e7e1,6cbc70cf,1f053860,fd21e120,98b652f8,df9eb31c,74eb787e,87e5ca5d,bd5afa95,6996b7b,357b475,fa7a326c,d6c2505d,1ebf6fa6,feaa27c2,c2685867) +,S(52c497f6,f8b9189d,30fc42cd,9c2a44d4,2d4f70ad,815ccf05,4f50571b,2570bea5,35f54d97,a45e2712,b0f9a720,38adbb27,a31cfefe,c065ba9f,883d36c5,c070e9fa) +,S(2fd360f,1680b7b6,5f49f64d,5a648e8c,97e4a756,fe88e107,91fce9b6,295cfc85,7a88eccf,c4d82e86,72780c6,e1c34bb7,51a6029e,dea0cb77,3d29a85,b0689f5) +,S(7b328546,25307c85,f9ad0c31,ce2c31dc,e746931a,57ec42ac,16231165,74f63d78,6862d363,4360e404,9693dc03,772f4840,4a30f167,993c8f1b,56244c0b,af6e29ec) +,S(af76b473,4cf5f641,25124792,fb558b97,df60d67e,41c2b104,ba27ff35,e3be96c9,21e6d4c6,c1e0d3a0,69520227,c4cf2ef2,8204d85e,26f4ebc4,5d6f81cf,10defdb2) +,S(5b1237e0,54c98238,df2ccb28,a5b42b64,cabac24d,1126c8ea,5520ed69,ac449521,de7ac1bd,4994cce1,8800ac0d,5499c33d,bdde3096,1a0c9028,58de0325,b91ffc36) +,S(b81bcaa2,25743a49,36fec95e,13c8c20f,f818ee5a,6bda3850,870492bb,b3380d5b,6ea959d5,483ea6f3,5b3a4a5c,1987673,a8196c98,d8efe8d0,3aed5884,dcb391ce) +,S(5f6ca7cd,1054051d,3d8a2a83,73be30f3,516b305c,feffe073,ea2773fd,77eeab3c,89287d8,22775f53,61c931ab,bbc43d38,380488fe,5e35124c,2daa5441,3b36c126) +,S(ffb3a36a,8345f9ca,30369f21,f04dc9f9,d5f0282c,d0e1d68b,f5ca1cc0,c05ca91e,21ddcc3e,f5a94fd,8046295f,c0629b61,b1e8fea9,364fe659,d298e0b1,be5a6c17) +,S(51902e3d,8801dff4,e6bfe7e8,8f600d75,42eef0f6,e186df29,3a8c691c,d57b36f6,48a27fbb,cf9dd38,a1ab966b,f635fbeb,35bc3fcc,52f0cae0,d9a3ad5b,2654eaf1) +,S(f1a68a75,8f0f8937,e14a48d7,15c4cda0,679d9b9,12682182,493cd9df,c3ccb345,db85d3bb,b8431e56,d21e8c1f,4eb1c750,225bb222,38da0bc0,30e5da0b,d4f4a985) +,S(81d88ea8,4969d53e,fd0aaaf4,248a3558,f37059da,a4b3d32,da538bf,ca1a4d15,840fe961,11756d96,5c8cea1,32067ccf,31ac66bf,e1086f16,afccdbed,f16a2d33) +,S(b5830ab6,2e236cbe,345044f3,af940029,39b00b52,e779ce10,b02c446c,84163e95,d8720333,b210a391,499f38e,134a0989,254faef5,126750c0,ec2a5850,e1d4a821) +,S(b50caed0,a4e9e41f,f03d16ee,1848d92d,d4e6b76e,4e2332f3,793e8650,20bc4d11,39195ffa,13745502,eed8801c,40f36e2b,d9b636bd,11d62388,8ebab8a6,41d3ab54) +,S(6190402a,3750824a,149945fa,df942c0b,3622acc,b2ee1304,f260593,8de5c333,290f4d4a,73a1c72d,c5ff4228,41e2949d,966da112,5278d082,ab779e8e,d4cb179d) +,S(8966488f,4e991a1e,e34552be,c6246b2d,b9486442,47fda545,f8083b7a,b0435060,7daa3ab7,87283446,a7900c83,b726b849,f7dad684,6326148a,aeeb6233,738c6c4f) +,S(edfa388c,fd246c1c,6bb7bd9e,6d9d335f,9cbd7018,ff2a750b,4ba976d9,dd922b5,c74e1113,f10e6954,6848e4f4,11a5afe4,bbf7dfd5,d252e66,5789627b,b81ce714) +,S(304740e5,1b99d9ae,97de2a55,8dc1abc8,60bb8b5d,a52f6208,af8e28f8,89904951,8ab409b2,3606089e,4a111377,c8a94e5e,75ecf098,4f62aa63,faaf7e18,f93a37d0) +,S(d4ca8aa5,e31028a9,37d77295,96b011aa,c26f58cf,3a7ff671,99aa7f30,3e00bc30,5ecc09b3,bcd9afcd,309280d2,617cbfb7,e4a9350,b4ef79ee,1e46a8c9,56d46fb1) +,S(4110ec3b,ae03a061,59910aac,4f2e4bd7,77d5e055,4eb6920d,aac4b835,2d7cfb4b,c1237e1b,d6f1cf1b,6fb0f248,9e3712ae,5557e4b2,f72ea7a2,2c482e6c,d84eba92) +,S(f7c55f97,3e9df72c,c9da8e04,b1926688,1d53f810,fef5e664,99b81f44,e4f9800,4b45e93f,e02c3993,95238c80,b65533d5,ebd01cbf,1b3dbf44,4d550cbc,4652fa89) +,S(2de3290f,56fbee3e,15def5a0,5d65436b,9d722e3b,a435f269,a5ee0231,857cbd29,f80d2ac2,356ac72,f3106b47,5cbf3701,bf924e3,48e93c9b,f3327b55,bc203828) +,S(c8e3d2b8,21922146,1862d5d3,319c2abc,7dfd568c,59df4367,eb975a95,6e22fda8,d6ec1b9c,e758a8c6,47e718a3,ee8ae232,c416d763,d2887e19,54ae4c30,30404f20) +,S(50c1a147,c117d907,fc831f72,9be19b3e,e93733e3,aa3bf402,e64760e2,edc82065,acebcfda,80706b53,116e4cc8,cdede6d,5aa1b7ec,62ffc942,572f729d,47396289) +,S(7bab8930,55114c0b,e4f7637d,ad165491,c21d6970,c8036375,1387012a,7b785528,6e31589e,2ecb13e,b7bca5ee,39e3bca,fd2e5645,6574a642,131d6178,901c0d97) +,S(dc94ff4,44a12ca9,5180904e,58802ed3,d1be43d9,8396360,e9e932e5,622d257f,ee2a426e,4da3dbf9,8a6d5ad7,9a5437ce,6fdbede1,25e836fa,697685b5,989c86e2) +,S(efb2b411,e66f8e8e,186b0fd0,c572381b,e9edc68a,903e95f3,759a11b6,b6a9dc40,4a7af79c,a1383f20,55bd080b,f410f554,24a21ae5,7b57b63c,bea36486,6c30dbd1) +,S(2f37ff22,26a0c4b8,77a36da6,7a423f59,497a26ca,8066a651,c13573c4,4954599f,f9d1c91,2b74f663,56798637,9de41a46,683a7cb7,61ac6e3a,86d65094,d1e07a8e) +,S(63aa61b2,e24fa178,95688d95,442844cd,7e68edcd,98eb3496,ea071c4,5b46abd,9423daf8,b6c241f8,785b76ab,a40803b0,97da461d,cf6579d4,4308c9a5,e63ac4e5) +,S(58618e22,93c52375,4db8187,34e355ae,27b73f7c,4469d7d9,115623f4,e8e20900,8531be34,22616853,c2c095aa,138819b0,bccd7c51,1380c64c,65ba2500,ae18794f) +,S(61418bdd,2619e7c8,f32c8cc5,34097cc7,4a9a0c57,a38db50b,ad828a60,f658fc0b,acec4e21,774d283b,db9a8a11,115d20be,20cbfcd8,2d67b10a,3d57dba7,74537c48) +,S(79ed2dcc,dd4bd25,67dad04a,b32c9273,39a9c592,95a69b09,be7965a8,c779b2fd,64860dc5,d17e409b,4feef8ea,8a7d7350,3eec186,1fa15f8b,f5576a9a,39f65283) +,S(a20434a4,c51da2a4,c7a6699,84f41ef4,67bd4de8,a628fbe1,385693ee,6b6d8a52,e2a00a0,d00aa33b,b49743ae,6f9c824,d2fe1f7a,f51f7720,cfb0d800,94279dd1) +,S(d8c0bf47,530ff603,c140503e,84fdf6d1,ed908b98,cd27136d,ecb2c4ce,da9f8c61,19e02399,bd898b4c,b9987fb3,4262df35,9b32cca,430e7cd3,aea9d20f,530610aa) +,S(29f06c46,a20b5387,aeb6e490,ef9a7bda,ce16fc2c,8e8eb202,b75973ea,8dc4f3c0,2220f678,daae0cd6,8514c091,a1dd7060,b21c2630,138b5e32,e0d57d79,b7b06d7c) +,S(b18aa504,d9cda828,e67d4f55,ac51c961,e9603d0c,ff737c16,42f1c8b3,fe81aeb9,1f6d7e83,480a9290,789c016b,b62e6e8c,adb4b500,fac710a5,7969bff2,89578ba8) +,S(e7591f42,e649f9f4,477c9cb,bc8559e1,f01eeec5,e9f3a0b4,8d9bf515,6d2044c,24c8777d,5e7c3f7b,2c6fe0e1,cd0e3845,45bef898,aff192ab,c4e719d8,ae466385) +,S(65992fef,50a1983e,bca478b,419ae258,77ce7a52,339ecbe9,2394dba3,8ba72081,32491cbf,baa7f8a,9cf21a4e,57ffa85b,eaba7653,d46d9f95,b4e25212,7bf76781) +,S(771b52ad,e47d035c,ddbb1012,bb89aa9e,b774e0bc,aded4998,86e1e358,ccabf9be,1a897dc8,420a076c,5a723f30,206db0bc,e9760b09,1f698952,1c4edc17,f2dcb202) +,S(a7d5c532,bcaa8ed6,6846046f,d1570837,111281c0,795d3e50,16cd8108,5721d644,13ccc5ee,4bab0d34,2f740ae9,e538d50e,900aa30c,bfe99e54,c69cecc,f18f6aff) +,S(fb504652,a55d01c8,b45ed7,6c71d,9067026b,27e9ceed,c38bf6fc,aee16d50,a150b6fa,f37b0c6e,ce4ebbef,22277b37,44933fd7,a135a25e,5ba8f7b6,1a6b7d0c) +,S(6242a221,115863a3,73bea0fd,39974dea,3c33b794,68e04087,8ebd8bf3,ca09f1d,b806de29,fe9eddde,1556c09e,973fa20d,c4ff916a,3d22504e,19e33169,f6f903e2) +,S(30382a2a,fefc7110,77af1a7a,d8a4a4bd,622635bb,73e50bab,c58116af,d1e8f3cd,d7ff3c80,9845a620,d53299ee,98cf3c6c,499ade93,84791af5,d6618866,3b6b74c7) +,S(b69ab576,13d1527e,990d747a,bab1582c,af995b34,6b25ed1f,df3490c,5549f36c,cf896a0e,4878bc0b,ffa3a750,f83dd329,ade24fa3,76acdba6,dfdc294,768e3f41) +,S(36f6c331,4071ed0d,b2be8f45,fe19be0f,9b37a675,a56679e8,bb49925,9339257c,d593ff7e,a32103e4,9cbf2995,21ad3da1,5b1b44f9,d6c95418,9c794291,b1e6769e) +,S(fc312428,7a9ab1b8,3efce7f8,17f707ae,320dbe77,e5937cd1,513bbbbb,90ed9995,11bce5f0,91dd9ef8,42a46aee,6f3a1d,7cc23da7,381a5f24,4b5a2638,45b2bb0e) +,S(b0de8720,58e1165f,ae1207ec,5ec0888,5f14bab9,35a2fe6b,1f7212f9,7b4913b4,5bab24ac,2589b8a8,c5e102,26a907ac,391289ed,23fba10,b2acdb74,a142b395) +,S(699828ec,db84587e,31ad233d,c27ce5de,a8f4e03e,2c450706,d625e387,12c0af3d,db1d9e5b,9a74caf5,855aef9b,6b8d0c18,c98c27b8,ce0d8a67,c6bd8467,261f726b) +,S(8d133509,d51edc48,97830f8b,3f8a6688,7a16834a,5ea31602,1649e219,cf899cac,9d188e67,2940f23a,39ac6ae4,fa532478,9c5df2d6,57f8b4e4,eca17e02,5560f08e) +,S(9cd47f8c,a9d3ebaa,d94dab36,4412ac4,a74a4b18,bb516538,10da1df3,9efc7582,de1e5cb0,fd5e7a20,322636d1,883b1ce9,71bd0565,a0eb60fa,559b552b,34b42e1e) +,S(1fef4107,648ca126,d5c4fe59,1f190f21,57274d0d,d9c57fdb,ffe2c348,35d36ddd,abf8fe20,87ca3feb,d8150e5e,c66c5d07,45731121,9b759430,4465bb14,55f992ab) +,S(e372b12e,8d3fed92,9e01babb,1a6517c9,ecb54d3e,6d0524ec,42ce57f8,5351d32f,43e910a,32447627,e2d9d5ef,53cb9c0,ab60333c,b07e72d1,c2c6644c,83e7d8a2) +,S(37c346cd,ae9d76e5,7ba2f30f,d05c33fa,3e6058af,642fb1c1,1810b4a0,b97e2dd5,9939c619,e1e49ec2,bf716714,1c23e135,157c7e4e,949e4fcc,b7dac7b9,7d4932d0) +,S(14e337ac,39f0c1d,98333716,a6e596eb,ad0d0688,b815c7a0,c182b546,88e5c3bf,fe45e34e,bfb94cff,a72b6312,a422562c,8ba782e2,16d5ee31,6425651e,e67d3d22) +,S(25517b3f,79da61ae,dd50cd1b,69b1ee36,fce0a44b,feb572e2,e6eb4aef,d751146d,7d2a017d,b9089d13,9a072803,dba874f0,f169ea36,95786e13,7fcd36d8,8b28a213) +,S(7d5957a6,92fd532,b9991383,cae895f2,8554e6c7,83ae3bcf,e72e3678,3475cb46,fa4b9b07,2bc725f8,e35b01b9,590ec1d8,f205f6c1,3203e91d,d9d39954,922d7f65) +,S(77eaf892,c4f9e0d,f63e33a5,1c088e0b,323ddff5,6f854475,b143b458,3e0e2f81,93d0f67d,51abf50,ea260593,96effe6,7f985caa,a9d68250,224e7193,414105f5) +,S(812c11a8,2851f474,e5a0a175,fb527539,7f1c73e7,6a766cd8,7147c9c4,4c970ec4,f9e22a19,a35179de,30379c37,a616d226,666311d9,4ad62b6d,59fcc579,cd024af8) +,S(b633f071,57c5a0a3,7ff5f626,17de24dc,14b3bcd8,4eb43385,e5a59be5,1c371fab,93e70e48,68ab5a3b,e29dab87,8a50e2c3,a09edb5,bf5b47d9,a09ccf59,53b67673) +,S(5e78caf1,9a2031a2,d92e1ba2,1f43f91b,10a98672,5d23ef95,1bdc1f83,cbb16343,b438317e,9446b88e,92206d81,883d5f3f,6497ec33,d144cfc,3a7dba41,db53cbc1) +,S(dd082ebf,88d49fed,50b76df,8e64d3a4,a1d4bbb4,fcdee50,c3ad6d0d,a91e4ec3,9efe99d2,f15d46bd,26d67bc5,ccc122ed,bf5034d9,28bcc946,e4714784,5edb6244) +,S(1ba1e135,62c06b5,63db5c49,7ed46ee5,73399a56,15fbfb1,4e080815,874e6a2e,f298d5df,43111fb,2f050cfe,2a06b3,c9a1fa02,d409dbe8,a225a3e,bec2d8be) +,S(49477847,a590a536,e7370341,5380459,843da9c1,78a1d176,f2f0133d,6ca214f3,3d1b8f64,a1d94169,2baeef3,86b4740c,4eaa84a9,15e4d03,2bd7bfd9,f5d5bad7) +,S(c4336d6a,4fbc288a,2c69fcc9,691fc8e0,e277fb98,e34b7a66,bf29d2d4,32c1339d,64ca0adc,72f0ff2a,f150f01,ea243a51,e91da8e7,480e0553,c7bb268a,22fbd383) +,S(a510cb67,9970c117,49e4e9d9,acdb97c6,d8712ca2,7961ca45,ddc9669d,9e02207,afa065b1,46b75ee2,ff7ada4f,ac7b863c,f4937cfd,15ca2ff9,c0901c7d,faac88b7) +,S(7cd63347,59eec80b,666237b2,abdd6c6f,e5e24a60,9305165,b5bb1a04,2898cc7d,abf7dab,f9e12893,a8040b13,afe16524,1d749660,93cf2da,157e2a78,e89cc758) +,S(e0786f8d,6f339bdc,9ff47416,4070bc08,c864d0d2,6d507762,19c2ee87,61cb7959,892cfd2e,62f4c352,b296a508,455a1dee,8dcec943,f5109add,9d38437e,87ec58c9) +,S(d81f740b,123cfd5,9c5ceb73,47668148,995ca21c,a3ca1b8c,b48e20db,32f6b55d,3af34294,c83c41df,7d5f821c,68e71e34,4656be14,f09d1858,7a204244,6f74f4ff) +,S(f4ba0503,6ffc1812,efbf3fe3,81423d91,38eca2,a67a0f4c,2d0474e6,5db9efc0,b2b3c3b4,4af46f2d,e53b1e8a,adb83d59,4c32b6ca,a7113207,b7993bef,dcdf78b) +,S(aa6f03ed,50640e0d,72fa4de7,ec3964ab,82e7758f,5e6c16d7,78c18296,e3b1a527,322223f7,ecf473a8,36bcfd41,e50f871d,715f9729,93df1359,80794587,59d9767f) +,S(f2d48f68,23984bd9,e8e87772,28da095,4ca134a0,6b43e0d1,1a8843d7,1fd0232,f0b7d9e5,982d0f6f,5ef74bc6,78ee504b,6202f52e,8db7c069,e179d175,c6f760e4) +,S(70e9ec90,7db14601,9741a4d5,ba604187,a7313b7b,500864b5,383b3763,be303979,63f9ef9d,eea1d1bf,a84e0d19,c8f15665,60b4f1dc,839aef5d,b6fbef7e,d6dc6a4a) +,S(23cfe5f9,7198efd3,f34f657d,158f092a,29748586,29983927,9c58944b,146cdf1f,3b8fdd8d,cd82a757,44152552,35de0cae,c39e20e5,f82c7b6a,2afde8f4,1c6afab6) +,S(b1e2b9d6,4c14d667,4de9a6a7,5499cfb,12b30a92,b9bf7578,f8fdbb55,b6d414de,1e91c321,24341a58,e2c6d65f,18f3f735,f9f98d2d,76d124a2,c694db84,37cd0483) +,S(5092db9e,5bde4edd,f385c67f,357e43a7,c8fc8e09,f5c07c14,25bb405b,7e52d1fb,cbad30f3,f96767f9,553c9be3,2adbae2e,1f27f9d5,3fbb2f99,a361056c,ddf52858) +,S(59d39b90,2143ace3,3a1a1e54,a5cd83e9,6cf56f65,4a91f524,af8c8e19,e25496a5,be21c89c,baaffe09,4f2114be,72ff26a8,22db9a1b,818d96a2,bafa797a,3af056a5) +,S(89cc95d8,cf45bab6,9b3f86f7,9e1fa71a,34fa83cd,3d4dfd16,1c9df1b5,817edc16,5eff0aef,63fc853a,f8b65e8,8a45740e,6c78aade,4bcfeca4,c7413ad6,714eef84) +,S(6c2b8809,79398e60,87c756c,443fb032,f2adf5f0,17bf9ac6,44d164b7,d2aeed3f,bc46cb71,c9ed9f46,b34a22cc,e1332cbd,44318165,85407951,580e4b26,270f3eca) +,S(767ca583,c950f7bb,e3aaa6db,b6aa9867,792e0b8a,6930ab97,5c46d09c,30e14a6e,bb90634f,87133104,1c7eeaa0,4a09887a,e5946daf,e88828a,68761cb6,21412d49) +,S(cf742ea0,35c4d9a6,40fd0686,a460ab96,e2015d0,2c15fc8f,333ecb7b,8af4b08d,2bb94f28,bd69b51e,de993065,fd61fbad,c65fc62,90059a8b,d29948da,20b704e5) +,S(84d5d76a,a5a6ec84,52f024ea,b365290d,9c3b6be8,f33a93ea,b0a0ac4e,e6271059,f5565742,f1a47a88,8d0bb802,b002ea6e,f5acea8,864e2f64,fbfb1565,dda51952) +,S(8f5752a,8fbdc1a6,201b6e0b,7bd5db3,cda2eafe,f18cd6d,559724b9,56767d32,d63c0fad,de72b753,6d0c8606,88e0a82b,9f9e35d4,b1db7be7,efa9040b,82298008) +,S(20578def,f94e3597,50ee95bc,61ca76db,f8fc059f,e25e42c5,bf887d49,665d1871,5fc52a36,c95c6edf,46bd5c38,60e151b3,9f123e9b,c58b2079,cd165c1d,e6f33d3c) +,S(30f2b825,739fdf4c,5af0ca08,47f50323,d3ad6eb0,413b052e,525f837c,38f97a4e,d698b076,4417357c,a49b4306,7d73206f,d3d97036,26ab15d4,f11c56bf,4bc820ff) +,S(2350eca0,b4d0c460,12024be,6d458444,b37b20cb,50042830,182b5e41,d564e26b,5909eee2,e3999d60,4cbe0832,58012001,30a344c5,f72ff127,35e66cdd,904623d7) +,S(ea660cfc,45971e57,852d382a,ae8cc6b,1887fe68,dc1b84bf,31f4409,89f89b2d,52297e86,dfec0730,81a280f,9451623f,9e69c320,6f3c205a,f07e56a2,54cd5837) +,S(9cded450,2a7da3bb,77e06ae3,ef398954,7687d21e,df522f3a,cb6b4fd9,d3d49beb,7b13f455,35a49049,277abc34,3cc6f0a,336242e8,7b69815a,e27122e1,d7838a8) +,S(ac8705f2,cf8dcd77,d409a962,f98a6abf,198dd238,3a5eb258,6b0d2def,81daa172,892fa835,a0af6cf9,dd5bf158,44b22cf8,2af258c0,519955dc,ee4966c7,bd5e995c) +,S(fa026b1b,d5e5fe3c,d6b144bc,6b22f7e7,5512ca6c,9525f62,fc7fb4ea,bcd2282c,4ec40de5,7ffc1768,edb20cae,d3a11380,fcc32f45,f410ad9b,8b674d95,6614aad0) +,S(a928eb73,28285c79,5717dc0b,ccb5280f,92f9a4be,5a0b0ed7,67e58eaa,8b9097db,af57cb66,61a9d08f,4d4e9e25,aeeea2dd,e4c88767,c4e177b,37a87ba4,c2bb772e) +,S(bfc9197f,80fded3,c601a0f,1c8c1d77,cbccaab,1c8357ee,4fb67875,cbbc8261,6a721e0,241ef436,69cd386b,d07fa2e8,900527eb,ec3c0025,24bb457e,1bc7aa28) +,S(ae0de043,b332bb4f,91395870,4f3a41f,65e0f3d9,ff77c1d5,ec3add49,6087d5db,34d697f5,dbef1bdb,f581127d,bcd2755,a5a6b32d,73164665,ef84f6bc,145c2afd) +,S(4433db73,29d75b3f,7df0e229,538b7a33,e41183ad,7a7a5e3e,ccf5863d,6bbb692c,3a66630,a03ab85,9f23ae3c,a0a38717,d82ac240,d271b3a6,ccde1407,d0dfdfa1) +,S(bc7380bb,128a6f8a,5cdb971c,31ad12e2,ba593acf,718f5468,285b7f14,69ca2b90,a17af518,9a7b0445,cb37e797,a281c84f,8cf8ecaf,c661e601,4ecc2467,18f1d8e4) +,S(bb53297b,18d2d785,a4756437,70b387d3,ab0fe62,8b78c09f,bb6cc226,79bc92ab,5c34b9b7,cfb3737,bb515ee8,fcff8592,1fe8f30c,e97d21b7,47a4b084,22b0c811) +,S(1accc1c3,f46945d5,7b46b1fa,15291ae4,2f0a616f,df23f1c3,3f0dcf97,53851fb6,bb434ef5,e30fb9fc,15e99b15,b5f9d766,9681be30,d2b0a6f5,a4946268,158d5369) +,S(2fd61a9a,b99c588d,fbe74fde,e8ce95cd,1c0ee9a6,da7ae59,910485bb,9a3ed9c6,2c214840,e2bd764f,74f9db81,43ddd549,3d322dd2,b25790a8,a681c97e,2fda07c3) +,S(4bfd09f1,4cb492a5,7b9ef3ca,d245a0ab,c4bd97ef,12bf7204,8ecfee47,660f7161,57102f3a,ecc42742,657032bd,aa36526c,e67f2589,2775fdb7,e8b029d8,1cc7ec9c) +,S(f60eb13a,8e6485ea,fe653e74,de1c1376,2df7ba0d,4ff0c65f,24bb1c0d,74cea3fe,c5830078,5b74cc82,80128896,f275fca4,9be94edc,744f8535,128ba7a0,5c1d9552) +,S(2b4c7864,9f568eb1,ce1be63d,aaaba4e9,7c31349f,aa353371,6e9123f6,4c57b041,b5dc9c1a,b39325f9,3ead6f35,66c30479,5f817ca1,b3c37258,554c4fb2,51a0ca39) +,S(7fb057e8,5f559f11,b5d41538,6a25a77a,aeb904c5,d1be33cc,bece20ad,57715ac4,2352db61,6fad3f10,a2decdef,5a7fc369,5c8462b3,7d2d5ae8,bde17311,ac6b4ad3) +,S(a49bc870,bfd62cf1,1dd1bd23,9499157d,247ac61a,a9b34210,65d4d029,56f71a0a,b639709,88ffd1ae,ed1b62b1,83ba629e,f5f0c088,f8a9016,d7fa9157,46642e3b) +,S(30b1f21,f8dd3f40,697878a9,fa0b9fbe,d51c1ddd,165bd5f,ed9d1fd6,49ae913f,d5a55164,4628de36,25895fa1,471e0f5,77326d14,132d8ffa,37e0277d,a928532) +,S(8a015768,8aefcd7d,13cb3b98,373a8823,aad11a4e,718a6ea8,5fdb8a9a,6edfd879,e7d92909,4d198910,44c00be,69f267f3,84aca1db,642648d8,34a5b9fe,518e1363) +,S(810ee87e,45d8a5ee,c0e3fd0a,cb771d2a,5a3116be,f4dd7d5f,bfac0dd9,fe072778,92abfc24,9500ba0a,9cfa1725,da4c37b6,cf081f5c,c6cb6a8a,3af889ab,ddd2b7f1) +,S(a0eaaed7,687f6a94,398656fb,3fb15f49,6522c3dc,c19e04b4,598ac4a5,6408d1d9,792a67cd,677ae878,eae040e1,6378cc36,9583b513,bca68fa1,cca3cbdc,37aa61d5) +,S(ca438737,ffa6f30d,9aa695fb,3d29db01,f805f480,ddf1b227,3a0515b9,5f8eba97,56238731,ff5314f4,af6a3835,b30ae83d,feaf0db,dd4449e0,5736efba,8a8cd51b) +,S(b252f5e5,4b67554c,ba3d481d,66a2f223,a633b5e7,f335e357,29928264,e744279c,c6296730,5007e2c9,3fbdb25d,a33a9fa7,411218c2,87b937c5,dfcf8f45,472533a0) +,S(f61b57a2,237befe8,2f1545cb,131acb03,3015a5ee,f0cb77d8,c73add0d,ec0083f7,9b1e0c93,b326a265,eabf096f,f8eedfd5,9f765b51,5007c5cc,d0d3b569,838f381) +,S(30df434c,1051cc43,4ca35671,3957f964,af406830,38ce82a9,5cdf2c7b,55c50f7c,883bc89b,f54c490b,3be0d434,fffb6b,7e829be1,55280401,eaf44bee,7c445424) +,S(fd0ab148,727eb712,adee1fe3,4e3d0fe4,99bf8307,fbe18e4e,d20d5236,f7ac25e7,f5f38f32,df094903,b3219b02,8413cfc0,e56b8ed5,6ad80e5b,aaa00f4e,3877377c) +,S(b4a8fcf2,b406becb,6111c030,ae375f12,79de175,7f2f3b90,13e7ac55,12de747f,d1634039,59a6600a,fa05b1cc,3c459fa4,f1a5fd4c,27ee5382,c5f01e4d,a0259889) +,S(a6c10f0b,33d1518c,8f8b7055,b139aa84,c96e9998,8e8a256c,5883bb44,10687c72,8f0dfa52,ccaec6c6,789941f3,cab90b55,4d4f587f,bb6f3354,b5f7158c,758e4f9b) +,S(7188fb46,e244a5a2,6e38cf13,bf2e3c4a,ff5bdcdf,8d9f78ae,88213692,d866f5c9,8cb07d12,ec743540,3be09b19,4cfb2f1f,c4a85d27,d940cad1,15ab53ea,4b8e0d88) +,S(fe4f9f00,308670fc,48e45208,4063fa94,a6cf7141,d75a6ef7,4f92b474,5bf692ea,5dc45ab4,77f80594,4355698b,e95bc582,efea563a,970217e5,2bd28ede,d7e8cbdd) +,S(93f3b5df,43006183,47c7bc14,3eb046a3,842614ad,78d3cfc9,a6b665e,3327b7cd,ffe5f378,7ac36947,d635d156,7a28fa5d,45c0b5e1,70508cc2,7fd621b4,47b63b53) +,S(dd350a89,e0c3128b,54a3955c,bf802ff7,3a565760,39e1e068,e783ad00,36c13604,45cdb508,3c33c35,fcdbb29a,efddcc63,c4cf3fe7,c08a15d,8b2cd4ae,dec2c3e9) +,S(4f164801,17c1d338,7738b728,96442b9d,66f44eec,e3eeb7ff,ffa87d24,4226e44f,750e6348,490d0ecd,3be07303,5a8e653c,1b1f7c30,d89e27dd,4efedc9d,755b89ee) +,S(b7c62749,aaf79754,de281314,acb4b2f0,271f2a35,fd187307,20349a3c,a4b577a3,f100956e,ddc307db,56542c1,d2c8f176,e0636ba,b04877cf,3dad451d,edcb0df4) +,S(fa5c1278,1dd929a0,2ae4755c,70531cd6,c309261,36ef51ed,7d57c117,c1c8a885,57c5280a,5f08f0c9,393aab6f,eba0ae81,a32f8c6e,2a76c780,a871170a,e37856f4) +,S(e16d6dee,7830b0d,e6cc5e4,9b1cfb7b,50b7d89,57fa4e6c,42ce9925,2e6a29b6,cd5955da,4c1ba840,a3c98d1,7dea8d8c,f4a3d2c0,1e0cf164,2cdc35ee,87fea835) +,S(a2c659f0,a0ef6147,ba84ff26,ca81443c,ac8ba9be,f6fb32f9,50653384,a5db0213,5176a4b1,88b5bbef,3680e875,437e4209,d2fd2462,77c5f84,4a0eaf5,e9d8c129) +,S(7d507179,6a7c037,77fcf84e,62e6eac5,456f88fe,76e71301,76fe458c,8f301a68,14018264,59d3f62,6788fba3,1505c83a,4161674,21dbc2a9,dc14e1a,f45a50a8) +,S(642721c9,20d9b3e6,72db8d82,34ad60f4,bc74684f,11f2ef1a,8171d02e,b9eb1f12,fdde8b98,8aac7393,be2366b5,6e853c7,b72034fb,2cb176ee,770063dc,42b63d48) +,S(65fc35bd,2f604eae,48a1b68e,1d66cac3,627b1498,247d8376,47082702,293c97d,d01018e4,85dba402,17ac631a,9b88d240,de32ac74,79c7d47a,9f5d9188,f8ac01d7) +,S(65c8b230,2e51129a,b81de5f5,22217f06,f5d5360f,af191c56,8f395a33,2b04375a,3201b7ec,117fceb2,b225f137,877ef481,2be4d6b4,52d1c855,f73adb0f,e99b2943) +,S(b82aa6a2,86fb19a,d2eeaac8,9019782b,d0d6009a,8fa07a02,a0d6295,ea8637f0,426f8d72,ec1b08d2,72671566,1f77f470,f334e4fd,3370d96f,b0acca8f,2df99398) +,S(a3222e7a,c6c27f2,8b24b33d,ac78d873,1ce060dc,be055100,862e71dc,e6671a18,6f2c2a1c,4b80534f,8ea53777,71760fb6,5148d47e,ca097fd2,b7bb2f53,bb07ce22) +,S(281ffed7,48a4022b,c663d08b,5681733d,f1343818,d68c8b63,9f4405db,ad7020e2,b5f18609,d8e5c6e7,990808ec,b4fa7d2d,7d4cd106,b7ad2c6a,e356f239,9a535eea) +,S(c520ea8b,a481c220,bab0f218,72ccfcd5,d7014d8c,fe55d1ef,743af305,c0277d5e,e23eaf34,33e4369f,30d371d6,e396b0dc,a065506a,c4159967,fec4475c,8f6bf78b) +,S(54d39ed1,114ec02d,8005d7a0,82178175,78f827c2,1b55a95f,330a7af9,34727958,4aecf190,229c49c9,31862a57,9131aeed,5518cda9,4695e8ac,7ebf7667,d9afb23e) +,S(756b9bf0,1da8d7f6,1627cb2c,b3ce3ba,a9b6450,c2d24596,feae8bd1,2ef67a23,51c47b15,b2ac96c3,5d7b7dc2,d8c57ee9,69b347ff,dadb04e9,cbfd6889,a0ef70b7) +,S(eef22145,6ff200f,ddced960,f422588e,333a437e,d68c04ca,9758d77e,a938ac54,21587cf5,8b8ffb72,6d29aed2,3c984a4f,25df40b0,abc9b7cf,2c07436,ab7e09e2) +,S(b841b560,c0af44a,35bc9320,3c05cb32,250fcca3,f83dafe,30d1dbe6,61aa3d1,e7956525,3d07a89b,2335e2ce,9e11fb89,96e2c146,271189b3,461cf944,2ceee2d7) +,S(14b98f62,5849b798,48f32547,efccc33c,3ead6cd1,a290f03e,618acc2c,1ce065e1,4e7a2415,805a4486,476221f1,ce8234e6,5b81ee60,e1ce5eb6,b6a2e041,ac885e00) +,S(fb0aafb7,68c19f64,17e417b6,f1c22dfc,737bc74,fe8b23e7,4dc1c1c9,aad7ae44,88b83e23,631c58d,c3729cf5,54343721,e9ec7dc4,a889b85e,31cb302f,f2a6ab3b) +,S(885497ab,e34d1745,a3e2ff8b,bdea904,eeacf100,324540c6,86de137a,9756468f,63f3f160,bd266c3a,7c49b13f,c5b06403,d0614b79,17c49824,bf507257,2ac0b948) +,S(52dc7bd7,17e4d8e,8b634439,f6f06b8f,7121a0e0,cfebe7a8,3031668b,9832b8b3,90679373,9bbce1e3,5c48f41e,942d9f15,9161e9ab,273a2217,d9e857c4,3bdd0a5c) +,S(e6ed2c69,a8bd7af3,35591f4e,4dfba7ac,d82e87ee,e2b3bd28,f0f87f02,3abaa7c0,dfec6118,7396bd5,e32ba2e7,a8fc912f,1e54e078,6f2ee222,35adcd22,8feca28) +,S(9e2171a2,c1025129,1757e26f,ba979e5d,6b68c2b4,975c7289,2afe7898,cafc46eb,3dd062bd,210bfc4d,d30cf01c,51d810b5,cf1b8ee3,d3baf490,6bf5d381,b87c9a56) +,S(ef4b8648,3bf209f3,b1c2e166,a32cda39,44b21282,db8acb94,6ef62122,63bc44cb,903d1088,ccc0ba47,b5ac3252,33ef9b55,924e61ba,7ca80bd8,1925b269,3998920b) +,S(64ec6d14,7ecb6e44,6331907b,b9006b2b,fa4fb854,20ab9aba,f1026bc3,4ccdc4b5,583cad3,b41bbfec,d0817207,dd312cdc,26c0411,b888ce5c,c6ee025,baafac63) +,S(128cb9de,125429dd,e5b9b33c,ef9f34a3,e7b38ba,f22dbcdf,8e169894,3f7ae5a9,a10a01dd,33f5a4eb,66091348,c4dbd90d,62879ff6,7559229a,e53c2896,8fb4584b) +,S(a7d2e7db,ca0890ee,e07c4bbb,399a0120,e71fc284,c5b7c96b,4889fbb6,db95dbbe,b8caef70,404a19dc,15670cae,b19d5b74,e70b7492,50390b12,5f559b11,feda83de) +,S(298b17c0,b8beadff,5e6eafb8,ad7d756,8e961468,d8e12c94,78ff3870,dc722450,a0542f35,c7b95774,b1c10f75,3e9da029,ec7a54a6,97bcd9fb,46c98d26,91ac1a43) +,S(31a39bcd,a3d10e9f,6b46e1e,c30b41aa,557ba664,9b12db64,a13557d7,5c592d1d,814f1a6,15382d4,e57b8d41,351fd782,ce7dd9d7,86aa9bbb,c5b1ca7c,207ab12a) +,S(3317f1a8,1afa54f6,ffa6df13,bd3f818d,e9a29bed,7c119b6d,fa31560d,31d81cfd,aa8eb746,4e9acaea,19a42509,a23a281c,e9917788,6d3de977,4398c57,8867e095) +,S(85511857,80eab56a,274cad22,966ca547,3027d3c,3cdd7e25,7d8ed8cd,a5c6ef30,b13de0f4,45d71bd7,db0327eb,15438e9e,84fefc1a,464d8a2b,bcb8c6b9,f59f93dd) +,S(fdbffe5,7e378262,c32bc4b1,e84ae01e,a2d6dd76,28e10b04,9adf6a3e,ef106e83,f19d0c4f,1411ba50,35d3ef23,153f306f,d40b22c6,69e92ea9,22bd7d5f,83a98ad) +,S(7562779e,6aae0c51,52acc7ee,43bed76c,831ba008,82d89c9c,e29a5f3b,8855b3c8,c83c1662,7cb9e1d9,126e07b3,354b82a8,a0cd49eb,3936c14a,8d8d64ed,2a4e217e) +,S(130b292c,10d5b336,4635d43a,fb6d6e02,d5acec2,c2033525,ed72c030,e82a4a08,d534b710,e1201276,6f6fce50,ed6efec7,3e0c3e75,50e0bf36,d5d625b5,4855fed5) +,S(19fecb77,bcfc0db3,e595fe22,e96f1212,b3ed032d,183be5e0,ed4c1b8b,d0501bb3,6b0fafde,2f0636e7,2b4ea946,a0e5c27e,4e5dfb5f,e8b8a1d1,b36bdee5,75d02e81) +,S(ffc668c7,9c6f9fd2,f5c56104,aac1286f,cd4a390d,ca586af2,c348458f,b4130f77,fd7b748,d15f10b6,4eaf4946,34fb4ddc,439919a1,1155e40f,24f3eb2f,482445f4) +,S(b9797c7b,d4112aa4,8abbc827,fae12fd9,6d19f3c7,81626e21,5c26ddcd,b2d4552,ddb0aa81,3113288f,1fd2505b,d23f2a9b,a1ba0a38,dcbbfbcb,46da78bc,5c705327) +,S(9388c9f6,5bda9c81,62ec04ec,5345ff80,da4afe34,7281f768,4d8daa1c,cc3d7869,23ef5140,3f926d0a,d2ebbe6e,48858850,aa98149c,89490e99,65dafeb3,c82644fb) +,S(44cf864,6c2d2f30,e62f63fd,8e145786,80c1d5b8,a27fd496,a8e34bab,5f88270,9784e329,a434b442,fef9af66,b23ea917,edc0f6ca,8d28a992,bf6944ff,26c5cd25) +,S(ebe08589,930001bd,ecb83ca4,45c4a9fb,fd61b229,60ba9848,2e0fd520,1af5a0a9,ce2d31fe,3c271048,24ed891a,910e2cd2,2b99b39b,480ad812,a5d6860f,71ec817d) +,S(176d14f2,5491c2f1,c1d4fc87,a8f59aef,f560bbd9,41872f6f,2a1a6adc,7620f1d7,42c1e0f3,8a3379b0,c5de8a01,11b846b4,35db7783,caa9b84,8084a985,f0e123a4) +,S(74e96d3a,972baa6f,8ad6876c,9494f451,a12adecb,681c4d55,57eb58a6,de920fc0,c2cd92a9,994ad5,f4700561,e8b57201,96e61a5e,b4cb4a55,66959bf1,35a07f83) +,S(6751dff8,5079fa45,7f5df468,624c4a85,db970586,889cd80f,d4514bbe,8de42d60,7cc20505,deeb3f91,3d78a265,cb301c68,49cd5a53,dc029af5,c0db1876,762ba3b0) +,S(f9c63056,24d8cffd,abce64ac,65dd3a09,ebd344a5,5404d08f,b4140a4d,8489628d,49ad5449,bf1b6def,74283afd,2f315f77,3de82cda,d4c9de21,7995a2ff,c44e934e) +,S(69e8c4f7,3f757235,d0e4f39a,f2595cde,f7ff4d20,dd2d45c9,78f32d19,921b6672,8ffc35fd,8a6d541b,3f7135f5,643efb00,14f275ba,d929671,df610748,6f763f55) +,S(3d03e571,ed2aa88a,3309f014,caddfd64,26ae84a2,a526fe35,f30ceb8a,4e645e22,db95c744,6bf115d9,4af9074a,6b274725,adbcbfa6,77f9ce48,535003ad,dd37bc6a) +,S(e5b764c3,dc73619e,51a2afa,fb2292ad,db2b7b0d,e12b46b7,f14b66ce,f8aea7bc,41fbe1bf,41838b6e,9a57fcbc,b3e2e3c8,60170122,29a5ffe1,7394139f,5e8edf2c) +,S(adabcca6,b4252849,76596462,36b17b0f,9d1b4e9d,279af84a,c02f556c,e0f4c385,7d12959,9b411665,dd23b676,57229f84,ae46773a,e13284ab,1cb608d2,ccedafd5) +,S(963094f7,7ea2a7d0,3115e201,45dc6f6a,7318f8b9,a55ab015,8096db54,48e341e7,36bb26ce,3852ba30,dcb1a8ee,ec834f4d,d5342ab9,f7bbe85d,7addce07,62cb22aa) +,S(30ca6324,b4f34e1a,4c3dbe4f,d6dc6b13,a8ebcb35,2f632fc1,5725bff5,f260c508,5c04aa15,8dae7205,3bb608db,1b9245cf,fc57c10f,d015e80f,7afc7532,632eaaea) +,S(8356d1c4,55479df3,adbca347,fdb73f89,6027471b,e528da9a,d9e6a968,8dfba744,c325c86c,cd603953,8f610b03,21b6147a,371314cd,2c41df91,745e579d,8564a177) +,S(996ca7b0,4ae2dde7,b5ee87d8,c077bf97,9a63ce83,cfb84349,c7d231b3,1e15bfd7,cd1d1b48,d75f9736,68b91101,8ade913c,19a1d785,65adcf71,6c805863,fa6c1f17) +,S(8a15dbd3,5cc16f77,b22a87b4,4f93e5e5,810f0503,56e47d53,95769128,a2047738,cf96df1,9ecb6da4,3895641e,4fbd4f27,f00f58ce,cd34d38d,e258fa78,410a1f7f) +,S(23c1e11c,be9f6a93,6c5f8abb,6cc501a1,ca38b03e,f00b31a,79057156,f382ad7c,1d996782,9f709951,2c9728ac,68c16db,1889bcbb,7df432b7,f430ebe6,56b1e050) +,S(d937ad87,70737b1f,d52bfb7f,86e207f1,9e4bed5a,43b165fc,981685e6,24b8e84c,202913d6,1eb467fc,b488fffe,5914f853,73aaac20,1acde09,ef975cc8,a05fd181) +,S(6457f59b,2c744ca7,89537c59,6485abe9,7835368b,47de3667,4740ecff,72e5596d,30b6ffac,65e34e88,43681e64,f041870b,c85b3b5c,86c032b1,e290848d,ad2f7a5f) +,S(7101d56d,813abe1f,c50aa99a,bc7b2363,9532d79d,facc17c9,f2a5b4ff,50edf82e,62a0b9d2,bcab5b18,9075f6f0,e648a4f6,fa66741c,389a4196,a4c5ead7,cbef14d8) +,S(2dd4cb3e,5cb59cbe,b961af3f,d1154fbf,c21916f1,d5331ce4,c8a32ad6,8f7ad818,397dde68,7b1f6b5d,38e457ae,2f5fb332,74917949,801151e5,3d4fe19,9a34289a) +,S(509c6fcc,ae22b09d,b8f3d191,434e584c,9d17dc76,c268560f,2290d81d,53ed66dc,cbf69e20,c3f9ada3,41e32dfc,581f0ba,f015413d,735d33a6,260e0cfa,7a4e4d05) +,S(71babe5a,9458bf5e,112b23a5,3f87007b,66ddd721,32a45a34,2a9c521a,c2029aae,55ac872,a0275be6,4f569901,d84dca32,ea13e2c6,cbe608ac,de228185,34e031a3) +,S(f5f2144a,46fe975f,82b91da3,a98ebcb,6d5769a3,4e5fc50f,3ca640fa,152fa7fd,2fc05c22,2b20b895,5503f23e,627558b0,e023988d,f02993f8,f495750d,db6344fe) +,S(d6f274fa,fdfcf64,25972a56,640e53b8,15c4d213,8e4a72a0,b8ab3394,2955e416,738e267b,2fe0d9,5774afdc,7c4f559b,7bfe2824,ea6b7a49,d3220eb0,460ca733) +,S(81a12fcf,cc6acf7b,89f30fc,8f61e2cd,7882f664,55923993,2b8d3f9b,1d6e11e7,a8dbc6c1,cdca67b0,64b285c4,e2f69242,cf55f06c,5eb28868,d9bab656,eaf9116a) +,S(57019cc4,941f6f5,9ed34305,92f35a83,39a495ee,fb3e311a,fcef9001,cb8123be,a3d632f2,54083f5d,6f2857b6,9556205f,59578908,9d8d8fd2,4d10bf1a,e6d2e635) +,S(4205a71f,504362cd,576c4d84,c8b65252,3d4227fb,d6aa28a7,e7fc3d70,d1387c80,781bfe55,7fecdfff,c54d1c1f,e147792c,5ea7a1dd,7224954e,e110cc6e,18ab452b) +,S(1c42ad3d,f90472e9,e5c041da,52476ea0,896a2032,ccff22a8,fd7bbab1,4c3961f3,a5072a70,be702dae,f9f93148,4bdfaa00,1e2f2ad6,7d79f46b,5717147,17c5499c) +,S(6c9225cb,668ecf25,1f7862ad,999516c0,145faa37,b4fe92eb,561104f8,f1dc2997,8c12c1a1,e372baa1,4e9b1443,d3530548,d7d1d05b,fa354c7,f47ecab3,23993a31) +,S(72a0fd2d,eced2a05,6885dc81,fb61e881,b09104f3,8650a872,44e40471,ed189992,d9c67490,43bb493d,9aea4a1b,3a50da8a,e1c48523,9a480442,32406d2a,68487e6e) +,S(b1d531af,8faa24b5,69945ec8,1448915b,a46fd13a,f7fecb8e,16cd5d03,52c6c2ab,b3ba6cf4,bd36bee,66deba09,35bb85e0,b9ff7e62,5b5c793b,543a091b,dc83292b) +,S(da79daea,d6ea65e1,4e8747b8,b4546560,a9e5a99e,eb572f17,f2ebcf3f,9a307a86,f5b3c430,e0f2d4aa,2f278088,2d683c48,d84f926f,6feea88b,10e06930,6567a290) +,S(1fe7fb5c,99a69a75,a2276ca8,92f67da4,951bbb4f,ee4df8b4,a54c9833,d0d33869,e2b2b4c6,fe0f63f,d97fa179,331e9bb,55786006,f0425e98,71452aa8,361f177a) +,S(fcdb7de9,4eacf36a,9d662371,edd2b535,af33de37,1985ff49,6ce5293b,9d2ac00a,e332723c,7a9708e8,5172e56a,c4291760,baa17e83,72c98dbe,83a186de,77c2aa06) +,S(daeaa6cb,19bdb4b7,78077495,a9cead03,3be16d2,97e742c6,97ac18ed,e5b514c6,4545ca53,bde3c1ff,6bf32604,ef037da,93134215,7057ab10,cf6af451,e7753f4c) +,S(83e4b4c9,1a923321,196fffb9,b45d089e,7fa1f6b0,5ff45a6f,d099f7ec,fe283088,926c28cc,bf405fb1,17c5f168,20216226,4c89cda2,cf669937,2739ea05,279325d5) +,S(cd7f2b53,8363914b,2e83f1e1,c9bced9,32a682fa,cd72b46a,eda578c0,640089bc,ddf6dc27,a5281d3,b4d66af6,8fc80f5b,16cbb7b6,ebfff06c,6902d38d,4632ed2e) +,S(6f3f5a27,b19dbfc0,238bccc8,a9adcf95,adef6480,fd4ca405,454509b2,97a40928,36a56db2,abf62faa,b2255d86,d8a46aec,361fd2a8,65740c31,babb2e2,c551a85e) +,S(f7aa5c92,a523b86b,c27cf714,51f7dcec,fa18ef3a,9e839c41,a8b20c4e,30ba3b77,fa7d3ce9,8009f23d,f5eae927,acf1b28d,5ce4a2f8,8a92da7d,fcc1acb1,3c8cadc5) +,S(4adaaf95,5bfa6a94,b518f7f5,b0ebbdca,493798f6,72293e4b,36d5fdfd,5f641b89,ce675ffa,cff579c0,61e63c2f,36e77f3d,5c2571b3,aa99d3c2,74086b22,a862577c) +,S(2d737aac,3600371c,f6b638e8,8a29884c,978b783,cb843922,bd449e95,814db692,205d944f,13b21441,76d8276d,74da68e5,142aac9f,ba632568,79753c01,e54cf4f) +,S(7cb5d365,10ef241d,ac378fc,ebad8738,e8f2e6ad,6d838731,e5c82bb9,169d51d4,33b088df,5a572e8e,1010886a,d01b68f1,9f345770,81a465ba,8c5c784f,225f6510) +,S(9872a376,e530e254,8b623b6,b9dbd6d4,d123f2f7,30579f47,4d910831,7c714c0c,3de01ddb,3145d81e,6ac002ec,70086f74,6eb2bdee,6295f5fd,9d2cf8b6,1b222e58) +,S(8242fc8b,2e848618,ba0f26c2,6acac090,8eb21b4f,41a08b76,beb35f85,3b8c2f33,58b94d44,3379ea4f,829fc809,ce2632cd,78d8675e,45a29c58,e29fda43,785f2e9) +,S(88800a95,cf1682df,4e5bcde3,a96de21c,3353751c,5300dfa0,d0f802d6,7b60eeeb,2a35b86a,4e213e9e,c53dfe04,d91afb48,25bc8794,a1574ac4,53e81ff,4b6e453f) +,S(3c8e2755,9611937c,b7e2b2cf,8a87fa5a,e5c696df,fc6703b7,e1e65ac9,111ad87c,c54d129a,be0c774d,dd415707,bfabafdb,daedd1bb,2ea9cff3,bcfae0e4,55c916e) +,S(281af73e,a1f092c5,535557f9,3b5a8c94,54165f8,76650801,856bf926,19f06cb8,deaa8495,30951f12,ea157714,3caab5fd,d30f0dce,ac9b80bc,fcdb3477,dc01ea1c) +,S(6b353e5,3202f63c,69bce96,30535f11,1939fa,849dedb,92ad21c4,89f5174d,bd961eed,c16f285f,2eccfa69,d37a6d63,be5fad00,4858c80e,6fc4dfb4,2717acc4) +,S(68c184f1,a06685de,fd20f36c,82b5446,7446d5d9,8fc9c312,4852bb02,f35ed91d,486a3d16,7d94c66a,31f9e134,1652f658,76d49379,f3e3429f,e9f2da30,84f56532) +,S(5e884531,fa011576,3d36e1ad,74b22e23,f765db14,8b8e965c,80f7c9bb,7d561bf0,34c4f03,b137b627,3fbdb6e4,8ac09ef9,bc3c8ccc,e720853c,61ae58da,ee3a0cca) +,S(10c13f0f,313e5ad8,ea61ba5f,ed509aef,5ddd3016,c3339eec,ffc8f9d8,6f131118,28f6ad5b,324e44ae,64ee65c1,b86710a2,91a8e71,c33adbcf,a84f18fb,144dd67c) +,S(aa99d8b3,1031d4e9,8c078a68,7254968a,9141c710,cd8e4842,5a384bf8,414f5c5f,ee6eccfc,1dbdd5a,c9080cc1,ffedbc6e,64fcf847,ab9c0ce,fa91c4fe,d1de44bb) +,S(f087945d,a464e66c,4c73b58c,5034f057,b96ebe34,f5128397,cfadd7be,22ac6100,c5485411,d78fb395,3f229109,45aac354,1a2b2acd,1d95c38a,f51f36dc,d3cd92b2) +,S(2e4d8752,ac21c22f,e4d465e,3d2f5ad8,d9168080,b2b44930,e5de75a0,d9bf91ad,92f394c5,963c0817,500d5a98,2eccdeac,aa55043e,27a9a035,1a6ce245,a8d048bc) +,S(68b59755,44feb608,15a6ae70,9c2647b1,5c7fe073,aa6af8e6,202b9782,83daffac,b3745e92,fd86bfef,ab9d3d26,cdaf57c1,2a329889,cf646b6f,d6cf869a,f727e0c) +,S(15f5f668,e9576897,a287f131,bcbe1216,84f7a108,3c28c09a,afa77074,63dba49b,133e33fe,9bf06bb0,3b814938,7a099da4,77a3e758,82fb19a4,463ab360,bfbc368f) +,S(f2bf3cc8,ea752c11,db2ff594,d3f9b085,1dc9dff5,7999aa39,b5af2a29,30d50491,6e01a801,c5b7e4a0,a16af1ff,b011bc12,cb0483dc,6127fe52,c992b07a,9fd77635) +,S(1b04817f,46dae06c,120f8088,b3cd09e,267d4ed2,db14881b,bc32b5d6,345dc54e,31634e28,56f61b80,56a414e3,94a34ced,200bb172,e9a9aa07,6a224329,61f55ecb) +,S(693f066a,bca2046,ffb860f6,5e769ca2,3d1f46a3,6c09273d,afe5eb89,d2da45c5,719dd749,5c1b1938,a92af84d,eef309e6,ff1978b7,9adadb96,c58caf2b,625fff9) +,S(3fb25a02,bb232d18,c798f688,b16193ae,cb2eb9f5,e124c999,225f0720,63417008,90db4fbe,fdbf8a26,ff9b4afd,355e3771,c7c95891,68e2abea,264aba44,ad74707c) +,S(4c878f4e,6ebfed8e,e12a0a6d,17298b70,79d9de5c,6a7b5359,5ddefe4c,db82a79c,837592e6,927938cf,dc82252b,2cbfd9f6,cbff1950,405b4511,f2c21fdf,a3f72715) +,S(5ccaf6f4,2b75e152,49263cb9,5fdb34a8,770e8828,98a1a0cf,5407c48b,b9ad4ba0,70851419,379e5e2f,dca9613a,a9f92fd3,8ad8904e,e0ce0048,b2510943,ba8ee24) +,S(455907ae,713d1ec9,3792d488,7d9857bf,a02bc2ce,abd2c599,cf576f09,f7d09d11,1fc9ee5b,90a039f8,eb3200e2,ee58022,3f0cc699,60221d67,86f0deba,f13ca6b9) +,S(6f7acd2b,3683482f,c2c2d55b,eb62a89a,37578a34,417bcabf,ba7c56b7,bec14f0b,6049db59,b6210e55,b06401d6,17247d91,64e84e2c,b8de91a4,d4998c15,6f46d621) +,S(100f00d4,eee4ccf5,ea2558bf,92bec83b,223fa214,ad692ae3,b0a2ac93,c546d558,fe055fdc,1ae02552,1557db5b,96a62c92,556f918c,ca908708,46ffa1bc,8192b65e) +,S(8650c359,664c9f15,935dd776,bc6fbcc8,d9cb02d4,c22428e2,aee3e3cc,6e9d0c6f,89dba800,919866cc,8c16895f,785fc9cf,2661f78a,9e065472,652b71ce,d5ec8732) +,S(22b6df12,b3932756,713e2ee8,2d296c64,5d10364e,cca1ff94,9b477fa4,9a2ce5ac,ac58a22f,42769cf1,e2e23308,b3b5f139,4d329323,4bbd6053,4817ab5c,624e995b) +,S(ce87a23a,1554ae1b,9579ae96,863128cb,926a0cce,e51f17db,75155607,754b5992,4bb953b8,9d590216,e326f23e,66768c0d,17626262,6fecf80f,97435b50,d5dbd503) +,S(e3ae6365,29e3fe6b,cd1c89da,d72b17d4,8bf05c1b,c487ad41,d3b97838,a2cbc19c,4634e222,316b6ee6,c7616cfd,cddaee07,7fb2cd0d,26dd9f81,9d0ba43,313b3f4a) +,S(2825cc59,3a0678fb,e0d37d42,df72037b,6be96e98,18c52c49,fd426d75,324bd620,ea0079c9,2ef91a7c,dc587343,7b454763,f2fd4adf,561cd023,8379c8cb,1d281f6e) +,S(a6b2a170,fb23ae2f,943408ef,60fcb145,106735c,8876238,5d0fdd9b,75a2c46,1ab40091,e000012,60837529,58e3134,5f260890,d1bf6930,ddccedb1,dce20255) +,S(99a36f38,759f0a70,d719e3d5,b741a40f,daef1ad2,bcc65293,3992f134,39ff339f,a36d4b07,a7258053,61430332,6be79a,61ce8eb6,97944c6d,8bbf433b,a565bb66) +,S(e511e0a,de5a9be1,1b8513e,a5706258,6de09e2b,e2df739f,d647fd33,7890d36e,c6cc03ed,e9e50830,bd5579c5,9d6db693,dfa5c057,b1c214da,e4064804,9cd7ed70) +,S(bc9de66d,a406288c,a8a94e96,5ca16dfd,379608c2,63222a24,e3fc1116,20a82125,ac471a7e,579cfeaa,fdfdb5ff,9cccd4e,dca4202b,1b0149ab,ba9f6c09,aa219626) +,S(e98cd505,bd593bc1,496b1203,436f6038,ebe3fa4f,361ce4a6,54315402,a74c3a4c,1350c197,1c7979ca,7464c4d2,39b24a55,a1e50812,aaf92479,d566fffc,9135d977) +,S(47c0c788,2490ca53,37cc668c,5a549bde,dac661cc,f77534ed,d11f7ddc,9e0f37ac,ece10949,be122263,26819032,a2d952c3,60b27e2,7e527673,e8fcef08,a8f27685) +,S(e8224d65,35ea98a5,e3fd8833,7bd167cc,776f89ee,7d0ccfdc,46a15fed,93bee5e3,44b260e0,e0b1e1e9,383041cb,1dd985e7,22edb214,ae58f784,f174ba84,ef51c59e) +,S(c195ee35,5880dd77,67e01659,ecaf07b4,571e324b,b8a1a4fb,75265af2,3ea74709,95c39cef,f781f53f,31bde05b,d0289313,4e478b2d,1c55e741,aef8035a,2ecd4226) +,S(60d989b9,c9cccc66,139bbfed,e2902a95,fb9ca9a8,6c2e863f,21eceb4a,7d73c4bb,8295928a,a48ec1fb,775ea29d,9da1ceab,47e82f3f,1e6ef7fb,c7505e26,92bb51d8) +,S(a33b33f6,9db29609,8cfd34,caefd3e8,c3c0d863,ab695b06,b47d102e,f827fe62,669d9d96,842ee809,2cc31cfe,baab0f1f,4007c3e9,e7e41be3,7a08d221,1c6bc905) +,S(bd25afea,d9b8c833,fe332a2a,a9f3b627,d8328152,8fe1422c,5da90163,4b971584,35bb66e7,35326f67,63f4f38a,c18f8412,26da97da,c9e66902,f28904eb,b49cd78) +,S(4d7e208a,4264b565,d8563cd7,80773012,581e8688,a62921f2,d6a334c3,25625279,6729dd4f,b45ecd25,2c5cb033,dcb2f520,dc928ca5,71026fdd,b42943e8,b5da9988) +,S(5dd46f97,fc740db3,ec56348d,ed73fbbb,c440e3f3,33c64a3,a37b7a73,7f0e987d,7e2d9ee6,9e1c07a4,b764cac,aef3d780,e2d43288,2863f76e,35ff4cc6,832ede1a) +,S(4631992d,d72c02d2,2073222a,d35917f9,2770198b,ad13a847,8d3c9ca0,6ac91a3f,e28ce87b,35a69d5,c43b685a,e59d5f9d,ccf187bb,62517a92,90992b39,86d9e1eb) +,S(9153ad32,32177422,e03b6739,d5654209,7fe04d22,28b1e873,f02e990f,8936d1e3,8eb9f3c6,b54726b0,b4e867e0,5ab2fbca,e76d2e20,ce07983d,6edbd5fe,ebd0cc8d) +,S(939a7349,28fd798b,5036e2e9,60360387,b9c080a8,982d4530,78415667,848c2eff,30d2a2d9,5890d023,7d117cde,2eb3c532,e419770a,8783a7dc,dfe40674,709776f1) +,S(8e67bb29,9f11e01,b50be7fc,bee1f73a,5b335f5e,5ece8619,9a514156,dc243f3f,7fd0cb92,d6f9cd8f,bee9d337,90a4492,b8a7fa02,a0914c48,1f8becf5,d9a9d7da) +,S(a2cab3c2,537d8fec,b2f891a8,1da2f523,de4f869d,3c812806,855013c,73485ab2,765d058,c681af53,36ccbc8e,88d2391,b4894b18,15441342,4c4e73ac,1a8e0d71) +,S(9b39be40,976c13c2,faad320b,9338f985,b0718123,d2fb543,b65473a5,3bc2fce0,10f8234d,455fa7df,d09d76ee,41035515,9b560db,7b92988e,a42f9e9c,f7baabeb) +,S(35011530,6f2975be,73e7685,6456c94d,700e9b1c,4685639e,4f60efd6,9e513692,5992efac,9dcc0a58,ac6e00e3,54e44582,7e2d66c7,248e4b86,f8c216fe,a9e44270) +,S(df5a5b75,d96ddb93,9a341f58,7e1f997,3cb9e799,b04ccdfb,9907b57a,7b005d1f,3fd070b9,8d759043,8a53c302,b7ac0dbf,594094ad,7101d500,1cd5d687,e80066f0) +,S(91f14eda,a0db8441,10fa531e,eac54762,d52ca420,bb872327,6b383587,d40fa761,86cbd213,358d1f70,c3f6ac7e,913daf0a,47a80f8c,bd72445d,fcbef37,d0d71e69) +,S(53ddba06,46853311,9fe95719,15a9efe0,bc7fcf80,59d638e0,be6c1aa4,c5f21ffb,e59de2f6,5e583ab,5ac86c77,fc298301,70a18b68,a1979074,c21c0d8e,4a562567) +,S(56599462,4ad07c16,607afcd,76e86218,b15b50b6,9df84695,e60a15f0,3d7bcc49,c6d36636,ef58556f,9b688db0,eecb6bd4,5a7b30e,a9748732,68be57d8,542c966a) +,S(76fd5413,fdee9cb9,7f92fefa,5efa27e9,9aab744,e1e15029,241e35bc,743307a3,bb23f425,9aeb64e3,8ae82c3,b4691bf9,3b4a719e,a8ce076b,d0345a2f,d02a6d05) +,S(511ff159,2127502d,7499b988,7a3b3bd6,1242518,58bb62e3,dc1638be,89204a0e,21da5ba4,34b7819e,53b51e46,29f5fb77,e739ae5,97af55fa,aa09500a,dbd502f6) +,S(8e948cec,51635ab9,5a057404,39ff17c5,ae2e05e4,523bf2a2,3df28fd9,86de6b15,e16aa2ac,6c3d34b,9535b795,29a82b67,34bfa260,4a74ebe8,86110d73,ba564375) +,S(ebda8670,9277fecf,9b8507d9,40da6c74,210c8c7e,ddcff0d6,e3b52ded,3bf57095,3ca95e8e,112c8137,fe8c5088,bf041674,fb657260,70625890,1fdc5626,7655d654) +,S(eb5ffc4f,559f7ad,2469f48,1c730925,1ebf3863,357dbe72,41a29205,5b667682,b1f72d74,a5a16ef1,d55804ce,76974f46,61a49210,8a1a36f8,a59484da,a9bcbb96) +,S(2a93ae8a,d15c82ed,19fd2161,4a7a65a4,cf562432,623bf7f8,6c765548,b02fb57,5a949ca6,60a1430,9d4baa6,9be69b34,848e9874,62471d74,54c4817b,336584e0) +,S(9ac4a3e9,f1c8d115,138bd299,b6fb9132,c5d64a92,1fd94adc,82eb4ae,fa64704e,47f0eecf,a9eea827,ff339f3,48e67e8f,da9f00e1,a6b9086b,6f5441c3,7ae1d335) +,S(add254af,39d99d6d,355510d7,4f8985ad,3d8ec1e0,1e8d0210,27e80049,f555d65f,5b147a1,fc4bdeae,6c2f1224,b35e9e61,ad0799db,53597ef2,a23a8f3a,344dc526) +,S(d374d326,52cd006e,3b27b8d0,3ab47d44,bfb1c5d4,48adc992,5f63235b,c34aa128,3cc6ee09,c04d4cb0,aae8b1e6,6018640e,d0964fb7,148181ab,e9fd0374,642ad9a3) +,S(fa7632b4,78e5389d,cbf380d,8efbf6b1,d4bef9a1,70aa3517,e4c2005a,71a283f,ef2bcbb0,4b20be5,d4bda0f4,26dd0baa,31037d2b,7b530e2c,24105c3d,c817ce89) +,S(68ea197e,76af6950,1633ff9e,c825a817,80c7405d,ba513f96,6106632f,ea73ede5,633a5f90,587d4ea1,72129820,2ccefb30,c14a052a,6c0ca723,65e2f91d,53b3ff4) +,S(8874397e,1813f0c7,6946a84f,b05a0f44,224bb110,8aee722e,736e807b,b045b73a,ced2e2ec,85ae00e0,2952f55d,3626b613,641d2a8e,84b4c9ae,36177bb6,9ef80d9e) +,S(2ffe42bd,89256069,2e460701,b94208d4,85915043,8a85f71f,32246b8,5dea7594,6e7e4050,a35f1570,f8cc40c0,862e9cb5,59e744bd,8788646e,b0dad904,8b2777d8) +,S(c6d3a6f8,c997cfe,779a9a30,79de4bae,c19c226a,21f166d2,71ab4da2,cbc6defe,a8f8a618,3f6c8b2b,1486e60c,337725c9,9a9adc07,7dbb6581,e5b0119e,ca10f418) +,S(9b51cd75,442203ca,c4b8aba6,e9829b73,abe29f96,92b8dee8,500e1a90,9ea9767f,ed0ee32d,6042b6dc,dc818dbb,8cb00619,6bfeb2d7,88f35626,789cabb6,5d159c51) +,S(952c518f,775c8bc4,dbd7629c,8dcf8807,1b208033,8aee2ffa,eabad5d0,be6eaa1d,8a3b10a3,d9343d39,e7bef8c1,193f5cbd,717efa3b,cd2491f0,2dc1aa17,2e5b629b) +,S(49a18372,63eb11af,77a2e33d,2743393a,7eb269aa,f64589fc,8f81507e,55e8ee4d,7feb4a59,64b781b9,640d60f9,4e7eb291,6025d190,95945aab,7ac7771b,6f96cff8) +,S(cf974d8f,46aceb5e,a8c04e55,703b5a43,ac577e84,cb174abd,88198e1c,12708c9d,c50cf6d2,afd79d3,ce275e91,26bdaf0c,f46c1eb,536d0753,9dcf6c2d,d79afc35) +,S(461a831e,8beb6da0,df92dcdf,2697d551,cbf8f903,138d13f2,ec9b7fa,4a7d4763,e5fd85fa,c251705c,27d4e870,64af33b2,ff99b19,14496d96,6fa18916,faf40e01) +,S(eef4eb8a,9eba3f2e,b27e3aca,6cce7335,49f2656a,c26f1921,60c05bb8,fc3f1165,58f74526,a812ddc3,713217f6,fa4be02b,7062d042,2dbf5625,abd1f422,58b54c36) +,S(d674ace8,a7e8ae,d4bd4b7f,235b9f4c,41ef4355,4d9e6e44,3b6a26a2,d16f798f,8a25a7f7,896c0dd9,b1639f99,5c4b3df1,a3536104,b7d59348,c2c56c0b,bb21c609) +,S(a8eb465a,8a2869cd,6419af81,b3ad1355,1508727c,2b2494a4,93b5ffe6,2c1375,f1a27219,f59f29c,bb93bdc0,6157618a,454075ab,b95184e6,a4601ef4,eb2c8a1f) +,S(ccbd9d,6253fae3,f7d2527b,17854e21,58581e95,11a1f11b,55e3e04e,7326e6db,51ddefc2,5d9083ce,e9999e91,cde32f70,344ec937,d6aa5272,3dd62496,c4b0485b) +,S(524bc1e1,5c75e8f0,6718d2c6,da0f6599,c8b5d83,7cb9b48d,615e8e46,49dc6659,f6c91d14,72a50c31,1bb202b2,3d76f224,b55af957,c7bf3c19,69d175a1,d36ed19) +,S(520e667b,a0604a23,dde663ea,1a29971e,7e753301,9b2217af,296b02f9,de1df35d,9c2a2c52,290b6927,ac566ea8,4caa31ef,cb19b65f,29b4833f,5f4eae8c,f12b38bc) +,S(156282cc,65317dc1,3323aae2,d5d83e8,b7113d59,a50e54d8,dc54c1a1,ffc85d23,840cca23,67da3c5a,15b6427,72f0cd7e,675bb8b7,fb5dd58e,8cda9fcf,cb21606c) +,S(15afddb0,5adcc8d8,f1322a7d,f451fee9,873d4b8b,78b0c1e8,1d99f002,84aca6a,15465563,a129272c,b5e25bc3,ac76c52e,b4e115b7,b216a40c,145c4699,175cec9b) +,S(9eec4fea,e9508445,4bd275e3,f8d0d6d2,9040ae95,c8268f55,918d5f3f,2f75865,b7a873a7,5fb4ef70,3d62a723,81df2ded,102726ac,81685725,424a7733,8307ed7d) +,S(3aa7be96,660652c4,de1c82f5,cce1a864,c37725ba,848180bd,52e4dead,1a33f60c,f323d266,3e5d14dd,18fbab76,271f6c8f,32d7de0a,42724fde,f6ed3582,c886c402) +,S(bae9e070,a8e5a976,8347368,c32b4287,c7a6a20c,b491bebe,fc6acc71,aeeecea7,b5791703,f98ae848,1a9c66ab,878f7c27,d37a3e0,133b4e36,82ccb2af,b518e8ef) +,S(7b12ed88,be061d1f,7dab874b,17602bb0,ef5ccefa,54f9ff40,e753312c,335f5f86,70930f8,c465292b,b02ded5,59a235e6,c4c83480,9eb94442,8440846c,377498d6) +,S(9eb22b3c,8faad620,ba002990,4a5d8d1e,8cb4a054,179e3310,73f4ae8c,def4e1f7,6d58b972,ee88dfd9,4e429a2,4f6961a7,d085f00e,8d6f8d14,ff2066e7,df68bc34) +,S(bb2aa6cc,d8402cb8,e7a9a6f,a755c66,366c659e,bd2e5c85,7fa486e8,aa86b857,443e7128,674c040c,b0316d9b,3908bcd3,298e727c,c805bc8e,ca58894a,d51f4130) +,S(c58704a9,fc3bb18b,c460c4e1,f17a880e,c0dce45b,e2caf759,72f55061,d59d30d9,75216472,aee1c9c,280aef07,7208fe42,136b495c,f80d8a79,e8309272,c6c4d6a7) +,S(b7d7c721,70af0b6a,489c41a6,e817da2b,ce59f30c,88a82b11,83a6af8b,174c70eb,59481a78,52f3726,3a02ef48,dfb366ce,7bf170b0,af3c2000,2c1053e6,5dae1ef8) +,S(b1386833,25f5450b,f4f68dc9,93d72fa1,1e636a3e,8b881ac2,f237cc44,42f3461,64d18f1b,87f9463,10627931,cb003c09,981c4a94,969a0df1,7f717830,4daa6cd6) +,S(7e27af99,500cb8d4,d812a82d,29ca369,5e543231,8432c9f5,96f5b76d,c6d1bd8c,25a477c5,a275daad,10973822,40961da7,5385a367,6dff887c,42bd904d,8e885997) +,S(62e04f6f,d953c744,aeca984c,bad13c91,f4e09c1a,d5441603,2bfbc277,5ebbfdc1,4f1f609,db0befd5,fe781afa,d21efe44,846f9f78,9ed9f99d,f3291eec,3cf3fc89) +,S(b08a1f84,a3cbc3fa,f952247e,6d8d8d9b,1ba3ab01,ba03ef8e,836b94ec,dfe2e2c4,5027889d,e524fd0b,e6ada02f,4f33d1a3,4d0c3822,f0ca6651,ecebaa37,3c54692b) +,S(d417933b,c7a8f68a,9e023d64,498b5117,850f8885,b6254256,f9a12a47,538d5bd6,7ad14679,21349d14,10e35750,167282ee,9a6f6044,b6c9d71a,633f4475,5b432ed7) +,S(575909cb,46a36dc1,c270267a,10a62f31,941fb7bf,3699aa43,1a3bc770,fa37d5de,c12ef954,c937d6a7,bda47e2e,67d9ebb4,9434cda,e1571ec9,f604c41e,b49d6189) +,S(5298ad25,cc5a6bf4,d88b693a,d32a61fd,efd763f0,e4008ca0,eee17730,4365de57,75f821d1,66b60185,41cf7653,9a0cc41,597b8b78,10fd1fed,f0da4542,3a26d5f1) +,S(5aab0fa4,b0beb77,d5d2a8fc,c95d516f,1dfdc402,3e3d36b1,4ecb206e,ee8c5ff,7a4659c7,7c062356,c51ee28d,fd0cea92,a1f36d5a,b78a3ae,8b48ac9c,7fc63fca) +,S(482fc791,7c739041,41b69e59,62b0b815,8a9bfa00,f203afa6,46973980,9b250a23,89b117bd,485ac6ef,4de8eae0,a9e96edd,a3615285,e33282b7,bf0b6a6d,e11a9c8c) +,S(a576ceef,40728a7b,b63756f7,f3095c75,ff2ef84,c7933d02,b9dd8a0b,a6046653,b4c707dd,9d880fd6,d7a1ea13,87dcb6a8,e2433e21,8ef3a7f5,e348d2b3,f9a9796a) +,S(3c9d7c33,f8c62b35,fe977359,f290dbd,c2b46fb0,a2fe126c,d06e0422,54d1527f,cf92e34,3ce9f624,84c04c9f,d97569d6,67065598,9418d858,aa7368d5,bd6a2df1) +,S(56bdd1e7,363c52b8,2198cbe8,62ed6d7c,7b96d184,7da44036,2401368e,b2c83b89,505d385b,747c9545,6669809a,a9da035c,364e7971,7cd89417,3d1d5d58,298a1869) +,S(99e0696d,ed30d242,bff69e9f,ff4ec88d,eaa3de35,34dc7f35,c2bb7df5,9f8b440e,2cd1fc77,3bd071b4,c9695f25,458be688,f662f7ee,ae8f313d,9c373172,6185acc) +,S(7d5cb46c,81f4a4ec,f1e5d913,1772277e,d17de7ca,7a4b277a,d6b135e4,dbe61916,cc854503,d73e8034,7a6ad7e7,f5bab321,b130d7d,3d938423,9e0656d9,74971849) +,S(45cb6ec8,9dda9aed,5242347c,a20377bf,c93ebbd,50e48ea8,159530f4,4f4a250a,411a2ade,aaaf43e7,240bb0f7,cde77d8f,846bc700,4721f6c7,4d313fbe,70ae38c2) +,S(a7e23331,bf08ecce,2dda8c2e,a6c3c4ce,9bbbe3a4,4d40068c,e39e94fc,edea42e1,d1f12d24,144bb258,dcda7060,5348c1d,85faf076,fdd3611b,ecf6c34e,843788e6) +,S(d81aa0fc,b0a8fafe,d4c67dcd,6fddd414,80cd5548,cbd6aa58,35e5896b,18797f12,92af7ad3,89320814,bbe53ab,4cb5bd26,3df11ad1,8d2ef235,ae9ba163,74495d8a) +,S(8d379fd1,fc0acf5b,c96d03e,b73b340,5a7326ec,82882235,918a380b,c3e2669,f8c6063a,eefc0e2c,ef94d8d,ac4e5b5,ccccdf25,663d993f,7f9a0172,6756564e) +,S(5e20f600,6f533af1,8f3b6e65,17aaa2a1,2876b79,c99ca059,c2791a1f,1e466e8d,b23fb129,57640a9d,d38bf206,7649216f,50b913b8,69d241c2,baedd5e9,dafac9d3) +,S(1a0a4f54,80d37257,c62d1b0c,18dda7ce,f2b64754,be9a3d77,b3d80ca9,215026df,2f76696f,f4001927,9ceb5652,44d4a60a,9e353266,42bc2138,1191a51d,7661ca1) +,S(be868184,dc2e91fa,b11833b6,f78577f7,8c190220,a2b46551,53cc8ea0,73a217e7,6ffa3f78,1c64c118,68abc331,beb8c284,2919d593,12bad699,53edd222,2b98a31e) +,S(a4650db1,917b10d9,1fffa809,d9f9cdaf,f07faeb3,8f0ecda6,9c80e0e0,fd27592a,d5a6fdf5,647e26c4,1d7b9c78,7880c76a,b0cbc23f,d4c1840b,78717b34,2ade1422) +,S(944b1701,4a7c7eaa,754c9e03,d56516d9,e21e254e,9a871683,7a14f19a,9ebaa517,ee198337,3822c796,3ae7df88,24687dda,eea01e83,c82e66fd,baa746ac,485a6dae) +,S(f9e76020,cb9087d3,a60ba7ef,7ed5e552,3e5a3645,f61f9ee7,27d630b7,98d37ede,28371db3,433bcf49,f6d77711,d7ed9101,f5e478de,49c58103,b021457b,7a0b526f) +,S(7ac0c7bc,e17509a3,e4dc004b,d18c322e,600aeb83,8fe2045f,6da348ec,6f178b41,8b5cbafc,33469334,4886f60d,ee7626e5,36e9a977,60c0dd18,7bab7e45,6b264956) +,S(1d7ef98c,c8520f5,2310ad12,107351f1,966b651b,4b2a39a1,7a47f658,857e3bde,2b78bf4b,7be6f1ec,61cb235,a26e252c,71d91f58,69752719,8125712,55d47664) +,S(fc57f5ea,b40add8,f00c2da6,c7d24540,1b24b6b1,f102836b,4041009e,2fc6d5f0,11d3e017,bbc33913,b7861dff,bc11bca5,5aea26dd,f956d21d,2f333755,ef823af1) +,S(340c47cd,3b473c01,80526815,64e77f7,6ec29eb4,b6603985,d6ef7b64,29e2f289,994d98c9,c1de0dad,d27f3386,eeb7da40,6144e060,ef4db403,ee8a76cb,8e21bf89) +,S(81b13929,f08e9a23,69127ba,3e6e839b,8e9cd05,b19a9bf5,2292148a,26bc47f9,b6c33861,ae8fe20c,7a6c7830,4dd03fc1,a281ea57,59661e74,7f9e904,e4261226) +,S(6f325fba,15a463ba,4a61e2e6,82655af2,72603643,8a48075,f76c9882,4d7e252a,1f205971,70f9f48d,5421b73e,97bb6260,cd2235e4,6f611e9e,99b7f8ae,cf435d45) +,S(4b388e91,fadb26f9,b23b015b,398c8666,91521b8b,484d4510,b3c162d5,834bc109,ade8365,9d59c363,3191c3b,20e395cd,13ddabe7,1933045b,cfd8e941,f2096d25) +,S(2d1c0ab2,83c80dfb,ead3e083,76024910,c1d97acd,6c8be069,252bfd94,ac1a0db6,c4856c74,e5ef2e6a,17ebc35e,3b310f6f,8e7b043b,abfff733,aa3ed9f8,5a391c98) +,S(4c77a1b5,b88ffcce,1f98fd89,251c0085,9d4197f7,d45bee5d,edfded14,a97e5b87,48b8135c,b067c292,6c316424,2392fb06,f698b6d6,e98b2ffb,bcdb028f,4d85e5bb) +,S(d39cd5fb,11cabce0,e31f6fac,10cce3c1,c0bdbcc7,294119e0,2b433b0c,20e3a4ee,487695cc,8a8ec5fa,aafdfe25,3aa7d635,8d44e82f,77328e8e,4541f7bd,f629bb5d) +,S(238a05a5,519ff4e6,29b0f86f,9d259eee,4e620685,a2f0509a,cc9fb1eb,4e89f5f,6772f6b7,816018af,ec95717d,a6be2d05,3d740ec1,80241798,117ed39f,91f3beb1) +,S(c146bf13,72816407,b5f8532d,91210d59,a8a6db2e,54fcfd3b,fe910365,99f7ed14,e952ca9a,f88779c7,eea67194,3df6fad9,72b717a2,19d1eca6,33106f97,2dfdf0b3) +,S(4cd9154,861edfa7,c29378aa,1a7d6d0,83b134a7,572383ef,3010f34e,19d40bea,9ad99f1c,b5841c57,5f7db959,362542fc,40b0cbec,58d16ce1,54c5944b,6ff2aabb) +,S(d35f2995,2478be06,e86b342b,fd2d2cc5,ede30ee8,509da11,504bbffd,5884765d,a0f66db4,a21462ee,e51e226e,2d20d896,2c4edb1c,babc45b2,645968a9,c7810fb4) +,S(caf9c953,ef1f57e6,905bfec0,2fd64fca,92ded9a1,9435ad1c,a672cb7b,117c6fa,23b01776,7662984f,9c2f9e43,756ed3a1,3a574960,558db4ec,8670122f,472d0ccd) +,S(4bd40ba0,21d2beec,ec7317ac,df3b719c,179ec012,1274a198,d0ebd9d5,165bbfaf,9a5751dc,d7885a78,20d8ccfd,1db3e3d,aaa2bd65,b7b6fb2a,2d7b2902,c629d81f) +,S(560928ae,7b15a63,62eb4444,d4c0e069,1ae43323,77a2de40,83f056b2,70259814,ae97006e,fa5986b6,5da4ddbc,2bcea172,f12945d9,b6f5184,4027085d,bf644794) +,S(7870209,38e53dac,8e250835,9e41e313,25b09faf,95b03a8d,c25e83ae,f8255301,49fd164a,915e0af1,a66af8ff,d215d1d3,92e4996e,5ef68f8f,51a4b895,145bbd90) +,S(7aa3742a,6c82c90a,7e6c1b04,a41e4643,47925d,66f4e7c9,ab2aff17,e64932fb,7317dd5c,f2cb9b3d,5cc0fd6a,c433d1be,d1dc8345,b26e10b9,a2b8cbff,ce2db0c6) +,S(7a400535,be3b134d,4572e0bf,75c13098,dccc0f04,1c10068d,31e2b0b9,149c2e08,c00fd102,309626e5,a2f97ef4,e0374a3e,de0a7ed2,e45aede1,40521086,5d10466e) +,S(f4d71adb,438460c7,9003e150,c4143557,ffe30efa,eed122f,dd97c572,e1dbbbb7,e73588e0,fbae054c,140c0474,348b7ce2,92a1976f,e8c940e3,62c29ea4,31bb719a) +,S(34b68d32,810bd1ae,51d0c82e,ef99752e,8206aa04,8c5c30,7c3e9a25,b2d68b94,4d044a,6781875,6aeb8982,61bff840,a3ab951f,bf60cd03,e8befb25,97203c7e) +,S(f83b78af,f18f22b1,f2081707,3dbb9c79,4f180b0d,8871a1af,94d16d29,5c71f1c2,93ea5b8,c7847ea0,2cd5b783,5021d37c,dbbd395e,fe6eff8d,866e333e,9d6083e) +,S(a4a0d5aa,f521e1bc,2e818063,f4575f1c,99bd2447,80eaf848,2737b297,b2deaffb,3906373f,2111a47b,102b0294,f9fe1a4a,7ea9a9e9,aa2d9595,68ff8419,9f1abd97) +,S(cc211da7,28671182,1f0bca25,b9703fdd,ac9d0277,7e1829b4,4d9921d7,998011ff,c0cc46fd,5519211f,3a4cfa43,d84e5b3,bfb316de,39a5f4,9a50b1b1,8dcef321) +,S(8a07ed5b,e0397b5a,8c33ef,108df270,4b385c45,c8296593,1ed3e391,17b2f531,432023e3,8fc1a637,fb5a92f5,9911932d,f5cd23f7,eb16ef68,c8c573fc,86e8c1a9) +,S(8add7841,86b68399,b08a0bf2,a92a3987,36fca803,3807b564,f97af438,ac70d49b,758cdffc,ef477c3a,fb3028a3,2866d860,c65aa2ef,7b3d6261,9664ace3,658add34) +,S(ec6b9f2a,a1cdedaf,306b8a5a,b021e430,e9931126,a1c505d4,a10e71ec,3cc60453,8139b262,40e2c1ca,8ec89808,2a37d7a9,b78a7e5f,6330ed32,f9786cb3,c4ddb722) +,S(22ce2541,dd8a47ae,227dfec0,95ac361b,88ae2cd2,c9547344,f551f6bb,cada196a,68ce4f4,a677a0f9,60aaf4a4,f8e83a24,ebfbf46c,6ce2a470,255d2ede,c4431581) +,S(ee7dd0d0,3e5b6d8c,ae78caaf,27b902fe,4136201c,12a49551,bf208c0b,f88bd33b,aff0eef0,609bbf68,7ce2aef,9f48f87e,67aedd82,e5342159,3809cf5c,da4ac004) +,S(f7f9a352,ca18b2f4,3aa18c00,9ae0eb31,17679db8,d9fd7e5a,41b77e85,b54140cd,afd30383,ccd2a6f7,ae76b953,5bc80330,4419d38e,73e12d1e,dc407ef2,f3b50326) +,S(7793ef5f,8e57e872,ea9fbb18,bd710ab9,6ea4f646,134d3308,930cbf62,e73f0e1c,8d5b3b79,3573090f,a4a7e7e5,c38fd987,e889bc3e,720e05b2,43e856f6,32ae7cc5) +,S(db743211,ba814bf,e6371ddf,d03ba554,b558548a,a90e81b8,e1421321,656065a8,8236f24d,965a9003,84b382e8,d772d7e9,2dee2ce6,c3cb3388,3ea627d5,4a5170c4) +,S(48c22865,6e51199f,6306a6f1,7dac1e6a,13f82d42,61de0f0a,9158ba98,715d3cf9,19a2a4dc,35d2bd03,5bc5daa2,5526598a,8eac11c3,52e5fe70,be726531,747035ef) +,S(70a28bf4,ce75b491,582b48d5,9a5069b,9dcc1e49,c41702d,ee5d688e,6e643a59,7183750e,2995f655,1b58d5e7,21a5f33b,69045934,27f27f34,f8ebf62e,74e49de2) +,S(a90d8505,596b3d01,a5e8dad0,fe652cb2,4a008a7a,61ba3cc6,8401a7a5,5c2e3132,f98af047,6e925c87,e13bb7db,f992b81b,1be564b6,8589cf2d,b79e4800,3ff7b0d9) +,S(88647576,8e960c09,6aec9832,448decac,6574491c,df737dca,dcc42b84,d7e775bb,ad94bcbb,7309f483,19077724,2582f5cf,a39ead6,a4050afd,89a49ecd,7a9090bd) +,S(c505d2cc,ef72aef5,8130f472,2ab3b2c2,3a6864ab,bcfffd5a,725a6df3,fae02112,dcb82329,cc51dc7a,54e7104,462997c,3d135d6d,5c82463f,45e875f5,8738652c) +,S(24a1d4be,c709cf8c,8b8927a8,8bcfb11,43b0d579,10e0900d,68fbb682,d4e14df9,9ccab057,8440f6a2,edaa4f41,28f427de,adce5584,692b79d,624e8724,572a043f) +,S(48c44581,51df1654,fa78370a,6975e59e,576eeb40,e94f636e,72aeb37e,8fbdc4bb,f48e8dfa,bb085834,43a7b495,ced76171,348e92b0,41b9620d,3cd5a84a,d9ee4eb4) +,S(42a7838,d33d0b15,b4409534,18024a33,e93ccad,946b50cc,a543ea1f,1bb457da,dc2f0e6,4f30e973,cdf6289d,d8f6455d,51c2da02,bc4e1d13,6668250c,e4dd791f) +,S(80988f4f,c2dfcb86,f1f65196,d93a6cfd,5c664e1b,5f8875d2,61e7c4f7,b2ea31e4,1e695c33,b526d582,6210e694,49c4673a,8697e1d4,a197c9bc,a3ecafda,2a7d5b93) +,S(a0ae003c,65d7f1c7,b65cf828,124701b3,876d0be,587c2589,9a618c4e,7b79d480,d7f4ec52,bccd57a,9515e80f,2c79be42,a6b53ca6,253ee13d,ca33c917,ff2ddf02) +,S(392f57a0,ebe08b06,cb4946ff,3c1df6c7,c5cdd97,b9cb2190,dbd4678,cdbab3bb,1be9f9db,dfca7981,b3dbbb1f,daf50e6b,c5662fa8,1b8a58f9,9953eebc,d1d0be1c) +,S(cd904f6a,3d8c4ebf,6ebc4e5a,e536c544,4a04e278,389d771f,d5e7566a,fc592d3d,e3e10f61,a15399c5,f3f29626,af323cd4,3d6572fa,bad4f02d,cf76c0f4,9785919f) +,S(27a4480c,df5782bf,52ddb140,ea5a908b,38dc1ec6,a570580d,2b72b922,e7eb05d9,bd96ddd8,1a6aca1f,88847632,5a6d48c8,4d61e76e,b4d0d957,15d39f80,faa42f3f) +,S(6673ae66,3511292f,fa4dd8cd,bc0f7b36,613c56d2,775602ff,a8cf9302,4329f5a5,d8b4ffd8,8ca2530b,18d85762,529d056,e8048cdc,51730082,2d24cf42,e4053141) +,S(3dbae13,5c395043,d5b88161,4dde355d,5a669076,98c36b23,ac4c24bf,80e34f2a,b7d46059,3154fad7,eaa37c3a,291c6c67,16df2944,4274b044,a9f12ac0,a34139db) +,S(f2db4c09,1c3c606c,9784f6af,7dbfb26c,2b18bae3,b22f13bf,4188d761,6cbc1371,8c84e295,f57a9722,260d5816,c5d57719,c6fe2a12,3ba20a48,189bee04,ac252f32) +,S(918e415d,92e768e9,f5a875a8,aafa7dd6,66109cd5,8fb6044d,d2c8640b,f6b966a7,b53400ce,9ee9f6c6,9cc35b5a,3e04eec3,dc89c931,e545068e,ed4a818e,42073e71) +,S(5eda3e22,bbb8c368,82d46c19,2068b3e9,a65624ae,31feba8b,df725d5e,47bc3437,1cc2c541,ce3ad8fb,ac3cfabd,a492c03,87099e1,659cbf88,bc8f27aa,f9a2fe26) +,S(7df83e06,9cf09a92,5405e0d4,3cf0c7bf,52a8e603,d286e26f,f273e218,b455e61c,9eba2975,7f61b054,29c9e915,a092a591,ac1d6044,8a63a8f1,313f4018,1650f4bd) +,S(b778c25,d78b0bc4,68dcdc80,5de93809,1c3c36c5,b5f9569,a9394b5d,c7afb162,901a4ecf,b4821145,c7d9e56b,75e43ab9,cb7ef8fb,1d384a4e,27033e9f,90b80fc) +,S(dd4965e,f6fb759,104f7877,307e2a6a,f837ab6,8c19aa40,6fbea75e,e8a7adc3,45e92312,b5c77585,3c4b95ca,6b4c1740,a70b57c9,97124883,2c53d291,4b0fd4d8) +,S(ac971379,7dffd8d8,2e33f927,48ca063f,f1c8ccf2,5b88fb6,bf80946f,1dc9dede,6ce10e3b,ee4db87d,40e8de66,fb5263db,2a578d6d,be100fef,d6e28bd6,7377bc26) +,S(6046fab5,37fb413b,29797312,5a6049b5,5c085194,4b058264,c39926ed,fe85c6,dcdf9ed1,cbe469ca,2976333,5a159e42,af6f0d32,664ffb5e,173986d3,a277180d) +,S(a0d94b05,8e3b4d30,7f3b3f09,ba5ba28,d0285a3a,22cd577a,1d949b8,bd23f1ae,37fcdfb2,e3027e07,ea77f28,447ea13,93971c67,974304b5,dbb7621,2ad2db10) +,S(da15b971,1b974ef9,14433ca5,71175233,693cab3a,dfd5f6e8,cf034254,6f73dcd,e08c7f62,90f87fc5,4e2f4ec5,a5a93d19,f4484868,3b5ae9d3,810b0615,c7e79402) +,S(b26ba5d2,72a744f5,562cd745,a3f3f143,32980458,60be4e97,d737fbb9,b3b0d544,3d308307,9830f281,14de6c5a,f3876446,507558e2,95353dcb,738deabd,80c0ff20) +,S(fa26c55b,bac04fff,ccee0610,ba9b60a2,4042aa08,7a564ffa,b891e087,7a2185f5,5b5a62eb,1ff579b9,ee4c5d6e,ceeb57ec,e9881b47,dbfc24f4,3b9a18d1,4addf4ab) +,S(5ada4a59,4802163d,4da685d9,b7479f,4b70b489,5ddac7a3,b06a1c4e,a5f46dbe,2ec25e70,871b4958,81f6b0e5,cf821b91,febe83db,a52fe2f8,1a2e4e82,165c7e3f) +,S(a57751d8,895282ac,bef2384b,db4817a3,539899b1,e7fe7a62,2596ad18,5dcf878f,651eee9c,12ecaf92,9eccf109,635680a,a7499537,f2054e2f,69b0f062,c820784) +,S(3f17f0f2,6a540098,d18f8d88,ad323e9e,e300b029,b7b8101f,6aac6ece,8d375f3c,9c0713,79e35319,7f1e76d,55616e5f,8e573a54,b6bfa56e,5dacd2aa,e2e0deeb) +,S(eabdf476,d2e9d76d,775388c,da759930,4e1ebd59,b3a7e491,e3c9c62a,4d0968ba,f4bfd5b5,e0e8ab41,a04c4cd7,763b243f,b82f56ae,9f08a6ef,bc365f3d,fa227c4a) +,S(c5b76ae8,dabb664d,fc1fd499,36399e3f,c2b7366e,a21cba10,dc7eec7c,5c93e0d3,ef30249,19bc03a,c24c8544,9467728a,c160edc5,7c901e64,b947f298,9bb1242) +,S(7161dbf8,6b1080bd,bd6aa47e,dcdf8a77,17b7e281,c692e9d8,739caf9a,f3f23d6,3c30b786,b095288a,4522749a,3d32a35,5a8bc694,cc9cf7ea,989675e9,a1688e8c) +,S(ed6a7b49,9b74e62e,53183b15,6867d41,3ce902a8,4b71fdc4,fa414f8f,249c2ce,793d0356,1bca65c6,be127ce5,a1034b9,86285fe1,f52075e8,1a9b5bcf,87348c4f) +,S(fe6e1abc,3ee3be4e,22456f4c,bf93810f,282f0fec,96ab5cc8,2b35b08,54492bad,96c76282,3adc2cea,1563c02b,fdb25b55,eb15e769,90a7ed7a,3fb8aabe,47bb077c) +,S(979e7ab1,96e66818,b67bf79,31232826,713648bb,ad956add,ed594cdf,8aec2937,696a9505,e3c473a7,2df68f96,13c2e494,406782a4,f92a8fd6,5017a83e,d7912491) +,S(9f947cb3,f859f2af,11a63400,800c18de,b8813c1a,b396ebd6,a1d5bf4a,9689160a,8efeced6,7f1e6fdc,191ac965,5002a02c,386a20b3,eb2aa1be,7fc12008,b8bead1) +,S(71790030,58caecb5,dcd2e281,b42eb59e,57de1e6e,b77f6bad,7d2d1897,6a512eb4,abff54d0,e20347bb,c10a79c4,127f5f7d,868176a7,4e34077a,8ede1d54,7e339483) +,S(d786ec15,c140af46,841b7eb7,de5fc9a3,c0636885,3950bab9,ffdbad01,d836b8b0,fc90191b,63616a44,72efb2ac,a7d84da3,4892af1e,25bca0e2,d41268c8,d381d062) +,S(2d553f03,31eb83ca,edf2508e,67054734,d929367b,ffdd5b7c,dd78dc6a,2e724534,9abcef4e,ee588e28,fa1dee0a,b8c426c1,67d37cde,f8aae9e4,248c036b,baa1af70) +,S(326b36b,eab4d932,c40182f0,fde043ff,d6b84b16,72fe1dc7,3bc7e518,6ef68062,9d86868e,2e871ce5,c3488624,bec901d1,47b91bf9,a3154cab,6445870e,d51e8f1d) +,S(f7a6a26f,4e3583bb,9552556a,5d248735,7ea4af7d,ad1f7a92,717d19ab,34dfa11,7ace27e1,dab2dea9,704c01ce,50ea3de,529d864d,9a5fc11f,fbc0e8c7,81778b2b) +,S(8ca708ea,c072334,42eae4e9,eb0c7b45,83e153ba,84ed7a0d,3ece41f9,4df6cd15,33f41d25,e446c47b,68ce1bc7,d1dd1740,fc701538,3ac90e05,1dc89a9f,dc97592b) +,S(4fca2ed9,e1948697,208a87f9,a890cc96,4aa9e5e5,7c7274b1,deea92bb,586875da,98a9303,4df7185a,df9f557b,b7def9a6,41e7ad5,a3f24051,435673ff,12f0580) +,S(466da0aa,97c68c05,21b8fda0,fc70d74,bb586eb3,da7eab4b,6c104404,d9234d37,5834296,f94f5b54,beddc0e,3d7f6004,659952b7,90a6341a,de99ff26,5530e5e6) +,S(ae22ae10,d016b54c,c0b5423b,3f4c332e,3180ff23,c279078b,864e8e07,77e26a5e,ee21d64b,d6043d56,de3346dc,f93e2c40,b9a51498,b4d7df61,d476d339,7a2d0c8d) +,S(58cd60cc,ea7e0896,2f65a353,5d45ad06,517fea5,575c5511,277103d9,fabb5167,175a68a9,850b4026,bc7b5684,e859c808,edb5f3,7acebc47,9ba489d5,5aa9774b) +,S(4be8a0cf,7ce26101,49cd90a8,68f4049c,43054aa5,68bfb2a1,a5bfa386,9b2b485,a3bab0f3,e3bec469,f779404b,d025ca14,79e3f6ca,9d496f8f,8ce4aa6f,b7e3b404) +,S(428599d9,398a2c59,58c5f74f,1226605f,3c5c8e74,ad8f9bc2,d62b8d9f,d679d3c3,12a1b04f,add5d70,bdc5e15e,d6347f7f,6785c425,61f14ae6,275cf050,3a1bd5a7) +,S(134ba4d9,c35a6601,7e9d525a,879700a9,fb9209a3,f43a651f,daf71f3a,85a77d3,21c112f7,6a9b9b21,e2e3a7c2,8cf500bf,f48aaf1c,48e0e13e,f15618b9,ca62287d) +,S(d53cf8f3,cc5e5739,bc9f9144,a44e7b7b,bb8f2c36,b50844ca,9b2d9cf0,cd0616d2,799c23b6,c57aac44,90d71450,4388cfa4,689393ab,6f30a347,4503400e,c568e03f) +,S(a1e22cfd,e8d12f17,eea1eca4,ea0b520b,6598c036,d1bf837c,e23bc300,a384e5a7,cfbb52a6,e1fb6a65,77cd0377,8bc965b2,a3df592f,f73c34d2,a91b8008,74ecc295) +,S(72bf047f,a0da1391,78b97ea,7b317168,ed0576fd,71f49409,39a8daa5,2a02ead8,f8d93088,cb3457e,7828ba9c,bd8492e4,9eb2bf0e,2e23bfb0,4591e9bb,5273f462) +,S(c5373038,4b951abb,3bcd1f4f,98d983bd,cb5b36a,42719531,c4d1797,2e9bce59,d921f353,a9f7309,6dc16028,f9e1b562,f406bf49,54d78bf9,f2b4c8b9,2db26a82) +,S(ab20d194,e2a6c4a1,5705d3d,19300810,89342b15,e9fc6224,7be58805,a8682a5e,44dc39d1,8342502d,cafafe40,33c4893a,2dddddd8,ad7b238a,efca50cb,5d5b3186) +,S(1432ddfb,108ee664,2eaa9c97,585f47b7,b92a5ae5,39a38093,b8f3153c,e971c8f9,5362084b,5482e375,1662aa95,dd3b9a6e,65235aca,b0ce1eae,f5153951,1391e269) +,S(f199ede,4a69d778,61e107c9,376bdee5,6430e279,28c74d75,66e65589,be8c433c,5e7f6fb7,1b68a535,f407a9ee,2e42f65e,9835bcc7,2c34b8e7,712e5332,a65e9ac6) +,S(b24dbf51,47452b5b,ad94bf4b,493120ab,61ce2ea4,37b3ad71,62e568a,1d595d1a,b3af5a90,8d063602,6b3869d0,c9f31793,61afd6c3,8db99cb9,77b14e0c,46427518) +,S(d7fc29eb,b681e025,992d9ef7,295db58b,40f36c64,d1be10e8,c8e66858,d4d0d9aa,c587764,ca84b3c7,2f95eba,eb62494f,ce391202,90c42b9,e8b2105d,ed972595) +,S(5c71e90,d5f00ee6,e033f0c9,c1ac495b,d148a31d,143a8e3,59a99c7d,faa3cc9c,4acc164,ea3071b7,a4830a27,24135c49,562ea631,9dc4455f,808f1282,4e3bbbb3) +,S(4c9904a9,a33f7e33,9a3d85ac,c12b21ad,11f7d7f2,76e46620,76878593,9d11eaad,2387a445,b0967403,86ce4634,62dd101f,95650365,ac02ef1d,2417321a,3fac1df9) +,S(58f457ec,12d22482,2a91b78e,26f7d8f8,5fa39d90,59fb833c,bce4b1f2,5c9720f7,90808a70,79d4970c,b2b70ae,390844a,2f0283ee,eae05a5c,7d2dcdde,be656f2d) +,S(9867259c,51414805,3be6a73c,de522d91,a8d8b359,9f9bd39b,9c9575a3,90405bdd,9904fa47,34973bc1,77a3d0dd,f0edc0bd,cbd77b36,357734c0,a0feff89,4895f3b4) +,S(663b4991,913148b6,631d16fc,27471938,20a7ace4,ee85c335,17b60cca,b5e12b5b,1b295a18,16b92c5f,15b88bbc,177dc011,f6ef0760,15b5ea47,9bca876,ae072070) +,S(5e3ff13f,bed18235,fe28dcc0,72f09cfd,41394cd,a9a3aa52,5286cddc,e56acf05,c1488c2c,903bff6a,411697f4,44e6e72,6ed9c0bc,5aa87cbc,ed8f8802,6998fc7f) +,S(54c8aa07,2f1fc5a6,ade56cef,d7c6aae4,846f6855,34912868,b84b195f,78bbe14b,ef11dea9,5cb01680,e7205f1c,62aa5242,2c0db969,9b2a0202,966873f3,1fdff34c) +,S(bc69e00d,4118d8af,baef7647,6e435883,2ae9864b,f154368c,e2ccdadd,c58cfd9c,148aea9b,2babfe00,3a6592f4,d3788893,5be42ac8,a50f68d7,ba2cd738,47dd9c52) +,S(50ccf184,c0213602,af114924,fe100f78,1f0d0cc5,beafb671,9dedea00,c7c3ebe2,b6559878,d7c33082,4588dd33,3054c4d,2da86b8,ff23fa9d,6413920c,d876e36b) +,S(c24ca0a4,8ff2cbb6,235ef33b,42ba032,386d5475,3cdda799,e9bc53c0,5c299aee,8555bb16,bf4d7bb7,5c0cbdc8,8594454,bfc819de,72c3954e,76b65780,2be28fe4) +,S(cebc8853,3f6c3a01,58dfab12,ef52b4e0,a7473d1d,209b3585,bc94a13f,a83abf17,42fe28d4,136bf80a,7149a0b,7ddce53c,45e23c0e,7be85fcb,73c0e66,2c4c0593) +,S(7d921a84,65b11feb,7a755a4c,5d96b6b2,f17e07a,95db112d,48c03bd,18f61422,f0ccffdf,7f04e350,13ae7f36,411dea5a,ef69f220,790c37d7,354ce5e,83925f4) +,S(b6909fe5,6824e868,f4cbdd10,d3d00ca,23e5b4,35c78aac,c78a9a1e,321d178c,3d513c55,136d61b0,73dec253,e1ed817,782d9f76,b536d3f7,c3b0d1f,d06e6c1) +,S(5a3df3e8,c78c0fc,56971dea,ced3a6ea,e1ef668e,2485bcb3,d4e24408,7f53cb74,960721cf,316278bb,56bcdd1d,9f3385fe,8feea6b0,661bdf1d,44771067,661aaacf) +,S(dc65c06,50cc30e4,d759fa93,d4d0ab65,5cb16591,289206d8,7a988290,20c22f9e,be39ae0e,a41a81d0,2175dfd5,5e004e19,fa925a99,2166d862,296899e,2532b6a6) +,S(f659d02f,f2d4bc82,9f816525,24019a88,6ad539da,3f38b083,5d8265cc,bf3a67ed,bc9c7a81,9036c702,338c57ef,26134647,2a22b8cc,5543f4b4,4a4f7d4d,d4339573) +,S(b89bbc05,420a8a65,aa03441e,da1c54da,9ca84f11,e85a393d,47cc54b9,78b8e5c0,5f3a2fba,4cef4457,ca6befe2,7dd3f9af,a5d8b6de,86679eb4,c877c7b4,cf03c08f) +,S(b9bbb789,690b53e6,e42266bb,853cfbbb,f6788b58,b325097,a55470e3,d4cbc3cb,1f984f38,78427212,cbfc8a93,8c1f0d87,59792ca7,17635c75,71b2c4f1,29e35c2e) +,S(d8ae91cf,8a99ef6d,2ca0c15e,3132974,33cd46cc,55a2c8f3,9f909e96,7d50006c,4fe4696a,79d2f269,9fecfce8,8375cc1,81c2c2e5,4109f380,3377a020,5496d733) +,S(35dc2c70,181aea7b,ccf6a15d,1f708c87,cc8bc5af,93671c97,35867367,549357bf,6f27dad,a9abbe5e,5e59141b,78a2e6dc,5b5433ef,dc8c9cde,a6269c2a,68346f87) +,S(a4c042b7,d54b67b5,877442e7,2e81de4a,7edbe667,f00838f2,34f567a7,9e3791af,a8c6f7b1,6b23a9cb,64732852,c9734547,69ef3e4b,9165ebf0,a1dc4967,36c73242) +,S(d6ab68a3,353b6c65,3836b66a,8c39f2d0,892cf856,90ebb56,a5e8e4c9,e669da34,4847a9d5,f39ea1e0,ce392c8f,9e63e88f,8f3feb9d,7b2a05c7,23a932d4,b07e38e4) +,S(e161c34e,644eb3f4,fa217d33,dd3129b9,c2b85ad6,40b56e56,e20982d1,c5483d43,ceafd0af,a8cf7a25,be092307,22c30e41,b6ea151c,d027326e,5152aba8,d9a50749) +,S(94959a2,fdc2650c,b4b0219b,83ac99c7,c477132,eeab585c,1fb262e7,6cca22f,6243f3b6,ba7d4f26,24f7b7d5,8e070b2d,64610aad,b281b4a3,b93b030c,ac0cdab9) +,S(491129ee,3130c2,f262c4d0,a1bfede9,e470c3cc,8e80774f,52ea023,67e2e3de,c1e61e2,a5310866,762a0cf0,ebbae0f,738b9527,46001aed,a991e0ee,d95f0db5) +,S(e2967539,b0b29fee,a668eebe,eb8e47c0,1ed84950,a1f9fda8,6884a421,5ab6f265,c304cf3b,b7faabe8,cfeab6b1,b88d3d41,7e950963,745c2479,85211d50,888346dd) +,S(d90a380f,5283132e,7d6760ca,f2b28576,49445507,b8e8872b,d0e1d5f,56a15af5,97fa0739,7a1357c5,e24d0a3e,ce608332,107e41f7,c65d3c6b,98ed66c3,af30a4ed) +,S(cb917a08,153599e3,e531b1ac,63fb8e71,fcce572a,29fde1b,17de843,a99ea2b5,701c08a4,a9da11c9,3b4be64a,6832af1c,900ad3c1,4b4dbe70,c62e3e08,55b41b6d) +,S(e6ee53e2,98efb026,bce900e7,8d31f3c4,539108bf,d4c5139,16417f8b,49199a0a,bedd41e4,751f657e,8cfc65c3,2a82f981,4b223e62,95ec36cd,da5125eb,da736429) +,S(5f777c41,f4e3441e,75c66f28,852e7815,59d0f3fe,b8b05b59,b6966fa0,de84df2a,7fcc66b8,127d26d8,e0ff69cb,b80acf44,bae5546,edc9bc52,90b73da3,447a2731) +,S(16d312a8,1295ab9d,c08f9fbd,61e6445b,5ef1dc51,fce19d,89f04e7c,66ba2e07,6c555fca,2a1d2f4a,24ced2bb,c3966f4e,1bfc1912,eca39067,503df586,41a4d4b7) +,S(660d3993,fa887e1e,8b05d80b,96e2b70c,341c3ba3,351d2562,5792acaf,3859de3e,87b06f5d,4c6f854a,8714eb3a,55454346,f931c21c,c77da23c,2d069d33,7dcf12c) +,S(9d45e660,879b6e8,b8007a8,ba7fe7f0,c7090cf6,9c733bf9,43f4eef9,965a1ae2,c81a3fd3,9b6b83ba,d163c763,f3010359,ac050e64,a47167ae,2ca41345,c7d95662) +,S(c95d92f8,c81d15fa,a68f645a,c1ebebd8,57c6942e,e75ba13a,3a4eb9b0,c45c43ba,2f55ceb6,c1de7877,7b322a91,7f3e48d9,480b80f,d49e362c,99f8104b,a20f392d) +,S(95d445ff,e8cf8240,fc4e9856,9d41164f,50e9ebcc,1fd3bf19,d4309de3,34b4c97d,7c391704,a75cffe2,f8971ddb,417e8158,f97a3688,6841f02a,c4b699b8,df6c0d32) +,S(40f028ca,907d6521,df1f052f,ba5268f9,a60e705,bdf94328,17881b44,1500170d,4eae26bf,37d04379,126ce777,b1fe1115,8c34d077,bba66994,78ede7e,244cc8c6) +,S(dab90c34,e7460068,d80d2be2,2bd81f9e,667bbd96,4e30c23d,3eaa7a75,a61e862d,cafa2892,5128bf3a,4821cd14,8503ca8a,86f06388,d21df6ee,af92d514,e66c5f1b) +,S(6df2280e,381ef8cf,922505d6,7646c1af,105f91c0,59e8e7a5,3ae2e7e6,cb456be,d94a020e,7776b713,b31aff5f,d72be6c,f29bfe46,16ea3d29,95913db4,698ae3ca) +,S(a13d83d1,3c60cf65,cefc8692,f5d339b,2873582e,938373cf,3e4df54e,ae32ffd2,8f511212,a65d8963,d7df7ed6,27d87fd9,208f83a,1a4dd14f,ab0593d6,38ac71d0) +,S(ad4c1ec8,39950ae4,a7fa551e,5aa637a2,e5d40bfb,3fab696f,ea886a4f,40bf2167,fea9b599,202841d0,c3afbf08,ef1da210,cdd92a4e,6cad485c,a0d5275e,8a5dacfb) +,S(64188be9,af657254,1314e661,848970f6,35a0b6be,7e594824,6dcf36d8,66840610,58880b5f,c3df9b6a,45b49ee6,b90f6b5f,f3fc440c,37855167,a30ac013,3d48e53) +,S(9b71366d,a66b165c,6495e4fb,46ecdc15,84a193ca,d65ad8b3,7a01a3b2,cf2e43f6,d7315165,ecec296c,4b71a860,f3b2f0dd,fb9447ed,5c59a458,8b81f679,34321301) +,S(4a3c5006,74814f95,9e9c7726,595658ff,84e369af,636f6aff,ab579bb8,5583d395,1b495757,1a302c2a,d1cbe53c,2ba34a6d,66bf1aa1,8bddad33,679e4890,5f9a21e9) +,S(e4305e5f,72c43558,79a749b3,d563d4d1,dca704c9,c8867d01,ef503cf8,97c90034,ee563dca,4d31945f,c536a318,e9297d28,81954b37,af992722,9e4e0e9,1c16244d) +,S(3aea4eb8,ee74c9d5,2259f37a,da33ae1c,78f5dd8,d97511b0,2e0a0201,82840a8a,8fc58135,757b8c0a,a8f2c2ab,ec9d9152,20ad2046,f429667c,c4586765,10e93e87) +,S(58e8e94d,e9f85066,7cc4c61d,acd212f4,77454942,33deb015,858e500e,9530228d,5a95aa24,fb782a4a,e64e155e,eac2b644,cd614315,9b46db6c,9bb4fe4d,5e5fd690) +,S(6642c782,7e1df912,ff54dbf7,41fa1567,3e9c3aae,5e7630c6,9cb74b60,c070af1c,ff338a86,34a404c0,cb26af9f,59df36a9,e1a848e1,ac178b25,c37ac177,db45e947) +,S(c5c69fa4,65c79a50,a98996ee,cae55474,5c544a3,ea838a42,e12a733e,9181b30a,6e805461,5a424a9a,1fc229b8,7e594211,697386ef,189d1ad6,ac75eaa2,5727253b) +,S(f4faf099,fb16a1e0,e5f64428,5317d91,a31daeed,fbb6a6ec,b70a213f,ee95217d,ebfd8445,42fee872,1f721f3,11ef28e,30618bd1,bdd097c1,ca573285,5b079734) +,S(773b3e69,fda8abed,fa61ef37,57101756,9d9d2a6a,ebb4fc5d,d9049d56,9c66b76d,1bc051c6,302a383c,dc0756b5,114dfc69,1dd2180a,88a4ea9b,6acebccb,a59f27ca) +,S(bcf80e7,b2b54cf7,971fae7b,db8b3826,85acc1b0,f987f352,d9b0b3c7,ac78142a,20620b00,8c010ad9,7a98f093,8d9a381,f9935d5d,4bc9b060,af2ee6ab,151eedce) +,S(865dff30,47f31564,99337316,ea20223c,5967e034,83d92d54,7486fddb,fda959d2,2b655c9e,37697f10,5535b736,a31b2c6,7f5726eb,602f1438,f808ff62,4bac074f) +,S(e48e0e18,101eef40,f351067e,63d2b34f,4fce76c,d204d6f8,85d2664d,fbc92d3c,594061c,8d3f4748,bff85cdb,f70a4035,5ad826f3,46d44aa6,7eca3196,e433bb65) +,S(9807e350,7a03e134,9bca9101,cacca5d1,a564b647,8c906619,61ba503c,5ee15bdb,301e68f2,d584b1fe,3eeee7c5,85cb4d0a,26621bda,229589cc,2704dfa1,1cb8d927) +,S(95f94e75,8602dcd4,60ded52a,c9d7ab40,1fdf1405,b271acb4,133a86be,cfe5027,f08d34eb,e9cf1b1e,78e1fbec,452e1ab0,412c642e,1328b2dc,f5e08b08,38aa3c51) +,S(7ffa20eb,ebbad406,deec68c6,9bdb7b0c,7615a56f,5c62a646,a57535e1,68a82a31,230241b2,3dde374f,7a039eb5,5181e954,f0472056,79edc688,7c4ca6b8,778333e4) +,S(1dc7e0b1,487fbb33,d1ecdf84,7bdbfef5,f7df9f31,d07ff024,be063a51,53eb5498,ebcf72da,18a1a55a,5aec4aa8,efe09407,263a7b36,f09552e,22cbceba,7a3cf980) +,S(a8052e02,e39d9981,2ac6c4e6,2cef526b,9cb29843,127f2227,50a8021f,4ced5cd8,9011f0b4,9dad7e5c,11222b64,c5d8c9fb,297d9afd,c683f545,849d833d,f2697220) +,S(3edfc4d7,f1f699c2,8e8ac2e7,5cd93e69,fff31607,d99a8195,30603437,f9bfb20d,f901260d,68c6dfe8,aef8879f,ea1ba009,a1e1d931,fa6ba39a,ce1e2673,ba759311) +,S(fdf8ae7d,c10d01f1,c39bee75,3be3307b,53307caa,4af0e8dd,9de7d696,45ce527d,2425a3f8,c6147073,3a44d3eb,eff3d8cd,61e5fd55,ffdac357,d7906600,153a8dd6) +,S(1cd5ba80,fcfc77c3,d06e230e,e7ad8ff4,f9ee6c60,a71d37b8,3718d8b3,15d5a4e0,f90ac118,30b963ab,fc64492b,415db7e3,47eba55e,d2c5a64f,578a13ea,b4435cbd) +,S(3cdb43ea,b7afc936,24b80269,18319fa0,e75de21a,c0587af3,541e492f,1510257b,49b6411a,c74a2eb3,ac2ec784,feface51,8d5a5bd6,e76d694,bf5ab8f5,c146abfe) +,S(165b6f5b,9b1e6d08,14e44cc7,c7969297,bba7c659,58dc3274,7e7c4148,e30c09da,e715e411,2e6cb67d,cb8e1ad,997691f3,bd6119c1,3a5f0329,1ea3928e,35c04551) +,S(d4c1190d,da3c01cf,6c75fa06,7b4dd1ee,e645a0cc,8b034f4b,24580661,8ced0bff,c837ed81,b6a0e5fc,6a02d6d5,f837db1a,20eee55b,41ff531b,9bb642d0,52c42bfa) +,S(f7359bd0,bf7db6b0,48f1a040,a0163fba,285780e7,909ab689,7963168a,a7de9c29,8c71bc3e,95ac0f52,54db6192,5c6f9112,759635fa,95846be4,6a28573e,2b25562b) +,S(4d54a2f6,dbebbee3,8950627e,8cf2c65,6ca071e7,86687f3b,a0a77178,be14c55d,6579dace,73dd14c,695fd781,218786ee,bad84445,ccd910d3,43aa2478,f5576671) +,S(f70b532c,e7203208,d6440bf8,55e1293f,cc6ebd75,96a04b27,9fc056e1,2ee32dee,e9d18f7,126ed56b,4a657104,2441bc08,1778736b,91062c9f,cac28cbf,b8737be1) +,S(bbf3ff3e,577aaf34,157e32db,d977b907,e62b16b5,1ae0abd4,f14e71fc,cca11357,cc1a78ff,44af7c2c,cdf17423,9b3aec17,b660ff2e,fc07953,2d9f9d6e,55d3abf7) +,S(53bb2321,b36d1dad,226ceb24,f55d4292,be245444,b2349611,5a649560,59729700,a5db4fb9,46c4a2db,b1a634cc,4032b7b,cf23f7d1,717a0ee9,6c02f131,24f834b6) +,S(3b863ec5,5e4ff2cd,d32cbc81,6e645009,da444255,9bf96267,2cd012e1,15372186,914682bd,d6a052bc,25cb4d41,e9bb28ed,76e9aa55,3f5aaf25,75140e04,eca69fbd) +,S(4cc4a750,d641c574,5c68a48b,953ee51a,258239b2,fda1f5e0,80831417,7b837946,cd6f665f,6f32246a,1cc8fa61,4da2783c,f4c7b92c,4f42749e,b6bd4a8d,8a84c54c) +,S(6f9b5d79,efddf08d,26183b4c,d6001d6b,fdad9e8b,dc5853,f3a8c47e,7e6f9e96,b81148f2,1e50152a,8cd7727c,ad14862a,37fd186e,2054d4c4,a4cdbfba,a9076991) +,S(9e13d0e0,44cd3fc1,1c7596f2,9946313c,918caa65,bcb6387d,361eec31,ebaa6977,c5f55650,7691bc2a,b2c9e4b8,512f7282,24276490,257288c5,2387fee5,54bc9c0d) +,S(a4441292,d0e0db3,2a4f33c4,8bbc5fbf,d40650c8,d9f5c4f4,88a1f69a,d71571bb,a23ef48d,38abc24c,608dd688,d524bed,a3709a5b,3567ef3b,e43f0240,796b7ad2) +,S(def598a5,c4828c5,16b7076b,9682aa82,4e74ab42,e4d4692d,17c8f289,67f3cbb4,e6b4bf28,6dba0803,e4a97a1e,be55a088,10660466,3d7726e9,300109ee,a1d62a49) +,S(8e991fb7,372df8d7,7b09436d,c9424a8,5a14888b,583b3c58,6d2a19e6,91e75b67,1780f6e9,b8379b0f,ebb1328a,69a96878,9f58b45d,8e3ff218,81d753f4,8ed6c43d) +,S(bae09288,e10351fe,fa0b0971,400ac3d1,a7eed65a,b11d1ba4,8a1c6240,bb981114,dfc2979e,dcc2de8c,abd9abd2,27cf7351,4079d950,aba60e3b,f4c775ac,72c30f4f) +,S(4d09ae3c,b484fe27,411d4142,e41de523,2c54c42,b387c7c2,cf42a23e,e7611fc1,b94fa116,27eaf5ab,8fb7fc25,1345eb28,8f5249e5,ec65e056,d60e1294,41481375) +,S(32f57ac4,3cb29fb,f8a00d8b,c95da8e8,3f0f541d,ed6c9e78,8af17a14,6a2704bd,2a969b58,9a3f9a5c,26b51ab6,1a5717bf,c06eb438,85e4f4a,84b903b2,da5bbf09) +,S(595503ae,e179f59e,bfc581b8,7ac18e1d,55b4c794,87d90d62,492d3ea1,1ec57579,1f25d8ba,e38c0a69,50a17836,a842b418,b0f7c317,9486fb16,9ba11b23,d315ada0) +,S(5555fae0,6f1563af,238184c9,304e26ef,f8b2121,394e6856,79de6792,31a56842,6840bd14,faf202c6,60650541,48bb87,df27b979,4ec0da66,9ded6830,b0623980) +,S(714321ed,2f0432f8,a05c33d1,84619de5,f81fb8db,95ab3121,c24fc998,ab9b9ca4,4470cdaa,7067de2a,e6678cd0,6d613e19,35b1edf3,bf278205,da69ee8d,6086c2a7) +,S(d41b84d5,9a0085b,86e88fc1,499151da,b0b9a574,92b01df6,36cc2288,313bb592,c04c54d2,57fe5ba,691f6023,bd72edaa,20e71a97,1a760bf5,3c990a39,f5ef7c23) +,S(ae34a065,b42f5158,e6a5b91b,9ff54b0e,6d5bc906,f6d18c3a,82865e,e9038f34,bf2c90fa,30639811,2ca2ed02,b7ad090d,8bc990db,b6140a05,afcdc80c,bae8490f) +,S(9b3c2682,3050a52,a164ab,f4504ca4,7750c889,b6465f95,658ba7b1,c279139f,ee36938d,8a675824,51ca289a,55265606,cb9ae4fc,8cd274aa,41db5ea9,9a5b4299) +,S(27dc9a57,999ed109,c3dff978,58d44ab2,73987af7,b617e9c,766331d5,c06e0dfe,4e97536e,67e363c8,add07030,d59061,33a726de,38dec51,e5a20009,61ee0fe1) +,S(c3415e9f,9c823521,bad3090f,f2c48e8c,647e438d,70397e5f,7d7a6f2,b7d7d4b4,8c3bb607,c746147c,d5efbef,7e27d236,c4063116,89794cc0,40c235b4,6af412d4) +,S(f47e44dc,90c8bd2f,150d9dd3,e4922395,14990fa1,f2fc361b,a24f853a,b37e33a0,f4282a26,bf5f358f,2dac4956,8bcc15a0,d7eddeee,b43e6fd1,8f35d5e5,4295ddb4) +,S(3cfa945e,6044ec2a,da895f9,9dc24575,deee57e,df8b1a10,a2d2ece1,9951a812,d0ab59a7,46ac6edc,69307a0d,caa00aa9,e7b73897,b89185fa,9dc3899,ae7e3664) +,S(29df8149,9d83bd0f,8fe61eb8,8f0abe0,96a75e5a,2cb0a0a9,76d8d27b,6533a4ed,7eefc80b,63f927c2,e905a56,62d5ed34,e9bde8ff,4402491f,19215c9d,494e62d4) +,S(eea85a80,566d13bd,da65f553,b2077607,c8b9184,6a5a8096,f57afe93,ada9fff4,b5389645,fd772da0,1cf3b535,6ec40279,cf76d812,11f20a16,71d7ecfc,441d71bb) +,S(e1a69e64,4434db7a,54550d44,adc43682,c128c560,3907615b,9282cf1e,e2b74f82,bd434a85,984a6e64,441134e6,d1f1a3a3,adeab658,c29af8b5,4bc42667,634d20ee) +,S(2d99f69f,a7e9f3f6,6a53eea4,381a4c80,ed17e8e1,4507d7f,4a80ef25,293c5fba,25a6aff9,a23a406e,9e34ad6a,21627acc,96b6ceb0,7896382c,833b8fe4,8e603e0a) +,S(d2482127,1554a14a,7283dc8,1ca70179,42a35cfa,c8659b2b,db78c426,51807cb8,a252027f,3fac319f,c767652e,469421b8,d34decd9,c9042d58,f8aa0ab,70e5ceac) +,S(bd030cbc,5f0de61,ef194eac,38f7443c,d231f75a,a0b568c5,416c5b8b,917545d,ad0833b1,4f1e23a,76c0626e,71129455,60fe62d7,4b3a1b95,69e4887e,c0661e78) +,S(afb44b49,ef00b1e9,59c7a864,19d2a4db,71d9bb0c,4e1746,9550d39c,9a37a161,eee390a9,530a5baa,5350019a,f756185,8038c2ee,7f78c365,dd6f62f0,f0589aa5) +,S(9e584f1b,e06ea4d6,5f8dd96f,206cf4b,88aec6b9,ccf06779,53acf110,99e2165c,6994ce27,46b0eab3,d8608ef9,33b61339,d3e589b,c2acb7bd,aba3af72,b082fd24) +,S(d2265b51,b4f7f4ce,1d0966,e7012f9,76433dfe,444b2351,9505b29c,d520c6df,44414498,df439478,328b330b,6f8c6876,682b6a32,b5d01355,2494286e,a635bf65) +,S(fcd56867,58c797c8,3aa1f1d8,a9ba34a8,8e624aeb,666507fe,706b310f,3342264b,680e0b98,455f0e64,94622fa9,e36f76d4,863a9fdb,a3df93af,c688c45d,fdc5967b) +,S(bb9a0c0c,74db0525,370e8235,9d733aa3,494afc03,fb61a1b,7c2536ed,9903fd91,239929a2,1c0ed586,b9bc8f03,af422994,f81619c6,b2fe637f,a511c07c,d9421603) +,S(2358b078,1989d6b5,666d9158,2fc640b1,13d52e61,ea2147cf,a0a103e1,5ae80db0,73f84f47,a78fe2c6,e4d01d7e,3dc10065,e052401f,64796358,c784d59f,742cc8f5) +,S(ddb3409,ce3184a6,d9d7b4c2,cbdf32ef,ebea1be3,595ba19c,42933882,237dae94,59215423,3760cdf0,513442bd,2fbef84b,9c8c0fb1,ef16fa31,783d4dcc,50f24f24) +,S(f99aaa8d,8d42ce59,86ee8ffe,d4dc8a48,81810a6f,cdfa9519,46f00857,4ab1c3c7,d0f29fd1,32bd65d,7f9820b6,830a3e42,8664f9e3,9cb25729,1adc36db,4e177187) +,S(83042093,46ced0d5,a33f491a,c98aae7d,51f17ea4,1e5722cd,29c47f15,49c183aa,1f680d05,ca015018,664dc767,4de0305c,b09efffe,e7b164c8,c733d2ed,18c15d8f) +,S(339f95d5,5e293243,ec10b3a9,a8dba385,dcaa23a1,bb424bbe,4c894deb,c61cc881,3a4ec84d,67831768,e9ad1d9d,db82f785,52883fd8,b0b63bf8,38495a4c,455d5865) +,S(f94de87d,1123f6b6,97d4536f,7bb6a995,ff158060,b7d72b9b,3c9d74c7,1afb6009,f123cea4,bd4859b7,a852270a,17c76c06,e6050a26,9c035bf3,6c505fc4,1fa81066) +,S(71341ad1,bbebbb4a,17a7701d,30dcbf7e,2a70b901,5f6c5ff9,9fb614c3,d3338fca,6ab14a0,4b4956d4,a687acaf,30d7997e,cf70df2c,b49356fc,5b86453c,5ef6d55) +,S(79b8571c,f52ee30a,4d3632d4,965cc6f4,cc6ea06e,fe1cb7a6,ca2c9c9f,1e835bfd,259c0c7c,b8fa8345,57febdba,2183042e,78f8cfaf,24a41dd8,2eb0ad3c,426683fa) +,S(f3ce9dd9,d879e70e,21737426,dbbb27c9,7af84307,6855bf4d,af141d55,5006e402,302a436c,f8be3a4f,dd70a9d1,8f63cc8b,ecd3ba1,ddc9aa3d,f4285239,61e7553d) +,S(4a66f7b1,52a8cafa,78d0e98c,2f8361b9,a0bbad47,d23b24f,5184477b,e90d6318,7555fd5e,87676154,8f7afd4a,33511daf,b3bc4a72,c9f54d4,92327a2c,c235c02f) +,S(cd3b4037,5cd6da61,ff432898,fc592175,c90fbc31,373489ee,c988f280,3459bba7,b0e86ab2,2f2d8d97,5f68a7ab,3ffa3be,511390df,5b647608,fb07f29d,3155728d) +,S(e96f166b,84d98bc5,41ea8885,f7a48612,227bc907,795782c5,d0e2325d,96cb44a0,18ac220b,8def89a1,e3bcc2f2,7a66c0ab,3ee27c3b,882dc16f,e2571963,92b94310) +,S(87adb3fc,7fe6b07f,795bb7d7,ab8383eb,a3f91564,ce89d267,599657b6,9d793838,68677cee,bc7b3d09,efd0f118,d392d0f,d2d5f2bf,f2b50230,e127acb4,97f5c886) +,S(fdaa2f5c,ad1da3c6,3d241a7a,b4365e63,8eede0f8,229a8187,6cd76a3a,7020c545,5b04616a,a1a84785,c4315dda,da6289bf,e57cb9e2,80c42395,a1b13d69,dfb2ddfa) +,S(7eafa986,1a94fc8f,d263cd4a,1e481e1e,8bc1a385,c4ab748,8715b032,3bcdb52d,d655b395,607bb0b,c9092364,803798d8,17a4bdc9,a30e2844,94be8322,42af9949) +,S(a7fe4656,98538c32,844337ea,bc90fb49,feaf2fcb,8b86da6c,d173bf9a,70e62a53,cfb26d1d,689a9075,55057ab0,d4261e2c,acbf30d6,cdd09f95,9cf1830e,5d635aad) +,S(8bcc3b82,d543f365,478fe32f,dc9860f0,10d51f74,b7b5344b,ca6b868d,3c11264e,6bcc32,f7ff3e48,fa1775da,44b64848,f52329d7,d8bb0a09,338b799d,7452b4af) +,S(faf9aa3e,f1ccd659,2feb2add,a1b58ed8,27511b39,bb981cee,4fbe47db,5cab2917,854b88e3,50a6e9a1,fc7e9e45,f3fdb69c,8111c654,877cd620,fd82ee18,ba2d195b) +,S(77012901,ea269067,4d8b4397,e8976f98,e33b1709,c81624a0,7916da35,af75cb29,b63695d7,cc896358,e119eb98,7dc0f67e,22a70c5b,5e6e2072,e61ef62f,9333bc4) +,S(127602ed,f5f1a04b,813e2b6b,2c27f50f,803b70b7,b9525b7d,902f348e,c03591a4,1f791f7d,2427532,968f7a08,f94df6be,a95b7e6c,5490fa9b,5eb5a3f3,207455ce) +,S(17e82c3a,3731a73b,36501eaa,fde3ee8d,ca9f2573,dae1e4fc,594cee8f,e1d19179,8af04092,79792fe2,273e3f0c,e642f3fe,edf1ffed,59c5826d,a7fb2716,ed365a3e) +,S(3c34e27d,5d5737b7,78e968a7,fe8e4113,f802bd30,1e0367ea,41fc8b5c,14b0dd84,67bfc61f,bbd062ce,6224e883,9092a962,eb3105a3,b6634dcd,d59c61da,906a4ce0) +,S(b7a35907,c7b55a8f,7173a5da,c73e306d,64ee0f6c,cf4f5c76,3416bd4d,4f5359f4,d111c21c,e5a8674e,3a64adbd,4f56b1c3,61350b,44a552fb,19186b8f,95ed534e) +,S(6c7d4836,62c28812,7b904cc8,969ff925,8d9fafae,e88f6d3a,e6e4d771,bf8ee7b2,b593dc47,3c29694f,95b00169,286e3981,afeae4b3,dd7a788d,f32a14fb,6e6a8e7a) +,S(dfc406d7,625719b9,4f709993,c5d15062,4c725ef8,eecb2308,bfeec0b3,6050bf4b,651c0d2a,fb29eab7,d4740b5e,1fc2c069,54ced865,7a6bb980,2de8d873,a451717e) +,S(1631fa0f,4e9fdf51,a2842994,da94f835,52b5bb40,348c706b,54079073,665c6bfa,de202803,9a8d1ba5,b133ff28,6df237d2,a8d73343,a08e7c2c,4560954b,eda5ade7) +,S(fc52b3a8,8f712053,2c7667f9,62146d40,eaa3e924,327d959c,a49b74a7,da11e5f6,7bf890f3,daf8f9d9,49e800de,8a3f5458,5aa46e2f,25535cdc,18170391,e2101daf) +,S(6b7036e5,c5993c6,8a744776,abb0b5b3,31a886b4,93e49d41,bc7d93b2,28566fd8,6ebe771,42a56189,f272b6e8,8f70f356,ed1a3d37,ea2d5e4c,998e47c1,319e2ec7) +,S(b13dc5ee,7333e3a,4b13628f,7ef96ae9,4faee9d7,3a46297f,f1e357f6,e7a57a48,4f30b474,99c66456,33f5b521,9164a890,d8cdb78f,8c7ee211,1bd37fc2,d41bb2bc) +,S(1888e944,6fe20426,d4fd677c,5cf1043b,605e93a2,c8532623,b5951e22,34de08ae,9e1f4fed,d5de001b,378ad1a9,98e31f00,30af9674,c383f287,50172e03,ea0b0f81) +,S(2495b334,9884d5f3,166f8fdb,7ff81f9,9042383d,def7cab6,3c2775ad,226189f8,846850e0,2a1cc051,eea77bbf,d5f44499,673f40c1,190e379a,9b37201c,51a06e9c) +,S(e4c0e483,f21102eb,7dd2a78b,5a605b8c,410bafcd,f2ee4bdd,fcfe1374,ab32d17,b53fd34,568f5edd,a6a3abaa,2d2c3a4a,bbeef0f6,c37bec1b,fcf012c3,dac15b9f) +,S(8f9bfd7a,2e798812,eb927fc2,b0ad5eaf,81a0a30f,a97efbee,a1d6d9ef,19348a5f,1eec535d,1bee520a,13a8410b,6f3824cf,7c9d5a82,8208d2ae,dc89fa13,8bb7c2b3) +,S(1d95c760,f3fc2eff,df51cf0c,4b708538,efb56675,eba3ff8d,4f6abe65,d3f167cd,c2bb1122,5016ffe5,6859da47,4b777703,49e4e655,5da3d9a1,6dacbdd2,d42ab0a0) +,S(9df72bbf,fbcdc42e,adb71d69,1791f073,7f945e8,bfbf4e2c,68c5e3f6,5f6955f,24d47aa0,1626b0ac,ce77827,fd7daff,7424d4c7,1d76ad3e,b66d22b2,6f7d1df9) +,S(2df6ef96,7c0e1a41,2bb48bdb,f2cdf8f4,22829abb,4b7a42e,95bd9cbe,8b7f860f,bace2e70,7915069a,bdecd097,9d133cad,bcfedbaa,7eb9891e,ad3380e,9ca99401) +,S(82bf2a99,624e408,188da19,59599de0,eb947438,fcd45784,9a731a1c,15796028,3b6c668a,e5b8f394,3ee713c,a8fbfde5,8ef0f9fd,84054a9d,b626e274,37e611aa) +,S(60260fff,1f213916,9261edeb,5f1d2d0c,a143ca69,400b2776,21793c11,fbc89d41,bec4bfeb,9d09f8d5,cdb11e3c,f65c6a7f,d4aa87f4,e41d7f4,69717a64,5dcf9945) +,S(6391ed61,80cc46fc,33481faf,d21151f3,cb678e3f,4d667748,1a24a01a,c5e9180,c48495fb,fa5962b,44bfbc4f,491b89a6,a8588fe,91677b19,b872dea8,8e34026c) +,S(20807816,758361aa,d5f62d25,8e3951c6,da518890,26507a7b,c0ceb7f6,a96c141c,8526d53b,61c8427b,eb141d91,7a338fe9,f7789a60,cc1a4a62,15dc754d,a73903a9) +,S(1ecceb4f,8acc649a,dbff29c0,fbc62c11,498c7cb3,7d29ed15,e0ebdf03,e994b67d,1c701af7,a9f3d870,81efb798,2382bed6,5d56b8d3,f050bfdf,6da32b10,a18fd4d4) +,S(be82742,dcafe3ca,f646cf01,80202cb4,7086e0f8,ccea3c11,dcccd9de,aeae688d,236d1fd2,5e05d6ab,8651d88e,33d18a3b,caa66c06,b2b68c50,f6158717,f23b4866) +,S(15252ce2,3f666836,dfb47b60,1e642abf,6e56ff2b,5d58fc97,ab09f29e,1b4ec3a9,9a6b2658,f52dfc45,32e6b482,fe909e47,ba7b4442,3be4d474,a524df32,d6149913) +,S(b0429186,21f94599,f7032b4c,1b53bc6a,9259f142,27922f42,fe774772,4b0ee9e7,e73c32d9,ede68eab,e77d681,dd4cbd9e,a356fdf3,bf066f33,6ff2c367,59bed08b) +,S(5fe0917c,1bca66f6,f34bdf1f,dad88a5,b3dc5f5e,2e0227e6,5f3a79c8,9e66c888,885dfcee,c0947b01,71dbaf65,52c09ab4,c0414f8c,7373ec5,e3080521,401ed575) +,S(455985e6,44d9b679,85980752,a13a3f94,94bf9cc,8e6f10ba,fc7a70c2,27ce272c,47eadad3,15e88a99,9d3f5ce7,792ebc10,2fc68f18,cdfa1df,564601f6,3b26c22b) +,S(3562aca3,2291c1cc,ed072a4a,85fbf82f,6b3299f5,2626154,2b41840a,1c868d4,ab4b2656,11db5875,10c48284,7f72c75e,f822f46c,2e7760e2,a46070eb,5db7100c) +,S(54225801,f82406ae,74416373,7408e94d,d3990eb0,60581c47,b453a859,cf63042c,43834935,a6a7acb4,9c086391,24e80fde,72c0a876,1c13a340,1a4e48a5,d96f6a2e) +,S(3c253039,fc8278b2,8135e21,700af1e4,dad4263e,ddc867cf,a3532499,c2c1e48e,ee01ce7c,f8c56c74,1b4b3593,b0cb90a5,9c59cbe6,9a48235d,1295c1d1,ac657081) +,S(8adead1,d898eca7,9e043f71,aa735a32,763f75f6,f6ba7a70,bc47a284,4b580972,7a370bda,412df63d,5590b3da,80365c71,1267cf8c,e3fdd1bb,91ddb981,d213bcd) +,S(8361e522,34c8d62b,9051a95,8af3f090,4f15ee35,4b69a560,7155ea4f,69548037,ca2c329f,8cb65e8a,eb6488f2,2131c525,29df97bf,c8847c87,47145767,7f82c954) +,S(97d65162,d96feb36,e8f00221,52c92c06,2e97087c,703a9dd7,7241216,2262807,15a260bd,bd591c7b,91bdcbb4,c2684545,4706f039,8fef8de,9173e7fc,a3f31f44) +,S(2609f072,5ec8e5ed,4ec86128,dcee3baf,9e62bc24,aedbaaa1,eed8dd31,c9c07503,d51fcfc2,55398507,7e471397,ece94d92,e26375d2,2bddc0b0,d1b780a9,65caf2c3) +,S(820e8f01,5b4ec57,b884dd3e,6a740d90,68fce86a,a4833636,4b65ba6e,9e272357,bfc87d52,eaf352bb,91f071ab,6e986308,4f197671,298eb614,93152f54,345ce5db) +,S(2116bb76,7a56312e,71ac58f5,ff2a7071,1be5b711,1e9e56d9,aa098af4,b991db0,2ebd4fc2,abd618d7,d1798739,7e9b8eaf,8276086c,2a5066e7,e7525603,fbb4c40d) +,S(e43f029f,97f4370d,65826870,3f29422e,7b81112,61364972,e26892f,77eed56f,4e265fe8,40524def,23b7ed34,54c6618e,ec70d3b1,92ff30d2,1b9b6fc,b1f7164c) +,S(9b4ca445,5cada269,2a77f7e8,9aa3082f,ace4de3,898408eb,6a7d1cb0,8ac15c14,1446e397,d1c3fd20,283f43a8,4679e728,64f05251,b1d3bead,58aca70c,4c0fcc29) +,S(e2abb09,c0566f51,7947f99b,2d6fc4a5,637310b5,5f9d9014,84decbb6,ca22cbfe,f334bda6,a1d9cfa8,2b18f8f7,e90b8426,ae13e20d,8834e061,ab1671fe,4f4665f5) +,S(3579fd9,9cdf0be0,2d7e8587,2e213ed3,3a424650,5608d66f,8f936ae7,72511e28,dd93278e,ce754f69,4b3f09d5,a3c32c99,2c5f2e04,cce0a517,de750a38,ccd88abf) +,S(f307f2fd,d0f6c0b3,12841e5e,1e17b966,47d7ca93,4ba4970f,4f9c0c0c,3ccb071f,4829a5bd,40555e18,bf80ae66,b9742249,32679acc,d0e46003,e079e2e3,d20d248f) +,S(a462e750,9e718317,dbc72b9b,fce5909a,bdd2fc36,d56a525,97d3adc1,fe4b98a1,2f9ee390,13b70415,d2e6de97,7aba55ab,1f7c6f2a,a5a7b541,a7101a62,f2799836) +,S(72ec447a,245624d1,1e1270ea,1c4c060d,c6501f11,70c69f4b,229bb98c,e7c47804,cc32a876,33bb7d62,e660ba5,59cc1804,10a51cc9,dc48a9ae,fc3d8225,35fb8ff2) +,S(b97345ad,2a7eedfe,71ae185,11a3e2d6,c431e628,363e01a5,21622c17,e92b32a3,2ba1cb4a,abe0aaa9,619ea819,4e5c0222,3bea32fa,e4ee3378,ba798472,19670e2f) +,S(f417f269,de287f06,8a74a330,14331059,73ee691d,a7f5aa1c,4e00a100,1e2ccd56,1bb297c9,5b3fb72a,3263f126,719a82a6,b8bf415c,e81f6838,2c8b3a9b,42917584) +,S(cdf7b5d5,f7632248,be1bcc1b,61f56491,e81cfe76,1ee897c6,fcebdf4d,109b9b41,118f3f6,32f18892,d37a2aba,1c8d22f6,587ad56e,eacef09,b9202005,75ab7b11) +,S(3540c9dd,992dc4e4,9aba8fbe,8f28950a,24921b05,e1bae568,2714aa6a,95eebb81,841d9499,7bd92dff,53ee3c86,eafc5f6c,6ffac94d,3161ae86,2182caab,8d5a9268) +,S(70f4ef3,37a5519f,466cfdc7,ae779588,74c9a9a1,9a558550,8fafe6fb,d61decfc,413476f7,78f5d377,31aa712b,5c866100,bcc2a33f,ae1a078e,c5e5cbc8,4b7bac5e) +,S(d08990b7,ad5c205a,e5be2700,63bcf8a7,e13c2a,73dbf321,b0d9cdca,a1648da6,b0aa7acc,f47376c,115b0226,1494162e,d425b496,a2392aa9,254655f2,4db6cf48) +,S(53d6c5ec,f59c49fa,d970611d,b8423bbb,e2f5aecb,d4575877,d903d95e,eb88e455,6a954f77,532c80c4,42f2bf65,8e9d763,617c802f,369f1a62,34927e55,ac549f56) +,S(af7216c1,e51fbfb4,a5ec1e93,717f7375,9f15dbaa,86706ca3,6636f499,416ce194,4ed49771,f858a8c2,bad65a31,b5ea5a53,8841553b,accdced4,8c41e2f6,984470f0) +,S(c560d2be,2f2fa6d7,3f5224e,36acdead,8d91eee3,b99a219,a762adfd,a5e79d07,30d4b54d,a96fcda2,2187a2bc,1562d59e,24ab55ce,f9cbfbb8,570cd89,4d436343) +,S(30b40200,c728bdf7,510db9f7,a8a63792,ff70a9f8,c6262e89,4ef902b7,eb30fb8e,8c98fdbf,29f8c5c1,ce6d7d4d,61a2907,ab57b4ea,a25888b9,e8ce751d,6a19a88c) +,S(d7239e30,814ef236,5193c19e,dc91fcbc,955dab78,45b4f3ac,be994264,2a434e1a,454dc941,4500f4a0,f93f751e,1e2d4c25,8c0f10e1,b4f0c6f,3be39b0d,e5170dc9) +,S(60e511c7,7c8d7496,a3f262f6,376d3958,dfdc4645,73aa303e,a6e6672d,b1c21b36,bf86ea8b,c8a37a4e,c5ee1a60,d6e1888a,ac90530d,eadf40c5,b4f61a38,2ea1e340) +,S(55cd8f35,5a242219,3b64633c,27b1c1fb,7ffeed51,c815e1fb,ebaecfb2,3883d739,b6508643,7e53ad24,1fdf4dac,871e58f3,b5abb87a,d4920057,3c37a1c4,b2bd4b3) +,S(73cdc2fd,468a2d21,72a9e0ea,3d4a04c5,ab5fb13e,2e2ff2e0,8af5d70d,ac9bd41b,682e525d,1263abaf,f070bb47,6f754da9,f6c74d,27f319d8,5d9d2882,6d06fd04) +,S(e5f30676,3c9f620,1c5ada9f,6d01201f,97e36fc7,5bb10a12,4cf69cee,619f07fd,611f0f16,39aaac35,5e311a18,a5dd65ca,70e1a52f,452bed2b,3382ac03,dd50546b) +,S(c2c21323,b156ca78,5e53c41d,10bc235b,8e32e4c8,ee377fc2,42d089a0,d2a27d84,6b9f3faf,64331dda,d25d603c,d8f334c8,5cefcf5d,3bf640ac,96fe3bf7,71ce9cf5) +,S(599ff1d4,806aa8c8,b1440a92,9e2383bc,efd9b16d,899289a4,a335dd06,7e63d9,459cb346,7c387470,1b86aa34,c47b8214,7f48a0d2,7b9098bd,2b53d7d8,93e25316) +,S(f02ddd62,a2456e7,b4a90bca,1cb01e98,8b0a09e,62c90154,42db0f52,b635b006,a5666540,6cad4d01,aab99686,90a7ad3,b1ce936,957c317e,57bdb763,b8867583) +,S(f332b89d,1977afdc,aaf681a5,19bca58d,59852f74,78572346,b688d55a,d55a34b,988afdb1,afa1041a,51ed913d,d780b21,5dc90b8a,b5ae857d,73df2883,50ca78d4) +,S(d6fa4679,4fd4d05b,d6b7bdae,22a970f,8c3c3628,ea0d2656,55c0ebf5,2f1b3a73,d9f47018,86512ff9,9c4691a1,60b62e2,616f5c8a,fa2151cb,fd6dcd80,308ad947) +,S(2a13e09f,5c00016b,d974d62f,2c7c7ce9,e46fb142,e7334f5d,98fa2428,e26b25f7,f300cba4,26636d5f,7f8fcb2,bee6e5dd,b9697cdc,9f9c0636,b02b3fa1,820ca235) +,S(c6480cb1,c1bd41ff,e57cbf57,ea854158,36284048,e79dbb51,44a59027,13d13ba0,fee7ee1b,1652e63d,ad49736,8505b302,f135df7d,4a2f8720,74631646,244cd43b) +,S(559613e,8111c9e8,25fa96,aeaf4b2a,4019ea61,4c67446d,76305484,c9a4d7f7,cee9f4eb,2680a723,9187d407,f39390c6,4fed596c,b40f58a3,aa6c96e5,c8c9c2af) +,S(3a95b2b1,e6d19b19,84dcd59,501c33c2,4ca50b59,d410d99d,b9b6da4d,b1dc85ec,7a802198,a5c61542,81669bc0,640a8f40,6815d25,3bf8090,3ed894be,a1b09c72) +,S(5ae541d,b816522a,5d347339,713e92f5,25a637dc,75c9d9b1,5d834f2d,b265c2,e98a115e,f76b2102,7953f65f,cbbfd29b,a79b43ff,8cd6813a,b65174d2,b03027f7) +,S(88b5506a,72d681bc,d34eb118,3d6a7fc3,77e7f496,6d4c65da,bfa60a18,210ec487,c29638a6,ad91272b,3525ab40,1ebcd1ce,ecebab3e,b506cfec,e7e9df0c,6ee40501) +,S(2942de16,93ce8b88,e7e45657,daf88b2a,2118fb7c,9d2296ed,a1725ec2,f7d408a5,778f43,8b4f088e,fb99cb1,819fe6e7,55b0641,8d8679c9,d684faa5,16970f5) +,S(25c22037,e5a46e15,4adfcc47,480a088f,fb53410c,dea814f8,a4f2c387,df2afd0a,45cfaef5,5c5d3742,3380be3c,c38e6785,c85a90be,7cc92fa7,a390bca6,d3e7b3c1) +,S(b1f78a73,d0b935c9,80cd8ab3,b8237e3a,df5a40bd,5f875f7f,bcb13bfb,cc45839a,466141e5,d465c35e,37f80e57,c4923c84,c3a3ba98,549cc8f2,db6e0dde,915293b2) +,S(39405322,a57a4846,d8b42bb2,58f851cb,5570295d,71ded6cf,b803852a,8b4d8304,c81047d5,92fab5a8,c6139ffe,6887d966,e809d2bb,ee3a10b4,5adc5587,ffb302b3) +,S(7faa8352,31e2c6d5,b331ada,5e175954,6142b131,5347196f,bbc5759b,dd6add0,8779b0c9,2c176b72,5355bfb5,ccf5f739,5fc82ae9,48896a38,1be85e58,c48d154d) +,S(b786c145,61fe4677,54e14766,56d33daf,adddce8,e86e09db,ea93f1a,2ff0c3c0,4c5c35f5,99bb9637,75b4d61c,b30da8ad,a4e83a56,2cf7d2a1,fc22f06a,fff92aa8) +,S(ea4b9a9a,b4b509da,d1e70ebf,6604d624,8b6b63d1,c905720a,648e208a,993ce4fb,f5ab8356,ce28ccb,b6f1368b,344e15dd,372d732a,d8953864,21ce415e,6f0a92c) +,S(c986010d,6339bf7d,2ae3e9a6,c977b9a,a2033a42,14a1e9b3,e700abd5,428e2491,4156f13b,a68ebc80,ad12efe2,d5a0469a,a41adc0b,1dceb765,f651b4b6,b652a85d) +,S(385b81d6,e023164a,3662209f,5d694910,22e84b5b,7034e8ea,346941b9,c04df428,9d12b15e,c1868f27,362662eb,cb3c9bc3,1626ef22,36c2d75c,65e82c75,7ff81a2d) +,S(82196a55,104624b7,6710b4b,864b738d,36ebcfec,55226aca,990474b2,58aa978a,48dbd01c,5af9b1fa,21d88b0f,f6b994a8,38d47755,5ad85171,1a4e3d0e,14ab1914) +,S(dcfbdad8,34d74f6f,9df6c143,abd6dbd4,57f954ef,6323ff77,3a19c367,8d6616c,698d3051,8f8d7ffd,b45f0bde,c32c22e,2cb97acc,a8aa0aa9,c16d8789,a128c3a2) +,S(343b04d9,babecad6,5479cf60,e43350d9,8c56f989,69eeca59,5a5e97d,89c25489,14d00978,2729ea38,a79765af,ce78ff5f,16ada59e,9d275274,e6e0778a,facc25ee) +,S(25af2270,88a6beb,7c76a80c,9e87a412,ed166a71,d65d5722,a082e57f,8ac7bb77,d01d89c7,39508a84,5ea64e03,697c2867,5b14bbc,fb484f94,a530e57a,cf19ead9) +,S(1292823c,1759fa5e,48d0724e,67c93df2,c8ce9fef,9124c5b5,8a477aa4,dd3f5e32,c481025f,ece1bed9,26ecd3e0,3cd7eddc,3cc31836,a12855d1,639a85df,7c69650e) +,S(ed92246a,5a5cb2a2,1618deb0,794ea013,20560b42,273638cf,afc901d6,2ff0bb6e,3675cd33,825e611b,8802c746,9cd82b97,b659e31e,c31ceee6,681a35d6,2d5097c) +,S(8174e89c,9b3666aa,69ed3bda,6c73c572,ff3384e9,60863f87,b7d346bf,afd553df,154d75ce,caff95ba,4b5b7b7e,9ea99dff,499a522b,f0252691,cb6b92bd,98182d0) +,S(54169816,f0440f73,1f14de95,e7ab32b6,702c0183,62794ac9,e55ad632,95c4484d,12e541c3,ee64efd3,b5b8781e,bcc5e273,3544653c,d8b55d51,fa3f887e,d8f42465) +,S(c654d2a5,e31ce452,739f9cfd,b2784d37,eb974a4,fda45fad,13a2aea2,f7fdee9,47c9d2e5,24e7391a,f645ed92,cb04a0e5,6aef0362,9b57d593,edc85b1c,686ca4b1) +,S(59724a3f,eb1a1cd3,7fd6a5c,57c3d055,28fbdf48,5102e709,7ac35912,3f9c2ed0,4df18ea4,c0de4053,6bc5a6be,2df794c3,2db2a9cc,19367473,d88829a5,8603010) +,S(d99168a1,3fbeee0b,6aec4b7b,a0060649,1c4ca151,1cadddb9,2ab3478a,325b1073,c2b0876f,528de53a,f2f695b9,b8225fe0,4660a447,c9e9bd9e,4ba5e52f,beb0ce6) +,S(769c1b07,c26b402a,9a4b60f0,5bb0b318,d20f65b4,e941f525,43a15697,5a8f876b,7880299,413ffe86,94a76f26,9acde007,6e64a753,94701bf0,84324215,debf3d69) +,S(6074f53c,ddf9467e,b9fcc4f7,ea4b18ff,777abd8,895c9eb9,71195a9d,57b1b1ac,de1aa32d,e5488e69,eae8a06c,3c89422,a26f819f,af3cd9cc,762d7fa6,1fda3094) +,S(1f9ea27f,3e9e789b,1cde3fff,94bf8046,f5399046,867a2f37,2da59221,e85c655,c47b5ce1,3d399032,89449260,7db3f7a2,52a74084,20ab1846,fa378674,1e7bf7dc) +,S(c2551e26,5d3978ce,49cee376,ac86a0ec,7ba10804,bd894019,e79f51eb,ec9830c3,23dc4415,10635bfc,2af8f85e,c4cc59de,fed9e9e4,198304f7,e57a1f42,736871b1) +,S(2ca9e4d8,3358ea8a,40bc15b7,8c06169d,ed7a5abd,47147972,45078e94,75264d20,f3324029,9fe328b7,ecd14a11,6fd82bf6,5d925532,85a176a9,b7ec892c,ebb2cd94) +,S(e0db4052,8e3eafca,1f514b26,8b673afd,277c5aa9,e2dbe85a,74478d6a,f2ec1f94,f868c782,40dd75ba,3c6809d2,d62f80f1,ab7fead3,c67a90d4,ecc242c1,687376a7) +,S(d34cd3a5,764d99f3,16a260c,9659955,fda3cd9c,cb305f73,d3aaa61,27d422f3,3f3b80ef,74bec102,2e442e69,8fd4e28e,514d3a9,5011ba18,1299793b,b760da72) +,S(588dadd0,79d2280f,37dbeb16,3e05a70f,48ec61c7,cf3e6455,f3ea312d,4ab2e075,731a5c9d,f803c2fd,b22de461,d51af493,5874b745,4ab8417a,940383b2,9404fa3d) +,S(1731c955,931905d1,ccad3bc6,133f5d9c,9fbb10c5,e800be80,643ed02d,6d7477b1,d7e89b3,1f18ac07,6c7b7380,64d2449d,2d9beac,728ffa8f,6d8a7498,d43baf1d) +,S(e2f990d7,6818c0c6,e73d066d,5644e9e9,29f495ef,507b18cc,594871a5,88e45b46,2ca12307,fb565d0,7c60b6c3,e92c9757,45777970,1733c0ad,2b299a20,8f50925) +,S(b92872d8,a146c0da,ec576be7,35a22896,5242cc61,ba37313d,31b0e5ff,21a2273d,8178dd34,e552e97,fff949e9,b101b44d,35d6b57e,79c0e78d,f91ff3f,2817daf1) +,S(b980d2e,9440c3c3,be5cf393,6eb9634e,923cbde7,bbf2a07a,d7a97287,7d6caf11,51b7d51a,8685bf75,c6d376d,441dcd69,cac67b77,762f6ad6,97a9649b,f3d3719a) +,S(db2f9a64,3c3e3706,e9b5aaa4,5ebf08f2,ee9e967c,205a49c1,7dc76b8f,b20a3a52,d05d486f,ab967e27,b9e8c175,e93df203,4657dd,750ad788,1bcc4897,b80f3d40) +,S(5d5985f8,910be82c,538d70d8,9614ec3f,bc9e1f91,9a19950b,a8fc99d9,203d92b5,3efd77d1,27e43849,a710d1e5,7b18b681,c1acb293,2244fa7a,30f360ea,88565e35) +,S(fac2a758,a063dd8b,46b41933,9c70d2ed,3807bdca,69d3b36e,6369f8b1,23200866,8294340d,6154afa2,d7b730b1,301f5ab,322bdcf8,6fb5676,78fc47cf,b15809e3) +,S(cb92092a,d45ab0b8,559846b0,d02a0c67,a13edc86,7d0cce5d,fcc09e63,d1b6cbde,d2593de2,6371136e,390bd52a,c9811334,e13fddd4,e9b86b1d,942cacf5,4615b287) +,S(d715f4a3,66a4a770,bec8abea,49ab6c7e,99e9473b,73e479c,14011843,9470c844,40aff69e,ec6da9bc,38ec119,df4482ff,3bc2b67d,31284db1,8c757990,de6cd0d6) +,S(77312617,4a395a4e,f7bad07d,f2f38843,22293a17,ebf09f20,4732e7f1,2c418417,602cca39,d6352365,420c5ce2,9d2282cc,5d8919b5,e0669b09,22384b69,7bd48a7f) +,S(a7c4b675,f529ba17,e9f1ef44,c88a8066,66131845,dd98da82,4cb04f24,518a4071,d88edc2a,1eb0cd48,57283e3,f8658d8,2da27a7c,7ec16129,78fbb484,41ef438a) +,S(6362f575,d459b970,db814a7f,9a142605,f26f577c,4357be2d,dc16793,64906f7b,fbc9f007,bd08b6ef,cd49c1f7,1e199fa5,ede01123,5d9b015d,515bf7a9,7192f8c2) +,S(6cfc45f8,515813d5,dacdcbd4,c34c155d,c66b0298,8b8a8702,73a5342a,9249b623,f85c980e,394ea0b6,39bdc5a5,ed185de1,7b1f44cf,b7e51c7b,b9f56b3,496b5ee) +,S(d76c0b83,b8a8a8bc,4e8985da,f6f1535b,9ff3b4fe,e13eed4b,39d6426c,87cec8f6,15ddc103,bc6c4f43,6f7e23a4,78e47166,e3f4156b,5ad2d581,7f3a7ade,7d80dcae) +,S(c4f98324,57330d12,e4e26735,464f24a9,a93dcf75,9194fcd8,a2d12ce2,bce0449,e24a6f24,f9a09aa6,f58f29aa,f4e24a0f,864410cd,80280432,d82cd9a4,ea2ac2b9) +,S(e86da865,238fcc7e,d8c2721f,89c2619f,a2caccd8,5e05a21d,8d23a095,634cc439,85b35268,31871eb4,3323caec,13de6de7,94ddc6e7,5d44835b,7443137d,25ee2194) +,S(a6398918,6969469a,939e774,eabbce54,109b833e,b3dfb566,876cf50e,bdc7613a,c48430c3,fa8c730b,dccb53,451b5a38,888f2e85,1f510ca7,64360c9c,b72b6eb7) +,S(6986ef9e,88c8dae7,ecc8184e,a4c5d131,32a87ad2,ff8367ee,63fa0ecd,b7a2972e,e9acba9a,896e1eb5,bc1d2625,983fd2c4,13f54b47,3056a893,7197f940,92eb4bf0) +,S(47bf849a,e428bdde,ceb221ab,e0ea2fd8,c0a5bd39,175aab96,c2fddc57,e809527d,401a7ba5,1999aead,4dfa6ce0,fbad17e8,e7187e52,806a58a6,7033f653,67aa7c02) +,S(c0c02bb0,92af6a5b,73582a14,89067933,8b31318a,f2d5b142,d58833b4,cf07fbe4,a19dff69,5ead3a33,d8f9f7a6,76b8287f,4bf6b23c,6761b084,12d86508,830f8990) +,S(f2185913,405156ab,22baf16e,644063da,b3ba25ab,f191efee,1ff028e2,f7d175e0,814c64f9,9a4250be,2265cf8e,47c8276b,9e5245cf,16ec98b6,b789dd26,be894f3d) +,S(40d840cd,ac4060f6,de850df7,c37462b9,b4d5892f,a1e74f35,89ab3955,a5d941f8,9892b0dc,ff43a872,6974705e,3a3fd077,c2b91a2c,1c6ee153,7b728359,d3217833) +,S(6f6b79e7,9006fe48,5546c3e8,52a33dd1,cfb63f3,96b44d1b,af1fb112,93271b35,f5aa0beb,50a628b7,b5348817,8344527e,d1ecf0ff,a0766a78,faea2361,e8fde7eb) +,S(4edf60c8,c0488128,29e7bac8,7b03ce49,c8df0f1e,6a3e02e2,ea8ad097,f66163d7,9861393e,fcec430c,c00ccd49,3d4e2d2a,a45e1034,fd9a81e4,b015bd5d,56f16dea) +,S(7ab0c44f,f6a444c4,e0feb1c5,a6650c37,26249caa,38f53e62,b6bf225d,bb1e008,e7f9af86,a2839ce0,80c6ee9b,d86529eb,7a7abaed,aa6aa4e7,207e67e1,a500e5f0) +,S(6a90e50d,3dd2f382,1dde8714,57012b3,5c1103b5,80ee4982,f9bb78d4,2541f8b1,5ccd34c1,8455aa76,4cfe6c9d,61507ca3,cb613bf1,4b9eae3f,8391e1a0,9dec03f1) +,S(289d4d81,cccf40af,a61ef56c,242ef8a2,c9883267,54139e1,dbf018ad,5d251df8,f3fead19,c49de6b4,32869220,7e60408e,dcdfad25,26e6e555,9b022941,592081cc) +,S(a1ee466b,c561919,2e82a316,ac3b7514,b109f442,1c93fbeb,234f5862,d37ade3c,db12d4b7,246e8ee5,55dde2b4,9b5c42e7,408eff9c,a853af00,5a6f6c7,73aff21c) +,S(ab30a856,403a1622,14be9837,2ebaa8cf,8d946074,abfddf2b,8e65e2aa,51554329,7a6b7f22,a6ea52be,8c0c8002,29613020,a247c026,86eaf960,7fc56cb7,d696c56f) +,S(17c5f1b8,8e3e4e08,dab8a5c9,2a679c05,688a7437,df6336e8,7b0d22d5,ed56e5b1,96068e6c,72fa9b39,5993913b,305caf70,3186404e,17131b5a,24e14273,a83dccc9) +,S(a76fbdb4,b99e31ba,c434462a,64c0557,8e961a53,dacb9bd7,68400b8a,823190ec,52e31883,5ac1a3fa,e269a4d3,17bab065,7e890844,c3fe96c6,d04fa015,89c89f14) +,S(17b8bb76,10476261,ebd75e4f,299f1805,5c88f36d,ae65cc57,3c959820,25bb794d,1bd9a52e,585a40d2,67db59c6,b9b1bc59,4b8d5344,29b5d4b0,82bb1c9b,b54e0392) +,S(65aa92ba,8fa51cbb,3954b93d,68cfdfa4,d64d97c0,9e099b1b,d1ba853f,18500b37,a2b12d21,b7a1ffd1,af48e4fc,e80c6fc2,e624783c,7b0cdce7,9f01ae7a,5fc96e14) +,S(3450bcca,5d3b30b0,3743f0d2,6b61ea09,de6ef7cf,eed44b3a,c58641ab,93ad7867,4fca3307,5328a298,d310d447,4806f297,3b09d885,9fa3b949,11817d8,39be66ad) +,S(484bf072,134849c7,695ba73e,5f25a8bf,74a183f2,bfe35ad7,34b53878,a2036be4,a5295452,a0830b3e,3c45043,43fe950b,3289d402,73d3bd49,6c0cd7c9,156a1d6a) +,S(2cdf1bc8,920ec641,63fbc8fc,c72fe5c2,dfcb87ec,15725e04,163e1ac5,1b7ec763,c680476a,28f054a9,ac3a073d,67ceecf1,c8262ed,4bc462bc,44798e88,d0e48e54) +,S(59c3c60,8031a214,d3e6be15,c644265c,b6f3526c,2b37d840,86532c24,52359bf9,2248b28e,922e0468,fd98856a,41ca37ec,2fc7bcf9,a13c7a9d,b4135e28,5cdc1bf5) +,S(4f20493a,a7a1e558,a44e54e3,b81c889c,d45b6384,9b8448d4,20a34a31,c7c451ef,bc1adcc0,d00384e7,93c2433a,a76f1f08,b8b23170,6e285d56,3155dc19,d5aaaf1) +,S(bed9949f,dec9813,5bcf76b4,83117fca,57525221,8a6a52c6,a44f2468,29d48ff3,6ab35499,8cad07f6,250dec89,a0840192,b62777df,6e241a4e,325b0c4c,bdad23ba) +,S(1cf32b2c,46deaef6,fbc892ae,4f05653a,3cb69d0d,821a7125,3c2eed77,4e75f767,caa6268b,b8574b47,840b3626,74f4a479,5a2c6478,c440aa4c,36d88a2d,ebacc8f6) +,S(9d3f7c5e,5e0947cb,d9bef5a2,dc1a3e9e,ac22d6a5,9071d0eb,5f270100,3e66dc96,6ad63f62,22f3a787,9544c330,4c3ff653,2a00a764,5ddce01e,c4ac4933,a5c7aedf) +,S(a5a927a3,f03dcbc,b3d069ec,156a6ba3,474f48cd,4828f54c,a673e10d,265eab6c,b5e360fb,39f65847,b63eb29c,a8b403d3,272d9ef1,8127d3f3,7650d13a,9a5736c4) +,S(48de778b,7bf72a21,871ea379,c02b8887,5da9688,37faeaa9,93e68eea,926db673,d25cb808,7a7c13b,fbe8b1d5,522ac2db,6c44526c,13ca0327,586d6a5c,1aaca91a) +,S(a029831,66e7cb1a,fff65515,48faf447,cee8ab2c,d4937269,db002cbe,b8f1d1ef,ef34ec5,42554e97,1ae8897,b049097e,3430c99,d8e93c50,94377c07,a5619ea) +,S(6ed75b96,c4e976cf,75cf0b72,df83c043,5b15d2c3,f8fb319a,94a4d97f,1394df6f,9b63c36c,1e31becb,e1a5a6e2,1abb99d0,d5c39694,cec00fd0,ffc27b53,309bf6eb) +,S(9372c1d1,6997f792,688a55f0,8f246cb0,f206ce31,d0f416c0,c81cbdd6,8487aa5f,ff97433b,be60eaf6,6f19c182,e8a8bbbf,b24cdcb3,7aabf79d,5dac9f13,9c5033b4) +,S(269c7d84,b42f90b2,f39b4db7,5ea0724f,fa6a1a5,4c66a1bd,a21e4254,6f243bf6,8f6f8b36,e278c6fc,bb0c9918,7325f1b9,75ec3add,69708be1,b4703c5d,53d8f8f5) +,S(62f9cd79,921ec46c,d470a12a,9619ad4e,3bed051c,14f47071,e55f9da7,d103793c,92211db,6c846f43,2867b9ee,3b1ff00a,a08f179c,13aa7475,d64d0731,23a69e4a) +,S(fa432dcd,e7e3b40d,a127d65a,e0955d58,a009d81b,46b48745,c4e24597,4e589a8e,a8dee557,cae7e50,d96555ce,c56255b7,c64d10b7,6639b3bf,8d60aea7,58716f68) +,S(a424d18d,c6861074,40f42e5e,f2bfc95,f4c8f94f,e3adf681,79086502,fd9d80a4,cb30797e,1d973012,d488f54,6033b1b3,d6b50c8a,39badf8,fcc12bfb,3a1c4d0f) +,S(c2a6369e,e2857d2e,fce4ab31,49556c08,3ac6af90,6be418e5,ddc5677c,f2f7ec8d,a7097ae2,9fea3774,11ce3f81,b6b3356c,9a2abb69,986ad81f,46b13f8e,a0e7f0a1) +,S(f5eac1a2,3dc91862,d8022931,3be5c7a5,364c0880,23c0650e,53e22f42,2f91ec98,7dd62b80,3ad606c3,3d8d9bd6,cb397ab8,1cbd688f,8375a405,23bb7315,a3f48c24) +,S(dd94fec9,3bf7ec6f,cfa0ced9,df31a1c,131c39d7,e110b5e7,b988c59c,dd594fec,cb858565,6a32e03e,2eb84732,4bdfe2e6,3601148f,7bc7e56d,22cf9aa4,54f063f4) +,S(d3dfdaab,8f9db2d8,edd3db27,d96be5d0,678e9088,5448222c,5b3171da,38fbd501,6b210554,df32021f,35170e13,42e2da18,72be61e9,481a4b74,ec470ed0,b942025c) +,S(47ff9918,3e452838,f63eb828,a239d95b,62f8a746,8acd0b43,6c149985,2afbe3f9,33b7b8a3,a5b51b15,fadc1f9,baec6b8a,88e0da56,5a54bea6,1b2d728f,eabbdc48) +,S(1e99e92b,aae56401,1cc10c94,dac071a9,27565a17,2d6d4a20,224e1b49,c007660,914b98dd,a92484e5,a43d7de4,7bbf57cb,2346d852,f743fdd9,15dcedca,4393aa21) +,S(e150364e,d95ca778,70fb3367,64f9f417,70bb672f,7e794416,13678dd3,65d84fc8,23ddee4,30d7b565,cf545837,58df61fc,502bf86b,a4cbc1cb,7630a9bf,e339ab85) +,S(44dbe753,dd822ae3,f3ef4939,a1d96a98,33e697f8,c4979191,c64114f6,71e8fbb8,b909bdb1,e6e55571,b03517a3,c2345b49,a5793d21,15fac018,2afbefe9,c726c8d5) +,S(fb843458,725d557d,b1a17ad0,427b4d98,6ba189e5,d6da81a8,81867259,6d9d2858,18f1c9ea,bd8e71cc,72e2dcbc,532b101,c7381475,46c24790,d010a6cc,32d4eb10) +,S(48f43c41,b63bbb05,57f8d71,edc739a9,57baed23,efe9c814,848c54e8,54159144,cb75c418,d5557cfd,b29d4807,3f193343,6eafc209,bdf9685a,72f57b98,6676b193) +,S(5520f175,9be037bd,cb5af2a9,a0bdbcc4,9e1531c0,32fd17a4,66f59b38,6d7de1b7,45b933b4,cf256aa3,c6513a2,8a4eff90,7691a34d,e6cc2e7b,a0b83f8e,a7ed4e52) +,S(83936718,1d7d065d,5c15e246,ce8391a4,bec58c71,7f82419a,ed6547c,63f081a9,4c903568,f5ce9a54,65fa845f,985f24d7,6e66cbe,3ce256fc,1703b4b0,5dd636c3) +,S(66a82c47,e756062f,6586ece,86911ac2,23b84c9a,e53e5307,4e22bfbd,3eae6b30,ab2051c,4c231a40,c6da6ac3,5ee32b9,b7eeea17,222cb1d5,a3abf9b6,512db8ec) +,S(974ce35a,9d5a4ef5,84d252dc,3c365423,1335c52a,e3daefa2,8ff9b75,56bf3b46,8c82a9a9,c49d167,4f3995c2,90ae06ac,fa0a5c14,b1c5f41e,c1e449d9,5effb2c0) +,S(1139c2f3,60cb8a4c,e020bb8c,3d19bce2,1c6802e8,5fb3df33,8fc9ffbc,8fc231b6,59adaa14,7980b3e4,73801b73,9f1e0248,2e9f1e17,65df2ec0,183d9f81,d57723d6) +,S(c1bd3793,3b03d95a,b17c10bf,c5167556,4294e38c,740fa3ef,9b356be6,71883b94,c68bd82f,5e926a59,95a83f1f,1a8c2f4,5966b073,91ee74a5,ae2ed99,106c6dca) +,S(c7778ce7,ce668003,86db9263,cddcf608,aff769e4,b4755858,20554ecc,8407bbf2,92509200,9c57f224,8f9b4e71,532c698c,88b91b77,4a3907ae,1ef30c51,78d807c3) +,S(14aa1177,51626b67,8f32418f,1855cc34,52d4ec13,d2d900d8,8a22432c,70ec022b,6151fdf4,f4372a2f,e803478c,da340678,c18a0a7c,d540b0bb,4168f9da,2edd6d81) +,S(a53443b1,b6065cb6,abb18c84,1f171b3c,7152b34,293a7ad1,2e8599fd,f1398cd6,3a07e076,35254aaf,eb30efea,328e3ffc,3a7d280d,5cb2c8ae,9e70b412,38fe704d) +,S(35c3e3ab,ba4c946b,1eafff67,a9831588,d6631e18,9507eca7,66e22449,f8d294fa,94973920,58f6830a,4e5f413e,4d7d442c,4348328a,5115fdc6,ae5ab638,339e313e) +,S(1aabc2db,5ac6df10,1d097db6,26e3623b,295ae6c9,941e3717,ca849065,512a7fa,2d2781c7,b42ce42f,b40b737e,9100ea24,ecfdf58,fd724244,dd67d84f,4a6cb097) +,S(383103b5,5a4beefc,89dd082e,f0e14211,9bacc5fe,8acde710,7429241e,f16820ca,2000fe09,2b820a28,f065924,7823d6b5,18756044,1856dc46,a9fca8c3,84913398) +,S(2cb0f0b6,35022212,88b8be63,a0ed5d71,bc6b89ca,4b2fb4f8,54123124,49445107,9a9eacc7,cea4c27f,ac63a2be,96884112,435d5f6a,bf4ad519,461017c6,1c87b2a4) +,S(ae63a05f,306e6980,f439afe1,b34c7b3c,1453e110,e477e3a8,d7e9ad3e,fe2af088,6facce76,d579afb1,cded78a4,1dc64c79,b6e90279,d8c5f07b,fc2b0a3c,7243b309) +,S(83207533,78d5c6ee,ae26aee8,4f2a0833,a65a94ef,53a477b3,c8708ac0,35dbc24b,d8306300,4caf8d6,7fdcd09b,267a2d5c,b0e83e97,60fc4d8d,2b07e2bb,c2b387e5) +,S(f38888f9,3337633c,9873d501,8b9fbfc2,ad135870,89f6becb,528ea063,a817af28,8beb556d,8e5342f0,6fe06215,891e6091,f8b940fd,b6eebc08,ded95ea0,99985ecd) +,S(c15cc888,7d13a93e,c2411ea1,6f21e86e,4fabe47a,55a94a6c,aff7681e,d47ba1a4,5bcf5b68,91f3e01a,3754fed3,f70e5052,e33fb62a,753c5f3a,532112e7,f7f58f55) +,S(9b3b0b21,1befb305,b02d035a,1e7cad04,3b8ce04,f9315bd6,5067a73,f2680030,75828df7,eeec11f2,e0dab801,5c75213d,cd93cc84,7e873e19,b7d03eab,e368f989) +,S(2028eed7,50cc8973,c1ca2f28,a30c05c7,73e2a05a,db916825,60d41cea,3b4d0a18,40efea34,b941571e,98a0878f,a13c4efe,1e3410d8,d5166661,115cfd55,53bd0d71) +,S(ca697e9f,8954a7cf,593068b9,1078486b,c8c9a71c,d1f7a890,a0a3e0ec,e48521e0,4268dc9,28ef996b,56af66b4,2f410831,b9f8c6a0,2658d706,975a7624,6468322c) +,S(26c2615c,ebe251a8,a78b00d8,1733aa70,f8f9a97f,85c2fcb5,d9287e34,b786d4d3,ecd17c3b,e1b3232e,bde8f859,39f5158e,f8c340ef,cec4e758,cd54eb7b,df4df77f) +,S(7296b5f2,c4ac6a83,c180cc55,2fc79a84,691c50df,8e56ca8c,731ac368,2d8737f,d4410073,1f98235e,cd75e26f,d251bf8f,f93ee806,52446208,c9643fc1,1b938aaa) +,S(465d9610,c3f6c8e7,366ff5e3,9e1e17be,53ab9eb9,f299be2d,3d9dfe6f,fc601a5e,741cfef2,cd41ca9,4b847ad6,93f29e2c,7e0bef4e,6244dfd9,8e3bcbeb,8c3ae7c) +,S(d3264c87,fe435796,b4d40631,a0a64a34,570e36a9,809d98a3,7ffec23d,9f3775e4,e6fa5190,b66bd281,538787c7,40bdaad6,f37a1eb3,90b19c3d,cbc65b19,9bad22ad) +,S(d925ed62,5551d49d,151dd55b,2cde29d8,fa5dfa21,e9454c17,a834f090,7d744640,e398cb93,1c9fc1ea,d9912968,b335015d,162a04fd,c17049da,80a7ad4a,b3b21451) +,S(2f8339f7,72cc9ff5,c59ace6f,d38a13d8,21562e0,a0d5dc2b,a2c074a4,f697413f,d09d6be4,3678836c,e110e805,68a2fbb0,b87d1657,d568d7d0,e4ba1237,dbb4fa4a) +,S(f954909d,f67de727,72437ad4,d3229c50,8440d23a,9215394d,d09c7232,fa5cd0a3,6656c1b9,8e726305,644994b1,eed6234a,834f74d9,2fe16ec2,c945478e,ec53fafe) +,S(962b9348,d9b64aec,7ae38297,e80a5f80,ee1ea253,6964742,99c5196f,cd58f33e,10601c5,87838f02,5b6735c1,b711141d,ed04ed16,2fdc5bb,4dc593fe,9b804145) +,S(b70436c8,4c6e25a5,34c3c2c3,34f13350,7050b552,72a04032,84a744a8,6336efd7,1b9911f4,72a19b13,e8bad704,ad3fc911,3223a5ae,4939138f,86422536,da1009d2) +,S(8989063e,49605ac9,78705f40,cb916505,615cc465,40c4760c,db302cc7,a9e4c6a,e76c05d8,5b32b5f1,9913472a,be4322e9,ff5149e6,e224da9d,dde930c9,948ce8ca) +,S(9e2c1711,29d01e44,25e4d5a,802f4c5,84eaa0a2,2aa8fe0b,bc0aecc3,15fb00ae,b1385087,ff34618a,d126ce7c,dac3a7f5,1f0fec09,2a7a9601,b65c2786,c733fe81) +,S(3a88a3cc,164795e9,cc668d88,d9ffb6d3,52f90edd,c6b0aa5f,dba493e7,273731f7,95f0b3f8,2fc2c9c8,a25b337e,af92ca08,e17ef68,ae5abcd1,43bbf5ce,d68a1fd) +,S(f5cc5ffc,ad18ea3b,c15ed2e7,d0ee8e9a,141bcd7f,8e6fbe1f,81be287e,e7281725,ec049ad7,6ae3bc58,9a60bb7c,ae79dea4,b512fe66,bd812ec6,91fb3182,27d9a288) +,S(c8af958a,201a29a,bf880688,89c211c6,da59b59f,ffcc02db,9010bd6,65b7ccd7,3755194c,76d6e0a9,3f2424fa,f26a512d,f0605393,ecb5216e,d5f1d452,99b247f0) +,S(16f10ca2,a11493a1,361c80df,40066683,93c02635,78f11f2e,d9153dd5,5d6019d7,b9fbc23c,39323b8f,6fcfbfbc,b1a4b81f,e7eb1bb7,2855f46f,5379c68a,dc4680dc) +,S(1b218d55,81d012c,5e804030,ed342308,29675ecb,e1608d75,1ac1fb26,434744dc,8ac73d03,b888545d,dd8d0321,afe66cdb,e8dd7c6d,f1fbc3d,74f7ca46,c551f357) +,S(d16f309a,820828d5,e2d30f78,2f055428,fc8e7bb9,dcedf9c6,34640c19,7562685c,1f27768f,9a2c63f1,cda9f0f4,132f41ba,dd48a03e,5e387abc,d6c73a51,2d1b23f6) +,S(75c161ae,1b38e93e,b623305,e2566957,a277e515,44c2fe13,e02ccb8c,c72886bf,384bd613,39e4e389,5cddf7e5,b0cce8d5,35c03c29,118624c7,32b75a23,a9befea6) +,S(3327a22a,c4891ceb,2a704a19,e60d04fc,64cbb0d1,dbd5a1c7,bcb2f4b9,8a1d0d2e,1ef62067,d81d66,8a7960ea,a63832eb,5c6fe33d,3ed99147,b7f68eec,cf81551d) +,S(8c9fcb52,65eb08d2,90cc1f6c,9c3d70f0,2b553119,2a0c96c5,f59231ed,370c4036,c986a64d,f3972c00,5618cae9,4a84e74f,2566fe4f,aaa0e2b4,d3f52e9b,4acee6bb) +,S(2465bc60,19bab7e0,72bfeefd,9d974124,19bf47c3,24477dd6,c83ea3a9,e9a3f353,675034ba,c62cc0f3,afbf5027,23127859,280e2b2b,91aab521,9b48a36a,d5bcf77f) +,S(3eaaad77,af1f4e6d,a267bce9,e7095672,c44deecc,a71ec3b8,c86d8774,ad06805f,8a3277fa,6247ad67,e6aab22f,a7e7375c,b95eea16,a055ca8b,32615122,30033ff7) +,S(21734e43,c3ab4ef3,55d36330,adc76a02,7fef2658,92c29ea1,a26972fe,48c3528c,e1d82d68,612ba50f,cba70f17,3cfc17a5,d2d380c8,d62322d9,e6e93d3e,475ea6cd) +,S(d21f30a1,19f86a54,2c7d74ba,20796cbf,dc6644fa,2327392b,3aaf9f9f,ada97235,22d5e9ae,2940960f,6722d2bb,c077d9ac,aa12b5f8,b9a404a,e28224d5,5b604f6b) +,S(41741846,c3c6355b,69e39c98,fcedb9b0,73a5b526,75ef5388,819fbf5f,ce1d00aa,3978dffd,d11f4f53,ae1f5aa6,a04153d1,e9ad984d,8feffa10,9ab57fe3,f58145f7) +,S(cca0a89e,6612524b,a9c318a6,879ef971,d346e29a,4cca7c2b,4619a1a3,1f567163,8ed2e1b3,587cb5cf,37e18db,e9a95ca5,17795137,a8215cd5,293aefd4,92b74dd9) +,S(dd3be3cf,83feca12,c3dbd1af,a9166d2f,138efa4a,297c742b,778da203,dfff3728,b0a156d2,93dc289b,94abc958,f17cbdf5,94f04cba,15b71ed0,197e239,8b56976c) +,S(6c535f98,868e9ec3,31135e87,b80aae3b,a0609455,8d426bdd,3dd400e0,344a3cd2,30bb8bb3,4ccc439f,c343d3cd,ceabc511,3efd9087,d17004fc,37f70d98,94e3c04a) +,S(338bec98,1bbaacd8,8b82a53d,d1ec2ea8,aaf7fcfc,e5f502c0,a13b95b1,d5fd9000,dcda1b41,ca43c103,f0c6b294,5f9e94be,be971eb3,12f18197,b4dc795b,1efe13d3) +,S(b70accd5,24961804,40dbb087,c3c11f33,f27c7e9,886aed80,b89b121e,8d51ada9,6272d04b,3ec35419,be43ecf,72824127,ae4fd87b,640a5a4d,8e8ea05b,5f3f9b6b) +,S(dbf05f1e,b489594a,146de62e,c9423699,a7aa2d19,93919b0a,2a26b53a,a0f1a033,9608352e,a1abfc2f,47c42ed3,8f1d2ee4,bb28ce2,9dc98325,eb137acc,36924d65) +,S(56e94226,a4237f18,c57b5ffc,cfe795cc,b11522e1,fc47d549,6dfad2a7,2f109783,f137a96c,7965b8d3,2eaadbce,d86abe0c,5ee79de0,9b94bf60,8d72a4d8,8cafb542) +,S(c206cc19,28af717e,63e6e7be,781ea37e,d7dd1766,f1553fa3,2acc34ea,c1157bfe,78963ba6,f03b670d,602fdb93,d71dafc5,bb5ec7,b541b9e3,a84d42ac,1a444e29) +,S(8b579cc3,6455002c,372bf1c3,21012fbc,c29e102a,9acb149c,93c651ef,e3dee157,9fa8c521,e2f911c5,3438015f,48134dfd,66fa5acd,8916902,c1aadb94,7ceab096) +,S(3ddca5bc,e582f08f,ded36cce,395f4672,9fbfe7a2,c9aa3479,7fd2e332,352daca8,d77a9165,e281ae70,f1e9a265,630acb60,bcb79f30,9cd926b3,550b6c9b,644e5e6f) +,S(ee7c92d3,d81c3d1c,6384c771,b609de3e,e4979ce8,84df6312,fff84a0a,bd5e662,f131dacc,28415d22,729f2b70,934ef8e,3033b7b,c5a38dd9,1a11e4b1,7843978d) +,S(b9f80abf,ab86d596,521bf2d9,cf500e15,adedade8,b51fd8fe,c1d8de53,f4191222,82548186,bb97991f,1f28a93,804cd0a6,378355b,f7c7ed41,4cd585ed,af0afdab) +,S(1ab67bc1,50fcd943,f0b3419f,e5de2969,fb4428a0,b90981d1,a3893c6,18aeeae9,56fb8eb4,4671006a,805e161e,6e3f2bb6,b0199659,667967cd,3c72ba65,97a2c39c) +,S(17425974,39a91dd3,72c09b53,68d9821b,2acba5bf,a5440118,ddb5c494,fa0a807c,1b73d3d8,5eaad3c9,b37f7451,2a7ddd17,97e10e71,b640a820,181757a7,6cd27cba) +,S(72b080f4,d8e812fe,b485361b,59213f59,cd708e6f,d2f7ee71,27af3d87,971633a9,5b9c6a0f,d7a6f32e,f26a4584,542c15fd,e3504935,baa7b48a,d67848b9,67229f32) +,S(94e5f999,b8927b65,a2f4d318,8e3f2fee,229e42b9,ae3e6b46,9f7ea373,d3f11beb,aa27336,204738d3,b2a306d0,4c6efad0,2ae3a431,1da988f2,c6c1decd,b1fb3c92) +,S(2f59f652,2f045980,833c45cf,ef8f3a37,d65ed946,9b3beaac,2167eff8,142e8a03,9101d9d0,60f1a770,9f604eae,4b4243c4,6096c041,2f861106,dc4b8d1a,d9f9b170) +,S(95a443a7,22a88b70,32194130,a349a952,67b89786,e33938c9,7bef7fdb,d211b54d,3d80619,399c0975,a67ea7b8,9a5f6427,ac454278,42f54932,cbf71711,3ae460e7) +,S(c8430fa0,2ce95d35,96eef42c,69f68502,100a29c3,6ddd1f46,daca1e14,4f382d0c,f26c4baa,4a6d9711,e6de2b92,5042c6e3,cadfe60b,93d4f385,d759ec72,5a32bc21) +,S(67504cc3,ffaedcd0,c5a2704f,af1aa41b,4cf489d3,5c23b6d1,4529f4f5,c49afa03,b3858859,b3749792,4d01676c,d96fc03b,37be7b82,aee57e64,a44ba433,2fd936c0) +,S(d4fd8a19,6a56052f,71e8d51,ee3db667,7465ea90,f8449939,be9d1814,86fdb56f,7fc64dee,2bf744a5,ba155865,fb722e11,f3087010,b566182e,8a39f718,922953dc) +,S(12810eca,7f3087,944d3dd2,69baabcd,491113de,99b36ed0,65520569,484fa7ad,f25d02ff,81ed030f,1e67e002,6680a3df,3f27edd7,76155966,6f043f85,f82c9e4a) +,S(b347e0a4,102d2954,cf3ebf6b,7c0e5f88,6a823cb4,c134897e,3169b081,8bd35f4,78494910,3eaf28be,b2d9732,f88dc9a4,66a8b5fd,cc50a2b2,8b347436,2e05cc93) +,S(54cf5638,7972ba75,48dcd07f,1bcc47eb,5d99c95c,a18de15e,9d2ac40f,1435b27,48558294,410d7ed9,9fb008c2,32cc6ae5,33bffa9f,3f02f0a,76b1f390,9e78e507) +,S(e75c0831,ab9569f6,4844f67c,3650f691,e1f84366,46a28613,653c354a,3107cdb,5e2da0f6,83cf019a,82e44f84,e7bde49c,5d477f34,fcbfc3dc,2a9a2a4e,3ead0a1a) +,S(f9eb5462,7d88b64,5899b177,99257d92,4570b3fa,59fca83e,1e302f38,5c524693,dd187873,9fe69020,970609f8,ca1ff56c,3aeac075,43e6cc5b,bcf75af0,2932d516) +,S(8890093c,5bbdd22d,69c91acc,5608e19b,59d2b105,b75e054c,8e873b88,59865997,1f18b0bd,e9b546a,9a2955ad,492290c1,a041b61c,7b534e1a,bcd4db3,b5148bee) +,S(76b95d04,88c9bb7d,2cb28589,f7f3f9a,e2ae24a8,33adf557,76bc3132,4bb80168,590b3022,81649af7,bb2cb0cf,fa0e90ee,13b97294,1a7a8748,bc9ce53,88744e53) +,S(8b3526c5,afd2a987,f8a04949,bb5695da,8b073b93,d8418878,28f9d49,2a6ff4f7,387954e7,60f2ce55,17213bf9,c987a9e7,f9b9b05e,c4677911,22e7a28e,777ab4f4) +,S(2aaaa06e,244684c2,571785e,a77a76f4,2c4bca21,14fb290,ef66d150,74ff2658,49e3135a,3e8ed289,4dcf61d5,7e4cce47,815ecfe2,5bb1d8a,a5d067a7,924fcab4) +,S(981b94b,be061268,c02db0f1,fbc330b7,351d6229,b645e4d4,3d908be4,241795af,c294f8d0,7b6c70e1,c18ce6da,b3d28c4,d53f3e9d,1f8d9ba9,de18cd39,51c8ff5a) +,S(53721e95,737d09b1,49eb185a,1663999d,23429e88,51ab849,a671c0,d86efa3f,d36f27f1,9f812f8c,c9d770a4,1655ef57,efc1f126,ecfea4ac,dd5bd42b,13e20a54) +,S(9ab129e9,a4d92118,3ebf686d,97286d1c,9608003e,67b026ee,d3d06a8a,e21c0bcf,4683a375,85be92d3,331732b7,8e12f452,480a9569,4c309907,2bbb9427,602ab016) +,S(330ed8c3,3c3647e,7b80f38,f3a1865b,d33abc8,ecd4d0d3,390e8ab1,a20d1c0c,5e3db6e9,33d6d0d9,43cb4202,f9ed135d,ced588f,8742556c,2012989e,768dc770) +,S(66c40c78,6933308b,9397f3c0,3c4263f0,357d0f8,a6a9eb06,725c4c15,c226d57a,697777c7,13cf3b5a,ca964377,fb124f87,81743794,afbb1966,4b126a86,9f90bb6b) +,S(36ce2c7a,9c7f1267,c081c9b4,296a191b,951415eb,12e95b02,e5f5d3da,47809b23,ffad6d8a,e00096f3,878f54df,5cf714b9,6646b5f0,9cce0d06,ea38c558,140223e) +,S(73fefc2e,ca71a95d,2e9d5d0d,464a7408,e38e21e,4450ce8c,51ec9d6d,79b43f52,cd47ba4d,6c2ed98a,c369ccf1,a3d65e05,758f7f70,1ca87a02,5baab12f,5b765a20) +,S(cac2c00,567cd06b,d4e98e04,e911f7b8,7d4fcc19,28a5b58c,635fcb96,bc7c0a8f,fde04dd0,3235a3c8,9b304c97,7889506a,c3ef937a,e1dfce4d,ce29a1cd,dd385090) +,S(f6eb390,2654aad1,1c69c028,2d1449a3,4198e774,3d329c3e,85a8af7d,f6219e1,6403deda,8911378f,7defebc1,ef7a4ee6,20802e76,499993e,15b22e42,3e492d0c) +,S(91a7da19,ecc1a979,7d5dd222,edd74bd5,af76d200,30cc27bc,41304ef4,578d8773,a32b1a26,e77631f9,6a3dfe17,ddf16ef2,f38f4026,4d3fb882,dfb34cf1,5fee2f1f) +,S(90c3942a,7b00bc3f,7b852097,ed4590af,cef6fbe,783fd717,9fdc4955,a4fed12a,aa7d174a,8d9f1292,b8e4d9d0,19dd336e,da305ccc,ab69659f,90011b69,85366751) +,S(717c0973,ee959e19,6d11939c,acabeb83,607f9367,83dbfe6b,911f30a3,c51af3a4,f93d840e,88497801,223992dc,24dc976e,dc0b442f,2f845650,4903c9d8,338c1ce2) +,S(831f9794,c88cc5b2,2d202130,3731371d,a0ab67f3,c080cfa4,d958e6db,aa85d140,46ed65d2,1c8b5565,14e83074,e84267d8,43f47154,8774533d,cc11e6aa,cc655895) +,S(f6c7e9f6,69447c19,843ff209,72c47cf9,5341e0f9,d2d5f14e,c9b17abe,20eacdab,1bc7e847,a9f2824b,5895edf,cde746d4,5ef0fb67,b7db1637,e62d2d40,e046650f) +,S(c0ce97e7,ccec223f,947c0db2,62fe3865,9e06fc77,99a41581,7ec36642,9d5f120a,dc281020,af95986,dfafdfc6,ce122d33,e797197e,c24c09d,7e6f04a1,c5b4793f) +,S(e1eae094,f68fad14,5d905240,e79abdef,562ac20e,d52f3503,db34b2db,d2f72d43,71e4754f,ca9df5ef,b3b86c88,7e3eba7a,33554a83,cd68ebed,f6dcdea7,fecc6486) +,S(acaa286,bfd582c2,c938ee36,23a20db7,5cb6f0d4,95419f33,b0b35f2,59841bad,c3eea949,18a16138,caecb54e,ac03b6c9,282006f7,14d4b024,2bad29e9,aea7f667) +,S(87f6893c,137f60ad,22a5d543,2dc2cb2f,f2e05fac,d643839,38936c2d,206afc82,f6bc3092,1de852d4,4894d318,aaff9243,a9a521e,501ca78f,c7baa82a,3a118ed4) +,S(9df94d49,e9508ab5,63ea1,16cc4502,aeed0bb,7b1db426,c6695da5,8da1f59d,51786cb4,a7caea66,39546ae7,5826dcb2,5abc5a76,402fbe9,b32432cc,aa48adc1) +,S(8a902a14,5ecfe343,503f46c9,71693677,80499405,5df02c32,9446a373,e34777e3,fdfaf856,f777d30c,24ce54f9,d503fc8e,a3cdef47,e292ec5f,f98d6449,a69b3f0a) +,S(ad6128cb,8d9903d4,23558eb2,23fa580d,e31c454c,d3985ac2,6a2854c,733c05c9,9b69c9e1,564c9271,5562d4cb,fc040495,6ca539c9,691e2f02,5f41151,ca6667e2) +,S(c2a2ff9f,6d064f4d,551cae44,f726a8cc,b14c9742,96725620,1d01581e,5375e57b,ae53fd93,fc405150,3d6cf2bd,bb51720e,7555cb24,ef7ee8bb,9ca306a0,59563e65) +,S(56c0fc7d,c2ae8f26,4e132fb9,3a52a634,2b80dd38,f329fe9d,1871e2c1,6529996b,5d012467,cd511264,82399d80,c7f8d248,d9267251,e4d18aef,ccb9bbcf,d854414f) +,S(2131bb4c,5014e751,ef0690bd,562ad29c,d8db4461,9eda575c,9f0f75c2,da4e0f32,7bbb234f,7a83afa6,47599f05,8ab8f5d2,83f1f02a,8f8d5292,15c7cdc4,71f03fef) +,S(e8adbaa7,bb0542a9,9b9f7598,59637f1a,cb734257,13247db4,540b8268,6c14a462,72de1317,fb5ed43d,ec57ebf3,dbec4eca,bef50923,a4743359,72aee4b3,c03190f6) +,S(827e8e05,2a084162,19c8894f,ec6f31c1,a7902792,a1e8cdce,6fa5f732,4b428417,d46d9c86,4fb85e09,81bd40b,b6c3a563,8a74c222,6e7c8299,3ef6b408,4aaff5b1) +,S(3dca9759,338dc06a,8e81218,4c14c82d,3fffc50a,6d0125d1,1af0523e,d14fd699,e6c98f39,b3fd3ca7,66ac5444,be93fe24,3085a38,7b484f28,da571afd,4b8ba210) +,S(3ceb28d2,e59d3692,63432323,c36bd680,f531697d,c33245aa,bc7c5838,52bb8eb1,d2456980,96a36ca1,7301778f,d1661743,f43ed9af,3968e4e7,55ab39a1,6ded2d19) +,S(47ce6c4d,c1dc8371,de44ee1c,828e4b3c,6ba040c6,8dab0802,417ecc31,1e7d79ce,2d6b7bc7,c43e478,6df00ca9,75268b3,39f0ad68,7b0c70c9,ca857913,485419e6) +,S(ad6387f,fde71126,d0784af6,fc8a1ca7,be9bfee6,176245cc,2a18c9c1,c17f156,3233a7a,d7d50605,8cb63aa9,becf9eb2,bf8fa88c,afb2ce9d,a9236736,803dda1a) +,S(8c9c591f,e2afc468,4b64d9c,44b92627,e70babb1,aa9f7f00,6dd5b0ba,4ae794b5,5ed4c9cf,30c7d1f1,ab31e9eb,8d20fd16,77b67152,44db075c,c9de1b49,58607617) +,S(2d601d55,1b07c8bd,10db6a9f,516882b3,1525d819,9df56324,cef2c40c,6753ef7e,d32e4bd8,eeb642a4,38a9493a,87824f86,6731bcf1,6c4b1f42,240f07fe,ff075a2e) +,S(2c67af99,3de02d6c,b9db16fb,7fa99fd3,6e32aff3,69e855b3,581af5bd,cf8f81bc,69fc1c49,501a76b6,e21abdc0,27aca6b,a062dc11,5cfdeebc,b8b98ea,ae35d935) +,S(a904b9b9,a0abbb60,4be04958,74b0bf72,5c1c21fc,1ad75b9f,99ed5d60,d1beaa3c,a2cc5370,58dcb26,6677e730,449cafa1,c0135179,4afa24e5,47b10479,a2590069) +,S(bafa5456,e50152d3,115d40f,b9571d79,7ae8fa48,97801c13,238d8b98,b919302d,8108653b,f4f9bb59,de7e26d8,55f72103,20eeb48e,9f127778,5f05ed34,3e63ac43) +,S(fce057b,560e9da2,7621d46f,bb709275,4a6793fa,eedfcd7f,9a782aae,e35cd9a1,c59891ce,d7c19c5e,7a841620,8d0d819,c8634bbd,2466ed60,214a726a,dbefd784) +,S(b8dd80d9,6b6229fd,d13dac50,23f53657,3b353efa,45016033,58a9bcfc,ab61fe7f,a72beda2,c2cefe01,eaf1ceea,714b538d,8b052eac,3df84158,dd3530f8,9c5bcd25) +,S(c676cd53,7366b97d,9a056e87,2bec47df,e2c35e88,947275b0,53212536,a6231c5,9d5fe80f,763e202e,6919c760,bc96c732,844c4c18,7e7a3a1a,a0760c29,80c076af) +,S(626a28b9,c897481,19d6c4b0,bab6e81b,9d6747cc,6c49521e,6f032f50,36c9fa87,f8373b3c,748231d,b8aaf580,90898566,27b112f5,6697b18b,3cd6a73a,16f2203a) +,S(d72eae41,548363f7,cf5b5b9e,ab73076d,650f7616,e7584fd5,1a5ff2a8,ce1959b0,c867515b,46c9973b,53498582,5bebdc1a,54181a33,74b507e1,f0aa21d0,7a6c0e0f) +,S(6e34489a,4ca57c6b,f3b8a98,dac3b2a2,995a7bd,f90acac3,b81d56d7,678920ea,efe88e16,e60cdf2c,3e6a07a0,ad323e7,ff9e731b,26f9cac7,87bf43f1,b3401169) +,S(a8214f4f,1ab2d150,b66eb9e6,f64ea4f4,6ae08909,9248663d,8491cd2e,90a56ae7,5d252b54,ec694068,a0944f8d,4e0ead5f,2cf0982f,3981240,5165b5a7,e4d628fb) +,S(76591c34,fdb90d13,14c5f85,e76e18c3,aff3aceb,4385011c,d4a74bc,b36f775d,f13c54f9,c32fcde6,94d29b12,f2a8d8fb,a99d19be,80ed9a8f,903b33c1,ae52a447) +,S(17d22fdc,c48ec732,afd7bf62,7fd09d22,d2989437,a8ce1950,3acc99f,ef2c0cf9,3bf80fed,48c4c2f2,f25ccee1,9a717067,976f108e,b1cee625,1fb6257d,f1788384) +,S(2ffd19a7,f46bc028,9b11d7d8,2b391091,e08202cd,95c7a4f6,fc351713,d3645b6a,807ee1d7,af310183,fa9edc73,4c098b90,5b0d4021,6c19b797,1429725a,5763d01b) +,S(63496320,c4eaa16d,ca4ed516,bcbae7cb,124af3ef,10969329,dfec9a92,22f143ab,3ce522ae,ffd08245,d5dd6ce0,17ea6915,aece97b9,9314d61e,2d4e9fbb,5b92406e) +,S(685a372c,ead446b,6f8797c6,dbbdf442,e337a200,1b09c03a,84dd523f,674c1e31,9436ad88,7c61bd79,d0a73f9d,1d06ca0b,37f19511,9d9f9f10,6a6d6d97,f0654d96) +,S(d1aa115d,ebf2ca79,61b1a13a,9f8f2f38,8367280b,c36f6208,15cab71,d235b866,9dffc173,6590390d,a2f3239c,f85ac4c5,3e842aa1,3ba035ac,2824a269,c7c2a487) +,S(d12c58f,5e20c6de,34a27270,d29ed5ce,c2a36ac0,8f2a1b1b,69cdf2a5,d501bc3c,cf7bd006,5bedb875,bef1861a,335457ad,66042a17,c9249006,60ee461c,db0a7de6) +,S(95d9af48,d2d3ad22,4ca83889,2d7f14a0,bb4770d0,42ecca6c,d71b9278,79e69898,39e47d1f,6acf9570,5755c560,22a8faa2,e961b25e,c5ca36e6,3a5ecf5a,e54a48d1) +,S(6e4dac4d,1b6d8404,e84152ad,f5d49de8,d269c9dd,1c66136c,65b8f78,5cffec16,62d1dd58,22c06f57,f2ccefca,31c318d1,175a3c60,2aad99f2,e5c63e2b,c8e33afd) +,S(d026e847,3e8eec4b,d9ffb21d,49c13900,34a9a66d,5423174a,40c8b4b3,4f6fe060,682d65fa,cbb29cc0,91a290e9,305e4615,5a5d472e,16d37c7f,e06a9a40,f578c58d) +,S(683bda54,87643e28,8799658,baee6ec4,73ca9c66,4a76c302,b26f5762,877e766a,d3d80b37,117d6b18,c04174aa,2aba0774,43fbb78a,2649eb38,e5798935,75fa237a) +,S(fe2f54a1,830a0d86,ba30acd7,d208f6c7,22e2deda,4e554a5a,533e8e07,dfc76f8f,6a6f032b,5bb03b33,3b28e6bb,30b2b04,305e0aac,cf53e2b,53f215ac,2f1ab8e4) +,S(2486b52c,511b2499,7ef5d49f,8098f596,568fbd0b,756334b5,d5f01852,191d677,ef82dd7f,9dd36f42,55b75292,40af86da,bbbdeccd,6ebb3197,11fb3432,236f5ccc) +,S(c6fe27cc,79f316ca,5a59acd5,911963e3,bd6ae911,c50bfa1a,f2ae8b6d,69ff8ef,70aa6fed,ba4c57ee,5b3b33ec,ab6efe75,e05b8b43,41c3a7b9,bca5053c,40292101) +,S(be4ff208,8334d043,2d35c9f3,806e516d,fae58bbc,d2f69565,ec461006,99af2be2,49de6b17,c8636af4,25ed00f4,228ecdb0,4208d18e,b5c9c194,d6714550,26396adc) +,S(c5789253,316faa6c,2f87f888,a8fa4312,42618ebb,37a5184e,29abf20a,e6b4aea4,77647e3a,e083159f,afe92726,6c60f666,12e4fd31,ace116a5,11678291,185df958) +,S(27d2c091,b2212a3c,b2a827d0,951a4bea,6994953a,cbfff146,cac83f20,f164ffd7,e9fb5899,d757055d,f0e273ef,c38cf691,e958c6e3,943aae43,85f77a14,8189eb92) +,S(94d45ebc,ce92d10a,3294114d,743db35a,8e2ddb7b,7f5bee72,7d093c89,15d98d45,802386db,bd731bbc,5dc793e4,88fcf20d,15be9024,b94d1d19,edf99ea5,ab1c0acd) +,S(46739c9f,6245639b,692a68bb,8587499c,43184d0c,f0ff467,7b264985,b4a2fb62,9f8f41d7,2eb951ff,17d4517a,3fe7dfed,556aeec6,be518188,8c39a57c,913f7da4) +,S(5c9f57b1,baacb2f,67f1bdb5,3fc85aa9,3293a2d9,d85d1f2f,f62ff40e,d26e8c30,6bcc8a89,7ebf12b7,2f397b5d,ba072f3,c91f413f,df14e441,ae2a2155,887c1527) +,S(9ccb3d34,4c813c15,e9b85517,95ddb04d,c3c790a3,a1ae051b,60202b56,b735f3fe,e24525a9,fa784ee6,2576fa15,6ad350b9,eb5802f6,e5d5bbbc,7f4217e8,73f85916) +,S(f0826eec,162f343e,4cd7e135,df33219b,507876ef,5d29fa13,d8fa2326,3e7ca425,649c1d78,6547e29b,d266f2b3,cb70b823,8e71d198,6791fb09,a19ee4fc,1823e02f) +,S(8b672a2e,1b76096c,80b87519,10b6a09e,1b7204e3,ec139cea,46aabe84,4302dfa7,33f05056,ab88de5,e036f8e8,5bcd51f5,423ef431,4faa1015,7eacfd8a,9db71787) +,S(93cb8f71,9db52708,986fcbc6,26679315,fe79d119,9f8abffc,5c02f375,8e5a50e7,ed7d055d,91843e32,4193d866,81551f5b,36b484d1,f0dd5fec,f59e51ba,57b93bed) +,S(da506843,86019984,4004a723,7ae11605,a7132e86,55145d8f,ce9e0e50,feef7d5d,260f6393,886e1b8a,93986894,a4a98fa2,61771a46,16d04ebe,baf8bc48,29816d53) +,S(2d469c5f,26610e4,6bfe1cc9,43cfe267,e1bd0a22,e451aeb3,e74f17b,b9ec2f76,1d702b5f,fe2101cd,f5a5cdc8,4d4a4890,6720ac6f,ca626979,d942c218,163474a2) +,S(1ea83777,5513ab9,cadd3b53,66cd9049,da1b01c5,d347f7b1,c8a74f6f,658cd621,b9e312c7,2dee3d7e,d6e67596,70c65bca,5bec92a,2eb82fab,a122ffde,5b1c7f5) +,S(70bb25c7,9589530e,f129166f,cac1d5d0,81083ed5,fc5b9b99,e744585a,1d6b6816,63234c19,dad2914,3e99ff95,a906a5f7,a48b3e87,2d45436c,8d987baf,a93b3588) +,S(fd9989c8,f68537ea,a3248b19,ae721256,ba8d0d2f,d825980f,f89bb158,a700f0a0,eb76c5d4,93e52d45,5d27a12f,fcdba859,664bb048,1686e67c,e79e40c2,e0160c97) +,S(f1c32c17,8b36e837,b058e9ab,ed3c65a7,e2c76397,4936a524,838a480d,b3089b7,dd4101fb,92488a78,480cb6af,6cf73dec,5aac619f,3bb42594,c3dbef4e,cc7a3a11) +,S(842d8101,ed396c79,b5b19779,c245dbdb,b1ecba7,9ad77d5d,f78fedce,f9d83f33,6fe77300,9117a404,f4b28ef2,57441145,c5afc6ae,2e655ecd,2497486a,fb1ebc16) +,S(6e9e1a2e,847fb133,cc92a79f,767a5ea8,cac887a3,16903a98,f3ea86ad,3e8cf24f,d71de5dc,12be0a35,b996d880,8442fdfe,4a6cd810,7fe29548,da99783d,9049ce3d) +,S(f6739fd0,1f5429d,27c216fb,2b02d871,7028366f,7af115d1,e154f87a,812b5e37,15186c87,f776c8a0,3532b554,1e1b583a,5a465334,45bcf93e,dcf539b,21663c95) +,S(c3acbd98,43bbbd8c,68f153d8,553a81c2,81dbc584,42edb9d0,e51d056f,2b80e2f2,8397a220,483081ec,ea7de090,5d063412,1dfbcc32,ce70379e,c58b33b3,20f39d25) +,S(aa9c8bec,c845e691,a4c3daaf,a9bf687c,ad733290,32abe151,a26c2a27,1fb94732,b82dd0fb,c53fa616,74b684f9,7da10e8b,77f1f7e7,388007d6,656988df,e18df322) +,S(3df35629,654d5b70,db9547b7,5373efd7,e1781dac,da11607f,e4f3c903,5493c8a7,56fbe92b,25cbc615,96f2cd4,10290da,239ec3d9,360b3561,4199b006,c2d2b54) +,S(bcc8b337,98973e00,771a1955,89165cff,83870f8b,a897b8da,84c1bfb7,57168bb9,483a7f4a,70c8250f,62105842,310ed427,168382a2,5d687290,d54e65c4,c83bb16) +,S(bd2b07e,a84da89e,bf5e39f4,d3f03df8,658061fd,8f78d5cb,99f488a3,e992b870,33ae1dde,77c5b467,f5b3da9b,c71a6557,b0cb3aaf,892d0e76,d9f34b40,1fe60c9d) +,S(2c55718b,87b4facb,8ba9a6d,287a2db7,1b5a03cd,c7d933d4,c6014232,ec35d05a,aab1de0a,d8e3f72a,ae822bdf,f3ff70bc,bc5aa56f,1dcc5352,d1f81614,f3f461dd) +,S(eb837dc3,b2e346c2,aba58441,8c84b20,d144f93f,841180f0,860f7280,a7ee23e,6a342fb8,38a63813,e279d1c6,94b2ed26,79c3dd21,652d5678,5f47aed1,5230137b) +,S(827719c6,9b097381,da18519,ecefa193,9a9eba18,189092f4,89bde77d,33046fb1,e73b0e1d,76e40777,4ee6fbf5,2bafe516,f6d94fa7,c7dd1eee,b3c36f7f,6429dd3c) +,S(2b0da4f1,23095370,1f1b9444,847ab289,5cbfecb5,800f2d7c,16e7a56b,c6988d2,fa8b4d9e,5da41962,68e10a3a,7d69b1ca,7963d4d8,cbb5fc1c,83239212,dbc340fc) +,S(95744eb5,13436e2e,877fb0a5,20d5f1e2,1e1ab59e,15bbaf46,206550f8,d5563134,5fb1c034,62040ef2,28adad1e,83fc2c74,57344c38,7b7ffde0,d247bd35,6b5ed1af) +,S(4c805d94,78793e63,4833e90d,d19822a0,ab7d263b,1ab67654,bb77358c,67b327c8,863cb8f0,dbca3c1e,4011928,e5827619,53df792d,449f8980,bd10cef4,472ab56b) +,S(fac22633,3ffa2cc8,93c434b,46fb0cbb,cdee765f,e848cb50,b1dd6e70,272e0ec3,6a6b07ed,46f9b9c0,86e970b1,d2323fa5,d7d66b0e,3ad3077e,da5766ca,ac5b500e) +,S(b9d6af71,c59f0fed,ca4ecc31,25aaa645,f78d43eb,79c22034,1034de56,f59ec4ef,5509e17e,3d7ea457,c428e10a,7e9d8bd6,69f0fdc1,165169bd,a2101d8f,6f4041b8) +,S(57a68137,90725717,2dcd8c46,3a9b274,69c5ef27,2ae2be60,b10b96e8,e6b47537,9f294700,1c04c06f,2e2e5aca,cf4b9549,265db1f5,74b2328,ef4469b0,1c2bcb98) +,S(58ee2a22,9aba401a,637c4d34,2b1ef408,d9f47c53,6133fcc1,de030d00,25e2f53c,d361b0e5,5ef24c74,94cb9e65,cd273e9e,73da6e50,f452f8b1,7d30eadf,32ceabc0) +,S(b8bae4e3,f2e22824,7ac9cd8c,a68632e5,1bb13d4d,735fabb7,305a8169,31b0e34d,ae8ed4e8,6ac41b60,60ca3423,fe6bffcf,a7f215a4,7076f270,a2d1017b,887b8002) +,S(a81d5e0,f11549c1,373b4c02,a61c8908,dd109f4e,7f0cd250,a667508b,aea3feab,8c6cd790,4cb4bc0f,7e56d928,ac362cdb,f096841b,dee9dd48,429c52e7,23511bc1) +,S(fea67ebf,f8f092fb,dbb3110b,77d6981,efaab5c4,97a23c3,42afe294,64f4746b,1dc947e2,94b0fd7f,952a6d5e,1f5ddc9,5f0acde4,de8db93e,41f37ec8,965d4310) +,S(4db2ae8e,6b8e674f,2d79e1a2,fb7c7d10,921c9280,d8eff92a,df1a2b02,4485bffc,8ed56cea,38c2a96f,b6e0ecf3,22b745cb,35c43313,9b3dd28d,9189a9c8,9f2c055d) +,S(be31fba,3995348a,78303047,24ff117a,48dcf5e8,72356d03,ac059306,fc5ae314,8bf72f6b,70189284,ecf86059,affb4a2b,c7b5f923,d7c34429,6f401490,5a94061d) +,S(e8d716d7,18078be7,78535c20,4f9cb681,e8f49ac1,85baf865,e7b78e19,58ee703,2c79f768,c6d3bb3d,b0923d19,74647e8a,966ce69f,d06a8fe7,5601e51,61f49f85) +,S(20ae34f7,f3497d67,6b0496fa,1a68178a,f4fdd57d,15131ab9,c60bedbb,1a840070,21fc951a,2b29ab95,994cd404,b3da37f7,d21fa790,820339df,84f17b50,3572edce) +,S(73db09f1,3c8e7bb4,48629f24,83d56f1d,a207617f,454edbd9,d51ce59f,b7ae1ec9,1e4e5175,efe03956,cce3f160,791595ad,35bea993,139e8967,f591b973,785dc29f) +,S(14f5ae1f,af20b6af,9953fe91,db5bc192,31f302e6,cc03a265,d661b25f,8f07cb18,b790b1d5,ef6ad5ef,97ddb309,354756e,138f4db3,208a873c,17cff3a3,13a8be2) +,S(94ec6992,d2531cdf,3a1002cd,efb12e68,868be66,b704dc26,3dd422b9,9cc379ec,d2c4e479,ce9e0227,4d9175dd,e2a42639,67ed377e,d0416101,7e41e8bc,8adf7fe3) +,S(f73b5edf,c8d60e77,328279af,ae99381f,4ce0de22,17a4edd6,4c228b4,84816527,86758bc6,f44e1204,68555e71,786f7d50,da7f9c72,665a7475,e77c32e9,dcb13419) +,S(94b51939,45a518e7,c602570f,863902b4,385c8e76,c335cae1,b80e1d0c,e118b573,7c285008,4d398cfa,24c5cc6d,879868f4,d8eb60ad,ffc77214,5debabc1,3f154ea2) +,S(26acc055,2fa90d45,1dd6f2a3,9bd46a9b,99b0f66f,3e6e72c3,16e09e52,f7b265b,997dd988,5d5b15a1,957e1cc0,a45518fb,b0e1f847,d58fe9de,9be95273,cbe61b00) +,S(e8a5ac01,959edc90,2050922f,af51365b,ecebc967,8e57cac,420faa6d,4e2fce98,2c2998c6,fdd97d15,fd0cd228,e9975064,f2576316,6e61a45e,ae532481,9dd96227) +,S(d903bdf2,5ce9e855,60f63d72,512626fc,fee11c4e,304d249e,e13a4b69,60f95019,1027435d,bab3c246,c93897bf,ef7779f8,9a165595,a7c9c536,176fec9,1adb645f) +,S(eea105c6,fc04a751,cdc27e40,25f0d50a,99f8d01e,1110a505,eb95206,922e50fc,b93db8cd,b914dd8f,2b57b907,4df41e9a,d8cca9e9,c3a9754b,e8473446,ef3a6c68) +,S(801b116a,1fc2c2d8,fc8b412f,e9b1b7eb,b19f4e96,16b420ce,16f1b4b8,dad235f0,53def02d,8a6deddc,250de95b,d6a96d27,1c197d36,e137e640,4123501c,15fbaa9d) +,S(db3b8667,1b0dc54,436520fa,c8d437cb,7a4c23b6,bb3c3cbf,dd34b605,af406939,36562d35,a298b620,f7a06498,b1032f4a,33cc3b3,ee185e0e,aa8d3e4f,3ec5c481) +,S(7bb26eab,8b808402,a9fb3fa3,8f0e2f6a,7d82d7c7,eef75cec,43594713,dbc17706,f4f86283,713738b2,a9209e49,f82ae1bd,9bcc908e,b9565546,3a8a5dd,8d0c4b9c) +,S(e89fe301,8d87bdae,20fee2ec,7a3f6cd6,cf932d20,a026e1bb,a82f9c63,a47b97d9,92a7e80e,e7657ad7,c72f471,8f0c28ba,acfc748d,a6090026,1191912d,32b8a498) +,S(c9a10a8b,14d1845d,be6eb6a8,65cd2ce3,a4d0be4d,fad24912,b01fed8f,8bc812da,5852b791,85afd22a,6f9ab486,91340dfc,e9979cf0,bc9732b3,637434a2,25001d71) +,S(257df2e8,cf535cb7,954b52dd,7e3ee08d,24cd4415,d1075dba,8f75bf74,74afad3f,f72d1e76,d4da3c0e,5b41fa82,28639f2a,f4e114c4,94073ddc,3e8fb2aa,f82596b7) +,S(3c64aa9e,548a430f,a815bd54,713ed69d,bc32a0a1,30ae7ca4,1541ff21,a5314886,8377911,7426e30b,dbf84c57,b110cc3f,df5acc95,7313cbc9,86e895d,6e0ec912) +,S(cd509f83,3b65a7f9,671b9239,c5e71323,f183e956,2c2c115b,751046a2,33424ee9,579243a,c7fbd433,81cbd0fc,4330d087,cfe0c41e,449ef82e,12def6d9,8977338f) +,S(27adfe4,febc3501,3ca7a0a0,b5f7e525,3768df69,9d236f63,9ab80782,c2d426f0,97cb4e7b,73b065a2,499a1675,88fc116,be5606f,80619d42,ddb63286,4d20521) +,S(ef5bb148,98dd6802,6f25c363,16a34acc,c6131851,a4efe8af,219fcbf4,13a45207,49f30d08,291e60f0,975c93ec,403d2a14,3742aaeb,3777cb9,87ff38ec,b51967af) +,S(58df8d45,955e923,ec7fc327,f8081ec3,7ca6e261,7fdf7785,6eed51dc,95057034,cdfca79c,92dfe719,2ec63f6f,f93d211b,d7cdcf69,4deac173,d3393fd3,7655a310) +,S(2a4ca8d3,fff5ac47,bce452f0,1587a769,443e66c0,164558b6,301a6a2b,d3d44270,ed73b405,521274a2,3abe589d,c5ecd607,b6467691,f81e3c9e,6a2096db,2ec82366) +,S(84bafd1c,7c6072cd,fce244c4,8ea004ad,9b8e1765,bb8796d9,118d6dcf,a5ac58ce,86ab8db1,7c26c921,604a3c3f,f0155a2d,14bd7274,16f9e319,efb68f50,2b636c00) +,S(c3785528,7cc4e3df,f5e95951,c5bc5964,28705a12,10927e89,890726a2,ce00b657,302ebd13,5643eb43,f0bd14c3,65e385a4,c9a177f,96595054,3c3d96db,69ee8f79) +,S(c3aa3cae,efa22927,56c72aa,53507474,50f7a64e,2df1bf64,333d0402,5dc87d25,c2eed94d,ff9c5cac,248f77bb,9e189302,286db019,64214d71,1a199119,4818ac4e) +,S(443b9c8c,7d8c4f7e,de7168fd,666e79,5da85e6d,6c0f6448,7d349de7,66acff4f,2d4f1d59,b0d1688c,9fff0f2,f80e3434,db72d76e,6ff886f0,63dd63fd,e192b01e) +,S(2afe7ea8,688081e5,ee8a4ae9,87aec6d2,ede5ec3b,ca887bbc,1461709c,bfc6e5d9,5c319df3,2556ffc2,56194b7d,eb46dcee,59208922,1e55c384,2a03ddd8,78add90b) +,S(c62004ce,4d82ee0c,e2edb82c,e0ca98fd,413bbf44,55b96624,a86aa252,c346af6c,b68e4fb6,88f78331,bc2218f7,6a5e43f1,cac49fe3,4c5302cc,d6a3f1a3,258564c9) +,S(f759c4c6,e0bd72a3,9aabbb17,fc62c900,d57e0b5d,ab9ecce6,8f439025,2b17cd1e,6dfaaff8,5f9f3990,ad2c55f1,3c74e3aa,aa0f10b2,90def714,229cd3da,d5d18d98) +,S(b527a6a9,d27d0a1d,5adfc1c1,35308e5b,9a805638,132f61d7,e5e60709,ac3a9d9,e387f69,62ad151a,d920c82a,739af00f,628865ad,4ca42405,efd87e89,55b91042) +,S(ba23656a,6b0a5c57,f9a00d6a,9e6a331e,cf0c8097,3675f41c,7f0172fb,caf4eb02,b48ac68f,1a108de9,18d76d4,95a811c2,b7614aac,3c5f6b18,f28de8cc,7bd4041b) +,S(ad94ec6,fa161fd1,60dea3b3,2c63a480,9f7bbb91,49de206d,8cc61306,dbd18aa8,5240858c,ec88a022,7c1c12a7,862b4d18,e5acb344,5d66bf85,79ff9fc,ba866a4e) +,S(db4cc48a,de1bff28,c8987eb4,d00e1c5c,4c49fa6f,125d213d,bd814c34,cb81adc2,ffd64cf7,3c62c097,a2cb3b84,c62bc32c,54fce797,74479146,7b9a2cb5,d6f821dc) +,S(27d276df,fa39d889,beb0b586,42a0e479,8057760f,c392d052,6751f2bf,d0c75aed,c670b966,575401a2,a790440b,e5e5db56,2914aa74,e8304e3a,407aadc5,c87e12d8) +,S(7663e9d8,e34b525,b336587,eba3678f,488f95f0,6e9a6848,d2e72d35,36b569da,472b1c5a,8ee189f0,7a06addb,e6a8d90c,dcb87039,aa35e896,79143547,34e2786d) +,S(b2c81e15,1c1f8ef6,51ea1810,97eaa280,7e3b4a96,fbe210eb,b49554ad,6e0c0c4f,2d914319,f5ff59f8,c7038de7,dc70d1fd,6c4434ca,e5c0451f,4fa99f46,55bf8e4c) +,S(25131e21,9406fae4,ab96326c,7bf22892,1f18aa90,c52f46fe,b23f90ac,59ca570f,2e8a380c,eed5d51,6c190251,4937aa0b,1f39d3e4,42ab2537,e9e8d9aa,396e4c20) +,S(c2694b68,8e33025c,fb9929a8,c7ccd1c4,7fc5811b,9658ecb0,f41e4558,5d9a0c3e,c443d593,e68abc49,cbaa92b1,757ab2ab,c30671d8,4699a5c4,85a30b05,6b1ca701) +,S(8d528cc5,17a371bd,9605d8f4,e7f030fd,8a82d489,5bfffb9e,fb11f63b,be534fd7,ef2f16fe,64ceab2a,d261bd1b,314ebc65,4b4127b8,643466a8,f367b991,d28795d) +,S(409e69c7,62f856a2,4b6e80aa,baec8496,33b75c21,8943dbd,7280bf,e917b032,7f049016,62884d22,dfbda29a,c8061b7e,b82eb94c,13d7efcb,77531f8f,980babdd) +,S(82c9b4b0,2451fde7,8ae877c,ed9af540,1ec0e258,119e27d4,1938f71d,ebae71c8,212d6e4,99b91fd6,372db1a9,4ce3fd9,c5443b7e,fb37a566,f0c5f54b,fd8edae8) +,S(6c9fd728,37a39ae7,1f0b5852,e5c09d7d,cde66ec,e8f19a2f,2ab46fdd,d17c7f88,430d3385,aac729f3,8ef5ed,922e709a,73df8e70,eb9cdb83,c41e5958,272e8687) +,S(9f012582,e527901f,ad1f350e,1a64702a,ca1f6670,e693bea8,fc3eb0fc,2c090329,a2fa07ae,c15e9457,b2c75e50,56c79a6e,a4c8f431,d3c720f0,60f7b5b6,da6e3dfb) +,S(6a1a49b0,7b2b61d6,474834e9,953aa455,63910582,57db16bb,406b600d,bb01300,d4b93b7f,66ace505,cbbc2326,ddfa2fa4,ebab145c,ffbdc2c0,606e2ffa,9dbb41f4) +,S(981d0638,a585970d,4b12e577,95e76c26,1e10d65c,c5a94f19,43560d10,472fc9c8,f9babd66,3d02e030,1fc0ed0f,75cdaf94,fafc18ad,2cc68db6,d2eff7ca,e6c013bb) +,S(7edb47d2,b6295063,6cdda3d7,169b4296,3616b6dd,79e2e148,609a7722,476e564d,179a20ac,a6deb286,76fd466f,be78c3b6,789d31b4,91622149,4d7d634,d4bba999) +,S(51867800,4bd8a43,8f180cdd,efa17ff6,e16e29e1,e5fc4ef3,f5fb9bd0,bbf14ae3,306cc2c8,60ae5871,8632f94,c9acb7,321ba1f3,5092a0b5,72c33b9a,cd8cc956) +,S(bade1926,d8b0d136,69e056ea,ea46b2c8,2bf0f0f9,a25bc481,8a40ca8e,201500aa,7ac76679,c9807217,ee802773,dde582b5,6f0a4b66,f6e21764,285a6a81,4d584502) +,S(87815e7c,d1e5e88e,eb882b23,955de59a,d63f14fd,457a8d96,4b47a611,b3e40043,ca82343d,8e2eff9e,314ababb,15cd03c9,6fe6660c,421af876,63500d49,ade0d492) +,S(77d815d8,886cbf43,c1b4ce94,253e93ef,767bacc2,42ba7c1f,bfb7ffa5,308d855a,a8bb3f95,37ef9a77,ad7e282f,8ae05ab1,8131e59b,46a67c3c,7e85ca00,a2d3e1fb) +,S(49079a0a,7d9d9add,3a17ea11,747c8baa,d0922a7a,e766e5e3,fb80ae0f,dbb7d6a9,162b4e23,58f03e01,b4e09264,8cd0657c,f2cdcf54,f6c25d5e,fe7330ce,421e0093) +,S(28d61211,c183ccc,2b08168,5a4487d1,57bc0714,d3ffb16e,96bf0768,ff8075da,3da98c13,a2d1b07,2ddda165,3fb68a21,aad4a9fe,b4536dc1,507dd78b,7e51e0a8) +,S(40c34a4b,6196561a,d4591c49,df51b8e0,4106e545,26092e88,72018720,41448080,7a6e7478,3ce7d82f,b83f15e0,b74ae6d4,435593a1,67da6f57,f2e285fa,8c107e4f) +,S(88754e6a,e12e77ec,21e64cc2,bfaee207,f5c882df,80c8b15e,983fb1aa,99037c2d,5ae10e7c,e7464c69,472ce85f,5183a836,6ed5b3a9,1fb1af7b,d5078c76,2512f37c) +,S(8bb7094f,ed62beba,d628ef9a,84a0679d,7e0d2b45,a655fa3b,68d9a6ef,b24c738d,9f5370da,993a3811,48ad4da6,2d7845ce,4cc81766,f26189c,2199ca73,4312d102) +,S(79814e63,7bf2cfc1,cad39a36,b06fcc4,f7e865b3,ab2de1f0,c786f9f6,40dd80ea,aae4d149,f1e44635,e4800962,f533eb38,5f067114,3bfb87ab,9e68e27c,b56df226) +,S(d493573f,93018d4b,8599b54f,848c3afb,816e098b,8e218e2e,6304baf6,c726513,383c7ff9,b3ab6472,ecb80f72,2f70feac,7ff26989,bcb6f984,628d5eb6,a409b9ce) +,S(59599fc8,7d6a7532,5ce8f205,204596bc,4cec40b2,f3eae8ca,4530053d,1b7c731a,7a8d91e5,5d989961,889949a4,bbb71e17,84055697,b396a011,eeb33889,88f0681d) +,S(4a834ec4,da3c9afb,c62fec5e,898aa2c9,5a835e60,ef199346,3e4bf255,e32df096,8736155,ecbec836,e8d51d79,9176a5c6,6672aec9,548aa63,b7f5524f,6b20cf73) +,S(2142b447,f2707c37,45e877dc,8039161f,d222c69b,9236592c,c1b3f56a,d30a975,9a48f0a7,1ebfef1e,615a7d5,a9decf8c,70764133,88b0e57e,da554257,256e41d0) +,S(c3831b8a,eb58dd77,e21762c5,f2e88035,63fa8b1d,f5d1fab6,3d012fbd,27971797,45d1f565,6fb2779d,6ae18e96,4d9bdf61,924a5f6,a7dfbecd,2224f1c5,70292f46) +,S(a09dd11d,b78332da,663acf08,c08b3d45,d0f4740f,5df66e39,d53e6c68,f5654040,649959b5,bfdfe8cd,45fc89b1,ea21cff5,94f6083c,da8f5e5b,94525d22,3e326217) +,S(53b22e4e,8a17b408,6b119087,2b8fbc9d,fc667b40,223ecd99,27cdf4d2,a9dadaa,87eb7fdf,b9c6e23f,e7c6a8d7,fdf94438,88c6c0b7,1a3728ae,ca8e83a9,4403bbe9) +,S(7de0aeb6,d3c264c7,f39b087a,e62dfb5e,aac6fb17,483bf33e,bc34a903,f0ee35a7,43f92307,6a2205a7,f2f0737b,2167863c,43f3cec2,ea3abe32,9bba3792,6f070847) +,S(ef20ed3f,3dd1cd8e,a610f1da,64086eda,a4a646dd,e2bff224,ae72f069,f341b532,c3477d8a,a0acf4a1,e9c83a1b,c890e59a,1b739a82,55d3747c,7403034b,221fd0f3) +,S(ab21ffa5,3c7baab0,4ee74647,5a5e5800,dcae9a10,644c84f3,a108cd41,cb0dda53,3a02b102,dc21cf05,3abfe19a,2747f34a,35ec6347,ccf02880,5aa95119,110cdebb) +,S(ee8aa184,532ceae,2c3a5071,d905c6ba,bd1982cb,391151f0,fa869339,aaa50ad5,157d9d2,be135082,9eaf2c54,94e6f90f,8a82ad35,2d486dc,58068cf1,c96a421e) +,S(6b234cdf,fed7575a,f1cd7ac0,76c4251d,5853718e,2ea07c04,77959afe,5c0af2ce,223c14f3,d3d61375,d104402b,bbd51026,a7644b15,4f4d254,85e9a4a6,e8dc2831) +,S(e04eb879,7821557,a875d846,75496d9e,420ac3c8,6e718e45,347a616d,7616e836,59f33383,8354990f,2189cec8,af523611,df4a1b30,3001c5d,84e1de70,bbc6bf31) +,S(6b8c79d7,791e8423,788627b7,a99be936,145a8eed,178c8bec,affa8a2d,72965da8,28fece24,22f67bd8,a2d6ef6c,66fa51b4,c4abe766,7480b520,4f77bd8b,2e3863a8) +,S(d21a9136,eed220a9,708c09ed,2b22f5f2,87868a1d,493f6ed6,2fe9a455,42a4da0e,efb15959,cc7a2c02,7ab7f5f6,ec8a538e,91df38be,f78de45d,dabcd8ef,9b5394b) +,S(f950b37e,a5bfc8c7,a76ebefb,f228043f,de066a1b,cbb30688,b73e085b,cce1ce6a,6bc569cd,609a15d4,28ce7874,53ab8d02,fcdc9c50,c8c44016,ee2b62a4,16849616) +,S(75a72a76,520a5f29,368338ec,fba063c8,977548f3,7bbe08a2,e1ff5e97,88b9bd3e,41c140e4,5e2be58a,dee8af9b,e64cbe8b,4c82860b,98299d52,3b27737b,3266f978) +,S(4474da75,3d9c68d7,2218648,1ce835ca,4e17220d,533adb53,38a1978f,cdfbc3f9,b5e2d3c4,ae2c8276,5a337068,58e76666,52a81638,27cb6b94,3d2b80cb,36ad3eb2) +,S(e3f3e682,fd38b067,33f3e91d,585f3ef2,aaf90409,ca125479,b93039fe,3437388c,aaef5ad5,4bfddc87,f7c3f969,94564ac2,27e6d5ac,ffd345ab,246ee2d8,60d9242) +,S(140ea6a8,ad374157,396b064,f7a952f5,358ff408,951895ee,b66b6140,d969afc7,2f340af0,b08a67db,e6ea7535,581b763,24308f37,6015de2,a4dbfa64,1990cc78) +,S(257c1e04,2fcceda7,9aac2bb1,1f01bce9,37b445b2,bff51fcb,555395d2,d0c16b89,73b21d9,75bf23f1,aa0efe21,5141bad2,5a235978,e36645d,8503a60,3956cb5c) +,S(c243452d,664d2610,d1acedb6,ab5201b9,cddce44a,b9320806,4824329a,e0b7a550,50607848,db2b53c3,c9ed2b4,8c0adc28,322d2e,1b30c3df,1ab9dc37,64b001ab) +,S(a0ae37a7,3aee0e63,c0ca3e50,e59a660f,c7ced178,10dcab26,7f91ed44,3f265fe,8332d25b,94e0555c,21ebab61,cd209599,bab277d2,fb9660f1,f237c9bb,4327668c) +,S(2e4886d6,678f10a4,460b4ca4,a9964125,413a739c,64b6abb9,c44f675,1b47dca9,96f6bb70,9602de31,1be57a61,966c8227,e5dda6c0,48d3f1d3,bb5bafa,fc1e8de) +,S(855b47b,efa7dee6,2452a602,980258cc,de813ae4,6f580a46,d5d18432,5b423f8c,c27f5513,114fea7f,b5a405d2,3f25915d,775ac895,7fdc6e74,2d968bbd,d86c181f) +,S(dd360b5,38fe460f,9d6ba828,e2ac7973,46dc386,de05022f,fe48e891,a115e2ac,8fbc127c,d9e79454,a0be9bb9,cf25b7e2,71a02e7f,b4c68653,b7e08329,747cd68f) +,S(993aa6eb,47f7713e,e6c5bea8,1a65af55,1036d0eb,3df8a6f7,e091c16d,3f424c7,8478497f,a774307,d47ed357,35462f3f,a680eb87,fda11107,275c1883,e859ee34) +,S(4828feb,5e3abb4a,2df7b990,e20e1214,804ef219,4cb8acf6,cb8e85b7,5696d961,d8d2636a,6b664b15,f371ab5d,3ff31279,f7c42678,ff380ab0,9c220b02,6ecf3e3f) +,S(fb8dbd84,64bbb5b1,904a2610,2321e59d,ee9debbd,afdbe585,3e1af139,f8fc472a,54e088c0,91a67284,6c81d136,85b4edb4,391e5121,3c4d35e8,47863018,62844742) +,S(851fc8f,cf378f62,5edb262d,e0360d2c,2e9566c6,93abea8a,aec29e5c,275ecc9f,dbe6025,e9857155,83b38b7,a167adff,da70398e,85223a6d,9b940fa8,30a9d9e3) +,S(4d5d07c4,23079d83,d001c000,8c76fb6a,e03bb39e,325d5794,b5414b,46c6777c,d1c1e970,5b80fef0,8450f941,1b8d6197,21f1491e,87745c26,9458d58c,18d14678) +,S(8164d5c9,cc72b489,b6a54e8b,d9cfa9f,8496cd34,3a227a74,f37948f9,5d35340d,90b51776,9e8c68c9,20f5e948,755b4da3,2b294bd3,eae81da6,e0c0b287,ce229bf7) +,S(19a42dbb,9ff7a400,aa821c88,807281ee,ff7df5c6,e047cc51,9693c191,6145e00,369e9596,903c35a8,bb38f4d2,a74da3c3,cd2246d6,b0391e98,e01d6101,439a1018) +,S(7299deb0,a9b7bb52,76c8acae,37ba0ee7,bbfc9c0,7845765c,136cd762,7e7b7f09,8a0a1d16,f00e3090,cfd9cae,d8aed291,ebc56d97,66a131a1,4fdcf6c9,ce6b49bf) +,S(12c7adbf,112e7718,a3ec6774,1597d6e9,87763a10,4350650,e6a804fa,507ecf6c,b3eced7f,bc3073f2,5f86d647,6d822b8e,eeeab7f2,1b3263be,615517e8,ef3b1a64) +,S(b2d76aba,c1af6c6a,b4840b34,db1125c8,d5baf2be,90dc7e6a,52edbf79,a4b0ccf6,92938b87,641e0886,3f22f5ef,e27f9b18,80210d14,312ea6a1,eacaca0e,58c0f73f) +,S(818baa52,8251c326,bf545ff3,a56596b,58e0b525,64ae359a,c1d5199,4b52106a,9f8b4753,a7b56b26,e0e79b9e,9ae5f30a,64d0ce27,5898bf3,c0f12e43,faa69681) +,S(e08080aa,21c9b6ba,da128bad,62dddd3e,e8e5afc1,c460b997,45eab92b,b1663a80,2b878efb,95a19892,8b3609a1,cdbbc1ad,d1530a38,b528539a,c52fff24,2c382dcc) +,S(7a8486a4,1d774bb1,32321247,f7b87964,1b18a621,508f5376,99b31798,490f3e8,ee8c3085,5c3fa5c1,6f90b68c,89944aa8,dcb824c8,c37a0feb,ac796403,15ee96a0) +,S(f74e74f1,6e67c1f3,f5952373,e53cb85e,650a6dae,2302f495,f6882b9d,e2b71cea,1b15103c,8566d2ee,cf5c59c,dab607e4,97075e30,1443b75,42620545,2d1d2bd6) +,S(3ab4150c,cdfd6793,5f8718f0,dc961126,114a5d82,e1791c2d,48740425,8e8ba004,2a6c6f1b,9b546945,f9d327b1,437b1c58,30a48eef,6a14887a,9d8ca24c,c6bc446d) +,S(effec0ed,bb80580a,7bdf80cb,38cf775a,43b786e4,2c80d73e,7a254216,ed7ab7c9,c7c27bd9,57c996e0,42ceda33,2d0b5972,91ae5725,6df77e82,48bb1716,127c582b) +,S(5f49ea21,4d80f735,fd5f51d0,55d4e2f0,fbf0f804,a8f32615,340bd6c1,65a059e1,72e0f032,83684df0,98e740df,bcc39d61,6956ea36,275ca5ae,dbcbd682,510496ca) +,S(2327c29a,7f906,4cbfd900,43d28618,5c555bb9,bb64bab1,c3e20417,4cee2591,db1711bd,ac9095db,39e3d2f7,d2b84129,41dc6f8d,116115eb,7bfe710c,13b9e41b) +,S(12f2f427,64f77c84,f8a97c5d,7743bd8c,cd0c6132,5cd10fd1,76975a97,b447991,713e4660,cadecd98,3b0e4986,855c2c67,bc220334,2991a18c,bb0c08f6,8282b246) +,S(cdd3eb6c,b496141c,b99bde6e,a66b2c78,7264e6c8,74efdda,5ffc53e4,b3292a08,d1270d9,7cd63394,b385739f,4da31dc0,80f410a6,aee164fb,8147b7f6,9f2f1cc9) +,S(2ad4df2,1ff316e7,ce29d76c,da40cb7e,31aa7e14,49fce23b,93f0d096,e1b74159,972c77aa,160c98d6,c64dd9d1,4a0cedad,875e09b5,b0d5378a,7311cd2d,a7d641a5) +,S(df0ed61,d6c8f906,f970b9af,b4080368,2f12127b,e318575f,8e2111bd,514c33a8,e9e67c4d,7b1b0fb6,fa0a4640,62d72f,28180e6,bc8bef1d,60a1ea79,2c4f259) +,S(9572faff,160577b1,83aca01e,45d61647,7dfe147f,a6ae0b26,ca0264aa,23d2870f,b7de270f,572e1503,8a4a9b3b,706eb7c0,2a6e5e56,ab0f73ce,9f4b7926,a79c5c5) +,S(52583f1f,1d51acb9,bd25b63e,158f66b9,8e021432,427efd5b,bd629594,ba951264,3267373a,94719487,344c9af6,1eb4b726,a595bfd3,41d78b33,f3db8897,7e53427f) +,S(c95cd125,7e59d04a,6d953d7d,f68089c0,c29b6a28,90ff264f,74b469fc,af7cfa58,f5c7c7fd,82d3fd51,4031ce72,657cffd2,da83d072,9b0c4d6c,66180214,9e6ac90b) +,S(67a190df,e1a2bf4e,cc23972d,24d1f13b,803a9b4e,5c1f3cec,55d2c2c,3b0b2487,5c35f795,c29a2f07,74ded776,72ab5a7d,45902f50,e76a229a,212d580e,5edeb8c9) +,S(7ffcb588,ee9192c4,3bc5bd3b,4d0c8211,28c3f2a0,62ec3b0d,77752ada,69f468e3,9204301a,fd0ecd0d,26f49878,47c42c70,e526f7d2,e69a97f9,2aa1c357,d4140a8a) +,S(7d693f1e,6e35e062,83f35910,3c1cdd8a,5279c4ad,ed0edb63,d6c574ea,322e91d6,a9042da9,ff323c4d,46b2b40a,1d44970c,92e3cb32,ddd8dc21,d32d609,c5611888) +,S(7e0e5dae,8ce3c883,49a9ee95,fb357694,a7bd48d0,f27c2eba,49896e4a,3da04fab,a397f8ac,dd4077f9,58d7b5fe,28582bcd,4c46d1ea,fa253db5,18fe90c7,61dbaa4d) +,S(715ea4a8,e5eca76e,48605688,560872d6,7a499a8f,e84f715e,a91d724d,71fc0f06,9a7b3eda,8b82dcb4,60ba3515,18c22f59,fade0636,dc893050,a51530d,77ef8501) +,S(52a9c85c,ca99e4ca,50f5efb0,118fa604,b7e789b6,b589a5d6,368bab11,44c8dbda,3796e4e7,87dda75a,59c7503a,f27732d,8c973414,c1ea0a90,fb6cede8,a5066fa8) +,S(58f1c65d,ee5ea200,57644796,a94e4a42,771c827,fe032116,657e990,b56e42e,7f12725d,388a22e3,4f191714,9f48f0a3,3d537c8a,1037247c,de0594ea,a11de507) +,S(3ce165f6,5f569bb5,e594110e,ef91f30b,7e330586,e86cc4c8,347d1ab0,f4a8eda1,90480327,7376335,72d92c00,10313f96,9a0c5d18,c852597d,1f88020d,f69987bd) +,S(133bb4fb,1a16b008,80379e4d,ca980355,c747683,cbd7e81d,87a9eb8f,4219a314,30e76cea,f57f8b17,de6d31e,447fb926,b1678651,e980338e,8f8327d2,648ba25c) +,S(cb26bb35,4cf94461,c675838f,653c3844,24ce543f,32ed7b5,ec1b6b33,a2f7670a,d6f9be8c,7f3781ea,fc765264,c9e84f2f,6d2ff771,25b8d381,199b67c3,763c4f2e) +,S(7d944d40,58cb78ac,739b85e,6dd3be5,6b08fd56,767fd02b,1d5bba08,d4639f1a,79716d18,44baabcb,aded3600,ffa68989,45920de9,1f2cbc83,e6326ed4,e37c3fc0) +,S(c4577e42,ad4014,e1fbc0a4,d69fe37f,49937d1c,19a95765,74f2437a,d06e6589,4a76bf04,18a4a8b,af103581,b6c2cd16,727fccaf,12a3998d,52b1a095,c5388570) +,S(c71f462,9196f35a,cefd651b,3f6f2b30,485e35f3,305dc774,21535961,60a17a0f,9ff53452,52ccf823,b83d47a1,a6a70f84,b9c83142,db0136cf,d03b1f24,6ec57590) +,S(35acf6e1,cad058b6,7543eb60,ef4d896d,c21c4b5e,292c3885,d9e42cf3,85bd22be,cce4ea31,c9a37f8f,21e32a5f,6f272699,7cddc6fd,8ab11c0d,12c3ca4b,fe6b0e92) +,S(c2872bec,f2abb3fe,8a258b3c,51a2bf82,6712ec12,587cb33c,a6765a4f,e3a3e448,a739cf63,63cdf69c,15c9827a,f759e0fa,f7d92112,9bce9e18,bad86c0a,9f6bf467) +,S(50fa12eb,c3dfb3b,dbb61a16,a8b0cc6b,6e6882ae,f245360c,e5524143,27d2bfe3,873afcc9,5ed9a3e5,2f1b0515,d901e9c9,3677d49,4e64a478,11ec59c4,c3374393) +,S(3ff1688d,65cc134e,c6f27fa2,eba78abb,2cf22eeb,57163e2a,150ed7aa,17b3640b,ec8f8f66,11d8f7ed,a296e690,63b3393e,58d8bf85,90630da7,3dc2c0ec,e9e05870) +,S(91a113c6,c53b57dd,60b2eb66,e6bf7ab0,e721dac1,acd71d76,2c278b31,f2fc2701,beb6c79a,2fdba188,4f98ec5b,fd97626a,131f5c16,d4466a84,a9d77213,96220b17) +,S(732b5521,e6cb7053,ebfec5a9,c5b35f47,8da4a9b4,c4bc5708,42b0e8b1,242bad45,30afe970,fa640757,bff0e825,93a102b2,e1b619db,7f7d68f1,17f27543,e72f57c) +,S(94831570,f0146aaa,fd2a7ee5,11f992c,6e2999a4,b22cb176,dd516dbe,e0e16e5f,eb275132,385efd06,35baab61,5367697b,8bef0c93,14fac991,4a2c04e4,aaf785df) +,S(dadb60a9,3af95d47,cebb540a,1c0aecf2,839f1be3,e264a294,bbd03317,686726b0,8b4bb755,46efb999,cddcb88a,ad5b28dd,b73ae1c6,48c810bc,cd9d0f03,c200e27d) +,S(148ebf0f,7e23a220,52ca69ee,57237eca,6c1caf1f,faeb8718,b9b8dade,4b97be1e,32f68bfb,464ae6a2,b23ac7dc,3910a87b,89ff7042,e863ed3d,3038d75a,f3689f4e) +,S(ec532193,614ca440,33a8275,49c65e0a,af446a21,6705f9e0,68e448e8,6e882bd4,30277366,58dd1673,d9f701ab,50dc3238,f073a297,d579cb8e,2ee51dc8,bcd44b36) +,S(bcb65ed5,b16fe248,bddda875,28eab71f,d9357099,af71ddd2,9a8471e9,b2b26e99,ed827c35,e6e13dff,ade8b9c9,d2c620e6,576db5a7,1b1e22a0,3f943f96,cb7282c5) +,S(de30301f,18df0e9c,15d709a1,35c30473,28cd3356,95922ae0,f283290a,638d516e,89398261,37dbf197,53012e47,6846f6d5,45a48312,bd6f4c65,255b89f4,a1b9df99) +,S(2eb56a7d,b051e9a5,8a7c12a3,a92509d9,5da4956e,8b820006,aef166fa,92873644,30867ff9,7ef8d955,d497abfb,463838aa,c946d487,d702956f,b75ebf89,e25bddc2) +,S(88f839f6,d7f06f85,82ed781d,12062442,66d4f9a1,e2007a89,f660fd24,ebb30d5f,29ce1d8a,376a587e,96fae37b,521a8903,8f0bffd8,9f9934d4,eada0750,32faba00) +,S(112cb93a,8db33b09,641aef75,c3f9a399,b1808314,64e8a855,16e309c4,99ca9a16,66b1a1cc,f2255c2c,119bd0ed,a75dfe73,fe2e9d9f,3aa9a6d7,43a4b7aa,9d76bccc) +,S(407dbfb5,53b43e95,639aa6c8,d6868ef3,2f41f1ea,70cd4aa5,9d76ea2c,83b567d7,69fdde78,a4971ce0,b05a57a3,8891691c,d1fb371f,b1322a6f,97849c64,bd7b57ed) +,S(16fb5fd1,fb41d76d,ffc130d8,9549465f,7976a3b1,ecd6a4d,9e5d55e6,b2a6a40d,3d39a810,95904ac4,9559aa89,8fa087b9,b84ed72b,55f17fa3,aef8b32a,10e942c4) +,S(e40302f0,6c102ca6,e6be1370,2aa6e860,5e71fd37,6c87e2d0,c0ebbf49,6fcb31c1,d32d294e,1e80cd,94925538,2156db9f,2bea101a,f652309b,8943cdf,b82d75a3) +,S(8f2cfdc0,eadf8b00,f74305c7,892a4326,9cd31300,d716d652,92a7a36f,7f1b3b9d,6d0e726,838fd161,32d19538,147248a9,5d76c7c0,beadf1d0,b553e4b6,b7d1a2d1) +,S(c7a636f1,1a9cf793,4385daa0,5c3f3abc,8c3a1589,7be0b49d,ae789fbc,e07674cb,4f715f0e,e52c638c,954b8b3a,84baac76,6a891889,db0b7f82,6bdf81e8,4040cfbe) +,S(245aed6e,5fc309bd,980d5597,9380e8c5,79dcc887,a2758e13,24ed3a1,833dc820,a7980b85,c6ce770b,13a888ff,22a1356e,4136eaf2,49238c38,dd103016,f0d0b1da) +,S(91ea17c1,d90556a3,722dffa5,631286b7,f9db0f01,e411ac16,f5203c4,1a8a824d,281023e9,88fdcec1,94af265e,c407910c,54d25f20,69d64b13,c5261f0,c157a3c5) +,S(729db97d,35fdb72c,a354c65,a0e7f76,7bff9ade,964b1d57,a98f9bf0,39a74eb1,59596a57,7c888b01,6e00143c,63f0be1b,d86d95a1,ef59e075,fe7e377,1472bfc4) +,S(f8cb711d,f74a4961,1391871e,d8de6a63,89679130,b587beef,f4eebcbb,9daaae9b,4c52c310,c6f960c1,53f386ed,6842c4d5,bc1b4c99,433567b0,fbc40e93,91a5e022) +,S(1700d0a,32624d75,258d80a6,2228b6ec,91e66949,a463f3b5,16dffe43,b9fa08fd,a007bbb6,b687b509,f450908e,b617f176,92918f18,be3113d3,8a80ebe4,4ee750b5) +,S(9f2f3ee7,70a2c422,b9b92eb8,a52570ab,b5354154,57f0efec,fcd9141f,62894132,c977d79f,ef198135,b69aa3c3,77a7f251,3274911a,73736b2e,c543a721,17908588) +,S(86f75064,8a2b829a,91acae01,4beb20f9,aa9ee46e,8e513678,c4fbd7c3,2ac36e6e,1768035e,bd1fd375,7caacc22,495a5902,a3c616e6,49eeebe7,4377b996,30192b28) +,S(1d4207d7,adcbd969,d432bc74,35f2fb75,b35adbe3,fa1f45ab,bf3ee074,b8269f68,11d80191,accff888,928a0835,562186c7,30367e90,91d310d8,2a712a9b,13d70f99) +,S(f782bf74,2e55fd7c,ab249b2,1570d9e8,cfc12f46,5330d2e6,57eff609,7c3d19b6,896e9e48,a60ace9,84d07ebf,12449980,9d96639d,101b3405,59eed877,908394f) +,S(22bde2e7,e3c0d268,f556c478,82e50f2b,634c4235,9067cbd5,a0daed53,1a166a7f,5e03a94a,5baf0f92,7f4beaf7,6b7e9649,aa578eb3,f105515c,ed670c3e,e1fa3e72) +,S(85ef9f8e,b54cc4f3,aeed4769,85529945,7eb4f3bb,1e5849a2,aec7b257,a8a9a074,8a0245d2,f0c8eaf2,84a01114,d29c65f1,c146af0c,dedfb5ff,9e3be650,e2acaab5) +,S(3bd6c026,63620684,4d2e1a89,2378ec64,177145d6,24062d23,ce9c2d08,4f34ca81,7f0e5053,87fade82,8596f440,3687b04f,4a2693ee,25361442,1d9712e4,b3e0c179) +,S(364f9a2d,641173de,4a0cd185,972f6d78,75b06722,3cececc2,9bfb8aed,7ccd3311,39e7616,8d64795b,504de9d5,3049dcb3,a95fb3c9,affa2d5e,8e8cb35b,6cf71219) +,S(8833f933,f4049c7,98493b,e5f764bc,47dae8fa,baf420d8,44c7436c,eec27898,bf615e47,1b0f1029,1afb2839,2c874f83,ae55b15a,58e61be4,12b7c7a6,13868279) +,S(d4fa5129,4835f9dc,49cc3ad,b9401f61,97654f43,ec88f206,9a63852d,6abb4a6,f24535f9,9efed47e,80d66925,8924e56a,44530eba,a2aff32b,70f36551,1db59521) +,S(50eb8613,99f79883,58b9de58,88c47cd7,bd4547c3,96e1280f,2806efd0,d0715b89,dff64137,f74442a4,dd0c25ff,ea968845,f9e14ff4,d3e32010,f1c64ca7,6afb1be) +,S(f8608ede,92c5a1e0,5f61c065,606ae232,b0f81161,bcec88bf,b4f2b14e,22165cca,e583acc4,7ee133b4,8c3c1eb6,5d6f4891,b53c84ec,7bb352ec,3b6e41ff,aa6a2089) +,S(2c00145a,60e21169,98f23b9f,6f83223a,6ceafa12,c1b92844,2a17bd63,582a4fd,ed76c7cf,c65a881c,5dd270bc,7be9ce49,c2990e43,425ccb7a,eebe64e7,eff423d) +,S(b42d4c38,79f7aeec,96f212f,1d5bd79f,bdeb9850,ae44af81,b4b3467a,85c29c49,7bdbbcb6,1eb04e41,9ea8f9ba,dd5289e0,d718158b,63ef0599,55e3c5de,41f833f1) +,S(a5831ace,8c19fd68,85e9b9cf,34b9fa4a,9e80eb3c,36e256cc,44cbe521,6efb7128,e10dc489,3e0fa1ca,f2dee476,5b8ab518,c3778f4c,583abe27,af293869,c765955a) +,S(9fccb821,59ed46e9,18a407b4,967e1154,4566afbd,df6c0639,d5cced94,50e56b17,c430e829,438188ed,a443cb2c,aa7d6939,3004ed75,5ff61e57,8dbe9e64,251615ee) +,S(c1efe41f,44186467,cc0def62,eb0f0ac9,22b8bad8,e2347849,28b465e7,1789fcc5,5d73f89f,709d54d4,e167806f,a07ef07a,7fd1a7aa,dab9896d,33c290f1,dca74872) +,S(805c0816,43fffffa,c9055f2a,996fc2f,fa02b4ab,4fa440f4,8af5878b,4eadb694,b0a0dacf,d9b3b9d0,51ac59e2,b367a8f2,eaae274a,ee2b05d9,18cc0042,eb02b6c5) +,S(d5da1b82,9b477768,bec17829,1c9abc82,b595bab8,6240e705,715de420,fefe498,dba833fd,df1915b8,fb43b39d,dbbd635,8f12d4c4,31b547c4,af07a6fd,75fde785) +,S(73a2441b,1f1b9ddb,844caf0f,8cb0a91b,5adc6556,6f883026,8ceeca8f,7c6c5cae,512e46ba,b47e9eaf,64cfce27,24566bf9,ab43e32a,bb0e098a,5dac9687,11927437) +,S(dbff750d,bed18702,eacea6d8,b54540e6,ae60ea05,85d77db8,7a63a050,806037f4,1f349895,29ce56b8,bba91938,16e842fc,f74b56e1,568857d8,2f193e02,207f84db) +,S(57c73f7d,57c7882c,5d574f70,fa225552,ab3d7741,260bfd3c,b616d6be,9698dbb9,f633edba,f7f6cc7a,9d8ff9eb,75bced20,f865fc9e,81245e77,32db2ed3,876e42f) +,S(6663e27a,7760f187,a1f67823,64044da8,d4cb82ef,e296f5ca,90c5d81a,49b7cc5,4df0d12,4ca9c8db,4885f8d5,18cbf06d,f5b437e,242cf86b,b11df29c,5c83937c) +,S(83f688c5,88ee13f4,a9e72023,5169dbd7,ebbe0c68,4cb61827,3e2b75bf,5fc581d3,f76e519a,151ba05f,df5f11e6,f3cfbcdc,4b00776b,14c4598c,51783088,2b2bc6c5) +,S(2114e129,1f65c339,d1bd4373,6c677937,4385b3a5,5dafa8e4,a0515134,6b650389,88103399,1b682f7e,9ba02fd3,e104932f,802ed44e,b996beff,7fa9523e,c9c2a9d4) +,S(a68b163c,db6c8aae,8ddeda39,7d8031a1,394ddc36,48168f13,47774ad1,d569233a,eba470d3,4ae15c94,57ba1b3e,cf5f3d96,682b8095,f83eba7b,f319feee,6740d3e1) +,S(a44b2a55,baa92a2b,cdd2f06f,36874d69,40416b79,20bb6daa,2bd9edaf,c12bbaf6,d06941d8,28f1092d,3667ce3d,59d23159,54d6cbcf,c0da31d5,1663a6bb,ccedbb47) +,S(5630eea0,8fee5570,c094ded,917746e9,18535cb8,b0286bf6,f6cc294d,5714fd33,91f60b64,3457dd9a,b2a02ff,99f931e,b38b4d87,204de10,d8a30cea,ce576b62) +,S(cc8b173b,d3112432,cd0c741a,8620fc26,ac5c5d89,e05c18c3,13067fe0,a41b4b00,8cdcccfe,b4ca500c,34dc3087,58f424f8,52517974,9a33e27e,8859515a,2f7c0926) +,S(abe16c8b,e0c99bf4,d396e70d,af00af89,b5d95f5a,3ba33570,892d086c,4b807943,14b2bcfe,8cec39c5,826fad38,9b8f8788,51e1595b,b25b1a87,149d8627,1218e9b) +,S(62411146,ca2da616,b557f0af,ccc2cb75,d278b07a,4dacd864,7e449ddd,cf29c09b,d081b63d,67ff0c07,5f00a3c7,2771c581,87804c1e,4ec5bf68,faffbd21,4c71e15f) +,S(5952a672,a50af560,66de08ad,be4f5cc2,38f3e4ee,84160b1d,14534c4e,2b50ed52,f7d7e2e3,e9612005,a0344e93,454f112c,792f825,f3d3044a,28d9af6b,798da761) +,S(128fd5b5,420f68be,3742def,c987da3e,bca771d7,af1cf8e3,12d6b3ba,df162492,afe5edc4,80c1c8b9,5580dd8c,aef14338,c09fbf6a,a1c951d3,57ca4df2,9d3f183) +,S(6315678a,13cd71e4,6e283287,24499671,6adedf31,38841718,cf5168f,60d4bf8d,ff691d8d,c5f97f7a,f2ae319b,dc590518,6ec3bd36,7f492d0a,95cda47,9492ad3b) +,S(50277159,4169f70a,ab39095d,d8027324,e212f78b,c3b0865a,a57f1574,dba1bdb1,e31fb30a,58eca0da,aea93548,bdeb9f32,325d6c30,69b3d936,d610bbc0,de3b771f) +,S(51eac8f8,8cdd7ac2,46375960,c6b7d9fa,a89352a5,4024003b,cada1e6f,df389721,6d4c8750,95d6ccfd,9d8a5830,c4672c71,d414ffe7,cff2cc15,b7b5d169,48e872d9) +,S(bd39330,76c0f542,a0590ad6,398b2418,92b899ab,75ba0065,b1ace928,b8cc0ecc,12f4bfc4,57e97c3c,9d4a21c2,ad106ee8,8cb5bfc9,92d151ad,589e90f7,d65b5d8) +,S(bd0eb600,5ae967e,81214a1,889f7dc5,d1e765a1,af74a93,f5292758,539d6dd6,2e532797,9e6a22a2,63025e57,4805e4c2,6d62b33c,5269d35b,bdeee7f6,4a2cfc3) +,S(b7b068b6,8ed18d80,67a0c971,a06cb3f0,5c96ad7f,371dd849,aec3a2f9,bbe23eb6,89871d76,d3e6b605,9997345d,4246087a,a3fa61c7,dd75f5c7,b2ed1e20,59a00350) +,S(10cf2c38,643a08b,dd842c4b,79efa2c0,3b5dcd1b,c708b253,ef71fba7,f0e51f48,e37d14c,934524d2,dc562f6f,997227e1,44094184,e8342995,d5562000,34e71f4f) +,S(5936b571,20b6dc97,ee242ba2,deaafad4,5ab83795,9f1e7390,54a0c026,df7bb342,86bab74f,b9d4f776,e82831c6,3a409237,d5923c7e,7b3e0b18,12ae203b,64fc750) +,S(67bb9ab0,bc48fafa,3ca66493,995ea995,e36cdfb7,152d64ed,ddc56aa2,6c315896,cfa9a456,dc2c82b7,f87f4216,e365f5e7,97223d2a,820a127c,a5ee4ee9,281b71b5) +,S(5580326,678b44ad,fb313c23,dd8a7dbd,c6869fd,70cc58b6,d20f8b92,ecfd81b5,6d343687,f3dc733b,55dac794,c895e5d5,9032613,563f2d72,ee94afe4,c2a932d9) +,S(fe285767,53d2466d,d056d2bb,b7141cf7,e52c2b96,d0ef3c8,52c728a7,d2dd8126,f344b3ad,c8077e92,24c6c5a9,c9f40a1a,d8721351,6b8691ab,c5fa9f73,726a6c98) +,S(12f25359,638fe4f3,97a17f99,c233b2ea,7a794d71,e677b206,aa32f251,8cef615,dd0d68e5,324e4325,ebd45766,441677de,40c15792,19d65c6e,9c63f15a,91519c20) +,S(f1e45fa7,21bf7fb4,45fe3eed,29c26bb8,bf1ea59e,de7c1a6b,e652663d,233c3e9d,6d145f2a,c3a041a9,83b9865e,66775342,a0f8a435,de19626d,ca8b9328,797e20eb) +,S(6b6ab442,d2623235,dcc7e3e4,85d00ade,7f219576,509c528e,6a3417a4,fefd328d,5d627367,ed25278a,6d3505c8,e13970ba,253a26a3,c605d11f,1eb345c5,56584e95) +,S(83e10be5,d21bbef2,ed1ceb33,c4e558ce,bee76405,257d9573,51f5d90e,f219552,41f5e174,c6e9b283,2a39c2fc,4d4fc573,634a8975,e143243d,14dc4be3,434a4380) +,S(2ba25948,9571ce20,f792129d,f43caf4d,ddd93b76,e4c8cd63,7a9de68f,f8d615c5,9469a49a,d1a814d4,2f460325,b7d58f2b,eeb85183,a370cc3,69a685e6,a87f6e61) +,S(3fac1508,b669f540,77a840ca,3ddeec5b,b70c03b0,ff93a77d,f2f73df,2728f36b,dfbac9d5,ceb21745,a6d27c3f,d6fd96b,af708066,a3bf765a,208b7231,d5fb6955) +,S(8996dc02,9b79d0f9,d57b8c8,549fc01c,2e1c1c7c,2ce2cd70,7a0bba0a,b3420ee,d08fcc05,5194c4bb,2d17ad54,2f9ec734,f2a9ab8b,a7dd0467,c5d916aa,10f7b8b1) +,S(16af9433,c9baf15d,921f931e,f530a477,b04b2e03,e1e8cd05,42e20628,df7c3241,65863e2a,acae34b5,a1dd53e0,5efd423b,165235cc,69195973,2d0f64e,c5b56fac) +,S(d82af39e,eda70e3c,f28e2f6b,b8009131,59ada2d3,854e81a9,3798e402,43d1d3c,fe03de8a,326e8bd,b202b5b9,929c2f3d,4bc8abea,a2377cb2,29cd4630,d1dc1c50) +,S(a7ad92e4,7a442903,c2f91033,7e2ebc98,14bfc943,f2747eda,666bc813,c04382ef,ffba6b43,9379448b,56b20163,44439b9e,8d6da764,72f67a27,9c7f45a,359234c1) +,S(fe9b9274,7b27f7b0,6419dd38,53e61762,de7a5116,48008802,681bf521,21a1ff92,f32bec26,b9d24872,1a47c65b,48426130,b8e72e68,d231bd4d,82c5d4c2,bde605a9) +,S(8e22ed5b,e5d80940,970de428,5ca609af,872b8a4f,b8c93942,fa1e62d8,588ac5f5,6a461962,b74b0f93,afa72284,4837ec30,b99a65da,d688c161,cfa42028,2ed97167) +,S(bd3bb0ec,bfdcf06a,62f0046a,989b45e9,c76f4d9e,b3225495,eff70685,71518fb2,5592029f,3eed8e35,727865f1,dd2a6de5,e19e6eb5,f92e520,529fe97a,c296820a) +,S(50a9dbb0,b08a48b8,76dc65fe,6e2efd92,d44053ed,73b8c279,5b688e00,a1fd1455,4a1fae82,51581f9e,32fe8f67,5675ef70,dd7c2ec6,2a42eb3d,e1aa13e6,717df147) +,S(6c1dc44e,67b52cf5,a4564ce1,7a9da713,c718833a,6d527e7d,ebc6b1f2,c893693,89cb4508,681d58ad,77900c1c,aeb25c59,b307c9f6,c84f1329,35e32af1,e39f8f67) +,S(3ffc35e2,4d4fd0e6,ffe4d1c9,b5097d10,c12dc7c0,4356cea3,b5fad66b,5f3333c0,89718e69,78748c6d,e99d181f,137eb74,6e28b05f,27af7726,e86c5f5c,daa1eaea) +,S(fe2261bd,b40fc492,99be54de,1d0bf22a,634aec85,77b5e9e1,51626d67,3f4214eb,896bf33a,5c9b7537,b621a168,f3da1bd7,dbc94816,922350fb,38925c96,5e57c175) +,S(129b6e5,dba2fe86,749274a4,f1ec5999,b2fc682,933a1120,cb8e16bf,4f4131e8,24dce651,b0fe4770,6c78c217,f0d5ed4d,4bda4e7e,4e7ea6b9,ca59e751,b018b5bc) +,S(c2d1b280,79d91abe,1a44c4bb,96ab548,90323054,94075907,37b39ea5,e1fedd72,6974b9f3,80edabdf,e7961bbd,71ba1971,ded6ba24,90466d1d,a5715d9f,92472637) +,S(d8dc5f38,76f6049d,a9a5c9e9,396d287f,911e06cb,ac0148e8,26c8de93,15bd464c,701d0a43,ab41f321,b8f86ea1,b1f51d0e,c22a3399,c1d8534a,433ebc2,38ec248e) +,S(2b1a41d7,ebb9756a,b62a96fa,57909ad1,a747dad4,b3730da9,a12dac8e,3ee4c414,8ebb1512,3f43224a,c2cb4ba7,c90ed765,5470a968,454d0c81,1ebe3384,5c6ca968) +,S(724fe9d6,e7f75b52,7da19421,3c984e31,f63ac3f7,1b5819bc,344ea339,567bc179,a1db688d,ba1d85fb,20da08f,802b5195,163d179c,7bc60f70,4ade1f26,4e1552fc) +,S(835b30f2,8e54b834,5ce95569,7d71b7a5,7cd4b5b3,17ee3fce,57722454,7695c9bf,f431ded9,b7ba9477,ff041f83,22685e4a,8c88c91e,15a14f21,6b16e302,e243cd11) +,S(f5015d22,16cfe581,e650e579,c49b6ccf,b5ca4dc6,42561256,21df7fc8,19047ee6,45b099ab,febbb493,5356872c,40c06825,47aaef2a,72e80d27,521b65ea,e2d4918a) +,S(df0b1b57,f3a0dde8,b136a92f,bf953a83,694244bf,99782ea,98050bcb,3313f826,6f7c8326,bf5f6e15,538a1f31,273adea,6908e5db,7f38f395,49284822,12124d5) +,S(a5a24cab,96c04bdd,6e5180a5,8fe27f9e,51897bcc,3a0aa9d8,de06de65,53d2890d,4f6dfa5a,a6b44550,105fbf39,7dce3a4c,e0b42362,4a97d979,eb31324f,f1215525) +,S(849c2e79,422d1dce,4b568aa4,c80eba4d,d8acd237,71f6dff7,40849bd3,ecdb7e41,a465929c,a3ab167a,dcc4fcb1,7ef9102c,35d8937c,fa900ef1,8022918a,6ebfe79e) +,S(a9a98d5d,d8f8ce0e,ddcd90ae,671c52b7,1b09b75d,b4185d4a,1ff12c71,70b499a0,a4eb522e,3aad7f1,6aec7758,c9528bb0,c07184c9,e3c965f7,afefe128,bd285c5c) +,S(8d60786e,1ec1fbe9,61e056c2,d6a57c5d,813d7f20,bc8c68ac,eea0020a,2c4e57af,3a39b0f1,6cc346c7,fc695f45,91b557b6,3c1f8500,89d742b1,60c39744,90e55720) +,S(4710166e,65b9a2d,8de5b80c,192303ed,25cbb80c,b91c57a0,b31a38c5,5c218fd1,b4cd95bc,fa48a016,658382af,37ada302,26887fc9,8200f77c,2b8819a9,ef489206) +,S(e2183510,40815901,c78a304,e6f0d545,5a116560,a91d84fc,157f061,5ed6c0de,6c557bb5,358454d,419c5cb5,1bcb85e7,db3b04ba,d18e1a63,a75687c9,8fd6d973) +,S(807cf529,8730d656,e68b4aa6,5f8d8692,ce246c2c,4e668c69,b5e93e8c,d26b289c,b22a6fc3,d7ffdf57,f18e7447,38cb1bb0,aafb7b39,101d3259,d31574f9,fff644e2) +,S(568f659d,f19f14e1,5d91f3d6,bd2a4690,b274901e,cf6fc684,dd0d8615,8dfbdd85,28eaf8bc,1db68471,4ffbfbce,30977c7,606bc591,dfb8ec02,e43a31c2,ecafbde7) +,S(651dacbc,564fdedf,f4e5e3b6,f2dd366,37c69140,7fa923a8,ce88ed1c,a65e6b86,88dfdb8e,6f117a1e,b99ba423,89ed2db6,cd5608e7,8be2c896,334ffb8d,2e19aa79) +,S(5a17c956,8214ae71,80322b0e,574529c4,dd7d951c,872809c6,b33ece6d,8cd7cd0d,ba4b0cdc,7d7e6ff9,5a97e4c2,6af714ae,f00c9142,5e562ffa,16942fe2,852a3e06) +,S(6d564251,5edd2987,568dc237,b5b98fa8,de9b86a3,e7176e62,f2609dfd,65810920,a99a0d1a,12534f64,fa97227,825b094a,22fc16bb,e8777669,d5aedc4d,58e81ff0) +,S(e3687c75,c0689381,22f60fc5,b346e8dd,17b2dff9,cd7fbea,94aa54b7,ba1f6de9,4dfd4537,1f62a968,399cfaba,87a0b985,cb333510,dfca666d,395e0f8e,2b7f473e) +,S(1a3d974b,49e7e68e,bb2851c9,c9f22d9a,5929ccde,9d635e8d,61aff93f,f7244472,f6c9e7e2,98815ef8,d53a7bd7,9f10275e,ea74ccd8,5d97cc3d,cf2e97b1,83c97c86) +,S(8e0dba73,12c4afe,8e1bc508,4d9f4944,654a5693,81a64158,d7db7007,3f897cb3,560eb34a,2451905f,2e9daeaa,63dff50f,761bd68a,2321a714,45930de0,4801875) +,S(35d9eaef,6c4ded5c,371a655f,2fdbac45,35471c32,b369955b,f8f30d95,21cd5817,c5a084ba,7b2ea4c2,e3c3d081,dab53c9a,ee40e10f,607ce88c,899f0e3f,5850d75a) +,S(44d1dd16,c42b7811,f78374d8,2ec9983,7fbee7ce,4b3a8ccf,81ae4ed6,3b7d2c73,6a7bd35c,b10c4e89,60e3eba1,8f658510,3be8d1a8,5c4932f9,f1e48d81,e3f66604) +,S(4b7a54a5,e7153a54,e4400ef,9311d6,cc16f641,6695fd92,5fcae9ed,6b2738d5,43a7bf76,ac2f663e,daf0036d,b665291f,cf983c0,791a8a6d,a5ee1956,2dc18850) +,S(add4a15d,d1a350e9,e5df62b5,4a6638d,76ee221a,4007a19e,db5bc93e,87f11ea6,c26d6fcb,3a8bc1fc,f1474c26,31a4216d,740cf94b,a9d7e48c,8f01be28,885ee849) +,S(9b52aafa,119ada49,ce33340d,ff75ac50,ac9a9d87,775e8e45,da58452f,228a23c2,67640253,503b5e3f,89f7ad07,b9379bfe,77c946d,4f61b83d,3fced91b,69e850af) +,S(965916f5,89854944,26c1efb7,88079a55,f8109cb3,8bb111b8,42ef7f00,2d4a45d6,9aa2ef4e,61902148,aea7769c,a561d04b,cbe1b340,a231388,e332c30b,8488e531) +,S(3af7890d,c045aaa4,2f7a8f26,5fcff9ea,41bae0f9,87c75c22,3ae3311d,e09b6ffc,dbb31417,27adbd5d,e34202b7,f7a880a2,41f18b0f,b1a40a25,376c4a30,ec607152) +,S(dc465cfe,c07f839b,46406f4d,9a0078d7,57c2fe0,e62aa4e2,212ed33d,5b2026a,1ef12aff,a98868bf,b51901f7,2693f868,5ba2248d,91440380,53bd137b,24b3bc8) +,S(5ae92f8a,cb9e2ca7,2f4d4c70,f4daaf96,bd237bab,2a83c0de,693d8207,baaa0f4b,54e266f7,aa1b7f22,8f24ab91,5e3f0a92,3220512a,de239da3,1069bbf2,35d63049) +,S(38134bb,c6c5a4b3,63421af6,ae573ce7,20421d36,1f4966c7,b9e7f125,f49659ac,5d42678c,d6f89848,72399321,fa86318f,7a4e3f05,4c3bc6f4,6782be35,4ac4aa16) +,S(f2b807a1,3fd603b4,111ac02d,5c646f6e,eb819a4f,7893992b,9132aa83,76892a57,6f1beea1,a315c000,3c957d85,bc5171d0,ccb8ff06,446f4748,738a3c78,f9ec2d4b) +,S(debe05cb,b308a6da,a1eb55bd,73c3f1ba,248ade5d,ceb1ef3a,baecc6ac,7a5e8c09,f4fb16b1,44beb4ca,789aff58,9374e476,efccbbbe,b74e2693,a4d05ba5,a809ff05) +,S(15cbbf1,2720f8f5,fa1a7752,b6f33333,91cf3d0e,c40f0292,24f5b7b2,c966c099,be3b1573,fe38200,a464f4f0,c3c2f9d6,24bd59bc,9412110f,6eca2ada,2f1c7294) +,S(e4fadc29,2f0cf77e,4b14c3cd,b567f5c9,be82fc93,dcdf2b50,bdf20fdb,f5984769,2858e2ba,c9834a2f,942ea7fe,2e339d8e,b384c255,6a48d688,a9510808,a1235452) +,S(b0a8c6dd,f57434e8,a8bee1a9,530cb9d,3d4ac31e,edd17653,3d84780c,6909554a,4f7467d3,62185e38,f6d6c30,e4c3e4ac,e167f3cb,aefcab8b,eac754eb,c76ea3dd) +,S(a4398869,26e4d06e,5337e61d,dcc6f491,4f40c04,eb3ec752,47d9d058,9dfea2af,ac1fdc5b,70d792c0,7bf7e55a,b07ea1ce,477dcef6,cce8585,84cc90ad,c62b6272) +,S(84b362fb,1597f179,f30b7e2c,b516153,94619081,1131d45c,ba55fd1,94f369be,d2a80ffa,44965152,78c2ee3b,122b5c3f,e6d27f9d,6ed6ba94,9258c2fd,94eed4dc) +,S(75182684,96e2d037,24c11192,e9112501,f7c27d19,8b92fa1c,3b0e931c,2b85d32d,eddd2a6d,d884f93a,b6f8d225,c9fb32b8,9f396f1c,2613be98,d866b713,14a00d70) +,S(aa96e0b8,104884cd,7e22211b,8b12e6e6,b3f3e3f7,fdff04fc,202d8946,838fe15f,d8a9b5c3,9739fae3,dd3b2483,4fd2981d,ea529097,2ba52541,56905664,f289e3e0) +,S(ada17e80,82a0a15f,366f3d6e,6775b5ef,35c980f7,12ea7522,1aa796f4,2454988e,7df4c1e3,191214b6,e40fdae,2f5dabaa,b6e9837b,f53eb10b,dd28e674,230cf2e5) +,S(322a0524,20f0fdbc,85f35fc2,de6690e5,a61260f1,428ec662,4185ee8c,d2385caa,fc81cabd,789995e7,d36d3de0,1b650a20,1befd7a7,a415d250,697114e3,c95e096d) +,S(5082ad62,3bf2ff8c,b4571b9b,86303032,ecd137bc,86c5514d,b9f218c,4f091153,b29d3823,eb4ed958,9b0fbfc9,2d006fb3,698ab596,d3e60360,e435bbdc,be4c80b3) +,S(de9e45fc,e9e0dee8,3bc806ae,286a2c5a,a7978608,42ddf02,d29a6ac3,9fbec470,bcda9466,e7207f7b,7d986e,36b3f238,d5bc51ac,90ec35bc,56e0949b,334ef964) +,S(95cbc3a5,61ff4cfa,278678a5,6f8b16a1,efe2d286,c7103047,310454cf,a1a822bc,8720fda5,58d23b5f,af9b80eb,dd5fa625,93325a6b,eb5ffbd8,f333cd9d,9c8b7366) +,S(fa0e59a0,969de9fa,aaf7be60,24136559,cb384b76,26d3bdec,f70f3e55,696a0632,2e8af3c2,a54e837,ddbfc32d,8a47f342,a856b854,7ec4b0ea,6fb3695,48b8b588) +,S(56aadb8,2056ff5b,3337aa5d,337671a8,77168b0c,f0330e8d,8f5445a0,cdd75075,d6c4cd4f,db81d8df,b095f681,f7349fdc,c2cc80d9,399fc16e,5fa3e86,9460a5f0) +,S(7da6a13c,11d5b063,8132254f,c064ff3f,d3818a5c,e07168eb,ed5b7345,53bbc19,26e912dc,5b03258a,f914cd86,88d6a068,266eef77,7d4f45f1,7c47cf92,16d00c4c) +,S(4004b235,d58417a0,ea1a2071,32b30a8,1dcd6a9c,3ea875a3,6d2a6225,e2b56917,1c960bd1,443c22fa,96f06eff,a717b5bd,efe8b105,7402cd93,7a6aa909,5775e226) +,S(b12c4d85,6ec6c85f,3553bfee,c7dacbf4,f742ccc1,356fbc8d,ab3d25b7,52bdfe93,a8a11692,49dba87,8c8e6c56,ff8f699f,d7e69c6,f994d05d,4e0643a9,7f9cd2e2) +,S(a78d9a2e,8b74ccdf,97c6ea9c,aada2644,8b560287,7d7b0970,41d24840,91490970,39cdd434,1d1e16dc,b89fe937,665e70da,ea80a174,5ae7b99d,dcad04e0,efe841a6) +,S(c8233855,b1f242bf,59b86372,ae49a985,2528440f,e3aa8e,28d594e0,114d2ae8,6f515202,a14738ee,ae4b430c,27391144,c551bfe6,bf24005b,81f92900,bda92b7e) +,S(6da24dec,9d6ec569,8dda9655,672a9b79,4923f595,9157af10,64cb53cd,5e5e8f6d,59517e76,8b0d39d0,2c075a46,c1e653f8,cf876fe,cfb10746,a8c248cf,4c73fcba) +,S(d0c55dca,ab79e0c,84ef08ad,57ff67c5,b36336f,2f6231d6,8efa2fac,54558ef0,d4365ebb,4096888f,c9a74d90,1adc4c5e,16f5dddb,442cb5d6,b5e22b32,99aa573) +,S(d76f084f,237dedd,ac8a1936,319d198e,baef2c4a,3b81ae42,e92f96b6,e222490c,c7737563,9639b7c8,32e4bf45,efc8da2f,53e20e25,641ea714,85674a40,1dd5f14) +,S(6a1f6920,9196c02e,6919abd2,c8fc835b,889c5ca1,6bb25e3d,ef7d0c4b,9f4e6d29,84371bc2,7bd206d7,389534ef,f2a49c6,cca4c9c9,874f59b1,ccc8b5b,bd5df3b) +,S(693b3520,85e1ea36,bc5c8ce8,3fa49843,369300c5,170010c1,b11a3c76,4deb12d6,4441c9b7,808b1ba9,8199349b,243f08db,6cdf5326,d7453828,16f008d9,45c1251e) +,S(5ee94c65,70953f27,37c16a59,590f7cd7,87143bab,405f6b23,718878c7,bc95741d,8578d18e,a49f9204,e51513a8,94920224,70837b2b,ee480929,5e4c4f0d,cf5c7794) +,S(30c174b0,e7b0cec7,e6da6a5d,335f48ee,6f59ef16,984e8912,32e874d6,2e51fe2e,af7f955a,8807444,56b2c965,5c4ad915,e040a360,eef0c4c7,891db1ae,6983867) +,S(3121068a,eb60a54f,dd427eb0,92e30895,92335900,cf191eea,79118442,67b7f4ca,d9e8f74,b8d9c0e7,c35e314b,51a52a95,bf672adb,9c6fb104,8d2ea489,5135aeae) +,S(a06f5e3,6513a659,106ec301,cf1f2df5,6093e690,38daaebd,4b17ea45,9e977ff1,eb19f18a,15630965,d2bd8bce,9e350374,1ab35f0e,4b442f12,9c9d831f,3811cffa) +,S(a26af0b6,50967dba,1c4a33b5,5226c2a,ad445f43,84567580,3b97ca1c,f3d217c7,22c8aba1,604df49,abe16949,59b33cce,db11c241,cbdb171c,50b0fb0a,399e6839) +,S(8e4471cb,b650097e,d3b0e938,18b8ec5,a86fedd1,addc6ed1,8703a99b,4128919b,fa5457bb,4068bf35,7b050244,6eef2507,c1d87051,28770161,ef0e92dd,d2308495) +,S(e9116ea3,24650463,fde960ed,eb7d5dd1,f5754915,62c99f48,31b553ba,2663ba1b,e30d7323,fc29e388,94244422,63434cdb,aebc5895,8a6fb350,33141e96,46a4529b) +,S(8b2267e6,9052f769,833b0fb0,ffe413f3,4b8edb93,9a2009b8,59d6673c,4ca6ec37,97f80a18,ac047152,178432b3,d445a0e9,84755d9b,7ad43165,8707185d,d573fc5e) +,S(79947669,d7bc732d,ca08e0cd,d3e601f3,c4344532,e35aa7a7,12271b12,339ee2b8,55906cbf,e782d32c,13cea8e,83812e8c,84c76d38,472ee59e,134994b4,b7b92897) +,S(ca6d40aa,2f863c02,b6444727,d00f8923,ec58afec,3b4a4e51,f4be232a,4b4c7c7d,ec73856,b0529f1d,9d2ed892,b22b059f,35e4a91b,b60c6a6d,e919d611,d9bd90e9) +,S(7ba23bca,5f9a88c4,588dec37,3861b699,ddfc9f5a,5b277bc5,e6e16f54,513fe7d4,25f10a4f,eeb77ff0,e24170af,dea0e2d2,3f2289a3,e53ad674,1640cc69,c042dcf5) +,S(186da622,d0e8a9ba,e26d43e0,b601c68b,311d2046,4eb36f2b,f86c3e0e,5d4ffcf7,53a6f54a,dd11af9d,50bd82d9,70825bcc,fe9da1d5,ab55e64,bbe4582b,f5248d37) +,S(e9601474,568cfe7e,6cdbf488,63f11f12,fa17ecdd,c623cb11,4818eb52,cafcdf8b,96d51b2,7b5e4fd8,1bbb009a,2ce40fc7,65fc6a3,7f8bda60,c4927766,a52267da) +,S(811f5957,accf9f32,3e48ac3a,33fbaeaf,c5120858,943e7065,9c0da185,71d1d4e9,ede77562,cc8ac601,e3dbdfb5,944d59af,63bd1aa2,ffb35bf4,1f79c418,d1d67937) +,S(77424acd,1d55424a,edb0149,a6ea0349,afcf44c6,667caa51,302b70f9,5fddf277,70e15309,989a2512,422a5bff,221c0e0e,df608746,7a34dbaa,99e77f9c,62b56c3f) +,S(e9e139fd,73c2c50,375d3966,ed4af6f0,4bd80bb,439121,d61bfe66,99dabd2e,260efa55,805918e,d45c98b9,c119bed4,21483d88,722e0f87,de7a31b5,e4b541fb) +,S(a9a5313b,e634813a,b10b9b3,6b38ed1d,a971c0de,5b6d1010,4cbe426d,544e7d79,ef7b3203,2a95144f,17803f09,72f6e2cb,80e6a099,5196911f,916225ac,e97bbb97) +,S(ff29a1dc,b5c97b7c,c5e2b73d,7a0e0244,bef71dfc,765127f5,f7e0f38b,f8a099db,b8334f11,682b9a22,ec08a376,dc3994c2,7d235d5b,a4a77803,79ec0fb6,7b4d0345) +,S(c98df4d2,da452118,852c096c,bb34c8ca,a2ebcb6a,e9a3420d,a4fd3eec,cc31c5f,f4f9c618,44cea236,edef80a1,4634159c,72663322,7372cbda,4b2680,b5dbbf7) +,S(66126139,77cfafb2,283e1a92,d6327174,86add807,b88cf793,12fef2b7,197289a8,504387f6,70caf906,2db248c3,ed5faee0,269d0190,70dd5acc,c8599f5f,5e01d1d0) +,S(efa8bcf,281ad4da,2f083e6e,182765cd,ab0e66f2,e8411007,e216a69b,d73d5e94,6e1afd7,e97061c6,cd0794f6,837aefe6,e8ab76b6,53d80846,98747ed4,64e20a) +,S(d4f9fa7e,6e385f02,c068ce7a,1b80343c,20f85b7a,4699c126,575915bf,69a2f6e7,a6496004,f280f970,c1028b3c,e0d94187,34dece11,3f9fc737,2ef0125c,851de143) +,S(5980a5c,456f383e,f0add523,13fe37a8,874059ee,497b0a23,c6dfbb2f,9f6c494,e1da9a59,c8e3d482,ece7972,9c77308,e47bcd90,cdff915c,32a94908,db1651fd) +,S(988ca976,ac6bcfb0,b42125c0,939a1207,2eb13565,29da3e72,6b70b2b9,5c310e12,97368d81,79a76a51,7c7d063a,179a2941,fe5df19f,25f1e1fd,42a32af9,d5de16cc) +,S(ca49ad0d,25b36130,cc878861,f4b72a4f,e945bc0b,dbae2f4c,629a6375,3d88037f,5ad2c0b7,2e084bb3,95b9268f,22ba1774,c6e423e2,4a5191d5,b940c89c,e1039f0e) +,S(ec18622f,b9771723,c8e6e6e3,5096e517,38c4dafb,82b10317,1f55f900,b24c2e06,5803ea86,c839ddad,6c288b8c,b382a1cf,76a790c5,6f99df9a,fc9915e,eac6dd61) +,S(c53aa261,60e627bf,bd905ff2,6b50a171,18062ebc,af9d9ca0,c486430f,b6de5da2,7d6298e0,f17a515,529fc5bd,2b85c7ef,d183710b,96d62a2c,5a0195cd,ea561790) +,S(ad138110,f9161559,229ead18,4b7ea7b2,846384e9,dc22b8eb,5b771027,8c8913d2,135a3ed1,d9df6a0e,105c7c,e6ce625a,f8173d76,60ea04b4,9ee781a8,90595eef) +,S(46946390,304df8d9,15705fc4,5714f3b4,233a5ec1,afdaf145,b6c09717,9c6b43e1,aef28d5f,88f62a7,e3ecb978,6efc97f1,1123fde3,88ec1bed,bbeee3c9,f9d3e014) +,S(d464a300,df9de2ee,220ae23,4d59b6cf,44f4d280,7ab4f588,aa21dd1e,eeb80819,89988349,b1ab280,8b829754,7e5b36cb,e66ddd16,4d7542d1,cb0cf210,44a8be1c) +,S(5e99ed21,9ade424e,25b807c5,bcbeb05,9b638b7a,4ffb3c6d,d3bd054b,b7af9f41,a373ab0c,4aba0b04,878451bb,96807604,7d811fd3,605e8e46,57574efb,21681aae) +,S(805edc92,6fddf92,d33db068,9334d778,4b30f73e,4e65517,42e62c50,fc6ff2a3,170e4317,4361275c,2102aa8f,5406ff9e,7bd35523,8bf1e946,1a6f16c0,38beecdf) +,S(ec6e5a3f,bb96f0af,dd700701,8c046998,49a879ef,5ebcaf67,456748f2,f25fd18a,9401937d,cf584df5,a9399fa7,bb309ffe,80ae015,20933d63,df1fc181,b2979fbf) +,S(94f226aa,a25c710e,2cc68683,2b9124a,ffc5c3fa,179ace52,327c6866,cfdbb3ca,b92762c3,a4c56d95,1ef16db7,b3992e9e,aa2f9c3,ec48f077,62a379f8,408f94a) +,S(8d2668fd,5d46bd4a,fc84183f,4fc31dac,964358b,fa6b03f9,16ac5bec,a619a92d,c24f6815,3e49048c,a461eea8,ce50c8db,7794b10d,d8080236,2af6677b,45e45f95) +,S(2a3ef112,d00514a,c562de17,a68bc4de,c4c04db7,8266892d,b645ac6b,ced47f67,6e93173d,64333933,c3db0f56,8c05410d,8a1dc73b,6a30c6bc,2b0d5493,d9f9fe1f) +,S(6eaa1185,19d6cdff,45d88426,6fac5867,790faca7,4ccc31bd,6eb19551,8f752dd,affb02eb,277a2bdc,db79d91,10ee8a7d,58c9662,22cfac03,b3d26cd6,3c678f9b) +,S(d17802d0,1944d9f7,aab2b542,fac985ce,e56172b9,e5629e53,ddf57e0a,8dd07137,485ae7ac,34d13d9c,9ade04f2,b3fb8cc7,d0cff406,97abbe2d,4961e753,b8de013) +,S(9e4cd82,67c121f8,96c8104f,988a140a,71f0cf18,782b574d,407a4840,607f5804,c05f08,3fb5c4d3,9d3e237b,101f46e0,6547828e,f05040ae,87db7874,9d7f3bf6) +,S(927758c2,12452995,886e97b4,b1d16c53,4603c,7362e190,dd2558a8,43521a41,30e4d5df,c5ff4b5a,5f4f757a,3483234d,4c658b7b,f24dd509,7968627a,a2a86d56) +,S(589906c5,90a1e143,ae7ea4fb,84edc7a,9f00bc90,dfeadfba,1933c36b,57f2bd25,e9d1d51d,92223636,cab62cab,362b79b2,12a18be6,6468f06b,a543921e,bc9b1c61) +,S(5b516216,1171c076,b10d4987,3aff89b,c080d2b1,9e3ebc3a,de8dcfd1,734e2f35,572c40fd,24965ce8,a78c3402,381bfd90,b683d6a0,d379d7ca,21e66804,31b8ffe8) +,S(1603bb4b,3dced105,b1a2b748,21080a5c,2629a52b,56823524,84deb617,2f6a9694,2dc4243d,fd20fd16,d1f2798f,23e43be5,f88d5feb,1f6fecca,6fadd5c3,f5a63c37) +,S(7bbf7555,4c14bf1a,63ef9f38,ae3ec279,5cf0aa1f,335c816e,580bdeee,10d95ed2,d2e12648,81ba6d5e,e8cf389e,84e37ee1,7c178b8,dda63756,32d9330c,beeeac53) +,S(b2d3aee,d083787,eb4e14f,328640a3,c557724c,e06a62b9,17134ebd,fe576073,68cd90be,2df0fa6b,da2693b0,f18357b7,ea5205e,2a1f5fd7,5a1413b4,fd9ce0d6) +,S(dd10759e,86121fd,6296f171,57a90f2d,bc217238,53969f85,4a71461b,27df81be,713442b0,65546c39,1b71ef30,3bb6ebc0,659471be,fc165a3a,686aae0b,270f13c9) +,S(54229d57,3a274ca,6eda6194,62dce4b9,35ed143d,16e470f1,239f1045,6dd2de16,a6739dc0,916112b7,4fd6ab7a,134093fd,55541758,5b3fb39f,da647bc6,5cde08b3) +,S(141f3cdc,124460ea,15fc80fa,dbba8fce,d89c4426,74e9a3dc,55f74f69,66bb8ff,f0c8d7d4,dac4ba66,1768514f,c9bb9e2b,319645da,735e5be1,51790483,d7b477ac) +,S(e9795743,efacb0d0,4c91c74d,33837b61,8d08acc1,cc2603ac,f02b1610,16fd1363,9f1c8ab6,735f3161,811f710a,1b5703d6,aac65c23,35fc1af1,32ba005b,bbe66d7c) +,S(e5e8c40e,c6c9475d,d4cff6a9,c9db5cb3,f8202bf1,bf60ed41,3e213d6f,2c860797,a9570e76,482a8177,b1adf9a0,1a7716f4,b1e754ef,864d2deb,354a96dc,ea1decb) +,S(5292362e,a095d145,c002f027,be53a28e,d5244982,bcea97c,b56d9ab6,162f7ae9,e7f00a61,8e63664,4555170d,9f13420e,fe1849dd,641bbabd,d3648250,81934e37) +,S(a6772998,3d6a765a,67e9e3a7,45e7de0e,1e42f34e,46b7cdde,8ab20262,ad246822,53281b0b,bb45bbf6,a1e804e4,cb6f443,537b4bb,d551c9d0,8976d53c,1020407f) +,S(7ed3bc8a,8a68ea64,c9dd316f,48f012ed,229e5f9,1a294666,4546ef68,bb48959a,238e6696,a7cac135,ac551927,fef28c04,5bbf23ac,9d24ef52,3d69aaef,27312e69) +,S(96702aaf,a9e17a9b,5fa4fe87,d3b45633,b59779ba,57002679,63a3a5,7e7442c8,53deadec,73ed54d4,db98093f,9e269442,d9a4a955,f9b18878,8be2c410,84014a4) +,S(bd3e9c04,42a9b0db,b063aa20,b09e7e0b,4ea18ecc,55a5794e,14108aea,1ffdea66,b5e43b5,fd8cfa37,dfd49f34,1ef14b0b,c2cc571e,cf9f7511,f2f11e15,825a57dd) +,S(d95c6dde,f07abe75,215e14ba,e76a3be1,6dc514f1,7542a246,e48a2a35,108c0833,e49d6c1b,baaf6f7e,44fa7389,31767757,76d6756b,ce8353ab,ca6e648a,cd2e8fdd) +,S(86f7406,7a86227b,2f5414cd,12c9907a,b78464be,8a5c2284,7d8442ea,d585fe8a,53c73db9,3ebd3340,2856a7e3,d91d29e2,e9439a3d,c43120e2,1fb5bb04,384a8e68) +,S(bdd92d35,ba51344e,4deb6b77,126fde21,9e7030e6,5e1d96fd,4987f1ec,bc5ee6ca,a49915dc,b4f29eb5,af9d643a,6c6f581d,94a205de,3a8bf3f6,a26d294a,be11cebb) +,S(dd4b5fdd,3ca88300,74f19532,728a31e4,152be230,2e6ef55d,a6ef9209,fc70b65e,fed2978a,3cc4c8d8,2012cd5,7e06ea37,4ac5f802,a0032e8a,21d58239,860856bf) +,S(fab1a71f,f8a64cb5,14c94e0d,1c67fb23,70998570,ebbb0e25,9e09df03,e82aaeed,6208c3fe,3fd0d9c,640a1908,1a6a6db4,cdeaf7f2,ede4835d,46549734,c1c50035) +,S(4d6fcaff,167a869e,311e8dd3,f736230e,78634ebc,c4470b91,686018c,7b529509,e860a3b9,28927956,1cd132de,a1de3456,576c4cc6,138bb079,a166b9a6,79555751) +,S(502caf19,5004fb43,75b13ca5,16583e1b,3f60b32f,d9769832,b42423a,f7ec78c3,c0aadc3,36019a17,ebf7f2f0,5afc036e,e807df5a,c2869bcd,19c2aca0,1b5ccec8) +,S(35727dc6,ebe8f38b,1a84d201,2fb24a2e,9ddaedbc,63e8de82,e18de4a3,c4d021ac,8eaca26b,3b88adf2,d19d9d52,c84d83ff,89451750,6a77b4fa,fd717b07,4b414322) +,S(7ced897a,47b5b0d5,f4db6d9a,ecd9c5d,54b35789,91902324,6f270d7e,7ac4b377,1c6ce993,fb84c89,ef5dbdfe,68dad70d,ca39a4ce,29cbc658,d5332d1a,6f6cb157) +,S(60d1d74f,660a5f6d,bac1ee84,5aa43dd8,889c9e4c,6b0ce1ab,e9952ea2,7146972d,dc4291c7,db1dcde0,8e618261,b8d177aa,77b5b0f,2aa8f341,8afc9eeb,dbf068b) +,S(a8b28606,e7040dac,7941cca0,b9cec031,31db3f95,bee7d6a9,8d60c3a,1091f81c,3fbac401,61c81632,ac8655c6,d5c02744,7c836244,e228b9a5,bf5d799f,1fb810ea) +,S(6418a48d,2705a27d,5fe68188,58a61a21,4e4dd39e,4151aa89,9fc6d414,95f975c5,21abfd32,14d98ff7,5b154250,8480b32d,ea8c50c2,3400235b,be800520,1609c7a4) +,S(b46f6f80,c71cb354,3058372b,9ba5e6d5,2617728c,54c10cf6,6ead7ca1,de2700bc,2008111e,c4b86ec4,26bde7ab,f52bf201,10787bed,d7b2e922,e3a5a60f,e68a0f4e) +,S(a0ef81c3,c9f78950,41a8d90,69cc22e9,22bc0cac,4e61a030,495ddf48,eaa6dcfe,8617df0,b32975a1,6666f86c,136e8c99,c07ff948,ff8d8176,9d968544,aee5eaa8) +,S(c03cfcd4,21cc7095,5a3e10e4,a4ed12f0,d31abe86,506da6e9,c83cf6e1,df73d093,8d6f0b3,c0d6edf4,b5d2041a,94d13f89,91adbb03,22ba9f,a56b31cb,63d4400f) +,S(4085a2aa,95e4e8f,11b0e94e,2673c48d,d42506a1,81d93a19,b5f79d45,ab88b688,cc769f7d,f45cece,d3cddf9f,c75c4dc9,bb7018cb,f54986da,434128af,b26c0f28) +,S(a485186a,b21c4650,e9f7375b,2ba644db,f22e2db2,20933cce,2bf0ca7a,c404fcb,2d227efb,68649a60,bee9461e,9390ba02,eb133cb0,eb8388e3,f64d23a4,332ec903) +,S(9faa3103,b212c2ba,9a454898,fb451d17,c3632b7f,c9368452,3ddb88a,7599f14f,9dcb34ce,51f7c4db,7cebb0a2,1b50ff2a,d67c6bd9,7066e505,60132168,3be236e9) +,S(1bb9ddd4,804edffd,78d00b86,ccf6a07d,a798d91e,5d88f2a9,37575d96,81187564,6577e8f3,ac22184b,d46339b8,25a426cf,2dc8cc86,78767d87,999a8e63,5789dfe0) +,S(7b32d099,c78bb658,24868172,1b375689,b91f0650,45fe3d9c,8af4a331,2acfdf58,a4c92e67,f4bc53c5,aa84cef5,908a36ab,afcbaf66,a946d98d,4254271a,b4f088a5) +,S(daf23c72,c67145d5,e2a55109,f95742d9,28cc16da,e53d0453,c8dc22fe,a9eec7f4,205dac83,6614ebe2,a55c04a5,970d4ae5,a9ba4b1d,d8d51f52,50de622d,2a2a472a) +,S(6f156518,addc53c9,76a16944,a059a465,8c49f6c8,6ac4339e,82a2f69f,a3599279,50a277ea,6650fd6a,4a5e4c2e,fb09bfe2,78fe8fc2,c7a86089,b4bb0fa5,fa7262d8) +,S(17661b7b,5b5a8a4c,f700397a,1f819c7d,a6c44cf9,a7d28bcc,df6e7fdb,efe50580,dc1d7f84,841d8ee9,3a9f9fa4,6a03b2a8,365398c3,f94b57d6,77ad4238,264c7868) +,S(c3042389,1483fe1b,12f16146,f48ffe67,3a1ca3ea,ea330d54,db5f7c95,fbfce6b2,131d108c,14a4fda7,77d323f3,f717fdd0,a422acfd,20b9db1e,2b2c4039,a330ce3b) +,S(654da43f,70e4c85f,c9aa2d5a,12ce1a51,d4364a09,5c230ce4,f8ae61b3,cde7fa4c,f82cfe9d,bec57ffa,4109e9fc,c9d79135,49817f50,9fde8195,79190d38,f0afd2f2) +,S(c17be24f,d7d2535a,c4eb722b,bbc4444c,fa529cb1,283585c0,730813de,7219b481,2d35a0b2,27582d2c,b8155b92,680f6651,c0040508,ae3de034,cac87591,654c0c86) +,S(fcb1fa46,f8178153,fe5f10b8,a91a411b,cdc4cfc5,61b5eb2d,29446a79,8deb14fb,29c75252,4cb13054,2b9c1a26,b4606eae,6f40ba1a,f73d006f,5bac65e9,3821f0f0) +,S(7b86452,e43ae1f7,177c131d,999b5fa,a6e4a107,e0a06f6f,4305a8ff,d1ead9d8,3e7cd53b,b2f27d89,829e331b,8236f92e,fcf674c6,478846c2,c18307c6,e82691f5) +,S(8271b58b,67a27540,c1d8305a,840475f5,3faa0031,4e779e2b,9e578c07,366a342b,5cf145f8,6fdff832,6712be08,ca1f3a27,d3e58fc0,baee76f7,a052f7df,450dbed2) +,S(3f027c76,4ebf933b,50df3d37,77f60210,4b997d1d,4b9cee19,cb549c58,b5d0fa23,cb44dc89,c533abb3,e255fbd2,6dace4aa,836caf4b,2589113d,82ad1886,7eee5d80) +,S(fbeadb62,ffe218e5,d0245d5c,4bce7334,cbbfbe91,610e8bd9,f0b89953,bf472bf6,7e824c09,9727cd33,1aafba9c,6776815e,3f954fb,539efa5c,fc4ce034,db602c09) +,S(ee2807ab,44643652,12b021b0,dbe94618,5d22fae2,f500a740,127f4dfe,32ee4c60,d958ade6,cb9d3a,ae21602e,d25556b3,b3869202,beab0910,1a1d97e4,8e360e1) +,S(94ab159f,2448f865,f3d38d65,12273da4,ff476289,3dbf74d2,ef889807,81d6802,88739de5,da331b70,87c58bd0,d734bd75,5853753d,1d3b97fe,39c68555,8868576d) +,S(98d2e8e5,a41a0bf4,a880a510,b4b65321,7b9a62f0,c466c589,d0c1634f,557666cf,aa24bed8,a5cacda,bc3c950f,d56bbd1f,f156efb2,4632e073,ac822875,2617d1f6) +,S(64efcff2,76cda1b7,c8e5ab1b,12c73a48,5a25113,eb9a5be,496e52b,ec6ad16,ac29e2d7,18bbf63a,16003992,d85a9090,98ae89,834dcb24,293d6bf1,b8130e3a) +,S(6a8e3376,1636ef4d,b1116d54,34f3fa05,d8cde7e5,31b260ee,6aa9ee61,1c4cf5ed,5161b5ef,4bafa1af,f76a1e21,bdad444a,2526cf5c,c81636cc,36f18400,b8dc47af) +,S(4786ac32,6312dcbf,a1386ca8,c505715f,2bc7f85c,22b6049a,e4386bec,11648013,67c80d39,bfb6cc58,7fb312c3,8fea53cf,6937216e,8e7f3b3b,4a2290e,6d6df687) +,S(b87d2d08,ee206c18,646713e,8af6bfad,c77754c9,59158fac,c31928af,c66bf596,6110c98f,bafaffc1,7b40277c,17ad9650,15de7069,705019c6,b7a74cae,eec6e65b) +,S(ea9f310b,d088429e,236d565f,d1b3129c,7ca8573c,191d1893,c1c157d2,a0867d4e,61c95d39,c1893c68,fdc60ddb,27909f2d,98c9ddd6,efc67ccc,7482c0e4,3c05b144) +,S(abf862bb,9db85d51,5d6a37f5,5f3942b4,5404238e,d49d3124,59f9ab38,29b34ebb,30d13c26,2157c1f,1ffc8a46,a3679e65,35be1981,c202e7de,10de5386,db863739) +,S(80767b75,df3e69dd,757b4c4b,fd0b4be,f75fecc6,ae22b488,214b0035,a276e492,ceea1fbd,bcce30be,2d88b601,895a8fd2,92f61b61,cafa5589,f9eb9652,8a78fbce) +,S(8b7a47e7,dfc35093,77771622,482e45fc,84708ab2,c9c734d4,fdc9e8d2,499dd950,dbbd399a,d62e8309,14bd0ba6,19a9963b,8aacc765,cad19734,e2526af4,2b2013d4) +,S(13700ef1,f1e82cab,7e9a7d79,d76fcfb0,b6e8c18,ec1e6546,d27eb919,bd871f2c,97488000,f96aa2a1,5913502b,30ae5bd5,f9edc84a,f97dac7d,c79be68d,a0f7f4e0) +,S(51f9a79a,991fe61e,c5b7c93b,d0905bf1,2fea0e0c,bb9e9a7b,d5d99188,f42c8a16,a3ffae0e,92e3bde2,51c9a8c4,1a6d05ef,2fa2ed53,d7a21402,e759c102,65d96000) +,S(ec7c6892,644bcff,715b027b,be48936b,26dde18c,bb4a1a9c,fa1628ba,84d5b456,51bc2b69,b76646df,51644c28,8570bac5,d51a0e9d,6e9f0ce7,1abf6812,650b18bd) +,S(efb8249f,bed3299f,7715b3fa,b6a23bf2,86560ad3,72e31e6c,ec725522,227f5c2,f36f4624,59a7fced,3c621158,8eac73c5,54593c4e,b7c82fe7,b0951bfc,8987bba0) +,S(4efe94a4,c34083dd,49762ea,eaf58feb,72f6e283,9931b706,56427bc,e9913bd,5c8b9448,5c687c16,76605dc2,d414f37c,da98a562,c71e7e72,fb2b8d5e,6ae0d60d) +,S(ecc5864,fd6a1f7e,1e20a84c,d9dc7090,9775446e,2e0bf6cc,bf896bf7,97f9dd73,49eefb1,981d4b87,ff21ca80,5471770e,8e063541,58e9c1fd,9995718b,14d9d6f) +,S(133f3710,9bcf5655,48d03c90,b82d55de,cfae1cf8,a5f3e117,5eaee107,aa7eb121,1af96963,e9113d2c,588ab083,58df45cc,8b68312c,9aaed504,3f17fffa,b29bdd7f) +,S(a8b1b9f3,971667be,2a65072c,efe8b1e5,e64f652a,4758f51b,4888087d,4fb489b4,556d9a3e,c2861fdc,da258a1f,8c6e81d8,1df43669,e64e3daa,90dad4c7,c6c0b662) +,S(104889df,dd81534b,655921ae,5483db4b,b3227f2,fc3563fc,4af46e1e,2c4fa88c,a70984a0,ce97af36,b827aaa5,218a9743,73feb2e6,fd7e2a02,408590,47323ee1) +,S(4603c58f,4fbc4575,7e9e165f,8a4b41e6,b0d2bf09,b1124998,3881ecef,2a8852d7,37e5990d,7c50bed3,2b72a43a,2e6a0ac7,5676cc82,113e3196,d6569e21,3adcd0c) +,S(5d1ddb75,774d6419,9f07f578,21786ad5,9fd7119c,f895196f,deec090f,1240748e,519140b0,1b340a4,a7aa2864,fef5a066,feb59c6,3355c222,6805e45e,160bcd9d) +,S(c9f86104,62644b3a,ec4daa3e,bac656b9,de816cc3,a5aff1a3,633f90af,8401a97f,405087e8,80403629,516d485,f17590a,1277e058,840b3fac,4e02d3bd,7be92954) +,S(b774b1e9,9f42b296,dab0e371,6d4ee04f,8bd517e6,7846d0b3,3ef5e0f2,569e97ae,ec78bffc,d6cfa76e,513a2b4b,db638f73,519b570f,f423936,ec0a54f7,9ceb5f9) +,S(d7a1e238,ad3eddf5,29002e8e,87476ae3,6668d656,595b3d10,2486f1a5,c30e6a28,5c9fdd1b,e132b9eb,4d7b935c,2209e105,55cb28e6,c4616be5,7b248607,697ef6e2) +,S(832b146a,cd002cb8,199e800c,47b2a0cf,d96591e9,91f1b406,b2db981f,c0aff924,f64632de,b99254ce,9d60b026,76551e8c,e21b300c,86fa5bd,8bd7c32a,4a81a18c) +,S(635f97ae,1785487f,437fee89,9ec21d13,dd8228f2,e209637e,18c85ecd,6cf50202,b53fec65,1a1af1ab,2f51eaf8,8a3af104,e1a40e82,691da03d,9a179c6a,3b30e5f9) +,S(f882f983,99891dcb,d58b931d,c215ca05,a232aa9a,7cfe5acb,5226ebe4,f4a598de,3d0313cd,aa36668,5422a6e0,2dd7c560,11fef0ce,3c268a42,3509991a,97cb4562) +,S(5b16de8e,3f8b8670,a98099a5,250e3102,51107cd5,d04bb804,e2a7175f,48183594,33c3d3f9,e3099917,e707a429,3c83205,4a26cf2b,2a9e3118,fa64f441,e7561fcb) +,S(b47e085e,c7a7977c,be3e2329,ea417e98,e86eea9b,aa23fc93,67cc06db,cf06647,cf6f1cc3,f564879a,f9515604,4b7b856b,827335af,5cdcd55d,1f8bde5b,d3f539e5) +,S(afd1a856,e0624d6c,16a876c1,2f78ba44,303460f4,d3cc793b,5dd32a98,d8aca9b7,3b334e53,83301f24,df0e2df6,12cbd7fe,3e1b6650,d5355bb6,c9d3873d,f42d73b8) +,S(454316e,69f558ff,6e19057c,9c754b2b,83eab233,f696ccd1,b80bbb42,3c81ae57,ebbbce3d,4e1cf2a7,315a394d,d03bfb64,300ac0f5,11627d06,7a5341b,43a4ace9) +,S(a51f1d61,dc60b34c,65345205,b2a316ec,766560b9,c50d72a2,330f828a,ec978d05,d4e9b10a,58bfcc59,ef24379f,532784a7,ccc4c077,8aa11bd8,bf008846,44175faf) +,S(771329ba,3ae1f814,764fb9c9,ebe68f37,26b8260a,90d4e49a,7dfbfd30,80cc6128,128479e4,bbcd5b06,ddf46f49,614f6ae1,bb8914a0,7a0a5bc7,34b69b39,caf71b1d) +,S(aaa59016,d18bc9e6,2716bdb8,6d0c6bcc,e04f74f1,98f17675,c021d078,166c9fee,36cd35fd,53be5c17,84dec1ce,80ab3ff4,95abf363,17824a12,71cef620,2784f91) +,S(be187d0,b3afc0,bcbf98ec,bf31bfcb,f4121265,c4b815d6,9403d9ef,926cd254,a3aa0d55,8b5f6720,9d8a6514,fe22026e,66e8d972,912a6503,5faaecf0,ac2d9b25) +,S(228afb7,a9564fd3,641bd417,20a0e44c,d2ab5d99,844fa61e,264ca823,e197da88,24457982,391e3209,88cc44fe,e42cd242,80fe1f64,b87814b9,bb485d2,ed0d7757) +,S(dd55db40,e3333379,7b8ae013,297b477e,bca2f586,16f29300,6625aab4,6c367ee9,836a69d6,603fd34f,92d3f775,d25ce89d,b92d2803,48a21178,44f9273f,1a97a9e9) +,S(f82dfaf2,5113d8d5,728c53de,3b43f2b9,d2aac0f2,f90b762f,390f745d,7e10093a,1097ff80,ef2f5dc,88873c1,2b5acf0c,a8a803cb,ba3624d,4a036649,ffa07bcb) +,S(666f1006,57ebb1b,f05f50c1,2bfa7fe7,cdf11e0d,6cb37c99,4b39df89,acefc7e1,3e3ceb4b,eb292e5,3c00e4bf,ab6dd9d3,becfab1f,19880c3e,cbb93a4c,415f67a7) +,S(9769b542,3b098d8c,18871a53,8403ba2c,d32f556a,7ca7b089,ceb9134a,5d983e73,536e7c80,5c71c49,9d9acbed,c6fd94a8,3e64a2c,8afd8721,12f6848d,60851084) +,S(26081d34,3771ce6e,39ba59dd,2c2e15c2,4c6903eb,b6c157fd,b1c51dc4,e5343bf,82f6d675,39d04825,4cda5bea,e4879547,9570f86c,9ccbe1a2,ee0deb39,afcf5efb) +,S(feef7b4a,dbb0e287,a0762b14,445a8fae,b860e08b,19600b41,45d92447,be732bde,44e79fff,55aed478,f8d951e7,f4a327f6,c4a1e282,ce617a3b,5128f528,33851e5) +,S(ffb8488d,f26d306b,70b5b1be,4b6f2e4e,b6d6b2b,4cf05d3e,9502f3f9,81406cef,f2891496,f5affbf0,bc60c46e,b96baf7,2a4e6797,3297a28a,948adb92,1cfd5dcb) +,S(fd1ec3c1,736f2edc,5c080981,fdd99fca,9e301851,cbe8d840,38f03a6,59f21ea2,86755e0c,7b01dbff,ed701a7e,b5deb21,3566f331,d707888f,4f658879,cfbf3bf0) +,S(addbda08,d536486c,b9d0b4f1,5ffc9104,ff75be96,739d4641,a405e2c4,2775fa4d,4d70179e,1237e2d4,61a0a0b3,c3bf9df7,9483afcc,1b8fe02f,47d4b312,2f339089) +,S(fb5e9c09,8ff0520d,b162e57c,19b80ced,7c63ea68,1c7a2c56,2557a1ea,d2d7a46b,c4d9cfa0,d31cfac0,78c187dd,2ccea738,4667776f,b8eb0935,9330fab4,b9f67e2c) +,S(28c33364,1762626a,c9e4d2d0,53a1e5f0,771449e7,a0977f2c,63db4681,1c675b45,239e717,a76b80f6,2b11c6f2,c459d516,bf81dbb1,4dabba88,9f1e627b,5fcb525f) +,S(68e783ee,84fea44c,59c46bbb,170d7751,c47fb05b,602e9995,2469def7,cd061c9b,7054cae8,31dcb37f,ae8d8298,859b4e56,772f8a6c,d079918d,b49c7bbe,cde61f16) +,S(1526613f,fda17eea,1a7930da,c1be4a6a,4ddffaa5,1adf3c92,73f3a2da,44d69c46,c9c3d04c,996c4d40,b906bbcf,5b0ac89,f541ae4,81b7c5c1,8f9b5762,7b9796af) +,S(263e6099,2adc9f24,1cd1c16c,de291760,babe6e41,d4e3d064,f1a8768b,94bc5439,3ba3eade,1c5b8225,7559c0d7,97c47e5c,41f60195,463b2eac,74801439,b3a6663) +,S(ce58e7e0,73c871b2,673e18e3,c9ebbb8e,e6bbb2d6,226e3d0f,4bbe6bb6,73e72816,85ba41f4,13158058,fe8d068d,df70f97c,acd4f512,cdcded1d,ff9c3c39,eb1ce1f3) +,S(47c3eb29,1402d2d5,25a95ee6,fc54d1f9,721f29c1,e5b51cb9,d82d234b,94de6594,beb5da30,3383e0d1,4d13eca0,8eb8af0,14f8220a,81b1e8f6,47c1f95c,4503380e) +,S(8f5e8092,c71ce97e,af578fa,52f174d,ad0133f3,94bf2ca,ef5c7adb,bbb37ad,1ca41380,ac714a5d,3c6be070,117b10b2,dcff62d1,bef220e2,4063c971,89f6ffa5) +,S(edefd606,5883e90c,31215558,b05f297c,45c64fcd,34cb864e,3f0265e5,7e7d5a4,924502b3,1d0e8df2,2a54ae07,edf1b0bb,f2ad1df4,7de805a,43ae11ae,8cf3d628) +,S(31516a47,50773473,6e691ec4,e6891eef,601d6e42,d7f4ea4a,1e5008cb,b77e151e,7f243d73,6ec9d71c,d2047cd8,d97c159d,345003d8,72556e94,4f7aaa74,acb8562e) +,S(9049e0ee,149d379b,77963972,1027627f,5cf68f7a,9b1c81fd,189ae6dd,eea5c552,ecd60031,71dd9199,77ef92b4,262388a0,7aec9cbe,65d80882,1847a5b8,c758ad26) +,S(977ac11,98214ec6,eb92699c,aaa9c219,6246df82,85a6afd2,fbef31,a5a93b8c,27e01787,d6e29c74,f6308e21,24f9fa99,6a5b78b5,4f45fc95,b71430a,abfb964c) +,S(bd7ead55,e8ebc96e,5429f59,52427ca3,8dad3d9d,649676c5,52a01099,3c359a26,9e596b26,8c90186f,8cf38e1b,f47d6d6a,d7204c78,b557b3bd,25125bdd,c3ef7824) +,S(90c82d89,9178857e,e2563cdf,d822b872,2901b53d,3b93a6f9,2905a4a2,163be70d,3779d0d,c99fc814,8b2f58c9,fab70952,373365d6,1adb6e5d,9ac3f761,9f27e943) +,S(a312a0c,3111faf7,2cea8b7c,3e2786a1,65362caf,11919687,3368c77f,117ac42f,1b78c42e,af0e6219,ccbe3ed2,384f5529,dff57894,b9c82566,255fc4d0,fc798b6a) +,S(7cd723db,c046d3f4,5b0fa248,1197790f,688632b4,5f57569e,2f7754c0,9fc9bcca,eb5fb704,a5cc0b22,979bd64a,790f428,b57bcc79,3bde8fc4,4d6bc9b1,8c21e495) +,S(2b24dc16,59324483,3851815c,1675d051,60713a5,7dff00f8,9e72df7b,d1c7352a,ab05061c,224fb577,a72f5d2a,38a9e59d,18c52645,9564afca,a9539d0,c64c8fc6) +,S(955ffe05,c4653033,c2b4afa1,fcf8d3f1,3b55c9ba,80d67c37,598f6d87,97f11b1f,d3502a31,bb37b950,93b3e594,944d4bac,3314d490,d375e118,4e8c5a7f,2346e6a5) +,S(699392f3,c2baba31,1bfa8aea,180283c1,9036ea92,f287fc08,adb32fa,6785fefa,242acb3f,fcbce5f5,9dba097f,3d358862,11232403,2730700d,724488e,8bee3478) +,S(193d04f3,61eeec14,633c702a,f8e7eb22,2c3de17c,a0130e9b,cbfb3daa,94674d24,39b68a32,79e62533,8bfda780,9f0f8264,ed2ba2b5,ea9c0035,6459882a,a943e088) +,S(564387e1,ed778e70,baf9f876,2a0171a2,6a4e660a,bc6eaf1c,7ef9f00,69794817,7cf553f9,128d0716,e3c81039,3d1ca83f,1cf0fd82,7f7d4ff0,ff538637,34ef42cf) +,S(f0eba12f,b282171f,d20aef8e,192741e5,4469c5c7,bab13f51,7084d293,c3c294cf,bb0211fd,18229247,5238ba93,f6992d34,a41a7ae6,78750b04,fd34f3cf,af61f90e) +,S(a54b91bd,b09d29ab,f4cb354d,283c436f,a8e9cb20,d3a7fd35,e59f59c4,200bc13f,bae1af42,3459a852,bc16d45c,cd35fd94,c0033d89,5c86fdfc,f4fad5e6,3bec2cd2) +,S(a9294788,b2c9d997,18193553,403350af,78008113,ed58cbcf,a2816c80,46f75d47,dea8059,c24c1c84,44a0263b,2896725b,79c2c8a2,6d425479,f44bb7ad,225bed8f) +,S(b6967b59,ea3d2899,c14fd2,cdd4590e,68dce683,de275313,ec94d5d6,1bee65d1,67eb4a27,8813f69f,e5bbc586,15dcab17,11bca30,77327665,2fc333d0,52fd2a0c) +,S(ffc0f3fd,241ebede,ddb0c43a,a9b8fc2a,9e778963,1af8d54b,bf99c64,add0cd7f,203e3aec,321e40fd,414c002c,e5c6cf90,2f3e75d8,ae0e3604,61028ca1,e21da260) +,S(d8f86220,c390bcfc,f714ec3,8b6f6ee3,d37b41da,4026805d,6fbbc798,8a936ab2,7c0ad863,31ab776f,c22b2539,fd65086,2cfd2ba6,2f5d67a1,6eb957b1,8d812bf7) +,S(11295381,19a146b,442c3447,400b6e7e,9b2190ba,dd42a75e,24460ca6,45a3cb88,44950501,75662a98,793416c5,3c55febc,7babcd29,398d6099,23e1c3e1,92dac1ab) +,S(d7cf3779,236c4a8f,d592525,d30dc0a9,a3318c05,1823e0b0,43a6542d,f38d92d4,1f866df2,429a3dcf,1a285265,18308c25,262c1ea7,2aa2267c,39a315c6,dcd22ac) +,S(d2bb0f89,a0897404,25fc85ce,4d8fe24c,ca061808,e426b08f,ff49a525,137449b0,fc4c4bfa,2bf202e,4d10969a,2c4ca383,17a8c179,20dcb965,7de7aaa9,6b97ff33) +,S(832d95a0,cfb91494,5b43d9a0,4f037266,2ad4453d,353f6e78,47d4aefc,449dabc2,6ec0aabd,3c3981b,8ff55747,63bfb800,453f302a,8161de79,b6b623d9,253124f0) +,S(3a224983,f83c41d,33d3aa2a,c9d29ca9,55850388,a968407,664b2830,3967f25c,7cc31841,96c4fb8a,953602ec,3c79ac75,69e1fd1,7a263946,27826a88,7d651f79) +,S(81197d87,1452332c,2fb18793,c0ebeca,3d1b8a4c,f161b709,e3da21f,3917917b,56a0980d,1ed1f77,3c960de3,1ce4aad3,90a5ea76,fc410a2b,107ed82d,b8bdbef9) +,S(b8204012,c77ebdcf,790f48fc,4acb23f0,b03e5d40,6fdcf212,81545200,faa2b4b6,b8718e0,12ed5a02,16485561,8a5fb6c4,ee4db08e,dc9c1842,881287c7,dc7191b3) +,S(766d82f3,b602c418,d020596a,58e61400,20f58fd1,52448443,2f816dc4,8d437750,d17969a3,c71ea79a,3854b526,efd56f8,148b2d79,3ea3c76e,eb14ab7e,de5841d4) +,S(35fe7655,5d4c88c,dacad9ac,1bf125d9,924276c7,8c2ea9c6,a9c1ae87,52d1e323,9ce2d43,ef8fdb37,82a38d69,972229df,9b9c0c98,abad263,1df192f7,e0e75324) +,S(a29581d2,55efc206,4d1d1839,621daef2,ab049724,167ced73,7566f4cc,3a81f5ad,7eced1c0,575b6152,38db2928,964f7713,f65edd4d,c31a4b34,ae20b6a2,babaa8b1) +,S(d7787fd3,75473801,2370e71f,4d2575a5,b9f89e11,aee370ca,2660dff9,dc6a807e,2875ab09,bb1b2a7e,cc6cb39a,939e4a91,2ddb1dbd,5ca43ca7,93ac663,552ae91c) +,S(1fb6cf61,e8be4d39,b36578cd,8853da6a,1e62cc7f,29426838,a7ecf0a2,77395288,1c018114,2dfbefaa,6bfc2957,6b79c91b,16cf03d3,81285e2e,b74f71db,1986e43f) +,S(511e9c97,866e651b,c4e32e41,92f75019,42316ead,6a0cd78d,fa61e0f1,e76aab8a,2e8cd531,d55bb19e,886b86cf,f7105591,68a9507c,7d78d34b,9ec50f92,5485931f) +,S(74afe7a5,6387bd58,d5996a9a,9650730,44141ca3,1f5236e9,da977289,73c9d434,be7311c2,b4566819,12d13546,8ac1e26f,6113b960,3039c24c,5e77edcf,de452567) +,S(5b545191,25d5f8e,cfbae2ed,bb724782,d07ff380,10eca9a9,29ccc9c1,ecd0f04d,21126f87,a0cf1824,1040d707,4d37e8a3,f035471,63de669b,9f502fd8,92322dfb) +,S(5286fb50,1a525e82,a944d1ba,eab49572,52d86693,19af1367,eaa8d5c3,e73ee8d9,f2abec43,68f3800b,30da81de,5b81e564,f94942a4,9409bcb,a9faffd2,51daa0ec) +,S(7b01eb86,c102438,4be1f023,90a5ed7d,beea652d,cf3ef77f,92fd883c,f2993069,becae52a,915d1393,15435d9d,edb72e2f,fb9bda33,4b2e39ed,6e698344,9e1ef819) +,S(3955e911,874fd6d6,74e04ed1,ea3b43a4,486a0ac4,19735114,3b451c3b,3028a674,3552c619,a845adea,64951c82,75994959,8609a3d,2f691d0d,5947b474,4636e06c) +,S(b67801c6,d96aca89,22d8e7a9,96e95729,c4c29d63,180e4f73,dcf013f1,98eb0d29,876e3361,d82f58f3,f1292315,1509ed62,2e2a73af,d063466d,4af5cf1c,1ffbb150) +,S(1efe4004,1c7ddbba,1aade160,cec007e9,8abfcba4,7d292839,4598b5c0,1b763b10,d9f00f5e,d0868390,230168e7,c5839be7,cef8ebe0,b3b70d73,ebd92931,678dadac) +,S(2083d5be,389e4bd0,23f7685f,2ad00b23,e3687672,72183afb,d5d02384,36d122fb,11b6176c,c7554617,935304d0,4e12e8a7,4bacc20d,d438bf77,a1729a15,b424937e) +,S(8a9420d3,93ff0ba0,25bcbb4f,eaaf715e,4ab14281,85b2dd91,f8eede56,f3006e46,f48edd10,dff93031,2b5df63d,ec9c7a2f,ca373d77,65033de3,8a54d37b,2ab1f4c8) +,S(64a2e8bf,b42de0b4,b2dc8fd5,9e3b2c18,753b43dc,e914fbc1,478818f8,145891c5,82583660,40ebc62f,d5526ecb,9f952091,47f7048a,4004a0a4,7b08905,12ac098) +,S(eb97193,28c44e0a,3f2568bc,b99815a7,c5c2e7b7,90e7fcb5,a2e7f7d9,920404f,cfd26c16,e6709873,1219fdc4,aa8ed998,c6fef955,78d7908c,c72c04a4,4bcf305) +,S(cea3219c,e03a2433,f9ad8d93,73a6bef6,c1f30b3f,fa79d7cc,6ced36be,9abc9c03,13ea8ed6,a0dd8fa3,29bd7563,a34f3499,6442b03a,f2eb703b,d8d5228c,cc4c4e7f) +,S(2e1675b4,f00a0843,89b0587b,f0cb723e,1a833539,c024caed,36101cb2,bc4c4774,ec1d76d2,2752a662,5dafb3c9,6235eb94,f9af1286,2b3eff6d,2a0fb965,ad3173c7) +,S(b0eb3277,7c8d1b09,e22c9b9f,1c37e8ab,74be3c49,7ab6d73e,7fb6ec11,10602438,6d44054e,a4cb4a22,3811bbf6,6d2ab2dc,f7263d7d,6421a368,9a9ca4f,97fac66) +,S(48254bd4,8df24e2a,759c5ef9,cee30855,1c1f79da,b0a32695,2196ea1f,987b6d70,9c12a458,f39f4880,ff04b96c,72b8877f,b4ad0020,495626f4,1d9b32a8,84f7a36) +,S(e3c6dc6,cfd0b94a,57b3d34b,3a77f4f4,45328a12,764e4619,efef75f9,f49fe8e9,5c229420,500f2fa2,888d834f,a517188a,207d8f88,c98b7b7d,31484a49,c4d43a31) +,S(a8d9d9cd,def3362c,b260ad0f,3de51aa5,db066c74,4166d9ac,57db782f,656be9e4,bc696df,80eaccdd,bccc9ac8,960325bf,1a0e9aa6,100908b3,cd0c0ce3,43205db2) +,S(38281034,a34cd153,34b6fdc3,26fdc558,555147cb,534a1c31,89beec74,5a2eca97,f4371a13,a65de538,f31ecc5b,50ce4b92,d5dc5645,9e523851,f6fcdac6,5994b5e0) +,S(b745114b,449f0d7a,4521d7e6,728c89ff,54131e6d,8add9f3b,bf18edff,bebc6ca1,18678d66,781a9120,ba33e01c,ee3fb1ac,b7790f18,b30a651a,99b913c,e621eb67) +,S(5987629f,9c26a8cf,ff39955c,3144f4ab,c4d094c8,8270f3de,620fcdaf,93a7fa9,a554b7be,24e49819,f1256c9e,72b8d981,2aa5984a,c942bd81,5709ee03,67894a07) +,S(8fc9dd0,d84cf297,75ece75e,8cfd7c38,dc9f602a,b0152b01,982be4a1,f29b7290,ed128f96,2cf60503,7acdf6d5,9578ca8,9a232a0c,c432364f,2b661ac9,2a3176b5) +,S(c8b5b1af,90d64379,f2c02ac9,51ff715b,2978ef0,bc87f721,3edfd09,983ecc35,c295c0d4,964ef85a,59490ae,dbfd98bb,f6096217,d7633f0,44470b6c,a1816b55) +,S(b4eabf60,c44d78fc,298b2c90,6cdcf7da,a23d095d,867fd304,513f90c5,437775c5,82d906a1,2d10d6d8,e4c843b5,48ab645b,e6f32104,f07d8fd8,c128351b,e7b526bd) +,S(b19350e8,a5163076,bba0b2e7,2159865f,59a8ea83,b0154fb7,64308bc7,4d0bcfa5,29e4ca7a,554269c3,21a12b37,a4fd0fb2,d3e57ed5,4e79423d,f715bd2,ecda9907) +,S(fecf1ff7,663c7921,40f4deac,ced92484,8c66bec6,f4a5550d,c340896c,5543b886,b2621f65,d52538e2,92a50808,9008efa0,8f530fd9,a321bf30,6dd24f26,c9a1208d) +,S(ab70fe2,355d6d6b,5c5a3f5,a6bdb605,86372165,b8f07d2b,ccfd61f4,798dcb7,7adfb6d3,dd44adff,87ce3727,efef0bc,6fdf9f49,44fbd238,822974d6,dd57e8ea) +,S(5ae5d60a,efd1dae2,43df9d7e,ca025c3f,452b6c62,216c1c1e,8b315ceb,b94769b,d90d73b9,6e33cbe3,6d96c45,656f098b,e7e57d25,dd03be95,8b9cb2a1,d00bb434) +,S(fc51f965,bf8dbdde,b5fa4af8,7abee8a9,a380918d,4d8524e6,73f8501a,291eb96b,ceebbb7e,35eda612,47ad8c8a,5d54af8c,9dbc9bd1,194ba5a9,5844fae4,b658496f) +,S(368b51e3,778f8ddc,2d09e9b7,fc2808c8,ac793edd,244fe177,fe3229a,e5a6d919,5b3ff9e5,af4c6ae0,575b553c,c0ce17cf,fc4da66e,e19fc3f6,2d047007,e1716db) +,S(ac9c4efa,5f63ca07,35fafa0e,9612b459,1a764955,d435c14f,91717e42,26ec0186,5d4d3ebf,9a064670,e09f1d48,79bc9e3e,22198188,5610731,29aa403e,73d7777a) +,S(2b5f951f,360dbecb,9eb1d31d,b414aa13,9d9a7d7c,ed952a72,c0f93a61,d52fbc08,8d46f1b9,cb8883e4,cb504715,eae4326f,11187e46,de477dec,2108ccbc,2b3ddd35) +,S(25a3593f,9670924a,a35c2008,bd8278a9,a78d22d6,572841c,98c4399e,26f67cfa,3b07ab0b,8d400f1,af88561d,af8bb7c6,a6e4b7c6,a8bf5915,4cd85291,66ecd965) +,S(3f03be51,b35e265d,d9cb974c,4ac021d9,d22b2291,40016bb4,e9edf52,36193eca,a17df05d,e4b0e5bf,c7ecac3e,e3253017,cc1d47b2,9fd3d1d5,411f2660,c34932f9) +,S(edbe9bd6,f16782a5,a00d7003,488b9291,faa4f22c,9602c736,a3698587,995d25d,64569751,212d2f6e,c2e7a6a8,973be7fb,c49d7a0c,8857fe76,f9c48011,735179ed) +,S(1f477d33,1fb16ac7,45c29e48,77df8c17,83f69e85,5a111a30,e4717fc8,ebf85377,64c947cf,64a66ad,8a417bae,1bbc1cff,56826349,e024d3bc,bc4a9078,f4bda708) +,S(b8ef8b11,901602cc,9fd1559f,c4bd6bdb,22f9bb7d,8b289c6b,fdae85c3,e9aa3e9a,60b3594a,7349c920,33d816fb,295f41b2,7c4d1d86,b4c9d2e2,2cc3f4f,e603f582) +,S(eb6b31eb,198741f7,49e4b69f,85c23e4b,58e3223b,df8537cf,60a94411,f03e0071,576746c8,ba579896,969c228d,67a57cd8,8501e27c,773a3444,35b7e860,bec9f471) +,S(47193aec,aeae207,ad675228,f4506db8,40a316a2,6cdb328c,2af6c24b,bd5e9a8b,dc67bbbd,ca7cfeb5,981571f5,7022986a,4ec3e408,b641c34a,57b7cfd5,5139a1ad) +,S(ae3c9591,c2768a02,f99b0076,9c56fdf3,1a98fae,1eca3680,38698abb,1d44f961,ba9b0c42,90c2fb0a,ad84754b,e1c3fa0d,7e34f737,f3874af0,4ed2824a,46efdb24) +,S(178ef542,8c4cc38f,f088c383,71f0ead1,4e7b4423,6d90bc7e,9ffc3db2,fdbe9b9d,a5f01afd,74aa9324,b10f6041,27ccae19,24da7b23,72269ef,ab984fe6,ba1b347b) +,S(2df7e5c1,3d0fdda3,3ef8f69b,f0ebe1d0,8649b106,8c965d97,37a7e9b3,c13f4c92,eddbf5c6,324853c3,7d478864,a68d0b40,2c28ac46,295c00c2,2359e10d,d0693d94) +,S(671abd13,fe274da6,a5cb6119,f33fc88e,37ee1b75,59adf215,e08fcead,ee946b8,49d7cd3f,3b8162f4,a85787c6,91bc29fd,69eaccb7,1354bbc2,8ba17227,8a8689fc) +,S(b69fbdbe,e72b1418,6fab59f0,6b57d940,fb8cb5cd,92c53727,a0eed42e,532ed39e,71f488d2,e104d21f,c816631e,d774a714,94c0c609,c86ee052,210113d,672ea302) +,S(1d5b8e6a,25fcc50e,a4a5429b,6233e276,47d978d1,28a5f495,a66b1b12,d7cd8714,8428efab,d2bd23c3,2de8da3b,cb630ee7,ebe84541,ec3eff60,645ec4fa,3978a6) +,S(4844a10e,ffce265b,1a5338e6,a10c4f18,b95b0681,bd702e30,9a376e23,7fcefa22,9018e1d0,34bf225,b4826e42,565a76d9,43c868c3,168d74b9,33b34596,98b5192b) +,S(9567ea6e,231a9c9c,3ea5bd83,59b7340c,dff96e3f,d1fa7a5b,c56c88a1,a57d951c,507e21e0,cc59bab1,f2c38cb3,42b9f83b,f291992,a0c83edb,4cb62b49,6c54759b) +,S(60f2f714,71258f56,6de74774,eda196e,46a30d66,3dc0b308,1cbad662,72f07bcc,12588be3,f62dd2c8,1e485efc,76c754d2,de642f53,d3937c68,f058c61b,ed7b6c22) +,S(4276ad32,b33ba53,ef2ab0af,9fc42af6,6c7bb23d,c7b7a9df,9c00e1dd,f76b6283,9c477729,c61fccfc,a2dc0c3,c3a9ac89,b98f437f,bb221be1,268a6f17,5d0dcd9b) +,S(fa3ec157,f8186c36,3419d818,4473745b,fdd2d054,e0c16e1e,fccd514e,95c9336,a7864a68,91aec12c,fe8104a0,eb3cbec4,4a907380,11a3acbb,d5fb6680,289cfa2a) +,S(7d7d2728,b1db5fdc,38ad6a75,3f39df22,88d50838,b106475e,28ba6eb7,5248b600,25d9d454,8b505739,16ec7bcc,877f6aef,e2641eee,8f78f1b1,a7f74c11,40173e1c) +,S(8cb9cc7e,4ec87013,b6994670,aae06b1a,a4785c06,614ca24d,cb6534,6592ffb9,728c4a8b,36bf36b2,a0bedad9,144c3261,71df8448,e87d151b,d8bee067,769113c1) +,S(8a9aadfc,84aa81d4,46442635,d47a9a4e,988e64de,6fe8836,79b8de44,f57c0169,60f39bce,be18abd,10afefa0,2d076d49,73d9615,10017a1f,469eab8a,c15eab60) +,S(3ea01e46,3a9bfcfa,39125216,7b6ce771,5fb309e4,37d495b7,852be3c1,af2a0b5f,2b756a06,75da2633,b8d2650a,a2102738,d5918420,9c57dd64,7b4c6c2c,c5250252) +,S(a0683395,c5245bdc,24b2b275,e8c2a196,5068fda,253343f7,49ab56e8,93672c4c,7f25a7ca,92d25547,975ddfab,fe50c247,6b4855cb,8f9ec4b8,ecbe9271,779431ea) +,S(b8293e68,1e33b654,7d2902ce,3addaeed,2fcc021a,cf7ee396,9be12661,b2abfb5e,7943e6b6,fd0c90fa,824b1e8d,25d63a1b,c01f16fd,3c9e2254,e1dc35fe,416a5afb) +,S(412722e8,ba1809cf,2df25d5a,49c7648d,b19e42c7,3cc30b7e,1107ee4b,f0aabaa1,557a299c,38ef6a75,61d79a10,ea052a52,818ce67e,1b341c1a,d70b984e,8e41fa39) +,S(7a62c6fa,f4a1f6fe,4a45aa48,a854a16d,a2fb19a1,a5647e3e,28a35d0f,619b2844,dab31641,6241ad42,3e7ee774,acb52a96,26b4b6ca,a4ea0b4a,67a513fd,9637dfd4) +,S(c3915b0c,19df99,ac0ef05,3a07b36d,62643630,201073b2,8e3ec588,6714a695,8f21f136,3cb4ff42,a52f74b4,b10f1dc3,5bcd782d,b477ecf6,38866d79,541de3bf) +,S(2a373fd3,ddd12547,3e30efe2,5533316f,355dd52a,6854d7f4,8144d19b,648f4b59,2ba90aa0,b3de3887,c1ba231f,49b28294,677adcb3,2e81c2f0,3c563e0d,221260a3) +,S(d8729e12,46cc8a52,a5c9b7ee,dcdf4d3b,3d0ff8aa,6efafdc5,ddf37480,2dda4476,1966d7a8,7e527a7a,bc1e829f,90e4e3e8,f4a7df30,48f098c0,df8a5eb0,2a8bc40) +,S(ce45fb7d,2ccb83af,dd1662e0,3ffec83b,5173dd2e,448eaa87,edc980f9,10a20dfa,5973238,531c5a84,1388c656,3d4f3579,41283e31,44d84ea3,31374d8d,e2122244) +,S(230a69,f0fff585,a1163702,4b16481f,65bf27a5,3ad7992d,47ec8ff5,edfe073e,61ae3fbd,90f157ba,6332de25,a571777c,30d8144b,e12d9a25,42bc1877,1b6abedd) +,S(d7f91496,1bdd4fe4,7b538429,df2bee94,cc4d66d9,270da392,a85e8c62,1527700b,67ee9184,bb2cb2b,9671aaec,57634814,b6a1a9f5,dd0430e6,6c5e2774,5afa9f13) +,S(4f2e459b,3eac7349,41cb81d9,2d8b3942,ee7b0ded,b2d9d8c1,90ff390c,aff7e4c3,4188f6be,c3526afa,2b29f953,f5044bf3,8e583c27,395c9f8c,979ff539,b4198e17) +,S(8a4a7b6c,3b598e42,851b0913,209a95fd,edf0f8be,6f152b33,1dac61a2,6f9b6997,53c457a9,f8926415,63e85b0c,b39ac9ee,69b31c65,5e3bc200,d37d86ae,d4291997) +,S(a48f69c2,9dbbc922,78a5f8b4,4a2fa2be,f432a4d1,e6fcfda3,8ad60dbe,6d157990,f251873,152f4ec8,fe5fc88b,cdf28ae,acef895b,1d0f0ce4,44105e14,7ac0ff22) +,S(fc0ec54e,20f7e8b1,fed5cc89,d18a5004,b7aa55ba,7520dc18,c9cbd935,7c78eb4c,17374d8d,36116ef6,49b723af,62a48350,4bd47bd4,c17c7990,fb0e119b,47f21ba8) +,S(8203924d,9fc7e5d7,6e3c593,ad439d3f,8512c0fe,5c298163,c8caaa3d,f7b39755,a224b743,258a82ac,2dec871a,dca1dafc,2bfa8e33,b2217785,2b97e57,2e1344f7) +,S(c4f66a17,a595217d,58d5b5b5,da997a7c,79b870c0,f5fa9dde,e146fa5d,c21f9380,13bc8ef7,ce6f915e,fd7a3522,f5fb9c3b,ac603d0e,343d344c,74565eb9,e8e3c777) +,S(4341f0a1,efdd7d68,435f1998,559e43b7,7d1c6780,d3d3e7e6,212efd96,5b30cb47,1777a450,1a693970,c2bf759b,a253e716,b17cd5eb,9a247d47,cc382424,48ae90a1) +,S(865d8a50,ad3b8c21,f8ff0e92,8e853789,a607abe6,e155b04b,3b81d80,c97c29d4,2a506b83,c4166a1e,fdc32c2f,b2d027e4,837d9989,a82d08ee,a31a46c9,dc72b272) +,S(d8d95cfa,ac50b79f,3189093d,50b03b38,3b798532,3f01ba52,d76f033c,83c832e2,cddf6560,d9942228,5a3c0f18,58a7c27d,fd7b8bac,9b23477d,8677a1a3,c01a8454) +,S(d09fa59,8ae65883,60247b05,519aef86,2b1c5196,d38aed11,e8350fe0,5bfd6cd0,45f51a97,67445680,37b1bde9,86696834,6dfaca49,719c5174,a9f9eea2,92ed4ab8) +,S(e19796c9,c9b48a5e,59556b72,9d9b8073,71cd7267,812b044d,637aae50,d6d3d1d3,1b86acc0,d904a31a,b5637e18,872eb31d,32617930,2f3d6bb9,36016653,9f218d89) +,S(6a88899f,be0c3c82,96fd27f8,6f89283a,f83df13c,a273217c,fef69d8,b048afb8,68ba38cc,bee044a7,a026ada9,d51e8d49,97083dfd,f65bd483,a45eb58d,5cc774b0) +,S(e5082ab6,a112848f,9f5f3362,8be3e267,87e24cbc,6d5563c0,7addeed7,ee44662,c3c1727c,d0c09130,8323326d,210a68d3,68bcbf81,bb3814f,dcfe6631,d42968da) +,S(795f456f,5d0cc15c,72ea286c,c881d8a0,21294e05,cf80ef7f,4497caea,92235487,bea99154,424f54d1,e91322cc,c52d3a51,4627fb1b,2fe9062d,91d90177,20530ccd) +,S(6e9e5f96,8c233f4d,8d2bcb8f,25d9232b,f2230e9e,fbafc89c,dca17498,8d7909ba,3f8b0b0f,e60aaf3a,89f5de79,35f9979a,ac3f3fc6,fb161d3f,29ab2ad5,d50411e2) +,S(72ef1e88,89cb7f22,19b4a7ac,92d5678e,a04c898c,5b83128a,1f7fa8a1,63772f28,dffb88e5,3f348c29,411e4d47,3ccd7d41,8a0617a2,6a640a9c,4b03aa08,15ab10d3) +,S(4a91fcd4,32f6d2e7,ad20787d,749524b2,e3e1c348,31b41041,c311421c,1aff04f1,bcd9108e,6e8c6da6,a15156c5,5c9d60be,e4aecad3,b0756cd5,81b1eaf0,ad300b9f) +,S(5f5255d9,8c7465d6,63fb4507,ac985629,8a434d5d,429d5a9,7b645256,e2cebab2,7c38536c,31e7331a,362fc944,38510aed,bad4cf29,bf0e7cab,c995ac6c,1fec04ec) +,S(866b5f8d,a735ab93,e84f7811,a33f1604,40a51373,7b52e675,7f212c8d,65c9eb05,af2cfb6f,9e32f412,5f1c66ac,61393756,b8c6016f,9d45a58b,43e16c6,d3549be5) +,S(636aca,387e767f,4702fb3a,d7b50b4c,4b40fb78,2c8c44b3,a298051d,bb3a71f1,70e580b,6993c9ac,5a48c2f7,558773c1,f5c4ff3f,aa929635,a2a44e97,c0eacae9) +,S(31a28d8c,2205f5c5,75ddd861,df94bfa,5b6b6e38,83797d1c,7d4a487,5fcf7f7,a790eae6,788407dc,89df860a,9ac25011,8b8c65f5,f47e0bae,6aae95ee,2d733698) +,S(c7f36e08,bcea178f,7acb0b92,fdb32411,a028ce88,be5e3480,a47c2c88,891827c8,5c285010,4742764e,7df86e80,e6e2d975,472abeb1,bd5664d3,a994289c,112a9e9d) +,S(85a82c69,2a5e248f,42a3f0d3,e092840c,de52e31f,19a2a161,85b2ad10,6afd92d3,eeec281e,55c79f17,332c4ce0,7ac4edc4,a3d75e67,558b4b3e,4dc86532,6132155c) +,S(e67482d2,4c2e3a75,3c1fa968,bf120a4b,7883d00,950bb0bd,ef5472e0,dfb09287,f9801b51,e0450fcb,9e405ebf,cb535355,24db5e9,91bf1572,6f446aad,34ae4194) +,S(c6ba17e7,81fad656,c9c93e54,36409414,c58e2761,b0297b8e,1811dd68,62779f1a,92583a9c,515a096e,8691b384,4104419d,c4e86966,4da70b3,afcfceb4,b9d74c92) +,S(67cf02c5,a616b59a,ddd421dd,15812e95,f36e6d16,af501663,9e60dd4,a8706b24,7856ad72,8a5f0d18,bf4bc3d3,75468f85,7bbdb1c1,206fcbc4,7ae66b5,6ac91b29) +,S(72bb64a0,aa8c690e,7bb6ed99,847488b9,f37490cb,a7fa120e,a7b5df10,8fce4b61,6057c37e,198f6428,3b9481f0,53441e97,dc827cde,edc55410,5108fdba,a14d81bb) +,S(1b132067,209e179a,5b77977b,eb81aea1,c480b32d,81729c5,32d100df,310575cb,67482a94,b5ddae4f,cfd613eb,68680dd6,c8172553,18478bf,79b5c07a,b0cd817b) +,S(96f5f126,4b68fd7e,f633330e,f32951c0,3716b62,7d1f3368,703447,f9dbb5a0,941fa02f,c6262bcf,dccb1cdd,1637c9cf,719077c8,1b26e7e7,2bb8fe4a,4d530e19) +,S(95335907,9c15cfa4,a674ce65,113127f7,a1ce740a,ecceef55,da5ceed8,e4e56a51,57ee067a,5f506b14,5c1c20ad,6e5d6b11,9bca103a,60c2e6e3,b5049b4d,db15baa) +,S(72ca7d41,76c687b2,1125c290,e737075a,3281ce7d,76b72725,c7680956,e0463f23,1e6a85aa,246b0f1b,324365fd,19809840,242fef0e,6d658cae,cc84bbc3,ad56af44) +,S(d5376a10,2cf819b3,a439feec,b04d9fa3,c90d76c3,b9bb749f,bcd6aa26,39ed5ea,3659d2df,266a0ff9,c2854f6e,f5a5ab04,1c0d8547,77fd4f75,320e064c,c4d0a4da) +,S(664a26cf,a965b59d,10c05dd6,e0aa4e6b,c66f356f,bb61b699,113a83d9,e0a2b4ff,fd191a92,c88d577e,47e725eb,a3c38b3b,9074bc42,16c5d6b,4edb3af7,2c4e20f9) +,S(7729abf,ecf9ca40,e8867936,7fef2d84,29bd877a,56f36780,1e677273,8e8cba7e,d5cb7517,42c9de11,84dcbfb7,5c9e139b,a59b6255,b59c7ef8,539de55e,7a709d36) +,S(c6d5f50f,e8e784db,630bc589,b4df5810,a2001482,9ca1608a,cd3e3634,7bd8141,eedd06e7,95d063ef,3d1627f0,bc7ef37d,a4846580,61e472b8,89679d3c,d88ab294) +,S(baa60dda,3cf83a11,82dc2ef4,f79d362e,6b32304f,896d30a5,b363c639,56ec70d9,cc9e6274,75feba44,b93451d2,753e94a2,85315277,7674b3fb,c67490e5,3627043b) +,S(370243c0,92b957c4,74df755f,e0951321,49dd3669,1a89fa84,e43a0668,8ca235ff,bbe8ff04,6600f245,349fbf3b,1c8ff04d,8d51185,3e35d13b,30deba91,84383ba2) +,S(1182291,92b1e768,2abe56b1,9f90e41a,c882edb2,27b25559,ce4448cb,dd19ff06,24271274,e6156ea9,e3f82ba2,8a72d476,8509dfad,b985c200,244687d5,8a11c1be) +,S(dd134e0,e4fe672,38716aa4,edba1ad7,6879be6,8b5bb029,b32704b7,9edfb2b6,7aed5398,40cd7dd4,7e94c224,151627a5,62f6a519,2f0d0b5c,416e6f1e,5e8a337f) +,S(ab7e722f,458d3acb,ad28a29,2f90cd8f,c2e09b2a,2beff3f8,f08517dc,e673e3a3,522a2227,c724f9bf,1ae08d93,c4c6ffc2,f5434173,7fbfa502,d6e49b1c,2ec4c792) +,S(2fa16842,ebebd6fa,e6c67327,bd5fdcdc,7e985b1c,22dfe307,23a9e2dc,ec43df8d,f027937c,9624aaf1,ccbf7c58,66bdd9d4,5bbb279,c2a37813,9166b720,32030773) +,S(adf5e014,e1f18c38,fd1863cf,76a6dcfe,65827107,fbe0eb99,117a859b,c5268bc5,c9cb3584,728b1771,16985b28,f5259aa5,279e15a8,1c1cc6b9,2b9e5f8a,6206961d) +,S(d939322b,a9b2cff2,6a2b1c4b,5ffcd96d,822dde66,ad0aca31,c24a8260,c9fc6d26,162fb654,6118a68d,7fb88bdb,3e3ab784,9278a5eb,13a940e3,3228580a,2258c8f5) +,S(18fb2621,71f79e5f,46c0087c,ac8e55d9,66f29a49,e2c91363,58900787,3d7e3a6d,cac82dd2,4a0f75ee,adfe906e,ccafd36c,5b0c97d9,cb150fcf,d08b28cb,83787a05) +,S(b8c0ac07,5d009e4b,5ee44298,89864cf6,fd54092,df835ec2,6658c902,57b670d3,2dbc6d4b,6ff28cc1,14e1f34d,2b6cbe52,7ca7dead,24f84681,4407c4e,a0df0bdb) +,S(6477536e,43a3ba01,8988c8ba,753d732f,9ec061a3,49f7826e,2c426ae5,3f2232bc,ede465d7,6b7798de,832e5f68,512cf3c4,d17282a5,ef88725b,36d8af1,5c5d2679) +,S(55b052a6,52008a83,41135e55,ef7de2b1,33eca8b9,ea0c4800,ce4f8019,5f7067db,a823cc05,63efbc19,d47c2c92,5771497a,ef6377a3,8be0d23c,81a56f06,25c43e56) +,S(c86a02fd,becc3647,16c58f5d,f3f150da,6ba86499,2df09dd5,82b9653f,10cc9289,263d1b5e,eff52a27,1a9c46ee,8adf1194,1da9d3bf,e69f62b7,262099af,43d6fe3a) +,S(23c659e0,3a59381b,3d47beea,60f0244f,66af0596,5f903297,c53aeeaa,d143e90a,1c14650e,3aa16bd5,b67e6077,be307cac,2bd2cd39,b246d6f7,216d73dd,dacbaf64) +,S(2f6d8482,734aff4e,21094c39,2c5fe833,1c8f9756,4de252c2,f6f690ad,8b2fa9d,8b143db3,7e14b40,3fa98a74,a81adc79,c34f17ce,5c9e6f21,68770957,1eb639ae) +,S(6d58e265,d6b08c0b,b050ee18,5175a9ed,51b5c64f,d523ab35,ed1457d2,f9caf153,d0675517,eb71ed0c,4fbb86c6,a2b4a7df,259a7795,3293777f,3a87f620,2265edee) +,S(4af09f2f,69d7b9,6676f472,d7f2009b,f0bb6f0,986f502f,322afacb,7e9d570f,1f93342b,ddfe5896,52e8b64f,a348f333,5396012d,3e870885,5b31024,f14f8e7f) +,S(813e446f,87d923ab,ad8b8649,71b1ca39,d00217f8,232a71cc,d6346798,3a9a0e9b,8ce9f4b3,541a8029,f1476728,2bedf1f4,367ff257,60f2ccce,7b273b2c,dccff418) +,S(53c4fd57,ca0b1eb8,7f5ca0f2,3ecae8eb,c44e9c19,aee3477a,3ca8524e,dcdefaf7,b3db3613,aa916430,a3227d73,35bd0532,74c122b8,18e4ac52,858e513f,c3ab95a4) +,S(e0f8afc2,ec89411,d926355,2c33af71,328331dc,9c9452fe,b0665c39,ae90121f,13523c16,1a00784b,f15d2867,15cc05ec,227248ff,80082e73,ecb139e8,f229eb4e) +,S(fe3efcee,6b82a5b5,a8c9a51d,ccc11f01,ef8f1a7e,588ec4b,17ba1369,cc6bb80b,be17246a,4d8660ca,98d57f07,ddbabc29,650f9a89,9da60a53,d21c6c96,dfdee15e) +,S(8a5182ea,591089a5,11ba9f19,ce4fe062,31b7e2ce,ec4cf75e,5c11094b,9ddc8de5,73688cc,f13d97eb,19a86c2d,8b010406,1c69ca94,fc9ec90d,8ada10ae,37503600) +,S(2d95aecf,72501ef8,e20bc117,22dbcc09,38c552f8,f4e0596c,9974d62b,a99fc884,7d9c418e,e1745ac9,e8f5e4c3,9ada4400,e65acb22,d336bcc9,fa2cdbe9,97f7de88) +,S(7908e4f6,ede4d311,3dfaf114,9bf6e40f,e1f8e33d,72094448,5105a113,21d18b80,11d92d74,9b011e83,5e06d7e6,1103cbe,bf958d8d,bd47d0b0,1ac2ad22,2f7d275) +,S(2c6dc24a,687d8437,44baf725,c75e7524,c0e6571,f32817f4,40183b6e,cbaa9f95,9692bdaa,775b832b,48584ccf,713421e7,5074f1b7,ed5477f1,4335db2,7abf03bc) +,S(a019d9a0,4a9780c9,43dd65fb,b87534cb,ab7c0831,f845e724,d663578,ec7bc090,38de35e6,faa2a1ae,e0649333,898a6ca9,264dcdd5,ad9f289d,ef750110,9bc99d4d) +,S(ced934dd,5c15335d,d050af1d,a8295d2e,bd9b8272,58d689ac,f4a48d85,5ef8a0d9,bc0c9237,1ee7fe7b,69c7c100,e5258c9f,1d68b6dc,309736e4,e05718dc,3a49cb6b) +,S(65e5ffe6,502ea7a1,47fe9c98,9cc745a3,b5262bd3,888069c3,92d1d1f0,a08dbb83,c80ee080,84dc5e65,de8df271,c1132cab,b8be293b,69a390a6,fb3932e8,51ffaf38) +,S(f4466d47,2365b665,6d1947b0,6e67e393,4c0e4f3b,91d52ea6,1f4588f2,4d217655,17afe3f7,2d384ccd,9beb59c3,d64353ba,57713f03,b8644e3c,eef45db,c74ae84e) +,S(66a80bd8,ec0d08ef,3d9aca5b,4329198c,b949ce84,7933ef2a,10baac28,dc98cea,7457685c,600a707d,5fd5d527,9f309b9d,5b14e668,1656869d,b041ba77,97029537) +,S(240e3632,7c3f4c63,afdb84d0,8586bf90,9b359c8d,7012f9ff,aec81986,4c44d597,a701b76c,d369e013,7b627216,f75d0ec9,fa208b66,2d7075bb,a6b6d39c,6a1cbb30) +,S(137f0df8,cafdb26d,36e1b57,c427ce08,444516da,ad1ca806,9dd60e2f,2ee23f92,c2922219,9e4e7bf2,f9159138,13e68273,6bb6a998,6c015caa,43cd30a5,aec74a49) +,S(965fef87,a63bedda,fd4b2e35,e1d0baf9,17d5850b,1f6beca4,64d4fae1,997d3a41,5f19603,369108a5,c599ce56,22bbf02b,cf541867,a57cff2d,8b527148,30124ed3) +,S(1e2ca98e,519c60e6,cf7ff3c9,51cde109,209188e0,6c68f4dc,c22eacf1,34a4125e,edaf4c8d,8bb97032,89f9fb0d,d0023783,fd35e779,41773a00,fb4289cd,ef8411bb) +,S(e8e0e2f0,378595db,68f96e6a,882752bf,df039778,e261375a,47fd4394,2b68006d,75b42822,1e2fbf9c,42772d35,e4bf1e0e,8d3b1ad7,92ff25ca,a488b51d,4ef7186f) +,S(a405f5b0,28e89d81,79e7fa9c,2ebac86c,ffd20ade,60dc5226,cfe6c91e,5c2f6634,c27ea4e3,b0da9e58,665f507,84225107,7893d6cf,5225d5d8,a06f68d1,1d863550) +,S(bcbc3c77,7367168e,169f3fcf,dd2340cf,9e6af955,d6038a0c,b763f036,6f4564cd,c7c120cf,99138201,40ec5339,ec23f5c,1ac0dd73,c9f947dc,e19c034f,7e7a502d) +,S(fd569bd5,14843a2d,e86ab2c0,475e0c67,4959c04f,bc230255,db3e82d1,15cb0758,aea9c73b,bc083366,fc5e31fc,90a1da72,66a9c43a,9d16f6ee,67bd56b7,9c354cc9) +,S(c2fdf561,eca2e3b8,f1107475,9cc43b9a,789ef592,e8afe885,d88b9dba,469c616b,678f57fa,fb2e42fb,bd1482d1,e22c866e,683e4fa7,6c1d2714,6540610d,9cbd1360) +,S(50f20965,510b3317,2836e1e2,d6e00ea6,160a9c71,2aa30bbf,ac527c62,9d8f4088,fd9852c6,974c603,7e88bf45,a279b565,d1246924,e3c4a0f4,8877b716,69b68141) +,S(3f293417,1e371e20,cbe0a858,e5984175,ba465906,fd64a7e6,161c8a7e,5847764c,763e8dbe,571ac3dc,1e803f32,7e2f4585,7268774f,1a45c50,9390dfd4,96bd374b) +,S(8276d399,fe32e931,65f2ef6a,2f4198e7,944bb9a3,226b1a55,fff52dce,d2b92b3d,e955a591,5c496a1,623466be,88c45a3,f545527b,4edd4283,582c03f7,2a2d897b) +,S(e77e7701,f4b405c3,5c8b7a6e,ee7d0637,fa1f566f,d2a2cb64,531dbcc6,19a9e474,23fae4c0,7661e588,365ddde2,63b97f2,cca2023b,c70633a1,41a2eb,1d3799cb) +,S(7ae8112a,732d6428,25aa2eef,10298300,42939628,69e7eea9,3fbc7b3d,2c5210a2,3590e349,f878af6,7f7754f9,abf4ffdc,4d4f4442,48c1e039,6071271f,be5971ce) +,S(f9fe96f6,8e20a422,5b563483,c1d2389a,ebd8a97,b1b9accb,ed7bc51,8077771e,cf3802de,20b5ae42,b1d1db65,b033f2e3,602ca08d,972eed63,9234e1c1,48542478) +,S(b9c5eb6d,ab28292e,49a76b34,49cf903c,dfe79b85,f7797623,924a4295,bf0cd171,adc0a5d8,18926d8d,7bdc83fc,72b2ed11,19b87592,900ae961,ffbb165c,4d5bced1) +,S(b7e25a76,3f3b8bd6,1c57da51,bd90ab57,1df3fcab,28003104,30c44fa5,4a6a5765,c471aa74,babc3fb7,dc80138c,83940e42,961f80a3,23e9741c,c44607a8,258141d) +,S(5808e4f3,e01937f0,e9c887ff,8ea3a34f,8fca4d8d,7868a9d5,7de6d854,a0582d71,fee8cfef,2d78896,55dc9560,68e1a23a,4308a8f7,7962c2e4,f90b2ddc,87f011bd) +,S(92ac7dd9,8da0a4e6,60964943,3887974c,5ec4b32f,875c02ba,1163d06c,b424793b,857b2046,8104a986,a0030596,62039e60,71c8f950,b7f7f746,16fcacbf,b8eee5fa) +,S(5c38092f,fba5798d,48d0068d,d1037563,1f40a693,194584fb,7199c409,b85d52b2,32b1d628,15ee2555,f582f16d,d59c4658,67691e1b,389d1fe3,222b5444,294ab391) +,S(ad7beb62,cec8aa9a,b619693,eb40c477,53e22897,a0007693,f10ce664,21d5c15e,49f98176,a360297,42402a93,26e34a38,cc837278,3873b076,f887c811,e2bd98db) +,S(aa335f87,c61f2e9,7d87355e,2a1c2e51,f2a0ac92,1cfd3cb7,5189f256,386ef185,b39741b2,fc158d6a,435bfa8e,1a68eedf,13deab27,388032fa,fa22d649,c9c9a8a0) +,S(854ef509,24fa2fb4,9b7b7b49,44ad8c9d,87627883,60ce8bd9,36e64f12,a550356d,c5af2246,96c7e32c,a385f7e,3eb8326b,7d9e3537,43a95c8f,3010a160,1d6f534b) +,S(71b6366e,42a8e2c5,31ad6770,ff01481f,5a39c54a,d38e0ac6,f068117d,8d5c9d5c,d6684df5,92f085cd,aee8313,59bbceb0,1a357edf,b36f8e14,706245ef,f01db334) +,S(3a4d1869,55b698d0,5e760d75,8842bd1f,cd869e84,c2c29e44,4ca83bd0,3408d6b4,5ddd1b14,15ff793a,80fc196a,83ff2736,e9791418,fba7eb98,71b51269,170d9904) +,S(f596d242,7e51e5ce,403d673,cbdd71b,75550271,dd2d7d93,79883258,9d3c5739,cb9ef0ea,f6326a5f,83e40428,79675f81,188763b1,ec06fa26,3d7793cb,82b4ceb0) +,S(4bb25028,b5598090,15286b2a,a8858e52,227f3b11,9075077b,3083fe16,77efd4ef,cb63c7c6,9de6503a,d33ee35f,95d4533e,1e978f30,2762b478,e88d18aa,5c4ff098) +,S(77c7c018,4c89f974,df648e0d,ea57ee40,73acd63f,c6e22a55,6269ca4e,a5dc1c99,978faba,232a2b0a,9cf3de55,976ca950,ce3f197e,e774b2e0,d4bd1e5f,e65a1b41) +,S(834d038,926b1ff6,13dc9001,7d021bf4,5bae5,d3741460,db681332,61975c30,f5624b83,614f5e82,10190b34,9f966fde,cd4eeefb,e3e6b046,b3028d6c,3807b475) +,S(370045a0,a7f8a64c,a2b9c64e,85a07fe8,9a7f725b,2cdec8db,258b3d3a,d9cf379e,cbec192c,cfc58b62,6b89d6d3,9b4bf622,81e308b2,2aa3ddf,51d45561,37b1811c) +,S(61302164,6103ee82,1c3103d5,f4d2aba4,645816cf,a67d94d8,ca53dcc2,92ca36d2,935e3db4,5ee1789d,ed8f0ded,ac0430e2,7317f38a,87682850,9568feb8,15e20a1d) +,S(4d6868cd,4df5b1eb,8d27e045,ef04209b,c1dd0bd7,aa712937,8f7bc025,e569d90f,dc0079be,850ab0ab,ef9881ac,740140c6,958e12ad,edfcbd79,2f446d78,7157780a) +,S(43413ee9,a35c7c44,bc95369d,38d9e7ed,53175f17,6f9eb54,6df98540,93105549,9eaef64f,45b421d1,ee80731f,ed61f658,861feb4c,72b5b2b0,ec659825,63172f7b) +,S(1e728340,95183b28,a443e00d,6ae01921,75844d9b,ffb1c77f,c00d388a,80a6b76,d1931ac7,fccf26d3,a2ef72ec,e8c7ecef,c51ad264,ecca5748,7e9cfe5e,d798428c) +,S(7b5995f0,fb0b8246,c588e393,4499404,415f0d03,c9174317,6cb2f4ae,b06960c0,716c7849,b6963a9,f1a7998f,49cfac4c,42a329f8,77d7c8fe,5b35f958,ceb9c0eb) +,S(9c5efff9,2be6057,f5223d41,87fbafd1,a59c364b,239120a2,fa1c4596,4fdad960,4f4aa66e,e42548c9,4d6cafa0,81e59ce7,ab65cbd,78027de6,b1edaa,25e6d7dd) +,S(46970472,192c3690,3c7bd061,dee19fee,5f3a973b,a70430f3,581abae1,3a61e55d,4d232a77,62e04a36,c62894d3,41665ff9,ad8ba55d,353d52cf,44f392cf,7787922b) +,S(add62a3e,583dce2c,55e97257,b64c26bf,5e86b0db,92962b3f,a54e7c52,ac00b32e,3c700f82,c5365611,f3cb1ca9,cb6b0c2a,dda80e04,617142ef,eccfabee,178d3dae) +,S(526115b5,34b212fd,9836a98f,853ab3c1,24bb68bf,afc1d641,b47d08d7,39566c4f,29c983e6,2a4de19,4efa5b2a,9cd4971d,6a86c8e9,f535d599,ee04db95,120fdf4b) +,S(87908ac3,ee8f4e5f,31aa08c0,ac97e93b,81ac75fe,33bfbff0,7d4f0934,7c911f45,b756def7,52c71c51,3f69235e,8d515d6b,f3289a5,a579b999,a695a2f6,49586ba8) +,S(2d6e6ed5,d2ea8912,6797b396,8ac1b0e,f876904b,acbace80,a2613b35,d9bbdd11,b1b66613,50ee7a2b,d149ec9b,25a502a1,6ba6143d,32da00f3,13cc389a,7c0e480b) +,S(f076c9e9,8590180d,dfd36cd6,160c21fb,7dc60263,77435e74,30f74cc3,c46533f9,2c9decd8,6da7b49b,1b4d0a8f,47aaaf9d,19d9e8bb,365c383b,63726f64,ae56fb98) +,S(fb52489b,6d101de1,2f51720a,60a78207,84ab4dd8,39d05c9d,a3b9c349,a74452d6,f1a967ae,deb5329e,faac7381,f3f0bc76,9eb8cc89,78d5d56e,f382a17d,4c3baf4b) +,S(dc1e911,53b3435a,8f23cb08,a7b52f64,a5e2870c,9345896d,ab4ab880,9710241c,3468d632,eb3a51fe,133381ce,2b5dc9a1,64f8eb68,9c019b0b,7e48d504,50e85630) +,S(2d8c6759,6c7856d,b7062c63,2aaffbee,46779bdc,777f0be2,a64093d,41d4000,c7006eca,b64904f2,9cd7baaa,14a5226a,e5c4b3fa,68c62cf,65789066,2eb8e8ca) +,S(31e9d361,fa0041fd,bb73665f,2e1541f6,c41764e7,78023272,478cd7f8,e9552f06,62fdf441,4effb45c,5408a0dc,c0a78041,cbe39cac,562659c,ab8c2b89,1a940c11) +,S(792f50cf,66aa0f00,68bd7fb,ee12bf44,e1fa6662,41c43d2f,275a248c,29459830,633cf86a,a3f10f31,40aaffe1,d04ee094,aad1cc56,129149c3,2702c33e,40d91e3f) +,S(be4f52ab,8f6ad1f0,664e4d28,b67be76b,c3d318f3,9f455708,94060e03,2f8547b3,22ffbfca,44482e40,19ef36d9,209b4262,48d62591,7d81b6a1,57ad945a,1878b4c1) +,S(bb693c4f,7110d2d3,8bdcd6af,d8b29b43,80d003a7,d0f6420b,e8d02cec,3e7cf385,3bdfb9c3,948034e9,31904f13,e3dcfa78,13d3413f,5c2daebc,744bac87,9e4314b2) +,S(56e8a65d,2eb188d4,64dd4280,b987b5f9,8b92b8e4,34b6bb1d,1800fc4a,f8f2deb5,11cd5d14,63777189,f8c7d19a,c692461b,d21fa20f,f12d1976,3b915fa4,33006cbc) +,S(f09d5cee,514e56e5,9566953d,f8600a94,cbad003e,9c898261,5bb998f6,a5b8cbb4,d07ee0a9,a0e88f5d,6da3d918,d5f309ca,7234373b,d528cd8c,21ee9ca5,3d1bafd0) +,S(58671c9f,687ab0a6,f6b7c687,ef546765,7f29ecd9,d6250088,d588742,7b96fa6c,70355403,abefa39a,72d89348,9a8251c2,10d59df,80b4d284,f3f02246,f3f6c60c) +,S(e47ec1f,8a7169d2,9c05cb96,42ba126c,aff841f8,c2edfcf,25ec9303,772eea78,ce97644c,ca60474,4c269973,fdfbf169,bf0fa377,61737dd3,77692b9b,ac775c9d) +,S(ed95cc7a,a24a4ed4,1dfb019e,31abc80d,93ca5c04,b0515f2c,492e9105,efdb12cc,1602bbfa,f17e8c16,30ab470f,bd8fd829,b4a466ca,9f210904,7e0903c4,e012d789) +,S(b6fa3ced,a07a9cf4,db717242,9de8069,216a7b51,4145470d,d811755d,a2908a2e,64f695ae,7f19c7d1,17af6ca9,36dcb2df,8715ff96,c8134313,c111da69,7a354dfe) +,S(2e3047cb,4d210007,39b8d5ce,e4884a5f,ae969eef,898a600c,2202da33,239b3627,197f37c0,7c11943e,40328e3a,3c7c11d8,f2d77d16,84532631,53b7cbd7,69808c9d) +,S(df9c446,7a691cae,b8a01ec1,a4a8ebc,fbbacfc,ca347aa5,39d56853,c14ecd3e,acf9554e,906e86ba,8459c108,d49f7aa1,e1e4b2ee,9957101a,f16d43f7,7dfaf6aa) +,S(d452f3bb,2e3e54c4,1f68267b,f846f504,99f39f28,5edb86cd,68330ed9,510aff54,52c5d16b,41eb1029,7f86a30,28d1b610,6f6c5aad,61b63bd3,53d95b2b,fd214755) +,S(cc196d06,9ad60096,c4ba1057,fa4fcd9c,4a50b28b,78227074,22d531b9,dd85a5be,bd930456,14388283,b28cb67,758c792e,5f9d6c0e,2d4c1a86,745e0504,ec902b24) +,S(4974252f,9c246a45,1187b1b6,546cbf27,af9c21cc,d03c7b37,df7a604b,a3b6859c,276e69e5,b85e3241,33f9ec76,d628fee8,3af37bd8,def6e677,bba19739,9da14305) +,S(311548d2,d9f880a7,17e77608,8574ff4c,185cb0f0,a9660ef6,7a94d090,3e2fd845,82b2dfdc,2d0ca2e1,d403c1db,7593dc01,2043122a,fb50961e,d5f86174,18a3d7b7) +,S(30068568,4497d5d3,2c98d3ee,1136a9af,d5bbc79e,340528cc,4e0b3c55,74e867f4,57c141af,fd650050,79ea563b,e9ebb161,a7725bb8,e41e3c13,ec528b2d,df23430f) +,S(1c223f58,1f03b4fc,68024db4,876b743d,8a2b635f,988340f0,d22c389c,43d130a1,9d99aaea,d3bd3b1a,9891dae7,4a3dd857,3a86b643,6c623c00,6604b211,4e27c133) +,S(a675c89a,5d453821,429109cf,45cac77a,880e0e6,396a0b4f,16053ff9,eabfe4c1,8cda99bf,c3426739,c4888767,113b7f4c,9b321a61,1b63b4d1,2dd50a79,d80b90f7) +,S(e990a236,d7854ca7,3e40c661,93dbf3ab,74198351,1236988b,cca29eef,772b32c3,a3d42c05,851b8138,ef1bbb7b,41510bb6,fc893baa,928c98ac,91127b3b,a100aa12) +,S(2a6eff8,af4b8049,2c3d31ed,f6672d1c,d0b231d7,6deeb590,a8d0c4c0,83586027,2a7427d6,951e07fc,4d5cd4f3,ca8a3415,8f0d03c2,3cd2f250,541c0f11,8013a623) +,S(7dad1061,9c4a7bd5,1edf6813,daa8fb4a,2a9e494f,9835db8a,42f4b0ca,827df50a,3e3b2b7b,a44500d0,277b792c,8a529fb3,41667560,1c4e443c,9c2fb2e0,dd17f1ee) +,S(39d5b162,fd48725,1bb42303,b7b8887b,92180fa,ddbdfb7b,a14ef2e0,3cc32aa0,3a8bafa4,5645e4e9,bf4e0175,69fad346,210e65ea,fa92b971,413a2190,b64b6f09) +,S(f9ac329c,ba09d60b,5aa62bed,81e9ca15,7a3bc53d,acd83836,89742ef3,cfcfd795,9c2fff50,aad80c18,2e6593ae,796ada7a,e0a42a4,17ce77bd,ea7be927,161be4ff) +,S(19adeabb,6e9aea9c,fe245329,623b8bcb,3554eff3,999b0b0b,8e035450,14cd964f,c570d99,99e9c62d,a3321f3f,a548d43b,99f05df3,e17273cc,2a45a3d9,20654cf8) +,S(978f705b,eb9b6009,22285468,521eddae,e71f6521,1ae79567,3b122090,fd4eb3c3,8eaa7bc6,1ae92adb,506f9e32,c66f5457,4e1d929b,ef4953cd,a1cd3f8d,c98ff8ef) +,S(e29b57d8,f6808d6b,ec982a12,ac70afca,1c9c19ff,a7b0c724,4fcc5b0e,3dc2fcf1,f7d60b14,133721c3,471fd91a,864e576d,84e5a06e,b031b1fb,3a2947b2,a33b159b) +,S(72073aee,f39510e2,81cca2d9,7831e533,56cc6016,9462a9f0,45100dae,3443bca8,bd761539,177458ee,dff87628,d155c9a2,d6a00e26,51158def,6ce72c35,84d56a3c) +,S(c949cbc9,48db844d,2cd04810,433f982a,680b6a95,e3461ff2,108492f9,247fefb3,162ca70c,c9f19d2,d3da47b,3b0a2361,f5c21492,a12828ae,9c0ff9c7,ef1d7b20) +,S(9acb7d8c,e958f7e5,189676c3,e7248ad7,9f717a67,2d4c80b5,9c425663,e078810d,112dc86f,1b241c26,30d87412,2faad000,473bce32,95bd6989,8b6a4521,7773284a) +,S(e468a13c,e5ad4c24,4df9aaa5,e13987f9,50900b4,a32ba33f,430935c2,1250e4bf,61e3e755,a91bb2a5,3fc2ac70,bb232b2,c1aa356,d494656c,5df93232,a866e400) +,S(26779f67,75d8caf1,46638c17,71e33b02,b41c61df,325acbd4,506199c1,bea8310,e9de26b5,c076eb9,cf3436dd,d9bc7f8e,5772720a,a8401227,7af573eb,65a769) +,S(8c408da9,a816c7ba,ae2846ed,bd923211,926e5e5c,ad595a5f,f2dbb190,f48857a9,89373ca7,e9f3f96c,1f0bc7ee,d427dea,99808bd3,b943964e,f0db4bc4,a7a1256b) +,S(9ccbac95,d80bafbc,b7e699c,aaccea8d,3169db5e,328e1519,825a3f4b,adee6a19,5a8d6936,a2859d57,6accb35a,5e80c944,4d71612e,76cd755e,aa3465b0,dcad8aee) +,S(34c7b7ed,6fe88bc9,803567ae,71ea7c28,c9511f60,e2ebfa8,fffeba31,dbbce2d7,31a3bfbd,c42cffa6,c77aa417,955c671a,426497e6,b35efaee,83a58bf,84de02c8) +,S(7940ca7f,c3bc810b,5679456b,88a73cae,4b2abed8,47260052,ffcb33de,edef6155,8923cf73,9285b368,d32d690c,488d8b38,5d3285aa,c399fdf,6e263daf,4e0b35c5) +,S(2cb10da7,104ff7d8,d8f1742,43425c2c,5e8773ed,71e62e4d,cc0c2d4a,56ac3a08,610cb16f,53ddfd28,7a7ff301,a8047555,801c13b4,81033c94,4e145b1f,98458520) +,S(ced78e5e,58e2893c,3910bd9d,d43fc362,ce06dcea,f44c5aec,ca17eb0e,cdc1fc53,c66050cb,835c97cb,c08ae0df,242895c8,f0f0085d,85a020b5,122e041f,8fb09607) +,S(5e83a4f7,7c4cc672,a7a381f3,e527c8fb,331e8d75,f8578a85,39ae1007,51903f24,545cda31,25c29fca,b343c22f,824c86e8,89f2cd3c,d2a6f3b8,9e3308fa,2968b8fb) +,S(c62958f8,33217811,cb099492,fb8c13a4,5b3d04b8,12a0c1f1,68cac595,e7efcfa0,e179e98,1b92f1be,25c9f892,d6a71ef4,62f3e1c5,43127fe1,f2b711f1,bf61aba2) +,S(7eba00b2,f151282b,83c7fa9b,5df6d9a7,b764e7f,42ca29a9,2734859f,a2f0f016,9e3162bf,a619123e,8e87728d,da825814,4b760c2a,3d05fc2f,1fc25565,1d72a7cb) +,S(8f68c1f4,83ce557b,98d96444,4a2a7d2c,a05d8f25,e6f9f909,cb44b58d,a030cd90,30f15dc2,17e7ce70,a6fae901,70930130,8f7d8706,80c43840,765ee89a,5f864e00) +,S(393d5b72,a9bbc392,4f712195,51ba7f65,4bc4df18,cf93dcaa,bace126f,c4262b5b,976cf232,fe59a3eb,c6514242,19128395,2945cfb,f792e4c8,19248346,37f16e9c) +,S(e1648650,d0d4ca1e,8fac2522,cda2a042,bc93b879,2d6f870,29c6d888,a11312ca,4d919105,9ea261fd,9470ffb9,e60c703,6d21da3a,ce975880,39e1a820,c636f269) +,S(efc7519f,4676989a,a12d823e,8e49b1de,96397ca2,11fe729c,cf0fd67b,bc6d6a74,3f304e50,be6dc6f1,b7c79979,4ae38ff,ed11a253,778d0294,13a98547,e3b889d5) +,S(85726e3e,aa8f7016,1c3629c2,84b7a7ef,79259de0,84f8bbf6,9358f66d,a439133f,756800a8,11a472ec,a72604e4,c2eea080,94971b58,3738e7eb,2c817250,2595e47f) +,S(2e238f2f,de3c39e1,19119541,9eccde3e,b0c4fee3,e432fcf3,f58c4f77,4ba070b1,7ce6b671,c0c79a82,2fdcb88a,a10a8033,bcd0e1a9,2cfab941,d052c09e,4e5e4c81) +,S(9cdc6aac,41e79b7b,ae77a7b9,bc027e99,1d4f8c1c,2b4913a3,1eaaf1a0,9bd87f24,9d666c3c,3503b9ab,d609b074,743f8a3f,460c0122,ad7a0cc5,a22a6d17,9d948ba1) +,S(360dd1e4,608c9215,287936b6,97e5e819,390629a0,7bec616f,7fc713fc,5ef8ec3f,7628d770,5c744125,d5885c2b,de25693c,5afaf8a,3d5739a5,deeeb5e9,ac1c62da) +,S(8657fbee,524c5f5e,25aecdf7,7306c97b,78119e0a,5f155c4f,37918e87,12302d35,242172c2,f90ea26d,b1f7d2cd,dbb9af4d,78a1660a,32402a83,6e598c92,df9e999f) +,S(3ae7e8db,7b069528,acea3e0a,dc005d52,7ca9e1ca,dd3d3cdd,5564ea86,5e1a453,ac203ebf,98b7e46b,bcad5156,cc058857,f32a8d62,2114acc4,55cde626,591fc5c9) +,S(81bdb0a1,9852adc7,afcd9775,54143362,c7e724df,884f1a2e,796d88bd,1c1696cd,2f189af1,a90f9445,353d0549,4d5562f7,4a3d37cd,1362d92a,aefe0393,9b46ef0d) +,S(e95b0171,dd117d45,263141e6,95ceaa52,3498a8d9,d1f09ae6,855fad1c,5e5c3e8,dc8bf907,ea6a4824,9cf930b0,bad3e3a6,c179fda4,107a0812,76f02a9b,9c689416) +,S(20e3979,e95fb62e,ecfa4ff1,3aa3fd46,94b24ab,c814f560,ce180262,11b70bc8,c9d01545,50f1d7be,da471272,822522dd,d6924a98,f6331fd1,cf6837d7,db91da1f) +,S(e0405598,cda639ec,6c058a61,4c39d56,f71c43ea,693f9b86,c9df1bf9,e4fef30b,9df9b561,a7bb2ebd,67b67031,a92dda6e,12550d0f,5cc2368a,603ae64f,ed20ef3b) +,S(faea8667,646d1600,2dbbdfd8,74a59ddc,a2b8024,b2f7f6f0,f2c2036d,ab5c5e9,8112167f,ed386f1,d1e02307,de202bd2,363cd1f5,fefe0621,1c4564fe,eb0220a9) +,S(f01d6b90,18ab421d,d410404c,b8690720,65522bf8,5734008f,105cf385,a023a80f,eba29d0,f0c5408e,d681984d,c525982a,befccd9f,7ff01dd2,6da4999c,f3f6a295) +,S(5906b143,9b994465,c9f3d4fd,f7f09a4a,b9ae0864,262b0140,def21014,8b097533,2917b92b,d0368fff,6e6a98d9,18cfeda4,d039c73,a3cb865a,5d77abff,9fe7970b) +,S(d6443bcf,53ba252e,925f5ae3,5d508732,a3289059,308fa67c,7b051ed9,66b6cc92,e0155fa0,366a2d1c,af8d2c17,a4ad9cf7,f4fc0102,f1e1ec13,7f1b2b51,1af0e7dc) +,S(b95a72a1,dbcfa0eb,ed2200ad,b57d71f0,b96a9703,8bd3cba5,78eff5f4,e9454196,f89c7cd9,783a4c34,1bdd05d8,241ec4eb,d8815463,4d05cc84,d5601f4a,6f3fac0d) +,S(50b287b4,d8b41f03,88804ae2,2b56abc7,be632cb8,a20629b5,3a00fd3d,9a879b6,67c3bbfa,4d8307c0,bd32106,57f5c0b4,78bc070e,53a3024e,1ffe103e,e5397076) +,S(64feb83a,5a81f6d8,8218e2a0,4e6f97b4,6efb89a,6f394264,d905c93a,cb7e5493,3fa224d4,eda77580,4d6ba88e,63df4c3b,5d9fab1e,519eca92,1ada5f44,741d5035) +,S(9434b5f9,2d63c2c,c90ee2fd,b7f7289f,b6277c69,3076d73e,cc38b032,bc8b5cd6,c940b3a6,4c04e6b7,1de7f727,d6fc0883,29443276,6d2ccd51,6d24dc22,3998aee9) +,S(a6db8e98,6d1bda8,995015e4,807b900d,704f8d3b,8ac5fc49,aa16bc61,82390724,3277c29e,bf27d0b5,ef8af507,5e295f23,92c41f29,3803a8b1,6ce601eb,2abedbd0) +,S(50733cc1,dd80ddbd,b254ea6f,14d0679c,6839e6b1,73aa0bc0,9d0ef5bb,bc5c2f9c,246e1742,a5a9172a,ed4e1e0a,9c0d623a,5233334e,47bcb68a,aec41101,92771eaa) +,S(4252122d,5a89f621,2c7b0a99,5ebfa8c3,b980e142,f7a89e07,d4788d91,1163ad99,bc63b87b,fda041bd,f9ac11c,e2e8ab3d,a1368cd0,2e276b55,6419e0ee,3d7fe284) +,S(6bc86411,d3f9d25,bad0a922,21f0146c,9173cc99,d00470ba,a41897fe,b5678f5,e2c1cd75,3915e977,c20d4508,1af1946b,1d8c5926,cca74ab5,c4ec0bd7,921c4cda) +,S(c786df9c,6b2e656d,a30146cb,14da5372,64683e46,5569b1dc,df4c1541,580d40a0,b8d229d1,d8773d5,dedde14a,dcf8816e,acaa274a,1f4ebd01,2086159d,1feb32f) +,S(f42032f7,dc6dc676,5b1a9453,74ee45f8,486e9b94,6a57e651,7dfefb0f,9ea3164c,ad2d7a22,e477f5ce,ad0fbcc1,fe2c2533,78920fd6,cd9ed4ec,1095fa88,2189131a) +,S(3c2fb5d9,a5bc7ad2,d4ce0970,5090a5fe,ef54a6ad,7f8d827b,2ce51785,b29ba5f3,3ec2d878,a4d836c1,71f68648,f8cac869,472847f3,4c267139,5f38e0b5,e96b653d) +,S(b182d837,dbb1e47c,bdbe559e,f30f03e9,ae1efc93,a5a165e3,10285bfd,ffe47303,c40cbcdb,d7f1fd56,c486a35,67420a7f,e4ed4ca8,43a68bdc,81eccbdd,213d7c5e) +,S(75a35130,cea9cec2,81792d7f,ffe84375,a4aec378,57496122,9a77270b,43b12391,988821ee,b6ee31c9,8201a90e,853c4afb,8e330592,6349d405,90c4840d,fdf3fb5c) +,S(a97b9c85,97362b4b,aab43b64,db7e5e0f,3e4cfea9,82939289,e5266f09,87fc8503,ccb75937,fd647eb6,7da4aa7b,72e8d873,c9f035a5,cfa120fd,4d4881f0,9924d8a7) +,S(d129bad3,4c7674ca,60a6f07e,1c1ee8b4,aa3dce4e,82ff890b,cd256324,13a56fe7,b3c8d404,7c8610a1,a56af634,b54dc568,6af075a0,a0cdd4f1,75855fa6,d22cc4c5) +,S(d8a0aed3,cf37542e,a0f06c6e,754503d7,3bd693cf,c3c357f2,7445989e,137f73e2,ba4ad8e6,3bde0d8c,42172a7b,59e1f4f4,581f48e,cffc45bf,929d815f,8133e6a9) +,S(9f905bc0,a5f479ee,6162ed38,24d74a1b,d6d48bd5,4611f840,ab1ac55b,7b84be18,5babdad,4248a4ef,4606dd26,1807e25f,6206dc81,6eeaddda,fd8b5082,52e3da53) +,S(d51c86e1,4519166d,c2aa7604,c88670c6,ca44a84c,6735f692,ee4dda79,e957b85d,fcee6753,29130c5,f4b260a9,cc7efb73,d51e6ec,8ac1ec52,28ca0ab6,51d5b8f0) +,S(ce251fde,ffdf0f59,5a563941,179f6f8a,86402b2c,6bddd1ea,7b37b89,bc649102,5b26a79,882b2f89,79610eb6,5de06e02,b09412e8,bbff66c5,cc650211,d1b9ccf5) +,S(6168ac7b,101fbe73,5b9339b6,9c459fbe,44a6f6c7,bd488beb,bf0b81da,ce511f3,65b6e531,f350983a,2f55db14,588e92db,436f7068,5117255f,ed474aa2,53b5c9ff) +,S(aab2deff,7e77f414,59d4361d,2722b448,6530f0c9,46b93d96,975f5a96,eb4bd091,b416562d,c5b057ef,7e63ec2d,daf0aed4,84320d7b,60695809,c6fa3aa9,e4eaa431) +,S(9ebed934,ca30351f,44b7ea4f,f3f6453f,6d0c7f81,869226c,c8f4312f,d413056,766a6f8c,311550eb,a8500ab6,f3466ca3,52e6b960,c4a52cb9,870ff784,4191a2aa) +,S(a2e78d35,d51970c3,42d03a09,bf3286c2,3a131ff9,abc4bea6,352826d4,5fe2da0e,fcb844e0,4bdf8d96,f423c499,44275ac5,8885c384,57975268,ec8cd880,dc640346) +,S(1a49f352,5203a773,9c7cce34,d21c51fe,dfeba5e5,c0f21622,eb954621,e3d6726d,e617de36,7c6a9283,8d4bcfd2,bf2fd21c,15b53007,6a0367b7,6d6ea65b,af032213) +,S(be65c6c,de6c54b6,c0c4d306,65cb4d61,211c97dc,a74c57b7,13f41028,e2d14832,d7875fb7,5cce3a40,9a74e48a,9b577a04,4c09a43a,989606b5,b44fbade,89e6c03f) +,S(a1572e58,60b10c96,bb3e0b6,7a047d4a,9957448d,74bd8a44,823de9cb,50aaa639,5ae37e0d,88c9f6d,173026ac,58ef45fd,17b0a0da,40304954,f9671c56,93946d1b) +,S(21917639,b6ef2333,378bafe5,fed1780b,24d9fa82,17ee49e7,369099a8,8c9baee5,fee39df,4bcb318b,4dcc4017,7f1af605,f22c44ec,d67a15cc,297f02fc,dfec4eb7) +,S(ac2a8d9b,b2219c98,444d03a0,36db728,ffa182d0,d31831ad,f2643010,bb76d3fe,adec7f18,c9474dc8,d0741d1a,5e72e479,c8b86f74,327fc5d3,cd79cf86,869310ab) +,S(c540463f,bf62ef36,a972d797,2bf79054,80b8e67,415f1895,d42d261c,165d1b86,f04a3516,83039c2e,8bac5ef5,1db4e105,95a27e25,cfe680ed,e7d840e4,f70e50b3) +,S(df63238c,77e75ec9,b844431b,d15007d6,56b849eb,4b6902b4,e79f0d6e,9527ef29,63846f3f,dfba6f2e,46bc7f2f,17af5067,a953cd0b,dbe2fef2,52e73be,b8a17330) +,S(43dd347a,1bf0ee84,ad774d4f,70c67cea,594946c2,94cbc330,15bbdd21,890998d4,b6f58d9e,e6e13c1d,b65dbd28,2343d8d2,3f73035a,b4399672,15b0300c,f7dfb48) +,S(5af8e3e7,f5ba9d80,73c5c1e3,c8d0a62,52eef1c1,17043e01,7d610f20,8b5eff0,246c7a4c,6f6e75aa,eb60e256,756e6365,711e98a6,aefa5345,adefb632,321d39da) +,S(60e7513a,b327df8e,e3d44222,95e0d886,b264f560,1c4e3d03,3b405d37,f6ae8518,4c58466e,b68d6c81,33fa6639,12f4a12c,a4a9f3e3,d4e0f6e2,7e92a85d,4d541cd3) +,S(126520ec,f3129775,786c4d64,7226174d,3ccaf5ae,2e4a1514,90e1b691,f07946a0,d5a2544c,efec281f,e70f05e8,2494085c,133fb918,6416435d,4b7fe673,88c440) +,S(b588e8a0,2396bfa7,8512585b,cd0d0e4a,7d14b5e9,f76e1426,b4591c9,6602c585,d7c6a7d0,827852f9,e34942f9,a6f5eae9,cd0a7f29,d30057cc,46d13e2d,4ec04caa) +,S(257f90fe,4409ef7d,30730e37,d7358c7b,60a1cc21,57acedd0,355d7a1c,89b5750b,b14da56d,9aa8fb67,b2d1260d,8de63c00,a9a7aafc,6fb890a0,e1a148ed,5e371201) +,S(8072b8cb,47c71331,9ed2ce85,cf913c87,85955c84,d338daed,58528427,3f3a4a56,6d7a0ed6,bf3383be,8953b47,d93ac5a5,e40e8547,2fc6d3d7,71f89007,f8d20d39) +,S(fab935ba,b2b72a27,b338ef89,509b3830,b7800817,19c2b3ec,8467c736,24ca2640,2a610c06,77fb514c,b224dcd6,56c5136d,88f87f34,86fa0699,eb71319d,c85a103a) +,S(7c6364c6,4906b7c2,e1ca0d87,6c163932,7e8e146b,afd94c83,2330f990,f979ae52,c97e7b44,26b91f6c,88ab7e39,d57f7b7d,4a5e0f9c,ff15aad5,e58e7017,d51c5317) +,S(98beb1ac,48c8824d,447a10cb,43b51167,b8e7cf0d,9eb4e4c8,43403b03,2208570c,1712c13e,ddff8fd5,191fdb28,717efb74,ed52a9f,f47bc21e,b15838d,fcf00af3) +,S(f683a667,31241c44,4adcf062,156f3fdc,d04e8450,911908e1,95bbea2d,8c5bf918,460eac53,48ea1e78,9fdef168,a150065e,1e4a2f83,85268385,3355586c,87453f1c) +,S(38f065a7,165e5d4,d31238de,8dc38f43,4dd024c6,6eca026d,de03c4cb,b43639a5,790bacf5,d35a688b,130bdb38,29073b8,28837b9c,9357544e,1e44d766,e401d044) +,S(cee8a218,2b3004fe,76714511,30340b0,7cf10241,d9e933c4,97ae84e9,a1d525f2,ed373709,3e0eb05d,3ee2823b,25bbbb11,ec943848,1a3ceae1,89573d71,7a596b3d) +,S(164c6ee5,620f4582,35520eb0,8276d85,9a14e266,b7b59576,d0a3e0a6,636f124a,fe92dd66,139f02c8,76ff6e57,8c769a4d,63484072,5c909bc9,481d4a52,f60565f3) +,S(d4606a18,1a0bd363,eb63849a,81c77d0b,942ff14e,7f885c61,d1fb772,78ef1008,81e7b2cd,e7c5d9,29e1d69a,309a334f,2c01b084,e82b789a,835a7aa8,5d7e93a4) +,S(905f5725,1df1651e,83aa8b3,dec2d96b,a32155eb,90d7f985,b3ce5213,2092be07,e4acfdaa,9eb8995a,a4ac8a0a,2b66cbbb,d561fe6b,389c56f,3af6f62a,d7579632) +,S(2e3ab14c,d3aa69de,a35a8ad4,99130302,b16f3d3,9df06b77,7c30e404,91eb6dda,ade534e7,ea0217a8,88c50bf4,ef81dddb,a5c7ffbe,bc0f90e7,110df2a8,e0c7c2c0) +,S(98207cc0,23f50a6e,5f5ce8a5,68c5b24,d4f4f741,94de76a6,d1e6f44e,72619a9b,fdacc236,bd424684,52508806,b08fabdd,98a15b15,6751953b,95b4c5f1,40bce374) +,S(b6d8bc0f,894863a2,3a793c3d,a33a5e66,cafe8696,f9cdd40e,777a40ea,aa203ee2,7e9b246c,8555b4c2,47c45fe1,d1e5d160,c7ed7d37,a3a43440,deee6ef4,15dc092c) +,S(56d030ad,eb30f1b4,7f806276,651a56d8,7f0d8b6c,458092e1,61351368,8cd0f6c3,bb3a1513,155c5885,e084180a,1728902b,33e1a61b,364c8d9c,94d67ca2,e386f131) +,S(77251aac,f919aa4e,b7610a77,ba27d94,c85b973c,af04c885,92fe5272,a48ec088,ef27aac0,593cc67b,93535bc8,4d0a04a3,e8a865a1,bdf65312,85beac2b,d58e149d) +,S(cb7b6a,cbbbdc23,64711585,6d80df3,2ec9aaa0,c6380b3e,677299d0,13658121,1f818bab,72575e35,a60ce7f1,c720e9ce,2f59b086,63cba841,ea288920,16a40ca4) +,S(4a18eb1c,bddb4c3f,ed44fdfc,6242959c,29720142,21d10154,c7fbca68,5c475d0,bb24f347,ebdcdc0a,6429f8ba,49065475,9cce87aa,8df10496,6d2ebcf2,97e70ffd) +,S(384286ca,1003c97d,7d151032,97d81cfb,e3e3dbbe,5dc70c76,6a8dbdc7,c1e625c,7201deb,638d2ec,6cbb4db4,e955ee1b,a3015cee,e06d2ddc,f024daab,8f07a277) +,S(84b6d6ae,d5e00e31,73c24d39,80f05cd6,f61625e3,11439a55,e03ae2db,d79a7d55,a3da9e1a,4c32e4f9,a1d326c3,6670296d,3ffb18fc,266e169,a99d4d00,4de383b1) +,S(aa1cab51,f7239cd4,dd27a4c4,805e614c,5d972cbe,c2830ebe,7daf6ed8,781c37e9,cf8bb72e,535fc8cd,12a2f4d5,e8f9e257,38a28812,1c93b061,5fd4fdeb,368be5bf) +,S(7c4f183a,f4abbe43,d7fa6d5,77ea6c14,83302f2d,b863a7c5,bf072e51,3d2140bc,1eb08c67,a417c0b,58fe8185,1a66902a,a608db07,24dc38c6,706bb80f,5956c808) +,S(dc30f68e,58ff30a,4bf2f6b,28b30708,506140a2,1a971c04,8afe04cf,94b54d31,6f996e08,8d4f7f53,aa1c2050,644a47ed,bcc1da4f,519978f8,6496ba1e,c7be2688) +,S(145185a9,ac6b036f,d0d3cd25,c904b3b7,c8f1d0ad,3ffe5f89,d87b7804,8b017426,d7f6acb2,828ccbc0,db0708e2,79db6313,fc955d2b,cf9e2754,1a7535e3,24c7bc90) +,S(e8700138,5c0bc4e2,9911f29a,e39a5ae3,ad3cf1cf,d690cbef,32f313ea,fd190fa9,92d83708,2e5139d0,f8084001,8ebf8703,da250361,466caa96,717edd0d,6e7ada7f) +,S(5fac0aa7,9963a1e4,5e1c668e,3512d0fe,2eb2c709,d5ecc71f,c862d5dd,523f864,9c7bfd73,445e7d9e,139b96e6,813f1f80,2ec632c6,a76e9dfb,8afecf40,2788d16a) +,S(441f40f6,f3ca4dde,5a085c15,57f14cf3,fbb7c3f2,5716c33c,63ee90f,45c564e2,c81f1205,1179c2a6,f2614495,322cf40a,34cab55d,c90d61b4,d1bc3787,ec3baeae) +,S(a4068c1f,c63d8f21,203cb6af,b37d796a,3c454bd9,db974ab8,e8bfba8b,b832b043,b5318b99,e9354250,a837f8cb,cf8d9cde,d95bb1d,1db0becb,1e887535,4ddb96ca) +,S(44563417,c647b097,d0238a57,74998fce,3c809a26,f6d2b71c,eeecebfb,134cfad3,3f417680,1c15172c,ef636dc3,12742429,13d59079,73ad09c3,9fd8c6a,8a95104) +,S(d57a5fde,47873327,728f5706,d2f0d64,1c5386a9,fdc41808,a2c062ab,942acb6a,cffcd62a,c0c85aae,4a6b7881,f3be170d,9836abda,baa47d60,8c0b8f60,f9aaedd1) +,S(9dcedd10,d495fa2b,6f4b4387,57cb38be,d6f09949,17e7ece,7de913f7,8cb111fd,73196e22,59d4ae9,950725dc,77321567,167d7761,29cc32e9,d92b6dcd,4c056223) +,S(aea290f3,a4ffd405,d51f1c8b,5f11cf74,60f05300,a1e24c08,25b96910,b24e32c1,f6c100a6,3c918f8,f64ffe8a,95840421,dc384635,e3465cf8,65034bde,17ca8eb9) +,S(bbfcd317,5091846f,181696f6,35fb1b05,802e7659,7ca97040,31339381,46812234,2a0a4ebb,1f09b31e,aab4478,89000fbb,5876d7e2,dd889393,3001a977,8aaa3a15) +,S(2a3b4e65,d9d7661c,addfe1e1,96beaca3,ccbc0348,dff6d2df,21f394c7,a7f4594d,74c6f171,1a2c0c01,78bb6a27,b6e17cda,bddb7260,acbc533,a49b19d1,e0b4a110) +,S(d8e47e32,15cbe145,aaa9efec,ada428f1,8d8c599e,98d2f9d7,8177215c,c85dc2ae,5c4d4f6b,aadcd87c,7ac76eb8,22e1c0db,e7c81342,702bfd98,e193df1,809e0511) +,S(5b5954d1,25d77778,f3c1514c,6256ef65,2ae0ab97,151f8856,dda6c87d,1e04a34f,1c5ddf3f,b185edb9,14769482,95e687e4,40497582,26b36fc6,3502922f,cd1bf81e) +,S(e8097e1a,12c6837,a8f29eec,31ccbd16,f191e7a7,d7b199dd,d6d9ee6b,7f26ef55,84ab3d24,e2c4407b,53e4299b,8de1aa8a,22dab9be,b6efa5c,5715a943,65174b9a) +,S(495ebcc5,b0573416,f2b3e705,fe4a4bfe,1e756211,5f37b8a2,dec57688,dedbdd45,3bc65725,6783970c,7696d5a7,b04ac7ca,8c627ce9,251844e9,e7cca774,4d385be7) +,S(4ffc69af,b9cf40ff,c94beac6,aa020109,b7855e0,a993984f,5e59ba16,fc78ad51,6d43d1f9,e3283528,494c9783,cdcbe9ae,2ede071b,ed494c57,2539df6e,b185ca1) +,S(b047e0d1,afc92251,7eaf5c0d,a9d0a093,fde5e829,84c8483e,d256640d,166dfc75,dca2ef00,a282972,d4bf67cb,74fb31af,da5b8145,ec1b7a65,6636376c,504a70df) +,S(ea7b0b93,48e0b3e2,be800ed,6ca4b121,277a496e,84fb6680,2658f68,37b1d530,cef40d2c,e1cf820b,19b435bb,a541ff1c,fa572b1,ca3693d0,cfeb3b32,8ddf918) +,S(e35a53cc,ad74738a,bde75a3e,e2b10d7a,d4ec39bf,e32e1daa,ecc151f3,bef1966b,ad06a8ab,a0296c17,fb24eff3,b27284c5,6ebca204,f6eee752,276ab9a8,1f1bce13) +,S(70334511,ae9acd50,e094f034,17dbba05,4a104c84,ea8d6250,13e1f8f6,907261a3,d1f603e0,5af2e1df,4b8eac69,b4067810,c302ed18,f02bc964,2eba34f6,bc67e84a) +,S(13adc074,c3ea8877,4598d0b9,ad653285,c81bd98d,d4bb6a43,c126db2c,d1f08d7,4bbda9d3,c83c7a64,fcccf3e2,c4251a7e,f61966b7,ec48e89,c991d44b,9588c83b) +,S(4a2a5fa0,71702fa0,934b66ae,7c003f00,306f07b8,625d92f2,d2276efd,18ce5f0c,f9c2f4ac,d8c594a4,117a836,7fa5224e,a7ccbe60,2475e3ed,b19a317c,5feff6e9) +,S(e2f7dc14,79bac0e,a95b5a2,1a9f4e,8c42a23b,8f25d09d,dacb9a3b,fe3ec638,ae6c82,c4f3dc5,41f140a5,2eb6b0c,dd0e200e,d0d951b,e85efd4b,b9b086ad) +,S(eb1d6d07,8f6b74f5,c48a913b,8510e8d0,5cfeb954,856f3ebc,628d0db1,a253963a,f3d73300,e216d14f,d5a67c35,91b362be,f13818c3,36a93784,875ce9b4,2cd8c7d2) +,S(a22c6d71,1d79ae71,403feb96,6dc11adf,253a5d3f,d3d74b44,5f7268bd,84b52277,86d5212,bf37db8b,4e873476,36201714,3f295f0b,d69d2187,8904a53c,831af06) +,S(42f7eb02,797cc76a,21c95db3,c9a0014,4ec5defe,553a45b5,1b701c0b,6f5ed3d0,60525877,3cb86452,928e37d,ce19e2ad,4da63174,2f049214,9f9823ed,ba679519) +,S(f5250698,b37da26,20a3a80d,a9c1c88f,792677a2,6d2b9fa5,49065339,ecc1e95c,b0826c,66edbd2c,5562bb14,d6f8df25,a5d0bc54,7a1163dd,4a8dc1e3,7d140266) +,S(b845d4a0,bc8db805,43526506,cac5c093,cece5c5a,85750d54,317dd78c,7bc10832,e38db2fa,207ce0b4,d9b01ee8,b174a24e,f28591c9,9d203ca5,7d90080,807279b) +,S(4955d281,746b8c9,4bac7d53,26aa28c3,9fba7149,7b4fc036,f9971f7a,870a67cd,ce72ebf4,aef6e987,3fa5cf3,e66ec918,911885ae,848aff22,eeef12e2,e50e6cee) +,S(20fdca2a,a03d6105,50f2eab8,d5e7d47d,c4e2e9ed,e6d2c7b,bfe64d75,176b9e9,1e077683,2c44d6d2,19d19c7b,aec0a303,f4d3d5f6,4ad8ca35,83f87325,6aee262f) +,S(418de9de,9adbec78,769eba7a,cab3853a,9a85ebc7,2bdffc86,844d0f32,15de4877,20d521c9,974c8ee0,f817ee37,a0fa14d2,eefc4e05,2c93ce87,ee665898,9e49c5a2) +,S(135b5a4a,f64eaa0f,d288bee5,c1bb7846,30df305b,5d3b13da,d8c446d3,6e13485f,3e571c3c,fe32fe42,669b08c9,14a655ce,828f41cb,12b9c18,9234f4eb,1aac0437) +,S(7eb64f50,5e26671d,21d3b2c9,fefbe094,c6300348,25248e86,5daa8939,f8b7e90d,be847834,f303ae8a,55ebaf3b,5bccfd61,6284e836,13eecdae,ab43bb6e,d4d4e986) +,S(9ee1ccd1,670be914,f9b7a070,962f7ac5,ac9d069c,eb3e0748,72db2e08,32870fd6,7d3d9dd4,9e71fd68,4271b17a,a8203ab6,1d2bf6d5,2fe3773c,78a8ccbe,d256cfed) +,S(a256c06a,796cffbc,5c90d91e,93ded565,b9755b7c,b760794e,e3060b33,3c217e71,e9ef8b6d,7731c262,6c93fb06,b7a6b3fb,fbbe0e0f,54682409,e5218a74,d4a064fd) +,S(dde8a9af,ec32c1fb,be9470d7,a435b4fb,bd34416d,e703a1ab,5188fe8f,f721aa4b,e7dbb850,aced2fb2,fcf5ea6b,edeaf383,e4ae0fe7,98badf41,66e58f13,6a87f3ae) +,S(fe88599,811d0e9,f780d359,2e8106fa,2f54fb6b,ba1df66a,b7b0b41,2c130c49,b3b0b8b3,c7f36d43,86f30438,1989d885,31edab91,f25251b4,e01b3d3a,6ec97f2d) +,S(d7da001e,8a606b37,ca65ae71,32214cf8,258dd422,efe0fc83,adabd56d,64b0467d,97f503ce,8eee1873,7e422bdf,91f051f7,1025353b,3a1f6f1,545206f8,2a32aa5d) +,S(65237583,e3e1a640,c2c16a9,a49d09c1,f5dbe2d7,a3845989,574abe33,397e747b,2296a1b1,e2350d8f,14a6fed3,afe30fac,a45ff345,9f8f515a,370aa260,d435f7a3) +,S(419a8e03,2d8fd27c,afda6538,9b757550,313307d,12fd185b,4d2f026a,40ae1de4,2932ea7d,3421d738,d821030,f75b0343,fffe9d25,8b605cf7,e20f6b48,1a94db03) +,S(275d261f,7ae2ab4a,4ad1fd66,1621a223,7ce08787,beaeeee1,a537b103,c0a44023,da955bd0,4ef1256c,9e184615,c4ee666d,c9ae14c7,d95caa7a,5dca6f11,1e5e2e58) +,S(3ac6681b,d0a2968,290ad83,cb0e00c6,6a9962cb,4c082366,953e294,58ff3651,28348b56,38ede228,7578cf14,ae385066,4595a2a8,d86282a0,edcc389a,346066d4) +,S(d4ba242d,9407df55,a9f672b7,e01cb1db,99ef744b,d24d3e47,9b1841af,a6c1f05b,9e395144,aa1fe50,9d72d086,4a1673c5,24c4ad65,fb7bdb16,cbd52053,1c6f11a3) +,S(c6525077,2bd399d9,901d57b5,7e8fc941,cae0f5fb,6d47ee3f,5b3a7cea,3fba2e83,629f7edc,a6ec6b0c,579cf9f1,867e1bef,e3bf9bea,8d8e64b7,2b18532a,47280efa) +,S(f12daac6,d38fcb00,c2425a79,2c52225c,a94d544,c6b96076,7ec9c885,d6d4430d,1764feee,2584dee3,abf2aaf,737a068f,fa6aec89,6c02e2fd,cf0ccad2,7ee8f210) +,S(db858a7f,4a84d88f,236b5994,dca409b3,d7111df4,f7e5c009,4ad1decd,82036673,c0606c89,e4b13042,9e0a63f5,1c93b3bc,95d98832,d89a9515,2e5c1874,f2c94a53) +,S(237f5f80,4d4c50eb,d611b079,5cbc6567,101ec8ba,1a265976,64472f7f,5a725ed3,b558d31b,7647c4c9,1367d696,a67e5d88,76454900,f340cd,5b8d7490,9fdd5993) +,S(e962e9c7,7c97cf36,32bf0a88,d6e939d2,68af9fc6,ebca96b8,6fb679a2,d953eb20,931395ff,a50a854f,5aa29314,c50c253c,c3175739,9c2eb20,600b0217,9f8ef48a) +,S(890514d2,14b57796,85c0cd66,818d182c,3d285af9,771c7c48,92ea2ac,115a8c3a,47c5a,a4d76cfb,2a62993b,b499df86,fbe7e130,d4758235,7decd72c,b61aee8) +,S(8b058976,295a316e,65da1774,da78722d,8d729f88,5ea4402b,f20dc67b,bab7f815,aeed497f,57d52480,23b94a3b,5fbe9c0,e34d0039,2d57b34b,377bda9e,b8703335) +,S(6a4685e0,7d96a793,d55a6416,6b089623,755fe549,3a879fbf,fc9a5a74,7ee7991f,313ffb6d,98044c92,f37b3f66,81f1b4b2,d9b2e42a,7c34a5bb,db45b9c,6063aad) +,S(65157530,e4ffeeda,41064bf1,f8d85174,2b9b8f64,87a05ea9,3d2198bb,3f33fc26,5b0e76a,8f96facf,9d492232,95a0c6f5,6a609504,b9b07c38,a72b6f15,4cb8c9f1) +,S(9f6c288c,1e04703,46b02d47,8fc0a40c,dfc0229d,928639cc,6ad2ac88,96e55085,2af7c1c1,7210b552,4ae2083b,b45e9749,c9452776,c12d5e83,ce265c98,51266c8c) +,S(c566e04f,e5ef7062,7d914a04,40731caf,3a7dccbd,5415cc1a,a2d81328,b8a6da75,a3fa5263,a7f66158,67f43270,77d3b2df,8db1befd,552249ad,e96db0d2,8c439282) +,S(6963ffcc,cb62ca7e,565fa9e7,99db54c3,dcaad601,95bd2dd8,df70d447,c443ba4f,96c715c6,84bed531,27c28e3d,6d6a0214,883aa214,25c4626b,4c11cf17,36b8f134) +,S(50db27a9,8e0328e2,81139df7,5376bec6,37e9272c,f7c23333,510bf5cc,c4f46b2a,b5221242,9eec82,1e9143fe,af9e7813,c135be82,bfc153f5,2ac061dc,c1302d92) +,S(7badba3,8f23f854,2404e636,b96e86a6,84557310,2bceb7c0,241e71c6,1ae22ad5,bd000395,b5d0ba4c,a76ac682,5191fbeb,f6066d8a,81c4a210,56ceda82,e13459e4) +,S(147667bd,5591aa83,26fa497f,c60f8e7,a5ceda47,9d4b2f7d,93bdab3d,81bcbd0e,bcdbbbc4,2adac6ea,413fc3f3,6cd2089f,420a6183,a918bf98,fff27aee,3e870849) +,S(ee576c33,e8404e1e,11e1b5d8,6ea52335,cf8b0ade,49dd16a3,7a61fc10,cd3eefd8,722bad17,6e083868,b3c14ee9,a70013d9,89c01b5f,44188ec6,7db7bc3d,ca26fe2a) +,S(8e3cfa71,f3b7d3cb,fe59d8e0,b579b76e,d33d318f,41d3b76,121b02d3,2acdec80,86be156d,b76429cb,ff2c67e0,c015b7d,d0007c7e,33f6041a,d817ae9d,ed5dc4fc) +,S(e220362f,2df8a485,51dbb7ad,634c4bb3,714151fc,db3cc2f8,e483aac,50d88768,acb8e001,a81eb6ac,99dca40,2d62fed3,8891fe2,eeb8e023,6d8f2447,6f4fd200) +,S(1777fc26,9bd7aebf,c014c785,25dcd40c,f93db012,31541cac,448c44f4,89628808,641bdcb2,b87e04ad,3ea3a3d4,c364e93,1171b2a2,cf3c0205,77552b7e,594c649f) +,S(ddfb5269,fcbac0bf,a855d2c4,c9062c77,836af1d1,145b4df5,688b6a5,24c11651,c353674b,9520ea9e,eac3bbce,a85b0709,d0284c37,a7faf78,8b573ebd,67bac8be) +,S(b01ea11,d4704bb4,24cb11d8,b42411a7,3f227c84,dc10eb13,c2b20a1b,bf23258a,240844e,9ea3edfd,948d2df4,51538cba,ed57f157,d0632f2b,8b644570,5f9ccaf9) +,S(934e20a,46fbb416,fbe829d1,46bebdf5,2220c0db,958c2a9c,64244713,4509cabe,76b7a1cf,79ebb5fa,58f77e64,4395d33e,bf90c0be,37e7439,c3d29013,25b0dd76) +,S(15bfe959,5ee58bec,791981dd,13ac5380,6615ff53,95dd4661,28c23f59,ea236967,d6dd460b,d3d36bdc,eb7d3ba7,745fe6c2,fddba241,fadcbdee,44f377f,bd43ee00) +,S(5e1a723f,403cf56f,8019797e,6f8191f6,6e7ccf15,dfb1965e,590490b6,224ecd24,97342532,36c48696,645a7e60,552eeacd,4cba990d,6d73117a,dc6f2967,a6a0fdbd) +,S(1485fddc,85c819da,8894c1b3,8be82eee,762a052f,3830dbb3,7d21ee74,868c778c,d779373d,d503731b,52f9e689,805988c0,b916a579,921c637b,286c580,93343d5d) +,S(6f4b7385,f881c9ed,202ab6ec,c8302626,668a1296,36274f3c,ac4296e9,1eece7db,fcf6f192,c6c80fff,3f5c2bbc,7c6c4a5b,b0ea2e3,70799827,440e998,cf6b26a4) +,S(bc27cb29,33ca44d3,b56280d7,7d69af2f,9220f4aa,49aa0fab,685c7c54,62adaf76,7607d5b7,a02c5e21,cfafccc1,26e8439,88c10942,aae6333d,b5262426,1ed4da98) +,S(76f86b25,2530d87a,b04e64c2,4cd1e05a,e8324bf0,a717280d,3845cc5f,a6a1a733,2db7ce38,33bd24b3,55e95b89,ae6d8a54,19124761,e382745f,2a7347ce,fd7c382c) +,S(5615175d,2ec968f8,81dacc1d,1bd6c06b,df87c9ab,53fdef11,335818f,bafa918b,5f755638,6154cee9,e71d21b9,cee3971c,7d41e3e0,ca2c1ff,f66982b4,d66fec25) +,S(6390f1af,1ef24aae,20e2ce29,dfe9a0d1,50b2826b,f5cb3629,8e0dc16d,ee2bdf8,cf3e2b98,4f120d10,16f82e1b,8916928c,263f3323,52bbedb3,c29ae1ed,b0d49b1d) +,S(bc5df46b,4fbcb83f,7aa53579,ac8d5c3e,8482941e,cf848810,f9239138,b57e9378,d4d15516,624e72d5,9002dca8,3c8b5914,b224d4c3,75260dbd,cda88f9f,2f772627) +,S(3d069f1d,dd52177f,cd802195,c7c8b2ef,1e43c34,9bd88b41,43bc2d54,6a2b8d33,2ba48861,14218d67,1b1fa4e4,2aae97fd,66164e94,af1e3026,8dfe9dfa,7155fde9) +,S(fa657492,fab9ab23,f1a49c17,40079d7e,abafd7a8,72e481b8,7b30cb63,8a47757c,89d2c7b9,2f1ad11b,d2808968,c426a00f,e584ad83,86dff03c,1a047804,a2e98630) +,S(e2318d84,61f85ac0,7db07d08,aacbed7c,5f5a45fd,7e505bb7,ac86b417,6b3eb46d,3b0170a3,b6f466e0,380ab984,e5bf4b34,89cbc479,cb2808cb,445614bd,8ab012e9) +,S(defa0810,91d1db16,fc2f86b4,fa5a7331,f0c15682,55855134,10f41a6d,a2bfa6a5,8429db90,fbb25354,3e77ca0f,e7a731d7,f1a481bb,f1c997e8,5f585844,423ace4a) +,S(fbaa7567,7306fdd4,8c85514c,bcb78e04,ef4d693a,dc7c356e,f95ad34a,cc880db0,45c4972a,161f4a23,cd71f726,d5617b71,421b68f,b0611097,3edf11b3,8a391909) +,S(5dd76e24,e3cc0c5b,ded55d15,858f1c19,dfff7e43,b299df43,3ee77b46,2122205e,992de68b,87bd6760,a75d6b90,89dcb2b5,5f0b39c8,eb079ba0,e4451fb,dee8f2d3) +,S(890c7a78,d0f1db95,75b53e98,a0a63d81,8096422a,3ee18403,ede8ffa6,3af9418f,7a362df8,7430b479,11e8d310,558195c8,fed28b05,531b68a9,1631ef97,ac008085) +,S(4914f692,f88e858c,b6174e6a,9d4bbdf9,87f0e373,1bf6e69b,8bf3531a,43a37e6c,8751e02b,fa9e0384,2ff3e4aa,307cb7c5,fe4f7941,1069249b,c8b19866,b6169cf5) +,S(a5f97745,ddc25117,81693df1,bd15203f,9d23bc93,9015be73,c6b4e256,d1d05416,57a99674,cf64bff9,7b9ba0c5,69d253dd,52aa188e,3ec645aa,89466c79,5d0f0370) +,S(62da0bf9,8d32519c,16fac809,95869f09,b570b953,e0a7bd83,9623a9c9,bebbdf84,9b9ec74a,c960fa8c,2ea8bd4d,93ff624a,9ce54fa2,4a1822a2,37d962d5,64e9121d) +,S(5caa2062,c25d7df2,23718f9d,ff29a403,e5200d22,bf064b44,c9519742,4c448a5f,6063bf93,1f72f65b,9ca76400,de5f5204,a8a0bdc4,b19cfd12,2664aa33,79a7a27b) +,S(4a81083c,c18dcec3,5825415b,2854250c,9dc651fd,5d897610,2ceb7691,576ebe60,850f48f8,7ffbf26d,eaad1f8b,2c0b8272,5f7c313f,55811b98,408f8f34,8421f241) +,S(ba8baaf4,9d0c194a,4814070c,786fd9f,4b8dc012,c42ed667,7b39f67d,da7fccaa,ceaa8874,10bbe854,9e87af6a,15ae1326,d85bb995,19a8c4d5,dd3a8599,d9ae0ff2) +,S(4c780a0b,886fdcbc,a30f239e,21495f9d,5ea38a6a,7960ecb,ea4dd2dc,9266103e,7e50e1d5,b6c811fc,f86ee651,5d64e06b,26827ba3,656dfd51,1fa64124,224e182a) +,S(50a433f7,f528d66a,961d7123,7e6d2bf6,7321896,5ec6599d,b1f34b0c,db21524c,6bca1083,9ef8d450,e56829d0,cb23ddcc,81e2e7df,e79b53f3,2f8aab9f,e2eec15b) +,S(b98e05de,573e37c2,80d6de1b,fd479bf9,bd23a6b7,2f6ab34f,caf03236,c67ec5fa,d86f07e0,8a4c3d61,f087dff3,a2af2d98,58787d2f,424b49da,de0c584f,4d8756b3) +,S(d0cb5279,e76b8be9,b2e9cdd7,b0c841b3,33398541,24923224,db54a91a,81995433,11fcafb7,28a3307d,2d87f2ae,d107b0b,d64f6030,b89e845e,1f67ce7,4cf7ee6d) +,S(90c89963,619b1593,d5fd7eb6,751ef03f,aa7c6802,46e36bcc,5d0bbae6,25376720,6e8f2a86,75b803f2,c3c87f9a,98318cbc,61b99073,2b8b33b6,62197ec5,73f64a71) +,S(bd3ad39b,989c3a08,e45007d9,116b0d4e,2dcb6a14,26a44dc2,29bff230,6c1a89be,7e633d7,de03e6d6,a7a4a833,f338160b,cb914997,6dc2080,28c3e2dd,b1c1b11a) +,S(1da5082d,a6e4721a,499d5559,91e8d216,f26167b7,d6de224d,17bc4e5b,ac94093f,5f864511,4b89eb63,60ef865e,6eb887c2,bb0b97e3,9a0b7078,888049c1,29f63c77) +,S(19320416,52e24197,d195a0f1,99818925,35c19790,99d15992,8999073b,4028d659,2cf34c91,2d1666fe,1abd3b0,49b12dcc,f7086e58,b7700b23,497bec18,e057059) +,S(79a7b5e0,482523d0,85bf574f,2e6e431d,b3bd6ae8,4e921b87,fff0f683,976efa9a,f713e011,70de0de8,a8cbe229,b147cf82,efc7fe3c,d7171785,c85bbbfa,ef935755) +,S(c2e16cc6,8559a160,9fe16d0a,9be4016d,55fccdc4,2d22ee62,895e0eea,a64436b,22399345,d40c11bb,79b9f036,5fdf6a91,4e1f43e9,bb1f0a87,81d2ede9,fdb6a118) +,S(f76c0f67,bd3c648d,c320125,5c34a93f,ed656378,8c9f61a9,c60933d4,e2d55d7,205c9c5b,83bbf922,8e99191d,e7ef0feb,429050e8,2b9fb3ca,1dbd2d5,cd35f612) +,S(24a3af8f,ee393ae3,2c30230d,ed6f96f2,9797d591,1cc3d934,b16e1304,de7bd75a,302041e9,2ce00cb5,d4a667ea,90df7f90,576865d3,7f462126,400c77a0,a44259b9) +,S(2e8bf897,5f29a6ba,636e6ddc,1e2dcd6a,1373f123,c6f155b3,3c8f46dd,b18baf7c,a93f0c91,258ec64b,d6e18761,872cf0e2,c89f9713,b9008605,b0378f8,1ec867ae) +,S(a5d35483,7f90d71c,8d829897,b3a8fa36,7c38b41c,879a3e6d,52f2988a,b88dcf68,853a586d,9661cd50,12d1ae6a,1501b874,739405c4,c7e32bd4,23ab7c1,62382bfa) +,S(51a6c879,ba6f75d9,4480aa71,2a343be1,bb9aebc6,bb4ca3be,de16d33e,992659c7,3e636d28,f8b0a4fa,a3ecd585,80d46253,61f496b0,344382b3,5742fcc9,403e7e05) +,S(a1d34e3c,aba45bf,1772d2f4,bcacd17e,342b66ec,97dadbd6,780cc453,ff2449d5,6c3a3b8e,9717365d,2f21e2ef,d72308b3,45008ebb,10ca02e,969d14c9,1aaf677c) +,S(fce0f1a1,69034370,33de7e6d,b2364b0d,4441c5f2,ee405e68,5dc546c2,58adc2ad,c018bc7c,fc5ad1f1,36103729,e1a177a7,495a6195,915ca5ae,c086804b,8c107865) +,S(e380e6af,c47b11c5,1ba0c8c3,9b796179,39b07cd9,988896c,38011e73,a4f98a81,60ecd299,c22fbed9,132bd455,1f44022e,151927e4,7ad93f1a,a0539c37,2680f6cc) +,S(6382fb8b,2f4179e3,191d863b,a0ec4cd,94b52103,f24a0377,8f6ee27c,7c81115c,6e8d4181,9621bf4e,3c04c5ea,2b4c0146,dd0ed973,bd4530df,d671f39a,e54db63a) +,S(c488650f,d66629fb,927dcb0b,9f5d0771,1caaa3f7,ad6df39f,7d8f98d9,65490aed,b395d9fa,46475b16,6beed01e,90c9cfd7,83e6138a,7bbc6d5d,f919d41f,3e512c) +,S(5cf1f5be,462dd02d,f8d1e9b,6cb1540a,4f1e5be,de9c8d29,954bfb0,217e494a,5e8727bc,2429c9a7,5123967b,b598207c,46105822,5402bfcd,c3d070b9,b2351d20) +,S(9644ace5,9dba2b1a,f3f3a4af,da130ba3,c3bdefd9,39c3b52e,670ead47,54407b9c,5e83dd4a,e338fc0b,8c501f98,72295400,4b2465f8,4f1c272d,20e3a2bf,300b1b79) +,S(728e6659,f0bb9bd5,916846ff,3aab6f10,85517ad2,c17254e4,c2ce908,c7934781,7df32327,354020,319e9cb7,696b0384,6b8e5bf6,691cc73f,829abd42,44e674b9) +,S(80e68c8a,31d715a7,5068091a,142d4a60,ff30d2c9,42f625c5,d234bb78,31009e8e,fe04addb,b9c47f69,3dc0b126,67b0960c,1b4a7bf2,882aa626,b1888e5e,e4157fd9) +,S(e655129e,90211425,558cbf1a,4eeeb630,df68a4e4,f96a176b,db55500a,89f5af02,d5e3a471,ba698897,9f747ae1,a1aa87e,e10c5069,3df12ed3,ed52307d,a0202a69) +,S(30a9e289,f6ab5edd,7b56f48c,e7373a6a,97dc698b,511343c2,8c5c217c,de67ab6a,f4016c18,c4f75d52,927127bf,c403a83d,4ce304d2,8a4fb965,beef9fda,4e9d3f4e) +,S(8a6a4557,2c1dba29,c9499ecf,d59ea43b,1ebec5a8,78a3e2c5,2de09aa7,c0288e69,56e4aceb,e8315c2f,b9271519,80a21d,c17ebad,63223380,b24a7237,33ec205b) +,S(647d3443,9f4e4f50,cee5b0d6,8047f130,965f8abf,482f6166,8859c86e,326c1bd1,f951b5a0,b180894c,f74c5235,cc625888,fb830382,3b0d085a,dbe857ad,dbc22088) +,S(6d143d17,9f0a42a6,85031c6c,f62ef32,2cde46b3,978b04ba,bc37bd3,34de5634,925d0fd9,11c7863d,b0ed42c1,76591307,72b456fe,83bb8063,3afe5340,cab4b5a7) +,S(f21cebe2,7ce8dd3e,fa30428a,cee881b4,d65eddd1,30f9fa62,9d78291c,a4f4b0bb,4a6d7f43,f2ed3d26,330e58c9,27a87c55,850620fe,1edc6e36,c9a3978,8f922ea9) +,S(37883073,e227a5de,452c7706,a4a06594,5a891c06,e594fd4e,191d36f6,79117c35,224bb4cb,389f3d25,42411fd6,594ad6ec,bf4f1c9,11f723e1,53dbb420,33ae8ec5) +,S(c21520ae,e6cb0358,53a7da78,919c88ec,84c17d10,3ac13ec8,6a412d9b,96e57c54,56720dfc,f748ca09,e27e8aa6,e29ea591,c0205290,3d38bc35,3b0b0155,113a5bbd) +,S(96cdb3f0,d6194675,7346b2a2,1767fc01,2e6d1ca6,f5e788d2,f89e2fd8,89a57924,9f5fda94,e0455b28,1cccc531,7118b175,edd6c93,c212e7c9,fe845f0b,cac5a592) +,S(7b5e5f5e,564606bb,a71b8f1a,7d410b1e,6482f508,879e1bd,38ecdc44,b7effee4,92a3f1b4,84ddc60b,4b005282,89984241,4f91b9bb,fd55eaba,37dddd0a,dcc1c6e) +,S(541fd344,c9d553fa,1e87c9cb,72150cae,a69a9a10,771ac96d,fb292be7,261912f5,80ef7a00,6ce5ac0e,975ecd69,601fd059,a9860e07,77f6f31f,365187b1,f6c9b392) +,S(2b2b3929,50b07da0,5c20b72e,4101e36a,bdfccb6a,2a7f36d5,b57f58dd,1403035c,ff6c1ba2,caee889c,14414086,456f096f,d065a7d,d2f9c7b0,9ed4eb71,3b4002a0) +,S(23acbca3,4754dffa,8cb3176f,d1435d6,4cba0deb,84e12ae7,adaafe88,497aa60c,5d95b3de,26f703a4,fe9efaf,cb273921,56a49687,a71433f6,9a2813ab,5fdb35d2) +,S(5fdfa393,6bf9c699,24417a2a,f36054d5,95640b6e,3ae30807,5ef51bb6,cd63fe34,97fdd994,bf74c959,2a5435fe,f1baea41,8a79c5fc,1243fedb,5fbb0466,4d599d04) +,S(177cf8ef,58aeefed,2832d53,417c7025,c6b56fb3,8122ccc5,2b33f79c,71c461fd,d8a12d8c,69da9b31,832cc10b,55b57a60,b900c19d,f8f38c92,f6bccfdb,98d3acf8) +,S(14f90282,e5a3121d,a59e919a,fcd146a1,9251cf5d,c0d805bb,bd013eef,4ab78bd3,74a504be,928ed13c,f29032e,5c3dcb3,a18a1df8,aad26b4c,a64ebabe,6afb4244) +,S(31099221,e6ceaf16,81b22b33,dd8ee3ef,1c2a95f7,2bed88e8,15333f69,f91867b3,772e45f0,930ebd2b,7f5b7ca0,640467a0,8ab5472b,f6bd347c,903cfecf,8f80176a) +,S(a6a0a416,d8eb22be,49036f4b,dfc79c6e,6cd167cb,38813269,70e199ad,c5d1b5de,54d036de,6b84f308,84faebee,4f944375,fed61a6e,7763bb40,a283ab52,3335af10) +,S(c7c5cb1d,ce484477,82e7da9b,55bb8482,4f715a80,d844294a,3c05dfd8,3dde77cb,bb66731,1bb0c2a4,e493e257,d289a42d,3630ee24,ba0f7f86,134a7c6a,72dbc3df) +,S(f1bdcb49,43267948,fe1c9b7b,51afcc79,7027e4fe,f98c2175,d7d1b8de,770328b,271f57bb,a9249cd7,dc510173,5a2168c6,ea97b341,b44cacc5,4083d115,6de8e728) +,S(2815f09a,8f0e2dfa,d21f50c4,60b8f69d,3aad54d8,aaa99226,86050582,b954d912,dec68871,752d862b,32ffdf2b,482ce1c0,6a659bcd,3a2931a6,29bda260,cb3cbf35) +,S(622619ba,8b74a0d0,5f8fa899,aaddd272,c9e6d43c,49bb6708,367155ec,4907d0c2,aab9b1ad,10201d50,7bea05bb,5b20453b,6474154d,ebe3ddc0,c86535ad,7c701954) +,S(a0390604,a40611cc,6e36c81d,30cc3e75,d162e695,1ae0515c,75417744,c093b997,60428c28,8d32d229,7417b6d9,b1003522,8190a83,66cae58,f7887037,9fb99641) +,S(422c7d1e,b0498cc4,dbba0135,ababc80e,5416f187,11f0dff3,80f1e1dc,23bedf0e,9c47d3b7,eb5713dd,cbb9ec8a,60d931c6,3382452,a4c0861a,847a354b,ba57d9f1) +,S(982844d4,7f572298,afd6734d,98064369,d81e4851,4b176059,6d3a1e85,6f043f5d,9b86f6a7,678cb5f9,a4304f1a,a8d3458d,fa85e65a,ffc79da3,faa1fc8e,a2b7ed2f) +,S(993385f,a76b9373,422e4411,b9e8a85d,3ac0e09a,f9598570,63d50a8,67b67ed2,3e7a9a3b,222a66d2,f55fce7f,e33effbb,bce8cfc2,8991d8aa,376a8ce2,4e9b8460) +,S(15b05ee3,179d1dfa,61bfb0d0,1903f93a,f7e04f98,cfd40be3,2ec094d,1bd5a4a1,ed1301a1,451cecad,30e8fadd,801c9db5,5acfd697,3ed36621,2f2e3032,adddd939) +,S(6062aed5,7d6312fc,433bf7f4,9c10772e,829e294f,e7ad07db,177c75cc,9fe5e52e,96aa4495,c6eb07da,9a5a0e19,8771dce5,23a5d7ff,de314562,3b704f44,c4ffcd24) +,S(ef45dd6c,1213ac0a,5df18426,9491cb3e,bb5312d3,fb55c7f2,8351c98a,1ba564e3,91541d32,43e032f9,450f3605,cab238f2,703a9eea,8e429824,7a6ef63a,45540e68) +,S(a1e32dcb,c3a13a46,166ebb73,7e09041c,3487120a,6ec46987,6befb2a9,94f4a69a,ba88b7b1,8cdb2088,b5998b34,461b8a5,d85a57c6,31aa10f8,6ff808e6,3186e5ed) +,S(817e6c2,6d4ae706,f43ddd7a,cfa4eeed,6498ea2b,86aa661,9a0b45f4,e22ea33d,8aeed38,bccea5e3,4923b959,53bc9629,d9348442,4f33b06b,b02c882,25e47bf6) +,S(e734f5a7,736014fe,2ac9137f,d025f914,7574d67b,3696596,9f89b5e1,aeebf88d,74fe8220,7c83d3ba,ec54f032,f11f9309,9be25f53,565f0d60,5f2ab406,5287c997) +,S(87b2d307,414c314f,184eef07,6e9809d8,ea19c002,390b5047,38eb7bbe,ba1ae7d1,37f5c369,f5dd54b6,87729036,b88dbf37,45f33da,8c2bc9b2,64213468,f1c56841) +,S(dda23ad9,6c51604e,602b8e6e,9f08a67f,981bfa98,93194369,269c56b7,7986b772,6de02623,5ef973da,13e2577a,bbcde720,aa8fbe12,23c5288c,5724bbc0,228074a2) +,S(8d56a723,6adfe6a1,46182431,da5ff846,aee78931,27564954,f14172f5,27048fb9,c7cd6bfb,fdc51a83,252d4e4a,2c978cd7,67fa3809,521678cf,7dc5e514,eaf0b418) +,S(9da30ccf,f147de11,de528d14,863a4fcb,a2ef228f,506aee98,eabee895,eb618def,a4ab41eb,a16b4733,34a818f4,b6bd3c43,de4a9392,c15c9e19,a8b4e961,7fd4bbe7) +,S(e3339c3a,b14145e5,40c08544,eaa631c4,7be6c09e,563ec93d,2a05f219,f4afdf2e,fd586d7f,3a668a0b,f888083a,9ea84f48,43598417,f55dfea9,790ee89a,c412fed7) +,S(a6e08d07,66274337,f3b139a8,d6fc3f61,4dde9ef7,2e03fc52,45f7dfcb,1c0ab41e,d9620b61,116af945,708a610,c78f0b52,8abd97c0,21ee34fa,10d289cb,f3c06d4b) +,S(f8ffa0d3,b463fc5d,44e6eaad,caecaa85,8515bc4,69fe76e1,4ecdb25d,e503a040,e80dd6f8,934fa405,fd4d74b1,1da0d09c,dd723df,daf46221,796cd7e2,4bb83f1c) +,S(22a212a4,3c00408c,b4b94e2a,45a6a999,917c0fc7,aaa565d,c6f982cc,64b0d0d4,663d8ed0,3128ada4,f421853d,8ffd8201,1ec8b997,4b0d827c,ed318551,ff9930de) +,S(8d33b62,f162963a,f6636f18,ef33a83c,e9a17fb6,b1fc58de,6d271d,472a9d82,cf0092e6,60311726,e0856ff7,1893555b,625b117d,4698e4f3,f31611eb,21a56f5e) +,S(3bbf59cc,5b4aa31d,dfa0ce94,1853ff69,9db29cc7,a0021cb2,11ba28d0,1dc61d3f,d54beb79,d1edb94c,d6bd5ae7,11a3ff22,9f2baa0b,efaa139a,e4724ae3,624d8318) +,S(4cc9c2ed,3a7266ca,faffb517,d3ad4aea,2d4d877,d9b08433,a4fca2a3,691aec68,70ac52d6,1094da70,5f714f60,854a5656,8c25cb13,1502171,7bd4085e,8b489756) +,S(a997cf82,50d7ec36,125189bf,eb6b8631,cec31fdc,f156d34b,186f29c6,5d0b30cb,ca73d95b,93b43983,b2c51518,b4e419f8,415f14fc,b6356287,cd65d49f,92929d5e) +,S(5fae92aa,7c43ac60,b4bb4f90,ae2ac462,a6f88681,9aeada99,4d0694a3,a6dc1722,6b7ebdc4,dbe15dd0,9c1e4587,c7f297c1,74d5c933,6bc91511,f31e0cae,2e51b280) +,S(cf541216,323a9591,13561470,2b187b35,fffaff7d,8cf1993a,5144c7d4,aa836308,9d955733,feaab81c,4b03fe4d,25fe36a2,5075357c,b6ebf8dc,1822cee9,7f585f80) +,S(9c2c8607,bad80760,efb4ba73,442a359a,c1cb9b45,f81e54be,28f3f6f4,4699773e,7848812f,f3101eed,137b4dd1,4f503a42,9d71c157,449767c6,a5850204,869a9817) +,S(2f3bca36,fe504b7e,93f70176,2e65dacd,250b3789,541076ac,86352481,c896f77e,5af55f5d,b2e84dfa,38bdd0eb,fde7ea68,33471d28,add88dd2,a7e7c63f,dfe513a) +,S(f2fa3afc,fe4e5da,385f26d8,1848f801,7401b06f,652121d6,9468d2ee,f640260f,54cea12a,b4ced3ee,2ca351df,4310e96a,d3ca0d80,c3a3c86b,267c4620,bd0f69a2) +,S(82559cc9,ead1465f,a910b781,cb2a50ed,9a2b6ff5,d8513182,425b7dfd,983afa50,db5dd99e,242287bb,c94cd149,6e4aff70,7232e2bc,1fa4c440,5cd9f22c,fc4d239d) +,S(954079af,1494e324,fb707e7c,e9f1fc2a,751e194e,4ee058a6,e55e26d8,34901f5,2f90eb0f,43bfff96,c3b0f3a1,bd48c00b,85d3650e,52d1f614,ed65ce70,4fa19e99) +,S(c913a980,b1aca09a,19654428,6edfed20,dce31676,1fbff05c,1c05fa70,7eced342,17d2864e,df39460f,99b5b51c,91752c57,10ca7af9,a6e10c4e,c2b3e9e1,7317d3c1) +,S(815b7dfd,3b97ad9f,cf6ce427,ffe4a91f,2b541e2a,11305b17,2fd7b63b,82272db0,f0b958eb,fbf32959,dbc407bd,5290ca66,6f28bcec,2fa69d1a,7108a2ea,19d58484) +,S(7f7c1689,e93b7c77,20ab5b74,572e87b5,d2a907bd,624fb6ff,d5f29f3f,c64795d5,691a2f46,430c53c,375829fb,46ed4030,b5bc4dd6,70646523,45fbadbe,e6f8a1f9) +,S(8911275c,106e5a48,1c3dc5be,b9b42e2,3be8cf2a,5a76198e,e6749b24,bd9c5e7,747cb0c2,16d899c0,da5a8ed8,f279a650,f4537e7d,ca51bf56,b3ca8c43,92b5e99d) +,S(24cc2552,c907e757,9e85bf7f,fc868ebe,53e44b97,102b31f2,38678bb7,ad8c244a,a152808f,7d615060,ba9e78ae,720c2fca,a67772b7,fd99ed6,ffd5fbe7,ed114567) +,S(b0fc5873,68795dc8,55e3e19d,9236244a,812d1920,afef4c9,7f1e6c79,25395f85,f8b46879,5a0e40ba,2029538a,fb7cef58,9bde7b3f,fcc010a4,4ac962b0,afb8d7e4) +,S(cd6f4558,d634fc66,6dce566d,f94397f,d3ab9178,affd3707,55852679,adc6565f,d34d7be0,ea40586e,4f9007d7,4aca55e9,edb4b31d,8ad4f344,1f611a9d,94161b8a) +,S(fc5e8a3b,ada62f0b,6453f445,7dd4aff3,993005d6,de7b94d7,19fd487e,b88fb7a4,46041321,f7fed84d,2266d4a4,d86d836f,12f12296,d62ed296,6a7d5507,d6717130) +,S(dc72a540,55c962ed,90e64916,bdfaf6ea,aaaacbe2,fc180a7b,7e7bda98,f45488d9,e3b46394,41a2063e,59c4cb06,1a0a7e5a,a171fe39,812922f8,c04df63f,41c8e588) +,S(7d135c33,88bd5896,47f4cc3d,67fc7809,a7a4c530,e96fb5c,7dabe3b4,32a4fd90,79dd3834,8a61b642,9eb7a837,4e9c2176,95cff14a,3596a18d,19f84360,8aa0922e) +,S(7a56712d,b72ac3a6,353dad9a,15cfc9d2,7d9ff67e,9a35936a,e38e1c01,5980980f,6eda856b,9b5d4019,d0efb2f4,9f1af933,8969872c,126b2682,f56a8b08,97a83696) +,S(d3495480,25c7f966,d59b40d9,6ccb9831,2948c992,fcbe2f6a,7a7feb6a,946125a9,b346f8bb,532da4de,96908618,b0f85a10,fe9a87a8,d612e4ac,53bdbaf,9dfdb3c) +,S(22175a8b,d0a51763,d1818054,60951698,14af196c,df8648f5,29d27a9a,825e60b3,756d5713,81b5ce71,e23c0190,a1062fd0,645eddd1,7dc84c9b,b1c7d810,c13db63d) +,S(f557e381,37a1c6e0,a19e4207,4a1dd59b,17c5137d,97a58fc2,55d18be1,bf63877f,6cf0bb41,577ea3bb,7c9945d5,db33a862,3c1cce5e,d6fc13b9,b0739ea9,9af10381) +,S(8ddbadb9,c6a78978,2540d3e1,9ada3ed0,5ef35f45,a38be470,7083dff,75d501cd,75b4c5f9,51f70fb8,a89fec5,d52ea0b1,dbfc5709,3c1ee5eb,ff2ab0bf,f5854644) +,S(53f0892,cac79f48,2194dd9f,fc076305,a8ecdd4,977ac278,92e2d454,965a2aee,b39f7a9c,ecdd4ed6,d0fb1608,3b86d1af,68aa85b8,c733617e,5e97ecda,269ef97e) +,S(2712110,8fe28f55,c746525d,e7cfd4c2,f3a11b8e,3c6329db,a57a7b32,5a7edb40,cf6732b3,74681ab7,3448bad0,ae54b953,ee5d7bb2,5a8658d,3b366a78,dae5fa69) +,S(e7627b26,ff0448bb,cb45a538,2ff8ec9f,9376127a,b8425213,46e899b4,41cb5660,79842f72,e02820b1,e6b6843f,3a0c23dd,c0941ac2,b6fd30a4,39397ede,c78bc40d) +,S(37c48874,f07ce0c6,cf5be181,9ba31bfd,9a19aac,97b27011,1de59fcf,559fcb57,34dcc405,6a6dfa3f,283e0dd1,8b1722e,bad0e367,c30d9f1a,d552f394,9ce19b22) +,S(316868fa,33cf5544,1e9b9bc0,9f74fa1f,8daa9058,3fb8b3cf,8d339971,311eddfc,89fa5c82,9d9f4687,f7cb6b8f,ae20d6a8,cf872ded,a7f9b6e0,6e168c1e,45db4e73) +,S(d34a83f3,7b7673b9,6c8695f1,81ce837f,ce2f15b8,72664d3b,1a045c7a,bceadd44,e4f2cefd,59198808,15692950,19b9120b,495a44d3,4862323f,808b11b3,a8698081) +,S(687a48cd,4142060a,171a1efd,c41dce8f,8127ab64,ebd7c22c,7803f077,19168799,c082e152,41f7db05,ae6c1e15,e4ccc340,f4a7c8c2,cfd8bfb1,6bcd04e7,e635726f) +,S(70d2cd79,1d2d1418,9cf67e48,519aecb4,d58be2af,164d0605,2132517e,87f444e5,73b4c12b,edda1a70,89ae9db8,f105059a,2a558475,f5cf4796,1042c470,c9e190a7) +,S(2a6f2786,a191130e,dba1307f,f1bb0f61,c3d7b8ad,c02286f6,44871cc,170dd2c1,28a0c85b,8ec93fcd,1b9a0617,780da654,e5448475,a02a6222,f7065132,5ad64b2a) +,S(3f482e12,8d5bfc4e,d2f359cd,b4244db7,ec7edf92,f3fc5dde,5367d125,dde8c772,d41be140,cc4b4217,cdfaed4e,b09ce5d4,d3e95b52,ed6689ed,3f6dfde7,3c581cd4) +,S(96673e27,fb0f8a46,8fcc53de,12876045,77786d93,5afbca99,35545363,6614a5d7,f6a4eee7,1c4249c6,ef850090,59c12f6a,44adb8a9,cefe7a8c,ff2ac0a0,da28884f) +,S(be7a886e,499a9c2b,c05e5f64,77bcbb4f,26772e58,4565897,408eb36a,e25a9c58,24457eb7,802810f4,de64516f,24718b06,d61b0adc,bcf0d279,d883b2bb,45363a40) +,S(123985af,a3253837,e51f933f,8f25591a,823b2442,88cf8ba5,a0247ec9,94eecee4,a952096,21f7a9a4,3867c6a1,987dd661,1d3cf996,2aebfadc,dee0a5b8,6df196b7) +,S(75887ee8,c28bd2f6,a96086d9,aef71b7b,5a5fce50,80c3963,787089ed,e39b0214,47386fd9,a9216193,3bb500d9,a1ee8207,dc3edbc,17d3ccc7,32d9c90b,8995eb48) +,S(4f7642fb,12376864,29104657,2a2fffe5,2322df39,7cc097e8,f7a57816,e6709fe2,4f2ff70f,2e99354a,60cc5b2b,c3ef33d3,7e3e9ee7,16766018,e3a0ba39,efe5f971) +,S(8117d4fd,551c9ae7,4c9fdac4,5d87bb66,9bc7dc35,4b08de03,7c4a1378,734653b,13633743,d1ee8fd7,8482e3a,3a9e39e9,75b0f6a7,efb227fa,84feb897,693c5c10) +,S(8afabdf9,acd49723,d73c0deb,1016ddce,571abaa1,a71ae3e9,a20bcecc,ade5782b,2b66e3fa,ee86dde2,23dcc7b6,10ea8ed2,dd42124a,247b7937,9e190098,2580c71e) +,S(c4819cb5,b5af7aa2,895b81c9,31dc6bd1,de4a1434,daaa4fbf,abfca6d9,28c9965c,ae4db5d5,e1a09a03,67df8c9f,fbd2ae07,9f79ff96,410a9a5c,17229fe,5575c22d) +,S(dae02e8f,5d106f77,c8a1e1f5,4366daee,d312da83,1f86dce2,3e846e30,737d49f7,6d666cf4,73d269bf,aa7c3eac,4e5a2868,57df3661,c949b5ea,7f9a7a0d,11206bb8) +,S(a8762d34,c6f8317f,cba5c64c,68e25d55,e5bf7e4,5caadb65,a5468d2e,f9d779f0,6accd443,bb181cd4,591f8fca,210f9996,86460bcc,89dc06a0,2edd7bf3,d4b75533) +,S(bf503c35,fc8a0c55,fdf4149e,96b2d218,d29e4b9,1f703e7a,9b0d4da5,4153d99,7e1c09ab,a1437e02,a2be3d4d,7a444753,e475acd6,e3a42056,94e68ea3,cb7d1847) +,S(7898067,48cc0ad5,ab3a3449,ac82a1c7,d51f2b96,791ee038,dfceae58,ea0c5cc0,66b59634,96eb4a69,b87aa0da,2905449f,ffd2ae3f,ba1555f6,5c9b8ec0,e94ad922) +,S(25833d28,addd8172,c2a323d7,cf498482,732a0be2,c10d1895,8d097cc0,ff4c9a19,74708306,d01258d9,bac99a69,58ce1117,f245d6f1,4a1f92d0,dd48ca9a,4c7b7da6) +,S(6800bb8a,9dffe170,9ceac95d,7d066461,88c2cb65,6c09cd2e,717ec674,87ce1be3,d5228e3a,1e0bce22,c2d85b44,e670e78e,ffb1ec69,6c01a722,2cd1e62a,dc4e63d4) +,S(3d7d5874,42e4816d,af2f0897,dbb06cea,f6c673da,445a5342,c61a8793,420d107b,422b212c,93ab83e5,d6323ad0,35a55321,b7441835,b83f180f,c3803ccb,46fa4ba4) +,S(3c44084f,aeee2803,34db27ea,63339db3,9e8359b5,c9cc9a85,7ea49740,32d063e,36493b7f,1a732a87,db4703bd,61a76825,4a82846f,31d8920f,2cba7ecc,1d744491) +,S(cefffb5e,d26cf721,a51bfb2d,460b91a,a0b40a81,52073da2,cb75050d,f7fe8d19,b4e40e1,1eac7572,efefac2f,a97e5cb2,a0d042c,3ae8c541,e51be4bc,f6d33f4e) +,S(63add0db,5f5099a3,2f274c38,780cc215,bfd58753,144bd464,e75b0da2,dde97938,bbed5231,fe6d5b4,9679a13c,c3c6c382,5c300fb8,42b5eafb,13355c41,120c6848) +,S(ba5d1f34,63130cfc,425cc6db,dfe08329,4d7aef4d,cb207e3f,d1cefebc,7c791920,70df29d7,8030a8ba,56514df4,b6ecbd2f,ebfaa1b3,df7b23ea,ed16458f,f2f18786) +,S(7d363dd1,c6dd28da,94a7f850,ee753327,8b735dbf,f43e9456,67fc26e7,af75d6e1,46026468,2bd00bad,a5be02aa,5034e762,fe50d02d,6cb8dcdc,5aafa21e,423267da) +,S(e2dc0164,c9060646,904206ff,37f912ce,2d50458a,3ca186ee,fdda8d53,4184070,de5267d1,354d12ad,8d9a5930,443dbef9,65947f2a,5efa206e,146e7b1e,df7f5a2d) +,S(2e53caa6,35f0ad1c,7bc4c2ee,1e29b39a,972edbd0,7d3c0feb,9ab0d945,45815ee5,1bb33d23,ad85b572,130e93d2,fe366e49,8371c49b,b47ceebe,de3c1286,3f443b23) +,S(5dbefdc4,9fabdf50,e6bc1464,13d59940,cb36551e,5a6607bb,13213ffe,b56eba1,893fd0a6,1797abe2,fceb4054,c4f540a4,ed644ed3,13a2200b,e1d532db,44d0374) +,S(5ff207e4,2b52b004,6ab8bede,6bd26f5,316ae52c,d148965d,8a21e8d9,63374a2b,1b778704,daa94eb7,a36ad0e7,22a6d56e,c0b43c7b,a739985a,538bcc22,b9181bb4) +,S(da260b,ff4bfb8c,a54261ed,c96493d3,ffa90273,a55538dc,c9b237ec,e775fb3c,c7c744c1,dbe1cd19,20edbe3,c13f7631,1378140d,9ee64c3e,ab072401,86c067dc) +,S(b1985ca2,e7103268,f18d1063,c59d8d78,2250f450,c467d7b2,f4e41c28,1714421,16357630,3970159a,99a34c0f,e114b95c,f115d9d7,dc9b09ad,7c81d769,aeee6898) +,S(bf98e773,fe93f15a,ced03ac8,368e4276,1cf3821b,461cd844,2426d2d,cd1f7d7c,f4fe02f5,f45a9cbb,b67ef626,f239bad6,e5108c28,d783d70f,6bd889b8,6331185a) +,S(5dd657a9,ff99f15b,56c5143e,86ba7bc4,b0f34957,71d91805,71a3d003,ff008fa0,8da0b780,f644b14d,2b661b9b,484225b9,86b13038,a8a9bdf6,6999144a,4f5c212e) +,S(53b42d75,bccf2203,7252ee9d,25830f3e,36e7ed8d,8e1b6d4c,b2371e14,fd4fdba9,7791453a,dda2ca19,a775d684,9ee60c18,ca495808,6f8b56e5,1bf2b216,9690cd73) +,S(a3f43f6d,eb178109,cf4aaeed,a0666bec,481a1894,c25a4fc7,f4a87e82,680d63b2,d0331e73,7dc25db7,35625621,85073240,3a69a474,d5f78e54,93486b5b,3d1c067a) +,S(b83bea86,b07b217d,ddac9cde,9b42b334,c994cd1f,92beaa87,57a7e7cd,2c71b1eb,b68f8fd,66b45aa0,dd568458,73eb7829,1e613569,58345fba,7dcef9ee,dab957ca) +,S(16ce1de,573b3654,a0c00212,e878811b,25832f36,373da91b,9d9d7c89,d06ff12,264031fc,7441fe5d,4ce8ebc9,232d1837,7fa810a0,a0e19ba7,5ab16ae5,e93d5763) +,S(18fdf98e,93a7e380,8762e819,2b6e634e,f255b2ee,51c65b58,1ab799ff,52409e15,2d71afd6,c6298868,52ea0a1,943dbcc8,ff844ba3,80b177e8,62f92852,97868dad) +,S(3d5f8af4,ff89de18,866f596b,91300a32,a7aedcb2,a9423f4f,e364cf26,e2f53e96,46e9bc8c,ddc56d4d,ba25a2f6,e77a6a70,2e712496,7591725f,1d240e7f,9836548) +,S(69dc1e7c,11516a15,9edfa4bb,1afe0ea3,5be5b7a4,7695df8e,728a8dac,e2997db2,71be8ddd,d4c51c1d,5c13704,3aee6129,9541e929,799f7b6f,da08aee4,52f4ce8f) +,S(4e8278ed,ce9b340,1ddb1c3c,6b208539,164e1ad0,3adc082a,8d9dd5a0,9c63f737,13e6a5ea,7b2e8ebe,babd812f,2579b8bf,56b476ce,dd23c418,9be7b85a,940c5d79) +,S(91157569,7aed20df,771c1f4e,78b73dea,c89b2781,9b8a5ae7,5e2dc12,e6e7d148,e7114d60,218eb1bd,73074957,5b96fd10,50fa2d09,f37c0fe6,2887042,24ca1a28) +,S(3a37e743,bd2fe2f1,3f667abc,b6c03077,fd82722b,859d7bcc,ebeaf1bb,a6087d93,4192a6b7,eef51034,64040fb2,6b8d9928,21e321b8,cd611b4c,8d3e0186,646f5dad) +,S(d45b5787,9e4732ad,ad0996d5,879980a1,fc8dda5c,b628435e,96c3b44b,faf98f09,e4d4f5ac,1e4b039e,731143d7,60e2ef35,dc243097,d2e2382d,b86dc82d,eba0554a) +,S(ae5ff450,aa607a9b,bf4549d8,4d96adbc,6041cb0d,719793f9,2ec53b96,14522a00,2f061b20,e9bca3af,358e8d14,a04f1d82,97d1e1dd,a406d60a,d15727d0,66b2b8fa) +,S(befd3684,32785d19,7709ec42,e3b6407c,7a539b55,d97c8fe7,afd4f96f,d2050e17,65691153,b2efb4af,ebd2dae1,a50fd3aa,b648c7af,f5804d99,5270cc22,c02e151f) +,S(d13626c,bc00cd,36c776c7,8bdb17c8,18a2bc14,9612e0fc,7ab7888b,eab48382,ea4c3fc9,fe2238f7,1023ab83,fe0e09a1,dc167c0e,6aa05933,8f177cbd,241bdd45) +,S(9730fd42,fa9ffdc,414f90dd,ac790110,9619c01b,f43bfcab,e65a341e,2434435e,de61024,6152fb04,c997fd62,961209f9,44badeb3,6ea7774e,30e8c8a0,8bb0b496) +,S(a27e09ee,9dd4e34c,6a92f4be,aa1b8c0b,2a60b33e,99fa981d,afaac623,9f616d15,33e6d8f7,bcaaa24,b6008e44,377b4892,5f88e884,5fe73807,8cd4f405,a2747f14) +,S(d2dc7884,31e5a497,3905876d,bd6ceac7,8246c9d0,73d68872,f54685eb,5970763c,85f96d40,e31ecc47,dc07fea4,4856068d,15d2a999,735aeb3a,4959e4f9,9ecf5fc8) +,S(38fe7a6c,c401daba,981875a0,f0c2f528,30ce31d8,816a1d3d,47a3d96a,664a02f7,e9893a1a,87034596,9d95e644,313d9b65,5896a931,81d36f6c,7e390102,3cb28c74) +,S(f2d38ff,14100172,d117dff6,1522c61c,3a590eb7,ee9fca77,dc264e60,32291d78,94eb4046,ab31eda3,7593e705,792fdfee,2e3df8f3,655befa9,ef0ef392,4b02dab) +,S(9e23c290,94b6b8e7,4e112b11,69c5c775,4b690d0e,141b74f8,2988bd84,78d42021,e2528717,28fc8d9a,283bdfa3,a011d28a,f531f392,b5da6da7,1834a29f,203e747f) +,S(3054117c,33c15a,504156e0,97e9a0f7,d76be8a9,c1c88fba,e1d9d2c5,4e1c9185,998844e2,b73e9468,1b0b09d7,4ca48dc2,f29c6df5,f3c38f7f,b6846178,d4ccae2e) +,S(65d1e830,3421444b,7d5f8600,2c6de12c,16f15a88,504c6876,b9e94cfd,a206810a,71c9cca1,6e066545,b11e2c29,edbac8f4,8533ec41,1e331e15,a2bed53f,1b1878db) +,S(124b78b8,948c4374,7c5b32de,50cbb055,ebf9fe7c,56437573,40723180,131ec0dd,c0fefa74,970829d9,4c1314b3,64a8516e,3a3c7fb8,e1d49f06,b1b9c19f,be18ddd6) +,S(f6d81a5c,395ab698,28e5f1f7,84edc6f6,a55137b1,411baa28,615abdfc,36c18567,3a759acd,4b758dbe,79e22f4b,26774b88,40121768,f655664f,c3f9bbbc,91f564cd) +,S(e76bd19b,fe13dc17,ddd14619,da6b12c9,f2819514,6acef71a,9e7bc32a,7abbea8a,68cee27f,152177e3,afa7d47,903801cb,b20ba02a,c48fefd6,e23fc102,e6456bc7) +,S(7356c0d,ff8f26eb,7df215c5,cf923c4e,237fd7ad,cbe58f7f,d5c745be,6451a830,16a0d86f,ebcf42d2,e89e9a1a,803838d3,1dd7debc,527d49e4,a7db799c,e1eeee6) +,S(b8d00a56,43fdc57b,dd949193,c5df30d,8ecf5b4d,8b3a13e2,64ba3ef7,c8bfacc9,f05acf53,9343641c,3feac336,28e9b08b,9a4e3c49,94c029aa,470fde03,d5d8cf8a) +,S(f555e29d,4dd3e0eb,d03f3866,596be43c,677d1ac4,1a1a3a8,1936ca6c,89618880,171d88d1,9abf05a6,981eddea,8f030e53,117a2e2a,97c2f352,255038fe,32ecf95a) +,S(172e6167,6e7755f3,c6a59c40,97a8a870,cdc09d73,2064d24c,3db8ada,7ca50ec1,7c1e58e0,38f322d3,e147b3db,e9b8f311,135d688a,98458da9,f6f8a6d5,4d4e2a96) +,S(f8f5fee7,d4e8eb51,92cb7ad3,9ee26cfb,44724b7b,f9c74fcd,61f95e3a,f33fabc5,607fd05e,361bfd66,519b5e11,d00d22af,8b0ce85c,11b16cd8,eaba71e1,2ebe6bbf) +,S(6fc770f3,f6169350,bb8b247d,16088031,4348ef73,cee49e5,c0f56a19,d2d66491,47708f10,80e755f1,2b1b0d9b,3439312b,dca07d85,fe94fda8,414dbdc6,ed9353de) +,S(2b8c0b49,94d3f78,79776d8f,bd2980c8,7840df15,82427cc4,f07ac806,eb7f7e3,3a335552,ccb38312,92a71376,9c7994e4,19a7919d,b776ce6c,db2ff092,92e4d798) +,S(e473c99b,dffad22b,72b6fcb0,d741179e,afb78aa0,de4b5d42,dd19d7d7,72ab1a60,2d0f795c,61ed1ac8,b5691d5e,9d52b19a,42c368fb,9d0787fa,8ef3b275,2a3d9d26) +,S(f389dc2d,b76a47af,f9d7a380,ab49274b,1a40c4f7,970bfa63,729da698,b4afdc4e,b15c2100,b63f7f5f,911a6474,25866d79,5a57dd97,74c21cd1,4907dec0,f5f3afab) +,S(df6e3625,8fdefe31,dffa19ff,2416f8b4,9fbc09c5,e86569e4,4b7330fa,56cb6e1c,4b5fedbe,835f0b8f,ae20f627,c8e74f41,a5443c1,a764c466,65f673f9,f62dfc7b) +,S(27e40da1,a5d7cabc,ce586e33,a4ace757,da972cf6,17c3781f,3fb0e0c4,e6f0a70e,ffc4b339,9cc0b701,36d871ea,a7c3a6ab,fa9dc92,72625fb5,b8bde8d8,be55904d) +,S(71b6f20e,e558ac12,829362ae,53900a59,ae29cc70,77dd1001,d9d7eae,36b95618,e765adc,1125219b,316beb88,4c0434eb,a6f62499,b8b2d217,c209c7cd,622d0597) +,S(535d5fc6,1eef1a92,50ceaef8,e09e1797,8debd360,8b03f72c,bfe265a2,633332e2,f8453dc2,4ad1ef7b,819d4329,a4752757,26c98e55,65440cc5,b5d509d8,61c98a38) +,S(d1e2222a,26817cd3,a537f2fb,7437ce06,ce9fa651,9d3c1967,71aac21b,97de68bd,a131cb69,cbd27e62,cb65ab48,a7f3035f,a78ef40c,6c42e94e,da326ccd,2b452849) +,S(5aba9590,2b5062c1,59b9639e,f08912b8,e7eacda9,759a4e98,b0e21d96,c2597b07,896a74fe,e2596e46,1e93f4ca,178646cb,4bc5454,227a2dce,1bb5d532,e558b334) +,S(9f07bed8,4449bf9a,815a546e,ffcbd0af,f22c9016,188d15ad,7c353e2e,5cf84343,6fa14d01,ba16dd07,15f3e68,d57738f7,1cb56d95,61eb84cb,ad63bbd2,d9ba439b) +,S(80a1920b,14723439,cc2090b7,189f96e0,20e6eba5,5f8964ad,2f0be013,b4925515,fdb63791,6d074376,8e32f983,f2ff1754,43136323,50b98674,2ccb9ae2,7997a020) +,S(dbb37c16,202dfd9e,914f2922,e8930789,a70d4de0,9fe7eb25,7d9a2b83,aec2b4c2,f6bcb8a,2c7bfa20,491d3fff,bd36e82d,91a7228,9e4fb6f8,9e167803,a17b7932) +,S(f03035f2,f0ad31ac,59e64a6c,f46e9ee2,a2243ee7,de5ccb0d,cb30083,97551b4c,1a1aacb9,798651c1,2bdc6ce7,4146e259,4263474e,d7b9d42d,78026331,60748722) +,S(1886fa45,e7447e89,b0873362,605beafc,4e05965e,53fabe41,41e1c42,4fb234d5,eb5374d,a4a198cd,d9027311,6b4331ed,f0f6a7a2,fc52aa44,8a9274b9,ee3d7743) +,S(46a262a2,5b76baf8,ae0ba3f4,ed8f86fe,e4854272,cbd0ed41,313c4e0a,357471b4,c08ee494,66d7dc12,a8e08880,732574e6,f6fedbf2,71d6dc37,eec3c324,33d8070e) +,S(d521c6c4,a0db2668,5a36b61c,b73d3504,ea7b7488,e3d75410,494e89e4,ab404d37,41f334e7,6a28cb9e,25e6efd4,fe3eee2d,17480189,b921d726,aa027b3f,75f94bfa) +,S(8f44a4e3,c18d714f,62054e54,6e9ca86e,818fcf39,fdde40c8,3044ddbe,be3b951f,210ec152,f8c90d7b,8486d1f9,c5c49a48,68249795,bf7d0171,34d9573a,d5b22aaf) +,S(d5a74098,eb20aaf7,b664fb8d,63e08b0,430733f1,466552db,417ec648,36a31dd7,7eedeaca,97f1c85a,98496159,eb024564,1c8ef0dc,21c31ff8,9d06012a,3387647e) +,S(d2a63a99,d6ab9e57,a2a6d39d,3738c3bc,94505332,2a34d3d2,4cabd1ce,5111bb08,e50f6c3e,796ac830,e276fac9,ab6738b4,722fc87,880f2e93,7417198d,9c6c1323) +,S(a1b826f2,1f7abe38,c622b93a,7510114d,dffe4cb6,d3fe0627,dcc0465c,bc82ad9a,c9cec051,a253ab24,a8507b07,d24ee4a,c1d5a5c7,33f0c3d5,611e8a9a,e4aa9667) +,S(40719ba6,89926b5b,ca99a4,161a1bc,d999d40,2311fc5b,e2f5260a,c3c10208,9edb353a,73e9fdad,96ca6b77,b467dd9,c7d6d2c8,e041d8f2,19448ea4,c603bcd0) +,S(c0ee8dda,80fed10,721e7cd8,9dbd237,216f4e84,bb8f7138,11f8ca16,1e3a0977,6a786e53,2a0f49cf,eabf0338,1d64de56,1a1973c9,36d6a5ca,4aaf4cba,b8fbe1e7) +,S(9c75860,ecdeaf1b,c598a530,48a22158,8099afbe,20cb08c1,3afbb133,b2681809,d7019eb3,5fb61aee,56a1afaf,2675a028,b8735dcc,b3f5d93b,c3e29672,9203321b) +,S(e39df640,6dbf2584,fecea5bf,aae78b5d,bca93ef0,9054c754,d8b235c2,c5463657,33ab2fce,3a2e3e7d,e2ab230b,e69bcb7a,4d71c87e,a1ff5d34,eb8b78f2,d5c61a55) +,S(22480e,4a7cadd0,d17a418a,78074f80,c4731ce5,d9f1268b,1ca50204,1ff8282a,993591da,11ea4445,8ccf8bc,2cd55fae,69e96a77,89d006dd,b85a22ae,85316200) +,S(c613fa66,231d38b3,359c3b94,132a2337,e2a8c608,3c88b41e,58434c19,48a6a1ca,8087377b,c3d6ca30,8c932dc6,ff82430f,3fce21c0,1a8b8b6,c28bab78,d3ddab43) +,S(c0a94837,c2fb86ad,ca791fb,bb0838c1,3bb0c981,e23c4ff7,94dfa5fa,c663e5,1f81050e,d21fcd5a,471657fe,abe6fccf,a391f1e1,9a88c143,4644bfb5,e1f69f9e) +,S(87ab257a,cc2296af,d921bebc,8e52fab1,c9c21f08,ae09faab,18858a06,1e408ccf,d5dd88e7,89d2f2d4,3773854f,ca980411,3dd69475,a56864d,3c869205,d682027c) +,S(10d14c28,cf44c5d8,fbf5caf6,b307f6f,ee203968,eea1be3e,b3697515,2edf45b6,46926a1e,dd4f79ad,74fd506e,4443375,23ec76fa,e09d216d,3ef3ed4c,73b635fa) +,S(2eb78fea,63035a3d,db64149b,612832b0,c9ab7880,539c67e9,d722e252,f7e23166,4f72ef76,d3dd59c0,a4e1be46,6ca5a3ce,fd84d207,f7d671b,240fd41b,20e72af3) +,S(14d8ab11,402af341,dc5cbb6e,1116b858,14decf11,e6761b09,31b449b0,20b6f56d,91bf8c4d,cc717657,990e0e3b,3558a01f,ebbe534e,897d1204,8a7d978c,3a1d735d) +,S(cebc042f,2e7bd361,934da5e6,dd2dc8a,9e73537f,5d5e3e46,3a88bcc3,ff6d5552,baa841c8,5e0a7287,b1f16c89,8ef03f22,3097e92c,44952c32,45f2fab1,dcd988c5) +,S(4f28e546,ef539c7e,8f33191b,897b7245,8f48a01d,79f65b8e,a8f672f7,d0ab027b,b1c1db0d,55be796d,2b415259,89088a7,d86c41f8,cd8ccdff,2bda49f2,407123d5) +,S(c4d31178,b73cf9ab,b0e1d554,a2cf93db,ed9a7b9e,8f49c9c5,4d63c815,6e111505,f5e4528,7089cd96,3118e279,bfc6661c,1e77ab67,b81a71bb,4ec14fe0,ef0c13f) +,S(8e260505,bf045c43,f3fd972e,d4189725,a4db0774,52f94eb9,51e42eb5,6131f0f0,4afee681,c6069893,5ce21991,208457b0,11548d97,9a33a0be,cf3c840f,77c4b4d8) +,S(982818ce,69b4c6f7,631daac,868af6a6,79fa6631,8c9da2c4,bac994ba,f9c95d81,f5b13c91,e7593e5b,69c85957,6398b186,8c503b6c,25179270,7e602f52,f30ca9c9) +,S(75c2f2b3,53720779,8737488d,16a5ca6e,dade382b,78f2b2b3,226fd5ed,6ac6c855,95aec19f,b97734cb,8426e530,afda15e4,c3c3dedb,2aaa24f,7ca73b4b,af475960) +,S(606ed5f1,8e4dc1e5,3b6f5ae3,896433c2,a904cb84,1ea021fb,84537f6a,9dd45ed,3165cf75,26f277f5,b9bf22e7,36291513,10158d63,b97b7c88,d49d88d2,d63dde9d) +,S(a33e07b,c2934f5e,f02ae143,6b3ef5ae,d2d633f4,2b40e35b,d365fe2e,b8c72d51,e93cfd7d,f2e98817,9eb9c348,73530504,bc5cd8e5,d8393f0e,844073ee,df6d6511) +,S(5ee1d077,735a4a18,533b36d1,eb484f14,98b220eb,cd41746,b0947403,d6b4644e,7d4e1233,46a6ba1d,8a862514,4d4bc5be,72e23d,f25287c7,3512817d,e632f8ef) +,S(7485b837,2bb28a8f,d496f6a0,33b92ba5,96202661,8adef933,d6aadc56,55765b0b,a58defb8,deb4445d,80016c9f,5c04c2f6,e06986c8,cc95da94,3105d8fb,d0fe84ed) +,S(3a321f94,2268584c,cac5d8ce,5d6011b1,22169e73,d9093b2c,e3e0bdf9,ad680d21,99fb13c0,ecb6c544,1347a4fb,842a7269,1492219,f9bb7c25,1916f837,7d4e2cc0) +,S(c115a2e8,265c6005,10bf7108,ee30bee1,77893d5b,ab0a8cc1,754810c3,3f112585,e2f0a636,5836a24c,7a5c6997,45022e8d,e0b88afd,37737c84,d1ae437d,eaf0b3d3) +,S(d8895b97,cd390ca2,cf8e6093,c125541,1602fd98,97074a8e,aa11bd3f,5b0f3c1e,af8c594b,bd2308e0,12a632b3,1d05a25e,23247f75,6d7a22f6,fcf48cde,28056ad) +,S(4ad1fd48,e77fe497,b4a15e7e,869377bb,163d760e,105e46a9,a5477d69,fa944eb5,a96cce4f,e2f5f590,17af2359,1dcbda3,b640271e,95290d59,1fdcbd8d,ecf39703) +,S(62ffcf4b,7ce6c5cb,76766893,bd0a6f2a,e33ef821,d953c001,51c4be3e,67f2cd8b,d6b1d025,152db954,968ea1bb,dd2a89db,16103f55,47cdd042,9b7380f7,c4c985f8) +,S(e71343c3,cec5e49f,60fea970,6d256a4d,ba499e86,6f9ab33d,6045a1be,cac40a,ee1fe3df,df226027,78228bba,91afd126,a96fc10b,f5d2cad1,26091119,3a92b426) +,S(31766ef2,f3531ead,2c7bbaa3,279e81e0,b040182,ab78065f,d193061,2792035b,87b93ca8,91151ee9,775669bd,df2e5bf7,9f728d52,efabf584,352ba4db,8cd6f6d7) +,S(1e8764f1,982a97d8,b65a0a60,53a2fb5d,39f1221e,dd4f532,b007b2c8,c52d39f,8ed84e0a,de68b789,5ecf8c07,80ba0b26,53faeb49,3d23a453,cc23987a,b51f3a18) +,S(e249cd91,4e35f97c,92a07f4d,6f9961bc,d7f6efe5,ccdfd44,cb3bb698,9939fe43,9ee2fb47,4abdac66,5bb0178f,d8ff3bef,6381a90d,bfab05e4,a9e5566c,cc362ffd) +,S(b9a28764,d21db971,f7cb0c1e,87c9db64,ee6a1acc,485a02e4,5d5ffafe,ea1012b9,1b55a989,43ff4fb,25db6aa1,12d5c459,b1ee0fa3,aea913cc,54878682,f625e882) +,S(5d042803,9f8c37b4,dc92a9ba,43bf7213,971488df,be699901,31820bda,c0b6ff03,1ffd5348,88796c6c,a631c3a1,4773f89a,ea6d5914,bcdf27c,38949147,cab8ac1d) +,S(6d817b42,52986e2e,8ecb908e,99011265,df0cff59,61a82b2c,baf0c61e,c8b22326,55cac99a,d6a70b96,5559af1f,c5b67469,5d653662,bce7594e,22916fa,7c4b826c) +,S(9b069431,297f0d35,91451039,df8a382c,1eba93c2,f62f4e98,90e54559,39916ae8,70bf9138,a04b9f14,2841a2e6,bdc3600f,1b22c81c,ba27f308,19a763b6,e64fef71) +,S(dbf5e41e,d83110a0,5dce4bbb,bee05f0b,f9700ef8,273b4bbd,57099bc9,460050f6,e3e8f5e1,697b05b1,23632b89,28c3b34a,6cf1e6f,327b4252,c3009046,c8406404) +,S(c8ef12ee,22aaefbe,9ca024bf,ba8fd744,d7c5d489,663cde66,a3ff1dee,8174ef33,db64c2c,db21415,fc552968,fbef01ed,131db2f0,1ec8372d,1b9da98f,4792e8e5) +,S(3d086c8f,af84b66d,bb9212f1,512663b1,793d6893,23f45af,9bdd17ba,fed8d7ce,2d6a47fa,9e1b6c20,a2cf30dd,a99547a,b9ab9c13,5ef86ebc,280ac62d,2ce7847c) +,S(e173d58,714db8bc,cfff3ab8,8cf1be0b,547e03f9,db60c97b,ba5a6735,cbf4bf4a,44b8f991,6764f393,68b36b56,9033e304,7fe90662,70758fb6,85cc3f6d,e31b2fc) +,S(31ef8faa,90826125,66e739cf,299de928,68c6027,b882978e,f72d014c,4aa4f379,9fb9e021,fafac237,8d21caf,f1262d7f,bd9b8333,eaab0fe8,8a3499b3,d153a2e5) +,S(5e112e52,2997b67e,146b998d,781bc528,7e2ad47c,b2c5863d,eccb0873,fa088b3b,19cf3f06,d3c1fdeb,8147e074,a42fe178,c0b14135,2dda5274,50a7d5ce,58d3d441) +,S(9ba2cddb,c1a5153f,89e9144,e862acfe,c624095b,8cf8b7a5,b15edd6e,c7b70eae,f032469b,9527911a,92dcff6b,5847fbb8,9f4ce42e,f20b40d4,80b3a58c,72fc805b) +,S(9ff7e46a,4e2c6e9a,d5843f4c,c5e112c6,557babe,723203de,d75be7eb,179e814,ec890ac0,2ece651a,6614bab2,1e4944a7,d248c886,bebb33c3,36c28df0,69be91ff) +,S(2a13752a,1aea6e21,d25ea21d,b644ab0b,fb84b130,8d3f2083,be26098f,fc4978f1,18f4936e,65ab66db,11bf53e5,7eb7d114,4820fd01,ed827f96,652514fc,d8ce910f) +,S(a0647c4f,2b4f271,97f3fbc3,bd81bc7f,f72d964c,1bcc131e,caf9bda6,57b356d7,5e023102,9a8eafe8,9466181a,80440196,e850390f,d42dfbc2,1d3fbf6d,6373a56c) +,S(6abaff96,aeaca928,ba9a0503,dcff7a51,420feffc,33b1ad53,b1a7bd57,8c641ede,ab59c03f,7ad47f73,df424882,dc3ac2bc,dc2ae6ed,3eaae48e,b807b010,98dc0de2) +,S(442abb18,54161ba2,47fd366e,52d40d56,65293573,c339aa2b,28dc67c6,70f4ee99,c3f44b44,d13ee3ed,4ffe5188,c5134d60,a28806b0,687b5652,99924655,342a5898) +,S(9f54f23b,45f632c1,f05245f6,c5d1c433,9e18671f,da494eb4,3bd22be7,b1610096,25c9e532,1a5563f1,f47a1e4c,99d6def8,541601ac,8420de96,190157ed,aa17445) +,S(50296c0c,185abbc4,1c86f578,8dad10f2,7f76074e,24e931db,53944b48,6ddee613,81a02b32,b1edd539,37ee1c78,ab630f2b,45336e16,cfc560f0,adeb464,fb71b9f8) +,S(39c2d099,e2892b2b,1b6abb1,a198305c,ed59d94,f7022cd6,d521b510,9a8fc219,8900f6e6,3fe1a7c7,27728b92,aea4d70c,1316570f,edba940c,e626e94e,f03dddff) +,S(3581e30b,17067e44,664201ba,d7a6ada3,e0648516,260b760f,b406dc48,11c9d0f4,c8bac129,83e49250,bc478ee5,fcfc0660,37d68f9f,fda1acc3,6861743e,d7a794b5) +,S(72b67dfe,d341824b,9fa09057,b8362d1,38287eac,7292610,1169e41f,19dce477,be527b0e,52ce07a6,99065bbd,ebd360fb,72c6dc77,88030aa9,45fbbabe,7f038524) +,S(805af91,4a973e36,43712cd4,4a1da4a8,3d1237e5,9c991387,17175aec,4a8667c4,f6a7beea,205810ff,5d1f0e8f,5818854a,bb730c7a,1ddf02c0,968b1b05,92ed8a15) +,S(44794289,4b297a87,e3cdeead,5cb2dc42,9fdeeed5,b8038189,331874ac,88e67536,d67efdbe,8d7ab8e8,1e25c340,77687b94,d22d8ec,b89d7f5d,46ca212f,abcc1b5) +,S(b73347c9,baa967a7,5e5c8ac3,14f3c6cf,275cc893,72b26bee,731693cb,48d36df4,307f8fa1,98f1ba57,7ba330d5,816cb8de,d9ec3f13,6bec0586,53c64675,753f1542) +,S(ec6d499a,efd540e9,357f100,4a136049,d1f7df5a,d99c44c4,6e3ed416,9e40acb6,21e8082c,df4fa2a8,38327e80,aac15ee4,40549109,aaf6ea01,ccbfb95d,3f7a47c4) +,S(7607b7ff,8bd8369a,67d22545,c40a1588,aa2e50c1,b5be6115,cbb8794e,2085f283,6c4a9aa2,1dd2ad4f,7d6c4f02,23885803,ac3b06fa,6c0772ec,bfb610b6,a1d25ea5) +,S(dec4b7ae,42e8a25,2c414458,d4e0d7fa,4bf4d0,c9432754,13d3b770,8fb53839,bc54d902,6d035b64,35796475,67805bdf,af6cdda4,d0177206,384c4ca9,8edb5898) +,S(a7be1017,82bf48e8,37c2e0ec,821e37b3,eab03607,36561152,a95a06a7,fbb7ae2b,dfd27057,dfaae0a9,b9523a9e,dc28a2bc,3631e84d,5fdf8c3d,e1e65055,805fe0bb) +,S(cb398b20,29e55994,741b87cb,592e9099,926229a,aea60bd6,30eaa528,726a04a7,263e89b5,85475a8a,50723568,d3328fdf,56c8fa8a,f0f796fe,7b4d2fc5,9aafe2fc) +,S(438a6d60,c289dab2,e8933153,5c2e09b7,a677cfcc,a605ea72,8815bdd2,615c852c,109ed19a,51e01f3b,a9dbea30,f652676b,b3a8afd3,5ab5178c,ae557793,13025f) +,S(4db8d4d,882fe513,e5738be2,347a05e9,2c97816c,b39339b,adeef99,7b682e50,88280370,d13551a8,a9803a28,c56bac47,70feb07f,56a1a0eb,d132262a,f1ea574f) +,S(ae2ad953,bf13c4c5,c3fd5ba3,389323fc,260de722,e36bdbae,6db77b2,1c0df210,a5866bb1,7580958,df07c171,80606be1,25b3ee73,9c3bae92,8fa35e9d,8efc7364) +,S(85b3809a,3f772b20,dc526b9c,19de8cd4,9c2d9814,df4a9b60,1aadd016,64c66c9d,984a8061,2ce95364,b9819440,551ab1b6,4028f61d,3028b725,74dfbeb6,8c174cd8) +,S(7e2ddaec,e443396a,7c7eede7,ad96c2b,63faaef1,66109949,e7431b06,309259e4,3aeb7f92,14fd37f2,aeec1921,e64e7a8f,e6a4c704,dfbbaf62,779d0eb3,3b1e81cd) +,S(4565a74,6cd1d26e,962bebb4,447985ed,7b1622f3,faade84,1291d694,17c3ea84,7215d7b9,6362fcd2,320c0c29,e0b304d0,ab174103,bfd372ef,e6e4534c,64ff3708) +,S(aa8c5a11,712aa04d,a870bad1,606c9549,bbf676d3,1ea5b260,27bd1055,ed56f996,11ec28a5,a7435436,3d302f23,24eba092,68028664,f0ebd323,cb7bc587,7d92aac5) +,S(d9d5c0d4,b5a3305c,9f057dc9,8ecf7482,f6d825e4,69a641f2,caff9180,b7096e0d,d2b0eae9,cdf57651,bd296ad2,f4403e77,d643db66,fadd7a84,27a150f3,6d547ec) +,S(2ab2e7ea,1e1bf61a,8bedaa4f,e8fe3a7a,db66c25,ed1b7ebc,536efc7f,8de22777,28806bd1,fc7dca1b,a0cdc177,908e0588,605f8c1e,e76cbc07,ea05b6ad,80c0e5) +,S(2da97d42,a9d064d7,38bc7fc2,f2db39a9,588d57f9,8094903d,cdaf5054,238c1568,fff93946,e789b902,8694ff95,a68a7fb2,981ca0d5,d2b6de3a,b3112381,b8360f1a) +,S(470fd28f,31418f2d,70367e4e,961da5cd,af8d0255,5bf6bcf5,e7db8967,6dbb174c,59a49444,2a250264,3faf843a,cd242640,e3622df9,da6bb1cc,6c956b7e,5a26078b) +,S(e41bbdd4,6b78fad7,ee62c33,9664fbc7,e884f88e,dc184e12,715e8368,160a7ef5,40252593,7979b92c,f72bfa7d,b3f378f0,cb4de758,a6348c7b,2b1d73d,57ac9faf) +,S(9761799a,7e155a4d,e6aefab,963b23fb,1f17d8a9,cc5f8c64,6d4dd638,2359c553,493bb00,3ab38aab,cb4d4491,b6b9e8ec,ef068c9b,933fbb32,6e0e1c75,ca44bf1c) +,S(d59fe2e0,5fcdcc2f,dcc22cb,b9220051,2c936bc8,2205f5df,75267a5d,b45b1245,68af556f,949df3fb,d8299f05,f5e85874,57d109bb,4d395634,89d3ac77,3d4b7b2e) +,S(f8bf168b,8a03f3c4,8e7568ab,ef613bf9,3f515f71,93a24b62,827455a6,c6bdf142,434f350e,8eeba6f6,d8f07137,a33199b8,88907744,eb547384,dcd96aad,5f9f3911) +,S(65298ff,636b442c,8c45e748,c3cd2d1b,94770ff3,3bde1d63,21135bc0,89ed81d9,d0aca445,cf460f5f,47090202,2c84fe1d,ac0a81e0,b7458e4c,9b21dc34,8c223ceb) +,S(d1ac0d0e,25dd02d6,fea02b6c,c98f4b17,38046416,93258208,f04a81d3,450aeaa5,be491f07,1833efce,56197dd4,d3471eba,2a23491d,f09a87f9,8a4ff14,257d1dda) +,S(be876d37,fc1605e9,ea0923c4,e53497a3,8d51190b,dfc3dbbb,3191a483,949cae1a,8499ad31,ca5acd99,4a98caa9,2a91a321,5fd1f1f6,cd70c463,afb91673,ab6b3a72) +,S(7c440cd,aff0d8da,6fb5e2c8,fe27a301,c2906a63,7d9b1bf2,db848f13,175de738,7dd6cf71,cb013a8e,9494cca6,b418fb,e99e9c80,3ff34d35,e586fe25,8ffc4fef) +,S(25086ee5,f0037c83,e38abbaa,e0e3356f,c49020d6,f9006edb,235937a0,4d7074fb,35c21eff,8cb888db,d3271a5c,4dc1db52,2072e58d,974af68b,4d6cecd5,d13e582c) +,S(b1a7584b,6f43a593,363d6e62,edade636,55ffc711,48e6c9b4,2915d0d5,ebf4dbe9,f418f23a,9dde8808,59816098,ea06d2e4,dbad3385,737b7bff,a1b339e,1b556718) +,S(87e1c0c6,aece59e9,1118829d,ba8e0271,db30409f,c08dd790,4296b91,43fb7aae,4694c5cc,176cf309,e4bd4935,b88e2fb0,e7e1b63c,28c5bab5,d3356733,184ef152) +,S(19f43d3f,4bf0f2b1,9a157f3,3f71c5a1,20e2135,3187b508,e568dc5d,8131a2ea,3ff130d9,835e0eab,2744cdb2,5607fa63,edcf9648,d910e25f,b885ba9f,b340860) +,S(a7f9239c,5e8e371d,7d175c8b,120816be,2e543d89,a22c3f7c,5478ae1a,14f8f6b8,75711a87,561fc767,93510d5,47abe6f1,678d0cd7,335e7bbf,b87abbc2,cc3089e4) +,S(9f3598e8,f80cee53,969a79a6,d3b655c0,66283a8e,f2c5d7b7,8ce89e67,5d06446d,d9cbf50d,c2aedfd4,51fcd93a,46245bc0,772e9f9d,fe5a25f6,3af027b2,ea1edf79) +,S(cc00a72a,66dfc8a9,e7a4edd6,699764ca,c15140e7,216daa59,cadf0edf,d1e3267f,91b10836,c8ebd031,2f72cf2c,cf26c89e,1489c100,c72a04cc,71c0d08,45c27d94) +,S(2dc7758d,b176a48f,f3117aa9,671f7b6b,f0b2128a,4bc60fc3,f907eb1f,d20ff347,afc82704,39787ab6,bec0d4f0,7b7f2896,43073cfb,65e9d3ce,db8ff7b,791f2f59) +,S(2502f7f5,8dba7c37,bc4637ab,8c77c047,700dea3f,5b760ec7,9b68121,9cee008e,f6fea3d6,4e776f5c,cd293dd9,4109d6f0,1e55c039,c30438eb,6e626489,c92f078b) +,S(70d39d43,d7f2092,53967479,de620ed2,bcf963de,6ceae3b1,a80fd275,1801382,fef8bea6,45807be0,e1c5c3e2,4d391d8,bf0a6b33,564749d1,4fcf4ef,a8aa7133) +,S(a09962fe,9a934004,bc31f92f,526ff444,da7889e1,79453a55,b0fee769,34c69c2,dd717079,8cf19b8,1f55fdcf,86cd3755,f708256e,694fdaf5,f929c967,eff687b5) +,S(355a2555,4590dcf2,84ca548f,9ec9f40b,22482773,cf122a40,25ed416b,9d29c692,549ed0bf,db861bb7,4684ebef,7d70ac56,3703997e,c59b1f86,bb4b5dfa,574a2f64) +,S(4c145d2c,a165a5a8,b66f7fdf,c16bcd5c,c22304f2,f0ec3145,9b9fb0fc,797c9b9a,7cc14054,948caa4f,be04b54f,1b60a51d,cc482fc8,c94825f7,8de4f4a9,a63f8d5e) +,S(b5ac199b,fa591300,6d635fc6,86d87cb2,52c5c67a,6b897a09,bee578f4,9c57f8f3,41e164ae,d3d967da,94f0cd06,91cb3ec0,79c5712c,279b3a8a,d75affda,2879b234) +,S(ad619913,f00f620,38321c3,59931a9e,fd26941a,aa02a812,8d9f3bf4,8818185,d7b5a033,9e4b8ab2,bf66a597,45c0b496,b5825886,9084d306,660670f3,a9de912) +,S(f8314cdf,d7659ce,e8377abe,f4c80b00,9c99c1b2,f2bee37d,a726c6d2,a1deea90,db5a45c9,a7ea22cb,dba3a784,131ee81c,2a1d9edf,d9ccb9f9,6fc93d35,a332eab7) +,S(1fe1bfca,5df9c482,68e88661,89e238e3,7915957b,aa1e0c3e,af317d12,c2f84650,dbe03060,745396b6,fb22d6cf,a6b27329,3b3ed08b,a24ddb38,8942199a,765d7414) +,S(c414da43,814bcc43,31269d58,1c0a8c14,9e304f5c,13614a89,7f414725,9ed39070,ca194f90,dac3f722,6090b94a,3b94db7c,5c68931c,7461619d,8b912692,4fd90a4c) +,S(81a098c3,d1ebf427,69f621b8,3eced558,9dc0faaf,24206f97,480e40d1,25faba3,fffac91a,3b729698,b0b26f8a,e6391b1c,8f8327f4,7978b011,d7d1cebb,6b0ad8bc) +,S(f99441dd,e4332003,b6421463,b4bf6595,172121d3,f000763b,a40cccdf,be2cf439,231fa7c3,fffcee74,bd111f18,3689062e,1b6b366b,2fe14440,2061de8e,4688b3b9) +,S(2f930e6d,e3586768,792e565c,211e1abf,99e05fe8,79c01083,3e6e5121,7abdcc60,2d51a776,209a3da9,ca4dda22,7beea48,a93a90db,b51f0721,2864f36,a56424e7) +,S(9f8e96d5,99fd07bb,e9e0010f,90802d25,4b30e359,bf0fdcaa,d6e782da,62c6d25e,baeaf150,de04c7ae,d8d34278,aba6eeb4,9b3f213b,fd56585d,41890632,d6b64e02) +,S(57f186f6,fa5f4aee,e3e8b44a,d775301b,66d7fedc,4ab8c827,cb138386,64727f10,5a65c0c4,a69b16e0,1c32a95e,77c8f99d,53bc15af,5c168457,19bc8220,d7baf849) +,S(d344361d,dd0b764c,be16f46f,5efe166c,10a88bfe,bf532a8f,a1fe138a,78e0e1ac,dc1afcbb,a84b8524,a5d985ac,5506f15f,d0b92f85,875c2c4a,4144a93e,e455792) +,S(444163a7,58095900,e5c8fda4,88ecae95,24fe54ae,2592ae53,7e6db41e,8019344f,bae54b91,e69ddcb2,c1bf22e0,bdd721b7,a9ca51b,dad93b28,59e09509,77c26488) +,S(5ce2e1d6,46f10fe7,e4196414,37fa2c16,48029fd5,5340d2e5,f32d467,e0c4e222,6e95f538,cadb1b56,8313429f,35fb925d,d9ba571d,bc6f3970,ff4fd276,4228e82b) +,S(8b7226b0,8525a07a,84ee858b,58c418d3,1d4acdaf,9b081761,56b83a8b,fde6d773,684e6dc,37a2ba2d,89c0b01a,b4e1fcc2,1734eed8,2f7b1509,6724acab,5e276006) +,S(6aa5e306,36046384,ac8e3da3,f2f00713,8acaa0b,b0d12ee2,1e69018a,4d0554a3,2144dece,31a7453d,3a07e290,cef1b694,f393e5d3,f6cb07b7,a8c991b5,2a788029) +,S(8537990b,dd59836d,da16ccee,3871a232,3bd841f,6128f845,b0369857,66c7e0e2,beda6acb,946a6e08,43ec2890,c2d11ee2,404cadec,afb3f1c0,37cfb9fb,7b733fb) +,S(85a8cf21,1de57c,9c0ba88d,2f9a773,61041619,639c9de3,e2f2bc71,cb9e66d6,80d1d1cc,3c757338,f5a6aecd,815cd5aa,1d772aeb,5c1efa05,d5b64886,97ff6de7) +,S(d4f18d05,cb183c54,7594ea93,9330c174,37870e7d,48a613ab,4a920e38,18068267,32fc3b50,394bfc8f,a2a3f912,b35ebb69,d388c87b,198c3619,b04b6b3c,36b6190a) +,S(123e8bc5,65ceba86,d4c1726d,5e7e2a32,ac6f628e,940aa97f,c96ff72c,ec79e637,e54b4332,975774e0,748fb58f,3ddc5a14,8c3eb1cd,824bab83,edc76c28,e991d2c5) +,S(ac26cf03,c5a95e3,9a975746,a26bde6,8eddd6b1,6c83a3c5,81fa0a79,e93d0cdb,73ebeeed,b96d879b,882ae503,2f400142,5c8ed97f,98daa225,346a5b7e,9abc4832) +,S(54f2cc5a,a4d81daf,6600e921,441f5aa1,5bb51a42,7479e123,b9561d0c,8c71299e,3ff4e7f0,83f85039,d238a740,b7fd16a1,e313cbb5,b0c6fe5d,ad99f221,da4aa27e) +,S(8bd785,b73cca1c,6c405ca9,1ed4833b,428b7ddc,1a61c8d9,b0d1dea8,ef133586,fc5b65e2,5c3fde0f,3239ab96,625a9751,27a30cbe,f98e1ee,735c1f71,c86cf292) +,S(bd4218be,af5f92dd,f96a54fa,fe873cf2,171c2e30,a13c866e,e830bb2f,abb17d5c,86097c6f,91024f4f,8900853b,d17dbede,e2674e36,9f3fc69f,a2578eab,174e783f) +,S(a4006630,1b63e757,fce2f5d2,a7444e5a,1f2d7509,b7f59476,6951f38c,1755b497,87aef8b3,eb160df9,4b46a56a,337b6400,c724658c,a49c1162,c418e900,29efde08) +,S(5c5af5f5,65b2870d,6fd08f95,b4146379,15cda056,e18ef682,4cbbbcf8,adca740a,c7c6de6c,e679f0dc,84e28027,86ea726b,8eb0ad04,af4b9a5e,de516f11,583607cc) +,S(b5c3629,b86e9235,478aa7e2,d2e5b539,b70765b7,79ace9ec,ae76a659,80f0ebd3,86a8a06,84fef80,7a081bf0,3f08c078,7ad04420,76f5e1d4,521cffec,8b2dc96d) +,S(1784e06a,cd25fa66,72d1fc08,9219cdb4,54f5c711,4237bfe4,a2143eb3,20a0bedc,11feb0a7,d8d43ebd,5bfde5fd,21fcaa5e,7f091da6,3acf4b91,956172b3,5d3af378) +,S(39266c28,48f58af4,47e5ce4f,61cb3ba6,9c3bfdad,7e5742fb,ba4ca3f4,f175a291,7be4b872,9d1e2fa8,fee16e5,bfcdf4ef,2cff2872,e9c7fea2,c1997d6c,5d7f1efe) +,S(d6fbeb8c,72214cee,58b33bbf,2eb04924,f96e9b63,d104aa92,fbb09c8f,c2e4b1a7,cd9bbb10,a800d777,9d4cda4,561a2b8,759b4dde,45dfa2c,319e4e59,39938c8) +,S(42ee0a83,85464cbf,cd4a9ac2,73001bb8,592f2a74,b28ab7c,2eb7055e,2a471b76,d22c6ec9,d5499b4f,26947233,a5589aeb,14c94376,9a6166c2,af9d323b,e1adea4f) +,S(8cd2a043,4de9b238,f4dbc3b7,e56ffbea,4f025e2d,6c73a68a,4aa62bb4,9e9057f2,abfe69a9,986ae1db,52a807c7,c08a1116,a2dc7aa2,ec3b649d,7326bafa,ca74d21e) +,S(14c35089,62dcb50,d01750a9,441eda38,1a95abe3,72c501bf,a99f953a,5c94da3b,bc57dbf6,bba79503,f33be20f,96a54fda,fcd7be9,cb064410,3db11e3e,2034a3ae) +,S(2cddb646,76717e44,86fbe0a7,f7d6d853,7c3fff9,465e31e6,8da22abd,b3eedee6,136346f0,cf5fd102,932036c,3605179d,1429a706,71d95524,a14869a3,d1cae8f4) +,S(d806ee3,b5702d23,50c3f179,a00c3701,9c055103,318594c5,8f10b100,1b705aeb,79201749,21e69cac,a0ad5902,42e39a04,c3af8cc4,c665587c,cc0c89b8,3744b9b2) +,S(534f24,715e9b8f,f5f76a4f,a617839f,6fe2f175,3cbc3d80,331d12e,98f6ec30,e26ebaf6,4affe9d7,1ba2cd55,421c33ef,2e4a3fb1,c59a72b5,93ececec,65a40e1c) +,S(f33af0ef,4e23c8ae,7f3de5c5,22e8bd9a,6e527c8a,23242c8,4ae6677e,ec90b8f5,8510bee6,bacb5633,45f38075,8d85dd0f,493d179c,b9250d25,fe88134a,6055aefe) +,S(3cad4725,12a745f6,7e36fb92,1a2926d6,ae294278,8004386b,272d8520,f5a9aa61,d12ccf97,27da84fd,317116e4,9d45d741,776c8278,4b2c9f1a,e3773e1f,57b8934a) +,S(4b7fcc39,5f50944d,5cf3b3f6,2b1bbc3e,3aca20e6,d259e931,d3398d08,cb6fcdf1,99acfb05,a106a389,b7ad644c,cd275396,d76b046e,9992e573,dcead5c6,c7da96ff) +,S(9b5c0e8b,22a62110,bca2770b,778f0a2d,6d67e908,c57f806d,7470f5c6,abbb27f6,da52c77f,ea3056fa,dae674e6,daff8b21,100d007d,8bdefb12,fd56efe8,13c15a02) +,S(ee7b7f5c,e79eac13,d9b500ed,ee0b65d8,e7c93203,aaad71a6,9a935e31,20722361,e77ccd78,bf6380e0,5e5e8de2,20448a00,cabe7d6c,6b7ac318,56c09e2a,9a390778) +,S(b4774237,d36a59f0,e39a133,756bebf7,4df43365,2a4505c8,b0b84833,dd5b3a1d,5a5a03a9,e3463ce2,fa8bbfc9,afde9c25,763f4874,3cf0b2ca,7dc42c3f,9bf3accb) +,S(5827142,c69944cb,a066a985,79acdc02,83e1df82,8935ba82,5aa55047,5a52271e,c05c5805,6bcb6cce,ed5e8c8a,beac78b9,69c3b482,7ef5b402,c94fe1fa,f7fc81a7) +,S(ba06eb6c,a54fe697,9be9e9c0,f8c77be5,ada7bd7f,43894d1d,1705cc18,9c9b0ed,176be0,b5d3db28,7f235e2f,a9531fba,65f5ff8d,55b784dc,bf7271bf,864e3d5) +,S(ed84c2b6,11c1208f,2f059d37,a3d2ddc9,c3a0196c,9b9dee3a,5f2cbb0d,9383625b,6dff970e,b08bb4c5,4dd6ad6e,df25bbb4,621a5ea9,3869de76,2524dd2c,af1c6f6b) +,S(158b136,86fbdcb6,ad8ea001,9005405,b5cfc0d8,f614592b,d9e76b1d,8cdd568a,8c576136,634af4e7,9034b450,1bae33e0,9b5712f8,642cbeb,2b7c8910,cb28fab2) +,S(687d52da,10df8013,7232821a,990adf74,c54711de,110027f0,68464c9d,162c2410,dad3819f,8071b3cd,dd84fde,550d24e6,31785e1c,e137e115,8b5cc687,8cd09f10) +,S(32e8617d,de77c33c,a1d317db,d350298,50dc7fb7,148913cf,413e04b,384dc81c,9cb2fdd5,15231e83,21a3feef,804d62e9,2b8b9c0f,dfb73dd9,c3323017,b29f2ff7) +,S(a53a659f,7cc90421,21d96a90,3801753c,ea43b363,405af6,16d50b4e,fff054df,96734742,ecb3c201,742f8f64,df22569c,92212928,ca0d5453,d706f905,33c345cf) +,S(8a9e4990,b9b1a2b1,32ca9507,16170713,bcbf5719,2dca9d71,7fc9c4fd,a3993fe5,9542de81,f66098dc,c0bb0f89,44ea56bb,bb7e86f,9c63222c,80620c7d,2fac20d) +,S(5966c5b0,f92c5906,b9bda0a,7b3f10f8,e4c29796,f953db1d,35976175,dcb431d4,539665b9,90bc3810,4b7938f3,47ac94dd,7b9228cf,7270284,a825a202,ac62d135) +,S(2170d9c7,4ca5e85,305d159e,697fd1d,d32d6f6c,a2806992,f082ce00,9139c34f,b5cbf529,66f71e55,8015c90b,ea2b95fb,4a0fed8d,ef1f9af4,518789e7,39076c64) +,S(86e9b03c,2497519d,615f83f9,d0f9bf9b,101b75cc,50059e19,4d7b58a2,9b6fdf76,215d042d,7976ea35,a3dd586c,f5b286ba,a30e013,966fbb45,99845111,db8b56ed) +,S(2cc7d91,ba630172,ae56cf60,9a5d3c05,e27c2e68,7d607c85,ffcbf6c9,a467028a,9404f869,32385290,dff3f8fa,1a085661,5855aa6d,e9742d8f,9e2777f9,472ab5c5) +,S(84a89b0b,304ed760,c3a3d972,5a65764a,11d59ebc,25249f69,1d3b8711,10d3cc73,b7200408,fb1ab866,53b61321,10b6bc53,c8a0805e,568f8a0a,80a65678,c54c5829) +,S(4e9c88e,d10be9ea,a34bae15,8ba3093b,42ad9cb7,356f34dd,33eada3b,1937b4a7,b92050dc,95423a8c,759222ea,c09593c1,342c2dde,5fe382d5,6838df0a,877dbd9b) +,S(fe2883e6,6db454d5,31f2aaec,96f4f3f2,868ef393,d09c7685,a65d476,c6c97a99,1ac28015,1bc7c0a1,cc4be80,c6eff3a2,b8ae70b1,180c6a15,7c89dd3e,3e78568d) +,S(c74df902,ba66c205,e49f25c5,62d1eb18,f4f4f697,3cf49135,16000924,80f3f68f,17f7bbc9,59dd7e6d,9043ad38,7c0097b,403c8d1f,e676b8db,d7f2c63,1fa1ecd9) +,S(e7e7a72a,41f95b51,2ea42d1c,76da24bf,67059e,c27d5313,55c30e60,69a72c16,a20c2f51,6e9ba9b1,fd3a8473,8309ace7,da6006bf,bc42d4ed,657da6eb,6efedb8c) +,S(5a93859e,dc4ee632,9d36536e,1bf1008b,603d6a8,859ac6c3,a098748b,d6e18bce,489326a0,1e05c331,d97db6cb,68f098c4,6712d7d2,994e6c8d,be892138,e2106220) +,S(6161b293,71353343,a46d0917,4f6467ea,25a0f77f,fe614133,7fd3bf77,71062de8,57c439d9,a1682d4f,773c8260,6ee65e88,473544ae,64194ab2,3fafc2dd,7612b385) +,S(c35b16b5,a3808dd9,553c7644,400d6fe8,ca48c8ae,49c78018,4a71eff6,b94ce4ee,6c3baede,4925766f,3a7c59e6,d6c1c966,c3348b1f,5883498e,9956f3e6,6d8fe13f) +,S(fbdae49,32baf904,1d295378,2d227dce,4e2af60a,86796a69,86b777ce,bd2cd134,9ed9b5fb,df42e755,a9cd761a,cbb92877,6c66d299,35dc526c,f6950ba3,d63d0c95) +,S(6c5bdede,17ce2007,a3a1c18f,af8a846a,ce67b751,3d8bd602,23610ae4,b01b720b,6492873c,26a22bc6,39d4614a,202cbb2f,2a08b78a,753592f4,10c855d8,12f8d39b) +,S(eba4e62a,bf52b379,9305bfc0,eecc63c0,5221a0b8,b554432c,15e460d4,21dddeb1,e378e6c8,d6ddc7a6,72d83c3c,9d863c53,32b1cdc8,21ed458c,b817c49b,6dbdc519) +,S(5a79ee4a,1aab7803,23ced132,f9c67d5a,c740900e,cf71a0b0,ddb1d6c9,794cd90e,9f608713,47b3a231,548909fc,812624ef,26eb26fa,98630512,2b1466f2,665176cd) +,S(78b702ed,6d816c15,eb31dc27,619d5bf0,6ad646b2,e39750f0,73c31d03,e50d9385,9f1cc224,91befaa4,fbe9721f,86bebcb0,11024a08,4380e46d,bf11ce99,f157fd24) +,S(494e82e4,1c24936e,c291f69e,791979ae,3e2a6696,c8f68601,b57942a8,fe6b98eb,59f3af2f,c720847c,19fceea6,e3d2a918,ff7f564b,2e3bd7a4,beda6415,65bf5da2) +,S(28b3ff40,467a8c68,69fdc61c,33f002f9,73705468,4fc707ab,c0b495e9,a5c0b401,46a44995,b2c8f0ca,a32d8e33,b8e38465,4cfbaf1d,addc4d1b,852b2a04,58f84e34) +,S(4e4cf4f4,38a40e8a,aea162d9,dac13531,f5730d96,59c436fe,d8acd06a,c4c46be,4fb4bf3f,bc394c7b,57f81a59,2ea14c30,1e9ca990,5f48ee7a,5db08ea5,eb6dfd7f) +,S(e2ace7b1,3a9e3e22,a9b8ee66,c56e80f1,9370cda9,eb3ffb6,2d20805c,7f4c34be,1c8fcde1,2a653492,6428319a,981e1602,44aa823e,a82831b4,d0eafd9a,2159318e) +,S(e090ff27,e42469c9,91dab9a8,dc9a3a41,d46b7482,a59ba9b,cf4de93b,c95c7e78,d070752,c5679b45,4e1b617e,8315a48,1cd9d24e,eb53a671,3b4160ac,64e6f824) +,S(705c8790,7b976b8d,c8ccd3aa,897b2ed9,ea091c37,e285c37b,aa321c89,15ce089e,edccb405,5ae9f933,973950f7,eb79657f,e94fe286,27f6cb2e,784d667c,21ad4d3c) +,S(4aefb3df,663a28f0,d531e390,339a56a0,4da1c64d,4692c086,de232740,6d386d57,167af97b,43a36a18,1dfde22e,633547e0,eaac2f16,84e8753e,1ba1741c,2a18fe3f) +,S(ea909685,ee8c283d,1d7dfc4d,6ec8910b,b8d821d3,3997f24c,db5f5ee3,bb7bd72b,685b64,d3e02ee2,be2045ba,c3bb428,636258db,33177da3,17f6de0c,f8c805f8) +,S(5987cd59,ecccc129,b3498331,f20cbfef,f377cacb,dea76ce,2e221aac,d3aace8c,3427cdb4,f7367d60,44ba21b8,adfd5863,bae2981b,340c9bff,d0d7e93b,ee4d6140) +,S(e23845ea,e6ed3d33,14fd6f6e,f6d6e9f5,92f921c9,f448eb93,edb49869,97837eb2,89eb22d6,455cc139,e42c6263,b65233c5,4b1a3b45,34ec3d7e,58b788f2,6b11b131) +,S(cac7dbd9,7dcd353f,fbf60696,d325bf14,2e3920ce,26570b59,ff9aa65a,a6993199,6e81a4e,cd60a26c,90f890fd,6de2d159,50bb70e8,92eed375,25a48f3,31307620) +,S(9dab063,3a5952fe,f168d6c0,3ebb226d,de3e591b,4ad0c9dc,96b247ae,49a317de,846d87d2,7662b958,b3422b3c,a3410ffd,1ae549d0,c6757bf4,f96d2d77,168cc83c) +,S(bce277d9,ed439b09,f255cee8,af5363a1,12ec2d5e,b111196d,be30fb21,43f501e4,63f472d5,2649843c,42e8f900,5adfa50,d6a938ef,8f4f04d8,897a68d8,8c213328) +,S(df9f8700,2a6baec7,8b79cded,bb501dfd,54f376f4,5756501e,f03a6c7e,ac5f1d7a,2a1c5c92,789fa6e2,84105f4c,74b0a108,27ea2f05,5560bec0,5d0000be,b9b6c4d5) +,S(6211dcc9,307c40ac,3c7be1c7,5553511c,15d3224e,3b305c5a,39653d83,f134dbb8,545c00d9,f02b8833,5fe4851a,88cbde99,f7f02d05,ac674f5a,6559ac9b,d03febb1) +,S(d739aa30,8d9022fc,45735eed,3ff92f38,545f6c9b,b70994fc,b5f41f78,772c9378,d3c3fbb,9077dd53,d023838a,5c35b728,af4a90c0,1f16739d,12870e1b,15e1e6ac) +,S(9d85e55e,8ed84471,b6822c68,3268c35b,fa314b72,470e51c1,a7ac9f25,f8bceb6,8b01f444,e84436ee,ae159a32,7026d279,5c4116b3,b2e78f90,99f1035,1511ac88) +,S(25d39bff,22c40a94,b194c38f,be9d001d,4a632407,237fb091,163e463d,7c5c70f,33381905,11368982,445ad7f6,608be022,209466c7,98b9abe4,f4fca781,2c0c398e) +,S(67553ed3,f14c28d5,2abc36c9,3f15d0c4,7f6fe1dd,628b652f,36b29225,ef8ff51c,da5d42d5,9d41893d,10ed28d,569c0cbe,1cc077e3,36bb5c21,e3712bbb,9c480383) +,S(ea3e80f8,c800b52c,a6dcbd2d,399ec5db,65057477,8852a73d,68af22d6,f1abbefb,5cd8f55d,b5330919,377b48d0,8ac1bce0,dfb8c3ea,2b97a5bf,547b7beb,ea64a4d7) +,S(7cf11aaf,638b1fe7,3b8c5753,48bcc01a,41c61ee8,f2eb3279,c2ad21b7,f6f60780,579d9a90,3a8a77a5,6bef3ce0,53ffb3c3,cf969f9a,39ea5bad,b1fa075b,e918f048) +,S(ed377aa8,42897f6d,1092caa7,42c29285,2349bd7c,a0e0cbce,d3cda58e,ffaf5e17,44d1e8bb,6491dfea,cde53662,5e5d7b52,1ca11a47,1eeda260,647f6f0,f0c5f917) +,S(fcafcd82,dfc87415,6e0db5ab,2fa2b56f,dd488032,d22ddc1a,b7a0ec8,1f1c4083,42f88e6a,cf851a7e,ca3fc28d,f771cce2,bef0d7ce,3d26da45,a2d9c307,e9e7e040) +,S(4d372865,7fde43e1,68744112,26b34713,9c1ca4ac,c2905858,de50def8,5515339c,5dc438eb,7091eecd,a4868c48,a7933b71,7ba99d8d,5e8a946d,ca9605a4,7421df39) +,S(aea6fc55,47faaa10,a898f21a,f63249ac,a0625f78,ea819629,8bca035d,7639e470,4d20c80f,173980d2,8e6bf433,bd1dacc3,1882e283,35fa9993,ef808464,a5568d42) +,S(f0ce04bd,bfa81a58,e157a49a,11695baf,7233470e,baa7ae76,3a07f0b7,f71cfce,f9e4d701,baa6f197,d9912b57,d9df016a,b789e60e,d731afeb,f2e5f920,b4eef9f6) +,S(cc476e63,130a950b,b8284c8f,fe74a059,8d9d44d4,c0372a9d,bbabca17,517523f6,d2cd50d2,e2cae10c,df744ff6,61a6c96b,64e17368,5f81027a,c937a292,3ad7476e) +,S(90e0477e,8dacfda2,7a563448,65947a05,d0afe9ea,60634473,143508fc,6abfc73a,d117be49,166bb010,afb0b82,a46a4204,c18ffa42,e3c89764,3eaae0f3,303dcd9b) +,S(522a6781,951f6ec7,76b6cf9f,cd20287d,6977764c,517d4ebc,7209d55,5714b5d4,a109c149,6318d481,4cb22199,3567e5f4,5147b64f,c1f9216b,922d653,7637031) +,S(b0a4c701,725326e5,611ea140,325b0536,b22406bc,c1e7eef2,1f874ff4,e02ec2a5,df44faa2,8a60eb90,3974649d,54cf340e,293fbd09,66b7b7d8,884e4c8d,dc1ec875) +,S(9e874924,90f8d4ca,2ada28a3,2bccfdaa,51ead138,3421d7d3,482af7f6,6df47c51,a58a577d,d03a719d,1bbb64,6ec3051b,44535da0,5e7e04d9,fca42716,2e335fd7) +,S(650a307,7b8007ed,f0441dfb,b7103d3c,d5146ecb,b949f9d9,c8c99e2f,25df7324,aa05b394,8c909957,ed1bd7e2,720286d7,56c7e413,8aa202be,b08bc446,2fdf86e8) +,S(f891ea99,2a3ef255,6feafa4d,7dd3f7eb,1f1401c2,b75d65d2,6ab81372,bab6f932,f7002bf5,821837f5,8df109f7,2ba5eea5,6c767a4e,198a7594,21467d64,df5e0bd3) +,S(d35e82bd,44fe54b,5d2c0543,91260c04,a5ce8d47,32e83ccc,2f3035e5,56bf2626,b002495,99705173,e0a45f97,196b9e41,1a7f5d1e,33f1b39,100b511c,e51f6953) +,S(7dd56d5,1f139070,a382af7a,2db135bf,854c8e98,2a325b41,ed869de4,349323bc,a23a473a,7f263bf4,944ab5bc,2d82e20e,8e9256fd,b11dbc17,bc0e6bfa,a8325f5e) +,S(afed2eb3,c5a95b4a,e88ee73d,b57594c4,7013cf13,a48431b0,f7930d5c,27f5c3f2,26b49096,da666097,3403eabe,342ab065,78c8ec6f,bc3ac7d7,2b3c95dd,54735dbd) +,S(13826776,74f36fe9,ca81cea,ac65c2b5,51e9fad3,af246f,4cdc65cb,cec534c5,a78e8139,760a94e8,3b3f5ff2,a65fbc7b,6b2b55fc,978b8399,df2d7947,18b496f1) +,S(99200c12,6fed5ec,1fc849f7,e9769a7b,aae3178,bd6b59ef,2563ed6c,5342b80f,7a7f1713,38a84536,e73f358f,91eb80b1,6ce8ef27,ea55795d,16aa7f05,577fc13f) +,S(159febb0,27e04f1c,321b852a,3cca550,28aac30a,8bc27caa,73a069e4,df7029cb,6bc7e080,8834b880,c590d249,241b709,e7280a05,7cbc1897,9b8cc9b3,cc21a821) +,S(2add9be1,a3acdd9f,efebdc0d,a4272ca9,311567e4,61db8eb7,3519c1c,6473bbc4,357ae640,a88c55e0,d3559faf,b0775d78,2373537c,c25e595f,f21ed1ff,b36b5925) +,S(8e2d4265,1742837b,b077fcd1,488e73e,5dccd6ba,6401c6c1,8d36fe9c,c428b664,ee9a5b1e,a04ab8d9,6430ef39,7756f62f,a1dcf35f,fff314a1,c3eb1dc8,d9a1e5e7) +,S(79dd7d76,5b4d7db0,537a69d9,b94210e3,8e7a11f8,cb9cdd8c,6aed6a15,748a3ac9,868c4b6,26dc49fd,de693201,3b89cf13,e1dfa1eb,56fb4de8,9e5467dd,86e449d9) +,S(552c2ba9,96a13b57,32c3b2fe,d4e9579d,365e03d9,2bcb231d,f14d1d1c,288a963,118e11e8,646a0335,6834379c,bc93c1d1,3ad80145,dee0a51c,49b10e17,f6952f79) +,S(fcfde18,a53b5a68,9d33bbf7,79d0b699,2faee8ec,243e72c0,7ca09185,d997e581,6709b56f,43013d47,23f15969,ee01b0b9,ff0d9d95,5e2b98eb,7e78e1ad,49cf3d80) +,S(e9e9d7a7,4ad279c5,691367dc,9c4b7bda,b27451b6,a8e4ed47,afae1883,96d8d82c,292bca82,e6d1c88e,8869f33a,7a6df2ec,ad812dca,4c46eab4,5c56c3b9,15f79497) +,S(514054e1,3e7ceee9,3a19dce9,96256b5b,5876a55c,6cab3c48,74b15547,4a58f285,f9ea80de,80403f34,2866dc40,cb0a9aa,4b38b98c,c4c38e3b,37f4da03,fdf7f5e7) +,S(ac0364,eeb9e7b9,b9589051,635de6c9,447b327e,8c820272,f04a4750,6cc5f290,ccde3ebf,13b5a291,a73b0c8b,9a69414,4b217661,7b0a7735,3a6e92eb,4af21b7e) +,S(cf558594,4a73a11a,ef500dc9,60cde799,ffb4983d,ae76826a,a027fd77,811058ba,369ed987,eac1683c,4e8874c6,40049a33,867fa0a,520e5204,df328d89,f197bfaf) +,S(ee216b85,62eaf12c,9189055e,32cc55c8,2ba5e3e0,237de083,a6e77878,63c56291,2a8bad1d,a697832c,856f6adb,e1cc5058,77e543c3,429b090a,1d3cf0,d2df6248) +,S(89903a70,55dfcb5d,175acd28,f7161862,c9fe22dc,ab752d88,3f52801f,92ab1892,e89c4f9b,7954c2b8,cd3b4868,ae171331,871a2693,9355d88b,8d37d4f6,b90c143f) +,S(f9830f50,66b1b44a,89231a81,1192a284,9ac94ec4,13f5223d,51d1e75c,a7727884,18ac8170,58795d51,cb9a5c2c,c249bcfb,ff3fe3b9,1506b721,763c8fcd,7e2ae44c) +,S(326be8c8,55c9f742,19228eae,f7d79c48,b02c2e04,3bc28e9f,275d6754,31afa8e0,293647f8,76b00450,b223e715,5faefac5,990322bd,eef964c7,185acec7,7c105d06) +,S(6117b67e,bbd6b120,906da047,88ad7dde,3549bc5f,c4f80e04,9b216b00,d441dc9,7ebe5576,17dabcd9,f41aa34e,1443e12e,715c9a7,ccfa04f7,ec6a9a25,74c1e540) +,S(1fa858e8,aed841c0,902db240,aa0e4c80,f26927dd,94e0e404,7e8ecc25,216dafce,26566614,2111086b,caff0e12,e4b38940,ecf05a5b,58f3e705,d7011b49,413a52fc) +,S(dd77d202,96a15eda,eef79ced,9b59e77c,1483b936,6e9949ef,ba3298a0,efac4886,b1914a11,80cb154a,f791a934,8c89bb0,70f2ac9b,acc50c5,f75b425a,df6bf125) +,S(e5fdfb45,1e7ac947,ece4e8c0,5b87b9a9,2d49aae3,5ef95f5d,1d18bcad,18053337,841d054a,47b4998d,d3ad8dd3,d2a1ee68,406a195b,1975bd1a,d4194417,fdc4cad5) +,S(decd87d4,6fb74380,56a83258,bee67d9b,1a49e170,bb1b549a,a5c2a2bd,cbc050ef,5ccd1cd3,614fad6f,601a4ad6,e964ee69,a1e06e8a,2e29edbc,7d19562,a4aebc5a) +,S(1a94991b,939bf699,468c465b,5aa4b064,520222,c0ccfcff,193a8484,6f6e4b8e,31b1e6f5,30147e1d,ec0199ae,1830a36c,bcf4fce1,e1258441,3e89eed6,889b9d1) +,S(f32874f,d0f18d03,7f0ae5f2,ddba8f16,fe7ca4f0,d694e803,b9216c59,91bb456a,1dd8f5ed,f228a9d,53cf881e,a4e3c479,6017be43,e613ac30,690435b7,84a4056) +,S(1c5991ef,154b79dc,df2ceafb,3f7fd7b0,7ce7563a,9312ee6f,1dbe5960,f91ba569,497d2a93,28ddb18,221b0075,3432f510,bbf042a5,ebc44cf9,3090d064,4a252a7b) +,S(3c88095e,dce54996,3bf6e312,4dfc14ff,4ed4ecc9,d6240af1,6ecd5984,5f01de9a,499a17ee,e13c81b9,bb7b297,5e7ed1a1,231d9094,348d22fb,9254c520,a65be01c) +,S(c849c359,1c4fdb68,55971840,c0b78bd3,59d1de02,130adf7,e277cb4e,f6eb7748,6add7151,b2640b78,b8fcfdc,fee4310a,4c4c97c8,bb0cdc2e,3bbdf802,750a7920) +,S(f53017aa,a5f79e34,5a0cc318,f40115f2,52ba5401,614b9eb8,ac9245cb,3ca5680d,2d8b8c24,ad89361b,6d77bc72,fb0c7da8,ff129a5f,2bc00e26,e635483e,c4c44b1f) +,S(b3657e9f,84975313,640b7302,a288ef4d,2dbf36ca,651c0189,b39fc10c,87d7c4b0,d821329c,a2f18f94,7a71f5f7,51ac1b2c,e56aa432,992e7a3d,ef84e631,db61fa14) +,S(79942dcf,a834e013,77bb3eec,b7fa31a7,b4eabe7a,578c46d9,3a0dd17c,b3455f61,4c08fe53,c3afcbd1,7fa0a809,bd4ff7af,88713a3e,d7713f82,18c4d4d5,2a757ac4) +,S(e5f14474,619e3acf,905da5c2,3d1bc311,7f1d58ff,8c63ed2e,fe939a22,5fd9d9a8,d4d225b5,85b6b319,431939a6,8e2dafbf,8ed90a6e,5fb559c0,70779d67,7c03028c) +,S(bc5ca503,3ca4398d,5f3c6240,946c5d7,c9102996,e302b9bb,640aaeed,8c9b54d2,ac15cc8,51e59843,fbb2956f,55d39f24,200922bb,6cbf1e86,68ed3ecd,6fae2627) +,S(2f3abe56,d63a2afd,35e35d4f,9e964c61,a5483402,5fea8cfa,66ba9aed,f75947b2,7adeb38c,e14ebe73,8dceae8c,77903b24,3066aed9,bc4886c1,356449a8,27496d5b) +,S(704bf0b5,f564ccef,4d6e5f8b,eb2e90c2,4b46d581,93cc0a41,5bfee2fe,95021b75,44618d17,c54684e,ea1ffe1,53892090,b74201d8,ab3f9312,e7359ed6,5ca94c27) +,S(a898e473,d4b59956,2a905ede,afc78bcc,9f374c6a,f524fc37,86a91375,83d749dd,5452e556,7d72dab5,e085ab72,1168b5e9,c96a0fce,f9d5862b,9c5a0daf,3769395b) +,S(fc4f83da,817b1648,a8a1be3f,dbd0f309,db712225,2988ac8f,64774c29,e8d9d573,57876e31,6a0ea473,3e34f34c,b0df75b1,1194017b,258cc944,7ccded35,19edd00b) +,S(63e97e30,82c36634,d151f0a8,837956d6,16d5d4,64c66373,253bb94,ed5c8236,af68f06a,e045e5be,88242af4,2e314ecc,d719f76e,33092e6d,8b69f791,446c2acf) +,S(4c06073,5107e9fe,f27dfbfd,5df447c,16f1c911,8ec5cfc,8083a588,9dd82b23,8c8508d4,b86e9eac,2058a912,f2581ae7,fe81647e,e27075d4,fd01b051,fe0ab636) +,S(667f609,7b6af1f,cff58520,83175f85,ea01a1d3,c508b12d,a2e19281,c8d8e443,ff9fd0d7,4a0cb42f,3d7ff6d1,67e5a65f,23c34679,caf3f94,ed5d1073,af31607c) +,S(e01e169e,7fbb4365,58e07dce,8f8dead,e2ec2e27,7d18db95,ef8e9f85,ce800fd7,f49f594b,9d60c59d,155ea702,a1b5e3a7,b26aeec6,71b275e7,10d0139a,21041960) +,S(ed10fbe2,565f80a7,65fc90ef,224c7893,cf9df84d,aa0a3b2,9089f7f1,c014ca50,ffc44137,c3ac6fc6,fddc65d1,87d6b456,819ab1b2,df461ecf,899c70fc,59387031) +,S(4563833d,d0052218,5a43bfaf,7e55c2d2,62a12feb,b76254bb,e8310687,e917cc36,fac05d5c,c781d49e,9bab4cbe,384b511d,1c8c1fe4,f68cdc2c,8c576be0,1c669e63) +,S(bf5907b0,1d05136c,b0a1b514,73682fa1,68772a1b,9f5db994,3bdacb3a,1e8c47db,fc69b036,4559f5d3,f9e0c1a3,e4da38ac,b9968e9,17311288,69da2158,2e334cbd) +,S(be106d73,d01ce0fc,5555d4f2,379c906,1ea6ca18,ef8ef8fa,754ecf64,cfc27fd5,9c84f04,947687e,f7d641ba,ff89a11b,da9e9769,8f8ceefe,54e2a4ca,267956e) +,S(5bceda4,2e94ac3e,68f6a3e4,e4509872,4724e9fa,59ee0918,859884e2,2c98f15f,4b19d70b,e1471e3c,7907f797,7311f5e2,ba78c6f5,6f2ccaf1,cb6b684f,7d048934) +,S(e0831b14,fcb2d4f7,3d17b6c7,f6d16803,304cbb32,2bffcd6c,84bdb891,9d7cc9d7,b474a715,5520cd3f,65b64d08,b8e92ca2,4b2238b3,11d91db2,48720a6b,65444038) +,S(df818b88,2300aaf8,41cb3962,2f0c9166,468c1ad1,3aa284f5,89dc354f,bb1fe97f,40f571f9,f63fb358,231c204b,3b9707f0,c5cf11c6,d7ffb93c,991cf7f8,dcfb3895) +,S(d9fdd569,bfc89237,4bc56a1e,e56bab5a,cb5e0ce9,85939b85,c929fde5,82a07bcb,5c56b150,4cf3767e,e22e4b00,fa467b75,4c9ccec4,c1364216,d34ee210,aa5b56ce) +,S(11a93998,d031bc3e,d55e74c9,ab327945,cbace727,647bfcd7,5ed04a2e,4836ba,4aa311b0,6fc8fc86,b67e8eb2,1e75d997,189fa22b,a33e7e99,b07d610b,1c94655) +,S(7c4fc747,7319464e,2d71f787,80aeb385,aebb0420,d8f8588,9652d5de,aaad580d,31d6d7fc,2cae58f7,b3e4804e,f615d7e1,edf9d06c,d1035b30,ee9b55b,21b06eae) +,S(83704a5f,4ef8ca9e,a3d5b163,2bb3df98,acd774d6,4e07b219,b9a36a9,ce88e1b7,52976995,faeb6179,bde4c123,1437dc73,b53b6f90,f0cce08,1e3e1644,e1ebeb18) +,S(5de15f19,21258b5c,f12f240d,147bd38e,fd5e3c3d,dbf148c5,9e541c01,ca7d724c,c0e18562,1500f0,e3fbbdef,45550e16,5fc2a2a,adc72558,e49f1e3b,f5f4fb00) +,S(f5d1fb46,e3288419,1f2cc8e8,2ba81ba7,5bf1d7b5,97ff82ae,8731d27b,7f059938,3d5118fc,9acc8394,9e0bcba5,c7c79fec,2f0cad64,7910976b,e4e8f9ff,43d8baa0) +,S(8ebe619a,985f720b,9381a99c,db63d089,6a787dc9,7d007354,fa83b931,223f8596,7968b6fd,e3dcc13c,512aae25,d9a8127f,313e2d9c,34489606,864732b4,c3b5ca1f) +,S(5b14482d,f96cb0a0,5664bcdf,e4ff7b87,6169db9e,8107b0b5,78baba9e,b1f8fcdf,19a4ed84,cd2ab376,b1e0c2c9,ecded5cf,2e874f09,6d84d946,22be5806,9f8a5e82) +,S(ae810d52,7f94dad0,d140877e,ddc5e0e6,cb636325,f4c926a,1a263f1f,beb9a8b8,c94f0c8a,f5ceca8f,ea29dbe6,c8afa649,f813744d,39e303b,c1f0c135,867658f) +,S(38853d15,d74060fc,7eb2a56a,b8772f6,855aaf83,b731d853,b99fde93,e7c06e7b,ade73ce5,4f513c89,531b5bad,7f47ce7e,a498da85,e378639a,5ae0507e,1f27fa7d) +,S(837a1d99,db477c6c,da832700,37f111f6,eec5402,2bf74773,4c18bbab,35b503b4,ce852762,ed9b36cf,65602da,cfd3a250,c547a971,1977ba86,64f72cb3,89ac1f8c) +,S(3136acd5,a1460d8d,717e452b,a2069b88,4eb6fa81,756f8768,932c210e,df08173f,42ad61fb,edf97b53,f59ed7b6,afaeaadb,831134ef,73e33b1e,26b2816c,99fc330) +,S(a9609269,c3ef7f09,2a43e394,e482483c,119d94df,10bcce43,6691230b,b77d3201,8c580df7,9147069a,5c84abb,73e28b6b,ab9c7c0f,7803d6f1,d9fa86c8,f324be1f) +,S(3cb613e1,1ce19ea4,a8a90eda,cb182c09,5b1601c4,92822974,6ec22fda,be699e08,f05a18f5,aef9dfe6,87e69a9f,287fd868,4c975765,284f578,50294598,51538b05) +,S(b41c56a7,47232950,7777847e,178eaa67,ce61f561,21c7f21,2c525bd3,e7adc359,b0026b4b,6f9dc954,7efedd80,d914a3e9,65b17378,e6e0055e,527f6754,c5c589fb) +,S(f44724a1,3cdcf9fe,5b4a8f3a,f0d3e076,4559c14d,87eb8ea3,803a41da,9ee9dbf5,355b54b0,7ae7c477,9eaa314c,953340f2,f5583ae2,ba730339,acd231e5,c3d64627) +,S(6fceab96,d5851eea,b5db9caa,9a0ff7e7,86c2e097,5c2207d4,67f343e3,cb36ae1a,83f2b505,20094ad6,cb8443aa,69b8af96,b531341b,81cadc21,565d28e7,43bf2c47) +,S(2acc57ff,ff168361,9275273e,9a821fae,54947539,7f6b1936,13917af0,ef83cab5,764b04bc,9068fae5,75a202c1,f01f87,f3650358,3f5d3042,1e246020,9fdcb94e) +,S(2ac302a,28126e57,5e6aee8b,2b12ad19,f5e1c056,2d63d73e,80204b1d,1d4227d2,74494cb4,1e7828f6,9d2dd529,a70f2e52,9bf4b524,26a2a3c1,ab10a974,99624589) +,S(c5de085e,4dcf8dab,497a645,c7abd513,4054b225,32ce8405,f6e5134c,515d9de3,d1da7171,31a859a,a2c90816,386f0318,9759326a,6cef86f9,f3425bf2,390bed7c) +,S(54729254,5f78e410,db85d01a,182bc5ed,84bf6843,3b5784cc,852d3e70,acbfe90b,618b0f0a,7919751f,46c0ec61,1dddd798,cd89d4dd,32d1acac,31432308,d1a615ba) +,S(c6fc6b5d,84bd05b1,ec8b0ed8,fd4eceb9,dda38669,3859d90a,a0853c3,7f75e8a6,d3d8ffb4,988f7e47,2c26bd4b,83f95453,149d1534,bfafa97c,39a1e8d2,70c53582) +,S(1e325c1,ef4a976e,77d6e76e,f9a6dc51,175175bf,23e2c46d,7203d6bf,86ea05ca,60f35511,510aad52,e156e265,6e7ec137,c319b8c1,a1591258,590186ee,be4c1471) +,S(bbca6232,ed8c6093,7ad123f6,87af56db,28947e01,99340510,95850d38,6ac1d89c,d1257327,269836af,2793a1ea,21106bb7,ec95885f,de541f66,1a4a7c38,39c222a1) +,S(c55b1ec1,1f7aff98,710c3b80,34021aa1,83645a14,edfc6926,cd56eeb,f1e5332b,e541bc98,7ecd2b66,d10ce29c,572272ec,28c26b1b,1703919f,d0b28e76,4ffa87df) +,S(f026dc49,feb91051,68f76b0e,7abcb9a3,cc78a5c4,e520c2,57d2f688,5f1c49df,2471f06b,5dc74f9f,6cca7d72,86571c1b,54ab3813,d30bfb57,53274a4b,4257f5c5) +,S(3f721c3c,605169fe,dee4a4f2,b07865be,e1f0838c,669f7eb0,f234e700,f2fb16f5,9691b1cc,ead5fba9,9d9f1feb,fae6baa3,cc7717ab,c5a671f3,8def1556,e27e100) +,S(65bccdce,bb7e968c,a1c5dd12,2d5440b,97b07014,9838f4ae,95962044,b822b0ae,bd594952,f8424625,91375009,3cc6716f,cf7bae14,a6fbab35,4a962282,ee0b3fdb) +,S(6c155658,7020a902,c225d721,7b1a5f2c,5646179,df5613d9,b95826ff,7723f42f,1ee346cb,5841939e,42aa41ed,84bd24b,33075490,68de1809,8e5f8605,59e9c073) +,S(d2c9f745,8f75b42f,b48dea34,13b2bf9b,dc045542,8c5a3dd4,2a08716b,bfc4367,e2a9be5c,8f06a432,6f148cb3,cf58f767,cfc8f8ea,1ff4656e,ec19a64b,183f650e) +,S(aa11c12f,5fda607,aeb4af7f,8430cae,3f5df00a,43910ff9,e413b3a4,7295a38,e506e63c,a0568d96,2c489851,489fbb62,acb60d9a,fb9dcf1c,7aba7be2,2e02c67e) +,S(a355e383,43937932,21affe2f,843d2541,3faf807a,900bc299,5a201f10,d5748f99,22ce77fc,c627019a,ff0245d3,ef2b31fa,55687ea7,69a4948c,5656945c,c5a5c74) +,S(d8f4e393,8b93f252,da68e1b0,16fe8889,d837ea8e,61e5d3f6,8928bf32,22643cfc,c895006,61003ee5,3d8f739,d6fb7cea,e2f7b414,28a65ca1,bf493a3e,27a2e826) +,S(f69ff0ca,3aa0ee7,122a00a9,4b6ef41e,13945263,96e8c590,84ab2b37,6b899cfe,a5211104,271a3020,d65ca305,c0daa6ac,cbbdb1b1,d349a2ba,1abcfad9,bf63a7d5) +,S(64b1b59d,7415d433,7f5b9a3d,98f06d10,7e647525,b347011d,6d3b423b,2a377592,12ea2814,ac8e0bf,1da8e617,c8f051ad,5799593d,f9ffc1f8,abc963b0,faf202b9) +,S(bac6a7ef,9a3de971,51044204,ddc3a2d3,4668613e,101a7e6a,5f93c25a,6b20dca9,7bc2b764,57620478,321de1fd,8ae8afe9,6047d087,b95390c5,bc69b972,654b97cf) +,S(fddae798,dad79951,a4c3b803,11ced882,903c9dcb,4d4dacca,c4cadceb,b837f688,2e21e1f9,f45ded15,76829823,4892d2ca,26ad5b6d,7b0baa77,c2dfbba,b1dbca19) +,S(3dc783eb,40779120,25b7dfe8,f493f073,b3a8520c,ef0c94b2,1c3a5388,b0a9a01a,b3fd9020,2ca16d20,fbe8cee8,fb8bcbcc,821696c1,15545aae,84c414a0,c4401bb1) +,S(299a187d,299c61cb,6893a5d9,cc8831e3,df92ab13,da2f0048,555d1358,e55e866d,ef0b105e,52a18751,56080cc,cefde2b2,848d43ba,6d650068,2b71fb9d,d34b819c) +,S(b690b4aa,fde43b5b,362de597,100c74d8,97cbc750,688a46b4,cb1093e2,e253dc4b,affd5af2,30e4de4f,9971627e,dac86808,c97bfa30,f051af29,bf91e36f,c3edf0f7) +,S(7217384c,1596318c,2a98db2b,7264c909,f823de21,702f5e64,b19af937,cbb8be39,b125b7aa,1bd67232,df7d2d3a,a671bbc1,bace159f,3ba2fad5,e82a1ae3,965d5c01) +,S(4bb4a86a,58f1248a,11f61599,f420fc69,bc77b7c6,86d2838,f4368971,67013852,29909cb1,3bce655e,88300d78,4f7984de,352c9b9a,960148e,a5b65acd,99b62d4b) +,S(4b3a9328,2e473993,9d7722a,7de44fcd,51658eff,93c3711d,3a8f0193,9a54902f,9a012a8e,7df3b988,204fe0e0,50cc197f,a27618ca,d8d712cf,520c7be4,cf4e0f02) +,S(5488985b,26978af,50099d93,8d7b1aa,c545b07,44938190,e0b880c2,11782b26,b51f749a,76b998c0,83dcdbe7,21d5fa0b,c4aa4392,f81821ab,3436fbf0,37d37bd7) +,S(7f2ff4bc,f270b566,d2d26cbd,ffeb1b9b,31b2cd7,b647d89a,2c86c003,b23f644b,f48749b6,21ed28ae,47223281,fe8e633f,35580bf4,8eea29f,d6aae487,ee8e0588) +,S(3305c475,1d63baa8,18f5bdc0,b4e46c9,acdf1c42,9ff5d177,bdfc214a,b838efbc,491d45be,85ae9675,310ae85d,258c6c9c,8e28d7fc,5239363c,911eb12d,ee68a435) +,S(4195dd13,ae5ea569,179dc64,b07f66dd,4a2e2878,d81a222,304d6a88,4da60b86,bbdb99ff,8d4ce150,543b48ee,9109f127,5234c69e,52293758,d0171ae4,ecd49677) +,S(8dca7466,8ffbf319,7dd9826,cfc7f450,fed841ed,83e1d466,e92470ca,1e2582e0,2b19be5f,69fae0e2,563a3f80,2f9450e0,fc48ebe5,973f542c,4c12fbea,97627e57) +,S(e235d150,3449667e,ba23d119,9b5225db,1b26220f,60f84476,70c6bdaa,f5eb7aa9,3d4d8dd6,b0c8c2e0,c8f54f6b,dffe8dd0,5ae22d5a,b4f9dc18,f17acafb,3fab327) +,S(aa214fc7,23c3c458,8bbfd962,b86cc3b3,e1ed52a,25524ed3,ee5c4933,1748ddf3,9b54e29f,63240e30,434f7a22,2679006c,24593e26,90254978,35a60897,d3578e18) +,S(1c468a51,cc9d2632,860bffba,9ed83e5a,e97dc1d8,c8bc3577,5dfef223,b3ffcc73,fc569e94,8eb20528,98b4cea3,86486afa,cec0188e,44dc4e0,25b34855,f1466e87) +,S(c663e752,ce62dec0,81f8ad57,3e4f5c92,138e6a8b,e6c9d015,d5cd2cf0,ccd1a203,ffc249a7,554fb97,c0f9d96f,4cb06fb7,ce6e868c,e7e60b30,f67a2b9e,919f6f98) +,S(949a84d8,5f68f70,81f379e1,9d673748,bed14bb8,dba2458c,34327c03,c893067f,1b9fe41c,f474e57f,8497f6f6,76472a28,fba6b259,91297f81,474cb6fc,f31380f0) +,S(6a4bf3ea,5798c8ed,4b35c629,c6cfdc0e,d16d0d27,39f8bcb8,c34a9105,fa35fed,6f69e357,d5123305,56d04946,f9265353,77610fee,20667815,e7f3cb01,e8196b24) +,S(d0a99a37,d1df89c0,99b0dc1c,16f325b9,b2ec1455,21d4f80e,ad67da85,4f2a5357,7a75846d,eaf7c4e3,5c0c87f,83732eaa,7f6903f7,b721648a,87e1909b,53d3e9c) +,S(e2a45683,f3781309,b6223a7a,5ca64c4c,cbc5d45f,29c66082,912568ca,3ec6d3c0,8e386acb,63c52ed6,5aaacecb,fab458b9,9585951e,cd0e35a6,19c0fc39,5ce1c0ab) +,S(9527ae80,10ddd443,7237c2b3,c8f3afb9,f31e1696,5b10fedf,f150c296,3cb8e60,6e0843a,87833be4,f882c417,7198d985,5af8b144,11e78c3c,497fc49f,5f728479) +,S(15f15c4a,2cc43062,d4360a8d,dcf8e0f,52bc4741,c7924f6d,e1dd9f12,a06b9b2,66a127e7,2c55db1b,57050f4c,a0d8abf3,9ccb455d,9785a4f3,2ee67a42,3bfe5ccd) +,S(558648bd,64c52dd1,189912b2,67078e8b,d3c68952,47e6c848,d7dc529a,7a24a75b,12332187,62872867,5bc88378,88deadf9,3a8f2c5c,864371dc,6be0be63,44fad7ed) +,S(1e87928a,b6e10b59,6b231b08,87a823f1,3c6b3ff3,2852d35c,d1167244,fea2db0b,4cf60a4,767783a9,1c9747c5,7abbade1,3d7fc02f,e833b474,648038c3,b68d96f5) +,S(7a169de9,1d4c3f0,3296279,2c3ebfe7,f2eb4410,f7b9a34d,c402ae64,ce9231fb,1ca2e8be,7a7603b7,d95820ab,86487a04,c91ab3fc,c88e2f0b,514a1589,3908e463) +,S(65185a2f,bbc8c96f,cf9a6df4,d002128,afff1f2e,5c0182a2,95639a7d,9fecaafb,10b6902e,e83c5683,3d796b99,665cf365,c1e41d63,41fe72a4,72e5ea6e,39dbb9e9) +,S(61c45212,4664432e,8fbcd950,1dbbcd9f,1fb8842d,c8e61758,439b6d5d,bf8dd626,2a9c7c57,48509dca,ebfc5062,4d7a0b0c,21c9f5a,45733f8d,e0441bf7,f2b359c0) +,S(f61aff9e,267b6d91,e3d4ab45,73457987,b1af9a9,38b659f4,1ad5cf57,8cc59d62,51d0b694,e5692be0,6841a3eb,160474cc,6c248213,19c9648,c32ea444,29cb2553) +,S(29f27a51,8fd448cd,73aee0dd,7316e566,c655ca44,afc5daa3,ee359ae5,b96f8bef,d5957a97,a6447a8e,a8301219,5fd53c1b,63784a8,14c29c80,d0061fac,2c6cc1a7) +,S(c656d66a,efc3597a,2ee977ba,bdb7357,a2485a6c,d654c56c,bc58a0ad,598f202d,f8267b3f,f293a5b5,11f4e466,dce0fa88,a37f1603,a3a8092c,934fb824,1427a59f) +,S(f28477cb,efe654fb,ccd3a9ab,e816f950,3749e183,3b1faebd,418c85c9,112a5135,9df0f505,6ad98099,ac0dc723,34af973d,9c98c597,ee26e22f,a0a7a60a,a3b76cb7) +,S(d007a1a8,b6f05046,a66fe0f0,9a02e510,3ca7555a,277c40a8,87a71920,5a429e79,d9a68c51,f17fd51e,b19e4946,694e90f5,2cf664ed,d2d45489,5f880400,b410b8ce) +,S(348f74ca,7e5b1ff9,e6ccf3d9,90ff1f7a,4e3a8296,725075e0,33a85b2f,5ba0f338,1648c7f,32a206a4,e21e7309,f1a68a4b,b2ee116a,f3fab3f5,7455da93,7c4afc7a) +,S(1f54e125,7ff3dbcb,f1b55720,564f0c72,d322b8e1,f14d2b9c,1f6244d9,c85f6f70,34c23405,4a970b58,2cbbcdce,e67cc564,6e187cd9,b3024dfc,731a212c,c53c2861) +,S(a984f8be,33360b3f,a012cb99,65ed10e6,43a8df49,26f8188f,24719a7c,ad6b5238,79a592f9,15c925a0,98406d08,75ec4fa,90b5015c,4001addf,1cab32f7,9f06f213) +,S(2ca5e948,76db7877,fb828609,68e39c8e,a413a057,1a39e20e,a7b98f93,f4cc4887,b1ce7c2f,8380eaff,57299cef,e840c552,53629691,7ed367a3,5c59c3b4,ae67a02d) +,S(65bc7a84,15cdd07,5f493310,de05b7a4,ae7c874d,5b5221d4,7ee556ef,4c21a0d5,ad20620,aa39a14f,dfad58b7,9f1ad70d,2c637119,d9eb33b7,ca9abca1,f5dc3db3) +,S(a0b6b293,a9e25a97,18fa0db1,16362757,6e39cd43,83140822,b2241fa8,c432f276,2cbd88cf,29570778,8a6d79a3,b451833d,c596fa08,8b26c6a9,962880bc,48ae2b19) +,S(b4d308f5,74f7832f,4f402626,5ff81788,91a86724,9df74486,f241baf2,28e130a3,ca82dfe7,4c5768aa,46927fe,70c93227,cc7c30ed,c2fb6303,9a1552db,534019f9) +,S(819b48da,f19c48c1,f6efd0b7,c4ff5996,dcd5e99e,7146bde4,1c83e333,ac891b3e,c15bcf4,c9a630f4,e1489585,e5719746,ac55210e,c9b82da3,898a0d88,4eab0459) +,S(66528e21,adf8c447,526d616c,777dde1,fa7469ec,175facb8,3ac9ed2f,db773f85,c5d38c7,c13449ad,4f346498,1eb7abbc,a98de561,d94f46bc,edf3dd10,1839d91e) +,S(a26e3a0b,6f61c611,28c2afc9,15ddf48b,8d3d3901,df93a2b2,aeb82579,4822e605,41f4e806,787884ec,84716647,ed72f331,126f141,6837a232,e1612ac9,99c7d115) +,S(56623040,c198fbcb,9aa32066,90da22a5,a0496a82,5313a2fd,529fc9b,26647d22,35867158,42a4c950,e67b9033,23c55fe0,3ba3bf92,a9ecc5f8,39708869,7e2e1e98) +,S(acb401f1,b535f181,75ba9cc5,8e32514b,be8b6d19,1401248f,20500dba,23ad4f,f57fbfc7,9bb94ec0,eac7d09e,52b699e6,d8407335,e6dda706,f7d1bfe0,71e09f6a) +,S(9e02a873,fbbeddcf,b760d48e,6e29e6a0,b37cae8d,6348a8d5,bd651be0,59ecdb33,9f926735,cb2f46eb,71005600,56dea853,9fd6d140,2a57d05a,e884e8f1,1a293c39) +,S(3e88f76b,ec410c46,ca20cf7,2d90c66f,476fb966,c46f20b7,facb7f50,17f71617,bbbb4d9,a453277f,a7bb83d2,eb8b2950,3fe51b0,7d4b93fd,5e993663,9b78438b) +,S(cd39870c,a6484a9f,e6d30e47,3a6f5e8b,3ecc1702,e191b5de,3d4d6cbf,dade08e6,234240c2,8f2b2233,9369298e,f22cf32a,7663edb4,2524f02d,6879b4c9,f4ab442d) +,S(5de275c2,69799058,3348c4cf,8c039b44,daf431d2,b7b1f862,98ae24ea,271644c9,adcf9fc3,10ce2d93,8459db47,30273255,cc483342,3f6bd4dc,56593f06,6466b8a9) +,S(2d986200,bd9dbe51,eee40ec1,2730701c,621333db,9e71c232,1a6463e1,f26cb76b,57433deb,d9149b32,37315114,e9747758,228d17be,5f7c54d4,f552e730,1e094329) +,S(654868b7,39d6a72e,75223cac,d0f827d1,789c410c,fe0d5ab7,24cdbc2a,c9bcb269,3d8d4270,63cfe,6724f8d4,77ddbd10,b24899a,3ab0a33d,87683646,9f4806ba) +,S(d97cf5c8,e1a40197,75312099,fb1a2d62,2b3354d0,e524cbe7,bbd3187,506f909d,53c8784c,cfc900a2,f159e98b,76481239,3d883d70,8a953905,44691b5,1c8c97d4) +,S(697707cc,9c74c828,7396d53b,9e5d436b,24b861d0,2fcd9208,dcdcfb54,8ad2d903,bd203dfe,7f4a3484,1f5ec966,f063d251,a89b7da5,468bb2f7,32775a1f,3a62412f) +,S(36b4329f,fbbbd80b,e8eecd1,358c05f3,6616b456,588571da,c23d7752,edf15d65,7c42145,d8774827,a0cbe9e,b9ca7b90,2353c6f6,118291ad,950dfee6,124fef3f) +,S(dad2b02d,a182ef28,5b00b0e3,2af77064,ca6b3c1,41766194,7fae0663,4861e144,ece34dc3,704d0561,f6029366,aa45f192,a2b55b1a,1786e8a2,d84b2361,eb2c2af1) +,S(4cdf386a,c0e7cbc6,e19c5f85,1edb009a,59b0526,f3f4d0ca,3c82f280,dd33531,3f8b3eda,4ae484e0,95916efb,ecf1ed3a,27bcb034,6cbae87c,6a388488,331ddc86) +,S(d4b65a7a,eb74d38f,2a8e9383,2ad27a7,2e2a89f2,2ccb5c24,9e4e55d4,da7a0cf1,a080a32c,ac9e0ee2,6e6538a0,233f2374,3428b2ad,821852fa,bbad2a23,63a7d7e3) +,S(c41cd230,d99c5f66,7d7ea000,53945fed,70a2a807,4893d488,5be2ee46,cadff9bf,4a7faa2,3ea4ab42,5f21e12d,dea7530d,429c64fb,c05e1b24,adc24f55,c34af43) +,S(4c67ce59,9a841ecf,ec147a89,c120619a,227100ab,c5dd0ba8,da6d362,6f687824,aec0ecc4,b65694f,150da4f8,fd514d37,52f4c6d1,aebd8b5c,19846ea3,bf4b13b2) +,S(e765b00d,a067b5cf,a40bf02,dc8ed6bd,4e59b470,ed6eebad,c02b49eb,1d20c37,23e0df00,9ca95773,a91c0805,40b024b8,34c0d7de,4dfd6c43,76c979fd,2665f21d) +,S(18a8cbe4,d7585fe2,3b958cab,a9303d9,505928a5,7ca1058,21a9f192,ea52298c,9d00506,4a1f3406,c3864d73,2ebf3e1d,b6f20234,d0f5a99c,3623ed9d,530d71cc) +,S(2dc043ea,a53c27b6,50e2f1c,b6fb7fd8,26c4fccb,9572bbf5,103356bf,87b3d649,2695f192,af96b031,a41b72e7,a61593cc,30672c07,cedb0908,35ee207a,5cf18271) +,S(71699cbd,e1efa1f2,914bd0ac,9b28111,8053f7ec,d51e79c0,44daa4ac,ded9c9e9,8519592f,a3b05922,86797110,b222231c,fef973bc,d51ea4c4,34998999,63637c05) +,S(23f4668e,40761e37,235dc0cd,41b6c7ff,1951678f,131763b8,7d394e12,6be4c370,1cce4181,2279761d,8753dfaf,8bdd206c,e4cbfc5f,ccfa8826,9d2d4327,431fa689) +,S(92366959,9a173d3e,826233c7,8062863c,2a92b525,106c1159,4885058e,4a7797a6,d1c9f57c,d03c0042,38f898bd,cb45c064,a1f2cc56,222bbc03,a61997fc,877b23d4) +,S(a2dd03bb,a75a7bb2,fc9915df,c66c0b22,76a7347e,6cca3d32,e5727cb8,b54bfb70,9ba4266d,b9c66907,b25c41bd,b96f8a94,a9559830,f171a878,66372067,51c7126e) +,S(79174d3e,2379484a,d3191db7,26073dff,d69a31c8,94314f7b,282ed68e,71395ad7,1cada148,7ded181b,f1a9cd30,21afb04f,4402a171,3a570d7e,9f4928c1,2069315) +,S(874597e3,80449235,af5c10e3,7af7eeb8,f755ebe0,6784d5e3,ba0d1021,fcd3b12c,2ebbde83,58c4f2ed,cc89bd52,e6cd61df,a251bcf5,713858d3,d247750e,266a6129) +,S(f23c1888,c22a764,c85c6328,387e9126,f4ad772c,fa0a6034,914d5f60,7efcddc1,6cd5bdba,cb3c6cd7,4c2c5cf8,1c62e774,560211ac,f1ee8096,be9eee5e,b716881e) +,S(a4c2054c,3a834498,6dcca592,db5fbe06,7f80d32f,8c492436,79c57b76,ae13b96,7ca515b7,8a3d5590,6100ecda,f7066459,db9db34,3bec1b4c,6a57626e,1f560444) +,S(d6880dbf,50d3faa9,835404e5,d723eec8,b1bae88e,b8ca22bb,a85fda5b,6a8cb669,a08c4200,718edd4e,42b775b1,1beb9a6f,eb3bb93,b54c57af,5218eeb9,7aa9fa09) +,S(2dfcf2b0,babd3990,c305cdbf,cae7795b,a2fb3cb6,3ea0cd17,787122ab,5af86bb8,e0e921a,15882601,c151fd93,d7b7c607,cf033633,e6498004,d29cbf76,7fb19f6d) +,S(d1dc82f9,aae7e02e,177680f1,e5d73ae,8a178207,7b5ebddf,45b56bac,fa1f11b1,4c9294c,e3ad0fa0,ceefde5f,fd80905f,ce57a5c7,c6807da4,186c9b4a,7c9d6237) +,S(ff111200,4231109b,d131e7e0,f6434461,ff699d8c,6be3e6bb,7eb9e827,9af4a4b3,2c30b8db,bbe56de5,3d8b3307,9dd741ca,8c7aa596,78a3c75b,a781a77a,e470620e) +,S(9fc4e1ac,28a8f268,c66aec12,f5e795d,f3dc23d5,c515c5ec,11c394c5,e6f2a11b,188bc037,ab114fd6,508627db,12317d0d,fa194cd1,bfd56c1a,4ba25d07,206aaaa9) +,S(bdb0b373,5bcad639,386579e2,aa78fc40,ec2f4700,4b3174b0,1bc2cfdf,f4164f95,45d65b9f,eb1f60f3,29195060,78d5c016,8c6b1820,6afcab34,a2623e1,d2bc70a9) +,S(1386e11f,3950b8d9,e87589da,c3dc9a47,bf36b0c7,8378d2fb,253e5bdf,9f704465,415f50f4,f048413c,7eec4c2d,122a4f7d,f4908265,31f9dec2,313bc7b,b1b2402e) +,S(be246169,75b321a2,edd491be,90b7a11d,75a36c12,ca782d20,732a285c,5a6a1572,ca9109cd,5b041864,5026977,9490edc9,d239778c,25609736,7b52d82d,97f588cc) +,S(baa5965a,c352a017,80b1359,3945030b,32c83b60,805bff01,476ece26,cf89384,c83a9515,dee6663b,b5688d5b,483f0a2e,51c8180e,a130e0ea,48f7a4f0,1d3d06e6) +,S(17dfb33b,957bd5d3,36c918f2,cd1fdc95,23e2980f,20a7666d,bd5e8a7f,8ab1f83e,32ffdb3,db6dfa31,ca67a5b0,27a648be,b978b6cb,7ace4241,a0b6a7d8,ceedda20) +,S(ec5dce25,af07a01d,9dc43a9,e92dfb51,29146307,cef69b48,cb7b6e85,d9cbd91f,1018c449,949bb2cc,e185a9,4a9a06b6,bca4c8b0,1a3079b5,3f86d830,21d46de) +,S(a56b5b4e,d4e4e3a6,29701889,2cf21f67,868ebf37,b8696ebc,83afd980,b5c63817,1cea139e,521c70e3,f0a4b02c,c20345df,90a579b1,20ea5dce,bc1385bd,162adfd7) +,S(2ff27783,681d264b,540df574,b478e3a6,2b919e0a,c4ab1b66,3e279083,25a707b7,3a477dcf,65b233e1,34ddae74,7fa5971c,cc0498e7,be9f17cd,5e34bb0b,480d360) +,S(aea30054,dcc9f7eb,c9dbbd45,cbcea779,49780d59,11edcc19,937e6352,a726b3c0,7ba5e2d8,9f681e00,bb74a353,f37c36c0,7264acc,d6a31529,cd5275ee,94a631fc) +,S(78531772,142432df,81802ec2,84884682,5ae2bc93,aed1fa8b,e345c106,7e23d059,6b8d514c,a0a13c1c,6425e5ad,f808aeff,f88fc6be,dbdfc788,1d174868,efd21063) +,S(c104c683,8448cda2,c94b0303,7b5ddcca,d4db1d7e,e744e70f,5f9275b3,244b8405,ac9e6545,3722e2c9,d7d97aa,767c3235,2a213391,aa2e327d,3884ecd,93f4b133) +,S(d4b02b47,3f851a30,604356c0,e9310d4d,7bd0f9a1,17db0c90,54862b58,969887c5,d451896a,5eba571d,4e55d26,9c3c8082,55c5cf18,f1f2d033,b8d30788,224a68f2) +,S(93d2f6a3,e97e4aa4,10fb6006,f3853f85,65bd14d,aec87192,e61b8f97,93f29b32,a0a840bd,336034f1,a98a0239,c6ab3ecb,eadd69c2,51b2e03c,339dd4bd,7a407308) +,S(7d7d7357,467e23a1,2022788b,2ada9a69,1243fbae,486cc61b,56458e2e,781f8f3b,59d5566d,97bb583b,940de406,44e19530,b1bc7ced,2a00c50,f4bbef30,d899e7e6) +,S(ea80f7b5,8c72080f,f2d83604,ccf6e4d3,28a71914,abf94888,8dc87c42,15fd4a6b,ecc6e626,f01f73b2,5d7e92e0,d1220b82,8f2f8ef3,3cc92111,3d15bfab,179ad8ef) +,S(c74366e7,26949fa0,6913e6ab,c41cb17e,c3837659,253c3038,30d543f6,ac0e4aa6,671ed272,2626ab33,14b6b1d8,1cda24d2,9fc132f9,51f97b95,8e72bc0b,9eb42d3) +,S(6170ed4d,c3dc2218,2b45c1c6,fcee9fc1,3897ac17,fc32fb25,aaf2880f,4cbd11bd,cb40f34e,7e8faa89,71338834,21cb247a,4c938f3e,f6a97cd3,1711f803,c872621) +,S(7dacf9ad,5775fa62,f99e093,5e948526,b94ef22e,912ae95d,8dd4e5ba,744a2ebd,69931690,6c73045,d8530a39,d33a8e21,d5912969,9f7b721c,1dd0c616,725d5778) +,S(b1d113f2,ad7b487,908767a0,b6faa413,6a8b3dad,41dad9d2,b6e8e7c,9f294639,7c802cbf,4596903a,90b1de93,649bff3a,6f63ab85,a9e3529a,7d907b41,7f973b61) +,S(d09d8d8a,17a1b113,aaafc270,db36ed63,4342d90c,64b6ae97,9733391d,eb67f3a4,c48701eb,738c3edc,a4f78313,a56660f5,3da8ebaa,3cd8d469,d1dd5910,c618851f) +,S(c264ffb3,c223e60f,fa34faf9,feb18668,4b05b7e0,6770db1f,9561ed5a,ea0bfef7,e4df501e,ebb4cdce,bbe6c4cc,b966de77,18ac5479,3e403e79,389ac330,92928e6e) +,S(55505edd,605e4299,afb5a69d,81f6df34,c7c2133e,dbc7bb10,ebc49187,857d7c49,ddc19610,7c3bee6d,ad955e1f,76afb31e,93a88e4b,de8aee59,aba50864,c295a487) +,S(9d61801b,a07c358c,f9942bd,d3614d3f,74904b8f,8f8aa8e6,a957eadf,79fe99ef,7d9d5980,2fb5dacd,93ec6c6a,92ef86bb,6079076f,7d964d31,70e3ad3b,7bb854a5) +,S(f1a6cc66,3dbf46da,e1ca98af,610f09e5,e9251a44,f6b9915c,b68c58f7,9038645d,e41bc6cd,747c0390,6d29e29c,4cbc2dec,6817114e,daedf220,b7fce48e,7e6f42ee) +,S(df247558,50b523d6,de15c3ec,38537a3c,af9a90fa,2c0e8b25,35696289,10517a79,bb567ba,e42e9899,85fc478a,4303188c,2da741fe,bbd1742c,818ec1c,e64818a5) +,S(4dc30b60,b174bb78,1f339277,ce3996f7,fe102e13,d80873b1,1a9e6b4d,54247cef,b13e5069,a7344a99,4f9cd284,1d9291a6,50e1d969,dd3061dd,ef34f037,7c85e20f) +,S(e77aac3e,946f7715,b9d0999b,1f3aadfe,de9c31dc,f8eab336,c5bcaa51,f16f64a,9d78c14d,90cb37a3,835d23,fd8d5a37,2b8fa160,1274e5f0,2bae50f1,587a11bd) +,S(24f29bd3,51e62864,3a7d2fa,6c47ab78,a6d0c6f2,c73bdf00,864e8bd0,c3f038d7,4a34c7f0,22e43220,f6d30d59,3d3ccb54,dbbcc50b,4b845712,e72636da,d0cecff3) +,S(ad4b9b47,b9cac9f8,a5f3728c,ec610000,163ac2ec,6a18cc34,b630134d,9fcc9364,afc8726e,e0f988f0,53247177,1efb25ae,e07b70ba,ec7c425c,50e3eae,2898c077) +,S(1d38128d,ce7ede1b,265a4f8c,4e6b911c,d0e28087,87244a60,dd9f646e,2932e509,857a6c8,e4f43cfe,129e11bb,462101d7,9c76e99e,c7b4aed4,efc029be,b1b9c1c5) +,S(c171b7a2,7badcf84,c3c61afd,7568d23,5a14f0f4,fec777b,4a91c92c,61358677,cde264a0,48d2cd4c,d53d7371,8546802f,1ab67815,d6ebb3cf,b6415f4d,5cf4057e) +,S(d50f20d6,f4781aeb,eeca2a8e,85e8b75c,187c6d34,a940266,daa16876,96acef4d,9aa99671,35a1dae1,af29ed05,9fa15eb2,a4aaca27,99d98c64,5ae0ed03,7f08f37a) +,S(6b83cb07,7bfd33d,181fc835,63eabdd3,a50be6d4,abb64a16,e338f18c,c098a977,3e04e660,cfe61fd8,1ec67b2,d20ca9fb,f9c6e038,71f7c838,b261ade0,51b564e9) +,S(2e75abad,dc0501f3,afa90484,e85972b2,679d1d04,62d6d206,42c73830,15213b19,4754077d,a6868edb,a0943397,3c60a581,88a55ced,dee38351,93ce045a,e93517de) +,S(8a322085,d749f63a,38dcfbba,624d0c87,b9bcb66c,e4e3d84a,e97f7781,a0e9a164,3b592b8f,9d8cc10b,58fbdc7e,982e3fa6,7aa67c90,e9ca884a,e1f57291,6d7e2076) +,S(b890b7f9,ba1f1945,2a7bf1bf,944f9949,36bb4ad,5e2e0fb8,15ddc1e,2f30d72b,c1b652c4,f8e9d91c,8a92f76e,f6f72ed3,3357b35a,5ac00d63,a039df78,eb778a46) +,S(cdf33d41,c54c8a0e,dd3a0b1a,12290d13,715de82b,21af5306,a1197444,acfdd5c9,2d7b78f,31d08fc8,afdb3940,ef1afaf7,3bf37029,1e1be3c9,5acdc673,ee2150d) +,S(20b24e10,c0f85631,fb891ae5,c0b0b36e,5a3829df,a5018c1d,8b59fe87,b051b55d,b5b9204,67394039,df0a34f1,308b086a,454c7957,40d31fd8,960f6ab8,33998c41) +,S(61976c23,257b9adc,48147038,ff5ace08,39d88274,9810bc9,25590555,b0e1c709,2b31a4c2,a712edd6,6b2da3f,84447c73,f2e3f652,d22b81d,d37ac4a9,def5390f) +,S(4ff22758,a2a25681,d28fbf09,e4cea5f4,74c00681,d9b4fe6d,ef3227e3,6092b52e,4b0f517a,4e56697b,37341ab0,6fbc92e2,4ae3d03d,392c33d2,377f7432,10a89fdc) +,S(46145b19,639938dd,9c6c84eb,d4180cf9,752cf9fe,a77ca609,5ffc8f7e,ead61f35,5b7b55dd,8a5e7d00,a3b62d20,2f371d42,8eeacc9e,7556547d,f2396c85,9503f6f8) +,S(32464689,a5d7626c,fd02b5fc,da68a8f8,dec32eba,887b523c,4b4e379b,c40bee7,6e9cb8c5,3fb716c0,b583b356,7ba6890d,2cdccd39,646a49c8,132ef061,d89f6710) +,S(56438894,2c9aa575,efbaec77,cbecd9fe,79fb4461,c61ac051,195ae384,dc0d6ddb,663528a4,29696073,f9d47d2c,bb2c256,9bf6c452,c171ca43,7cd3480f,95b69a05) +,S(f04fa37b,9c510bea,ec12fd4a,307b1b0e,d934fa1c,78cbfbe3,bf904b00,91491e4e,19b7da4d,826a314f,586c4c78,457a3075,76f3ada4,61af5bb6,c374178c,23a79326) +,S(36fe4596,b1ca6409,741f7a0c,b899f89f,a727207e,eedc8e57,504847d,2cb304cd,78f11f,4473b124,5772a101,564b6468,43d4bf76,afacf02c,bc45ab39,c7221e19) +,S(ce3e6d1b,f2deae03,8ea4333b,ebfa026,d1954ffd,f50df66,e2899b05,1ee87b0d,4cd4635f,10af69c7,50e96ede,e4f38591,2a14b104,ed9023af,60ac6e93,a9b9bcb0) +,S(33ad3a7f,a6008875,74bd735c,b2ec5dff,10ffc5dc,3163d8d1,62644086,888d29,8c959ba3,2f7b8ed0,4cb2bf2f,2b5e5f56,b29a851c,8d1f6bff,b48fab31,5335b3e0) +,S(7101a2b2,36aa7903,6348006e,cb8f81f6,b481ed8d,8a3081aa,40ed475f,13fde43d,d0a93654,51471aca,80a05745,57b4a24,9d627dd5,c1428ed5,79feac02,5fd2cd2e) +,S(ba3b4042,9c0bb526,c31cf602,3f9abe17,69974344,5e66566c,851501a5,d125471f,7db3e93b,e9944c42,b1654407,6d5bc6a0,99806c67,6cc7415a,9d110661,f4c644e6) +,S(57c6a582,1da61528,dc291aec,3a9f1a86,229594a2,27767583,5687ee91,15acd72,a9e4750b,5580b225,7768ce7a,b2909466,589a1a12,2e54a7af,35f44de,44cd5dce) +,S(c8353ee5,847efb7a,ec03d949,633132b3,9ad898e8,9a367c77,7b4a2ece,c47a7c10,dfce02ff,71060be,5e12d377,524c798e,97bafd6,e9aa9e10,27c07a8d,6f7d3a55) +,S(b0f6ef67,78b4ee99,6d7807ca,9f1f6f44,203eed8e,62584c6d,666e3698,e41c0eb1,b92763af,c9ea095,f757e921,ac0bdb02,605eb66e,d3e1735f,f8f17e63,dee5460e) +,S(f2e4015e,62645bd4,6f858b25,cb636f97,6ccfe5f8,da065b65,1ec170c,ecf5c411,8c05cf9b,19459597,7c1d1b6,4ff6e902,5d78a175,6416e0a,ebf33c21,7b3d5dda) +,S(ffcde722,ad4a2223,24396b52,5a95a233,31dab41d,95a4e19c,1a23c2e3,db7460f9,f7282903,525ac2ed,3f9db21a,92d3fe4e,b1635a8c,77dcbf8b,e671146c,8eca8115) +,S(81dc05b5,2d9a210c,4904bbde,cfb4eacd,8b3f08f1,d667e9f0,a27345a9,7d37b37a,747aad1d,bd0003a6,d89f9d9c,fc00977,719d24a5,b8ebb807,98d1b644,87105f5e) +,S(5b92318d,a267772d,94656087,8d698aaa,7d2c721b,28dfbc20,9e4a3e8d,1b0eef1c,b2d274ec,7aade417,4f2f8766,1b5018bb,47c83d32,b2fed50c,437348a7,93041906) +,S(3eabd0fd,6b5bc51b,c187c943,511c3005,8f86e474,8547fcd6,49595070,26fb805c,95e8bbe,8187398f,fa4ea4cb,b50bae2,19f8cc5a,5f09503b,3edd115f,729b2101) +,S(a64d3807,f92b91e0,717c310,ec799908,43e3a394,a5ece3c8,7c3bb209,8d3123ae,50fbacf8,be11f6b0,ea0e36b3,5c46bdb0,8fb79064,59b52901,9af59b1c,e80ad239) +,S(db9ce153,7cd47f3f,4b08858a,d429c975,9ce6738c,2e6d56f0,fca12e70,777b83a1,a91b2016,9fb1e2f,fd52192d,7030d86f,66358516,5ba32829,6c9aac95,192afbf6) +,S(bea03f49,76ee0a86,e00bfddc,79e52173,1baef841,d751ee47,9a46cfe7,89de2399,feec1fb0,3901a923,862054e6,7024ba7f,4c485c70,2ff22aa4,1620e857,6dcc863) +,S(cda308eb,6975d59,db439e23,32505d29,4ebdca67,5373ed79,25b52a6e,f60a33c9,7d2053c5,414c9bcc,5155f17a,6fc206d8,81cc882,54341778,1c5db51f,3ce4c224) +,S(430bfb3a,802988b3,a68d5595,c989cbe,75d409d2,68dd84b9,a1d4a5b9,42360174,3de4c6e1,3c87338c,8bef6195,6559335e,bec503fa,2025529b,b015cac6,6d8060fc) +,S(b4b1b7c9,932be243,6b06b2c1,e5de312e,4a409498,11a226d8,5bb30c5e,1487c36d,e169a70c,b95988dd,fe1a98df,527fc172,61cc3103,88d41ed3,4bff23bb,31da4dc0) +,S(7a954055,d2d6acda,8dbe81e7,46310113,e26af09b,91cd59dc,92a479c6,d6079ef4,83c6d3ff,4582eea7,becaf8bd,422c0558,a2bc8d6f,cb615c59,7c46982,47cabcb3) +,S(aedd36fa,91a7f95f,2b2f32c9,1be77860,75783bcf,8fcb20b5,f20ca664,dd89474b,c747f32a,174ec6a7,936f13a4,7e80a2e9,324b7f5,e163b396,218c4c35,9391e565) +,S(41052d48,54402d09,a813492a,2f9362ee,9799ffa,3d270200,45a0ae07,9f913f60,97cbdcf9,b60518c9,74ddd987,386d60d1,3d10defc,8fe64511,843d5bf7,13774178) +,S(886e5afb,69f6debc,c1c5be6f,b636eea8,7314ff1f,975cd96,9070e376,c1a9973c,6a8ec4b7,98fec5e,b4a8d645,c7b72663,d6bf4aff,8f4f4b36,c064bf3b,f6e7b5ef) +,S(c93adec2,ddf85ba8,d9147c91,82ee4fbb,5727081e,a6938c0,a4bcfbfe,6856dee8,9ebef5d,2b2253e9,4474331d,b52739c1,71214093,aeab11e4,e51a2be4,e201dfb1) +,S(d97166fa,94a4e51b,ad21e1d9,76e01011,655ce24f,5f5afdb8,feda67bf,8ae65a83,815ac894,57f83bf9,5579fed2,ea470ad2,ac1c83f8,546ef3f8,bc383701,1bc62a48) +,S(c23cf94f,c5a93aa1,719ea8d4,4f426fd3,d48220cc,10ea558e,e4680c1a,dc91b18a,64a4dd89,8f36efa6,efce9354,fa30f506,be3766f3,a31839e,1fba56b,5a07ebd3) +,S(7236b1df,88751e98,2689e049,c5084b71,b8d7979c,2c412a3c,995e61c7,2440929a,67155955,bf5d1916,9e36636e,ba56fe44,f7cef6d1,b0afd3c2,beb59b26,5e3b67a6) +,S(d1890a85,df4f7933,ff72fad6,5b95f5c,c9fd8683,3c1bd2fd,56a3b7c3,e90428d,8b4896ad,4b4469d8,af074eba,ac38563a,ca68888c,5411ce0e,b3701ced,75d4f87e) +,S(41ae85b1,9fcaf4a6,13901d2,3cd2376,62f299c9,7cb306ee,8ffc13fc,75d54e15,20d99cc3,215f0b1c,20922ffc,6e111b53,e88ffb39,bb6e118c,61b9e3ee,fa7d01f1) +,S(d125489c,4e07c44f,35d39008,e4e29c43,c28ca505,3e370570,a7bd34c7,57e673f5,d142e19e,825ff93e,b6661160,b60d4e06,b4393388,43500b29,2d4d62a9,28db2bd2) +,S(8c50b3d3,667b2aa1,a60c425d,1128d389,f2786b3d,656ee126,dd57af96,ebaad9e4,55eb7ca1,c2bb5881,7f82cfc,c8b5ca35,5c2aec5c,68dd479d,948261ee,d342fce1) +,S(3e77a3c8,a2e995b7,582f502f,9bb1230b,35311af4,dc8d0744,9211a13b,444fd42,99c427f5,8365ca18,75272508,7dc57985,d59d72ed,aedfd5f9,d61517c6,1fb8679d) +,S(73ffde64,80547448,658ae5a8,529755d7,2ad7ec84,5711f0b3,20acc53e,a15ab609,786de118,c6a0daee,48f3f585,d10b9f2c,b4947661,b844ed51,59903ce5,f2cc8d18) +,S(8f2ec78b,47c61a39,c2ed1110,902b3a43,4fc9ddfc,b11b1ed,75c675be,5b8a172c,441686b5,c1327f0f,d2bee35c,5d8f2aef,b6da72ac,e6206982,6d6812a0,5b937346) +,S(c36c0376,d360f87d,28069511,7eddf1fc,75ae7118,5fd5a82b,b47d8fcf,519ae4d4,44c31c56,cda1c2d4,41161ab7,45f3c0,25c4ada3,72396658,cca23f93,bdb6a303) +,S(1ff06490,3cc7e686,d408909,4812a7d8,531c4188,ab8aaf4f,f10bcc5a,9cac352c,87af78d5,3122ad89,9a6a1297,fcc87c1f,252bbf9c,d8cfbf57,f64cb6ad,fe77f3a8) +,S(1265a4c0,6e1f1a6,126a9e37,a6e4f90b,290fe449,49b82bca,8ea73759,451e0b25,4f0f7a6c,9bc7f00c,42b90d95,95871176,d723941e,38335581,8f7aacdd,f830d15d) +,S(2595358e,4d45d362,5fa1c89d,a3249cc5,a26ec3d1,e554a863,51b79fc3,4eeea90c,d9b8d147,e4e00450,1baeeb5a,8440235a,88913063,bb1ffa78,9402c3f7,2c603899) +,S(3f432621,7a5f415c,b028f338,40fc226e,5906a09b,d054eb55,45609fee,90135082,a572303a,131fb0f9,c63d88e6,3520ef2e,77bcfea5,1031fa60,fada909,a610c830) +,S(9ee85c9b,4cb0102a,6b21c517,947d798c,c26dd853,7bb5d6c0,46a50144,f3297f45,85b798ab,c2e4fcdd,bf3e17b0,49e2a495,6239ba16,9917ed08,ebe109e0,4ac8016d) +,S(479c2ec0,28e8c83f,d7946f43,8d802ed3,d728179,55d94c55,bdef5050,67774934,c262229e,23eacd99,f9d3fb37,b7b9040,47cdd5a6,6872f4ac,800dbb3,d87fc3fd) +,S(2a52f4d,821cf4ae,758ed477,6cdc3bc9,2d3924fd,97a12f1f,4dd5a646,24766b4b,28500754,6ca8f142,6f3a4a6f,6ccf8437,37c6a917,7ab59b92,728f588,f11509aa) +,S(d89159a6,d5447ab1,bd03d44a,a8db3410,c86305b4,4f06b25,b88c4244,5ab1e929,c539ee3a,e7dec645,810c4a02,e1777977,d98ddba2,281d5701,2ed2a4c5,85057013) +,S(c91267af,4c303e07,ad82c1e6,2ddd45d7,cfae00a8,d27a34f1,eea8d15c,1add920,975967db,347415ae,24b427a1,b8f7229f,8db0758a,7ea13f7c,582c260,c0711b85) +,S(c860be31,18ce92b0,39b27a50,960d3caf,88e24bae,6e45fd8c,5a253a78,e3d0e6cb,15b8374,922f44f3,adaa213d,5e3facdc,9de1ff6,4da677d3,d89f6e0a,a800413f) +,S(eb8b5f4,2fa90313,b3dd7d4b,d47338e2,9861e52c,b492e9dd,6a1897ec,4da14c14,9d1c4d0d,56c570b,8835e188,517fe7db,490aa6b2,bfbe1564,579e7af9,c0647bf) +,S(151e39fd,d5961da7,44ac5871,94081a88,666d3dda,6507404b,607d449f,1b3c005f,476bca6d,6bfc5e2b,2c183794,563d35ac,aa8d38bd,ec3846b0,22831bda,38fa28fe) +,S(b46d2d52,b764f922,7ead0399,c391a9db,1737c9ab,35394951,5a57c76c,c3c05c59,8aeb78db,db1e52bb,a8030a3f,b9f57f6,644332be,6d0ad41c,34b7fbd3,13c6eccf) +,S(a89e77d,30c66dba,a27a2dfd,5af0684f,f6ccc84e,49b8d98,f402a88b,20e5bf7,af45b2da,cffcc49d,4f6db574,29f13971,c74f5321,4dd4af49,2bc7ae5f,10abe1ec) +,S(8d774c5b,eaa0cc57,7479873f,9bf5ff6c,808afa4c,6fa6f2be,88b53841,4cd088c5,6b9461a6,600ae1ac,4e617149,73fa8b48,74dd7cc,9f331eb6,e15bfcc3,2e26eb63) +,S(34ecc029,105f5e19,d6c2471e,eae5b671,cd55f2c1,bfba7dc8,46787c92,ba7de2a3,13e3cd9a,db98a6b2,433dba08,ec7d40c9,c2467878,f6f4bcd0,ce60397,67aca327) +,S(41b10298,6889f83e,e89d4f8,fa50898b,c9bbf650,2d153c36,85064c9b,f3dc3c43,559f5bf4,fb827bc,dd068d3,cdb14d6c,ace08a47,c30e3fc7,8972ceb8,9f88c21f) +,S(4a77505,79ae33e4,55228533,b8856da2,b14f70a8,d13ac2f4,f6bdc5eb,4f5c9aba,d365922e,3a487635,3ee1b02b,511c7926,e5c5edfd,aac153e2,686ce4df,b623ed2f) +,S(173af9bc,efacadf6,c107748f,278adc1b,d42174e6,8fe06d9d,f84fe278,70eda280,7b120d62,2463b94a,57303cfb,2c477f95,49d41a66,d6ee7c2a,4c652284,b8535faa) +,S(f0fa5cfd,ba53a5ba,df707983,134c3459,5ba232b5,7fb67a94,5c5c0f25,a0539be9,ccbc91a9,c0a2efd2,3bffec87,cadd16dd,f4292aef,a59b3d31,6e9c7082,742edb6d) +,S(a5df803f,751c4846,10799c60,db405439,9b1d5bfc,c99fb316,fe884468,e57ab77b,27f8f706,a2f08ff3,249f8b62,ac0d59b6,31fe52fa,7ab08ad5,2d09ff2c,4138dcd4) +,S(d165fa7e,d61c251e,a93e8f16,c9291b09,1f258720,fd303a3d,c573131b,d98628cb,cc0dee9,f01f0dce,aba94461,1e48f9c5,282a7480,eded0794,81d0b8c,a9819a73) +,S(87703371,46a8694e,2bb5cb10,76ffcd94,309c9c8c,be6e8cf6,5a77f4ca,4d31efb1,ee64af6a,5569a205,2cd98c10,871b2ba0,6addae3b,3cec463f,6002d86f,b16e5e9) +,S(1c7e4ec7,c090906,3d98f786,dc22db53,da4d258d,6e75cbae,30d4b99e,f4ca47d4,d2001df7,3297e6ec,c0aec17,e72cfa6f,5951e2bc,f03e4aa5,5f329c77,47cd92d8) +,S(d485ec0a,1a0abc6a,69f308d4,c7f8b8bd,fff5ac6f,ad4ae4ee,271a87ce,973b58fb,68f51764,ee705265,3e2f7d7b,7415847c,3856e3e,1a7f4932,6fbfc9c6,5976cd48) +,S(ae5ab510,48215ea2,3be55d93,4e0dce0b,ff88f09d,10c8953e,390b79f2,da26e43f,9f80d71,36a5da61,7f90d0c8,a6d9aecc,5cf88abf,6bbc2181,5f8320a7,2fa8929f) +,S(cb879f42,4613487c,24aa73a7,36f211ea,96541877,33fd7091,40a824ae,7641a708,d46a4ad5,7f607301,f61648b6,e99891d9,ccc41af1,af29a66b,b894575a,a6b3d5a2) +,S(1e8d6ac8,ec0b543d,1e0aea66,7f35b556,87e30be0,72841fc9,3f599c81,4a750d7e,8965853e,6519ae5d,c523cb52,720b004f,ad2f03e7,aa3e0413,bc68efcc,c0617f85) +,S(dd8e5b0f,be63df6f,5c20e447,778f923,2e1b2c22,4d28cfda,b2c672c6,66d05f8c,d8b75f77,f955219b,d4d95e65,35d5cb0d,23c2a1d1,671b9416,2da9c4c9,b2d4a94a) +,S(78ac44e9,938bf51a,691132e,93ec3a42,22be3185,35209054,a76b87c6,645e0252,c0f66cf0,3c20dd,d136d1f1,cc00eb17,efdf2a4e,72d373a3,99c20da8,8342299d) +,S(d53110b9,5034e916,d904cd15,1170761d,4f3492ad,9e257265,3ef37739,df9bb035,c091177d,796d199e,5c05abeb,29d0df1e,e5ceb93,d272e6d,d254b6d9,a6dd35d8) +,S(868b2732,3debb9aa,60942498,3be71d0b,451ea44b,64c22225,2af3d63c,3eb512b,8951dd34,39774c8d,89cf4b4c,485889e3,df2503a,102ae568,c63fa74d,23ee659f) +,S(672de7f2,34e96153,d83da7fe,3e199099,52ee988d,961620ac,b8c6b4c3,520fc50d,ab02a8b5,2a2d9306,8a83a0dd,23ff882f,b1052f22,72a0ad11,cea13c63,4efa33a2) +,S(4887f473,af8189d9,c46ae22f,c86ba6e0,f03c81a1,490de032,72b07937,b63a7527,a2e7a713,e1e6691a,ce09dc0f,a86c92b0,a0097899,7fbf26d3,98581731,a577a21d) +,S(f97ddd77,38bb419d,ec051fcf,a93753ff,e3dfa122,6cf02e1f,23afb376,7a121440,2fa9c241,f747fcda,dd09139,437eafc8,94e7a47c,ec8a7ffa,1e054ce9,21d73243) +,S(ebe75f9b,2c92af9f,11eefb04,3456f6ef,f616d1ec,b616a9e9,9e7f8960,4f1d62fe,40b5cf37,b06cfb0f,294da3c0,f756c867,af06449f,e2a916c8,a327117e,9a47f74b) +,S(10d376b1,1f0138b3,238deefa,b57dc84,7ef66849,14e9f120,1a9619c6,b1715a13,a216f393,1f398b67,d68a2888,1d5a31f6,e5e0da82,e2b5060,4c6f6322,9cd21748) +,S(69e26679,f103a1f9,8a9a4d88,c973874e,db7c82ca,99e48554,37284445,b55517b,cab62aa5,13b41a9c,56ea455b,6a880b95,9d400bba,74e7a203,7b60ccb0,4a89b8c8) +,S(3acf827d,81e39933,64e99fa5,63f89305,dcc60b62,44ecc0a6,b101c6f6,ecd5bdab,77e3bd28,40a99c45,30ab7767,4d8ed17f,f57a4f1a,4ab91732,7059114c,c06fadbf) +,S(2e5125bf,9e263d80,7a220063,434f928,d9a4907f,68601eb9,829041e1,a7b89bc4,9810022a,d7d3c333,d7c022d9,d0779b9b,5807226c,9fd41e65,c3fc8e1a,a7a0b51f) +,S(7b68da4a,197f6bdf,56948023,d2baf10c,9449d6b0,b18addc,49385125,e62506bf,85a92b7a,190aec87,bdcb9df8,42e93917,9254ae6f,b45e6764,32e410ef,4b28434b) +,S(60d4b53,9a29562e,8fab8ad7,3b699550,3fe7d6c1,e2ba1465,f05c92b1,61dc829f,2c2ad439,8fc7c836,5b2efcf2,1e4d0156,1a753f5e,d945ef2,bb1a3394,203d07eb) +,S(5a3a1bd,30250a40,d22aed42,71892b88,3c03ea0a,baba458,6b65cc50,4c79b107,9bf3bf42,df1637cb,80c1fef2,cb9bfaef,dcbff761,89cf9f5e,d00f0f4a,e551e31b) +,S(9b9d93b5,6b70fc67,5476c6a,6913e173,11ed1ade,6ea7b810,b9c90977,a8f3707,ae01a481,7a9ce6ef,5584a48b,fb96a9c5,21d5bb7e,2bf73cb4,b71f4dfe,aa7da298) +,S(44bdd82,86a3a4d7,6ecad7f1,ef66022c,6a49b916,3d7a8ccd,e54bb017,814d2f70,26d345a0,52034ce8,b4382905,f60f8885,e20afd4c,54df6d6c,ccd1c2e2,5d06adaa) +,S(8de8205f,e44946c8,582dcbe7,152dfe3a,7eb85e7,bc070282,3c972727,54463869,1dd97d78,e12a92f0,cc2145ee,db4ef561,af21d3db,f3cb123,ce0bb582,6791a30b) +,S(c36a713e,3d88ae25,f79b4add,90c6a724,77be7d9e,a62ca0ab,2d5a800d,41f9321f,2df57da8,6cf17f7d,63ebb85e,e7570869,cf90b462,e76af48b,641c07c9,45a638f6) +,S(1ce37a88,f25b8b81,941db8a6,13a7d952,c2cf868f,e979bc0d,5f35410d,147207a8,7fab8cb5,f6611850,e541dce2,315a7833,3999041,5c18ab0a,718dfe32,e0ebe992) +,S(e489744b,dbb11e61,a7e827ca,ad18ba55,41f4c02a,b50b75a0,353f4a2d,f504d575,6abad3b5,3ad97e6d,a301ff7c,7931f37e,55246ab4,c7560,363ff214,2cb9a398) +,S(cb4ec0aa,c1cddaf1,c7a67507,5cad6762,cf8ffce7,6a06f76a,38bb88c4,5181ca3d,7f15e726,5092287c,d2ccf3c5,dfcda0c1,8c63f2ad,21c06a2b,469bba5a,d9e4ff36) +,S(aee1c436,6b923847,40127dc4,150c6dcc,ea62864f,394415ed,9a39d539,adda44e6,2496d2da,97990e6f,5fb1526d,b93e92e7,8a011c33,61218d,c3d3c56d,952f8666) +,S(a099ce61,d950fa1f,19abc21a,79c74021,472c46ab,d8f67798,34df0429,ba785491,c4dc483d,6d61ab1d,7578ee0d,7548e0b4,295891a1,39774c22,7d073232,f2f3ecfb) +,S(6c57db5f,b194dde1,b8cc9686,fdb65fd4,eaf8aba1,84434344,7a770ddc,9055e429,2dfb48f1,58663b3,6a7747e8,4b5a9001,163ea20e,f07649f7,1d7a21b9,b11995e2) +,S(f6efa15f,20b2e91b,cd7323a6,51e5d7b7,a8b323df,924c616f,21a7d6e0,e34d3c76,ed48a439,2bb4d596,58e75757,95a0a4d2,7443415d,7662a535,a6246d64,3804fc1e) +,S(e7983476,a900be4,e9dfed94,42f575e6,4d9af362,1e874a99,576e06e5,d31485f8,9d21080a,8b0534f,6b2dfff8,9eb8172b,cb5388ff,d910fdfa,405ead29,9df779be) +,S(88ffff0d,7b415f76,8c515d80,9c607949,b469b07f,3978caff,1ba64e,ce198ba1,6816bd9,ab0e773c,38b73787,2881e96b,8eaf381,b155b205,79b24a39,eb9e0fad) +,S(e5fd2c3c,a1c85b03,3d93a3c1,261a5c1e,c4adb72a,7700405e,7c0bb108,d8fec1fe,97bdee17,50801ab9,a96e3fd4,ec4860,e59034e5,c02f9168,79b1e654,5a65fd39) +,S(fb010f18,146336ff,30dee37,b25aa384,9588b83a,bf943125,613d2c72,c2f5b3c4,4b0ff7e,7a6f15c4,d377e92e,73c8935b,d2d9f7b3,5be91cec,da891f61,c7631bbb) +,S(9be574b2,c28b1460,a1d67d94,43e4bb85,c46a6bcd,a957499a,179cc8f9,7ed33c2a,16aada1a,367def6e,d4f34409,e0ff5d41,f3854494,6a764040,e1109574,109bb310) +,S(358e97b7,6799ae09,b80b6797,90e34630,3d61fd4e,71733d6b,3c90fdee,2ad44bf1,3eeb5209,175677af,c16a3869,5ff7d3a5,e9704201,b802ec33,50c6c2ba,c0ff4144) +,S(2ed930c1,c941b209,b6e7cf3e,83971e70,9e36bed7,a4d3884a,faaf013d,5b589b59,ff6a5a5,e601377b,9dd974bc,4fe71e36,403f2cc,90b16834,b1beb6a0,98553d2e) +,S(d86110c0,6e8b20a2,e6da1930,fbda70a0,d8c022e3,e68255f7,262168f3,2bd58986,34dd600f,9b7157cb,2ec545e5,c50b3f95,2f422b21,4afe255,b7337815,1f3dc048) +,S(4e7ffdde,305ea002,f7dfadbe,e2da926e,6d2c2714,596fb052,7eddfe92,81d4fefd,fb4dc1e9,476cb2d1,3bef4548,9ab7ca86,6ccbdd71,4cfc937d,bf024f12,ff04eaef) +,S(6ba04fe,47c4c99f,849fbd68,7e1ca6f6,3e00179,3ba3a08f,86acf668,df0afdfd,dad78b7a,9d34c738,31112801,91476b92,b8eff31f,fcaa6d,a0704244,5fe32e37) +,S(bda2c2c4,86029d0d,b804f1ea,e9215150,34276a88,179154dd,d5d9f176,cd7f50ba,a70291fa,47b98bf1,fecd9aa5,b53ca619,41d62c9e,c8b02ea7,91c79482,afc8f1c3) +,S(99801a16,4da92a6b,de6ec7a2,69c2798c,b421af01,5ec24c8f,1b090169,18980a5,3af209c7,de27a683,56f242e3,8805a368,66cf7780,60c2806d,76f9eb06,35c18358) +,S(67fcf955,dba84390,638517f9,5792d09b,64c056aa,ba98acf9,d63c2bbd,df5f021f,96f96080,b5758233,ee15e8c4,7ffdc3ae,bbc752a9,d7697e1c,3ec3d479,4f912d2b) +,S(c15990a0,50c2946a,e4518cf6,84ac9cae,1022a29a,bd88f8c2,c8e724c2,89b954c6,611bc99c,e4ad5b6e,3ac932cd,e2e70e0b,a3690ec,758bdead,5edb3b0f,b5b95d56) +,S(c5261ad4,f6d03a0b,c15ace20,aaf95bf,94d9ab5a,95a45d90,6ce7a622,3b09d59c,5fd1b7a3,b22732c7,4b5dc1ca,fac99882,467bd80,53f2f606,ca5af8fe,6d741448) +,S(b0bec3f4,eae81fd7,2b70027,72a49acf,46a5c50f,48358df5,e174eea3,c0da88a4,13a4cf63,fca873d6,cf1b8c35,ce25f439,4d74a5d2,f2fa2799,d4c3bb98,8b50ab67) +,S(e3d32fa8,9218a38a,c503780b,dfe23dcc,e6a7138,d84668b3,f71b3fdf,891b6256,246ebe20,7ab7c536,8f7c9795,9e7aa1fe,69909d50,f4b24263,c32b8bea,7674b85b) +,S(ebf3bd9c,1920f625,4c32467b,7c1c138d,3ac6a4c2,b185557f,6eeffd7b,2aae0d63,58ed82e1,25fa2241,2bc4397e,73009692,af1d5feb,f640a422,f52e5cb6,42d4bccf) +,S(d062e72b,3dc76d03,5827786d,a9cbcb03,b710ea61,2eac883d,b7f50df3,fc6f7175,cc56b076,dc3cf1b9,e544858c,1a31723,33ba9848,a8c463f2,abf2c6d0,dae14a6a) +,S(97444eb2,32b09240,fc596530,374da035,f5ebd37e,6c74b51c,8158eab7,8ae30f89,fa06190f,d2072bad,b9144f72,db18819,ba76399e,d171d4bb,1293c20d,63d70391) +,S(3e1ffac8,15f68300,4714f302,1ed39460,d5e4d63f,6fdc445f,12d8470f,b273c242,86f0839f,8610c4cc,6ae85d54,b951441e,efb700e9,9ce54aa9,fb6c7988,a8494c25) +,S(deef1e7c,12e498e8,6542acf2,3782ece5,2a02b13e,3b4e71cf,e39e79ba,541d2679,e039a94,f4b169fe,a13ed182,f9e541e5,2b117536,d90024e6,9f3bcc7c,988714cb) +,S(69ed1a62,b3de5c,c5785b27,c7926e52,4ca1527,9f8a00eb,b5e1c247,a6c8265,9c5fce7a,84b79a67,9f3030cf,a179a682,cc22c464,11ffc8b1,ceb885ab,4753de36) +,S(cdb36419,5c3be45a,bc9f58e,e5a499a6,ef58ff2d,296ff989,9fa987c6,b753f82c,34a1a6fb,7a6b6c95,2a604340,d2c30c15,69c46123,e5cc5318,833f3a3f,bd622e47) +,S(c5749ad9,f4583689,f2ed313f,dc35fe8,acb6a85e,dd0498c5,ddcd4842,fa21c555,f22ea47,ba61044b,54ef967e,c8c82167,3d14d710,334784f6,a7b46d48,19f99cf6) +,S(fc86862f,b2fac126,e4341121,c82a9e14,d7a48b9c,988b8458,300dc3a,ba10dffb,42339dc,e304641,f814327b,ca5a611f,3638d610,85826d70,3d94c76b,8297f6f9) +,S(66dd174e,446ae0c6,3ded267a,faa20ba5,62131459,5576d10a,1e44ef18,69e36ca9,d93a449f,6d3fef4e,435f6fa6,3191b625,b883c303,1dd8b380,777b556e,acee9df0) +,S(736a80e9,15b39c21,5e5efbe8,ed6f8fff,7aa826f8,5c940110,3c7ce372,86d952c6,4a9e17d8,9066ecb2,95447058,4dc58c36,c84b3d9a,30ea45cc,e62454fc,ae13e0ba) +,S(7b747f80,f4a324af,e6042edb,d8682d3,1b8fe12e,19936844,b44c3e73,f6b7075e,c2684490,56e7633d,2add97c9,75079594,b9c0d038,cb864331,aebddd3e,18830199) +,S(dfd54b47,e4d2abe1,c40e0a1c,2916469a,7e8a61b3,bd95a1ea,8b5fa182,903d8339,c705b4a6,761d2ca,49f87fa9,ebb4b39,35c3c633,4f6b7643,417c8a29,95515fa9) +,S(992a5fca,521a86e3,dce0ccc5,fd1b2ca3,656f44c1,f4967931,8ccb7a28,7879213d,ca2836c0,496c75b6,4c56c13,641d0402,b64cb2c7,617c9fbb,d820245a,9321217) +,S(38e59093,acc26364,de9cc5f4,de398799,54774d68,ed4b0283,2bde2a26,cfcd23bd,953c21c3,14ad2e0d,511d3f05,678358f9,eec2fa48,d6b24c9,6ed4efd5,da3b3719) +,S(889ea31a,5969b77a,c41c0a39,cc5d006f,6ff14f22,a62a5f26,d736ebcc,f5df8239,4c2fa5d9,c2f0316f,dcd6462b,e7571f4,92aaee96,c3c888e5,21cfabcf,78d2c3f4) +,S(f70e24a1,6807d5a1,8e15fdd,f31301e8,bd210ed,5d3d614d,82eec8b0,326d7b6e,dcf95677,b29a5ae6,15e2e7b6,c370cf69,ccec71e8,9569f0b0,5715963e,da6a34a1) +,S(d6eb7425,9c17d292,e1b1a4ea,624e6876,a78aa774,2b14e94,d3fd1b43,562e35e3,c05013d1,4056ea0f,e5f1fca4,b0c74b5f,776a8564,ac973973,c929707b,b3f078bb) +,S(df7cc5f2,69faf306,6050409a,6a03cdeb,8f33d1d7,4e30658e,e871de09,59701b16,3d8a28f5,f604c765,5f28dcf,b2f3407e,6a63db14,6b879fb5,bc785e65,59319147) +,S(e6bfa4b5,85f6df59,7840119b,6a31d0e,4ad800ea,239bbbbf,a8a1a36c,f8c6b5ba,312b5d55,35402ae1,37f9a02c,aba859a0,22a8ba00,88a2305e,4afe8283,98844dba) +,S(3c762a8b,acb68a13,2e3e022b,35634b3c,1907cdbb,261ff639,9520352d,fd94b3af,2ad358b9,65555cf1,e0027e3a,b93d46c5,b104324e,2c62f9b2,5f70930e,bf49f385) +,S(b4d94e26,9955b213,8025e5a5,bc5ea171,c2ea6d04,9ab60184,88f47f7b,f6a6d3f5,197b20a8,81e9280d,96b5b4d6,ceb3fa20,38a28654,63e76ff,d0b5b401,8b59bd1c) +,S(406e616d,907a0f72,12acdf3f,d5341a79,9b482697,88976615,388064c9,74cd8ed1,72730d26,b2698e29,7f62fd98,2a3955c,da516ebd,642d6619,2d33a915,ba39d0ac) +,S(1762d974,37705ae8,37603446,c8c11568,c7878053,f25baf9e,e3bd23f9,5babdaf1,1db8fe6c,77f41656,1fa4df40,23662039,66a8f891,e5467b55,3a2593a5,1ba796ba) +,S(f5fbeece,aa5386c4,d75c92a9,88ce6bf0,f957a0ed,3f0caff9,42f1f29c,7ad765ee,fa45a4e5,85ccc691,88426bd2,8ae561d,a2f59d10,e4bd63b0,4f8a53ef,1cc3ab28) +,S(7e0d92d0,d12bb892,b87b8bc0,993b4422,cd1e9d95,144602c3,a2aa3c06,bc945ecd,601b1019,746bbd4,ba9bf00b,4ffaccd0,b1bf885f,57ec49d2,9fc91744,8aa70761) +,S(64cfeaa1,4d4e0cda,db6b6a2d,9e2c2820,d2fa7817,43d7b2c2,8211b1fa,e17ee0db,f0b199a6,1a1856b3,360f519a,a6056900,7a0ee623,69e0aece,ea64f0d0,8cf568f8) +,S(c90f70e6,99ba1a75,86073eb4,5540b3e0,80bc78a4,e811069e,f861b048,5f11c88b,7a8257ca,cdc7538a,13b55285,939c614c,14d6a94f,70509900,44b286d6,7eb84e14) +,S(3edbcf0e,b4e5e640,f40afec9,ad370813,426b5488,3090f8d4,b72b1680,6694f42a,ede4512c,c4baf93d,f05c14c9,cb17b1c1,fec46052,c7087306,2214a05d,60743c80) +,S(77adf15b,ae449ae2,f63d7c44,3c56cf9d,64d43840,5154473a,5948cc79,160b64d0,a1bf9aaf,7804cae2,c377f98e,86b75e90,6886d293,21aed43c,77e330dc,df9113d0) +,S(350632ea,23e39962,3daa53d6,5a916f31,b2ca02bb,5bca1f58,35b85165,b430398c,41931339,48282550,bfa1cef9,94c28873,ee0165e2,fa970d04,e51f8ee2,b87916be) +,S(3d6aae93,5ee4ab6d,46de768a,d6938703,262e9fdb,13bade31,d38fbd0,9fade000,62674fcc,6eaddef7,b971e964,5a688e32,14186605,615982ed,a09de4ba,13eaab23) +,S(856e564,a155a29d,c1b739e6,309fbbe8,5ea4debf,f12a9249,347a5435,af674993,a0e6deeb,3777ceb4,6017ee63,caeda231,e616fda3,c105f0cd,6174a3b3,dea84256) +,S(95f8b405,c1ca86fe,d56727ea,eecbcce7,32d2c521,415eff95,b3cb42dc,5230cc7f,c8c66b1f,2637df4e,2a5375e,3a2e5e4a,a89404c,810322ce,c4b2bd1c,91163ccf) +,S(b51de213,54aa18ed,6ea589fa,e3b92d90,732dad07,6c80b842,579d53bd,2089e0e0,8f069737,1baca2db,208f7db4,c43a85fe,d816eca4,e35fe95b,780e2c4,a3f1b948) +,S(e36ac0b2,c4b73783,7a96b372,b8d0779f,41605e99,2a0013a5,3c8eb4eb,d5e2a988,d41ea6e,ef06bd62,7c2acd2f,645acd8a,75e353c2,448aba53,452787b6,670eedd7) +,S(4d08e46b,a3e812b0,67071dc8,b76cbbb2,4effce48,cf4a4c5b,ff4e15af,71c51635,fcbf2dd0,ba055845,b70cc545,5a8658f,39ef2176,9802fbda,2d3ab98,ba914c3d) +,S(31421774,5b1a6b68,918e8afa,4e8dda05,6094a6cb,6024c3e0,c10fdd99,245d7501,7ea6ac19,1c0db139,eafdc961,e8f91f1d,79269f69,cce275f7,abe9598c,2916fbd5) +,S(79bb2dbd,f9afbc9c,f605ad45,4768cad3,14d48241,724b301,7b5abd51,6f8dd4f9,d1c9dce0,30fe1a72,5d100c07,d842a78d,beb689a,606a933,ca865051,49007b8c) +,S(112abf7c,1d5d66d0,cbcbf42,1874bcb8,88d3b3b7,5c2cf36b,1399fc04,17525731,b3d3ee4a,f44b5372,8d0957c5,e388094c,34fe0f5d,c51abfc5,76c1e18a,c920dabb) +,S(f6257a3a,60365e63,471fe77f,893a8ae3,174d30a1,9aa495cf,251812d4,c5040400,293ef8f3,91804cdb,34845404,996a24a9,5554fd24,185ec85c,3a27ef8e,c89938cf) +,S(ee7c8ee8,bec75bae,db32c6f4,3b3b7a04,2c10e903,de9e7d21,5ca08135,d59a682e,e68a0137,398fb186,d5168e64,4421ac4b,30a635fd,c15527f3,e56b21b7,c0008ff6) +,S(e292a4c0,fd63ec7c,c661ee1b,25c9d5c7,dd805a97,fc6e64ce,5d3d18ad,ddc92aa8,ede226,7fa6fe51,1d4a510f,e7f5e14d,8fa29fc8,b77d61ea,2e140739,29644745) +,S(cf914327,85a05d41,2ad06146,6df68649,d3b8e0f6,86a83a70,d32c2fdc,978d8124,f74c1223,7b0899dd,53afaad1,b9b06704,c61c6e97,81456e86,ea55e65,96b0b13d) +,S(88e58d21,95376fcf,b3f0c44c,b013f2ba,3379ba55,2ceca46c,38ed48f1,263fe894,f2f38177,bc673cbd,70853432,6ece1090,5863ad84,1140c59a,2a782af6,ccbaa71a) +,S(90ada18b,df0c62d9,dfa35e14,d1eab9b3,48d09579,f4e82cb3,65dad65b,62ba53c5,2c4e704b,fc9a9b97,7d330d92,602c677a,4a06040,74517775,d441d0ce,6c5e5e2f) +,S(3bdc1eca,a939c8b8,c164e5f3,1a02a6dc,9d2712a4,6c30f54f,e2159934,d492d1e5,e53acd26,28f6e646,edb5f53a,d9e1639e,43b4ee9d,b61a3545,a9874609,9b3c1e94) +,S(54a206cc,48c7d529,c8bd2ca3,91501ca2,1b58f5ed,921ba11a,95eadfab,3a720bf,83f4f820,b9a07ae2,8c5e137b,c9ec4f0c,31c875a4,b055b0bc,8de38f74,c54c06fd) +,S(2754b021,13885a9a,f44cacd5,2999a03b,d16c90e,4e3a7a67,cb3426df,f6abe546,f8969b1e,e955f8e2,dc0d3090,167c0116,66beaa68,35bbb1dd,e721c4cf,768ef566) +,S(ae438153,4cf07fc9,1dd14a40,68b3cfe3,aa6e608a,bf1d1c1e,13ac54ee,e0759165,e7807ae7,395fd072,6f77d7dc,956c58a0,69243b63,32bad336,72d2eebd,662fb99) +,S(cb9d28c5,357165dd,fe18010e,4263e626,65fd6315,60ec8126,c7b60603,6ec067a1,86879039,f3264d1e,511fa8e2,4298c9ed,6f1e7625,897666ad,4db9a43,3338f5c4) +,S(763534f5,52317771,551524ae,7ce33579,41da627f,db77d4e1,a9cf72a5,f182d276,9fd8ae13,b1706cce,ad190066,9b1d2f46,8c177970,b5173f76,55efee54,ec5cd8de) +,S(3990fb8b,39d529d0,b2d38432,3c60ffdd,3b32f7c,278aca88,f49f1523,fa16ded5,e43c977f,427570b5,b238edd0,77db9df8,b1b82e20,b73b8d56,84a2ee37,886edb83) +,S(6b76502a,22280e31,d0b6375d,6dffef0a,94dad7bf,e640a406,2ad696fc,2744cbf6,e667122c,b6861cfc,97fc4ed0,e6193883,c79a896c,79e31603,a67063d2,421845a) +,S(7ac03be7,2ff15233,5ec9c349,98e77ff7,79e5f348,a49fda4a,e52a69cc,6b02c02a,74a9e36f,af0ef72d,b493617e,9474b112,593de375,c845c8dc,c1028ee7,9fd17599) +,S(31a83e18,c03c570f,31c3ecbe,bb787aad,6492cdc2,3e07d3a4,43b56ca2,51c0888f,3cbddf10,9bf08e81,830dfa49,d4d3cf95,224b7a4e,fd6d9997,9dceb64a,a8d7e440) +,S(ec13f2e8,53935ae0,705c2644,d1512bfb,8ea4adaa,d45a454e,f761dc68,c7ace561,54139641,97e2f5c5,5b4b7f5c,5267ea7a,bf36b01d,cbd62765,ff56322,c107f321) +,S(ce8e23cc,aa38e603,70defdd9,37803f02,18ae79a7,3679c363,4dab15a,bd46004a,1ddcf92,92ea77c8,4a1346a,a5f79f13,26c9092f,14ce1992,dfc24bf1,a2da35d5) +,S(77d80689,f7cd8585,fc03cb20,14d02425,3b547962,a282beff,17aee956,88292ee2,466283f6,429248fe,301e18ef,61a89784,47142fd7,fcc5c496,36dca83e,ae8e9f03) +,S(6eed61a1,4e7e7ea5,54a4e43a,61fa7eb8,b8e7fd0d,52de9ad8,e4e9b130,78178a5f,2cb4d228,90af9cb,a3c050ab,12a3dd53,1f1c6d6a,e4393449,219d86e2,6465bbab) +,S(10cb3737,a7916d84,12c955d4,32d1ad46,d8c7a60a,e44936ba,f62b2a26,b698e4f9,35499a5d,11e356ad,fc5960d5,8d6842e8,ea0615f5,e8bf39c1,8c217cc6,7a1faa97) +,S(e866ac84,6040f92b,c52d298a,6ae110da,e16bc797,d6958858,1f63c00f,6cc68211,257803b9,ef7bb5ac,59c6b59d,32a49d53,64c6659a,cb0482e,a9d57530,4e244f90) +,S(5e75ce15,aeb91c2c,e4ce06a2,decf02a1,db85ef5a,a43c42b6,179d4a,2eb4e404,a08d537e,529a6654,a785969c,8d8b0b86,e3a76f91,d9b72d92,992f8215,1b61bd1f) +,S(fa80c52a,12afecf4,7a5b48fd,60fa35b5,ffd122d,8616ca07,1c1271a9,bfe2c104,74487acc,dbe2e60e,e054643c,37cd624b,3dbbc3d3,4aaa6009,9c97cfe4,b3d69e81) +,S(ddec1720,dca13ec0,2eee97cb,445044e8,d6b049f5,694ce5a,efa664d9,d89b6dc,122b68af,feed4f56,b72a4a7e,e20a7f8a,8daa9883,9a797857,8dac0851,1b843872) +,S(85116566,57b70a1a,96c5da0e,fa5d3025,49fcd00d,104a4989,442ff143,a08b5a59,2c96bdcc,430c6c28,9d54806c,9c17961a,8121b10c,5168cfed,a0dc8edc,9f4f551) +,S(7de80b36,89b9dfe9,de2f4fd3,4dbcedba,9ad39842,f105f580,d8d5f6f7,e1eb3e58,43d20653,db727ee6,155998cd,f7bb70b0,9be15c7c,a04593b1,398b4586,baa3c417) +,S(e66179d,366fa7af,a982c480,9578d469,91731ce8,c669d8e6,bdc399c2,a2484b1a,9371d856,28bfb10e,d07c3390,b9f08222,98793229,ca2cf2ee,75d53d2d,e8144441) +,S(1d435048,d7b8bfa9,6df91fa8,f8f6d1ce,913bce85,c2c7a1ad,cc199afa,5da012f1,4e389f26,4f36b2c9,296934ad,5f567eed,30f3179d,6538ef70,f4205219,2c3eac82) +,S(5866c91b,619f53ee,3256772f,56191a35,23696c7e,2b5140a2,89f36c11,c1cdfca7,67090999,33ade86e,3a5d384c,840fc584,2a85087,10085798,913c41b0,e2dc1737) +,S(1e06d768,20c95907,405fc2c6,bd75e1c2,fb9c4d0e,4cee156,94e1a4d7,65a77a01,4aea359f,bd26d7a6,1b1e9f75,5544363,27eea590,fd2d5eb8,87ece7c,41759674) +,S(ee415cb8,5e1ef106,28c149bb,2d2f9e1b,a8083367,60a7b56a,f122cf4c,9b59e5c9,f52aeac6,e2fb8a7e,ca5a629f,b431736a,eec16a06,c1a4b876,94ad8bed,bad88ae0) +,S(42da5368,b60f85c0,9f52c3c,9aa82e66,4868ee37,4b1851e,d37ba6a3,fb717e6d,71f65b16,a3937a5e,b535da,ec530798,d1c91c88,722fadb6,580510bc,5f27ed65) +,S(10bf9254,6300aa51,bb08f849,5acf4e53,b1eb4e57,1328fef8,304189e9,7acb81e5,9b519bf3,482c9516,132388c6,dabced4d,971d033c,52bb5607,6c788a37,a9eb49cb) +,S(2f6456be,5c2c184a,1dbdde7c,2dff16ac,8f504a9b,d86de1a7,d9d3c1b2,bb0688d8,6bcdc62d,4e6184ef,1fd39720,55da6e7d,45cca6d9,4d15c052,8ddfa715,4aa68336) +,S(e68e8fb9,beec6d15,207e7017,c3574e34,102fd7f6,5e5f18f1,e533487e,5bb2fae5,13624e45,da0b6edb,df4ae938,82148590,63094aac,1b25d534,f80ca56c,814a944c) +,S(7d314f19,4b776d00,b946825d,f634f763,e0b5aba9,b1fb0424,833301bc,ab1e94ab,80d402d6,a8dca19e,709b9e23,4dfda4f3,9f9f758c,928c1b9d,842b2d5d,aea3fa54) +,S(fd78e68e,5b5b9522,14b35d5f,a0951f4c,4d5df056,28c5bafb,9c6144e5,c2c33a49,49c62b9,aa91e5f4,be13a209,7f941c9d,cefbb300,eeed9fc4,a12c1e45,37f4535b) +,S(e751f61a,11e0b68b,205fd306,9f4abab0,b2576131,3ac3ffc4,eb4c525b,f2b28f6d,aafd8f6,2fe20722,b180ba67,f9c3b6e8,8ab2b96,956d603c,868a8867,c09ddba5) +,S(6db64d2e,281e6734,a8908de8,554dfa93,d7811f01,2852a306,9e6ed59e,c09a4823,1c1276a9,1de36164,309d83a2,d9fdd003,d889612c,6026817a,cda97f8b,d2cec77a) +,S(4de91b17,fc227eca,652f8d15,8cf0c696,c6902df2,b44a02ea,d05dfd68,e408a17e,130fd485,d59456b1,48458cba,922e9ce7,79968340,d7e5267,b2f288d9,6df924ae) +,S(356ceb61,8c57db92,931a305,4537ddbf,8bad8cb0,c13f447c,1c3fa485,5c0ba01b,6f52d242,ec189e41,d8ca010,cdd645a0,8889206a,4df81651,1e820e0a,74bbaa7) +,S(595d8d68,1ccf61b0,456ec03c,53cc5a93,85e553b5,36033f8,ec56c575,db49cce3,773b50cf,f0718e6a,6a269cd9,65b5001d,f5613238,3e279bc8,fb937580,a76ad035) +,S(b076afb7,234e8fd4,4107caee,8d31338a,5122d785,4707605c,2e5dae93,2e6c935b,a18e661,1921080a,84a74df6,15006847,981b552a,4c3021fc,93967c64,b19d629f) +,S(834a4467,bada612e,2705b0ae,19fc9f1c,b80e6e9f,7c4c01e,5899fba0,1f60cfe9,9215b4e5,f8194645,813f00a8,58f77324,e28522de,16e93e80,93197310,38ed9af8) +,S(d00093b1,ba6eea04,c08df30c,90b2f7de,6e13b42,c645b01b,127003b,5642aae0,87739294,746ec547,4497a951,c26ca6e9,12ae4638,1d0e2804,5363fe26,de088434) +,S(66a33bcc,71bb2f0b,ea36e5d0,f1446ce5,f3d44a9c,b715e6ba,ed00cf70,4c4ce1d1,27d0f5b1,a40fb2f1,e1f9440b,c1c15731,50efa23d,b8997928,cbdc0e03,2824a6bf) +,S(ac65226c,dc40fb92,a9632724,20983b87,9e1a7615,fcbde26,ac9754ab,408211f0,ae633790,687f1c02,52115aff,3a7d5c92,9064bbff,616b5eb0,87d5c1ee,57cf8d3f) +,S(a4b98213,78cb0e23,d46b1359,43b354da,3825e27a,76f33334,147a3ee7,52a81913,2786a9fc,3701a6e7,caf07030,3bb382b2,ce6d7c52,42496130,13382f59,92fec4e5) +,S(6f58e6ad,e4af1dcf,633d3f35,8ac86836,cf0968a,49c2e85f,2434ffb4,2475a34f,70e30dbc,dd567c8d,a6aa970d,3131009a,f5297a36,f80750be,6462f1e8,336db9ee) +,S(9bc7ace7,d55fcd7e,e67a0484,7d0d6902,f053288,ef17b3c2,64072dc0,ae0e94d9,7f57fd70,93f3d09e,53a82818,e5ca4cc1,6b46f73d,2c00e50c,698d5963,8a8f3f7) +,S(248195de,ab1ad52d,fe739d17,a03ab762,927e058b,ae666f2a,4f7e220,3173bb3d,1b1914d,3dc9f584,51ac3346,d05f033a,b793277b,dd80262e,d2ffc219,6965b96) +,S(f6008de0,21c5cd46,d9d811d4,4070a7d6,46105a55,2a68c389,a11161ce,9baaae2d,962cd254,e5b0d724,5ddf7114,32ab2800,16f5583a,b8fa02a8,61b7c3db,eed77d91) +,S(f6dce5a3,a919eab8,c1d850b,4643dd3b,96e5c7e2,a1923b58,202543e5,4ece5b40,c1b88f2a,b3d516e4,7d289ecb,b16b9bb7,4082a6c0,8ccafee1,21abf691,73734c08) +,S(23fd6281,b4958fb3,b94ac9cf,851561ca,415cc979,7ed619bd,15192ca7,7ad39a71,fac12f70,ee38f19,b2dbbd5c,3cfe02e1,b69bbde8,7a45f8d0,bdfc909b,640622b0) +,S(da3a5c2d,7cdeffda,1ff2085f,fcda0ded,eb40bd40,3591395,e4b20b0a,25a1aa8e,e0d90d58,a6cf6038,10bf2891,d51da508,77d3aaad,5ccc971d,944ea960,c943e3be) +,S(22113f6b,8015b2f5,bbff28c2,cd5dc253,c495cc62,88361c27,3e788aa3,58a94554,7b6f7bac,2db4f198,20ca6e90,bab75cd0,983536bb,80051e6b,7da589ee,dd2ae962) +,S(3b59d8f,d59a2e6,89c9d1c8,a4e2515e,73317cf7,41e38108,eaad880a,e3417c72,bb96d412,50614b50,8903c28e,b5d39ed5,b4e735f2,ea10bfa,1265aba7,f21ded5) +,S(3407e5a2,4831b572,abc0eeaf,c587b20e,9339dd05,ebf395d5,378cb151,e0dfe661,49214182,78e4d0be,31cd4e1b,9b0458b7,7e028840,4a0745f0,40960dff,b9022926) +,S(9540e180,47717f7e,f6ce71a8,31368919,e4acbfb6,18c1582d,cb4093f7,caad2601,6fe0f64c,3f0aec37,5b36758a,7f65c7b8,e9329f62,3309900,efdd58f0,7bcf244) +,S(bd02f758,513ef045,af72344,f5d790cc,1c549a23,147a2743,b8c0cb30,891af3a1,3c605d60,13a560d0,d792c5a7,6ae2f739,7631ea13,7347864,4c6bbae6,dde96079) +,S(43b10d72,cf1ba39b,17abb149,884fd00e,56525f61,594f9654,48683c16,88f3e69a,cbce7dc6,1bf71def,95bbf6f2,fb03751b,8a0c6350,9eb9ead3,713366d,8cb71407) +,S(32900344,9ad58567,6ba2607d,c873a8f0,80d9c0eb,2f7314cd,9746008f,3c569642,8c6560c6,9a037d5a,3b2e740c,270ff543,54abb60e,b32ce5cb,4d18ecf8,1ab7ef60) +,S(a1495bc1,91188644,4991e097,5334c9eb,cc277640,f568a7b3,1350e4b7,222b885a,c5a1c341,67cbed14,7f28f794,d9d2867a,9019948e,56f986a0,e69a0d6d,6ae7dd1d) +,S(4640f683,f180cf5a,4929c2ab,5169de2,85861055,67c7c2a3,3db2d01b,c3c8d726,7d6ced33,7e752ab5,c87fb211,903c3a91,e5b0ee78,361a43,b716754f,d0daad8) +,S(91b3f9d2,7e989062,ced571ec,f373ff66,f8775213,95e625db,7d1b5168,e895473a,d7efd35f,56ffd001,bcf0191e,2692e832,99d0715a,edc1a19,2b74d8f3,c0b23b80) +,S(437cb866,aedcc0d5,8d89a41f,95cf5dd0,b355f244,7885843f,c163d54,a3839db3,9d644bce,31992f2f,302c5daf,67e42b78,74bf3f9a,a944e936,aef17203,5ac2bddf) +,S(be8cd347,572e0e46,5c745c83,26799611,a5ebb1ad,3ae74bf,474a6386,6f4a3705,6d39457f,c1010837,eac6bd41,bd4a245e,10bb39f1,77c5633b,92bda8a2,c50a3dd0) +,S(f40a76f2,130d31a8,c560795b,54fa119b,153a9a75,bfe7dd28,cc00ca35,2d258331,f92558a4,69f1055e,251c8814,7a94dd08,44bb2048,31f2d33f,d95858bf,dffd695) +,S(17e01809,b94d294f,c4438a92,6f90a295,5a9ed96f,a201df62,b96b19d1,7e837876,c9506f35,8efcf330,35603c30,880d5625,db15175c,486f3c5,841a14e8,8e5f4e72) +,S(7dbc457d,7ad4752f,8d57a09e,d4e8cf02,6c8b009c,bc29afe5,ce2ee745,61630da9,fea9908b,ca852ed8,3c1b44da,207e8bc9,221b8dbc,7e8b61ba,ab8d29b4,14eb29de) +,S(89fe19a7,6fe2208b,ee4de72,249a503b,88c63e22,71794bcb,9484fd11,1df7902d,8a4853de,c3cd9e1a,713e46eb,e771ee97,b88defe4,7e1106d,88ccd713,4e3a6779) +,S(3753a13f,531da9e3,5569ba37,7db76dcf,b43b5483,1e65fd50,a6ea560e,e70f3eb2,ace8aec3,867312f4,f095b4e0,d08ad314,2005cae8,b1369223,d1301e29,8e51d4c8) +,S(30d76056,384beb45,4c54b4bc,fcdcfe0b,1c1ad5b0,5e693384,8794846e,c93a144f,f79b9c96,8eee678d,b899f349,412bf193,5da9cd,c0ccdec8,2e45ac5e,58f3d3f) +,S(d9864700,7c74872b,40ec273c,59aa149f,8059a1fa,95e5b47e,378ec515,841eb2fe,782a39eb,ea47da96,9361a337,c5e2cc0e,49d43dc,6c6f9da6,6952f347,ca51845d) +,S(40d665ec,53720f95,42ffaf3c,30e8602b,53c52123,e9dd3b91,6a2e9099,8d534fb2,cc420012,490afedb,d840a466,bc27f66d,526a965a,ee653886,8cee46a0,6a58ee30) +,S(f31507a5,516719bb,f07438a8,7b6d6d93,d02a88ca,c18fcec3,9190f358,bab3647c,dbec3898,f884cb2,aedfcdff,402ca4ec,8c8f8727,485060c6,8da0d2e4,edb46eec) +,S(62573f5f,75db743e,7939137b,6b5e1d0d,41468ed6,28d2b76f,ca26ed2d,22532c03,9a4da6c0,d7966d8b,138497df,af25b0cf,2d14215f,ff039065,d42897f0,df33be40) +,S(d0887924,f15c5069,1d7ace01,7eeda410,e8d0a10e,f6091a4a,7b5f368a,42c54416,b2fdc385,527d34f7,a434c1a4,1f9fddc5,add3b1e6,82b63838,da0ecd91,16571c4) +,S(f7585b4b,5f3318b2,2307f34d,3e4bcedb,d4b91eb,180be664,4d031bbe,9b5e3d90,b6fd16dd,49993bd6,4d05398b,9ba7714e,798d3ffe,95393231,395c03da,b3ccc819) +,S(c9cdc99c,198ca8e4,458e5473,3e5cc0c8,100fb0b2,2dc6f07e,b1e99d2f,6a4cdc42,c4c21204,67198733,a845efda,33a5c1b7,67cd8ad3,47a16b6d,4a6f5ac,995dd680) +,S(1a054d1,5c4fcf45,384ead78,e1260eda,dee9e907,84021c99,179a9fc1,c7a3ac49,50ac5d54,d4fad7d1,5fbff150,d70a3ce2,9825e79e,206f4279,f1030d29,2de89a07) +,S(b0796a05,52245e66,56b3ce51,99864d40,aed71b62,3b9d55b0,d99163de,7a8e3455,a061fa65,63a84b15,1ef666d,9f99abcb,f1611e3f,6e26dae2,6be7ac56,c0f2768d) +,S(66fcf877,6ea02717,aca92a3b,5c19387e,72658125,f6e20da0,7595e376,804c3738,9fc66cf2,3195dcdd,7a72225d,96a8c5fd,1c84287d,2189e414,d0deb6b6,76e67518) +,S(3c7caf6e,d3da8c0a,effd832c,f5356114,55646982,3a62dabf,2ccb3de3,452ac96c,e44ca4ee,bb290527,4cf8f554,40c92ad9,6055fe3e,1bb344ab,ace5c4f,80e3b984) +,S(edf616b1,1e7fd6c5,96df3fa,77bfbde,f3f82e7f,93e5addc,53c83933,844e4b73,879982bb,b89ac019,e83f5c,dac1fcf4,fb918e2f,53a5ec35,45be03e1,89bfe152) +,S(7e9af2ac,b3044985,181de5aa,9908259e,77207ab,933c7915,9dcd7aaa,90527eec,e4cc83d9,d29778a5,eb83936d,97bad637,370e74a4,3254eca7,65d0a449,106ee3a5) +,S(32dad830,3bfb015b,6aa6759b,c2e8d4bc,2a9e356d,92d97286,c92dbcf4,53591aaa,ee27e7fa,b36a2450,f04962f2,ee60f9bb,68a1147c,9ecabaf7,e0981564,c1164fd7) +,S(d20720f5,73f1db82,c1a2dc61,d3684d7b,a3943186,cd513a5a,9eecd59a,c9225a82,3b29448e,cac88f13,7dcddeb9,36f02724,6819c6c3,3f03a2f8,cc40a6e6,f8704570) +,S(3a732b5f,5dd6dc77,1d215321,f8cd223d,22f2195,9d45c708,5b000129,94d5f03b,3fc75d80,ea7a0663,c90cc7e8,8a6096f1,b3a8c9c6,9849ea50,f1fd5c94,7928cfc7) +,S(201961f5,412beebb,7e190d75,70977b50,230810bc,b3b69e3a,dfb5e259,d811333c,eaa3f681,3816ca15,dfb9aebc,8888b578,e592825,82dd1b47,ea50cad4,f59b0101) +,S(cb184267,70cd3b68,151f7d82,cf7a12c,dae332,868663ab,4546c119,fe26f4ad,6c395538,eb09c00a,3e973def,8272eed4,27a3ca9b,a77d1a0e,c4e206f8,74591a40) +,S(2c13d3ca,9ddbe3b4,2920f0ed,28622260,2cbc0493,e5156655,30b53da4,7ae3ba59,f7d9f8f0,c58510b2,db28e723,6d9af034,658599dc,fae14274,efbff408,dfd18613) +,S(3ae7b7a3,86ae6c41,90b3a0e1,e5f1a7ce,4fffc405,84f05043,93e716a4,3ec83d41,643043a8,55603964,c46e3ba0,999c73e6,ab34703d,9dcdf9de,1743db7,71591bd9) +,S(b5eea0d4,ac4d0a9d,e37fb1d9,6825233d,a00f26be,86c0b640,f0fb34c3,465bc441,9cb5b93a,56d35b2f,2d921c4f,15b4ce0f,fbb9240d,30754ace,f16b3019,54732e1c) +,S(dc049453,9b8d5200,d513eeed,edc2afdf,e76146db,358a86b4,12ae9e28,e8501e3,6f6f2d25,b331a4b3,686adc14,c26814,96004900,34524b53,8418fe5b,9776a3bd) +,S(821e937d,a6fae1b8,3b6aeb4c,f5315bcf,77b2fb07,d0081889,80478765,cea7f398,41405d00,33224982,2acfc2e7,87be9658,7baca419,14b70315,c1a57843,3f85aa21) +,S(818bdf95,f55a8e51,c0d08d83,29574c28,1ae3397c,f6ac5224,4d82ea53,8f465c60,bfd41438,46dbbf6e,3fc442c9,7a66e8b5,32445d39,fae8c473,51e0ee9,9a9a53f2) +,S(e3bb3262,36533fd7,84fc6d9,84cc5590,2b03a19b,6c956665,322c0bb6,264b6d72,bbe4844e,2be51197,d8d84c75,ab83cee7,c9ed7dff,51eac125,1161e09c,c1078aae) +,S(36e3355b,5f946199,b33dad7f,b42d1245,4cf8126c,568c4be2,cb2abe4a,b83decd2,fbd5d87a,8c012064,3ed3441e,ec686237,1759ccdb,4a7f564e,c2ff9584,ab824833) +,S(bd7fc193,1b06bd7b,c6c274ea,73d33e71,1e1e57f1,e6bf7a8b,6452d979,777aaccc,95b84e3,d8c41224,c74451c5,ec8a23ca,35436798,c2f34ad1,b1cd095,2f0170ce) +,S(b82cb5d5,2e026caf,bc075968,6e1c6c18,206231e4,f25c956c,b3a05690,8c72034a,6417cb0e,f1a18ad5,e1a2a5c6,945f3b38,b0522ac8,70188640,80a0f33e,2796b042) +,S(47d70d51,e97fad87,fa0b1c10,43246c0b,32108c36,734c90ec,9de5a2cb,c6227682,6d5a2cdf,e916fe8e,8b45d5fe,14ce650b,79a3cc9c,e4f99aae,2e9c449a,a79a4a08) +,S(13fa7ee2,5ea49c25,200b40e6,b9232eca,16dc6840,4f76b43f,510c8a12,d520dead,2722287e,35c9f98c,6041cb15,845d515c,870f5943,74a1ebd7,36f973e7,5e6dc30d) +,S(c1350b7b,2a4e73bb,90d36674,771d5537,1fa647ff,c490726a,3748e7d2,e72fa7a,2370f4c9,403ba7,8e950274,bc1f87a7,bc80c1fe,7618169d,5c9bc5c4,81e1badf) +,S(dfe512c6,f884588c,80c1ea7e,1da4b3db,ab8d4beb,60749f40,9402d583,ac793e05,b52da5f0,333b904f,678dcd37,a890b79,e985dbfa,b501e61c,89930678,5a0bdf09) +,S(88da191,2face14,e6f5ded2,30d303fc,867f9b26,d85c2299,bfac1a23,9757b34f,4236025e,f82eab9a,f1fd3c12,42a73cb7,fa305e5c,ef6ad5ab,ea62cb8a,4d74bbc8) +,S(b7a82133,7cad0eb6,c1de7b3c,8aff8798,8ee936c,921a7dee,1434156c,c6505abe,d03b693b,4fbce189,a552a66c,3ef4586,35454006,308c40ed,c7dbbc29,75361b7f) +,S(44971116,c14d80b2,f0f88829,fa1fac44,ac44124,11ac6e92,fb898e72,a0aa7ed3,9171395b,3cac83ba,18e9a0a0,34fec786,986534d,667b0521,801638ec,e19343f9) +,S(95f0aa61,8bd8573c,81b2dc3c,aa16b577,6ee636a5,a8f9c963,b8a45370,7f35a618,7f2300b3,90006ec7,37365423,2b488d72,edf5192a,a1d5afc9,4bc95a18,edf5532f) +,S(e1bd29e8,778a30e7,d9d91da2,3db2da23,bc2e8d08,d5cd170e,8e753e3e,917b728b,592894f2,114c11d5,f04dd5fa,6b341cb8,29c58e1d,a7adb51a,19d881be,39f87eee) +,S(f6110619,208f64ea,8f0e8164,1ffe9f32,8e706427,87dcf8c9,28ca8629,adb99e7e,cff63452,a596744a,75c5e8a6,badc4937,e6f2c860,39196251,30784499,733651a4) +,S(4a3f7c9f,1ba0f01f,d6d42aa4,284e4481,ed1433c9,3248da63,76f25b62,d2d2348b,dcd4c18b,2ee4e447,3515c727,1467e6b3,86b6e640,834598e1,4ce3f679,47f5c2b3) +,S(50fc4d78,3964a68,b26689df,34d996cb,6f229f2a,ed017a98,4e027407,5fd730a,7ccd6964,c6c5ab52,5d31db1b,ccefc3e2,7a0882b5,8586a955,b76c754,9698a7c6) +,S(1bdc6b52,e92022,229cb15a,6436d601,26c640da,bd9697d8,bd0c49bf,606ce554,1ddb0cbd,e7b0816e,b65d7ea3,98da0744,b3ff390b,d2e13cbb,f8fe85eb,8f3d2059) +,S(62dac912,48f29712,c3126524,90db807a,af92d3fb,36117f6a,f5c7f5f,de317000,b3bc4dd8,97a2fcf7,483c0015,f793810,29bf6f01,7be37530,18b55e35,4250ee0d) +,S(ea552caf,1d0810ff,24eb5089,31b57573,d8eca976,2b314f9f,38301b04,ff5e2193,68181368,108c4fab,7c58bcdb,5bac3a3e,31eb1b3b,837c7ead,e691b56d,e24aa832) +,S(7d6132a0,9e2c0af4,9e3359de,a750551d,7addad6,8bdc602f,e65af48b,bc1127a9,5bf6234c,903e5f72,45b46187,9d780ffd,72aef438,c0b65c7c,d0b5fc2f,8ad29d16) +,S(916d0d6a,3d08a94c,604c34ae,8c930edb,5ad57532,4dd5fadf,7a4841b2,775c475d,e3cd9b7f,79572001,a1ad9c19,2921ede7,64b12210,4d4d8796,a435eb13,d883d391) +,S(804128a3,d982b50d,203135a9,c59449ec,c43ebb35,b2bf5266,6b710975,a3847524,bcebda70,4364414,dc269d2,6214968b,95ad5bce,239ca9be,f10fa1bc,d6f31757) +,S(850314b3,4898b572,5898dd9e,f39196f3,cabf4026,8248844b,1c3d2f55,a3346f2a,eb8d17e0,3c9f7fde,29276d95,c20b657f,af2173e3,7c620a0f,d2ea7ab5,f4706b33) +,S(fd879539,8c0ee90b,89aa731,a4ab60b7,be0375fb,59932879,7bd73390,58d7aa8,3fd62aa8,35d10f6f,8bf3338b,b48bbc33,8f235cb0,6bcccbe7,56716129,abe8159e) +,S(51536953,12e7c4db,bb18ecbc,26c51224,8f841792,e557e879,8eda9db2,c9840357,175d3e7f,92ddce9e,5595fc26,725f2c09,fc322b2a,251fc323,ad3c6f08,44badaca) +,S(8783f2c5,f7325f73,e5941ec3,5f91449d,558e31f,28af335b,2fde477,86aa2808,dc602736,ccef3e41,60b100a5,ef99c6e5,c59734c3,42b545e6,21d9b03,daf0030c) +,S(c871ab31,4afd8d5a,a58a0cc1,a5eb49aa,f25b4b3b,6e0ffcf5,38851576,27c0726c,d06b7e2b,f44d36aa,fcf653df,a675bbe1,36a18938,60864df1,fbc9e604,5a3707fc) +,S(40efd5c2,1a9807bc,b34a44,71066619,a2bba48f,c306293a,ab59d9c4,b30e9b23,85cf348,4df34dad,2f7aaee7,b8a6f585,4de1314c,215f6f0f,e5a38e61,f3decad1) +,S(7feb5d9,844798a0,2413cae7,cd791e6f,54250fb8,12f998ed,e0ea6eb1,435986e,d90ca7e,8e800e6f,fd0ea027,b8a379b3,9030a03c,7b111d68,465d2a05,99dd358d) +,S(1b2da7e6,f9fa412c,ec873512,7328f1e9,ea77501,5741a284,12018290,76a79b2d,9fe58682,ba3f6ee0,c7b73933,d14ce656,e3fe49dc,ec7a5643,efa07a3f,1a4f26dc) +,S(d7fc1f3f,7a6bcaed,1a84e8e5,7127a6f6,37d935a4,35500e21,47e8fe03,d3b06066,29938603,d89fb118,14d33850,451f5c1e,bc5a5943,70c2d8f0,1d9bed34,f0b2e940) +,S(45352264,1cd962bf,35d8ab65,3d8d6c97,75782706,1454a2ba,3d957152,e177ee5f,de5005a4,3989b6c0,cee0a71,b534137f,b946b262,bfe353c9,6a217c06,c23826b9) +,S(91733546,dedbbc4,c7c32af7,760e0a4b,c2bdf82a,73e2a91c,2d70afb1,100b84ab,e60a6ca6,f2a5b12a,307cab41,8793b7c8,b7ecbaf5,18166c61,acee16ea,83071a3e) +,S(26bcacdb,bd4cabe3,e7adc5b9,27465ac9,616725b7,dce240e6,37117a5d,80a9ffb,172208e7,6603837e,4a9cfeea,22bc6002,a5cb8f1,36d73dd7,ce30d010,acc05db5) +,S(18b520f3,e997b5d5,46a1d81,ad95c52e,7841f14e,11e9d677,de918fae,7bd408d6,51b0cc1d,4c6ec5ba,e6c587d0,d6489663,dcf74bbc,d93c4839,6e4203a9,caae57e8) +,S(e25c2492,b7b25c37,cb88da91,cd76021f,de8511cd,27188b0f,d4bb4fe3,dd845e8a,244facfc,a7dfe65d,6e1d1d84,9bec4e4d,17af0d6d,2611333d,b8b7498f,96c88bd6) +,S(97e572bd,300d9649,b9de3c8a,b02d4ce3,bfbe4ba2,68844329,85971951,5c34a535,324a34a9,39004c24,b2e55e66,83577259,6c9cb2f,84378bd7,e77806eb,75e77070) +,S(4d31f4b9,42526f1e,769bcf70,85f39523,60475a0c,3f8d0a4b,c1fd6a07,a4765fda,27815d6f,3b083965,8fcbb540,925986d2,bc6d1fed,d1c254e2,9580f413,99afa899) +,S(7344c521,23968b7f,7ee12500,e9efa4c3,859a72fb,cb1cc9d7,af91e6b3,b5bbe152,4794848b,1541a965,b7527533,a6d43398,d619df34,2608021,a26bf9a8,76e0e4f7) +,S(1d099181,8da474dc,38e08fc6,d97ac823,be34f4a9,81adee58,806f68cc,ffe1ce9,f5449d7,c69816bb,6f04b32e,69e46771,c7910f3d,77cee6e2,af75c293,119f729d) +,S(84607e2f,ab205637,4b708486,51e84966,9c386eb7,c6855a1a,837c8fb8,5da8e7c3,975b5227,26e4625d,cc5c55ee,22dc667f,1fff7c4e,417cb4b1,45bcb3a4,53180ac3) +,S(3d2ad8dc,11a9103b,2f03b3b6,24d93114,83f4faee,c4b9bc22,f4f8f559,16bae70c,b4f79cd7,27d433f3,72735afd,64ef4da7,de9ac35f,98b3b6fe,5de956a5,ba93f9c0) +,S(2ad5f6ad,c7fe8540,8b9bf547,a564727f,374e9194,460f6037,ee299f83,e842c883,f613f0b0,8e306fa9,fbf39919,e3040d16,ede4dc6f,9d45ce42,e63f4b02,70832f9) +,S(ca92aa9b,e8893819,e49fc29c,dc98a42f,e23084d1,fcc37d19,3e9c638c,db0f2f93,462a5ee3,2bcdca5e,c6bf6819,32ded511,12ca847f,7e110405,a893b011,874a66a2) +,S(4e435dd7,ce2783f1,5bbded75,e832665,e4b4cb00,b50e2a69,d986d2b6,d3d893af,cddec0e7,1615f7f5,769cf2d,ee649723,1218fd34,91a07fa1,fe619f2,26673042) +,S(b1d936c3,fa1fea01,e3e28332,51f3790e,1e0f0038,58656e8,af53a72,118cbd6b,183b67ca,8039f372,d04b685e,c515466e,8ca1fdc3,7b2ae8c1,ebc5fb02,9c0ced9a) +,S(77282290,d994b6db,10b06247,1b86caab,e4524850,22a1e63a,682f92a1,ae65019c,feff37f,1fee0cb5,569db439,a7697327,1a2e4254,a9125ce6,cd94fbae,110f6363) +,S(acd0184f,18bb7c72,f7b6ac5a,7ba3f617,c40e159b,a3dea242,ed8e6c23,ad89dc82,3ab71793,fdf23305,aaebfb52,982a2603,e56d7b3a,5430585b,557d3406,42fddfba) +,S(933e3401,91e41c37,69b60410,fc0ac56a,e5bb44a2,413921b3,d25a52a7,14015cf4,ad3aa53c,76c106db,6187f4ab,755d077d,c6d878c7,64181565,77bd5d3b,affad12d) +,S(6e02abec,969eb027,bcea0303,6648fe60,da6a7c67,d1e4df3f,a34c1225,36de6fa1,c0283bd0,9fb2bc2b,19bf5086,f1eb5c6a,a7dfa258,64c73647,8a6cf0cf,c5ed5c14) +,S(2b86559e,82e5ea58,423163f4,448327f4,2429f1e3,14097621,667cf1d4,f0af1ab3,35bcfa55,9e2a71aa,4ea25edf,f9e1c59e,2274ade5,9354e22a,9cff37e9,31258107) +,S(1c02f45e,5787587b,9d68df04,66df67c9,552301d1,3b32f50b,8c9a2d5b,c826606,5f5de968,b39e9263,c1624aa8,811a4391,35150e,f8167698,c381388b,18a232f7) +,S(d0a65374,7fdd0c5a,68c55060,dd4ed734,34956730,1997d07e,d333b5a8,79894eed,272fe0be,bb192ec8,9f2f64fb,43f3a3,cceff7d2,cf92cbf4,4ddd8fd7,b104b85f) +,S(bb48b81e,e0dffe05,b6b8d05,5e1d2e5,37481eb8,2ce2bb81,cfdfbcef,bca5c6de,717b99e9,63d59e1d,66c0737b,9843231c,9c5e1bfb,26820215,78e8e01f,9e5a3fa8) +,S(23901c4c,625d77bb,1d390891,6befda04,522c698d,3c4e82c5,227c3975,3d7bc3fc,2434bb8d,98ebf9bc,42459328,464c4a7b,b26f258,2d454209,af66edb7,e84effbf) +,S(2a150d7a,961b5c28,434cf4de,ab9bdd3c,d019f667,67437158,c0f3fc38,54de70ab,e0d4756,9cec0eff,b155d7e7,37ee49d9,863374b2,4c6f4ac,876a80f3,7fdf7461) +,S(d42bd53b,1de9e41d,6e5ada81,3b86370f,ec1cfe1e,cc8ace39,edeccdf4,e16e7111,e3d4de0e,e5cb0d3,e3dcfed5,a09dcc,28c9f1ec,969d70cc,ffbd34fd,d0ceca5c) +,S(2a865f60,413764f0,d50adde6,4825eed1,134c6875,d1712396,938cd8ff,784b743d,4b628cf4,8e2a56b0,2142bf67,8829a388,929a0c0,5784426c,ed114f21,ca1dfade) +,S(2189b2e2,e88054d9,c71c2321,8cd229f8,a0165a15,650d1557,3eccc450,671817fe,6b9e0fbc,f9b9c354,644dd8df,3ec14217,66fb6783,5c698a1f,d598d074,aae79d19) +,S(e619a8d8,d63ce9ec,7f11cde4,1cfd33e9,62884fd7,471a4e67,9b9fd1c6,8537fefd,d819f364,5438c886,915f46b,40fb5c6d,6932077d,6f9726d8,86b9ddc4,d5a552a0) +,S(80c0df21,91bd2fa,2fa21bc7,ea86e54b,ee25d9ad,43893869,1cee20a9,b5792763,b27d7eed,198a695b,405cc3a,9204242e,45833ab,3b9feaea,f81db33f,938dde53) +,S(cb3926e1,eaee7f44,6f2eb390,64d4ced3,cf8bfda7,9c54a25f,6894be15,61c2d02e,35d9e098,6612e1c6,fbc2dcf3,54022f34,5b2220de,139d1ca7,5dbaabe,46c69160) +,S(82e82221,5dae0056,917680ba,a3233d29,23a2a0d0,68939d9d,2e2fe013,9aa2a8b8,f28975c9,b27352f3,f6a2972e,ef33eaf8,5d0d0a4c,673e3495,afb71869,e768bcfe) +,S(6b48f2d2,d756c7f1,77d5d33,cf62e419,b32fe0e7,352e84d4,d3056571,fd837e52,d4741717,3212dad1,b476b8fb,7ace774d,fdd545fd,6f99ba1e,b701018d,f762ad14) +,S(6cc8e1cf,ca1a026d,c1db0d97,46029b6e,b9895d7,61f66549,4f29cafc,1243b56,429b0dfb,ca05d077,d4d87022,d5ab333f,d9068170,5e246fbb,6861bd07,7e85b500) +,S(fe3de551,3fc157b6,e5bfbe45,d88f9339,71ff5ad3,c436ca5f,21794899,33f01e9,a50a9cfd,8aee1546,c422c5e1,494dd42a,db36bf43,89bac501,38211c21,803be0db) +,S(25140d46,a9453d6c,9370c901,6cb163a5,a5faf371,50152526,b01c7454,56b995de,6e00dcdd,82ee197a,3d5ca028,86fd7fee,56319f7a,925a39b3,becba6b4,c806cc11) +,S(4b9c4d2f,bbd879a7,de69e578,a2ffc7c8,8a0c700,f27f2e7d,cb8e0c2,ba3654f2,4c876a6d,7778cd81,bb02c450,5867d448,c78e9884,c72af037,55a66d7b,848e248e) +,S(2c11d305,3eb4b59d,8e8319bc,2b62624d,b97244a4,47326f24,6b83e959,5797c2f8,41e096b6,a1d2082b,c852782c,74a02cea,55dc09c,64b9d19,1265c1ed,9c306340) +,S(9a515c26,394d56b8,77c2b70e,ba1745df,9322810e,63c379ac,1c2320bc,48baa2f7,5ccafbd5,d1dc3d86,4a7ac805,adab05bb,5eb27f8f,dfabfb1f,708b2e8d,42e097e6) +,S(791a6bbc,91321ca3,6e017798,1a611cc0,db9d2600,34d2c26f,5f6fa5c2,ef7a5fcb,4cc5b203,db4459a1,f396cb31,acbaf9ca,18446f1c,cfded245,a3b32100,38417ba4) +,S(ad40b691,d3eb6ee0,e22e6d7e,1e0eafff,7afffe6f,2e0e3b75,103001f2,3a9653ec,ff7b436,47c2e09e,84f90910,2b2abe7c,2d38dc2b,151abd2,4f92d214,5607cdb0) +,S(52eeb361,405a56a1,331e3fa4,b854156e,7c403961,240f6003,135df1fa,8f3e475d,128e88f9,1f089e60,61d3df85,fcb2c50a,b0e67ec3,a7e5b3c7,ef1f53a4,5d5336c3) +,S(fe1a5ff5,162731b9,7b4423d,ad1b5169,5401920a,6b1a07c3,6ae9a25,ec3fbd18,22076aaf,ee720a1d,96e0987a,c7bb8756,b04a6b25,ddf5823e,e2f93ac9,e54c85f9) +,S(4c64f48c,fa628f72,b2897c28,4411684f,c0795753,60b8633a,188a89eb,e7fe1ea0,2eeabfd7,1b976ac2,acff49fb,bd029ef1,a42344c5,489334fd,393cc4a9,c305b4d2) +,S(44cbb9b1,7ec26b5e,3489c17d,1da0776d,539d2efe,d9317987,b86225e8,77b4eef4,f5c58a8,6ef02531,bcffcd80,ce788f5c,e43f5ad0,37e940bc,70d8411d,27c32673) +,S(2a5a456a,99eeea58,761c8802,7a86a310,63cdc681,b4ba0e2d,e5bce690,db8f3e84,7c3a47de,ce538330,49e998b3,4415c46a,2ac5c633,1a074e8a,8b4cdcc2,c6d1770e) +,S(566c0ddf,ebb82deb,bc867f76,e2fc5ce4,71249a9d,1b659237,2bfbf9ed,4eb6bf04,76989cd0,e0ffe1fb,a5992e71,50272abe,8a483f5c,6bff023f,3e5e1265,3598bc80) +,S(6fe42288,6d5d8232,4b229084,b1b2924c,b6c45080,3aa095ba,aeb2dd14,7b6def9f,b3b394b3,fc2682be,6e8c1e5a,ef2c87ce,eebe8d98,31aa60d9,ead74896,d7d9a38) +,S(35b45332,b65703f0,4feeaccc,39e04e1,72e58555,db94f04b,1899d835,9abf996b,6643809e,ae897680,5e37891d,3a241094,27ad6dc5,48429a07,64e2e12f,e89c2d29) +,S(17288055,5c0c5643,bd740b89,bbe47949,58ddb0e0,786cbc80,84d64ff7,838930da,f60cda88,7f85da2,3fa719f1,29aab43b,8b9a1578,53f91836,3fee5bd4,fcd16a2d) +,S(76eb57a6,c2d7bb45,d6faee14,4ba7c798,2d8ab2f0,5240862,aaf32c22,77dbc985,ef7cd7e4,d10ab9ce,4551c6ad,18a3ac6a,bc851768,18fe0805,f1c6107a,5c8c291e) +,S(1e5b38b5,81ad0859,454370f5,2f636726,5987e7b3,981af60f,a987c4c0,2440040b,d9817e99,89af200b,da690446,df5d8681,92808bee,91ba077b,400e8de2,712c2ade) +,S(ee17e98e,12a9efb7,c27aee78,15da31e2,af0d3294,40e7dbe1,9783caa0,2bef5709,a78346df,4d7dded6,9146931b,f1ce1b6f,1aae295,50a877ad,5f2dd0e6,adb43e42) +,S(bd574652,1eec6a76,7c2a14fb,15c85590,f7a19e12,342d09ec,67dd98e1,7739a81e,f26894f2,b8eca34,493bf871,dd6a133f,efbf1ab7,687a15fc,336d885c,6f5698a9) +,S(63852cb9,391a1ee0,23947718,b27c51a,8f9a5d0f,2f707f2,d0afd728,6596aaed,9d7c8c01,102abe28,43a7cff5,a1b15fa8,b56f50ed,1a034963,2e867007,e946d639) +,S(6c3fb2c2,d49c1c29,4eff674,158a3971,f65010ce,93f53614,ac9e0497,e31c296a,ffccd06b,98cb8021,589e833c,9c8b3b38,67850545,7e8dcf2e,775bbc71,47243707) +,S(3c29a60,103f7f0d,6f9a186e,48ac242e,46a525e2,380c4430,609f26d,6c3559bd,9381e8a8,7b4bdf9b,361acf28,cbe43e1f,a8fb073,ae2d1d09,6df7813f,bbdcfe22) +,S(bb76e94f,6f9ceffc,53ee4b3b,e27d99f2,d02eac69,8a4865f,9cb0293,a68c5eff,9ae48507,33f5984f,21726a37,c6ed7a79,e832af6,83afa20c,ee5d117f,63ab7472) +,S(422fcd5e,d2774d45,6d5f6312,c716582b,c142fcd1,342b71a3,d729643a,d022b492,b6d75412,aa9d6ff8,9be3a0b0,17384764,35ad4408,b544b53,acb5ba63,119b6bc1) +,S(328db4a7,9fff0037,c79aedeb,e8895e37,75b1e6b0,4d0a7a32,e2fcabe3,29c60dcb,40a2fab2,622ca3f6,39711923,812d8687,9d92b15e,ceaf5855,a970cf32,854b8970) +,S(4269bd58,abcd5e92,c62b0895,1c5ae948,efa1c96f,39ad3601,5e28d809,74da818f,1d1412ac,57ae762a,c3918ee5,33577c29,a8e63afd,c33b69d5,e6758416,6ff87b65) +,S(6c08ab40,97320e51,f3c571d,3beb7d7e,cfb690b7,af3d449b,50bfd276,290b8830,aba73078,edbed082,2164c850,5ca4bc58,6e53b174,83675f9a,26734cb0,747320b8) +,S(f4929f5d,99d0a5a7,3d20a223,c84261c4,6a085af9,fae2fa8c,4a025489,30174c22,afc89b10,7a38c32c,a24e947a,d8efd761,cad69f7f,ce0d595d,d4cfa849,201f6178) +,S(5cf5baf8,726c125b,e1499cb5,3f33bc0,37c983e3,b03f37af,6b48f3c6,29827611,17bd2e3c,d12adb0,5502a9a3,aa418cb8,c3809868,56d00c5f,319c34e,66074a65) +,S(c4639023,b41d90eb,2b275a2d,b7ab632a,592535ff,b439491c,f0e4e692,8188904f,738e1a93,5ace46a8,fb4f6ee0,b9026314,d8c243a,8fe08f37,b23b9c11,11763de2) +,S(a21b2fc0,2a60cae4,e694f206,1bd083be,5ed681e6,53af9271,a8ef9983,5807ce92,7f80d5e5,5a684392,939d6d1d,537919c4,99e799e3,4bdbb27c,b3d79587,f08d5194) +,S(7841ddd5,80f9f3a6,e702b0f9,3e1a4158,5e2c10c8,fcf98add,2a0f6286,c5d285b9,4dabb8e6,2aef6506,392b0fa9,4e2005a5,ad03c4fa,5fb6de65,2e89b31f,6e5ed166) +,S(5d5fccd1,378e4983,8d8b05d,41f89660,1b3a7c0,58df493e,2a74b55f,d8210356,a7e7b0ad,fba08a37,6fa3cbe2,75dcfbfa,bd0629ec,e8a5830d,d6993ec5,15ccf447) +,S(7fbd50a7,360c09ff,fe55369b,fbf6be2f,70cc5965,340e0489,77e01b68,2ab6c9ea,17ff93bf,4fc95325,26caac54,89e22f4b,265f63c2,cf46ff6e,a5b1d387,98a9b72) +,S(d6c8bc1a,479ea533,e99afda5,95365a32,cb1f3a26,72b4b960,2e039494,5b379061,cbfadb4,a6039cad,67ded1e8,8513dbf4,bb1dd3e3,437c989a,1df98b31,d234975f) +,S(5753de48,683d633c,11103cc5,b1bb04e1,5a935e99,297c73f2,fe851d91,5d5ea18a,10ef5d7e,ca1580b7,31ed4fc,3cd606b9,e6af8b1e,dea8bcc9,b91d522a,af361376) +,S(fc0d0265,b6cfdd0f,6b755a8a,c87f0ad5,b5a19894,5348c719,e9593566,91a638f,c5f31483,3c166c18,8c62415c,e58297fe,157fc6e4,b8e36b16,ce28cc75,df9017a6) +,S(61570f72,5b030b63,def84933,d0d25039,cabc8853,e5185302,d3f2d3ed,2611eea3,b3edb685,379c0068,9e9f522b,a5ad9163,9df723b6,b5c3eb96,3b05e5e0,a4b8fa15) +,S(5fa72a54,36b2b7eb,c15b34a,fefbb908,acbada63,23809159,66785d12,fbb3d6e1,1c027ed3,a34e892d,4b3d56fa,7a93ac18,663e475,a16a3d2,fac0ec90,be6d9ce6) +,S(5296b2b3,9f179516,d3cb85bd,5b86a9fb,274da608,be6e95b6,c44267af,187e2371,728aa26,e5869775,9c392558,34d00992,73eb6986,5db38b3e,df87f394,31c75dbb) +,S(b145c8b4,4c3f3c77,658899f0,a5b97c4b,dc2b195c,aa56b328,e0535217,88c80298,c73d96b6,47c2e764,e36caa26,8ebfe40e,c07b1e0,947e392f,be2a9095,7dba2595) +,S(bb585531,3cd05f8f,7fc96d8b,6e5194fd,2a70ff55,e7a7c067,cfbf54bd,129d87c1,31ed0367,8d24c231,8c4295a7,90d31094,e54ca68e,47b289c8,45b2f638,64812607) +,S(c6ebab34,ab48c0aa,aa5243f,c82a90e1,9a2012ad,74c925f2,e4e22f6b,13d6e5e,8107a95f,28e11f9b,bcef4b22,c4228c0,b530cdac,1c977640,53828b8a,15fc065) +,S(92e6ec9f,83dd27e6,3be3b0bc,8ebc521e,d84219bc,177f15cf,1bc840d5,be2b551b,931aabb1,5b3479bf,994f7eeb,34871b04,81efa404,c40e063e,59aabb77,2553ac79) +,S(280280ef,424f01ec,3fff321a,61dde1c3,4e674a56,7142c8e6,643ad1d7,e2dc4d51,84710eb4,5a88503f,b1078d06,26522501,fc165ebc,ce3b90a2,925ab1be,3c9ebfc4) +,S(6326eb72,abc4017e,c3f55af7,6a50a4a8,d0074ce1,2f5c9e08,146682ea,e406d047,53dcc346,7b61d08a,204a70b8,7658e4b3,c4016c8d,b5f03004,af6b545a,60223871) +,S(6e59dc29,408efda3,1bcd7b05,276b9f8e,bd9caffc,7f22c207,61f9fd0,a281ecb8,81c60999,45a6a834,8f2bc7e8,4ee002af,ec5729dc,aeed8187,87060c68,c2763887) +,S(100b0cdb,ed05ba0a,fcfbedde,94ecb25a,5cacfb8f,bbb80fed,1a9d87ab,72e4b5d6,1ac27087,8d6764fc,ce5f036e,ea50294,cf38c4c9,1ca9c3c2,87718505,491e11b5) +,S(95865771,e313a1f8,5629585,7ab9aafc,68a124b,6ae61f1a,a7b6e9f5,fb5de6b4,1c5195a4,338bfee5,9910935a,f5fa6091,7d06a2ff,3908fecb,b3fbe30,b0b52b41) +,S(6962774c,9035ce5e,fbb8e715,9d381004,a1828d67,38082e1f,45307ea2,d1d60eae,e9c36d21,6a2acbe5,5f9f9535,bea4b38e,7b75a149,3a281e4e,11b19064,e282c036) +,S(8e0fb8c0,d2d7977a,23f19efb,aec886a7,5170cd08,6a035386,ac784b15,9fec90eb,1218a3d7,6306cd4a,b3debd20,9bf9238d,ce00984f,47b5fafc,b715e2a,655ca9d9) +,S(6e9ea5e1,127c4c60,a01cd278,ac1dc091,e768acd,41566200,47aaa32a,e9cdf5e4,bfad3214,9a299887,c74bcb20,33e01704,ace7c646,eb00dc71,fd1e0461,af05a6eb) +,S(60fd55,9198e1ce,86c401a1,d31d04a8,fec7da21,4efd01d7,f2081027,1c49206,4f234575,cf4e6150,16ad551c,2f8e7635,3718b626,70ed30c4,a4c15e9a,488e0755) +,S(d413c7fd,2c2bd34e,2ab3e871,38495543,3b5ceb32,cba0e9e5,1e0ce198,cd5ea806,b585f836,7ef44ee1,8e32dd1d,95d6f8eb,555d8e53,451e5d8d,1cfca993,b23e344d) +,S(e26a95ac,c0855b56,b702cba4,abcf2004,c7343cf4,72056bb6,161ac077,bfecf98b,36a4834e,4532fa30,eb1caa21,c1572c46,efe4f7fa,e3c370b8,3f1fc221,632f8c2f) +,S(f0541a0a,d29e3806,e2812aab,ac185a55,687e058a,eb17157,e00a1cae,5a9e3d9a,40e81917,4473fbbb,58d40f1e,ccb2444e,ca4a616d,b0efc710,8f887c09,dd04b4b6) +,S(db1112bb,394f5e1a,b315f575,e2cfb59,4b83b599,6c82365c,c2095bdb,eb7c3cb9,c53249ca,30eb726e,6dfdb792,4db693da,f9740213,d87c410c,afa3ade9,51f9f688) +,S(2ad80407,9fdb7722,c96abd1d,35e76a7d,30948c7d,7b1e62a5,ab0994fd,667103df,5289aade,9f71ef7b,dce049cd,3052f8f9,653a9b69,3876b607,7bb42d77,9829bbe) +,S(7bcd5085,eea0f429,238c23bd,bc14017a,f8dde478,9d99b2de,325503f1,fcf7e738,7338f8a,7980de0f,404764be,7fb22578,ee820c6,16044f18,ad12d4bb,4b35a2a7) +,S(85819e4b,348ef2b6,d141baaf,3297248,7f34b594,8d834249,df465fc8,29a83188,306e8693,e7e718e6,39f48a1f,7dd5d977,9da12288,ef3edc6b,74afb1a2,906f931d) +,S(8d035a4b,5905b0ef,7fd9b050,ac1c006,2c0a8d84,1ab342bd,9444d101,92ed4a79,1ede85ef,aa83c466,4ac1cc71,c2d4027f,632f7ebe,2a097d98,9278cda6,35e2e0a0) +,S(bdc84795,289c3268,628904fd,5d8ef1f1,a89587f6,652aa883,5e83c47d,c008c282,1d8342d9,e330c123,7e232067,6fec10ab,b19c0d76,744915da,9980a9a5,6459a61b) +,S(75dab97b,d9e6571c,afbd8ce5,ffef58b5,72b6d8ff,838777f9,21834b61,1079c079,d048e6d1,fe2598db,31adfa59,8a445f0f,7f97ea3f,dbf8fe92,f2aa495,ff033bdf) +,S(b2a4a872,4a6ccfaa,8b8bde86,64fef1fd,bf9d4edc,215f9f71,738885a9,af19b42a,9bec2c2e,76be8104,f2dc4ea1,3e1ec916,23baf856,a92863cb,33b2781c,35f9060d) +,S(caeb3a77,35824f9a,b24e364c,789fe66,4729fe9,d6577ab3,f9cc857a,e1c2bdaa,ad96c92e,e91cf44e,8f0480cd,106b115f,23f0a30c,fd6ab638,86ee87cb,ba5ed885) +,S(a897e41a,75e6bfb0,78c272d,ec320e70,13afb506,478d984a,b5532b04,6da0502f,136cff6d,896be55b,5da484b6,15a09e9b,13453973,79fe4157,64ac5b5f,35aab82c) +,S(a33679a2,dc5080d4,a77fee11,5de9eab6,d32e6479,bd4fa795,3e4a03e5,3242412,1840b712,9ae52592,d99ee262,a56ae597,37e2202d,2871681c,6625de82,7c57819e) +,S(3183fdb2,b5ad14cf,9e2ee00c,e23b2c42,dfbeab54,acdbf786,622a83f,4db62fd5,7501e003,2ba129c8,50c0f17d,2a16b3c8,602c5225,1bac7212,6d454cd5,fc35a92c) +,S(aa6ac020,42f80323,ca77289c,88dc702e,e354fe1c,eedc720,2b87601d,7641b00,3ef01b0f,8b396221,8c5118e3,2168a6aa,ac901e02,5610db0e,8cf2ab21,bb06995c) +,S(f952d843,386eeef2,64b1078f,d835308d,514bc162,559c8f3f,c8ab5c18,378b40c7,fab32d0e,850f4bac,9a4af6d4,7d15976f,2e6fcf3c,958a72fa,b8db1817,cbc5dedd) +,S(75b58bbe,a5a1d00b,40f2fa2f,9e2ca8c2,eb568bc1,fe5559c,7e40ab8f,a0148e67,7fd6db81,7359736d,26883e35,727f4b21,2813be05,8d5d2477,1563696c,feaaf021) +,S(504e2324,34a12a8f,a96f64e,d39a7c0d,4168bd75,1e0b6249,6b24ab05,eff49d46,3bbb93f8,3d2ee95e,2e2821be,c3d98f4e,1f2def75,b5f8ed09,6947c4a9,1c933ea7) +,S(563fe95,1482826b,38f21deb,207a30d0,21271292,8b53c790,c33080b5,c4fc14d5,9b875a5c,70ee8bac,9e6d7225,1981c9f6,c3b5bb49,c8772243,14c4b287,e990bba3) +,S(91ed3211,161cf1ee,96499e83,7baa574d,1f56b244,56fc1589,d61f4d40,dea01443,f1664cf2,578f5ff5,8d81c281,514c7f95,56bce3d2,2150db9c,6f4a4df,db73d14) +,S(27526d79,f92c2519,838e3e0,a9ebfd02,f66e857b,d49cd8ec,6deaca31,d6064be2,9e4b644c,5bf8d50c,96892f3d,6843c94,f9afb359,55fb10b8,6a2f166a,6fa17f00) +,S(3ad1833b,df1ab0,effb0dd4,d535285a,900060e0,f38555c,ffd3e7f3,392b5c07,5c37afe3,89bf6e88,b88c9a34,6ab5a0f6,2128828a,22b6f907,8f9bc6ff,ed5c311a) +,S(eeda869c,21a8911b,cf713c68,caf261d1,e7fc58b4,3bdb0fb7,e83e677a,ec3ff6d9,f58e7eb2,3a62a9ec,f7a13dd7,b6b6809f,5cf8bc2d,22af477,e002f2c2,9c44d444) +,S(c7a806e7,bfc982b9,342fd4fc,e8f34786,9509fb0c,f0f54522,98162dc8,ec5a398,ba895fb4,f9084463,3eac5226,e91a08c9,e83281db,c406ab37,fa3ffc38,421a3647) +,S(c59586d4,ecde0cfc,3a1f5744,45cea454,aff18703,720fb4b5,1cd7b0de,de79c9b3,1eefa71d,5e67d9aa,15231b20,966951e1,93ebebf7,ae54ea34,e84b7c98,7cd853ff) +,S(3b259287,5283a78c,5aaebc13,5ba13c5d,4e5a1e6c,cfa196ed,6eb7960,e7eed0be,274d3739,5757e482,1ee56c6a,f56c8acd,f58cb337,6bb5096d,2cff4e33,ebb3c1c1) +,S(d062159c,e511418f,ea6e9853,b1e8d769,96c686dd,eef71443,e994a347,3b90e239,95ca957a,b37c702d,c707a3e6,388532cf,26cd3db2,64e4e9cd,fe0aec9e,77ab27e3) +,S(12a2bd87,c4ca2337,7915bd12,3f39e88a,fd7257e9,9587d70c,a9d8fcd3,2aa7ce4b,85562f37,ac813598,cf59e427,106fe886,aa1a078,1170f14d,3968119a,9ed65e61) +,S(9214dd98,2737e4b1,585b3363,c363ef83,b40a3228,53d6c54a,f5b1bf1a,a21e43a8,dbc49c6d,abe985f,d95202b6,bb925094,8b98bbcf,71486065,9b77c447,396e8eb1) +,S(34439200,b0dd5b6c,4fe8cb57,2e26de38,3311a479,ee39ea47,221a179f,fbbc124e,b8c15197,1ea4149c,d2a77b4d,14cea316,6d70b971,a7f9ef3d,315ce741,2ad43e1c) +,S(396b4410,cb5a59ac,15fa6034,7215ac8e,4ce3490,4dd15b41,46e90679,ca3128d3,ad4eef77,94f0c541,e70fd5be,45652364,c43e91aa,34683525,36c8b1ee,c061cba8) +,S(8ee1b02e,3ddb0913,dc781279,6316fde2,4489c98a,4e4c3cfa,c84b4350,34d53d65,9a4686,a5241a7a,cd4295b4,f1c9f094,3f8991a2,b7edeea8,bc4e9c4e,47956cfb) +,S(78f4da51,26b42e21,1d69c640,4e128c71,cd08fb67,efac0157,3bf128c6,73bbf6e2,b3836f1a,e397d7fd,c88d2089,6731fe04,6a46b2e0,b617117b,161e1e7b,3a2958e6) +,S(ff5c1378,c8a233e0,5edeed70,e23bb9e5,a5eb65a8,4b37c6c4,7c0a4952,e00169b8,a7275aab,c73eaa15,22328118,68de268f,189d3adb,da113553,e3f9d36,7664a0ea) +,S(18ff6e74,87ebb21,dc935fdc,265616bd,d3a4bc2b,35037483,c911f185,596a93c0,34209cf1,2710b007,821ba024,f0491e54,bade44da,5980f505,37869b8,b410d0dd) +,S(3ece6ecd,1c52894d,90043c67,59d158e7,143c9806,658e8e65,5fa53867,6609b0b,4b1bbdb7,7ed6deaf,fba0d241,5f2b7993,89cf7df0,7acfb8a7,a22f42d7,7858c622) +,S(a5356c78,6cdabe6,a1c379a4,ca18acb7,b41fd691,c32c31ac,6cd0edcb,9fdc5694,ab8f37e6,d19af264,58ec5b1c,78f54a4b,877c9416,ad76b646,7e91ca4b,24f988f2) +,S(e5dffa5d,961253d7,f99445b8,f8d8aadc,5415c550,da64a987,ee604278,12de570c,401ebeb4,afacec6e,d41006e9,c60e0ec7,a4840c2b,c64527ad,80d640e9,70800186) +,S(12c46133,4aa32bb8,465c1e9f,afe68d91,63a7a9df,e11940f4,593697d5,fd0c9140,e4fdfe80,be2fa183,4c32598c,a096a5d8,15386dc8,67588354,300018ff,5b2e0c2c) +,S(bd8d9bdc,ebfeaaae,691a19ec,c20cca22,af76db4c,ee54f904,ee5aa8cb,2010ccd8,cd5fca87,4a6cc17,79658266,158066a2,840e61d2,28bdd4cd,f2697e19,7c6c994d) +,S(597d8ca,babc10d5,5402f3a7,48987270,7cd5d3b8,3356ea13,6c8c5135,cefe3fc8,bb21d384,a48ed346,eadc6ba0,2b1e2231,7b2014bc,62d17fa0,9196213,6e12ab88) +,S(3d91a096,24fe1048,dafae0e8,c693226,cb89157b,980aa490,a9a12598,e77d7c19,738fee86,ab5a6e43,753b22cc,d6a28732,65db5dcd,38a6be5a,6635e8f0,136340e9) +,S(44addcb,55d0870a,19682075,116c8fc,d8f49b5c,5ef767ea,aec513fd,8d71841e,5e126cb7,8d13c0d0,55c3363,b236bba1,21cc5618,40e3cc3c,e100722f,1cdbdb63) +,S(5bc89297,4447eb3f,54b7b451,6da3d1a8,f23d6d42,54ec7268,f3e9b2f4,78d88467,6d708655,6b679453,253df54f,68541560,b5e542ea,8f1a4a9d,a023d8bc,6baf9559) +,S(8fe4f040,553ba9ef,47a0086f,a8dbb75a,2362af22,a58e0739,7c62d2dd,2ed2fc40,b2d0c561,5afbbe3a,18fcd594,a8e91e14,ac714af9,e34938f1,74a2c7d4,2028f65d) +,S(e36702c,2af02461,4d5f65a6,b855848c,6d72709b,b3ffbb5d,f08206c0,9c481a27,c5558c45,9cc186be,665a54f,19ed5f67,983bc004,c1c196fe,80c57310,59f1505) +,S(45b0165,d5eb9c2f,22c6f2e6,3f2cfaf3,5d4a71e7,460a41a3,9d3708c3,111387d4,8fcc8dcf,9eba288,f0183ba8,345c4b08,1b44cf73,b9df77cf,3e94c089,1e53cbae) +,S(ad02f6e7,378d62e8,87d651a4,eaec6d75,9b15f4f3,b7e999e5,2e9e493f,7d765205,25090d49,2164feca,33270e1b,3b08ead0,fcbc7ee4,aca4b4b7,7e06d865,5259a63f) +,S(5684c664,de3844ae,90bc93ad,426bbf69,5f349b97,6080193a,710b6125,3d6fcb0a,c5138172,4fb53812,9dffe038,7029b209,946a913a,cbc06370,b3b58f1c,759ac8f2) +,S(cb36c4a0,f6d2beae,282e9783,2148704f,aea7bea8,af0abca,ac670a7b,3808a2d6,d0aaf774,d65b7eff,589afcca,746b02e1,edbd10b3,e2938d6,5a0bd17c,f71de58d) +,S(143e1741,5da8c61a,959643cd,bcbd1eba,169257,2a935eda,1d0e2495,6eeee4d3,c12840f7,7a9fb642,50d19be1,5f35199e,1da83a3a,54fda063,99a6908f,87c9beb2) +,S(b6292192,d471ab52,fee206cb,64bb526e,6b8519c4,3df9ae85,4e4aafca,d53c1509,3d6fb4ea,45ae494a,e2c4c776,29047e33,f73af147,4fd217c9,856d5d1,3b837c56) +,S(d490352c,70551c78,9951a057,cb02eb17,fd710a0f,27dceaa2,ff224ec5,3c566a14,15ef3825,97ee6d88,ed8840f5,9d496c0e,6685349a,f1c62c27,a32eb7b2,bb193fb3) +,S(4797be1f,7ae122c9,2193fda3,80dac3a0,fdc14361,110a2a3f,5beb9f26,f3d85449,9377f25c,591ca377,2ffcdd37,65ef9a3d,6fa7c2,79d18e45,83901795,2e5fa3af) +,S(fcf5b790,98cff1c3,b02be521,76e1c6c6,ac10bcf,f083ae4,5d26ead9,82839614,8d94f596,5b075d45,a8f732dc,9fbe679,dffaf0ea,d2c90d16,b2c7ace1,1de05c45) +,S(d7153203,1e8cf246,683ee529,b2dcf54,1a731397,89e5c354,3bffbf4d,f95f76f6,740af4a,40e7849b,a41c4dea,4b7e0479,ca377fc2,69db00f8,b484c7a8,c4c745bc) +,S(27946ccb,dba75dc2,23663d14,2b56bd9f,2e63cbfa,73290de1,8fb7e988,31b44330,52c0ed5e,abb069e0,84fd8363,dcdb9134,364dcd4d,87b46025,9c3460ed,63e04ad5) +,S(cf3ea523,751eff3c,a785884a,b019199d,2a0ccf3c,1d90679e,141d4e75,74e41f61,b38d0808,936a2920,ece323ac,a707e1e4,914b51e5,e54843c9,63abf292,88ef17af) +,S(d06327e7,917280c5,d8a5c516,7e0d0c1b,e5fd9e25,4c877e9b,9ae6b264,6d9a126f,c3cc3913,9d0d7b8b,6a6b0c7d,b48213ba,eade2202,544dab7f,9ae42e08,fc7c781e) +,S(acfc233f,28f98688,2ac5ea8e,61478f62,505b8b48,38833499,1ccad1ed,5ee2a871,244a188a,64a6aa7,9f74e940,8681b45f,88b5c65f,d120650b,1a25674,eabb338a) +,S(87fb09cd,b3b8a514,f6a02da6,1d9b160b,798fdf7f,3f05d7ed,25c1c4fb,84b19253,586effe8,c4252dd8,c225a6a2,8e515abc,e36568af,107f8c75,a941e936,acbf6e38) +,S(77225acb,8ae251d2,be2f48a3,2eff0c6e,4f558287,13dc8a6d,3c6b7bb5,de9538de,d6eb8501,2aa7fe12,285e28dc,3efe9cf5,b0cc8e91,6fd63f71,c28c3f5,60259a8d) +,S(b03074f3,f2effb45,5caf88ef,e0eca7d5,6f901b18,fd04c01a,f0425c58,1f13dd5a,c8e8c915,fe06d774,8ceb2da1,78816b8a,4db1d082,6df3064e,7a4b0f85,ae99d461) +,S(992278e5,229bad50,82c8c346,8542f91,e2761305,62a34627,b1d97aad,a5999908,56ef7d8,d360d7b8,5af0f210,161ad17d,dacebd13,c45b9c8b,34f1ac73,bd6a1ac4) +,S(b73a2eca,5e9d0e4a,ef4f6ac3,e9610f3,1c72c67b,6a152fb4,82681595,8d44be12,c621ee64,b03b17e1,a25f27c2,aaea43d5,eb2918d9,e0949306,d2ef720e,8975c00c) +,S(7f6dba94,39e3302b,e4f7e0b6,f2363609,eedb30e,dc0b135d,e4aef970,cbcbc607,61685e2a,eb8e8244,175deb0,a006b5c,4292bd73,40b2fa1,3548262a,db98a3d7) +,S(88f0e36d,345aaeab,e8af18a2,d14191c3,8330c5e0,d4e32c5f,c562e549,cfad763c,bd062c83,13e44ed1,891b8048,2ee93ac9,95a0142e,e0543a92,a215735d,1e94ac05) +,S(da3a270a,bc03e6e5,3f572a27,94c8075c,8ce4590,b1b626e0,8a83fba,45dab386,884b46e2,3ab44b4b,c3d09f5b,97994e4b,109f2db4,ee04bc77,6752fdc2,6f0df055) +,S(df346699,77cd82a4,8e3e1b11,6311a5fa,3bb0389c,1c500fd5,15573af6,da0b2cfd,2ecf1fe5,fcec27d6,35c28d58,5fdb01ec,2192c8a3,848a72db,f53b7759,7b8b3735) +,S(11a4dfcb,3a443c3e,259c9f27,e24ca426,6e08fbdf,e4bbedb7,2e6cae42,569b0116,7fc6c4cd,1e3a0e22,d0ee0249,d6940def,bd776bac,9da5a98e,23cb6025,42b3de9e) +,S(2ffd148c,132eba23,e235bbd8,f09be1af,dcfd6e4e,5f2f0b49,6e4fadec,b931706e,6a4def93,52d875c8,31794fb3,6cf0448a,8c9ab5ae,804c6397,cec41b0f,24583acf) +,S(109e1f3b,7043c5d6,fb822b8a,54c6949f,117e829b,4065c0fc,c3ba5e05,a79142f5,c976793,6c034671,e5aceabb,9b08f5fb,af3cea75,a7a4485e,6c08f7fd,a63786fc) +,S(bfeea71a,8bb8ebbd,ca6135c6,26b739bc,eb2ada11,9babf946,6db9f4be,c7406610,44ff78f4,76074ac8,fd7ef860,cab01522,750fec0e,4b86f11d,831eecb5,22d1f682) +,S(4d2b7cd4,6cb01842,46e7846e,d0572489,e306b370,81515cb1,8a7c6cd1,dfb51665,60ebb290,44169e56,1d10a8e0,a2971b69,82276f1c,e7d11f60,ad7decde,e1fe9c95) +,S(66f2068c,e65a1a61,ad95ff3c,a2f15f55,29e0ce3,ad522dd3,d6083d5f,793e0e5c,a95bef60,2bb89e00,98723b4d,7fb421a5,b2cc751c,e8862ed7,439c1b36,efba2f72) +,S(4908ff3a,27aebeca,8697ec,dd7d5483,c6e56427,9d78f013,129e26ae,2ff459df,4c5def88,b60cbb2c,a3430911,aa84e4fa,1055fe1d,921c8fb7,bbb83b45,62b0f5bf) +,S(f9a90175,3a0f4236,dcb612cb,fcbf3f31,d97a8e6c,cc4f9e74,3887407,5d19ecb6,ed3c6f61,259943d0,310208e3,dd8d5a40,a5bfa646,35fca871,a6df79c0,830e24d6) +,S(ffed50c1,2434484c,ae866c1,86b88550,b0bd02e9,db04657f,aa81a672,8e321850,f16e95db,d44bc7c5,66fa0a23,669827e9,9cdf4372,6fba5f4e,a3e28d86,33edaa77) +,S(8061e9b6,2dd9d027,d43d13bd,1361ef3d,ccb4e599,c8d3d015,1d3adccb,6c762eb9,d33a9196,419b283e,5579ac98,8c1b6e60,378fc692,69b18da,a38f362d,20ca6895) +,S(ef8d0e44,e8b6b5e4,857d3d87,c82b01d8,f254c516,fdd139ff,7b8d034b,45698162,8325ccfb,6da9438c,e99dffa2,92afddbc,e1a101a1,20955945,cfb1608c,d35e7065) +,S(a31af5aa,cbc4f6ac,aebb9abf,de164046,1b631b2b,8cc43eb3,edb53185,fc1822e4,c3dbc990,691987e6,a8c318d,e381202e,a0c2297c,f06668c7,a2f027de,e5118a2c) +,S(81e47ea6,b60a3819,2094e7f8,f7bb3f48,a839b26e,d2aee7e3,e159bb39,798cac0f,186a8c4,97ba163e,aa779f6d,a8cf88a2,9f5d79f0,43e6f195,9c14bb1c,b1a53967) +,S(e15af4c7,8c61227,ffbf080b,a3b1dc2a,4966639b,926aae67,f2bec480,5c1fd232,76fd417f,4fe9e7c0,96db39ea,180d38ad,2360eac4,2730186a,b1da32c7,33fe9a63) +,S(3a185818,fb47ffff,640f265d,a2c712eb,f7e022ff,67a21a22,a2e941b3,f72639e0,8d370a41,1f133f43,34534b15,655717f0,73293f59,3bd34c5a,fc5c933e,120e76f1) +,S(18e05d9,2f227564,b572069e,18a271fe,2fef9d81,14eaee28,adb0fd2f,5f078e07,75f390d4,6e8f464a,d71067bf,b0d6596d,a945ea44,c7ede2f8,a9082440,d7e9a263) +,S(7bb788b2,4f4e5d49,2af81fdc,2f3a0274,6eedc5a8,cc74d1cf,ad17c2d5,4e80a107,5b28450f,1cd8c61,2b73038,ae889c39,d33cd64f,d452ab5d,28810177,dbb6a28f) +,S(a156cb3f,e4425b79,3334e19d,2b1208ce,5e6e8fdd,78748c0b,a1116031,912fb9d8,b2571319,c644e959,ba401415,3cba9b3f,cd8ac2f0,f8fa1f04,2d59ecce,5de14d21) +,S(eba23049,f5228794,1651a922,f60bc406,aa15acd1,59eaaf37,d1f2cb31,e7d20b25,ac8f8df,155b2703,d65b33a9,af581a02,8afdbe06,f4927a4c,5546ab7f,b5b2cada) +,S(8203a1da,56c4fb7c,96816507,f99a9a2c,950da51d,af7d21bf,123402ee,a95954a8,913884dc,10a53ab4,6b2be70f,5e2d201b,4c6bb23e,b6644817,b4257664,ed2ece88) +,S(d46609e3,ec19ef57,97ef86b4,ec51b8e5,7a854643,f817e7a0,9be4bc7f,291e7795,e1b3a8fe,3cda0479,11ab8c09,ecbbabd3,ce96974d,8a309ba8,c38c1d04,ef730830) +,S(1ffa9ab5,8eea8682,76849108,9e12ee5a,cb0ea4fc,e6f68436,377e985f,fabe919b,302140c0,7d64e9eb,6ea74636,f9efff59,e907a16f,5c876658,2f4a242c,b52f1236) +,S(4032bf99,32057d1c,8b6a8923,1575d3bc,6e2d6d0e,e1c7aaeb,ffa9ebe3,bcd9a0e3,13ae5217,f9f70a4,5f626295,b30eba49,e9f7c697,e3ed7cde,95442a03,b7916a54) +,S(8d32845a,14575fa5,ea061425,5e48e37b,f3a55bd3,9d924648,209d26ec,b94a20cd,e0416169,8f1e1626,18ce160b,e8b502b0,20a5ab81,7853903d,ad7ea792,b76266fd) +,S(403754d8,1a0dbcb7,1ff4893c,a5551387,b73d64b0,25bb612d,5e2187e6,7acea8b4,134dd3d6,8d642070,cb7778c,7ecc8d78,5c1deeb7,2582e25f,5c58b19f,2f59256e) +,S(4fbe9818,60e5f281,cb1afa62,8e8787d3,28afae7c,fcb73637,e2d64337,bd6e08fc,31a10b4d,78155900,7cec4099,3b5c59f,4bbb2328,b00a7550,572a604e,8d55b6c) +,S(a5414064,747b2ac1,e8868074,3a0fb05e,7ef510a2,a48d4f44,4647663c,b5c48b39,4b3ba626,56cbe6ce,2f228f8e,88d00ddf,135d6b81,979286d9,ec41c81a,f74ef7e2) +,S(5af99ffd,9f27830e,6ba54e05,63b3bd39,4bd8cdb5,764f78ea,b103405a,dbf3a01d,f625b35c,f510f9c3,db948363,3b2951e4,b2209b37,1397bdbf,1d899a7,400a4318) +,S(7fa7dbf0,1b2fd3f9,3ff4ee6e,17115c19,1f663d95,ff446dc9,d53d3e31,c98026af,f8aa82d5,28f2ee61,1a71b432,d553eff,ff1aafcd,8bf18e3d,b6dfa38a,f33eff7c) +,S(4838c0c,ed78e7c1,e3707d85,7311b2ca,6c7a4396,5be4e363,d4a374d3,36324640,4404fc6f,1a6c1751,3354d364,ffd43bdd,61b874f0,714430be,8a5571a1,808b5150) +,S(309c59a9,b42b374d,5c88136b,43310fbd,fccd6ba,e439e7ce,3a9c5e7c,ccb8dda1,fdded8d0,661b8ccd,834e4762,db87640a,fb1e9636,b894dd48,e1b4fb54,863863d0) +,S(1cc76e1d,788111f8,eeaed575,43afecba,548785d,3d66296,223142a4,7be59190,560e4685,6204121e,402c977e,76fac50c,446560a4,9bd2be30,c6dd2c58,62ef357a) +,S(188e8999,b9de6190,a65cc051,f936585,9e7a0498,4452402a,3093b4cb,24116589,aca3c642,dec398db,81fab67c,d05ffa2d,948a430a,e26eaa0b,ec3b2cd1,20b01666) +,S(2fca76ef,b917fadd,88e30d06,d6f398e7,6803307a,b8ac9817,4baa2945,9e9517eb,186c092d,95755005,4292ee1b,986b55c8,ee3be8ad,8adb6387,5e4dc582,c1105078) +,S(41d690fd,b5eb4f10,8aac4bff,26eaf866,86489227,b6e59b89,25440780,10e3eba3,251f34b9,d69611a4,31fe9605,7be2e10,6d058db4,34e0c814,b0b8a0c5,f2e50b63) +,S(282f850d,344e63bd,abc4542c,66cf1f1,a6807b1a,19ed7864,82d06a6f,a03b1e05,de82333,48fc960e,b22f5641,5265c1bc,be290ed9,4ee81fae,248d4676,d38a1a5c) +,S(bdba09b1,c1810ad1,ab2f5da1,b628a44d,a8512221,993c83ee,4a9484fe,6416bd2f,7049aac,e507d6f8,d77587eb,b8759f51,1b7bb2c6,5de0481b,d82a2f82,246d229b) +,S(e7e238af,4639d3f7,e5ec4298,65aade7c,c1127f41,d04b3d11,477456c2,b155a79f,da29edf,1e3c0ede,5546ed8d,cf8fa801,b5bf0dc,720a02dc,d9d706c9,a9c6bdaa) +,S(53a635cc,4e24790f,3ec5c17f,f854e2a1,800b2529,fa882945,50a0d237,58d622f7,ae6bf987,2d3a31a7,4f97299d,2fbae146,58c32dfe,418ee242,2029fff8,166656f8) +,S(10750fa7,df634f7c,7d8bd73d,e056e48a,50c413fc,282748d9,f4d0b485,d0ac5c1b,fdc72a01,883f0ed0,52d97ffa,8e6935b2,3f684f58,5e6c29b3,702f5147,dc645e04) +,S(881e3e57,ed8f639c,5023e45c,4e843bf8,e7d13323,289f92c7,143faf66,a65c3fcd,12f991ee,3390b45b,af1aefa9,dcd20da2,5891ac5d,35073750,47836a0d,e75b4dc) +,S(6be50501,4d72c612,bc0d5df9,13beac50,bafefaf0,aac7d032,824a102f,25bb45f7,4a0e0d0f,f2477287,ebd8c221,5bbf3e33,fff7194b,4217f9c7,57efa361,1b3abfb4) +,S(2ca955ef,23ed3481,615d1f0,db0fe5b3,f0fe5f1f,1b7f96a4,bdf814af,c4a58987,2dffc8f1,ce4ceeaa,d09a7610,7ee08e48,a591a177,9de2c84a,765a53e1,808e3c78) +,S(250da25d,5be3561a,92b56f0a,a7ab8fc2,bf7398d7,aca09237,3d416615,6991a05a,b0e62549,ca492ef2,9ab753e2,62b9c3a0,10df946a,99a982ab,812aa48c,def60c81) +,S(57606839,4791a29f,b66f2314,73b6bc6a,ff383623,c889695a,910c1894,d9c060b3,bac9ea05,7285d6b2,7911b19,b32fec7c,1b25db58,ae39eede,f4aedf09,46c04ae1) +,S(46edba34,d53e958c,c3e4e74a,ba8bb4d7,c6266aa8,9fe804fc,e27bb8eb,cba98e2e,2b85a88f,136b201f,9a1747a6,dc55f59b,41049a69,f824e3e2,f7f00787,f687aa6e) +,S(5d4f6ce9,ac52d698,1a13e73c,3156dff3,918d5b72,5e42f415,a503e573,bd6611fa,4c633703,1de35eed,dfc5e646,e8b0f812,2b951fa5,343d7b59,ceaa5c85,e1ce5c08) +,S(c77db927,f7e637fc,24a38bd7,f605383e,91e4e2de,8ba5b1ca,baed4376,8ae120c7,347f43e9,47b5d13c,c7cb6fc9,fc2caa5,2991a0e1,bbd4bc96,d98ff26f,1a81bc5e) +,S(ebe2ccfd,ce91b78c,95cdd34d,79fc9a28,478c406a,224bfb4,668dd5f,197934f4,d7866df2,d346bd30,84ad837a,a0c65cb4,62cad5cf,3d23b0e4,bd260fbb,f4666ec9) +,S(ddc5f94a,d4420ae4,8ece780e,26940338,294b8929,549fb897,82c06e09,b7935549,25802633,a0127d73,21ef0a12,a2a6eb32,692f2d30,5e7d3cee,f137eac5,8896ff71) +,S(e4000918,46f79f21,71b299ae,6b93108a,9377708a,e7d3f5c3,147a98d0,95e876b4,c8d8c4db,8fdecd8e,fda047f,b92bd9b7,3c999493,27c491ce,df19718b,6152c434) +,S(4add9850,90e16b5c,525de57f,a15a9c38,97527b6d,8683e407,3a978cac,53b29b66,dfa1601,d36d2021,6efe432f,8a335e2f,42b6d645,7fd6f032,d727157,32a85dbf) +,S(8a5536ff,ff9c9dc7,b2a67823,5d60ad10,834c9029,bc243f3a,f10d7e14,4ca0a78f,72ee78e4,e0a618ee,191dc7fb,c1143e4d,70ffd570,bd50ce8f,d368ec29,c22bc926) +,S(9f708795,6233a0e,59757e17,5a87e34b,f7a7485c,94f9aa62,61854b4b,3ac62c05,ff9902b9,6a6cd1cb,6ea35965,3527decc,7827318,97b5c8dc,c24e2399,fb16ff15) +,S(bfa5d3b,e3fd56da,d8e70330,dccb79f5,bcc46cfc,220f4921,4cb8e700,e7cd0ae1,2a4870ce,aa2e001f,567ac21a,79eefe94,8763b5ab,c63fa649,8a5cffa4,126c6d0f) +,S(a965e34,47f07286,b91df55,3e4211af,e6b837ad,a9cc10a4,905975f,1983f2fe,393bb45c,3f6eded,b6de1e70,5a706501,cdd10ea0,2548279e,c75e4dd9,15f0da2b) +,S(e5e38677,c1e4a659,51358301,dbba1e3f,c44f5c23,af7011aa,5ab93ad3,c69b18c1,7939d32,de371524,c3b14f5c,745ea023,34f9222,31f29d8f,c8294802,b334821d) +,S(473453e1,80511622,cbe6df28,46f479c3,b8638efe,9af11beb,21dd093a,24d243e,e2b897f,eec79c08,5afb9daf,c9ead107,57d21019,c655d0a4,e5254a69,941962c7) +,S(fff734d0,e5f24c63,dfbc061b,bac37c88,ec5aeead,4974cefd,77f1eb5e,86219772,ef8a22bb,c29c9756,37c600eb,82ee5873,778d539c,a289a50c,5490b5cd,8ee0bfe2) +,S(d0508f53,85f92779,809a1892,43a58f71,47f643a2,a8f5876,510b191a,fa292dd2,329eae7a,2ee52766,a5a2874c,3912d777,e23c4aee,390aca18,140ced23,b8e82d8) +,S(93170604,98fb43a8,41d09d53,98807f99,23405879,be9f224d,52d21971,130fba89,e84fe72a,cd89fd4f,f7db1817,edab493,5f809b78,6d0c3448,f19505e5,a79e60a) +,S(63634cc3,ce570dfd,8bf90307,f4543528,e26f2637,ce32d690,75cecd2f,63dd127,bd12dd78,7ebe0ea6,661dc389,5bdb6478,7435e9da,5812d06d,d9188b47,e1a31939) +,S(30c7e2a7,925a47a1,5aa1e2a9,6f564e31,61b7a559,3af1a696,91088dc8,9ee64431,5ef4f2d9,cfefe53f,3dc76f96,1a04bd71,6aeca894,73553a0,1faeed0f,6bd2d506) +,S(f7b7e1e,d56b7caa,74f60145,98c18126,d8bf10ad,c37cf1bb,5e6c88ae,f9f6e6e4,a019d45a,7e091a62,8b7125e,d3720f95,dcc091e4,2ff17050,da596fdb,58ebc508) +,S(c6e9b0e1,177dedb1,2e19a0c0,d1167a8d,8095b2fa,1f2dc402,adef0cad,d5d87d3a,64440da5,2b3ec64,4565ad12,6f732ae3,c81276df,5ef15605,3318693c,91c12b43) +,S(653d41dc,e6ae6cb9,45533e54,63b50a4b,72f6efa9,7884d878,52c32eac,fa0f59e,693da28a,13a9cde,d1b7597a,c199e00f,fac2f6f0,6bb0dc58,940b6734,e5eb934a) +,S(b9830b38,f0f8d466,e363fe57,38124fd1,8c9f60f8,cdaf6fd1,a10205b9,5c7212ce,a3e31906,6ace61e4,ad861027,7a12d498,5c35969f,62e5573a,5bf4ac35,277cf444) +,S(94d9457b,eb2bf3db,cd38a667,adda8750,f449af92,6a92fc93,f1dbaa85,457182ec,ff1bd647,8f00626d,1b203da6,992a2366,2ca2b39e,f6c1528e,956d7d81,7e2497c5) +,S(816f295f,1648ccd4,360b1807,bfb9b05e,4a84af7a,140a1f2a,f4016527,1d4b5b80,98217f98,6ff6f38,1987db34,7c6d432b,f24b664a,bb47124e,641d0677,aa4ec143) +,S(3b830637,17254b06,16c1a5e8,999dcdc7,cf3cac91,67284981,75c6909,92e2b2d8,dc2d471c,5323eeeb,611495f9,cb37840c,905eaeac,a85cca33,76d24705,d152acce) +,S(33282bad,f48bba9b,3db3cab7,c3b46c83,867a63b0,db393ed1,2a4bf49f,cd2f7c5b,78733604,b1c94144,ab9a4886,80bc53ec,9d67c4cf,dc77af88,40bc3535,f2c42309) +,S(58e15e93,95c3abc5,2ea68f94,6e3f7943,b1ddcc8c,e258aca2,8cd9f5e3,14b257ca,d7c15bc8,53dedf6b,f7dfad87,bcac6e37,f90d32b8,344d95a6,44879ba1,e170070f) +,S(c9ee3e27,54e8c8a1,e99c39ee,cd3d0b50,f8fcd03f,ccdab94b,e503a1ef,b66d900f,a1ce86c4,7f78400,51c87612,1b26922f,2b4b2358,e302c568,da6310f5,14909db5) +,S(6e2621bf,dcab8898,7d50b5ac,b27eb94,b52cfd9d,29e80d2e,befb5478,a3c5a514,ec4c657f,ebbe25bd,9d6b172,68ada77c,5bc4f32f,57f325db,9556ae0b,4d1adda2) +,S(6e3c35cb,9c86216a,250ae256,f8ab076a,76264ca9,97b1a6e7,41ee96da,5cfb2c9a,d45f0082,46489230,268e5c99,56dcff9c,bf6a0621,f8978be8,f2183920,eef3dd74) +,S(f3b5baab,882e20ae,b0f444e7,47688392,37acdb60,e7c878ff,40ec0aab,7896c278,7d8d6b2f,92addfcf,a248aa96,e8a87e92,4c821c1c,cf7b343a,f588ce7e,93e37260) +,S(b89b2380,110087ce,8c8bfded,7dc98e40,3cada8dd,77b2e68d,120361dd,6beeca0a,616e00aa,4aba8494,9835b0a1,eb0ff955,6268d2cc,91b7672,d0164693,848389b8) +,S(6659b720,1db6e160,58854e12,dd78b89d,40d91a17,b7eac836,ab8453c9,ee3cdbe5,5ac9db66,325b000,1983df0b,6693d93b,adf7e35a,a18f76ea,e2053e34,b1b8908d) +,S(6fc76d79,bf3c34ce,afe73e9d,7a77af23,bcc7e894,dc555f63,8b9d53c6,c15803e6,c366b411,1d6ee57d,52d3938e,f2c0c620,746d636c,92ab73f0,bc812888,ef0b5ac0) +,S(a06b2395,238326ea,20545cd7,b021a5cc,9e21e9e3,26c28b1c,fb50f3d5,e0f6e069,8560335b,a5c16aec,a297f185,ab09e976,dc57934,61170b35,b8a3b6b7,4ff622f1) +,S(bb8064ee,177f3753,19e45c8c,4dcdda70,ddc4bfff,1a866b7a,ae7922e3,13d1515a,a3be84ad,274704ff,e7a76277,d87687ff,572633b,2fb46b4b,40f601a1,ccb98d7d) +,S(27f08788,6a2c0ab,8f26ef15,a85d2d38,f6fb8cba,622acf21,77ac20f2,f05962be,ab2f2929,45163b83,c9cda8e9,4f6d8f7f,167bb589,50d4226f,827c5b5f,a782f8d2) +,S(f51d558,dfd8f74b,7c9c3768,65f82932,65c1bbad,d8aa64d1,ebbc09df,b7f6de1,101c88a8,170355ec,ac23ac98,ab5aac67,7a68a94b,9343012f,74cccfe9,308c039b) +,S(60fed665,a3ba26d,eccd1ab6,c956ed2f,e33da384,dc687f41,6c37b550,123a5441,4bc061b9,b2d7c63a,ac042a7c,efb2b5c6,a43260f6,8bd0f843,fa218cc2,3fc9b5bd) +,S(fdb04aaa,f2958755,ed65f968,ce4fbb81,ccd8c616,32e9494d,510a7b3e,d2564256,afbcece8,c52725ce,c0ef2aaf,a094385a,831afaa6,7c4cdc9,57712bf6,1073990a) +,S(7f45848c,cac04d5a,d9caa28c,e60628c,aea7f076,262689e8,27fc7084,d6b94dbb,51e16503,e044b101,a0d12d73,3a57d8c1,546c1f04,386721d7,a6f9fb15,458e41c9) +,S(b4091018,4c556249,30ec006,95f02723,b9cef749,57996d50,72642d8a,b492c9be,1b3c221c,235e721e,95bdd451,f0f0fc8d,a6a18260,d47b0c09,5f3e1b1e,f6135e5d) +,S(4d5b1a50,d00b83fa,93ab4746,3f84dc21,d0ff4559,2e697fa0,bf8e8f68,5e1c9713,da52a118,24ed00e,6a2434d1,ab383f0f,1e495dac,d08c6a2d,2425e25,a9434af2) +,S(63fb80ea,cb68910f,69700533,8a1769f0,69acdc85,da71618a,9cc03557,1d4bdca4,7f2e51d0,4446763,9cfdc2fb,247c7cb9,5b8e01a5,e27e6bda,6713ba98,1936573e) +,S(f5035d5e,12313edd,b0c31851,266f7e92,6f16c1f5,a6031aae,bd5e14fc,18304faf,7381fc4b,cfb33c18,7bb59e22,be95081c,6f52cefe,dd84bf6c,799f419,453f61fd) +,S(f62c9afc,5a2cfec6,afd54b78,375a73b0,eb5a73b6,f53e24a0,6d1e9111,ff20e835,a5d386e,211845ce,9ffeb917,76a8b91e,27f0773,b2d53fb8,2ac44b8e,83198350) +,S(7477749f,3824c134,c1a91bfd,d1b646f6,43f8109,c2f46887,22799f6d,53e6280b,232b459,2259cff5,99e4af77,1e03c94a,11fc32bf,f2598beb,2316d3aa,d9461c55) +,S(2e2c5f43,5fcf4fcf,72f9629e,ef6ac5f4,31073f2e,7034d6a7,64af194b,1e84b6ca,cb94ef61,c794f44f,2c7d1115,b9dca665,7fd1c184,e30f6f60,caf40e75,142ee26a) +,S(8f7e4f94,fd2a651,86e4624a,93272af8,2d362587,62a0baae,f65cf47a,bcd8214a,9edada6a,d23cf1c0,dd98b1f9,d9a83879,4c21654d,239f1a9b,dbace84e,de6145a2) +,S(e184ae37,4704eed2,b054b667,33544ff5,6ce55a9f,bcd7625f,740b6a67,621c75c3,ea773744,2212bf1d,a26fd119,248b0c51,c413ebaf,75e52de8,97b4383d,b397e144) +,S(fa47fd9b,94cb72b2,60fe208b,c022dfe3,a2bce2f9,ec776313,a497cd91,4166850e,9a12bbf8,a6e0ff91,5176f71b,16327c7,ea5d928d,816de31f,c8de2be4,57b0c185) +,S(98d36e76,a4caf051,e848fa49,64e09bfa,815109f8,63cd5e99,405e64ec,d526c67,706b36aa,6e67352,8fed83b6,8118ae7,1e043964,f444c477,590430aa,8d80d19e) +,S(e7722849,c00c5875,44751cf9,a88fe964,9efc05a3,4d810788,f30a2057,cc1d0c72,d64ba14f,978e1769,51951a4e,8431af78,57e6d97a,f5fc5ba0,2a1fd46b,1c215e7e) +,S(93374edb,547efea,e5f22d56,acd80ce2,80e4d47a,bddd1d9c,9d85afe4,aa6fe6e,e9c40824,cdedb038,9b42e2e7,2e15009b,215d9080,7df6316e,6e81ec9d,40dbbee3) +,S(840eb546,a076bf81,e4954196,6eb8c437,3a055239,8dc4deb8,62a73b76,8b380e28,97b69f93,ac1009d,a3f47ff1,b62ea845,f2900d7c,84e8a1d1,48d96f,df6fdb98) +,S(fdc4ef19,59ca06ae,92587249,e45d456f,d7484278,6f4b3381,676094ab,446c3e8d,c832aa3f,f0ce9f79,1fbe89e1,5511e25c,6a7a4230,401471c3,7b9ab011,1b304366) +,S(42abeb49,83403d4b,5f529eff,16bb991c,ce705250,5a61fd6b,96467a51,f661651e,d815247a,f807af52,b454e83c,9d46327e,d80d3ec3,60f84a3c,dc88b9b2,59efb05e) +,S(176fc9a0,b44a34ff,fd652cc8,bf715a12,a9d5f40b,adef6032,24536660,5e0680af,a47100b7,e0fc557a,f5ca7dc1,c220b5a,770231ac,184f14f,57e554d6,11daba35) +,S(11fa2a03,aba7cdd3,1940923d,37045c99,ff531ba2,a1266fc,26ce7a26,c6495e63,360c9e1c,54fbc823,9878d725,30254bfa,70453c3b,934915e9,5ea4542c,1026b272) +,S(b2dda11e,db5f668b,8d90dc96,9d10f8dc,6c95a16a,a3e2cbb,3a1ccc03,d9acec22,f4d44dc4,8c260995,4fc1316a,2d5bfe6a,18ea754,43bd9a55,2b2f2f08,aa0652c5) +,S(baa1d433,e2adc426,5f87f407,1c8c35ca,423f3e76,5a835a70,2d804593,cfc3f7b,3f55a493,9e25a77,8a9d3ad5,4ccccebb,8a45486e,1aeb817c,dc0a2799,6e70e996) +,S(478f18c,30470c65,b578a6c5,df9c71ac,934e3439,ee5d5d23,21f8f5a1,7adfe55c,c43dccf1,9a9e48c4,41ebdc12,f2876cbe,32852cbf,d3bebc9b,a3708fe,6cfa450e) +,S(18223de3,d62283f6,c440102a,a1769ac6,f5e1a0a2,cf3fdb2d,ec62563f,4e149ebb,57fc95f7,f8e3151b,80fa4e68,45349b7,961fe72a,d6ffe725,e3a0a0f8,907a4555) +,S(2c8c523e,179bc8d2,1e3faa5f,5db5dcf2,cfcb0426,3f138cde,428746d9,94a17276,c3f00baa,69061521,5d512c97,aac1b858,40842fa0,d8bdc773,4e11d370,4f6330f3) +,S(a001d77,af44959f,f1e83be7,d6b16496,2aecd428,3ae2c38d,f3ed3fb6,a0f12460,e68a305b,6f60a1ae,5a01eaa6,7675f0d9,8e6c5baf,75d725bd,d0e2a499,1c323770) +,S(cd8a1d36,2ba4a2db,255ebbab,ede7ab7d,383b641c,515250a5,cf52a2b6,a5b2ea9,20716fe1,e0857b5b,55b836d9,39d3175,188a6f9d,d3cc42ba,8c61a7a8,d9a7a1d1) +,S(7796adbb,7949b234,6df5147e,c3d7e0c2,5b61a874,43fea9f4,b4e742fe,6c1218a5,fc338089,c80c6415,dbb32994,cf5e2af6,b5c3342d,d291d7da,def80628,a904edfb) +,S(3c345146,27eb74dd,88ecbb47,aa9933ba,b7fc8cfc,bd80654a,f96aad51,5c1a7017,cf4318c4,1c021c06,5c100913,dc84259d,2b8d6ee8,102e5c6d,c3f809a5,7f8f2beb) +,S(cb4470d2,d5715339,acf391e6,5e3cc397,eac932d5,5acb65cd,a94538fd,eb684f67,15e6e6f3,383b8bd,1b674497,589ed7cb,e0f41394,e366ec61,b7e1b927,daa6434b) +,S(954a527f,c4496d02,915f0b11,4e95f104,c500be4d,a61eca3,2fadde9d,c1f118f2,96acbc82,d0dd6226,5652b61e,226b7ef1,c6f00491,91bce5cc,fecaebd2,fdd28ed0) +,S(d3be92f5,697a11cb,b8374938,9fe89418,97707ffb,24fcce90,16debabb,a4faa4ec,23d04ff1,e309abd2,aeac3159,ed9acffb,9c5336f5,517531c9,f1cc2dc3,a2d300bb) +,S(7490df7d,5a7ca290,fe029f3e,d92f530a,23a7c983,654bf19d,5c9ee21d,b4f57586,3d7f28c8,81b259e9,f5f735fb,be608154,b80f38d9,b5131bd9,a6e2dabe,7ab2bd54) +,S(992c4a82,1176a784,ba2767ae,a3d39697,5f96ea50,b7bc8947,2356fd98,20aa666f,519d9792,458fd39,7050829b,6ef7449d,da4ebdcf,fecb2a3,8ca0f057,f051c851) +,S(f070e211,b384b497,3d2dac23,3373a3cf,6dc7b9a6,2529af9c,b2fb1e84,b40901e1,175cb1d4,f8339521,26d4b41d,9fe27781,92a2a1d4,7d5faa48,1e96f51,beaad506) +,S(108f6113,c2795472,244db9f2,3a1002b9,349bd34e,f9c9d70f,e146df96,be198ede,2bb9d195,d087015c,253af145,bdd6134a,1845dd92,45d7d8c7,c12ad2ba,2027ba2f) +,S(ceea04f7,9b611056,ed7043f9,707bb318,e3ad332,1da82104,9790b1d9,d264349e,5380e9f,1c52e5ba,6ce18afd,289f49bb,c358bb90,9db23d67,a851dcf,9ba5ec9) +,S(1c74297b,14a4fbf1,2a6421f7,561c549,414147c3,2a683391,c4cc5eb0,79948cd7,581c9642,98232591,bd5469eb,c1a01be8,37bd5d43,cb63e21e,8540ee84,52b12ab1) +,S(14bd0f2a,ebcbdc9,22fe8660,c63bf12,c6db8521,f1f0acf,7406e982,a103bdc2,46c3002b,1e5f25e3,98c8d7af,e340aab7,23ccb0d2,7e24bec4,55d547ff,1df59c96) +,S(32c923a1,526240db,b234ab72,565d6880,b260e7a4,33747aa2,802da713,c30ae9a3,b79bdd74,6ce4ecd4,a554d66e,b787e312,a1ed53e9,c77cd6fc,73b1bfee,8b13d620) +,S(af0ec2cf,21ecdfc6,a71c6edf,6f73ab6c,76600a89,86b62006,8b246008,7cdf168,d229f3c2,7db8019a,eeb8f25d,84f3e341,681de4ab,2173f510,51ef4249,7a9dbb0a) +,S(1d648075,8273a9a9,c970cb10,5ae7e537,b017aadc,8be5044c,a1f6a3ef,4d2cb275,3faae8a6,87925e3c,e9c3482,d34c76a5,702c9bea,a307aa45,f2ee992,efd86387) +,S(160ebccd,b4d5561b,488037ac,25224afd,91c66584,660af970,672d9514,87376568,f510b49c,b58b09f9,46001627,2fe744cf,e6e7abef,8f54552b,41b6158c,2ce2db5) +,S(50867128,704795c1,a190077d,49a87c99,8b10601b,c37b7aa9,908ce92f,28969c30,106fc462,a115f2b3,e83a5474,7a692101,8c73853d,83d8a1b2,2b0bb785,bda8a896) +,S(3ff4aa26,7e8d344c,ac75a46f,7b17af59,5d056078,fe860a96,573a8f0c,164c54ee,2632d1fe,f4b34a45,ac38a80d,236b51ae,de92fb72,47b81f6d,af1b9554,4d426d82) +,S(739f875c,ebe795f0,cbb846c5,88c2b809,21468ec6,4ae09034,6032a97d,fda93c1c,8393a2b0,f3e68c9e,a57d5c8b,f8355d8e,71f4699f,201636da,5451023c,92a1b98f) +,S(717bbfa2,b2c4818,ae620498,3506a421,8cdff59f,2e040521,764b8013,b688c7bf,9229cafb,e99cbcd5,3f73938e,82723d2f,e7187ca2,13d9e0a,57c12254,dbc7f63d) +,S(cc0a808f,2618d1f4,27f165df,4412739a,6ad9af38,e8c25a2b,14bc97aa,1c5b0f7b,3b83d5f2,3d94aa87,9769c3d0,5e921731,17c345a1,3418ec3,2f92d4b2,c1e275ad) +,S(4a0b31f8,8f82abc5,6867fffa,6deb20d2,d8e7613b,aff466db,b260734d,1ef8b1c9,375d7c69,83784dbe,a5bfa8c5,8f8baead,8e94b9b5,95c01d9b,2747a06c,5fb7272e) +,S(52149a1c,53b2da97,f39e9dd0,23443cd2,b21e404e,b6235014,ce04c616,9f5d05a8,a9f9a4cb,ea6d202a,c6b5aa93,28f583c4,45db83e5,8ba7fc25,3eb43e3,df7f542a) +,S(6e294aff,9e9fe4df,9345bd93,1229a7b0,955a3b63,fd19d1ac,57bbed72,50262b8b,abe6fad1,5fe423b,e1a55867,137c485f,85639823,beb6ab2,81dd9e1e,ed447123) +,S(e9a70c2,c5e962c4,dffe24f3,8930e095,c2b0b540,cca2d891,2f6f5b4f,e4592e9d,8d115293,95051750,ccc9369,63b987f3,96bd05a1,49915103,1e47baab,358decf8) +,S(e6c934a,57ec5422,5d42dbca,715e62fc,ae957590,52849f8c,b5f282a9,b82d4adf,6da738b2,40ff3070,bf0c4ac5,50ca5a77,31db8a07,20312e2f,f9de572d,d7b67d4f) +,S(89b46ad7,cbcf1b6e,8741e422,ef53beea,49662d96,bcebbffb,57baf0d2,1441a0a2,b7205431,1798624a,3a1708a8,986ca47e,374d9704,22f7d3fc,57ca7f22,94913e8) +,S(5b949cc2,69f0b0a0,c3b85fd9,e45b737e,7379a4bc,70d926cd,cad87ae3,4e7a686,7e54863,c1efbe6a,a98d6466,65057347,7291b068,a43f1783,9d02b190,9327bac9) +,S(787baad8,9882587a,97b049cb,9906db7d,b909239,aa50e073,d476081b,4a73d7eb,8e3bb416,b57585f9,8b337b72,b23c2b9e,c790ef6c,bd397b18,ab78f8a8,cb662425) +,S(58460ae1,5a204740,c375cef9,e447edc1,2fb6a0ae,2f8d18b2,8e82ba60,729c82be,1bdf3641,d16d89ee,378e83ea,302efb0e,2a9471ac,9bcbf1e1,662885a0,81c7780d) +,S(c9bc29a2,1f7383a3,a90ed3d3,fc5f6d32,1697e354,a77173fd,77899d17,2012f63f,1c850132,db81d86e,e866d9e5,75c4f7b6,270599f,2e48c0b4,94317dc3,97d1043b) +,S(d4c54b66,a1ff77b7,63f8c520,181e4ae2,6b82643d,758f872d,cddef933,36cb84b7,23e64d9b,f7456086,ce8b778a,194f8b8d,f1f0bf38,fbb8454f,d271d062,ddb9b9ce) +,S(a947a90b,b27db3eb,8b4ca4cf,f947e587,54fe6a48,7b922ab1,9ef4b5c2,99eabe3f,c83e7022,f6e12dbb,f95e95dd,2bde8b94,3d72cbb6,5b222f57,94d13251,c9fb975c) +,S(d83f6040,4099d448,8ec6785,131524f7,3e58727e,829b3d58,7d445197,cb367746,6d50285f,831e1173,cfd7de2d,d1c7c29,532a391c,3f450b7,f25e758b,f412a8a7) +,S(75d60448,78902615,467175b4,bc16c936,14bb10e7,c9fae9f4,57d4a210,2d506a0b,885237bd,b4277447,fc7970c2,4e3e7240,ca24a07c,e46b8bac,7a91272c,ad9c5854) +,S(1f96a542,2ea4726b,b639d270,17eadf33,43bfbb7f,f1fe9307,a20fb5c5,f1c4fda,5f80a9b3,ec8b0fde,ee914ae8,e6052100,77701a73,57829803,4cac5d44,91ce0a22) +,S(3c0159ab,4f27b61e,c2599ad0,a79b4228,9000fcb9,ceadb440,24e1527a,f5ebb9b1,77df26bb,659283a,37abc70f,9f465794,ef3fb178,107ccaa7,a5404c88,a67a12ef) +,S(5b250c4a,25293ab5,34f287a4,9f9f966b,7ebc1c93,e5a774f7,c98980fa,7980e07a,dd6c9c36,5c015685,9e1ec5fd,3a740d1d,7eaea301,2311d1,a9cf505e,7e594613) +,S(20a6dfe3,71696c50,c3a7abf9,3341c41d,9d6d2111,729fe45e,f3ceb49e,977151fb,bfdd0224,fff97fd7,ac3eda1e,ec0e6f02,8bf7a3b8,23cb49d1,52d643e8,fef3d820) +,S(915fe7ad,5840d789,b94d1bd3,2d555340,3c9152f0,340a5f87,6862ca40,19825b79,8d2f0ba,3459615a,2036a07,ca57d0e0,f3a4290b,f5fa7327,2431e3e7,bc44255) +,S(d6aefb63,618e2fd0,34e4f17c,eb766d5b,c27c9a15,d796b16b,7cf8ba71,31a2404,f0abb6a6,e862f6e5,d71b062d,e9bb7b9,dfb2e4be,1c5a85a6,dd3e0c25,3617e8cb) +,S(4c804837,7d65a97e,f65a342b,c4549e16,5cb1c50c,cd1549e4,d2d2ec10,c663882d,e1ec6bee,d0bb7243,a384e6ef,100e5180,4de6ac00,b06d7b67,3e445dc5,7b76dc8c) +,S(3a6df802,f372b56,1ebed30b,a4740d03,d257d256,4931422d,fd3c8c1c,619847f4,d168c60c,9a86bea7,e48e58db,d8e6bdcf,b6ea7d31,d57f8996,70f79e33,241bc439) +,S(423eedec,169fa4aa,52588642,a62ec6d3,8acf2ca1,c8098c24,4a56a6b3,169f9932,4887b475,7f27b4b8,d288c05d,3efc1d98,c0428b5d,e4db1cb0,6dcc4782,10cc6f52) +,S(2864f372,8f8c5ca7,5dc56dad,8b968c71,a008eaab,80b8bf28,16bba436,78465be6,14f5e2c3,423f863,64962871,b786c840,50cc07b9,f537ddfe,cf81b95a,a276b813) +,S(cb96234a,985e2ada,d8130ec5,472efca5,7ed7331d,ae7570c4,dd42f4db,9597ff08,69722bbe,5b367ce,5868b30b,31f67c8c,a5f047ba,a7f65202,48041458,66b88d5a) +,S(3be93dc2,99b7e701,ddf0f239,286ac598,bea1ce42,f1e21ae8,1cdf07a7,66c1123e,8a9c69a6,6a475e40,d81b5d0c,7734cec3,40f528f7,4fa0073c,ee92161e,cbb92d00) +,S(9022c43c,7acf3552,fed52d25,d25dd3f2,9aa61fa6,988a5499,6aa3626b,88b7f497,c514a46,f328c9a5,dc2fd03f,81ce3fda,915f1e8f,127348ff,55e4b5ca,2eba0e53) +,S(a24cade9,47a24abc,a050ef7,f62d138b,85c96d0d,2edac403,dad58ff7,8a2a9d3b,a209613b,c05a7b52,41697e24,73fa7fc,412f8fc5,b2fd0447,a2e20e71,949cbc0a) +,S(cb2010d3,94259307,ee3491c5,58efbaaa,203cef1f,8a0a1e99,67a4ff3e,719495f7,1bc5b6a5,b5acd447,baec221,141b601b,a5a3a640,7f84b8f4,319a760a,6226b0c) +,S(fda8c6d7,c6302b27,76172f01,5e59da8e,4af1e96c,3bd05f2e,a393fb7e,1dc1ecbd,87ce1baa,ef24102e,19c7a17e,b267acee,7681d40d,705f7058,c514c9c1,f615e666) +,S(b459fb13,5b9902e1,760286b,b37ffa03,ceabb618,e684823c,17ba97dd,c95ebdf5,6e35fbaf,b5175d3f,ac60f2db,97447cc4,a79c212d,5496ab7e,4b536ddd,797a19d7) +,S(ec137d8f,23b119eb,a286af6c,583ef011,5d21f335,8a1a2df,ba6af216,d03b4a36,344fd1e4,869d68a0,87a1974a,d48b9704,5db2940c,dec017fd,a0605c11,8e5c7bfa) +,S(8e0be401,9f2d3cb8,9ab07348,cae295c5,eb7fd7aa,fa5a83e9,3d68d994,af68e14f,542fcba8,51510baf,6f962401,e8a607c5,34a32971,22645ebe,2dd51867,b26c80d4) +,S(b1dc8611,3cc18708,338542ac,698a6981,a6192261,7c1f71d4,3b72baeb,1c0dab03,f3e61423,5b683727,f1cca8e8,41de0474,e8c4da8,d2bef431,3cc2da5c,c4ccf38d) +,S(d438b027,7f6c7048,c1eba2c,c1d7e554,888a7025,3f513261,3bccad8f,a5a0a9d5,fc419852,23f6ba14,adda0abc,389d2d16,4a910dab,b464232,298c2a1c,50ae64be) +,S(5484d618,5cdf3f21,42235130,62ddf251,1f53a84f,f0fada86,602c4b13,3dea0f70,6e697180,33860802,6ff41cec,cea79f48,b695aa37,2a76d046,47603a67,ccf9615c) +,S(8c1856e7,6842f5ce,82c09a82,4d343a6b,ac67ff27,f6d32de6,7117dd75,59df362c,70f78515,c4bd17c,23f61049,d6ccded4,100234ba,b7e1b9be,16925635,a9aeea2a) +,S(48052022,94350095,8c904f57,54285e1a,7a17ff81,dde1f50,8586273e,40bd531d,7f1ad451,38b44b15,33327a0b,15fba2a3,f70989e9,1c271b1,461750c1,5044294b) +,S(4adae425,86b0b95c,fc26159c,6aa0b1ee,dbbc936c,83fd6056,f2b730ec,14dc17e1,e6d0f9d0,bfec452e,3f2f9b39,4d73c72b,990f9683,b6004fa3,8e8831b4,f46f9d4a) +,S(d296fd2,926eab53,db70b1d8,d5c999c5,7eb36987,62537954,2074ae12,af5844f0,b4472b2,c33661db,50b4370,e0ae7811,b16646bd,3f4771a3,113d677c,7f1c0cba) +,S(1dbf607f,5d1ea26f,ee8e416a,52c8475e,a8363cde,6bebcbb9,bc04cf4d,cd19cd54,832c9d78,60c8acc4,5d00a568,2d28fe07,4952a897,619f8b23,42dee2b5,e20482d3) +,S(12321adb,c5997830,8689b103,ec1552eb,679a3ae9,70ccfc46,f4adab54,f8dcb2b2,92dd316c,bef2864c,bd5002f5,ba052712,3f920db9,44992ccf,1b2f967c,b70d1f1f) +,S(fa2c024b,76460eb7,a64d1e1e,fe059496,c28372c8,1d00cbec,9ea76f62,546642ee,5a848904,a654469b,dc3eec26,736d7677,ceae5fd6,d6f30adf,8c3fb95a,bd8e5d8f) +,S(a77dcc2b,218b5acc,d6172931,91e8ac19,fa4d74ab,4c88b84,775d2f35,3f51e7c3,de872263,4e2ff356,7d9e419f,26ff51b6,c41fbbf,48124d01,8409a516,9735a950) +,S(83d740a8,52a6139b,53b60796,50d64902,9f9fe35f,87689977,66246b2f,91e038a,1c630f32,722468ea,72bfa970,8a27bd9a,97b68e53,12b7799f,66ede01e,9c75b57) +,S(d894b986,d74580bd,84b24a68,eba87e8,32a9c34d,bafc5717,cdc03c22,8758c9a9,f0d68c3d,284574ea,21a357e8,cad5fecb,90a57b52,62f6ee06,1868d970,458d502e) +,S(67b4473b,3f1420f5,a8fcb39c,8671d583,cc1b9f48,e288f311,2af6241c,4190a786,14fb410e,e33f4a6a,3fe5dd9d,c30d581d,a350c756,6b513290,7f3ce97,29310b55) +,S(24522965,87039934,a6927d0b,782988cc,b126b61e,db154f07,18d97d41,6dc8f0c6,538c4e2,a7e180e2,14e36785,6dedb105,f688f1c5,9bf81d30,d92a8a93,d3c5a82) +,S(b47bdb89,b087a27a,663f9884,7ab44a64,43fc43df,bb61f4d2,bc5b7ff9,234644cc,ee508868,402613fa,1a200032,afacf672,9bb3f7f2,43b2f415,383f4067,d0212483) +,S(92eb31b5,79ac7b0f,d32ac278,4f3d2c63,93c285c9,567bf912,584c00af,3be97d8e,518e379b,ea24a823,e725a3a3,3608e62a,7a40aaf5,318c2c,41afefe8,ec9afe7) +,S(a5e06969,cd69f1b6,c30ab55,1028e1c6,1bef12b4,b2c2d1a2,572c3648,fc739332,378a3b33,3db8d289,667bcd98,9a3cbe9f,f20b08de,4047164c,7f4bf9fe,5d1f93b5) +,S(604823c2,f1ab2bf7,eba63c65,610fe0eb,c958e8c4,7f509c8b,42b79934,7fbd9bc6,29f532aa,3707e872,2169a02c,210fa9f6,100c6b1f,926c73e,a3bd0427,a1844733) +,S(1b4bde22,bfef0cb0,ec9e84fc,e3af2e8d,ce7f381c,e9766b1c,c1d5fd90,9a1bc891,ab20347e,3f4c7ba3,2bb773d1,50868756,69865df1,18297657,6c283704,49451f49) +,S(10caa116,2067d668,5371a20d,97313b54,4d79b61b,3bb41a87,980eac97,e82f58ee,7ee4f118,32d9c2bb,1f849731,d779d12,571a084a,4ecbf4d6,128f33f,6af477e4) +,S(71e7f07,513d42fd,5c0ad06c,c96ce17d,3542a4a1,a101e581,f7394c2f,d89e2072,e214ca42,1033650f,e420e574,e2266c23,3897de25,90dc3999,bee41181,db0a81e4) +,S(fcbe392d,82b4859a,2424ecec,dd8cd47d,bbb89d15,ea2b9591,f5ff1067,e2cbadaf,9b06334f,6ae45d74,44b5f09a,995fd91c,a2712ac8,b159126c,8cc0120c,513f0bcf) +,S(a64d9e9b,5c583eed,aa7934ef,a7ad036,8dc9adc1,9437f97a,7a16b645,cf46e262,9357dd,1aef4b07,a376b468,99692754,9ddfe9d6,7982a7fc,d607f02b,8a7158a2) +,S(e634938c,aaa4010f,f4a1e760,d87a253d,5fd645a2,4f85a75f,8eba78bd,d876fcd7,84be5fa9,c11d8c3f,54f757ca,d9ec4e18,86e52db1,4b3cd0d3,97f666fb,f347d24e) +,S(4640245e,23e6eb75,6e0a44f7,698c1faa,33ea4f87,7a52f850,3477ad4f,8ae2f4bc,ca2a72a4,1348d3f2,6a7fb977,d3106710,2494a982,a96c6514,7fbfcca9,1ed2225b) +,S(c2a175c7,badbfe95,cf7db594,626a42d0,1247ebe5,160c58a0,2437fcd5,eed8c59,94814fe3,7692ad4f,ef0f4fd3,41c63f84,b282324e,faafbc59,38d88f4f,eff210e) +,S(b1296159,d0651519,d76bffdd,98013d1a,bb17de49,111e3035,5f7a1d40,3d8d9148,ae3c442c,2dac0847,bd8d9052,a5470b9c,80536fd9,feb5f820,e4c54ac1,78aa44e) +,S(d30b1976,b0867b57,84d5e619,a5a63516,13980093,5a9458ed,59e4a3bc,ab69b7c8,1b1eee49,690de06d,7a71c334,4fc0a647,133f2fc2,99a8f096,a8a445bb,27f5b96f) +,S(fb1c3b4,5b0f6f0e,35b93a5e,ea157e60,134b00c5,38a6e429,301962f8,38fe51ae,cf79bafa,d7c3fb08,49e1c2cd,48a90ae4,af507bba,5a42f3fe,bb1e101d,7f5fb818) +,S(2bc4d2c1,d34c6d41,9d97ddc0,c758fac9,ff6489fd,786065a3,61ef442a,fe37199f,5b932f15,9500ef4e,a331be88,7022f42f,5148c54b,30957b0,424a168c,c6d76ceb) +,S(2744c1af,3459c35f,d8e1b27,668ac653,eb25f017,e4fa15d,6c1a6bae,e50f3a99,12f95a25,a87e482c,c647b1a9,f22286cf,3297a354,4c7b575e,aa888dd5,6db2844a) +,S(6429f3ff,d37b53d4,88024393,d3a9dabf,f84e3974,ef60f446,61ec9da5,efc736ee,e8426421,f15768f0,caf020ec,3999e8d3,a1aafcb8,24339574,fe119500,a168016a) +,S(33c132ef,437e9dd8,ee9c028a,2ad51c9e,5a836eb5,4bd97e5b,4b5b6bcf,38d006af,e2527602,e5e74d67,5a5115cb,9a89c579,c760445c,c70d95f1,9ac82a1e,6ca16c6d) +,S(3ac856f3,7d53e19f,f6ab49e3,94da6ed2,c8645e65,f4666bfb,163778ce,7cd910ab,ef40efa2,55d7a5bf,99e39055,8993f753,8fd203d6,7fdfb7d0,81cf8bc7,947cafcc) +,S(5ec9648d,b58770e0,314217e,f090c776,396f47e8,ba27c30b,98c35955,aab03247,3d3402e0,8fb71448,6ee97fd9,15293e53,b095fe03,9cc3100f,21240a24,d70819b6) +,S(54955c84,3c5dddd,89f60de3,828fe4f7,1666d807,ff88006f,b46c37bb,8a822645,c8745950,64b3c721,9eda8253,633deb6e,ac9a7825,8d1de2e6,c2dee05c,f167405d) +,S(e0e845f9,35054008,fa44cc4f,1f2e538,33b58e73,bc6a04fd,c16faa76,c1a92d3c,edc48f46,2a41dc1b,bc604e0c,82d993,edc2990d,f59fa034,11702d86,46dd1c1d) +,S(bdb43235,19acce9f,b95f83fa,485940c5,69108af1,376cd09c,884e6419,718ed14e,5669c5ac,84bacd6,eb6fa8e7,39da1196,dde69170,f5d4e5c6,2ad528,66b6d9a5) +,S(d208bcfd,f9754dc6,7e099754,983fb58d,e5679bda,96d8404f,266c0e65,9e4160ee,c602f6f,f0f586f6,7ac771d1,fbf9d807,c2edf68c,a2c10cc2,314221fc,cd3007ee) +,S(3cce9096,450e620f,29b2446,39e8809a,39000315,a887d6e3,da141ed3,32b1c30a,db0ee91,b8447860,18289da1,11b3bb62,289d21f5,2aa8f436,562e982d,bab44be1) +,S(6c351350,d0fa9ae6,e1723848,33e654a3,f3f655de,7530d9bb,59d92462,1dcf8253,2e5ea374,7a368904,e4cc663,feaf6f92,4060dd70,95bab9,ca2e0773,4c48df83) +,S(c64b42da,d63cff5a,ec1eb168,41fead6b,3dbcbd97,f6786efb,5336da16,35950d2f,73706863,cfee031e,3fee4be1,9241cd94,42c24f4c,c57faf70,f8ff8b81,f094ccef) +,S(c4b99a41,7b2277a4,159bf3b4,859e36de,399862ac,70ffb482,b92e1b11,99c748d4,6ae88f86,1ff14b38,b545ec86,1a808c5c,cc78c3e7,91b48f29,350afe20,9efdc33f) +,S(eecf955a,f1ae50dc,44b57715,5ea67ae,1ae39cf3,fd306eee,e943908b,a7a42a56,26c9e114,22cd3db4,b278adb0,8e4c16a2,1a4c0a9f,b837a493,6cbdb70c,65fc5be) +,S(454ef33b,402e3a59,d437925a,b62100d0,974abf69,8803c04,436b4d2d,5a5819c9,4a38e398,1e1d9809,72df7faa,b06bfa96,20fe213a,36ca0227,c7c20ca9,2ef31563) +,S(50f11935,c20dd410,7a2cfb65,2c94e39,8df7d985,c183259a,70f6a04c,6ac5734a,aed27454,75f207b5,dc1e9f4d,f8cf1108,c9507b03,d0e889d8,d33ebfb7,3b10e670) +,S(43bfd366,10b67773,a254a077,624c2b53,4d8ded30,bf53e918,4f10e597,e2edd980,fd0655e2,e6b257ee,a249a5d4,299146d0,e08653cc,cef19a88,5ad6b33b,ae8f345c) +,S(7ad3c8d8,85cacf19,ed6aca96,4607f344,91448d7a,651fda8f,2446686e,bd06a9f3,9cb921c2,3e338436,73fa1bd,101dc4f8,a9a714ad,7fb91057,dd5af779,835000a0) +,S(874346d6,9cfbfc7a,2e13c605,baa69c5b,d39bd69,36841594,1cc50cd3,18c17380,35326549,dcc29eba,4d35a559,e8f2f0ba,b4d94ada,f2c18612,a45c9c90,8d99ef4f) +,S(1001f64a,23afdd92,789390a2,bfde9ae1,d85737ce,3e5087cb,b1bf2d5c,fd0e6943,184b6a2d,ebd086eb,6e04db54,2146059,e6ee341d,1c8854e6,e57345fd,5dd237dc) +,S(659607d2,68695906,fe752434,a229c309,60b33825,a41589d8,6e663230,c1610fe3,77005570,df191869,38a56d95,4643d991,486c70cd,3d5c336e,11a9667f,fd8f7862) +,S(eab041d9,67f89c37,c04bc6f5,a9059d69,a53e5fbf,ef7c17e1,7cef48d7,e346abbf,a2c2fe6e,63e38c06,477d2821,d22b4a0e,4edb0b55,cb1d9fdd,6cd01ebb,d8fa51c9) +,S(4ff2394f,377db94f,e96f51da,d7364407,ed6bc1d9,3822f24,91630c3c,abacda99,4a77b936,a42493f0,d739afce,b769c7ec,cc0d4720,93e839a4,330054db,22e93b31) +,S(7952c74d,e0576ddc,c85f42e6,24937e98,1502b2c0,105b69bd,4e35f59f,1c2847b2,e7159304,dbd9183f,3abde60d,5ad65ab,5a4972ba,19739b65,1d50c056,ebdd5b81) +,S(b3149a8e,f602b6a3,c69a769d,893d561d,c7438a74,bf47c2f8,ba07941d,b0dd214c,99e591f2,2f8da0b0,c9d7024b,c82d1031,cc4336e6,bf1436a6,bf03bc11,3f041979) +,S(ac3bf353,ce672165,a7e736dd,632c7018,1e454200,77471380,7b875d3e,c81ead58,78def098,2f0f5936,5f5c6519,1857463f,7376ec93,f15c01c6,980d352d,17a40195) +,S(9edcef9e,d26ac408,61d3fdc6,66e09068,a9b1e05,cc23202e,1d0b6e03,faf546de,b1387281,71de9aeb,b02b5290,d3d56d63,b6c98c00,cecf8b0b,540f70a3,79556f2b) +,S(fd48622e,8dc91972,7ac21c30,c0fb8d02,d8cfdead,dfc39a22,59853e17,5d8e6d26,4bf26514,204912d6,8bca0ce6,71a967d9,921bb882,33099b76,7a056967,3fd42bcf) +,S(e6dc2ea,c28def67,78b0a351,6ef0f4b,104fc7c9,88a03a46,8cfbf207,ca0ae0e8,d1892329,e77d5770,d9a84e59,c2d6f6e1,db6de419,87c5e3a0,ea508ea4,a11b3762) +,S(e8ff8f65,559128fb,3fc52650,ba063717,cd2d140e,ed3fc4a9,10dccaad,bb0503db,f35c361a,8ea9b3a8,139676c,3ff31cdf,5511535,7859e5f9,3590302d,bd21e21d) +,S(2e18c597,d4e4a4c7,d54bee9,215a1ee3,d149dce3,25cdc4af,f62a3da4,1922c2bd,3e8595ae,4b6cd57b,7f685a75,87ed61a3,281b52ff,d76e9126,4a0f0666,701c5354) +,S(589924a1,2cc867c5,b2289f81,2d93f324,c2df420e,3c948bbc,e74b6bb4,6d30f262,f9bf3d02,cd0001c0,bb9558ff,515ee86f,e39d4357,fd39cc3c,8ce73c75,72850466) +,S(ef55eae6,4a07199f,1a3f3463,5007a8c3,8d39db17,48af39cb,584d4471,d3d32e18,9d31abdf,91bfedda,3c1f02a,aceea672,21d347f3,5d355042,75452c91,5f4b19b5) +,S(7a8f75a9,41182eee,49883295,56588c86,3021548,70ecc05b,31b83a1d,74be05d0,bda4d0ac,ac72ccc0,c07270fd,1c2bba00,4cc9ce5a,fc927f,6d4bc0a9,b2fb4a64) +,S(330f8a4a,582dad9c,159e0f9,a47101b9,223fed7f,896679e4,f764b02b,3d1d9eeb,50695f30,f9dc9c75,6df20cd9,aca3a06d,7199c138,4b3ede52,2dfa0816,31fea2f7) +,S(6dd34c6f,b89722cd,182cd5b6,a0d83132,56814bc,7ff147ae,668618e0,30bceab1,8998216e,8ccfeee2,78e5c0dd,e206d3b,1fe058c3,990159f,be3beb2a,2a97cd60) +,S(66c2d4bc,1e1ee63e,75481e23,1e6df60b,82c73758,36d4c9e9,fa99a576,304ceb8,f6871e84,fcb56780,682bb226,a8d2f46b,89cf516a,7aa0de01,2ccd981a,b739244c) +,S(560ac5cb,b9a55c0c,8bd6a36e,9dc90922,9297a452,b83f8db0,e0899577,cdb8d04d,b6255568,4574e609,ab7dff47,938008da,5b11adaa,480becaf,287f2216,cf1c7891) +,S(a2377a79,e597dffe,224988b1,63ca63c6,67827b81,ccc645ea,cc23ddb2,2a1503e8,7663e301,4dcdbd71,620ff660,426581cb,7e723605,72b651a7,103faf36,480834bd) +,S(fac987,e1c77065,bb1eeec0,fdd92f05,5d10e738,befbb155,152bde06,87c7fadb,c6fd2faf,683f4e87,77a6166b,59c4b93,e7f5d803,fec49ef3,29e1a4ee,9981e803) +,S(81ee9f52,9b5c6b11,8fc6ec23,88f3ecac,4120f8ec,d134d22c,f809e2cb,1e88a490,e8bba906,3a3ba848,7bdf4a82,c5014493,40da0e2b,fda93fc2,b6440b50,d24536d8) +,S(e6439a0d,545c7431,cd8321ea,420dd3d1,9932427d,475df712,529bfd17,99dbc4aa,6c86e739,b6d0f23c,d3570bc1,86fd9e1f,e617fc41,8089f2a9,d42d0b91,2b4c8d39) +,S(e08169e0,f7362908,a0d207f,bf49a44f,5839c76e,7ad80a74,44e7d24b,573f0bfd,948ce18f,15ef6e2a,23f2db47,db402d38,2a4a3cc3,a8a3756a,c382cba4,f608283f) +,S(5687e6f5,7b2bacda,eafe58b5,94bc322e,70c7afe7,884ab4fa,4d46467a,7a8ba729,994d9091,e432b4f6,72e7f711,b5e0a7bc,b07fae10,b6e05ca0,5a088cc6,e4d89d80) +,S(6edfc830,82a178b0,d9160f4c,f0b01004,65c29bea,e3c29d31,e3826aad,9fa1979,5f4c6676,3df8ac3c,4490ec9,fcb0695b,e9c0532f,df526e83,f27ad47b,5bfff2d9) +,S(28128135,a17d0e29,4871831d,2542c2e6,80dcd79f,6b4fafc2,722b7db8,4ed449ef,4f7e515e,b5c7eb7e,415d7b02,83ff11c4,8f3f3ce,a724c476,71d02d1,50835702) +,S(f55371f4,2d617023,dd5542fa,db9a9127,c16ac04,1545db5a,a18cdbb0,cca4cacc,d0c795cc,54057d47,5bd080a1,acbe6881,3263f593,917e012c,dc1bdafb,920b3ec2) +,S(10fffd7d,a62de848,c07b50b9,64e3b31,ee6a13ed,996fe92d,565cc54,fd0b7c1b,92107e28,5319ce07,61e5f212,5724f2eb,fc61498,f838717c,6637c7af,8f0fee23) +,S(a6a73f68,bcb103c0,523c8f28,f14fafd7,5b8d399d,617a68d4,6ad0a1c8,6f12a46c,d18efb60,37f40a9f,6567c993,24f3a7a7,543fbc30,feec0252,87dc862e,b22fa279) +,S(2984cd0d,5c4f1c06,3854d233,6cdfdca6,50c94275,975feb2d,1b0b5bb1,c7dda582,41b0a86,8064dfd6,5c2653b0,27dfcc75,50eb755d,7c1f5c78,b0c13493,acbb4db0) +,S(a701d075,7be9ff89,67c67622,dfa8ff9f,82f7d5d7,814f6c29,c73045d0,c5b16589,ada61af5,62851c60,66501019,70953ba6,fca0d99f,42378b8a,5059ceb,2a0835f) +,S(f07463c9,c37479e8,259a32a,a2e8f283,27cc267b,95aec8c1,1242a092,bf4c47b,1ae9bb16,e538ff69,1e9ecc98,838e112a,a2016657,c7af104c,ee92471c,df6cc136) +,S(fdec5a71,21a17f37,b4c2e93f,56d910a1,788d2da,b3cce509,b3e2f3cc,f141043b,a62e32d9,336fcfd1,4bab6cf3,26ee3f31,4d2ad023,430768ae,8f093408,e3505d90) +,S(be32f9cf,9a13d4d2,652d122c,c0ce07b,da21fc85,52c0808c,23dd5a5a,9ffb3599,a4a73b26,2b5f8239,e8c279b,20f79c71,7ea47a64,1c084f52,f1bd4f3d,dbcf9c43) +,S(735a1f6e,2575ee01,9ebee00f,a4acbcc5,93bb6572,c4db9505,bf96a2f,43b66f38,20b1c7a,99c6cfcd,58b3f00a,3f9d7739,f9cb682d,946b33c8,879f041e,15e198f8) +,S(a0b840b0,6d92eb95,4f029204,1229b9f0,f1838bdb,4ead7432,4d8facd,70f7447c,383fa2d6,47d88c1b,fc9b04a8,a27b3a99,1a22b82f,7c99fce5,5cf30855,ed1c22f7) +,S(3e54abd4,36a9763e,52b7f46f,4955a339,6db284cc,77d0b351,fee7a568,e4774c83,1c64ede4,fb372325,dd435f71,e4dc914,391da9f1,ee08a21e,2eb5ec18,2834b0ab) +,S(24675c97,67f69242,4e1d43e3,1c46ecf,b418fe9b,3fcdb495,822362b,2a8adcb8,9e38e08a,4359dd9a,a9ddf4c0,8fd1147e,c70ccf1f,8855cdbd,49f44dcf,1edcc36d) +,S(16e0176,9f5a5c0d,f6db88e7,fc95419a,96f836f4,f8255a96,77ca2710,2330e317,30641d0b,fbf7a1de,24c72692,b7032355,6996bf3f,1b541dae,d6ccfe8a,f847646e) +,S(a2e30015,a53829d7,c95d5704,3d6dac44,bca932b7,d4115826,c602aae6,8e4ef847,33ecf0cf,e81236c4,e8fb76e9,645e4827,9bfa617,f6d2760f,dde2b110,77da6ce3) +,S(cd9bcbcf,b7338c75,3fe393d2,2e2e44f8,45a09b83,fe4ce29e,546f2a58,7d7422c5,7683e5e7,f990e09a,e15902e6,c57b8db9,e2b1d29e,8d3bf33a,f90291a4,616c794d) +,S(77a00bb9,6abb918d,774a2a4c,3828fa5d,c7d40bfe,aee10091,f5d92cae,cdfca277,f3febab5,3310a2dd,5dd7a5e1,33572b3a,83950172,be7e4cd6,fec7575d,10142e02) +,S(be2f342c,ca1f161,d15f98cb,ccac9f2c,806c6d1b,f34656b5,c671c730,bdae8efa,c9c7a70a,88ed250d,6a7c0307,d3dd907f,ca8b399d,4affce18,e988ce5c,e0efb5f8) +,S(538bc08,c3c775bd,33edee48,c96c6fbc,1435b0c,f00aa42c,6c15fc7c,5540dd6e,9d8b1293,14283325,8d676a92,d479ebb2,c5ca171d,a43fefae,74c7740c,7e956eb9) +,S(d5e26827,fc0d8283,ee020376,56e83ae1,3ee306db,92d0bba1,6b3fd99c,7af15578,b41d4816,b9643a41,c4f8c5f,4121cddd,d7eceeea,9f2156ff,676d6d2b,61b7d210) +,S(7d18f6e9,95f9077f,c371fcce,729835bf,aa903ef6,682404da,bff6949,4b7faac,1423bd83,89410b9,a2cd8c3d,3d13b495,d856b103,eeb96e64,8c258ecb,a77d581f) +,S(fcb3cd95,fb0b4940,bdf0bd4c,ff534d94,26489c72,953b19d0,cedce320,6e3eb556,46043aaa,3d1ce85a,3009911f,763f49bf,df3d7fa6,347f5573,4c6c36cf,97f15702) +,S(a0e8413e,f66527ff,12f6de1d,2ed4eca4,6617064c,afcc4e98,495f2694,34492800,ac640fc,e3d5d094,54ee6811,81f8bc5f,3fb1bac6,84c8c572,b24fe3a8,66234d13) +,S(fbf60da6,aecd3cd,9137b28c,f7bfe541,efe60e65,52470f80,e301884c,1e9cf33f,aab83f4c,9d9e5ed9,ee35be7d,33a02bec,ebca4f40,8f6fafaa,6f385a89,8f7d846b) +,S(771c8d7f,73bf2b9f,4f032e7c,daf17c39,c375ce1d,2e180758,fcffd82b,26fe206c,af22f29,ac2ec5a8,ecb69e2,aa954f49,63d4a58c,2d6769b2,5255e9ae,2689f756) +,S(a30bea5b,4a911ae8,de11a310,a9cd3616,54143337,30aa182e,ba75601,3d12ab80,aad0f1fb,a9a8d6a5,71301b1b,dd11f4bb,161c26e5,3d3d5143,ad2678f8,9960029a) +,S(55d93940,b0a76283,6aac5bb8,c04f490d,e7ad8da0,4cee090a,e1f381e8,5c13fd27,f1c58d73,b90819b,bab9933d,60f54370,7a625449,d637f01d,bfcd6b44,bb467937) +,S(f6b03260,ae0373f5,b2ebaf15,1a74369c,22535844,13ec4356,ea4a9a32,f2132f81,4fd750b3,7f377f97,7b62580b,6ee7176e,a720a434,8df7aa86,642cc6b3,963cfdaa) +,S(80f7aad4,3deccf41,cf4540db,97150bd4,f4665ef7,72bf6c4e,e551c566,d11d13c6,20a9b836,67cbb397,aadb1211,fbc9a78e,2e998354,6f263403,1d844e7,b95766aa) +,S(4f574d76,130e2eac,16bd6b64,85bdd2fc,88855c3c,68a232b0,29560509,463f0c90,33dabadd,62ec0192,9fc3ad15,587150e8,ead8518,327207c8,7ad2a7ec,c712d268) +,S(41b6872f,f47a0d4a,764ab086,764e1844,a8b4c775,cb2bb06f,643a7c13,5a633e6c,301d54fd,d55c9204,4d337b83,ff17dec3,3faf0bf7,ddf7b5c0,afc8934f,65d54e17) +,S(9f4c75f0,cb44460,ad14d416,76c8b60a,1ae979cb,1ff6a506,b5523cee,8acb1bbd,253d8a0e,985fdeba,1ced50c7,aa3724ae,79c75c6d,7c82315e,65f3b579,5fcf70ec) +,S(25db3430,667796c3,b5f3ec0a,cf4f11e4,73518ce9,aec19932,3f0c5adf,e32f4a87,cce88dd2,ec02e348,ba569fec,15a3c527,ba580e44,c32f25cb,fa6f99f2,a1eb4250) +,S(fa71cf1c,2312c228,c706a7a0,2dc3b9e2,f571b468,913b9cb,3fc5ed1a,faf730d,156df61d,752533f7,afee2781,30763eb9,45a6198b,a78a8288,f30e381b,a809eb61) +,S(f5d3adb5,6d77855d,8e0d0b71,300e620c,f96a45f1,5948d97b,affc3ad1,7226294b,95fea642,5be2e987,968f54f8,f3fb30f1,e9a1ba5f,57b68b1,101a5981,a47f9f4c) +,S(907eec9,6db952f0,eb7d0436,c47f5980,dcae53fa,ebabe57c,aaca00e0,10361460,1cefe286,19dfb7f1,969c7618,e0ed4775,e23527df,6a214754,4cd066a4,65f92468) +,S(abbcec4,36e06bc7,bb92dd79,bcc5d9d7,73189ef9,2546dfc4,54b5d624,2c96e8cc,d1546a38,1f335077,ef40473d,baac9c37,66aba23b,8040c4c0,60778d13,8603be7d) +,S(42f1594f,b1e088f7,2020b68f,7fdd9027,b9638619,b0320410,fc4bec4f,4fbdda76,9a417cab,515a08fc,9e7a7c64,7029a457,9881caeb,df8430bd,c1712af1,3c6b02ba) +,S(a4aace90,751aafa1,fe3e14b9,ead1d460,e1cf029d,cc82afb2,4d169248,e63f83f,97ec83af,dbf32c34,df9cafe7,de0b6ee0,67460d5a,607e1ea,fd13a96d,51999d54) +,S(ac7ef2c9,56b41a0d,824999ca,550ddce0,83f2aba4,8f2bce5,644a579,c0e248c4,d97b0ee7,f3a109bc,bd308b3,e4d4ce2e,c1a65878,e7e5939a,76c9d8f3,6959c5f1) +,S(e9cb9aa0,ab09aa1c,18daf08f,bbdd0457,25d4ac95,8607a88e,5bb14c1d,61d826bf,a1cc215a,124e31c2,e426e337,89736101,b739a56,b6d4e139,ce65272e,2e4b9a5b) +,S(885de0dc,e9700b34,9e10dc17,68f9fe12,2672ed3b,ff9d20cd,93b98e38,ebcc67a4,f66a36d3,75272f66,cad46fcc,cc5d3df6,8c023da0,1ebcf766,f4dfbb0,60e1eae) +,S(8ad4ade1,ff9a19a4,fdc89e75,e4cb61c9,1485ebce,b1e4c063,ccb8001a,c5038e6b,e02acfc2,19c22881,d38a8232,fae54d82,e0b1fb77,e6b8b741,890357c5,be261ff0) +,S(5b395388,a62979a2,b931f243,7f3f65ab,292ddad7,728e67c0,e753565e,578fa354,7e77c8a9,7c274030,b22e802f,f0fd69f4,da65e54a,b50953f8,b9945b79,20fb89f5) +,S(271982cf,eb593e95,17a8fa5,6f62fd23,ddb6c7b3,8e5a87e3,712793b6,f10a2d14,6661cb55,543414dc,e02b3650,8660d54f,48086cbe,4b517092,564188d,6815d2ad) +,S(458be91f,a61f477e,47d7b997,931c992,86281efd,21445349,af820000,58b2a93f,48725c06,e7dbe303,f0c73d43,a5a62b6e,131d004,2bae9dd9,ec12cf97,8df04c49) +,S(763f00b,348c1cb9,e922c6dd,a7e72e22,8624fae0,158af602,457fffc4,cb0bf3c1,8119c3e5,b190c6d8,7f3d7066,72136a3b,d0f1b198,d9f304b4,cfb383ec,e075de74) +,S(4fd5e9e2,77fdf260,8ece7268,10343542,312773f3,2518b363,7075fe98,dcf7719b,c234141c,d3e83309,539aa906,2b17ee35,99a3246d,86ad20d6,2885cfaf,5a88162f) +,S(c578afee,a7e492e6,30ca55ff,8923d9d0,9a6d0583,5553c61d,fe871b6d,e1d956b0,bc2d5e2f,add48f2a,50e357cd,4d4c120e,e744fd96,dca0a959,c0bf482e,2e081ce5) +,S(df02c64e,7a60b87f,73b4add8,5ad93b40,bb6a862c,18e0fba4,3f722650,c0439107,d86dc018,525efc69,cc7b282,cd145650,3b9bddae,607e14ef,3e380d53,c266fe29) +,S(9471f488,84cff3a9,2a99dcb9,4cad96f9,d4761570,c0bda860,bf1b0a9c,32a27a4f,23471d9f,6b3905a2,6d9481ec,dfa10a2e,7c7a5405,119dc8db,de839140,2e063e13) +,S(6d1b5784,f58e5393,fec90c50,a674278a,cb841f46,97da9eda,12013447,a2e0b863,d052c806,2905ef3f,6302892f,48b20497,e89cf7d4,3c345ba5,94233cf8,2586a17a) +,S(94eef4c8,be627560,17e13634,53f733a7,fd590dc1,294cefb6,4d8965fb,3d2ed1d7,49a1e5e4,d72e6a21,14e7c4d0,eb9c9240,b3b988d3,21d2999b,46a562e6,1a203c97) +,S(3206fc87,582d1267,92c2a68a,7400a29f,61097fdd,3ecf4cda,fe495993,87ec15f7,c9a7af2b,88df18f4,fe453bf,fc4af355,519fdf21,9251bf6f,879f291c,32a38eb2) +,S(fcd215,45f8a36a,a5a81bd7,1fb1804d,b3fa112c,c21542de,27cd34e7,f7309a1,191c6b9a,42b0adda,bacffaa9,89bbebea,3424a3bf,11345ff5,2af9c3fb,6193ad0) +,S(4432309a,40f6c71f,cb7fbe26,d6390778,fe6f816,3ee50264,2b2027c4,86fee04b,550981ec,b4d2f6df,fd25f26e,6d65f62e,5e549c1d,79639c4c,d07b6282,2d075847) +,S(7cbff748,7bed64ba,7d6346f9,18e23992,a3712ed,1b7cb89d,a6c0540a,335b582a,ddf155a2,bfb25607,ee6bca12,f6df2a01,98513445,9b353c60,9806fbbe,2d9fbdef) +,S(f8cd164b,ad3e65e3,63368645,76c49035,a95f7928,350c855c,fa534f6,80709789,25412c86,23bca2e9,8d5531ee,d57c80c3,ab01abfc,498cbef3,deeff0e,ae6912a) +,S(6fad2644,990a231f,c27bd678,36ff84c0,11fdec01,120dcc0d,f114b032,1d60648d,6beaeb65,ddd28481,a23af85a,5a417323,350d057e,1a574b0f,5d994816,844d9d98) +,S(1fbf086e,d0adb5d1,9c49947f,d019046b,289c5703,1cf876d0,8cba81e3,7739dd6,86e3511,3d4593f7,a8142c45,8e915fcd,685efd0b,f8cca8a0,79ebded3,f4453acc) +,S(30cc2cab,fd0a2244,2c8a6e00,5b6220e5,4061dbb1,4f8ceabb,6215bce,f5f5b312,b5a1f70d,4a05fff9,9716ac44,57a4342e,7d4bdef2,6cd07fee,b515c56b,19fe72b2) +,S(156efdd1,901ebad9,70eb167a,bb99ac5c,676a0929,3feb0b37,8ba19ba3,6c2a3935,b1d39453,32f0e107,15d06df2,d784b1c3,bac221a7,f184bfe2,4824a368,9ff33051) +,S(48682e29,6b8e8123,c9fb6246,5e8480d5,54350734,bc763757,f319d40c,87f2ddfe,efa5e5e2,be832508,e71b15f5,3a7f1d77,773129e2,e57b2b86,9545cfc9,a20360f8) +,S(d188747c,968b67b1,88958f37,b9990bb3,1a54e3d3,e3fe9e06,7aa9b1a0,87f5e3d4,6d60a049,25660c21,81efbbd5,6a436409,6bbdfa39,b37f70e6,4d13f3ca,6bc76b92) +,S(d7cfeac2,7fdb5922,a5f534c2,b1d325a2,903217f2,ff41b6ea,1e5d2264,8095d3,19618c66,87bb0d92,52133c84,26fb8aa6,4fe1355c,86aaea97,b9ef49fb,de063e75) +,S(dd795951,27b0ff86,94dd131c,e85ca6ef,9aa2022d,d0c7f053,4c83735c,43096c02,caeb4cdc,2633b01f,1b51f7e6,103ede8c,a0ccef5d,e33a8ece,5ddfba8f,736e2adc) +,S(5b2bf207,9a319707,52496851,68aad1e9,5582408,7e5d361e,87b77900,d9c63939,728df41e,69c939fb,59803668,6c44d0b6,f102dc4d,ee146a33,42e1c04c,9b6e30cc) +,S(d2a26a5c,313aef0d,6ac190cb,11c84771,abf97d8e,c7e6e67,bd3313fd,15c2ba11,84a1fb57,1507d012,9d98ebf5,34fac803,5de7a43e,48868269,d5e9656a,773fe768) +,S(22c22c99,860b2b6c,630487f2,5263e77,91b62450,290e9df,379efa7,1edadb52,d2b227b3,dc85c1a1,ed64a7e5,6dd6b178,ce0ab5e,68647b50,1178ac78,4b7d1c93) +,S(b811b039,d2cf5f3b,95e38e2e,14da67bc,417cfd8,623593ee,1f2e924f,d9a064c4,a860653d,ca39030e,8c1ed7bf,aeab73f2,a68cb8a0,5263aaf2,431b6f8d,9c862a28) +,S(59ee23c9,26b38d6d,d6c091a1,d4adcdca,b3a5a548,a5cdaf92,fee9fe2b,c3cc2957,67462318,96e4f107,67e39d47,b03268af,5b54edb0,9f9e8e0c,3f3f89a3,e9d204cb) +,S(cc79ede7,ca5a9ba5,a7c5114,d2039d5e,c6a54db8,fee6c102,577a20d9,18ba857a,2cdc980,3a06af30,c19b262a,12f54132,933ec985,afbd1598,45c40be3,2e24861a) +,S(1319c7a6,2f3959b4,cfee1223,b225c6e9,9070753,a1ad33d8,8f3a8b78,a886f7da,d8a75f9d,b8266ea4,2b650265,6b6c0ee9,7f3598d6,3d149ad6,9a5829e2,f3c29085) +,S(e4ae90fd,74e9b229,b9100cef,1da59b80,753b4f0a,cd7790f6,34930a92,b1eea356,370f1c98,f72e698,73c8d0a4,e76fb117,d7e5a9a4,d13521f,f4902a1b,ed3688e5) +,S(286a98b7,b0b0527c,310afd37,717b5061,467be24f,8a0b5528,52ff26ee,d658988b,d10699be,f79e800a,519b964a,163cffb9,722c3ba5,b56694a5,c1a9b883,b32965d8) +,S(9b8544b3,79746ba1,8524e084,2d15b853,46577b81,7084e02f,7d0cb820,7448f5d6,8421c0f2,ba15f648,246f9cb7,3b10d6db,1de7aefb,fafd9b52,16234dab,8e70218e) +,S(81efaf7b,50a18c8c,2481299,bbd2adba,f3510ac4,f871c3c0,f849ef6d,4550681a,ea8567a2,9c871ba7,fccea923,fe07e8ba,2071d7db,25d33ce7,a6125c0c,2afacd17) +,S(6680fbdb,dab850c9,115d5765,344f1466,b88cc5dc,8de9fab,549f281e,974ed7b,c7871b4b,2690f4ad,1e67ea81,e2cefac2,988082d8,b1c70e67,4389c79a,bc880368) +,S(4c38ce7b,a8e3d317,6f615d6e,27578edc,746fb80e,4701efae,f7557469,a1dce4bc,f6e73d73,61ff5407,10dc9f1a,4bd5c1eb,a7d8c8d6,45f0427e,a4fc3e45,3990b88c) +,S(767146d6,bc1d5bb9,c73321b5,4cf6bc61,e8209703,fe4dddf7,2b3d6089,da60be69,86df7dc3,6894f88e,fe24a4ee,fc78b1e0,fbb5138d,31666be7,97b8934f,d0b9a37) +,S(bffd4856,360c02ac,ee741a65,486d5a7,44e2a005,9db5ef5f,f87b9e18,3adbed20,c11246aa,3bd4ec3f,71f88d2,cb3b96ba,2c210f90,d8234c21,99bf7781,f96ad781) +,S(ad19b5f7,45556650,eb496450,968d056a,fbcb55b6,8852f510,ac96df54,cdc677c0,f78295f8,59445c52,d6ea285,3fe9baa0,5e453bf0,9b3f4d28,6c99e858,62a04bbe) +,S(5924f679,bb94f6db,d8232b01,ca8dfbcb,37a83d24,d0e7026f,b526162d,c82aaac7,baee6567,6a526460,ec7563ad,42482d37,a42f2fcb,f4a5eb7,b37b515,a6c3f1b9) +,S(dee240ea,c90d5399,89d3b3f5,764e0680,1e601a4d,f2c09226,21eb0b7f,bb53ccc6,12668b,72cc139f,5f9fff4c,ef24b5ec,d0648e03,64c17417,f35bfca8,b819316a) +,S(e288a00b,e18b0987,9765940e,caf8972b,1a09f67b,fdc455c8,8e3b4ed9,dc0dad81,fd81e0a5,adf1df8f,42c64825,6b107d44,887d01da,f4cf89c9,11529124,16a1e4e0) +,S(e747d6c7,3f5366ed,241501a0,ca6dc04a,aca7241d,8effbd94,7d3e6a0d,bb6eadb,9954822b,15f44840,9c9e73d,97722194,1eb6a218,ef1ef4f,269ab118,8f9c773c) +,S(57b8865b,ac78b9a1,c244452e,8057be3b,4fe2c6de,9ca9a295,ded04377,2b61aefa,d0e46172,8828f0d3,f1fa808b,1dea8516,b0c30d93,4acc8c90,6ca2bcad,303f06b7) +,S(abda4b38,47ed5cee,7ace4e8e,e652336f,26a8f4bf,4bd610f6,e87e5936,e4e8339b,8860963b,8f266c30,9c6a00c6,cdb44048,a9a1b76,d0a5a652,b4453f7d,330bdd9f) +,S(7f05f2d9,5621d06a,d344bf91,7fa8b9c4,2ceafa3d,fabd0620,bf7086fd,9539e089,298ec6d,8d5a9506,8d916678,dc8e62b3,7b6fb9ef,7967da8a,8419433f,79922f29) +,S(99e4f06b,b8845bb2,12638573,63f7cfbf,3f15570,44256dab,21b5a8fb,c43e2453,5d76066a,86d5c498,323af928,2c3bf419,acb758c9,7883d236,7d9d9e3f,eb8e1417) +,S(ff994b1f,6447ae81,8bbbf97b,8b6d655d,900b04ad,eec06fc1,f57eab70,95375094,6a63980d,3a9324a1,9339a073,977130de,d0fddc50,5b86ff73,464dae04,c3004a68) +,S(3e9af52,f00d1993,8b6205dc,7b6f8ef3,31d624da,fdb2f09d,fd701b78,ed8b0471,a674914c,ac86037b,f0585de4,d867424a,ab9841dc,83c0ca8f,347e16dc,1407167f) +,S(eece935a,e5cd4afe,baca6998,63c5e8c2,e0b338a3,e2ae7dbf,e34102f6,f1c613f8,be70c210,b925dc66,c8546e65,ae9600b4,21a9f668,c3a09a01,8bc5b88b,91cf4d74) +,S(bf10e625,7d336eb4,a962bd97,4cbd9f10,76787b8b,90575250,7f0cfc2e,121d1276,1d93f629,8ddbce2f,1f670326,265c4ba0,f7f5256b,472412f7,a24f999e,f4e1c64c) +,S(73e43284,c80d4ea5,c992ffe3,cdce4149,d490843e,bbac444b,f47ed5a7,3d6e0bb4,82cab83b,c7d2d2bc,87881618,54034d7b,dab132b0,6340b316,964854b7,f2ee3e6b) +,S(5410340,b614b676,63173725,ecf0b8e1,67c2de61,ce999639,be2051dd,2695f8b8,f191ec95,9d6fd8f4,eca243b7,8d844214,976d97e0,65218487,3366ca25,f2e6a091) +,S(203d28e2,694df7a5,6c9b9d42,907c1e02,192e8030,77ead781,8198b2a9,69b127fe,c06fb7ff,2361ac16,a884f0a7,9e4f5a19,b0b5b207,9901e634,be237643,ba93852c) +,S(f9a1e3dd,f53e41b8,84f7c4e2,c2b47131,8d14705a,4e7362df,3221222e,6b2c1921,cd150a1a,abe8ea0d,853245eb,509c1d4f,e26c54b6,98cf9aad,26849a7d,e63b6264) +,S(e82e5e89,db35aedd,4d63b7e,4d55d637,cd2eafcf,f16ffbd5,b0fd1444,c7c783bb,6701a95d,ccae2272,2a834957,e0a4a3b8,3cf5ff19,2f41e8,1619dc46,b8238cda) +,S(9fb768b7,16032fd7,f21315b7,79776882,767d5d64,c9141267,a0ddedb1,55d4ae08,13474a8f,90fda6a3,43e3ea23,e858327,dc2f4c40,4a445f77,4b39b92d,a312574a) +,S(d0793463,ca7cdb50,3622f1cf,90032794,52af3fa8,1866e536,159fd23e,ba6082d7,35301f6b,66858d6a,3e97480b,ec3d2a53,8dee8465,ff5c15a9,1144ede,a208bd0c) +,S(cf8fc191,273383df,f1d703f7,bb237ea6,cb5d1307,8ce8ae62,67fd20da,4d845e05,efce641,3bb676e5,5c0b64d7,589ad771,23900e0d,60feb71f,93270390,ec66ecc1) +,S(f12aeec7,55a7138e,4e91024a,3006db3d,eff6ec84,ffa73d96,da21ef00,452064fd,f0f0660a,22cd7cda,25206f10,e82ca005,3a40d539,472cf41c,b86ed8ae,3d29abd9) +,S(3c40f94d,ab460ccf,c8e47a1e,d015b074,ebfb6142,fbbf5b4d,e77aca70,be67c57a,998efa4e,26df60a6,f1a466f4,c27b2dce,ce6367b2,e05a5ad9,dd71ed8b,482ce55c) +,S(f2fc6db0,49861d3c,a01a6778,22299264,88184967,3802ed49,503857d2,2860f00c,79f0f245,1cc6c5b8,d36c330a,ef8c9c84,95619911,1d4a01a3,d9363382,8b609576) +,S(35d3e3c0,29fdc9e3,88da1cf3,d52df6bd,9ac0ec9e,e591adde,26d3e414,f4fb92f5,62ba2346,6d19ec1b,64d2a6cc,9822feb8,e03df178,3f526a9a,13d10fa7,72de3219) +,S(5628da0b,cc2c0583,902a56ae,711a2217,455bba47,c7222dfe,d60580c6,461b4ae3,1cee8f17,8ce4c7f9,8cf2a2c5,92bf39aa,57616913,bb66f232,a813904e,7b574ed9) +,S(7ec54044,c3fe53ac,8437a540,968e0b,b725e794,a8c240c6,5dac1f12,4ce21be3,f6290891,af9af62d,5dfe10b,d567af1d,6b4b22f2,8177a14b,44edcd0a,be811c0d) +,S(eef7a7c2,a0224a78,aff7c61b,d2379259,7b307a20,bf1c253d,6f03d57f,a8a84203,5c7d6875,905e26dd,2fa4e5,24f73b00,6f4bd0b6,786639af,5d222411,bf69daf0) +,S(3f1e6459,38e4285d,ed30be98,1d149f68,24b264c7,df920f0c,c5d776df,83228cc3,a6a5df53,856be619,25e42d58,2f705567,39c3d7c7,a6e222b8,6385b63e,d1316916) +,S(c83ff186,ae3f42d5,a2c39b43,7712d607,92b9006a,d8bbcc89,97bb9b35,d1663cc6,2380aa52,44674eae,3d96d65,f484e7a7,62cbfa10,96c5a313,9eb4628e,77b72d40) +,S(41d20761,160125ae,c669b1cd,395110bc,94e09a,ffb52ef4,e7e86e,1f4a61a5,c8509f71,2c20aeef,7399d11e,7c438d0e,9b4dec72,76c1013e,a4c76d31,ee5c7496) +,S(cd358f38,d2cb11f2,9fb54431,dc5adee6,721c444a,8fab5743,1149e504,8ba0dab8,e6ab91a8,79a51f40,cf75e405,e508cad8,ec54dbd8,2dd4115c,fda7b255,b1a6fe1b) +,S(d1e1851d,cc95a94c,a8c77b42,5b4430a1,ac10e526,e3f4c6dc,f20267dd,7c5f2d2f,889de789,43c6674e,6bf28470,3ef8867c,8d827681,d2df8bd7,75384ad7,15730ecb) +,S(89268637,1febc520,14709cc6,b2aeb5dc,32e06b14,cdae3d76,b1bc04e7,b9b5dc8e,46823e42,9c0815e,ff99cd7d,f3712f78,9c102af,173b61f,8de08519,f19a3783) +,S(c7341942,420d4e63,263a144c,8a10d22a,fecb1bef,64f926a7,83951e0f,6490caee,925019a5,212e9de7,2e6e2336,c3e2aa75,9511396c,a171412b,53c8f9ff,3743dcd2) +,S(fdede5f,38d83f9f,a4ba3218,fac6f0aa,7c9f464e,33dc59f9,8a3444e,fc0ed7e7,26e4cd3f,3dcd6a6a,211bc8d0,65564250,49c6db2e,9946dcaf,43cb42f3,b0f20449) +,S(b2b5364a,eaedfe4c,f046193a,6777ec1a,1841436e,3cb17c34,9d27f42e,8e536618,32b886d0,f0f94a7f,1b1d87e7,4f2c7dcb,ba4a5dde,8e93c864,f8f48bb4,50d08ffa) +,S(4c3693f4,52a95b79,85e39982,f316897,93d289cf,66b3326f,3e1cc77e,457f64bc,48d7bdfe,fb8c3abb,584db0b,d3407ed3,3e543715,d4ede995,df0e1b8,52e12123) +,S(5cea23d4,927f0385,57f6bc1f,b926e594,93250b3d,6d934a16,9265ae08,24a35e60,5806886e,b01ca724,8434f2f8,be33287b,d9cb3c3e,b927bc4b,4fefbd51,ba98b5b6) +,S(db0a50f6,b4558c10,61a3ff88,1da60f9a,77b42469,a9713c8f,8339b8a7,b903d93,7afa6cd2,57685f49,9635d15c,bb7defac,d6f94c17,aa19be02,4e2efc70,d84c45be) +,S(b0029adb,25f32b75,8023ced1,632de91b,3e3e55a6,1abb56d5,aada032,f2c01ab5,baadabe2,2ebc5fc6,d5dee65b,262e96c,63c99fc9,13277d84,9ec8a730,e1bbfe91) +,S(c336b077,3ce16975,bc204169,8126a40e,f8cad886,6a52c50,c5081ba7,b878af5,6f46f5e7,b82aec01,ad499340,fb90b81,420b4a3f,977579af,d3eb0ce9,c7d752bb) +,S(f403fde4,7232a9db,9efda1c0,5df49636,2137f5c,aacdfc93,1346dacb,d2501451,ba30815c,197de8f2,258c83d8,dd7ed0cc,cbb5388a,415b8629,2cf5c271,2e75bcbf) +,S(85cd71a2,20beec1,3edd0133,6b0b85e2,da056a1c,4a48a328,f371af1a,ee502c30,d6accbba,491c915e,88474b92,bf23c740,2648085f,88a62d51,b26954b3,f6d2d4c6) +,S(324d65,b3c2bc55,d3b2a125,1b673ecc,d26d2b23,e333849b,7549339f,7f0d9a42,83750e95,32086164,e9aaec58,b6a2f00a,3838d76a,208d6453,14042334,b4af616a) +,S(322033a5,c90d7a31,9439c368,b1301f1b,d088974c,91560063,793b6f2,63b401f3,a61f4714,488bd2bc,84bdb122,c615ac94,a7d05157,e6d961df,4f873f5a,582e4606) +,S(a414ed01,691f2a43,b18dbda2,2d3d009f,f94f8b02,672e49f0,58dc2323,b71f5836,2fa3e483,a12ba874,12d709a9,47cdf22,6b96523a,ac7f4afe,c93f98be,f97ec01f) +,S(774310b1,7752d7bc,d8b3059,f7f4cac9,e661a841,9dcb20fe,355bc7be,3a4c65e9,b3333227,469ec87f,19e14e3c,98148b4b,45bde0f6,698829e9,3bbc9313,56e18b12) +,S(fbb23c7b,5c15bbcc,7ad0118b,6826e385,3f6c4078,5342ea57,11109f8a,27dd11e,b12ec70c,9b4c908e,2538f4c6,b0b3d548,ee199f9a,1e9b6535,f1c78081,41664ad5) +,S(4bf836d7,fa7308c,89b075df,1f336fc8,af3c6ce0,64e1253f,853f623d,c483b400,8b368da,424e5a83,48cfe987,93d47a1e,1e9bbeb7,3f5282af,82e12e4a,c7eac850) +,S(91b4a84a,e521232d,71e3d202,49dd1b3b,d134509f,e3e1ed1a,4e8b5062,a438bdd2,52d30545,4972471e,6900afbe,2471e1c9,16c82ce2,2f955ab8,454f9b65,b70ed759) +,S(9751092f,62147caf,f3953cf4,8a117082,37a78b6,5bf0de56,848da1e9,4c3c3a42,57fd0a15,fe069db5,5fbe870c,96d4280,7b9ebd87,33908bd7,49ba0121,a900b08e) +,S(54439284,6f6d46c9,8ac10a58,ac3c34b7,3cc5569f,8f9fd7f3,4e7ad2be,826bf293,1aff0b85,e5b9033d,7c44e877,57513317,a17734d1,13043cd0,780da032,2dc3ed03) +,S(172704b7,fd7f5560,f17cb6ff,ff9a0144,9a05a113,29b86df0,a8d3256,ce139a9f,a416c0af,b170cdfe,169f894a,b10aa97f,2c068a4f,d70a6878,ec9f359f,e8323bea) +,S(2236799a,a82d4b64,5f412aef,eae944b5,e28e0996,8a243ce5,b8986861,6f735dfb,7f20b2cd,af70cbdc,6aeec02a,dae1535d,4bd919c2,631ed69b,9913771c,2f482c1) +,S(6a52af7f,c6f75636,c33047b8,9f0eec31,66bd97d,8df6579d,2e2a441,6ec4fe8b,4eb0813d,220849bc,e0b948e9,a6efcafd,339f8861,eacb9885,40ff8e1,acf1efdb) +,S(8696e0b4,ae3f0dea,bf6d8dd3,854faa5d,d07b01a8,86f710ad,9b4cd84a,5d61a617,67633be1,a662024f,77931f06,38884175,d2c234cd,c4709637,4711c79f,42a897df) +,S(6c4b727e,3bf9af50,fcae1ed6,163ecb00,142d9a53,b6d3f54c,8aa14064,1358ce7e,c4f2665f,395af262,b30561d1,48bb0f4a,f5603102,80f57f40,1506ec37,2bde79a3) +,S(a51d2296,98aa29a9,6d0e5510,f3e815f9,cfc6d492,dd0b2fd5,bbfdefa4,984a6934,861f0848,7658d4a0,141e9d38,aa0e268f,40bad7c9,e2615a37,7a4b974a,6828d525) +,S(1afc4051,cfb5635f,9c2a8477,7dee5fd9,fc4d40a8,3ebe2f89,f36c0b9d,8327288,61ac4eb9,16567e13,d1b03ae7,ad5c3d8d,ef85bf6f,387c511e,bba6c237,96e95f7a) +,S(f8fcde05,5a2a92de,c65d1842,6607a939,b3475abe,2437c5d3,88387fd4,afdff590,4cb8f7e2,825625ba,e3f179bd,4ef94560,6e186346,61edbf48,8ce51ea8,ce1b0404) +,S(cb3dad82,7e7464cb,5fed0cbf,7e29e6ec,112ea411,706d10e5,c1fe6fbc,a04a3e9,a33abaa7,6c9afe3a,a8ce5add,7a2a056,b396cdda,2a002161,3de97556,a0364629) +,S(39d2cea0,acf8059b,a6275a08,ec3a3664,f09cfc43,f143c317,bed8d751,33d4ba0d,6beb4ca3,d3009ac8,881d6d15,e0a29eda,6738befe,e31707d7,f95eacc5,fbd77192) +,S(90bfc4da,3be2d74b,ff9b5539,d0787bf4,4a1b6d7c,2baa14a1,dc6801d4,42187f96,1254e7ee,c8acb35c,fa0695c5,85f61b69,def3ef5a,6219fa97,e3b09dbb,351152f) +,S(50772bcd,454ae992,f97ac3f8,9d8193d5,ed50b69a,b2e62e04,d6a115a6,6e71c977,f199a8f6,f78b0b97,cc20316f,66177383,64338fda,3eee7f0,f36eb0ff,64accdcc) +,S(afe51284,f033bb43,ac6feaea,9520e83e,f2cc1e42,9e273bc3,1b087161,52ea6926,77ecc481,9ffe6efd,33592907,17d22ceb,f4344c9d,f5f5ea4e,4d443d17,25c8aa1e) +,S(b0caf67c,151b838e,4ecaee09,c7908c95,bd3ef86c,797a5a8d,71cb3bf0,3a46ab17,10ae756,7bd2f6d6,712c448b,34636eea,2c7c3d99,98901308,14825b4e,423284bb) +,S(f2766b4,8cac8f6a,80a7cf39,81725834,d186e88d,735fc7f1,5135ce58,43b3dc8c,63590fcc,a4e21c39,50cd78a0,569c0d2e,959254e1,4bf2ff22,8d8fb216,b53601bb) +,S(80d50e7d,28269280,f8ce0dd3,6afb9f43,38df0403,d5661c99,27ff817a,46f60a0e,22fec5b9,7472824a,9b2ff25a,68d947a5,a8952ae,b763f37f,70228978,514cd22) +,S(18114ad0,7097b5f3,7d788165,e45ca1b8,462da0b5,78e5d37b,e4be3632,35d2fff6,87c5f261,39cb366f,25fb6bfa,fcc8408b,f4c69c81,29df3cfe,9190213f,8c15a66f) +,S(3bd52737,68294cd8,73a48831,8f958e45,85871165,c82cf6a3,9126e378,43975444,8c92d391,e39a50f3,4388510f,c8dbb686,27f29251,92ae8edb,b2613948,c01281ac) +,S(acf47eeb,526208ba,8a3de26e,481a86ac,f17f5f88,81d89d43,ab8a5a26,e00db5a5,b451b4cc,8be8339e,4203c913,98b9a29e,de86a91d,3e347688,53442446,429ace0a) +,S(5e39f375,87a07536,86bcd792,1183c424,20159044,a9f66ecc,2bdd552c,62ec35c2,b7131328,297c6995,7df6783b,d9bc550d,5c553e1,30bfc3e,fffedbd7,5e2d003b) +,S(315b67c3,d980796f,6f0a5505,ff2d25f2,8551615d,12bd73de,b10c4897,580371ba,dfaf812f,7525e087,2d11e10d,612004cb,3e2a7024,8c40416e,5020ef66,82d3bc1f) +,S(8f6764f7,73810396,62537cc5,aed6a8e0,318654cd,a95d8695,89fa471a,edd0d7a0,b91cf5db,2994d207,135c1dbf,b9d9d78f,7e3adea5,8c176630,c09140b7,f5c67e84) +,S(e844b948,118fc6a7,eb2f96e,ece3cab6,def55940,75c7b7af,fcc5603,f2012f96,707668d8,89db03d1,561596da,a831aa92,771a0fb9,e1b21273,d11a3415,82292314) +,S(fbbedfd8,4144785e,fa71e234,59973cb8,87deda88,971eb62a,3007f350,1fd0ae4e,51d23941,cf84f121,ff1e6a5d,651d9528,6ef1d803,819ce64,3aba8d16,67ba7dd9) +,S(a0190399,c692b9a,db172ba8,348b404f,19442b60,4df60142,f6330f36,ca6bf352,6ce7491a,b5329042,25556069,71502da1,601e3a04,f38601d0,80b31654,20fb527f) +,S(d240e135,4b9e6dc9,110a6b25,afcf35e0,74fb02fa,f3dbe484,4f46818a,89bca65a,d704be81,e2597460,6014ffcc,ef12563b,45faf24,3e070727,64f341b8,7dfcdb7d) +,S(39bd84aa,f8a15b0b,809888f,133871f3,c40ea5f,2825582,a35fa9a7,808e5e87,94ad6588,658752fc,ce45ea1b,752ecd02,2b621c5a,26908cf8,69c44584,1d831d33) +,S(2172be6e,dccfd021,a56a553e,53f814c7,c7cdd55f,d181d671,4ade45e7,72093142,b21439df,f7229e61,cd3b7c77,fa750a94,660f60a7,53da96ba,d8ca7e20,69abf76d) +,S(57db209d,a40f30ae,fcca7838,2ba525e2,231343b9,250a1b1f,67fad7f4,d4079594,34ce9bac,bd35557e,2f73c718,4287b493,c524a3a,d6b403f4,ae777026,42fd37e3) +,S(845c2bc3,3683d899,8b90a2d5,ff299064,5214b272,a056ed93,63621406,d3a4cc11,44a46738,839b2e3e,1b6b19bc,56a1ff06,7754126b,20654e51,3a1f13c6,de4c6535) +,S(705af30b,251cc64a,26edc929,e3e9ff3e,32ada2e,69c2cfd0,eefce4cb,a37329d1,c0e693eb,94c0c1f6,cf1a0ed4,8c9b13ae,faba8ebd,926c4fe3,ec9071be,2db463dc) +,S(9b2a64df,9b1f8e,34844e3d,920b1af3,14df1b7,78b863d6,f1a6b94a,869061be,5ff03134,722faad1,ab6f87f0,bc3c6abe,8406bdf3,6506b662,6d066ce1,fa6a7cf7) +,S(494967f0,1a0c07df,e7d9a8b3,e6a4ad13,893a894c,2619238,7384e38a,d514cff3,11ba0803,72bc4ffe,b86e25c8,b69ea450,5f6e3b24,504b5e38,210beff8,5d82e1af) +,S(fd547247,812e4233,55c4a977,4dfecfae,812ef2f8,f3fd832d,a3af2ac9,257d50a4,65ed23c4,d776baf4,53faf3d,d3edf65a,5d9935ef,9e22fef2,53319e22,ca4bf51) +,S(4aa16ea2,68ae95b3,2f405fd9,6fa78478,7c369015,4c124733,a07c1953,874b6246,4306725f,579fc013,2cb8c640,7361c7c4,685a2a49,532fa14a,36010779,7f5104e7) +,S(de6fdd33,8b6eaad1,bec84d55,992a5b74,aaca294a,5f804015,796d69c2,cfe67add,e58564e9,d2cc10e7,184d65b1,7e0271a7,f2e59073,bdca05f,ae664f82,7e6fba13) +,S(c8290adf,d0da5f1d,1805f36f,288a8709,eae0b93b,1a7490da,5ffc29fa,bf834592,ff161787,f096e022,f513afc4,e0b84d73,e7f9f347,798e1026,931271b0,8f1c8a87) +,S(1b95c512,815603a6,19750d6e,463d5a33,55f09c22,56484ae9,8f1c76c1,10ed8fec,93b3750c,3a1272d8,bc9e4c52,b5efb6bc,d794c2c3,939bbea6,1848c9ed,423bb39b) +,S(ac0d9939,104bbaf4,d2eb2560,356f2bd4,f1037ee8,397f0703,b7ebfb49,463a22e3,c6e6d039,d6acc470,c1ee1013,722c4a00,4c59e472,11da3025,49351216,f0bb8985) +,S(d8c8f5b6,366c1d29,b2f28f53,8645b17c,f001ae59,71a19f05,fb6ebb3e,9e36faec,5db24ba,6d78e76b,42262b65,e631390c,8540b72a,746cc5b,edc1b681,8b1a113b) +,S(d42ccf6e,6d1c663a,3dd95fd3,c016d535,c50e394,fd63b353,2949716c,49315737,e7337f22,2d353eda,651087c5,13cfea43,96e9cc5e,22aefb4a,5fb3ea8b,579c7298) +,S(53417fa2,4871adb7,6d875c05,8c46065,681f6372,95d221db,ea76d88d,f687b817,d014e6ea,e00c4ec8,ad931dd2,5cf569d2,efb3068f,7aaf5ded,d4978546,1bb31d76) +,S(202e9476,53b677a8,d7aca305,c52af8b9,d33b1ec4,c5ec94fc,5f7775aa,c478f150,539a24fb,211da532,b378f3e5,cdd688b5,c57343c8,2e03a637,39544c8b,34e3087f) +,S(434f1027,72aa0555,8bcb2f6b,1f64bc8d,72bf1bb2,8b972c3a,f6f342d5,f1493f93,a9db9031,f2d1b8b0,e5840fc2,b4534970,90aee2af,5bbd83d2,c14a5ad8,acbf8c14) +,S(a0e54d1a,f09c47f7,cf56d3a5,725d6777,9fdf920d,3c1dd566,caf71666,de7d5d17,87f5db7f,197185b4,73cfc293,7b0661ce,1ea92099,fbb51151,63c2b26d,47ba97f0) +,S(2d43cada,5455b682,f6430cbd,96a2e316,ac0b4b27,e9fb8777,a94dd2c5,81c0e350,bcf18180,1c1722db,1bd9b8f1,8a1989c0,fb372acf,fecbf9f2,c37ec4b3,b459c916) +,S(e5e6dd12,6340f04,431552e9,903ff4a3,c309ea1e,c498e483,e19b9cc1,37418d4d,58d35fe2,24ab47d,93cd53,fba32252,4a3ea9b6,d96390df,25935a1b,dd12126e) +,S(b112e4d3,ff9adc6f,706cac35,195843cf,302324e5,6aa7305,9c8b5f3a,6dd7dbc7,4fe76714,6529e6f6,b0379366,334595be,efcc7cde,d3596ed8,83e3b30e,780dbccc) +,S(d26b5261,ca7be739,95de1bd4,d75991ef,4d357fa2,5c8d513a,e209ac6f,64ad960,5f3b8e07,74e78bb7,5c395bcc,8512f2c0,1b6c451b,5c8d6ff4,18f9ef35,30c6d046) +,S(e2e4f568,eaf2807e,cf43ce08,3146e961,92271bb8,d6d9b24c,e7315b00,1cf04fbd,56894a02,58093a34,22f2ad5e,548158fa,c55ce47e,d00ede05,40434424,4e204b93) +,S(a62080a4,2d8aa307,32255b2b,a239d9fc,19729eec,1dc24bca,67652705,9b1182cb,ae848a12,893c34f2,260c33c8,ce2bcb7,14fb1438,8e6f3f06,d9192549,6a9ec13e) +,S(684c1647,7771de55,ddea8aec,290c1e25,65120fcb,fc8ce0db,4316dde3,f5ae8d91,ba85dda9,44dcfdf8,cfca86dc,ba902675,3d99e751,5719e579,64e0fa0c,3be1f06) +,S(3d730e7a,afa97950,bee35934,da18648c,d0bd62e6,9a49281c,b63589d0,5efbd2fd,c28545f2,3dceca1a,ad0a9c77,23b61519,44a3c984,d57517a7,cf6702ce,f4dbb630) +,S(337c9584,b49a49d9,29b1212d,dee7ecb6,39f007b8,9ba94180,80c9548,459c48b7,b26db317,3e996893,fe1e0797,f75cd05a,2eb23ddf,4806407e,1f173d29,48bb0bde) +,S(7013edd6,f49ba92f,9c9757d1,d3374229,706078df,c2e9c64c,c2e84cbe,85c6b5b7,e850419,7975353b,2863b577,d6f0c392,a8c5bdb4,2dd557e9,8e971114,5e078de4) +,S(9877cf36,bde592fb,5f4a4581,2bc3c39c,68ac9956,23b3487a,635d6e45,89e26e1c,6207d384,737a0d80,fa9f42e0,57684584,efe1fa4,5cd73eb7,bd50abc3,2722f159) +,S(6d35bf57,1c91a2ca,1765ed62,f9b2f680,cbd0955,bc76332c,c83a7378,4bf3eafd,47a589b5,15a88d78,6f94f64d,674182e9,7dd12450,ab3ec375,a9a31d8a,375e5f7d) +,S(40ebcc0f,be3a2a59,968bf6cb,4d638873,5468b532,80a9c96b,639dede3,171db2b8,c2181816,ab9f0d72,c5cb167c,5bbf7e57,9f17d7f4,484996e6,3a23e0dd,5f5d3a8f) +,S(90de4b6c,3a5ccf14,cb033478,577461af,8c347731,9857ff40,79e6ef27,5e557b87,c534bd97,a4af903b,f307c1ce,549a9976,70edb69b,c76ae827,f277ffe8,133cf394) +,S(54e89b59,b73c76b6,cac52433,305c41b6,8f50df66,9b99f47f,599504ee,93ddb110,d307e828,1e89cba4,86ac125c,1c5d8bc,943394ee,222b4b06,f4e3e5c7,b5da176b) +,S(f2ef67ad,60858ac9,fb03ad25,f75f85e2,e5ac151d,95c96967,93ca080,58756f2d,92c0dfa9,372e1e7b,7363f229,2776c059,56742f60,7b100be3,56dffefb,bcda8cf0) +,S(65b7d935,a71dcb6d,eac70b64,91b9fc50,35c63f21,655a856b,afd00a33,52f5be39,b0773657,cbdd3813,8f50813c,558ddbe0,3f8ad81d,e420401f,175bade7,1429927d) +,S(6e950ff,6471cf66,72ea542f,cf05aea8,2c2e1e0a,c2247021,4c78895e,e291ee22,c0ca0886,f0ac828e,21a5c60,776494fc,a6f19e71,741de92e,c11323e7,e874788) +,S(c3b15f8f,96c0079b,471896ac,89d7d11,8ea1607f,18a20627,fb18e1ff,24ee3c1b,33a033c6,68e3cff6,414835a6,ae3f89f6,643326cc,7e149f56,99ab4fbe,d5f506b9) +,S(9e333d9e,1c022776,da901c19,e6936c3c,1af45491,a93e9405,ae343c54,775f36b4,c6734e91,3d013610,6c77a1d3,ced1babb,a6c6723e,316c3fd,34a7911f,cef616d7) +,S(398d2109,4c0baf8a,ab63ceb,6aa6b64c,678bbe86,f7e01b3b,8c0ff291,450244bd,f1ffb185,112ee219,24a1702,183f9075,471611e9,54fafb4e,36f6acc8,4ac7acf7) +,S(8f99c7d,553ca4ea,b160a07b,6d457058,90634086,80c709c,530aef44,bce43c8a,52a15e23,2e90d233,211d707d,5849e214,1f56e8d,189783ab,3c09f37d,b86a776c) +,S(8d798338,b2774399,487fe227,e2d883c8,39698301,5f01bf00,d154f4f9,296512a9,7cb53de9,9303a6be,9aee01eb,3a5c115d,eff0e18b,2cb5e852,75e9b7ff,53e35666) +,S(c9d6aa,ff6b648d,69416bfc,6e4688c5,cf13b711,29c785e7,3ad1e04f,ba02be57,9fa83446,5405aa0f,332a6aa1,922e3fcb,90de108a,db01796d,9045d423,ca0c2632) +,S(f736cad3,f1264671,f2e79bc9,c21551c4,aaa5da0f,befc1928,b9e7fab1,f59c8c5c,2ceae81d,16206893,b3810abf,d2aedb5c,55b79222,1346cc9c,908346e7,cd3e661a) +,S(7748965,7c1fcd79,60fa4a8,36feef6d,835f960a,d3b85009,7462a71e,8320a34d,cfacdaa1,2906f705,d83212b1,55475160,e02cde20,71fc5c9f,6a6d59b6,8e100aa7) +,S(279f43f1,e26ebe73,34924bae,563a0e34,e5cea7f0,eb9f5702,129fa6cf,8b0c67a5,eb5a49af,bada9830,7ceec508,70a49027,7d1cd6f7,6f332249,b2cf2505,82a2a828) +,S(cfccc083,9bbcc7d3,5ceca575,3b9148e4,ddd4464,5727cf47,26f33d62,d83a6a03,e3cc09a0,9d26889e,c969c734,a3361dcc,d638b17,608baa1c,e7cbb99d,a5bc23fa) +,S(e60b0451,70c2e3bf,dd627fcc,5eab1218,d3d598fe,a41f6bf1,dace1a35,2daeb287,a493847f,4f1d3bf,9e90c022,851bb652,691af15c,f4c6c539,bf2831ae,9cf8f2c8) +,S(11875535,ebc90fb1,eb7a08ce,90dede09,fa8cce24,b3911fa6,44ce8111,8848b433,2fb1757e,38148919,bb197d43,48aa536f,c0f06f9a,859ef737,ea50b1fd,82968ce) +,S(c69559b3,75cdaea3,56003ad2,3edd8ca6,c415868c,a13a30d9,11d4c694,f5822179,a39427b4,914b58fb,dd35408a,67ace872,8c299a39,278335da,9228ac85,24652906) +,S(625ff5c3,1e951b28,40f431fb,4842f510,8b738722,cdd52c4e,fdb495ed,e42f1f7d,a3eb00d7,4eb30337,d3f61ae9,d595996e,c7d5a3f0,ceb39f23,3df0f5ff,43298d7a) +,S(1e2fb107,bbb46666,8c31a927,3ce57baf,fd1df905,3fa28286,196a03da,74327c2a,aa882338,5261bb03,a8d8793b,c8f98330,97c22731,46ded3d8,966b16f,337643e2) +,S(d0cbd747,970ab0f6,19e5e4e7,78709399,b65b3f14,24a084b4,a2dca8ab,10d76ebe,7b5f778a,94d3d75d,57b5e979,3de246bb,f36669df,b7dcc24a,ecf4e153,2025b73b) +,S(ab4c057c,a40b84f9,10142209,a5c173ad,6ef31616,db80bd13,61959f11,b739f9e1,598f12b3,4695bb27,ccb2fdfe,a0911ece,eecf2cc3,1063a3bd,42dd100f,e93c7ced) +,S(f9c11e91,2cd3cf06,d31e4795,40c703a7,4f5f3100,8e6ce299,30d5f08c,7307276d,f873ce74,bab3785,156468ce,3d6a8cbf,c532db23,2a0a92fe,91d290cb,ad08713) +,S(2d95744a,79c4d234,40e2f40c,a83cd89e,61576686,21293dab,6716072b,2089b77f,a25249bb,9dd8a94d,44576a4d,7ed800c1,9adc5e26,82874ea0,5d63bcff,2f6b2704) +,S(3bec0dff,e9a96bb1,f3cbccf,cc96ecf7,e1335b1b,86f13b63,6467fd31,5cc33abb,e31f8a49,dee2408a,2d0b9288,4e381379,9fe404ec,1d8b96ab,39413f82,52b85b5f) +,S(23721d31,616051ab,60287a0c,2b4ada42,1bf00825,127ea0eb,1341beaf,a207fedb,8cafc4b5,40e6f3a8,6fd1b546,87ff8c3a,fa2372e0,24696071,59b6e195,f633b169) +,S(ff8e494c,446cf1c4,bd557615,a4a1ce2,b8d25bac,62a89929,993cfd,51d45099,113e1b98,555ddb77,b8680eff,c57eeb96,4038de04,26a05289,8744f8ca,4f3ef028) +,S(f170cfff,f158e368,81cb677a,c9d9512a,3c1705c4,850d5a85,17a66636,7b0cdf21,49512fe4,3ff0f91d,b9ab918b,808ac11c,b5eeb4cb,ed905f21,adce5e4e,42ebbf7f) +,S(e9ff6261,d6c05d6e,4e35e373,57fca0cd,3c3ea884,4a33e504,df3dfa2b,a524d158,4969683b,9af581c1,963525b4,e8244e5e,6b7e7e48,f85c1fe0,1e9f0dc2,c66e591d) +,S(c1c4879a,b614ad86,cb64d15e,cba92aaf,4d1c7742,76d6aec3,4b59f731,addf6cde,6d7185b8,fc1b99be,383a7a5f,385a08f,d7125e3e,f72f93c,25063bfa,d44abeda) +,S(deb0c036,3818a101,ba38a657,5c0db8e4,a65f824d,57014dea,1c110387,7bf2d9ca,f658d43b,f0c106cf,6b45e552,3fcd066e,e754180e,8510b58,43708b5a,b40dbe32) +,S(c4d4164d,f782df0,f5366667,83e5aa9a,8b05c7c6,91c47a49,14798685,1da3fc9b,6c394d4c,3118c8a1,30bea2,2396562f,6dfcf8cb,8f0a91ec,20a43bd1,548bd80b) +,S(94d83b82,f6db0da3,f1bc24ac,8c5bdd0f,6e89cf2a,bafd33bd,2fb3ca87,9cf63a84,9e8658be,59d64a28,7cc0cfde,1f35b83f,e3e098dc,6212afac,ea234437,2591f2ab) +,S(9de3fae6,e6934304,a84eed5a,58e077b3,76da7310,61859847,d6abecfa,fa650dba,7e4cd395,ea8b90fc,20850be2,4ba8dd83,e79dbc4f,4efed68f,504eec04,f9bcb212) +,S(251869eb,7a567c9b,7866c9b5,a829206d,867f2092,8f3a6fe6,46ebc3d5,2df7d99e,bd87d706,c49690a1,9e0ad77e,4b3b8f0c,5efba7e1,2a448a3b,b4ad3c7d,44e35e7e) +,S(e92e5aef,818b2980,43227673,3d15021d,c84192d5,bc9307fa,1add63a2,8e888a9d,ba3a3157,96ab2051,ad53b5e7,a058f700,ea90e40c,c5855712,d2176a0a,c232f94f) +,S(b6a8a783,c2716ba8,9a37c7,d7022dbc,25fef8f6,76c676b8,267038ae,64a33258,93b09e15,8bf081ab,9e69c4c1,6d965743,cc08ad85,a8eb248c,9c67043f,fe61ebbf) +,S(26e95f26,7ee205ad,50dcc75d,82330877,394c56c,84546cb3,72fecda5,f57c2556,dfc935f8,63840ca4,71bed804,d0c2d14e,c9528a9b,ba1e6f25,6545311e,5cae673a) +,S(6c1ed40d,dd086dd8,2fb00bbe,d969ea90,7e363496,97c350e3,2d0074d3,3e05bc13,854d177b,5593cdc3,ab1e4903,c64be02,2b6b0cb2,25c71390,9316faae,a235b269) +,S(a9286b2e,81030401,c37d69cb,1e73caa,b1c68a4f,4ce1538b,11ed850e,67d11aa9,64ab5453,c3a1166c,18f35115,1f031117,e29b1a31,237cb2ba,51f1a873,529766fb) +,S(a2b862c0,ca02cc3a,e1bc5737,876f81ed,83dffeb2,4e6954c7,3cf97bb2,50050cc0,db3a03cf,d704f98d,dad8f48c,5861988a,1caf439d,b50c196a,32289622,b9a49b3d) +,S(19259392,58c25edd,953117d1,fc7a74a4,a9cc2fad,892255e4,fefdac84,4784c917,b86a1bfc,b7bc8844,abe424a5,b7409abf,26e8ac62,7983fafa,70dbdaef,43a88eba) +,S(6b85864b,194b2cfd,af1d6550,4960370,306ee34f,87c91187,230de0de,42fafd09,54a9ddf3,87458a54,cd305e06,61dd43f8,3911e88a,db6f0256,d19cdf15,3ab4b388) +,S(407cbd77,b88e6d47,60b07e26,f53fefd1,2b98bed3,5403c693,e7ea33b4,cd74b5c3,eb73a1d0,fd122265,dc880cb2,920b4eda,610ff1cd,a74660aa,7cb91323,e5485d60) +,S(f65cd6a4,594299a9,6cdb5f9a,7889cf44,62cca331,d3329f7c,43ecb224,d58c817e,8c906c4a,11925697,9f84722a,9440d2e5,f97e483,542658b6,8538aa0b,f10f5572) +,S(2ea38854,775422db,43eb69b7,bbd47a6a,b8ef1694,28753fa8,8cf49c8,9efc6e63,bf6f2d21,2b21c740,a25dfacb,bd22436b,5118f1a,2004bb90,adf580c9,6f21f1e6) +,S(f2bb4814,94677f3b,6af8aa4e,6a3b1100,c2e0e99e,289536e7,eca3e61,a20793ee,a3a788bb,2a810267,9a3d98f2,6a9a2740,91a3a29c,234043ae,aacc488a,67849762) +,S(e157c4a2,84354b8a,73d5e5ec,58dc1ceb,2396ca3d,7f651e6f,4547aa78,99899daf,f06970d9,5bef3e0b,e2bd4597,a1c96581,275c9719,605f63f,9618816d,669a0bc3) +,S(25aa7f3a,3a14731f,c7fa3b81,31a569e7,4bf32c9e,3492e626,aa4a4316,f263cf12,e5c2e210,a8a75180,31778f4f,4737a0dc,bd1a1312,1dfb40c5,5c435803,4bc3eeee) +,S(73ba2208,8cb96b2a,c23dd2a9,7b3cfd2d,c504ccb6,24c2dfd,5062f8e2,bcc442ee,ab9d3a1c,6bd762b,9cd866ab,7abc0e1,f898c567,61c7071a,d64d5233,caec0ca5) +,S(da94893b,3e73246f,6a72041a,44c7279e,dd8d4d3d,55b20db2,eb0e08df,4c5837f2,6949f652,8601b0fe,e572ac03,89fc3530,6b2d09d7,b59c40c7,a1a607cf,51684006) +,S(908480b2,35c49b11,12bd6504,5b3a8e13,7cbd4820,3046880,1688ed05,abb8b7b5,8a887f57,622a7482,3fd40b26,f58ae7a0,18d2d03c,d5ed31cb,93a529e3,387fec7b) +,S(682d7401,31c966e3,2a8bd150,27fae9f5,4452fce1,360c449b,1b20bbd0,257d58d1,ee7f773f,9d074436,685a2fe7,21b1b829,9369f543,dcac37e9,9adf43b6,4525c19d) +,S(c8661c4e,dbe125bc,a31e7a22,83aa0f9a,b4b3ae70,8512fab2,21bdb4d3,8c89fcb,30299a17,16d3fe04,7f48627e,36195b21,e6800d4d,a26dcc63,96c7fea5,8f25a2a) +,S(5112b1c6,2b88e704,f0d2c731,834019aa,d51a108e,1a8614e4,f6e62f68,d7372b4,1bfb5f8a,ee37bb82,5494c9ce,651d32d8,d47e5a29,4b9123e0,7311f260,9ab4053d) +,S(b9214d34,49e16aac,b90f6704,ee589f6d,8fa45126,be235e9b,61ef3ebf,2150eb99,c9465341,2dbb107b,965d177f,de11bb25,53e8795,69814d17,34ee9ae5,267529bb) +,S(94185601,f959999,1999c919,82e5042f,b7e68583,533f9569,73788d5c,3a087b2,5e51c755,de79b6d2,eb640039,a4268d3a,601750c8,dcd0a942,eafc9339,6fa36c98) +,S(3cdad3b2,2a707d9,90fe4228,adefc934,e8c69a9a,8a4cbd87,844a6ff5,a073f511,f6de425f,26e17045,5589e22e,7824dacc,f8cb8561,832db31a,e8fd2910,558ff9f3) +,S(ca986704,a0d1935e,1611e176,60394d00,7d2aa1cd,cb17357b,b4a557e4,f5a4b5ce,8d527934,a73f2b0d,b3cf571a,ac53b3de,11ac99d4,6ba995b7,5a09195e,b10bb5f0) +,S(f5920156,3ec396c5,82fd6090,2d98ac,2d5dcf5a,cd37e651,a1e80c43,f76940e0,2e821f19,7e27f927,20230f1d,9e26dff,5b3d977e,4b4a6cc6,7482f3ec,3cd5523) +,S(9ced8c1e,bbe0d213,b396fb89,8aa8c24d,870d305d,e9346239,b2cb0315,c883cdc,79367b21,4a2e21fb,1e9b24d9,fed6a0dd,b377534d,4da2b501,6999ebf7,f77de2c) +,S(5b07b283,ca262751,4a10817e,bdfc8044,883f4de3,38cae14f,de955f18,9713dac5,b8d6d9f6,8a71aec6,3b7bb44d,1d2b678c,75ff83c6,37c254c8,3a14be30,a5957b5e) +,S(4c2eb4cf,3fe64ba0,21297b8e,321cac6f,a8245614,45848933,19453052,69337386,35ee2473,1830eea9,85171af0,96b6bc0a,72f3e83c,6d83f8af,8ef1131d,c8b52c8a) +,S(5f24fcf5,f8c0bf43,43b8a0e,b3b6d8f7,2901c902,6d43f8de,4bcb1cdc,6d5019cc,87c2a306,138265bb,59b2b2b5,6992fb37,b2ab28d4,ff4909f,d6067e2b,4f312cfa) +,S(e26bda51,c385a875,5083faf5,6a915944,3eb351a7,88e1597b,f17649b9,b23ab8f5,35d66322,ba25896d,2a14a0a8,a3f5bf91,d3ceab49,9b2683f5,db7f58e,68ca1071) +,S(ae5be06a,b1ae531e,5d2338ca,d929b5a3,4c283035,95282aee,7c3ac259,8196bbd6,f4f486a5,bf11191c,9134d522,62ccd692,cc5c6686,c9013ed2,782b816c,da416d25) +,S(d143463b,4661a173,6b88f274,6b3c20c6,d054683f,9efa5221,ffd3badd,14804880,77b28055,7aa11d3d,b2ac8de2,c9c5757e,d0c9b0cb,af6fca3d,bb295bcb,c3ff8afa) +,S(54804f7,28ff88d0,bf6fb4a8,a24d4eb0,ee5379f9,30f890f7,8e31afca,87f23343,79288e99,a38accc2,c59ff29d,9da5df60,42d63089,45900378,c40dd765,2f0f5626) +,S(68c21fc9,93d41345,484cf5c9,8aa93bf2,25fc2c01,922a0151,cb3e247c,f130ba0d,9c435478,23b9d8bc,2e8ba0f3,8f2b60dc,ca5b6030,eef51c6,cdd20eb5,a02c6245) +,S(2f50b870,96b2e15d,6fb35001,cd8f95a,875cea3a,edf21a2b,c433b254,7798b856,44b09dfc,e0b8d522,17e7d9f2,9bbc5d6f,9886fe9e,3e360688,8d7c4e70,c3bea0ff) +,S(9d054954,f0c22da5,f330b3e0,69310a93,66b72129,2fd3c98e,76464796,847d16df,45962d48,143c94b3,57400130,d3e050a7,4defd464,223ad599,e6aa947b,12679a85) +,S(31980b95,9f51a6bd,4cfd9a11,b86dda39,af66ffb,97713ba7,3edf8c10,462d5685,d0a02979,5b45ba4e,7464fc47,7a09a90b,7265f5aa,e6b0d655,fca5828a,837c2840) +,S(e9c0615,f0444234,1f522d93,eda33b29,8951a267,7c4cdcbd,fa02a63c,a57d1ed9,7aef87dc,7095f483,5ebf2b3,156be9dd,ecedf54b,1b0c739f,c513ebda,5c5f296e) +,S(fec8bd3f,f19fa6fd,17523af6,27384c7c,6c92fa85,aeab8bf,bbdd2178,89b12650,d01a278,6ee8f9db,38b1ceb1,a3fb1df6,b631c0a5,23e92460,d0d51367,1098e414) +,S(2094133c,86322dd7,ee1abf80,2ddde826,e6385342,6bc87510,dff63f3a,b94f54eb,efb2ecd2,13bfda3a,227b791e,c24ff627,17ab559f,1bd289b7,e7db992f,d941e850) +,S(a34c3385,ee882646,b44bfbf0,f64225b2,fb86df27,c616a2ba,6cabbb68,cf36f3bc,e99bbaac,57c9f5ef,c64c6687,6f2bd6d3,b9ec8eb5,f9227c98,9a768f34,23e91422) +,S(df09dbfb,564515f3,a6d86e05,dca59a0a,c353746f,b291d9c,add27d68,6810cbec,90738e50,6bead3aa,c0cc4a2d,cdfb8529,5e752945,a7b2e357,1a99c901,49017c47) +,S(df9817de,89526a26,c61e4294,f245ce06,8b5e22a6,4937d5f9,6898b9ed,74078989,c4db6e86,c6a44091,23227adc,345d6eb7,d2f12acb,f2df3b44,978a1743,94072f15) +,S(2e713387,7a0419b3,7bf77874,b24fd0,7cae9fb1,59919a50,223437b,7746eada,5dcc4c1e,12502573,b0520817,16fa46d1,8ba43ff7,e7f8c8cc,e3c141ca,6176f805) +,S(99826364,f0061305,1ba033ad,63b95884,97158ee6,9542d06a,f2f86d91,3bea7a2,5f109254,24af4592,2ab30701,464d504d,6006969e,30a9ce5d,76a3b115,6158c6ea) +,S(19222e8b,5fec6d2f,33a35fca,83c3b9eb,effb9e3a,f2ca9c53,929fe5f2,a43bcd32,c79b4f98,4621b2c1,d627dade,f01fe761,8af239e6,b80c23ed,a2dd1b1b,e750549b) +,S(e0ea59f8,6b7925d3,ad511280,8b1ae5ed,c0acf6c6,d4ed0846,d870a663,5573970,bbfa69be,ef531b32,5272ee02,8c880178,57ab2a32,65b5a6b5,38ef81db,83b5de52) +,S(7df189b7,c29c06ab,83f7d849,58ba3d1e,7da3ebcb,feeb9dc4,64b60420,3631fdd0,88e00d45,8287fbea,5c14ab33,6a879948,e81d9798,cb82054b,772728a4,4b69e56) +,S(42b9867e,7cde3ef2,b4b73f3,e4df7504,b7f06cb0,67aedabc,16edb276,97bbca58,eab47aa1,df9af0f5,40d1c6d2,ba7edcc6,fd436f56,c944c872,1e1f4958,63144390) +,S(9ffd9a,5535bd30,a697f61e,e6fd0ffe,b1a7e5c1,9459bd3a,708a7112,3a3da54b,79fb0a7a,8334fe38,64fef8a7,60610920,af2741c1,fa41f582,37e92acc,29644011) +,S(13ea8e5d,1116a57f,8b223a5f,79c750de,6c25511d,558e6878,e92cb134,7b81e393,a41efd37,d35ea994,8175d989,cde449d0,e325b40e,a247edd9,e8f4eef,e6a4d283) +,S(110d401b,d7a1a0c,e484fdb2,34cd839d,5e40cad8,6244cdee,5c4f2ba3,ee1e2eb3,cdd91a5,4dfa47d2,98a46f15,c021a38,975ca108,f2653019,46013427,349d7ca) +,S(48a9f1a2,fe29b05e,d419a14e,8ed288de,46affeb2,296522a1,f2407b76,a8f6b040,f1c5ea7,887c029f,67202b41,198113cc,f1ba5617,79afc1eb,db0e10ec,5b5d2a91) +,S(d8c4d9a,feb94e7f,7b831464,77aa4e3e,a48b6af5,35015941,4047cd01,1beb7176,fb8af9c8,da06c2b8,8787793,bd19d7ca,6cc64508,7713af45,4f5fb4c7,eeda3c2a) +,S(34e84417,2f5ff4a2,70a9064c,d5994327,9cefde94,d295f424,2c491efa,bc1f0839,2da40cc0,5120e4e7,8e84435f,895a3ed7,6c507bda,4d16cd14,b602deb4,366ff9fa) +,S(ea802ca2,f07a4348,791b7df8,99639d06,c6db8d15,74ae8441,b29c2d18,18b7a6c8,ea475a0f,5f74e6fe,ccfca44b,ddc38a4e,3cc19c49,e2bffa49,a9572146,6338a155) +,S(d80542c7,a7be8da6,6346d867,4154f65a,b1cc8e94,19299d81,6a5c874,f25ee43f,5e85d69f,b5c72ae,bd94b1e4,67e0d30,df8da61e,4150f4ec,e3efcfae,78d88d25) +,S(bdb35e49,7c1c0d1d,7a120366,cd259e7,31cb253,1bf804ae,f0c82cdf,561d0c0c,2675a4ee,aea6dfed,8597c08a,69fc251b,7bad9869,e83f485a,73dd1638,605915b0) +,S(5174e27a,9a1eeafe,6411f3af,b627223c,db0da11,6bca0ac3,d39a3080,815e22a7,b1223046,5f58d183,fcda2603,e4593398,51ed87ed,6839d9b0,4c845459,daa3d5bb) +,S(c8b1299b,1b2880ee,7720ad03,62588349,44bcc309,6a7081eb,ce10ef20,ab1f6731,ead86be8,85584e4d,34ac18e3,d787031f,72feb217,694a32a0,76f2f88d,a04f3440) +,S(fc1378cb,c42fd6e2,f61be9bf,e60bb2c9,b36c5a0a,4aefef09,c8287a3c,f1310d31,ae4ff85e,5b22d2fc,914192d6,28324d12,51ffc469,1ba8ca13,f8347edb,5a9170d4) +,S(7c0bf943,23e7c1a,8004b23c,c05327a4,d4127c7b,eed27e3c,4a825e41,5f3c3a6e,30ad62ec,bd19f80a,a9dcbb5b,145d18af,3248eeb2,1d14e648,d7fd7217,f1089728) +,S(2ede5f01,232c0409,34b07b70,1ccce3d8,27f85ad,2a56c987,e29cd6ee,d841efdf,24cbe9f4,69f036a7,6e140720,f65817dc,847e9562,4820dbdf,b8a1384c,8d39bdfc) +,S(decd1afe,faf01eee,d2dd89c,bdb9711c,4f1899fd,437d0371,55cf74f5,9aa0858,899d1c8c,49b0b3a1,89a24445,568becb1,d3b1420d,ffb2c7a3,8fc291b,258f8ebd) +,S(1dacbc1,4be6e70c,4043f5be,3f972d36,3cb456a2,2ee1b1ce,3e207578,8233a79f,fc3b04b4,f502affd,37d71c58,d6f1a61e,b126cda0,e156608d,7f2ab786,e0734486) +,S(12ad0f7f,cc7cddd7,60cc6a3,3fd3de83,b1ab0e3d,cca013a5,68d5978b,a176cc19,b4e0cf97,335b374,661f6c21,46aa7315,a2c4f6f2,b839f88d,5376e256,99e6e216) +,S(f649bb96,e477a5f3,f852dd31,65496c07,5e14a85d,fa929794,64f1297b,d56fd1c8,46e37dfa,7eddec82,88fd18eb,9ac200e6,79337296,e2cad24e,d67f98a6,2e61d040) +,S(34f5e5a1,248db96f,a165950,a9b74392,acda22d9,95496808,82760daf,642c600e,a8a6637d,a1cad7d2,f72fe1a,df67eff8,49d0ab0d,7e06d7c1,a11078aa,de9dc733) +,S(26e940f9,ab45caba,adb1e4d3,23e5cf70,575c44dc,dd2f0b10,1540174d,d2aa715a,972aeeed,c5fd01ff,3b04f236,c799039a,9c7fe6f0,db1348e8,b97dc885,c57926e5) +,S(e3ad36a5,132f1067,503498e1,ed4b315d,4d06cc67,3a9207ce,47224497,12f51a4a,4fa719b7,37cdf1b1,cd5b963f,16a47e6a,e43dbe0d,490423de,fe5deecc,5baf9e8f) +,S(413fd0f9,4e231525,1aae9d6f,61aa0038,dbf7cc03,10c81185,394c8cc4,8b721a9d,9281c5b9,ac1f56f1,50776cf4,69e57118,8cc6989c,ae41b950,f72ff25a,d6de836e) +,S(9841a473,600446a5,5ce0ab4f,2e77ad12,bc2abc34,1e607241,c0c61d2a,d87148d5,7d1bb113,ee4b5199,95231834,1e05d87f,f9bb355f,df958410,3d161969,1d786f4c) +,S(1d4cdc2e,3e06c052,69958eba,f00484b3,36594f9b,be1ea98c,2382e608,cf78272d,6cf5d126,766fe5f7,75bfef7d,c2d91b48,66d4bff4,c8eb4e59,230d1903,16ac6bb4) +,S(da74f388,86de9c6e,36227258,758111ce,3b9414cf,cf8d5cfa,bcd9b3f5,44f1262a,d9231255,e3d9189e,a8d0344a,80978b83,3f1afb57,5c799f01,8b4ab73e,866a38fa) +,S(b2ebf119,46e37704,e1e12345,c68f70a9,a031c0b1,e85c0833,c5df9c0a,b836a6b5,c1652832,1666f0f4,19806a4a,86f4aa8e,46fccb4c,f7b6493e,26d9699a,9db2bde4) +,S(9fd899da,eb6f84ac,edfdeb4b,fbf8b521,6b5757e8,10d22d4e,56afc38e,da747cf,2daef35c,7ef36b82,d6158256,2466895b,9656970b,4beee8cc,2e0b12da,83d7af64) +,S(eda65e56,9cf07e84,19d07f6f,4aedd24,3c46df2c,bac92772,bca7edc6,ba17b217,1f394c99,b48348e6,fb709e5c,b4b4b77d,41eac2aa,bea2a4a6,353d1982,a9985281) +,S(78567d1a,1a96df56,299c9ee2,1d916472,303178b6,9b18fb00,a23c10e4,f093ed5b,9321fb0,6c5d2dc8,52e64d6e,453d9923,bff7c626,efaf5e50,245b4ff2,64158f23) +,S(c639e1a5,90f5973f,148e96f9,15c94d8d,7c7ec36c,bdf15150,83503aa9,9ef5636e,3620e7fe,faaf7581,886776e4,f7391599,94ae3e2f,2a59d4e1,ad6d508e,f4db90d4) +,S(73ef6655,c49894,7aa2b63b,89b77f14,3ac096a1,d7333494,d9774ada,5467b60e,c04509b6,2135fa8f,816436e,6ec0f513,ccbb23f8,782e2ca4,d5eebfea,6a5297af) +,S(bfa4506c,dca70a3b,a8fb0188,e0384bf7,3afbaa0,6818d503,df5015f4,f10cf341,9fc7388e,2edd63f7,9a5d328d,1b949a2c,a364075e,f94c8de8,37cda5e1,7d566ba1) +,S(2d594b,814a9e92,7ac9433f,3400c5e5,1a58457,6f47b8f7,f5f0b8d8,f48b2cb2,fa9a1577,d565b906,1acb9efb,4bf415ed,f264b662,594d1ccd,51baf83f,101183a7) +,S(401ae44c,a4039850,4d57390f,66044f6b,cf1e9fe9,f0f2b057,3f64f026,b6d5f3e6,ed947768,36ce65ec,f947b81,9dedd31e,c8ceacd0,16a40a35,78a592bd,4c2626f) +,S(43f9397e,a000ac26,8a315406,fc9cd047,b9cad513,8a7dab38,2717744c,ec6662b9,14d5bbe0,52dd8635,29c0b0b2,dff7379f,3e2ae95,6c5b4920,b36452d9,56085bca) +,S(25036a12,d8eca48a,78cb5e84,41aa5a53,16376e83,e2ac7819,db9895c4,dcf2a22e,14c421de,dcfdf9ec,b69a24fe,1c289ec9,f4d0f9ca,6f4b9409,35ac9815,a4154209) +,S(30e9c9a0,d9b9c92e,65794acf,a2cea34a,8d56e3db,d5b56205,59100128,26bf8991,999e4729,bca75c06,18f0bf9e,8ebf0455,3460031d,4ae47623,5e4ba182,2f62550b) +,S(a8fb641,fe27c40a,8e410831,fe1b0d2,cf74072a,bb626b19,2fa51341,e99ca538,f3832ab3,4eb6917,3e2f3755,366b2bf2,4dbe257e,eb516e39,4bfb91e0,a63cff8) +,S(5e09a349,98a824e2,f3ffe2ae,34a835ce,6b2f0d28,43b765fa,8dee010,49df7867,20ea03e8,4817593b,931d1612,2d01dc7e,52715fb9,36838de9,d2c9fb69,9c935025) +,S(e62a12e9,d02a5a7a,475dbcc8,79850ba8,340b638b,a5c3b505,8d3c7ffb,c90f0dcd,b075d21b,40e5897c,7e849529,bceec7f1,d5f87881,318c115f,acc99680,31d17f55) +,S(45aa5534,530265c1,c358b529,de15487c,b6bef551,5125e835,e027b0a,a69a9cb6,2e56d88c,acb32ed3,24068fc4,4c03ed2b,1b70392c,9facfc2c,2fafc696,fdb8d397) +,S(7fe3d940,50e2f358,31b410ce,e54c7c82,5eb05553,981f1c45,b136a24c,4d4a4b57,97b0cfad,4f6669f6,efb2d35c,42302e10,87c03b3b,1c22e23,24050399,345165a5) +,S(110dd614,85bedfa6,c09a2e5d,5737ab2,4a5b35aa,40129388,c6ce876f,bd3d9c30,7972ec2c,621155fd,12f0a1cc,30927669,13a9165a,7dab66aa,8f8fca53,7411041c) +,S(7427d28c,aecb7a35,a4100c42,9fe03d5e,6d3f2f91,a5067866,c618c4c4,5fc53547,8cf74ed7,1324616d,bf4135d,8f442ba8,b473ebab,fe981f2,3a426eed,bbbcff16) +,S(9779c811,98040c8e,754b9df4,b547c09a,a9f25410,1ca1fdde,365b0ef8,34ed95aa,148280a1,d26c8ff9,51774c55,7590081e,36030a10,a148c322,3c7379,67d036b8) +,S(41113833,f7da3a4a,4736fa62,ad7b4508,74ef5b9a,b0961665,e30f3081,7d861adf,98399ec3,485a984,cdbb6817,783223b6,59884450,881d2f41,3f4e59f0,ed5fbc65) +,S(f9830e6b,9a9a9dbe,50abcae1,d44d4856,3a92e505,aefd52d9,2259c41f,4b8b14bd,12061be8,5a0042ea,1baa46df,b36d6f78,62c11cb5,b8a070aa,6c6a8991,62ea1c0d) +,S(71284b2b,36a4c8a4,40fdd713,6b647482,bc73d680,3d6d0142,833d34bd,f2794077,6e54f5fe,8cff4ebe,bad1b47c,4e5d6407,44be9171,b391492c,df48bc35,10e195df) +,S(524a04d,a1b7ba04,34377531,99178ceb,7ea18f36,2c300aeb,a8daefe8,6e63e9d5,1c71ed93,861c3b1e,41a7fcd6,57225e92,b2ddc507,4d54652e,3898683,8c3688a2) +,S(e1fb70fd,2057dc3b,c545fb80,eb91cc9,479cada2,93c3492e,260b0a75,4bdc0222,aa799a9c,25786c64,d5138ba2,1f801e5e,88fc2602,d4e288f1,96c8d79d,7bad2278) +,S(2bf126e9,8302e8cb,407570f8,c3fe1206,3c91bf2f,63cdd9a9,3dcc403f,a8592d29,6452a6a2,20edbb86,3ed65ed6,cddd70d2,6b4975bc,e843a41a,10ce6ed3,d38591f2) +,S(faa217d0,1d9f0517,5950dd5d,e02972c8,b2c88076,36090d2a,6f17e7df,2a70cd7,73077022,dc1cb45a,f9e9d056,19635760,66ba7b07,bc79601d,ae7dca1c,a6cdc033) +,S(3d184ee0,ed45af08,6a7263b3,47b12449,a7270887,b8460b7c,6428ae4a,6dc4836e,d002efdf,1259dd8e,ab5bb606,97e8892b,4cb5376d,c26d08e,52b7c9a,760e8826) +,S(3c825a76,29890675,bfdcdb73,27f37c4e,43214a91,c6ddb6d0,f31e13d3,cd26eae,45bc7ae4,649d70ba,99df5d07,92e89130,87a272b1,bb2d6043,dcad0fda,a5444fac) +,S(3a8822a8,d5b230ef,62f657ed,31a12d63,2862f22d,eff16f08,8065981b,ed3e926e,ddca63dc,57ea2ecd,b25e8d03,2868b12d,abe8f7ba,8125a4c5,56d80a9f,9784a04) +,S(d0042da6,aa3b60a2,463e3396,98229067,c80f8924,12d8323e,7482ff2c,53ad86cd,40697e7c,4c5d6c,4ba11cee,fdbae25c,e234ece6,7db446df,daa03025,5f8adf35) +,S(a06e32ee,93d70c5f,a45a68e,2a180be4,7d8a7f60,17d035e,47c94d47,6f3838df,f4bc98ee,c7f50d34,4e88ee87,d8705b50,4cc0fd5a,5bfba498,5fe0699a,df811bdd) +,S(21426073,9f41da95,2dcfa74e,dbcc2f22,375fb359,93f83842,99e3735b,e39b45a5,697f2d88,74cd2249,cb84c9aa,16d20956,f5c40358,9d5b7965,ea4b46d1,9cd61249) +,S(84d52769,327646d6,13e3e1ec,2d20791d,76b765eb,fc5fafaa,20097164,dc9cda7e,d87be4b4,2e2e55fc,8f87dab5,c8c64493,f09b3996,87ef8fb,3a6c653a,a2250cf8) +,S(ca48382b,49283747,d433be3f,ee0569ac,7d3714fc,bbd76157,ac5229ee,ee25dd0,b67165e7,60894bf4,3cc80df5,6e3109,db7e370a,bebc7503,ce20836d,3f0ebb2d) +,S(8a6a751f,816c206b,91e67608,58fd7def,8ea70956,598b1c61,8e0699ce,602cda79,617ea6f1,c7f98cb6,41f01862,1f4c8cf,12a556e5,675765cc,c7bb1283,cc8ed073) +,S(1d035f81,fdc7c483,9936692,9bebc7d9,15fd3c0a,380f3348,13c65527,d82344ba,e4203070,f687298d,af8f6d66,6030f3a0,5826b0b9,31f0e55,8c356aea,b3464712) +,S(d28f1a4a,1198f572,a8130bbe,3f25e585,348a33c,2d73053c,ee7e29de,8a3ce79c,2841bd4b,c46c772a,57018c74,8510fc7a,dab16644,f157d51,9c38391c,4470f7b7) +,S(41c71a1e,eafbd926,4a49ba4d,e976e72c,691026a2,b1773d4a,88670b4f,d9c57fb8,c2b198e2,e4557f8,41203c16,b511d61d,b39e8a67,21b776e9,865158e1,91ea5ac) +,S(3f0ae72f,b1a06f84,803ff8ad,fa0e5c76,ed0b596e,d52568e2,6fe4aacf,6cdbc3ee,69a9dc3e,a0ae93b0,6c4650f2,941ebe38,fcd4eba2,fc9cc0b2,3fb9c127,81c53f78) +,S(b59e2f6,2f01449e,d6728b04,e9334f10,54c4c8e2,db4a422f,70566b55,ba4d2e5f,1b6b73a5,7444de3f,4137f2ba,722e70ab,e6a785fe,1ead6fae,9f2ec5db,299f00d3) +,S(42145fda,e72df9aa,fa3c20ff,cbf11a0a,d357515e,ec6846a6,5cc6ffd8,8fcb1347,4a34e518,c9d39736,3c88ad65,62ecc0ea,2652c6f,48955852,99a0de0b,5f42b6) +,S(17a085d7,8d8013f9,b98a8509,aad7553f,bda81df3,33aa6f7b,2457a74b,c83f6739,412d9b80,efeca81b,29619ca6,8bdcdebf,7cd253c5,88793675,6a379655,d10df76a) +,S(f5ec770b,2e0d0afc,7b155abe,bf310270,28bdff39,a08d113f,b0409624,e7049ae0,e9ce5d46,2dc5d255,a09ba37a,a7a5edcc,aad29ce8,6f9c6b58,d2781e81,5d88a25) +,S(45e3976b,749279e4,486d2db6,fbbc7731,168e7311,d7d75f62,b754839c,2fd17918,84f0c079,c0127eb,d1064724,927459d9,ebc22eb3,502a99a0,e5876e15,29c8845e) +,S(df15c304,378da361,7f821d07,d00d1bdc,189fae9b,7aabbc71,51c2117d,8fe0c21a,589daf,cad5cc54,58544b9d,a69dc510,9f8f1e82,866b1076,ff1d229,5942deb4) +,S(c5798ca4,547cea39,75e3b613,911434e4,e5f503bc,9ec6e9a4,8dfe8386,a371494c,2864334d,fb2bff0a,4690f2ce,d1a1d1cd,e3b13f96,325f295a,8e0d4f1b,b13413f6) +,S(773ba0e2,e1a80ca3,9060556e,2fa8d15f,83dfd018,dd226751,9262651c,9765c915,e59a686a,3fd13284,e380188,fa40e9e8,28991374,20c906b9,ae882512,7dc7dc60) +,S(6ed4cac2,e1685eec,16c12251,db5dbceb,90f542e3,854177d9,83ee6024,d6e7a740,2558db33,ab598118,1802a84,e6ed32ae,49c25379,606a3150,6ad03ec0,a5308b98) +,S(21cfc6ee,d98915cc,1bb52da8,e83aae9a,64970d4f,ca3e70d1,6536043e,bfb60fef,8154f487,290cb8ea,73cd147,c1286d5b,9f471665,d9e0ee24,c2be264a,2f1fbc36) +,S(f8db764e,bb8f031c,88921a73,92f75323,7d1f4a22,7bc8cc64,8bcfa9a1,235cdc11,82c25fea,2d0a1e37,e16dc4e1,b6737ee2,281693b0,b48911db,c79c1470,c4e6274f) +,S(d52f4eef,14a5a860,983eb0ac,8e02def9,53f2ba03,604cc60c,80882e56,ad6b3dfa,b34b3131,7e37b973,9559bc2,6f85226e,705bf06e,1fcd818f,d5b88eed,f2d6b7ed) +,S(3e9d0688,b9b67517,e25b526a,4e46be08,4e95a171,f9d99ae3,4cca6c14,66adaf6e,e1938d76,c4349375,1d5b9876,4ada7b7f,57144878,78805540,70b7c27c,9bfa312e) +,S(c74f8dab,54590ad1,3fff217f,b62f43ed,7f42ffe3,6c8fddac,fb6315f4,a3406094,1bd8025b,57dd382,5b5b6896,e90ab5ba,fd31ef46,8f02846f,29f1b1fb,f90302d9) +,S(71f88089,a8e0ac,6cd92e03,b1dafb04,76c0f489,f16def9,75985abd,5dcd02ed,839bb263,7827e6ab,f6941b53,67c9aa09,835c588,3956733c,267fb52b,6be767a9) +,S(983d1cde,7d75d70e,328a8a62,ec82a96d,5174ed4f,c9676e10,7c282be7,bd408b07,5fe2426f,287fd353,173c699a,39407e36,c365c413,76986640,7c12f11c,5dc436a) +,S(3cf9defa,a067fd0f,6b012fe9,8b05aea2,83c332e8,cbc8296d,c777951,9e62519a,3fbffaec,c77d872,7dad2011,aa314690,2806f763,b73b780e,375508a5,c77a613) +,S(f415897a,cf653c3c,26fc5231,f375e28f,c23041aa,af05455a,e81419dc,25546e30,3a9d5669,806ef66b,7a0661dc,cb941531,d81fa7f3,e08fec72,ee6312fc,4a7f59e7) +,S(5bfb64c9,cacbd09,244f3a96,d5a6800c,4a012297,95962fbe,a429b659,8e085eb1,e5c4ecb4,9cc4c685,a4fadc80,77889298,b94e779f,7f462aa2,130ed8b,ccc0604) +,S(61a5a78,a086ccfe,9f54cb0b,750b7c8c,5c8dc4b0,e32f3c69,c65ce4f8,9009587d,50193c13,affe3a34,1ff3b8a0,b37f07f4,b49667c9,f8940311,9ecec58f,a76d8c60) +,S(e74514ed,93784bda,ca6e30e4,da2a9a78,c7c70bf9,42cb4ba6,afdc357a,c694ed1d,ee4a8c9f,7d55dd09,c51117d0,754d301a,cc36dcb,49d437dd,ca46a920,7088440b) +,S(dd9aa58,f2cc4c0a,8d2bf548,6dea653c,b4671e40,c0073df5,352b2a9b,95637617,6478aca1,582a65d2,6c0f42e7,48f06e60,ab85a494,d0129b85,5b5fdc62,7dc7f580) +,S(fd7f2622,665c2005,9bdb8c46,d140ecda,ce013ada,6dcf3503,e28eae44,c2dcd83e,536c948e,5db2978,31e2ab3f,fee860d5,dd7fdd16,645cf561,67e484,f4a62c61) +,S(9635dbcb,b2595930,835598a7,149a8a37,be64f607,c227b307,4d8e8184,c2ae99fe,1b2cb226,bd9f23d,bd243ea3,eb57baac,163f4e49,6272d220,9f436f81,7b6d9442) +,S(642ead1c,c24db5c4,77d798b1,515083a7,7777476b,c3a03993,883a7ab5,e1abf814,185293e9,6e6dcd7c,209fc891,d96f9dfc,4012f756,7d3e2f1c,282eb0fa,5de46eff) +,S(3c5be7eb,3aeab34a,2d982ebf,3a766962,822ddb39,527ab79b,83540818,a4e2931c,a161ecfd,2b906280,46d6d1de,c149eee0,e6c92ccc,5f936a51,e2a4c3,82e555a9) +,S(c1a90946,6c0ea8e4,b60611fd,6c61733a,6d90b0f9,d1b7a761,1f9e3e84,6423bde9,f928d301,b6c27eed,79b8a8a,ba388ef5,24b17220,7ebd7396,5623e60f,f650dcf4) +,S(e49d97c4,2ec1b8f1,43180188,382b265e,4216bdcd,82824a15,3a0e1d73,83207541,8e521e4b,95a1f4b0,934753af,cc3b73b4,7b3eb00a,a9c7af48,7e4e5a02,6234b733) +,S(49f71f26,f0d828be,9e9a70c1,bf768117,ad2fe6b4,6e9f416d,eaf17695,80dccfc1,86f4404a,67e8e6a6,9a901589,d7c09873,eb553aca,41b0cb66,f4767621,76ff0d79) +,S(487d806f,67635c8f,b66afe46,3754a5b4,64afa469,2ca69541,5d91a6cc,8903e853,b610d414,26951e55,46bb7216,6dfb62fc,602b3d20,18c38670,760f55a3,6c45c688) +,S(47af5aaf,cc7b69e4,bc536d57,8f57b958,3fa17666,2d302141,54e3e35b,57357e38,b79a4c34,709d215e,dd3b0fe4,9cde9de5,b45ccdd2,af25bbd3,602a0c90,9834dbee) +,S(84f79cc1,a257fcad,546d8218,5caae7da,8a8d523e,7feabb79,16ad7d8f,5421575,cc84b844,55ef03ea,59913a0a,1919c0d,cde9fd92,ce872029,57a998d3,80ec1986) +,S(550b7e54,3d3accfc,eb488b6f,b2b48d0b,9017a5d4,ed54d55a,72b8ac6f,c83f6d14,91f318dc,ea83ec1f,f43d5172,bba5ab1,7891f3e1,2e162b6b,8c512589,5f2e5141) +,S(f691885b,eece383f,1f56593f,92de0b34,1627cd58,389afaba,f442663,88aa6a32,1e6c920d,2eb76656,63c7586f,7907471f,79e5faa1,b6fbf4a6,c905e422,9a441638) +,S(4e3c52a,96889e52,b99aa469,b5f07dc6,f6720e49,29f3961,fae2c59a,98ffacf9,ba3a3d9f,dccc36fd,a8642167,7f54de2d,4c079b2c,e70b46cc,926d7d9c,ef1978c4) +,S(66720c8e,c638367c,c934347b,d8768338,54eaaa01,a81a876b,d2321e41,40381224,eb595ebd,67c5a08b,24482042,5035ecad,f20fcfe8,9a84a60a,93f3c05,a926d574) +,S(4b01f86f,f9feb661,eb33d7eb,87f940b,74302cb7,449b0bc4,84e97af9,56b79d2c,2680db84,1b233e25,16b74190,fd3a0cdd,b8fce285,ed8577b1,e13c2205,9af0d3a) +,S(dea430d,6a4b5e18,fa04f77b,55f85d36,df9dcd47,87ad5899,c16d2533,74494867,46b1f5b6,307a1c05,f3b42ff,e7a272c8,c63c2a92,19bd2971,d70ea793,5bd508e8) +,S(3f987bbe,d7fe896b,8a8067a6,de49de63,670e7260,f255e5c8,a926b9d1,fb62945b,373b2f51,86d7d9eb,18570d3b,9e48756b,663cab9,df388899,7af923c9,bd79971d) +,S(6cbcf291,56e3cb2a,b0d3c03f,3f4c0283,d953a641,9f7e8655,d8c46566,e3990b70,535c1017,fb40108b,24de2a8,358d217,8e47961,e5f4cca2,aa7e7c2b,339c60b0) +,S(d253488a,5610a541,e4ce2cac,bf4d4901,5fe63dec,94615e80,d795b39d,9885201c,c58ac205,e7323ca8,9bfd284e,9c9bcf3b,89b05571,b84d3afc,d69a9a96,9ae4fcc6) +,S(bb77470d,cf0851b2,29494d6b,e69aeabb,dac44010,17200af6,391cc2d2,352bd9e7,187cc653,b6b56e6e,6c9969ea,705a6d9d,3539d4b8,b8777371,b64deff6,45307942) +,S(438c5a3e,1ede7063,eb928da9,693d7602,809b9e08,e49951f2,6a600eb3,e929ad1d,d2918af0,67d34eeb,d8f179ad,2f3f105e,a5cbfc9e,1f416cec,372a5175,8ae797c5) +,S(35db0905,e28b3e7b,b8c4425b,8d9151b9,9cce6a6f,b6e11561,65b7e356,9191e69c,25963fe,ba45cdbf,5472c046,3da3279a,60a3f1ca,9ace47d0,4c4648b1,52d2e560) +,S(6ef2e9b,79e48447,7532ba0,1b658af1,e27b13b1,f1635317,6b47d994,cf3c6bce,88cc8a3a,aa1f2040,7976ae7a,9bfe09f4,f0c1fb85,72f122f8,4aeee871,b87867ca) +,S(c85fa35,4c064f00,ac39d455,7884f8a6,420c4192,aef2d6af,8afd61ec,2b977b33,3d17f849,6ba4a79a,bcdaf502,87fa5fe6,15d2c24e,58f27ab2,7cfb2d86,140a5f0c) +,S(7f47028b,4e84f4a4,21909f01,85df2743,e3f18f1e,134f90ae,166c4089,a9d44803,4c025c2a,c2a1af49,fd7e1e3d,2ddab9ed,104a0e21,17895fc,36eaf9c,7a550e9d) +,S(6ecc57c0,5c7f6b98,6cad9c94,435664e,3b036ae7,325ea091,234ac216,3dd0e324,67086288,9346eaf7,e6bc8ac5,25d60d5c,41bd9701,f5cc5f58,7995fd6,1c75def6) +,S(46a2a28f,61fbbf15,c3afacaa,e181f527,2b957bb4,7f127465,fc03d021,76359328,88b36e79,2c071ec4,adf1a34f,a3d1114f,f9813f91,39b2db5,83320bef,134ace83) +,S(a2072cb2,e25bc045,fe40dead,8fd3f7d6,449f8d7b,57adeb47,b6ae9b7f,7d6a5b2a,fc019c0d,8c9263f3,aed518e4,44c1e5bd,dcf796fc,7d16cc6e,c90c4c59,7877e36a) +,S(fec203e9,60d4ead8,e3510545,3e73999,1ce5234d,a92a20f1,813414a3,599874c5,118cddc6,fe918be8,d2c5483e,c985aaa8,4d708767,4af70444,1fc0692c,b92a540e) +,S(fd166bf7,a69d80da,6e03c740,2ce6f4,a05f1df4,e2a131a,daef89a5,86f73681,1e3f6791,7f2d3824,ba4ef07,86ed8f08,c65860a7,e6913fd6,8cdd759a,2deabf29) +,S(a479787d,b514baf5,b46a578,6a221d72,2eda896a,a7fc1e43,4817f125,2bbe0d6e,1a6f7857,92bc5fc4,e2fcd87c,6b82ed34,20426f30,a9c6fde,4f09ae14,9ce426a1) +,S(7aeeb17d,f75e9c7,2dab575d,2ad1cf87,b3eedf99,8df4b14d,d42b50e3,7895f041,8060c0fd,5f903934,d47f3886,8731ddfd,a6fc1355,53be9a44,38418174,37b79fbf) +,S(6dd254bb,63c3fcc9,a5d1758e,90c0c6d2,bb1a19ae,788b351d,191d0261,cba75c76,b00b5cff,f3246b0f,ec835345,1d9df948,4fd903d2,e278ac2e,59d8ca20,647c2ba0) +,S(d9e76bea,acd64f55,9a9c2888,5834317f,c24fe5f6,7e540d27,6233c187,76cd7323,4d079fbd,15ab81b4,f3aed0d,663178c4,33f976d4,f69af7dd,ecf61a13,b831e71c) +,S(b57b26a0,55c4f224,865b22,287c9402,4c801618,c50b00df,33ef8509,a94a0f57,5abc4303,1701260a,f41a0e49,a100da19,8d033179,8b26026d,6401654d,39d53670) +,S(e03c71c7,9d902be8,5caf4df6,aa401a6d,18592725,2f10be1,f4190b67,bee3bb8f,e5f16a54,ce5772cb,1390e49f,966a00e6,893ceadd,5a753c7f,9d82a2ec,7324240) +,S(b7f3b64c,980f19f4,e4f46083,c1ca758,70f4313b,3c23c5b8,6acd6c8d,57ec0de4,5fd0d8f9,2a70c9aa,bcc1523f,91fa603b,e17fa73,fce73899,2c1d720d,3d55b1ca) +,S(27b24868,2a1b9186,3a1f5c9b,a5010a37,2349c417,e1d7acaf,dd94c7db,c5e12733,c54c23bc,4e17418b,deface22,b8e527e1,4de1aee9,71c921fa,fb3f58eb,e4778125) +,S(5d4b2b1b,5f9e640,bad96aec,6d3bc5b6,169411e9,5dac7346,d1f7f885,50679a14,80f0e3e7,7e8d6c48,62b1f6c9,c0ee37a3,3b98be7d,e1c6c8ef,12759b73,c20a2e3) +,S(790a4189,63c3ec0,ba6babae,18ddb717,463d3ec7,c0b01852,5e760e96,ac5fc2c1,6db8b456,9f2fed97,783a6e80,413d8ff,cd0ac6e,d512f712,4cdacad4,4845242f) +,S(38dd209d,705c3f63,9cbdb0b4,22160943,4ddf1366,56f2cc8b,22d27479,c5446f99,8b793f60,3621f6b0,1b1ac36b,cfd92c3a,7dffb7fb,fcbf831b,1db077ff,7482c25a) +,S(29c6b2a9,24f95c8,58857951,cea2baa0,bee9866d,77b3f7d6,3cf9debb,16437528,c408f565,cc78e5,15a6e0c1,7a96392d,2952e25b,d067a0f2,d2f10eff,b54c2ce3) +,S(19f1ab5,b54c80a5,a32a1fb8,1bb3f389,ebb53641,6c8a844d,3846c2cd,350420c0,38a56a7d,7eaf4155,4f5b8090,c06fcbba,9f516a23,340617e4,dc5951d3,35b75de0) +,S(fa3d2b8e,d73ab5c3,24980054,27830806,3715c17c,7981db6a,61757048,1e1d780a,7bc0b4e2,4cde1ca3,e30ec601,73121a43,f87f679d,cfac6db5,a9bd132b,d6a89454) +,S(908e538d,730377d9,d3585ae,59b0949,c46a6aca,bb04e725,70b189d5,57c26825,5e108800,6cddf00,39f7d855,64252cfa,d4a37761,2b58b6b,5fb2942,7e274af6) +,S(e57bfd8,f38d456f,2e977090,d9f81673,db11a195,568a85b8,dd8bb725,a30d22ec,b5965e5e,e680e791,e87ceab7,156a3e03,dda7e9a0,9a9dcd76,a72dc838,d9e2e6a1) +,S(aabc514c,b88112c4,6e6e1221,d61e2abf,dd7a3bcb,a2c7cb78,4d57dea6,1950534b,96e3d9b3,f3a4c3cb,1473f61c,e224dcbc,a535c90a,7d993409,ed079d32,3c8facc1) +,S(94a800a4,6eb9506a,8f6dd737,ba45c697,4e563c3e,1df40959,4198d1fc,e499d2d8,627ef26,d39e19d,ab4d6bfd,9d4fcc0f,4bb4d97e,b0886426,40b7ca31,952be814) +,S(1022de3d,6caa7542,ddeb47d2,1f82cc3b,6e04170,ed9d4ef6,81b58b81,efd6c3a9,2317f1e8,37716a0d,842884b,cd77cc3e,d6235dae,9fad5661,9f20a883,af459b5e) +,S(9509f343,17c15f7,a54cafc7,3d4275bb,41e39183,53858724,4031baaf,97bed951,dec71a0c,7f8108b2,5e296361,2d6623b6,7b2f6d9c,69d7b6cf,d7273503,fc72b4ba) +,S(bbf19e9a,efbee2db,fbd5eef8,492f52be,2e2f9072,6b3adc1,d16f0627,f4f19d25,d9e691de,f2ce976,c66d806b,f35a2b13,56f9fc07,7b7bb239,30668081,4b52cea0) +,S(b5997bb4,5b359516,b28ee935,e4d59c39,ae434c29,5e5d98e2,2ddeff57,4afabc5,fb6d36a6,fb2e1aaf,d9b5d89c,39a854f4,a3cec053,1e1a776c,b4267b4a,d2bd8ac7) +,S(fb746cf0,cbf2f56f,6a3a99dc,71e84cc5,af76899a,3a7d02c,fb272391,b77c8384,d1e4cf27,57373ab2,d1ba3f2d,d5bf8b26,a74d6814,23a5b16c,9621b788,a51e9796) +,S(644facf9,e6290462,1a5278c3,f4a2ff8,84600c23,69eeb557,bc412540,c4966655,5b5ee0cb,449423fb,67c9b542,3868f7b7,6d1968b,9d7dd751,75e7dd5,2f994b88) +,S(c41931cc,9c311617,f77faa3f,6b6f6e21,bd030c2d,9778b065,6ca105f,cdb8658c,8a759dda,8db8a8ed,eb1f2972,12858879,bb2f49c7,468d8edd,14d28525,ca3c0746) +,S(e8dd9063,48691527,e4f4fc96,2a0e5608,d151aa68,53257e2b,1acb7d94,56f66aa2,470d108a,4180fbd1,2a377517,c5e472d4,680ec468,52bfa472,cc400ac6,91541a0) +,S(6b48efeb,ea6d0d17,346fba31,8fa33deb,301062d5,94b254bb,db6dd28b,ffe27451,94cbae78,eff2064c,cf91bcc4,fe1ae3ef,3d767b63,6eb4720e,35f2340e,87c1e941) +,S(1cb08c2b,72f069c0,e1e4afb,7ea73e48,a33f23cc,cb89fb08,db1b0919,62bedbd4,64d3500d,5b6577e6,6c18d3be,fc0a7dd0,833d3245,1ad03257,b45a31a4,67c14095) +,S(2150558d,bc64dcb6,55224045,6d943208,7b7c7182,3901f78d,9702a736,998906fc,b49e2adb,321e0c49,ddeaa152,9bf83095,762ea96f,6c1290dd,b6ad29b3,c84b8657) +,S(530f4c16,58284100,55a67001,eebf528c,f9286825,fbb60ae5,da4ecac,e3d7f4c1,80b147ab,1eae8922,50bf82fe,1a9263bb,41573617,7dc02e91,fe7e07b9,66bc6af9) +,S(c5158947,8266dd62,fa495d4f,94bbe77,b1230f44,685ac488,7642576c,8d92e6b8,1705fd37,da813af6,2a799e41,3a45a4e2,4d2121e0,1065e692,ec1de149,43be7c90) +,S(e6963d21,b576da6e,6aa6f1ec,da7674d0,d827d533,31e19d85,83ba0e7,31553f86,d3560d2f,91c7219c,76962a5e,3b2aea76,604b5ad4,82da8f8c,419cf2c8,7cfdbe61) +,S(c5aa5963,a249a9a5,9445c0da,9537d482,dcb6ed9c,8372e455,4d440931,3c3f169,7e7f9c15,4ba213f5,981389d6,22af8694,b1efbdc8,18998923,92c9d654,92ae7fa6) +,S(bd04e3d8,5bffa429,81310c7b,2c885f04,69f01977,2819f6f2,5e69621e,5a32752,dc4da51f,b88ed097,b17358d3,da4fb755,254d8ceb,5b0df72c,9dc995b3,8e145d9d) +,S(f8f55476,4418c668,3390b604,c9f9f452,1ef63756,58000c49,d3b8b1da,80261dd4,9943a6e4,1b928da0,fad12667,cc997ea5,6af49db3,8c499a2f,a2343efb,52ea450f) +,S(77dc24bc,5f32159e,7c3b6a3d,168a6698,43b12253,e403299f,b4fa3db8,74350dec,240d860e,c38457ab,6d741edc,e4fd8c51,67f75733,f12fe892,aece4f9a,578c6bd5) +,S(9f238f7d,588d53f1,52da8118,2691194d,99a56fee,373745c9,aa2a3a7e,58d18825,dff57ffa,c2012315,ad6516d6,92902476,cdb2d3f1,58803c3b,4dc854ed,8ba9b756) +,S(92f95782,a59da5c3,a12401da,34c24ae3,fbf3822e,355ec948,6020ac04,3ebbbb6e,1c6231c4,e09c414c,e0d3cbf,9be73bbe,4f1fdd,b3d65a41,c716f0f9,a39788db) +,S(1b40dd47,f435579,1474b560,66a0efb9,88271a1c,19186bcb,b1715196,84f3130d,9fe6dcec,991d652,c9e13099,66b0aeb3,53869f99,28ebc955,6c64973a,4d983b5a) +,S(473f6b8e,d4162f9a,2f40d48a,8827f79d,180052e1,7b28b240,4772fe1d,64cd82d3,743450df,fc8315db,72c01f1b,21c4eea,9c0a39e4,c1e92e33,91096576,37e97fe2) +,S(40cfc629,a550b437,9e0941ae,fa8abc6c,8b492155,2045a8b7,560262a4,86954932,e627bc57,9c84859b,d2a9ba9c,9d7a69d3,8c8f06d7,ccd9e68e,fbaa0697,655a8a23) +,S(4c91dbc9,8d2d2891,a7861599,ab55fce,943755f,5f7c909b,3f0f85a2,bbb75c95,5e541495,ecf13109,6ac3aeda,5324fe5f,6f761ddd,d2972fe,812242ce,12fd23d5) +,S(1fe3c538,ac185172,44461f82,63961364,c3c74bc6,9a91bb4e,69973971,8e729d23,974c02cb,d7d97c,65f89b90,327e6dde,e627d96a,275c869f,22c14bf9,6be05389) +,S(fbe873db,56579349,4ca9c844,8a6e0dde,226d4e4a,2f210661,30fe1075,bb11dd6e,c91061e4,d03f9f09,21f56d76,eb78640d,4df80464,459fc41d,4ca33d4b,5ebbc5fe) +,S(b58277a8,3a6d6779,82af314f,7a41a69a,b1744e6b,1cfb4803,f52a25e9,8200957d,c8faf7cd,59e43256,33403b90,7abb1b83,d3f0cade,ddb9884d,77c5fa54,b55fc51a) +,S(3949cb,e84b7790,a7a110d7,9c41d548,d379604f,ec567cea,e3aaf0f6,fd0d9b49,cdfe904e,56a9c88a,76292c3a,5da21100,57795a76,fddc1610,e7efab84,750617b3) +,S(6ee9ab2b,537aeea0,bd8332dc,d810cb7d,36f8f7f3,57be2bb3,5d84e236,f1bca531,d75518a4,d975b0d1,e2780851,4b726626,dfc182a3,885900f0,4d82c839,1c64722b) +,S(c2875d78,3e15f959,33bbbd48,8a24c65d,2001f599,3536fa83,8a3e056c,20a2eabe,e5870c25,20adee27,83cbeaaa,cfae7283,538446b,7cfd7ded,12e68ffd,3f66de8b) +,S(88e26c2f,dd475547,8795e8dd,8285f73a,dd9eb9b2,68c1b16,65f1a701,cb3c81e9,d00344e1,9d14b3f,1dcf5c7e,8269237d,a2af90ea,93a9e24f,3a0040ee,d3f171f1) +,S(ca8e8c50,660f3928,3cb72105,43710f56,9a1518a,7948689d,3d7e2ce7,a038bc55,57600213,1892bc9b,5afede4f,e71f5ec1,a1516039,ace088f,9a851278,c52b2487) +,S(ecb6e53f,4330d0ec,b9aa3605,b6e6d209,222d611,72858b1f,d2663797,772e0249,b054af9,4c535d01,bcbd955,61770aa2,e08678ea,cd8de0db,d8efcdf8,623e9eb7) +,S(a011ad64,55123316,9916b20d,ca6efe7d,e78c6b58,feee97fa,7f9e3fc6,8d889cfe,f53b71eb,63f87651,aa0de66e,a51f56f7,c5e3ee26,ed4ccdf4,1978d7b6,f0191277) +,S(3ddda2f4,ec1b4020,31a73abf,ae69dd42,8d801bb3,fc96fd1e,b06334d3,cd7dc27f,eb1b6b4,137ca36f,5b160112,38fba958,32c5e5b0,aa5560dc,39600db0,624b6c1a) +,S(13f5b643,e908dc91,415ff856,76357687,bb777f21,3972cebe,e8157828,53982d8e,bc2d3402,f3af6ee7,bef0ec2b,73c75e53,b70309ec,633d97af,b9ababc0,62d20ec2) +,S(ed9fc1ba,60a7db8,93db8148,48790e52,4a246279,d938a04b,cf168ae5,71618e2e,b241c920,ab995cf9,4ab1b707,b06bbc7e,1cf7b8eb,80325934,d57e9e9c,6ba08459) +,S(89d4f6fa,f6252ba0,d036dcb4,54fa5f1d,311ee828,1cc5ca85,73fe7607,7b16fadc,5f441ff0,56fd4e24,ca4c9efb,859d6e16,2e4daa4b,a7f3fc58,e42a540c,23b6075f) +,S(4acfd390,e8a1b430,9af0c28c,87f51308,a1ec5741,8c194072,45c96c79,30498a3b,dde7b57e,5e5ab271,78f2ae5b,6494a578,2757f508,bafbbe64,30b96bc4,96728d2f) +,S(8320cbe,fa7483dc,4f5e7b7d,d74cf492,b95b7e31,b1bdc651,6595b605,eecc134d,e766291d,13959f5,805de8f2,aa59cd66,8376d93e,4b775010,426db24e,b2ff41f7) +,S(fbfa6a21,deb1d183,cfeda065,687a0b96,6d8e50fe,475a17a,7b690019,6e7c696c,f5901c10,5f30f5d9,75530b0,3f943caf,8de85a12,f54e4c7e,5685184e,8bacae2f) +,S(70695a81,45fad213,aa14a7ec,d3c84f51,53e3906d,5483db4a,c6e8c229,ecd2c3b,febf34ba,9744a37d,6b91335f,c735c426,1208595b,3b8d048a,3fb48e76,2008e90) +,S(89fd8cfa,8fd5bdda,b6a80bb9,96ebcc92,6074a15d,371622b6,1cd772f6,ae1ae9a9,85c2cddd,a8065ee2,244b3d35,61e9e057,87c6cc4e,d4b1ff59,53b736cd,d3876108) +,S(342256b4,cfd8e5b7,5f5d088e,3a919d64,ccf38827,b18bdd00,2ee9a6c3,fb4dad,c54f4704,f3512e55,4d96ef92,3005e4aa,34a157e5,8bd6b180,e219dd51,16c4be16) +,S(cbd38ba1,189a152e,bf78ea23,3eccebc7,16f4c28f,273f5c8b,ec9df397,9dba0dd1,d3df2ea,fa52ad52,9089c7c9,581dccbd,a2a0e060,7fd4b902,cc915f28,717c2d29) +,S(5f7ae38f,61dcf176,45affec8,7514c624,85b880ad,38df28ae,b695cac0,fd1d27ed,9b955855,f74cc040,63cfa4d1,fd098e5d,e0030c4c,6dedee41,71bb5e7b,c0939226) +,S(72e72eac,aef492f2,f3c5ce7d,dca58f40,c919a194,3662adb4,3d855a8b,532d194c,d7b5e558,a0cb091d,3b39407e,1dd58b95,30fe7561,6b4c3352,bfa51320,509d2d7f) +,S(925a19f0,c73d85d5,674a62b0,2d5496c0,5868fd41,a43696ce,eb153a0a,2e5b8051,2ff229b9,6c23cdd8,2bdc56da,37495c29,78fae40c,b429a1c7,3111d392,3c5505c3) +,S(baca4fb3,33bf98dc,165cb9e4,3bec920e,bbded256,e990820c,8f902e84,3f6e02bf,af304697,137728d4,e96a38d7,95b830c0,6c18579a,9b46f4da,a94a13e8,d3a0341) +,S(fbe24c7a,53b90f3f,918b92ea,e58ef633,bb72e695,2eee6c6c,2210f6d8,8da9e0df,1febd844,af3d057e,c9ace544,d5fd57f0,c125c55f,1d9df636,4f6be8fc,bc53e3b5) +,S(73b7de54,ae8a38c6,ccde88c9,3f526c2e,54d823de,a6415488,5e864a2a,1b0574,2cfa6943,634201d8,9438e6c6,fbb7224b,c2e6b313,538523f3,305c75c3,5c68aeb0) +,S(84960402,31a60cd4,cd623d4b,80bc69aa,7cfa7c0b,52cd88b4,2f22ca66,17151dfa,b5324b5c,af293ece,38deafd0,76835e10,469997af,7dcccd89,172ad20e,f36162a6) +,S(b6de647b,98585f7c,61f0712,76c6f62a,40926888,b1bab4fe,ad64098b,4b9434dc,f7180d81,be634f34,d878a645,2c662e8a,db9c18e0,ca7e7c13,8bc51e1c,1a5f5c0a) +,S(e062011f,da416281,bc296718,300a080e,fe7ab89d,8469e8dc,fd50680e,12dd9348,c33030e4,1ec1b1c5,4ad01bb9,8c4e2c48,32b2516b,1b2b3b22,adc4add8,1b690787) +,S(f7c7545,649b4659,49618dea,7fd15a06,1e7ee032,5d955649,b76b66f0,534a5501,2a929b2,a68342c1,81b2f55d,6b543584,ac06077,d95ad8f3,fd3f3ffc,24f56a3f) +,S(bd90ad48,1694f297,6506e2bd,e97d5803,b810f9ab,7479ae90,dc1fb146,38d4d5a0,f973b70d,8dca64e0,c9384b7,ad3b4ab6,4d3c74aa,722f9284,a9da82d5,5c6d02e2) +,S(cb5d91e6,68b3c202,b72a38c2,f98e6e4f,14bb566c,f7996d9c,c08aaa07,210b1b1a,68e9920c,597b633f,9bfdfb8,72814422,4ad69ec1,e435e843,73a9255d,79f52d7e) +,S(d251bb9,83bf849b,8f058ff6,32ac6bea,bcd12649,4fea947a,f943cdf0,6e0c240b,5098026d,b8ec5c54,8e3ae103,f0d172bf,e84281aa,b8c0b131,16295587,ed4500f6) +,S(27235299,c1f8d73c,268bca88,62d2b6d6,635f151a,d148c662,6c0cd5cc,1a3d2234,5b03cc60,f9224aa3,10d8193c,74e70cbb,6513ba73,d6d98ad3,2e1c2d,7f78ad52) +,S(1cf437b,aef8e007,ba02a24e,735d8444,698e5edf,2f9d41d3,cdb28cf3,3dd53851,e3fcdb74,b580b8ce,8f6edfe1,c276c478,da11323b,4e96862b,926ca4c7,f739a8f3) +,S(aa872c85,70e9449d,6cf020c6,77669c8a,7ad408e4,d9fa194,99867c6a,f77df918,572579ea,3d1d9575,e60a79a0,7a2aed83,4fdfba52,61b962ed,42e59322,c02fd873) +,S(b3224a2e,80c3a174,66a9994b,717b4c37,424f12bf,9dd3f17f,6eecd801,3ee2ed56,7ad1cea1,128c1605,552b8be2,a5fb6bb8,907e4290,d76bc82b,e17ecc32,1be6fa43) +,S(29b8f73a,7fdf6032,4c907022,b0107c72,ed951eef,29687feb,a8de56ab,4e47b8ad,19b849d9,bbdcf00,a6bba6b2,f1058695,4f286884,9b5be608,d6b4c357,1098f54c) +,S(3c2f5680,96f946ce,3d048364,dce939b4,a05ae9a7,c31c2a11,d2a29a1a,3fed06e2,47701685,b698de43,ac515062,9c40a15a,bb952a0e,bdd96,ba4a1b4c,5f61658b) +,S(b80f00c1,ec0d059,c9f5c69c,10cfcb26,651716d9,3d0b5702,b2c7b295,85af4c55,aac197db,ab42141d,31f63425,5df908fd,fd026d10,1263aa7,63d99414,adfdd02e) +,S(66af071,6b78b854,16572c86,fb3e51e9,b6d66ebb,bfc2a2f8,dd664010,83c83435,b8b2ce8e,fe794b13,4fcaad05,821dd884,9a8318db,614d858,8dfd4d2d,65314398) +,S(7ce8342a,6ea85f61,559cd2ab,e82debe,82eb5aca,142153e5,320562a7,6ba155c0,8a930243,5ebf4269,d75363c6,93ad4255,59f493e0,e492150a,9f110c90,8d7750a) +,S(cfbc37c5,184fe206,7f7b5c6f,c5e50adc,ed58ae61,d9059bb,4ff64a19,f48483eb,bd567b19,3da2b2fd,bb8941a5,be9fc72f,11d9cfa2,4c4438c6,a4db3091,9c8867cb) +,S(728c27be,52c5a742,859774d3,2d33fbcd,41e997d7,25d6be46,af480c8c,f9ec436c,745c7738,2a833cee,19808d12,9768c213,7500e8b0,b140e3b2,94abe97c,9a7c73e7) +,S(4553277,fbb30c09,a1ac1ac6,cb7d38f5,88cd5f3e,d4ebf6bf,5b5f6e78,12d47d5c,3ea80bc9,dac9f1a5,ac4beedb,d254cc15,728f0ee1,6949ce97,53f1bfbf,98e3c78a) +,S(7b752d90,9fd6d063,f1ac0f22,d8cf1e6c,78a335c6,ed11743,88192fe3,cba54cef,a252376f,e482ec59,2ac440e7,3aac3b46,a149e35,1aac2d51,244ffd93,f51d11ec) +,S(e78e796c,eaba974d,89d344f2,b610e84b,d51443bd,1fea5422,d2bea957,5467a376,13f0797,376bcf76,b6ade4c6,a95b6446,962ff925,b32fef9f,4549aa1d,e64e2b1a) +,S(1b7a8c02,83f25ac4,cd4a841f,4045035f,92a39bd2,c1903c90,4071eb44,5e8d702a,1843f757,7d03b6b2,22bdc28f,47c7fe6,fb83b25a,8d795b46,9e3ee9d1,ccf7623d) +,S(90d06a90,6ad81dae,20cfc2fc,6be85b2d,41dd9f23,63e13423,c557c4c4,bf3e5e4f,6ba7a127,58861784,2d7ee3d5,9b71ec99,86a72ae7,71312739,79544095,1e5237dd) +,S(d7bb4e18,ab61d8f1,de4b5bd9,9a5d03ef,1e0185ca,55ef14fb,be1f0b5,4cc4803f,311f268f,a672975b,acabcab5,1dec5754,48eb5a82,685e339e,e23b41fa,112873e6) +,S(6d5f1808,f17e0b81,a6bf12aa,34032644,b708882,96e99861,fe5ba4c5,5546c44f,8eb304c8,92cee7e0,70649d73,ae76893a,610504d3,fdf37af0,92d5dc7a,9eab1094) +,S(e4f62cf,9835a4e5,c2b7a456,596498df,2973192a,af2c80ef,c036c71,69df470b,874a48df,1a25a003,ada8939b,f727e0ec,b7d2e4d7,1efbec4,7193a2b0,50ecaf28) +,S(7fb31d8d,b3d5b77d,4aa9d0d2,692013ce,c82ccd6,83a2235d,848037b,dc6bf8ee,ed5cfa61,9fb4e350,dc37e2a5,2bb67104,90dcb484,b19af368,8101e59c,f9f0f0a) +,S(8887db9c,e3eddeef,ece414a4,f46ff048,3c4fd25b,14354869,6c60871c,5eaa9ffc,50294d61,1040a466,f826e654,3fb93f94,b4d60b11,d589287d,6ea33df5,a8dcf366) +,S(9d9d224a,595c843d,1f70297c,13b3645f,385eec97,80fa9e50,d27115f7,b677aae7,af9d5f61,24594cd9,a3aa7100,ae6f169d,dfd467c4,1affefe9,c9a0a5e6,6d7f2802) +,S(743d9b40,527b23b8,f165b6fb,9d5c14ef,450e1ce6,94439354,ab501eaa,2f34137c,6aad08c3,bf602b52,7d43e3a6,e7efcfd7,f24222fb,f8213f25,e8195501,9c8f0885) +,S(63c850eb,f0cd6fc3,3bb7a4f5,6d43c389,1f93b11b,5f67e3d2,f9b7537e,e5a951e3,29d214e8,bde33612,a5a160e0,f7cf3acc,3b83686c,ec5d7c36,dd90ebb1,d97c7ab5) +,S(b95608d9,84c13243,63809f82,b42cd16,fcf3c6be,5b19ccd2,249016eb,d93b4a54,41aabb2f,e7083dfb,ea380fff,2467a843,c88ef6b4,9740e73b,33a088a7,649fb0ef) +,S(8361b632,5eeafafa,f01e3624,6bd8f0c7,aab461ef,cb3484e6,c1ee871a,7ef95114,34ac956e,791cef3a,baed24de,7f0f59e0,bf34dc75,edd10159,b3870248,255eef36) +,S(807109d4,931731c0,a94127af,cc98e487,1fb44467,6d8cde89,88dfc252,868bc853,363e3944,be00a734,4c50afc9,cbb43183,f56eb20a,c0a5d9ec,74857484,ed9e1d61) +,S(25ef876e,d1654570,244ec258,e7ebda09,35b11784,bf5afb7c,8652e5f8,bdb34055,63459bb2,b8affcb4,1f6ad9b,9437f3cc,6d8082ac,d400928a,29f11fdf,503c8553) +,S(1aa87b1b,54eb6bd3,5fefb162,b27ad9dc,eee4b5ec,c1b69d4f,1fc6e230,d1848435,e5cd86ac,23c3790,369d7fcb,2189098b,a4fb3007,f82e5090,22e8ce5a,b44258d) +,S(cce2b0fd,9497190d,e6ea068c,98bba7de,a8f50aa,12930b4d,9060808c,b1ce6152,b6aea7ee,becee274,2bd8146,d792a6e9,ae75fd79,bb8882c8,11135d0f,8d5e68c3) +,S(fe421506,955b7cf6,f6a84228,30f7c6fa,95e4576c,da711415,5a49c238,e0bdcd4b,4e4a31d5,9b70b51,f73a4d02,eb09e4cb,7dc74a29,bef959ed,86558fc7,d4c8f401) +,S(cb26c118,264778ef,512f8acc,385e5ac3,10b489dc,88991e15,13665b7d,587d713e,7375bbd0,9fb3051f,a907fee6,80683f93,54403c76,85ca7eb,97a711eb,69033c6) +,S(8f286ae6,171d88d7,d82cdc28,93960bcf,53768c8,9cf1f149,fba0acc6,f5056014,6852d427,a888c5a2,4e748f2e,e482d38a,42879db2,2e824d1c,d72cf15b,8e32b085) +,S(b7af4b6d,7eb4eb03,e827f099,fb8b02f4,bdca366d,811d031b,ae827941,235e75a0,7cea697a,e8cc53ff,8c738ec2,55a64e4,4a499643,4bc5e16,422ebb9c,17d3dd12) +,S(c8471c9f,53eaa3fc,850ae514,dfa1109d,e89c500b,e965682c,6a4bc2f9,105be1e0,7d5f32ce,d1e758ff,e38325b4,778e68b6,f0ae5509,fcf9195,c1a79d41,57dc519) +,S(8d192ced,73629184,ff6db80e,b2c6df4c,a8ad77f6,dfc98c52,9406e7aa,dd506536,3b01ec04,ff45b037,c1444255,9cb2f629,7b4f8cff,e4c3eed6,3b95d4a8,88fb2137) +,S(318aa156,f4912dd9,7b90ae6d,c29b0f8a,99f616a2,5b023f08,ad35a8c5,10ec5015,b398cdd9,5ad52ba1,d7038cdc,67e36c74,5625fb94,f62b1b9f,aa2eb5dd,be6ce52f) +,S(b7fcf98a,6a385f68,a1c6f9ee,c6f069c1,81b0c94,df8c05ef,b59b49e3,aad66f54,912e2098,e3b6e44f,46eb6382,83f554e1,80af035b,16c0eb3a,4e000cb8,d4ea2da7) +,S(599b7a5b,e7a7cc6,3e0b66,38171c0d,41d78efb,92a9bc8a,1d0e8f48,b2b92fc2,afb3343a,1983a867,c8e196c5,92f745c,9060330c,1f0c0509,375e30de,3a214b7c) +,S(c3578705,3221f18f,69dbc241,f927ec48,3280ade6,44c70129,2b30a11,a296db9c,2b75b2e9,fdef6060,29633ae,481ba7dc,8ca52847,d4d0a201,9da74056,40a980bd) +,S(9e2020e7,cc4153b0,adc2b1ef,3cf607ac,305a480e,3a8854d1,1907fca0,4811fa7,19153a83,2c9a0612,dfea182f,a855a039,33035757,2e98e5ef,43f26699,3b8bc6b5) +,S(1e0c4c68,6e5242c0,6645f4ac,6ccb18c0,82c5d5e6,c89322b4,3b6079b6,ccb5a5f3,63c4a4d7,3ab71f2f,c49f5532,b543e381,83ce223a,c8609be9,d6b72981,8b5dedfc) +,S(44b11683,5f922e88,e7ed4328,cfb212f6,aabb6199,64fbdf3a,87dc7f24,faa761e0,a9181b5c,341cd78f,2e1446a9,e99acfee,7aa5b91d,4c7da20a,b7cf200c,f470ffbd) +,S(940baf24,717ccfda,e539064d,f6e4b670,2ad8b60a,c32e38cb,fa4eadf2,6a7bd3e2,bf5ab95d,2cd9b68f,cdf535bb,84b967a3,f4fc44d5,5e6d21af,d09e1de,f5f13ad5) +,S(4191f800,85767106,a9e5fa6,8521366e,a3adbd79,ea315b93,9e63f797,2995e7c5,662791d3,407f50b3,7a68e15f,5ee71991,2e893099,a907db3e,f818938f,9c3bb2cb) +,S(1bb8ec05,76ce9cad,f96b418d,cb5c7d46,9b49ca81,7f253b15,8b26cca1,cb9a472d,762e9c6b,2335769,72396f,36a56efc,f2618754,f1c30923,30b521bc,4e0198b7) +,S(c5216da7,91635b83,e55ec5a2,d9f3f8be,b1a2b0e3,cb097528,654c50a3,315be78,2536358,e58ffcbe,789d34e3,25d9f59a,2210c247,a80eac8,c716214b,9d5e520e) +,S(7b1488fc,83a02d7f,d12b9eea,555922d3,f4a9c42b,52f030d9,bdd39156,f0890225,ae7dba7a,d95420f2,8c8185cf,5aa2b777,b9fc5c14,b6c47048,d8ef071a,77dd4397) +,S(e245e4f9,7d6c69d1,5e244f4a,668afd07,d57fea2c,f8401b2d,8cfb6ada,f01f8891,88a0648a,ed5eab1,d57226e4,63411b9d,3632537d,699f39dc,7d7cbe5,49e76900) +,S(ed78f3d5,1f4fb987,5918a0cd,d6e5280d,6516f5a5,acdee916,d3e7c7a1,d757d188,ebc569ce,9b3cd325,528cde0f,9a2ef54c,d9f920a2,1ba7785f,62ef40dd,9463a81d) +,S(3e8d870f,bf768b41,8264ad34,89026fe7,8870e201,3f98696c,81dc3b7b,c0b1b599,28558e59,a6a6c255,a352cc9a,c20508eb,55af7449,8d75ded,c94fe414,fadeb218) +,S(96125a01,8f901790,fe25b41c,f2f7fc98,50cd30c8,cbd05ffa,cb76bc45,94d5f5a8,125db476,3fc8ccde,492e7eb4,45873147,8f8ddc5b,6c2b588a,b72d9b1b,fcd4c43f) +,S(779d9847,6fd72d41,937fe1e3,e12d4076,5cc61f41,19b37437,3919782,18a3dfa0,75a3aa4b,95523e05,42f38dab,b2d80895,cf3738fe,5152c8d0,96a587d5,90442891) +,S(681e390c,323224a0,7ccd9520,23c9d89f,4069100d,3b275c5a,e773efe6,170f4e4a,a9bff0ee,334bcf6e,a3bc44e7,5d85acc,f753a471,ac008e0d,47b19ac2,476b184a) +,S(d7b8530f,3fa18d18,ed94b938,2906e431,44ad5994,5eef1d53,e3290887,5c4af2b9,2efa5bd1,acc4ce6,73b8c76a,beab2e87,6399f84,94a1450,bd6833dd,debddb92) +,S(1277ad75,6e965ecb,c8c04ea6,c22042a3,ca3e71e0,74334012,7063d3b2,da257a5f,38c90310,ee2bd94e,5f3149f1,f38d065f,8df110f,92f126f1,3a69013c,515134ed) +,S(4e66e596,94c521a1,8114b232,427dfb97,8c7f14ec,7b5e18e8,9c11cb5e,6a2f6f65,47d553c1,8a858b59,f1aa8f4a,51803450,c237fd2e,60b137f6,d13647e7,6683caea) +,S(1fc1e8bf,3eae2dfc,b141be5e,ea612378,209ab1bd,7ccce45c,d51fcfb2,8f192aa3,5632d350,ab6b3da1,599779c9,9cd8d7b5,e317ca9d,ef3245a8,eb62af95,ef769c20) +,S(7eca2d92,8d2bf4fc,ed1a8336,eb87c5f7,b864b842,b3057c8f,97d5dfd3,76771d7f,969da039,7a37997c,c243d448,90d8110e,fa580359,bfb35342,bf69dec7,4bb17337) +,S(2531025f,8fddd665,cf34baec,52733303,28e47e4d,827248ad,9a1e6c4e,be3db9a7,e404fbcd,d180b2ad,931b4f61,5902eb06,cf00f66,6f1323f7,bf0652fa,94dff64d) +,S(dd28941c,bf6e4bd,76b4bad7,88f700a6,8c4937a,67958c3,bf6388a9,d5e26441,cc45f07b,9ea1a81c,8d89af84,8883ad1d,53ee8a52,2416c445,c4963791,7a366909) +,S(d3af9e12,53ffb85,ec7829a,4d41d704,1ea62952,4d7452a8,d9ab6ef0,1d6b509b,9c115e78,91b383ec,20739d37,6450a2e6,6f332e5e,c7a3a97b,2eca8c0,ae819bbf) +,S(2c59063f,13ac98a5,ed196aec,4f2aba11,c8647d78,42be85f4,ab87a007,2b49001,e9738418,cbb6e31c,f588a3b8,70883f90,ed3bd8e4,86e3c77a,37fd1152,c22637d2) +,S(6c0ace3,f182c963,45deeee3,c41c5e51,8dce984d,3d409a89,6d766ea1,b1ff0e0c,17e09dc8,dfc53cb4,952fec4c,92782ce4,3515544f,6181bde1,1d1ba1a,bda709ee) +,S(f161125f,3a229d29,2053fb9f,6f118550,43d80e33,9bd45af8,c1519043,2098c9d9,1b442ffe,a186cf2c,343b90b3,66a3a008,e08edf90,f073e740,abd5d20b,8dfa1327) +,S(fd081f05,6b219fef,56a3fc1b,6dc7873a,fb054b40,1b3ae0b2,414384e0,9080827a,9711912f,4ceb0036,3e5921b5,c2f7ca49,387b78cb,f1b9c2ac,9c5d5d1d,1bd8203) +,S(72c6eecd,d87657bb,ffc3a03d,b6e1f9dc,83252d2d,c73ba3f5,8642fc08,fee42b4e,282180c1,7737b51e,d047cc50,64d53cec,6340eefb,d969525e,a1524f0c,a305e39f) +,S(10df231d,4582143f,1ad7fe00,508cbbfb,3d49775d,f13dcee1,d6155768,c14bfc51,b7743bf4,e7cd49f8,88cd0d26,ac196037,e1da9402,26518e07,407bad1d,20af7dc6) +,S(354e8b0b,e40bd9a0,36620006,744c0913,5bd4bcea,34ab3371,9561e36e,f465956a,3e7407a2,2b9d71eb,a04239fa,600834d7,5f643c8,b4ca6308,475f6c9e,8d35fd4) +,S(2ae99ec0,6a4e080e,879a60fd,a93a47df,9ba7e0f3,b87a6772,be6d7e23,9bf2c42f,3fdfcc57,6a36adbd,52467e01,f3490fbd,82766cea,b956f80c,7b1d29b0,5066c31d) +,S(f47ff09d,5e93e827,72e73c7a,8f1623e0,823b09bf,86ba3023,a223a680,fd849bd9,379ad3a3,cd546d27,35fbe5d9,97c3dd8b,8c45a3d1,ce8e9c49,b23bbaea,e93a08ea) +,S(252c0934,acc3a624,c4d8b409,111b248a,2242dba4,7d57718a,aedc9cfd,20647cdf,17b7a015,a2ea993e,89a7161b,f50124ad,561ef131,609981ac,fc92e495,cd2ec91d) +,S(b7f6bde6,7cdbbf9,4a3e06b7,dc1bea75,d6247197,a8617a6e,a1f65f44,a7459006,6d6ad596,fd3472c,9d7eff56,943c1a03,ee4f540f,29782f77,afe999e6,14f5e316) +,S(210c956f,e0a741a7,edad58d5,d47a2a34,fface7c,5edad0f8,f4953b72,28350b2f,4d4498a0,892a9a9a,4e87ccdf,424d7910,bf90fe95,186653c7,6e6966a5,e7a816b8) +,S(7ab93adf,b8f35eef,8af99e5e,e37aaeee,401a1936,fc0b8c88,518065d,12f4a74,4f0782b1,c78954b,8ce37bdc,7e533145,3b885d92,da1dbf85,940da9a9,b7f0dd8d) +,S(bbe1b787,9c93e7cd,891f628b,c9a655e6,f4c7cde4,fa799596,74978224,9fd05fd0,493d3dd7,be33acf1,38ef5b73,8eb8f8f5,4e270323,8f70078d,5f7bd9e7,177088cd) +,S(61f42d35,ffcc6151,f8c93b21,5df0cab1,fb804cde,f9c68818,fc4f413,b804942d,46ef1e12,d6add082,3917a758,9c137d45,c38ae2ed,eadd847d,aa574e06,18708396) +,S(18542b75,3e78191c,b3dabcf,f9c64a8e,5e4b075d,d600fe60,b830e732,7fbc7b40,6a816e01,41b17e86,65ec280b,f6da9dbf,8061329b,6db9d13a,a9f10c0f,41340118) +,S(ef83d0f4,a3d2963e,d14e708c,6d22017e,aa97b2f5,23b06f1,140b4105,459781d0,5587e5,13725819,1b10bd40,e616e06d,16a50392,7a8b1394,a562c396,973d98b6) +,S(fe73429a,7714dac6,ed0db327,d6949d43,30d2b16e,a513d3b6,7b74452d,78a82a4d,7079088d,fd828815,ae087319,c232817a,4928f743,843a4966,e9411276,d16214b3) +,S(2e8b8a63,3048900c,4b82ff8d,fd86a971,86e3f1b4,6206b252,f06a8c85,82555130,74e10dbd,ca84d796,b3b37ae,b32624c5,2c5aabc5,d4fcc5d2,21c1aed4,71c940b) +,S(9f4164f5,4f34a59f,3a7be378,66a8204,def2fd98,8dae6dbf,5d471e0b,caab7017,4b662fde,bf2615c0,8c7b53d0,b2915d50,ddd2916f,a3599d81,bb2eab6d,80e93f57) +,S(c6f3a26b,adab6699,aa08fcf4,6f0ac900,2be3597c,16133225,6a5e6577,11b16ecc,f29db1d6,579d0e36,4528c297,36019f4b,6e8f060d,ad5effe6,d357d709,882a250a) +,S(76a4f5ef,6a869e28,e6494cbc,ffc6eec0,1ca983ad,1b8219cb,d2b84eca,96f8b910,e1d8bd7d,55a297df,32ee185c,c60db286,a2e46cb1,312a8995,5923a068,cd3318d5) +,S(d2c25c8a,cfaa0b2b,3f6e70d5,bf095700,68102f8b,24867970,ef3c8000,b2212d1a,bc907681,9c7926dc,bf81278f,7dbfc4cb,292a8071,177ce8a4,f4e9346b,a2d9e500) +,S(b2fc2ca,5a30c678,61b0bd22,5bf2c088,26d799a5,9c9a680d,dabac9aa,5cb624fe,d4abc7c9,fab915d0,fe9dcf59,a0f83ca,56b27566,6e9841cb,b5b14874,5f6732ee) +,S(110ef531,7824c321,ba7fa94f,ac98de3a,c6cf44af,db92b7be,1006c751,9b425065,cc3daa20,6c0eb83,6bdfe640,1f7461a,261e7233,c70e615f,db82a991,77b83cb7) +,S(fe21a607,7419ed88,12d16ba7,5485e01e,3c063359,f95a8634,3aab1c84,ba6ac00b,d6e08c98,4b7a5282,bc1857b8,82604fc0,692a2fa6,40cf5a5c,d298f344,54c836b7) +,S(c5e45275,ec85bb32,edd32702,7d7d87ac,8394bc51,722e0bd9,58281e61,c454fcef,9b158ee7,89034035,fec4f06f,2fc81755,59f9f762,38742715,92ca6ff9,e5712a8e) +,S(cc68f3f3,36360481,5583d65,7da51968,a4a44a69,1264bac8,289791aa,dc7a4ef4,9db5cab6,7b31f3fb,f3b5fde2,273496f7,93316358,6d14e80b,bbca4613,319df9aa) +,S(6d33be85,5fe8bade,89109a3a,8c089aa3,f7e9d178,969100b7,eee7a693,d83ace80,9312736,87c08455,c43b4cab,afe71408,333fbd69,d330315a,3fc9a52,a9d473d0) +,S(5aa581c2,fc48c38c,2aa2e176,c12f12b5,4810ff6f,862fa17a,196c06e4,812b9e3c,adbff08b,bf6fd5e9,9f91f9f0,9881cfcc,a7b5c2af,709bf838,6055079b,2f75f3c4) +,S(12eb2dde,dc6ea4e8,dfd43067,9d45052b,b882e4d9,bf516b,61edaf00,305fe883,8f948ee0,f8514f9a,1bd8a71f,20c95e4d,e30caa5b,bb3a383d,9561f027,34bb1950) +,S(3d0d7eda,43045e9f,62dc680a,be47e933,74a95d59,945b69cc,60acb89d,e40dcded,45c53d35,e369af07,eb223a79,1d148ea7,1875cd1,8ca066d3,399743f9,65e184b4) +,S(173d4741,5803d266,7ea94abf,319c5917,204256ca,e217647c,c024a9b3,be7b70c,2da6c348,cb066462,eddfe8bd,3dd00ec1,34a0a060,4b7e17d7,e6cda389,dd4d5463) +,S(10659655,e2f1ba5d,db390184,c2d6d1df,1cd2abfa,4cd4bc18,c89decc9,5b5d6319,5ac2793,3a88870e,d5c7752a,459ced45,69435a09,7cd0e030,25608cf4,ac2ae267) +,S(e462be7c,380d7bbe,cd45c6dd,8fe60219,404b0c9,4c5e0e4d,31a23064,2b5b95,872183ec,1ba5b854,1f3f99d8,ceac80c5,9e84756d,cae2e694,9b43ea7e,d1cf752e) +,S(8200badd,1df41faa,19b20cb8,efa424d2,2f39b1f9,26b692c0,2a0ef6e7,feeed67c,8402fa9a,6ef0f83f,42546b05,360296d3,74db551a,d89be995,f2c11866,5be528b3) +,S(760e2457,a3e1a165,526e9fe2,2b5bcad6,e8107581,337cecac,e2ae87dd,a3c54592,c5111ec3,24158a21,56b897a3,82bee2bd,de0f9df,af9ef611,a7fd3fc7,4a635b3e) +,S(ba6229c7,1729cae6,5275719d,9a35691c,f260a003,168f1a25,1ac00b09,aa17872,7d281600,6bd8981,82126d21,70fa0ab1,d5dd0c7b,cc377a88,c43cbf61,70a633c3) +,S(a2cf1392,571e758e,6ec74708,dc45f70f,90833ad4,135e7a34,9d2810a1,8efb5216,2420ffdd,afe96506,9e6f9266,1e3839ba,c9b1db40,d40149ae,3acc8683,86acd175) +,S(f8822204,27cc4b37,33268925,fb80beb5,a52e5391,b2c8e31e,f6e99592,1775af20,6cf6eb9e,b19825da,6edc5d2a,66f3987d,c9eb01e2,b70e6395,abe2903,d43acee) +,S(eea28950,fb676991,444f96c5,7e42ea16,aa380e3d,dde63111,fac35708,a4e45b3c,34d30722,98a686ec,7e1a8095,4e2911f1,5e11d426,ecacf11c,eb45a5cc,7204114c) +,S(7f252a72,6f9a1497,f61bc4ee,7b194a31,432c0178,2f40b16f,2d36e9c3,7279e25f,8edf25c5,f50c6f0d,f8a17f92,611bf024,14e02d0c,de38aced,e96d5a7f,4467c449) +,S(d3da23fa,56881cf3,a42a50a7,42e1067f,54ec24f,2de19921,b1ae7f15,fb90509f,b4ec4b17,8e555cbd,15210f09,bd1ab43,28e458fe,6aa3e800,44bf0093,ea08f90c) +,S(6752f294,f8ad85e9,60b6a88c,cfca7874,5c80ed7a,93f6f05,3782ac73,d96e31e3,976222ef,a6f6358d,42d6289a,4f11bd65,e7e755a3,845ed49e,3c972b5c,5fdb2418) +,S(4fe21b06,24a45b69,7f42aa54,10e6385d,645a8d49,2a61ece5,c8d5b2ad,1fe74efe,f7666c09,7caeea3a,c4b2993b,64f4c0cb,ac934099,8870ade,b7cee48a,c3c2c413) +,S(15af87cf,6dc1acc5,1d323a36,b2daf163,ccc8c201,a92f0677,6a26ae27,7fb9d766,53fe4566,6a975d35,ed20a5a,7bbe63c4,4cf8011d,45e7a171,d5d72e57,5debefbb) +,S(656f3686,c60039b4,4c39a5d3,ee82cd08,e8aa8ed4,b9a943e,42281407,4ab6821b,9f277baf,2da730b3,dacc2a43,512411c0,13ffca65,7092e695,d49c8d24,a4cda4d5) +,S(a13286fd,2c17a61e,6bf8d209,d64f5879,2534b037,cd854470,a09c8c8d,95aa0564,9322d3d4,c735a485,5d76e5d1,fd27fdbb,a8af2fcf,ddf7bdf3,f9e26f97,7f4cd1df) +,S(3b355928,4ddb285a,1eab73c5,6e6bc554,9f40d83a,2b859e01,a30032f3,a5a7109c,780670b5,67755fa5,10fc3385,7745a69c,bbe73e3f,8186b3c1,8a82c51d,5e1d9be0) +,S(b0b15be8,6c2dbfed,6da6e7c6,51c10b17,504070,7d1747c3,ff2dddbb,256fa495,8d2c438a,42750adf,345332d,f02f6c4,55a07fce,afcc51e4,96c270ff,913546e3) +,S(c754130,bd717ab0,fc17e14d,dd6ec50d,aa6bc02c,a338cd9a,798ee62e,72d517db,fddf938b,28500dd,c9f1fe0e,70104564,d1bad398,d3bee900,ff609c8d,f56d3b26) +,S(ee615579,33d877e4,9bb228e3,62766ada,8615d382,c022c333,39f78ff6,5e5d9ceb,3dd38b15,5ce01a1b,3d5434f1,b2e04a26,6a830f47,fe89263c,b0ad1b5e,18bd8b76) +,S(f830dd7,4d03a39,d7f5ba3d,132b40bf,130b33cb,9b6609e2,12b6479a,14287c9,9183a68c,33c2d25d,c237f8ed,b5a63d44,4dd2bffb,d1255631,221edb9a,4c9e9e91) +,S(544fa477,3aa3589d,9e63c8f0,f30cd189,a8b6658e,ba908212,cb1b4caf,2d5f64ca,bbf57d7d,b5c6b8d6,e202a7b9,8ed06edf,e1a9ad01,381da1d8,11405fcb,8ef717c3) +,S(9b270440,132f5b09,6fec6214,dac1e27f,3e6c6f7f,25eb2cab,680c3fea,e0b41b1e,a7e591d,eb990617,6bc87263,6ea19e04,c9a3aea9,59059078,2a757fd7,6d99c6dd) +,S(bbd69c5f,f0b9228b,cfeebb97,32b3c316,c14d9a54,d5a3e9ca,ebb337e1,e33525e4,78cc6c84,8c246e7b,7636949d,4e3f2b94,989c77c4,812b8189,cb857cd1,3457c403) +,S(a920edc1,4ddf5bda,56719c0c,2adaea7c,9aa8aab9,25a5d6fd,41172725,bc65341d,b8afac74,46e560ce,bcaaf438,69dc9287,2805fc14,122cb19a,bb59e51,8336ff80) +,S(3c6e9595,a201956d,ed27e83,41b22822,445148e6,d00b2fcd,ecfdd66b,2405ae3f,2b8ef9a7,d7c37d0,d2b77309,74718eba,16f221a5,f3074678,317f0b6b,7b0841b1) +,S(c35c9e45,3f487f8f,ae5b6010,e1bc1ac3,ebe4ee53,33666876,13cc4b35,5162ed91,7a8e64d4,9f827631,579421ad,3c7f7ea1,f4866432,a341f955,6741c521,c757addf) +,S(8fc84331,a8f8dffe,28f30d71,b39c105a,ec09aca,4876241c,1c81a223,a1953637,aac7257a,cf0fce3a,ff8fc7ea,e8d19606,2ba6d7ad,9b7987bc,35a92b9b,20360174) +,S(b43ca4ce,f1b4a2d0,1a20fc64,2f3e1456,317f729a,1ee69798,4ed88bfc,1c5a2908,39ae1e51,f352c0c9,8a79cca6,cc859eb7,92bad6ae,5318f99d,d62d3bd4,d8fedad5) +,S(7f29c501,75628aee,5d39db41,cc4d89a6,9f133f00,47500f6b,aa7a90cf,e13159d2,cf17c6f2,f6072b50,257f722b,5756d8ad,c7486cc1,d21a925e,8cd29a15,4b514cd1) +,S(3fb93959,55ea2522,61b0488,212e15d6,b28e975e,5ff5f357,15337538,247f2a54,7c3db409,e06d6980,d834639f,e9e357bf,e6a4e9b0,ae6b4fb8,f5e45143,ff625ddd) +,S(945ad871,18199665,a4078a46,a9596bd3,ec7cab84,b6323a0,7ceefc63,d7ba29f5,6eb6d896,a24d02c0,630c909e,65d13d4c,2eacf1ef,6e600b89,1b171594,aa28c206) +,S(513bfa93,57c827c1,b3c0289b,c4ce443b,cadfbef0,b28b32a9,265ab85e,67efaf4d,645c5b3f,d45030f,1aaea514,baba7069,91def89b,56fdc292,4b684241,6653b6d2) +,S(d41b35bd,421ef7bb,1c03c794,477c2851,dee92831,714180e6,6e57e735,caba5835,beea2116,9cf971a5,ffd83596,d9bd77eb,cb1e0c7d,506a45ae,be8c0c7c,22738f9d) +,S(96006d64,fac8f0de,88f93e05,da8e76e6,40afc1b2,8ee09a7d,5633643b,d89ee3e7,1404173d,e96a97e9,ae9bcad5,c9093d05,cba96479,30bfe6d1,96664d0b,13c93618) +,S(ad528227,12257f87,d1ef82c4,4af5f046,648c2a72,497651bc,2327e971,1170e7bb,2ea908a6,c742f542,324be959,4746ee48,4229d497,cc8bd535,e7989525,aa36f079) +,S(b4709a81,c067f6e3,93ef97ab,c26675da,6f01a2f7,e3f35275,e7089ea8,ad5644d6,f655b89b,d6a83838,ffd23f6a,fb944bc0,57fe7f1,1d321a0d,2152568d,91751d99) +,S(3b7bc8ac,5ba85b40,2080612a,84e0226f,3b43c8de,c0e54b6e,ea779b76,812782f0,8405dedc,a02825f3,5a60333f,190001fd,98ea3995,9dc6e61,c28c5e2e,5213fb0e) +,S(2a76b67,d197e7a3,7a38bb10,d49d523d,c4beb4a3,75336974,7e22e407,9e0310ca,6331389f,b9cf9fee,e89b089a,95abca6b,a3c2aba5,38725c1a,6848fa46,997d0e87) +,S(9938e808,77c2baa4,53e0256e,d250439d,b11732de,1abf7555,949a7574,f62819e3,250b061f,bba0faa4,468a080a,fee8264c,f72fc12f,2ac91dd7,13ed92a1,1b281124) +,S(7366eac0,7e5e4573,333291,3e42f111,e53a78a6,5069898,52db2355,de089230,b8dfda33,31646343,bfb60b2f,25050967,e735861e,1654f0f7,ff42ed9,5dd652a4) +,S(10fc632c,cab22fd3,2583599a,a2efaaf1,6e1b01e6,a5a96c59,50871012,33022152,cf53d9ec,c74aef44,7019150f,ddfde494,c2382a07,b2dfd73b,c628478f,7fbae0eb) +,S(785f4da0,240de52d,bb50b1bd,bc53994a,47318076,9a1fe06e,5a40a8e,e677ce63,9b5759d2,f77bbb9,e40ac169,a01500ca,6dd6bd70,6a003871,e7ba4d66,b32db9e6) +,S(a7f20615,593850c3,27aaa06f,c03e0d46,d3ff20a0,9b849810,1759638d,8cbb9cf,13b9ebb6,f0cd59ef,54e0f935,87a14fe1,2337e346,94f5e8f1,10323fbd,d7604d3c) +,S(cf083e4f,e0ed4444,85dbd99d,8e6823bb,483eb749,b94ce672,8671de8,6105aa4a,36eaa305,37378494,17050dc2,8290c74d,d9ff9df4,cbfa434a,2b89de00,e06f3099) +,S(9fb8c370,bca485d1,dcadc251,ee906f58,6f3e177,be37baec,6912e535,f5c7ab0a,df5cf77e,1ad07532,7150136e,7ebe7f35,1db47415,74444b24,e9cf2f4f,31ec683c) +,S(ff9e2f29,170dd456,2c94d48c,eeb0390d,db783702,c13574f,8a8c6a79,6427adca,784c7b68,3c824603,5077911f,957aa33b,47534180,d70a60d9,f248b860,736a24c2) +,S(802343c3,e07f9f9d,ed2ca436,3e455427,367b852c,d23ffd7f,fd690eab,90b4162a,b093f0c5,f0fc7d01,a5dfb7f6,bf9d90d8,8595140a,a13fbfc0,f7d6af2f,54ff5ce0) +,S(ae74ed87,11a1a684,9e558e05,47ff8f9b,f6337551,1dd3d272,ee0597fb,fc2d6914,c304897c,e5afb5b9,a383cb64,e85071a3,cfbb2981,93ea6ce0,55257ba4,cf15bec6) +,S(c099b05a,dceb601a,14892c97,7b267152,f29ea71e,fed6090e,7267249e,43c2390f,6c3ad3eb,8c95c72f,e0030a7d,34329945,fd1eb71d,8c4aa1f9,8fa4656c,6bef067f) +,S(97c6949,a25581f5,945814e9,9d590dff,67d936d5,94101005,4cac33d0,fb3658a5,cdc7faad,5bc387ce,a16a10f6,6971e5ee,6d32756b,596adc14,57081ad4,1dbd2e4e) +,S(14a19edc,a1ec89e9,524548ef,cf3dbc03,81b14b46,928f7425,87b11df1,7aa721f7,f83c4d0,aca08709,63a017b6,8db3434d,6088015c,2ff1d8bd,739fd620,35d1a19e) +,S(4742af63,c7597424,e6d04a8c,cb43142c,54c5b350,175bf5a7,27c39820,2187d00e,bb1f2f72,b21e15f,ec17af32,2147edfe,1ca80ac8,3e030dfe,8be39fdd,f340c56d) +,S(a6597869,4d168b00,d9df41de,fcd48ae9,68313394,db683407,330ffae9,f2559a11,6bf65c42,13317a5d,fb561e8c,872c8b1b,90bdabc8,8a8d2e1e,39919f8e,5043ced3) +,S(9e62e468,1e22abde,4d7a2fa1,2f7867f6,ecbfc15b,54990e26,821a8cde,fed76985,4877297b,a64fa8ed,c039ab1a,e62ac72d,8d7bbf05,7513d1,4237b8dd,9f1acd37) +,S(d24333b4,de55b0f5,d47c72e4,88cee8ee,8c960903,260a64d2,c89bca45,db7352c5,688b20b0,617ac12d,5be38fa2,ab52e785,69766a83,2d8b44d5,cfd6ee88,b19b9f1d) +,S(d203301a,13d1c8ae,a8c79007,1ef8116c,3916bb3e,dd5110a7,304b9145,465be838,a606dcea,398dc313,e61c8fbb,dbbc3874,3c103297,164e66a1,4412a21a,5319e55c) +,S(d1aa98ab,7010146f,16a9d6b,cd911535,2595bfa5,1bccb3d5,5e3a4a87,62666610,3abafa4,999294e8,80e3fae9,edb4206b,9b9786d,bddcaec,e2d01cf1,ab715690) +,S(1e20823e,81051b2,65535085,9aefed6,3631dbe,23b4e79,abd3c17c,21f053f4,e238adb6,86592008,f7fe34b9,9b934060,15c323ec,55981b27,85feae6e,5fde7186) +,S(d878afb8,8527a861,4b4276d8,fba39300,72196017,6f437014,980b7bbf,d4320ffc,7403107b,fca8ac64,baa94a4b,128e72ee,4a015675,845519ba,d5609331,1680e7) +,S(53f86d45,61deef96,ca88a685,38fd35ec,a95740a4,3a52c601,faaad0c2,aa3ab72f,667a6ece,bfb97682,c5e9e5df,b6d29156,9604f63,d9ab00ab,8cb10000,e6b01514) +,S(20990660,f1055420,b885fb0a,38824740,3b141c37,5aa20dce,8a29191a,e77bbb16,7d434476,9e302e38,9e14c02e,f5fd8a5c,64cfcf3d,e9813f1c,f53bc6d3,4da93559) +,S(1e70619c,381a6adc,e5d925e0,c9c74f97,3c02ff64,ff2662d7,34efc485,d2bce895,c923f771,f543ffed,42935c28,8474aaaf,80a46ad4,3c579ce0,bb5e663d,668b24b3) +#endif +}; +const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)] = { + S(8f68b9d2,f63b5f33,9239c1ad,981f162e,e88c5678,723ea335,1b7b444c,9ec4c0da,662a9f2d,ba063986,de1d90c2,b6be215d,bbea2cfe,95510bfd,f23cbf79,501fff82) +#if WINDOW_G > 2 +,S(38381dbe,2e509f22,8ba93363,f2451f08,fd845cb3,51d954be,18e2b8ed,d23809fa,e4a32d0a,fb917dc,b09405a5,520eb1cc,3681fccb,32d8f24d,bd707518,331fed52) +#endif +#if WINDOW_G > 3 +,S(49262724,e4372ae6,f6921b82,aa4699a1,f186aea5,40122630,3ea42648,97c2a310,1337e773,bca7abf9,5a2cfa56,9714303b,6d163612,a75ff8ce,c41b681,5e27ded0) +,S(e306568c,1a240c90,d5e253b3,e477e2f8,4dcc1a56,ff06db8d,1384b079,cebd2d31,eac6fe3,78934260,888f2b10,7f7d0db6,ffbc8042,be373826,692b4083,92546e44) +#endif +#if WINDOW_G > 4 +,S(3b9e100e,2428cefc,271b0e76,23fbd633,74ebf8d9,aab41dd9,c530c39e,363136b0,fafb9815,2d16bb71,df1533eb,8f475b26,a2ae28a3,3ad31f81,953ec16f,6cdbbc8a) +,S(bb0aad49,712ac9a9,2b76ca80,f5dedef7,17ca0768,8107beee,9608f047,2f485d3f,ea699c53,c5835479,8ecd201f,7297da34,895a5afa,31670bff,e7939250,3ca2f975) +,S(79090ac8,e4eefcc0,d4e8eb19,7afe0113,e1e58b4d,b01123de,4aeed33a,36718dc9,eaab722b,91905b8f,13d816cb,cd9aaa56,dd36afb7,ba9008b,963322b1,1cfae7c5) +,S(e77c81ad,e9f97b55,1c03dbbc,e549ba66,8dd71de7,cd775ad2,a269694c,7f60c7d1,3acf1478,eef81321,c5fc3b32,3ea81543,631470f7,1c2986d3,4ec581f2,82d72449) +#endif +#if WINDOW_G > 5 +,S(de2b5ce9,dbce511c,f2d8878e,3ded87cc,3d633dae,a2d45341,501fb3a4,55ccf6b0,f10576f3,d3c3e0e1,bbf717e9,8b1a3744,65b8c45a,c66318bb,34829eb7,11100666) +,S(d07bddff,d491a2fe,1ea59fbd,7c121217,29659ca5,de46658b,26b1460b,13c03c56,b2ad4708,cd3c97dd,f9c40e2,a1de04d5,61d963ff,8cc2eea7,6be3f60c,2b405ce7) +,S(82403e7c,5d3016af,3765ec4c,396ce8e1,f8da45c,434b8257,10edab41,bb6a4d51,d09661b,e27cb767,4456badd,b3e84051,99ab6ccc,4ec67c1b,11e92ead,7b463b19) +,S(eadc3131,fbd626f5,263faa58,c4caf4d9,930f933d,9541c23f,438cb486,750680cf,d3c977b1,c9b4a897,5c64b36c,972d5d01,a388fb9d,c3791a74,36094ff1,2c87a914) +,S(3903ee5f,6758ff24,c518a4b3,86748f4f,36bdd65c,b77e78ac,609f2909,fc7987d9,e92194e,a15241d6,40915934,bd234749,8d222a18,4927a8da,b0cfe2ae,182be83b) +,S(d0803b78,39ab48a3,8475bdcc,f9a9f219,5759c343,dbbf8e93,23e1f882,5be6a5d9,2cc3b180,ff29c97e,a12ec15f,b38bafa4,4ecf06c,e51d1d24,2894a926,64582f0b) +,S(1f56f096,b18a7499,a153a5ae,acf8be05,8496dd23,da8e6c19,215628fb,c0567ed0,fef22b8a,3b52f490,83004436,b65cd69,c94189f4,1a93c0d5,1fc13cb4,379dff58) +,S(1d9f69b1,a4a47432,e386f525,234aa30,79e947cf,cf203297,4e0fc05b,638e213b,d898ec17,949c0761,b38500c3,a2b1da24,5438d5b3,d3f6f720,41f15d6e,e4d4ccbb) +#endif +#if WINDOW_G > 6 +,S(128c913,4d9dcb78,12fc4361,5c67ad0,55213354,dc8008b1,aeb5a9dc,fb629efd,fee3e54a,dd152610,d9725936,99d662,c160c8e4,ec6f76e4,5ff41818,be67c96) +,S(21ec012f,5a95b94d,244b8d51,9756075c,301f2854,8e2c51fc,49c0e3d9,d1a9685,2def2105,77af497f,4c7fef71,6949f28e,7418eda6,fd5fc162,d128de19,3cde08ae) +,S(688f5202,fb9d8bc0,9e480e89,4c7cfc74,761c3be7,7dafb11c,58422836,3e331cc5,96ba7d59,63b541a7,2ec7cabd,92403434,1a393eaf,89eebd94,62d9c218,c7302cd3) +,S(fb5c9eea,1cb9a8f5,b3314c30,a50d35,744d0ef,e8bbf68,2e4d3ab4,f7f02baf,29fb8844,e18fc551,fb28bd26,95c5e95c,6868e0cc,7e526af0,91157e9d,fb630418) +,S(f1479fe2,2eedae3f,2f5f6a5d,84a9de1d,593168ec,7b52380d,e0b3625c,cac03421,1a642d5d,2fd88b82,13b50d1a,3fbd3419,c0b4630c,48352131,cb856b2e,22764606) +,S(2273edc5,e8199774,93c5b0e0,9fe0effa,f60f7b,2898565a,69f5c7b2,bf1a7950,b3aea238,8fd978d9,29f1a1df,98495358,b64691fc,4f50b530,906ae39e,fe7bda12) +,S(99f8480c,30504378,b47d10b3,2b39da2f,496d59f4,b1462856,56f05ad7,9bef5214,e001d55d,8e224286,8d8bd397,cb5aa99e,d930e437,e4e62151,71da7ae6,6264b2cd) +,S(382257f,e4751280,d74fdfc6,993c8642,9c000d5,87f57635,bc9656ba,996a6f1f,c2dc733d,fe52cb06,265a4f1d,a6b5f1f9,30dbfa39,e3659973,1c672aad,8b51d474) +,S(23a13632,9125386b,e45f4e1b,2acc847a,62e5eaf9,f6d5f452,6e145e7f,ecefb24b,9129777e,643ba22,2bf817a1,af7155f1,413cc370,3734ba6f,49f15f55,996854c0) +,S(6659ea60,58a664de,a35791a1,8c5cded4,8cf5593d,c440b9d4,8a30ac35,79149f0b,2adcc705,a85d836f,b347b69e,742fc6c3,5300d1d8,e534f1ff,c820c6d6,b2f2199d) +,S(52dc3bc6,e1acd3b4,7ece6f6c,89fd2a3e,2899b487,41421033,37a67dd,1ba939fc,5daeb346,32ad107f,bd83d9da,15a3c4ff,1e8f6ba3,ee5193e2,709e89c3,43d05746) +,S(524b2a97,93cd5745,bd9189ba,9c947bc1,693fbceb,75f074f6,17376b10,d5573551,9e8099d6,cb23fb1a,9deb92cc,3e8a2fb5,a6865ac6,3dececa0,2d146e1b,bcc80b71) +,S(732181a8,e2bc5953,923e6c3d,d960e9b7,525b7b95,e5906997,6fe79156,1782756e,2516c6b3,5592eb0a,42ba193c,bae98ab,e3c42d96,148f1d84,edac621a,722e4823) +,S(b8e8942d,926e38fd,f338496a,c2ef6fca,49a7ae3d,f76eb15d,8d570111,e502664b,7990d56e,7dea588e,4d670ba2,2031e6c7,97248641,69e51d77,f792f5ed,befaf8eb) +,S(144e88f6,3e73abff,72cac11e,7ddccf79,19e744e6,278941ae,18d1b797,e098e4e5,63cdbf3,5df3c655,c58197f,ea54633d,158705cf,7dc2eb3b,4e09f83c,3021837c) +,S(9436e3dc,489ecd8e,2d16a739,c9c73e3d,60e5bc93,68157039,75b8efbd,5c3a9081,1460531f,50cb6ebf,d1aa7806,ea84e7f7,8e8d76b2,b3a66d5e,3a0bf60,39a7e59c) +#endif +#if WINDOW_G > 7 +,S(9d3c2561,7a56d10b,46d9b01a,1710d193,e840e005,df669e76,1936c275,20890db9,6bbdc0bc,4c4ae9bc,c2dfee9b,82da9b94,1f89ffcd,e8af2aca,4467ce3,78521ea3) +,S(29f98e50,f51b7f8b,e18c6ae0,b453c4f2,d0aca5a8,b0e61d2d,dda8506,3fdb76c8,daf3bcdc,ae8e031c,73eb8b21,14058063,58a6ec30,ad379186,df80e3c7,f0e5d28f) +,S(d67d30c2,c71daa36,1805e31,1dd6046e,17a89752,94d76e1a,538af074,4dc22c94,48b9b0e7,12c807b0,b92e690a,a2e068cc,e87ebbbe,aaf4bd96,9c1114bb,a54f670c) +,S(f22c2ba8,8ce9c2e4,b772c9b7,6d03a017,59aa7b9,97a78334,83566027,2fc81649,6aa9e710,f190be16,243a4e0f,1570270a,2d92dca9,8cf99a3,cbc06fdd,f9b7028f) +,S(c5e718d,6b94c83,e52533c9,ef3234f,36b722ed,cfc074a5,eff30969,9ac5f894,24961051,ccfc6619,dd64e810,fa9c504b,f7f8ce9e,cc445d7e,642b3166,eeef436) +,S(26a8bcaa,c836eb7d,57618999,ef87ee4e,c291dc8b,333554a2,c1f66f73,7944d611,c20051ba,7236663,ace2da29,c1e0763c,e57192d0,e199e7a6,c69cc65d,bbbcecc9) +,S(388e3570,fb7b1545,9bf01ba1,7a6496d5,6bcf65e1,764e7aa,2c083346,2dfa098c,2d4e0d22,a2eb0ff0,545561e5,ae344be6,99120d12,45db6bde,a9500f5f,a07be798) +,S(68189bab,b5a0783e,23227efa,4eab2c6e,da2d1c,2ea57fca,7a7f8f72,15250709,bd30bd83,3694d3fa,a14954f6,251445f8,3e42d517,30d30855,a0eb834d,3c7ae856) +,S(642e0823,bb347795,967b7aa9,418a25,ea6ff683,fd7b3d42,b88d90d1,292190ab,db73dea7,86ec052f,e3674892,639daf39,286b4690,63b68903,210639c7,f3b4000f) +,S(9ab6ea81,e5bf5505,751addea,5896afab,7f4eff2f,d3986027,f916835c,64924afa,38c06aa7,4870a5e7,2ff29efc,bce4b3e7,dd951c9b,29966f2b,47d007ac,7629bb6c) +,S(b09805ae,e567f69c,71a98248,e89e64f9,e059e015,bde01a62,dd18158e,e94a8ee7,62aea16a,7ec912ef,cc5382eb,6d220ac3,dea885a8,e3da12c,8147b28e,1983d221) +,S(3d632a5b,636ed5a3,4a58bfbc,9831691a,91d6b5f0,975bfb5a,82b4c1bc,107e6e5,577a449e,75bf16d9,2eb6ba0f,9cb4d496,7a7ee09c,f1605aef,682cfa31,cf395a1c) +,S(6b821bf0,f70d5ff2,ceedb69d,d96ac8bb,b51e3635,3a36d50a,b1c1a697,40cef707,5212ce11,993fc120,88028674,5cddea94,6371b4,dfa2f47a,6d83b789,c6d12e5d) +,S(bf294951,4496fe0b,8527740b,5cd9394e,dc33b330,c91d996c,789db854,45728b23,790aede5,da35ce7a,343f745c,410de38f,4c53bc2a,bb41bbae,c13272b1,e912782c) +,S(a55354c3,82bf968a,16668267,c4498946,4906f69b,114f6f06,742b6035,1d75ec80,2809bddc,45661a5f,28b31967,6cdfb5b1,9dd6d296,d1828c88,179a630c,ca5962e8) +,S(fc015036,abcd8311,bbfa1574,ffb4980f,b893f8af,84f519f4,5a6fa344,2649a693,d0f6a278,1946e04b,385cd004,29acd3f6,f5542aca,3e7c789,657f676b,f19db819) +,S(6164410d,9f81f352,272a799f,b4afbe24,59caea6c,511fa4ea,b7578980,d9a7aae,92bc1480,ba19fcd,3cbee69c,95b9396f,4982fff5,d4e7dac0,abec7153,ee5a7966) +,S(ef816535,8de9d737,728f9a9b,3182b4f5,6e25917d,1ec05fc6,faa0fc85,170b5f2d,dc372426,403ca9c4,50649df8,8b6fd32d,f1721dc,cb1c7d7e,155c83ea,747ec595) +,S(428c34b9,89a436dd,dc704e68,170d2c40,178c5646,841eb2e2,642c0a48,8987a8ed,b1f24158,251c4646,ca04dc3e,64369634,3836f97e,71945f4f,51237abd,3aeebe06) +,S(6eb61782,f909157b,415e6243,7bebbd6a,5f19da73,7eda64a5,5acfe206,65417a9e,4fe7c546,baedf2b1,6c92f168,f99c42f6,af03edee,290ecc39,4c4efff,e8577b72) +,S(992e0af1,466d4fec,5ef83009,98ce31df,cb6f9573,d14c1646,e4371c62,a376fa4b,d0e3da69,1e4396b2,eb01e3a9,964365,50d000e6,31d79ae3,871690d5,29f9e825) +,S(fedb564b,adc70078,f20f31d1,12496934,513e9903,8cf5b9c3,1084383,5721d11,1a8e2a49,57e8420c,f2d5d97d,657f1602,ba26ae87,d5408b2f,a9448def,38157a39) +,S(f3f2068a,4dd89d18,1247088d,3c424916,3e683226,6274b575,e54430d0,73b24bd,f2aabd19,a7f462,1426ab1e,e0aa7e33,12381c5f,e1f1cf0e,75c1a7f7,7ba2bfa8) +,S(32b9225e,4217a359,8de4e7c1,476a8581,5b6aa458,d93dae02,b3d30772,3ca13680,7466e804,26856340,12985683,dd071e97,53246214,733808a3,96f35d0e,5a133802) +,S(85008a87,385ed6b0,4ff89979,2eb592f9,ee6c6b93,fa24dc7f,c6299b9f,dae64a8a,1f279e2b,8a5b0576,fb9569f6,c0825876,84b5b38f,a250e362,2ae6e284,a504a2df) +,S(4dac7833,ebbeab0b,ec8edac7,cfc49bfd,b835362,f0130e9,e44452f6,a82effd4,fc9d1970,f230aa68,6114ada5,7b4237dd,133dc3b5,db8ec1f0,ccd09aa,23c740a) +,S(9b755881,45a65d54,19b40226,e535df5b,4b44de41,1b93d71,31f3102,d56dbeeb,d0324171,d6937b7,c9b38290,7dbba3b5,c1516061,59e7ce1f,a1ed9d11,e089a02d) +,S(1bd6ceb9,2592a7d7,a66e6e8b,1b645db5,98b525ca,461dc4bd,b583ed9a,cbbc8bdd,9a59de87,84a98bea,48b7abb1,a5b7055,5a1c4ce5,551cde4e,7b790ac4,9a29944c) +,S(25a8b2b9,3b360941,6525b08a,7fe786e9,6b3a3c7d,8b444637,268f5355,bd5b56ee,3c58ccf7,5734687f,dbd027e6,3ec6c550,45f131ae,df71a40a,c45e4e8b,965f22ec) +,S(244b2833,27c33efb,221a5767,15225d6a,bf5a1caa,8da543c0,d88b21e5,17ed9f5f,220036ac,e48d8953,5aecec92,a29f5012,37f83ce6,44380db,c229f0bf,c1f53d7d) +,S(6f97ac0f,27b87905,6b442d13,e566978e,91f0cc1d,d6ac1e64,e9764a35,325dd1b7,83c6e70c,fac6c707,226ce1cc,691b38a0,7e937f5a,5f2d9c81,4dd0d3ff,9f433d32) +,S(72c5d60f,eb014e2d,ba8265ca,d454f261,2d6abcd4,b2236bad,c94c4801,561dce1f,e3119a19,7ef91963,b3b28216,3c5d3acb,97b281b6,d246cbf0,690b40da,63978fe2) +#endif +#if WINDOW_G > 8 +,S(a96d2da0,1b10186,6998659d,f441a1b0,2af32b94,aae8c6ea,707d9ed0,d5f33825,660d7d83,5da5235,9f7cfd41,28c370aa,5659ea71,16a91690,6c0e8108,a513f9f) +,S(2cce6f63,4d815ecc,1981d200,87616677,d906aa27,990c4875,17314dc5,5be3c4fa,615210dd,bd599e91,1b6f997a,fd05475,b33cb274,c9ecb6e5,d3c23323,beba4b50) +,S(992b0084,525dd399,d98602d9,8b8d53b2,4558fafc,758a2f46,60e89bd6,a645f0c4,83ca98d2,26545a29,8c45f40b,11420602,f5a5c70e,595eea57,2da64d61,a4e2f98d) +,S(434efb45,3089619f,cc761ee4,3fd4b77d,c6b0c69e,b45eb88e,44ef766e,9beb7357,3dbb0d6d,1c0b92e,5965586d,236c0be9,26967ac8,830b9bd0,1e9efc2,2a9291ea) +,S(a2179ad,2c683306,a2e4735,93efe304,f0dbf589,c4dc2b88,4bddc5c7,e3fbc156,ee4539f8,ab980176,a18e6dfa,bdb609d2,88a2d223,86dcb20,19207afa,f6033c1f) +,S(3934081e,d3e1e147,aa52bb40,9221ef6,a445f22a,66718f14,6d63907a,ef05a2e1,bc370656,31391b7a,209e79d4,9f1e959b,d3a9fefe,752c6062,14fab290,a7b5b3c7) +,S(35bc24e1,59a2b939,438354,6cc4255f,f1f3f7e2,105293db,39688e07,df95d8ef,dee1fc70,a9698da,f7abeb5c,56724f8,e87e0cd3,8849edfa,246ed0a8,9223ae15) +,S(f5d1e75c,251fb473,8552a0ee,f05d8e65,63aa14e1,bcae5b48,bc7e5258,b948127d,e260c1bc,7044f058,8f409134,d298528b,e7d586f4,bf7b6fe,92d212a8,6f7170fe) +,S(ee0a76d3,6fed282f,a1170dd,6acb7743,f9617bb3,60350f54,d12da1cc,7eb121c,f8cfc2db,eba6960f,e6135ef,ff9e10ca,4e56c458,4b42b516,6dbf7af1,420ba5b1) +,S(9e3b87cf,78927664,15cab377,f1774d14,4d1879f6,16da5676,f94790d1,9ca689d8,f8f34522,da3ca2ac,b273b0c2,b1b1f26a,7a9c2d96,b4547482,266a8e6d,bab3b577) +,S(e26f256f,d08942c0,3c85b89e,e66b8b50,12f409c7,4f625152,86e5b310,eb4868f0,bab3c4d9,6fea49fa,6d08c656,23c9b127,3552c23f,3c4f12f2,1bbe8bfb,56f210f9) +,S(8ac74046,a5d38398,d14b6763,4f07abc5,a3f5c852,ea8c421c,f0858980,11da6c2,d20ca793,f56e3198,854f5916,35402c2,4a71af95,c84288e,1495d324,7229b3dc) +,S(5b00e095,634694cc,93d531a8,6e81d29e,753928bf,b2c83a83,ac677a92,55932bd0,8d2f267a,8071c48c,616daf18,d587e,42882b33,748032d6,4bc3efd6,60a99656) +,S(162190c4,80c5d7b,ab1ae4ba,7b2a6611,546ffb9a,b4e9ea87,2c0357f8,9e11f0b1,db5e2104,12448a9c,e586d7a3,13bdcc6d,bb84192e,98c5d9d8,79693030,92423525) +,S(f6a84421,b4b383e8,87f8520,e06017db,476774dc,9aff636c,f26a676c,85b145b1,504c71a9,596770ed,7a2da8,2e8fe1ee,93717215,bf88e0a8,ed74a80,4037a3b3) +,S(1f02d142,f0b5d3d8,b3f8937d,a49f908d,83e5919e,55c9c134,55a759a9,932dd6e5,e6a5cb33,8ed36df7,50ec2eae,5db7c9ff,fbc9035f,48ae0348,fb3882da,39863e65) +,S(61f4d96b,c326a1fe,a2ae38c3,73484a56,68e29bf5,12d77a04,34a62278,1d78899f,651ef738,62005ac7,64f97021,6180c25e,2172724b,375e6b38,b3a37ad2,d7b4aab8) +,S(ba7d5c0d,623c5e79,8088a71f,8d2916e0,7c7ebe2b,1afa19c1,9c917cae,31c11616,da409f40,d7e3f6c,78655153,fb35595,a1ec37e7,e66c8958,ce45b07d,bd5f5a51) +,S(8b90a590,eacb977c,6e6a68ee,6dbc3e19,fe5a92a6,9abc43c3,bb16f9d1,925bdb09,a5cf5f42,ef655d59,ae734e1,f746a752,4d01ef75,d829b9a9,2a035180,fb5df718) +,S(87f35227,21914cfd,ce8294a3,cb5ae171,f0d994ff,f55b25b7,1c9e9aac,dff4fe4c,cc71d1af,530bc5e1,eae7c1ef,b9a91335,f26b283f,222a3552,dda24c28,64babb2f) +,S(aeea4d36,ba405159,bf0ffe8a,5530f1f3,83d5509f,187ef58b,6c1eee4a,cb77a15d,db563dea,e7403df8,7d3031c2,48aaa28d,96958f7d,ce36b3f7,8d55607a,60d3ac1a) +,S(300fe98d,3996eb9d,57c6f1ef,8058d4c,d8dda436,5774edb6,2a338a59,afcc7111,d148a017,8fdda40c,f937913c,143b76fd,d2e6e226,d27225e3,a49658b2,38c40e77) +,S(c700af5e,22cd146e,839095a1,f6743e4f,d01e9c1b,76d4c73a,a5005f42,99c19fdb,3fe00181,b1f01c27,27ab1fc6,bb6ea569,d4a3092,c2d511d2,8b5546aa,194b32c0) +,S(d03d08e1,17b94138,1aa147af,38448539,94228f75,f96bb4a5,941c3748,cf50bc60,5b119ffd,2785bcc5,2e0bfbfd,c541da8d,f47dd076,e91440fa,10e071b3,a896e31d) +,S(6c6710fa,17a520b8,56d7fadb,6af81a5f,ea9c983e,c94cf832,b395da5f,c22bd361,db4efd26,36e281ea,419964f3,c0897b05,b036a408,25ed4ad6,4fba393c,f2804941) +,S(d7b5c239,9df47a16,6b6cb900,d08a5d9a,5ea3bfe9,94f861d9,b46f3fbd,a3d91bbb,ed791f4e,4ab1c25e,9c83494d,794ffe1f,a3c8a065,29c0b710,cffd597d,64efe8ba) +,S(90f699ab,8f728152,e2deb8dc,ceaaa3ee,53ff2f23,2341a952,4aba9e8e,50f66c06,8bd0c3a7,7f5312bb,9d46d80e,c36921f8,561558ce,6e63c08e,641c82c9,fefce91d) +,S(4d0eae3e,3d7adc34,c91eaead,6a16f569,37557dce,2b68744a,bb9ae71a,8dfb65cc,816b0806,a9508731,ba99a685,142aa52e,6e874c99,5096a53,52c6e2f2,1fa3de5a) +,S(46cd9edd,ec318498,dfb4f815,3315185d,689a2399,8e06b1d0,2438f7c9,b2f7de62,3b5bc1a3,d5fd7874,8c964a8b,b813388b,e0d5d168,1247d008,10a846fa,561f29bc) +,S(4aac80e,3f6eaab7,1c576297,b4552e40,653748fe,21a580ae,bce4eb83,2ff730b,3d42a00d,8014f46a,80fe2dd5,bac6a046,40d331a9,4f1de050,9e435398,6c8c7954) +,S(59bea661,b73d9c09,131e4573,199937a,e03e96f6,2ecbc637,4bb681a5,582a4114,31a20be8,ee8a2c2e,81d062e7,8e891504,d9f2639a,bd5db5c1,30be3d2c,b1afa47d) +,S(7fe9065,88b2ee92,2b19acd3,fec7a4de,9ee089a4,a4e1c338,5e293567,90ca6037,dfb45d90,c5f43eeb,1f5eb326,20763ff4,2659b763,e7ec72a7,c69e9369,35e5c128) +,S(db390f91,32277889,784b5e4a,cf8f2fd1,f3a5fc47,f2c8262f,19dc9518,95322157,4364955b,241c831f,94fd7d4,da63db19,2aaeb5c0,ade82dc8,d5d61cac,d690bbad) +,S(34dd0266,e5fc19ac,7daa9e61,5ae8f78c,985732a6,1c53c29,e6e5d407,7391ebc8,c2d6b6d8,e73fe00,e6013b1d,2c2b48bc,77a5db6b,45232ddb,6611ea1f,c5dd797b) +,S(eea7f72b,7e31608d,d3dfcfbe,16e2ef95,5e6c7ec5,328f84db,336e3df1,9d1772ab,9662c8f1,ccdea4c3,48ea6d94,739aa747,17219556,c6be9b8,8af0d30d,514004bb) +,S(c6af087a,f1b10eb3,93de412d,de856129,9376d264,36d907fc,10d3e7a3,88c391f2,ba99d62e,31856457,8ad8847a,9cfeaba5,e5ff9824,2c614959,eeeb4ae7,50825144) +,S(eae34735,6c715740,ab73d034,bcb43f5a,aff37fbf,50d35518,1364c999,feccefc7,b9386c75,da8bf645,cd6f15d8,4944f74b,9685256d,b61fda98,79fe6639,92fe4703) +,S(4a548c25,f4d8f54,4f9a27e,64e49626,41b68ae3,1d90461,65c24ff7,fb40438f,ae9f2c85,bd608cf6,ef5e40c6,7e29a63d,4c274215,c2a0d578,38252f28,196f6d10) +,S(61925679,dd6545a8,ea19743d,7cb3c0bf,453318d9,e180da53,f43af2b0,ecf744af,a0682d84,d7215372,e9ec062c,a3e4aa1f,47fc551d,44e3d1a1,7260a44f,2bcb184d) +,S(e1db5e86,9574ab76,d4fa260d,2425ef62,50267ab8,52ff04fe,25f0150,9137ea2a,c8eaf421,9fd5f7a3,6c1a99a1,d0c61250,836e204b,fb496774,83f43c81,511905a8) +,S(3062cbca,73923842,2a0ab862,a1fd84f0,38e63691,cfc204a7,d2f9d263,d248c7f1,8f112e57,e3f2970,dce89eee,1e184310,721a85f1,cc9feb2c,f55c047f,dd9670cb) +,S(67c393cc,aa9736fc,eec7a861,eb53f953,9da74ff2,97764f4e,4e814004,4da4f739,93d329d0,9a165fe2,2f8009d5,ad59b524,33ac24d5,46c7d394,2d147c4d,49853203) +,S(c67471f2,36cf2187,ee5a5619,d581cc7d,ac5bc5b1,e8bb728,f943084f,e899bf5e,75c90c9c,787b318d,943c3247,74cbbcc8,3a533f37,fb684aea,62fe6848,8de2c513) +,S(d5015fef,d5938dd9,2133d7a4,25aaac5,12143acc,6547070,1827e98a,e4ed1b52,44305616,a02236f1,5c37c0d6,51d845dc,e9966860,b798f79f,4006c25d,7cf03d6b) +,S(aebcbf65,aaa89615,cb48ed56,4002ed9a,243ca309,1cf503b7,3c1929ce,8164f2d2,4fc1f25d,1a30ee2b,4220305b,a9c88e86,a6ee7f55,55399ee5,35e7d37f,e4b3f019) +,S(15cb1617,1727deef,49ad6821,932a39d1,bb8f980b,b5370d81,5ef00ff,ebb30e43,64ad8c82,87fc053f,ee35c1b9,9734b34d,2dfff86b,490ead93,b1fe7d2b,f80ebd7a) +,S(d404209e,8530d674,9bb88a5,525211a1,19fb2523,63e2698,6bd03080,4c49c123,3763fd68,fdb85d19,e8506275,3b5a327c,46ef87be,8a3432c5,62bcc622,40a7a128) +,S(f3abf8cf,c232849,58e330c2,fc327ac4,d40b4497,f422aa4e,d42e9381,9bffdd96,50861f05,d831327c,3e907643,2d7a7621,d1dfe9ec,7ccf2061,cc720e9a,7d5b0d5d) +,S(78a32893,2ee9dbfb,3f84755a,651b9d23,5cf92b46,c3e4bb4e,57b7ff6f,7c874dea,925b783a,966721f4,6eaccd87,495eab7d,b3c36eb2,92c1a473,b4617f6b,9ac85895) +,S(8165210f,5d146f8a,1ac1ed91,a7bb678d,1b7d15e4,3ed55e8d,f6503209,a750cd4a,fe390d3a,19e22bdc,cbd45875,e396c713,85954166,a1edb63a,384b8587,915d260d) +,S(75269de8,6c2f3d34,cdf17dd6,f3efa198,ba73431f,cf0072f3,633ca57f,7dfe3f09,b162a65f,d19927ec,4446e3db,d5ee8850,f463f39f,1df1a0b1,f5ed153e,704805bd) +,S(5e36ce8f,b393949e,5b9c4e10,44fb2ff7,c520a7b7,a9016b38,9544e512,427145b0,7c40e718,292f96a4,1d9822ce,d54aea90,22074c5c,c82ba4e,7d39a4e0,7811614c) +,S(c8cc7129,fdebbfc6,c0576edc,6ac983e5,c249d360,76da7d25,b05c0b6b,16632746,48a8cce3,a77e4498,76d1a332,c539feba,2653fbaf,d4f75e68,e4674d78,4c716fb1) +,S(9fe1db36,f1ee3e6d,3924d2a9,ae3ddcaf,fa85798b,7383a1dd,2d6c0c14,ea46973f,1d35b6a8,607045c0,95ed9658,80212b63,43dc55ec,beb3223e,7c2e76ce,2c74f6d2) +,S(4ca8ab8a,3d45748e,6e19e02d,dc351279,e23648db,d26d2465,7c9713f5,bc8ecda2,8a5866ad,9bb7db92,273c9f23,c0876c95,13b8a68d,bb20c5cf,164a9a39,4e3e73da) +,S(c8d0150,e4a989ec,5cdbc724,21b1e29f,f1f30818,1d8117b1,3d376f58,b72060c0,5c5880a4,c5a73a4a,1ae42a9d,f0b20032,7ac4a732,cb26e717,49e63365,5082ebd1) +,S(3d61557b,b4b9fde6,49fe1b7c,981c9883,9e368444,f130bfea,fc1e1a0c,12f2aa31,933167ff,62cd840b,3a960c90,e6b1c37e,1e233695,318ea286,71c87992,de5b56f9) +,S(67569f9f,fd44ca09,5b478dbb,85c3ed1f,feaadaed,cb624552,ccfaf169,24e69e2a,62bb2948,230fbd2c,aa941288,7adfb24b,d16619de,af0fc102,feb1b26d,67eb7fcc) +,S(6313d13e,debf1401,eb7d279,2c66daa8,6e3075d0,3cf0daf7,f3b753e,7372fbc2,44621230,50eb1245,86975455,63e06e2f,2839f874,beaff9c2,f65e26ad,d3573ef3) +,S(6f8ec9e7,fbbe6e8c,d0e3085b,47c6cb2b,88529f2,15f13195,5e2fde24,4dd23968,1fb61e14,523b3fae,b543b215,dc46eeeb,23e1950a,8301c78d,c510c76f,ed36cd79) +,S(56613dac,3c5aa1ac,bd9a0ec2,f839b4c3,36f0ae58,e0e02244,7bec0546,710b7f6c,247263ab,86c398f9,3b23319,4434af8b,530908bd,dd7f716c,f7b73aa9,8eca79e8) +,S(c9de15e7,b4147219,137e6e57,c5a7ddd6,17e91ab0,6859dda0,41eb3c21,87aee08c,c7178ea5,cfa056d0,dfd11c87,715591cc,40cc5db1,f5e4b70f,d8ffbfc4,3f8b0009) +,S(7590a4a,627d5e90,e42a4b0f,6be6497a,f906182d,d2dddc48,a8b6bbfd,f56c0504,d611e21a,b5498760,5c97e878,baa464bc,cc5bd875,353b69f8,1f93ce2a,a6c38587) +,S(94b1da0f,b310e056,db0dff72,81db3362,1fcc555d,bf3c973b,76097908,7fe19d6a,8318893d,d5b41a56,33a2ab4,ae4b953c,45c42e9c,8f2fd159,85286de3,fd4fc217) +#endif +#if WINDOW_G > 9 +,S(b5af4299,bcdacef1,e07d081,daec2cfa,d6f8f821,38e151a5,f20e6d52,84c9a6cb,c0984407,8a7db82d,f572987e,b137dc09,c8cf65fd,aedcb20,43b2479b,ab95448d) +,S(5f49ad43,70744587,3980a153,c851829b,f8ef6141,9889bb0c,3c476847,6939c3e3,5c40d385,20f56c3d,ba08ae1,b40fc24a,2ae25c94,45cae0f7,d01d1800,747e04eb) +,S(f6bb067f,88ccc11c,64e30d1a,e6893942,16bea3bf,26ec9c64,5cde1b9e,487da385,315a476d,7268978c,d89d4ec8,adde4a83,28dbfdd9,f2bf44fe,ad4ed721,78288f55) +,S(7b47cede,c02b19e0,94daea0e,ec000455,52690b49,44b3f10,beeed2bf,f9df6950,1bcda5f4,9beedec9,6ebac5a7,957918af,53b7ccd8,c211330,280ed93b,e0efe9a6) +,S(ba69d7f3,82d56d9,eb65e1ab,2d70f52d,18223621,c0029035,a78fd660,9940876d,5f44a2fd,56d5289c,f36bdb9,50ee2538,1d1cf935,ae1aec76,84b6d11f,975d393d) +,S(a3b70894,d226c195,223713bf,330ba39,fe7ec35f,9743347d,1d3dfdb9,7bd929ff,5d0cbdf,42755aa0,355ad2e1,ab39479,495edf2c,20bb0aa5,93cc04cd,56ae6135) +,S(c756e23e,bb2d81fd,91fe73b5,20eb3bfe,5ae602b3,448cf84f,e8da37d,d1c804e5,89f4b6fa,edf86b9b,ca9f52b2,9864a982,5a4faba9,d4fb35f8,98511210,34df49ff) +,S(36327c35,6fab94ab,f791c234,1c39049c,65410e9c,6cdfaa00,d172ee84,3671822c,fe3588a4,698c8d35,f0e01f04,e94f7039,eb745631,8c25927a,be7d061f,d3ed4c6d) +,S(3b75bfbe,8e372311,f46ecf6f,c5eb2af4,b66051b1,874b0c32,1189e106,37dd21bb,b9144a33,e3c3339a,4595e248,87940b4e,2e42a095,d7d1bc2a,ea50aa29,5a879908) +,S(44a61f10,57b4e88a,c55ed72,1f8f4477,5f0272bd,379a97b4,d92a7f75,f0d3c5e2,e870ea65,80340464,9716ec1f,5b79392,18162306,6dc14086,111de144,82d80141) +,S(11ae02f7,663c0a,24c6fe5,ce9206ed,1ebed2e6,ca294acb,74c9a227,97fefd,635a1b87,a262fb30,5008737a,e70422cd,a4e35766,940e424b,d697d28c,dfd6a36f) +,S(c751310a,dfb25d14,2e6ab1b0,ab31b37c,8e987af2,105d5981,69085ca,3e142f5c,a4630dd8,ed2717a9,f10485a4,be685c5a,ccca851d,4bcc1886,4df943ba,ee821014) +,S(fff4d7c6,4009f39c,41757b17,3eb2536c,a639b72b,e15af7f,790bddb7,efefe46a,694a798e,ffe22d1,1030697a,292a4bb1,4c110d6b,dad7edc6,e8976450,ce5080e5) +,S(7d76ea39,c13c9f46,e931e8bc,1cd43707,932b1a,31254d18,c06c8ce9,c3f90534,bc14b2ba,8f0a3d8f,34c7cf7c,3458c916,4cee438b,39a5a6d4,d2a1c9fe,8be415bb) +,S(b6efcad2,ca6ae4f3,6f080707,530aaaad,625fda5e,825f77e8,a6730e95,5e07ad39,4868d8ef,8a56d327,3f6f4a3,23ea6ad6,4694301a,1f6405f0,a421939,bdb1c765) +,S(1a04b12a,a889c4a6,d37f9050,e75406d3,48e38faa,c0d2ab4a,e30caa6e,3633a32e,f43a0c8f,fad38d90,6c817dca,3e7ea09e,21e1c801,7af86966,c246ebc8,dc75911d) +,S(adaeb0fe,9b345190,4e878b12,6c8edddf,b70e2500,5a4d6a6c,531aad51,83209b7e,2b26b16d,dd4d29a7,8cc6b4e,198e6ede,b1c59def,c6793173,f33cb039,d37522ad) +,S(4e4ca02,3931f3fc,b512121d,2d632764,d97fa125,8460d0d1,9a94eb88,2c6e0679,ef90eecd,3704a6c9,454c6860,928eb332,cc917b17,f2594348,515822d1,84537467) +,S(a1f3c279,df69c13a,711b5ee4,139f603b,5654ecac,adc02a22,a7c2087,c11e2971,57249794,54cb78dd,7ef69916,5efe2326,e8aafad7,a8a923b2,252523ad,b6a16b2d) +,S(aac76f81,488668e6,f4b0c911,bc9675ff,c19424c8,6a6903c4,f4b13e0c,e798c7a5,24ae16df,dd6c7d6c,1391df3f,73609bc2,c3759536,eb277189,588a72d1,84dd2978) +,S(70e94171,e59622f0,de360166,6498e6c9,ddce496,a15e30a2,a5bdb701,d0034769,d6d7c0a7,75a9cbef,2b84d4e8,200f92a,446111bb,cf46a57d,5e244f1a,1103b757) +,S(ca17e5e7,11d44492,496fa849,c6ab1c47,3426706b,5b8282b6,f288e096,8ec78890,b3ddd632,2ce577b8,ddb9f501,e17d32cc,e6c58fee,4e283410,5e32f3e8,8bce2c2e) +,S(1a16a58d,8d70fde8,6ac0700f,3a43ab9c,255ec001,8d5fe571,7ec6324a,2faa62e8,f2cb2eba,65aff0a3,dd7bc137,257c1d30,dc2eb6f3,7a3897e1,16c0eb1d,1a710c27) +,S(8f2dde65,b4ddf10,c29c6bbf,5ab2ac11,2dd3357a,e3e5f01e,98190e32,94b9d4f2,e06b8cf7,e5a736d5,4e954bd,8591f7cd,79df335b,d3279f5d,80493fe4,df4c6afb) +,S(3314b553,f8213e7c,80d4562e,cdb3564,ba1d7285,6c88d8c5,a3adda90,4950162,33e83c5e,e3f7c550,f94a7434,e3cad51e,b4dab462,13acc24,fc4aa1f9,fc43532d) +,S(7c107ef4,65ac0c2f,fc5b11a3,348a7cc3,fa589554,ee2b6606,2af3c5ba,25304000,6b5bcf12,2e8a0705,d067fe78,e56d365e,89b5a979,c23f124b,508e63ee,975702c5) +,S(e918a829,325adf67,511e257e,e5596d08,19be4605,36b20cb9,7b76a54a,5be4f8b3,1a92f0a0,b46152c3,e1ba8f0d,12119c15,b70af0ef,3ff0ebf,a9dc9207,cf2fa8ae) +,S(8770da03,d4f3a4b9,e92dd2e3,be309c81,c346c97d,2cea15d1,e3fc94cf,41b9b079,d025430f,dc633d57,18d372fe,64f57fac,53f96461,1fb5005a,10ce842d,ab123c03) +,S(c6b4ad3f,ae2b2557,b126a57f,6bbc039d,a6589f70,c6283ea1,7314aad5,acd8b22b,e8523dcd,2c1c3412,35df278d,e49c38df,85f2888e,cf3c76fb,46e1affa,d8d29bfe) +,S(9aced948,6ffbf984,373b1e91,ff871619,4622741b,1e1ab968,9c88cb70,37a86e14,d7a7eb1f,1b4c31df,ff43cc32,1949c1d3,16e1e7ec,a6a852cd,e8e7f592,8b352d9) +,S(af51536f,fccbdab4,c4f4015b,1e8aca69,b08bf055,e038b22b,87c54f5f,1b9007f3,b6bb0b4c,95c07ecf,49ffa85b,abb1d308,cbe813b7,703a27ef,cf849e,47130f7b) +,S(ec5306df,3ea0abb5,6fc45a09,25c1c925,56e02ffa,18238c3e,5bb2ee53,11823ce2,c950cdb6,720f65f4,18065352,43c90bd8,9457f4bf,d941c9f6,89812840,2dee8b99) +,S(293b1ca5,be127bc6,1a397ecd,59164363,587f468c,81de4d87,6c5d9bae,e72d90a0,4821030f,238e9f05,e93d81d9,1764863d,443a524,3d18e61b,ae26f74d,ba35d821) +,S(ebe54b7d,99876ab6,b2951f0e,e68bfc10,16877142,22ef83c1,2561f486,b4865488,2a1d651c,caf8802f,fa699d91,b8242f51,58d84fa0,d481bc47,9246eeb8,6d381c07) +,S(88f77523,3ab0d69b,ed220109,b29d0d99,33ac8325,445d19df,d38d9c69,3464acdc,8f915122,fbd95ef5,31ea2cb1,aec6bebf,8e059059,459c0d5b,79a282cb,cb276702) +,S(1d84753d,e7210dd8,9db6cfa0,8ebe9797,c7fa40b9,6e94439f,b8117359,a2b3bb01,f7360b5a,ba53a4d8,7440b6d6,f540c485,2e889c33,9f34260d,abfa7861,f1f41ad6) +,S(19e69df5,176f82c1,cf1ae032,cb388ce3,36f82a3e,5e741e1c,27fcefb5,311d4b2f,c401f4fe,c9ba53be,be175dc8,cc1d17b3,9d9f7af,5bb496e0,b95bba6,cbd5c143) +,S(73189e02,c1f125ff,df1a9399,57f29aa5,19b04f5e,42adf729,53d354cc,aee3f2c9,52b8e88f,1c6e7cf8,621d21b0,1e406038,d901de1c,4101d424,1009c01,a537f704) +,S(c5ebe082,8ff1a8bf,52f8956c,b747f1d3,278fd2b0,a5ae7669,1c256e9,2887a74f,ce58cb9,62e74b98,1ab97dc9,2d736b5e,c506e51d,6c09b382,3eff1cdb,cd259860) +,S(783c1621,f7990e01,4296feed,3bc883d5,1a780867,c83b9166,435a0562,4982da76,370b3e2,c9a189c6,9c565c3e,8eb8019d,f5224574,bd5ffbc6,22f563e1,8a36da30) +,S(555e7e80,ccc6a46,1724cbd6,4a53721d,fad66fcb,2c71d579,4d799f6f,fa2b3305,67bbf165,d39d7042,18f5ed31,28fe6dd6,db9b4809,b3270eb,63bda603,f44e9e41) +,S(40c49a26,ab1cd46c,f1e8467e,242c6b1b,faa40a4,cacdd50a,4b0213a5,40243471,16950b00,5002622f,e0b9fdb4,c34224c3,ad55bf30,67f4e96b,dc2813f6,2fdadf86) +,S(eb6b3be5,db098d18,9c810b9f,5593c746,47306226,d77e162,7c8b62f6,d7935298,3d295584,3f356f5c,1f990231,701cedc8,c84e9671,44be22fb,9bd74f0e,15c5bc8) +,S(177218a4,2b55c169,1ca0a073,4d061b53,a0683536,9a04fca9,3f670ce,5eb26091,9611661a,a8a3bc73,7717f243,e5e8b97a,57e0e72,759f0f4e,cedb690c,b3a5fa42) +,S(841a8fa2,f3bc5f8a,7d028c00,127c267a,ea0c3762,8b07ebe3,7f883a67,8fd2a680,579bf37d,b2fd1f77,a0057712,88dbbdcc,526938c,4f9ba89d,9a42d4f3,452cf1b0) +,S(b01ef554,3a377f1e,c801421d,a399c53c,3585789c,d7e51691,32250a61,6edea82d,28f30ce9,7e29b2f1,3af626a0,7a37f14,82e119d1,e66389eb,9620200b,25a90265) +,S(b93e014e,8e3cc643,17ee70d6,ef8c9918,ba344e7c,b38a9a6,2591b0ac,4f38904,129c185,5bdfd10c,6bf152e1,2ff89b4,d0b368ed,c0ae01f7,2b29fc95,240ac3d3) +,S(e0f426f2,43c50d9a,ff80a1dd,26d63189,a00601c6,8ac81373,5fbf548,7acd522,96d883e0,951adc5e,304bd848,ccf39c2a,1c19382a,eb24ad1e,1430d705,deb749fc) +,S(e11e9c74,40e897ad,2870adda,63b9ec04,d5379f14,b3bbbdf2,147ea9b7,9c73233c,49d6e54b,29197532,3f5a9df0,3e22e359,e125e34d,d9f3d6c5,cb9f0a20,6dc1f019) +,S(91ad584b,c5ef145,3b796eca,20027cc2,ae38ee70,9ac4591c,79cf67a7,a96b2c2b,d815a213,a620c531,11f79e5d,b5d9c3c5,565dfd97,ece841e2,3e9c1ca7,530bac2a) +,S(3e725392,f4fa34f2,7413785,cb322f35,1032971c,2303f3da,bfe40461,4299f8d2,8e323a51,5addeed5,f3548217,6907efa5,4e0c1d57,7895839e,42223e5,7708ae85) +,S(5e87bec2,1a589ab,483c00ac,fa863f35,91d9119b,9a0239bc,ed4f5790,45a98160,a88a3b84,33c75c1f,9eaf3c15,9fc39a6e,33625f1c,d0cd7263,3a825023,f2e7d47b) +,S(c2e08613,2cb93b35,749cb652,44e99909,da18260e,d252cf32,489fa1c8,d268a0ed,d3f2e3ad,1f16365d,d47038d6,854e0773,28e02e64,d05a4764,4ed0d82a,8c8a5761) +,S(99304c5e,ccf09869,7b2193c2,31dd9432,3b9053d0,e4b9025c,74517ba7,f1978af,ee77fa7b,638b1396,6f7e77e3,43dd04a0,ba1324f3,1e0da111,338019aa,209dc789) +,S(40e108c5,59adfb37,651f04f7,9ef895b,25a79f03,650d6b1d,1c21322a,b4c5c6bc,8980ab38,5733e648,84aff3f8,c47fef44,210eb2ab,a094eb2c,fc5e464b,679db653) +,S(98c88257,2d190721,20c31528,7f508df4,6d6276dd,c9711aca,5bbeacdc,88c6a78a,5d1aa976,1f5c5ffb,d12ea7f4,8d0510e8,b57f270e,e08c3256,f3ee676b,41a61c92) +,S(389aba7a,25e92306,b84eeab7,a16c37ae,d7b4cf09,806ff740,c05dab20,60af6fed,673ab0c9,ec48e2e8,d372ed60,812b2990,49c32637,35f61c13,d6f0ecf6,d065707e) +,S(9dc64fba,832c956e,93efda62,e5f11b3a,6619eaaa,e539b732,61453eea,ca53df17,180b38a9,3c56ab10,a4267ad8,d8a358ef,8f60a9c9,9483889f,956bafda,f45990ac) +,S(71118e18,e758c2c3,6203528b,8b6707ab,b3439b0c,d3d508a9,6759c155,fe4921f7,c2f61af1,2c1b4e9c,64908719,f11b52d1,76bf22f7,e1cc800b,5ec79e28,aa104ee0) +,S(33bcedee,11b9f3c4,924e0990,9adc5fd1,46218b23,6531a242,45cbb2a8,3ec3d096,15f4bd1a,6c22c673,941a71f6,f4694fdb,f83b3e8d,5e317e9d,655057d5,acfbad0a) +,S(4b599b3a,4ab5e9f1,f161e5cb,62fdba55,fbd97740,759871d0,e66b20dc,4e13ccb4,635039da,9035272b,8b706411,9b342144,6c96019a,2c6df423,2b18299d,4a3fb523) +,S(19f6bf4c,dae54ca9,41b8f642,95136026,decb8dda,35e97627,5694365b,21269d10,a24c3fdc,90b06dc,264bca48,db27502f,6cb31a6b,609d3f3d,a1c92c64,cf3c95d7) +,S(bc3df1a9,8027d14d,f6629adf,7ad073ae,8a270875,b177a67a,58dd46f,1b01314c,99dd3a91,54f51d07,2ee33e89,8d915189,93445065,770745e7,b6bb30ab,808d1f76) +,S(977a4264,521a70e8,4d25f5b5,ac1ae5f6,c34ef31e,4dda285e,1ea4a9e5,7dd72c3c,f1bfc819,7aab2fe4,d0425b61,cd403fc9,dbf44f68,32e1c41b,4fce9b2a,2b9f5a0c) +,S(5fdfde4a,85fc5a53,3ed4a7f5,8adc7b1c,98b2611,3e271b47,a1c12c69,dc9b339,3edf2baf,bd6a94e6,951bad5,26fb24b9,731c2588,b2f6eb1c,e9744f49,16c6555a) +,S(b8bcd72c,dcd28afc,eeac1ac5,fb7db8c,afc17abf,82268747,6ce01423,e9e9c50d,82633c5,2e6dc057,9bbd9f2f,3771a53f,9cb6d0e3,6a7566db,f2c45125,3c55e9d) +,S(6c20b999,133bc37b,c65d01eb,6e946565,721bc2e9,da735c72,8be8a41c,1f75c77,20caf674,d8ad036e,25f42aa4,7a5ae475,5e36f44a,79c5ff20,cf6df115,40b71e53) +,S(bbe49141,69655f15,39ce4bf2,f2e919df,f877b5fa,163b7a70,22bc91ad,315adb07,8cd3e025,6618d23c,8c6b5ff6,db8fc0a5,a77b847f,ec876ac,40f76e9c,cbf93a1e) +,S(748b3078,e38374bf,7f39bbb,c5641737,bf6dfeae,d3980c75,2fe14c68,65e73786,7f7cae0a,61a7dfa2,471f2c80,217fc847,ea86b6b0,6297aeb2,8f3c94cf,2a811ac8) +,S(fa63c7c5,b89a2559,4615728b,2272cf68,5d39d592,d052c0bc,d23d48be,c764e4b4,c4c32ba2,77519d60,e1e38a50,6d67d041,804724d6,5cb4dd31,fbe7d692,8ca47c8a) +,S(c2ed7197,d014e380,a365ea13,d948314b,86978eb0,70e3e444,6c953871,cc56c91c,5c73c293,e7c1cd18,f7854a09,d8b9b0fb,3404bdb7,737dc070,9bdc01e,466a595e) +,S(2514c1ef,cb1e0bd6,c2f34e84,6f3e8006,6c2b3a04,c0d9fab5,f22fe872,6fc266be,c5a0ac6c,7bbb2d9,ff844346,65f66ec6,507c35dd,8ccf9ad0,69a1ec94,c64e3eb3) +,S(5bc07f05,11647f2,58dd2e28,9a3843c8,e2318bff,c96a081d,f6b6ef94,4e286350,213ce093,1217ef04,8d87d059,f2584db5,7a91c465,1e112c66,a41f85ab,ebbcbea4) +,S(edb56e42,97375b03,8a573f70,67ae464f,db9c1335,f6a03dd8,862a1731,9a3cad8a,d3e61a70,16f8d546,61b8414a,426f3be4,35862053,1d981f2e,5314447f,15ef5fa7) +,S(2925276e,78266481,3bf60998,2e028646,6849088e,d0d77d55,817c8d9d,73d5d732,f53157a6,a97c989d,ceb2d755,dbb0cee1,84b33213,20dd6d22,62213fe4,9a87296f) +,S(2c4579d5,bda0f4a5,37209882,937019e9,91286379,c3afb37f,a69e409e,9bc0a034,e150bf4d,d889c3c4,655acd23,f3107bca,a319d467,b1b9b15c,336ca934,5ef7d99c) +,S(5f260a00,11f9f876,bbe29587,af31832,25f21b8,42698b3d,5688545,a8808904,6ad33a32,164caa1f,7a4d2ce0,6eac3d,736fe64e,d83a3a9b,53473a89,8ee02350) +,S(3bbbbcc6,12095ec9,52fd430,f3fb3d6a,9d1f2c69,e8885100,d65a4d7,b6ac4b8b,328e828,3846a6e7,db5b090f,8c9581da,40d244cb,aa3b5948,7e4f9faa,550b0c97) +,S(4985027b,dd0fd8ef,fec9af44,bc222f4a,343e80ca,662d917d,affb9d81,956acff0,58befd2e,37a36e41,305561b5,f2716a23,460b1014,fe814654,68c16c22,3b8affda) +,S(214638e8,d2e30891,9b5eb2d8,803b3dcc,6e826ecc,e1b59b,92e263d5,67959de7,9dd8921,6f131e29,35ae0454,ff5fc9c2,dc22c0f1,c8de7dd8,ad9d41e4,f632342a) +,S(6ced8705,5ced2d6a,f3e3532b,965e0a31,6876c110,69155f35,444004f6,e6f3cfdd,f51b1aab,c86f556f,8b7ba4e2,a1e6aee7,55b17c01,997fcac0,a83eb56f,7e546ec6) +,S(95016e67,876c936c,e3263498,7859d1ad,7fc3ade4,4219727,30a1c886,c9dcfacb,299e78c4,e6e266ee,ffbd284b,81005bab,4df7232f,2e43f160,742bb392,6af4f660) +,S(4bec66c8,30401c39,c42a8019,fc398cf0,c513d20f,9db30763,51315319,ee6f23f2,f1dffe92,3b7d4609,871aa916,28929c63,4fcdeda1,543fc3d5,8e8b2735,938514fc) +,S(b50513d1,40513b97,6ac0015a,60e53ae5,9088c4ef,5ab27bb2,7f3eda78,848a59c7,9c41cae5,1182e6c2,3fb254c5,1b786ccd,dc9282c9,a6674841,29a5894b,99c36399) +,S(59792653,3989a039,6a69bda3,8a920ac9,d1df3845,26f30c00,3e415593,b690708d,7f2c14b7,274887db,5e656192,19ee6737,4c750cb3,97ae4bab,3a3ed02f,1aba648f) +,S(7ba2b766,cf012a93,478fe2b3,e916d665,251cc7f9,3ec16dd3,4db37056,5eacf6f,14fd8938,f950798c,37121286,5e8bdd14,3dcc7e8c,2c84aa69,3fb311f,856404bb) +,S(3062f2fe,f69c90d9,fc947af8,a9e839cd,7f9e9d22,566bd3a7,1c43df9b,eab5d6bb,db84a833,49916d41,7fde7b71,9d92a716,64047d4,21a36bba,ad9972bc,6f5ee58) +,S(ed5f949d,69dbec8a,77f4d695,cb446700,f6fae687,e327cce3,db38c2fd,54b06e74,4724e060,57b3d50,65104ff9,29950bcb,2a690723,f15999fd,ee62febf,2d8930e3) +,S(4d655e03,30028276,e9312fe,a6acc010,30e12950,9ebd68d3,d7170e46,61b7cdc,90efc122,6c27549b,2f5e046b,69e97f04,4399579e,278ccd0b,7bcee523,10ea99bb) +,S(f6b60756,b888efec,d0a9edf4,a483f95b,68e05e80,c351a60d,bf166faa,eaf1b35d,27bedebd,aa781584,6a896b24,1afaf9b0,cb57e98f,bce5df6,bfd22a3d,38a5fb8c) +,S(cc592caa,942ba237,72c4db94,58d6ea2c,8c81c538,8fc7cb51,6ca30188,a3c55748,36e2f7cd,358e5608,36e77d10,361c3f1,bb6bd2b1,d640307c,63d512d1,db288158) +,S(4acba9dc,a5bb4698,21a3acb8,cedf4304,f9372161,976d0edf,6a7a032f,f6c1a456,b36e983a,b2ab47f3,3e72287e,9bbd02cd,d6fb302a,972f2166,9cae4e85,52262437) +,S(c8a5185e,42279d3,2b50e0c6,1b9ce961,7be3633d,84a9472d,97446ddb,eb061f91,cfaa50b7,445e189b,d64c1df7,4668eeb1,cdb7cbd1,ff65c0ff,3c38d22d,9bd4b5cb) +,S(c1c95567,7f4f611,365168a8,89de10ad,535faf08,65f8d20e,52b1041,d35f18f9,34f7bc3b,3d956b63,9afc1eb,956f4472,543919e1,3708e7eb,537ab941,48033749) +,S(8df4fbb7,36f6736e,b4a09370,33f7d256,8bb68d68,f3e1f8fa,8df1ae51,d236a8f3,3d7185fe,8e9a2d00,3987af26,71bb3850,cef6b0f7,70770c81,22977764,5d02122c) +,S(d635f0,e35c7cb8,f2aa1ec0,c475011d,c2c8bbb6,d1ebc297,c2baa5e6,aa5af3dd,926ebd,c588e8b3,1a990a5b,5907ae5f,441e5a99,1853c643,5e36803c,7ba51a2f) +,S(b58d12d,5f865375,7514ea38,30e38e05,3678b525,e8b51923,d6460720,b46a4bc,f7b59183,5b0ebab3,935d587c,e995c0b4,d77c9e40,ea4837f6,48e44841,7438d3e) +,S(bb7c6a8c,b4013640,ecfad075,578e89ae,12cb4253,6461d780,11ba76db,da9a7f36,7dda0258,3774d618,68995b83,5708295a,3c2f5c40,306dcba7,d1c20da1,4836581c) +,S(14f6f0f7,92cc8cef,9dca990a,7fa5b7aa,f116b819,722cfb91,9683b298,3514a9e6,88c35f92,7a07598c,90ce5aac,4b3fecb5,2261045f,f23800b9,7b96f210,3a4d7055) +,S(4b95e5f4,eb9fa118,5ddad896,457f4aa2,fb60f4d0,496ad4fa,76bbbce7,77448541,1e100787,513acb31,ba087f51,201201ed,502d1f08,f7e2b8f4,d27706d1,45e71d21) +,S(e9a17fc0,67f75b2c,6384aa31,223355a3,a7af5366,4d85dc16,dcecbd2a,364b63ae,420a2388,ad674523,62f8fcf0,12b601ab,a40e06a,1b4dac1,9560c085,de7fb8c7) +,S(39d8536,f320ec81,4ee3d066,c0834130,96d4ff43,8331a81c,f10ad544,43ff9169,70ee89e9,1478e898,60d66a55,6054abd0,c7434535,13a7a3be,7a76e367,c28ca248) +,S(9779a0c8,8624d6c,beb1dc72,f371ce26,9f95b993,c49ff20e,1daa3c,2fb636e8,9d9e27cc,67296c50,9da4b0e,6037920b,369684d8,a64cb907,d230a4ab,a0c2712e) +,S(cd4c584a,1dabb48f,6a5c09de,9caf36ff,4a97471f,d1565586,bd78b4fb,66f0b401,95902ab1,eff06e2,b3e104b0,cad2c28e,6fd60eed,c47657f0,bc433411,273446f1) +,S(46ca11f4,142362cb,513164f7,c72b776e,dbeb3f65,5d527196,88eabeea,2561aba4,8060431a,2a2ad442,dfb6d3cb,d6263c61,bcfd0946,6204e2f5,e832c4d5,a434c9ff) +,S(dfebd179,1ffb63f5,76f5c753,50031a21,eb712de5,7e8f83b4,75ac39d8,8a94a513,cfed6c7e,39b2b54c,206aa0e2,2f7c610c,6576af2d,ecb28f0a,a71cb1ad,c7be75de) +,S(c71c6532,82fd063b,44633d9d,7a3b94f9,43daf1a1,7967ffcf,e1238087,5d2c2469,62fcd7cd,e006a10,38df8aed,33abe940,f18a4736,52adeba8,620d1b54,a9d376d0) +,S(63ebbb4d,dc8ba09a,4e2640fb,f48fb75a,6864ec41,fc1647b1,e9f8aef7,34c0ff37,e59d034b,fe16f4b,41d090e1,97360a85,dbf1ae4f,719c62df,77261205,da4ae28e) +,S(650498c8,cb51bf16,58eeac61,61b5892d,ce6e5c1c,271d40bc,eea14db9,dd12814a,e7e66785,5d8e0193,24457769,bbd5d14a,7a614585,70ad5e6e,e3058af9,64a65279) +,S(14a1e03f,14c00863,81599c07,b816df44,90815a8,40c1032a,c41225a8,47c43fd5,35244a59,bc6ba88f,46f66bac,9bb8ef5e,4926da38,50532ddb,6d6d606f,35fe98de) +,S(1c9f6eb2,f6a8a1e8,ecf9a16,71154fff,a4f14c15,bbd50f08,4d6f5315,b6903c5c,e6bde1f5,2ca4ff63,9b66fc51,150eee99,5386383e,402f987d,d266065d,2a03a033) +,S(1de71eed,bade7b1,7c80966,4b00d56c,b43ea61a,c0e069d9,7cff0218,f970f8bf,8d4b2de,77edeeae,d78d42e1,6b7bc94d,ea99d65d,985769bb,5c67da66,18ee1434) +,S(f4432a80,ce954d2e,baa2f062,8bbab706,479f7a39,838d8c3,5a96eaab,5f5cb4b1,96fe6ead,ac34a40c,3cabf47,6fc09382,91f3d077,29c6302c,c67a189c,bed579bf) +,S(8f71e74d,17964af4,5623d3f9,68424119,cb37e1ca,c1524737,4828b5e9,2519fb21,6990f0df,d7f0ca4b,a77678e4,ebf6946e,5b6b1720,869c91c,ec07854d,604865ab) +,S(22293157,5e3dc25e,665546e2,96a83a0,5a09d052,cef701a1,20019c49,c6a6745e,aad8f887,42585607,c792bfae,8a941caa,83d05082,defea859,86a6ead8,e5c423b0) +,S(6585fe63,2ef3a69a,816bf5f2,9e627650,cc57d069,3ac217c6,3b73aa2a,f248a096,820aa3bb,20281afe,edd9ca57,76ecc55f,dc8a893f,de11f7cc,12f37a83,6cfd9f8b) +,S(22232479,e55c51ca,b2963ce5,abf06281,aaec472f,e610d339,1951e41f,93f67bf8,e192fab,2cf22d7f,e67f0514,bc1329a2,888a8f18,a8d6504b,b7c5a9bb,ebf927d2) +,S(da8d02fd,e4ba069e,bccaba08,2b396c94,4460148b,70e98f60,8267db02,5ddf16fc,1a30213d,e337084a,47d67e7c,17a2e64d,579756d0,8b66f4d0,59a76021,e63fa2bb) +,S(a6f72c62,854e82de,f1b8a006,64c4e8b9,ad49e092,78ee6501,708a9f18,92202ebf,8355972d,b08c8104,b7c56ab,c2318ef4,2e270989,1a83837e,daa35537,1d03ba4) +,S(2074fd3a,309e85a0,5c6f8c35,937dcc56,a15077ce,99f5a8ee,8d55ae2a,3bc7db68,e11c02ea,cb783c94,2e58fc0e,806a9816,3061a4e9,aea9582e,53ae1f08,322cff97) +,S(49ed5666,fae9aa2b,70cd316f,62a4b62e,29aa59f3,1826106c,8611c50c,79a1a5e3,5ca7e49a,ae144e2b,dcc0b19e,f986967a,1477c209,2a8368b6,324bac6c,807643f7) +,S(2289ec7e,a1f7e4e9,85f472a7,13722335,b582c4e9,8e191468,3ed13622,5d6c1b1f,11e2b18,689a0867,517bff6,77fe40f7,b03f898b,d70e8902,61a512ca,d9cbbeb1) +,S(ea852ebe,23f1efbe,d8ac64a5,58ba2ba3,fbed0e52,ffc70635,bc49cebf,85859164,bde2ef41,fe97a639,73266583,c7a4e415,25ef1351,5b25cfaf,c97aa635,41cbb824) +,S(5718f0e6,7cc07d3f,1ac1a954,8fef08a4,290b257d,a4179855,3fe9be1b,d302f0ea,98ec4d5b,fca65d7e,e72d8bd5,3645a6af,a6ffcaa0,a2eb894f,d4e40ecf,69acbe90) +,S(df62a2ab,d77afd7d,ee8f0650,b75458e3,10269c3f,780cdad5,50bebd92,4b810a4c,6a6606cc,e384d27b,80bea2e9,588663e0,8d39fe8e,9fc8a8cd,54c4829b,8e4c034) +,S(1010fc45,4b0c268b,c339bd19,809508e7,9ea7dc0e,efd779aa,4974cdae,805e6668,686a3adb,681b597,2b30a323,c6b6bd2a,d51194f1,9d3d801c,3fa65fab,e96410e1) +,S(8ac79852,75673818,69fe93c9,6141493e,72ca344,790487b,d5425ed6,9f5c5c18,bb314248,fcbfc867,d1972e04,b9ef1f90,775375f9,9d25bcec,684c72c9,bdd1c08e) +,S(560e9711,88cbc7ce,c61f3bf4,45f0ade3,6f3f174d,219a160,5f9c8692,3f848b9d,9e92dace,6775cc67,bfbbf21f,c64e6e9d,4d133f8a,c18ee277,bc80ef6d,d1b9cd2f) +#endif +#if WINDOW_G > 10 +,S(8c464204,4b95eb66,cc95ca08,8469a1c0,28eea52f,7f709fe,e6d90700,f5fb943a,bf10fc5d,7bc25181,301b3a61,5ebea597,a3492025,953c3aa5,1a11271e,689d0223) +,S(d293f74c,f3578b71,35377247,cd8b0367,7f2245da,f87453cb,4d8d1cc2,871eb5aa,86c2013a,61dfea14,63e45931,eb09050f,f080e3d4,ae357423,ba7afbed,a64a6f26) +,S(35997241,ae757b1f,c767611e,c76eb935,fefbf7a7,33666aff,4c6bd744,d7687d35,bcbea61f,246bcd4c,c3c7fd35,7bd393da,2f36e0ef,cca0df9c,5994f96f,c44b2aa0) +,S(d096097,7467197d,3c1a0ef8,44ee35dc,285a17c5,bd9e06de,15f36025,7f6464eb,342af6a5,1e06db96,692954bf,c79cde9e,3dd44869,9e88b03c,d144b70b,bd3e8783) +,S(8e875c99,2aeaead6,7033a375,521b0f85,62125797,23a25470,bfdf898c,ae41a777,24aa273d,2d2f19bb,4e0ba10,13127ad2,a5ee6686,1ec6d0c6,53f7a989,73c0bbd8) +,S(bf51d1f3,2703a4c,d1ef47d8,172c5bb8,d622f444,8569aee,d2de1b9,ae541855,8f81e352,b6c60acf,bbde6e40,99353d84,5918d931,4433c30f,3c60a710,cf9aa484) +,S(6fb6b462,9726856,22b2d141,5083ef56,2ebb115b,6cdcbaee,696a8d4c,8341c26f,9c08f7bf,f9cfcd9e,cca923b3,e578ba45,468f2530,baca2032,a899f060,b83c9c73) +,S(75583ac1,8b5cf78d,7de6a21f,aff045fb,1db56f68,6b2cf89d,678df62,93617438,8259a22c,b08546ff,e237c7d,9c669c96,71fe014,9840082d,f6790340,9b69f900) +,S(42611933,a5d759ac,7ec51c89,31b76e95,4aabc2e3,61010f36,cdd8ff9c,b4c0ef92,88a644ce,6b8acbce,a378e2bd,54eb84c5,58cde403,f99cbf8,7830151d,21ed4261) +,S(243a6dbf,6128f964,bdae776c,a716bdc5,6dff9c95,24baf845,8a43ade3,af520d2,262a2e8a,5ce4db48,d0401850,e92bdfa8,3dda744d,a3d9025d,6091f1a5,201b7e50) +,S(212bd175,1548c6d2,41e9307,a7df15bc,46e57e2c,5a76bd58,82b1291,d8c2ac76,82461bc7,6cc97273,267cc788,a8b24082,57f04ef4,719a9aaa,e33cbd77,79391bc) +,S(da6d030b,21f96d2a,aa0b3e56,28ae0ec8,8ca8a546,10bd61fb,c1a7c16b,4d61177b,5b5bc635,8fab0287,4a2b8596,1b49ec29,2c2aad1e,1eabbd0a,1cebdbe7,2e3f9fde) +,S(dc230af0,55a243b0,a581e101,2eea48fc,4a43137e,cfe80108,86a9f4e3,f6c1f01f,d0f98e1b,e70a458d,7030120d,a3d7feed,2eb5a9ab,601718bb,950fa03e,568180ca) +,S(82c2de3a,c815c686,98ce73b5,6f232684,ee9c5972,f0a44797,dc16d04b,a9089df1,1c847065,c6c2cc18,fa253b8e,c1fe178d,c859844,2c1fa432,54462d97,93b8573d) +,S(6ca2de88,74e4916e,e1965dfa,200af89a,cc439f20,6a4077f6,67076149,e20494a3,6ef0b344,97aa85dd,a43cc1aa,57dc7ce6,cd51119d,ae96ae06,99b5119a,9a662043) +,S(ba2687c4,1728fb65,206448f8,28400efb,cf1149a4,90bd31f8,8d33af53,7851d97f,96ad25f1,1f2ce7aa,e8b803bb,3c62cd32,3345500,243b1de5,d61f20b1,86b4c0c4) +,S(ac362040,1947f301,16032d5a,4b303323,d311f533,e46a1aa5,f1ea2f08,d553e0d,53839f95,fef32884,5a75881f,a17db91c,1d5b981b,7b20937f,df171c3f,2cb30a22) +,S(6780ecee,5b1b7205,68d4241e,c3b35c9e,4158c7c2,2dbba46b,ac769476,79049e13,9ac115f0,31e0888d,2dc90b9f,3562e732,46520d57,ecc7ae4e,e0fbf401,3057d9a8) +,S(95377a47,e7a2d5d5,30510d62,2bbd3439,c0f7653a,ab294254,cbb10390,d2a63732,57ac9110,9dafb62c,fe1abe4d,fc64557b,bb01f76a,36649d7b,91be523,f8195fc0) +,S(4f195bf,98fd83bf,7ee97c5,9bd42af5,486a8507,3327415e,85f17a17,2add8921,a56acf25,1c82323,6327cae3,6b1cadd,1a057bbc,f1ef3b59,a865c7b8,691cf3dc) +,S(eccd1fd1,efe8299f,d2208240,adbaabce,cc0510d2,d7b6f6ba,d9e291b1,4cbcb53f,ec2ff321,6da50fa5,c57d6f2d,3198e019,2d9b6f8b,ffc26b29,13580447,a42c667c) +,S(c757444a,f2c3425c,728ff41c,f7cb7475,502e7601,c1edf2b,1eec84e1,b058f438,e1d481b6,169f143e,29701105,bc8b6657,9cd267fc,685014b8,fd070283,6362e53a) +,S(3562837e,bff50776,58d99662,7a11a367,aef3255c,1c470ac6,36f1b57c,645250b8,cdcf4a0d,97aa58fc,ccd374bb,bcafc00,fa1d0d35,ca7fab9c,f4d72d66,299234d8) +,S(ce9dc245,f62e97ab,d2d339e9,7fac18b7,b1f2f07d,fb654a82,b113317c,86d4a3a1,f6e1e325,342afb8e,64fe8520,ec37abde,fcaf1b30,be6ecb79,27ba5615,f0d184d5) +,S(ac022f3b,48ee44ba,9d271a8c,1a01fa8a,aab4818c,e5383dd5,42d9d6e3,2c858a12,1e0563a8,91f8d11f,1989e091,739611de,191e497e,66055aaf,45db9ba9,72ca76fa) +,S(d1d4f682,cb12cfaa,e46e57e6,db6f2277,55a83782,88cca4ff,3a999c0b,a651d9f9,1b19bfe5,870e1931,4c23b4b0,71672233,1607264,acb8e960,488598e7,85e71a36) +,S(79962171,bbddaf94,45fbacd4,f9bdd1a8,892e754b,2d0052ee,2435303a,ff1c8a37,b8ac27de,2a952beb,45472f77,b34c1354,fe47b6a9,daf0720a,b8515be3,7bb98a7d) +,S(445a17c4,2390b604,bb3c3573,b061a2f1,20ecb3b1,83a0f8d8,cf032e3c,509d3b90,b75f4088,7c07fe5c,a0c057c8,7eff4966,4ea76941,e409a6aa,e34ad4b1,693f97b1) +,S(6166b5f9,63a9f47f,5fac49a7,8d175763,8c39cd49,11d16ccf,b0e83bc3,f402051,ba337661,8302aeb2,213e4620,4ec57492,933d6df5,5a045d7e,5317ddf,e92430b3) +,S(cd666e74,28901afe,8e67d0e4,48de7e3,30b6dbdb,a34db4a9,29315d3f,8b251531,af72d8b9,43cba540,e42398e7,49fc89ed,44095951,f11b24f9,e5451810,3802304b) +,S(c833be8c,fd2f6fe0,46d837a1,1d990355,5a6285bc,d7b8814e,e839cbad,523ac72,7ea8f90b,44112363,a8d75153,150c3b4e,b6c07dbe,fe8c8ed6,3a24984,c9a6af03) +,S(cc185f36,3036d385,d890ac1f,5e95b162,e40e4a4f,e8427613,98200369,f25ea477,e0768836,146d9c98,98aaabe5,a9ce12ef,f66d0775,4055eb42,832eeb9f,26338236) +,S(148e0863,24bbc2ba,b67c9be7,407b809,77ccd910,e92c9770,47943c29,8c9c4a5a,89e83c85,9cddfc80,9de733ae,6138e97d,b706a331,fb7176ee,55dfe3ba,c2408797) +,S(9b1539c1,aba5b583,5c88d9b1,92a3761d,cf8b649,54f53a7e,460e0122,bec95c76,391cde19,45be59da,d4c895f1,3aa1ce24,d8472e42,a232795b,967f21d5,acefdc18) +,S(68a2e6c1,75fb01d3,76a9e575,ff427cc7,a6032774,a974bdd3,e93b8a73,e4495cd,153e6484,c8c30dde,5f269b74,1c599647,666cab7,e273d4f2,5573dc4e,78e00752) +,S(58fe9049,35a5a40c,3b633440,533cccac,7669e9a2,e7c2f0b6,6c36c228,61dfb04e,b36905c5,92450e2d,71d06e2a,2d599a77,71ac1e27,15a79555,b39fbb60,5536e1bb) +,S(823c0f96,dcbdd9b0,bfdaff2a,19b6027d,3e9bca6,e298378,3375a783,5eac7080,d91546cc,f34d9a58,babeb6d5,43bf3c36,8831a2b0,d9043db8,895cd208,f2ad0a7f) +,S(4a56aeae,e908f908,55fe7b71,3013ee7,d6812152,4f7decaf,533cde20,2d14537,7e60c801,33b718d2,119995b3,3790eb9a,3129a7fb,2e030d8d,21af90a,c622b7a2) +,S(6c0f3855,e6c4f5f2,c4594e2b,8881319b,82a64bf4,9fe0968a,71f6ca3b,f9240334,5c8e7b6d,a9efbba8,4b5ade85,305aead3,e1478ad1,b4d56fc8,3acfe34d,23b5203c) +,S(d9cf8f2c,d1704907,15dde21c,f172e648,496e40b,5248f331,3aeba2a3,35ac9632,92a7c251,b440f930,bd98299,c35d57f7,15867e90,b6c3e8e6,b073815c,3c934344) +,S(4bfcb492,8b91dc7b,afa7ed43,d9af3039,77592728,fcf1b9e2,7c6767f7,b993d898,276a06f1,ecd9d410,b34c9a4a,e3aa33b8,1854a4e9,e4703dda,7bfca949,a45d14f7) +,S(abde5893,ac4032f4,4ed93dee,8156596e,7cdcc575,e5928792,944019ac,23c434e8,5e03a809,2b9e6044,e942af7a,7cef02fb,46162cb2,4c19916e,d774b00d,8195c40a) +,S(205d6307,7a98a8e1,178814b4,9281da20,4482f1ae,31be20a8,3b3b0fd,526e1cc5,4bbe295c,943e3560,6b95cb19,d6e64bfc,b9cab7d2,55657614,7a79ff50,6fe4d780) +,S(cb4c4c83,e6673a1c,6c228a42,36e6031d,b59653bc,45bf4b7c,3b98cdd2,441c43bd,142e0276,39267ea0,f7c2ff39,75afe714,62f3340c,1fea5149,cfe4e8ea,e31a2769) +,S(25a1f4b2,7ff5bdfb,3af54a4b,493356ef,92ccf0b2,dec7c4f2,b5abb225,2cca77a7,1b25dd93,153f8341,7df3b3af,c991f2d9,36c32e8b,288a7fe9,3e9ff97b,335c3c38) +,S(222f76a7,7eeca0d6,a511c863,a657cb89,5a1b7154,957b66dc,89ca77aa,2a54237b,a8f2bee0,64eff88d,87a598a,8665d295,a205c884,2f6a3492,7945a02f,2cb0b289) +,S(32d4328d,1ad2651b,41bf1015,6936b406,379f5c26,99f1c2da,ec3cbd8f,3b4dfa8d,9f6de6e2,3294a33b,5f4d4062,3e478096,df5de0a1,d069290d,204ce930,7988261d) +,S(cde9ecbe,6948cd70,3b193790,6662b7d,187d0830,cf991b14,e8265691,81f1d3f0,84887b32,e1218d2,9b77794c,e8ad56c5,f5abe8ff,f95515e2,4bce81b1,5b029720) +,S(bc89f45c,3baaef4c,a8343582,6506a006,509f4e7e,265e4b80,11d53d3,a748947d,eff5bca2,714db146,7a272fce,534f79be,9fa15af,7226ba49,51129f5e,6fe68475) +,S(62678cc0,eea2bbfe,2bd4ba65,5434a9ad,39b409b9,b57efdf0,9940f748,ddb51d4f,8d384f4f,d234d31d,1c161245,ef6dd54e,a5cc8ab9,e7bcc883,6735051c,37a74acf) +,S(15e01d39,c63ae225,63dc89cf,3dfa2736,df7c0ac3,4fe86f8a,f219f933,86bc93d0,1f563532,314fcb81,c1725133,49769861,e7efb999,fa317ef4,2bc75588,10cfb13b) +,S(4f8d2b49,3493258d,ff98e813,e428ae9c,52c60103,1bdbeb9,7b8f364b,2bac10e3,8c7d117b,67955db6,c0058028,3f919f57,1e8c58e4,216ca1bc,d66b264e,169b73f) +,S(d14ce31a,2bf16b60,983e397c,ddd3588c,3b0d77b4,f449136f,1a789276,b56f1d61,9a15f620,b227d83a,3722ca6e,4dd7bbf5,833f24c7,2584f356,11ef3734,ad3f0910) +,S(35221b4e,b8c275f5,c10d656c,9bfea000,24c1aa2,c4130841,9c3e8e3b,66f780f1,3d1c5a02,5274afcb,bd78382b,b2778657,6888d46,1b5dffa0,f8ec5dd9,3bf8e808) +,S(82ed9c3b,1c76c1b8,f44ff6f2,9f443b20,83f68617,7270843c,49eac0aa,34a8ddc8,262e9e6b,c2ab2b86,7342081d,90002690,e81f5a58,aefd6fc4,8a91dc5d,e95f1340) +,S(919e960e,acf2aa36,e86342f7,742e97c4,9c49b64a,ff5c6118,d181e349,10717b85,4b51a94e,a3ea1679,cd9ce9d5,ac329f13,ef530d42,c7821650,5a082fe4,d945b861) +,S(cdacae3e,20ce551a,beeabcaf,a643ce62,edca3de1,acf06c30,65ffd366,5bc3ec7d,aaacbb13,872b076a,e28c326d,fa54f4ee,235df4a4,b341c9b1,3d322071,6eb95bb6) +,S(1a4508e2,1bd05c09,f3d80f82,90726f08,de3a62ff,b663d5a8,f949ce26,92a5f2ab,52780ff0,976eb033,760459bf,4bf02994,c6e672c5,6d25d3e6,2b320f5,2cca97ba) +,S(8e46eeed,5686f25c,a94f73d1,3f26c98a,e9129f77,f3aa18dd,d5214262,803a0b45,ee56d38d,7041eea7,c87f2ed1,e7f0aeb6,7253d556,610e8200,782c9af6,1dedcf4d) +,S(782910fa,3bd6b309,dad797c1,5b618469,68d6171e,7a0a0532,a92e5bb3,697e4031,ff178365,c44c2a28,e84c31b8,946b0a80,717914ff,6d3f22dd,ee409753,44e4b3f4) +,S(2ab9e8c,c5a710ca,6cc2d0a2,94f1d7d2,65c50aa8,f9069041,ae93c91a,e5f64e8a,aabcd0f,a2254bad,67cf23d,a5934947,18536602,a13d81c9,db23afc9,a7f89b9b) +,S(d04667c4,4fb25b22,8320cc53,35252937,a094ddc2,4610f7a5,fcb1bd1d,6382c9e5,7c93613f,8bf048e7,86af436e,cac4fa86,6e5a91d8,3064f5c,e31d4794,b2b0f74e) +,S(b9c476f9,799cdda4,a51b0476,c5838994,f157bd29,c9361252,def4af83,6e86b0f7,2ec7619b,c77948b3,f25cefbc,46845527,d1a9b0da,a90529ef,f13aab4a,ca97932e) +,S(90bdedab,f13f9940,4b9d8c56,5d64739c,4ef765ff,dee2ae0d,64fda841,286eee85,a9f47882,d9a848ab,4be812a4,8187d26c,7f8bb8dd,b94f7725,5c628104,e0cf21f5) +,S(a0c394a8,2177734,c02b8310,74ebf0ff,ff4208cd,dcd59e7b,a680737a,fc485c84,c4f08932,b4c62f34,fc82434f,e9b7b164,e835cab6,2f34ee3f,d640e5d7,d09364b) +,S(1b0319bd,3896e8c6,284f949c,72e7694e,bd3c2923,ebeac273,b9aab50d,30294c3e,15dbfe9b,17c3aae7,e5f8233d,703b7b1a,1401b672,1da32080,53ed52f,a2ee339d) +,S(9914ef0f,e92f16be,a27a9354,518dcc0,1210eb3b,3a90f2ab,6992e3d9,bfdc719d,7a0bd065,cea0b11,e8df3629,faf65a30,5e671d2c,86332b83,98ddc2b1,b3c4086b) +,S(3a68fa19,5599f638,7dafa176,395c9615,5798ad6d,7ace7810,daaedd13,ddf60d3e,74575ae6,a3f569db,394faef1,e0641ca4,de158eee,9a8ac54f,5cd96bf7,d4e71a89) +,S(b7361d41,e2b67e31,f1872b1,b1bffc8e,41193dec,7f012385,9da69c60,5e88b2e5,fa9d6b95,66d49bca,73cf5890,f6e7acd0,315347bd,f10be9c2,9b0907e1,80668344) +,S(341e9987,42d84640,f6fd1354,3fb7ff9e,aa93a4d3,12e99bc6,37b85b83,25174e81,c49608dc,91b46187,611cbcff,762e5fc1,e95b4e9a,6ed747ac,8612b6b9,8bfcfc95) +,S(83d6a445,de34f557,40084909,402c9718,1f6420bf,af87426e,2a0f75da,c483e6f6,7a86db44,58c8fb53,5edcf48a,14a94dd8,e9fbed09,277db0fd,787c121b,a1dddfc1) +,S(4f11235a,14bcae9,89082bf1,c6a499d8,32d17686,2fcffbdd,a40b84b9,26ac351b,b50624f1,5f31269d,168021c8,37739cb7,8678ded,be59e288,6e963339,e94a2acf) +,S(8fbb5727,21cfe12c,ea685907,ab6e3d7e,eafb3892,c082115b,998e9a9c,d3ee2b89,da7fe685,c8148e1a,5cd8de8e,2a5b5aa4,ef1bb1a5,af8bfab7,91c923a3,66906680) +,S(804ca63c,b9243f5f,76605b1f,53f5989d,286023f2,fc672bd6,3f52c59f,5496c3de,372912,eedb1156,a1b8300e,eaeb44f8,865fab6d,49c89fd8,43170b05,d75233c6) +,S(b2795c6a,b83ca824,6b18de87,5660d04,60b48ed7,1de9bbf5,8cc1769c,2d2a5365,66e8c2b5,88530b6b,4d351044,186a8a01,db684157,9bdc041f,90d0935b,2a49d820) +,S(deb5304d,b61bd914,c0939d07,c0464eb4,caf3903b,1903a588,208c5e05,36d9dad3,18d54f43,e7e45e76,6a4b6249,1e48073c,40507dd8,3f7b3b27,762a06a9,4d5777ca) +,S(111bf502,d177ec34,b6c61d69,63366901,eb79d5e8,5749f5cf,7743cebb,9b7714c4,be80d52a,bc38bbcc,f036bad4,5e47a0f1,7d8ba20,fe6780f0,bf8c38d7,696a4e54) +,S(94b10f43,c15c5393,e8d4e71f,db863865,daceeb50,674d0f8b,161bd38,dcbe92a5,ec55af2e,a34e8c36,5b3f7729,110586cf,8d087dd7,f1a0ae9b,d25b9b77,f5be6dc7) +,S(4627abf2,2d447784,c53e529d,62d3036b,fb4a422d,10146248,d3b1f188,e895593,8b341d8d,6110b59b,738172d5,6651e948,cbea9ef4,c7e8dc48,3a560503,eb7b3e4a) +,S(19ce15cf,dfeadcc3,7375727b,5ddc5327,585dcabe,c172aa80,757ba468,297c355f,506555e,ce829141,736ca9ec,886cef26,83853e7e,5b3ba66,25cccfd8,4de60f81) +,S(75a40681,8293fcae,8c3e97d8,e1f916d,2950682e,16d3def0,fe6dcfd0,ab9a3e55,5292d5c0,e02ee24d,8139f2af,495298b7,4526780b,f39f5f22,a047d155,dc8c7930) +,S(a7eb8b8d,ef4b7686,b47a341d,4f4a7333,88cb82ce,8f3226f1,cbbf79bc,1f3bf578,85d98b6f,e238577c,b3b52bf3,94a72589,24407ca2,86865cc8,80cfc93f,bd8199a1) +,S(a5b9a2b5,dcc91d67,b352d14,3c19f6b9,6c9f8344,50e16c00,e8a938de,b3da647a,f12d4fa8,39850471,64335aba,1260cff1,26fc4e13,fd16cc29,63472f28,7b9571c1) +,S(7999c6ed,48d589a6,5df7c20e,e9b0fdf5,df58d831,78ad6171,57c09cc8,44015cca,156f4505,3706c3a1,c54b3fec,bd3f12c8,aaacaf0d,22755014,5bcb731d,418f5756) +,S(88fe81f3,b708edd1,b85baade,6c05c7ad,42202058,6dc2e8e2,fead379,c49829b1,cd62e24f,b04b7d2b,b1434150,260a052c,8972a8cd,daa1db10,d99d40d7,df727c01) +,S(18fb0eb0,cfcc61fe,423192be,b694a77d,91216537,5087a64e,89557d5f,4fe86763,3cf72b1f,dfe8b565,38e88e23,ed871d7,80f4a6e3,55229922,b1f28c5d,38169785) +,S(dadb3231,2be4f2cc,cff171d5,baf18e76,4719fa,eb5fcb66,d919c86,efd38aac,8d67945d,752de8bc,b0740e42,3a154449,50e0b330,c6a73981,3d9f4b30,f98bc0d7) +,S(f0b9a086,7cdd9f64,6b3aa0cb,e3105ba,7b17e09c,6c1c39c2,d8057f06,a39e5c8e,2b534e56,25e6d180,40dcf431,9821cbbc,3ff91303,c14bdc81,370c9e0b,5ef4e9de) +,S(dc0e0b05,2e49c3a7,e5d0e253,672e8d43,1cd60166,648b932d,406fbe8a,c2fcb7e0,ff919786,8e1c651a,4cd39cb5,6921e24a,223e7af3,821fdbea,86547e1,c7b791d9) +,S(e71cae98,fb6ddd47,35ec365b,515c6ca5,6bea748f,11811038,b74aa5a2,32eb91ee,804ae818,396c20f6,e2fc5bc7,5dbd1f41,9ed731a7,2801d06c,e6682bcf,1d600266) +,S(50d1b5b2,f7b2e4ff,3b594d48,6bd2ca6c,6b5d5368,2079bb9f,88d792b4,d4ddfd8c,556cf4c5,18fa0660,86b9b03f,aba18fd,5c554fe7,4020df5b,6e34bc88,4d5cc744) +,S(c087403e,2bd5d954,df8c5e86,f23f6cb4,96634886,b4709747,325321d1,bc2701aa,9db44987,d8517300,6e3a549,eed87e06,258bc14b,e2b00679,3a2252,a3507712) +,S(dd1037f7,f3843422,de8988fd,3f68a299,4d45f8f5,1e9242b3,7980f517,bd6d6894,ca8e6d61,5cfbbcdd,8b1ab8b7,673093a6,1a9c08ce,56b065f2,54fc191b,25cccce1) +,S(de229a19,67ca589b,f4a840c3,d18f764c,424dfda5,6c099d14,73a9cc7d,34b5ceb4,958fc9ca,84ca63a9,4323f4b2,ae46ff44,a1d352c1,1b8e8be7,2d5115b,54122b22) +,S(15e33c9,cc9d84fa,16225f48,70a35a42,f8a3a3dd,67a8dcb1,143c7ee2,4cdfd9c,413c0206,ed48cd5d,36205836,45e4ad6a,a59a1e15,c7f36256,2f89b9b3,660e920) +,S(53422561,ca3c4d87,2d23e317,3b21ae38,dc010b99,b7ab0fc4,394e408c,a3d6bee0,6ee906e5,e505909f,6507c7ab,779ce1c8,20f2c50b,a71bb8b7,8debb3fb,6103048e) +,S(829dcf4f,9b2c4f37,32800bbf,f5cb71ca,308bf0a,9176a74,a031d972,9a82b2fc,47378200,429e538a,4e249d3c,9f58873d,abe3f8c4,615c5d3,3525f6ae,5f8483c4) +,S(ed6f6eb7,3769b1b1,4923b989,acff97f1,c05594ba,1d5f4ebe,450e65c3,8ae911e5,dfee6f2f,3fe584db,8b98cd0b,69ff6219,d52e2d9d,a372ffbe,18e500e1,a2c38eb4) +,S(47e52398,1fbe720e,8fcd1982,df2b184b,70616ebe,cb4913da,30327205,c0455503,afd2dceb,f360c30f,6820cfbd,1de0de70,179f4cb8,6c461251,5eae2f4a,baf3e900) +,S(b02937d5,8f48e1f8,6f3f1170,f5e880e4,ba10e2a8,c13dd0df,49fde04b,a9037312,dcb0a4f,3e4c8456,316de580,5355e17f,8a6c7924,f68cbcf5,347d3c7a,28c18c4f) +,S(9f993cf5,3578c1c3,25c10c2d,c3c066eb,878486eb,dfdc65d4,4ee57fd0,ec1989f8,c6b8d40b,16b8811c,d666ea43,2e61baf9,e83eda6f,d38275d,9143b386,31c8bb52) +,S(943b6cc2,5913ec1d,f12730ed,bdfd1d0d,ce431784,f36fe84e,599f9b89,dd3240e6,e58102ba,cac2ff3f,d42d7ca3,254ef55a,9604d3ff,fab5b16d,9f77482,4fed3fd0) +,S(9b0e67e,69b3f9ec,51843da4,f7b5a7c8,59511dcf,47f58a64,81fbf2f0,19acfe0a,6a4ddc28,17a4ecb4,ce2defc7,d7333ca6,2e074c36,f7e49c67,4a009d30,edc54dd8) +,S(97dcee33,9cd8d18f,8c3b0fd4,48ca6e6,c8246b4,136bacc,72ae8673,a4571651,6163a205,cc20bf39,8aae36cf,c8933dc6,29b95246,48823d51,d82d2d2,74e693e4) +,S(a1e5e6f9,26961eda,7cea9c26,f4a1ba02,798c940f,2b7dc267,2999ff7a,d2292ced,50274b7a,6a710f74,ed138401,36d97657,cfc07af9,3b9e8fbe,ca18d31b,8d5f19d) +,S(473d5fcf,7cdfddfc,52fc9bdc,6fc77180,1c21bdb1,840821a6,1a984296,5b4884a9,348836a7,ad7f550,feb2d703,6c82d95b,89ff95eb,e8be6250,eba7c5b1,8fd856af) +,S(9c187442,7384b2d0,4fcc33b2,70544c98,db8c1e13,2bb149d4,54c51ea1,4796f613,2d6dec43,970f0079,3da12e47,595cefba,c1825d36,c71342b,7913f7f5,fcae0a19) +,S(11ce1c46,9150e2bf,b742d826,be740e4a,ed63c729,5f5bf51e,c7a6aa6,562b154,6e86514f,ea38280f,abdf8b93,be8b7d92,67f3b28c,af2a4271,aa3b6a62,1f4fa33d) +,S(1e037904,e4e2de6f,2893c354,18d1cc6f,dde2fd71,4bacf1cd,4d9a5c56,79656042,1bb759c9,34c26821,2a28aa38,a0af035e,3c81ac85,3c01e21b,462e81a5,8c960755) +,S(52fc9467,23f899aa,f1a94f24,f9e3620,3f8d505e,31cc6800,9951d9a7,c0071d82,4632ae0,75430820,20cdfb99,270b47ba,39c909b3,4b3a39db,92419697,d0bd6dbb) +,S(cb585905,997519cb,214f9e39,496f5386,35069eb4,d78dea4f,f9e9d803,642b20d,1b9f42e7,a5b475a1,e42a0f51,ce2d5e50,7131b2f3,5990ed45,64e3913,ec93ac7d) +,S(382c2857,29f14558,75727584,5d37bcd3,e7ab180d,a11c7a12,cecae00f,b4a69c46,cb27e912,20a70fb3,6e258684,3f128693,495907a3,e0b248e4,a25c1e7e,54039440) +,S(16f086c6,c2850e49,8f8456dc,eb33a692,a4dd613f,b2f9564b,6dcecb88,4f4e5024,2e152a08,88eb1188,3448ca68,25a65034,73cb5ece,c9ad5df3,12deefed,279339a9) +,S(7589bd1b,1f0a3577,5530f0ae,446ea275,4439a51f,66730950,6eed6177,65a02492,2d840e12,d3758153,1e5771bb,14d3634,4076fc3,630c389c,ad9765,98462d49) +,S(18b9ae40,cce63a51,3dedbd2b,c3beee9,a80cc5f5,a26b4446,9a0326f4,d4930890,24b86a4d,d5ed3c44,71b57138,2b270d0b,9e0032d7,8e0ad18a,cf6a4eb9,2a2690e4) +,S(8c1f74a4,acc71ef6,4030db5d,14be8627,94e9ba6e,102c89a4,ccfe8a8a,d3ebb48a,a79f0119,98aea529,1e3ba735,c8b26c86,1af1c119,92d5dc94,16eb1673,9245677a) +,S(8d80592d,36bfaab7,5b557ba0,d03825b4,2c0fca08,8ec7d046,5cd2c203,c2bfb080,3e479487,91f27453,4d0a1bd4,a533fd2a,7671a654,10cd7a51,859b466f,151d3f6) +,S(eab0bb19,f477e158,ec85046c,f2c56777,f36782e9,e0452770,f7125765,670ca248,a27d7081,23093af4,daf55e56,32ba071f,37f0bd64,3f189ebd,70074cca,7cc04640) +,S(ff0d0dc9,ebbb2fa2,6d3b249f,d5260ce9,9647e1d,db48799b,db532c6a,2a0a039c,12b0f6ae,7f161f8b,ce1c3505,5d9b760a,fad5b0f5,66211023,3c43942e,fab31fa9) +,S(d89a3235,71dbbd1b,92340346,8b08b7be,be22b320,3ee6b0ad,42a2aa96,3837d526,25da35b9,9988f167,3108124d,9e6f6f1f,db4a0490,5546fb62,146b7421,36e3cf27) +,S(f150023b,f01cab2c,433cdafa,86751f7f,13ffb315,55d34a22,9ec4c012,925b43fd,31f70e21,26ac896,6dc966b7,17a9e483,8ac37a6a,2072bf34,1a9c3d33,3ac7a9cc) +,S(d98ebd3b,2d580978,72ae9d5e,2c2cd0da,76f442c8,e0b4470d,9b3ee019,c83af2a8,9ed5b6a9,5a061970,34bf9873,da6c7224,930fb358,a514c823,e0017c92,75dba3f5) +,S(55b62d85,833a94ee,dfc2e313,df3ca816,8173533b,fa77d827,583fb01b,cbc3c746,9f848773,cb95af7,b79eb921,19a7a139,1f4dbbbf,44c81897,15bad111,364a835c) +,S(dfaf4d76,fef73f93,44c69de8,f6c1c3fc,ec759c49,a2a7a1ca,2860fecf,bd718de6,ac4af693,44e2c287,f6409f94,c36d93ed,7fba1f15,195bd971,357d3142,725a0671) +,S(84a444a3,4510922c,37420f29,a16ee22b,a7839f3c,5810cbf8,38b7f3e6,c5fe29da,ef733d80,2215c12e,143f420a,673069fe,6e89af70,cbf975f,a1898550,1114f06a) +,S(d7c84e11,46c87008,3ddd24d1,296811a3,2c337749,83892548,6291aa53,a72212af,b187dd58,a3be40bd,c3d357e5,480aec61,9579b2d1,4d79745,f84cd406,10844ac4) +,S(fdedc27f,a70b08be,f3a9f616,575072cc,c7fca4b5,71a2ea06,9ffea788,5598051d,fe9b7b1a,1c575a9e,354d279,ba7f4de2,53f6f54d,e7245fbb,3ec462a4,7b9bf9a) +,S(cfa7478a,d3f2cc6a,92022b35,58437b3,f950c250,4d96b9a5,c2d5c795,ef122e77,f3e48dca,e9592835,354f8eed,ffdd4c2e,2ad7800a,3da863bb,158945b2,261409c4) +,S(8e9157f8,3fd62097,70fb7493,d7678fce,aa1584bc,d8dde3f8,337dce8,ee0eefe2,6079ba89,8c05dfb6,ba4f91df,4b4b229c,3322fb5a,44fa988a,c8d9f3a5,3a05351b) +,S(7bf5efb6,103eac30,ec4eb80a,9bddff22,9d422ffc,6a7f9dfd,bea8b928,3116f75,efadb659,64791edf,e5935554,25796141,2cba4b4c,3553fe67,ba138931,3ba71a3b) +,S(f5ba02b7,b7b2c2d2,68c7b1b5,37697079,690a13fc,89d1d53e,85f27820,d0e8df0b,66316d26,b2640e41,bfc329d1,9d2d4430,a9266b64,c3c793a3,af7f1515,9e465485) +,S(5eaacdf3,dceca4c9,6d2bc3db,f22951fb,87c10da5,f1250828,4a1498bf,ff004475,cb3db3ed,9721ce09,16985d40,4831cd04,b38f5810,977ea106,c8c25194,ad1f122d) +,S(1cfe5c17,b8d61134,53552ba6,ad513371,d1320abf,4fa2de41,77c5a768,a64a5554,53837cf6,4846b887,1e64a2f7,e319f740,99bcabe6,7a0894,5edea46b,fd1dcd5d) +,S(92a83f47,8a2ccc86,1cc91dd2,a1210fbe,286f47bb,44e46880,5e21f0a3,7a5dbc10,fee35c65,fcd45b02,f8270b8b,c198132c,cb69ff9,ec35043,684f54f5,c999de94) +,S(172285ba,d5d539b0,f4d86ea1,35bdb79,73c07ad3,24bf5dd1,4f74ab69,cad277d3,45abf940,cf356364,e0bafa15,cee3e20e,cfc29040,288b4897,314c22f9,aaada654) +,S(ad17bd53,92e19bab,8554ae08,bf9158dd,3126ce81,3a05c32c,7646eb73,cb164762,a129819,1c833987,775d4f47,d9d70d4f,8139c651,896f9b94,e164574c,8d065586) +,S(10421b3e,91a4a89c,1f6ce9e9,13e511c3,c23fd307,c4064a12,5267cb31,2ebdeb1c,539bb5d0,9e49f0fd,186b8a51,73118cb,98569700,dac77cc1,92359286,3aa53319) +,S(c43adcfa,78152a3d,dcb9eba6,6632aa5,2e8476de,1e0e30ff,39735b06,21de5bfd,6ddd09ca,2122580b,847d04f0,5dacbb7b,1e81c6e2,6057d880,1a911a55,9cabdebf) +,S(f7a99ccb,603a58d0,4c6b9e50,d9e7d988,14434f1d,92aae27b,5c8d9006,98bf9a73,ccdfc244,76f4393a,e96d6809,1cb74130,5e62934c,cafc9b08,78a3a77d,a71a7ccb) +,S(9abc95bf,70174ea3,5038f44f,4a2ca9be,f602d516,9d249aac,b3175be7,e09c826,6cfbceed,3e71f8a3,d427d2c9,f8cedaca,22a9fedb,4cab7763,617198e0,d7adfe0c) +,S(8a7ca893,35c84873,ecb4af06,b493c9cf,d7bd08fc,d0535c5,546bb9ed,5c5d8d82,2518b372,90d3c08,72f1ee4e,54144799,209ae3fe,d2f285ba,7b00193,21e31bc1) +,S(70c8e379,8649628d,969182fd,862f8d4a,b39fdbdc,c246fb79,ff1c9227,a64d1c3e,c7931ad5,27ec0a4a,ec297d9e,fd56208f,936c9517,4efdb86f,7f50e321,26ea3cbb) +,S(d783f6b4,6121ee0,71ddcf61,b4808fdc,934a82e7,c185876b,9572d628,31002121,aa92bd84,14226949,9e107c82,b9a64898,28b3ed15,694ba62c,a031d98b,5e9c7fbb) +,S(c1f06a1c,29abb43a,cadffbb8,7ea8e4c6,b7592795,9c778758,1a17e4e7,7b654c18,1dae0de2,f1db42cf,ab9b0e7d,9e5a098f,bc102470,aa418547,6cd1925e,fbecdbf0) +,S(2ad74e11,3205b587,866633ea,32172662,d1498a27,48698724,87b7e62e,52cc5105,c70c7507,de1fa1fd,625aa7d3,755c83a,b5c85159,4b8bee10,5de45da0,d0ff779e) +,S(f490e9ad,72246a46,6eb74e23,371c4f57,a9e32b57,74ac9ac0,3d800978,d77408b6,546f367f,8fdd1687,ba6ef15e,4c258507,77e49a1a,8b449fb9,63a0f01a,a9dc3d6a) +,S(20502891,8357b697,e05788b0,55f8bb32,80c431c5,de07055,3f123373,981d6149,39d040e5,44110e22,58da6771,2852fd09,9489ee5b,5c77a777,7966abd0,468e3b0d) +,S(6e91bb8e,c169a3a3,eef59915,d4de9296,e4b78299,e038c5d1,bb001eb2,f86eae95,d2c21297,88f8c9f1,16434063,a89fac48,45305dd5,d208c887,2ae94ba2,80877dfd) +,S(cf2947c8,39fc40b0,610d0d2f,e1e5ad53,39e7d0ba,9e7dea01,90678bb1,6ba34905,6145a70f,7f0cd53f,d758d7b,172e875d,8db00f6a,131ec7ba,aec140b2,3f37c63d) +,S(b48f8387,ea93a6c8,561c9b01,ad32a28,1c8db1c1,ac3c6864,ad161874,fa2366f1,2cab333,cbe07d3e,26fd971b,3609cfc8,9f46bd81,df84276b,375315d2,7a2d253c) +,S(7c4b5f66,c572d34,e4cae58c,696fd43c,30f6054e,8145715e,f391eda1,42a1f827,3cbe264f,be125af0,3907c5fc,c61232c2,d0adc2ad,5f94f3b0,8ed32ad,99843d97) +,S(e5796368,d4649e19,6227f989,78758d9,8fe24e51,f5d5a567,378a85e0,850d86e8,74bb343,c9a69128,9ae880bf,67a7e4be,1fa111b8,d6608896,46ec354e,f6c9d4a7) +,S(dfa1065e,fe83e9ef,c19b8841,6e3ca5d9,67c1ab26,53c7d650,9f02ba58,fc4d637f,22d2567,eb0237ba,2f270e04,685e5352,e23fdf19,a2aa0a23,1ec83eed,ca5042d) +,S(2ea1d8aa,d436c332,8fda3ce9,8e710b80,8f463844,cf131f2f,2347b37a,928af132,33fa7e0f,b8c2ad10,580a243c,ccf2a4b2,13ff9620,7a034432,8fc61f31,e98dc4c) +,S(12ae1451,8122af3f,a788298b,5e59df37,ab6a976c,f8a931b4,c0a51de5,d567253f,85ff1dd2,b3271d2e,de2fa732,9e3f0a5a,1c3ff9ae,b55555a7,926d31a0,1d24877d) +,S(fd46e1ef,b588af1a,a72b84fe,dec75a3b,125579ef,55ef8270,85645930,95bf6619,d06adc6e,ceb6292f,60c7d477,c73a2aff,342e6b7a,e81c5ea4,f57cb7b,27a51b17) +,S(ed7d93e,b8c0d1ef,1c49e1bf,be22acd,c7a17946,b172de61,4a290d0b,7f32b52b,4d0ec30a,39a81c3a,f8f6668a,742abeb2,b5552284,a68ce246,f368ce9f,b2303ada) +,S(fccfdfa5,cd0e79a6,9febda81,475c06dd,58517913,3624f4dc,9d808b6d,e9619ef,79b9040d,11d09bed,f89959c6,992a9636,ec62324a,d60e1513,9bd2441a,dd0adf49) +,S(831762b8,6a9b9afe,d2a044b2,7bc714cb,16823ea7,22b44010,a57a5564,4b4ac477,147ae062,8ef3bfdc,b48b3f77,f84dfd77,2754c1dc,a626aff6,9c3169e4,9956c708) +,S(33448c01,a84d5303,c8f70adb,bfe0ccf9,f92cc461,f2656fb3,4903b99d,4ef26b01,e5727349,ae8ba61,c8ca8284,ee7f906,208ad03c,6fd7c95f,736ea541,ffb8f2ff) +,S(920a1261,6ddf1304,157ccb8c,50ebaf6d,60df85da,b19b24a2,48254cc2,7d215a6,19e4d4f9,cc91e890,3d2f7a11,ca8c0b97,e2cb671c,e0c4ee36,9f1a3ca0,f28d0f4e) +,S(1df8ce1d,3e370b9c,3f60ac00,cbac25c5,458385a5,c4b926b7,fcafe62e,536b1ba4,344df46e,e3635079,52af6160,2729094e,3fcbabf5,bc701083,533e7e60,5099a92b) +,S(7227847d,abfe26b8,13c18175,c37a0526,2e2243c8,d80d93b6,286b2881,d38b7b72,bede79eb,33da3cdd,95289c93,46165cf9,28b5aa41,c46b364,622988b8,a7973d24) +,S(6defba59,e1218bfa,b02571f8,ccc84104,3caff74f,26d8d995,9729f292,eff7fb8d,4d7baa8e,21f2fbc5,96f770d1,bd34e77c,2c188c05,5921c1a6,95696a8d,4c340a04) +,S(c667f4ef,f5127d24,6b31ae02,2adf53be,8302e1a,b631a0f9,90b16051,e02d6bd3,3d7bce76,ce11bdf6,fd4d822c,37d746a2,f8de283d,527af237,3e80c4a4,dad34cf5) +,S(ed9e8674,441620f5,990dcc24,23a2ab00,6fbca1b8,e6bb3d23,55c2c72f,ce29d866,64d5ed9b,b4289a2b,b81a12f3,30930dee,7c03dd71,1ec361a5,8297c22a,5806ad30) +,S(86a36c57,e6b0cee0,33c00b25,66344ef3,219e57ee,ac452ea0,b0eeb98c,3176fb24,b4f4bdda,9e9b58df,4e103874,89592b5d,b147b43e,79a1af25,135e8db3,eafff739) +,S(2e237784,45396ff3,a0e105ac,ba151e3d,fd02bf82,1de70e04,33792280,bccca913,f736539c,e77983f0,610464c4,3bbcc904,f43726dc,a336304f,c0b716c3,67148551) +,S(ccd3c14c,7790d936,5226dbcf,11a0bc00,9db88a87,ac2d68c1,6899f980,20a1390f,b240b35f,bd6d5dd9,f33bac2a,f1899320,f8a9cba8,7df0a67,81cdfdd7,1c3af907) +,S(7713be7f,988d7b1,c6c6566d,558978d,eba4efad,b82761b2,17bccd87,3637b018,8fb91a6f,a9d62baa,2eeef7c5,15fab341,c75f31e6,64ee7d94,70db34c2,74475781) +,S(5485ad60,35dcb3b,9520acf5,6b0855cd,34c739ff,1c59798b,1ab667ba,a4982b02,1dec6c7b,1e7c14ca,743df62e,589311bf,57cbd455,e7dcbf9f,cd439962,96a90f0f) +,S(a597503a,d3be484d,1d2d1cf,c4e8540c,411bd201,f2b05ed1,89c9a3dc,b0ee0f19,35113e7d,38001199,1e2cee66,4dbcf490,becbd6f0,765c94dc,e2855ee3,b01113cd) +,S(ba91b251,abb130b1,57dd07a3,dbd2fd91,1ae24937,80c8046c,b94de57c,dd91ce4a,cfcc2080,500aedfb,a69f33f5,4f642fbb,8377420f,e1799dcf,e1dc3593,d3e1f6c) +,S(adfb5a58,83cc7bd3,c6fd3386,95c86414,5c6d2f4a,603fb2e2,fb045bff,86d324a4,16574ed7,45d82dfd,c50415a1,8c30da91,3a525753,cc975722,22a5553f,7b0cdc5c) +,S(1084914d,dd710a5c,ac854b14,10a4be35,ba1f13a4,e0fba3e2,9d94edcf,a3561ae8,653ca135,3240ef60,412ac6cd,adf8e664,2f2b74a3,5908c3ba,be6dcf85,49c25e99) +,S(704aa271,9af38b14,17a8abe5,b881efe,81876a6a,f807833f,133cdcd1,6e6c6f7b,a6fee2b3,48c1180b,c48726c9,be2a1a41,11395af4,42ba7b92,63f4f66e,a3769e54) +,S(46048cc1,7f5d2a86,5c1f5734,893c6683,fe68b0e8,942c9080,51d7b836,a8aec289,d85cec30,89a8f77d,75bf9c6,bb4f8a33,2e766834,3841b277,a461a079,8b288efd) +,S(50f1e6be,315d3b21,636781ba,8598d2f9,7d04ccf,5ba1fc76,3d547657,77fce9e9,f7dcb7d6,2057b9f2,8cc24975,9dc9621f,25dd0ce1,47e00db7,d095fb0e,ee6b0b00) +,S(7ed0a244,676655ad,10efa03,7748d49e,944df1f3,5bd46d0,3b7ffcd0,a63501c,a8377a65,593f227b,446eb266,936ae475,e9b3ae65,a60768d8,2690d0f0,5c18c21) +,S(d039ca1,ee66c2cf,611c431d,cff1bd2e,19b29d3b,b1f37342,c29f4632,4febccc7,db0d0d82,14f4c661,629ff5e2,4cfdcc84,6e652ee1,15a6476e,7813104e,696d736f) +,S(c27973a,cc55fe2f,4531768d,94cd4a0e,8e36729c,aad61579,7beed810,a7b092b7,cdc310ea,b36ab246,c56d5402,9b9e3314,878e1f1,ff7520db,43917a14,1f41c99) +,S(36842942,cce3c683,25472e48,de202d15,ac14a180,3a2dd84,6de0c33c,6446e945,5000b3f8,19ab82fa,3589db9a,eed5609b,208d95fa,ddaebcb,57403b96,7b8f2f7) +,S(d1aa195c,338621b5,19ff3a8c,55abb454,74865ef7,85e0fd7b,c4554ae,6d62d0e9,e7e1dd33,dc293859,b4634576,d8840630,832ce773,a9a8bc88,c2e67251,a7b737a8) +,S(4f423d32,607439ec,366bd6ff,5766ec13,a59b2c2a,8cd008b0,489f267f,5c0f00f0,5e3c7e9d,7ee94c15,c048e6aa,272c888c,b6c3e058,4b4f4ee,f5e1d787,a4e7a9f4) +,S(6bb1c680,ff8991ef,17c0859a,9b5fa9b8,ebcb9afa,af7398c5,9101bb99,7f06c4a,318da775,d912ae5,d17c242c,97615c5f,217005fd,535b839f,189ff3c9,8669a253) +,S(14095d4,4713a46a,5fcb251c,9fbee2e6,bc393423,30303b8b,d0f2d09a,c0096f68,647e000b,3660b374,959e632f,6867c7fc,1c7aa4fb,b7f5593,22dcb2ba,e604a2b1) +,S(12112bf0,346e9c6e,4a8f831f,6c087876,8943191a,38e9fb83,8b2613b0,4b5e5323,e4149ac2,cb4533d9,4c3abf62,aee4dab9,faf64065,89cfe10e,30a42986,9657a3d0) +,S(f99360cc,c2ed4810,d80974eb,eaeb59fd,4f2197a7,8459729b,4f75c370,8bca5738,b92a2f5e,86d77a8a,c2c1b9f8,6e1971db,a06e4414,935020db,c0c83a92,ee6f1cb3) +,S(2dee5a4e,c81a3ecc,4872112b,be53f51e,64ae779c,49488567,a654e806,ea809ca4,1e2ea8a1,df6d47c1,c0aa1bcf,ffcf260e,bdea4d63,934ff3b1,bcb1e1a4,c73d4954) +,S(5baa6a2,139eeb78,f49638f7,b0dc5010,b73688d1,bbd746a5,f2382c7b,d461229,72677383,10a352f1,9f2a75cd,9e42509f,b08a0ca9,60154693,cc01d595,25dca81d) +,S(a3f77eb9,321d44d6,b774a6f3,b1319e46,f60d102c,d96e983c,8f8568ba,82913d70,f93d75df,8271e70f,1aa38630,26bec1d0,f6db1765,77470077,d3fceb8e,5c613a05) +,S(46ba66b5,fa1f9274,378fd62d,68ae9f38,8588d766,ebbe97db,72f9084d,c7f2cf08,5473e24,3078b8df,92df9b55,52ad5055,f44bf7e2,ecf0785b,72db5dd9,238897f9) +,S(db6a0246,ddcf0260,b2b415b6,f551fad0,bccb15c,ca196af4,291d21ce,ce80dbf2,396cd446,f93e1c97,a56c6f6f,63cd0966,5f88856f,e75e1c7e,a985917f,28591d3c) +,S(b82f8d1c,a7a298da,3992c4e5,8dba1b0b,38187eb8,66992e8c,5cc1c834,6e6c8fa1,4b0ae76a,f9b0413c,8d4fdbdd,db767c6a,b1b80589,533e3ee0,28eb6036,1483461) +,S(446e96a4,dc9264af,e9cc6348,aa612861,d106fdd7,b7ff94a1,82e0f018,c485f000,32dfe3d9,21593a58,1fe23b7e,ccf677bd,2771c40c,a612a507,c8e33df0,99568440) +,S(c86f10,7bfa6dcc,b9f00ca3,465049de,5c8a3e6c,d85bdfb8,1ada1d39,303a2eb9,e64f7066,7e910814,ae18c6a,7323474d,9dcb277e,4aaa7ed8,88bae4ae,7c34219d) +,S(bed8eb6e,cda14299,e4cd94cc,202be7b8,9201c2ab,302a5cdb,83e5f5ba,db6cd710,15736cfa,b375a40c,5d367b9f,6692746d,16a1f03c,20941256,708489a5,5d411aac) +,S(b3efa7f2,c5f6ad10,41f171b5,ad759480,665e0a52,de82a881,da1926e0,8f64d38f,3df63c84,32761a24,eb0dfa,ae98e034,b6dbd361,3fb53ff,c535fac8,ff1677e6) +,S(b0460da0,cd869b5f,235213a8,49e143e1,8fa9afc1,651ee921,ebdc525d,2715cbd2,c11a3ead,f3541877,ce73b4c0,2b57b299,46b4725e,cf630eee,865bb121,b86fd7ee) +,S(28b09517,a17452be,b2c19187,12d600d4,b4969253,a7d0d52a,49cec3ce,d73bc071,36696708,73c7591,11163518,40af594,40ffd6d0,690ddae7,fce7a43d,e920a326) +,S(521becd8,192acb58,7ae76b7,c0bf17fa,ad86afc,47157753,6b1a51b0,fbb5f136,648a54c6,d7aff13e,cccf399e,15451682,ee06710e,edf32669,1dc7fe83,75ac858d) +,S(b7bc19d0,b7fd9d65,26c9bca1,b587d84e,a2a200a7,76d39082,368b761f,79f6cf67,5adefabe,e0d0c8cf,4252c29a,773163b6,4a1e9ffe,ffbfe3ad,2f796e8d,1f70acae) +,S(e48e3be5,1b6ca8d5,41f0c241,21558cec,66db7b6d,c13e7114,dc931f0d,397aea8b,dbcf6357,5b16e2f1,30f064bf,ff12b465,f6cb3a3e,f9f74431,4bf41e7e,e0f28ac) +,S(395c6de,71c692a6,a3247596,8e28f2a5,4ec795b5,9759e890,9b2f4290,9f455751,ee5e0118,3c7dda2,c1eed4e1,5aca155f,b5b097e4,499bc3c3,fcfc2c85,a669a13d) +,S(28938ac3,b1184399,22741291,9c0fec36,663da3aa,8a4e89a8,1a66052b,ca808d99,4ae8de7a,b1ebc1be,a2beadb1,80cb9a10,da168295,ba1ea5f8,310b986,4f174603) +,S(5c0f618,95e88cf6,205472f2,3e27e853,be3af64f,d0a376f5,8523ee6b,5248f5a4,be5c3c55,cd09ebb3,b7363456,9fdb50fb,8473e3d8,3441e624,b41b1c3d,e44be51b) +,S(abe1f7bf,22d0f733,ed28e125,f7ed05ba,ae2e8f13,1eba2ec0,1554dac,5e3ca1d7,2a5a48db,3de31f6a,9708ffe4,b996cb33,e553e6b5,95aeaffc,918aa2c4,1ab0ab4e) +,S(c3042427,57d370b3,79124907,ea609129,5f1dbeec,442a6349,bccfd29c,e08d8be7,67a64eb3,3e0fda75,535b35e2,f8c9811d,528959c1,29e8f144,8bb75ce9,b1868934) +,S(65a59946,356f219d,77af0b6a,9e1a43f7,3152746,6af41c21,c81532fe,3140f5b8,64e7128d,5d3e4fa0,518cf27f,c070da20,1692b059,3d84641f,2463a61c,74f35918) +,S(6c7d2e3b,48428c87,46b066f2,bb99da10,60311cb7,d4dae19e,de2eb53f,141413e2,4ba47bf,c2e7c670,4de2864d,1ed7b383,286292fe,28f7c7ab,2a664bcb,6cb7e3a1) +,S(dd257bd,b99c89c2,b47798a9,bc93ff57,5655797f,a45399cf,44acf58e,93fdcdd9,f8d670f2,a9207f25,52e7e0d7,14289103,e8194f81,6390e0cc,1af2ae36,c1b3e4af) +,S(2516034e,b8ddc424,42952b8f,acd47c62,6827b87c,b08f263e,b2aab5e6,ecc23d7b,ad8e8879,f5feea07,ad3545bc,a731dd30,bd2ab534,4b486826,433c75a1,6216ac9e) +,S(7e723054,27b591e3,b19834b3,8211edc1,7f075215,6591980b,907dce0a,d934246d,5c91fcbb,d8c184a6,f21671df,1098760b,2506bee8,e32474e3,3b080147,4e63a71f) +,S(1b1f9d16,ac3c0d2a,4b87691,45a6f6bb,8d4fb57f,ef9df33e,72b5d399,6dd1898b,6442bf1e,5ffe450,b14a399e,16241a5a,15e94453,94519bd1,24d0a67,f35b4b1b) +,S(e0f1fa4e,57cdea43,a3b9f671,596631c6,65b5144d,93c51a23,e9006c63,fc872f2b,c83851fb,54890d14,2f605617,151dd47,74f9a3de,cd27d864,a49c176,af32e564) +,S(ae95bbb,697c820a,251a3667,b2a0a078,40efa027,99d7bd0b,3e9a12eb,32728c3a,e0dbba97,280096d,86ea4da9,45ae509d,1140e0dc,7b803f10,e685b148,6baebb41) +,S(fc8ff885,d52ef42c,1fe529ea,853ff8c3,afad1ae,6e7f1b30,69e34076,682aed31,525eced4,b26e8f62,7b904f1b,3356d01a,9cced71,432ac850,433e0a64,b1e3dd14) +,S(6613136a,459d625a,d5b5753,3a965a0c,ed68d63c,13652546,c629cab3,32c8e810,10f29ff8,24d30a94,b3d732b4,3b168bd2,28b4cb01,4012469b,93a9853b,655b65cb) +,S(45085915,7b683327,c76309b3,96ef3b63,19dda841,f6be1b91,f24f5a37,ddea56f0,b9a71446,584a88e4,6a155e34,f08d5a6b,2b6ebbbf,b4b1aa12,bbc7654f,91956821) +,S(168ee3bd,8f10ba0d,deb82576,cd5e1711,be58af4c,2274464f,e32f3f7,7c8a4325,6eef1e63,43ff409f,a916891c,982f8700,465fb184,5820b886,68b74202,6678b34c) +,S(b3191d97,763c2341,4eb4db8d,eb2003e4,fdd86b4c,6077931b,71802714,ef048c04,b4ac3085,59f975ca,be7d53d8,3ebdd5c3,ce6860d6,37710a04,f885a83c,c2152edd) +,S(da9d5c5b,4e73dc93,3c72acca,1e93f4bb,3ec477fc,f201096a,51ea0226,3a2f8738,7fb6a2da,65f966c3,689b93b0,d6366511,400c05d0,8b0a15b5,b4b3209,a812f8aa) +,S(140e55d2,a7e75678,1791730f,c526470,8d1cfaa0,954e215c,1e65bcc,e4b0dd66,4bfba0d8,63ea2597,91e470d8,1ef36318,87e2d5e5,c897918b,ce805941,953d5b3) +,S(15a9ccf6,4b95cc87,cee9bd01,bfe3d8bf,b438f7f8,66344a1c,f3f399eb,16b173d8,4f5472cd,bdebed25,605e51fb,f0b31a93,5d0ba59a,6e51bf90,e0363c8d,9bb33f3b) +,S(e86e364b,6776701d,b7b3d3d8,fad181bc,c7ed5e91,2d0a888f,814caa3d,88af6e06,22fd460,afc040d,3e995518,c6286989,24a466d1,4a624915,f834c357,4dea7b92) +,S(3c261a98,cd25f0db,2321134c,723ebce7,b1f81d3a,a6d5bddb,fc282fae,5a500eb6,2b8d2145,5e498211,8a4b6ed7,ec96a66c,4027a506,deaeecbc,45535fc5,77abd9c1) +,S(49b6a811,4d55b517,6cbb1f6c,177aacfc,368c3b5d,238300b,d66546ed,f4c955c8,d1b124a4,9f0e7c1,6b8e001,7f1b0b2a,ab94411,391d5bca,5b535838,a3815b94) +,S(6ec8e861,f0d3e5a5,3f9deab6,20cc4b81,6cee801f,f7a43f71,f34a8dac,c525f6b9,42e0545b,68ccafbd,3309c4f7,eb6b5eb1,1e01a871,c63fae27,782001ab,a6dcfd6a) +,S(7342b341,59aca5cf,d305a2e2,a8f14da4,4b527e57,4640fe1a,c08898aa,4595b9ac,b5261302,d2442ee2,363969a8,4ea61281,27f64f40,ac86dac1,21b5d234,53160124) +,S(842b30bd,54ef350b,65dcfc43,df26967c,b2747757,a609c54b,687d30b9,5a686fa9,4ffa9e92,2caa36b9,ecf31f63,f5c8de57,7d594f7c,71e7e77b,9cc5ac83,f336ead6) +,S(2dba435d,d589a7c7,bc3fb60d,495757ef,7c13bb0a,3e91a153,9998e04c,19f94862,c440720e,a4b23cb9,d238eca1,6775e500,931d3e5c,7df853ed,55cd4889,5e8cc0a1) +,S(9d1e8524,8f84ce5b,2a75a457,819390be,bb284fbd,3d035c07,998d3c45,c73bec02,8e40ee4c,c935ccac,2338bbc8,4a8063f3,6d62e8cf,849bff40,1298074c,94eb9ead) +,S(d2735ac5,d1fba75b,d4f63912,11549755,9a7f8623,62e25cf4,e76562d2,d8b441af,bd2ac36,19f9f339,77b7cb0e,5b52f3e5,b4ade86d,1c9fb31d,a1d8fb36,7dafc081) +,S(b0130e38,f46cff13,ad1a68d3,15729395,b27c2b96,e0a957cd,ca63adfe,b0a3e11a,3d9f697f,4a61401c,87eff844,3b11776a,610f1516,4366c1b5,535599a0,c6aa3c4) +,S(e0aa062f,15306af8,b662d8f3,3b89de8b,f59faa78,29942caa,ed82e668,35ec76a7,c5f5f0b5,6ea77304,a5dffb8a,cac98387,34305b54,25fc6181,79a4457e,c15e6f2e) +,S(ed1626c1,a8e6d1c9,187e15c4,ae9875ec,2156d685,997ac413,9f44bd0b,19432d5,3c0d895b,9dcb4a3f,4235e531,ee7373f7,7f0fad46,c5938d7e,69d50429,71f0c35d) +,S(a2cccc31,4e18fdaf,8cc25aa6,74c974f8,664744db,86e04be8,431d2ed0,4dc92833,b6410e49,d6d471ee,d20e5536,8672f5e4,2e1b9c88,c06438a8,46c3a74f,c759d71c) +,S(5bfc192f,db15f62c,4af19119,b2d96a88,b3b24e06,3d54b31f,a35f675b,f668bf27,46774374,acb4e140,90431bb3,9f62a38a,dbe0dc62,4021e23b,6099e198,47d99051) +,S(66842a89,da73c404,32a2e553,97efb009,61eb2155,886ac90e,97dab5f0,9227028,3a8e83c3,511ea048,88d2dc9d,f1016cd9,da171bc6,89c9af4e,90b18091,21941de9) +,S(ec823197,3ba95f98,d45f8991,3ee8b92b,e3a4a84d,d59342f7,1810766b,cdc516e8,532d3c79,f5113f4e,1973bc88,2a953b5d,77d5476d,ac9972ae,f1d25e19,ab7206fe) +,S(3b65fe78,bc516176,aed5e5b6,5f3ed39f,e8e8e26c,32ab07ad,1ac2519f,72fc140b,856d36de,5190eb9c,13f7f976,466f95de,566a1fd7,314cec1b,9c9f7adf,98208d98) +,S(3ac0eca,51c43525,e9e545ce,83fdd009,f9f31eb3,2722b945,18262036,d18cc346,dc72018b,c3b2a4cf,3244ef31,340e0944,325bebc8,b134de50,9ab3024a,a213a7e6) +,S(4929658d,6c50ece6,edd2db7c,217d9be0,bcdac8b9,bb50972f,fbe53a04,2ee23508,e5aca42c,61aabbd4,b8555980,a2328741,6dfc8df8,d7a10c3a,7284bd90,aacec38a) +,S(9d16e76f,4bc96492,f0e9e748,8c6d2297,7830e2ab,491a6278,1d60ab5b,153a6291,e6590f00,e4ac6922,5436318,9770aef5,5eaa988a,44e9711,da7266ec,895ac7ab) +,S(b0649c4a,1327e7fa,f52a9bbe,7ff97add,4e13b36a,27c0676d,5e09b2b8,1f5df94d,991c8316,a6f36848,e072a080,77f75a8a,d79fdd08,1a606d12,b355c3c,3891acdd) +,S(8f194a21,f6303ded,2c9ce51c,44a4a16b,eb39a8f6,5fe13c9,6b7c12bd,b052235d,bd1df3d0,c9af82e2,545afb23,e9a2dc85,c635172c,edfe70f1,bd755d26,9730739e) +,S(1da71a97,cc7a4cd9,4777f6c3,dd5e665b,3872b721,c6c2262a,60e87f1d,efe21ff0,78d17a41,39036e1a,7af2b9af,1273afeb,a4d30e8,66a3e6e8,7f0d0468,4be6a06) +,S(9fed363,e493f262,d3efabb1,c52291c7,e04e401b,b181290f,7a37af3c,df86aa45,130cc33e,e164adff,bedb1827,6a5c965f,53a54f36,90dfcd6c,b3fff836,703de729) +,S(d166eccd,221c3568,199ebc38,fcbb6140,7a601a3a,c1e7a98f,ebb75a87,a7a1e49f,262222b7,e7c200bd,5dcec562,85485434,b0628c7c,ce5483c9,93795f76,a072f06e) +,S(e7853cbd,3e3770c1,cc307839,294a2e8e,b998a56e,393435cc,2930920a,8ddbe0fd,7977e6ca,67147cc4,965d2918,1023c3bc,cff1e7b1,8fa4850b,80a140f6,980e5a8e) +,S(a8b0feb1,cb140201,2bea3cd5,6b1a1f02,51036ce7,423f511,480f49c5,6227a17f,ccd7c3db,9d3ab6db,6cceedd6,d3801c8f,67afe792,c8977b5,27c9dcfa,75ba8a9f) +,S(57ce5dd9,e1815755,31e90579,74f58b98,6d02e406,a846ab26,c9059f6c,56d617d7,cc34c090,4399f316,269598f8,aa8f9aed,829f61f2,5efc9bc4,e851ac63,fe142d14) +,S(479790b6,4f60fc6d,befbbc1d,365ab3e4,8077b6c6,cbf02f2d,6c8b986f,d0f9c858,157f4982,e3581925,dd25382a,e3e48fa6,5cff911a,95e9bf43,5df8b356,87f2f9b) +,S(55abc7b,1ffe0a41,2181b622,813be76c,8ee0a0ca,3cb37b1c,cb265087,fff17c68,bd134249,23e94c53,4cf9e603,a1dd259,606272bf,8283f2d6,69bedd4c,a971d99f) +,S(6ca7e032,8bf5d67a,b804d431,e5f709e,bd3156e0,1d4511da,1dc67394,24d2e659,c428b133,f3683909,6551c2ff,2f870d80,d80aaaf4,6d2b1a69,7722057,5eca2647) +,S(60df19a9,83e9086c,4cbd20ba,fbafa8b2,346ae4ee,9c1ad4dd,99959e91,2df530d3,dae7b854,29f817a0,421c2f1e,e4e8e4d,a09d60f8,84701e31,d7a8b7b0,3b79cc48) +#endif +#if WINDOW_G > 11 +,S(6f18d50e,5ef5f2ad,bad80ea1,c59a3847,5c22ff05,6ba52c7,e1d26d6d,d3686bce,d1d7ea0f,a166efd0,facf5c83,bc3786e0,d3f3405d,5b4578f5,13a336ad,f0d7d7a9) +,S(b634dc9d,5ed51336,4ac9569a,8ddee9d9,fcdfe00e,65e59233,b3be8a07,2fd949e0,d72e46e2,c61b2575,f25a505c,bdc3456e,fdf18976,6562a1a7,e86d036,eb31db69) +,S(5a37fcf0,2dba24f3,e6646171,43dbc5ab,40d91983,69f5cf0e,4fc566fd,97445910,a960d1d8,13f8746c,662a9582,614c7847,33e6153d,2975cb59,c3342463,75c69d1e) +,S(8aaf16a7,37318032,c60201b6,b196d8fd,eeeb8f8f,1aab29e1,1b83ae1b,f112661c,c461ef56,66a3a4a7,563cc0c2,845f2ae7,6d03a795,987c615d,611bab48,ab9a8e44) +,S(456f0ba5,a05f15ef,d93e7f49,e0729c45,1d85a693,42c2804d,9cd4b8ae,af5e3434,a680f4a9,99221a8b,7f46da13,13041e16,13f616bd,84b9135b,b0f7ecb2,7311cad5) +,S(f89c36a1,f1905409,75f146d9,31e12cb9,4bfdc90f,a178970a,9d0b34cb,38f5c741,3b562c80,58e31b92,a1186615,9c1ffa3b,4b1df38c,eb4a1646,579d2375,9c44099b) +,S(7f6beb11,2e1d8600,d8c4903,1d69cfb4,e23876e6,32f30428,9d2c2503,41f3f76a,a1937407,c0925afc,be994b9b,51627b98,8d98ed6,e8cf6fb9,cddd0ec,a4ff4a9b) +,S(905ad0aa,b585c7c3,78b7130b,ad1d5001,1010f543,194f40d3,827dc606,12d73511,bfce0701,c3ddcd38,150130ae,e91d16d4,a447821f,a2e098aa,b83b8025,b7177a9) +,S(f559c2d1,62122fca,7201e7a3,b6033d1,e54187f4,7550b2ae,f1d51521,f7408b6c,3f10d622,dfd0eb14,7f6f04dc,43108273,7695ea42,38ced7f2,5dc167ad,34154481) +,S(19b328a4,fa17149c,ccae5830,a8bedf53,7c0d8a0c,c3616345,6f4d91d0,718ce8b4,9a1ce80a,2a4e6923,69925883,8e786779,fdff7f09,25d68855,12644d04,9e582f64) +,S(afab98a0,e75619bc,ebcabc24,c1a6a0bf,2743d4f4,921fe53,3a393648,adad5d4a,bf1b3a87,759139a5,79741c09,21f29a10,7c8e5be3,13d75715,7dfd39be,923a32db) +,S(c2cabf7c,1d86a34d,addb36d9,c83a8ec9,b2dfe0ee,8176d085,cca91fd8,ee4181c7,5b32b724,53f1335c,724465bd,6eceb8f5,159ab150,e9c972ac,f51d27aa,4d91070f) +,S(92839424,8e847452,29a8c534,7c14355e,4f6e9cfa,2c1a2be4,f5ad6cfc,2a89f593,bb9c585d,fd41ee06,99ca7b4a,146faf68,51983b15,d652e996,c888a171,7c8c3a07) +,S(bca2853c,389ef184,208cba64,617bd7ad,55e55f12,d0c9fb4a,a8dc30d0,c73c7dfa,9f41289e,f32aeded,3d45952b,16a62fba,fe9a142e,1e65340,17588d79,e1df63a2) +,S(a4ea7bda,94b565a8,ebf53aea,5ce672c5,5745b7bd,37ca77e4,a0e4f281,71bf56fd,c9507485,1405ea90,9b9e1a28,42c5953e,629eef31,37bb0fb0,970cce6a,893e96bc) +,S(71707d45,af71139e,d7327ced,89a2403,da57c18a,8527bb1f,f754e78c,60d5e169,24b36484,fe4da6f3,a3f4e4a8,55a477dd,3eef0f39,fd3c585f,1b9de9d7,10223ef9) +,S(52c1de03,296f591,9d5cf4d2,36b8ff51,5b1f5ff6,d73228c0,7dda706e,4fdf9a05,db958d59,d73d574,384066e4,fda3b785,c9509714,90607c51,35d1d34d,5a344d0e) +,S(7b09c0b0,7852e845,30691989,cbccbb87,74dc2007,df827120,d8b1ea62,2368912f,4edf5717,ffc52817,d0eebeeb,782ba4d,9545a5c,da979f3b,e9c09e84,f82bd263) +,S(e99870ce,b29ad1a8,2bc08834,3e3b3c03,f26e7062,66b32540,681c689d,ffb8300a,8080ad92,78947d65,bcc12dbc,614d17a8,8ff75e3d,91230fad,c6f785a8,cd597f9f) +,S(c7e2326d,e28b8139,85db4cb9,c3d4c5ee,2dd2c2bd,2b912444,adc3a434,205c38e7,5f2863f9,cdc0cc95,1fb87000,e177cf05,d31adf8c,543d899d,195bf5e1,c6ad940e) +,S(883596c8,4ca7bd78,3c586bfd,28fba489,4c6bb66b,5ea52244,1199b55d,3e3f7965,fb114be8,59255f10,c96d6d4a,72945ac9,47a22f5b,68ecfac6,9406bce2,58e9282e) +,S(7f73a648,a19640f5,b0f029dd,37e56e7f,5cf61659,5e532dcf,7ffeb7e3,f20b42cc,4f76248a,f931aedf,b4e2df3e,ba3b426d,8ef191b,9d59507f,4a94ffa8,80ff4feb) +,S(c89ee34a,3660d03a,ce3b5604,1196a66,18c8739a,8a4795bd,db9c382a,9741aa3d,a4a3b888,35fbac57,f2f79ac9,d0ef292f,6838764,b99de084,684d1b95,12923884) +,S(24be4c56,d7dc0c4e,50050cf4,31d81f19,b5c46889,430563fd,566c4ed3,d941d5bc,e07236e2,4936315d,5f0714a2,af1ad769,f6a5fc7,a56fc1cb,ac09a085,f29e6213) +,S(6c31e71e,caa91c00,798ee5c5,3237a9f2,2866a91d,26936852,c4eb9853,e40b94f5,65aff323,2b5f2cd1,c1117e0a,c30b94e9,34543cd9,480f7922,5723c385,9ccf8cd7) +,S(506c373c,8479693d,3e03c022,9b61839f,e470a574,d31fa286,92601ed7,8e58b7e7,4fd0bfd3,a57c5035,268bd4ae,707fee83,e24f8676,e0ffe3ca,1673faca,1b7ab65) +,S(59d9a5f3,ea1a6cc6,16e7b097,871f731c,57571a09,1dc01b45,b48c5332,c98349a4,94ad373e,ee6496c3,263c348f,a7ee539,53aadf13,1aa6b638,21c16e0d,55fc8447) +,S(a524cfab,65371648,f641912f,a6ce67d5,c6f8929d,366448d6,4de381b3,22d75c69,14c26ff9,87fbd599,17a6ae90,bbe7c79a,ac1b6158,c3f46144,71aa36a9,45782823) +,S(126c986d,f83c6307,87c0d3ac,6a6b2393,8aa3fdd4,df26e76a,92af2c65,7f48c550,808539d3,a56a6f8f,3bcf04dd,31ac72e0,3f74ab1d,5e9afd39,7741656b,3d4c5c5c) +,S(32cabbc0,1aebcfb2,7e1a9d5b,4cd05550,d8ff25d7,b9a81db7,3188474a,ce39722,7d30120a,e08031c4,12c070f,6ee6b52a,be191021,faa9f5bb,9576feb1,8fbccee9) +,S(3fde1cba,f7ded6f8,a98975ab,ad5a64aa,8a9f0864,16dc25da,359e1cf8,22f42c64,e50fcac,61f0f174,b0e93cae,691212cc,44ffeda1,60dcff91,9ee3c960,2f5ac075) +,S(9cad22ca,d6c3dfbc,1d3a08d,6b102727,36e9db37,1ee1f26b,3ce932c7,11462e24,5ae84f1d,873dcd04,7f0781cb,aabbb53,422bb119,4e59d5a6,8824db95,50461c6b) +,S(9859020,aa807626,3a8ca18e,91c1afad,c20cf9f,9249c24e,1c652d19,7d5872ef,454323fd,21ab7d6e,470976f7,2d85fa39,a084e7eb,b332edd6,a3d054b8,d3c73e69) +,S(821699a3,e7cbcbd5,a2b093b6,c825281c,ac00bc53,c44b33a9,d8c31b9e,464eb2b6,f7d59c17,2400cb9b,72b44cbc,bbbd3e9f,e62cf451,bce6f840,23b073ab,66a9726a) +,S(bd06d4be,36423862,795fc7a5,5c48ceb8,440b3cc3,fc286dad,74ea7f6d,8cd370d9,3b09193a,fdcec88,ca4a5663,2cbb808f,61bb1253,fbcd1714,accd508,6183b90e) +,S(2c7112e7,9c8cc78d,f04a4ed0,e043c6ca,bb4b734d,9177f822,5bc41123,4bbdf4d2,c81ccfad,d42e2248,7612884a,d900f61e,bae242ef,65ff1afd,6e03ec42,38391243) +,S(51ae390f,a65d772c,833cbb8c,9ddf9ceb,b7f5236e,f1983905,762b7aaf,e122131e,3d7c9f80,80406b06,282f2a88,87dbb714,f1e96e1,e84eaec8,1256e1a8,ed7ba06e) +,S(c59de112,de237a43,2bcb8348,e3b31356,c7432672,6b9167a1,77d826e4,dacc59ea,36109f16,7c5eb66d,9f09c1d9,c5e1676c,aa33e403,a8e052b0,2854c689,d5903b25) +,S(8b99f23a,b7509d9b,151cb89a,45753026,77ca1e6,9219f0f7,57d01823,f556d978,86a31aad,f53afe44,f533cf0e,4bcd573c,d338e12f,904c8e9a,dc8e0080,f56a4164) +,S(4c670f65,7d6fa9bd,9ee4135a,1ef1882e,61f5fb7c,9deea717,39fe0ab9,78369dd5,531a8226,5d4b5363,12875dc1,7f891d1,b54e0435,1b539dd3,c100b797,efe65417) +,S(8e967e35,9daa0f95,fd7024e6,e57f0640,36aed9dc,9df0f33d,9388cedd,e0f38548,36f8055b,a59afaa5,8c88b833,ba110381,45fa0ab1,f0160d2f,1f1a1765,190d218f) +,S(3f611915,9c45a37d,5c7bfaa,cf0cc959,5e2e097c,8c7bc3e,c82e9e33,3b2ac9e1,c80134a,b7437dc5,23e08757,8eeada53,b9d2f3ee,25b754fa,f6c32e02,d597d7d6) +,S(3f59e49d,7c61412b,53fb203a,c7ebdedf,66bba683,87070745,9f85000c,f47641d9,bedd7088,4243dfe3,d238f101,f5dcd4e,64cd0978,986d50f2,ae3e2563,a43ad5b0) +,S(5b7d84c9,b64836a4,3bc44b5b,fcf170e9,ad46d4da,197a2781,bbbcaf87,5bf6d490,9f55b29c,c7d6b0ff,facb8975,507df04b,f2164e5b,9928156a,7c73fec2,b34d984f) +,S(e1ee74ae,ac3e83c,f73bf1f9,aafc3eab,90decf0d,a071aa88,962c29ea,51744b1c,9e86d2f8,b34e8525,568d674,8839839d,eefbe15b,80c66216,50acc508,f1277030) +,S(fa1ccd5b,8d489448,e3196c22,e96ca7ed,eba721ac,beee200e,5ddc496b,6beea871,e2b7f59a,326a6654,9d6479a8,a7a56d7e,8513504b,fd2a9829,d25e5855,2f9bc469) +,S(ef1e1cd7,f386096,1f6199d1,ab4a63ac,b292316b,f7a5e7a0,4c9f0c3a,7bfdc8bf,4cef9c01,a9de111d,8395dadc,e411e532,5783d377,559dc687,eeb510c2,ba98ef05) +,S(db714eb9,3e75d3ba,dfa5cc4e,d4813db2,fe9c395,95a1ee8e,9b3e468a,e1326120,3dc49a86,b81278f4,84d30311,c8816840,fa3cb701,665c067f,618295aa,6a71a206) +,S(5997f38d,bd572858,43ccf936,ee9d3feb,d70c79c7,9ad1c452,29af32fe,e6ea5d5a,adf7d862,b716011b,b9749e08,965c1ddf,1f44b678,df548eec,45a69a56,97e4a224) +,S(97d6f6d9,a920577,7b08ae66,6fc1fc7a,956654bd,3bc6c039,ea4eec3d,3bbaeb92,b450dc47,ff219854,dad5ab97,13dfbbf7,ce03fedf,4e7ffc68,4bdf1b5c,c20068b9) +,S(4f453fcd,5ec8b72b,69549ae3,c4eef99c,40232bca,1d6b10ab,c4b00d00,5ad307c4,aaded568,c4a8bc87,c7a442ba,f960d9e8,bd61f15e,d668f816,b94c0d2,9683f7f) +,S(5a604a3,50593035,c71c0a6a,caa7946c,ae4c4490,c0db71e6,49972705,949424d6,e578fc12,6d8701a7,a02b92b9,3fa89d09,ae82779e,2f78586a,8937a6f4,133be9c8) +,S(3f3071a2,916832fa,1b64cf0d,5b5fe8ee,2de601c9,34e08498,5d118696,7c635b3,e915b199,baeb233,b22adb6f,69df0e43,8712f25c,1be4470d,53851e4,451ad3a3) +,S(745bc1cd,643189ac,fcf02c5f,bf99c222,f7476a6c,2ede6c45,31849491,901c06e5,59a2bb4a,8703775d,e9a519bd,10e59db4,be16cb41,d0275d21,87291d06,d29933f0) +,S(bbd06e8c,adb3959d,853591a6,6387989,ab396736,8a6c1942,17580911,2637238e,ae0d8296,b484e5f3,dc46cb88,90b86a4,d562b003,a65a0c2a,2b4eded,38b8b690) +,S(fcda8db6,128dbe66,850b7e43,63a3b35e,9f3eb569,b7af97a3,85e53fd4,922cf07c,4bf3ddfc,37a0f9a8,5f758ee1,4c4d5c86,cd11f1e8,2a05ff28,3a0f535f,f9551974) +,S(6325dfdf,fc9c7ded,2a65e113,27210ccb,4ed2da97,4eded570,5ca1add9,9873cce2,89fe4c99,683e6fc7,170ada7e,26179fea,7ce1930f,af1a7358,4d7d56d3,4cf222e1) +,S(77594ca6,93495096,3ab5797a,5279d0a7,513df59b,41a3ad59,245e3f29,22ee0d7f,195eb112,2ccfbfc8,fdeddf45,ef2ef58f,631df03b,ca66a4a9,5818dd83,e5faabb2) +,S(f356ec67,ea9b242f,4f1348fd,c6592772,e2defd7e,308427b,ede15452,baa67867,3d2265b9,e23f8ea4,9a2b7145,9c98b03f,d75a2110,8f104121,e4a2fb4c,d633ba7a) +,S(3360ae12,9b0fa48e,c78e3091,4f8ae6f9,86149f0b,590a12ff,cadfdd2e,f8a205c9,79b37bf2,720d5a11,3ec09872,22b0a626,3d7a2051,e337cb83,dcb52df7,25d18a34) +,S(44e90f52,c703c50d,b331a4c5,fc47613f,b29040ab,9ff0f282,3fc15ad3,f9e8727b,62dfb341,92653e6f,636d013a,718932f6,95c2491e,26d16feb,4009ec05,e2f55f17) +,S(e5d367a9,b5c3ae22,31195876,4b28fe35,c9e04289,518aa09e,e7902b5e,4ec84047,ea1b257f,1abf0fa,6fb37c06,907052e7,fbbc06b4,c2382ace,9c9a98bc,e6f8bcf0) +,S(8478e8fd,7910e5ad,3c061e6d,422806a5,559baab,e083b8de,1005413b,59a63957,4f793418,5193499,13fe38c4,514bd4bf,2f3f1ebd,b492fd5c,fd8c1bc3,1a2df1d6) +,S(c38327c8,587731b,f5b5e224,79c9274,10c97dff,f6855b6d,c2ccf761,2a84b42d,eb03afac,cb1b102e,7e87d61f,5012ce74,a213fefa,b855db22,bc657d52,4dabfcd6) +,S(b9e8a812,5348a672,558f48c9,d17f28a2,4662b4b6,604ee14c,d622b521,bc51f10a,35c2780d,65fcd07b,51ea0224,1771b523,3813e7bb,97a1744c,e3dad732,ef1ccfee) +,S(a54aa2d5,95cfa325,38d2e483,70ba86af,d3c3b53d,2141b0fd,cc68a729,a5cc713e,bf74dc6e,63c02b2e,e676b9c8,6a851a48,7e9552b9,a32eabaf,4e1faa06,8bb8a159) +,S(d45fec3c,e2df54eb,844ad145,fb8884ac,420ce2ad,85cd55ea,4cc19e1f,da9fd956,ed8cfb00,65aecb6a,6901dbf9,b8c208d4,bf6be1e7,ee74a08d,205c48bf,8cb81bd6) +,S(f4b44e98,f728b318,ca959829,d4cd836c,5c0136ab,8e433101,87be24ad,53192172,ef5521b3,960bce49,2c841fd8,8cf7b8dd,2febdd8b,f0aa64e8,4d3c2a09,89ea9fa1) +,S(dec6d1bf,d349110,faa0cd40,e8533078,dcec40c6,e260b9e2,8412d424,353d67e3,73a16f81,3609c901,71efe44f,32ffc90f,9451b0b3,24107b72,54ca2fba,65095895) +,S(1fbcdd53,72e17c41,9310b9c0,2273534d,265f1c24,bc1a6039,238b5b7a,b3ff013e,9cf4ff4a,6a61c11,20c4d14b,97275547,b2358f75,8a2a774f,22bc77f2,4c6c27ca) +,S(d9cef0cb,38c6ed7,7aed53f4,93a31daa,50ea1ff9,aa43b890,357012fb,e2ab593b,32a416fe,246872d5,b68e6654,7f19dda5,e161cd13,ed041486,4d0c2dd,3653303f) +,S(1641b549,88e22a18,45e2135f,88d2386,4e2f607c,ce33fcce,de174a60,1ff03da3,edd3f0d9,ed718767,3664e1b9,540f816d,48e3ffd1,cfad86fb,5b68dfbd,7d94922f) +,S(99ef6c16,3c5d9ffb,1b638b21,1ef60166,37938f83,ac4ef76f,96c5366c,3a243cdd,6b6eef62,d819581d,e1dd7796,df043e02,7f912bbe,6ba1e499,a311769e,d6f66b48) +,S(49358d2d,c24c2e8b,80ff79b0,9c53645e,b9c47fb2,8ea4ffe4,e2f4679f,5b5bc97c,512a14a7,f9df40eb,ef7c1cbf,f8e1caf7,b8c80748,7bee3865,37837cae,dc1cf5b4) +,S(e31d3fcf,b1dedfe9,2549c5e1,a14cf383,c8c122a5,a430aee8,a4eec846,7ceb206b,7bc3c266,69db747b,a3ad1dd,e83464f9,effc4dad,b4de7687,e6c3ae56,a5b0449b) +,S(a82ec9d6,ac86bcad,fbb32e66,a28d7483,ad1fbb7f,979a15d4,4e324ce1,86c64adf,bac87d2b,c28b1ae5,f4ab46f1,ac779936,3a9efad0,b1e1f81,6c4ec6d3,cf74c89) +,S(21650994,2bffa2e2,479ab82b,18cd3aba,dc370c3,18c71c08,1bfb53d4,c8ea113d,97a8246a,2f653450,be513b6f,62419f90,f84511be,9a5f3103,feca77c9,c81fcae3) +,S(735050d8,208d9688,7fdf8070,e448e905,e4e666c6,3db5857f,63ceb362,c6dd4b84,2e3fb438,563661c9,e6fe23f0,7c8219ac,216887cb,ad307918,90001f9e,2ab9e2e9) +,S(1d021861,e679dc08,a34c3813,bb9c3e9b,65f87800,79dc08ba,197b3b66,47afe506,14b6d0b9,2303483d,9e92cd0,e295bf08,4a10e84c,ee0b7c50,ceaa6ba7,a6fd2f1f) +,S(7a7eee74,86ca8973,a858c15d,54eff96f,f91c5577,4985433c,1bdc4f4e,46d7810b,5e83a07f,5d9150e7,a7f5057d,87d19ccf,448fed1b,bc1e2297,c7012cbb,77b498cf) +,S(811c3d4,fe0a3061,47c05cce,32a32ada,48593802,32f24b51,f50e726d,a702beec,a6fcc16c,6c9cf4f9,2e84214e,35ad8577,b28e599d,31ed74ef,c95eb2bc,833d9f0a) +,S(2ca14438,89ea9e8f,24d5b1e,e44b26d3,ca25ed08,30ae950b,4357da49,21ad606c,7b48a6c6,92d8a29f,a82c656,f8e6213,c5e90be3,7413d86f,42e10e63,1026c551) +,S(a980ffe1,61041afc,339566d2,957e6624,5dd3e0a5,deee9c80,d57b1f1f,390277bf,3276f7a2,a139343b,87744079,7a174d99,457d5005,71ce47fd,10e41456,7a1c64c) +,S(e570a3d9,cbccb74f,c582954a,998d9371,fde41d98,e65de6bc,9579d6ea,d9cd80bd,5a749177,6658398e,99d3035,12c168bd,9400bc6b,c7dea2df,2739abe4,16973a52) +,S(f5fbaab8,952cf50e,66d3d985,d9280bad,71bd25fb,662358c9,72b954c3,7bce1110,1aca2123,6179f821,a4f097c9,b48a744f,8010818d,3ac6cf,b02f57f3,1fd77175) +,S(2e5942fb,ecbda8ac,15408d25,84ab7c75,6f9e525e,c4dbf375,5559dea1,718d89be,95106507,d14199a7,8f123d6c,f6b59262,30e12a1a,8c0ca016,40c556fb,14bc790b) +,S(92bd04a9,891c99e9,6c9e7f64,a9bab705,a9fc83f,a739413e,a2f33001,b55dd296,cf5e3733,659bfd9c,e5417ba6,817b6a0f,5cc71c34,22165fbf,13019fad,822ba587) +,S(30ddfd9f,a50feae1,e3cc5426,93ddcd62,4d0e52b0,867248ff,ed7d3041,a7b11083,ff15d0fe,2bb183ef,a18389e3,df4269ca,21bdfa0f,87ac641b,14bdaf66,26eb42ed) +,S(8cf5150b,df8ac68a,af319688,245719e4,67ddddb,72fa7f1c,baf39de7,252a9f4f,4c28497b,a299bb19,83b18bc2,508c98d8,2a9963ab,4145807a,2130fc05,4186cfd5) +,S(1f4b4efd,50974efb,3caed9f7,4f6dd979,4a8e3c09,8decc1b8,69032885,265e46c7,6c4b04c7,f7c6b00d,c38adeb8,a47c7c0a,68535229,26500a76,ee1c6feb,179fd399) +,S(9d524900,979afa33,8d5883ba,d13d038c,3f915cb9,f2e29a2,2a028b18,d091af81,409a113c,37c732d,1104453d,6b161d33,db3257c7,b9a73e1,e0f1679e,6802be38) +,S(52e1e4e4,46eed9d0,fd5c124c,1c23403c,5b03984c,f3fb0734,c627f34b,dda2e3a1,674a5731,7375ffa8,c3c4104f,12c1713a,e2dbc630,75a77e5b,26243217,88320a7) +,S(827b171a,8eef4e31,e6ca8b6e,7c6e36fa,e0a6c93,a77d7148,fd22f7a8,16401c8b,65cd85fd,d9b801cf,7de6d14c,b78ba114,1d58c7fa,129f9f08,8275f364,f7ca7540) +,S(124f45e9,61d89642,6a1abc32,e582e246,3db29954,1bea0383,c83f917b,6cdf2f9b,734e2fe4,110b65b1,2d60626f,c6288f87,e48e7a7d,213a4f83,58bb4d67,978d6c62) +,S(3b71298,18b2b324,10e4f002,899204c4,fb4ac9d6,c08d1169,5f5f5699,9a4d67e2,28b6f78b,cee16b5,5c010c51,ec465609,54ba6368,a18ae218,5607c1fb,42c27c3b) +,S(d271d87e,63b5363,e664485,ea6ae70e,e2b887a1,c7f7e0a4,290033b5,512d8a00,65d43804,7865e280,273122ba,8d8644d0,60ef5927,34971c9b,510238eb,9d6da847) +,S(1d1c6d85,2db35160,67cd2d82,e2ba552c,c5ca0c9,ae7bd661,e8494b25,cdc03a7,bc31f4c5,673a0256,ee9b6840,7aeea035,e19f874c,bdd7aebb,ae8b1005,4e691f62) +,S(8fee89b4,71e394c0,ddad274c,ba07de4,bf8d2ecc,695647fb,1d3756fd,46efdd9d,5d5ed0c3,8479578f,d17ae148,7198f9cf,4ba5cf71,46a9b4c4,34ca62f1,bd2b8c6c) +,S(681fcf09,55a0f351,6026302c,ce3ee475,8ef9385f,908dace5,5d7fbd30,8810a6ec,4307f75b,99927624,80187edb,c4c6575c,aa54e8f4,190f0885,e6d358ca,2a38faa) +,S(717fd6dd,fcb5a71b,6a584a28,904cd3e2,6f6c1a89,7fc32918,90792937,b3a6971b,b403f829,71d4ad04,dfc40553,27f6da8e,1b05e25d,341d6511,d7cd859f,58b17992) +,S(f2b95723,94eb9786,dc1f4998,6ad8c340,d2983279,c7323a34,227013e3,754f2ff6,b553d381,3efdcd41,7189645d,d9917b73,bb69e705,e7a6520d,dbaa497e,7766763b) +,S(58714be6,d7d86c89,65309b52,414135c1,9ab6fed0,1d56d7b1,4237485d,96730b1b,c011f34,3e38ce5b,deab84ab,f0e31537,4039845c,5fa4fcf8,1c9a4d5e,6fe3e533) +,S(d33ce5ab,c828f8c1,b9700d49,e9c6b4fa,b30819fb,b2bea23b,7f915bc0,7a6ff3c3,739b6222,39134988,22372ba6,3fbe22f1,ef59394f,37db956f,caca4c11,75a23395) +,S(82202e32,fc7d0128,4eba58ff,42f7d94a,24904808,d6f920d5,9837b26d,63b55479,fde63954,50aa55e4,fcc4fb0a,8ac2c880,63aa3202,9a00004d,edd033b6,2563b4c8) +,S(25e63218,5bfb4c88,fa300e37,c8b64a,941e6487,a34262b7,419fa7c,2dea7781,ae696b07,4802ab99,4df2d84c,c6731d7e,9caa124,548c2a11,42ddcdbe,f716e640) +,S(e0336a05,b9254e1a,f2468a36,343a0dff,9da8773a,1efdc487,53c1a95b,605c114e,41d75960,377ada38,79b97455,346266c5,5ba05915,9ddad050,d96d9d8b,afb12a18) +,S(843363af,7fd2b1bd,1c9a9253,e42489c1,34ee875a,db57b752,62d731aa,9a996662,e5c0a2d1,dbfcf013,ed4bda36,f153a328,12c4b3b1,66e48473,4d2d3562,ffcde6ca) +,S(adb210b8,1cdb7f18,f97955cf,fa7e5763,abb9f202,9d283c05,26df6332,951178de,2c211f05,d8182aa6,d784721,948afa11,364db5ec,2e1becf0,68eb91a5,74ea0e35) +,S(ab0c5fa1,a2fe2235,ee93854f,59a13792,2034604e,5857b6e0,88b65142,f24d7491,e54725cb,e36d6e15,71ca7384,7383553,b9dc48cd,eca6932b,8d92f785,b80124d2) +,S(3e5de77a,1d2163e4,3f3124b0,af4f5473,868a080b,67acd835,f9cbc88d,7885deda,a6ed34a4,2f9503b8,b83e66b8,377f514a,e1927dc4,c37ef6d2,254e651d,15746630) +,S(60c68b3d,31d1d326,5b71f068,8f32f671,32184815,f83a9ceb,50eaef6,4991ec05,977acc61,9f7d24c8,a95aecbe,987737a5,89886729,500ed32a,9d760fca,7c00d498) +,S(21b052e9,b646e595,b6c04a76,a66b9b25,4a126729,6bea0654,64fc5b31,69c135e2,1029e4cd,2fb3d717,6e87292c,4b0dfd7f,18db6ed4,59aa9285,38f0989c,540779e7) +,S(700caf3,7c664515,ee501e66,60be4cca,f58bb2ef,5b11f79d,c027dba3,7b523d68,7df76b88,f1c346f3,2e32487c,19957830,8eac9b7e,56edc948,e1a934c7,6fa08be1) +,S(c5ab9bd2,1293844a,ce5f1c9f,56458315,5d34aeaf,565a5696,29969664,49541e8d,2d2081c6,c61d6c8a,a0df4467,8ec53a7e,9b34d90c,57db2f29,c0361304,1c422d8) +,S(8afc3f2e,d53f5dc1,448d15af,8c2151d8,5713fbdd,5d46a3df,a4ad376a,16d75a3,11f6393,2627bed9,e015a99d,42193e6b,6767c513,f3457897,64db1a4e,4b9b6c8f) +,S(414ad9c6,bb55eadf,cf4cf729,27ae3682,c0d69867,ede9f4d8,6e173c50,3a5007a7,c4bcd0f8,f4de9b1d,1102306b,667a546d,dafb6f82,edbdffd6,181dd3a0,8f603585) +,S(8211e240,b84b7317,a9c5ec88,fdc426d1,a163a2d3,aaf088fd,b2317247,cb04a1e3,ca76a59b,b268bf51,4f06c4f6,d5961b33,a74f10b1,70a9e9be,4e7942ad,26722bbb) +,S(a54dfd32,363add3c,75ec4452,3094b27a,3f7cd291,43ee52f4,29e59daf,22ba700e,f160822c,59510098,3e38d130,49b44865,3639ac74,6a93ebbb,2798d92e,bad4490b) +,S(77d64c55,52b29b18,a7aee1a8,1e1e9d3f,e2921a43,cfbd95e9,a3ba7cb9,498860f7,e97bb8f9,5ea9c8f4,440ad9d7,36d9a06a,fed03a9,cc96597,8d06f2e7,8208ff10) +,S(485b3814,b33e6bf1,1f47f0f5,f0e5a189,1b57c103,60f13d61,ba7947e1,6e309ca9,e6bb7870,ce607c62,a6050dd0,946c8653,f998576f,2c781b5f,15282632,4e38bdb) +,S(ed2381ec,a90a78c2,def618be,1b6edc51,7ced2ac8,14aee9aa,b0a7068f,72739c,cb0873e0,ba326452,380c291e,c635381e,d6859916,2ca10fbc,3de45ffb,134954c7) +,S(e444af79,d36bc127,c83c7369,a4cba0fe,955b6a66,8f2e7a68,4a65e57c,44ed971d,a7876f03,27b6823a,aaf55ca1,6a48998a,ec50e5de,10d34e9,dd7c554f,d3785fff) +,S(af8c34d7,7de75a2d,5f64296c,152fea4f,b8677b8a,96cb278c,7ed7e50,69fc1fca,48ce5862,ab6ec1a8,ce55899f,24632be2,f3c451cb,8b81ca8c,f9ecc3b2,2984d673) +,S(e999d466,243a44ed,18e745a8,1da04a31,8940c88,760480cb,e315436c,f67efe13,f41e8e70,63a84661,c22ac0e7,5cdedbd0,ef55d3eb,7fa813cb,2f7d1fb0,237fe36) +,S(c40ef8aa,7d8964ff,a3cc923a,2fdebec,72cafaa,58b72d66,e209b644,604bcc72,480e35b5,6549a1e6,f112c3b6,176f3378,ff50ebc7,b3efac2f,696f0627,b7238ce5) +,S(482ee41d,e3f9499c,8992b546,e209aa5d,679e4b8a,22a26615,1bd1b0f3,9a52982f,510e6070,d2131815,2d52eff0,ee10ec6f,563f92ec,a0e549f8,32efee81,dcd3de3d) +,S(4660a468,25a3c1d6,67003c69,4d36f8b7,6df7ca32,c6029fd4,65dcf726,5c58fae5,3d982bf5,46b5c296,988acc72,2dade97,791de8e0,150397c0,700bfa10,ba23f618) +,S(b85e624c,92ba6f0b,3fb1dc03,37589994,d8a3aee1,76314d87,3c8bef0,eb5d8f8d,88936b33,20a55ba4,24bff93e,fb36ef77,e2cdff26,866cd486,88c61868,ad75679b) +,S(a41920b5,361a26bf,bd187eba,b62fd5b3,b3be282f,94ef94c6,b1698754,902683e3,7790a196,29d93b4d,3d27201b,32053e02,c95a8f9f,260647d1,491c7a4a,e15ea98a) +,S(93882da9,79262a60,3252f01b,bf101d89,ed1abf8b,15507937,55979f4,fbb7f86e,938884d,f0a716ef,137450b,ad5f022e,23e570f1,3ed37e02,15a40910,189d7e44) +,S(a10509f8,3efeda60,acf56b64,3709b197,ebfa6a59,e66efb06,79c23225,c8952e00,759083d5,559bde4d,9a37df5,24cae4f8,5a06e7a4,7c0e15fe,830f0677,c24d1ddb) +,S(2b945a97,6ea74278,73d7e587,dfe75eaf,c55de704,8aa26d29,4b3b1ef9,2beb3651,423c07ed,27ccbf6b,9d1cbabc,e00b451b,cb488d10,e5daf752,6980ef65,6893c65) +,S(86f9d9bb,c1a0bfe4,e03da0,13f17017,f6951691,28d51073,b594457b,fcc37f0,f370c624,2e303796,9339cd4b,fbc19e8f,62388f02,649247ed,df3c6c67,464c32bb) +,S(f8995af9,555e044e,6238d895,8bdb4e13,3aa9cc0f,90a9206c,16d0f83,dd61ed91,b2d4d2e3,1bee12c8,3b8bdab8,34fa2e63,1febdb93,4af194bc,d0825921,4ea8a060) +,S(ab55a27f,69eb352d,455eee7f,bbc1c74,fdea2621,63d09dbe,2f554417,819394ce,8ac56493,60f585b5,72373bc1,74a930e2,4d54674a,89789353,4a166200,e31b801a) +,S(4fc106c9,c428df98,916a8906,95e98353,ce84723f,fadae522,e8a89916,a23b9fa6,90d732e8,3d54341e,4f4c88be,3392687d,fdebbc4a,7c19afd1,92531688,9eb92031) +,S(c9c85980,8831cccb,77d87b25,73a894e3,874080db,ba076b2,4626bc82,3149a91,9fad4ccd,8c0949f9,be9a6355,f0bdfa36,c5f99268,780566e6,a6f302e3,b2abf0b8) +,S(c0cb5b7e,2293abba,5ff78c46,aa1422fd,a278eb5c,ddd58cb7,aee77149,1c5209e7,8101f42e,36648586,5db6b572,d0df4ca3,cc72789e,ed8d27d5,1330d733,4e10c47b) +,S(dbfc03c5,16d93f83,472ab60c,391bdd69,af2f70ce,fbce15d,140f1590,d8ce0b63,f838e14d,7228ca2e,9a33ecfe,c376aa4e,4811fa24,debc7b46,4658c153,fed26564) +,S(de260685,eea13ff1,1571d891,35607b0,435140b9,62e3baf3,7cc3f3d3,484f59c8,6bc23ec9,a6025865,e6363335,bb66f1e6,c1f5f54c,aa5f8acc,d7f8fae5,99cfbbcc) +,S(58d78d60,b8cb8fdb,1b62f79,f6c17ebb,1ed8129f,c7819e5f,6f73c58b,faa2e71e,7cbbe4f2,fd6bc671,8c222f5e,16391133,b04d6d3d,bb263531,40aa4053,b44bccc1) +,S(e72b9b1a,eed54fe5,ab0869aa,90014e3b,fde1af12,f646d738,211ebefe,2c00a490,cd92d14d,8f595833,842af020,a2cc82a0,d9465969,77d25d34,8cff3273,90af4fc2) +,S(6a86bae,d55a5be1,8b7cef97,c9dff8a8,b725f614,2221485b,3b9f348d,570fd658,138a2691,4c3b3015,10312140,7709fa87,60a14f14,571a9d40,81c06d67,ef2c5724) +,S(1ca08cf6,7240f244,d6cb0059,564fc283,b17c39e1,b624716e,e100aee,bb0a1fc5,22e24fce,655d09ec,34a36317,c66adf07,deec2743,4e9c016a,b3447b3f,d9ef0a55) +,S(d95dc128,feba49c4,73e1ee30,bcddf76e,b7cf628a,fd495607,f558201,824a0b0f,d5340ab8,fea3e137,d1061274,c69b68e3,633e98ba,ae2fe116,1612c4d6,c7c7e8a1) +,S(2cccd22a,7f4fd501,6c3a14e4,769a88bb,ae7e288b,d9987afc,f3c073f8,ccd83857,ae82663c,aea89fdb,4710f849,ff8e4fb8,c2a7b614,4edb5f3b,f2564dd,73b389e) +,S(ec17b5f6,c8e4de23,937bc003,7dd7b411,ae4a9ac8,1f2801d1,c5eebeb0,95628a43,b3e0d51d,fd5815b0,631fa298,968fe70f,74319620,f0798734,8e66e6e9,6658df83) +,S(a63aaf7e,62907f4e,1a613cdd,ccf1cc98,cee8e12c,8bace3ca,95685889,6c96b6f4,2f953ebc,dc5f9973,e9d44ab1,23255a21,f8bc1a7d,e800cdee,ef754031,aee8216e) +,S(8eb4ff30,318d8d0d,6b45636c,b296d137,90e345af,19a14b2c,550e0169,87ad32f3,4b8e238b,ae7ffc7e,7d600151,c5ebb776,cc01d51,827f171,8f28af77,ca4a3e3) +,S(ab1420af,bb5b4397,f578a6e5,74a63aec,2432fa8c,b4712341,4374add9,8276b8d2,faf6328e,a197e927,65b9df90,a79558b,8f264acd,7f75b574,90ce657f,64b94396) +,S(daa1890e,6b2ba1aa,dcc16f1c,c1d5999d,5102aa6b,348ffb5e,9630bd1a,886f680a,19facb69,5a63eb94,cb6f6005,cf2bbd23,8744f05c,2c220510,94bf6dfa,352fa209) +,S(f199f52e,5398d1b4,899a1b0e,df8ebb73,cb08a642,bd22ff2e,b1cf647,7f2a28e3,3619abab,a5e2131d,4ccf8747,67ef9b75,2d5278ac,5549bd9e,5c1b5985,9ec2f454) +,S(182a9e93,a5f9ecf3,6bf20bc1,497a4a35,e75c86f5,9c9fc046,e2752223,f046ad6a,c6095e88,c39dee18,ca867693,d85617c7,e0924dca,34af07a5,c731e488,ffb8bcfd) +,S(8a4cb53,636fe66,b660a701,64277fb2,5ac21eae,906327c,3b509954,b214abbb,693e5851,4cc6a941,23ee707f,ad25d638,8efcb85c,25500bbf,63fd6926,a1d0ed1c) +,S(4901335a,3b40c33e,115e3105,82c55972,f495178c,813bd8d4,2b208916,5c8c1282,47007176,429d740d,dcac70eb,9e1f0e94,f26a9a0e,4dde0166,24d9d801,c84214e3) +,S(8180e5a7,7c34362b,461b49e1,4b9f2e05,df64f55d,cad82b8f,cdf41232,984e01dd,34cf5621,d4b9f100,aa34b0fd,5ac91d,cb3fb49c,130f3e65,de742ac,af05040b) +,S(8f71227e,fea9f4a8,9dcaeee3,58eaa5d5,a90e1d7c,b7d232a4,b1085fe1,3651ee9f,a4da15bc,bb2b79a0,a27c344f,3b914c7f,e272676a,bc045aae,e90daf4e,9655ad73) +,S(dbeb9b74,cdc9bacb,83592a2,a3cc19a6,d1ea8eaa,5a086a3c,cc68d423,cfb58264,be668792,83f07fb5,830732eb,79e16bbc,18e86df9,b659e2d4,5b1009a3,40576161) +,S(f328e93f,a7f52cac,3c7b09b6,280528dd,7d9ea4df,8317a958,ab0a617d,71591933,41ce8c59,811f9e90,61dc3f3a,7d85d394,2f780c17,d7ebca60,fc042311,f2405547) +,S(56d4f403,416b1bec,49c5f44c,2021c245,d4ca4181,5131cb7d,8fb0cf08,30fea051,cc5f6133,948f77be,934cb637,3d5dce8c,51ae1a92,e3d802a8,d35a3ad8,50bd39ce) +,S(8e22e04b,8bb476b7,ccebecf2,a327fd41,dd90c9fa,67cfc49,e9cf4ebc,39022b8,1f8fa60,3204696d,34d03c02,31d3ef58,934e7992,c2c81d6d,3e4193b3,8286b8b) +,S(341b22e4,b9a77c68,f93624dc,1cfefade,b396eb72,bf9fce1a,51867d7a,ef064f6,95839f87,7bc36957,59562bcf,dbcb2db,af11ed72,7d329e27,cfc8ff8b,92d9441a) +,S(3ea42e93,9f234112,879e8680,94fb8a8c,e6af9799,c000b050,45eb2026,3b324763,44324167,6f5aa6f0,4fe4d51f,fecfa8fd,60a5c0a3,38b16f59,1866bd51,2e01a623) +,S(afe7b44c,ef10514e,f94faa1b,b8cde91c,23d8a660,a71c3173,42f927bf,535d625b,7617a788,51218772,bcd51f18,54b063ee,6cfcdd77,7a388427,51cacfc8,7c8b4b65) +,S(a360ca02,abb40d4c,6e0ac725,f2c035d1,12f69ee3,ff0e1dda,37a3fbe6,a2034d2b,161e7178,3fec3ea0,305d0f72,3a60846f,9d8bbe79,255a3814,fab83269,916b646d) +,S(10484e5f,f7d9fe7d,9b65d989,9b2ecdf7,5984d18c,1199f61e,c914a85b,78011b88,12d1c0e2,1e137357,9ede1086,c2c1449f,e7f4e03d,78f7b184,4f744d6f,9576cdc9) +,S(76c2dce1,5dad9ddc,24276c40,eda7de6a,b11245e6,5b051ba6,7eec39c6,d256b138,d9a601ce,585b0839,92e3fca2,a43739a3,61a8967d,3eb0f605,ed4cef15,fc64ce82) +,S(671a31d4,c3e6ed98,b044fcb1,83dc60c7,d1d83988,3a547356,27b99b75,11d4d2e1,6fdd8d15,2005ef3f,7ef3762f,bf43a849,281f185e,a52c1b3b,8ad371b,e053088) +,S(91d0f565,a2da6903,12b72998,57f71c18,c2343a5b,a6f17243,1bee12b6,6e898a37,9d6a55b9,1956a288,d56906a1,1f7cddd,e6393ad6,7249147a,41eb209d,7f32f681) +,S(7e59f058,1953a2c3,cbd4d0cd,8f4df7b8,6b90d8de,7240b2d4,de9ee9ab,628512ba,33b0d1eb,74cc7d60,ef419b0a,f9f03714,35a012fe,328fbdbd,9d9b69bb,9a42a173) +,S(ef78b65e,b791bed,212652ad,ab1f32ff,f43a285b,e040380d,d3492afe,1f788a26,9f3e2538,96d5afc2,3ea7ab1b,24ffac00,f156cdef,93957910,abb1cd1b,6508d306) +,S(78b978d0,199833ee,417ce2f5,fc12cb01,cb0c0e4c,ee752e1f,50a8cdf9,b56b7cd3,9f9c7dd7,372606bb,e3170141,31591f5d,dd631f91,71460cd0,19709478,c1560dd9) +,S(5f785b31,f9945a20,e992f5e8,80abab72,906ffdfa,7ba7ccef,f1b3d26d,70bfe64a,a3cc480e,b3cb386a,ffa1988d,3227911d,57522413,e5d0846e,a6d0a17,2b881c1c) +,S(9fee7999,7cbb492f,cf3aadfa,44484d71,2c3887d,6375c887,fcee9fe5,7806b3d1,43114327,7e94c760,1fbef25a,60e7d448,c0f0b8f0,c6c64437,a129d4ac,fe24c22e) +,S(12f2dd5d,b75d8885,7b7befd7,cdbd7c76,c0f46213,f9a53102,acd8b0c,4ee3f30b,ce27598b,e85049e,9ad3ecfa,d3864070,f8510570,742dd021,6dcb4aa5,334097d8) +,S(c694aeb4,3ee2b51c,3f0e2bef,bc1b718e,fbb86f9f,1d2a84d5,3178325d,cf997bd7,41481f3e,b6a69311,2cac3e5c,c85a6f83,6fc5190e,ae71f226,bdc887a8,ed050977) +,S(fe266a46,14c5c05c,baf3493f,5af3befa,9bd16100,860bab1,49ad78ca,81047ae9,e2e18ebe,c44694d4,b7c614ad,a772a5c4,f58ca087,4957f20b,741b954,18471e6b) +,S(7975e1dc,926b07c,487abfa5,8c183f21,daff04e7,f67a7250,d2152699,356118dd,c984b97,44e2b300,ca54b779,da94dae5,f943468d,9b9729d8,21cfc709,351409e5) +,S(93573cdb,50183589,a0909e8e,6186d700,7022848e,b7fd6951,a137cf16,a18a2b06,7a957c66,3047f6ae,d9490039,d136cace,caae2d8a,fc9f50f0,26590e62,18bf47d5) +,S(c0bd2e1e,a60f6feb,8e0ac7dd,485fc4fe,6771d80e,e29b4829,fa37faf8,81d77660,685b74fd,9edde1c7,69076267,d9f247e8,2effc83f,e25af065,56aff25b,335bacd) +,S(56bac0e1,93192207,906e5f45,d55d5919,b676852b,daa43253,8c4c6984,9c24bf3e,e3bf51d3,9856b812,d2e480bb,c8b118e5,f5c0ae9,f8d09096,a5d207ec,2fc18ebf) +,S(53b41b13,fe7cddd2,ebfec7c4,a985fded,5225fa0a,b93dfc65,2314d1e5,9142c06c,90fcba57,44e4f565,5d2e038d,ccd2bdff,cb4ecf20,48f2ba98,8f62fe9b,c3b69c4b) +,S(bda05e31,ccc0edb9,47ebaa26,9182ca2c,b1136400,674ce5f5,d55fcf2a,c2e765bb,97275979,31236982,a7459356,7308ea97,2fff08da,ae8f707b,447dc6ba,7acf75e8) +,S(48dd1c6a,8a900820,1fe09f19,a8f65f82,91196e95,1c57189b,21aede15,4b0413d8,79a1f6fb,1a943dca,6517e287,80e72f85,c5a6150d,9c50d7af,78c8b63a,c09b98f5) +,S(75406269,e28c428c,8eeff4e2,ce9a2d48,2be8346f,3446451c,13c04380,292f1f2c,4743b097,211c807e,23cd13d7,692efc44,202c44cd,dde5a89f,9e7cdc5a,133e996a) +,S(1aa55d93,bf318133,8840ae4d,24314ffc,74420002,4ddab165,4018604a,2192ee5f,babac354,92d59e8a,656ac7e9,9b6cb2cd,7a6a8e88,1361118f,41e38f1,2cbc3bfc) +,S(75be4c50,db7bc629,e64fa850,3d89f722,34d214f4,9b176fba,b937120c,477dcf03,b5520bba,8c606db2,833d934,3c860c6b,ed2e5e2a,41a6c3fb,51154c82,94b6f819) +,S(f3604822,e4ed8b2d,d4b2486,b611b95b,6508e10a,1c725c7d,8d638254,3cef6c8c,f405ac79,7404bc6a,25a1a412,f2cbd698,75d99d2c,b23ac105,f9839446,222dc0f5) +,S(6c9216e6,6f9326be,fad5f727,ae0326b1,da54ee91,f041d2bf,2d87dff0,e77cefe8,64a021b9,bc1947c8,df546f92,2f5230df,1ec2f372,50651704,557377fb,39d16517) +,S(ae479bbd,ce97732d,df313861,76807678,988346e2,5b12bb09,e74d474d,6905668a,a3ce0355,c5996087,89936336,64d9bdd2,b33a6f97,ea3f28b3,f4b7c0ac,92612929) +,S(ce92c179,66f74db2,1c6abcf8,36cfd2f7,9ccc05a7,aaaf74ff,4807052d,754898be,f3e3d3f3,530f38c4,ca59cec9,c8e3456b,8adebf80,3f10927c,e44e79ca,601bb978) +,S(8a0bbeb6,815275c1,77553d87,5988c4dd,a96f5ae2,378a3b9f,477cf162,6e6ea68d,958b795e,46f45412,acaa9f77,85a4e34,a7c74eac,228476d6,4e917983,5fe77f4e) +,S(c2a44ee9,975400e2,912a033c,5ed1e7a,7f0e97a7,1c86e8d0,c2e5136,8dd9ccfe,956435ef,7d24a507,dbfb69b2,93b51369,70cd17b8,ebf6bc60,596a9545,3675668f) +,S(b615f625,534ddf61,47b78520,85443bcd,3d3bbe91,c815dc29,3cc891c7,199ea1e1,4cabf4f1,99e21468,62a90876,4f65c624,fe3afd1c,6b399e12,267dc1e7,6ec3ea25) +,S(afccaf8d,fdcf272a,cf56dde9,3980bee7,b64a0c54,f80830b5,5fd0b93b,e8a75a0e,8d8ec5d,6f6fc44f,89f6d9ba,735861af,e7d6a660,7d88e95,54f2c141,1042a63e) +,S(534176a8,c5311b26,1f39395d,f78300b,559d072a,cb3873ac,32833c8a,9b135f53,ab84f84b,5eeea7b4,87ef6639,8fa756fa,b16155d,683ef643,b03c7e6c,8ab2f436) +,S(5f7aa173,97ef95cd,f47651ac,6220f3f2,8705abbc,6531b93e,a65fcd14,1b91f34c,72f7d898,3cddb34f,2ed1b28f,17a77d8e,70cffcbb,e0462ab8,b7548561,9881da22) +,S(d4fb4a4c,c1e2fb72,b301db19,335afd7a,b6a95258,6903f449,aa287fc,ac8f3d3b,76b572e8,4a9db287,19d098cd,5dee787e,f213adf7,9ae90306,8881894,e14154f9) +,S(3dc67563,843b2f3a,f793116c,23db0dd0,dad0975c,5abbf569,4c6d454c,9f7a9ff4,ddf65b9e,4db83b7f,43d0ccf8,49a8088,4894b277,4fb39fbf,78076a60,356753ae) +,S(657912bd,1edd014d,1386c449,50cd1667,9c3e415d,b36e36b1,3bb5c82c,a2f897d6,4e2fdfdb,11bbe240,8fc7fb3a,acd06c69,78205e48,c9f5a143,4300927e,fed505cf) +,S(5a453b3,5f82585c,f64473e5,f3fe937,6f412b5f,c4ade7b8,f9081717,3fd69f99,fc169e11,3448b590,4e1dbf06,f4aba1a3,ec2fb4b5,7f2b4c4f,a29b6617,58097ebe) +,S(c3adf45a,c24b4bc8,69acfaf1,f96a3043,d01c68b2,f4ff689,93b37b3,a4052679,3d923207,cd374b49,d3a85bea,972b8d09,4f0d4b83,cedc97d7,edc2ac68,10ae19cc) +,S(1a32edc8,905ddc84,2756420b,e1f25daf,5bd84f0f,acb046b6,e9040fe9,5e1e1d56,7f467d9d,113a77f8,c1cb73ad,16a62f4f,f1612c80,f8cf859c,ca42164,68eb4c51) +,S(70957d98,62e5977a,c328b7da,2e51024a,f925c142,eb1a46b7,b4a3bf20,a74d6c98,269b56c6,2e42cc34,a0951348,881d2c53,7d7ee231,f2327ec1,441fd273,bef09381) +,S(7e69416,5a02b16c,107ae454,b6cdf25,bf6dd256,d976ab44,bd7edc84,837537a7,ffb874db,38360c11,e2d0d2ce,3e47363,a6aac21d,78a37b24,3e66826b,445185f5) +,S(4f81a159,7b42e9b5,24be7ac6,ff4405d8,3b9d8a75,e37b58b6,eed5525,6ddf9678,b2531207,18676065,ad8ffbe1,6d27df4c,3558eed7,992538b3,77cb8497,86e0a78c) +,S(fa250368,577065af,b60be8d,e9381334,9be6fdd6,1bdd02d9,3591a35d,294fd547,f0b991e3,96c77cbf,5d642f0d,cf5ee10b,3b0a1fa7,7b696f06,d4d61cd4,48e81625) +,S(f4df5ebd,67162bfc,3e3da517,23fec6d8,6b61d6c4,a5876c4d,440f025a,272ba3d4,b23ba279,8bc75fb2,d590e384,c9e375ce,6380dc5b,90970d44,674e32a1,8052212b) +,S(ab5b6b1d,b3725b65,fae28e5c,44460d6c,51b8971a,655541c,4a587076,a1ac5015,16d2c457,ecdc1718,3a9d7876,d785adf0,424f72b8,d08b6a9e,286ea5cb,26ee2ece) +,S(a8a4ec7e,13db5370,40680dcc,470d38a4,2e08d99,3c30f981,ac877ce0,28869e55,4a9ded9c,2cdfee53,897d0874,965878a4,754025d5,babb07bb,2d248151,cb7f60a4) +,S(337f54f6,33bd60db,583d08,165c1011,6f914dd9,e2abcfaa,5f1b1410,b8245f48,9453eb28,696afc4a,40b5452b,d3abae4c,679b58e5,408b0a94,ea456771,8176dbfc) +,S(eee337ab,dc2baaf1,544c767,41a5054c,f6db480d,529d20e4,33b642b5,fd901b53,65ad5b88,2cc00d4,a4ba1d8b,a6956f88,825616cd,5f6c9830,87264247,869c27be) +,S(59f52e18,57cb000a,ec1aaf0c,b43f1274,f56e477c,50f010b8,4513fcef,752f1548,d8ca8f6e,8db03b19,8047006b,a6ec1e29,4f225461,9978ce70,a1ae0f53,9e1698be) +,S(6c200a0c,25fadb2a,8a9618d9,d7d86287,8583ab10,f2b4915e,8f5a5f05,406f3e12,14d4984e,374cf35c,145af24d,a5c0d0f8,504649d,b1793a61,7d6ed949,ef8081f8) +,S(1654a2fd,51dfb6f8,71aad878,239b657a,f8144ff8,98a3c2a0,32cffbc3,8aac07fa,8b6965c3,82d98569,b6cdcc1d,4c71705c,e36d46c5,fa5df714,8d59043d,161a839c) +,S(c48033c9,ab473556,c9982f33,953f96d6,7b3ed1c0,7e98efae,8de232f7,67556d77,af3f48a8,7bc43168,10787382,8dcffaad,abe4a54,828b02b6,f897ab4b,ed968bac) +,S(5dd977fa,a9d228d5,1885aaea,557f7a98,1a95771f,212c3ba,f1a4e428,3c3c6032,3bff9d4a,ba178f6c,d2ce5204,3daa06f2,abb06acd,274beb45,49e72a37,8f2eb656) +,S(2a76dc25,dd9a96c4,bcff1d8a,f3c9aaeb,261e4c69,a5d832ab,efefdf29,ce42a564,493452f2,3ad5cae7,de8c972a,af5c3883,7ff82aa,df616c5b,2fcab4c6,d5244806) +,S(cdbd3506,4c0e7923,822bab4d,b4662b2a,fd3935a9,a49e6d6f,f2db8f4b,d29a4b8d,b2126f2e,b61e274f,a688a84c,386fdb5f,58b84515,1543f143,a8ce0a3c,557a90ce) +,S(983f249b,2cb9d4f6,34d82d6c,e713aff9,2bcfd525,a4146a75,bf6f725d,2b54d978,79cd2406,850be02d,a6c4d25f,5a02dabe,af302e77,238833ef,cff0484,8a8abca2) +,S(88c765b4,a5a0a9f3,a257e21e,ffb23e51,9e128489,fade1383,96fdc18c,38afd4f4,f4d5fe64,729995a3,e505cc03,1d144682,e3336ae3,45c28697,1cf89b7d,595f46c2) +,S(197505ec,d603cb0a,199c7d08,b88d0e63,1d147d07,45603692,6b67a582,b7d52c31,947ec13b,f2d75fc5,af5a746,15a75aec,2f212adf,a234e08f,49a561e4,f9057f15) +,S(98184232,e10f605f,58a700c3,d6bc04d,9a19790f,eb638fec,668320b6,3b2eaaf8,ef3076ed,c0e2fa39,30ea837e,36c31f59,dbbdf192,ab18bd7f,39578e1c,eff9c85b) +,S(50f0db35,cba0134b,790f47a9,e322670e,f0c7d081,6869a764,892f8e23,6c0bc002,1c1b1c13,d98a84ea,e77260f6,58e265d8,9e466b44,b8604edd,83233fcb,68396072) +,S(d9e340ea,1a44bb50,ae4bb19f,3f4228f4,99ac8516,cd6bfa86,80c1dc31,d5665502,128a1688,335a2193,ff805251,b83baee9,341445ad,25048f75,355f4b35,5b4aaad8) +,S(15aa8133,1b84ddd,8c706702,555dc19,d42cb4a9,a9474c9,1e33c0f8,e87c539c,79530720,96586400,ebdd2ba1,7762ccbb,2a14bf47,45f63b1d,e22c6a6d,8942dbc1) +,S(6f708704,53d19a4d,b910d169,c7c7be23,d489dd18,23604242,55e182f8,7a5d34d2,e0531956,7c1c2bf4,a0a9beab,d7c4dbb9,c15246fd,5a6de101,35578aa9,99c7dde2) +,S(31e920df,cddca3a4,89ad97e9,168854f7,867f9a58,fe2d3f1b,f33f8dc3,c7167674,52712c3d,b0c6e58,15157660,ebe27dd,244a9c5f,b12cb8af,dbe82900,c3706f39) +,S(93300e11,708ff01d,96f81fbc,f1888c96,8258dec2,86a315ab,8d01f2da,4c8d51d8,15368647,3b6a208c,8449b53,66584e4c,9e0b7636,1256df46,4c93d4a0,e26c33ff) +,S(8f7ad50b,f62d6702,616cfdf,3712c1ca,30c94632,720797dc,ecd54f65,cfacb3db,5ac10a32,7dc52bc,33290080,a1a194c8,1eff0d71,65f9d34,7e4f8b44,8443c637) +,S(6ed80b82,76270d71,c468f5d7,350c608a,7f5cf51d,c8efbdd7,4458a487,2989f4a9,bcba2bf7,38f6e77b,465e47b7,c687c7e1,77fd3cf2,163b5a2,e00923d0,89826dc0) +,S(ec6c1d7d,b94989e2,962cb85f,777eada2,7c2b11b2,86949e38,eea2bb4b,7ce3714c,add9f9af,6042dfdb,1d4089d0,ebca5755,8ef2664d,52fce516,df3b030e,9ed08fdd) +,S(8f77cb2c,24dcc192,593a82d3,510859b9,c59bca8e,9546735c,1fe26084,4a37f093,51674986,fbf499fa,70b55bd4,f0a70cb8,423fdebd,587e6213,83199b3c,4fe07202) +,S(e2addf74,dae831af,aa4c4ed6,2f4a32dd,1122f2d6,243d049f,1fd78c1d,64b6aca,7dbcb394,1eadfb0b,8a56022,4da66128,a73a1aa0,20a5b23c,cf58118f,e28b2297) +,S(bf7af1bc,614d31c9,9afb7c6d,b8cd45b3,3a22b151,34ba872d,3e845da3,2b1e3eb,108d39e7,8cf88a22,fba9e255,23267bd5,2b850464,f1277239,7542ec2c,50125a21) +,S(88ffc7f,cec6580,5b92c5f6,952d82cc,35b4f068,a7581987,93ebc59,8efe50e4,382dacca,94b42c3e,ba1558c7,82394564,d39193c9,8b9e8cf4,a63dc4da,4d378a4c) +,S(b114a384,ef4ae60,b9c569ae,636eab27,9070e207,34cf83b7,a28353d4,7d3a152b,37c7673c,e58ee20a,6076438c,9bbe5cbf,bb826076,6d8a7001,b188c477,cca3fa70) +,S(e411a42f,e20d23b6,fa768fa1,e310192c,cfb0cd2b,1914c9da,627db3a8,c7e801b0,feb1b79b,43ee7980,7252bbc1,728af29a,8f6828ae,8aec480b,91c85008,959b1039) +,S(191f687e,46432313,c085182a,ede5e7c4,31057ad7,f1f48fd7,cb814fcd,74ee1999,5464b42b,3f77ce2d,59a39efb,83808cd8,43e5c540,3d5081e6,e4f4b1e,926dbc72) +,S(63ff4977,33b0a49e,f618c4ff,1aef537,9837744c,85a19bf0,b2208eb9,506bcd81,6ccaef97,ca835931,f3a87b50,a93f2a4,39535d8c,87e26090,3ae49b29,30593d3b) +,S(efe36425,c37705ba,69e7056c,2e8c628,f4ce72a4,68d85556,4c57e5ad,b7fc2c1c,392b9b5f,27ac49c5,831a5f52,c2e55bb2,8faa7f12,521732d0,8dd910c0,51970ad5) +,S(6d2126b,dd7cc08d,1bd41910,21704a1e,841d4737,4e5a0a99,9880051d,f77e94a5,2e9b823a,cda1be97,52f72ce6,ead42127,efb4d4b0,8daf55f5,5da6f956,84e6e806) +,S(cf7b9ff4,297d9c5b,91c6340d,c1cca93c,6d453ac9,86b4ef54,b20df6a5,4933743,8a57808a,2c07002b,111efec2,bf751b54,c20613c4,1e3612ca,83baa3f,eb670c15) +,S(b160242b,4cbe5ee1,d1dba4e8,e2d55a0,27f5a5bf,f7c023f2,c1524fe6,5f7e83e,ac35795,6cf31260,7ee9f54,fb39d3e,4f1faaf4,67d09567,6075b8c6,3c0fb5a0) +,S(7a86452c,4f8918d9,86d3dce0,22619a72,1744d9c6,dfd0e733,c02cdaa5,6abb050e,30d30b1c,b558b0e0,fbaa1fb3,596cf454,542370fa,43d8a85a,91eb6bc5,c90de179) +,S(a279bc1a,64d206ef,ea96d3a,b97c6770,af41ba40,9381d372,408052ff,582323b9,aefc853d,701ebc44,679a7ab1,fe033182,e96199d3,4b58261d,a1b4a6bc,6ce42046) +,S(e8e28570,5c16016b,608c301a,ac59f868,f7691886,261eb01a,d4e6ec6,a9e5cc76,92350315,f8e78051,b703b7a,49427272,c988ea66,27699eb8,f2fb3eac,9f0a983d) +,S(1fd9cef8,14f3fc81,8055f300,a734f9cc,46da1585,b939be73,459e0ce1,8a9f2bbd,dcc4f73f,a50fcc8e,6ec3c71b,c045f020,c26d79a9,794a25cd,26488c0d,9cabb55e) +,S(321b1afc,70275fd6,fd48942,df364f6f,c609d4b6,cf4e574d,39f1ad06,927e5f11,1368ecef,808bb311,ae9ad36f,8a4c81fb,725a80f8,ed029680,c5b54463,80add33d) +,S(4dff29fb,6518e393,dad0cad9,b0dec257,f9ef1e9c,c50cd741,8108c42e,f6d7bf72,4159786e,5aa4e82,4d7bfd06,713ec8f6,d92f8f8b,48304efd,e4d0f4c2,30dfb70c) +,S(937a84a5,eb63055c,65b162e1,1a3f2e54,c839b972,95a8c1b9,274373f7,5ced1e0b,a03078bb,bf11a351,da7fb3b5,2e3e7a2d,62c122b1,a9cf9954,53294f37,7966afc6) +,S(be3faa9b,7cab73b8,4fb2a87d,25db7fc5,56f07393,b3177c7a,56df0447,e96cc3d2,e7051ee0,1ad794af,571dacc4,4e91f7f6,9276446a,7e348ee1,2998968,afaf77f) +,S(58b39c6b,cc36d506,765d24da,6058d7dd,36928d13,b0fbe1f8,c680df15,756c9b41,449e9691,aaa846d9,a7412b77,73f7ae6f,b4ecd99e,c57863d,ad72d3f0,423d74ff) +,S(9b18a971,b1660b46,720e2100,865742c,8c91282b,1c72c7b2,8192bdc9,c3765798,2812e522,98adf83d,2cc07a93,4a065016,2be28d37,59cfd50,6c792e31,32e0f49f) +,S(a6c44c03,dbacd4bd,7a35e207,61778826,c86740c5,c92942d7,f73a1b3e,dec0f59e,73316b7c,d1fa3410,76b73727,8aaf39c6,2258d29e,c40c80e0,797493cc,7056077f) +,S(1ffb2755,628ff8d5,d837495b,94ad78a0,5dde2043,bbfa3aaa,21a05a3a,21682ee3,4a0478f7,6b8b6c,ffd9962d,f70e2a83,a71243ad,c690efec,5f95aff8,dbb5943b) +,S(aea4c48e,36051144,482538a8,8ee5f72,b67a21e7,8fb425c,3d6f1e78,419b8283,4517cab8,c28eb397,bd89d216,ce711332,82c7b530,6b64499b,2216bba9,41a80b27) +,S(ddc59bfa,5f8c0270,8436fabb,5003ca6f,b972f14,382bf127,f5297990,b4ed3eb,f6c3f19f,b80e75b6,53c370b6,742045e9,ad7dbc80,3a996696,99605345,ebd995c1) +,S(22184fe7,ed301b2d,62bf83ed,64742f6f,94d204c9,866a637d,d03c58b,54c80a8,9db27528,1073a3d5,617a389d,c5698255,3bc55d6a,3b80cab4,ace36140,8179b442) +,S(e58617f4,74e46f4a,74b0ed2d,6bafc3cb,6488c510,87136eea,f98aa37a,f201cef3,cc6a7375,52dde05e,71bf2047,d49a41b0,c6b141e2,e4f519d4,36d4f8e4,f2aa2220) +,S(c1aa4092,5addc5fe,de6c2c5a,ba73b3f2,b7394a0f,1d02846c,5b2a0379,824f8e41,9713af07,e30af560,9516ce73,5083ab53,2475bf26,5713570,28b586c1,d28c687b) +,S(4aa5d88d,89576459,1ccd1c2,3064c718,69e4d320,b0b71b5a,c08d291a,c1df6168,1d0ea41b,915c288e,c6b36cc3,f7806481,c048482,dce586ad,f240d32a,c913e6e6) +,S(93876d91,73137834,dca5e192,fa869a02,738d4171,391df1e7,43296f93,a2a8a977,7948463d,32bad450,24e63d9d,d5786a69,73fc6c8f,9d2a7c3d,e2d6fbad,7a6457a4) +,S(c80cd7d,30268025,b233dd13,f2f2af37,5d18080a,54c406ee,50e4890f,a91b7b28,9f73b58b,1f1d11f9,1648f904,ac7ad275,9e6260c9,27870292,278fe521,b718bc4b) +,S(d2bd24d9,7dd4a345,a8c4e857,97a9c30c,e8e7e7c4,3ce79bb8,fba4250e,a0c8c5cb,330f0cb8,15cb1931,90331055,809eb028,55ae895,ee1a30f7,665166b9,6494b9e) +,S(d4e4a3a2,90deea18,fb15457d,f3ab9815,5d722589,515a38b8,dc303307,5dd7e9f4,4854493e,77d0ecb1,742bdc9b,a5219e9a,71c57a6c,b914b8a5,6eec21dd,3e7d1c21) +,S(f0fb6cf4,810de399,fcd1b246,f0e76e2b,d318f82e,1601ebea,2779be6d,47236d19,e3ad5160,66480239,88b0b197,3eb2a41e,2cc9b4d3,7cf58d07,ad0edde7,ac595daf) +,S(dd4ec58e,3f4c470c,36991740,d02b0fc7,9a4f9df1,98647ab0,ebf73b10,34858939,3a6ecc86,a3b058ce,f278c839,541e92dc,737a6390,94ffa464,17e37da0,40a3bfe3) +,S(ec56910,1d7ed954,d4efe1b6,c4f6ade1,2af12f3a,ddc75a8b,8fdaebb7,ab904e51,3497c67f,5d594f71,4327111a,e22f2621,be7cbaad,b2cc1d6d,be0b7e50,d450c54a) +,S(ca45def8,51856a5,7ca5e1aa,64edc3cb,e25ef6b0,e28abda5,a85d9a19,dbaa35c5,db8b2357,268db9eb,e013fcde,111372c2,6eb4ed69,5a7a3df0,4d1d33db,703521b2) +,S(b44c5388,964521e2,4803c8b6,3dc8a494,40f8ba15,435ce2e6,5f6dc092,15b49a47,2e16435d,f30c4b80,cf125e04,b85166b9,509890a9,c1daf1f5,72462a83,de198d00) +,S(95b735e2,35862f14,e9291a5,4b46d977,33a20ce1,b59b4603,666cfeca,e05dea26,e1281705,5f38be19,9bc9977,b6e80c08,f22ab5b1,286ea553,21145675,264aabb9) +,S(83d9d867,8fbb0263,6ce8d231,3ee4716c,a15c71b2,66c1a7ce,e56928ed,73e5bdfc,e0494c2f,be92f132,effe7d78,499f4a00,c35027c2,37df8545,9918687b,6b949246) +,S(98b7c85,a04c546d,bbf6bad1,6914e247,1d3b478c,f30dd6f0,2e843770,49bbae03,769c3b95,3733dfd9,d9027da4,a10b0a65,ce4106f9,44364972,e569c63d,3b2ace57) +,S(3ce7b677,852d34ec,34358a8f,4da66d53,75019cb1,19a45dfe,864062a,a3b12e45,68d2790f,1838b86,96272c4b,d5e418a9,2cf03d9,de44f218,e42562dd,467e409a) +,S(a0bc28f4,d4da7101,41d0dca7,51542b83,6b50bdc8,997b291,e074727e,cad7836f,6ed7e149,40f2781c,d685a581,99f163d2,177eecbc,ca785224,2a8b4859,97e47c88) +,S(9a571ba3,52b1d62b,4e5d290a,c0d41983,97750fc4,9a18cb68,18fe11ab,1e185c0b,1a91cccd,b2b1f58f,9cfc0dfe,d3464917,f6c2870,9bdd8128,ff61e295,ad1b4ad1) +,S(fba0544f,cdd2de73,d24eca5,55a8c4b0,4e135c1d,8348cb93,d53f647e,2a21b9bf,7a11a425,a4ec6acf,2eafe631,ff83be6a,f71a6cc9,f7dbe3f7,aed57e04,2774568a) +,S(d96b253a,1edbf662,3902bdd7,1c3bad9,ecad1115,45614b48,5f7abca1,d4920a9b,2bc88998,f951b831,2f27d09f,2f331536,1499f1c8,b172f1f2,408d0660,3b18c2e8) +,S(2b3c17ce,1081b825,94ae14da,f9723f9,9823382e,947c1356,13a4b8a6,42267c2b,a4cd589f,2ebd245b,88c7f1fa,427a2ab6,e77205c2,dbbcc74f,dbbdfa69,336048ff) +,S(69698780,fdac522c,69313ea7,2e244d9d,3f6bc5c9,4fd86125,2eb56369,c96439f9,e8eeb3c6,460f475f,c06b5943,9bb9994d,8d6e4314,fe20020e,c1001f77,25a03154) +,S(1e344611,4cb4dc4c,963e172c,9bfc2f4a,d1577efc,ae2ffc6d,76395ef9,a0848c68,debbb8df,e6f59a0e,b96d464,3bbc6d51,a2bb4621,6059de1d,a473436c,404f5b19) +,S(6ccfae02,4c7f2a9a,ba12c191,bd35e287,d5c30284,c4273a1f,c558ae8d,286aa61a,c2014174,c78a2fd,d342ade2,51e4588d,94c4cdf1,ee83ade8,54e48388,b6e7cb11) +,S(5b5fd487,69b6a133,35bf0a2e,61a2128a,db43153f,9497c77e,c32b16e2,ca4c728e,9954353f,b23c9d44,eadf2632,168711b5,5a54c9da,53c41088,50fe77cd,8cf00c77) +,S(6b74a257,27af44dd,61fbbbd2,7323b63f,e6a41d9d,f5412215,65a6a9bc,35d069e,a4e1214,f17b8dff,b5bd689c,5f004c98,39b87a46,15245756,48099d33,f432a34c) +,S(5171a187,8ae9ed01,837408b9,fe08f317,8688606c,aae04b2,63cbf143,b8e372a2,b5e7de6b,964153cc,fe64a472,8a8f20a4,44da8e15,c593b7e8,68140276,b172d06) +,S(df9e86a,4337ef32,3518568c,e52958ab,dbce8a92,840b756c,279e96cd,43c8e80d,5442baee,c72f460a,110e8ff6,1e938132,50b2ccdf,61941df,5f591bb4,73027da7) +,S(ce070279,eb6f1f71,af876ab7,3903fbd0,ac9e4693,7b6d3307,2ec80182,3887c850,de83ddf9,88f9d345,e1ff2a79,e91f8ad9,6ea23097,538dde84,aea0ded4,b6a155eb) +,S(a0255c62,44afc84c,58238936,c9d08d36,96e5789b,ed28c40,7667f348,4c2f35fd,93e2d407,aef898d7,c898293,fb20f222,6cd5017,cd62669f,17ee0d16,773c6f7a) +,S(ae82dead,b76d5dd7,140e1197,a383ff62,138e1840,dc2f7ef0,d5126dca,86f0d86b,239dbbac,caaa0779,a9f6d8ec,2e30b590,72d36b58,199a27c6,5f5815ca,5720964a) +,S(cf0999ce,bee65e2e,d596441e,a8942461,97c597ac,9c090884,44c375d9,16332393,6620cbd2,f074edd5,1ff8cd5,45adcdbd,1c664ad2,6935880,8655ffb3,3a748ca4) +,S(5fb4af74,6404b01b,63bff1b4,1bacbb36,9ec06801,9454622a,76258033,9cd3965c,464cb2e1,2cce697c,d409529f,a48e7448,916a51b4,5954fe93,d99ce392,272abff5) +,S(15af3c0a,46b5232e,55e5687,a2bc4acc,2c7a350f,8114e3a0,1993a0f3,1b3216b4,ae03739b,bdce38b0,4735acd9,3a3ff7ba,86c8189e,56a5bb37,ad83a574,cdd45a83) +,S(5d0035d1,d008ccc5,42cb8b5d,32d973da,32c88787,640d0465,76d33e36,540b4b10,448ed8e5,bffa9f28,6689061f,73a74f17,76db8a8c,d5b4af39,6173e7be,6e54c465) +,S(944c70f3,9cf749df,edb9d322,ffc69e3a,a40b0704,fc4af915,e027bad4,83c95527,b0ac0c3b,bf489332,64a6e95c,e49a669a,df10acfd,48e22fc2,1a18ecbd,b86c6f0c) +,S(fa5219f0,82ec3c4a,3f246754,dad62f04,52e26225,6cd28acc,846bc5d6,151e4402,32ce81e9,d6403132,d7b64f26,a0289031,eb730d2b,dcd0065a,1b4e3f3,a7afae9) +,S(c9f4aa30,ddbee263,509455a,858b8518,85c6a16b,5d9bf032,70443928,38a30ede,5ef717c6,b438af31,9a892799,46b73ba7,add20334,c2fa5bae,a15b7632,34ad7b7c) +,S(2f4cf3ca,7454d569,5b0dd2fd,c72d4ffe,529b362,deeea120,162c178e,7b770319,dcda920e,3566ebcb,f47c1ce0,fb767092,fe7c87c5,ff146042,d5a0ceb7,a2f7d487) +,S(2417f576,2e0cd74a,f07a41a7,51f91b3e,a1cb0a42,2246af4,a0a96b8,79969945,6a96d755,f8dc71bc,adad0a3f,61cb44ed,741ef96d,96baacee,fcfba7ff,1e7807d9) +,S(9ab22f84,305a1c1f,675ca5ba,cbb3dba4,d43d060a,ee9148c6,6cfb61b8,5888852c,af0506fa,a2588e3a,7aeac12a,7acdda3b,b51d996b,2cca9c18,e23b517a,a428a03e) +,S(f7421ea2,24627926,28ed878,7e154724,77a91726,5a162f52,87501d1d,24a72b6c,db0ae665,e4484132,f372ca6d,8cd46115,fe1c72cc,885804dd,8f508900,5743fcf6) +,S(35756af3,548d57e8,dc0bb791,8b9875b1,10a912bb,7d971e35,4963bd7f,df5c6f75,1ca46dba,78a2b4fd,d4ed69ae,bd4e1961,86d94b8e,20b1660f,c517098d,e077a1d2) +,S(a7e9f00c,494cfaf2,16449d9a,b0dae7ff,de4041c2,fe031bc0,241c44db,1bf01837,f2aeb9ae,480b406a,9753d009,3b5fbb74,5a7760de,4ef508b7,d10804c0,161a0280) +,S(69451dba,92872879,7737755b,7655ce70,64838aa2,9084fc1a,c88f5e6f,ca62adb7,26218fa8,d40df091,31d845d4,96c7b950,1071537b,51a3143c,c73f1a7,b02b1cd9) +,S(c49c3b30,15cca66f,ce986a37,588205fc,89a92d0f,c520ad3,5eb6cce3,daabf06d,7afde84a,665b02b0,e0cf9ca9,9d2ad097,6242919c,53e31b5e,6216d67c,580e354c) +,S(e9e181bf,b68e6e38,c5b6ee1d,f11c14f8,90c0c744,8570387,1ab6b624,6b9dae8f,b0bcfedb,3f394317,907e260,c3651aa4,d1af5ca5,e1a34018,fc6c26a2,d5ef5e1b) +,S(a428586f,adf41cf,5b5c9e52,e0d6e1f9,2e7d8738,ab99e8bc,4062e302,de392324,77c3e18b,fe71c937,65b911e8,b49cdee9,a2a7413f,4de831c8,3f967f08,95b8d142) +,S(f5c92ed2,de1d1a25,4b4a4830,b656a674,38077be7,5efed94d,785dd0d9,72712cf,7ee98d3a,497849cd,5b5f6dcb,c51c5119,228fdf7e,1a67f1e,d7c670b9,eb3958fb) +,S(a85707ca,6c85f506,311b6930,767b5571,e18c19c7,ff2574bd,f268f018,b49c3f66,1785fe71,cde2e189,aaf67d10,337b8fb8,53654335,4d5ba73d,77518d9f,5e8aa050) +,S(8866f5f,a4c8d1c2,f2de0cf8,19eca5c4,d084ab60,67a7d97c,f9942fe,c0a7468d,3014226c,3f33907a,2f6c49ad,c762be6e,2915288b,a7ec009a,fe693048,3588336e) +,S(425f6d73,37eb2d68,e17d07c8,bda406cf,92af22b5,6461bd66,f40be14c,ae0688cc,e865526f,7c42e391,1ab73290,e80bd9fc,9643659,5871bdbd,ef8d698f,d04d4980) +,S(f70fc3e,1de3b3fd,55418441,43deb4be,36bfe6af,3bc9d9a2,f8ac823d,68323139,8b47994b,1febb309,e3774a82,d6b18d78,8ae5750b,40aa944a,dae404b5,da24ce03) +,S(1be960f3,38d2a16,703b10c,eafa121c,d59c66d9,439e9067,58a0b363,2a83116c,7fa4ca2f,8218ee04,351549cc,3b0100fb,647e0db,19eea010,62f1c0de,3de29aef) +,S(1f2a2d3,bc5c80a3,8af51e9f,5694a80e,e915eb89,4831ea7e,48472d53,320cf385,a18cea39,174b4c49,f9bcb945,5e6701f9,47053f07,6782ce9f,f55653be,6d3940e5) +,S(61d6b60,70846b0b,b7790861,17cafaa9,9aa67c37,fe77140e,88477f3e,44d04766,c7f4be90,86849ae1,632eb59a,6c96de66,b7c4b1ea,caf724d2,5338c11c,a8f2688f) +,S(2b37093,2d9a6451,79508daf,4be7f26,6d540538,9276fc4f,e6ccf0d4,1ee6cc9c,c002a3f4,2c8998b1,ee16a1d8,616ce0b7,91cdfc44,61839d9f,5ca0090e,295beca7) +,S(48f5c3ef,aba8b7a3,4d7fd136,fe9b01f,64af0e95,6a27663a,87cd6629,f2708858,8cc38cb7,fce46724,7c2f09cc,52f973be,90aefdbf,b52895e2,b88f03e8,fe32b5ab) +,S(e609b597,2e5ec227,6f5cfc87,67b6d534,adfbe9e9,9e60b86,e981dd9b,3e62cfa0,6be9c1ee,ff205fd3,e3b85e3d,bbf1b27a,335ca616,9ae189f,a433e65,f2b43081) +,S(ebe40b1a,5b2c9cc8,46eb8ea8,1ef0c1ce,f19a767b,2da6ab0b,2ab66a01,b16d205a,2f7710e8,e4fecbd1,39899bd,1964f5da,967d6920,d70b2f4,45d6f914,97c67058) +,S(97cd4c39,9391b1ef,653d32f3,9b062bcf,dbc72d45,83d81b3f,f70df659,358e3abd,a05a6184,a175b6de,f9bc35c5,6e9f5cae,263acf2b,a233bfe8,13dd98a7,fbf37968) +,S(826928aa,1d3fd0e8,53cd99fc,e6559ae7,257343aa,378100e,bf64a3c1,bea7e6d9,bc4a2db1,a3bde90a,ff50fddf,cf6f844a,faad7f8a,89bb399b,20b07b2,2e1efc79) +,S(3e754097,f3ac95dd,176e9181,410bae7a,83bd1431,6772e398,967ed39a,5fa19121,746cce99,c6a2cff8,a0907ea1,5cf9436c,ca7f94,7f3f1801,135fe675,a518df32) +,S(ce539464,b49b9947,808a236c,8a027066,82991f46,3bb828fa,44653266,329365db,3578fec2,b8bc4763,61f2fda,29c2c38b,a7bda79c,11b2cd41,a74d4c02,762e5dd9) +,S(c933d9d9,cda615ad,7ac41d6a,e64a77cb,44a2b669,21533669,2c90c3af,53e349dd,4a6da24f,83baebbb,8f2a8ede,298babce,a25b054a,a1c4cc11,f9f0b0db,572c610) +,S(459aa43b,1aa9815f,e9116f2e,78ddddef,a78e2def,28027d51,d081a3bc,800b2ac4,1acedbc3,de995e30,b16900d4,cddcd1f2,5c615156,fc29645,4bd5fc7c,63e993d5) +,S(5f2aa5d9,9862ad29,eb467564,639abfc,ff445334,9a30c4d4,3b27f913,1e3b0a5e,571eca2b,e61d0bf2,d9def9ba,445b39b2,5acfbbb7,dd4e2cfb,ce7541c9,61ace144) +,S(ec66ea1d,e6cc5d59,8c393e68,1a338549,fc2c3d7f,947b40f5,75681e60,88f4fd1d,d711ffdb,3b378435,5894dfa9,d0a5497a,5540739f,a3706597,8ab7dbea,a9280f52) +,S(6ac53df5,aa097f2d,9983f018,bd1cab39,69ad0638,c78547ab,1a481682,ad6105fe,95f69a81,5127b919,9488f224,24307969,3cd51796,bba08578,abfc8e05,6618a598) +,S(a8a3e9e2,9e4ad0fd,c466dcb8,fdc02cf4,16fb5c85,b3454fd,3842f129,9f96c0b0,df86eb3e,3006dea5,ed6d152,f394d7c3,169b8d09,bde3685,ce138a55,6716dc2b) +,S(50a764d2,a0d8741b,95ec84a2,feda6df8,1dbe987c,31861166,32c40c3d,e6db251c,b28203f0,233917c1,4b67632a,ce9b512d,76a8c7e2,430a4a40,85cfb422,7fe41055) +,S(c2c314b1,5ef9df1d,26856c9f,a6e39cf9,1bd9c584,582893a9,423746ca,1ab51ef9,a27f9286,ff7fdfaa,b949a9f5,d59f08b7,a22f1e31,e7175d44,93e219a4,e92ab759) +,S(ba655585,da44c8d1,2b3ce375,e220a4c3,64868b75,370fdb75,dbf6bb92,76a9d3df,3d64e16b,a03a385b,def18f61,432cc49c,bdd9d04e,6fc8873b,e51663bb,ca4fda50) +,S(3d45fa49,d4d100a4,b5a76a65,1a5100e,56bd0d13,b9e141c2,aca5cfef,a46e600e,92953c,38eeee42,e1da93b1,3c75ba48,da30390e,731801ec,ed5bdc2b,58059176) +,S(e464c346,e40dc3e2,40e5d96e,1fb2c10c,83e5ab7f,45138596,4ca46b04,bc8c3a8c,63f14b46,182950bd,282205aa,374cd67b,ca364a4,f57cf90f,c7ac90d6,5204cf4e) +,S(14a7e12f,e235b307,5b0d218,bd3dc720,d56f3fe4,c73841e3,fdf42dd5,aea42688,d79683cc,40cef482,ed6a22d4,8137a4f0,eac31249,9ae13809,9eebf3a3,15e9ff2a) +,S(8e7afbb8,21af73b2,25b34ffa,bb2ff6f4,61d2ee2b,85d5d936,a99fb078,963828be,40e4776,5aa0768c,f055bea0,e20e1062,bb528470,dee61ec1,6cc9ce7d,ae6b1853) +,S(9d641162,3227bd0f,4bcf9f1f,9e5ce829,7d844055,8a7ec246,5b160690,53297573,ed0d83a0,68001be5,70067ea4,70fec09e,1f8630d5,da5d1b2c,126c35c3,9b07fc8d) +,S(6758c6d6,d9e49d9f,4125b52b,e3da74e7,52bb40f1,44af0f0b,7bd80589,7fc83eaf,749ae08e,c2aa2c36,3a229b3d,e9577dbc,5f7d22cc,d46826e3,6a1cb434,184fd292) +,S(b3e11a0,45702d8b,14d93df6,3a4c11f5,32632719,b4a33fb8,da11514,bc61d73a,c6e152b1,2b267ec2,1a23892,8cb97044,9660c6b6,34b22d18,9a86fbd9,a9d562eb) +,S(50a325ea,3b309911,1371b0f,e0b9e276,137bf43c,22108b98,994ed5a0,d66fa5f1,946dad1f,d39e0aa5,8a758527,9b39efea,8a99399c,2750739,dfeae140,3745b70e) +,S(f7c8f249,3befd5a2,cf6802ce,8ac508ee,a97341a6,a46efe39,1214e322,e95e9661,3c072cc4,eec1f370,144b7ec0,598e4d96,573883e7,fa3f3f5d,4e33d88d,1e34cb67) +,S(302d3b50,c1543386,f0b0b94e,9c49ea68,38c7e7bb,86c28cc3,c8965dc8,38f85b6,988047d0,d891aa2f,60b66e5a,96c78c91,3588d128,d4e7f720,5672d25a,88310744) +,S(cb8ee728,2e7e5ba6,d0e8ecb,55ede89a,1d3810fc,b0d8f86a,fbf53b7d,219f0eb7,4b04ea2b,efad1099,8c9a4e3,cf0491c2,bc10bd60,e06a118e,75fe0163,ab8094cd) +,S(645caa2b,4a0cd8aa,20cf6f04,ac73a49d,74f92035,f90bd31b,211572d4,cfd5fd42,793f2996,35f9d7c1,de62b64e,afe516db,b0aa1323,7f51d0a6,b6fc8346,fb7ef5b9) +,S(4d37342f,6148b5e7,5434b8df,6617d64c,f00b1c73,3d85f4f3,e69c4a27,395f5a21,6400092b,d4c5c705,464a7db2,b1b6b667,4eebd7dd,38d05cde,d1577d8a,53a708bd) +,S(e634bf17,24e07b2,b4ac6285,ed28bd39,747a2134,36e76d3d,bd693170,18c0e0d8,cccbcade,4b82a51e,c31d9d8b,6b113876,5e9660fb,e897ca53,20db873,13e9f021) +,S(80a00de6,2767c513,d5bff535,431d259a,64c49006,3bbf992b,a5111005,360cef38,7dceb589,e8d73366,c467e23e,8fdc7e03,b2620df7,9530b6b2,3fcdcdf,628ef572) +,S(606d50e6,d23d50ed,9a5b8409,f11d5c76,baf5b765,f719625d,5b2e2dd,9e8f8a0f,19f55492,45b1b4c2,fcc1d220,6c171200,4cbb41e8,bb7c8cc7,48c4366b,3fb32788) +,S(9c8a0a14,f7d44fb7,4a7ea835,ae4a1932,266c3083,38d66a24,7fdd60ee,e4f0420,42c6c237,31578dd2,31eda621,81aedd29,8737fc7a,3b2be8b4,d0187459,e5d9169a) +,S(d6ccfcf7,81a46f58,ff9a0154,8a417924,1a32d3ca,43a8e59,cebc33db,1e35da1c,a1caba1a,ce846b8d,8b4824e6,1570f832,87cbcfbc,910256d5,68bdf223,861d084f) +,S(8cfaf36a,3e4c3ff2,4556f446,4947c8d0,6eed5ded,a40ec0da,4596bad9,f5f2e3c4,991b6ecc,ede6cdfd,e33f81d1,c1067f22,6b72373b,96ca31fc,c80e0692,d8f3c4d7) +,S(d46c3d81,5b0f3a0b,bcef3973,8c6a6cc7,189849b0,4917fda0,541c08eb,b7e664a0,35524bb6,d053e5d7,c8adc9b6,3a84ed81,58cffe99,4041e642,1fece58a,d967c159) +,S(8ed7f0a5,2f1f8df7,f82dce33,e4637dcf,e2ce9b75,ca02ef04,90c23fec,2b7adfff,f02460c7,b418d10c,96c27225,3dee3b66,4be1aa5d,427759a5,5d90c223,628d99ff) +,S(433ecadc,a8a351bd,52ba4d6c,aeea3ff0,825c46b2,8abd2c2b,cea85f6,6daaa2ca,4d3b71bc,c2d7d177,45cd03c4,86f390e3,f6d396fc,83d0438f,983a142f,162977e5) +,S(c0771ef3,10377f83,7a9bbddd,81f6642b,ba04493b,15c054eb,249b3f9c,bba006e6,3e53ddab,1d816a02,7898c6b4,778d4c48,e1ea2b33,a63955b0,784df258,ef4ccb1e) +,S(dc2e0226,4a6a87b9,53997383,e35c6cd8,92072ba8,a741fd23,8ff3a9c5,f597ad7,898ee746,ecd5f723,440ac0ff,6f597e85,8ddbacc9,cbc80e01,d8a3c1f1,7c12c74d) +,S(16bace34,59ad8cbf,1fc5f781,19cd9e31,d043d7b2,ed839f03,11f0b760,6adab771,f64532,6ec697e3,2ca23979,72b2b834,66e835b1,2bd49243,e896c1df,c02fb1c4) +,S(afb94d8f,3a271439,146539a8,68f00346,9af55eda,839c81a4,725f3a5,7d69c736,afdb294e,a455031d,a70a4eff,7563d764,bdf37fa7,5594c9cb,386e8bd1,a35201d8) +,S(bb31d236,4a98f7f4,1edb0ae7,6018e5ea,ecc33780,5f781dc7,6b15aa9,d0e89b74,1a064c03,1f47cc7e,cd49f032,f4dcd95e,87cbc28a,7b9d9c27,a92a4c1f,da031a9a) +,S(f73b1b6c,4bbf5da8,16604ee3,ef6e83b,241e486e,d727e700,1c3c115,3c4318b8,9a28ad6e,9d64cba,b58ac225,5c01b261,25ba08ef,3b7d5ffb,476f9b8a,6c8c9b17) +,S(63bd212,d0ddc5a0,84f8ea7b,69605b2b,708c8766,f0d3313,b236e921,91afa8a4,ee6f4f6,4824032,afbb0b3,a9fd342d,2fbca8e,ccecdb0f,a3307698,c56c3e67) +,S(6367d22b,36068022,30a416b7,8c689078,967b955d,875fd629,9e007f86,1abc6465,c3ee1f2d,14e6793f,17e444ad,5595f9b3,118d1647,9259e0bb,ec628897,f69417eb) +,S(64e2e543,fbb7f52e,57901e3a,448394c6,c922d0f,b632c4f,2df061a8,9485976e,641a602e,336a68b4,fc447e5a,5863a4e6,89511942,4fce011b,48f937df,fcab2a4c) +,S(2e290afd,18c835c8,d1d79e86,9d9c1322,e16e824a,60e67f38,d6bf3031,e3fee1c6,7f85628e,d2fa6b67,7686b0e,c29a3626,da18ccac,5e373874,96266458,79390f21) +,S(859a208a,c475d3d,f5f22907,988c7774,c0ba2dcc,d80ba42b,17ef1087,2cee401e,a667c645,778e743a,d62ed1e3,cfa12fcf,84b982a5,f1349e31,33627ffa,8b19f5d8) +,S(c9291908,ccc50aae,f19c0b86,829fdc63,b608d3db,d92b0939,b92ac02a,2bcaf21,e5c52bb7,47111f58,c71352c8,b2fc89fb,20cb7d45,77c6231a,17d8d01b,6cd2599) +,S(50359490,42b5b620,78ab0141,1f1a1d4b,64bc42c7,58da4459,b04d41c4,61cefb26,f61e823d,b68c064f,f80d9bd8,f272f817,347c132a,f7bd2af1,e5b451ea,bf4f04e0) +,S(f9bcfae7,d6a3f1fb,612787c3,53b535ec,39f29a01,9f45f43e,7b61f2de,c4a4cbf3,f4d86e6f,273ad7e7,902d5a99,50fc846a,a6565862,aeddc67b,28fc07a1,232ff883) +,S(1c8fe8b,901cf050,e93c0004,b0764715,602ac4e9,7f8d5dba,d7747039,f14a9152,b25ddb34,7c452942,92143b6e,cb19f87f,b42a0f27,f6f74c4c,99d7b80c,7d36769c) +,S(3c50be1,4cbe3a87,d363947c,6eb534e0,8ff676cf,412bc4dd,2c543131,e786f552,4434471c,6e03f600,d8a27775,4466cad0,194f553d,bb653238,8a0ee4a3,9b05a74d) +,S(64cd71b2,555472f8,fa968b4b,4f8c8b24,5b3e91ad,6d9dd409,fe72702e,e70522f5,f1b1cb3a,e9fa4855,2d7fc2a,819bd629,40350a3c,168782af,5bff16d8,89ede304) +,S(c1c00444,c584c346,d1bdded8,7cc40b0e,fd8f69e7,d2ec8bcc,c41e3414,619af7a8,d631b494,3e3febb0,87bb391a,d5810b61,f78dbccc,bc6de38e,ee09005d,3d879436) +,S(fa509582,dad5bb61,c7450fd0,3b7e4ba0,2fbd0c28,af971b96,cbef5956,3fa2a7ed,267c2764,617c2f78,9ab890d7,56be2195,2acdff5b,3490b816,165e2b36,2f3df4e5) +,S(655dcee6,864e926a,a6e05f04,b604c2da,35175e0c,f7d264d0,50920d46,c1a2386c,da2eaeda,bf062cb4,ba2d36c4,67965baa,5f1dc238,b5e22df7,2bbe14f2,cfee19c8) +,S(6ab5e1ac,1b7be624,97c8fbe,fec5c4d4,2cc1de06,d15a1beb,7606fc0a,df3c213e,26f983b2,4eb319c,7443e024,7fecdf58,f833928d,4e809d3c,f36231e4,d0a9e466) +,S(c7da869e,39caa2d,e9f73a0d,3f73ab73,6224e2a5,47ef5af3,5f5a9d51,60c25f3b,e99b1102,49a607d8,12af4cf6,76ae4c4a,cfdc0f89,9ec2175d,c7942b6b,40da579f) +,S(2a6d4ca1,5f1c3ced,ed68091f,af4d149b,e20b6854,bf015084,a9cc0d21,4944ef99,dfc27688,ae9295e9,ab8d9284,6a703ac5,5cb44bf3,13f179b4,ced6b638,e661ae0) +,S(447260b3,bba7224c,aa659f70,b1e7716a,92600a27,18129575,2de62cda,11c846c0,f17e3e0f,33ef2ede,8980c922,613947,8331e2a6,40260996,db8da1e0,dc8999bf) +,S(8cdb1cad,baba7003,8d4b0f44,1b312aed,5a8788a6,6e5356fd,5b994f6f,a7781969,b3a5bd0e,262e673a,ae7be06d,8d56c203,b88750e4,ba06cfa1,7c177edd,74536977) +,S(28be0f50,fb60f905,18323e6c,dcf46c0c,bc3e2c0f,175d8576,85126a85,d5caaefe,5cc058f7,fb188c4c,e1140429,568c3176,8d986fc3,e96409de,21bf9ba3,862b7320) +,S(b6dccba,dd2dfad4,8b69218a,d9cf839e,837e2262,7f8f0eb6,f23484a2,994673a0,e1c14ad7,297f1626,774aa2ab,5dcc730a,49623176,ae81eeaf,b52cfd4c,fa2de992) +,S(e45ebec8,8813f7e5,7a7ecec9,dc5fcda6,b9cbb0f9,19bae1d,be770955,e3766a87,3a62a0bb,4ccf3783,7c384885,7acbaa9f,f915cc7f,13a46856,3ff135eb,dfbb07a) +,S(de926f77,26f39d48,1e0b9e55,22b7c874,59bc9d07,df65f0eb,7b21fea,e8dccdbb,9d190ea9,263d4240,24b618ce,1239f6e1,115be2b1,d721aba0,f5f367f6,304d8e05) +,S(f7621384,20669c04,6d794807,569722b4,91e4272e,1305f091,b54a03f2,ecf2caf0,d0c7e8e5,a227f2a9,5c594528,4590caa3,3088c92b,b4c7cf6d,12d293d0,4b9e4914) +,S(4e795e86,44ffee08,f44d472e,8ba0eb9d,a5cdb1d1,619a437d,4a8bbfe8,565ce751,5292d8e5,478268f9,bb9b4be3,c751e587,65038c55,99cb3549,749e83e2,1590a4e0) +,S(70e64689,a944b03f,32b33a97,c8923531,cdf75e8d,e8577559,bf45d2d2,ddb50b3d,a675c6e5,460b89a4,a2dae263,c71e6edf,925a93bb,a916951a,5364d252,c225586) +,S(21637c2e,682b247e,cb8c1c,8b4bff1f,477ef390,3b9da0fa,b08b5cf2,5b67056b,e357165e,3e761a55,7e4c2b6c,727d8387,c5716b58,e24d0e04,8314979e,4e92d882) +,S(7691a399,8dad2e1,741a4135,18bdbb,d8ae5bb1,7466a949,a40560a3,9c1d1964,225f1404,b05b5bb6,cdbf2296,f76e7f27,257280e,28c68be4,d8c81c47,a422b74) +,S(748316a4,f3950849,9af5a14b,27eabf9,b0d11e91,d8752cb,69899af8,79af9302,cdcdd4d2,6bd709d8,c3d87c12,6dd8a2c4,f600fc1b,9e84461f,1793047b,5bfd7ee2) +,S(af588dab,3839e85c,6dc84aa6,c1e05294,a9708951,8006b390,c2ffe0ef,f6ed9b8a,a3d37640,1b06548f,2794131f,5e002aad,616ca135,8cf0c81d,87015416,37d9cff0) +,S(bd91dc60,31706ffb,19b61796,995728b0,5f869d07,6f0b6537,35c46e10,d9b42dc6,3c963ed1,5a74f5c6,1a28db8e,de070870,cdce2cf7,d6525a6d,16171076,44f153b2) +,S(e625c4a5,91460bbf,5c3aa583,c4cb1e1f,c202c82,7debb82d,985732ed,ede98f47,d026c5f9,a9035396,1de50534,8e4ac600,812a461,c913299d,7fddccc1,5970b72e) +,S(6bd227fe,d4b193af,8b94553c,718357e4,122cd057,d95980e8,ebc8fe5c,7fdaac1c,5f3fe540,a98b044,9ed835d3,b0a2b4e7,c66a0549,e4b7b9f0,22fd5249,c621a9f9) +,S(27707a25,895e6f38,523d3872,c5b34e7c,68a0f0f9,54c6ef49,5cff6664,1edb2609,ef6f4f8e,c893d697,69f34b38,f7f677e9,e5de5c91,48cdf35e,3a18022,3ea777ee) +,S(6052248e,3359414e,bb7770ea,4284d7c,c01770c0,e75466db,1f314e0f,cff0ebde,3d982058,5cf0d546,9fa62e02,aa556fb,1a1ac7d3,1cb9712c,8b118e2a,e3f7b7a2) +,S(f2cb5b53,4fa6124c,16d82506,8b229857,4d4fc666,9b45550e,6c75a114,f370f6bc,5cde5707,63a5cad2,13952def,43cc779f,8ec9dcbb,c5fac8a0,ad7a740b,7241112e) +,S(77ad8215,9fe6b9f9,e08030c7,a75c601f,4989b51,4ef6db20,aa9d0b23,e87a502e,9268a1ee,ffc24932,74856add,2ba1ebb3,c13678,99af932a,87fc680d,ea9b703d) +,S(4418748d,171cf80f,a7f80fd7,c2d7891b,5cc9aa0f,ba4ec1c8,a114cbc9,4a8fd29d,5130285,79f01b7f,72f18322,b279fe7a,9916c16a,a67c6aee,babbb418,fb1835c1) +,S(16af4960,6f89c87b,7e5901b4,d11a826d,126e59ff,df7d0883,1d37d7e6,367355e0,1a138440,537223c9,e8e131ca,8ea3b38c,12c8e8ea,50ee09f6,8ca4c2cd,4cb04c2e) +,S(22d2043c,ab4431b8,cf77ba0c,ad81848c,730a730,35277e4a,ae6392f9,de120f9d,d7795dad,5e5b46d0,9c36520a,c7fccf9f,4d71f9c9,8ed3d45a,432f4f6b,991b8acd) +,S(57e7a8b,34826533,7e203360,2f6244b6,41d92c8b,b2419734,9fbb3271,57676302,4d9238e8,ba4bc8b2,c3abd2eb,6bb2e545,5146afdd,3d1ce2a0,9752803b,4599b83a) +,S(45567f60,2755027e,282b39ed,5ddab1c,7ea19a82,4c0609da,9ab455b0,26acc359,db55ed5a,77a354ed,e4229161,141392dd,82c1ccf7,f726fd4c,2fbba48d,4134f5a7) +,S(968fb554,91059347,9dc1933c,a8453201,798a0be7,1a284c38,3e8fa5a0,f67fa80f,63586b1,6853f550,c36d8394,56718376,1c14101,dd03cbd0,b164cca1,24e8920e) +,S(f366c649,f633cd7,f1fef522,b78f7b85,3d640acd,11af2d17,14c14251,ad873107,5fc396af,38f4988d,82c4cfab,59d415ef,25b260d5,711ad546,e56fb65c,7482c6b9) +,S(aa0c4fd4,4a2e68b2,edc16eff,d2b3c29c,59b19289,1503e6e9,ad068743,fc201d06,614e3224,2fba7977,464b5c4d,b76270d0,2763aca2,54aa5b82,b5ddf8b7,ff3fee33) +,S(6c886cee,19b2cec6,91c57abb,da830e45,da4cbdcf,37484ad2,b4444948,8f2cc876,24cfcbbd,9ab4df87,87eb384,fec64e5a,a197e897,bcf2dcf5,def4b94e,afc16a1) +,S(4d600199,c33f76ee,c81d1686,f116d4e0,fbe5e4ca,df3bee43,9a81785b,c6095554,cb414cce,b769f70e,115d4321,fdfed743,2bf73dc4,9f1628e9,dad15f32,5fae614a) +,S(377dd0a0,196d59e0,e71e8472,4b65bb16,12c3caca,d2f2230a,a675a25a,5d0a4fc2,2c727e7d,8c8e27dc,a5ff7c27,b349752,1159c736,2b51f38f,e0343c74,acfeb560) +,S(9cc0cf8a,23afdf35,1bb1826f,9d900b8a,e8aa5019,8cf36552,9ca928a5,9c820f46,b572f15b,e2aac0a8,c8142c53,ea43a0a0,693e5446,5d5531f8,b068d347,f7e67256) +,S(d55dfaa6,41492b1e,981d154a,2be0441e,4cfb01ea,a51c40ea,d4a4d8ed,19fa3050,2e795dcb,408c74c2,a9898f31,523a1e72,da0c4c77,c2dd2eb,45fb2e51,8f238ac1) +,S(46bf63d7,2d113152,3075efb3,fac6c07e,e3d27e87,279724e8,46306dee,7d210fd5,771bb1f2,30fa3253,7e3b433a,2905c4a2,dc4a2e37,32e282fc,94cb2c88,33b0b199) +,S(4bcfe388,3e77c17,8c6f1826,f75e7c3b,594ef8b8,c1a9ba3a,13f00597,50ca3aad,b5562e93,9dcf4672,fa283cf5,6c05389c,ec5ea923,b47d09b6,2ddaaf54,8a1b0129) +,S(c9681af4,715e69ee,d7cce802,34bb2a49,6255ba39,1df76c57,df9747b8,d8c241db,c8b175cb,b03d5206,5f2bb846,81bdcb04,da530e81,31082e08,28c21f7e,cde038e6) +,S(9fa0a1b,56bd6ac7,f4a2671a,3b4f6ae9,bd5538bd,4c6b4101,790b16bc,c2fbc33c,27f9eabe,785c7cce,e4859959,348b4864,16056f68,6d445fb5,c08fd8b6,33129e63) +,S(15042df0,ca178aac,723e7b9,8677964f,a87203f2,bc0e1fea,a56ec6a4,73d0381e,445db657,dac86b0d,f8f9eb59,a143e75f,e271cbfd,2420b3a1,677ee3bd,8d0183f2) +,S(354f6a63,d4c1877,e0e7da3e,921db767,6b7f9dd0,eaf8b65,eb08b032,1f37e9b2,1000503b,d65b80be,eb72f480,a43efd65,2eb784d8,650bffea,5559aa2b,104ea8fc) +,S(19c36161,7a448fc0,49cd8864,d2707d6e,9e4ba74e,79ae3d8a,c11430c5,99de065c,2f9f9fd8,fd38ee81,94ef570c,1b7299ee,75742d18,1610a2fa,4dd06f30,989acff5) +,S(3739848a,d2ab8a66,b6a7a2d4,add9fa8f,5a50807b,56ce5d39,5bd4c146,7083f88e,6fd71820,611102bd,f4dd2056,92e188cd,68a5409,1036951e,6f58162c,65f0cbc9) +,S(9c22cb45,261c2336,7dce66f1,f84b84f5,2dd7e58f,8ac6dba9,50062eac,1c10aa35,ff84e3f5,8c25be72,910bead6,286dcb9f,605b0017,1996d46e,c8dbee64,52a1116) +,S(572145c8,7f311732,7ecc71e4,5e37c555,5a412785,7513fabb,d0fbdd49,6db4538e,163e63ac,5e3908da,2aed5166,c121548d,5338c6ac,4ea7550,242c7910,8a38871f) +,S(c9f07954,d8413eb5,8ef213b7,51a966c7,4c641ed9,8db8685b,d931e321,2de940ef,9e6844bc,804f3d3c,a065fe7c,b09bcecc,92cf5af3,ede9041d,792c184c,cde17fd0) +,S(ac297f46,b07c8a29,d664a24d,f05a8a51,f7b0e4aa,e8800c3,f9291a13,787f25e3,686e3b7f,78e45ad7,fd1bbca0,54a5d182,b1556c77,753c1858,75e98de8,29b66cbb) +,S(6c5913b,b383a688,390274df,121eda23,5ad55dbc,80bc198c,21897934,98b3e1b5,54b9b83a,e3649f4a,2f11ebf4,61e24a55,53e5b4b5,d0f78dc9,1c35aade,2cb9ccf1) +,S(b9926fa3,f503356b,eca59ee9,2163cbf9,846e3efd,c793db45,cf7ea8e5,af2495df,d6dd7c5,33d4e7a1,ed415c51,1fc15e05,54fd00c,100bf047,bb8f9054,42e2a512) +,S(4325d1d2,f2cabe77,fe0ac758,f6073057,cb36adcc,5357fd5a,31473ad8,74e69556,de437968,2ff6315f,8870562d,560cc48f,818c8fb5,c45ad932,ed5a7d4f,534904a9) +,S(a183e95f,fd84bfca,4afc9059,ce1c40f4,eed924dc,d1bfff11,d38a8c1,14164917,11c57610,c7ffca41,145046d,4cdf95ec,c38d695d,bef057f0,a0d01bb4,41d64b95) +,S(b340d0d9,ad6528f0,d9651414,f48fdbc2,ab7af5fd,3baa8091,84d5e881,6cd07114,85ed726a,9ecd70f7,f964dfbd,40e4b68e,ae2671a9,b6c3d384,919d040e,120dd4e1) +,S(b52daa88,35992fa4,1595f0a4,c9e075d0,b146fae3,6c0d640e,8e6f34c2,16719377,6088b139,9fa83889,a6cb5cba,d478c7a0,4f42f082,24b169df,85ec90e4,7a4ad7ad) +,S(90bbd15,42b0f88e,9f7f82bf,7c2b5fe5,f269ba36,4523a18d,5dc5709a,2ab9d8ad,c9df924a,51af344c,a71461d2,bd3743df,c6958490,caa68743,e06e7348,528fc4e5) +,S(f72ee5a8,1696194f,ed3d4603,f2c9312e,b31c54fb,438b1fd2,2788ea6a,a3aa8365,e2963d82,b6ca0f4b,8ffc1078,cd45a72d,e66f4cc,78567074,4fc1721,e50fde8a) +,S(108aeb71,5bc70525,42f5d6dd,dfd348f3,66a10f4d,d99f9298,c35a8397,e6b9fb53,8388b339,75a58e04,a0f6df47,23728986,97b8d970,ac6bd45b,49b9cf1c,3209f1ce) +,S(dc3daeed,87345ebf,824a5ff5,c7f46268,fe54c901,493e2e86,e2667fb6,ff61d5b0,b5a7e641,238e0467,196c1683,bab47f66,cf001079,932a5d56,da20f89d,d93411e5) +,S(3f96a83c,2be16120,e81e1d26,e3853ef3,a82c5f32,f8d6bef9,38179c06,4265c589,eb8d370e,797cf20f,d5a0d734,9fbd027d,630ba1fa,bafffa0f,2ea37131,6b5c64b3) +,S(27caf86c,e1f423e3,1cca2278,244fbe3,b358357f,af1b7866,1de13b96,eff5c4f3,e8f77718,647acfb4,633ddbc2,3dbdca0f,2187e24a,2f2d45a1,39bfa1b8,a2b30f61) +,S(6681cfb9,e2418786,1887f964,84819645,2d301a1c,7c082361,67a24c62,f74d04f,9c89eb3a,7849e944,2f5f521c,c08d11ef,f1ce4869,98d4d760,8dcb4a37,b815151d) +,S(6711b849,48664639,67274709,2fbbafa2,fcac45dc,1795e80e,67fb0e65,beba8da5,ca12c83f,1c8f5ed9,222d8cec,bbcaa51d,6b986a5f,60d2c118,b812b259,294cfcc6) +,S(5ee9cfd0,b1102cdb,a0fd22b0,569875c5,fdd73467,22769011,8b7843e2,b71dd94d,1dd7a4e5,bd7f9ee4,e17c518f,19b60332,60d2294,8b5f463a,ed9021de,87d7d86) +,S(586dad7b,13390be6,f3d95a46,6d0224de,d7538f1d,2d2d9785,e38a3f2a,edf4924c,c777eda5,a68a3582,1735bd33,7119e58c,bc2fb101,c995f986,7bed9786,cc2b64d0) +,S(5a752d2,fa012c7,1924b6e6,90ddc7e8,867f6ee0,ad8eed91,84f7250d,665091ec,57f2232b,32b36429,f15029fc,5789042f,ec1ace97,5f2cad27,d53ae819,47b95db6) +,S(f93cbeff,22bc577e,a9cfef22,378eb142,426372e0,7be72e60,2a8064,a53e638e,abc772bb,401bdb42,94b16670,2279e4f3,eeadb75d,57190a59,96f34237,83afe50f) +,S(8c272c9e,96130972,2efc34c3,6a6e63ac,76052cfb,856eb8cc,3dd014e9,d2608a9,9987d168,13c57162,3ba7d226,18b54003,731e3716,3495edfd,e85e927e,6e4607b3) +,S(bf78a0d6,1519542b,a54226c4,d386ddc0,38dfd84c,9f9555e2,3e187c11,4d769bc5,6094e1e4,d84ec081,e6014b59,d42959ef,e160587d,315bcfe5,5d26ec98,b1910280) +,S(5b264b76,cd092a1b,ffbab651,f42485fd,497aaa5a,e311eb28,ee1fdb99,32e65caa,944f9359,4b68d7c3,6610fdc8,85695b06,1dd84722,d5d88c84,c8c188e0,69d70d78) +,S(a2473cea,8075a0d1,33bc1459,8d147705,322f7151,274e797,4b7e042a,c082b559,64de830d,b6557b06,d9b09d79,4f6c905b,5168d32a,708484b5,d2c68a89,a2575a18) +,S(3e18d5e6,3dd0c514,4341535d,a7087bd5,f14b0708,a292350,6528a803,609efa45,6e9c71b9,7d007382,f82fd041,be53470c,26dc2f16,26a9f0a6,e1d9ff67,54288c5b) +,S(d1acdbcd,b91e6315,bce96eb0,9c229086,6a767441,4285984b,71af6156,8294dfa5,5e3b0cd8,9872375c,3f807201,73e29d3c,accb67e9,66b99452,2c9e9f88,613da5a4) +,S(3aa999e2,9344e0f2,b5ecc880,a35ecf75,25ddb028,c40f64e1,a210aeb7,d850c90d,cd2ce25c,fbe3a1be,dd2e6fcb,e9e9a881,28c454e,c7ca1951,5673aabf,a543d42b) +,S(98a2361d,7c3815cb,ecd0aa4c,8a3a6ca3,3e1b31e2,5a4b6398,146d6709,61a5017d,1f33df78,3040c13,be821395,8d78e039,516df25d,4d9d0de6,d397128a,2c09f2bc) +,S(528b9d8c,907ab870,6d7a5562,84cb69cb,ff348247,be1b7cc4,61351674,53d98d0,f91eb836,d6665778,7c6d67bb,800a1141,29700d53,194c5051,aba7ead3,ddeafabd) +,S(f1adec8d,3d1b0d20,8bda6a86,6b8cf730,f4be50e6,2c8d993a,3556c1ce,625029b6,478324aa,c3bf6182,25bfb61b,32d47956,57e4a754,e08a978f,964741d4,1bcc7224) +,S(ab2ef133,b1b115ac,41870cf8,d75d4aa0,e0181ca,742a8f10,f74d50a7,3924a099,a2c47b74,c584eeab,57949ef5,38c0af69,2f2baace,70a730a5,75629ab0,566a91ea) +,S(9d4eb41a,f6da6f83,b1d20e2b,f9370868,539a617d,111b8c72,348c9b27,e0576f85,c1c7b00d,b786c84f,a8adfe90,4353305f,73acc3c7,1c2580d7,cc5d6b33,c5f30eea) +,S(30edd57f,7b1b2c81,c886dff0,5d9e9062,a553638f,9e4311d0,18a42229,3fb916d9,6bc4774b,16d257a1,81e20b48,5acfce30,f7449e64,aa288502,d44e7c4a,44842ee7) +,S(28e3eb9d,9a2b855,65c58fc6,a492014c,f10969a7,1e81066a,41d1c574,31306583,fc653b87,80734067,e5245c,8c150ae3,59ad3c15,df4a8e7d,dc93c8fc,dfbb6c2c) +,S(cb984735,e3c842d0,a2fbe578,ff3e8263,5a3a8bb6,749d8e08,c91571a6,9aac75a3,e935a0cc,7181c3f5,3013f977,ad714af4,4c3e257b,e9936268,b481429b,7bea8367) +,S(36186672,7e8307ea,eea83b10,6850dfcd,5e4d665b,20aa37a3,ed0051ab,a40fe170,ec626ed3,2ae6dc01,f5d4c710,ce2cb349,ab27cbf2,da5d924b,e32ef8d1,707a6d) +,S(b1a40d5e,69e9f365,c2accd54,dc8267bf,4260abb2,3b503136,2183b17,4c6b7d2e,76619dab,2a7b41f5,2401ff89,4ef632eb,31eddea8,bae27c3,af04730a,3dc186ec) +,S(abd488b3,dff60a23,e83f0ccb,22620064,b32a8f35,d4c22be2,42eb1427,15660825,6eff80f2,17dae3af,96c7a463,d1848bab,fa994904,91a1105b,e1bf7f23,840b3a89) +,S(ac0cfb04,d91ceb48,2f497974,321bdb10,2a572115,73fe4598,c92510ca,4dd6aa22,6b5f6d87,4a90d0a9,658ae4a,64474d9a,3950314a,4662ade8,1c5e5605,274582d5) +,S(1fa8be0f,476c4b67,697c7541,dd1d8be,a3a0bff3,552948e6,87baf11,afc34432,c6b25084,8038461e,32961d20,181c7187,fe79df6b,8f5c5e54,96ddb5ab,80788d33) +,S(281b43c0,d3738989,a817d313,755c5f0f,f336a4d5,7e8d0ec9,b29fb425,c1f90e56,26b5070e,ba1059c9,b73e3db3,1227a6a7,68683044,7f823689,921a9bbc,bc9f4a9c) +,S(d64e69e9,54e81ec4,7446327f,55e5a82d,3b83eb46,2a92af12,f0b2694,c88f4052,aa7ed55f,284c3ca2,9be75565,f66ea54a,27a8f00d,afaff0d5,8f394797,3dc8622a) +,S(f4cdbaee,d4b01db1,f0b5b0c9,d6178235,483fb58c,5421ba54,17bbcd4f,e4e7b028,66d590eb,29d69904,deb9f48c,5a250089,b2b92447,8ea91302,1ddbab19,6c63b47) +,S(8ff94c4a,6c46e334,feca809,79d21a0,761fc1cd,1de76f4c,7243ff0a,93c9dca5,123ddc33,5f3c68e3,29f42d4f,187fdcc5,77207134,a8bb777c,2ab08dae,f149abf7) +,S(c7869b4,6e34186b,7e87c0e6,23b64fb0,efed70c4,f2af5e70,5c33ecd1,27cf267a,66295439,36620898,2f17d95d,7da2bbd7,29aefa4,69005a59,629720a7,5c11f48a) +,S(e0ea76c6,ad5dc87,bd26ba9e,25b5041b,9836f72,6eec0142,351b2431,6cce1a4,8bd724e6,632049ab,88aa620a,78922b65,6a3a4417,c8af7dbc,5a03d4b8,d4eff928) +,S(2fa63ac7,3e5f8982,36419f1f,4883f52c,e8e357d2,4b4aa7bf,c6aa7eb1,29e30159,57e1601c,d6323fa8,f5a5b314,6b5e5c44,7251db28,6f79d51,7d0b038e,b8d8c3fd) +,S(74ed4038,d4c50930,22e783fc,1bb7a671,49d00877,b202012f,6aa6d32d,c73026a1,5b74f70e,65d009e8,8cc618e4,9f7bfda6,58234f80,38e9835e,80e6fd42,6b28476f) +,S(71d6aca6,e38713dc,6ded1f93,4fdf20fa,16ce75dc,dc405148,eaefd2d8,f0025f97,b4314533,7d48dfc8,278c6c4f,b19f69d2,72ffd4d,a22dabae,dd3e60a,7067e302) +,S(28fb47f1,6e91bc9f,9a2d5720,f40297ae,ee617ec6,897044ac,8a174acc,5bed5292,d04b6961,d72472be,4fcdb605,9943c1b4,ef8e7aed,2ba7859e,bdb84a4,f8b498f7) +,S(68fcd5f5,c8655b5f,5d2fca79,59a7b32f,828c5a5d,e262f6f8,94270ee2,1f47a37a,57480650,33627166,c372bc4e,7a710275,7aa1ad4e,5460dfb6,d3d27f32,778d74ab) +,S(c7617ad2,f423abc4,7ed7f8a8,a7a6002d,17c9744d,1ac6be97,49110685,95aa36da,d9904b67,fba96cad,cbe7a9db,833c614a,69e330fc,a06ca2e8,d597f657,b7121d9d) +,S(a7ef4e9d,2396fe16,c0e78b95,5259a9d1,474fdc21,8b24e8c8,df566192,a6487cdd,d6782604,91c6be04,98c3f7e6,86f22f37,23c1e4dd,4f7655c1,f40509ef,5af67f28) +,S(f3be7846,7ff03676,4ace420f,4091bb2e,71856d18,9e24890,eab6b436,771e2578,f3027657,45cbf3e5,67a6966f,6b27ffc1,dc58f3a,6811f309,434662bb,636dbc5) +,S(5c947f95,5bd9ce29,5214c30,3ebf4f35,6c8d9e2a,4e173470,94d3f755,36f0259c,b6b7b775,3e7552a3,d2dfdf49,8578a24d,90a81d8d,68ef39c4,68fb5ca7,b75e76cc) +,S(236fd960,c3b1735e,279b8702,8c25a074,2c54c189,d1040c13,4e4cf40b,bd8b2c68,9ab59bf7,c0bac18d,d0d9360e,b79a76cd,b44bacbe,b425d181,873ac390,59bbc279) +,S(c92c9f26,17cce2f7,659d0243,8b9d8932,c1a9e9ff,ca8b0d99,cd7613b3,b1947b31,abdea94c,1a5e64eb,65e70769,51ace2b2,e4804ddf,1539d50b,725fe09b,52357a51) +,S(986087c9,142c608c,33783a12,4d22c316,733c2ae8,bc1fbd2,8bd1a142,6da94fc0,14925bf5,fd76b51d,6be82c65,4562cdf,8f5baddc,eb26c68d,3fa6113f,ab42a1cd) +,S(465a1f74,f4f6baad,7c644e21,f35650b6,22424e93,83b421bf,91478621,a48a1d43,26da71e4,179430bd,ee6698d5,7db01553,d41c147b,83247157,9f2fe923,c788cb48) +,S(dd7658cd,f28117c4,4ff3c88b,d0b46adb,c7aa2ed9,1590ca00,785cee6f,5c9796b4,32317c0d,1e10e997,a74935a,8e45d27f,9a9b8ac0,f77dcf37,c1c7b340,cfcc43be) +,S(55bd2abf,a803c49e,b4548b17,725f52fc,6222af8b,dd9aed09,715ceb87,57c72033,34ad33b3,9d7344b3,abfc603b,8dcf2a54,96b991b8,41564e35,53adfc85,3d3ebf43) +,S(77be5c06,d10c226c,8c9616d3,15b1e1c,44006876,4189fc36,db0c88a5,ec12fcde,ccf2cbca,5c474949,88f27ae1,b0361b9c,20e8b55e,d965f7f6,ec8fd9e0,429ba01b) +,S(fab72486,3eb6f261,f0460b19,bea7dbdd,80b890ee,d4bb5618,30db6af2,f52ab21c,914f03a,408a2e2e,aa9174ed,99d80e68,b67f6afa,fa9da5c1,5d22f74c,8876d0b0) +,S(232a2039,fafe8b86,50a671f8,de78314a,510db65d,5cf105a1,9db8082,2a0b2f66,14ca7082,510bc1e3,533b9f6e,e216ec13,3be3a6e2,64d2e218,d95f3ec2,ad78576a) +,S(b3482839,612a4ff7,a0584752,68f13e69,deee9fa2,894a8cfc,64e39054,1b7f58e7,722d02ed,df30025b,eb4e9fa,f7c58de1,653b8224,66b1193a,3f2fb71d,5d26ae44) +,S(d3873a57,b0a7587,cab10871,a9322712,cf6fd84a,226dd7b2,85823996,5a353210,3b7e4984,59c7e706,cdff95b1,c55e3351,f1f45d0c,c9fc11d6,60e5e27f,5160f186) +,S(8828788c,eeebb2b7,71d289a7,147c0a7a,26a049c3,26dcb281,cc9b2dba,162c20ad,e428a195,87425f22,3d798922,b4971c26,5da2fa2d,de4a364c,c8c65f48,c07b71a7) +,S(79fee531,26d0c00d,74986c18,993fa174,52f8dbb4,ea75680a,37f0b3f4,ea7e537d,fde50071,3143f994,b4d7b4a1,43ab3abd,525cebbe,93d5b5a4,560017a8,802cb5b6) +,S(f44f39f0,5a9f5f79,5f0f3a8c,e03ab50b,3672429c,bf699cba,ac1e58a8,66814e91,b95e45d1,e4de1300,950a27af,bab28bba,ff75a246,46ac70e3,fc09da30,d59a1dd4) +,S(1138e209,baf9c9b7,b89d7d78,832cf7be,da45afbf,3c2fa148,50426ec2,80aa9abb,15c28d6a,3965b2af,ea28520,7e67f2eb,ac7d5917,9672f88,3727e499,f06a0d6e) +,S(29d3e942,1b98d78c,60e4685a,aa503130,dcd3d3f1,5afc2620,472b83f9,34912c1e,90a514f8,49680969,215d46b6,db7c53b9,411c8c67,c88bace1,a6d45ca7,d2bf5825) +,S(a8a36a94,5fdd33e0,4f0c18d7,cd2d4709,d6efeb88,a53fa0c7,e90969c0,84ff3eb8,1dd7f905,edbfcd70,26aedbe,1cee1cae,23db1fcd,479f02a9,bb596af5,f56ab564) +,S(5a048ece,b3fa944f,90eab4f0,c3e7a06c,3c35f2ca,81263fd5,3670c212,6a981eff,124f1bae,b70fed65,d53caf7b,5e88077c,8e330d05,692199b2,4b3d6d4b,b7c886ff) +,S(32070282,c5ebc2f,665ee579,c645fac4,fd1eb4ec,d7297158,3dc81288,e932b8ba,8f69662d,d68407e,dafb11ee,8842707,c17eda9a,803cbd55,b86dadf2,85bdaa17) +,S(7c22865b,fb04d3f1,bb988a7b,80a49fe,c7810593,27a19786,db77a47e,57afe787,a02eb26e,30f599d7,d5599734,439f19cb,d0830b72,60e70d53,97f06e1,d036bd3b) +,S(a0ba4c13,30ad8252,c06c8269,a3dcc365,fd842e5a,aaf33a4,22de13cb,b9385cc,58ecab13,5cfdbbf7,f3b6d2ce,277b9e84,940fdb14,47568960,c13290e5,fe239bc8) +,S(42ae6042,c8a2ba5d,c8fe47a4,12e2c0cf,7be448,70e67819,4e31ec23,44f76309,72ad69ac,7ba38bf2,2210a6e7,53c64467,36ea3a23,cbc96c3c,e19f209b,dea1542e) +,S(8f3ae8b6,45507a2e,3ea5d82f,47020739,d8f35f0c,8fc11e7c,6e802d5b,87b2a19,61bb8e35,3028ed54,1b83420e,fb9b1473,60425927,d3f9b6a5,d1d2b80,ee5b4cfe) +,S(3a84ba4b,1e151920,a0e4fb4f,30953e6c,a7ba1e12,62ae44c0,d91b437,b05df32f,b20f6579,43525f14,7b23abe9,c90e1d0f,32c44eeb,cddc6ce7,d3cbad9e,7d3e20c0) +,S(6481fe6c,b04a503,3ecc102b,de462e7d,7b87d181,2bc145b6,2d25fd88,e7316210,bcc1b4ab,f5f32ad0,9176538b,808c9187,d4e88b0e,aef31075,b26e5c27,8f64560d) +,S(5340174,722c583f,af9cd365,1f73b33f,8e4bd1ca,cac0af4d,1ff13064,d551a094,e4902135,448a616d,e435180,f85d0a95,d9e4655b,aebf8a41,a3bbe221,1a66a8e) +,S(c0693eae,a5825c4d,6c24e08b,d57bc32d,6c9ee2a7,90dcb49b,b350f852,4e2867cc,da20fb4b,7627411e,5c6c601,bcb8fb55,f4f6178a,efe0ca04,62c85d86,33b9a05e) +,S(c51d0f73,72fd0502,d17f9200,ca189821,e63e581a,8356735c,a91b6e93,3cfa0d9d,8d10e6b2,7ed7edd,2cfff134,54eb979b,a2797a7d,3c6fb413,b3bad4c2,2e352655) +,S(16811856,4d2d99ae,2daf79f8,58b52ad3,3666008e,d9d2c59d,be3160df,bec3290c,2bebf1a1,45617848,e81dbac3,4522cd0b,3e9cc84a,3c08602d,1adf77ba,292e7460) +,S(7ae94933,e1438525,b2ce1622,5654aa6f,b15999a,57835a09,20a49748,7c0afeb5,91912e37,830a645a,138282a5,1e3331bd,a13b87b6,f443f901,95a2f4f5,bd9b95f5) +,S(e7792d97,d02b76ab,2414c5f6,c2d1bf0a,c27709b0,55b2c36b,179599a1,3019d4ac,9f4d9689,5fceb179,b98c75a0,d5d56cc1,dd274614,a2816e8d,16fb98e0,ed3f2b52) +,S(2ffb9d4,946fd63f,24cff64f,4ac79450,3d97d706,eea6c4f7,69d9e34d,3247bde1,66b1c74,34881531,2bd6907a,6e3608ea,cff18832,5576fa9f,f32257b7,eb81014f) +,S(4544ba32,f90ceeb1,1412aafa,b4ae7351,aeb6f4ba,12e00ea3,c165c8b1,ecbb2fbe,62fbd7b4,c2a5cee8,bfb9ede9,b02dbbfc,2bba538b,834797b3,948887cb,9f8f6736) +,S(250b01b9,25d9ffa2,75eb156d,d8c67b5e,5d981ce7,8824d37a,1b09e3e6,7918980f,ba1d924a,32f0da86,e532bcbe,6766259f,eb185161,4042c0ff,261eb81d,3e09c481) +,S(9cf30e54,1f2a5fdc,73046807,32e962ee,62e0b813,901e30f5,ecbe1fee,abeb4d2,7cb246cd,1281b77b,19601d14,baa8ff62,848259eb,6567c741,c6bd54a3,b5510723) +,S(edc9e8b1,3c61a1e0,8f93be12,495084ed,b5a90eca,4f11dc03,cd217b1a,56285a2c,66c2fd21,7e8fac7,4fd43b1b,58c80661,b0e8df85,a2fddfda,5e9f99fe,621e1f3d) +,S(dd94295f,8388a498,2aaa4164,927b81ba,cae9d002,b3ddb6b6,97082c70,f1e2c66e,838c060c,d409c1ea,9bcd9e8c,b1fac83f,3b08c2b2,482d8f4b,fd3ebc18,8d6706b) +#endif +#if WINDOW_G > 12 +,S(7e068e04,dfc0be48,e5c0d3b3,5bfc734e,96e96ddd,d0ac4876,92f74535,685ab7e,df2cd146,90d225c8,d04052e6,93f14bf,69351e08,79883646,2c88401e,4ec70d0a) +,S(73a9bfcf,d10aac9b,46e659f,76c439a0,b7c2a073,7dec217a,21f43f39,949a5052,73b91529,3ea7b052,682062c,8f86cbf,bf379df6,91a9cec2,4a1424a9,b3be10dd) +,S(efddff84,c8cc754,e6e34678,d85809bc,55cc224b,f69be05a,daa847ec,d408c55b,65dd8f41,8264aab2,efe6ed7e,c45b4ac,8aac218a,3b6713fc,1736dd6d,c2f188d5) +,S(46a94585,7118384d,8d23d6df,a4386dd9,dc264f5b,171a7585,7565688e,bfd73f4b,3de5af7e,a298c18f,4dbf16cb,38e7f617,1e684ee8,e8df2a6d,256c011a,65aaf35c) +,S(6890edb2,7ce3c265,d4afa17b,be160a94,45dd0c8c,9ad6d93b,910ea47f,3821cd3f,60f47c5b,10ef5494,cd8810a7,ca8802ab,7c24beea,eb67b852,dd22040f,77cbd1ab) +,S(8cc9eb6,340b886a,81ec4b32,87a251c1,e33e68c2,1f55688d,952b44b4,2a05f5ae,9b176b0d,90e38290,8911981a,3bc475b9,f0323870,150c9c95,5078bf02,307fb6eb) +,S(2b062f5a,da48de0b,58001cca,e96cde15,227875e0,26c94e0b,fd1fe2a,495b0475,537f1c68,3d5170c5,8097bad,4bf17276,da9de994,8eff6805,48b35390,2f1eab0d) +,S(dd55b91a,84b3d53f,4332ff7f,224e9231,cd358bdf,27f30082,52d7a8be,bb7240f9,e6f1a08,a40b6530,ed737609,4deef969,774d2173,a3ac158b,ff681908,192a5c94) +,S(ac5127e0,40b1a979,46c0cdb1,c782ee2c,8986fd80,d7151e75,16fc964a,f2c59c70,849e2249,323d0539,dda0a82e,1764593f,8afbb097,880af8e2,4765ea01,b7ae5db9) +,S(df2f2eda,f0b6ce9a,3784e9ce,1e1ddae7,9d136423,153174bf,f72212c1,b5311123,b9d98f8e,bd78bc20,316da64f,46644026,fde6ab44,162027be,dbac75f6,e86d46a5) +,S(fd83b387,d630c176,23b85e21,62113610,97bdc5f4,3fb08027,73ff93d7,a373e5f9,9a962a7d,375f35a5,9d7503d4,c0fddc9,115805bc,38438837,d3c670b6,ab6cd2ee) +,S(d8fbdfc1,155ec8ac,8bead443,ba3feaa8,d565ca1e,4206cc95,5feb8e1,32cac4df,f9453c0f,ccb99cb4,739258ed,febf7642,7fb1fcd6,1f963abc,9cb9a5ea,751f73ac) +,S(9fc9749a,20a3e8c0,1b309389,16aaf3d6,85f00872,b82350dd,c89110c0,dfbf86d6,a2f679a7,6c92ac59,5773bca7,8f0f18,75c85cba,e75a6379,1094a799,863e19df) +,S(29e0e346,71a91ce9,bdabcf25,2e2196bb,65b81092,d3728f62,b58c815f,2f476a3f,2f440c61,b82e0ae4,798a35fb,9c66b261,1ce5ad0a,ab42f9d4,174bd698,d4d0c0e6) +,S(e4068a15,398955a0,f27e6f92,9cc3dfb8,7fbee70b,a86ee78f,8736b519,ae102d7,a3f2f2ad,550f9cb6,aed99943,84a9a350,16b91143,747d4e7,7d69e698,8f165086) +,S(51b45e10,bb1bd989,8bb156c8,a4c81978,10f16364,d3d55092,48a42028,726c9f2c,e30719d0,4225de63,281ac479,70010cc0,8a1f1d51,48c57f6b,b478c95b,e3e141a2) +,S(14cd5d29,7b8ab6b5,e92ec2e6,6c63b3d,64dc492f,d5a0c5ac,f6fcbfa5,aaa0b83e,5bf307d7,7cdcc866,349ad1fa,fb1c7d8d,5be19270,2a46b327,9b72bd77,e3666805) +,S(a5a8a711,49d6d146,c32254ca,e9c18288,45e9f2df,419ed68f,8c3cddb5,d22c4da6,9f47d887,7bc3d345,af4ae693,35639bf0,b003f481,7833d2d5,49c0bbad,3cbf6c2e) +,S(359328d2,4baa4232,d75b13dd,d146624d,bda494e5,2cc778f9,99a4c0c4,1f9372cb,d31556b5,71df399e,99084afe,c8f680b,b6695d7d,648f7050,a7881acf,241af6d8) +,S(c9eb81ca,4f2a5a2c,17268a12,d901edb0,c8fdacc1,d26c5e8,91af95bd,e673e7fd,6d4a512f,c974fe9a,711ae19c,d9bfbd6b,5acb73e5,355608df,76ed2942,488adb66) +,S(e26631f8,16f3b308,ac4c9f90,eb6102e2,48e55730,24f41f38,6ccde5e6,c2ca8e2c,16e0b2a8,823aecd0,165e2f10,20518253,96cfb814,bd5a248,58a4615f,eb9306bd) +,S(f76e9af3,65c0e7e5,7807b24,269c4732,677e5af9,a3b0a965,8db8355f,f99110ba,80cbf439,d26f164e,bdaf2542,385f9d65,9d174c62,96ada102,8a0cb013,bd2a9407) +,S(dcc8145b,af891483,295d6ab6,9a88fce0,bc333d54,841e7421,e65f6270,852c5dd9,cedb3770,a620e7a9,b40d6cd1,60363bb0,296155cd,80d89480,ccac619a,f31e2a19) +,S(7645e13a,6a1c4d0f,a56a199e,cae93018,7660bc40,41edb847,ed33fad3,c603e4fd,7c8ea51b,7990e5d5,125eccbb,5da890d2,bcfc5353,b22c42ee,1864c22c,be91e713) +,S(ba26886e,d74cbcef,afe7210d,51c1b6bd,4658225d,45e20fb4,4222b318,9e2f3f25,fd885db2,23ddadee,9e65fa64,abba326d,e0b89627,7359e893,bdf50db8,a2b3409d) +,S(68b500e1,31005b1d,901bda65,4a525e80,fc6578d,5e792c92,299d21a5,19050fe1,71ef7d7a,b3544a94,f3dac8e8,77da5468,8df9b127,83e02022,7e05d5f,6b12f96b) +,S(2ccca7e2,613fa83c,27ff851f,12c6fa07,5b19f7c9,940a5064,b84ea75a,da7996ff,5ab70a22,22dd1ad0,d0db2d2f,c59390b,cf37af8f,bed4570,3c6ae0f3,27d7707f) +,S(6d797d2d,6a56a45a,1b5af718,3cb6dca4,383ad9c0,4d5cf3c1,827f4da6,f7179f14,aae34e5,d203d18d,99e84bee,7d6f5a8b,b80e541e,15a3aea6,7b162551,e80edf3f) +,S(aa6997c4,37be76b1,9553751a,d96a53e4,9a565a58,55f67b5,11605996,e98ee327,6034a421,9cdb40e0,9698a15b,2e2f5f1b,6532e277,a1f4f4cb,3cc0c33c,c684835) +,S(56c40fbf,fb8e1d70,a345d53a,7b0f897e,1e62484,dc01adea,d010c5be,ba2a0f48,e9d06789,78b9290,27ba0e09,173d8ca9,676a4a78,7e299f4c,458cb6aa,46f0bd01) +,S(db6ff6a8,3963ed7b,dc262be0,8b52c3dd,b6e1e237,2a535073,1d2903d5,17918d89,a40112fa,f30fd44,b42f6b18,c144ca0f,e248d65,d757bdc,162b7118,7d951769) +,S(8df55701,a46f63e2,338e730d,4a543013,dcdd1173,754e5de4,151ca180,63402c6d,64cf9c9a,64b63ff0,1396ddaf,b48bbf62,b3e69665,bc89ea93,b9dd12dd,57a1c3df) +,S(9d10bc2c,51018f57,407ae460,e5dd5e45,66485cce,de258af3,7bef48a0,1b0588a1,38ea3c08,b2a4e171,7edebe44,e03dfeb9,726b302e,aea0eac2,fcbc9389,84922c04) +,S(13bbc875,cc07a787,2ca7a706,8201606e,560257b,fce7e66,2e4b9807,37640367,b4cd971a,47c82a66,d8ca19ac,baaf1b1e,d2ea3daf,d6f54769,7fe474b1,c0c2c708) +,S(8f26dc37,f617b174,dc947630,d0da6dc9,1857d9a3,13c92b1e,24ec9cc9,5ea9c3e1,3848a303,1d96bf27,4e423877,6591ac44,f887f2fc,1553375b,d5cf76e0,e73f15ef) +,S(2e1e543d,f290916f,5e55236f,660dbe13,a23e0d9b,11065041,ad3a579a,4c7b5f21,885a4527,626e05da,c10cd9f3,218434b7,947bc083,28fe2d28,ff10ad2f,b5473846) +,S(c83c2ca3,e0509ea8,bb876936,e3eb69b5,8bed8f50,e8c7b85a,1238082c,ee3f3109,2b9602a9,bc808de2,b0b0da10,d09da554,74b75e75,5301cc0e,3b07c331,329cd5ed) +,S(8c7903b4,e2c114e5,3264111a,ee385311,afee8b1c,90606700,578d1fab,d3d29607,dd02dad1,964df94d,1eebea9,a2a343e8,b488c401,88299b25,28d47376,f1025731) +,S(48263c54,dd7575cc,b30adfc6,c1c1eb85,b5185786,654c89bd,a38a681d,a6569cc0,e6f107bd,dacdb528,ed98e49,a25936ea,e223ac5f,55cb7955,ddadfb88,1213167f) +,S(6a7c050a,ea7d1f58,7918644c,63cd5d98,accb7127,c54ee274,95fb2546,16f0d2d3,fad19261,27a2646e,34bf733d,c089b0ca,f80f7383,b4bb1546,28d7256e,d821e232) +,S(e1f0a53f,62fbc202,df9147dc,c31cb09f,ece879a,ccc5a3b,f105a198,7f5c3ea8,3930a10f,b0eea30,c314848,94037780,3968f692,fe2e5d8d,cfe920f1,e5706277) +,S(bc0fb113,cb0fca5b,fd66efca,e8a4c866,da9b6a0a,6d4e613b,48526675,d3182b7b,e11e725e,6993eebb,d2715f69,13ecb148,37892c56,745c601,31ca1c6c,bf090f31) +,S(1fe5a0f4,9c438f48,64bf9ebf,89eae7b7,ee7e6a1,74a134fe,266b0329,cb42f908,db8095ce,f912641c,92b3878b,cfa7b596,694514a,ce9b779b,35ad6109,c675f66c) +,S(5de3fdb4,90167002,fa6e61aa,eabfa53c,ade6ea83,3f3c8f6d,e434320a,aa524cd4,b5cbde88,862ad6ce,b344a1dd,88d1ac29,6d7e9ca3,d5e98535,dc158579,147e08f0) +,S(93b06993,a913dfcf,5eeb0be6,294a645a,b2964f2d,e2196073,8adbfcbc,23da54f,7836782f,856cb744,4187330e,fca3c7e2,9c151ad8,1e8b507c,4d14a14d,492ae0b8) +,S(705740d,27d90741,e685a044,f6b055e0,9c33369b,e3815851,886b7860,8e762f0c,c4a58fbb,738d46c6,9e93193b,529f12ac,b2142b32,1fbb3c55,d3f5dc99,173d956e) +,S(7619a000,fc485526,734a20e1,99530f0a,e5b78767,61040864,34a1a1e1,1d93e296,7f300de1,182f479c,f6fa0afe,a2ceb59,ab26f675,77203201,4f8be86d,46ebed6) +,S(fe20f5a8,ddbb5201,6cd346fc,d281413d,cc0d54b6,384e460d,bec5428a,599ff2fe,5b488ae6,e2604871,afebe551,f9957b0d,338cf47a,b4ecae0b,ae7a92b9,242d879c) +,S(995b9727,ba7e52cf,2dd29e07,73c751f9,70768121,8ab88b84,422e1e3f,42ad11e2,c3c9ddc9,7ee41468,c4ec5e5f,529bd8b8,49c8d585,f905b91f,42af5c6d,2f7fd26e) +,S(cb4f2e4d,2ca94d7c,79e91344,55161921,636d26a0,d84c2a16,e267c242,702b3136,215eb6ee,394940e6,cf00df48,f7e2b8b,1b9b2f71,7a68ee49,bbb879de,803ddb9b) +,S(ca0a2a56,34b49144,bacb1070,7668eb67,4572b69d,5e1a4e6f,c722c256,b9fce397,92079cc9,74ab2fbb,a5098c85,56ada7a7,6e2562a7,bdb5ebf,e958eb82,d3f4841b) +,S(fb82332d,c6c0c0af,d72f27a0,24ef163a,bfadde89,67b4c246,acd6b922,e3af7c7b,1a697119,f21cb690,338beaa5,2e2c4b1b,2b90d399,19ccf0c6,60dc540c,a934c7ee) +,S(d056ee05,d9258def,20e184a4,e2018bd6,d07550a0,63db4673,6afec42a,5c513dd2,af2c1d0,d222e356,67e7cfb6,201ad727,89ab0fc4,d68dc31c,276d998c,bc15bffb) +,S(3fadb222,c6584262,c4046c59,4b778635,c6325712,cd828726,7aea1253,42526f12,da5c8c07,fa6811d3,84ca7e8b,fa1d74b7,d181e0e1,eab86717,58666b7e,c199ae96) +,S(d27ac969,e222e50e,5dd915dd,39d3e453,214b818e,fb67e924,8ab4263b,1d9c4b61,c4857694,baead305,6e6709a3,28403236,9a7c55a,d81e7f6f,9b494a76,cb3a1c7f) +,S(412379b4,8b981ae6,a5fa4324,bffd69ef,99cd3a01,91a1acbc,d9340f01,72c565d4,f24036c9,c7dbe4f0,2ca523e7,ebe6ab57,c755053b,245523ab,ac9d3e87,fcfa280e) +,S(d8234eaa,99374c13,b9a8cc3b,663d00a5,bef7909f,b21243ea,ce9dfaa3,f79336f1,b8cbe8e,c4b465f6,6a3c1593,292babc,1845d8f9,1dc80e5c,b1ff904b,6e755c27) +,S(426f8b35,68c5ff9c,bac0ea34,9d8d3c00,427d323a,3d877bbe,47fbaf2a,5d189009,4e02293d,ce023c7b,9c7a1ba7,27cb82b9,9931f57f,78853bfd,7dc4399c,bd00586d) +,S(f1c706f9,2ee5f2c,2412a7fd,c9ca5c79,8717576e,c780f6cc,fe72760a,4497dfa5,c5e1a1a1,727f55c3,b3978700,51a09b84,9ef75895,d6b9c4d5,9f85cfac,2bb7e740) +,S(84e2e07e,cc1d5987,968d6682,525356b7,5982001e,67598b67,608f1869,36c2c679,41ab1343,8ab5ecdc,cbe75a8a,b7fceba5,2903f4f6,f5b43bb6,28173866,cc28555a) +,S(7935eec2,fe535823,44abb699,3a18cf6a,3d599b0b,ef0f6068,9c689b40,76ad2b54,ce2fc96a,ab978861,b6ced574,fe4f5c85,b77480ad,e3d75b40,6c4cfbd5,53371910) +,S(d542a4a8,319f6d56,b79abbef,9da3a009,3e8c2689,421e3839,27aa6a30,b0dbd9a0,5104a162,65d285ea,8f99f3e9,c1951a06,6badb70c,985877a4,f1979aec,7b8173e1) +,S(bc692619,42289890,4af0157,a038126c,41011b9,26fb232f,d3c27d9a,44ece2be,8e2f10c1,47e2a630,9372e854,3cb8ef77,11e2022e,db25f4f9,847369c7,fe52f3bc) +,S(ebe1b736,bb178c08,deacdd80,b48ab650,ae079a90,95f43e51,f4521bf5,d18d8d03,ad81c659,b1450de,45f78ef4,b2a8126b,782f2061,fc8eebbb,cd0a2ea,cddb7514) +,S(e626b908,49e1853e,4fdf887a,df8f0562,666d094a,9382be7b,de152dec,b9e2774c,90cf55da,a4192a27,caab406,2cfb8758,2dca7342,c59627c3,f513ff9,f4834ea) +,S(fba7a057,ba048792,2313b8b5,ba4514f0,d8f571c,bc7ac0b6,1a987a9c,e4381e67,7d2af7fc,142653ba,bf05133f,958a57eb,7cea5b90,ee5300f7,18cee7ae,d69ec44a) +,S(144cdb95,5b5d5181,5a2e5bdb,57033e67,239735a,456579ea,1e3be689,94c35a54,e6016f89,e896fc59,80150d2b,8135b4b,ed0a108f,8a2eaa83,91987a77,6253f1e6) +,S(538de6e,e7ab1b5e,cd74a2d1,a9599d9f,ad28cd8f,2679eb6,81c25e1f,183c0a24,36c0a747,79611193,5bdbac87,d5b38a05,2482b973,213d0960,1de8404b,14121004) +,S(76914f0f,d28f73ee,20ca3806,263b757c,7876eba7,54bef2e,9d10615a,ebc03794,6de24dca,e16855bf,22355786,1626c62c,59330752,f9f8808e,c3930680,33a12642) +,S(69915e6c,f675f7da,f595f7f9,6c912f29,86bee7bb,aa5800af,27e32baa,9e34e4a7,6094fbc0,2f109855,77b53c91,8dd2da3b,139bc31b,77674d56,df72cf22,2b9513c9) +,S(4ee6c20c,900bd4fd,be942dcf,db91182e,2c37eb35,e4287e5d,859ba847,18ce3015,84ac9769,863d618c,4b738e66,8c293d3d,42e2a9c6,4c47cf75,90ed50f3,2062cd64) +,S(a6813c1a,f57bf8a3,8ece11dc,a4c8c581,aa598211,af9ec6a,d2271796,88a0fa61,6420274d,f4e29631,5b7e2335,e98fb2f1,d415c99b,dc5a00e1,d182e809,5b8edca4) +,S(421003b7,107b2897,24dfc743,275db49e,69d91077,6ee53d6c,fdfe6ab,710fce84,cb955569,7b924395,c31cb149,88bcfea6,a932087,3aa8002a,c218f33c,76f9427f) +,S(9cb19e1,cb8c4fc,4009d362,eacf5f25,5e125298,5b546df8,fc60bdc6,48c8c522,227015d3,2c6ee68b,63e20e70,ed7cff86,8fd286e0,905bf623,1b7e894e,c7d70d12) +,S(c7413596,8193588f,38f412d6,4e2ce0cb,c4a7ac4b,75e33704,36236362,8bb953c2,7bee7fa0,1b7cc4d6,d22dd4c9,ec16b39,5e1d70f2,52778801,9ae75ef4,a908aa6b) +,S(2a8e8a05,321f4926,e8fac1ea,8a97cc64,c2f8e398,e86ecec,9dc2e676,61df22cc,63b86507,4e4fdcaa,acb60c21,c0d3f813,64f0c007,faff7780,9c81fbdb,981fae42) +,S(f3ef2e60,7d403594,48aab014,ea8e2dca,5af1d8c7,c6f66127,3552293e,d497a14d,dfcd5334,214b9f44,bc5d1d96,49d78c15,9e9ce44b,f43dbca9,c637c31d,622cccc9) +,S(6d5c41c8,169c33a5,d1111b36,1b1d6713,a9396424,bbfeb65a,80e40280,4857ead9,4c1f74c4,9f01bc2a,27a91d37,f59bde,3d674220,a521aa4a,6a0c548a,a45e84c8) +,S(5d812a61,c6a986b0,2c5982ce,34fd478d,60822322,47e07c73,488c71f4,4afff85c,37083f7b,16018fc4,25749e16,4c923484,680b1517,8bed41fd,cc8da253,ffa960b8) +,S(e01596ec,b82ff347,c3ba9710,82911855,720177a6,9efa7d5,dc6aa847,7f73093e,a674c832,849884b9,d38da5d0,6a58e4a7,a17acac1,8776577e,5547eb3b,b45b3bdd) +,S(67a5a900,313ff2e,7b32fcae,adcff7f0,ad52b960,ef6b0d0b,8344402c,9980f55,e77efddb,5e8e8865,eb807575,37c41e0c,9fdf928a,eb8b6a03,f41703c9,3c0a4a02) +,S(2b96879c,2e2d0ad8,281c1647,7de62583,53d77db3,57281c21,7df0d7c3,6466b277,dd5d3473,43bac32b,cc72408f,64a9fe7e,7e0dae06,786a7074,3cbbc846,80b62b25) +,S(ab94378d,f08748d7,2df137ae,a3e3e123,639b054b,fb726bad,825e2d9c,310367e9,5785ce24,40037d11,a8331865,c78ddaf5,7f9d769f,f2df11c9,9e3dd018,43a10f03) +,S(70782556,fd6fde3,8c93def6,ca3b6c8d,2f3fd4db,87be4985,fa3aabb0,43e7439f,7913bf65,ecf15020,cc5274b4,8eaf5351,51894bd8,fa236af,8f9b3fb8,178ebec7) +,S(3025d070,138bd507,b338c72c,1024a3f7,6b4d5e80,efcedeb3,e71a018b,77ca3942,3a8a6a0e,175eff95,a94172b5,f2a4ee53,8d503295,63a5b096,f83dd669,eb470ae) +,S(3fe372d0,65e97abb,94069e7b,2a8d01e6,576081a1,93897ac9,901a3d18,b9ab0b6,2efcee92,3154dcc0,377315e4,1d67b5a4,82403552,ce260c2d,4c1020a2,54842e5a) +,S(368c7011,3a9133ee,97ebe8f9,cc06bd7f,c3c373e0,da810164,bce5a30,2af55636,21bd40fa,4870a8e1,6f28b942,bc169712,eb7d70e5,a6faa4a1,35bf86b4,d06162a8) +,S(7df8ffd8,beb45e4e,1e440f23,ad6d713,57682f68,e54fd003,87eeac94,ecd96810,3d9e4cf9,908e5a99,44857d78,94c7ffe7,dc55550d,a07d3c9,ec07667d,982ed0df) +,S(cb6ad939,eb49c7ee,7c216262,49b11276,88269172,504fb8bb,dd2dbf7d,b6f23d4,ec8604db,18f27367,de1319c4,59f8e668,5480ca65,e1789cb3,45e0018e,ea98346d) +,S(5ae526c8,fc319e6,e054e6a7,59d9b205,d8a1e042,e684c53d,39098f28,70f4265a,da1e1281,14c25a90,cff3ef80,d5577c08,a03f4bab,d9e33850,f2488617,d50a9a63) +,S(868d7889,6ddbacc,1bbf2b10,e00456d6,17477767,5b8d3323,a8786ae7,25ff7661,d92d681d,189b0df8,e2be57ba,a9c146f6,46e6ce48,342a0ef2,96fc3093,af22ca1d) +,S(9f2f0b4d,e7b881b6,c4dd1f8a,74106a32,23bd3298,47c325a4,8341d899,d7686b74,6fbbd511,c2974af8,b5729ca6,658562f2,deca285c,b47f16e3,c444fc14,8e440088) +,S(faaf222b,813b0df1,5bf2da98,3ee2eaf6,c522f5eb,e8c08b4f,e6950376,d3fca8a3,bec53e69,2e98dac6,8fb2ae87,44f12abd,47f00e6c,5d6d1469,b2cdb41d,440b472e) +,S(7f5209b9,db4ab9fa,2c2a7ab7,6c5c62f,13c81c80,a4ec4008,fd67d229,a7161475,a13d6cda,f9e8699f,f397d1c7,6f191cd8,a58be40b,9acc4ce4,e69cea0b,4a48d193) +,S(f436156e,80b136f0,8065f395,e2700a14,50c7b492,405a0c04,6834bf4f,12c84c2a,cdd957b0,5684e01b,a760807d,39b007e8,e7aa890b,8882a0e5,9118951b,bd7e60c4) +,S(ef9aa749,5c5b37d8,2060c2bb,3454fa6,88216754,2b24d69f,201f1c31,3cf1d06e,f840da4d,f1d84a8f,ac125750,e4e6cd7c,50003aef,d1f77666,54ccf4ca,f27a4aa9) +,S(7deedc43,e96eb93a,c290809c,25e7936d,6d9e1cc8,a5971d40,b122896f,fb5de05a,e65c0e66,27b9d0e4,e7b349,ccf12fcd,de6683fb,6bc93381,22026b65,26a8e0ce) +,S(5a1bef15,6669795c,47be7495,582f361d,878384f4,f283e15c,e74b3ce,986d6459,ce985a81,1fdb02b2,9e35b97e,1833e380,69b28b81,ddf8cd61,b1179c47,2ccf39ff) +,S(d8123d39,233413c2,b14eeb78,983c6fad,73b8fdcf,84b2383b,fa453558,e525fa8e,ea9d399d,905b7200,46ff78a5,abb3cb56,835e35a3,c958095,ea226947,a633ef73) +,S(62f43dd4,f1f4c310,266a36c3,909afb5f,10d3dfd1,a7a6b5d8,93931334,e4d4bc8,bb7589f1,f83bd647,2e34fe22,53a101f2,75525829,daa2e8ef,89fa1dcb,b590f3ed) +,S(6cf371,d549c045,1415aa75,cf594d4,865f6e44,6f62df4f,cc1cf312,f79d72f7,f8ceb62b,5c979bd2,82a4ce20,682b45a0,2b3dee9d,68ce16a,7581adc5,c9e93af4) +,S(5bd7b780,770be9c3,7c1638dd,8f954086,49aeb371,516bdf3c,509efc5b,47cdd7e7,d46c7848,8a87aaf4,f606b91c,5add0c25,efc12c03,2a28b1e3,2190999,286ba9ff) +,S(c7704954,a319bd4a,e5a08665,3b959ba0,81eecd7f,f15681af,e6bf3db,c36b6a62,373543e8,24784ba8,3f53b9c6,189ccc4b,e508f600,b15c7378,36e3b3ca,516d0fe7) +,S(2b4f27fe,41533a9d,d807da70,7102c1ee,d6e92c8d,9e43958,8fedc6d0,39b19cda,98ba8310,ecd7cb1,c11fadd4,a92f4c30,49ba2180,24015d6b,89e2ad9,f81fb424) +,S(e7d4171,b3dc34d,2600c581,d6931f97,2c920c81,3d7c3db5,4d306c8a,5d4c0e5a,b29581ba,9a825387,99fa97ef,b5a6c4a3,3e75b71,d1cd51f7,5b6144f2,4a9a409a) +,S(6203022c,18f43577,5270043,56a2717f,2face761,e806e84b,2b5660d5,f1c5d52e,18a52f25,5d0a4d75,275fe97,3542b97e,212efd6,aa8864eb,6c80865,136a720d) +,S(bd81c7a2,8c1c80db,a0e327fe,3b0fccca,48987679,791e6630,e81c004,92e43b2b,ca50a84e,a14bbc64,9e0831f0,7f185536,416064ac,e93a8678,db1e2347,803871c0) +,S(9bc43e1a,d3c1390f,cd1385cd,603a6e0d,b875eb4e,6f3a554a,626a9b4,fc4bc29a,857a58bf,9aa54bb5,7acd8b34,b79717b2,64ea39bd,d8f4a22e,6b12e6a6,e0cb2cd4) +,S(3055a68d,194de3c7,9ef0117c,b98bfaa1,5e5bfb71,c656f908,2c8769cc,a7e40f33,183f9ea,dfebe1c4,bf0218cf,b6aba6bc,acbd8c72,a7fe086c,1c9233e4,340d1d10) +,S(4adbf984,ad1fd188,c9271072,43583b80,2cec1231,7d8bbe1b,71079fbb,734b08ac,14527188,9560ceff,3d950766,8e3f2d0b,2192ceb6,f79f5954,7094d5e3,d7ec04e6) +,S(38f72dcc,27e041d9,c7bae397,9cf16d22,83fc6a36,aa074b0c,d00651d1,a56487cc,5238c97c,33a106e4,1370d6f2,c0b6ffc6,49610444,2e51988d,f7160c3a,933dc0bf) +,S(de55bd8a,7bdffde0,a1413828,ac59ff2a,4560647,47c27813,322188c6,655be2d3,477861b0,df5b25f3,75f9d097,97b0afb7,67bf9d51,b996d51c,e65d3bb5,42d9da) +,S(c617bcfd,c47e02b8,918edf98,666fe912,e19340ea,6c567893,8739b89e,5e3bcc66,b90ba117,357e7683,2ae0f4e8,644cfc49,a6e04672,b5b08d47,3b826349,65117072) +,S(4655c196,1b5188c9,4b6402f1,e92b3033,c455f4db,ecadb672,4adab3bb,f1c84758,3ceecc93,a2575f4d,fb202df4,f4bc05ea,714600c0,28389b5c,f2c1c6dd,e6fbc4a0) +,S(fca90f40,dc05e5ad,3693c503,fab43da0,110df431,9c1dc4c9,e5f86e8d,d7726a45,f5822f9b,be3e6604,1af37aeb,19a70a6e,7478edec,68c8e1c3,e6cc86fc,5f5771ca) +,S(3176cc4a,dcb28258,779e88d7,f90d3b3e,a31cbe05,78c7cafb,93ff151b,d27f61e9,3863f2cc,148a0a43,c94fe7bb,afb5ab5b,6a18ce44,56cd06aa,c340c231,42cc0135) +,S(63269f73,d124210a,d070db15,14f82cc5,51d9c19c,d31a54e0,b811e650,ebb2ddc4,bf8ec7dd,8a787a42,4a74114e,5088c387,38246bc,3f6aa188,e300f0db,d85cd0ac) +,S(679a1d32,8d0f53b6,1ae7f544,541326a8,f07e749,34dd2708,dee3ce54,632003d0,83ca1348,8f21eca3,11be341d,5f6ee9a6,c9b3eb55,c9a3485c,349018a,725c350f) +,S(69a27d79,29982c84,d3948568,a54d8933,f7172f9d,e80276fb,846cf399,e0b38b28,f411d207,cb0f0bb8,574b16a1,22f39bd7,69c8b7f5,ac2db4f3,a02163e4,3bb26168) +,S(298d5057,1af5042,cbff2171,6029cef2,abfdabb9,cafebc7f,9dd56c8f,6773ee4d,f4343e71,d271844e,412e62c4,bf6dc36f,4271bda7,9ccfa220,75e3c055,aa97e9e1) +,S(3f2983da,46d1f101,8f8eb984,5bcf3930,e26f66e4,544f63b1,f8f8b979,200c4653,4973a914,c4ad33b1,36d57e6,b326d380,9b2c38bc,79d81b53,b26c5995,9d71db0) +,S(f836fd3e,30ceb88d,942d64b2,a1d2a6f9,54412ea1,ef6a3b13,59faa8bf,7e3538dd,720a3081,53476b5a,709fd29c,158b7720,c8161ee3,6e6aba3,b28e0282,cf7f9367) +,S(dd72eb9b,911e38a2,63bc8ee4,fe991fe9,295ed522,1eef930,b3ae2df2,ef583a,2a0da5a5,688bf7f9,79285d9b,360b53b2,398e86b1,43f10b86,83cb40c9,40c1b2ef) +,S(551e2650,46ab255c,c427bd81,8258b7f3,7cef92a4,496119be,283f033,4968a619,317c33d2,4cd8f35b,9b86a5ec,d1582a6e,e5ca16aa,3c6ea23b,2007a370,e7bc4f30) +,S(6683de92,131de3d0,ecb19a30,47825591,ab28cb61,5c852a90,fbd3ad78,5336c650,49eea58e,7fd95523,f8a9556e,c46fa0e4,b3c3b2c2,8e5d9e4,d636d089,282225f8) +,S(b5b3b1e2,84a6ea65,e0a9b146,e8f895e9,ca99ef3d,31a4bac7,bea49c89,3cf97805,a1720a94,f333e296,f2b91437,e19500be,3cf16cc3,547e9667,ffa4ee88,e5b6fe0d) +,S(a5019773,7c337684,9709a232,9718d463,ccdde43a,55350d10,11a2401f,9bcbf466,9cc069e,ffefc5dd,e8fa5e09,b6b751eb,c51fff8c,fbf3c27e,12efad87,a9d429e2) +,S(9ec3498f,eb2bd861,42841b66,3b1c58b2,e5cb7224,88e2f849,e1236b63,ec1588fb,e00c91a5,e14b97f0,362719bf,2150dfed,e517e585,a807333b,a000652f,c1f5f12) +,S(e10b6cb4,adc13185,750b446b,ab926667,581f97bc,5aaf04b1,f4731abe,f3c5b6b2,53a51213,7db20477,f3a87bba,5b65c01d,d5520b42,f2660ed3,c1f5fdc8,35e2b9c3) +,S(b754a967,e36ea7c7,98c93691,e02b6043,60ace927,13b18d0d,3ff61ce1,dd3ae314,8a9a3963,9aa7ee59,a42f8d5f,bab01e50,d83ee029,933cf59b,e12b82a1,5473d849) +,S(5fefcb61,c10cbf3e,6f8a51e,6bea569d,7999a275,6340ac8d,489183ff,32efa869,d81b3093,cbc4835c,1d88c093,28c20541,dfe49950,9b349207,15bbe1bf,4e881e83) +,S(fe51a3bb,4ac97e1,96009400,b27c8995,f0ed6f0a,b29b9184,70aa442f,27d2d848,8568fce0,a4c39e44,f2b8aaf,59f0b183,d306254f,83cbd6,ec5fd568,c9116a58) +,S(6a3e4629,9fccfedb,c58d5d38,aeb2a420,391df798,e447558d,7b591466,fab7dee3,1bed8fba,7bb15d9d,d42e7b5a,3ab1d9e6,89873eb9,e3161a91,aec3ee9b,22a5e548) +,S(adfdbcb8,3c40d4de,f7d62d97,e16bd32,33db304d,392492ee,7457ffc8,97450c37,7b082bdc,163549ec,2a8b588c,4156ac23,8fde7819,2e1cc195,6be85b87,f4138e0e) +,S(96850fcc,9c202c54,83654c27,2d17011,509ed7dc,6ecc6cb9,f06c3dd5,113bf61,10404432,7f966c49,af0c05da,c7ec18b5,b9fcc455,a01c3b6c,88b8b0,d281aaf7) +,S(2ae21197,8f78ca14,d88151ca,804379a7,1703f514,166f3ac4,f09409b5,5c458bbe,4de74cd9,576035fd,451c7dde,387961ce,2328e327,fa0312c8,6cbc9dc4,19ecf7b1) +,S(edc18742,e1b5c996,2661a332,cd62c426,7e5816e3,c52746cf,b79eac61,1a987e57,80003b3f,c63309bf,3f9d484f,ebabe579,29ba9032,30311bc0,2c021a34,5b4fe5e) +,S(7802aa2a,5fa0f0ae,29a90885,c8b94368,38b35d49,843765aa,1d6a640c,fe43a244,c7f329f,e63239a8,407297e0,416c49bb,7e3dda11,85baa5dd,7f5f7167,9192a803) +,S(fb774579,b124475a,c36ede71,2e3fc5aa,c2173de8,35e72386,bf67bf7f,992335cf,c0e66b51,63c17b7a,e43ebf0e,31a8d641,b6f413a6,b763ac01,cdfcbcc0,47a82c94) +,S(d81a3d8a,43abae9e,32f94881,fe9c1200,695a9c24,a31b6982,51e21b3,fcbc2852,630dd811,e8a8cb6d,7bf51de7,e0a98db5,a693e3a3,c9064dbf,2ccf6bf2,dd12673f) +,S(519fcfd4,97cf068b,804da0c7,e2268cda,7cb2eda0,4be5249f,9bf776b7,c7324cf0,bec6f4cd,198ab3eb,be691646,6e44ab9f,a357c8ec,3bca391d,c20e6ffc,9562fdb9) +,S(cc4ad3e4,8fd66073,5e193853,e0f9b1c2,3e31b284,e2770441,24f9296f,868ef592,88af158d,8583c474,7d5520ac,67b03c75,9b12151e,db25af68,996263ad,d783c27b) +,S(add950ae,6f5186a5,98b40cf9,64ded6ea,c06a57a1,4b85de33,8f709034,78d24117,c59ca4bd,2d69285c,debd6853,a0bec744,111f6dfc,7004d65b,c047bff4,a3affa7d) +,S(dc071b45,43097de7,12bc8173,cb358af,ef0437c6,7c4927dd,d0bc3f6d,bab383e4,793912a9,899b304c,173b2adf,c187dfbf,f28fcaa0,fb11b85f,9e410b40,e95ca8ed) +,S(5dce337e,6db6099d,a9c37da4,a96b7a72,fd97a672,47f6babe,94d79b1a,aec167c7,1b887fba,1f098a43,b6482991,f16ba2a0,eb35bf56,64eb21d5,7549dbd6,4e4377f6) +,S(516eb6ad,8493a662,6d22ead8,e808982,900a83f4,3e6109e5,ba284cf9,e1f5cfcb,ca350ab3,8085b46f,48d8308c,61d3f947,ef6a8511,bb36fe3c,68d30fef,ece05042) +,S(f767c150,3b1f2da1,e5b91211,4e917c87,732b3fb8,8c860a3,35af1c7c,f00e5e75,3ecef8c8,cdbe467b,888f64a2,655ddab5,9ec610e,153cd657,95bb473d,a1aaab54) +,S(f9bbebcf,f792c8c,a7bbc5d8,f177de7a,4185582c,2cc65e75,31f3ac26,73c977f0,290ab4fe,fecb3a26,256f767b,8a19e55f,ac751eaa,acecaf52,b8c99657,49614a85) +,S(c6bfe1fe,be5c8db1,f55bff42,c123df61,6ec3adbc,c9b08e8e,af477fcf,4d47c45f,c595f882,d6d6a2ff,d832eddc,95679890,41c27101,347ea995,c79ad56c,d641792f) +,S(56c2d771,808fb4c8,71dcfe6e,5170bb47,c5559521,8b872425,761829e5,e0d3ce1e,6de72ae6,9e03e626,fdca9188,9e721c61,12ec15af,7163629f,5ee0fc9f,540468ba) +,S(20218b05,ec9f5be5,87a96d8c,3c0cf7d2,da9ecffe,fc604fb5,66a3667,5109d663,2ec1a7c2,c5357e24,1f2ea0aa,7a7321ae,b41bfa3a,88b42e12,e79283bb,ef8f6993) +,S(3a089269,a04ccd9,5bfdb4f3,3494aff3,519035f4,bb3a4f09,e2afcaff,976be4ee,e5680e25,fb0ba1fe,91693757,b3404b32,bbeba22,640da757,ed91ad85,6842d1a2) +,S(8f9f2296,a0cd8b53,db0fd0f2,59860496,dfd3e101,b2975a2e,2856523a,f45b3f07,61c15907,2cacdf31,b229015c,d6290d77,8ab3be0a,57785920,a3fb5722,b5c625b5) +,S(86580be8,695bda97,cd1599b2,6d4b6328,97e2b90,d1ea106c,836f474c,fe88070e,abae68a1,7e19ac58,38a2fe5f,d07dc7ee,2bb220a8,9dba4ac6,166c51ab,b17d7d21) +,S(fb6ac38a,1e69d589,ecc5b4f0,e57aa1e5,eb1f9458,fb187d04,8c72dd29,72b4d762,d601dd16,bec271f3,16f1d3af,2b82b5cb,e5d1806f,b960014,7fb01301,86ac32c1) +,S(7c10606b,c54fea81,bf3aec94,72bb09ce,c5bb7d31,b66e27b4,242b8dbe,7ea5f0b0,12215180,d3d65643,76583987,240b445a,2ea522a,3e0250ab,d14d77db,bdf68f54) +,S(85e6ab94,833593bc,74c7822b,1d9f384a,740a5be6,3b846495,2042b017,2d52a1a6,f5c160d0,68d6f86a,8f651213,8cd28e3e,d6e69fcc,dc75f0f9,81fe5ebe,1fae93a) +,S(7e1e2d3a,99cd1ba0,51b74ea0,e5471f50,5e626aec,b880ca27,f02113ad,ff51cfe5,413ec82e,e9d4fe37,8c232229,136f1ade,c1eb96ce,c0062997,81f4b009,9dad89bc) +,S(589640ad,813735f2,ed7a08dd,6931c61d,6a9490ac,729c2bd2,928ebd01,e87aaacd,89d6b10b,8a89fb4b,3679fc33,96c4cd5,7a1e909b,e343ee15,c1a02719,20485429) +,S(7080cf4f,f3465ce8,fdcdb0ef,3741c19d,91fdd7d4,44118c5d,7b7ad040,5e6e6608,7a3f0da9,5cbc0ba0,b5c6d334,f80db1d8,3033489d,34143d34,7dfad89f,8e2441fe) +,S(bb660b4c,2d400269,2dd96bd4,d7737c31,91deb03,6553e61c,7d59a876,26917c55,b494ad13,a7560497,6068403,15e8b86f,f150af11,18dc02fa,f5ea3f40,c0983c24) +,S(73a241ec,7ebf15b2,4408161c,5d8a5c65,3f4f4fb0,8cddae0c,1e2c506d,9f221b27,80534bb4,33a0a56f,78486504,1d480d8f,64bbe192,a2f6f32b,5e1bc175,d463640a) +,S(fdc1ef51,f08bfdbc,7705741e,6a2b58bf,9e45f202,c3d7ba6f,89a15aaa,78b1fe07,7e9d00dc,dc1e4878,647ac05b,55832540,1684f714,755f4e36,880e5a0e,996c0586) +,S(204842cb,a0ce5cc1,3ab44736,ea0e33df,a15ab13a,912687bc,6d6733d3,a33618af,afc92205,a6e991cb,fad18741,818a94f2,9e1804dc,2145ba35,896f92ac,c96bd521) +,S(a03a9c1e,f82c3151,81009567,50486869,a47c4a99,83bad93e,b2bcb60,157ed768,786f9164,fb9c6980,eef3e5ee,d9a43b8b,2158ba2,dcd8663c,a26cf19f,f6090a65) +,S(5e3b6e5f,6cb41784,6355e3ff,7da813cd,fa18bd42,c54565ba,ee19b15b,dbc00ed2,b9c3a553,42bf2284,fc3b8f9f,88d3e4d9,9d6f358a,c5c8acfd,e340036c,42ee603f) +,S(19b0960e,82d1280,663dfbd6,efb2746c,abf76476,1029a54b,154385c,a05dbc70,f8b28bbc,440112a9,45f35645,135d041d,33df5ded,92116f31,2d2664f4,e5504773) +,S(1061e900,7597bafe,74b9b274,ba1a22cc,6f1c2d1d,b6be8d05,9876638,dff3677e,707ac922,dec592ec,44d7b59e,be2518a5,fe2ffff1,4cf4cfa9,8155c781,21444b21) +,S(c9184c11,60fc7d87,5439b567,69a0e501,cc0e221e,3b155f57,9a71cf1,f3030b85,880b69e3,7c04689f,d6dd30f8,75f23899,8e83e594,9fb1ee30,8c43e982,28327805) +,S(a35fb304,4dec52cd,8fc5af94,e6c26ba5,c8fa2364,2622af12,d37559ff,4374cf04,1544f375,692a3584,ac7adcb9,a3422dcf,8b360471,85326840,42dd755c,112242fd) +,S(ba8c03ad,60ffebe8,118efbe8,eb130f6a,1b2c501a,78000a8c,1b204bd1,b90929ca,e95ef729,a3f341e0,faf73211,2f7800ab,65b88d47,ae137722,f11369c6,e3aaafbe) +,S(d2ba5755,842d8a77,97fba189,f49a010a,fe08495f,5e64bba3,361d1b52,8f30ddb9,da3669b1,cad179f,784bc5f0,c3a55d60,549e72c,390b7d47,7c030bfa,53df7957) +,S(3e04eb58,7ec988b2,77b1d2b2,880ccb24,d3de1579,54ac994a,86db9ae,6c8703f2,fa412113,e6dc85d9,eeb1d650,3df96fbc,ff3c6089,cc5c207b,b98cdb4f,e728dd9c) +,S(efe5bb42,4339a49d,3e19aefa,91f466d6,60c9f120,5df91ca1,7a0da3c2,699fe7f6,98c6212f,fb39640f,cea21db2,97cf9fc5,e3576b0a,7cb4408f,f9e3e9d3,245156e9) +,S(a29442e5,a330336d,eefe6591,5c4e0ea7,bca2dc2d,9816c8a3,2bd66a4,baa0908b,a1bf8829,7320e47c,3b774c13,a6fb9e6,dc5e7789,44666311,2db427a9,dea135e6) +,S(454bccba,6f7225f6,a91f632d,1c9218b1,48e877ff,8018d371,4da8aa88,f08bb792,da0ded31,2d532b01,60a1106b,202ea0dd,8157753d,a07e0e3e,918958b7,45ec713c) +,S(3163940,32c39566,cb0631af,a2505404,56573782,e940dfce,d425834c,dcc2dca9,18c561c4,1b15b0d1,a477464c,6f4d668a,67f0895f,a55544dd,8445a8db,cfcc5fc7) +,S(54b5375f,53f07bf2,f15fced,ffc7132d,5240893a,3bce0a92,bc4fc884,49b07703,31be2b3f,a944251,e52922bd,fa2ea218,f5df11c6,d67226a7,b3f163ee,61abdee7) +,S(283ce31b,745d067,2bfb9b6a,694da3cc,de9033c4,639e8328,d2b7ee6,58b3bd,f6a948a4,d452bb56,e3dc24e7,6e81d2c9,dc1c7aa,67aab38f,f9d20044,d8c0245a) +,S(b5e74f53,117ba754,7b12419c,b0494579,48d5f831,624bb3e3,a60167f2,10e99967,5f635754,d635f9aa,a83c22e8,9f383008,3da8331f,4cfd9b5e,10d48280,718dd3e6) +,S(681e5f32,cfa33183,170dc776,fcd51daf,d587c34b,1cd27134,a856713,cbf83080,c587d8b8,d144e4dd,7b4361d9,b7fcf30a,76f646ef,fbe390e3,8f241a54,7279266a) +,S(1fba5eb7,722f289f,2521ec17,d05df56d,2f28b221,5ff8c621,b925a5fd,29f1d0c,df1140d9,97ecfd4d,fa7f287e,fcacb66a,34283b63,5b2bb7d1,524dcbe9,eb11f5ba) +,S(38bff4b0,df378b3c,ed38fc5a,733f1bce,17855b64,cc254f20,31e1300a,6a0d0a77,6d4f065d,f634296e,64c485ee,32537475,f35a5065,e73bfdc2,520dca1c,6606b1be) +,S(707013c3,59a9264b,be4050d5,27b5798f,779df8a0,77cc95ed,6e08f74e,e57de831,b9f379a0,315386c0,657b8dcc,53cd98ae,582313a7,632e4c3f,da9c9157,14ea422) +,S(ad94ed2f,70282484,e490abbb,320905ab,fc5b8c91,9de6535a,73da3f63,45642ef5,9dbe8813,a554e1f3,e98011fe,c6545216,fdf4973,6d026bd6,cb8702c2,aac88457) +,S(47b56de4,e991876a,499ad155,2443785c,fd174f87,58b881f5,4f545584,ff62612e,a140537,5855beb7,7c56117a,5f753777,383d92d2,d4912d9,86bd59a5,7cefdced) +,S(51bce64e,9291a693,1f24643a,f11f2813,f31f624d,cf336af,3cf7b48,15f431e8,8f743d9,a3012247,ee35d28,4120394f,f40c4c69,d75ae13,a063aaba,ed07e552) +,S(76287cfe,b52c5a0f,ce98e56b,49b4ebe0,83b80bee,3bc7447,a0cb9542,e7f7a43f,736b7e56,fa5744bb,d39d064a,50d98b07,e9e3399b,dc5847ff,13e33eb6,e2a7a7bc) +,S(614d739e,ad01010c,3191aaa2,c1b7771a,8dc29bcc,f1c4d55b,181acdc0,df6b8f5e,5ccd4e8f,e8607b76,c8a96c2c,5000464e,5591efdb,aaf07166,4f4db66d,c2f8085) +,S(c38444c8,ee8c35f2,b339404d,90d53ed0,35cd5889,89663808,3e2d33a,5e4e1bc9,8b4408cd,de5452eb,dc222109,287fa9ab,1d2ffc9a,16b93f44,1f4bfaf6,6ccd29f2) +,S(8a9c9649,c6016f35,d819bf02,852bfde6,56a1c197,2dbb6539,2391df7a,99c8f349,b2dcd957,be2c19fa,6c4a6030,a4cb500b,1797aa5a,339181af,dc6e974a,d769a8ed) +,S(a0f5cd1b,e4449709,25d0ea0a,6cd28d75,96292ab4,1d1766bc,ed6b3311,bea04b03,d270b1e9,291b29b0,ce045d92,3e449ce0,c8d7931a,71cf4b8,68af9594,927ff95b) +,S(a78f2336,87675987,7afbdbaf,28e2590,25c64ddc,a9543a64,709d4c11,1f3a9614,1365fac9,a5d245be,e5245b3a,b1f50d19,de34aa9a,439f5e7e,e241f042,32a6de83) +,S(3bfd37e3,ae482c5b,92baa6f5,a413a46b,af6cae30,9ee3fb51,4a9fc3e4,b391769,2d930818,34bbb0dc,66e424a0,7778c9cf,d0219c06,4dc7fd66,bdc554f0,396d1c59) +,S(92cac49a,261d23,e776ea75,7e796d2a,d426f23d,602ece5d,1b41cd71,d13881a2,8c76ec13,8e0f37c8,99a3e587,a8c0c5d8,c7a43ac8,187a35da,c0d8492e,571521c1) +,S(cf6ede0,ea7dc67,cc370894,1493567b,718944de,7a96dd6b,82940214,b56842a,e2b717d4,e939608b,7ad6128a,53dc8c52,fa070d0,f591842c,a76e8d0f,54627cb7) +,S(6204c998,ba512945,26ecb92b,bb06e218,968c8c2d,11e0435e,3dd1bf82,fa91e17a,1690a15f,e78365c9,c8fae21e,f0af2a3f,d1ed18c7,9a607939,d12d8add,94cd0ea4) +,S(a2c4fb48,cc5500e1,35268d13,a6ac2e16,d8ce0707,f2237f12,ef71affd,e4c0aa5d,3809440e,e608c897,cb7e3906,c58123ab,c403f57a,8d59b950,9e5f2d70,3c0cd839) +,S(d8af7fa1,cc303e4b,c5da36a6,d3b2e309,6acc8ec4,d73224f2,b667873d,eb656f60,9fc7f2bd,5a5533c5,dfb39f9,7045b135,5e14d81b,9edeae5d,dd4ccfff,f0c6de0d) +,S(3e9a00ad,b873291a,604e6bbd,b05304bd,3770733e,d1daf90a,864d775d,76dea0e7,deb49457,f6d1c4ef,53524e37,f19a8d77,20a5cb9b,321b4630,51f8eeb4,901ded0) +,S(bef5ae9,30aa620c,9854346a,ac1b2ac9,760ca8d5,ea189368,9de50e5,d3dc3d7f,20d80c42,f7925f59,b0212b9c,7d4041e5,5da98a3,fe373034,c0fdfad6,48dfc48f) +,S(cd4169fb,cd28d507,6c174308,8f39645a,38215e47,888a435d,5922b490,9155f67f,f9e62ca2,1a5564dd,5a65f274,356c1b68,a170dac6,4b5aa5b9,29dc2f26,35e74674) +,S(a4b691ed,34cd2624,fdda2504,797d76cd,4bd37b11,4cf3921d,538b6042,ed5a4c28,c65374b1,6781b4c1,15b0ca54,53e3397e,5c045a77,72c72d12,c336c205,d26af55d) +,S(5e4e916a,4226b788,197cf68f,aa850c0f,c2b3a615,bf9e847d,c9e55dbd,88aa4818,3f3c3ea2,5c7c52e6,5c9991f4,464f4b2f,f3395d05,3eb27280,8d984a31,b798951e) +,S(dd4782cf,f4d69f72,c951b3ad,50a4c601,f743e6ba,2194d05c,a5f474d5,eba74a7c,97a7bb5e,9854ef7c,5e3dd6ae,8628d8c2,5d3a791,d4db281d,6c7c12c8,20977b99) +,S(a1530ad5,4ab405ec,ddb94543,2669c07c,281aff41,13e4af0b,cc080991,c1adce36,f3d25221,2732842e,5dddda78,1e2aa5b1,b18550b6,fdbb968a,77444958,4a63e756) +,S(51924ef7,b438e4f0,614523f,232af64b,e5ee0d32,ad8e5323,4a2d76ca,9e64719e,87c115a8,11f94db5,6736e82b,8b644bfb,fdfe6e55,8ead8176,26858c77,128a8095) +,S(82cfee68,e137d874,107625d4,be20a9d5,6ac9055c,6b97563,a3bd5568,53fada6e,dd49aa46,c4f5c51c,72a804d7,6dee7a72,a363e978,502a5cc0,6ff67987,30733b7a) +,S(a3738876,f7f1ef44,5a1346b,36c7da6,e02b70fd,2cc3bf30,a4efd7e5,5f2e623a,6596f52b,e1ea52b2,be0de46e,5480331a,b1204d36,581b2edf,368d9611,ea04a21a) +,S(ae4ca6f7,aec818d7,2b624fd6,b2ccf24a,8d8382b3,18b0dd7d,d8203658,2980bcbc,6a7ada03,35ad7c57,1e2a29f2,554c8bbb,34815596,1aa995e9,2378c97a,dd8f1ae2) +,S(be33562b,fa9d762f,9b18d198,4dccb9c8,4d6ac894,2d8506b1,400f7dfa,89d12732,b666efb8,77c666a7,35336cc2,14e874a5,c4f5c956,903048fe,473d2e6e,9475d442) +,S(9d7da6d9,815b3db8,5303b288,8a60ff6b,f382891f,5c45ecf,37cb92da,37c74446,46c29073,72ba5be0,e61f6d73,4b413d44,df3d2c0d,89fcc1ac,5402b68d,755b12a8) +,S(39233d31,e513c2bc,c0602849,8bb7b3be,b5981fb,7c99a366,b62a9df4,3b0d4d3f,fc27857c,92e0ea4f,4d8ac3e1,c61fa774,1ec57d4b,a9affc81,f97e384d,b916dfd8) +,S(5be2d788,db90e83b,58d02dd,7b58f41a,547e6f33,a82d84b4,3f7e5143,db7768be,b8cf3a8,6b2dfa33,e71396f2,e84fb6cf,d585ef6b,9a264875,b9049f2f,6fde1026) +,S(3ff59de8,191fa14c,113600c2,5700479e,7c53a0be,3827f5d6,82f7861e,88f162ac,25d5985,6ab0b6e7,beff5f60,c279a11f,8ae4efb,5e79a4df,d815cc32,2dc77ba2) +,S(81dc9c30,ed221920,98ad9475,da00f8d8,b61a18a4,e6305b58,75f75bc1,719a256f,2970745e,5c44cb27,a6f8f9c9,869a25f8,9cccf024,4d40ffc2,ca678d28,f54682a5) +,S(ba3e1e16,579c4099,1576121b,230d4f4a,ea386943,bb7a8d24,f765a3e4,9b70e9da,a1eeb808,653cfa67,8a9d8d9c,7d30e7b1,54eb0de6,55abaabd,90f82236,32c72f4e) +,S(35ffe81,50faaee1,141f52a5,1b7d1e69,fa66d194,3b96f04c,a0589c48,83f854f8,d66a1822,e83f6dd3,fcca09b8,df1105c0,b4ad3163,6070dc9,b7dd08a8,c9366fad) +,S(398ebc22,1435f972,1c214c0a,e38b9817,8b50d7e3,e5724f68,5b950aad,60763a06,c2df549d,eb2eeab,fccd4da7,fc2c8ce9,15551b87,14903011,6825b804,80811f46) +,S(2ba27f33,e7d0a75d,1d18511a,84e5ce1e,9ca89d2a,a44fda0d,6cfa1389,ca89e96,5023684b,832375c3,8f39946c,c91ca114,45c2ac54,fcc12f19,c6bb662b,997cf4a7) +,S(4257063e,7ec51f92,4ecd485,653182eb,2b54973e,f1ff0144,65cd151e,f9e829c2,47351f41,16dd0515,11c9ab35,b69abd64,919f8b5a,812ad5d7,47c5462b,55232c1c) +,S(77e737c1,b5b3ca56,94218582,d2e56519,80da8195,88ee46eb,e3ef172d,9b4063a8,f7cb5c5,e66798ad,37c8d4f1,1cb912e3,651ae45c,4d7b07b5,e0e20c2,89d1587a) +,S(dfcbb64d,71018c1f,bdef98b8,2a4cb72d,ef027d43,47b5e8c4,4a7eec7a,34cdaa4f,dfc0cdbc,c7207588,8af379e8,751c4f09,bc2f4e58,2dca9a92,e06b0c5d,97972a23) +,S(8eb686d0,a7871e8e,32ac5256,746d7189,b39855e2,2a52ce78,ce6962ad,d355ae8a,ea8b3611,fec52837,fd0afe42,4c22c5fb,89b79675,6e8a6a5e,d71e331c,6ccc30da) +,S(d17d8713,ebaf2dd5,316703ff,8c4c20fe,ee56522d,bea7a987,85a96b1d,36cc3e54,ea70b7e8,6d7862ca,9d8a7a19,bf8941d0,e9fdb872,4e46f8b5,6821d85b,ddc10b54) +,S(7d4c77e6,ae050a1c,856d28e9,c14eeeda,249c471f,82cd6cfa,3ec037e2,30b3ba89,c5a07653,f5fbdf93,4b180f39,327d102d,900ad68c,3da1a7bc,ea773fe9,6265fe60) +,S(96381109,451e5e68,6d61d51b,3b250bcc,3721dced,de39e88,f4f50c1b,4d7ebcab,9498f419,b088ca54,7f17642b,dd6f0fe6,9f06514,a7228394,7f15d165,64801b64) +,S(7400b550,54353d73,7b2da8f2,f8f4e953,85f44e83,fda3cd20,8afaf90a,978c2ba7,9933aca3,ce503677,e2129a04,cdb1d5ca,e36bed1d,275048be,6b18aae7,fd909771) +,S(3d7b0c11,fff7bfd2,71ef5963,9f12ebd8,d1de3bc3,93b51be2,a011e4ba,66ff59f,b6397431,7f7ca0e5,ce1eb57d,8a886144,8bddb12f,75469789,b791c4cf,32404b9d) +,S(4944d9ec,7ebf7f14,e6312545,5c8dd996,45d128dd,fde3743c,5cd6f4cf,65c46328,f0655193,13baaec1,329cd408,c9d1f3d3,5c2f49d9,126c9d1f,5bf271bf,2c589996) +,S(9960432b,4764b1d0,f8607d6d,8e08b355,f37b9933,69bacb51,89ce46d2,79bdecf1,304ebb4c,921d2fa,29200ea9,ec214adf,f7e1a9f8,debab865,78fac56b,7160ebd) +,S(313f535b,63585658,fc3409cc,726b5ded,9196cc59,6331681d,9ca84aa3,bb3de4d6,e511a48a,a55fe0eb,e5f23bcf,d01ff4f1,59b049ff,8c999fb3,dd64092f,c56c9716) +,S(85c4586f,8cd36dc0,db9b9006,ef4f74ec,c99478d6,5c011bcb,3ccf034c,548ed7b2,cd6953c0,45c5d6c,dc632592,3f9b0070,144c8c5a,67639f63,a75b4d10,5b434229) +,S(968bc6d2,a7fc359d,1edb668d,b7381eeb,d489b20d,b64d651d,21d706f9,94671af8,fb0ad6a3,723d707c,c1b2f330,4e59517e,de88bcfc,b52f3ce,d0bdb7c,f0725186) +,S(2325aceb,3722e77e,e6cc7221,56ec0e87,26d343cd,cff6a420,e58c563,bf28985d,601a7f53,dd295978,f2a59683,6f3e9eec,19b9c8fd,e81bba5a,21acc8ff,878d39e1) +,S(8c6e76ab,b2313bea,dc0667f9,9aaf32a6,4b1c9335,87c31dff,5407fdd,67acd2e4,27e3b850,d422df3a,c93b19c4,229b390e,3d7bb92e,340daa46,b3f5112d,1e50c29f) +,S(e31fee31,34468d3e,4d6b2c72,8d538a14,352e7a8,8b9837af,9d8d4230,5e36748f,89b096e1,2d1948f8,937974f6,b9a101e2,37f9df3e,280d4139,e419a1b2,6d0309be) +,S(596b586e,849404b4,7c742fdd,7e5a3398,da748ab0,67ae2981,215c17d4,b0d306c6,e96c5cc5,912cc711,5e4e8f05,edadf219,2ac27760,2b2ce791,ff6e18f8,62a0a16b) +,S(200cc167,5cf500cb,a199c3b7,1195270f,d453d5a3,8313f317,71452486,15aa1c02,780aacc8,7e34429c,6445c133,49240371,1905e24e,c17de4b3,e7b79cf5,5320ce61) +,S(7e4d5432,e10e1fcf,79148f8,77a4f247,70f0e96f,81331767,dfb5e9dd,2ad2025f,35f5dbb2,6ee82837,f37f5fd7,d417982d,fa58f0ca,13e3136e,ec0b5251,63aa432a) +,S(c1ed7508,95c97e6e,7a78f800,b6eb10c0,ff21f879,352870e5,776bb7bd,9c0237b7,90723a06,8dc0aa89,9c31e89f,64ffec3d,a38e8095,97209bb1,d8b1418f,eb418fb9) +,S(e5fd4ae8,a53e809f,83d239b2,a15d8dd2,9948ddae,6956d8de,fc7ce730,b2104770,6a4dda9c,1cbb2197,208e8ebd,35f2ddbb,50c7bf5,df4c112a,de02f0de,f71c4fa2) +,S(3ce75f2,4b33bd88,7ab72cdb,42f9ecef,e3534d15,f6733f2c,a766eac1,da51f30d,9eda315b,51ddf6e2,62ce9b5d,828af559,a43eb48c,d3dc9362,13bf04cb,1a838ed7) +,S(98c04c4f,33a81cd4,e498d8ce,77edf598,527fb9a8,8e19dd34,ad8cef3b,8813391c,fd2bcd67,f853f812,f4371c46,30560957,acb4843a,8ff21949,483f0617,ff8bd3a7) +,S(50e9c88,2906cb06,cbce62f8,413ce43d,f3d2dd28,6e4141b1,fc8a079,a87bbf3,43c713b,b05f19cc,685eefb2,ba04474a,479a615a,2f3c8a9c,e1c6243c,d82fa3fb) +,S(5d41ba17,458bde3b,64faa66,3f21b76c,71bf6564,2a73e3a2,eeb8a831,43adf2d1,17effc54,b3082159,2b39e22b,7ab058f,7f64fa7,68763510,87cc445f,57b6cec5) +,S(4e332cbf,2a02593b,6e83cb8e,1d92e076,6b34cc60,646fe3e7,89d38f9d,24d5b077,50fa745c,3ab90300,95b69985,99e391e1,744ad03d,decd1955,c8b2a859,e79e1f95) +,S(1bbf629d,27ee825b,c357455e,43410507,c83cd47c,dddb53f8,34716ebb,35a2dae9,850908c1,e99753f3,4f40070e,c0bd85e5,8fb72f69,601d3709,71ffa894,3de9bb75) +,S(a9149aef,f9dbd62a,ad0cb3f5,debdcb30,23aece9b,dc79db8a,a25f5b01,b5cde650,a7bb4b46,e6db111f,468a16d0,9df686d6,ae3c148c,61d99a79,918f0bf6,b4c327bd) +,S(801009ee,185d642,19de5b40,6b21dacb,b98ffcdd,75f8037f,fc5e1721,fdb72a71,e8216609,57c7ad6c,1dd36f70,645c75f1,38283905,898650f2,daf2e5af,37e26441) +,S(c070e99a,e466f67a,b234584,66f132ec,96c6b639,3900468a,b7368a86,c0ba6770,883fabdf,358d4f56,8a56f77e,3b291fff,be6f8fcf,9c0f0171,a1544905,50769362) +,S(6be89639,cf612761,78f549a9,ed0af9a1,8e028c53,1dff79da,71c5ff1f,54109f4a,777aed7d,dd379131,26a92f38,ff9970c4,ff2dd6f1,6d766e0d,8215fdb3,9604cf14) +,S(d1fd31d4,1ce71e4a,2052e79,6dbb1a87,10094505,2b9d9009,2195afc5,9624ce8c,f357abd3,78a8029d,eaa796d9,1860e5e5,36d5f2aa,ea2bda2e,5b510949,253fded1) +,S(1c85382d,66fef14b,3cde617c,a426996,614c328a,ead99033,7aed469b,8f169d9e,58c5af1c,b236e6a8,4f58702a,b727d9a5,e2406a4d,fdbf9113,a8f895ef,78a71f9) +,S(2d8fa9ed,d5fd67b7,42e5c2d5,2c128ad7,eec32cb7,43cba12e,272edfd9,4f36b5ea,71b15f39,37eb2a09,f9533af4,bc964c32,23145340,f780731f,aa9ad1d,8f2cd37d) +,S(4f512379,d9f6c596,700d0a15,950ddbde,40ceb1c6,87030c95,4c538122,dfdbafb4,54de9b05,f864df5e,ba861980,c7dd8567,4b320afb,e0381674,c7f7c083,4248c05b) +,S(9a5f91ba,48562c21,58e60949,6d43eca3,2c69995c,ed93e834,168d22c,d9e7cd1c,9f88a3ec,c668eca2,e01b1126,6acf9c51,29bfa33e,e12f7638,2d40d2a9,b722b86b) +,S(dda30502,d417fae4,c4ccc6b6,e833b75d,d84d54fe,d58fcf0,6577dd8,52f9f610,fbb88dda,2e74641e,6d45468d,102e2a42,7f4c57a,6c7fab0c,5d4dbfc1,155469a1) +,S(8d2e9e7c,5586141d,848e50cc,631ce5f4,600dfb1,618d65e8,e88da5e3,5b26e117,989c39ec,ffd67c54,d55ab4fd,85c2a556,bb72fabc,f763c9a9,e33a1ed0,251aa86) +,S(726ce076,e6b63d6c,b071cee1,c3d1da27,10c911cd,e3d59bbf,a27a7ca9,641ee995,4e41baa0,c91ff8d3,4d2d01ac,d8ab5d36,6ea5e81,d489595,1c49622e,610af9c1) +,S(debc91fe,183503d3,fbac0dc2,c9e95062,c0d42971,ed2e97aa,27dbacd9,bea43a1a,13593715,a6fece9a,f33b2ab8,d5f26e6,6dfdf3c8,ff688100,d497a333,be2d2f11) +,S(c5394335,77914ab8,e7039e8c,472ff2d7,237c794e,d6b24f41,c585e910,f0fd4b28,2805359b,628a9c4e,7b304112,80aa2a0d,23c26cf6,9a47310d,1fc6fc54,cd26087b) +,S(9a2892fd,33c300b1,802bf1fb,e8a8faec,72b81810,4bee4e1c,c998bc79,a05f29b0,997f123b,c2fa0136,522ebc53,a5ce37cc,5538705d,f5fa8beb,b37f72ff,45186e33) +,S(d4a22cac,f224fbe,7ed7fe42,7e0bf180,1503bbbf,d73de79f,4c558104,b39a351a,8268fe97,30622e09,2a513349,548e346a,23260311,a82e860,341af6b8,3ace752b) +,S(4a4cf3ff,15adbe1d,8d414963,b0709fb9,11d4d2bb,877dc03c,77594fb,9cc11659,57c84583,36f1952a,62441810,ea64ad3,5109a30b,c39ff36f,c2dedd60,d1ced874) +,S(58c0eced,b580d530,98c836cf,42ca2648,e85e0b27,871caf44,1f69bf0c,158e1539,eaf79c49,1e1dbc94,4e63d36f,702cd1aa,92e54a09,fa11ffd7,4121783e,e842467e) +,S(b0fbd0e8,a60c7e89,38a154f3,fe586a33,26132302,7f4e416f,634cc9bf,724892bb,27ba767d,6757f40d,b54fcb50,104998ba,6dd83f93,137c3d07,9a0330c7,82a5d3c3) +,S(a94ae12a,26b0135a,125fecf3,e4ef1844,ee90c2f7,84cb4081,8c16d8c2,d992f0d3,a37447ba,665e7595,c7816a6f,6bba3d66,e046fe36,8877c95,bbc8a760,218e2050) +,S(8cbdb09b,3eb74fae,32b6c484,4f9004dc,c540e240,7305aeeb,9adbe308,8cdcbeb5,2b863a2,91f6efd2,ff07b14c,4e5a169,912df745,1b49e3b8,10e72cf4,34c932fe) +,S(3f8cfac3,b70eebe1,cc6fb89e,d508abd6,ab3131c,40d37afc,f8f39c87,34cdbac8,dbb02111,846ef25d,794b303d,b48964b5,a68b5287,b443d321,f0c493a1,2d58b65e) +,S(b61604e0,cea3e79c,12fe9a4e,1816630b,31fcaf4d,b3ac84b9,547da60,df15b25b,1aaf2bad,9ea0fa5b,56665b41,ba1264a4,317d5388,9018d92c,ea2e9d98,29b86801) +,S(eb0e7410,3c6ab38e,1c26630a,7fbd68b6,fa51bda3,64d1ca3f,7c86ef0,451327d7,dfa05017,57c4d3c1,9541c9c7,d9fb7438,45cdaacc,2ee377d4,4c36817a,e0e82e6d) +,S(636fc503,be51e64c,8dad2812,6762c04b,1fcfdd7e,4b25544f,4bcd0bf6,9556b7ae,57b83b0f,5104149,7f3b6735,a8b7d886,b633c8dd,5052d1e6,9848703a,313f4cd9) +,S(2fcc70ec,4d42235b,c6afc2bd,1d2de19c,5ba9dc65,4ea3e288,c15c7358,e52ab330,6a356018,2bfa1e22,db64cbbf,cfcdb695,35bde8e8,2519d069,39577e65,256a30ce) +,S(115006c3,8d38b8bf,db8969eb,d6bdfa95,83be81e5,bd5bc7d0,1cd10e22,7ea94b54,6043ad02,16eb3fba,9af39e83,f6e87802,3fac023a,73252780,2505a1d4,2080e08a) +,S(17d565a,15ba1c29,60ca2da8,2fe54d01,3756a986,bedc19a5,15b653f2,8db3aaf1,917bb9dd,42040b3e,4b8b05aa,b9d31252,7a633819,33534c35,f274ad7a,9bc7399c) +,S(dcc2489,88501c43,b8598f7,a3e5bca9,d2af8f8a,b482f30e,2374c6d,6b221ef2,a859757d,d5c6ec52,b1f102a6,ef00decd,cd14cab5,99f1eb0a,57864646,4f652e72) +,S(a68b2b9f,4e9430b7,cdd919db,6e808a7f,ae2cf9c3,d43cba03,d833fa8f,351f0b0f,e34b8a32,d3ad0923,8e95614d,92778021,7f45b14d,f2f9cf66,d6525bc5,94786526) +,S(2f954e5a,938e1198,5d2d11e9,ead59539,fe7e2f17,4702d3c2,3190829f,8d0e9462,b2f0d379,fa8b7d40,ba2fecc8,46a393b1,f6aaa6bf,9f89ac61,e55ab1e7,bb16dd5) +,S(223d3d13,6bca94fd,9b3fcae8,6bb2ddeb,3cc33c8d,3ccff556,fa93938c,c27ffe4f,87e19106,e317187c,c256f7dd,83d6219b,27f6cd8a,53bb4ec0,9c74ca58,51512915) +,S(5591d8e8,291161b6,43df3a3e,9b4f495c,b614432b,a0f3aabf,517834ad,9e8f7b2e,2c8d6a35,f6267e52,d9bd454e,bba4719d,30b3fe7e,c40a1416,673ef594,e6d07c2) +,S(eb2cfc4a,d15d1a14,870cbaec,b9e9aefb,4141841e,2e4e6252,c8e93751,45f29a29,78810e08,10bfd992,b7b04c79,c7650150,e62f210d,6d35cb95,5bc67215,7052e5ac) +,S(6112c3f9,9680a818,5e4b1d4c,539cc436,bdcdb47d,2e19f927,d5e3e9,eca3f74b,6e860bdd,723c8bfa,dac8f9d4,1f6ca96,f2579d7c,6a690f35,3b8da52b,98da4403) +,S(892120d8,d552d8b0,c42c23b,9a0f17c3,b9b32914,d7e31579,7b391ded,a7d58b16,e62523ac,b3c778f2,f913d1f6,4bdcc037,cc4a9496,ccf0cedf,32502316,b5cf7941) +,S(4758b456,217ad3be,2315583,963044a5,60ca4a49,168461c5,ecbd1e91,1fc4dc0a,99e4255a,4f30973f,57eec6a,1c30ac1b,bb74987b,3c4e7ca,9604878c,d9d83679) +,S(ab0422a6,9a207a87,97fa0c6f,978479af,a3b95dc7,d962e143,b99e7575,6e5629da,73398d0f,fc9855,ebc280c3,2b8dfced,84af0f70,4994edfa,7a06e2e3,a5823faa) +,S(1980432a,ccb90b14,30d0b4c3,5829374d,852cc7a6,f0a1b20,ee7ad43e,d545d227,96ae3873,bfbc8ceb,2afd1a0e,9b989bd0,69c919f8,f2e51546,7668da5b,9e8b05c5) +,S(4288137f,e2dffb3a,ca761cd7,2abbef3e,93b8a015,743d50cb,b716252e,e0e93f17,c02c333e,36c366a6,fbd855f1,4da07672,71fddb04,59e788de,456086dd,aa238825) +,S(d65fac35,5bc89da,afc4d16,aa73fa4,77e43276,e0db7d3d,52d9281a,d6b6cde2,e6f4c975,a6c5f337,b4500545,603862d3,8e9f07e4,18886b13,5678478,c007383f) +,S(7029b144,e62dd27a,4fe8b54e,1607936e,beb96784,d1b294c8,43e19978,b98f6ca7,8b10ed66,58056c6e,3a2c90c3,855444f0,9a1af347,c73dd14a,a478f2a6,7140a25c) +,S(4f2760eb,df969bdd,e80ea87d,a5da0c19,fa343e4e,44715711,50295b43,cf9183b2,43e2c17b,f3f9ef09,fa01fd39,b8f69b69,15d8625d,4daff425,d4629677,83e28167) +,S(cc996aad,db4196a8,f355f0d2,3b9fa539,b573ce57,f2ee7e52,14372615,c374a5fc,b1c40f87,18782935,c30a9cb6,6be85d11,44284bad,bfff9923,2c09f2dc,a8ef28d) +,S(c7818ad3,f3e3d905,b2c38e39,85eb7091,cd9b3285,3bdac631,3cf4303c,d54ade42,55574c4e,7bbb850b,14763fb0,fc1443cf,3403a5fd,d1f5f937,8007fbaf,94339eee) +,S(6cd03584,6fc48ebf,f4344d1f,3ae5d258,9a45dbc9,e779445e,52a75737,2589c4fd,afa85b7d,b165e371,adf67dda,8e4d1fa9,4d811c92,8d2d4723,a44e8cc8,93416e34) +,S(d652a205,f716b1ae,632b7235,91152314,f5231b92,474dcfd3,bfaebbad,443b2e0a,d2198421,b78240f7,cb82f0d8,5de03d8b,c4646a23,ec166dcb,a458a06e,b93bedcf) +,S(a807d04d,cd844a1d,f99b3e4f,e3400459,81ff0baf,d34e2d73,a6a052f8,dc52fb54,188a78bb,73939835,3bbe5079,ffbbc718,c385c047,97cfb151,af019e9f,a2e2cd9a) +,S(1efd2bbc,a5d6ad48,e93acd07,d6cb02b9,b8c3a95e,9f4cede2,24efdc17,cc9eb2d7,f951ef88,1b98c7e6,357e191a,1bb357f6,2a9d2ae,a8af1a05,63eef3,66745b39) +,S(5bc5e54,d27d3db5,982bcd04,497fe0e3,ea0ff13,7c3bdf66,6ed0b9ac,2395888f,3555bc02,d4f4eb01,661f8b85,7321b36a,5a22d975,2710375,4c1f65f2,82ec3300) +,S(f600a8d,26b08d0d,e6e2ea80,e8ad2f1e,158cca71,15be6f22,1f5b808f,746a3247,23be5a13,4bc3fa5b,7ef75b2,8e8e11ba,76c753dc,6516caa3,cd5b3ab1,8bca3523) +,S(fc7e4e0b,2ab2a7a8,cc5712a8,be590135,f5119bc3,6c73f81a,e492bd26,90ccaf7b,4bd612f4,1f274690,6ea862b8,a6dd8929,e4a682b5,aa835cdd,b31c90ab,381151a6) +,S(51325f3c,fe12d00b,fac67eec,d79b63e5,41641d58,76aa9700,bcd3b3b5,89442655,d6a894ad,7b7ae6e2,db962360,579657ff,982a35e5,91cc3b33,a4437a4b,133ef941) +,S(2db3ac27,1a55f608,f21bd2d5,717f003a,afee9a6d,b8fefa09,5626e4a,c598aec8,c526bf33,a0c01c60,c1cc9fc9,d66609f5,3c662168,b47cfdd6,e0de0c88,9bf9533e) +,S(9080772,93deb01b,5eb05b55,47de4321,35fbd436,3f391be5,1e1d205d,d5fa7dcc,fe961eac,17243337,653d318,b5c62159,64dfef84,d3cc3f23,e034c102,5ed7442d) +,S(32a1ad81,e5a64fc8,2dacc03f,6790cd4f,45557ad,3d3597cc,e2ec37bc,339ed9d6,87abcf68,18010022,7097b63c,a795cec6,79cb55d8,a9076cf3,d1371062,627cb07a) +,S(f7cba8fa,58689c51,a0f1af76,971d17a9,8c5849d,55b396e9,a3771d17,4d9246f9,f4b0aba9,10d5a9ca,eda4d733,35d5fba2,5309a0c2,fc83072c,ac37b9ec,af58ee45) +,S(cda6b104,2da900d9,d65b6b7b,c0579a43,fab75f55,ae7046d5,8ee8af82,6329ea81,70c86c0e,acfd7401,5a1171a0,1e3601e1,a8ee20e2,9ac7c0fc,68d6f1d,cd1771e3) +,S(a261a640,9c5b1ce,9a8f27b0,544ca0bd,a46f3bca,d11b7f2a,c23878f0,f67ee58b,1e26a71d,4c42dae9,b4e9cda8,fd33d725,85da67c3,52594d4,20c6e410,f3fff888) +,S(bc70c967,fd7f842c,c018e885,d1fb6d34,9435aa3c,682f6884,6b394ba6,e9f4db57,a2b99d3a,837e2de0,c40a0784,7865701,3032efc4,87c47e57,18d84e11,f8bd9468) +,S(364152f7,5dc43149,4cbfdba3,ffaf234a,c7a26567,1051e026,9c60389a,7077a9c2,ac3ac7d9,f4ec8543,3038ae4e,7ede71d5,3c8fa601,25bcd8ea,e084c32a,546d265) +,S(52fea4be,d57d5d58,d92f59d8,e4022df9,d82ca42f,a3d89326,cc36dd96,94f3043d,b7e98328,52f98a75,f738f9a3,7a67b39c,5708c608,5b6ab99b,2495428d,8c4feb35) +,S(34fee910,c8bac880,f973a096,a9ac3ffb,9c32ecc3,d2be3ce6,7b8d6822,863e1a4d,e0f01096,9c9dc446,c78db14b,122e260c,2231f6a0,971d08b2,24355620,689c7a17) +,S(6af28f0b,f4c9d2e8,192424ec,31f076f7,f815ab0,f476a4bb,4019b3bd,db49c65b,2c55fd2f,bb663b31,1a9aa346,917f6064,17d1e1dd,bca45d3,f1350feb,6ea45248) +,S(70b6ab66,39e4b41e,644f1b6b,6ac5d36f,a4f0ad81,3baec03b,8bc74f72,4d320e46,ec6409e6,4f4e4fcc,d19ad5f1,96d3cdd,96f7135d,dfcdec95,23780c18,8a913a14) +,S(ede56f11,4ab975ae,adbeff50,ff7dbbe3,614196a,138600bc,15508481,a065724d,9e7fae4c,11f421ed,26d839dc,61b0684b,71906b63,6efdd73c,2dadfc9,5336ecfc) +,S(83c34c3c,840a7310,3d819d74,66648e66,5de54af9,f1683efe,6857c3e4,556df8a4,9c238041,562dd6c0,eecd9771,9ce2eed2,90aa8137,f109840f,d31d70a4,c86cd10) +,S(aa2afc90,89b98,5228cf03,205e87a4,52cbdb45,24d377c6,1020593d,a0c7e200,3443196a,b382ac19,d3d3bc4f,a3161e00,6d812924,fe8a86af,2db5cc27,96be01f4) +,S(e42ec7dc,4310cc8b,9f2956a0,2fbf71fb,e90eb045,881ee800,e3a75730,4155c520,939ef2cf,a52d91cf,e20324bb,e8da54d9,2d000945,58abe7b6,93c2679c,d625336c) +,S(bc0bdd24,937c5200,fd78de47,a16ef9f4,181617ab,267fddd3,4a3c5606,32ec2b21,db04a4c,10b521f7,986e0e1d,192b0870,4a028511,205d7ac9,df6d2993,52b63035) +,S(dc88c9d8,9b43a733,5e310fbb,3f760e29,55c005d5,640df990,6264ebae,adadc8e7,2d6779e4,6f984794,65bfc677,79feb7b7,3fe37b32,cc23d636,25a3c8d4,fc2fc512) +,S(a7ae0d8a,b0c932c6,2ff0cb02,e05d76ef,5ee3dc50,88c57210,f6f9e349,80111c20,d632abc9,d63162c8,98b9dc94,b321de53,ac8dcc45,69233cdd,1d07da1,92e553a2) +,S(4620236e,e7bd6eab,db203af7,57da6e64,d631ac9b,a5f03215,592a5acc,5cbe0e97,5df4244f,69ea1e2a,6cf30cdf,4fae66a2,707851bc,7028d8c8,8fa97690,28627c6e) +,S(804cb84a,3d8bd930,51f50aca,cf932301,5cd35fff,349d8a38,e2bd991f,27d8f671,4b77b812,9ee0f835,96ab2f19,20362128,cdc39552,bbe6d267,bbc9a8e4,70ae8d3f) +,S(6ea5370f,5382b2f2,b801fcbe,ea463912,b4f6fb4d,e207237,8e71dbbd,b91c2ed2,f5b4f909,d8f3ff08,e92a002,f1959ec8,8b513ee2,d37825b1,a8bbe141,90b2d88d) +,S(d8b8de1c,4ff575a6,12bb0852,af61c6b3,1ee56403,b81a1f47,69fc7072,a2e22ba6,1e3c4190,d37abf89,896ad827,55c256e5,f23cbdcb,47b05892,8d538df4,e2468c0e) +,S(66ac1864,4a0bd6e,9c73f3ea,43a00d6c,80d38467,5080a9e,475c8291,edf1b147,2cc60c0f,7db6b776,1503efd,551e1a36,9be98ec6,73dab0bc,a61881cc,4fa1260e) +,S(47194a2c,4ed223e7,7663cf9,38b5a5ca,f2784435,c375d85b,ef3c5367,3f60e942,b0fde11b,5a64dc13,7bf2738c,75027d57,5808a3ce,abdf7604,5f4484c0,d3d9f920) +,S(1141c859,9af2d983,88274742,88dd768c,9fdc1b2a,c5f06290,10bd3cf4,2a4c6186,7a431f47,61ed4613,3317555a,578d0f8,5392a0d2,ba98ec64,d6b508d3,eef0226e) +,S(f905bdd8,e80afe9e,d65da689,bfb8e549,487002d6,16ac651d,4ba300c3,e7496f79,1ec7bf7f,3bfb5045,d461b03b,a7f05067,cd999fc5,f9f4c0fc,a7e25b19,77bfcf72) +,S(ba54b8e4,fba452ee,23c4faad,b14f0af8,232ea62f,ad47a3e5,573f1fac,f15e9e0,af556ae9,efcabbcd,bbd8e48a,82ac80f3,9c96ed0b,11370b8,da1bd4a0,60f5cda8) +,S(59d3ead0,561f6e24,30e87f3c,f361a2b4,1494a042,3a775e9,c08a28b4,a26a80a,9b26f47d,50a92229,c28a278d,427c7306,f5f1ba1c,c2d095d9,ac51e18f,a9bc8) +,S(2a6e5a3f,ab4cc928,d8f2924b,e7e0f3cf,15520a08,eff00f5b,129d9070,ac865d47,55c0350,58727023,86d19196,4609351c,919913de,e93800cb,38b77183,5ca625a5) +,S(898f50d1,c35bee41,88afe91,842cf659,fff1fb1c,5aaebd84,6828b002,a8907502,b2456e80,c97c2ad0,1ae02e49,6b84c02,fc9bd0f1,4a3c5a79,dafb8f8f,62f3267b) +,S(d1854ab8,b49bf0cb,1f9d2304,e9ee3cd3,bda5d9a3,ac04fbf9,422c4671,d6af85a,4e2500f,d8818180,5b16a077,53eddf34,d7bdeb02,17df7fab,d0afebe9,47155c20) +,S(861fb88a,394db6e1,f03cc787,d968ef7e,4a417df4,2856d303,a3edfc66,feaf4680,a5d7e95a,ab8b0b13,23fff11b,638ce02,68f3c38b,dbc018dd,dc6d2362,a135da6) +,S(9544f768,b9fa9dfc,3c155d90,b676cf7b,ea526903,39fc111c,b0ccf62d,813403d6,cec4d92f,cbde624f,851ed21,bbf5154b,28d87603,5e302902,53e99670,806e047f) +,S(f7722192,f80a66be,23cd7b07,89f3a094,311cd40d,3b7149ba,2cb5cca8,d1db68e9,41d0e9f,3243d64e,73e26661,cc851e5,1c11e320,277f7462,d40efe0f,c81b516e) +,S(876b4c65,1f88729b,dbf9927a,89ea91e5,b6bd8e7c,439f6fc1,be9e07ad,698e14ed,ece2cf81,1cfae9dd,cf787b88,f62f2537,7b573084,86ab84e1,6ad31ddc,f96b49da) +,S(706af4e4,62249924,88461427,8917899c,721be8f6,3353b127,b7ecb03c,7b70b10,c972d972,c65d200,e695bd29,813deb74,cdcf0ee0,e612f545,aa6506e9,7e58a5f3) +,S(ce97a218,c9c96262,b5cdde0b,a27e5f4a,4301b75b,f9d17dde,f1495b7d,f3863c9d,e9398e1a,20fd1426,88916410,d7af68f1,c12900b2,72b03f55,c5770aca,2a1ef10) +,S(fb625b9a,92cf831e,886a1f01,c2db3d53,7dae0feb,e9b3d9bc,a8fe6449,d53be895,7f783e74,ba569e04,a29d68f,12cbf223,1fe2a8c2,a651f44c,30d597de,82599a37) +,S(81ffbf69,7a7d2b8b,51b9098a,8833244a,f126c6f3,b42ddbc4,c6b2c5a5,55f4747d,e2c67357,982eefb7,3213d530,3cdaaa7d,90b4d1de,d0fd4d0a,8b002162,f006f33b) +,S(6dfc0f66,8c30ab7c,af16d4d6,309ca2ec,679d6b77,be695ba8,c0f31b55,6a0ed0e4,a41ed2b2,d9a0aa74,3182d7a6,20f441e9,36772438,bfddfd90,5aeff87d,b15a563c) +,S(1c6bf1d1,b953e56a,ba1a9b5b,f63c328,1d5715df,88bcc23f,e77f94c3,3b501b44,c667214d,b4ca1782,19c368b,f7c2ba4a,8f1e74df,91a22d3a,8e336089,e4e4b0ef) +,S(b69112df,5d999f60,5d863231,9144d2f3,5417b9f0,d1e78ba6,b2afd247,fadef93d,2163cf7a,302886e7,70fafeb,8acaddec,464f115c,89422020,9a034c63,558df4ae) +,S(bc038732,ac230f91,7c58b8fc,f9ef9229,9737a2cd,8e01687c,da464bde,4976b6e0,3392601,796373,603e1d6f,a7e23385,7a7ae0d9,df638ab3,7191c046,a25682d2) +,S(96df3295,1047ad4c,6aa4d9ae,e59bb00c,7489c20c,aded01ae,1833ebda,27e32d81,418f6c2d,74ce633c,181189bb,f5d0f066,cbfaa8f1,e6674466,1818c4ef,e2e2034b) +,S(a3c53227,939e40ab,ec6fcefd,eb6193c1,cb6a65fa,2f3501d2,63cd2fa7,6a304979,4468caa5,498ea6f1,92f29ade,37a2f667,f46798,dc600de8,cafa0ed6,dbc967e4) +,S(93fd8207,3dfd6d6d,6b85f1b3,1e172a61,7a0c7d46,b91d5a92,601af0ad,2545eb2b,601beac1,9a8a6a41,1bfca863,6acfebb3,9611559b,20b8a866,88397d47,d563a847) +,S(ba7d3bef,2e2c63f1,f9acef,2468ad8d,a5bc0d9e,b45e4a2b,ee87a0ba,86ca0a9b,ffff9a67,33129e31,10d33ed0,bc5b6bd9,376f29b1,7bbf2e09,7c6efcae,a55114dc) +,S(e0d955c0,2a4f9c35,97597258,2964d7a4,218898fa,97ef3011,1904290e,36157a8,176fdf9e,7d420bb9,a0782f0f,8707789,b28cbc69,d5a6797b,aa2bb985,1c617f0) +,S(16b2c140,8320cb93,112da689,c690d6ab,6cd226fd,e1752dcd,a444750,bff81ac9,2a2face3,dafd3932,f2617488,faa17b6e,5025f792,53c65edd,2abc7790,d98bb281) +,S(2fbb0432,9c823e2f,645d61d9,795a414e,220db4b8,eb4da0c7,fc22bc10,e9f502da,1adf66ef,15eaddfb,abbcda69,c87068ab,cbfe58e,69f58246,a0ab6259,90ebc31d) +,S(649134da,f42d2579,b6522f2f,404d6456,c178f883,8c9ddccc,e132de4e,67208ebf,4385abfc,3c554bc2,78844648,a9aea5a,e7709b51,fe644e8a,4a756c3b,f09355cb) +,S(b95544b1,dcb81f9c,e0601c17,29c7fdef,128d62b0,b8993023,dbcedf8b,d3991cd,f871fadc,ffbade32,d51f2d45,4f0726f,206fe760,93c0ab0f,33cc5383,769dcd2a) +,S(cd403bfc,5034d0c0,a23df5b4,a4b1b096,ace1ea17,288f89f,d063c0ca,5dd668de,c1296131,aa56f46f,49f59760,f3a4bf0e,3fa92e54,a5d8f160,54ee1fd4,26717742) +,S(a4aaf37,d7f8bdc9,90202074,c9a8f56a,1ad78479,95b4d939,4b6ea478,3c04c581,4cb3b6f2,dc02b61c,fd2594f9,40773d73,1a8cb9cb,388af431,9348d3,af16da34) +,S(57102ff8,ebdf048e,85edd3c5,2864578e,97478fc7,e6e7b937,6c37d9f8,abf438c4,c84f1d9b,eaec1962,e79e308c,251b2f31,915aef16,90ab5128,8331d8ee,f8161d4f) +,S(68fe98e9,3c5c5fe1,108c08c5,8fafc701,12424685,c6809774,832b0623,a3c9b6ac,492ac417,fd956b87,ee8078e2,c46f21e3,cb5ea58f,ee871cd4,d6480cf9,c4df273) +,S(d4bbb6,9ef5e23a,f0932cef,2eea4ab,d97baea2,b0893d43,ec08be40,2a4a5e77,5818e60,9c1dae31,f65e223d,f0cd08c5,9e74884c,2a2dc166,607fa4b0,47c7c98c) +,S(e9627957,a8eb8b72,7f0d872f,28acc53d,23a5c53f,763f3b5d,68c7e690,5a83192a,5da92e7d,dc291696,d9466d17,d4ca6cca,cab1057,4f5a08d6,6e59ba87,cd0d984f) +,S(49f21cad,a83bf2eb,7c508ffb,70f9fe84,1cd547f2,df83f207,6dd2382f,1711caf5,1c7d8129,5f834ed8,ac73afc2,132e6eff,2447611a,4fed8114,ca18925f,39f31931) +,S(58282a9,40f61d53,14d1d110,c18713d4,6c34a8cc,5b0ff64d,fd6d0182,aefa792e,7855e155,d3e0f2d6,52370145,7d83d7dd,2a96ee49,3eac091e,677f0a34,105f6ddd) +,S(c9c97a32,4b07027a,7b5db6f1,d70bec7d,dc3a14e7,43d492e5,f5569199,23ca118d,f601f40f,894ddfe1,c2b1e99f,7c2032b9,15d600d9,e2ec41e8,747d74c6,9664b56d) +,S(9e4dc175,8ed67501,86a7bcdd,a11f9273,9bbbe0cc,aa72862b,8d515a21,159e054e,ca11c31f,2bb866a6,be0736aa,19b7e36f,fcf4f4c8,715ebd3b,c9483813,cfc6c0ab) +,S(fd063789,3ae0030b,cd8c1e5e,8cdfbdda,8e5af1f6,268f552f,7a7f0c6b,8aafe2b5,8c09eb0b,68d744a,20468a8e,4326dc01,f4a35480,df1a0435,b2e21d53,dc8e676) +,S(37dfdf3b,6e7a7651,9ba81c3e,c1377580,d85360b5,b466ec77,b3f2b272,fd4af04e,cc3137b2,7b732758,d78f3b07,80129e77,43dcd85,ec941727,ea3b4f8e,d0fb7844) +,S(45ef106a,c8a5e25c,771a2f18,bd2be0c9,a69cb49,de16d8ff,e72a45d4,6c1dbae0,cad6a40d,742e7db7,3f7bd452,e0163490,60e5681b,31918bf4,2ad8b698,220ab158) +,S(258c52f9,88b9ca25,73cde71,472bf58,99648cdb,c1052d14,be02469c,11fdfca4,4491d88b,26ea5c7c,6a66c9e2,1a5b61fd,d60d0b8,8394cffc,359af9ec,29939dfd) +,S(bc92a4a7,727c4e36,3d0cddb9,d36f1d9,d4f8ff67,de881c83,afd51193,a9e65217,76ff6a08,b18b4795,61f1c024,d464e9c0,331c22b4,ba3779d7,9dd13122,63aa5120) +,S(8a19e8c2,58c04834,f11ceccb,c156bbe,23e4e837,fb5ff353,249c12d1,45f27ebd,15fc6c70,bff48ea2,c56caca,2b978fe1,8f50a9cb,85c19f06,5d65e507,e4e92c1a) +,S(e59b82d1,ab90344d,b113c1a7,a39968bf,e6f3b1a8,c2a44572,d9c911ea,55d70eea,91e33d8c,d58c6a1b,e4df0bc0,12eaa76f,6634d699,814b80,cc22afc8,313b91be) +,S(f994ee5f,88244cd6,bc417db7,2f941bea,f3456d2,5dacbeb3,330031b0,7371a7d0,9026f86a,ecc299b3,302bf9c0,4dae48f7,d9c2689f,42707d40,51440a05,ad9c62e2) +,S(776c4c8c,32d1fa50,27b17bc7,9803d121,8000cccd,565d95ff,c1e3a693,7800410f,40ece234,438e7738,6f8201d5,3d3e319,988b64a6,38413803,165f0bad,c8785149) +,S(393675a5,dd13b001,29caea3d,8bf25730,32c1968a,c5e02620,fb83fae5,b5c9b12e,39e6cfc4,793400ce,ed16ff4c,4b0ebcc3,2e5dc773,4e742dc0,3784a69f,a75a8b00) +,S(d7cdd294,22edc7b6,2cdde130,e90be1fc,94dcfdf2,7bf38eaa,2f09fa8c,c3401b1e,dcb9cb28,73cd18b,b74ca141,dc79eb46,728bdd9,8bf14302,db5c7065,354fb184) +,S(bce3f127,2726449e,3f620671,824949d1,9026137a,9885a1b9,9cb67dcf,6e56bc2c,a4240017,ee92dda4,be968f04,ad125ad,1c33c37d,c52a497d,296d5786,e6e76217) +,S(9df098cd,efe9414a,79adaf44,21e35faf,70080137,74399eb9,738dee97,ff5d6e52,6bf9235f,ef36943c,d0f17bb8,6917d97,f04bf4b4,dbef1baf,3b788eba,51abf15d) +,S(9958582e,e561dc4a,9a4839a8,292713a0,5d88ab4,72222522,e8dcc94d,b3d43f1d,e0958a14,b63af23e,86f76cba,2259b37a,850008b3,43b5cdc7,8cb4e88d,68c226a) +,S(3e7fb8ce,7d7b279e,7d292447,c88c048b,dda93379,5233a871,bad933c4,6dfb1f24,4279d08,34108239,2d77a5dd,906ba4be,e36352aa,9385f09d,2296ecad,648806e5) +,S(1cd05450,f7405a11,cec93ee,7826cf58,97611d69,fcb681c7,1ac0a6a3,75e8ed62,85bbc70,bb52b040,d620a3a0,20b9536e,5759d35c,9931936b,39a203b,af34d0f0) +,S(5047776,32145a3d,f6f87bd0,1b81032f,93cf99ca,fb4c5e3,c76adbf7,d7c9b367,7badf59,919c7771,89eb97ce,6c71f418,a0e67b23,884cbf7a,1ed60804,57d1d2c3) +,S(1ea912c9,49b64ba8,309b8d87,ad1498a4,79fd302b,f7f2f0be,636f7a0e,4470e6ea,9b279fdd,b1211de,8414896d,3502ae8d,4acd50e6,cf83ab4d,29086d0,42b7650) +,S(9b3fa0d3,4b00076b,cb4e0b00,95f03c4b,e1ed329b,d2f4c7ac,8c03028f,21a01628,10117a48,b2a58ef5,2e0d5dcb,cec661f,8cef81d5,50efdf41,26e9527c,27d420de) +,S(65fef7b8,1d39dc4,b3ac7f7f,5bad14c3,6200d128,d0257e22,ff678fc0,824c94eb,3021e1ee,680c4fc2,77373b9b,36ef276e,f2dcd6ec,7a02b2fe,3259af09,2708b475) +,S(3e77b23d,af763a55,644c0f2,bc2bef5b,6ef5e1bb,8fdedd46,c5a2917f,7f85f9ac,55b278e9,5bb07879,9c7f0766,a2db2c79,8d4fc785,10fd021b,415b3e4c,2a4f3221) +,S(2ac4dabf,2fec922b,c4615fba,1cd7d352,f69fbf8a,3232f783,96f8c08b,21de2965,2c33c017,76238bcf,2be6018,7f85a518,6d649425,1eff089f,a92f3eac,219f957f) +,S(febc8a20,67da04d0,855feac7,42b2cebb,748be0f1,97e31558,68d54285,4d62c66e,aee39287,3d45e63f,f9a9d583,e105a771,e3db346d,a262bbd1,a554a8d2,65d96083) +,S(a41174b4,a5982751,88c2d10b,d5c5401a,2654202,dc4e38d3,e1c8f689,8606a569,bc6b63b9,9fb5f85e,c6965337,e82b651d,6b589f2f,8d90f67e,3bd087e9,1f732a00) +,S(122196cf,5d10a3af,3bb97fc6,d12f749a,907c194d,3caf2ae9,3a3a464e,5a5de220,ccf46742,b3c1e213,544e2c7c,59423fdd,674697c5,d405b2b9,46fc6e92,9304e533) +,S(77bad5cb,104dcc7,e1bbfaa0,8c867761,9f93ec61,e8e3b73e,799b663c,2e1eadb3,889747b,ad8bdebf,48e1214d,df2522ed,4023fd8c,5ef08fea,411e8609,c6faa3cc) +,S(1e8d4075,8c49ad41,6ad45163,73327e6e,4e3f6c89,695e15d2,f5517ebb,12d4a98b,1d16ccb0,730a619,c9b379a2,ecbc4f83,98d94aa0,d4881cd1,25968160,e3b09f4) +,S(c87a656b,240241dd,487f4974,afb5b535,880ff2ac,f4a028cf,b1869fa5,fbb6ee42,16f25f3a,6fac9538,5ed74412,fa6a790d,34f694a8,b4c99cb7,6ddaff70,be757beb) +,S(96b01407,482c6e88,e9769944,cce16a05,669adf16,e7393b80,71fbd9c2,4b55a4eb,b32be280,590384f0,e08d68de,38688018,82b786e2,1b178ca4,578bfffb,94b50223) +,S(120f68b3,739562e6,81e72fb7,46d08f54,b2afd162,22e1deff,7ebbf884,6dae4af5,7c1eb74f,2b2376f9,477c6729,bd90e14d,2f4da9d,615c8743,dedc1690,300bcc78) +,S(e64871ec,2789b455,8608be2c,f248fee8,49a4411d,285c0989,b65c5dc4,e6acd157,2980b2d1,4999b0b5,5b79ecfd,45ef91fe,f3dbfae5,d02f2145,84376294,58e10a6b) +,S(608b1009,b20d3e2c,25324adf,c73e5c86,43daa1e2,53a8d266,eb43863,aa6798ad,826e5a03,ad5c9638,51181c68,ccf0e663,a021e13c,43efc38b,3b4fe2c8,8d0e13df) +,S(8c978155,8132e45f,60a61435,36f4c1a8,cdc4dc2b,6850b3e5,7c65f841,a1bb152a,ca3b3098,394d81ef,a9083c5,3864f194,1875d63d,9c31b44b,a6ed4137,db7460fc) +,S(353591a,c73b2482,f8d8e731,ce01106f,10072757,68210627,f80c8f8d,9821bf3e,2b7e3d1a,501ab469,ac6306db,2608eab,70ae8981,9f44bdf9,d4f84c7b,41eb6412) +,S(eb2dfd88,ec357372,ece70a67,178fce32,3c387b7d,a9fda978,b05dc430,9cd78857,6f2bb6ed,1f5a5521,c441a8cf,9852372e,3dd7aa7f,ca0a1f63,18c47ef1,a24b88e4) +,S(a41c0ff6,5db1050e,6998f3b0,7eef66dc,abd72ae9,8672c487,b29ff732,992eb279,56fa7b20,5616ff9d,f619d7f8,65210727,bc0786eb,2aacc244,ba951eee,99a99cd4) +,S(8e748b35,f5bb1500,ca45917e,859df11,615d85ad,861bcea9,41524e57,a2217e92,55413362,e226c6a7,84bf8604,3973bc50,825515a3,96cfe66c,9ef75e3e,fca46df8) +,S(a83f6007,cce70624,73cde2c7,b7ec7bfe,bc506c27,ccce7708,f35d535c,26dd17e5,ad48ed2d,af217e5c,63397a37,9d50d615,5a1ac614,887a2cbb,26c3b74c,626af268) +,S(f9ed7a92,7e451624,9380246e,bfd397de,5cf208dd,b47573ab,f118afed,1282d2fa,c1574616,3a6f30f7,80d5d53c,670d380f,3c84407,b4be5324,87bbb5d,c8237b70) +,S(a2bde78a,175ec7a6,7f917707,8f09f812,c7dff012,46c5255a,f0112672,6c2ea08e,7125698f,e82d4c0b,6d7d2741,9dc503f9,3b5dd62a,a5db9e20,b091323d,c9ca12ec) +,S(ca8c05c7,9dcb6736,905cc0e9,b8e1690b,6b37da42,e1875a56,e62ea231,bf9899b2,504c51ca,1e19adba,66560c1e,3fba9caa,2751259d,71389996,41d0f19f,1487534c) +,S(fc106ee,61db13ac,4137ecdd,15018278,61fd4b21,c979f97c,617b019,54eca02b,6da55a28,4fc26638,2afce9c2,cdc5a2c2,971f2cd7,5c92f08e,6bc99651,7bbef3ee) +,S(2cb21839,f47b1068,5419a321,7ac7846f,504f674b,c2f8f90b,8b9b6a71,6492a8ab,1feb332,ae75044a,f6807feb,965e2fc8,63726433,45a97af,f1081249,f00a5757) +,S(678c50ee,759c07ff,fca2963e,fba55edb,56ba3572,79970224,5d4f2132,5561f3ae,1989b787,abbf04c1,c93afce2,d389e1f9,780b1657,daa77107,c498bff4,aecba96c) +,S(ab63e1ce,aa2e34d9,8215097c,30b2f266,75d407ca,41f3dda4,1b21c910,824aa6fc,ec65be61,1150ff72,715d3da2,c4541ad6,812eb7e5,7d0f4d82,4792556a,6ce2363c) +,S(a69399ca,fad59597,5a639a2a,31264983,ec567279,b052bcc9,f5c919ae,903dd336,b525c659,c30c4f4d,a7a799dc,c93ae348,1c87304b,63491755,1c43e12e,c50d97dd) +,S(32bf4282,507bcf5e,d25cb5ed,439c82d0,bd7a48af,d3be41fb,e13753bd,c0fc5f3e,cd92017a,4336d9fd,25682f90,be347e82,6773c598,1e80033a,c20bb695,e79bff2) +,S(a1fcc983,7e720096,7203e2cc,11450716,f2fe6484,f681b2ec,5e42e9b8,eedfd862,1e16b6c3,17e8fb89,dfffa79a,722de49e,a419affd,bc17fa96,4ba6c316,31ed4fd7) +,S(d85a314e,69617e50,18df1e82,21cf738b,60485cf3,3abe8838,472b32b9,7f0ceae0,71a0ffee,e92dde66,66b4b5da,a88a79b4,fbbcbacf,3308a4e8,6e1aa367,e00a52f1) +,S(189226fa,688c70e,415b20e3,1356eac2,f5a53b5e,8043e24e,4ee03faa,f20c2e7f,d9bfd8ac,40c7d53e,7bcbe575,9987cf62,fc2bba7f,952e4eaa,1a0587de,f1515aa6) +,S(d3542e0a,6a931162,d7a674e6,32cf2135,32465d25,4d2d9241,ff70709a,559e1330,25e8f51,e2664234,34cbe5ed,622bbd83,dbd42784,4b1f2bf,9a079917,4b57c369) +,S(514d9e86,fb2cb612,1ec6e6b8,25875856,9a8c0a5a,adbfe45f,2876be18,753a2bc5,700785c0,be5423c4,341918d9,f65f79d9,1b8370bc,48629791,45ca8418,57cbf261) +,S(c9f86365,12e9ccfd,e1f1db33,5ae606ab,43f9aa62,2d723f6a,d6d684a3,ea3fe495,30d3a631,3868a01c,9c6f9445,ddcbe3b9,b7b80b58,f31f5db3,a3b3beb2,1e30270b) +,S(226f20c,8fc089fe,98cd96f,a0e790db,641200a7,2b908768,357d206f,2c2deb93,2e23fbb8,b43e9362,3fc2045,24b43da9,5e02626f,ee180cff,1c03b95a,aa5f66bc) +,S(a1b27668,d4b6f94c,7219bd9e,6b8a7e61,9fcc79fd,88d9bda0,a38496b6,cb5350bd,3933fc5e,b6e1c16a,e7aa62bc,200fd5ed,c96b5f74,b72b9b94,2644f32d,d6d68a32) +,S(10f13657,87bc31,1f7b7181,808eb0b,57dd4e7c,1590dae3,8c40df7e,afe28887,1a52e487,9bdc3ec,4e6c570d,91d4edce,291338b4,a79a3995,db5c6e85,e3366d84) +,S(8aaa0ee,a984f583,f9f55861,500dc5ec,f613b3d8,8f989884,273e1841,cdbe3e46,52962154,f85277d,c02c46ab,c2f246ed,24e56458,156d97b8,f2197d22,a133260d) +,S(32805a71,24b1b7,9b397ce5,f7a93a98,dc9472ef,a5b8b4aa,3bd66643,f1c89d2e,af525c7c,b7c139f5,cd2d0a85,82a74ed6,9e23c765,c0b882a2,f4d50e58,843091fd) +,S(c72f10cc,909ad449,7fb0835a,4f3a520d,58db0c2,87f6ab12,cde50749,a9412451,a5666e7d,5197ba9e,37d5ff15,b64b60f3,b8e2ca32,67467030,a7a112d6,f2c7c65a) +,S(6ec768c7,870211b2,415a74ad,c203bd41,72c0fa5a,d4c05f97,c0320865,77fc9a22,18394a22,aa2dbb0,925e6710,549c8c3,b51cbf42,db67d4d0,5da260ce,af1b09fb) +,S(de36ebbb,ff99d156,60506143,87045fc9,a846e7d0,eef91e61,dc93a71c,3ca64737,c5817652,f3cb37b,40647dcd,a476c4e0,488208ba,1b4d0c81,b39a4b4e,900f4270) +,S(f534155d,5538fc68,5ac01ef8,6dea6f4c,19bea322,b46a297b,c0c20ab7,3cc00218,4fab7df2,979d98ca,eeeb38a4,9a2d1253,f9d0924f,14dda603,d3d5706,b3b9523c) +,S(dafdb850,a1db9025,80ecb98,155b687c,8db2088,d0dab521,bc7fcc1,3286129d,43965ffc,ae6c4c14,3febe601,f36fbbd2,7d0ccc50,60ffe91a,a2ef2fef,651ada22) +,S(ac9a0a21,1dcabc85,1816893e,e33cc69e,2efe4069,680b3721,2999f9f4,99d705ce,16ebfe40,8281d2bd,ffa1e02c,2d00d712,acf64eb1,39f5ba88,79c3971b,98c728ef) +,S(afb37bd4,b48cf6e9,5e1eb8b9,7b8b69fd,31ae2b2f,3b7aceb,1db81ebe,98503030,1ccf4164,f8d9cdd9,6f231af3,e5fa313d,c47c06de,ce44dd84,d3fcdb16,a4b7929) +,S(1b902ef,6c294f83,3ab18e7f,21d6470c,f553682d,2b1287d5,1a602925,3888e709,7735c5ff,34e49fe7,2385e9fe,40d66a4c,66ca0102,46c724aa,24b1ecee,dcd69ebe) +,S(6e4e5b10,8a202958,7c5b4ec3,d33220fc,c61b41c5,8c3bf0b2,55e4e28b,7c3133e2,b49f8306,5c336af4,469ea410,648915a4,b55ae504,6cea2f66,f14a99d,9a8fcfbe) +,S(87ce3f7f,bb800210,5b853276,d3931b9,12342d98,7d81e80b,5b10d1ab,1b7e9714,56c6a847,79dbf39c,293c386,9c1e3385,6b71f898,dd46ee16,d1e1973a,4cf0f635) +,S(8724329b,b7ba649c,9c019372,45a1e946,d368a706,2747dd0c,9f6667aa,c9426b2d,44458e8,48d7d44b,5dba5a5b,b0fa0479,55b109d5,21d170d8,9d090ff9,650b944c) +,S(b91befa6,4735c091,32db18b6,b64d7d7f,c6338dcc,cec845cd,7d297f62,b6a1a4bc,bb3961ef,8c9b79c6,867f16cf,be4766a0,15e7ca0c,8f9f340b,14cf701d,e0138467) +,S(4321ea59,332e97ea,3bcfbb89,68a3489c,9ae3d6b8,65cd696c,d8de3200,a0d08fb3,97e480d4,c5149d53,d7582e3f,c73a35ea,3f6b023,5ce50f7e,e31cb600,84cd538e) +,S(dc4597b2,836d96a6,431051d2,5a98d421,7950a8d5,e88c2069,5752ca6,f6f1bc6d,c712580d,16ba30ca,e84e3a83,c35725ab,362bb4fd,e4c42ad7,f9b73f20,53df36ff) +,S(ce644ef0,85ff3009,b261750,8de007bb,c5f19b65,2d9f8992,9972d39c,159a009,9a41d0,58db965,baa00c92,f6409ab0,c9402a69,20a66c17,c089906c,d73cc8f7) +,S(ba1e35c,b6c7b4ba,b81aecf4,23cb8ef2,2ec439c2,584682b4,a7444e01,9936b41a,f3b3c652,f91dde46,3e178d6f,7b17a8e4,1098b33,1cead28a,d2fce694,35bd6272) +,S(b9f98ea0,2a331bbf,60fc839f,845d8f43,6988c747,1902d14d,72ed1360,86e3920f,9fb2501,a7f23a16,cc726f5e,8aa17c12,35d9b04f,a94bb27d,318fb292,c60d03d3) +,S(70591746,55f90f81,c478e702,ffcff930,dc10dbf1,16d7aed0,9c1a369e,807e886f,8267a0a4,b9d6f0ca,db1ec92,560aa3f7,d09d3f41,d1f36f8c,64b95509,b205a59f) +,S(efda78bc,c43ca063,a7b6469f,84012161,14cc5a6e,4e31c31e,b76221ac,c25434bf,7b436ff6,ef45f859,f521b13,53193d13,4cdf8064,449af2aa,92be3781,56fa2864) +,S(229a4b0f,5d62095e,3a630988,c8056aeb,35fbd874,1a2f0e,4306d094,750ccc34,170d33af,491c74e3,d2d694ce,f6a519bc,741acf35,dc6a3428,8bea3595,e234de6e) +,S(c770f48e,20a02132,189d44b8,3acd0f93,f91860b4,81a6bf17,8ce8e2ec,6af07100,7e1120d3,8b2a191f,9ed43aca,3325beae,a6d8dbbf,7e0bf8c9,610f8621,c0266eec) +,S(a5db2c63,3901d52,8b60a48a,20b189a9,e89b8998,3d424af8,eb74869a,f286aa44,b9961d92,6a93d5b0,1a74e6ab,d9c37eed,384e186,8051ba14,46fe1a37,24af1e50) +,S(3ec7169e,9f330288,a63897b7,c168db9a,4b447e48,cea2c5ff,77b298,da41db1c,c3fe974d,e8e60eda,22c4aa34,ed34a4d6,4b3be268,12e58b49,e4477835,f3053fb2) +,S(b733de17,c3311184,d5860d4c,f99e48eb,810cff93,ce92eb77,7cf2c114,fb5bf3b3,c75c0dd,72d20ad3,2000d537,ebb61571,57fc4ace,9f26a90a,d28e1a43,480c11b0) +,S(57d6e208,d555bc24,15d49616,a158075c,27db59e,6a821df2,8b450161,6c2ed278,83870a79,d130da5a,3528e353,353b34f6,74b5d02e,6cf2a891,fca34c6c,3746eba8) +,S(9e4234f1,aa69a478,3bf2fd3c,3208f6f2,6f069409,fdb2faab,8d792588,6ad3673d,5f9a4773,7725ebc3,e8bed041,47a05841,9fb42b16,affec29b,d753733e,288d0653) +,S(6fe3ff9d,9fc12ffd,bd896202,fd8ae913,22e4fcf2,76068a75,8d43f1f3,9ab68173,ef0d5682,1d414608,273ef7b5,9208c59,bf94e16,3e7faa3c,2ab3da22,b509fa1b) +,S(2c31e54f,d2586e19,efaaf415,e54cb499,54c49257,d11b161f,ff2aae5b,b45c4631,bedfb0ad,364ab1ac,e7f53c0e,9fb825e4,39af354,1a70708b,d8e0e423,13311346) +,S(51597259,23148c3,478ea2ee,2b933858,4d745b89,49c2f782,3b8660e7,78203ebc,329f6153,f688b743,c4fdc470,25790503,b81ff7ce,5a613362,8a59f3bf,66aa1817) +,S(188b3324,58f7d7b8,dc3fcb3b,df51ccfa,d394684,cde37d60,70d41e46,cdcaf1f4,4dea5da,d112a117,31a6b04c,8999c6a8,3d1ddec2,88aaf104,487656a4,d3901910) +,S(92058e41,a503e158,8ceb0a49,4e13e2a8,85f804cf,7f13c90e,307372d5,cfa6e471,368072d4,449e685e,17e5a230,e2177e95,bcbe177a,58cd1510,68e7255d,84ec108a) +,S(6a6f5226,44e06506,f27a7a68,96eac537,726f79e8,9e83105d,5b647883,34099fcf,cf3edd4b,d8ced83e,b167b664,574987f4,7104e79a,5a4b5321,4c19a32d,a5132586) +,S(7e37cea2,340cdcc3,ca21e0ef,ad548f37,c77c3402,34f0148d,89cf926f,2376bb26,c72d829b,42a27c6a,b062938e,5cbc22a,6b02d42b,d31cb69e,83b9fe9a,cc9a0016) +,S(1e6c2069,cf0f6cf7,bafb4b39,bc97a8dc,800d010c,52c3cc5a,d848fb82,d8d0b667,c181e76,bca1d846,86ecfbdc,2cb09140,49146986,630b7e81,f86c7238,8e60196f) +,S(5566600f,e6eea4f7,b06336c8,d44b47ea,f36ba43c,ca404be3,5203ef5b,6f07e16,6bbbd08f,7adc1979,ed4acb4c,f372eda,69e5ac16,7695a78b,5a7fe1ce,1057e55) +,S(435c634d,ed451c5c,21c5adc,45d94f8c,69045016,d529ba76,19ad07d9,31c791b5,31ede268,8252a50f,2206f959,1953c0ca,85009876,2b6f6c14,24b4e47,c74d4cc1) +,S(6fb8cce6,a66071c7,395c0612,252a414d,f19a0d2a,f855e7e9,dd142342,9c57b9b6,17f94249,e2f05314,d4799fad,68232626,183dadee,abfe34c5,b845d89f,2768e052) +,S(866f3e99,20fc4c94,9496a695,f54ee634,11c711a2,99e05890,148de8c3,2980dc36,e99c55af,4f8dc3c1,d38a11e1,3c00db2d,f5211f02,e837909b,ae188786,d18d62f7) +,S(80c13410,b7164899,a724f723,4dcbe505,62404f0b,7c027c79,4616f618,80468b2d,8631942e,71a01e4f,d7b59281,9dc69d39,bd6e8fe1,c2c41621,6d8df895,280b91aa) +,S(8f85bdee,ef4e9d88,53e68be,c17bb6ec,bf37abc0,a4ba44d2,c3815dc1,82a7da99,36d45bdf,8ae9342c,af0f8ce7,8aa591a3,4e8c295e,49ee6962,b4a9fb7e,ee17897e) +,S(9cd0b2b,3393cda6,ccedaf4,ee8a1b3,17a920e4,826da2aa,4404a01a,49600749,3831d35a,51d9650b,b1901e34,8f0c4ea2,3a00c492,a4960463,414e5dee,aafc5a5a) +,S(a0c5f1af,15c67ffd,6cf832f7,974c779a,3ab7ca,dffa32d3,bdbe0377,d49f33b0,6aff40d4,42de6262,41734412,3620c5ff,3079392b,b8843c57,80029682,1cb91ec) +,S(af396f40,13e217,d7e1fbf0,2ec4039e,c0111370,37cb2d78,90a82313,58edfacc,aaaeb9e2,5a57534a,2dc35d16,705f0e5d,6754c599,e85864bc,936e94f5,9acfb936) +,S(fdac3c57,e3e0ecc5,e7e871b0,dbe35979,87d4c071,f2f89307,cf1e71c4,91ed0eaf,3028a0cc,a22ef096,73c877af,ccfe36d6,b14d14ff,5da10b18,cdee6068,3ca09fc7) +,S(e3aeb123,9587baa9,ae12b6a9,68efaedc,ae745fd6,aac5103e,14a471d9,eefa88b7,7ed1c786,52c1544b,e306833f,bb27d1a5,7b460305,a2c8f6cd,2d33397b,caf769c7) +,S(96baede3,382a0162,fb4cc663,c91acb94,eb83d7a,3e3e0a0e,6055a50c,d78352f5,78722e97,b3ad2824,388c3a80,fb930089,5100d61,ea58f997,2adae059,f0c50cbc) +,S(68704956,16975637,f35e1eda,4db546fe,ba93d122,446a3e40,8de04ee2,3bf5f5b5,6247d2fe,b5f7471f,3a06c7a2,4c4261a,934bd226,772405ff,46e361bc,614ca494) +,S(71ccc634,2ca1f858,8ae02d72,eb0dd2b3,62eaf652,f83edad7,94095e09,f4bcf749,487aebd9,23b10e69,4a8e3f22,2703e5a1,aee17794,42a96c68,6cb9f983,dd2a45fb) +,S(6fda1dd0,65739a2e,58cd183,1e8b6109,713844ba,f249cdff,25d0b3ec,f635d3f0,a2ee44f4,8afccb72,4f8a96c3,2a88a8b0,a232a93d,553713df,60a965f5,2078108e) +,S(d3f27709,ff5ad97b,45e395c1,39947115,65cbfcf5,838e7b64,b1016cc6,d5147f45,f96cac16,cdc8e1c3,54e026ed,29bbd6c7,29006ee1,51d9d61a,4391567,93265077) +,S(27ba1944,a28a6eff,78a7d064,bb8292c6,68f82793,8e2be786,41ee366e,a4a011d6,24bef875,9d216430,e7312fc9,458f0571,fcbe305d,574694d0,a77f7a98,4e7bdcab) +,S(fd37b812,5fd87ce0,82fca9ff,7872e0e9,772f4c44,1870748e,e35e7d00,944fe190,9450a525,d9ae198d,db9b8c43,fb337df2,8ec68a44,60106951,1847b9a0,27dcb453) +,S(d9967cca,92583e0d,8d329b63,f32a8017,4467518a,595d8b80,2c24cc8a,8e071c69,6aca3673,c2c39d69,3bc86dbb,92e5af27,28361cd3,2179eab9,7ed64ae9,73376c25) +,S(8ee82d3c,4a8d01eb,d22798ef,bfd95c16,f53cd45f,e3d044f,3d89ed40,b94a0a3c,e0b0ab7e,9167fb9d,aa71c3a,fd5b9c0b,79c8b6a0,db3ae2f0,36c626c7,791e1b2d) +,S(461ec3d2,817cb549,a9fea029,15029707,8d709ccd,bf22da47,64c8a1db,c562caa,661b2d7d,cb5c9790,510f6e12,61650401,26cdf80d,b086259a,db16af47,af6684af) +,S(3155885c,935caed,469bb7ff,b53ff6b8,59f51780,f3de5890,673101bd,41f5793e,603594e9,92ac108f,8d0bbdfe,8f3576e,8ca6ac2,69c7581e,28d434ce,2043dfff) +,S(5cac93b0,ad9199c1,906267a0,ad8874e4,c68a60a2,b9fb6f0d,cad42758,2a4ea9eb,836faa98,a116dab9,69961fe7,ad7483eb,c48e7295,37e6634a,e423b99,880032ab) +,S(1fb6d3ac,afd5ef56,8b6eea1c,4a8f0179,54d05274,24487904,7e3ec56c,6956cc42,b8ef91f2,f89e4f32,6df6a1ec,50c6362,7431be48,1183c839,3133dafd,2e2a5411) +,S(89c0b1e1,52f0005d,a30618f0,3fdee7b3,69fe0157,f7bb2bdc,d31fc773,d82b28f2,61d6e357,bbf46816,acd05de5,b26c67b5,ad8223d8,ac9f47a9,25477ab1,80b4a507) +,S(7c5d18b,1f9d1afc,d663875a,34193240,7cb968be,f31d751,807ab1b,b79a211e,45fbe7ea,985bda0f,bd23b449,5d4e945f,d136b5b1,296c9b3b,6dcb9c37,bc779ff3) +,S(c827cfc1,9393108c,9b31ad4d,b5eb7f00,b6afdad3,a5e2f792,ddf9dd13,f159f85c,5c5fe07a,3025d401,54fe12fc,89951e2c,330ea3d,d6335a12,9c31aaa6,753a1cb1) +,S(6347b32b,b1f3f7dc,205e2fa4,6b201b4,2e0dfa80,550741e6,57117875,57cc5d9b,f8f30e10,9508d34c,a48d7255,3f8ac26d,a455d3f3,b170ee52,e22be1a3,ae8c3ba4) +,S(d489f595,e822101d,5f6e4283,7db032ae,bfa21f3a,94998130,e0a1d226,67ae1014,8b112e89,8dc4a146,8f64c33d,1261f8c9,2bfa98df,eb9500c2,2b4a66d9,227c66a9) +,S(90cb9c63,fb4afbce,adeb8f98,1e76a645,2200d73,d43bc0b2,76f058dc,b8a6205b,894afdc0,f6ba7f1a,bbaf19c6,720471d8,2611a77b,5bf6c87b,a02324ce,52e74645) +,S(40df68bb,19f121f4,e566a1be,f0a98954,869bb06c,699e818b,bc49a795,6a196af4,70d41c09,d0cedf7c,31c9f830,3610f6b6,e1d6b3d2,a431e69d,a31bdd63,220cec90) +,S(4936fd74,a0ac5045,91c962b6,431f17fc,a888dd1e,b35549d7,8b41143a,83da41bf,33a8e1dd,6517853e,d7c68af8,5b3f1cf5,3fc5b72b,5dd0f392,c5ab5ff2,1bff4f92) +,S(17177538,811075b8,f5baad59,2958074b,c1a0c6e7,b2a3f594,288e82b0,da023557,583d4814,efd8742c,5e7a0c5f,734da121,b163fe28,239a8775,4bbb072,c1b10837) +,S(a126b7fb,ad5145ea,b414c82d,8f21f208,6abb118f,3692bab,586770cf,4f8926a2,79b4ac17,b601b4d2,1a2bfdb7,41f7fec2,88d46594,699e4394,452cb2d1,ae2ec669) +,S(51eccf61,f8840048,d55de51,2d865a52,3485db8d,869844fd,ba30e703,ae871163,594ad253,97bdc9f0,82c0c46a,200ea090,12b2c6a9,57a53dce,e87caed3,2ea8d50f) +,S(97781633,6f1b7131,f55966cc,a79d25af,d8984438,8b516882,5105ba3b,52b3c7a9,f1df3541,b4b08fe0,cdda20e0,a5275eb6,105011ee,f4355516,e47e89d9,3b214c60) +,S(8bc2c43a,72248dab,5c78cf6d,b1a35ce8,64231d3a,870bbf01,cdb79be0,2c93f7fe,d52e2e76,173e9dbf,9e8106a,ffbb9d7b,b428f07,80269b2e,f49bbe0e,14cbb425) +,S(59ed7881,6c7ca119,ca4abd03,34b90b37,6c327175,e899e0d9,79953e50,5aef9f2,239fc027,690c0feb,e4db46a2,8669e0da,20779425,34bc6133,152a606a,16449910) +,S(bec399d1,76714995,d4192390,72a39c59,c8ff8e9a,2cab6520,ca0cf6b,2fc70fda,ffc4bdef,7831208d,23a1ab9a,de52f346,a21a2f7c,efc5ffbf,70999bfd,ad0ba8e7) +,S(93bd25ee,f4cef1db,fa5f9951,7d22a77d,9e3b87db,58c63076,68a35885,9e0c4d34,dd7d1412,97361b84,9a43b1f9,4f89970d,fa008c63,3404860,794e6a87,6735b4dc) +,S(b203a657,fb4e4d51,158b2e70,87455a57,44e553c5,bdea4f8e,3e8e6c92,eddcf58,98246948,c63e182,61f0d4c7,543fba7b,c74ae5a7,a19afa6a,ac80359,5ed8c99c) +,S(af38b53c,1dcd27b5,8118a28d,11da8aaa,3e20ac21,4cff64e7,be683dd,80f6aa69,91e38936,ba8b2b42,34686723,7a3fac67,5ec10179,18f8ac16,acdc32f9,c09fd919) +,S(55e4da5b,b99d805,e2058756,20ab4cee,988ed472,f5e6d86,2f8c574f,6bfd8518,7368be34,75179d32,e15b5976,c34c366e,e7713b25,8f179309,40b16117,aceb2d35) +,S(d3d7e82a,a7ebe240,83e1a15e,1d817d91,a3608c6d,d25a35d9,183a0c9,e42133f5,a5245cc,e89537c6,895080b0,6c5e2772,4b1c6d69,6c1bfbfc,ae6a7d4f,fc5d504b) +,S(8bd14f9f,e6b54437,9761e803,1dcc9907,beab754b,68c6c3f2,2316e5a6,6ee48799,f89dc150,a3876257,51663a26,35633868,ecb2eb27,d9ae8603,89110aff,6978fe19) +,S(b1d72365,3f50f42,cfeb0858,972a5a22,3a7dbc5b,4823704,85c88fd2,22212932,40597dd8,594ee1f9,b74aa52d,385b21dd,6279864e,7d0255,70bf3716,c02143ac) +,S(44d303e1,cb7d920c,93be4763,e045cef5,c22d4403,5e1d3a8,593f4f72,679d3023,79fbdefc,5ed6da2f,31bd6fcc,83e3cee3,e77e41a9,a01b2004,76912c61,5d89a70c) +,S(1655ec54,447aaae9,727bd4b9,60eb996,92558999,83d4aed,3dfeba12,3b0cb3ca,8e90e578,cf96e31e,988f7bf8,a9f06d94,6ea28fa6,b1dad744,3b9ece50,6626fcdf) +,S(b02ae3fb,530566bf,66da9326,18990e6e,7902b104,800cacb1,9717bb7d,845a3f29,c6d32713,f4483031,19bb7631,1b397427,d8c05232,92a61051,62a0307d,7b006876) +,S(13c46566,53a0042b,8755e140,2b12b9ad,8e123699,a153ec6e,65e49cd,10c5bcd3,70f3672c,498f603e,3c521ea4,3ac3e10,7bab13a8,a78b02b0,4492c51,6d41c88) +,S(e7c7562b,3fc37b8,2e9c7bff,c5e97b39,dee483f,141df4c6,361eda3c,4f1483f,734be460,3d2b4958,c1bdce51,57a16d0e,1a937298,1dbb2833,1b12f8e6,c3454066) +,S(de025d2d,fb6cfc75,342b2ed1,ebc7b27f,332f3921,c304b8d2,263d7fba,2959aefc,46c609b1,6ab6f3d0,2dafc30c,38373a30,1a88c31d,80694598,5e676f1c,16de12f1) +,S(21e788b4,fed21c3d,25ddb714,abaf053a,25730af4,83817e4b,6a42c323,3eca2e01,1fe716bd,a7d07592,b66af9b8,32335b9d,b249b1f9,cd413c58,ddd29fda,e5c1c4c6) +,S(a7db27ca,7481d50b,1a458242,c75b28e6,d1bc1a9d,da97e012,e39cff10,7b79edce,c4f8686d,cabde6c1,d3455fc1,795a7cc4,84239d2,3b11e238,85136183,71ae73f8) +,S(c5205173,2790f240,e2161627,5ac894cd,e80a7d3e,bd5bdccf,41af64b6,5e2d477a,e9aa295b,209410a0,f0e8e216,deadc3f8,af87700a,40543cda,463beac9,f62ba20b) +,S(487bf4ad,99d1daeb,f1c25f86,d36ebcd9,38e91eea,8b855d05,ea9371c4,9572846d,81293837,ac6ded0b,ee04b2a5,4c18ae0,32f72970,86de0ffe,791a9576,fcfebf70) +,S(bd6dd2a6,bfcf688b,84fe2d55,e56025d,35567574,20edfcb1,3cd14483,e08cb53,c86a45e1,84c83806,38ea1501,c2851598,c467d2c,d1c51a1a,1b037324,d9ab0fca) +,S(94a417fd,fbf188e4,1334fbb6,906731e8,70dbca18,672bece7,936a4c7c,235ec737,e03c6607,343ec14b,81eaf124,bcfb7d97,564e9f93,546f9765,299a443,d9be8e34) +,S(2a57dac3,3fa13b26,a96d9b73,317a23c0,2ac597d3,3968fa8,ebd88d94,66aba51e,1754a6bf,1db7b3b8,b0a7996e,545f34fd,3b05bfd9,805b50c4,42db2937,e8c13b61) +,S(ba2e4a71,6142a39,67c613e9,93083c32,d1c66da1,2c3f9742,eae90b7f,ec7e7df7,c262f8c1,a704e83b,ed7fc60c,5adec65e,ccc6de35,8247cc97,1da7acfe,834cb07e) +,S(4ae19743,b3132512,d28a12b1,1fbbd824,8bb0b9a,730d5a8,a862ea8,ecc01ca9,67b7267d,48fa3ea1,d1c1ec7c,a6a8ba0,cb27883c,3f9d4193,20b4c8f7,a017eece) +,S(4cfb26c,81823667,f18e6ff9,d77493f0,778b9bf,411b63ad,61850ea7,7706ddcb,10df8a3e,3a8c93df,4d7af16,407c3211,aa6c6079,c397a0c7,78e1e277,24e4028e) +,S(9f9e4566,a014b66f,fbc3ef,b3c05062,15f06102,6f7d6561,934d3db9,5d130349,492b8ba2,76d526bb,98fd0c17,c5a0aa7a,ab6e5c9c,ccfc95fb,a417d25,9396c592) +,S(e36c0513,3641b560,b0f9f4c1,1159e2f,ecf2a194,b55f3bd2,22ecf1f6,ac239301,c7fd74ba,48e7fc40,6322aea8,e9f83a82,20e9a113,ac2b0c7f,aa05a5bd,bb43736c) +,S(91b013b3,b94d4568,78737580,bf1da11a,a0bbe0a4,e3ec65e0,33e9f824,d8480bbf,15e3707e,c13a2529,22a6f824,7e33d172,948790ac,3d367f00,6472f22b,e8cfc5b4) +,S(254d1788,8c676d52,236782de,2d539f2c,41f667a,d75d0107,7d43f723,ea324f56,f7042d2e,93511e5d,13f4aa03,bb2dbf27,9bec3df,97974275,5fd25133,c814094a) +,S(452d6b7e,ce7d0f71,2afabe44,2a22f16e,34fce662,99697f0b,6135678,56f4079a,21ea8ba1,28cffe76,3400d69f,ce13204a,9a39ee59,14132d23,db3315a4,7f776998) +,S(1580b9d0,7888f41,81b86b85,5b1982d2,81783185,5f28c163,1f151479,cc4c508b,4d9d1e9c,78b3d9dd,73bcbbe8,778c1b7f,65b69faa,f6576dc3,ecdd00f5,c1d689ff) +,S(79dda23f,c31694c9,16d1470c,2cf25a02,45a5aa7e,d084af45,c43960a,a2fc2700,7c7bc169,a58b8d8c,c4b74e0f,377031ce,d7158c21,a156fc03,c34f25a3,a95bc978) +,S(866da7a9,bf80cdc2,13e500af,b5f4aa0e,419b4905,44653b5,fe2daee1,4149dbe6,626d38b3,b45d57aa,6867e8ad,c8abc49a,81a282c,6bc6524b,239819ab,766bd3d7) +,S(432bc912,bed271e9,321624cf,c6062b96,cdb502ca,f990522e,1024b80b,9411d374,e645449e,dd7c4d41,41e0cc5a,cc5d45df,4cb341c2,baebb605,bcdce6a3,e411cf01) +,S(ac3d3b28,83ec385a,15297086,525d937b,717f5ad,83a5be4,77b3ec9f,6410518e,d126eefc,c9ed7e75,c10d01b2,c0e790e7,3dde58f9,54185a12,5fcc7268,84b9b8db) +,S(4570834b,2a82385d,6db696d9,56ae2667,fa18b262,960d064a,5c13da43,abd6aa37,1e9d6083,b249bf88,7ba2eb59,a9597e7,d9d15c64,ad6404e1,21a486b0,61236f28) +,S(88e9a6a0,ffaae05b,7c29bf79,2163c0aa,b224b051,36aeffd3,341355d4,b983ef15,ed382a2d,fa2f63ea,dc4ef5e2,579abafc,fe457475,d1ae8413,99969324,718d1e5a) +,S(16810eb4,de3327c6,a505663d,cad7f618,b397033b,d6c9748c,4fd8748,2adff706,352ebd8,91326c9d,2159e84c,40dc29ae,30693b7e,5a9ed119,1fbc2cf,ee60c81b) +,S(d7d03a92,95064981,1cdc6503,588d157c,88c861d9,43fa9cab,e2e3301c,994adf7b,8c820bfe,933c2c05,1ca3042d,5ce781e6,ef419c8f,d9aa83ef,2a915e36,382f9627) +,S(5b2c9504,f645ac90,24e25c4a,e880ce7b,f33aed77,e45518d9,1c6f2652,ddcf11b0,500b37bc,c7764f32,11d681e5,e8f2a407,440e1da2,4eaec354,fc289c76,29296449) +,S(d18e26ed,d2c78bbc,16982675,9d59eec3,bab1a64d,f579dc2d,6284add4,8cfbd761,1a1e0172,37a3e78,8fd8989a,a5bb6944,685915da,1392e1a4,4a6c7ef5,7d0770c3) +,S(5f6b1416,9bbc4795,8ca21e88,df252546,dc9e46bf,85d64772,24f34ce2,8e58222d,3a8e7616,4d5a0501,947ca0bf,163e64bb,3a57918d,e383c600,e02aadaf,4b7fd6a6) +,S(d7a625e8,dcc8b456,69802023,8fe85691,ec2e050a,25421373,39bdbc8a,f762bc7,8f1f9935,a8ce2607,abd7bcbc,fec1fd8c,208683a7,10000806,20d50b4d,36ea3643) +,S(a56a5419,72aea4f7,15dc891b,3a1b34ea,7ffb42c9,5e02a771,6bac663e,8d5913f9,47b3dfcd,ad785671,180f7bbf,a7f5d144,59b44023,640e3897,1e999a90,6bc3f994) +,S(1ebb89d7,e574cbd1,37b1a3cd,4a306b44,30325db3,361b7c3a,d93116fa,baade31e,2039c52f,bd30c84b,4983d118,5422a342,ee020c33,49357e6c,b9550075,38da4dc7) +,S(b5728208,931a6575,4b5cd1a4,a798ec27,e189effa,3ee4f0c5,ad493a88,b49706fe,aba785e7,2da3d301,cb29a612,562078bf,358f680a,317836c2,14ddf7d1,bede9ee) +,S(56661670,d67b7c77,202a00de,effc1ef6,f5162a97,47afca8a,a2457c85,85a775c9,adaf08e1,83bc5107,4c55122,e549d3c1,4de8a893,39f199b2,ea044a25,4d8803f6) +,S(18ab56e1,ecc86b69,77104243,35737b51,c18521d1,b170a3e9,3fd068f0,ddf2704d,cc694c3f,43bfba9b,20c9572c,acb30563,df74f07e,ce1ff9ff,46b8259e,8119e94a) +,S(bc12a874,48270360,1575b754,bf5f50f,6e945185,2e0f27c3,c1aa0f1b,ce0ac357,9c6ce76b,ac175ce1,d667783c,7204ace4,abe12d56,62ff36f9,5de017c6,f1ada1e9) +,S(a4494c26,99b2da0d,6edbdd6c,353eca75,75666796,5ddbe457,2c27ac46,79054584,589804d5,8360a9e7,d3e2a914,61d5b1ba,e8f0cf69,3b8add03,5545386d,5082d621) +,S(1ff846f9,6d0e4e7e,be34de77,d036a027,f1baf9e2,ea3dc9c7,8284ac9c,ce3aea6e,8a0a336b,9f0e3560,31f5d1a8,d4c0b68f,27ba3eef,a52dc974,8d03e12d,653f2e6a) +,S(33181aae,91573ddc,728839e0,4173f716,6862d724,35744099,ffa8f1f2,9510b374,1252129a,8cc8ce4c,1ddaaa0a,4c34c4a5,f01ee26b,3e1a9fed,ad0e7c9f,bdc5223e) +,S(e687832d,fb0e44ae,f7649b15,77274a94,64426406,fe4c6ae5,7028c9e5,78012594,5e5b3897,6b734b7,b65caec8,c77ffb7f,c5de4f98,eecab002,8cac0c4a,a513b7c0) +,S(354bbec3,ed9371ac,58174b5e,2a18c76c,c22951,df4c6aa5,755c72f3,94b37def,40d0c876,9283416d,b3613ac7,37401e3f,3c2f4def,bbaba44b,5c2a83fc,c614c29a) +,S(fa46ac6c,5205b81f,3c9e8aa6,8b5ebef2,a8bc68bf,fa2f4511,ae36f726,7439a485,3853f9fa,b016d2a8,1cde37b,13f91185,f25657a,765fbb35,c1b4d52e,3f67d180) +,S(426f86b7,33255f8e,1e85263c,923fb86e,56a53d77,945f6688,5627ed43,3024328c,92ec0168,5301c89d,5b13c4c4,57b22215,658c6341,6aff9148,6a2efbcd,4e8c4fdf) +,S(5c8d1c9b,f9a72d5b,e15d3f4d,17d48cf1,7685dfec,b5ae1ede,b47b6e58,80bc64e3,6205550e,286c8150,6638a3c7,c20f0dec,b6a26b53,641d2dc4,e18d0f7d,29bda7e5) +,S(3a021dbc,7bf7501f,ddc31356,26a9cb01,be673373,fa663c80,271be570,e683422f,64a89c54,ddadf89,784e508a,d056492a,a7a71b82,485fcfff,54c7b0de,4c1bfa53) +,S(8d82aa49,1d719f00,75d2dd9,11d642da,7c0062c3,2296726f,a504af27,23ba47bb,6e616f50,6d1478f6,988ed10d,6c6d3c50,7c2ae8fd,4760e699,1ff5c62c,53e4e77a) +,S(6feee988,fe488e1a,6ed5d60e,fcac1b3d,bbe5451,6e7aad76,f27f08e5,3c5e536f,ee9f95,839fba96,ba26d848,425b68a0,73dcee61,35e04eef,f482998c,b044c502) +,S(36240979,bafd0d57,72fcadc7,314093c6,3063880a,e895ce5d,2df3e59c,ae16fa1b,619d0376,58ef3d85,a7afe326,77d832cb,eb20820c,157836ca,65f17c61,c84afa48) +,S(4c2b8847,4da56053,c2046fc3,26e81704,b78494c,91877407,9984a3,cf6a18f4,459a9e69,17a4d711,61ca0b43,85c5a823,734286e3,d0cab398,dda1fe21,3b28142c) +,S(f921c9fd,b33211ba,a7f4eb5b,15044c34,d6e54f50,af7b85ad,84e12fba,b1478ac2,38cda9b8,c850483e,48c6b16a,5f7f624d,e31faec3,5cd594f9,3171490f,ae016973) +,S(a57769e6,6181d68f,8f86c8a7,da3fdb4e,850ae07d,f41e78b8,ca42c6b2,1b19b257,212a987e,644bc42b,f757e00d,54d50ba5,1dcd6698,280f8eb3,8829dafc,527cfc6c) +,S(95a78104,37abecad,888c9195,23c9b16b,375a2714,fed74639,1ea949a,c7c11d9f,eae320aa,227b056b,242723df,1f11a494,ec642876,91a22748,9e1ecb2,a2cfdf78) +,S(76a7e034,f7ef3e14,2ada9a64,ce984008,9f034a5d,8584a0e5,d10d40f4,29cfa42a,999dc0e4,9633eb3c,2a4ec931,9bc2eedc,9f2e4996,522a2404,79c9468b,668effa2) +,S(eba89396,47567805,1cddf92,9db7d82d,427010cd,5e94247d,f4e8cd1e,eb5881d6,b92ae1f1,c0885214,3f37d8be,616cc5d6,aebe0f8a,8da4a6a5,d4a69b5,dbbca552) +,S(a53a48d8,59fe156,6b14f872,aaed4735,dc0b7589,713ce8ad,dd3f3e1d,6e23704f,9e738da0,7e85a3a8,3d89403f,3ee7d564,4f463418,676cea0d,2528b515,39387fb6) +,S(8326590b,dba5f8a3,8e39b148,105063a7,c831cdf9,98288fb5,95b4fd5e,a707d3bc,a02cf88,a2a1dd25,2d00d62e,cfa4130f,61b7d4f,297e6b06,cb4661b2,bf768982) +,S(6a492194,ba8c10bf,e31714a2,17a74b2f,b0c35a2c,95c54af,7f5ac6df,17916030,3cf0bd65,8e0c937a,92ee8b4f,b4fc3289,c531cd00,6febd45d,b6b6c522,f8c77b87) +,S(b4ac71c6,ff797eed,61d80c49,46ba221d,3b34bf13,7e3d4747,4b6c3068,33c52a57,46acb2e4,8fb6fefc,ef3d2343,4624e0d6,14ae3b60,df813683,90503506,d52820f7) +,S(8b11711e,65bc29e1,16bf05b4,e557b211,13b19b93,a1c1ef9b,49a19316,c286e0bc,79c4a0cf,cf383538,21ad695e,5b4eae58,faa6bcf5,c722c491,aa9078c,8aaf0dde) +,S(b8b00a76,e86b2579,97603f82,e80fde24,727362c3,6d7a192d,8974f643,4408e098,5db6718,8b0108dd,7cc6fa1c,fead7b2e,9e0b9ffb,78487d0a,5851b6f8,513e56c6) +,S(884c3a1b,fb6b968,53427a8f,69b713c6,bebe8f69,645fa52,c50e2d2d,61d89814,3dacc0e5,94b2eef,3743f821,df54dec0,ff28aa4b,d5b18fbf,14d658ce,7a3749b) +,S(3d0c1dcf,51aabf63,fe04100d,cbf6fb4e,c004dd1a,aeb637d8,496a47f9,74637596,576ebd5b,bf5de2cd,6242a6f,599fbb76,883fe013,3e2ef05d,22843236,a5df51c) +,S(56b3edaf,61539adc,25c57f79,a277b77f,1ae972b6,3d5328fa,13f811e2,dabca8c7,40383900,a2b28602,71ab3d2b,5dda95d0,96bdfbab,79b3d347,dbdac66d,2d2e98eb) +,S(426e29bf,50f34c9f,434eacfa,845485fe,5fbb11d8,319f9457,a74905fb,2bcfd3e2,eac47ee8,eeff40c6,20d10cd5,c3b9df40,eeb60b88,df1f57a3,5d613198,33cb117a) +,S(955737c9,f4e24d7e,c6d419ba,a2edadc7,cf0a91fb,5bfc3ea6,7ed50ca7,62929308,97bbb89d,18fd9040,2fa78314,359bf645,b69831b5,bb82e608,67baceed,481675dd) +,S(5d72a813,d46427a0,f2fae639,fd7e7ad0,704e74a0,83a784a1,cbb85017,e8b3e514,c92f410e,851fc61e,559d6839,a99eb95a,2e8c2636,f51c45ac,9bc1613c,b8876c2f) +,S(c7da9359,e9bc8890,620876d9,170495c2,dda7849c,7852406,22551bb7,e769b6ef,12278168,71508d00,95d90787,24a0c7d9,cb41f6c5,c82f01c6,d3794c3f,5c10653) +,S(67080a26,da7af0fd,c2fee080,f20ae516,d92697d7,fe1adace,9729064f,569ac683,ad9a07ac,fbba708b,30944107,e510eac0,8e08c5ce,79f77714,aa522cfc,2316d94d) +,S(210d5a39,d61428f7,6f878ddc,82e3afae,3947f404,5c155a41,63a00570,5bfc0dbf,617effe6,b0a629c2,ed14cc29,67a9193c,2efa804c,93e997ac,96eb1803,2e8c511c) +,S(5d0b9231,ca1511b9,c53242a9,37837d13,9b8e461c,6ff655fc,59021d04,e334ed98,c8070121,f4794eda,713ae1b4,a9e7d6cd,1a2f58e1,f6f8d986,bd13a66e,bfe924ae) +,S(687bb82c,42101161,ed0c8bd5,44c71975,9013fe2a,fcd10ab6,3ce78a67,e2907392,eaf63d87,758aa3a6,f9fc721c,f8b209cf,fafc8e81,10397e35,6a25e966,100d9eeb) +,S(51a44157,b8048f68,1a2a3931,ff2c3ff3,c63527d1,f4bccda4,e66a6d1,ce5f5d33,6ffc8d16,519c2940,14fdc8f4,20a63890,1a0c5667,2db96a1e,c5127fe9,e847dd31) +,S(b2862572,56f515a3,5624786a,478c3bfc,a5dd7b2,2bd7c4f9,89f70bcb,8de86775,22ae96a8,a5a5396,b7a67e5b,29292ffa,f53b64de,45f17692,abcd932d,4664f3a3) +,S(f76b721e,201078ca,eebd89a5,ca396213,6ee129bc,fb92ae58,4bb7c7fe,835bc30,599c6ab1,8419840,3d6b3d17,161bafff,223a0a38,1e96a4b7,a062f4a3,e6c0d561) +,S(12f24a87,63adee06,e82f20b7,ff696911,d9a3b88b,36dedb97,93b07c34,c4178e9c,59fd7b9f,96f01fb7,b265d939,c2827bee,b2427fdf,8c2e1b7,35178d58,e055b7f1) +,S(9e1b8a90,de6c6bbe,2a082d47,758240cc,bcfaf145,c48f90ce,fa0221e3,1922260a,fa5e86a5,b54bd9e0,7c2a54f4,2097d004,8a71eb06,ea48c0a6,6cda5981,b390f9f) +,S(63f05903,20b73eb7,b01b6a66,e28e31f1,ed4117f8,6c4d20a3,8c109031,2fbaae9c,24b8c9d2,d34a81fe,6e88967,a263877f,40bd68ca,baf5d9c5,1abe8b1,9501d8eb) +,S(447c7409,f5402a3d,a1f569a4,ad9f2855,e5c89b6e,99c743a8,e27992b4,63905999,d44e8d9a,b34a7a09,47b37723,be016c08,716baa73,8b93f28d,b7790370,ad49e154) +,S(74a4406a,4c5340af,ab77db0c,20f197e4,25eed4f4,a3f986df,1bbf10df,f8793254,162d678a,a4ba712,8cd36907,d1c46b16,dc4c07bc,52aa46d,fc7987eb,67742023) +,S(f7035171,31872637,ab0e63cc,841cc7b6,2bf5e076,53a45ff,3a23246e,8f047c07,c84b0391,4f470785,721762a9,5972b59e,b3c7eec9,66718936,ccaee9c1,da1097ef) +,S(ec4fe07b,57b23581,2c53bd70,6b0a4152,2194d168,dca164f6,ac999f6f,72eaae11,af495291,45deb29f,ec2b1dc4,e9b76051,b2f9df79,bdd304d7,b5528f5c,a2fff789) +,S(17156de8,fa96174f,7a0b274e,e168d0d4,c6552047,11f36388,78dbab4a,cdd2ac9d,2ae3ec4,36c1460c,984e37ed,6decb88f,c2de9f84,79e28ca6,abb6803f,1461ac3d) +,S(e41b462b,9c5a47fa,cfa9be56,dd30cd,549cb90c,9506a6a,abfca643,9a1b2ede,108fe2b2,8bda60a,c68fb353,38c6958f,e1b3604c,22215311,d380bf11,17507f4) +,S(ba6c0159,20a67883,d7880051,51a8038f,f357ea78,c53b95ad,38a6f437,7744aa38,da49c0e7,deb6b746,83366aa5,c0e8e710,cda1441b,6686f680,4579b5b9,16002cf3) +,S(26f0186e,883a4b6b,87102ab7,f7e52663,7e8a9553,8495729c,ee283568,f8cbf1ae,eef8de4,bb2197ca,ccd51980,995a18a0,aad78823,75702d3,98b245db,4bd5f47a) +,S(10b93de,80c0cebc,351b5588,c0140e63,e00874e3,da663cdd,c4501ca5,b40c9d22,ed3189dd,f79af36b,e7986b02,7ec495ec,1dfef7f2,14358284,2d05b4d0,1c903258) +,S(e79ec274,337a82c1,c97b32da,8f5a8c55,7a159540,76c94255,8bc9a3e7,77769dde,9f23079f,22dafce3,54a4c175,d888f3ee,e527dad9,83d7502c,3b651762,628a06f6) +,S(fda0175,44f0ad3f,c8b9915e,8e0caa4,2be265e3,92041b0c,1b7d31a1,6fc101e1,424e9a27,85d59c6e,bc7e4298,1a505733,e4d49a76,b84a030d,db2f5c1,858902e7) +,S(681f01cb,5380cdfe,50314725,88bc830c,8327d8a3,cbcfdb31,577cf11b,a099c6bd,bf9d2117,cdc3b05f,9c06cef0,6fc9e757,59c02fad,8e0d98cd,794918,f39002bc) +,S(70c25a6b,2a2d2cc2,dd251f4d,9aca250b,d6fe9f8d,b9eff961,1de2095c,dbd12f64,c9eeaf68,a386b2cf,cd3f4dc4,793ea5b7,134dae04,d991e1f4,6b299a4d,1a966126) +,S(464ded2c,404b42d4,fefd5ea4,5f408666,3b466e85,fe8b304,3b121b8,9fccbb9d,ac113904,6ad3f613,23ad2d3e,a568367,610bb47b,e41a5260,79627122,105d910b) +,S(a32df72,48e79198,5d455109,a8c5dfc1,b7ff8990,1b5ce3f0,2ad2f134,13a103db,6db4b4fb,9d60906b,9aea2d1d,876296c8,cf9ad8d3,3e65e173,8212134a,4b160e72) +,S(fe49ce9e,7ee5d39c,97029774,64ec4fea,3ccb74dc,2a5c7fe9,a7695315,165179a,653f553a,35925dce,eefb9866,26155723,90bfc582,b4c426e6,3f58f0fa,3fe7dc8c) +,S(868b2e55,c895a7c2,4da24750,c126b10d,ec0f1a0a,2add5a87,8aa7316e,3354ad14,5e288874,cdea19fd,71f03594,1a6291bc,776bca82,804324,efb61f24,7ac299ef) +,S(fe0790da,90ae34c6,8ad3f1c0,80fc486b,d267ff7e,fd32d1ae,c63d08b5,8c098461,ad331393,de35b283,471a0244,422c6132,cdbfccdb,5680bef4,16f3beaf,6cf7177e) +,S(fe7fca8d,f4f80dc,ff16b196,167dfefa,42a23bf5,66837955,7f6d8279,6fe9a9d9,bbc4dd8a,d7ee925,dd80cb3d,681476ae,ccc5729c,e1815b1e,71c8f1cb,d8d4eb3b) +,S(a236c270,aa4ce20b,eb51b11b,511cf4c2,ae797598,e9f03fd2,3aa36858,9434cfc2,593599c5,75a7bdeb,41cc3ade,608c210a,8bc37040,fbb69f4c,4863a31f,2088f29b) +,S(d6a04a5,6bb8c27f,3ea8a348,538364e2,800472ea,d9e1f644,565546fc,76519248,4b95470d,50b97629,22b099ab,a5761243,dbf6e466,226e8e07,9b77069a,b542deb9) +,S(d09cd377,d64a045f,e1a76f97,4d701a24,67773228,3261aebd,74e02ea9,f8a30e7f,9f0942b9,2b702b3,d76ed2d0,1caf880d,41a342ea,ee06ae57,b90a924d,6588ffea) +,S(d030c72c,16d01a9d,6c2e5245,61c7e3fd,b9a469bf,ff0a7440,b2ed0ea5,e5d98b8b,c6b1308,dba4f981,16b60ff,eaea843b,fddeee67,ca1406f4,73db0f11,531f2c8e) +,S(56c456c6,d2c04a7d,441980ab,80b39a55,57d0c6f7,5706bba1,100c6bb1,e345a691,c5b2f0dc,2c735d0f,8ef10ffc,2753c2b2,825ce525,a0613189,fae34e64,26084819) +,S(aad5adf3,b505d1f4,28dd1b98,dd4fdde5,29d911c5,e0e5837d,75e51bac,308400c9,e94adf67,4f7994c1,123aa411,b790c68c,f55569f2,1df4b6e4,6afab87e,2777acc6) +,S(ac8cd8b4,dd76b8f7,4886b089,f18b4cb2,ca1d43c3,19ed034e,6b1867a3,5e6a0ef0,71d70894,f9daab15,7413f827,1cadcfc6,ffb71db4,9bcc81f3,c759d4f7,137ba96d) +,S(3964006d,f110fa45,409d7a4d,5996b44,93eb4150,f4217948,41dc5357,dc47ca1d,e4a11c6d,21dbd93a,f922a2bd,23f057e5,c2f24474,36bfd7d6,395a46df,3ad7cdb) +,S(2be10b92,27a312bb,74ea37b1,9bf910b7,723a1ff8,fb43dd55,1a0e1fbf,7bca56ec,19aa8afb,c886dc0d,293ecca9,4290b24b,755b2de8,c1dbc0b4,59052edc,c6df59ab) +,S(379c1556,2bd7f51a,1d219a34,dffc8bab,ccc1e417,1c38d342,a4c6325a,b5ad6ae5,47a1f28f,a6371df5,66dce223,10d95535,e7bc6734,7f20748d,b983fac4,2f185907) +,S(24054dc2,e675459d,2af584a7,d78110e9,30a36290,989dd4f9,914cf7a8,1fce9809,6572ae1d,3e05d0a7,1c4e06d4,820d16a5,3553dc81,a6f02a76,12b584a2,e57ae592) +,S(9812e6a6,f46ca979,ab7cd879,1023b32,913199c8,b850298f,a3bb4c8e,a02420a4,468f6eed,dfecd933,1bbaf36,986f9377,3afd963b,56577151,52a12b9c,88f937f0) +,S(46058644,6a348e4a,d84c928d,62c9de2a,9f6c14fb,95c83c6b,96203a5a,7f13c700,9dc55ee3,ca3d701f,e6759c20,3b18840f,4c873f11,57b21ad,90401e77,622d57ab) +,S(a8dbaf97,2d5b05f2,a44d862f,e4aed0fa,1cb877ca,639ac322,8e909507,bcbe006a,3db54c03,f082937c,4f98d38c,6141d0bf,253e6729,b83c9902,51ac4a97,176fa4bc) +,S(9b8b39f4,f4d91329,13324bcd,44f9846a,8b3019,22671128,74178009,391149fe,490a4f72,1c452e5a,88ffc693,90b0d1b3,4e4cae7f,2e0ab097,6b396a99,1c52c1d3) +,S(334681d5,a7ef46db,196404ea,9e501f81,7406ce24,27a64597,73e358ad,314615eb,2b23603a,1d80cd6a,9f04775a,52069de2,e328fdc1,37fe6b6d,6c165442,53ad6c0d) +,S(feb8e310,c63c6ebd,294639b4,a4cce42,bd5f8372,b7aeaa88,2023f0e0,29c32529,cb6e42ad,6a0cd780,aa57934b,86682260,68a45c63,bdf7e617,fbcbf86d,db43b213) +,S(f4a17bc2,c7334e92,dc923252,3b910a55,a8ca5cb6,2b3d93b3,fcf0f2c4,8705cb67,812b7795,1b24729,4b3d55a3,2f45260a,e7f4a9e3,d5cfa304,bb0471b0,da6e9dfe) +,S(8ec2ac7b,85514349,5496d596,bfcaaf4e,c330a995,f082324c,7e0479ba,4ccf181b,ea1588b6,7811d263,7bcb3bcf,5cf0bc4,70e92797,27b1c258,ce4ebba9,35250130) +,S(b1e6d61b,d9aecdbc,c9c4b6d,9e48c6f7,e4aa9eb7,7da3c001,53443c6c,4d4f19a,43af7b55,b2e2c976,8b1fdb34,48d6f339,1bc20aba,eccb1a3,5aef98af,b28cbf4a) +,S(4d83d2e8,210d47dc,3904a397,4db35433,1a951963,2d4e2e4,b69f2049,2f13b2be,7ed96c83,3874fc97,be45f1d8,8e5842b9,7a0e3bac,95400036,7c8572f6,3d37a6b3) +,S(1448e92e,fd51fc21,d6f5d514,35527f67,25f5c5ee,b0b29c36,b9eb6e8f,2bb20b84,248a338f,c8be83e5,2f91c9a2,2868973c,13336aa6,39e43f4c,ea8bbeb9,96e344ad) +,S(e23b03d6,9c2250ac,2cdcc7d4,4e0a218e,39d928b0,2585fe63,dcf7093c,924e4ead,8c69c7d0,4a8a4b7c,1997ef44,fadb04d7,80b91cba,13dee454,2effb8ae,71b9aea9) +,S(4cd1e35e,21fb3fe6,946a929b,9aebfcb8,78663224,da66af94,e5a722b4,32b5d7cb,6b1112dc,5e865b10,ba688780,32978617,eca892d7,730ca984,cba4ab07,7167e3bc) +,S(f3cebaf8,92cb7b0,27cb9212,3596ece0,bf25c6b0,d8f1dbf5,f2efb204,a0db647,a615ddeb,8418c013,91923b88,7bba5d3e,cf3c7172,efbdaab7,e12582bc,a968d8e0) +,S(4b8acd28,500bf88d,68337c81,33181706,dfe341de,7b1d5736,a3a85a2c,6d655e7d,be93d7c3,825a5675,84d6f76e,52f3b06,7b7c5d87,844f18ac,624c96e0,fd219bb8) +,S(8dc7ac81,d04e0088,63fd2de6,2cc68de8,3e567d81,85aebc53,d4771950,7ceb9fe1,62d4b64a,be7b1931,c47a7755,e25c803f,1eb14c89,2ee100e8,214b94c4,11fa9198) +,S(aa63343f,3078d48d,942bbbe,df4f2c19,a817c257,9003e033,7104e530,c1b89a23,277ef834,23a6730f,69c20f4d,9de94758,13befc6d,ce389bb,fe7958e6,6ea7b524) +,S(37de5061,9f301e40,8e9096c0,1a37df3a,dadeba61,bc217495,5d04d7a1,5121d30,7e7049c,33e40b96,6a136516,c005597c,e3f6aa70,d6db4c31,f5732fbc,e538898a) +,S(6d18cf55,506d59ce,a3e8cd44,f347481c,3ebc6682,2f91445e,11f2c0c,45eb83b4,e930e9c1,ca8b73f4,7fb9818e,5d4db8a0,220f7ba7,ce807854,c8ff2af7,b8a30cdb) +,S(77d85660,6de7dac5,dd4203c4,90152c9c,f70243fd,eb1d1c0a,5b797b39,16caa7d3,3f57cfe3,9b37d550,c9db0fc9,4b3c0e3b,1a2722ec,f920522e,8c37d848,f59c659c) +,S(5c2e69a6,c44b5bb1,c55dc8b5,6f9d4fb8,ea56450b,d69d9229,670e635d,f381bf16,f082049d,a69ca9b,a2821a8c,2fd0b46c,9ec21af2,4c34b049,f1af0126,75a3588d) +,S(329c01f5,66d925b,251944ed,92beb06a,aaacb98d,89b2aaf1,918ce400,b5a393ee,7e29b038,427a0fff,6ad50c80,aa49252e,e21c2c45,3d4c72a9,c3cafedf,faa57abf) +,S(4c2e631f,18b2dfa4,37ebb401,771d7b0e,b670f4fc,8546499d,f62b49bd,629525da,8a95ebfb,87423fa7,4c131432,6b7c204c,50c6c2d,a3f85370,1f789ca3,fe9a6f9c) +,S(fe121b93,d254465,c7f7cf02,ce10a575,d3808ce4,c6133fd9,392fbf1b,63d03fdc,33129b07,7bda4311,94fb997f,9443a0ff,e59438a,f360b635,2a80cbce,a49e0ba6) +,S(323ac27b,1cdbf3f7,74e20521,f1e74b8b,2cf8c5d4,4180316d,a532ae61,2f784c23,21156108,f6a64ac5,888b15fe,834ba9a5,c8489e16,f3d31197,bb296b2d,3fc3dc18) +,S(11478f62,fdfcb1e0,3a5f0ed5,ce0c2101,eeccbca1,e5934d37,41b1a8d2,7afd533,a9f79673,2fd3ecc8,644cdb17,6d11527a,aba8d0b2,985366c,70d96999,ec5f9153) +,S(9f0909b6,c9d3c1ad,eb88acf3,aed5a6a6,bc8d82b5,767896e5,e7343efc,20b9d078,a5161ca6,c5c95d64,dc663e30,b8f65234,61a579d7,b99a57a3,3b0f3844,e47db181) +,S(4960a875,32a9ad42,299d8cd1,a1af80bb,2807acb1,b52f1711,c55957d3,a64a6b9f,578e51f3,f1b46628,eb48f54a,93f82f24,4bfc6202,eef77dd8,cd6b90b4,de976625) +,S(675c29c2,bdb265e,5490951c,bfc9f73d,d142d536,4b5ec668,54b582f0,5d310354,22d1f669,3d82de84,202d4f9a,186bdfa6,8cb8ad5f,9da33a49,83229047,e08bd6d1) +,S(c4096cbd,6c75d0e2,6a922177,916ab32d,a9053adf,ad849d36,f65b7c9b,107ce605,5f236b47,2ae3c979,2ff61efb,9633ae05,b2b97e51,24a3c2,94f5be53,95c2bb46) +,S(9ea0d341,ddd05401,f01205ec,2c754155,b1ddd460,1fa3789,dd80ed9b,3b905c0b,3bf48101,97e7d0b7,6f3692cd,53989764,ba7ce059,953f7b71,7e615c20,da28e69) +,S(bdebbed7,84bffa33,72a6edd2,d9815b0d,637367f2,de3768c7,b4dd75a4,32fb92e4,5ff3437e,b62a9b62,dc16af10,5a20941d,297a431f,ca2b0067,6734c4ae,cfd0b9c0) +,S(a486fa44,b46e34f2,d6aea82c,8f554210,cbfe674,77b560c7,bccc7d6c,9e910932,1ab7e36d,8a15e284,8a3caa0,f54ca555,b8ad5baa,7f47fca8,3231c822,f897317a) +,S(4463a0a5,57a1a926,aa204376,a20aefab,66e7abb1,18c7f769,fbd1a7d1,29cbba08,4a823aa5,ab7b602a,704f01de,20b8ad13,7dc08152,25ceace0,9a9dab69,d034af0d) +,S(d6e08a4f,c45e8dfb,ab713584,d91d1d8,8cbdc5c6,2eeb4b4c,593a73df,4d825ac4,2cd85bb4,77c0d0ba,5071ae8f,c0fe2dbd,8be98d9,622fe506,c59800cb,5eb4c55f) +,S(b626e299,2a69cad4,e6076dca,29bbfd34,546d31d0,a4f8b656,a433fa87,f96a10f1,6df4b2ce,ba919268,f1568632,55e27655,62ac5e3b,8cbbfd34,3c656f43,43cb5bc6) +,S(3619e6eb,74645070,b2dd6196,5fe4d25e,25a4dfeb,619e3b05,7e31a566,947139a5,964b8989,ba156121,9d36c3bf,29467c7b,79940c3b,450c1431,1aa0d725,1282093f) +,S(b3529b5e,6718843f,c40a3a65,d5330961,41e5c060,e326aa84,7ccf7f48,c8bda2e9,49e6e0d3,7ce1bf45,e9c595ac,285becf5,31111e7b,2a67b057,9d4fc552,59c1b935) +,S(e51f0067,5bd7145f,fcf85527,dd247ef1,4a199778,94035598,d42afdf1,2fa9e05b,d59aaf3e,8b4d72eb,4523d5fc,69b047e5,7d2e175f,30eb6c8c,ec729cbf,c1b32666) +,S(8a87f066,f64bc468,d225eb6a,a0a7b54b,91c930e4,d4520720,1705f831,cde79b28,a92a5d95,e0057c95,b219062f,5d0e4277,249c34ac,6255113b,b5eebea5,66800227) +,S(d8a81015,aa878ee5,a69c771e,bf88daad,3a926afb,b8aef632,cd7d987b,fd310b06,af77f7e8,f276ed4e,963e3a26,2f3942c7,ec9f31da,199ead3,d5e5f53f,e20acbdd) +,S(88c3fa19,4f3f4d93,dbe5b8a3,865d28d6,51c9abd,519af4d2,c3b743d4,ce0cc5c1,104caf7a,f9ff822,7b3671a7,e7745bee,26b5deda,9982b9d9,a9d648e0,760d8f8d) +,S(f8738725,3434b0ea,f05e9c76,3c729a8a,22070111,6c5a6484,5532c3d9,41ce648e,a8b5eed1,d4ee7913,b69f6627,d3e1be,4c286e15,78167201,46fc9e21,786f7bd7) +,S(5fca538,5afb021f,94cca826,5689605c,7b35c8f8,dc8fef60,6b18420f,909acc33,1d7fa51,f5c28bfd,eb1f9a52,723eb2bf,c5b4d078,d5d4b639,2b791af5,d5b2b3a8) +,S(47484548,d4b2acd9,bb2cef9d,bed4bd0f,f1fddf4f,e1561a51,891464fa,cf5007db,ea61e154,f011cfe0,46fa2539,7fb444fd,b93e223b,ed882bce,3ddaa3c8,328f44a8) +,S(331f17ff,b14d43f,ec69a6fe,b41a8021,dd8ef56d,2540234a,b466ac85,e6c5b8f1,ba20bca1,8d774731,b6b64a0f,8a19311f,37d8c061,2c4699b,68d569b0,9eec144b) +,S(6aba62d,200bd2c6,4ab88ce9,80530e56,5b8971c,f9c427f1,5e9b146d,dbdc68ce,e4c936d7,d7d98919,acd26ef0,cf071f2d,fcf65fd7,78dd8c5b,ab026,e9f832c8) +,S(c76b6c35,e72fa19c,621022b4,d9ec6ece,c0cfee8d,c73254fc,f52cbc69,23ca19c5,5b0ffa7a,48ee8599,9b74d0a1,d7fa0289,b49dba85,7b21bfb1,ee7ba831,fa13efc9) +,S(c056ea3d,43f33df9,b01590fa,429c14a6,aaa438ed,415254a4,4a93854,ce1bb77a,d5b194e3,2337a9f1,2c479e7f,576a571e,58355a02,8ba0231c,c337b8c7,eb3dca7b) +,S(3d688ccc,8ddf0ef1,137bb897,e6b8f3b7,7df652c4,93cac3a1,47e88b3d,bdac938a,bca94788,4d7ae1f2,960daead,111558f7,38b6bc9a,7af3bb4a,691af22d,4d5879fc) +,S(4faffaf6,69ce1180,a9145f0c,df6fd834,c59d7a9f,5f2e49cf,3924b33d,8d2a179,9e015cac,2dca2ec2,5580c16d,8c910abb,dcbad872,79bcc485,b71f5561,60159d2) +,S(47578e3,7cd7eb78,6b5a44eb,3decc7c4,e8ba0c7,6699ef61,4ac30579,a24aecad,948ac817,a6bee00b,c68eab83,fb628ed8,7fd0066,9ebc8569,45eef8c9,67171651) +,S(9aade275,3eaa646a,24ad1a35,f74887db,8c72fda7,77b59dfe,103e1a95,dc618836,b651c384,8f4625f3,1e6e7a05,c94483f,ceef2fed,dc7f4256,87e0373d,d02bca96) +,S(b1b0c3e0,b1c6ee75,55a81852,447b2bcf,321c9b9f,629caf9a,276133af,63aed711,493accfd,624e6ff3,dfc1d0dc,aff17113,c2c74167,58cbd571,759bab24,300ac827) +,S(c557758f,b192a058,eaec5762,ff391a9b,2a0ce462,7bae01c,156dcf3e,bf2a8ff6,1d4e9b53,d209e195,9f10f671,b1bfdbf3,98921284,a7719766,39947969,6d1bd3b3) +,S(73522ded,5120ed4f,b49b5ca6,df5a1b6,edcc082,48df4d07,cc9ad923,2b7b5e0e,47569d94,cdf0270e,d1d299ce,d5bcfdc7,7f87db4e,c9725a96,e4388cf8,dee08d74) +,S(16571c0d,66328963,2a3ae46d,fc2bee50,fd6fbc0c,f0ec73ad,72bb9c2f,e8323506,65de9d86,9e001c60,ced57911,e7ce6150,a936d684,d759f143,d2224448,4bec68d2) +,S(f5fe5564,2eb630a5,c860cc8d,7c9ef86d,b1810d2e,82dcb343,dbe2f958,98e5f090,5cee7a1f,bea9dac8,ca340dcd,fc2c097a,eec2dabd,d7ed7504,e20c913e,9fadfa87) +,S(ef09db32,70d09043,43da67a0,b87cedaf,7aece017,58d78591,8814e3ca,396e3592,5934f805,ba246e9f,965c6161,cefdf4e3,7df14271,2ae076ea,80ca239a,c7b675e2) +,S(886cdbd7,27d2f099,9852b102,bf201ed2,5e174622,f974b0c1,3edfe523,373a54e8,dacb328a,7fca6e5a,e5351825,564e4f89,5166f687,38d46142,6eea7b09,dca73b2b) +,S(b7d86bcd,4f7bf2e,8529ff84,88d9f3e9,62071308,9bbd91f9,6e4ef82a,ce237cff,c6b0aff1,375a547e,a8546dc4,17574843,3acf2a4,ed0d002e,e32fd88f,3b702f0e) +,S(d7d171b2,8132ab85,30791059,395d94ec,c24f5e99,67bc6c4d,22bfc7ba,eb388c67,983770e0,2421e2b6,55d3c135,1bb39bf7,7be39682,97088744,bfe6543d,dc1a8f8f) +,S(ffe712fd,881e30e7,229f1cfa,833dad90,f01a1896,c1493502,a429080a,9794b1be,f4299e03,75d084a,10b11ae5,8f2fa2be,f18b037a,53165586,cdac18ce,54505da8) +,S(563c92b3,3226951,cd7cd10b,3f7b35c7,dff3f0de,6f03d66,9f664655,57d13f7c,dca1eef4,85bef41,80b0ccfb,2416f948,9bb21094,854f5f43,769cb37,33ec10c1) +,S(b8e76ef3,3a2cebce,614056d7,efa47c15,dd52c228,66a7d3dd,9a0d4d64,68f32437,4454e79d,652ae799,a3a539ba,42619a1c,3076ccc2,109dc4a2,2aa41a28,918651c2) +,S(36db2304,f60703a2,df2e429f,b8a99841,7b4a4f3,e08642d2,c5675460,aaf1c971,a0536e8f,5cc30aa3,d9b859ee,e26b1abb,ecf7f9b4,8c8fef0,f842fc9,a684b5cc) +,S(c5d4e51d,1521637d,d6055e52,9e9ae2a4,d537c1a1,b7c6a314,f9d558a1,88d9a5ab,c841eeed,6a13782c,fbf65b08,c6570994,aaf7093c,4b48ad0d,e04db33a,6feb3f6d) +,S(50c03dc2,985859f6,ffb79ed3,f635e17a,b0561533,600af220,7cd98f9f,71c4bffd,c68c8797,a7ed229a,f59a2bd7,451c748a,5c425528,8b7f6b0a,68b64a77,d7137720) +,S(2806d84b,3e7e6f9a,2e10ae5d,cf5bb0ef,98560691,71d31ff3,3645346d,f08333ef,72f23443,38e34ccb,4ccb5ddb,f3a6b58e,bf8cac26,4243785e,54a9b503,c87b429d) +,S(40d70ddd,1ef58dd1,c43e33c6,29840fee,82bb9c1b,e222b53f,4c58952f,388790a4,9b1a9d57,b6dd9932,338d170e,af4d5516,e654685b,3946930d,96b2a1d7,f70770d5) +,S(8850ec32,4e71213,bd77b193,ee21da82,ac733804,17983905,d0156608,8b87c835,aafff7a0,a9160b91,92df58ea,a65c0716,961480b2,b0cb4d3a,7d637f77,ddc160e2) +,S(54951509,bd7c29f4,77f9d4a6,2be485d7,de291b0,6a308bd2,c240cf71,50ad6e8b,2fdb347c,f2a23b9f,a3a45c76,44cc1fa9,b1d8f79f,77c02f27,f136c732,c7ef2722) +,S(9f5ec355,cdf8eb4f,be5af1ab,70a3e7cf,1c3d3e8b,e643621f,acf8f69f,af7e5d44,b203dd5f,b38b3550,6fda94b,ada1c4bb,12b8be5e,92bf8a58,4886f2ca,19d3c06e) +,S(812e4a9c,1bba9e52,8cb5e606,c8b326fe,8b72f0e2,3062837b,bdf371a2,2ec0b3da,2ba7b5b7,14a9ae39,c62bd36a,1ed00135,5d98d248,9ef90f24,d10d1c58,f8e222a1) +,S(e6035ddb,cf85616b,540ff16e,cd5d7fd1,af52c6f6,2a26ec36,c5c1ca86,2a3d924a,a945389e,f687fcac,6f918718,a1f29f19,173d3104,69c5954a,d6cfb5df,f01eec86) +,S(d788a5e8,d771d471,b7169693,86b2339b,2643f129,a6b50bc6,321e752,6a033446,34b85622,5095783e,fa57fe32,a7d91b65,c0c9a42f,79fe30e0,b2598967,e97d3990) +,S(663733dd,29374f9f,1db5f11,6fa32b56,c8ef42f,706bd802,5615d4a4,77c6f41c,3585d45,3ae0fc59,1614e916,a1400b79,85b59f66,6e2553c1,394ec26d,d078676d) +,S(5ec6e728,5ae1413,3dbad4d1,19e2e3d5,6affda33,356146f0,a5ab023d,b323ad9c,3dd241bf,cfc6301e,29cd609d,b1a0fca3,d35a56e4,668de9f6,45c23d69,c0884579) +,S(f18fc442,1fbb66a2,7c336647,1459717c,87532be5,d4416cee,e4a674a3,2cf8f3c5,d38a0881,3bb33df1,fb4e83,6686c0fa,26847e5,f7580de9,b4f229cd,1359d560) +,S(818f549e,d9bcfe1f,14b8d336,21342465,7dec0dfe,eea1d719,20622442,39f5345a,37ce611f,cca2f448,45c1a8e9,d7f4b3f8,48b24c5c,2b9f5368,8cc2c8df,846602ee) +,S(75e2c791,f98e3fc8,2a74ee3a,532e8796,4f4fa8eb,6421aa64,17a5b00b,1edce942,51f2373b,a4951362,68aa17c7,1160855c,7c4d37be,222a8b26,f2d54cd5,37e5f6b4) +,S(711f8db6,4c0c6d31,daff4ec1,f9937730,9b44de59,9f4b9119,9ca6836e,1e3954d3,485955e3,432ac82d,f3170fcf,7b3519cd,6e4dfbba,170bbeb5,b75e3e7d,70caa4b0) +,S(63502c26,6f755a1e,4be2104e,e8ca9c2c,5216f50f,e21e003a,16071bc8,df3ba6a5,a5c829ea,c8fc3f4a,f55075bd,afe77977,3954b88a,f1f3a8dd,90f28aa1,49bea942) +,S(2a677459,ccfee070,1b5bb82f,d2ee57e6,13f5c3d6,3927938c,92d10954,c2850872,ff6e9798,5c5db0b2,9bb1cbf5,db03e0c4,401bbf28,eb39e053,714d5c5e,ef7cbe71) +,S(68f85f87,78fb69a7,9db4a22,3d7faf95,5b359bd0,5f230d99,f051b008,32b52cbe,dc2e949,f4fc3189,c4f7b771,f8b56b85,ef9c65c0,b3bdf89e,405d5f3c,ffc92210) +,S(7ee9d5b7,3b542036,509fd8b9,de590b24,9e9883c8,6f4bb90e,1c2904f3,d2b74ade,98122413,241cf205,f91c6977,b925ddd7,4920636a,9dd67828,2c30ee,7343e62) +,S(8447b090,cdb19271,db368023,d40e520,102b5d04,79eaf391,3817553e,24aa33c8,25b43fe6,55a27481,c02eacd3,9025a523,121d02a5,78896a78,c14a8c21,f7c0bdb0) +,S(316073b9,3f1550e6,b7951f56,90c5ef3b,e45e622e,77a2f268,c89a8b6f,2816a645,557ca5ac,2fc70ce8,c3e54a4d,b31d5c77,a1a6f38a,18646caf,6a52db31,947624be) +,S(fae2312d,a2ef21ac,358fe949,5c011b18,cdaa8ef1,c99284ae,5fc1eb77,4836d6ac,6f3bf661,2d99e865,b0cee7cb,3fccbf08,aa948ad9,b29b4b8b,54eee8d6,3f0b76c7) +,S(280a2bef,5588dfdf,b1e1691,d3162aec,7d4c72c6,b76f23e1,2f8ce783,54f839f0,f00ded1b,c31a9774,a87be1bc,7e440585,b2b4ba63,cc0d9c73,ca7b4873,93683f72) +,S(3f43e77a,9b7b92c9,92b7e5d2,8c75444f,4d0609b2,8aa65ddb,86bf6ac0,bf7ccdcd,b3117903,bb3c0a54,bc6bd6b9,92b8d85c,ac267855,50075536,6cf70a84,4c72a2d6) +,S(3a0afdc8,387bfa34,87e53929,51e10e,9535500d,f6506296,46df162d,d469f2de,75697cc8,f0f690b6,e1f86dff,3f2ca53d,907d4cf7,c8ff324e,8b4187ac,c9bb29c7) +,S(3f972b64,209f723e,99a6e7c4,a72072a0,2789d0aa,8a23d660,949ea417,7970809d,7a482428,7a6bfd9c,afc26e76,9a02c5ff,9a7c053e,e63f2342,b32a4f84,42e47d15) +,S(938ac0f,fa73364d,11df1ecc,4b84e3d1,c21ff85d,71f404df,e8daf4a,e889b0b4,a1c09ed3,d526b381,dee8820,eda06a10,4e968995,64cb604a,63fba74a,45be0312) +,S(5355ed75,2993e74c,275eb9ed,3bd34575,631c9b5a,64e99071,8311ec8a,f4e28bcc,bbb1007d,680aaaaf,ac10279f,600f1851,c8188547,3091a40,ddf7253c,fc6ad088) +,S(880e32ed,70ba76c6,d83bda46,a4340646,b033696f,ab62e457,4e989311,fbf277b7,76feb2cb,8d10d5e2,406763d5,f696686b,8dcdaaf,330e4e7c,623cc7a8,6e0410bc) +,S(daf778aa,a2755b68,2b8beec1,14b74e9c,857ac503,daad6bee,bd6d11f1,8f11aa8,1ed85c62,710d3017,9f0f3024,d6ed6976,e38325f0,92981c88,fd4982ee,98a5f428) +,S(e5c3e9dd,75633d27,d19c0a4f,f3533f80,9a60b95a,42c8c464,1cf7abda,8fb474dd,f1e56af6,5c5c087e,ab303699,f20bc9f,71b7b7fe,16332afb,2517b241,8dfb0dfc) +,S(5d403f34,ecdfd870,977f3bf2,ffb274c9,6859c20c,8cd7afd,d116837d,c0096973,6b5be47c,70246cc5,9781ba70,71764d72,2335c334,443e5e4a,5ba12939,d8f6aeb1) +,S(50ba053c,25511f71,b35b4caa,c990ab27,993bf034,f3e55f81,3896458b,5e246b12,d2f12a45,5c7a3170,67690399,3063dab0,9f8a22a2,bccbe5b8,8a7fa2bb,f2291f63) +,S(385a80ea,ee4aa9ed,a07898f0,b3658793,9f290622,399c3a00,b38bf02f,66629cf,a543320b,d72ac6e5,d750806d,6a90b8fb,8cfe4902,46991eb1,6e6a6974,befcd50) +,S(98610b9,904ede38,6e69de6c,3d40518e,eaa669a5,23620a9b,276e1996,bdedbef,907755a2,eb6aa100,d0cd0c89,25b5ff8f,b88f72d3,61d83315,c4ad0d94,8a06b581) +,S(83f10807,d9640d3b,dfc7b0d3,dcbbf6a2,19ae215b,4754f29e,d4579999,191b7fe8,f62d231b,5095d6d2,860e69c6,509de2c6,fe719e4a,fbc2b5e2,489a6f9a,7293364) +,S(51d22293,927335c6,2f82b028,52759fd1,e3f287fc,67b6059e,74dca17d,4fb1c246,b9b803a3,b5145b4d,188b909e,23c8b126,f7184bdd,3128587b,e05219df,6c63745d) +,S(be6a6342,e5783d43,d2691945,826c37c5,3e8cc24c,5a09fc70,3689def1,4f465006,81c718fc,3fc15279,da9efc14,13ddcfd8,81bc7e4b,1c36004c,2008dba2,7c7ef000) +,S(f21334d9,c36f1284,a4bb043b,58b27070,448681d9,a82ae81,a4e8f226,bc790036,44851,3a87fd30,453dcc1e,b21e293b,f5f143b8,2cf2708e,428f4753,8816eff2) +,S(1558c4e5,af34463f,810cb1f1,b73bd27e,932a832,9253e2cb,419eafae,c9730508,cb8cc650,25e14132,3663f3f4,1a75085c,6921bb37,428a149e,2dd1fe4d,f4c917f8) +,S(1853a32c,8f6020d8,1b4d3596,a88e3825,b575a4ed,99072e64,2e090a1a,665d71e2,8da2a31c,b170aea0,e364aedb,b1861fff,eaf26888,b29405e8,9e3ed982,a03a8367) +,S(ef585cbc,f0f03bec,21df60db,cfafa9dc,2da679b4,3bdd590b,8cc35388,cccd323d,2bc5e203,aff91f6d,38592e07,82813905,f02ccdba,1daa7acd,d93f6d80,78c2f296) +,S(3f4c2e37,e1ea68eb,befd9971,424b3c7b,1fa45864,e0d13471,a1476808,b2fd5c14,678990ab,3d283b3f,aaa665b0,4f329b51,51b9c17,b54385e3,30de36a4,7e0eeaa5) +,S(2b001b8a,d557ac4a,181cb20a,b3abf2ac,59fc9b10,20b5533b,621b4119,e421693a,fe4f3007,f8d19db1,73e6f8c3,48b2525,310a328d,2ca0c675,8fa29723,82c6b94a) +,S(6589d1dd,7d5a08ff,8deb5b10,81fb0ca3,79c90d27,58ba0bb9,8d05bc93,452cd229,82409480,ed842993,4bc8dca2,3e000fd5,fdc5475b,192bc7fa,a1179165,9a8149a9) +,S(c233fd0d,f5d3835b,8e855316,276a6a90,ab4377e5,a3a3a8a8,3b89f0f5,27950a6f,8fe8e0a8,775a9a43,12cfbac0,85aefe06,31468031,86b8b84f,49422392,b4f6f3e5) +,S(82731a85,2a848eee,d6ee3f57,f75a2bfa,a388670f,89f6f6e7,b65b13d0,764cc14a,c00c509a,307c5e87,f1b09688,38e34a21,1ffacc9b,8a7504c1,2080e4cd,39117583) +,S(e21387a0,e5d8b1b0,5aab5150,122942ec,c9dde3b5,53eac977,7eea6d0,6d2a50d,c74de509,f90d93df,343c920,74ac5dfc,fc81c95,93354349,bb2810dc,8db0ff83) +,S(180871fd,2fa443d9,c5b5c341,4d635b8e,92780fc1,6d04236a,bc9a49,5b9fdc25,d66c7150,6008f37a,422014a8,bbe025c6,1f25e636,e2778146,59985003,ab14d120) +,S(b5a9de7e,ed112a8c,1ef29a9a,31156b90,d64dff93,4d83fab4,b44d30e0,bccb2c42,5675a679,a81c3faf,3b0afe66,ef85721,30315ccf,b0ff3d91,130a71f4,3539db38) +,S(9acce472,61f1e50d,f42baf78,c05a5cf9,8ce5697b,6d3b4d,40d011fd,aee7d6,fb7c413c,40464c69,e5756830,4325a79e,6cb8c831,add29e0a,95f88feb,9507a05c) +,S(f80ab79b,7bef7712,2fc7bc4b,2193deed,916796e3,67d85100,a02cc0eb,8b574e5c,c6d4d03f,842d8b25,d9b5834e,d6cdcacc,3a1ac585,b5d22aa,c77019dd,1d5c8f6d) +,S(b431e355,cdb4230c,3005845e,f60b24d9,25d81448,ec161aee,faea1f98,bc9366a1,ebcdadd4,ae230a14,382ddb98,552b6e69,7aebace5,5cc7390e,f69d176d,da41c1cd) +,S(7aa60b9e,8c93a63,51eb686f,46dca4e6,efe56edf,6c2089c5,93f6a800,6e75f1fb,4c81e2,17700bf1,e053e389,2e33e694,cb424800,b4068c98,328f00ef,5fa0347e) +,S(1a88250b,3aa4243b,7441d1a4,da37b4dd,d304fbef,272f696b,a72e7610,1286b30b,625b9d05,57d3815b,e06d8cb0,f056a9be,b33b7658,f459b3fe,3fd5f4ab,69b7a473) +,S(5b524eeb,49fd558a,2d34db23,cb5dcee1,6c4ca47,1eba9966,82dedbc3,aa2b57c7,2d5c2c97,56b7ce1d,735b163d,56e02bdc,25c8b227,2bca2d5d,bf252906,bb8ae50c) +,S(ae60e777,6d9fbe79,d24cb8b1,f756098,191550d8,433bc7d1,8920584e,7676d2c5,430fe986,73772472,ca11be83,eefc8678,b76c36d4,346a311f,fff926fb,158d7784) +,S(323a5e3d,9e29f668,d460b081,a5dce6fb,53e8d730,9c42f105,ab4f812a,62efb9d4,2b457b3,69483f42,16656d1d,3b5ea9af,da6216a4,47661830,c2fa56be,804776ba) +,S(acd1b5b6,591e552c,864e612e,d69429b2,b3db8649,7a5962a2,a8b36511,7a7c1c9d,e6131fff,56f6900,926ba772,92526348,67544d25,1ebc4fa3,26562190,8e6e88b8) +,S(6b4e2c70,817852e0,2a26286b,155248ce,f2e61e60,84742cf1,14ebf74f,785b36f4,8400951c,7a529bdc,2007130d,1cd5297,7398f7fc,d66e5a1a,1e4e8644,e5b893df) +,S(c2b2c727,d67b0a46,1f44cb91,48c34744,4e6a375f,80a817c7,1517969f,8084ab31,fed64359,ebf37b0f,998aa251,9c281fd3,a52c47d4,89051718,82481fae,c36d5f59) +,S(3385eeda,b5b2bd94,f794609d,978a0f86,2ec56422,bda0ef71,2207ca1b,904f202e,2808d2af,1db8a8ee,1c5975aa,31a9f441,b12a2186,746a474b,4907bb71,603d7443) +,S(800f6cd7,f2cb437b,8470c292,3fab4786,edce15f0,d4c52a82,33519c07,14c803f2,981f2e3e,ad11aa0,cde06ca5,9b26028c,23e0a88c,ec397734,ad0152f4,d4a37056) +,S(73aa0bff,3a9f286f,d3c103c6,d7bb6caa,ebfaf4b7,614f1f32,4741c600,eeaa2f3b,30bc529,81a9b983,cb89fe73,dd8bce7c,a54a2e3c,4fde6846,701f1da5,18c6f7b1) +,S(9280fce6,ab5c13f6,80bfdfa9,c3e7612f,86380498,9bcf29ca,789169fb,a178f2c5,4b96ecdb,c5bc2e3b,2fd397b1,8f7f5bb7,aeb6a7bd,db0a3b23,3e74f7cd,ccae36bb) +,S(72055c4b,bb50b9ef,b589be16,270d12ea,9f438780,e5eccb81,7dbf69d,a66e03ca,aeaa257f,c30a77dd,58574693,51a8623d,985ad705,aa1fe3f9,8915a6c6,f6bc7cb) +,S(f0f3cfd0,c771e3db,ba687c7,3fa827cc,eb8e887,12abc8e0,3085d047,e7c1879f,2c612e7d,8b744c54,f8f0c4b3,24fe10a3,1bf8aa5c,cf6e2e20,eff98153,a4936b33) +,S(97c78b65,70b0f270,6fac8fe8,ea4376ac,d8b61177,e5e7b3ec,67a7af9b,e6f5dcfa,1aeb950c,fea95858,a97da765,c3cb5941,1334609b,347c4daa,1279d58f,3be14c3d) +,S(b39ffa1e,967e6fc3,d493a9de,48b077fa,4b7908f5,33a73eeb,9b5c9efe,9e509e69,f55f3951,81ac72cc,d618c00,71c817e3,f76c302f,11219e16,f3b40e75,ea65dc05) +,S(159b9f7a,5ff27c4d,1bc3fcc4,d91b160a,1b2a972,8b1e7fd1,7351c663,f8e7baaa,b0aaef6d,86c54ffa,eba1c7f0,d789fd41,5e60127d,578c2697,a8380b7c,a4c4360a) +,S(25810fd1,8d4a4b16,c7d07a62,b626fc45,6dff76ab,3c1361aa,f729f7f3,cb85e44c,f4052325,7794bd70,ad295526,ab4b8b00,9252dd5f,33578f44,2fcd2219,2f6a2d9b) +,S(27e20a4d,5860a328,c499864c,9075881,eab36291,2da641d,6e1934df,473352b2,c1598cf2,888cb50f,e270b490,503c11a7,d3822a2b,e86a7b,65cb9499,3b45203) +,S(483f454e,517a94e6,6708f465,ba217b60,6d684a68,4d9472dd,685f3bd1,341448a2,c13b3144,d93b9a36,45d23346,c5dcb70d,d338d06f,f0c22aa8,2ba68a61,7f9ad11f) +,S(4f47b2f6,31734aa6,5ae4c9a3,c1532f2,67ef068f,83a4f266,e2e0a59e,be04e6e5,58f1f34c,f11b9cb4,5d33ebcf,3edab72d,6824392e,dd547a27,c0134d66,58d99d2b) +,S(aa78eb7e,835ce84,b4f1774b,8e810cc0,d6f42a2b,11c44574,24fb6341,7797db07,39640139,d957d47c,59cc7541,d3f72e33,ee9ffc63,2171311b,cf493ea,185e743b) +,S(d2598985,83c00560,11dc0655,c37580b0,31a3f1f6,aa5f5944,17eb0ce8,cc033d49,3641c973,9de8818b,a294622a,2dabe172,b6a83006,4d04ed8b,c841d11a,5af24b08) +,S(4f023ba0,ecccb74f,56f38f87,7435907b,f2d2b85d,59f7ffaf,48712a48,55e26634,f80efc33,b15d5125,b8fc35ea,393b6c3f,a2ae094b,86a6ee95,bc48295f,b1a6a456) +,S(9c86f08b,48abd097,7bfe13cf,a15ac8be,8eda4128,f7c143c6,70bf7e2d,763a1589,11511f87,e9ecb88,39eff453,d29d4db2,17d4eeda,c8468a17,1a152f15,c1c2df45) +,S(3808718b,72e95cc8,fffaffce,cd57e269,c5e6ac77,69d8120e,9130d8b8,ee137576,f40ebdeb,cf5eb722,4dae59cf,8ed8b58c,c614a61a,9e3ccee,db789fd3,31ea728f) +,S(8defd15e,399492fc,71c80a1,3eda0244,eb349f47,5c7dfb42,55dfa752,fcdda3df,d3dfa778,4353d0c3,b4fb0d19,ffc39631,a01786ce,e3b0cc7f,f9e4c5f6,7bf7a771) +,S(8dac8d42,5ac1d07e,3a805248,798fade7,ed99f9d0,c324bd46,6eaa8aa7,dc24bf8a,f232fdb7,923234fc,d8b2f097,d354dd6e,62e9d926,20d28087,d6410b72,aaef8009) +,S(87ce6443,f3bce6de,287178b4,f243c3d1,e45d26fc,6f811d35,329cac04,7fa90e1b,a897019,62414ab4,c582799d,77edf3b0,f0af0d4,8f70e875,fac33e95,39724138) +,S(bfee6bfa,bf2fb77e,9eb60a3f,8b7775ba,124a21c8,741af3b,d22966c6,a8fdf08d,29a1c399,541e4bf1,7f26f215,52fc83ee,cd2e8be8,40b83fa6,9c9ce5d5,fbba76f7) +,S(c30fda5,b553a800,2341a553,7aff72b8,44873af,8381b41d,aef9af2b,5cc2bec1,5ce3eab5,87d88d64,fa44aafc,ce34046,8a96f76e,65dd562e,7d14153b,439fea6d) +,S(5e7151fd,594119d7,c5cadbf,e1b419f5,4d922607,728d70a0,f1dd4d8,3400ed97,6a8ceea5,a51d4a7d,62d36816,ecbdd75e,4c64ec96,6257820d,73bd9531,ea108917) +,S(a9c8eb0a,66cdd5f0,f33d0620,8525225b,e974af7a,b50d47c0,4bf690db,ec86100b,f209cb9d,898731f3,b02a24bc,ff290cd4,a4371e88,f3aeebf3,29c9e1b2,8b8e0a2f) +,S(955e79d7,93669150,471b1659,52ee6121,cb804373,5faf653b,9468511a,e3a2e439,68daafe3,2a9b67a0,10ea3bcc,1a56c7a0,2e82cddf,120e6826,1de0700b,cf930d06) +,S(22d27293,d3c1cc6a,5b3bc70b,3bb7e1d6,bef24805,3c8685fa,c192b409,dfa34a71,c74b44e3,4fc855b7,53c4e42e,740dbb59,4d5d76df,b39de389,e6c837e9,639b3357) +,S(d19fcece,f74b1767,4e9d91f7,1487aebf,70d46e8b,3a037835,b2f4e8c4,2137abc0,5b904bf6,3dca0981,3ce224f7,494ccba3,34ca9fe5,f365ca83,fe9adb6c,4adb7580) +,S(6aa1722a,adc74800,d6609113,6bc6a6a8,1723c36c,524a873f,2a437c91,c2336899,8e97004c,df495b4c,63164058,321549ce,3d9709d9,ed667c36,9a4f1ee2,d6319d07) +,S(79bd3623,9ee4d220,12d07262,e96ad186,b16e3b6b,720d052,f736f851,b0ea6efc,a4b43db,f568cda4,1dc972c7,1c7c92c3,6a31166f,ad6b80fe,42df4dbe,f418729e) +,S(b5e02b2c,146337b5,67583c5d,3690c0cf,a1c7d820,14028c9,e401182f,a4f16ce9,4b9646be,3facaa70,e793516f,a0e8a142,1a819ba6,718d26fb,938e2795,9069e0b2) +,S(8e33e271,de2deb4d,6444d64,387f790d,14a2b685,4b38857d,d05af743,7a7403a,d82d53a2,c7a4a1dc,eaa011bd,3e0ceb0,e08d73ff,fe9d71f,c913d6e2,89ecc429) +,S(4ffef442,77dba780,e5769b73,feda37da,abd6ef6,2f5ec36b,74593ca,4c19c2f5,a8a30857,378aa0ab,9ef6162c,fbb09f9b,796755bd,67bf9d69,4a186813,d392f854) +,S(878b652a,633805c8,b58b0334,11b9246f,f7e42ed6,ecba6bde,fb737126,e9f57368,2cfbeb3e,d691158c,d3ae71f0,b4a41d42,148c9711,d274820a,d541efc1,56e85836) +,S(ef9a6a15,aee2aed1,46b99ee6,a79acbc1,a0aa0b2f,1b082783,dd40b106,9deb415e,9909e2ba,7fd53514,a1bc4480,2b49c7aa,cffd9cda,19c54d82,6d9bd08e,49e97240) +,S(d5c248d4,1551d230,60835885,5db0ce8e,c7814e18,c2d548fc,dcfac207,645bf37,f9c5e89e,7bf01f82,8cb78c88,c14d50a8,3cbeb45f,82daa9cb,3c3804c1,15a36f05) +,S(edbf25cc,a526157d,9676e614,81455682,6dad0c0f,96ec289,f2c5919f,57227d1a,6845488,be056456,4a833c13,70d37257,d0ca701e,f6e574c7,409dae02,ee99554d) +,S(5c12026f,b8e2e376,2521f5cf,cf9286b,14be80b0,dfcf378b,26fe6ea5,4ccf09bb,3d98d5ef,4e2c6528,7950154d,581c9a44,94b81a50,40ba9047,1bfa6758,66daa596) +,S(c27e6243,5056055d,614dcef7,f67338c7,ae728bd4,af3970a0,b434d2b2,e48e2d6d,76b586fc,703cf946,f78839ee,bcd28c56,9e372d97,856333ce,d82137aa,7d8525c9) +,S(a298c704,5140186b,4d424e8a,f98ee604,7f67603f,ab14a7e7,b96daede,51abaf8a,4dc70158,2a1b1935,4a5b430d,b4a0c21c,463b779e,ba72f108,5d7d638d,68108fda) +,S(e1fce957,82dae8b0,ac204fb1,9496a332,fdf40014,88ebaf07,3a62f33e,192013c4,40517ee5,d5786ff9,6aa2b50a,a77a10d5,e8ca6439,44f308a4,a264e367,1dd02f4c) +,S(e719bfc,5f06b800,8e4e49bb,62361544,1a2b0c42,f673f3a2,1e139bfc,b097d6d,f0c83c1d,83f5df68,a1e3929e,e18c4945,d14e2c33,4f9165e1,a0a462c2,aefd7822) +,S(77766a4b,a9d8cd62,840b1127,7e697dba,dc27c50,d9c8e35a,17f4c38b,50ad0a4e,5b3a2ad9,448327ba,22265ac,86c190bc,60b7586e,6f6e4554,b26b69ce,231b6431) +,S(f237721f,6215a855,f8660cda,41063690,4f2c9dd7,6260c292,597f28e4,348514b4,109daa1c,187b9f9c,ecae8c6d,33cb9874,46f5ade9,d57b3651,bccb9338,1acfef79) +,S(9408f5d5,e8891a1a,3cc4e7a8,a50dbc83,97517b3b,6c5af3b9,f1953f09,a67b3e08,1b82f212,c32f1ae9,c95f87b9,5ced2bf,ca33e954,32d9eb90,ed879ec9,59691555) +,S(b2837655,11707926,c9f214f1,3e90675f,883649c8,8f1660f4,c4f9f6c1,552a7064,89553739,15be8962,e6f03ca4,5bd5516f,be6ee041,519c4131,829b0bd7,6d1abfcf) +,S(ce42ba00,36b5f54a,4ed2a9dc,b6c0d29f,98641331,3f92f9c1,43767bfe,4b78f4a9,6e547292,cf35baf4,768c9179,2f706bfb,39b757d8,2452a802,4a7bd37f,e3a048d4) +,S(bb3da2a0,1a063a97,bec9325e,8d4af420,d3942bbc,42f0807d,8e9edce2,eccbcc59,7c28e7aa,bc39907f,ef58a19e,cd6e7b2e,25d6eb00,8da14d9d,5c559d27,fad70b32) +,S(25d84c3c,97f3a074,ea76f620,d6fb2691,dd3e9592,6de8eacf,5392c0de,36c490ee,5e0e7745,88c8a9b,7b91ffb,1ad6fd27,4153096c,9e759540,16f73a43,16d5651a) +,S(8baa3bfd,ca256f18,2e55a01d,e7c07617,7649942b,e743b4a7,faf39446,84d5765b,6147e897,8bbe15cd,171c2816,4730b211,587bfe7d,7e71811,7f308b80,d30506f1) +,S(507d6a0a,5b7d0385,11c65dea,8024c706,4d3b6b9b,287c7192,74c69797,21f5170,139f1647,70ea83ae,47ea8141,c3ae32bb,c12793d0,ce30fb37,2dc3adad,7f7bf5d3) +,S(7c6992f7,a059c5be,99b7354b,10fc217c,e45620f3,b4ff30d6,d640fd3a,26bbd846,964474e,fa63641c,2aa7062d,7139fbec,1f64e6a0,50e1ad03,2741a0e3,b5e0bee6) +,S(f62832b0,1bf65b23,14850750,9ea6f157,3d5e3317,bfb0a38f,cfcc6692,5a698bf2,d7314810,7b8fdfd7,3f6ce6f8,84f375bd,1546cc3b,8c75840d,3668c2a6,54c1ec95) +,S(aed21cab,d8e4ec36,2b4e2091,3be3c7c4,594f628a,cccca657,deff8b9c,6bd1ebad,f800ef3,833c7ffa,a8ade1ac,2f41d456,b880a205,60251dfd,f9cdd672,bb7100f8) +,S(46de78a9,343a9a41,6b91b877,aca94252,9e0ba8ca,b6c01f66,e06cdfdb,714bf405,c1441252,4f3ea73e,e12809c6,f19184d9,81f30b87,8df8bf6,6c89d98b,ed4d2bcf) +,S(2832b5b8,ab82e932,5356ae19,3043b99b,ba4b6591,a750a174,a6303b42,54bd41bc,c0363e03,3f59f149,23ece534,cb86695,a8275224,f490849e,249e63f7,34aba440) +,S(5b57c502,4b5c1621,77cabe39,b0f36bda,d85bd04,2736c7ff,9395f0c4,cbe43f9a,842407,dc0c0473,f1bf57b9,b35d84ed,b282ed4c,7adccc06,8530c8c1,bd20766c) +,S(b384da70,8063758e,825bf821,196b4a9c,814c45d8,a9edbaf3,dac4cbb1,c1c2f103,e6e661df,6400cc40,74f92596,590757fb,aa237515,af30ed13,df30befd,230fa325) +,S(36ffd991,563e448a,9b0a5da9,61a5466a,82a5b672,15ec8f8,e7300c5a,5c9a5e1c,97067835,fc17d47e,94187320,84d722a5,d1a742d6,4b513b6,32aed897,bb961c) +,S(8367e452,57c20367,e4e60ecc,33adcd87,5b9d142c,c6c362e7,f5aab34a,ed89d81c,fc7ff090,3ffab26e,d38a9e74,df43819e,b77ce2d5,bbdcf27a,f1f3bf19,948be121) +,S(f6ce47e4,8cc9296f,b40539e2,41238658,4719fb9,d4b1ad17,9c98969b,dcb0564b,368d2b6a,fe5edc0b,6f159017,5cd192ae,b524a606,7800aa60,930d60a,87950e1c) +,S(438c23e4,bedaa6f0,527d20c2,a725645f,194ccb58,8ff9eac6,5091da7b,f9fae013,54620a30,c7218257,dbdc93b5,3722a213,e28dc6bf,f8e48b45,6d6131a6,92ff15f8) +,S(1cf672f8,cc9434bf,7ace8722,85db5017,a1fa1dab,2eec7fbc,84e8492d,86bee7bd,d6d23d25,8bb4dda5,957ccced,b767cefd,8932b511,e2479018,16734bc5,b5cafdcc) +,S(47464e12,b0fa29b6,6e9cd157,4f7155fd,94305263,8af28bf4,4325a23f,3e1a2861,209a41d5,3bcdf566,5e966e80,84869a83,a2468db0,a1b19e56,81da864d,a2b05141) +,S(a9adfba1,c884c904,e6877a0a,9bbf73ae,c4ee223,e0b02ff8,717c075a,6aa964a2,ab16101d,a7bbc35c,73f371d4,afeb527e,b2d809a0,8487a36c,6cfae404,83f79dc8) +,S(2932fede,10600312,5ac983dd,659ecf95,824421ae,5f417f97,d3101c6f,c58edcbe,8601a743,e666156b,f2e34fe0,6f4cb11d,2df54fe1,7c842176,e1075423,dd76d727) +,S(5abf5528,2f87ad04,202b62c5,8ff7440c,64f9ba39,e6989df3,e31d665a,73a50216,71dc4e16,f2705c02,2ca1b37,edc5ce0,610b6f57,282d69c5,d3269295,5a1fabf) +,S(419495d,9a121cad,41887fc2,82c2c7e6,f359cbc,d24093ec,57399c3d,a801843a,9152e197,40295094,11afefc7,83990732,d5e6617c,d8e389d2,956536aa,f73e0c31) +,S(fca38482,ea2be49c,3c27979a,5acbb158,a902bc4e,226f7eae,4165ab7a,29fbc3af,1260735e,5fe62664,90a35f0f,7296c441,bad50a75,7b00e34f,28856a6d,cf46f5f4) +,S(bcf05123,3d703688,aca13530,55bc3ab2,d499ec40,8c912de1,4b7af456,55065d06,f32657f1,645690b,35484e63,a3456885,c16d4991,7670e71d,5f5cb65f,a5fb8bf9) +,S(4e70b42f,6391b424,b159cf74,f5fc96b2,68bf6cc4,a26658e4,79dd8a4b,8e9a92e1,8ba78811,1af31c06,77b24fa4,4b6ce356,66c595b2,3fe4fd36,591b33f7,e53b3688) +,S(3fe853d7,331c60ea,c213703c,a7628dc1,3cdb83f3,8a25ce6e,1be84f0d,e921742f,fb7dbb77,c2c6dc13,6f596154,f24dd3,f27b5125,9b60476d,b230e54,5ddca5d6) +,S(d803377f,c3cadd40,a2aa810,4e97641,ca42f582,3ccf65f5,ee726349,f648b9be,6357b84f,281a8080,54ab7fbf,ecc113ac,aeed2118,5ad12900,d824719e,8fd6fe99) +,S(5ddfdc7b,6f9e7162,2b7128e,77fa5ed2,90a05114,d6d8b845,94106c9e,70bebe1,23eaced,fa1efb7b,fae74c81,a1d03066,714b6dd9,1198e1e9,d5911ee4,55cd76ad) +,S(5f150243,c964948f,e91353e6,b12d167b,7913b46e,d7214411,5bc4cd4a,3b6f7dd5,36abc949,7a2fd102,14991e2,ba360c4f,b18147cd,955754e5,71cdd4d9,b8af903f) +,S(24b4fc97,5b0c4429,7a4cc89c,2b127eff,539f022,61544e14,97969bac,50942647,bd3e3fdf,54ad07d8,5faf8881,9014a77b,11d96f2c,a43cb8f9,a823a257,9eb5c207) +,S(a020eb35,5556b5fc,9de5ba2b,28644187,f11b18ea,ae61e76e,1dcce55c,e42202e0,9a71ea1f,1ad2f457,16b667c0,a982e2b,9765ac6e,beb71880,27e9059d,56639f66) +,S(60b79064,f7173eac,60531de5,961c47e3,8a224c78,ccd58a0f,86f6afda,e1f37a68,3ad04a4c,f6a47d6d,6b9fcbae,d8b54a7d,3437e4e3,627256de,cfc5f38c,490786b7) +,S(835cf1f2,b57d1e54,4ac2d915,9c8e3fdf,d2e233b5,d1109685,1777b7e3,a1f7d60b,7d23dd35,136edb13,bbbf7733,9e1c6e01,a7112f95,7c929b16,1665ca07,f6a84b31) +,S(faf74350,1f1edad5,2e1d8ad,e4b319bb,606cd7de,3188cdca,b1d39527,837f77ed,dbbeb0bd,bffb580e,4b9a0fa0,39b7acff,fbcd11b,85751476,16d48bdf,fe21bcc9) +,S(396c6fc3,e072bae2,3e7f74ed,f121271d,44091a5,d3b2a762,a39dd77,d2de938,5de522f8,a143544d,4cc49940,96b8f54e,9fb0e076,f46aa479,9e99d162,de6fa667) +,S(f8ab940,ad8df2ca,1c2622f8,8ef20c,ae8e605c,1e43b684,881147ee,d44ab88,99fe5281,fa7427ce,c9857163,f804c429,630d28f5,33e451e0,4063e70d,ddbff796) +,S(a6202868,af6dfffc,1e122219,a829c374,8197af4c,95901e78,75841b46,bd772367,2607a20b,c82a49c1,4fa54eb6,f8d68d8f,fe9c4fc4,d83b0e4d,145f7bab,5e9af45) +,S(b12d1993,49a98616,90764484,23a4fdbc,cfbced5f,b76a2bda,4d7c4984,7067e41e,a66dd4e0,ac6c8ab1,29045eb3,f7014449,73fdd555,7001b7ec,99c33d,c2d75e31) +,S(8dc8f55,b4990f5f,c6cd3b97,b1938304,9ae0a734,5cdc9c64,fd67bdc2,15eb3b3c,1be7457d,62cc8fd8,cbb54cc3,88722f4a,c00ce438,c847c2f5,fa641119,e5435d83) +,S(2c0b7337,d1db9e4b,7d521c4b,36351f65,f128643d,add0c53b,1b6d619c,658feeec,e8a27b9c,eb7c1219,f7bdae62,c07cee15,ef765b95,3b082d9a,d8b99005,b39bad53) +,S(891fb4a2,50100689,a48a0d1d,22414ab2,b17ad692,bb5f0d0e,66d06c93,da3bab35,41685166,cdf43c13,be93c03b,c347f3c8,52d06c0e,661a4c7c,cb53e24,e7260f6) +,S(4a3379b1,511c440f,e7213729,de668ef0,39fbccb6,1f5bbb02,ed99ed3b,69ca1738,b12a3dc2,39e9191d,a89d75ee,db44ce88,17b3bf03,d4172b00,39d1464c,a3ac0f6f) +,S(b8b2a7c8,54936bfa,62da360f,83bf8d65,7dc58e3c,1c8780d2,2c57061a,5f815521,8f922c0b,7719362c,25ac7001,252a89ba,1cd4412c,17c2b021,c065a3d5,f6a2d15b) +,S(9066fe19,d1dc52e5,7a9341d,77cf73a8,2fb56ab6,22c97a7f,f0191247,db9624fb,23d19b43,6ec3c575,d81d4929,eb6789a4,c281f5bc,abbc896,2153e7d4,711baf50) +,S(bf9ab14c,19c9e9b1,ca1a18df,2b5b73ee,9f32c8de,6e6757c2,b0534d75,7cced8ec,ec969923,3c3863de,aa72418,837a3af7,85e79375,d5bc91dd,481f174,e9759c0) +,S(68b2686f,9c654a02,225b7e69,e8eb7aaf,78c65686,e885b1af,10265e35,316f9d03,1d3d7504,846826bd,8554d407,739272ab,b6b407d6,f4f7419a,f284b81b,f14da9c3) +,S(20dc8385,5251a21a,94c989d3,92c9f36a,4d3bf669,bf7bda7d,e0427003,710bf2fa,217e6ff,713d329f,f9080c4b,3608c877,975d6794,5623e24a,974760f0,95aa749f) +,S(f0beb49b,555d998c,a39859bf,8c59184a,5c822e46,9a875568,1689a1ca,b5fd0368,e0e05ae7,a23ddf94,ba33b3b3,a75d3f4,2e8ff7f0,160c32f5,3bd08b40,72664aac) +,S(8f1aa973,270ff9eb,a41ad8ab,f2cf4c44,16ddc1ca,dc8a62cf,aab5a3b5,c4a0ee57,90aa3660,e3409b17,a86a441f,12f6eba0,2bd6bbb0,2b9a0a87,71e30a6,595920ec) +,S(c71eb135,278dc147,60cca847,a934b880,fecd43a8,aac9dfb,41382283,928a9957,41667f77,485281b8,89307ad5,decc7f6f,51d23ac4,7e71b299,a9d8715e,b6003804) +,S(e900726e,50d66a9f,37d09df5,d4965c5c,fa904d3d,bba1d180,b0fed651,bec41c81,d520aa30,db036f40,b34e64f2,cdc7d7b3,117f7725,786e9d5a,921c5f09,71028e39) +,S(940ab0af,a15952a9,ba3a6d6b,720efde6,58d72dd7,4f87cc3b,edae63b6,123fa38,fec6d747,6f788a19,b85e443a,a49116e1,6e5061f0,53c40702,f8765d28,f3bfcbcd) +,S(9a13de6d,643e9866,4df3ce9d,412c5ce6,a03ba46a,640c6be,8b62e70c,a8c76949,42388296,6c2d8d87,8b4c914d,4bc6cbc9,a4601630,2eb6a499,6103953,6926dd5e) +,S(438429b2,b31129d9,4a86b149,7d7f62e9,b76d6a5d,bde09d6f,256f83ba,76c577c3,e4360186,a7229be1,b33cb600,be833bdb,b2398e98,7c46c6cd,2e44f932,5cbc1c7d) +,S(3f63b25d,66d472e5,fac7b524,e4300e97,c8bb59be,6a3a8f01,8c1677c6,96d02605,4587042,158e19cd,2bd19bbe,5cff2c69,d9971aa2,fbdf649d,44c95f3b,50ca39dd) +,S(661fdf7,17c7a520,a384f90b,98dedef0,47afe5ed,6cfbd3d1,e1735c5a,bb8cc0c5,bd9a243a,b43c0e19,2592f00e,a52f820f,b83b7433,b1d96549,d9970293,7da80abd) +,S(b9c1bb26,daac6af7,d0c27c36,7ea2d4c8,c999d7c,75bc58cc,279c5f89,5ab951ce,a4d3bf34,a42b86bb,7c66c5b2,eed5d7f1,b872d17b,b58c938a,767b87eb,1b140f4e) +,S(cf5ac4a0,fc6cd9d8,50aaf473,3efd2bb9,7d9b23ec,bab5d099,9b11bfa0,b127e8fa,44926316,c37f1718,7fa94fe,3a62caf5,ad465d77,fd484287,2caf1605,f91070ec) +,S(aa52b2af,ab8da32e,3b882c57,ff0a34fb,749caaa1,b3c29b74,13c86471,beb3b422,4b562728,4a7be595,1b68df35,e320252f,73326084,16c60244,ac4e3ecc,c0859ce) +,S(610f22e,b3aa08d0,a9f2909c,546896bc,7926b056,7987217a,d347f183,4868211c,a52e190d,f35fc4b3,19571e6,166eda3d,2dbf637b,c27746ea,c1bc3552,4819e6bb) +,S(13f24c3,a485a58c,e0454330,79512796,db65f15a,4265fb44,acc3cc34,c51a6d80,faccbfb6,18e069ff,3cdc4327,cf807366,f07976d,b24fae61,1a44984c,7f3bc3b) +,S(15cebea8,49279b29,cb0112e6,922c5a85,caeb18fb,415cebdf,92285d9d,a0eb0f24,23e5ccfe,158ff9bd,539af7ed,4a77b1c1,c36de452,8d0c0d05,821e89f8,e075d833) +,S(2605a18e,fb7d5367,dc41b1d6,24d61a,cf92e0c8,96f29a5,5f2dc872,4d97f6,8d6a6774,f111b7ec,dc58ae51,80ad6fd2,fd6d674c,9402e2f4,f944bd50,5e66d375) +,S(e588e272,a78756f3,7fa36d6c,d35b362a,25cd0513,3694b56c,33d0b05c,be7f9995,15beb983,20b84296,9b8715c6,ad23e53e,115425c0,d071917,66e56ffd,5472fbb7) +,S(80032522,f264edc5,b6b205cb,f79ca7e,3a02cc39,93458b6c,cb98750d,bd6b46a5,479c92f4,fb4e1eba,98f8b93b,5aa9725e,fd2c1de8,d4c3d043,bca7183b,851a44a8) +,S(950c040e,e1a581b5,70501308,a21287e7,94b525b7,f916d3f3,c166a2fa,1641bfaa,e43db20e,911d70a6,9f171725,f760237a,52441a88,dc385a75,1e4ef1db,b738ea71) +,S(e899ff36,423fee57,2e70aeca,db8bc0f5,a634b9be,282dd875,9db5500a,86c391fa,7ed97b0,dfe6b68e,26710034,f87a911,88611790,cb18a790,a0248c7c,b43a9bd1) +,S(d236688f,c206b7a,8f8ce5c7,66e19fb8,6a7415d2,9c57845e,8332a5cb,d8a1a51b,72f2359f,e3d54a60,fe6d6508,5183b525,d5098887,55219113,adb05c2c,656ec9e9) +,S(8d3d7c71,da4b2f24,83e458c5,85c628f5,430eab5f,ddc2686a,e94e2fa2,119dcccf,33c408e4,7948f20c,bd79c22a,d647ff1e,1f435c03,1f594aad,82778f58,1f61178f) +,S(320f137a,e8918199,51a542ba,5d1063fb,fee4b750,c56168a5,87d7fd9b,b72651a9,b840546a,e2a4e1ef,32275a02,153bf003,8603698,a8c5e232,6795bcf3,d3c402c5) +,S(9e8affce,3fe6b259,f4568607,2d46401a,7546c87f,9a46e0de,8ce577c6,1881352c,d0ea3701,d83b7f7c,260ebaf0,97236525,af8639f6,c53ecf92,73e77bd4,c29d02f1) +,S(5df465b8,1d353987,293c915e,a24121ef,daf70ff4,9ad2bf53,9bec72b3,c61eef64,3206c5ff,5ae4c841,58c193d,40f46083,8b38047c,f33c3e54,38541a7a,d5e690af) +,S(999cd326,a18c350b,f4861d48,826ba3c5,1312bb39,886a064d,6e1465d4,8ef28f58,2cd8ab2a,d6dccdf6,7998e662,99551608,a9fceab0,be884b0d,d418911d,c8b1ef12) +,S(81d8fcee,574d9c16,fa2ba6f4,255460cb,479a6667,4761b4cd,c0ab026b,6bce163b,594e7f34,f5897a6a,3b79a996,f5a69814,3cf771fc,fd7c8ca6,38cb4ac5,98673143) +,S(9e83d724,b9ac73be,f932b42d,56f85183,85839c9e,c953a0dd,4da6d843,d096d278,f8b18cab,fed05acb,89efda95,ac496ec5,d3a000,a4a1d689,a1afa5e2,30c88869) +,S(98ba38b1,3b443c08,aecb1f64,73b2d901,908ec33b,35baa317,64f91144,3e320c3e,343f61d7,fc2232fb,f5d2f972,e6f42f49,d8ece7a,3434a0a4,4df1d602,3f99b84f) +,S(2092ea5a,9adf5eec,5a7a9488,6e970671,5822447b,e6c35285,de704806,52a875ec,ddfb72eb,52382722,a94facc8,e2616661,95a7e9c2,6594228f,304adc7b,ea4e7f35) +,S(f9ee909a,8f45a05e,ac77bce4,ebc97410,c044c639,95a1de76,5b9304c2,2eeb75a,861031ba,93f5b0e8,473e50fd,2aeaf13e,3a39c0d3,7e2e9d51,a41ee4ee,1301705e) +,S(a13878e2,3bc55a7c,b342dfc0,2eea9bf9,5c676e27,c63e8603,c75ce535,35df101c,35c0ced0,3d4bb091,92a2f83,3d3e81a6,233f0585,35c72ed0,1bfff82,7b108427) +,S(e8ec81d2,cd32dfd8,7284cfce,9d80c03,b863a7f8,3a71865d,34f7b1b6,104ae3e4,60be9b77,ee12dd7f,f532b01a,f517bfc9,1d24c4e8,b0865e4e,c6e27227,417648b) +,S(f07cb255,1529dc43,3470b18f,e4e06390,d48e9898,69b9a97a,6642b898,1cf35b60,bd46eb77,6d74633d,59b4b941,2e2355a9,c6e85421,59513d2b,a3297a6,c223b550) +,S(39bce423,dcfda9f0,a97189ae,a60b836,42becd3f,2f2cbdd8,2fe884da,baaf7f51,c1599caa,4b71219e,74490312,7303ec91,f3430be8,14979a2b,2db78bb1,ea2c8e4d) +,S(6da611cb,d51db814,18b3de21,13c9e4ff,58142f67,cf2d8ec8,e0fd105,1e9ad3cf,6bc2f048,3250f654,fdbd494e,bb03480e,f7fe5568,2e19cd70,4d178ff3,41e4b7f) +,S(cedb9c03,8d2e0eb9,8a4a5e8e,fa7e95c5,f4e13a47,79470c70,9a3c9fbb,8b1aed8a,79a2fd31,de42d8bc,820d5d56,ed084f40,46804fa5,f7f5e8fe,eca6ad4d,859a0d40) +,S(7d895498,6d1106d0,32f40458,f6c41fe6,25393f84,d00ded8a,3a07a107,5ae3d82,5d4fb6cf,ff1c594b,61aa117c,7e0ade0e,edd110c2,b2109866,ee7d586a,1a6d0d61) +,S(a4f29162,737043af,eb1e2606,93ecec60,851aaf50,c6e9daa1,75a00c43,d7dc3df7,beebfce8,fb764b15,38fabb20,145aaed3,92265d7b,c4628846,b2726821,c79c4439) +,S(b6389dac,de4ccb08,ec0ce964,e689bbcc,e0ba8165,6680c0a2,9cb162f0,f91cab70,e440c7db,d2d02474,17b2826d,28e31fe7,9ee836a7,eefdacdd,679040ca,50303529) +,S(72ce6dac,f752c36f,978ac2d6,aeef37f5,ae4ee016,999ccb49,27b8aefb,f6fcc9e1,ce6ac297,bbd84403,d60c6d4d,5e01027e,8ad38acd,e796bbc6,7c45f10e,d79bbca6) +,S(efad336f,cfd7425a,560931fa,a6bc50c1,4fb3e5ad,f8ad175,31b13846,6c255f06,3fb784f4,eeee9a11,ec7ab559,71817163,9eab6b09,4419203b,2b422e8f,e15a82c0) +,S(f98d4a2d,4bb2166,7c74bd1f,393ca57,22002c6c,f382b49c,2895deb2,34eaae3,9875e31f,7e3778a8,34750763,c6147cba,97a26f8a,d669e69e,9a36cc45,b56fd148) +,S(768cf74d,2bc24233,2c5eea34,2ac13ed1,2b0d161e,65876eaf,b0b89460,c934183f,42337607,e55b4d7a,f86e9f72,dd06a550,af083b32,e72e6265,4ba00fa7,a2fdc34e) +,S(ac26f3b0,1d05c625,915ec27a,aa916d0b,d34cfb6e,22525c59,9791274d,a5beff7b,e36760ac,89b61681,d1913bcb,1ebeb199,a3005576,b8bde54a,42fcecdf,e94f4045) +,S(dadd4181,741a0be2,e665045e,1b042a3a,fcd9050d,a08d1285,21298f34,1f74fbac,6cf46fe0,da78dd04,261e4e2c,863574e7,f6a4dfbc,a902802b,8056e00c,e4a84f60) +,S(e5651598,ce9e6a86,2fb139ed,143f1b73,2c4e1eea,91a88f82,a6fd0ab9,1a86a3e8,bb421336,69ab6c10,109723d8,ff4d5f6c,770fd8a,d569a21a,9e9efdb2,f1f1ac98) +,S(f26f791e,b4f0f596,39b69b45,401ee3ab,2d47a2b7,dcc3d65,de9e48ae,270f5b02,22e34b25,1fe5bbf2,5183c799,ea45757c,2693c591,633a84fb,e1a9bc0b,470ff699) +,S(a50cf10b,95612f48,7a9da048,a84dd8a3,2d2bec22,9db798ac,19fde68e,623da9da,50107d3c,a76a264,1db9f9f4,7cd60598,ce345ecd,cc3de888,e4c81553,bdcc576) +,S(c74883b9,2736c1b,d5f86a5c,1817cb9b,e917e5ab,5ec5cc10,a1197f1b,a45c13c,e03c43bc,e7393cff,d53e73b,60ea2759,d1c2bd55,c2b7a32e,847f4bd1,2c8beedc) +,S(a3437d0,1741ed88,bb05c00f,629e2c8d,be7cada4,dd002e9c,98dfe800,9e1c0a9,a627e05a,257fcabd,1fda00af,a4d3eef8,fc268e67,bb41c9e,d2160713,847bca1c) +,S(a6cc4988,f179bab4,de98ba89,530686fc,90c00c77,4a3f093,8329ffa3,99c8312d,f4eba473,7db25a79,29bcad7c,11346471,bbba86ef,4f611643,712ff475,9d70b6df) +,S(efb34a8,f5778d57,b3333077,6ca1abe3,9e680183,13936f24,da1aca,70b84dbe,a94a216e,fc53fa98,320878e7,167536ba,7e5845ca,149b2595,2f029878,7f428d3f) +,S(139846d8,1385e6bb,b23914ef,487fb9ab,19ec3b8,3fa45a94,a2c5fbd6,fcdfa07a,4fb7cc4e,599b10cd,a99f6aff,28dfda0b,62d837b2,e8c96aa0,9c34cbc6,acfce099) +,S(660923af,98ba567a,83df6eea,ab53ea62,49c2090a,13299bb7,a538cdab,adf2a101,b28b58ca,b1a29722,699890ee,8462f440,ee2a5686,9715478d,4460f0d8,8c94bd29) +,S(f18092b5,8c7517de,3f389d31,f1a6345a,d2f86bd0,c1dc9a98,d3e03890,f52be3c6,a83e7a04,91484ed7,7dc27697,33b0321c,440ca763,2a36c6d0,7e8a9afd,68f9c906) +,S(e8d0aa0d,1b2c540f,38a6a6e2,5b5fb295,7b700467,648cff74,bfee1138,81d0ab75,a324cbbe,52055c1b,d0cc3f29,88a80982,1abfc0cb,feaa56e9,f19bb8ab,d314409a) +,S(2586a0c0,230a0743,f9613df,51f7463e,1d8ee72d,503025f3,c7d2dfc4,6f526c1a,a29735a1,eb2b470d,43c7b469,4850f5c3,ce9b1da2,47406653,ede03ac0,9816c735) +,S(217cfa88,8d826d46,c31bb2d2,7dd7c8f5,8be68254,e42c0e48,a12cab42,677dffd8,4d5d9c30,9ff0fb15,35f9901,7af91ded,34179c57,f48131a0,6d96b6a,c01ac4ce) +,S(4ea65934,71aa3b8f,9e6791eb,37cfd67,943af3bf,100d7ccb,8203a353,1aedf4c0,feed9ac4,19a302c4,58047403,5c95e997,ded8a534,c88beca5,6c12984,84b7b4c5) +,S(974b828b,51026aa4,ea522150,c497eebc,7d7759f2,c9645f7d,4faac24d,18c7a1ae,c0369da0,c3087336,2566f344,ca81f261,65cd3a03,fcb05093,96d18fed,4faa9d26) +,S(d9815b79,d572d7a5,94dc8ae9,3cf45b36,99bb4544,ed1d5755,529c7096,9c978186,9fcebacb,f5181954,ac4ea24f,508fa67f,5b6c20d8,64ed53ec,d67e358a,e75241fa) +,S(52712597,d9bd4e7,cbd506f1,bd65aac1,478208bd,f9f6ad38,efd2b30e,b8368837,52eca996,ba2cecad,9a0911d1,65368010,68bbf0c1,12d6dd79,aef23262,8b3df18e) +,S(d94231af,d890f5f9,ef70e1fe,e8a8f4e8,ed2fc89e,2b8ad818,6af55de8,449abf6d,26592b6e,f0789218,273475fc,32d865cb,84278ff4,8cd0de27,e0646549,219e2867) +,S(64851231,7a69d956,3b3a99d4,b763eb9a,b661f7b0,714d34bf,e5328a4d,a99a7d90,eb20ba33,515040e3,6fa02088,5a3e9216,1e06d3b3,78122fb4,af4920a3,51d46bc6) +,S(d0a4b11b,ef662f17,98f413a5,fc062567,70df9edf,ee00217,79c3811c,ef68a8c2,d4bb9920,18e16945,c38ef5c9,9ab39eeb,748b7a63,ff4d4dbe,8b329f74,dd70b9cd) +,S(1d89b886,c4b24868,1fbe103d,dcbd76b1,dcf54637,3bd5249b,3dc07f06,985802b6,a339ccca,aacd1057,7e36056b,a3a70c6a,a7885a45,42bcdf30,30d0939f,6369535d) +,S(b6cecdd5,936343e4,f136682f,a38ba0b7,9dbab223,beb0b6c0,10a75cb2,e4dbb256,2935c053,87dd87a2,5bda5d1f,ed813666,5f77d12e,8242dd58,3ba8db03,319f7be8) +,S(84b244e0,a0cad847,35ca6c5f,bf581968,40f1b491,98682c4,28aea50,bf2f8e24,62e28e8c,7df80b11,f5713087,ee3a5d8b,148c8e62,da0de1ba,d8289ac8,861f7a71) +,S(f95eccff,2a908028,39436610,2e377c41,66433159,43feb6d1,638df6c1,cc114d1a,bd0da83f,1a0306cd,b8d1b9ea,189856ee,56d16e81,61b4f9ca,7de38d2b,e558eba2) +,S(7c4cedfd,3e613de4,af2ccd25,59a2dd23,2a1e6335,e410d327,27fef321,d10f55e3,331f2109,d9d00536,c697f73c,672a660d,11d4827d,41306696,cdc224e,e7d7b1d8) +,S(235c2e38,1bf2d829,e4b918de,435e276,f88af866,ed31a1c3,4b9f7203,a0269713,50dcdf0d,2671092e,e7c48614,44eaa87a,815a1304,4600fd0f,f26104ef,a0dbf929) +,S(2a961cd0,9ab50975,517ca488,d1c4a388,cdf2686,c5dde923,76128683,ea07cd73,85c91076,b2ee46d2,3cc0f7fd,e7654723,84f84c2e,edd7552d,d7f93be9,2398abe5) +,S(958bc491,f0afb8cb,8713f591,cbf183f7,e00c4775,93d1b51,a628f40e,4cfd65e3,bf5be339,fa21dfe4,9113e026,af0761a1,b2a09a7a,ae8f6eef,92d50c6a,89a65b3) +,S(6e960ca3,7b5b7abf,99f5a2e2,46b7e953,adb5ccc,6424e73d,dc865bd8,3d5f78fd,53ad4bd1,d5e9643f,5f2df612,ea16fcc8,dcc4b0b2,9ccd5a81,bd659b35,6a5e0e15) +,S(d7ac920e,9272bbad,dd961525,7d91d6a8,e747e4a7,a48ddb5a,8b2ece8f,f0d05871,6381b9fc,c37bac5e,38c0b96d,c098c3,9d4c7620,61b66dc4,adf66e24,f0c87ed8) +,S(9b0803b,1de95706,ec123844,ebe941ae,4481c12f,f2d9c078,b6c1d531,5d730609,160cf3d6,b12afdfc,eac2ed01,fe4b801c,5a5ff0bb,13cc3ef2,f5f0962a,6b3fb1b0) +,S(5d50746e,5b74e006,9dce0153,aba04216,991bd509,f022f3ea,689553bc,a4c5fd88,b0fb205f,d2a14b1b,bdba2e48,429c92b6,99cb336f,b6ed0e58,9276118b,6b259ff8) +,S(e1bc2669,fa27629c,92708748,36008c2d,ef4483ab,c686ecf0,bbd01a85,fcbe04ff,6fb7af71,83c0921,6173fd43,5b3a1b2b,15e8b149,3bed8e78,3d409f84,cd95ecf) +,S(cfc9081c,b5a893db,40c51979,7dfa1cf2,f36ac620,cf7017a2,fe90dccb,d8bfbf78,26a88d23,50772fc3,2f377c15,a9bf817c,db321d1a,55c4d659,b5f29ae6,96a69ac2) +,S(54d9c9d,12bd68c5,3961246d,b98ed78c,cd8ad158,8458d4b0,5fad9df4,2229bb9b,b5e97c31,1dec2259,630c961f,ed33d7d4,f8de7005,849225eb,a4549d76,de1cbff6) +,S(8a914ee6,7e9d6619,d00f1924,8735c7b2,bfb11eaa,61fe42e8,d64b5a53,43057dff,1b91e1da,3374da49,8bc2f018,c2a6fa51,99c51846,a2f59b05,a6311ac3,1bc040c8) +,S(d4b81177,3e641dfa,bc704fba,e9ab0ab8,aa2f4c42,fbd23b03,a0b0595,d0240522,ac30ce3b,1ea4a14f,4a5bd364,20f40df1,cf2e6835,17107b8,ce6fbe05,665cc726) +,S(b810a787,c232357c,bb82c351,79249f64,6f3c8e2e,72e0e004,36226670,14780ba9,54364034,1078dd7f,216bac76,9abc8467,4a422c30,f1b7aef7,6a2dbbb0,158319e2) +,S(d71f88ce,dc738ef7,1ad691ea,c3a7eed0,d29c762d,8ec7ce0d,14e72d3f,f534a833,a47cce83,1aaaadae,a2d9d0d9,7b4c5125,97c1b514,95c3aad9,d2a4e716,cfbcd99) +,S(170cf31d,4cac628e,139d9d89,662ce5e1,1ad7092c,cc6c6174,96c99d71,6d147ffc,4fb3b894,e741f585,15e8baa,addf3119,adf6c4ee,695253a4,6f9a5dec,cc6d77a5) +,S(8e7692a3,b1275e80,38ccbf66,ecb9a55b,bfd48d49,4085b4d3,1729a644,ecc316af,f339c1d3,af07525e,26500665,ce66a91a,4fc0bfa6,b8a46411,34cab540,68c504b1) +,S(5d1ff338,3dda5e81,32c47002,ee2b77ce,a07ca869,e7684d40,a27cbefa,4aca891a,a1adb3ac,b0decbdb,6772e62e,74c4516,fe843833,8d2979cf,5b091801,bf5fbb8b) +,S(d566cfdd,a9dec66b,ddf2605d,a37ad558,375e1c5c,5f5403eb,d75ff6ec,3c2b8af7,13e2232c,78586da9,741598bb,25a90a4c,b6007bd7,bfb75ed8,427ade0e,619c78bd) +,S(cbd708f9,cc713af1,999ae74b,2b9ee3db,3cb85bce,249c5e33,764997d0,2fd96493,f01a1d6c,4ca9b0b8,9337a5af,889d8dd9,c264f4bf,6b8066d6,55cf9267,684cb2cb) +,S(fee1ece4,e8ac73c8,8220bea2,153800f3,e8d049b8,f89053f4,ad4b5ba3,f0ed0fe2,9b5208ea,17c80640,a353354a,7cf42f6a,f9763db0,bdb0954f,53d56a2e,ea26aad6) +,S(c6aafa66,de444853,8d7a6c3a,fcb35a8d,db916f33,14c15dbb,79c48bc9,46ee843f,8a61c6b6,7fc590f7,bc81a761,7a6e24fa,34c49d5b,30b11bfa,7cdaf3bf,d1505b1b) +,S(ac351560,83d91f7e,4898551e,7666bbce,dcbe21ff,f005ef1e,a866781,d9aac415,d709d997,77109afb,28c318fb,eeec8a27,5577410b,8da6d494,5ac7d660,1334483d) +,S(a89c2616,7c024b4,81455d19,93ac04f5,7a212e34,95066ef9,21968f72,3d914e18,551d3662,6127866c,77df092f,5ed8dab1,3569ce68,433de199,ac8219ee,13a3c1ab) +,S(9951831d,b58499ea,e94018d8,cfb9162e,b045b95a,fd246a3a,72e8808d,1ca3f06b,fe39aeec,b9d5f867,d5827146,fb384808,81696ea1,5b0d1188,fd487b16,d9e4d773) +,S(b71e17e0,14564447,955be26c,61ecebc6,8615e2e9,37cd2e8c,78d26922,681fba96,ebcfddf1,d21fb8cb,95e3cb22,4efe9553,1a6c5ba9,cc92bdc4,3011c50b,63b9e3bf) +,S(e170f81e,dbdd9ff6,d460ef6a,1c3d4bcb,2fe89fed,4e6742c2,2d683ffc,15914074,93f110ee,f971cac,8ce206e3,df6f9caf,801fa7eb,c7df14d2,d6f67e72,ab96e67f) +,S(431a5547,318d05c5,5ecf04ed,a1fabbb1,4ac8dd8a,47dccc73,acf5d5c8,1ec104f2,3e3188ad,7b141a36,4afa1f04,57ca827a,7a6f1f70,75ca8dea,6fd08bf2,bfa779e7) +,S(299e6a6e,e1587523,2be26ce4,a1f80cb1,3c193291,7f0b5eec,383ffec2,62203394,5dbb70ed,3ad4a211,bfc8e8bf,4c00a055,23c9b3e4,ed3790c9,3bb2a77e,5301575) +,S(66db488f,f2b58869,b2fb5f78,61e7f825,bc99ac9b,ea02b59f,b0978c9c,c38934ee,ab76e112,b51c83f8,b10e997,2f6866c4,6040e7ef,eb14817f,c316b730,e8ae6a5f) +,S(1259856b,66980d52,bb3912fa,78ad5b70,54c812b5,fed402a1,c3c8247d,26274932,ead7cd3f,c67895c7,edfe0557,d5681bc2,d70dfcbb,870c7c22,45d458c7,f2150383) +,S(502c8614,cbb0f3dc,caa5272f,dd252c7c,4269968c,efebecf9,102745df,fdf1cf00,711bc688,7e4e356,fd9d0695,16af0a38,1b2f4500,6487154c,10b90995,3bc53c3c) +,S(e051193c,323c6403,f69c1073,47b6b7fd,f43acdec,17c00c42,2249bcc7,aa8d6fd,2102c271,ce428ee6,16d1d2bc,f25c2630,c574d9b1,87f8b9f1,c85117e3,8a560455) +,S(c9187bae,d768d32,29fd90c1,5c3b37e7,abe7c58,b538acb8,ae0741,adf1dc46,c130d443,f9ebba4a,197d0252,615ac29d,5714f6dc,f27fc0f8,d7547335,89c92c0f) +,S(5b08567e,b9f3b3ee,2b03ae70,1c6b0641,23dba4d4,4e8297a1,6eaec8d9,e90fe897,ad071c15,9079c91a,cdee9c72,6e8f4cbb,914d4b4b,750fed92,aa81a987,a90c27c9) +,S(ae5b648a,c5817a86,cfb06a26,d62691ab,8a9cc554,d0eaa86f,839f4a51,b43ba7cc,1ea8ab0d,b665c22a,ab0a48c3,da17c629,66e75212,a6fe9983,d5e925d,432db311) +,S(3b9bacd0,a092856d,98eea5c5,ccc9abb4,4f2e0d3,27e578f0,42102148,890178d2,b681e88e,9603ba1c,57b628d7,ea929ae0,b79be447,f181a491,1fdc65df,21bd5052) +,S(524df580,a74066da,d522f827,95e415ab,f6dfbf7a,1c1f6d7e,e8d05a86,4659fef4,3facc728,5f3bc1e1,a6fc210c,ad302ef1,9c72c5f9,e358b9c1,ed2aba72,2652f35f) +,S(2e0637f2,ade775c4,87d09a38,3480b875,599a34ea,7fc70cdf,f6ed309d,450e4363,e3c6eb08,7e2f4e49,cc78e903,e4ad55f3,1aafb7ee,ada72369,6da8a0a0,f764738e) +,S(f7fec6ad,beafbd3b,e413fb33,587b9427,3f785728,226f764b,bda6130b,aa0cc483,f646a974,8eb457c7,fc8fefd8,e63b976b,dd42093a,e59fc544,c66531d1,9e08c68d) +,S(75f94ce0,6af64c43,2b6c95b1,2d892dc8,cd6eb497,4d826299,29ad8bc4,8a3608be,bf8716d0,a2b7906a,69316b32,21ec0076,6e32c892,2c7be6c6,22e8877b,b1958a29) +,S(410296de,5e0df3cb,c4f039f,cc869090,f62e07e9,d3011043,31bdc1cc,f3fb4d85,e963579c,a314dd96,ab8a82ff,86265b82,da74267f,c861f96c,383f72ed,3ffecfa0) +,S(cc824eac,5f5e16b,2f7c1703,d97da67b,69b4e698,16cfbb23,cbdffe00,d73ffa05,17c30da6,9f414ef9,5dc58218,27c7880f,d18c6f1a,92afaaa8,b8cf10a3,353e8abb) +,S(acc1b0ef,4d26ed8c,d78f0b3f,d3177077,d2074b64,fa5d8d03,a83ff113,7e6e5820,6cce44c6,8519ae91,19d2a80,4f8fbeed,4fcd24d0,169e8000,11150c8d,9c3ce6c3) +,S(1cb3076e,ccce1d9b,774bccf,4318b921,583c2b8e,31877825,7c2fc71b,c90da922,2a2f276c,58605d,82a17dfd,3ecdc5a2,a6372df2,cf25bb04,c628748e,4ce373cc) +,S(6efda451,2a22f49b,587ea975,9e5a400,8cb3a521,7a38b978,3d5825aa,84fe13f2,11d44ed5,6dfe2fb3,1ff2a54a,de5a2a5b,60673cfd,bcbd5039,54a94758,878e2424) +,S(47f69619,aef4378b,5cc931ec,da8fd996,e2fcf1cd,17de9cdd,51b30c3b,9dbf0858,149556a1,9776e3d6,da457af2,a4d70d66,d2fa28a,c33abee9,bf890894,7cb5e274) +,S(dd3d8e1e,97f5dd5d,539032c5,13a19e26,8b2eaebc,1a47cd4f,8ff48335,794d28e4,7968bc00,20f6a83a,a973d7c6,382ebf33,c2233bb,34be9c2,e0ff9eaa,4c467e83) +,S(2bd454ee,a19d3a6c,be55737c,d3cb4b32,7de2a2b7,50535f91,97aad2b6,65e16d78,a70b0f0,d6a1278f,34271c66,7ad40feb,9f7c6248,87e3f754,9c1f1fd7,129f7f99) +,S(8cfe75bb,2a7e74b4,4da035b2,9a26784e,915462df,13ac2d91,4733184,f5a5ee0,648ffc56,bdc87c86,4f6226d1,c9245540,b65c2da2,7fdadca1,eeff2e24,6607cd1e) +,S(5eff34ae,19c462cb,c2fdab83,24b57bc8,5e046a68,4f112f6e,665b3255,65724d36,198fb5bb,9db347ff,c2289629,d2e01051,d551e783,47c6a6b0,ccfcde15,a04d68a4) +,S(9aa54554,f3673b08,e36db624,47631774,a2c51bb8,1f18aa61,426639f,78f92b91,8744a3ad,4a6e7404,d2e22faf,272b50bd,1d167b46,5f25c6fa,75c8d784,61384806) +,S(4b837575,8cfb5970,dfc7463c,5df06ebb,ac88a2a8,b9d7565a,955cb53a,5ff259e0,87591d42,bda1a53f,6e474396,a1233df6,ed70766a,ab7aaaa9,9171a5e4,fa8df208) +,S(5d4b74b4,9134f90e,673f5a57,959c7cef,c49dc725,85734428,226cc5ef,76428bb1,1b2a8910,f466ee15,abe6bf3f,100d8da0,cdc2f6bb,f19c3cfc,b1f07a0f,bed89425) +,S(d50be2c0,c55244ce,5d93bafa,f62ee680,2d475441,7ab9c2b2,5702a309,57cad2d8,fe207e4c,6ee89ab4,c0185461,7eaa5de4,5a4dc0f2,bc4544e,f241cd5c,162f583) +,S(bb0f61ce,8e0eb384,64e48915,5bf985aa,f93bbff1,416db2e9,a1da034e,1075bff1,13a715,2ddeb0df,30ea1032,cbcb08ef,4e6b0561,31474412,631f6fbf,b77b7d0e) +,S(3ce6bddb,473f01b2,170e41fb,22fc5efa,63e22b9e,14d9bd22,88632bf8,4ddcb2f5,43086057,f4b3d298,426b7308,110dc52e,9a84268f,1bac1edf,8d47a25a,ace0922e) +,S(ffdfb14a,ef1680bf,c90b5490,c7cdb75e,bbcbbff1,a56c3c85,bd37460b,b38f81aa,f3045def,2f1f19e,232880d0,e948b5a5,24f228c7,3bbcca54,7c216ee1,eaf4af0d) +,S(1ac1f2e1,9ab4264d,8126eb60,a2330aee,c828d102,507ac0fe,d59fa4c0,8223172c,7636a4bc,339486af,b215e3a8,f80d8f02,d8fae063,81b4e7f5,133f1936,d8e18bf8) +,S(52534c0a,740e89a,6142957a,a20f2339,b1a1a6b6,7e6c9a2,2d6661ec,adec228e,cf6fe6ba,fe41c899,c1ec2fa5,d884fafa,e1a31835,ae8022f1,365a97cf,3261b669) +,S(40920285,7cd22c2c,78cdccd6,137d32b1,4f36f2c,964a278d,5b9f6462,651b09eb,40c94f73,a5fa3e3f,66dfef1b,f4f16091,f6b7738e,b8a865fb,3bde12c4,2d031d0d) +,S(8b1d3c33,4b9ccdb2,14aac6e4,e840db16,25a5b3c2,4069d9e7,c81bc51,9b029289,114fd464,2acf9599,1fd65898,57822277,8020769f,145f86e5,630d6db5,5e23e853) +,S(ae14de60,b7c7f13a,59c6bbd2,64162dc,8a6055e6,3d3460fd,7e473979,f4a242bd,8b960489,cdb5a333,a14463e2,376f2113,afccfee7,afa00ef1,6cac6a3e,4c65a412) +,S(f37f1c40,99c95e6c,3e8d4e39,5dfddbaf,b8153948,137de420,788386e,2ed3e3d7,1f290080,82f6ad34,b2283d76,9cf76577,a564411,4f51af5,310c0a3,b3fb3606) +,S(1fb07fae,9636889c,34441c1d,3c2496bc,a13f8933,666d05df,aa53ecb2,1b017a84,128189c9,3931576a,c4b68934,b7ff551b,58e6da46,fa97fcb7,b8df8c9c,637753c0) +,S(44d1eb54,e112eced,480ea2b5,1ba22ba7,2afb0721,d0d6b715,52bd9728,4815f3cc,a6e13b28,574c526f,12673e02,ed7938fa,ea1855b7,d5b6e88e,3c3a9b2a,f2ed7043) +,S(6980972e,5732b875,7fe311cf,f76f7bd0,ec94918a,759a7cbf,d8795645,a103238e,7b9fe832,4ffb9143,21776b24,a92fa09a,ac4a0fce,17c5bc26,2d2eb063,63d26a5e) +,S(6a3a8c9d,405bb1e4,de59639c,4f6406a1,a8566a62,9d85b79b,f7030255,50efcfa3,3e8abae8,7b22d04a,8fdb408e,196b47a4,2e0f59eb,9d51924d,ce8de66,cac038ba) +,S(ff3108d4,1598464a,bf5844c4,dbcfa027,bfb6804c,946c3683,1da390b6,4412ed0b,805565e3,3ee1d089,5c6abe85,77054648,11f5d4d0,219cb515,dc072d47,cbd0a317) +,S(ee4f76a,2f8549ab,3e134e53,335dcb5b,49972750,180491bb,2139324e,95517d73,6bd90167,22402b11,68989e89,9c942767,8307367d,8a29075c,8fe81049,7071a838) +,S(c21175cb,1ca958f,36a3b720,5cbaba0c,230c6305,8cd09966,ac78f51a,4c53e0a4,6a2183a6,7a7ca0af,256a0ecd,2c085d81,585a02eb,2ffe6a44,ea923688,cc72bf51) +,S(2d5e4c08,a9a0b398,34e46e39,e7cab91b,953141c0,c5f2d292,c409cbf3,9a37d6fc,7569b9c5,31a331fa,9234f37,e9005ed0,4b512721,dc4ef054,d6164046,75c6e15e) +,S(6302c041,bfbbeb09,cc012408,631765f1,5d573b67,6b799c26,ef7c2a4c,bb15dbc3,32a8f20f,67ce42a0,ac4ddfed,d0932e91,a1e51488,49e463f,915af082,7e491025) +,S(3e61516c,198de08e,f7dc9cfb,89ef9b94,5b6c67cc,2deab08c,a3b36612,5934e2d,1effbbf7,4d5f7104,f7784944,70f62784,5692f3ed,48e4dbe,e956e063,37520d9) +,S(a008bab2,d7d134d2,4ab35a37,8f330521,b8989219,108b05a7,d8aab0ae,e542fe30,77a377ec,903c06e5,463ec2fd,e9c05e43,f5454aea,82b99de6,be09fe31,51b475a1) +,S(7782ff48,b928962a,950f42b8,2e43017,28711467,16f22f8,c389917e,a624005f,78f23e49,38a03e0c,ad1b766d,b9bafe30,8ad2c9cf,5b22bc18,c78c8898,fb608c15) +,S(233b4a78,c26ab44f,d1019d64,8c896eea,f6ffbe71,8cfefc20,d20676f8,27ddcfc2,de508436,d976df90,487ddc1a,48284cdd,f553d342,2e0977b5,18f3ed9e,773b655c) +,S(8014aa29,6eed493,d83d7aed,2d8c3342,3f7a4623,295f2a07,92c5de0c,71b8bb0e,dc58729d,f2a5bc9b,1170caba,4856a9e1,695f39af,81a1e444,f3e6dd55,f583d92) +,S(8a01e90b,233dae71,1bb050ce,7bc61c8c,60882aea,ebead2c1,b284ab59,dbbbdfce,580ed75d,c9e3693e,92c06cc4,12c95a77,b34b72ef,20a51cf4,ca4ddbad,7691fdb0) +,S(50a2349,24a29158,70e6372d,582ba07f,a569881a,96bd1a4,4cbb9232,1ae733b4,6943c220,a97701d4,a79d8e2f,a446fce3,aa21d00e,2f7cfcde,3edabcda,678cc751) +,S(cbf49357,8c96744f,7ab07bd6,182640ee,b51b8f6d,a8a655ce,cbd2087a,eeaa6d83,4d1b36f4,5711db99,404bdb1c,9484a04d,29e79fa5,87d051d5,e75f07c4,ee8d4bf0) +,S(737b3d75,e4edd296,8d164c2e,828b31d8,7c63d11f,fa4ebd89,ad59ba71,8a8efe38,ec7f7ba1,8aa8e515,4527002e,edc8327a,ff1ebf6d,d3877439,e7c822b5,35f31586) +,S(29cb2864,251939ae,6c7f46d6,9d7b4416,8812e0c5,9aaa8b8b,b7e22ffc,ac38813a,c3ec280a,7c98b2c5,c96d77c8,b410ff1b,b5f1eb51,debd38f0,528bb73a,eca2e6e9) +,S(1858aa59,24282fbd,e44dffa2,5197954f,f3668954,24741d35,2c9594fc,5e28fe9d,a0e891d6,b0a69fab,9fbd7879,a7e4ab4c,be50b1d4,4be76485,96fec281,d2d4bd46) +,S(72ce7c58,1a420eaf,67bae314,d4f092e9,26c1378d,d346c4fc,2a9e9174,862eb75c,2329177a,5a9c3e0c,f6e236ae,30858bbb,8bec121f,f7462ff3,6284bde0,7425ae1c) +,S(34c1ca5e,5dfab6d2,4abdcb83,9ddf9bc,a3f9dcbd,ecc315,17bd6f46,af112903,93f6fead,c931cc97,37c4aeb,6a589a08,80088a24,eb49a1a2,7aca807b,22a1f803) +,S(7c5ac4a,80af5867,f803100c,cee3d676,8d348b47,9ce26243,284ba0dd,24392c36,a4468964,903be647,31fdb23d,1ea7ab84,a3201cfe,ab585b86,3370ea40,66fc5828) +,S(be2ddd13,244c7728,1a98851c,8683ff7d,b57bf3d,a746cb35,e594b7ec,4c363caa,adb75939,af8a2cf,1cf3e5b9,2bc7ba65,8c45ea85,47959f25,7dfe4592,3e580fa2) +,S(6dee1f6a,3b3befdc,a4a44471,d62dfd9f,7f7b222b,819979b7,901a1764,8ec13806,5d9e8501,4fa5f6ff,f8c0356c,eb013122,1a9a2431,f641ab6,af3b9999,5c2e5651) +,S(15f264e6,8e2c8ed7,490355b3,a7b11512,c764386b,f6bafc31,80ee6fe7,9de68c19,90574d26,302bf408,ef9053fd,371cf29b,c41291ab,a76ab74e,ddf3f8c5,70326aba) +,S(3d7cfbe9,4cc890c,ea592b78,5a984c8d,6d4c5e7b,183f3666,df9805e,be9c91a3,d55cddd4,4ea7065a,f8f51694,f6a84b54,42b30b48,e7630d12,6827dfe5,e7f62808) +,S(54388bf9,d7951dc,7ab5dd3e,74971201,1ec637b0,7febee14,45b1dcd9,9c3a1e10,17b36788,25dc2a5f,9bc8738b,3f560d23,725f99c2,a9d6fdcf,6fbeff54,aae5a547) +,S(3c229fdd,9a0080a5,948a0d2c,c9281794,425327c5,52063c94,be5f0197,6a088313,34975795,a84f83b4,af883d12,c373c505,192f0a71,fed21d8d,3a8dbb8d,2a926a1c) +,S(b612bb6e,e14659a6,e1691f36,8fa8d7ad,1974e74e,36f1ab26,15705271,27c63210,5948c5d,d623cdf1,f9477733,dd5e8eaa,5240817,e8e08dc2,23b6072c,a4df5bb4) +,S(ec56e585,54470dd4,28341ed3,e900e33b,ae381e42,2efb3d64,d2edefe0,7b05f613,ecd7f151,acf6e308,dfff2bd6,578bce76,86effe0c,d3b156d9,df8f66cf,295e9c45) +,S(1bef3ca,85ff9f8f,bd80c8ba,f9b15b26,a565eeaf,e4d4f08f,25ee748f,fc11f80d,fe0260bb,96be497b,a194b892,71bc8989,125f0a0a,de88b135,272c5683,f92914f9) +,S(1bdbac4a,522b68e2,a90e4265,3d2bf4ad,c4b27e5,a2ebb251,68a083e9,9107c20a,4d60e326,3ede7fa0,10467b9,d2e8b206,5b09e127,e3fba9e,3d228439,50d63ea1) +,S(e9032f9a,567ab8da,551e0f8b,1b2c2c22,6e601b7f,e894b837,3bd9eaad,3662fc84,ac563e6,47d21af3,a0cb0a49,dafde0f1,21d60994,8dcb4000,64e3196d,74eb70e9) +,S(7ce746ec,44af748,a5508044,f56e3467,a9608deb,c8a051a9,fda907c3,8f79c75,8f0879c1,3166bd23,be7bbb80,46f3c019,2c6b8fa0,52fad7d5,40640fd5,f2aa426a) +,S(e0d52789,19de6d1c,a0929856,46cd3200,68862dcb,ef369fc9,6c6de4c,bb59eecd,98f4679d,b4ebdd90,a4f54791,29740bd5,f46680f1,d3ebfce8,8cda2946,ca886b20) +,S(c6a245cd,cf1f4b58,4400a4d4,82f2088a,e28c8b85,641c1f18,a13aea,7e5ca397,d306dbb9,f8f2cb09,958ff944,ab5e6cd1,cb11eca8,33021bf3,605e6768,961ac628) +,S(ff956c8d,9710f082,a1f34ace,c99987fe,4ade0919,4a0deb06,a1b286e7,3695c910,fabec52b,866afd46,1fe8c832,fd8a9375,a8086aec,b0e2e39f,b7823d0c,13bcc306) +,S(549dda4a,d1a604c,d0f44fe4,5c4dc276,5cef1216,6f4accc7,3ff12152,26c23af0,71e3afc0,e05ba826,36eede7,1abb15e1,166fec97,562c4381,a33f765e,100631ef) +,S(66d3df09,21573cc,e69896e8,2dd91f9d,6070dd12,edc21723,2077e644,9e776416,93981613,59a2ee3e,d9429dd3,eaf058bc,9ccf1c9,ea931ebc,25ff279d,5bb46d5d) +,S(61bd3dbc,9426386,9c53ede5,a5c4f186,8a4d7a82,fae1be7,37b702f5,79e4f8d9,8c056a47,e27d4f49,2c9ddf54,efa48c,502aee81,e2336caa,c1b572b4,e082e780) +,S(8a6d8b46,4a31daa9,2702f784,9148db1c,4ef20c76,fa67c006,47d6f3b9,80178f4e,d1f406ee,e4087601,96c82f9e,38205147,c31309a1,93bf4d8c,cfe67cba,ae8f7407) +,S(e2b60e93,99eb8441,700aa90e,1edd981d,37893b42,5acf6b1b,809fd1e4,922e573e,68a0c65f,e394829a,8ae09dc0,ab35d789,bd8a38ad,800e9ed,63513eea,4e19f7af) +,S(4c76030f,e85cfc92,64f16cad,99dfa541,fc23b8c7,2b558574,ac6f26cd,d4f55e85,44b352d8,9a31b4ec,c8f9a574,51855f7d,e98c63aa,98aec090,2d959be8,a12b7bb6) +,S(dcba96a3,59103c35,aa2c9ef,538c13a0,2f0e8997,3663d580,fe454762,5fbaed2e,af9e205f,727698a,de9f91bd,75bfb73c,b13053d2,db2d83de,b4d14c22,176544b4) +,S(fd0497d8,f75fff9a,cbfd3e03,6c9edc73,e682427f,e9b66a43,3b5b2b31,f2dc7883,d23014b6,9c8d1077,ab3fb2fc,c0bde4a9,44576289,896de135,9c0badf,fcd62d79) +,S(5bb401bb,b38e413,43d1b779,54e83f9e,e705009a,eb8a1077,542cc6ed,edf48040,431fccb5,acec1391,f68ea628,378e3ca8,ca944573,ecfa5e,e7a82bf8,82599c14) +,S(1fa96a4f,f9cc6ad8,b2741c38,b35c377e,3acac704,67bc5d20,a262db5b,48bb283b,c3448c92,ffc65afc,f1eaf7f1,f9e149eb,6404dcc7,1b222ac8,bfca8feb,eeb963eb) +,S(9534aef,1ae551d2,7a638453,171d0a63,697ea420,2fec8f11,61432291,642f86ea,cd0c943c,38837dd0,33d48a4e,ca13e96f,46fd7f21,2cbff849,6432aac0,ef729591) +,S(ea72afed,43300390,bc98d08f,3aa4ff4a,138440bf,1a8f8b7,b57032a0,d01b8ceb,e174dd8c,3692cc2,9ca856a4,4eae7e94,af4fb044,85172809,25ea66d2,d858663e) +,S(39593534,3ca2523a,603801f2,abf3a1d3,16569862,35d79fa9,a01f86d4,5c122327,acd3e3e9,2cd76dc8,551cbf0e,94475125,42a5b887,ac6c975b,45d2e000,9953dd96) +,S(d57b2a2a,375e5a0f,6967d4b5,3dfbb51b,4f74eff8,72742a3f,246e3e09,ec2d4721,12d6f848,4d107ec3,10ec2091,3482781d,c0aeeb94,71ae7b03,6a0d2551,d3ed306) +,S(9f2dfc5,1b99eef6,e6c781a,fe0135d5,fc5def8f,d520119c,59bbaaf6,442f1082,8f20962,fd273048,fa3ca6e4,ea96fe0d,7ad1d758,99e25a77,e0f8b56e,5b20dd0d) +,S(b1c30bc6,f030c913,49b36c1f,9c0deda1,afa58776,58c5a16a,9352c1bd,229884b,f8a459d1,6e77888d,cd5c63d1,8a2e28cb,5563e727,f53b59f1,939390c6,1eecdfc3) +,S(8a663e7,40cad237,12dad6f9,1bb5d266,30542933,853e02eb,665e198d,a5c6e53b,e206b399,51175d15,daccf711,63b0918c,786a8fe,2077812,c0c1eee6,bb5c1e99) +,S(2b0956cb,e0ca91ee,f44fac0a,76cc0b00,5f4a5ae8,27e63696,fe1aa8b4,a92941a1,a31e6fa8,dd454eaf,90ee1e11,62627e3,3f84b8fe,da29f423,ddf2a962,386cffd2) +#endif +#if WINDOW_G > 13 +,S(e0144151,7a2ac970,eb6381df,7e11fb4c,6b009980,6a0d330,d5429126,e662c3bd,8238ce9b,a691c80c,21563934,18d18dbf,aeb3fd34,48863a1e,7f4ba360,408dfcee) +,S(be3213e,8b062f33,caf16c53,5a0b666,f344e0d7,1e28aeba,8b215a3,7ec86c37,552523ba,eaca38a4,cd795683,852a2643,550fb83d,d1db0adc,3f1b29c9,7d51cd1f) +,S(623393b6,bfbfbd64,fc7aa1db,9e58e274,1c18eb6d,b5eb30ab,c4fe167e,a9e8ff2b,7c0e4174,f0fd5bf2,a025e316,fa3b7b97,1339a197,b52b0b50,bad4dfe,34e42cd3) +,S(dadeb702,dd0a1e87,669eb624,b8cf40bd,bffe79aa,8afab26f,bc6215b1,dcfe97a,930890ca,e4c29b41,2d660acb,8cd39bca,5a522599,a1ab0bb4,8fbc38df,17253490) +,S(b528d3b7,83179b82,bb1c9cfe,c26184cd,ac98ad5,8e253c13,627fb778,c9362f33,63203af,1545122a,63940676,ba2d18a1,aa902e08,8bb444f0,47c2bd52,db8babab) +,S(2ff223e0,93986e22,ae418a5c,804e9e81,7a4de562,d7436e0,2d025ab7,11734a6a,c5c8d188,ec9cda19,bda76d8a,97838ab7,81990475,d4a00096,5efa79c0,100f678) +,S(cb8731d5,e1e53c9,ccfd2c39,3c8ab1cd,9ec839f6,99fc712f,f946e74b,99eb1742,cd2f9df8,38fec504,dd125248,92ce8a4,a9db3848,e487076d,8c18e53c,f6d19fb5) +,S(1377ac45,d776a5cb,76ec265a,af272690,6dac52dd,be987799,36bb1271,e0cf4a2e,a4b3330d,d5954932,d5a7a818,7d9493e0,25ab2155,d4ed0d4,f34aca1e,c2a04670) +,S(984b9bf2,f140c75f,e03489bd,88041faa,22fbac73,7ac10724,c511a253,641a5ccd,c474f639,9733eecb,a750ea82,ac4d50c7,d82f4c9a,942a2bb5,90b1431f,c8d14ff3) +,S(4b8fd000,74f57cf9,b135d56a,c002bf99,d5050479,7298cc4d,857960d7,afbdcb06,7c044103,1df0f6f7,721937a4,c60cf76c,95560ee9,4c6d097e,3a8e37b3,34c703bf) +,S(57316653,68412236,619250b2,58bd0ddb,34fc751b,8becc0b6,60585683,218b6079,d1d56e4f,30f01c57,48972898,b8afe142,16f8335b,e3a39c37,da64050a,91652904) +,S(c9a00197,a0ff16f2,fbf2cb59,767d43f4,60737367,4f2bbbd2,53c7220f,db69f286,177c6783,d739117c,1de074b0,c605cabc,6b4dfeed,a531f4e4,9cc518,40142f0b) +,S(e23416da,91df23a9,db161618,579b3008,c87b9ef5,7ee8bff6,45eec6ce,a61881cb,e556417f,84043691,e7ec82e0,e1718296,e42fbcf4,a3de0137,93772dd5,70b8da15) +,S(9f96e3f2,369d753c,e6614c45,77bd8a9,14293eee,8a749c1e,3b0e2955,638e9ad8,f5cd1268,1567a4da,71650d10,e413e0eb,9b01a396,e529cff6,b494b2b9,a21ddff1) +,S(48657ba4,b24b0123,cd54317d,de6a3245,ae488078,5ba43d5f,1d94fbf6,b9301fd2,191edec0,6eb53781,2813ca77,2a9021b0,dd4931a0,929a7e36,a4a8c66f,aef0d890) +,S(67b322e9,d72e864d,8cb15511,11402d7a,c6c858c8,77832d4,e0187e69,6a36f24a,cfeb12c2,6b58bf15,3bf87058,c5faa833,e15c867,f7f9a208,c3dfdf3a,c7f6946a) +,S(42e8068,542bdd98,fcce8925,52002db,c545ba13,16082d40,fbde06f0,a44ded15,1645a9b0,c1f33cf5,27364915,8c4f261d,a1ee814e,7aac6402,bf644451,bfc4aae5) +,S(8ee7dce1,339c50dd,55619107,9bbac005,3e058cca,4a8c8e30,7588c105,fe90d4c7,ffbd0af4,8aae8279,2cda6170,5dbe9fe0,98e102ff,1e6f11d2,b4669a81,6ec9d5f9) +,S(abc9504,12926a71,6adaaaf2,7b209216,37a935f0,cc66eece,55978a82,1fa368e6,72e54935,e9b461e7,9fb75c48,4dae4fd2,155a4a48,d3a467c9,624c5f6d,71f79203) +,S(bd250320,81e0e9b5,3b00568d,40378fcc,fd72fd8d,783f2f3b,433ddd1b,a6976ba8,5adb8bdb,85855498,994ca879,717b8e7a,e8c4c87d,29d6a1ca,4c3c6395,6c3ceb39) +,S(b4fb262,fbeee84e,49ae9167,7e7aa0d9,b31609e0,48888740,c018a5e1,8ae25f71,34df3f86,dc091d51,258ecbe4,1cf616e9,265d6d36,8ea3403b,24cdc7f8,e176e5fc) +,S(d1ba9b67,66f24eaf,a145ad14,81063b5f,e4604817,21b361c4,95de8833,be605c01,e80a6cbd,17de2f1e,663ce7f2,8917e3a9,f871943c,a4b8ba75,68476a3,d9e8400a) +,S(5c98b6b0,3a3e5a8d,2d46652d,5eb9e2ab,a80c6702,69dc5ba8,3732752e,922639b3,81e2f9a,145d0cdd,2c51bd13,f907a04,6a35efb6,635292e0,6b8f6513,c50f4a54) +,S(c1fa4688,f75fb86f,61cb7071,4fb25f2e,908abf0e,a87aa84,c8db5dd,4c2618f8,f2f74a77,6d4bf26d,17f55d0b,1aa913cb,9db869e5,ab861d9b,2043ccb9,ca8397ea) +,S(5e806e9,a644eb32,51c62ba2,f09a755b,96aec78b,4405df76,dc22ba6c,f7227ec1,b88c8118,d6a1829d,6aecaa05,742313a,b871d2eb,72f31bba,9d84f87f,a73e614b) +,S(f9d147fe,fd2c1a7b,f623d965,bc7901bd,968636d,eff54c14,34c6326e,d1c8de9a,c7887249,ab6686c7,93a7d77b,41173060,40de44cb,84980c33,cd548d72,d29caffd) +,S(b98cc956,85f6d11f,a8d38a1f,50799634,9f7020ae,3171023b,abea0fec,a70ccdb1,f074d495,3689e8a3,6ee4cc0d,40882355,3dcbdf21,70975f49,5712adbc,990ecf7f) +,S(f161cad4,100817e7,ef9091dc,714bcba6,18458493,f3bb6b03,4648a649,6817b474,b7eeb92e,396af324,22881eb2,45e62515,c4410af9,fa519ffd,61289f6d,9b740904) +,S(7c8b6c89,2ea4061e,456abac2,46edc08b,fb54aff6,8a2678fb,1b7b1c08,5326914c,f08e1f02,6ea1d2c2,9ff5eacd,2b34682,2960723d,cdab95b1,d69c8af,5e7692f8) +,S(4668c29f,16334658,195b93cc,ef71a076,3ab2078f,724dde5d,d3635eed,24f28729,5db228c9,8391ec52,324c723,39d99514,8fd22f7c,2f61cfa1,29ee7400,4c74ea4f) +,S(3443d0f3,9dd6da5c,19a39f8c,f3672652,96fa6729,c9290b2f,4e21c7e5,3167b65e,4b6db639,9a088ddc,8ed31f63,7c079451,14a4320b,b7ed94b9,2a87c0e8,97429234) +,S(d3ce3501,17a04e95,58281e69,3574c096,458dbca9,afac20e8,ffec7810,8bc227b4,bcfc77b9,628f6ee9,3541e47f,8d556ad0,7696ee6e,90ce384a,9b77fcab,6eb9908) +,S(c4dc6363,ad772452,221f8640,9de0ac28,f2bc1ac3,cd2d7080,23301560,f95127af,78c9ba8f,d789a666,439bc949,38345250,38a79c5,97f6a71b,3e096b8b,752d3038) +,S(c771f94,221a47ec,fcd78d7a,123d2e0e,1bf4edcc,bbcdd075,b23d29da,6d5ac666,4dee3b30,829f5aae,f4471924,65de293f,f2ec526f,5b8f5980,d9155f71,ce8d6091) +,S(bff88ce8,96338f7f,5b6516e6,448a1f25,36a1e9bf,275afd50,e772517d,79e6e199,8f3f0c7a,b62010a4,eb0b6211,7e9761d9,c1552629,bb55bf68,53274158,a788c206) +,S(4afcd064,5d57bf24,e850e7e3,d3cac224,6a467e76,f2ce02da,576a1f2a,9a3b97a,52f23b54,87b2af93,6cc692f6,1876d6c0,ef927d3b,c06df93,984ae54e,4d10f0a2) +,S(c4bc122c,b9bf0e20,57f933fd,94db012f,79e23c34,98007abd,f8a8ba21,32b1f373,e40c47b6,a31d81ba,dc45d427,3ab56d77,1daf76bd,7bdf8ce1,a8778861,66fbfc6d) +,S(487a19b1,d1be7791,ce223d27,bab11aca,837a0f8a,7d34d9dd,b4c68f18,51f821a8,a53cd743,16ff4e9a,8633554,45415e35,5552403,7b25ce67,f519e44a,a5d0ef98) +,S(274a3cec,be06c748,7603516,588ccffd,f4ac3d80,a85887f8,10632cb8,4301a326,17a24be3,afbe8b45,9a72cab,5385cb6f,5d06b47a,63bf19b3,ff4989c4,85a9f40d) +,S(32b31f77,b0cb99ac,3bfc34e,7558f9d3,e82fcc6a,be2c4,8a079106,33afa9e8,447b44c,c191da90,e0eb3f71,db804472,17f422d5,b1732a8,993da80a,5d8f5bc2) +,S(78c39dcf,55561468,dc339d46,ffd09337,945285e1,66dfc29,25d8b85a,24a2752,d691ddbb,4e41ca85,eebdf63d,5c023e62,a6680931,5e1109ce,89088467,7ba3ac55) +,S(5fc75911,a4920777,c4502116,deefc1a8,d2f21f96,2b1e725f,a04d6fb3,9d34e5ff,59f36f7f,18f5885c,dff524d9,6a139749,f3fe1662,4b728d50,7a460bb3,497512f2) +,S(ca1590e9,152b2b49,a6d0fc16,4e346e19,fa62dde6,f693b64a,e38289d3,ad08fa8a,46a7bb3c,1174ed75,49e9eae1,7126455d,535ea744,936947f5,24a8ff30,8046dc8c) +,S(5c715266,5ff0bdeb,a7f6e660,bf66d5ad,743d94bc,5ba9b7f1,f3d50cdd,9d11fa1f,7da23b15,56e995c3,a21ee9dd,ccccca4e,e41684a4,f208c39,b31ffe9c,4473a03e) +,S(c7f71da3,6361c73a,55dc3877,4f2e1033,fa0c09ce,1c9557c8,c29d8684,e4177e82,8d6e47f,b5c2cecb,6b22dbf9,a04f0f95,77c6f50c,3429df92,78edb85,59b0dedf) +,S(6e91bd9f,5264a13e,37925900,433b7536,4130b4cc,e6fa716d,a0101c2b,dc58afab,5baa7455,506b5849,5d820c20,f209aa01,ee0f9434,1df5b449,9ed23a51,b4fd604f) +,S(1f00de8e,69ac7cbf,c75c789d,f3322813,244907a0,35059072,68954196,baef0d33,2892ce90,f32330ed,2800c30b,4482b67a,e65fec8,41ba6fea,b2e83703,dae040f4) +,S(c00133f5,7d8c469,421efa3a,d71d8d58,1a2f5b0b,2324de10,91d79145,7d300638,3c76b182,d3ee982,dd05ea45,59e8e31b,1aa3dc12,fdcb67a2,f86434ed,34f18895) +,S(af639e7,95e8269e,12cef756,4bbf970,cdb172e0,66cde48d,2f8e9083,c60cad49,1bd01179,ce92cd29,e414a74,cd1de487,c479daf,5673b219,8082c474,2426abb4) +,S(e6dbd27d,5447c044,18fa0a5d,8ebcb9a0,ede58538,8b73ccd5,4e979797,31f4c9a1,77f38524,f2848320,3d4c780a,d0cf8bd,a2071037,348db8ee,6b5deabe,3d242153) +,S(f51a8d23,c95b70aa,d02dd904,ec1119ea,8d1e3e1e,e405646e,4c2dfd53,336360a9,426b2c9a,1d703cf6,c748871,4959acda,ae5c6aab,51945138,73e4b1a9,c0f46c57) +,S(e12f11e7,fe437b7,f578d8fc,33ae3a60,a3e4d1ac,1ee45863,42944d50,a0f6bcf4,22d15d58,35fa89ab,563985b1,4114c957,8bfec8d6,6dc7d253,e3c6d900,4419f5d2) +,S(e758860a,8ec762d0,62f51e56,d958a14f,ac619351,9d890bb9,bf6bc7ed,e988e14c,42d9e0ef,10b84f21,fb88d780,dcb4750f,10438682,3b003b23,ec41c297,567ecd78) +,S(3c933fe9,ba21e5c,d822b90c,78a54b7a,d4799882,ef91f2c6,e423a398,20a64163,c1eaa0be,531922e2,ca5b23a5,6700b4ad,7fc16135,11f67f96,b672ddf3,669080df) +,S(4757576a,83c9066c,b6eb6b08,e91a79c0,df828e4e,3c09ce07,939134fd,ea857872,13f22fb2,62d77f15,de3e8388,d9270c45,818248e8,9d950d7b,58ee6c6,c38277a) +,S(35e63903,70085140,b19df903,9a7fff42,46570fcd,8661caa8,129d6b4,31045c7,2855f4bc,aa9d60d8,6a44f022,b3c28e84,53cfb3ad,a58691f1,b0e9cae5,e5b9e8c9) +,S(ad446e01,1f118207,3565f031,6d0a85f6,ad5330dc,6a8be4fe,82be632e,32126fa3,240382f1,decee3f5,1f92b2f8,1ac0eab2,1d8acb54,2f730d43,15c194f6,28e83e39) +,S(fbe9e5f3,eb01ac37,820af752,9c4221a6,89164ef5,d77461af,f82d6400,6a718815,f2f30cad,d85a2e0c,e393e088,44de9215,ba207384,2abf8468,47801ff6,12d088e6) +,S(1e675320,d81ff430,a0549aa2,482cc9b8,b9b585f6,32d32916,6e952f13,3b038135,ca0f1276,c9c7d995,c5baa5de,2988700c,2e2c7f1b,366d1db1,b44b4c9a,f0686aa7) +,S(176dc770,23b0e52b,a2eb8068,ad27924b,94c3f643,30e0e85f,3593917c,d6267718,d2dc6288,5df75b06,f450686f,df660950,548d4f6,85d1a701,d510f3fe,297ca8d9) +,S(3c8536c2,32a02b3a,b36feadb,ccc7c541,7ac83942,3cfc8dd,99a0ab7b,41a9c938,a684eea5,249cd12a,d24dd8f1,73022ad1,8ebc7f52,d6a3bd9d,bdc4f5ad,a25186b5) +,S(48aa73ab,c61a76b6,e54c446f,ba881198,ec6ea003,d63c54a5,605a322d,7af006fd,c28c5eee,ffb20882,2d018506,5cf3ddf3,5977fab7,40e4d4e,cdbf9935,8e403a64) +,S(74732762,abd028d,9dad2b36,38baca49,263d170d,ca7e4cb,d83a3a1b,53cc1ff1,ca11df0c,e8dfa09f,3f2ef7ce,5c023b6c,927a88fe,60ba9f3f,ddfbd69d,e536c2c6) +,S(eb71ab09,520e5915,767dc918,814fe901,a4042725,5247c02e,b8672c5b,95698522,5fad7ae0,a7e95b38,ed6563cb,2023b2a9,c81b6901,c007f1eb,8749f56e,4d48e995) +,S(2b101bf6,c7763df5,72eda74b,eb179cc6,af5e8695,965761ce,f8444371,7ef5be6b,dd16c8,4e1d1a3d,98d4629f,ef258421,f6664719,7f89a597,67fe862,3f140ce9) +,S(a099efa8,2c666552,5332b050,75e81ba2,13976afe,8f3b33eb,ca2a4436,6e0ab337,f883957b,5cf1f2b3,ddd6c7fa,a126acca,fb1e33b5,e5b753ab,dc0a99bd,5d136c07) +,S(f4396856,a61c3ce9,5b72ab6d,470bdeb1,8cc107cd,2f58f15,3d5bc99f,8b62f95d,6e3ead1a,a8edb0b0,67240ca,f3274e63,df81c2f3,e1ef2567,cfd76c01,6e9f6133) +,S(da732197,26aabb18,4a0aabe5,a493d803,53215b7c,49458008,bd5e387f,694050c0,e2075f29,17724b68,6bcb987d,85e954e1,9489af4c,e7ce1b46,66d84604,e9a0eeb6) +,S(99171a1e,19596183,f4259c09,b9740201,8fea44d1,4d0f2f45,75f4d66f,980a6792,522b840c,83e1eef3,e7f2cbd8,e07bec0,66af1bd2,e7607f5f,27a767b1,75219a4f) +,S(353cc684,8a2c4f36,2408997a,944889c0,1db7bcf6,9133323f,8f0d34ca,758cf08f,1865bc62,f4ba0156,7e2b283f,702834c8,97effd14,6e0e5fa2,43d5124d,ce67ebe7) +,S(8b16983b,5053d3d3,8e67c77f,1b6fccc1,b9ed7e3d,d57a26d5,deb242dd,7a312852,49d93f92,fa5953d3,956adeed,cff49ac8,caeb3d2,c72a0e9f,be6c85e5,d85d47c6) +,S(68f5dea4,b1da327c,227b2513,83fb622,efb36730,3bac02ef,505e0464,750cabc9,26740f9c,5d624b9d,aed25774,46c9c742,146de045,71cb750c,4356898f,e3d31782) +,S(faf5207f,c3acf00c,8e19d8bd,7208a6d7,cc936706,98559244,e74bb202,20c699b,fab7b446,17a6c6e5,4ac186ac,971de8e7,d42c1527,8607eeb,b8564a0b,cef1936c) +,S(c3d1aa91,b541c5bd,3da04707,a2f01a16,917c0420,a26604a2,bcaf5081,e8d17630,5b57806e,5a58c405,f06d7ce5,4e5f7b45,c9b631a3,44c92c64,d8cd1435,fcd9ce27) +,S(23278a35,4970b920,450db526,391b30f2,54b5bd5a,fe2c1455,623c99fa,8ac8db1a,864d81da,e8df9e47,1ac93b74,660542df,3570486b,fbd2144d,55dee441,90e1888b) +,S(602f6181,33cbca4d,74de4ab,29dcd101,7c12c32b,ecaed25,485765c5,478c0146,4c42cfb7,279ec350,f77d2da1,599b9c85,9ffab342,ce6a011f,91c9e460,27aa968) +,S(1dc4cfc7,126c3b2,5d82aa46,3dcc8cff,c545a9ab,c7962690,fd4ecaad,25843ee9,a9357982,5c535575,35820f17,25e32afb,6002b1b9,2a9b43ac,18225e61,b3fedeb1) +,S(3694f121,6e02bc79,14cd9910,8ca65fc5,887a95df,8b04e8b3,3c6c23cf,ce35af82,7ffee291,b1c41976,d456e742,88458b9e,c61e57c9,9b8386d1,d1c36424,38555d88) +,S(743ada75,a9596420,7b8725e0,af06c2c4,457be03b,a920c3b4,b65922b2,1df1bdbf,8f2b81b5,5ac4c5d8,9cc23ed,92dc1b43,5629b9f9,39b126c0,b16d7175,b40f908f) +,S(bfe9397,7c7cc4a7,b9cc42d7,f044607c,f047cf2e,26d6f94f,210af7d6,b2420085,625d6059,8f80dc83,1ef2b51,dee53d5,666c3dfe,a02e1d92,1260906f,ae373d64) +,S(86c02c0e,6ee646c8,c2944751,7867a1ad,cb56ebff,c8795f83,73e6d8b9,1b240eb9,659b5e9f,da4b1098,b76af529,f56f809,59d39f48,916477b4,bfa66af,c85be4ed) +,S(3b281045,857f01e9,995d357d,3a84dc66,6c4f8f47,4b82ace5,dc3a9229,387bfda4,9948272c,cdeb1542,47c7c42f,1f313dad,e318a123,3f500f8a,16d80e7f,d2e9fd4c) +,S(cddccdd3,b54d979f,504d33d,46d6ff2a,9859038e,33087a3,da9a5284,fefc47c0,9f2a13f8,369313c1,44d91e5e,807ddd65,196c991,a7eb0321,2133aeb4,56683b8) +,S(98100502,a6023ddb,ee34462b,d0232711,8f8c2e9f,33708088,40352c34,870e16d7,1a8bfef4,69af3b3b,1e381c08,454a84ec,4cf8fb66,bd721a57,47a94e90,1969b9cb) +,S(8b76757d,b2fc179b,9016847,9b82124b,c26092f9,b35de316,c90223e5,99978179,47eaf326,588e65ca,541a71a6,a1167321,ee449268,1e8b4960,6eaf9a73,42b16f05) +,S(e66ed7dc,897fb660,6f44d8a9,46b0c61c,45c83bb2,d55ea771,bf2571d6,7ecc3b43,e536f79b,8a9fff4e,c6cffd47,8a405bd,7f1745f9,9374d810,518cc5a9,f214dcbe) +,S(e0600592,cc9c0b9f,8cead065,6ef5c115,ead63209,6a0a0d2,2626aa13,f2bc88c8,628d94b7,8b84705d,16e55254,4c138416,e7f75f5d,d549ff7c,a42d51cb,7f5a584f) +,S(1b0af242,a9cf25d4,cc758fc7,63e2f07,62db2e42,6b392cfb,ffc5ac07,19152767,33ae8aa5,eec30559,a3d28da0,d9354048,592dec4b,2f975a0,ed043fc3,c856a2be) +,S(e204ffaa,142f7eda,3505beee,db0bcbf0,9b80924d,ce5bced5,439aa4d6,af5acb7d,a2804d9b,98e11519,adeacdd1,aef2c22b,a02f7030,479a559e,6924db49,5d8911ba) +,S(afc40e67,651531f6,214ea1fc,13173d4c,a35431f4,92845964,69cf099a,d515ed5,57ef6ef4,1e480de9,32ae8596,3b04d267,5e629707,cd3bdb45,5896d333,b648e0) +,S(59538bdb,747b641f,800588b0,45c0e3c9,72963406,5ca601d4,690dee22,abe8d226,a030486a,3c919c35,4c26547a,3de96087,52ca7a28,5d378e28,652031dc,ec2d4438) +,S(6a91d34f,c38d4028,c63a4bae,bedb2a76,b964cf44,1804a6f1,efbe469a,a997ed8f,32500c83,6a0b5274,2d2ead10,dd3e73eb,45f221d1,ca6cea00,f2b01d75,d9073260) +,S(9260e687,b11d97ee,97dc44ab,5e21c344,332ae39d,c85c2ee8,f7760cc2,8ac28d61,f47df3d,e8d8654e,f7124f5e,2dcd9d95,c1d13e83,a33e5d18,92ce9851,6223e778) +,S(3490e733,7a66f301,f678561f,4b4f293c,b48820c3,dcf9be06,a0390410,4cfe3cba,49591a79,7edb70ac,74f87636,85bbb22a,a8169536,532886f1,f5ea0721,5e9bbd6c) +,S(9729f4fe,1f47a9a3,7dcb1311,ea9548a1,d71d7a81,27803c8a,6ec0a680,8d07b4a0,56e1a5d4,ccc4fd72,8e7ee569,e22efea5,c8f03d73,fe8ab86c,2dcb8af2,eb17f896) +,S(af63904f,6da423d,1cfd77a6,680044f0,5e694eb5,80ccb4b1,c37d8d83,ae9c2caf,6decdc2f,5fe2b948,d15fa10b,4a7e2edd,b8cfaf0f,7c79a400,f3d1b306,dbe110b2) +,S(96271f72,1f4a1f21,a2274edf,87c294fd,403cf0e0,c7b7b1f2,f242fb7a,2c435a3f,66ffbc73,1fc8cfd5,2bfbbca4,49f6e949,71940077,ae411e79,51cf5b21,ca5adddf) +,S(a42ef215,1f0cc5a0,15827287,eba8d960,dfa5a13c,7ee2696a,95bd94ca,4b717c7d,5e491ed4,5f08a591,32296929,814608ee,e3243172,b523a1b,a4995f6b,50046fec) +,S(193b3ded,e770a757,d859c289,68be2780,fc4ce92b,135bec2f,7fb2c07b,b862e5e4,192c4bba,ffbb735e,a1d5cd1,38de0556,d1d1d740,980c5775,22d19b5e,f0716700) +,S(ccf9a075,da6f44e4,cf3b4fc8,26feef3e,54084b0,e2756029,e290a7ce,8c1e8dc7,d04f844d,ccf2c30b,9020f0a2,308219c6,a5d6491,ffe9ba67,bf6b20c9,9a35a183) +,S(7ebea25b,1d69bb43,f60ec69e,f9853208,d3ddffb9,6dce3831,873e7ace,d25b0140,24540af2,bf87d637,54f1a47d,13a3f38,2a948375,8955dd16,fc83e7ca,4fec3d65) +,S(c9eb4a,c2a31b01,9b7ff038,38478b6,674662eb,d729ae45,d7111c63,84a038c7,7e2ee03d,caed3f4e,bef2b90d,78ae42a3,12f6e8b3,29d116a6,e26bdded,81f32240) +,S(45756e0c,8c84e9e,a7b23bc5,cfd87b4a,cd0b290d,86c547b8,7fed946f,e5acd867,9c3f522c,e577c017,3db984c3,d7dc16d0,31326e2c,85b08413,4611da0a,70acdd1f) +,S(1bd58481,21bed636,c789e341,665e2477,59438de7,10aba25c,e4a0db7f,13e3c0da,cb0eb897,bf905399,63a8a7b7,50787430,ffd4d6d7,9589c8e7,350f4351,4786a90b) +,S(f199562c,8e809ba5,84aa80a9,759dd98c,32eda7e0,ccfa4063,547ced9,d9324dc1,33519ead,76430498,949dbcea,33ca14de,2f7ea811,cdd38f32,4009ac7a,b408d1d0) +,S(7fb4e910,e9e37dc1,f56ac3b9,30589522,975319e9,84dcb559,6743d3d4,f45ea6f3,b74a03c,cdbec9c,f36b59bc,fe3203dc,5f4d94a7,bd54c628,55f0d04e,67c960ee) +,S(503d08fd,19839d78,aca27020,54dc4233,c1a1d68a,6b9cf136,4c6fa9fe,886c03e6,84ad95db,9a09eb87,bd905914,473d23de,698459d5,7c436f77,58937bd1,8e448e0a) +,S(335c9204,e6aed3e2,586d0dea,c87158a5,62db42c8,e42fac25,9196083,51e1e713,15b359bb,10f8bee2,940849d4,212fdd84,49b60c5d,d3419ce6,7ef9f0ac,f4c1c2f9) +,S(ba68e5cb,e0f7159f,821117df,5720bb50,f218c298,9ce3f5ef,30c44134,2834bc9f,2ac25bdd,ff34e4e,ff45a2ed,e412a287,101ff447,71c657f3,ca57bc94,40fa5d72) +,S(93d6e713,311d8430,58c20267,739c494b,446d7943,a1e47a0a,2a5ec20,877e6baa,5997c19c,99a2fd26,e0471041,b509f9d,e10bf615,7cd4f24f,db56a65d,201a0856) +,S(7a94bc1b,5cc77a0a,73a84fbe,c5d1b68,cb8f4626,8ecc0c22,ac7500a4,5f397172,128c1c6e,82a4d52a,719c9f8c,1bedf4d3,32d3695,16decef,34af6b4d,578bee5) +,S(f031eda7,c19383d9,45eec848,f6f3e467,75fbe52d,bacadc54,c213c596,c821b809,b4a78d0d,1c17e4f5,db81e2e7,ee52f195,eb505d36,af96bea0,5170c776,23cabab8) +,S(86ef1acd,5c17e082,dd4cb924,c74d0195,ce9f375,60ca7608,57ab7d70,2039907c,6936a13d,b9078ac9,426d34b1,6d5673d,36c3105c,9cc77de1,ef7e0ec2,4cf3bb3c) +,S(fceb6cc9,c78e3a35,49b9beeb,62a14fb8,6d24eec9,2ab10bc9,40916b60,cbc6d720,7c2e6024,5f561f1c,e0b69701,512ca518,9f8d9292,ea75562f,8b17873,77f7583d) +,S(a1d9ed1b,9a36f348,1f426d83,7afe4380,d475e36e,3b140f3e,cd2213ee,dfa5c8d9,3683c97c,a1273f29,ec02cb77,9e9fee54,78bd5e3b,e6aa8c60,7d5bf07,dfa558a0) +,S(d98de999,6311ed55,e15bbdc7,58affca1,3e8f629a,77eb3dac,844f90e0,51bd48c7,8af6194d,272a8ee7,68d1b810,778e5c2,69394353,969d77cc,7d449f2,84ef2a22) +,S(78328db7,cd6afa29,b6f1ba80,d65f8050,60f4d223,9897a3ed,bee8ba3f,a99aac60,e37e496f,1d143ac4,8123377f,4e136442,629f8185,c4996f01,f35c7a9e,76fc5efb) +,S(3d701493,31faf0b,37c1e1c0,9b29ee6c,5d9747cf,cdb26117,223d1f66,e336db5e,d1e99140,8311b20a,b41f7ce0,ab4e9dd3,414ea3c5,b87f88b6,648cd1d3,e77600ad) +,S(f619acc0,47e0d4ab,bd5ba2a,7a54ecc4,e223986,fdbf7a96,e90f762a,ce288628,f24eb63d,e1545d10,fc96a2d7,e7fc1ee,f9cdccdf,cefb5de6,8fa4eca6,781564f2) +,S(cca809b8,71f85a00,3344a851,4f797fce,91718f35,9e2fb489,a1dbc00c,aad0a2d2,b7d72ab8,35658359,2258f260,a1f62f97,aba642ed,382992f7,12b11c11,6890b037) +,S(bbd19766,ee2c501d,afb4eec0,30fba145,aa26c45b,51c1beea,a7d3ed1c,7dc81958,bc709dff,70b3612e,7cf0a6e8,9724442f,6c1ca4ce,c32efcfe,b98f1acf,df5250fa) +,S(6a6fdca0,e4a58197,267a1938,1644aa5d,ca8f0ee8,3a68a5f7,9c34d4af,ec1cfadd,c28b1236,76585255,cc104298,d7ebcc70,6bd7ff6f,cadb0c36,db6517e9,d2732081) +,S(922e3e1,fd401a22,ee7d693d,e52f0ade,9564af2b,17a4be0,2c553216,df5c8006,a7b10065,aae84a40,b9b79e0c,5ca8a227,696841c7,20b944aa,3b9eb1c4,1488f757) +,S(53ffae4e,3526b553,f92bd9da,e3cbd3b3,aff8a6da,d4895490,38382f98,a676eac8,81fdfcae,b51f80b8,3d23b222,8ce860ec,9e665292,c456fd23,cfde43ed,99f8c6f4) +,S(14a0ddd1,c94596f8,9d3e7028,929cfe4a,7c2e70c6,b55d15b9,77227862,a03d119,2b5dc071,febe1d1d,df7e1483,53dc6558,7e8c94ef,b598ee83,806f1fbe,976dd086) +,S(7368240d,fb74f35b,b51a2542,8caf3b90,bebe272a,739eff4d,c0150f1e,3d68c8f9,95392b17,b4c5e82e,774c7168,7c46469f,21801a72,b15cbcd8,fd2ba85e,e4a7a27f) +,S(4c0a8053,b9eab39d,2396825e,2416885f,5fbdb610,7bc5879e,6400d010,20580560,85a222a7,5b7de532,617f67f6,5408b79e,f5a6f826,6083c2f0,93ca97bb,d7db5427) +,S(ca0d66a8,24a6f8ac,bd9447a4,933dfcb2,6751a26a,f5790a1e,91e32053,3ddabbf8,61cc898d,4f8b0845,11dfd49b,1ef01e43,6f7d7d08,a5f16b2,1550f329,79395d18) +,S(646a0775,e62f6a36,d520763b,5c7fb081,a3d7dff7,355cba76,45358a6e,55e9d6d4,3e528844,e7380a64,20db2366,22c936f9,b1100046,e17c66f7,a6b1a01f,7b7dbbb4) +,S(435565ec,f3d6bc13,142d7c47,7052da71,bac77f3e,a81107f2,30303003,6455d070,4ed52896,89fd8d96,343ca8f6,c9f0c70f,ab6edc5c,1ae96d15,9fa9eb4d,a4c9f6bd) +,S(d8b01896,9328544a,a51f22fe,e605c693,7a014aac,37316f,ff6a760b,93aa8f9d,63f51e42,a2b879ad,36d60719,c1497b5d,dd412782,e4c620ac,989f7259,3a06edf3) +,S(b9475950,4a9b3052,94af6f2b,6f182e5e,83a30abb,47f0799a,21ee5446,d63d48d7,cbc74028,37a899bf,79b89676,9e358ad6,9680277c,34ae1018,4290689,c2fb876) +,S(14317c49,2972d5be,c5a01b5e,34842135,d521b467,1b262f0f,c3e6a271,ff8e0ef0,cc4d2235,d1cecfd2,2e6a476a,7db483d9,d318e79e,4c3486cf,c2090651,c2069381) +,S(8bbdb357,5b6867f4,4f062ab3,38928d52,78c4b873,4e95c5f8,fcddd4e4,9d44f8c6,d38d3387,32424054,c05a67e6,c7d00e62,1279eca2,ee1b59fa,90b97f33,5173a778) +,S(7775fef6,36ecbe78,9279786,b996c0d7,380b00f9,4ed31476,1ab0b190,f06aa685,53152a73,162dd659,dce57d7f,cb885c44,34243153,2b8318e1,2a996ebf,2f55407b) +,S(db5e4bd1,39ebe377,bca64950,29e72fb4,bc9b0ea5,5450e42b,a7491c0c,39693b48,a6468113,a5a796ad,a337ceb3,238827dc,416ca20e,bdbe4e62,14194e66,cc5a0abb) +,S(eab057b0,578c52e2,eac11be3,9f069cf1,6ebf0631,709560fc,2414ff11,f1c619eb,5422023f,cf69b8a8,458e5c6c,3c2de1e8,6fb041ce,180c5f75,cddb455,fd023f67) +,S(e955fcd3,c657d611,7e2d43cc,651333e,c231ba32,418e6fe6,d021183f,e7f5e44c,dd0eaa98,65212f27,2454953a,4c46c5da,973095fc,b2e36369,cfe228f4,828e6b57) +,S(5f5a3c57,58eafc30,c311f596,f1d6605f,ec0f5e73,eafb27a7,2a07f91b,42d8e49,3cde0b0,1d1fb2ea,9d85a04a,aa4536f5,c6d9f55e,84ca890c,cf23ef2a,5dcdf1a2) +,S(fb7a31e4,ff0ade1e,efffbd7a,e04af118,49c82cf2,6ad219c0,7572d924,8b99bab,ea87aa0c,431de57e,ee86bc4e,be463dd7,9e69102c,736345a,5502b07f,31df2a01) +,S(d57b1d6a,a3e87779,4b9f8dd9,683ee3a3,6ec18d3d,e6b22b44,e411778d,4bae1ffb,256ffed6,b85bd2f0,9dadb0e,43ccbaec,9fcb9e57,22d88ca,73f8d7ab,dc0f62ee) +,S(9326fc52,d3a24a38,ef0fc90e,183697b3,f726832,c70bcb5b,bd6ac548,cbb8f1a6,863bd0a0,cc0a2bea,d21176f5,c99fafa8,d7d766c2,54d57308,1a58a6f,12889a2b) +,S(58362cd5,abc9b5e6,57617e94,620ad087,d5d310d5,313ef6da,36079b4b,a93caff4,5f2a404,4e86bbd8,d73b673b,2e432233,d6923cf3,c262e1c0,3da48d42,f62fc52f) +,S(7dd488b9,cd06e68f,e01b3a9,6b318d61,b8c4cd69,7e9a3681,34fce81,841738ee,fd7aa5ed,130c897,cb770846,a3d292a0,d963ded0,5266010f,34a99ebe,99782cf) +,S(9bf78b02,524c1554,3330d7d5,a3b41705,1fa2a324,6ba8061d,f9550640,cfe798d,59f537d6,6d2e6801,d79d5a70,3b4219c8,c7d06385,76964f48,10427548,90cf5a83) +,S(4c816973,743ad5cb,18db4f87,9bbd6d1c,e71513b6,eeebfc39,3663dc36,eb3fc47,1a6dc6ac,37a49400,a933ef09,f00f9650,44c6f8eb,d516c254,ab142d89,d41105f) +,S(60636bc2,c7486343,59296408,40f3a26c,173f4e5a,7f0031a8,35c1c56f,b1051be8,71a78b7a,3aed2bc9,70a4190b,d1be56e,efc2e6b,7cf81b08,541dd8f5,dbe88e8b) +,S(a6e772de,c3e90a70,6c663fc9,4d5e6cd3,12211537,40ca4a2f,47a0f3,7f8d00a,25b8fe1f,5c727181,4a6175a8,10aa1eb8,f1090221,d78c32ca,76ba7c73,d0eed520) +,S(79c6653c,60307215,fabb4b2a,aa8bfbaf,1692f613,166326c9,19324e5,7cb89262,36d5ed12,b6b49496,e2b79da4,c0955cbf,c24eaa3c,204e28f8,db1e7ed2,d2197bcb) +,S(3f556b2e,4530fade,d4774af4,ce4454c3,4a2bdb4e,aabda42e,d4ba8546,d646cb15,bab1d321,1ce84331,3be8996b,f5c5c4e2,c9fd04d8,397cf9e0,58829389,ecfd25c3) +,S(eda59a23,8d21fe9f,5e11e0fb,cf731fe2,d645c52a,f3861dd9,3b7273b7,3fb3913a,22f22f01,4ba320b8,2cc29c06,d75b7eb7,d3cea857,40cb2562,4161b9a8,712bbfee) +,S(7a1ea77,323dfb4f,36958adf,71d4f03,3a2bea2b,a9f62cb0,c42a4279,7de68548,4866ce25,ee7a2b5d,a276f976,6261318c,6d2d7f51,f6f41940,f6cc3f20,264825a0) +,S(ad0fd3a,ad62d6d0,bae7c51d,590876e2,33d1028f,62d5c178,a0ecc3d9,a323de2a,88e024c5,9672469f,54f4a64e,b792d761,d163157d,ed982787,a6d40382,83b0601) +,S(1bf19432,f4044a69,56d6e9d6,7b84a5cb,ee743771,8d634dfd,20706cdc,602729d3,4114b200,afb6a1a0,75ef8e3e,16c37e9b,4f2acd9c,3fa4e922,63d1c430,7c516aa9) +,S(514616f2,bc2dafa,8be3b9d5,f00b694d,2fb1af5f,12d219af,c35204c2,e121d93b,3e5cee53,608a299c,f67f4e0a,65adbf2,57ba8eb7,450058a,74072ccf,922eaf9c) +,S(8e3fece8,5338ed31,93721d18,1cff34e4,fdc42330,6a8e1a1c,3b002da1,6921a661,b095734b,6736486b,676dfc24,9cac99ef,12894543,8b333b2e,77664f8,20f686d2) +,S(46c06820,df101ed2,92842186,7d8a20b9,6db1eb9a,ae63355,916d438c,a7ad4447,fcaa10f4,59bb73f,c48d1b60,1147b535,d7d43958,1bcfe26f,9acc7abc,ddf1afa9) +,S(56334df7,1f9b390a,b001e406,ab37af71,3fff8c69,1c2eedba,fec7dbf,cf722b31,22d04394,340dc156,a73c4b0b,f49a6c93,8a3724c4,4744690,4af420bc,726707dc) +,S(202e246d,89045f8c,9dbe3dc9,7ca52d23,b2fd55fa,1b5cbd37,cb882663,ca67c4f,f4e6cf89,9cbcf023,1c9f661e,c4588072,7a6241e3,513cb365,9a2e7b20,a17a62b1) +,S(c8054ee0,10211c2c,f5bc1ff9,43552eff,c56b635c,d65e409d,ece239e9,9b9bd4d5,f50515af,51601cbc,de6842b4,3b854b05,bf1ebd1,678c46b,46e22827,17f31057) +,S(9c29788c,235eb61a,d2940708,4b9701a1,ea3282ae,56f984f5,1c625538,14438383,32111eec,efdbef2e,236469db,4ad30e30,c116cc42,99dd286c,2ab70ec4,9759ead7) +,S(5854e8d0,b7b5c394,7068dc86,f94c3cd6,72999023,367509e7,4bc1745c,19a57ef8,7e7901c5,c06bebd,f50c4113,4e0d2d3c,edafec05,417d45f2,345b75cb,a63eb98d) +,S(8bb2fff0,f45be789,a0446e1b,3547a44d,1104a5dd,9c8e50b7,4d0fa891,f73fef34,c332e365,a5343ea6,6c571e2b,c383f767,efb979df,72223a79,35da9173,73b182c1) +,S(ea88e65,6ee43387,86165faa,cb643cda,992f5656,dc7333c4,5ad8b561,8ccd209e,c38c40d6,4a7a343d,8ab357ab,845725c6,af9f4f4a,843986f1,fd0a83a2,5df0f909) +,S(c0c1d4df,857c7ea6,13322c2e,e0d4ba2a,a3b18ab8,cc8d9ff6,6981d6a9,4446295a,247115d1,e8eef7d,ce6ae1db,ec9be46a,9a284648,ebb7a918,7292fe05,9d72b981) +,S(91e6a4f9,407d3600,2a808d8d,db723ebe,67b8e212,792ba65d,b74e028c,ec7fc72a,ef6ae560,35f58be8,5cce98f7,b2106e0a,12e57dbb,47a4a995,47ee5041,3c5721ba) +,S(cd749618,9a8c1d36,2995cf61,380d0366,24a7a402,e21cf078,18794e08,fb208454,f3dc92be,15d1f912,a03debcf,88afcaba,2dd6ba2f,1d23a4f6,ba02c5ed,cbaf0bd9) +,S(99f5d12d,2e68e70,c304f3fa,44eb24a6,85f63065,af0a15e9,f71752ff,82943018,59f1921a,d97ebf33,68f962c9,c0a297b1,dff9f980,246d5dfb,61168dc1,da0b8a9e) +,S(63c6cd30,f9c07096,11656b1e,75d17191,a6ac02db,9debadff,7b3d602b,b9f7608f,2e439373,70a41b8f,e0e5f0a1,3ab75be4,6d8b1ef4,ee71723,4b73ffef,461083f0) +,S(b7407f26,90a5ea11,d9b7fc55,17e6c1b1,9e04fe47,180b1e93,94cd5e97,5d184d92,1b953929,47dd4984,7420f727,7a6796e7,828ee880,3e0d701a,aed8cf7d,513de6d2) +,S(24979116,161c8840,dd521e96,27a50056,c29ce48d,d86b6297,150f9a6d,e383fd40,13dd71ab,3dd69cf7,384d3e32,5fb16648,76f99943,f7ba3649,143e09b0,28b9a70b) +,S(f109b6c3,6122b278,8656c80d,4c84150b,b419919,4650d96b,6f2de8f7,f9d73b7d,a7457369,bef8d54d,c0a91d4a,39496f85,bd971f6b,4a13dc77,142ead5d,791c96ac) +,S(59b303f8,2031c370,4f17c929,7fbd0ac1,36be9900,a26b5516,9f0e3b6d,69118df9,30c7c4dd,1666271a,5ac8c936,b35068c1,9830306d,c695e02,d6c65ebd,2fd678c3) +,S(6627359a,eb3910db,4ba54cd6,c7b884c9,a678621a,d2bf6cd6,6023974e,d462fc52,bcbcf9ba,d2de78a7,fc486734,79379778,feab83dd,ea4f50b2,555c457d,a910d487) +,S(76fdad80,c4fb507d,9c9d2305,90e818ac,ec7efc04,1184281e,9212785a,dd51f1d9,cc8cc7cc,349cf307,f34adf7e,f559855b,9b88b70d,7fc9d19a,18cecddb,e3a8c346) +,S(7893406,e99cf08a,52fed9cc,4a9bafdb,7f2380cb,4c288700,b983b791,e1313330,ec15e1af,39eafe5a,d081acd3,fbd5b8ec,d0c2e83b,7a5b8074,50ef80af,2511d149) +,S(c454aa4,e8d02133,ed93c229,d0e834f5,18f16cd,d83a39ff,3bbb1ba0,838c81d5,a98e61cf,89c43808,f4895924,529a6e59,8af57be6,debf5f5c,67e3b3a8,73ac51f0) +,S(ff0bc21c,cbe5c122,dd2ba8f9,64239010,97dac1ee,3957b27b,f990b611,72402880,c34089c,1f7b2181,8d4cd5f8,9e445ec1,ecd634f7,52960da,467cd396,77bca50a) +,S(8e4486e3,49a0423b,d8132e39,812b78f0,3a0e61e9,d3eb7735,86f1e279,3731c301,897b24d4,37cc260d,52e1866f,4dc222ed,16bbf084,c108883c,a8a7b9b2,9a2053a1) +,S(4f4ca57f,84f5c4e9,6aca30d2,351089d,bf7fb6c,13847584,590fa5b4,4dc579e7,d53db7dc,1691556c,36f1cb1f,8a1b91a9,33634975,8f28d0b7,17d250e5,ade63a9e) +,S(fe8924b2,d7a24fa9,5c61830,aed8fba,79b3a96f,388b6423,c760aad8,cfc203bb,bd303e29,c6be0e2b,f4e79df9,cb17e0ac,e92c3784,fa8c26a,7e3cea32,d0b056be) +,S(3099f75c,f6a8c72f,8685895d,152f99b3,8ed9a3,320f3fc5,dcdcd14d,c46abb5d,fbb5bc2a,ec76529c,a278a32c,2a95c2a7,4a939c4,c0e2c0bc,6fc20b2e,a6fc9f1c) +,S(3b939f83,f84126f3,b6632de0,12405c9f,43244322,2ac384b9,7415c2dc,9c72f4eb,843b7353,ec454380,e9d4cc20,23a138b5,c1e602c7,f48be55f,1d3c24ca,f05607fb) +,S(dc7506a0,4a50e345,dca3cbc0,6384a938,b032f197,d6d30932,7b0c646d,95c732d8,fe942311,f6d49d62,99f9559a,3d16f43d,c6a39d4e,b623f9ea,e8dde39d,9bd5772a) +,S(f5a4c596,c6996a35,172fb61a,2721d75c,3dde68fb,4abc9433,f84d20ea,83b30dea,175e0d3e,77d2f63b,bb2ef922,d30b962,fd783b30,ef7dd8e3,5ae680bb,9df26572) +,S(7e9038e2,c499049f,e5d222ae,2f79f4b1,373c2f69,262f133,cb9be1f9,aea4029e,3592e66a,343335bc,e016276,6550a363,1d7dc64b,2223bdfe,7146f32b,8025c737) +,S(80f22f73,d16bfc6f,d6c28e92,1f990eb6,e2cb803a,d920850f,af489ff,f62b1f41,8714a5d3,c5ee74bc,73e11fd,24cf4d80,370e6711,c726ed68,2a1bd77e,7b503b28) +,S(498a2ae9,e86e53f8,43470a58,ab96fe0b,7c3107,d9d23535,fc887bfa,fe0c897d,47aa9eb3,73e841e1,4260f651,6ab3081f,7ec3809d,53b8609e,c3cced3a,6401bb53) +,S(601af64c,d14ce184,ca52c542,7a78c746,8e9c069a,80277b6d,960ddf30,3b3a010e,2900a63f,ca1576d0,11b46c27,32c87ef5,56dd579b,3bcd59,9161cd20,ceb7fa18) +,S(8fb2e0f0,7b2fcbc4,ad58b06a,822aa683,957f2bf1,5dd5984,9a1341ff,2d74a25b,7cd82350,8d797cea,b1b386f7,5d5f82af,6137dc9,9f6d6e6,b7c68cb4,75070aa4) +,S(336d780f,e9d14e8,b55a1498,72c63bc,83468eaf,aef3282c,9bde58af,6a69e6d9,92d1004,be45bee6,b8eeba68,2fd0187a,ac3e6679,f4fe0fb0,b723214,a63d2261) +,S(507ac721,f4d58704,4f8d2cbd,fb03aaea,b0634303,cce3e1a5,e4e47efa,90d5872d,b89a398d,e7db05d7,a1055093,97b83d60,9ba53c95,39caaf0e,917d22c8,307174d9) +,S(c42dcec1,3bb7fb96,29171026,f66c012c,992c604c,bea189a0,46e688a9,473ba343,8aa37731,a53223cb,a021bfe7,c413929d,8fe010ec,353464b,e3c1ce02,e54f7bb5) +,S(b02ea2c3,cd6093a2,d5e6b5c4,5c510848,857eedb6,50038417,d9f41947,2a866a2c,ebb45c50,cea190c6,1bb7c505,8cfce93b,ed1d8ee8,c75a5bf8,6ac9c127,2fa5527c) +,S(f4d193d2,9f20ed2e,273dc2c9,aeab43b5,85626d41,59b7edb1,51e17c45,ef70d84b,bda19a3f,19b834a2,c493f8cf,14cda579,1f84b6c,611ea7e7,280e5196,1add0974) +,S(8740dceb,19eac62b,75859b9e,4d0302d3,cc84f6bb,1ff6e857,eef7fb64,fe5f1bb0,a729eb0,4783205a,2e1d5b6e,7eb5221c,f2f151de,1489d1b,1d98fb68,e7c6ca49) +,S(79ec464a,85a29f08,d910bc94,449ce88,50aec626,3693bf6c,92a5ea23,84fcc9cb,77d170f5,b52ed0b2,9aad476d,85abae3,a1d7c544,c625ba2c,d44e68ea,ef53b39) +,S(4f1018d5,dd54bb71,cbc0e29b,255eafd4,6fb3aac0,45889238,847efcce,3207fceb,c32819e5,d23cc2e7,73a9b2a0,271fbe3b,a64531d9,2d416222,24a2f64e,3be7dd8c) +,S(dfbf1936,2094e85f,ddb25de6,8ca85cd4,e53768ab,81780eb0,33a0607b,fbe969a1,25ea0b59,33ba21c3,2ac5f1e4,932debcc,a2ca3aba,e0b7c671,93d97e1d,af80e563) +,S(184c66c0,2c36883,2c1805f1,8612449,940a371,54174f9,b67bb41a,85226649,cf63fe44,f1cfc791,4fb4a24c,1e0530e4,736f815b,a910b487,ec4fec7d,f8662eaf) +,S(daab3606,d386e04e,e39a8a51,a8242e43,ede9de09,f50322e0,a0f410f5,f043686,c0ba1c4,ebe7d10,6fd0d0ac,4e8f6e8c,fbb2b682,3a9d55e5,dbb7718e,d411718a) +,S(a887f4a,5311f252,ba0219d1,f848d334,26b0e216,69020dfa,89dcc339,7e04530f,5a7c04bd,8c37cac7,f429bff3,eda01dce,a5b4fa44,eecd3195,2878f79f,9dedeace) +,S(1b315664,409feb98,4d5dbfd5,a85afbce,4784a907,b284958d,28123f61,7c2d207a,2972cc7c,ba348e5a,5841d463,4597fd57,84eea5ba,a99bdc37,3119c568,aba205bb) +,S(154adfd4,27c30d56,d5f5de1e,d7e8465,6727e69f,82ec8d1f,19dfa16,b1fe4984,5ba86e8a,324b279e,449f61ba,a7fa52df,882477c4,921f2079,98199775,3e0372b5) +,S(debd69f9,fe55c15f,b28df417,cb1af3c2,585fe89f,b44c2f94,94fec0d5,88480994,98d8cc21,55c16d24,e8b1b831,4fcf616b,2564ff,9345fc9e,f8de3cd7,57f9708d) +,S(9fcd3490,2a7c54f9,a2855fc0,9558c465,e0316c3d,fb72c66b,71d4492a,efbaf9e2,a7ac4160,c2b5a416,89e9e49c,8d5aba67,143e1de8,26498be5,1cfa691f,f7f5d14c) +,S(59cacdf6,fe4bae99,598fb1d2,df3de7e0,586fd792,eee0d9bb,fdabfa73,8943a727,7c730d34,7b3ead16,c74d349e,191c484f,624599c4,d379acf,ed8d2341,160df035) +,S(5ce1abd1,fb291d97,db3a4c9e,c4ace635,34e6b373,407a8821,67722fec,7fb226c,abc24634,b4070973,d8a11025,5ff7a81b,a39de6f,5275d3f,7630de8f,23b7526) +,S(f783628e,bd0a0b4f,6ee68001,5b3014f5,e70897d0,ce159baf,3afb1aa3,207d73c,d06438fd,5b96b88c,94a68b6b,1f5fbf32,6c7a6efb,83b2f1df,2849f809,cc39af61) +,S(7830fabc,cc7229ee,35c7130d,b441d2ea,9a988d47,72ebe00c,6c159658,537ba0b3,49e8b58e,6aead178,3d5c901f,a803a33f,78acc889,27f2d57e,835aaadd,1b38fa7f) +,S(c930390e,a8901286,21a4399e,ef9a4a90,6416d549,c28f7482,6252fab,5fcba9e1,fa0e87da,3d0618a2,f54e8fd,d14b4bca,3bab137c,daab0197,4d110ef,b161cfce) +,S(2a0da867,20571917,6f949876,e5f00ec3,ba0924b0,a5e758b5,2d0c23dc,da9cd28a,96cd04fc,69350959,595b4870,f6df11cf,90c1fa1e,cd04ddd1,975d0bf0,fc907647) +,S(f64881e2,60da581a,f576e92e,3968e24,f2bef6ce,dc1c9c53,256374b3,1446fc83,808a945b,660b67f4,43ef833d,b491fa56,2aacec09,f8a2dac3,863b72f5,e7c8b94) +,S(970bd933,5ec5f0d,3a3cea17,5090f1e0,c181e488,1565c341,33017f99,ab81f052,4d1d270f,e284774a,fcbb6658,d5cc019b,8eb30bdb,39464a79,6ca1431f,1ae9fc48) +,S(dfe94b31,24c4541f,4723ecfd,f5cad197,2c058886,9283073,35415bce,e4c4779a,cc283e53,d547606a,a0fafe8c,5d3403c5,d047aff6,8b194b1c,1855a7ab,9540e23b) +,S(f1813379,673ae594,8fa30bba,d8737d0e,16c8bdd1,8f7047e3,bf33a39e,858df800,acd2c1a6,139a2dbf,9b008d50,d0b4d1f2,20bfb9d8,c24855d2,ed54440b,a87d294a) +,S(f4fbc156,fb631bdf,51192bd0,1c0db0c8,8890ec97,9c368f3e,c2106043,6d423740,3cb08cf0,5b07deff,431faf91,e1874baf,9cfccd3a,df487f4b,4f69026c,1fb7149f) +,S(124da4e8,3b079d72,4a7a9a72,5cc45a80,cb92675e,74541bbe,d36224e2,793de6d,3e700066,f12e0cba,4d6200fb,2a759554,1cd15531,ea065e6a,c6fb4986,548d00e7) +,S(749721c4,455e7826,1de045bb,266b97d0,6c2b112d,2ac8c16,428ce961,b78d1138,27556aed,a3f331c2,fe95b237,d3326c7d,25bc594,39f07b87,86559fc,55a3032) +,S(62cdca49,aa58f55,21c60dfe,d50fbf58,257676bb,fd4c4e97,9ff9a91b,7627a028,8bd49b9a,e16d10ea,7ee1528b,4f433e8f,17c4a688,a7148fbb,d10ed605,595c37b5) +,S(64d650f1,39b13aa6,16d3b227,5ed164b1,1cd3a1e8,81759344,7895a4b1,686478c6,deeee52a,f7572d87,f339595b,79643402,f9e2a065,7b95ba42,6b83d87f,3dfa5c2f) +,S(d08a3e55,66c636ef,3417c17c,d8526df6,37cb935e,db00365a,1ecc9f4a,9ab59d,2db049c7,5eec5176,3fcd3502,33856da4,e9ed32fd,24242a54,9c9ae462,240dc103) +,S(8761705a,35bcc509,afa20d62,61859afe,97154782,49ba47c6,f4b8df0e,30f20d89,b34c25ee,bb029622,4929c3db,78046a09,fd43b9e,be2dbf64,436f0df8,adb726ae) +,S(e3453933,4ce22643,146cc317,54e7ce7e,e35f6f4,e37b307,c4e9e11a,3c6f5f85,73ee178a,941e81be,ff22a0ca,f2bb4513,1afdde7b,336a3bf7,ad05c1,d465d97d) +,S(8389192f,6609a7e7,ac8e6f11,fdbfce8e,246b36bf,95e0de27,fac36082,34ca917b,957073a5,50448ec2,9d67b681,ccfb1aa2,67c88976,e53c99be,c68c378c,f2b636f) +,S(8bfd70c0,67bbe25f,e2e78029,a97fd863,bbf287fb,7a24eb8d,e5a61af4,c3c5d387,e2e6c66b,ee7265cd,5a1b1d64,4f24fcec,8b59001a,6edbb1fd,5d894740,f3f952fb) +,S(a5d0999a,a05f0bb1,59a1582d,980520b,eaf82015,68875269,fdb593e0,e6ff257d,e34d9720,5ef05766,676b62b3,62ce4b34,fe6d27d1,a644050b,f9c65c34,c423635a) +,S(44e479a7,b949c88b,507942e3,89ffd9d,17645185,92d4e544,2827baaa,5d5043ce,7b86ec29,8c12c463,b0a71416,24a570a9,e2b10d77,ae12ee23,2504edde,213a7087) +,S(60dec943,d9797811,706e0251,e0abd0ca,3f37bb8d,559213c4,3176ce3d,352aa558,2dc689f4,a31c59f6,c5181448,d6985335,16b0764f,8cc6fd50,8bc109d6,69fcaab8) +,S(5ca58d38,5b5449e6,f93c5c5,35941b98,d4ab829f,e641bb24,af7e7ab3,1f7709b,82afbae9,80eb6f48,110ce090,7f39ddc0,945d9d84,d5d3feb7,4d96581e,c17cd575) +,S(b775967e,a1b1d60c,9b09cf3d,26bf86c3,b9a23ea3,cd329138,10099048,d18b031c,d2b7169b,ecfa1055,70d885c4,adcfadcf,66f12d8c,846f70b7,12004097,840fef1) +,S(73d8d4f6,7d602f61,3c3595f,b9aa05d7,a23bc4c1,1fa3844e,92e6b79a,40220f96,bf722a2c,ffc9fee5,bea18530,9ecd14ec,bb17fb3d,568fe85d,331575ab,2400ce3d) +,S(e8104df9,f49f7822,152bcce,79c6df0c,8b1e9745,448c24d6,1e7b1180,99182b75,dc2fd539,ec8f2beb,1bfb0da0,f95ffbb,e14fc682,1c5d5023,96b1253f,82137361) +,S(ecd72ef6,fb6c432c,8e1449b6,d16180e5,777e5524,4900f209,e89e995c,546113e6,1671715d,358fba99,e509f518,e1458600,4252913e,268129e0,e00d64eb,7a26e135) +,S(e3b5ccf,be829bd1,6f1fc6b5,fa6d7c35,464bfe10,7e9d6455,a9907050,a4fc36cc,ce7abb9b,5471c1a6,de17a2c9,b5b671fa,296cb5f0,10b5ffa3,31e7a87d,a28044f5) +,S(f3591a02,ffab91d4,eb7e75f7,f4ebd22c,41c1ce4f,25f89c5e,d7ca1ab9,27107734,345a2e11,f2bab926,487c7d53,5314bb6b,cf04746b,be2edc10,18a57c2b,94fa4b3d) +,S(ca4b045d,ae54ad95,37d184f9,ffc5a950,c61349d3,227ae1a6,5501ad97,cb45c635,e30f817e,255ebeca,352f3c24,b441d1e9,4660f456,ce9cd72,eaf4c4b4,d7c1d806) +,S(f7cc5740,54a9ea61,fb8ebdb7,b76a95f6,30094720,675aaa72,dfd29bb6,6f41ea38,9d463d8c,fc5424d9,18275aeb,5e046be3,b3dd7fbf,f52d4990,f52c81e,b2556eac) +,S(f75b5f79,fba3e3f8,ee64bbef,7d34e8a9,b4fd9bfb,27b6a9f8,76b1f70d,ed6ab6c2,220b40bc,5c3fb77b,72c48e36,2745677f,7e0e8266,f85a14f9,d4030ec0,90a43faa) +,S(2aa367a2,5060236a,627d89b6,ad0a398d,89d86a64,735a4fde,e88fa4c,d9cd450,2bfedc25,2491b1a,764a802b,c4d77d86,1e70ecff,e9aef8f6,e829448c,d841fc32) +,S(ff7f49c1,11783cf6,e7da1e22,15827b07,a1078ce7,b1eb3257,65a37c38,a141620f,69550c9e,2e48058e,8bca8b54,21251dfb,a488c585,df644bea,d519acf6,54702733) +,S(31d05358,1164f4ec,a45f7338,fd3ebb90,76d017b4,5e679601,6fd02a0b,5c3aa39f,f124319b,72177ff1,462fa90,2e1f8d23,d4d3ea0e,d1bfd1fe,6bccd92a,9963f575) +,S(6eaf0edd,fd1203ec,a2cbf2f3,8da9ad7,c8a02d3,ab5f06ea,bb88fb5f,7e6a3bd0,d9336d01,2d8e9474,49c521a0,10a3b83a,815a0c74,a31596d4,125909c6,73e05f08) +,S(b95a519,77991ab7,fc3943ac,ff5fa88d,68e759c8,11cb91b9,e9a1ba97,7eda1347,8cf2cb5f,446d448a,5a98fbfe,75a2ffa6,9758bd15,36eea87f,533822bf,6de5ef23) +,S(4e5301d4,8ce5edba,f3b1dc21,2e804e7e,1fd386f5,6b90eeea,da6c1c58,211427e8,f503ec3d,e169fdb2,e1d2f684,cbd9d684,dcabaad9,376d96b7,6fb0a5d8,1b9f0d9) +,S(4fd1a9e5,9031b43,715f92cd,c49c2d0a,fc7c2b54,ad61d7a3,9142033c,3cf49cd2,73ecc11c,ab0165bc,3ab4b43b,ecef694a,2d99c9be,8b877160,2c885a6c,8e4adcb1) +,S(67406865,b32543fa,5ebb7fa4,a8d8fae0,384070fa,2e8a4b86,74510099,20257c84,3fdd9ad5,93a4e0b9,4f4451f5,e3227df7,e829a45c,ef3d271f,3fd85896,bbc62008) +,S(14b955ae,d6ee5be6,ef3dcfa0,edac40a0,de7e8dad,19c8dcb4,e4992a65,a46569e4,d4b920b6,21823f81,8481eff6,761353dd,7d9f31c2,5ea9d1eb,ed60a5d5,fa2daf70) +,S(14f283bc,5608d5fa,dfaa0b3f,fe42fd20,4003e434,c6368fb7,22ca5f22,3339ae42,b2415e3d,c3aefd3f,c644d4bf,b0a87fdb,bf0ba630,2baec8c3,7c1577cf,9edb7397) +,S(3fde0c67,7d3ce20a,6e6275be,7f80cba8,5416a55c,58dfd09,8e733a32,1fbd1c1f,9b8ef7dc,610f192c,949782f9,bea1f08,9a018b25,8926389a,1155d033,1adaaac6) +,S(9c55e669,df5f3d05,f15c74dd,48290540,b993bf4c,41dd9247,df5332a2,ed17267,23db0ce9,30c97665,175abd78,33757fc1,8c6b3c32,2d260810,981b4e0a,6e4979f6) +,S(bde84df,ae141a0d,6e8da60b,30f41746,506d2dc3,4b3faee7,d8568a92,82968d16,45a33214,ff1361df,e724697b,99a6c686,900374f3,6c298dcb,468f38c4,4ab3ab04) +,S(1940294a,b8f3c2ca,45f68f45,4c60c5a1,e5d97085,946b30c0,54939daf,c99546a3,563f9f99,3816c62a,1e60ea76,77c61bb0,848bc926,e76e386a,bfd96bb4,ece3b81e) +,S(dd6ea1e0,d0d13e64,7d0df92e,ad22d838,757a34d6,373ccad6,6829fcce,b32ccb0e,c018e9e3,6bf4e8b2,853ad27f,a49e5ff8,384b557c,aa00c3fd,d8e008f0,ee33c313) +,S(657847e8,c7844562,e26656bf,bbc27b84,dc104737,42c4dffe,c0669616,5b7fbf19,dd90dfb6,58b6ada4,901beda9,a4a9a8a,42c6a4b4,e79a4172,5b5f6ab6,95f2df5) +,S(fb7024b1,40be9d6e,906d26c2,edb781cb,49b8e71f,396b8d3e,352506b3,fe3dea6b,de408ff4,e50b2328,b6ad961e,9dd1ac46,fea36005,1407061c,5a0fca32,eb08efdf) +,S(2d29c008,65a7b279,d3a80179,cd3e8944,b3f2be0c,49a398df,a3113350,d1d8e8e0,caaf127a,ee704a4a,65802748,59649e45,25c55005,f2667ee9,92e9d923,daefcf8f) +,S(db690474,79b7209f,4de8d42b,a3c1be3a,39268589,a7c33632,6d87c1cc,53d5662d,90de8be9,5c3587aa,9913ce32,c83e24e9,c58c1fbf,2922c63c,b777770,fbaa4e00) +,S(9806506f,922e4f0a,afd54ada,258d6fc1,723c7087,ccf13f0a,df247356,c941697b,c07e2018,a8cab841,37698eef,3d31cad1,b97fef49,77b277c9,25245a12,f16bc237) +,S(ab868d3f,e6da25ac,5b11c112,28f14621,661e0ad1,e33d25ea,ae1ae7af,60e40187,ee24b698,334a9850,1a1195ce,d57a7fd9,4b12c488,bbd301d4,d47d5f13,3cbf54ad) +,S(e7561fd1,9d2a8ee6,12056be1,74257e28,3122f366,abf66f49,31fd89ee,fd8dcda2,2052e74b,e3656d8c,5c766ea7,3227b75b,85bcb190,8a07918d,5a8a8001,3e166d5a) +,S(5f19523d,84bbe307,be08f2e0,fa844cb5,7b562f01,39950820,83c2df9b,e8f21e6c,3a96fe16,28ee1dde,2ae9ad2d,5724eb88,33377542,6e91acb9,d9be7c41,7265d7fa) +,S(c9fa4668,3c949b11,2422ec1d,c5501efe,2fdcad17,255c7545,69837d28,d9c10cc1,1aaae75d,18f691ac,cf1dcd8d,9e8e0348,b5b6e734,76d47ffa,b5e23ede,c7fd1dba) +,S(1da90e2a,1e911879,ccfa084c,393b8205,1799b2d4,15a42401,b1ab793b,beb8d8c,3d3f7c69,11ea4d38,46cbae1,53b3fc32,74994ee5,1f4fd332,2da4d28e,c89c0b63) +,S(c6fcf10f,3851e432,6bd504ac,b7847f7,707e4098,d8f66915,3e6f89ad,f31b3186,d0ac89f4,a16a63d8,6e36ea10,8f8ee5c8,4e2705af,a9c98bff,3ea5253,93a50ced) +,S(15057a2e,eb56c67c,cb6b7d4e,f1257ae0,3cf236b,1f9b6588,fefd7f46,16378233,4dbab530,ccc0a7a8,c49543ef,5e3d0a87,6f205a62,2f9a90cf,5054bb0f,dc4930c2) +,S(37eeaee0,72d5ac0e,6ea7337d,d07ddebd,45bf1cb7,8c02dea3,6d1e419f,308b20f,b0c64496,5d9daa14,19c77249,a32a3a3d,a5761adb,bf5a394a,ebb91630,f361d506) +,S(5a207bf8,3a8bd0e3,3c71cd96,d928bdc5,f1d6ce8b,7ad9bebe,61a27362,2557745c,3accb757,fadc9b6a,2a5494ac,15744113,ee878901,323c6138,19ec7666,60f54dad) +,S(fe08dd6a,1a0fe325,5a391271,e81befb6,f6b2ee08,907046d1,642d39bb,fbabd139,42c342d1,3535822e,e4ef1b43,69f204c3,665d2326,1379b0d6,c520c64e,181ef40) +,S(b7d262c9,8dfdbba,6483edcf,38044cad,d6d859e0,3d1ddac,a39cb999,78706111,96086350,b308b397,6a007c8f,5181b5ba,30bb4c11,653d689,ee97fe47,28d798e8) +,S(4b12ab2e,23b33775,3ae97d7c,1badf5a,7d354b57,dcc78407,6836f802,34130c86,419d4e0d,9f708bf4,2e11e73,a1fe5815,2bc9649e,49ae45c0,f52fb8f0,f23c450e) +,S(fc6d2682,a96eccda,4b49570c,8bcc47c4,8f362bab,7750b4f7,4f30cc49,d8e88dac,1af56527,30264580,d1f22612,e90597f8,694aff0,96001848,8a243ac,f4beedbb) +,S(c7b9c3a9,a189eba0,54742c40,c4afdb9e,5e07e6c0,e442cf06,32e9b655,1e607e8b,5bb68277,2f2274db,62084cd1,9c1a545e,ef6b38b8,d4dc3e30,fc58042f,f01822ab) +,S(eba4d342,30dea72f,29a339ba,3ed4306a,46c761c2,bb6f9627,3406fa7,50dfd956,fce17a0f,23d278b2,e3da1747,706840cd,d31b01a5,8793506d,2155cbf5,dd237cee) +,S(a4d36dc0,2177d471,35b4358c,6adec285,3595dcf4,6cd9acc8,944a569f,82c04155,85a29779,63b21be0,e378fd0f,b5a60fdf,65f3e45d,c2fafad1,13377f4,81f00281) +,S(4916d063,ae8bfae1,e3f5bf56,fde73abe,eb165aa,4e6d4a16,9060ac95,76109ba2,a7916703,4a0b40d5,f967a08c,a536b7c8,3b2b0b4f,67638656,4ae9b4d4,4c3f22ee) +,S(761cdb10,b2966030,85f8f1a4,404ab49c,9de01979,85817f97,ecbae412,eedd046,1d115720,763b545d,72f8f50a,b881e7fb,9789f0ea,8dda90cf,2ee2f3a2,2e193db7) +,S(d7a2570,4d718e92,df85541b,490bc13e,860ff014,e8ddd9d2,e05fca2b,8dc64ea3,5e454b9d,21346767,71c0e035,fbc6dec6,6102db85,aa3acace,c158f43e,534cb90c) +,S(2af6004f,7962c52b,b0ebcb06,32975bbe,a6b9a99,4dc5a5df,eb20a43f,3d4d3bbe,6988a9e2,26f8cc15,3108e3e,b68c6596,be1deb1b,53239933,d91e095d,d81a14f3) +,S(a92740e5,3bab0860,1127571e,5d33184f,ca805d18,75ba4959,74108f5c,a9504255,5df2851e,2eb76b71,66dfd3d,3aa84e0,96d49c85,10daa44e,68d75eb6,c6d2379f) +,S(90d0961a,510d8a6b,60a87c44,93a0c8ea,76856770,d076057,bcc7ed98,70014939,74d4753c,1c913088,66b6f7a8,a2386ad3,7c13dc2f,85b4b4d3,f8d7603a,ccaa545d) +,S(ce52bea,f2e3a604,f62bfa27,92e2e083,8dd5c6a6,ca338ded,249be611,4ecd12b,a869de73,738a0a2b,7c824444,925f3d9b,dd08670a,8f8ff1a1,a4988008,2d5c009e) +,S(99ca8dc2,10e3fcd2,ffd39a47,1c06ac49,12215441,6cf16be7,cc3e350f,f3cd05c4,78087a80,131adc2c,6bf26309,ef0720be,4550fbe8,912142,c6ce496a,dfbc4982) +,S(be442cc2,9f5a7bc5,d07ff1f4,322deb90,cbfcc6a1,7d8e611a,b51ec610,a202d1c6,6250f2c4,680ed934,8028f2c0,1acf5bb2,fb3d1f25,e324b734,11156128,77c084a2) +,S(53f5f5f4,37fb010,2130346b,51b9b14f,e75d95f9,b8f80e65,67770bb0,e4ec8e54,8da52b53,c6e733f5,aa0dd2ef,23e2e1c2,24c0d571,328520f9,cb1cc5dd,28c62f93) +,S(206ce565,e90ebff,7d799e3a,134a56f6,a897ab19,186ed554,11de6daa,5c8c4d6c,c2ff5d22,bd2d6dca,7dfec5c2,e79d5320,aaa5d53c,38ae0675,4dca9a96,a6a75804) +,S(d1dcbfbb,87ee2fab,811f2a72,726d2b54,2176a20,cc23f744,faadf2ac,7073f443,106c63b,41800bb7,bcafc27e,3f8337d8,f71da693,e1f4350c,1870f968,edd17db9) +,S(d21aa173,c54376ba,1eb9d432,26ffc9aa,a516fd0,ef17c2f6,db117392,db749328,37cf5df4,e01480d6,604f79de,63a754b0,2326f9a4,ed74cb24,7724c682,6074e424) +,S(5234b024,a22c69a7,569acfbe,2cbb7ce6,15e56383,f8e1e031,78dd54eb,7d1fa3d2,2beae442,651db52d,62bc3b04,2a5b343a,b4103895,a74aeddf,d9189630,8bc000cb) +,S(9e6e9875,9f3e21ab,a709dbd4,f598894d,f5048dcf,5ee6cb6a,50941c13,35412f64,2b670199,e38f2e5a,424dd169,e047189,43111033,a7e4f4a9,2dc26906,31757ea8) +,S(8416e295,9a718e77,10df8a92,72de9bb2,89232c73,832597fc,d28f2928,8743ae45,6ef49202,801b408e,d81b7904,4cd1f002,20732a74,764c44db,4c77121f,1133d139) +,S(852a4fa7,48a3b2f,326405eb,e52ba2dc,27462f72,9ea3429b,b108e27a,d53561a5,3e06c046,ee0d9c23,6b0e441c,2cbeb672,770b99f7,8d062ac6,a81ccaf3,a562e520) +,S(2880dda0,2dbe56be,b93b876d,3c083ced,fa6097a1,cb234c5d,3282942e,3677c1bd,dfb0ea10,92d46bb4,fe95366c,5370dfa2,3d371f78,40e919d3,bf966441,f1bb43a) +,S(cb6fbc02,9e828d7f,c03dbf86,99a676a0,37b53555,275c86f0,7709ff89,f1819c65,fc4e2d9a,36577399,15cd50c2,1cb76cb8,ce9161fb,e05babda,ce516277,86062266) +,S(8087bb5b,ff1c3438,21b24106,606d0ec3,abc76a5,8a872161,5f6305ef,f81afebe,578b287a,a602c02b,8f5c5030,ae9a4632,23a4437e,944f4353,d9bc17de,824ce72) +,S(369f54bc,30f2c90c,7af0def2,2517ce58,f8ae829d,124ed482,653a28fb,42d3a33a,b8f2eaf,35af7e32,c63c97ae,f5962143,61f466bd,c4cc1b40,b4526157,b9b59d16) +,S(87be4c4c,1b2f871,53bb2448,ffdb6ac7,df294628,6be49eb6,edd3d533,1fed8f7d,7ef474bc,6386c0a1,5771ec54,21cd51d0,71fdc8a8,66938a2a,dfe6f4eb,ca0effb1) +,S(7b6678f0,18f75bea,8c310eeb,239edbe2,80393f1b,5eed1cfb,c013fa29,1e14715e,78e8b8e2,666ee69a,7388275d,2aa1bbf3,d985707d,3dd52890,c181a8b1,f38b1fd7) +,S(89ec641,96729e02,2a9608f5,8fba388b,77d2826d,6b37caed,90d27394,b160f135,5def3142,108d7387,19ee5a7,41deb18b,5e3030b0,d919a1f8,ac94157,a4786cff) +,S(2cbec739,3769090b,3aa2acba,b78c3fac,8b83749d,641f9311,99e6d1a6,36177f8e,3140e7e7,57ad2d5a,cb34a007,f4f26aeb,67fea7cc,8902fbad,2ca92083,f3de8886) +,S(678cefcd,a2d6a58b,53e7b116,d03020ae,29d57618,4663fcf0,2ebcf0ee,bd946908,f45be9e0,13298eef,37cd56ee,932b2a41,18834fc4,331c1713,314bd028,e6a3491) +,S(8ddbd278,adcc4ece,4692305a,94cdf011,5073b073,c88c1524,b43f1822,c73ec0df,90510edd,3c52c6c8,caa9ea1a,e28c7784,5d2d675b,a33b1022,68b93b17,80fc5b0c) +,S(972bf082,b162ff5f,22b149c3,d238260c,607d7878,aaf70739,3041d0c0,d7e36626,4685b3ba,f61cbca4,d99b64f4,3e90a442,6eca9f24,d0235324,797505be,4c4087dc) +,S(42af0d52,66604ab9,7de801c5,4514d23d,d8c1f760,bc86280f,540cc57c,bbc97230,5649b89,8c9029ed,4357160b,d97b74d5,cced0668,98de3b89,77192bec,1699ce38) +,S(5366770,87296d1d,8e6138bc,a9a1a0c6,1748ee21,4c0410a9,fa5623f3,d7bb30ac,e0683a60,786ba0d3,52619c2f,672d90ba,7c297b2e,59591f31,fd8b8fd8,ed5cac1d) +,S(a03b6284,e85bb18f,f04308d6,bce40e91,7d5d0ab4,ad920255,9de55c11,fc39fc24,2739ee82,c22cc348,23fe7235,a939db8a,c073005b,e014b564,4cad5a8f,e8785493) +,S(2f394ed7,268a53a6,bd998055,a24f7dd,f5801dc9,99233a63,7332e24f,26b66e97,b52b4f3e,e934ba86,d1bd3714,a26bc4c0,e49d09f,5d055413,8d3f4cdd,73918d88) +,S(91773010,527e537e,3aa0c19a,611ef5fe,7740bced,ef0b56eb,bb35a12c,7133f8ab,68f937b3,28b64809,27e1063a,bbbc36b5,b097ae5c,ccfbb965,f4814f,ea9fb5b6) +,S(2851bdbf,cddc8af1,7a20c1ae,bd529df8,28486bc5,50a00b24,763600d6,904af615,d302c085,702e27ae,6d46c376,33035d6,ee2acfc8,3b731758,5d15b2d6,dccb1356) +,S(e986d7ab,25499f1,45610b79,1b47e597,8be3d363,5a6f29c2,5d34da48,314bdfef,d0638dc,b3b3c150,10ec63b9,61104559,cfdb182d,31c41c16,5f53c331,47de35a6) +,S(bc45db2c,5639b2ce,2dc1c5e0,d831d824,ab44daca,7fbfa099,b2e648e2,8f8bfc03,5d93e3b1,27b289ad,49e32740,a9f53e0,79a80580,82606884,2c1f9b52,7213e32) +,S(4145d67e,47d9809d,2c67b4c8,49e29101,849ef512,ca7b22fd,667498cb,50a8dfc6,5471f4fc,2a4f7f82,9708604d,90daa64f,daeae007,d6290ea9,4922173a,4513f096) +,S(2d157f7f,4cd79d56,bb15314a,a738dcea,427e3087,e7a5afa3,c1ad740f,5c686825,c1c4f318,76159f4b,94e7a29a,2766bb46,962a4e21,3a7234ee,eabf1ea2,296fc1c0) +,S(2f426284,77040b2e,5dfe26cb,c12a81b,d6e89696,8226987b,361d7961,a73933ba,bdce120d,141b2879,effcf601,c75532f8,a384f942,879f24bd,45e483d1,8144075e) +,S(b419cfa7,6cc91302,e683c9c0,eef23ca7,bf9f8f44,37ea220a,b8a1fffc,3bbf527f,bb86954e,290f2419,e4891a70,b48806b4,a911e956,e3cd0dba,3c0251e3,aa929517) +,S(cdb4a6f9,5734164f,c7af2913,f0ded939,2b17bd09,b03698dc,ae2d72d5,4925236f,89eda236,bd1bf5d7,e500c47,d4996451,d57c963c,4f125ff,c9ef8e6e,aac8e7aa) +,S(ed4ea751,a45ac44a,33e6f2f1,50392fe8,a12a8c4c,2233ca3e,321800f8,f408c256,9c7e9da7,4a2b349a,ae9266d4,d04d912c,a296d963,98ace64a,caf40634,970ffef2) +,S(9b06fd38,fdf963c2,830ccfcd,1df08a73,84a74b02,fa79a87c,96decd0a,3cfbf5d3,e866461c,e7ee6015,aec4ba3c,d4dad0d6,3ede27a3,2a1b20d4,eb29de00,6b226416) +,S(df11481e,efc1cd1a,97e13f1e,e0702056,c2b7894b,de1a44ef,5166e521,1af6ae75,a1411856,35429fa1,ebee1f24,de73e2cd,80c76661,717abad4,a8354aba,222b7e02) +,S(f8328d01,b1f3fb3,d07bc65d,e807c619,46e4df15,a518a845,23da032d,12a3c9f5,e29dbc74,7746d478,9ca9a6d0,b5ca9ebe,de174914,7a709df0,d5e0f100,cdca6216) +,S(3e3afbbd,b7fc2301,f9a13590,acc4fb5,ff0d1b7a,92e09e46,1fcf0093,4d3fff86,1fc7f7e1,b9821c51,bd44c8d0,9619aeb1,a5c2af1c,3ec28742,f0f26212,6eb6ebd6) +,S(aad17eea,68348015,9cc19f8b,69d335b4,78ede880,4c551660,74d1ea9b,1ff86125,e993b8c,ebab89db,67cf45bf,361ee910,dfa1749d,26b488e8,ed6cf9df,9d365257) +,S(213fbb19,5515c686,fe8f44b6,fe26a178,286442b8,fb29072d,37ce9972,910ea35c,497b951b,7df7f4bb,2d0ee577,19876203,d68c3958,62781362,18e8969d,ed52a852) +,S(cd7f72a5,78ed819e,3e93321e,c8b8c7a7,eba91b47,92821a2,92493790,370120fa,a3d51c70,99280f2c,fa2c537d,991077e6,ca4eac91,93e97ce2,d8ff5fcf,45bb1148) +,S(70a360c7,a72939,f9a3a28a,1d1a9e2f,8240aec1,878f9b19,68923e0,b67f3b51,a1d9c07c,53a4dbc2,2ea4ae36,b6a0bb8c,dd175c98,6d2f61b7,3eb05552,ad710259) +,S(544a615b,4f8e2b66,fa1dd19,99e9cbe8,eedc35fd,9cda6d33,7a076601,21b5e46a,75d26db9,c76fc8d7,65286aec,bdd9c97f,d7ba7a9a,7308e6bd,75150b35,ba8451e5) +,S(4218d79f,76a073d7,af19b265,74d5b5c8,f8b779f7,36c23c92,a01c3467,8ec8acef,6815f631,49073b5f,e65c05f4,eb284c21,87e60355,e207cbda,f2c01eb9,becfb28e) +,S(6ada2638,1a82acc1,8a333759,8635f83a,3deca5d,9e4dbb38,64a2fc1a,a269b0a9,53d356da,65f7526f,60d05f32,b8b5f841,2e77b6f8,b61533ba,e8ace229,5eda6c08) +,S(5fa99d01,d9f29a59,75518e98,7c382c41,8bd46ea4,7813f579,3366618e,e118b09e,d479d238,38deb81b,dcce381e,4982652a,f15f6602,dbec34cd,6fc0e82d,33fc3b39) +,S(cc6ed576,34cc67ab,6ea676d7,2fef96d3,bbb4a00,b2b7fe44,12d0195b,44d76f6e,b15c15a,d50999b8,aac9e5f1,5834284f,dd801b0d,da4be94,f520af62,f7bf820c) +,S(e4cd0fdb,5323ea3f,deb10bf8,90a26b6d,ff447679,d8747ddf,ec32ee3a,40ffceb4,fbdb40c8,ba9c4357,656af718,db7629c4,e2caa87b,c41f8c48,d5d86a30,d220e1f5) +,S(77fd722a,ba51b929,ac1e3ca1,a2346833,b3c1fec,7a756568,6afb7cd8,9b88a8af,d02519e1,d6e9cb4,4f378ee3,1df4bb74,6b5b555b,2c7b0691,9cf90f5b,3de98505) +,S(4d391fbc,a9dd3d47,9d3ca57b,f299f4f8,6291e523,95ff73e2,665418c2,997a41dd,5cc9ec33,b55e606b,b93e9fcd,593c43f3,e5d4a3c4,39ec6fce,1a9ebf25,b4ce899e) +,S(740bc446,17b17b84,5c99d63c,3c92fe81,2eb232f8,8161a2ba,83f3a445,73084e97,fd8ec6e,f4f9567,71717481,c1301876,fb10742a,99028c67,883254af,f8355464) +,S(c258c21c,adeb8453,5bafd8d6,cced030,c6aa12c4,1bdcc392,b2d10e5b,1b46e5c,7cdf037f,3e60bd7f,739d08af,a20de5f2,b73646a7,5ec3e2af,4cb62139,5d171d31) +,S(8fc88069,733a4d5d,bd80261,c0c9ca65,fac22a5e,1bffd768,dbeffb83,24130d44,4211a94b,f88c042d,54d37ba7,41cee691,ca5bf0a6,38f0ca95,954f4aa0,12fc946e) +,S(cf62ee1a,40321c24,7fbb0e0b,ce99d314,f5152de3,32b827c9,67a61bb9,c96ad4c,6284a7c3,e64f7b8d,4bd978c0,77dc0d22,e6137336,6410d5a1,9bb09640,1ec4a3fe) +,S(53351f8a,4d447760,ecc88443,19b69160,bb00b3ca,fd6fd9d0,6c0040e4,549f8ba7,83844e19,3816e6ff,755c148f,d5488384,c7c1cbb8,8c09ea0a,16352bcd,377f6b83) +,S(a02063ce,ee2c9191,94d0e1f6,2ace9407,baa0157a,d2e600a9,e173348a,1d06bb0c,630461b5,55653f52,da9b40ea,c4448a8b,fcdaeeb0,1007dde0,5f4c186e,9f146339) +,S(70bcbdcc,25de1764,7274f374,196608aa,c360c09e,951b9857,5a6a8d6f,e1d35660,3bd5bd9b,716359ce,80b5e719,a9e1d40c,3a1c7430,94a82b64,a90b0f4e,db461d74) +,S(df8ad77,83cfc3c0,6fbb1fe5,2a515de0,54b161c1,74155fff,13812d19,aadc8fc7,bc4090f6,416db0c,9d34ff20,a0b7cb99,af38401b,1264c604,44ec7355,80069569) +,S(2504e9cc,ef399800,5f2fff3a,452d56fa,8788df47,e05509ed,777a9d9e,540a30f9,73c506a2,c6f48efc,af7f4d2f,ab5fd833,6fd6514e,db690a51,11659f79,7390612a) +,S(24ee0724,1c920334,3a6a6fa5,68979fce,18a9ce0c,819e3a61,571141a3,5bc97025,ee642ecd,605b84e8,68940a6c,cd7f4d93,fa0c6816,2fb0bf6,ba22427c,b0bd7b8a) +,S(1ead5ce0,9665c05a,63cd8eb1,12097f35,4961e12b,25c03093,e1c6d919,7a3929b3,1800df5d,a1abcc4a,b1c32fbe,a1dd7120,7284b5f5,dee7009d,c2f4aa6d,7156fcc3) +,S(47cf2ff2,26084f8f,9020b0dc,d838874b,160c69ef,2e5e89c0,98e7891e,ea05d507,a340d3df,129b5aff,1044d0d2,c3866464,bca2efdc,8dc83516,cf8fa522,d5fb7d48) +,S(4064fb9b,8e2e4952,a218bb8e,ae474a4d,51f050a8,3f9a7e75,b04e39c4,42d6cbdd,ff9cec76,a2ef1930,92d3e02a,aaddce0d,18ea66c0,d1adfd2b,9c7886dd,b835de10) +,S(838ac8d6,e58e20d0,321e0150,ba6d401f,cdd70a40,69d980d2,22de3353,fb81904e,993a6f96,2909dbbf,7b9a6b25,14153331,b1ef24fc,e892710,5f95488a,d95614bc) +,S(a5e36d83,189d43d2,34d6ea26,ecf5943,5aedee72,bc4cf385,5fce9b5e,e202f266,78c02c3c,e25c3b89,9dd2933f,b41435a3,dfc2d1b5,e7ebbfe9,54ab1c94,79822c55) +,S(9e240cbc,d357c4d3,34f31209,58d6f7ad,5ad79e7a,9b51f572,5ddc8fe3,1fba72c9,aea34a5c,ed60a062,ec1476b7,b30b3c9c,68cc5e10,cef9f0eb,6729172c,b511f06b) +,S(ad1b0646,bb315380,5c22b91d,1ee47a26,dfc9ed5a,860be0c7,ea8daec3,b6dc2eba,ee2e61a2,2499c509,1a910c9e,ea159873,a298daa9,6d30d8bb,353b9955,92dd2083) +,S(4f7b0889,11d8f64a,550d8c7f,11ecaa6,fa12df74,a236a0cc,35cb7cd3,5b0ec72b,931af41b,d297e18,b4d9ffac,8d7f8691,29b94250,f1de1d99,3e31525c,4dbb21e3) +,S(dab2a170,e4108f3c,93fba874,70bb12fa,834d0274,35695870,d2d3523c,93d3a7ee,262f12cf,c37f010d,deaecb24,d08ce35b,293a5c6f,1746651e,7bb0b2fb,c573ae4d) +,S(3437257b,784d72e,419e5082,311b5a66,d499f687,c4bcfa31,7abc7484,a3cf39be,ce9bcf07,6da8d68e,8453fa14,3b06d7c0,f38bd0a0,76f1cec2,a49b3bda,a5c398d3) +,S(4594ae9f,82611ab5,bf786024,ea34bfaf,939fa409,34ad155c,9ed5e736,899545b,2255c7f5,62b0ba72,c3834e72,e77b478d,77d3f15e,3ee0cda4,c4b3f928,ead450f5) +,S(7337705,12db06fb,36b21fc,26b585a7,3aebb036,b22743c2,f13212dd,81898819,753ddd59,725fb0a2,561cf461,c587f3f8,848b53ed,29283c51,5150c57f,50307887) +,S(bd915814,4d2afef3,552d81c1,8c74abc,a53f4c2d,654f72e,3f2abd66,d69790ff,1af609e1,7f27e373,b42b3277,a5f4714a,31ae895b,95e0c5b9,50e7ed2d,1827763e) +,S(8a11cd4c,a51dfee2,28c1ced9,3d8870d,67782740,1f49fc73,d4ce56db,915bb557,d30ad7ee,ae9f9c97,eec27822,9f47100e,ca46b3f0,27339719,6be0f619,56f5cf23) +,S(7929b5f0,2802bfeb,6c23e688,65b0272b,cfd058d7,c0a45ea6,97d46d87,6f9bfcfd,f9bbae21,8039783d,4d1e366c,32a890c1,8c80d1cd,41f08b36,963b54e2,f4fde5d0) +,S(80df06ac,1d5b966f,8080e79b,cc9f01f3,d55f8855,9b1a58bc,f6e4c526,3bd89d01,346926d0,a59558a9,2625614b,ac010f36,5ee5c337,2660fa7e,be41aac9,41136538) +,S(74545478,9ff383f2,94a92b4f,383ad13b,ed4b01da,d20f4ac6,efc83315,be5ccaf7,36489f77,81ee77fe,de1ea165,c4cf2b5f,e8217361,9e760cea,fae777cb,c160fa9a) +,S(2c6d35bc,b213a8a0,95c11fdb,42828b7f,e562d7d5,f877de67,de62bcd8,5af8fe85,aa30e370,34094f9f,4502206c,72f23298,2e60139c,2bd35631,44dbe6b4,c75d159b) +,S(8353657a,9d934eb0,2811846a,728cd162,4b43429d,304aa7be,830da70f,b2e338db,f8400438,20ffa5d,28189c5a,ce693c8a,ed4a4caf,3aff83b1,66a9d404,74e02b71) +,S(f216e93a,54ce56d7,c7ef6336,561a6299,2177ca73,4ed867f6,fd1a8ddf,aaae494f,db0a3f13,a0fe8326,63e8fad,b11cc347,8da296b7,2f1b672,3f43ea44,acd30611) +,S(dc371221,9b5d73f9,6562baa4,b62ec7f4,2e9a3dc8,de6e7112,273d0811,a88324fb,eecc9092,ec563e96,3720acaa,929f9bb4,4f1c9015,7c3300fb,581b154f,df57c004) +,S(db34736d,48f0b4f1,e1ef6029,6ef534ae,b10f047b,4256516d,d4499072,36649475,1c29cd6c,f7a8c786,952c34c9,b93e5188,1a116966,164d0fdf,dd1be4fe,ac586bec) +,S(a248457,20468424,f355af53,62f5bcf1,971b09ed,358fbd33,78fc7297,3696add,9a703d61,37d0deb8,a3767a56,c2e24573,baffc931,bc850694,8c9a3776,26547803) +,S(bb7b806f,a9ac753b,bbeaa429,31f68d0e,3eba38b9,8fb25ed2,40c9faa3,124436c4,8f812574,a1a8bbe8,d9b682e3,d9b0150c,7c6ff9c,f9b42e64,6e5836a8,12426752) +,S(6703c476,fc28a023,f6619427,69e0f068,489344aa,74495ad5,17b096ff,c3ecf446,8b48023f,7c9ba723,584211a3,6731e14,f42699ab,522e15e,ed3ac43d,28e2a38c) +,S(bcaaf8e4,bfa4b448,fe23f3b7,a1612b82,14cf0daa,349463b7,1b44ba61,e2dbf6a2,bdff2700,e2cc953f,e9d08835,dbe8793b,b07498ec,68ccd736,d6fe1710,d5c7f404) +,S(906b4fda,1a557220,1dd5b446,d726a2e6,21794517,3ec74f7b,bfed8791,9310cd49,d753f2db,cd2c4d28,d0304bc4,78690871,cf838490,2d7f4f93,441a74d3,892653cf) +,S(9ec09783,18f7d95,5180e326,e1bfdd04,fa5369cd,eb786905,8d726ac3,9ef93d5f,9cca8057,994b1641,53ac6842,4d28fb70,ad22baf8,f894a049,d1794add,97acf205) +,S(53347906,b75440ec,28362a96,f114d2f3,6f823cbe,bb0030f3,a2de3314,12b8209d,ccb38e0,471f8abe,47ef1bf0,29550ec5,59581680,3e19034a,b06a090c,ca0c1fa0) +,S(27c53f29,61b70480,93e24b18,eb357807,a33e5411,15215337,3b98f80d,d23a4870,5a3f4b8d,e18636c4,71fc70e5,9ac8c4e4,703fa5fa,880594fe,2f3b888b,da575601) +,S(921927e3,7a115f9a,12a616ba,cf55c213,22ed51a3,e75caa5b,eaccce75,de59b68f,bdbb7c7b,c1e4c5b5,98afb590,6263d779,55884e71,17864ae2,e0636c4d,727b141) +,S(973b3c87,6eb81ffd,677c692c,ae432751,efb3e609,1a3d9ff8,dde6cd6e,3f3ea8c2,340df771,129510b,a4112c5d,adbcecd9,8684b0ae,3a9683b8,49aebdd9,57bbb0ed) +,S(20b817de,f0533767,9938ef03,69204700,d5972c32,12656ce4,205e9ac,1b01ae71,2ae2fe5b,e2daa016,1c65c352,94a0abc5,c6b1ce64,fea99c12,34a14aa8,8395707b) +,S(63e2544f,7a7e9181,7a347b7,f72eb43d,ca9fc5d6,3d931402,aa6889b4,a3c95876,e62aee6d,20d714ce,5cdf52,18bd5fae,adf49cb1,f86e6067,f91cad71,280d16b1) +,S(2f90de10,71508cf0,b3583abf,c47d762d,a69dd472,e4183421,6ac39753,e22aeb80,5371bebd,4a0dd74,625e5e02,5a118488,880f3a89,9c23e64b,76193abd,3788d389) +,S(8d423ce8,faa96d05,45e37cf7,5e5a351f,7c9359c2,ad1c48a,c9adcf29,d2ed7209,83d4b83d,ee76c401,a18df794,8a655c3f,bb9d23c1,5ac0bd6e,ea80b129,bab40f2) +,S(12fa4142,5e028aff,303111a2,9144242,a9c91d88,55b3ea3,becec110,80181efd,6b95b370,8e792b57,ac10eddb,362eb10f,ee5c3b8b,b2e37d4d,c4d2ac40,e8c3ff57) +,S(923ca95f,2a3bdd7c,d7505632,cdf2d730,ce70196f,ffd0cbbf,f8347882,8a706f73,f8b0c866,c39b6173,b383983b,210cfff3,1903afdb,cad0b2ee,3e541ab5,2746abbc) +,S(844d53e,878240e9,63e3875a,728f4704,64ce3aa1,66209776,a869e0d6,88893646,c60cd291,92bf8c1f,f98c47b4,a713bc75,1c84f9c7,19fb32b2,5b855e73,6feeaca1) +,S(43786fd6,c5471d8d,ba277ff8,1005a5df,8838299f,66636b2a,65e7ac21,f1dc98f3,d292a2c2,9c8c5bbd,8f79109c,b8706fe7,745ff884,f98c127e,9142f52a,56091b51) +,S(6d1bc28d,f5e9ecf6,38783f71,fb98a2ce,bb0dec45,8b07257c,e94736dc,ae36d7ab,c2c54192,bfd80447,86214cf7,a28108dc,e2c00e07,2321638d,a0e80023,88d549e6) +,S(6bc4ef34,7f74ce3c,2ef3f89c,c3e265d5,6c742ccc,ff84b7f6,7d8956ab,16ff86c6,eb4492fd,2d2ab04f,1276be35,c6bde62d,be26a6e4,60c5c66b,8b0fccf1,79b46408) +,S(6af45075,fa810958,d42a756e,d08d5c,d67a62b,cb33cddc,b35fa99b,bf678b38,adbb724f,e7682c7,678ffc3f,ab738666,886c7b93,84960bfd,5287ff9f,ba5bff28) +,S(eb6d8b76,36466365,a96f49cd,355b7460,939f340f,905ad1ca,a24e8a66,55260600,7ae9cefd,aea30b7f,b9ba11ff,603b81d2,41f7a187,33f95c3,3c2bae0d,7fbea3cd) +,S(bd0c2233,2fef7d3f,6738dd69,4bad4cf5,b34d5e9b,ad6500af,11e4575e,91795068,eaba5c4e,2ea0b21c,a9100b6,66823a4d,a91c4d57,3aa9d136,76f820be,9d1cf209) +,S(c5e23bbd,c5049419,3483e083,14249157,aa56d9f,804374b5,54c9879,52b7e392,4caeb8cb,f684217f,bfdcd02e,3aa4ae3f,8d59e766,855b4fe2,f7f8ac7a,6e597751) +,S(b5717631,f3aaab92,5543edb0,3d21c604,17178e98,dea38bd8,10867cf8,8c92d2a3,e74209cc,324a9ef,8b31874,524dbab4,d2bdf0ac,8f1d20e9,a02409f2,8c11942a) +,S(9c456099,49601f2f,caca85d5,d30a07e1,b2d17b7c,7b838cca,2fe4b5e9,5d305cfc,2d7a1540,a109dc7c,2841b61b,31e50078,329273c3,585c8674,674ee06e,ff04eeb6) +,S(52ae2946,c0ab36c4,a8aff175,73b6604b,e33dae5d,73228d54,98c77a51,8aa82f63,70e23d9b,66061bfa,4d03f899,b65493f2,7179f5c8,643104d,24dd771c,777f87b4) +,S(149ec3bf,55ff462d,dc1ba490,384081e9,89db9ac2,c29efdce,f4f59f0a,394adf9,59c1d88,b91db942,2ae8fbc7,ce6951c8,49642b5c,df949801,341a8bc1,789dd7af) +,S(aff89294,d66718dd,dff83534,61538da3,dbe14a09,c14d0576,8a163810,42ea7ea7,71866beb,cf5887a5,ece2352a,cbc256dd,7b615491,2a88cbb9,a924e764,4d59266b) +,S(de44f478,2cb30472,ad52d49b,303e2b41,33887eb7,38e2ab78,da7bb406,584e76fc,6798ad84,25bad82c,57c630d,7ac8ef21,b13d08fa,830edda7,eefd23c9,ce482bf5) +,S(e0bc7a73,76169366,c172c88b,e1ba02c6,b3a380eb,2894e134,5a2ec7c7,39682e61,bd147eb9,33b18fe8,dfe7c0ec,87b7e993,5ad1f7c2,ab5424d3,c23609cd,262cb2e0) +,S(5ee34f27,2af69f33,9473cfa7,a536a22,ed26139a,71cfbb11,27c7a476,32f0e6d,c1df8f96,dc0d4d82,f6a57de9,85cdefc5,1316bf10,dc3636cb,80762aea,c4e13b8c) +,S(4dca3bc1,77fa7a63,9b8c274d,fe157d7b,67296846,bed5d13a,68bce5e8,e599a0f2,8fd2b558,36fb9aeb,fdb3fd75,8f59c8e9,2fb48968,52eff2a1,d01c32c5,3d2fb234) +,S(554f6bc1,87560290,ef9ed937,3e993f54,98081034,a03484f5,bc184751,f8b48136,b454c3b7,dfd512a3,517834e0,e8c3f50f,de80863a,1e0fd83d,2064a6bc,a172b26a) +,S(95a81b50,a6c0879a,6a960b2e,162dc22e,955af87c,b539eba4,20b2825b,85592ad4,be55e8c4,dfed22d1,f5872b75,f38aa4c3,7c7d5086,f67011af,2651ab0c,c45c712) +,S(907b6d53,9e496a6e,358d14d3,431f5582,44a4f8a6,ea291d85,3efb8be7,477e5c4d,b3d3d694,3853bb9e,67817fad,1dd7d1d5,ff33e200,2922665c,21f872e4,77150eac) +,S(8527c81b,b342576f,67737cb2,33f17605,c8884c64,6b7a8357,5bcccc09,c7f17aa6,b6d675bc,db8d5249,57b1930c,145777f1,9cd47b9d,33386a64,5044e8f5,877604fc) +,S(8e1e3a7d,5a320d92,4ea13436,f906e9b,bc6bf83a,819b9e9f,913974e2,efab00ec,d94f03ab,d81d5f25,c323dad4,ea792c50,792e07c,79281c4a,ff309e0f,f418b0b9) +,S(fc02cb93,be1f4a8d,9acbd86,bc68cb6a,dd0d8949,5cc7434d,72cfab75,519a8d76,71f7a532,729e45c5,98a6ceb0,885a256e,ffe4cd9d,967e84e9,8b73c772,7e4d4f94) +,S(cf981302,a2858b3b,b1ac44db,4f08751b,ff76357f,9b2ed6af,80a289b1,be6e7b8,237e9c12,bf23666e,70205ded,984f1fa2,f1a8a828,b88847ba,d3a1be88,8d73b528) +,S(3e6e45dc,1408e920,3ca74cbb,ac8d50cf,71718d1e,ba05228,e97dc4be,a8231d82,2e3fdb7a,2ad3a805,f61f287c,a7ef86df,961009e1,f0fde8a3,14774677,3b1ef848) +,S(bb047795,7581471,10809088,8119b0ee,3ce1b2b2,df2668b3,749b9eda,707d4657,95a72efc,5f95f3a6,af5ad697,7dbeeed2,8d6ee55b,fce29bc1,bc439168,75c67587) +,S(4e015d42,b8b02c10,4aba3103,4ce04cb5,fe356d,81291939,3f5d1b9,68dd6748,d35b20e7,dfbf6d71,d94e96ff,c9267422,746419fa,811bcd2d,d3942c00,70a870fb) +,S(609a4c57,90c8b210,9eb7391b,d68d078e,70850af2,410df867,92a37459,24a49daf,f3a6327e,bc965b3a,581cb14e,78a4390b,14431d00,d1f34e8a,e35502f,bad0e98) +,S(ccbe0736,2a955ac0,4e1b7558,a17ecf61,b9ea0761,305b4aa1,780bab03,a27fc730,f96b7c16,6c98a1d7,65ea4e3a,e0643298,d981a012,4b03fabb,71fc47f9,1c92cd3b) +,S(6ed60282,85df2302,e6b10ef9,4e11ce0,9143c569,a84388c3,e2151c69,c3ccab14,675ea3b0,687a3b78,e8fc7564,9665e62f,e91b0d1c,25852608,1d591ea5,1ad196e7) +,S(bdff05cb,a0cca14c,55b3c592,38515532,70806177,443dac7f,4c07ff69,cb49d8e0,5149ad04,86cd8ecc,274a7239,833910f,f09d7993,aaac9798,1dd106da,6e0c9a50) +,S(64ce68c,cc70325b,22be5366,579aed1c,af9f6e55,c2c7386e,ed579911,4e2bff2b,f8c89976,3c8a9a0e,ef61dddf,2213cbba,11bf1be1,eab6506b,d596aede,45cb1cae) +,S(cd42e46f,489150f3,dcaf3c06,e1e5a2f6,b40de7f5,626107ed,af01471a,18ab2bb4,d9c250dd,d2026967,b4c921f4,e253a788,17f11f89,f679e5c2,81dfda0a,1bcfada) +,S(f7c29007,e7145420,e2da7e8e,3ec4daea,5e9b121c,35c4ec43,59d55f01,89619735,66451406,4dbda93e,637735a5,6a06ddb0,5ea2933a,36cfa3dd,c2ba4a33,eba493b7) +,S(6339c1e1,d4944856,26b3d221,4715835c,377609d2,d91150f2,c5c1f679,5e93b7a8,efbe6dea,47b4e8f7,ff55a20d,8facb8c1,d10a6960,98762d95,be532fc7,3ed59b28) +,S(fccf1f13,7d22ed06,5f4bbcf1,e9f4eb86,7b1ec78,d9f40b4d,aaf58014,3489b37b,a5a77c2f,ef9facc3,881559d9,d9756b4d,6646beaf,21b3511c,64a4b550,7dbf3e10) +,S(da97ff10,6f284ec,f123b554,17bc8f5c,a13434d7,58ec3d4e,935c1600,404f62d2,65c2168b,4900330d,f2f1e3d1,cd8ab92a,4f308222,881a493c,f8b301cc,af12e168) +,S(6676a4d5,428a24ce,36957556,c1b44593,343ab6f2,21f0b9bd,dce2d898,333e4fd8,45bddca4,b9332535,f5f4d3d8,3467d793,b7afcf58,45a19593,854b1c5f,3daf7b41) +,S(791e6abe,cf461420,54a22c7c,d3deea41,53396e7a,2a619ccd,30212ade,e57859ca,e4033bfd,8c55c93,ec732990,aff43ecb,e2ec07dd,17e4ec92,68a7b0cc,fadd37a1) +,S(3a7c7bb2,d5181550,a78985aa,84b73246,c66dd947,4bd7c5ae,20717f31,af0018a1,2388eb17,e03cedc5,221f732a,9e505f8a,b6c38d25,184afd14,37b52d45,fe9d7459) +,S(249a2db1,86801c96,9cbca936,101381d7,62b74017,2b454c3b,ef720bc5,413ab999,da185c41,76aa91c1,d783cf9c,85c075e8,2f708e0b,3ec930cf,f71897b5,d1d5e7a3) +,S(b25e0d53,b4e0cc09,985f21e0,c5655e50,32c0857f,b792b136,14da6885,6b4f8590,1bd17aff,6b02e3ac,e1cfac42,fd28d837,ac5b80,42b21055,d6b84e67,5d83eda2) +,S(73605368,5e83388,a869db66,f110243e,bd1073f7,517fecd6,1359eab,b7862fcd,e9c7a02d,842c5a6,fa43407,6e12d41f,e767fae5,5a75e913,d6912536,6d5f9d56) +,S(ec2f0b56,71392e97,2f8a0c9,af259d42,2e5b52da,5e70fff9,7115c961,77f1b1d9,47f7debb,adb24e59,c8571fa,98e56d32,d49e072b,4fdec818,2049498e,908183a8) +,S(7d7a8fa8,250dd43a,91a2ad2f,320e18c1,afc25595,213778e5,cbfa6058,4be2d378,6b48ba16,89627d77,2700f11,9bc20d7,fab2b07a,413f752e,2a0e111,60fea3be) +,S(316a71ce,52b6723b,a67aaa01,e26082c6,6e59490,cff4c366,5c695ff,aa6713d7,d6f1c1a0,7820c612,12b44cf6,e5cb4ba1,84152ffd,cf82e020,e95af73,d6a1cb9e) +,S(21a2a8c3,ade89ff,c32e5fc6,ead97a22,9ace8857,11db9930,ade6e72a,9fbcca51,95fd3d04,38df517b,5712aafb,432f0e35,726fd438,a2b941e4,7c56c1cf,8882e4d0) +,S(3f181867,b3ad8170,dad46c68,f513afae,1ad2cfde,41f9535,5369ec32,728f94d5,a51a94e4,e9f20eaa,d5599189,4222ab0d,91abb8f0,38b00a91,5f09df10,a2317527) +,S(e9673139,11be39bc,f11ecb9b,690ecfb4,79b7aa6d,3158ea69,7d0092f0,89f63c1e,c100cf7,6f8783e3,8de2017c,32022a0,da9be6e8,61307546,1f98142d,4903abc2) +,S(61ea8ab0,1407ac7e,547e94b0,6f3986c6,d3096d43,2bd08cd8,61554fae,9008b122,e5c55bcc,a6f713a9,76490488,e69f1cee,150167f4,283fa792,a105ca8f,f4a4d182) +,S(ad8fae7a,17457fdd,9f481554,239a3f1,49673df7,24a3a402,cab73f93,bedab9fe,53b7dfef,7966c4bb,bb01d037,12563f79,48517220,2ed375d4,d777efef,50f03e6b) +,S(8605cedf,bf7f2e54,d3f62f27,44d9d436,cdf9974c,9190020c,586818bd,b6a829d3,5af8a55f,ca2aa1a,6209fe4d,a7708ff6,e7a33df0,50e85873,d786f54b,7d946b88) +,S(bdde544b,465b9ef4,7dcffa5a,7a794cf9,6e83253c,2f22d4c8,cbcd2d6c,ff921d87,6c536367,7ba867f5,5ede7d23,81be6ab,ec97c8d,f88a1a74,14ebd6ce,8caadcd8) +,S(31882a45,e8b088dc,93eeafca,85c28f49,62a47bd2,bad916bb,fe3e7346,32fe1cdb,b3588f0,c5f86e1e,12ab833c,12e028c9,d03557a9,e02aa1a6,fd11d693,55f176bc) +,S(17be4052,45800f9e,db510b72,603b8e63,e49fadbd,62798883,b0d04f76,a5dc1202,1504ebdc,df8855ae,28f7738,e40d277d,81667e55,a2f59cb9,c9e33a4b,8d32fc54) +,S(c633bd33,bb697d2a,6bfc4e69,707f2b28,a303eaf5,a601b08c,9c56afad,cb629537,86e3f413,2d4764db,f2c06b92,461c64f3,9f3b7f78,33139eac,2b4d59b7,ba18cef8) +,S(f39e208a,f4c710f7,190881f3,a33cd113,633434b6,3b460062,570618f5,8260bb52,90c56805,807b36f6,272e2b66,4d943c33,d0171ee3,ba5cd4e2,bfe52f92,b9e2e62c) +,S(ce984394,14f29607,a54ddfb3,72db8ac5,ee4e5414,f59f73db,89360232,f4a16c54,1a4805a1,d1057b13,c72f7835,4d40ae96,bb80542d,ba5ebd7f,627cfbae,ba24e0d7) +,S(5266e79f,81107a4f,ba571af1,885d755,94504122,a15a673f,6257f633,bb0a76bb,5e7ad1d0,9cc85f12,8773ca39,77b55c20,18d38200,fb739918,d3b0fc96,a559b457) +,S(4fb9de57,63f47aa3,bf370113,c778bc8b,67507009,5126f5c1,1ffc158f,be7056e4,2cd97636,8eec7197,aa2fa34,72fe3db2,29fe0275,8789d75e,52e87553,1486f7ef) +,S(ad168024,a99eddbd,aabec840,6158cb92,4ae7bba8,d233745b,ded57407,23cc0226,ab105015,968e4673,8ede230b,b53c4be6,9ee6386b,91ee03cb,a21f7040,f14095de) +,S(55829ae,f7cc555b,733aea9b,f1b307d,277923ba,148ba8d5,5a7c8001,73719cb8,6a7b2eeb,9c9b9585,5403b47d,6c60a7bc,382969f6,c4bafd3d,3c4f09a7,63267689) +,S(2119f233,8efa4e0e,2204bbe7,84e9de01,4e1e4c43,450d5910,960ebc38,6b78b935,9f219dc3,778544c6,7a337db9,69c513a8,52acb469,34a71957,11c36913,b8e7bb93) +,S(11fc3e1b,9491be9,d7de53ca,a2558d36,c5227498,3f5c1b32,57f0fe5b,b1295bbf,1c69c74d,ecb05933,6aa6b6c0,231105ad,91b8d188,d109ced6,2198c528,844cf6f5) +,S(34b6ce6f,ea6e5143,95091bc8,67e606ad,5e64ac18,99085821,80abea3b,dfd2a908,5b6ed904,f4bdbef3,fb9e41a1,32c7a313,28e9f325,4e180694,40339642,2bccad6d) +,S(6c225dca,b45768ab,3b1c567d,97ef745c,b326fb3d,2db6ae2e,22a40c95,3610a84c,7e85d752,2180fd8c,ebf63cfa,2d843bdb,912fe042,d00ea29c,d72fd768,402a1084) +,S(5f776e5,41dd95c2,32fcc757,14b688b,cbfd2020,e7043e3,2a707144,5a8ed7d7,3b8c5c78,fc6d8354,3a09de0b,9a64d529,c116803f,6d0d62ff,2a20b369,8b273c0e) +,S(3e26d8c5,531543ef,5e37eaa6,3244faa5,d5371e48,16fd94e9,b8bbd932,891b0e23,30a09d1b,43a4a036,ee1a53bc,6c3ebfa,a5b4c70f,6d8af4b0,c70faabe,b79bb65) +,S(c634da91,c17a3568,aaa970ac,26553e45,6be8afb,ee12c85e,8aa0dabf,f18b36af,649681ba,e1390a7b,d05d34bd,98d87ed4,16eb9f99,c606f46d,6d522019,f1a925f0) +,S(ed335d6,4d643598,c6eab4ee,fc242d7e,4e8361b3,ac8d747e,806962df,2e7e9a7e,f0e7c3f8,19c97aa7,2334b690,98f28bee,5a1552e7,f578d5e1,eb56b600,fcaa93e7) +,S(d37f8c09,411359ec,3f63dbf2,2870ffb2,d10be164,7553f28e,d72d9585,1e521581,da7cbfb9,ba3ae036,72df1be7,56d3c9be,831467d4,cbe3b51a,191e47b4,9d1f1922) +,S(ee3121d7,c7475ea5,c3aae061,1c6b420c,5b32d05,ee86f919,43c3352e,7515c360,703b2e37,97bea3b2,9b447411,dad7b12d,b809164a,ba690281,b76f245b,bc4c1686) +,S(7b42c9bc,5c2b114e,a0ef1a59,492a6132,3f5c7290,427572b5,fe98017d,1987a12b,5cf76382,e85b73d7,56fcd92a,99242725,dd57edde,30ddd9c9,dc7dcd95,260d27da) +,S(9af5ff9a,b13a53a2,93f9b6b9,a0f925d4,7c8f9b84,5f6933c3,ad074922,f8a555cd,ca93ec9e,89954734,c8aa13fa,5908c855,13a9ec19,6417042c,a336f1fa,be5d4153) +,S(5ebfa274,1a2df1b,6e1d591,f70983dc,a5b2b850,856bd7b6,59c81877,3848dacc,b0adcb9,6ac23c64,2904c15e,822991e8,46e12411,f472e0fb,5fb69fc7,a0f7ad18) +,S(93b58d08,465e5eac,8518382b,c1f6ebec,daeb486,7da65dd3,ac125e6c,fcc81e6f,54be8918,c3151784,d74646c3,6bca9c8b,8a50b8d8,63b1db8c,f4fb3ef5,1a24a4e7) +,S(a28a579b,4fb46474,ffc943ee,32b40664,5bc86899,edaa111,32c31f1d,cb6fc858,40ee91a3,d5625648,196605f,f650ab7,6e059b14,faef6396,46c9b153,9af14670) +,S(e987909,781d5560,b71f6029,750d20ad,add7cb47,f90c9078,e8de5f2a,d606ac9a,7121ac3,4c80dacf,ffea346f,5c5e1a81,c55318de,ac8cc907,10274f18,ee9819d2) +,S(291ff11d,158780d7,fc0ee62a,e395456e,5c84bca9,75e84a7d,1d2b3bf4,61e1dcef,c5c8cbe8,abb6854b,670298ce,8224a945,71e79e37,9335acee,c230366a,53ec2616) +,S(4adb1390,9e28b53e,42bd9e57,373aa131,efda7d16,b8dffd82,4bd9803e,fde315b4,66d7eb12,b827ae7c,970a796e,5c0c99b1,24eb7002,4fde63ee,fa2ecdf5,d4b1456a) +,S(55e25f4b,95240efd,e3c7e47b,2254601e,1707a8d,e40bf384,6b3a7024,da7591ff,e9f2257b,7e98606d,743000b3,72dcba0b,e4491ae3,22e82266,4b1e2b5b,78c830c2) +,S(d24e7493,e41dfc32,be7a6d8d,5463834d,388ddd01,8c213ad8,aa3005b1,fa747eca,e73a8216,a51b4b16,5e9f5bee,414d49f2,6d7feba0,982b9e93,fc4b7863,48c26cac) +,S(a510b252,6d015da1,cb7e4600,3ed61af7,caa03562,19227d9,ed8eea13,61fd8b2a,3d98c2a0,9015abba,63eb15a2,80c6c479,eaa2b2f2,a0011adc,3565d2f3,8abea726) +,S(c04d04d8,127500d5,15bac63c,ca55d76c,8404cde6,fe681f4f,6b8c2b48,87b314d1,cb3fcd77,9fb80eba,99cdb937,31bc0814,e3cd4458,df7fee1b,98c4067a,db4d9d59) +,S(ec9c7c61,146c3357,ba851e69,18ffa770,6b5dd2ff,a789245a,df70f90,eebd0649,9a09d3fa,10ca6923,c068803c,e9161923,b36b0709,b12627a4,dafd0e3d,3d186170) +,S(95df5d3f,5d504c45,f4b7e840,3805e54b,b2598511,2ca53064,baced58,a0488cc,a43dcd85,89b85305,b07d1ef3,23eb305a,35079cdb,743dcc21,c7a6ad48,4ce8ecc6) +,S(b8eece0c,3a950c52,c46bf50e,b5dff949,2fc8ec4d,6bb19651,c72d447,633a6d16,74e942a3,1b75bf83,ba6c1460,d969a2c2,4a49572c,ce3fb84b,8d0b08e1,d5583744) +,S(599ece16,d1f69c22,53deac51,75121ea0,c82b2d77,c5e2c0ba,520bf1c,72dd09a2,48a10c3,25af3d0e,dd8e2e72,5d7baf48,b2fdb672,66423859,9f73d231,a911bb14) +,S(b8ba5a06,8d9458a9,6e2fdfaa,961acd80,7fff711b,bba4e3bc,35a5fcdf,e82ab32,8035ab22,7554582e,9038845,44d32a53,c2d82417,6e2ac7e3,2d44cecc,50f8ca4d) +,S(b6846be1,cccd7865,e56d3d7a,f1b1fff3,ae806380,a1710c50,8c35ed17,227e65f4,bbdb7025,32945f0a,de989f52,68230763,361ee9d4,9c0e6241,77fe6fb6,cbc7201) +,S(a1ffa65e,69872bbe,ed009e53,f846d9a1,20dd31b3,a11932ff,c3580ff8,da9d0fe,aa32e580,d5763bf9,dd054999,68b6ba6f,31c210cb,26846ada,dc0045b1,ceda215b) +,S(9b38176d,67091c7d,f448c707,80cef08a,2ad73cd6,de65eebe,b62f9a21,730d0fa2,22d26b19,c0fb9b7e,f1ec86ba,b8ff5996,64a45988,190499d2,6fb604ed,4e609207) +,S(bc2ccc9e,209dc64f,bb132553,bdab43fa,accfa4d,7deac898,1fa52841,35fd0cd2,47366adc,176ff88b,674931b,a8791fbd,350d1d13,71891343,74d58305,a55ccfa6) +,S(1ce000a1,65452a62,5d036f51,4fbd2a30,d4518734,e7f93aa6,7a7dcd7,24730f6a,e09103fb,5b90f0ed,54b34baf,3e3d5bf3,fa288acd,b6b0ec19,ee3062af,35c6811d) +,S(846c569a,887d64c0,e8fb26a4,49c62447,4cc63d68,4da0909d,63dcdd0a,dde0031f,547753,132c9f98,d7facf93,d4ff0416,7dcbe44,77987be4,7df408c6,fa12c07e) +,S(6365a8f7,28656e23,c9c58518,5686b18b,701f7b1f,54c84b82,f5c81ea5,74fe59e9,8c7cddfd,a992e53c,ad151d46,c9cc0b3d,be27f2b5,7ffcc23f,c8d9cfa7,eb16c2eb) +,S(ed425f3c,89ae3d8d,97972619,55e8fd17,71dc5bf5,98c5237f,bd267f80,7d2939fc,4226abdc,14f7a03b,cd7285fd,19cf14f6,10c98d0,6e3c1d74,daffd602,99a3590b) +,S(cda5246c,2e1b7ebe,8d667f23,5ae310be,85a0bd7a,2e903d56,62a6dca3,971f00c7,791ef296,f8ea9b34,918534ba,318a4fea,96b2c2f3,21e6d3f6,eae8248b,29247f56) +,S(b42a84e6,ce79c1e1,bedd3f7e,596a11c2,f5017d98,386fbbc6,f906a5a3,f4eaf99e,2e722cc9,60bb3718,36ffad5e,47509fcb,cc3d0601,70b02610,823fa40e,d407e6ac) +,S(358be08c,e1e2e9bc,b43149df,58700875,be23cad0,ba8524c1,6d46a01f,ab0bcf90,f3c4fef0,70baaccc,f64fe0bf,b6f5111b,462318a6,36489b00,34f05c44,1f9d1308) +,S(3ed6435d,e5b36230,a4f74bfe,14571041,427d16f7,9b433ac9,85c9e135,6016a789,1c72e85e,142743d2,b5be677e,352d3dff,ee0dc56d,5aa56d91,4b92762,6041f26f) +,S(249f7e2c,580dda16,5940d7e2,672176f4,afb7e50,b9250610,c253d9e6,2416c910,6fc16311,49e9916e,8f70f842,3dcde36e,1630f508,79e96e48,6dc7147b,3aa9f50c) +,S(97b3b144,e8381ba3,1b0f6f0b,752cbf91,14d2d76f,6f418d4c,69f0de6e,c89cc85f,67c9bd30,33b720b5,a1449257,f1de85a,f7282260,9e411dc2,1820444d,c988724f) +,S(3b38459e,868b2912,51d0fcaf,41245087,80610d0e,395e9b68,cfaeef1a,5f395a85,be5180dd,bfde7454,c78cc9a2,b77245eb,91ec4c25,9b17e3a3,c3e8e49d,5225ce6f) +,S(4e6f1790,9f33e08a,914974f4,48270fd0,74fb35d1,49a017ef,c54fe21c,96163ebf,fb6578f,6f47156,5b6d3491,3a9a5e4c,dcd2880,d774e6a3,e56cd078,e6b9fd15) +,S(9141ac63,e408937d,7425a0a6,70a2565e,72e301b7,75619a92,18db32da,315c75de,d35e290a,56bec3e1,3cc55e72,12aa57db,f10b34df,bd7847a0,5de91c4f,546d6045) +,S(ec9b73ca,72052751,565c006a,4fc9200,337c9162,88eddaa2,e212c611,395ba578,37e11ef5,c1a22e77,38d5f3ab,4c74e2f1,ba192275,4c4e7905,1b15010f,3c224887) +,S(56fc14e1,bb1a928f,ce0430b1,feaac6e5,aef50208,be530d7e,f0f5b81a,ce1caca3,4e5a6084,f8680d07,9f3101d7,a80f452b,b05e597c,c38d9865,f6d7f307,90209001) +,S(aecd741b,2cebd4cc,82b7c362,70f1b22c,cf3997c3,f180e1e4,d803a89a,657df731,5f104b33,6c0df49f,1936356e,8dd09b3a,256bd317,afffd4d,8ccc57e7,f90b8e21) +,S(516267af,54f83d52,24a22b9a,4309e9eb,9b5c1072,31c3ff0d,418f8bd4,15836cb8,4187389b,9e062c17,f4ef6fd5,4b6b8439,cc37e85d,8a3db13d,86592098,7befe4fc) +,S(68bbeabd,8d3f4473,f91a0368,7383b4ff,6e7658dc,6e1287e7,f258f543,2466fed5,cf63c80f,ac99b42,7a67f7cc,d978d5b0,8656fc7a,6a383c27,48635ad,97049c4) +,S(20ce22ab,69467e9b,51d59213,8b52c1e4,49ba908f,909658a2,b90dbeb5,b07b67be,562da07d,9f4173f6,9232d17e,49ba2c17,31649ff1,4a9dcc3e,68f20dd2,de97ce2d) +,S(b5b7d6d3,a4a59f92,3afc1ec6,a5215786,9c86cd90,7ff80b07,d04160ac,6e798f78,d05e32c9,775125ee,dbc55af,4d1597b4,45b5eaba,5bbf6dbc,b8ef3e79,fe9d4de5) +,S(955bd489,7a4280b1,5de3d848,f75f6dba,3967e593,6b077d4a,cdc4c30a,33f45df4,4bbeb7cb,5d79991c,ef3b9fe5,bf25dc01,6448261b,44b156b2,749f9734,3d453a02) +,S(9f60e951,98e7370e,b3c02fe1,8bf53735,50fee849,9c876211,201e47f8,660a5a98,6395aaa9,33ed5866,a02570f5,9321d89b,c865a7ea,62e28a6a,3a62c4fa,4cd613cc) +,S(7081f0b6,f5923d0d,be4041c7,589a7100,9c2b6459,a255468,999f2d4e,50d776ee,9cb60005,e067019e,93aec9c9,1bf28b4a,27f3f0a3,288c4758,403a9ff7,668f9fc9) +,S(e290180,d8d5a7c,1b0e982a,bd63ef9a,b607d605,87e663ff,fb0ab73b,3369561f,462776fe,77289a4a,250ccc7b,80b54e51,993f741a,14299f78,61b88d17,d4d924f7) +,S(8aea7328,b285bd5e,b63d5939,c5c8c6b4,ac254cdf,c42cb521,2f4c5643,58598bfb,b682da77,4fc55ff,eb4a559a,8ca0580a,13819aee,990d9e22,8e0192f8,9568ec2) +,S(e9d108b2,54b24b57,ea4fc287,45865c09,27302d7a,1dfe90fe,b3a17906,2f256e68,fff7274,6d29d9fb,e7b0fc0b,1af14365,8d0ba69a,a45a72c4,8f67b939,aba128d0) +,S(9ea1f93d,1f317e61,786d4909,429e4cc8,b81f2914,17d28913,6d886b86,adba0fee,231dff25,d3b0b351,6e63ba6a,afdee115,975a5c00,b95936e4,5d9c6be4,6980ec0a) +,S(e8a12415,e5fabbee,7cd687c,43e8d530,80701d01,85980c5,7181b68d,481e7a0d,dd69839c,e263e746,99462f18,58745727,ac53bf2,2e0385dd,5d6a21b9,922f62c6) +,S(e287f3ba,ae486145,a1c2e04c,7f6d5c1a,ed796840,27636cef,b4446ff3,6c3def2,9395413d,401db0ea,4ec53bae,ff215580,5bcfbe8e,7e6bd6e0,be5b9fbf,9d968c63) +,S(8f99f79c,ec205ab0,e79756eb,a14c8e7d,fb23e232,6ab77927,641960dd,56ad1194,805953e6,15cc6d6e,2f61b0da,389b24bc,89cbff4f,c9f0ade8,c5dfff99,e819a2ea) +,S(9c87ab6a,8cb723ad,e0cdfb59,e5a1ff6d,3adb63d4,7af33e14,c6b3c343,c766f586,74798122,7a3bd79e,7d5012cb,bc81cff7,6a3699e3,75874200,4edc6e8a,a965bb19) +,S(c52c8608,6f245de4,baa10b7,fb512ff4,6042bd50,7d88bc3e,c75ec75d,d99dc00a,e8c2813a,bae8b8bd,9c8762d8,37d42fe7,85e5406c,5fb5cc2,ca05ae03,4ab3f844) +,S(b6286e1,94d5be25,9a79c6b6,ebd634ac,dd7c3fd,66ab0de,d8d4e160,ba8dafb2,72ec2ea8,ee0bf270,777cdf7b,47991524,27eaaf24,2a0334aa,18b3855a,899b5910) +,S(df7b56f2,45f2f8b,7213792e,370ca89a,45c648a0,5f3ba4ce,8c5d6d34,2f086b6d,386ced48,3850bdcf,4209fc90,d039b96d,39ac18cd,5d97ecb4,3df23ae6,1596ab4a) +,S(2acf4c9f,4cd42357,3e9110ed,a64aab59,459b2b37,675e420f,48ecd068,6d46a3b0,5f1a5829,aea5e981,cddff9bb,d2521ffa,58b37baf,9544c0cf,f622857d,5a2cc579) +,S(bfaf95aa,eb55d378,7210033d,b352372e,6a64f2ac,a420b877,586b684d,9cd33f36,7d22bb13,bb61e76e,2a2fce3e,bbf9ec83,78c6ed2e,5f143b0f,60803cda,b0a3d8ee) +,S(78cdd360,4eaba890,da793c9e,f589cca5,faacb6a9,14a29f6a,6add7d8d,74f31421,ed7e9c15,5b801d1,16b0d60e,fb5e2287,76430c8e,faff4bfd,327a38dc,ea19a634) +,S(f2ebcfa9,50a391f,c7b97713,566a8a49,edb8944c,7cb68276,d9843c22,8d213d2e,b1c7630d,956f9f13,c53a180c,569d534f,9513d16,4f3dd900,bb3f5e78,b0fa4eaa) +,S(43cd60d,83bfcbb3,cc19943,34552eae,857593aa,e8158adf,ca850b9d,1aaf4c2b,ff64bab1,f721e6b,9e23d659,224998cd,996230c,4fccd302,47e9e110,607e8f62) +,S(41925ce0,c01a49dd,7be0c3a3,b27f13b7,2168dfb,a5ec1315,f9209709,f38ea93c,5346b95e,cb6a0ac0,1a2f49c1,9b02d9a9,a725a676,f144ac26,c48f0d8b,94f77110) +,S(fd231210,6c762d82,a851bb47,8d0ee0d8,fa1c232,7e26feee,3e6ece5b,323877e5,39763316,f5a6ece8,baf748d6,234eedc1,4bf33462,1db3e66e,7eb2fab4,f96fa162) +,S(fe3e8a98,cb7abe1f,36a54a0a,a3d1c9f,d5ad684b,d05cb2,6ea683d8,f4556ef7,7d220677,34d80663,a1ff05f9,bad5a648,837b4475,abe0746c,3fa940e0,4f1223bf) +,S(e602a764,ae0d1bdc,4c3f9b1d,271717db,38232e94,84181ab6,9ba8eb73,4f5ec5dd,ad1038aa,26268b10,2c1f951,6b77b482,8bc9bef5,7b483450,d513e6f4,cc916fdb) +,S(871895cf,adb772d9,719cd962,5dd391b,3218142d,364764e,eb0bc6ff,8d81e086,49a09064,f7916421,9d51ef56,53861350,dda2c9ca,4e6269cb,555c8996,3f37722e) +,S(e229d56e,77755805,c814ec27,8fbcc56e,8ed4ec4f,4c14907f,4ab3a0e0,fa7e4b4,cdb07ebd,66d68055,bed7a46b,63ceaea8,6d42659a,ae6ebce5,795ab908,14e48af2) +,S(5535f85,6b0cc868,88ca3118,9d20d68f,471066af,a70addd6,ca4a9537,68bbf8ed,8655c844,245e2a67,8427822f,ac3206a1,f6f52953,4f7a6c29,6ab4825b,770ac5e8) +,S(10657905,4b37ce9a,e240d78e,3d1066c,b8c48d21,fb7130c,dd35ee5,24767ad6,52836b7a,508a6190,28eb013,c0355f70,4393a5af,e133abe2,e8b81dd4,83e125f5) +,S(3366b207,2521d023,99e9e311,e3447778,e796db0c,87428e4b,e6cb0ff3,a0868c1c,ec6022a4,22a8dd2c,a7f2f15d,39998394,ac908c64,74a34ae3,255a28d,4311638c) +,S(4a789396,339be46c,73608a1f,59fdb41e,91bd0164,66417332,f2630316,b5953ca,d45b657f,615aad45,809c0af8,4eb8618d,6e6e0346,ae1ba101,3a123ef9,e5b4c442) +,S(ee4f2484,fa0a9c7f,dc0c64ad,4df60628,d75d70b5,7ab9f0fc,ae9947e3,89f1302e,52b77894,d8ecdfae,df7dbd0d,8dab74a3,4092073f,47a543cb,f81ebf42,9f80170) +,S(4095b5c,163f226f,7937fbb8,3035f6a3,9aa9b760,c5086c0e,af9959fe,25f30a1f,1ce180ac,65554d4e,e9b14595,5c059f64,6a15d032,930465aa,d5547c58,5dff7ab) +,S(6a225d3b,67d9d42,412ecd9f,d018bfbb,7a36a59c,d2f53494,3d6cc62f,b0436a24,29b3d63d,9352e0cc,aa23c91e,e300592f,cc698abc,c73c48da,6a384f99,ea7c2701) +,S(23efaa41,e5f9bbbf,c6953a89,e3f4b9e2,17249254,94f2057c,f46d0c8d,71d36e93,cc89a7b1,7f2671a2,5bd7075,5c269219,88cea3a1,1315b86e,f218e493,7cdb789d) +,S(e30c1e97,f7f99957,58d591bd,6a398ae2,f972176b,f637c66a,258ad081,4f3ae55f,1a70cb6c,3e66e925,fc1edb4d,4d29bd89,3e8e4755,6825adf3,11e64b01,866509e1) +,S(be64d782,acd416d5,2b612f53,4601876b,f05aac91,13c8d265,b57ca32b,df08e278,7a41844a,43e837c9,293b81c8,73cb504f,bff8f15f,5a21e61f,9466acd5,87ad7e4a) +,S(caac02be,e009a61c,672b4c2,82fdf2f0,73ada0b8,d4a45450,76d24c38,f23822ac,7d93e4bb,a040f4e2,23acc304,75c455e5,72a9a64f,c66108ea,500ca62f,9216d06f) +,S(da2539b0,3a9cea94,9209321e,e1719b3,c1ef94c3,86d0e860,fc0ec1e7,684ccb3,e85e1387,bef1cea2,f67f601f,8067e9a4,b1b1306f,6a33df15,7795cbf0,ce3cf9f5) +,S(bf2ee552,5c965248,64bc1bd8,ad9cfba6,4ce4fe7b,be9b4198,700e936,799cc0ed,889dea1d,b1298a24,a11529bc,30339023,5df42398,e760304f,6343030f,6058f18e) +,S(b3e4b141,cb0c3662,9fe4c9ff,7a42c635,1130602a,720a6264,30b967c1,47abde36,f66f7118,c38a828d,8c4ff83e,5d6affeb,eff979bb,2e419f56,a7d7c8aa,52865657) +,S(451eb24f,fad7211a,11181826,5a223649,24a25593,63c33e01,4967ba58,889475a0,889ff940,49f6c3b7,9a5bd321,1c1f33e3,4cb2f8c5,bfb141a2,1fe5419e,44565bb6) +,S(29ab658a,6a754778,2127a0b0,c4b8af33,ea4c77bf,4bc0fc53,b5d65d07,38f5984c,aab1bda9,c77d6c3b,a619f9a,d72da6be,947b8baa,b80b16d2,15ee01a2,2bf0f2c1) +,S(9b59c407,d815c224,5bbb9c0,d1da59fa,9d9e79a,c654f8ac,2879b341,297b24db,a4ef058e,e6300114,c2827811,abacc0a9,17bb35b6,9b1b76c,c761ab8d,a676d190) +,S(87d27b65,82aeb975,8b9b970e,76c3ac77,78e69a7a,52ac620f,c0564e74,a66c9fd0,3ff3b3cc,dec29337,41c83e08,7f07f41c,4d03d5c,93268b1a,cd9098e1,37511e03) +,S(fbb3684d,38958163,bd85a0ab,36bcb93b,7fe7d383,b70d8bf4,d9bba6f6,989701dc,7b07cdc6,c9c5b3bd,10dc2af7,b2606d09,759e7342,68a5d4c0,301be264,87b94504) +,S(82022ae4,ccc42b9d,223cc1ad,c66e58a5,a3ef1494,f95274ea,cc7cf79f,4314a453,c2424250,9ddf2da1,6f0481a,9b4db450,3a81805e,9a8eaa3b,b5cd0e49,15d2b695) +,S(ba5cd45b,3b51cb37,bbe475fa,e91f8975,ab4e657c,57d0801a,1dbec958,be20f901,2e0d4fc0,f8b4f58e,3407eddd,298e5324,7f9eb718,b58e4164,78e3a01e,cf41b0a5) +,S(1293c841,b316d1be,76ab4444,53e72e22,cfadaf3a,df5b6d27,7cd065d8,8a6703fc,98f58f37,40fb4988,b844ab52,3420709c,2488f144,88049749,28670aad,5133c2fa) +,S(ec9fb3c8,54bf1bda,dbb972de,a8ae36c7,987d77e4,8d8437c2,c69aa988,df5015c6,d5f35bfd,ea59e974,961d6b36,4832560c,fe425d54,bfceccb2,a00411cc,a5486d3f) +,S(2ecce03f,4cd55b69,6cbd4466,2e7d58f6,9950eaec,6adaed62,7694dcb7,2544d244,e14f30a9,7f1cf747,ead403ca,e07cc4cc,d1bc793f,de79082f,f6615e6,43f68879) +,S(ed8faf7f,a63ee520,7825e7fa,56f6ef8a,4c6ad5af,ac507c3d,77c025cf,566fb3b2,df120b8,ab21273c,a5af1040,7fa3e54d,cb0636c4,8ebf88f2,c9b046d8,83684a9d) +,S(47cb8f7b,8780dabe,c1eb456a,f30fd917,bf3fd9f,3c28e3a5,bc078c5f,14c32e4f,f8607a02,1f16aa6c,68afc948,f21ee2de,c5889d19,8978e9af,66931bd2,b4aa3203) +,S(76365ac1,fdebab2f,3b9a3ee3,8afe70ea,d4962047,1e38e5ca,cf215a24,3d762009,2cacaf72,8b4bb600,ff37d3a6,97d45fa6,5d778334,dcddc32,11fc51b5,4e53aa28) +,S(c9dd5de0,99b8e552,e1375055,63edc83,9f09311e,11868ea8,a233309e,cc27b424,4bd4d238,4e615eb7,c68f134a,eafe7d2b,38163a8b,b117f9e4,b382236b,b8f8c1a5) +,S(22b6a7ad,cc406ebc,7c1c2f96,bdbcb6f8,9a1e08b7,822e2a31,83e5932d,ad0a8961,52b86095,bab24f4f,d2ebe9a9,534af2d6,87b553e2,77536d5e,22c1eddf,ae0ac794) +,S(3ee808a7,49fa7df0,c37017fe,cab7f6be,96f06c04,b2de4d24,a331a9b6,9f81a158,3e954cef,5f1f9ecd,887dc174,64cffe5,6c4b1356,d841ed0c,1e23c1c,2439cb4a) +,S(2938bc58,8a7a4896,de69ae4,4d5b6240,aa97d302,7043048f,3e49c222,b8fa4803,f26bbe61,9fad1d90,de74826c,ba6ea02a,9ea59a1c,59cb4818,65b054d0,39ada03e) +,S(682558ec,da97c9de,4cbea34f,5df43274,94962e5c,df72b0b1,2c3977d7,e1a15451,c4c2e765,22c7013f,19253c4c,c8ec6cc6,8b543f33,5aeb620f,112824af,b9fedc6c) +,S(720d8c68,fc520da5,79f6811d,e1f3d045,cbfad09,f7f7d8c,8ba68b4,6493620,b867e8a8,4f7a6d06,4d6fd4b,8bbb31a9,7ac26c3,b485fa29,50d545e2,644c9cb5) +,S(967fb3e7,1bdf658d,356153ec,6c0463a9,994d5d2f,b3aca9e0,2a17f5eb,f4b84831,b84a65f8,861724b3,2f5d0926,ec9a84d7,e3cddfc9,c7887a09,4cf602eb,547cc83f) +,S(1d9fd25c,77ecc3de,8e5fc113,1ef13b9a,73f6ebd4,f8673d88,db2a418e,8bcedc85,54a06301,d9720fb4,bfbff58e,23fa4233,33012c9,d62bf0e4,aa6adc4e,ae8035d7) +,S(80138158,a1137af3,114dff5f,f346e339,7d04029f,9050d44a,b4cea89,f1311c0a,16f49876,e6d6ac18,c25cc712,da3afe70,bc5e9489,7c55dc36,bdd234aa,6a5a6b31) +,S(aab4021,77fa5844,e3a0906b,3107df22,33aa3418,222a8c55,c6c37933,c3ef632f,9b83208f,3ad0dced,382d5876,7a089711,9a062039,9a7fbd2f,7034e5e0,3201b092) +,S(8f3fd14c,7670f464,d9ef1e3b,3014be60,3c523237,14bbcfe1,d3612f13,fa72f10,84cb7094,7901b81f,bbfa593a,5c8606e6,862ef6f5,d71c30a4,b546c08b,4205c68e) +,S(3ba9c91c,aba3c06f,eaf4578a,33979ec8,df69a903,30cb8d88,e49953ed,4a1f4933,7048a74c,3eb66231,e8410799,591bbef,fdcff65b,b492072f,582ee47b,7a6f99cc) +,S(2f8c37d2,89dab0e0,d5152468,29f6cb61,7344c21c,29860645,5f29a9ca,dcf36a7c,37f0b64e,9d02710e,bfaf145e,69c79965,4223d093,7a834201,d2f74d40,eb508396) +,S(45e6eba2,c9209d27,b87f6050,a656fca,73fc6128,cedbd2d3,ec40ca,76dce846,a3e28d44,ba1882bb,d1c91a63,5ee22582,81386757,4e66ad90,8a062c93,bf5f16ec) +,S(a5ecd3d3,80a0cd23,4467143f,fe842d9d,82ea7d9b,98ad23cc,605fb8b1,fd767ee9,22f12823,8ea84269,3fb31fe5,b5015cf2,c9ab6c33,d167b95,9bea6e29,4f11353f) +,S(f7f45a71,c4663b0d,44369821,318374e8,51eb66a9,ff6034a2,c943ff90,174be83,3a1633cd,4ec197f5,40d3d6e3,e6a3281d,7fbdf46c,f52fa149,8acc0a43,5b46fce5) +,S(92582286,6b314e17,5af03b7d,e5717d42,52bf6c82,a55ec832,a94b274b,487cb59c,fc8e9584,736809dc,65234670,495bbc7,d6c2f52c,ddfac4a0,369f0527,4a811f68) +,S(c15fe8d3,2303d00a,2f57fa96,6ae6fa75,1d7849f1,4dd527b5,a7f76cc1,e556da4,36242bd0,4685dff1,a67c445c,50cd348b,e017c06a,e2e9cd06,7b5fb109,81c10951) +,S(49ef826,152aa60e,310372df,270bf0d4,4dd7136,7d72be5c,a464f60c,c62b5355,7cad4ba2,dc4480b,9a1c572c,77a93e16,4e369d2e,b565e165,d9c7d2cb,20c4c645) +,S(c8de09e7,538ff94f,e12c876e,163133e3,629b2f1d,ed6686a3,be4ae122,9c91a18f,b5a7f31f,e58088a1,5f1e872,d6096562,9cecb10f,1a76fe88,5eab6247,697c2635) +,S(d86b9fa4,616f43af,1d7a6cd3,d9af24a9,6b3d5119,ef764576,9461ffeb,96abb344,2388ce8e,8f931b49,9481b660,669cb8e8,56df6f72,e392e539,fb570e19,f003bcab) +,S(a2cd7618,f351e2b1,3fa7b719,30fe3041,87c4969e,4f3ec55a,7433ae6f,cbbf88,3e0b5c62,436a363b,1455711a,b310c362,29870cd3,a096324a,a8dd36b8,5d19d685) +,S(b7283cd4,e33e4a3d,7836e4f6,b39b5576,ad6c213b,ed2fab87,ab442ccf,2100b2ca,918006fb,111c2307,1821e7e3,25eab3f,9083367,4248fc,2733173e,8eabc9ea) +,S(b1fd2d2e,9707ba8d,355b123b,9ca31365,d12e1854,6efccd9a,cda40f6,48b9a769,8c37cc16,8e8f55de,f604d222,62818bfe,1a40cf3d,62dae94b,58c9ef4b,475e674e) +,S(1b0997e7,4242e85e,cb4be32,885b5a6e,cf6077c7,395d262e,7c0d2b82,cb39f90f,55b4d8d4,27cd1d8a,ed8c2d2e,f3bcf8ce,f30fae12,4c14b183,fa36923b,6b7760b3) +,S(56ffbbbc,94ac925,dea36258,8ee1bbb3,4f1dc9b8,1bfd7e69,8e055065,d98d78d6,aa73208f,46d72bdb,20af3d23,5bf1c5ba,a517fcb7,b8036208,9f8a7198,d8edc65f) +,S(c125fab0,7ddb7f9c,3426cd36,812611e8,e3908191,67228685,3533e0d9,3ad7045e,2806703f,622f654a,f6c3f118,92c1dd8f,1f235ef4,4df464b6,8ccd30f1,9b77e5ae) +,S(e7ede9db,e4e0c742,8b1fa6fe,e81e80ae,dbab85fb,f259d301,48a51423,fe7f4a17,93ab277a,9fbc5cfa,c80d32e6,5e7f50d2,e236925b,c2dba1d9,e635a56c,d33fc066) +,S(74701763,f1bd6bcc,470c3da9,d853f967,a47c1628,c48b1cc8,aa395159,a3df93f3,ab2c011c,7c5510f3,37393dd5,f05547ba,bd22237b,28ed69d8,a4b6ed55,5d8ac8ee) +,S(8d27f97,55baf71f,e6dffb8d,83784e32,a65541c,5c656576,89c900d5,e79081b8,a7176e68,f3c89601,4ae1f837,bd52227f,f308f90c,b7f31386,e5586125,1ac250ad) +,S(63e06afe,9040b531,eac0a0ff,1ac25db8,71b0db01,8e9828c1,f5798ce,accc7ea9,aaa11884,a9dbe08b,6b28fcf9,9049aed5,c911244,b2a6a13e,9300c007,f4910aa5) +,S(dc7ea1ae,27d60ab3,42d617d0,23e4b1ab,6bf8bac2,882084b5,dde95894,744ed50f,93c7d76e,2b95c5ff,bbfe97fc,754a5a3,b63efba6,e111540e,48a0291c,142f3dfa) +,S(f3aeef6d,f69cef4a,3d7dfb69,1b5aea99,36e40239,bb976253,2213bd1b,f6e842d7,57d37dda,339c7002,f87bde03,1cb1e8ae,72e5628e,f493c115,1fbd0f46,2208de5d) +,S(825bd84c,316e64ea,dc5d081,23d7272e,ae87dafb,28f69b67,816a1aca,76bec3ce,61e3a7fd,ba8370a8,6a3e3f69,d62f87f0,849a2564,97658f1d,c28ca11b,40a52251) +,S(310a2cd7,4dec5370,9d2988cd,8e9426a1,edb63b9,50ec3ba7,f5aeeb93,3856a75d,5d6d86ae,dfa5e57f,7f2b4ab3,aaec250f,e3ff1eee,3e18c228,ffa3b81f,17122c97) +,S(3471d475,62a512d0,f82355ae,f9bb6c3f,69f04db8,977ee4d8,5af582c0,1b425217,272dde70,2fe0b69e,bf86d68c,5037b425,ccd444a9,45040358,aed399eb,db9cba31) +,S(bf6d2563,bfafaf24,20a2b3df,6829aec8,aaeee4eb,ea3538d,8086807e,4c257a2f,e8077a00,7e7b496b,64f847ef,755746b8,3a2738c4,4c1e7ff1,a920ee2b,40b496d) +,S(eb33cfc4,a883f718,52fce42a,3cd876e6,d6f4d465,327223fb,bdbed425,2b9cddc4,9bd400f2,ef608bd9,904f03ad,27de86fb,eaab9137,e25de8d2,a7dada4a,1ee5453f) +,S(1317e0d0,3e5df319,fb383edf,7de95645,6b123d3d,a0d8d08f,82091d6,ecc2279f,3bf6424d,5c6f9d56,b0d22b60,706a5471,dcae4297,eacbbb25,2a9d2292,33675afd) +,S(81b09f2e,99dc43eb,eb22cf5d,c5406f30,7e00f8e4,267bb456,c99bce34,309aeb56,9d4856a4,b300eeac,42f5b1df,92e331c9,1dbc5f6f,ebf17d7c,49580180,a3361932) +,S(deea567,a32ff19,722626ba,ef4ea337,ed436d32,d23df7e,98b86644,855a62f2,5c912697,c61a17fe,8557ab3,40c1792d,4a8310ef,69e785a6,dfe66d43,9d032414) +,S(ce4ad083,5746d173,e68e02ff,a7a91b9e,96ae44b1,cee86755,ef3dc4e8,e43444e5,be86cb89,5238d4c,b553e289,1545fe84,df7cc81a,ff1c2a20,d3406f62,7f03aa7d) +,S(9a993e3d,407f1af6,e4d19a32,48a0715f,2e36384c,7d8184f6,fbbce7ff,530b077e,e4a1a52d,80a267ee,99a7bd6f,e6d96ffa,3f87001d,c543f4e2,481eebc1,301a7a7e) +,S(1f10df2d,7c7f05c8,1717ae6a,1267aa63,9247c7ef,45aafccc,6b36112,fb9bd0d8,670b265b,71e2db79,32683b0e,c967e9af,e45ad643,27cc29af,fdc783b0,58760410) +,S(70ceb257,29c9208e,7db17633,dca775de,d57d1dff,9d914a5a,bad5711,86621b53,6e016e91,b3f3455f,cde11c0e,c6d1d75a,ee9825,7e9d64a,ce7c1ec3,49df0c62) +,S(ba46e5e6,4dc882fb,dfb7921,a106060,43fb6c4,ace9f2fd,46693f7e,74694e3e,eaeb4eb9,79381ff,8a208e06,9d8c436,5868d0b3,dea049cb,f342c88,7d789acc) +,S(bba3badf,d233ad20,e4179bea,f3d7579e,a631d154,e048f7a9,e320d388,3c30d81,f2a7c70d,69dd44c7,317a0af4,e765693e,2bdfce6,8c8a51e8,ed3f9003,5e1b961d) +,S(6df6a769,d300ba68,17e58f1b,f41e0af2,57d491f,38e59283,d93750a6,36d3f8a5,63a083b3,aa51c772,eced1f31,ccdfb4d9,ebf0f492,99f12819,dad9a36d,a73a4a6f) +,S(affd131a,4b8c9a98,294c7ea8,793a5173,4fab1953,1d2fe236,1ada5c14,a7174f2c,4c3de4d9,ec4a3698,3feed322,58a9788f,3426891c,b3205708,73429671,3411be6d) +,S(2da31049,9e54b18a,19dba546,4c7c708d,d42ccac6,bc2196ee,2f0a2453,3b0abc7e,f354ac91,20ad9f8b,56d09d44,51c4d052,426981a3,f7b47e7c,bb0549f,232db974) +,S(3882ec53,cbe3f82a,e8d381ac,edb4c31f,23cdd201,eec93f2b,2dc7d0cf,92e57b61,1d34315d,e5a7bfcc,492b0046,b2740646,71a43d53,2fb0bc78,6cd80ca2,ef7e6e3a) +,S(fcab8635,6a08ab26,39bc8e4e,8e9eb5e3,46825975,2a65cb28,d559bb48,7387f9f1,af4080c0,d08f07ce,57566753,ad3570ae,bef2b38d,4ef7f54,d7b2054,c8fceb94) +,S(fd34b8bb,8a897e12,a29dcd5a,57540caa,847bf011,a1548ebe,5dd89d75,9d36bb58,51a66aac,6a56f973,57927eaa,723106e4,d19b603b,d0d5a55b,76235197,7910b2f3) +,S(1e89bd20,c0d85bf0,76c7a167,87c7d817,1d3b4660,99dd82fa,808d98e5,87d4b469,4f53a9d0,e5768760,3dedae47,574f3123,dcf11590,fbc4d353,eafc8629,3cfe882a) +,S(8a1ea7ba,66909ace,c8d7d93e,aefbaba9,ddca459e,548c448f,5fb3a957,7baa05ed,d58059e9,64f37a4,39f7655b,25018031,ea1f1fcf,8ae94f99,e09c04cf,8b7be091) +,S(e0c3780d,80d59926,96886549,af2961b0,e4451f0c,b5572cb,d7ff76d6,1d1331a1,99d9d2e6,a13c3b1f,c2fe6f1e,5230e7b3,d827ddae,bbeda551,1144f68e,4945491d) +,S(964354e6,ed23ac12,16fed36c,5daade18,8e7e1bdc,ff20e60e,f7cc8c0e,83996035,f748a09a,8563c6e8,72253198,4e6f0622,7e6a408d,3c633529,aa8bd326,3428998a) +,S(9809e729,5125c862,fc6eab86,969861c7,8bd09415,585414a1,ab1dbc3c,1afe3f9b,d8536228,bbf55568,833909f8,6fc84a58,ab0fc089,432fc05e,fd46bf63,987b9fd7) +,S(195f4d02,305e4c42,28d83bf9,4025fc7d,1d8d7173,da14bb34,abbecc4c,f01ed17,957db8b4,97aeb9cd,68152e0,23cb4467,ce13845d,3a88e21a,726b8766,7c9d637f) +,S(562eaaba,3eb17e34,efa3f726,d02490ea,b0203fe6,81b836c0,f2c44a1a,854e0b37,b4e658ed,9e664804,2d3a35a7,70ef4253,97093ba4,d7b32da5,9db56a6f,8552b1e8) +,S(84a2c5eb,1efa9014,80c57969,3302f34f,de3a602c,a4b1a28,8d79f28e,dec8282,700d51c7,88cfeed8,587261db,adcac440,c703313f,5f0da023,bdf62b36,46207cf1) +,S(83d12fcf,dbd9168,b14e7340,6c6d4b84,b93e2bad,77d4c7fb,8ba00973,3672f913,e4856e26,bf2532cf,bafc78b3,682ce9cd,3c0dd6fd,861218ee,523b5131,e7279a7b) +,S(9988a6f2,bbd9320e,fbe73bf,9f4643f8,ce64d522,9ed4b701,dfb0068e,dd5451cf,bbb352fc,bd3b2650,d0a44e4d,892f89a4,d2f431c,2abe9910,ed5a1dd1,8a882d5b) +,S(3e92183d,cfa615c7,33721d1e,2a2116b1,83017d4c,2aa70b51,60f80a10,afff0724,c7888251,f4bcbe62,f0dfe545,3a73f3d2,76a2f30a,74e57d7f,22680b39,142dc945) +,S(d9175300,fa1efe3a,4cb130fa,fb36275d,e5f85b98,5ea5844d,e7763d6c,8239492f,59138c65,e9592a0c,d9a36220,d165abfc,fbad38d8,85eeb521,c5566702,9b678b4b) +,S(6ff5825f,7c12bee6,5d17f7b4,7766e677,ed74c5b8,7a95d068,b4741129,36d933dc,661ae9de,cb7974b,2304be0a,4d2b8d80,2ea9aca8,40cd0381,31f80248,378c0edf) +,S(ed6cbeb1,a8761064,3067d580,ac024f7b,9560366b,bae875ab,15ceb116,50b1c31d,9140687e,d1e889c1,6564d60f,702e8101,1269c476,f19d7f45,19a7d66a,8617dede) +,S(5f8ccceb,32d75aa3,1096b56e,eb132230,853bf6e,38643ca4,43abe04a,8bd69164,35f72a3d,d0c81dcd,4b6ac0fa,c4f5834a,4f6576f0,21cd2d45,6bde5b7e,7995da3a) +,S(81e02085,9bb23977,522896c6,7ed66751,86580d62,f015af7c,479a6e23,982d0b7b,8791fa9e,4159f26f,b42ddc08,85d562b2,fce84a38,e2af9960,1ebdbc64,cffbb669) +,S(de226b16,dd1e5c26,9b7aba7a,d63badc8,3eb435e8,7aca85f1,41d42712,95d8f721,62e1e399,fa2ce72c,3f87dc03,de33d913,3428416a,434dd20d,84156470,1ac8423a) +,S(60a46f42,3fcd3295,fd058be5,9f7ff164,fa762995,27cbd2b1,d13a0bdd,97d140f3,9571d2de,7b789e17,e46bc31e,1a03cab5,912cb854,ccbfec8e,f4d370e,df7f1219) +,S(6fef445c,e1b4bd91,fbd3a77a,ba0c6364,80d7e759,3f42a7f5,ce089fcb,c32249c0,115fbcfb,af46db83,9ae0cae2,e581796f,f82e73d8,7d4c9a91,9a92c5e9,f4fa347d) +,S(6d37f51c,a8d2f953,a3e5f7c2,6edebe57,a9892b5c,14482a30,9145c4fe,4293522f,78e511f3,6718ad4b,de6897c,d3b90e08,cbefae5b,a884bdda,a967eee,9d5309af) +,S(c0ac827,5bd0701f,5c9cb035,eddbe996,738aa155,fe74acea,a76b0351,3d46098,e7f32a2a,188fa708,6a968490,60ce26a4,31d76231,6a65a6b7,c3e83201,f8e3cd97) +,S(9000dba8,6f895023,1fc507df,85faf4a5,822a648d,4b256b93,5d012060,50cde108,9b7ae836,94b2e9e8,bbd8383c,2f4cb03c,32331902,2f58cff1,779d83cb,654ef3fd) +,S(f1109bf4,b490bc8f,36609253,26c2a2e1,ad58dea7,463e1d9a,28aae8d6,969098a1,87431a27,9fd72c10,80230514,1c8c17ec,6e3382c2,c325b022,4a800509,5d2f24c5) +,S(4de871e5,4e9cc6f0,8c4aac8b,36d61f83,929adc8d,4f6e18b0,d1dc855,6e8c0003,25d1fcf,ca98e8a6,c75d7fce,19de16bc,805f4b70,e9a3e9c7,f0187f07,70d3bba6) +,S(a23cb675,92972bbf,3a6e89ff,94e10010,8f47b467,fd8cdc80,b66013d8,62766ece,8dc70b84,ed05c23d,a1681126,77d23aaf,cbca18cd,fd7e9dc7,cae5aeb9,47cf548c) +,S(295d0cc,e96d8f8b,91ba9dd3,be703cc5,79d3c938,a5b7c32b,bb40e149,584244e5,a6d45a06,a16bd4bf,6af0fe37,6538ae5e,745e078c,12b3ac95,2653f7ee,2b03c926) +,S(7c683b91,9d5376a6,d40b13d5,1fbd1769,6cb40bcd,efd248af,9e102545,eebabbce,3da0c9d0,3608856f,5b7ed30b,8d9f1562,197d4e5a,7c23ae39,332b1ada,adfd3f73) +,S(30f7512e,d27e249a,95e0e21f,fe22ec23,8505f39e,ca9f41ec,df5e7ef8,1c0c3189,2f5fd85e,25ea3a3a,15928651,4b473197,9e4e7f7f,56e88164,fad41e42,e4875169) +,S(9377bf8c,96584f27,324a41c7,78d6314b,1c7f842f,b4910835,431f5a76,2f514961,d599cc55,e2eddb2a,e7d7fe92,aed830d0,3cfa892d,3a89cad4,335fd6d3,69f3df42) +,S(3589ffe8,67f20495,ba3530b8,5f83c54f,28a66e78,6bff4ca2,40ac1d55,6d31e9be,98822eaa,983089e1,209c22a8,9f133dc4,d75b3a67,8fdd385b,581a9274,6d224c89) +,S(39c1b1f4,b2dadc4c,e58e0f84,1fcc6415,2c79e77a,11d53f85,999db8b8,ea3f8935,e785271a,d9df3389,6436991d,eff9da83,50bb8a42,616cd31e,6289aa84,d4256721) +,S(dcf11459,d3d62c2d,99879918,8b6118e4,b103f9da,2453b72c,ad5eeded,8b25be33,dc038c1a,af3270e6,345a92fe,7c7dddc6,a190f6c8,fae7d7b3,30a3cc72,f3a1c074) +,S(614929dd,1de9b0c1,3f4d82e5,5bd8050c,a32ff05e,6eb238f0,eed635b3,6623d1d,afe8517,c9e7f17b,a1918e3b,e8180ff6,afafdc43,1acbea6a,e0eaa75e,c4d8a24b) +,S(f4a72228,cff6da94,a45da35,5ec8adbf,ef81609f,b59a8296,a7c1b0ba,9cce743c,545200fb,de095aae,9de90f1,569c6bf,2fbcd025,3cca1e50,a25a81a6,e19cdacb) +,S(63cc4273,6caa5597,46e62fbf,5371b943,57aa164c,fc8fda65,b5fe524,e2c93f7,1fa4ef5b,c5a6413a,d6ad2bd3,4b08289,e7d8224e,450f04fe,9b47c45,ace5665) +,S(ac175228,118438a6,d2cf761,f345cb04,aa7f9d89,9678c201,6b84be2b,8eab8889,dd7df8ae,29643dac,27ab01b6,8f7765f0,832f2989,99a13396,3435a982,aa4af2b1) +,S(9dbb5eb9,637c41b6,c4a5a2f,72efab5b,823e8622,f3786c03,dd678816,9e4a0e48,772d6ba,13f4d61f,42dcde34,b8519aa2,5aa0107,89c625cd,1ba38d4e,b7d924d7) +,S(717095dd,d2fcc135,1015b586,65a0d888,4e88f599,b8c32fb1,73d5731c,3ef7dddc,1de0f109,52b470bc,fb23da3f,3c7b640b,4727326d,d18e020e,581fdfb4,7e4fa5af) +,S(5ac230d3,f829b1ea,401e3964,c14d6e9d,a32c4a68,2ccdbb2a,3319a964,265872ca,fac3c3a6,27dbf66b,c5e06a16,e319ca43,423484d8,3217ae81,51bdcfae,c9c026ea) +,S(d27ecaaf,a39f415,e1457537,b2e74e1d,382496a1,51118100,8577cf76,1f8752ef,fc480b67,46cbaf31,e3d8eb6,4121b68,d5938e84,face3ae3,5dcdfa4b,71c6c037) +,S(e08777dd,f92d99b7,c4f87d53,9fada8c5,703af619,3a088d64,77f1e20b,f2ac6cda,25a4f88a,c6cb18b2,4e96ecc5,3ce10d5c,1202c4e7,edbdc070,db05a501,29ccfee9) +,S(45ae7ab7,afe9580f,bdaa6a13,8896ab97,63bbe3e6,88054776,753a1180,699ba6ed,dc1af7ed,127fe06e,4d0d440e,3d96f43e,502f797e,fefcff1,6c46e6a8,a156f322) +,S(fd28cb3b,71c50453,b3cf509a,768b4c2e,6ae26514,5801c045,327e1de4,f4d00590,b0684f95,4867cf44,aa5081f0,8174ce21,3298a22b,257f6159,c2666518,5ce5a7b6) +,S(f226f00d,ac6f49f0,a195e4e2,23b9fba7,95681660,7671dd7a,158b3260,1c1d850d,d05d5c4f,6925a38a,b4630e53,a1986fe9,d823a08a,3691550f,10f71b65,a109ef86) +,S(3cc61613,a80d8480,87ce23a7,2b3038f8,a994e1ec,8c9c740f,f0e44e90,760337a3,8474f96a,24093af6,94221f09,f95ab010,90377f1e,52a173f5,a11dbbda,cd3c3956) +,S(721ecd89,8cd99712,bd3be233,1f57d686,633e7ed5,c95e6223,e5cdace0,ce60e736,31d294d8,6fc07cae,4a09450b,fec633c6,21dc34a1,2f7668ad,532ac192,a0ffd69f) +,S(dcbaca58,1144d9b1,b2586271,5e58fa8c,d5b1062c,ffabaa2,db0fcffa,2b2eff38,9cf7621d,339f6cff,90efbdca,5e2c6174,708b53e6,1af38689,e6d3b257,21ec7d34) +,S(ed314e93,e649ec2b,ce491938,2c7a256e,b9300b99,528e7878,3421f337,15db8b92,70a81aaf,229fef2,e2922355,e1f15465,53ea0348,e3dfb18b,c837ddcb,60744a11) +,S(6bd19bcc,7a59bc8d,19a97768,95f65ae8,5f5c7eb6,429c09,85436b8c,29c036ee,51346de3,f4f65681,bdbea28f,843545c5,31803ce7,78b5732c,bc42735,4999090) +,S(99ed1e15,6ac8dfb3,604228bb,5be088bf,ebe9d640,7ad8be15,5777c6b1,d43d9acf,75b159a4,478b4cca,80ea0ac0,472436ad,69f57e9a,f447c61,e19910c3,9d2c922) +,S(3e166f8c,793addf0,84add90f,b0303970,f00c3c3,8c36171c,c7fe0877,b2452045,91659a63,b0cd2a65,ec330f6f,b9a6cc6d,9f07e382,7b94b8da,1921aa8,1d5bbd59) +,S(fc1baad9,a3a95f38,bf8d1b16,8409d09d,a1b1a432,841f656,cf8559cd,176df936,31f7a7bd,b013b89d,5045f248,982b5b4e,e0b4d791,21b6e638,84a563f1,a08af43d) +,S(80b3ad3d,4b371eca,c903c879,53386884,3bd31843,4e9c925a,5a5a819c,ff7ff340,fb1ca8bd,aac96d84,c67ed7d3,b65fac69,108ae28,7347abfd,f20e4cdb,712af178) +,S(bad065ab,2901f727,d76c6c36,48ef7aac,2a87d49,4d727422,73cc2e4,68616af2,ae9d7902,16b5eead,4d9d69a2,eaba2972,fa925a34,13f15d92,236329c7,470a37ed) +,S(d1f046d9,d700ca6,995beb99,cc8781e5,a2fb758f,7e81bca9,bce435f9,129b8fe7,274ede5d,7eb815af,34716718,84433143,3090fc0a,46575017,fca345a0,6111a4df) +,S(db535f55,e3dca80a,58dea798,d29aa0f6,99df1761,473a7ea1,751a047a,33f0a22f,e7d8015d,931a3bca,1193df83,7e7a8f10,e61b86d6,477a37cc,ed3528ad,5b53ff6b) +,S(da1dba06,a56ef0fa,f98b1a5d,b9a4f184,8635b7e5,164cdd50,82ae691c,ca42a80,86a8383c,a69531bc,ae806621,5cb4160,8807e265,b2179508,d928e312,a210c9ff) +,S(267c26b4,d980066c,7dd4f29f,f7b54277,3b176b77,9b3588ae,ff5ec28a,9aa42e7,3390c03f,f4e5eb25,5d230053,1d93daa9,d584658c,7fa30341,42ff20b5,827161d) +,S(8024af52,4e6ff955,70c7915,208491aa,5561fd29,fee5c27d,4f3483ff,c1cbea0a,c9de78d0,498f726b,8078fc0,609e76ff,df7a8a71,7345ca16,dff1d7cb,b2dd86b0) +,S(11ff6a68,c7beb420,7f0d7dd,371cf000,dc3dc195,406882d2,77953445,6208f661,b53ddc25,254781b5,1e7cac25,c1f7e3bb,916b75ba,97a7fdbd,658c1bc0,a7b4092c) +,S(562a1083,f9a68203,39a32d7a,65a9982a,b70d6596,b00751f6,aa88c27f,36e3c929,a380ec7f,908808b,950e7d25,510ad741,66ec2061,50923364,55744acb,b1e05b51) +,S(4efe70fd,327c0d69,3b6a7598,7ef64573,e097fa5,4cf077af,68d082e2,d341c413,10d47b9b,92e0b62d,d9a8befc,3ed1db10,b110a346,8cec98a,4a1abef2,c8ce3dc7) +,S(4d64bf0c,d7f128b0,bde8576c,91e01c27,354abd98,2cd3034f,f9ac09c0,23a51f20,159e741a,f57fdffa,de7bf38e,14dbc2e7,da3c524f,3d4c8d6e,b9dc32e5,e8a5e28f) +,S(9a41634a,ff3278d6,b3ef0064,ceecefa3,466de2ac,372ae43b,c48f30b3,a187bf,eefee0f,aebb77cf,8447a193,6564498a,f409e530,f4053c3c,ad27eaa0,6aeae2a) +,S(e1804fb,9a6bde08,8efec2d,2e5c6774,2c85cffc,e78254cf,4fc4ded2,9102418b,e9cab1eb,9c1664b9,c2fe81c9,b3a665ae,447e93c3,183cde7b,fa56ab34,7efcdda7) +,S(a603744,c0247b0a,f821705a,dff44d2c,717611f0,25f9fb41,1eb62f1b,64593212,820fd32b,706a7638,4335c0a2,f8713b9a,6dcdb015,a96b9d9c,e5c19bb8,ca603b61) +,S(a6f1d9b6,895b1298,34972a2f,ec96064d,a1108ab3,aae276cb,66a620a0,495f20b0,9a95dcd0,df038394,63ff5ea8,18679c3f,7f55d7ef,83a06880,29c9d543,6dc8273c) +,S(4ac51432,7822b63,e00f920a,b6e22142,f09f30f3,bd74c418,93baf126,cdac5c48,abf5d148,77e94a46,45fda161,f9455bbe,7ff037c7,720f6a6a,d7e4bc31,a0f43885) +,S(5a2cf55b,a16eeae5,8cec588e,1b339422,48af6e37,33604475,2dabbf7a,f7fb7a9b,8f27be2d,32ff72cd,4fc5aeca,5de55a21,a45f8c1f,7163dc4f,e0c00040,e69322e2) +,S(e16f23e8,ef48c1f6,4012b27,f6ffc4ea,a876053e,30cb388f,232b3d8,db011c99,195ffd52,b0afa5c0,da95bb97,7bda614e,47ffe3ea,13429799,e8c390f,b8c56000) +,S(65367cd7,ac109f71,50de4263,cdd86e92,28923a3a,ff96945a,c1bbd163,8524fb84,cf0b9ba,fbe67dd6,4d09b170,beb4fe8c,a7687c95,68086b6,8a7834a5,1747d731) +,S(10a8840b,39443b8d,7a44228b,d6dd6647,89da489c,8e954d54,a5cef366,6bd6eac2,7ff6f76e,e4aa58de,185163ac,ef7fad13,d8cc4055,c4e10a60,7987e034,c661eff2) +,S(3fefe8a6,c01b8202,6bb9d038,c577f16,7b1db5ea,91ae80e1,528b1327,5245d6a0,a96df5a9,37e6144a,454a0b54,39d68eff,a959757a,7c9fe350,ecd58c3a,3b637b5e) +,S(ef93d77c,e4162e9,6bffb908,f5d654d0,58595fd5,d6184c62,6c3ada21,c4052b61,40088b85,c18d97c7,f59a23a8,645d169d,e535261f,6cd7466b,953fbf40,f3cd0bf5) +,S(f1789f5e,b0fa903d,485edbd8,4971b7c4,9224a2cd,519bdd40,d627bd82,b0ca4872,4c845cb6,5456457e,a2f570f4,77b1f4a1,9e36a905,adaaa8d0,5830161f,a71a9da8) +,S(d0bb1788,ebc75ed0,20c0d15b,ad4e41f0,64193890,8a8704bf,ff3cc4d4,cc9b3274,3a120ca8,95a327f4,8e687796,30666649,43ac5524,44df62fd,8f7abbff,222a7641) +,S(164ac10c,f7807ae6,4d6aab31,72110d42,2f05e461,aeb9805a,3facdf7c,dce8963a,8dcf43d4,40f1dd90,bb1d6f85,849f98fc,9b6dca26,301f3209,3f9dc59b,ea549b69) +,S(f122d965,a8e40e3a,b857dcf8,92949f0c,cd3aca29,739a2e40,9876c782,941fbe5f,4d994b9d,d9e68983,78a192d0,bb670bec,71504372,d218e257,f50d0268,da447371) +,S(ac971547,75e5a92a,1aee2cdb,f5781f09,b975fc21,816e7829,662143a4,e48870a8,249fb603,795b1742,96767945,278dc97a,53fff7dc,f8bbfede,f8943c71,43c9aa71) +,S(959ec91e,dfd5fdcc,90d3da81,1e9c870e,fb0add6e,144b3fbd,d48c485d,2d330906,1e5ec128,b707c761,b61b5ebc,653585fe,29f48975,2a4724b9,aed90a22,6257ebdc) +,S(590795d8,ed7d8232,457b2d15,76de09f0,3c6abd8d,23b5e8b7,c59ba93e,1e982859,5edd2a86,1a3c8841,60e16490,a47ab42d,a09cb123,a9d803c0,6835292d,34576708) +,S(c5372b98,7439245b,eda17853,5cad1507,48fdb4b5,bf1ba555,89714dce,a3e0ba9e,f82d0b61,7159db8c,35536a5,46b69c4c,767afc43,8b64b5a0,22e899b1,60bca987) +,S(f3d959fc,ae39cbd3,ec8d2016,630f26c4,10161128,7dcbdee1,6534f96c,e35bd38a,e1e55c1f,87602783,2ffe2f97,fe460147,da586a03,ed0ad6ce,1603cf17,ac9b3562) +,S(922bc76e,be3ce378,2be3d960,489b064d,3a28043,f8a92cf8,dd5cec2e,537fad9e,b3199f57,2508efda,230b9ea7,51a95218,116fbf5b,d1032b54,352c0995,f5122109) +,S(45c7dd40,7a6d2c95,79ab1df0,8070acca,2c461d88,dbafca12,99a38734,d9f0360d,3a17855b,5f2469ed,6c3c4e04,4dd96f4a,d076eba6,a60e8e73,2644d25e,67e85ac4) +,S(6422d998,dfd4b00a,3dd89a5b,74411c14,f1af5c9e,1f090d5b,33ee2d26,b959bacb,e2358f34,491218a1,93d8cea2,276f5b3f,376f597c,703bba09,cdbf7d89,37a3bb7) +,S(8e048214,33196d15,1a4640f1,92bf6c1e,95b1a3cf,5365a6f,535cc82c,c4b0535c,d6d2d73a,1f652c55,9f282ee5,35f55aa0,20012195,8ba94e65,b638ef50,e97c34ce) +,S(5a2b3da8,b5eb2f0f,8a25a9e1,7124613e,b8a7080f,15d42c4,a1c0709f,e64a79bb,607c791d,eb54aafe,6dc95f8e,6ef9d8a5,a6435a82,6b824cd4,4227f188,bf86e6b7) +,S(143587a3,5cf614a6,750f3d91,220abf49,c5296e00,3cdde13e,1a0d2d5c,f6cd7ccf,49bc85fa,de6cc58b,49a1af49,46c340b,15f14c7c,2e83201b,6622f2df,86a653d7) +,S(f0080c42,8737c74c,c3b2c4bc,8c9d8505,ba357b7c,ff25f1a3,ac81be19,dca93193,bdd0119f,57bf674a,7d7cfe32,7027d1c,1c6a5ad9,2ca24f0b,5cf25c39,4a3951f1) +,S(877ae373,e547fef4,36cb26b6,85d7c426,3e162dae,ac0749ce,f7748d50,5d130034,1f0af495,b750341a,ed956b79,8f268ca3,e1275e15,32e5ca8e,6f9f6df0,d4dfcf5f) +,S(a418df6f,635ca18,8c96a071,469a272f,e55f0706,b73aca0,d1df2ab9,e8e619d4,2b06cdbb,5bbb24e0,fe499a6d,aa5b5918,2e755818,694b8856,525ffcd6,2f754e3) +,S(4c213d74,bb6fbad2,25edce4f,44c7b0b4,114dc209,4eb52967,1d907637,a2aedeab,741bef9f,ccc65c15,8752c7d5,48afa9cd,402fb5fb,206c5be0,e480df73,9f970b51) +,S(a37906fd,3f94e51b,1a94073a,4890011b,2cf93bc3,bb4cdbff,ecb7056,20deb13a,60a3b0b1,c14a9b1d,184d5e55,23314b70,8a8a16dd,894aa332,f01a2d67,30e6030a) +,S(2c677eed,639eaf51,64b8ae3d,26bb4652,d6d6528e,5b85225c,5e84ec4d,4de72301,df0e4c06,d3bb7cba,17f89240,cac07c24,5fe63931,3b2d278e,aca1b9ff,7ee832a) +,S(b551f814,eaf86be5,335fc3c,5b01c001,684473b0,cfac8939,5d61df4b,7d7e77b4,a979cb35,469715f8,3033f923,b4ae1e7f,8818b6e6,11a4cbb1,bd399ce3,646664b) +,S(98d5c718,5c8c04ea,f1f61ad7,40df0c71,2cd47ba8,74141984,fba82146,ddf45c39,aca52591,5c737ec2,eaf88f5,f1ecea89,9d4a8e2c,428f5bc5,b36d2ba4,a0050804) +,S(5148e2f7,260fb652,68c10485,4fbccc62,ed1e1386,ef8fbbc9,a0b23e2b,94cefc7c,65b4dd2d,35dea498,5ba4a8cc,b1a08dbb,9e9b2716,7ca96e1,29672452,a7ca2500) +,S(12c699c1,8c9d6410,b8a40ccc,bbeb4514,a08a227c,982df1da,f91e9131,8e0e753c,7d953c42,89b55724,3469a197,50516e88,4889e968,4ed28e1,20b022d8,932fcc99) +,S(4d0d3ff8,a7734011,b36ecac3,7ebb2312,134e4479,5039ac63,9dc69d48,120a8d20,edff17a0,e0984c60,3c4f1026,197f2173,960b3d29,f0b0ea57,3979605b,144ec64) +,S(ce90b70b,3e7b7a71,a91b0985,a668336f,ccb069d9,81a9fbe4,48125061,5536e42d,8cde9d56,12e0ead7,524640ca,2875606c,d3af73e6,457f1e67,2e63a478,5569000) +,S(28c79327,6bb1879d,99fbf985,1d2fa908,d197f5b1,c83be97e,360c4931,563b2d8,c8944e40,e2f3b546,5b6b10f6,ae1cfbe3,bc0f3e3e,33d91085,7c18496c,ec643868) +,S(6e2dad06,2413cf01,804c2b6b,55b707f3,864d4c80,87d30665,9a1fea53,e7442443,9da67c64,e05d6914,30a1fba7,39c0fe36,497bc028,43441f7d,c4c035df,129430e0) +,S(bef94ac8,3763946,c434d03d,fdf437f9,19f26188,923ee54f,8715b724,8c4d20fe,d2324534,e5fc1dc6,6fb83032,e95e1406,38648473,ce7e38aa,ee7ced54,31e25db) +,S(53548c57,f1b45c1d,ca166a24,c0f2653c,9b7d8664,3d45d125,918cedaf,818e433d,cc138946,f0c207f9,c01307e2,130b13a9,c36aec5c,3cad640d,b6a93804,f10c3b44) +,S(7fd4f784,7f25c901,4e8b0e09,b8b723ed,2aee71ab,fd47988f,90f6ff40,4b5867e,ffc3debc,901f12ad,96605805,a6e402db,58eec18d,375fa976,41b5d226,74a1bd9d) +,S(444a8a7e,499789b4,49c62424,cd9046ef,d4251bf6,9cb883cc,d3dc79fa,5397dd9d,4cc5f03b,3356b020,ae8c775,708d56c2,abbe8e41,bf393f82,8f7c45e4,dbb30282) +,S(ff05c877,84d8625d,20694bd0,a4201c7a,4af8c67,8e62abc1,acb0cea8,5726bd8b,7cf0e8ce,6ac26253,cfa5a0b5,cbe984ee,a55f6aa0,90bd12d9,6ec2de7,a996eeb3) +,S(80fdf7ae,6aa31b6b,ce894ea0,83fd9274,e29f4704,88f0a7c6,79b8339a,de7e4ab2,77d7317b,16962745,6344a8b4,bd4575c6,49e066bf,bde58fe,3f46e60a,3952fb75) +,S(ac38a4c8,10a307ca,d5020a74,f0d772d7,ef20227b,7eb49589,6854aead,41879214,f49c4cbb,3c675858,416f77ca,92e229ec,d75ecfab,3415d213,c7cd2cea,1f5016ac) +,S(b3736edd,f1e10262,fd562f40,8f502f19,3a90a435,de9ab6fe,a2691155,a5f75514,818cefaf,f190353c,f01cb068,2a15ae0c,eafa2de,657ee751,4e483057,ad5a78c8) +,S(66d67e12,d100c116,b57f6d5e,ac6a85ab,e698d4f5,cfb6722f,12738b33,310dc295,9cd4fa1f,3a0c9a54,d3608ea7,9bbd7ea,685faec6,32d7318f,d4e25fea,14a05dd3) +,S(b856d75f,756ae484,daaeb651,46ecdf0a,9fa10c6b,a7b9b33e,b8747135,3eb59043,5c8542b1,2f249649,4b3a177d,8df246f2,6566da1c,727284c4,b041a7db,89cb0a38) +,S(683bfd7,3202393,458142cd,661a6543,c736b15f,b8595548,afc52951,f9c47d27,90f52a40,f5dbdf26,51429f84,ac68cd96,420387a2,8d94d746,b4163411,762de166) +,S(2feaa1f0,811e1e65,13895934,533a0941,41ee1ca7,f8975896,3d00f8a9,1b2923c2,9dd80976,b884d401,5d7701c3,5e6ee1ef,690d1820,7d06e02b,7e3a10f,e8499c1a) +,S(ce652937,da9ebaf3,a9765e9b,144d20cd,847070aa,1a968097,80e07b58,2287cda4,c1c46ffb,5f152dbe,5a9db378,29e7ae84,454e1736,eb7a1b68,1b321f3,41ba572) +,S(9a695bd9,170163fb,ab3f9738,a750bdc7,556087b6,b04dc8a8,4fd5fe68,78976211,f40ba1f3,75accd85,9a42b133,294868d9,dce262d,64d6bc27,d0c9cf12,3eaeda70) +,S(e5baaf68,bd3083ec,bfabd6d0,9e4da4c3,5908b0a1,75578ec7,18cd3223,bd34ba44,ab8651f0,365cc3c1,50476d0e,da3e86a4,5feb7f46,a9afbdbc,e4defb99,ba27fb0) +,S(2c26cea2,b507fe77,d8f3530b,b7ee1fdb,dd0c4dc8,bf63d04c,e06376d8,ffe59cc7,b344e3af,54d03eb9,b0b67151,b5845297,c30a1cc2,aefc004a,5000b69c,e630d62e) +,S(7c67539f,52af2e61,88deadaf,a07e2f6,4d53339c,7fca7a3,c2a149f5,c8bbd0e4,3f9872fd,c21c9136,4ecc97e,c6642ec7,df7a2cbe,61b63038,96ee73e9,309067c9) +,S(4b5ddd2d,ec8b0bc9,3b6e1d17,e1da71c8,3345614f,74201aab,8f9adc1c,aa249574,cfada2dc,aa3eefdb,434d18b3,d2a85a6b,6e16e755,6e55fd69,5dfb36a8,aac5460b) +,S(d775c2f2,ccfc0835,86a66edb,873a84f8,f9bb6680,2eb0be59,216bc35b,88d80e4b,c8a5d9b7,988a2231,cf6aa0b5,19640a86,ff56ca57,91135ea7,65bb3a4c,fc53ddbb) +,S(71a3cf09,78810f9d,fb01d984,43dc3da4,b005b07b,36ad4dc,d3c803a9,bcd9bb4a,8aab8e21,7db0301b,9640c5b3,9617ad55,bd4a3c4d,8989df5a,1ad31040,bcaaa55) +,S(bc71a054,92b696e6,200596ae,3d778ef6,a82f7d05,825c0d3f,ddee8bb1,991f53b7,15789125,9785b8d8,b1374460,630a908,d1125536,e400fb52,b07aaf61,729a2a15) +,S(9d220919,ee62bfdc,fb81ec81,a0f60e58,e8d94a0b,c6b79f7e,6f891c64,fc847abc,8149379b,1a073c2b,8dffe886,59f4e94c,75f3a7c8,a7bfaa16,e530bc7e,6ed0c675) +,S(8369766a,d30bbd19,a330c6c9,1e3ad594,d25bff1b,4e3696e5,c6c8c33e,eff33425,a27f7682,b3f4575c,858970d9,c21f7daf,8ed5d28d,8617c8a4,e4b958b9,72e79e4a) +,S(4e277875,e4aeaab,1a8d36b5,487fb427,e91f51ad,1cd68ab4,57db2e8b,20542451,9faeff65,5bbc4b81,f96bf1d2,a152a546,d138fd0d,a8f8523e,7635020e,a26566e0) +,S(27f907b5,1b9dfff3,e68d202,72605a91,825046c1,b21336b1,8b91023,39a0d2fa,115225c3,6cb13600,fb84bf3d,dd5c49d8,105f459,ffc4068a,cbfd7b0c,52d4a15) +,S(6d9feb20,650674c4,437ff42d,41f70f16,ef0900a8,f3cd6818,64b42eed,56b1fab3,82cd97ec,d82b3c1c,2e55f857,653afa3b,5f7f7b00,39aa2444,f60574d2,fa02065) +,S(8981d2b4,3360669d,361c3b36,3284e729,ecb9cdbd,3bd17558,857f2cf7,8187bfac,1b9aeb27,d5a45d1d,8791bf73,614ecd5c,216b263,6c27645a,3e86d781,70d48498) +,S(84a67518,e47ad1fe,25540d55,77e92ce2,81691685,6d3c10ce,9c5985a7,72e1d72e,d3cb93af,85072ea2,e6c11777,dc4b73fc,16ca04e2,699ef356,dc8a5341,c5631658) +,S(d3e66756,72a6cf77,50c111e2,e65a6674,7e666cdd,b9dfb418,d50c28d1,aca8c683,7776ecaa,20e5c6c3,ab5aca5d,8233f83f,4e2e815b,dd1063f0,7359fae3,a6556dd9) +,S(ede97def,71d45688,804e76b5,ee52563e,522a7684,a68efc4a,f7b2db38,65b87bba,92e6d20f,c9c1276,60a279f9,5758a80e,85bafb8f,b77eb513,7587b692,fdae702f) +,S(3359e142,e000484e,cf7db3ae,2312e703,6ff84f84,247ac6ed,25a0b9c,eae8c871,67b039f2,3c845fa1,f38c98bf,739dbf28,d00ada09,36e4377f,87166f9d,d21cdf66) +,S(e0d0a972,c0502fd,2654a3dc,40914a55,96f675ae,cf0d958f,8fd62c7e,122b44a1,cbeb1bc,34575a7e,bbfd916e,dda11903,3ee29e2d,1b11e171,8db7bd47,576b0312) +,S(50b89367,5df77704,64031ac7,a1f5d5ed,4f332019,d8da2605,9397df84,21a4c987,c4765d81,63ec9eb,a089c3f2,56d6ff0c,45c38253,3d9ed204,cb04f335,d292f293) +,S(5dc62d8e,66775ff6,f21e84e9,9f8e8123,7f80cbbe,41ce9113,91ce432d,cd6d446a,4b456b7d,e27045a5,76e1cdab,d163fd5c,b020cabf,125f5de9,9ad6eb14,1773a9c2) +,S(8ba1778f,c7921845,d2632e18,790710c0,4e56ba7e,22efdb03,fdcd4f96,22c10971,1f31fcff,a8359658,b39d7d43,59707268,48ffebe8,8f418c53,f48c7af6,3e3e3854) +,S(a3a14614,7d1ea7bb,e6bad055,fbf9810a,999a102b,ba8b694b,e7ada06c,8db9fc7,c9827731,d4321284,23ccd6eb,3531ffcc,b3bdb87b,1a727d57,a697eac3,886ac294) +,S(9620a847,bd2034aa,c81671c4,436682c5,f6ce1af6,4d8df286,21ad1c2f,e0af78f5,e1cc6d08,a7e3dffe,cb47e32f,4156bcdd,6168a205,e8959f0d,99e1555,4d826e1c) +,S(a40d86a0,aa7d6a79,3f0b6a52,c48d8fff,95b2c57c,584996ee,bc9d98e2,796016b,ec54d4e2,d453466d,ad94c15c,b25617d8,62911b4,45f44873,96ecd950,a351ea2) +,S(71ef35a6,f60f268a,57573b97,9745986f,7e5f40e9,ba64efbd,5ed90779,b3484c80,eabffa1e,9ff3590a,c577df7f,6f5a6ad7,2f3693c,be475669,8751637b,4f8a1ba3) +,S(bbd1a408,c742a3b2,e49ffa52,c5f70958,5308abbe,f103e674,86fc76d7,a4f68de2,4941cbec,9d07e13e,1b0fbe96,c7328459,ee6e1e08,50a079a,2ac0b61b,5d246124) +,S(169ebf38,92116df5,3e09c92f,f2c89b5f,805d60ff,9584d2ab,433f1f9e,84ba9009,914f5516,e7667ee1,581b5ade,bf1de48e,c997d149,1e932a08,34503599,7c6228d) +,S(8f157abc,4c5ec7fb,eac11545,890d8e45,d71c8d9e,4c4e0c3,9777502c,f8666acc,d41576ba,1e78a9fb,9899883e,602bca3e,14dc709,8982e1bc,63518138,3ff25908) +,S(8cd338d5,694b26dc,4ebcd8,39a006da,84f71f93,94fb8100,91ed8cb5,b4ec9a8d,40318c10,dd88d9b9,c080eccf,45464ab3,3fd9d34,c2027d95,2a6ecd21,d0002578) +,S(20e47e2f,7ba5ba2a,d36171a,f4ad760f,a64748c2,94892e28,cbf0ee3e,293272f2,b96ad220,56b89821,5c052089,789e4267,162ddaf8,76c720a7,71b15254,67be00bd) +,S(582ed8a5,a0d38f9c,db6942d1,1f411dee,f9c31ec6,ffbf1579,3f3cb5e6,5f2bb880,14928c0e,4f9d9d3d,ec4a8db5,64baf4be,948ea892,34a6e352,a4cf4796,3ce8486) +,S(f4a6f59a,6e76c11d,3f7daf30,b8c046eb,b0bcab8b,6d1f5e7b,877eb1b4,601896d6,2d39c6e9,e5d84156,559a05d4,a9b148e5,ccde4641,e4bd9abe,edc8a648,b070f0c5) +,S(2a820c60,f71cf5c,76e66bf0,15623f06,fc8564b8,c763a52d,2c329af7,30957b24,b38c0703,d7429599,e6c9a1d7,250078d2,36f77f7d,b9956d37,fd92646,77ff3ca2) +,S(8c2d9c4e,9fccbf64,871d4802,6077a3a9,33634d3b,c1d7f872,6231848a,6e2799e,ad50136c,ae43bb6d,8c49c534,e80985a7,cf032d77,604c2db8,d5954858,a9351a7d) +,S(b18e9053,744b3ed,d0b991e,23927593,db00d25f,adfc4490,6eb0d19b,74061ba9,90f5ca44,c829b2c6,771edd73,998034d3,43a8aab8,442302a7,2ffea92,b33877b6) +,S(cf1d157,b03d435b,905d2f58,cc53bfa1,d124827c,f4ac4109,33078dcd,1ce835be,ee37a9a1,5547c7d6,a0f03cf2,1451cd64,3ea656df,61eeb1ab,1196d959,ca71b459) +,S(8d8b9d8a,d91a840f,b2e1ac36,a6f4bce5,92fc13d1,f22f84c1,562d63f7,e54a6007,9528be43,93ca8f2d,dae0ec3b,439abded,ee9227e1,47ce6ee1,ce61b46b,b842dba) +,S(604b5544,bbc5b0d5,716c936f,b0d9a4cb,7ae04a8e,1d5a506f,2561b463,fc87fc9d,33fe2f9c,4fb9a6e7,41c1e5fe,7d3d9edb,ee3cde6f,106a1d8a,3e319254,a16ac8eb) +,S(3e7ed414,1058ee44,6057aab7,49e14ca2,cbd16d64,7959fe53,9ec0916,fbaed8f6,fc15b241,86dec6e0,c91aa697,10a015d1,f66bd361,82f18648,1ba24568,952e79fc) +,S(d0ae7435,86c17b8a,c9524243,16cf42c1,26e46f69,4c69cf26,736d0527,7943f326,bfa02de8,b983588a,d4398865,abf6b69c,fbaca03e,8bb5f04b,1971ce1b,f74e0757) +,S(ef5c05ce,d4f343e3,7e6ce2f9,45380ade,3627bc65,9de0597f,5f851eb9,88be1441,d9267c1b,379f19e,3bd0e40b,74ae8e21,b681e7c2,ad49f635,d60c619,74103281) +,S(176b8feb,d7998ad9,7c73015c,3b09d9af,d7cf4265,c7bf38ca,8dc64864,5c8f49ae,b4bcbe4c,8267c9a3,69cda190,5676c781,7f989f5e,a014f4c5,fc821bf3,8522f1b4) +,S(88f683db,cffc14e,ebb58d69,fb6da62f,b20771dd,3542fa00,97b3a766,bd16c3dd,bbef3de,812103c5,266797ca,252b74e,cf80096,b2972219,f52ff718,1d1cb601) +,S(a65d438f,1247ec44,fd8c4121,c3d67891,8488b082,31fb8854,dd1fe238,f637abaa,5f65c84e,551e433f,dfdcf3c0,b4c771af,4bb50095,dd0fc986,d4d4a82f,9a3f36a3) +,S(bd6a7e51,c5028bb7,f7e08148,af1597c6,d5cddab9,2883d2f,f6a5a6a0,6398cc27,3f2280c4,247cdd22,e8b97979,b9a98e93,c1ed14d,a76eef66,2ddb70f6,7859d885) +,S(a672436c,2896a0dc,54b1814e,c5101451,58f7a3ac,74d36202,34411a09,909d274b,dee80293,468178d9,5baacea6,badade56,c81f3d9d,95642654,a7afcece,bfc2ec3f) +,S(ca0f55fe,d3a1d0cf,1adb0993,d7d2daa6,57891ba9,321104bc,8d9e0379,f03a24b0,dc01b8e4,63462dcd,91588baa,ebca8d8f,52016683,9671399d,b5843e6f,5a3cfa6f) +,S(610ff08d,9bff021e,544961c,cb2fe206,211843a7,ea0c74cc,b91f0b5c,4b6429a1,4be3b18a,ee965fa7,dabdaee6,8fcd3e12,d889bc36,35f160dd,9b0760be,d1d46b28) +,S(2d6f8215,a70aeccb,78cf006c,ddf8f0a2,6b695dc9,622dd622,38fcc638,a9ff42ae,3fc0964,e2a3c969,e61e4e5b,ed50f337,7a988715,246c50fd,3ff45487,95a3927b) +,S(8c0e99b4,868e39c5,b610b132,de1a09ae,99846826,a42fc4ea,70b0c630,88a1bbbb,32b8ca42,f0a240cb,2876a41d,e61b8c17,6ead992e,8785a95,c384c536,141cfe52) +,S(1528ba8f,9000ae75,e3062af7,74ef6d77,658c6d1d,65af87e4,dbac9eb0,8fc96ed7,a8dd278d,54df6bcd,1d4e6466,5753a8bd,2d39f0d5,c731a53a,5faeca64,513b5651) +,S(c1466ea5,d9256a7a,f13a040e,29515858,104394bf,ac5af7d2,fa09ef7a,6ff1d7a4,cab6fec6,fb36d879,f0684b54,6003df0,d8bab3b6,e1050a7b,c05457b2,75be5128) +,S(ce8bb093,e051089d,2a297a87,cf90c3f2,2ea946ba,87a76b56,c6f11812,d3e98cb4,a8dbba51,b90684fe,6dff556f,bd13baac,679cbcad,90b0e888,4c252e95,e03a0470) +,S(76f3a73,7c9d9e15,8d30ddd9,b092a94e,7c426763,a17a96ea,9186582e,6d6c86d,5b1ca07c,4f345e6c,778ad27e,c6ce3f05,b29c5302,7e40443,b202a022,e5d16c8a) +,S(f757dfc3,23390b21,3bb98872,5dd7d43b,2ed997fe,af7681ad,ee1572d5,a74017f,d0b4e4ea,67879726,700b63d9,88eb3957,74ec4f67,ca1a56be,461d244b,a5b83cf8) +,S(59bf6198,a2deaefd,f080ec6d,3dbe3c67,f27a5769,d91c65c,1492a87b,9ed5f5d0,bf5eb739,9011a282,3110834c,4d467855,6e02f2ed,601529b3,a2f3d70f,8410f8b2) +,S(b1d02f0a,c86d8757,48685790,918c15a,a7b0e85c,f12cc52d,53f8082e,549ba16,7925e03,99926b76,8a80878d,63f3852b,97297725,96d3d06b,85437fc2,571a19d0) +,S(cd27372f,41d8e07d,1bd2ec1,27c41842,7e5267ef,14f3a908,882e4e40,381d1905,cce36e03,661b9f33,ccf810f3,b411693a,c3329617,52098352,2acaf0c9,5dc77297) +,S(112644fc,26ca3599,3b68940f,5cbaab4f,ad2258cf,bbc81695,b01db49b,dd9d3ace,8685f790,7b5ab95f,2f7a49b3,bedf09d3,7ff1362b,3be9db90,4e74d049,15c0bf60) +,S(918df72a,99ce4a16,20e84575,935a24d9,92fb51ea,eb8498bb,3a606e2c,d97d3ce,88b339ec,9ebbff98,f1b8b0d3,c90794cd,bb6b7918,2749b065,602ccfeb,bb8a8461) +,S(9b8f18f2,65c4ffc8,9425b51,d48a770,436e6424,f34a1af2,a7dacfab,fcdcb83b,bfb95e8,6a34c1b9,2c2e8c78,fc628139,476c4af9,3f63d247,5e454a9a,d585ba55) +,S(ad02f2a,c396626a,42abe52a,1ea1d8e4,3821740a,d8b3340c,9b9c78ff,bc24ce30,fcc738e6,cf8a7872,ff827cfe,1b7bb7a7,ad8c97e5,e254db13,255c2d07,1a2885fb) +,S(359afbd,5e60dac9,8ee34f3,f5acf126,9b5c1928,8f54476c,84bfb9ad,da6d85a3,2e2aa1e7,9cd3fed6,71272155,3932ce17,44358636,a18230f6,b501579f,b3088955) +,S(5639aa3e,230f2f1c,e10c34a3,1cd6c78f,c3c15c0,2061f3ca,55e09116,68b279de,e0b6e95c,15de7f0b,3fa3bc26,3a9e83e2,e3a7d51b,462709c,8ed6c2ec,b511bef1) +,S(309cffcc,7b2f959d,85cef3d0,c25efc2b,693d3b6c,ad42ce4a,d8657652,d669ec44,3abb62f,d917b1be,79809520,5521d522,32f949a6,7999274b,cf7965b7,a950077d) +,S(51f3d5d2,dac1d7c0,5d8eab6,375c9130,534a026a,48abf3ca,ce91af6e,533b86b2,50b1e7f,4bdc48ed,9f3fbfe0,ca05bdda,34f9cf2a,ad04235a,ba998a8f,a3e99f74) +,S(8f563d18,33aa4100,4540e0c6,f501d327,4158b0f4,8b3e4e1f,a3fe25ee,29c2a244,4d4c71d8,5ea93371,57f5248d,a012898f,3d031d93,c1803589,2875928,67432193) +,S(36ca2909,d68fdab9,cbc45b39,fb096ac0,3c4853c0,ee19d108,ee7c72c8,a77177a9,64f511df,c8252960,85f3d095,31467a5e,69cbf363,30e12ed6,90516208,d24301b0) +,S(f628b8d5,1f3ffd7c,c201ca9c,2db26f0f,58dd918e,b4d70cf3,80734702,8ea306e0,bd6bce3,ea82e9b,2e8d6eb2,7f557def,b7c2d77d,e6329c1e,a2d360bb,d8adc2e8) +,S(fb7a6bf5,a82c0b,b2a6922c,9d0350d4,b44fa7d7,61002f25,86e41152,c0e67c1b,c12a1c37,f1c9c703,1f1406,efe8f3e9,8419fc33,23a1acfb,345ebc9,4a702da1) +,S(c2091919,5c3e2af2,df14080f,400c8c75,bf8ec01d,a5a5b033,75391fbc,fe78d092,b307b56f,cbebdab3,ef87b1fa,3b66c327,7aec3818,e880de6c,3826b632,f1adeb9) +,S(7627df89,3d1727fa,a06d7c4c,93774a48,73c3bef8,d19bc03e,8d1bfe28,bd3192d1,35d2676c,36f455f7,aa29a865,f0776c52,1326dacf,f6d366f4,bcf726b1,b68451e1) +,S(26666518,7c9f33a9,6d25df65,8dbfe035,a3df6f73,cb059639,ed54b296,2c62b9,bb30bbc7,d34a5e26,a51fe757,8356a876,c4e7fcae,f4a977ba,468025a4,c686630d) +,S(3bda9185,fa9802e7,7dc6a02e,8f2a6f71,ef8b125f,735837bb,c7abf3a4,c62ac683,202edf2b,c11d1784,d7875a76,a0ae3876,22b3475c,bb0ca118,9362e54c,a05b85) +,S(2f90bcde,4486b64d,81313c71,48570d22,3be1978b,7f524097,bc033d6b,983a5c4d,63864e50,2028d475,365b2e30,cca99dd,f4aa759e,cf579705,270fda71,bc384f89) +,S(8893f5d4,e9b00e6f,dc992e65,4c9fcd71,7083edc2,6c71dcb6,562bcfbc,c8becda7,1faf3055,8e631074,fbf566a1,fe0c6996,a80fa29d,6cdb8313,fe313b4,b238ab50) +,S(acfc4ae6,86be5de3,eda4fac5,4da73510,f482fc25,309ce37d,855c3495,8555abba,387f4597,d1878a6a,d37a5b99,8ec291fd,76423f7c,f9bd037c,b9071685,2ac52d87) +,S(2ac4d090,a4c5e988,2f3a892d,d28a5229,d5fe35e7,d74660d9,5422a55e,2017a469,6058f516,2aa3ec45,47a79f2d,7d8e6869,927d172b,f75a1914,a3bc2571,df086c09) +,S(137ed3f,fc13c572,e5bc235c,d13c7e62,c9b1a3ec,250c024e,9c9f584e,7ebadef6,c1e95cc,3a464f51,b43ff02,3c8758f1,319e7c2,f37acbf5,4fb8536a,8ec6fdba) +,S(28a037a,72148a3d,2c89f606,81152b94,6cfb16f7,58f0a002,cfe4d857,ef3ecfe4,b2f4b650,135cde9b,8d3788cf,5c6e7a3a,ec595124,fa903aa8,a1bb3984,fb973d10) +,S(303ecd51,8fd433fb,ce9d426e,8761a76f,78ad6d5b,5f34c0ae,3bbaddcf,1a7a9eeb,6a7fca44,3b73b19e,967a5945,a275cb1a,cbd8dc3e,89d85385,ea956339,99abb602) +,S(cf63042e,5680f71c,2641defd,9d6569ba,c69cf079,f8b3140a,50923381,51533202,39f3376d,fb17fdc5,719a2052,5e1aa428,176643a,f50dc9b6,b8ff3401,eceb4ee8) +,S(cfafbbef,b4a49fb6,96923b6f,2e56c493,34a229a8,e2dd968c,44f485aa,1b1fe4b7,dc0ed34d,4a9c17e1,ddfafbc7,1d76f71,f3950698,18faa16,b5d25c6,c69f9007) +,S(ec0e3de1,fd527ea,6a493ff7,b3c6aa40,4a7ffd76,9a08953d,785d2f31,390d363e,94bddbce,300234c1,82f3c6a,717f53cd,723129c0,ff353528,fc5c285f,8e7a35dd) +,S(f07d3cd1,914422cf,d4b9c0c3,501916bd,13e9cd84,eeb02f7f,84be2a40,4b2bcde0,cf0c96fa,cb393218,37c48de5,16d1f705,dfe91206,8ae2d810,3aa1f77b,39637320) +,S(4a4254b6,6f2e204e,a3264ac0,a00c7a63,8a6fab7d,e67643e2,8217099f,3648db10,b5510e29,be93fc35,efbef989,15f7df95,b187ab08,bacb157a,c26ab2bc,2ee5023a) +,S(56f3bcf,b38eaf1d,35e62582,9f671945,910285b0,3805c1d9,b5d813e8,e87774a8,a9b964e7,9e6b7f9a,9abf3e5c,a147f773,8a1e8270,8677e6ba,c57a7a75,d1ed9dc6) +,S(f89d8f4e,7d32efc,c2d95bf,feaa4c9d,af6b9886,51fe7561,ace561be,6b081295,ca632f11,56a33867,63a65691,17186994,75e48f51,48d770d1,449ec719,8dbacc69) +,S(5c3791a0,d3e716eb,50ae4a07,51f0e92b,2890b933,c6d9aaf9,758e5205,27c5530b,44ef13c6,2de52d11,179e30da,e913493a,c4ed861c,336ae1c3,ca1f8bab,a7b34616) +,S(2748765a,e6baa4ae,62cd7156,16ceeadb,8ab94ef0,d3a3e331,15fa0132,aba38d27,71d4d19d,de63770d,60905bbe,6c7ae92a,f36b333,a93b3359,cd4f1f2,77f69e48) +,S(964f1fa2,f8ecd778,2ce4ee1,87ee3e78,d2c41a0,45a95453,22e363be,bb27e254,c744bbca,de64a883,e9481a5f,a2cce621,5137ae00,3b9822e6,77556610,d4138a2e) +,S(8bf60775,8709c9fa,8503594f,e6c379ff,ee758a07,4f7d2754,58985e25,79b8ca3b,3e638992,b3fbdd72,ff51cfb8,fb118d0e,ccc193ee,718a7715,a5ae6188,87dd51a4) +,S(fa107123,9189239c,2bfc5a95,ddbee798,fbff70d8,ee0d5f5,a10238dd,2e06612,a60cd5e,1a4eb0a5,99133ea9,71d5ec1e,315a6be1,2d773936,c624c468,f968e7f1) +,S(5b48c6d0,9f6f97fe,c03d145e,f797cb8b,3fe2503c,a8944593,83c34e51,44975588,44d86689,352611bc,c1291762,d965f136,173d6c45,28077d83,c6410a3a,906e30a0) +,S(80e153e8,23aa7e3f,2865d1ea,1e5e88c8,5d4e854d,54bca5b1,ae8f1bca,eeb94fd0,edd3fe29,e435c11b,13a92d8,ef4f6413,c888a12c,71823f7,3ed7acba,a06b9728) +,S(16e225d9,77bf7526,c2590dd1,54c6e29b,cd25de9f,7b1fe3d,ae7ed6d0,79ccf2c4,e0702d23,b9b57554,6d2db82a,fcdc22b7,40088c52,e0fa274d,d85188ac,9710768) +,S(a3440a09,15a16c74,8221b65e,7825ebcb,bb064aa2,de3593ce,7a691efc,d9456938,ff7c7aa0,3a582a8f,5641323a,7f437a67,26fa5d3d,e7c3e26b,be970904,d4dbf40c) +,S(8154334c,d1164468,2320401,f2d59385,8d607203,93eb37c8,a030e9e,cdaa2b5f,bba4094e,5f97e4e7,b0f0676f,4a091488,17126ad8,7d573d54,150139c6,5b3d5142) +,S(c91348ca,27b5baca,3a092b25,74e09976,fe7f2361,3e1b5efa,329e6a5b,7d4d93c7,ce241d0d,e9d49a2c,5060e62d,c01bfb59,e7c37295,4095f639,9d61e73c,5976b44a) +,S(9408b5a8,79fead4c,67635e99,59ca9649,cf362940,737e6436,3ba2590d,7e6e8a88,e10b410a,26c710c1,bf2858d5,21f46094,e02155d2,84b80fdf,cbf17645,7f994fc0) +,S(b851d158,eefe48b8,79e0a159,f8582aae,f80ddf90,d9021b92,e7d3e7e5,d6bdd2ce,290ae2e1,792421,c1cc53f0,69c7d580,60facfd8,e537693f,6abdaa2,c6d85469) +,S(9d320b4d,4a7c2007,65805387,5e536093,87e7a5b8,54da05eb,1b971e6a,e53d10fc,4f6acb7b,6a1f190d,6822acd0,ae783b0c,9b44be61,ca68306e,79603f47,25d7c456) +,S(6d779810,7b29ec65,4ff86799,d13a4d89,eaa49114,d00744c2,2f30a9e8,358ac7b5,8f7993cc,105c4f09,ba060a2a,ce265cc5,77b2a334,3ba3880,4b0a3e79,db823950) +,S(bdb2d2ce,77e14fb6,9a17d62d,b8056d28,680c9607,2c82772d,73c91da9,e57f6489,9c1ef71,d43c3b19,dcf8eced,ea6f5648,8a3bc00,3c2b0c1,84c9e42e,5baa590d) +,S(49a8ccff,1ab70a94,a4db4787,f73bb058,1f7897a8,d0a1adea,741ffda3,f055b3fa,f298d277,2049ebd1,ee2414ed,6e053ad5,15b41914,fd6de43d,8bd9282a,6c6ba426) +,S(ca3f7d6e,b466b7b0,56267992,d317a02d,3b3d5652,b51040d7,7f1a173a,769d2236,a26d6225,9dcf384e,f78e6f2b,f96a42c0,90e538ad,f6f1a1b7,126dbb12,8e145c37) +,S(b672ce14,f1c427d1,b478469c,b0d08b99,902e9cad,a66bc65b,c00ea630,737176e4,176c0979,15176,27a0f1af,f3c5a56c,83f4f550,b8c4bedd,b818bf76,68865efa) +,S(bdcbab57,d4ad621b,d6db6866,f43778aa,2c26dd78,8f2e968b,da3c913a,ee9c199b,79868872,9bb213fd,7dc75a33,8d6168da,1cee9f0e,e93c7c11,24055232,88df5603) +,S(f5f25f1e,382f7df5,74c64aa9,6c5f423e,d5beed0,82d80196,1cb384b2,55fbf9f5,ea388f0b,5ad84aae,58393a82,9a50a4d0,f54bc068,e12724c,98a9dffa,f2210221) +,S(d2a10464,f9f8ab9e,1ca6e280,b2747c43,60372049,85a2650a,a730b894,16ae09c3,d19719ed,8dc46533,28d8dca,f2c902eb,2c9ffaeb,ab3c1b45,4fdcf68b,229c5962) +,S(89255afe,e6724c4b,c5522105,8e5e6aa5,19058c3f,f3ff691c,c5f81a00,20410038,8d626dd,9560c934,11b52ffb,4fbab500,c833c3b4,671713e6,9147d8af,da3fd7bd) +,S(5e468c42,c5eceeee,2a67d73f,57819019,5165e3f2,6c93f94,beb12fbd,556e3952,af83e24a,467f97e2,ab8b6a8c,330e400f,ce1fdeb4,3a4ae1ed,c3866505,8cf240de) +,S(70c2bfac,9eca198b,f606850e,8f54ab03,552caf8e,9385036d,7fc85007,e99c4e2c,60322365,f5ffae57,8a8f9939,20cf7596,3b45d940,d2c4591,544feb6c,d6ea37b3) +,S(16143d3a,fe5f6b42,500f86d,7c79630f,bbb0db1a,64e901ee,ab641c0c,b9c2f318,7078e814,bdf81d7,81109561,d4d1cd37,9fd74924,4cad1e68,ecb8b247,d76a8a94) +,S(8ac33ead,a9341644,db25b034,60ff60ab,e1326eb7,73a0bed0,29f6e966,16b62bce,6d07756,6f0d18b4,bd055d0e,d99bda50,ea9e614f,da46005d,c6d9dbfd,18945cc6) +,S(476b98b8,9e7feafd,ef5f0116,6e0c8eb6,70cb3325,a10fbce7,71ea9e06,2566e22a,38dbf041,83252b86,7e138483,c012f220,fd98bd5d,b80fbf47,30c5d0e1,d6a91050) +,S(e4d262ef,f0de9c3b,d3302bcb,321adfa1,2e383a7f,19297058,a19c453e,ed497f11,a1f830fc,2fd6120c,8f2070c4,9ea49001,953d0c0e,7c02050b,fec7cf7b,ce2781d3) +,S(67bc850f,48f0be1b,f18c4f7c,b9f33e67,e2e09279,4196d987,1bec0fcf,f0b5cbf8,e2560470,334aa4b2,4693e927,1d2f20cd,b7e6fabc,92e0f355,526dceb8,5f52d32f) +,S(50dcb2c5,c0dd4942,2564be02,2ab274e,b543a6a5,a2712b8d,58f51e12,72ef2797,2cbc036f,b69c44c9,9c7854b4,9705dccb,8d2ea16a,2f77fca8,90d89f8d,4ab04ea0) +,S(6c9bc577,784948f4,1e8a57f1,bddf5665,f860804e,89912876,44ba7b76,8758bd6e,84a671f3,5998ac84,7329ca3d,1224901b,a0401915,c9280260,cd40ff44,ebb3ff20) +,S(5dac93c6,d27cdbb9,9f3ceb36,18c6ead1,28b44146,467390e7,a337c494,8382a868,86572065,1805082e,7434578a,a97704f8,8a91c2b8,e315ed8b,ac2a4bf8,342df508) +,S(207903c6,5e1c57e1,7a6e9484,d3073c0f,f6b2a40a,b46b996f,2ed2be7c,85780c86,4b568420,29564d4f,6c4fd310,73e17a3a,bbdcb83,115a6c14,854633c1,47f6a442) +,S(da025f63,9be593e9,3ab35113,2282830f,6ffbc94c,829111dd,29546221,2edc2f90,9b4acdeb,a315e576,f0edea9a,21acf5c8,714defa6,5ef4ae68,eb694383,916d2723) +,S(327faacd,1b489c8,2126ffa6,b87cf191,2a0f61f5,ee47eea5,6030a50f,b2823cb1,634ab42,6010009b,144c5ac2,903e5f8b,14c00c67,5fe177e9,6b7f9ecf,b8c33b9b) +,S(44cffbee,1619f462,a853478b,a9d1bfd8,6c9cab17,f5bf50cc,79a24558,7b7e8084,b08983db,62079e28,7eaf8c28,81079a45,76442a1c,fe35f64,563c714d,748e7da4) +,S(c5d945ca,13730ce2,c21ad679,734d1deb,beb19785,480f93a,43a2170e,6a6fe3a,a3aad11b,4d8b7140,f67f7287,8e4a9c1f,74102ffb,ca3ef04,46e7bf1b,ae3cc3fb) +,S(f4d8cf19,84dfe935,11b2694b,8f1db0ed,d4bf22f6,435359e6,77fa42e1,cec0de31,83d02d22,3aae1880,d7ad76bf,c7e3bfde,5b48a55d,4fb0ff02,c0ba5c2,e9a30845) +,S(13d721dc,8e7b0bc8,90c6380a,fd0f0ee7,a2dce0e1,e153ae70,7e50ae7c,1837c4cd,c620c1e3,e1575411,7eb9e823,70af7e4c,9309c412,d5f14d28,e976112e,88841116) +,S(e5f9efa6,66fc6728,207eb55d,94c1daf2,5164824c,e27b1783,92862e11,6265ce1a,500a9fe6,18302bb5,22ff9fbe,163d79b6,1f0f3cf,53e0956c,7712f23d,5c0d9975) +,S(73ee3cbd,a1ba137,65a7abb9,827b1b32,a48ea0e0,a43e9698,8da603c3,c319c9ec,d96832b4,4093689c,beb30bd5,a2e825f3,bbc909d0,20e18744,b0a5ec5a,1ab38f58) +,S(11b92fc5,94046bba,813285e7,122750a4,3e028501,f027a55d,f101d2cf,c5990d91,e08b24aa,e20fcfe0,40dcfcd0,80949b2c,23b324cd,1d957b63,9fe91716,a4315417) +,S(3043669c,22be0dc5,fb14442a,22a625d,b1bf4952,362f06a0,623ca1cf,9160935b,dc4834b0,4bf47d6b,fad52c04,4d26e21b,41eeadb2,5c92ca22,6dd2c86,24d0eb34) +,S(490c39aa,c290d144,2b87622b,407dec4a,3f92aa61,6a9c8495,132b5c7d,3d5f9a0c,5c76c0fd,57844aa6,fe81361f,73cb314f,110f87de,6773e1ea,b3d68dae,2926b986) +,S(fdd5cd58,67d73347,ca1fb212,772b0c42,3a4caf94,a3e0bf2d,2bbb2433,9002d03a,efe5f407,d1d26bc7,6fb5bcc0,6bc94da5,bd69f84c,85d89172,10bce909,77411995) +,S(bc8a108e,b0830fce,443db272,2655ac40,e2d35989,cad192d8,e9c5017,14435ea9,924c0258,cbc3da74,a708a384,b93196c0,76bd3af6,2907cd60,22069b93,e3c979f9) +,S(ed809b6e,41f4b6cb,86ae431a,718989cd,2c706ea4,10152e3b,3395df8e,ae924b44,135d805c,3295589,c8d42ffe,947aa88,bede6699,b119f8a,324c9bfc,64315da8) +,S(26b50ac7,5d871e07,4147d2f1,ee42d6a8,4398212,79e9f276,7978517b,6cda52d8,26599c63,86426e9f,b14b4c8,3494f0e,1fe37ea0,521e4518,e346bad,545dd7a0) +,S(cced88de,27d0ccd4,7f6746ff,98907cf1,679f6b10,67785dd7,25ab94d4,9fe8efd5,5b0ede2b,4dc584ac,b4b6adc2,c52b4268,e2beba67,ce2bc825,fe4df43d,73f5729a) +,S(d8edf7cb,31526332,308429c1,178886ce,bf3fe516,18f472bb,52da883d,d83c6249,a56abc3e,c155eef6,d43427e1,30ba691d,8c71b80,6b487343,7f3daf07,17984be3) +,S(ed82c3c9,f8db3a75,50949aa5,cd6c8fce,52648910,53f66515,c2fb71c4,7564b4ef,5ee59949,6d9d3c7,6fa9a26d,444a8a45,41ddccc8,15fccf39,b06e8fe5,20b2f0b4) +,S(6e277bae,e89aeb54,5e6249d,56d50848,5853b3ad,8588365e,7771ae44,3d8ca937,84871bd8,1e6f94a7,c31a3fe6,63a1170c,8f9623dc,4e24a5b4,3f7d023,39f40b8e) +,S(aeb67ac8,67271210,565b1229,3e1aff94,f2f8b642,76768967,f702afb9,48a03c5c,fcd3c588,94259c03,cde7898d,66ff5ac6,747100bf,3707e89b,6980d21d,78bde197) +,S(9f07ff4b,aa20c756,94c967d1,e38633e8,45753193,a3d13af2,3ba7ce07,5283da79,ae8b7f0d,49d06168,ff3c5f36,3aca3f1c,14308cf7,d95bae36,3975fb7f,dff2136b) +,S(24046d14,a026daba,1644b3ef,7bc5501b,baafc3c9,76acfdf7,243395d5,713e1520,265485e9,6dc40a31,ba93cd0e,915534b4,37fd5380,bad0d6cd,321867cc,aa029ae6) +,S(1376926,bf8fd1c6,80344f48,c574e6b9,1806afab,7d9f90c9,13bbc233,2b3de519,a34100e7,c4b44c26,f86b2198,e7d3696d,8aed9051,a1755ced,56ebe795,d5a61fa5) +,S(943c6d4e,816cc668,87f7c85f,b116ae82,5e4c38a6,581cd5f1,1efc9a3e,ef5a7d6e,d93d4724,f618da6d,29e35165,7883ee36,74112f70,3169eb24,eca31a60,969de8dd) +,S(adf8041f,159260fd,cafc9e61,d5f4f867,a0f46e94,af60bf53,d4d0808e,885432d9,c4eaba1f,99d2516f,3d731bcb,be90b36e,c055ff5d,e6c3ed95,2b95a037,1be57958) +,S(15c17f13,a404ae08,11ddefb6,707a9fa9,dc0d9461,8325dbb8,d96537c0,6e2dcc44,8740d352,21f95e8,36842b48,2512d79d,a799fb62,60d65dc6,79df383a,e9b6898e) +,S(87bbbb35,62365994,9c5bd575,86b813dc,966ec9ed,1ac31435,80e4b7cd,cacb8ca0,159992c,1bfc3c24,95e14ccb,e24a3e9b,6a28f4e9,1cad4a36,f83624a8,d22a48c4) +,S(39bd144a,96454c1,9e082b5f,eae9c433,564da73c,d5d44daf,95b5c176,9f1fa105,ffe8a11c,30b5d4d6,f8abe12e,bc3ca8f9,dadf1527,330319bc,fa277b13,256fb207) +,S(c4e4eb4f,9bcec0c6,6bb99bfe,265b2f4c,a1c69676,ee970a9a,b78bbd64,a83bca7a,1bb9a83d,316cb9c4,bce4be2b,d05e6381,2ecb493b,44fc3cb7,c2248a0e,96bfc286) +,S(c183e783,1c80d334,f0ddd2f4,48ca035e,8b53f034,f53c1801,488e4aec,cf244e69,f998feaa,c7711d48,3db38926,8ddc080c,8ff2f95,494e60b1,59330d8b,d9a8b820) +,S(99d1d7ac,22a2e108,f093b630,f374d9d2,7ac812d9,5753bb6b,e39c2401,fed47d92,a67d334,88dfe341,e8dca3d9,b36a897b,52080a3d,c366c8b0,39cc4de3,52d0e1f0) +,S(e0700a5d,16cd89bb,df3d6f18,76909082,985a3339,e7f5d2bc,5c3ccc92,ad61cea5,26f6abe0,38953fa8,40bec97b,c9d59c20,1fd08b29,4a7ac7e3,bd994e07,70a0b0f0) +,S(b19bf6e8,cf36d839,51b813b5,67aa62ee,5415e95c,d3fa668b,55487a3e,61a7e721,630e78a5,ca2cdb2e,cd59f59e,4c10e712,46c1055b,a7709041,fc03f8b9,1970153d) +,S(25009156,e90dd0ec,88027adf,a9701474,39abaf72,1c333943,c6fe6e19,ff71fd44,324047dc,86477632,214ed74,cb933859,b7825500,2d19ddec,9c466e1f,573afc11) +,S(45ce7fe8,bbe45d1c,9bb0c98d,9d4c500a,aca5011f,96238681,771b8538,61a3e4ae,8cbc22af,d1adb8f0,a5c72570,2b6c7f65,9e41b176,1358832,7ca062e4,2392f8b1) +,S(73255507,d3a27fc6,7df39212,a286ef6,b939e953,43b12683,4e38148b,619ec059,3174d6e6,e941020d,db0f3ded,aed6c8cc,eeba10ed,1344ce28,a354e93f,25c35b63) +,S(96b2cef4,1c6c39e,1ec9a945,8c8bad3f,6025962d,a1207885,97800ac1,c811df58,ed85ed21,41b4ad26,3adab5b7,c0c0035c,2fbf9e2d,983dda99,7d1249c6,8a7fa8cd) +,S(5764181c,d941b28a,a307bebb,912ae87,57f23cc9,37025cdb,b983eef6,42b9c772,e8173b4f,c23908fd,db5f6437,5457a43d,2495764c,f3ce1b8e,f2c8d2be,e0ac7089) +,S(38ec7839,7e965056,2b1e314,5d5b2782,ea16d2a3,82bb6c60,efd29edc,93ec1b61,acf04ea4,c7b6de2c,d8acaa3b,a4bf2656,f522e631,1cd51089,744d4c96,318ec96e) +,S(6ec4ef80,13d01c79,758439fa,108f7389,79c9f7dd,4b285eb8,b7aed579,76c0b572,2328e642,e618ecdf,3a6560e,3eb6af15,7a6d266a,f5f3c4df,13c1ba2f,c898be7e) +,S(d8da1f6b,30c27b1a,5000fc14,9a768683,4c40a581,c4ed67ba,88492449,ef77141b,ccb532d6,876d92cf,2b8c310,839387d7,d92464e1,727287dc,49a3b348,2d519758) +,S(84f25402,734970ec,966aa9f0,eca84a1e,6894d36c,338722b4,e5fed162,8f7ccb90,f2d7fd09,f07e6302,cc97d283,d9f06319,9bee137,d3946944,983c2192,335cd8b1) +,S(ef6752b5,58874372,859190e3,91d86ff7,3adabfd4,cf008038,136b2ddc,ce9503e3,23d9ca50,13cb479,7cbaa675,98dcf98e,73f949e4,614390f9,1e6159f8,3f131c56) +,S(f88d8590,3b3fe67c,f641cb52,c77c776c,fe198f74,fe116a46,602bc2c0,1085ba6d,58af2abd,2178ad68,a3695714,cddf14e4,21da61a2,8e6cfa32,40507fb7,ba08742d) +,S(93b739bd,d366b95c,675daaa8,c5ded7d2,18cde6d5,d15d354,645de017,2db9c01c,24ec535,6c2f8eaa,633af5b9,6ae0fcad,7afea5f1,c7c8bfb4,748b886e,25cf3627) +,S(732cf404,da7ae5a2,dbf82f80,180c1154,6d313b92,58980f95,d413f223,443394,858e8326,1758b90a,902eae58,a777b56,e8820084,153c9e43,1b7d789a,4d596953) +,S(efde0719,2c40002d,3f82e024,a1b838b7,65fc252b,5be4af75,28ea5994,a9d36e32,89c1d35c,3a153576,91a63585,183a9c6f,b8dd69b5,69d45483,f0c2f80d,3dd9107b) +,S(9eedaaf2,80693392,76420c1c,da950bda,f114e65b,9b1a74a6,b42dd90c,1ec90a15,1399dc24,7fa540cd,3249728d,a4d28c52,26f427e1,ac3b533,7de8ba07,d3164de2) +,S(23f0ea8d,342aa214,69deaafe,bfdb487f,775805c7,d4ba17dd,877d3d42,19433195,dc1c6e31,d2a481c5,5d32ca8d,1d4e93c1,63444dc3,9e7c306e,4fcbfd46,b699b03) +,S(d85270,58c29e60,58916e82,76a305d2,edd47c0d,4e33052c,74cb76e,abe060b8,9a0e4904,e4db5bb9,5ec9e510,59ea4993,84d497b6,8a9a1258,3a2fda6e,bd0cfac8) +,S(1b34c95c,ccf91204,5922d2d1,90cf3860,f7d36b37,7ab3763a,d4d9046b,309f28b8,70c2320c,3f5f663a,b6478c3d,2607cb4d,f7080de8,91bb408f,6f14a11e,2951e948) +,S(32558fdc,ae5e596b,b756d4e2,f10707a,89569d36,1498e8c2,8fca1473,4b84b228,7759a8b7,5ed5755b,b23978c4,3d5aacd9,fe63f6e0,74b6fcfb,501906f9,16038d86) +,S(64818b77,37d2bc57,391a3820,2040afbd,6028d7ec,fa3d6bf8,577cb1e8,dd984acd,4202b934,6ae9554d,9227b891,4a6304bd,2cf895ec,a7267e1f,5707489,71ca2300) +,S(c6af6ac6,ec2d7cb5,42aa2373,24288551,bcd33705,72e1b1aa,e572d87d,8d77b333,fffe5559,4ae5a2df,18e393bc,dd0407ed,5d5af18b,85f22352,9fcc7cda,dec78cbf) +,S(91f8fc44,94ea12f8,fa2a031,7f32fd44,2e7a9e34,28eeaf13,a8b0de3e,a4f1cef0,6a0a47a,d81b1dd0,ac6765f4,20cc26af,e76c2225,eaea2a42,481ff6d9,a554dbcf) +,S(e159a9fa,6a26f57c,879b081f,dc015b46,dc610a61,2335d6c8,e353fc42,11c1c017,c209c643,445ae009,a75656f9,b4c1df2c,f1c181c7,ca81d0b6,bd749afa,a93e8851) +,S(e8e9fc5e,135f3a97,1211eda9,c06d283f,1a705169,b89e5813,556beba5,a4f9330b,e8b96899,3b73e8f6,da7b55fa,6f1e44b5,c88423b9,f3fc5553,fe0b10d4,e9af0abb) +,S(f3f5d529,d5ae4c0c,36c27ec6,e13384b4,11aa9818,aeefb5b1,64243536,bc0edead,3f740643,1e40c133,345abbc4,ffc5e0aa,1dd1e306,43e52ae5,33f5be61,db3d34b9) +,S(c5b76430,f5d8bb9a,e1b9acff,e1417602,9eae65c,9ca1606a,2e4f6d7,6cc81159,80689f09,70089098,24087591,6915380a,29b13933,9a000fad,d2e86d8,cf2429c1) +,S(954aa4b4,34f59074,45ed30c9,ffb6db50,ff275564,72894261,e935109c,cfc09b0,8023ca86,1bad2c25,6cd76be8,b3b0fcf3,a808b76e,80a70ec5,83265d3d,c72e4ad) +,S(55da8bb,4803f339,3020c9b9,30a58336,1b96ee54,4bbb4249,d6df1335,6e3d528b,dcc44b88,ca06e9f5,86cbb209,da01785c,2387b14d,355a2575,799ef7ce,32e5b64c) +,S(8084e800,d810b286,b0ad48d3,d262b4e1,db59eabc,a176e368,77a7f8bb,a3a1de03,d8beea9c,59f865fc,9f09c12,9bc5f980,70d60ac,eb348f85,e0888fc4,63dc1480) +,S(1b2bb6c2,36c87f88,748f49a1,5094949b,d15e0217,b00c0bd7,f85efa41,5718b39b,2164b195,6aadf36e,f1bdd018,6bea9a4,c3c3f42c,b0e81dc,8101ad14,51029c74) +,S(fba687e8,125c372,e5dc65ce,3d2febed,de9139d9,9f91ad84,830da38a,54377872,8944eadf,3b89501,ca4a7a82,105a9613,55aabbf2,57f4bf83,923ec12,73e001c9) +,S(b58e4b80,a5f1c16f,f9c699c9,75a2d797,d21e155e,f091ba94,8aae2dfe,fd560cbd,fff9caba,1429bfa6,e571b7f4,12d6aa97,4606f7d,9025efec,937a5128,52cec3ec) +,S(8ebcd526,da5d6c21,55222551,e05c6be4,114fdb7c,9d43a900,fcef17ce,3426edec,73a0fb98,6b3301b6,3eaaafb1,a52f5467,de11f034,aeedc21e,ae97df86,513aa97e) +,S(fba4540b,924b29e8,95dc68f0,e971549b,7354e032,64040d2d,bb956691,1bee325e,529088c3,3b9857ae,342ba0d0,7e52843a,290f3c27,16f5321b,6c9e6f51,9105ebd4) +,S(8b7a2c97,a1a7d324,6d86301a,66f3f36e,ce014c97,651b25b0,ab46f4e8,bf9c44de,b82854ab,699c35b3,6786c1f4,71ea7536,7c88a684,43fc17b9,4cb328fd,a4b247c7) +,S(9df11743,5adb7154,e7003bbb,a1ba909b,93179677,4bd4896f,40c39a58,ead2279c,a7922f4e,a216cc36,c36913d6,e7ab8641,d4566865,dd7a2f83,77ef219b,41b884eb) +,S(5beb7b84,749b444c,82efd9e7,37314892,c54b6215,c1f9be9e,414adae4,56931cd8,99e425f,32cd0a7c,28e753fb,ff308eff,d32b7cfc,eb51df7b,64f60e9b,2fabb95c) +,S(2a830c43,ff204ba,78c5114f,4a3b7b09,c9f8ed5d,17066f43,cd512af6,4c788879,12523a4,e8882652,eba827fe,d207eb00,9ba14809,9ee42865,61e96230,62666c84) +,S(f71a46a1,4c1f2a18,e68ab408,bcd32d94,985a7714,19c1419,1b69221e,1c57486a,adf19b3e,ea79a53,4fcce36a,4cc0da0f,4fac443f,b281cf0a,ef675b6d,20534875) +,S(2b80e5dc,aa9c2b31,678ae2d9,f7d63c0c,bbad2bab,36c412fd,cb6436a7,c69d193b,bc83e04d,71d60062,b681ce04,c506247b,8f3c9019,c2084ffa,27621d62,22119c3) +,S(49cbdf3b,e521c69c,68375b58,d4449341,75424a0c,3c45d5b,b975235c,e63beece,c5615eea,f0f0e7ce,c3756aba,d3a136ae,91d260f1,563997a8,ae46c49a,5c62de7f) +,S(ce4d4714,b643b115,9215e2f3,1dd070f7,f7aa663b,9ca87739,79c5ba31,ce9ee1b2,b1f35e12,a2fc3aa3,4db59ef5,e62101b0,479745b4,200c10aa,d6f8fddb,1efeac38) +,S(6827b6bb,aa905ac3,8d93bb1b,5d5881c5,a8bef479,ed7c5656,2992d4dd,61e10054,8524a87b,af65020d,91848427,95801f54,30fc3727,7ef2064d,1aff8ecf,296bb869) +,S(e71e4d5,48f4d7f1,c7b7879a,a03a49a0,ab947218,b16dd125,19af4ad1,8056535f,495d0461,7098b3d5,6f7e3bed,ab5c9813,83aeed68,3ded1c09,f0d1bb38,e32f574) +,S(ef683979,7429fb30,d436aa32,a3feda68,65652816,873ce542,6320667c,6e00e032,b4b18e4a,de1197e8,fded846,f188a6ac,2f17506,f014d404,fbba3635,534613f) +,S(c729c1,ac8f7eff,e908007d,e2eed85,dd557e36,c1ec645b,a258b03,e52deaf4,2e83edc2,18584f6a,c5ebade6,a335a087,12365b89,ac38f27,bde7ebf4,561305fe) +,S(cf1d3919,9a716d53,b2bc4f2c,3ae2ded1,290d54c2,2124a88c,c1cc7fb1,115735ab,6b44f5a5,7ec3402c,e8980970,dab8538b,c276c8ee,ad542908,9b7b70d6,dd00e6e6) +,S(6cf3d7a0,266dee28,f3f1f772,ee90da75,a9c28a7f,f82d8f55,cf9d609a,5becdeae,3bd18fb3,1e11cce2,895b9cf9,4d9a99bc,ede5c9b4,c44ede14,34dfaeb,49bc58d4) +,S(da4b5832,ae63eeca,cdee4274,f00ae932,56393cae,cf830be7,f28749c0,7d395542,9aabb23b,d2d940f1,815610c9,d1684b92,106374e3,1b694ec4,dfec8818,cdb2210b) +,S(f91ae350,23210e16,f9c63270,cea2c6bf,407d1a10,e95842d4,b8ad5f7a,4330bbfa,1f161ac,d1962573,5969290e,fd3d1af1,53c91543,33651e16,1b51086b,913aa1c2) +,S(7e1bef52,cc3e2a2e,45847c86,27328526,c72e3f73,fa1c8255,56c874b2,f2f1ac02,be4b0f7e,a706e4d3,db7048fe,e0fc4f50,8ff0523,ee8d97f4,4c4c1787,e6f6e6fe) +,S(dd2695d,30dc2ee3,748e256c,cdc92eb7,706567f1,4be720ec,b27fc814,d3d5998f,9af32c44,f1028013,9ee7cf99,845472b5,bba67740,f0f0b96e,d1a02a19,a32dc74f) +,S(78fae650,714763c8,d12602ba,33b76da,125fe395,43fb37c9,4d20b337,649dbb9d,78dc4c0f,726cce6,f65826e5,eaf1fea4,c3b92532,6624ce1,21de2351,bfce3aa6) +,S(1edf521e,510e5dd2,aa1d3e00,d016b45a,1b6fb6b8,591d98df,ee692636,8dc98bd5,9a0d016d,9b2e9b8d,d0f4d817,71ab0f20,aeafd8d3,63beca59,7518da41,55311f86) +,S(8607bb0c,5e53b60b,9153272c,d3cc69e4,7ce28694,37562b4d,4166aa18,d0101d39,15ca31e,c83c6541,c35a294a,a648af8e,38870757,27924e98,8ef566d5,96eb519a) +,S(65fd300d,9a0503f7,80a0dbb7,c42b9bb7,37f9607,912f2df7,166b65f7,96d02eab,fcd15350,84fba852,11f94540,1f6b43f2,904caf3c,d44ecaa5,335b928b,4ea3b5d9) +,S(c918b3a7,6c847ce1,c01845f0,34ccbeb3,36d031a9,33093f99,f47f1458,cc02d148,f256f403,dbbb2e20,32063270,faa6e62,596329d,ca85ceb5,3ed3adfd,7f728568) +,S(6ac2dcfd,2f0b879,becb429,140ade0d,532e54d4,dbe0bbb5,c1352ace,5661817,f2c26310,abf9396c,5af23074,e72251c3,784c3de3,60466dc,ccaaae16,4a9e2af3) +,S(8d71c4ee,54acf389,cee39b94,b5feb2b2,cf8e95a9,45f6a95f,5b0bff2f,cb3f3d19,98442bd9,5a02c1c4,7dba3881,e3306103,f0bc8857,89b44cb6,54875847,f1ce52d) +,S(e8bd24d3,fd557118,f2c0abbb,511e874,2e5d7368,a909b072,b3dee124,44f583c3,e1d2c3a6,e28622db,65b7992a,6716459e,2380285a,cd60f43a,4d4b1bf0,8bce6538) +,S(62dc2975,5cf8cf89,e52c8c51,6311e3b4,483fd024,ab2ad1d0,32d7255a,3c075217,799e132,d80d22d8,e0f01e9c,d0954251,8b3fc8a9,48f3cd1e,9391f8f,5c0e2a97) +,S(37db13aa,cf727e60,cb102709,9c7d3c07,4d43234f,66a95451,a6050496,d44c0e13,c383bbe,8f8ceff4,196e9d07,e013a1f6,d3402a6d,d09eafb0,62924334,89b1066b) +,S(37bfb765,eab7719e,c858e17c,472f1df1,be9dc439,2699ec39,37875b30,fb2aa1ab,72718bfd,865dc4c2,2f935f4a,98af8ca6,5cf44b5d,66f0eea,23b53563,d1721364) +,S(433ede12,87fcbf35,5fdba6e1,f62148a7,b5d5c3fe,1200d456,6dba452,a85d1b94,b27c5613,ad6e513b,28f0c959,13e30781,137a4c7c,7aee6e60,5715d949,4757c20e) +,S(e582d9f,c5ed0de6,92a1917f,6ab7df46,d23295d0,b8b27b32,3af9a57d,3e671861,33ee8785,e2770dbd,7e79faa5,386cb1d1,d1c9e073,1b78dfd6,5571deff,d4073154) +,S(60b07b40,634bf15a,ee2d4e5d,a0f06ade,ad8fae01,4a6a189e,4e428600,4c9442c2,fee087cd,d243ba,62b4a2cd,68d8aac5,1557f29c,a57b0f37,ff2119b1,bc4b283d) +,S(4b167276,1e5f7ca,a245e35,b6e88fba,643e6da7,ce37c9b2,10265ad3,2de03100,28aacf02,476887e0,90d26c1d,cd51f15c,cacda02b,b6314a64,73b90c93,8ed8dde7) +,S(5d56113d,6d797e74,c4803e63,89a88ae2,fab97de1,4ed4e7b2,a17d2f9b,fe2a3170,94ef2a8,534eb2ff,a62462a2,7eb2b34e,c6545992,e2d973ab,ee42b1e7,d9cd524f) +,S(a9d03fae,75111ad8,d1157287,8e8c4473,f4a06cd8,f28dfa7e,e38b3d06,3a34f828,a0733c0c,c7319879,2ca665bf,968f6bab,480c94b4,c7de262e,4d9d1f95,33517881) +,S(74199571,2b1abce9,ed4db3b7,7b3f7e70,58fd3716,1666c522,50855f25,660e1ad5,710caea8,97f7589,cfd3b8a3,22726000,ea3ef2c1,8aac385f,22b67bd9,da44db) +,S(9f16990d,bf81a5b1,eeba1e5f,84673e16,ba0106f2,acc68be7,cabab96f,25918dc8,d60d47b,62321042,34c49d39,c03806ab,135d46f1,ea6587b0,f0b6588c,50ebc4f5) +,S(3b5069bc,4f12b9a7,ad91c888,fabd15a7,c99143f4,c8b24619,b6a70c0b,2301d57d,dbb87cd1,ae59a944,9fb4ddfd,4b311d66,da18544e,a86b75a8,979828c7,fddd1a79) +,S(9dea63a9,67b5a36e,bbbf9af,bbfabb31,f90cdcd7,9b75c68,1159b946,dabaee90,b14bb99b,11bab958,e31a605c,e9180d23,5c7d2eb,94d4de57,b8a66627,c6bc4464) +,S(d0b23392,1da36a84,2565cb53,4411e63b,9fe6b2c,c33c3a18,8e0ddf48,55e31e79,80ed93ea,1a6e5492,dcaf1cfc,c350b3b2,99117276,43fb6a75,15c435e5,f74f8e9) +,S(8adc9655,966ae44b,f98ca7a4,9f441e3f,acfe85c8,f7111da5,52c817b3,90b03d20,ce72054c,6a717312,180c80ea,c9337430,5dd1d566,db1b93b4,eed1a6e5,73c0021e) +,S(f6f76bf8,cf6d3dea,700800b6,d018a4a6,141ac610,e2e13fe3,ec916726,1e0c1670,b2c478af,e1ea9876,98e5e2a1,6b3a4ee,63e4fef7,6644da54,e241c395,3f9a302c) +,S(d58287d,38b7da30,174fcaa1,873b3913,2176388d,6da5f9fe,f873d86f,14b898e5,785fc934,69ed085e,8318f91d,114ad0cf,da2b8ff5,61e545ee,3502e9ec,6afc8402) +,S(7772ca23,50c5ee55,9ffe810c,6d8702c1,538e3d11,f4b8354a,2fbf674,39a3661c,5a2312de,853fda14,5b48aefb,23e98e4f,fe3dd3a8,ae1fcd6c,931d9a43,686edddb) +,S(a2f9f976,c50f3687,7ad0ac95,efc3fb2c,46ce903e,76ade308,69705df,72433ad5,ec565311,24c289f3,35e11b22,bf8d7445,f201dd4b,68afa38a,22af056f,c8c285f3) +,S(e20d9765,85f8c567,24d0ec16,5ad27110,26fce166,b52ce11b,cb221a80,4f8b15f7,63b61933,c7f63862,98b48b6b,c6abb54b,21d08220,166ac31b,fc85d4dd,998f33fb) +,S(8868b59d,ca1de2,cbe98d94,506db1df,659ba688,b2bf093e,42dcec03,acecc18f,f02e9b07,96b98fb0,51dbfe8,4524ebf6,dea56251,afb53076,e2215d83,fcf2fd0e) +,S(1099f82f,e32a1361,a785f86b,9a6bf0e8,99c83226,7826d6a4,3f8581b8,89fb677c,13fb83f2,9aa7f271,2cf20cd3,592eac46,cd2d3e61,9afe9aac,7fcf37d8,9c44445b) +,S(4af9c696,77ece7b3,5f732969,8ca61b27,deae65ca,ee2d5d31,ef2051f4,35cbeea3,73004596,429da976,f96e3f80,a24408a4,ebfe5196,8130c698,5b210826,664e5ef0) +,S(9680cbca,5aceb8b0,322d4bbe,8713cab9,300d1f8b,d16ee045,edb3b543,57dab473,2f293940,e36ba1d2,ecd4697c,209b33e0,6904ee3c,2798aaec,e9131d9,bd0df58a) +,S(7eefcc3a,fd6347f0,5f9c3720,31480c92,3eb7fdfa,d6e9c0ee,4e2db9ae,27fae7c2,b8e9fa75,4f745c14,7c753e42,17bb1e28,7bb93d9d,aceb357e,9738f10b,fb5cac06) +,S(b823156,d63612b9,3461fbf3,6894955d,65e7805,b025c2fe,98fd46fb,2f9fddb4,f23c517a,826fe91e,45f453eb,fe9eadd4,d0b537c6,a2a8f60c,dab9dc58,10bd465a) +,S(e801d35e,2035fd54,92178706,e2e765a9,bfb9de22,e89182b4,4d5144d3,85bdadd9,1e648234,27dee6f0,818868e0,419e37a9,1c216200,3faa7478,48161809,76956a26) +,S(e9d4610e,56b70969,284369e5,7e890fc,29fd7750,8489a1c,2f348f52,cdc67f3a,8e5f6aac,357d82e1,a29bfca2,2ee4516b,1df0e622,257c2c1f,7d9a84fe,b48e4a0e) +,S(71c3ef0f,51d6ddee,340d7aa0,94680084,b94bae8a,e3528ff,4a481af6,d3b7609b,4d1674dc,2f8087a3,138adc4d,aa615a43,db6886d4,4992fca4,544f57e3,315f6b96) +,S(9567ce43,b6f5c41f,bdf8b44d,938abac5,21aadb83,c157b947,ce999c0e,4a7d6f20,c9d86317,31ea318,a647ca8,945cc35d,1fd0fdd9,b2de4fe3,5e2a0021,33a35538) +,S(34523d4f,81166739,10b3de85,11a1921,4f8fc753,fd8963e,b9db22b7,8edcc141,900fb9fe,268b88eb,9b80a066,277d8ba,877bca84,f277dce7,7d6e90c4,8422ac90) +,S(69fd1f7e,5f1c43df,a2f4350b,f20e5cf1,f2993dfc,b61cd278,1590ad79,e3c1bd98,633726cf,8b74940a,edb15665,a9277973,2d1c923,2bcdd615,43c9f3a,6c51d7f3) +,S(e4c2c424,c28cb8f7,3146dd39,bb4fc6ba,411b2a75,e317faa2,a9f878af,e94a3de7,fb8d17e8,468e5ef4,8da60739,820515cd,c861378e,9b3bd158,fcc8a949,eb21ae89) +,S(5710459a,ada916d0,9c1feb59,c494863,98e44513,226119ea,5ded7b1e,34e32773,89deedbd,d2d83a58,4e56b409,30a8355e,905bf12a,f33f49f0,7383eca4,e63871bc) +,S(d56faed4,171806e1,5ac17f91,37101b27,59a3a8a9,90b85bc1,89b217a0,6fd48e64,fa871ec3,3408b2d6,b62f513f,5368f549,ebe43977,a48878c7,6d731447,34a6652c) +,S(e7416eeb,da0b805b,68b47be8,eedf87dc,cb5cf012,804d03f7,604525db,aa599bcb,8610c716,f11c567e,313eb4c7,77e4314b,533d4f37,13b11185,bbcf5442,b9a56c19) +,S(8ca59862,ebdd3541,91c60608,13ce32c6,a4fbfca4,6e60175f,2d5f1607,d5fa997d,aaf3480f,b132feac,6adfa195,2b14d0d,113dd6ee,faad71c6,980d5691,e37698f4) +,S(6496dc45,1fd43b45,1915867a,846c5203,6eb8e4c5,28c2a181,72fba6f1,53243413,44fdc41,f85c99e,e00a281b,9292cf1b,153fe2bc,5c8b3e87,cb14d624,e44da1f2) +,S(3a424463,aa82416a,a38bc248,dcaccd20,67d20721,d4e8f5d6,c9cb2fc1,91925a5d,71a56463,fd242591,434775cb,37c81bf0,d4857abf,aa527ca9,c3178464,8afa9fb2) +,S(6a945b05,51d55194,adbf7985,aa85fe63,8811781e,6b787418,1574d109,d178c2e6,186d343a,1ca3a836,32421fc0,d267ca27,80df9af1,32625d31,924e99ff,9b57ac44) +,S(13f1f692,682d04b7,b7e7381b,8c5c13b1,32baac0e,b7f8c8aa,c9ffd77d,3aadd47f,572a05e4,9622ff88,9eb36852,85d1400f,43372533,38c47ce2,282aa4ae,26e99f0e) +,S(79fa13c1,4f0de8f1,ed98e7b3,3edb77f5,a2700707,e54ce522,a516634b,d2804330,a094bd88,e1969ee7,3f41e40e,60f7198,cf2484ab,5a2efaa0,96e891ee,d5987c65) +,S(df1ff6db,d2c61bf7,c273f735,a6dab3d,fb08377d,bb3dd101,9dda03db,e533130a,2fdc7ad,68c58689,92e5c969,d8d14a94,cd0061b7,5ab0e824,fd19611d,923f886e) +,S(a8223280,5f5939ad,180f8776,810cc7,2bff651b,df7972ec,51d86d2a,1acbdb34,9681590f,982e3632,b2aea9b4,40043751,e7f2ef2a,d4b125b5,2784ffb5,17c2dfba) +,S(406b0cc0,49f3bf58,6990ada1,63c73932,b3780fad,ba3fd8c4,79e6a688,484c7c44,aab0e4ef,f2508e54,79074fe0,218aee7e,8b217932,859192d3,1bb20817,df6503dd) +,S(4e7043fd,5783479c,3dcf103d,bc4d9bc8,523c81ea,dbac9460,4b73300c,f516bcc8,196287b7,3ed01bd1,e8033ead,66c92625,77c859b6,73a4c7fa,98f53d69,e82d1133) +,S(a9a2a671,b945a5f5,90575c0e,ff24c070,a7d55b00,e9d2f44e,43cf400f,f3e9997,6cd45e20,cb972715,167f957c,af7f2f3f,9ae22ce4,3b46d4ca,5b2a58db,6e0c6285) +,S(692a1394,75ffae88,fba47ae4,9315a6ef,12b2dec7,6807608b,22ba3ff2,883d3c01,74dd5b4a,3c14a54,c0a86732,1a77d160,c834773f,8063406,85a65c16,6ee46131) +,S(36f915fd,156638bb,88928e75,d00fcd49,63b44ac,f5d016e7,7ddaa8c8,d62cfad8,3f11eb6,16edd183,5ee17d02,722cf6de,991dc8b0,e37fce3c,cf7f5db,e842e8b9) +,S(3f0f6f5a,7e010c0b,5442fd6c,a3643144,a5202a7e,bb3ac8f,99aa38d6,4aa53b31,2574d7cf,5b33e29a,950099ac,db0ffb3f,ab1f9ed7,f13cdf9a,b869fd07,c35c649) +,S(8c58faff,71f661d,b21d4258,a92aacf3,508a9dfa,bfc00cfd,26b95673,34b7b067,38d1e894,ea1d4ee2,843d08a8,80b11325,e9a8a171,59de273f,694a14d6,73944893) +,S(d806731a,205c1a3c,64b91864,2d940b12,dbc6f580,866b7a9c,f287fb7,c5da78de,870a8430,2ff57abb,735da831,863525fb,70402006,d241eba8,d43c2ebe,cdd0e05e) +,S(7dbda37e,195db041,a4dde151,5a7cdd97,416bde09,12b9a741,3354204e,2b848648,83c89c7a,649d0070,fde84ff1,32f60a9f,e1c0261a,87a8ccf3,885fb003,10715e71) +,S(8afc23c0,c803b0e2,df78ee09,3b776cfb,410a1b52,7d4be45e,58d8cee8,3ec54a1,b041eece,4f4ae4a0,b3a52957,386394be,bf7b11a2,b97eb5b4,1bee89c,352ed76b) +,S(4e4424c2,2c50fab0,4b803b4b,2562114b,1b2531cd,e5786112,36fb9021,3652207b,22bf6181,51187118,fb421e4,fb0cf243,889d5ca5,c14b6ab5,7e7b9d0d,d9796e6f) +,S(60717788,5a230af8,a0816e39,6e39b34a,f394b1ee,c93ba382,8fd92941,e6e97453,a84df29f,2b9da41b,14f24762,df6db87,fc0a18fa,89e356f4,9f8f4017,dc4b26) +,S(c9f73d20,384e56ec,37bbbf8d,facf70e4,a271f169,2dc22ac,6022ca24,8caf3213,7622e7f4,c77f9581,b73c9bfa,8bf5b578,89070e8b,97616cb0,69ea25f8,8dfb5437) +,S(19ea5dfb,dab5a1d8,c3c2bfea,48d90f6d,a8b9959c,630bfc4a,81ea5eda,ee45282a,c21295d,14bd81,7c3a4d62,af307b1c,870a959d,7d6e4c65,3b8e1db8,fdf1d56c) +,S(564bdb1e,30b2c292,cdf0e149,1bfaf852,4780669,717de5cb,290cbe6d,c1617b58,9a8da0e8,6fc0b95f,99e84198,877f5ddf,32508c1c,ebb9984,7004f74e,7e2b1c0d) +,S(5bc93842,4f3ee6cc,926e2123,7bee0739,50b39d1d,e0dda3b5,4bf46953,7d0bf06b,d4e9c3a9,662778be,b7f4bd4,cd753a50,32bb003b,694b5e00,c119dea4,20fd5d16) +,S(19432e94,829e8b57,3eef4fc3,181c7d7f,5b2a5f2d,a2e8c3a5,980db9bc,5cb7f99e,f75c999e,5c5b8567,bb69316e,36e01acf,2e860781,5c5703f7,a4be72bb,9abcbcf6) +,S(d399281e,6196ce19,a2ec28bf,a0b1b559,8d0235d1,beef1672,ea230cda,20080b8d,1ca7e95,20ffce3a,33e94931,95eba433,d5483cf0,d5edbea9,6384d1a3,5168aa19) +,S(6c84e35a,b220fa9f,e55f5556,302f6656,39372e97,74ae26ba,e21ca8ea,10e73c88,98a11b2a,bd442c0a,d49711e7,b0e8b234,1d15465,71efe9b8,9a7b4c02,1101b2b3) +,S(7814cd8a,b1b045ed,a1797f14,c83bd807,ec4205b6,e9df4858,1180a80c,a0f8f64b,ef917e40,edc8b8ff,f53e8b70,4de63adf,6bf17730,41af2284,1b0e38d3,b515f33b) +,S(7a01ee83,1c8e22a8,bfdaccfc,cd280532,444e710d,7138b993,fb6e06c7,996235f,fe512d09,19895c2a,b62f2e08,90dc3bc,dcb06198,18160b41,4527e7c,281a5519) +,S(655ee6bc,df86c9ef,918b5660,5d4a5e79,512e856f,3f3e40ce,72e8217c,1f9bd908,cbeba5a6,91fcb085,f3996ea9,d081e69b,7dfdefba,123df5c3,cae94f63,12f87721) +,S(ebd68009,fb0372e8,eb0be25f,e78117bc,3d4d4814,440f1d9e,1cf87ee1,de5219bb,8efb7e38,6f96df55,bf0aed2d,6bdb75f3,6da8cdb6,ff65868b,d8ce79b4,ba58814b) +,S(87340818,9ac05bbb,4e95cf05,17d5abd6,8b7834cf,1168f914,9f1d63b6,19a3865b,9f1fbd27,72ce0f15,c91d4dee,dfae0a3e,7d24c0fa,de2bf30c,df63f93c,14480838) +,S(61b6b213,b02a7bb6,4de62e92,515690cb,5dda3a4d,aa96f68b,a12f2c63,30513df3,cc71b8f2,4eff8194,36ad2962,8c003a1b,c42c6ce6,53997d56,e0162508,c2b6144e) +,S(4ba7ee4d,77171ae2,e39c9e66,3849841a,ed5e02e2,182d872,98f0a064,3925fe37,5cdbd5b4,fe344f16,cb72158e,b80a726f,5a9da4f7,751bc4f1,f1fdc734,8e96dbd6) +,S(d5827a7f,c4d5dcd4,32e5bd7a,46892e9a,6f9a3971,fe9e1de2,ee247e6f,208badb7,f790fadc,9d0e0c0f,61efb534,9b23c60c,2fb667a6,3b52cf18,ca0f0a1a,6098e1fa) +,S(81ec5159,7f950cf7,c0d44d4a,89efe691,e9086dfd,ca25098d,411cb9b2,93237633,885b27dd,c9eff80c,94653f28,ef92fb60,741d3a2,aa828065,5fa60b73,eb9a1e7f) +,S(28fc41f4,a0d4f680,76a3e06d,af0aff1e,6e723779,d8ac9e68,4cdba2fd,6ab6dec7,b1e4af1e,7affabc7,3eab9415,c15b235d,482c6a8d,b1085f54,d80ca2aa,49657225) +,S(d5e753d6,c5bf75c7,cb0f5b85,77fa2f9f,6341a88c,cf59b5d1,328b18a8,f7ae4f47,d1aa54b9,8eb01a32,2518a10c,8ecd66ea,fc2f380d,d97953cf,faf0c540,c4a1bff9) +,S(1682355d,89094297,e6008fac,44c1a5a9,257d413d,7589286d,8bad4873,1476e836,4f69c762,e29f90c9,e8459b11,d53ed84c,2ec9c2d9,ded4ea02,78d04546,eb09cf4a) +,S(9ef7a85f,b64cae73,2eb511a7,8cc46e22,73425d1a,d02272e7,9030240b,23e781db,c720356f,6f6a5a47,3f35e2f2,f5e92e2,78a50c9f,3a77604b,3eb3987,d09ce73c) +,S(4f6aebb3,6f429a52,4cb1be48,ace0eaaa,2174468,c13cf612,dd7ec70a,2e915ec,406ad94d,a8b6d790,2ad3609,252b6d7d,b28f96e,8780f6c6,39620b11,cf8e761f) +,S(4cac3e0e,5ac02e66,66710dae,5c0d7e8b,7a3cc7f1,a42b1f8e,88561bb,223f8232,9396ec8e,aa96f3c8,4ffcb9c,d8c29d27,dca65556,c2fe5931,8ba05a08,cb263142) +,S(86f3463,3aa2ac57,2c4a9dd1,64c7606,f61fbd78,60619937,38ea0a60,f79367b8,c802fd2b,556179db,5f776c9f,db4c38af,cfb2aa61,b5ae712a,3f23e58,25824f05) +,S(5323f145,7685e123,e7a5ab4c,d1d39fa8,bcd6f23,ba3d74da,318dc7ff,347103a9,3092fb79,ecccb29e,12dec977,cbbf38fb,94cab4f1,fee1e8e3,46100378,88691cb1) +,S(d3d70d46,402711c7,e680c45f,3a0e1c5f,f85cf106,983ff0e7,1a7f1178,33ea74fd,91982773,d9b90f31,16893b9e,eea7fb9,e4f722f3,e1577c90,fdf6f625,a8d07bad) +,S(df63b937,28a87613,2db5d71,43654f1d,f8cb89fa,1ab1efdd,6fd864bb,db6d4359,7c3b79ca,191a3ecb,6c793034,832fa5b2,a2c7bed4,84b792a7,91bacb7b,62ce5510) +,S(f1fe9222,8cc334d9,5f303169,a4e2262b,28a99494,c7decec3,9746be85,71b70c74,5588f3b8,4e65fa72,a2b35f60,f99af1e3,b67a2435,8c28eb64,69de5136,e751a10e) +,S(9030e75d,918ca330,edfec14c,b7cb28d0,fb0adbb5,fa29fc7d,cb3c9085,ba74fd95,7df20128,61698984,c0928821,c38aded7,5a452dc1,3bbdc4cd,71ad99da,38b427f7) +,S(1cd3c139,35bedb87,134f628c,576411eb,dfa0b586,2c3cc7d5,ddd7cf5c,77ad641a,2154edf2,5488bb08,be93a25e,c847b26,88264cf1,30fabcf,5924bde1,4b9a324d) +,S(e56e0737,a19fec7c,78b9f462,1ec0d5bb,bd6e91ff,ac995f42,202f127d,2446ad96,8830d827,368c760e,40a8d9bb,b693e975,1e69b42f,4b2ed776,98f889aa,3ead70d7) +,S(1b0a6ac4,58abe5e3,63e6dfeb,24ad8a65,56fd0886,78086657,587e63f1,5fb6b101,d2df6fda,e64263a2,b133e5aa,bdddee5e,9a35e86b,2e1f5926,5212cc49,335178dc) +,S(10a14146,8fd4618e,4ed390a6,246d62a2,50bb1676,45cfc679,d80cc081,23ea22b2,3383b868,dd7fdd1a,ecd13dba,f4ebb151,f9a09b25,bc30d562,b033800,fd40185f) +,S(9dc4ab51,5378a351,6db8837e,568afa72,e357f7d7,95d546ac,8a73e419,a43f5e35,8ddaa2d,9bcecfbf,e2a422be,1ea591ee,bfe05ce1,90439a06,cc68d66a,6305903f) +,S(aa93175d,e7a4e1fb,c538eb19,e89b20ae,13539e99,362035de,1aaac76e,3ced7196,edcedb04,c1344568,9f3e133a,d8b48004,c18d146b,ece3da05,effb864a,c2afb9ad) +,S(8171f3e4,da02d9a0,8bb6fcbc,6d06cc6a,94f3cefa,35d4ce27,536ef6fb,222edf7b,e91be5fc,aae62aba,1c02b55f,73c1a64f,c32038b7,a658f189,7499ca59,e9e6dd6b) +,S(51f6c983,c89128e6,635888c9,3c79cf79,893fe627,437464b1,11b08058,1aa19ab6,5d2ef149,4bb164f5,20c1dbf4,1a8dc650,b8cee400,d5e37252,a3d0f059,3881a067) +,S(c0a1f184,766b30dc,6a5016b1,9db0dda7,ec34dfac,74dae580,9500ab8f,6fd7d38a,bdcad3e2,c7b6daf1,29d41051,624d26a9,b27f361e,c695d490,52893597,eac6f01e) +,S(b1bb1ecc,95435169,4ab6fe0,7341efba,fde9279b,1eb78a22,2bd39472,33a0eb02,df523f5b,525342e2,c0cdbf0a,671e0c95,4b149084,de4c61d5,5a7bfab4,c81689a8) +,S(b5cc30dc,86d04ed5,88539ea7,e437391e,3b0891e7,6818c470,1803de7d,640b5dce,f1cc0d9e,45c7312d,fb1acc8,62e03f28,9f55561d,fffe4b65,ca41e62f,42d4ec14) +,S(de2b49e7,5f0ff53,28155b3e,a7d5941c,8cacee23,51fe16b0,da8e940f,9263ccb6,34d7a42b,b12dbf67,b0d7c680,178154ae,4690d5b5,703572ab,74b4d93f,6d8de99f) +,S(8b18f4e7,c129e117,e898404,65870cfc,ea5c0db0,ef2ef11a,d515f3ce,57cc8f51,6b1e1086,c8674a59,3c5e9d6c,dc8edcb3,72281c27,e6b2caff,8842e008,99111f37) +,S(727162c0,27cec888,918e46f1,762a830d,822ce424,b6a5f442,f9e582a9,17c86889,de348296,1452a369,e6fde5af,693e5247,24865623,cc516e7e,8416f38a,2f223cca) +,S(4ae4fc1f,4dd17483,f18eb9b8,1c2494be,946a75fc,a3f61605,6d0856b7,3505058c,d87e7812,e901fc17,da034a05,bd878470,59999b36,e2c617a3,9ae46921,f2563e7) +,S(e90bc9ac,e9e873fe,91826f01,66affd02,72007bba,4ef690bf,58b15206,5ff43cd1,4bc820e8,9acdfd68,51c9b0c0,65b9bfd,47f0762c,d2e56d58,905e6360,4564fa87) +,S(ba0ae6a1,db432fb6,f7a1af7d,be9ef746,8340ba5,7f051020,9af4076d,f51450ba,7d3839b7,4099420,1729894c,51a2c30b,51019a18,c32ea908,c58876af,912be720) +,S(70661b81,f77c6531,1d98b403,ed7b97d7,4f9682bf,2981fa5d,ef882022,d3accfeb,9022b973,18959f4d,9ae4bd7c,fb06fe66,7b4eeb92,5f46677e,4e5bc4e4,a6d06387) +,S(fe1b7b47,28153a07,11f81b81,7d9efa38,29451c15,8d1f11d8,e5e0922,fc471a47,95a075cc,68cfb7c6,fb115dc0,5e4c31aa,85725bdf,2344dfae,19c8a034,d2b0f847) +,S(8acf3bd2,bbaea907,28013d04,f27e3a5c,4325bc37,ec5c5e86,7ab70f7e,9acc3fc0,f679e3fb,36da27d4,f29c06a2,5951f80d,b3e2e0ef,dbe2c785,ee148657,3e16174e) +,S(1d855d37,25fc7d5a,b87fc6a4,7f62ba7c,d2db01d1,ca0f14f,1d6ea8d8,4af395e3,ceb263ac,2d41654e,d4655183,f6268c5d,9b0a9ad0,da8912a5,815dc8d3,20b1b90) +,S(1abb4566,30c24ce3,c84ec6f6,d70d19b7,9934498,451f02e,3926d70,592a8cba,4627706f,6be87fd7,2ad886ef,73245452,1778d293,41229863,f4b19548,74525885) +,S(1b4790fa,672c12ff,965d07e2,44a3f30b,620e5c66,4b098a5f,b86f2bea,93eac036,eed050fc,a758e2d1,f2a2a9a0,6b8391fd,7c19fd70,9c9e1283,1b018d24,e7edd60e) +,S(61878b2c,fc9cc88e,30ddcfc1,2561367b,44c106a0,21e3dc98,a433732a,68de3dd3,fa2454a0,37c279d,1b54cb77,498a9efb,afc6f50b,6b13e29d,436000df,1eaed78e) +,S(84048df0,2767feb1,7bcc21ec,f4502238,abc7271a,931730b5,3354010a,8544308a,d4712e4a,39d608e5,d47f9814,f7763c6e,605accaa,438ccb7c,838c88ec,e993c32f) +,S(eb7ac4e5,6c96175e,c3f1e1e0,37e89f95,8ba37d0c,a88055cf,889bac33,ca683a94,4941e267,2ccc274b,6d8bfe07,513dfc6f,cc07de33,2f517011,2bc3814f,5e85da8a) +,S(48a36ac9,877d4bda,b62b452b,a0288dc1,4cbce455,3809feaf,1a4195af,22142e91,e24d6d8a,1256288,6c6d8848,4e950d8,27eec39c,21ff6e25,30b50eba,ab69659c) +,S(9c3125d0,5a62a25d,7869af3b,1b23a00e,e817b664,c82d2a91,2522ce16,bccca1b5,c6ecda10,f6707168,18417277,4e18f5f5,38566361,5506b450,a189b6bd,39e5afe3) +,S(33e81e21,dcc7670d,c7f3843e,4dc8be3,10160bed,49af116b,c2ca91e6,90f80d68,e694c1d3,a0a386d2,e6df1167,8efe38ae,9ce417e8,9ec05bb8,fa592906,55757b6f) +,S(9543769e,6899e0fc,bfeb1071,50959827,5c1d0d4b,8a68f056,d8e1c033,1b6a1ad2,700cffd,afc58410,7635f148,72ed1ceb,1c4be86,7f668b16,3f579534,ec9b0d7e) +,S(4f41ccd1,73e62c39,7d481e6e,5b50807e,6ca9b163,e21dc203,a0d50826,7439efdd,fbf98ed6,aa8c1972,d88b309b,ab74b254,8fea56bf,e158d1ee,d95ce77d,c69f79d) +,S(4cfb6a45,584b00df,be3fd9c3,38eebc28,a667fe6a,4651bbd9,64ecf20,645f12e5,2ddfd6da,fe080e87,470fac21,d1255900,219638a2,5e72b12f,5501921a,f614652b) +,S(9efb8bec,d9bba33c,a5e217fd,8fae533b,8e536bc9,1817f982,1f217757,75eca626,661300ed,529c15e,918bcf9c,1a7dc3e1,8e3573b8,875e2f8e,9440f8ca,b0658fb4) +,S(c2a80952,5be7e4c0,b85ab953,ebe6dc5c,f5d3c0f9,e850e470,da9e61da,e430e441,1d2ded36,bf72697c,7da6fa22,1c09fbc3,6be06363,d50d277b,4839c4ef,809d9d2d) +,S(42b7ff6b,49ae822b,f5a16276,4c620b13,2501a1b4,1bf830c,a242e02,3bbaa707,e41fe058,83f0e400,712de994,dcbb5a38,fb2c7595,c5ea8b0,eb90a236,82b71d6d) +,S(ee0bb129,d420b641,2afe1518,55f78f39,e00cc3b4,7ee3b86d,f781f0e2,abb0c28c,f71d0e7a,5a4fa247,67c6204b,60edbadd,54b17455,54ae9099,258343eb,5c0aec61) +,S(1f1d8a07,9cdb3bf5,2671a716,26c503c,77546ce4,2a252e78,9ca487c0,78ef5b9a,c611130d,ae55512d,ea8e8e6f,9fbc3064,180ee4aa,63d1dcfc,5c39e98d,97571c20) +,S(5bda9c06,ecdc9fb1,5926ebe5,5418f016,7cf3136e,5f9317b8,b2912fec,d2a31310,358ffb70,dce1260c,80fe59d5,b72eadb3,89076168,a17b63fe,b728dc28,45ecad7) +,S(c32f6503,fa50c727,66652dec,8e0efd71,edc78973,48061be9,1f847544,df866ea6,67234a26,7a13ecc4,7b09443,cb13f0b0,6a34af2a,20b80856,6deb9c71,1fca304) +,S(5483d511,b71feb06,70e6c83f,29612640,849bb673,896bb069,941cdea8,9489caed,a09a6a62,d3233437,40adf0f3,8d8e4ddf,494d5350,7944becf,bfed3927,d88c1148) +,S(3d2d8f5f,f0b86ab9,1ecb9342,5a6cc246,d5e3c6fd,9c43d047,2d518958,ea322ef,4188348b,4c23ce05,1879cf4a,b71d7608,fb45d7ec,a184c509,c739f364,d955b830) +,S(3a5c3939,29ed6780,5fdffa9d,f936bc10,735ddf03,aab89e9e,40b47574,21af1dc0,760b1919,76752916,2ac2a7de,22975c83,44dcd52b,a945c81e,dd8224e,90a7011d) +,S(a3d522ac,7c1cc06e,3ef9272e,fe24a0c4,64886948,3373df90,e5dd484,d4590a83,6f53ba2c,b739dd61,219684a9,50001697,28c377c6,93054795,5661f2c4,ee1b6be2) +,S(ef0b0931,13992018,44078583,62e02aa2,c1437d87,ddb95d42,36751445,d8e8180f,73bf4407,8d184772,7d0408cd,f92f8c74,2173520a,41971980,1b9c842b,9486c634) +,S(8140effd,1498ceb9,c2211899,161185a6,a770c15c,d1ca3e07,f26f40c,6d15da20,4c74f3df,6d2db7f1,be68b7eb,2162f03b,51c1102,a02dc3e,45fc49fd,22a474) +,S(3445d720,8e089f1f,93d32f4d,3fd6fd65,7603c7f0,378b74,215a59bc,ebe122f0,6d41035d,fdb54ef3,3a3c8626,f036e1a2,38da0637,e82953d4,b63e23a4,890b6d5b) +,S(e14b2a5a,6235369a,1d1933f9,7124cde1,789a366d,5fe6ab9c,72c23d43,f7a58cd7,216f06c5,2f63c102,6cafe6ce,58a9e589,d67a9f19,625513be,44744d0b,f9fc8f8f) +,S(6d9640bc,8389bc44,fcd0b2b3,3c088170,eec93106,67348dea,f8f3e92e,2d891e0b,4b4c1485,6e42db64,9fe04759,a42887fc,68b5d4b0,8161b31a,1852bc41,7d04227d) +,S(272f1404,5c461f21,3f67cc60,d7c03b1a,fd028a05,b9e06324,62a0afce,fd9b2916,98635ec0,c0b23538,a63f78d,800eb0df,fd6b7583,31544b1e,825cd433,ab348416) +,S(a8c99928,eaae745a,631250be,cde1ce3a,4152334e,de916257,681329ee,1f3a07e3,4ccc2686,abdf3f7e,8e1149aa,5162fed1,24ae51b7,e61e4620,9f5cd611,e7351621) +,S(fb024b33,7f93d565,899be686,9b1e4c81,1c660d50,fd31cef,fac38600,d8975409,339686b7,8bff3c95,7e8730c3,9457966f,ee562ca2,89d95e12,7b072f47,c4c7fdb0) +,S(e0e48547,aa613549,773ecfe3,691b84d8,a6cb14f9,ce4494f2,35187057,28562f9c,60b6dd8b,56407580,52748838,9396004b,778609f8,69f47676,a6d76eef,dca7b307) +,S(bd6c402d,378b8b53,9f74d29,605e1b0b,ed9e383d,dfec2169,8076ef59,125d16e4,cc3aac9c,bb761c7b,3776a8f8,c8c6d2c2,a276924b,79510f10,75521b22,9def2c24) +,S(e6919231,eefa4f44,144e2c55,4f695235,d5886cbd,e150aef5,52c217ac,5e451c0,e74ee1d4,d34d2612,b4d56133,c2a11cfd,73a888fc,6927f46b,c2aba9ac,63b1cfa7) +,S(1a9acc6a,2a487874,4d92ac5a,328bdb3a,37c481e,8c145463,f9cba4a1,a03d03a9,ba6069a,960e3628,fae22422,47fe1f5e,df71fc81,b49b5ca1,26a7c588,fdf0fb10) +,S(5b52bba9,2e5fe301,f2c4e939,52db99b8,abfde642,3d6da8d5,36ccef4c,f6070910,108ddbdd,901e227d,118c68f0,a71aed0a,cc1ab1b0,2fe74341,f546ede5,b747ae29) +,S(92c13760,1ebe82a9,b11a096a,73be2828,652b0a4,d7f9a286,f1338a6,b1e05242,2e3e93fc,2dc6d0fa,5d43dd57,85f6c79a,51a588bd,d14e0275,59fac06c,a449d7c) +,S(3cb6f8da,79964c17,73a1c749,e89542bd,94b4f279,f6061d69,a12ffe5f,1d4318b8,42e4c1a8,b4f45ad8,dc23bd02,faee2956,72a77771,6e6b1d54,d05ba413,6bb11956) +,S(5fed6351,d34518dd,111a5110,50de0e5,3c60a14d,9a80183f,66415145,bdbf5db,6b79a590,de07a4d0,b74140b6,49bd8375,da77e01e,295e76cd,56a6588,7746c3f6) +,S(2b88f0a7,81c384f2,b7c245d3,7c061128,a14132b1,fd0fb56e,7d3193e3,d95d3840,f787e7a2,11446e57,655b6453,c2244974,c1632bb9,4838a981,bd4873f8,89a0e10e) +,S(c7b247b1,5a3f55fb,35b0ac3e,1da36719,18507f94,e988efd2,47bb02d,83293443,4ab40437,34c65f11,236b6ac8,bc27c548,c3c8e5f6,64f3cb67,99e7b8d0,6db85f4f) +,S(ddfda933,8dcb9481,5c08a20,12c137e0,45df69d2,121d4534,4c6aa375,e03647dd,e95f79fd,2a116bd,5972e93a,c58712d0,95f91255,a46fa091,bbcbfe5b,57795c1b) +,S(dc8da645,5084b105,6c7e3233,b247e87e,9d15a6b6,677f8c29,da04fefa,371da7db,c2a345a3,fde3ec03,f6a07fea,8bd7685,8fc66d28,6637cc80,93132048,441449c3) +,S(f53f3b26,c5fcbfa8,f1263bc7,a6439056,a31547cd,3a8c795b,8e355482,d1ff5333,113ed45,e664b9ca,98d88f1d,a17c4fb3,5249e8ec,7998b1d1,bb68be3a,e6716ac1) +,S(648d23fd,c6d4b5e,4ee1d647,7d969df6,7d754686,9313ba39,1d89dc90,b646cae9,d035e045,239375d3,4e6ffbd4,bae0697c,9b336454,3261206,15edbe28,3e18962) +,S(92e6dd0e,5dbe580f,82473f3e,dd70b343,bd51bde2,b1ca91cb,1c483fe1,3c2839b1,cd90dffe,a5447bd2,592d1a46,5a09b391,a61ab01e,a10c9201,5ddf4614,b39577a5) +,S(1315e58a,7616ef8c,fa223ec5,49415a54,eaec0583,6be6fb78,2ef4ee60,f49f687b,729e0100,802d60cb,c54e1fa4,5dac72aa,2fe189a1,737da80f,1ac58426,d7e1431c) +,S(3c8a9799,9857fd85,e26b284,a3554e51,86b001d5,e6d075e6,c9402148,ab3e2a3b,464f0492,acc720a5,59487b3d,60502067,a722e915,a10412f6,d6c69dbd,28b25977) +,S(ea417230,cc94c5f4,436b37ca,e6f9ace1,bf3c7f8,ff03c879,f862ea76,127591c8,961238cb,8d95d50b,baccff1e,b9cd4040,6f4ec475,7026b3ac,e916067d,85a4faa6) +,S(8eccf9c2,f271079e,329a8c81,62c98af7,48496ca0,b0c5840b,ceb19a15,361a6ceb,3e259a19,165bf1aa,630c6a7c,52f37b29,c8ac5239,a132fa5b,b53d687,b17e56af) +,S(32f0fc83,b3503a59,6873c34a,b54eb6aa,7bf3d913,842cd556,77f398b5,4f0f296d,d4736d6d,906f78b7,62eda345,9cb5f7b0,311e50ad,cc9a1e26,655d8ca2,fb81a811) +,S(b7d63110,77c83a8f,a43c171d,a5ff7cbf,e4fa4cc0,b2614a9f,63831836,e0d7accb,6095f640,56441552,a8ac27ef,9c1eba64,8b84a5b4,c19237e3,5e285ebd,796be9de) +,S(ef6c904a,22df4fb0,a54cd74e,6563e56d,588b4f8,d6926cf0,6c32694b,be536954,308910b1,44cd37a4,e5bc3d3c,43715e22,aa7a0492,e0e9cc9f,b1095a22,65dbaa4) +,S(19e13bd1,e62825bc,acceebf0,b48e17fa,b375241e,6eaaae27,672d7ab,22941a6a,6f22c329,7005bc1,155308bb,dbf8ccc2,855ea666,e4af3bba,d3e3c90c,28b613f7) +,S(57d9bcdf,10f2f790,79349ae4,5f2980b0,9a98a7ab,d792a5df,967b7b11,1c8e9420,bf665de1,d9b7854d,e34f8fcb,1cc027b1,42ebfdf5,bfe4e65e,b5068a72,9a65db68) +,S(37bc6685,7c3d5e8b,878874e,3d1ed324,bb530a21,f13d057e,4e3f87ae,3df06b2,15419bdc,764db12e,f12abbea,c1ca7bbf,77764abd,72f5eec8,3a81c452,4c998539) +,S(1b30c5d9,9ca59151,33c012a5,96512c2c,b572e11c,a7412138,7f3658a9,f9c2cec2,dc42320b,2a0dcd0c,5404d842,17af8c9c,2344f751,16a5d691,1db0590,5ef39697) +,S(96831db3,50c55ac,dd329f4f,85ad4a5d,e6e89f21,85b93e65,b8db4e1f,c1efd0bf,86f43820,fd03739a,d0e75ef6,17072f2c,82bd8bd5,a1f8cef4,55e49ed9,cfd47837) +,S(cd2f500f,aa1f04a5,58309f28,f7acd542,bce7999e,a17cb792,66b93cd5,44e3d8ad,1f977080,ddfceaee,97c743c2,4815f795,27dd1b05,63ef009e,92994046,c8dd8c29) +,S(60392a7d,237c9e27,a3318ff9,d3552928,802f519e,60a783e8,ff32be17,4ad01c08,eb7f3147,df91d1f8,d8994afb,df297c44,88ae9e1c,539fe065,663d856f,22893fdc) +,S(f6cf77ad,df6ab73,20d68fb,9f3c1d7f,d8abb679,179b3c90,d22574f9,fa37ee9a,8ffa29c3,3587f716,6b5d513b,7df76311,77e81eba,1cf9b523,280c778e,2442ebd1) +,S(57c8015a,f542c514,595b6f4f,f11be2fc,944a0ea2,d26a4abd,1807142,da7cdf7a,b67c779e,80153cc6,7b6b32d3,3a3754dc,ffb692bf,d16e3e3d,2c9c673e,a8b05da9) +,S(7fe08558,ac184922,ffbd5c51,cae99931,2f58a17f,bb643b4b,fa1e419e,6b4fe462,7600477d,8bbf58b5,36e7e9e4,cd595858,7268cb5d,1599079e,5a88fbe7,79ec7a11) +,S(2e16f56e,73b39bef,d729b87a,d8e7c4e,3d81095f,58be177d,87bd9f3e,dd517b75,4ce271ef,57323a0d,baac950e,668f0981,77aa59f0,7a0211aa,69b4e417,375fcb7a) +,S(a4d4700d,456d7802,be781f66,6ca24a68,49200de6,d2dd97ad,9c2eba62,18ffdedb,c099f86d,e7ba0f0,e8f0e762,8864a4d8,9124aae5,af12f6d5,efed434f,c66e4532) +,S(b4764d50,50119e3e,a316c921,91e57ae5,a2327e74,187f145d,c048c199,db3fc059,e39be8fa,cc272129,3ec831ea,9016a188,4f127070,4fa4f092,c2f3d56a,4798653c) +,S(3e686ba7,d291abf0,ced5b352,e84fc696,c29fe123,aeb82235,5031931b,e7e2d0e,7b35c0ab,7cc3c81,f84caf9a,9321b9b8,5a889b07,98c9eed8,8c7dc4c1,a985d266) +,S(d7886f2d,1d4c70ef,c5961e56,33122317,58400105,288d3346,db49407c,d24a46c5,da645ee6,17c46024,b2e25903,d4d7dbab,c5ef503f,814f23e8,68d94040,54b9efc8) +,S(7cbd23cc,14654d40,5aa57ba7,1e375466,cea867f2,325db475,d3a7990f,ba17a40,eddce5af,96e66db4,b985541e,e638ecea,88d327f,edd37039,54ce5a1d,d2dcbc51) +,S(54626185,c279e1da,eecea0a9,233c2190,18f877bb,58614a5c,5d2b9894,17eb9795,6507ed85,dc8f8454,bf96730,5cfc7919,8cfb07f0,dc64b09d,928d0b86,e0e9b6f8) +,S(edcef155,1cbec2ce,2bedb20a,addabefa,59e68cf9,e2200681,89285c08,563c32e,ade67143,75592853,c296ab45,bcba4db4,bed59efd,9df68b33,b03d7a3d,be753179) +,S(e027a953,ff6ef9d3,f27db47f,bc91db7f,6a30bc5c,c834add9,9cf8d086,23380cd,1e6b244d,e18ad020,8e52d174,ac452a81,62eafc80,975872e4,c7e362da,cba2bbf5) +,S(a5006d68,db980242,54ea251f,3787d527,66dbf92c,aaa20960,e17ac6f6,72e2b2d6,a1938d7e,e854dd5b,94d98766,c0f74723,72d1e6df,5cd6dbab,fa63faa5,6a0b2b9c) +,S(327075f2,1a1fd9e,da69adf7,32995919,dbb02025,ee504e0,3d5e5066,8427be11,41a57eb1,c32e94be,948ee335,6d855fa2,611a4ec2,4519adf3,2deab381,6bc4debb) +,S(97e1a5c6,66694bca,6b10cdcd,7e95f74b,9c87ac04,c623799a,c1c7959f,1a3363bd,3cc9a48d,1ec7561f,7b72bb6c,4d671c25,56689498,42546a9,48c9b927,c8ab5e88) +,S(450fa640,a7374dcf,d11bce28,f4eeb4ab,d0a2d868,9f6fda04,7f790ed3,b0c07a21,eae88298,dc17cfa1,d482a1f1,70d1dd36,aa35a56c,7eba231f,c4c3ca16,efa77f4c) +,S(f5aa7340,fc0a66a1,2da09ce1,f4094240,d81fad91,87e944a8,a7a1ef4b,9e0a6559,1255b3da,9ef992f1,c62e7738,f84dba74,899d9810,9db522e3,49ad9fc7,2aeb5017) +,S(6900965,55197836,a7b23841,97fbd75a,8857ac8a,8b14ec8c,90cc94a7,8a42f1b4,1dc181d2,38c976d,b4627107,2be05f32,952b5bb4,e9ef4710,f1bad8c,171b027b) +,S(2b1aa05a,8ed84136,7e99f377,bc3760c3,bc3bc0f9,33555e87,8ff2d212,c3f290aa,47b25af4,1eb8bc31,915f5896,57f368bc,35e9000a,cbdd0a41,7b267e58,cc13e280) +,S(a4e6b69c,a18caff0,d993540d,3005e5db,454b1e39,d4c81a7a,b5315d25,d052d81d,7cff2103,9c587904,a42d78ed,c2e7a6ec,df4fcb21,17c89822,36fadc01,a15d70c5) +,S(ab44bb96,c74fca4b,3e39cb0f,d9dd7795,f728e1b2,80a7cfa1,7a36916f,b39d2582,59d91ba4,519fd8cc,9e773feb,b1915967,7edc0dd8,1e794ab7,cb76a2c9,9026f5c1) +,S(83b0c85b,3fb9c3e4,8c96a31a,e5442288,93472975,5d42fcc7,715dbc23,9de332a2,e99f5640,fb620582,fd833b34,2f086800,9652d739,2d6494b1,e36d301f,35a6da6e) +,S(ea45313e,624ecf81,676911ee,500bc0f,e5bd10f4,40e04788,41eb215a,ef954537,4ab8b00c,e2359cce,203bde53,b9e8a454,d5afb101,4d0b644e,81ad1313,6c0c7445) +,S(936c10e4,af823d96,9f7f7a26,98c927cb,ae6d609e,37cf7412,ac4cea1f,51a3cd4e,46f72bbb,10dd850b,8e3e5bdc,f0359f6c,bdb9067b,13d2b60,bf68e8df,b17b7213) +,S(436a5d5b,61aac3db,392cf8e1,36a89b31,847bb116,5d1e296b,36c90d60,f2e9bfd6,f81e688d,ae67cacc,1978559c,84a90f9e,5e342bda,e73647e,33655686,2f36d68d) +,S(9eb95427,3fe789a1,3a24b929,e54f6262,d931a442,2e61867a,abd84d80,4b315d7,38bfc192,7dc0e640,820fba,8effa82a,d29f204a,fec11c60,768f95a3,4d2ef59c) +,S(3826b6f5,87ecbc0a,cb6b4328,a00f63e6,ecb77a0d,bda277a,e6e4ba5,fa280d8a,d9435fe,dcefe69b,213e6eb9,eda63f89,db35e293,8ba3d6e6,57232f04,3a4ef271) +,S(a348cd11,ae0ea1be,3f993bcf,84364b9f,4dbdceb8,db3cca21,cd0f8ca2,4a1dde2,1fc851d3,db7cfaf2,6a1c202f,212b68a0,7078ebd,6d6441e9,1d1d4884,1c83ac75) +,S(bfe15639,237fdf3c,4e67646d,724264e,5d70d1e7,3cb70205,3c4e9a06,2bdf7329,902b37e6,1ec5e59d,9c3c09d1,d7767483,345488dc,e492e3ad,f12d04f9,2b5f88e4) +,S(e2fdb14d,81a1b6f4,d40dc346,c8205821,2642ae10,2707e944,14413cc9,c03dfa5e,3011b4ed,846e8551,6c66925a,e7676062,131e37b2,9b00c408,6c60a3e2,3488fceb) +,S(bbc659c6,8f476748,17663659,db4ac222,cf1119ea,ac27c38a,535ddec6,913c7416,1f8b6ee1,9fdb512a,fadd13a4,d3fe13b,48250120,975b8c7a,47798267,7954b954) +,S(65bd2a02,9866789b,dbd6f743,af85a789,ce9141b6,fd9ee056,cef4de8d,a2505521,32dbe030,1cedb7bc,5d5644a4,6c3e6c56,990b184d,710a770c,6b65f39d,3378f5a5) +,S(1ec0e6eb,8382cf7c,24d75a49,fc0f3724,e9318d90,9e05d406,a3a5916b,2278e981,e50e129c,f486bcaf,eac8ade3,c697debe,fa56ac06,337cd9fc,240cfc2b,3415715a) +,S(7390af1c,203da259,9e1aceb1,ea101628,c0399c92,33658d9e,10dcb10f,63a9eb8c,7d215496,60647b09,d7bcad45,1debe7d8,2c3adaa3,39bce418,320e0df0,977c3126) +,S(99a51469,7b913764,783ff7f3,7099cc45,127baf1e,d8931eb2,b4b71e81,6a1a533b,49c0d00f,7503770b,fcbd57d,bae748fc,809d21f0,8ea38d4c,8a288063,a7e2e8e4) +,S(e4d6e0b1,3b4804cc,cfb7dbf,ef1b7026,320ba2e0,c4fc98cb,f12fad65,8a0394d9,aeb0eaac,73a006fe,6a75ad20,3e0ce2fb,af5fc3dd,81865b6c,75075d36,3b761a41) +,S(488a4141,507ce5ea,cb3e1c46,ad23fb3,1a9aa058,2b553459,d885116e,19fe1a04,6bd6a066,43ef8c7,4cdeaf25,ead63b04,e82f8073,a5fd904f,d7235f4,cf12bd12) +,S(c0ffe24d,ed0ca54d,1ad1c2ff,d2dfbac3,2cb65b47,ca42e8c5,5d2c15d9,67babaa1,d15cc63e,29c54df2,19dbbba8,8df7011f,a0a330e1,6756567d,bbd7c6bd,7e7e9289) +,S(336d9b02,6c74e25,9dedd36d,d8fc5ef1,31b05d0f,f20bffb2,8305b923,767780b1,4aedacfc,9886a707,aebe6510,e1bdb89f,2b1b6461,1471fd1,b055e7f5,414e647b) +,S(98353eb9,8973a7be,3bbd3711,dc7b86e5,9a2a175a,ce8464a7,6aece2d,2dcf04f,a877fac2,27894a43,8f610887,305e1c12,8e45b4a4,3d6c596d,9807461f,aaee767e) +,S(cdc35e1c,17fff9df,63639cec,b54fcb0a,71c9fb77,c38eb905,3f37c361,36da1e61,a8ccb6ba,fe917260,df64f0cc,dc14a31c,87ae559d,7d629778,2bb9b668,9494eace) +,S(912cb1c1,5e62a0b2,71458409,39c06f15,5d7407ec,526ccb5b,5159a934,80111941,584c14d5,1723c447,cd0cecc8,6c70dda6,6fa710b9,8348f5ad,bf4bd587,37049bf6) +,S(2145e17c,7c1e8acd,99eec6e2,cff40341,ffd19568,9800d02b,5ddce693,c3bff3bc,3b8a71a2,40c0b373,95b0e9b8,99da7bac,a5c43088,afafeb68,957bff4f,7636356f) +,S(e4a09336,7e877272,2224f7e1,d03cdc85,43e0910a,20bfc4ab,3aa2ea94,8d0b1692,24b1ec31,33146f03,8eeb8315,afa6e34e,898f48dc,af7d0f80,328155f7,c2cf846e) +,S(fdf526dd,464d459b,b7f387ed,46402875,2b1390d8,4006ebb0,f579b36c,d328db40,4396e6c5,679216d1,dd2cf776,61264ec5,9373269a,a745c963,14147c0d,e53a3987) +,S(6c85c16,b3e37273,509933eb,caddf3f6,52ca4c49,4e751da4,fab5bfb4,ec729f86,9b530fc8,520b807e,5e649040,c5de9929,e592ce99,1b9f9cf1,21766f16,eb648d6f) +,S(4fbfae3c,596ee2c0,10c98ce4,bde00cfb,4e7da2,25583203,feb0c791,2ce28e58,fecf0504,ed0e364b,95edcfdc,ff50fd62,396b8a65,83bc1799,3e73557e,da6ff099) +,S(9bcc3b7b,80171179,3b683c2b,90e9c811,97c1d7bb,d3c281fa,1503513e,778bab8,da2eac92,878289d1,a77825ab,9859baa3,a887f009,d7d8be9f,3b70b917,41bc0b43) +,S(4415a040,e70a3b3,f5a95695,672d1314,855b0a26,3b5e3c8a,24e02f9,6b635150,d8a53b8f,cf55a9f8,81e92160,39afd5c5,6843ac56,39f3223e,c58a5869,da3986be) +,S(55e759c9,cdafbcf6,a38988fc,be203839,b617b536,2d537092,4d2084b7,45b2341,4a6933ea,ca8a3405,89952483,4a231585,3c1191b7,42eb95d6,cf7f82af,f931bb95) +,S(21021f25,bee23c2f,a57e072,bdc83e09,8d115358,adbde4b9,5ed63488,5540e9c8,9aef5691,a7700eff,7c42c98f,8dc822a3,4ed8dc1c,7f8648d4,ba5bfe3c,f9a8c9f0) +,S(2b4e311d,dded1aff,edff3c64,10d40b8a,c70771ef,6904e4a7,a28c7982,cdb376d1,145c30f5,6b255b07,fe43d02,b57f5b96,48b25dd3,6c792575,d20ac730,d709b05c) +,S(5190b21c,7e166100,c90dbf5b,e05d25b6,5ed91caf,904b091e,8b98b5f4,5d5378b3,b83cce47,1fbdc5f8,b50e3f26,8be0d540,1826d26c,216c1166,4040b4a,66650073) +,S(2b211ee4,54c65c0b,3647c7b2,87608189,88b1b009,77d016ae,1f2f4030,545b56f7,75743959,17d8fc1d,571a2563,47a61288,fff74669,b863f506,f9b70ddd,76854f5c) +,S(cb30b792,b41e0aee,3478ec37,ff6ba66f,a3caad4f,9418e1b6,d4af94ae,e64134d4,45571ade,cb3a9f4b,922b8b4e,c0d1c728,9142300d,daeb08e7,71b1aab6,228358c5) +,S(f4e437a8,d2fcaa16,e9749d07,89be67b,e4687952,7eea12e0,65c3cd32,4e4bc6c,fb52d28b,7e81ae8a,30de51f8,bdd0ee28,8e7647fc,392249c4,3449e62a,77ba97c4) +,S(a0a676a7,6a2a19b3,bc6a726c,193d9df8,ce85a94b,cb678080,545c53cd,df50d518,647fe8c6,b1b7bd21,b9816e5,aae40700,41198d68,a3c9bfe8,e437fc88,8f190a71) +,S(15dd4fea,d7f39428,b10544ab,1eaeeee6,75a2ba5d,15d8971c,7860a5bb,b7ff7b7e,89955ddd,5fab2154,7d231342,7b7322d2,53924d1f,1b1fa961,8442c471,9c38445c) +,S(a806b800,40294b47,6377a188,ed74dd9f,1bdea3f,f72cd2b8,850f6321,930ca522,4b6d7365,47d8b1af,697f1fa8,8ab3bb86,53e49aac,618910db,9c6bedc8,deb97213) +,S(41e3723d,ca086487,7a36ff9f,6e431ee8,58a983ac,f3c0406d,f31ba3f5,5b9f148b,8ab166ca,f27c58d0,1a80b136,dcda9fd2,2753c52c,dffca007,9139481d,3b8392e4) +,S(63b8a0f2,78558c89,d9ba3e58,70946615,690e0447,f8d4c953,ea00bca8,65bba3c4,321fad41,85eb8b49,53a95da0,f004c80,8c09b297,728b3a0c,2d300b32,43cf787f) +,S(62beb7f,aa8b0d3a,505cae5f,82229a61,c1ca21da,d2ff856c,8942a9a9,b14c5963,e3d9ccbd,7120c27f,5cd88655,3efdc43,a36f4c02,2f5b7045,1ac9d7bf,56bffd4b) +,S(b75a180a,f524b89e,be5d79a9,92f0313,bc133fcf,3cb2d99a,c65f2c48,1bd20427,e7855056,b11cc054,d37094b4,1e62dfb3,6a636964,633eed48,c39b8225,4a1d2747) +,S(4e5bbf6d,5298fc76,97ddf9cb,e4d063a2,6b51f93c,eef032f2,f03eed04,fe4949e9,66702686,40cd9dc6,54514a19,ecd80930,1871fbbe,99254119,476e44e3,16a12188) +,S(a9778c3d,f509f069,3baedb83,6d5fc1aa,b78e86e6,dcb61200,74bf6df,c173237,33a9c991,86a0f913,95fa0e50,d0a85d65,9230a41c,8c0be5d6,90ee013f,29d0cab7) +,S(f1b3aaad,16664be7,c49790bc,1a4936ac,757fb3e7,26ccbc95,cdb7bb63,cf570449,d1dfe1cb,ea3fdc10,3f218398,14626782,643426,24d3aa3a,52b0fb4a,7460cc06) +,S(d66cfd3a,b015d585,6a436ad6,a4cf019d,9563a05c,af4ce2d0,6988a4c5,9349f598,5ea179b6,d097d9e5,663b7305,6db940f8,d8e91bbe,fb951756,d07cf6fa,111efc4d) +,S(a532a4f0,924b5d13,bef0f30a,a982edfd,5d87a16f,2c0d8470,ea8fe3bc,da0ac7aa,c2e62c19,ca4e3481,3cc3de70,df50386f,74fd1efa,ac6217ad,5532a927,1f8d5c1c) +,S(a9ab2512,5df78835,ffbd08c0,9e07b632,81ebb3ef,3fe2fb3e,1a3e5ff6,28439b70,58ff55db,56e015aa,9aa43698,acc35df1,f2eaadb5,4e950c7e,3501a5b5,85877514) +,S(ce058f84,90813dec,c184dc83,915c6d5,53df174a,41ed6521,f2cff46c,460466eb,414d38c4,58817414,5a815a7,84f4f71a,28237741,97b37d47,c7646b2f,8af3e745) +,S(991fab65,30a2b36a,ab385c7f,31644de9,afe9253,9db603d4,737beaa9,6e406299,2a29b576,77c544bd,f156dc9d,44da01f4,5d373cfb,7ada94df,4f82af9f,e48eed57) +,S(ee6cc81f,bd034eef,cc841921,5ab4817,ddfdd2fe,a13f1e14,e91c3f2,af715d8e,b8f79ffe,48c3e965,21c7358d,ea5cbc04,df8fd847,a97bca3f,6893af3b,e386d8be) +,S(66a2d372,d6426657,5544d5cc,5141e003,16ff2dfe,813357a3,c5daccda,159c5ef2,b57d2d6b,91c6f48d,389423b9,af265e04,780000d0,598229a0,5bada3f7,4dbc8929) +,S(20a02dd9,f697de3a,15043e73,fc7f36a3,7a5798e5,acb4cac6,adf5c692,3a421da9,1e6cf100,d162361e,aa6ab61e,711e3dca,ab4ab538,2fcc6b97,33836c30,cdcf34f7) +,S(a0b8ca43,7818e81f,6be98b15,4da25331,9f92b79a,1ceda110,92e3a303,cb7bf552,4541bceb,f447d990,50663ca1,10fce2da,218508e6,48b630ba,a1abfe5a,3d543be6) +,S(51714ead,73dce488,7e15c25f,b5cba9cd,e0d5018d,db5b8ffb,9e4174eb,1cc52c63,47b794a0,82ef561e,bee272c7,d66dd201,a5c24831,99977097,73b9141f,9bdafebf) +,S(18ea2763,1fe4de07,3e7c41f6,a9921e91,7da195a4,13417a2f,ba74ac2c,d6451c59,398a0b37,fff6bba9,b33e0428,e8d7c93c,d31b3b83,2e955e6b,106aed50,d64df316) +,S(e1d58b4f,c39e1834,a61ec341,acfa985f,c3d1f0a5,9d75b0cd,e8b9057,17c5a87e,1b62ee02,15fdfdec,8fe2ab3,bb7f99e5,af82153a,dd9c7f2,cf299225,9c6b3c47) +,S(39793917,30d3c125,7dff5ba8,eb253dc3,2c19c541,11caf9a3,bbdec3e7,716c5a84,d6a1fb50,189f36d9,912cded5,c851da8c,be7b4ebd,41c2a1e3,f78aa4a7,f5f18015) +,S(49b49e4b,601b406d,381dbf88,8b02519e,1d57360b,24f2aef1,5520f17a,5b9ede88,fcf3ccca,2f2d7b3,59be7be1,9e45a3,a0a76e9c,d0e42fad,bff7e772,f969a38d) +,S(2cd8190d,b42f36d,20d88548,f0ff17a1,d64e38a1,2241e4c3,2bfdaa45,28bdc871,f729c369,22141490,5aa84f45,e5abfeae,2fff780d,2b16aa67,77ef59b,68259187) +,S(1fd0fb11,17385466,2da0cb2c,f1f9d19a,b5b642ea,45d1c6f2,30808626,5e41025a,3136a688,fec60820,abc7825d,1c7012da,94e928d6,dbb6c08f,5579181e,469ce0e9) +,S(f08e5f3b,d7f8b5be,18648a0f,5bd844e5,3f93d5bb,120d3871,7de4440,7af3a141,3dd8725,9067eae1,cab61bdf,cc94ea0d,bf7ea1bc,df1d289f,a526e15f,d9902fac) +,S(a0033c06,b997fa96,373a046b,b5c6bdd7,a0584cf0,1feec5a5,d3f5cab1,1c5ee207,eed61931,aacbe48d,708c2cda,2208d40c,39a577b6,3d4ffa17,d140a8db,c3e268b4) +,S(77deec08,68bea671,df01e29b,117791a7,83ff8f70,4426bb1e,1ea91b6e,62c16f70,b908a228,ba8f73f6,3271ae7e,f19f5e9c,fcc1fe27,c0a224b5,dc426b00,5664861d) +,S(2fcded5f,fe2f10ed,1a1bd1fc,63506b3d,994a03c1,c188d960,5fd5aa1b,a9aa72b1,155bebf6,f09a86f1,d20d7c12,e12a0c66,b4df6628,4ff9d45d,3fab7d76,6bbefc6) +,S(1f0c0b2d,fdf5e733,abcadd0c,9ba47c09,8667f8ff,77c2a904,c8310e20,995db3ad,bd711bcb,84cef55f,5139b761,33268489,70f63182,85ccbe44,8efd7566,577bc566) +,S(b4a8544,e7162c44,60dbdf3c,5edf654f,d603fded,4aa885ef,465ea8f9,a37dcf8,53c04391,b3f2e8b2,32e27b,2292cb38,99f8ee6e,dbe1934c,13938a3d,203c62b2) +,S(df0ebe82,dcdeb735,38f31cdf,ad307397,d00a900c,6d94221a,9d85b0b7,2c5bd68c,c3299639,e7fe2e55,447b869e,3a4acf8b,4a1d07e2,d70701c6,8a2f4733,88decfb2) +,S(eb04b9b6,d1c38c33,e1eed101,fd28f89e,f9fd460e,5b379576,ec7c9267,3c101c0,4f26d849,7f47f80b,2b13cab5,782d6e9c,f5ee7548,3974a4eb,8d8f28,f5e0ee9e) +,S(7bc9efe2,197cc6ce,ac94b37a,cab9865,7db4ee0e,ea7b9cfa,ce9f71d0,d3294334,d931bcad,52347906,a941d940,4b5b3a51,ad8fb493,1c15c9a3,7ff782da,5da72013) +,S(8922d1e8,f4bd52c6,4bd0c10c,66a3e8b5,1321dc50,cc964844,e0a41ad3,b73e0b9b,2b643cf1,7d23e21e,890e6abd,3337dc52,61c9eec6,d5edc318,2a02a7a3,4a41c431) +,S(42f2ede3,3a9312ed,22f6a842,ac46801f,139a7da,77ca0e9a,cdc19d1a,f2ddcc72,50d45bcc,715c985c,b9260edf,fdc8e342,ab95360a,6bf4776a,c70e3497,8f26f99b) +,S(7bdc9720,1862feb2,58879255,726b5e4,627549f2,92936ea2,f3b27051,4d6761c6,700eb72b,7f77adf5,76e6f0bf,f8406660,65372ee4,cad6269,f1ca8541,2da4fa8c) +,S(b9b527a6,4bf549bf,5e42e0d8,5228e1a1,f79d1647,d2102306,6b6d98e1,746314cf,8e1b3464,2a721f5b,93a2a2b6,802f30ea,e35b1539,c6d84eb7,499299aa,aa0cd93f) +,S(b65de529,34d47765,1c29192,93ce1177,d187c431,590d2d74,978ac258,75e3dda9,3d6fcbe7,4ab9b5ce,b3dc5535,13036457,f0755509,ecbd94ef,324e36d6,3b9fa529) +,S(18eab632,608751e,af3604f6,a3f05611,a036edea,3405aca5,c2e66366,ce7c6b9b,89eb07bc,94671119,36e11f05,79f91e6e,ccd42605,24bd7dd9,9d12b365,95074c5) +,S(a2611066,4a479643,909a1606,596d39db,c7502ee4,a31b40a1,4eb1c60e,ead360d5,4b45d74d,88025576,3262d9fe,38198218,85721a81,f323cac0,3e87f372,75814901) +,S(789454b1,2c108537,a019dc58,35cf25c9,c77ac0fa,f6001959,5da9435d,3c08a8a7,6bee870f,ed2859fa,cbef4337,8a0bd760,8841da03,252687a2,591ae0bf,a5829041) +,S(1977c206,fb4f65f0,11b683b9,c2e0df95,f81570f9,9f6625ed,7cfe25d4,62791569,de76dda3,c22244aa,95ff435e,5a9ebe05,9dcc79b2,75d91de4,67de435e,bf698479) +,S(891f0df7,d259d536,40fe6086,1ac34d7d,ec3b5ad4,c3f56585,189ac986,65f4222f,cc5e0bf7,f538a2a,1ee7a601,1a8d6b0e,5c3293ab,404257d,ba90ace9,1b2de219) +,S(8534bbf6,9262f81e,5926c282,f412b4d3,50169de0,3c5c5e55,c80a937f,fe99530b,fbeee581,e0bb0737,4cc764c0,be5451e8,f70cfc23,4d415cf9,fb08e7eb,557423b5) +,S(e5b6f564,4e7dfd3,7474eafa,354598d5,58fc897c,f010198,9e44b07e,a86f63fb,4368bbfa,68a83a8b,76de7d98,38880780,8e153cc9,b380ad0,b2c6ce26,6118da79) +,S(f9591a8b,11c3e514,983dc5e5,507247a8,46e184f3,b4e38e29,f7c90d4e,6c2b850,423b6436,2361f587,cca4e288,a366a1fa,957de393,f29ff2a5,1fe97a0a,d90ff6b5) +,S(3d3239d3,252f5e9e,ef9eb617,c9646379,7c995059,57bc7821,2f2920b1,ff72384c,1c3e37b6,fc9bafac,e52798bf,695eb4df,ef860ee1,a9b67df7,8f73ca9f,22a2e57a) +,S(f4089723,4b574d76,86a8e855,408612a2,a0a6ce61,c1f14055,201d5c67,bcc5dfb8,6b8283b7,3e72fc91,54aaac24,2565a79f,c3a62fa7,602ffaf3,c7453209,c0a56a4) +,S(ace076e7,aea9c745,f6be65f8,498b8b47,95058ed2,b0413c64,bc4b462a,2e267ccf,b62c617,377fa9e5,eb72ed6d,caf353e2,dc58f362,a994520a,31f1dac1,168b97aa) +,S(70ccbba7,408c6069,3230b848,eadb1d1d,b4e63f33,b4fdf6af,29d6fc2d,86ec161,fc1cd9a0,46d30e60,e4128677,654a80ca,5a4ff338,71fbeec4,d7782c7b,a14d6959) +,S(e6e7a8b2,7c0c5b0c,5ea58d3a,4af5abc5,9e33fcb3,9970aede,7a8de629,e758d372,d40d11c4,c8c8b5a5,d511fee2,793e2c80,b40df3a5,c98bd704,9a8db3e5,c98d4a66) +,S(cdc495c7,e0a02e68,329495b7,19e2c424,7910e9a5,cff6739,117b1d32,23216346,63664f6e,9306c0ac,f29ddcd8,7f1df6ec,d51fc68c,6ce422f0,559205b1,681583d4) +,S(2784e89c,2fd721e0,22ba33,3b824dc1,d0142f19,6f35ae4f,825975d0,7a2fc5cc,ba58a66,bdfa661d,354232b9,b25628f4,5a391e44,f00841db,4a335ef5,dc3b8cf4) +,S(ab699b62,ebcb7380,2141dd83,184ba3cf,c9118bf,f6af4d0b,9b98ecde,b01a2390,5e548210,b71420f6,c5d42547,da0a7ccd,2be0117b,79847e71,a609044a,34766905) +,S(781ea7a5,67ffe37f,b9fad6d3,96dd1eaa,2209552a,9835ae08,dda3d4f0,b75756ec,3c76d87b,46f63b97,e4d48174,4ba664cc,403a507,dacdf4b2,af9505a0,f2637256) +,S(75ab2d30,dd5c0a82,a5c04fe7,b8fee5a3,a0e1ce3b,e20b33fd,39d0bd3e,e374029c,aaf46147,fdb1393a,cb9f6f8e,694c1cf7,30536efa,b5ef921a,72215fcd,61914b9f) +,S(294b6698,37303da9,6d23caea,684ad56d,8712433,d11c7ced,85a10cf8,8ddaff0,af4d7ef7,feb73e9e,a9407fa8,b38bf1f1,e5861bfc,82f9cb42,22fa64f7,9b46f7c1) +,S(d8676aea,7433639f,c9683b06,bd97011c,f290f6e9,1257ee55,ea3c6e34,b824c8d6,710c8876,35d45545,90f3e5c,d6aac133,9017b2a,de71e30f,d71a5b71,97a7456d) +,S(5e4eca03,d90f5ac,2ac4771c,6d86a458,cee71427,a93b7544,fd8bee74,161270d0,44fe0143,b970f8bf,affa6d60,33628894,a93bb4a4,f48cbb9f,f0caf0b7,40c97351) +,S(90152daa,244fba85,fe708f21,29b55485,265c3a3d,dbc761dc,157f125b,8580097e,1694d2c9,200b8690,b59fa3b2,8fc2f613,8a6d392c,48357939,b9435739,83ef2cf7) +,S(67dd54f0,96f171c4,53fa953f,acbf2b9c,daf3a199,732ee0f1,91fb3c90,8c5637b5,5327db43,2d33676d,b6502236,5a338c62,5fd6c4a4,536645df,b36279bc,4ede74b1) +,S(c6496a83,8f95ff57,65a0f144,774cf543,2e770457,55efc790,142df95f,bb6c51ef,cc0041d6,604d1d73,92d86f01,d8b05b53,1177b51e,3a38b8ca,ca8267fc,bcd752a2) +,S(e799d70a,b163bfd,475e5e72,8810d9d2,425bf4b6,9461e9ad,933fdb6f,68c11c74,fc34745f,e29bee3f,9b0adcf7,618c6d13,e504449d,1a272b21,5ef9fc18,14ba8600) +,S(6d3c97b0,151a9011,5032aa22,1183d82e,820c8774,c3dcd75a,cb6f45ac,5d489d3b,5aa8bd01,3d15d77b,8f695d43,8cedd9ee,64b57df9,ee672323,1c2cd5b1,4ad4749f) +,S(86e53e00,1c1e7de7,419cf2d9,a4c6a39b,b96d8ec3,a82f8165,45658eff,a517539,f8b1b70,f2efecc0,cedda525,40663114,c24491ac,266df520,ce475f01,ab44ad86) +,S(a641c339,ac877cce,a9a3267a,78edb33f,75feb90,1f3c8743,47c50843,52a9880a,d88a6d4f,2b275ac5,3c7dc101,b7d69ca5,407559c6,afdc9009,c34a7256,f982163) +,S(3a0153a9,4d778266,4581de43,6de31754,b925aad5,4090cceb,9e013568,9d82511a,f6ca48,94935c5a,7a252df3,8ff06cf9,11154b0d,9f0ac55e,35a33d7a,58802035) +,S(e78024e8,a131c9ad,40526b31,d26e96f4,2c2e51d7,c63f458c,5bec2a61,472b170f,c540a14b,1ad7b18f,23493d9c,edab65dd,3a309204,976408ea,f197f658,9f4e0c53) +,S(7858c85e,8351f0ec,740380fa,b1924668,7f05a161,e2dd87cc,7df13338,a86a5162,cad94344,5313a06f,c382897e,7c444d53,7e658e06,5a76fa60,928d7e5b,36a6de1c) +,S(6643e28,1c5bddd4,35a68c17,965f334,ddb9da8a,d599a4b8,2f37147a,cb0263e6,9f9f9e36,8ee1aa0b,9bc8f928,284968d5,6f2dc8fa,6944ff36,d728b588,a72cf79b) +,S(5f36d937,a286f14c,96fe8f9e,3ea05d56,b3132523,e9a135e7,106592d6,b9b2254b,9d6377c,c8265ff2,dcebf753,ef2fd39e,9adb0e1c,3c86acfc,2e54648b,9056310a) +,S(212eb1ae,93d3a0aa,5f626f26,628503c2,310f9172,461ea12f,b17677eb,c63e2224,51e57e33,347f2016,c738d9fd,cf528269,bbc5afe,f5fd6fa5,1dfcfd47,4b6d1b67) +,S(526952c8,940b9f93,32848145,203ce261,dedb3b93,8e6f277e,9a085d77,35e9eab4,8657cfa3,56df2aaf,9a5fe2fd,81804ff8,1d9aa58f,143fa109,52e4f4cd,85a42918) +,S(20f1750d,ef762812,e4ba8778,c953a2d1,419e03c,b97ab6ef,8f98be07,4c1c099f,d2fee9f5,3e7ad2a7,fb20bf88,16a1ec2d,d9d97b4e,5abc060e,bd8e8b31,bacd485e) +,S(e231a3b7,ea011665,c223cfb2,7f13c691,dbc7f5e5,efb66496,da2936dc,d67ee910,aa645c2e,18e80131,f3e7316c,7cdf13c3,45e4f602,fb17011e,96eb5fc0,bf65d53f) +,S(7a4e4d52,3fd026dd,3daeac35,552e7299,d01aa962,687a02cb,ed7174b6,25c702ad,351c12b6,a7398e5a,ae461204,4cd7c9a4,7d2bdfc1,1f941b84,71eb3304,fdb965d2) +,S(fd2f707e,76965670,67ca5a5c,a0010c6f,9a858967,19a23eaa,5574d1c6,cbf137b3,c45a430c,1d5ae473,31f9b161,3ce55f41,df00e287,9e3bf8aa,1ae75306,f8315408) +,S(c506cc1e,8cf2f4fc,e1011d67,6d304877,6c2ac2a4,f8265373,f3f918d3,f02bb89d,8de6dfb3,74029b33,2fa47f6d,1f7ba609,bea33d6e,2f58ef0c,58641e2,a5d3118a) +,S(2ea7ad02,d9ccf999,86ab901c,3c9cde3c,ad1bb4d7,d8f86eeb,b8204b75,ab5c0369,11222bd8,6d750302,763648dd,daf76947,2b213562,494ebd9c,e4003195,eb0ed43) +,S(ab8cc192,3555e4e5,2f84b421,ba2ac134,f8a6023a,ddfd279c,4c338cd1,9e159c5c,2c48e3bd,cc268dbc,23e9fbda,6c449079,5a5b54eb,54ca8ff5,14d1f23f,8751ee1a) +,S(88fec2e1,cc7c41fa,91b48e1c,2a71089a,c3778427,f2cfce04,c54af407,f5dad430,ccb45e88,4f696653,5fac7a04,9b035c26,dce30666,fb1fecf3,c4b89deb,8b3ed80b) +,S(404587ae,1accf5d1,b42c3127,2ea0cdce,940522a1,c64c757c,11d3768,774b0d41,e8dcf25b,25ae61f4,f7368c36,9b351b35,63401deb,5ce55325,f96a393f,ef0e787b) +,S(8a701eb9,cadea8c0,8d0cf20a,b2750915,28a377cf,bc4d9097,51424d1a,7eb9ab8a,4f045982,82a9ac70,c3c76154,ca98b5a1,265e8b26,6f02d43a,4549cdea,caba5a45) +,S(c2812978,194009c2,9da141fd,b108a4c3,66e15e06,c6d64389,29b2aa78,89ad3d56,85409efb,6670e969,a2834255,dcb1e546,9c9db5e7,6e549afa,974936c8,b75db5c1) +,S(9ffd36b1,c810c843,92bb04d1,90b82be0,f8ea4b4,2baa6129,8adfb810,71d72fe,11e27a4b,a11f0df8,1a42955e,bfa9fe1a,6f25fda4,6a65fd87,1caa3d6a,1b38404) +,S(ac4a0044,bc92b017,cad07210,750eec62,39e43147,5e3feb25,f1c6f879,a5a48b96,41c7c3ba,731002ff,1e749853,344c1f53,f526bbbf,457b4de2,d5f88ce4,1eb8dfe1) +,S(c78b101c,157ca920,b3fc83bf,9d19fc5f,57d8086c,d764e142,24ae4e86,7b06eb5a,1a8d2c6e,b9d660ff,faf5f533,b4f3b8f6,b7a9d7cd,5c29c1d2,deb37f19,d38126c8) +,S(d08f3b05,572348b9,5f3c1c2d,baedd921,c24b0db8,e6d17d13,578e5ae8,77147cd2,27b5fcde,a067cbb,69ae3e5c,90a38523,4987dfaf,5dfe0696,91461e26,762713cb) +,S(40ea043d,5060f61e,b81db0f1,c7c5c1fc,1091cf51,c5808489,3d08c4b2,a5e312f5,2ef11ec4,2836302f,e02719be,259f1536,43de03e,fb659f30,84816a00,1d66b27c) +,S(f9d104bd,fb53b4b2,de8827b2,8242eba5,17db73f9,dbb1eec3,9f184ad0,358362e7,d7644a0b,6c371948,2ba707b6,d7d43f0a,68f4e3c1,4af6f167,296ccfcf,4d771877) +,S(dd276aee,14c34829,4e6132b4,9a05dac,fea5f8a2,41712b6e,5703778d,eff9ddc9,9be617d,5d92eec9,7fede655,39690d0f,4803f760,2b74066b,7bc98353,a5ceb7ef) +,S(8522f839,d5f17bd0,c67d11f6,7f0db8db,2104c7d7,785252f4,c8be84f0,61155d49,b7791951,80311f8f,6cb9b59c,ddca495a,e01f3edd,599f8777,3163a959,5a3ea117) +,S(732802bd,b4f3be8e,fc02a62,4614672a,51049166,4bfce64e,eb2030d8,b6b5b225,7bd4cdec,590eee1d,6a505f92,cc0b25ce,d9022d62,d1155f8e,35a6ab72,46a3c6f3) +,S(1b3641a1,2c4f8352,21e73276,b8bdea15,f5ffcbaf,c4496fc6,8fbdb573,5967af62,3d50ef5,e5d12b7b,2ede2e15,3b4cd01c,b824c32,7a8e1ce,f0fd866d,99664048) +,S(d3034e18,4e9284ff,ed6cbe60,cb66d391,c897255,dbbe8c85,2c79525d,3f01a7ce,b3666304,16ce50e7,2a094b05,85f1ba1e,11172ac4,eeb353b4,8c4f8f99,f9d09e25) +,S(8e7a8200,bd22f5ef,18fa4461,8f4f85a,61c6db2a,a3ad176d,65c3270a,69e9db17,841fe3b5,1cce979b,f87536ed,c71f4cd4,4a482475,19b35cea,dee4b3b1,f3530568) +,S(fcccb4de,29ab8671,d1aaee27,61421ae1,c4af5f3d,839009e8,5dab0b65,60a4027e,a0229f96,203b89af,d5b6ac06,9e977e71,a6e269d4,bea29c47,fa6bd22e,f7f993b) +,S(e68cfd7f,44358180,84c681f0,aead705b,9e74a476,1f99e576,9252c007,e44c8a26,add9c0a7,b027e2ae,42378d50,cf0d0eb5,71229161,8e9f13c1,672121d2,c428f82e) +,S(8b6f0fad,4b81ac16,4866de7a,c8bb3252,63bfe008,b726e9a8,72e0461,2c6891d8,9bad6508,a8d604b7,8088d328,ca27fe13,91493e8f,a6291288,92ecaed,ba4bc9ca) +,S(108a0caa,37ac1949,263178cf,20674616,470f8943,57a921ba,8cfd499b,d64b78b1,68150d22,be05956f,5ffe302e,1ff517c7,9b7c0452,6112b2a7,5a819f64,a265bf55) +,S(fed18333,844c579,1d32daa8,3370a5c6,ab8e13a5,2654a08b,42940284,c757edb6,67bddf37,8395ab84,eba29a97,6952ea34,b1b52c2e,d3f89e56,f839c1ff,36457fe5) +,S(bebfb39d,ecd56cf3,50bed6f1,a4cde24,848b2d84,23518da5,1fb2ee0,90170a2f,1302b4b3,bb86f887,22925fbd,e146d948,5acb2db,a61e751,97dd40ca,2ba11573) +,S(67135aed,2a58d3b6,c4470d3c,b4da7b56,af8d5057,9d28a86c,9c67bf28,181e716c,97c40aab,2786e3ef,dc8f3e77,8f374446,30fa2f3f,53eb040,194809c,8efd6664) +,S(b00eb5bb,9566e5a,cdb09dd4,14d6df03,c3dea75e,90db8b9,c37928e5,4354f90e,6d120e41,1cb6e674,e9973aa6,3999af3a,ccc3a670,112c964d,8aef93ee,e69b1258) +,S(721b1a6c,be8d2022,f09db6d3,ba39b2d9,23337592,de9efbb8,ecdf3384,f3bb73a2,cdb41b62,631a0f47,75ae1f2,e94f8075,4acbb2e7,950be088,5b458c8e,4a05310f) +,S(cb8d78ac,15b12ca,8dd47cde,190c420e,42f60b83,9489bf71,d10a3e44,df8a0837,80be31a6,a3073675,e8cd3846,cfb2e127,abdc448b,1081a2d5,d177ccff,ea96dbc2) +,S(491cfbcc,4919d884,d23f3ae6,6d143e55,37e5c52b,e2ee017a,afec785,6c781920,76321b50,26283088,d344d29c,c4d9f2ec,3ba714d4,edc1bee6,2b17ecc4,56874189) +,S(6ca33ee,48992263,23aed33f,f822303b,8145d146,c5ebc27c,fb3700b3,6ab507b4,96b73ab3,f189d064,1e0a20cf,d09522bf,8c376a0a,9c9dbec6,44e3e8d2,c0b11f4e) +,S(6d1fdfcb,3c48971b,6cbb33d3,822cfa68,1bf602ef,98160f89,97ccaba8,19d842c7,82bc7c4,66088262,5e57c062,96f04600,fa555ac4,5596b769,9c6d29c,cfb1713f) +,S(a3e81699,1cf92f41,a69ac3ca,36b23796,daeb533c,3e1e9b55,c88e3fa9,fea43554,87a6fa9b,e802467a,fa206b0b,45405309,65887df5,786d20fa,25e94832,312855f1) +,S(fc84abd7,cbfbc329,4eac7438,d50b2ac4,7f570e4f,3f2ffab5,71f8c3e8,7dd49c70,7447b269,71356b0,e59b3f1c,d99b6416,589f6c3b,a566c75b,6915377d,a7f73dd9) +,S(beb23240,8fc515ba,180d3125,2eca15a1,af4e02a8,73a69769,53982408,355d1b1,12fa480d,6fa8a9aa,e5edeba9,31b765b0,e2bbe6a1,5eb9e95,b3bc343f,519c1459) +,S(68891679,cffad7f3,19a373d7,1bc02529,a50e63b,60434f13,df760364,1a99eb8e,40b78db7,6db28aa2,d2ea7c1e,86d01503,7736ce96,2e6ec524,da07b5b7,68772fb8) +,S(ec435ad,1ae7b040,fde2f736,e8fb5d53,b42e2fcd,428e9d96,ed401ee2,bb068817,13bf6eaa,1283436f,4a828a85,66c4f795,26860c45,d650fac2,44bbec8e,fc96f9f2) +,S(679f5afa,661f688b,7dfb7ce7,f77e4904,60a75576,6216a49f,374594d0,6bde3033,ff3fffd9,6c254fda,558f14bf,c8f05cb6,c8fddd32,a487d709,4e0fb35c,6f617ca1) +,S(9febd8ea,5dc26e5,fbf48aeb,64307b21,1aa2fc02,eceb6d68,ba89a652,f633be60,c0867bc8,ea6238a4,ad36e785,cbbc5e0f,3fc5dc96,2c778992,72be4364,8e630bee) +,S(d886b154,c534b48e,db6bed69,6dd8f9f1,347b381,1b593acf,e2137c93,600b1601,a4cbc118,aa07daa9,c4e246c8,efeaa3f7,d74028c1,93b77964,f10ab5d6,f75d077) +,S(af8ccbef,c187a3a6,83f6ab6,8ff217a1,96a8e27,dcec349a,b7ee4a74,446e9d47,3ee327c,99880392,7da5b625,be554e6f,1662a733,25a8fdc4,990716cf,6be941f0) +,S(1e9800e7,891c261c,a3451d22,44a54a84,42d33458,a997b365,4a6198bc,7dd3d26a,322f8986,bd6ffc0d,d5f1a321,e82e6b37,978120c9,66f753bd,5669a773,65a215d4) +,S(115c62f2,9f008009,5840dc97,f3a90f30,aae4ffa6,a2d255e4,15d64c56,77150044,4d944c12,7e37ce5e,fd7660e0,1e4fdf0a,cceef95e,8bc2da14,a8fd7e32,ead8af95) +,S(1cb9f9d,acbf79dd,b34d78e8,e51225bf,3f53135f,f4282ba2,59855968,2ae0178c,8fd3a4e3,7a189bc9,421595e2,bcf234e,d7b602d0,855de84a,50c68cb4,bd1a4bf5) +,S(62a15bc4,63e4c167,4bab2a5b,dc991e39,af86d258,f9de770b,66a79ee5,2fbfe357,b78fca9f,d9467e4d,256da69f,e6f45522,d376fe41,e8ebde9f,9f7bde4b,8ef52749) +,S(574a6ce0,5bf31948,31570914,a73bed4e,6bd2c82a,5a19dec4,54b11e93,5edf505e,e7b2e2cc,cbd6f338,f0ea60b8,c1a9a50e,d02dbaba,8bb5cb78,9b281a97,5c001318) +,S(64c6e37c,a3a361a4,baf9ceda,d9ed24fd,c5ae50ab,560e6319,4adad1d5,264084e6,e6e42f56,56b6b404,9c54a07,f35ae004,4b7a480e,8271c8d3,f7996ed6,68116067) +,S(49065a97,fe4a8de5,55646af8,475607a7,71b27746,ade7fb11,55308107,4900fd84,985d689f,67a03090,9ab8eb43,c7b2767c,94e7217b,fbb43342,83485f1a,d70ae7f9) +,S(6fd32ff9,185790bd,876a683b,7e889f32,8500c91e,7e5889aa,44394caa,330999cb,12fe8084,1be1f25d,7a93784e,9c6bf01f,efbd6493,8f1a678c,64497a8c,85d2de3b) +,S(4a67d4da,48189c8e,6ff34812,f7094851,2d6d12c4,26fdc98b,4ebb92b6,62d3b185,58ea83f2,f6e5b777,737c668e,efa71b8f,3e50095d,389a5540,684cea51,7f8150f5) +,S(ea1ac931,d3a92770,5d20752d,b9adb464,edecf4c5,95c20c85,987e1beb,a79f4db2,cf689b0e,25aa9601,58316597,b06fd91b,426b5753,68a48830,9c3f6f34,6722b83e) +,S(8cb35a6e,248a0527,d572663f,7abc99c9,61414af3,f196c6c1,2de4dbf4,dd545c5a,4b32e4e0,47dacdb6,66edfc3f,a08d500d,c43292ab,f36bea7c,4a3952e6,680cfcfa) +,S(247c800c,f150c2ea,cfef8dfb,f4581560,84318684,430788e3,c8d99ccd,d27f21c8,cc82d8dc,914fd1a0,e626462f,5829eb7e,a708395d,db3e70a7,57942e85,1f1d0db6) +,S(6543d7c4,7fb927c,fb0f3566,6103708e,5e0c4a4c,ed202482,c9f48647,33426673,e252b29a,69b4ad75,814ae0d1,631ea750,20bbc730,3fdc819c,88d8f3d4,7907ebab) +,S(c4f11255,d81c33a3,a09da4ac,af5c9c16,d5e759db,2e1026c2,9b3556b4,c388e6d0,e2e636a8,1af48ab5,814e5530,e48f518d,95379eab,186e94f2,4fcd551d,1ca8fd49) +,S(cf186a9d,85da39b7,7383d92a,14af5a05,b082848f,c9e60598,1bad8ef9,5e019eec,cabde21b,c860fe08,53f672a1,64010968,6b49f37e,61cc642,48f455bc,b079e3fc) +,S(e6c3e353,ad69dc13,e595c2c7,a88b8fd8,fe9d1d47,3d45f7f6,be9ae903,86ea8f32,7d3becc9,4f455c1d,21610800,a4985f33,96b5a920,d5ed2b57,2107c28,ac690be1) +,S(3827b3a3,9bcb554d,54695dc6,bcf22911,d1ba01f7,730d1c11,8d6a7b2e,c1060988,32413047,b7c9ee83,1b818c5e,cb8f4c10,c800a362,419227bf,d9f50aff,ca25a211) +,S(ff37cd38,a4b149a2,a8dae898,c40b0ef4,4b55ed85,11b5413e,48f5608d,cc6d24fa,5e615919,8f4c6665,7c3a489b,86853a95,f3ffded5,20433cec,a6832cac,b9c49048) +,S(bdff4fc8,5b492fae,1ef34322,9e83b751,d9e53c7c,455141de,f68d3e8a,320ce509,e8fd9864,9dcc5d66,6155088a,29959e12,531f8a4e,44d70b8a,43b4fde0,8bde3d20) +,S(fd6ba29c,313ff2d5,7fb2719d,9018f11e,e59d1007,24146aef,625a9b3c,3bbcd0af,187daf5e,913310c3,39f584b,3196b877,5018dbe8,1e38abf6,de73e97d,f5c1079d) +,S(ea3c422d,48606929,ef72ae1c,3ac30178,4f4b5f78,1405fb62,1d0b710b,1b29ff28,e458b41e,c6c3e06f,c37637ee,fa316e25,d10b377c,ef99aaf2,564fef92,33bf208c) +,S(46537133,4982d600,8d228924,f0b459b8,2ba8aed,af1b3c39,f87053f,487b3978,fd96654c,13189def,f243bb29,e2143dca,3b2444da,3b895700,6bbff65a,4dadf3f0) +,S(fda493f1,1226069a,ac76227f,9f9e1051,b5b29b4a,a2d0f9dd,99637176,8578d8f5,5a33593d,f63d136d,f43a69d7,f9803a62,e04e55b5,25633a06,d8eb86c7,e1d46fa3) +,S(74fc42e9,5f09018a,5468e283,5ea36fee,7ab5e757,c57200cd,966174f,39f3e4c1,ccaa0b40,3802c914,da86204d,45f8f5d7,3760e075,4bfd10b3,2a8b2521,218751f0) +,S(98cec4a,997b79a0,cb818da,58e41477,d98f8c2,8140fbaf,e118bb1a,ec483d53,2fce6058,14945cd5,367b82fa,182c19d5,ac422d9e,840eae4,d81689ac,7eaaec08) +,S(c742ddb7,89a5cbdc,2055119f,697fd575,e4fa1540,96cc5fc1,3c2374b1,13cba60f,9b0af128,34a990e1,d402474b,e6dbaa1,b32248f4,f2b1d680,13fa0dea,46f3532d) +,S(dba2e04f,9a78066a,b5897913,6c4c7224,5b5973d8,3b13819b,77409fd1,e791eb89,34747922,3adb5f74,168240e7,a178f077,aa0e90e0,870456a8,89dfca5e,633baf43) +,S(6d4cae43,6e598586,7b984dcb,6c2472b3,6cc47f86,eb69fbf,1069c69c,42f6538d,c7fb58c9,f0c4f7ce,dd7c53c9,23efef52,125c2b67,d67f1ced,b98bb1f3,d5e0a84f) +,S(4c457f6e,d5b67b05,5b664ed4,3bae291a,9ec5b539,6fd9410f,9cc16a03,b8523982,492e5bcf,20aae19f,5462ed68,2a72827a,a435f47f,ec218e98,8e91fed5,20f344eb) +,S(4d7e6922,34778a41,f58033bf,d74ae295,51fd8ac3,64cd817,9cdd441f,cb46eb3f,756ec0b2,ff5c9d3c,3a453879,17ada4bb,6d7bbd07,bd10d2ad,c092f46,c62750c4) +,S(ac5be50,69bad479,bdbc565e,ab74ef94,4a48399c,a4af915c,fefc47e3,7d464b2,3246e3fe,bc5810b6,37722c54,69ce45d8,8bad5daa,529b4381,928b7cfa,de874345) +,S(7da88d41,21350139,bfe6a481,2534b25a,24f91e0b,60d882d1,5d69e840,da3995b2,9888ad8d,62a7a4f8,700bb03c,f9772432,6a2d092c,98adbeb5,cbc20348,f0b9c587) +,S(389ff31a,63239cd2,c9aa3eb,4d3ceb49,5d3b922b,5d137d4,e8b52be3,b1abf149,b0ec2a2f,bc840bf2,8a22ab22,b76c1485,42f54ed,5515ad49,dc3c0037,38fe7c93) +,S(c1cc1acf,5fb128b2,ea65afaa,d3d5736e,a94b2e49,8dfcf6f8,f3c27a5d,596c4370,8903584d,1986ad31,6cc6bf2d,aa2a88cc,ecfec6a9,c1bb153b,27c409e6,934fd38e) +,S(399ace52,b92768a2,a4740be8,31c96c04,2a34957,e91b3cf9,8b3518b4,87c9aa3a,908314b3,abdb3a47,a117ae09,5d609fa3,fd9af1c3,ca04a869,786eb134,48800005) +,S(69543fd,8c9d01a5,702d9859,305a52b9,470cc606,cadbc76,d8283ba9,ba06d0a2,e998e7d9,a0c372ed,2e348f17,b3298088,404eb1c3,8a901d1b,6f4e8a19,731057df) +,S(2172d54f,df9b46ef,5a1289a5,872b1c28,911e553c,f703ad6d,400b6af7,e8200100,2121b47d,3b790e5e,c820df5,772b226f,34a8fbeb,f642b5d9,edc18971,1b687a8c) +,S(f606f7e9,37a324e5,d0e6847d,24923965,cc27133a,10e43f28,6d45f7ce,9d5e8b56,70013fb8,622a21e2,d1337944,89324a13,f5b80580,91ca08d1,a30e7571,3e86e007) +,S(9f1520c2,dfceb64f,1f432013,b342af35,2f95bb2d,d49aa14e,dfcd8e71,7c40fc99,fe8fca26,feb1f004,8fa4fe3b,764a907e,d53dc0a4,10308199,6cad54d3,898e863d) +,S(6670af6e,7587676e,eb0674eb,75c93d38,53afe418,cb286605,18a9370a,231eaa08,2993ff5e,dfc071ee,97fcee9,bb12fd8,fb59fccc,524d8537,34ba4cee,4beb09f3) +,S(15c6d58b,345cc4bc,e4ca4e2f,ee954c2d,40650a4e,ad6c9524,65f59a94,b3898350,894c53b,47276196,65a0f3ad,f528d2c0,221b12aa,73df2cf3,a6b0e778,a363cf7f) +,S(bc4ab6bf,60dbde42,c9293ef1,75f85a48,adfffd20,960ea454,8a919977,75389621,fe28a0ba,24a4e2a7,45d6bb68,ecd71931,791a74,61549a44,37a34761,19040e42) +,S(5dab1c63,23fbf2f6,e495e87f,1c703ba8,64f20e50,4007dc80,54ef2e11,d3e6ee1,1fd0c200,cf4460bd,ae6db415,3e68bffb,e7f01ac1,6b30e305,9c134a86,52695d93) +,S(2df1cd57,d7357c44,7be28dbb,c339ceb,5cea0bd8,e702fbb2,dd67c189,6a8acaf2,33192011,20cbc8dd,c3b9c031,94db76f5,86eefa67,995dd741,492f425a,e2f1b9e8) +,S(2d81ac17,5a02daf0,83100585,ed2bac76,3d9f9764,15356fea,584ddef,60d9ab8d,f9908cd1,3b1785f5,78297fd4,9e6c26e4,21052e2c,ce9f51c9,cd58183c,2df9a0b7) +,S(1fac1762,fb732e73,2440d40a,5356eb17,67b1e7f4,f11e8db5,9ef90702,437dc097,edd5784c,a58d5113,2b5a08ac,e75cb30d,5ae7ce27,129f158,4df5d95a,7b9b8729) +,S(d06a0b5b,4694b90b,80c93e88,4aa9086e,45cabaf0,99b15a9c,c2b19678,38c8c98e,4cad46ba,2777b24f,cd1b391b,222ff3b1,14fcc814,5f78ada4,98620cfb,747def3) +,S(4928df27,590240f9,9907928a,cb6f0695,870059b8,cf9b1d69,29b152b1,7de53445,b773e60b,655b3b0e,7b0c400f,37dc336b,240b83cc,286a8ac5,3dba751a,3300d505) +,S(a61bcdf9,cd541811,4ba99261,7322827f,f945d450,c331ddda,1b8639ff,87a28390,3e771d6e,d6fdbb28,54601b2b,301fe24d,8e61b370,ebe644ee,b40fe807,b8d93a68) +,S(535a35b9,3e2fb7ab,b3b1228c,a7977,fb8e34c,107f093f,9f641b15,11db93c3,2471ff35,5657cc8c,38283fba,27c2e3c2,92475fb5,e8d52e96,f0c9fec9,b2ff786f) +,S(e68a652c,e0140f29,376888bb,c6be70b0,f23ad42a,d10b8acf,a5f790b4,c465d4d0,49d7390c,c368060b,3134ecb6,dad52120,ea6e0c7e,b80c94c,6cf9c1d,3c1a7385) +,S(e8939e7a,74dfccd3,ef17855c,3ea20e99,f5f05f6f,8bc4757,6b4f0e99,37e25fde,6b48a73e,ff0a55b7,c90c0fdf,449e4c2b,3773f454,da2c388b,3e0829fe,d661b173) +,S(496013ea,31451874,800fa293,a6e70ac,7fe16483,67c31daf,bfd00faf,48751543,b5715111,8790556f,8a4001cb,282b3312,581e1508,b8537f65,6142e2f1,ab8c4332) +,S(444735b0,b1efc3a9,56957a07,22604d09,bb0f6c29,e7cc5201,89ddc3c1,804b1e1f,b1ad60a3,461abab3,a9732a85,7050e55a,3e9a439f,32a5b21f,9aebe400,7e59d6e4) +,S(5805ac8,4acd7d5c,f85a40e7,4b9c98c3,e8882189,e77aa475,da3b4114,3ed9511c,c952923b,fbba533f,7bd70dcf,d8d69b7,1ad0022,aeae363,bb48134d,6a3c07c0) +,S(8ac11518,30fdc785,5e1c53a1,2b690202,c12619bd,c46c8898,dcab77ef,279a9501,29fb7cc7,7867fa0e,1d015493,abfb2000,d5deb3b8,ddb3053a,d59d6bd4,a9ca4fa4) +,S(aa47add3,e42998cb,68fc8a7c,cc7beff5,4d70226f,22f41ec6,7bd7b444,aab542d,cfa5ac81,ebefd98c,3af4f9e3,9f67459a,4f8e8c4f,c1959816,f771e75c,c43683e9) +,S(f3504127,a27a14ee,92133f75,364922b7,d3984898,e433d3e4,19e88db9,e599889a,f1af9f7e,9f9868a8,84ecdae5,47bcb886,56c6d423,a066b313,c09cdf08,601b45df) +,S(33730f44,edcbe688,35887076,69a989a6,272d3ce5,9261b98c,7c6eeeed,7e4bf08d,3f833928,d87716d0,4b2a32d8,1bd2d789,b6fd057e,cc70a794,8605cbe6,e1775a6b) +,S(3169d6dc,8c06f584,880bdf07,29249cc0,a33d417f,be137478,6e5b4a14,3edfb0d6,2a91422d,ec563839,ba782f59,68f428c8,a311600c,2fde77fc,ea163e86,aa74ce5f) +,S(d8c64582,13aae81,cf07a64d,5a8dc3eb,c8c43a45,d57f8e9,80cfccc6,f02a4429,c4873051,968863ae,8c92f195,c9fee3b2,c4773d47,849e2a7b,e7f48c4a,93822aea) +,S(ae67101f,307e246f,7a7cb039,5631b884,7e59c8d8,14da3fe1,7891f69f,402b6f11,f5f2dbb4,a90b09e8,b96767af,a9f9a357,1d3900f9,7d8222ae,e411e1c7,11ed44cb) +,S(a9e87231,83ba8338,1c0a7dc9,c81a2c5e,b4e2ff43,82574f0c,1a9d7f14,81dbd8ee,96810599,90d90e33,d69fb59b,ee68344f,333153ac,3d73a335,4b7ddd6f,96468901) +,S(616bf21c,ae7d40b,2694f43a,a33e6848,694ef879,fb5bc48d,ad141e34,e43376f2,bec18f83,2aa8a0ba,83245115,3b5a4faa,4a27725a,a3d9e799,bf05dc94,9880fc77) +,S(121e8335,601f33d4,78a882b1,1e9be5bb,39be47cf,701a695f,8d351098,af3f5c2d,2e992933,18faa04b,7d85fdfd,cbff81df,10dd070,4485b659,f682a298,4d03b3e8) +,S(bf884797,3025ca9c,9413948,fef1bc48,3a83cc28,4a909933,25c8c97b,b89f1141,1953a326,3d26d1d7,86d5ae3a,7838d125,6de24760,6abbb63f,e2713f6,6ead5386) +,S(7c28e9a6,5a3800f9,85c94d4b,ddc75cd0,dd1b06e0,faeda124,e86600a5,6af811f0,a3756db7,e339f03,8914cedb,707427b4,2d396fd6,f2e43863,13414863,8ab5c277) +,S(e5ec6dad,45e62cf4,1ccb5bf6,bb92387b,46be0791,31bc2b9c,b8b93172,90a66077,d0045ecc,775703ca,f854bea4,be3c4d21,2bacd092,7a210eda,67c33aba,e44f0e19) +,S(6fc96e1f,92039545,fb31c352,544a5974,7036263e,34d8e043,58336169,118c2fed,d032de87,1571de8d,96b0457f,84397e36,6ca7c20d,d90d089d,9aababad,8b8a9a51) +,S(89e3d351,1c219c47,42e79091,47c13146,1db684dc,e1a1149a,cf49115a,746e4133,aabd970b,672e8468,d84b53d2,303d57eb,52fde5bb,bb224b03,6892f918,630c5c90) +,S(2b7a60f0,b2136453,878eb44e,aadb8da8,c043e947,fea1de8,4ff8e18a,390d5890,c829b16,1ba032a0,59340709,1b38b365,b806686d,19026f41,ae8bbab7,d04a5244) +,S(464b9f1a,c2c2aeb7,e6f7c3df,a8782f25,bfeb9879,9263a9d4,2f872050,6c9627e7,7c260bf4,59e1bcc2,df7761db,e503875e,9a23a107,6cb4e8aa,dac5b5b5,b6f7502c) +,S(79253e30,43572295,e331519,e774b670,b25141a,986eb5ab,268b63a2,759b616f,da609d7a,55b62353,b20f5bae,969665ca,ed6467d8,f2577f69,10003586,e27f88e1) +,S(634287c,e900c0cb,5c2b1967,f55190f9,19acb09,43596773,87642d16,dd399556,a2350909,8cf01601,30c042db,253334ac,223c473e,312bf758,1fcb461a,c3debead) +,S(761121c3,8bd8fd5b,a3418557,f6a75b42,d7ef2f4b,91620223,3587f183,421bee98,4014715f,f9c17435,10e6eeb0,1bb29226,76070e34,afaed040,5c897bdb,52dd530f) +,S(2618c8c1,bfbbdf1a,59da3078,4e50a2b0,77990fe1,c2f074b3,e63dd606,6d453413,ae539a37,20f5b6ab,18ce584b,4ea3cb46,4bdaf35b,326fdab0,58169ddd,32a48da0) +,S(d429fccc,10c6f025,fc7a57e1,949308b4,d91699b5,c099820d,ab31f1db,90f685be,da2b15c1,ee155918,de414ae9,1be51688,a8df043d,6fb6c964,689bd4e,5a648edf) +,S(6a18e3c7,c04b8cab,36e07625,ba2daef5,bf1e0cf6,36650b6d,56dda8d8,e4e8b705,66291330,f56c96db,ebf9c9da,bc52541d,20e75440,25fcc49e,d6215d8b,c0e94eec) +,S(985b6846,d1c9f3fe,5482fa4a,d6a21c65,d7ca3eff,a41b3220,1a37a122,f8f97756,3e2b23dd,98e18f6b,76a2f2c3,2c543f8b,bb9dc6c0,8d391592,d56f5440,aaa3a92e) +,S(948a0ddb,4ba838a4,63eee339,5c7bcca2,96fba8e3,9654ff33,55c9296c,9e6e8c64,c5b34c25,da19d83e,b67b69b5,2e527d61,c7b705ed,2f794d2e,12c4325c,3cf5c1d8) +,S(4332d02c,1332b03f,b7a46b47,e82617b2,a437fcc,694868c4,256aa40f,a8a3de2e,e6e5196f,5f9c555d,a94327c0,39411780,393985ab,73765de1,e1bbe0dd,8aaa5289) +,S(5dc977b9,2ac1c895,f3150b68,a8d69f5a,f7e12dc5,6b211d96,a67cc3fb,722a5aa3,45888ca7,4bf1ec9e,1cbd2912,3cc696d2,83260c34,3410217d,10fd0b95,9d07844d) +,S(5b9cf534,ca94f124,a9b0cb6d,f0003924,605e3bd7,d063a2b0,c6e1a81e,3fd15764,44e98dc3,b0516ffe,bda48790,fa0b2d67,f9ba4b48,ce88bd1d,d81bcbc,897458) +,S(84353007,3a63714c,7d26baf9,c895e2de,e2feb4b0,9746ca66,97fd7ff6,d5372f59,d7373a9e,37689d44,4cb7361c,f2f3452,3f9fea7c,826c62d2,3ca3f368,b0c7a175) +,S(9cf0000e,3eef9b5c,89c8485f,c3826e78,8f1a28df,f8746619,804030fa,c21e6a61,2b3dab3a,d8684b2d,94e1fcb9,d2005c20,2764cd76,aa91e0a1,ac2612f7,fe91543c) +,S(bb292fdc,5897188e,20888b25,b491a757,8ee02853,83aff5e9,99671a24,4ce1235c,d3b6d9c3,50ba7863,bcb83990,95893348,d5e9b8f7,27e1a3a0,9e02f59a,412507e5) +,S(95d6d1d8,9835ed57,6a88a21a,9239b623,efd2bc6b,f27c5ced,2d770c90,fb7d680,c91535ad,39db65ce,fab4ac72,f3ce692,b39e7d38,c72ce468,e40bfe06,6cbaf048) +,S(cbe3f20f,a164ec20,9c2c3fb9,ca0c95,15ea3787,df2c8fd8,9ee50a3a,85d09a46,cd589754,faea165b,48e22280,4186e6ed,734a2251,a6588e8b,8252eff9,afb9a28) +,S(3e01dab9,9bab9e20,59b1c215,ba67835d,2942f4,487d6094,9f39e293,b39f604a,b41ddc32,33365044,ee350979,8679f3e8,d0a556f9,e8b6a267,bd5cb5e,8523d481) +,S(298974c0,5543dc96,15f1cfd2,e4b6331d,c798918e,15e3f350,97213a64,76afef7a,68018355,55f2d8be,a74e02e8,747f60b2,22354ea3,62cb657d,e5cd8060,7a99da2f) +,S(1d70674d,54763c96,ea3764b4,641d14f6,2aabdec8,a093c3df,d936793f,511fdc61,9674adac,697e44bc,6324378e,59753f42,80774101,623dc10e,8a4eb4be,38dfe632) +,S(75220107,b43ab970,6261875e,c8f8b634,73c47aaf,91ab8fba,cc0b1c4f,40fece1,29094e7c,c3bf07d0,12aebf2b,fb56efb8,41bc9ad5,9c350b7b,885602e,a3aeaffb) +,S(cfadb9ff,b3474ec3,27db31aa,b0bac83b,fc7f4c8c,9d0efdf9,2e7e7922,f779720,ffb7657f,6f7b8cc5,78f22ee0,2a99fa82,97d41806,cd2b8b06,ab00b993,d9a09b2) +,S(24ee919d,be3c5603,adee46e1,39d84aa7,34a7b4f4,d7b826f4,64ce8b6b,c1cb828f,44039756,794b547b,9360b63c,539b8f11,ca651476,ed57fe29,364a5ea6,17ff1506) +,S(5995e246,2f755256,f4d6b8f1,a5cbeec,c50ddb53,fe4391dd,1b530eff,7cb100f4,77ddda7c,7da05165,c46d7ba2,40127ff,fe78ac6b,13dd018c,e08161d6,d81dc64a) +,S(a7233471,97dd478c,e129fa20,59193c08,364f8c37,1cf19c2,9dbd51c3,234d54dd,2c4e695e,ec2b2ccb,384a5fa0,1a96664,9cfdd711,1a1d19ad,92f2eef1,31796e68) +,S(6466ab69,d5bc21cb,d7e75fcc,5de9fcc9,a57cfed6,3ad41c23,4ed56cd0,132251a5,76e7ef89,6dbb16e2,76622f5e,5f6894da,2e0c1ecf,c4af05d2,990dfa4,25294dc9) +,S(a5eccf90,a29388ab,de6fca2a,bf216145,7fab8bb5,1e33d4f1,1e0acda0,f5c28e60,afd75916,468a11f3,73e88643,56690adf,110e74e2,c81123f7,94805b26,620e3ac3) +,S(4251bac7,493678d9,f26e52a1,e3ed9e58,6a15d060,4d1c9cdf,89ed5871,ee9c2779,fa1df27d,92e6716d,76990c60,e6603bcc,4bb023c9,dff938d,3a15ad8b,72987aa5) +,S(77a9e6a2,4c3cc21,d8cf6b97,3181e283,f40c9d0,26a81903,f042c2a4,fa7db30e,a1ef4fef,23f25ccd,bddb757f,aaa10ccf,e78d9310,72b2f180,b6e3de5d,18155aa0) +,S(33fe7961,c40d4e1b,d6ade73c,4577fa2a,e9c0d20e,999f639d,e751ff7e,6fdbea6b,91b7d5cd,4eeb306c,e316e7c1,464c30cf,9a591994,7232b037,5840b8c,d5f54849) +,S(43f66b2e,5ee52211,a48a9d8c,b485be2f,39535701,5249c311,5b682170,f9179564,5370b55f,fec0ebbf,c30cf7f,e63f5f88,3555e699,728e6892,1dbf7874,2da46a45) +,S(4ad36614,97ef1074,d74c7f6b,446ea87b,ad2f0b43,73f5970e,1a745b6c,38b19bfc,8f5dc1aa,769a5bfd,5eada00d,436f850f,6f9eea82,329ebcfc,cd4cd60,ef5cfd39) +,S(9799aaef,95204d54,f3734dc9,75b797aa,59336866,9b2f12f9,155d5953,c012754d,4b6b34a3,d31fe173,43a5b476,bc492d54,44c256ec,ea236f3a,9845a875,e83e6353) +,S(c86249f0,c6e4635c,2d03f252,50e35d67,c1c22f51,6f9a8dca,fbc9d41,15d828a1,e21770b,37dc4d0d,f4d260b3,94bc76b2,46523893,469f1025,86d99467,ee95ec73) +,S(b48dfcc5,de5687ef,c7282c84,cfd4060,61a08fe6,92fb08e,3accdc2e,6656038d,87e3e1f,ec737074,71f69c7b,c7147665,c0b52a95,37ad1566,277b6d19,fce8927c) +,S(77dceb6c,62d65535,c625c828,fd3836a3,146fa4d,36732da8,58503fcd,4e357fca,d90b2600,5a139713,525b8521,3d370ed2,4304d08c,87fbb67e,9091d1ea,18228bd4) +,S(5b588cbf,4cda0184,4df1cd63,3cc70ac8,69cfb43e,332f5c17,47364750,3175e49a,1424ef1d,f9e69e4a,84eb823b,2f95fce5,a52e1978,474697c0,d47890ca,fad55cda) +,S(c087bbba,83934208,8c70251,8c9ddd93,2c50cea5,11c443b7,da107685,9320b20c,77f26a69,717555f3,b030e345,5cbe4b30,f637c23c,7ebc2b5f,6ec2207b,9209d996) +,S(8d16057b,68f8082f,208b3e7c,fc2c558c,247d7d60,f117ea38,35e474c1,3031ed94,3d305db6,62ffd13d,100f6e0d,19c439e1,6ffb8ca7,eec6b14f,ed551091,d6ba3eca) +,S(75fee0a6,3d32bc8,6dbb8cd2,af7371ff,d17daa96,5e1e19d9,242fdcc1,edc184b7,c2b1e4ff,abc30975,fe7c992f,f8091795,61ee89e,9a040409,10bfdc64,93efa2f8) +,S(65da3959,b147093d,7d092599,a87710a,dda7fb75,460e47a1,10d5c1e2,6f368abb,3599e1f5,2f92c1e1,c3f2b463,d9a30230,a6f53028,cbae3ce9,5e345c5c,21862844) +,S(6561fc10,94632125,d76b787c,a7539870,5dda1a5b,f4407f4d,f8140b6f,967933d3,4c06c7ce,a88e2828,3eae8aec,ab6e8802,cd083f37,6d3a1ad6,29fa9b55,920e6337) +,S(c9a53f80,70493701,523041a6,a9d23343,c8a3fc30,6664d6a3,5ca5e7a4,80c4410e,9af470a9,b2e30d45,ebef0dd0,6e3b2736,369d4dad,f2366d42,18344a22,b6e4bf9) +,S(5c1525f3,443e56dd,b009f45a,1b9a1540,c203f814,5f577bf0,3c734597,33b89158,967892f7,cb3ed91a,d74f4c80,3625707b,58574afa,cb99fc02,f5b3493b,eb4f4f18) +,S(3565ccda,d87c171d,714add6d,472fee0e,69bb6ea9,75f61454,d69939cb,541648ed,9f7d87bf,ec2b6358,5dbd09bb,d008b197,4f02d3a7,6a8d54ed,d486a2d9,3462aef8) +,S(4003ef34,c0f5e1a8,afcf29df,42a14a5c,4527d3dd,138b5eda,bd8de661,1d0e3614,67203152,44894cef,cc3d0a76,35839c2f,3d3ead0f,36174e2c,d3c4c682,4c3048c4) +,S(f5c4df5b,37965079,3ebb7de3,9b495a26,13886422,929393,1cf55d1d,912ea57f,b0b93c3e,12a98cc4,5a3672c7,4a3610d3,aca34da5,7d31a968,f30047e0,31eb3482) +,S(bc9f680,e21186cd,ba63533e,56580289,cbe8698e,69ced0b3,97a96793,569e213a,6adffb78,8105518d,50fb94ff,87d204dd,7bf54ef5,b91e1d72,713fa9,b32e06a3) +,S(4dce8797,f1fe8811,453e15d3,7a3e2621,549e8347,4e7046b0,55f99d2a,c9a16516,ea5e6b77,cca7825a,95cfd9f3,7d70d7b2,fc8a8aa8,749a9d43,37ce0754,abe668ea) +,S(f49b5aba,1ef29570,bd72a0c0,40009382,af2a4f85,26511eee,81869d3e,9759b16b,2e496c20,b996e8d2,696125d0,f60abc66,1d2fb343,b4181202,8658e459,d57c7f7d) +,S(26917d4a,7573e1d2,7b4ff765,72bf2948,a2d02f07,7d7d7fa0,54a1bee4,92125ec,b8e47f7e,ae9b66a0,2a6fd2d5,cf8c88c9,7eb12530,a618678,ad5ce83,7cd8f97) +,S(1b4948d6,285a2fe4,98cb71da,f213e6d8,7ead776e,cf8bbcb1,cd7faad4,fb29d290,1ab4081f,ef87d925,9b736c7a,92d28618,d5698499,b2f5e27b,dd30c1b4,24d3bfd8) +,S(14d712ec,8179baf7,9dd9676f,ea99653c,f8b20ff4,a69636c7,7258bd57,99ae64ca,2e1db8a6,424650ec,32b0df37,d72ce3f0,6f38538,53bafad6,d366e04e,380c6ef0) +,S(7675220,41747684,9e1967e1,54445913,a1111988,8b5bf813,4d9694f7,1d952453,3f1fb063,6457b603,3a155a90,6a722de4,de1a5c3d,6094dc27,37776843,ed82fd31) +,S(5ac8e534,a8828b67,40016d02,80bb1e26,a53b16f,96b24937,fc84ba34,dd49fc63,193d020f,68f5fb7b,2c5a429,6909ce70,18568f87,115e987a,8e5e206e,b8a1fc73) +,S(87cddeb2,8d16562a,531135b6,193449e,d618d0dd,6acf6c43,3372202d,ab4a14b8,5c1de4e6,7c958ad9,9411cecb,de2e9129,cd709425,135c84b,e5b68cba,9f846e2e) +,S(c431ca25,a39ed09f,48e1dfe7,afa86630,4d4f8b7e,eb0d6d52,f8c778a0,424c84cb,450607d6,5b2dbe6d,35cf2d11,d3129330,489eded6,e35ff429,2aeae0a6,7100d825) +,S(8c5021e8,985c1a11,4bfaf3d4,40edc4a3,aaa93002,5c2f2c1d,9bff3683,88a3dd5a,4cb960aa,8077d81c,71d74ba,6096fd4a,b6d31fae,d4315db1,3c2b60aa,a12fb108) +,S(338e54bb,38a47485,8c17c07a,177dbbf,6e7a14b,26781bb7,70b9d717,6e513d4f,7876ae4e,84cacfa4,c22951de,f67763ba,c44a6ad5,52ee66fb,92f80cf8,c4420548) +,S(87f3bca9,efbb3a21,917683ab,ccd268ad,3c7b0fe1,7eff461b,cb06ee8d,2f1f3c5a,a7a1d2a1,ecccfc54,4881f258,bf5fbbc8,e5cc11f1,a117c7f8,361a33ed,55229b61) +,S(f4023df,8ed85856,8e56a037,5a6a78d8,de27d6dc,467c9aad,52407bbb,413a3e40,b2499142,fc4e3a11,6aa30e56,6d59f373,d5e2c545,3e274161,5cff9f6a,1fe178cc) +,S(cfb51fc6,d55a8a22,89d3d282,fe63b2fb,453b512f,374e01a8,92708564,9c6f2d3a,8d4a3223,283811ed,28ec120e,761e61d3,e4ea5312,1cb2525e,b567fe9c,9070635d) +,S(59a44a0b,97050147,bf219db,22249635,c45f77b1,1721c486,8937ce96,ae43c539,31e1ca6,6a910f3f,1de1d0cd,55eb8a76,400ff959,13774efd,158d931e,7039afa) +,S(b99cee56,ec277a37,6ab44628,14bb3a8e,d8e26d73,19fd786f,8ab570e8,28a8ee7e,46e0f398,dda05d4d,7253b16a,b4d80c14,b6be5d31,d1dce230,62ab1135,c23494ad) +,S(a39e136a,d96b1a22,6d039872,5da75b38,1c6b922b,52947cb0,25207ad0,d172bd2,7a5c0758,74de08e,3d10fa71,79639fa8,7dbfc977,8af1a3a2,d910a1b9,b6abb532) +,S(6e8b4125,3b2eb74e,626dd59a,eb7512b7,2c23c855,35f479c4,5b48d974,57001976,cc0b88e1,e4e8c045,5e804068,acb85aa2,715bc82,ec21ab47,873999e8,cd2bc88e) +,S(9942b6f5,681e4189,f7fb6ec9,8efd1343,cd1fb66f,1c98e418,9c44478a,51abb019,200d0ebb,b0cc2d52,90a11e6f,f7c989e2,d2fe986b,ed266430,56951679,8d0e7a9a) +,S(7fdce1ec,3c57b949,44166918,b48af352,759636f7,2eafd744,642e0f7e,5078506d,d7785aef,c19a76e3,73b786ed,1e2d2ce7,53cfb979,65d3d46b,2e313a2a,d7baabd2) +,S(6f13205c,958c83f0,f170906b,d77c79ab,5f51654d,88195b04,a70d4e06,93989c57,8ac9a15b,b386e483,b268d4f1,c950da35,33deb99,55116c99,e848f13f,73b55ee0) +,S(f955a35d,833c69be,40a0665,f4dffbfb,cd405f4f,5b4247e6,e50cd4b6,3697654e,89f4fbce,22468389,a4af2407,f40eb37c,f56e80b2,7da1983e,4e2fa4f5,8bc9ee44) +,S(dbcd152d,619646a3,42a25743,1df9798d,b58b8d1,89238132,e65fb6a8,26248007,66fa717e,c1948fd3,e4425e9e,2e6830f7,e57d23e3,d0219dce,c02b4d36,32d8ba13) +,S(f1aebce8,e57b909f,ac7cfb1d,a2e7953f,99f713b2,8b35b5cc,71eea153,5e6e8ebe,8755fa14,3e77e5aa,60dc24d0,92e4f596,88b0bfd9,585fd57e,1b7f610b,e5d9d516) +,S(a202164d,941f84bf,f89ceab6,50430905,c002bc5a,91d505f5,fef6e48a,4b55187,e0cd42b,2bc268b5,1e572e97,8b9bce4d,b6d4b095,ade884c1,bee3b3ef,c2f057ff) +,S(572e1657,46fde7de,9480eccb,287f8b9a,b1344da5,8026861,e784047d,ca8ad68a,c174ade7,c066abb4,8d2461eb,405dad76,39eda86b,a0fd170,47569617,31eb5d9f) +,S(f4e2c907,fee4d753,c08b1052,b76e49e8,b67047ca,59e64dac,58acce9a,5beba31d,b243aa2d,3a92d2d8,e48b8317,ca8fe897,2b76d134,248070f8,f41bf871,2c11c42c) +,S(a6fc6aec,84455716,f5e9e436,d68809b2,26698781,f24d0463,e06963a5,fdf06dd5,dc16a615,548efd18,6ae135fd,f748d9f0,a96b7f4e,918513d5,73900aa,1818ca8d) +,S(bd806817,5fde9652,9ccd8eec,937f2cbc,c4ffb3ce,b04cc9bc,c00cde2d,5a05f026,b2791ae7,8e014328,e0fe6a0d,8b6bddc6,db048274,5152bf76,bce228b3,64a26216) +,S(f888a667,6f8c3d20,b9d5e810,ecae6b8f,2d8614b2,3a5da51e,16386dd3,5c0165ef,fb4ee20f,e429f3ef,f6f4bfe3,9c7b1ebb,57978853,de242239,42a3dadc,909a0dea) +,S(7c8d1e05,5adbaa71,ec9023a4,8d160fcd,c3182ee6,bda76fd2,3ba8877c,409ae200,8a3b820b,ec595523,d96936f4,fce83779,c489b9a4,f2c8c524,f16e1764,2f907ceb) +,S(18886ea4,ee257120,610ccd71,593baf72,6dfd9bb7,5229959e,75c14e76,26fabf43,266c6695,f57068b0,d33ad3f,7d02b7a,898a3184,39889d31,ffa98d86,e091531d) +,S(fea70f1e,38c8adbd,3339a44e,cac036b9,1242a099,506789a3,184fdcfa,6be52cba,9dff6df5,ba8c1b9,ddc58093,a36670b6,76c0e2f,d745c468,83e26ece,3b9e7915) +,S(4de30389,45aa3c90,76d99142,e79451b8,96dcbf7b,fe420c8f,b1dc4b4a,37d1365a,cee74e9e,9093de64,2401eb2e,201b3377,992ac0a2,13b0b16d,35664ed8,d287cba4) +,S(67d09dd1,eafebe79,c63b8c40,1c102982,8c2d8e6b,6b5bfda3,73988830,1a104fb2,10eb5508,92660d96,8e99049e,818f89bc,d4f03558,d9f2c984,61ffaa5b,bd360a5f) +,S(2b5d70fe,186834f8,d3b96d4d,87031cd5,325e55f4,ffa31b5a,f5ffdd77,40e6010f,646e7e53,24d2a373,78b1f54a,fb2081b4,38439890,c9f53b1f,7bda4d47,a895ed02) +,S(cb426299,8700a76c,193f7b44,6aed0ad0,5d600b23,ca24c752,527f62df,e17be248,92843e13,f3eb60c9,e5f74eb,8cce7723,bcfd0250,4c2186e6,5ace939e,5819a8b6) +,S(3ee6ab7e,75b3bc57,135ce4d0,1e6de88b,22d0b853,fd8e0d25,f9b04ded,418e4e41,69c83f98,4e52519b,931b6afc,933f5200,6ee1ab4f,680ee768,9ad55368,1b4bcc87) +,S(583774b0,a95a5143,17232df6,f17d7829,6918acc7,2a385724,e904085f,c887e7be,33bb1e66,ee8cf17,30c16073,665c353,f8f047fe,150b4424,18c736aa,807c3e7b) +,S(af32e1ef,39822787,79082b77,2a643ea3,eb334100,9a7a3fcb,a8838e0,7079dc1a,6985e28d,c660123e,73aee7e8,b1a36697,16938331,e4b4b7f8,b3a9ecb7,4e95fd4c) +,S(6edf7fdd,32667551,9b60c740,efbfc3f5,50f7249c,deabbf9c,948adc16,e034d0c4,f08c5f18,5def7da7,5fb0de81,9b092691,64534f14,bb7d96d4,bb4513d,ef46026) +,S(3b9a6645,5d268f94,6c504120,a81821e0,86257a60,b3fd9f00,72a0a4f0,1f16b42,ed583a15,aedf6c08,95f60109,6190106,3dfa4848,645b0117,e2e1bddd,2cfe7c7b) +,S(bd035b08,2b5cfdb0,d17cbdf0,7a012b0f,27b52943,82e8bae2,d683ad0a,747a1039,6494cbad,ed4ad7e8,aa135ccd,572be8ac,e94a23c3,8b62bf61,ac90f9a3,9bb2ef54) +,S(e25fbf19,fe9b180b,ae3316ef,89e0382,4dda59b1,41022ff7,a8c45b44,f15338c3,45ec47f6,58a3dd52,34241258,1852e694,7c2c8f11,9f4fbbe6,f6388363,174c7cf2) +,S(2e231dcd,8ffd7356,52ebea7,50165405,f30f595c,3871ee6c,7c072e64,ecffc9b8,c664452,db15961a,8458f3d3,ea24ade2,7610d4cb,ee51927d,29cf3164,6f59317a) +,S(7c0f29c9,3932626f,1b1ae126,316e065,fd2a4174,a66a6048,3b458660,f5338fc8,27ef533d,df6f1272,c0255d7a,587f56a9,b76e2c4f,98c98162,350233ba,75cd037f) +,S(e702d61c,ea6f9fef,fb43e014,4794fb32,7bd857e1,70b299ba,31bb6a20,7cd5bb48,c4779881,c924ee3e,7f228a71,2de07794,ee5e28af,ca63af21,12ec0eb3,1a3f79c9) +,S(f1780044,eadec1b5,bee75c11,7c1647ed,c362c5a4,35a66d8,cc2ae45f,66c852a8,5f8de9f0,f31b3977,f08f63ac,1380310d,e8b7a304,85c9f0f8,9a677572,329e1c18) +,S(7a41b37f,22ec5b18,d4952c53,326665a5,1582ccb7,1660b69f,8d00701f,1f12dd9e,8440be13,2c57259c,80cd74d,2a2f1e01,3448865e,2429c2b9,db750951,607fc443) +,S(94fff7d,8111d69e,198f4e16,57c3551a,a5ce6316,d520a779,ca4ccd0b,282db6d3,482c9270,26c0c05,578a75d3,8b1d8ed7,42541d30,3a933b90,9c3249bc,505c6fc0) +,S(d6a6d44e,8a3ffaa9,56cac76b,1b05a4a9,d3775989,2f70e560,a54c9440,17f4e9d1,48c3bb22,cd839de9,9163bbe7,83a8a057,c7b93e87,de388b6c,dc57ba57,90863e1a) +,S(cc0e25c0,8e24edab,1e5dbc47,71543b92,c47c0993,95b93d53,699204f9,50cdf80c,20c52cb3,7170cf3b,43b76ab2,cb4a6d3b,1a977c55,2431b8c8,220282bd,51fb70b) +,S(cf953f68,4cb7d1af,a125d0ea,cfb83cb5,efddb6a4,41079be3,db72573b,62f8d827,70cfe366,a45d11b1,a847a7b,8e3e50a3,b302fa50,1afc89ac,b89eddb,30909c0c) +,S(1ac22694,2b34ab06,ff16b711,2fd5fe1e,f8ce6975,143ab19f,bff99d6b,6815d5dc,a43d457e,2bd0975,4e9b7fdd,d9e16681,1bd823d2,24476615,4d9e3fa5,ab6539fc) +,S(d02bbbff,1153804a,f0f800bc,f959406c,496349fd,a412e9e9,bb9f7232,7a4d65c2,5de80de,3c7832f7,1d744f9b,9ef08b56,d41e682,1c20f2f2,876fffc1,b802a384) +,S(3ccad347,8d464ee3,42e1cc2b,2c4b299e,d8a60326,4837a040,25a8525b,4f1831a7,35ea2a4c,a59b55b6,ac79fdd,6ceb3401,47492f3e,49b5035a,f3036b26,d02691c0) +,S(eac4d554,3e69c3ce,d762e90,fff84b3d,b3a758b3,419d06b,80f7ba43,36033688,aa64fada,c54374bb,fe8449aa,ddaa1846,ee00fb6d,c9435dbf,17f6a12f,d1deacbe) +,S(3d2879b1,73d93713,3326d0c6,133be281,5df62465,d3dbb7a9,a028e0cc,63fca753,576ce64d,9b95b5e8,a9e3eecb,34cdb8d1,fd38a08c,2a6a8c9d,8f0a7296,68d6e0f0) +,S(3f58ab8d,56a9682e,25137087,ca8c766a,72358a56,99ebbce4,cf74e304,6976ca14,3c9053d1,1a2a8a8,1f30f45f,1b480dad,f6bce20a,15e6315,447405a7,b321f29d) +,S(4f5f1289,b48dcd19,41a9df0f,a8aeae42,2a4ed913,58845b97,3145ddb1,13fd12d7,b5c3e32c,c40c6577,3e286ed,a233ddf,42ac0d6a,5a3c3e86,77f8256,e0dc1428) +,S(a64a29e2,a52dc6fa,e74e70dd,da2bacd7,e4a9dcdf,f9a0bbc5,ad0392dc,93376a76,ade2f8a6,faa9b1b7,7baefe87,33ddc365,c776f2cc,b0e5730b,4ebb0166,418a9590) +,S(dee0aa12,c4d6f88a,d1d86f94,e1c6d3e0,b8694b5d,e234af04,994cc7db,c8480e70,cbd9acd4,cbda37cf,a9d368df,332d30d6,413ae1c8,d34219,3d4651f8,62f93389) +,S(8677a99d,c8af6ae1,b653e294,80eb66fd,772b958c,882fdf74,f9c0f188,d5796936,31c668c8,348c048e,4b7a24f3,a0861f44,6621151d,4dc3e9ed,783eaf81,ff97232e) +,S(51117d3a,cb73a7cc,2b229bc7,9bd6d676,f44aedc1,98cedd80,ed6178c1,f6997fee,5c638c04,123f85c1,170651d3,96343e,78f20770,321c1a4d,174e568c,39110cd6) +,S(48d8af64,69670828,e87585d4,52ea1242,a83c9f8,3423e468,9c3ca383,9f141b12,558a8f42,f07f49a7,c6a9843b,9055ed05,1998dd35,9406c40f,dc4d64e3,5265e9de) +,S(62ba9ac1,b0fdeee5,a143d457,41c164e9,d4060c7d,f5bbb17a,ecbe80f5,f6966d2c,65a0653f,2290416c,5fc96494,b70b3b99,9329fe67,3b034aed,b586c118,a5d9450e) +,S(be4df7cb,679da56b,50ef2058,3c79310,508d8d05,43f3004a,486297d2,49febf0d,c1b56550,dd5f3e7f,a898cb8b,aca88694,ca697306,fa3fa09,95f6c43c,d5f3ba9b) +,S(e49c036c,cca2e068,5acdf34,8473316,424eac2c,ce1550c3,a0c435b0,28c9979d,456bc25f,457fde5,5bd0d273,d27afd7d,21186b1e,3b42bbca,b168992e,61609a1b) +,S(ae6845ed,a81d5d90,b3fddfc9,cb774c2a,976e701a,ad5c1302,7057a6f8,97fd58e3,529bdc55,322ae360,9926194e,7539a534,4501126c,e69b3e11,e5b4a675,7ed755bc) +,S(52a1d8f8,bcc2b772,cc8717e0,2d713864,4c274499,4a19ed18,3fbeae31,bea25e1b,da2a0b2c,e7f17894,848e77f9,53b7528b,dbb80673,c70341dc,9f869e60,4189011b) +,S(ffbbaf01,d89a7804,d5d19f50,dd5a4abd,cc5529c,90d26918,425f3805,96a2250a,88b5f7b7,eba662bd,5aa47a6,c2fe1322,2d514410,f6b1a145,38c37ed9,9a9880e2) +,S(6ffa438,aab51ab7,afb840ee,d4f85725,4473fbc8,ff6051f9,fe5a59e0,ff8c942e,5b0226dd,3b88a040,33860dc6,69613bcb,50a0e95a,2ac7df8e,66884c7e,e602d775) +,S(9c895658,f92ac47e,318f5ee5,91d26a10,c2c1b77a,c8bc8cb5,a45ec943,8a2fc79,708071e2,665ebd58,f1655e28,6de258ec,ef4b0115,ff74f38e,516acfa9,c01045f9) +,S(532e6e0d,efba35b1,3fdbffd1,8ebece3c,a59bb3ce,54fbbb5,df1df6f0,c1861ba9,1af465da,d326bbc3,eb732ed2,464b4593,36f04b0f,a50ba7ff,f61b4754,aebc5b8a) +,S(99043321,e3f27092,cdadd8e,b50cb4a3,8a8a9f80,83da6ea1,38d48e00,e5fff425,11be8597,325c250f,d9e5b1be,8e52c336,404ecb24,df29b786,ef9d1f04,8f77ea6f) +,S(96799080,3a0934a9,9a0a6e94,120c22bd,7d79085c,c331e172,87daf46e,7c4084f9,ea90012d,18450bfe,6a520b5c,9b2812ee,574903aa,d75cad04,7dc46c23,98005e03) +,S(74f5d157,915ffe10,cf6d9981,9eff7616,1f36f71b,4fc386ab,729dac37,3aa0afb9,54a0011e,4922bc74,12ae225c,dcc8c447,4e4ce4a4,941a409a,2c49d421,19b29eb5) +,S(12692753,81c63955,5700ddeb,e8d7a751,76e5f3d7,2aa0631e,3e7cd6a8,c1927855,b92e5076,811002d5,44c554fa,1e1d10b5,3eefeffd,513357b7,2c5e0cc1,c39ae553) +,S(84ef81b,1d143d73,5b6ae35,af18d810,d7cdcfbc,dd1c68e1,1aae007b,80230d9f,cae39a2b,a5b4ce8c,21ebcf2c,638a2e5a,b0dda645,aa6e01bb,33ca2edc,b575d42a) +,S(1c22ada3,326e6ac7,6647af5e,ed62a85,c8d89dd2,a733ea62,dd71512d,ec9037ad,f5a598c6,1562a6af,99e46283,cb9e6fd4,bc4142dc,99600b64,49304981,16aab458) +,S(6b91ca4f,f08eabd5,aa8dd35f,e9e04153,c00f1f48,50bbff4e,73671cc1,fa4aff1b,c6cdaada,85adf99d,4fb68c8b,6104f585,b3c9551a,7dd87977,8cb250fe,11b31852) +,S(57bb4999,6d2e2157,613f0321,983736e4,b99063b5,e8f7188e,23f7895c,edf85bc2,93b46dc6,72eea90e,9274b9b2,73a82da,d0a1ad14,55b550e,94fdb765,ab47cc3a) +,S(75790b27,ebf7566e,1056d9f2,463df8f0,67c38a2,78af81cc,b40f5260,4a33ba6e,ca0c8ca3,d99b0a5d,b065decf,346eadd4,3af8dc71,9ae06dac,6be99c5c,b89d2045) +,S(ca7a75ad,a90b590b,f7f2b6fd,e3004a1e,8dd7b4f4,db8c4a08,f32bcbb5,474ebe9,b3278d9c,5c9351e7,bf4e8a08,e0f1dc00,51273259,acdcba1e,fd3ded69,83fc69e3) +,S(a6dc68b9,3bf46294,392a8d6c,e52bb365,47b65a5a,f318765c,7a4f5d5,2f90b2d1,41ba6d67,fc575561,a0f3c76a,931dc62,37f53348,819224de,8f925c33,c90ad45b) +,S(da2139f3,f8afc90a,c7f5a025,20c36110,2fafed4c,3f525b56,fe0dae1f,6bb6bba5,95adcb88,fa9ed816,dc097522,de5a394e,71e92c1d,f5bac36,9ad06067,1b6349db) +,S(a32b2475,2f0e0063,acb4194b,faba9ccb,2159357b,23f102cd,f5a8e24f,413da4de,57df4143,bd8b27fc,c7716ffd,8c35036f,e09f8ab8,34f053db,ddfd3161,ebe576cc) +,S(aaea491d,33824ff3,c7319d8b,a233c73a,741718f2,2c921392,b893894c,ade9bedc,c8fb291,84d8dc65,93a6a3a1,a5aed86d,a7ad0d32,d5f8ef4e,b24b6154,4c1a63a7) +,S(2935e0e2,7a8409bd,224f3eb3,d68fb639,ccf75d5c,2b0315e7,ed388acd,887f2c75,c4ff024,62c9ae40,983d0068,180d4c3,977e900d,fdfc164,c89a938,c568aad4) +,S(7fca8076,9e2e7253,5834259a,abeafecb,fdebbd96,5066181,63d244ce,770fe577,a3ddc3ab,f04ded22,cac3b8f6,ffd14ffb,69cfecba,7dbaeed9,9a5e13cd,55bc3542) +,S(c5b5f1c6,1caa4a7,fa5e665f,57b45134,bc129ec7,131642a9,6a7b4191,5e8b483e,26cb3816,da5098cd,a3f58fd0,c26011e9,73dabb66,d8cc9257,6d37bfbb,9cb538e4) +,S(410da274,df436772,64decf4b,f790035b,d7d5b174,cffdb4f4,56bfb6a0,79a50d88,71c81968,188eb349,6dc2ef1e,841979fa,254a1939,5bbf00f8,8e1d2bbe,ef9a6abf) +,S(3d9928ca,334dc800,abb6c5a2,43a2681b,6f7976ac,50abf387,54058d05,cf67769a,cfcc01dc,766127b5,3e183cdd,80a0a1e4,62bf01ab,c4df115b,2e4f4e9f,95d2beb7) +,S(65a8f57b,c523e4a6,4777ce31,2000a322,d858eae1,f39fc919,2e4f436c,c8040cec,820698b9,9e953745,b1ff7b0e,a22bff63,c9df69fc,c2055b32,3f07fdc0,61192432) +,S(84e553cc,baa606c2,ffd3ef5c,a62725a4,55f4e539,24a72153,1ac3e66a,5d92fb79,34d6af32,4aaa9465,fd9f7731,1c01221d,4c0b5f75,1902dd67,4dcfd0f3,9cc5f8d2) +,S(3b4a7558,28851226,f391578d,5d146da8,dda3d4b4,f79a36ac,5f8c166a,773783,e37c96fc,4de83cc2,eb4b3cc1,44d4d35a,1a4249bc,4cd7c787,7d0084c1,b1a59e53) +,S(6dbbd12c,6164e8d,ea489819,37fcd12e,74339578,6482ddb8,9226d9ef,50cee6b0,89e48f49,b3f5d154,52e47c17,e1a68ace,eed3bc6,8002a70,33316116,ade02b90) +,S(b64180db,3b926481,74a0b743,1f84af72,f1118e9d,6cc1fe02,f0bfb72a,97c441f6,b394f997,83d00816,267a4f0f,8c95a05c,33cc19db,eac704d9,9e1f0c2c,4fb25fd2) +,S(2173f38c,f47377c6,d977fc08,ebb67f29,37e96fbe,e46b2115,b260f03a,216b5c56,bda02a78,3c4a684,fd88c6df,6becf56,3bd1c61a,4e79d36f,27e22fb3,212e2abf) +,S(9dd9ecd3,f3732f0d,864df0b4,8cf35e06,ea2b89a6,a8a2756a,222e266d,fc5c5214,e42ea720,2ba68242,ed9256a,57db94ad,dcf00b1a,50ded06f,a70d712e,17e921fe) +,S(705f9fed,5cebb62e,dd549526,af729092,9d398232,604d136b,2a121cf,e7af71a9,bb2cb17d,aa4472eb,12e69a4a,57a7863c,2b32c100,a1601d2c,44d2cc29,750d30a8) +,S(f1a908d1,807169bd,7fb7fcd8,cfc125e3,3fbcdaa2,8d8df1a2,17b84c2b,2cef4410,e86cc08,804c6c56,f81cfa75,9851e67a,d792bbe4,87812cc1,4e7aa468,b8911512) +,S(db0c5d79,35693c81,c752a475,6852260c,5625e434,5247cd5f,d40cdc24,e1355f57,120c5ea9,fb00d295,37721f1e,2539ebe5,d0de9bd5,354ce629,fe8c2e8d,c683daea) +,S(5e4d5935,56007e92,1b158f68,3411da86,e979d470,7b53caf5,9a2ed94b,ca423ec6,71588b00,1a0e9ed3,27862fb3,7ce6aefd,c309b5a0,928766dc,b947773e,6272d935) +,S(1a79ee08,3c46e5f8,8e97fd11,22410164,a264d106,7ecfabcd,4872af40,4fec7f28,f928dbfc,49bf7553,356289f,18a5c8fe,54f94bd4,d9406aac,c4df7a32,32349111) +,S(e693f88b,e3be0c46,cb40a2d7,f3a0a435,1c3a1812,4abdf46e,86ca3af3,6cac5468,55f0b7bd,24ab2a2b,aef2db89,d8aec5af,fb4f354d,66538efb,78f094a6,dd649cc4) +,S(6d15e8b1,f3c73c76,f73b12d4,f5e96e28,43bb6157,5d0d7e58,1bcc551a,329ca25e,f21f3ee1,84386427,32a0d05e,419f8a59,173f8cbe,6e3b765d,b74c3588,2d7f069d) +,S(48b8f127,b2614af4,95303f2c,f6593d16,20dd98e4,ff536dc4,8a5aaade,3bddb682,8ed1b9ba,ec137c62,5127e23b,55d786d6,a50d191d,6803ae99,c7ce57ec,2f546e3f) +,S(2ec32631,ee1e4510,94719f29,1a32e0a0,8c29fca4,8ff7e3d4,170a7c0f,5aeb3028,eb861d9f,e21b536e,58d0ee35,9d07d09a,491572f8,13eaac91,6105785c,697aa945) +,S(f7960ecb,3b35d4d4,5ed2c13f,b55cc944,7ab72f66,ea1857b6,776b8ca0,afafce3a,90245cf8,d40f6b40,a7140334,da02eea7,d8f7cf7f,8f87c510,cd6d9ae7,8410f08a) +,S(a94ccc3e,4b22f7e6,ef385780,d58f3aa1,139b29b8,c7dcb5af,7a247125,ba613ef2,ef7050fa,dd6afa0d,a89ba357,cbc6a66e,782471cb,8cfa4c45,e94d445d,a2845409) +,S(e48a7ff8,6d80f430,d3d6f57,6c56f026,8c42b3ed,17086399,56d62f54,f5485c38,b1695229,b4997b0b,229e3c65,c7ffb42b,e429b702,47b98231,a7bd9c5a,5e9a6255) +,S(df99488c,7d46c83a,cda5b422,b2a633d6,cccb09bb,f6488d9e,ac79e9bb,7f22d2ae,89490280,a958f45c,4501a878,5bd3c72b,aaf83a45,d91a38c3,e0477562,f345fd4b) +,S(a150c6c0,4db9f9f4,6f64368e,bba348ef,2bb4e43e,29b27770,553ef41a,ef22fd84,61dfaa74,e1525a0e,c3922ab0,20e3ed1c,e7b5397e,b4485cca,e1f64f29,19c5c201) +,S(9b7dedfa,452ec6f9,1d7aa167,bc984a28,937392ff,d856a4e1,204aa541,f3aa0edd,a37f4912,2f5168de,bca0ef6e,7c9b31ab,b4262c09,ccadbe79,10a4a844,ffd2c74a) +,S(c7d77a51,6d0cea71,b20f75c5,579a5906,ad1aa83c,f9209a23,d38ed358,28e51904,399a7c7d,9e1a3660,37b0a7a1,49b0dae9,8e5a288,cb5ece7f,56de4d8d,74a44bd6) +,S(d313a829,8e4de5b9,a166c2b0,f73d9812,fc1d1dec,b3b86e8d,8062794b,42fe73fd,6524463a,7eb26e2f,34f062c5,dbbdb4db,b8514c9c,60af6a16,fc9a8830,1f708fe4) +,S(4bbf363b,4d66c693,6469b8e,83c4f18e,2e6c2a3c,498f38b9,787607fe,97211e5f,9e42ca4b,243872c5,8c7b6406,11817743,82bb0d59,c0de2562,9f26e8c0,7d1c60c3) +,S(3be10ed,23a0ce86,d4a7ef1d,a667cf19,d471bd37,7467403e,3f84535f,861e9cf2,bb959378,cb317c0,6534748a,49bb9fa8,edfd2090,cb95cead,a7b0433,4066d885) +,S(fcd1f880,d723963c,829074ec,8d29eec4,946da198,cba5d96,b169cdb3,5dca2076,9489bce3,a31362e1,c4cec275,5fa5fc86,d3b105ae,25bed346,7c0919d3,b2a87b01) +,S(b5fb358,993d3662,b2e7114c,d8ea0681,f39f42a8,52cd217c,f0ec0271,fab317c4,89d88eb8,ee622cbc,f0dbfa82,8b04ac27,80a653c5,14df734a,791b3bbb,f3a71b43) +,S(a86bbad1,7fca460a,4740f39b,d2ccab3f,30fc137f,604e77c9,55624815,8fe274e7,c26dc259,ba969ac7,8d294742,e4962c07,1394ede1,263f5a0b,d03b7a29,30753fb) +,S(ed321f6,348cbc96,7e34bc7b,a935d129,9dd3fc94,c27d1467,88792180,1330d29a,b4078360,832b5de1,c77b44d6,cf07bdc8,fc5ac402,15002135,1be0d251,a3f7c3b5) +,S(c8179275,e4ddb936,f55e827e,de094c4a,2c425b8f,701fc979,96ed7194,1ad17dea,d99f1c5b,e241d165,eb49b0b9,266486af,8ce5e963,c52b2622,e16fe99d,d82553a7) +,S(6f08f13f,23b9b383,49274328,3f8dfcfd,eeaf82e,1d91e512,df1d0d7d,de84985b,96b6a829,f99f433a,6ee58ed0,50370ac5,665d61e,22cc7a76,a4a3fe08,d8bd602e) +,S(9443a7e3,410f9d4f,ef9f8b60,9eac3e5f,e6ab5d6c,a11855e4,b35c7e67,9f8f9d5a,d8c507b5,78188c3f,31bc93e6,d07abc22,ac9b2add,5a11db53,8fa0f936,3beded57) +,S(432ea8ca,3ed53681,ad3afcfa,570056ed,d38c8848,de293d2,e37703f5,133c502b,9e19228b,70b52bb0,8e66a49,826c6a61,965dddc,64270118,faa3389b,6bedff71) +,S(1d17589a,42f82fd8,c5a584a3,d3c7fed8,5e22ffea,e2b732c1,30f903fe,1982403b,9f7bcfb4,8f18d208,26564ed0,245f0c6b,511e965f,be5e0e94,54e0f552,78c39ceb) +,S(743399b5,cd84846f,65e778ea,790412ce,1ab8c6ff,ff7c098b,55436a1f,e18e6b2d,dc6cc81a,82801be4,e6566d3f,c01b6fd1,e84ff49c,e5ccf145,fb1f49b2,d8b784bc) +,S(e4378558,3b2848c1,62e3e80e,3b5f9242,5330d232,e05f871f,a279a0da,7910b2a7,c39b4171,aa4978e4,7d3f99f,8179a189,d5e2421b,d076d1f0,80cdacf0,55624b68) +,S(eef768a3,1b1639a8,f1755ac7,d00a6463,8f8a99ce,f5f42a10,664026b3,6718d63e,2a9005f4,cbf4e686,1af0043a,fe97b065,878efcb8,8be29ef5,ee648473,1e24a991) +,S(15db4687,2504612c,f40dce1b,d601d848,fc2afa9f,b2de929a,1800caa1,bfc91fe9,a8b6e64e,7d508d9a,504678a9,d90b82ca,1e72360b,95a2f515,f17710cc,4e7eded8) +,S(ad45facf,2529a84b,9d28d2a0,456a1fd9,d2b3303e,fc78e2a0,c7757bad,d4a4191,1a78e571,473f3035,16ef5867,8f77d5ad,bf8d8109,60f9925a,a6b4a88d,3654f069) +,S(41a03744,6e027b4c,eb775050,a892bac2,1c19b66d,5fa4bd89,58c949b5,b9151824,ed7c44dd,fa96d38f,a721cb2e,60e07a84,27c53acd,6435ce74,bb45437d,95140317) +,S(2020b869,58f4c7ff,2cf64589,f1043d,5a70d5d6,dac0740,56011f1d,27217ae0,111959e2,2757f431,a1994617,124eb1c6,b37f5961,29d52aa0,490b94f7,e1c4e9e0) +,S(2f99a946,859f74a9,50f3bf27,d85a169e,99c5f755,71000180,283383a9,eabd4ba1,3e622182,d3caeaa2,47a4ed24,6e608592,36ecba9d,4e8d79fa,12854f74,df89fc53) +,S(ddcf3989,57f65390,167688c,2e227f29,e7c5675,d4a83a3c,177ebdd1,9e369baa,a700c63f,3fa6833a,239a3cee,a90dd021,c3c3428c,f2b11b87,3da1dc01,2f4b2431) +,S(9863a7b8,4252360,19e2fa9e,9319c5b,92df1eaa,c0b7917b,73bd1042,191ace4f,49a499a9,281dab21,4bf09f8c,724a30ea,3a1fa7ae,4f1b2b6a,3bf63562,e03b69e6) +,S(6c5465f9,ea2c5917,34f3734a,64b8e92e,19cb4def,3c6d5d2e,467a8f58,dd733886,57e22bb,179df35d,15aa2616,a319ab3f,768f655f,a1c07c8d,3dafc443,1e0e733c) +,S(ab375513,360b3beb,d0ca387,fb0a0690,25acb654,fe703a53,d979f14,50f3fcdd,3e9c1149,309a2de5,9b7842f4,3c37a6ed,57f0f776,503ee7c5,46445c2f,6c41be4a) +,S(6acbe3ea,4a72eeb0,b23aee37,905b22d0,ff0878a9,e9143111,4821207a,4c2603d2,1ecefcbe,9f934d96,a163dad7,6c9e6806,ac2ca23c,e495a533,aecb19d,df0d32b9) +,S(7955d144,58fd0c42,5e4ac9f9,c766e253,b4ddd105,7f1c8c3,653f95cf,3a955d89,8fa9c5f7,304387f0,94a89225,53a20287,40c6723b,d25245,84735024,9650aaca) +,S(b5972d0c,90433f,702b25a2,27bd3da2,d488ebbf,e5782132,28c20cd8,35ace377,235470bf,7fbc3de5,279ef70e,d174b2fc,e3e78f84,5c0bf212,cf3d64cb,42b008fa) +,S(a266a810,33a5fa68,a204f3bc,53cc79f2,cc500d7e,4495f8e4,d9cb48bd,4bcf886,31a8b1a1,958d15b7,664390e6,a46f3e37,d52b7824,5b0b91ec,b568b7bd,f55949f8) +,S(1c6412ec,21191b63,5bbbf47e,1e9f7c21,ae7f4f3f,7de0f123,451e421d,44b9cc15,833f8a2c,1111c4f3,f5973851,d0256309,6e7fec1b,22ff969d,82a62284,c42c685a) +,S(ee3532ab,17575b57,9c19ccbe,fee04ff3,8172677c,5e625f68,a7462107,3e0b7fda,f12e10c8,b2fd987b,83dff04d,cc48ee6b,4b704b4,92b2cf53,a9af4510,6e7e8718) +,S(5ed10fbe,4867937,2ed2765a,f7f5b4bd,52ef9a4b,96515e,37944d9f,ee1a3838,8c4eb9b4,9fbe3924,ed8ac641,25dce66,a4bffd7b,5fbc68af,2a8c8633,b4080573) +,S(fe348a21,f04c85ed,69fe7345,f73420e1,b8f6b859,7082152a,15a1d535,d01378d2,d595d446,c9f5abf4,5ceabd10,3e38e423,5069473d,7d9f9911,7fa9cfd2,81f2b7b) +,S(7140369,b7b64ba0,861e1c0,b5ba3973,b573679c,c091623d,bda88745,fb2436e9,f0770350,f9799607,28c3bc21,30c6672e,40dfa362,72c50ad,1f376a54,83a12b2d) +,S(6d14c4e4,8e981e3a,e7ec6b88,b1230096,a7465db,a8381bd4,aa82157,99dad15d,25e4d2aa,a5f2d12a,a4e635f6,db58b2d5,f9c6de8f,b5bea99a,50e5b050,e7e0f841) +,S(7931b9c6,a6837d7e,3620558e,55504e88,4dffe071,5bb628d,aeadb0af,1a4383da,586caa73,320925c6,ddd12128,bf3bd38d,96b7a904,8422c2ff,9d5cfede,fbe80c0b) +,S(149e9d6a,35b83d43,5d0e1f32,a1518b88,88dca145,27aabd95,b0ecd0bd,e5cec834,45807aa0,fd84cc65,e91d49b3,8d012fb4,f87b11cc,1906e1f,cbc74c5a,ce5606f5) +,S(656b276e,b4b351a8,222f2b59,d7949010,1bf6e696,c284bff7,b809bd27,d297394,8746f309,5f8643a2,928ebfa9,a0e35893,905eb6d3,faa8e5d9,b6473281,7b763291) +,S(60f399e3,68086989,ee62370f,f7852e1f,3656a720,539880a6,9884b60a,f1eb02e,55dca05a,8347be14,85251676,d20b779f,9e5976fe,4def267d,4f1b2b6f,d444ad59) +,S(4dbda303,a67a41c,a46f417,54f9bdc1,34a305a,9018ce0d,4cadbe41,886eaa13,e062cc86,fec33458,d65f9fe6,4433b745,909a3b95,d23d7970,c22585b8,3fa48fc4) +,S(816ae1ca,4d64cd9,5a7c10c8,fd819c6b,f8c8b1c4,f495b111,d07f2a00,dd0363d1,c09f6bff,c331d6fd,56ea5520,8e9d13bb,b12187f2,d49366b,2dfd1c18,66526009) +,S(45839f9c,983fe0a7,c3b2b8fa,e5e288ad,87202944,c16d60a0,f18daf,8081b52b,f9368e07,4de74eb4,81f7beb,30835af9,aff40c6b,cda104db,2a785a6a,65dd8649) +,S(50ae4a48,3a49203b,1e04c482,ec2454f2,44b7157d,b23bcd50,63c5b6e8,d4223465,e1b8cfd7,e7bd2e1f,65f2031e,c583bda5,a619028,5c364658,36dba37e,7d5f3008) +,S(df77b231,60395089,19edde15,b21ace77,c5d8bb4b,ed26f9db,a694195f,616b72d6,8a4b75b8,9ecebfbc,b88cff82,2673665c,c99e270c,b33f3037,17dc9500,8b4344a4) +,S(ec6c0e19,978e2f18,b74419d6,70274075,6d2d238d,63b2d345,437b0b8e,f233277d,f90dab9a,2dfc4cc,62571dc1,35bfe4c6,96bd3968,173ced8a,4a363f0b,2636e553) +,S(2874416f,90e7fce6,a6d4eacb,1a722218,5af2a885,4852be4b,a4619011,617b3329,1f323675,f6ced648,8ba4c9af,7912ad7f,b8628e49,5b4da82d,448dd265,eaeb4466) +,S(872367ec,586d3a80,f8c87f3e,83b6dd3e,529de5cb,897c9d2b,e7dacf3f,70ff4247,e5bb60e0,fae0843b,788768b5,e427e009,7dc571c9,e4b62eec,eef68512,a6a3ac05) +,S(c10f2004,baffd30,ae430ce9,40c4af34,4339a0b2,13bf1f48,91b8da3e,424713cc,37be9055,f0c39b36,c546d456,b3f82edf,bf6dbf79,6343ee59,c3537fbd,8631c7ee) +,S(14e12ee1,91c83005,6bdf0f15,3353e80,733b8bb3,b93bc59d,a356dd94,70d847c5,e9707b8e,e00c1781,12b32ba7,c66d7245,d487f032,18d20da,b1550e3a,9befcfb2) +,S(dac3ba1e,2583379d,d2cdd89f,6ad053e4,3687eab4,ae804305,7b57823c,489fdf36,45e3da4d,88211519,55c20ab1,c2d1ec4e,d13a6942,fd37bfa4,7614745c,6fe2c041) +,S(d9bfc67a,5c086ae,e879fad0,b03a5a2c,a2507dbb,fdd2cb09,2644dcfe,bf800bf4,e015dd4b,5a39f5bd,1536c8b1,e93490f6,e5bb4e8e,b23e6ca4,2fc14634,2be6730) +,S(de6f3452,2f04ca0f,170d7e58,1d965982,8a9a981c,12f6cb34,761873,7996c61e,1ec16f3b,28d74fa9,43b9c251,f34e15f1,2fc6d814,ff024e3b,826054ee,f72a0cc7) +,S(432ab355,338e17ae,884a15ef,2365283e,b35c873a,4fa8cd93,f54bf828,a0e30eaf,f56066a1,a130dbf,8a3e076,720c10a5,caa9af0a,7d86ab9e,8703dcff,95447807) +,S(3d2e3507,cfa127c3,a350f546,d95431d4,8d96990d,b5beaafa,35a408d6,7f7c4d99,da60885f,4711c373,145655ca,b0f8a235,7f4a0508,2bbd2ac5,1b255593,a35f74f2) +,S(7f3f431c,b96dd4be,37c29d0a,55f3b71b,f781c7c6,191983f,4576e518,24ba87ef,f4df4345,7649d24c,2b8259f6,f7177b96,cfdb08c2,4e9161c1,695c8027,60b8bfec) +,S(4270bf59,f2c87000,44b6cdd8,b558e6ae,6f7b67d5,f128d716,3d604a7f,2f687143,358cef,2e8ff919,6865da0a,15a25524,6c4a180d,ed25174e,d08eabd,4da99315) +,S(c663722b,9930fc9c,4113af50,d51c6539,b7931cab,ebe2ebd,46f95b8c,7f603852,3443e7b3,2cdf23d8,eb532a31,3ca4b32,b94768c,78f8f13f,719708de,925ecfab) +,S(b0014864,e396ff02,cebd7b65,c66e57f9,168e8f3,95ae614f,21f8f162,c86c4e14,3f6c99d7,e2ec94de,ee65007d,ab501230,4a80b69e,a0e0672c,b7dbe4ba,182eb876) +,S(64c9cd93,98fe9da3,5d3329f0,ccb82e43,c2d735f4,d2467b2e,1250c410,da84f41a,d24b50ab,71bf6033,d1206fc6,dcedf049,c223ef78,ff50905e,c8d95115,564372e9) +,S(ffe0841d,51e05862,4f759706,b27db960,ecccfad4,cf326736,ab4fd9db,cd29b766,6bd1f1c9,f6956c10,4fec1595,24d8064f,eb5d8391,30b34a01,77c07491,79cf2562) +,S(d1dd0c0,c053c597,bad38d63,c40d1e7,4b451861,cf0f20fa,47fd3f9b,77ca7432,34aa97fd,b59495f0,3e7b5628,daaaf66b,5c9dc5ad,de929032,80ba23bd,6c55976f) +,S(87a436e8,c76bd7f7,a3e49cd3,af996f1d,9153f704,1b185d8d,f99eca45,ae8e5779,8d2cf3f9,12553844,ff905d5b,2a1fc36c,369ea4ff,6a89a027,b6dbe797,f11006f3) +,S(a54500a7,4899c440,384f707d,a8fd62ec,1801070d,cd5396e4,b59e9ecb,df27c379,e216444a,6d26bb06,5f5b5e5,72c927f8,5315df3f,11da2cae,2f334572,33cb2668) +,S(937ea4f7,99a319f4,fa5aea85,b48d6323,28417b72,8690a9c,88fbd51a,57d8187b,2931a7fc,9eb4aec8,b7dce4af,d14438ac,fce77bda,a7d3e7bb,b24c8554,cfdc9d9d) +,S(50793c76,bb914aa3,204dbc96,cb04ff26,c7060863,8d497f07,a1eb05d9,b7fa6f36,afaafc78,b5e30762,b68940df,41de9ef3,d963b603,6bb1ffbd,eb13fd67,4bdab21) +,S(8b600630,fadae564,dcd1c570,9bfe1ad5,f8da5282,61d55bf1,3a29766f,6d8bb5a,fbf1b64a,3bd0439a,ec45a7c3,859374c1,7885389b,9c201f4d,c1142120,6b2916c0) +,S(14e88bdd,e32a15ed,a37c9650,ffc18ba,1fc61643,22b167bd,635f3d02,e78c8458,82c1ec3,dc240faa,5fa355be,475afe0b,5cc2cd13,760249d7,35b1efe9,976f02c9) +,S(c201e4a3,24b68472,d453dc02,8c78b1c9,975a3d92,efc70a30,a912fcf4,991c6c06,263a954,41d6e6d0,8ebf3e50,3c786a12,a82f5f8c,d38dccee,62469e9c,f0e2dc08) +,S(4097665d,319a8b3f,71861b1e,11828cdd,4094182e,611b35a7,c5d10ee,99db4fb,ca0d7ceb,b1aa2b1f,576cd1ef,56ffee03,322a6b95,505727a8,5dcb70d5,27a506a) +,S(173d287a,eff9293e,dd2021a0,4be052d9,3713341f,37a537a4,45deab49,b427fa92,9626e204,f03a1886,c27c37b5,85725465,72e5302c,d3f9ce54,1fb9a46c,16432548) +,S(c923c74d,1b114f,30d4b03c,92629bed,227fb8c6,8f1f39e7,8f121a44,694d4256,58edbe6b,dd5e1382,108d1e08,ef022788,c9f91803,d8ad4273,1f413440,5b5b3d29) +,S(92fa7906,b1f25c2d,3df104c5,196cf31f,93e5a8be,6cb91a57,c88c4ab7,cb92d46,a12162bd,79341fc1,e8f74db6,2bcd0d9c,ae99a75e,ce588240,79a61751,c887f307) +,S(37477df6,f51f78c2,a9c8e17e,ed30d5dc,976a9c91,4aea94c,691aa3c4,8639140,6a6a26ed,1955656c,64c6e15d,e50b0453,25c3da66,f5067730,5c2d5fc2,a8089872) +,S(b5b2ee59,1195f38d,f834e78c,abf00fb0,be9bc724,36c5f596,67ada098,dd0521bf,10f36f85,95233008,46dd276d,951abe90,cc8baeb0,fd8fe44,314706e2,15ddd5e4) +,S(b05d1b8,443f1bfe,36a415e9,d307ef2,56039335,76ecb630,94845b03,d2a137bb,99fece4b,ddc90b2c,3102a415,6f0d63f8,54098f48,3e1ef64,65f7f062,7d066cbc) +,S(e5d711bd,4778b3bd,cefd703a,e9525b5b,d69dcd86,6cd0b179,de76ae8a,5d918fd,8af014ae,5aa05b29,a0c88e21,8fef5690,9685d524,af389327,5421c35c,6db64248) +,S(7703cab8,377a482f,bff1c6fc,4d137998,1e217d11,c424beb9,f4f1f786,86fa4f30,3323edd1,3c80b8db,c7e247fd,5568c92c,8dd329ed,420aff0a,8e903571,e884e8b3) +,S(f834af29,c18bb488,366cf722,52a44357,2c87da2c,c14b3085,5405f626,154f3cc8,2e8a0ac0,ca5441a2,9e27dc09,4fd5bcc6,6bd8f7c4,717615c2,82001fed,bd5ab248) +,S(783b093d,13f33c60,1db8ee84,51d852ae,13bbcd7d,1d03a79,4c774336,4bbbaee0,3aa90b01,cfde6abf,fa0dbfb2,ec2cefb,6b5fb1c7,41701ab,66ec9b82,74ae5b4b) +,S(be3cc435,a7770b99,14a243b,48ef2c77,3ae42e82,1c18a266,6f92da59,e01c3391,f0d3bd36,9118c58,159fc64d,e61ebc58,a560f705,25dd5c51,e6aa9276,5ce4a701) +,S(3e980bd7,adac00ee,fe362454,5fee1ae1,97f89e06,84576a08,fc909285,783b606d,c64f0e41,204c946c,74473434,7e091147,67455e30,53fd488a,34d333fe,e9c5c228) +,S(a6b04140,aa621e6a,34959bf1,29790d72,91d7b154,5dd5e7c3,35bbcfb2,d582b442,9cb2c9e2,9cc05d97,5e61d151,542af6e7,a997f8d8,ee42d37f,8041c169,abcce830) +,S(7ea7a83f,c133cb8f,a109a6a1,b29b2c3a,29ba432d,222382e5,1f280e2a,47fa721b,cbe384e8,8a1f7731,831c5562,ad1430a6,6aabab75,e38571b4,5bb7dd8e,a699d7e8) +,S(8525e87e,f0fc9ebe,2f82b5fc,a14ba6d4,8189f9ee,146aa6c8,d842aca6,90fa042,dcf06a78,f311a3cf,182a393f,2a34a570,192873e4,7dfe22a6,86c70e75,6b32c86f) +,S(7555a77d,fa050d0c,9ed29c33,765fe967,16dafff3,6cd04fc0,952a7b41,bbd56dce,9854c0a7,bdc3dc1f,d8bd0a3c,d0af3111,18dc0392,830699cf,d0bd6f1f,17152177) +,S(9ed142a0,7a0adac1,14e6f026,133e00c4,972bb3bb,bee62f71,beee17d,9aac296b,c1eaea41,6c80e3b8,d24d4006,f699af50,9f4dca85,11c27f6a,39150a20,2b7a9d08) +,S(a3fd2cb3,784d8ccd,92aa67c,8118fd80,c9d761c4,2e0169d5,fb13b1a8,dfc56b79,75cd9b41,55db55f2,d50fcdd4,8c90d58a,b0d13df2,7a09df6d,659bfd5b,f87ea755) +,S(2ab4be05,217e7ee8,799ad598,b9c0e211,554338e2,8bb6d42f,c9952203,605ad251,2c2a1a58,da066d4a,7fc8c8eb,83e1e47b,b788afc8,3c8c5dc7,bd8f5e31,5476d853) +,S(4afc2888,af8c1aae,af6268af,566ecceb,8c95d09,d9f8f359,2cea567b,8648c383,b1e26b82,5e69e92e,98902579,7e99c7eb,cf3f284b,e1de0054,58b59336,a84f5eed) +,S(dd800faa,92319d2e,48038600,aac1c2b2,f63f5fc8,dafd988b,548021b5,2d8e3d4a,59fe8092,6e0468d7,60e522ac,91881bc6,8fdbc192,14fee60c,e8e1a977,1039ed7d) +,S(84aaf3d1,daa3a5f8,89b9bc88,6afb07f8,7bb5182,6df9d7e2,af5a74f3,c6378c91,f4164ab8,45eadd6f,a6331218,ecce096b,a04fd586,b744f0e8,11c2a48,3835afbb) +,S(b770f2c3,9e2e9db8,a92823a3,adffb690,d2ffc180,b88cefcc,8adad3a8,27c40b2b,f7c6e37,9894982,5d1b90a9,16ea564f,7e319c97,ca6cd22e,79f599e8,dc0d53e6) +,S(a60608a8,a0d7e556,70145c5f,bb107cc9,7cb1db87,2493f362,36a21e7e,babb2b29,3423527c,4e414548,96406f90,6d4a3819,a289c91f,b580ce19,6f25c57,7b54de5f) +,S(80f470f9,7b7f393a,5e6b4e5f,cc911a73,20f6b0f7,fcabf2d9,21eb649b,53414597,57d8f2f9,6e1bbe0c,1328faea,13c3f3b,770fa14e,4b5b7e4a,fa1ce9f1,2bd9adc3) +,S(4e111bf2,1f5248cc,3fff0096,c64a7b58,72e4a3db,1f0397fe,261cb33a,995abb6f,249cf172,102733bf,5fd829c1,d60bd930,c03af614,31faab0f,6d5acbb6,96eb2b9f) +,S(7d8c0cb5,47fa1d8c,10254660,a20e85ec,960cb70d,f38174f0,18416c68,c62844c9,2d79ba3c,17ec4d79,a157335b,f358cfd3,72b0f1ae,1f6bc743,40400571,5f35a271) +,S(bc0d4cbd,95896fa5,7f23d48f,a5a9f2f0,14b132b8,9b5953aa,f612aaf9,670a0034,f5d06670,7b316581,7a641091,55773bcb,83d7563f,28ea5412,480a0f48,2fa0639d) +,S(b154a2ae,ad08d115,95eddbe1,c9321e15,5cceb0a6,a7e646a4,2dfe70fa,b6d37a40,9abade21,674dd12b,d01e586f,695c896e,17120d8d,9e3c756,c8b5e53f,3216592a) +,S(ef603c34,a6ce06f2,7053bc31,841fe2e6,314be756,7e477325,5315ca58,5772e1e4,f9ebbe28,96f3b0b9,923a7e57,d819a231,15fced8f,3bd08f51,64aae597,c49ad65d) +,S(a601176c,2d901ebb,ad5a05d9,1adc0041,14f7bda,1ac496e2,c04e23fe,82aa9376,f781ddb7,ce0c3649,3772fb84,9e914377,d59abcf9,d3eade68,f8c8a303,1ae88ab8) +,S(abc41547,b6b3104e,fab968b9,bc9a9027,b1c7f0ef,3a9007eb,27331539,5c31e6a7,cd2858a2,28f21d6f,bd8a1821,dd78399b,594c5bd3,52628dce,879b8a37,d97e0ec9) +,S(92890105,c9c721,b2e4c430,26e413a,941d1da6,d31b48a9,2f2e3a17,d87f5a81,c1cad87b,1bdcc617,1e432e17,c13b47c4,15c22399,a7cbfe2b,b3097f28,da60a5da) +,S(e520dea6,9f4b35ca,46a46831,9947690c,500a7a80,6bd64228,ad144a7d,c37ca563,6c00d766,ac3f8fbe,90355dda,6ad4e2d9,e2330b0a,db673356,638b0d3c,8a2a82de) +,S(c0337a23,e2b3f1c1,a57d18a7,9d6ef25e,ac2e9315,18f0ffb3,7502d701,c57fadc4,fcea5873,be22df35,4729c3d5,b07a570d,7ac7e938,f6e061ec,cdd2146f,50808b65) +,S(276c62bb,6a8e2c07,6b5fb6a7,62d1d624,1b796a96,f53593c,fa51279b,2981ac04,5c53a65a,bb6b01d2,3f9284d7,d696236c,773c4578,88f692b,73e2ea17,6e1afc1a) +,S(604e1e87,e5051dc2,b837ccdd,43c8ede4,c4a2de6f,67a9ded4,fad1ddbe,8d663a5f,f70fe23c,e3511973,93d4d675,9444d862,ace4c473,99c34349,2d06b27,8b429bee) +,S(f2fc151f,470d9106,d58b05be,5e9039ba,4aba16ae,f7e4ceec,3b6e3887,5c41f6fa,f49bd2c7,f1aa5c63,d8e7f2d6,e0769060,d4188773,9c16b7b8,5d2a9216,e1e98de0) +,S(8e031346,e9f34ef,3b81d9cd,7e46eaf8,7ee0b294,d66b0315,eb0902e1,340ac560,ff00c8bd,a5e21e1e,5127441c,ee0504e,6b028c,ec0dca,450145f9,2c394296) +,S(a8680f1a,d75b7a8f,27a1cbe1,6b2954eb,d4e26eb3,a85d1a0a,96b9f40f,e5a9970b,60c6bf41,a55bdac6,397281f2,a3f52896,757401be,c42964c6,9501973b,e6070c01) +,S(4d68a1e7,f4d82ea1,e03407c0,5085c794,9ca8c00,d4dcb066,128e6c6f,504f4658,85c5de11,e5dd3691,2aa95d2d,2c36dd6d,26a9550a,3a672af4,d36265e7,a3d1ce76) +,S(3708f41c,2a6d8649,6983cdc1,bd02eb39,758c0bc1,ae78a483,5c6a20ae,e6c2a7a9,310b799e,79b7f5dd,5c9ae0f8,7aab193e,3c2b7145,c70af9e7,f4553faf,abec4152) +,S(8c883967,45028c5f,f1b96181,43f5b732,2d1a18cd,3abb1a92,f6ce3780,a115f059,24563ad4,e4ae484a,c344180,66dd87c,40128e42,5c8dce10,b008a7e7,620725d8) +,S(c445e76a,7b377ad3,bdd0fd1a,94a7263b,652e83c2,6342305d,a0e1ff4,d58f8fb0,4bf5a41a,dc8ddb61,3afbd3c1,3aae7dc6,f60ae2e7,23065b8c,c94cea61,cbacc89d) +,S(4ad9613a,c8a635fe,60d9f1d4,da4b9fd6,36949d5e,edaaee8d,eb2f65da,8e419f16,5a9b5b06,8f67a0fb,3ad31c83,ef1a81b9,38745877,b4b07316,42ab4951,68b0d7c4) +,S(beb3eae1,958bfe6c,9ab49d77,648aa662,2e397fbc,58e90b0c,20d1d29f,d760c943,d5a46be,f43a67ab,225dc6fb,5aa68daf,ec76f27b,6a822678,dbaeff88,382c9b8) +,S(aaa9aab0,bc0e21b3,be3f1dae,ad4a076b,4623fc14,3e4018ab,9df9a19f,d134f397,9c7d7fe,19642c65,a6c0347e,8fa2dad2,d3f094f8,bab6790e,d3c703ba,2742e40b) +,S(553c1e89,99d6f446,2fd7ae86,f1cf9d24,d4011661,9fd5d356,604d6a55,ad99dc52,26b40d3b,8410ac5a,6d2ba776,f7c5f0dd,3f6fe494,379344ed,6460bd6f,f550cebc) +,S(859885ea,36378fc4,398dae9c,4725d604,c3d56509,559ed28a,b47ebf82,5aa1abc8,fae5aef9,fc74b963,bb2fd930,5b2d1636,e6e84aa,3c40b066,9e531fcf,f00687f5) +,S(5fb0a118,679c5d48,554bf7c1,63b82345,89e51032,a70c654b,bb7bdee,f0368f93,e8d55f0,4a6816d3,bfb02111,eb95d868,5b9966ad,39d94c70,a4cf1826,6bc2a2d0) +,S(a424347,86f3e153,c9bd737c,1e70ddae,bbed445d,77ce4302,194be82f,94f91dfa,27d1cad6,abd9fda9,c1012f4d,f25b69fd,a54239a5,8ec12496,97116548,e7beed46) +,S(5d007508,63fc1f3,a0a8213c,c729310c,39465945,72b083ee,f571b921,a0c821e7,e538fbc4,5d055a07,b2cc2605,61238486,d99bfa81,6b0407f9,39f1d12b,feb2df3a) +,S(a3eb25b8,97b10286,934605a0,e4aab7f9,e80393aa,71cdea52,5f82f5e8,282e3db9,e2b354c2,1430c45e,4236baaf,128967c7,6beec58b,e6890c6f,303d83f,71e7f77d) +,S(73f63220,8a133202,96f3f51c,d10fc816,1e309e51,4ea35f0f,ff72e09c,e897981b,43412959,cc78f32e,d6df7ded,349a92e,3095257a,8a1b5dc4,15ed073,a420179) +,S(5f0825d1,c21bb5f3,8f0d9628,f6046648,7760512d,f1bb9bb4,ccfec4e7,48da41af,debac60e,1d95de12,84f1abd5,b6592824,5becd4b8,c2496323,b374239f,fe5c0cab) +,S(cc42a6f2,b4a8e9f2,fae3f624,cd12294e,efc26dff,c66a676d,a10259fe,f7d84294,91b26600,f92cbd05,f13f2adb,2b5fb17f,118a7ae1,6a011690,1bae0e14,3b230519) +,S(7d56e0e7,6eebe13f,a81aad7a,8efbcd1f,4de0c5d6,bd136261,8f0002ec,6f635a17,95462707,fe55e3ee,46dca813,eea5de7c,51122ec,55a91754,f7d13ac2,43fa1ad8) +,S(7972b61b,4fe85ec4,acb605b3,aadb56b6,fba8cafc,3c764dc6,add54c06,f7a5be61,ba186670,2642fa6e,a7cf5141,c46a8e92,4764c4ce,5d45b7dd,9f4926c9,32b8c7d8) +,S(edc8a440,347b1500,899f6360,9674f90f,4344c87f,361fae0b,bbe08235,d5025626,2f812740,9a14bf59,9bcc7cef,ad140b2e,7bf84122,9a51e486,4d01ecc4,1b2cd77b) +,S(bd9b65c9,7a8cf4d5,2f727b57,19f99986,d4ea1bbf,25560d18,d54877cd,3db16899,59cf7127,4e878e5c,bf0d9e02,dbe4f861,ee9c8e3f,5dfe99af,7db98e2b,c2fe432d) +,S(27635e38,1191e8cc,d3756571,44c5d8d8,72d91802,5950a106,f3be2acc,4cf35782,c359fe47,a019870d,7fa3ab,8f51bad4,eb5251f3,7e6b8ce9,db1992f7,cd1ab7d) +,S(4492dcc3,16c05300,a96abad1,47a00e98,359950f4,95dfb261,839ddf21,3b21d85c,edf1371,a4e81e42,dbfb8c6d,2229dc5a,fafed4bf,a58c2433,18934ed7,dc9ad35b) +,S(f8124c40,409e01e5,8de8a386,9bd88f8f,25887fc6,cee37c01,279aa606,edf9c67b,e0071d1,d31fee0a,8a26269c,3d7f3662,2b0f008c,61e749d3,65560c21,a26fa6bc) +,S(cc597b67,66eccdf,a2c0716a,dd5e51c2,ce3aed33,8f55f0b1,b5784bc3,9a05a2b5,12e031fc,394a43d9,d1e12ec4,28e8d5b,df52dae7,f3ef22da,74e3a418,74682865) +,S(142cb2c6,bc1283fb,d2164270,7d525dd3,d4a45f71,a63222ee,6fdd31e2,805aeda2,bde93d12,c72c422a,e4d5b718,bec6458,ed082bfb,7c686f2e,1815edc6,5ed66ec0) +,S(fbf4d602,dd765941,e696704a,1a8977a9,c3327375,e3f0d479,68fd9148,c01d2d3c,65b46df7,99e895cb,a6d4cae8,e68f6160,c7b96fb2,9af7d18d,8ef1396,c06afa8d) +,S(efdb5d57,bb5fe8cc,e3300ea5,ec14c50d,f09436db,cc58ebc7,c6d123e1,8dbfffb8,39083803,d9a90c62,6219ce93,167bd89d,d444e47e,ddd60deb,8137b8a4,203fe01) +,S(5bca4334,faa30557,b4b36c7,b6bf2d4e,921f59f1,eadebd74,97690742,2c3f35ad,3c97baf5,e2a663f7,22bf2fe1,cd646db5,79d27f2a,353fb45b,520d227b,c21206e3) +,S(9aa1dbbc,e90cf065,5ad8a0f0,54aa6641,ff921e97,1a73cd4c,49ff1f3f,51156632,cbf6e81d,8bf1e85d,b802f0f0,b9cc1125,6e0b337a,b90112dc,6513bf40,2b1a4200) +,S(2fc7fc55,86ed7676,4d5d4d23,ddec2827,5386e56f,eff09b86,abaa9562,73c2d408,5bff69e4,773c34ae,e477b0c3,e0310b5d,6019a558,5d4c7f3f,54f9c810,69d6285f) +,S(8e5fb941,c3ac6f2c,43195487,80df9116,6ef3b210,f2fff34,764cccbb,d34190b2,dbe2c1b1,5f6668e2,c63ae154,ce7b32fb,8d29b59e,dcf1ac4b,1df9baeb,fd10d2ce) +,S(7a5bbb59,4748d6dd,5d3389e,aa95b8da,dcfbaa07,26693690,4801bd61,b3d49c6,c2d28043,a42d33fe,8d8b755c,61235c68,ca13861c,effe3fa7,fd4edeac,634187c0) +,S(95beb8bd,f0d33531,ae73ee1b,1b631ce0,917c2fe2,22534745,f87faf21,bfb76753,c6cf8600,d9c55975,527e269f,b4a0e4cb,b9bd7783,7e230ada,a43c2f0b,c64f45b) +,S(f44ecb0c,6d896dc0,304fa480,90ab9793,576dbbd9,76b8fa32,540d223,e2968d25,545064f6,29644329,76a03c62,9ea46a09,e20e470f,5e76f810,6d19f353,c321086a) +,S(8dd32cd3,3dbd936e,6173ef50,1f7ae265,d56d68c2,77061e07,4fb49d26,538109de,6b110e5c,80daac20,5392bca8,a47d6d90,ad158c25,a10c0851,ae985f70,7c3f1e76) +,S(3d4afd30,b0f0f578,d4fbc77e,b71d044d,fea5e3f,891cda8c,77075dda,6237997b,2816e0e8,664df57e,c793d442,49c23ada,ae286ab,e748493e,d83b1efc,58bb9ce) +,S(a9b739fb,beaa3b22,b295ccac,86a07ba2,b8391381,2d2be020,a5ffd17,85d95ff1,a1d08230,21d6a6ae,f696d732,3c43fdec,d3c5d42b,8ed7ad40,1a55b2ae,bfb84f1b) +,S(e9009747,e51251eb,fc2cc754,c8b55966,a37e5d67,acf9b632,bb77f46b,9203715a,34258967,9ea8f997,71b476f2,5571a588,756f277a,17ce3907,d9cdab4f,cef9df72) +,S(7e348ced,55aad74c,c24d09b9,6b332084,2108fe41,3ac4c6c1,a8376439,f21a3f2e,39874f8e,3b722795,d8465706,e439e4f5,c884c22f,365920f9,1edcf83e,b4389e5f) +,S(a7dd6676,5ec2d701,56f2cdab,f0fcc0d3,8e340fb6,8a0d1220,aaaa74a6,fbb1f55a,b7091bf2,ab00a63d,292ded9b,b00bbe9,63710dad,445e8e73,760a50e7,2f41d447) +,S(b8579e9,a8cccbf6,dc033a48,16d8934c,51c0852a,4693fa96,a308d51e,3f57025,e696ecdf,4d79151b,2f164a3e,bc11bda,42c88833,6f694fec,a8bcdcc5,7158268b) +,S(7b29c45,9de0080c,bf8c8c72,e7b59a7f,184f1c1d,46787cda,bb42c2c2,bff57af8,40de8367,a6d8d13d,41901ca5,60376ede,817578b7,25f4e614,5dc46de9,5f801799) +,S(1ceffa6f,89b65be7,ac20e34e,f0b7e503,d1c4e9d,b31fe14e,179afdd,96f00f9f,6fdee8b1,f05930bd,ed98feb7,81790e10,8e293bf5,bcaa6da9,79a744b5,1a76f179) +,S(556e2d6d,11d301c5,6d5d01e9,a01e2ec6,80ba4efe,a004de47,ca2d97d9,15e58d74,9588349b,b633d7b6,b55ba7ee,feecbc99,3d66e6c7,2f4d8961,8a2c5d7,5249d711) +,S(b3506e88,73b93dc8,ed04518a,42b62ea2,b97f7bf4,e9ee66ba,6a7ab917,a1e51586,474f8100,1230fb7b,fe693eaa,7acba9fe,5917a39f,1f8fe3fd,5823ae4c,1b0b3b38) +,S(d186af3,89cb4908,db01a886,f90ee67c,1ba7ff3a,19994504,e9774b96,bd2628f3,3b39782b,c6567cdc,b4778c75,a862ef36,d01d746f,f411821d,5d08f7ee,f2a2db7d) +,S(f951d921,e1065ac2,3fa45900,62c639d,19e8c980,2a810d55,d6788572,ef987bb7,dcf7ddc1,87f8e975,27db239,7f553b5d,51abc66,bb76a070,55d098c7,f9d7d950) +,S(8dce8e16,7bac6fc6,1161b75e,8f340e0b,8bcbf874,fc82a42e,bb53e0fa,c4d915ec,11ce53a1,4a9eb9eb,9b4b410b,34d26ed7,9c0287f4,9032f674,e3212617,e0ae940c) +,S(ce2d3cdd,a0a7a43c,d7d2ed15,ec12a7aa,755dfc5a,ed5a85dc,4f439eea,99e26e2b,6a96aebb,e7ca2740,ea75c285,3c582207,6a8eed64,7e21809a,36b97c60,7a5a145) +,S(239466fc,dcc2d4c5,cef367b5,c8339248,f712c40a,558c80f0,5ea390a8,dcd92092,f2ce223c,9b49f08b,ca63ee8e,98e01736,65d176ab,3b7d718e,d0e855e1,27ac28cd) +,S(220ab764,341d3c08,d9c5bcd8,331e0973,4a2f3c64,4766395e,f6a5fee,3563e033,ec1e4460,d03013ef,467dc7a4,2b520c03,aa51a9a3,57817f4c,f9dcd837,56df5011) +,S(d5455dfe,16406a6c,70fffd81,f3c4d10e,845f0b12,64fa3db4,ee2ffe80,904b469f,a0f93b8d,257e1e62,265d99e4,9158497c,28a20af0,2af959b8,8810a10,60aaf9a) +,S(52367377,a1f6f05d,df054665,f1eec0d2,f5039cf9,cfc1d37e,1a9d89f2,88e60c72,78d89f55,430fc352,cd58d047,7e2497a0,d05e7016,d98f9ce6,a039fc5d,9ec7bb41) +,S(5b996113,3ecc9422,26a3dc88,67364125,a8e569f1,912e6c9f,4c1ddea5,5fa56395,bb9d7764,12076caf,5d8ac902,c5e2fd5f,f7a0bcaa,10898f19,10142af6,4e436d0a) +,S(f36cdb5c,bfbed1e6,58c7fa4a,5b0a6773,eecd1a43,db96cf0c,7c24f32,b84c13fb,cfc6d2f0,5ee9eda2,9156aee1,81b62659,993744e7,479379b9,3156c919,18c394c) +,S(3208c58e,25107af2,b38bf754,5531266f,842ce33,10ec7e44,595fb91,7079a6f9,831c6dcb,5346b6c9,605d9ab5,895ec2cb,653599a2,c88801c6,45a4758a,32c785d7) +,S(a6073a07,1f8510e2,aa021b80,b44d7356,47253583,6501a5a8,c5253918,8c9927a7,e93a9fc5,4c8a7612,16718baa,dcfc9bba,6fefa30d,85803246,2a9f191a,6364fec9) +,S(3350b462,f79eaf7f,260f2147,6aa7ffe8,f7ec1a7e,35624713,9e335758,b9f0d913,1f0c9db3,fce1222,fbd2341,ba8d2e93,20f33bc,482a4d4e,80571711,21152959) +,S(a54d5b17,bc82a74,9207c89b,5a1650cc,1773913e,66f6744c,11de24ce,3073caa,3c243b5f,5309dd11,83c7fe5d,49222c9e,fe62dc26,f92b73af,cdb7b7b1,32cd3ab8) +,S(6590a2bf,676a7a34,a1424f7b,1c7863e,8a7d346d,563905ca,e5b25729,4a04cf8,11cd5803,490419a,1382d972,eea2f734,4f8d0cec,42466f09,39650645,a3e781e7) +,S(b3c09c02,9fc7f48b,d2f461a2,a367011,8840393d,fb5b9592,89e96ec9,c7cba9a5,e7b5aa6c,bce54ad0,197bb1bd,ac030e2b,c6a3e6d6,af2db60a,b97cc92b,8f5cfa9) +,S(d7968ea8,44a137a,7db36143,98b29972,cdc693ef,8fdd4644,26a92939,18fa8bc0,82402589,2901434e,cbd5dd29,410ce2e5,56dd3174,d74da2e5,28326ec8,ad57a75c) +,S(8a57bc6c,2f98f9cc,d1eca172,b2501adb,3bf6edc8,4b50365c,6d959f00,838e8304,2ebf5462,a0f85985,438b5d67,cbfa68c1,bf643410,11a478b9,92cbfe0d,87e7d14e) +,S(51886841,684750a8,c3cb8d18,f8c863cd,1a555dd3,7f0efb4e,551d0d50,6073fd22,eb05f09b,9e983ad0,a6ce0f15,c2f5983c,6a28ce50,6c52f691,f30517da,36f3f192) +,S(fea8c35f,27e4794f,a9eab856,615d55d2,d3a02616,9b9eb7b0,ab7493e2,f67c85f3,c325de97,cf0a6e3a,98512337,8e2ba2e7,b24158f5,4aa97c88,9b54a502,8c148864) +,S(6612cccc,d7bc25e4,f8dab955,d5c1c9cd,d79d5f69,7ef4c510,77b5027e,d1f94b63,615512c1,7a378d0a,e7aabab5,253df9b,e9bd6a80,15c3b200,73d0499a,3457860b) +,S(c998b07a,499859db,4c9d698,33199956,f8a7ae67,9f6d3533,cbdbd7e4,a86f8746,d9e01371,919e775e,a259d81b,ea206e9,37d6b5e9,113838a6,6af11bf0,8dd17138) +,S(5c0e4669,c5cf965f,854fcd0d,23ddc908,c32e3915,460d44bb,520fb0c,3a4cc1e1,cfebbbaf,7e0f9a4d,d2f35ffa,cd0f7cb9,89f5eded,c8b3c554,64fb909c,675adea1) +,S(d0fdda48,30385167,f06f6433,c6a9d3fb,7ab3195b,64f9750b,cb2dbfb8,7158c0fd,4cde5577,6a34f61f,c82e1359,8618336b,f5c6e315,d10abc35,8f0020e3,ef1283db) +,S(d925570f,d78bf65a,5d48265,6222ce74,7cab153,19b7cfd3,7bc70185,fa4a3e81,3c399a,c448ba90,1a21a5c7,b9c6575c,ff52bee0,cdd00ed1,673d8370,87c1924c) +,S(45d2b56d,81f84bac,2077d607,484b0802,a023cc4f,d7818f9a,1d0c2187,98374c8,14ca18d1,92a9cb37,ad50506e,a25663cc,9829411f,848bbf05,3064041,9c19d7f4) +,S(6ad3ac11,8588c5bb,f793404d,df9a10f8,ea8c1978,65a93fba,5b7170b7,9e157400,fa25741f,1e242c3f,edf20e80,fd76292e,382eb5ad,1731ec97,a8762fe9,811686d7) +,S(5da24445,b6dc960b,793ea9e3,912b21d8,26d54028,2ddcbf5,28e1ebf,4a595f52,bc18ff8c,ad1dca69,8995063b,ff8a2fd2,fabfa0d9,8c8885fd,1b401f3,65f16026) +,S(ddff6468,11ce86d2,93b9b89f,865d7133,d7b5f189,d527cf44,5ed15efc,ad32b346,7260e994,cb22016b,e121ae08,12b01c3,4d236b67,13ea510d,b1aeda36,567f5737) +,S(a8b9ff3b,9120fa93,d0f2f50b,c8509846,c1030d98,dc9d5243,6ad9e69b,f897f029,5cbfa29a,4e516872,ea9a4c2c,a3b07efc,c866aaf6,a2b1d7b2,3597e332,8466c591) +,S(943077fb,177b9d6a,723c18ed,ac8deeb2,62875264,868eceb7,a2fc1a01,51dbcafd,219a9fc,41ad01c9,d3f8248d,ac7df93f,ccb6e312,fa5fd442,e48f4a95,18e7eb4e) +,S(75cb61ac,9c9817a,fdf60f52,4245ebbf,82b33f9f,a564d74e,9e810f36,6458b8e3,aa8135bd,f66f0843,460986f5,f9df6b9e,66441477,cd58cfb8,5b3adfde,ec03c367) +,S(1bb7e177,27cb8e85,4bc922b2,28e7f0ae,c34fdcf3,b9bad0c5,750e7c8,e31fccc8,bbf72886,1e855e70,bd9e322c,2425cdea,855ea00c,3e6263d5,2380da38,c0221ca3) +,S(9443384b,39e9dbf3,45b4b41c,f05d0f30,87f02471,c98e2a2e,afda94da,8bee8dbb,e3661173,ccb211f6,38cac6e2,27e3939f,e7b5da57,f6f7a504,abae01c8,fa4544ee) +,S(49bd15d5,a68caab2,8d51638a,ec1a9668,b4c27d54,d6691839,61ccea76,ef740d25,648fc868,8760e47d,fbfb9f0b,d995cc0f,77563b60,eacf3e57,9db7439f,3f18c6e4) +,S(d0c7b78e,92809e85,84d3684f,d078907e,c151aa78,a5832f90,73f945fd,7acfed85,a80d95ab,be494a40,b5529046,bc305203,be91e475,22ad9d57,7ab95b3,8e970c89) +,S(debddd46,3ab22232,5e98f9c7,5cdc875a,7c4c28d8,79748bf0,cd96bd7d,92eb9275,d103c8d,c3fffcb0,5ffb3dd7,a73af259,50d02064,b12bc754,ab594c71,ab9799c) +,S(1d79b17c,192a6a15,8ea2d6bf,9da07312,9f9ebcc8,54b02dc3,3f64012f,1bf33998,6ec818b3,dbc1c8a8,50d986f,bcf64702,c787682,bc408a12,b78e6bbd,4cf60a5e) +,S(2feb76eb,ff5d47e9,7289c38d,7d1535ff,74bd3b57,264c5844,9edfd36e,6e81ca1b,45bd4e4a,7ba3a823,dfae18cd,1f9cabc7,bb462e74,7899c899,378c33bb,89f93b74) +,S(14d0d90,faef5a77,f5372ab6,2e4f5efd,3eef1b39,498653c0,6372fe0b,b0682573,517f169a,80c2b930,4f530f51,d7196831,601a4f97,72ba1312,36ba92f6,36081453) +,S(7306a7a5,728f91c3,384bd9ad,b10b39b2,ad094137,46d2e476,fd522abf,ff313321,215e22ab,a5b9e87b,35bbd4e4,f492f1b1,574c85ed,25b86a85,a8e17b81,b7a915a2) +,S(85d8454f,870cdb8c,b32873a0,698fad20,fd24067a,737e9719,76d4d362,6a55aaba,36d63c0a,36eb9e8e,522a0715,cb9c833d,539fe7ee,111af3bb,951434b1,3117e4a2) +,S(c68f6782,993067aa,259b21cb,9e19122a,2f7da28,96d8cdff,c1f0a0e4,b34384c3,74e6e96a,331c3387,7ea484fb,995d6a3,8dcd493,6b2994ff,b7dc3681,3079e94a) +,S(81448111,5dbe5550,846d5c9c,3351c89c,e29cd850,6870a17f,e18e3184,4214dd3,75dd78b3,d4cdc29c,697740e9,2478689d,540ea33e,5edd6785,210abcb1,670d19a8) +,S(310b5b19,de24d478,f5f25993,a706f21f,24214e1b,cf614ebe,3e204815,60c945f5,8b42c6ca,f01d205,e09d017e,2e840d69,bf04cc53,f02a21a1,47e33327,104318c3) +,S(cf8a47c7,4bafe2b9,dfde4bca,b2e6d451,b0a90f11,c684f420,a025974c,bc4bc3e,f0b7b264,a9a78699,786331e6,2c8762be,614d8a69,c0a65c3d,1cc201bb,e34c97d1) +,S(a0fc6226,7352a904,e70100ec,63d3b60b,ab553388,69b982d3,3d747af9,8b8650fc,ba3ae54c,16b24eb4,64b88c39,521c399f,cd162eb3,f9966497,e2b96f2b,3b85865f) +,S(aae5dbe2,535edd47,584d0339,10045333,2e1eaf70,a4e1bfb0,7dce3c23,6cff8bdb,7cfaa5f6,e55806b7,bb278439,2473732e,a51d85c5,a3558321,91195533,b7a7449b) +,S(8a4e9311,5b897550,cbc0792f,b2705a18,5c317226,86da5bd5,b0a17bb,503ae39,1623adc8,d85f08c7,1751b976,daa17572,2442aed8,a9dc1692,2dde923f,d17cef2c) +,S(cbcef535,eca90b09,5295cd61,29010259,8627e1a0,ccbaff26,a51cdac6,87066463,651c2ffa,c2a2c99c,3fcafb9d,8c50e156,498fee17,3462fc25,9d87fb8d,6b212653) +,S(25971559,4d6a2bd0,baa90e33,62b9c841,bf12c4d,2ead6609,9902eac1,ed0f8c99,49e01b6c,c97404cb,8144002b,c33e8bb1,d974dd22,d0a26a82,94bad2bf,2875245e) +,S(b754d68b,2b049f6b,ac389044,c80f0364,a707da5e,3e9b2a89,1672cd29,b6f1445f,1b29b7c1,625e23d1,67092e3e,ddfc2f4e,bea55542,5f4ddda1,af2aec5e,4de37740) +,S(20aea5a8,50e68f39,cc7ca2fe,2f38b5a2,ab0bde8b,d294c40a,afa898ff,4f084037,6ed576b3,f17666ec,6aafd6a5,6fe7e1b2,ab1e883c,31230fc2,b4e1df0,3f59444) +,S(26844e02,919de923,3288cba9,a97eb85a,c6939fd0,7cd01e7b,f0d5e1db,e31979a6,3df9a8e,6a5fad1,266f11e,518fb60c,cc08a6c2,832c45a1,6c7c5520,5c9ebfb7) +,S(11afca61,33a69aaf,27cfd413,becdf9b4,efbe0a6b,1a38b3fd,485dca95,dc28414c,8d4b8790,c0677fe6,22847bbf,8e47b400,9e4678fb,b9c9377b,2121f5ac,db737b1c) +,S(c46e14d5,2fe25d65,37bbe09f,ce7e95e0,4986337b,23e7160d,f3d78dee,e8d2a63d,a200fdab,4211e9ff,2d008dd7,7ddf67a5,1f04b9ef,43fa1758,9b175d58,f5d2b723) +,S(570aa12,578afe09,245f598a,210a7605,2412283c,8f58e142,d31d9cd8,d455e4d7,c28fdb61,f8e90de1,d43439e0,8512a071,9a2beda9,5d0a5601,b932c0f1,2cc50ac8) +,S(d312db5e,88a1cea0,28570b84,e3854e16,224236ac,cfb14d1f,3a33108d,fbc3fa64,ca5e5089,1843383c,845fa0aa,e031c930,64b8aa4a,ea72e6cf,36b617f6,cf97e1de) +,S(1ee22876,9981670e,14da9ad9,9279f001,c9be5eb8,76224a6d,1fe4ec08,aa398087,62101114,e303e37a,dfe42c65,54460d4,b68603a2,580c7452,6ff31c9f,2176dcc) +,S(1fb9cacd,e2b84ff4,ae85511d,1c964c01,1700b9d7,2d4c04a9,4afa9aa5,57bb81a0,430b73c1,295c5f2a,d6d9f59f,74201435,15b1306b,2cfa038e,e0456752,5f737fcb) +,S(d04cc82d,d3cf0b47,69f2934a,9807e743,4a998bb9,fa44d145,f191a176,611c085b,7a4a19af,b551d151,c42cf1ca,ce123dd5,8f4c13ac,c865b92d,15520169,1be5fa9) +,S(1e4cb208,8bd4d17e,ba8b97f1,f27df5df,8a544f8a,548dde15,712e8704,cfe7e9aa,d805c61e,b72933ec,e799930a,53fda3f3,db066396,5c71be51,5e8466cd,a59b828d) +,S(520aa398,707a85a0,d672bbad,cbcfdab8,8f769f69,df3de8c7,17d6dc48,de51590d,98d344e4,a9047a22,c09095e2,f1176aad,3b54724d,998e052a,39a52554,4ee9ada8) +,S(3a9fe3de,165bef7c,2e0d45a0,60693fc8,e7080ac9,783245d7,a79cac6e,7b614ef2,5189446,fd3fdeef,c7a895f5,2934c888,7607ff49,aa6d798e,151061ef,73038d4a) +,S(9c929dcc,c26c0805,e4289a3a,2b6d68c9,8e3c6806,43730056,65fd8e73,da149938,6dfbf940,b4c29209,3f39f6ba,b102762a,c81edf2d,aabe6dd9,56aa140d,396ba2fa) +,S(355b60ce,f4e00651,8baf1e42,e5e7a08b,ee22abab,c69aca66,d117748,89be419e,7f478a3b,b277fb10,5fe0eaaa,cb53fb73,4fc01dae,bb44f1b1,ed146f43,fc2604e2) +,S(76bff14f,21ad4442,e1389bb1,c11e1019,ea966091,97439705,dfce7bf3,d7f7f37f,3855a291,376aab12,b5f4da79,bc22e02e,a29a34f8,9223f07b,93f6a549,8289d763) +,S(91bb9cdf,10577a3b,7e23aadd,35883396,becbb4bf,fa22e1db,fa08f8b6,6156b454,ec6cbb9e,4f149b02,edc53e93,d1611b5c,a3edea42,c2ca9a1e,f2cccf25,94edbb91) +,S(9e56b10f,1ba86c61,36481204,f0c45b09,a7dde7d,4eb32537,f8c310a5,a8865562,cdf3453d,8552c16c,48bca1a3,79ee8c6a,8b523eaf,d1862d5,16f4361d,5a8aa67c) +,S(4e73594d,af286bde,4e6e28a4,23930571,a11dcb75,4e9a4af5,f4972d,988e09f9,a59f23d0,70c042ce,e03d812c,ea274035,af0d8e53,828a418,cd1b51f1,458a36e7) +,S(156fdff7,e92d89fa,691d3c55,7cb2c614,393d5973,4b11bb1,d9fac953,3923d860,4e929637,c448760c,ef6d68f6,4665023c,bff653cd,23132ee,620eb013,a13b360b) +,S(f2c8b650,eb372336,5d57a905,23d34db9,70d23d52,1f893569,98b0a7e7,ae8ea03b,bd9ac314,84a99bf6,973422a5,60bde9ec,204488c7,6739583d,72f42a87,181a7881) +,S(27dd3657,a4a37430,5f5bb92b,a7b816ba,88d526a2,1ae316c,d4a4e67a,c751e3e3,880cfdd3,c0faa401,6afaf3d5,1fe975e4,8a756b01,f7d84e8c,226424b,83be3304) +,S(f6c25e0c,19f7357c,3cc5d98,1cc4b7f3,7a390182,c2673708,1c64f163,ebb3d1bc,8c80b3ea,7c05a0fa,39944d66,643b3589,29534152,adf37c2f,183e7c22,8e89e43d) +,S(c678800c,71305ea1,ea2847d3,d9d37612,ae280305,716fdf45,87ac7f4,a7fad4f2,be5ffbf4,d2fb2b8c,ddb49a42,ebeaf5d8,55d41d39,f106e2d9,2d549e88,6c0b63c6) +,S(f35db221,e66b7786,fc9e2d3a,68f0d1ee,f98177df,a05bfd30,931912e8,13f6d560,4899a808,e6b2040,89974ca5,afe5b1ee,9eccb15,36a7c7c7,bb67cc00,e43f29fa) +,S(2b93e37d,a915633e,db9843d6,c33888c3,5d944f04,c4074deb,d021c639,93e69de9,eb3d1095,c6ffa1cc,93f72a58,f1320efc,366a4a5f,c7250167,6f2d3c88,4b0522f0) +,S(818023b3,90454716,f51913ab,fdb406f,e4875b94,8b14a331,60901d1,66091b69,b3f5718a,6224e447,c5af3e1,f38e4f2e,6fe57389,fa7d8990,f98e44c2,a227e7b1) +,S(1676e6a,244ca69d,b2ae565b,65b14184,6645ce7b,213dc1fb,db33f060,3c662bb6,88e1cba5,deef5dc1,26b20830,d2c7c0d,aeb9689b,16ecc1fd,cf4a31fb,822e0298) +,S(2f931a1,a92537de,38629d73,323e2f21,d9657454,30e32e4c,3912cb21,dc298d54,93292d08,6fbc0fae,eef6fe43,f5626711,95a5b2d1,bdbbccc,52e1dfae,a30ef904) +,S(7ba4d612,f0dd8c91,8bff20d9,b4f45486,be8a32c1,122601af,2d1730c8,a1fd0279,8aad7aa1,f5b06431,b2e20af1,4cd049a9,3018e3c5,bc4c4310,d0234e78,d2401179) +,S(e8dfab0,85fe7a91,6a79b2be,723799eb,d6974d08,ccc8e3d8,5286aa61,c81d5e78,2121686e,519db556,e6595d47,a5487bb8,fbaec53b,b18dd81c,37dbab40,6e3f926c) +,S(7d5623bc,b1597ef4,6f907106,17eb2e6a,ea751da1,5535a64c,94c90c9a,d84ab5e,dc639f31,8004c4de,31514b70,ebe2e8b8,701b3cd4,5d66b7e4,204dcbc2,a0ce7575) +,S(8e81e2d,8074bec7,48986194,b3b82200,1e4ac916,81de2ad5,7b9c84fb,88a7ffa3,4085ec1d,f4a34480,ca56f6cf,762d03f7,fa94e99a,8df93e6c,dc781499,59fa890) +,S(a9d5a3e7,8290ee62,5e18affd,169c6829,73e68ac9,2b5cc52b,53ed3a85,a68da71e,1cdaad6b,f9eb5889,5189ed29,8793388a,8d6e8b20,ce47a536,ee89be4a,b4805fd6) +,S(4f7c17ca,bcda7c0e,3b7b313,4312f848,984985f0,e46ac497,d64b123c,57dba2cd,860bedd9,5f470c3b,f3cbe7c1,d5070cd0,c877010a,9baa8f5e,888b5ca8,a34a25d7) +,S(478f3d7a,9234a7b9,a91bd016,f55734e9,34b8c3c,535725b5,b4fbb0ab,9fa64921,db97a394,f0253f18,ebabca05,c21e9a7c,3f253054,d83f2101,8ffb4d93,b8051a1f) +,S(ace7e57b,73d96e7d,69f7cc01,b1da179f,3ea09aab,61fba329,f2552eb1,fe7963d5,fa0251f2,2b8dbd04,ec90f824,be025965,7e213e4c,1030611b,796efb89,26908918) +,S(cd56e867,f5170771,8253757c,dcdf69ef,4401f2f8,a1d09f24,374040e7,a908d1fd,878f7216,52cf0ba4,8a2b29a2,2f620c7d,83e4bd84,277b7b90,a454bba2,7f338fe1) +,S(3042ea5c,d9d2f89a,64b1dd24,97b25da5,67a2c672,ba067e33,e923e513,ee4d5329,b84c144,d5516a14,a0a8568c,d6d227a2,d3fa1d86,8e05e612,81ce41b3,5a68b1fb) +,S(55e088d,a094ed26,82b042,bafa0345,30a2e291,57af3f1b,ce351ec9,9e712ec0,c6f8297f,64398324,96091933,514c5449,cacadf,82d51db2,82c9d2e,c66b33e9) +,S(bd2db13a,69dd93bc,a37f9181,7a57a0e9,e0e0da83,eed71875,e63b4691,3b408966,46e12660,f9489b2f,123c25d5,f65b3f8,187ee6e4,405b8cf8,78a742a,9b0da2d) +,S(7d7a5110,cdbb8455,5fe678e6,24ed1a14,ef7c5219,986a7ecb,6095624e,7fd3d210,c9578dc3,c0a54524,f819d640,abaa4a04,626a46da,15c0867,72774a59,6ac6c37c) +,S(1ef12317,513b1354,2a966981,34edabc6,fd4e6d29,1bd7782,5bdb30f4,937a3fa7,e0e4b688,a391bcef,3451cee3,36a8c9f9,12319899,4684c039,909489db,590e1ade) +,S(effa0403,766fb976,dbec6b2e,332d2f12,9f463b86,8b9a1d19,49d30cea,1606baaf,8c5b1c83,bf3efa64,f38de1b7,da03de17,b0cbfdc4,5b4a03c2,38221def,bc1cb082) +,S(dc9271e9,76a9a042,5565f022,273af5bf,20bf780d,9d0ea069,df5da661,a087d65c,dc8679e7,b27bd30c,986f11bb,1c73b76c,55ce7c7c,621490c1,944cd8a6,b63d6063) +,S(ae1ddc2,1e1ca02c,218f6946,275501d6,a1336b93,ddb1b2,384ab414,b8264619,21c6b39d,300b6125,ec8e5c8e,19aa76d7,32466bc9,a887c76a,1ff4220,7db26b48) +,S(aea2c00f,fe5835c9,2b892480,83164635,33dd989,bf2bca12,85cce3ab,4e82cf5b,615598cf,935a6112,42a20e84,e670b193,9aad65d4,53ba967,3e8193b2,93dfa97f) +,S(913d0e16,34b43a86,f55b30b6,5914767d,b45e723e,636c866b,6348c8be,8aebf696,e14c6607,51affda4,d02574af,43172024,39c0c10e,148d4305,1487a5c4,39971a9f) +,S(4f0b3354,775cac80,5e0d6191,6bb0f9c8,40fc163d,8878c05a,301252d2,3bc26fc0,b0b75486,3aedfdf8,3a6eb2eb,5f3e25f1,6c0e1077,6e855ac3,fa8fc3f3,bd8da1e3) +,S(5da21940,73cc978f,7673b2f7,5c65ead2,f469df96,f80883b,181a3da4,f316129d,8516d080,743d2670,570d5e63,e19eb543,237b1db,6285b1ea,f3bc1459,8ef311d1) +,S(76e1b330,ca7af91a,ccb92fb4,63404d36,a8fbc132,269d163d,d4beeed1,6be74a23,10b39253,c5908ef3,ec96f2e5,2ffa0dec,2ce2800,31a791,bcaae0de,1e7f5326) +,S(c4be488b,2f210ee1,82f91263,78b23359,8fe8ef57,671ddbe1,d76975d0,ee393e64,bec1392f,a1a09a54,480beadc,b98ca024,b910cd70,f807eaee,10d4e270,bb79f449) +,S(546918d,a141fd77,b1f13848,d3d608c0,25f5be00,4d36a542,56d0ca5c,9333ff37,3d1d4c7,9684be1a,5cf00d71,6cf9a1bf,b0b82ba4,833704dc,c2d23e8f,39914ac7) +,S(cdfc6fc4,2c51ebd1,2df368b0,98ff0f40,2e6df8b1,9c67e10a,320c1960,266078de,5985e930,23e5264,547bef45,6b3774f3,c2689411,b6f7463c,febe068,fd89cb0d) +,S(7730fccc,593b14a0,6f21eec6,2408e146,36f0e4b,4718ce99,c99bbcd4,7cf03034,f17d0fe2,736e412,9c30151b,492aa7dd,52beacb7,6f97001c,cc28f991,3e016b72) +,S(8aa4c3de,474308f4,674c7b55,9f895bc5,d855a7a9,5fadf090,5726b354,7941b3ea,f275c44a,eac2623,1bf4ae9a,df403ed2,78d9da42,150c98be,7dbd5f71,5cb8594d) +,S(15926da4,97a4e925,8976f87f,f8940491,f32d33dd,7855b13c,5cb54d10,d325bb79,15ac60b6,5b1ebfa8,e871bf67,ec9f71b8,1aa03c78,82880d40,d35f16d8,67ce8e51) +,S(55f4f4fe,aa741574,79462b48,f001688e,fc99f545,d4566dbb,35faeebd,f5b1710d,80ecea05,63f24c84,e767b894,57dfec3f,d015a4ad,b6e3fe0f,662521b4,bb02d15f) +,S(95a56acf,402f7f33,fa357c4a,e4db337e,f04a60d7,4cd73e0d,b137f68,e0e93cee,e72405bf,b7c9ba84,16f4e72c,a30c9ae5,d21c89e3,ce5b61a4,bd521b4e,ef6501fd) +,S(28a9fd90,b50d7bb5,13034b7b,c36a9783,c2a697ff,499bcd6,4b0881ab,8e7a2aac,76b151b0,5c7e7ea4,9a263596,81508781,a37cfaf5,14fa1720,b583faa3,9794a788) +,S(6406dd13,6d6462c4,a4116b93,eac38eb0,b571e2d3,99cdb93c,b36fa5ef,e734b672,3974c77b,92b8e614,52d9c9d0,62a911f9,b4c5eb1a,977da74f,defea358,5dd7fd1e) +,S(8fd8f23f,cb62e1c0,94fef903,9933747e,9d40c37e,376703c2,e3c8b666,f1066529,8b0b2f9b,de10175b,24a9099d,75926296,5ba19013,20912baf,3100e057,d4ab5c8) +,S(51780a2b,d4457368,9c0679bd,c8c94e43,cc525bab,2d2723cc,3e0eec15,63a1a24b,5026cd9b,e178d1e,c746e5db,29391c4d,4b6b08a3,3530fdfc,64603fa2,f0e01109) +,S(aa01493a,e7c7f9bf,3d2fe0e5,cd939dca,5b8c8534,6848d065,beeb42a9,8c283561,a08f0b45,4a42b5e3,6463af14,5199e3d2,1783e908,b3e130f0,e9e88110,2cda82d9) +,S(cd8ab749,d4bbe6d4,ac81c4fa,d6a27e81,e4456d4,196cdafb,97fa6053,18ceab70,fc6c7739,bd68a20d,e01c9249,3cd7ad3d,ca862183,b0529231,da32f1b8,5df59beb) +,S(e69cdef2,e824501e,7a17bc54,e0bb4886,379f56e1,c59a27ea,e00bec5c,55fe3e32,e80ed10,40375398,10125338,f6291791,3fe735e6,6c4bbc80,f41d858d,8ac41cd4) +,S(5a4e72d9,182b1f7e,efb08af1,9e3181cc,f6b6ec69,790184a2,f30188e0,dbff8a8d,2d1cf7f2,d5a857d8,3b31c588,5ac33a5d,7b62ea62,7b5b0bee,2d912502,2df9da19) +,S(9e000859,48bd6211,410416b0,3920a79e,d78f154,5dd0330a,8f23d1b5,f8984a2b,36ae0492,412fd3c,c230680c,edb0dfc8,151ab85a,d8d3338,db611674,c88e3f62) +,S(7e0b97ae,b12f8734,ecad35d4,aea425c7,99f88485,f0bc8d18,ac82f213,258bc6ff,e76f4e24,a4be1b6a,3fc3b0b8,ab0b6e5c,ab95fb40,4692f7bc,cc7640b5,69f3946e) +,S(62285cfb,1bdfc495,dca81ff2,867878fa,b3064be5,81be0c86,b9336c6,61038ee2,f2c91be4,5f60e9f3,40e85ea0,8f159dd4,a65ca8d8,21a6e4f7,71f4dc17,849b5161) +,S(70234e81,2de1b5cd,699870ef,36d5c19c,cd3765ba,eef3cac8,6f126a,a6c82623,e2dbf98a,f92a777,263f3c92,4738ba,3140f769,fd5b6ec,7139bb8,41330736) +,S(ae770461,8f31d5cd,ede40ef5,7434b0a7,7dc1b4e6,7f4be5e6,136978a7,cd5db07d,a4e25164,65584487,3f520e42,74037c,5cc43e12,95167b01,d46d3e93,d93d16e6) +,S(cec7ac8f,e4db698b,48ab78fb,768e6094,5b7f4ce7,d643e604,9e349b6f,246f2b53,491bb545,99330685,433bfd2a,7a4fc831,7f5d3cf4,80d6bc32,5ca6d001,b65fadfb) +,S(80276e96,b051e49f,276f62e8,35622979,852e4cf,c2ff8665,8db4d5c7,7c5eee36,f510d696,882589f0,870d526e,5f7513a4,2c4d4ce5,3733f30c,f06d7dc4,f42f6d9d) +,S(b19027d4,9d85faae,e6163934,ef8f8508,e9e351c9,82bda741,b8944317,da85b27d,c12461cb,dec0e69c,b378443a,f2eb042e,8439f812,205742d6,dbabb372,ea47a824) +,S(57599d4a,cf07c001,d3d3fc78,aae147f1,989c656f,fbc43081,29e05b2e,570c792c,5cf8ea0f,d215ba16,e18e181b,1b4b4f02,38b57af3,9010ba23,f13bbdc4,18514b0) +,S(5ab76283,fa110b82,c53cda2b,653e763c,306e6f8c,2b07d490,bad6e418,eae6e4b7,ff365643,cc2a78e3,17a7de95,b37b3f83,aebe8272,4162a884,f7437aba,b55e8ea0) +,S(7b93d9e4,8602d7b7,ea52dd45,fa0031de,66ea88e4,4250c898,64903e7f,959d4a85,99ccb201,5ab91fe9,a0f50a0,fefad6c3,f6dd060,1f2ad099,a4851d33,162b52f0) +,S(2d5878b6,af642776,41101be7,2b37b4b9,1de26a21,b9610a93,7ee2ce2,fb96ebb6,138ee05d,df4b004e,820815d9,46716f2c,a887066b,b7d218f5,47d4bd7c,2cfc585a) +,S(1d637068,eebc32da,24a0fce,2e41cb57,cf1ccff5,38cfbee7,ac13269c,e560af3b,6a932df1,a2896445,6685ce54,2ddca0ae,d589a494,b7ee89ed,1b4ccfd2,c276eadb) +,S(82babb6b,460e1235,f3187a68,912b057,26a478ef,fe929a3,9479cf04,467de64c,3a9f4e33,603d0396,1f3c11c,94d58369,5de43a1a,327d0faf,f51089e1,1345647f) +,S(ae86e71d,4e715bfd,b63d899a,9daae610,a01c5134,c1b9262,c276dcaa,b48090a,3564b48b,fcae8f7b,feac4df9,3b458678,6f2f9e83,9c9c6126,a301de29,4cfd7b5e) +,S(35a5c2fb,fc661cc3,f4ad6ad7,f1eb32b6,664c50bc,91f4000e,f5774364,2aa413e8,4a5029a2,887f6648,3e072782,68a81c85,b901d692,4ccae752,7111bcce,cad6cde5) +,S(386bf07f,4dd508a7,61e7c29a,dd251d9a,76324496,6c6d760e,cbc6b069,5858e2dc,d4f14804,9c1fa038,1d903e19,68fb14b2,f07c621,15a81f41,e811ad87,de407696) +,S(dfec381c,9bd6f4cc,50ac445e,c9104d87,f9c46c7c,cbd70909,fabde6aa,12346f96,5e7344f8,25b6649b,df97ef3c,ad96945b,d1ce0f76,a48b7f2e,56ccff02,797553f1) +,S(3606dcc6,4db04cc,5493e0b7,ea0bfc2,f8a24302,d2358aaa,7c1ea8,842abbb2,a5c8743b,bc4d9b74,b8b569a1,feca3667,87eea8b1,be2025ed,bb547e78,5687301d) +,S(3441e737,e19096e2,9a3025a4,71d192a0,db086038,8e76d2b6,66052825,e52b0016,6d10f7e,d5cac98e,73c3ad47,bb233a39,5eb9bd4a,37861b9e,7dbb60f7,81eef0da) +,S(b2c97c2e,460d8c34,b5ea7a5c,456a9cf5,b1d902bf,5cdff030,25410a,26636e99,67133081,a8c8ef30,753417b3,cf6973e2,1f151e1f,27216bfa,23289ea3,e2057b7c) +,S(2740bd8b,59a43ddc,f8ffdabe,d59027b5,9b7932b7,3db45a97,3b6c1501,57e045fd,8106f2b1,f69f1ad4,2c0787a6,3c137753,987aabe4,b0ebd82e,1ea7807e,93b02a85) +,S(a1acffd9,bdbd94c0,cd8b4f40,3f9400c,aaa8e269,d8cc49a6,9ee565e1,89b6c21b,62ec7d7e,733f518,974acfbd,4f4e4f44,bcc4fdc0,cc194a66,df7c16bf,ef0235b) +,S(50bb2ad6,8d524acc,3278c0f1,538d3aad,9a5357bd,332d8cff,6301f417,57349847,d8fc33d5,d03526bd,b97d4c6e,1ef018ba,ba4b33e5,9677f139,b8535287,fbacfb32) +,S(ebdfb262,6031b4fa,d675e860,12288101,948e2ca0,8fd0d32e,c9fd0838,5f4fdbd9,b078066c,c470113d,db3964e4,466e319b,4f853a42,8951aa0a,9c4629a7,a40dbf2e) +,S(5daf4c23,65482a2f,bdef73e8,208fd5ad,d57b35f8,171541f6,3a48b742,e98bd48f,9015bfcb,5a248607,f5ffc83c,4fa3dfec,9cbd11f2,c230327d,b2cc75ca,2e87f967) +,S(22db9c20,5d840814,67a19517,f353f825,238c905f,2b12a77d,8551cc9,ee8533c7,680a1bc8,23432a28,a3219264,2b9acf0e,7ad19e29,b604631c,85f7038b,386dcdf8) +,S(404435d1,2e8be51,92625213,f86e6e55,9fb44658,44694d4f,4db72861,d4c100ae,9ebce682,b321eefa,e8e04776,8f82491a,dd734e5a,941e0f4c,b6284f78,6d1586d1) +,S(dcc36eff,6831a6de,f8600d1a,3d52da1c,fe59df9c,cc69c9f2,60c26532,e837530f,8609b5e6,7360b7e8,5ea98c13,578566cb,b6b385ff,6990d4d6,5b795acc,1f77a893) +,S(ef0dfb94,1a1c383e,4a44cd04,c633cb48,e991d140,45e2d9a8,b4353e79,9c1a1514,2685d60,f2a75f9a,b733afab,f693ed05,9c3599bc,3e3346d4,61e5c86a,f76f6f42) +,S(24884cfd,c6c3efd6,b4d2e18f,2ca66b06,410b0fba,d9d61b30,86abc537,1d766b8a,7c1cdc85,66f3daa7,d395c6bf,8a23c130,86a78619,aa68519e,4657b17d,ace2267d) +,S(541b6691,c7004a81,2c607756,f81b6f05,485b0708,678d9a45,de74632,4acd8b20,ddccf301,8a3c429a,c749f0d5,2383784,cefff3df,ae98517f,c7f5e764,c5c609d7) +,S(5462969,67262e3f,a905eea4,ff1f8296,f792cfc8,bb9dbb9a,138242c1,a1fa822d,63012289,8e429527,4fad8e7f,9865659f,da2d7370,10f6e185,70dadbfe,21e6880e) +,S(94070912,ad2c129d,cd122bb9,704616fc,3ddfd949,6ce9f6d,6e18020c,ec848e83,9c3b38e5,6bfac9f1,4c901080,b5a732a4,b5d261f8,2b571536,d1fba6d9,b714017b) +,S(2a6330e4,8ddc661e,afa8071c,c1417b92,ea73b060,3653a017,3edb92a5,6e3ca6c9,b38c51cd,4754c350,ba2d56a3,fbf4fbab,5802bc38,6b5516f3,d8b761e3,c3fc7d79) +,S(9142e493,5f95da17,5ae4078c,5ff5a7d4,8c418c1c,7efc4c39,dacb047a,d3f7424d,15165a74,c47133a9,e8684ea5,5a4f9b05,37d0ab7f,58a7eac0,e698adcc,b885cd05) +,S(2e198b29,5cac4dee,dba63ef3,888d47e8,bb8d372,7fcbd69a,d1eea656,ca85804d,31dd5db3,e700ffbe,152b0c2b,1b1c830c,eb382468,1c522e63,676b9ec,6780fd52) +,S(b44e35e9,b2efcafa,f123e52a,7bd9bc58,32a671e2,fbf0264e,5a3f536c,b272f72d,8d489fe3,beb39fd4,2632b80a,1243e64b,f80c81c1,3934ab08,71c16a5a,5aa43423) +,S(dc99ad01,e1324b6d,b5ecf365,c22463dc,f609f0b5,90e6d3be,efddf641,b83a3cd7,b4b422ca,2feabeaf,32c0ad6a,4393c087,a4c1e794,47a043de,cf0fe486,ed11b682) +,S(e174838e,eb991c2d,cfaaf89b,b868f4d1,3029ebfc,ea286376,48fc51ba,f962a359,f80dcc87,27cbddc9,4bb1b60a,4da5cc74,238dc62,821a9ec7,c05ad2a,a0e7570b) +,S(6240358b,15bd16d4,42cd79a4,8b739eb5,4ca21d18,b568b497,65d10dfa,a2583d33,6acb054d,724e7550,ed6d8caa,8a436d51,fc546116,df33413f,a613c0dd,6cec2d00) +,S(a757fceb,560aac0f,543a29b4,bfd3af7a,aa61c077,2c1c07b2,e6268342,e63f8d70,5864ceef,f80855d0,fb4713e2,7bc6a202,b4c07450,6749457b,39d0c40c,f40352da) +,S(f36e1073,57c3149d,902e9416,2e509d19,d4b1f498,bc74814,3a1bd411,2f777bba,d4d7da2d,139a2693,e40d9396,76c3fe48,45f74b43,78f0c25a,14aa9698,3bd1993e) +,S(84ef2d4b,55a40ff7,13934949,b6277ef0,4a8e0e4f,cc49420b,17269d59,224af99a,57affcb7,1d3508f,65ff2b7a,b1d6752,60465e76,754efe3e,80a83085,85ea73a6) +,S(138ef64b,274ff66d,7defdca3,4ff28bae,96b046df,408b3f47,84f78784,3fce7576,ebdd04e5,1d517c43,412010cb,d03252ed,dfe97912,ee4a7d4c,ed98551b,fee1ecf1) +,S(e82f03fe,2ba05692,212a1145,550d3057,2d454728,e2d9989b,435cb608,3d1f318c,191a6fb9,cf295881,92aaaf1f,ea34e123,613b2937,602650f2,eb25f63f,5812dcda) +,S(56a68400,676b6fac,7eb5fb3e,7f345ec0,11117098,c0d1a96b,e44bd2c8,5aafb317,3a41827a,5ae1b7cc,5b9dcb5f,4c41819e,f49ff2fc,ce1d1949,3f5b0ce,9f1dfb4e) +,S(82f5747f,1b353db4,f3afe255,e1f2660a,8f735b1a,e40a5008,4efa3c32,dc1309f5,42e8b903,f4ccc01f,7e87e4c6,71572bbf,d05f9ea2,a4cf7bd7,dd5a9906,264a0144) +,S(89136941,c47b1964,a4b89e0c,376b3136,80ef76c1,19e02bb,bfad594,76e0cf13,b3a2a785,fb6a564f,f4871bc5,177c635,d722e659,77f621a,f6f7537a,2c2d3f3b) +,S(c6250969,c98f580,f0cb51,eef5d8a1,b9954bb,97671df1,c7360a5f,42238909,83d0324c,915eab22,4dd3f935,e197e0e9,552d5bd9,6b1ed240,219731a3,58ec724) +,S(e2399ad9,63913200,4664a481,dea99d85,ad12938d,dd0e4184,27411fd4,8fc7e3b4,60fffd62,beae28e2,2ea836ed,389c3780,5d8b1fa1,fb10f298,f9b54df8,93c69d47) +,S(4d00b1c,186d2992,9a6383d6,cc8d1796,a59c5d7,c27cc7b8,5a1f821c,3003d959,8752ead1,27eb19fd,49dc8ce7,a0b7c7e6,dd4aa3dd,6f8d5cb4,687327e8,ce487640) +,S(344663ef,8b8b52c9,1aa548e9,8b7e1c48,933cbfa3,59644318,5ea973ae,9264121e,73d099c8,9dfe8eec,b957e624,bea5673,6fe3885c,e2f72b06,dfeae760,514d9efd) +,S(37ff484d,dbd22a98,333038d4,7949b4f3,f411d3d5,7ca319e3,5c788bbd,a0de6648,55a5394b,51618d81,d2fb1455,4ec1f5c3,a45cf086,83980bfb,a9aae6a9,20547c67) +,S(cf3bcddb,ad5066b,909339d1,4cc6d3d8,d2881f70,d6f12e1,4d795b06,17556ca5,e12686bc,99e20f20,6220e402,32760224,b61b90f7,8b7c0b1,3c197a47,11678a6f) +,S(961d02e7,db8fd1ac,a38f9110,13d74a5b,d35e47a1,49818d41,49f02edf,5da73402,9462eaac,d698677c,16515ca3,bff217e9,765dc8ad,fe2fa82a,1db05158,71fed240) +,S(43e62f90,574a8e65,25d22ca6,74814ac,3648b724,45a535c,5e1af97e,b46ec3ba,6def0a56,17c1cf17,9369e20e,d18d0503,e141dc85,9edc73a3,18f6a35b,3d939734) +,S(9e682b79,9d79018c,352113cf,98de93b2,457e4b4,a962d160,33b80052,57dfdbb7,9db9cb16,bfe96343,89c468a0,6405d2c9,b2983354,ee9a81e9,3f23ec5d,5049041b) +,S(790187a7,8079b59d,b2a22d13,8520192,5f9682e4,2002c8f9,436876e4,d5a1a8b4,25c8b46,f6b43180,3654381e,56a8e6aa,ade0ad1d,6a6044de,17e9592c,affa456e) +,S(928a4b8a,6c744b33,99e22d65,35a21ffd,662a0dc3,d5bab1d,683ce555,f0169583,251fee84,c064954b,e1daf7e4,5fec87a9,323d55f6,687fdeaa,75d4dcc9,9a6fcf84) +,S(684e88da,81182f2c,ac5872de,8c98b86f,a6ffb73e,9bbfbfde,6c16c3f4,be084c88,c451b59d,fc9d62d5,921ae45f,f7557ab3,ad179eb0,6afb8bb6,bff0645,cf6383fe) +,S(8bdd2e83,a403b0cd,7a8ebfa8,6949bceb,8e8166ce,a8596f6c,ad7b7bfa,4d174343,7220c147,97f682f8,7d707b2f,eec937c3,643bb359,e9effbad,8ccbc8f,a8177172) +,S(c3fa3b21,6e3c4952,85258ef5,f921f6b,b7195869,e46948b4,b69e80b0,be399543,eb2044ed,21f6661b,77088050,3026c2c5,5a519ca1,748bb10f,c8eed953,aec1796) +,S(1c063c13,eb2d2959,379fb0df,50d355e0,195a8bd2,e642ab48,3d6a38a7,af7e63a2,20538f92,d14c9ff6,75c5005c,8c40e26a,b0042874,7f446ed7,cfcf5737,870f2abb) +,S(60c06797,7b54c18f,4b82dc6c,227cb539,6c6086de,107e3999,81f1b5e0,f31d452,3f4546c4,e3eb11b2,e6fd2617,b57afafe,ce0e8bf7,aacc13b,73755f18,dc98429a) +,S(fc15cf99,92256abb,cf263e90,a231ed8b,421cdc2b,af185722,c0af008b,fea36856,abe346a4,d9c40853,70dd46e4,69a3bf24,c01dbd97,f5c9997e,27634dd7,c635d798) +,S(f6143985,18173bb7,428da262,bc8b07b8,1a92b06a,65926ee5,c6f8fe44,27249454,b1d832ef,3a2558c2,d41f06d,4be8e5e8,11fcede9,9cc784aa,b9f3ce18,d701cf84) +,S(579458a9,62218442,41e68542,76a116ab,1f1fd43,109d4bc7,ad5216dc,ee61b5f5,33e56474,68c157c6,15cc8d46,135bed70,21274a4d,97aebe23,7bdd4b61,2c53e2d8) +,S(637553dc,b0804132,b5562678,fe355e8f,abab2001,fe17e3bd,8c051e7a,41fe62e7,28bd6dc2,ad586e1f,f1a6a951,167ba14f,6989b296,874e0d3c,31917920,9b572dce) +,S(eebbd70f,6f64855b,e21ddb92,3e54f583,89e99ddb,577fa8ea,66c3722e,b580e2a3,3d1b6979,15b50345,4a55606e,ad3ac4ec,7c986698,3df60e1d,edc86827,32fd4d68) +,S(4ec8931f,2bf4b1da,6891135f,37791236,3a6e888b,6e5c5ddb,2e350e42,686c56fb,d5f6c679,4c2b306a,bd719770,48dc3e28,3cbab910,556919f5,35d9df23,56a09bc7) +,S(6b5a7f76,fc5b7e7a,7d84deab,ffd5c771,8f49375c,cc4dc1a7,35bc253a,bee9730e,1e935dc4,8fbf5f6a,b12562df,11855757,9eafb8ab,f6ad8b7a,f8f9df64,43b58af8) +,S(2a3129eb,f620958a,4264c759,17e29807,5f5b73f3,21d4cf27,683e4788,9e013af7,e940f5e4,c1fc28b3,fa346ede,fdb8ac7d,4066732f,a6c276c6,89a1921f,d1020da4) +,S(8bfe81c,e99443f3,78307f34,5bf2c826,94a8723b,c4836d12,4c6f5163,bb28b5ab,58b16e27,857e5faf,9768edc2,68d177a4,87de9848,52e65348,36464ac3,f0433c71) +,S(47820cd9,449c566d,2d39daf3,ee4d356d,5423692,a050cf83,1c1337bd,8ad61be3,48dfae03,2988a810,6d069d,22f27445,1200d38c,a9aea665,5e5f28cc,9952c2e4) +,S(2d7f03ce,8e453605,89d221d8,84c3ef28,f9e8dc52,41d7d131,cd6e9921,55a934e2,8414b3c0,5a39f38e,1f14d55f,e28604f9,16a7b272,6d6c843a,57a2b8e8,b7ee9c72) +,S(83887cec,919d8c86,c2150d4e,e842505b,f5a5b06c,b3b1e67f,1dc2005e,99d8e37b,fee0e7cd,f5c9eae2,78d34fe1,2e58845f,fcea9de7,f9883e32,7a2ee941,92b4c009) +,S(519f9e1,138bbab2,da8c03f,565c3fe0,a9d0b709,1a7b50f3,f37df191,d1ca1e24,64d6bafe,2bffce42,3f631ec0,781e96f5,ef6cd6a9,ade6b9eb,367c036a,1a61ba9e) +,S(8091f78f,84bc74ea,69ade208,72936152,3946ffe6,63edee6c,3cd13ad9,4a8fba61,1aaaa58b,af84688c,1cba5d90,d700aaac,6765faec,39e7a212,fe13a9cc,b0bda1a) +,S(50abc00d,d3fe5748,7c2a5343,4a36f10d,8388cf20,56cd5bb4,9ed8e97e,7adb3afc,ab8bad95,14b6040f,b1c64f01,d9b9db01,670fe0d9,3add5d6,8a80e41d,8ded25ea) +,S(a9a428bb,4da01f44,a9e4f253,3436ae75,20e5722e,6d12931f,aa20772b,36a2f110,ba05121a,1830a26c,440f0582,2fa53e20,f8c226b6,85b437a0,557c8450,774c0c5f) +,S(d7afdbd4,6314d677,727fa11b,211e99a1,d6948be5,b7753ecf,64e9b1d0,ac7a83ce,b5f8b97d,748a4abb,a390ed9d,79cb42ab,ee9b2afa,517288f4,80aba1cd,34e21d04) +,S(2b6b834c,d2b54466,a3d41694,b672ac55,13f19b1a,d518ba99,d622abfd,9b6de265,c1922593,ddc0b3d2,ad1d52dd,3cbeb2e5,74ec849b,892d9df1,87ccec50,7ab9b0d6) +,S(f393cf4a,d7f93fa3,1596ef7e,a9c11c6b,f29c344b,1a3ee5a2,51360c9b,a96ac8ea,4e811ca9,de67ceeb,90e48016,30d06125,fbfa56b3,35e3a7ec,41bedbaa,7a8133e1) +,S(bc3b9250,4e14b254,81305012,a248a94,bbc546bd,52fbc0e,848d75e,9c8f418a,9a52afc6,f8b487c1,7653a911,f11d78c5,8f5eca38,c761a2d9,af0ef2ad,a6a58223) +,S(2f5a0e73,c601fb8a,7321e170,4abdb1f7,e71edc3b,bf6f9cec,1467eef,5f6055c0,d8bb1d0d,142d2cb1,3b9d97f8,f807212,b79a5ecf,13d942eb,c5a3f442,6553e393) +,S(b83e51e3,b4fc69ac,84d099b9,6916c11d,8d8d8d7b,f5cbe15b,fa13ed34,73a54ae8,232e0f88,69c53923,22018084,a7cfc251,daeb7a84,6e1daa78,f3f365c2,ca3dda5b) +,S(10971993,50b07a32,1532b372,2ee89058,e90e9b30,5908cc0e,a249a40b,e7516377,69a0b67c,7bd55a04,9be3a3a5,e308799d,dc735f9,ce56ff67,2c796b6e,5a0a1055) +,S(dbeef75c,c95d5018,f3d71711,a0299dd2,62250814,c1469647,dcb27a23,e85c4477,dd4712cd,16334f8e,2baa6855,6c5237f8,676311e3,1cbf9753,35e76a90,88d66413) +,S(28cb1199,2bdee938,f3405f18,537b410f,2723888,e4ca0d29,d96806d5,6baf114f,e6c63fe,bbe5dd81,e3a9fc1e,83a5ce89,c3e2ef6c,c2a57fea,695ebf4b,e81e5aa3) +,S(f0a2df0b,64efe99e,65f9f176,89cec5d4,caef385a,e4676da3,790ba2e2,4e9f60ba,a7ca7e08,b900f664,14498c12,aaa77da6,6a2520,7bcf1a85,713b6d14,807a4519) +,S(d1bb46eb,38e54396,dc7ad4f,f553106,54fe9b06,9abb1410,799dffe5,482b0f00,14b0619f,e08830b6,d0a5463,96826b6c,d03bbd2c,af930b14,a031f922,eace4214) +,S(27bd2e56,7705126a,5f5adb31,ac1d09a1,85d74002,c548a84,15c0cce0,1f69517a,12203dd7,cba21cd2,9f9ce428,a8e302d7,202690ad,8734c08f,65578192,a5468d32) +,S(6b2cc790,1c72e201,693835ef,ab2b676f,55441add,b8dbc3bd,61d43201,bfd21d9c,59973406,deea0493,daff90d4,b62ff38c,6690bb05,18e75560,1bd5b3a3,4add7456) +,S(75e85c3f,32f953c5,632a8bcc,6bfcd6bd,c63c3b93,e607d267,5df09fb5,94840f27,22f5a376,8714c73d,96b24f89,d426e668,bc59aca0,cbf6dc47,723f01ed,6cb6bb30) +,S(d37a3071,969e152f,41c0eed5,7e28f1e6,f26e1752,68c52683,15e200b9,f86d56a7,53d52726,98751d1d,dc4b1fb,d9621723,70e296c3,b47436d3,abe20356,76ff6181) +,S(715bb304,7f5e6973,36546640,8e183bb2,67693198,94e341d2,37d5101e,a7414976,28440f5f,9e82d5e8,7a5ea672,2e95c3d6,a89dd1fb,3d81aca,db7609ee,a1a968d4) +,S(f72d142a,4f5b1595,a7b4a52c,c6812ec2,8e4924a4,b087c139,68d8adf7,dac642e8,501b644b,b5d8042c,f16ab9bb,bc594c14,585486cc,fbaf47a6,5378f97a,761087dd) +,S(7b3eff8f,b4ca8a3a,5fc3cf02,a469f34,3840846c,d8fbff28,243b962,c1284c26,be2588fd,15396124,a50bc555,5e161022,3bbf636e,fd510522,811902b5,b1748579) +,S(2441a8d7,71fbeca4,cd365225,7974e4cf,ec2a7035,ff2b58a5,9cc5fc37,8a113dd8,54b0776,5316713,4bbf4c6a,7ac23360,fe035d2d,9316cfcc,ae129893,82447981) +,S(c20fca4e,d05467ca,45b916b1,2f4ab386,512d097c,b64b824d,e78e9a2a,14cf7591,8851acc7,96ee4072,ca87e69c,9dad10e7,931fc48b,238cf46d,2b2355a,e4eecc02) +,S(2f6b0e8d,1375263,b74e415a,ad758130,a34c6c6d,690ddd67,63492eb2,49ec8e7,d0c791f8,438cf6a7,976cb614,eb4c9f67,adc72275,f6236868,e384d538,daf25dbe) +,S(bfafc1be,426f056d,6f8b3ed1,1374db21,fc00373c,3dd8c762,c5ab91ea,b2b665dd,9c41f297,a4cf003a,7fa7b071,a106da4,6dc40050,a7592781,68436115,150e2a2e) +,S(cf711dca,90560273,6d776f86,759d74f,895980f7,1728dbe9,1df93076,cdcb4e8c,52a379bf,cf25216f,e3556def,e889b23e,2f91f6a6,47ece012,4e140aa7,734f1cd5) +,S(b9be95de,27aaf198,c3001ec3,63690f2f,f516fd75,1864794e,1c3516c9,abd1384b,68875f97,dca1dc43,3e9b614,488cb8f8,1ff85d58,2ba853cd,27fc1227,1ecb6df9) +,S(f5f257e6,c4d06a8c,53442b37,7519ae03,7bec31b3,c257f331,fff53773,28e9638e,b6a1e60a,48d03213,bb52e3ed,d20d0ca,c80beaec,bb40169e,35ff2165,43e986dd) +,S(fc35c74c,17e38aa1,15803603,30af7d92,a5281b3f,cb6cebf9,df09155e,64099ce7,6e2f984d,41e8693b,5a4c1c58,9814d131,8421fbbb,2ec8e45a,c6239227,db79dae9) +,S(ac135e01,49d97363,7405e5a9,89ffaca6,c1bc18a1,cce34aa7,4732fcce,d54384dd,3e38bacd,ff954a6b,6bccbf63,9f8d709,d8e54553,6113dcb1,c471a162,af021d0) +,S(60a013fb,efb3c5d7,802400c4,e791a019,bfd8f657,cf4c1055,f3674f92,9f5f345d,7e763c48,3582fe3e,2a0a5138,ca320013,9907e364,5468b5b2,711205f3,38a1bd97) +,S(a099a106,5d907a8a,43a3d027,3a789992,ceb3a659,bef93a9,6ed04ea,19a7acb7,137f9ffb,fe3c22ff,c034bb57,9f0c9b46,d5cca4a0,db1407db,6fe3d7b,5bc5a50d) +,S(9ba1da86,d02763d6,187ea5a8,c11c9da4,c6ed7017,49f107b,9ef4fc3,94a792ab,f19e22d8,ab5459c5,5bf87908,90175184,8716aea6,5c2d9650,c472199d,6663f741) +,S(3642701a,d30d1430,17be9363,3f28d90d,b5e02238,9350934f,63a514c9,a677ada0,2fdf9ab9,c76bbbc6,c4e79f48,7a8bbd86,6432fa98,4f52ac22,3440de3b,f1aba970) +,S(29f79c58,100b7098,d8d53012,e2c98719,6188c0d,54712c31,c2ea3a52,d6941a5b,be9edd99,eaa6c1bb,d0ec42f,586a2806,919d5bb7,2d59bf3,7216890b,9a2d524b) +,S(e011aadf,bc35284f,816d5030,c3feb350,4b470d0,ac5ff061,e5ed2c47,89ba1bbc,e0a98f93,4f2b591a,36e6ee97,f293be77,21ec1a9,3f4b2700,55a0c01a,3cc979e3) +,S(a5c8816b,fe5356,37eb54b6,88b9221e,ee06a51,77ffedfb,3ed96ee0,4fd78585,3f86637b,9d63b11a,44897792,9a6aed53,7d65951d,aed6476f,e03be5a8,c9ff8e5f) +,S(3b952c23,7e44350b,95207798,e708fce6,2e6d49e0,912a2509,abef16c9,c7194707,f784972a,419e6c8a,c9d41a38,57912e66,e6ebb631,6bcdeeda,ff49b59d,bdd68936) +,S(8d9796bc,d9d8152f,80c7982a,187a4aaa,b75dd611,99f86632,72502f24,dd57af04,fb9b1479,94a31e3a,28d5695f,2d689951,317c2d2,98e9892c,89c98202,b7e611bd) +,S(96b2bc5b,2f4e6445,1536f689,d7889669,4fde4d7b,6ef67f51,84517704,6a02de40,e0b76d26,f91982db,5039bbf5,afbfce51,914eee9b,352c178b,2145c4a1,88e89cc) +,S(9bf7cf10,9f129500,e2a8f54d,8658ef97,4e3ab2b9,a1d0d036,25bef5d2,432e2d79,2113d7ad,f77e1c68,51b8bb52,188ebd25,dd6373a7,19bcc20b,e32d0f19,496e8582) +,S(10d3ffa7,20375b5e,afc8c741,4d9aa184,c91f853d,61d58dab,11a04f2a,f3d4f1b7,c1f84b2a,8a96f43c,b215c704,6f8c3f02,c98d750a,d416f21b,eeb10ea3,f298c90) +,S(56d64e2b,6adf1cd0,b8d63692,1b68733,e92577e,88430e92,c0e679e8,c3a5eb6,1370e,fbe98423,488427c2,57d5e696,5d4b687e,25e4b824,51b1a6eb,7ef71cc0) +,S(fec4a03e,1c83cf20,75deddbd,20c24792,6dbfa352,a56821c1,420adc34,731528bf,a152b2af,8670e42d,3bba0d98,f387e9bf,1bab788e,fd7bcb2a,a787e6a8,bda95509) +,S(580a7517,7ccea9ac,63ae6d53,e8959e5a,a45d11db,29a87001,779c260f,2fee92eb,793be69c,3263c64c,2048c411,115375a4,86733a90,d8c12a06,862f4f9c,669e8edd) +,S(9286bfe5,78931ceb,cf97431b,1137a19a,991b46d2,d0dec2f5,35edb976,6af636f6,7e774d30,e962db42,83cb38fb,2053b780,c55fce80,51edd5f2,8cb1b5a5,d329f516) +,S(606d55a9,9b702652,5382cf2e,efeec65a,803e3851,da60a041,e5422c1c,28f4890d,dc895a6e,3c2a6411,4a04a1e0,31b8aa17,79ae2c05,1f4eee54,7f8a54c,50eda1a7) +,S(a16a0d40,833ec1cd,dcfef2f1,bcfc8ed8,11387dc6,4e4df6,6e807f69,75f917f5,548d7d37,13de4a53,151f32a8,2880d087,7fd281d9,63011388,ba991bd8,822d6527) +,S(5949d2,be574e23,9a3e3e7a,ae20726c,4a687a15,edf5a62d,9b79d0c3,4f9f0329,71dcb25a,167ab25c,311d9427,5480f78e,f7f4e777,9723e55f,337a9121,445288a9) +,S(841f4e4a,e67b0d8a,49d7b295,e9c1ff4f,cd1e2333,82101536,cef7c4e5,7968b240,1f561c9c,265fa4ed,eb979f4,a8dbe679,ccae8037,8cd73d5c,b56671d0,571f4161) +,S(22623df8,c748e9f2,88bd4b83,142788ff,faf680ae,a2640d,dd43ec1e,46cb7442,380ef00a,dfcdb592,f964381d,ce9f787,17d5827b,494c3aaa,d5e0e013,87a55da3) +,S(816067c3,6438301e,ea07a21e,5a60a17e,670083de,b3b66e2d,c88c6548,f45185e4,5afa391b,9a95e9f1,f04f4e8e,236fc39e,2eeedcec,45026647,f5982aee,4dc4cbf7) +,S(f8f23561,4745c531,24cf6431,ba8e0425,7d28af9c,2c196485,3546924d,ce085c1f,a165067,e3b41b55,a548c1b9,3fe76b5e,bd101275,acd29e75,7f66753,6734750f) +,S(21325584,e25b8a15,c25537d4,c70853b2,28bb933d,de04be23,7753b933,57f2f57a,3708c8f2,78ef57a,f0b00d5,17f21a6f,f627b5f1,59ba1f53,d20b727e,86e873e2) +,S(b2f4f7fc,f48519b2,c00c24b3,7ffac141,88b0baac,bc915c77,845cd6a6,3fdfbda3,b206b59e,6f52ee43,3e7196bb,5f4cf3c7,de49723a,cd5b3e17,1c94e28c,7d57702c) +,S(b4e65d4f,5f420006,b7c70fd3,9564f9c3,fd9c5c53,dacae064,62212fec,ee7f7265,307b6ef2,e3993bf4,f321723e,a83ec2c4,3c75b8d,684665bf,fc073506,816bee0e) +,S(4f104593,9ac609ad,25f3968e,9798ee93,aa58b61d,43f4bab,8f2352b1,de3a7240,ed8d87bb,988395fa,581698f5,c55a5093,ed9d0a89,3f4aa4bd,186221ee,7f8179ae) +,S(9b5e74ff,e515c125,9fa6b215,7ad7529f,90018e85,23888738,d097c016,494672fa,1d55866d,4c4e30f1,7bdbf70c,43fb3b9d,fe2df3d8,41e18bc4,3db3e3af,21fece15) +,S(77bf442,ac8cf718,102968f9,49387b1b,30f8a2c2,c76a2cf5,10d817c8,7e17e302,bb0f9e61,1d90046b,1d3b1103,e6c5beed,e4daaa85,f6eee1f2,6a6e756f,d32af0e9) +,S(27de125c,d49f2049,6b028f34,b16a9988,d2f5d469,30834fe6,4bcd388b,78c266a9,f43d86a8,483dd92a,2ad9dac2,4039ad2b,84cdfc2d,323979b8,1a43de25,5cb54bfe) +,S(21bf7178,ae1d75e1,94bb60ae,4efb5a8d,7f026cf0,7f845b13,2250989c,4be9c116,6caa82ad,bc21df15,d1744466,4d3b58f8,76b52291,5696481d,434f689a,edb8d967) +,S(249254,93ee016a,41b65b7f,8289da2,dc9100f9,9c0b956a,66d245b0,5632e234,bca30194,1cb51f98,1504c536,74f6f904,d883ff46,7aec96f8,2ed5ce31,7c45b3d) +,S(d3f644c1,e3472b4c,d46d89b9,6b937108,ea8e9425,9b9316fe,230e7538,7d867f76,91822603,fd629732,a3b37ed9,d5227942,2e536ae,316bfb7c,597b2da5,d8cade5) +,S(c8461f4b,e2bd14c,a88e52c8,147f656d,915c2675,46252e89,d0337f7a,e325b261,18971181,97ac799b,3f632868,e46efdf5,fa3b615a,a8a92b07,e38ceeda,9cdcae06) +,S(b6e5f590,be20a938,c1b57e1d,a7bd6ca1,a8c2406a,aaa5860d,9133342a,c395a380,a6728cf1,a2f2eade,72d86569,ab5a6305,cf01eec9,6a6de026,ff146d5e,7d8a04b6) +,S(3d25179d,465701d0,56d4eee4,b5efc10d,8b70138d,f14908c0,3124ec95,59eb5d6c,158b7bfe,1d61d7ec,633e88e2,b3c5897a,3b56f7a2,ac557c8c,3e032a71,8b95980f) +,S(abb5d54,c7171499,95893425,bda27f10,d8515511,91af6927,9849a597,46f94d99,4cdfebcc,3be28dea,36d06e89,ff4209c3,7012ff0a,d93d7ad0,4e454422,c4b9a161) +,S(989d0125,115ef9c2,900dedaa,4e31cbb2,f1243386,73ec624c,52352907,b325c73e,d3699ee9,945de070,fc1f28ee,14279750,d553df63,2951c0c8,d1668206,94c6c8df) +,S(c4c5c5d4,29c3d1ff,628bbe4,e0edf70d,5e05db13,c82a2af8,2d0e4232,5e013884,c2c76cb8,825188a9,fc29da67,70ade97f,ccee860d,d13323ee,f2ba7e7,efa97eea) +,S(8662d850,c623b65c,8db5080a,900a0e83,be947111,ec0b9edc,3601549e,26c0807b,a71d677,b0c9e7a4,f66a72b3,2918083b,f91e724c,cf8c9526,b3df0f6e,35da840b) +,S(d26fef49,7e7359bf,33309b38,93abbd44,543b73c7,c0eaa626,cbdedb17,1d083898,ad8bb209,bb090b39,6b501ea9,a5070f90,4d60c20,d48dbad9,56d381f8,79851395) +,S(569be8e8,c584b682,7d742ff8,5b402112,5b4560f5,f173c983,8f8785d2,229d8d0f,b09381a4,a8267d89,a8d5581b,f9a49d52,47c74a33,5e26e354,22edafc7,d41b8559) +,S(de34acc3,4d1787b3,ad967bc6,c5960d8f,842f82bb,c95aa255,d4a9e794,d30116d4,2fddb41c,b2b6b52a,57cf4d3e,883d3f0,e322c40b,ef098505,b6cb3d77,a21816d3) +,S(47430b48,76dbb762,6d549b86,1742a5b3,ece85240,70dd83d5,5446fa99,c5c50b1a,d75592ba,7004573,58c6a0ea,dc8ec772,b53dd048,8ddc73e8,5af357a4,af200df1) +,S(f1d1e0b5,e6687266,ba17339b,76bbab6d,8c2d8ffe,f6c68fd7,9140b097,d6e9fe13,a56226,fc233385,349c5483,72300f97,a1d8494d,a67db50b,b96543d5,bf24e580) +,S(22a6f735,76140de1,3dbd0426,e968c374,6e8132ff,383f44c3,c0515b85,f8cdbcd0,9dcd89a8,90270e3e,358dc004,40f95a43,430a399d,a8405e48,e69e3455,fbd18d1b) +,S(2ddc5328,afd8ca0,9bb0c6ea,57442e8e,fc307b30,c29e2867,b46654e3,e1a9ada2,7b9ab90e,db84e6e8,7bedaa6e,31ff90e1,7d07793,19977393,b5fedb73,c087dee4) +,S(60b6f839,a60af52f,d30a116c,58b9c65,1fb1c854,546dfa9e,1a01e2c1,95da0fca,5e77f69f,28cfb414,be39b07b,2469d8eb,b0e74306,1d856bcd,ca54d83e,20d26c40) +,S(2790c19b,9b9092e5,cb06bfd,f95ea43a,2a1f1f28,57c96776,dcd26a7d,ddee53c,fdeea120,d04e6e78,b2387afa,a0217098,de067759,8b2bc5b6,2715d9f3,714e7f64) +,S(e544320f,9ee8bc8b,127576b1,6fad9782,db181ea3,4514f7c0,d7f9046,f5113803,b93762fb,2397444,e69b63dd,9dce7c32,3c73680a,e26b5e0f,95211972,c0510741) +,S(6c7f25ae,73e428d5,860a236c,bbd4d74f,8e2706cd,69bb4cee,39f9aafa,db55313d,d8cb8fc9,e33f9b18,e9a0864b,e58ea921,8db30c4b,d5dff091,6a44b581,c8dc9121) +,S(289d1b28,ff710d47,4d1e9c3e,f3952f27,dd9eaa3a,30ef499,121ea53b,9b93d4e8,f36af80a,aebc2dd5,84cd5cb7,245b3cba,64285932,77f4be38,cf2b394a,ee880667) +,S(f02ab597,ac01d673,25e87b5d,29130c18,2a6f4a8a,d4ef7476,b9fa1da7,5910b5aa,ae88c02a,ecf28b13,ecec5379,5c34633d,d3262d1f,65ecaaaf,fe89640a,cce38adb) +,S(a9a974f,71a73106,57732c82,d6d4c6d3,c625bb70,4ec29a8d,2d8f8418,dca0413a,c20df433,eed4e96f,d5ef222d,860ed1e5,af1497ac,cfd1dc21,26e8925b,91b372cd) +,S(7866190d,728e0899,19a0e9c7,8634b55e,4cc392fc,1650471f,4a21cf40,8d77496a,1bb5fcd9,540422ef,caa8e265,c35a1e64,29d79de3,a9369b23,3512913,ac0cfd22) +,S(c8a7ffe3,44b3b8eb,f00e4e2d,e63d9540,25cc115a,9110c773,ce0130a4,8333b9ac,ca1ffbe5,10c63b5,674141aa,5ca87246,ca91280f,da97e806,dbb523fe,5ee67b6e) +,S(6cbba6a,13ff6ad3,83419e84,e4da6871,9cc1e633,d4cf3347,2f9966e6,4f9208ba,35122582,c7893f4,4fb92c34,e9c4661b,5859889,62a7d1fc,fac8a2a6,1e214a88) +,S(e07f8dbd,691a8611,eb5450c8,2c765dac,ffe9aa81,49ba3e12,87b23fda,fd9de719,932e35f0,8e39cfee,a2593799,4e118c7f,acb0c6e,5b526bc6,894b061d,8cfbc509) +,S(62136898,32fd9416,cde720d7,1d3f32a5,51f3e238,fccc69b8,4b633a2c,86d2c5d4,137e9a4d,62247e41,8596d968,4f1e5997,791f3b6d,69cbcf68,206f715d,be784e9c) +,S(8b010588,62de6706,253eb2fa,f710c086,40a318ba,1ea684f2,3254e8c0,dba7b9eb,54a48862,dcc56c60,cccbf43c,f7a33f9f,dbd7e419,56f0f48e,2ce2371a,19bfd264) +,S(12d3908c,14af8346,fefbbbac,e56bcbae,3fb2ed87,dc30b1cf,eaf480ea,84f213d8,fc4615fb,df7ddac9,84676421,2c4d99,fef41e5d,98e5824e,cb181a98,9a67fdfc) +,S(219d05e2,a7b8cc69,bbce368f,62922992,b474286e,df7c13dc,8da62d16,1784cd2,8aee4f73,9a7eb1e7,8ee9407d,e8fbabef,dd28203b,2161ede2,761e178,a34c7f5c) +,S(d7d0cd59,9a76fa91,f691fa23,ad265f38,49bbe213,c38cb074,852005b6,d85de204,f349572c,60750dae,5ea1330e,a725a0ef,ed1a2d60,c0b1d9d1,e938f37c,911ce2fa) +,S(a3fa69f5,a04c9023,83d8b73f,6fa8fc3c,9f65cfbb,2c77042d,635f4978,eabb6c6d,c798a1a8,9994aab1,4af95b18,f389a2f1,accb2d7,59997e83,72c1ca5a,c3cbdea2) +,S(902e881a,825c457d,79872e71,e5d94170,8540734c,1d050e92,cc5c8afb,13b2d1cd,ff075132,63bf6fb9,11163ccc,f62f8246,de099f07,ccfc9e33,8ac82c30,bda62d43) +,S(325f19f2,4c470556,d361aa2b,3f1932bb,6923ea5a,4f8cb505,d34cc60e,729c144,f4a9aeb8,29a6a0cd,f981bf35,81bf8f9d,73e3e9c1,61996178,2a57c46b,9e94bec4) +,S(6994f3b4,41a6cf61,53e5f860,2cfffacc,bcdf7245,eb078247,63bb07c6,fa1edd4b,ec2fc5ea,892da897,29c479d8,d3f05152,198ee4ab,87f73bd9,27db1160,1874c174) +,S(21855832,4e8f796f,fd51bd2f,8c1f6a8,5663c5a2,b5bad37f,3b7a1052,6acb2d8c,e77ceecb,33cec03c,99690d44,b0343bf7,3b93c495,5d67ccf4,b15d1d76,a1897c2d) +,S(905daa3b,32f2a801,a567c312,ae4772b5,3196933f,487aa1b0,a5674cef,9d91b099,bf6285c3,6d271719,13691d5d,767fdc17,82b64843,5b2ca1d6,b695871c,41cf369f) +,S(df7cfb84,34b60524,75fe5161,3dbe0e7f,1b685376,315397f5,b39951ee,b65339f1,e725cd7e,1419e455,2d953393,dd9651d5,d1beb3c,6fa44d2e,e580ccf4,df558243) +,S(e7fb9efc,88842b9e,a3c96b82,1ca5eb80,385cb276,28cf64a5,d8c5bcb4,e5732491,c8e676bc,a6f9e037,263b8390,675a97d,1353c128,eddabd5f,5e928153,78f22331) +,S(d1a35f0c,272ba216,1e6ac0a3,fa440f59,bad79715,d71e12fe,cc12369d,cd24285b,1f5b70f7,d475716d,b9ef2f21,bb156400,49dc41a8,96102ec1,806b949a,c99edb3c) +,S(66ba6e8,5f2ddd4c,e17da74a,c7ae629e,4f420429,45932e5,55110da5,2a7b079f,d8ebac5b,eb8eefbc,f4da4f35,79bdffbe,21967904,36487733,263089e7,7a80402) +,S(6f7f69a,26881052,b4bcf806,575f9c50,c36e7c22,1d7b9e48,7b1f39a0,b4f3a749,11d06b84,d89b88b,ab4352b9,cc160e50,bc183558,25bb602b,89235aa6,7331a4c4) +,S(4be16d6f,571d503b,26169906,75c01ac5,41c23afe,84cadb90,eda0c21c,926c0abd,1041ede,ffa1f2dd,61a116c5,dd33fed5,d9ede78f,cb2311bd,9a04fe32,9ec1d06d) +,S(8af88c5d,b55eacb6,760abbc7,91698c57,19160335,ee569bd,33bf050b,1e75886,4f5b850b,6bf2b4b1,29aeeb24,596007c0,ca203eb5,d2be6bea,f61bf596,bdd9a12c) +,S(ad33e77a,3316eb8e,1a764849,13915e81,edb69518,8ce7507,2e2b6088,4cef8672,fa0161e2,4bc88bd9,da5157fd,7950c75d,6c4f4f89,f158f13f,16ca5e4c,af7ccd90) +,S(444a81ef,7620afe7,91d96ee9,b1c34485,cdb51e1f,6022dba0,69ededb3,d9d8c2bc,a88017d9,a49d4ebc,2ee811c7,fbfcd9ba,bd268329,1efafb52,e641af11,9751e2fd) +,S(5b1e07a3,9530f8b6,60787e9d,26503a2f,77af3ad1,24ac8aa5,1d10b663,ceaa5c51,fcf4c0d3,8d55e0fb,2731e59b,686a806a,e87cb510,7bbd013b,4500c470,f77810b9) +,S(3e8c17,e986a86,57b4c403,3317e67d,b1d42e7d,9625e844,ba533ed1,73174309,deebe49f,f4f5a35d,ea0f396,63c7ee0e,9db702f5,c296fe5e,696f5521,94cd6caa) +,S(a1096eee,5e9bcb19,9d24c078,b46b528b,6432af90,7f1d57e5,746e83d8,4d112c1,bd13e4fe,699436cd,656b3019,acd54f3c,97eace0f,e1e92fc1,3f08a76d,d2e7c6d4) +,S(54758579,4218de75,db40a6d8,99a75ee8,36861093,4ded0938,98c071b7,6665f2f0,3bd55642,13e1c689,70cdcd94,fddaa656,6bcde4bf,29c761b5,c6f613f6,19174548) +,S(4eb32992,fcb4bc44,bff56604,f4f74586,a4400290,5ee9adf7,f7bbc694,45456057,8576a8f2,68349f01,ada77c67,30510030,e0cc9d8c,66db7609,21661540,ba45c3d4) +,S(350b2def,d2eb4933,c6d428e7,5990a7c0,f291723,f92e5ea2,69c5b4c8,b661a22d,61acdb00,add9f34b,f36126d8,380ef5bf,70f807a8,1320d59e,3540fb25,90de6943) +,S(914ea8be,ce7f8819,5337341e,eaca129b,2da3c96b,306b017,d7afd984,75f360ff,f2aa5548,ebef80a7,483b563c,e8b242db,582948a4,9fc89213,d3272a63,85ac7b53) +,S(f656e17,38da25f4,baabaa6b,d70e3f5f,ad6d44f9,c53e1a33,4596246b,83dc0fef,40a8b4fc,34639287,a65f53c,f373c2c4,c742ce4b,2040fef5,4c31dac9,59fd83e5) +,S(a47c8af0,334e3ce5,464310bb,c0daa66e,d77e1023,a2124182,ce3e6771,933b618f,6dbccb54,56d7c75,5e71694f,fa1713eb,41ec5b2e,8715ec4b,52295294,c0c7f08) +,S(a8a2862,5e1d04a6,5e87947f,82178d5c,3b5fde31,1eace688,6766ee9d,30753ca9,f82ad6f7,483aa04d,a79e672,efa109be,1feb3f75,d73923ba,94df2f1e,2efc2169) +,S(a01ff54e,5f8eb855,e26903cb,3fd407ef,4fe06208,a0f44837,1e83f7a2,31c017d0,2247c6f9,c52f1a68,84c18ec0,77d92514,9fd59b00,27663ee2,f0e5b2ee,f2edf92) +,S(e7b09c3a,626ac89b,6caadbd6,99a320c,61ef4fe3,11f6072f,f2d7c875,8d42aed1,8ed996d3,6a7b50e9,8e5c64ac,e03cf5a3,37c3c5a1,6d99c5e2,c0faefcd,38609fdc) +,S(3bba9e53,336c2a06,ca89fb52,26059041,96307c97,373cb717,3f35a45b,863ff2fd,f2fe9109,3faffc16,f58ccaea,e54e9b8c,419d5123,6e8c960d,52ae8341,27d24799) +,S(f61d22b6,dc660174,22122400,432f533,11950c21,b6240acd,af905f9c,2c0630a3,6068f5a,1a662cf3,93eb7e86,5cdfab18,692bb250,15de2796,1421a457,49ffb05) +,S(a5b60855,6b1aa22d,8bc38dcb,8f3e4721,891c45dc,2702d13,7189be70,e8a80962,f77f97d2,d5e305ca,1fe20b99,e6c182ae,3a9b3a69,7cd5e34a,7199032,fcb1ddb6) +,S(70c3aaf9,eb2562,e1cae950,be6f592e,f030301b,28022ac1,be3aa5cc,85e1a259,3f2cb7cd,31a8d319,ce4626f7,213aaef7,3f91f2be,a17addeb,61f217b9,4c587583) +,S(1dd70dd1,a8755e37,28dfcc4d,443e7911,a67952af,c33e7d93,b975d136,8d06e530,4684f974,1f5894ef,47040074,2ecc73dd,240e677d,b6bee0c4,141dfcd,7190d084) +,S(d44d698d,7aacfd4b,d8d6bb7f,2d0dca82,f5d37c3d,46573546,2b180cc6,9083fcf9,a18d803d,4232965,90c67b0f,4c415bd7,c0c94041,3740be47,2819bebf,87dc407) +,S(84589ae1,30455742,85522ae7,4b1bc3bb,62730a10,6154d9f9,4109c010,51b34ca5,b979fa08,f2a9af49,bf6ffce9,b2fa707f,de14fcba,3de3b903,49bf6235,37b3606c) +,S(3dec8fdf,89118996,bed31c1e,fff15c1d,bc84e73f,fd04c6f5,469d2f04,8b724627,b143f3c1,e20b5bcf,dbd1a555,f4ff88df,dacccaa2,bfd4310c,16ae2710,1beb2c8c) +,S(367a5fc5,519dd9c6,39bfcc4,70ce465e,23a8dde,417b412a,2f0f4374,8cac160,5b8fbddf,2c6bfc90,e291b136,a3e0f8f3,faa64820,97a87cc2,dbafac5c,a7f021a6) +,S(8aa5587e,7777606f,60bab6b3,20d88e93,1e7c2efd,487bacce,5fa3256c,9463efc1,ac5ba76c,98bfa132,c16921ec,aad52289,50beeb34,449e0c18,88a39fd1,d3f091dc) +,S(79c00191,ea632ea,30fd9e6,b0d11c6,af3aa441,eca678c6,a5d6bf3c,c84cae0,3f954070,3b19a941,3ac0b659,bf401c2d,ae9c8bdf,2bd19e85,472d2d82,39dfb899) +,S(c84de722,21a59e95,cdd951a0,66483255,e858aaa4,ada498b3,d4ef8bf8,3a04fc8,73cde958,915abf28,df811109,a6220449,548fcd2,f639102,158bc451,4af0a0b9) +,S(8b1b8c50,c6327d61,e063822b,2a3c5935,fedf74dc,fe694c21,8cb6b892,b5a9d6d5,57bd8952,9f156435,f47dfc47,9ff4314c,c036766b,5b6437f8,41f60cb0,fe168b) +,S(b45eec8a,3ae82f98,52117c4a,341f8184,33a31ce7,719d7650,e783fd52,48702c52,cd556b5c,c7086b4f,905d0fc,ea01497b,25411785,9ee9046d,c988c6e1,9e0a1c90) +,S(a2d5dcdd,d93096c7,67b4871e,ac58cbdc,31ab7013,865a9cd2,c5707780,80757319,7aa406b4,b130b23e,9e6b5978,b1e0b537,227ae8a8,af62c1a6,a6d46ae,4b064547) +,S(712036b4,e5d35950,a7564ea8,3509bec1,e97f6e19,121ae5db,3d314c19,b9ed2b2d,25862ff3,8d0560ea,4698d2f,425342c8,e3a32232,f9c9572a,21d7414e,68a93616) +,S(5bcef0f7,d70fc8ba,942e58c8,79afc973,dca402e3,795adf0,7562b552,f0bfb392,7cc85a4c,ecb45bfd,3efb0e12,c3fc56f9,1a444ce4,73256474,54ccb089,baf1919) +,S(dcd5702f,9d508a1b,afab9f0,af5c4e9b,b9e5f214,6767ab0e,b5c1d859,39741ada,f7eaead7,ea13e3a7,dccd40a4,a2526501,3369d558,6f0c735f,9eb2518e,ddcc1fa1) +,S(2cea30d0,4f629d,91c3ade,1b8b7176,363bfcb9,25d3eec9,784b91bb,e6cb3d9f,a83f4bad,a42ab171,cfc9a76a,a3dde34b,c48ba454,b39b36e3,44446096,a1c42624) +,S(858b41f2,767b191e,df15fcb1,3a41934d,150e54d6,e95035d0,9c6dfc7,a1c32f8d,8180b97d,76dc95f5,478a2172,4802a28,b34d6e9d,f65d5358,e5cecf82,9fde8dd7) +,S(d5c98002,bee359b8,6d1234e5,ff418013,3eb9a668,d2f1294,245fd020,c30e81e6,4e522da4,cd2bc795,65a2e4e,e2fc87b7,a0b6bce9,1d90376d,921aeb49,5b3781de) +,S(ebf9162,2f9cea9f,71a4ddf5,82de4b7d,34002d76,da8acfb7,d4d6c3a1,9520c1ed,eee75322,3e1881cd,8e3fb483,318c75aa,7e43d049,8e53536e,cd481d18,5ad4e251) +,S(387f6a9,d08756f3,8c2e111,af74be68,acc4504,f3669ff6,b406f6c8,a61db4d,288595e3,ea1d5f91,26df96d5,dcf5cf4d,ed0bbba2,37224c4a,59db552e,87cdd28a) +,S(897ff1c0,989bd52e,383a2d70,e5920144,9aa409ee,9fef20df,25574956,dfe46714,3cfbc0c9,308c6529,f4e95a00,644a873a,de094069,36dfd6c6,bcaecfa5,9adc9d1) +,S(3255a8a6,8e0484c7,8b6bbf21,e2d8b24f,bbcbb337,6f84feef,b577ef1a,b5a395af,17b3c002,f9204b84,e6d4a426,d2d74893,79ef3fd5,441e881f,d8122599,2912aeb3) +,S(2ca4a952,d4d9e3b0,3943eeaf,b1eda225,1fbca101,e7071b7e,2778ef9f,ddc55599,bfacbacc,df02c18d,f81a2c04,4748c7eb,e98631cb,63ca16a0,9892e163,23891e00) +,S(c3e8289c,478c334a,d47b0410,e1b6ecb6,46ee5f8,8a4dbd73,10505f6a,de4383b2,5792c2ce,b0431238,647f4309,cb4ed220,229bee,2727b91f,de4004b3,d6f0f55f) +,S(2bbdef60,a86292f9,867ad63c,67f98420,86fb968d,db92d9d5,f87bd27c,15119049,f4a4b762,3536c479,29099d19,3d40d4d0,e75dac62,54f03538,80286756,60a85362) +,S(77a6e090,9e7dacb3,18014ef0,714a4be1,fe3ee47b,e22afd2c,e0333cb9,ff2496a9,54f0e475,b1a9906c,d1d915d1,81961492,34461e27,e163c384,3815d188,5251065f) +,S(d195b96b,78719254,deb4f413,979f64d6,ea94d5e4,79350b11,45c39e45,4f40ff0,238a4440,613c846e,9472d4b2,b0a4db88,b8245cad,a5af469b,d997f729,c0e0636c) +,S(c39aa336,208aa65d,75bb0f3c,6084f414,ad024d15,48da5bd8,113a619b,4815b1f,7aab1ed6,32741dd4,14883b22,6e573ee6,455a0053,6d849200,4b233153,1126fe5a) +,S(e80ca23d,baf82db,cbe0bd27,24cbb31,d6661c70,44d8a8d2,2967764c,fde31f30,a153d1d4,73187878,bcbc583a,5eb83e5d,f67e8142,46861713,8c484744,a597451b) +,S(395b7a65,a5a9c23a,f96723a,4d595a7d,f3e8505f,e0aec120,711cb7b0,2e72ef80,59020dd5,47476e39,36ad37b1,9a256543,4f88cf03,2992f4b6,2229a5e7,e49bf990) +,S(67a7e8db,b83e23d2,7b57e2cd,9512a5da,e8b49545,ffef2577,644fda22,910b495c,7c01499d,3791b9f4,100a89f7,8e80b410,41fd34ee,68ce1f15,a8753032,e8965735) +,S(c4038e7d,76d2e7b0,86986395,2cbe2ce3,ecfb4b08,61423892,ac9b3b3f,6dc0c7e7,61bb3b0d,9efc9b7d,326a27ba,bc34fc8c,129460b,6642629e,72f20351,65e92f3b) +,S(7705a5e2,26a4d3ae,ee69c52f,5fc3f575,b9bdda08,70a19a8,8a525698,c3a25e5a,458e096c,f01906f8,c2426973,d1c6a982,44be9e02,22406207,3a883e4b,53c7a1b7) +,S(f3ce8bc3,5958b5e6,16a994fa,1fe0396,68a5f1f1,b464a875,9e4a3475,34ff48d0,9c1a1d97,be3ad78b,67c8c441,f7aec63f,8dc92aa0,87500d6b,222a2473,e10058fe) +,S(905ec120,de69cebd,b9a9d764,e01d6f88,3ebb94ad,af5685d7,6649e7f3,3ca4e0d0,92617e99,3974aa3a,774a75d0,e51c00ca,4d42ce12,d79ab0e9,3a8e449e,9ca9d554) +,S(b1b74a4d,a3578592,8bad0edc,3664c1e1,27d48447,fdb246b4,f15ada68,9b21eeed,c43539c7,b84e9e8f,bcce3823,1322c4d0,c14e4d90,33c4e132,8f5b26ea,9d3206d9) +,S(d440165,c72f2d46,b2fa2a47,1c42dab7,8dcf814d,12d3e025,bd5fb963,3d8bcf1,e0864950,261f5fac,e97ad9cf,fc7683df,fabab749,1d80422a,ca30721f,5343ae3e) +,S(ff524c4f,722c19a7,f7b910be,6d573a57,fe08d5af,6580aed1,de03f939,5053b303,fd4ad4e,5b25aa8b,b3a62dea,b320335b,5b9f1368,62f5f913,98fbaa61,b753bf0d) +,S(effde0bd,331c1083,e4b76a53,c9c1ba43,8fafa2b0,4a3ada44,63a5fef1,8d8d091e,fd7a869c,a75c2105,e6ae5420,86ccef0e,c563bddf,2b41ab9a,ee0e14c3,1d947dde) +,S(a5e746c0,99c8d99e,88b4a304,b583adb2,1115ba64,e409d278,f40c4571,2f3875e8,7f832112,c2af3830,2c4baba4,f073f7fe,84170939,dd9e8c07,fd2c1eef,2e934a68) +,S(6accb9e3,af5ee943,9d8daa72,2fe45513,7df5e274,486fa46a,1ba19093,32ccb431,f0de1658,842d6580,507c26a9,b68f92e5,a3faf108,1fcf5dc4,43ec9dc9,9f28dcae) +,S(c813d055,e40d32bf,6e8e782b,3ef85698,b86f3d31,ed0123ba,1ec8978a,f72b6d4e,baf6d757,2f924631,c4da4191,684c6280,47d37ef4,2bb9528d,28879011,8d068ca6) +,S(8b882012,2cadfc62,44fbaeb5,8be4d587,599dfae6,2fdf1177,38a844d,97c7aaf9,f5e6c293,ac900da4,f716e131,fa5a42a8,7867c8a4,76808b2d,4093c782,6f7a6a3) +,S(8f075050,f49ee582,b54a5acc,4ffaa443,bc02ff34,4d0717ee,9619d83,2d7310ce,13b901bb,7ab3d325,7cc555c4,a4799a3d,f1f9f9a8,6b7021c9,b99a1315,b5f7fd3f) +,S(bbc852f8,cf643e54,3c65fb1d,f2f72c97,89a456db,21c81f66,921d411f,b0374c58,ad08eabb,e7971e24,b2bf604c,fb248b3f,a27e1c2f,84f032cd,4c14bba2,b30a590b) +,S(2d77dc4b,662b55bb,878edddc,9dcc2dcb,9278cc,b1e549fc,ffa02503,1a80bc1f,288bb0d8,4fa7f2a1,ad1a62f4,e76ef6ee,c07707a0,89caffff,a8e60870,ecd058eb) +,S(bc83f71f,f3b4a86e,b9bdf7d9,94bba6c8,c90945ab,9c858b4f,fea7914a,d7ccbdf9,18e91fa3,e5067d23,809ed455,3d119541,fa3c2563,a3a88b30,20d3e49,4b232292) +,S(7d5b9657,8d9b88e6,b0e11b7e,847d0524,45f83dc0,e2bbb7b3,205db435,2c200919,1e689f7b,8830c10d,c28e7230,c569af4c,b1c9e672,aafd4d35,2faf5570,90515ba9) +,S(85e9f364,8d758688,31dbab4c,7460c4a1,51614887,cacc3cdc,1baf928a,200cdc80,7f4ce518,d5045c0,5865224c,c07f7fc3,5ba5e4f4,c03ffa9d,d5f8e5a1,31369e27) +,S(425390df,c1c094bd,34855816,dbbdb71a,9c1d1077,45b1c65d,a101d974,4acd0810,81f14cdd,20ef4d70,69026d94,f09de176,707547c3,8c0f27d,1e277d4f,1f49bc00) +,S(3cc7cf0b,66dc93ac,250d00bb,60a0f75a,dbb59409,bf8e4419,4cedaff6,413549d7,331a632f,c3dbd899,f688bcf9,9df70e66,ae17b719,a2beb23a,664c1d6,1c204a58) +,S(fd72088d,b8a1bce8,8fc923b,cff789d8,9d6a0b2a,2be3b5f0,17e2b3eb,ce70853d,d3912b23,a38819ba,eb329638,3a0bedd9,93db4aa8,df647494,b710dec9,9eaf599) +,S(3e558f8d,5e0096da,4d8940af,9a0baa25,c7318541,c7dd37a6,b72b35ac,efe65060,2a403d7f,69d805c,3ebbdb3e,fba95b87,f78f6431,7fec0dde,7695053d,e660e90a) +,S(70708223,f525f222,16c00149,fe1b745f,721ec32a,90fd0b01,e82f2049,d8694a7e,ef4ad787,f0b4d53f,19d86ac9,7d943b5,fce17d88,6366354b,410dabeb,efd12569) +,S(eca29625,eabffaf6,4b9eddb7,11e4cf76,440b4a94,def9d2fc,6e5e9114,aa414f72,f1f83875,75afa3fc,b23bb227,4c5890cf,f798b628,283989dc,d3538b8e,237618cf) +,S(5b7c4750,542df0c4,c4606db4,6861925a,da7423a5,66d6c108,77838f65,5f297695,42811366,1ae1889f,d6ccb1a2,4cd9a6a5,de04db2d,5e805079,5f922b9e,791f784d) +,S(af1a5fe6,40cb2ee,d36982dd,1e7882fe,bd5da168,8005838c,b379b986,bc012042,71570549,305fa634,a63d12ed,1fcfc8a2,5768778e,863d4778,b7e41215,ad3e6224) +,S(727443a2,46787e70,f83cd1be,1189c4cb,e1e8b18b,1d57746a,9a319676,9366b1d2,86357826,9bba3e89,a12565cc,1770e5b4,4df56ac0,d202fdea,d68928d0,6d16d540) +,S(967979,db34e62a,149e6835,213991f7,ae2c9a2b,abf3d255,6c5e198a,12640b8d,99dc1d4f,52445651,3cee44ac,3bf3d1ed,8547b827,251b3b01,4d4c07c1,fd9edcc4) +,S(794009db,8f3491e,27ef9d73,905b06b2,be56937d,be57b8b1,59dfb883,af203601,5a6ad64d,7ee5e1cd,15a6a087,289d86b4,5db60d24,243917e7,50eca61e,2ada40b6) +,S(87cbda39,6f90b090,dba9470b,1fb0dd1f,d2f4212f,50791511,cf6297e,a9851d10,9ca095f3,a2a4f997,501fb4c9,c5585dc7,fb8f7952,e11cd3e7,73a92005,a41b63f0) +,S(9ed57b03,475d1752,58c20772,1be7e12,cd1f3ada,5b95fa8,4b245b01,b910acb0,d58c9054,43bd81af,85c58a7b,d0cb3e8b,25310644,8e1ef50d,324eea36,a3bbd5eb) +,S(ef8d0a22,92ca4498,2dac77e3,86113363,35fd9521,fd266be7,d5d354e6,28b0402,e55c4b4a,556881da,a4a23e5b,677c1a9a,f2f547d2,e2b4037f,f9758a74,3cb58b6b) +,S(6dba21f5,a274f29d,502d369f,4fa4ed08,2299f6e1,b12f5c75,abd01597,d127e3d9,7685f72f,a0ce41e,8c4302de,3e6e9c81,c951f69d,d2df0f3c,930da77a,51a39d94) +,S(8cdc3ebf,857ac235,7dc1b0f4,26ed2a52,7841969b,7fb332aa,6ba44693,c8399a3d,234dd3c1,915ac714,6cd8724,9b68a19b,df250dab,2748abec,a5876fa4,b7f910ca) +,S(a00829c8,caa665b4,7e3391b6,f4706898,a9c790fa,29344de1,e88fd882,b5eca2da,b7c8fcc7,1e834cce,5884b129,98318254,23486297,6068eaa8,184b5316,fd424110) +,S(5872f762,446cbeb1,4a12e54a,1d4f22d6,a4ed5b2e,eff7c5f5,640801dd,2149ce6a,8aacd3e8,862757fa,1a70c29e,24364ef4,4c37d5d8,bbacde2a,c75a0c1c,28ee198f) +,S(b70ed5c0,5dba7150,f22677d2,e5b532cf,53e7ceac,919d3b2f,ec4cc6b9,2fd34f2,7e43f528,cc74171c,a2fcee0b,18d8fcb,76c3d69b,8560831,26bd4482,a4d28cf8) +,S(4beaa213,3c6161d0,c7da6d7c,8eb09cba,2e8ca505,a790a7d3,9d0c16b,8053bb52,da4c083c,9cbdda2e,c6626d8f,e4b2ee13,703496c,c298bffa,db1acdca,99d4f6d5) +,S(a8d31ec6,53ce1834,a78de363,c5f9abd1,8594b34,4d34f5fc,8a10e81f,5804831,b4d6a9cd,7cbbe370,9edb5601,cb7c8ba4,8c462c18,594a4bce,64f4c286,dac5cff9) +#endif +#if WINDOW_G > 14 +,S(a8f11586,f3df4945,a753c485,ee0fd4d,e410771d,bddc1b26,c9ff10e0,77b915b7,a4ad6f16,dbd741bc,71b2dfd2,dd2d340,3816bf73,4e73cc10,abcfa6bb,d0f161a4) +,S(13e697c3,812d4772,254082da,372892d4,e1a66e1a,eb16bbd4,f7a0d531,c979cb2,87fa7baa,f6def12d,31e42c14,f672c0d6,a9d0e2e1,ceee2546,d65bd01,c18df57f) +,S(3cae4590,821a9697,a5963269,b44f0222,98f60021,b6048b3f,49c6fd4d,8650c7a,e03f8745,60418449,ad97f28,41664745,349329d,268c1c43,86e25147,6e44b234) +,S(6f42f6b1,cb6bbe13,cf081480,766cbb36,9d2e63e,e691722e,ac81621c,66e0fccd,e5d8f8eb,67702ed9,e33c7b71,e3cd7b25,cc9cd315,314815b0,b67e8622,fd35f022) +,S(43d24bc8,469cfdb7,51ca7d82,98727059,6fac14e2,11d37041,370f3bec,90e411eb,2129d618,fb1f7030,9715b2ee,d8e70aad,8b172b74,425cd747,3a3fe40,d7c50dea) +,S(259170e1,d48b6f36,6a281592,3474f0de,434f4ccc,e45126e4,a15c503e,c1f8b97c,9ec06188,dc194bc2,be131217,bb862943,aa9cf36b,7703c45f,b1ffd282,c3c12549) +,S(18d547f0,426139b8,7837d1c1,ca0f5f06,883581b2,c001e8e7,2565c9fa,80fa2719,26d9dc3,e1145ccd,23ae36e0,5c133f6a,5ebaa9fd,bb954792,3e762a8a,9fb60260) +,S(23b5936b,f2dc961f,2fc93814,4c96232d,dceb477a,753253cf,1bf05713,1b9e58be,9b678070,1bd976e8,8d66e740,2c00bec8,e4fbdaf4,976289a4,4391b28d,45519b07) +,S(46de46fc,209df62,6185387,938724fb,702c3239,fcf29113,2807894d,148774f6,cdc2ab0b,5d37a348,1b44de55,d9c50ce5,4322f8be,6f284ed1,ee49f04b,65f4f2d8) +,S(d3b78208,f5876faa,c4d3c970,3a87a586,e897c11f,dca9a7cb,6573c814,9b5d5da9,112ecaec,9f4451ae,23485579,9cfee804,ee053df7,8e65713a,cd43d953,471863e1) +,S(52d51f46,ac86afc,391e6a1d,8ab1d862,2492ae18,b3e86f13,5e42fed9,4cf3735a,cea47627,e7eefa90,7b8bfd12,f3212ea0,bfaf9e00,f407bb4,8a86039,d4815215) +,S(46451d04,48f3f959,e133723e,b9138a73,b3877adf,f294ff15,6303a845,65a4c39a,fd1c4a00,bbd9aa06,afb14790,5c0530e1,d6c3b5da,c9001b9f,8ec76df3,c7bf3c76) +,S(a12f5e51,16c58aae,90d8532a,9182d54,f539014e,e2d8357e,5ac7854,26fc78db,3db94e9b,f37ced91,7c9f466d,2a6db2bb,21725e9f,f4dc1482,3e6e384a,265e0cad) +,S(98999fcc,38fe6b71,97ebfd61,fe8942dd,be944f98,6f139c4b,7bd6bd3,28ac250c,48adfd3e,c348281d,c23335bb,8702cf8,acbdfc84,9ee34a3a,14bf36ca,b7dd0ae8) +,S(8ac22420,f9b9aa05,705b31f,bdb57d05,218ad72,ce09b489,4d0b515b,4e5940a8,37a7e2ca,442b2446,686f91da,db6975b,6f63454,e3a96df3,de8c62a4,364d30b6) +,S(cd0804d7,b1aea00c,13a94a33,f75f3736,f5759080,96a2d418,c5b54c72,de31d619,c7f68576,10df1c38,6e677bb,dd6dc121,b3d9e9ca,e54d22bc,a5ce1184,a3dc755e) +,S(b6c4bde6,2f8fe3d7,3c32e641,573098c1,c559e847,e40f60c3,49d40050,49b0411e,62c691f1,68510458,3e5191b3,758d7e3a,b2cfa31e,7a00d7b,97e39f88,786f9a9) +,S(c20990dc,70134917,42cec766,8b725c26,d918cb46,6cbf7ebe,7b1f37bd,63d5df0a,6f1e71ce,e28b22e1,9c6f180a,4d7a48be,9fc696f4,cfd418d,134c1196,6e285d1f) +,S(ebf16672,45ac7f7,385b5356,dbf977a9,3602a11,40ada114,7face805,dd93f9fb,24b15faf,3b3ac9f9,833882db,b81a976,9a37e6ad,1a4228c9,a4f7d0aa,fcca3400) +,S(1c620657,63199ded,804deefc,c33822f9,cf3d4c1d,72f2022f,37714eb3,83367621,600221e1,48f74ad4,dae118d1,b6dca782,e00117d4,92881c23,b5a7cb79,86cad767) +,S(40b300d0,7520348,38bec63e,f155b527,286db841,754702d1,d512c183,345d492d,29305ffb,31b1feba,abe027b5,f432679c,e265a57a,3960b8b5,a66e6de9,5a10fee6) +,S(5768ffa5,c8b56772,1e10c2ea,421afef5,dfd84120,a8d40e13,751a895a,fccc6c2d,52ee5ce2,e60ec485,7ee62e81,fb2eb118,4d2a6ecf,d8ab7e09,dd728d16,5e508d30) +,S(d906e71a,b6bc6697,858c66d6,82aa85af,e8d80ced,5f470ac0,8158b5aa,4cabf2b7,c75ace8c,74552756,8cad89e2,201dd954,bc6f4ae6,3a671d2c,9bed78f6,40b7e70c) +,S(f71937e,f4553a81,a3f155d2,2f81a5b6,e080c0ac,bd8f5c5a,fd437960,6a63460d,d6e4e57d,422df901,e6292a28,c83c3bf4,136b5700,f6da0351,33099feb,f1228b19) +,S(3c498699,da858f1b,364c464f,b4317b76,5d085393,1c187888,83072cfb,39ee337c,cf3033a8,9749a0f4,fd4ad867,67b919a1,c946dc67,cc46524b,af5c0015,833daa0c) +,S(c416570e,cbc5576f,97090660,438dc3ec,be269c42,6e36fc44,45d53b0e,b2c5d54d,cf6380d8,76e20ce9,5cc181ac,4fdd42c4,b91d7132,d1b1c19c,4cc0db01,4ed782e) +,S(8f97b2bd,344fcf8,62846992,e826f5b6,7fe7d103,28f34231,8a9f7de9,20d71110,e296632,fe41f8cd,b3da3ca,e1c356a4,2424c649,11dcdd58,c21aa1f8,cee07ec0) +,S(6283f371,8e67e917,5b8c1bf,28e66bd8,470dc4a0,1a720a8f,cf1df325,fcb0e10f,5e80225c,87c0d6fe,3432db79,e8cf4365,8640ad4f,21efd2a4,333eb6ae,a46bd342) +,S(9e29c616,ba66db06,bb71e56a,2a049727,e07b83ff,cdbff6ab,898a73a2,f2f9d58d,b5997133,bdfa29e4,431494f2,8444f186,7c4fcc1a,516ca195,c8eb6fe3,f5693dfe) +,S(7a0db51d,56a2b33b,8ab33329,a1d41454,a30e34fc,3db33a31,45c1cb07,923ca061,334164ab,64cdd8fe,9a106f2d,156a16c1,5da4f07,fbd7f1ad,e9d1fd7a,c8630fc9) +,S(5994233c,13ba74ea,19c1c65a,c3653a6c,cef79c4b,bbb827af,e736545e,33ac05bc,2175bea7,3090437c,9af6f994,b33023b0,5fdb278d,c0c59063,eb3b805e,a6b6bf6e) +,S(11e13de,2371f715,4d15373d,d52c504e,50811146,10ebeaa3,f47a3335,ee4e17de,fa961827,b81e71fd,60696d97,17820d67,ec86e8b8,74d3d4bb,f50df644,61f738b2) +,S(787099cb,c8896328,dad08bca,4e682e4,90461574,29aaf740,23795a1a,47f25ccc,1ea5755,bd653ed,ee7ee8d0,b3e6214,df2e31d7,731a1c9e,47a95f46,8c3c8ac5) +,S(c644c88a,fa42bae1,27bec7d9,528cd695,7bf7d906,942baa4e,14ac960f,46469cd,9d7b39cd,22007b04,f61c5905,3a3b7614,81dd45a1,532d395c,baf8ffff,377f2644) +,S(79d1abe5,cdc8b0c4,9508a87d,46163d1f,ada43640,ca1a5e89,d2f1c07,8c58820a,465cdc,983f1be8,948b850e,a9a4d9bd,f3898781,65d5a186,1c94d3d0,3fb9289) +,S(e8d4fa8e,db2a1612,d7b6fd8c,d6aa2f1e,a8f1ba1,32572d6e,dd0826ce,bede0e55,92aa3d43,e944d032,afa03d23,dcdb4604,56cb0363,1fe2f8fc,404dd9f3,f832f065) +,S(6f99e75e,b09110e7,3d5e304f,bf569037,577554e,51861356,40c2c69f,4a92e88e,63b5bf05,c554aa30,261a09e3,b292b9ce,8f1bcbf0,ad91c35,aed04f31,567757bd) +,S(cb089170,d912f8ae,e59f21f8,8860c0d5,182b5252,3b2cdf35,b9795d1f,20c37815,4e8c5b3b,6d79cab9,9f2570de,8c58c34e,6b6f5e19,b285bc4,6988ac86,20e645b5) +,S(5c248793,51e487d3,af1b6d16,b25367fd,9d2b7185,9923c565,5d7567d8,ffd621f0,5806bb36,ac3cca86,2624401c,27c54e90,c76fc747,7e83e6f6,ac89f22,35c84211) +,S(f1d10f0a,2ce54b90,ee71ccdd,eb6dc4d4,c2cab0c9,5cd35bea,5f20d3b3,51d15896,7bdb4d3e,cc613f8a,8fb84d25,541970e0,6c7385e3,c04022d5,82e2efb8,4998eead) +,S(536a5966,b594b460,bd27b4f3,aea6b555,95940f06,311970a0,36dc0fa2,3a274519,c44b0b54,cdb4eb87,b5d70d9f,bfd4a601,5c34182a,31a882c9,880878,7910b3d4) +,S(7f8165ce,ed27a393,41d542e,ba9ae875,554265f6,1c1c56c6,cc0bbd66,2ff88686,6993724,26c18b1b,dd1207e2,f3bcc0b8,673f481a,e7638d5d,45134835,9b4e39d6) +,S(12214607,c610d012,83b9265b,c59d7458,4e0a79f6,8a4e8535,a72809fe,11a6830a,5d26e498,9e3edaf6,27cc4bb7,105ba8de,3344e506,d9bc9a33,8f1e3219,e473e609) +,S(9ad7f097,1d1c326b,8ac468ef,706f53a1,9e8fff25,8e599f0e,72acaa15,b21d58b7,2e7c0921,2199c7cb,da8d3645,a5bd7831,4234849c,41a238c2,a3dd7fad,fdb8a880) +,S(355f75a4,9df69d8e,4ccad41b,1fb0445f,619ba9aa,34697a5e,24ec8e92,f5b41068,9ca83421,4622ad8a,90a09469,d155bbec,717295ec,c071894c,6c91a7b6,e1345f24) +,S(bcde8058,8336a996,fa6af5bb,5ebf7441,ed3bda73,4802ab5d,5c0eac31,8017c706,49e40844,78cf1912,ddc91907,26411814,a782a3c1,452117c9,993d9e8b,4f247563) +,S(372cbbc3,3417320e,21ac4ba5,f286a9ed,273b6425,e8ed22b,d0c352e4,f0a97270,6e05363c,bbbd6b11,8f2842d1,243dd629,247e90d8,4e7c9d02,c3677f93,d1d01bca) +,S(a1122e8d,82e97ff6,ce9fd024,cd4ff32c,76aa0aac,c1c2849d,887240a7,a368e064,ef97035e,1df99943,1139cb88,e03bdcf0,8b3a5c86,d4b42d13,9b3acb12,e4e7df3d) +,S(e0101d71,1d0c7b60,8093997c,229bbbed,63b05224,53c0079a,518826f9,2bfc9d5c,a0acb9e9,c3d3d384,7f2d38bf,29da71c9,af0b5a41,5bf738fc,be24e367,c8db2fcc) +,S(6df3e575,4b62c92,41f8aba4,12804ddb,74ec864a,12076a34,d9cdf9ce,be336e8b,bc66fbf9,276fc85d,767c2155,ef481295,963cf371,c0ae6b48,50140d1f,c32f80d6) +,S(e5794801,97d3eb68,fd859d0a,a616912f,a2a52a7e,f3881969,626f43ae,4ac20586,3ba69743,176c43f7,7afdabef,a06eabf5,94b9d0ec,1114f352,7cb1b127,697a5275) +,S(7b290c31,de7dcb10,177313f1,9a15d751,c128bb2,16823c5d,69298baf,575657cc,9d3b3707,d8f2b17f,e14b6b1d,80c55d14,b747c3e0,8c79d55a,bb54809f,d96f99e2) +,S(4ce2adcc,18632b7a,560bfc3,beb7138d,8ab210de,6cc7f6cb,47171b45,13e991f7,5aa8204b,689d8f69,a42e08d,5ecd2936,97ba76b2,1bae122c,e9252659,25a874c6) +,S(dd798cc9,97530af7,d7ce96d1,a6a93aba,c29056db,c69eebca,f4649648,4942bcb3,e9ed537e,7b679852,88bab4bf,36ed677c,14db982c,9ce8714,b4f3a32b,56609e49) +,S(356f4414,9da655e7,c9ea5a3a,5c4847a9,f908c608,aa492efb,15e7cb00,8b065b79,2adb4e6a,ce059ee,44ee8962,b4aa8c71,a4d55f31,28f56877,6c70c4c7,19fa6332) +,S(b607a62b,c16ffea9,b30f61d9,c711adb1,d110c6b4,357b1e0b,dc71c8e9,4d06668b,6b933ae0,9ba42b06,96419a90,e6579a33,8f4f3fc7,5134abf,70cef838,efc5270e) +,S(77fec5c9,24fbca2f,f564bdc2,96ebbfdf,d52f0dfb,15011792,57085c0a,8fec498e,6c7729a7,c92a6626,44f33fd3,1ad5142a,b521720,24e31308,dc11f73c,ee29d69) +,S(804dd2d9,8014a95b,7fea2651,195585ac,acab7a46,1f3134ad,f2c4403b,3de98461,66fae33c,458de63b,dd04fce8,1c425938,dc13194c,ac03205a,c278c071,918a4e84) +,S(65866c36,90a6cf74,95ef54a4,f222bf9e,3ea803a8,98eebc19,2214133e,9ad35234,8cecbc5f,4a152864,6350711f,c4df57dd,8a2c44d,4133ec17,c95e00d8,b49c62ee) +,S(eaccdd6f,2a9616ed,d6f8c3dd,bcb04c1d,49f0c4c3,8d8c34fa,d47174f9,2323e15d,15a435eb,e23d23fb,2313b59e,2fe0367b,17b6d9d,e900332a,20430362,19c4591b) +,S(860d382,8ccde42e,b27652d1,c159d9db,57a0b9de,f290b071,e93e36aa,f730c53e,b4688879,ef616c7b,87bd37,641e0381,115dd487,d5fa3e87,99257afd,26906aeb) +,S(fe446d0e,8d174570,49394416,9c332f9c,eb47e70,3f214d83,2777398a,dc8189bd,d4cb299e,760ef11e,a3846dd3,9a49f34,4d5c10bd,ba66dccb,a43e3647,718e598d) +,S(e4e6bb03,528f913b,bc34d910,2a96385e,bd0b8aa9,a07a863f,9d5d41c7,b982a578,46ed6885,471b4806,aca3c265,d0c40535,4bd63da0,af35a89c,e8a86896,63d38690) +,S(12d69042,a5515732,8b729ba4,4fc3bac1,95c419f8,ec71f438,e676d722,4509bc56,80d7fe55,52e88a74,a87d24ea,de1f9e35,de5c45ea,b8a9b48,9e7a0b8,4bcf5d31) +,S(d3ab5380,1f1b1f7,36d94c4f,2af00a81,ee1815ed,83dafdb6,ef5189e4,13a32552,691c4594,657c0809,f7b6335f,fa4fddcf,8af5b729,9262f790,2ef12e34,f546a401) +,S(50bd549c,2da95051,7b4c72c3,67074539,412f3b4c,45ec69cf,aed0fe61,25b50d7b,147f8768,515cb545,2f291d4f,5a627f36,5c88b2b,d19457b0,1fa711fd,9bc71abc) +,S(a36bfbc2,330165f0,728578b9,ec81d14,c0417090,e6ed73ac,e8aff550,2ad9c62a,acb88155,5251f37e,f31aca05,bf33f9af,9ccc57df,58692067,4f11b787,8c7c9337) +,S(2be3d416,ca9627d5,9f259f0,1d52d915,9972f50,c391531d,70a6b79f,735e7413,fc0eaf6c,97d11c6b,cbc2722a,b3e821d5,363b04b8,edf2b700,15ce37f2,f70e51de) +,S(7ca7ca3,393a9884,c94430ad,20731f2b,7629203e,9c892d22,ae6df1a9,fa66aecb,c05c74b4,e2580f6b,9be6efd4,379b7631,26d3e0d6,d4e9925d,1a7f874c,fd620f43) +,S(6805c83e,19aad851,6fd7a4b7,e9bbb82e,28d9d0e7,1f1608f9,dcf37a71,3b434893,2313791b,8fc68b18,444cb309,9cadde98,f4c95ff9,88ddf601,ea3eacb5,bf1c1512) +,S(7540f073,3a358a90,80d2b07b,64e179e6,5de8010,6eed4eec,dc8c879a,87d007ab,998820f3,bac2fc51,48b0823a,d20b5f77,eb7acf5c,fb2e968d,2b98711,a1ef778c) +,S(6eb9b5ac,960407e4,465a0c22,8d98621e,47f169f7,61189aa8,f7de2fe8,79daa64a,6a32f21d,379c38e9,229ed85b,33b4a35b,9999281d,f96ecdc0,18d2482,67d85d54) +,S(e32d3fe0,80d92f46,58331d25,f0f2bbdd,43671885,98cda416,7b4920ff,afd5cae,61a8a2bc,aa82c5d1,1e958a0,fbfae374,138efec6,84ea8e18,af1d13b3,5388d1b4) +,S(22a0ca56,c95c5221,3ca126b,65e5382a,5f14d17c,976da5df,54942495,43415d70,4cfbb8e7,7e3f04c8,69e62ffc,edf23907,e8b17a48,13fc95d3,cf307e2,978e0bc6) +,S(ce3aeaf2,dceb0f4c,50120b90,fc027d7b,b5a4cddd,fc337e05,14298873,e3ff340d,49f2b65c,4a64b462,69e93c2f,ca6cdf14,b0c81982,b095ed3,644805c,cf333021) +,S(75251b27,b360b236,9c0cb297,c5f6ec1b,70f6afbd,5af1acfc,38bd765,9c9dd5bf,cd0559b3,9b18ceef,85c15189,fbd7a93,1ceb3f7f,6cc93d3d,7681f564,17f3f891) +,S(9d69e5b3,32a9ba92,17884f7,e7a1ab91,53a65c43,917c566a,c2969f50,accb9047,9ef330b9,d347c93d,a9441706,a502491d,55d27723,ac1138dc,751308ee,fc6b3a37) +,S(783ccac1,f7d6409f,758849b6,f7c4d5bc,401fe5f5,b08c2f84,1e0e3fc4,fd7a2d47,e5c62a27,65ea5ab8,6aa1aa00,9297d1fe,57248127,a5d3c36b,9665cd93,b6255f83) +,S(dffbb444,8362773f,e45e0272,eeb1a8b8,fefee1b5,59a6bb12,b9613fe,55ef33d4,fd539cf6,aacc930d,2ff104dd,405ae6e,e4a6b3ad,1a9a0038,f4ffb4ba,1a6115c5) +,S(cfc948b3,c14d06fd,c528d299,22305663,d7a427f2,fe08cc2d,942528d,dac8ebe3,81ab799e,5be02ce0,d3aece6f,c6ce84ae,988872fc,ab640d96,c3ea6bbf,3e2e709f) +,S(d9fb08fe,6a7cb6ce,721cca32,74e20732,5933595a,e59aa0d8,811008f5,cee83490,2c7f1287,8b6ad3b5,88cf9483,f08a92ca,ccc18ece,93c68297,4d80ae31,54965938) +,S(4272b558,49ef0ac2,d7830183,bfe3cc45,65ab9d9f,32b9366a,b0477d1,ae93956a,caa07aa5,d117616d,9f442b94,40549bd0,f64e7a2e,3cf96053,bd14faab,196c698b) +,S(69536c0d,6404b026,61598e11,1e6eaa4f,e50a2cfe,879b0f74,4df57727,933367fa,aeed065,2c5325a9,53913334,7e4fc4b0,d2583608,c2086bf6,b2e5ad25,261c6bfd) +,S(199589ed,5c4b6e24,65d58257,2fcfc194,60f7643b,7019c02f,8038d04,70368268,c48567e7,ef7a3507,14d1b479,1a70e7b0,5c1d4351,eabacd9a,1d8d5e80,a5da23c2) +,S(ef3c4f9e,53ed652b,f48feb4d,1c7b711f,5526dfaf,6588007d,1c2ce942,86db1f4,128e416d,570c3eff,d45da6a6,31246fc4,f45b7d2b,8cf85a93,22b5f65b,361fc49) +,S(6bc3a126,11ca8f8,3d0790c9,f5b5b137,4ce51c66,6c553ff6,9d103370,3b3d7cc4,b20988c9,4b882f50,a0ba8194,2f168bc8,f29eb6fc,4c3d0149,571968e4,81b76ab4) +,S(a0100574,5ea131b1,4c180c17,f26bd3c8,1bd48ca6,c2310c4d,34bad277,6bf51aab,177551d,299c9ca9,92de3e9e,f82b115e,6d3cea9c,fb276955,5509795e,4870a546) +,S(15553b6b,defdbee,532599ab,9e0de23,b4954dcc,912f49e8,f084ebb5,af6088e5,8dbaf203,351a1119,16e8aeb2,e5eeaade,b0ee5d9c,2f5020,62b9f5cc,ca40cbf5) +,S(ae84a42d,49dad25f,f0a5320b,d6a33f8d,79c9f2c7,2871f41e,f8b02cc2,c469452a,9b23f07a,234782b1,cfa524b1,ad539ea7,b8fac3cd,e9bfb867,799a2587,95a48ca8) +,S(eecfc7a7,a41f75dd,43e2b85b,5af33ad5,f017e0d4,8f9b9bee,f0cf4499,a3c762d0,65526d26,73b9e5b2,8ec256bc,a524e376,f0e40f62,2db6e492,e1c53820,a3180d11) +,S(35e427f6,d0be7dc1,2d306ecf,be9fd8ff,107a044f,81c38c8c,5b9a181d,f4565440,de09eefd,27a8bb89,d8fc38e8,d32aecb,5c6bdc57,5cdf91ca,2f18e926,dfcca94e) +,S(d27cec9d,11130024,7f71fadd,4ace1139,cbe3168d,174c93d,4c756c42,89cef3da,5747fbf8,c4040895,fded5c00,e1f60403,40e07827,8924ca96,2f83b3f,e50ed701) +,S(df30926a,ca9062bd,7bbef9d9,e312a1cc,49442ebd,9994b93f,dc652e68,25efe5b9,8d1ffe08,de113447,5c3adb77,ee5aa58c,593486f9,c3f27c32,a20df570,6ff5c572) +,S(c2602b7b,56d0eb73,ab494934,5eb77e88,787e54c,79558ea3,dafe3f50,84f96682,45885bf4,65996b12,993efe44,39861b39,84d5fa89,5242ea8,f498695,57391182) +,S(d6d606e6,28c55e08,61a37803,72c17b1,6a2fe04b,e68a0cc7,60fdf7ac,85c8816c,76b299fb,9e716eed,7f09c879,ea8256bc,a953454e,490edabe,c90a2e5,dd277da8) +,S(d1bb671a,10ec5393,9d67f6aa,3b09e1b,57bb6414,e1f707dc,b832ff67,56289c4,47559cac,311f20cd,55760ed6,2e1e87ac,cd8603e4,c1d0cba9,79f6802,6b294a94) +,S(739ab4bd,6b6132f8,2659fcda,5fb46836,7adf2133,37f897fd,70a9552e,786dcb91,b562e798,2bf508ba,1b932deb,3e6b5962,70bba4ca,402db3b4,d806da6e,fbf6670d) +,S(a710cd7b,2aef0005,6d8db954,2abe6cba,2a6c6132,a48a6670,c501fa82,4de21388,4a6037d1,87db5b52,2996bb0e,47fc7509,1ad9eda8,e15faa56,92d56006,e72fb220) +,S(cdbf59c9,b38e40cc,d63b36b8,b6e894a,c6baa22a,93a1382c,9d7fd070,58e69b7a,3e836c78,6954d509,348314df,8ce08f0b,59967aef,4e5f0136,9c6d0f91,2682d77) +,S(1d32e93f,6e5e138e,7d226636,d5e0946b,8117f91b,bd59efb1,560a15bc,657e4dd3,82c43daa,bc1e23d6,3632e167,6bbca422,9797551f,f729cb5d,c8ac1460,46ed20f7) +,S(2730066,cbe72e84,304e3563,a18689a1,c6c8e0b3,e92d8c0,d63a96c7,e3573337,8804d5cc,6aa91f7a,1ae23506,17332f7d,811b8f1f,752fea43,5208b770,94e67c58) +,S(44624ea,a1607e8b,8bcbd736,9c67f86e,6b0f5226,4cc76a3d,b40042cd,bc621cc4,95867a99,d110d9d9,e382d3d8,a5dff78c,d8db012a,972a87ae,ac24bb42,b2747e53) +,S(8ba805d8,864774eb,4494ca5b,f8257bf6,980466f8,30028340,8aafd665,7f1ef49e,1a1164e3,c1b243cc,57507b07,7348495,95cf67c7,b40d4d7f,f10ad096,3f3866b4) +,S(297d0130,25bdd2d3,f4a008d0,d8c51a3c,7b16b605,95958d9e,93e427a8,7ac01267,56361e70,22138026,683b7bf3,1a6bedaa,988d3938,cf8399aa,e0f3175e,61d7e2bc) +,S(d866bb84,23527208,e66f34bc,e26a8ac0,daea9d03,27c9dccd,cdf0e2a,a0588f52,5e16262d,3564736f,30f26e68,1c5ea26a,b6f63429,f0b25dd2,5635a3b3,1fc45584) +,S(ab1e9d8e,b18e016c,d8ec49e4,388636d,5dd2ab55,8b3dbaa2,433a976a,ad8f16a2,a14cbcec,6327451b,15d47fac,d3f3cbbe,fef828c4,6ea07a0a,9c7155cf,2a2f291c) +,S(cf2f035a,ce393efd,3032cb05,4f4e92ae,5311dd04,bf8f3653,5197748d,2094cd30,75b38e90,9f02bb50,7a778243,35a1c97d,75bc653f,c6dcffcf,615bf8c2,ec6b32f5) +,S(a801d552,e63ba120,2c3ff08b,8fb025df,e545ed35,1adf00f,1a08d982,9e8bf9bd,bdb9274d,f5298fab,4cb08f42,252639e4,a24b553e,892cd1ea,93499c47,41c23165) +,S(f7ad7a63,eb2b90aa,3de2a80e,844e5336,287984f0,6075d9f1,26f24108,f4a5869b,d151e7d,9766a81,1db45134,7cc22654,c5ac40f4,a1d82d96,2de02c58,d46cda31) +,S(732541be,26fcc3e8,c824d539,28282611,96717b00,2af01bc8,57f4c0ac,cded0a80,d44adf28,f26370a8,3c9eee24,4e870dab,3fa7a508,bd14a56f,17c9a845,5055f8ca) +,S(892ee5f2,a5266a86,5bf2094,14c31225,b92dffda,7a3ec00c,ee53dc0b,8c3a3367,21bef833,3b983665,7d243b85,c0b4e2cb,6a5b339d,831cfef5,d676c7d8,87a0df00) +,S(1a4597e3,77569fed,70875f9b,f8f5531e,6bd3b363,b96a345f,9275365c,e1e64424,bd142738,fff7b9db,cbff1c,93a968b1,f0ef3e63,8279b745,21aa53a7,6e611f7a) +,S(c7306404,4b4a3a00,6a584193,e915a174,631c8a2e,ac45973,c815a2f4,aee82f35,280adb29,4f9642cc,cbcc4345,28bacdc5,74beb7df,84c06216,68cc2fec,d78731e6) +,S(c06d9d55,264e4ea9,e160fa78,78a7e4fb,1757f6db,fe610966,503ae03,b4723f2e,c0d82600,ae072564,b29373a1,ff1a036a,45f68f22,9d1594ad,1c9584cc,ab732743) +,S(e878c0b2,bf38b500,6c309a51,5121a3c4,5b13440d,74ff6e27,5bfe71d7,51e6926a,4b8be149,11432ff6,c5169731,1c1db30b,c921cc95,b4c98a39,5228c08,b99b6229) +,S(d1f6621f,89ac4421,7ef39a54,a0922c77,dc7addf4,78b15796,2558ae72,9b24f65e,657556fe,e02492c1,97c9c97a,67bf1d6c,eb689415,80a1ce6a,1e4d98d9,64902f3a) +,S(f9199ae3,ae51f441,d88d72d6,9c1ff64a,d5cc4979,b5fd6a23,c514e9b4,66ea0a5a,3c484bb8,8ec31009,eb95b971,69c7ae03,c20dd833,eef53cdf,fdab8cd5,7a82d4eb) +,S(4e059bc7,516d5fe2,510ae63,d3ca9543,f840bff5,710a744d,62de3965,af6a657f,222309ca,242c5858,5a792045,bbfb3e55,b61daa3c,afedd1ee,19a0038b,f929a47) +,S(c1673413,d8b4298f,6ca04741,a3c32d79,83a7d5b3,dd39ada2,53013d3c,9750ac65,333b1660,7b998e8e,fa7e3d32,2d51c052,1de24d3e,9e389f0e,9a00015d,6cc32d54) +,S(c078723d,8abfbc03,63f12766,cf9c6261,9c31173,5f3a9654,b653a8f9,e08f551c,880fa5d0,be09cb8e,4f145749,1c7f54e1,ceef1477,ba7ed718,5f27013e,32deb89) +,S(c77f3351,4b44b047,3835e3ff,abe8d7ac,ae5f912d,aea4e6e0,4ed03feb,78c41ce5,cade531d,26ee668b,5e2fc7ce,421de2f,d9a14dfb,87286c22,c840144e,1290e910) +,S(90e14c45,4ba40739,10f800b2,bcc7b017,ec58660,bdb1e72,16cc6afb,8320277e,61dfb75d,f5f74d47,287f828d,c4ff46d7,fa351a1f,66da99da,40e74758,2c6bd4b2) +,S(34c65f34,23f2474b,7e2f294c,ed4da6b5,c05d19ef,a2b5a792,103b681a,be1a3f68,d0fba1a3,b12d3e4e,f18acdbc,68fc285b,8ef1365,6aa900c8,c86ae191,37f028ee) +,S(fdcc63b0,aa5017ce,215735cc,2802eee6,aa5ef53a,6a258dd7,a128ed7b,9a5df38d,217ea863,5c9b88c7,19c7f9e6,1286844b,d4f4b758,81535954,7b24df0,1fd5bf03) +,S(10624260,58bb9f6,a5e83740,59595ffd,e7013492,4392c753,15853f4d,9c7070f8,84a92509,e809874f,86e60bdf,85c75d7f,2cab596e,185f56d9,262b06e4,e79cf785) +,S(e21f29c6,70cfc7e8,b104921,bb524414,53acdc5f,fd80066,39417966,ca235c9d,41be8bdb,969ddd53,9093dc1,b85dbd4c,a78f7e68,67fa916c,36136d24,b6c4af38) +,S(154a85d8,60b532cc,16bfdcb2,2769fdf3,6dac818e,cd2daeb0,864eee0c,f78a5c5b,15f2dfc9,3e5e08e4,9d340ce4,bb805afd,79f940dc,f97456eb,c73b47ea,5098e429) +,S(ae6f8b12,d52907e8,4ae5063a,114f8e2a,da7be317,454ea505,571f2132,5e4acf42,49376af9,1aea68bd,cdcd637a,909b639c,b7ff8800,ee003fe6,540d6797,f0f296d1) +,S(de42ac26,47fece4e,69341582,7e3c5b7d,a19dbbd6,22da9fa8,58a3be29,8a47bb65,e57cc346,b83b33cb,79a34805,42811d1d,4178805b,a2b88de6,d90b4fe0,ba8e2740) +,S(14c2030a,c65ec50d,2f7c176c,45256587,59cae0d6,55cd57c2,c1ea970a,11d7bd0e,f3d9f0f0,5881801c,ad4df439,3a3bd2df,1a045181,af7ccbe6,7500b02f,61edece) +,S(32fd40e4,7a94e51b,e4c927c1,42b5f470,b2abd2b6,2773934c,a29a5ff3,924b2e8,b3d74958,f17147e5,1da38ded,7cb09c27,96b7e36c,3149d85c,9b7db85,acd89bbd) +,S(fe468154,cef5383,4820fa33,ad85c158,33635cb4,a55870fb,f588fa6,b8d2918c,96650453,25235606,7bcbc214,b0a04021,bc71c9c5,4617b1be,dd34e6cb,dbb42873) +,S(57826e08,8fa3841d,a33ad3da,e5b5a688,1ee770f5,bfe45f5d,507b4801,ccb511d9,6cb01dc4,4da6d83e,77a6e8a6,d374275e,7d8484fb,4863b5f0,34bace60,30e6b3be) +,S(61bf08fb,1d537624,1dca6119,19f0dfcc,7787090a,6747cdff,8757b037,a1ea59ae,6bcc632a,f4f43c6b,547e6ac5,5854268f,1801614e,5bc9d4e6,ea0dcd99,79f7adb1) +,S(f54dac2c,b5521855,9dc274ce,25b77645,6525e91b,c011e657,5ff812e8,d846ea4a,bb9734dd,af492c18,82bd36fb,f365009,bd41b8bf,1378d9c6,a18477b9,ed627f11) +,S(640ebea4,b85cafa0,d5a38ef7,7373bfb1,36b9571e,f9694724,680e92fb,13efe03e,eaf8d756,c70ee813,60dadfd9,702f660b,516fe3a8,4c50043,92bc7c1b,892a43ac) +,S(6c4814d1,e3c6c16c,366c8776,93b6df4e,266b45a4,26fb0d5b,a2d8fef3,a3803975,d9330c82,8fb02d63,33d57990,b6bedffa,ccd143d5,1b5eac78,5c7f058f,af77a37c) +,S(8dca10b5,95293452,7bd2f264,6170b6fd,59d636a1,f2578b6f,cbde0c96,8bb2db30,50da6972,64516689,57d2273e,55dd046f,1c398d1b,9e5e864d,ae6746fb,825ec83b) +,S(1409a8cc,34389c3d,3fd1b482,fefdb25,3ba32070,dc23b7ae,6b8a1ac0,2f00b776,f8f1c0c6,3bef8011,27ffaf53,d5c07c,430566e2,6c4a9591,f92d694f,82d7a9f8) +,S(1c752b3a,2cdb6257,fe8bb102,e7560b8c,6f86e7ca,e809892f,58df3b16,728c0999,9f1341ca,61dd07f8,882596fd,12531577,d09fcb45,5a086b0d,17dd5390,8326c741) +,S(ae8bb1ae,a4341bf4,c18e7d99,7bc3ebb3,d9f13c9f,b01b93f,885cb32f,d0586999,92eaf2f5,c4e231a6,851a2324,a146400e,6b9eaf63,8eca473b,9d4e034a,3d5c8e6b) +,S(e3d2429b,ba45b4c,2d9c9bed,45f384a1,7d74cd28,56c87772,6d9a98fe,67bcef97,729da85f,927c04e2,c1db1458,c133bdef,c454d0d8,88262b1f,418f3420,5df2380c) +,S(858ee23b,e5166c66,b99d48dd,24cb5078,fcad23e4,a8df9f91,53ffcab2,fb8624b,c5088132,3af436fd,c4f63b91,b06061d4,b26fadd4,6bccaf05,bbe1a8b7,338cdbf2) +,S(7c6a82f0,e2d6c5a3,ba37be0e,1bd8d4e1,99f9aa3e,c9c58054,a66099b9,a4938a1e,881916a7,87e1f9eb,b38906c,c101b0e6,5d245fb7,733c0093,9a7f6f0a,9b4d113b) +,S(4c980c4c,144e4060,c00e7476,c782cb83,42ae8b02,6a155904,c29837b9,fc25caf2,fbc05490,a62e49f5,6daac9dd,5c730f90,183ee565,d62ca949,5bc7ce56,61c2e8c1) +,S(c9b66a8f,6c163037,f5bbc7b9,889e9cfc,357ed5f7,a5e5cd17,6a7e4bd9,6da2fa3e,4eb8b3e5,365a6a44,4b277b4e,89b89e04,2b44cbf8,b73f183d,42c9d8b6,547885d3) +,S(f2f8fb3e,2bd3cd82,99e2faaf,bd5809f0,12190658,b1efa389,f58ffe28,c1056fbe,db6c4cac,35f78015,8fed40c4,341a93b5,64af02c0,12d4817c,478726fe,4faf8273) +,S(8556c286,895b9402,283b5d2,f90ec950,f91c4dbd,6c1c8a0d,6b27cb8c,3bc7da8f,f2979daa,81ea79b5,d3ee2718,4aff3805,9bce1bb7,fa36cc53,4d139b83,c176badf) +,S(4d4c2752,5f24a7d3,ec3673b6,a3c8f110,f5bb5c5f,e9675776,3d81620,90579267,43ee95e6,5834075a,83675a88,15babeb9,824d4703,763b5b09,8c3aff78,837b353c) +,S(cc6689e1,d08b243c,a49a7020,b08ce4ad,817193c7,456fbf4a,97fca02d,f1ccf2e6,32f00dd1,1080c238,cc7e8c9c,60a1b7dd,7503417,2ad0464e,1cdb4221,35ea580d) +,S(966525b9,26bb6596,584cbb3,5da78cec,e6709134,700974f2,6cff34a1,23fba535,b5c18347,52894cc5,26336590,d961af5d,2453d9a3,40bd151d,259d8be7,6c5a9e7b) +,S(df7f51dd,b0e6c595,c8f3de9e,eed5da8b,b05e2cf9,a4555001,760888e6,38b11c4d,19759148,2d4f49cc,b69ef50c,a1cbf3a2,49e3958a,aa9af2c7,becbb72b,8d53f8e2) +,S(4ac2754f,93745ef5,61d6d213,7fd2339a,81cfb619,b6699d9d,21897ed,975f6fea,854a0153,17ce38ef,e070da13,c07829f2,1bf50d40,6458109b,5700a3ec,ed6a3c0) +,S(7c062917,2c59c7ef,2d488806,b1131193,b6b6f0e0,221d1ebb,eca1b358,43959694,77f73272,291c1c73,5d79857d,60cc9db6,b6128e86,4613b3dc,92dd970b,d5dba9ff) +,S(c80152f1,e4b7728a,36acf22,158b8215,d8ce0ea7,401274a2,1139dd71,59d81557,dc0c54e9,88d2ee7d,e8a56eab,d358aaaa,4542a45b,a170db58,89d634f1,dae95df5) +,S(9c2352fa,464cd430,31f43578,53feaddf,7d5ee143,c6403ea1,230961b6,377423c6,841277d5,71934bc0,20f71b36,dcba2293,65819fa2,b20c57b3,5774a524,d6fb20d8) +,S(8d7554f5,fcaae19,cbc20c7b,73f22f30,aaeba42c,a22bef77,3d780205,8c8e1d7a,c6bfa4c0,9db5101,d33abd0c,47c4e125,bffab86b,8ed50864,6b6a2b0f,322bf5d2) +,S(1e75acec,28a2ce98,5929479d,e0842826,bd556b56,6961d5db,66c9055f,b1b63635,89cbe475,d2036dbc,9227db67,d62b51e9,ac669a22,76e4e1e9,d0be9b1d,58efca6d) +,S(9fe62187,5e71bed4,7d9f2d79,91e76b41,88b2c8c6,10f20d33,5b38bed2,eee85236,9a3fe290,fbe192f4,8a44177d,4f0d037a,fc6fa8b1,c57032b1,3d5894c8,c426e8cd) +,S(8dc1710f,8869b645,73c361d1,ada3f43f,6f2c175e,b24ec358,6409e978,1687a220,37a4187e,bce1845,9520b60,9317a4b8,f33b371f,1a768ba1,96316f41,373ec87) +,S(71ad2a17,5cf75568,214fbbd1,f177c1a9,9eb75486,c161f1b7,ad47063b,567e8d6a,29d80786,e42d9cd,4c801f96,a7d44eda,5e325acf,3b82e143,2576ff1a,3b334850) +,S(be0eeb11,aaab9c1c,ef7a2004,731e3ca4,435c8a02,548b36b2,db68ea4a,56ad8b7a,cd7ad5,c9b7e867,1a1c7889,95e45cff,bcdfe42a,6222e0c4,1054a0f5,f7bb00f2) +,S(364154a1,3a7d9fa0,b349c6fb,ec36ea43,51cdabfd,8fa79318,88e4ea5d,ee8bf6d4,40b40474,7e8b30a6,a3cdf3ba,f0956fa5,f7f61a2f,89a8cf7e,c2ed7445,504a71ee) +,S(19daf7ab,c9f69a31,8b2cf1c6,69d50532,5bbd7254,c4bc4126,d7b31dcd,e7b558f1,6b740772,606874b6,5b1f819c,c7339ffa,30669d9b,2770506c,e9fb243c,6ee4a925) +,S(5ab3dc00,eb9efd03,ae491844,50fe176b,765c5da7,d95ffe6f,61aa0073,7366c918,2603f1ce,935e3af8,af5e3d1d,d76a3410,200037c,87c17a93,96e11018,260dfa01) +,S(47bc2c3,d7dd83f7,2b2160a2,64640e58,16316d0e,3272abf4,b859dd0f,6c7b27d7,1ceefb1f,23dc61a7,2f663d9c,3cdd6625,441a63f9,f9cae8d5,c4ba88d1,22c0f258) +,S(b220435e,e903f1bf,3b443549,5a01e739,250be2c1,43f08a73,bd7dbfcd,75602ab5,3659abe7,953b817f,fd1c02b6,56da4e54,9df250c0,7c28e9c0,89ba315a,bf25e1dd) +,S(be25604b,d52413fe,2c743031,98aeff78,c27086f8,97fe4b20,be5b6251,52fa2fb4,ebdb5191,aa195ee,a0a39bf7,399bbe03,76073830,fe54cccb,a3194eef,d8d34fe5) +,S(5cedfbfd,633f16f7,8ec8a8f,3dad7cc6,edc1a6bf,3e37cf3,65069731,64aad0e3,70e687a9,d8632ed6,ab188f14,229f2e31,34a3adc8,727c7b0a,d7a16d78,1244c9a9) +,S(8109ca32,a86fa712,690315e2,1bc09265,bb6bae74,588f507,1bedebac,47e54a3a,e7f3342c,6e8a3dd1,f6d02bf7,5610511f,d0cffb40,1c14633d,308c2939,e662cbf2) +,S(54264a0f,dfb894a6,b29b6922,b859d715,77f0359,ef825442,e0d43b79,a0fbfe3e,4884ea59,cb88fb60,4ca4de66,110b7d98,ec529112,d4574cbe,9a2e7a5e,5a4a644d) +,S(f2756955,a6a7db9f,eabaae3c,844cfd37,5d86ad8b,a84dcfba,582bf4a,273f90f3,b24c14a7,d2f60103,a7d3652b,c5e68988,390c0e67,1f0fca22,ed927f6c,96302239) +,S(351da3e,6ab7c98e,840d0dfa,e7231d21,ca21a81b,3638371a,673892d2,e40498b9,e1c5ffeb,43b443ab,d31332bf,aa314fda,5a4c2634,afccfb97,67bceb3f,13ed5f3b) +,S(b5107be0,90f84c7a,e3d89782,c6751b22,f9a7ad2b,3a1810c8,f14bdd8d,52344357,3d5571d2,36a7c9a1,aada0835,9e8ce162,c46a878,5e09265d,bb52b419,144c5b6c) +,S(b6172135,85b2557b,7c253189,9422c428,79825eaf,64d8e8e2,2f7bae12,31c9ceb7,dbfe3609,df9b8e1a,33629219,eb241daf,42d8be2d,b9a20a0d,942f24ce,1a117e3b) +,S(5eeaaf7f,577b445d,13481c9d,a567825c,f0a5a3f2,9ccfbbbf,d8f1f8a5,36e712cf,84a4352d,c40556ff,ab75acd3,b5a63366,39119d8b,f814feb,e55fb3ee,dea5821c) +,S(c1bec874,44b0210a,9a86ca9b,94891d00,e1fee6c7,490aa26a,1af61f97,5dad1c13,14a61af6,d280ea47,433d795,1786351d,f90a9879,7678781a,8d9d8884,e88a06a6) +,S(34787098,f0df9eb5,e4825449,6fd7eb6b,3118dd45,aa0ccea9,f606a794,126b9ad3,85c30ff1,c8dbde4b,88fe9ff8,20c9908a,a35a0c53,c2175524,a5929eea,5566a564) +,S(6599b07b,5d31c19e,ee02e287,ccaa1bce,70890b14,cd739140,6f1d862b,39d794a6,d18396df,27e6fc21,a9c36a1,8d8f73ef,c79e6c56,ecbab9cb,83750220,a816d5ff) +,S(27b50b15,c92c010c,60feb473,5ac6ae0f,9ec0af75,81e41a90,a3a940da,a1a44ee8,31c2c3c8,61e64b7c,df8ca011,bd4002ba,5373ec63,8c3608fd,619bbb92,3552c1b5) +,S(40aed5af,953f3a17,f5d17622,127f16bd,4cc5bbee,33e23443,5f49c4f7,a48e7a32,e47011ee,96c702a1,1eff428d,2940ddab,d17b76cc,6765d5ed,126876ea,2496f6e6) +,S(cb56977d,f69956da,cf40909b,69fe44c1,4a5ad547,a025d684,c9815ff1,b5331ef8,9904de7a,9ce0f656,2f025ffc,79e8b3a4,2e410ad5,8f0caa16,62a13e29,f0b00bd2) +,S(11dc40ff,58c6d2a5,9768a776,41c611a8,2aa651c1,15e9d36c,bd3ebd18,ac7a0df9,4717af95,274f820,28592bc7,4a84e467,9d168dfd,826a292,5789edf4,a06e0e50) +,S(3baee366,3d2033a7,f3170bd0,723eded9,2fad6501,702fa530,b26d0623,8d6992d0,47497025,41900ac2,fb236a26,81ca09db,c34fc84e,98ca289b,63e07d17,2e4671f4) +,S(6b19e8e6,b2010e2b,d461d716,66f691ea,88417df6,773208f5,18ee5fb1,e0fb580,a7c74380,9f744b05,99b6c4e4,709a8b86,241ef931,effd9323,9a6d15f7,22916578) +,S(412a2c52,b31158ab,9d3bf4ac,d4355eab,b7e94e98,6a839681,94a7322c,72bff9f8,c649c493,b19b713c,8b3c4e30,567547ab,472a599e,cc95ea73,d36d373d,c92f7dc1) +,S(b5e0c57b,f79e7364,9826a818,bed1d521,3cb88645,5dc91a4,eb157a8a,dd869c24,752feebe,9614e233,3b876297,175078fe,f9adc63a,4639242,6c88ca94,aa06163c) +,S(f656ab08,9e75bac0,6eaaf373,1cc71347,6a636347,35ab57c0,222589b1,e914160f,d05493f3,52b660e0,4cb00b45,5cede6b1,74337488,dd1650c8,4ddeaeee,b73a6ae9) +,S(bd2465b7,b5af290d,2d1157fa,76e4550c,ddb23922,7d30c255,8f0cc3ad,ae5fa32a,63a28c79,cbb50c21,bcfc85ab,269090ea,d56f6396,1fcc6dfe,b3a000e7,3284880a) +,S(d53c8d24,3dc3600d,fa32dd69,11a87ab,722108e4,192d7cec,4d84eefb,9b32a351,af681092,6afda47a,ef5bc91d,97f273ab,78a21c01,64f59c0c,ed66f7a8,5b67ca24) +,S(4a83ae18,ab379d5e,f6cd2be,77f64abf,8fc23b52,edc88ea4,9efc1bfe,402432c9,e9eef9c2,f595ad74,abf10b85,6ea24ac5,603d46de,c320f9d9,a1453be3,92eef8a6) +,S(d1df4416,dc7cce22,832f9ab0,b74d927b,f9b3b7a5,c52acee5,3d95812f,f26caa82,9e5242f1,163a863a,a5702af3,cdc21f7d,b0143f76,ddba2a2d,d592676c,57c310f) +,S(e6add3b2,583addd7,8299fd2b,14b87155,93dcb13a,3231458d,ab6864ce,87b9c890,384bb2a0,930ecde4,1e9945f6,247a6530,58e26bf6,88226c8f,ee9a1ec7,a1f07740) +,S(7d3f5447,295479f2,96c11443,eb9b1fbd,fe81a258,78ce4195,d2f01290,7e01fe4,d12e4fd7,9f66a45b,2596b066,651d8686,83e62627,95f681a4,12022046,86304ac5) +,S(60636a7,45442fa9,57f21668,7fbdde4e,a6f7f80a,ea2832e,ca3ea43b,d1f12709,395ef963,bec2979c,fb211f8b,da3f4b4f,2c129ce8,26a35367,d955243d,3b40022b) +,S(6bce0837,39c04ba6,b9dbba8c,f668bea9,4d8a8b38,2ac17b87,765bdd52,86e47963,a2d85e2a,7ff5c433,c2c77363,666ddd3f,3fb28f8b,2b7aea1,16a8f42e,384a0a37) +,S(59e4e7e4,438ceba0,cad5f146,bc127c1c,df7f4735,f581a0b2,6a53a366,947d4581,32207f5,95fa4cee,3c8ea269,9578b28b,6290a3c,33eb0ba7,e3bf7267,b2bfa445) +,S(ae2cb18,d4f053ea,3a497162,8c822f6d,72806f79,bd39dcc8,364ea256,f30af032,583d363,b9ac6fd2,709985c5,79603d9,4902da04,1563879d,245433d0,abc54a1) +,S(bc4eb578,630ebde0,f58fb192,377de006,c630e96a,51219379,43e9a240,c30951f7,5224d403,4635eea8,e63b9e87,2875f27a,129de5ff,fae3d516,5f6d0cfb,5bb7e584) +,S(848ca19,6fc34e2c,e484f74d,79565ba6,9685128e,7b2d21fe,8cf0e4b1,edbd3b13,2a41e449,532de110,e0d3fbb2,bb794fb9,32d0d4a6,33aa65f8,ec40e5bd,5c4314ef) +,S(b90e1d09,4257ae30,bd12debe,648d4cea,3f063740,e3f9d3fb,c67eaa4b,8ca0bcfd,5604b475,31b28a6a,e0a13a47,31f6cc70,de91d429,d2204d45,e1423652,5a5a4b43) +,S(430752bc,3e1191f3,6e084f2,5f3e30b,da104f40,1de93267,62dde1cc,39d94c71,e707daaf,841f62f5,6d9c45fd,3304e616,30b6af9c,d6871476,6132e127,40f5ebe0) +,S(ab919243,c8bd75b9,d67f331a,b3b487e0,ee9c97ff,c35de7b7,e29827c1,ab643be2,d4d853b0,3971f1fc,ce365db9,cf4a54f1,5e6059c3,c5138b2e,dd765c51,7bdc0c7d) +,S(adce8be3,2277c2cf,6ee46781,f1da8f30,1cafea51,18322adf,8d6b8a29,fc3f7551,e819a7fe,73311592,bcfda0a7,3609748e,6c039066,feba9e5d,41e125e8,4dd67fb4) +,S(d6ed759d,15f5d47a,146e7fac,423b952a,5eabc238,a0382762,c2a226ed,8c24b601,456caee9,1c212f19,acdc2d82,9eb90cb0,2ac35a72,8d280042,658af65a,b6840e9e) +,S(3583bc8f,c3ca09c6,6f2f4fe2,83da5c47,f0ebcccb,fe8e94ab,fd315173,fd3fb2be,ed60aa95,504e9b31,81225d0c,a4f513c6,6da2a2ce,9fa9afaa,c12e04c4,f1d50b59) +,S(223879b3,b9e50b46,7bceda29,905d09be,1acb206,5b23a61c,686d6f39,bf0744d4,a8326789,ddb38afb,e993ae33,6cb1c3f7,92addfad,e47663fa,52a296a3,b6f2873f) +,S(29329ca6,c6ce20b5,81a90873,7206d44a,95ff382f,1ca0cafb,755a3450,83883d69,5d2aa87f,59e13a0a,8ca4460a,4db7f496,1c118ab9,b4f783e1,305bf43,ed44fe71) +,S(e1c6a08c,593454a4,aa116edf,13345cdf,6dc00b1d,b63b7a64,fdea70bf,e4301ea,e0f9f3ff,5e7e395c,42b3e093,87b8363d,37092335,31c317d8,1b61f20d,f06fa662) +,S(da098bf4,133f656d,f2a09d95,c437eaed,fadb4c9,8102d164,b355c7c9,38e65216,74ffa0cb,1fe7f0af,8a1a6ed0,531f8e98,28be1110,90b580dc,5ff55fe7,b75d9b66) +,S(f3f7c27d,54b40dec,5b3da04,b2cd222e,1507aa70,bd236bd4,2d6e5c95,c71bbe7c,80e17f04,7cb2203c,cc58c364,d77e9a1c,8abb092c,18a9f8d5,6edcdaf6,1ae4062e) +,S(466b6e28,8981fbcc,92c4ec3a,a54eae4e,2e266041,5b242aa5,523579b5,b1fe93cd,9ae0e0c7,d056b2a6,831f540c,67a97732,33bedbd5,bdcd2904,2a8987cf,1fe2a86f) +,S(e15af336,8c59576c,a36b5f80,d9ec0458,d9534bf2,6650cc26,a2079946,ac43fcce,7fe0423,e6ea121b,308d167b,ada98cc2,fb8cd772,f95c3d84,c1907f09,66e5b46c) +,S(c20ab235,6dfe247,d8fd1a9c,d8c4f16d,a5322bff,692efe70,f256521d,1b990492,3c0aae11,e4cf9a17,57feb324,e1a2f0e,48d5978c,6007429d,ab32b2f4,d1a19bd6) +,S(d8b6c190,4a848755,f126651c,d96fe374,7c5a3744,1fb7048f,e15c4693,dbe35e17,fefb5310,e7e38891,70fca6ec,61ffd2d3,72605ed3,4bd22d73,c852a92c,c22fd30f) +,S(a8256823,5416b18,a01d2df0,f47757d0,f42c26e3,780ae6ca,2421aef3,83361f8f,c9192412,77948b80,87d1c45c,a95224ae,5f9c294d,fa74c1ec,42ad6004,f8646540) +,S(28f2a237,c4dcad5b,a6bb5274,1e743020,e90bc598,8ee66b39,cd672ed2,ccac6c33,416c59f6,c1b1b036,f38a5523,722954eb,52848872,8ecfac4b,5bfea63d,cfc181db) +,S(e65d92b7,571bbea5,4e541862,a4dc7890,bd546782,bca886e8,3c1ea17f,33d77e9f,6116ed43,13def2ae,6b0f2b92,ff07c91f,4139982c,12511152,fd7ed5fd,851bd04e) +,S(68adb9ee,c7ae0198,726b0457,91fe52b4,b5c2ec78,4199da86,bceac230,d55914b5,41ff0808,e42aae9f,e93ff704,6f08fb38,4b72d7ec,7b1dc6cc,e0071306,7ee5cfd5) +,S(3f0f7d6e,6bf73a97,40eb842a,35cd4800,85db4766,f7fc374e,1ac915c0,e4d6d6e2,392aecf6,8b446346,2d37a106,8299a09d,9ceeeaa4,f0ee3397,dc54b2f3,5e3332d6) +,S(929aa2ad,48a1f3a0,24fbf7ea,70e9d57b,9ef65afc,b3cb2d8c,5041a933,321359e4,b1cfddf3,4693ff40,ef16d8f1,8fd1fec,a71252cf,ee13ba4a,16094c20,3b4fbf66) +,S(9a9ff691,f16ad46a,d0b753a6,fb09025b,e196b443,839114a9,580eb2e7,fc494e2a,3776f83b,92c135f2,5e5e600,27f65e2d,582fa2cb,f5842c3f,644fb726,1e305c67) +,S(6752b226,65900d81,47ea6b73,25b212a2,9bcf899,799eb1e6,213857dc,6959d32e,fafdac9c,2f791be2,d1cfa78b,7530859d,c1b2ff43,e546de14,1f42baef,3d6d1371) +,S(9fc32749,e636e845,aebfede1,1d0928a1,8cc6e3b4,5a2536a9,fae0a2b,ddca6434,9021fa85,56c5fe05,cc87bdd3,6cebb00b,3d1b77e1,80ce2f8a,a4d155ee,84fc6441) +,S(60ca338f,ff905b58,b1d70d5f,89c4cebe,15600495,698b262b,e1550da,a0054a99,6d57de6b,f7c637ac,4d728090,9960ce01,4b541abe,754b82c,bfc87ad1,5fbe6ede) +,S(91537a09,697d3658,b06b853,d07153da,6d0228f0,786f334,db6151c,64becb87,231a2595,e04dadb4,b3900188,9f34b43d,5cd3c81c,f13fc6df,d432a377,4f53015) +,S(93a85356,195e109d,ddf054d1,2a901d83,b10db692,fc17e878,849eecfa,5d387fff,58f2112c,3df38b46,51e347fa,5aa8569a,48d95b2,670c76ba,d0de339a,72ee87e4) +,S(d5d1f0ac,bc2ed1f,50490030,43fd020d,7a1afb27,cdf78318,6a043bef,b0708eec,c473908d,4d754fe2,a5fdea86,62a6ad21,b711560d,77ad85d4,e3b47175,b5133e52) +,S(afe283d3,8cbb257c,5f2c0dde,2fd1bd56,2ad33e5e,605c24be,51a255ec,5725b1bf,a050f64e,978a9ee6,36885656,5cf22d7c,2fb45e64,6df60abf,6d3f9e1,132311a7) +,S(179667a1,72e0c37f,33e835d9,b5b6f326,3d963f37,1dd07d40,e790e0a1,21765180,da24290e,e38be6aa,ea2e86e6,bf683d4d,90f5fb79,20257b78,aee8be4d,fa65eea1) +,S(9add8ed2,6feeca4c,d3e583f0,88398ecc,f245d30,a888e135,b86ac1a7,e4e42d05,41bcd07c,c2e6acef,bc488d74,8a338c9a,7e6d3e43,85029f75,63dcde83,54d82232) +,S(25ba1237,6bb6e146,5195db78,29f51889,869dc972,fc9805d3,f6dfabb8,bce6b,a39dfc2d,223f924,47ae617d,537a4877,e6a47e0a,7e5fdbca,e1bfc956,a9c42571) +,S(dbd78620,c9a75ddf,55d0a41f,7312ec44,d3108f34,e7d75195,d3d49f99,88e2f986,c184bf06,ef304b72,1637bd3a,d511dc92,297dd5f5,9bd8d053,a048702a,fdbc400f) +,S(f8d67c64,b71d14af,b07d734f,675913cb,7a1bebc1,6e4a4916,44f8f4f4,6eb69448,eda6023e,5df40a5c,89a7bd26,94767a5,f17042ad,f95fb4f2,88bf9fdd,b91b280f) +,S(fd5f3228,56c096d3,4683a672,64ca5d76,58a8b7bd,41c3c1f2,5de2e6b3,164c8fd7,8372223f,3fab4f89,f6604b16,dd66db85,b8a27eaf,30741bd3,7a90d34f,f19c154a) +,S(ea49d0e1,b07948b8,b122d52f,8e8be6c6,e470262e,1c239b40,483a6076,c005136,b81ee77d,3d8489ab,42a9978,48a2ba17,273517fa,604a2abd,f2e1e726,d71b7e19) +,S(bab8ce82,c1210a99,ce17a5cf,3636baa5,52cc793f,89fd25bc,b6f078c3,92149bc8,afe2bb15,d00cf460,953a7c1c,8e466556,136ebd4e,ebf61a76,e49726f1,e3aa8e73) +,S(98802d2e,225bcdc7,9e02e746,891cdf12,ac434154,c08c2e78,589dd9f4,27277e1e,1eeb6b5c,4fc6459f,28e3fc49,6d9a6baa,fc66ede0,85d4b0d7,4af45840,78987514) +,S(5dc54290,2b33fd65,7d37a22c,c669ff21,75825cad,b34e1ee4,7aecf7f5,2dfd750a,41fb96de,60564df7,6c8ec857,d7f0ceda,2b330fda,2195a70f,5f64f973,ec0144d6) +,S(c4894f07,f6679f4e,13369495,dd501aca,73666303,2f7bab6c,fb81d7a9,1495834e,31b7e5c0,35e81c22,89de373f,85d648dd,892021e7,1d120742,e4ac6af2,44a25a8d) +,S(f7c9950c,d5c5afda,ede613bb,8f21ca15,b0e92487,81e16378,c7f2cba,5efd7beb,1746037c,b9211262,f0867180,16f0fed1,75debbb9,5eca39df,ed757c02,aa282d24) +,S(96703c67,4e7e2859,f274e7f8,d458f7a2,89ac0bc4,961ef3bb,b120a1e1,b82b5a55,1f92a15e,5e8b476a,a165823e,59da387f,2f9ab551,4703010c,c35b787d,c7d8ddf) +,S(4e8fa83b,bf9307a7,8b997e49,68227e86,a0402f0,643f98bc,5d13837b,63d08156,81f1f92,bb2a9ca8,14cd212a,6de7ebe9,7a04ed97,4de89e5f,cd8749ba,6e49e4ea) +,S(bc239122,b0cb1f43,2ed0c2ec,bb3c5391,b7eebafc,c4190fc5,8f62d313,7f58c1bd,5b3cd401,d9cf971a,6b9f70a4,b6f8fab2,d0026a24,cceaea2,a86aef0e,a76a3cfa) +,S(90b7138d,5d2e11b2,86d29b78,521aa9d7,205351f0,1451e134,8a593b78,fe5f1778,77cdd3f5,829af7d9,937ac98f,58a78b99,b54fe9d7,593415f2,18dde880,b5039a37) +,S(631d0fd3,27bca9a6,aec8eff9,54fdde7b,df43edb7,b1f602fd,a32c387,825841e7,d6e8af71,273702a3,a2a767af,3c438f0,b07ab614,2fd0f67d,74a9d358,74e29100) +,S(ac2a0153,d810371c,6a7bc097,ed09be67,14ae9935,4a9910ad,7ee77ab9,6d54cdee,39707795,a4f01640,87b5e149,2ec8fc1e,be11d8f7,c43555ac,6f4674fb,8ac5b0b0) +,S(89751ec3,c1aeb288,1953d3d3,f2f634ee,29b1aa18,c55b8b62,59d5cadc,852ac99e,8b4d51e7,e2f94c0e,ef80e16d,9b62c935,2ac91394,902537f1,e93744c9,72f22a3) +,S(849a6cfe,5e3ab81,2e21f491,4c6ec76b,5233d405,7ffd487d,bb0b5091,2ac499d2,a490b967,b5fcea21,d0135ec3,c9ed5efe,ecf7ac6c,81e06648,66cdca60,a1be7037) +,S(4ffa897e,17d760e,41859b6f,3bfc421c,55fa1e31,eb999f72,5028be41,cc8a9ed,87b4b5ab,d9875b94,aebe632c,64ea441c,71ec7353,5ae2c83b,d9b904e3,7f7fd326) +,S(4fda56c3,8bae34b6,55b2ed2b,621e5074,7ed1dc13,a1a815f3,be12a223,d54c43c6,6cfaa7b3,c53a1dfd,a03dc7eb,6086b84f,ac280c55,7c357d16,fa5938cb,c149bb10) +,S(b572c9c7,9ecd2ee3,154c56a5,9c81444c,b16df1f7,82198eb7,40a78c7a,e5c7e99,a1fb603e,42d3ac6a,5ef5dd74,ced31624,fed9086,5b02b3c9,2bbad21a,ffb1b79a) +,S(a77038c8,e79abb7e,a94b4e17,35f0f5fd,a07b1ad3,367047f4,895a5104,dfeaa623,e9bef9db,e8e2078b,346aee0e,efd64657,2210e451,ed2e8d63,b92be059,c577e1ea) +,S(3158f3e1,14de5071,c6e2bff9,32f1c269,7e374dbb,786e960b,7e59df03,26e2e1c9,1d0e950a,9124a626,4553d29,3e5cb8cd,9dd05d45,f48de2ba,f60fcee0,ca42a9cd) +,S(b0825b69,373aad7b,53c256c3,1258169f,2736d47b,1c4aa22d,a052b864,375a807c,23ec01bf,a857fa0,1f3d46f8,7857b211,f7533c9d,611dfdf7,951d190a,d7ef07db) +,S(9578e6e2,1a738f66,ca04647c,ec610da1,afc5602b,1e72e096,bd192ed,f19c205c,fb5da982,7208b4e6,11e6dc5d,dd8b8ba3,569a578f,275e6d21,3417fd37,7e4e6cae) +,S(a0aa979a,5448d27b,e42c39e2,2fcdf40e,d3b64c74,42b2c40e,2f6d38ff,fabb196d,7a9bf938,937be244,38aa212,d9342f98,ab9a35dc,1361fe56,5d04a25f,176eaff9) +,S(f535145c,d57aca97,f4cef68b,ce57d5fb,62ccd1ea,b48dfeb1,3b87b188,4614be82,1323e73b,dcd6b16f,bc481294,198d8235,b98a1885,a336f07d,593e5df3,a21ccc11) +,S(587d9e30,2f9d60ed,eeae03ca,252cd2fb,117bd07,fc91163d,a7cc569d,1b023f9f,7bcd5b42,3c01038c,9d3f7f71,ef52b4ef,a99e4be1,6de4314a,5e517e8a,950f45d5) +,S(b1e3b70,aa8a0cab,ec119ca0,5430396,ed98d9f9,e3e1a650,94cbd985,4cbd0932,3c9496c8,eec7dd92,9718f7a2,8c7a67b5,c4e55d88,5a943cc0,deefbd11,fa4f8de2) +,S(8f7001e2,928200d3,a478ba12,424be4c8,de8f16f2,a932e000,1468d9a0,48d57816,bedb10ab,72eacf26,1ab17a34,e5138686,34995952,545129b5,5bd6c7cd,84b50bc3) +,S(c95bae04,e1c397e1,498822f7,b7910019,922e43de,83119ae4,8517aa9b,aad6f35,8fff7d3c,d8bd7af6,c8523375,84f73aa,2f1b03c6,585c7987,98fe29aa,36620486) +,S(228fba21,ffe5ff9c,e04017e2,7cf04c71,1cc454d4,534d3404,49bbd1c9,60d2230d,825fb4a9,169ab67f,50963731,10f27fc3,f6f7acbc,9f2918f,c6f0bfa8,a92ed32e) +,S(89610875,bb7c5f53,87929e38,22249817,ade80ed2,a69dec5a,eee31a48,6c40e316,f7d5f522,92a53c2a,447f9b6a,5c06b3f,22fcf19e,4a200ef0,9167c255,a373ef47) +,S(9f0542f8,8e7e2b4b,c20b7b5b,87f051af,6650f605,67dca77b,7b6e1ccb,2a63f6e8,2b80c840,5e343203,d0a7d1cc,ccc99736,4bfa10d0,6e71880d,a0955cc0,b1ff98a2) +,S(859b6ce5,b7075222,549b59bd,3de967b2,1655d163,c57e94e5,6c9fae12,e5222061,25b8cf47,baba2000,19036027,fc86f03a,1c4c406c,4a8b2c34,398b7191,bf125aa6) +,S(e6febd1c,91e66c5d,afc7caaf,4150a023,b70c57fe,2a14f84b,c9fabce7,34982ddd,b606e3cc,f997b627,a0a02c4c,e147e0ef,58e3e275,a43940a3,4ac74760,457ae5e5) +,S(956912,ea1f5ce3,52d39e67,a41e4ec5,8c7106e0,4552e1a0,48e4b195,6cff8c01,b1eb2fe7,7419c11f,f7e34dfd,a752064,39fa2e6f,b9f9d34f,70740950,cee3cf40) +,S(1bca39eb,9b6a5d5,3575e510,6955143d,a6fe9d67,999500,ea78cb89,d832ddba,47afc8c9,358e5f7f,e92370d1,44ecac99,4e69afbf,6ef1af7a,32adefb7,9331173f) +,S(2c6db85b,c4d84c2e,61f0b5c6,2f330e7e,dd672c63,a14fa534,9e4d1488,ad462c5c,bb488565,cb2da5c9,be8a6f6,c71555bd,d85b4a53,20ca0753,f524f91e,ca1e331d) +,S(f66c0d73,36bc153c,5f85e297,52845255,8957a08b,603e4d3c,746e0c19,572c9f82,74e32022,faa58df3,1e4a02b6,f00ce5e7,bf34ec93,d8095144,a1af69f9,c637f01a) +,S(774959ef,cf8c126a,67012f8,10217d39,298040ad,da97e973,9fe13f9,927f6757,c33b9f7d,b2901f8f,171151c5,dd8b890b,62c0a1c1,9b7d4691,9c23ed00,cdafdc24) +,S(f59361a5,74b69786,f7ea4abe,44eef2f4,5000328d,dd72c2d5,a6dce9b8,63037ca6,34deb360,ece45bb0,a2417618,e7c67adb,24b33620,80d464af,a1ef20ae,35da05b) +,S(add233d,31c179da,bb62567d,2a5bc5d7,9afc5c50,93dc8196,9767ccf3,8790a5a0,b9ecd675,13d81a64,8ca5ab2f,4d580d3f,7f7d4def,909f2759,af61e497,b6d8f82e) +,S(3d204b0d,1d705714,7e947150,52a531bd,b6749743,5c94c7f4,8f821579,170fa257,ae20862b,cd86c6d8,e8344911,cfa8914d,f40e3a80,b762fd54,e2b7f704,4de86017) +,S(22be58e5,1c5ce0e2,f1ee6f5e,523a2f55,e110c4b7,bd3135d2,39d7a25a,94bc13f4,56894dfd,6c2cb7c8,5689cf04,3c1d4221,a7dfdfd0,d05b1e68,cc41afb6,6a472a04) +,S(6e015fb9,af8ec2d3,9f101509,f8f1fc9c,d95dcf57,82621ead,4651a062,c8487687,c7dc43db,d1d068da,9cb751fe,51251bf8,7f6edbc0,bb19925a,bc02cf6d,d7cf8554) +,S(3baa1e60,42844786,fb720758,67ec526c,2e0f7fab,ac8e0eca,24eff876,47720c2b,909d202a,b40037e,9afe2ef4,d8638491,d27a1d24,98e497a0,908a52c1,52b1f8da) +,S(689cad9b,2cde514,b9c25275,d6a3e68a,ce0b2216,4418a403,a83d88a2,4dc4d25f,53e7be29,165632b1,d1887aab,94c525f7,86166f32,56b44e70,295dd0d8,bb9f22f0) +,S(c1cc4802,101d0251,76875033,ed9fcc07,a66a57a7,71ca1374,63d7c7b,655fdb6b,ffa73601,5dc4ccf6,8afc41e8,e254501,93eb75a1,60a98c,6c800d0c,f10edc5a) +,S(888e34,86eef22e,2a25aaec,9bc9b84d,fec14fa4,c98e9d57,4fb9e08f,5b0f76a2,d2e3ec7c,db9286b4,b0223762,234d771f,a5b6f378,b6a4bbb3,c94c3303,af49b4f3) +,S(ab355f17,a43d24dc,330a9195,c2be2ed5,6894a9d,e38d3dd1,1a31f9d9,9ca88a93,7f8f8748,c07cfbd9,fce0ac7c,b624f2d0,f83bc49a,53276b00,7ca2b821,51988e6e) +,S(12a65c28,aa2020c6,5f56d916,c1cd111,10f68f0c,2408863e,635e05f0,1dbe4141,48bbab23,1be95484,7a0b61d3,89913ff4,5a8b97bc,384a0780,294d97d3,9c9b9be2) +,S(9d96107c,591d95b,42854234,1371290b,370640d4,2dca9fb,5f5397db,84a5577e,183fa1b1,cda4719e,869c8b44,e97cf214,3ab14e5d,e5d0d781,78e5d68a,923b3dc4) +,S(7ad05c26,aa642731,9eded7a,43f72faa,d344ef4,d413d884,67bea154,4459ad55,cbd8ea0,7fcbda54,813f990b,a6eb8450,6faa12d1,cd478a9b,cc278a32,511ba8f9) +,S(d1ddaa71,27959090,65ea358f,b887e4b0,894028bd,457d217,f1ef6b9d,143a2292,e040cd3,d5f19cc0,456a55a3,88ccb81f,787eae9e,51a289cd,d8ae8d25,881e6ed2) +,S(ec3bc5da,a9be90e5,1af0c1a2,bf41adfa,8023bb4f,b40e65d1,c65a0e82,6bdc30a6,d4962737,f9df1f4,48df1d9c,d8f7a140,233c2175,5d8ef5c6,f292b230,9ce263cf) +,S(f3135904,dc55f515,806dbecf,d51b8106,f13dd1d3,43f78e05,91de1f94,86fd193f,c5bd3002,24934faa,2f9ec634,53fcb3a8,20af608e,efbeb963,23871faf,a7dc2246) +,S(fb5f135f,b2f7638f,36bc332e,1bbd2050,335c141a,49db5452,619f266f,df85e8f9,6e71e045,827c3ef1,b75bffd2,ce54361,1e627cca,c94c8d3c,9b8fff62,e10b7b6) +,S(d1dc12ca,62a1285,e3c16125,f71a1b7,7b0dfa9d,c1068ba,2bb56bf3,98864620,6a6bda82,232af467,afaecb2d,f4a7ca53,3c41d63,d8f7093b,f04a2964,6e4f19e0) +,S(52354730,2d24cb39,f9117e35,d9374ea8,f3b6d027,cfcc23b7,58f0bc1d,b4f2d94,83719f2a,ccc79c43,1d8ea584,c78dd5f8,daded80a,fc3341f2,5789181b,7671d586) +,S(fd8247d,d208839f,93eebd97,f6068ae8,a6640a46,48c16b65,6bc992b8,4ccfc5e6,dd560b93,9b530bf9,a8bfd5f9,614f498a,49e54061,61107517,e9ab0104,54e42f3f) +,S(da5d83a1,9254990a,c14af844,df04bcb9,accab655,5468d08f,3b5d93b8,425f1600,9e5a8786,6be51fe3,54bc2412,6315f8de,1f0113cb,ae78b72f,cc70572c,d978fba6) +,S(1205f8ce,b9c89dce,13cd44f4,9ef0b2e8,14b78639,372d9f61,f0543f54,bdef2944,6c820a46,afd1dd98,499636d6,afc34ae8,218a8c90,2f210dbe,530a9211,a058768a) +,S(7d94e0f3,3969c5c8,164739ff,11aa05e0,45b32702,333d947f,8a0cbb80,57dd3c71,7b92b367,33f92723,17948d9c,a1875303,865fd47c,ecab145d,9ac9d4c9,864d62bb) +,S(d7f22ab5,6840dd87,d939c4ae,3bbe5a67,75e7a2c6,dc969a96,40c7f65a,9c18b2d8,bfc60718,2509244,b0ab951b,f4032852,54b73d5,a23a19a0,b4ccff25,1e5dbd6a) +,S(cee33146,2accf4fa,5f06b598,cc36aa06,342c83d7,eb4b6aff,90b9555b,fee0fe61,97583a48,5c323459,ef4b3f02,bf63f9bc,315cdf91,6163b389,c6a48cf7,4127da34) +,S(1e1d2d64,1ec550e1,1a29bc03,cf7c8442,ca13f10a,182783c0,d4ee9bf0,8c3c8a18,1ca8ff62,fadef98a,4d1faa0d,28e75e5f,117cd890,2934e457,e042b870,d8cff1bb) +,S(f10b2e75,8246bf49,1b70ff95,a385e701,dbbf333a,95a94652,6df7cb7a,4b4cb68f,ad15b5a4,d39d6458,55e57a65,3872d9d7,5f4b3168,182bdee0,a6289f68,aa7f99af) +,S(4674dd8f,16ba5557,c9ef32a0,2b6be805,e864e7af,c4fecb8f,666cf396,f7e6b0a7,c9d95120,73388bfd,45f702ac,8851b5b7,531edbe2,df04d855,7bd58b3a,c889f48a) +,S(95bb741,da472f82,8ff1f98,970c2bc9,1dcaa4ff,2cd4c0eb,195978b3,242c66f5,1e097cf6,d47dbdfa,8c3f2ce,90e0ccde,5adbd581,9a6e135,957ce258,805a4130) +,S(9a892056,42e03fae,b24d8fe0,f94e4f6f,d0c72581,604a65a0,99e3d28b,b103d2dd,c6bee4e0,d94c30de,b99c1a21,5d28d7cf,930e89a0,7865ea1c,87d39f5e,1522b33a) +,S(ade39c3b,e9540095,2176bb09,20541076,dac8e68a,a20903b1,5048e5db,4b0539a4,6bec56bd,60596cb5,7ea8a355,a6a6a4bc,90871c81,de902b0,6abd45d2,5802b204) +,S(45f808f8,bab4b4e1,a790240a,f036516f,bf0a8eaa,dd4dede1,eb88bbb0,7d248b8b,3f3bc72f,bced768d,bb90ddef,5b1baa9d,aba634f,1fe19842,c3b4b456,8957794a) +,S(ac9aa903,845a3081,2ddb195d,d79ffb6b,6e8ef0e,d34d0a5,49b577ca,35a116be,368ddbfd,1c5a2fa,c2c183af,19097414,82b272d0,52cec4b1,745fba6b,4a9fba89) +,S(ba26fbbc,ffa6b9f3,584f18ca,255da089,f561c30f,29a378e2,9f76de9e,b756f6b6,55f67b11,81ff78c4,c4c86e7c,931e314f,dffb392,306a7145,5efe875b,fbe39ba3) +,S(d4b1a902,1ebed925,9d53f2e,d76b03d,25b4241e,d5f932d3,a54c4dd5,db3f0423,6f1dda69,9e60053f,d9d2f5c2,c2ed2ae8,ba3337a9,b669ba05,3e48d974,f73c2d93) +,S(bc91d139,b2de4778,458ca891,fa97e413,d4cf32b1,753cfe0e,540726c4,648b451e,b56454c3,4f568840,6d198248,19ba350e,aa291f16,5676d7c9,fbd2d592,169c76e7) +,S(cd7a85ca,a0f408b,26b29306,3e01dee4,acaa8f9b,36f7273f,378290f,a4435450,1d9508b,1e7f5bc7,ba8fe5d4,f44e8c57,2bff9a98,887c3ef5,2fba3057,f132c5c5) +,S(497f8e85,57880856,32edbfec,b0065ac8,3267fc31,da9100ce,c2b99cba,1e7c26f6,e6729428,fabdec3,2db731bb,f33cf45e,5001b890,8f82c0fe,f7cac291,f89c6a46) +,S(68a607,4065c372,a95e7a6d,fc742e32,e59cc4b,86f9127f,f9465474,a466e30d,58e59131,1cfff974,e9e9162e,e974de92,904ffaf6,ffb97f49,d9dbb1ca,bfd927e) +,S(79d2dba1,67b93ef8,82ca60ef,b803e1a6,eadb4406,7f9dbf6b,d45c1a72,23da19b2,a59f1b7d,9ca146bf,93b89f2e,244dbf00,31511075,4dc03050,aabf0d20,41230ad0) +,S(5a2802ac,f4b92bf8,1c98c431,28ebe1f9,c921c211,910b6648,6391ca0e,4c6ad50c,5a0d7b4d,49b5835,dc3b395c,83031571,f7c361dd,840b41d0,405db351,14d86eaf) +,S(87b8a84b,1fd98b53,e9eede06,74555c7d,806d5b7f,4cfced4,16203280,18c398d5,a38c4d7d,549bd5d,28fa39e9,805e81bb,975cd137,64aa8c7c,a7055d63,bdec52f2) +,S(f7ca4d9e,7ac11395,70db6a06,c7f00833,5982181a,6642846,5d0899bd,907a9223,2c3dcce1,2ee6a995,52a72eee,e0968552,919502,5d4962c5,a33035d4,501badda) +,S(15bf39e1,5a11ff6d,216c0f7f,f1597f7e,ceeeda34,91b450f5,3b3407cc,bf7ced7d,325462a,6591d018,e495c6f3,fedb3abd,75d5a4f,15e9ab99,e43418cc,4aef1ecc) +,S(2755adc5,e69db19d,7caf52ee,117c6907,5b342e73,4af64a4c,77b369d4,269897b0,199bbefa,7e0b1c10,bd78ead,d5e65a6c,e6b3ee49,1400b9ad,a7874bcc,be580d5) +,S(96ef0e89,80602225,1d8bb9e8,693f3a67,5152cc9c,43c4e953,5310b9f2,c4338d8c,2414e799,14b2d6e2,a9be60ed,52508d6c,15765c0a,7fc1746,8820fb99,a9feed56) +,S(c1642d67,339fa6dc,c553233f,116f8086,2edbfc24,5512c2bd,4ca6e348,712bfb19,65e9a14,c7356a36,625022cf,873161b8,ef43ce38,a99586cb,9b5c8189,f3c6b8dc) +,S(54c536b3,cb6da9b7,e4483ce5,d5c9e660,bf973ef2,f4c8b095,f52dfbed,ffdfb96e,777f16c3,b026b75a,c9863f38,d015f04d,e1067f2a,a9cbd15f,9ee27475,ad46a4b7) +,S(706041aa,63dee9bd,4a441238,bd343bef,14e69929,f6e007e,181ae87a,68362926,36e15a44,57b86f4d,9b233dd3,37fab91f,67e4c811,3340463f,8f443b50,5a0ba014) +,S(49acc336,116c91af,6f90a6a2,d69b9d3d,c0be0a16,afb9830c,c1af0b5e,749b2765,bc4f0f6c,725e037e,3a9d9be6,c5d4f80d,67b3e28b,92e5d3a8,fbc8f66d,9ba97d52) +,S(96bee384,ff79ed86,a9d816cf,32f3d569,d1ae03d2,d154c65e,a117707d,74c818b1,848e45ec,27eaad75,5328d84c,a76a7235,ef4f492f,5be115a,a622171b,51dbac8e) +,S(3b2b0810,c4052498,189affe0,4c7ebce7,b9050aa4,6a702d0f,72c5c770,4ca4d1ec,f782ad72,1bec3b8d,b1df97d4,7765434f,e4145c81,27acece3,9dbba604,4df2543f) +,S(54c3547d,e4873721,df6215fb,ef7bcb4b,b9acce42,7b0381cf,2de151f7,c69549f0,5e7ce1b,728a3b21,e94b4138,bcb89af,f4778dba,fd21aa42,16d83a7c,9ae81edf) +,S(9f1c53de,e7b895d5,6081585a,c6eb3821,d89bfa61,55cc96d2,e8b6c472,edf57f27,38369e41,ecbdb4ac,619aa7da,4d708eaf,4c572ed7,f1f2c079,d0bd17d5,3ba8288f) +,S(e79f75e,a1a224c2,a0533936,65a5f705,15eb0aed,b924dfbb,5aa30055,d1d82b44,30c65139,f6a6f5ee,5304334b,1ce9dd15,27ba6031,2ff2697b,8eebbdab,67105171) +,S(7f95a1da,79cf25cd,a904b7f3,11674d02,fc6dbf34,ae8ba7e0,b179b48a,d942821a,3d3dd8bb,31cbafd3,247ddceb,be1faeb3,b00e057f,7e90bd1a,78f89cdf,648f7c8e) +,S(41e83f7b,9067a7c3,bb6ec755,ab7c83a4,dff74c93,65d0259c,cb635bea,718a416a,a54a4b56,5286b26b,d0bec338,2053c349,2de80062,2189e2ef,ed10e3c3,9457a34e) +,S(81599046,453d0a96,2c5f3b47,fee7f827,537c7c58,c5ad068e,e5e6ae6f,7a9c6848,4a83b015,3abd0df4,177ef3f7,e8a7ac7a,e8e5afb9,a2fd359a,c30c13ee,321f943e) +,S(11c9aa76,2cc334f0,a3274f15,17a1e60f,2f0eedfa,d603f83a,120162bb,e87830d0,7c73d374,26f648fe,4a9978c6,a64ac787,f4c8d79f,b58b0f58,70e373e4,d317136a) +,S(2b41f344,b285a31a,ebf4f4fd,f0c4f463,49fcc794,e5762e04,dc39efc7,936735c9,7eb708ba,3f683d48,db8e0c25,ac8a6f8e,5c340749,c3d6ed5,7936d515,7f3d6e73) +,S(dc063e66,38098e8c,6ff55a73,faa20099,c10d0258,87c19850,43d1011b,ab211b93,4abdfdf1,285ca3ad,65bb9a85,7ad647f7,fff01782,79fc6df1,6179e1d,495d212e) +,S(7cb514e8,b6361aee,f9a7abe1,f84ef401,97de721b,609c3151,a056eb03,71ccdf8a,4d359c89,7d03a633,369bddcd,52a67387,fd4d1e00,2406502d,9ba6e967,a5efd0be) +,S(103a6644,ee731721,bf29f036,97641fde,9775a642,9ce8d97a,26b06ceb,f9066693,127b6948,6db0d230,6ae90a1,4b8c8ecc,1e9293eb,cf154371,5ecbd579,e886a726) +,S(adfaf771,662d719e,532ba045,72a50f12,144fafd0,afe93f7e,1d8edd13,99226e5b,b4d0335e,8b600a4f,84d919ba,514bc249,e3048cc4,281db3b9,a7c62013,4f00bbca) +,S(609d9352,30f3c6ed,bf64275a,23a9a258,33fb8c3,9c25dde,4b55ce22,e64b50fc,cbbae84,c57f9c52,67278c4d,3b0cc5de,9327ba71,ca1a1bb1,8aec9a97,bce17552) +,S(5ea5aa20,1b958a8c,49b70510,b7c6a29f,86d9ded9,afd4e833,77c433d0,f62d9ba3,27c5cee9,fe3c0bc2,af8d0e30,57eb0f57,b1fa4237,996bf8ef,5ccd25ef,e1b87ecc) +,S(3f801115,3603a689,800c04d2,7d3b3fe5,c415ea29,c6e11951,7a56712f,20a10862,4280ab61,65b122e1,85abf4d4,14a31961,ac6595cb,421db183,34e57cb3,fe9bd059) +,S(54981ffb,5b692a3d,6d9ec7ce,f027fff3,c5dafb7,aaab4c5,572522b9,e1157e5,893183bb,554c81de,21c84134,e395b9fe,80a5a9ee,b06e3b67,2ef93127,24c307ae) +,S(97c18e92,d499ef62,77585c6b,28f36fec,e9a2e118,f793260e,32750861,a1aeb813,38a87702,7f1df077,d6e734fe,18a023ff,36c6d4bf,4a7bc7ce,d3a3d38f,c3069f33) +,S(d5507aae,97bb6e17,410bc87,26d9eb2d,11558b96,6c54e7db,6428b44a,3589820c,e78d0140,7468dda6,d9c4af92,1984460c,e523c101,79f7aa15,d8004dbc,4fc63cb9) +,S(220d6c2e,6c500d01,9ded2aa6,5de205f7,cdbb15e5,69038ba5,7bb1700f,1182ca70,64b68506,c387ec2d,9e030448,797bc28c,5e09e8a9,95f5f80e,70c26a1f,db7b16b3) +,S(c1a45038,da6aaf1e,396595c,3ab404eb,9584ec90,d894985c,18e779de,793d20ba,1a443da1,72e281aa,4393e1de,6f1e4f89,4fe5d1ec,b3a5bcd9,607cf79e,6f20b533) +,S(9a66f9b7,f3162c80,d22d0b5d,2a659bc6,ac01c74f,46804ca6,c908b6cb,90fb419e,3465357b,209c2b,a7c766b6,9c17abdc,69205c54,787fd0ef,e744692,16b95d3) +,S(8b305bcb,1b6156e3,22f0f0df,28265cc8,79e5909b,b76b546e,eb223d62,89883387,929a341d,dfa05574,90cf5293,244d924e,852b00d0,d328ffe4,7ccc5356,623a31a) +,S(4e36ee67,b5398169,8ed9460a,cb450023,7198f249,4dded391,4c2ae003,63c8f664,a784c95a,9a443b7,5859a1b1,373eb750,150e1ac9,d5120ca6,f273578b,73df77a6) +,S(167275aa,38d02988,c53e0a36,d8312e32,369bc677,6d7143df,cc6fb83f,66747caf,f26b9851,31abcf45,369a6415,84b2956a,7122a51f,b909bc30,5427eff3,916e6e14) +,S(c93d0b74,c99358d6,d24a962a,15adafcc,8a4e57ca,df0afeb4,9d46ef53,cf619797,f93b324a,b144c6df,336e34e1,beef5c13,b931668e,54ab34a5,eee1a8f5,5acc683) +,S(8bcaa2d4,671bb4b6,8a924109,32128551,fbf6d924,d4854027,7c1dff57,3bc4a8f2,88be3e1,6482477e,62255fb3,24512abe,27cbb4df,f63c6d8c,93c3c923,47e519d2) +,S(69d186de,f9a7ea8,be833f2,590db08c,fc0acfbc,64a648b6,8ca412d6,88c03808,d776b644,43a81bf7,527f658e,45d92324,a08ce171,6db6c259,898fab8c,f3d6d41d) +,S(4a53595e,e2cfbc6,7bdc9f07,308f57c,7ff5afc8,a35e27ec,e22cdbdf,6efde161,e55913de,d481077a,ea36c502,494b3b72,b1691786,335b0278,3e40fa1c,1a1b0876) +,S(90856f9a,5f7bbc14,557dd419,516ce5c9,aa451bce,13c17ce5,5c9fb1b5,f2924995,ca083d2e,b5a3a067,4a2534fe,e03bd99d,976b96bd,2b7f16ea,6e2552ee,648e934) +,S(2eed315e,d863298c,aa374ca6,2bf8313a,a0ca07e1,9a94bc4d,58eb235b,52d36dfc,afa36c8f,90d7adeb,ec33ec69,40c08d1f,2a4044a7,477da88a,6653d90b,880856a7) +,S(345a7f2,ab7ef064,eccdbe6a,ebd11dc5,3c7ede0,b62ab3de,f8e409e6,258e84c4,c0c0dce5,93cf9647,c0228d8,42b78407,c3b634ac,799fae19,f0e685d2,6ccfd73f) +,S(5a669d7c,209b222b,47843a5a,633e0b53,48442258,663a58cf,f6ee3cc4,1b893d3d,7067be1d,8636698,2b808b16,3c05e57f,2be77d1a,2bf78038,e242f5c7,4ce10523) +,S(3f0b0f3c,30a991bf,927f5119,6fb4af39,e1399d01,1766b1ff,1f0ff2d8,a3199062,be8f8781,4c06a75,97d062c2,196a49ef,93a73923,f43d16ac,82c015e5,4789d472) +,S(9d7f2c64,98e78982,8492b8c9,2e0e49c7,b5c9d4b2,e86c409d,828447fe,4a2f5a13,95ccc540,8202dbc,78323d6c,7ef66d51,4af34699,5be50b56,98a5864d,34e502cb) +,S(9f741436,55b3cfb5,39917a7c,79fec4ba,164503a8,3958aee1,f6e8f34b,3d861b78,345738c,ff8f3c64,f5cda5a7,a1aee7ef,f3a33141,a5139c3f,b891c6aa,feaaa7ad) +,S(cf1d3136,11d4b6ec,5f1a9728,c9a7b037,d9c16d65,bad95fdb,17376200,b1a9a97a,51c72169,bf7b1ad8,6159fead,dcf3b0a7,a7fc13cf,7bf12d98,409dc3b4,fcb7a9a2) +,S(7e04c6ef,c7433f3f,fa2bb827,3fdcb3a,e0470abb,cc7c8dc5,414ff77a,915868a0,781125c,2184eeb8,87019f7,c5c0b4a5,5922d11c,53c3db9e,d5795bc6,e7539cc4) +,S(fa6d73b2,a97801b6,16697ac6,102b002a,53d29d33,289708f,d8f73964,77f3d57d,543db558,25c67a4,cd010413,9f8a093,7ea7ac2a,380799f1,c2249569,3cf557dd) +,S(d0fd7208,8deac18b,1bd63fbd,6d5be0ef,5dcd34c5,538a9b64,ef43daea,ef321d1a,7a5e1e2a,1b290241,7879f223,8cc8928a,65988130,81366846,69841b93,3ddc3a1f) +,S(e856e67,e28330ed,77d8687f,bfdce5d9,ab8ec155,4c94ae0f,491d1e43,9361cb99,c51585a1,9da7c26a,4fc07c6a,f17999e7,a6718542,d7500fc9,1bd21fc3,8acf1eea) +,S(389cff20,9f240748,b9beba0,34d36e0,5e758a3c,95c678e,28cb0226,37db1bcc,ae5a0d3,db1e17fe,30daa2af,1e1f759e,905811c8,95706b7c,e5741051,2b7ac4c) +,S(28ce0f42,ff79cdb8,16b666c9,c3014051,d46e8df2,e2377c3b,619b78d5,17f21a1a,4e835188,f742237c,fe581edd,937b7294,e06fb295,d401b35f,5b7b293c,6d57f875) +,S(3d955bfe,5b27beb9,68400d11,3b8666e2,63af6ef0,ac6ee49e,8628e2ac,4d1e69c4,1fbd2aa9,b6913655,e00f1384,a15a7215,d3d7340e,4891893a,a67faf39,88801e9e) +,S(53dcaec1,2dd48ad9,ee65c9bb,ef21a023,58cac930,316263d4,9d607074,8aceb771,5b976f2,411d7624,d4659e5f,db624b05,9dd5e06e,f0b65740,ba394020,b9d279dd) +,S(ab822568,f7e9da8d,3f1220e3,24752c80,b02a8124,f8d9f65b,3b4532ec,3740881f,6c2152dd,34451ab5,b47b7c08,f7edada8,f9f230c3,5fdc2de3,35cd93d9,e25703c8) +,S(36719c40,1518b976,684bbdd9,2a923485,ce92b321,dc26534f,e5a0473e,4c873c30,d5d58a83,d493cccd,d16a1282,68aa93e4,94ce8638,41ec947,930c72e0,887564fd) +,S(360c82e6,18a53dc2,e44677b,a0bb8c2e,2a08f6d7,afbe8498,15d605c3,2e5fa969,ade18222,e1d0fbe0,a31c55b8,d2cb947f,1fcdea11,1e08ea3a,4f3dff02,e3e38b70) +,S(ecf50737,25a3b81e,dc621bb8,6c98fd59,f805d6b8,2f08380c,64270df1,95f020f,f5431b8a,cba5d27,1da26cb4,fc3412fb,14ccf088,6e0e08ff,ce0db47c,6b4172aa) +,S(3b751389,e6dadda0,85298860,76076249,46df960c,e030caf6,91f91d46,4d05be4c,244b0028,48829fc3,824dbe61,168fa1c0,3e4d3835,d3da3a53,7c729f0a,191e92cf) +,S(ee6e33ee,7fd9d7e7,aab10b8d,2c58f2a7,26ed307b,6fa69b3b,f1f08a74,f1b04ffc,4233398d,6ee49505,c5f21525,6cc9112f,5dfdd7e3,4bfb9a8a,476b3cd8,2645b8f) +,S(e7141075,e20f0903,f39fa384,f91a5708,7f24deb3,68571939,572caf0d,2fb543f9,5265e24a,bd84336c,26b4607,dfa25c44,49c4693f,adddca01,599d814c,21787cee) +,S(d401b043,ee9944dd,7429a8c9,4291dc55,7e5827d5,88375dbf,1513d394,a778826a,9ac9b417,5ac3666d,7c6327be,5172b8b8,1dbdc96,eaf8578b,76f01128,4434b937) +,S(d48c45cb,b90394d8,23574c16,60898091,75d503b5,99d936f1,f60246d1,79c9cac5,4e6b2bad,a67ebb7,a0743cf8,52298052,2737f0fc,6cbef646,fb270d44,2a285612) +,S(19f6446,fabe1899,ec4476ee,1d61f6af,961da42,ada1f77d,2ab41cc4,28791c64,7a0aa5b1,4f2ae030,d9711963,bbe160ca,424f6a7f,17b6a709,b5f0dce5,af1d0498) +,S(2db1d56e,f19a848f,6d6747c6,82cffa47,78444b3a,d57ea076,b0560b1c,4e57c83e,701a5894,d1d6b6cc,b421b168,fd34aeaa,e85262ab,44f70c65,b8ff61ac,ee541cf6) +,S(443597f7,9da3df8b,5fddf8da,3bc3a060,83f2cb6f,affbb1ab,8a12db92,59661adf,31b2c4ea,362a0cbe,2b9b1488,719b7ac4,3a85f7c9,63e9f2bb,b46ee055,71e2ac2) +,S(e49ad52a,7bd2db07,d972def2,d1ce6684,69aaf6b3,3c7e3427,52d79fa0,9d2ee9ad,b2063f37,1ca78c2c,429cd401,c5e46d6b,dcbf373f,5cb77163,5760b8ed,b4f91ba4) +,S(35b3fc0a,4a625cb5,808e1c2e,73c962e1,6ab7dfb3,28109ef,fdf81e15,841afd0a,cb558481,145a5f75,b639133e,8ce42c98,d36d8fa8,5348c815,d92a2c8e,cc993bf1) +,S(1cc238ef,3f64a075,c3c264b,ed42a0ac,aa6de195,7db40d52,86c482cf,f62f609a,d3382317,2b8a1450,bd918aa3,c57de76d,3012887c,98452f7b,c1f58610,f528af49) +,S(f5a2794f,48885192,dec727c7,79fb0b6f,c2cdf399,4ef7cacb,94e35791,4d138e84,d3ed4f1b,912f5dce,5a0842ff,d2e671b7,f3ae8448,b1a73f43,249a1acf,915b9c34) +,S(21b41016,a8eb7c6f,5519d94b,adb0fa7a,5c553822,6d080e3d,6d2956e8,8a9579e9,802570ed,b9b01b1b,ed79b6f1,76ebc4b3,55dfdd16,f43e82e8,7803be0,fc44e274) +,S(9b5611b7,938ac10a,9818bda7,3615a47c,1ee0f072,75aa3dcc,b8919dcb,e7beaa88,89787c01,d088e3b3,603047e5,2f49981f,7f007c8c,a88502c1,3bd9c327,e3c83b1f) +,S(28163c9a,b08a7ad9,38c7b35d,b19e700b,3865800a,55a3103d,2213c9ef,2c03858e,661e089b,df356bd4,afcd0604,fa5ade9e,74c5663e,77ab57f4,a069bcf9,b8b227bb) +,S(bae9ac08,aecc06f0,ffb8540e,2589a32f,11d34a7f,6d899e5,7a8f5ec5,bcf1601d,f5b63d9f,8a5d23b0,80d0bb6c,b8df736,aa660a3b,6f987683,cc0a54e5,f7d1b4d4) +,S(19f48542,3ed01783,cb83d2d,2efd7264,a10c6c23,1f5a242b,112eccb6,31d91f7c,79ce383f,f011ce13,87537ebc,3e70dcfe,2cc2764a,3d180fdc,74a21062,a5b75f50) +,S(cf459ca,cc8c4ff2,c827efae,6593a52,838658ec,bf1a78f4,75965856,a8ad007e,786781e3,3279964e,da5e6374,bf088fa7,5d18901,df01a0d3,6c87b62e,b419dca0) +,S(c19f2008,e6945d10,471a13e4,8b16f3a6,381de3e2,b24f2d92,77ded25e,930d1f47,7179aaf5,322b51d8,7758219f,cc30e9d6,bad5ab77,b35dced9,6a513b4b,fa7fe147) +,S(3fc1b649,3b6cbecb,1767d0e5,6202c84f,39a6b41,87f05ac0,d659c45f,5bc565c,db9edee1,1768e29b,4eefddae,c6234622,55d06e0f,1979c8c3,5c366f4b,5cac3f5b) +,S(502f74d2,cf589c65,e63b2a8d,b2b1e4ba,5f851715,bbb27e8f,165fd34f,29cff7c5,755e6c73,765bc45a,c2f9d4da,499198a7,36743571,40846ce3,6afd8063,981a96b1) +,S(b9eb62bd,7cc6d1d8,b0eca2b6,1920be5,9227534e,7fb581c6,4dcec4f8,f1ec44ca,ac567b37,891e3eb5,c40fecf2,d4c5b106,bd222c8b,64ab491,f7a028a6,a02178e8) +,S(2e5280c7,25a109f4,c5de565b,9fe5357c,718f9fea,db53aa9c,b07a0f3b,f5030ad4,4783be94,1b162e,79f58d4c,448756bb,8ea18c4b,692e236b,4b2b3ffa,24a456b4) +,S(bd59ac74,92d24606,9b233efc,1b68c371,bbc9713a,284f7f0c,699a1d5e,ccca64ab,1abc71f2,fce8372a,a4a16abf,1d75bd87,a19c08ed,c8843f44,fb71bb7c,a74ec4e3) +,S(6acd12ba,4623582d,d769c8bd,3d6adabc,2c13ba3f,bb67e4ed,ee0fe70f,3f832f5b,982fce11,ff1e6c05,2f21be20,ce1710d8,5cc043dd,eca9bc43,5d100d9f,f68150b0) +,S(601f4285,8b0cbce9,90500c64,e7eb77e1,c433dca5,55e6ddff,5264a98,d688decc,56110eb5,d5b3ed79,5906ed4,c0275827,79cff7fc,ddecbe7c,74d2bf10,ab2beac1) +,S(4d393daf,c47391d8,8208263d,b8132156,e9fdd6b7,da48eae,90489d12,832dc938,a14180a7,898a5a00,6ae5b8c8,d034c233,93ed2ef4,faf6a4fc,42c4df1d,62d0ea7a) +,S(4ea24f6c,3c164285,166bf2b,1918b3ee,3cac8631,5a1175d5,4104506f,68b7171c,87da621a,a18d1a18,b1dc222f,af37b5a0,b149714a,e755ef03,ee3af91d,f2a7f5ea) +,S(eb1f6f2c,a5749f80,b88a7359,f0b67230,b2b844a2,4fb72dba,f5604e73,cf6e432a,6f58093a,55e3cb37,8830e58b,10612b24,56a35fa4,b8e60409,1b9b8304,e35cca51) +,S(2361315a,3d41b82,98a9d768,be7f453c,eeb977af,bf1db132,c831bc00,aaccc9ab,90df3be,336d4b58,7965778d,9300cc1b,3d954d4a,89abf173,a9bfd99c,29492dbd) +,S(44f432f0,46c7defb,630d5535,aca1bd47,10505012,6b2454b3,4591b079,7f8e9b28,1fdfbcb7,25eee981,c19f98b4,6bd19dff,9b6cbdab,730ca2e3,1643d415,e3aa0489) +,S(d563a475,4c130e71,81b60a66,a3f2ee52,7040f9f0,eac9e26,866fb226,f93db593,49fab7c9,6e320961,6f4610dd,532d547b,b24f7f07,f916f10e,630ae5cd,b40d3b11) +,S(2fac4651,f0ac9876,4a74c066,16e7f1b8,aa6d2bb2,99ef9f0f,43bca81e,7a4089b,fff2b7b8,c330e1f9,86a69324,a63bf10f,fad8e78f,dfbb6062,c96a67b9,eb460d5f) +,S(b6f60ef3,d8b793d6,5794aa89,12e8e1a0,9ef7604a,5c9eaede,b803fb31,e8195dde,b9b17946,4057de11,9d0bf993,fe92e4a8,bb633d6c,d03ce8b5,10200166,467e6bbb) +,S(d08c6813,65789ba2,4e580637,2eaa1ad1,d1254462,3cb64d83,5ea2e1d8,6e34620a,e94875ca,f5beb1cc,f88fa3c5,e2776203,a6f3cb5e,b4803618,52215d0a,9076b185) +,S(dfda222c,a4ddbb56,661f56d,b9b74be9,a5a7c34c,4761483d,928aa48,9bfabf52,bfac4ed0,ab4ccfa7,caf64d8e,ffdf1aab,6aad50db,595b1b49,7fab28d7,656b6475) +,S(3f72e4cc,ef5c0bbf,995bf8b4,67759969,d93ee40,8e738a4d,41f55896,17f241ed,c42ad857,3f49218,c7daca7c,8ebc5c7d,f9ac301a,2aea209c,ab6648f9,8ea16f5c) +,S(6e85f587,91431b6e,dd848aa4,70101103,f63881d3,2fa9f1c1,e3324161,e9ebf0ee,f7f00d38,31e09d69,f0684107,59dcf837,eed3d833,90efa352,40a9ac5b,2daa2a57) +,S(d991fc76,2f75235a,5268a32d,64dbeac1,b2333a34,5ad552a4,cedfab54,9b191f14,90d58a07,794983c8,3f6edcfb,55ed0b68,8f43d9f5,eb7678d,29610299,63c748b) +,S(24cd7922,7ef207bb,6b9b678,5156bf76,77101e6d,f5fb5576,a9d33175,8d7c00,44608974,5f1157bf,9c9f45a1,b212a978,8e348a0f,55129935,b038940f,84e91468) +,S(5c053ed8,367806a2,8545692a,47314850,66910d02,3373b89d,e85bc7a1,c25bf6bd,9a3e45f8,dde03e64,6d6c546c,cf4c8fc5,a253054a,2d6df43b,d8c4afb6,385311f2) +,S(4f3a4d88,20948d82,b598f118,1d350719,ffaa5ce9,9a7f614f,a9e3cbf2,e021a6cc,149c6722,980a41ce,5d4c0b94,9cbe3c99,4d94f2d7,c36ef45c,d7b9084a,79f451a2) +,S(badbce64,8d55b579,cf8d6dc6,74580211,a6bff856,10804077,adad7c2d,238aa542,567d75d7,1570d7e5,184f4f4c,a53fb92d,654b67d1,f6bff96d,fddcc3fb,932f0343) +,S(d2eda540,5f828eb2,cd3bc5c1,9f9a838f,8a1186eb,3cbe9575,5cf6642d,13601942,ecb3dc3,655ea992,4773cb57,f4f4c8d,6380c665,69f08184,f521dada,c108629c) +,S(191ad0df,31c7f3b8,258e5bfc,ec9d1ff1,2143b240,24d93a17,893da095,97304f1e,4ad4991,6bd2296f,b6f6b697,dbf5a3cc,4c3ba136,6f6dfade,c859b190,48fb523f) +,S(f108bdc4,a1874aff,35bd1fac,b8e81b5a,7a7ed597,e78dfb7a,c716bf7e,7a15dcac,b88e4fa0,d630d92d,bbdeda05,4a6c6624,e7bb1d5b,a6dded85,347e5275,e08c9414) +,S(30fb7605,7e2a6cdd,59fa279b,3574cf1f,db9d5159,19d0e523,990be02b,da1ebffc,5743e72a,752b558,1b959a48,3b6229c2,33fa1b3b,2719ad3c,a6f8f9ba,1702ae8d) +,S(6facb1e2,6d1ef1cf,ff413145,63f3b2e4,e762ee7,3e43378,c4c15f85,1cd948bb,92000e2e,a3a5bdbf,f6eaeae8,8619f2a,48b649c9,19972b7b,83cbac22,62d484d7) +,S(741c1253,8cd4da52,c596840f,e6233558,fb480a0d,43232756,2a9e2d59,a574b981,79040b6d,580efd7d,84356117,a93941f6,b47e6c0,a53627e1,bb80fcbc,e6881234) +,S(2b86fe60,2b2e87f,59498185,4af1f986,7debc5a,84ae8bf,94d2d6ab,4ec8be09,cf4c27b6,b33b5020,2ff7fdd3,ff0743e8,f28ca75d,3cb74d21,ecf21dab,ad7ae079) +,S(e6e7b676,9f0ed86,4163e9d3,66a7e2a7,a37f1ee8,e827b105,3119b8b,d36e7b84,c2e5b9b1,d82b4504,454062de,6c24430f,53e03bd1,819eb1e3,2f24606,73d09be2) +,S(86600d22,e7bec946,5b0afe05,5e733b03,f8f81548,ea44e008,740ac807,ddaabbe1,abb367d0,5e6d2fd0,a2c1d0af,5ded2926,1439c985,ef287860,80614bf9,8e8e33fd) +,S(67171261,5cbe2da0,b252a773,58f81c91,fbe561f4,87df09e6,cedc8a55,cb3414b2,bf02d81d,10a47287,2b7e65e4,93d97cfa,e3bd6ba4,39977371,8cde674,8829b0a3) +,S(97db468e,7f3a25c4,c34e202c,e9b2480a,4344aa9e,1b76a147,4bd375ed,6d10c0da,c58ceb67,a28f99de,2eca70ef,e8af24fb,c381f962,d5db6e3c,481cca6c,469c4c27) +,S(f3ac0267,ef19ae9d,762c4023,4ba97e33,a88b015a,e6a83f4b,cf730d84,405aed26,cfb8a3ef,d1104873,8c1c927,b31ebd05,105bcce1,d57c7fad,1972a5fd,cbe84f06) +,S(fa44128c,3c258fd,5a99c85e,775fca63,4e8a46d8,4fbff953,b373bd50,6ca3da85,f3196e74,d17cae3e,3c9958cd,ca591374,ddffcba,7e362139,17e5e119,a5538b1b) +,S(95244462,1eda0b2d,acdc1a57,41725c1f,a7c5660c,feafe18d,ff8789ba,164e7dbd,214bb6b1,7af1584b,76a9e5a6,2c32eefb,497324d5,7b00f71d,24b162e7,1383bff9) +,S(11de80de,c03a732d,6769e52c,64be4d2f,fb1d696b,2a658721,94aa384,392dff9,e1eb8932,42386216,f543eea,a2d1099e,531d8e27,7cb2e5fd,ec76b3af,e9e9c7b7) +,S(7318b452,a2b9d23a,eeb30bb1,3883dff5,b373be94,94451c72,36a2c02d,a4c37e75,26713361,aaedfdbc,2966fd1a,ecfa705,772012b2,564b077c,7f5db7b2,c810861c) +,S(82d189ad,e5610825,1b03cae0,4b138ff7,dd2d77b5,422535c5,cef9be7c,1899cf75,3634267b,1b3c3de0,d2dba36b,924949b6,7e05d790,29c9452c,18c6ff70,252d570) +,S(e5dfe995,82152513,80859865,f16fd0fd,e4d60c7,be0e2aa2,d9b2af4f,3714f8f7,e1d87d8f,fdef889,52918e62,5bcc90e6,83f337a6,103cd000,1cfd01d1,eef4b9bf) +,S(54cdeddc,9fda5fe4,63240f72,8ca66c34,ec05394,899f2472,d82d2378,28a06a3f,27bab620,cc373ed,10a71c18,345ff27f,e20e1bef,98052afc,bb45fdc1,80b94a2c) +,S(7f96757b,8b473785,e1359cd5,bffbce2d,5b26e8fb,579d7833,607d58,a791c47a,d4b43e2e,20a43fa3,5a96d1ff,93109aa0,b7831fdc,2d2c016e,181beac9,c1cfcc4c) +,S(eaed18ba,83238fa5,ce4e6c82,edaef108,b1f9929,3148f3e6,2d3a6d4b,535455be,1017291b,805f7b1f,eba367f5,9a1a10b5,f7501355,7e6eb921,20838c50,aab0d29b) +,S(91ca8ba1,da9c2625,66a135ad,81f57b10,65ea4632,5bec5d42,ca1ad62b,826f04fe,2d5d619e,84fac3c1,e30343ba,a61d3bfd,e1c4a9a9,8d968e92,d560956e,138e34ee) +,S(8a31ad57,12e32254,7d0d2907,cb73adfb,a9a1ed5f,fe98d645,22082e6f,1cdb1364,8ecc3fea,886737f4,f94a2984,e6edba9,8128b2d3,bc79a209,2b2c1a7b,b00bff9e) +,S(123acd6b,ca673170,400bfc4,1071cca5,4e03daf3,e1ed1458,88470c04,568b972e,e97dc60e,cfec2d5,c6a6e173,9d60f7e9,838ad723,ad0fc7e1,52b5e70d,b48b853b) +,S(d7c26043,ad647f0f,d056c10b,4ac932c6,6a545bbd,509de346,d4391942,52e69df7,6bbf2f04,2c9459cb,c72e6aa3,1b6d8e4d,e606eeb7,d5d4e0f5,7f729a79,ab1f5e9e) +,S(67c4eb00,548e2cdf,50626c8b,1aec1173,8370da41,9280c9b0,1c8783ee,91e018d0,ffff201d,91a4538a,97ceb50b,c9aac646,bedda1d1,3f22a121,c709bfc6,23b95a67) +,S(7e1264ea,486b08c5,19c7d8e6,5c80e1d4,d2994bb0,95185c72,63172b1f,ead93428,1797609c,816f10a2,e82afe39,65112a35,798b0874,b24503a8,f57c983b,6ce7ef6) +,S(912cb164,5f7d7bfe,5ea443af,1c458500,a95ff22b,212109e3,12fa01c2,41319cf8,bab658b0,111c48f8,a2f620a5,fd130d53,e1c70e7,62e33dec,55b22d87,38c1eb99) +,S(1d60694f,15577a40,f6b9f299,be5eb62d,251f62ad,b9b5651b,df804e27,df919fb7,3799eb92,e18335b0,bdbc29b1,f8ce07ff,3f7cd409,5840d5,dd324bca,2f902a14) +,S(8166b50b,811bf53,4a94af10,7672ab4a,4e154b2f,c5cebee8,c8ef6ebc,18cc3906,6dea31f3,343e5b45,f5b08c19,903491f9,349f4ca,29818fa9,16f5e02d,85e09ef) +,S(4852393,e42d0821,6664d5d,f85eee60,9660eaf9,54ccc6d,fb1c31f9,da17923,e4cadcab,17f64d8a,f5dd74da,eaeab7f7,13be1de9,600d4db1,a781a058,5ed2006d) +,S(f40031b5,ba171b26,e02be47a,c34173aa,18ec3850,1b1d529e,a922a418,1c3491c9,c2db89ec,2e50105c,4074b729,a53ef0a7,9371d2a3,354d2d23,8fb39bf4,bcb5028c) +,S(8926d233,3c842f9a,213547a2,fc5ef5de,b0bbd603,e69d347c,41e7d49e,aad76cb2,8459bc10,b7b2617,b0d434f4,b62a4452,80bb951e,b4ada14c,fa800389,b3ff892a) +,S(7f362b16,9d9bd514,c6289cdc,70ea4b77,e7518db6,a2e33acb,8acefcd3,d8c5726d,dd1e69e2,71d77dc,2629cded,72869345,7c63ea2c,8636c712,e45e6af0,4c15fe35) +,S(261b8037,98ca780b,50dfd56b,81093f32,d7c348e,4f093b91,70470ccc,4516ee1c,5723ca6a,5959d589,4a24c12b,5f87a5af,84c7a6a6,89304000,344bf5d4,81c7752a) +,S(d137c0e8,edb32642,12f6b958,8b527a9e,9e57f3fc,c358a2b,68f11d61,89fbd900,d1043b3,5f809513,ae370588,4adf90c1,9d164c3a,8166027,92ca55df,74c71466) +,S(96274665,253f4479,753de9ff,ac94af8c,943b8231,b1302040,bee72240,2ccc445e,8ef6f9fc,f1e21c2b,d913f877,98c6ac9,f53445f3,6c2b1678,a301a4f5,17867296) +,S(bc6ea584,b1f9b006,5f39226b,e31a866f,7f90229e,12aade70,136dc747,b37f70c3,23f1c4eb,99dfbcbf,66539762,4d20c4dd,4414bf15,172cde8a,b7652ad6,f87ad5e0) +,S(3e968741,5adc1afa,696e3222,fe351939,1d3f19b6,feb1de83,f4f1aec4,d25e2387,e3f4de27,67ea84c7,8baf1382,4b7917dd,477bdc87,cf1cf38f,8f5da1,e096b528) +,S(b5973535,c9c9d4bc,2b2a9b38,57cdfdf6,4995d64b,81c9e68b,abe4d4eb,4eee489,907cff05,5eded925,770280de,9ee0e025,1629796e,8ca05a47,48ddaf98,72bfdc3e) +,S(d616bde5,acd5f345,d23e8b2c,3d95038a,a1d7a354,a7613cac,57ec3e8,d07e11e,6c88c62d,d795d065,c6c86478,cacc56d3,2282b4f8,f3059aaa,55388555,449879df) +,S(540345c6,5869d3cb,cf4099c3,ba7422e0,feb87ab6,ad67429c,2dc99840,e6bc82b5,9f424998,bceafc7a,a58e5f16,c58e53d0,c0d51f64,285b0afe,e84ec9f6,b22f8f37) +,S(6b7893d0,ace6ab5f,c93f2e80,65a3de57,4d552e5d,4a89d660,714113c5,a256fb84,81a016a3,7be94a2a,f45b1bfb,968006a3,58398fab,424811f7,6765fe75,d4438d5d) +,S(357ea5e1,7a0795ca,cac47e4b,9e59bb24,45d1b6cb,2c713f04,7029f6de,2be57734,571de7e0,27dd05af,90bebc29,bd7345f5,77babdd2,75498bb6,d43a668a,8a4d6206) +,S(7baa2739,1db2a0c8,679d0e18,8c5e7c8f,ef1814ad,b7bb3955,519b4189,1a63ec40,73b56168,20fddbb5,749e8dfe,ef834f74,e266df86,e34510cc,f5eebb52,a868075d) +,S(4d5251b2,dd778e04,5143169f,8cab93b,9a9b7428,1a0ea1ff,964225a8,10b1e578,9376395f,2091036,16a95686,4e55382b,39b6934,2b2964d8,34face11,a44f491b) +,S(3c0fb553,b0c6330a,3cc06bb3,b0cb4c2b,31be7582,55264b29,98bbc166,ff57f7ca,f1f409bb,cc227824,4dc08c3,147e0b83,3522da9,6859400f,8d19272,e33ef1d9) +,S(6dcc7ba0,4b3b0827,e3bcb462,7b7db8d0,e0997c7f,900d27de,2d6c87d9,aab2c373,f2dcb11e,87b69faf,4400e9b3,186eeb6a,4fb48cad,6d6da276,3943772a,4e18b450) +,S(a5271e35,ca54c1b3,16d6113a,40414ed9,26bade46,c3258c6e,82a63e9d,927ce06a,e2d6051f,bf42dd9b,e0b2e00,1fa4e308,66232871,313f9c82,fd6ee37,6e8e376b) +,S(574d1ffd,976c616f,60371e4a,76b2712e,84b0a231,8d3c1c0d,3b56b10c,e978efe0,13733a17,a956efa5,733dc130,cc4c848c,19ecd6f8,7fae5ac,82c73de5,6d1bfa0) +,S(ccccd911,ea84c247,262a6e61,8028b2c1,a147f55f,b637b570,97400472,fe3e27ce,cc4b4f5e,491f32aa,eb6d0404,5965a97a,e4119e73,33bd1b39,f2ea9873,7d8f33ef) +,S(df1e4fa5,410f1438,9a41ca26,31eef376,4f10868a,f2f05a1,50e2c7f,8c3a2643,8185a88e,2b4a343d,bbc10da,723d4cb8,29014cd6,3211a82a,63627b01,1b01e87e) +,S(2ca6b7e,b53516c7,2e216263,213c0d60,fbb02f,dd227f6e,4ad29069,f6da9213,81d5fd1f,5264af85,53a8227b,7500d82b,84ca1fb5,87ea30bd,ab30fae3,67e3d7b3) +,S(df4bd790,ac3a0db,1663a8fd,aec1cdb5,b30c7a67,99ac2ed0,16f1c474,5bea92a1,db80f378,f33f920a,d0f4fad9,595b0655,44ffc36c,ebc3f294,3db13b83,cf609bbe) +,S(792648ad,8c053cb2,102dde19,789d3782,79e0e0ca,c500f40,d46bce68,97af2839,3c2d9b55,afa4ba1e,1ce3d142,5e17ca6f,191b4013,7b7d8162,8de35e8,801f72f4) +,S(dc6fe845,50fc1136,1f648fab,deb9b3f8,e7fee837,ea545228,b2fbd432,e53a8aab,2a4bf746,19fc5408,b4bc6421,f4a570aa,172ef263,c890c853,d7b06aa0,65960dff) +,S(10d4786e,9151f2de,89f368f8,9502b7fa,74b7b9e5,7a1485ab,f82fccb4,9c2deca8,15da7f51,bc84f421,2ce948cc,28663e57,8b4b851a,f6533f2a,b548adc8,147d2243) +,S(67c7c0ae,e82dfd5a,194dc416,41388947,29ddce96,5b7d50f3,ca922512,6e730bf7,a8bf40e5,666ba93f,1f723414,24d8a7a1,6a2aed83,7f022fdf,557e6082,e3e515fe) +,S(602c3df0,8a2efee8,329f391c,a9f7b2f8,31ab6d32,bc4623c8,92272934,1f78a4f0,ac17903b,3808ee52,c0208342,696f5250,5789206d,515421ee,8b1ab28f,5b788eb6) +,S(c3441893,e78910c8,3cf917fa,44b608b6,671ea508,37a7d2e0,4e658c6e,2a91d9ef,b5388381,17c264a4,a0876c3b,7c261bea,229c2d0,a7399c05,114f520b,a7185dcd) +,S(49dc68b4,412dc3c6,c4b265c1,6cde755d,bcd49f0f,394d552b,76f67ff5,33c7fddf,f1490a38,cdbb6c88,d270eead,7de6358,132cff29,ddb6aea0,1baf6353,4c0cdae9) +,S(89080197,4a95beff,da864c28,36997c7d,3a4c0fc0,4ad59eb1,5ba4b124,702d0f04,86e165a3,b2e7eb55,9a7996ad,63265609,aa6e3385,30b51d22,4ae4f16c,d30be3c0) +,S(c9671a3d,f749d635,5684de03,1764cf19,1087bd06,965d23bc,4ea0555d,29ee0804,33cc0d4b,b02a1910,c158db0,ad2bcd66,c9585f9b,456321d7,61752148,e6224d85) +,S(f3c1a76e,1d4ce622,dc667a4f,dc0f4ede,7eb7111a,1539ce5a,bca71d2,fd48a26c,269ebdcc,e1d42428,4e0dd49a,73968676,58857998,7a062320,6251ccd0,ac9f9e2) +,S(12002fa6,68924900,8a540429,50ba2901,5870a70f,7fe95ae3,dba4b07f,aa6fa460,51543d34,34568008,74e8b1f6,6ec72fd8,e2936b6a,6022401c,d13d50bf,931996ca) +,S(a59df11d,d3fcf1d3,264028b3,6e26dcf5,62083e44,f91f3d27,f23acdcd,f1392a9a,4dbda718,48afff3f,faffaab0,5c5376e5,5fd15ced,68b03ac4,4785ab2,201cbe70) +,S(89f738a9,802d7deb,5cf2895f,60916fa3,d6d74bf9,e740d2f3,13ba393a,b40cacaf,293aa5b5,b03557a,e7288066,5ade09cd,ae6abc71,8e7d445b,cbf85a44,a035b73e) +,S(d0414978,6252c5fb,b4bfdae7,56092769,dfcdc2f2,ae38a5fd,92ba9df7,f91a9ee,53ffb526,a24df2b3,d6e8faf5,ee6d79dd,7f427d8c,14d2d5b5,880f1863,e7e95099) +,S(4a638f24,ef3528c7,a4e42cdf,3f5bb946,81e6435,ba2c99d3,625dc282,b941d341,39d97ef2,949f1338,bc016ec7,89585780,832043ff,33777357,9ecefac0,ae40620b) +,S(70a25f6,34d32af1,47c4dd06,5d52f78c,eb5e53fd,64bb151e,18e8629d,f4f8088,1b6bf3d8,15a0f919,68dfd6a7,7ab7417,d4aed9c0,a52b93b9,9b4e4e41,d1e558ce) +,S(59ea9490,24765add,f99fd908,11c65ac1,d0f9ee8f,27e459b9,b5851765,8e96ab82,b38bc716,896e0337,e4a1b361,59e2b5b4,e1680ef5,beb4b47e,c5934b4c,8d6675b3) +,S(874a6ecc,6260617f,c6d4f334,40c8e080,3d993594,ccc2d47f,be2869af,9881f2aa,f509e39,6663327f,7d768a67,aa0d2ef8,353b613c,bb60fc38,bd2715cf,349c02e) +,S(dbf3567a,1e634ab1,63a860ce,244f3046,c7f486f1,b12928d3,1c44624a,48bb5df0,bcdfcc85,38e4702f,99f9d55,eaa55216,730405a5,66fbdf07,4c62b310,6baf7ce3) +,S(a534bcb1,96450965,5593155d,2da069a8,4800e4e,eca0b504,62d844eb,d179ac50,f86b38e2,d558be4a,b0a216a2,906099dd,f3cc16b7,30e784e8,745f39cd,829ff3de) +,S(e11bb840,b79063c,4e090771,29d2bce7,8f291f10,120b57ad,63594780,fd1f1905,7fcac0ad,e0cdc573,67c9d74,1c6c9928,15b7c3fd,3a19b266,e0e5a94a,9a9ef9cd) +,S(d79bf0b6,552c5b6e,6e9192b9,765e687f,ea226d86,c6f83f44,b427ea9f,14b404f8,54e7a54d,583e2cac,129f17d6,835597aa,934b4732,6ffecbfe,deb503a9,eb9660ad) +,S(103396a6,57856b61,5507969d,958de14c,251bbbd4,9851a5e9,ea64e0ae,2f87817a,9d66ba9f,cf3e0c2a,655cabd3,91774015,e209d771,334c461e,d27b683f,f83b477b) +,S(9b49e25d,ae607f4f,fd876837,5ffc0fb7,142f9cb1,f0fde836,537f320a,9636723a,3472462f,f9fa5ab3,1fd1279e,7953dbc9,85623021,e714c951,bf00f632,e9f72ab9) +,S(a017d4f8,8e757556,b7ee81b9,d4c9b260,ba2f7f8e,5e1b69a5,fff94abf,723cc438,5f2819cf,53fcc35f,c9c15d2f,13dd51e5,2c8dd134,f012aed3,4b4383f4,8b00cd95) +,S(aff1db2d,3fa6dc00,51a8723a,7127d57f,69ed0b49,ccbca35e,25f72bd,19076211,7cccb7c9,4adc2075,9c7f8870,fbeb1a1e,9f95d644,af0411be,a6b12d3,aa6f00d7) +,S(21ccbdab,f6902a86,d368d445,dfba0f31,4f80de6c,c7f05f7e,9fd1818d,45a174de,eda0b8b8,7f40e9f1,bdd5ded,e65bd72b,6cbe049c,bb1575c9,6b779818,a67251d4) +,S(c3e58ebe,36b0e5b7,2e15c47e,cca6848f,5312369d,d270dd18,93b589b0,56ff7082,212df92d,d724e3aa,c42e293e,b1a2de5,3c340712,7ebba791,b901ff87,9fce94b0) +,S(f19961ea,da1d77df,2fb9d976,7d7c664e,c0400066,2ecd7244,12b72dc3,c5de133,74f321a9,1287943a,8ed14d02,96b05ada,1a24fb52,a09d467e,8e8175ef,8f04a2c9) +,S(3aecbe48,2aaf6af,35e63dda,fc919adc,f974e89e,765c4437,69ef535e,cdc05e01,92b854b9,30e5e4a8,85397592,fde89d3a,601c733f,d88d230a,a1168e36,ee367273) +,S(55fdd639,b87de7c3,9acb95ed,33222935,bd4217c0,fee1c924,f1060f54,fd22055d,81f4ef46,16e51585,cb443bce,f16ad8e2,36d6ed18,87ddfa60,ddba2089,f4b83c4d) +,S(b86a6272,ceed47d2,4ef4cc67,bef0b117,c0761b4c,29548c8a,367d8ae7,bf90744,1c0de18c,d5f3331c,5439020c,5964404,be582f88,3feec4c3,112396ce,b657c4fb) +,S(d141a7ae,9d92913a,26deec5d,d2acb7a2,115da997,63be5a76,c5a0a415,8b5b8170,de784bc0,9308c82b,ce3be9c8,9abe41a,4ed9b9dd,cf817aab,3785e344,dfdc2ecb) +,S(af340559,6902ad5b,e3fe3464,3cbcea5e,7a478a32,b1bde828,ec966837,192344e4,3f65050d,13e7b969,35b013c4,9df385d9,833d419f,aac0f754,5c395ca3,75ae8965) +,S(b70dce7f,870d3d12,472d3c5,481a1288,cccfdb2d,12637a9d,973f4e12,b026cefd,4b4f733d,e5322132,80a36e4,ba57894d,a563f4ac,b1a55a9c,83c8dbc8,96a7fdf5) +,S(14fa3dee,44dafb00,d2e71c91,5d217cd7,a9c2b50a,edcd0025,f7aad2d5,b6c62ce4,67c3a65a,65bd4292,d271fe13,9a8c9d84,343bdf68,cc16e50,11676580,6bc30d8f) +,S(baaa6a53,26a7fc36,e519d9a2,48dd3aca,f6f0628d,a6406021,caf0d0c,56d9bb3d,4fe9c638,c1078c39,a0fc39cb,e9a81bc3,4b15840b,631ecbd3,8ca4a2bc,10d1f3a) +,S(ffe2afcb,5e53bc7c,9ee07740,c8094a3a,32c8e627,4dec7eb8,cf2673a2,dba11725,68d7092e,2b8b56da,1653dfd6,42de49c1,799d3ad5,864e052c,8829815d,b2ad952a) +,S(a25d7c5e,83a0659c,5ead610e,b581d325,adfdd3b8,af03736e,4039ee1f,40612431,679ecfcb,b1da355f,d73d02e8,b79fc949,bdc9fb5b,5a4e28c,5e68c244,7599c806) +,S(1c5d082b,3121c4b0,2e0e2244,88e53b8d,ac5500b,bd396f0,7fc218dc,7311b299,a2a435af,4838d028,4d459216,f3955427,59f1f51e,9a15f28e,d83987dd,9c09e5b1) +,S(d8d21200,2cf2ceae,6c9a90db,89f7d0e0,42a2e97c,458b9024,437e28ed,a775ca26,b31b6a02,4b01de6b,6159ee51,3c118921,f61a536d,c1442525,cc613290,364b9df2) +,S(b5265664,54579771,947bee20,f8e7bc48,1e15d07,2adcecbc,3aae7b91,a4d0f3b3,170ad05a,da7f67ee,f7c611ba,3c55c835,f054bcf2,445e5c1a,399c7cd7,640ba8be) +,S(1d0d2a24,8982635,18a28203,b78cb089,acd5c296,98b86b7b,48fd4db6,3c80812b,71e2e1a2,7bff3bf,9e85e145,7f446048,7643f154,1cbe829e,f600d861,dbb752e0) +,S(cbbd4ee6,33aec586,ec7ba712,c3bbffaf,a0e6497b,8618a476,b64c660b,340046da,d792753f,c73090ac,177ec5e3,40aada73,3b31dcf3,a1f46952,625dab85,7e9b9795) +,S(73cfd295,99b6b80f,8757a873,ce9166ea,b1960f77,fa8f1d55,ddcdc90,9420a751,17832aab,c1083af5,683f8cf7,23c6376c,c22d190,241e1e37,6b1ef2dd,7333c873) +,S(20572bf8,abe50ea,37a064f,738dd18f,531b9404,e7e4d693,2c9fc34f,ef6dede3,41c79375,11c8911f,3146bb2f,63750887,c663d2d6,f3fbbd53,30af73c6,9d332191) +,S(ac208805,2f1518d0,3724ef5d,cb149f36,1ed713a2,94392f92,96173857,94794f70,1820bb1a,e843255,9025f3ac,977d9f59,4e812cd7,e27c390b,b2fe905,ae2b7017) +,S(33467f95,60aae872,b5c9afba,7f29cd32,a213f197,47745d8d,945d06e8,295afacc,44040bd8,138d9bb2,76181e21,79f4bf98,4b0c3965,a1a47d34,be8f47ff,52e15af2) +,S(1a77910,75bd3497,cbaff6a5,d5e8bd6f,439f5bb7,ca3eeb98,68033ef1,cff83f03,d8af802b,daeebe88,f823c43d,447f1906,63ede3d4,c4b9dbd5,caf82a3d,b4f1cecd) +,S(dfacafe8,cc15f85c,f829d913,9a9aedc8,6a98e010,5308572f,94c183b5,533f5bb2,c076b6d,c708d2c9,895e22f3,2fe42f4,33ad38c2,a0c55aaa,5c551fac,fe601916) +,S(3cd975ea,9eb5fc56,14955bb2,db0ca413,b83116e3,a09454dc,7fe973c5,7ee33ca9,261e5544,2fd503f7,7c1c7a49,de96fb50,aeac56d,30cf3ae4,8b2e1cb,1b9fcb6a) +,S(168ac250,d23cbce6,23eeda,1389e261,c56bc718,4234bebe,6b108bf9,bf6df45d,add3ffb7,b0a9a860,21ca51e2,f3d2e2d,19206bad,78d9e661,2895068a,c880fcb2) +,S(47bae439,31966a6,984241b2,2afc8b86,94db88c2,abdb1737,728e1af0,e3803968,a7cb7d64,a07cd13d,2c8dc7a7,8a7a144f,8edf915,5cec20af,102260b2,d8d355a4) +,S(76e73a26,730b1444,8ecf60e1,3489de8b,93355af6,8943669f,20da17f1,4f04d517,41f75520,3d5d528b,2e81bab1,9ce8031b,bf9c73ce,7927645d,178ad762,669b99fb) +,S(f6f08712,d85f9219,bb475122,1ada6a75,1a8d4758,f5dd72f,f5231d56,e634c19f,d72cfc42,379ee25,eb0fb134,338109a3,7752fdd8,1ad102b5,f365a276,1d133f10) +,S(1acac95c,9b0ed53b,e6c37d03,7d47a796,2a371caf,cede380e,799d0110,b0634f7f,658c6b74,44846952,93a5215c,63695a5b,fc80f818,633e0278,f6a1193c,6d441bc1) +,S(5759a8bd,ab76d449,13258631,68773369,5b76d2da,7b1e4004,1bf99198,bb25f218,15c1dc97,8ecff6f7,cfd6cbb5,44ab8666,83127b41,951c247a,f44855,4afde3cd) +,S(cae1e14e,c28ddbfa,379a97d0,5f3ae379,3771750f,5a9ec743,2039f440,8fa7e2f5,eef09268,6b9f60da,8e64ae64,8f13d01,8f7b9ef6,aa849f9f,72df2f9d,f80fbf60) +,S(9aaa132b,947da7e4,9c1de2ea,ce06e3f9,ccdc37d7,6d2081a,be5f3a37,9b0756a0,e9bee628,d6a64476,af601737,68829c11,e8646e8c,beba7174,806d800f,56f6676) +,S(f38b62b2,4d609d01,70cbe85a,cedde44b,7a766a30,d8b7db6,8d935735,c4d0d204,8b61a5f7,e3caa2f9,17ef9ce2,c5eb2499,667558f,7c4e4e84,2644dfdf,a57666c6) +,S(25c121fc,74c57f34,29a143,8ff3c47a,f06b5de,74c4dcef,4a093b87,3a2ab659,69254121,eadbd76f,289cbf3c,21cc96fc,436ea33,9ccbc8e6,fed92b2d,331246da) +,S(95666156,c40929aa,8a7ca656,c42c64d0,e24c3789,ad3781f7,9e2a0ea,c7ab9c1f,116f5750,7e07b846,92106d6b,6976741a,59bf7cf7,909733e8,e1fb54f3,fd77e783) +,S(cdf1c010,7c48b65b,c001df94,c6e84d12,d8885af5,820d65a5,4e7ffea1,ef4c0081,8f3d1be4,206bd313,e1c498e1,5e7a9995,64312ea5,aa823196,9c566349,9c3a04b8) +,S(955269f2,be0d5e20,5382b2c1,959103fd,fa2c2386,9bbdd33e,a09487fc,294dd1ee,6306a092,4ce63798,41b2d773,8cf97ca5,e259f81a,a67b1e0d,42903f1,beaa869e) +,S(78013976,449ddc23,4d32a793,5ea525d5,9afa3617,47e0a8f9,c8141d9c,2b231e14,8d28142c,bb88abfa,1a72d583,4e509d69,3cdee0d3,bdff4788,83618ce7,a1ace69a) +,S(e6d67a8d,fe513147,2c0fe227,bb08a8f2,25e2606e,23672969,ad3acd65,155f972e,46c8695a,5b9d931b,adb568c9,d3f9a8a9,dd501508,fed00c99,5159f518,bed035ae) +,S(1779ea78,eed6d974,563cac2b,b3e72693,409b7029,789e0188,d061a182,3f18e962,82590ffa,6b9e0e13,d2e72bef,96d555df,9f7d2b81,2423a947,e0dae41f,91cc0722) +,S(28ec208a,6e929f8e,a815fc17,7b927086,7d482547,53ba5c3d,3b56fa91,acbb67d8,b4453dd2,eb964348,94cc1cfa,25616a2e,2f0803e2,8796206c,dd31ccd2,dc69aff6) +,S(c218c6d8,3124c9d1,c988981f,d4614af7,ff85a572,dd89e4ef,6209e80f,e7656de6,7259c421,45ef6e9b,d4f451e6,e2dd226c,2e750650,8ff7834a,965cca4b,cdbfede8) +,S(4c9891e7,5559d993,536fec73,a433006f,4f0e4e42,f427300f,7a3825df,85b1cd9a,7463ce1b,9f9af66d,7a5d2d43,ab0f09ed,186eb132,92c75431,ccee645,4280aa2a) +,S(a89fcff0,694ed82d,537399eb,b59a054f,f43eb74,f8e1fc95,be0c03c5,9889c931,3ef3c627,e3011b2f,38d596d0,8ded759f,fe30ffc,9db95356,4e01c8a0,2949ea1e) +,S(a8b3ef89,561da88d,ca9890d,5e4be652,8a4b8fe1,691d1522,54bcca43,1e7ed801,c86fc397,52254f61,88ee5128,4bd54347,8abe7390,c784b51b,6d41c947,5d58bada) +,S(6a2fd5db,da9093c,2f7c7ed8,9eeeec7e,efd7e759,eacc2946,5d1f3a15,baef5b42,8b71ac63,3886ef25,74e212a0,499c34e2,d2c7c1ee,b70fe7f4,38e08914,48395e4a) +,S(d33dada5,30626dc9,1d23d16a,620dbeb4,7551ca44,dd6c8b18,fbf136b3,1ae4e097,4161f6a7,8273ead4,443c93f8,2562a29,1dea1adc,d84ba0d3,75a997d0,f07d4ed0) +,S(53ef9ef5,731d9473,93e70829,bcac3396,3b7a597a,1f3c861d,401af7f7,fb1559d0,8654f8c3,63e53905,a4d1e2c4,378fc3b5,fd5ffe3d,e7fd3adb,399d883b,3d1b9e18) +,S(5f13c5af,6979832,da1bd43c,4b7df970,1ad837cd,e59d8f15,381858d6,6263b0a1,3b0ec16a,1024c902,666dca02,4649c110,2a17205b,e4ac20df,26ce5b92,8baf90c1) +,S(674b7de7,f65337a8,c66dbf23,2f86d6a4,feedabbb,b71e83dc,fd854926,86f14f86,e3961790,a662c6b3,70460e16,18ce3b6f,42bb6142,78fe9e2e,6bb1179,181c2aae) +,S(291eed8b,47c3e2f6,b3c2967f,76743708,5c460c5d,d5d6a75c,489dcf0b,4d98b8eb,e19a9d2a,72fa37e1,e10ec853,9c772565,c53e36e9,160651d,c2a8e364,db408ef8) +,S(e737a407,1bf4fbe4,ee5d3d74,7df3cb54,cca38f48,f977919,907deccc,7090ee3a,ac66d422,79441d73,2809d695,68f700a0,3fc5be05,8241da39,9be3a63f,8da16069) +,S(67fb1676,7c3231f3,428b39e7,bdd082d7,1194a51,ae99a7a3,6c113e87,d338712f,38c2ae1f,afb521f2,279aae5b,6ba5c636,1dd34c04,a7726555,acb9265d,31c996f8) +,S(9b3b4788,71bc413c,5e9d2b9c,61e0cda7,f2fb908b,805f3370,45639,5e616230,7028b68e,af818a13,d32f116a,aeb0bf45,215d3d62,6e6ccb1e,a901544,ef1d696e) +,S(63193415,59bb1e39,2f92dad6,e5f8576f,7f49d4d1,439f4f61,a6f2be0a,75bd99e6,259d5f21,6c780a8a,5bba3e66,2242f26f,1adef829,a535dd97,11f8e786,f0a57932) +,S(4163082b,7720a8eb,e881b398,dae059ff,3a65fba7,f8b93afb,6e3dae6,6a969c79,3939395,d8e90807,e77e87a7,4c89f861,c689de81,a37caf6c,32788310,7b938ffc) +,S(b3a6baad,15c01677,ad6bed54,ea5ee415,4d0bcb7e,3ce59f17,7ff26,ef23b82b,711681f2,1e56c0c5,f2c2b011,dcf75716,300e305c,110f4071,51d11890,25bc4760) +,S(9011d111,fcebd882,b9a228da,fdee1297,824c4007,7d5ad9bd,59e603b,43be8f52,d530102e,aac87930,eff135f2,e55b5310,7c03ea00,d24f1201,6653e3e5,5d778246) +,S(d50adaf1,d68a746,e1e7b148,7660e90c,f268450b,df460d52,e1f761ab,bf7018df,4ed454c4,5eb30cd6,e6f1c4d8,7df2bea,e15ebc07,e4b4e50a,e4dea733,93abcf8c) +,S(cf886295,d1eca9f3,4c95acfa,b86a5061,82e30324,ba5b495c,70318cf7,9e910d70,59bb7068,3147c26e,45c76e7b,e018e467,1f47f488,2c044484,62a5053,8023fd40) +,S(38723d58,ffc69ea0,9a8f2655,dc225da3,78b9224a,f8d81e7a,bf8f29ee,292ddd24,c41d67bb,e699e504,3198adb8,ff11a5e0,4033b66,98d3ec18,256bab11,93db5535) +,S(5b41d5f8,1e2443db,d13521e6,e7b7fdf2,4a226cce,f369279,22b353ef,107f759d,8ad730a5,bfb9f01f,853434b,24866a49,912fc756,e086e781,a07ff2e7,98ef38d3) +,S(4f3c24c7,7dc7e41,843e9018,400d3bc7,5d1dc958,2895c11d,3855b80f,4709373d,a485adae,c547a5a4,e0695913,c4c2fb5d,ea16a3c,5211c162,4819d704,5b0d8d6b) +,S(f603e0c2,8b40c8b0,a6a0378b,c4289059,5a4cf4c9,2b74199a,4e4e231f,a6b458a6,a73aa12d,76572041,f01c33ea,ca599a30,9ba0b838,f1d67fd,67a9a5d5,c3ffe258) +,S(84ef0a98,229c7af,9404cc25,60f4fe1b,4c8e66d9,1aa96118,53fc4f25,eac78a61,653df937,3640b28b,2c2c4061,1d79c4c4,a2d577af,b572f5f9,e50cf3fd,2b2dbcd5) +,S(e675d998,6b3bcd4a,d098ec95,c386be9b,4e96e448,ce6c9371,15c5dedf,d97941b6,4319799e,c4103d65,18590091,e333cd58,9901b020,a62565b7,f84219bf,e31003fb) +,S(10837b33,3603f33b,e528f391,b5b672c8,93fbd813,99c5dfea,f6126e6c,2a2633bd,cdee9534,2456a261,8a293b49,d91ed2ae,f620addb,ed83fc66,d169da3a,a6d0e2f6) +,S(4cb1ddb6,6ad3c1b,68c6b0ea,408ba1d7,dafdbe54,89c22d47,7a62dcc7,77a8e013,6c005484,29e789f7,5c34d8cd,a473270d,75eb8f1c,3db13856,87cda96e,5cd4b370) +,S(db72d671,ff3e0102,b1c52481,b66ea142,8f7fcd43,15e2792,eae234a9,291926e6,71c55f71,68a088f9,980bdb6b,79b052d7,4edd0b19,7ab7359d,9a2f9ce9,f1c5a5d9) +,S(99f92125,162e18ce,7493e6e3,91cd06fd,681371b3,2e147ab0,24ae3799,15f586d3,9286b3de,12ee578a,12ded341,75bdb712,d939b7e5,555e86c1,82f1f283,3c1b1d40) +,S(a2b8b63c,8984a666,2b09c18d,b2d7f263,796660f4,3bd78eaf,af7c63b,986c92d9,2003787b,2af02879,642b0a2c,f716f4d5,85dac86f,e58c7d41,d1959763,310a67e1) +,S(9292ef40,21bbe6dd,8c26a862,c9b7da54,4292e479,a9e89264,618e3a47,9773b446,d1a51e4,65bdfdd0,dbf74fd3,d449f6bb,ea862eed,ad369c52,34a695f1,d229ead2) +,S(8d5a920,547d838f,90159068,ceeab220,cc6aa126,d423edd0,2e136cc0,1cea5d4,c3334a69,f7694e9,43ccb182,2caf2abf,f4caa83b,a006af52,bc010bab,8710b596) +,S(7b62f4a7,7b79c09,76dd2f74,4ec08d9d,21511fa0,7891ff5c,52b8dfa4,ae3430bc,70ab2073,cb3a7cea,350e6aed,dd0c9a6c,ff8e02eb,69bd14a8,a09e9b8e,ccb19a0a) +,S(e18a9c02,5829b47,cdd34c11,f97f2edb,a7fb9b9d,fa4777a6,dbdc3cd6,85245b12,7386fa51,881fe49a,adbd5327,8d6cd0c5,1063dab0,aa830b7d,88c7a4d7,9998e743) +,S(ab9b68ad,61335dea,767c763e,3294d414,74a6d4ce,e4ab9a78,7fbb6749,7307d0f,aab48fbf,53f365ad,bf94f823,ea973a25,f6ddd341,397bd81f,8e825f60,c916852b) +,S(3412531e,8423364d,8d8bac05,bb78973d,7b8d375a,9e52d81e,bed48027,2abdedeb,1b9f5eae,59ea3385,9de752f5,db973a86,4c735e69,fa8882ec,e1ca8350,77d77335) +,S(6a6425bb,af9f65d0,1a401330,46053b50,7ac8d45a,77b30de3,69eed52b,956799b0,7cbdae81,93368c60,5671ae9,faead4ca,2887bd8,9a06062b,dd6707fe,f849f484) +,S(87860648,af9ffbad,50871c2f,29bce0b3,e9693835,8a067201,5c1156a6,7107a4cf,8660c0d8,f1aea58a,c613f6f3,5b27baf5,53835493,fbc0e203,f024ee36,27bbfa53) +,S(35733610,71c55057,5392c685,3cadd8a3,6618443,d80b3625,53a2f197,d3c52539,42935628,adab5bd4,e0aad0dd,a7d76627,58524b2f,34ded1cc,d3e44249,6d213630) +,S(82d21949,2fd48d51,65bea027,6ac15cf5,d27bd736,45e03271,24f0f689,8a2f4a25,f13d9063,fed02a94,1b4e5c67,f42d82b5,33f18ff9,ca4622f6,79c6aabc,ea454c21) +,S(ba1a1c83,6dabf825,e517ff65,549e1d5e,729944a1,d7b17cea,aa4466ac,39ec6eba,f01dd751,3557249,d2fb224b,40ea19e0,57b4052e,adc46787,af587ad1,458bb4f0) +,S(5cfeac36,6bbe58d8,45a36cd7,de6601c8,56943a07,522364b2,23a1718e,6df8de8a,6651d3d5,a344af69,25fe039,c9e29e77,95544b96,66752f4f,c9a3bb57,c5586c32) +,S(e5e314fa,2b2bb630,6fc235ba,cfd356ae,bbf88bf7,eb039629,165d8651,c0c7d5ff,c727787b,a63cddb8,feef96b0,2f6c8d0c,9722fb4c,6274e034,32d9016a,eb4d8cb6) +,S(f84d8db4,b745cfc0,bad4844c,b5a28d7c,80ed5fe,6baefda4,1d9cff9c,158c7ec1,cbd7bc36,a8313a27,feb8121f,a8847bd7,937fa53a,d56ea066,fa600411,d87dcad8) +,S(8806a2b9,d72156ee,4948e86d,43f4b3ac,cb24529,e1b2b2f3,5ff94812,e9534513,aff42464,773f6535,b4dc5eb7,76a3f7b0,7bc2fdce,1413587f,c4055cc5,afca3129) +,S(e2ddb5ef,a1105437,b6107305,bc715e55,ec0266aa,a0ba1bcb,e12ab801,45af7eb2,43e4d056,804f229d,da5a1efa,8f429189,6c9edf94,fba505f3,1f22b511,8b698ba9) +,S(636f32ff,ea843368,c0cb708f,43841ef3,20151e39,35683ebd,bb1f476e,af2f8c5d,7fd53321,517616c,c7d24b51,851bede6,b03c50d9,82269773,dd51e36e,4898365d) +,S(bbcdd1f,f5b47391,d728a06d,b4783d5,b0e279cc,107488de,44446e36,9d11d143,6ac7dfc6,47d25b37,7281abf9,ead782a,b5f815d7,b2c9f6a8,46a8a6eb,9253014e) +,S(af0ed949,22336a4,337e9c01,53357e02,3d7a2728,3c649712,3e117944,39ed3577,d8b9c03,958dfa89,ec2105b1,d9542d68,568797e3,7df16cc3,861627f,298f3359) +,S(11ba75ae,db365552,b0d3f938,f03a115a,544a0818,b2f54f50,e4873249,6f80ce13,a6bce69c,f9838317,70f70370,7073e87c,61b65c0d,bfd34dea,f0c549f9,c58e674f) +,S(e7560fb5,79e5ca35,f45881db,b05383f4,c5536ea8,a5438fc4,ec198ba8,7543d3ad,ff48d1a0,bcf5e510,9ed50a0d,ed8e5b83,44da25e1,a1a3d421,606d19f7,e28fe79d) +,S(ce7e289c,61f4927b,bf933eb5,193fd2a3,a0686435,80c8f235,1e24c33c,e418cf10,17246f2e,e87f4ce,f1c8596a,ecdb1f95,1407ee7f,dd839c9,98102344,2f4dcbcf) +,S(b765b875,32ba4db1,211c612f,b833ba18,156fa0dd,875aa61,df1ba9b4,7d1c405d,862d28f6,d85a8ad3,bebfbc82,437404f5,2e0abafc,64369b51,b75364cd,c827171) +,S(400560bf,d2863ea,2bd9e246,4eafab2c,2798cb95,b976c022,bb9d2153,e5978a0,92ca9a1d,938e53d5,d10f1f83,54abe43c,e8f8c2c9,d4e851cc,a363ed59,71e2681) +,S(7859190b,8e619c98,76af21e9,64f323e5,221cd4c8,83dd9fdd,e56f691e,e3db91a2,e1874376,755165c3,72abd73e,415f2663,bd94cf28,2009492a,e5034da8,6f6bf949) +,S(87d90b40,bb472b84,f9d24caf,ba7a6437,b50febd9,5c643aaf,e235750b,12527ef6,e6a0f719,25697425,23517ea6,183faa64,dee1ef63,183ab1e8,3a603b98,20452c4e) +,S(dbae1ee5,a1b6affd,f9b41ff6,a1f2790b,2c492ce7,53865690,ce5281e,a7f08177,f6a2be90,a2c3cf,8e14bf87,4cc52648,b60f9a26,2930f6e8,9fadad4f,d919db6a) +,S(943a79cd,88260475,10d90c99,4d8d784b,32c03d1f,f2478102,96125f7b,28576216,48d4477b,f97c4cbb,4a96ff99,e427d4ac,cda9a367,2ae66930,88d8cc57,3bb3e2d7) +,S(699911a3,81ff3c7e,71b3a458,14133f3c,ec644378,e3244d66,6d083c55,7b6c040d,3eec684,3190d6f3,85b07116,b3b1ba15,4ecacec0,63e02933,9b83afad,5598b22a) +,S(f002302d,9ca256e5,cc38ad82,e529b461,efb69f28,52513917,fb8d63df,45e602ba,78455ea9,708b750a,97dc74ec,8939c880,d76010d6,78e0c112,3616483b,fb4e788f) +,S(5f701ce9,65a20314,a65e2c0e,1cedded9,ddfc9d01,41a1e095,e91b9915,cd2aacb1,57e770f2,d04e33ff,c9d7807a,4c3d1edb,3f9ed2,c19771d6,7e85e618,463e5663) +,S(454c122a,ff85c42e,49d6f033,87744462,8acfed31,90c41255,e8e34928,83563fcb,9d9d6435,a2c4d146,d92f34cc,40b32a7e,55584885,82143a,52039fd7,129fa6f6) +,S(d9abd19e,81f392d8,8382918d,6ab3f89d,de793abe,2eba3aa7,b58b0ca3,1e614e51,8c1a0f80,8b8d9e56,aed21554,95f8902e,a390505e,15cafbc4,2b71cf05,575abeec) +,S(20779414,b5ed6524,b3613a8c,d0b6e9c7,ff3b14b7,7264cb8d,7b266ef6,cbb224b7,c1437dd7,71f46cc4,3cfa52a1,28c70367,d6682553,28942150,c4068da4,8c218d66) +,S(141739f8,503f2225,feb40431,21f0a5ee,844a7707,62e37d1b,3e43fad0,81c631b5,a0a13de0,10566ee3,1af8c6e6,38411c1c,a3df6c63,c8ed67da,8ef7bd19,5fd6e73f) +,S(de8d06ae,dd58b148,91184145,fcd9bc64,634725fa,e4a77d35,70b21c8b,77890b60,a046f351,eccab99,1d3d1c1c,642387fb,fb9c3f92,75bbb93,46688555,f7aa9460) +,S(312c7ad1,53f7280a,9bb86cab,ac573944,d271bcfe,bd59291,c6f05fe4,ec003a81,3c6428db,5eea01c6,9fa2556b,1f20c1e7,4e65629b,e73e6429,81b971ad,b6563866) +,S(2eafa04b,d276e33,75b8d063,b206785c,ed69f763,7a5a8b99,ef7d3de,bbcaf35,f06464db,56ccf55a,1f41efe4,d1cedf81,a642da24,3cbe68eb,6ddf7ace,f67dac6d) +,S(5873091e,dcc8a95c,a0a47570,3d88e54e,1381c2d7,a418f615,eea97470,2c2c6fbb,5a91598,b8e47d2b,2fee6cdd,c33aa309,9bec74dd,21688542,9b76543a,c233ccdd) +,S(e713bd84,ca505ad3,aa022577,c0cac85b,466874a5,b02f4ab9,e8d14bba,c131fcb,706dab4a,fe49e6cf,d290913d,358d1dcf,62e8b4d5,b9bd46a,322ee4a6,5a660849) +,S(aacaa633,6fe86d41,b05feec1,cf4866d,340fd268,f869f912,c2373e10,bcd95340,d933cc5e,c01024e4,77d1e80e,c533f293,e4fd0dcf,7d1156b8,7ebd9d81,b9489c57) +,S(cbe0ce9c,77649031,25590e03,cd9643b5,dc45ecc,604d51fa,d5bcb8a,196b65ee,d2287fed,c331d56f,e585bf1b,793fd957,ce425492,df41d8b3,4faf84de,c3bf4d22) +,S(f9990413,deca9f9a,4ea6bb8,fd9b8732,57d15ec3,70e98187,f4170103,dd416dfd,b0593cb5,dbce573c,f0a75f2b,c4756781,963e1a2,e988e0cb,23efbe26,c215ace7) +,S(2ee21d79,bf3e82a6,2bcaef34,85276c5,3b51bfd8,becbc9f9,6ad316f3,a74bab97,fe3cfa79,b208de80,f659cb81,bed12184,ea2c2524,dc0bea05,64acefab,1acd8fb1) +,S(af5c91d3,44fccd3e,70345a2b,ccefc0d2,19287be5,aca40ebe,e61de522,56f25faf,bb58da83,bebb5346,9b345695,fc23853c,bc0221b8,5d75ced1,da107fc5,c106875c) +,S(2cf50e13,477d628d,117e0bb6,1d3ff9e6,1108fe94,bf82a6f2,4138a743,6077e0af,339c0a53,77a6465b,29377e1b,dc344464,875687e2,7d1f392d,96a275a,e259793) +,S(c51a6610,1522f63b,84b98ec9,31984865,eb3b29ce,fe115b28,a87f89c,67bc441a,240b9717,6af4beb4,b0502d7b,2caf8c7f,47a9362a,9f9610c5,826762ea,a2a2be5a) +,S(27478eb7,b14d84b0,80426792,b0e2e510,8a4804e3,a15e80b9,c430d7df,c09d05ce,eaa0a072,86fac65f,3da47bfb,4010fed0,fe8a9e17,ae42ece9,233c2078,2b36422d) +,S(531ca72,e21caa6a,43f0c9bd,d0bbca5a,b12dfb9f,70f045b2,f0865077,cdde192b,c4ed88b1,a0397589,3cb14ed0,897d6bd,783dc647,ba59772,16c308eb,630367e8) +,S(295775cd,950d0702,602278a1,56c1d05e,4343474,a4b3ae87,63f4a686,7688e42a,907fa8f,1269cb64,41591004,f6e62b14,4d6c54b5,f6ed424d,6b0a8a75,26935b49) +,S(e88425d8,bf6e89a0,f9c9f525,97eedd4,3c331058,10936c23,4da69d21,9a86f82,56d53ae5,e7a354d0,d65cf742,d603da2b,199e147,3d42bf3d,639f83a1,cf91cb65) +,S(4d20a032,c44453f7,b374a82f,f088d816,c1fa9338,57dae8c7,b87295,98869a4e,a7ad5993,af43cd42,1620e87f,fa0b3305,e7da39ef,704319f,ae5faf55,5e3fb43c) +,S(b98e9728,e9288607,a7ed6df9,c68749e3,9d7efa1c,4f964428,5e9bf81e,246e936c,1620c470,19b9cef8,7c1f0612,cf56adfb,5526573c,f7746a98,48a0d40a,3a92d38b) +,S(562eb109,e9988778,bed85413,2fa7d086,6b37a8b,fa2d2d3,470da3c6,97996a48,29f4f0da,e554e380,613156e3,34207e6,fe8fa678,4c08f2be,c3d6a59d,1e0941b1) +,S(b189e864,8dc0ee06,b09ea73a,9a01cc06,b6fa74dc,f626e41c,ffad926b,901ae851,4e42c870,3d04838a,9f0682fb,bc13c849,a515d5f2,f248f393,e2caf0c9,b6d61d0c) +,S(3894cdb3,425c618e,1da2c6bd,1177109c,49362a4f,24030692,244bb0dc,27af6913,20c0021,5c72939a,497f08f0,bdb03493,8d04ddd4,8fe8f3f2,97dfef19,ec9397c5) +,S(394f74a9,9146fd43,9035266b,ccee72e9,36ff59cb,eab7bf4e,925c6363,fce7d4f0,c7da15cb,c1cdcea3,21efb1fd,c56bb3d1,2bda06b9,993b6f5b,2293e493,5aa3e5a) +,S(44fc66ca,d6e67f97,be95c667,fd5dfdfe,dc82edba,35df2bf4,737b3ba4,14d15c27,9c485757,351825c5,245c6eab,2ec4a51b,ac60c9db,fff7988d,8f28728e,60f418d) +,S(fa355672,d9f7a1c5,30b2d76,f183720f,e50840cc,ba413b64,e449d2a,8b0518dc,63fe1c7f,d97c7744,35613167,660926e3,b7377fd5,97dad03c,9debba5c,a5a76e3) +,S(7325c269,50f1bf21,2f9cff6a,170e446e,62dafc2c,f05dc50,4eb951d2,6322eefa,5f8fa04f,ac5232b6,cb553630,5a48b647,263a57d1,2c485363,6c930497,40965f00) +,S(7004b364,c89ac7ba,ad03a03c,c8e2972,e5fc52c,bc656165,e08df216,afa216c2,971a4284,80556797,ebea8b1c,b37de6a4,1aa11abb,df9b28b7,7f50d362,b6554974) +,S(ffd45087,eb9308fe,e7644817,9406d9b9,77364732,f3570ebe,80a4710d,a0ef292f,f4ae4df0,5af2ee0e,456cca0a,2c9d93a0,83eb9751,a09c2f8c,5bcefce7,83764ffc) +,S(ad899e8b,a7aedce9,e53d86ac,5ca15408,140c8f1d,be3ba4a4,275f332f,b0320572,a914795,bfd9850a,24251eda,98bced8f,2e2627a7,8a1bf6e2,8b66ffec,f11ea105) +,S(7078718d,e94255ff,ae25f1df,4ec2ad90,e59ada11,5ad4a6dc,8b305fcb,93a1114f,ee736453,927cd7ed,bbb55010,32eaa95c,c0f6bb42,be77db4d,62b77650,1094ed7e) +,S(30858d4c,d39abb36,51b8d35,58800c18,5495bf31,bf23dc8b,176c1f04,171e304b,3aad8415,4abdfbb9,1eb95aa8,4e7ace9b,fd8b5f6f,cc8ea08b,e094c874,8161f85a) +,S(c06d6d2e,5637fd7f,df08b41e,5573478b,eb19dded,ead1f0c2,9309fd59,9551c787,78cb2514,37d4ca62,91bab9c5,57e88244,edb9dc30,fb1a6441,78217039,628e1db2) +,S(2f93455c,279d2a26,1cc7b724,4c32c853,459e5d99,32692fd8,ffe7ff0e,493de2c2,455f0902,74d698dd,a1a97586,fe797421,899f7c22,60ef0bbd,db0664e8,fa323156) +,S(c00c345b,b4b53f5a,5dbc5f10,597dbad0,75e28162,32e0ac71,fd778c50,20b663d5,c30f78de,3495063e,ab98f001,83fb4bb5,5cbf58a9,1bd52ea5,36a4a38b,cfe89288) +,S(7d78faed,f86a22b0,14e86e1d,f98d425c,fe2e65a2,39b37994,ab25a4d8,5c863382,cffee7d6,5181e361,679c9d51,feff7a36,e8d84282,32e752b9,62689eef,a1ff4441) +,S(ab492cb1,da2e8463,a2536c0c,7cf143a5,9626497b,23d4c179,d2af4cc7,f2b55866,11d4205f,55a74f81,e9512496,becb61c4,6363c42d,baede671,9bd7f2f9,3e00b14d) +,S(d1a3790b,478bf657,360b3459,555e1dc4,ece339d6,93b5b51c,8a3af121,79578688,c6028991,3ea89956,802f8b8e,cfc8dbc3,5894846d,1aba2074,9a55153b,83f73891) +,S(6fbb6fcd,36fe0388,a4bb648c,95a004f9,b3c64e4f,9aad672b,42d8c649,4c0cef3e,51be473c,74ca2609,c3b79c60,2fe90d98,62eb9d14,b9e52aa9,ddde106f,7253da44) +,S(db150ec5,680299af,681ce826,794e4818,c0d6d3d,e3c392e2,79ecb408,aa55b243,15e47cbc,1c4689bf,fbf7ef42,1db5c57b,e3ab8c16,b69bb518,2ed8a1cf,20067de8) +,S(51ffc919,afe67f04,a889323f,4438da99,72d2161a,54f9e81f,aa1e644e,9cb88835,e4b579b7,e985b38b,486d0600,3f825538,52a9d0ca,b8fc98d4,371a7e33,4898742b) +,S(fc86c54a,48052ae8,d8480235,e4dbb7a7,6d05d830,d2c0cbbd,297db0cf,3d2d6cea,6cd61522,e2a22531,da973c1f,9cca1c77,98ff66a3,8f568935,e378f73f,9f1d7dc3) +,S(d440de01,20d619b0,6add3d7f,66184864,5754a424,f4b1054,479a83bc,7df0db9f,3f09b245,91124175,89071c56,84215cde,a6999b17,b5b2f664,6074e7ec,6c38f68e) +,S(f3310bc7,7556f234,e7c83d69,48afebf0,5bd91a25,b516cf84,60d0d6ec,8483fefa,1d10f23c,e0e35816,6b817553,cbae0792,9e34a4a6,ebb47186,1d401341,1ef2b3e3) +,S(ea770a59,e88b598d,493fc75c,62eaa9e7,485271dc,edeb1d2f,76df983e,54cbb51c,e2a4baac,96c9538,3de82a29,5bf3cf30,53bfe2e4,6fb0861d,65c60c09,978601f) +,S(2cd56ef8,6fd04d2a,ed4f8520,951798c2,a1c69a38,8e635a2c,edfeb08e,3af0e331,3b9de80c,42e0c683,85aecbd9,c8775b56,86a8a376,39efd24,98664343,e712707f) +,S(37bb0206,c96d8fd4,5315e96c,860f5cb4,a44d2b6d,af17844,bc305b4b,59c9c649,c77b4a05,373c42e4,e071090a,7da9b4a,4ccbbeaf,d399496d,f6fea1d1,a83808b1) +,S(55fa08fb,f83dab6e,ea7034db,15bbddc0,ab2b472a,b29861af,543a970e,d16033ff,73c8a90a,86542970,4e25f370,a5caa4b,a68eb72f,5ede1edc,5549105,491858cd) +,S(4eafb675,281fe8,98593817,efe128ca,c59fb775,82f6006f,339631e0,6e7d2e7f,41347946,6630f6d3,9fa97404,6808067f,fca9e173,3e1c4149,6567eacf,47a0bc6) +,S(857587d8,375f24f9,e6924793,9ddf3a60,e0469f38,6ea0d55,d990f1e8,4ba5c7dc,1913a118,9d867c57,2f947fb4,3e062cec,3df37c3,e8edc6b1,927b315d,10c37be3) +,S(89e334d8,f71eacef,6cdd0a87,b1e03352,1078a1fd,20dff144,10108202,93143815,8b49aebe,71b60eca,c9256794,3cf74d9,80bb3e47,161b2730,9ed15872,7accd84c) +,S(69902d6,8a4ecb1,d2e496e8,cdaebf94,58f71f94,8f4341a4,11fbc2dc,524f694a,19a54c4a,5de17930,6c50cc03,b0b8d54,b613cd31,6f0bdfb7,851db63a,9c605896) +,S(52f8a3bc,832de46,1bade518,50121b5d,2ff475ab,5eb0e71b,a91ede46,41f0d576,2a946bc4,42f24ef9,469b8121,31021186,5b22f3a,adf93648,5b7907e4,791236e2) +,S(146fc341,4ca1c497,73734f6b,b78ee9e,56fedee4,9487ea01,a31d3e4c,152d2bf,82e21722,e415f5a4,1a076f3a,8324db4,2436da5,a3776f60,b5c6f53d,e5419db9) +,S(9e22043,8458e463,b1bd7399,28200a4f,ef7c3760,a7b6357e,afc29a5e,36b37b94,b1f5fd78,c1c40d98,1473fd4e,72af64d7,7387c28b,7f005191,5ed2587,674877a1) +,S(53190555,8d044a1b,94caad4,526cbed1,82807c65,2bb053d7,61301ab9,68323f1d,ce591f2d,61b47a8f,8707d8f6,a8717139,68ad569a,667ba4ac,f2d18356,ab6d326f) +,S(b93b3c6b,1297cadc,392b0cab,da322a1f,69791a68,b48b0ce7,4352ba3b,b8a3cc8a,136ec007,24fd378a,53d5c573,3aa7a06,15b2fb20,4fed82ea,934bc131,7e7ef22) +,S(62e6af72,a9fcc956,4367d44,c0699897,3674e3f7,b79c67bb,8c8a82f1,6d3f744,4c1e4e33,2e9316ff,24a7b38d,13ed1b30,a659a8d1,8423db6a,af6324f9,4e7d5475) +,S(c91facca,aad0790,886c4421,d28f3ce2,9d64dc87,514f06d,cfe95063,dbbd0e3b,e7a0c83a,18d655d9,7a555c51,4bf8f117,59ce866c,61a7e691,8ecb1cfc,21e50710) +,S(72b3b928,bea91ce8,767b2f22,958458ab,9a23f455,78f836,65c89717,7e7ea502,773235f2,c9ec74e1,c06e4e7f,89247d12,27f303ff,2fa354a0,663791a6,ffa40e49) +,S(1b014ac2,7213cc08,67877fa3,c0c07b1d,91529259,23f6164c,f1d204d9,addd6f4e,e0dec57a,c1ec264e,380909bc,c62394c7,413cfd48,180b1de1,c5440d08,99c67f2a) +,S(985e8845,97e2831c,4ba48888,ac219b3,bd891dc,63176953,4e0d8a96,bf583a83,5afa0b31,1e909594,4b228958,657b95dc,a198b008,6f5cda96,c3e4da6d,e444a418) +,S(ec3cded4,cce88ac6,22315a51,ec99ed3,1ba2cb32,74a43e6,98e033d4,e490bae,1c2a2236,2704a765,252b2a57,aa1ecaa5,4f1c21a5,2d67c050,a3dba077,ad4b4480) +,S(f882c4f7,7911f6e8,64da7cb0,5f09da54,b9cf7125,21504815,e6fdb9e5,73f24be6,9ba4a4c1,e0978ee6,1f83aedc,b1db2193,518a71d0,c112b9fa,59c629cd,d42ebde2) +,S(f06c3a4a,9f1e80cb,e2ee6b06,ff50e447,13d8eddd,5857243c,cd02c5d2,7996eac6,6b38bddf,fccb4888,da20ce7e,495bac5e,7b9ec8b2,2feaff5,8d4329c3,c546e839) +,S(dd1c366d,5be82883,eb86da5a,f9b5d5b2,89de6b9,1165b91c,20ad7b73,ab4de421,19bb181,70b31a81,45232ba7,ed0fa93c,273751f4,838633f3,c94647e2,93c06bc0) +,S(e965c1f6,89b3f7a5,97d23d9f,378b9a03,fb1c6e29,5354de36,a5bfed53,3338372e,d98295bd,890e98a5,9d6dd93d,bd9eca2e,e79b028c,7459779c,2d3fb665,46692242) +,S(4f9148b6,cf21f5fd,911d7fb0,e92132d4,686d3e10,12da444b,f5a89040,69c2fcaf,60e9b3ef,924260db,ad68793a,d684c316,6889b0d0,38474c70,6ca25978,4a5fa7ad) +,S(d9341e6,6a505a91,dcefd533,90abbd54,52b39594,42deef9f,6a67dac0,8faa5e00,eafdc1b5,2b7c97f2,21ba8635,d49b58fd,17cc7983,92e09d13,8c41d679,6fda331) +,S(b948bed3,4f426bbc,e6c24ca1,fd1d2092,1de6f9d9,f561c32f,877a4104,afe81ae6,5cacf40d,f6fba19d,763c5b0b,83aaa284,f9485705,ad882b6,d51bd46c,b12f532e) +,S(73011c97,dbeaca8,8bf04371,311e9558,1e494b73,1778a2f3,cf906cdf,64dd781f,2b5abb31,c2e56a38,e8236f7f,b28a93ec,1bef3fc8,9be46d92,c2fc476c,42ff4ed9) +,S(44835043,1373a095,13f756e7,36ac8342,24004348,70d6cc5d,ba31f74d,565056ce,748f041b,a9c990b7,70c36f68,5667109a,acdad74d,4569b107,c968e517,143499ae) +,S(3463b029,e9dd1907,bba2b582,c9ff1f26,4a5ef4b,40f5af28,2a00c136,97145ffd,9e30bb18,fbb70c1c,edff9065,968523af,33665b53,3f14457f,59d7edbb,d5f07c5c) +,S(5d95aa9a,9fc67758,56e6655c,21a62670,c567e236,a41b523,436beb2c,18e69c97,d6478496,4220cd62,b4651e8f,965bbde3,22aeacc0,6557f656,764a20e4,649a1ea5) +,S(48c65239,d03715f5,71ddc36f,313a1723,b014c047,30cbbd8b,ca9617b,e8fb3874,c0bd39e6,3cc00fde,74c991cf,f6d711a5,356b029,5b6eb9c0,28c445af,21de8325) +,S(67c610ba,fda8dfe6,c7977b70,7a57ebd3,9654c7d4,c9a0aef2,80c896e0,e8134078,c3d4ffc9,891a4267,612aefe9,6c1093f7,8e1b9a58,746c986,c5265381,3ba46aef) +,S(4605213f,4a21b15a,4a471e10,f157d0c3,faebaf0a,f7cd05c5,a27c56c1,88b6d430,9853c145,5f4b3d38,200aebf9,d08f87ae,3eb4a99a,3d94ace2,94331e03,876fb751) +,S(6277ce5d,fb56c2fe,3d32e28d,6754255a,ecece179,70615443,b0d33e5e,b54e475e,dc7a742f,92160074,69d53e73,da526102,a6f68e7f,e8f07a91,98614f0c,17daf06c) +,S(7fbc032a,fdb50898,3270249c,f1a7d27d,198432c1,6815b7d2,c929ab67,bf12f01a,dd696a37,fbc4f852,6db85ca0,6bb498e8,6dc33480,a4f84564,2b49775a,6bf20ae) +,S(dc849e28,6b934ef,30cab6c0,1cffaed6,9ea74ab6,96578027,4c88845b,8ac264f1,6d7f94ae,347b9b18,bfa2bc0,d6b9a8c1,13ef1a70,78e317a2,53f21590,667f4b5d) +,S(e29e0833,7da9e0b6,b6886c7d,fe010cd8,9a4b10c6,f5e4ce38,c1202f59,94a69016,de082f4a,9c21db41,573dde9,d2ca8256,57c67173,207d43ef,e42ea81a,ee812dbe) +,S(407f0e21,ddccb63b,5672eb15,742d72f7,1a522f9,20d04247,3e1438e3,7bdecd35,28d6f39c,cfb36986,351d7619,daba6271,3c9869f9,357504d3,25c112bb,74ad336e) +,S(653286df,15bf657f,1685bb92,98462383,7c819def,84a8c332,77f6d777,4c8dd3b3,c5ea3d4e,f7a97324,96a98abe,f999c25,9a8c622c,944a099e,146c0708,d108eb34) +,S(47613ca6,ca7fe67f,4286f12d,3b4bcd86,455a1863,94f2bfca,e162f991,3bf6ed7f,4409a6d6,2ae63ffa,a3f2be74,e7d0e5e,3ad4704,76282b0,c2919750,72be1386) +,S(8f9bf4cb,4aee791,12162fff,75f35393,509fcd4d,aada298,655bd58f,567e6adb,893c8b52,c2c25f8,e2ea051e,d1a35a3c,8ddbbf9f,508ac792,37e53143,7818102f) +,S(4b25cee4,2f955db9,79c85682,4dae806a,3925a33c,42e6b6b6,ab4997bd,884f68b1,ebe38f45,bfa13922,d3112af9,1324f526,1c5f864f,4d722576,24e3afe9,9eb7ebd8) +,S(a8a40ca0,56b5e168,6fb9a348,ae26b15b,cf812cc5,b9c5abc3,44f86021,69958e81,a55421a9,4f1fda1a,f6d64e48,cee3e4a3,434293d6,b49a5cde,b521c0de,49cd31cd) +,S(1f7e97c6,198e27a6,48ffebcb,55c001f0,d591ca64,77c7c1f9,43928e2d,dbe88dfe,2dcf0a3f,f296f744,dd402fd2,48d29c96,49abc871,28624da,28134cf7,6242e6d2) +,S(7ee29348,7d6520a5,586b3ba7,4a0a660a,a4392e5b,77529e8b,890a5927,aad1ab71,a51d3123,b4faabc3,77bcc565,d66d4c40,92decf92,f63f81d2,ba3a4f06,2a8ea485) +,S(30880ed,b4f5f2d0,95c34730,d10a8c02,11efdf6,784b4886,4afff98c,407734fe,4ca4b106,41c55905,9a19cbaa,bc6837b5,300aa1c9,8b0d8a72,8caf5cd2,914ea693) +,S(bb7ffe45,b725038b,597a20e2,6f67d0fa,c77730e2,4ebadc9a,23afb4ef,a01b4d50,dcfbe717,46bc35b9,81357857,c0b4564e,1ea11852,c5ed8372,bd15eb69,e674e14c) +,S(ddb59e25,20a5842c,62607d4c,6d31f2ed,b79e387,527dc12,5d96fd04,84385e51,2a167f97,85ee4285,7471c45,2c38639e,69940f77,b3fcd54c,a697100,37d9e5ef) +,S(3c405df1,36b1c6f9,99fe0b3,2bf5a305,bfa4a6e9,994a1506,9c5fcfc,318dacf5,ba5ab8fe,43a2de82,ce289cf1,2255f554,d7881d08,a54017f1,e0c84180,d963f3b8) +,S(ed4e6e9c,9d4eb277,73f2249c,13d6fc1c,5c07be47,9ca48e35,913f6fe8,384851a0,8242617e,36b3c298,b13aab58,b7383dd7,93ccd4d1,7787062e,195456ec,43fc4198) +,S(60fb7766,9f312be7,11d0a269,a72a85c,e06b70c8,1d34416f,f7ce1a28,41d50895,ba2097a9,772a616c,82cd5dc7,84585c80,65206913,474f49ef,71579a3f,8cc0d825) +,S(1336a678,bd5d495d,c688c039,a60b256,a09fc946,830fa80b,1622890d,9c8f0881,6d57f261,b1073b42,f6eeb514,58e994f4,7406b3f2,7245a0e7,528748fc,65a4937a) +,S(adb7e6dc,72c02a9,fb99645e,a3695824,db60df0b,f9b6a420,75cf02bc,4e3713ee,96325866,2a062180,20f8b86e,e5ef1e04,57d01fd6,d5541d6e,50798883,9f03b3c) +,S(674d6e5a,6501f824,87efd592,c37bc14a,ab596cec,4d5e6e8f,1be44a53,a9d2f416,e6ca1153,76af0429,1bc2dd6b,2c47a816,c17e0ad7,c252c1d,cdede8fd,c9a18630) +,S(ed73f5a7,93dd0359,68e253ba,8ac4f2ae,83d7f290,24eea4b6,fdc418e2,4b63dcdb,bf687b81,4691d48,5296e192,d5371ec,daa831ea,ce2d502,4e321add,b62f0faa) +,S(601cc630,47ce63d2,c1fbbc49,f3b2dbe5,6edbca09,17ac41e9,b39f7ac4,5cb3ff8,a773b9b6,d98c7b35,458e956f,f9cc71e0,8539b118,bc2529f0,fd496e54,efc2b25f) +,S(a31ffa07,e16fd36d,2edd7d1d,944ecdb8,2da2641e,cc6ccfe1,88219a67,5677a740,c2253d87,59ab43d7,c919710,9e9ecdae,df1f2d82,d34c5d82,d113958f,cbf1e3f) +,S(131060f1,ba302b06,b26360ad,de531db3,422a6bc9,6ca1e9e2,98b5da8a,c8266249,4dae16bd,40159bfc,96665d6a,d64c6c5,3ce90fe0,95a316a6,8cb84844,ec183cf9) +,S(f4a29fd7,90f35f1f,4b3240d6,c0cbb983,3e701a9b,ca241d3d,bb7630a6,da2de25a,b2ecd794,5afa51e0,1caf3c21,5334dd9e,9f9a1f6b,8f35767f,c63a3f00,69c01382) +,S(b30546b7,c5e45266,854b90ba,53afdab8,be115251,5ae22f1b,5e0c472b,a3b44042,f14a6b95,178fbb85,5aeb9cc3,a4e65560,3e8b18c1,4cc54cb4,1e059597,faad7f4) +,S(b6cbbb5,10ff83fb,c8bdd55f,cfafeae8,947f5e83,4cc78eef,dce45dee,2014e175,d0e29276,a14cfda6,f518a3fc,ac6a4163,13666f91,ce5ae7b9,7abfdff4,925cd415) +,S(fcaed74f,19199482,564ce4b0,7e1033ca,c17bd418,769981bb,6547caa3,b61bafd1,c52c08e,f5331ccc,271b108d,5e7794ee,4a493ce4,f6665773,f97902d6,ffcf40e0) +,S(c6d1ed83,29ade032,c9924945,189ff23a,c6b1befa,e4a33794,8b1b4126,6d14344d,6e1c0e9f,da231092,86d23cb3,2c588799,507368b8,8c0628de,b8a79c97,e4ba817f) +,S(ac7d0edb,a7b86cdb,60963277,cac43674,19dc5d85,ccd9a649,bd335dd5,eea2a9e2,61790bc0,ddf5307a,56fce870,4bc9eed6,9d61d857,f4d2fd34,d53a97f2,4c4c5206) +,S(fd9d0c61,d3dc3ff9,bc3735e2,b2c7d5d6,4a740b1a,bcd46a7a,860816f9,84a64645,701e082a,5e59460e,c3e3ca21,40137ed1,5bf9ef49,fb4673c7,4fa5e4ff,2ad8b762) +,S(82ce7d44,87101716,6ee31310,11bdf02b,336fe44c,88572c37,930a33ff,5bdcea1c,d7fdb097,3961ba18,b53b421b,21c0424b,7b4807ae,256d883e,2e3a6f22,9bc44c0b) +,S(5e507c80,bbd32e0b,efc31714,b464580e,f7ccd3a5,2004f2f1,9fb9b0f6,dad1a767,95facec8,a3b5c996,e0bc9d5f,77c11407,d0ee071b,9cf5af3d,ed625025,3aecc75b) +,S(640d6b4e,bde998b4,1bc86fbe,2e981683,a83789d,b71bca76,76715a29,143c9b55,61334a92,358ae235,104aca00,a632006b,769475a,da8789f4,f7047f75,c8b1123d) +,S(e951dbb6,96ceb16b,6059c3ec,9d84ae8b,8adb146f,fd79a323,59c04677,aff990e,d3443900,ea47be0e,10ea9178,3f1524f2,fe5c5720,efb62458,987dea0f,1612a94e) +,S(2b601b8a,550333aa,2a0e98c9,a4b28043,aa38f20b,13a72cb8,7a8cf212,cd0a2a92,2f3f309d,ff296fbb,a406602b,be72d9bb,c3ca0578,f5f0aa08,6e65ec0d,8989f670) +,S(d803b242,9814658d,df7cb378,bb9708ed,6ddd7270,ffb7d712,b64da007,158a5add,bffd353d,c4d664f8,6d7f150f,30e44ace,fef4abe3,83f30369,15b4d5d6,5ba3c131) +,S(d5a8348d,fbb9f9d5,798d7d1f,3515e25d,a2707869,26ae598d,500186d8,a284e86d,ce31c62,19960c61,f2a8a7bd,2fa36f0d,6ea7838,5463a4a2,9dc1ee95,2f37905) +,S(250dd67,781128de,65f0529a,11b2405b,eab01ee0,1e9bde06,cabcc9d3,cd038065,524aa9b5,8dc5c6e0,6951aa70,c4bfdffe,a2dae26c,1e8341a,5f63a180,731a0dcb) +,S(f3a2017,127dab2a,917dfaba,5eabb6da,bebe554,431e796f,a3b09771,66cd47ec,69d1de46,2e63beeb,1334fccd,ce147b96,23683942,21c4865c,d50fd687,5c1659c1) +,S(15626140,5aabf9f9,d7dfd218,3d7fe2c,900ee051,784537b8,deab8bcf,20c6e0e,863d8797,f2b20b0d,ca1a5b93,9a43a712,4d5f0725,8ae7caba,4b76d308,65f9a98b) +,S(3261fb49,2c55978b,20d2c5b2,3e6ac5d9,5e3b40a9,462b748c,62a41035,2efd227a,4072fb7e,3fafe456,8f62f4c9,83d0988f,f9096c14,317f7584,9fc1aed1,3e39708) +,S(2a5e6aaa,f5cd7466,b851802b,80305dff,3e655dd9,b0456bfc,fe704eb8,582836ac,2e3894d5,762e70d0,4d3595f8,83dbec7d,5125720,c516fcd,f361ab22,be67062d) +,S(e85a7e08,13294e2a,6eebb00d,2e3fdd76,318b7520,dc682705,8b3e923d,536cbcd7,5a936569,77b89e9f,10c4ba6b,7dcb1611,fb6a85fd,af0b1136,b19cf222,a2e9a477) +,S(8e36e66d,2f080ff2,a24ac836,25e50148,e5017b7d,b898820c,b7d73214,bc198b28,edf99b43,c2b976b1,6eda2a75,f8bf5aa8,6945d700,9965b528,bb78b530,3888c56d) +,S(99ead62e,11cc613f,2290332b,9d5ddb98,8c121ed5,21a0147,589bbfe7,db0f0c58,6e73b10d,bac646ab,44f3a062,4150da41,d666523f,ed55fdc1,c1146fd8,c4a262a7) +,S(15e233c4,783fced,39c74cb4,34e77491,83004e2,6e16c372,f6f7f23a,e30efb13,c9954660,eedf09c3,af8e1642,3b57af59,227ee5fc,e1885837,5ac5a853,34fc5034) +,S(3b33e0a1,254d310d,efbf526a,8a2314bf,18bb490f,e592e36f,6763b174,96f57a67,e4e6a395,a6e6c730,67fb2e0e,2c5dba63,9745daf8,bb9d6aab,e96f59d0,8eb24c83) +,S(8be3fe6,f3e45fda,270d54e6,49bdfa8c,1dbbecf6,35922aca,2d605c66,6933e859,10269847,15eddf7f,b7b23972,ed1f6fd6,882481f9,1a12eed7,f8fabad9,da0917c5) +,S(ae6863ae,e6d519be,773edc77,8e7bb5a7,5e0d30ca,91dd0920,aee35870,5bf6effc,d104a8c4,1939444a,1a5843e3,92fc5fa8,d2dd864c,1f442938,9dbdb543,415988b3) +,S(58a06c8c,658430fe,e03b3218,6ec051c1,18174f8b,ade2cfb4,a98cd9b8,13e12dc,17f4ba3,da575c84,81cdfc04,25567dd5,1d2b5e94,a8ed37cb,346f88fa,e6f3553c) +,S(cf0b0d64,3843e10f,142ff912,720373e7,2fd18576,1f3d6c71,52647afc,1ebae367,8ed9b909,f4b622d8,cf5d5b19,fa2e1cc4,bdb42133,c4dd9261,22f1aef4,6dac4c64) +,S(8be41872,15902e71,8f75558e,4b1a5ba7,9d3522d2,e8a2d723,f863c4d7,3c4713a9,f7be5a77,6b8ea8ee,1e59765,ecc6a33d,210eadbf,df4c5586,aba43710,49c715f3) +,S(1e6bfed2,36a10a7d,9efd88cf,af1dc1f1,9649197f,785b4a30,c68391ce,808f713b,90200be1,29c5235f,41a79bc7,2d4d10a9,b00911cf,b9f27b5c,6d47eba9,8530b8c8) +,S(97176463,8cee344b,1ebd8c67,17782c6a,86108b76,e1eb74a0,791527dd,b18e14b5,ccb128c5,2295ca09,626ccd39,b5827ffc,3168a628,6633843e,96184aed,d7bf898a) +,S(2fd20134,8e0b7259,415cc828,c3e4f79b,2184735c,86e534dd,77f1c5b9,9d8cbacb,41fc80ab,25ca1a82,67582a89,f901ac61,2237b942,9d724a2b,8cd0dcb6,c96564b2) +,S(5ba918f6,6bdb4013,481bee06,6aaafa88,f741c362,b5c3a4b,28dd4555,3c1aadd2,230f6c20,f39849af,9de4ff99,8e39ebcd,818d5d6d,8056ca67,8f04f33a,c4fafac5) +,S(69b5676d,b8e2a30a,8870c86c,4a859ba0,dee25a28,493909f0,9ac88af6,83b70797,4831db1,98c1b4dc,69942571,e4908ac7,41ec4568,e27089a4,682ee7c9,8ee905d2) +,S(faab5a9a,c530f7a3,343c71a4,273935bc,fb280258,24a63ce,8f8da6e2,a60135ab,1443a23e,793eb339,f4353371,34937bbe,9bda0eb8,c2fa2d50,bcd85757,68c79797) +,S(c70ef20,284cf135,7c437093,10451a9e,5ef10cbf,e3a0ebfd,b90f487b,8ca62d9,8970b394,35c29dc2,b8254d1c,9c4cdf54,6df52979,ca70ff8a,7dc171b0,5a176ce5) +,S(acb67abb,fa6dfd52,e9829767,182f5ea5,66dfaeab,42a2f2d9,aaa545e1,2e9cc68e,4a097150,2367b1eb,4f51f6c,a394d351,b734b30f,fb36dba0,9e53b4ea,3f6ebfce) +,S(2da4ea09,315e0f1b,f5b6e0c5,b8af330c,c27e26ef,54affcdb,fda834bc,cd578a3,a4097d6,ad006cca,53ea3391,10c80150,f63694be,c5ea7728,f77ebb83,2362a407) +,S(70cb8427,c2d5ee86,59b26055,3499374,63e7a482,6731ab85,6b3fd10b,be3dfdf,f44efbf9,a914063,3e8378c2,6e9676b8,351b6ddb,33f7e7db,5ced5208,e4cb7361) +,S(b14283ed,9a9db980,b135557d,97190066,60e4e1cd,3ab288b8,dccba9b1,67b24934,95fccfb3,827332be,a813457f,28a63a89,87dc8c5,340a8f88,76788a60,f03b2606) +,S(ca24774c,727efbb1,15bbbf12,20e59841,891dfd50,9f99744d,de815f5f,3e959555,2519e414,a9703de5,60f7412d,8949f509,bacecf3a,e672e7ac,58c5f98e,33162bb2) +,S(5a5c1b07,ddc79f18,26bb95e1,13e03894,bb63b593,c808f0a4,2bd44b36,dcd3765,a11bc328,2f672c9e,60846826,521add7,57b891b5,d4fde6c9,738c6329,dabf67b4) +,S(2caf2545,1daf272a,b169a4e9,b0eb9c0d,26888c18,ae7d8357,b8dd2b73,ee4cf7dc,bf8d8ea3,afc9d56d,9799083,c79f1289,7d20d7ed,48ba38a1,acb039b1,2292a3c5) +,S(af6650e3,4022d1a1,b66e8c3a,b0a8e9f3,baf44318,f6946a0d,d1c65aa1,e3f9c9ce,1b0222c1,a5f3691a,248154bc,bc9e5e9c,6b2c96c1,ca468feb,97a7c01f,2551bd5) +,S(3653e476,4215cd7f,83ff59e2,f63f2a7f,dafb8795,95006bd0,182e0e,78ca5b39,c91824ee,6ba3c685,2eeb2695,9a3b136b,371c9bac,4141344c,a1eb3051,8a6d8ab9) +,S(7826902b,cdd4e7b5,463452e1,baf88534,64723588,86643d49,cc89b482,298f6394,dd5bf1b6,91647ce2,86c745eb,6246d087,35cba4f,22c26a37,e326ed1c,4e3d968b) +,S(da19c301,4e77f987,abb00fda,8a5dc50f,d2777850,1fafec84,2ce7e5f6,37edd1da,757fb28b,366104a8,cbd26981,3697d8c7,821c6e0e,5acbb33f,9cbd5fed,25cce98a) +,S(efa31697,2a61cf86,df713186,c1bc61f7,63a618a0,8034c26c,462a2457,907436a,74f17527,e6c7aebb,ed6b28c6,26e612bf,82d61ad,cd1ca156,b971abfe,2efb15b0) +,S(379d460d,12fc351,4c46567a,ce05cc9e,ded3cc35,fb416bfb,76d14f3b,c5164f7e,f548ad44,a5c87313,aeb52885,5ac3a955,178c8992,2415837d,d3e7863d,685004fe) +,S(e3b66f05,ed217cb1,6e3f8ce3,56704f70,36b97104,e39c5649,83bc204c,5b112de4,8a2ee4f3,ab9c8cd4,40afe707,d8dc0fed,473db9c1,be2b6e7,b14de905,ba38ae2c) +,S(b14ebf0c,ccda021d,8db1fd20,a4108c48,750d10a7,e0659cca,64f3e6e,ee8c7a4d,c94ca9d4,d2ba47e4,576aaaad,c15f9019,f335ebc5,763cf232,f56f215d,ce42322c) +,S(1ffb2e29,df24e7a7,6a71f607,f4f03608,43d3715f,c3e468b9,92b684bf,1352cee1,27c39636,54ab505,4b008e5b,4598d025,ade823c3,df6aa7c8,18d4d4fd,32442990) +,S(63e13d75,38f1eb8b,7276ee28,acd56bf0,448f026c,f98c77fd,5f743c24,4872b70,845d65c0,a6cd8b30,7c7ea0c9,8024773,86a50daa,3f361539,57cf995a,43705cc4) +,S(169b95d5,417e6173,b4393c6f,1ace153c,21c83c7c,971418f1,27e1abf3,aaa04673,bcd1ca4e,5618a183,420b34d2,52d25dfa,e7cf699,3e936450,ffaae3d4,61a50c50) +,S(3dde4fce,54d27794,29b6f6a5,8c5315ff,ed682bc4,5601c623,948faa88,2309ed27,2b22dfb2,dc46f625,4f29f8a1,4cb4496a,dcef6806,26d4f499,a17c4751,4a1802a7) +,S(6b37e3b0,2422eccb,299e2b89,1a150be9,ef56a628,62c78c11,f3411614,9fd37802,a9c347b1,fa5105c5,a27ed367,261a1cb5,5d54a071,7a2927ed,29d45eca,6e958295) +,S(7bd6703,ef78de4d,f32f0d7a,274f6371,2d0b0a9b,fafc3f6f,5c03b654,599b443a,33d9b1b6,8254d47d,6aabb7b0,b66298d,8447d674,4612a2b1,f722a597,857fda25) +,S(2e9a4aa0,a2062c8a,63b18e5f,91a609de,b60ae126,93d7f1fa,757057e9,ce169b61,65a55523,e34dd131,3597b250,acd11763,62df6b07,1d3f0f1b,907fe0bf,46ff87ca) +,S(f90c1316,9524f407,8c7328a7,126c48f4,eadd6d65,8baccd1f,403a0b68,ff95e7e1,1d6a1b16,6f5b4f7,9f51b046,42306f53,bd84b7df,2a58457a,a8869,4111cb38) +,S(a7bf0bfa,8e84b448,9ee29801,a5d06f66,a17d2374,a6d91eea,2482354d,66c60074,e60ec871,7ea63cc0,e4785455,478848c0,363f6717,748ee9f0,1c928370,df0905cf) +,S(dc4ac1a8,372c06fb,ea7a44cd,11a352e6,fd204df6,f6868cb,5230e420,9ab36e6b,f3a1b986,c86134c7,40c0ac9f,8f2780,82a103aa,e9e4269,84516e09,659f668f) +,S(538086b2,aba47aa4,dae137a4,4bc747ce,9bb225c0,6aa015db,e9478da5,e2c9cdb3,42ed59f0,fb831257,84b15d27,b9086eff,9aec4d8b,9ac36f87,10f93bbb,2ce7d971) +,S(92eaffc8,955f3f06,fca49a8b,881734e8,6750b34a,d253f160,183388af,f18b8106,fdb45519,36f9e291,9e2e2e6f,7e5d2dfe,16e14da8,b5704a27,60e92d9b,13758767) +,S(63fda46a,4350fdea,fba277c6,190c5f37,c4cf7c88,ab1b2ba5,7b0ce9ec,60249c46,b64fd169,403a2687,f5f41038,91e811f,6dbb344f,2c3a1492,fc408f74,433c65e) +,S(f9f7568f,d2e444a8,14b03934,72564798,5c16424c,1ea6fa80,79f96df2,ff3c73d2,8ae3a292,fbef875d,ca18fd89,8e1e882c,ef7bc222,64140183,1cc2d268,ae795a14) +,S(43a5ef22,93462849,ecbf95d,3c92eb63,ea89a39d,2e0a5da1,eb261c1f,2e8e4bdd,896699cd,e580ef97,64ef1860,19317dd,f7c17ccc,34d340dd,b23621fd,5e5ea5aa) +,S(1fc26dd2,9a3ad966,4206f233,82e54363,6ec9d95e,a58e7af8,a4bc8aa4,736c155d,5f6c4cd9,c6f954f3,f0f3bc54,8bfc4a58,faec99d5,9f3466c0,bcc09053,346bab63) +,S(9a63cdf2,84ee5189,34b73c8f,d8b3932a,50ff88f4,8ecf9b40,c0056c7e,168956b3,e52e7902,6a8d4e95,c7f473e3,84b9966e,16347c60,8b6fb6c8,484335c1,2872f4ad) +,S(aabebcd6,8050337b,1e6caa45,13d279cc,ddc4c218,f849afff,8c1302f7,6b728bb5,808fc6b3,90c2f001,bff1993,346a55b3,663378d6,e457c639,b9a73f87,78ee8d09) +,S(9fd45b70,59cd26ff,2188167,ecdb5ad7,62efbcf2,b668830b,475df22a,bf526239,6fa79fa0,e76536af,92eeace7,77c1b735,19092fd4,870ead71,35634768,700a1241) +,S(ebb3ab2d,e71844f5,b6ff8baf,637cc0f1,1004611a,e8a3b570,1afeebb,a7a4edd4,30eed3cb,55a23613,3bec9aec,b620f1fb,1f39a067,8a44622e,84b9e271,62294133) +,S(a0e7ea2e,33c6a3eb,423138d,8faa7ae1,d7802a73,507d48c1,bb38bcf9,29838ca,31158fe7,ad132036,62449ed9,76c4aa17,67382a8a,cd42c842,ed22badc,882d7d26) +,S(a19abdde,db579ade,1dba9264,9d58b15f,1bf3b87c,eae44520,2ae758ad,f2164fa0,508d24fe,f53d8f4c,77e43ef8,eabecf3a,ddd04eeb,acfbecc9,637b6c07,fbe88084) +,S(e86ea1ab,95e23d10,f086c91f,289e2f80,d10ea0bc,aa9d8f3,1873158d,19166976,4b6bc016,6d95e08a,72c4dac7,9eeb405f,938346d2,ae45ea0f,ab76ba98,8c4e910a) +,S(aad23857,d8d835f8,e3785020,6b1cf1f1,efd9c9b6,ea15d42c,70444ed8,81710ca1,a550855c,381bca50,44be47c1,42d52259,af2f486f,622699a6,aec28138,554cf06f) +,S(b5c04c3b,436fe2ac,97bf2043,3ba57e9b,897816bc,eb8383be,ab11d488,e231a138,b1ee4b56,1965ab9a,9fa87112,57a250a2,d7f06de,7759918d,85c69d66,5546a6c0) +,S(eccf5dee,9b6e3fe3,1e3c02da,a2d5c408,72766edc,29da88b0,cdb01f4f,524b0ad9,7770c7e5,d97ca3f8,cdda858f,ed5976f7,cf2bdcc6,60459a64,daa495e9,28f4cc37) +,S(4c34b06f,6d02467c,9e667ceb,630d9865,4540b18b,8832292a,17e74d9a,d0cabc6f,57671dd,326be6d0,2ada8789,b5f27c7,b052c8c7,d300b2b3,ef881a24,53bcb6eb) +,S(9493f9c3,98a50b50,4db602ed,ef50cfce,5bcc9f0a,bcf80ffd,d5f65d1b,d030ca31,fb45d7d3,fc1216ac,6b948369,42d33e82,932af020,fd7c29f0,f2959eef,a41dcb30) +,S(b0ca3c54,153d435,b9d6427a,20ac3456,ab980b67,ee92c6f7,605aa934,faee0bbc,2e2a47e6,8b959402,1ed83edb,d4968c6a,2eb4be8e,2cf128e3,a3778751,20f27b16) +,S(d5632117,2e9b97eb,4b282d8e,1e303cbc,d50656df,2a99c9fa,bad35909,1888ee8b,30157215,efad51b8,20c03f8,2e4c9c93,11d15bc8,3dc75bea,e44e1e52,7f1ced7) +,S(3a0f593b,69396a6f,62655efd,97c103db,5e209554,8d45de93,8963cbc0,dbb9b4b4,66ba5298,590d027b,30dcd9cc,e4605e4a,73adf43c,6e377bcc,cd19eb92,e20e267c) +,S(10eb3c4c,cccd5ca,e15bcc7b,92d108a6,de762cec,b71bd78e,1917752f,b3f6cf86,6d65809c,79395f45,153d7650,74597eb7,edff81bb,598ed20b,f9780e45,bd91d077) +,S(40ae7e81,e33791bd,154945a5,105be36f,57477fdd,d36f83f9,d31fb73c,862e70f9,71511daf,e9cde10a,7e4ff05b,948a0454,e5fcd355,d98b2bf5,8ed3ca54,1a568498) +,S(994dac9f,3c047519,823c007c,57851a8d,41be0480,7c6ba5bb,88e19869,261fd12f,913e96eb,bcef4fe7,60469aed,51e9dbd8,4910d606,9646255c,9cb3bb7d,55b1e342) +,S(f0d9a17d,112e91df,63c106a0,5df3cf41,6471b817,a3ede631,d845b604,3c04d0a5,3ab43cb6,cefaa228,5c84a42a,8f1f41b5,631bab61,1d006946,f06be576,bc817f18) +,S(20919d38,ef12de1a,64992396,f7b265e6,2ab8267c,bb988d1a,6771d8e,724d16e5,81f79a2d,b629ce97,47f146d6,b16cdfd7,90fccd71,c46cf9f7,fe526e58,8ed1eafd) +,S(b92087f7,43494d53,71978b1d,63e11ae8,a1595239,33b87a44,704ca3d5,30f1b02e,6eef6ac2,49a8550a,135072c2,9bb42afe,5d27c8f7,fec88aee,6274d27,36dc0eb) +,S(f69dedef,a8894583,c05b1fd1,ae205fba,3ba11a37,ca628150,d287f01b,b6920b34,a9f88097,66d18287,9d97e01,5544c7ab,ca0cf8fc,c5b9f305,ed0bd9e5,58fa5b3d) +,S(8bd8b3c9,a301a76,9f5607a3,e116edab,9d87bf79,e4099d62,a328c1c5,f8b8b6a2,167117ec,ce6e15da,47a076c7,afd851a0,cb5dd1c3,d8187f4a,9aa5abca,cc0af771) +,S(d7e2bc76,e2a87357,82611,2619513c,10a2eff8,857fe6fe,a2e2c00,c6f8ef4f,85e1891f,531481a5,e935e80c,448d8da7,32f1d061,dd234e39,d55c58ee,df8cb93b) +,S(2701bed3,778a857e,c7a9095e,6487e92c,555ecc9,32ad8e0f,b1b59d70,4131768c,9e38370a,8d30d5d6,6aac5302,efc7496b,cd5734a2,20d2e76e,fae3c72c,a793d991) +,S(3662a916,a05a80a9,13bfc287,c81cf28b,7295dd1f,aa52badf,5ea1c83f,e1b90521,b14bfdf0,a33c9286,eac83a4c,b982f5ae,82e2e134,99bcb3de,3ac930e,2ed0c931) +,S(d778d74e,317063ff,6556388e,2d2ac429,410337a,d62917,a94b7654,6a04787e,f7d92bac,c92600b4,e8184960,11f135fd,adef70da,b72c1bb,9da26bcf,7a81f0b7) +,S(7b05001e,388f9197,ff3504fd,402a5291,d1257621,c8eb202b,dba87b56,154b6f8c,8c9c1c9b,5c151be,39f2875d,b31797ba,2899047b,6e5c491a,56f7fd28,1b897f2f) +,S(603546d0,1fe46be0,eaa9f00f,c99b2a6f,c38fc225,6553bef4,9ff47442,ffa7626c,1f86de50,aa457ed,ea306251,91cc3cd5,61cbd8f3,2b41145f,139110f0,64b73b74) +,S(80f9318a,ca3b7aca,65cb1965,a36981d0,86ba3b32,8a95cfd2,9c6bb718,1f662c25,c195025d,794abeff,49c9b1f6,724f72ca,70b0bada,d06ae11f,2101b49d,d592ae18) +,S(61182e02,a877565b,1209dce1,bc84c62,f3b1007c,48332c56,6dd6e697,664cf64f,d21f9259,517656d1,3efe7166,750c341b,6c064b0,542bac29,28424a30,ce4b51cd) +,S(21cd4f22,ec3a190c,77073680,58562d82,36d463c,f7706f10,fbebd283,c19378ff,2e04af2b,155beea,daace708,c510555b,467727fd,145426bd,680d1964,fc1b03b) +,S(2d3f6c78,94479443,6004ac92,554a507c,5a20ffd6,f275f715,b176b3b5,3d2000b0,72e0e16f,9d9ceaa,2ffc5a1a,71a2cee0,eea64e44,7f716eec,1fc417be,ba16d92f) +,S(a9f45433,c040d1ac,6bd36d33,5b655fd8,eec0d3a0,bf1a622b,df422039,239de17b,264ed6a,8da4a169,a66869a0,a846229e,81d52517,22fa4c2a,4c775322,f33b1184) +,S(16e052be,bb65657c,309d67e5,b68ea441,4179ace2,38315c8f,df88626e,84281ce,91c007f,fcd4633e,597ee06e,b28296bf,2837f30,8cb21be5,9bdbd52c,4ae0422a) +,S(ff6d96b6,f633beea,1de80512,73c06bbe,181a1098,db737c8,41a48d44,cfab935a,cd9a8011,c22b643a,90f1d9c7,54b7330f,1c1970fe,5ac04225,c2720054,fa6a8444) +,S(dc2e3b1b,a2619ea0,6e4ddc09,99630c4a,7b94c78e,ed13517,25b8b8da,137fa467,f97e82ad,49bb4389,84cd752e,820aac43,bc6cccc3,f9b0d9eb,c2337bdd,89cb83c9) +,S(d53b97c5,8e23d50a,3b855c43,80a992c9,2d667afa,bba4b028,20031f58,dd6947c9,24a54f43,bb9a04c0,8b93aa96,9dc61f92,e705ab75,e644a3c4,40391af0,ad375ec7) +,S(b598a510,beb9cbc1,c4e03f8c,1ff610e0,7123ddc6,ad69dd6e,f9fa7810,f79c8ab3,b895b8f7,68a80a37,77d8b5bd,46754473,c9590768,a56fd586,58ce97a,366dcdbd) +,S(cc2296b9,ee9726c,17b0cc6c,745a038e,38b5535,5e19fc49,e89f4ec3,372b2a05,6a466fd2,f9a5c412,9f5b2faf,aaef4cf2,be71406,590ae031,d68c482c,86e3f89f) +,S(3e84c76e,254c858d,51cd4e74,72c22ec8,364ce28c,de81ddbf,b7b3093f,44acf9b3,ce8ae6f5,f56814dd,21186370,f70196d1,339c264b,c78a502e,bd57e771,b438c81c) +,S(976f67c8,c626f8de,9de43f8b,39585d7f,d4cb35c6,e4211b00,68669ca9,a973a3db,ae4f1f6d,25af4ccc,3eca4b2f,6cda0cad,dcc28f78,c8e881c4,eaca9131,2f0b057) +,S(b28bc958,aed50ba7,6d5293f9,7c419828,53bec43c,21ef0f96,9000fa47,49ee95e3,e7d4cc8f,f68182a2,15dee707,4df2c351,906d5527,c47e6414,54e97c1c,b57525b2) +,S(e54dd5d2,16bc5903,9a630bba,7cccf5e6,81a3113e,be8fb57f,83c51209,965cddb2,86352dbf,5f2b2327,ca50458,b3b2cdd1,8d403629,a2e2a776,5562240,7e8407db) +,S(58379e1a,10115a0,8f2b93a2,3f2f4e2,2787aaec,cf129910,b1911b43,c209f379,a526d32c,abd99175,e63b4493,7a0dc96e,e0feb99c,bbe00c91,1e606537,c871c6c2) +,S(7858a68a,cb34cfd3,e1cb7d06,4d233322,ceefa6a7,a2de391f,991b94b4,da9ebd63,f54490f5,ede73b49,946ffe19,d5ae6f7f,ca026c07,b1dc0138,b1409383,5d792db0) +,S(3c8c636e,d20d58c2,f03c26ac,bbbfed70,3fd13304,74bdf2ea,7526f16b,4fe6f7f7,550069d1,cec630e8,6d22af01,5981f20c,ffdfabdd,6416bb00,f2dd8c6a,44401759) +,S(d03fc7ec,eb716cbd,f033d76e,8db97314,858674db,48ede8dc,1a1c7dd0,82ae7f93,16f7a717,a197fede,dadc25b5,a20b0486,1cfaa63e,3157e5ce,ff0c81d5,bba296d) +,S(6d6c983e,d60601d4,ae5ef4ab,c73914c9,b9546964,a6a3d2a5,681b09cd,afee2c22,13f5af59,61877fb9,2a2ac09a,eb691a88,20ca8361,81359fa3,96558ad7,b2276b1b) +,S(92a9f5d2,149065eb,1241d82,fd06ac2e,f1f48003,3bffb06b,ae3a9d88,a1d05f8d,f0be5964,75545835,f64b0985,1baad682,b84d7a39,91ea0f49,1d19b7ad,77ad75d) +,S(222aac7d,c2fe0066,b766e1fd,179c1912,5f289e98,33cce93c,749afe38,ce0aa74a,bd6c4d8,43e5923,b5944e40,8d309733,dc0cd9c8,b266dd8c,2df162de,fde5bf5b) +,S(28b14628,3a7e1785,1c9d1831,6c9ca17e,56a13c25,7877ca3f,49ab2369,ba2898f1,292856f9,572ecc,5f000e0b,1e7ebdc2,3ec72619,3c97542e,8ccb10cf,d608eac7) +,S(5031a6da,df8d12ff,9eb19209,b844b008,dcc26de,c4a6f9f1,bbaa45c9,daf909a6,ef31dc6e,3cb5c39c,64011c0c,89cddb04,7ef9a881,a0d718b,5057bdfa,3f5e1ffa) +,S(925835ee,ce55e98f,130008fd,a6f01768,aee2de4a,f96f239a,430d408d,95a627c3,cac1b7d7,60362e24,f3b5f277,e370ba70,f0f8c6dc,a338c15c,46c5fb4d,f9f1bba7) +,S(6b7253e6,9dd65781,8214fa04,67f59e92,a4671648,c465ea4,9c993bf3,de8d9e77,50a9cbd6,b429c3d7,32bc3b68,ec581327,1c2b0a4d,2d8587bc,7b26ee15,ee7e92bd) +,S(f82d660d,cd5df408,714213aa,a7406a3c,868a8d05,1fe37689,baa6fbc3,effb3e33,affe0a1a,b7bf498c,83b331fa,f3e7b723,2a2dbc66,3b93da28,e12f0d56,260677a1) +,S(990954a5,5342c5a8,db3fef46,da2b31ba,32b6d597,c67c8290,9329a90,c39845fc,d764f091,40891e20,a2130696,216049d0,b3eb1af5,7dcb9797,4c42abc,5298977b) +,S(d6b8e341,f8bad7e6,ff434dce,fcae81a4,1946f237,e0467120,fd420,f3dafc0b,a8ba941e,81677d32,140666f3,55fc28fa,7233ec8f,8fd13703,214bdf8f,340c389d) +,S(fabf5120,8632ee4c,81ad6d34,cc84de68,728197b0,fcf07971,326d4c04,7017b905,79c781e4,aa7dedda,4663b8db,7fff3cad,f9752cf7,ef2382e4,b0254489,7c6c04b2) +,S(e62db266,d9b208b1,83016754,c871a8d7,4b6848de,e496ee7,e2c1447c,2029b0d5,ef7410f4,f44d7414,53b9c1c6,8e5689bf,37cfecf2,1602e95f,3fe053dd,aea24f77) +,S(4bd90928,14753ea0,1025ea2b,86ae2310,5b581b48,98359481,d1b7d36e,d9c6e478,2f12e4b7,b825c858,5362afc0,d0029880,45fd638d,65f1865c,6ffb31ce,424baa50) +,S(3e397cfb,cc5c9fa1,15519366,c6e814ec,4b0ed9a5,dd093321,219e4028,28126ed,31c352e4,d4bef7cd,8929d3f0,aeecf9b,1d577ef0,e8086a28,40d46966,c1165dd) +,S(24bee951,54baf31c,f5322941,ffc01fda,9e89f80f,2662f5b4,edb751b6,5b372ee8,9568a4f3,a34ce5c9,8f591550,b75f2a84,be5cf67f,1fd7713c,c126f46e,1c3b6883) +,S(d242bb09,e4c6cc42,a2bdcdc6,bad2a02,8e4bfa21,430acb16,3f0e8a70,2ad2f0d7,2eede9ec,799b9e5a,13c40c4e,4cf6dc0f,9640d472,2a78cc6c,d920b610,d070b913) +,S(a57b5fd8,f50de3c5,98073cef,bc6fa56d,20dbacc0,72dbbf81,347bf0e8,7a36ebef,a99f123f,a45b1369,32394f8c,1f7ea2b3,563ca2ba,9c0da00d,b2c9c119,e6f20287) +,S(82a43e2c,a533abf0,6aab1199,fdd20f9e,1616a79b,859c6467,ffca4b27,989da9e,19cd40f5,8c997e78,311e5ba0,c0b3328a,b845da97,91dc8ef,a6cf7e5d,efd51c6a) +,S(95bf3b4d,b8ef8bab,16e00f5e,7dbe9907,b54c98f9,2331c4fe,688129a5,5cd021c9,2b4c46e5,b9d9f915,d5d020a3,3c63fe49,eeb32931,9373bf9b,e359c40a,19328c47) +,S(791ea768,4d333125,893356ed,dd8ebe4b,3f98ae58,e25a2d1,67006a4b,5c05799,5f72cf68,7827ce2,6bebd598,539f6519,a50788c,9d093766,9c3b9c29,f52d5422) +,S(85138ec5,a5d3f0a7,881ce23f,e34fbb80,fc3038e,bb7c2a24,ccfeb2ae,5ef07b74,8eb9e80d,8664b11b,d24753f2,bba612bf,c06bf9f2,a4bd061e,82ce9037,895b084d) +,S(3b4c1149,1d98483,9ff33b31,39da0341,f430175a,d5800c80,37e35dfc,a68ec256,574d6475,e225aeea,dace647a,1489b2ea,873175ea,83cff3f2,fec684b3,fd2ad143) +,S(2ea17f9c,6a028f58,396474bc,8c51b1e3,cb9ac0c6,7f73f533,a428281d,4101b04a,19d1f021,8b8cc0c1,bbfb8925,77087caf,ebed3409,69dc2281,3a1dd6eb,9d6c44a8) +,S(67839592,2fcc7ffb,627486db,e1d98a45,25ee1338,5a98c01d,6b3b9f8d,f64c507a,e13ed82a,a1adf761,7cce3760,d049a72c,7572508a,5ecd0615,1bbb589f,17e10a7a) +,S(54a0d2ed,39778fc1,237ab423,1e4384e6,4156c1a7,d5e999fb,2c92ba42,ef40ee68,3d879ff8,c25ed54d,df848e5c,49e3eeda,e8eccf33,afcb1c1f,67440810,8b3e979f) +,S(263ff1ed,726d0ff3,8b47b398,c713455a,3030d499,3a77ffac,b9cde4a2,cd12f7f3,a5f3fb33,c739bc93,c442508b,ac70884f,d90c3699,34fd698d,bc27f7b0,ca48a0ac) +,S(43b2fae4,a431beba,598b3ccf,caa1e034,91e7099f,c19508fb,8e693de6,dac9e3ac,3e43aac3,379c321a,5313b412,7cd00a1,bd8cd177,49c4240e,7cef1e97,22daf69c) +,S(a73e77a8,5733a296,2da7fe71,f4c16166,cf0acdc8,2d5288e1,8cb9479a,2a31f362,12b393ee,e323fd52,e44a9ab4,3e19256a,f7a8c892,76e9e6c,9052f0c5,3ecbc031) +,S(f007a9f2,bd3d0d4a,8cb9524e,a5aae499,6b2d0c1a,19aaa56d,4038a21c,6dabdd86,517a6a7b,3b75b68,bb04bdbd,d6f93414,c97b4b75,47b8fe22,c5828d6,7e979702) +,S(bc64853f,111371d0,8381c082,c72d2528,823e18b9,99de4303,c85a5fb8,87250833,51e7dc7,23256176,62a9f6f2,70bde4c7,94020e61,9e8dd87f,3f266d99,71596146) +,S(144dc699,a063c473,4b9bfd22,845317da,c4b55e92,a232b92f,965967b9,9c8e21df,a20a7982,7d57de38,85e573d1,6d22025b,648b9ed4,c656c48,bd6f4902,2b67c681) +,S(834ed659,98d49650,c3f525a1,b34ec725,89d167f7,a3cc6e86,8e4cdce3,b2ba3179,6bc2b06,c97a108b,2abf4033,152065f5,24c1bf1a,e79adbd,b7eeec17,9e598cbd) +,S(efce9278,6052c989,adc9595d,cd1500c9,8e93eaa,dafe2b87,2011bf55,3488b1a6,48ca33d4,cc89b486,c0930829,91f23147,d910f29c,c9d13787,7bebf55e,a3dc92ab) +,S(5b150240,c3563354,39adc9fd,23e9f94c,369a6cf9,27f45bc0,f0110cc1,b7321f4c,629b62e3,1a85fb44,b448c7e8,e76ec423,b059c9a,c8144c64,9d77a4da,eb044aa0) +,S(cec8cb02,3f166bd6,9fe04f66,8ef6e949,f4e3d26b,d748c30f,53a9b9f0,9ef3f9dd,997f9fdf,dee5cd89,352e6c38,760c4cd0,a7bb2696,94916567,ae60fc5f,39b908ca) +,S(58427cc8,edc5e616,3726519c,7522980c,30443eef,7e72cdbf,b135ede1,f15c0890,d2fe9c00,7eeb0be0,8295e972,e69db2e6,a54193d3,ec9a3ea9,f2515e59,6e34e88) +,S(a7d0a30c,1787b9f5,8ebff502,e4e38000,6bf896a,2feaefa4,4670dee,6030bee1,774eabaa,863fd4f1,63b3a16e,4c17078a,fd0a1761,b39ab05c,3c6b1d36,5e487592) +,S(9d70eeed,55ed86a1,ba17e817,4c400cb8,ab0e5da7,b568ca81,60b585df,d1a84e74,f4c1fde7,f11b329e,f3c3e196,bd78a3ce,5387662b,859f99c7,d61f7962,2d01b5f2) +,S(e0715fee,9639817b,8501de6d,6561e623,628de7ff,d0dbab5f,bf58ee4b,a365f684,e34ba5d,acb60318,c6ccc001,871800cd,98ba2c5d,529a42a2,fd145336,7b10c22c) +,S(594612b2,4cb1912f,fb945465,1036bfb2,79be0bbd,e718ca26,973552b6,93d20143,d68338a0,d03fd0c5,e6c6e3dc,7070c78,72eef1c8,cc2154db,cbdad699,b594b142) +,S(f4f41087,1dbd5394,5fde2583,b08ba65c,6729dc05,b32ec3ac,c8aadb72,a6c0d8,8e948ba3,853102b2,99f2f558,ffc66181,310bc676,4b82dd7e,85fd075d,70d92fbb) +,S(efca7b38,69f2981c,406cfa40,2bbdd00f,15ba56cf,c6e9f66,9bdfa14e,aa9b1d21,458fd928,a07fa32f,d6a0ffd6,64a16b21,2bdad00f,a4534093,209b0c92,f507f9b9) +,S(25b2384e,d9e09e70,8098971f,153ada48,f3f4a9ae,fb946225,77d213c1,e7b326cd,ef50fa0b,4cd30cdf,2667bb4f,7dff0287,df666dfe,7d5bdb9c,ab567af4,b77c7535) +,S(ed12b20f,aa2ac5de,db62c17,2bc67cdc,f0534a33,6a32e26d,b325321b,81901268,9245a6b1,35df02d9,3db1224b,1a0a296b,a39f07ac,ce7ccee8,eda552b9,748eca9a) +,S(5dfa472b,b84ada50,da3ede14,8bca4f0d,aa885d2c,61633336,b2a8a37c,76b200b0,f314a5d8,2d20fd30,ee237487,7a922a54,f4c10468,656a5432,974cc3db,c2c7fbb7) +,S(a9e5c0d6,5b6d4b4d,b242d87f,57c805a0,5b7f243a,515c5d34,a037ddc6,afcc4470,d90fa599,de5fc8d9,87a42c57,f3bf9dac,d5b766a,fdfa07db,4c56c0d,3d71324f) +,S(4e9ccc2,c0e3169e,e25a6701,a82e7f02,2663d3cf,585100c8,2c6b5da4,d8c42e8c,854aa160,d48d241d,f5bdd1da,2c74d1f9,a00fad7,effa29fa,5ecedc42,3ba43484) +,S(2122c569,da05f145,48d42f9c,5ce3a96b,bbcb49fd,fc5b2dbe,1a7ab0ea,84aec76d,40796418,39879018,93bac618,8a7286a8,f8745709,58a40cd6,1202ac,dba5867b) +,S(aa8cceb3,415df249,b5069899,75a853fd,eb409729,331b1807,ca2242e2,a75c6968,5362b581,fb676eb9,9f125fd,5f674be4,800d89f0,133a1363,f1cb30ec,1fa5b468) +,S(beaea0f0,1fd8e442,50648032,530e41cd,7e3c8271,f4b83b4f,7493039b,b21013aa,e21f7d1,53e5d411,794fb472,47897cc6,a86396f6,3f6291bb,fe2f0f12,a263873f) +,S(8eaa225e,63bb92b9,666bb318,22c166e0,3843ff47,482cec9a,69ff584e,d1a750a6,aa26b32,e69c5d94,19663e05,6c9f7a60,1274aec8,a839ff1b,b5a43c2e,136ffd64) +,S(bcba926,40d8b4cf,8d73c0e3,7867f5dd,81eef91,70e904e0,15f05f3e,1bf6591c,8913cf87,e33aae4c,a16b1391,75d60106,ac7d05f4,a8f10db2,b0569a6d,ec121260) +,S(2d03aaf,6828d0c5,9ffadaa7,5d1b7e95,b3c4a547,46faa5c7,c428fe45,1a9f3332,68468e2d,597e7534,37b3865b,3c968e4f,e3f6b1fa,996e6b4d,296a12c3,20e61cf2) +,S(b39b4de5,be757b36,b1e88773,47cdaebf,11f8d6b8,ab59d780,fbaf2263,a823b5b9,1b609d2,de73faa,d613c4dc,6ac3c2e0,33d62b22,7ca3fcfe,4aca992f,eef90b0e) +,S(eabf705f,b6996148,170b23,9fb8998e,df6214a2,cac27fe2,9c66a899,63d2f0f0,e1867fd2,98603f79,d17876f4,7aea4437,cb39ee7c,bdafbf0c,5452b024,86182d17) +,S(a4ce885a,ebe9335c,6ef43c6f,395e1644,201f578a,4caa7f74,65c12542,27f1bc80,bde32eef,f7fdc498,1c50942c,efb38cf3,c3f1a8a7,5addfe7c,f11723e,f57d0c41) +,S(db8ee69,b0e00ff7,6a094251,a53c61f2,e00dc65e,a11e00e5,553ae121,ea958361,24e7ba71,22742e09,728108ac,59c5f46,aba40d1d,c308edd2,9d494f39,d156b2d) +,S(88a5b43a,d6cdc2b5,aa3d58db,9a9a2e1a,6d70afa,808efa87,1d7f3cbc,509cf064,88483c55,e5bc8717,8114605c,1febc726,e14345d4,4211b670,6b6185d8,ea6b7103) +,S(e3cb24cd,2130716f,10a4d432,d4e59229,2e11a2f5,3190bffd,4f478da2,216b0051,df432db5,caabb417,f8252d37,dd23e117,38066c87,101cd934,73a2883a,1b7e8de0) +,S(d9c88471,97f04254,731794ec,e29ba74,f1d72f19,8f424beb,8309e1ad,e09e1301,12037266,331f04b6,db4264df,ae6d934e,5f753828,35a646f5,cfa4ae8b,e6defdc1) +,S(80bb740c,3510574d,10afa586,a6e541fe,b5368797,231d2a63,67d2890,8877dc58,24ff9389,bb268f42,b04f1702,f7b7c6c1,7194c7bc,c5f4f63,bbcd4ca8,ef476fca) +,S(4b8b08fc,400d6fae,da05cb19,65c9c785,8f93452e,d1be8f29,28c83e6b,4d2b06a1,70a6612,2549ec2f,6cde4a4a,9ae8a528,1b05081f,8eefa8cc,1111271a,1beea7ae) +,S(d2708078,4d19552b,13ec8473,1eafd2fb,bc0ae927,dd746a8c,be1dfced,d072ddc8,9362bac1,806dfc84,e736758f,22f1039d,57a5e44c,40586195,885abb78,f75d3355) +,S(7345d1a2,7b9dc922,f51a0466,57721451,cea5b54f,6673a484,7a210b4c,339d1f18,293053e8,c180ee0e,d81bc4fd,658fcd5b,99bad329,9e62aedb,74867df2,3ac12d98) +,S(3b3a6baf,b9003f37,ca27889b,a2be2a02,748ba52f,6c6dc719,afcacf2d,578b1e24,a9749973,c49ebecc,501f9b18,83056505,6c88c286,2747496b,951892c6,8a61ffcb) +,S(b2d1a3e9,15b02709,1abb5ba7,206ad2c,5d07079f,8d4c7fae,3e6837be,34159226,90007202,78d4188e,b8efc45e,8306ab47,be1c6a16,d88284dd,fb627b1d,92959898) +,S(298019e5,5de972ae,fd0b4c94,9a9d4eb,46689fa0,9b849947,bbe27805,4a3f4a5d,5b7a4298,be50ee99,363b5f9a,1ef103fe,4fec0034,fd8a2364,5cc76f8,ff804f0) +,S(604f1e62,7f503661,5b55fe74,4540df91,67fe575,e0aafe13,8af68214,f1080eb0,2ade0355,b373ddce,2353669e,6af5575,cc6b01ae,58b2a581,2b63f36b,58effd5d) +,S(ddcbadcf,63ffbfce,326db7e9,2df0d483,9a35df32,fc576070,9f2422f2,6e07b8be,7a3bf369,dc3a5ae0,c91cea62,1429ad45,76f7110,b654a1f0,edda9b57,3076306e) +,S(160a19ff,10c8b334,7683b21a,880226da,81d536de,d9dcd357,d4f2283,18853837,91dd522c,f6d1d276,e88287a5,a37afefc,ba010111,82b93eee,1483cf56,e6cf5218) +,S(bc1210ff,d75737ab,51300e3e,ea48a264,5f363793,1f4c6f95,e8507034,84834819,8acc70b,363e52ee,779e6342,ea7dcb7c,d7d09946,5b0eec60,e35ea360,e8baa7f4) +,S(c2da24ff,f2c5419c,3d2ab241,e55cbfff,5f41b9ae,4efaa105,abcc173,a81fa1ec,3fed4d9a,4eabf3bf,6b913bd9,279761f1,4aa630c,e278d0d8,4bc82ac7,af77481) +,S(73a495ab,b26d4be1,bd99935f,f5583f6c,f5c86d79,fc86a4ed,48f87f40,2f12259b,f4126c3b,3e9b8dc7,ead63ddb,5749fe5e,6cb0bb3e,3c85426b,950326ef,9092301a) +,S(599baa65,fdf949f0,f54c44bd,ff605ef6,2f53d68a,f0e44bf8,274f0b73,ce251227,297ec5da,e3893363,617f5448,b13237a1,91fb5a20,e52ee897,a124daff,9f1eaa9c) +,S(9a032a50,6786e1fb,bd9ecd25,243ea67d,57f9e4bf,d1083879,e309690c,fb07f253,a073c6cd,15445d6d,80c51af2,4e7f540d,f1b75fa0,89a4849a,ea14ea09,ededdb0a) +,S(792160b3,eda1d493,48ea96d6,857d8631,ed1e198c,c7f185d6,b9d2c75,2b1cae63,d12d76d8,bd73a681,9bc581e,cdb84efa,dd143704,5554984f,8f1132c5,fe1bc32f) +,S(8fc4cc45,9639aec0,2c337f16,589c09a7,e787dffb,69ba2907,37b6c465,db9f12d8,b2ce3c2,57ccb79a,b677a9d8,49ce1833,2a97fca7,28bf3e83,6dbefd23,5343571a) +,S(fc06a9a,5857b2e6,df0c3be8,b5840946,ca77f690,4ba114be,44e760e,267eeda5,6662078e,f0de0e94,5a770654,b8281a74,f82168c4,49455250,136dadf6,87c5bd2a) +,S(345da4f,e1e89eb,eb27b353,4352c5a8,32d3c9ee,456c01e4,657c2885,733b5f69,3db274c6,b89e7400,cec4e2a9,9995ece7,be8b98da,39a2fa48,bbec96a4,5c758be0) +,S(309850db,36d8c2b4,610cf8f3,e1c12431,3931aebe,1a9d2099,cb3bc7b6,fbd8b0d8,edb3a9bc,f6417672,af9b1379,9bd8aab2,f953391b,27cdf167,320005d2,3fb3e4d1) +,S(8a35d7fd,8c7c75f4,e22ba36d,d84533cb,f314a54a,2e17a43f,d250c941,5025b0aa,97ae015f,fe364a2b,6c12cc42,fe526eea,7250092f,79c40b94,ab7102c6,fde1fa5a) +,S(982d9d66,dbe6b738,2cf2820f,c72ed491,d6a61add,f1eff091,de30fcb4,96ca4161,b4a7b42,2e9cd74b,10cde7a8,12b4d88,f3621324,acdcc911,b39d0952,3cb3b501) +,S(1396bea9,57d47670,735ed20d,e2ecaf6b,afe7e067,5f2a0f65,6b3e719f,573cd1a2,cd77e7d5,a49d6cac,5e7871c4,58df45d8,821d77e,f3ad3db3,56989c1c,700cf484) +,S(6857993,76774ed8,a08da47a,9323241,71d09fdc,964893d2,aa5e783c,b8030057,640c986e,befd426,8fbfb131,8133ca77,879ced3b,56ec251d,12d0a650,28bc9d3e) +,S(801865ee,fecd50cf,4970e6ba,efeed453,769b3e14,c103db6b,2632e241,2405fb6c,b3d3f23c,8f75e475,8784016e,6ce1b91,8db76599,8c7c1aaf,af047282,ebd7a636) +,S(f09220f7,27e57fd3,209eac13,1ed93f96,142c400d,b9bd708c,9e716686,20f1793f,8280375b,1b2f4915,cb82a72c,43c9fc6c,f3a7de5c,32762b69,43187a8f,13510eb) +,S(1c814b69,6104f8e6,5a51b98c,e6b0c4f9,f26b5633,8ce24ee2,24a5aef2,967ab705,1cc2bbfc,61828277,90502c11,bcaa1f1c,b5e34891,a7c669f4,dbbb604b,df2e3135) +,S(22fff436,de961dd2,a7ef38c2,f588aade,320d0721,55e6a42a,3201bc6b,c7d24a54,6f13476a,f48f9197,3845af18,ce68ba91,77a0d4f,a835acce,76814c81,f6aaef5a) +,S(39da98ed,a85b2de3,c9bba6d4,1af633d5,5a392dac,b1d4fb9b,654fde5,a3343a65,29b89534,35045e6f,2ca41bfc,9e5c9ad2,55eee426,95f41744,b239659d,460fbdaf) +,S(6fb84bb6,3be24203,6e067346,1a5c1fbf,7d89a0b0,c98ad2e2,25cc3ba2,191fbdc8,21a37f8f,e4f821bb,3886333,c554d6ea,cb8924f2,bfdd7ebb,339a8a92,ec9bf8a4) +,S(29080a3b,7c1d33e1,13b70c4c,8388fd4f,59118a86,c4bf697d,25346368,8f60766b,745ea31c,e9731f68,89aaf5d8,1e7f686f,b345c9d7,3af728c6,7ac2b8d7,60ffecc9) +,S(a54f7e6b,aaf05de6,77e7d98c,5385d9e9,57f68d2a,8e3c24bc,11b6435f,50cfd955,f7d61099,22ff9c98,ee79998a,597dac10,be885d5a,e7b53158,fb671e38,470b5c69) +,S(7472bc8d,c109d56d,a5f150c0,bc41edce,7e378335,15e17267,62f50cce,e8845b2e,3c59290,820b997d,3c9109ac,7319048d,e37c5280,88e671fe,9cd85487,f03917fe) +,S(6f4cbc32,ff1805da,6cf83c64,b0d0eefc,6bae76d0,586de80f,df2317b0,a4e68267,29e492e5,89bf6c68,17731a29,76577124,c9bc9e32,1856bba8,8a060bf1,6a6c9d9a) +,S(1a93eff,b60cb865,8538cb27,d8c12490,483e6886,16320327,e2689591,c5413a12,d96609d9,251ea2b8,f150664f,efe6bf6f,a0634cda,b8846cc6,5f6c8a8e,97697c9a) +,S(79b82e7b,bb23efda,cd79c0f0,87f2d0d0,e2d3db59,97696c73,e6e94ea,8cb72027,bf16f23,47e594ec,fd087189,48d531e9,8306b173,88546493,d620218,b25e3758) +,S(a806c902,28fbc405,ef56057a,aee9993,ef177261,74d456fd,818126f2,5d93f986,fc49c640,7d9d26f2,f043a1b8,8a41bbc1,3ced6a93,bd669ddf,3186dab2,9eb7c5b7) +,S(227d9094,69eab478,9da2fe7b,3cb618d8,d781e0a6,54892f86,92eccce2,f41e9a1,81cbb45e,adfe3fc1,de5975cc,f87f0a44,e9f106d7,19cfe796,f33b5c60,85de7691) +,S(14f8dba6,4bb5aba,f7f58e8,1c9b0425,2c357f3f,fa8aeee9,fa4ac700,8c49e060,26b19dbc,52b913f3,b6aafb31,3de99445,b49d64ef,2503d28b,bf2f9e2f,4614609c) +,S(f22646cd,553c5008,aa3c4cf9,f01a05e9,20cee021,4e9b0553,38a75c1f,23e5fe4e,52cdb77b,7502794,ac16003e,2f4e859d,ec3e68d8,c84a3365,a307ac80,53d3089e) +,S(515de841,814df2fc,7cd43689,8780686e,f3bdbfff,83eed568,af19c75b,5ee93a2a,7395bd22,705a81a3,d62f3130,ad416db9,268961c7,facf81a4,44d2ed8f,e4df1282) +,S(59f4aed0,38f07bd7,b2aa6600,ca6f15f2,d396310f,e4ffe212,4e6a89e7,3c7c4ed3,47a048be,5d6e45c2,4fa69329,86b86edb,b990eae2,f5dc6524,3eadc69f,43b2ed3a) +,S(7492492a,d7f94293,4287c7e2,5f05203c,4c70b8f5,80d23b4d,4822d1ce,fa3450a1,19523158,2fa06da5,eb5368b0,f0b19971,1a1bdba7,50d1c6ab,80ca1b4a,d649eed6) +,S(2e12d13d,464de937,372a69be,b90dac92,78977cd0,e7b954d9,30360d6e,a51cc3af,35a900c5,6c7cf352,8c4a5af1,56dbebaf,32d2a128,8a58e3a2,ddbcb539,bc3e3505) +,S(ce4c4b4f,a52f06d1,11dce52c,402395e2,a6ffd186,dd8275b7,bd43e941,9f4699d7,957b994d,c5bcd5e0,179a67e7,94a40ac5,cfc074da,6d23d178,969fd8b9,2d9dc455) +,S(c51f1cac,5814de82,f4bd5d2f,a8e4950c,38fe78bb,8d09bc5b,628ec13c,e3084592,721122a2,f63289c1,f8925ce,34d810a4,be52f7bc,9bfea232,47617f95,8db1cc95) +,S(9fbaba14,8293f578,46c717c8,718a3a9b,9dc5df98,63ae10e8,9c3649a3,e26128b1,4917061f,ad964c4c,5d79780,7914b2f4,b6c3e730,3bd440b7,bc00f15d,bed2b497) +,S(a4a9ed86,ed3a1dce,5423c1e,1bb5fb9d,fbc1ed41,66a4219e,bd343922,8542ea9d,fcf6821e,46386764,c61eec0,19b1a84f,6a8851d,89be0da7,9d2768af,6eba9d89) +,S(a6fa3567,9a732aa7,b58582b1,5f3e95d1,f702ab16,5249e9e7,89a5a395,3858d1eb,3bd67e4e,c0dae02c,43d32cfb,d25a4b2a,75898bad,eb2986b5,6cf61825,ed2830ab) +,S(3b3992be,8f7e1b1b,4d8f5710,6feb825d,568b176d,af0e41f5,9c2fd59f,f67d9b7b,ddf2751,ac17a413,2ffc5c08,3e8c7728,a74b0063,377228bb,a60cdb87,1b5db297) +,S(e9ccb20a,8a279cef,2a15de57,e34f510a,f60ce397,3fa2ec2c,4558f166,7ad20201,b70a11bd,1b5414de,1b30035b,3dcd1dbf,17558bad,368c78c9,d5d9136,6592fa53) +,S(98083dcb,1356be80,b324aa95,e38217f7,c437f421,5a7f3e98,ba803fd8,5cc04445,bc0d9ebf,ade6c640,d16b82b6,5328a2,d5ef2f8b,52aeadca,e406ae25,e9b756a1) +,S(6a0f3b01,9e3b2a9d,453cc36d,275fae6a,b94aa14e,e0b4103d,137b1741,8b446ba3,ef30c9f8,46c54902,c10a4ee6,c5013b25,709e7109,fc004b6,e291b1bb,a021facb) +,S(83a62b60,6a1c4d03,1a18473c,f2230088,1d767332,9513b7a9,4f402f18,3dd45640,b23888d9,98bb9c00,ea57c9b9,517080de,95e6491d,cba0d7a5,729ab99b,12a1246) +,S(d2781bf,4b059449,75da8b83,cf82b43d,b5ee89fc,168186bf,74f22321,30678492,76fe1955,18e00974,6af44fb3,6e623f4b,fd0ae8b6,474e91c3,3ec364a3,91049d49) +,S(e4445252,dc6acf3c,f7b3663d,7176d46b,efe95e40,3063d1a1,68fd5742,2795a986,cf7613dd,eb200aef,e665bcf5,a6dd7fe3,cab6ede3,877f6a28,22b6620d,1eecda68) +,S(51f59cbe,68f523b5,b435633c,ce11c0fc,ed2129f3,5d392b2a,ef789044,722052f5,10403f8b,e7024887,3c4f0aa8,e4d0fe46,11f34268,178368e9,1eba8e4,d9b318fa) +,S(7d1806b8,410ec629,77fc41c8,8c86ebcc,74da9a0f,c6b35c43,68d069a2,c8c974f4,efe8890f,5aab9bd,c2da2956,bc089b58,b67ffd79,957ce0dd,9a53da,b26d68b5) +,S(add67544,8cb87ade,f8cfc3c1,85fbce12,e0d1525b,812fb5d0,2420481d,b22dde96,bb80527c,b22a3bf6,728ba305,bbff36ce,c6b44d68,9cf79ffb,93030460,8f461174) +,S(ceb2968f,fcc7b751,f9b560bf,b08f40ec,ba1395fc,9a3f63f1,65a1be1,862c3dae,67727357,b2dc8d2a,47606c1e,ae61ce54,1d79ba49,4a5e310,e0435b,383cf088) +,S(3a03b03a,1348cf01,afc60665,26b6fcbf,b3977ecd,7c17725c,a9f0c494,f31223d0,3e71c6e0,7da0635a,a2fadf5b,78c892c4,c95f794a,88594b72,183a9b2,4dcbe7a6) +,S(42ac22a8,c708f2fa,559f9b9c,fc7ca705,4356d18a,95a69137,bb8b8b17,2b771aa,ef669b2,85ed6abb,477dc2f2,bf0517f3,794c371,9ba5b267,8f622eb4,aa4ce374) +,S(b2ded9ee,ab06f1c4,19c5aad,5163e731,722c4923,818185c0,d99d6a8b,dc603a06,23bb4786,f84e6c75,e565a708,2600585c,e1fd60a2,b935bb4d,390d07ee,5e8646dc) +,S(ea1faab0,bb0b6cd5,454e63a3,d1546747,cf9707c6,48e4837f,3fc6b6f,a2ccc5a8,8fddc23e,651ebf4d,89e54148,2043fc34,7c26b66c,b2ad2d80,1fd2fb7e,77d4058a) +,S(487920c5,14ce0cf0,9d939ce5,81e13409,9fcad06d,3e6974f0,a3b5925,12cb3a86,db447217,8a92e9f8,65a1b022,3baf54fd,618a87a1,15887f02,11cddbe,986dc927) +,S(6828652,aa506655,60349cdf,132ca8c8,9a6f9a1b,8baf6adf,64e10c12,9ef9217b,9615f563,20db2860,9062aca4,7a136e85,40ebab0,3f8b5f7f,93bf0369,aeee0cc4) +,S(b66a66f1,9c94868b,3e45139c,ef9d7586,1a6d06db,72027814,83dbefbb,41157a94,5c0763d8,8aa90b2f,ee04eab9,fb96b280,5ed5f7e0,58c9805b,64fb17ae,9a0f224a) +,S(5318b13d,a824dbec,eced642d,d742ca30,479874e,31c1013d,d770a0b3,c9ddcd9f,13093540,9b5d56cc,d5004948,3bb22009,4b7d5a5b,6d357bd,76b79117,458e60ef) +,S(6bef6b9,555f29fe,b5277c48,863c990,8f1fe2c9,5b4b45fd,8c5eb482,3ef4964c,36c00eed,4281871,fc5e15d7,7acfe3c2,6793455b,9b3607dd,71f3e163,9790e3a2) +,S(7972f783,4c010837,89b92a08,d21b8b8a,b6ff6ef7,92eabe32,fa1c92da,4c8dba6,2c3352f3,f458a538,f8228321,c1adf9d4,a2df9f8b,bd22675b,afbdf041,9538f1e3) +,S(7f03f087,168dfd24,7a93e840,e68cd221,f02735d3,93d777ec,c9d2c9ff,7cb0228b,663dc741,fc8e98d0,7dece960,5b506b5d,a5f2af72,1b64480b,1dd3e7b5,a0ee7743) +,S(d06ffe61,973be011,2f17bec,6f4dedda,9b9d310,4ed22ed7,d4c2f009,843d2c04,175f409c,edd739dc,5adea16a,187a951b,d42df4de,d1aabfae,d56f1ac5,26cda8f5) +,S(9094c510,3a34209b,45f7062e,ec65c14b,72fa75f4,13999117,38cd7f6b,792119d9,da541e51,7211db66,272f8f8d,413e1717,13cf499f,6c9cd694,b98e53df,45e9d501) +,S(22bb9cee,8a5b99fc,d7ac7d67,5e232183,3f71a72d,55248a3b,451699f4,9f151eba,841e7292,93a98297,ebf2e9a6,6d106325,265d91cf,f7e4c245,845e5a40,522b94a0) +,S(b548dacc,944b013e,d50dfadd,fb84173f,d5829b2f,69a2242b,c152684e,7b8a3ecc,6c7b70fb,9ae39eaf,583939b1,1a1b8aad,673b18f2,7568d2e0,b2680b19,8c662a88) +,S(34f46e0a,2281a617,f8ab78c3,86ed27d,f837f23e,e986dd20,bf705daa,1b0188d,4ce4df08,bbf1e735,6760e05c,6e5d3f3e,664fea9d,6e1a72d6,bad17bbf,a3c089d5) +,S(3063ee2e,3834842b,84cce6d9,50ba5afa,1d645c5d,e0acdb00,a9cc4ce3,c266f649,b08247a,f79c2be1,a0e4e021,7c9ccfde,f76d1e46,65f3185e,8623aaf8,63bff9b6) +,S(d7232b55,3740b2fd,464a919c,46168ef1,e09638e3,65117eea,979130aa,d40fc525,f842c256,38e84dbf,47d13fcb,1763a296,47b72908,1b522623,4e307dc0,1a402ded) +,S(6025e82,e2ec643c,32b10e6f,62ef310a,11576957,96c10f8d,b099dd4e,1dd8cffa,1e5aeacc,cc5c5455,d542dc51,b12fa3d1,75061cc9,45931548,7467d09d,945e2596) +,S(141d07cc,256c4d2d,44ddb7f2,ef720aa8,4bef767b,3597ba32,3b39915c,1d84f175,a842c439,9366b2a1,91e850df,333c9cd4,6c983158,cc57989c,588c305a,1144ead8) +,S(ba4ad105,6ffde493,54d13149,31846519,86fee8b2,728917ec,bd1a0112,b986a90c,97ac53,f84e995d,92d14f0b,b156f47c,be5b6506,2a7f8b07,7e235da2,808029c2) +,S(5a6ed894,bae212f3,eb44304d,98ffba1,4a944cde,ccd12517,5e52d767,5e0f801d,d8160707,d43053e1,e5806d7a,bc17563c,ffaf92da,ac51deee,55fcb9ef,715b08d5) +,S(d82a95b6,56bd1abe,50933a3f,e291526,7b257807,c8cde42e,5f1648c7,f35c4f3b,748904dd,3157bb07,65f94c18,7528c74f,ac639a36,be18963b,676b9b37,83f54591) +,S(df7c9de9,8e748188,74967340,34a76645,c1e55bed,3a90fc65,dfd9726d,a2bd3826,3bd77fe3,e4a4018f,3e256ca0,2bb5c8b1,b783b729,21ce329a,fff9caf6,b530b1fe) +,S(d3ae1d68,4614c95b,51cc4af5,a9e8a05c,4ad7eb4a,ba4a65a8,9a151b96,d91bdb68,a24cad0c,ad0ba98a,860d6d74,aea57c3c,23780812,5fb2356b,b55f0bf2,95e25e67) +,S(ca85c924,48a27be2,2b68c9f4,c9ab431a,b380ccec,2439c8b1,944c234c,bd865758,c53177d7,6b16e0a4,389e1e32,7072d460,90e92f48,22043bea,924fab46,4023038c) +,S(34309aa3,4e9fda0d,f2c20da2,3e8f8f31,eebea096,1e769c92,6c4251bd,5440bb04,f655cca9,d5811164,577d0525,2f5605d1,b4e2b6d4,dd5540be,aefed4ae,84caf3e6) +,S(40212a4a,b2bfcac9,62442617,8a807655,185d2929,7e26c437,4879903b,41307b3e,26624605,6ceb4509,b481df00,79e25f1c,4dfea60e,a3768e8a,462ac273,8166dfea) +,S(2e441425,d121e140,5d2118b9,7a3b305a,fcf62e91,4f24bb72,46e92aeb,1ebdd152,c3c7a567,51dfd709,9535d07,23778131,692dfdb1,7584d9c0,c8fed42e,5eb662f5) +,S(31539912,9e59668b,49d9b8bd,5ee66b2f,aa727ff4,96f457f4,33400a20,b5242b5d,5e90a20f,a700c59c,fb0ca2cc,ae3f2837,6dde44c0,3cf6af64,365e4cd3,b4e6b3b4) +,S(3b586e2c,30eb1959,bd5171ad,54b81c36,cda6b0ec,b5e77b41,a7b5b0d3,e1ed4ba,6782aac,d675436c,d969f413,c471edf8,ff7d89a,d0a07575,16bb695b,19ef40fc) +,S(f4299c9e,b3453201,375b972f,fa39f01d,90c68625,a63c9d06,513fc9c,8c623fc3,cbd0e2a5,f9b9ebd3,f482a5bb,c5c17894,d5c320e0,28744292,31c94fe5,55ecf68e) +,S(96d35f35,eee50b32,32371acd,99d6db8e,d2b7c4df,1f62b867,5559543b,785503d2,c0e8bce8,8bee1e02,29a5d2ac,113c9f2a,feff0260,869ecde0,7cdb1cd6,3ba5f73f) +,S(ad3036ec,e2bcae0d,1fc34680,be2d293f,b40d9133,905af375,1ff89c49,2c183e1f,2c0773d4,bd30833d,24222f89,3a4f5e8,cd6abe06,63d66d63,2d5fb832,4c260f9a) +,S(a0f340da,909f04df,70a33195,1c48901f,6353f4d0,4d22f99b,3763f567,be9d207f,caa1d9de,46a37b8d,623a39a8,6792475c,bf3bd694,597351ac,515ecc8b,1a4fe78b) +,S(2adc4874,af0b3cfc,675421b9,5369ff0f,950b55d1,331aeee3,dcd0adf3,859be4d,6ad9fd3f,a840d02e,ddc01fa0,ffa61bf9,4dc1db4c,ec733976,bf1c6e41,bdd92b79) +,S(b9222a37,c14456a1,cf931410,d96cd84f,a304b9f8,5a96edd7,6e67f928,43536175,4002a875,dfc4cda7,4ff7145e,ca46aab8,8cfc5ed4,53b34eeb,1e5dd859,4793e3d3) +,S(530bae23,c3796fbf,76f86f6a,d8b59b80,801328b7,6c46e8f1,cba6398b,270919f8,d4d3b34c,6701f07,bc47d1d9,fb868fc2,b46ff397,2086cbc0,517e29d7,38a7964c) +,S(a7f2ce51,5b932506,c740e84,40f254d0,e0da57bf,4d9199f6,acfa3664,ec36b823,4946fc41,3ef1b3f1,86a2c781,6c05ce7f,803fc7de,a00fbc2e,7e6c4688,fcddadae) +,S(8ff613d1,1c81c4c9,fda3860,cbaa71f8,eab9ac3,d9263f31,55317949,d6ac1d53,54f683d1,fd382305,b2193554,bd3a6d2f,bfbb99b7,5d9c3e1b,876c3b52,e2bdef49) +,S(6fb3bc81,5ef3d8a0,d7aa1a69,dccbdfb6,3f7a58c4,7a12f98d,b09cc105,4306422d,798fe7ac,f9fc71ad,7023a8e2,c9376161,8fa632cb,ec607109,d28a63a3,9a4228f9) +,S(c32aa38e,bf0ec0ac,61bbea0d,d2c633c0,bd49ddae,d77179c7,e0098c8f,4488da8,e01f5fa5,1107cf4c,f4c1c5,78c3b5f3,a1baa059,90bb8913,9e2abb30,2e9e5042) +,S(ef5e1efb,d1ede40a,810434ae,833a4681,5f9021f9,41ef1d82,fb8c1399,16c4933a,94a9cd1,5f160c1f,4f85ec8,16fd1834,9cf19f8e,96ac9247,695ca37a,dbad6ef9) +,S(8e3aacf5,33de35e,4f923b36,c378ea57,7a5aa477,70ea6390,f92c73d,50fbfed2,49cd7650,ff69ed12,b96ac3b1,420784,7677497,b731e0ce,316eed65,7e40e014) +,S(84521790,204c64cb,e026152f,474b0da2,25703d93,25943821,7d66f20e,3ae0d06b,c1da2f7e,438fbc82,57f7fe4c,7e49b73a,446a19ae,775e7f1d,20c8fa31,edc3bd20) +,S(604cd900,97fe538d,b27cc2cf,a2d6c79,692f2e2b,c1b1b23d,1f0eb949,df560697,914d5288,29765538,d77f8e04,182c50f,d2d9aecb,2412ce47,4888d666,46b2258d) +,S(c13a44bc,9a27e241,5531b8a0,5570e66e,6763b3bf,a80e00bf,59d6124f,b3d67858,71557bf0,4c261c2b,19196d0e,9e459f3a,f629cc19,84f411,31835400,3a60563) +,S(14f3399d,5204b654,23d9318e,4adf3af9,dc43099,eb43b719,eb4644a4,897ffbff,13808cff,4c096655,72329034,d489433d,976cc011,d1a30ced,702ba4e9,5892422f) +,S(bd84d712,43dea7fe,f151b207,5d03d2ee,170488ab,4175965b,128411f3,f592a36d,57a1c602,408fee75,ea9e683f,43d7a984,bf03d66a,37513c50,5cbec6c6,6d286fc0) +,S(f319d4a9,b5f2c1ed,6619ae06,e5aaabe4,13a2a6c,265283fe,4a51c7ca,6c49b572,bd9d90c2,2a369a03,1856ca9c,86426171,db952537,edbb1ba8,93fd16ea,35aa43b2) +,S(9649689a,424ec9f5,aa4cf4c8,45588046,c50eaf9f,700d0412,83e02640,9a80c61b,5cba8567,95b0440a,53e0d1c6,ad560364,c398dda9,d2e97a1f,e594355e,1402fa33) +,S(45fe12f5,a340034f,381764b0,adf503b3,8026374,70eb26e9,6f4181e2,68cb1c38,ab7715c4,52e5581b,ed940fde,355892f2,b8a16a3d,d322123c,14a57a23,72f244c1) +,S(98bcd24c,3222401a,a4683213,5a378790,6c9812ee,989b8f52,fa522c6,d39adcc7,14c7cd38,7bb5191c,f49bbe41,52af8b03,7135a6a,bc7e4697,35a72a38,e44433a4) +,S(6dc56512,7be34196,a7653057,f79b854,83c275ab,65c05c2e,83663da5,31d7d652,a6839fcc,ba7db053,affaf5a9,4c95676f,9d65eba3,c2474472,cadbde17,2ad3692b) +,S(7a7f66de,b04492d1,fd2fb9aa,dbc4ea7b,ae5a3801,47b86e68,60513a57,eb6b10f,fffe4f2,b722f36f,1e555671,90d84d9a,39b819e,fb7a3436,29b83adf,f6045f05) +,S(aaf9f188,3865e2f7,eb500794,3888b4ec,9013371,f7162947,2cf52adb,bb5288b,df634c19,e7496b4b,478bc10c,7c00ac8a,5fc24dc6,4f193355,f0fa9c62,d6048243) +,S(6304b1d7,56988ca,25afb747,476acbad,2e5afa5c,86136090,c86a82a0,e52b373,91a2d829,2357463b,ea1a7cb,33d79be5,8bd71732,f1d2cc13,ba4b2724,6fd39f05) +,S(6eb17147,2aad3d80,bf4e06af,a36e37ee,5fed9c18,bbaa1c4f,5cd871dd,c526515b,6afd615a,e2512fa,70c9670f,b56682d0,f304a0c,6a23d1ab,fe958a7c,2a4173fe) +,S(9113b613,ba815ca6,43e7bf66,27dd71d9,8c2d40ea,5c00f596,6216ca9d,d32b1ce,8790dac5,bce4100b,8e4e5135,66a104ac,b55d3ca4,3d6ea083,d23716d3,3894de2d) +,S(5c7af38b,8821169e,2f7e2edf,18b3b73a,c387e6f6,a8ef1cdb,441f5a13,284f365,e12619ea,e2a07b8b,c55dda85,6cd37927,d448cf2a,f4028459,2e371e10,8e91358b) +,S(becf19e9,23fa7b4,1cca0efd,937a5b11,e227fd18,22743fff,80c42692,6631ff0,3213c209,9f255eee,93323d1f,b440cbb7,64e86f1a,4021b82c,485517b0,3440ed4a) +,S(f22954be,430be6ab,34dfbf92,264c2406,df3a0a7,19ed45a4,d09cb161,4abb0c91,a60397e3,ef3308a8,12527744,311673b,c18bc43f,352dba00,4dcd4124,7b84846b) +,S(c50ae8c7,61776e62,5156f9fe,7d863c36,79d43126,c5f3fee7,5b837a38,1803e770,be966bf5,99b67e6c,ffc421a5,e6d12e4b,cbde12,4d84eadd,781ea562,aac7dab8) +,S(c6c3a65f,e849c113,748e9b6b,c9a9419c,1a919503,36201a6d,f989bc5f,fa07d359,fc205b83,b4764ded,ef58082,11eef120,4d9fa959,4d5b7086,c2fa2c9c,3e56f37c) +,S(73466c27,8d5f13ad,dc7da10c,b8855c23,9069f57b,6ec5e80c,e27191aa,196d9b1a,7e7e2cfb,533cfe9b,24243cd6,7680ade2,35abddc3,d8d00faa,c8adae39,15ddf6a1) +,S(6315ac10,35eaf884,8919bb56,759f7013,92fe442c,771a42dd,dab88ab0,2fb0df2d,a49d2c97,6e0e66b4,50e8511f,d91f0f71,a7516fcb,70ca61a0,98f135ed,8e19396e) +,S(fa195146,fdb7ddbc,41daa8c5,98e1f811,36c33eb3,bf23dfc2,3f20b36,1c8e7bca,324fc70b,38677dd4,c8e7bd82,4b836d0e,738dd757,ca408ff1,95bdd5d2,bcb5cef2) +,S(ac40bc48,87734bd,51247e91,43e5e188,e5e2bfa4,2e3c0392,f39755f7,3952bcad,75904ebf,603c2f07,4eef9435,eb22c663,1279afad,94d3bbca,d5349881,7dc4a472) +,S(15b7e1ef,d2c41c6d,416b6dd2,5f6612f0,a0acb0c4,1b161b4b,c40c5ad2,a92604f6,a13da672,17501833,4c4057d8,85be8fb1,ceb6d369,6979b805,83fc0a37,bc27a0a3) +,S(adf4aea6,6fff705d,5bff3c84,93e8870,4ba4019f,ed550cc5,c203439,ff8512b3,53ad2122,30528e1f,4fee43c9,2369dca4,3d071177,3ccfff26,aa16a502,6206a3d1) +,S(da0d5286,fc261d92,1095e1cf,f67e729b,501f21b9,45e8d84f,ba2c80ff,335d105c,5632ce7a,e8d9ce7d,aac7cf26,2ef7bd27,418613c,b288e793,35a0a638,6abd83f9) +,S(463fd081,daf02794,18b95a48,bcb8dfef,3a9dc67c,2237d2e5,dded1522,f714d6d6,3de4cc76,7126750e,4038fb43,bf6af17,63ebc0b2,ef56ba8c,a376b815,6b4f28b0) +,S(15e37b9f,58ce033c,2f0ad85,d49f8207,2e2547c7,91c7ec52,a8606974,2badb586,38816873,5e37c957,c18ad56a,e7ab81ca,8fd89a2d,1710f032,54393ae,a046490d) +,S(2e121b79,765d4f4e,8e7aa8df,5c70e4b3,716b976e,9e4536c0,dbb3b5ae,4044a345,d7ba59fa,97a7d6b3,8b70ecea,312cb01,f9016b33,c160d1e8,d33fdf50,ffcbc928) +,S(8d4c7aa3,c59dede0,bc146b10,38f8f823,8182c4a7,1cde0d8,e17005e8,64ad29db,78aa343a,28a48f90,edd7fb31,849d6d3e,fdb4c677,73cb523f,82c0b187,2c17f44e) +,S(1ae12a1a,19a5d1,3b2f42c,35a385,f8302721,86a67801,c22818f6,94438c58,5cb421bd,990ddad8,16de9439,87bd96e7,e1ddfc5a,8d0f86f7,b30e3483,897815d3) +,S(7a6f584c,d48be9eb,a7b73377,8a173d5e,3833aed3,a603a226,741ae1f3,a1c21bbc,5995b840,bcb6cc28,b83d048,9faa5dbb,c6a93190,46b11b13,59827266,d177d27c) +,S(2dc5ccb4,8f78db2,3f0933f0,ef67bea0,53c7f2a6,80788bad,b71526a4,f55fe758,9e4743f9,ddb46206,a5449942,71743b44,713522f5,f358ab47,34c9afcd,f528736a) +,S(f7a5219c,75dc4426,4322bda0,3b603127,26a6b3aa,c471f42,a33072b4,a44fc9bb,9e1feda5,5da277d5,cb18381a,4471939b,a12c692a,a40ab965,fd03949c,d8124ab3) +,S(a1bc311a,e29e3926,5b3be1ba,23d7ffee,df0de8af,fba089c,fad797dd,8ba67c68,9abf66cf,109821c7,68c98164,b0598068,c4590d7e,b9ff4c53,594af6e8,e0ceee8d) +,S(2c2ffba2,e3fee930,fe8d061,3bbb8290,22429fc6,654d5ed3,61eb8720,1d6b92c5,ed89f28a,bad9510b,acf44d05,5934cc64,ac7e94e,2dbc72c9,986e6cb0,acbe434c) +,S(1d157e13,97f6b22c,3dbfe448,d1168b8a,bc963f86,bb3bda29,a8011f07,d2cb5ffc,bc7cfad1,e1633419,cef1c82c,d0249ee8,4c38b3f9,d628337b,aacf0449,4ca3c0b4) +,S(1b9e9723,56f8a4c9,5e8d5fbc,8e2f2cc5,99c77d62,90b2fd44,2e63b3e6,dc33c772,59db6eef,988386fd,21e8a772,a1fe048f,95ba77a5,122253c0,1a52830a,bc12742d) +,S(80460a3b,16fd9ba2,250b07fb,c77f2526,bec5488d,7d6c45ae,6f480308,39af48fb,bc7648a7,744347ad,e17da2e0,5cd1ce10,db704acd,26c81fbc,db251ff1,c6fdef10) +,S(c6903a0d,d8c26c8c,cdb675b5,972aa050,6912813c,a6f0c8b0,2edfb792,491222e7,f4759b4e,9db7f1db,7c8a1c38,dfe76d86,c3778423,29280aec,12b1be06,d8e49ff5) +,S(95ab78f3,a4268c8b,39aa645d,8c9fbfd5,b92469b0,809d6369,3d57d076,d305a241,8df4c8d0,ed85ac01,a965d580,78f36a5f,690aaa03,d9479d1,b2297a52,53e3c6) +,S(bafa3ae4,40a4b8d0,40862a18,cca806fe,8cd0e780,483b396e,41543486,db91d9b0,d7bd60f0,c0ee0b8e,38aad85a,85a42ede,56c66d54,ee73d371,a3bb7cdc,e93df670) +,S(7cbf5d9e,3bea6864,b87ae157,fee6e352,dc3a4f32,6e7cfc68,377fd199,a6dbb71b,42d082e7,5d55eb62,9771942e,3801c27a,fd80b502,a997ccc5,9f5a95f7,d7276999) +,S(9108db63,751b8a9e,f4870524,f1198f9c,c4d3ec20,af54119d,6011f263,de13ca29,8c1d6c47,aa016e83,d2c8f76c,df0935b1,b6f909b5,bf5c90b,f4203493,22c711d2) +,S(a705e7eb,c20ac4d7,43be660b,d61340c,9629d069,1b08ef01,a59e78e8,2d8b347,1ed8ec9,13ba19e0,851e1912,5854433a,f71b21d8,df64958c,afc5d7aa,cd29ccfd) +,S(b75483e1,60144d46,78af9a3d,701c4ffc,fe154c49,fad45ece,3945289d,c3781c3,a4c0455,13cfa7fb,ba2931cf,722fc569,87b2c79b,c4b94313,5a458d34,5ee16d57) +,S(c59aff26,bd4fdb9,37468989,763376f5,64abce,c00d54e3,45b6dc2d,9b7b76cc,c396c194,db446fb1,a22e86e1,8a37981e,d114e675,474bd24c,784daa96,91eb15b3) +,S(2f6701c7,815ba7c6,37c4649d,d05a31d3,e909d8ba,931e7136,1e0662e,3ea19985,937eb67b,9262bbd5,12a21e90,393f9e65,66e03203,55c77afe,cb98d1f4,bd25e8c3) +,S(170d1e33,f0862542,dc72b1b2,950ba98a,812cc308,74ecd0c9,23ce7c09,ed7cf9b3,5148ef39,68ff35f7,a633ba7,dab6cdaa,54dc6f87,510f1a7d,4d3019f0,c00bc868) +,S(743b02d,b02301db,453f8694,cd517c6b,433f609c,e205cac,6f6a49b8,55890708,7af6350d,56130339,1a9ddce5,f566b9b2,9c10d535,d5183850,6c743124,8dcd707c) +,S(ba6df8bc,f9d83988,4991c6fb,e0aa0ecb,d0b6cdc4,d0e372f,3ec83b51,da6a6570,7d27b176,3a01a8bd,fb7dbe0b,226dee6a,73ed3644,807ca33a,1f5fee61,cc161fcd) +,S(d3b63a2c,364f01db,6a6f384b,4bba6c2f,2fa46a02,86090826,1c8b5045,4b92ca5f,df6b9cfe,fe7aa14,a38bc44b,8b627b6,e0ceeca7,1720d630,cc4fabf7,b020e2d2) +,S(638c2b1e,374ff6b3,4b634f4c,bf363bbb,55d66c8c,af4d3fed,43cf436f,a1daa7f3,9854873,37b48f32,4feda3a1,f267dbe8,8831aedf,d7bd36c8,6cc8d862,857507d7) +,S(1749ab4a,607d7864,5c4cbd30,4bc34c06,94a7a636,9c8c8f8c,be4602bd,16c4b4b8,465bff86,b459b842,dfae4df6,99be1758,8b1aca97,f9802827,d892792c,748ac92) +,S(9071a5ff,ff23ae4e,2d81b2fe,d341bfa9,cb86ae6e,ed32870d,d549af20,a1db9feb,c0e3d4e8,277d099a,9801ddf3,3e513aa9,1761218a,967d530f,21d70894,ea7d38ab) +,S(91bc0055,28e2d857,ac644954,242fe0c7,bbaadcf2,9119837e,898244e3,a305ba6b,6fb63758,3aefe600,46997b88,315d5a24,683ff955,94398694,be304dcd,8b588f67) +,S(9663913d,48c865f6,312fe51b,6e8e7c6c,51ae397b,d141aaf2,df3d6ff5,edebbe68,c6251751,7e24d81d,b1da26a6,6627fbb3,28b5f818,6477b34,43f7c36a,918753bb) +,S(e88e8702,7843b941,61c71887,9a0a9a90,cc0d6dd3,8329c73c,a18acca4,3f44ffc9,7e31ae63,1f9c927f,bd055f58,e682935a,3225e778,9221a062,f2826d86,97143a61) +,S(5ad27e79,dee03a52,be771a9c,ded6a02a,58337f26,be810d1a,f8cc5ddc,f1eeb917,91c18e01,dbee34e9,a5302a7a,11bfa7fd,ac852e1b,e53aec2d,3138259b,bb53e6f6) +,S(bb7f4694,f2935a5e,8711ae47,bccca550,cee2632,4347b468,58e40c74,49111ead,d9f94c14,332ad75a,59dc784b,d674e8c6,146a2b74,566ac1ef,b0ca17dd,9eec8d74) +,S(ff77ae06,e0624cf5,f6d905ee,b0de7281,5377c026,3e01b6c4,a139e4ac,3304e82c,1f27acf9,933d08b6,f0892199,11805d14,1611a318,661e6e7c,75014b84,cc35c395) +,S(84c15fb3,1b12d39e,ae59ce0d,f8646e9a,67c85492,8d6c498b,4b836be2,eb19a060,6aea0d78,d54090e3,2216c3ae,be0dd433,a666e67b,44cce0ec,1609804f,fde33f74) +,S(9a48086a,8bb9b150,a6ccb966,3978f555,41db6d48,1b3d5266,e958cbd1,df9ee7ab,d8eb2109,13ee09e7,b5767661,13157905,b3cafed4,641903b6,da0ebc08,a0ce2f58) +,S(db32ad19,45f4d9f7,eff1b8c6,b87c5545,1b0c74d9,8f1c4ffc,6ff1e79a,21ab3033,2d56e65,a70bd23,617f85f1,4a5d0e4d,52aa6a70,a8594158,36d02d87,309c7eef) +,S(4de7f1aa,b9089f5c,b6d95b67,a04952b0,d4696cc7,6640e1da,f4bbf7d1,da985851,96f2cd33,5fd4b816,4499ddc5,5e81f5ea,c4db4399,17f2151a,f86d2ad1,e2b3612e) +,S(74bcfa73,5aa43e8d,1fb540fc,9922362b,21878c09,666bf541,a0e739b9,dcbfd1c6,84b26fc2,8b2a05cf,a67947d4,99c1ffe8,f94ed4d4,6ba583b7,cf26ee81,ba60bca8) +,S(9c596bcf,3d2e1df7,cd8d9807,8a1ab17b,f16e27d8,66cfb582,ef58498c,48ee0fc4,14dfc093,48f72d7d,af9e3599,8b5f18bd,5287f3f8,381308e0,63666028,dda9ac56) +,S(8e2a0d3b,2786d67c,a15cd72,4f2cc6dc,16cddfc5,cf080ef8,d9576b2e,e5b0ff9b,2ec4853c,c83c72d2,68555129,ce30c836,50fb59b5,17a3d61d,56ac4273,1b33ad06) +,S(25ec4838,5fee8fab,773498dd,85a23ec9,46c59839,14fb8a9f,d1239ea8,ade3f829,123bded6,5312030e,d4760047,1867aa4d,b7537239,b363b6cb,58ecff98,44986924) +,S(a1cd9872,7551e2c5,db7985b5,1698b97a,31b90d3d,32fbe60d,34f8ec2e,398df76e,40858565,aef814bb,8bd91fe1,410f9556,3f1bd170,345c1283,b64fb268,4980c398) +,S(bf7d3973,aae2cc31,e831390e,f2458e85,9ed6847,e9eefd6e,cf91e3d,4a4924ef,c2829fc4,2127b303,c801605f,35602b84,32357564,d9333ba8,d962d639,ef21a6aa) +,S(5a5299ef,e0d394ef,f4b510ba,96dc73bf,6332d358,e276bddd,527ec290,b73e3313,9ccd4618,17e18104,d324e1e8,1597eba0,cb6b475f,4e5f2e02,9cfd2d63,b613de79) +,S(90efd8cf,9e4b9d74,5cb36c13,20a8bb0d,b5cb8578,de49ea4b,c289043,e2ea810e,87a73339,aaceed7b,af47b5eb,97aca554,d80a4f78,d439ee14,4b2d0fb,f8df5e3a) +,S(3a174294,4db7f2d7,2498e2fc,e2026d5c,f8600ed6,958db97c,24ac0de8,417f6def,e60c566f,f3fd14e2,2ff0cdee,45c4c2,31797951,7aa0ca68,af91a5,e41f5f60) +,S(2213e0a1,3679040f,73e4d68c,bb941665,6ea83640,33abac76,2e64d509,48a97656,2b87ce0f,bec2728a,aae6586c,bc6d9a89,a4bb9b9a,211de522,cc909279,5860791c) +,S(382412a1,ab396523,8b06c47b,e941051a,bef3b215,16efb280,3ff3a1c4,824954c6,7cae8b14,1938312f,ba482980,ab9073da,c66c1ca0,d746231e,8ba8f331,4cfd9cea) +,S(3d76bfac,89c1269d,53b6ded6,bf13c785,361b1fa3,84be2ea0,d582ee43,f06de56a,18b1cdbf,96d12859,bf887b89,6d8f2e6c,a08b892c,688c7687,8294974d,af6d6284) +,S(715b18a0,68d86cfd,41a20541,847b36a3,ed7814c1,b5528751,927042f9,85e7ab70,2b8e0228,b0a4d39b,85a3d3d4,f5a10db,c6825659,f4b967c,361da449,24890911) +,S(a31a10ea,e38e6a00,ab4f004,8b45c8a3,e57856b0,d0b64e47,fa90e234,e17943f9,5d4b5150,7d3f3a82,87e5d51,6bb30b89,2cb9f540,96aa5962,1f77e028,480e594c) +,S(b397f965,1dbbb6db,34708066,a1743511,d4a16332,95f53772,72c43a6d,6e21c1b0,673fd327,45bea2fa,748a759,30679b2,471e4004,423dc8b3,f34f95ea,f88d2b8d) +,S(2e4b865b,c1245325,1ad8b3f6,e8776bd1,a5878b93,ec34f847,65af84fc,146d9919,b3e7d479,661ce034,50094432,c538f55f,c8be8693,73a91fd0,350c8089,ec0d76f) +,S(9a38c790,7c0751e5,ba750bc3,485b4a4,72b661c3,63a3980e,feeaf59a,98533a43,dad7ac3b,65493036,d30068ca,72808000,d54b42d6,d263de93,a1ced3d8,fa82ca71) +,S(5599d251,3b3c8337,f8af18ea,70d1d2e1,83f3e363,63735357,2b3f6cba,b4371d9b,7ccddd9e,ec8dd507,69f6f633,cc70488a,6a4e322a,2716218c,5de50fae,45398dfe) +,S(610c472,4699e983,530e8a32,b60a8077,c7f60226,cc3b2010,e49b2e30,f2a98afd,42157de0,fe6d8e53,17a3f565,fa450f53,8755679,6d98c7a7,ba0b3e96,844d25d1) +,S(89c082e1,1438e2b5,6a4bff8b,cadaf804,c9d11fa0,8f47bff5,39cd0741,76f24a59,f4dad4e6,19ccf814,e899d48a,904a88e0,6db6ab19,a2e06a7,b359db9d,cd0ad0ec) +,S(bf810fed,48d1ec4f,77cf3732,ed10a44,df9e4540,2e1a1e1,6b29c82e,32537565,6657fd30,337e294,fa31d30b,409b426d,546a47cf,38cd23bd,75aafaa0,b527d66e) +,S(3b1317b8,bb3c9c91,964ce369,19ea811b,90a8bd5d,ebadabc2,d4d1af3b,50fb3524,cfd5988a,78aa555b,595531f6,5fb0e3f1,e756c1db,626cf60b,4c1b17e6,caca603f) +,S(88520439,61558d79,7b084143,783d9e03,791e6183,c932d1a4,17eed30e,bcec0bd1,271097c4,4c723ab1,c1d13e9,93b7b232,235957ef,f21a13b1,2b3d302a,ed46ba1) +,S(6c420c30,343cf500,da0cc05a,c315d3c3,45ed8aa8,e0551bb0,32fbc512,732f34d7,fb3c0808,698d38f8,3310fe1c,15587cf7,137bef2f,666229b5,bc789dff,1b2f1111) +,S(b12e21e0,e060fcf5,580d75ef,22e8a800,33e2c19,487d0660,615f7d51,ba00e430,3931d63c,a6e0da2b,295bd22a,4bbb27f5,fb52d89a,3c4ac36,795747e6,e74ce944) +,S(4fb9da54,4da95655,c0de5654,f68c2820,a7884734,4bad6934,e671d56,e7bfe11d,16586701,9bc89b28,f5fdec40,78a2a51d,6e087ee4,29456cf3,d258b97c,209d44fb) +,S(18f8f6ef,23bf75f7,a7811025,5babbeff,792109ca,5a550472,245552e4,35588e7a,e712abe6,3a374f25,fd4b18c8,4b1451fd,ea77692a,43c0e3b1,cf3469fc,7a9acd55) +,S(d730d167,1bd36654,7188c07f,78d82ed5,6775d7ef,bd0967e6,1abddea7,7ed6073f,49c4bf3c,ad4e31df,d840045c,aa8be15e,43f90196,818e30f7,b379c74c,1d866553) +,S(a915fb72,7d4c40ab,547c983c,24a4f019,1f5e89ce,7ab0636,e903aef7,592208a6,fdf28a3f,6557f27,5813ccf3,8d927f40,b910c5a9,ddc3c83,14a48eb1,6a5956be) +,S(7abe8d85,bd95c580,cd9d532c,c1295f5a,ad5168d7,e3dcaf28,b19f5e76,95107157,694abe9b,9a6ed0d4,c3ac1db8,79b49038,6fe9d2f9,443647d1,91533fbf,aae3cc02) +,S(93a83e8d,c80c7cd7,64dafff1,edd148b2,9c336de7,cf978b14,fbd35625,c965942c,91ea5775,db50bf9,a7e3f79b,77c7d5b2,deddfa08,a1d455e6,fa21e547,356c634f) +,S(a334ed87,dfd2e1fd,699ce1f0,a09fe921,487f8321,6cdcf75d,fc8d7e5d,cbbd1af1,42a0874e,d148bd32,ba4324ae,eb0260cc,7f0d20f3,f43388,38904640,8f7ae7e0) +,S(811597c1,f4129ac6,e150c231,bfd8e4b8,4ad441ff,2c698486,affd4ac4,c22bf8b5,5f7fb47e,11b476cd,acce1552,95ac000f,3acb3838,6ad3c6ac,191dc12b,d1e299dd) +,S(cf754ed2,47c9eb9d,24f3129c,4b4cefd8,94b5e58b,832f158e,2e82911f,8177a59f,262cb605,2991777e,bd1ed5de,d2e7ce29,76dd73d1,ad4c9bf4,9fb5d8fc,fbe4a3d1) +,S(290ec604,a6b4d816,ffe75715,419b0f33,452530dc,94f48883,b3982161,4592b229,4235db3d,df2e3f1,b61ac412,a90f543a,ddcd519,4f4a315e,d889b32c,ec8f76e9) +,S(1f90b869,4bf9ffb5,7697ee72,29b7f20b,52b47997,35efd7f4,1e4b9102,51886858,dc3d7a68,abaf70b3,c84d533c,48ef38f6,9be7d26a,13c4e834,5a7bee29,c6d3c87a) +,S(ea20b4c0,931087a3,44d5642f,6c018aea,2da5f189,a4d25968,96110281,88545ba4,f9adfa96,f945e745,88d2ab41,e32ef5a,76b370f3,f0362e57,129c3998,e32cedeb) +,S(b8bb88c1,21948c01,3a61fbf9,bae86eda,28e9bb4c,6870b0f1,7109e5b7,c00cf4e1,90685129,8607d7ac,25bea5c6,1cc4feb4,4148e07d,2fc3fe7e,449773d4,8245019b) +,S(2345a244,f2f411f6,ef091904,81eb9083,9128f7d8,67e8b910,124d1e44,d116c529,a8eaf530,c69b792,d6595967,4f23b9,b0e239bf,b69d05ea,466f9f5c,9bd5affb) +,S(75aee824,38bb03a9,b9208cc9,b725f13a,1fee1aca,20ed129e,e5ecdd59,b92c89cc,fb6bc8a0,fe0f684,ce4cf153,2053312f,b97aa1e3,739fab8d,407db39a,737ee51b) +,S(ca46d3eb,c981eb1,764867,c99cd7fc,c414bdf0,31b2c9a8,96829ebd,f31e2e36,46363355,862a64b,97541f7a,7fc5cf51,ecae168c,c6530db5,3a7f2394,2e87bb96) +,S(4fc1d258,575c4830,bc7a03d7,6a259406,7d633e9a,da2c734f,45ce4d9f,99dbbe7d,cbdc616d,fed2bae2,9312c5bd,9e195bb,bfdeb2c8,d1aee5e8,cae8fa0a,4bd6baac) +,S(4edae08,54365c27,f6ad83b3,8f68c7d3,f0a09c6c,153791d4,df98b5f2,3f0b9be,cdc8a485,8ac66847,c732a2c5,4be86af8,d6d637f3,e62c7802,dd71c7b9,2eb18223) +,S(624dca60,16beeb28,c35bef5f,e97d320d,d725619c,3faa7ca5,ed79d491,72b12469,cc33b49a,6fd125cc,98d65a81,c0713cb6,2a7e687,276e7fb,641e2f76,52646c12) +,S(6738d38e,760e50b0,6a18a9eb,b5e3676e,c38f3487,e34461bf,2e5d52c,5bbd6b4a,c3ce0343,9b9f624e,a92eecc9,860ff680,63a907d5,b57c43e,465ead5b,bef5e709) +,S(bcb74527,10f178a9,eb48655e,3d373b56,8f02036c,e9ab826,4ab7cee8,52f7f9c0,4e928392,52ee05de,587c91d4,6eaf5e5,92ef41e1,5a2b5c2a,da9e4512,c25bb416) +,S(3375c7ca,1b5fb4d1,1838ffa0,c21d7e03,de34ca5c,92bb4592,bb4598c4,2b490382,8c284e32,f016d186,875b87d3,3bf4271,4b9013c8,ea159634,b39b7365,7ea837de) +,S(c347409b,336c0677,ee95de61,f93fad4,738268d5,6f31059d,380af075,60e496bf,37dfcc4c,c13bbfa,5df43c69,eda0c68c,42de70d6,ab64a9db,a4ed22f,1cec3fdb) +,S(305ea4ad,ce72ff73,976544d7,a3deb346,452ce997,f280c3a6,106b7c9e,3b9bf5d6,bfc33cd4,ca178310,c4caba86,5b87477,77e9e572,4278f0f0,56b86a86,1f2e13ea) +,S(8333f714,70e57841,312a33bb,4f1463df,d237651d,fec4e1a6,40c0ebe7,478c5a9f,d39b03d1,11657c2e,19ad78d,3e1208ef,f8505695,1bc67098,b891c42e,b427bcb7) +,S(500af03f,eba3b646,a0690f0,74cac255,804c8f8a,c2aaa1f5,f5cee4e4,41913e7,5e67542e,8a8f0411,e9985a76,97ba626d,f0607f66,9f9c11da,826b47b1,a52cfa2a) +,S(e440385,c16bc15,5023cab3,3e7a48e0,5e7e0c57,e0fe848f,26b146ab,237a3abc,dd8ac982,b627fc9d,7fd83c26,51805de3,d7369ef9,2e970664,8744badb,3db060aa) +,S(83eef59b,b0a26fa6,60c94e45,c097bcfc,8622c37,cec46eb3,f9e93aab,d0fa6438,8b51311c,ff685570,d9aa7a66,5b47a3ee,b6bc05c0,a2709421,c73ef814,bc703723) +,S(930cdc95,f723a7eb,d698c1f2,46692f39,e1add95e,f8cf84ca,171d4700,2a7d759c,ff161a2,31fc8964,5bb6dbb9,f595daf4,86cf01c1,944021ff,6ff793fc,2613bfbc) +,S(4f7cb0a2,c83f3520,86085b19,a6e5ccc1,b0beb700,35637e6e,8a79fd78,337c2616,aa32192b,82831ed,a9412f4d,6ac6d148,f68ef492,5b438cca,12a73b37,b4a8fb74) +,S(c7238fe3,17590be1,d8403ca1,3eacc6b1,71cccad7,e2e8f659,f11357ad,70590424,59079180,90bdc74d,aa06abf0,940519fd,d09f24b8,88c15cb,a632b814,fe8910fd) +,S(c6afda17,e6582427,95cd34e3,edefb600,70c73737,2d99f6c,b2b8dd3c,99874880,d805463d,15d185e8,b4461293,b6e6f6fc,a0b58a49,eefd4d0,11ef48cd,da5a16a4) +,S(4a14de26,ab18ebc3,414c6856,1a77d62a,221821f,8c216496,700bfbb8,21d95b2d,8037ef39,d1f190b1,a24078e3,e554ad1,cf86d5cd,f731478d,b34b6b5c,c9174314) +,S(cbcd6696,547fc496,8c6e7ba5,4caa4a74,43764852,43f479e5,558e2be5,77bbad00,8e0099e8,559db5d,dba0bc72,21505ef,d42c1c95,876539ab,19dedb2e,8e561482) +,S(37f168b6,4b41be85,46abd1a4,7a5ab3dd,5d690661,e41b16c3,87025106,caa4e2ae,8c617348,bce3bbf7,54a121b2,37342794,5d734e38,da08066,c4de59da,e60b5c89) +,S(3aba7081,55dbb35e,dc4a3fd1,1db54446,a7501ea0,d67b0286,8d2e6d77,99162697,829502c4,2dd1105c,cb046e0d,41cd68b4,38437394,b93f17de,5534f014,270c4602) +,S(84842bf5,fb46c697,44eca720,7b1be6b4,e5f5809e,eaeb3e9b,1058eca5,4498cafe,f4210fd5,b49f6484,2efe3089,327673d7,95642ad1,73b6840c,7323b7c4,16d61fb5) +,S(88383dee,ee0db44b,959edd96,feec2bdc,73d6ab56,9333fb3c,d4b18b01,ed8af5e3,8f0cf362,7aba3ceb,104009f0,baf84ed1,f57402e,fc330f10,6e0b45d5,4e0626ed) +,S(ad0a97ec,2197c5d7,4e8eb9bf,9798a24b,aa7c3e5f,ad6ac263,1acd5109,5178d8f9,72b352a7,445db832,2e33c93,5619e7d3,266f254,64a4c4f0,96051ebb,1e37065d) +,S(9b727e4,d107418e,1f62b499,99c1f8ec,55ef6e91,a9a10ec6,8905be97,33903d85,27d6456f,5ea52aee,a190dc81,647ce31d,15ac8c36,de65685b,4784eaad,4a32e41c) +,S(e86bbef3,8d740a44,7a2cb0d0,a89c2106,d85299f8,c38fa540,a7075efd,3a02fe03,8a9f75db,ecc532b6,ade5be9,b855a27e,185895ca,d6a6549c,f6c4c1c8,7e151b04) +,S(b72ac468,9209207,2cb735e7,d424a18c,5ef097c9,3a9b96ef,1ab7e29,d0f379de,89111544,27b03712,e2236fcb,12cbad35,98ef794f,b8141913,aeb1ad8d,ed9e6467) +,S(f8f5819b,203b2bfd,ab2dc532,53277103,2f9caf34,c53c7ec7,7253b314,2e731ff3,433fa831,3dab76fc,aad5bafb,12362126,6d8d7c09,9d513ee1,1b633c6e,e3f1e96e) +,S(8e4a8890,a15da3a6,c14d2df7,d09f6157,d5dc95f7,4f9518de,8aecbc4d,c0ac62f2,c06063ce,1d3c2a24,2494a1cd,db381513,6200827b,78ed080e,3cd14f4,5e545acc) +,S(b1f6dbe2,ad730748,f906d1d9,160996cb,f3f2450c,fa656856,e34f2481,40767081,ee6b2a03,3f3245da,76d01bc6,e61afcc6,94a9e64a,4f0256bc,62acb5a1,82e45ae2) +,S(2139dedc,a8365bce,b9c49cfe,3834e4d4,27a46750,d6b0f0a3,4e7672d3,d12509b4,b20a9101,b63be2a5,28340f58,893e10d9,d3c63fc7,77b5c6e6,a9a67193,13725870) +,S(da3aa585,85c00e41,87db0240,547ff665,376aebea,a24e5aa6,67d477f3,c4d3b914,92405390,d255ccfe,a6bc7dad,4fb1676b,c741e530,cebdaa3e,669bfabb,d1c4780a) +,S(89c47de6,84e1eb9f,a5828e65,dd17a852,7226a75c,3d113102,97f5b8f6,5b67b210,970bc229,d60b00a7,c2354a70,37ec8569,ad615faf,ac77ddab,f5847a09,c1fa57ea) +,S(48ea67ce,db716a95,6b6066f1,e5e9fc71,5994a4f6,f4e2cedc,bf0c09f,4f8c8fd1,513e45eb,159f9865,5ac821d0,e18f4e06,fa3cb8e0,9d45c3f1,8d3c3bfc,48ff3da) +,S(c5ae6651,ded2c479,a3b6c9b2,44fa35f1,2eb1eaf3,fc78b529,42ffab7c,4e33a1cf,ae6ad807,435d4a9e,e8bedcb6,3bc804e7,e67e9418,6494bc8e,384b29e2,31af8cb2) +,S(24e485b6,7c27af76,e18ed116,90c9dc90,73a0b80b,e93f5381,6669e2d,3c0175c9,fcb183d8,696805be,789d83fb,a197fd24,996d3542,b2f3eb5a,c207950d,f9c079b9) +,S(3bb47a19,b1bdc527,a8fe262a,ecee2d7f,1e772627,e5cd5c70,eb2a8c39,f1977628,2d10cdb9,91fb5042,905f822b,68846390,a922da1a,7b7b313c,47edaa6,85217fa3) +,S(7d4233a,cd50bad8,71e0587d,e10204f,6013a784,b65b6540,73307364,5f3078da,be85d3d,dca838a,1f35ca11,1333e943,fb498cdc,63258ac8,74bd6acf,2b934b77) +,S(b5d0d791,b6685aee,2f599505,d01bd3,d41d5a1c,531ac7fc,e6c33b97,cb0ed264,47fbad30,413084aa,619d7bd6,62502cfb,9648e64b,e757d6eb,24fd5e2d,6b1629) +,S(bd6178e5,b1c558ba,432a89a0,482585ca,40ea9922,7c94ce,23f5b081,d606c7f0,9cdc6bf9,d32b98cc,73bad7b8,c08914dd,b9a8c937,913eecca,fff72dae,fa1cddfd) +,S(13ca834c,a5f41671,ce7f0978,a310420d,6a82fc38,fcbd997b,88a1e79a,66fb9375,ae32a0df,7f269c8a,744e409e,16ec3d8a,eaac151a,99bdd7e5,50287005,6f48f6a) +,S(96322802,87add117,4040f802,ed5c71c8,5f924398,1ee78480,4f16e5f3,f0fecb6,2d07de71,cfda4b43,44baf838,7933a372,3d536411,7e4c0f84,2b402156,3f9b56b4) +,S(961efbd2,ae687808,bbe275a2,cba1769d,4ca537a4,1046c5ab,ff269c1f,b9477ad1,9d22a10a,294666eb,5c816bf3,c4dc2c44,d7836202,e15bed89,e3d28822,8193251d) +,S(4e7162a3,8926282,84ac4df5,88301fc8,5d91c869,2fb854a3,ffd34c47,7b216ee4,6e6dc88c,d91b9702,cb38cff,2d6a38e1,d512fb46,9d85f878,8510ed97,2704ba27) +,S(6c1f707d,51b1d3f4,ab261d52,6d0106e4,3e0a5b1c,76a59868,62e9d97c,bc6e3e38,d2563843,5dc8b102,c8f4ee13,dc345f85,289cd499,9bcfbe20,1bf3dc7e,7dae1f74) +,S(3ae98e6f,49d363fc,8416f965,4e57beeb,d37635fa,4e78d8eb,77caae69,f2201798,ffd95480,fcef0686,9ee781ef,cd2693f0,e6be2e27,f207411c,39a18465,4d2c3cae) +,S(eaf94fc3,fae4eed6,35382e91,2cf963da,2bbbda8c,3197e522,e0054cf1,4cdcd5b8,a838a439,3d4bc0ee,a57e6235,5dacfd97,7d70afc9,16e61209,10d13fad,7c1c22ec) +,S(7eb52e7f,bbf5b802,2fa6d66d,801c3632,2c195b6a,4eae4050,5295612a,a184e2c8,b4591e5c,c66521e1,b991f63f,456306ce,cb2e7568,5227788f,a2e9a75a,bd58b384) +,S(d22b8dd1,6ff24603,5fda0ebc,77129644,a8469373,99b2c7a2,60d8e985,d4f2a215,7a9a092,e8473776,6718e2b3,9068e163,e06618b1,6d6bc046,b33e2d76,8649611f) +,S(8f6eff05,f746f0e0,9b328ec6,2089e575,ca64175e,d950ae4b,c67a7ce0,83afa1b2,3681243f,ca51a6c5,7ac92100,f38df1fa,d1093fd6,ecd53231,bfc01fcd,89e38305) +,S(ac9ba060,ff520335,9a4111f5,c8c536e8,e27a79d7,33528ef7,9da7b21,36243a07,2ba3cf76,3dfc0860,ff3333bc,e660ebb9,c4e5a988,909880d4,1ceb4219,89f23f77) +,S(d6896830,62bec27c,815191b3,4addf36a,cee1cfe7,475d34d4,d83a83cc,6dce3992,9f038f46,529fb86,30b19b08,db11c630,70593570,70bc51b4,fc1ced24,f43fbd00) +,S(e815019a,f6923eb7,cf963f2d,476db569,bb04cc7d,78a0bbf5,3b422ee1,caf43b70,984c16e6,593d8642,de871694,800ca14a,a103a61,20b91c17,4e06567e,2d731c95) +,S(3670e86e,e9aaf036,40136ef7,3344152d,c792c8d5,a064c0eb,a511e14c,41d6f7b9,eac7dcca,e491cbb7,cd27a522,a7db96cc,7d300c35,7413433b,9bcd430e,152fcd33) +,S(3d03f819,4802149c,c6428aad,851bd879,189c557d,cc9ab1ff,8e2e4cdf,f0723308,1f56ada,27f2c923,27ed2fe5,88d8736a,fb68259a,1d5b1c14,7f85669a,eaf47615) +,S(bf2ac011,9e417837,d4815c9f,74351869,4395ae40,77429013,7aab32,980748c2,17a47bb9,6f7a3e7a,31b5a8ab,2adc9fe8,98fd94d2,9ea7c3b4,a5b6c5bc,9c367ac9) +,S(c72eea14,ef09c0e6,85c22840,95e73e0b,6aafa64f,9410eb0c,97f6ad4f,64dea571,9a46c93d,256f67e4,1ccb609f,4ce94390,df9c91,38a9d2db,9b993456,13346031) +,S(25463446,6da168cb,2d816bdc,3c9e3a43,7ca3463f,8c8a83f3,62704996,c1bb5b96,3d69cc73,6aca2a,cb97e1a3,cd57be14,243e458b,305df59b,3e3a67f9,fdc17b6e) +,S(b40dbb03,7062dfd7,7151013e,7cb0a921,15096a04,c39f7e2e,66188aaa,368c49d2,34923fac,7b1a4570,e824c3c5,2edd775f,ecf93573,2198f801,8f617db6,474fb519) +,S(23fba417,ff084b42,afddc4a5,c070305b,553ed7ce,1311e5d,4c1f7b2,772c9aeb,af4a342d,f9346ead,89b3caa6,6a3f187f,96f2b470,c0a26752,76e895cf,c5ca4adf) +,S(2e7ecc9e,d4f21af3,a3118799,d1ab7e3,a30d011,edc53e33,93dfdc5,6e80927b,b3959fdc,f6c4876,36813bfd,e7e83b4d,7ee0f1c3,54e0491,f3195b4b,aee2df72) +,S(1c68c34c,8aaa0f2c,7daa215a,961180af,3938599b,1324aec8,7a1b3841,710db2c3,d8d68179,71acb598,5cceec45,fc5a754e,e002d09d,4be45e8,ab6d2bdc,ad094b24) +,S(fc0ff082,ca6708eb,9b9294b6,fabef142,2cddb5a3,611dffc6,f06c05e7,f1eeddea,6f67fbb2,df22611,e2f1e796,c67d6c3d,14b17f98,2b6e39a2,7bef257a,d6955b70) +,S(fa683ae5,8dc85748,1a7ddedc,708865b9,267e9fe2,e485a243,1d005e47,64130548,4d9759ed,76326207,891a9649,3b4d2307,b9694fe2,c15e2327,a79dced,db8277e2) +,S(3cfead76,5ef36c3,fa9903bf,6d43cdd2,46ee8fb3,3fa1d13e,42fe9818,6d299009,85a18ee1,da24ebc7,3dd87aa3,ca1e7565,8f868fec,50225e2c,d5b5480e,cc0ccd49) +,S(487fdda7,364dacf6,2fcec7a3,fc2dfd27,c38079ef,d48f0220,85c62746,2c8ac658,1479200c,b06440a7,186a946f,83a137d5,7e5368b6,7ef8a66a,9540a131,e4bc9b8f) +,S(f3e413ff,81c2ee72,74c079f3,451f41c4,bbe1e51,f7c3a1ca,513392bc,9edd487e,46544553,79a33a0b,13fe5904,504cce47,55d0e2e5,6c4163a5,14d5b902,906caf54) +,S(d93692b0,53ad5194,b70b9be0,1dd80926,e2c93754,328b3eb7,bc85c45c,63e6258d,7221837b,3276bd2f,9ba0981d,883cd68d,97d2ce77,9dfa1073,d59b01e5,df311ec6) +,S(e85af4c7,42fd5424,2964eb26,b531fd77,550d3b2,eb64bf39,e97de203,ffe2d28,8368322c,e40ffca8,49ff1a53,76cacb17,98fbf4c4,38f58690,54dcb642,f805b9f1) +,S(9e4e35a2,d913a2e3,bc931c59,298ef6bb,3893b086,ee40c978,430d8436,49fce4ab,ccca94d7,d4bad95e,c15b19e7,9555579,d47cec60,9f42112d,3d992035,6d31f7be) +,S(7d72793c,dcd78afe,23e8b000,41d67983,6528b1f2,6978e262,4d022416,7ac5e741,1189804a,2558ff1f,63a7ee1f,ad5f8ab7,50a412ff,a83a9783,996e5f26,637100fa) +,S(3b8dd2bd,ca65d7de,6a7c55bb,47dd5ef1,5ce6f533,96ab335c,84c0c9a8,4e06a7da,2ac78cf3,e1baa981,b27dfc9f,e1b7cd2b,1ed4c37,f96af6e4,99bca1f7,de62aac) +,S(128aa84b,3d920356,db64bc95,b52d4c8f,3054cf5b,22c6039d,1d21ea60,b2274c44,5a748932,6a98019,824a9d7e,cbea2de0,5ccbd9f5,a2cc5dd3,ee0b3dcd,a92e8758) +,S(de8b04b2,c761b876,4c41c344,a3b57c41,fb62e6b4,ba25ab19,8fc2ded,2849e151,134ae148,d89de734,a222b656,b878fedc,886d5928,fc6bfab7,bdd0a74c,3753f1fb) +,S(f643025f,9fc3824a,6ce70677,23475aa8,8df24d59,682f5a6c,b18b1c0d,5e297017,24eb7c8b,e3de50a7,cb473bd8,81db3515,8f9484f8,8574af66,a15f920d,3986a049) +,S(ce2e5454,54324680,7035594b,1aabcf6d,5d8cad20,729a787a,7e01b61b,106fdf19,f3a2e5d6,745a16cb,3403a768,c1de8f73,cd26388c,c10f296f,f00cf9f5,209b1555) +,S(bafd293,dd071a21,25a857c2,6acc5afb,ea79093d,3c9771c3,cd3b875e,b74b3280,2d56802f,b8f26950,4adb2a51,a91ad2f0,d1ee6501,f8c9279c,6a27b524,8dddbb70) +,S(10e0909,5dc7ae30,9f1afbfe,1bcad71f,c66489ad,56256c3c,a648f554,c000f414,47a5a7cd,968dd158,e8436399,40c30179,3807713b,c09fb0d,83c6c851,c6b7029e) +,S(73b8149b,4e7bf050,b6cd9f4,93c85bf7,61062329,2dec76a3,2d7054b0,c794da63,44cb915f,b6813c71,dff3830b,ebb6888b,76312778,897903f1,d9988c37,3c362bbb) +,S(59a5dcce,9773617e,73c529da,6015ca40,bf923956,339a366b,84a69e23,d0a60fd4,4c62abdb,c4453ffa,2b806a6b,b823fbc1,59f57f23,2234c8da,a471192d,3081ee09) +,S(1ad2aae4,f571c6ff,1abfd45,35b3d085,1aeabdbd,b3a340f6,7bef0f78,f7afa954,1c394b1c,94539758,85d72498,b36a3be5,56b4f80,8ef52977,b0157885,649549b5) +,S(2403f66c,a6a7d60a,254b51e9,32cfb700,f37ad73d,193f25df,6024bd51,d0f337dc,9ad75d44,24517aff,7df86c,9bf4f315,cb40199d,4a2a5d5c,74044c4a,9c79d69f) +,S(f3139f4b,50dba596,87080a7e,b19bcc34,2b58df9,26576bc7,dfdc8e7,4914c524,fbaad228,ab34e8d4,451cf6b3,a1dbe225,bd46bfc4,8a4bcd94,10c150fc,5636c687) +,S(ec415f8a,81b1f559,714dd790,2441eb9b,c5c7bcbd,e87190c,c109ca04,a3e75149,9b90bd46,d27e0200,369fe995,3b50752f,d00b9472,fd31383a,f01bb88f,b223bc5b) +,S(5e336f17,264a53e7,d0899bf8,6f676440,f83ea0c1,5d53fae4,f19a71f6,998a3ca2,2a86fd9a,8358daac,828d42e7,9c6c0fa5,bf977cfe,56899db3,27ea32fc,cdf09f3d) +,S(98828ad8,a6ee9ca1,37f9ec2f,f0cac84f,5e664e09,68455773,3f8fbab3,ec38570d,ae7ba3cb,e617e9e1,6e67f34,f69af863,3e69c9ca,1f46b182,88126f16,9ec0e548) +,S(d6a7c2b7,169348d5,1d98f0c,27464732,6f67ad5a,4809acb1,6b783fae,36808436,698cc098,ebe430c5,4dc74fe5,dc300f64,7ac0a002,4109e002,d2f43ffe,89fb3d9e) +,S(9bf4a4ea,9fc4b731,5391b653,1d3ad3a0,f0fbaf59,b99f76aa,7807c442,f8e63bef,e69fbade,598fccf4,6f1f0931,f37f3c55,900dcc50,64e54ae4,191796fd,a4791068) +,S(38a09628,aa450076,3826f384,7e63121c,d6e9e645,f6ee0f,8cffb106,508021d0,5460c8df,56fb7d67,992928c7,fd969f95,d29de37c,14c2c9a2,2d60d661,6cb7c383) +,S(dcf8afd8,ee73bc87,c17c97c6,807fd3e6,a9c57a1b,cca058a1,ad24f2c2,6e9728b6,efee9612,3e78cfcf,1dc3132a,fa4ef492,12369710,fa2e8e99,3cc70b48,6ba78709) +,S(9c26ca1b,f52eb7b3,a0d40dc,cf546591,38945c43,41e0c611,40d0662d,1033420f,4bfbeeaa,ece9f2e,e11cc672,24749c3d,e12be6d2,d3d21d90,ed742d,31541ec) +,S(2209194a,6a3b76,1ddb2b1,3bca12f,3697248,4bec29e3,102d7734,9832ae6d,7dde1b85,cd00a08d,38035f68,fdef0576,c458476a,93eddfc7,4bd4927a,cbd64543) +,S(6ffff27c,ce5efa3,a8f8af72,edcfc736,9874abf8,5d15e1f4,cc71a186,9a7a29f0,27a0e163,bcdea297,1abe52a8,a92fe191,38b839f4,67772c83,81504328,fad94a2e) +,S(34e91b7e,e2c5f407,8a9d1ec4,7e2b2c02,1b8480b4,8c3b6e47,19cacc36,b4250382,8d60947a,42d88728,e0d67d2e,e9a0559b,55cf3887,92c733a7,3ed50b25,3706cb82) +,S(3b2de979,9106333a,98504128,e2135e5d,7deae86c,1c921c58,529aff14,12fd62ff,4ba40985,8c5b594d,f4bf5e81,bd7eccc6,3a7bbbaf,fb32926e,9a47503e,f031d86a) +,S(fbd44acd,9e593ac2,12fd1f64,c4e18d31,c3b3fffc,ae1c88c4,6aebaddd,ac608b2e,9f4feb5f,2ab68e29,ca64f458,d162dabc,7a05c552,2e38c4cb,74529e3e,41d805d6) +,S(d21c3321,bb6ba2aa,dc0cd52b,be68716,864ce1f8,44107374,c0481c0d,91729b39,2b51f18,7b95725e,f74deb00,8e9d96f4,f1a9bbb5,c9aa28fb,275f700,bd964566) +,S(ea2d29,f85855db,78808749,9ed79c2c,614406c3,adf64663,8756b60f,16166578,33971e79,39faeedf,15b14607,37fa7112,7d6f49aa,fc423f63,783e808d,1fd10369) +,S(2a1a6709,301ba6ef,c5ad4958,e29fa73a,caea18e9,e01214a9,65291977,8bec874a,56c971a8,d29d6641,9c05fcc9,9b0c0156,a1ebd007,bcab2cec,b9e920fc,85f796b9) +,S(aa870dd5,6434af8a,36d89551,a7109cac,c1d0c5d9,f5e43630,17bba88c,579cfb6e,d1fab1ea,cb5652f3,cd4d5836,82aa3cb,3b1b6854,c0ec1157,41486028,73625dd5) +,S(e979a3bc,5165f53a,60042a1b,11e8062a,e74f35f2,d70aab2d,b250a4a6,f4507507,4de86928,b9dfb2d,8509a1c4,8efdfbd7,a5432933,e3f12789,cd51ed9b,b967ff1e) +,S(620979cd,f37b1cc5,b1fe3e01,f761b8a2,ffc29bfe,8afb7cae,7ded5cd,37f97829,cc971616,6ad43824,4c6be489,7cac0b95,afe5ed6b,11be673f,d67f0d89,6d58f7d8) +,S(90a5df7d,986198fa,70152c7f,e2abc14e,2c80d5e,6b75b42b,aa042e03,f3aa00b3,77e0ad,2f3e1eed,472a543c,3852925b,327e3eb7,aae59030,2d7e12a7,862201d5) +,S(17802140,e10d8be8,ef210b69,b7fa1afc,16a85d9f,ea1150a6,c6e5e234,cf638446,af4982e7,fdcb7a8d,b6478b54,a5bd7cd7,c48d1dbd,2a3d003,7e87b6e,13c9f5f0) +,S(1f2b8d3c,fe515cd2,53f66b0d,59fc51b1,4cf75ac5,d9c7b4e8,4c75d92b,f0380b8,6902b31,19f38b04,5b979f94,cc140481,d4e6f7ad,b3efe12c,4de1bfcb,c71be72a) +,S(aee51eec,9e5dedb2,1619d114,5594ea7b,27e21a4b,37accccc,d5fe522d,2e46d29e,d40ef18,86725504,fca42c2c,b8b80dc2,c1028b71,1bf3fb18,9fdd579d,f7f0ff8a) +,S(40fe6d08,b714ee12,a4d643b4,21b331c4,fbac165b,d7cd88fc,ce35a873,875bed7f,c32f1cd6,3083a976,6b7dd8ee,7133831e,6796709a,c67953d3,4ec5d8df,922d2743) +,S(5425c555,8a6f9068,946f7075,db347e6f,cb6c723f,c5ff829f,1634fb2,13b3c820,c218eba,db4e3ad6,e41a28ba,129a0c1f,8626ae2a,16839b77,ba12257a,a6aa2318) +,S(83663c0e,f024207e,16ba74c5,ca534d37,733a7dfb,b2d531bb,21a28243,d0572a00,2699a48b,dc9af87e,bf18c9a0,929359cc,d7f2f137,b84fc070,2bc3497f,69c83d45) +,S(bf931d61,e72f217c,3b820b63,282f5d4a,c929134,efa06fff,88480f86,f6247535,82553f48,bc40dc42,cb8bb098,ecb84af6,5cb3956a,aae7bd0d,cfa9e181,de93c21a) +,S(1c6e0876,3c2242ab,17e2885a,537bef4,e8920782,9c573d00,64fb83e4,910312c1,b7c14efb,bea753a7,5d8a597c,7f1a716f,8ae4298f,379aa64e,d070ab2c,28e66185) +,S(9a2cf62f,9eb5810c,31b27614,1592f201,1eb158a,3d123610,99af0b77,7d42c0be,159ac59d,728d1c49,843a0207,e47d1cec,7b9b773a,9ddaad52,3ff27d78,d2767d7f) +,S(3596950b,393a56e3,443c3b93,b4f8288a,7faa8d74,d26cab37,dd7a5b4f,6a9e183f,f99bbbdf,c566b3e4,e65dd63a,15c727a4,403cbe85,202e45f4,ea5d3462,173babb7) +,S(6f556cb8,f5da812,24bbe628,6dc4e379,ec12b124,21cd95d8,6bb1d580,a13b5c37,eeee3133,1dc89e57,48fdf10a,1fc0693f,1c09aece,aa27dcbe,919d60f7,4748d656) +,S(b952070f,fe60bf94,cb14bf68,b37e3e54,bd9b8063,ec8cd4d5,20408756,bd318bff,57996eae,d38f066e,cb3f8113,aab5e4f7,f322859e,1fc075cd,69ad1ce4,3fc48ff9) +,S(dbecc166,8d94b2b4,8d37c133,26fffedc,3e690b76,87563677,23352ac,1eddc2a5,f124cd3c,e42f56d8,a7588145,e53931e0,ce8b79ca,ba5195f7,3dd861c9,9027823f) +,S(12dde570,aae95b1c,7cbc2da1,ed2d936,bbfa5155,f61979b3,e67057d1,5fe5e1db,328711a9,c30e4455,e2716e60,3bedf4d9,8fa25d1b,e892ac72,b5be17c2,b25ca311) +,S(64bb18aa,fbfb7def,3493c920,d2faf9c5,57856710,766b0bea,275db46f,f8271282,717c28ed,e9284844,49cd0db7,180cc5fa,20ba79d9,41c979bc,c0a8f274,3e2e2901) +,S(a798f4c9,bb3ef48f,d2ba3df5,2b040611,d0d5532b,9134aa28,e21b5585,d2379ee7,91f903cc,a4628477,b208bdba,59ecd246,bc50be70,34620a44,b55e0e9c,214e563e) +,S(7bfc5902,58f80000,82946c5f,a1a352aa,808fcc59,4bf2ed7f,bc6dad3d,8bab00ed,17b5dde0,3bf6a814,efbed180,3e5f1950,59499cc7,13e727d2,405e0748,2f912cd6) +,S(23bda819,978c9a09,864a1c53,e0fed0d6,ddc18777,b614780a,1c6fe08e,c35a820f,aab57ee2,7d226f88,6e55b8a7,c4d7a245,7badf96c,9312906a,3efe2cfd,3292af5a) +,S(8f649152,54696b2c,1804467b,e1619ba9,d37cd874,88db9418,1259d69e,135e1455,b05b39ff,241ac0c7,7e2fad78,da585b09,c98815e1,b368040,d493bbf1,3ab54ac1) +,S(177ea3c9,e592ca96,e9e0ef4c,87cb00a1,cd51ccb5,1e1d5252,963cfd08,77f30331,57185496,db5e5971,24e55b14,1042ef30,99f206c4,67415318,ccbefdb3,b18cacff) +,S(16042996,9ab25db9,e4ee4231,7497a607,360bb1fc,96e74d66,cd87cab4,44af2f36,1dfa3d9c,c3acaa95,1f7ad037,bea4c20f,c311a8d4,c2ce9cb0,bd30078e,b0ff64ce) +,S(10210453,fae1b545,de76c4a1,4b6ea5b6,172ea157,1fa60696,25753231,2630e29b,ec8aa759,5708f292,72e2ebab,eed6bdaf,955b27a1,469758b8,44c2668c,42acf576) +,S(659574c0,39345165,e35deee5,ab4c3b09,5b873ba1,fa14283d,6bced3f1,d562abc1,1a8b17c1,bbd83037,b20fc2ed,495b890e,526461c7,8f0b8d61,e94a35f1,bac9520a) +,S(a8a00f02,174b4d3b,9ca825ba,88cb1ec4,4c188343,5478a00f,38025a5d,1e2cfe58,fdac00d9,55b6872a,62a36dd1,cf666423,b4dd6b4f,4558cca6,d931a1b1,1e42561f) +,S(3ac8f67e,b4c2c3a8,2cd90fce,f612ec7e,7daa1072,6e4f8da3,57d9ab96,56e30414,15f71b5d,17dece22,a696fbf0,2e360226,bfaf685b,6575fb99,68fd52fe,7a21f9d1) +,S(87c56593,9fc7bce5,650e57d9,37e77642,a1ef510b,dadd117d,2732d316,a4f2ce19,59908fd3,e2b646ea,210606ed,c790851b,4077142c,ec7733f8,613dce61,3431570b) +,S(6531e4a7,f9cbc2f3,f0448bb7,f8250542,6cf5c7b9,d4a1ec6b,80098799,d5e43101,622a2201,f3c0f766,6e81be2f,22f1ea60,f4b45807,6800fae8,c353c283,b6ec3d7) +,S(e2a5b419,cf421b15,859aac6c,9beaefe6,29293f39,3beada53,e1ae567d,9bb7cb34,3c20b681,578aef9b,138f852e,90f49526,6d30f3b1,6ea2d3,23dee943,1af4a5af) +,S(d4e9df61,35cf81d2,21003bc6,e167b6c7,9e912c1c,2dcac775,f7d9d07d,6ffc7334,c8f54f41,513d7bde,3055c7f4,8436c812,898770da,754ed9ac,d6eaddfc,a80f6c21) +,S(b83ec734,10a1989b,988e2bfb,a46a421e,dc3ce47,d549d838,8970102f,98a6943e,4e0274ef,ea2966c5,200dbca,d8090f78,98bc66ea,44164fdb,31507ad1,e7e5db5b) +,S(ec57668e,12f0590b,e99a75c7,82c02ef9,88354f47,522c114d,bbdb9591,238d3eb,2b3c508e,81a3f696,389a5ec5,974a1bac,a572c042,69ad2709,25001215,c58ad7e) +,S(5acca76e,7578cb86,8d5ba7f0,aadfcf40,5ca4cc52,d778712b,785764a1,2afa01bc,7b0df4a4,5e048fae,65a0683b,ea0185ff,f867a578,179c153,5fa93561,54138359) +,S(bd563b91,6419f92c,43a7c2d,7042fa71,fd88e5e8,41115b5e,36a673cc,93de4e07,4ec5b773,b35a5579,b7c729fe,1cde3b32,ca34f97e,83b989b6,fe756597,3cbc840a) +,S(a070b055,839d93be,2b4ca25c,a4a6b133,5ef7d09a,268bce7a,fb1406c6,42e71025,d3fe8577,1241be24,ed209e8e,b5b28ec6,e3a0bf52,27f36036,3a7325c7,5eeb6acb) +,S(9c50323f,c758663,346c5863,84d5aef1,123b4338,eae00ec6,86aef2ed,e19b2f06,1dd9442c,cf588e6,6a3cebd7,bc68f2f,6f270d7b,bf01f088,a49a5ce6,da430229) +,S(90fe8f78,166e3f6c,2d19bd0,685fa2d0,1f6bf06c,2ea220ba,cedb0f22,ac9c558f,826d63c1,60fe3875,9c5887c9,cabe8f93,905fa1a5,e87a8272,670cfaa,ffeeba13) +,S(d2f44fa9,b704491e,69488c44,cc8ccd29,6addc630,2fc66900,1703afd9,a2a5d3b9,2de1d619,247636dd,ce1de2d9,75f14515,ec5807a8,c7c0cc4,5c7d03dc,fc19352b) +,S(17f1ce71,9e3dfefa,106e95e6,62786729,e8ec2bf6,25421ede,ca71ca14,5782b23a,62b51d27,74f514cb,5452cd29,e3907a7b,b39a9b9e,400d78bb,f6cca78f,cfc1aec5) +,S(5b1dcad4,5974f0ee,e99d7c23,83e48585,24428c94,daa956af,cd692c4d,5a63213f,6958ca48,f13e31aa,c52e531f,886da246,5ba713d4,748cf6e0,de16e0a0,366c33b4) +,S(ad284e67,a0682585,f18be40f,e966b605,8cc787be,c265606d,12f202e9,31f3067,c86ce860,ac3c3955,28321cb2,508e4da5,abb4dcfd,2844b95b,ede54ce5,b17e45b9) +,S(9ba71712,dee6f0a2,7352cfad,59f6c0ff,f133b1b1,37ecf884,a537b672,a4275c8c,b910f036,f906a419,21fd37d5,5e0273a5,332edf68,43dd8afa,43070542,b0849b40) +,S(cfc757d5,171c9d6a,ed8b9123,a2b4a405,d8e869fe,e80aebd,75255454,ee6319a9,43dc370a,c2eb8fb4,4f78940e,b41d614c,ccf2cd7c,c4f324a7,92ba37bc,7e48144e) +,S(b8288ec3,2e4a569,27df3e13,6e81498a,bc9a52af,80d74bd6,c85eead8,85e0c49d,a0d53c40,d2234ac2,df69605b,1422bd1e,4a1d77db,fb0d7269,13de63bc,a2f96078) +,S(3808cddc,497c9065,cec574e1,3b82a10,fe2323f6,65a99df,1e724221,3eeb9a79,eb046225,eb6aeac9,5659f1fe,75dd910d,2932cab6,9b4b810a,d83e7681,e0c32907) +,S(a1620bae,cc99c311,7b3889b4,7bca5d99,4ecfd67a,ad5a7461,646e55a5,19e46398,5cc4b5d2,edc5f7a8,54cc3054,1c7ec571,e06c59a,52bb5cf5,5882ec18,1b07c0fb) +,S(f1d942b2,bff74aa7,1f9cb411,91ee85d,e6955802,4a4d46eb,53ac02d1,32fefa93,19a564a2,8352bc48,a8dcd932,50274bd6,496cf488,6e2ba390,3cf91631,453f57ad) +,S(1a4e3836,a34db30,c47ed6d5,9ba6fb83,fcb7a5a,a0002ad7,1b93b154,a5fd566a,745e195f,d94900b0,aee3c5f8,7c6fc62e,fdddc18b,984900c4,20c77ba5,4141cff5) +,S(af37075f,866d7aa5,9371a08c,1e7aaa5c,d23ee51f,54428fb6,84c09b27,93b432,b32e8869,fbe53ef5,4250e803,facc93ff,a100a84,becaec5f,872d0548,da4ae9ad) +,S(88e39f4e,83a0d6ad,a1e01ac8,9021a7ea,fdd1f9de,740bc10a,4d572c46,fcee9330,a14f6881,bfaf691a,96249322,37522174,e8a17920,52da7bec,a6c77d4,5fb8a357) +,S(8e406574,a46e56a4,dd4cf780,9a7ecfad,5a1f9225,cfc2fbdc,6b7bfc84,a5ce14fd,bdc6108e,d5616bc2,3ed52c5a,1314642e,a9272707,20f00be9,62e48945,3550f167) +,S(aa31e1fc,118e00c9,8b8f561c,479c6427,8676356c,640304a8,3b687a34,8ad4a091,31c95ccc,2520c0db,7c7440ac,7e640be0,7a8ba4d9,c0020b1b,f31418fc,98d9eb17) +,S(ef278702,becf4f15,ad43fb6d,d0114077,d9f8bdc3,ff4c78d4,d0a2a15,8fe160b,377dcf3a,774d6416,58bf108a,87201b9f,f28c70fd,449a77f3,966ff441,d89246e1) +,S(d1903199,b9762761,fd02c4da,99fcc503,ac15332f,4be01b7f,a044c5c3,f848ebc7,662ca3d5,9ff2c5fe,a75ad64a,f7044a94,60abbc25,defd0a3,aa6b0e6f,2c7f4f3d) +,S(682ffe36,6838fa12,827ae055,7e38c12a,bb571227,47643f26,9cb9f1bc,922b07ab,4531b021,2e8fad86,6f6f67fb,d8eac752,1a360968,f0f9792c,a4568a55,855924e5) +,S(418fa3e0,b32be1f3,f06b96d9,728aeac3,3294ea8f,16f35139,76b30801,81d8e833,dc1608cb,68bb0480,859c9983,6baf9558,9451022e,b9966e0f,498245e0,2183ef80) +,S(e3f7dd7c,f5898b7b,174cd809,5c7c0890,4188bce4,bd6487ab,e974d979,f7faec2d,5ed5ca26,77d3bce0,15a6cb51,9922a55e,9ac1adc0,61bb0774,503e79e8,204441ea) +,S(810ecbe4,f43814f4,e658ce9,234d71b3,946556d7,2ba9c3f3,6fa04b,4dc25cf9,5fc57520,81397434,e395a752,560a8a76,252e6eea,b9ec067a,16befea4,1f1bf1ca) +,S(6dc50f0d,7e9518ab,fa16bcdb,f43ecb2f,745d5ee4,7269225e,36811819,6542b7ff,dfd5e416,2d596f5,b44602c2,20a87cfb,77473aca,6dde260f,856b3295,527bb87c) +,S(d39c9858,5ba2a859,a6fac25d,602c8e1,fb205a88,7aaf628f,5d1a210c,bc648fb5,6e92fc09,9df932e5,1bd0c6bd,5b6567f,61a1e8c3,93d69add,111e9320,661ad724) +,S(d7fd8580,59c1a86f,1b81c05b,ee63bda6,8ca93c4e,5ec99e91,88d9c7f4,40dae0d6,ceb56f19,cb3e5b39,64a4c58b,5cbeddcb,c736f0a1,8a2f8f3f,f0758f24,525a8fda) +,S(2e269d93,319a79d7,513e6f73,918638df,c4b1b7c,4c19ec83,b254d780,dc45fa87,650b6846,4e8537af,583cfc48,caaff61d,f31dc67d,5a48e0f8,5857d7c0,9bea1d70) +,S(19f396b7,7147937e,bef30096,44b292,2a6e3c6,5b5c929,22b73118,7120224,4751cc23,4d49e926,651a9a29,c2a8a55a,f7e4b25d,9cb4bd2e,83530bdf,494b131d) +,S(88f843b4,e3689ba0,264d6d4b,4d310afd,85de2ea1,6fbe7275,d33112c7,538a7c02,5dba8024,30d31ef1,412f2310,3ccc5951,66e903a,55bb2a35,8be1e715,27fe45eb) +,S(b1301f5e,1474083b,3828ba5a,837efc44,21990da5,275f6b1e,bf773b52,5ef14a1b,f9fa0af5,b508ca7f,2345d06c,5bf1e5e4,907f2b19,3681837a,802259e7,7208864) +,S(63bb3295,b57ac21c,4b96ae49,92b8f3c5,7c23743d,44ba348,195c5f58,d5360bb,f5e6a98,96683293,af6b9ded,f9f163ba,15b44017,120c61bc,c9e51758,f3ac793) +,S(dac9f722,7d0c012e,e3e1ce88,a99cddeb,9a23979,14c1cf1b,915dd41b,8ce27687,85bd90b7,7f2917c,cf1ebd47,3bfe04df,386d37de,69893cc6,9e79ae89,2255a12b) +,S(ef05aacc,a8082759,33719aa0,e0958f6e,4be6a6c2,3458f243,f84fb2df,9aa422f0,d6006b80,bf611afd,3f1ed523,988b3e8f,d44be73d,565ef30d,911e4226,ae546f23) +,S(dedf3d9c,807065ad,8c1e3714,f682ff86,4f6ae08d,6bc15773,53f27677,ff86783e,7bf6f3f,1f3e5ca6,6902639c,a0b071d9,50dc2331,52f1b47b,5c68923,9a1cccc6) +,S(3db2b461,d18b367f,cbb4aae0,7a73ce9,6c1b4cbe,140099f4,d3839764,7414b5da,515ead0b,a8ba7b25,9f04484a,4c55b532,5686b882,77562b99,21827706,a036a142) +,S(5516a03,3da8cc3e,28170010,5e8d57f3,daf5bb84,596c040a,3d2ae05b,41cecd4f,6bf44084,f0ad14a1,f129a267,e13b0717,6d2fd274,2d4be75a,2192e54,7ceeebf1) +,S(7bd86d5e,6fa18e26,cb0b6e2d,faf2a4d6,a784e831,2e7168bb,8e660e3d,92514c3c,9b634094,dcf4ade0,eb49eabb,a26334f1,7770bb94,b776de46,64d847fb,f1574afc) +,S(a24a8b40,d63c242c,3dcd2513,fbee3c04,cc15117e,aae40daf,b39c3373,e6a83bfe,49163714,afef59b3,b503eb73,ee091349,e599c563,bac4aa37,13d7a6d,6f5271a3) +,S(acbbcaec,8b01374b,454208a5,19051ebd,e5128307,785f7b25,706642f7,775a932b,102283d8,1bd1e9e7,e5641b8d,a701f51c,86047d76,51becfba,89478d8a,a6226572) +,S(efd5654,8f37a094,19f9fc11,6d818523,c4d76725,860d49e4,a1cd8434,a0cfda99,d521204b,da2b9db5,dfa47c9c,6ae4616a,52b3caad,5440e4f7,f1fc41ba,766bc180) +,S(15600bf3,ffca622,a163244f,47789725,b4c112b6,e3d7652f,fe829a6e,386041c3,b1a1ddb3,e2b0e170,8cc9e6db,13c7b111,93673cc8,397d9b59,5b4e8dea,a39cc5f7) +,S(8d14cebc,62f7cd8d,fc60c2de,d144c76f,55d9d6c1,be5380ca,1e1ecefc,5a85cc53,244bdd67,5030a8ec,af876f5,99a34f98,ef7388cf,e6705734,540f57f4,15641220) +,S(e3cb7328,29c6d09f,6ee940f6,5f30c79,7dbbc26b,b8b8c860,f6e07088,a485ebaa,e50a5c44,6768827d,ddd57e18,68064e61,51c8951e,e4cd920b,b664ca06,67096db0) +,S(9a18212d,45364ebd,3ecf4d76,3efcc66a,ebd17b7a,f8bb7f65,8679664e,16888e47,85297209,abebf492,ebeca275,bdf3bd2f,987d1e29,6bcee299,9d6e59e9,2b890143) +,S(43366191,859bb3bd,5b44f1a,d9076ec9,5439c082,c99f70d7,4363117,8020521b,9dd6d890,16666a3e,6bd8c0dc,76cc9792,fe5d76b8,c49cf9e3,75e031c8,bfae2556) +,S(1b77e51c,b11e514,29955ae2,37659c5b,a8050ddb,685e5b74,fbe38506,33bf9358,f198ea65,1ed4a743,a14fb905,fd0bfefd,843bb00d,675781de,5fb1552f,c7f382cd) +,S(7cc6fcc5,558cc6b7,156a62d2,e823631,e0b95e8c,57fb79d4,b4aa3ff4,9cb718cb,526becaa,c0c84e61,b3fc85f,60d028d2,eb90567e,319bd6f4,12b1a36b,9c3d30ac) +,S(18c1e51e,10a7dc5f,7783d511,6f2c0457,664ca2eb,6541ff29,591ee59b,f9f958cf,7f72840e,ccf4d03f,29ce01a6,725f6b97,d701a935,bce8a2b3,c1e44904,cf98a300) +,S(3b9335fb,b191bc9d,17efec98,77960307,2648edb7,2c427521,34df37b6,f1620c44,ca526125,8239c80a,1ae893b,268d28c2,b02d56f2,d03a8a7b,aca25def,34d6d694) +,S(f39660c7,ba9bf800,381b8ddb,d783dc6,acf8c183,95f9144f,688db8c9,9d7874f4,c5037625,2abd41f9,7574a607,52be4c31,e5ef2874,5e9d80a8,da2ea676,4bce5cc1) +,S(d1d2872e,ee06a4b5,d3b735b1,9db1d88e,cbbf9ba6,89c1e411,980b2cde,e70c86d6,dc5cd630,859fb9da,70f25023,5b7bf2ec,938743a,a9f04fd0,69d1d746,e3ebbfef) +,S(aa4f71b4,720f6470,8b6261a1,ee97bc7c,ee85b274,caf71a6a,1f7f000a,b06a1948,958fa65f,acdc42f6,c1e98f7d,f67ccc39,14dc5e8,d20bb872,32d7c898,e451c017) +,S(85904824,63e69633,42cd1e89,1502c309,d74e1722,fad8e766,d7e8f566,49bb732e,585601b5,5bfef406,ec5f71bb,6bae29c3,c5e77247,befbb549,5ced52a6,da64a2ff) +,S(dc899ab4,89a12ac4,4152ef63,48553ed8,29855449,c204327b,bcce6418,75df4d99,6791a965,65fb749c,44f133d4,b3c9c8d,77488831,c8a99ba9,7b66c9b,43deddb2) +,S(2fd60f25,3e0b4f1f,2589a096,f9a0ea3a,405906c2,690fce35,ac7df791,f106020d,872d52b0,1cbfc3b0,ff699950,5be33b51,64a7054,bb00e22a,9a87d692,dccbe782) +,S(a74830c1,7f816549,cd617b94,c0360b8c,9206b382,6782d351,650785a7,fb71212c,fa928b97,75b28be7,4e340cac,eabf866c,fe7e7299,7c276680,2d211b1b,389823b6) +,S(fd450d48,c59fc4db,e3366b43,caf00c2,bd10045,842311ab,20f8e24c,6a9a10b7,512d1998,db747e39,34451fb7,9aaed7af,48801051,dc8ef756,4580db9f,bad910d) +,S(c0816923,9f2bbbc7,34d52def,79f9f4bd,cbd8c435,d90561ba,fb23f12,f1fcb93,fa00c81a,8c5cc2d3,5f78f0d2,475851f1,73f70cbd,cf2c950,8ebad1ee,b35a0852) +,S(247c4075,9a0e7098,25a5d82,4fad3419,55103052,bcdc7ab,fe4e559c,84a04a66,8da3cae,878260ba,1b95a5db,900f20c,12597187,4191cf21,939ab6c7,fe378067) +,S(fbe3b30f,16ad6608,32f9ab15,2f44076,2f7a09a0,b07b12b6,4375db15,37fa4e9c,98cf3e68,2a914c3a,ee54971a,793a9309,8c63aab3,e2db5389,3f05450d,61b9080f) +,S(79f71ab6,fce86bad,be02055c,520e6e0d,88e98def,d37f2d2e,488bf455,3ec954c1,b5de6a0b,c1745341,3023a650,45262a31,e9264089,8a655b0a,4b3042d3,a9114330) +,S(d190f258,e2e3bb8e,6812da59,606f2f4a,2e3fd1ec,34e2c80a,9d280f5e,e1e9c4cd,98997b49,afec7d7a,26a26f50,9d4948c9,b5ebf9b4,3eef6183,3a2b7a8,6183c267) +,S(24f355ca,c0e00545,f47e199c,3818e76f,534eca88,776ff6e2,54244686,24f0b636,37710da6,5c3afbb4,308d5906,7ad044c1,4df30f03,427ac83c,23b829f5,37d25b46) +,S(bd221461,ae73e639,6b23d269,ed6907ba,330544d0,80342de3,a769d3cc,668cf536,a5f25513,3967fa67,b22dbe31,917d9d1b,ae11a1d9,dc7ab731,26e8f0e2,fbc8deda) +,S(cf0371e7,22194be7,ac5d19c1,1b447978,b38f8a1b,dc1dc3e2,471d4a8f,75d0f6cc,4bb04426,94fe9d55,cc49dd4e,e168b604,564b95f5,99566f3b,9fe2fbdf,16084f1e) +,S(ce21a5e0,287752fd,ae9e04ef,363540ed,f6736c34,266a2d77,b5d0bb5a,868fc32a,fc30fc93,bb5a2731,8b81b942,4fe330d1,878e710e,b9a44fa7,bf4cbfa7,10c7d0dd) +,S(7c95d800,da4720a4,102de774,d585f230,2b849e57,1f42982f,a785bd15,334b4b12,244deb56,fa5b4367,2c39693a,f09083f9,2b153a9d,4829ab3f,ff604fed,a266b30b) +,S(40bce9b4,f90489f4,d392fb93,3f98f71,e9281976,164b25b1,982cfcfe,338d93e2,5a9ebed7,25bf11e8,7bbec766,c52309d5,e2036454,447b8ee6,6dc79dac,7a2a9b4) +,S(f15a2ed8,2c00ed9b,9e7a9338,2d08c46b,33ba7bb5,dc15f5df,4cc29fdb,86f11c4,d02ce92c,e556287a,3acd4115,a190767d,2979dd7c,7a32dfde,cb6d806f,6e7d0205) +,S(4230d263,d5a4a915,cfd863c0,e38514b0,4929d352,d8a90c00,c0ab9ee0,56215932,4b134eb0,51699656,dedc7704,3d5586c1,62134b00,e21ab1b4,517bdc54,5f05fd69) +,S(6cd6bfa9,63327c26,fd2c7aa4,fc159956,1a90096c,dc88f414,d5cc9c64,df6a9e84,6741fda,1f774c52,20b04db1,9ba7402d,9b77eaf5,b8e9e2bd,a000d2df,2022565c) +,S(118face3,ab188a36,581cd1ce,1d434fdb,f1d06f50,1e9a64be,bfed2ea4,ba3f477b,a263037e,c8d5a9eb,be1a8b97,bbfa5624,ce00e852,44828af9,8cfc38ee,1da9052d) +,S(6be81e79,5fd1229a,fb24a395,fccfbb6a,ae4fda11,28f93faa,f74bfb76,c39794c7,edd0f9ae,bbbaaf0e,bd1c01f,af128730,5d5fc5c7,732885eb,327eb21f,62683869) +,S(b9a0023b,6fcbb06a,48f97684,509b8b9b,937f990e,4c3f1a61,27a8a18e,e4c96c3c,e1b25ce1,3e8bda89,ea631d71,4c07adfd,c31fc6b7,304b5e7f,1cc7221a,6597df11) +,S(4e384b06,ee4007e8,e70f22a6,1af73d89,4528722b,cf58bfa1,16eaa29f,e1f2334,2fa6ecd4,8faeedb6,240db0d1,14c7eb3e,63540e31,788f5f55,98c52fd2,538ef0d) +,S(14c8267b,6462dbfb,6ad45cff,58d9b22e,9fb0de4e,3d026999,9357acc4,d254ea52,86da149d,e14de86a,20becddd,e33e99cd,158a50aa,2da085c3,cf675eac,224b292d) +,S(42d0c7fc,21129bdc,97318985,73b6d111,568005b5,cbabcf55,c1828340,4f5de376,8f83e957,92880a3f,dac6738,e65ea463,1399daa4,defbd1e9,41a5586d,a42f652) +,S(bfb03349,2fc28eb,82bdf9b4,417f02ee,f93588a5,b138c520,77250499,23e9f135,c65872e6,9438a5e7,a20c3492,7a3de7d,85c690c8,b20af801,915585d1,98184882) +,S(1a111410,d04e1278,3cded32,b3602007,7dedfa32,6493a780,999c68a1,dee18047,874723b4,c6b63cbd,d957098f,d0124779,3e711a56,fcb8499a,a046f5d6,36d5be75) +,S(a47aa995,3a999aed,9c1d1f77,da8b736e,6d045d3f,9b32ecf,a6bd4225,fa66cf6e,c4ae1566,4da8e033,f0e3fbbe,472e16e0,70a4b40d,f210f7,3d0a6fe9,3dea782d) +,S(52ccf2b4,5cd2555d,5a0a5765,92b5ca7f,5ffa329b,6bb12979,8f2c10d4,bdf34119,92abe502,d23e9f61,f420e4a5,44e42864,2462dd0d,7d7f386f,ff7cf2b0,b3a5043f) +,S(5d2af6df,77107953,e6221a4a,ccecadf0,a2a8d676,5e720d2e,38c386a3,e6b48e4,5a44be69,80ca8082,5d435aec,34db8be4,6dbd05e9,9b8fa176,45888bd4,2260cfaf) +,S(e0f9b457,e184de7e,7484ad3a,dff4adbc,4dfe508c,14341dd9,d2c4f584,807e3fba,d0712e1,3bc4ad8c,78261681,3d00a237,36383731,7de79d0b,1f52264b,6ea70526) +,S(6797c2e1,d1c2643e,a831372a,abf36ab5,fcf88804,9a01f052,a7930792,acd2a7a4,ab005587,69f8d361,2217de,8d4bf205,925bde,7817e97f,d155fa94,8f084167) +,S(f302e07a,8953b3c1,f0b3796b,55bdf133,84809aa7,3dfe4fde,a0d56ae7,a04c2f26,339d529a,a6c0c8cf,f46682b9,c36390d8,28b2861d,6f4906dd,a4659028,c74d780a) +,S(aa4c04f,b8261965,9254f9b3,2d9e25cc,ec651f79,b710cc3d,bdf4eb3c,dfc207d8,520cbe2a,c8c0382a,23d2cea6,6a18f28,bb87e773,6bf60dc1,cca64a58,9fda48db) +,S(cc4bbc6e,7f4b02b5,ebe6d484,6352257,4651fed1,a079767b,fa53d1e0,dc38b5b9,4be5e0de,c97683d4,939077d1,edffcf6,dee4a88f,f7d42894,c3d50302,70c9554d) +,S(6a4bada6,cf1e123c,e80fcf83,2d6934f5,486901f1,6d3ad0af,cc87a4cf,205e6e79,b79145f8,24d693b3,832c6676,e35a73b8,d8acddf1,681720f6,c8d5ac7,f81752fb) +,S(d7ec4d61,1d440625,367b2c5f,a6904b8d,cf6f0d81,39cc3bc,16299e1b,50c9024c,18c402c6,3e818647,7f15bdb6,d514373c,89d1f7ff,bdab83f3,5267eb0c,daa81d89) +,S(4e21e4fa,4b570b40,77ff6876,a1d7e4ed,1db77d0f,56d35445,178ff508,5b197169,dab19080,ef84f0c8,4919d869,36de1aa3,ca85a1c0,aabe902f,b46b31b0,3b350580) +,S(32aa04b7,53752059,7b4ef603,62aa208a,effa6891,240a587c,e1cae58a,28a6075f,ca649475,a58a3ebd,c3802c13,f006335a,7d203ddc,88bbd1fa,f0787839,b9452f21) +,S(306bcc2b,94214994,e86c7fed,4f510ad7,9eb1af11,b824d897,a1cc7564,9eaafe0a,820c2986,abf17343,35089773,5b4da35c,56265a25,4a768346,5dc084aa,ecae6dcf) +,S(37d23716,1044ed4,b395b044,5d70eaaf,864530a7,fd8490c1,fe2d1ea5,61f4bc19,a6a9da7,70558993,ce38d5d4,c69dd25d,134f37f,c28dddef,2e7edc0,c1343b83) +,S(1f324230,886ef594,aecbe39,2d7a4434,fbb9fefa,fe22573e,9302d3c,dc81490f,39e53099,f25e977e,da860f77,6d09338b,c0e75446,42557c8c,b05761a7,c18537fa) +,S(256d4808,d6dd018d,392a6716,2af909f0,51bfeea0,9ce22a76,6266d1e7,61df967,d5643938,c7d9163b,38fc8072,609bcbf3,e063d78e,10cb8cee,32c00abc,6341df09) +,S(58a91493,ff7aa600,1f457506,624ce8ee,b1c142ca,d49f67f1,be099c58,3a7934f4,bde8d64a,79d5722d,6a96d240,897a7f48,8e20f19f,259fc6a1,e4483448,e0290122) +,S(b4a80e5d,eec9391,8f146b4b,e0d91630,606a5c79,1c4b7b87,d4363de6,e2691f2e,a6ff5b82,ca6fa424,efc00b20,7ea90991,fcd5af15,d23140ab,96da6cc8,bd532297) +,S(41bca570,b4981232,f21ba765,4f23d5ac,27f3bab6,9f1107fa,e3dc5102,6f8dafad,5a14cd59,9b0bb884,10ed1475,8445c49,3af3b7c9,2cc6435c,5560c4d7,832709db) +,S(bcff28e0,bb6c242,a7805142,122848ec,6951940,bb4a2e3,5ae05137,d73e8264,43661933,9ff9f2e8,278ef17,329682be,aa801596,e4a12b0e,615fbe7c,4b24e1aa) +,S(8aaa2f44,fbf66c2b,809180,bdbb4e2b,e25ff178,232fcaa5,a2c2563,8c1ea21c,69dc0de1,686bffad,1ceee711,95831b90,c57900a9,baf57ac,2f34a917,6d33e21f) +,S(930a3df,f84583b0,ced82f81,96c39c16,b9318f2b,44efde12,2be6c10c,70b33dc9,ae802936,2b10029a,a81cfc47,1251ffc3,6b586de,da9c1754,4a96d3ec,31cd6d1) +,S(907cf1c1,92b98461,8021a33d,1c9d22e3,22dc83ab,d5768a39,c04444bf,d4e76df2,527eb629,ca0a2e2,7da96361,ee727a34,97edb8c8,68694871,6a7dcca5,13b6f901) +,S(f9d32e84,76c666f6,29e86e0d,3804eee8,abe1ab26,ae2eb396,b584e4eb,e9583b88,d92f265e,9e6c5f4b,bc05a432,6fafeace,1516f823,3e5dc280,b239fa6c,bfdf7fb3) +,S(94772c31,70e50bbd,9952bc69,44e0007f,3d928cb2,c86465b2,ef040fa1,b4f90d9e,29021913,9326e358,2cfa8ee2,428c4307,86cb2de9,6ea2c735,eb71f759,bab14637) +,S(2b49cd38,8cec8c30,e984d40b,f1409c6f,df7ff24d,36cb699b,5f3c24c0,fcc872fb,9e65a427,ce5dcc20,db83a96b,720f29fd,df643b2b,a192736d,c621d92a,6583aa8) +,S(454f174d,8c344479,9bb58158,423d8413,ce87def9,2fd25a,5164807c,982d84e9,bf324810,d9894da6,1eb1e3cc,5a30639d,6500a453,c14e8a40,78353d42,7ac67ee1) +,S(df4461b1,dc1eaae8,5b4b7fe1,e87753e5,546f48f,e39da02f,f1012b24,58a79a17,ac4fd2bc,af8e0b51,48cc5a5d,46373209,8993b377,becd718,732fa339,95412fda) +,S(32973a0,d1be4c6d,1342b2a1,44ffb36b,81fd9b38,c0b7411a,65b8ccab,cda9161e,558b278b,f507b498,fdbbf73b,524c4652,53a0082b,d53a87f0,75d5a49a,bb601b69) +,S(cb63a9f2,d1a11b08,479275f,e1f0bc64,37126875,5bcd8a21,3481be2c,818c69d6,4949d3dd,a31db2b7,b2d42f2b,4709a870,5094d470,1e742f07,b6f86670,e43bfaa6) +,S(543ae5d,a0c271b8,41542353,277e1651,b7b0f587,a5b18ed2,856c2e07,41c28914,22c999cf,aba6f95b,21f87ab8,2f2edb2a,3dbb43a6,ff413506,83835ae8,bbcd0a37) +,S(7ffa63ef,3df62097,a3b61289,4eaf5bf7,4fb39ad2,9ec63f02,2c6f310e,77268c7e,9d26cd72,8fcbfe54,6eda19db,5ac61978,1b456699,59a21628,2500e5f5,389679ca) +,S(72cc6606,b02943a,5bd9a476,6b24caf4,e0e2f83,ae3bf671,5f05b39e,3436122b,f35ff21a,39503637,d05b744a,77797565,1e290541,326d920b,d5bcbb6f,74b56c3a) +,S(f5f21182,de67c3eb,396055f6,a8f64f5e,54043376,cdce9f3,3cffa601,4a348a4c,1fe09f94,8ad7f78,6c184675,3105cbd2,e0f8be91,f9160e81,9201fed3,3208b3c7) +,S(1cfa62a3,70171431,52fe149f,db07b00f,bd8d7928,e5eb145f,b4ff7343,fc19437a,1efe47f,e41677bd,337451b3,92eddb1c,ecfc19d0,5ef04727,12927d4c,77b2a742) +,S(b6609139,733864d3,abbdb6bf,4b827b2,3861594f,ce9e996,4637ef14,f0fb6849,2e807df,ae409cef,b7be1ffe,63351d8d,8de5fbeb,f3be5069,31befc97,d479c006) +,S(13da7c85,bffeaa0f,e295ce6,38de0b05,1b4aaf9b,d888f5c5,5f74fd60,abf2e016,c0477fad,fba6531e,f6369aaa,be663871,3bd6954a,d1e5df1,269c7208,31cd5bc3) +,S(2abda634,547a86aa,1188b2f6,ffaffb36,dd126d94,18406bed,8b81e29f,596526a0,7db36141,2e96e02c,34c0e39e,1201617f,2a7f2100,d5c3cf64,6dcbe563,e2b25524) +,S(4e161f2e,22785c68,3ac494d4,1e3cc2d5,e6b87be8,bd65e85,8aa255dc,8ea8fba0,c81a4e95,a2cfa101,fcb62112,b60c574c,623b5df6,5a1fcf51,e6bf2936,45d5f17b) +,S(586be2b5,740b0ed6,6f5c5f6f,217766e,ad5543eb,8e983ffb,928fc40,9e76397a,f11acf99,8bc2a25,48799529,9c7ea84d,98c6a525,6cbca56c,3ad534f9,26c6b08e) +,S(a76c4f91,1d0dcd58,9417fca9,8124f62e,789e0b05,91a9ce94,13e0b7d,e7d5986f,6a49fc1e,2b32aeaf,6f291184,3995602f,903c8d76,858fc532,9b3a1940,2c2c9b7c) +,S(15f11b1e,804a6d54,a496ee4f,f3030167,eb510e9c,c1754bd1,d46beace,1211a68c,f8968e8d,21bca271,75a79de5,31ad810,ca6c6da7,72ff96f9,937ef824,8f4fec45) +,S(f0169f41,685292bb,4ac93afd,58b2c239,3985ecd5,16acc8ed,ce46f325,74b23e58,6fbd711e,fd488c8b,43151ecf,e3a42ad6,25697053,1df18afb,68f8ad71,ee9aa05e) +,S(2f241e5e,2596d32b,6cdedc4e,b6de5f53,374e358d,8db78d08,9e772b37,6250f359,fe79f0a0,cdbef5a2,7287c86f,afbe917e,4c26c4ca,512f57e4,ab066d3a,3f7e71e) +,S(a14743eb,92bdf49f,5f404a54,ab193100,26f3fbd6,fc5a06e3,e8c6b33d,1f7a5559,3e7e5f24,b1d0425c,ee5c56ef,1e38098c,6d67fd12,f57eb2fb,1ee76c57,41d57c54) +,S(2d097299,db14ce88,8da72472,da686f67,b8ecc812,5618cae9,2acf6457,a011d2a9,e9cf7195,32f71130,5bae1fd4,ce3a8fb3,c8d71088,df35b49d,ad9c16d8,8734a187) +,S(aa7257f0,d7e51fbd,95598b7a,a994fac1,41aa76d6,318cbda0,20d30471,73317f2b,15e00f94,f684c30b,5cd4a978,c6245e6,8d30d959,a30fb39,834e97d8,c18a1b27) +,S(ae524618,e2877095,d52ffc94,67a081e8,b27b4b16,566e2b37,c8d11b1f,1f7416a0,d0275a1f,6d49a7c9,44a07a6b,ee5d5095,7b22b698,2607f822,8ad15253,a546ccb0) +,S(e7a85ef,ff8b0443,eace4cd8,81d768ba,ef4d93b9,79b17eae,fd237e8f,c9ff660f,4b53f073,8f07b360,7d66f720,b1222df3,eee2dd,ca20f40c,630a7911,a0fe2aa6) +,S(daa96eca,b8412eba,75f58a80,84a302a6,37dd7d77,bc9dc502,a2d083f8,35bf242e,ac3dfd97,a01557af,cd1f199c,afea0cce,52c8e3d4,975cb331,1c817c9,fab0815e) +,S(34dec21a,965b7027,44fa7881,4ff6f782,790d551b,7be35c,18cd46b2,e189baca,ee825c5c,5cc289b9,d7f01b43,4de4f0d,d250f9cf,c22c8d20,a1e54175,9bd23694) +,S(dc2178c1,2f015bee,829f0567,566d15e4,d607c8f3,b2992801,4b6a5607,1e61247d,fc86780e,31cf57ff,5da387d1,c3c25a19,36a263d,f6571de1,d098153a,97b41db8) +,S(6faee1e9,354bebe0,1fb65158,20b7e992,9517cb40,23d49d19,2a002ba4,e4782db4,a4915992,ceb8813b,e2778fb0,47766b6d,3958cf72,f18e9172,3f74cef0,1d2276a) +,S(a2bcc012,4112818e,571c8dae,3cb724dd,e45faa06,d04d7128,e9a71dce,22f300ca,1f594d9c,64ba43bc,11764c61,f8fef5c2,e31fda39,3447e7d2,10d004bb,c13870e3) +,S(b8cba39a,c51d86e7,d83a50af,f5370240,cd7b20f3,81aeb799,f951883f,458ead76,3a8bfe74,2b3a05be,27ef835,39988cc4,616365fa,e3738d35,29f9c0d1,c15eed4d) +,S(56e532dd,295792a6,ede9da94,c43e0b2a,25b72725,333f8205,7a352ac9,7a1991d3,a617e234,18bfdccc,8facb454,649a4914,2f0abd64,f30e06dc,838fd80d,7a141fc3) +,S(4803406c,e4049575,19f5306d,6daa003d,2aeddc1f,c1d4db45,15a8d35c,aa39a6d6,7add51c,12412f4,49d7b0e4,b7df38a4,83151126,49660956,da6273ef,8b53fd5e) +,S(bd61ad65,2e44effe,ca39620,2f84e4d5,d81cc579,2a2390f6,52409852,cd79c459,f3d7071b,8bb18928,1d827f71,ab7b1ad,5289033,ab28d20d,643af02f,a2b4ce5c) +,S(1b543175,e5b6f271,58048588,f81a791b,3ab216a3,578e2f79,354da6c9,5e4ea9bf,67a2e60b,321456b8,5b5499ca,e33cd6a6,d5445f91,eadb5a5a,f0e2164f,324417d7) +,S(2035953d,3319ffa5,9f75d86a,8d1b52c0,e8118ec4,d830d15e,d9616215,cb82d080,302cc0d8,5bc1e667,b160bc8a,64cc3bb8,763066a5,6652a0bc,c12691be,c41d7aa4) +,S(bf2a9739,f65bebbc,90413f9f,d311e095,e7628dcd,d76d25a9,8a4681ef,f4f84035,83932d07,cc950bcf,380cea81,28e04322,26b9a4bf,8536122b,fd055517,e7d3b2b7) +,S(a915504a,bb62b4a8,1288c44,8605e8ab,bafb4f0a,ffbcef23,c9c2a26f,f2cb8557,2fec1059,abe1bf4a,834c50c1,edf0e5a6,2ef21f7f,9da2fda,20989bae,18acd442) +,S(318939cc,fb2eb0f8,30d30079,7e209f00,6e28b899,8aecb548,b3b97900,9ea6aab7,5308df9d,10c7d151,cbcbe417,91b627ad,b7204db4,dbd2e01a,c5698e61,bdbda375) +,S(ff9e4851,d3f0c9cd,818facdf,4781cecb,7f622039,c23e236a,7e4b7368,64af1a8b,fd69f241,bac1c6b9,a52d6dd0,6e7bcb6,4a4a79a4,9c3881be,6ef8c83d,3f462c5e) +,S(497113be,a88d4888,2c98ac14,ba0bd0aa,d3c75c8a,58d374cc,86a7fd0a,b6259cc5,9029d9bb,96076d69,a264d2bb,6fea2f15,423ff1f6,ff47c02d,4699943c,9cbfbc4e) +,S(2b2cdb82,6653f563,dfc4c373,96d738e8,3d1dcc5a,ec5f4886,2d5ca84c,2ba69103,d1985cb3,f42e4ae1,7da33b7f,f8563236,6e2f5c89,b849ac73,afc3a7a8,1d049d85) +,S(c55dcffe,fe63e948,af77c8c8,32cb6c0a,c09ced5,5c338bef,fc27fd21,dc63b6c8,edef9fcd,b00fb62f,cc97c03f,26253069,de6f8d00,c13a5666,f574feb7,fabcab6a) +,S(52a0dbfd,371bcfb0,e2c69160,c9cca2b7,8dcf679f,774c9d99,706d306a,30eeb3c8,fe01f320,781275bc,a6c031e6,d71df467,56473d8a,780fc54a,6f8eb1ae,5640bf65) +,S(75c4ace7,6bb32bac,13141f21,615e11e,7608fda9,cba4723,9eb6bb8f,349a9e86,7fde50af,19506ba4,65d49b93,c8884478,dc34ec91,9bd5e22,be6bf71e,a870a70d) +,S(69cd7caa,b220abe7,8f36f7a4,633802b4,85969ac0,e9c4a244,7b0ad782,29daa879,4140a70b,8d9025d1,7fb3402d,2ac8afda,e9e0269,b29d488c,2266c1bd,58accc9c) +,S(b6cf3a30,d2a5ec8f,4480df82,ec6104ff,37355ca6,f16418ab,cad3a0c7,bd8da064,f12006b7,5d406558,51fde0eb,c68113b8,50441595,dfe3dddf,86c17a58,94a6d923) +,S(65c4a081,656d9b7,445131e8,6081b306,3a6e0c02,5339d3d7,cf48e9ec,4e8f59f1,51f4ebb9,4b63b8bd,2cdd6d88,c84c8608,bb380e38,c748ddb3,3dabff1c,f50197fa) +,S(c243570d,e74a1fbd,938bea43,bb17a929,47a228b1,ae47a6cd,15c37524,b034fa66,ca57366f,e3886510,903970ca,e1a5dc5e,bb857007,cd4cc56a,37fc7fca,8aa4cd40) +,S(9290d033,1c95584d,e2bace9b,788c50b2,f7fda83d,d45a4a37,5705400,45339d7,dcb3032f,c4a41076,8b8e442e,46cfb16,b63f4fe9,f94a7d5c,f932d0d4,95e699e6) +,S(295df203,cfa65b66,6afc86cf,b879d650,7075f75b,d1eb753c,709760f6,6ae9df94,2cf505f8,8220196f,9e5478e3,6bd82501,671c6b91,a404fc0f,b1fe00cf,12085934) +,S(1631e6c1,3f89dbca,36cc78db,1056a461,6ce2dcca,62f90b0c,5fcbf232,77d41116,acbcbff3,2c164cd3,b57d3b89,a326b5d1,46b5769f,a5b35df1,efabd2f4,407759d0) +,S(db0b2c5b,eec9f06a,9bb43e4c,de18d978,59a95cfb,9b319d2,5ba619ee,abc49e31,d647147,d8330315,1446a405,85bd857f,ebaef109,22ddd0e,3ac62231,8ee91abc) +,S(2581d046,9e8bdc16,e535c787,1a37c48f,929aad34,b694ac2e,5d264962,11e744f,7bf3c684,3d953b2,dbead1f4,8614646c,d18b0f2a,cdf6fbfd,3ca68498,ab25bc60) +,S(9db20da4,d576f564,372aeed6,eae78eed,f512d13b,13d4e9e2,eb3133c6,13c4b80,40f8b2b6,fa113b6,ed7dce55,d62587d8,a86a43b2,9e0b4876,c5607b89,9144d255) +,S(849b193c,e490990b,e2aa48a1,c31694c5,fa041f96,7086a83,cd1a06b6,ccb5e3c3,353b49a,6ac0c705,5a3d5e31,fa428e2,391165ce,402291b2,5e1b0496,bda41e1e) +,S(ae83dff6,5a1dcb6f,e2f56437,c83162a4,a388a16a,bd387d62,f5c5ed,ea08fe7e,e9c57ed6,5404a00b,a2f87613,4d484842,4a32246b,def6c31b,533caafe,7029eabb) +,S(24724eab,46175b4,efe51d4a,5993da48,1a62c6e5,f05d16a5,17e4f58c,fdb103,94465b42,e4e378c2,1ef0d1d1,8b25d140,fb17f51a,fa4d37e3,450c73c4,72468b04) +,S(c2e2f802,4ac48fcf,41a3790e,e9916018,5a301859,3cc3fa77,c7840552,6700659e,b1fe219,1563f9bd,20c4dd45,615d8cc,400911d,20cfb7a7,672b06,20d32a2a) +,S(8b889bc3,e2d1405b,47a1a05f,fd0c17ef,9b4dd75,4d30640b,e3c4de7d,f70791b5,e2d459ca,285629d,956d5046,54c5e907,6ed92fa6,c95643c0,7d746b78,e03a044a) +,S(336c0585,8f5ee169,fc09fc73,a181ccd1,3bd62dd7,c454837e,1a5d7676,abb2faad,5c29a656,e8f2804,6e855c6c,eb0d908e,38f1b62a,69c67948,9d6a03ce,64a90c2e) +,S(c9a6df46,411961d,a703ab23,605fce16,fe021576,92a9b80e,65b9e4ab,efc9ee93,8b63a4ab,18a4b190,89dbc53c,ef0b0dc9,20c0ec7e,1fcf075,195bccca,58d52f6d) +,S(6cea35c8,b3a45063,75456a6,2c95e8b3,7d84a6d3,e909c5a9,cc4800eb,5bc28367,68198888,eacc9380,4a3233ba,1801d586,e5bcb2b2,78efc7da,6764bd5d,edf0ee90) +,S(f13d4ee6,ea31999d,d8d1220a,13ce8353,7c350046,319a0412,e562cb8d,3e4ee80a,5f7afcc4,37f0b29a,ab11a8b2,14947521,bbb4b622,261b9e73,f989e1b9,9f43a2ab) +,S(7385b644,2e43ab56,f4df8a57,4d0a32ac,6e5a7114,13dcd992,f86c0b04,33830307,6d27608a,8ea00e22,4197c8a1,9e9511fc,7ecd7083,86e94ab9,6aaa35f9,c8c2c5f3) +,S(35923ab9,a784ee6e,5a4e911a,7552fa16,ccefa4e3,dcc90083,e5a19e31,4dfeb06b,c900475d,980cce8,7d5cc091,7a28c18c,2fecd5f5,cd2cc66d,e26deb61,1c5acb89) +,S(d88b6907,3abccb02,2e235e60,4f3e2877,ef979f85,a5b3fc4d,fdb166b,a4155d9a,1eefcc82,69a20b9b,48d30d00,e7ffd021,a9b7b171,378a299,819d6e6d,19d5ed24) +,S(b86c5281,cfb9f3b8,4be4f83b,1d13d33e,1f6abfae,bbedcac1,63362a76,8740a827,c1a32696,fc1f8507,289f111c,85483b23,23d228a6,773030e8,dcf30f6d,57857dbe) +,S(d2813221,9c730094,97c257f3,1fbeaee9,1afa001c,84e4b813,d7ee2452,6454c640,75d722d9,7111d6f6,b6324598,8720ce39,66fae55c,3d81e4d,ade294d6,1269b4ea) +,S(445addf5,bf941ace,6b4aad55,6f174ba1,ee793bf4,9f46295d,19fd8e2,807f8d3b,cbe249f1,fbb39f8d,93079d0c,e84302dd,52212b6c,828a1626,b7446f91,4f6727e) +,S(a2dfad8d,66fd47fd,38fbcb74,b983d366,c57a08d1,b04f1acc,4fdf047f,100552f2,63011d2b,43822a21,ddcdb1cf,ef4dc0d2,5f595165,26939761,953fb738,77586c9d) +,S(c4e84511,6644466b,8c573b8e,c7dd3788,ecf1c6c2,63ecfabb,b13f697f,2b2e3a7c,1e53964,a70e83a8,ed9f5d8a,b6b79629,7368bc5d,cc90e6fc,4e8e6f65,542f63cc) +,S(63c4cc2c,cf368a04,be814d1d,81fa4250,653ebeea,ccdffea7,944801f6,efee1aba,6fc2bb4,a7e573f5,fea2cabf,abd9a145,c7c36d62,11928341,e9553e8a,b38fa90c) +,S(51eb8782,a3445ef6,43f01634,caad6fe2,29585dd6,f073acf3,62cfaa3e,960343c6,56d20f56,8e6d868f,491b6e1b,80fa5c88,e3d625d1,433b1dcb,5ae2d35e,b40a960) +,S(d89ea50d,ab6c4c39,48fc4d4b,73d7812e,a6b59ee1,8e7a51e8,bf6249bd,ec59d068,a1ae85aa,e842ab60,95feec2a,d6ce6206,e81a6e76,7f0b7b20,d41cd28b,6a8c4258) +,S(d121a6a8,11f953fe,a90d8f3,4487d654,fb48e4f3,c5ac4db8,3e3f50a5,cd7bac9c,a5b9e6da,e07a0f1,dc1695e0,20502f55,5fbf136,df11b586,4ecc63e2,d7061a6e) +,S(83f7dd06,e5afbb3f,7b2563f0,faaaa3cb,20c32db1,5bdaeeb5,73219814,caa599b3,c452f49,1e4482c1,1cd4bf46,75d74c5,ab054163,b6d1b837,dd10aa05,950f199a) +,S(1f5ba7d9,b4cf8684,cd073892,4aee1919,1f611d78,a943d49b,509fffa6,31fdc19,a017e13,7a8a199a,e361dc18,527f0135,51e48b02,c2f7f102,a6c1ffbf,fdd0baba) +,S(d25fc73e,a83ef669,c2e127c7,1615df3b,ec61ee38,4a6b3396,cc52066e,c3b70b8b,9b5d55e1,c8dd008f,19b5e989,363ea737,e7d7bea3,f7b0d9b6,951dd78e,be6c5334) +,S(d749373f,ecc1814b,dc8ce6d1,2ebe84c9,e09806a,9cbec814,cf98dab2,4a46ddba,88012af1,84f7ce23,730a3a4f,191d0687,4d5652dc,2be47214,61e9ad31,b39ee397) +,S(8e05da99,971ba37d,38e7642b,693856af,a90d7206,2d360611,6c8f506d,68316b9c,73de534b,5833287b,61f3f985,2723be7b,e8e22ee3,1d1ef4fb,f45d6931,827e3db4) +,S(e71e83f1,c6b285db,157f4a14,825aa540,558a7853,673900aa,fdb84556,ae5c891e,e37980b,c180e3d2,481d81f,f9aa33cb,b297ffad,7dbbdd79,4fc013f5,43ee679f) +,S(bc66d644,dd9da12a,299557d5,fd35993b,ab05ac8f,bdd3802f,25b35890,db8eed32,5fa8c7e4,bdf77750,573a4ac7,1681ca04,4f796ea9,c8379cd5,ed55631d,bfdb8405) +,S(537f194e,efe43985,8dbe1eb2,8e27448f,fd1b554a,b12805fb,3af43538,fe0e37f7,e82018eb,447b2810,1502453f,db4c1cb6,666330d2,ea3331d3,f79d5652,a1d64af7) +,S(4af2a9f2,e0fa4b4e,731dbdf3,676538c1,110f3232,7b8f2766,a7f489de,8aec3b4b,cf2e0ca5,dc830856,43151cc0,1507af4f,d84b253,2f0fdcc9,6489baf8,6c1bd4ab) +,S(81369bd2,a4945c15,389aaea3,4e2855d7,6343e200,a9407ed,d05ae927,5585aa36,a9b4ba4,e26950c6,6648b573,3c0c4e5a,22a51e71,ac3c1fdc,78403eaf,3a667161) +,S(1c0813d7,ef91aa73,9e3a6f0c,e3c7edcb,2b7117a7,2ad1dad6,1aed130f,c61cdd3d,e3390572,67ac3bfc,5373cc31,14bd0f38,ccc3cb25,862b243c,912c0aeb,98bb86d) +,S(8a651923,d2622057,59e5f82,b38bfae7,dc922488,749ea56c,e43f0f74,c268f9ab,f3df434f,14f67030,fe888ba0,185e25c8,38520bf6,6e85023e,e4ff4f04,b056d9d1) +,S(89d98548,30a2a572,dbe91018,e66b28de,835dd02b,f793a469,2de3d720,d70e8f43,629868e9,9e434bfa,98bdc4,f191a08,72e68768,ce8a918c,7c2da42,75e5cb3b) +,S(97d0c83c,5d83d399,c567ecd5,dae551fb,7f1838de,1967e84c,7f053b81,62965fe9,fd716683,73347fbc,407543b6,70734733,df623a55,1766f55,8a02059a,2ce55c4d) +,S(20807bb2,650e6d82,38a66ed4,b239b59e,fe073a5f,9cbf0d6f,e3d9a16d,be427de9,46a25a29,c104c56d,8436155f,64b1d84a,b974fb2c,951470df,17a9704a,be5c1f9a) +,S(3cbb1786,945bedb5,c8ac2d0e,dda1b0bd,ee314cc5,faf56b75,fa878bf2,b218a8f3,ddcec0c0,d05403e8,ea2094a9,6ea910f8,3261932d,701a2ea0,4e93581a,7e4b7275) +,S(961d0144,1618561d,c3504859,7e1701bf,35412ad3,2d04486,704e5593,b9278734,7e137d6b,2060572b,ef66f8b4,c8ce535f,b858327e,26dc2295,6ee6c94b,c83859bc) +,S(2814918a,115ca2d,688f4358,9010b7d8,b8b560f3,6a3dce2,8fcc05e,acd4845b,dbf76f51,ef80e324,8820cb0b,bc7f0c2,4d50ae48,6387d206,c333222c,5f959dd1) +,S(6c4f3b00,c02c19a5,ddb0ab1,798929ca,222a9538,b641cb3c,dd61736,77c9442f,a91d13a4,d3888b82,eaba5173,3ff76fae,8022fb10,8cd61f19,206cd78,7d1c99cc) +,S(8f48304c,ac37d495,fa1a2ff,2178f442,4af030ca,70662a1d,c750bde,5f5d8dd4,ccff6176,47cbdd3c,3d0c588c,37a98723,c2b2aa14,fd17cf9f,ea45ec72,eda8defc) +,S(ae3da559,e3fce253,f5c1fbad,8e12a52d,ee989ea9,8552a192,93f7db0,eaac9405,430b86d1,322191c7,9aed5bb,12eece79,f2519bab,17998346,8aa13b69,94032ef7) +,S(90c093fc,27fa9de,66a1fdc4,d921e5da,6f4fa049,81cb6f91,e085f89b,96561471,1bdad536,4ae198ae,bbb0ff88,3bd5dd2e,dfbaa91d,e989f45a,30befa9,76f2db23) +,S(730a1c4,5ca28743,538fcacf,a65b7d90,b6f4b1c6,87364cd,53dd6585,328eeabf,7420e8da,cc64a059,b46221c6,c3adb4b3,46eceeb8,8effca39,1a1e36d0,d665257b) +,S(341eabe9,66c6ce4,65ac18ca,1eda053d,4e6137c,ac0796d4,36a942e5,99ef897a,d298003d,fdd9f529,c1977b3,ed426d6e,2df46098,539b20ef,c2011a36,b7e49cde) +,S(8f7e1b2,cb538fce,4b4a7775,90d1a95c,2fef8331,9792c0bc,8d5f3493,54fca169,71b0849f,cec62c5d,fdce37a2,61e2a06d,32b3e0de,87c8aebe,e5a95cab,b0c3f798) +,S(c7ea6b43,ce1e0e83,819bee9a,31fba823,3ee03a6b,14988b98,e80aef2c,eace0d56,e9f1328f,dca6a16e,2100ad40,138f9810,17e37e67,7e7ca747,c3a57ad9,24b8891e) +,S(b16ea5c3,b03e58b0,e6c217c8,6eacc4b9,3032add4,30acfd7a,e50eacb9,a0e5c1fb,507fed89,5c14380f,ab9e54e,a3624e5a,cbdaed64,b2712f88,48018b90,7a88f47c) +,S(15cf4de,7c36b72d,f7b98c00,8e928731,a2e71c69,cd0427f3,ac9264b1,5a5fd487,3865beea,6b36732c,5ecfd21a,562ab253,d618546b,c1c24745,8881b20,643d7e2f) +,S(394efbbb,fa740f53,b1e70eb9,d12671e7,55337357,b982921a,79915acf,ddd18218,8f1f1980,6c1d631e,6519aadf,b563dbf2,37b75db1,54baf06f,6fde8218,a0a68eb6) +,S(e6c3e152,27453d32,cd4449d1,ab1ad78d,58f5bb6,f29d813c,e7c6628f,b284399f,89d87957,4b640a87,abadc6a,dc51a533,838a83f,53de4448,9ff0640a,502dfd62) +,S(e2480000,9db30642,f925ef8a,e31c54fb,1340e88d,b6d633f8,415ceac5,f583cee6,39ad28f1,8ecd8302,5cc1fa72,ae4e9897,81318cea,9e506794,50abd959,f19758c0) +,S(1c134120,3c2e7e21,f5b10ecf,402d52bd,33db3278,70cdfcec,f3b277e4,78f551f4,cd6907b,57cfad79,5e14e7c3,b2a06a46,17b7a27c,ff476bfe,38d68d0f,1470dd63) +,S(6b2fbbb1,515c261c,954a0be0,279a1cd6,63daa083,1fbd58c9,c69b7be7,ee6047dd,d38ef59b,4e276fe5,6f1f2fe6,74b6974d,5ef1f4a9,74abb2c8,17cc68cf,78a164a) +,S(dd5098a,8cc8ccf0,7db82096,b52d1fa3,6bd26c2b,57f0cbe6,2ca954db,1773e9cb,a198ec1e,71c53d73,5b50000d,678d7d93,de64a72e,8ad018bb,f515b4f7,c7840aff) +,S(f6dc494,3baa0613,59a000ab,3aed3456,1972d425,34df86ae,3eb8e5e7,cae23c22,7150f3bc,5a968248,d8c71ea8,32b116db,73ff34e5,35ec1e6b,64b2474a,947174dc) +,S(e115c926,5930dc67,bda89798,e267dc48,12c06d2a,a05e4a5a,6519b0bc,7096f84c,5b0dc7bc,82b61275,2aa17a13,c1fe2cd7,6b60cf1e,ceaa9234,ec9e6609,7b2018ec) +,S(6687f498,98a22d8,58ef88a1,bcbfb446,33d51eb2,6c1fc2ec,eeecdae9,e0960c56,fd1912f5,7c0e691,23977524,ba58ea04,5757aeb9,309a5b94,3c993a93,57475ff) +,S(366ea4df,3aa8da52,763b513c,efa3c739,af61a497,6fc4c884,e879ddde,c2457d1c,876520ba,cca3c711,a23186a4,833db7c7,14b3de4f,fc86e8e4,cbd61cc0,9a48f34a) +,S(f7951805,eaddd012,2bed030,f3013e15,6fec02b9,80ba8ff1,1a0b978a,3fbeb778,b255b5c2,db866de0,a145a108,f5eb4b69,271c13aa,8db75fc9,f467843e,a59549a3) +,S(c77d217c,5c7b8fbb,f7bfd244,b2a2d2db,372d8217,43eb4a03,47858678,471d8be7,55573d9b,dd16bda6,ad916820,874d64d4,b260a489,b4a93427,1ea5a79a,f57dc5c3) +,S(c803dc3c,1432ac63,19db169,6d7ebc16,58021b8c,b92c0fe6,a59d1efc,2056f214,ce8e23ae,c7dca471,8666f61d,d7d8bc10,e06d1929,7fbad7b7,7d45526,9e207b09) +,S(676c4c3f,617b661,2affb2c2,dcfe072c,ddee8b29,dad9124f,dd24e87b,52a80b88,6df8c35,be6818bc,b6857f47,f59a11b,e05cebae,ee6c53ed,8cb93fa8,92c49e0b) +,S(8b0c8502,bfa15f59,335cc34,20e04c90,becc2308,12d40c7e,14fc3e30,88b8f34f,eb75d312,9fa4db28,27d20c93,de9c5cc9,4237bbb,a9710371,f767f686,e5ddbbbd) +,S(6ea07148,5594bd90,2d0d526c,28918bb2,cdb7d1cf,d3ad0b1f,a3ebbf76,71a2f90f,3a30be2c,2058cb43,c6f8ae98,1ce8986a,8b4dfc3d,81d49a80,4e40c81a,a1fc8220) +,S(aba7df4,8bcaa5e4,c4fd9a21,6b4bb3fa,27617205,693763bf,71b8b214,9cf83c48,6b1b719f,a0633abc,4580a9cb,9c1210a3,3e5e3bfd,177bc76,39057e51,3fb9b3fe) +,S(ccfca0f,ee5bebb7,26e2062e,2b5cd592,847031d3,5edc7767,414af809,9b3ac2ad,135b2ff2,4e40f04c,adef93ed,ceededb7,380c1e9a,e32a499,467af149,cfb532cd) +,S(9af36417,f3076595,42ea54b1,4671d2db,f7582ff9,b7e659a7,6465ee2d,4db88e35,dc5d07a2,58d4f5d5,ae649b63,e07a4253,8b8b3e42,c65a6ba3,44900028,c84df8aa) +,S(e2f308a3,e4d99e74,d6b37cc1,dc41d9fd,e98a4472,6e86764a,89fe959d,deaf922e,f5f8eebc,d9252e1c,74b9040b,569c9d5e,11d12af5,aa21051,8f87043c,7b47776a) +,S(a62581d4,c4fa4b6,aee11db0,8fb698e9,864cf336,578c536a,8a887d1a,89b43e35,b530ce21,bba9d034,d53dd490,2b76f25b,4391914a,5f87b6d8,2526f7c3,def132ba) +,S(11ef91f5,dfeaceaa,52f434b0,fc03085f,60c12ea9,4441574a,5725aa86,52c259b4,a2c81e79,cb5ad0d6,bf0221ce,2bf7497e,bc91026e,adf0e25e,6269dfb3,2ced7d8) +,S(ff549a04,fb86bf9e,3ad207b5,ac76a74c,2532a1a6,516327bc,96353baf,66269c5c,ef1088fc,633f639f,f0061bef,4c1e4c64,5897ba0e,ee229d44,d99be0d6,95e494db) +,S(11c9ebb8,893b6534,b323909,961bb8ee,4c90c854,52848ad4,18fcf223,c80eb7cd,4b0229e0,89a1ca0e,d60ce2ee,590211a8,769d333,5f4ef32f,4460f8be,940a0dd2) +,S(e86b3691,f8ae48c4,12a6216c,c3633f1e,88667299,f828d6b1,3ff88cac,e060b1b4,14d95d6a,61298fb5,1fc974fe,f3957db5,4aac7130,a1ed873c,cee5cada,6eec0c6a) +,S(e5b9550e,eaeed973,5d8068b2,2c48bd2a,608fdabb,563c0e5a,6c2b2351,24c49d19,506ff679,2ea7c37c,254d7ae1,a459204d,aca23016,93c1598c,2449b758,6d437de4) +,S(cab58ba0,cb15982a,c1ae5b51,ad65574f,55540820,d057e11e,f9c9f9b,a1388335,ae1c9e22,74958b33,2ce0f0c7,ef621a49,4d5b0ad,b04748c6,539dbcbd,6bd4ef18) +,S(715e4568,9bd663cf,e9c83006,82fc7c90,5ae2da55,42b0ea4,40cbe2eb,36e1eb43,58ccbf96,8860cbfc,6b03f6a,a5fe05db,14be0e3f,3d6224bd,ce6eb54f,7372aa85) +,S(df92f1de,4d22a7ee,6d2bf45a,5728745e,f59b6b07,29614536,722c7de7,965c0648,59e18767,f0e22894,be586a13,46950c03,88f1529e,cced0d18,50439dd0,e5bc192c) +,S(885dd01e,dc8ffd40,c5f26d7a,bcecf670,7a791ac0,b2332b91,12e69cbf,11399808,4ad58276,6e763ddc,3f4ff718,569f600d,8c764659,87ebd74c,d506c2,ba886ac8) +,S(d3fe74b6,17a1ab46,c773549b,af4bcbff,917c7ecc,fbedb63b,651b2197,89c1ff9e,b2e6bbee,5d84b593,d43467db,7372f40e,493a9fdc,c5d88fe6,5767f45c,837acf93) +,S(c3730836,74b97237,66d9e9de,f7b6d792,93faedf4,f7d86301,75862d62,d4ada8e3,b669a24,a31f8277,8686d2aa,6b2acd16,872570f0,8e6f06b8,394f498a,dc29f099) +,S(4ef2ace6,422be7ab,6a614e2b,fc43360a,2fdfcdde,51cb31c8,372a2042,2df4e100,86868f5c,37366665,fc6121e0,a8ab3a86,92ba1714,f5b8506f,9a3c3025,eaf9fbc8) +,S(51110764,573c540b,813ebc4e,79d59277,67e30ed1,70a951b7,9ed05f8e,8d142cf8,ea8890e4,9668304b,63fad75e,33f42601,f2649a21,724fc495,61110e79,d7ddfea9) +,S(36cbfeec,5491e1c2,f853d98a,275c1baa,e74dca33,2bd3d830,7d896607,c1cb651c,f67659d6,677b44cd,33c0cedc,d5886ad8,90eac77f,5b393fa5,6cba1077,54489eee) +,S(d1ff3875,e1ef071,eef96f05,bc19d356,aeee18a7,f3892f02,4d07b43b,c3f09dbf,ba825e43,72b4a644,dcb5b8f9,62e0099,ab75ef9e,34b54874,f8d68197,ecbe8eae) +,S(45e7bec6,75819b22,f2761ae7,575ebd6a,8ef87727,a15e33b,3edc7ead,dd58fa5d,3482080e,edaea330,240b539c,7d6a2e42,2cbaf40,f93d5052,28c773f9,6d80fa86) +,S(8ca5d7e4,bd79aebb,bcc5250d,c86ac1df,373eb3ce,1d8cf2ff,5916cbb7,1e8e016e,1af3f417,afa5c1c7,89474f79,a0755bbf,a9a268bf,fdf242f4,c1599dc7,b7cb1e55) +,S(56bf2e78,e7c43841,6324e581,7330a6bd,208edee5,3b5d61cb,a141f9cd,ec3002c4,e8f91e4b,3984a946,29060a4e,534bb4de,f345879a,f4884214,63dd0299,2bfc2fde) +,S(af152859,31540f00,1be4a65c,e3f55437,f7be7d8c,db0283bd,f96bf71c,c004455f,1f58be49,77cf9b8,b7ddf7fb,74f7356d,62b8fe33,6bf798de,3dc435b1,86122b40) +,S(2f4d8117,bcffeaab,7db186c5,7aedcb00,80d67b36,a560c5f0,e323b7d7,79be70b3,e0a50d82,80677ee9,caafcaaa,5d7d1747,3f4980c,73831f43,29b15452,94e71829) +,S(bd96815c,e6b6d0f1,3688cc26,777c42bf,50fb8cd8,cd0aa082,94ad498c,620d1f4d,8a882c49,6592b186,b0a4071c,b0b556ca,27f2ec82,417aa246,ae24b415,8e4ddb23) +,S(cf64bc04,e0796fec,112a5ef1,2c3cd909,5c041b46,2772b818,3e6656ea,16d046c2,6a05162a,eddf163a,fc2cc91f,34f7a7bf,41660b4e,a8ac7af5,698c259e,47e77e86) +,S(3dc4bd0c,2c8253e2,4ed942a0,7f45c2c6,390a9d07,6d334f3c,80dfabe9,282a86c5,e0994668,7cc9c6ca,e2d04840,6d34cd22,e4f8e271,da4416dc,77e59af1,7057c43c) +,S(40e00b89,e58de390,6a56133a,fa574019,51be1efa,6156baa0,45fb3987,94f7ff11,cf675e01,1f20efc4,24b882fb,b7bb9ca5,5a1134f,b628acd9,a597fb97,968641d) +,S(5626496f,1f49190a,48929e9a,403f9f54,319a6b1d,301cf256,692cadc0,41301c27,21702c7e,2ee0efcd,b98a0170,110e3495,e23fe5b9,9674bb0d,b6f09e57,fe76b48f) +,S(2a2c8f2c,a580145b,a9593b87,dfe0dcdd,caa3cef0,20b0e2cd,3792da6e,2f989a11,4aad23a0,e01f6a43,3f6c2a40,f480f945,d45c89b1,df42d67,acf6b0da,3f46bba8) +,S(68a74703,a88b88d9,ee974a87,af7b1be5,1866ea40,ab4cae9d,90a4c2c6,5822b565,3660b266,c74b8be1,c98d3b9,b1f14dd7,e039b476,733a1322,d2d7d2f6,9ad59700) +,S(b50ad45a,4898f77b,c5544dc1,cc8c0515,3b1e15ae,d043d2f1,40bf9dd7,29e413e1,1a59e623,3bea3be0,5713c06,b18badce,69b84693,636be68a,532adfa8,c617a773) +,S(df18b016,3ad015e8,da7e87ad,e6fa5312,d665c696,e42e466a,5e9e2a82,18337c22,532d4260,eb34306e,691f42dd,c215ffdf,2f6cf3ef,cc1363c6,46b8921,ccf277b0) +,S(405bc408,446bb0bd,49eb838a,eaadbf1b,27d413ef,a15fdec9,86e8446e,2c799391,1293bad0,ca26e4a9,f80dcdbf,1ccb70d3,fca9f403,89bcc331,e917d7e4,bf4d0b3e) +,S(1230acd2,75b02450,255fdebe,dd0ae807,38f081bc,5faaeebe,4542664b,ec57bb15,aa31d16d,b145414d,acc29c11,b0ed9fe4,fad90a7c,451d9706,4f7ec6fd,75b15703) +,S(4015c1de,3e09dc64,9ec990be,898db42d,1193e1cb,81956b08,da1c15c4,b9a2af48,d58b2d0e,553dd49f,ab07e5dc,c5a66543,b7dd351d,84375fdf,2ce1db56,8185e67c) +,S(f3da2f12,7f47b9a7,192f00a1,5576aeb0,8bc36211,7fe1246,ad61421,85f79009,865ca0c6,4aa629af,b84f761f,b26a4938,25fdec29,ce1d4a66,9dbcd138,41bb83c0) +,S(15f1e896,f7c7cc94,f3f921e7,6dc1e30c,f0d43b99,e9fa0352,42e56a4b,90a0c736,61e85195,215b864a,6f5bd52c,d0274526,dbc80af1,4395f9d1,ce60bf74,27c18b33) +,S(3fad3455,470a113a,2f773ed1,258111ff,da926643,f7fa1cf2,8e9f7b80,dfd2105b,ffbe436f,a1975bcd,ee4eae51,8dece7d0,cb34aeae,ade738d1,b39f4c6,6ca08a05) +,S(62bbb9ac,282329dc,65ae7b4f,bd15dca7,70a088e5,45850aaa,bc4c09b1,9177f92a,9c000eb7,f6104a03,51e1bd8c,d8ac8f7e,22578291,35eea222,866f2632,2573dd72) +,S(9bf86604,a46cf253,324f5608,b7bc87c8,72939597,131f12c0,eae3482d,b1935e42,e9f2dd2,15cce5af,16149d3f,1116d79,74f51267,1b575f8f,6ab6367f,fede26e9) +,S(a2ec976c,b5e72001,a25f95e,bbd7d354,2f3b174e,80ee3752,db082910,895f723,dbcb75c8,365c6248,c52a83fe,1c79d7b9,37ca8ebc,5060ba7f,60b881c1,964105d5) +,S(dd91f713,ee212c4d,f94b1fc8,c7f246b9,cd162a9c,5c8988b8,f3adff0f,fdb0aded,efd02821,c4eb853b,bb8c55ef,c54f41fe,7e53582a,230d52fa,c18a53d,ca40c81e) +,S(504e6ab0,c47fb3f4,b6b74a7b,1e67f6e8,c28ef108,62c2db35,f16f31cc,e71d423f,e7adb424,3200ab4e,71e50453,2d849315,1eae2247,50ff7a59,52bf2656,65b3ded1) +,S(1a9ea377,27fad3be,155f7ed5,1caf01ab,1d30195b,1629fba0,dd04b7af,c1a4b8c7,2140f144,e531dab2,22cd4137,921b4720,59efbd57,c1c97367,ff2083e7,f2420206) +,S(d76324e8,31920463,d5d94ce8,f9654393,89d97ba3,eb5e91ac,56898343,397b34aa,189631be,df5d46fe,fa8f60fc,a8b22fc2,ac987d23,b21ff267,560863,6ef3a72b) +,S(de87a315,50a6f146,e681d8a9,f9a7cde6,7da28c7b,5cd7a70b,703695e2,3c9bddfe,d33a05e7,77ba9e6d,155bab56,2b8cbba,27f4cc63,13038f7e,d193137f,d14b8502) +,S(d8381e05,7fbc1910,8b5a304,fa984e0c,cc0f5d27,303a3287,9ecfbf73,a1137974,1dc513d5,ac96238c,79d8f740,c855e045,e5c4e567,b3f44744,abb3bf46,ca394e8) +,S(69da86a3,b355f0d8,138bf809,79e314ab,7cb34e64,45be4842,b8f3810f,11b2ad66,7db776df,68bcac9a,c0f8f55e,8ee6a7e1,771d4148,1f5d953e,e9bf832e,cf713cfe) +,S(698f8b8,66093996,e2e357d4,d671d21b,230726a8,84079fbd,766332a5,4e7f18f3,5925e34e,dcab3458,ed959aa,3903ac93,c39b8ebd,1c562691,3f844150,d41ad20a) +,S(37274120,6cb7047d,aa97274f,b12aa8d2,e5eabca2,f3ab0b4b,daa3fd7a,3d5365df,30d36bad,c10337a2,db6c30f2,e8876226,5ccc6a1,7104460a,6f438a9d,3e8e9300) +,S(4e8c8df7,30f5d411,77355739,84a530b3,8ca4012d,3d4c8ce,f6c00689,b72cbeca,d9f7aed1,f5073c8a,8d2948d7,86ce6dd9,93a405ba,393a20a8,719287ce,797163) +,S(1e62c3c7,16e4f6ca,77b6d325,8553a5fd,59f67df,f7295115,cd6e4bb1,19b4b5aa,7df17da2,a7397df9,e314fd8b,6b03d293,ff7325e2,769d7477,ef3802a5,7d8010a0) +,S(c79f25a4,664cae13,d0971832,fee6a316,ff338f15,40c1f3e5,95c707c0,6e035db,5ef7879,c46266ca,7b342264,1594e81,5c189ce0,f057f187,e43a61fa,10330e85) +,S(768a47a3,64304a44,34b097e5,132edab2,b9840584,6e543dd4,755038da,e355cb9b,79896b63,eed7e866,32c33041,d037554e,551f2a73,6f2c2b35,4dd7d7ac,f6562344) +,S(131671bc,604d622,eea3f06f,200edb52,f7223fc9,3fc8d4e5,496af1a9,f72e56ad,5a6614d3,7985f503,2ad7a53,9b99ccf7,7c453f94,3975983c,e948dfe0,ffb867d6) +,S(3b9e6127,48d11bfc,1d2d0081,24e79a9c,604bdb94,6b25ac57,749ca6ef,302d7a58,379e7cc0,fecf689c,f905e84e,8516388f,3e1cb41a,aab8192c,aa024de0,3332cc70) +,S(4f9fdecd,10e8cc9c,f5f2573e,a2fd231f,b1313468,f516af1f,76af0eac,9ad51d76,26d6731b,71382ea2,1172142,fc5e0f5d,d0f7afa2,c9409fdc,62bced0,e8246194) +,S(25f313d7,ad044b0,538bff0a,ead5c689,d5fafec5,7cddd9a8,31b9a4f,59b848e0,f28c77b8,9202c9fe,e64c0580,75a972cc,a4839e20,42c32b66,517605d5,87470c40) +,S(24a8d407,e26c4cae,3f8dbc18,5820f345,81bf4355,7ad036a5,200b9b7a,68bb8d6e,fc6a5d96,4fa25fad,4d09a1a1,a4ec4697,818e46b0,8cdefb70,367e3453,2462b98b) +,S(ef4df8ea,5cc100e2,768aeab3,112c7ac0,6077b754,75cab97,df3ed51d,6d397f4c,fbf555d2,27eb051f,54965eb3,fac1e21b,82d216ec,807b1485,5074ee56,1ad70883) +,S(80c9d594,578f6e4,e8462dc,228cd99,9b621493,63d55cf5,80e1c524,627055e3,b6d5bf04,97b44e3a,7c7e52e3,28f63214,5eedda41,f80c44df,c7ca6d29,77436f24) +,S(35961cd1,57bc1774,40dd41b1,6a81e31e,52349a5a,e4085248,fe4a19c3,b10f7a45,b999ee7c,b32f1051,f0e7eb9d,4689fb30,fac7af1e,b410d53a,85e79f27,70a7566f) +,S(4aa49d09,32a7fc5f,77a76a12,16240142,596a82d6,6b59d388,24f0d8a1,e7f70948,adb5b12a,5e40bd0,a14c174b,13c242c6,c5f25ee0,642a6265,60d293d9,64a4671) +,S(110d8320,a9b2c5d6,5b06f0c0,cddd243d,c83cfe4f,671db970,d1213780,f6c4af0a,a97c2689,5c7b6ea,a3a02564,d2af735c,9b43ceeb,9f6f2557,3fc468b0,467b12a1) +,S(d01abcdc,a363b065,d8d2bb08,388c3545,cc8ee88e,90ee66c6,18a9f575,c0caee80,317409e4,a70e30ac,279914d7,135f9d18,e19fe520,4c83c472,5f86a614,1863b4f9) +,S(cea07679,64506753,8dc24b68,19bc3332,f320f16c,61eb7b85,96e25bc4,1499796,edff87c0,67e97ced,4aa330e4,e9dbec3f,d800934e,ed7238f7,8e97a46c,a6ad9ea3) +,S(d4463e7e,da5fcdd8,8ef0133,a5dbb1ca,c93aefb5,64581da1,3acc3871,cb94ce1f,bb1efe84,81dff341,dc7a4a8a,c2e44ca1,b071bcc3,81e7ecdf,4d4b7edb,6996547d) +,S(89cb575,5e9323b8,7771a2d0,58dc78ab,ad8bba70,6f845a8e,9a45a16e,ffbca1bb,f7e743f8,a24a6728,f8e8051f,5a303d71,f1f47059,202d332c,23f3a293,9ab97e37) +,S(d035032f,8e8e955b,b71006d5,a3b098eb,7dedb73f,a15d0d36,7e01c390,18bdea9e,1ba4cc2,fbabc437,a9d17ff4,f3c59f2d,2a416d2d,c07c0c81,c3e0a180,260bf2c0) +,S(fec9ff6a,e37da167,208b1247,b754cda4,6c6eb072,8d6b65b1,3754e2e2,eb3223e9,305400aa,27a59f3f,f19d1513,3c5a3655,464c6f39,94fd2ec4,562d7f85,fccfb767) +,S(3cfcc8e6,9e872314,5853743f,efd2802d,bb1a05dd,a03a731,77daf6ca,da9007f0,42b23158,fd0c1401,29298d42,a6cce708,743924fa,624d582a,94b682ee,4beb222e) +,S(4438bc8c,f41b7916,dfcdb038,5c9b6806,83362409,69ce8869,c294990b,cd340e45,78154e51,a4dd31d5,14885a18,b7185fc6,84c699de,2862f480,937c9697,6155ae70) +,S(d2ed1c29,faf76c12,fb15b514,6a31cc2f,c799cc4,5fb226bd,c38d3b0,176b5d52,54984b30,96d0c2ac,763654b3,32666baf,82c04562,d0d92310,cce6db16,216bb219) +,S(37f21b9c,d1243170,5ee6db23,eb578ab7,31f4b470,ab07e1e1,68e69bc7,539b170a,afdc95dd,6379244d,cbcfc811,54aa1917,e8093b54,8ec2be73,5867574a,82ec10cd) +,S(73fe29dd,54c8584a,7d25641e,c62f257d,400f013f,763c504f,f0a3ec02,d1ff8067,197ada53,ba57463e,e23b9831,ef8a6a69,d3d2f84d,c7225782,e7569603,fe1d1c83) +,S(56b27676,f0e88c45,3db1819d,36a73d03,95aae3b6,59f612a9,fe28714e,20bc73c,98660256,fb7d7d75,aca14107,dda9e7c2,28459341,ee6de72,9e463c2c,17367149) +,S(fd898f2f,e7f918a4,61f8e57e,f30380bc,5192a5d5,e1f520a0,5b99658e,8d57bf54,6861b3c3,5b0f6943,48bc4886,15eab8b1,36630618,592ac04f,80cdd632,aa63b620) +,S(fef75974,2911ca2,8057e141,6288b351,ccf2d490,634c98a7,a80153f,e9dc6929,9d5d0031,3417797a,83f0ecb5,d4f45890,d679660f,b1b19686,ffbe060e,deff716e) +,S(2c4338aa,18a27e60,d1daaa92,3d837414,f199f585,8d33b66b,471c6562,c8324bb1,13c28f36,25f2b273,8646cda3,5a2a729e,eac1de3d,80430cd1,6a0f3a9a,cb859fe7) +,S(53d6a5c1,deb56159,34416235,c2f597af,f6e10ed5,444d15c5,d9ca82b6,8e1820f8,26a5d559,cc04f53c,6b1ff3c2,4d5a62f,f63e50f4,b7c1b619,9dc54c20,628364c9) +,S(e432c338,e550a635,79ab747c,f01f3ffa,9e39d066,b221fbae,8b44429b,873decd5,297e10af,3006b09b,80d0ae19,3c1e8b3a,80ae9051,3dd9944a,444b2c7c,42d0066e) +,S(a61c5ac2,60f3048f,92cc2af1,6d3f6a4d,696e543,f044192c,9d840962,493f5cf0,1249d4f,83608025,331ab42f,bbe338b4,727a5ccf,b086aeb3,f1d9c96,26859158) +,S(a2f37e43,c3c2ffba,c45ad316,e912b586,2a9ac698,f85ea54e,98fe9a6c,e1fa038d,93e95000,6bd329ea,57397b25,71dc2e78,a466c4f8,76ace5fb,36d945b,a6e9b24c) +,S(b2257994,44c2ed2f,3114185a,6ca617b4,bf4ac15d,40d73b62,44a81852,d30260c2,fd4607f1,3d4ee761,adb6b139,3f87bf8,e8b05156,5561d650,a47efacc,5ef01dc3) +,S(d0607bf1,5317662c,73df9f40,805c9b3e,208ca1e,7fa8c04d,ab9766a2,8c7fffc2,f06da1e2,7e721799,41a9e128,e25ec992,eb030ca3,6161c02c,8ee31d22,388bd999) +,S(596aa391,d4831e61,55d80829,35a85bed,a1ea3190,a499ec6,374389cd,1bd5d8c9,cd9240b2,9845911e,47ad147e,ae55a0c8,639b994,8d72d2f2,72e89fdb,578d4ff9) +,S(433ec09e,19b7543f,a460de41,e70f63f6,6097ece6,dad9b5fb,f4030c7d,bc5862c1,dce03718,a609efe7,1858f6db,184708d1,9275ec2c,76d5e93f,e55a13e7,927cba95) +,S(343b03eb,c285418f,ad522784,f91707e4,f268451a,394e85d2,824c837e,fa48900a,e6595234,643667c4,bb885b8c,1ced3a29,a71212df,f2904549,ccb91de3,75787922) +,S(6094f67e,41b23bbf,4d594e97,b53391af,f10a978a,19244189,63814efa,ccd6488e,ea874289,dd943f7a,c109939b,8fa545f7,58359804,ad81ed0d,26cef135,cd138954) +,S(cd0c3700,bba5677c,8d0ff53d,f06bdbf5,c5adce29,64921c9f,a1591c91,ae0a375,720b88ac,9374709d,1919854c,237cc5fe,dc53b14,3897e4f,3502af17,d7510c63) +,S(d37ef1ea,95ae727e,5166dd59,bf5ee82a,1f215720,79d82e25,6369464e,d9a87cc4,59c5321a,d700c559,c92e500b,1d3a4589,15a88575,df9774e1,4bee7b2,ccf9bad8) +,S(238158e3,d58e7618,95f7a0b1,cdad8a24,3e19bfb6,d1c65929,ff08e766,e62c2b12,1f65fb1,8969ccb7,27d50e46,39c7551c,5b3f25b4,90b7d70c,cc5e4ae8,7293a0b) +,S(260a340a,5245a039,4a2f0908,f2912f0f,63ed68b6,aba66fb1,951128dc,9d542512,d30646c1,e8aabbd5,e758adbe,980715d2,b0b169c6,fe09c502,3beb7f5d,b5422be) +,S(7333eee5,d111e138,f6e0b2d,4b476ba3,6df4357d,b28c8e7d,f232c61a,6c3067bb,d427a423,a4de1e60,e8b73098,b8582e0e,18923637,c44c52ef,fa0b5f90,8ccf786) +,S(c411f215,dfb87aed,be2530c2,82a61e5b,37a0df71,1ce61fd1,25624b44,b7673eaf,ca3d89d7,d136fd46,161fdbd6,3f0b075a,afe90855,51e075d2,391f3206,382a0441) +,S(275b0a1,9dd09495,78298aa1,c4b62ff,11e715fb,6c3740fd,80d7ec03,3f2635e,30dcc412,faf3f389,c9919b6a,f96e7b28,6eb8abb4,ada80525,b9ca7eaa,f3ce74cc) +,S(9f774052,6818bbcc,b068c11c,b400eecb,da60c4dd,22353a3,4145e3e0,91f81617,a9e56fde,8f38116f,cafaea93,35ee3688,50da5107,a5a3e571,92f2bfc,1b55033) +,S(60fb35ce,f1098201,353bd7e6,89b42fc8,9f86dbc6,3eb400e5,3b8d16f6,28ae4358,1906ce1c,6a6f41a5,2f45424e,86633937,8ed56578,ffd94174,f4f85960,ee0f5c2e) +,S(1390a621,f999c3d,1737c72c,3235e542,99ce4796,d65c1ec5,45f60b71,19f4ae25,8f1cb557,b101a876,296881fd,5d30556f,55d739da,5122c0f1,43c04add,3485dbad) +,S(15f372d6,9be09ee3,8d43c453,dc488f17,42f53a7a,7923439,66946210,60f1cfcf,c6007ae8,a836a1fc,b5a4c0f5,e584fb7f,2c468d68,9efaefa,6303bd6a,beecb05d) +,S(bc2b2a76,17dd9fb9,e6d60931,ef2d5755,d33c7174,7e8e28e4,be151b42,14537d80,2582a69,b6e9b9a8,c5bb4b79,4ffeef15,96f383cd,670eb524,2ac4e7ba,375509e0) +,S(5f8e0957,61e307de,26ffd39c,92410937,5dac9c83,7a5a62f0,b0864cd8,a37f2686,d342dc84,7657354d,d524b32b,62f5f69d,5b2ecbfd,71831b28,565cae36,777534c7) +,S(5451cd91,9e849ec,b8dc75c7,9f939957,69a39234,38159544,dea98155,cb001c5c,e00d1d37,f9ec02d1,ae8222a,744381,4f16220,800f84d9,17cea9d5,9a9e2a60) +,S(737b89ae,9d9951da,d2b489bf,f2ff714b,dcfb13fd,829160c1,39875a46,7343adc7,ef9e2ab9,f8246113,726e5be3,5c1da48c,a6b4fca0,53d35dfa,8a3d826e,e48c5ced) +,S(8b80e227,9b0a91a7,6af48413,71ae6fdc,68f4f5c5,58de6efc,1ec0034a,36a26000,909b49ed,6ce8c555,25441ab5,1046956f,d25a3a73,5d979c04,43ae5891,fbd43df6) +,S(9db9379d,346cd59e,ed0c0d44,abc4baa0,3b7af170,9f034c79,151aaf54,69296780,1a8f9e50,918a104d,b525c439,bb16b64,179dc4d5,452c86fa,e87ab757,61e97031) +,S(3aa7c8c0,293e5c9d,fb50b63d,340851a3,88b1641b,b864cc08,fe776500,76f98d0d,974dde95,7c958b70,e0ff9399,d2d03da3,4dfc3437,c1ca557d,2240fdfb,3ae1d36d) +,S(26cfaf0,d27825e1,6014e5c3,19bb907b,7a3b777f,b6bc69da,5cdafec8,40d5b4b5,2eabc11,73729fdb,d31fabb1,722be99,e5b4355e,8c2b4bef,53b21dd8,3cf81ba4) +,S(ee495a13,bd1ba28d,cc26fc72,4cbfee95,3aa72852,57c883f0,cb09d6aa,1bdf3b20,b340a2f9,978013ce,8275b7cb,3fad5c1e,857bc6d7,b43782f2,1e737681,fb39b619) +,S(2e04dc81,831bb465,59d6c354,c4c6105f,41f61301,769d6006,adb290b1,b75540c9,d086cbba,4d221cc3,7cc96b20,adceff4a,6157ab9e,686d1fd5,5d56801,dcf4b779) +,S(557b5b41,b2b2e4c,598460ef,22888da0,aa2ec3a4,7980247a,e8bd465,a6e64c22,6a3c62ef,f80832ab,83a9d698,f61f7903,b7f64e41,9900950e,c7d79369,403d57b5) +,S(a0ea9ddc,e2797fbb,d384a1a,2c26d7c0,edf866f6,9addb763,dc44b112,dc1cdc5d,a085725e,d947778b,40a2baee,98dcf460,b084aeb0,3f96658,4f990895,b15e3378) +,S(1acb89f7,55a51f58,d8ed16e6,99a2294a,b2f4bff9,2fa2d1de,9883061,4ed4b5fd,5b243df,31c3bc95,79c47c57,58eef875,c18bb896,424c0293,22d729a8,b7a32a21) +,S(fbced690,b601e450,2f0ed32b,8c2ac448,31c4b327,a4ad9648,97637b08,2f3d3912,3235804b,549210ae,8cb5bdae,e5b1b474,e682cdfd,8af4acd9,8c0c19a3,cb5c017a) +,S(75339a0,82043d85,54ff592c,186a183e,4597a0ff,48f280ac,d760d134,9dfc6b5a,dbf1aaa6,8bd5db0d,8cdcfee7,de6635b4,b7877ef3,6da38418,5688fefd,dc584b18) +,S(d83caf1b,2994a763,77a2bba0,3c644e48,7f170d5,845a7d17,b8be8bb9,84b0ad1e,e479d930,6d2a405e,f0be6418,3d4f8dfc,a7f58ff,95df1e38,c92a401f,17745879) +,S(35fbbe06,39d9fc5e,d595a67f,442d7adc,ae6f566f,4641fb76,149d6c74,42af49b8,5eaf204e,6217ef53,1ab09a53,e6cf4d12,46d6c4e6,b71ae8ca,4e821474,94d00680) +,S(d5563a62,bd6fba1d,e252a5a5,9c03bdfa,6c570145,71cd1a31,bba43700,2a7c1251,2f83b6a3,2efa7b70,1b4d3262,9e7a8755,8b681d17,cff0b992,1e102b7b,f851f543) +,S(8f2a2a14,a834ec79,107153f0,ffaf8f46,5cbb46c7,5a72d07d,5e2af498,f3359b75,30ac7456,5c946e21,73bdbd9c,dc999e79,260445e0,dad2467b,97234789,a4de1184) +,S(74482ce2,45605bdf,f7d586f3,c2e343a6,8f9579f2,543f7f7,22a4b352,24361b4,b2cae040,9ae59ee9,bff4fb5a,34847ca3,e4acd880,e35e4d5a,5ce47b70,3cc565c7) +,S(ca0c158f,cd362d9e,3724bb2b,f07305a9,5adc440d,24270efa,2a8f208d,7f540295,9e1daa26,5a5effd1,29f62b,bf0f5c60,c0c2b73a,58ddbd99,c832125d,3927e7ae) +,S(9c5403ab,b8b04f47,5eb4ac6b,5d526784,8d237d3d,c36e8698,d59172c8,a9d9e268,89cd0c87,9d02beeb,ffb6dc2f,fa882711,2071cde4,ee71a7cf,669f64b7,d463fbb5) +,S(e6bf2997,5eb88332,64169169,62f49080,29072e85,797fb699,df05526c,c4ee0de9,ae9de06a,1952c472,6047bbb7,b967e6ac,db33a123,24b07165,d2caf737,3fa40068) +,S(ae4ec439,e4392deb,5e1b1565,2310d52e,9cf5c0a9,8753a95d,d7b51e1e,5889a744,1400b900,c3159d2,25ceac35,4e566d2f,4e6f057,f4664b8f,465b0f53,2ba61852) +,S(c6351ec4,27d1d6c5,64c05959,ccee21d9,b086a881,3f4d7406,ba8d0ec8,6cd139dd,b7173d5f,bec7a8da,89c4cfbc,a911687,f39a455a,9293640e,7d473bd3,ef2dba3f) +,S(fe44937d,a54556c2,a50d9538,98abc367,6da5d722,6c6d3379,20092042,d1219cbf,c5c2e2a3,174fffd5,74761486,669b0cab,5a5eb21e,be669ba,c5c5a4a8,46e404b) +,S(760dd500,b18aa066,19a3977f,ddbb6947,d092649e,485f2b6a,d26d01aa,445588a8,cac47a22,6da2825,38126d62,38751a4d,93daf13a,420be353,3fc0f7ad,db68c20) +,S(8bdd111c,e271b136,45d00636,f2d33c92,df570cbf,6bbdc156,69fd898c,ce4ea8ff,884f1430,8ab84796,d61e557d,abb4d15d,15114c0b,dc770388,6ca3ff0c,622df5ad) +,S(406c6d3e,79fed3cd,16d616e6,7fe004b5,4f589594,ecb7ca6e,24210224,c5b4eeb5,aeffee19,f82cee83,d4796668,8545f0b3,b8e61877,f34a0b23,c6a3573c,b98c9b7f) +,S(c645ea95,2580652e,8e05df6a,3d208df0,83e00eaf,50cd7d4d,a7c51458,324a41f5,8b4b9cc9,d3f00fce,332d2ae8,2874787a,6c6c8008,a7577ad5,d225f951,82e8bd2d) +,S(813cd833,dacd8916,76af5b48,5d1ff72b,df03f2ce,c7657e6d,249e79f1,f12d7476,c364d1ee,f5f1d5f2,7438c58d,ee926c18,7162cc71,383e9524,b80cbae,3cea17bb) +,S(fef2337,cf88e025,d70e2a44,e68c22bd,95371f36,14ad9009,f2ba8286,290495e5,b622fc00,8b0a0f9a,9a36ddeb,ce10d871,e5dcd7e9,65ed2784,21ab5891,6aaf7404) +,S(8505810f,22888b4c,c8bb708e,c1e4df79,a3a361d9,5ac2b259,acc18d68,e50b0952,b80fd8aa,b7196e00,3fe24ed,fc6742d3,e7b2115,967f838a,2ef00345,3dbd4d34) +,S(b7aa2500,c77effba,3e93a4e0,b09a0f52,92240fef,4282cae,4c8036ab,2e5e5561,85823a06,1fcf2328,2dde378,8802d211,fb2cda3c,316dbba,d30048be,1295d7c) +,S(6dd2e626,181f0007,6ed53763,32493f55,a77cf5,3c268524,2be805c,7da06c95,2a6a76bc,b3f96c70,78920303,c5ed3208,170fa969,6c5264e0,c3cb1d86,ca322da6) +,S(ff5181a7,ab79b40,a3afdd39,8ac729cf,e49a6a23,2fa46f9e,4ce0bdc4,696e9f9a,99c20ca8,b11b6a05,47e81074,8a34c606,140eb3c7,ce5c843f,60203249,62858aad) +,S(a5dfb758,32aa580a,790fce58,b4c04a1c,9de648f4,19ec33f0,92491275,e8243ef7,78a66f07,e1466785,edfd5523,99fd1935,1ccadfb,e3b25bf9,d5279ed4,1d0b9fd9) +,S(fc5e4688,ea6e4553,610946a7,dd3497e,a5f698b,82d6b439,6a21e082,a9aabfce,d1b32a9d,761df7cc,3d69b5be,d7aac28f,976be204,7b2aff0f,2824fb00,b70d697a) +,S(179fb126,a3cd9931,f135cbe7,2604d3bc,83cd986a,d9a7900a,17436875,d3507016,dc2a57cb,b0bd39d6,c8daf32f,fbe6b300,52cff0d3,12e84b72,c00a7d76,3578e749) +,S(af37b7e,cac16810,9c51fe45,b2d6da7c,3505c1e4,bdc88b10,5a386fcf,e30a6c1b,4dc24b79,61e9199a,f594974,32c9352b,4ca9d735,84dde4f7,a4c0127f,21cc17f1) +,S(62d66f6,b534cd8a,66236ca8,5b7de9a1,eeb49aa6,e65e5298,edd1a99f,96fb1dd1,83c05dc7,e69dcb3c,86dab3d1,153d93f3,e9861239,6e25d3f6,6a6d637,248f237e) +,S(6a40f396,1587f5ab,89280eb0,568ec9c8,6958b4d,d8a379ec,2ce2489b,7e451ece,74972d6,1100a0bf,7751a400,6093ec78,1fe16c82,baaf0e69,74142a17,a405da36) +,S(2838f8f0,c6e20e53,9ecba383,c6e07a2c,5022d436,904e5da2,b91b283e,40bbd6bb,6bbbf962,2b7c41a4,6b72a30b,d051551e,e1227362,b0664dc2,509404c2,819b4985) +,S(21e927c2,82cd4635,c9c19c00,f18ddfe8,7aa9b60f,f3000c3,2019871e,a443333a,6834c23d,e05bc59c,f6fc64a3,af61f049,7c247d86,f76a2ada,7771dd16,999febb1) +,S(d9817ec8,f88f9cef,92cf9df,1fa9099f,3f10ac61,fa641ddc,9f36e854,98822571,53c57b49,4d84c3e7,679060b7,c7c8d4ad,f2db0c4c,c8cabbc7,5c29ad15,80b963a9) +,S(6eaafe92,1994519c,1c61bbcc,c1ad6ac6,f7a2d0b4,fd88354a,6a458e78,17503e30,f29a7f85,f3e91dbd,9e011055,f47a5079,7f55fa4f,46a6b188,ea4694d5,a086b4e) +,S(2bd45f,1625722,2352b5bd,a6d8e2b8,e7d23c3,f8497fe7,348a8d59,97b5cdbb,b5f9d5a9,8ed6387a,41397e54,6b3ff76c,4c6bf446,3093e979,2d1f8748,7a6b725c) +,S(176d02ae,cf4f1313,ff804e22,326d6a13,8b641e2a,3fd4d38f,2c27a35d,f1f456de,5ac13641,d2f19a4f,77097a4e,8eaae498,2afe9494,9188e411,e03ed031,fed9eb40) +,S(6d0bfca8,6296255c,1fede5ef,8d04dad1,2b6625fd,7bc127f7,3f6b82d8,b257ca8c,3c5c434a,81c17be8,8101b5d5,ead55e60,9d9dfb10,c5ce1b41,484d5fb6,f595fc10) +,S(b67d3fe4,f6617324,a4063fc1,142ff4b8,2a605a26,8b8fa146,697db96d,570ecca8,63ed93c7,a95a0ea2,9ffd6090,5c096042,b5562997,4957f47b,2d5bca14,21114bf5) +,S(c171bc24,fd80dd05,4eb3e3a5,5f50c9a5,322989c8,a1213179,be4503d0,2fb1f1a,2ead84ac,7528e7ba,982fec81,4b68ff7f,7aecf675,281f126f,9f41a7c4,5deb2e03) +,S(c4936f57,96269373,21abb8d7,df07e4ae,48ae1f18,ee1f8ea5,6682ced8,ec911593,52ea3664,1b441154,81805582,dcddf216,80eaadf7,4fb324dc,67439b03,aaccb1b2) +,S(b0a38c84,ecc73fce,200658d3,cb43cbe8,e0df114b,5d1ff7a9,33158b67,b404dae0,40c381dd,fc600cfd,ff24d7c,988cd4ce,74c18fe,130f4248,2ced320b,b91f2ff3) +,S(1610da0b,300d59db,d8746d5e,17d71ab2,e7e9c1d,2b43b688,656e570c,60336b82,8923b2e2,fa3fd34f,eff4ad22,7f9f6638,745167d8,fb769b34,b3bb7e12,a25c892e) +,S(f6723495,10cb5b38,da909d65,333adb86,d22ed855,74d24d35,83294cfe,ac88d999,6f726bb3,891187c6,3c74392f,a1e3ffea,f55b9a9e,76e3b584,1d13dac2,e888c740) +,S(3cda21c1,d048a768,d2863f4d,1028459b,c9a91c31,2626940c,f762c074,23d85796,af05c34b,4a15e00b,b6ce97cf,501316a0,85ba33f2,cb536f27,324f5506,54a8f03a) +,S(24e1bc3c,84c0ce3f,52e1443c,1ce82330,b69bbdca,f09724d7,e616135a,d9f99c0c,61385dc5,e5c36e42,275109b7,9c22940d,3ee4c679,99802e67,3163c114,be7fb0eb) +,S(f9511548,94dc4fd6,e2907990,7da4a5d8,ffff1eba,4fe12201,a3ebadec,2620a2fa,d40669dc,1eee21c8,ee1110c2,def5de0d,4f08ca55,6758dd14,b6f3ce64,46b2fe4d) +,S(c6808c80,61dd7e3,f6fb5ae,d129d23b,c2101af0,130537d5,4bb99baa,1b8ee268,2fb3e2aa,77870909,993f9d91,bf670cf9,bcd5abfe,26ea9990,6f9805db,c8707f84) +,S(ca952b81,f79a35bc,effc9f2c,c66c9928,cda6330f,42c44f9a,3191ea5b,5f473c3c,aa53ac41,f34fee5a,2028f7fa,8ffd5106,23cf2dfc,cfe5a1f0,99ef3649,d7f846b2) +,S(679c1de6,521c29f1,9b0d3c5b,ab481e53,d01ec2ca,c719fbe4,16054bae,593c0592,61d4eff3,5daff1f,a4bb875e,bbb42722,9cc996d0,405c74d0,6ef0c6f1,31ade7c7) +,S(6f7ac468,d33618d7,8c59d849,3571abb5,1d445a43,af10fbed,c5d25b13,58170f76,9187ac46,f2076aa,5cf4de93,52e5437c,4cbd2220,d8070172,807e84c8,10a05090) +,S(f4ce85c0,86a4fb78,2f081fe5,379984c3,1a7aab89,ef9ac386,a6a8a11e,596278dc,89d6d9d6,75983a6a,d1dc4c45,a3dafc1,cf951dde,2a038261,b414eb94,f9899886) +,S(18b0b225,19360c19,739623b1,7850107c,32ca6b61,295a8161,fc9d2e1f,8d1e60d4,4d8fd58,98ba10a7,3aadae04,a9ed18a7,8c48bd94,7825f0f3,b42685e0,d391dcc9) +,S(3f75a866,537d022,f6b9b18a,330ecdc0,bdfa7aa7,5b213f4a,876705ff,635d8eb,fd0f335b,b4f41615,7ea2752,2b8aa40e,dcdcacbc,1beaa051,97ecc250,f0782cc9) +,S(58310e74,290245af,c4acb91f,20b29db0,f5195039,24b9f76f,16952141,875d0124,f79e457c,364b374b,43c8d6ee,b408cbb2,94fe8eae,c6914427,83a74757,c8b27f98) +,S(90692ace,4fd3c4cd,3c808952,d5ea0781,2192c807,4619b8aa,4274426e,feb7f6d4,3147db2e,7b3b8506,625c21bf,8803c5f4,e7250b0c,4523a6bd,e25e874f,76d1622e) +,S(154d18c9,6c441173,ba7b8d2b,5099d9d3,92ae7e0d,57419144,229697cf,52384f73,1c196518,31ad8cc5,ea72b3f0,ed0d30f,78b773a8,1f54fc37,29043a35,6fde93a5) +,S(311ebd4f,5f52bdca,290dc97c,73102ecc,421a0b07,4c53c052,11b0bfc7,3b6eb94,69d17492,eca55f53,72b04c34,6696454,ab779ddd,8c7eb07a,34c8971c,b5168019) +,S(f62a716,6976f82d,b62e48a5,1eb45464,c845b71,6436d639,a9aa0a06,feb57d0c,a0b93a32,3fc8c047,3c4198e1,5ab5f499,e3eaa4f1,4bf99a69,b3ac303f,34839448) +,S(c23e0cdd,5e39eec0,d3ad195b,19294bc4,30c11eaa,67c6e87b,a4e2a88c,60998ed4,a521d1b8,8e409682,bf7b7daf,ff45f697,6254b8ce,6c63985a,ad2d9cfa,559208fe) +,S(742ca7fa,a8b4a98f,28040f8c,15db6045,70353954,b862c223,c7979eb2,3443ebfc,251ef412,e97a7e21,292ad45e,46c40774,b97a78cc,7826e45b,cef481f4,a64b838f) +,S(622a14f9,7bd04407,63eb5d52,c15c2f3a,ae185395,e89dda70,3cc4c439,60c5592f,e5db52cb,ee60b303,69da59eb,87ce10c3,c485c239,ae1c849d,32e0e239,df4d4d46) +,S(3d6dbb7b,4e28da6,b731c67a,6c038107,c2ec325b,6b10e31d,9b7d5273,fc81e20c,f0b619ac,febe82f,8c4caf5e,6d4710b0,caf89c2e,1a20073d,66ebe05d,69fc2c9f) +,S(d450d441,bc191b5f,9c2556c5,a56d20c4,48afec13,c7e4b9be,320ddb90,b4c320e3,661be65,b5eef8e8,b357f521,d360379c,585c9e71,c27bd038,f2d63f72,6f6606af) +,S(82f9dd1e,ddb046b2,2b33bf19,2970e41f,c5df0c45,f1375133,fe1b365c,eed1ec7d,cde9eef5,554476e5,e775e829,1d38a572,1d055c4a,925c7eff,35a389b1,388e18d8) +,S(5227c547,834a79e2,d6fb0c3d,720661ac,7ec0e2ff,5a1480bf,3f31ac82,cfb2650d,dca309ff,621c591d,aea1bada,bb1be76d,2fa30a0e,1c83b4b0,d66cbd59,7612c0b2) +,S(3eac813d,7e2c8034,f1d58217,c4372a96,a1fcae27,b29ed9c4,e870034f,7faa78ba,94005cc8,7b8f7aba,143573b1,79aef942,c1519b3,9c63b58e,e420a875,7c4c8b80) +,S(9373c48b,50fb0243,b42762e,3b80994d,61986116,ba2c0677,a38daeac,7dcb21a0,295f694d,70f8295b,cddc1c76,141ed17c,a1cd8e5b,79909785,dad43e92,9247b250) +,S(14019457,db851046,42b51ece,50fb8d94,201a80e0,f29d52ad,1af35e4b,8d82c6a8,c47d97c9,df2816f9,a6147dba,7658b5da,f9588dab,8aa393c5,8f721786,9c498b9a) +,S(1b01f484,ce98064b,f60333d3,65d926fe,ee1cead3,c1497c88,8409be91,2288890b,6817b86a,86c98512,634bf90b,564ce109,13fad61f,c807a256,36a5d6aa,7f2d6005) +,S(5bad5660,f615f36f,6bb9ff3b,19c07b74,9519caab,fffd98a0,4520802c,88b6cb22,4d23780a,e6796a72,324c369b,1987465d,90540788,88987513,13dea0cd,69f90dc0) +,S(7044bd7c,29d2a7cd,d662bf16,90d5ee35,93175691,b62d68e3,f8f66ef5,8304c509,f263888d,52d74133,60ddfb1e,d1c09b9c,871d6eb1,e5833949,13d24973,5721ce12) +,S(186411c2,f90c5402,6445dc4a,4764318a,f3acd811,52c01dcf,d11d13cb,a8c02afc,462b9556,1bf18dff,8a4211d8,89f420d2,122c4ea9,7fda3d23,558b6304,d25b7aa3) +,S(62ea528c,185fd551,745c1512,6fbfd40e,5f8933de,4e1e3b95,92a93b0e,b762ec3f,276da42e,3c8a6755,6be49e00,2e42522b,e3b95e15,39a4708b,36429a94,4f6a86a3) +,S(5e2c7621,efa587ce,bd3c2392,a1b8dac8,50b15316,c42570ed,7270b521,a65d6cc0,c7faa23f,eafb70ce,723338d8,19bebd10,bae703d2,1e72b496,f2f95b6,e83d7d22) +,S(7e27207a,b80f124f,9694f143,9a0cd895,2c67a719,4075d9fd,1bb7c9a5,a22dfa3e,322b729f,e19d75f5,89749527,80f3ae04,48edf9e9,d8c24267,18812dc6,bef5e602) +,S(3de40b43,9077ea26,8d94aaa1,93e9c7cb,98e362a1,551b9b10,d5eb64ce,15986582,ba36c2b,e0f9d3d0,220eb47f,4ea66d01,59236411,2898172,8582d3c5,19576943) +,S(81e94808,7e89846e,6c7e5ad4,feb8f0da,4553e460,e3e4620,d87a206c,9d3232b,e216962e,4068a44,920e6a9e,f03efd5e,afae7f96,3497ecaa,dc741c37,7e9943b3) +,S(3056eeb0,d00a19cc,bb5a2ac7,f320ea3a,4e931187,498ec23c,daadc820,a34f49da,c6803559,271b265c,80257585,1f0a78e9,85abeaac,cb570787,f398766c,aa21fed3) +,S(9b1e1189,752fb763,7a61246a,7134145f,86b973b1,e44a5e7c,c59998a2,77ed64f2,f6793c87,9b8c380e,65296c8b,eaeb98c6,b66e0be0,d03865f4,4a09177,5dcfd332) +,S(807179ba,f1f9ce93,bb1f7dc6,e3c6514,99077419,472b9d8a,1a8cc4e2,f35c0c5,36807219,9966eb7,f18dfb7,d3316eec,54f1a9a7,7214d4fb,ce3f3ff2,935e2ced) +,S(60dd7b7c,cbcab93b,8ecfa461,8cfef03f,a74bdd47,9cb90a1,5e46ca7c,c1bafcc8,1d24d147,9987f779,90cde228,22ea0cd4,4236875d,943eda25,fa25096f,e16b8ce6) +,S(19daeb26,23383b3d,d15b0075,77a5e92f,bcedee4c,91996546,a7c52200,d243e4f8,12676559,3d67fe33,b1c01d4f,cae44be1,5f5f5e31,1149962,83ce8f92,f6485e3) +,S(f42f8e1a,813dab8,9e4db5de,27445215,c0fb1cd8,91c9a96f,ca5ae1db,14e84361,3cd2ab35,55705994,42070743,d01fe633,34819d2a,af95e97,6dbee1b4,e3ba2ae) +,S(1a2b774c,d5d0dd28,26d7c4e5,886d65b7,a219952c,6a413d2b,9fa8f765,73fe2bd8,4e2d0ecb,384a158e,e57da809,d065e39a,27830625,400c51ab,dffdf615,5d88032b) +,S(e9fa7d8,94c55075,1ad1731a,b322fab,fd3d17a,889bccc3,73e44e37,b4c2c880,67528cad,e7987d12,77c61681,36abe0c9,5dfdce09,33129f27,ffa9d36,53673bd2) +,S(5347f349,e54c301b,abcfd8cc,50f6fe6d,8fcd0fcd,861757d2,bc36cbfe,39f460b8,16d08dcc,2a837b6d,f9fe2ffa,b188a966,9d39181a,ed2aeb40,9ed17c8b,554e9d27) +,S(e20e8cea,4450bf03,149bdf60,e95f7ed3,69fd79d0,aff9fb8c,ef6e5287,830c7ddc,fa256932,fcc569e2,613bc0af,5f90263e,6db633f3,6cebfe46,4c70b043,9b886058) +,S(69132e10,b3a919a9,8a7188b3,e9afcf6c,2d53859a,5955e114,a41f1310,55ef8441,e6c339cd,ddd26e0e,ac4a1c2b,39e19cae,2d67e726,8518b750,94cb5e6c,b525d84e) +,S(11e10c95,9bd9f79d,c2819a87,e17c0de7,9105af6b,fdbe3f6b,88d198a7,106c861a,27c29227,4a3677c7,381fe385,8382ca38,d4b98e91,af4250fb,40540828,246d5c16) +,S(785934d,e1b1827a,471d7e59,2a4c3475,3054b00e,b8aae372,444b00ef,d9d894b1,7b8dd2e,a038d4e6,23f0f1f5,a2f75dbc,fe34e76f,6d106ae3,33d88a07,56dc4a60) +,S(f09c814e,8e66b8e5,930f1a49,28b28e5d,206f4108,fe99f04f,ead93096,1cc17605,469bf934,b4059a4c,4a942214,e1d86fe6,dc900426,c7d0eddb,8d89e86c,76d60f24) +,S(732901c7,26982b9f,ff1229a,3e8f7c83,2f47437b,412d0b3e,274a73e4,24ad6480,6b82e2d3,d4830086,cf416593,9b04ff7a,89b835bd,81cccd8a,7a29d47c,b70da3b7) +,S(b8369a11,d23ff4ea,99ce166a,4708ab9d,389cefed,b1843d8d,6fc11f74,7260faea,f4346c36,63ec0ab3,6ac12df7,f61e9848,c2d4cbd8,c8e6e173,2d104d0b,aecaef9) +,S(5499e409,3df85dad,411b8675,c09d0c0,c25bfefc,2afb0228,b94f834a,34ff83bb,7775c877,8fc6e8d0,519a67a8,7d2fe9c,c8abd8c1,15ae1700,ad1a94d7,925a4c78) +,S(fa5bc8e6,fa9b13e8,ad787ba1,497a6b97,5c34a64d,a0da5b5c,836bd71b,88c93740,8c919cc1,19e45de1,54f6d0d8,f22d3b51,169b3f0d,181bb40a,56213cfa,a4ad126a) +,S(a871c481,a84f4447,89ecded1,e2b1f525,9b1d4ab2,b16af331,199f89f5,730cdb0b,c478609,30b85d69,1ae45d62,7aeca01c,9f10a119,500d5d4a,c317fdd7,8de4a103) +,S(63d3be27,66d33bf8,f7a38577,aadd5d9b,234bb77f,d206b056,379e023b,ecd25616,9509d09a,6dad6da0,aa5151f8,dd8e3800,abd8a799,2276ea0d,3c958f76,498ada87) +,S(413ab945,c133d383,d70e81d3,34bda75c,be7bacf5,e49d71e3,7a884489,adb28f8f,c3d49f0d,6c65f6d6,1c9c84df,a4138076,f0168916,393612b,837c1df5,df710a02) +,S(df070f4d,ce208b39,e2614db,77c6aa32,2a50bb26,2ec7141a,b1e26835,911b85c2,b0b1f453,1815fa7,83609235,da7bec0e,f1bf2ad3,b0e71f7f,7c18de8f,83f55a3b) +,S(1ae86e7f,300efbe7,8cc933c,f8cda339,1f0f8f7e,411e6c0e,708a0d75,a1ab1815,d322b34f,f0778782,7d2da5c1,4d6bf17f,f8afc8a1,8051a724,bbd719e0,f5f31a2b) +,S(2a38dfd9,ee86308b,e0c76ca1,8dbb9ec0,fbaa86fb,51075887,9283c070,f31106a9,69cb45,94832b55,abd6b686,f67d493a,9d45e4a1,7d557723,fbbbbb83,7ab30cc4) +,S(2c6d7ab3,b1c3301d,65c79d40,583b566d,3ee39014,345a4553,a77a8e46,95b779e7,eb392dde,318bd27d,446b814e,73f9cbf1,380e38d,fed25022,bd584585,d671e470) +,S(758739e8,2aa2e25e,b1d8e027,b0e401b2,c82db2ca,549ebb9c,e1560ec4,531c5c77,d3792987,c3da2cc5,5760e52d,a19ea1b4,d0c2cce5,3f612760,bfc28414,37090975) +,S(7ef11cac,99fcb66b,71de229b,b34e82c6,e3149f85,ba1ffbf7,f22db64c,6a72588,64d7c546,28892864,1db41465,a134cfab,bc08ea64,11f5b2d5,b1de9f0f,7ae41b70) +,S(a7d48b06,c66ef847,f17b4b3d,ec40eb97,cb91bff1,c06d4a6,5d6db8c3,5561e4c7,2f22aae0,d6eb7221,d24f025d,ad1768a9,a619d6d9,db9d8e74,948d9263,3d0676f) +,S(a14d7354,1bb93625,d80f654,af67febb,d774e42b,6430a14,a907c52f,84088ab,adfe7f75,2b080bb6,89c031fe,c7c11d1a,bc303b7,f1a0ec2,38a4dac4,afbb2a5c) +,S(16076f95,b067381c,9d71cc9a,928f10db,43553332,f747e33e,367cc7ca,ffaa5f88,5c05040e,43a29d4d,e16b5e42,b672f618,8f0496ef,f307c269,13df7c79,ed2b1502) +,S(973450b4,a297ebf1,70630a71,fa74ae2c,8f3f8e39,18ff73fe,41bd1e65,5a5acd29,ba04c21f,e92ea639,99d5d87f,77181c31,ae8ed87c,dca22054,2f746fad,61f63039) +,S(aa29f7ef,d2f06187,108ab23e,16d9f3a7,74ab6459,550048cf,e1ddca0b,45fb5942,431cbd5,c77b31b4,d8b8568d,b092e721,a02d643a,75621eb6,1016b363,9728e2e8) +,S(bba61b3e,52614d14,358dc227,e0c0ea6c,e4dce364,fb7e0500,72d0d780,14642d9b,f33e0e72,6e9ee195,21fb4a80,2510156b,230a7ff,6e4c6b38,cd38b3cf,65336d6e) +,S(911443a6,979ede22,f23df6af,e4b1ab,73867dd7,a47e9268,3e3cd83f,241bfacc,a0e5be1d,31cf0375,7c2469a5,90f3493b,e43a99e2,755af9d8,b87aac67,ee7a6488) +,S(ff2126cc,5698e6c1,2da7f441,b031ea11,30132b86,23994f64,b332a8f2,87616d41,c616d5b3,79eeaae2,b072a11a,d2b316c1,b2c851d6,698b6d86,7fae1abd,482e91d4) +,S(2fe68e9d,de151731,12e1653a,2a6abce7,615062fe,a5375ef6,a2be1e90,67f6d8ed,c24e4b95,718acdfc,cd9f39f5,eca6f2fe,74fe7f9b,ae6aa352,e3651bbe,5d81c9b8) +,S(dc08aedd,90e96f6b,892ee62b,1f719619,6af44975,58d70f1e,7294863e,271ddb99,7250d846,1ac24a2e,e74bc5a7,53d5361f,8c012986,4364d84b,4afe22cf,c94aad99) +,S(e9c21052,f350d1dd,caa82594,b6eefb5b,f8f01ec4,1a423278,fba3951b,fcc7eaae,6992071d,becaac44,a5cd1537,cd066f2f,c432f198,621b70ab,360ea8d1,35757784) +,S(110d5ac,7838b9d2,d33bdf5e,8aed8529,5ceb9334,d409074f,3c26e3f9,f0cb792c,7879e339,427d8425,b597e76f,56a7a6e7,9a8cb00b,374ac98e,9cbec66a,47bceac) +,S(92982af9,ab48532f,cf2ece2c,9ab346b8,7def4729,8ebcc03b,91869aeb,42f9bbda,c6bf5a6e,8639e2ca,772e8c36,5f824b3d,331c7be9,4c13e9a8,ae6a779e,208a157e) +,S(c3f07f47,5246bb78,eac4e9cb,263c774a,3447acce,993a9707,14c1b553,79013162,f1931fa5,d6fd228a,a5781b35,45faba70,df6bca90,936acf17,f81a1155,4897e136) +,S(37640e7a,eef3f326,a598d363,df4f46dc,8f0decb5,ab6e368e,62294c53,ef3fdc7b,54fe19ac,83a074aa,796feef6,8d39358c,7be8848b,433e1eaf,9982701a,3eca7a1d) +,S(e903363b,6c90bd,2bf15176,83411d1d,aa9f0bb4,a22b5f03,ebbee32f,8f0cdf4d,fa44eae0,78b4b6fc,63abac71,ce0a6e0e,16b42d80,94179f1a,657eabd8,7eea2480) +,S(3c5fdd9f,7313d178,312bc477,849ce90b,a22770df,867a815b,2bd1d1a0,600afb6f,d81524ea,9e23ad00,bd7197ee,63457745,75795d6a,63b8b15,a19cf606,72159a05) +,S(40b540cf,43713ef5,c8b919af,6c991632,e60c198a,677887be,33b84c70,7c0ede8f,54586256,7352c824,49ebecbe,6eaae259,8e1cf694,fbb296bd,c14a4a59,240798e9) +,S(67da332f,f57adb72,8eb8b926,5a650e23,bfe5271e,396d74f3,9878c22,6f912053,91aec263,d7b74e09,b4fcffa4,87cee236,356e4fdd,bfa257c8,f3e3be0f,3a3b16f6) +,S(40cea066,fa029178,5662c994,db5b1153,e59fa121,c9133c2,fe1c6d20,91d44d98,61475cc7,a5ff5251,558f258b,aa8d69a1,52ed6497,c8ffcd55,2b66baa5,534df64c) +,S(c4eed050,248cf186,f8e2c079,870a139,c0cb13ed,2cec040e,d98a18ca,9b67ed0,50e9997e,263c7441,9e71405a,4d342e76,c5548e,1a7a3cc2,97e4e00e,91fc476c) +,S(676b60d2,14e309a6,8c7a8470,70d5bf62,8b71b7fd,322ae568,56fd4a48,9f3ee83,16e0d8d,371ad6bd,4713e9f,7c5f329c,72215cf,21a48527,35a0df71,205b733d) +,S(af268996,29117c69,c3beb193,c5cf7944,d4d3cc1b,7481d08e,1a190b45,c03e1fe7,359e17db,bdbe179c,8cb75ead,8a0e3c86,2b1d7d28,4aafd2c,e45e7b9a,c6d83ebf) +,S(62e15cc5,a30d1388,2b3c3890,4e1d11db,97b0a7b7,c658175d,e438591c,ed1ed489,fab66c6b,ab7b5ed5,815c81ca,65cf364,f4cdf8fd,7a6fe8e9,ab5ceb66,3bb4e8f5) +,S(6c7af496,df980977,41f5068,f34d0477,7da16397,c853539c,1b0c1263,2e43ccaa,4eb0e461,5c6fd9e4,3aa05201,88bb264b,d55b3a05,fc2b6c8c,d6f5f51a,4314f6b) +,S(757a45d4,4c662311,289be914,4ccca5ae,6ef89f51,52d66a2a,9be64096,cfc8fba3,732ddb9f,62fdf217,44d7daa6,35ca3e92,c3b84061,bae4c220,13339e06,fd4da7e0) +,S(14978c08,f1eaa9ce,4d878db3,29f0bc94,43301fdb,24b525e5,4f9f27d5,7fc114f9,439d8e8b,2b9fdc0d,85914620,9c883731,26e961f6,82407867,b10bdbb5,3074e5b7) +,S(3f231c93,760d9198,4a8d9adc,abd83c1b,3ae620c8,f067d103,6d1e5e02,2a72bcf9,95eb3a0,a928d3f7,dff3426d,763cf6ed,20d6df2f,c5dfb17f,c53ce0b7,90412bc7) +,S(c90268ee,75cc8e7d,7fe84298,b1db4255,80c3c45d,3643a280,e3d5d0f6,7337b616,f566fecd,1158d49c,c12a1dde,d0b1fd7d,d9cafbb6,ed3fd09b,48689f85,b01cb59) +,S(6457f0e,4d6cee8,7a2c0aee,85306a02,42c017d0,1e1c9807,5b460732,5c1d82f,67bf2f81,262de4e2,ba9d29aa,aecc9315,ff56c3ed,2e73d438,2a3dfa6d,faf9808a) +,S(ddc591c,1abcbb88,3de13bc4,490a66d5,3d96c97c,f1e21ae5,6a430c1c,39b1b629,80ae50f7,b81f043b,e3db78c4,da7b6078,871d4813,1e076ad9,de59fb27,b942f72e) +,S(22b19bf0,5efeb280,44b43bfd,7a6b3427,2e8b3c1,f6635ec8,d6966a,6667a252,47f504fb,ef2cea6c,8692d0a5,1f492560,151429c3,e522c23,2914e880,9ffdeef0) +,S(d5883bd6,c13d93ed,50371ce6,ed6c4263,395c5d28,f589c84e,cb9fbfc7,2dca651e,acde7b79,969cde2b,9a580387,d8e3a99c,45f15d38,f2e2ed79,688a3a95,80aa9a8) +,S(9615736a,4804dbbe,439f2f82,ca576623,a1675aeb,9ea9e40e,f6b910b6,c84af16b,a0967216,67f9dce6,25ce5331,62d45477,31be7427,74eeb1ec,4e3fe578,343c46be) +,S(ea36bced,959bc461,95e730f2,26224652,2472c2c5,70df6832,befa40aa,5c600e32,dd52094,82eb08c4,bc233090,2aa54333,87d06885,a9357f40,246348b4,4d97fbf9) +,S(44814860,ddf61b77,77cad443,18c21686,85c614b0,1c5830b3,b178a52,d85539bd,f3e5fd15,c71050b7,280643dd,bd2c55b9,219e7fda,cfbd2e98,94fa9a4c,9cc7ce75) +,S(814454b,cde86996,56b44c39,69bf0a8f,31b6d032,40098f9e,43d52266,cee66f49,8baf21a6,601db25f,2e18f5fe,decb9f31,9a6378c,adbff6ec,99bfa2ff,8d26b5c6) +,S(1ff790f1,11f7bbb5,b6db5f83,22ac696,c1de09d8,e50b9f4d,641ef76f,d43fdad,145d0aae,c218d6c0,219ce9c2,313b4962,f873c5c3,5424d3b,536c1543,14fa9517) +,S(275cc6c0,6a8faf20,c3c1e88b,87e27d35,661c6401,d3a1bd96,18cb016e,fdbc6d0c,45cc522e,97b61ff7,696c5780,638054cb,5e97b6d4,fc4a813c,7000a633,4e9f2a7c) +,S(9c78cd3f,874afab,23874f0c,8a84fbc8,a6d032f6,7fef6c6f,29c90513,bb6926f5,818a2406,fedf958f,7efafc4a,584ff6b1,7bae1b65,f67d1086,c3e013a2,cc318b1a) +,S(3c060395,f2cfe9f9,e3bb4afd,e5a71e03,c5a92491,323de27a,c9ebe1b,170153eb,344d08c3,8021fea2,6f55c0c5,85af3954,afda21e7,14cdedc6,8ffa3771,43b2ca27) +,S(f4b61a9f,7392b960,752bafd0,ce521e4e,57bcb898,cbb2dd9a,b0f7db8a,3ce5ff2,e412589e,f3678029,15813dfd,acfe8056,2a59894a,4c87640c,6044656c,e8998d5c) +,S(418698b7,6230acce,49505275,a0c01e9,4eb356a2,e3c242ff,470b64be,fa91ce85,cb9dfaf5,4c64ed94,f97e03d,30e07876,9e5a3142,d0fc0902,5e20ac2c,21c4ceeb) +,S(809cbcd7,91c1f309,864ca343,3d9a11dd,2db3d9c4,5350ac5b,27f55e19,b9941ce2,8161347a,92fdcb92,263f1d85,2923a15c,42d5012e,30d7d9b8,623cefa6,12b06bf2) +,S(6410c007,1d1025c9,8ce11509,5359e962,58c6a115,5e7f34fd,30fc8862,f9569f23,d76363d6,2661a55c,6c211bc4,13b1dd7d,63fa6964,a03d9461,e2870f2e,54c87d29) +,S(8394abff,22ef6051,7517e352,12a4dca,103a19ab,4091c7e8,fd417a,98fcfd2e,20d0ad3e,bc0fd15,fd405417,61bfbb40,8e37975d,a77321b,67ad2ef8,35732c0b) +,S(dbec1fa7,765386c1,d7558cb1,f19788bf,ce0e9fa4,7ca41edb,2f2d9ef8,78a04308,5d7c918e,335ef23a,934fc963,48dfd8f6,ce79885e,f4c463c5,b2645c8,48083ea0) +,S(9d6fe17f,3f53f921,893a422f,c9f675d4,652cbe09,a870c81d,8b2ab9ee,9a591cc2,fae9ccd0,b22ce7e3,2e7faed,2d47c36f,25cac5b1,e56ea936,a6811f11,8d485a2f) +,S(622f8f9d,65c4270b,1479e4d6,6f82fbc4,cf23e7a4,d09a6537,22c20d9c,54f85f55,e87650ee,4d9ac5d9,c6566612,1b6e4679,7e52953a,d7c3aedc,2fecc22f,d5b76591) +,S(cb1db853,b615cb5a,b92d0340,7ad7891f,2e7b1d4d,120ba3fd,a1ea3565,ee1d1436,8362a39d,9d425eae,2451d601,27ac2824,3819da08,856d0db2,18f339d6,fcf20046) +,S(5cbc6a63,59d9d6a5,2ceb093f,ca5cae,f32892f7,c9d04091,8245d9ae,ebd594cc,c4c18f88,7436575f,39b9e7c3,27c4efdc,6a3490b1,23c50743,ef03b1bc,34566bd) +,S(37a3cb08,3a9b7561,78ff2128,e7a5b9a1,19577af6,61974869,cf555dac,ee2d11d8,1a8a6297,4d0b6c5a,12155e9b,cf895c95,f6fd2b1a,2776c32,8d6b56f8,32f114ca) +,S(8e0611d7,ae0914d0,5d39e06b,9b359400,f21c3beb,73ede92d,bcaa6d96,8a995b95,ddd4f522,d1c6a964,9629727f,52740664,43e80ac9,7d9c68e1,225e60c5,38129bd7) +,S(9ec34a91,8a4648f0,1c1d726b,51b1874f,36410180,8bee25ac,c159c251,fc115510,bc5ee2aa,b5e43b01,b34ab989,5f4cd71d,1d3e6288,915daa2,e84ed531,4b388b8b) +,S(dc19ec7d,c901e215,f6d0603e,bb5494ca,aa9b5409,67a5a339,8915c4cd,84000654,b55b9596,a18e53c4,b82c669b,92defe5f,bb5e58b0,3cd227b6,3b439b4,ef13bf13) +,S(51bc3804,bda51e9,d0c45087,13599f12,b9a8599d,6e8ce949,5a3f595c,7d38dc8f,ef0d6522,fe3a3c4e,64ee1092,b9ae8f6,e7847bf,94044693,a3ac7cf0,f4aaa37) +,S(13463b32,dff393d3,dfddbe3f,bd6ade13,190e0bb5,83e3f126,344b5e01,3105e234,ea3df1a8,b8270f70,24910f40,a519cef4,9944fcf4,d82a4300,63b2026f,8f019ff4) +,S(c49b3261,2e286adb,606686d9,67dbf4b9,57819dac,9bb75f44,8f1416ec,f900fa5f,ffe45b6d,8c19de7e,c08256e2,96667d89,f290f5d2,25a9e380,c106972d,79551b1f) +,S(10fe7aff,36a8f4ef,79e2d8ac,619ca92e,2300878b,cf21a271,70f89e9b,6294dd28,f67da70f,623fe6fd,2c7113eb,fe6458fe,d0d5471,ab639050,685a0fd9,33afd6a3) +,S(d56037f6,efec78c6,e31e633c,570c5e46,96f96276,b86d0b89,e993f014,53592300,2499b92,4fd99b5e,a56f9649,bd8e53c4,b2f20dab,9fc1de83,dc199022,1f606b37) +,S(a3c1d0c8,939cd4b7,5cce8ce2,f3be0226,589fb32e,55457fde,8e700a77,a60bf003,b9054f66,bf6450cb,782533b9,33190084,d6f5944f,cf4e06f,de72d483,144c941c) +,S(85d0c4ca,e1cfe42f,b5f73f31,42e97e6b,c0855f7e,db19b1a,8668e413,4efcd249,d8372bc,937fa754,b81631aa,33a8ecbc,a25f86d3,d5e0627,d6964ee,5c08e68b) +,S(3092eae2,d41d0ccc,10af9d81,fe8c80f6,9ae27c9b,74b5f696,7a69211c,8d6ef98d,153f0882,f6b720bc,c8ae5924,923e0608,d6163c3b,32d36742,68718d6,e7f35e4e) +,S(4aeb6ac7,fe874a0f,1c24681d,884d5497,3486f293,9b01ebd9,74c34ea3,429be71a,d7077161,c508a7d9,63006566,f652afdd,df87d0b2,8daf3fba,21f206ec,a94a53e4) +,S(729bb0f7,be975284,a68363ef,40003a6e,c770fa4,5d6e6b99,ab0c5042,da563f32,1e0435d5,ea85370a,7293396b,407da43f,c540aa04,24f21de6,a002f555,cccd4480) +,S(96164ac5,1074dce1,3b973689,a39b6795,9bf5756c,4de94829,66bbdd23,9e665fdd,5cf13b8f,56c92710,80c11626,6bce26c2,14a39237,9aa68ed1,b7a05d65,7bbea247) +,S(6d45d79d,9297bb8a,326b889,391b18d7,31af609c,67b31be2,9b4273cc,405e3f80,2d99909a,7b6969fe,148111fa,1b9c9326,97fb465,494a8225,a6c62626,555ed02a) +,S(70091076,b5b81f33,42170f0,4881c941,d2fe9b0e,ff156221,66f0c92b,4f9e8e71,7c676c5a,4fb434d6,58f635a8,20b454f3,4c9795e8,b8860d27,4d0fecbc,ce7824a2) +,S(d04c0a77,c8fcb3a9,a02df253,b8819853,63dd47ca,bc1f8881,88d5e56,87a7db74,302d1b96,c35a2626,22bbc6e2,841b5cf8,efb77374,af428f9e,d69b2b11,6993db09) +,S(3c93d2bb,7ee61cb0,7a25ef65,f3e22eda,6e74d2eb,f3ede111,b4f2a28b,b4f206d5,65ed4db2,b1647b39,7225741e,241310e6,7a47f0ee,4f459ab1,3d29689e,cef70336) +,S(8efd5a54,a4c7567f,bd971cce,7ce3006e,3524dd81,cb7a4ee1,a5c61e12,62961037,6b9688d7,d73db9a7,1410738c,80430ea6,ea329145,718b4177,71e542a6,93b494cf) +,S(e7aa8121,34fa1f75,efd2ff02,273becca,18bf1ea9,47d168e2,cadd6e9a,6c448425,8af9da38,e2471dad,128e004a,d7b03932,2976d84b,7c91f91a,af471546,dfa5acdd) +,S(e4335a32,b3218d51,9c582689,85138591,4b7cd8fd,4e4eabc3,b5f9e0b4,c3212b84,ccfbfb0f,50b5fe75,c849510a,bac5870c,3016573a,53eda160,b14602c2,42ca02c7) +,S(aeff696f,e98cf587,745adbee,3fca1ae2,3f8f5768,56bbad5f,4a26afe,904a17c4,55dfb880,250b9a5b,7eb971a1,fbe0cd6,ad2d375b,88d98e52,6afcafeb,7ac4617) +,S(72fdb2e1,eb120244,4b20bd6d,afd6d49f,46a56f25,63e679c5,2de98cb5,bc999a5d,e29f2,34ad3637,7b4a9cf6,c307b8a3,a779cc22,ae472aac,eb519c10,8137162d) +,S(eda9f183,f89750bc,8c12ce7a,fee54145,42edd9ae,9fefd508,ab588bf1,6c7da0e3,a9328c5,81b0cb02,fc09fcfd,2a57d2c8,fa313ef5,4e205902,9bcf0846,811be308) +,S(744683c1,2a0150be,1d7655e,b5a3fc97,4303387b,e53bcdeb,41dfbabf,ff12f6be,df2e4b05,a459aa27,2d3de8dd,4c211dec,e35eb798,67050285,57dd53e3,5b9950f6) +,S(9f3cabfc,106653e4,65daeb52,e86d99ff,e3ac6df4,5eef90f0,61226cc0,32592ef5,9f20d174,1b78c8ec,d7425d19,fc0a4c9b,1f1cac8d,b97514b5,8585901c,41862306) +,S(9dc15715,9f59c338,d56a7d9d,ce63579e,9e95424d,e6db6927,418b024f,ed95936a,278716bc,3e131fa4,75b9ac00,6e868d88,ce17e6ba,d7ecd202,33fbba0,fb34f0f9) +,S(b6c91d90,b1bf3b46,4b526186,69e1c118,dcf8d6f9,c8ca7473,5a361a28,b53c823e,15132dc7,69e59b7b,fe5e9966,1b82e47b,3ee4c3a3,1c0b8201,517dc567,ff90a4bd) +,S(56604a9,ab972c4a,f18d5f8a,d5cb6d94,2d0c841,a7defd1b,b94b1b25,c31df400,3d2f2a27,adc2eb70,336b4b44,5229e09,a74a113a,f1b21bd9,1e3f2351,15f6a85b) +,S(a5b57de,fcd3016a,917ababf,171c3c31,ed62957b,cd8d233d,c551fd9,6216561d,3731d822,155afc28,8bd7ed39,30c3f6e3,58a46f5d,d9fb3ed2,6d7c7da2,a8dee233) +,S(da179b61,81e27ecd,d545af40,ea5967ab,7c0ea9ad,68a8c0e7,4d4a5aa6,4aafa549,c5c97c42,e74f4991,55191cf3,3118f05e,19633eac,ff5ea8d0,7ec866a0,7fbbef29) +,S(42a0e864,1b594b98,90357e4e,8c32422a,19f368e8,190170bc,6d8abca0,9cf12f1a,bac7a5e5,baf7ddf4,934aaeb9,5078e0a9,c449de0a,cb932b13,a93f474f,52312d85) +,S(74c85e38,944e2003,435bf345,124656a,6a409bdf,fd1c16dd,d1246d45,cadcaaf7,bc18315d,caf237d5,5f3ffc65,41bf9ca9,f39af9f0,cdde6fab,f602e888,dc51bb7a) +,S(8ceda42,698e5995,40091f6d,f50388e2,7c229b0e,76e7def7,f8986b6c,af975e79,a8915f5e,7c524e55,5743c392,2b31c426,71fa938f,84679389,b3738af7,59e92430) +,S(f44e2dd3,ffe43da2,66fbaa1,990d1f19,e3e4e44f,bb565ec8,74af57d5,feeac498,c307b3c1,a90da318,bf928a1a,a8894080,29874639,ece7700d,4f4dddee,d005f6f3) +,S(7e30bb38,c9a603f9,d5fe78f7,453d1c81,30c140b2,1ad7706b,601d6b77,5c703984,49c9de1d,1d057fa6,b135ebdc,f0b5ad9c,f9f51cef,95a4cb7c,ebc11d4a,3bbb6d7) +,S(8e1e53c7,4f7e1595,b4a5f7b4,5b324f0e,435473b0,a61cdd8b,1607c0ef,d11e3c56,584781c3,ae8a8beb,f6cd1bb8,3938fb12,35994977,2d1facc4,240fa43,7bc241d2) +,S(63d0cd75,54bf2c18,bb180269,2d19b4a5,4acd77c,d2eccb7f,360dfd5d,4b9f22bf,ed79b7af,eee5ec82,e498ebeb,467380b6,1369802c,3dd995ae,c844d3d2,91ddd756) +,S(feef5d30,b382dd6d,a0ec0d81,b18ae45a,8dbe12c3,dd695648,cea27c14,7d075be4,20ba81b6,b48ebc6,b185d6bb,2fb7bea5,c6a011a1,24f49550,415eb8f3,cde3aec7) +,S(21bb575f,db07a152,5ff0a7a2,d7d2c189,742df276,9306bc7a,30c2c3df,f2125b94,8ea74299,b7b40a93,3db6afb6,6577ce64,dd10d24a,89bc3907,1f656f5a,71c56953) +,S(dee2dc59,44cad7f2,310afc94,403067fc,5c1c3d2a,dde88ae0,55ba8bec,d6e5cb08,606542e4,5301a6ac,86c5c794,444006d,d77e2bda,11c8af0,6d883689,7a6b6dd7) +,S(4768a2e4,98ca0472,67cef4b4,18e6398c,81289c73,e617a2e8,ca021155,edc576d8,f8c574bf,beea93d7,1a2a331b,cee494f3,75c1bc3b,ea918106,9f1665fd,589dbc3a) +,S(53d75697,160c2b90,aaea7f95,ad24bd66,b5fd7681,f2802bef,d2a71080,74f66b40,4b04d94b,416a8098,144dccab,bcd8742b,13e85b2e,ec8817c7,7b7e5821,2e8b56c0) +,S(832f268d,ad5f3bb2,dafef9dc,f94bacec,b369d4a1,ffbdfdae,bd4fcd9d,77404e99,a6495805,c9b439b3,26e32f78,8b06765e,8d984a37,86ccb4e3,88b36bfc,c9cc582b) +,S(657acf28,15b8cc12,83265bcc,9c826be2,c6d5329b,351fee50,2ed96f4f,bb1a6333,171a0a97,b2809b24,a89b337a,cbeab96e,7d1d850d,dc577a10,ef3c757a,9c2da9fe) +,S(7e3d0a00,a3378c89,741184cf,36e41bb8,758fd131,eccd970,638f60d9,31b8348b,6f2cc777,31f94565,2a3b4c42,29be627e,bb70d5c1,67648d16,df5470f8,90512517) +,S(649a30aa,4fac6630,c7bab764,19f9a34c,6676f17c,2458fb1d,ac48317a,734242cc,fb3f07e2,5737d6b1,a28b074b,880db818,c9623c12,80268b02,dad90da1,c8d246d6) +,S(6b65264f,537fa580,9d21588,fd86b246,4d1818e1,ec7fc43b,94af9211,c835c986,537365ae,4e61460d,c2c1caf0,62ac870c,9536d8b9,436a0ef0,dee6a39e,2bf25611) +,S(dc1a5599,d5cba6b0,2d692eac,304b642b,db32afe2,59e2e8fc,3bdc8f40,72c66c51,bd18d5f8,f99c6070,b7bc06af,568e28b9,2b39dc31,ad49a842,4bff4a55,d11ff42e) +,S(726d39f4,86401794,9e7a5498,8e8fbb53,b8b13ec1,cd5fa3c2,88f0d933,894e193d,f23e9fc5,68c9e0cc,b258dba2,58b3dd65,7aca0dd4,d9cb7bf,274e62d4,f65543aa) +,S(78d76006,857c2f36,889c14ee,90a8f993,79c1e0f3,5344cafd,592c961f,75aa8ee5,76dfacfc,994f3985,70d98c75,4f5e6d00,ae3ed428,49cb75d1,580e81f6,3d7427c5) +,S(d69c3e30,88874c19,71bf077c,89247826,b464d3d5,292196f,88ef0ad6,892375a9,cc7b98de,86017934,c472bc7b,e56f14c8,7494cf5,6f2791a5,d3132c07,26315cf5) +,S(9b4022c,907c4aa6,87631f88,8d47bde4,faeab1c9,23e125f9,280dcf86,7920ae84,c7468b6a,a7b4db67,a9b4a23e,11fff527,19e454ee,65ed88eb,3b89e231,e504c284) +,S(e638a253,84e985a3,5dca200a,5e3786de,52617824,7ed0c9f7,9c9d598b,8bcf8447,69211bb0,be8fcd6f,cdb0ebdd,a8782be8,a47d8852,7bb74b3c,d98c41d5,6aae614c) +,S(e46758ab,e2838a28,42baafad,12376137,7cf72960,d6a93105,3270330a,203134b4,2c7ca1c4,73d0c3a5,8f5ca754,6604ac75,8c460c82,64f5ab4c,832893c3,fcbfc7c) +,S(c8c8083c,3bd1b84,9b9402bb,9472263e,37e7d2bc,53a77b4c,b0ae9b3d,bc70342a,9085d285,6ebd4446,127ab4c2,fe7e5c84,d5c5c114,8ee76a1c,da72933,9ca6578d) +,S(cf21f3d5,75f194a9,3133a382,514ca64a,f998b099,eb307655,46e2959,f71f838f,657df357,aa09b443,c4763432,45d3eae,4fedfd1f,7fa86896,2ffc5174,d61fc4ba) +,S(684aa68,d4aabda9,65adbb29,1056db00,1c41b900,e11770c,c77c687d,ebcd702f,c6f0c4bd,f6f6193b,928d81b2,812c4303,7e6b90eb,598a50b0,742dd21,8d82bf3f) +,S(b9a4ef5c,acf4a82,77b81803,6bcf2672,945ec080,e16e8c3b,19f7b612,c408c884,1cca67ba,9e98e737,b4a55145,7f254d4f,5d793d4e,22b81b35,f4ab48d0,92b9c745) +,S(ff439f87,d4784ca7,490da489,e2757106,e59836ba,f3fe2e4d,f6700c08,cdb2327e,98f21471,84659fa9,a9cdb709,f894236f,18ecdac9,f5834dfb,b91a7bf5,8edb7461) +,S(e1750c62,9c35027a,c1a5f1aa,c9fb4076,badfd925,f5915b11,a267672b,15945ed8,e17610ce,a0b8d837,d1038d7d,9300edfb,5832fa84,c4e630f5,2b01ac64,a79c0e17) +,S(2b7057dc,1c59ed7c,e64f187b,86adbbb7,1d228e5d,eea347c,75c73d2d,a73b3a28,1b136a49,713b433f,f2c79de6,77b5a322,8003e614,2b845470,5ce884ba,329e20a1) +,S(711c07c9,ae61ac68,f1041b58,c0f2ed07,1106c2b1,bc47e104,527d540f,53690434,e9199a45,2f5a3a39,9506473f,be6bb46a,3105aa70,2c517051,7b4c810a,5a194c09) +,S(54dc7650,68c38627,4619d9a1,faadc0d8,c2ad8296,dd0d00a5,f2e53c5e,1a1a0d4b,2e9b7179,3af2f752,c111fd71,c00f4bd0,8fa646a0,428b4813,885d4e4b,ab7e3fd9) +,S(9c5aecba,3f8b3507,db7cc231,c2c1674c,3c3e27be,84757fc,4f1521f9,c3d9323c,413455e1,9e157ddd,17f51c1e,618dd726,d300c023,f0a0d24b,518c93e3,f2954630) +,S(c22c2972,5f67e23,a369342d,9a4e1f6d,dc1bf6f5,88d63086,fb54718c,f5183a,a26ca30b,d97ad611,4ea4ece4,cfdd3928,23c02838,9723d53f,32c3b38,320eb707) +,S(8f87ac94,a29dd2c9,d37aa130,f8b4e67b,da595ca,a22803d1,e2d8cd4,eba4f2a9,551fab10,16227763,6d7ad2c,bb055439,21743078,e02fe0e1,b7dffd6,8749b04) +,S(bc486976,76c0f638,a116bcce,d7ee781b,876ef486,111fd680,4dedb176,8125dbd8,16d7c6d0,19708ccb,510ddcd8,698c2fdd,bc6978b8,7b0639d7,a1c8ec6e,ee3ea383) +,S(5a6ec844,201d9b39,92a46fe5,ad4f05db,6e8cf251,24ecae84,3a28da7d,46e75ae8,9e1538ef,f27344ae,8f9c1049,c12b49d0,2d5341fe,33652a8a,9f2eb512,c74ef224) +,S(dd6b2c56,b13f0ab5,4e0a75ec,526219e1,4d43ad78,7deae379,1dfb387c,541f4d6f,7379c5ff,1b793b97,c8acba99,97a3c079,f1c147a0,f63a2ec1,a0a771fb,fc3d432b) +,S(74e27534,4d7d8cab,e4995d08,6d61d27e,942e2514,3c6e3040,8402a5ff,12a63ebb,7b5914d7,fefb7b3d,2fdeb49,359878b8,355eecef,65ac589b,dd31ccb4,c270d854) +,S(bea186e4,b5e3663a,fb00230e,d8ac1660,67b022b9,b69b6e75,aaecb88d,d750d34d,35807d83,5b75e3ae,670bf35c,d415d37,6fbc86e7,4f99afbd,c60a0b46,9153a0d7) +,S(17ef6838,a07f65f7,cc094d4f,77743c6b,fde12ae3,b81625c,23826228,650f30f0,9d696a8e,a5356fa2,10626ce2,cf312fb7,198b0937,493c9dde,4711dba1,333eba5c) +,S(b3e1bfcb,38c89fac,af3baf39,80b21e47,d6465473,c9d6a29c,8a08cb18,141bcb7,aa33ab83,2a9d4eaf,2a50f9f8,ba55d0b,c5e3b120,69a8330c,23120928,5f6b90) +,S(689d499d,c754f099,83372631,2f307f0d,807f4f6,d67df40a,318aadd5,5776202a,dd4f9012,8a19dfbd,8f5f96ed,df2c7d79,d451f84f,fa63b1a5,9845f84b,759377eb) +,S(4bfb2e58,9df27505,91a73a4c,6ce88397,a2f68f6e,8f866e1f,d3af9df1,f3c96bb4,a9d94c07,29948553,6433f0ec,b4618d1d,af309c6b,73fa4749,aa949e6f,bdc24b7e) +,S(97a3004f,26461f5f,b6cbbca3,13eecbe7,5026d958,a1804c34,6e661722,c67f91d,8b8e9bfd,b9b704d5,13bb5a50,a725bae2,c7ceb6a1,ffcf8c49,8e87c6ff,e47844f9) +,S(a07a76e2,48f87384,48e607ee,7f30aed1,db657b9f,b159ac9a,3d38e8ad,61050c28,7d7749b7,aa6dcd68,931c3c0d,87eb73d9,6bd5f43a,b633e7b8,f77406a9,23fdd47f) +,S(9bcff8ce,3a280998,fe077cb7,a6e4854c,4c834e21,af118937,9a133986,320b8e25,da3214eb,5cfea248,f1f8a1c1,e8b0dfcd,4171b2fa,5e133854,84a6c99b,215c9ca1) +,S(8f1d2dd,bab8242e,fad20574,c0f28976,d2e98df7,5e144d27,e558b9c9,8d75a036,8bd117cb,294db5d6,a39097e9,8976c701,1042af41,680637d1,c8a1d56d,30800bab) +,S(73910449,2a44d0fa,d27b97b8,df75ca46,caefe44c,741848f5,36b78986,8d966991,d31b7807,e1db48a3,380608e6,5f865cf4,445c47f6,c6094819,da2450e4,6b78168b) +,S(e024cfa9,4fdae1e1,2895590f,222b167d,8a41a87b,b1a6b720,61ccac0c,4caf9dc3,d62f1129,cd84f36f,bd1b9439,6f5ce037,fbdafe41,fbebd066,110549fd,50b0ba05) +,S(a378ab39,e3dce826,6805bcec,b8123eb3,ffada53d,883c752e,e46ce4f8,5bf093fc,db9d124e,4c0a8d1f,14cfc406,4498a7a6,513261f3,300ebe0,99a41f0e,701c7dd3) +,S(bea5d211,b808e4bc,5aaa1a96,a9b8842b,5204b60e,24d5e518,4b4e92aa,12d8968f,caf8b92f,87c4b8fc,4692efb,889ccd64,610fd604,b9669dca,e033ae9a,453bbca9) +,S(7ec06291,40b6bfd4,cc4bd45a,8a953fc2,653d73c5,d366b5e8,b732dd8d,5d30428,e96c9515,da8dfae3,a2f4e01f,f02ebad9,8499a318,8905c0f0,fcbcbb58,87360a08) +,S(9f9698a7,6ccc8bc5,31dcd9a5,b21f3f8c,9d143194,8902312c,b5ab89cf,554c3b26,e08acb08,2ab0eb8f,fc31f7a3,1ca8dfbc,d4b1863e,29d155f,4abb8d54,6c59a221) +,S(ad955b37,a45f2bfa,1779e8c8,e6786af0,dc49dc9d,d692281c,da10b25d,7517214f,b2048fe,ee71c152,8c8f5dbb,cedde340,284af2c7,71ee86e1,8d565285,5de918ef) +,S(e7e56815,9412123b,7737b006,f48b3f32,513023a0,70c595af,1749c564,8222e21d,3ff11313,c2992218,cb3a1c01,e333f2fc,ffdd05a0,c381f8e2,24de6add,85aad0b0) +,S(4afab50b,55c2a433,488adadc,ca5d11,2e225f81,9ab817bb,116109ce,71dd3439,d232e25a,e5a8f6d5,68344997,442bdc54,de9cc597,cc474555,5f64cbfb,6252808d) +,S(2f739ca4,6559727c,cc2fdfa7,c66da19,b7d2660f,cc63b74,155057be,d55313bb,c39350a6,10a844f,80730a2f,27bbee8b,a06d7ae4,a279f490,f975111f,eada018b) +,S(f3596671,79f9343b,bc3238e7,bab4686b,5b7aaadc,95848f20,52adfc33,d15a990e,8b5759c8,e0bfb8ff,e298e824,ef18c042,65d7f886,1af8252f,8c9d9d92,c1822849) +,S(b3feced5,8d79e1c4,d0a210dc,de416353,404f533f,5a1295bd,4d888d59,b43725c3,b07089f0,871f7c3e,440ea905,cebf66de,52c68c04,a6aae237,e23c3272,26d99826) +,S(85c74622,bb28186b,5f1bffc9,74d51ea1,8bd7e6f9,1a02285d,6d8818df,b87d2f9c,8eb95100,63263c67,976fda8a,18910459,df0755b9,307e4145,cfdd18,15b799ff) +,S(3823d01,5b240e83,44c936a,c9a5f7f0,fbbe3059,1c20f39c,ca51be63,98ea7a7d,6e6539ac,8f404753,dda08dbe,f7ad4e48,69a67a93,f0efd0b7,b53c14be,130435fb) +,S(b73ae7aa,e97af1d1,b6ae34b5,f6188c62,33ac811e,1ce5818a,a9f20703,7deaa539,cf495bd7,2df163b1,f6908b7,23042bf1,137a325f,bb8ebd78,c0d12086,e7b76005) +,S(f6724463,faac9880,41dc4918,5e27b97e,889e74a1,81f35b58,2601328b,143688a2,a290e04a,f10a477c,7c0269ff,42285277,f1faced9,eff88272,45f2d069,58897554) +,S(9eff8038,1d546c1e,e1b5d562,947f3a98,427e17f4,84d0007f,eebd71c8,261ff959,bca422aa,d4748c66,6aa99f76,eb8e75b8,55f89b0,917ec29f,401caf83,cec111c9) +,S(93384df7,33d0fece,931587d3,410f2520,6bbbd992,5e6fce75,5432252d,8bc1bcc5,9e3beba1,b9a92647,c630cb4a,69b9bbf,80e301be,fb8eeafb,fa0021c3,ae27c38c) +,S(ca85653f,975882c3,71902d14,6f50b3ec,1dfe1fa4,b6e6d5a9,e5068685,632074bf,a64fdea1,66808f60,736f7d84,850f841f,588879e9,5d1adcf8,ccbdc4bf,4f743bba) +,S(b80a52f6,951aa063,1094a2e2,866d3a29,b95cf239,48753ea5,cf5c6f6e,8e082f90,61c95d57,d6fc3ca7,5f92771,61ca211,1f20a67,9a85f4f,2b8b0fbd,494d55dd) +,S(3d5d3037,3a97dd67,fe45b273,2ce21e19,b29587dd,301f3dd9,b411432,e642a3c8,5c8e3a19,896ef1a5,5cf1ad28,41e47dd6,1f207f22,3388c6aa,23d011d8,fd95929a) +,S(b274f8ca,29a87fe2,8a3a1269,ddc35b5b,44f9e4d9,81af118a,187a7c36,acb155c8,410d9c55,bc34c21a,6368155b,c282e449,c5317dd1,c4e5758e,27493fa0,4f028ea8) +,S(f1557792,8cac518,66f59814,a70c14f7,beeaefa5,33d3b535,df19d31b,ce1cacf8,113dbebd,9fef9cfb,93b5606a,e4b48aca,5b7e9c00,a59832e9,6865282b,80b70ecb) +,S(fbe3f262,18fcb657,7fe56753,42765926,59ff099e,f36252f4,cb5af101,622c40e6,4c872d52,f1202df3,e905a0d,3f9c89f,b347723c,99b1b273,8f3dbb83,df0fa2ff) +,S(ef7d13fa,25ef46c5,3663eddb,a677f6e3,b24c7e7c,6895e731,2c6993da,3d9384a2,cda2cc35,114e06d2,1f6f896,666c16db,78fef74d,2ee46fb6,a4a34e09,8546935f) +,S(8e34b93e,afb7f027,cdf8696f,a6407213,91860119,cae17b66,d4f16175,fd7118cc,3198f5fa,27ee190a,e56813e,910d917e,3bb8c850,20b0376e,e55e88ea,eb56397b) +,S(a8291a3b,8e544240,a0f0dcaf,6369b2cd,98ab80bb,4dcbc2fe,e023cea,1fa52399,f8305f7a,b1993569,82b8f2a0,1fa0e808,46a506ef,5cf0ccf4,fcba9211,284e15a8) +,S(bd36854f,90dcd6ac,978c2545,7800489,35c4cca,79a0f9b6,bf461da6,5522c88e,631a3d75,7c05e2cf,4a445b22,73cf663a,332610a,8461dff3,846503fa,12e65ae2) +,S(fad86e9a,ae78aaf2,e55e93f4,b8ee049c,73b86524,e942ab93,f05f9dfe,8b783116,657988b7,20822c63,dadaef15,a5cb3d49,be52946d,53b62ed7,1814ef3,b5aa4b7c) +,S(e1235938,db5e1f30,fa0b4d4e,a9e1925c,6308917c,23efde51,47fb818d,a39bcb2,7641244a,7384acbc,3133fd6e,9ed61af4,40e3b951,751f9d0c,384328f8,b87bb2bb) +,S(40ec62d9,7c9bf05a,cd4bd50c,137cb143,8e3331ac,554098a,57b6a92,afb137da,8b1468fa,f334dcfd,5a43d405,aacd3f31,7e868af2,73498367,4d0e5a06,67186a8e) +,S(f6f5c9e1,c7d94d25,9abe1a8d,745dabfe,59e911cb,c917fefc,e2da2a63,cacb26a0,7f2454a8,550b385e,f49c26fe,bac89a9f,33bd6c9c,2eb05c98,4303a16,6b21ca51) +,S(be4dd8db,c703a834,9e24773a,acefd0d5,70dd2ec,ef07bc70,ea8156bf,d5b516ab,46a7dc2,5d56052e,dc64a0d1,b414da49,dbb218d8,5abe14e5,c753eaa3,84b958ee) +,S(273f227d,448ee218,1e43f2a9,89d5942,54eae85e,54fe9f76,fb67ce81,169e1be1,67cf461a,a6c7ac60,1ccdd925,b4b38e84,1998cbec,cabf9441,29575438,a855f35f) +,S(94ca507b,96c063b5,bfa9d74a,c92e656e,db186570,9a017ce0,e5270bfc,8a8c4a31,98daf409,49c48c6b,8c674361,17aeb669,36c76169,8d39eda8,9922490b,4fa6a25d) +,S(91d6f747,c1c7e012,440cf7c1,34ba64f8,9ef67b54,3a57196b,d2bd6ae8,f5ef4356,e2117eb0,4d4d29cb,5b13f628,f69e5eaf,2befc095,2fa361fd,f757430a,168c19d6) +,S(8e2c4d62,c17835b0,97ba07b,37947515,e710e825,15bc614,75a66ed2,ac4cfb84,7b7f7e56,22bbca12,2863c230,5271ad25,b5e4195f,cb96e5a5,ca2be6d5,273d6532) +,S(55738482,d32c4248,1bb0d1a0,666adab3,8bd2441b,9436b690,77925e15,2d8c948f,93a6705b,ba5e5b36,e73fe83e,e0ea81b,3de393c9,1c209e89,af90c539,9af5ea2d) +,S(7faa0f45,45fa7d68,918396f6,19beb941,43d93f86,c5a26539,5016d386,b3e85086,cde251a8,3de1f2c7,11b884b5,33226baf,cac36791,1ff30e19,25f499ef,27da9c06) +,S(61a766a7,7bf6f8f3,a07ed7c6,6648606c,69134c6f,4ab4931,9033f9a5,e8b7d191,7dfa24d7,6bba181d,7bd77606,c73b1635,46f41751,c05c34dc,ec54773b,4abea4a) +,S(64317c72,4f1207dd,a6009736,6fd2d189,8b702e71,8cf84fcc,7c50427d,7eee171,d1d45f23,b1c5fda9,ee05652,dd30f898,c75923d8,293d6eb4,18a0e892,ae400895) +,S(4c328f82,5923e7c8,9cdba421,92ad7a37,5a328323,71242c4a,e108c771,fc47356,322421bd,92c5142c,efe89e59,4689a7a2,e8e5507e,be8b505f,9dc9ac86,9d90ae6) +,S(360aa32,797804f1,649c44aa,b38fa9a3,5d011301,708ac7cd,a4135c13,d86a6758,ce4b0fb6,6957f5a9,7e4ef923,ebfbd850,4f6d4098,5333db66,1152f1c,ac6eef59) +,S(5b110b6b,d9ec8ab6,635f5016,bc597f31,ec22f7ce,cfeedd2a,1e6f883f,64d2379e,9472fb70,87ab6f91,2b10c6ff,995af03c,5086c034,f0f69860,ead562a6,e409c8b2) +,S(be27b39b,5a657cf2,9ebb1b16,45f5e1d6,bb6e32bf,e3a52b08,a916e091,9affa38c,93fbf27b,5d03ae3f,471ad91b,69e74fd5,a8f2f925,2bd16473,62c4feac,d26d1dbe) +,S(8ec65d75,c599fe6a,bddf3cf4,6ddcb4d6,1e9b5324,f5e7b7be,5407cb5e,28a9df4f,3d52541d,49ce4b07,7b543747,3a219db8,29680777,3cdcbf80,e4b47786,14ca082) +,S(6edaa1b9,ea8c2c45,6c6a34c6,13ad60ed,aed18a04,32e96030,ac7305e3,2dbbf94c,c64c8279,40cbabbf,fcdd4db5,1719c53e,f8cdb650,67af48cf,fd731618,bd304b7f) +,S(3fb5f6f6,60847e2d,e04341e0,26c4102,68d5a1fe,880602de,c07be98c,22640a29,ddd43c38,95e663fa,5aee3227,4a16f532,df3a180f,e0813ba,3ba113d6,f6fbd9cb) +,S(2d740009,d7addda8,a802b263,35d41284,b3b9a119,248a3b,29b4a532,654e84c2,cbe1e2d8,1bffb79a,6f9292f,43ccbbad,e763a56d,6d68cde3,d946f310,dba8f28b) +,S(15bf4abc,1d74793f,6ebf2fe4,aa74e34d,b359ad76,3d5624d8,19c24386,33517436,5efdcb90,259b5dca,39054a98,b6702fb0,f2fd4b61,235ed4c6,cd1f3dc,dab15f12) +,S(feabbebf,3c6ee0ab,9b584162,476c8e9b,f7523c30,7874d7cc,c4a6b88c,b118d423,c51d328d,276502fa,f79168f7,3787d3ac,b4e7bb7e,1f65b421,64ad6e93,2d405460) +,S(e3664247,929c3455,e98de868,60010f47,4258c686,4d4a7c0e,4bec28d1,b9af3188,7cb4bd55,ba579fd4,a3066f83,710a3606,2fab9f87,34311609,902407a5,88454bc7) +,S(d570f391,365aa2ee,29b6db92,2a96e4db,f1820a6b,94fbb8b4,aec45ae2,f97a21af,c0841986,2b0adbae,1cb192e7,bf80dba1,830520e2,35e1e42,569a31cd,fc0c1543) +,S(9cfce5e3,5119ca91,38629b08,c75b77f0,db3cb593,b2bf8dbc,b7d6fe3c,d1eba55c,33891655,226885b4,cd74d8ce,f29e978f,60a71bea,be99a2c1,d2071f53,239e4f12) +,S(186ecba5,f9998439,f6a3dca1,a179608d,a15adf9f,f4d2f386,4268ec3e,e62e4407,ec7eaeb9,bec50709,e8dd761f,6253248b,2fd064a9,638953bf,510a38ae,c7c6d24) +,S(ad52f2f6,fe0b72ed,2a0fe483,3745aebf,acfae58b,b40a0291,21767058,3e0f6b83,b0cae754,85e3038e,c6dc8d,b4e95a54,63e3e6f2,1b99d991,2f521663,3eea0c71) +,S(aa06c0be,7d72350e,6b094df,f4dec4c1,993588f8,5bd82a1c,158f92cd,eaa7804,ed628163,29369fde,f0fac2f1,a533fcb2,a704637d,6dfaa1f4,a3b57f74,4efbeed0) +,S(5f7a102c,4bdf0a06,76e1bd4a,4df17a3f,124bfee6,312b3972,c49fc4a7,14b3e867,85f153db,ab40a9e6,747aef3b,cd30f59b,fc9776c3,93293222,8f534d59,9efb30e3) +,S(31a4309a,64c225e,69567574,e05bb994,3fe01679,6f09a0d9,358b1237,96cd3fe0,9b9862a2,916ad0f4,1e588567,5a1e357d,19ec82c5,b31f967d,af058e1f,da7cab16) +,S(8906bd2a,505e8401,cc89e32,b9362c84,3443b4f,bafb7c03,75bc883b,11c3e59c,ca78e1d0,1c6fca33,b39d690f,5b85c764,ee15dbfc,48fa78dc,5f7d7cc4,5323d187) +,S(41cc93ec,a27c4fc4,19fc1c8e,4568744e,dab8917d,d8936cd3,2723737e,e36b4f9d,c11d8299,bdb95efb,842ba828,a6d89120,1fc6a28a,9f208430,c1e2f748,bce6b7ae) +,S(6e1b0bc6,199c3b84,220020e1,1a698e74,2fa97a58,c498254c,d3af1e8b,23ef34ed,25e0ed2,3f04706,6b4134fa,b6252276,b2205bd0,7a8ba64c,636e0b0e,1d6d0217) +,S(b55741a5,7b9c7270,dd1e5115,995ecc55,8729832d,9f4e373a,6824d9a2,83490eb5,9adffc91,52eca815,465e533e,c82bab6,ec6b37a0,dbb3b6f8,c3bce25f,6e3d944b) +,S(fde1167e,67f0e084,251d50fb,bafb538c,9c375e4c,fd6441bc,59a46104,46ff090f,662451a2,444d39f9,58593a02,e9a94ec1,4a1b8d87,9dc80c5a,73bb68fb,67af754) +,S(bbc374da,188df5c6,5a633621,804d22e6,f7474faa,47a8af94,a1cb78fa,aee68040,c2c74abd,17acf272,6c03bbfe,7dbe06ce,eb1f4e0a,b0001aef,4d8f342c,aef50186) +,S(bde6680d,414ce86,548504d5,55c83b18,c9f94e45,f55b6683,166cc81f,583e0eb,2b1ce8a2,6b5bbd8e,a087eaa6,49f49a48,2891abda,87c2037b,a73409a2,69b5e2e8) +,S(8f9ba006,faf50323,b9637f00,9aa29cb,8e402219,75d329ce,15796428,6c84e5d3,1bb33199,e5c30e98,5f5eaa1d,65879a3c,703b7a50,cb04c7ec,a6c7512c,94180e16) +,S(19f03bc4,3b61d7a8,62bb81e0,f4b84c02,7359a170,de0108f0,e9b9e9d3,95b63481,8239d21c,f31ae885,ae10c62b,8be0ee1a,95db0368,cf0488c9,4a110a76,7d22dd73) +,S(667c2647,2261828f,2653a0eb,e70de204,29231fd8,132961dd,ba3e4853,8e332941,5758f0ef,4362f75b,c4356b3f,cd8cb2fc,3c77cb25,b7d65c8f,ef7b4096,e0d879e5) +,S(86558922,618551b5,c4c66c50,9b81a622,ca376318,7c558ca1,8a00a00d,cf100ca8,32cd16ef,955deafe,e3fedb4e,55fd2071,8e35c1e3,736dba12,9f3c3287,4413739b) +,S(255bfbc3,d0b0d6e,385905b4,af6ee2a0,18109db9,73788509,2d5fb275,f1b47b45,b1b1078c,afe453b9,a35fbc30,c5f605b8,4a1f61a3,1104b406,ab5014db,57e2b167) +,S(acdae8d2,eeab48c1,9507f575,6ba60b0c,e9d5b6be,e2ac15ba,d31e8932,fe89e14e,b077540,ab137999,7e7dfb3f,5e3fff46,10c2a369,2306ac0a,418d5026,caee0466) +,S(162b0c77,da3bc13,a62753f2,b7b19c9f,3fe864ca,66fa2dc4,226c5cd8,ca8d7112,377956e8,59c2f465,2af5159,bdfc86c,df0bd742,ec7f9eca,6e675b47,d6eda222) +,S(9453c9ef,afb6a23e,40ebf013,eb1af363,c28a6e14,d235c7eb,58d3d142,9d1b498b,65e3b737,ede3c00b,5f322b38,9b09a68c,2ff44f30,c7737932,4e9c94c9,bdd78961) +,S(8409ed29,38a5bec8,669e24db,88c1b6fb,b397ba64,d8a1826a,f011e2e8,32e85506,573a0053,1be979e,1ae3f2bc,3d28ce2b,7a3ec55a,bd00242e,73523a2,582500dd) +,S(3b55d457,b1878898,9c486cf5,3d1ef107,4161330c,64fc2250,81096148,f5ea2c45,24780fa0,3e83919b,9e3491a3,7e0b76d0,f5d32f2f,a4c3aaf0,d2e7c955,43476fc6) +,S(d3fa2c21,f4704812,a5b582f,9096fc87,422af325,5c5d006c,63e1e9ff,d2d9ebb6,a6aea607,9ed334eb,9355fbff,27650096,ab19a007,191d57b9,4a8fc12b,a59bbab9) +,S(a938a4a9,9dc45307,29f3bac7,4fcd7241,1e56cff6,f53fb048,c727087a,9a54b374,3949a589,388ef8cf,aee8fe82,fde39e01,41ad91c5,2beaea97,e7494659,1a27bebd) +,S(792220fa,aaf49862,479a6de2,35be75f7,e811d12,7420571f,e46213a3,e77aa93b,5f274791,31fc7585,8b82b021,52057cc4,f1686543,3eb6e22a,de56bea5,8823131e) +,S(b1bcdf1d,57699459,1bc11d27,cb15d84e,75eb3d5b,2f9b4bd6,1c848c14,e9b7f2d1,a2115735,8c35ac77,e116a0c7,77917e62,e1d09897,316e2389,41d8e170,90adeb50) +,S(735b746f,6f0d453a,c45cf288,6941cf13,c63899e1,a41ff3b4,cc1a4c74,a9b2ab33,e4c2b67a,c6bd7917,2478b52a,994dccd4,475cb24a,ed1eb77d,a39fbcda,9c02771f) +,S(1640d0cd,ba4b4fc2,f3670b35,2485027e,2724ea4f,df918b72,3807870a,39fbcb2e,a0a71f4b,ba481eab,999dfc3c,15275eb6,b06d129,48000828,be4754b2,749bae30) +,S(bff651f6,df72e476,a097231e,b496618f,6e7d621d,dfd45356,8b08c718,e138caa7,10dbc188,2d0a17fa,d769f855,bffe1a81,14183445,5d9ae144,e6eddb52,8e67f99d) +,S(1a3fa743,cf429f3b,49e122c4,5c6d6e8d,18c633b3,f9903c9a,207f0405,c2716b69,b1b2c87e,65faf1fd,debc377a,bd9648cc,24abeb81,75efa4cb,5f0a0b06,aa2f1e28) +,S(bc2a9ae8,e2940908,ef5420f0,9ef4c2b2,ae988e5c,c0c0efbf,62f8ea05,b305ff21,ede884fe,6b48627c,84c96869,5944be60,df3ed5c6,66f16b56,188a9e1d,6bb14e80) +,S(8cee080c,e9204a62,502ae88a,15965abc,b2a8f18c,80f6c461,24b073f7,63990ec,3adc08be,7bea0bc2,b2c5ca91,963f4c40,bdfdaaea,318fe3c7,866229e7,e53c8fb5) +,S(2fc784eb,f79f916f,7f57dfc5,8fc62e8d,bcdc7dc6,70d6a444,c13f397d,ed528e2c,56c58a3c,be510393,90a88028,12d03658,20141c,b1b24241,241dba91,74d6eb37) +,S(fcd83e1c,ec7a6db9,1aef0894,cfb2e1e0,d2b48fe4,88bcd28d,c14e7824,6e62aa35,a86c9321,e2dd113b,cb7ec78a,d9d4db68,b5ddbc01,70aa0f67,5586b08d,6694a853) +,S(4e4fc5b9,65584dc3,40cec4ed,87ab0610,d674e1c0,9d76d28f,e28888df,7f9be562,d2344fc3,de7e5372,ebd87d0c,ea5431d3,2364249c,f6c350b6,d7aa2353,26e9ac7c) +,S(8df04fe6,e93afc18,b0508831,320caa9d,b21fb740,46bcc364,aa80564f,6f89270e,d7b37dd,2463e50c,583dde08,ca253215,4d52bd8e,a4252c55,6749641b,71ee7214) +,S(f662c961,3102fc4f,afd27352,cc697de0,1f4a1406,f99a0656,6597b96e,cbc99305,43783b26,759a2eb7,8ba4a3cd,e865d1f6,474b1ae,26eeaa2a,15220353,f6bce384) +,S(2052f92,b66998ca,f172ce,15cde941,484c5ee3,d3ae329c,87f339df,ae944439,3e9ef8c,9f4257d,c563509,6df8efa8,ffd2312f,60684baf,bb9e5d,9cbd04ff) +,S(730aa6c8,9c8abb08,855bc551,1938bc46,bad8f226,4b162386,9f2e1ef7,c2d6702c,7523fb97,799e2bb2,f13ba1d,59510bec,ee682f98,f865aefa,cf3c6578,bf46ff81) +,S(c5773c0,7d65fcb9,7cefd396,b07dfa58,1ab237a6,be3c1739,e6db944b,c7991c59,6afea6af,44ea94f3,ee67d071,4b6654a2,b1b335cb,e914d305,1a60b05d,44cb81dc) +,S(3ef9a63a,5bdce751,48d7c585,5e3e9aec,90d34ca5,1a3b4829,979d67be,c38c83f9,145e65ae,635acb42,e7949060,fe44f350,3535d417,f3ce9e42,4c3b3d0f,b02f2c73) +,S(a1632263,42b900e5,887b1800,196c5be5,11065746,52cb88c1,4011aae4,6d14bdc8,beda5e2c,40b55506,31aae0d3,fd9997c5,3f37169a,2d810b5b,402210c7,7c372cdc) +,S(8c1f5646,65449ca1,f16015a,a876bdb4,4d965993,7ca6936d,5bbb80cd,c2da6d65,7cbacf98,f6f7363,8940358b,60beec4d,1cd1a1d,900f84bb,9db5f784,d4565034) +,S(693ab562,230c1ddd,3493c64c,6f7e2bb3,a74cc535,2b7efc30,630904,e700d5a6,db890cb6,d09d5be7,ddaeec01,299880a1,2e68acdb,dd950118,3c8f5f07,739cf4e7) +,S(d761653f,f7979336,f833ca51,b91b9e90,b2bc04f,7b7407eb,be3c8462,95d59df2,f81a5d74,446e9762,2391368a,ed154b2f,4faefa60,af93d727,8357fd6d,98537c5f) +,S(41de1c8c,a1315711,3435ce37,c2d2efef,24a67cae,59347d23,44bebf0f,a2cecc64,77629b7f,46cf1d57,a03898fb,cc9f4e37,937daac8,12c4df74,846d8c89,60095559) +,S(21f89207,4e3a00c9,39862265,c1762dd3,2662d182,397c1127,4ef144b7,f598b650,e6e30e11,566dce23,b7a6a06a,11e12bcc,978a6b7a,fa9297b,8c978f56,40f8b4f1) +,S(6163f61c,628b4800,dc49f30d,dff19310,369012a8,f31d4a25,27c790b4,c51f068,4e87a17a,12055cd0,4c4bc19,e052a219,7dc5847f,ec984f9c,aebb8f81,7a7065ec) +,S(a68ebde6,43ab3c15,72f5ab0f,85d683f2,6e6eaada,550e2425,f85596db,8e2dd200,487604ed,38a6387a,27e3cf1e,9d4865fe,7fc67e7c,ee26ab11,1f03e0a3,316de778) +,S(9b9fd342,4e065ff5,b82e0c4e,e5efa0b1,d0991087,684c46d5,7885adcf,b352d06c,b11a7a46,570eb251,6562ae87,90eeb403,823380c4,aae99329,de713677,5b5b5e0d) +,S(d80c347e,98db32bd,57ba5728,20c7322b,b295cc3a,ae326fd9,49e7557d,27151fc2,6d734eee,40229d19,465a0e2b,a011af39,62ff5c08,f83a2e17,e5c2783c,a430cb42) +,S(c8aba983,5f814895,e5d05139,7b23988c,7fefedd9,aed9dd20,a9bb0025,49e63ef9,3811b18d,8310a67,532be770,45461d82,e40c0ff5,6af355a7,55ed4708,f1ab0c7b) +,S(1bad15b0,a186d418,bb84a87d,d2fb9255,9aa64547,cf47a93f,73d23953,86b0e301,e432c50f,662da1ae,f7ee8f73,f5d7ac4b,4a4da6ee,5a943d17,7557e64b,5eeab1d2) +,S(720fcf05,dcbb0609,e5b45efa,e055811a,66d84384,16f7091d,7ea66186,922779e1,9045fb14,37d2086e,ae7d6a64,49effaae,17e3a559,571ab010,57f20fb5,80535906) +,S(96a540e7,8fb6647,63d3b129,8a1100b0,88a2c3e6,6da3ebe1,4b6c39cb,f01c4b2c,4debf0e5,c95b9a1,7bec7f14,12018197,88a1c325,12f60973,9d5b4909,f087b5c2) +,S(2f068148,d385bcd9,6fd6b60,b7e331b5,88419085,3942ed16,18b464c5,9c3ca99,596f3fb9,2fa7377f,a9ecc8e5,be8421cc,77339f62,c6f1572d,7a28266e,eb66ae52) +,S(466e9733,ef167fb7,233363de,16d9d510,74d8e5b6,35abaf38,20a037d4,f6b3e45c,73548e1b,d4d5b78b,821fb1d9,94919bac,a9d4e12e,13a2e8f2,d4c5df51,2553410e) +,S(f8a841c,a8c7fb3c,9a334f12,cfed9ddd,d1dbd4ac,764f3c6e,87a42818,a4a8e51d,57ebf669,72e9c4fc,7c435cc6,a85d381,6a969d02,ea85edc5,63c57187,34f0f926) +,S(d8c7d6e9,6719e74b,2eb7ae7,59d82ad2,6aa003ee,58e3d9df,ea97c7ae,6d6b887f,f1bec88e,5e8df038,b069692b,9e44245d,a11feed4,c89ff45f,17bbb6b7,1b0e43ca) +,S(afd5e13c,cabf51c,19c39c4c,815618a6,14a4f461,5fbaab69,624d366d,540ab638,9ced3d42,5c361706,16cdba99,653c00aa,e5212c5e,939c0bf0,3e5a1cb0,a05cba0a) +,S(fb491696,a4a1b9a1,572b462,f4628f66,b8368f3,3ce957d0,6ec29a0,92ce994e,b4fa2340,68741570,a56182bf,4f1c71eb,2c80d6a0,cffa42bf,a3e9d9da,59507de8) +,S(96e301b1,efd54091,80e3aa96,6652a253,78ce4bd3,cf587238,f0367a58,ec45b0a2,1bcdfe49,5ed90efe,7eb853f6,6fdc5b7,365ca2ae,e1d9b787,afd41b9f,c00f308c) +,S(9cde8d26,40d197a0,9ac00167,9b93092a,6eb8b13a,4d9fe2e5,6365a5f5,fc38d809,c86345d9,cf95fe50,40b2b2e6,2bf4267,72cdf10c,988a4f27,836d960d,c98501ef) +,S(d33ba473,10c37342,43e2219c,f3cf4881,2e843be3,c7492d01,80239bdd,20a829f2,ac774707,a5b0888e,b2ffa131,b71035d3,6af5be1d,3a3605b5,751b92c9,9e58a45a) +,S(6b364a32,1b5aecb3,749093e0,1b5229d6,5576e65e,1bea096c,29065a87,e26cf2aa,668ba97c,a01f659b,3687cef8,ac87dcd4,7a8a4f85,4a434f49,9592151c,b8f96152) +,S(d0009cbf,1d0d0673,5f66c16f,5cd4747b,d33b3347,fd7f096b,a026355e,917b5015,41c10a72,3e82bec0,b92e560d,3bf1e0d8,15a22e50,3afb4bf0,e5caf771,569a7dee) +,S(e618f641,a5b443d0,704102b5,40efb697,c470955a,8375e6b,a845c299,f377b701,9d615e53,edf6463,9b3b2d0,8684f8b6,15cf4122,33991a4b,5b7c85bb,f5698825) +,S(789c55f5,d393228c,7cc7920,9e705d29,867a6e9e,750d05da,9bc6dbdd,36c5c49f,8f38e43a,338058c9,39c64ff4,3f8f7bf0,2a7910bf,dc2f9af9,532049df,ca236de3) +,S(8fa4f0a8,1bacc20c,5d402478,23401597,bfbcc47b,973abe3d,71d33e2d,fee792f7,7dfac188,c5d6c17d,9e7430ed,d9038a6,e6fcf47,174347d8,7a68aa4e,cdc46c38) +,S(4d5f8d87,9377b056,afd4c8df,54a48673,c43fce03,d05be56a,56c42a23,356c34a2,b064c60f,a3b75513,577c171d,68acbef6,ac96f665,6a899d54,29e9427b,533b8e36) +,S(7a409ee0,8299930e,ddfc1e4a,db8475ca,9a99bf4f,a178a8b2,540ae448,ac87a3b1,5c4873af,c8a079cc,38a385c7,2ca039d4,4363425e,67de4cd4,15d09514,50f28e17) +,S(ac327275,44973221,dfb8b577,e33bd935,76407a86,77a1a842,bb04832f,68304e88,2b41b0de,3e406560,a57978e6,3359a911,6f993a91,9dd1c2ca,79c9a36a,6a4c8815) +,S(f9168fd3,973728c1,30dda9c6,907912d3,2e6cf9fb,b1c7a058,cc948f4e,44282720,c7005217,a6adf515,d8d3a87a,7e8a8b2e,aeb470db,c014824c,733e9a7b,17111677) +,S(818b9a9a,295d8f3b,bfb69d3a,f4749e5e,b0c1c04c,838ac3b2,9e74f6e5,dc73281a,141d14ab,64b3023c,597e96c9,3fdf393a,b53f45f4,56cd17a2,bd917af5,dca8daa5) +,S(90a416a9,dba0e05,bdd25dce,2dd0b0d9,200aef56,a6c0e16c,748e7d4c,99cac1c7,bc871391,95a2f128,af9c9c0d,56bff605,2fc27648,4e0a855d,6472f0e9,a779e0dc) +,S(678248e3,d48fd800,8e694890,b442d3f8,4f851881,9b152a6f,da24a6ea,88e1efb8,fa5d302b,51a36e66,98477693,9ba9c095,eb8b78c1,8f1bb114,53cb1904,a2185615) +,S(c2333e2e,742bb244,b7dac90a,18c2e65c,1dcb447b,11f8596c,bb3fcb8a,1e85195d,d15b8771,a31ff36d,b46b9ca1,b0ba345e,b877b7ec,48de20d4,71792a78,17ee826f) +,S(7d562291,9c72b694,d81bd71a,e78204af,995a63bf,3e8ecb3c,d9b3f589,c75ef8d8,aa554f52,67d9d3a5,8d35cf02,191b533d,ffdebf32,dde4cf07,252ef949,ec7df6bc) +,S(c5023f92,698f955e,4fcf7fda,288673ba,97b4d275,7f26f25a,c63ccfe9,155232b4,7d9dbce,def550c4,ee4c881f,69010859,c7a09ea5,36a8f7d7,17c1573d,c5db971f) +,S(37dc82b2,ed0e9533,e87867e8,d1eb57ed,707f335,b081d14d,d57aa247,645bb1d5,ff0c021a,d28649f2,3f000ae1,123f909f,1c803a9d,98ef2487,bf5d44bd,a97068dc) +,S(ceae1d30,2bf19dd3,a952ac79,8426244d,968b6ddf,25e16357,553f7636,a15ba8ed,c5a3a752,4d05206,39ecb8b,bf4282df,a1f9c795,ea74410a,ed9e064f,9a37c70) +,S(8bd49da5,fdb92648,f321bfc4,2d8145c5,20b8dea1,46b2bbf2,7a054698,3eb6574f,f769854c,5b5c9058,20ab0765,1a6d8104,e9a9dd1c,7aea6425,2b239ba9,7b0609f4) +,S(d1553a8,9a5226bb,3c5b6296,9f094b2c,1b761aaf,2605b0ba,b3793f6c,6959e8ee,d7b11159,d289d42b,8ca2889,f3dd7d01,e1cd0e5a,745b9f12,ab98b823,3211b2fc) +,S(ccf443ea,d8b17d4c,ec59ab81,74f1b1b4,8b6c3934,6e64a955,c617336e,aa6abc89,5cdbd39c,64510cdd,b342cce2,62915966,f8cef7cd,e10f4a7c,41a0d495,e5bdccd1) +,S(f95ad24e,7accb2b4,ce6afabf,6c1a40a0,172cf2b8,42871778,881ad94e,3f3d8d57,f3142d40,377543bb,6dee8195,743a6d73,e60dc5ef,4b0756eb,68d09d6e,326caf5b) +,S(464189d2,52726cd2,6f5ad4ca,5184503f,c546144a,ce7dfb32,5e4b4147,da7bcaba,910f8aae,acb04646,3c6a2a31,6174510d,8ae8bac9,fdce4c47,6c0dbd62,5196e2f9) +,S(637d373a,7355334e,70c78ae4,99429ce2,a5d97257,c0f407b8,1cb41704,d1b36415,469fa81,5dba5bd8,bb53a5fa,aff5b4c,18e7c28e,fbf21f52,14359d6c,7114c818) +,S(b489330e,2a4a4a6e,a99091aa,4e5aebaf,dcdba016,2bbc38df,5a49d4e4,7eee62b6,e1fed3d,93333ae9,2198b85e,fd68582a,35f6fb60,ff268494,720b387b,b3a7543e) +,S(8f2fbd92,70781f54,9d32ca01,2479438,2ec9cad6,2151c893,64c1cefb,c2324b12,2ae5c8a,2e018e74,2089a4b,12082c73,ba466dc9,851e7226,388e48ae,b1270a1d) +,S(a1871963,e9a65bd3,9e1b667c,55fe1a1b,87fe4215,8273c6c,f338f8cd,9119a828,e6881210,adb32d79,10dfe9da,c46c728b,20bca3e1,ad130240,f0dac7b9,fcc0cbc7) +,S(4a91a506,e8b32ca,13cbad7,99c4e3d7,21fd64c9,7ac8a1b1,e7f4bf2b,cc0ffa1e,66a0ee78,cb63bdd0,1a7c4bed,7bb565fe,832eb2c2,d32f2032,c33935f3,f16a40ca) +,S(61c960ef,2a3a6244,e8e7ee79,d4f5e98,88539c0a,b8be739b,314a100a,375ab66f,13b94913,ac8f600d,dbe9a82e,8987a061,3672629e,45d7d887,822faff2,60fb9e08) +,S(10325f87,f797c48b,2e6c7acb,bc0aa0e0,537fbf59,e74ab9fa,a7630c9b,86a04b72,685c5ae7,26b5c9c0,31e1c830,d513db4,b7fda140,14f8b723,7a9da11c,7ce9403f) +,S(71bca019,c15a3534,e5bebab0,6e1e1821,1ab01e97,dd24e1f9,1f89f834,b2cfde74,102387d9,a8da4f7,a483480b,316f0303,2178e668,f7a72719,2ae7e54d,27314a8e) +,S(7d30b01c,5c93abf8,9a50d14a,535a88f6,7cbb535b,1e58540,661fd7ea,91121fe6,e3d7e70d,1a9c0cb,2d6c86df,53709d18,b1989a5e,7642c1b7,cb381338,f6ed96d2) +,S(6f0322af,c1617968,b2550b3a,cafc8d0b,9445fd7a,4692f933,3ae9146e,fa2d3a4e,ba402962,d311b424,d05f199d,31b07d5c,8534ccff,caf817e0,88712bb4,2e6496a1) +,S(a3719ef2,c34bce90,feb7668c,a07d1a23,e2e6fbbe,1eef4b93,d2995e84,2c74688a,7164f77b,67aadb53,30b4127c,2d71dc46,f11e2d72,25968163,f4ea7358,134e5d56) +,S(3cb0007a,d2f1fb76,aa9752f0,218e2498,b7217440,a6a5136,68e95a78,4f71a72a,2f498749,12e8f469,e511b7a2,5a5046c0,f922a343,24620b51,3f6f0160,6de6b308) +,S(26b62d6e,f46929fd,88f00ca5,a699ac87,e090ab0c,8f02a078,393fb3ad,ae18c055,4fb9e53d,1b643585,4f2c78ed,1a818a80,1ff62c5d,fb0f8f23,d5e4d096,29886fbc) +,S(55e9ad69,68f490d,bfc2e17b,4e90dc5f,58335c1f,7bf30d44,79679acc,8cd7442,d4df7806,f74d9701,378ea804,be9a6270,85767e0f,b816ddec,4dbe34d9,536fe892) +,S(74a87add,723320ea,f1f9c35c,eddb6133,79835723,c74bc043,af36aeb3,5e1cbc45,5c79ef91,bccc2579,eea907ac,85ff8c0a,57fb48a7,c273f9af,6113e177,588fb14c) +,S(d4f1a9e0,2189ffca,c1d9914c,177fd66e,9d9a41cf,d1a38626,aed6b82f,70ba8020,923bf669,6ad7c71b,bfd696f3,9d68373b,9d0cbad,f367363e,2f70a93,4a0dea5c) +,S(593c7afd,c178edf,9eae7fb0,85984992,bc5ca489,16a2a155,a0314d8e,31fed706,ef39bd47,64f3b3b4,cd505e3a,628197df,5aa74126,30d83793,75c85b27,76a1073f) +,S(6622a6ea,569856b4,23e9f68a,78bab680,759a0089,3f6f645b,2e0eae60,f5dc9d3d,e84d491a,1bfc3127,3cfecf5b,65621213,bdf1af30,2dd39d26,d756e75c,4f9bc86d) +,S(d7149e32,fb34d956,1f5b25d0,650409f7,33a28fc1,fa4ad822,eabe98c6,74b3437d,2c249dbd,a1a82561,51b6eca8,a44bad96,1b2d37c6,d01c1d1a,70ceaa38,9b3f5039) +,S(64058ff8,7cadb65,8efbf32f,a68b7b3f,19915f5f,b434830f,bd5ca208,a4a09b6f,71c6dc90,f4d8082f,72d5697e,48fb380b,8486d7e1,5f113cc,28365ef7,d3ee9999) +,S(6a6cbb7f,5b571865,d70ec29d,425115a0,82d1fc1,f0209e8d,47be5e5,a9965dfc,fbf10d18,f3af0e94,b2a6ed30,c610f17f,5bd571a,41d073c4,2b2a4dce,c98ced0c) +,S(3f9a9be2,9a72cf7f,2086d9ff,3701a35a,94a7f81d,4b34a364,916a45e0,d8652874,25b12751,5ff033c1,70feaee1,189a35d8,ba0b8da,d4c943bb,4fdcebd2,1cffdf72) +,S(873be5e6,3cca17ca,95980167,9568b487,3d34c5ce,68abd305,169917a7,30dd206f,6ea148c1,280396a0,7ea5c5a4,17980f48,d076bdab,3df1628a,89da4c45,14bcbd4c) +,S(17865995,f28d4c4f,43e2e9f5,9b20edfd,830a65cd,d632cf9e,e7024ec3,4da0834a,6773c06d,478f3822,86c749c,5ae09a10,910b5666,5b6df747,36d20adc,af58332c) +,S(efe91146,fdfc4865,bd784853,ef79b8d4,d2f020db,3f901f45,38c74c80,bef49172,a81a34a8,dc3a229,8348109c,14d367c8,7abe6753,50d013e0,b1b0372d,2a6ee5ba) +,S(7ee6fb63,36cc88be,3b3c2821,1552031f,d017aa4e,192bc122,973545bf,924e8a8e,a656fe25,846e8173,327ab11b,d8ecd2ed,9d1909fb,21d1f789,588b4fa9,a8ceb0d8) +,S(449677d0,2a78e9a,ce374016,e19e7fae,46efd0d6,4839680a,4d5cbc42,173ee605,47017ad3,3357db8b,ceca2513,c6477157,f3daa99,9cccb709,bbe88340,29312013) +,S(ca9db080,12b9fd4a,cef2255e,83f35fb,e20806f3,9839c2a1,699c5d03,d7b5762,6a1a811,3d82a60b,677d61c0,af995bd1,4c598f08,f915e971,d9f17e9f,8398487b) +,S(d040da2,8dd69fc,67414651,714d4e94,5a27c4a2,9fb44612,d6d87f4f,80e2ba45,a1a72b85,957a01ca,8c8d5d3e,d9ae6a2b,31d2d192,cd7afb9a,4d1e4629,aeb9f356) +,S(27eeb708,fd2d52a9,47f69872,3706b67a,1d6e29b,cc0c86e8,111057f1,e3655608,7f67db4c,25b2e88e,275e53c1,c52eb47f,c2dab668,64b91236,522229d3,1b001a94) +,S(3bc82484,daab22ad,6d887a01,ea9f4b38,bb70e272,b15a7b4d,ab5e3dd2,439d8a23,b0ec952e,6cfe3ed7,4e6246d1,46c9c354,dacbc024,45b1af9a,6a668f0f,6fd52ded) +,S(d0a00060,13596198,8f070ff6,7ea731be,7f97a51f,68faf899,95eb0ad7,746aec69,dde4a735,d6dd08cc,28e2588e,9af0eed7,57017b38,790d381f,74748f30,9717a989) +,S(8efc4c50,51c65e10,56f5ccb6,a4be2014,a9dd043b,641b7690,cae2a8a9,1bbe8ecb,26fd1112,e1aa603c,91eb458e,3874d010,db58efab,5dd9ed20,e156886a,5f39fc13) +,S(e42271b8,881306ce,f166138,7d14f0d,da0db64a,b379368e,fa79969f,432cb110,d2b9999e,7ce9f3c5,8a6c77ce,a97cb9f5,f2860299,9bacdc7a,b7d5487f,8b5c9f5b) +,S(bb068f3f,8e7fbd31,f3aaf96f,de53d134,e3a88b63,9d8d43c6,4b3a2b45,2f8de740,574410bf,903c173e,23d88fb1,3f7534fe,566984c1,aa10f0d0,f54eea9e,7883819b) +,S(a3d0bd11,d728bee1,b166dff1,81c3682d,650fde7f,285ed5ef,b2ac5033,5327cd66,3e290c2a,42afb4ed,8b5a685f,69bdd379,44215104,17a61d8d,bd3dd2cd,805c5f44) +,S(9884434,78bfd51b,d27d04df,b5282a72,4cf82c21,487a8733,9347e560,994debdc,545574c4,359fe553,b694803c,5a07339b,b4e1a95a,b9fc72c7,5d4c8f5d,ec6ce4df) +,S(8cc104b8,58b8fb94,e0771dce,a103a7ae,adfc50cc,dea4cf93,a5f4ec9a,d44acea3,ad73883f,57c470cf,d477f228,8badab99,938b6723,516f97b1,22578f2b,f893b506) +,S(1627b08d,a822d244,ec8fe2e7,d8f02094,111fa362,e7190cbc,11229a4c,2043c626,41f6b029,80fb1370,c1e800de,39507798,8b6f315c,f910bb00,423ff727,e9e04c3c) +,S(459d4b1f,2676fd9c,2aac5937,376dc18c,fd4244d9,dc937407,d641e0d5,491df69,6f22ce37,a6ea6a5d,c9823197,22b0085a,e61fe140,d7558fcf,7bb44976,5de7aae6) +,S(cdfc7b3a,b755c181,72882e37,ff641e2a,94fa4e5e,b1b2947,4cd6e94b,f4f9387,76a11dae,107bced7,c2870dd,62ef183a,d45a02be,ce33e333,dea061fb,d89e787) +,S(5e189861,b1615f76,ac416236,e84b0961,b2639845,ecf6e6ee,8dc33217,b0952afd,1cfc65b0,9194d1f9,71136626,a2c3896f,5a3de705,ff1009c3,49a09c86,ea1667e1) +,S(84749eb3,3d482c59,81cc08bb,8634bad,fe0572d1,42367cc8,57a3c399,821d12c2,146a4fa2,3fecc0de,f00299c0,19406b30,dfbd9ad0,975717c8,7630e726,6e96022e) +,S(d73a1958,e9aa29b3,b1ab0807,2165c06f,daa38c90,6be76384,1851fa3,5711bca3,41f13f90,20633dac,3a5eca40,229ad15b,434c4f8d,4ea570ff,76d15d4f,63ea882e) +,S(1d77616e,1ccf1fda,bd4f0beb,6b60c1b3,1b94576e,bf2b61b8,c085cd79,caf8c018,7d3e5813,cf181271,55f3d084,df1077eb,2bfc9d6b,8ab6ede9,55c0ba4e,5095f23c) +,S(bac936d3,63887dab,cf27ea02,50bd550e,db37cb71,a2a8351f,fabcb1d,6d6ca9c4,7aa18819,8bd513e6,b45d6633,aa1af70d,b1a9c432,ffd1be4f,8a8fda79,a38c47f6) +,S(4d18c5c7,51639d86,b21712fe,b2333d52,5f4bd3f5,e4208537,e1e3bf7a,9343475f,2a60352a,4d8fcb6a,ce01b4c7,63619f16,156868c2,d85e882e,a2e7fb80,16f6500d) +,S(8e473caf,d74fb06,b483d955,ba3e35ec,e99a4495,cc86485,a8b6fada,c4c8eb4f,41708d5d,ae2de832,c7c38389,d0ae46c4,46add069,8e83990f,52a545f1,6ef66942) +,S(91366f76,48ed27a9,2ab639ac,f37aba5c,44e8bea6,1402e075,e307c4fa,ea2cefa8,868fe0f5,565092ad,677eb1c9,8959affe,5af504a0,c929bb58,2f5c3263,114ea371) +,S(1eab20f6,51b63685,a0a8489b,4e3247ce,1592c4db,40cb2f90,7eff1c58,c6609915,c142e9f4,b9522b0f,1db90912,c6f83c7,add6d8a,6bd1de4b,c54503a8,4e873cce) +,S(a0652eda,796ff72a,eaf8cfef,371594fb,e1528929,1320230d,2bc6a252,f4b49484,67e6d40e,8aaca7cd,f2a2047a,fc0a59c3,b4eddc1f,d3d5662f,45bb5792,9e4dc9a3) +,S(83915afa,c936886a,3deb8958,70e926e9,7ee4a6ab,1a5c66b,a1602c13,c4f959f1,86dad7b8,e870dba7,712ca968,1ab63524,2ed55fe0,36a148fe,25b1bdb1,1ac2da4c) +,S(293f0bc4,11454959,86b19fb8,6f738d2c,814523f8,b75b280,f8f9021f,95db6061,12d98ddc,894669fa,86b073e6,5855a0a1,760733e7,b7c5bf5e,868dd977,82a4fdbd) +,S(a829b1c0,d6780732,321871da,2d28ecdf,18d13311,4ddc33aa,8ff4caf0,58fb9ad,c5375298,501294a4,dc38d1f,a8c96f9b,789ee9c5,6533643e,1142bce6,8e1ef5ef) +,S(48133900,866a344,68309fc0,cc18f79,c0e01dfd,ed6a7bb4,e5a4697d,4b9cd462,335b7188,ccea4687,50fcdfc9,a6fa6034,c239fe6b,27cf6460,182a1c0e,c8c96707) +,S(7fe9d310,bbdaa101,b28c1e71,137a7ab5,181dca39,aa8d1469,bc06c856,3c7a70ec,18006c39,538a5141,2371828a,4d73e02,f4699a34,7e887318,57e394fe,75c8143c) +,S(1bd5b65b,d79c3eb,54ee1ce2,541b4352,1b7d6c37,d2a26f21,b51d2c07,103ebd8b,66e81b90,a120f04b,340adb2c,42143ef6,5d8a383,46e71856,673090ef,291d7bf2) +,S(237374f9,306e5714,5f37a1ce,1418a238,73938fa0,8bb971ab,fb5d97e8,e5fa0206,d8410815,fd4049e,f54abd51,fe2053a9,bde7f3ac,f40fe992,21bdcf8d,4b9808a5) +,S(33279bf7,38cee621,c17f75eb,bf78af4,58c1a4ef,a7197456,b57ee679,f2c34bfd,d63a21a4,5dc29462,13750d88,ea5e12c9,900b110b,ce433c49,e9b37382,7de327ac) +,S(ee274c71,b1f43251,11d7e100,5d7e9d97,ed1590d8,95cc6504,3e8ed6e5,5a87a9b,73f2bd1b,1baec4f8,ebbcf9ec,f613869e,8a262d99,7bdee49c,c5b2fb22,b652e9dd) +,S(2f49f0ab,c24536a3,3bb0857d,57c35846,f5dd036,3851a873,46f93d0e,53ab8de2,66b3dcd,d367958f,fd06121b,e42237a0,a9edaf21,79ded853,e8bf3c5,b6a81531) +,S(2d122193,ea92ca9b,46eec10e,2a23268e,9b1f972e,91821489,8cb12571,1e3094b0,b54d4b85,a02f77a1,57a48001,c0a26c81,2c038d0f,b91575cd,835183ff,3a0b7071) +,S(9047eae7,841f346a,374131ee,d4299fef,970f59e1,e4bb1fab,819fecb7,3026ad44,d59d3d2a,2c03be1e,553a54d,2dc61c9,e13364bf,3338a5f0,4e4466b6,86695061) +,S(f689480d,c0ddd61c,ba5aefe3,17aaa497,c2d051ed,d527cc20,16877986,12d7c8f,dac41495,a948d83e,37a9f310,18cd7abf,6d5608f2,213aa5cb,7a2b8f90,98d87398) +,S(4a01c418,be472958,5bae0c45,cf6233b9,ad0177ef,eb6e74ca,ded59788,a22d083a,8a12550b,83de095f,22411b16,937a85b5,a079c7ea,b8137f80,ffa66116,2a1c53f2) +,S(a6c715ad,cdc77020,febc4ae7,c6caf5a1,107147ba,8281d3f3,7945682e,72a5da7c,69b4ce46,2634da4e,e9e43559,72f87511,a26718d1,d232f726,577f0d5,6b49d165) +,S(68ecec4f,aa19ac3d,dd8b928e,8362ed53,3be24406,15f5ddf8,4b8a376b,cbff327d,f725f978,f6129f28,49a1c9fe,b07bc2b2,78fcdf4a,96a6ee3a,70b9b943,98a89f3d) +,S(5701d52e,2cdb7b71,a9ed91e6,95396487,1b656bc7,271299b,62ce0a4a,78dc69ee,eb8e4539,be99cbf0,ad730fa5,fcf785b7,35e1f5ad,f5c16c72,85abfeee,4058ea1b) +,S(8210f0c4,4b2f54b0,62de4761,b7c62d87,42424b13,ca0448ca,ba999eab,73b26409,1c79890,e4149248,b9dcd496,1da563f1,517275ec,79949969,8c6b864f,c03f8050) +,S(64cb2793,4ee57641,9d52cd81,6144543b,e4319d16,fdde7a7e,2bd824c,113bc1b7,c3144c3a,518eaebb,51a55bba,d87aba0a,12d3add5,5a5e00c0,94a2e227,80f0f6b7) +,S(37eb1010,acb889,932d8536,b86648e7,c124a8f5,1005c0fd,ec40bdd3,6369c82a,1da5703f,b387312d,d5a337c2,2d3f63b7,33dcc994,38109c2c,4807fc45,c02a2717) +,S(84bbf980,b54d60e1,ccfacb7,e861aded,b4cd7bd1,a3f7baa0,9a1898fa,22144d2b,3820c4d2,7b545166,2515064c,dc9b4cf,813c2435,e84a4a67,ba47068a,e6e09045) +,S(29e74c02,6b43add6,939ae05b,dc0a5e0e,b7d05bc0,536e23f8,8fed55e0,6f93f1f7,f0f6fd9c,798732c2,1dd1c550,3cfbd56a,71b335d3,aaa22359,75fb0c89,9571186c) +,S(98f3530,1122a0d2,629e5adc,579acbf8,8c0aea34,c3450ea6,784c4ce5,ee9672f1,427b899e,74e0c5cc,c289304d,b9a874c5,1d401369,55dc5b03,e0713bb0,8c3ec3ac) +,S(16af2e5c,4c37b50f,5f2b6e94,341e365c,90548d68,2bd9af37,1d849126,ad2c6c6b,1dd1bef1,6077f6df,32054335,c81ff474,33b7c1c7,d6243dbf,6a2564b0,fb9d8502) +,S(56998d6,bd5b2da6,d452f951,5343a9bc,4ed64463,adc6b8df,6a3edd64,e75e1cbc,ccd52462,9dbda3a3,10f3beac,7b3d3bb2,f1bf3c50,bca242ba,224861c8,1f26760f) +,S(f1732044,ec59c52,86273115,3c53aee0,c7f1c4df,e6e55cb0,e7e37d62,c1e11ce9,16a547b9,a61a6c10,4df1d1a9,de99f54,b42e0ad1,104a6a30,e6e616c4,dcadb2a2) +,S(6e5fcc4d,2df77b2b,8d2f95dc,56ddb885,6030f9af,aa51d86e,20d4772a,854b8973,11939a24,26c1ad6f,90db151e,c5c9f036,3f0b6898,2464fe92,c33aeedc,77347660) +,S(74a3ff02,98c3cbde,ba066554,d6def895,3954af05,f0f72365,680b7b8,4c5e9fc8,23b5f011,e50dd2b6,9c5ad6b,b4dad524,9c6a8abd,f134c232,f40de18c,3c65206) +,S(12a40a59,169e806c,8e32deb6,7e64c615,77a3ca,5c56723d,ebc98ed3,11983bc1,9d97709a,9c644c8e,3fcda745,a70cf3be,c405d230,eedac78f,96792bce,a715c081) +,S(f25dcc0c,5ae3f442,7fc17acc,bf888557,82673050,c3594abf,cea7eec4,7a4662af,52a20297,bb9213cd,d1b4f1f3,4f6168aa,ec2d326e,d9aef5eb,5b497c39,e0642e0b) +,S(fe31ac7b,ee45ffd7,99941eb1,8d65cb2d,38618938,c6278e45,4b87e41b,3c7d0f90,a5f1be4b,e0373cea,c3137a8a,c5b5cab3,e1209c93,2d49b245,eb99a0c6,469c3e64) +,S(c0ff7403,2855c2c9,ba06c2fc,6c9a8fc5,29b4ebb8,be082951,475196b0,ca4d6711,2c53707e,540e0c03,27a10980,25e356a,81fa6a48,b1e41d78,b7fe5515,b022173f) +,S(5b23e392,b87bef43,a3c08956,e1930c10,cae049e,b6f041f9,1bf3de75,4a84f984,c905adbc,337b9e7d,78781dd5,deaa0590,18e20bc3,5114c842,72343879,7a37987e) +,S(2100a6c5,b6b96ad6,37e13430,8d92e2cd,97902da4,7a016ccb,63a20cef,e72ac25c,a1fdc3cf,93560ea3,8418c470,679c5389,7bcc12aa,dc87ee6c,3429c68f,690f7e11) +,S(d57874e,509198e9,ee6ac826,b101ab2d,fe952895,ab288184,55f2d85a,eb2c3387,1c7bd36b,cdb6debc,99228b,341abac2,94dfd768,c9e00e73,8aa58339,d226f940) +,S(ff91057a,e46817be,b3874656,42afecb2,a290d31d,f18c6da3,d6313565,99657c4d,a2bb1559,96ca6cbe,2a375c3e,510df603,69d0cd8,f66d6571,9f9866f8,c6e73675) +,S(7f20e461,ee306c4d,7db625b3,49906235,14aca551,21b7890f,244de5e5,84d18b7f,8cc69fd1,eeb89a9f,9e126be4,3983ed45,d88c22fc,89f47006,ecd57431,4eb5d1c5) +,S(7ca32320,75421226,257670e4,5f277f4d,32cc7b4d,53588423,317203cc,b787696d,1e940799,8f25b7da,8f1212ba,c1dceaae,ca7b1952,26655535,6a98769c,b3da15fd) +,S(bcb7060e,f2685623,9aac249b,f603ce7d,b5c253a2,c998e44c,4ed60db6,730d5450,e03df58e,6d279025,955a4f52,dfce586b,f427e376,ca72e09,36d80c31,5047f57) +,S(30387990,3157ac6,fed71113,a004284e,82fdfc7a,3e08c0ff,1ff5dbc5,dbdfc04c,7132084a,1230ecfb,200ded60,9a1666a5,2f574014,d29475e1,6a061330,fbe19e7f) +,S(c5b3aa24,1147d664,a0b80f33,5dfefed8,a8f7c1a8,c6258686,cb16e3c,c365a249,fb5143c6,5f8907b9,a44f10fd,27064fef,93ee588f,9e77a65b,1cf64e4f,956f5748) +,S(11d8bdb2,b750146d,d78d8c55,6e6ac45f,4d34f1ae,35332673,cbb46bdd,3d76d9a9,1ea28ad5,c92761b8,7df96987,6e5b3243,9fe97661,87b5978a,d7515288,f30a5970) +,S(d6db4c60,742914e,c9c7bfa0,7a716cc5,f5492aa8,5381f31d,f76d089d,a773814d,b0ca5fa3,bc5d1fa2,c62a657d,77215b49,82f72e89,b138552d,bdea8166,359b6a3d) +,S(d28a6123,3b4e073,f1242c4f,5292bf70,9e1ae15e,a654bae3,4239133c,4a8a86e8,89519c8,8c44b38e,ad5c2ace,52d01de1,d74ee0de,5365567,cf1b21b2,2ae8b95) +,S(ff32042b,6a943772,d6f5794a,43420218,2ed31ac2,447167ba,ec82d19b,86751337,16961368,e20f2550,383268c3,9fe62fe3,b5d356b1,da2e4231,8f9618e3,13655f0e) +,S(f2c6177,30a9870f,5999ed69,d34efac3,589baa96,9f660cf9,ac839eee,a10e374c,fbb2480e,b6f191c0,15ee3c58,bd950aa6,7bee7569,1681250e,502e1d76,b6ec9069) +,S(dca14b70,e5e33022,eb559d90,1cf3a533,4c40bd45,7a43df85,e87acd40,90342539,7d038e51,30f77ec7,efe84748,4145594f,87d613bb,85a95715,9d0cd377,91678d23) +,S(9cbb407d,acc7c2df,2d86a258,d5ab2b43,31a18bea,9480f5e3,7727aef7,644416cf,7ab9fb64,c5f54f6a,4e5529b6,eb7834ae,80283bcd,c3f6b24a,8a014d02,b3b80b57) +,S(4552c48f,2d96ef41,aaf27778,a7ab4945,e4f2a2fb,7e1564ee,c375e50e,3516f555,e63da54e,28b70a99,5f35a1ac,3a25e384,6efafcbe,4e8f73fe,d84e095f,126524ac) +,S(b4cfb90b,168dc850,36559181,3d2d084a,9866512,9396f76,879280f2,38e4af3f,cfca0080,37006c35,7fd89c5a,1d444d19,5fd72d4,17fee670,e7b743dd,57f71b00) +,S(8e264996,e4e8a858,a1e32c59,b0df640b,a096401c,e77be6ee,ccd228d9,67dada3f,c9f5a8bc,89322e56,838c6d8d,859b6012,6d0a40f2,8377aca6,b5b4dacd,44931d0e) +,S(34ea02ae,49a4dce2,5ec2dc07,c71e3400,390b3054,83b8f30a,81021eef,5761ed99,b4b6f9ea,c41bf9d6,c4bba143,4639fd57,b8735d27,6098e374,d9324319,3def4c1b) +,S(bd391dfd,8569db85,b567c36c,5e6c378c,c152ad9b,c23d1fd6,1af23e29,543a56c3,9bf167d2,77e6bca3,a8d3cce7,61a36abe,91fcad0d,8d6ce398,877d3748,f2f13bf) +,S(67b295aa,440c8807,95369b98,c67d1d5c,1b9265af,58541994,7353c0bc,47ea8483,c94a0287,f2983c42,14f3baca,a8c5c791,d4d88fb7,30eb5b3d,4309f5cb,c5706f23) +,S(755e0335,284ad31b,5afb5775,fa191486,32b29c84,f38cafce,1b0b3b4f,2d073a42,c4506c75,c8cc96d2,8e31766e,a8ed1cf,531f4f7c,73888831,65f825d2,2b74c47d) +,S(e4b0cb3a,6149079b,5e47ccd,bfc4f351,64e575c9,20cd9827,a83f68e7,e5ba0a97,1604e71a,afa83b19,61bdd7ae,e4be5113,f9e9ddc2,29957255,cfe40341,9e45e5f4) +,S(3baca490,3147531c,905a2c73,277e4f39,c27ff6e5,41f6f2b,3ed4f730,3af0c4a,cf36fade,87b988ee,a4ccec6b,6b70ec01,d057173f,3aa7c79a,6bf4d412,d4bcafbc) +,S(229519e8,2a4dd2e7,ae77d713,21fbc8ff,f31191ee,6604823c,a6aefe03,19d06d95,a70e9af6,14ae7a1f,76224b8f,f5d1fc26,2e34707e,a6bfd26c,8cd7fba9,b5627e15) +,S(59364b22,4a53ed1a,7dbe9753,1b3a2600,2f700045,b0576733,8ee87a9b,2559dd54,b08cc507,70f5f3d8,851908b7,ed79ebc9,7f4f7342,61de0752,e14237c2,14eb5f6) +,S(d4b681cb,f3467c9c,649fd640,7991b4ac,3c66bf50,26ae93f9,e9b0238,9fb7c1f2,6df1a03f,4a5f00f4,8356bb9f,b23f1621,bb18a8e0,5afac4ce,4edbb01f,99a27000) +,S(49784426,fb036d23,a289f4f5,b3b92535,76da111f,ffcefdb6,a4163e55,2c56bc,76de5ca2,16ce703c,6a62ea4c,a0f7ae07,3744a22d,6db67389,9b0e93ff,a69e2a9d) +,S(5b213b9d,3f84b248,a98fe326,929b94a9,7bf78521,106a83fc,adba632c,8ed4892f,8eec203e,d015749f,f01402b1,722214d2,b58af86a,95384ae1,c39a7780,5623a204) +,S(6bb55cfb,9e3f5468,966711b8,6343e4af,6e372d04,ee7f570c,6a12005d,628959ef,75359562,9d633c9f,c2432ad5,f4c9f00,c6f54005,cdffaf82,438e3e58,70d14154) +,S(d760efaa,3a9e5c7a,967174a4,705baafe,d230dadb,4c957cf0,c025ab55,4b2eeb43,c019790a,b1b8498b,58daa784,ba02b7b5,672ba2b6,13d312cb,b4563f6f,e26675ce) +,S(f8be7bdc,6a361b6b,2844c60b,af7fec1a,216d75f6,96418734,337f9ccb,ae9117c0,df66b665,21e3dccf,639a323,5d773c21,4364062f,c5260323,3007e2cc,457d783a) +,S(6bbd2558,84348c88,c75a8155,6529be50,93b06a4,885c5d32,f1047357,a11434a2,842f9093,fd41b2a2,153727ae,ca2cbf00,a494ab7b,eef1a2cd,8696e972,1b1491d1) +,S(e692623d,cda3bde3,d32c1c01,f480d21f,9ccf8f1c,416a7dd5,17f1aab,12d3f3c6,30dab6f8,71f4c6d4,c768e086,fd6287ad,3fd000bc,3b04aa70,35cf441d,44764b89) +,S(86dbfe13,5db905ef,9ec7483c,6f51b75a,71726a1a,27e5131,8d6c0b2c,b0b933c2,371f23bd,45c46d3c,18056f23,10ab6afa,1259c88a,3a55f8ce,cecaea71,aea083a0) +,S(7ee329d5,9c625a92,594e620,4cb48559,458514f8,da94c7ba,fd2a4835,a4f10239,80a58a2b,e17f32da,dc80038c,7ed57de4,c7c561c6,69bf6786,57ee72ae,dd2bef04) +,S(e16a922b,8255d2c9,6ef776b,cda14285,b1cad5f7,62f75465,f8c82695,cf1065c2,44bc0e38,df9ce403,a927cb01,849e166e,6838468d,c7a8bd4e,6ec3fbbe,1f3465bd) +,S(5311e064,23145aa3,10737d38,41adf49b,988c1ca8,e8a705ca,3ca67f98,f756fe87,21c3f6ef,73bcca3a,c376e20f,dec775af,e22e708e,7e500c24,23114b4c,84ea8678) +,S(c09eda1d,dad1ca36,a9aaefdc,d16c5f50,a6ae499f,2cdefa2e,e5b61ab6,69f7fdf3,2220cbe5,bc279362,c5506404,e1df076,52624966,e3222b7a,62a1f7f9,faf00500) +,S(8888e104,18fb5c16,fc3c2b7e,b9ea06c1,da2df71f,c647b989,e71662a1,731628b4,7444a776,fa8f5bbe,959c71e2,c919b761,a2f8fdcb,5e66e5b,65e561e0,928e2d73) +,S(5c70258c,c1030231,d897c9a9,199df5b5,8b920f59,18141ece,d84bbcb8,b9b6c243,d627669a,e3dbb6d8,57d65a42,ec53bdf1,c688492,d189b1b8,67b75c3,f003ff90) +,S(eb58739b,878ea9f6,74b16f8a,406e7135,1ef06377,d9be32e8,1f657648,60e35ae0,752ae84c,8db0c7f4,e956d2b4,5750a5ef,24ea454,8f275f0,52b59ead,e3405ab5) +,S(996af698,ef26245e,35e4845a,dbf9c45d,6fec5564,c1fab0b4,8ac78f06,9840e0e7,a86b564c,ee788008,bbb04ee,e3d66c42,3c6910e7,7988aa54,420f3a4d,3137a1b5) +,S(bd03f2ea,a505bdd,7f39915,23f3e3b7,7532335a,6b5a11a1,4e303542,c00b8f4b,345f765f,cad902c4,56211eb0,bbe520ad,aacf55d9,e9c67787,aa02f18d,ccd88ea) +,S(8480c77f,3dd59c6,329c221b,ed8473e0,8cb0446d,c4e9bc6b,f2dba8d1,7ddf0f1,b055a135,a224f1e2,965cff1,a4f0d764,fed265bb,c644c696,2f3570d1,9af6e360) +,S(f46b6845,fa45e8c4,576b7c74,cd1a308e,f1adeedc,1d539d21,1158318c,ebd4c584,e1ed2665,34a14e05,c1ecf136,8cf8d6bf,fd9f0258,a5f0a53c,8abb00a3,e953c425) +,S(596db19c,38d91452,ad238f05,453bb773,9883df63,a0b545e2,47e5947c,d9f52a2e,bcb35b45,b172aeff,9e4fc5d1,714d6743,46bb4073,6f571291,e6575d34,f8b0d929) +,S(4cfbd998,f9544921,e5f1658d,e3ee95c6,df85b3f9,309f7a85,f6e4d08b,7e535497,ccd54e2e,437e4aff,7fc2ef17,3bed5ce6,b7d6e34b,4b386f36,72140d72,ceba71e9) +,S(c3f056d2,357ffe13,4403cee,6dd5ba3a,a7d2d0d,91d83f25,cb2cee44,34e57f94,1c31cee1,595b3682,fd85840e,312a61e4,40cbbf68,55418b30,bd6b24ab,c3bbf7b) +,S(e272370b,82ffc486,53274eb8,898409c5,9338e024,202be5e7,e18b5ec5,7f824680,d2f4e6c,619f0d,71e38990,f4e52881,de27ee31,ff7ad9cb,11a7f735,80a546cb) +,S(81537bc4,6a5fe897,827aeba4,6e66d576,6cd05a35,cd3fe1cd,9c06a2d7,194be59f,6706c254,125be3c5,92ad55f,6fa6289,4298f23f,2f4f397f,3bc84f50,79bcb8ae) +,S(50e161e2,6bc89d2c,816030ad,45559a3b,49c8606c,b28b6307,6ac6a051,9226d2b2,98478bc6,3f8d6be9,2db02910,67e5e359,e865d046,a5dd853a,fccb7592,72985c67) +,S(76ce7272,fcff02f9,bfc355eb,24286fab,88ba08ad,b15e099,22724b84,315be56,88f98fe7,62e37fdb,b72c1526,59528cdc,fc4c4203,c465e772,38dc8618,78a5a14d) +,S(77935c1,3a7f5f47,13098101,6e10ec54,d5ca10eb,492d4025,365d5265,ef7e6ebb,3c15e7c9,cf230340,44444126,5e74456a,4f3b72dd,7aff0ac1,aa76c67b,ce77dd0a) +,S(b37c3ecf,5813b5a5,2f52fc4,42049653,991d9241,e8677d2a,f9779fda,43c7a255,4361c742,c070b356,387fef42,1a9cdf79,58dd47a0,b7c9add5,57fa425d,626a1786) +,S(90c64aa3,28d43534,271e2f37,3460d8af,d17f9585,516b909a,6a7bea2f,1b12d2c6,79394191,a37a451f,e439e538,5e876c2d,ac397f0e,dfe29114,d14b9363,b76823c4) +,S(a314f637,2362ef7c,c4bec6a7,9396c318,568d9f05,9b6ca38a,c5f56090,c33e5e5e,b3a401e4,f7741130,95179507,2ce3b0e,53d2f51,f2dcaa9,d289e25a,8de01519) +,S(15c25f4e,80a7de90,8c49fc7b,649afd24,4c5a4be4,dfc15b2f,70099f73,6ad003dd,4aa9fb98,39855fca,c9f8bb26,b6322c95,e5d7adae,5aca9bf6,de073949,eb364b86) +,S(445e6d34,90f4ce76,22b6713f,584065a5,e0998d47,1b7603a,2527ed85,5d67d7a0,ecf994bd,7ba618b7,6eaca0,b852e0eb,be7b7f86,70d028e3,f52d1b2,846ce8ea) +,S(def695be,1ded66c3,650e9918,e942e4c,bd420fab,3a4708c2,43ab4e3f,1bf2101b,63569e13,532bf299,a0cf8d0e,a4addffc,1e782a1e,98a2f7c0,e0b64f50,8dd0afc5) +,S(eb364f1b,89938b48,2d32271,551f9529,5013185e,3ee2b534,bf01a288,9a534a88,9e6091fa,b439d0,d96f6a9d,cb468573,881234c1,6bbf4c50,32a6c950,99e6e6c1) +,S(7efe80e6,5c0134b8,49b6c58c,7d4c54ac,873e43fd,1b47f9d2,1d33f9c8,ee26646b,5411262d,63357cc8,d8280243,41d1767f,c25a0972,4c8c7a7f,3ddf6701,d12478e7) +,S(5f412876,3774e9de,6f2f25d8,a1d98de9,edf959a8,884643a4,fa18ac7a,26d6308,d3f6eff0,e336d4f5,abe35a12,4c47ed4e,5dbbe6d8,7d563fb1,8ea89242,aa454411) +,S(c63e3b34,bafd384b,2b60328b,4aee3a28,c7b3ed30,8a7cde45,87aa6c75,6c49c2dd,724fbbfc,11d05623,a5cb449e,a2f9f65f,a3de167a,a811bfcb,6ab9c3d0,3b123ad7) +,S(cc92795e,a0be5e79,757a86b5,147429eb,ca7a7c7,d51a8d3c,93650178,4f6ba5b5,92053ab3,db369d61,3af1093f,50829c73,4618c1d3,610ebc57,420d2824,935ae2ff) +,S(ba73d310,b5170cd1,57bbe14,63bfe944,ce7cea80,1b1aedb2,da3db11d,f1c7ea5c,4114e55,15806ca6,323edc6b,f0b75a92,834c72ff,9579d1f2,27fdadd6,d773c577) +,S(6047bc6,fd3a1c7b,9a36036a,94139542,7d9432c0,f652259e,1d52d709,e5088b22,bb119bf4,5d8ac9bb,1a918e6b,95cdf23e,6e2ccbf0,171579f7,ecfc9126,6d236b8a) +,S(a0600a7c,484559cf,3da255c4,935d2d97,1628fe8a,e75b88bb,1f3c4eca,e68f78d5,a439ac58,42bc6ee8,be096973,d87598da,349929c6,92e37852,e57ac941,eedef402) +,S(bfdef77e,1efac235,c1c49f04,290f89aa,c2e4632c,85f40481,dfdf5c59,d479e2a,e6e451cf,d76433ab,1de85511,9abaa5c7,8e4499a5,fa48ad77,f098c825,206dc7fc) +,S(81ff778c,373975,fb041cf8,ce4bc337,e2c977f2,d6bb2c61,9122240b,8e21234,3fc02add,e92c9928,e94e0ad0,218d6204,d71ef295,4c32227d,96b30b5b,9a61f640) +,S(84c4653c,d1af54f3,fc59dab4,5bbaa470,48f8eb13,4afc8f5b,60a8974a,cbf03933,98ff808b,a4682139,68b73ecb,67fe0a32,85dace7a,19d300dd,bd517e3d,b04ddba9) +,S(9d7ed86a,69f39ecd,c448de07,55197029,f81ee886,7c9a61b9,62d13eb3,abce35ae,d9b27e39,41c6bd1d,87dab6e9,32e8ba57,1dcd2c58,67177ce8,e7ef0fdc,668fccd5) +,S(540b7fe1,ee263e6b,3610bb96,1071d817,b9cdd162,77aaf28,87e7e5fd,df72f5b5,6638015d,591305c1,7a598a44,ba6871cb,8d1d3628,3ea25c5c,846bab2b,cd910340) +,S(4799c5ec,f1fb2112,f479abab,217ed0dc,e936c6bd,14215eee,6bbbb34f,d811cbe0,abfdeb73,4ac738cf,f607cd93,de58c0a3,237201eb,da47a808,3bccaee6,da5c5515) +,S(70a58362,b360c280,626a8698,7e4f2aa1,abdc9f8,f0b8c216,bb88b0cc,133c2312,5e37daac,d2835f3,1d924659,e51858ab,68e3a874,947360eb,c520767f,ce4d46d0) +,S(f345a0ca,857102b6,e225dfc5,7ae1cbbb,dd5c2737,116adbd8,b3d1f74,7d132b01,16fcaf2d,f7cae2ec,ef25da7b,3d51afd2,8f5e9920,5c0d74f0,c1e7b360,17eb2fb8) +,S(c3f4282b,29f253d4,fae8deb7,941484e3,9d2555d3,f96889b4,551e7d8a,eb2a209d,fc562248,8a6e83f1,6bb1530d,2a35629d,b25c8280,2eea7057,d22d109d,4263ac1d) +,S(5542218f,606e7cf3,9cf646a1,3677b0ed,4ff61aac,1dcea3f5,da5dd4a7,d4727632,f1bce63e,a11d5176,f47e576f,66817f45,4b51840b,a79695e6,3a1a1cd6,fb6c07db) +,S(65e81ed2,7d6b839e,5c3829f9,24beda63,98264de8,b2223479,43881582,4d124b35,2a17e09c,e4dd6e6a,32d85d71,e6cc2378,b53b9356,ee5790f6,8fc3040c,e6b6179f) +,S(5066b022,e43a5f83,c4290064,9e2b611e,750a5ded,7c89b8f5,892126f1,e112edf3,381e92b3,e407c6c5,d1c0ab40,6fbe1a99,57643da9,a2118cb1,3b8c6243,9328d9e8) +,S(8df78ac5,c5ff1cc6,df1e1dfb,58ef889b,17886433,61bea73b,a805c3ae,a83e2373,dc668ddf,5b39eebb,7b692997,f22140c1,8347e14b,edb6d343,96017e09,d37ca4d3) +,S(426c1767,7d7b00ee,af8d7d30,1bb11cea,1cebfa58,fc54bf0f,de719937,fb484434,4fcfa5b9,ab7b71fd,560ecbfa,985db2f2,418465f7,cbf8acd8,fdd71af5,7f9519d8) +,S(4f7f0061,bb90e396,63f6aadf,70dd3312,f781b2a2,3867df3c,566e18f9,b4a511e1,1308473f,d8956b35,97d904c6,cf73c05c,fd7c075d,c83848b8,571e666d,dc44b3df) +,S(7393002d,d2e85925,3b23db69,6c140258,8272a847,d834982c,5b22b256,93685107,b61532fc,6706f7ad,78548e76,b334a836,c899a49c,46afa1f4,4579b5cd,27641528) +,S(c41dff65,e88e5c6f,fca3b0ab,6ae69bde,c4215194,cd7c57ca,fd9b38be,feab4e05,9a9ba27b,a0b7e217,d31340cb,acd8506,7f052d8b,f92a4be1,cf59fbe9,6241f0c9) +,S(f619dc9d,6dcc39d2,9155082c,2ed9bc60,99296a8a,982327f0,60fd6208,5765c518,87961d3e,2b850ffd,f080d5aa,cceb1912,120ddbc3,4e0ad8d7,96e74afc,aa4871fd) +,S(6becdd5d,f02a7bbc,d1cc811c,fb83901c,46aa8207,35e81c29,a8d4d4ea,3f5cf99a,a45f7dd1,8949f842,2905c7ee,836004a6,5bb106d2,fb623d68,c2690c14,f181e39d) +,S(cd2390,db1e7c53,f424a893,c2529660,69a8f151,6f60722a,524578e3,e5427196,b817ed1b,457633ab,a3439454,6ed410cd,8140b9d2,e7e679b6,3322eae5,f3466e90) +,S(96cd9608,7f1cbcc9,b017ad2b,c7824285,4047dc3d,f98e7951,2fc09fbc,e3cd33ab,dfdb9090,c8a5ae70,13b8faa7,855554d7,3df381d7,88fd5569,d3a7ef7d,f729d625) +,S(99cd7508,5e9abb74,5fe03e3d,b100f2c5,2a43acc9,4127bd8f,83314baf,70d72b4a,19c98b68,2ded269a,57e50e3a,28b9cd65,344000ed,dac3d3e9,d8ac8370,662ee1c5) +,S(f53c2afa,647496ac,6c1220e1,4627c138,186286ef,b776449,55f9238,b39fdb20,1598c495,106a200,58fe1fd9,b29140e6,a93996d4,fe4cfdd6,74ec10f0,75badbd7) +,S(c127dad5,3b9457b9,51192c79,5793734a,d0a84671,ff6ba236,f53cc40f,769585f8,688e6264,da4e9d1e,fe66f5ab,db078c56,98696ef3,53b3bd42,c344b3f1,3d3ad744) +,S(882bc4c7,651634c,930384d1,3daf5a91,41508df3,2d34818a,e61bb65,40e92bd7,5c456414,430eece2,fc6e95b3,7700f608,9815f5cb,12a09ebe,8a87e370,85bcf255) +,S(4cbc141f,55c0b001,cfd934e4,dbbc2c2e,4b5dc68,72e3388f,2388e54c,e2a91bdc,1749d8e5,30d21894,221b2aa5,96541f1d,e700bbc1,e3427140,24f0a9b,9c0766b0) +,S(bff11777,6bb9bfd6,bbf872a1,3b9b6a62,32465cef,f16c3c75,441c39ea,2975528e,9e7412e4,ae492669,58dbdc9a,b7b1f4c5,d2edefc1,d4f0a483,27f2fd69,f992eb34) +,S(251416e5,887b294f,c752a1e2,3e991f11,90b8798b,11c97033,e470bfb5,b7bb6328,e6981dcf,15fb4b98,ac8a37da,267f1bb6,a2a38b86,3919d20f,72b5bc34,cb5e329c) +,S(bfe2490,569255d1,a62318c8,416e9114,66dec59a,bcca5df4,e64c2f48,46d050d4,f78bf673,577508c8,3846bd5a,312b9284,2283c47e,d4df7651,79d33bda,ba6eea54) +,S(e50d0a78,40779b75,fa121def,456865d9,3d7bb9c5,d566d790,58b1b56c,3fdc7b15,2f2688ee,4abcfa52,9424d4cd,eb40a8a6,a6de26b1,be8946f1,e4ba429b,5b32a6c8) +,S(b3a9d7ef,235df6ef,262e177d,19bd1121,167a056a,3957ffd2,a3d22d00,9a199bab,6a7adf,40ab5386,21fc3447,77c97416,66537460,44113c5b,a73455bd,9658753b) +,S(ec7277c4,20af5d48,3a6247d3,a1da7243,31c0e35a,85d6057d,55a3e526,bb7962bf,2dcd3e8c,5abc47d4,56bfcf,a8086889,89354e10,8188fb0b,c9ab4578,7b91d69d) +,S(91ed86a2,330ef91d,e085df2,a947c9de,f1284b8c,76d9b432,8dee9342,bd297242,fcc226b0,c46a36f3,ac56ec31,bf297360,8375f0f7,d248c669,f8b31ca9,9d056713) +,S(e2a09eb6,6e76b287,36c5824f,829afff2,439d973,e5be5b4,f3c55cea,e83bbda4,6b217b22,123bf3db,f35845f,315264c0,4a67ba18,a49abd08,6b2acc76,ca0b016c) +,S(78501449,bd76ff1f,58cdf2e9,203de4d8,3325ce45,1bf106d,2f474e91,bb0545c1,d0bbcc92,acbad044,218a830d,5f461332,cf488003,4b6f89fa,2f58b708,63aaa585) +,S(c3626c48,95df6e93,2c79d5d7,eac22ef1,d7679f1b,1df1259d,2be08aaf,7217d978,a594df74,250bcb50,dd9f294d,e7322b25,f72cf935,700856e3,c31fc5f,35e61b67) +,S(5c6e0358,ec09945a,c4240f22,3304f744,63269e16,c4f87dbb,99bbb744,bb4afaae,e6168dcb,d719ad05,8020dbc5,b03ec4c0,61b1fd87,d530913e,6df5d498,69e340d7) +,S(4a3fb364,d55fca64,4cc03c40,5a5956b8,a794718a,5b43cdf0,795e5d5d,5f79e7c0,4c4e0c11,5f88ef66,545280de,af9e3d59,3ff7d1ec,d8f20779,70ed84a7,8d660d28) +,S(fdc828e6,e305427d,c925de61,6f57e13f,5d0c8777,b538e511,49cdd304,1b022d05,de9e1037,db0dab0c,fedd8544,3b926a36,88e8bc54,7420b27,c65e2c6d,bbcb1662) +,S(6d70ad6c,375119a0,f4b2b65f,51257d7b,e73a8d69,ab944dcb,232b8fd8,e7021583,31de3a22,c8e8034a,d812a7d,234cad97,978aba7a,1c2996b7,aee623f5,858770e2) +,S(faa9dff,68f63fc5,7ca8c39d,8d950c2f,78a90317,c5d7f787,6ffa035,fcce8dc6,419b6c29,a7c02ea6,c8b7ed5b,c9b6fe89,1b3c705d,2ed2707f,3ef7995c,81a17de0) +,S(53d9472b,eb9a020,e84e10f0,1d5ed8c2,6219d24a,eab4cd67,dd30f084,8fa47a12,624f4c9c,64c02832,9b6ad395,dd51f960,41eeffc3,b3238764,57d21f85,d8c674ce) +,S(598daff5,aac2831e,21d5eff6,319e563e,3208ea18,e3ffe13f,2bf19444,73292f02,3db66869,2538e2f,e3689a41,dbb05504,bc86dabd,e033fc1,dbd7f84d,dd4e18c2) +,S(eefd321d,41fe6468,a7766276,5932449a,d3956209,c4c6a548,c4392db9,b4e39a97,6a372971,d5515d4e,c691b3cf,e73ccf6a,a491df97,570c9f52,3f29b108,c626c319) +,S(5a3a8225,49ecb78a,9c5aa12a,49e02c5e,10c168ac,e053f85f,30921724,96177ee4,482a65fb,f57726d9,d4ad61c6,75cdd5c3,25b6e59,899366a5,3ddbf239,96016448) +,S(e21f7d4d,b2343eb0,1d23d1c,5ec76db9,89e1e624,2fabc41a,b204ca64,838eee55,fb64c87d,ba7c54d6,f1d68d7f,a49d50b1,bd79d699,a75227e8,4363ed30,430b2605) +,S(fd688c92,f80983b8,496689ae,fcc0820a,a3d91fb2,aa4d599a,f48de5b0,98ed491e,7f946da9,9169612b,dd6ad8b5,d686052e,3ff25610,21432c92,f8728187,29e860e7) +,S(65594f34,947f182,bcd1703c,dbb1ddbc,4bf59b2c,2fff23f4,1d363631,cd54af0f,e8d98a21,a603eabe,cc1a1b83,9ccd553e,fa5eb258,5dc94e10,d134f40a,63b5bb1b) +,S(4f47f3b9,8bcf3917,464c07cd,be99d2ea,adf31166,8199324e,d120d087,e14789e7,279da4fb,d718e578,b10d316b,9994dd05,ffa05431,f85db2d6,6d4327d3,68aac28a) +,S(32cd8b52,c027e4e1,7991ccf5,6460f3dc,1d2ea6be,6434067d,bd4880e8,a09196dc,1d3066d3,76961716,1882da20,e467e035,4ad84041,f391a042,9e94d8a0,5d89807) +,S(c454b400,c7946f9b,b35003a7,c51e8037,dd03fcda,f0a19b14,f8daba3f,310d8bec,dffa7652,86aecb65,2744c9e0,21229687,1c305d91,6279b414,1ca1a,acc021b9) +,S(151b7159,4fce7438,2ac83025,6d98abbb,6ca309b6,64ef0235,53495342,34f7b4f6,fc61aa0d,722156b5,dd7ffd24,38100589,1bf236be,a41aff71,c3f1964f,15978a28) +,S(59716aa9,6b60ebde,848783d1,a686e9ab,e337b87d,104aa3f9,4cc7af46,ea8b8710,2e3062d4,a7d290eb,f53ee38,31dd8e80,354fd671,62a01a4c,73c57fb3,4582d345) +,S(81838542,7622429e,832e7a50,b1a670e1,2a626c3b,97cc69f7,abaadd5a,44a92395,18a88d63,d42e3ba2,af4b6c36,9971b0b9,35363e5d,77417116,b58de2d,8b6afb42) +,S(c95cf1fc,af7dd741,479a54ca,40a0e264,a989f0da,99b3a1b3,c4f67284,c8ae2a75,14b32e26,99662bee,51ad8534,fca1925a,a835cd00,9807c5e6,915b8283,63872f76) +,S(9362c939,ea51a649,2ae2dc2b,c01e4bfe,ccdf4612,97932668,2435bf44,e9c6ea1f,944684c5,2cb534b1,4871f48,41e889ad,933299bb,474b392d,a1e85ffc,5763c2e0) +,S(8852fd51,1e5f5e93,c6c3c7b8,4b0544af,cdb7d0b8,497d4bfc,90cb7322,28a77040,b0ea5bb9,c338a6de,7333b4cf,ac29f997,36c248,405facd2,6ce438f9,cb997a13) +,S(59105318,491ab266,2fb94506,532ed81b,74c8f82e,a13581ae,ef6c0c77,80696ad9,3417191f,bdcc1dd1,43323ff8,6e6051ee,921dcf69,9eda369a,afec66ff,a06097ec) +,S(c78bb701,8e96901d,3f13681e,ecc24df9,65b124b6,43f72904,ddf00ce8,bd28a127,ef07ce8,1b9c1cf1,26108dd5,f96ff86b,e0d49bdf,ad3d518b,1004b3c9,4c79bea0) +,S(9eb55ba5,2b5d11ae,3d419ede,5a5480b6,c2aee921,6f9aeb4a,96e51934,e8e4c11d,50094963,25b94022,2642ca89,1fb4697a,5e643e50,19670934,99937432,f020eaf) +,S(79ca2986,d40c7786,dc4d3e6f,71c33233,ad0b65fd,96822383,c11949f1,ab42f5e1,275db48a,fab1f0db,188e1298,4b391ce,6872e216,85c04c0f,3e62d42,d1e6d310) +,S(a2cf65b8,fe2a7abc,b78bcdf3,f25db18f,432ada89,1ce7d99f,faccefe8,e9673463,418e9be4,f6a1dce9,200823f0,5a6a0e31,7924a0f9,44c18b2f,1602a2fd,1ef13a72) +,S(7f6881f3,9f4684d1,3bf35c4b,c350b64b,28eb3c44,2adf05fb,c5e2c1e0,307fef19,20ac47a9,b954e805,db6fa20a,4e1a04f3,36c058f2,1946aff4,d4c24f63,6bd608eb) +,S(abf40dcf,72704e6c,65502d17,aa384bca,5834a802,62ec0de2,fd46ca2d,d9316ef,f605192b,a8c56b66,f3bdb35d,9c1df4d9,94662b41,85e8e6c2,9fde9d27,45039564) +,S(4fbb0d5d,ada948f6,2877c665,9cfe5f57,c6d5be5c,8cbb7bee,71cc575a,f4c92989,d2290911,45c718d5,243e1ef,92b8f7bc,2c77af95,f8666ce8,15900462,35d1c3dc) +,S(6c62710d,d0ce5eb9,5196e202,7c3c1d12,5a25f329,878b1f38,fa883146,b8ccffa4,c70ee1dc,174a6a4b,908b54d,69c94ec,5829bc8d,f6513c82,b0fc02ce,f566dde7) +,S(83ac175e,e220c800,a40adc87,df8450a3,963015a5,2c9e9497,602f930c,37af6c12,b7dd932,95601178,f6db7b5f,98046d7c,e42371ab,34e5f11,31f7cb31,59d37994) +,S(c823727a,348e275b,f52c18b1,43653c3f,8f0a5c0a,e8f48432,a8016486,ec3674b5,760237f6,2222cf21,fe1813da,4cfe9437,edca8286,cf3be63b,5bb05560,fa71235f) +,S(388b02ce,506784cf,2ec7e315,e765f126,23f764a,7d1ef836,fe360355,cb3f0517,ed0998cc,9069f336,c938b639,d6a74e8c,672a7d2a,2fe1dd1a,d7e18969,e7e57b20) +,S(517d4da9,e25f9eaf,7ab6efcd,cc00e6eb,7bfb975d,e8287b2b,d7d15914,4b7a981a,2ea7196b,a14b60c0,78444a20,2b67fedf,8fd119a3,7a39738b,17694cd4,c0dd712d) +,S(eac89275,54b0f71c,4ee80260,4945c5e5,578fdd50,ad68c478,2295670a,80432bee,dfe1ac53,dc9e18b7,1a930e73,cea36af2,8c8326eb,3615f858,fa1d3884,446f59a7) +,S(f77a0877,e7ffd2e2,cba9f0b2,c419e886,73711125,7cee4480,f6529851,6013ce29,fb245db7,29acfa2c,145011f4,42c9d480,5fcb0be8,b7f27dd9,9d532f6,aee2d57c) +,S(747d96af,94b3ae3,4cbcec25,fe8f4b74,e8d2077e,31ca2520,6d0d5613,3a49bd7e,b13d780b,8d322848,de5463af,3dc9c6fb,4cee70e0,da4731db,14916252,4b6d8d4f) +,S(9bf6ae06,6db68c50,4ef9b1cd,6d123efe,1d8608c5,3a1a2276,f1f44493,f8b5bf72,5b0080f7,694a756,f306714,aa9d8b3e,617b7c5e,84d862be,470df13d,e79c8994) +,S(91d0275d,e99c876b,d6de2cd,481fd72,13d9f6f0,e41c3444,4790dd80,cbc72e72,b12126c0,8b03b040,60183216,d1468246,d32d834c,57e687a8,9ce42ae4,d4eba7bf) +,S(e3cd4480,6585252c,8eb09442,74222016,5ed4cb90,462310ac,ddc769b1,b9a111e2,d8821a94,f1bd3def,434557ed,4739d625,c74548d1,44bd370b,180fc4d9,ee04afa0) +,S(3502269d,e8a68ef1,a0d74a0e,1423de94,99b84d3a,1fbef636,d9f38801,ed00d64a,9c4b6259,8c1bb627,449800ba,d9e93c7a,265114eb,99f9b5,7bca5b6a,72e3b302) +,S(244e51da,a54a3c4d,69f7a53e,6ef82bf4,7907bb40,7713f5e8,84694641,1daa2ec3,61f00ad5,f30928ca,a20cd38e,5af6b3fa,afd4def2,f8433609,4f08e82e,d46a0320) +,S(4f00186b,5d6f0420,88ac1221,a13e3aa4,60190cc2,2bd8fc26,4df81f44,1e508032,fcf58149,b8ab94c,67b30d73,4a3a5835,c7f89e44,6aa8d2d9,291c5f6c,b17b2e3c) +,S(10a96b69,2f522f4d,58d1c9af,463ae371,73e6f72d,93aaf756,6267b3d2,f62a579c,fcc7a656,c9d72dcc,1540a638,51328135,85d3a0f4,ba5242f,f5aa35f1,88ee3070) +,S(ee66c2c,2b19242f,4d7a22bd,df36fe3b,b5c151f7,1dd8a81,93fbae52,23064f9d,9d4f46db,7639d9a6,95d51d1e,44b08d6b,4791e443,744042e5,cc9e3933,cc27aefc) +,S(872337c4,e34a3dbb,f4b274a0,a47c1398,f78ce842,fb11b994,b550e9e2,e21934c2,aa8a7840,d6dbf62e,d91577c8,8b8c6baa,69e01f94,5294e3fe,4ccbadc4,c1d64221) +,S(e2eeb213,bfeb413a,9093be1a,7f75820e,5f48dc34,8515ef1c,7026c116,9be224a6,a49c846e,9132e039,9d66da39,57cebf1d,2e673831,3a89f682,c28d2230,1792d36b) +,S(fe264a9d,63932bdd,5cd4629a,dda37c9a,8d2bbb1f,5809d333,80a561a9,66af74c5,543b7920,c6c27b7a,515b5adc,b8d144ae,64118447,dee21638,1d6cfd2,5627fc53) +,S(13806a30,2d32152f,a1ee8060,67b07cc8,fce1e67f,16f21859,e7b60de1,37debf51,ffcb1150,7be5c2a8,90237923,5335b575,4cd83460,423ece53,18be988,c7e5e978) +,S(db67e361,f9d91cff,1d8b99db,b7bd2584,f1b91cfd,77473802,f603ee9d,debf4dfe,6407a133,7604fbb9,35fbdfb,9fd6e2a4,ea6d8f28,a63e7524,172cebfb,d3331e2b) +,S(606d4f47,d1d4cc58,3e30f214,e1ee57cd,98e68b6c,91c852ad,cad6c32c,989d8bd8,81911891,8a074dd6,ebfb95b1,c97b4fd8,5ef0887c,15ae5e88,ec6e97b9,cba46701) +,S(51d60942,e93fbcf7,e230c116,77528c0d,3b63f7ee,64c1da65,692aa91c,af482ecc,b82db22e,3f104807,6338369f,d77dc11,d982296d,e630af66,36cedecc,108ae433) +,S(2553006b,b8474473,29108ffd,cfd9c91d,22b7ad2b,6a0e7bb,72f98a0b,770da376,6173583e,e6b238be,ff3cd6cc,9bba1b48,d89dcf6f,481868dc,773eea98,59ffa871) +,S(52e35836,fb0a1c1f,efb092fe,3c95bb32,26bf9aaf,50fd1ddf,29ef0ba4,b100d794,639078d1,cd1cd22d,135ca950,d754d3f2,bcd11a95,91abb6c7,c4a5177c,53adc86f) +,S(332e02e5,5c089c84,82ee9863,a4dff4ea,b01a7a83,4747ff83,512fb567,7a8ee3d,b1edbfc7,9c1f9264,10c4cc3b,8919b4f4,e89bad8f,34135af5,f16b1c66,9a28b87c) +,S(d9113a61,7d5a4a75,2080931a,84bad37b,ce2f907b,cc05adf4,16750e8b,8951435a,ab1f66e5,8d3a5887,2f664b56,6c2468df,f9d4d76c,a73111bf,57e10d1a,f7df7aab) +,S(71999a85,799030fa,b0575523,fab4111c,f4b60351,e03f8703,1f5a852a,f22131d4,eb171070,d6124255,9adbd82,565c8dd3,fba6b8c0,df939501,4223b2e6,148668f4) +,S(a9436d74,a39c7193,368ccbf0,d24098be,41309668,87ebb8d8,4213e0b3,436c23cd,7b93ba5d,e2ad9b42,ac45ac85,43f7ae59,7300e745,8fed1359,bc392015,540e7a19) +,S(f6288f25,57359179,cd3659c6,1cceef6d,c5a69631,174f63ac,115633ef,83530b2a,d54f0f2d,51a365dc,7ba8b630,67ae663c,b4102e2c,59cfa616,b8878483,6ca85722) +,S(bf685c41,863c9fee,dff2fdd4,ba47d726,1f0fcb6f,b0432a8a,3b7c4f6d,6f52700a,336b1d57,43ca6d28,52e20cd6,ab276441,61b2ed82,ea4e0051,d88ea92c,a66828c7) +,S(672eaa18,1009f3da,3fe74eb7,4b479e24,4b73b54f,206f7342,eaa865ee,f945b00f,3f056594,a113cd63,810adf1d,b76efaad,babcd42d,347282c2,ce66ad54,37cb89d0) +,S(299deede,3b6722e4,4c5e7600,214f85aa,4dd70ac9,df75cfe6,c020ec58,c8c859f7,92ecac9e,4a6326a7,8b01c0e3,6466723a,3d00593b,6597b6e,e16924cd,60105137) +,S(e4268a68,7e6c26b9,2cec18b6,8581bf03,8b25544e,2040d505,7b9823b8,b01c07d5,35d1c370,95a9cc03,f91db5d4,250a904f,b9f9daed,9388b5cf,d6a3699e,b03c30c0) +,S(7164e9,bfa6ade,a42bcc27,db38cf5b,fe908499,eda21bf2,27063fb6,369b1ae1,a2367f94,fe683e07,1cb7ffb4,287cce88,b11336ca,98e6769e,178262a6,b9103d9b) +,S(84d8d32,a4be7402,1c94d3b6,c0913724,b2db26fd,862fee1b,c467a37f,b98b299a,46b92145,46603cb9,1cd5ff05,a237079a,e290b496,19d868f2,8143d660,94e61cf5) +,S(60372ba5,d0eaaacb,c1445979,74a0553a,6e63c4d,15001b76,39f5d05b,84f626dc,8fab368b,c4d011aa,edf7d98c,2e6a0359,5737b1bd,bf701060,d30c9f0e,a8e8c847) +,S(453c17f5,5364f812,a7da0f75,d7c074b1,81cc0901,a938447c,df55ba92,a7decfbc,53d465f2,6d3d86b,a76ad1e6,f147d208,474989a4,64ceb6ce,79972cc9,3e2e2c3a) +,S(cf1f79b4,b765a894,2b967271,85d0c2c4,dfab4c4d,d679693a,4b35b343,c411cdc4,b89916ea,4ea34abc,63b9292f,591b5c8d,5ce802df,9d4f2be,275ef244,7e1ece) +,S(74b07994,b7fe3a27,eff2f9aa,72f8746a,299f9eb7,81f09b15,f3ae595f,a0c4ac37,5464345,f4873a6e,9f4cb569,acc8e551,a9acff9e,5e0a92ca,e2c3f800,1888f905) +,S(f9de1544,89b7a06e,40115de1,fcb7897a,f6bb2b91,5a1e8971,8d5d5ee8,68bab74f,789b5c55,2b352db3,4345ca30,328f542b,ad22e5cf,d98e5b8b,e85646e8,d47a0e6e) +,S(c011f3d1,897cfe72,827d2cc7,c04a6aa7,496273ac,11f0df10,27ab4d69,aa745c5d,8e31fcd8,3842ffbb,a600e771,feb0cc2b,1fb257ab,7c19fe61,67802313,cdec95ad) +,S(16567ed2,4ea1cb2a,15418d66,c70c0587,386201f3,4dde86b,82f687f,95229648,fc4aa805,45366f8c,3ee336f4,51397e3,7f78188e,b6dff3ce,d80c7e7b,6d9f7cf2) +,S(8cd33d56,9acd3607,979b3c17,bf5c2175,ef6f3428,7a25c18e,89a1b38c,979d50e,f4312cbf,f301e942,61b7da0e,cadda424,336b1201,82ad73c3,c907be8d,840f8614) +,S(646e22ba,39927176,4e1df1b3,16767718,79d7a16d,587b9e47,5232a331,42ea2a5b,55378afe,5f29feb3,2a3152ba,4d83305e,f77b1025,79154aeb,7bb8b8ef,c5958576) +,S(2699d984,462e1fa6,208a833b,8af2e32f,58cf2d02,7707b4fe,2e3f888d,82e8e2fc,ed6c46a5,c5121755,5f236a62,21399a40,5fd87fca,f4cc6603,fffb440d,54b888c4) +,S(be4b6631,3fd3e2fb,163530c7,2fa4a41b,e36d04b2,638315a9,1d07de72,c4ced54c,a7a71077,83a27b72,4e8aa644,a88ea181,c770cf6f,489829c6,6660c44d,45fd2ddd) +,S(1f2ad69d,a1438b51,fe02a47,9cf865e2,18bdbe01,259b0818,1b6e7e6b,762a72a6,d4da99d5,7aa328df,3c587a45,2d756bae,fc09c626,fa5516bb,c8781b9e,b1ecd29b) +,S(b1adb241,721a1622,35540622,f8e84291,e1c2702d,70cad33a,89aa3806,f7acda43,e6cd9324,12542fc4,25b8f16c,c0820f3f,26f33e11,1ba0ca5c,b5aeaa54,1fa3d9c6) +,S(b604e2,f06df266,1163604f,2a1941ff,4d6991fb,84796c40,ccbe74e4,cf68e207,306936ee,e887427e,6005b265,38af5ca,53b3cab9,a3aebaaa,96556c46,7db96e88) +,S(afb935fa,1e30617a,9b4f26b2,e7b150b3,f33566b4,7b5b4a7d,6223fe3,9c0dced3,83624f43,66dd82d6,8e4cd94c,464b6322,db0b1774,9fa1125b,a0944503,b0c63b0d) +,S(5cc7252,a08ff892,93022eca,b56a5e9,cd2eb4c4,71161d15,5d7a5113,8b12d235,c272b6cc,42461529,b31943fd,fcb51a59,7a0eaec3,ae8c2754,827fe1ce,a182bcc4) +,S(6c17c206,7c72a1ba,410f2446,e4ae2012,6eccaf88,aa4fea14,522a7607,143c1122,7172af08,2adea428,2f6a3cbc,7946db2f,c0170975,50ad8ee7,f4c514e5,dcd693eb) +,S(fd82afcf,c55d226b,274cd62f,385e882f,716210f,9a14be15,baf7e17f,b98eac8,4aeac666,a1153851,6d66390e,6c7818d3,3de26fa9,3d234eb8,5e4d5b42,853eb3c1) +,S(3d0121e6,c758dc91,8ce3bbca,1884788b,20717075,1e80742c,49b202d3,c2f8012,ca6b47b,306cef6c,662bf21f,77bae3c4,25009561,72dfc630,e2b1a6da,e733413d) +,S(488306dd,3bf3bb5f,24160f1d,67b8c053,bceb8da3,cb1b05ae,7ae9fa72,e3f7b0c2,2356a8e6,77ae2f06,6135bd88,1fab5b4c,6aa57769,3e2d476a,1b2a4db7,fc6c27be) +,S(d7e91488,6786009e,eaf12d14,a23ec6e7,fe41e406,aca5a5b7,47010ee8,8441d6b2,c98389a9,143a8fdb,df4a67d8,7c05cd4d,fff75fae,845e7e62,26c61aff,3dc4dde6) +,S(873a2877,9c45280e,3d196725,5da756d0,ee5ac567,cbb7c52d,c8e654a7,ed78a1f1,9bb9672e,e76feae0,d52be301,983c182d,ec99b228,defb2166,5310a4ab,cae7eccd) +,S(410a7c98,85f531ab,46d99b26,b6fc2576,97723e4,bd9b9c57,6544542e,2cad2ff3,8bc9e686,4f139032,cd443148,4f43abd4,3234e3eb,3825a0a7,db8176be,cb5207cb) +,S(39269060,b38b4abb,107c2230,6f541353,d8627901,3399b368,8b650ad4,cbf99144,780c2949,aad303f,ef8fff3f,b9734551,b45639cd,9437935f,d93f7d95,bc9d1aa4) +,S(bbc52d26,36e861e1,3e593d4a,c6ad573a,e4698ede,f101b3e4,f4aaca54,325b9f9,4a311f44,9f16bfb6,4c5c554,5ba373e9,fc41b7ec,beadb4a6,a929cf0d,79f37922) +,S(bb74e659,5ed6d931,9716b8e6,120f0cb0,57dcce87,150cb26a,cbdf5b1c,f86ccbcd,9f2385a3,bb460cdb,8ec74db8,fc5e6014,f4310665,c5b69e1b,cf96203,1afe085) +,S(67e64d65,badbd97a,bb204cb4,f9009f5a,973700d8,34f6b6a5,395fbaa2,c6eb0672,a122f76f,67490b28,9977d730,df544f7,d725dfd0,93135ba4,4bb348c9,e4dd3303) +,S(dbd294ba,e0775f43,f58ee677,6240eaca,b9b29ceb,92fc3354,de4d4b20,95548050,1987ba2e,3ce8ef0,5b71acbf,4c69f706,e2cb4d6f,354f0fc6,53a7a9b9,5dd1c115) +,S(45c946f3,93658d3e,589fdcbb,6895c97d,60352342,3a3676df,680b6bad,de6cee1,629c7238,db2cd3e5,29e5b30f,a8ba5629,dcbb1ccd,ada1eb22,294f98f0,4cae2d00) +,S(33ad0e14,44be7775,3fe47875,2688e384,2be7ae06,7d38e473,6b7dbe0,c106e14f,d89eed78,6518775e,1ef441d5,fe51c4d4,b2a1e377,eb1a4cf7,804c2e1a,5175f1ef) +,S(f9f78161,4cd463fb,6e358274,e47812b,4b0113d8,3f426aa7,85756c6f,b9e7853e,5eab09ab,51247c76,f87f592d,77e0870,238877dc,a47cf6b4,5fe72940,ff4469a2) +,S(ed3015a6,7a1fec82,f0f7a59c,45cb69ae,8aa0d883,39a05f,f6959c9d,b7d761c5,b7c94a9c,28389f1d,17bdf197,307411fe,1c395483,da8a097a,fb3b5fcf,e392e16d) +,S(301af330,de741ec5,61b71fc3,c5048a42,6b55d58f,800934f5,c59aa8f5,914092b0,3d3137d8,262d196d,872fe1f9,8acba295,fec02ee1,30aa4c19,8c888765,357b67e4) +,S(21e197a7,85953a90,226c1ab0,441e35a0,fd8444b1,92c0e5ad,65588063,f40c1246,6811f94f,18a9569d,4df2ffa7,fd8d75ff,5f66ad1e,62da2a60,c0084381,4437a2c4) +,S(325fcc8c,27804b7c,e73d6687,70db7f5d,3ed4b6ac,feb04003,c61d6262,8fd41385,2110e8d7,24e3a03f,46183536,b208b595,8586202c,2e69b954,d3ee1500,21ae7d8) +,S(48597aad,ec69eb0d,90f60e6a,abf83129,1de759f5,eff24d81,8677248b,ea87d945,c3fd850a,cddc2597,499be90c,24e249b,328728ff,5443fbd5,6515a6f0,4111775d) +,S(58648599,8ac44bd2,e937796,d8dfa60d,c56d94c4,d53cfb77,ee0e380a,53ab8f76,2f47f278,6a285454,475d3c9,ffe9ee44,a93e15cb,b17772ec,67a30943,d3191110) +,S(bd2761c5,722288b1,409aa7a5,db7690d2,73dba76a,3847d94e,3e3d3a7f,2dd35597,42590713,6ab6745d,5e573412,663d4d93,29c4a284,4430899d,68e5ca64,197ad58c) +,S(fac9260f,1d420371,7e468769,1af8c270,dada5d97,5ceda9f2,64deffe9,1990b52a,9ce17c1,ebe94ab4,e092d1d5,850194d1,7e6a87e6,7b283ba4,ba68640a,94193314) +,S(82e65b52,e4585ec1,4bc03591,249cf4bc,e5391f69,7b813175,b3b4b403,a64d6877,627e196b,42d327be,48526318,2dafb37e,222578a0,ccbcc443,7941eca4,a82ac893) +,S(b9473eb4,dd002597,464965e5,b6d95842,543cd14,e18c95d5,b45bb654,eedbd6da,1b6e80a5,377ba31f,b5b6fcac,633321e7,f6e5b2ad,4a54e143,e963effd,6805c3a9) +,S(31113d99,4caaea40,40182db0,17a880ac,64b183af,1746b820,2f29fbd0,d1bcc524,3f476b72,eeeb7c27,f9d04cba,71ac54aa,a25ec4ab,15d77e17,8544a651,653e83ad) +,S(d04adc5e,73e21fc1,8c3b047,4d34f8cd,1cdcebdc,5dabf14,e258af57,860157d2,b21150d6,ad94a07c,d11a81c7,b741a2f0,5cd6a5ae,aba194ce,b874bd19,bfb6c326) +,S(4e59356b,f280f51a,c492751b,3b3c7c2e,3fd1fb58,679b4fb5,5abeeb65,bce6ac2b,33a1ed9a,1d9c34c8,42b95e4a,108c7985,21c1f06,91f3716a,68fa5c5f,89dc73f) +,S(53d76685,9ddc778c,b4f719ad,55f74fa7,85d52300,65c06b1e,4aafc560,39ba3547,168b5451,29170fe2,c53abea9,68a25dcc,2719090b,e0814635,a1dc7267,9d83a01) +,S(7e9107a0,d2830362,7e53e06d,6e82efa8,b1a037a,328df546,a6d04c30,3037a63f,222d8b81,2a99860e,87fa24e0,aaab4ddb,b903cbe6,39c46cb6,3f2144d7,f8856489) +,S(6775b2d7,b23dc08a,beb65049,db8552f5,565a092f,fad86865,c17347e2,a744106b,a6f23c87,fb639e66,9830ed33,34c6dd42,6bab0e23,aadcff44,1d4c73d1,a61efda4) +,S(559885b6,a54fd0dc,b275662e,f66566e2,87a17219,e9c02f68,8c1cc8f5,6f814673,2ec87df5,917d1d7b,f217621e,82c31844,d2bb138b,bc35f873,5b52309a,baf800c1) +,S(6fb774c1,2971b620,b40a17ec,74dccc9a,8c711844,a44a3e4d,e8310d47,bda53428,68ab0f6,57b823e3,35df55d1,ed9632a8,f0825f67,8a05d5eb,9e115ea3,e43ff4e7) +,S(623c155c,2787396e,815ecfdb,5f03bdb7,282aeda1,7c9298f5,306ec10e,21dd0b90,69382be3,a4bae926,47252910,ad1ec62f,f4bbcde5,6259cb52,10ff2158,6b111f66) +,S(c42c41e0,63db66dc,9b32c21c,af94a158,14fd5b62,aaa975d,3ca06925,f6d6ecc2,e93159a3,ad6fbcb6,38f7b09d,40601189,cafbe5c5,90c70103,b56fbd47,d36ccfba) +,S(1103e98e,7a1659ac,4242ad9d,6fb012d9,21696e58,413f71aa,e19fff6f,1c334fbf,9f2d4667,ce5a1285,524d91d9,265d7a5d,da9f5ea6,cd508cf5,90076d57,a975bc62) +,S(9e113cd5,9e7177b9,19859144,598263cd,630f72f3,4da00ad9,84964043,9d82878a,6a09bef7,6e13f2f6,8e70ee90,5dd5af4,495f5965,859a1d83,ef149f67,2643c9f7) +,S(c03c5ebc,d04bf8a2,bdec182b,32d8c726,1913652f,e4547892,3e0dba7a,1fe275ed,f567e3c7,4b9313c4,11ac9411,11f1b62f,74a16f79,e7d90817,b54d4d89,958cda21) +,S(205c4c44,7b84661b,cc8ab2f0,221343f4,140c9efa,fb107c59,b5095b48,25f54b24,94a10344,ac5f48a3,600309ef,8ef94242,a8050865,3c018e57,a7734d9e,da18a55c) +,S(e393821a,58c9e9c5,6e45cda0,334bebc4,359c4b3c,1a60bab3,f1dce2de,c1da81b6,5469cb0f,4edf5f47,80df616,3a6b7074,7b26291e,8830d113,79d84aa2,15814e6d) +,S(38fc36b7,a866b165,a424f0ae,74ca34bb,b05922d5,1bdb447,5df797ad,4d042e2f,a9279b50,4b3edff3,aa8fe039,3415c21a,556609bd,8089383f,f5dbdd34,291c2b1b) +,S(1c4a1aac,3c3247d9,99a75a00,305a4092,c5f34321,d3a33b66,b110331c,85be2b27,a10e4138,a835e3b1,16d7b6c9,46c752e8,dc92c39b,21677968,147a3cab,fa5a0f1) +,S(41d70c82,207c3b7b,716a2d4f,784302e7,e1034555,a79965b7,d951ebac,b7d62c00,7311a36f,cf3de546,37013e84,b2162c35,3eba0387,3d296427,220e5942,af398bac) +,S(bada1cce,dcf3dfc,9834c49d,200fb82a,b13cf2d3,d5da9ee5,c9c35448,352e660a,42e0d3db,511cbbe7,942ff10d,a7d49805,972d9373,a75545b7,206e490b,6c5dc651) +,S(233c0c68,4b9fe726,baf2b7d7,a0503e,7aba8b1b,3c4f28d9,4d095107,2b429bc2,a7bc02a6,2b81154,c3bce0f1,6a0b4f77,d412d162,1c713372,11ac1c61,a8f6fa28) +,S(a675f208,a0d48078,93525e1f,b6c5be3b,ef24ade,8d3ab14a,afac550a,fa6362cd,3f8edef0,3e0600fd,1fdf10e7,c5562ddb,af4266a1,52bfca59,e1235d7,c9e8223b) +,S(4adffdf7,a8a92b65,6f747fe2,92e6bfd2,cd3deb68,ccfd7f01,5639d779,7d21e48c,4d4079af,a6e89720,3a50015,92e43c6e,97fa1e57,11f21bef,c9df4274,441f7d81) +,S(c786e96d,fa658a6f,a9f1fbfb,a15d7021,835ebbb4,3e8ed3a2,c7ea573,c2944dba,81130470,7a10b1e8,74f5b856,b7223346,eef3c562,8959454b,d536494a,f075393f) +,S(10df82c4,64b75895,2c54f335,6fc24ace,cda4578f,d34ae82a,8a1eb2e3,d0830349,dae5c271,86031dd9,2eff2db9,6af91689,2a131cb2,44534495,c3562cb8,dbc5e1b0) +,S(55532c4c,c4483aac,26b049d7,df1da7e1,ef281c7d,bd99d21b,72626443,f2c748c4,58160e32,da446337,d0642596,c17500f7,b0e64081,1017bc1f,4452c4a6,8d2c2789) +,S(fe994c5,d63149e0,d31f6cdb,fce5b941,239c4adf,8d5e6866,37990411,d88ead47,200532b8,4ee2fb18,b2c27cd5,9c3940f3,58c6a2c1,d96ad043,4d826c8c,2a457dce) +,S(c7690e5b,3148cd96,592e654f,2eed33ec,a69d2684,545cbadc,6f6a7e8b,4d3cfbdd,98e0018c,36423854,6dede771,b78bc4b8,c52d956,d26eb22a,e447ab3a,144cd394) +,S(8f1f0986,d273476f,b31d4ddc,de949584,97ec74c9,acc6b0eb,900e4cc,2c98cac3,31f420f4,b9209657,1656b663,a06804fb,78597071,6c138106,119ef214,43aa765b) +,S(bee7ab1c,c23f6101,be01ed60,574ffca,70fbd4db,ae73e5c7,128da065,9f78c042,9187835b,66b2b634,a87d1baa,7666bda3,57dd5ed,26871976,8e0ea9a6,ed102dfc) +,S(8093581b,3205e5c1,90e9d38b,5b5ac422,b48fb5a3,9176bf7a,e1d377,c764f74b,3a3e06f3,4c00cf7f,6216e67f,2d55236d,db54640f,192897e9,fd68820c,bf22ce39) +,S(fc018da2,70dfe007,871e0be7,f5edfb7c,30fc30bd,bed5052c,78a7701b,50954702,9483d20d,af9fb123,723e0c17,7905e94f,462831c7,dceb0238,6f0942e5,188f3a90) +,S(f4ca4cab,7f06af06,d0a8bd7,97d6eed1,7354420d,65d80e09,32f6eaf1,ca12a39c,76770553,69f93094,3f368b0f,2ef6e412,f3d5a45d,1c7edc3d,9550fdd4,ebb1950) +,S(fb03fae2,87265749,787de276,84bfdab0,4993112d,f384113f,1dd41e6a,b438bdf3,ae8829f6,80f60534,50113930,2aba238b,1dc295bc,6598c060,af8393b5,1153b479) +,S(b76268c2,6b873f54,9438a569,5e2d5e24,a92da29a,ca26f18e,143e3290,69638a45,bb4543e,23abdead,c3377320,dd8ffb6a,d38967ac,ea90afd3,23c69373,eeb2407a) +,S(87db8064,9a5a31a6,487893d,f487c00b,143c09c8,fe878621,b592b25a,6c3d8646,872a4547,520d307b,a537d42a,ffbc8e9c,e04d1c80,e3d4f506,b001b0f4,79e92972) +,S(fb9295d5,a7c2cda9,c08b0f39,1fcdea4d,b768b086,dd170d8a,966516fa,bd476acf,62496929,a85c828c,cda71d2a,ae70c429,7bc12f03,5a99ff75,7d66cedd,5fb5135c) +,S(96f749ed,a1fc306,6d133829,774293e0,b179a598,327c3bde,a2e94200,770d12ba,c16915b8,af011de7,614fda0,ce1c4a3,ffeabc2e,2e891e4c,a2d9c277,247fc8c1) +,S(1564d7b9,77b4eb29,e7b23ba7,a3cf453a,8eaadc50,87448fb0,fd9310ec,653ec66d,6d8935ef,a7d41cb7,5c5dad07,c3ca864d,89e49f0,f74d4474,af85bf05,c408009f) +,S(93db7b68,9ed6ad1d,bb61223c,dcca7280,9cf4a49a,14d94f3c,7cae77c8,f1298340,9088165,7b4979f7,26b156c9,d34430db,4a0af993,eeb996c,d091ad5c,4f7bbaff) +,S(2656af7e,d8a2e718,9849cd,793baf93,1c23374a,a3b5596,d8c88841,2b6a5ad9,dca0f4b2,7c7f1547,97346dfc,589374d6,1224048b,ead5442c,9f8950f1,63689045) +,S(a7dc8558,c0adf996,b7f57c08,1b509e34,7819131d,42647498,ba819c12,6d26cbf7,9fc494c9,2bbf6116,14527eaa,1de4708a,f0c19847,3ee9164b,6b9de909,f6a4497d) +,S(1f6d4701,effe09fa,17ecc014,a7a0033c,143fbfac,ba4861cd,d7ee2fe8,5bcb2cda,84c5b017,81ce481a,e610bd8d,96ffa58b,b7a158e9,d1cccd79,7e6436dd,b1308de6) +,S(eefe37c5,d547b779,d905849e,dd1038b,f054233b,f2d1af47,1684e5c2,a1e69960,b5f00dee,8b1f7960,aa068db6,78b6b41a,f8c3e14b,27c1f43e,10f9b34c,fe8eefef) +,S(8d4e8462,60602ee0,948ba5c9,f0506046,d0bf3fd5,e1b93073,bcc8a6b3,30af96d0,62d0e36b,bdffa309,f1257b23,6327506,5a5e7999,b314dbed,edc75800,b35534ba) +,S(da22079d,352d3527,5a80b95f,80b7b8b1,3eb6d178,310b6889,a94cbf2b,9a9a898,e8b06b65,37aae428,cd25fae,d0c1af8b,827b296,886de122,c6690a19,fe94df72) +,S(beb411ff,67cdbb5e,58da6353,172813fe,e386c7,95550395,1ddc23e5,d4e579a4,919f8f30,41f53020,4d3620bc,b0bc80e5,9d87ab73,355c046d,cf2986d3,c9995866) +,S(b0a5732b,76b4a526,e8e742e3,528891c7,3a1febb5,c7657a90,4bc1f95b,96d462b6,a5e4f134,93f9e24,75ac7dab,479092cd,fb59a931,dd042add,3d875e22,76965a9e) +,S(5a87a782,13130193,4ce6180b,714e99c7,30fc8bd4,fd4e8c59,f5b6aae2,f3622561,a929d120,68a64953,90c559f1,ed8ff0d9,bef92431,66117208,d0e8a08a,de9a3d0b) +,S(777ba7aa,6c50e927,64ed93ac,daf56285,9909b031,7c3c5ab9,38ebba26,d62a1748,27a32172,d7ff61ea,b6a26d00,c252f99d,bcf614af,1434641d,cdbd5f4,10e6657e) +,S(ad0f9f5c,8fa07d5d,3c18d4a5,7dc16bc6,3be0dac5,9166fb42,6bfca8f0,65b76720,d2c9c778,3caf2c93,f6c3980e,60ec0fcc,1f1d5ffc,8aff6af,a912b5b4,245fff6e) +,S(8904706f,17aad850,7a71f0c0,94f981e0,5e5a42d9,7f5cc3ed,99b4f635,660e227b,371d5f58,a63ec71b,3cd8b601,ee622586,2822a2c3,99ac70f4,ce293846,23ad8198) +,S(ce32a220,2e276dd,3f5b0a10,38a70f21,3c29ba7,58934c4e,27ee3bc3,c9dadf00,e43d28,80486b34,65e545d7,6618d80c,56874afd,29ea4ee1,e79dbe5b,b1ec1f42) +,S(3d031c0,c717447e,19266420,cef08d59,ac2aed4,7e84c84f,8980e8ed,ee59c7c1,86eabd82,d6a5f57e,cdb52825,a8c726d5,4a9faba3,6272441b,22627c4,a321d970) +,S(9dc08947,fa3983dd,44730aee,d8e94f2c,78eefc44,df126804,281f740,53330b43,58838246,3fc02261,c0e771b9,3d4a90cc,c2c19f7,2893ffb,22fe6d5c,6c5e7318) +,S(f9fb51c7,29646acf,94ecadf7,30989d5e,669ca4fb,3b4dfe66,dad9838a,f239057e,d4a04a8f,f44b86c3,17ce4350,1a2325cd,46b5decf,5f4e14e7,17ef0c30,1241f8e7) +,S(d4a1c33e,816419c1,884c2838,abc7148,c61f05d3,71fe3de8,9f06b580,cc5e1006,28d8f049,a1daec88,5d186da2,66e2b8a2,893d90c8,5e720d03,a53cf8bb,f8a10208) +,S(1b1c6ab,74436126,203ffd8d,8e9c58b3,e18f2767,3a72bfb4,ae4c9e25,ce17c570,ad28aaa5,eaf7128,fc8788e5,b9c1c13b,a4cf16e9,f651da6b,6c43fd1c,cf2903dd) +,S(3d791154,b2c062fb,e1f6ad1,dcc17bd6,b648aadf,cd573cb7,d29f9e47,e089e1c3,a578f2d,a568b0b,e95e1189,7bad8311,3098787d,62756c99,7dc3d795,8e0d3745) +,S(6daac2f7,ee7b01f7,277b3a5a,44785b4b,c6b6adf9,b112dd6a,227b2b46,9f27940a,fe9504e5,75c1e349,9267624f,2b2e603,55befd7e,d66d7fe6,80c521b5,e0d1aaab) +,S(ea6343d7,73a5966c,2ea66806,ed59079e,8b216a9f,4fcbe8f6,744808b3,2478c26f,15ab94e5,cc1f4a5a,33955f6,b30571e2,5104c615,c0aef2bb,6a8f6693,64639f6f) +,S(ffc78cf2,4b436203,dcc1b892,c77fb336,463a8070,332783c6,1824acb3,f5cc55c,7bfe0b6d,666b28c2,3259c4f9,2c0dd94b,fcf53921,91d617df,da1c651a,1fcb81a3) +,S(db38103d,5156c309,67189677,9317879a,f31dcfa6,b8d0f5d9,1f2bc691,6090e6b0,b5b3e45d,9bd41082,cd3115ff,824ff027,78f47a0b,d0ae71fb,32c48d72,cd540c84) +,S(4c08de87,abf89885,2791b455,126e7e54,d660903,f407b842,7b4fcd70,53e0b000,a9f83c6f,dcea99fb,fcb301dd,c31146c8,25c02978,6e5019e8,7b1b6db0,731b9189) +,S(53b6a23b,8f93200c,41bf45b2,bd0d20a5,e6fa5db9,a3686a7c,c669815b,993604c5,31bbf5d2,21023fc2,fef75f0a,f7bc33e,b4d38323,cbdaa511,c40ed497,ef42a850) +,S(b39ebc0e,53b74f35,6f573a40,1df6f8d6,fe1e4fed,f7d976e9,949da398,a45b464e,9d58ae16,a633ea0e,86bad1de,39f0b203,c1ef0b24,b5f1d824,48fc606c,a97fdff1) +,S(182e4920,f4a60741,a0b94fc3,e3ff0bef,39f1d459,cd6c18fb,16b072b8,de0bd416,6d048d0e,ffdf4e60,8097cde5,46955541,491721a3,d6e051ef,9279c5c0,22a32fb6) +,S(7a39e7e0,a2da209d,8cbb9797,5f12acce,840dddfc,5acf7c5f,fe778a11,829e1003,c24aa083,20e6a786,1c161e14,f37b1c7a,65117e55,2c252445,20b47b67,66fb410) +,S(62e6173f,2273d3ff,d9fb640b,87d5cb15,e5df841e,3462bc5f,6b94575d,a110914e,7c424010,4ba37e57,48404997,689a01cb,851343f1,ea8259fc,938483dd,d70ac5d4) +,S(3960d4cd,96de0126,5c2cc88,68e94d66,40e9ac8a,f2abfcd5,2108848c,ad62467,fb24aaf2,85a54405,f75db03a,464bbc29,3bcaaa44,344c763f,dd44656,fa7faeed) +,S(463437ab,42694ce9,98ac17cb,fd4d9034,ab7a1be0,35f911e2,864441a3,eff8e3e3,370056b1,24b894d6,3631087b,194dc5ca,fcd2475c,a95402b8,418f1954,d47599e8) +,S(65774018,fd428788,e4234b36,42c8a354,770ddafa,c38040e9,49f194c0,ff7ad3a4,462ec7,cb17abb6,5200a88a,9874c7f9,40469a51,c48c1fdd,6c0938ad,67741467) +,S(738feb40,e7f16fc3,19ed6649,2507406e,6501308e,5112dff4,db9d12d3,bc0f138a,4923678b,84470212,cc5472de,2163ac3c,51ed5419,dc1b1b1e,78dc0946,f730b940) +,S(546841d9,7985d80b,a0eb3448,3dc5d17c,441b7eb5,d24b6216,ab98b14a,d320cf36,719434a4,952ee43a,b1006ce6,f7785734,c6a5c018,383eed75,e3660f7,94eb6829) +,S(31143de9,1a4b96eb,be7efe31,56b6688,5d39ce66,fa8ce202,57626dc2,8557ece4,d8d8bd18,36e5c388,2273143e,721bef10,b0c3005a,5e2fd3a7,e471ae33,ebfae7be) +,S(ad8076d9,29feddae,a52c009,f3967726,a0a94301,dfc12d59,da63c47b,df6566fe,39eedd66,13fb7141,796c0353,9f560ac,e23f844f,d0d3d422,5b36e41c,b6707602) +,S(b01a4f7b,9362be2e,78f5cdbf,d9e35f21,4d296a3f,3e233d93,2cf33c71,95b3f613,245b535f,c58254a2,157caa87,38e855ac,fa9b071c,1b6182f3,5260da9d,18e385cb) +,S(50f3458f,a781d513,a944ebd9,6f6b791a,1b0cedec,1421f9a0,16a7f350,2d5f429a,4972c646,c1ad5958,18766bab,5bf54ea9,e9c4fe3,19810f1e,27f46cc9,41594045) +,S(d7b606ed,e8fc3a20,925e0a59,5c9462d9,4e04b5c2,b64d13cc,19a47d1,ccf10b0a,dc39a8dd,d5447a0,f07b5e7a,6ea35286,ec01679d,ffb6eaea,6222711a,d57cc63f) +,S(7629836b,73691a1f,f3ae6c99,7e06f597,34fb9625,2d1ec88f,2af15cac,f89c199d,296e4034,8eacfd71,7f64beb5,76736398,62114296,5fc818a3,ea89ba52,1b1a410e) +,S(88f6a162,7baea31,3a2a5d5d,aeda2f4b,4becca6b,812a60d,4b5b4e22,6c822a1,d3acfe53,d6189ab8,31106ca8,2388fc28,5b567e5a,5172050,5be56bf0,187534eb) +,S(8e93c72f,cfeae58d,fecd373e,dd3f31ab,3e4fa28c,f53681dd,ebf37d40,c376283a,e9c82571,2d0cfc0d,e6f35e77,acf0597a,7e2437e2,80f13420,cbe93acc,52901d71) +,S(b2264df0,eaead63,111d7b05,8767cc7f,36d386c7,edf21792,e8aef135,9958b2bd,242eccda,5e4324a5,40e8d098,cad23ecb,88955bb1,126314fc,5da973ee,b1d83313) +,S(9f1c9e90,7a6813a8,da520f6,84553a4c,aab650a6,7eaf4f0e,f2ec212b,95a885ce,416dae6b,f47aeb47,453fd0f4,7da6375d,136b6ee2,450bfe75,504f3619,84a0f355) +,S(dcc7585,132b95e6,a4a24450,d557a0fc,3ec93506,fd1f5f02,17bd0f7a,6943fa1a,c62ca95e,d976d1e7,2bcad48d,9bc3a316,a35e8496,952a7a07,760ecbc,8903b001) +,S(e3c674b1,eeb380f3,f08b1d64,32f4dddd,77cb602,915ac478,4f3c769b,dc2a30fd,fa8b08f9,8bb4a1b7,568c9d3e,754292b,1a35cede,1b377c99,fcee16ff,a16bbe5e) +,S(1152da70,2b7341ff,69e8d3e,6f5ce8d3,bdcd3a03,27df54bb,846ac8e9,18e747e4,7c139d20,1e2ea5db,984cc8d2,4b66c64,8adbd0c9,48c0b085,d59c73ce,b4d7a91c) +,S(3449cac4,abbd3ae5,e09dbc5,c89258a3,df93ead9,1f62fad3,a5add3f9,87a2f83b,197ecb64,5dc998fe,eb9b0df8,6267c7c3,f7af9647,96fea60d,88d4de89,33171e2a) +,S(ad5cc468,11c5a39d,ffa313f6,578acb00,cdda9ce,b3757479,9f2afd6,a8df7a19,4fdf6093,c8fa8a92,7702982e,7e638948,b982d84f,ae6658bc,fa839354,6d6e76f4) +,S(acad447c,b57e8f5,f528a113,347e5c5a,2097766a,b4664c70,3f496635,759a7799,88e1b4ff,3bf3e967,d2c6c948,4bb727a1,d13231cd,acc45463,d421431a,b6fc46ad) +,S(b74286a7,e2699aee,9802563a,4da514cc,d74fd001,48534822,9214395b,36158246,8df2b491,ea018b23,b1c7fb54,b7a05db,b79b0ebe,1117e2d9,ce73e70d,d097bf90) +,S(86bc560b,19d583b3,62c1634a,139bbd16,db30e823,75913cd6,fb688e4,38ceca4d,2126168,75c3adc6,c2aa16ee,2e028052,9e6612b,fe4b1aee,e4961feb,f530423c) +,S(dd79faa2,e97dd468,5f3ff8b8,d5e55598,73736de3,9493a3f4,4e679516,f51e495a,2cb89020,efaae785,5376d901,4d1bc374,21e0ee60,29ac70c4,65bdcdd1,e240e57d) +,S(caf6318f,825ca3d8,6d45c681,60d897d1,76875e26,bcd36d00,82b4e1ea,e6d8c142,d7abc304,55a5fab2,68c6d17c,3763e586,5b9e266b,bc6211b9,48b5ff3d,19f5df72) +,S(c49dbf15,70c3f0ce,1afd166f,884af550,1f26905d,2f726185,7c026405,efe9a2bd,54eaad70,8bdb7b2a,59f5d69b,5be6ed79,5fbc4137,945be17c,b4736649,6e8cd3c0) +,S(a87447c2,83c88db2,15630cb7,6029132f,47dadd57,5ea6f9bc,10d1b36d,8317a91a,8489d3c3,6334d65,fdf6089b,df19c3e8,7eecd697,516e1756,5fc8b977,be82c363) +,S(7467b357,7d21b028,dab4100b,ebfa734d,36345024,adc60b1,10b8f96b,c7860889,b2978a5d,dea9765f,7877d8ff,fba66c0d,f7c8e0f4,6854deab,21908da2,8572b1a2) +,S(6af133d9,bf2d6b57,ef69e0e7,5eef6d,eeb82d31,af490320,bd26f4eb,38ffd42d,7f4a4d1e,ce23c530,a4d64c23,cf0bf8,a46c59aa,74dce4ac,2854c6bc,d11b056f) +,S(faff2662,5a41c80f,c0889d4,83eaf50c,596aa571,6807b118,1e94ce5b,581b0a7d,32f3d057,4afc487b,43b129af,f83bc7dc,d495402b,90fdc30f,736e87a5,469e8aa7) +,S(8c6983d2,8047ab24,ddb292cf,1c8836af,7e75d7ad,6ce23149,e022cb64,2439ba2f,70a10314,447eaa73,924fdf58,fc607dc1,c69a69aa,29b84dcb,156fec4e,568a5bb9) +,S(bfdda2aa,b23a37b2,bc129bb4,280a2c45,926360c3,2719872c,ae1e81b3,1b3d3d02,e8319769,b7d21199,9e5de1ae,76021c9c,2bf75ed0,4c9a6c2a,c52da4f4,88cf78a5) +,S(80e24bf,3559d05e,c0cf63af,21dd7adf,237c23e7,ed930c7b,4124ad4,46871de8,c8f37f91,4e78e037,602ae9bf,ea3511fd,2c95ad3,6665117d,64f9fbbd,ecd10063) +,S(7f56d940,2d6fb0ed,dc6ce187,2ee8e55f,45db30f9,8defa84d,f7fb76ca,aef5e800,f43b9e6c,b60ce85f,44682fae,d8a48e5,3d9599d4,f19b4757,74f7d6fe,2fb2554f) +,S(437e7a08,900216be,72f14ef7,33127d49,9130309a,73369d2e,58fd4187,a0d428bd,3f0a4c4c,63dc779d,69dea37f,786a5157,43b3560c,16d4e56,4a1d7802,f40dec83) +,S(3bb8db7e,8cb3534e,d7f70f8d,eeb1cb81,3ab21dd0,552c311f,f98f38e3,63321626,9ffd98a4,b3c271e7,83ec8c72,98ba83b3,f4f0a5bb,61ce1edd,5c1095ee,eb16a569) +,S(21de8ce4,6aaebc6b,4ac51620,e2c78904,f9300b6,2930fa79,699e2782,5dc2310f,12a21855,50ceab27,aeb2e7cf,14710b7c,b3dc837a,67a1e4d2,6950e2b8,1942b9c1) +,S(6c24ddca,e4245972,5268369c,545bc910,ffddd8c3,49d83fec,eb27af78,cfc0c965,6263abc6,ed17a124,c8b2c5e5,c91b157a,13512939,b9d60e48,929fe6d8,4d032338) +,S(ddc0dfb0,49f7b6b1,cd1d03c6,f8ed2470,ae320f04,bc6f13f5,a88ba89,7bd1f91b,57c5f0df,8fd22e02,da44cd05,74fbcc1,c8b4a903,a909f906,aef9208a,89eeddd0) +,S(6fc5fdee,78c61421,a3ec2284,583a56d8,f18e66eb,58c54dde,e5209a1f,3e3761eb,baeac905,6101b825,8b08a807,72c977bf,60956b2e,d98d1b25,e71b2b7e,10e3d25e) +,S(1b6735d6,ac2f1db0,1c3781d0,cf42e2cc,3ccbf030,2e3837f1,3f6655eb,ba0dfddc,621e8c0e,cedfd28e,608c3da5,135d63fb,93dc6919,2a6154db,bf63e315,2f7db68e) +,S(1a875a0c,ecae6600,4bbdab3c,4fa5a57f,925079dd,671bd9aa,e8ac5c51,b21a5e83,2317a0c0,81c17bed,a15e1148,f44beb72,d4e65fa4,96408778,8216f85b,3924d9fa) +,S(51635c0c,ce51684d,9631c8ad,f6c9c4a9,3f66dc04,a372c891,294c42ae,2be5a84a,5c6cf3f1,bbc9c21b,124e78cf,ba05b2f9,ffb9c902,3895d584,48622259,635d3517) +,S(c548df8c,b685f457,71c564ed,a3e9a77e,a4734faf,7cef877c,b0bd70ff,d85afe0d,2675d6b8,24f99a19,8825f1ee,19510492,9eb633d0,367c01f7,c922bfb,c2cd6dc2) +,S(121592ee,aa39a310,3c02502d,72e360f,f500853a,7d2e449b,16c5e443,f42e700c,b5cfa2c6,689d973d,e0578a39,bc687720,acc0305d,6ad3b678,1d36941b,7f0cb435) +,S(c2a8b66d,cce99233,b3d83699,b20f0c60,21a83ee1,46a491e6,d7e69ebc,92a3e046,e0f3aff2,64228803,d8c1d729,88780d2,ae8c344d,f9571b86,70254b39,b4243705) +,S(b2b703c2,56ab219e,528886a4,4d6b7772,5cfc1b5b,17865ecc,c46e2d2,2420514d,b6aff027,b4408177,8c6cfaa0,123590a7,4615394c,aa83891d,15013d35,ba28a9cf) +,S(d249c36d,fbf43f5d,c6ddb196,d78d4cbe,898d64cb,3b239f89,1e8c4245,ab647afb,4e58c9e9,4199e0b7,8a0179c2,c82b6442,17eb3fe7,80c687e5,166f56ec,f812d092) +,S(ac3519a1,92c13eb,b37cd560,1a141d80,817226ec,7c86a053,42655c1,997b476,3522765a,afc2fe6b,2af9b489,27809189,74c2bc57,58ce502,13777ce1,a569083a) +,S(e9b69596,8983ee86,340b96ce,efd9a289,e86e6d49,3f057962,77b99067,af83c70f,983a83a,e1b08fee,392e51e1,c12a8e12,731d592a,517e240e,ea508f7d,b34059d5) +,S(e11e982f,10e65120,ca357106,f273c5b2,9900454f,81456781,36f52871,65444dd6,e961b155,81ee9ec5,1e6a3616,b7182da1,bd2e5db4,d08dad5b,46bee558,44c21850) +,S(f63f4434,bb0c17dd,3a17c75d,2d179e41,10a7810a,847bd4eb,37827997,94e57b14,480bff24,69c2e268,a51b2147,3d6cf7ca,23a3c61b,513267f7,c25b092,7dcc8549) +,S(cd8ea46,d65bb2da,7234508e,fb48a828,27678525,d102fa85,6d26475,eadc1a69,ba231ab9,513f90be,9cc8260a,fc63b05a,5aaa0280,3502532c,916d99c7,20b7b2d0) +,S(af9a2285,ec491b56,9cf53c8,6ec188e0,5bf18d1c,d7e898c3,c881a5de,481bbe13,a0cca7f3,714f8d00,92af7bc9,62abbe5,4d106dd0,a6089607,35a6d9b4,73d9ed58) +,S(5d90a039,55f41998,62e5cef1,af05ddd9,114632eb,abf27d6b,9b92c6c8,cfed8640,a0025e54,482aa49,11d8a556,2205c2ae,2a0f75c4,6f3faa55,7463b9b9,cce1281d) +,S(aa1f071c,55541753,3a47b490,c5603aed,2d2e5282,71acd0de,6ea7c5bc,ba66a348,195d8b00,fd90b1ad,15e46620,22d78bb2,47c1e9a7,8ab3b018,f341a005,6267a167) +,S(4225728f,ee2495d6,73f64d5a,cee2e372,2713a3b4,dbd2f098,d20415c9,3ab513e6,76c17939,461504e6,e1420d53,c5b07449,ce7f976a,e4de178e,69552755,75e92412) +,S(669c2815,b3357084,bf7bab89,63753b0b,ebbea33e,5b731ba7,5f969890,3a281eb6,23fcf486,e2839e2d,91fb08a9,11ed7361,81de7406,54c13306,575c576c,d0459c28) +,S(7b29749b,393869b0,d7f0977b,340b9e07,76a20ceb,ff6d8f8e,f4650348,11773665,a0d68cd,b6033ab6,a4c92113,c8f07110,aa5cf600,2335d2d5,2ca9b956,2874832b) +,S(6f096ed8,56f38c26,25200774,77ef7ade,19fb616e,30ed560a,ee5b4987,5f43a7db,54453b3d,1ffce3dc,b5e72ec9,3f15b57c,6725b271,d3fe8b7d,8f30ed00,35845b6d) +,S(1354de01,ef040d5c,681318c5,a6dfe7af,5c8eba0e,ab581674,acd5335c,e33c4bec,4002513f,ed215b53,c65686ad,8366cd7e,38711fd9,98d27750,bfce7e24,dda317b) +,S(5f8afb0b,3800c535,47cdf93d,61ae5c67,233c2525,17f99c38,8e97e7a9,1a90b561,7dad53b7,a64b7068,967fc0dc,e7178a43,a06e56f7,7aab1a57,7910d69c,23540671) +,S(901d50d9,b88abad7,84e75135,85a81d9f,a1d167f2,c9f377b8,e2598cc7,b249f3d8,7242b591,3c80db3e,748c63ae,47ee6229,2c1bc29b,e9f9088d,fb882259,405c3dd0) +,S(2f5e27e7,4c7e00df,c0bf6401,7d1a888d,1bb7a3e1,3ff66874,f7c306e3,806a48d3,87c3836c,7fb767f,4b5ac585,62c48a18,21dede2a,7d63fe40,da75d967,cf9191d0) +,S(8b2277a1,70464589,1d8b54cc,43bd5fc3,54fa6f1b,e7a062e6,6349ac2c,40eef8ba,ac3a007d,6b3278de,1c043476,13b254b7,69c9e14a,c2f50f9d,5f025046,2e06081f) +,S(4a6273a4,e9f28e9a,82c3532b,e7d3e564,66e87273,ad1fcfad,7ecace6c,54890de4,6d8b0fb2,1cb99844,610a325c,9592cc1d,e7c8b32,d70e19b7,ab7df472,8fd1aa51) +,S(f07330e,2ab0150e,435fe3a6,8c703091,4e7fb52c,307d58d5,d5120bfb,891f84d5,25b6ebc5,4c1d9206,33891a8e,39aadebd,988bd98b,a29b04bf,6ce4c283,a4438b08) +,S(3a30b22d,6f1fd617,9fff2c21,d6635828,8c21fc8a,94a274b8,993ecb91,eaab54eb,94035c56,6ea179ac,d58eb0f9,d12cb41d,67b94fbe,65805110,61cd9806,890946b) +,S(8c4f39cb,87d7f65e,591fa10,fd46d08f,fc5de3e1,67d8c9e7,718bff95,b112a5a,726c4bb,c64373f1,9399db5,18b5f823,3faef361,3e363b84,ad76052e,bdc8f2e6) +,S(38118e59,63a1929e,74f6d98b,c80e44e4,d9b32254,6a0f1eb0,690d08f4,f3bd4bfb,23167e00,c29513e8,e82d1140,bef5bf02,b806a652,fee592fb,1dad0811,604a4b50) +,S(75d4246b,db065274,550e9784,f3c9437f,3aec0fde,3af54a0d,61430cdf,2626bf5c,8392f570,3896cc62,d66f8485,9f7f269,4ff40a81,9505447b,7d79bb98,77f8f621) +,S(ab3bb0ae,c1f390fc,8d1bd3fb,4ecdad66,3db868c7,c4fbe0ba,6cf4f059,7068ed87,91382a2,2dcfe0c1,b51148ce,bad2140,24cf099c,e3e5e3ee,867db7ee,d070c7e4) +,S(d1453e12,383386e1,1976cae0,8a448b63,1a977dd8,47c19d2f,d7a212ad,5090011c,7044d595,fa8f68c2,4a972658,590d7ab6,dfc06ace,b9d8c320,205b858e,ba0402c5) +,S(894afc53,b0d1bb6a,c948d117,7e83c42,b4ff4084,e593fd75,d0660680,2ec0a4eb,5c5eb493,73e74fc7,39ca4fba,1940ebe4,6912d896,7cfc036c,7402e8ff,8d071d7c) +,S(f1dbde60,43133dc6,8699e89a,3dcaddc1,fbcb5ea5,e815eb5,8e7a6b87,dea2e6e9,96a7b1a5,b36e5492,68168c91,775d6107,a3f87f9,fb5c8b3b,acb75dad,5dc544fa) +,S(ad9126ba,6d35d780,dd2841cb,2ba817d3,f0267446,ee99abd0,ee2b4910,a4450b8,f77eaa1e,66c0f3f6,88268d92,9c9ee53d,6dbbc20b,b74e864f,d7831cc9,3d47280b) +,S(70d5638f,d3fc43c7,6f321157,f9715994,3b797d8b,1d366f5a,a5a7f1e4,ff1ff7a6,ba6f2d41,7af1c5af,dac8c83d,dcc289e9,4d6f29b4,2631ab7b,19414bdf,4a9ece36) +,S(e43bb23e,1f82bcd2,708730b9,3d3ed915,e3b4ad84,61904f68,bd91a065,80a4ebad,3b528db,117cfb49,99941b0b,63f51ef3,926a6230,dadbfcdc,28fd1d6,2bd44147) +,S(9daf3516,a015bd59,b648fd9d,9143e76,46b2e3fa,df5e446a,c57f2e22,9c9dad2b,5ec57ad4,808a9f2,ed297f7d,a7794e2e,3f1bb14c,bef58047,e0bddfb1,8ff11149) +,S(13970b21,3115c499,5eac245b,33633c53,1f2be101,a541f129,7403a727,67df16f8,3444e05a,7e49ecfd,633c96dc,99a0fc81,cc3c359c,440ffcd4,5df61c5d,1c027e97) +,S(12aef793,66978a2d,3fab4377,7debd5c7,4315b002,829b49df,c80fbb4e,1eaa94c1,e3f5c1d6,ea42b741,8bb3446d,c23679f8,e7a96d02,a8f33d1d,3404126f,71f9e37b) +,S(62a2ef7b,887de5a6,19c753f5,e0bc45c1,7c47b8b1,ffbb0ce4,8b93caf1,d1ab4b02,7d00482c,20c25e01,ad6ae35e,89c263a3,5d0fc816,952a96b0,9f2c2fa4,b8fc9bef) +,S(e6b03f17,92df5b1e,ec324ea0,898c031b,d745221e,791d2406,2aa917fc,de6f8a87,b4ee4b18,41153d22,1ec0ffe0,ec05b1c3,408d71c,5d2ca29e,a01ef9c2,e669b205) +,S(dbc02e03,e03e2f14,53ff6410,afded1f4,f0d51461,5ee00f75,d041ee33,c4f35783,6a3a332d,99ffedd3,d442b44b,aaa9d12,9d93e372,36dad034,9c47bd83,7c7674c4) +,S(f11be23d,6884890f,78ccbcaa,c1759ceb,5e7f98dc,19073aba,b85d85be,5fd23ef0,9afda170,dc1270d2,e43989a,4ffac7d5,c848ee6a,51e03b58,c308a4fa,39e2cfe9) +,S(16ec4f95,1db5c83a,c2c26209,f2577650,e9c48c44,224b221c,c09b0b19,1c1c5552,e3959034,d259e9f5,163a44da,f87ffd63,7a35b220,eea5ec6c,301cba9,eb09dc54) +,S(3cf701ab,8991e981,e9cbfe30,7b3aced5,c2147c47,f76bc2a0,733ee544,3fef3f99,1e6a3069,d4d0bb8c,def98d49,cd303b51,c45617ed,833be051,ca2836bc,13b8e1ac) +,S(96d093fd,1a8efbe,4f93c544,d0d7e397,cc83e114,4574f804,570fa3ec,58d5669c,2a29438,a05fe50d,b980db60,b343b06d,1796ddff,7e7fe39a,356cb608,69c05ccb) +,S(a6457eee,21025732,5094d3eb,6f6ea05,21e83184,adeabfa7,b6cd1206,9a9dc9ee,83e436a8,b234778d,9c7be0db,88639177,1d7a48df,19c29c47,682fa2cc,30b5e7f2) +,S(1b366505,1c858ac3,5890e7dd,b4aa7984,dbacbbe1,f4d2b62d,5337b530,da9bb0a5,39d3c2d,42c5d292,40b474e7,2e94a64b,4612f5a,68f5b6bc,586db5fc,a41025d6) +,S(e09325f4,68328cc4,d69a71d4,8ffe0380,bc118cb3,b8f390d3,4c1e56fd,27f4589a,16cbf183,78946fb8,3ff9763,41c6cc3c,9b2f451d,7661bc3f,3811f7e6,ea89a01d) +,S(6a8ea7a9,ddfa0f9a,8473c47e,f5667e44,3e64e03c,5c33a9a1,f0f1257b,40e1ce62,92806471,56238c84,9c0aadaa,2e9efdcd,e5a56a2a,78803f7b,66210333,88f525db) +,S(480b30ca,dc57c623,9ede2763,f113b46e,599076ae,ec687c49,33343178,c620f2ea,b5aa1b8a,ffe1e5ed,de587df3,341dd34b,57180cd4,752a1bfd,d06e4c2c,273b4433) +,S(134be6f0,b03ea43e,98e2364,46a45253,ea5822df,46227aec,b24b09d5,b25a34b2,d4841d54,b7fc1736,b293d314,bf6352f2,c7b08ece,4de652d4,2c1b985,d1fd78a2) +,S(7c84e23f,c54de6a1,a4ff6c9a,c7c88ac6,732d019f,a53b1a9a,a6eb2ab8,a3101f31,4ca88bac,a8d52f44,3703fa27,4fddde3d,ae5924bd,26b062fc,6f7fd0d,43ddf5ad) +,S(7c6a349,911f02ef,2aebdc3b,ce77f639,94c4dd2a,a842b567,141c023f,4f2d92d5,9b4f2f9,6215aad9,c7e0edf6,efcd8aa8,74dbbcd5,4a0c4cd0,fb7e01e8,ba6884af) +,S(9e1dffc6,a919c9b8,4e3d818a,5ec60f7d,5a2baba7,7d2dd65e,137d2ba2,8a1aed3c,cf26f543,bb7ef705,e2d3c429,f0ea27,84e3daae,1a71c556,38d281fd,aa3b1738) +,S(e24f6abe,c7519588,33ecc765,7446ae36,937e310b,d5754c5c,343eecf3,6e140079,c38a0399,774ff24d,90f8e599,183bf011,aa3c911b,9a66bbe6,920522a6,7510e62d) +,S(517505bd,1fe28c21,2fa85f18,99823b01,bcc3bd1,748169ea,54f35ab7,870f0e1,da94c34a,5de41881,1184fe92,8b3f08fc,362aadf7,5e7abf87,5d5f4798,fa712f3f) +,S(a02217de,4ec87155,b877b7c9,dd7425b9,79627f0d,ebe127ce,27d4f3ef,fb988a8b,cdbd866d,7b69e8eb,9321d07b,2a5c9d8f,6eec8be2,f19a6d24,4c987a1a,12752bd5) +,S(2e595023,c8ba084c,1cbb2d05,96ec35b2,7c366bf,cde27666,35d7e820,8fcb0ae9,ac08f27e,b8fd5ac4,deb1f46b,23ac1c5c,aa02b918,9761e6ba,d7c1ebb0,f412d8cf) +,S(ce384358,fba557d3,b76df62e,d2264cf1,e0bc7b43,bab30be9,fd6f65e1,a82b6c2f,a3cbf24a,e067ad85,ae0fc86a,6e8490b6,1e44980b,52f29a75,4a3f7e4b,a79ad119) +,S(9715da8,79cb1c5c,4291e00,fd2822c1,7f067d63,664170fe,463e86c2,d25e46,c5179ad3,a4846fb8,d6f290b9,2f957e14,cee99f6e,12fc8066,ec4dfaaf,a82edb99) +,S(19f61bb0,4cedc19e,5054eeff,8d0bc384,6cf62a35,1af3ab95,e03e45d0,786e1aef,aaacadc8,db84d7c3,f869931b,bd33d295,45fb37cb,7e474fa1,7a69a683,117c05b8) +,S(2a69afa7,581777ad,38882f6c,659ff4da,33fcdc17,a5355583,d1f8ae37,7dcbd718,878eb429,d42dfbd6,435df1fa,c5e0ed4d,e7b2fe4b,6f7dd6f2,6a3150a2,213fa619) +,S(c3da1980,cdf257db,f2a5eda9,94267691,a5e1e679,79d4908c,c06f7f50,71002381,2cdf4de1,90ef2995,a984d882,598c24cc,35cfc47e,5cbd2d53,53d880cf,a944bfb6) +,S(19294eba,9d19c03b,497551cb,7cc8d8ad,3e3b2130,942ca8dd,c8bc5579,1c424d2d,5523ac45,e676daaf,2d8da00f,5e9240e3,d904a536,63e6b704,735889c8,84b680ba) +,S(d8b3b307,41ee7ff8,2306615f,2d2ef361,6e3f7cd7,fed9d56e,69300fb8,5eab6bd3,7d57c12d,e65bf3c4,6dde736c,373ea374,d090b240,6e1d97fc,8049e21e,aa10a74c) +,S(e2fa1bd1,164528f0,87c72a18,e9843e33,43b376d9,b5616b74,5e0c3d00,eca95fd1,72dcfc41,15b35406,8bd3057d,506d592,771eb3fd,60a2c2c3,dfc2645f,86b249e5) +,S(ac587775,bee32b7e,90031ad8,9786df14,8e4d9662,55a06399,e43c0441,883fd6b4,b6d3eaa,6f6a50ef,ef84c578,b241591e,4a718eef,fb40ac34,99a57079,b74c45b5) +,S(74976cb0,77d481f5,e6bf700,6db57a13,f362fabb,e6aaf25b,6e956452,9d093bbc,bb40be31,7cfde25c,75ea859,2b622e4,9d42a0a7,30602241,219bcc84,a5f4bfe1) +,S(e71e6967,f32647fc,2c13a94d,4bc1410a,cf9728d,1f543522,681d750b,2620a668,33c4fc82,720210d9,afb9f1fd,51671f3f,fc1df5f4,e61a5ff8,c59f06c7,91f996de) +,S(bc36cf57,161e9b17,828e4557,74204c59,805b35e3,abdf4ba4,daa9a5c3,fafad6d2,df34c492,3018e879,bf459cb4,528d2983,340444f5,a85efc29,71e260df,29cd8a20) +,S(925251b3,9c8761c6,317c2066,717a2e8d,89e43acf,89527ddd,6078fa49,2d040f95,aa7a084,8b2633ac,ce551f1c,63312895,f4ece420,5e224665,2c486beb,b8131f10) +,S(4ec27df3,d9e755ce,b93e1ca0,e0e43f44,595b529f,6460e3f4,e6cc3765,3a2bbb21,eee3fa06,257b4be9,387ac7b6,6cc1ff6a,aae43583,37d6ed71,27ff753f,1fb179ac) +,S(6f733e9c,b86c3a17,5bce6c08,347577eb,69cceb17,3c19abef,c94b6646,92859812,2a895d6f,c4a7a4f5,610e8b8,9e7361bb,db728625,ee31e6de,927c74f5,b10ad0fe) +,S(c631f4ec,f205b1b4,6bc0fce5,3680e6a7,27f9e64d,5ee3fe24,c37291a0,d3a69b53,f0de9e0,e4bea2a9,cc01a5d,2f9aad2,f5af7ab2,7c2ff98b,983dd2b6,38dced4c) +,S(9326d449,4fcb3049,8badc221,6d3a90c0,131d31ea,cbca74f7,2cf7da2c,bb6aa2b8,c3f268ba,4c9a9ab5,3f9edb88,74f2786c,4e4c065e,ab58487e,cd8101b,7132511a) +,S(538c52d4,8fa6c492,cf546349,675d6a2c,ba10b442,8827dfeb,69f0303b,1b7ac774,c1b1db4f,d6d50f3e,c7533ee8,cea0d47,883b57e6,dd4137c8,2132f846,3b81ebf9) +,S(5e58a25d,8bdb4576,d178fdb7,23158d26,508f8486,ad553727,907901d5,6e99a680,97c1f814,8880cd85,51c9f1e4,9ae58eb3,d1a01285,bfa8248,44bc794b,7d83ec62) +,S(1e9830ee,b75d6c6d,c70989d4,ccb85e62,34a1cf94,ef81b65a,49b25753,cb6c13c4,d0780a7f,9607e530,d80dc068,68b1cf8b,82d3047a,2977d204,65187ed3,13c94c6c) +,S(c5b441c2,f7e97a03,dd690cbc,ac605772,1524dce7,fb5068f3,f73d78ce,50fe0183,9bdd2242,e35008dd,4f907600,64eb3b29,427ee9b2,bbeeb548,62878688,a916e410) +,S(a5f56816,e9448d0a,aaa7593e,e3145678,3be74521,b129f13,f11a276e,d419492,8406662,65c275da,76ef289e,d36f8af6,6ead9be1,48cec081,7c21987e,9e8af9fc) +,S(c5e85955,44004f79,2260d553,25628858,ce50c95b,9362d868,90fdfd20,8d1184c4,6a5f02f1,c0f381f2,7fd21eb,928f03a,c8524dc5,9bfc1bca,d025a290,7cf939d1) +,S(d5dd810,9e691f5,8694c87b,59907ed5,ec18d37b,8554799c,1481ac78,825d2ac9,ffbaef54,fd35a5ab,a49f9946,a11e5ad9,2f29590c,20e28180,9f4be3e4,b156dbe0) +,S(ee5d42a2,c705bae5,a11d9d09,af3217d,2ec16588,64a60a56,d8e4a1cd,4313c61a,f08f0e08,89c015f5,3a2a74c3,3dd625da,b329181d,1d0f4fa0,14ec01e9,5d113d88) +,S(90409eee,78af819e,249f62ea,3b4d70a9,26557f8,731e50ed,532c0b30,4616d615,17aa7a7f,8af635c9,c4ea353c,56c89da9,70df599a,faec8916,ec9a6d82,cdf957f2) +,S(5f19aa1b,a6d6e3d6,9445e8cd,71c95e3f,a3ddad6c,ff0dcb4b,9e09aee5,65ba9e46,f82b3170,c2953397,a6cd29fc,9c87bcd9,76cbc7a3,5f953948,5a57a940,63c2e570) +,S(5081942d,1039bfcd,96a759c9,27583c45,8dd4c013,59fea307,40c65fad,d020606b,f6f204b0,97cecd15,b2619aef,c25328fb,226598b,fc9384bd,de99a4d6,567e9b8e) +,S(43eea7b1,acbb1450,c9a49b0,262639f,702612b1,b184ac15,675d6496,a5df1a54,a31636f9,ceecfbd6,60f78f,f6cee471,d4366d7f,ff863db4,9a5a652c,71b94797) +,S(f2860e98,a30a6c14,ac43dc9c,61bbae1f,b8ecb294,36c8f0a8,7dd43c01,486706a1,bc83bfae,9a4effeb,4beb025e,962108e5,4a5d7979,cb9ae2a0,7cc44295,b95a2e9c) +,S(6b4a8c28,7d5c7af,63ad8d34,9751116b,60a613f5,7cac229d,7ef0d9c8,166d69c9,48333ada,f4810cf,94c78d43,88f8842d,fdc9fd7c,d391e456,a592d8b2,200bd6c6) +,S(d1efc808,393d4498,50837323,9b791d0d,a814e888,2958da8a,87136d93,bf1b7d74,13247e74,3c323631,9e557476,4ad4dcf2,b91dbc97,2d38244a,fabe4c0c,d08a9924) +,S(d3fd7a6a,fdc7332d,f2e6683b,a05ab787,e3c48262,ce837f9e,d8ebae1c,1f6f7ab2,3d25bfd3,3ddd4f74,8ff395a6,b4f36d19,cdb28ce6,b56aaa55,e783e9f6,3d74e70b) +,S(816f76c4,c5ea8733,5f220c54,28b31cc6,89fd8267,e498a675,4d6a2620,a60d9aac,d3b61647,f6624bb3,9fbb672f,51b66613,8a441a3b,660bb223,1f255488,806e79c4) +,S(1e344f97,98f11372,aef5c6c7,6b32a568,16198e18,8e611026,1dc78338,2522cc93,474e0218,9bb4f698,15e304d4,8166e3cd,717a1bc,a9cf4e4b,1f5c5d23,a36e392c) +,S(4d3bcef1,d6cff8a0,e0582d11,22eb7f67,28aae077,e9ef7960,ec519ab,3c6d6087,29f1b01f,a70e6812,3dade19e,d5d2689,6c491389,27a2da1d,3c628965,bccf38e2) +,S(6d5d596e,467ce203,297cdfe6,ce4807a6,1686a8c9,f0606283,5e0fa194,894d027b,ef58ab41,1d6a002c,12f469e2,e9f8ded4,4291b270,4b7490c5,4c70c94a,cb7b24ce) +,S(86f6ebc9,c25f6866,f14af018,88486b22,6c89b1fb,64bd9ac6,e523e503,e2cc6819,b0725647,4d9f3b4,8d4055d,e15b72ca,ce599bfc,247ce9a8,4b0d5e72,16b30425) +,S(520115e9,a47c3df7,23f81df,8422c03a,ea0084df,b122759a,8d6a5b75,540cb339,93b12878,44f22aec,9d5ed727,3d204d85,d3bddaad,73e3545e,5725b171,2b8417bb) +,S(19c9ff30,e5e50038,7e9be1f8,efddca98,7a72de0,d5cad8ce,7569d4e7,2b381009,b43b0c98,402748ee,16b362c8,b68ae79f,8493a7ef,293b149e,3faf7247,83ee3661) +,S(bdf0f8e0,928affd0,87566820,3c95b3b4,e6baf9f,f1da25c9,73814c27,551ee4cf,5f701bb6,8f8a6795,cb4ad675,e00b5ca5,761a0eff,32a1d3f0,9b29d5b6,3885163b) +,S(5c609591,37a48dfb,f778dc26,80de17ce,390ec33c,ea5cace2,a969ee9d,1e413e1a,670078d8,59a2c138,93946d1,e052552d,fd92c380,5fdf2ed7,8aad7795,2ddf2f51) +,S(98f22ef1,b9a62928,c5ddbdf,70e71c08,eb910ff1,fa6a6a1,56de82bf,bed8fae,f87be19a,9433d279,8088c882,5d122e31,bec9102f,c580fa2,24d40f32,2a2db1e8) +,S(d1842bec,2bfc5fc0,d5208d7b,40e04b76,88f26add,9b5a6845,751147e4,b4524615,f0405ace,6dc9bc88,48d18586,b713ca3d,67b76ad9,4f2f794c,55fbe9d2,f72ffa56) +,S(732cdad8,e0aaee77,473c0140,9702cb39,555ee048,357fa448,33ce8e3f,5f50bea5,24666502,448268a5,bc2c693a,85a1fea9,dc5f010b,a9b0cce7,6bf36124,bca1cb0c) +,S(6c86ebd9,5200b1ff,dbb6ce6d,e9fff6b7,1b6100e3,1144239d,77e7201c,db2e8af5,39c687d5,abff0ec7,c7ccc4b2,a4a16ba9,7324430e,a1ef209d,5ea126d2,cef24539) +,S(655d63c1,47441ab0,e65f9893,dd38f3ca,22d2d8a,a7b2c87d,a2e2293,b24ffe0f,d19ede94,b25ca138,94ab8fe9,842cae29,92cb58da,592c19eb,57c4184a,45121281) +,S(8efc14d2,d5845886,ec264438,449ff49d,ddab7567,69999bd3,6191cb39,efa41b72,9f1052fc,416db1a1,d9797e66,a816b403,475ac091,ded4dfdc,e262d527,3c535293) +,S(31a7f0b9,1686e695,d1fae6e3,8fcdbeb4,246fde30,f2ca80d5,2d9fde31,c728eef2,9661bf7d,46248da3,8ae1ff52,a8aba654,351a1f58,4f3bbfed,1875d439,3612190d) +,S(9dd959a9,8c862275,93dcc957,e369b2fe,5cc1d411,d4162ad7,d8e22b64,633adb85,78ccfeef,d95ede71,32a7011d,bd39b9dd,f77e38bc,47f7432c,f90d6583,5a6e665e) +,S(51beca99,fe3cedfd,1ba44caf,58c0fe4,8b926e72,50e5ca7f,8a187cb4,909b1892,12f38fea,aa9de148,7c14eff6,96cccf6b,c7cb23a8,6f2b7e0f,10fa971f,3545a0b2) +,S(1a84e21,3ef9b9a5,9f9a4fe9,d21dc1cd,1ec7a102,fd91557c,1129921b,781e6b51,aefbd931,17a42a75,13db0e04,782aa0b6,9cd79d36,b074f026,bfb7682,983cb78c) +,S(9eb14847,2d02a287,cd197450,78d81963,3943183d,c76c2090,9f68b94,12eeeaf0,6fe4b5a2,d18ac52f,9a129a91,1db00993,ca505380,2054b5c5,48f35380,c6d467d) +,S(9ecb3cc8,da5475cf,1a66ef54,3286f07,f5be1196,2c1fd420,b394bae6,c4256441,b4160952,e3701895,6f25c5d2,98ce90c7,91797571,267902a0,bba53d2c,2fe2cde0) +,S(541e567c,b2160fe2,75e9d479,1beb8ad0,4c07d6b5,12b43d49,888963f6,d6696ce,2444e184,66cc09d6,aec704c6,ea8ef670,4ed1488c,dd8107c0,c625b783,6534d6f4) +,S(8c061b6b,b6b55fc3,7c6d805c,808fb3e1,6fab1cb3,a05853bc,4933eb39,ca7b3580,20430304,c3780c29,a977f8d3,54424539,67924c2e,9a1353da,40716ef5,a0a0d37d) +,S(b9b674ab,361aacec,bbb69f7f,7c2b1361,44e55da6,1566ed97,cd58152e,4d391033,7841975a,4cf0b5b7,3bad8433,10866275,8a8eb93c,3b5db58a,15346083,f3d10386) +,S(3453c3d2,27e1dfc5,3e22487d,cce25ab6,18a3d25a,48f6fd1f,8e9158ec,dd6bfa1c,aeef1768,b754d998,fcbc75db,7a750396,930d169d,bf933c1c,15dfe041,17ff63a6) +,S(f36f7b9f,28463b22,d2c43e29,6b96846c,1b3401ec,53490c5c,35ec197d,da2c440c,9876476d,e2cfb7eb,b1cdef50,a39d20c,4ba5000f,9edef22e,ab7b96c6,f0cb5585) +,S(77c64190,33ef6119,ac3edefe,ed519632,ef5dccf3,f46066bf,6d5204e0,66788b5d,980cc59e,a103486a,9c8cfccd,213cf704,3e6aacb6,abbf3293,c833de88,e5b2716a) +,S(818911ee,6051c4d5,19fb7785,d52c6f27,a82e2d79,a4a55623,909f3d6d,b549e851,5d031307,a2d66fce,4b607967,f662bc0,af855112,11cc209d,8457ff41,968fa325) +,S(bf5900a7,7c211a75,231ebe58,17f91748,c957f5ae,b98377b1,9554fe90,d11ff226,d910b2e3,1760f0de,838cc159,7da6915d,e6c3fb29,80bc0e65,e87a36f7,749cf1f1) +,S(654b4257,11f03dbe,75b7d60d,b578d75,20e7cb6f,4923f774,8799b4a1,df06fa16,12c9e75e,26d3ab4d,645a7a64,d97eb6c9,356a3951,fb715bbe,9e42f500,a0c3f44c) +,S(33a425f4,f178af6d,48b78873,cf70da66,aabbaae0,397e6673,7a9c6074,15ab3d2f,1e5aaddf,d76b1b91,14016f02,1812d7ea,18decd14,ca3e3925,89894151,92178cb0) +,S(cb088930,f0ba3995,d7542d48,92ce47e5,5d8fdd5d,7adf60d9,3651240b,12fe7636,aad156ed,f0b25c30,e4bc3784,a1b7857a,4cabbe5d,2ceffb72,ca2cb7d2,45ddb024) +,S(ffa9e81,afb11dee,83a54b47,fe9b41e4,de4191af,7279d19e,90e1c528,7c205c0a,405233e,b20a4848,80210b40,18c098ff,a0a17203,c5a13b12,5ec0fe92,1d1c3567) +,S(92ce3be2,8fd6c9db,be1cd4d1,f58005b2,af0c136,89181c52,a67c2503,2649a6af,cdb840c7,7e0fc2c3,d4b959c6,6fc47142,622c8a16,b30168a6,c62ef368,8bd23932) +,S(46079065,b64bd3d3,3e3efc91,374e1443,69adc4a,bcd2bcfd,91ebed0d,88f78cff,b09653a1,1c0710bd,b737611d,e5d80e67,a516dcc6,2ee3f63f,e2d6a7,f3794ae4) +,S(5cf961ff,de982138,958471b4,b316cae3,6246ae74,e1309400,a3acd118,e4736c93,ab8e425c,ab39325b,b94925d7,795d8799,18efc449,e44c9f03,cf7bf487,fc32b185) +,S(d8fa1009,27c1aad9,6ba97005,f8a24013,bc29082b,ada0e0ae,f6f72ec9,8abc4240,38d88e5e,183b2c09,d53adeb5,8d0525f0,83a512c4,1dd64cfb,a7024602,f39e484c) +,S(cdabe8c6,7d0d4627,54cdd3d5,3e70bcba,e2ec925c,a46a4536,ce3be9ae,e0b37d8a,c2032dac,527cd15a,a1d812ce,1c658cc2,a0a379a5,2a30613c,2737812a,6e683830) +,S(394fbdd6,7069d83,8fdf87f7,b1c179d9,1a491ca3,680f0103,46de3299,37e92374,5ceac741,828ac862,7fcd587c,69844243,d17ba038,901cdb42,36e96685,d589a693) +,S(84eb6d44,103f56df,96617c7,11c79dc7,a6161189,157a0782,74fec78,fc5f6c37,57a16660,4d1fa3d9,cb358e7a,47984a00,6926df57,4e06a313,7b3c7524,2e882320) +,S(295dca03,657995e5,d432a606,da12bec9,fec8f4f0,582d75dc,5657c973,7cf1051d,c4df0ad7,b1e3a29d,cca4120f,478a2d63,f18fc67f,bd201be4,e2fe05fa,66ba2d6c) +,S(b42d81ca,1bdfb038,d7888194,deda7307,eb846bf1,738d8b7d,89663bf2,8097fa7e,2d913cc9,93ed5118,1082c85a,42495133,ace8bc6c,65530309,c6e15794,aceff5cb) +,S(48484186,4f6d8f3e,94977a3,45bc0db3,1330910d,4c555032,da8da876,912df644,7a78a8c7,68c9d9ef,b5242fcd,b7a5946c,5fbedaa3,2914339f,8b0c0ac0,eb8a3146) +,S(7376d600,9a7a76b9,dfb7e225,c0da3186,b683fb13,daed9fdd,25ac6606,7e7d2316,fc733036,dabd7c4a,719b699c,da115547,8a52d69f,387b8a94,28744144,c0502901) +,S(9be9c65f,5fd6cbcf,522eb9ca,91427f68,152caa2,a152051e,3919307c,9f67ab8f,14da6642,fa3b7c37,41c9f953,d1e01c09,267b7885,8414fe5f,24f47c4,b44c413e) +,S(7d0ae5e4,18d6c6df,45f6d26a,7e962335,4ea1a338,8f183eac,85b1eac9,1962e2f5,551eedf8,264763b0,913307a5,14fd9e09,479f43a8,87983e69,509a3688,d09308be) +,S(d91d965,d3b85441,acec7257,d444cba0,6243b34,14e9665,9cc62cbd,89aea7db,54e26ec,9c82bf54,f06cce16,2cfb924,2a354c83,fe530937,9bbe733,6010f44f) +,S(44c8fe95,aa48f8bb,6c0a32da,a6263918,fc2df7b8,6a68f277,6bf405cd,1bf0566,87fc1fa8,3fea76e5,52f53612,45e54053,9d70377,cd865915,b6b78acb,f73a6e03) +,S(c7f8e825,5f2ddcfd,f21c5c20,ea84a527,2c5f6c59,99843c96,3bce9e0a,aa7ef398,5c1cf086,9c1f790,b1e59ddd,ec9729dc,2b73c6a1,be333dd7,e423a0be,bee50243) +,S(3a8ebd85,a2bd4b1e,6c0373d0,63e9cc4e,a91e6e1a,f4bd7af7,501e0160,8fb7f4d9,4d9351b7,3c3f6f36,1b86ae94,ccecd211,ee3b13a9,522d799f,e78c87df,4473f23c) +,S(bb01a4cf,ad90f3e0,5355f0b6,d1b28420,786c09dd,9db0ed5b,38a56506,4da77e9e,1742b511,43bc276f,273afb9,8473ee3d,3d962050,7462cdf4,a8c641ef,cc2eccde) +,S(eee45594,1a04bdec,a02e7e85,1d86987e,798c27df,adcfd5d8,2979960a,3983f4b9,3cc75025,9b5d215,37570928,1abca8a9,29f5609d,56c8dca4,3d1b23d3,cba3fedc) +,S(d2290ec5,120d591d,2e4e2796,3d10c0eb,e73d8b9b,600587ca,84173ce6,796123ba,c4760011,4c68baf7,b4053666,d8bd494b,b4ef1786,c1d7a522,8a656f10,1c837304) +,S(21e359ca,9b7326bc,b3380282,b9017df0,3cdfb7f0,af95f326,701bd8bc,25dc047a,68b866e8,555206e9,7cc43461,34c3a61d,ce2a50ab,2b514935,a05f8e04,ad95c70) +,S(b4acba20,94b35033,5095b208,9126367f,3203efc3,35caa43a,51857181,f4987e42,fa0f72af,77db4913,af6d906e,54eb33f0,a3e9d20e,d366c878,3b7c513c,c5165c16) +,S(5ac6b2da,18754c30,9ae46ac8,3592d673,ac5d61e0,35ef1b4,512aa9b6,7551862a,e93b1d74,105974cd,b6bd3043,c0dedb8c,b4eaa81,c949999e,68d52fa,4a3941a8) +,S(4a53cad7,2a894cab,9b761157,38ae78b0,c36c293,c60ba8d4,b87300aa,792c51d,4b0dcfda,b890ffdd,cf8a6a71,15f2a351,d883ad8,fe3d15a9,118f3e04,43f840c8) +,S(5edec48f,7d8c9b4c,af3371c2,6e054392,755fa073,1e660971,4e089b04,2a07bc36,b18b8d1e,407f934f,e526fa5d,38b3a408,76bab92a,2bc192b5,b7c206ed,6ad040e0) +,S(986b120,618abe6a,d965f9d9,6f50fd7b,29f1b897,8276ff8c,562519ab,8aa92890,2c981569,23ff1809,1cb47459,bafc0d51,699740b,ca59dd7a,14e07b9,432f681) +,S(8c61517b,397d36a6,b30f0894,98d525ff,bbda959a,126e9be6,f67b9831,e5e7372d,f7608f24,130ce8cf,56a7b762,c1563519,a4be88d1,79e90f1d,b432ac05,d472d771) +,S(d6abe67b,e30fa40,b642483e,a6ae7ecb,4217a07f,35546f97,469aae99,a286b8f6,b5e5675c,91aa08d2,a5a77349,5f1ad2bf,8b6b9dbf,4b35dc6c,262ff1c9,8eaa70ed) +,S(26be12b4,ae013009,45c8ec05,58edb030,e19a75ad,872104f6,8642bf5b,c30f7934,1086891b,3ce97d8a,a568fe54,28164f25,4fc15953,c97d40c8,f32c0ec6,6ed49fcd) +,S(3f0281e9,1dfdf1de,69d5112b,1b86ea89,d737d09f,1cbbb71d,2400d0e7,719987fb,27451e9a,2cb336a2,998d55ca,ac12e16c,fffbbd5a,3703897d,5f566ab4,5f4aba92) +,S(b84b8115,7b1782f1,e4b641c2,a001daac,ac7d53f5,b3f1fa5a,d0a5ddc2,732af3b0,a0c8f7f4,8fa49815,7a6c590d,4ea18dc2,c586b332,2a303061,c19edf44,ebba25ae) +,S(790ab328,fd86da4c,66f0989,296229fb,609de28e,cc8cc6d3,d315eb89,fdf31e38,cdcf83d3,44d103c6,736bb5c6,375bc2e4,3fcc46f5,777d6e5d,cc407700,15d29aa0) +,S(d5fee68a,f9b7f182,20ea6525,6a591f24,da79a642,4ea0fe31,88a0b658,9006fb51,87b8608b,1b3d0d71,c9ab2c9b,84654408,af6551c7,1e8ec6d4,a8f26cb3,20577532) +,S(410f9801,4622b22d,62eef39a,3c5350c9,e80ecef8,48c4295e,2ae279ca,9623e777,53dbc737,5766d9f8,ac0b8b7c,e4b852b0,3214fe70,24386915,84856c83,6376821) +,S(6cbfa6f,fc7a6009,75edf0b,c260bd2d,258bec55,382e650d,c464b16b,e5f34eeb,de72cf4e,33028bb9,18ed3a41,d885faf7,e1d5901a,ad7a325f,801f1a36,2ed730c5) +,S(2a75c02b,3325ec0b,ffa42250,e224a4de,e0c4c12b,69b71039,4bc3040d,80e5c504,ed666a2d,8ac26964,f0445d21,f1719ada,fbaea128,9edd69bc,94ae6123,a2e6b8bd) +,S(ea2bbd57,6c0b20a5,6790ad87,29f25475,24ef97e3,86663aba,2473994e,fab39134,d98d55fc,daedbd5c,3aab619e,1288634d,f526f873,19743f81,149ba85d,535172cc) +,S(893e9899,fe1b8a92,439c1594,634ff44d,1d0a60cd,8a0183a,b810bb8e,f80d0400,c680717b,aa2ff029,7baa807,d7290190,37c73d0f,a5a1878c,9fa2a6dd,d17cbb2) +,S(d75b0a2d,1e9a20c5,398fc3b7,cacc79ba,fd53a14e,ebe23196,e4bdf4a8,f8546422,37a8efdd,618bcff3,3dd0c0c9,f8bf3192,2e131764,305b610c,88a2b74e,44672981) +,S(96c84a8d,5dd2ec9b,44a5b2d7,af3b65e4,9c07786,969452c2,5e8e64f5,a264c14e,292ed1a0,dafdf3f4,83a2a419,6e1b6b28,4d7daf88,88c7268d,70e556fc,ff55341e) +,S(458895f0,77782a62,43abb775,7daec5af,264a71e0,6eccaf8a,3b23baaf,fbd7343f,809eb056,87bb618c,a0f4e1e7,c8d05e48,95f18393,2e949b22,b9ddab0c,55d32b93) +,S(59dba4a8,d7956515,7f639316,75fecc7b,58a0e91a,6c9c3d50,7dae6d40,2e67a9df,718094a2,83e47265,1ef52d4e,db25b0b9,9e069f,391ddfb0,d9987596,d2f4ee2f) +,S(a5f92445,b7cd75c3,9a4b3199,96baf00b,f855ebf,ab3e19bb,71d4346c,878b4bb,9bb1bdb5,baa4d56,5b9c5077,c86b96ec,953ce381,17cc8d53,7b0f3957,a582ddd1) +,S(f146eff,2a9ee1ec,a3f26d6a,17c89639,a1f3505d,2776e340,ae89449b,99c8b198,1674daf7,a66f1a89,7b5378e4,add6a196,fd27795d,88969a07,a210d33d,646a64af) +,S(e67f5967,d98c1d3c,3a4d0872,12d3b65f,6f8df216,5dc14633,92c23ecf,ffc17e1a,c3dbbcab,d1971eb7,a8b088c8,c71d65a8,328bf43,58f0e685,9025db87,e5391380) +,S(32e8d775,ed37cc2e,6f69c85b,71c95d65,d40f033c,b5eef362,86d4499b,fb6071f,2fbb1d8d,a6364791,95ecaf52,6f63eb86,e4604973,edebbf82,b796d88b,ade44334) +,S(b98c7cac,475ee4a3,c1815a17,e460f76e,e5334b27,e1ea319f,be8924b5,819a473b,d7f1bb1b,a653f20d,c7145420,d8c8c339,d789ee60,9b9ff0ce,73910b94,3deeb88f) +,S(d9830fd5,545dcca0,ee37a402,9f406cd7,50bbaf59,e60a80fe,da976bbe,ff9027d0,cffab795,e45a2833,75e7b861,728421d5,f9e22d03,44f835a4,c55207bc,6479b947) +,S(399fbb5e,4f4e27ab,3e737a32,d065fdd8,c003ecaa,84a2430b,4a7b4d40,eb6f9721,93f7b541,121d13bc,480f7868,ac9d8302,6706d2f1,a46955de,a3912735,c5f02e0) +,S(64e067fe,17127128,6ef0fbdb,b2adb4c3,395a1ddd,f2ea76e6,261e6cf0,112c6227,8ef6afa,4bac7536,a23f08ed,eb8656a3,47a13f25,2dfacd37,c215cc3f,473687ab) +,S(57eb5e46,40721263,97f0d12a,532aa1ff,abef7822,4ba9b10e,8fc95e1c,6075a071,8a700d2c,80df0b4d,7e2c9291,9a51e565,8dd6ba5e,59bf1503,7bf7a0a,935545a1) +,S(b83adb94,ba1874cc,c61ade9e,43093cae,5bd86ff5,e86615c1,abca14cb,6eb81877,93417bf2,1fe01c85,5c6f7782,a5cdb01,a5d13b29,d719f0fb,a2373ba2,8bada7f1) +,S(7a90bb49,71537bc9,3d1bed23,891e43c6,e350fa37,ef8e73a2,3fd46ea0,5ed879bf,ee0fa59,3a51af19,70a6d8b7,22d42bf7,ca253572,2324a59f,c041b3e7,305fa3d4) +,S(195e4afc,6c95d6d0,8273cb0d,fda2da3b,4696b569,650d4230,4d396fb,3e653831,44075199,9dce9d6c,f10ef736,7888dbb3,a713423c,f2881cd5,76a681ce,6fee2c8a) +,S(28ec566a,29bd09e2,f8b228b9,ff2ec49d,56660734,f2ea864e,856be0ff,fd6f60ee,5b4f5e34,298b5a56,a6826143,8ba59d25,4922078d,f36dfdfe,d4e8972c,647fe031) +,S(1e005b72,be1bb77c,80512581,58e940e3,544cc133,a76ddf49,b681422c,1815cd22,9c523adf,4ba5d753,93e432f,491f8e1a,435165b2,f40f79d7,889d82f,8951a25a) +,S(f54ae39a,d074c399,636f0dca,682b9405,4e87e87,3132d7f9,cf79ad85,fa82586d,db2e9b90,1c2dac2f,f4851f4e,b0ffae7a,4c0cdf34,ae9f964b,841c539d,84040667) +,S(bc8dafb8,d385cfca,3643fc75,c8a93f9,792d2b9a,715269b9,ec40d581,5936e6c6,dda791ce,186ff28c,db7636ad,4073996c,4a2e2875,80da17e8,90d03886,1c14aec9) +,S(60b6ea82,627f5414,16978e7d,3c9d911d,9d9de92f,3baa0975,a8de4e3a,8ed3ab2d,64693ab,fd095109,ef89cdb2,204f2f3,89dae035,f451fe28,58fcb4f1,dbff0999) +,S(9c8d1352,bf291803,22730718,5ee65aa8,b14211de,6d73dace,2937cc6a,1ee79134,3c6e0d66,48f3fb6b,23e6e4a9,5df3911d,797afb50,9c12e90d,7eac557c,7b1a9505) +,S(bb2a8344,2997babd,6cefa2a6,1c9d2fc7,a42db3d5,bfb19334,c7535bd5,630be896,20de4f27,69596e65,edcd695f,61a0d8,3c8925a0,c8707470,9e84bd41,615ac75f) +,S(ba8bca72,496a6046,7b250a38,cbb536e3,b9fb9ab1,43800655,8ef5d186,2b66d50a,81abbb33,e835f864,3d075858,7ce59671,7e08c1c6,75af4c5b,eb80429b,9dc46aec) +,S(529fde52,c4d1c978,405107ba,d862f7b1,995ffef5,cba4a59e,d71b366c,28e17b46,ed7c2521,d39ca130,60d5f509,d0a8b0b3,40eb78c0,d4e4fc4a,83318a65,226d0a05) +,S(6e0e10c9,4445acc3,593efdd5,4b8ea1f9,db4a45a1,4c2d0a27,edbe3fc0,7a90e91d,43537a25,d2091290,f753460d,8816ff10,41308e6d,fb04b7e7,d5a108d5,c9fd83a) +,S(b2f90714,6fe2e01c,5cbd73a0,c0a358c7,a05aa730,97a060ff,491f362c,75c20e90,d0e680d8,f7d27eff,12b332e8,a92b846b,4242a746,9b31740,6c6af499,5ab51948) +,S(bf631a7,933e3ab5,f7b8707e,55a9498e,31ec3f36,970bb9b3,f5efa0cd,1a3f28a0,1030146a,387d4fd9,c12544dd,a448133a,49b5a6e0,d4b96933,cd47e89c,608dd5b9) +,S(cd7ec470,e9d5e3fc,a4c344f2,9edcd4df,4b7033ef,5e7ee99,de0db6a8,43926034,3aae77b3,bb008cb6,e982d673,7f78e920,f3a587db,bc106c0a,25c65d45,df8a4f6e) +,S(b3ac95ff,8365813e,e71199eb,946b5888,7dd34b1b,a214482f,dd3b7fa,3b8ce6b6,e3d9bbdd,aaba7887,8e763360,abd370d5,9d941ba5,cf758d33,3b480f00,ec5e7672) +,S(7fdc21a8,6962fced,e6f9fbdd,77e60a00,4dfb858b,5b149362,dae4b4f4,a4ab84fa,2ec0f21c,3d1c6d60,f22817a2,954d02b1,ce6e8b91,d826c11e,f8e542c4,245a55f3) +,S(6f019691,def39afb,103e524a,598bca92,3c99e44d,7dff4866,f76fb6c4,47e6b40b,a225b484,cda916f3,559e5782,3b519827,8bd7300a,c31dace1,7a797582,2a2e2a31) +,S(cb9a979f,c4e8d887,f03956da,9ac89637,579813b0,c3b27874,82961a54,e54c16a5,ff42bdc3,1a837d98,b7d37a38,db3c74ee,6109e868,d06b7c33,d5562dde,b11ddbf2) +,S(2ccee51c,9d63f3e8,99314da1,656cbb15,635928bd,309cde4b,69699860,c0e28736,dff9a128,adb8b4fb,7bcaa1eb,6bfb390f,226b2ae0,b72443a4,5982d559,91d379eb) +,S(a239538c,c5e0b53e,879f484f,7202a52b,d52d1cdb,ca7ae7d0,639850cd,b2c4f57c,6cc1f9c5,8998e347,2c6db0b8,6b1d9092,d3cd0c84,267bea8e,75a172f9,f4879dd5) +,S(e77796ac,c619974a,63476635,7bb3bf33,6ad1e87e,8496bac3,378db956,7beaee90,3eaa4b63,c9679050,59d8cf67,7b7095c,4064534,1c592ccd,ddb7626c,10586f0c) +,S(52c332cf,37646a2c,c1bf25cd,26a6131c,3b243688,9c44d804,d2762fae,618250c6,2279bab0,a19f78a9,43e695d4,53a0dc3c,f0312987,6ccbb70b,1d61eae1,e92729bb) +,S(d68826da,36e5f78c,bf728468,88bbe6ef,f6e55d34,f8b47a9c,8296e662,4ad9bbb3,88ffeb15,5f70c6ab,9b83f9e8,30e2f449,7e661dac,889803a6,d30a2ddb,11bfca5f) +,S(af92bd8a,2a5b0034,ea074d69,a1d7a517,808d3b61,58f5f7c2,d3fb08e4,eb825cf3,2fef9245,a4a3c837,d4b57ded,52009294,c077a801,8f633313,b6db2d4c,92c724b7) +,S(df86fa3f,63d95d73,98872011,c7545b3c,f5f27fc6,a821bff4,5d09afd1,bf76d895,a891e766,12953c4f,37a463c5,ce449574,b1906c63,c192ba4c,67f4f78e,d1e93a35) +,S(a049a35e,119e27f6,e272774e,f470ca50,9a1da9b,a4e5d781,6e64a13a,23383c24,4cb8e2eb,ccc82ca4,a2f82841,34eb3a05,f85a2335,a3b1b117,92886029,96fb3fd6) +,S(b3193cbb,f3c8f3b0,b47b1a0e,5689461a,8da801c2,4c8d51ab,fc2e67b,1d9f331,2032a290,3f0cf0ad,21b63de1,565170a3,edee470,a4dbbabe,5f3d459a,3827c7ff) +,S(ff3cd387,554fb3a,89142ff7,3e97fdd8,884964bb,2f457283,e45b79ae,ef1d692d,24475b62,c1ade1b0,ba36ad93,27916e19,637071c,22fb59c1,f2108fb8,d38ec5b2) +,S(c095d24c,42b058d,c2f77e2b,463a2c7f,1ddd1dae,dd6f6111,11ba78db,26763204,d2648519,61974d6c,cf66de22,1028943d,ceccb181,ae03cd38,fb5aec22,fae54326) +,S(5365a446,389f54dd,8279826c,e1e7df5d,b4a9699d,b8208efe,80d1eff,2d883ee,74625a49,b7856c1f,b157776c,cd79270a,2957862c,a437bfc8,75986264,401e714e) +,S(4c073085,e96134b7,75248412,c36b3b33,77afa275,24c83369,a2477b8c,9851f15e,fed40d9f,a44f64b1,59c290e1,63d1add6,92bd2782,51de71db,e302cbfa,67e508aa) +,S(71edf152,ab95a066,2b7e5190,8af75f38,d03d27b0,3a3b6607,4f472b7,706a3114,c3e6f145,dad44a3d,5cf056d6,2c608b4c,840608bb,aa15a101,c9bd3cca,e511741d) +,S(1b7d41a9,3cba67ad,c145962e,7b2c6353,bfbc8eed,34eb4c27,bfc181d3,1ac0a802,b165e7e4,23c5d880,1bc3bd1,ee0c6778,50986b35,9dbad06e,aabb2f57,dbe553bf) +,S(ce997626,cb41ab98,58f591ca,c89f7a73,bc1df836,716ee74c,45c4c781,eef4ccc9,be76f81f,a8e4b053,f63be23a,5e72ad6b,7aa359aa,e9407b60,98bdcadf,e367b167) +,S(5b0cfa70,aeccd544,cd634d10,a2bcccdc,33e4525a,54259ba9,92c40100,698bbf2f,ec50e655,163994b6,4881369f,b3aab550,65df1a5b,dc6037a7,7c01e56,904660d2) +,S(a03873b9,695ee82a,42b72a90,f0cdfc68,dbedbd2e,a50d5ff6,e120d811,ce8d5097,5947c8e3,56e64f71,b36fc1f7,7ecfc7f,a31c0f0b,cbb05102,775648bc,f2435758) +,S(d6b91cc6,6dd31e59,f04c6e58,bd7448a3,fac62753,68579214,11a8b42c,66084ed1,fec7fa6d,778c0b63,e7dfd72f,ef044da0,903ccfc7,1786f0b1,85edd004,f691a0f2) +,S(896a1313,e0a96d35,9fd42841,7790baef,a40647cc,f56264a,ac3b72df,687b5692,831d4b47,52f5fcd3,4942ca26,95dc86d8,4fe49c73,7c2bd46a,f892eef7,304117e6) +,S(779e7400,8e564167,56795a4f,9d2021b7,94aa9689,eaa37780,8e3a6061,b5bdc04d,739ea3a9,4f38be31,df57c052,362d1872,333d2777,c6704c2,e69271d2,9f78b123) +,S(f20988a9,3a3273a5,a015866a,c4de930e,507b5b48,cc5ba52f,a2a71e9c,185e72a5,6c861907,8fadd612,c0535163,dfa4cf39,648b59d6,4b056bb0,4e06695b,3b51213a) +,S(7e8520e2,3151c78f,9f48bd10,5aff4087,dd90f9c4,2ac33e24,19499ab6,8e5b21aa,995827b,43c276dd,61403388,27b2fb9d,9fbb46ec,af10b65a,a8025971,608f38c9) +,S(98f0e4b0,9e72ec0f,d80ce3ad,eab29913,fe84fa49,1786bd79,7f6832cd,7ed4dc6a,58c42bdd,7ca43579,b45df8f,b2a6db3d,41f75a3f,89dfab0e,e000383,c9e04a54) +,S(31cf38d3,dec1162e,e75eeac6,6827aad,22fa3ee9,abfda002,b6956600,6fe596ec,ceeb4b04,fc6c31e7,7a6260ca,bdf92569,92841221,d60ca74e,81309472,8fff4442) +,S(60766d5b,50cc4d46,a1234c92,1baeec1d,29900e23,4493f174,2f06ada3,ed9dfbea,13debdc8,9795f421,6f796a53,74b87aaa,bca4f73e,fda2ecf,7d151870,179c44a4) +,S(1b0ebbaa,35e8ecb5,a76d9c30,ab88fa10,b211ce3,e7c2b428,117645b6,881c7895,a312adef,e1c4a34c,d9f75d10,bb2ceb29,79184181,bb955439,e317cde4,202b2f83) +,S(b3129f71,c3438602,c9c24ee3,2f997341,26dbd76c,60cf7713,200ffb68,e486fc94,bd4beeb5,70966285,6a15002e,a25046cf,996a1cc7,9a570549,467ac179,b4f145f9) +,S(2925ca17,662f0905,3927d40f,f2fdee1f,66cc5c13,c3587e78,fe48effc,40cc075f,6d37757e,64f0438d,7bfb3658,5df58dbe,a8ab8cdd,89871670,dbe221b7,4c416185) +,S(8d55b85e,fce6bd0f,ff8906d1,6497d35e,4b69e701,da7845f2,aec1a049,39c9ec45,435416dd,9fd01388,b717ba9a,df574456,785cc0fa,c115dc04,8a242270,4a3c77dd) +,S(a660a9bd,b419e19b,16823b5e,dc3fcdde,f1021b71,4debd17a,9a0619a3,aabc23c9,ef6d4bbc,e963bb1c,2edffa5c,ef70e330,bddccb4b,3b23cc52,d5b4a689,e0c76c32) +,S(8896427f,c92bdbfd,59699ec2,222b4bbf,2198e160,94945c77,1f207bbe,4cdd6b0b,bc6081fa,abd2df26,b087acbd,a2c67c63,2eb1a8dd,6fae2454,6f3fa747,be421ff1) +,S(47e5d9b2,3f429484,61ee9f38,2f14babb,f93e318f,32d67063,ed20e917,9894e993,bd17f8b5,6084d3f6,62facae,24e93e3e,29205f21,68903ade,4f7476a5,ba70e8b1) +,S(ff352870,69bf1131,6f530ef3,b32a487b,3f11e6e,f8518c15,b1202a18,4e6d5487,8920338,ccf36f98,4afde38e,1a74528e,86fddfc7,8d7a6964,cad4286f,231462b6) +,S(2a713d8f,eca88def,b5fda7f8,8de9c6cf,9b97bf0,4c070173,aa47dad9,197bae2d,5ba64900,f7d18ec6,8887bd26,d2769b0,26d22e96,1007b58c,b27b8983,a6e7adb1) +,S(853d813d,3133ed7d,a85065a5,755ca0c5,3f32f156,154853b4,b018668c,b165ace1,fda8017,e00d20db,6ee4c0a,5790b504,afc376ad,170d74bc,1261abcd,241ea020) +,S(d5c4dc15,37b048d8,6631fd14,7d896d6f,f403ceda,7de8883e,1ccc006b,6d9ccd99,9ea2829e,64213434,eaaaadc,43ed10b8,28e706a,5001d7df,47146058,8bffa8ed) +,S(f649da82,d50fa298,8c598d5c,caf1e7f7,2bde2cc8,8073b55a,2e43b6e7,5d44905e,4438f4cb,d3e1938a,b461b1e7,b94d8f6a,c6e287e2,50d06da6,67aacb1c,609bb6cb) +,S(adc3515d,4fb7776c,b1592a69,13254d7,afcb20bb,8a4d7529,7ddba70a,c35a7193,49b7bd8b,3f280916,c6024e46,afb45e6b,da5bb15f,3d3497fc,85e9a46f,acec3d80) +,S(d78c46f2,603a00df,b45d0495,c1e2b346,963dc82b,84512cac,c2227acb,383f75ed,76b02870,2e7a3da8,79272759,1e2f81ef,54ed02f,debde8b5,38f9ff1e,4335a21f) +,S(13904467,59e0fc27,c2a499ec,384e0906,bf293dcf,c13ca16f,d3bedfda,d320e466,5320c884,b74bcdc8,6e0c21f5,40c16f65,dc61f19e,9ec5e8ef,385fb637,ee7a3701) +,S(93700603,543ec558,3fe48141,310b184,aa8faa04,6058467c,389c10f3,b98c42f0,8e0acf55,bfc585df,4f8cae06,131753ee,23a7bcca,68354182,61450e1d,e1a136ce) +,S(bdcb9434,4c556618,a247c935,29c5ba74,c68f25ea,a5507148,1431c00d,6926884a,c29b7b1b,ad6ec5a8,e7046cf7,cdf99c6d,15f6a3e4,3c6ce718,9ae2acbd,531bb17a) +,S(839ac85a,9337818a,b07b5611,f67eb16,6342c1a6,8aadefc4,6842c023,336afb08,88b30690,e79fb157,3e424c80,75bc810a,fb9d57de,5464a253,79d06222,ea656b69) +,S(2959c32e,bcf9289,9882e003,c8a28e71,3d491402,4d24d878,ba8bed88,47b949c,ba2643c3,95fac027,6b7c55e4,d2d2f530,318665f1,ec2065d6,eaf32c05,123e04c0) +,S(71116eb0,5def3abf,bff3e235,a0306605,b18aa465,b47167b4,4eb3486c,c442f3aa,2652a726,35be8336,f9b51607,76b3af84,26a23716,871fa64c,898520eb,822d6630) +,S(400c1bcb,dd3e3978,3ca06e8c,2abe8b0b,9b45034,a1655cde,fb748ef4,e2a477af,1471c86c,c8b27b48,1d4c45d,1533a5c8,d46fc3cb,ea4788d6,c48dbdad,6f7670e3) +,S(2a4abe28,5cf94456,aa92216a,dd635abe,71a7e825,712d775f,d61fdc98,a4c9288f,3c0d2483,3d6ffcad,b471d234,4ee8d07,15c09719,b18cb581,8ede730,35d89c15) +,S(cb0113a,1832843f,7e32ce25,15b0b23b,8a803ea7,50b500b6,3fb89f6c,e7bb1884,816d7056,b775f13a,cfd94a6,f88f442e,519495a3,6e74d8f8,359a8a03,16583bda) +,S(4d7be7ae,5c4271f6,c1adeb7f,4dac8467,beae22bf,ae00a71b,1e353be9,5ef172fd,cd7e6415,5708d20a,9fc3b0e9,85517642,f677281b,49490439,14845a36,afe6ca56) +,S(bc285658,fd724cfe,e6ec8c7e,35f9197f,e9083bf5,439fd4d8,d9b262bb,7a3c38f3,80c10d7,59f76b4b,8330c96f,38a1af24,1d1b0db7,4e6befc4,4f085180,c1c33729) +,S(a829ee43,221d9955,38ce8aef,e80c49ac,dc6e71f,4293750c,c0585c1,69963f04,144f6b56,d996a18e,627d4c8b,8115b2c1,c369f410,ec8924c1,73382302,3758ba33) +,S(f5450bd7,efc9227b,e7d28ad6,75ee14df,1b2378fd,308e6c5e,68945ac9,a47d82d1,20201fb5,cba463af,cc46e6da,caac8417,63356e64,5cdcfa5d,9d810c48,272cf8e0) +,S(7dcbdb69,46dcf79d,454095f0,b61341e4,45243bc7,c2262817,374fea5,37a1a380,bd2cee4d,c7ebc71b,46fb3bec,bd6787eb,d2be3128,703a884d,98359c5a,43875977) +,S(f1d6c1db,cc8d33d4,fbff821c,8c788d06,2d906063,2f44a786,585a6526,20ce776a,3696a3c,8473bd07,76e77226,8cd09f96,3dbcd143,e631c32d,5d83254,ada29340) +,S(f1688e1a,d5df4e43,67caec6,f2234534,f65aac3b,79a94ca,32a786bb,9fee4b49,efb620b8,e2164685,c9a3837b,5c6eb70d,759824,96541aed,eb80aebe,4193e34e) +,S(b639e284,3ecffb0f,66c2819c,73787e10,527086e2,5d3da074,e037a915,e06a5813,61fde1dd,63ff304c,8ec99d4,67ffbabe,e8000637,b9856bec,344b825a,4f198407) +,S(11a4ff89,d5e63ec8,6a0ce18,53dde8a8,875c9a9b,f563526b,cd25b830,6e3314dd,9f7ec77c,9a3f88cb,7f64b1ca,f2b5c7cb,d70d65d6,dbdba9f2,68832f3c,a2e117a4) +,S(323db783,26abfd99,2b13d67f,3ae01415,77162203,c50322c5,7a7933e8,7d687d3a,92c8a67c,ec834653,d0f1a50e,a7834b38,631d83ec,ee38e50,33ed927f,7e14253b) +,S(2907fe12,c8433ab6,2e6283ec,85b93342,ecf14d16,6d90cfdb,b4061968,aa35170f,160f9790,66291ed7,d51962d4,be02d85f,8a92ff8f,258a9a07,55b8a5ca,2d57c2c2) +,S(67cef7bf,a58519cb,6c5cd8c4,f69d5cc8,84cc77a7,854a4b6e,a40b6dcd,57e43e17,e8071d35,e590dfa7,4d4f4da2,82033f1b,590b9383,70b571ac,ebb3bc11,b9b48482) +,S(81e40522,3d4ccb14,3952867b,b8398cd4,e5ab92c5,d91066b0,d1fdeaed,55c71165,55357564,af12b507,b2e24e6a,425697b9,e6356b82,da36f111,2b5c3394,183c0d10) +,S(4880abe1,47bcc598,a3743304,1afabe99,fc525daa,564c4b05,2aa60c27,5c814628,b6d944f1,ec69e7bf,2cdcf621,864ba76,a1df44a7,ed15ae15,290ddbe5,b91f585e) +,S(fa2bc507,19131dc7,d5f23fe6,9e60377e,2d2f11c7,f8a9a451,82aa69e6,24eef53e,9b0f2017,5f287d80,41f58930,6cd022e5,9b63bab5,1b26abfe,1a295ac3,46a2e9fc) +,S(aaa18fe1,25e781a8,901ac351,38d2bffa,83cf7c3c,99a4c7d8,54b30c70,c9483e8,6a8f9e1e,a40f6383,6008a0c3,596f7644,c044bf53,9700a142,ec5e3c97,c075b03c) +,S(d473950a,8465711f,71a6f1f0,22f4bfcc,1c16ba81,4bf73c2c,1eca244a,da4999f1,6eccf9c8,aafb09df,46ca0d36,ee9028dd,1df62bdc,6ade77b8,a5d410d1,a69bc775) +,S(d7e2b17c,f8e1895c,cf9fb163,b56f4be8,ad99133f,f00f2ce8,8ce911d3,3b8e36cc,b6557693,ed9371ce,69bf397b,56c0b566,21d38958,ebdc0b96,ca488570,1561e6bc) +,S(3f1e73f2,a2192809,acaecea1,71d175af,683e796,e1337db2,11b6b34,8ba924f0,a593bd94,96308bb7,76b63703,bc11e30a,c5f01c17,c8b9748f,3b4c8015,56f52c3f) +,S(4cbb68b4,27899c92,1c0d969c,94341d8d,161f3b8b,3fe4cfca,2b583a63,eb383dd2,6b3c29d4,97728ac7,b45cf7ce,ea618789,95935bea,bd146e1,6c756f61,4698b6cb) +,S(e41b826b,52ff9bea,354af41e,3004b7b9,edd01e13,8cbd466c,ba4cbab8,d63bb4e0,75d5b642,47388aa1,51d4d8d5,2568a804,fcf66ba2,42b3f56b,dee0350d,ecc527ed) +,S(d508dd5b,ec38f795,88bf2d9b,6bcc9f8,aa96689e,91c1381b,9f8db311,94588028,9b144547,1a2ee559,6584c927,2d779fa3,123a760d,9faeabfa,1e39d3b5,ddac2595) +,S(5276f127,3bad7149,ee5ff022,2769dd6e,973018e2,a9948070,fdc82148,ac637de0,73f778c2,caca737f,acd3d877,14e24d83,964dd47c,f22915e6,212bfb09,8e804e21) +,S(2e9ebbb5,9d108d21,71d28c27,32af659d,b534cd10,c5457cea,3fcef018,4d7761a,229d20ba,cbf0104f,b385621f,dfe386df,4f40c287,7d956046,60eb3923,46937bff) +,S(ad819539,5b94bb1f,4e60ab85,932b24cf,2c79c20b,79a972bd,db1e4201,c49f1d1f,9226c45f,4d161a1a,c5c3c0ba,a0536def,3c6052a4,ec22dd24,cc803a37,b5d791a1) +,S(f5d4baf3,93ee5acd,944b2057,78cae170,8a622f30,68d3147b,62bef05a,88fee96f,9a187396,9eeba528,9f5fca32,6bbb922,2eeff5f6,6d205a0c,78b77dea,ee17d1db) +,S(1a0f5e1c,b2fb5d01,fbcbfddc,da83693e,9619ea60,1669c728,7710733a,e6ca778c,3074e8d1,61da2d34,38be57cc,fc437742,533e415e,5f0c888b,834a2fe5,5d4fd6bf) +,S(a78f6f7a,110cd16f,99fbe16e,9be52782,248518d8,e621f478,2167887,f81cdae4,e3f78e8d,507f9af8,11653ab8,5f2286dc,db34d9dc,8106e9f0,57610267,411f02a0) +,S(c53e4243,b26ebe40,a1abffdf,3c42129c,47e92cb7,32bd66c0,3d4a4290,c68b1c25,bd4f96b5,b5801b82,300b2132,2c39fd2c,65b2d084,e657ba2d,7db5df15,ab960e34) +,S(a3a1ddc8,56957468,2e9b8a57,50bbc738,f72dc60a,1c09c95e,a6559b2a,736535e4,94887a0f,a4381d9e,dcc4faf5,1525ce98,fc43116d,29f68c99,236e4940,6842a741) +,S(8160ee7f,738f54a0,698806b8,35ed4bca,113bb568,b23fd331,ef5f1cc2,80b6230b,382ff30b,f13f1e28,95a38af3,13fcd099,249b195c,96ac42a6,6a929fc7,a907b17b) +,S(68552ddc,6b219554,dbabd276,e0f2a5d9,33610bcc,776bc40d,7efdc1c6,1b992e35,eee09352,c82dec92,b0ae8d8c,d6918ac6,df620dec,86a0e4ac,abfe8025,52a0ab5e) +,S(919fef57,f308255e,1fa802cb,5acab880,c1810c62,c79a4ecf,c2251a2c,cc02ef51,cb38c163,8f7890f2,d61a980f,ed712ca8,97296366,7927ff7,39de824d,207ab566) +,S(d7e493e2,e2c33635,ee8d22f3,76fa8de9,31ed4eb0,9771746,f48ba201,307e04d1,ff7e6d72,f712f2be,2bfffb43,2764f677,62917509,3cf6bfe5,eb5cb7ce,85c1a8b4) +,S(6b642a8d,f4131ddf,7f31dc9f,c26b96c9,286e1f80,de2af96d,52e383d1,ffa73a41,1e55e667,5f0ee13e,76818c02,ce424d8f,48cbc930,b25dbb85,363019c5,fc29979c) +,S(7ade4aa8,1df8c53d,1e64655f,bfe0ad88,4057e0b2,1c88bb2b,4c8d5f19,34794191,cb0e9802,fbf1027f,dd8d2167,f4f4680c,f9e18f4c,3bc3310a,c4014745,530a06fa) +,S(6d578cb3,1ed19dc,812fd360,a367996b,91a7ba42,7d2f74c3,e2a1721d,72e1c017,4ac9ad2e,aab987ed,dc994b74,733fc710,19301e1,f691999a,5161cb15,ba11e9b4) +,S(df95b5f7,7bb79814,21892d72,743abe4e,828a7544,f9f0e774,b1f5ada7,a054978c,4ccd011f,a966604b,32f70bd6,1a3c1515,c6d1b261,a3ce5c59,7078cc9d,f723b32) +,S(d7392d17,1cf72e1e,ddea0be,a242edf2,c418e9eb,7dcbe1b3,aa07ae7f,a11ef08c,4b696f78,20a9ac8d,a5f52c8e,9d1a39c,bbb3d3d9,fb5b38c8,1b46bcfc,90e869ef) +,S(f01f2aa9,82842315,98f414ae,f87c9d7b,6eaf21be,c4dddea1,3967677f,5d2a1032,7c3be753,da5485bf,13a4cd72,a9e3fbe2,28fc6a22,c502b19d,1b6f7d18,149e2b3e) +,S(cee8f811,4b1829ab,a47e9b5a,54de7cba,1f6edfe,624f30e2,ec4979f8,3145242,4b01f7b4,cebb1125,20bb0ab2,7013af9d,11d19c4,14b0c29f,d142c7d,5b903a09) +,S(f4215bb,973b5586,ec051388,203b1c99,cf69b555,6b1591d2,fc711842,759e9832,5d8a5ce3,ece7c011,df3d414d,e62ecd4,2d716c73,cab02e29,621307e0,658e6fe5) +,S(e39ecc23,90c9464c,32b08759,9a44586a,da09af95,ba8a3b30,2cb015d6,4a49b18a,bd7957c6,e1feb061,f5535231,4f5c5e5e,c8245f28,4638f390,d079cffe,bd2eea7a) +,S(9e6bbe6c,402e4cbf,e298e789,458fa9a6,68cfd407,3efb3d25,4699278,760589,989bf3f,9912b242,419c848c,f82c3fb6,8690ab05,bc23372f,eb9a850f,b4dd44ba) +,S(67504bbf,57824cd9,8a3bd82d,34fcb59,3d20590c,a90b5652,c4ea4695,1f48905d,93ebbf6d,3678478f,56ae5a54,cde812f7,d8d40928,21b5e82,71669dd3,f0b263d3) +,S(4e5bee50,503a28c0,9252b9bc,dd28af66,cecae127,2128e88e,fc431373,7324657d,d6891df5,3a4cdf2a,d7ab610b,817b0f60,c2502442,2e40269,a7da80dd,2672e0f3) +,S(7481d5a5,bef3d397,533e01b3,640b0809,fd6ff946,a1e5481f,b90f0b3d,dd05c21,21ee7275,9c217d19,3999df2b,e3cddff6,fe59f26a,e570e0ae,58868441,f37e342b) +,S(778dff4f,dd32f251,6defcd94,188f2440,26b9f789,ff4eefd5,84b2c15e,2bc61d62,996a2edc,f43e10d6,93cc2d00,c6f4506f,45be1dc5,c762fe20,3dce124e,34e320e0) +,S(cf531271,3d65d471,929f6108,12db63ac,b1c52203,eb879ca4,a8ee9f62,774580,38e28f4c,881391e0,55fa7148,2c92c097,c842dd,74a58d6b,5753d6e1,2f773b19) +,S(99702d01,9420286e,723625b5,62c8152a,2dd5f1a,eff84437,8a182cf4,25582031,8c4af2b2,654f1631,82d08bd6,e7f8b6ca,d5365b9e,d869fd23,e5a3c4d4,7e5990c) +,S(68614c88,6b59c198,c49245c1,e1232cb0,b4bcce31,e0a2aa15,9fb2331d,ff1dce66,49c870bc,7ac78e22,b635c2b9,6f29e641,3b29c6ec,8ec8b3b7,8fa6597c,90180c7c) +,S(f497a9bd,3c0e923d,5d622ab6,afeb9e8b,d9b4525f,d1f30cae,2a44d0b3,e13256b,af4d0273,e088adb0,b7de7724,b387e109,d49d20a6,eceb369c,12e07eb4,f28c9e32) +,S(50a764f7,f5e29cba,ed7ababb,97d2ace2,22c06c65,9ce87d77,83b5bd0d,d165bbbe,4abc57c5,4c9f1d54,e73cead6,d77a85a0,8be25ba0,ce96b8a5,1b4fb460,5eca949c) +,S(fccfe1e1,e312e6a3,92e83cb,97274576,56415255,b127ad54,432c93cf,4ae29bc0,e681795f,d8340902,da0018a0,dbb8a424,870e4bcf,7de95f0e,b2c7e98f,47a46c58) +,S(66de61ba,48c1fd44,80d5c78c,3f06c3e2,45ecaf25,e4c235d5,8408c90,e1b62ed1,bf3bf086,a90221ba,711819d0,d80194c,c45177e2,57b1408e,7e649f15,a92aa6a0) +,S(4373e7ff,e3995503,97bdee9,c9d3d70b,39f47446,45fd3c1,63b2012d,58e148d6,440a1376,16096124,42c7bff3,5f9a8aa2,3ac64e8b,bd5ca839,bd3c5a39,b84e6fe) +,S(c8774ea8,7d83fc06,c36ab357,b1fa76b6,c647cc9c,ebf2e125,3f3ab303,9306ef1d,ccbde78d,2e4d2c0d,ace4e660,efdc4d1f,a1dbb44,4cabb0df,bfe29de3,191f7249) +,S(748cb6cd,c57d89d7,8842fae7,731b1e28,3b59ed18,cb761c88,a4d2e4c1,c3359fc,62f5b6c4,11c72d4d,a412148b,8b038b32,8f98aecf,ece537a7,237b9f87,646b9a3b) +,S(35a83610,30fc10f3,53d2fdbf,cf67655a,91b86555,cd3d9eba,f962996f,ecf55cbf,6fd79f5c,df8093db,5c7f3a94,52dbe6ae,bd1ca410,199deb04,761ffffc,77ec9fec) +,S(cd05bbae,d0a8d78a,2e05e9d4,1c33cbd2,8d59d384,75d42389,43f9cc35,3a8a30c7,9f7336dc,8e77fd55,bd0b9e8f,23eedf1f,d0c16f69,921994db,dc2588dd,ff72a8f8) +,S(da3fe760,2547c831,2d4f515a,5ce530be,29379325,41c6de36,364c4b5d,ead43c58,df60bf1a,d2fca43f,6d482df4,61fc180e,5e3cf692,995bf8c1,7d32a263,730b3ddd) +,S(bbd7996c,25ba5c24,a14742a9,745dd2,8c18a598,8279581b,f8b5958a,8092051,896a39f1,310be1c5,9de4b86c,7c9bde10,8035ba39,864a45a3,69573d16,4afbc2d) +,S(bf7c20dd,64ba5f51,2a996bd,428fdbaa,df1853fb,f814e6c7,a415fb64,a3e16070,afaec0ea,2b18c89,93a1a565,f3db58dc,748df9eb,4d9f8a04,a18cdc23,4710d5c6) +,S(919d0aa8,10928129,cad99b09,85bea5ba,7d4ea114,9f9d5d65,2b6c0e0f,20464903,60d9352b,d053b01c,83caa121,63e8c9a3,e2153cbf,b335943,7a2a788b,7aa02dfb) +,S(5e7c2a9c,6ab8251e,8f8749ab,e0ef107c,aee593e1,a8632a6e,1e0e0c4e,d3cace9c,74186f42,6f03f806,36d79258,e9edf593,6e21e0b2,d882d933,c0241ae9,7d761582) +,S(2815184d,af1e838d,86d63a32,db5339df,24731743,aee62add,21e3a6c2,c2b0b1c0,2a4951e8,3ec61221,b1035c6b,a7d2cbed,f6ef93e8,cff69e01,295e09d9,20e05919) +,S(e3086e36,91432a20,8602458a,87d82955,c8920ca9,fe1c079,3eed878b,282ec3b0,13db4219,50388269,cd591c5c,d8e07ba1,b532f01b,485829e2,aae4f55,f05e4362) +,S(8264d534,2db3261c,d7e294c6,eba040f5,461fb9e7,e3fa13fb,dfcec29c,20f2fa7c,4dc311ff,10b92db6,b67f47ad,86fd74be,24e3dbe0,d6a74842,92f35d9f,6e95eac1) +,S(9edbed6,3c4b66ce,a8c2ac6d,89622d61,6838e1fd,9b93c363,c2bde528,a629b2b,c1706a02,5b1f9419,2dde89fc,63ae2a81,ea015ab2,964beb58,d5ca7ffe,84266644) +,S(68006753,672e9ae0,79fcdee7,9814a904,80c170a7,f644302d,e5de7982,7684e12e,fc1209de,88ca7c3a,614252e3,153df13a,6d0e8db0,4c82d83a,fcbe65a4,5c084398) +,S(acdfba80,9e519114,a11b1634,1835d7e4,5b93a6d4,7094846a,e1ecec00,18bc4531,a4e57d02,51511f2e,5b729309,4c50ebef,4f8d3cb0,d930ff48,20d0623b,d636d664) +,S(978304cb,e99eb899,5ef43f94,c67c471d,6d42ec19,f83f9323,3a44b9f2,e2d13896,ab26782d,2c1dbf16,a90f90c,8e49d250,1e1172f1,3e1bd20a,3deba979,85fcb110) +,S(8c8b561f,9c857510,88478c03,866b347f,46e06801,82482343,923d7e27,c67f49e8,e7908d27,79cc5b19,dd00f2f0,4ab52474,5c35cd6d,4b85932c,99614fdc,64048cc4) +,S(d4a7ebc1,987b1abb,5d02e598,190f73a,36d1176,d7f0f7a8,cb9491c1,b86a3c55,4f321dec,9c1832e3,b0d0c974,798834ab,6a410bfb,398ebf58,177f39a2,22ba4e50) +,S(14bbfb6e,7910f522,69e544f2,ad3175d2,3a36b7aa,8209c24d,1fbb4277,9508c261,d16147c7,2a1df442,d8e831e5,aecd54c6,8bc3f225,4d0f51e4,9a375053,73e8d08) +,S(d24ad71e,81de43d5,7096e101,6bd4d99a,46e52e56,782d99ee,838217a0,dfea0f5b,ae574f68,e07cead9,f214976,67a18c2f,fbbcbddf,2bfb6c95,3b7ba673,7d08903b) +,S(ac96889a,f0b46b7,6896b763,8e1a13f3,dd24459e,8601f892,c3367c7d,8b52931a,b68a8631,8672c378,d99b0b20,44b06190,876ab100,eadb12e6,c16c2ba7,c1ee2381) +,S(36b4da52,4f4ad5da,d7396445,1e79bd5c,20973df0,efa82bb2,da4bf68c,55afeeb7,5cb7598b,576f0db4,db1093c5,e6c9723c,f493bb91,450a0017,9f79c8e9,92dd6136) +,S(98c7bc3a,7054f928,d062ae65,b4140dd6,293f2fb6,cd16fbba,e00d39d0,b11befd2,82d134ac,3e614e4e,62b1b475,bbb5fd80,a5e6d3e4,e4572dc5,7cb666c9,a06131da) +,S(95bb18cd,991cdf72,1c627d62,aee4655e,aaed0b6a,b1e64537,fa89a0ac,f60b4a52,c37e37ee,5b87a5a5,e61824a3,ea519f03,dc3b0a77,f755485,d337ac79,f1f9e8c9) +,S(41e45ca2,b88a4679,6df9106b,c8b53180,81674c34,9646545,e5ad9b6d,e5f6cdc6,151ba666,b0fdb7a7,18110f62,83e3cb8f,8e40fb8b,fa1a1854,75958a3b,ec10d197) +,S(32d15f16,dda923d5,c2f1bf5c,9c003b33,b77d2450,95e5ad31,2ec62956,ae092805,58d64c72,96ba6976,d61774f,f37a0d1,6316cd19,3ac0d930,bdcf4924,cd904095) +,S(41c4e029,817de516,8dc04b2a,9bde3850,7ae48602,dab08db0,3272c694,6cf099eb,303738a8,7b888601,2f9e2053,5bb8b610,92f6222e,96968afb,98940d85,98181458) +,S(28b8ccf,b14a86a1,84fc3c3c,a6a7dbd8,763415,91a67d8b,4109f026,1dd964c5,899f98fd,5e0c59be,69150d8c,5a917d6e,864fa15c,63072769,f75f6353,8cb276e6) +,S(f2776367,762d6468,c9cc0e38,d3921813,16dd394c,eaeea519,786b4353,a5044586,1a873421,1b170183,a117e420,c41d2725,84acf219,a415778a,4eb0c34b,bee9a68c) +,S(7a1a5f53,6e96ee57,e10b1337,6bb1e895,d0703c6,5adfa4bd,f24937da,98bd7144,860921d5,67fbdd1f,11aa3ced,103453af,8c3f5037,b92ff10b,ee70ddc,e4323206) +,S(d82e79dc,5d6de6ff,8863e039,60401bd1,610500f1,57fd2b41,f20689d8,889c3f76,f1947dc2,ca625df3,af5ec97d,32e62c09,2139d108,948795ba,5cb164b9,351bbf34) +,S(6a2e184c,23ee235f,93f036c4,3875db01,22416a6d,26ef54bd,85a2b465,defd0351,6c44297d,724eb2d3,2f58a197,2f52a7ad,ee49d30f,c8f8424d,7f26c6e1,73dc6868) +,S(ea0d5281,bd1417c7,2dbedbd4,dff37c49,bf143417,d2a40dc2,573b4b3b,2ccddcde,c7a35ef7,685faf18,c5a4cfcb,2eca27b7,46b21d65,ed71aae9,15185cc2,6d2b54ee) +,S(d5432c9f,8ed0b4a4,c3e42dd8,28098f13,11d2cdf3,94672331,51fddbf2,a6030974,1e047ebb,8cc01a43,2ee6ea04,578513aa,17ad2bef,7fc7653e,936b2d22,bf8f6c3) +,S(c99ee053,655c9d53,1fdd2298,3cc03756,299f47bb,5e1d0a4,d7b861fa,c3b5e332,61c5187e,4e12f8fc,617a5fd8,746f28c3,368b6b19,1189172d,8c56e2f4,679f6b7a) +,S(f41ee431,170be2d7,fd488c3f,5f21f3f3,aae5e501,1a3c4ebe,d0f6db8f,63e11e55,f767b289,118391c4,4d27c1e0,76b7c70d,110cb938,e9c5c62f,1af200ad,7e9976cc) +,S(505a65a4,29388bcd,55561f5e,fb3090b2,2d553bac,2f8cee97,6c0685da,40006e41,c72c9e86,6b4de925,3d463d7,e7bcf7d3,d6e7c351,1fe6c4b4,7fc436f6,d793e0ae) +,S(ca34be0d,48bc2931,cabe71d7,9cd2bc23,ffa928a,5d532d67,f3665acd,375dc01e,263008ca,4dcf002f,8fdd580a,65701694,bf4530e8,baa0438d,b77ec246,75b4db4c) +,S(d52c25e,9a76600,b16dfa93,cf9c2df3,38c806a7,d8cff18a,1d262662,5fed6d7,80309810,6055c3a4,d5d1e5ac,945aa815,bb8ca3ed,10b5d54f,156e4336,39c4ac77) +,S(83e43bbe,62e39426,a0a74ef3,831cb4d2,776d7ea3,d5a2d57a,8280bae6,ae0bd8d7,a1c2c1b4,ea1140c8,cb4ec2a6,98a3f727,666eaf81,1ae9b89a,9e09db39,d1a257d2) +,S(12326a97,ad8dbe89,3181d76c,6d7507e2,74d62cca,1f0a3517,30e9ddd7,198de84f,79e7823e,7cfa4df0,bb31e9dc,ac415297,edc6e061,4fca2f18,1ac7fd46,d27fff48) +,S(1ad3375e,c82aa917,88bd787c,37fef8a0,2071509e,aef62e8a,dd5c5e4c,b096cea4,f9f9f10e,efc1fa79,454c6d55,b894d65b,ff5c445b,f4e9e46b,8c82a4c2,a94d5a71) +,S(8e8bf9c3,a752258c,278bcf19,7aeebae6,fcc198f9,2310b13d,d114c1a7,d10fd2c9,e2f41d5,b7d94378,5f61f572,763e6e88,df7b321e,9baf0445,482d9f22,f1160195) +,S(c44cd33a,144e2926,b7ebfb93,d7d9ab56,3888f6d2,694efbbf,a5665e10,f6e0ff7,c2d4afed,f77c22d2,88f9cf38,a057df90,baae8ca3,1e074d11,bb8f89f4,e9e1bf4b) +,S(b960f0cc,bd7d3431,4138accd,aadc2efa,d5b60071,7c69f1c5,92900a40,ea68b24a,e0cbda14,801794eb,19401935,3f8ab80a,f525b8eb,2b64e5ee,62afaa5a,da4680b1) +,S(f7104560,8fe120fe,5d036260,5bc3de58,76e24b6,20684413,a440cf56,6520559b,2e208f0f,fea3f78a,9a283f9a,6b601ce,db4df4b,b2fda7b6,306dc8b7,3d514f35) +,S(83a31aa2,cb10fc14,ca8cb2cd,b21cc163,41cc9862,67a5f1cb,75f3f90e,1a92c59c,be18918,400a6e32,b4fa3469,ea6e3613,251ceabb,29cbbfaf,2c16af07,fc5413ac) +,S(3d7b800f,8802e521,341f83a5,efdb355a,b60669d0,adc15531,72c62097,8106f6ab,f9b179a3,aae98427,e02d4f00,89b3cee7,250e30e5,ed72d59c,198d5ae7,1d639e72) +,S(7bef4e27,9064400c,48d4f27a,a754deaf,8af74b10,d5dfc497,98c38216,803f50e8,bab0d71f,d02c67e6,b274693f,6a4f402f,831aa4a3,5fd83014,fb07c5c2,e62d561d) +,S(e6b2c83f,2a6ea201,f56a024c,482a8076,2f2053b4,2e4d2901,4a5178d2,3361bcc,75d1f7b5,209cafe4,f98e63ac,53052a40,487b3390,e4ab73eb,ac63acb5,cc3dc88c) +,S(eb4f3b95,f12c16a8,e5e13446,d9b8ca7e,92c56bdf,565aa4f9,bc1c47af,914fd145,e3776908,e3f3228b,ba0c0523,7eaf1963,1835797b,ffd7eff5,61b30fb3,9fcd6307) +,S(e2926c0a,858b9732,82c1b34b,4c4ba4b0,3099797d,d29c5fb7,4447f28d,ff962e54,2730f3b,e59e862b,37ac50,e5375d08,920cb62,b87ee8d2,f5ec9975,886359e2) +,S(8bf4efd6,c11d7251,b06a5e08,99ff2e80,349f8022,387f3200,6d9de060,bfbf3f68,5514395,457848e,a79ba6c4,39a7c151,b497751a,a4a1784f,114686e,e351afb) +,S(4ea97c1b,920d2ec5,3c2182ce,d6f7e1f3,df49e673,1a14ecd7,d67aba0f,fd077c78,5e958afc,d3894757,e0aa89ed,ba26e035,f06e4b11,da13675e,29d382c7,b21fa9e) +,S(1b12e81,3c7c19be,18576f93,69d938f4,bc81bbfd,7e9eb443,cf2b9ef2,b8e2b3ee,47220a1f,718c36af,8eb8a9e7,ecee3899,ddc49127,91421438,8760d6d1,699a5ad1) +,S(7c6c144d,4f839904,ba40fba8,b739913,54f40bf0,f5810329,c4e3b961,ee6a101d,6eebb976,3ceae5f4,f1ef2473,a50b795b,a6375c72,df67d15,f310b5ca,9706b5eb) +,S(ec637ec6,bea71803,2bae7631,9227ae58,9581d3a7,131323ec,35f0d9fa,27a3e285,c12b830f,f273fe72,4f3bfdef,4279ce4a,8ae6d0a6,de5cbad2,b0a7b4ab,643c79db) +,S(33c8d6fc,d2b37103,2426910,6b9adb76,6c76f788,9627a9,6807572,e0af0f84,b3f01db0,7ed82f45,252d494c,af735e6d,3934ff78,c89c57e6,6c42a663,e5d6a792) +,S(35ee32e5,f7204f0d,d48b1a80,cea0a418,1d71205e,c373827b,2afc25eb,e3ab7e20,d57bc815,684adacc,756291c6,87d0eab1,63067976,a7c3a2a1,98ef1d8e,bad12935) +,S(97362395,200d807e,623826e8,3bdfa37b,e98793fd,6d7057f6,370720b7,5089a6b0,c908e9de,cd1d54a,172973b9,1706fc6c,c3367d75,2216c2d8,1085dffa,5627f06b) +,S(bd37e01,eb944b32,b379b195,16256ad7,4061760e,4eb44361,5e8e5fd4,34eae9a,dadb545e,2a613e54,6067cb6c,179fbdf6,d94b7b8b,c799adef,391b2957,2b93f57) +,S(b332b57a,4f070d20,35986e86,d82cc6f,7180293,53bd360f,d3f883fd,68e9c5ef,eebd3a05,933526ab,ba9e63f8,cb24ffa8,550e50d6,8cc7a4bf,215c551,ab89832b) +,S(fe5bf27f,9459e640,7489bb32,2012d1d1,69d40635,74dc05bd,6bdd6c38,cffb61a3,72c6318a,3775b8fc,5c790d6e,31bbfddc,7ee07a71,93e5f137,e3c3e098,bae25da9) +,S(f27cbe27,ed93086b,517c5859,9929310c,ad0e05fd,482f1fc3,af041852,c63a2a23,cce74e61,4e14bd09,8f11674f,23e30be6,b3276f4c,f85dedea,b3cbfa49,5a716e4) +,S(b328535,1a1b22cc,51b7a590,3582dc27,518bbfa7,410dc36c,e63da663,daa8693a,1b260487,7d3ad6e3,db75a0b5,d6b89df,df507809,c203b4c4,cb0712ce,ae2e3d2f) +,S(bb47bb09,70dae4b5,4f4c3aa4,ad4c966,ae42691e,ae39f1ea,a6711d6b,5f04b81e,2edfe19b,b52b7b0,2b4cf349,aeeeab0f,67524375,7f35b6e7,b920d343,e71561d2) +,S(fb6c9735,d4333142,5bf6ad83,50c7241d,b82e35a2,9cbafa37,d822304a,c1b3dd02,946a7ec7,1e0e6dd,a4d4c315,2a6e7489,8671dcb6,8a219781,3e2491a7,6a9e3357) +,S(c711f224,40cb6e74,a60509ec,23daa2d9,fbca44aa,9a093475,524e31e5,43575a3b,e4259800,352d0d79,c5e22d3e,2bf59f4d,e4b42484,68d15c47,ab5a9cbf,854294b2) +,S(9c748d45,a07e141c,639ef97e,8887ccc3,aa84bdc,ca0618ff,4f43b1bc,7496c83f,3dab775e,c3001657,e71a9d46,bf8cc120,9a74b9d5,1025f97c,4dbb9457,e932b5b4) +,S(9d5e6479,81a9278,6db60938,4a462621,23070938,d50e1bed,8df9474d,bee12513,30f2517c,6ff04eb8,9a6ef21,e4ff33b8,e14567ef,e38871bd,b9dba6d5,584c8b0e) +,S(4d24d6e8,91644ed6,ac1aa619,f9eb2b58,a9932c5b,3e8c82cb,589694d0,14b1d472,6ef1a21a,9dcba4d6,850e6593,3ee1a259,91203278,2f478fae,cda13d6e,5abdab22) +,S(fa226c4,36b389c4,50143041,da93c906,70258092,a8de85cb,d20a0dcd,284bc808,524d2992,655c77bb,59258257,5db3d663,a7a345f2,85572ff6,e9dd1dd3,21bebf6a) +,S(d4e659a8,e9af7543,2d9ec769,5dda0371,7bd79ff1,9ba73f07,ad0bf13a,45ad3b77,5f4a2de8,db9814f9,9b73ec63,6c77f847,1aa48356,ff67c8f8,3f0b6aaf,1ac7ba9e) +,S(157b6da0,1556b23f,b6c46b06,145727c0,21d6e573,782bcded,d594ae46,598df23,737d45d5,2c247718,e720fed0,56352768,ce111425,72730890,5a84a545,c53c560b) +,S(d97a6087,19c8572a,78b73938,5479e4bc,9a2b249e,a4f064a4,550ce127,fc4bd45e,f11e233a,75ba1651,144368b9,55bd4dd0,f4ba1f2d,2d0bce2e,82315e5b,78e0d76e) +,S(d2fdeec2,9b5f4ef6,374c2b87,57e4867b,d2e036d8,964a2ae,15632ca4,6f79a294,2d2c1502,a935f5b5,960abbda,9db42aea,c9f58f0a,bfaccddd,f8d59881,e2953872) +,S(fbc6a2b1,b3c0b039,9abc55fa,835bbeba,b0461db,41f3d9f3,160d0154,72861b3d,54421d5e,a5ed3abe,f22df1a7,26a2b5da,a298b41d,acc69bd5,a72952a2,13f928c4) +,S(7ac224b,cf7efd8d,b214db6,a6601d51,829d57d7,28c4c3cc,398ba57f,5079bf99,edf12fdb,9e281367,5e7df40b,1cc3c572,55213edd,c0fa07b,4e3f750d,36d6935c) +,S(f2bc4452,4af39f04,afb480c2,f7addb57,a04db86c,3691b26a,922b6ce5,a1724d9a,63c372e2,4a659127,ace8f54d,33969635,1d890dbf,7e2a31c4,251352ed,53c3a0bf) +,S(5ac48ffd,bf27b452,ca37dbdf,83f2fe6d,8f704040,f3a56180,ab991228,a74ad88c,c7ccab4a,e859e7bd,982310ff,2b7eb408,678b6f21,f52ebea8,41021f3d,fab6f091) +,S(daa3d659,a4defb4d,3291a16a,d669a43e,b6891e90,dbe0147f,568b650d,1213750a,af36d811,9ce1ff85,5dd637a3,bd475b10,50216093,aedf5f24,2c98da62,29bdcdbf) +,S(381d3791,30d4beaf,aed138d1,4072bbcc,b8d71d6,dbb13226,ff168f64,3bf55d37,fbfd7b62,3ce32a4,4335682c,d5ccd4b4,aa4430ce,d8fe3d34,9582bba,fedaf9c) +,S(757c7b23,ff6b6ecc,51ac84e6,26ed70ce,4e6e5c74,e4b65f3c,fd17c304,e19b1ccf,56848ab7,f814a047,2bd286f6,b386af5d,34b27c4e,a3ece71,f153dcc7,7e4027b8) +,S(ea498d11,ca35804c,d6103185,ae468bec,6c2f4f6d,ab025173,b1de4027,551b913,ee939bff,8d30bf5,9e3341e3,58acab90,17de8fb6,e2977847,f4322ceb,ca8829c6) +,S(9d119046,59ea5dff,30105d1b,5ee3f8dc,c9291bef,15844057,66e07d44,72ee1418,45355041,4d4715d,e8c087d4,f05b5f8b,a424ac3,49b3ceba,bf806b9c,e657e139) +,S(97bce776,90f8790f,e7d82b68,b7dc1b38,f3baded3,f7c67655,1894fc4f,cd1b834c,fcc18c2b,4f743ca0,e00f4b34,509fc237,c030b689,83451d5f,e7407b81,ed04f7b4) +,S(5339f056,abeb4926,f46dce7,3b8d735e,c6e9c4a3,2057c22a,49c86400,f15d7ed9,5be6a0b9,37e26dd9,f6db74a7,74fa10d2,cbae30f6,bdfafb,dfa2922c,58a8e37e) +,S(27f22d01,4dc5d3,162f39c9,7de3ef62,f2275b5e,cc6d5e32,6ab064ad,f762a446,6aebbb58,d671179,d712926e,d56cd280,8393fd85,dee45558,300a0f8a,a2986f09) +,S(94af2fff,61741cf2,5f158308,e7333e3f,678bf1ee,56adfd56,629312e2,2435f9d5,33a7269,79df6672,b13198f7,e674330,806f2dd9,50d8e82,1774f381,d9ec24d6) +,S(ae8a0e18,486273a5,36d526ee,3974031f,f3ed095b,a6835a68,2e943dc7,e19b37e4,23c2a51f,69df1826,9b21413e,505c0785,576fbc84,acbb2812,fda146c7,f5e8c8c) +,S(623fb527,d3d99023,9f720cbc,64478e0e,a0b84b28,5c0c3f3f,107b3e3d,7dc430aa,3ea48a8,d1eb543e,ade4a55a,f909e62,14e47d26,9471dbf,4d98a3e0,39c72849) +,S(1ff42295,d85e98be,f7aa84c4,47ec854,29f01b4e,c87371f2,b2025ba7,1e31a768,d9500f9,6e8c697,7ecc51d5,7bb7dfd1,3cc97017,58bb4196,b0b11d1b,3c24937) +,S(bc808b0b,67bedaeb,2e7a4bc0,d328efbb,1ff35dc3,b51716ca,3e501a3f,956aed3f,6af0de4b,26a6378e,6d86378d,d1f54243,929c37ee,d5c10bbd,86b80c3,ead8e545) +,S(e8ab92e0,17a9e956,354203b5,5d7b15fb,acc666a2,79158016,33a91865,b5bb46af,3e87cbd3,66926e66,3f5faa,426a9db9,811a9db4,de3a4bd8,79073b7f,c1e3197e) +,S(a7bf0061,c383040b,6e89ba95,b57102ae,2c291ad6,72bb5027,3c27fcd,f90613ec,79ac8ff2,4bbc79cf,431f4159,4852ad4e,2f0a9f86,ca72ac11,9d4e3fdf,8746539f) +,S(6841bcc7,22b705e2,759ba4e6,83d6b83a,19ee6b4a,375b38f4,5722474c,ca41894c,dac48021,5c168519,d147a966,451dd63,7838d236,5667803e,80658faa,1029a7e) +,S(d67e6d5e,a1606817,512f1db3,9033829f,69089a41,902189c5,20f0202b,8511479f,9cb4a747,7224f93a,8447152a,9fdf4c92,36a1b698,2e9196b5,a4355715,b9fd6ee9) +,S(61b3a7a0,53c477b9,e03d0a96,8ba38de0,b02e42df,162a13fe,8ad538c2,840eed06,94c07520,fa19457e,8d98fdbd,d9a9bf93,57642cd8,1b48fa58,b4b14a89,cb6142ce) +,S(cbd26d0e,a00f7dd,4b0b26ba,7358b2c7,587e233c,3a13c86a,d5022ecf,c865e4ba,50e832c9,d84ff55b,7ba79035,559bc889,53700622,59dec3cd,8b3eda3f,1f2b6e67) +,S(17a6f57e,d3d729d,c5ec018e,1b69394b,1ed78e59,6c7a5e31,bfe5dc43,f9c67e56,34f16cdb,c23e46e6,bda5db2,7538d7e1,f66751de,3eb05543,96c66a54,36bdfe9b) +,S(eaeb62d,93fa13e1,ff9d9a4,9eda40ce,dd6006e5,ced0e8b8,c02f7ab9,98f06f31,7e225365,b4b39204,b01c8890,4476c141,1c166f75,1726718,8ad917c4,9a719ad3) +,S(d09999b6,c35d5d71,55605a17,e7f82d3c,dd8d68ce,9be252e6,99493031,a39c7487,9165e761,8dfec3d7,cf733fcc,e548f672,362637aa,8687f47c,b1eb5c18,a780b061) +,S(2b4cf8d,7fb166d8,a6931bce,e67f580,870c61c7,635632a0,71166fc7,4a11c693,7974e2d5,164771d5,2e7a121e,2b015565,b3a874d,d6313721,ec69d3aa,b44d473e) +,S(d5c0045f,a411cdea,470d85a6,66aafa44,49ed682f,a1903c5b,c9594d19,5cbebea6,ffeebc77,5b24e736,8a8b46a3,64837466,85df5c8c,b40bf2b2,291f370e,94c6eca4) +,S(1eed08dd,d9569712,6c0a4039,c6aa5ae5,ab4aabe2,a88142c3,b9aa763c,632b5e38,d180547e,c4640035,ca86d925,10a70a64,5dcbf2b5,d3add4b0,3f6d0fba,5f4c2f8a) +,S(9591b04e,3de43104,3a6982e1,29a2e79f,f525888,846689f0,44e50b18,ce14413e,cc4cc696,73279c51,4aa4fd63,474050b1,930e627e,a1bd9d55,867d700e,fccf8155) +,S(690a17c1,b2dc7ff,520aecaa,380b19d6,d4a28669,83dc5df5,8ab2bfb7,6c7b0600,bdd8a858,e2d989ca,79fbfd46,60ffdc0b,e0231562,711b13d3,47cfd37b,7a53d4d) +,S(800a632a,aca6b505,f9fddc22,14efe53e,4e7ad2a1,a6c07d90,27d8109d,893851ab,bf242683,e0c1a24c,9220c6ab,deae8baa,12c6203c,a0080856,bc5e5ac6,4c3f3261) +,S(6dceb824,c48159d8,57a92334,4c72b4e5,cf2005c5,6fadedaf,5a8b780d,3ceeeab7,e6b961f7,6162ab6a,d44f3fb4,5aefc843,bf0d714a,1a50d13c,68036f42,30a1ad10) +,S(3ef5eff1,2b76432c,4bdfd1f8,23bdfdee,f60b5d0f,5d0b4051,2a3e22bb,665f2b0,8741e43e,9f78066e,d57d317b,d50252fb,11d8d235,3c2c9d57,76191c21,8798b0a9) +,S(4ce8d33f,a53f2e1d,aa696e9a,2de694df,2192db5f,8e6fe88e,b5d51340,83791c17,a023ff40,69587bb9,49ebb15a,d047f141,9985b521,ae915f54,bebc6dbf,5320558f) +,S(da030efd,a3f6363,926abcd1,182f183c,43c4a6d8,8bcb0519,3d137827,6dcd3fbe,c14f27d3,2251248e,3c4b8613,481e7c48,f1493b6e,5c0716c7,8d5e3b97,876ccf3a) +,S(65c12034,87b729bc,3709759d,beabdd79,ee7f50d7,ed2cedfe,f2c2b7e9,97192f40,f440d69e,d59adfbe,e087ef70,9b75b95d,13ac0e06,20683d3c,6d49762,ddf68a01) +,S(82c052fd,dbd6aceb,1f429f21,eed34d44,f915e949,7190aa6a,d487bd6e,68d91c20,90dfd944,c7c20ec4,4ce35d2d,4036eb97,894f5b93,6bef62a0,f2f65082,b0f7678d) +,S(43e2f20e,cab47065,e71abd8b,aa511163,e17e3efd,3e17d790,ba924de5,ab402255,6b1ff657,e37b65e0,bf2c5e60,47e36c8a,2b7ba965,79bdc711,c3ae5935,d2c47bed) +,S(27f177cc,6722e5a7,70200e2e,a9198bb9,f227251f,8efa1988,ac7342b0,985a3853,a76767a5,3743db5a,1062ccb,64452ad1,606d5065,9df8c0a5,64f049f7,764d6a99) +,S(6b1ce20d,d15cf54e,59aec7fa,c1919791,c40c926c,55801801,75c09ac0,dcce0147,c90a76f2,627d2510,8b89df25,23f069a3,6b102201,c2fb7e9c,932ae678,4a28906e) +,S(f9df6109,27b5ff70,d55d2a46,ebc6a734,df165bab,3bd27398,24a60727,5410f62b,4da454cf,7a381056,581fb115,d36161a4,4beeef74,26724d,d4f5500e,3a6c1612) +,S(16bd87e8,2f87778f,6b3f1da1,a04bc048,3b14de01,420b0074,81aab07d,ad806cbd,13a50b5d,886047b7,6898c85d,cd1bfb4,87642f95,8304d54d,12c03b25,9429170b) +,S(f35175c6,2244f0c3,ddb104fa,3ae57557,424c2d0e,f6a20246,e2fa48d3,2908dae7,dfc1ef36,8ffb4e8,2076ae27,7788444b,33880ee5,b6d5bd0a,9a2ba79f,30c4d1ff) +,S(6a9ec43a,b8a6cb70,465ba668,5e15fe2f,9e714c0e,31f1f227,186d95ad,2faeccd9,ee752bfe,4da4feb5,e4c0266a,57929e56,62483704,6e927e73,9edec593,8d538708) +,S(92e3b0b1,3df6dea4,371601ba,3d92f507,2388a23e,302edf74,6da973b4,613d2292,9442966a,dff82878,f6e0b8d9,9e56f99c,68eea310,79b365cc,5f057eed,ec38496a) +,S(35427db7,f03afb34,d13ba232,420e5d9c,4a8d16c7,924a2043,a217fbd,4287230b,5cfc1908,108fa47c,95ff8e02,634351d2,523dd990,aee1700c,7cda57c1,b106a734) +,S(a61be939,d3a33b8f,65b8fb5b,897598a7,ee25e71,5797014c,fdb087f1,90895825,fa6b7a9c,f2a4a71a,857bb126,44fdcf27,c9f4ccf2,7bf6a0d0,dcf8179e,af1a3396) +,S(659868b8,2a9422d7,1da877f8,59956376,b999dc3a,657278f0,89e1b7,a3014222,9ecb6c01,fb97f691,92402a76,13f7932,d8a82252,e6b97c66,5c727d9d,e6b2ac62) +,S(12667366,d27bbe3a,d75f00c7,b28fcf20,86e9caf6,e8b5615e,eee0f180,526602ec,dbac0f9c,32895bf1,21c90190,d5bfea81,84289a4f,a0cf498c,3a3084db,1d4a833f) +,S(74af3ac2,60461898,c502229a,8eb4e7e0,962c8f38,897e43f,6e421ca3,3240b7db,72f03ec2,7c24abdc,dbc9af25,41e10f51,5e470c7b,19ab9680,24eecce0,954c84cb) +,S(9aefb23,d88c5745,da9606e7,ce81d4f4,5a39c8d0,4f5d5f07,62653594,d3a34732,f797796e,5c1c0a56,9886af6b,fd8a8299,29ae1897,ca43314b,cb6ed78c,6c0b0572) +,S(93a3da8b,1f686078,1849ca06,24c2cec1,796f64f8,4f46da9d,34766eb9,dfc1f018,e5c50d0,fe7d2f53,fe1053a2,985d2b15,25125981,30de3cce,2ebf300b,4b944c0) +,S(ed8d18c3,f526a062,bd6095cc,249b7d10,ee09d072,435218be,f2ab6c90,c5ed66a6,42084909,f4bfb751,5ec6da47,2cba7678,7870a9fd,bfc86fba,669e31ff,233a72a2) +,S(dba838ae,b57fad4a,6ecfae8a,acb50123,decb0f60,b702a9cf,7af7d78d,814845df,c3213cec,8f225c2b,fc02519f,dce1f67,5ad59b20,91381f0e,feef93b0,3c6536b8) +,S(f1a033b8,64caff57,21857094,e1038fec,7879765a,3b977a4a,c6616162,68c1d8fe,9592b8b9,e4cc6a7,ce173980,e68fc405,88a83788,a08c6027,8623ef61,ba81b652) +,S(53967cf9,7058ad43,1222e9a,46caeba2,d8fa447a,6b0295ab,f40b8aa1,af1f0097,e8e86c76,cef5299a,9a15a6d3,4985411f,2a71b8fc,99f7a76e,230052fd,d5309017) +,S(2477d3a2,bc3fd88,6daba319,8c6fa6c9,5206bc1e,955e9d4a,c6e5916e,5883eae3,baddd174,ce70e285,1e7ed788,cb81cb7a,3402276e,d94e6e72,f20789bc,ec4f5257) +,S(b483c05e,22824454,52f44e9e,287bc21a,634018f7,babd1252,d7a6bc70,24d9cdc7,5d7cd9d,23ad04b3,3a7ccdb0,38676342,5b2338bf,48d4f910,853e9100,e1f3aadb) +,S(6ae41ce9,6c8f0a33,674f74a4,587db25f,7c368fa8,83abe414,a3f6bf13,840d46f8,d52f2dc7,d4fd791b,36e6448f,5c8f746,759e68ba,994de0d6,48c6b1b3,58476871) +,S(bd1a4d61,e19ce013,d06740be,c3ad88fe,bc3b2391,45563be4,41768f01,45f4c450,88c18e77,c5313848,bd19bf27,374deffb,1f40e479,9687791e,675af225,1141fda3) +,S(1d2fccee,47b4553b,215dd2c7,f26412d6,73319507,43136454,35426bc1,29b358d9,93e52147,c13791f6,aceab8dc,95df1637,83d985d8,3a4426d2,f825d126,e7b8c564) +,S(322cdebe,5aef9ab,957b355c,e8e4fa7c,23f23f83,bf311785,f0fc40be,ce0f7453,2eb8c80e,561e419e,f898f772,12eccab6,e6c4ffc2,5daf67b8,47853a6e,8475d19e) +,S(c7474f42,5491fe9d,51a9e00a,a42bc188,50d4fa36,c19d9869,6939962e,61e207b9,8dd394ad,799a69c8,da550741,7352e7a7,92a941d2,10b3f65,f634cdc3,1f42a875) +,S(ac33b339,1bddf66a,6d04c62c,da618bc4,1ad217c9,7d37526a,38d12e28,9fa9dd30,602267b,59fe438f,ac57d14a,8dd3451f,acde0be6,c8984b58,7cfc1b24,34ed9688) +,S(158e2a30,36f71701,2020f476,dd869974,66f157a2,27548e65,688ae79c,3bf8141b,fac16be0,6033e61,d34d1d,1e2c95ca,6109dfa3,64232edc,8f8f62d7,19ce6303) +,S(88384c6,42d1bdcb,af5b472c,2f7a54b2,11ae4947,433d5d35,add21374,33ec4b78,3c3a484d,5b8793ae,203f90bb,476b4d25,773b268a,8e89dfb5,dcb17576,166b3e7c) +,S(21e3c1d6,32299e3b,5da75f6e,7ffa2958,e5d686c2,6322491a,2597dd44,f6973d2,9866fc69,7b9399b7,4307b1ea,e27eda12,590bb138,b22485b9,de6e3cfd,8d23bba6) +,S(abc484c2,6d06ec8,bba4170f,727055de,2611145c,8e4a33ea,56507b60,3477d319,4f92a638,17f6b635,d2d944a6,b9194d40,c4ab7041,2a8ccf05,e2fee038,58d87592) +,S(7a98d6d0,202f4230,a12fe9d2,e321bc55,a3a3b35c,92443731,cc8112f0,579b08fa,bad00e1b,578de9d3,73f0ea77,85502035,c5a04c98,8904923b,f0059a3a,a8ec6285) +,S(282e401f,57ef51d9,f9a10959,d272e0da,e9898f32,d2a3e059,4a65c901,cb1ae10f,6bb8b543,e9461164,a66d55a0,adc51ada,4ac311be,c6625276,5b2c1639,c803037b) +,S(5259a2f8,3dacac1c,18a9a64,d9834c82,e862169c,7a1b9d24,2b521c4a,d7ec4274,196fac52,458c7d1c,3dfae8b8,2ca130ba,99d43a40,8bf41da7,d2e9d040,291f165b) +,S(cbc4fdda,9ed1707b,59db2171,38e9bc1d,eda499c0,78f22c28,4309e184,cf906081,2929df0b,24074d42,75e8a861,8f064466,9ca0dd45,752c7d5c,8cf32661,f8a1ebe8) +,S(96b294a7,ed8d4916,21f10b04,3c2a5ad8,88b92c76,3c93f375,f6d31d99,64b9cef8,f5502e33,f1416c8,77cf06f2,5752998d,a30ed434,365b8239,617ab3e1,65948a96) +,S(287e1f0a,a510c8f6,273362d4,ff8d96f0,dd27113a,b45d0bf0,1af5d5,d24f5038,4b5ddc1d,6c9c4423,1f27ebde,bf4afa29,df337f18,2a2559b0,33de6830,cd7b9e14) +,S(eed0e323,3475ee14,5160d4b7,49210f47,c58d7b26,95dc8036,eae0e6aa,91a545bf,22407aa5,430aa089,3f7218f,2ca23ea0,16eb04b3,3c967e6c,d4c68ad7,16e4378d) +,S(1417cc87,72c932b2,b1116b4d,ab4e86a6,e7d80fc7,b082a6a4,c148c50d,177299a8,66e06245,56f09207,ab2d944d,167590d6,44afa2b7,b598b92b,65706271,d7b50e30) +,S(af6029b8,93c549c7,3544e849,b01ff2d7,b991fb98,2b8a3baa,b9f1b8ed,2b24bc89,dea2973,a97bcb6d,3257121e,9233956d,43ea9155,8105559d,ae17db09,fbc14f2c) +,S(dbb5544d,d28d2510,8a91dfa5,9a3c7538,1b4173c5,eecc8e18,b5065fd8,fa4fa570,4f84feee,755215e9,15abfbb,ff46eb6,9148efbf,39f69261,a9d2a345,3aaf1bd2) +,S(50ee1b42,be9598e6,3fcb0467,18786633,18b550ec,16645f70,869b231b,674a1878,8f4fafc5,fb1e714d,f52c0a10,55016f9f,3ca57c9e,48fca138,68464b8d,70c6b2fe) +,S(77b88613,4bcf9ab7,a1a6e0bc,82137906,d5c24607,a6d4812b,a6d1c8d9,55a5669f,2ffe0de,c5426e8c,92fc247f,a024f1e2,86668e7e,d7a24c33,2c887946,4cbfdfcf) +,S(2bf83837,74a9b9d4,7acfa6cb,6010fd44,620f51c4,e076d5b7,e798edba,21d7fb8c,5f336533,5203a820,a9f75f58,61bf2d0b,fcad07ae,9e297433,79d22b3e,a75f40f7) +,S(207b1218,9a6c2653,69f66738,b2e61d3a,c43cfedc,bd9f94fa,2b883991,ae69e350,c43b15c8,c08b4592,70c887dd,d15cbe95,d627a3e1,4a1c7afe,da2b0c69,549649c2) +,S(5ec76ba9,63dbe3e1,d054ad89,7a00c7af,f60f043,d2472f6,d3369e87,45637cbc,b66d383a,c4ec579b,8350a1b0,b2751fdb,f2ab329f,6ad63cdb,d6d46e35,944009ae) +,S(d010ddeb,3959bd8a,7a7ac178,ca573326,b578e940,b46f5808,12398722,42e13c94,2343d4e2,a380fc9f,617ed8b0,903b722b,a707c53d,a2140021,403ac617,d71fe37) +,S(49157637,c5c47498,5590bdd0,e4a8cdb9,f9bfd422,99812950,9ed25a49,7dad0da4,2564d49e,5c53c818,770c8a36,6e92532b,59fb90ef,e7ff4dba,c6baedc6,b792eefa) +,S(7e39cef2,8285f9ad,1b5ea712,78720954,f4933546,bcd7f9a,b4c7bcc7,54147a9f,6bbe4096,c4c107d1,c361befc,75916c87,6a2a0da5,dde637bf,1f125a21,5408e78c) +,S(45457311,84171f1d,aa931d3c,16b9926,59357877,84a4655c,54822c9c,1685761a,a13710ad,597e7da8,f4b12c17,9afdc5e0,5fc4f05b,e204567,9314149,9c73b421) +,S(c0bbe693,23e256fc,f69f0427,74c59091,287bc0be,82f0b5a5,6ea8f957,6d647d8b,c22981fc,6a015c20,525a0bf7,a9ba8ac6,dab6256d,d763614e,ea250c5f,fb433231) +,S(bb224b39,ff7d27f8,1ba86e92,a6897776,85074fa5,48b5515,987df332,15dca58,73bbcc60,c3adbb94,651cb73b,b311f690,6995d611,8b8238c0,4519de94,1e6bd47a) +,S(94489617,8b4bb641,9cdce312,5d863395,7ea54002,7f759e39,a8846551,ad3a0866,4a16c110,7730cd80,55fb7ddf,93c6deab,e3282da3,8a35d79b,3238e8ee,c8917935) +,S(9ae267ae,a964e8de,68398609,d6351619,4019778b,2341696c,7e44f446,dc8fac38,6d175dce,e589920,851c02cc,3fe3dfee,e9398e53,7742249c,e2745713,fee236c3) +,S(9e237d91,a6ce503a,65dafb47,a9fc5f7f,6dbcf3cb,b026ea73,68403187,d95afd67,64d491e6,df79eadc,74c198f6,fbdc481a,330d030f,851c7fc9,63974047,ddf2d12f) +,S(a5c5e0d4,920f0e3e,6973b71b,90ae2b32,2fa16960,b850eefa,1e516b4c,37252d6c,1aae183c,52ba9f14,f06c57dc,b483ba6f,740d6bfa,7ebb72e8,266895c,e6f6551a) +,S(a6d0cd83,9a198c9f,62bbefc4,b91b696b,57a4f876,6a16fac8,1131a9b1,1b36bc1,97981c96,9f758543,2c810b09,460c07f8,8520e78,3e68529d,7a1d3bbb,e0a86e85) +,S(4a75be64,16d6a87d,49e393c8,a26467b9,4b43887f,a90a25bb,139626e8,58b122b6,ace3e92a,c693f8d4,210932c3,89d4275d,75a46c6f,a9a76358,39c26288,1b8f83ba) +,S(1559a339,7f1e1195,51d8b4c0,fa53b5af,c693ab8f,843e6b00,1a6fc435,5967d7ee,8e450f28,78b2e9ea,829e965f,ae4484be,7e98f39b,a7b0ecaa,b777914b,848f324c) +,S(33565a48,44d9b25c,109eb9f2,9546fd5a,3f30d4a6,157a4e69,6029420a,21f74deb,c8141513,c4e370e2,400b8df6,208e867d,9bcacdd,d87cd975,8f91913,3ba97557) +,S(b49c8814,23db909f,c68c73ee,3995a7db,89e919f2,dc697855,357053a5,7ce26988,65878108,879801bb,ae412aff,72e83051,bb13c415,60499b94,8e0831d3,c2e11fb7) +,S(3a9635b0,b82585d2,37068f72,76291c4f,cd3d211f,80fa7256,58e28dfe,920e3e93,a1711c74,ba4e1a1f,f0a9b6d2,12c8b995,7b6c8c0f,f71da246,154f13f4,719f0713) +,S(ce6dc56e,6f5c496,71a900c1,ae531e3a,a8246877,98044497,fc543013,2572bff8,1af98ef7,3703f8a7,6fc88e9e,c9134aa8,a9e24326,314bf4d8,2a0c85ed,af291f8) +,S(a945a79f,1627e79c,9ce1cc5b,79ad02b7,c07263a9,11f8f78a,ad314049,92bea11f,f41aa315,4049b7c8,c9bef95,f3462336,ccfadf0e,16c1f129,26a5c9e3,7a443bf5) +,S(3debe447,a5f793d4,210e1607,642abdc3,c3a8d446,5a553a45,d73ede0f,20819dae,c0463782,dc5383b4,f7f81557,efddb90d,30138670,858c4197,5a47e6a5,565e339e) +,S(dba32245,a37b5636,9d7120fb,a99880a5,aa590299,601c6cff,d33238a0,395f8d2f,d589ab1f,ff442551,12aa1283,3deb9b43,947059bc,9cb1b32,4d8a29e1,1da82b2e) +,S(9c52bd5d,1fd61e1f,8e75f23f,f6e8baea,a8b7b5e1,5e780870,ea9f8dea,2b75cd56,e6d0a620,c116a7d2,2b2f797c,da7119be,556cd834,caab1007,e9a8ac02,f8945859) +,S(1ec28a0f,24e8910a,85f3c583,415afad6,dc5e10be,cc600749,8cbb40ea,b80fd383,c616ac82,bc6aa8b7,1a3cf89c,b82d7e9d,ddb95761,dd64da13,290f6bd4,a4ff907c) +,S(4fcefc4f,134d223b,994c1274,bd39655,878a35fc,2f50e405,ce11c76,1a6833c6,50c62036,fa49f62f,ab1781da,ec17a13c,4ec82c57,7993fd20,c5c56d70,145c2a54) +,S(85481ce2,90bb32a6,eb0fcfb6,9cb9fdda,580d8808,5b09611d,2d8747f6,ca657e20,ad2f9361,85aea05b,6a0d20db,9b6620ee,ee718c2b,2ae1810,42f6bf1a,2b3a2453) +,S(11aa1424,7760f682,3c11cf4f,12c013f9,7b1c9eaa,5ff0a504,334d2e41,f5daebfe,dda53fb7,b09620c8,fbcdf9b6,605710aa,f807dad5,c7ee4e9f,c7dc9c34,23302646) +,S(908c4f4a,15c58b2c,a0512eb6,b07c67d6,5b08b99c,13d22358,a52bbe24,b3823dc0,5e708db1,d4b37459,e33db06e,21a45fa6,5dd5c959,22ee7b60,7162a77,d89fc674) +,S(d192c334,65630164,2edf01aa,d974fb7d,af13ce8b,2c8975c6,ddde145c,1a2784c9,96bf7877,ced69d6a,a71f0908,86e2dc9c,f6529297,a2f8500d,d683b6a7,ebe4504b) +,S(8fa0f7a1,97138152,75f6c886,245902ef,b6e57515,c28732fe,d49b7f57,c19c6b9b,c09b428a,e54fe6d2,effdb332,4b1fc1e1,11aaf4dc,965b72c5,f97a8a97,18fdb68b) +,S(e53249d5,4d80b59,31d40779,4c550ff5,d6cfc715,13e0f419,4d7b42e0,62e74681,face5c4e,f404cf9a,275846b,11339448,d9133e1b,470489ba,64c190e0,b73735d0) +,S(9a1c943e,7f7178dc,c4453de2,d578c4e6,ab80d538,70c03001,a7a4d5d6,fabca0de,6ae6fb2a,1a7d87c0,99f6eef5,dea6a53b,a296824b,d8ab0848,b44d1216,c2c0789c) +,S(f0d4f862,dd60a74b,e06c9478,1b14b9db,af5847f0,baa00a97,72b61857,bb3d192c,6f48f413,90f9cdb9,edffe12,859b82ff,f8f7b32b,b655f3af,f28175c0,8f1efd8) +,S(1f474fc9,f6ee1699,7a7f37b5,f10f1d02,f2445e12,ae17324e,cd31d2e,c6fb8e1,cbb396e0,4b754b24,3dd587a7,d71eb673,c41b0fb6,329013a6,8ba95dff,c6d0d9c4) +,S(dd871b68,1cf78706,61bd7b4d,1ab259a2,1636cedf,39ac276d,5d36f086,fc9ad4d3,89456fa8,cce6295e,56cd18f5,9d9b83a6,4e4983ca,b55d425d,730726ef,12958dc7) +,S(5223e3b8,3809df92,8db9f4fc,d2b81408,96ed1b89,e6480fe,8a6b815b,bc7a33a5,95b640ed,128da08e,a10148d9,6f53b9ce,e53077e4,64eac3ca,1f604225,75b12182) +,S(65f26a8c,88fed562,12f11676,e2f237d,b4c500e4,a4ee0715,ae2e332d,74c48815,78df921c,545b864d,7ebe6c36,bedd987c,51ac9d73,795b3c8a,2a125d2f,2fb8cbd2) +,S(b62376f4,bd858d69,dc5d2757,b67dfdf7,1d3f770f,e96a0dce,3c61fcad,ed0e2586,c58d5af0,d669832f,4ff38f98,298e9240,c6202343,4e829b0d,145093ac,9ef023f0) +,S(a3297102,6001a6ab,ac0e84c,bfc4c829,4c607d6,c2147833,b1f726,752ddf07,b2c820e9,35502858,eea3b657,c15173fb,d1d45454,3c4fa17a,591a20d1,802d5c65) +,S(3b6e214,94773849,46056d4a,dec9e5c6,86f9873d,76accfa4,b4a377ec,84081339,d7e8ac79,e03d1cd1,7c83ad60,6a140b26,dfe67ed1,254a46e2,9c527cfd,c6afdf96) +,S(ff6aaeab,11cd4c80,ea69c3c,a10f09a4,40b3e51,abf56ee7,2c337414,f3220264,71d8a65d,7a605e01,852f0fcb,1bccfef9,147007f5,7c6b83d0,ef127b0,fe90bdf9) +,S(a0800062,64942e,b9bc70b9,f40bcc7b,52c0d43a,b4d608b4,ff65d73d,75fd4a87,de229122,80c1d66b,364fc250,5b3020dd,1482e43e,c4e67ad2,f2e49ca7,df9659b7) +,S(7c2b8b50,7e2256da,15afa166,84dcb7e7,c437b925,6c042450,6025a551,cafadd5c,747b5b36,e247939,7dd719aa,6ce55c0a,218312b7,26adf84d,eb7e3820,57a0b375) +,S(631c89e9,ee8a3192,c593ef08,baf3fc1e,d30a47e4,6a4ee9b7,e1c6cf5f,d6a0a5e5,8d49bbec,85a5245d,ecf6b084,fc65c697,190f8220,cbb84525,a344263c,ae10e2af) +,S(7ee8cbf4,a0b12cb9,d598835,bcf13fed,72e441e3,bc4b515,4182cf7b,f2818b3c,ea3b208e,70542467,a1e09248,8f34b44c,3821f0dc,169c6037,a7299ecb,25111774) +,S(69c085e5,86fad3f9,7b94d5b4,63b937be,5a95905f,eb33b25e,11ef9e8d,6b5ab3c4,5badd881,779a04f1,3a7333f2,dfcd0fb3,6167d168,b86b6a8,27640559,6e5510c2) +,S(951c09f5,563288a4,e25284a5,a694aebc,1e4b3d45,db0f0ef5,86ce87ed,237aa05f,a0c2704a,fddd2f24,462ac715,cca72894,7de034a9,2c958111,3f55c58d,83911c24) +,S(ba30b632,6ad18aae,6d87a1c4,6af749e4,6d639106,76f25f8a,673d0249,5e813e42,6c174bd6,3def5d0,2ce342b,1d0f895c,ef792f42,a97768b0,d091a92b,14f5192e) +,S(53a1d69b,77ee7d09,f9530860,31e93038,42daf062,c1ec9f19,1328b346,559fea0a,baea6eed,b33605f7,4bdac4e,749650a7,256bf215,737d1081,2c805ed5,298de5b6) +,S(23635f56,f8122da0,91d7e3a0,1125b99,a0f87e98,a717dbe1,f6d9528e,82f9b4ae,1a326517,904ad591,43f0f733,8c98f11c,2ea0fc9b,54e9eeb8,c41e469d,ef0ed297) +,S(c574946f,79574d9a,32c588bb,5cd8fee5,dc60403e,81b11fad,cafc69be,67c0eb67,d2598c1a,8568e4bd,a477d9d9,909b083d,f55a7116,9ccddf5b,666a8b61,96e2f73c) +,S(966bbcbb,4d397eb1,91ea2ecc,871fb24,b0c47469,33df7b03,124408fe,583db143,11741ab6,a38217c,e55bba9f,1c7f41cb,2e69e54a,8a78cf02,60bd3d2b,22789b8f) +,S(6ebbecdf,69e6e137,ad70cfd1,741ed404,4b3620ff,15a07f8a,769edc8f,c1aa1667,2ac87d70,baa106f3,a3490b56,a5960f64,fd80160,d0c14d64,ca1d40c5,f244c57) +,S(815f7f47,8609fee,733b7239,b272afdd,89c2f984,5da8186f,4ee8be2e,2e3e73ce,a972e06b,388be908,86c1e324,e1d2b953,18e99ef3,c0120906,f1508732,f839b930) +,S(24799358,53364be7,4675e3e3,c141e64a,febf3a04,386fa41e,f19696bc,5d3253bb,d6233c69,ec254367,673bedc7,1319641b,f9c029a7,2523f8ba,39dc375a,df245804) +,S(db32eded,dc803ff,d5a1f3e7,8437efbe,8c098fd8,e05f2aaa,c03e0daf,50ba5622,30ceea35,22ba7bbf,2ffe9c1f,bb817fb0,748efb45,65d01eda,9f9cff5c,b5afdad9) +,S(c5fb9cd8,8408cd00,33592de0,e602ad35,74e873be,4442d0bf,fe3bf837,51601689,a604a6eb,85233ccf,ef57fe7f,8a73c430,10e94b8c,4189225b,fe97637f,e7b97935) +,S(7b74932c,71dc26be,429f53eb,efc29905,bdf088a3,f2cf4bb,9828b701,11798163,e07d2133,c628a82e,4a22f58d,710b7d88,892cb999,2f921c28,3772310,c72909ff) +,S(308a025,4f659ac0,7c4e0850,738a2f16,df89ca15,fd64b35f,8f968413,b00b2819,4b4758f4,1eab6491,a8b50fc5,17f7767b,add40ea1,7b1272d4,1b1adf09,5d33c990) +,S(26a78f16,95b595f,63ff1b4c,cd52acca,ae650319,e67554b3,a77f85a3,637fa8ec,3db38db3,ca1e5dec,c73f2192,c4af6ff,66842a38,c76d62c7,c5958fcb,67f38097) +,S(bc440e62,f8524e7b,aef0af7,38e60a61,b213ab6e,713fa9c7,66d28785,891f15ec,175add64,8d472b3f,1547970c,6de2a57b,d2d3833d,2e847810,253b3712,f4d740aa) +,S(f2300d54,ebe04aeb,7a9409c4,3f2bce46,72d9937f,cf7e2a86,c4e8d55a,ef2a4e26,59e0e44b,9e090bfa,5291f436,6a3a5336,a56dbc96,65ae1aeb,e71e8c7d,e2fe77af) +,S(4d34ac85,c64d7d4d,97d40331,3fc19118,ddf31d19,18196594,d2f7a08c,db951c1a,551b6581,e6a1949a,4bbc211f,30fea215,5da8389,a69f6681,96f947e5,f7c8f7f4) +,S(53c3e6f0,fa2795a,adab1a45,a0f30f00,5f0310e,2f989d7f,d1f4504e,d03f2c04,12b382e9,b867a8c8,55461627,b7996676,880784b0,19690280,e709e91d,93048a32) +,S(259b0a65,79eced6b,2dcaa804,ff86122a,24e0d338,165a3013,9ab59f30,343f9ed3,27195af8,5217e109,33e2e1ba,57ebe333,9910c84,9b4e8f6c,af5700bf,93395635) +,S(fe07b39c,f9bd07e7,980b45c2,bd791e14,450eadeb,f6c41206,e73c101d,51093908,a8e47a5e,7a7cd98f,4f5e0afb,b5cccf03,56491271,c85fe0e4,9ae12558,721c66fe) +,S(7f38bd5a,87e2ebd4,526bfa35,5ced4f47,87c404c7,74e7f481,85d40d10,894210a1,4073ed4,cc499ca9,e7f8ff5c,f91f9c4b,782b6e6,f6225edd,d6f69fa8,b0b7fdd2) +,S(8796a424,9a251ecc,c0b3b44a,37edd05b,e34efda1,20926343,3a099e7b,8ae40a82,c02ec680,2860ecd8,f6ac62e2,845e8470,ff60cc55,10bf0179,49f95517,c1dd25d5) +,S(cadcc04b,9d4d8e5,22c153bb,def50fc,941cf94f,bb3b254,61422a4,7e6891b0,4ea1718a,53d64935,ff01f0c3,37ed2b7e,a31f9a15,edbbb60d,bceef362,8a454259) +,S(f2e614fb,346faa61,ec752d79,f9518b1f,e8f535bf,75496cca,513fa961,77f571a,1831227a,b5a35867,82b30fe4,720d2467,68f8c358,8472100e,fea76526,4581fa0) +,S(cb10686b,d361e64e,d82d6aab,5373f62d,b165d3a1,30bc7022,cb3f37ab,d61adff1,d969d37d,9c3db8d4,2c60a24f,44abdf65,b19fc6f7,56a452d6,7ef1b099,613019d2) +,S(6e903855,15042422,cc16d104,962352f0,2e86847c,f816468d,5754c70,fbc6d3cd,cc49058,80b7c15f,6f718ff0,ec2d8544,62e636c4,3e20dbdc,ee318a87,2d52d9fa) +,S(2c0a40ca,38f70b73,ef4da636,185c8260,e50643ff,9b5a83a0,fc0d410f,5526ac12,3f1eda92,8c32cf57,64d768ef,7a6afeb3,89dba8b7,e5bbe5d5,29b50410,5136ab15) +,S(1da89240,4f7ac31,136097f3,ed3055ea,d700aac5,a87ad4c5,49246211,f0ab0d0,e20f1baa,6ca3514e,ed4ceba5,9afe1875,c717597a,b7dd3c37,6d638e,287bd49b) +,S(5113fec4,172e4cf4,4eb27c6e,932e1d93,f16b3ec5,8c791b3c,e22c9bb3,634f76cb,7b129bae,b450023b,ebf81c01,bcd486a9,b494884f,b005b2e9,48eceeae,a6911760) +,S(a8d236b7,bff53a1a,fe23dd5d,63433dd0,a267e05f,31bce172,f80c5d65,c24373c9,698101e4,33e8a6cc,45b07552,7aa4ffae,3714324f,d5da0ff6,4fbc7123,773dde9a) +,S(79b2cfbc,b5a0c79b,d2ba680f,a1b594ef,4b2869da,3baba7b2,81cbf373,9d6f89b6,df45bb38,a21f4838,9e9eec46,f34eb6a9,78967e6c,5d181a92,e989e275,45756aaf) +,S(ba0eca95,4ec16133,1245f4fe,d70b725b,97393053,84fb962b,d1a0a014,cc403bdd,7bb5626d,2ee7d5fb,ad9cb623,7ba48440,26cbc27d,651811f3,92682622,2df76258) +,S(69609368,c01a1920,d3f62310,311cb7d9,cfca4659,1f53fc31,1f0af251,1f99fcc7,73ee24fd,32b08bef,f4254bf4,51614b2b,c0269e59,c6caf25b,bedb4919,76186894) +,S(c0b4d69b,d2344ab6,df9d8427,d480296f,5e0333a6,4a447302,5eac698b,e916f676,817dd44c,49b24aaf,627620c,ff7bb843,a84c7eb3,cc7e77c4,f65ba06a,14abd07a) +,S(80fd0f21,435d42a3,5ba377d4,e2401afc,dec30b21,db770277,fbab9841,3c5d9f9c,502f305a,a3350f4f,50d418d4,9b19768e,4976020d,8e158f2a,6cada628,e79953fe) +,S(7e18fb26,a881189,e3862fe0,9006e1a5,e07aa6b,39a5ef66,4f52547e,1cd7ebcb,dac9006,d99e8a47,d3c5539a,508f3f41,c649d475,4a53fc43,2dace107,1112ca84) +,S(a5b8503e,3f7c067e,628e5f5a,e65a0891,74385de9,69049aaa,26df1906,ed85af56,e9cc7458,fda4c95b,6b502498,95f4bdfa,ad9ed7d,346609ee,6549fa16,6e98dd1d) +,S(d93f866,450f7693,689bc9a4,644b52a9,3d006ced,d284332,4dac7fc0,bc6ff548,94c7526a,14b30b8c,b5a2b33f,c6508dce,fa141bbe,b6aba116,cf3cc169,ca094b08) +,S(424ec330,e4f5dff4,31ce33ed,1ef8293b,b8cdd070,12b5b18a,67b3f4c4,d766bae3,94f29933,fc5ee8a9,27295c4d,8d28b3a3,67c60d6b,13247616,a4dcab96,b58e2dd0) +,S(58805d5b,10cf81e5,b114c372,69dd5dff,cdf7e153,370a8305,bcba9d3b,7ebfe952,15e7b2cc,3ab0ab9e,a36df4bd,ce66bf72,8c45e295,d4a6c94b,e366f86a,ab39df5d) +,S(dab0c80c,a05aa70a,e626f81d,7b85c06f,b418ca69,8067b9fd,83cc6e0d,6a3949e8,4c728c4c,527f9839,498aff2b,91e8a344,aedb11cf,7ab9486c,ab3c7014,3dde8e3) +,S(55b54261,cd493b2d,7dd46f1c,78ad3983,787a37e7,ad8092d8,5cd6a55a,b870e09b,bee36be0,1168a67c,13faf147,6a614b6c,bf7b149b,4600c93e,4ec199e0,9f7fc63a) +,S(ea4f2da7,a5cec770,d986ba06,b1f18ec2,b3907a44,47fa2bef,4c9fbc10,d92afd4e,18f9565a,41583c3b,f7015986,ca7c94c7,4222b81a,9ac26eec,e7954baf,cb470072) +,S(5d835d26,54e489c3,d726f54,bc06ee3f,11390023,fb8d16,61f76b2c,29cfb78e,83091f39,9d1bfaf5,216add5f,dd4d60a3,469aaf82,ca6bf5e4,1070c03f,792dcb2e) +,S(f5efa7d1,484fe717,428e9f54,88c12db1,c775073e,27d028bf,7def8c3f,4f558774,1139d67,793faccc,70c7f48f,c892c314,988d4767,b9d6fa2a,2f2b632f,367453a4) +,S(132950c1,6f24a24f,a907cc59,704692ed,b6a5d254,79dea8d8,38cd71a2,a5d6542,b1e87d14,db8725f4,e2c2522e,c2f3f290,11d664f0,e6e85368,6c142c3,bfefd736) +,S(e479b0c5,478e49b2,c9e211c0,8e610b4c,1f1917fe,5960ba35,9af83c9b,4640d05,66ab2af5,3ffbfca,fdceb064,452c8ab4,b112ed68,8bafed44,1b66ef80,92144364) +,S(41b8288c,19cfecba,562b30e4,93a4c796,dc3adc21,f0c7a9d1,6adf4459,375edc5a,3ae93bec,6f438174,b3956d57,d9dcf29a,d673f6ca,74c96120,c22018dc,fea42398) +,S(56696d31,6d3cb87a,a3eb312e,1cd41768,2d0183f3,b91f605b,c4389d59,d86052e4,5e96c041,e495e90e,2812c09e,81d431c4,eca7274a,2204cb,a3a00a0e,650c6b21) +,S(ea36425,bc35c1f2,f0d96a49,ce4f4446,72848c5b,ec47d7df,6ac5cc30,d3968ebe,b00381cd,a5c19740,a266e63d,d59fea3b,d3d3d3eb,c899bf9b,da8090f8,1eea766b) +,S(84463c57,b01dd5c9,b98e0e4,38e221af,58c0e077,20540b7,da0b4d89,b3c36502,deb3a24f,9a0305e8,812fbaa2,f81e5fea,fd24c375,6a529c3c,c2bf4aa3,8d87b30b) +,S(13a22d5b,d23428f9,912df3be,eb82f4b,411fb39b,1604fa7d,4db63862,293c2310,99a19b77,c6912900,1047d70b,7e84ed80,a8427709,67384cbc,da11a158,6ddfb1db) +,S(de017231,52bdadcd,21b028b,4cee806b,89e98728,f91784d3,a418d7b1,22aaeb57,7ac0a9cf,15ff4a0c,f7d8a0e9,d2fe1469,1a08d526,7e3475a9,381be3bc,64771e65) +,S(1fc63549,9d462327,afc13d0c,eecddb5e,e99bb085,55076d88,7c064e8e,e40396dc,841f309,e47fb335,d2691c43,248a151b,426f1205,ccba170c,7c644615,54258a55) +,S(323e5acb,f821f131,7ff1dddc,822cba0a,b3b2380c,ea2f1b76,903c906d,83491dda,afc25ce3,b13cad24,6f6d9a2f,71e97d1e,e31bd2b5,967a5cc,7ebb1caa,adc7ee) +,S(57b1ec40,5c187317,ff9e70dd,2fd0eca8,cf2b94f0,3d7737ac,dd1468ab,61f56384,247e6f6d,7e2e70ab,a8d50794,36b1f6a0,b27865ac,791d1f08,c334013a,4ed93386) +,S(d6f5f80f,80586e87,5cd322f5,7836327e,225aceb5,6d8a83b1,6cf3bd12,4b581074,e925199,b597c7a0,a179cf34,519ca3a,f35b6d9b,24d76118,ace70f99,f1932979) +,S(2fef6c2f,eaa8c4e7,1cd31179,e0bfaa85,95d26471,fc36be60,1df75cd9,94e73c02,eedc9575,5bbca159,2271bcdf,d9ec8bc3,466e4b77,36d28abd,e6d68ff9,b9820f06) +,S(e488b041,358bf98b,11cd31a7,77a7d93d,e9cb3a61,c49fbafc,4bdabcdd,7b895964,755147d5,ba8f1d44,4ed0eeb3,d072c11d,f448c132,b9e06f4d,66f92ab3,7114a1b5) +,S(ba2591b6,35e7747f,20553589,11e7165e,618b6150,222a70ab,afa66bc9,a931cf35,3c60585,b16b1d07,7bd578f1,85e76bf6,77ff788e,a9b2caee,6c64ef9b,143ef487) +,S(ff4b12b3,cb0ec8d1,750c648d,6ed2695e,a41f8e82,58ba8b16,bf4727ba,6120ccf4,e2cbc52b,f0031efa,74c1fc8d,25466888,41c695d2,393e19e7,287bb34f,afb689ec) +,S(9e42cb1c,aaac0c62,47e4028d,501c84ba,6279b39,dd17424,73c2cd10,9bd36063,c9d0d646,381ca19d,528d2ff2,b04aaefd,9f8095a6,8811f8e3,e85b5ff1,5a5da5f) +,S(610e8f14,eb180ac5,ee435530,812941e3,ed7dad5f,c7bc7924,10f296e2,449fe005,67632a19,b1567d77,b0b5f013,77c6a05e,9261ca50,d010340a,968d8507,877fd4d4) +,S(f4c4230,443f3324,7be7bd5e,5cc12a0,27f0ff23,ede41c44,beacedd0,64789752,55d7b7c6,866f6bfd,29a410e9,8d5d5e21,98719d60,93e2bafa,697a8b5f,734d8bb8) +,S(66221ff,1d344797,1f308b89,a26e993e,c4d1c05,2c2fa436,3729c9aa,8c9dad0d,c0c78a0f,be8ba04a,932a7d6d,604f0fac,4ee01452,fef801d,36d3ca93,c4b7a965) +,S(c3ea4e8d,f8ac15b2,1dd251f9,7ebd19ca,2d91e97e,b13085fa,98294915,6aecfcf3,a7286bd0,3bc8f0bb,a3d28b6f,c513c4d0,472225b7,aab70f62,18c1a735,b31f1547) +,S(762ea616,8b3056b9,da318ef7,53ae0cb4,ff57eb15,8fff58ec,7e4fca2c,b605a49b,195d761e,9caa7603,ff1b5ab9,85d4bdb9,d128ba93,33d6cd94,f00c62f2,9452c8e1) +,S(50cbfa1c,f9a07c2b,42783077,8cae738c,3c3a0d5,617b8c6b,81914720,25712a6a,40a37fbf,97da5646,a653ec25,eeef583e,15cc1db,5bee9ebf,addf9706,cb14e689) +,S(bb8b806c,6798d001,f0d6b31d,1b17cf31,7a5422d4,3a906a79,294e5243,e22ae3ba,46b763df,b7a7a967,75b6b3ac,d21cfa37,a187ab39,99506c99,31623acb,841d4dd3) +,S(5491fa1d,88f0c9f3,6d87e074,331a9a6d,c17a5f63,b1e3326,500a5bba,1f0081d2,6c206f15,7dfb29d0,3b0e5878,57d1abb3,5f18b260,45c58da,87e8c128,7f699a83) +,S(c9d2726f,5ce823a3,ce02ee66,262d0673,f04ee272,dbc16cc0,27068850,cf472435,ff62f77e,60de3ae1,52c7f943,c3eed295,fe6a7aaf,8e6ba0df,bb60a8a2,b6081aef) +,S(a0d934b4,68151a34,cea5ff0b,d002dfb0,ec51df7d,ca5afd35,56acd53e,39515256,2f27f413,ac43711d,fc69e5af,785546f5,8e0da1d0,c9e89271,c8933b21,5998a999) +,S(342b7a8d,a3664884,1d8198dc,5e17b669,f4e602bd,5dfb28f0,95b7751e,4ce8602e,cf36fd4b,24cc36a2,806f8926,db6951a4,4c545076,70ee674e,8e2fefb7,e33f65f0) +,S(1f0993db,1084fdf2,6b2fbcfc,cf0c8a24,124c2474,92acbcb9,6221b788,18542b87,fbf92437,f6feeffa,4e04267a,c8dc57d0,c6d521b0,2631c20f,876fd9f8,b00793a8) +,S(f8f4034b,d7fcc9b4,256433c0,c2b40f9b,2f45a117,3a371707,f6ebec47,e456d9aa,cd895dbe,d97ab95c,b3c98512,c46a538f,385b9b26,5438f7f9,8caa245c,c680f54c) +,S(c80f3bbe,d409d5a8,cc0502ec,d7d95d8b,69067e61,fd2e8f7d,45f06ba6,7db89a33,dc803aae,6b936dc7,27773f6e,17c5d2d,af87a1f9,464320c5,4fd0cdd6,d7ef5c1a) +,S(b19fd3c7,8ee32a3e,dba4d6db,bb1464b8,5b3a5865,7f0c06f8,31af5b39,de2b436e,242c72a1,91f17614,8ee25c12,e0f8d4ad,52837a48,9b94b16c,27c8053,43c8e523) +,S(c88c52f8,a658160c,b10614bf,c744f668,ac46b774,94592a1b,99562a6e,e6482099,5a2f3a43,bfa6873e,7a198ad5,4fc0e3cb,2047f268,6396231a,a158a5eb,f4aa3170) +,S(b5f02d99,8f8f1c5a,8c8995b0,6879c804,1dca6f17,3666613c,efdbb82,820164e0,8e39ef2,207f5d31,2e36ce55,3569d2d7,2204a9f2,500ccff8,50bb67d0,a0802585) +,S(4d4e728b,5da0713c,18fdde5b,290d24ae,f7150d42,f9e5625e,f05bd17b,124f8302,be413caa,b7c77064,91110243,a20545f,8f9e5357,49ce98d5,cdb41384,5471bb5c) +,S(92832d03,32f7ebae,b67701ca,a0a2bfc2,b36b6403,742f4ff5,ff2ae46c,242dd226,cacf8955,92bc2fd2,90dc5b5f,b4185159,3e4a6a0,709a51f7,32e8c554,7cdc4114) +,S(2807a982,b4fc3fc0,8908fc5e,b3734a83,b2e2035d,8c6e3036,b16f9ac2,f4bba58a,ddbb9f8,3a9a6ae0,9945ebfa,9cb7e7a8,49798032,8545379,df582f93,72cea69e) +,S(e755ddd9,139cc4fc,b266477d,645b4efb,b02088da,752d10af,aee5ff8a,45df9659,fa7daf3d,605846c6,35e2534d,746873ab,cd502ee4,27e62c45,ef66401b,c816beae) +,S(93c33dc5,152a9bf8,31c3cf7e,ea833ca0,485f852d,52a255f3,55d7e67a,c1964f63,4a3a36df,13c8cde5,48feb589,dc56eb16,9a874272,c7a0becd,d40554db,cf4d8f63) +,S(70d66e2c,8f934356,d6720d9b,4809b984,6c7ab1c4,f8604990,d2e559b,a59c24c,24e8b668,4ee0062d,7bd79b3a,c96e0316,dcbffe2c,973ff6bf,e99590fa,192603e8) +,S(c165111e,fc2d7105,f6bde2aa,7f682287,2d803fa2,ec904380,27195cc,147904d2,c71184de,f408b79f,32086d4b,2b0e5d95,aed6e0e0,eb99bfb2,7e917abb,8d3a5e74) +,S(12144a63,67cc355e,e75486,357b0c79,ff4fe703,57a2f89f,3e3f7e20,ef860204,f2bb05e6,e55171c,c839fdb1,2b49ba11,dfd53af1,7a5a9602,4327f93,940b8491) +,S(3179dfa8,bd134725,3988033e,70f806de,fde9c6c7,aa4a6d43,a5cf110d,6fda7828,3133a35a,ffd1f24f,579fb314,2e72590e,475e931e,8766d462,842972cd,70e49344) +,S(51fe3e70,e5f21b21,1cae97a9,d0fa49bd,166dac17,5087ac3,a93219bf,d17ee77f,f3309396,5677c691,2a987cc1,5b3f016a,4efc22c7,6f89f562,4830f09,a9fc9bd1) +,S(2d7c98c,a224ebd2,a5167017,88018bf2,1f29444b,6eeead79,dfd9e503,7fe1680e,abae552b,bbeb09d9,dc82af6a,eea16d50,613c9314,be23eb79,d254a16c,decdc02a) +,S(c356823a,37dc335a,918a5553,bb0dfb9c,704ba647,d6cef22c,1e71bc9b,dedaa333,d8715c0c,a0ebf8be,d79ea3d0,85a70d2b,b40efecf,7dded60e,13d0577,cc235e3d) +,S(91af0d4a,56a75616,e9cb1351,4ca27ef1,b7411d9e,5991be14,c1658450,71a2b3f,f6c845a8,76657a63,ed37bd33,46ca60ef,a8fd151c,24a9e35c,5893f969,2580e26) +,S(6a32ae36,93ee1e7b,77fe8418,7266e6c5,cb41c7a7,37351cea,987a4f80,a26cbe00,2816504,dc3efca2,67e4bba2,5d4c9dbb,e8622e99,4a712503,37320925,ed5f64db) +,S(5851d327,5e18fb4d,79292e6e,2bd6bf29,b6301e08,7b418ac1,43afdf70,7d880901,1e17a9c3,dfa8c3e6,c1e9c34a,785321a6,e58d8024,c61cd02a,8b83ad41,a2366211) +,S(233a98a8,9fec3399,f74d99cd,7d5d4894,1be8274d,8f7ecfa1,f4f3693a,fb26a654,e9d5a9ee,fa5e6cbf,9ffe590,bd7db1fb,b9e08125,93f42238,65298e9,eb42d7fd) +,S(8751bf4a,9676e2f9,5036c3ea,97749d8f,f452f67,cd1259c8,4c39e8de,9cf796c9,4f883d63,bfb0a01b,e26b31b,53ed8755,49ed6c1e,4b67a160,7fb68be1,7b845711) +,S(a21126cf,7330697d,714be16f,27986c9d,cca4a0f0,3a12b6a,d54ef31e,d7a3dc23,3b0e984f,565d9825,2c523913,d2d90a26,b47973a4,8d8669f6,8dcb4c62,399b9777) +,S(8123c441,96d17ce1,c6c1a9d6,2aaecfb4,cdde74b9,317599ea,450e62f1,5639c3e4,406c585b,c9aee3ea,dedc117e,d58b1c3f,db5846cb,6eb11592,469bf958,6872b068) +,S(6f8e1a45,c18ebfce,2e2f710,efbd7ffb,4f107a32,fa6a46a4,caaf8ee2,37a22805,b36a7c4d,712315f9,a89b5ac2,8d1a5d55,5ead81,d7c43b8,8155eee2,b3ba8d3b) +,S(51db2e94,7e75c9d5,4ea07ea3,35942071,5987090d,b81c3b99,40b85684,2b0f0bcf,70967acd,454e6ce8,ad015f45,e0578940,c95dd818,70268d0b,9782a595,9a1462d4) +,S(84e0b0fd,b16e03c2,cae53675,4eb3452c,86ef07a1,ba278abc,d5aeed37,f71a3151,5a8e435b,53a4b51e,2ea659b7,1f3371ea,dfb28579,8b062eda,300664b6,d3b204ed) +,S(ced68408,c2b01401,fc039059,5140ab68,14142b7e,d69a64bb,e6ec5d85,be833367,76ce2478,28d2581f,6779f723,327fa83c,8cb10451,fc34625b,d069885,3cfad07c) +,S(8d860f70,a32921af,6376c310,bf5093e0,572e9b3,44e9204d,f5487554,c4f5484c,6dd24078,cb9f8ea0,eeaa4f4,3f3cf99c,890966c,5da8fe0f,9cd70128,88907cfa) +,S(6223ee77,4e56b9e3,da6e008a,eb3ba06a,40bafa1e,84383ff5,65f98286,d9095d37,ebcec7ec,f750cde,9ff7972d,172340c3,c324d843,f31db269,c3f35a62,c5f15f36) +,S(326943a5,5e7b7ca6,951a78dd,afd00e10,c8ca7f6f,3c01a038,ffc4fc7a,20fe2c63,b3bc5a8b,c87ba023,ee22bb4d,3f92cd81,787f2af2,4ecaebe2,67fe0a86,21c5d201) +,S(f69b5d4a,eb0b550f,851f601c,92698789,f9f94821,47a0ade8,c8a19fe0,5742731f,2a74e8bd,94469645,c8a328b4,24975dc4,93adc83e,4baddba,6c41e10,3b58e90c) +,S(f69a5a88,b8f13bef,a987194d,6b00a79b,7e576749,3d180fe0,32a1868a,26d853ba,6eb589cc,9c51900e,a6d99110,206f60dd,cbdc368f,5ae8dd48,cea05218,3415cbfa) +,S(c00ffc9d,8a57cfcf,9624a812,dd2181f7,195f459c,3b858a19,864393bb,1d1a269e,3097e10a,d6abfc0a,3fa039fe,952034e7,6bda4fc5,c5614092,b124ee3b,bf55f87a) +,S(9c021c49,d6671103,cfddcc3d,8e54848a,addfefa1,d6de5455,e5bda021,126dd183,4fa1ad18,81362f4f,f0587b52,a7a1b483,2d14127,434ffc4,c5bb90e4,fce50834) +,S(59aae0a2,923bc36a,1a5bc8cb,ea5bbbc8,b34f1504,4671a046,eb3090ed,3f4b2345,659f89e0,faa1577e,36175240,2cf1736,a18b070e,4d4b0fae,9ed08297,362cb246) +,S(7ba1ee89,479254b1,f32e9e53,517f0961,79d17d81,3ab3666a,75d4bf7a,7113f252,6530b40b,7e66a084,97168778,61cffd96,5eb71e62,e8b0ad7a,7d2851aa,15a26dd8) +,S(4b0e5728,cef356a5,c6d08616,47c268b4,c8a12d8e,89c2da7b,78e9db87,7b606719,235ec085,a1f3651,11b5f03d,7237dcf3,d70e851a,6dab8446,10e45fa,2996e70b) +,S(54285c70,315d9a43,a040bd05,70c35713,68504efb,fd103098,79067d6e,765d4499,de233654,e7c05b5e,f144d25c,6d539157,51e83ce,7f88dedb,7fbef11f,d6acadb6) +,S(ae15f764,d20e4eba,b95c3463,402a2159,fcd21daf,fa831b3c,e47bec08,9bd43da8,474c4cb8,afeba9e9,3f1d0a2d,28911298,939328e,5e364d44,68c64cf4,fec2eb78) +,S(6de8743a,68c42b81,ad069f2b,fc1482c0,204640f7,74515924,441ebd9c,917e3974,7ed602bc,16300648,86ed0369,21936ee,aa5e9764,ffc294e0,bcded12b,bcc86f55) +,S(7e4951,dfae38e6,f9869fd9,6d058847,2a38b0f8,827052f8,46195e21,44213a47,6fa2e60,a3883383,f8efebc,f39329a3,b7aec31,2958510a,dbdd5a72,728035be) +,S(1f7eb5f4,47d53537,3d29770d,5d7ed36c,a2d2a4a5,550d8bc1,849382fe,3847df55,5a351374,da5a804e,3b995d43,49560f7b,aa417dab,936860c5,baa252cd,1753f25f) +,S(dcc1272e,b31560ec,64a4b53d,24727bde,da576493,b571b5b0,aa7bb3ad,e8b2dfb6,567e08e7,bde60e6d,a614f321,a9cdba4,1b860f41,387b3854,603a8740,f93039b2) +,S(3f4e219f,5014414a,3c757cd,28120043,3cc199b,fa843c40,b344b32b,87dc7e7d,dba2099d,839e9c1e,7d7d4c0c,9444e956,168e2bc,4df1dc52,bb5b4da6,3a8283f3) +,S(dac6f264,74fee94e,dfbe9de,cb2fb88e,272ff622,4d7f8b86,3076337d,6d37acec,1bfc6855,5af0f07a,c9329ed7,5549560e,8d3e0c67,753d2673,eb6706b5,27a0de10) +,S(82ac1fb6,5a975de1,4bbd5709,9e2574d5,ebf883c7,7f38a7c6,1408dd3d,5e49b33f,a6d9dde8,b43656b7,9ab5d880,f3af2ca8,b70da7dc,251a7299,cb236b1d,75276c56) +,S(19a59ade,a0da1340,36a533b8,ff202a58,55b9182f,b19e8b79,caea80b0,9e263706,58030bb4,b17da5b,1879a67a,12c1d929,88cee2a5,d8915528,26456762,9a99f256) +,S(27e8a699,eca192b6,7a66b1be,5b290e37,1ff8e912,5afef253,134af2c6,ae709ead,54ae6059,58d036ec,959d789a,5316c70,a09db19b,179e5d4f,effbb057,abd87eeb) +,S(25e6cdbe,5d7e37ea,fe2b51f1,95cac707,a2aaa70,57fd5e78,8fc926cf,76e65466,576b2c22,cb6ba6bd,6acf0eae,79b52ee4,1fdebde,25293347,d624973f,e9b66be1) +,S(a0114d87,cc03bfbf,97e96821,2b69c53f,12910c87,e87e7a79,109f83c1,7042dbb0,869c33a4,cec89d65,633bbe60,a3cf7b70,1e5c83eb,e7c229ea,a4c279a0,4203a9f9) +,S(e8017e4e,806557e4,61ea997,f5f46e72,9fb668d1,e8faacc3,5804c35b,6d5cbad3,eca21b4c,294ed18d,d0df0dbb,771b8bd1,659c2eae,2c843f8b,bfd3aad,f44a4070) +,S(948209cc,528dc6d6,a406c996,7d7c191,19ab5142,679ac9ba,afc5098d,4d7c83e,3cc37cf5,1aecaa1d,ef14a2bd,cb6a1084,f3e60da0,9fdc4fb0,9d9f9fa5,84f14b25) +,S(10f4d6e1,c141dc53,fecfbdb0,b39e3e8a,c7f5279b,dc231fdb,55b25551,df90fca0,4f5e59b0,9c6daad5,80adde67,1583af4d,fae40d52,6017d5b2,9e798bca,6917e735) +,S(66361888,5d081bf3,9e9fc4bf,a0922dbf,dbbe8eae,451c199f,9aa844f0,71a327e4,f31b98f6,48940706,13a086df,12416779,a5c16ad3,7cf885d,5f1fdb37,1be94cce) +,S(6afc24bb,ae6cbfca,b34fd467,f23a31a4,4a0a35f6,203dd7b,a881ee5f,f340db5,7ab76f2f,6bada7ac,1e01c930,90c741fd,90c41fa6,943aa804,ff960b17,3ab28cf8) +,S(3551d572,2eff7d0b,275e310,d1466a70,2b828d8c,fec039aa,ce629aa1,2a9c23a6,b58af71e,1f9a6cce,c48d1fd1,18902a21,7f1e7f35,3ee9d794,8133d41e,2d2d61eb) +,S(e6e8cceb,f6096fcb,8f21cd9e,d428260d,c3867e0d,9c4cacc8,b8900fff,7bd4c1aa,d1b12068,f85e64f,7c9de5ca,f1490bd8,6dabf18b,4b78b5ef,531d9bd4,f64f13a8) +,S(5cd74a22,d46e7769,15b3c84a,492fad11,8790534e,dd8d9bb1,e117a6a4,78f566cf,397b2429,f978404f,ec96a4b5,28db5a,1b0cf9ef,61f2fc7d,470f0554,eed5ee08) +,S(abeeb656,151fc7a0,fdfca1ae,fef91a7,ae156db7,c433178f,be6fd700,991e8b86,e2a10216,3a8bdd0e,8254f459,b573d182,eb55f2b4,969a3f80,267b060,9f208a8c) +,S(3f9702ac,3b96bd4,ac9412cc,8f40d5c,99f4d7b9,d211bd2b,18c6f96a,ebd2f958,e077e28d,8f171626,9488fa5b,67a54800,b0d5a519,4384ca56,f9836b87,68e9821a) +,S(3c8e54a0,d094d63d,60aecab8,675349e9,f229995,587cefde,eaa1f50,cf3032ac,e77aa94a,fd252860,3bff0189,f11d5f93,fb26fe86,dec719b2,f8bbeda1,3cf38ba8) +,S(8e88168f,41689167,ead8ca79,5ef784c9,8e3cdc41,43a0ff8f,2891d476,98387bee,fb4bf21f,343fc6eb,ca6fe337,ccb7a7a6,899bb29f,d2f60480,ffb0a187,e875b00e) +,S(d5c7df6f,31001177,f2e88aa5,43276617,7a598335,cf6ad98a,e55a6d66,1b75c1ec,2edb20b5,47b7c233,23d5c4e3,295921d9,9d98854,e780f4c1,e756021d,79f1b035) +,S(262b9c58,75087b02,490291f3,963160c,c1f5a3a0,fd6a905c,25c98bb9,f7268514,c7e4ec06,b4cc77a4,ee551a5f,6c90ea97,4a0b2193,f1b828c,305a0fc1,b22e5b81) +,S(cc94ea5b,a4fdaa06,93976b76,893dbd92,f602bcce,822ff271,7a13bc2d,6b31e7b1,c81c01ad,f2ff92f,5c2cc42,f3c30091,11e6901d,36c9af9f,9b408df5,c7460932) +,S(b21abb23,4c435197,5b73471e,3b2eebe2,f537b95d,1b19361d,31ca4e63,336b0066,db02da36,73e62e9d,e96e1bc7,b79ef4ed,49449c29,7f4f0330,227dabdd,5b4c3d9e) +,S(ed130512,5af211bb,28118dc7,fc22b8e,8bc2554a,a19a8c7,16f69f11,a03df1dc,fa146b3c,2e0eab2,bba69407,9ee3b6f4,2f64dab3,9c19a1a4,256283f5,bc0886ec) +,S(42b829a,96989e82,37e48200,20eca1d9,61e487d,a9c6f9ee,60586dad,8fcd0e83,c2e164f0,29b6cab0,14fe76ad,82ee7372,78124cf6,5f251c9c,c260e239,50ec4014) +,S(15f09133,fe57a223,e2c9ad79,dadbbc7d,ec85df2c,6af39fd4,a156eb0b,1602a13c,563206ac,b190bc2f,c7b24d2e,ff376cb8,64102efa,12f7be73,84898cc8,76a12b4f) +,S(b8446387,4262c03e,312eb0cb,e562f460,8cd4f65a,75b099d0,b45e0de7,8398f5bd,da730acf,79fa0282,a3a29b99,7a0ea45,ba0896e7,598be8fb,8298aaa6,9b94640d) +,S(6a926c00,ef4c32f2,52d9f336,29fc708b,e21f571f,1f320ae8,6e6c46b8,9511fb95,9106e0c8,2eb9fa36,4a84a2e8,8eadc9aa,9113927d,99adeb61,a2ac5527,5de9a9ba) +,S(fd6cbc21,9ec03dff,8f3d00e6,9de0c64d,30ca5a04,1556d0d5,87339b0a,925d064,742ce8ed,a4b47eeb,29883606,211c453f,fc15ae40,174e1c74,656a78ee,f3a85e8e) +,S(6fd7f1b7,61116218,68e1038f,d5f341,c43b61bc,b6ec53c2,8d84b321,ac664274,f681256b,947a9492,5b8402e4,26ef8d53,20c65a29,3a7758de,6b7e3f45,a9d635d) +,S(c28c2cff,1e418550,f73fb839,58c1ca6d,4c616c3,74a67978,d4dd71c1,99902ac5,537d774,83b1ca9,50174ee,381023de,cc210f91,3a66615c,b242829e,e3285285) +,S(89458f8b,7db2cd74,346b8b74,759088,fbf81591,5fa1e97a,3f34ff90,908cb183,9b5b21fa,378f50f,dff2e276,353179a,c0a6e43b,13373940,c2e73e20,106742bd) +,S(e66ed94e,793b894,552b3893,88a657d8,55ccbb2d,f9ae0061,2cc07244,bfd434a3,8a6a17f5,da95e907,7b03192b,eba324a3,5595b6d0,660851a4,7f9e2259,2f093275) +,S(8c7e4ce,f5dca16e,620d6690,ce3b9337,8000ca08,e73eac21,deb5deae,83359160,29a44639,f9a6b8ef,990b72c1,5ca6f539,31000a2f,394b59c9,36542992,7959c505) +,S(a0d1611a,807750a2,45c68132,2f7adab1,9b81de3,809a9a82,ac038294,b732bdb,c6e35357,246fec0b,ed0c5491,24f13f9a,a01fe39d,e7630357,110a5878,90d9bf95) +,S(c1cc130c,474f5ebf,e4b4e26e,a444d5d,7542609a,2bc65a68,9c6453f7,9dcf6ab5,deaba85c,f0f7f9fa,cac2415d,9f82c62e,9caf457e,fc9149fb,55bd8f2c,32f74ea7) +,S(d6dd2a36,763b77e6,259f1305,43c8262b,784a268e,45adcd26,efbd6d54,afeabd68,2987d048,9549cdd4,c27222a1,9562b005,56dac521,1e67d052,e76266bf,fbab179e) +,S(885cf8e4,ee0498f,29a7f3b6,a2420629,4a941f56,f3d852e1,4641a604,9415c49d,b1002bf3,e34ce44d,54a18be5,3737d98b,28ad0f7f,31d9bc37,ce31279c,fc039b2e) +,S(8f0c57d0,3d85979d,5bec7346,1f0a3b7d,540fd0c3,8d8a6775,fde2ca35,ec8a0d91,86a3f4a2,cc4f934a,8b833cfb,dbb96eaf,159e00ee,caa0871b,235e4f8f,97bf542f) +,S(53456583,d2f4d9fe,1a13883b,7775b363,3993c9ce,6bca547f,d05021a2,d36cd366,92cec0bd,cd83312c,455690fd,d715e41e,c29cc70d,f5eb2e17,7f0b2caa,f3b5214b) +,S(a5ac3a28,fad5cda9,200bef2c,454b73ee,bbc853a3,e8b2ff77,111ea25e,5f3b5359,4951843f,6e23b9ba,60f326b5,d6b13f1f,f49e8b3d,b399be4e,46cb3ab5,7ef10bec) +,S(2ec53b3e,6d91835e,d236898f,8857a64c,4d898098,9af6ba60,392b774,6eb99ad,e21f4abb,cc05952,eec3fe34,f02d64c7,e7a91658,b0b11b14,118c3489,7bb2a2ee) +,S(5863f940,a45c8f5e,a2361500,84c588b8,a7f99d26,84121d59,9073d38a,69494c38,db422c38,41a2bb32,98390c98,e9f4c23c,da27c64e,a5481870,b33a2bc,866852d4) +,S(3492772e,d177b4a2,5f9eed03,7094c52b,aa72dee7,1c5b315b,70948dcf,a1975a64,c5a26844,26418929,b5bd1488,49b3241b,d0eb5243,61106911,1fc32cdb,29087562) +,S(4405762c,ba4f63b4,2401ce63,120c3599,af37ac13,d2de044d,26d830,9e664a4b,3143da5a,8319bf4d,32941d58,e9bda807,74c58380,ad8c3a33,460bfd85,36d9baa2) +,S(4894f457,1324691,8f32111,e1bd94e8,a43f717d,74e8c465,550e864b,9ae2a16e,9c89818e,6f09fdc5,b36c65f7,12f26be6,40598712,fefda799,4b200967,7de01ea) +,S(620abc9d,4efdc1a,55edc41f,29834528,ca87b333,a8678e8c,205d6817,cb7ec3cc,f524cc99,9e911d67,dd0e8bd4,3e003ec1,64af288f,3135a602,4e93856f,8110f867) +,S(d69800fb,9fe61ca8,97f77226,d42749b,1274176e,29bb85a6,226f91e1,e8c62a7b,43baaafa,e10649d3,ff2bb0cf,10c58f8a,f01fd3f4,1a06c245,a4e9c483,8bc9e3f9) +,S(87a12e5e,d002cacf,f55901c0,d374f81c,ab9da24b,80e1fa9b,25f038c9,38344721,36586bc,17aaf4d2,5d02ae3e,e9f98235,f9d605fc,1954be4a,dbbcb917,1f736d72) +,S(a0af0d5c,bfdf4fa8,98a3ea89,867721d6,3178341b,ba30f091,946c72af,bb876624,100f795b,18dd85c0,9af012b2,5d7d5d1d,5118d02d,3837fabc,ceab0b23,99f98e43) +,S(ac94b41,7becf857,1248a94b,a853f4f9,dd47284,157e0b9b,1756c4ca,fb692086,cf94bf3d,d0c7f89f,acf8f678,5508e510,faf27a33,10915d99,80b9fcd9,62f75c92) +,S(649654d2,966fb2df,b917367,e2ea4034,fe886725,3711bc40,8520d5d,579a3481,bf8ac886,a7550c40,29279fe1,c4d330d0,89935427,d6967412,66d79ec1,f1a2780a) +,S(5f7776ad,e73826a7,fd2969a6,1511141f,cbf6fb11,23c8d7e4,3ff93835,ee1860c1,9faebe0,2140468d,4564f7c8,bfe4f097,dd0ba493,8656fb43,ea9f0f8d,22089e5b) +,S(f5dfe7be,f4c42f3c,e91fea18,10402c5a,9072b001,286a7371,35a00fd5,c71e2f17,9787d33f,821a0633,ab1982a4,f9240b53,38a5644a,4d203b1c,6b5cb212,3c837b4e) +,S(d3432817,3f33fa7,e517d6f0,408bfcb4,6a882c0a,6d78feb7,44f731e7,4e1bed23,bc1e6ff7,cbdaca91,edd419f2,e80e617c,506bf8d,8acd4548,8267938b,813a281) +,S(a4420846,95528dde,2c52d5ec,cd67266e,3024865a,c6e812e5,1ef4f780,505f9d2c,4a721caa,63d62b9a,c23ac717,7a27e27d,d54e5ff8,aa204bf7,3e6b3131,3ccc31ac) +,S(b3818c70,ea29c1bf,db63ba44,1e42c842,11f9d2e,4d6b07cc,79938d3b,b294b820,1b2c711,a98418b8,15abf79,44fa75b7,db8965c3,1779d4e6,1967f009,8c005d2a) +,S(3854b55b,def18a47,7e87f62e,d7607c6d,aa2e737d,e0e5015d,de7e90e4,570d43b0,2865de79,552c68ce,4841ad3a,69376a36,9d74d55a,98c35d25,f97656a2,fa22785b) +,S(e2e805af,78bf592,6a37fac8,7429f6ad,88c45522,e58e5c9,2bd2ddcb,e893ff33,c2206185,254ef80d,fcc7365f,1dee9a3a,cdac0ebc,d0ce6a5d,4c9a6875,f07a46f6) +,S(37510b86,df2d8e60,10d40e34,77af6c24,47f2a41a,fa35ed49,224bee62,eb0b77c1,1f30b802,6a3288d9,714b33b3,7a09cf20,cb754f09,730888d2,a09869ac,1e905ff9) +,S(14b2bcad,c5272c56,8930c574,d745fac7,d190558c,121df6e0,c2c9cc1a,f9662fcf,baaf56ed,f70fc0b6,520bea13,a8794d2,d397e935,65841028,6dafdc16,96caaf3b) +,S(2984937c,e3d6a155,7a185609,9e44bfb7,28dc6d0c,bd8c628a,23a383ca,3f38082a,637c5e4,9b0943d8,e09960fd,2375770c,5d4dc4b1,3ea460df,d5ba49ab,fd6339c0) +,S(e64f46da,d9b9e7ee,3d2878b2,f604728b,8203a591,d02e7d23,721fc436,165918c0,f7ec0e4c,9f66adf9,98b8e41a,d43fe3e4,7cb9be23,6356ef3,ef5b9a23,711e1140) +,S(3f587c9f,1b88ca37,d32af584,e510609e,ae113e54,8d07fbb9,a34f6916,908f686e,37712f53,41485518,241835aa,d31c45b6,f5370c6b,238380a4,ddbd0755,17b2b49e) +,S(8218250d,b1ee7484,b8892bdd,53be130b,4b5d3db4,7c3c9e36,5a17baac,5d8654a1,f19955f2,a7f954b9,2050c815,8e801222,8e77405f,c9f0676e,76ec2e4a,f3b93bf) +,S(5ad1a4a2,55a22c56,e8d17acf,786356f1,7ffd6453,262980f7,188879be,9e1eaac5,fec5d2b7,ac26e4f2,d4d7af01,b49295c3,3a969fd5,28e3aeb3,90e86bf9,85093dc4) +,S(1c92ee58,c5226166,c313b491,5c731d34,739068b8,f0241dde,6f0d7151,243304c6,5dff29a6,1197aab4,c1ac8a25,625c4dc1,11729680,15f03488,b8a4baaa,d541bcdc) +,S(fe622f9b,fd9c4ba8,8c80c82d,d1a07bac,c1c9da11,996240cd,50b6a41,f6f8fdc3,666e59ff,e9efb9a9,b7c36539,ac948438,f1de235b,fbed8fe7,3a084076,39f6b901) +,S(b2e8301d,ee34bbc1,d95de73f,b947bbd0,325bb3a5,555738a2,8fbe4e3,601a40d,6953963d,3496413c,53ef500,6def0fda,607d9a9a,319cb93e,22d9bfd,a0c3b807) +,S(1505e140,4644537b,56da7114,5efd34d1,566ee38f,dd4b549a,34ff312d,5cb9bb96,d6440284,c1ba972b,413f8c12,7fc40001,39954fd2,5ee4993b,4dcd5e3d,a2b843a6) +,S(7a524409,67918e47,53b451e5,243c6996,c053fce6,1f492995,8d2bb84,9fd1088d,e089d973,19788a2e,853a3067,c4a98c59,4fce75cc,a9ba908f,37780e1e,567b7284) +,S(69eff8da,8efa75c2,ab052d71,e898a975,c58a074f,c46fc6b3,2b385e41,93ff5a30,30e873ca,f0e7d1d,e58713db,cf7c5c9,6c9f068f,e0e3d1d6,c3863d44,8da1cca4) +,S(64a5649f,2da4eb15,1be3fb68,b1210cca,61b32492,60225ef5,53426992,95e6d6ec,8c53c12e,8fbd7c,811d4a85,95787105,4719c5fc,368845a1,6b8babba,1d92f56f) +,S(ca23d56f,46ce3458,d95a5b24,d998188c,3ed76a22,2034b337,933c4298,8c804fdb,efcbc7c7,d0d11fd3,ef1c0ac1,38d1a2bf,d0e94a85,a0700cb3,630dcaa,426a4c43) +,S(630b2d2e,62bf28a2,ebf80f2c,2bb10cc,82014ee0,c48e15a6,4cd691db,dfe8a55,908eba92,e889f132,4da0f927,9c1bfb74,dcf16786,c9c8a964,79757a79,d4443e9e) +,S(29b5c3d2,57674ebb,1cab5fd0,56534261,5a059eae,c8002aac,c000a857,a7b7c840,e7724381,f3f1cd4d,198a06aa,33b7fb9a,d6acdd57,45f900d7,be34fd6d,4f6dd41) +,S(f4b9c47a,2454985f,e732c151,3216f7aa,f5de769,89344c0a,4b8b46fa,c15508db,9c51095a,c45d901a,75229288,fe5d49c1,1dbab43b,9a030cc7,c6d71bf8,9d097378) +,S(af0dbf55,79f3f1f,91847143,99a09fff,75c8922b,48213c42,1cb17d11,2ab7ac71,56e7f5fe,e96e464d,50cf98b2,90a04917,430bc2c6,72a411a0,842149,8fe23d66) +,S(7ddbb2fb,f5d68e,6acf574f,1fba12e8,323e06d0,b6b80cb,1b9e9368,5543a8e9,888670aa,f057a051,1738d69d,162ac2f4,9074e5ae,d28cd6a3,a30edf9e,e874d7ed) +,S(43612257,2c25dce0,4a0273a8,a83890da,3a27848b,103d5ee9,1f0bb33f,ddf131c8,62cf1a80,7bdfeaf7,7b9d90bb,ec403b7a,b4261e04,62a16c58,5c9e1435,afb177d3) +,S(8691a20c,6df3b947,e173735b,d764ce9a,4a7773b4,4b4276a,873786a8,8e5b0932,974ca0c,6644983f,e4288afa,a80c03de,fa8d9215,c148a63f,1a1d4aef,365d9e81) +,S(7376518a,528c1190,b95cfdb,ef241485,c84f34d9,3690041a,e4d8b0db,295fe87,fcd56fa1,3d5cbebc,ea197636,ad3e7bb,f9faf472,56d44489,e7cbad3b,ca9e01e) +,S(9c5e491d,838b7471,87eeff8,f44ebd70,d6087ba7,fa2b957,8302e46a,3e5113ed,3e312d47,a32d61ee,f88dcb4d,aa38b024,7327ba59,cd377798,75bcd10c,2aa13278) +,S(884a9710,9e6e95f9,9a52d8a3,7b91480,d33a95e2,4f385ecb,d9666bc7,ddad4c63,f39408bf,4f27f2f4,ef65b195,b231edc6,c50aca83,60d23ff3,32b1c3e7,149e8d6a) +,S(f99760ec,771c8f39,d349fa7d,19b0ff65,bfd2ebbb,f2d4707,eff2d646,4beca7fd,d71a5750,a9737ff1,bdd2fbbb,9674905,5508c2eb,ad22aee3,6aff09f0,1fc9d996) +,S(f2cbe279,98214502,77f79ae5,22da1671,452c8e94,27562e3e,5d78fc17,9e758e2f,8334d592,9b50b714,a50ead97,6fcd8b12,f9806edc,5da45d8a,a226e029,282ab52d) +,S(df67bf7b,861d0636,30784bd7,f9a472df,6c2db3a4,7af8d06b,ea3665,cceb76fb,e939458e,513e55b8,7e4b90d4,3f073e47,620dbdec,d7ceb425,1353f4cf,a8d20624) +,S(e3f17365,4bb1e860,d1812852,c67c0095,50f82b34,434c5326,d5864884,bf64fcb3,9f07baf6,ae6b8c28,e8a9d807,22a97f51,bae7c98b,daa09578,5a2d1fae,3f359139) +,S(1cc073f8,ac4fe62f,e311eb31,42bd357e,45ea17,a844528c,7261bfb8,24642103,52303125,ef059a48,142036a1,ab6353cf,90a021d8,30a936ee,9cc4ffc4,91f514b3) +,S(f6b037a4,9394a077,7483c0ef,326e694c,be4b01a0,3accec75,629f7224,7fce7f0,f922659,25e4434c,4054ea7d,d4bdebc4,d3801c39,be53b037,715c6ec2,88b34db3) +,S(74966556,eb8c4cbf,cd364f06,b2bac116,5b914c76,d394dbf6,b5f2f7ca,14e54207,8ef7ffba,85b9eb27,f444de36,86ce67f7,75c8eb30,5bae0c6d,1962c839,a88202df) +,S(44d3ad0a,bd1f2ad,30957e00,594f7738,18777896,9b4237cc,d61931fb,a564ff35,af69cb36,28168fbc,f194f55e,e7691ca1,88178a44,2e6bb250,84c6ea77,a3d41748) +,S(7914f911,b6956f5,cb0fa063,bff4ee00,cb67058,3dd4eeba,daa4e445,97f816a1,a61b333a,e72fef24,a47f48df,90b5384b,b25b5f8d,5530a5e5,117a4f45,43948fc6) +,S(65a31bd4,10c97121,dcf656fb,55a71c94,ac34ba43,c3219b1c,86f19f56,bda94c38,a2e19092,35d8b549,b1926524,132a5220,e26beb5,f9d87ddf,f46aae23,dd8834c7) +,S(eb092b73,5b789bfe,9a466b70,3801b511,aaa33260,407b8750,cad24563,abaafb49,ee29705,18088ea6,132314c,999ee924,5f50346f,c7a9d114,169fc20a,2e6b6a42) +,S(38574e2e,8ff7d427,3870b6ae,d859322b,deac3824,bdc1ec6c,e34d88a,8d92196f,a0a6691b,4d770ffe,e5503d61,bba954d2,f4185860,19aa60f9,303f3e89,9fbbc7d6) +,S(5e555cf3,adf0d5fb,530f87cb,6fa753bd,e2c09d9b,d703a899,f27d2a15,a051a64e,41bba138,c76d1e98,90ce88be,1053bd3d,559e7118,4b900aff,c048a494,24e1768a) +,S(4e8518ed,92b06242,b0f28b2c,e02582db,e5f908ee,fc660c63,964f5e88,95b509c9,9e4fa860,cd07c071,fea0ccdb,f1b9284e,393d9f61,45dc4ddd,5ded2dad,b8897e5d) +,S(507d72be,dc881de7,86103317,77afe208,69619a4c,f6cd3012,e04c8cfd,2029b562,2f2ec47a,963f7c86,de8497cf,fa70846f,22dad843,29643444,706487c7,d9999da6) +,S(c87295fb,299c6f1b,410f1128,a1c88eb3,4467d0b3,df7dfcd2,18fa3819,58df06f6,2977ab13,5abd0c43,ef791c18,5cdd6b59,443ad076,5f190cd4,77620227,dc38c479) +,S(5f9fcb3e,2d7f842e,22ae0d41,48d74b9b,66b8d98f,fb66e4d0,1f279be7,931731ef,523a9ed2,a911ec36,87619cd3,f7ffde07,e11a2b19,e90771b1,8ff86170,a747193) +,S(42d833f2,b9717832,1b9174ee,75127d0f,5a850a63,52452942,56fc4257,f90f74e7,fcb299b0,ed234bb5,4f0c9ad3,e9a87bd3,f4a83bd9,916c9050,6952df68,f39dbda8) +,S(cb173f92,400cf477,47ec4ce9,f9852778,6636247d,55279b52,81388daf,99b77f68,f9d99960,1e669f8a,d8283ced,317eb2bd,5aebe201,ab97a62c,25573a0,65b28e0e) +,S(a73a52d,a2ed0dad,e9943a25,8e6a1f0b,6b2b772,b010d81f,a6eb3bb1,61877d65,71f7bd19,7e9d575e,25a4c592,92061743,2cf69ecd,f33705d0,3429966d,956a2e58) +,S(209411b0,398bdbaa,7412b2b1,49162c31,da88d9c1,5dd4db67,8ab3e19,c90a8415,1392e77d,af6bcf59,3162c8b2,2e8ff0b5,4ecf8e01,4fbdc743,dda8f061,ba8a24dd) +,S(74590b3f,a03daf8d,537d9eaf,410b6c61,780f4146,44e7360f,7d6e2710,3c8a6d9,d40fb53a,1f6768ae,b4918201,54dc85bb,62c5ee68,614f1e3,b6cbbdb8,e182d9f4) +,S(cd77abfc,78148f0e,1acc919d,e3afeee4,2cb6fae7,5f68ce7e,cd31e3a5,adb54544,a46dc809,f9b1d0ee,4ba8872f,95166de3,87b08a0,b68b3622,492841d3,f4c8ee1e) +,S(ad1d5f2f,ef4890e3,5d1916e5,2dc6bac2,612d3b0a,3511ce92,94262b7e,fe2da353,6aff87fe,3778f197,ca8b1a67,9b8f89f9,69fcaaa5,4ef0a629,c0dd311e,ae83e568) +,S(de45c27f,fdb38ff3,a91c0dda,56076875,be8a1369,23ef5a55,26af8829,c9a17705,43564551,83b6ec8c,48c1daf8,d8f0cacc,4b3bd932,5d6e5adb,89368834,2ef5ee90) +,S(deba00f,aa0d172,a6bf1c71,6d280e2c,8c8e35ba,9c15f0cb,ae574940,fb78883f,2b282f66,c9499232,dbe30521,da2298c9,7a0dfc43,562ac5af,74eaac20,1d2dd708) +,S(eb95be9c,eb4d5db2,ae9071,e5dca616,dcdffd15,762dda32,5d13b576,f6532b04,c21f9054,d504aeac,79f98cda,de167ee,60e8cd52,bd44e4e9,3d66e2be,a9867741) +,S(a2849585,a2d9d78b,9da83fa0,cdf7f4b2,62c29e29,876297fe,3ad3bcc3,691acca9,a165f5d5,9ba43cba,816ddc9c,b33c4d14,e4f768e7,96ce32ed,2f711127,7bb8c720) +,S(e5a492b8,cae88b61,c72c8772,eaf6de20,40c89597,a4c4c703,85c28e29,62bdad2d,a0dd4bd,8cc5136a,184fd7e3,aa025c2f,62f85693,163e726f,cffa37e,2be168c) +,S(875a7369,7940cc11,b00b28fd,c72b31f6,19c9018d,5c261af,f1cef7e1,be71b61f,93718642,241a4e8b,22760240,2b4f4e1,fef54882,1af31e69,cd45afb3,427fe8c0) +,S(39a301a4,69836ad3,f98d7086,24b53106,fd9d9aff,c1253059,f45617d6,ad6c0c7b,a7f00229,6ff382a6,4bcb9dd1,fd9afb5,4dfdc2f2,bac962c4,8bb76603,7224a403) +,S(8bc53451,922203aa,caae8513,4deadac8,10c585c9,f9fb44bc,57113a31,9474f090,a4bc9c8e,8ea5d122,54a6cecf,aa46b791,68cf14a2,280c86ca,177871b2,abc65b8e) +,S(796eec76,37c1fc11,3ef31366,dbefc78d,ba5735a9,28505c0c,e2a22ad8,b447b1bc,11e91c1c,f9195b5c,b8948081,7d8ca5e5,f0fa07e0,19ee5566,90da195b,c5eda060) +,S(ac52e134,1b531c25,60efb2eb,1c0c79b0,d1f3cb6f,3bcc4b16,6a7f701d,7d5a60df,4415cb74,b2ca5b76,985a1386,2278f53f,871813e2,905e51a,cad23265,64efe34f) +,S(c231c57a,ed49f271,2d571e10,fea59a11,c4d427c3,4a67b024,b4713af7,d2288d69,bb4ec242,6026ce7b,56471afb,c4ed8772,dada1335,61d07981,907d278e,70ce398c) +,S(1a1b76ef,11f3d64c,5670f06e,7354fc4f,a7c17129,75ed3094,b5a6df78,c8c03034,600c7a61,188e6ea8,76b8bd21,b121ee22,ba9d50a2,d2ce0fc3,d836829d,1f829430) +,S(82b4e49f,2d9d49c0,f409ce6,13b65a5,c031c8fa,adb3ec8b,62885760,c69bc5,67b8cfb9,56b80bee,5e5ec168,6cbad5f5,cddf38ae,3bffcafe,17d242ab,896fca10) +,S(bb3201,8ebb358d,575cf58f,c08426b2,f7116d40,8cd2d779,9acf6c4f,55de461f,8f3205b3,291c8da0,b0ebab8b,ac292913,12ad3a7a,83ac3ff1,6e6f55d0,445f22bf) +,S(fab9cc75,60a02c8a,e916bfe9,b61cce9e,32d37203,8b42b58,150db6a7,cdd40a22,132d8021,8e3b6ced,e6b3060,5812823b,80c7f0ba,f369caab,8b3b7cb3,bbb477d1) +,S(9f96535a,bbd2b21a,bf41bd19,549528fe,1353724e,cfa3870b,3df3256a,661c7e47,b8acdf49,a9783748,40232e1c,9a0f6854,1547b7d6,d1d60bb5,c321a1b6,54fee431) +,S(60d4754a,2faf463d,f7b0cc2b,ff4e6495,ea9fa9a2,e2f1f4e9,d773301b,3d406daa,43d16225,6bddfb93,3588da3e,511ec648,5599ef3f,7db3a1c8,899c21ea,2fc91936) +,S(3850610e,10a40ef1,5aaf4d4d,b11ce214,7c82a449,ea965cb2,5cd9ad46,45ba44d8,c10cdca4,aa919f20,4ab148c7,2eb4e6f3,7939c70e,e134433f,5c70e45c,fc30be3f) +,S(68089586,3a26181,a6966055,1ad8d431,9d325533,70839d17,fbfed5c7,fb84fab4,a0cee277,97d2ff7f,fb7a6805,604eec37,4ef4182f,a163c53,15924f,287bd447) +,S(aee5d57d,17a9167e,9d3ff19e,8eebeb09,7675b709,e3a89ec7,38280b9f,ab9404da,154f14e4,f991644d,aad6d858,940a6126,5a8f1c1e,ef6071db,5e138081,5e2d34c9) +,S(8f3362fa,659c58a8,2376ab88,c921fe2f,2c8a5de,f36c057b,3154800f,bd493950,5f88cf3c,3fc1ccc2,2105f3c7,8ba7b8c5,525a9fa7,7cf76976,8906d0e8,caa64408) +,S(2bfce32a,9d69a14d,324d8f94,15b42f87,25f5befd,ba3cc6ac,2a5c7778,f23187a3,f7e88e0,51ea8e3b,788e18e2,95355b2a,75fc3c3c,e62f7797,d3b02681,d6a3b63c) +,S(62984e62,5d026f0a,c6c82fb0,46dbc152,a05c9a22,3f55663d,5cdd87d1,e094022,1dadce42,d6b68fcb,19439f33,2d2db167,f33861de,28cd303d,c94e3a8b,7b26964e) +,S(15502824,b02a10a1,d7b13137,4175bcb5,6b70f796,fd3d0713,42bdee98,99d8a057,b391d51b,b2b89dae,5b687e16,e2ce1351,2296130b,e86a7d21,c1d3c6b7,b20eca57) +,S(1bd98bca,c0ed80d4,f23422d,c32c5922,1164ce33,55526ea1,61e1d9fe,518c0e11,6b0afff3,b0fa5029,b4e9731a,fe772fca,c0e30c84,e6c652e0,f22dfd41,a9cf0ef1) +,S(4dc9e532,d5543e88,a59872fa,24b99968,e649977f,9ea08bdc,303ca4e,d574bf40,7c05536,d9181687,133dec90,43cae3af,42dbe034,af05a746,b6de1ef8,20276947) +,S(3e92be78,d7c7db61,1049827,42b0d213,672cc543,c27628cb,f5985c19,5685f3a0,171c3afe,c69648e,7bb7912f,fdfecc4a,78cfd246,a4fe1263,e5eeedd5,330f84e4) +,S(57b6c4f4,75bb9ce2,2086a5a,dfd5473b,73b0f6d6,278afc7a,16854e6d,32b2842b,4fb4aff6,738f05ce,31ec7934,3638a717,3806d347,c11afd82,e39d492f,b961ebb) +,S(571ac8b,835c5f4,a7457344,e8572910,309f0d3a,26b849a1,b3bca2a5,28771b59,317ae805,3aa2855d,aaec95e1,72f4005a,6ae09ce7,187590b6,41fc13c4,9bb4cf9f) +,S(534c2141,e38a7880,bf146951,7d4ceaf2,a25bf5d6,a538eb1d,4161461a,ae54c4be,59dc6548,1b056dc8,c3e98364,ce6b76f5,fbc9c501,6ff24e0c,1c7bfffd,306b03e2) +,S(7a761f86,3a224193,157d3d1f,8fff8a05,e5c13366,a7ef7604,2cd3a1ff,f9f936f1,20e86bd4,5e93b784,f433d6a5,8056c6a8,e8d1fdd9,e924fd37,bd5b16fe,fa0ece9) +,S(c1497e7a,b9373d32,4bfe813c,32aa9dae,f1351351,c86ed382,fd3d4c5,6a54f62c,9401bb9,1621a327,2c233004,d6a8093d,f812ee66,604eaa86,32085b3e,482eccf8) +,S(2dd83787,e31e7237,f49a570d,adc675bb,147b91e1,3910f22c,e41bd16f,edf3c0bc,10148349,6883687b,7ee844f6,d60ee90f,1aeb7c0e,c9f83293,be96eb2f,5cd6d46d) +,S(938f1399,18a0fe3,55ddc7ec,d6dacd34,1d9c996f,9ab4f9d6,90b435e1,fbc0a74c,30c71b30,e7a3c244,b8a576be,9e527e6e,60d1834d,17908e6f,a0771daa,92517448) +,S(e71217df,430dc65a,d188f6,861b00ac,c3214125,447d8e26,7dc5473f,9471284,8f27019f,114e542e,96eb5121,b7c3e094,f18f6287,f2cefd9e,6a5290e8,5e1dbac0) +,S(ca2ba87e,4c040efd,c06ca7fa,50cbe414,b66bb2e3,ded2bfdf,7744f81a,91b102fc,24848b82,4019bae7,4cd7604d,101c4819,6e808ecc,79db885d,bed68354,ba3f138) +,S(c267ce5b,633c7f12,1be2b297,45b4dab9,ff488b02,c8f89ba8,706948c7,77167ad7,16184a77,954c3b5,f9e330f8,e8b308de,1489ebe4,bb9ffe59,f3f545da,e7748385) +,S(1eb9af42,96d58c44,bd6fe2ff,db05e0ba,1b5f581a,af842883,5a47a050,468f8b33,f88a1128,95e53e05,4e514117,5a2c54f6,a235cb08,3494a7a,991fba4a,fd0bf1b2) +,S(ba342b95,76bea3ec,15aafca6,2f4f505f,c35bc2ca,64e2f4be,22323b77,1ee39062,91be5746,1fb662f6,cc28e73d,f0dd61e5,20cd3ceb,2d6fb0b3,39a76e5a,39114afb) +,S(f3a8c7f2,86117118,a4714895,eda7f401,dce4be87,dab4d4fe,b55068b4,c948b350,1dd2f669,31f0ec62,74e8bd53,97cb6b50,d97f9238,2603c931,8ff1c6b,18893bf0) +,S(3cc304a4,3aa02bc5,25437a89,977b8ee0,9f5f997c,56c4d317,f531d22e,4a60f55b,9ce121dc,cce749b4,78823adc,c9a613b8,aaf78f5d,c2eac8b5,d5ee6aed,592c7bae) +,S(e5be6c29,b9f12f42,1f499fb1,13e54bf4,4a577fa6,d8d0dcd9,6b509f65,1b4f3587,7755eecc,721bdd9c,c6e8c96a,d398cff3,c03e77c7,9e34dfac,1f51873b,8771d40) +,S(f933bc46,f296b780,4284de6d,5bbeed68,bae90bdc,cd731cb,b9519c05,278c7fda,b6ec0484,faa4c53a,630a8b81,e1d567dd,543a4e55,4e89ba69,d72646c5,7ab3740) +,S(e1d21ebc,297edcc2,b595976b,2f65b2a7,a6797cfa,3e5abd27,34e2a962,dd2f507e,aa31ee8f,4c80a0fb,9e52f32,c7e4a69d,fbe8d297,8dba479e,b0c9f4d0,350012fc) +,S(c3cf0aa1,8e45aa16,343c52ac,41b12278,f9899b46,e17ef9d,d7b67f75,84a1eb72,174cf510,70418a6e,f83b3db4,97102ca9,5bd99985,f2554e5f,c32cdefb,ba47e411) +,S(e6a90aff,6e1f0311,34f93967,538040e4,92120644,8e8e2106,dbba6f5c,701700f8,93895ef2,1d3513e1,19228b95,86289c26,f3efc024,1ac2c963,b394cb87,265638c8) +,S(e2b695fc,8f1856c6,131761e0,9f75a558,94a4a7a9,2837dd29,f8e8a474,7a9b9a91,b580a2e4,240724d,5c5381df,27a17d72,4d0e638d,958c0a27,fcbba34d,da5361d5) +,S(c0660a14,6db599e2,15f813a9,f267d6db,4542a696,9b08334c,6bc80558,ae518063,6a901346,6bee774a,54ec2f97,47d7a8d1,e157a13,fcde8cfc,57e48d84,374f6ee6) +,S(5c41cced,2b091fa7,df1f8e30,3d78b117,842511eb,41717b59,f776e05e,39daacb5,dc4964e4,d91fc985,af5c0f87,f0026a6e,290bb1c0,b181fe2e,195f7001,52509f40) +,S(6abe8574,49cbaffd,d0e5fdf6,450484b5,f8636170,5c8a0a59,a3612dc0,8d0d52a1,c669b059,3a5fadf6,86b9583e,7fecc9f2,c5eae967,9eb5be36,a2018337,64703bdb) +,S(560dc0ec,2d407e81,4b5034cb,8d26c8bc,7c86487c,f74e2fb9,a076b521,f68e22de,faa241bb,ee929015,b4183152,5aff5062,3a270bfd,6026d94e,c3106e3a,e66783da) +,S(f3ef40ed,8d82c02,a141b953,e8593f06,b74b244a,b85edb18,eda3e693,3c8f90a3,aeaa6d25,6db6b12c,d9a6ab5b,d6d0d854,62c0d298,5a772648,db46b614,3050d4a7) +,S(413e0fff,df030385,248b1fe2,1bebedfa,77c1cb86,d665790b,21914da4,58a4479d,6fa9db70,80ab1736,ee7d54dc,e5d1b545,dd17e3f4,45b39038,595fe180,2b34b443) +,S(ed3c5ee2,cf1cc502,37e5c654,d903083c,6fce29e,cda0f427,5a6e1ac,940b8183,fd265e79,3474e60,109cac37,a867bb81,d8ba8b8f,94b13f08,c409ad5,362492c2) +,S(b98e14a2,3f5e5d6a,a99ef39f,18e234d4,42102e72,2e330d2e,e654b328,e2f3bf49,67a60b41,8e820ef9,72ffa57b,1e383b1,35585920,20434df0,e443c318,89734499) +,S(31bb6293,28793b42,dbafdc9e,6a418c51,f0a0cf0b,6da96879,11a6f046,c146e475,1bdb131c,b14a3d85,a532f889,89112231,341a546e,c88e8a25,8bfa341a,7826512) +,S(79b2d26f,f257ac80,ca67a639,9be17ff1,8ea0c10d,739b106a,a9310754,6ba0b252,e09448ea,b102b1cd,654b6e1e,7e4754e1,c63d11c2,46b0ec5d,31df6175,6b99e850) +,S(ab8cbf8b,c3a740d3,c1bfc2e6,efbd7ac,f444795,cf2e311d,edfd5c2d,124d55da,70599847,895f335,a8bd33f1,811201b9,a860555e,8cde2a27,4c348b4c,6ab449a5) +,S(f6b7c2ba,c5468fb1,cfa0785b,f67972b5,36367ef4,d3dc9ef9,25e88085,524e6021,663be56d,c325b2e2,3753bf15,1f6b2ea0,2d6a62b3,a3d5f565,2734401c,9c661a3b) +,S(f5d2e04d,229d784,d7af5af3,ea65a35d,637b404b,c431ca72,1bec7fa4,dee33377,16c90231,e570a434,700fd8e7,cae5f8d,fbfda2e0,e234ef23,a2e82452,a0a953e9) +,S(4df218c9,4277fac3,3ca43921,e29fba57,6f183e74,fa2ea781,88b8245d,eddab853,7828e929,6c589e6b,1d80b036,2c9bb0c9,2c2a79aa,378c597e,8a64b985,d6e4d108) +,S(60e1cbc2,78d4a0bc,b7973b32,964da674,9e2b3448,24075a0d,1db93e51,ee3414c1,cec0aaa2,3db6c3e,6d6c3189,c2dca9de,8ce91791,a721ecbc,1f09c7ad,468ee8c5) +,S(1e7a9c4d,a6cf3251,559d58eb,bafd1a7f,ee686c72,8b1ad271,d9da3b15,6a9f3737,794e3bbb,cdc0df3e,b9669a10,8a32d7b7,f3fb843,388cc55e,aa893f64,ce1b960e) +,S(e8984316,5ee703c2,a413c7,2a5c8ea0,605c0b4b,58cb844c,85df83c3,b4f361b0,69fd6f89,5cac1716,f0bacdd,5a880f12,f964c2cf,1cd402ee,27ccdbcb,5188b64d) +,S(2b95eaae,6078c535,32a23225,eb9821e,c7bf864b,75187df3,2736459,f0797e4e,aa6e1922,b5102e69,77fc23b5,ac2de98c,edcbcc37,54c928b1,7c7d124d,980666fa) +,S(403c1933,59ac9027,7aed0f41,f9ebc507,8ae553a6,ec3b8a4e,4f66a841,19d221a0,edab5156,8667e7b2,c7793e17,839e46e7,85a6c7a0,8af7295,8e25b411,13829ead) +,S(fb182399,c535de2d,556ecded,54e42f29,8c0054a6,1dea2477,9df1c7c3,bb53e1b5,7bed179b,73268027,4fa6b227,d13763d8,4fa62dec,2e351ac2,d3aa59d8,8961123e) +,S(9375a9d3,ecfff9b4,b672d90,45aa4872,f61c3b8e,4cf86a38,7daf74cd,affaa521,41c7bd13,f4e491db,77a42bb8,d65ba77d,f03acc6c,cd789759,37486d08,c3f691d4) +,S(abb9554e,1b68c554,81d8bb12,5b426a4c,433cb110,79254f8a,ddebabd2,9f5be0c7,946d680c,1bee958d,32089353,41ceb7ee,5b4a8168,a6368a92,e1ab1050,5d0e76d4) +,S(56e8aa51,37b38531,1e5e1097,4df857ea,b4f7e53d,11102021,6463c212,ebcb873d,b51e1981,7eee5672,afe7f688,92ada73,abe703ac,4e19770c,97dac300,8d3b1632) +,S(ac487fb0,4b00962b,2b098cfc,4f22eb28,e5007944,d32a136e,5988dd47,d9828f5,bd305529,5f4200e4,c5e6238d,76665bc7,67ad8402,dad13d8,6c6fb316,a214a5c) +,S(1dd7562a,ce273114,660ccde4,5f41d690,11621bce,56cc49c7,2016f19f,d94e9e9f,a8e8861b,ef664d9a,c19391b6,5bb97715,ef677199,a373f255,876aa9ad,d8a93043) +,S(c198019,cda66df3,2bd528db,e3869d6,1d1d7cae,57ced846,eebcf1e2,bcceb8c3,b0a9c52,ae2b2625,7699d3b1,861474,4d66f09f,8b795d81,acd3e5de,902b247a) +,S(950f54ab,3cb421f6,95404b53,9b1f4936,6b43e61c,7bf9879d,168027bd,f58dc386,e14586c,7f005f5f,21e122bb,2a35194,d5d2fcfa,4898c279,cc296b24,9b48b2a0) +,S(5b20af8a,31b69820,a56d0df0,c7374c8a,37805449,81e0c017,83b4ff49,2bd40ed9,7e49b8a1,c5bbcb32,55991da7,99613598,cfab9d8a,82f731d0,dc2f52a1,6ec39c55) +,S(eb8a10cf,3777670f,437f55c0,2ddd8681,63da41ff,5b534c63,ffb23ac9,ecaed755,99c18d8d,df2ba9a0,d46ea92d,8b983f50,c16f14b9,86b955e,a577f332,10533df2) +,S(12977f3f,d75a9c72,81358c91,73664b40,8d8ccc98,45153ede,c62b189d,8da2b176,f24f505a,75761c5d,939ad836,17f0c6,dfd8a2f3,fea04721,9078e2b2,1aa317df) +,S(7a591539,ff4fc3ce,2e2936d3,50d753fb,131ba419,8d034c65,e76d0744,c159096f,c95d8b25,52b3920a,6341ef43,5e3e797a,446565e0,652a562,7e0674c7,ca243425) +,S(993061ac,819fde52,ae500ed7,3277ecb,fd08930f,8adff61d,f5f9c3c6,cca49640,d54444ce,748f6058,10051838,52f0073a,8a5d1477,f14111d8,b623a316,a67ad06a) +,S(cf807c40,c5664fbd,910a31bd,ed3cb7e5,2e54d1ff,ffcb4b43,7a579931,6f803051,a5d21e6,6fa9b5a8,2882b77b,ca66b6e4,163d579a,d245d089,602274f4,55ca9881) +,S(9c0119ba,461d003e,c6fb7a01,2bb32b89,ec819d97,8fd4cfec,ca1c3b2f,1f14f0bd,b41c5fa,ce1e9a54,f1605e84,61b5e6ce,c11590c0,15838059,2c511360,f4b537c4) +,S(56ea3259,5d97b7f,d7f9fe51,b525d73d,3d77d483,f8bf8460,8d874d25,aed3da3c,f764a40,2cc9278a,f1ae6369,e1723bf5,f0a15a47,992f8fe0,ae33752e,473c3058) +,S(2851e3cc,2fa6752b,e0a65326,46aa8445,71736e1,d22a01fa,ab3becd6,50460acd,ad778ace,631584df,da4730a4,20242779,81f9f829,cb18b20f,8ce727b,d62d64b7) +,S(1674559a,528fe0ad,5aef46f4,eeb4e0ba,34b8c2e8,c23d3409,5ec1e164,ef351979,afaef98e,ee2ada75,7be9675f,fee76686,d2350972,a9d1b80d,fbbc0719,efc38b21) +,S(ede70ea,37946f71,848d72fc,7a98102b,f9c167f3,219671ab,1843b5c6,8ba6d7c0,920d6108,6929e5b8,30c4fa,eb155b4c,9d324001,59d748c9,d7e74980,d54be37b) +,S(fd3b1f22,c5037c8e,93f4f9ac,27ea723b,3d3e861e,694ef349,dfe51f83,50ac9fa5,cc02effd,6df18244,fcbd177,a624ff17,b0da8fec,fd60624a,3d066be0,9c466cdd) +,S(72f037df,352a4619,729bc550,e23ad7bb,6f2d7977,7d39ae36,bbc1d45d,d6e864c2,c4bfcde1,2a5cbba3,7e047070,5937c2c9,da702040,bf49cb5,c762d60c,e8fca76b) +,S(f17a9b25,601ec8ef,e320558f,ca832789,d0d8d558,76ff7c53,6af0f84b,ca799a61,c90583c6,2a863567,b0d8c41,e47c3d8e,7e196a1,9269a409,31a1eab8,f1402837) +,S(ea9fdf49,9e201fbb,b0a26a71,1b9be2e,dd17b2d2,b96390c,4aa2dd00,83bf5c86,64322654,c8bb2a83,ab0cb743,eb907234,d8503fe7,381e17be,c17bad5c,d33b4df1) +,S(8d5d6f0a,24aa6e3e,7dff42b9,ab8b22aa,656788b1,1e18ca35,b4ca6f19,1d50de6f,d509a2b5,e9800d5e,a7d1d047,e945e693,2e5c1923,59bb0210,1b2e8956,33e0257e) +,S(25ebcc4e,84a1d22c,f0a8c980,8252d96,7dfd528a,808ea293,ffcae94,50e1fb81,3127af8e,4012c2b5,c92e428,2e455de1,681eb1b2,6e660fcb,4ee8fef,b64c6101) +,S(c55c17a1,dcd8fa41,8a3edb5e,c2da8678,4fed0840,522b24ed,4bcb85c8,cc45c20,7d583091,25261489,44b56fed,17b07906,9d156fa2,e9bdc462,eeddeebe,68f4f463) +,S(f4297f59,21a867ba,1e58b9e1,def633f1,18e058d5,a7889721,f0e4814b,7e63ecce,a39f359e,35a123eb,5fb66d81,f117858f,b0557859,aa2c388,a8298d11,43f137a9) +,S(626b0a,cbcf0e7,daf7d218,74f72be4,8d824883,4428bfee,f82ea516,c2d1b98d,74ae6867,1c27a642,53a36590,5247cbeb,77173b07,2e429de2,3ce09730,8d54ddc4) +,S(8ed35ae3,c02c5db2,acb516f3,2d3b6823,61964f2e,701889ab,26dc9512,ed40172c,aef4c71c,e241be56,63a091d9,e230463d,237e0717,78b7b6ba,a63688c7,6c694334) +,S(5b082ab8,963510de,46c1cc49,4ac6d3c6,dfa25f33,8627a00b,6b98121c,73899ed,cd8b2b84,185718a1,c4686ff0,7cad18ec,fe3d4532,9537910d,31458086,c280bb32) +,S(deaf505d,b08a282,d5274de6,43c5719d,f51827e6,2ed035f1,74279276,7ddc1158,c1067344,5e4c0d47,ad1ca85d,713a5916,1aef6960,9294d738,103b945a,e99ed1c4) +,S(eb62dcb4,d820019c,e865129a,28b98b5,be6c6e16,a80f7c76,db3a15ee,31ba7aea,e78eec22,be4a175d,68b2257f,c5adbe46,fbe31c3d,5eed4736,2304d80,ae4577a7) +,S(6c58cb64,7ef638c2,337cfedc,a9345837,597ac142,577b2230,7d231a3e,5a9173cf,563008a5,7b823427,60bbc400,5f604024,92f0bcf0,2ab2430a,5d7accc5,b62cbcd0) +,S(106d8978,775a41b1,12f07815,7c3bc5db,bb5980d9,c745806a,b5ca5ede,8b468d51,bf960349,6f7d7906,141bc4fd,b1766102,e8dfc49f,decb469f,75dbc54f,21338dab) +,S(cd6124f4,21796b6f,44c34982,8b536ef7,44bf30ec,6ca08142,e959a35e,c0385224,97ccdb9f,2896e815,19bbe9e8,ae491e61,e83417c6,6db8b6a9,bede3aca,f6608ea1) +,S(2918b2d9,b0bd83d0,b8d02815,59219c6,bd708e2f,2139ad0,1815b1ff,ae60e03c,f322596e,c56984f2,e7b2ee90,8a9bb56a,d213f84f,3088aefa,67e372f2,76e2a233) +,S(6d3fe999,acc04d13,2462f14d,680a90c9,89b747f2,3601d779,507c36ce,8c2acc7d,a6c7413c,36b6399e,58a443b4,e4137ea5,551a9fb2,c5397457,9d55b48a,5df0e30b) +,S(bd74ac79,8b320aaa,e3e51123,9354d4e9,280c99c2,809e88be,13980305,62d55d52,73477881,9b9067a0,78b40108,38ae59f4,3f6ef064,ba35209c,46a9f0dc,aaf84597) +,S(303f6cbe,866b4574,9d282217,1f571fb7,8c54dbfe,901f2f43,681ebb0c,76e5700d,b13dea58,d3dfe08,7fd043f5,8e63e565,85230d6c,273d9e3b,22145e39,afd6ea4a) +,S(3bbb0824,16a2e3bd,e328f013,154f18c1,4e840030,707057cc,f4fa0fae,ff56181a,18b214c7,823b0cb1,76375146,7a49bb8c,ddc0047f,782e3802,be12a119,ecf0f480) +,S(ef42fcbc,999a3f80,b4e7319b,1fafc2c6,49f51845,2e423c55,f57e5e1e,f8338adf,786ffec5,60464882,48641155,38aac187,ced4678a,cee2b9ea,eab6ae61,ab2061e2) +,S(afb21e4e,c095bf31,34276f4e,f1a4883a,6038c20b,a7a87ba6,6288bb1a,3bc6f77d,cda832eb,73dc0e9,fb77315f,6cc7a313,2212c7b4,1075a290,d5917033,62363bad) +,S(329c98f5,a40b81bd,7d121b90,78b50bdf,bc16c9bc,47744368,34a5208f,20d39d63,dc14f7d8,4bd2a1e7,22fdab98,1044d6e5,98515df1,7da5536c,7a95866d,8231a) +,S(6929a4df,e15e7ac8,e8a9c5a9,3544af51,aa621dc7,ca04038a,9c9cf603,8e081754,e1333f46,e4d1f151,f2b8c341,d2ff90cf,d36cf73c,6f441b4c,5c0ae272,6a25fbf3) +,S(f40fbdb4,27d2d68e,854cbae0,24ea5980,5948ca40,e3fdfcc3,3efea0a4,57e2bc24,33493d84,41c8945a,9e291b58,5e12789,34990a7f,5fec49db,ea1ff605,4bf8802f) +,S(220417f3,d9fb32c0,1439e473,d638856,9b169c38,1057b780,c9de7d12,e30dd796,4cd93672,5abc4e39,89e64ed1,af9b3d4b,4732ac76,a6c34d6b,23274573,8d765a1a) +,S(dcbe3dcf,2c0120d9,4d6336ae,6158bdf2,859cdb03,8c76ea3c,cad4ed11,13ed216,670823d9,73c74725,ce929318,c2ea650d,5feb7c33,c7831a26,821f2614,7db7d8ee) +,S(34de2319,c535a31a,87fd9b70,33c363e2,8ff754a7,9e0669a6,37230443,228ab3b8,31c65b12,cf6f4a9d,662238b0,c8ab52af,ceb96acc,35b90b2b,81667b8b,dfd9895) +,S(f0fb2bde,a5626729,720ff432,542c5e41,abf0fbc4,772aca7a,75b882ab,2b364acd,114edca0,74520c9e,2f5b8059,59c5273f,25d2e621,d2f55709,b42d187c,932b6bb8) +,S(90477ee6,a00742ef,78662c11,f3725077,dbda7b66,7ba55b55,f9bfea1a,4c5f88f4,467196ec,638d137,33971505,f291dc0b,b9d0f3f8,f284e3ab,9035273e,d9c7279) +,S(ecdef6b7,455a41ff,96cf943d,e489858c,b7abc526,e41d463e,b24a56f9,dd6eeada,1116e7da,9fe72782,e8c656b,9f677c5b,dfb3e46c,98957c30,49efd7b6,dd5d3258) +,S(58d30bd1,d8dbf5d9,885b6e7e,4f28ceb8,381415eb,3851a031,ef04b073,65e16598,9cb96ab0,546246fb,f5cc0878,7b99db0b,26c9bdac,184a0eba,728fbd26,bc880480) +,S(a7587d1b,771b3421,f56e342a,cca98e7d,82c7dc60,765a481,53379da6,fd341c10,9499ba9d,8351d194,213ba35,43d4b563,aa28bba0,9a6d8811,9b55f389,90742929) +,S(8aa99d89,9db3c7e1,c28bfc5e,18abdfbf,d9fff46c,560e4fc0,cff65ce,e18ae6b0,aacbc2e2,bcc4ae58,1e354d29,617afee6,20ced0ff,859c62b6,669cf2e0,565a9bef) +,S(45d81a7a,b4158aa4,2e45fe7f,3966d278,75f8647b,defa0c8d,a761ebef,894ef249,93a76905,d0e785f2,db52e09f,573a461f,183f672f,9f10005a,eeed6e0c,d40d31bb) +,S(de19bc8,6fddeed9,909eff4,80b0760b,66a1a245,82e33be4,55b8061b,225942f9,6eb2c1f6,f604056a,15c4e91f,789e35b6,1a787abe,aded0f30,abd2525f,19486d00) +,S(653f0e92,977b7830,fa546dec,44f05549,80f5a9f6,61f2cecb,7e360efc,41d16380,58ba9f7a,eb7aed3,40b54d7a,6f9ad0aa,ab5eaa2a,7715d8ec,48d52ce3,c3c57128) +,S(c05441fe,2ddce6b6,64270b69,83d44d5c,251efcb8,2bce4665,9388eb3d,537acce,cc82b7bd,3a049b06,98feacc8,11a1c9fa,e95181d2,50c0c62a,55a6d662,c9587d65) +,S(7a569bc6,a089fbd,294dd5d0,b10f3a7a,31b6bf39,42ee97d0,49c9259f,7adf0a7c,2399d17a,f6207b8f,20286fc4,78896af4,5e596b09,7c97f662,9bff0c03,14db53e5) +,S(1c4c7a37,4e14ce88,fd08a1b3,10025711,7d96878a,e173d29e,1ac53a57,1d6ae794,919f9b82,e827cc78,7352f0ab,99770e97,bfe1b600,40cf1034,b7c5178b,3d1104fe) +,S(fd4ef218,a09baf70,57b53f65,2ca1e2e5,8386e867,521dc998,1bd4ffdc,619c31c1,b1d2e716,64fec6d9,3cc8bf17,70ab5f10,a49a0497,ac1586b7,b8299f7a,e92354ce) +,S(f012612c,1f933373,ac30413c,1b2cfb9b,6582957e,b74e4de5,29c0267a,e7552a41,a38b2418,e7ace7bf,3a15035b,a68f82b5,aae49192,5783066e,f0f0263d,6dbc86fa) +,S(8e0d504b,c9598eac,c4bd2726,8b3ad24c,a22b7534,32eb5a31,d7e54948,d57f6f4b,50f59455,ba1ea3a,5a0cc105,a1c40c4b,72637a31,44bf9438,a1e3b52e,7b30911c) +,S(8635604b,89ec22bb,b3b4e266,3e76cb3a,976cc78e,c7db31fa,fc16a7ab,411ed197,8a11d457,6868d117,4f41c40d,4c82d27e,3960d57d,4b1309a4,531c2617,b1d90227) +,S(aba7addf,c234513b,3e861382,654959c9,984628df,72b2a896,6459b3c4,86bdbd2b,ddec8263,bfdb4c38,c9e7fd,e4693b0d,962c6e5f,a4f9eb9b,9561e81a,f04a3a3c) +,S(12aa3b40,44f699c4,8ff6c598,8a7ce56,84f3af85,8cf2ebd3,4d59ca7f,f7501895,76397e3f,3c42935b,6a42222a,525c2166,7662ea00,25decbf7,8a856391,a03956db) +,S(e01136bd,da38f328,af447a50,43a48606,a1ab5a86,b3bca98,b13a53aa,c7061098,76f3fc47,c1aedcc,bf26ec5c,4f6ad56c,fa163212,65844d01,8d2f2b94,184b64df) +,S(639cb266,f0672340,d0a789a9,41eec287,b60c380e,f2f62f96,41b67137,4b286aa6,d381e7bd,5dffffd9,50645e56,63c36d91,83210038,d70df2ca,4bbb837,e8eff508) +,S(eb12f18c,89a6d2e6,5e07d20f,f7acf3c4,b903ce68,5237aca4,5692c0e0,f6a4714e,d26860ab,e6f97745,dfb01cf,f6225c36,bf62e5dd,24088d54,a6d44384,e9eed86a) +,S(8fd06b6d,96f37c6f,8e69187c,c5ace64a,6e36b45e,37de82b4,872731cc,8781e941,e7dc3254,3b40599e,852d4e9b,e35a5438,ff68b063,3b81c8ff,c2f3298e,931e9e98) +,S(d248d914,4ca3f10b,3fb66763,713492ac,93b42781,9119683f,bf0e0f08,1bb6b241,e7a2ca15,f1867e9a,d19ffdc3,f1a20d0f,2469fa6a,e04f94be,a289d019,c405318c) +,S(ba2150dc,15884df0,34a64e20,89023947,687d1322,475dd073,b163a4bf,4eaf0740,af92a566,a320a0a4,34095dc6,f02f765f,4ebdf04e,d81e2c04,a86e6e2e,923f8c94) +,S(fb12f487,225a6843,31e39309,3133f377,a6f841a7,f6f90ccb,18ce3d39,48b56616,e3358a9,406905b7,d6bc0a33,6a89a5ba,e62136a5,4135c3db,bb32f115,4cf92b9b) +,S(bdeb3e38,7c36bb9f,c45a1d62,f7128217,20e6d0a6,55a285dc,da87af3f,f59e0644,b23fb389,3cdb280a,43275691,3c1de5fa,6da12909,c0ebece7,12c9da49,69a3cb29) +,S(32f3ecc5,925ccc13,f753ddc7,d5c0c576,e80402ab,ffc6dc77,6e8bf74d,15735007,f950add3,926bebef,9d8e3a5e,4d0ebbef,24b54dfa,ae7c12d1,32b6e973,dc67c050) +,S(94a725ed,e57e5162,817d95b0,54e2732a,3afe3a6,52ae3e46,ca9de38f,6dd9f0fd,805f6634,f8ba79b8,ecd5f46f,74b741a4,de5f9678,d29b8cba,eec73498,27671f67) +,S(22197e54,d35357fc,ad20f6cc,986216e7,f24e6dc,cfd9bb89,3e5c1ee6,9a99b3a4,b3e7edac,abb1d1c3,d375f361,1f04a927,9d2995c9,3e18e7fc,4b5dca90,a2a3fe17) +,S(a51664bc,5a1edd2a,ee8ea644,7beef61b,419e20ad,ac955847,5e1d666b,1b4dd52d,b8a95fad,e3aeac7,bcd8670c,78dd1b2b,5dcad225,277ca5bd,f24f131d,94405c39) +,S(896a11cf,f9db64a1,aef51088,baec42d0,16dd5a99,98262f71,a005cdc8,ae8cab78,7a7263ea,f64962db,bd09a278,a3958708,e61c4858,1a759726,c225471b,20899077) +,S(fff75552,46da269a,2124d03c,677f59a2,18b995aa,e69c85d4,3b29f81e,5201a757,dbbf1558,6670c191,9da69467,6e8906f3,80eb3f61,34c656b2,a4ccfc71,4b3223f5) +,S(89da8ea8,56f946d6,6e9b07f3,db5b2ca7,49a07e5f,78b59c1b,e52e46b1,3793e198,25889e02,d2013d86,6653cad2,7b3504d1,4e547343,fec74a37,a3ee71a9,646a36b3) +,S(d260dbae,6ac3e8a1,442ca7b9,8f7118c5,7d6cef72,783c0b3b,a4ad7e7c,3a8836fc,e00ee7fc,95131cd3,3a446bf4,c21b85cc,45a8e61d,2d9d6cf0,287996e2,77b7cb6b) +,S(bacf90ec,75ff002b,c1a259f0,3c9debe5,9f5f9dd5,cc0cbff9,e8fd62c,4552a619,82dedfc1,42202786,a7a12a29,22937c0c,23bddd23,4418979e,78723ff2,6a9e5e88) +,S(1ec23fa,995a22ef,53a91dec,a5b2faa9,514b5ef8,faf125ad,da61f84c,5b13a397,1568ab1c,cf75692c,b7d41c53,2dd4427b,ed7043e6,cdfe01a6,2f9bcb47,cb97435d) +,S(48225de5,eb07155b,dd86e759,9e172a3b,b96f69bc,ddcdb051,af2dc769,f4450b1b,856ce939,b81d976c,6a6c249e,c0d087cb,36e28082,ba050de5,4948d92c,6693f4aa) +,S(e9ac9963,16c1ff8e,a7d2bbf4,148c8b3b,a869d4e1,290168f,b3831d6b,3bbd164f,2b1ac664,6bc87e3a,e6914792,d0bda8b8,5cfe1107,3d0447ef,e4a65acc,6eac846d) +,S(8af31ba2,af0b68c9,4290bdf4,b4b80345,5f52ee89,f4ddbc98,1dda1000,9c1a2ec2,a37cbc1,a5efc09c,dc944f42,a66a305a,b302eb17,21ce5088,a7deb46b,5223f0b6) +,S(1d211de7,d75d4389,4cdac235,9b0b9e40,6b71b8a9,8c0583a5,7d7a0056,b3e88779,3ae4bfde,20f83eae,96982e96,62d65443,4359b2bb,df249a85,c7c83b95,56d7679f) +,S(be6beeec,18aa8d77,20100975,3dc7d745,c6d49f9b,ea64ebfe,b8fdafc0,92a192ac,c9e14aa2,4bce41e0,f444030f,ddbf035d,e808bc06,63a70593,454ba287,4ebe50cf) +,S(b126dd86,555491a8,e2ab601b,2f133960,d86a7f9e,bcd2c88a,cbd8764f,1afee3b2,d22ae79f,fbc60439,baaf2c2e,418edb77,70837ebc,a909322d,b5580c30,27c20821) +,S(857b9c62,6350cec4,f928d456,7d30cad8,6f1cfad,142b338d,74a137ec,61212791,9d3dc070,f610ee55,cfb9cfaa,4bffda56,52f7fd18,7f354634,ed4f2dc,d27f9ca9) +,S(bbb7d30,3e242e87,2e94e3b4,27197ebe,5252c363,43ccd8ca,940202ff,fe5775ac,f2b5b210,a40d1fe,140f8638,3a5b0f9c,96885d5,d9857a3d,252523b8,d59d33f5) +,S(3e90a10c,a61bd12a,fe9caabd,e52dafbe,8bcd332c,e0ff8bd,7718b685,89e26447,3a4d342d,fec7d557,7cc52bf9,d7c60537,50150146,8a05baae,7b562dbe,b626a952) +,S(dc1f2531,d5e0d304,66b963fd,7d09524f,c66e6bbb,3855b6d3,141db170,9af05fa4,f1644b11,e8291f92,4884d3ea,cf89d857,fc98c3fc,e49fef96,7986e8e9,d67c9b0e) +,S(2b4714d1,fd0aa7ab,6c103ae9,19493efe,4a503d5f,beba56dd,93a8c9db,485c1dad,d65bb3c,47efcc3f,7484b6c0,9f51605,30542a81,d1192ac7,5d506c43,16f41220) +,S(c9ffd7fa,3b14fce7,c2946111,e940ab3c,8199b7e5,40bface2,5d8e3b0d,d1a15176,3b40f328,a4539bd0,a0b71e5d,91a881c8,87b31e11,453d9f5,82066f44,ead8d5a5) +,S(e019b0e7,6b4221c0,e45d387c,6ee41bdd,ed5e219e,a7069b73,d92b6339,2657c39e,792691b8,4c8748a,cf10475a,955aaf5a,77328c6,f03c2e9,bd1b20be,f363f368) +,S(51e07e1f,e8dc56df,f6394d1d,7f2887a6,9e7959bc,ca10af77,cd54064e,6268929d,c09b86d6,6837e473,574bdf95,f0b99851,b97a821f,6dc622d0,d9c6cfbf,18db5ceb) +,S(c5c19c69,9a9b6908,4625d3b9,5c6598cc,d1bba7a0,6d4e2f91,88f1b77b,4aab720c,af066357,107d856a,51c699a0,259774b3,352f8c12,988201c3,c71bfe3,c5d8280c) +,S(7b51ad32,ec4a6df5,f9c952e1,fcabd8dc,7661ec53,2631331e,5205d231,533f8d77,e1346672,ebbb97d8,569a12ae,fea65246,e1902f0a,9cd91894,a4b8aaad,5a02ad35) +,S(be3059dc,3789e16f,5ca8f6e2,c469f834,bcd3fa73,5d84377f,907cadf9,e7eb895a,5a6fa277,ee5d317e,81819fb1,11f40778,ab437567,48eed726,238ab5c7,f4d6ef06) +,S(cf75a66e,810f3284,52e09fa3,15451289,e1cba33a,ff1013e,4702ff1b,92b6f587,a0658bc5,8c894702,ec5c366c,5a6b18fd,86269d5a,8117dee3,601dc40f,cc93f17b) +,S(6356c70,7d5228e5,253f09b7,7020681a,fa64dfd6,3cabd703,91d7f892,d9822737,3241ba88,cef88e8f,98d19fda,717904fc,737a9c77,45838ba3,97141964,946ac7b5) +,S(90d7f09f,7b8a1232,236b4459,b031b0ff,d5e8c903,36a35f04,94a89615,3baf8554,4a612ce4,b18b7ae0,f3c557e,c4ab51bd,7c32f26b,24d0ca7e,accc748b,3a2db676) +,S(170265f9,5a3f936f,57a39e1f,a748a3cc,902b1b20,4306c49e,f4485b15,555f80af,d2f813a4,b329da9c,68104a55,301eb7cd,3ff6dfe1,c4aab9d9,d2fb03c9,e7ae2bee) +,S(2d6316de,37598fe8,ed6e3e52,ac47d442,636a6553,64274692,5a468f08,54377eea,e064f40,7f0d3b32,74a61d82,d7b75006,6fab6447,e66f2d4b,20439303,cdb3a107) +,S(8c89678e,73f3085a,1a766e14,f566625a,cc29dda6,3eb7bc9,ed1195b8,5fa2092b,12b42d8e,91c9640,b8b2509a,157229bc,a66d28b8,157742fb,a12d7405,eec110f5) +,S(ddeb928,de6424c,f9ea76f0,abc208f1,16731596,29fdb2c5,c8e6ed28,38ab6b11,b1395663,9ac1f06d,74aef36b,61916872,7709eaff,d8b76905,ca404459,325839b6) +,S(485e8e44,35c46bd1,d0c2a4db,19b958fd,4a87511a,ad4aae65,eec4f5ba,6cbb38ee,e621d1d8,736d6df5,df2db5d2,36887c27,a93733b8,d3232dc0,95d0b2b6,d0be516a) +,S(bc527a44,2547aca1,91fd98fb,84ce7b3b,6210378c,46f7bd46,bfd375a8,1b61206f,ff7c1cfb,d3c21616,85d6f405,e6f19e8b,6785e6be,ce374189,4efc149b,b3031707) +,S(9911194a,7a75269d,2fda7214,21e4e2e,3666ad12,3e76004,b5ff9afe,9ea89ca8,b1f350ab,c87d942f,1aea75fe,6c144ea2,fc5cc040,5c38af56,9ee45413,17c7bd4) +,S(93226535,e27a96af,7953597,4db1d4d5,4a65d3e9,331fc3df,7f028fa3,288c3189,98007e66,60fc6673,5e8e864,afc62171,49168a86,27d35eea,2d02d90f,e6f15331) +,S(752d352b,2459fb97,d5a0c46c,3fef99ed,50ebfe74,ceb1c881,b2fa518f,3aa59e72,c6e99a8a,2544731e,d932a164,ca0def49,dbfe4f29,f8894133,ff5eed02,66c4fbcc) +,S(ab37b416,dd06a595,ae6fe33d,717c4ff1,fd1de2ad,6c58e2b3,660e872e,aac7aeb5,182f07fd,61ba43fd,e11ad355,d7027fef,714c9b9c,364c0b72,1838ef7c,f85d9470) +,S(d2fa3ff2,b1cd8909,52a0d380,d43233f4,1eef04da,aeac6ceb,46dd8e6e,572d170a,85f3c854,3eea0e64,b8a9eabf,18057700,6c3a6f70,a790cce6,24a3f6f9,5752c520) +,S(e256c5b7,99ae8dd7,1daf5a7f,3dd94f94,e040d98,291a2d6e,9b398889,addff0c,b4375e5c,82517974,b515ae28,54c83443,e8bf9391,cb975013,727e3bc5,1473b133) +,S(30056648,afaac00,c1d77bd7,e7b5235a,fea2bc8c,58b34a6b,83e630d2,3036db6c,16ca5c30,6882fd6e,f7d82f93,b25ad01c,eb3e9e69,b8280f0e,e3aef2e2,ec204600) +,S(8602fe69,d4b1f32b,e8422928,200c5b5,816f08a1,759faafb,29861e07,c5dccef7,59a5ca0,35490ebe,66409e2a,283f4c9d,f6e0a7c7,9dd1ec82,f31f7e4e,4f23ead0) +,S(53bb9f5,ed205516,36ab170,7afc75b5,6ab3a75a,3d360c15,3b0b74c2,d7d9d64c,77c6c1ec,c7a53dc3,8c6540d4,461757c8,b5f7b66,654fd754,fbfa8f5a,a5318cbf) +,S(badc41b2,86982d76,e5374b3,dcf023e,dbc1e187,70cd0b2e,2916d436,108a4328,b1694651,a69dfad,924fdf5d,526c25cd,e732078f,31128556,3d42ebb1,3329e2fb) +,S(15b43026,f5134b3f,1ad441c9,793b9e57,a318d455,fd6f10df,e4b0bb91,5d36600,43568550,60fb010a,6d5123e8,b446a1e7,cfddb6b4,6e4fb18f,245a4be8,f9975a1a) +,S(fcc64bd,c9df17,4d4e8e18,cad6116,a48780e2,a180f7c7,57f532da,9fdf37e7,ede37062,35eca482,b935410b,6d495f53,12b133cc,238eeb6d,e8e5f593,65601951) +,S(f394fa79,254fbdc2,7a1b31df,1f868c48,9b48b6d5,1afab542,2da5b1f5,6f3edd2,f56d3d7d,e7f8d9c5,fd45d6e2,cc2af300,fdce3293,9be5b975,9d81cead,e2000e7d) +,S(3c7c8c54,6b853a5f,97f92932,5558793a,e1debf3,3f680d5,6a79bdef,d4608d91,575771ed,f26feb38,a728354a,6c4023ce,4b019d65,3f7adfee,3c83cf58,9f2fe4a) +,S(51d61258,43b8d621,6c0880d,f04f34d,9acbb422,d8194a98,dcbf222d,cf27fc4e,2d0bbd0e,ae299afb,93980894,bfbdbdf8,6edf9509,ea408286,ef602cf0,ce3b33a2) +,S(14b17f35,ac7b5914,e08babb5,5aa37cb4,26d3bd34,f2c1e4f,45acb493,8ef51a65,a9090e25,cd8273c3,15d1ac6a,15eab027,7981f6bd,a85fb082,2b24cc88,2918fbc1) +,S(59ceb93d,d78ff6a5,f45c5fcc,7c1ecd72,43f2d8af,e4ba8a3f,fb03053a,586387dc,28f4d0e6,38ac1fc1,98aa3548,56f4f19b,479ff825,5d150f29,871630ae,f82f3777) +,S(273bc0a7,eb63a0df,eea8d7ac,b24a5200,a7086078,388db5bb,37a0a6f6,acf24656,a971405,a287160e,22909b67,357fb63d,10af5ece,f725b1ac,17c7fc73,759936f3) +,S(c9b5b690,3a45e529,3a298219,cca93e0,52a2719c,25cf2f50,c4ff7f04,5f346475,7db09fca,ff1aeae2,dad001ff,1fca6166,a607eaff,bdfc327b,9b63e2a8,e97f665d) +,S(90044bea,c8459e34,edf7c40d,2a101b45,66728d1,cf0055ee,c8ea07ab,e39307f0,19763d08,77d4a896,ca9ecbc0,56d405b,5a6ebcce,1ff6ac26,593be19f,63caf6cf) +,S(6e0898bf,bf6baaef,d085f41,da7e6b93,6b6c9a88,3728dc7,8ce7d71b,fd597b2e,4769146,91587abc,c2f21e05,4542280a,f7260a72,e822edca,1e63c089,3bea3dd9) +,S(e94563b6,e0156145,ca2ef19f,58de9727,7b806969,a249629a,4f024b99,8a023792,c8949547,a4d25901,f3980cf5,333f65f5,8e1797d8,b42ccb0b,dc550e6d,5909927f) +,S(3cd027e4,173c2799,54d06c3c,ec05c0d,161a3b73,348db0d2,8c03d097,8921ad64,f0d1a3e8,ebc3387a,ee88189e,c1fb3f6d,5e73e895,7b7372d9,32b00144,248271ba) +,S(4c96f51,2b4f0758,38335d47,db599db9,a2dfe1d1,6783960c,dedda119,693d5686,4e840262,66897288,9bd54c15,219ae871,e6426b67,afa949c5,e1226bbe,1204dfe1) +,S(8b03ca2e,458873,963ba6b,c9dcd14b,59fb1190,3f2330cb,22997bb4,19002fbd,2b29df15,c6be49d8,27981ffe,aae26930,7a461f84,8285f561,4f910508,eb865781) +,S(f4217bd2,32229dbf,39066a17,c2524838,38098362,f0891b69,275dede1,f8e64f0d,7581350a,957f480c,89246800,86c2803e,99ff5037,938e3e19,22e3f9a6,7098dd96) +,S(247274b3,d5095d63,132673ca,dbf0e418,898468d3,9a30c538,a46a2719,42846bf8,4265a1b7,7d1dbc68,956f2441,9c4d2b70,9e71f6e4,6e24e336,a978285c,22a84f11) +,S(19c25b9b,97f40ddb,23d62bd4,a298ce7d,befdf39d,327aca47,61815c0a,28d4af9a,a9b5d705,94cf4c7e,b7e947e2,101b18bd,fb9f2f20,fc3bf89d,f5a63d7f,61d3b3ce) +,S(fb69718c,baf0c5f8,e20ca98c,2fdb18f5,59df27e5,c2a064fd,ffb2785a,73bf27d6,b612c590,4e0b1c54,7beb4e07,82ad2716,84eb895a,862b59b5,cf6476b8,af52107) +,S(9fe6e793,ed1aed77,d8381352,84890e3c,f817ca60,37ee80df,6646a3ce,9c316a6b,17214a01,99370a88,41717ae5,41d35a4,96f8f041,e9b3fe88,4188f6f4,e30b0657) +,S(c7f7ab4a,394f17c8,47010e9d,f1764fae,6159b140,578f70c9,fe50703b,aaba62cc,9673f262,c875953b,90558dec,8ddd04a2,6d7d3ac1,672e3d10,c1a3c656,b0318c19) +,S(cc2e30bc,2d63d4d2,bd0f5bca,8faac99e,a6add123,82d014c1,d7bf8285,7ede2297,cb87a21c,f1efe789,fe72ca0a,b6acc5be,63e6973,2ca899e6,fb9e05e7,72d4d8ff) +,S(6fe7070d,a78205ea,1f12661b,4538d0fb,60b4bb4,9c1709c9,e53de22e,c3c25d6b,2f6b773d,492a82f7,f9609cbe,e1af3c9b,2940a12f,1e615c1a,801c02b2,19e6b8cb) +,S(1affe9da,ab5da7f7,9b331e9f,91eb7e3a,f4dad51,2317ca45,3ae13528,66013d8f,2706d2aa,d3139097,73a0febc,191c7a0a,df2ef168,c65e759d,7c034bac,49c8a92b) +,S(13566dd2,d0cdb199,20a1f9c,aa1ab581,c3ddf2ad,125c13cf,efe199d5,bc338231,b403ab04,67df46b,2efa5b8a,4cfa8bd,97399c87,12ffc55e,cae8de52,d4f6f28c) +,S(135fae69,9a969720,b1c0d899,790afa99,83074584,da3ee8dc,1e011336,dbc3636e,b4260b88,2dc79423,8cd0fbe6,5242147b,c96690da,c391e3cf,d2c53ecd,2ae9fc60) +,S(1b05d97,744364a0,5432de4a,7d840834,3ffe211f,a543bccf,71a4b210,3bb0489,d61c9d21,671b2481,a4ca0c36,7d4ea919,ae1b331f,a8aedb87,cc6b6c98,85616a9a) +,S(2877f026,83a5cb48,7014da9d,419c8b9c,920f0940,718e2d06,d7252de5,5b46a84d,849f9fb2,88d3fdee,de734aaa,3592ef01,483e02d3,62a5e0ca,2ead6c0b,42628038) +,S(8a7024ce,6348d2fd,84be71ab,b363bdb8,86ec6a2d,29d9cd83,1934270a,27370b78,8f520972,9e4e1325,363a68f4,ad53737b,688c63dd,1cec6cfc,bf9da51a,98b29c0) +,S(5ac77dfb,2309c061,8f68b320,bb6eb76e,4b0f0792,b8235fc1,ed768c57,44fabb1d,fab11baa,beafeab4,43a14a82,f8d70228,57752732,7b016b56,32b924c9,ccbb1db6) +,S(aee4edc,93413d53,45e0df68,99fc2193,be318a8b,f279f0e0,56c0ac42,a60759d2,b6a87499,1dc68ba8,503beb0b,8a6c09df,cb9efb6b,a44aed6a,3cd7befb,506119b9) +,S(b51d3e77,741d0d44,3a67b5d5,67b45aac,2008c25b,5196c71d,c9f910e7,b76dd2d1,431c7ea3,cf4f577f,950d22e2,74b7cfdf,2c2934af,ad0215f9,459a802d,ddee4c21) +,S(803a2ff,c59c2a94,65d8935d,93d47653,86e5beb9,c8e702a,12d7b565,98a09841,d5e02ccc,5d8ccf6e,29a7fb76,5a257dc9,c902c900,a4fe16d1,53e9187e,290efbeb) +,S(22c17725,44eef514,5636a398,23e874df,8c58bc6b,6935598a,440ae9aa,5b738075,a67f431c,688d4426,c519be32,9b1dd50e,2c64648,4d3612f,35d52089,c98dbcfd) +,S(ed67feaa,5aab50a9,ff71c434,855bafb0,5191f036,c691c8c5,563395,d2053b86,b2d13cb6,4ea821df,f8829ee1,57cb5fca,81dcce75,d091719c,73cc7785,c443f0a8) +,S(f8cc5ae2,3b670b9,3c27ab8c,7d8055c8,4654b427,f9e6b733,b083fecc,c7c5d375,7dc996,7bc3a2f2,f516aab3,682f8d6a,32b84173,ecc742d5,c8a15c5c,72eb261b) +,S(838891a1,fa46e300,a20fa3d0,cba3fe09,3326ffd7,bcdd7c73,b6e96da,5d591332,d46717e2,c5fa3d52,a268aa9e,a85922e4,547ea986,3a37b1ae,b77d75b0,d48a8fea) +,S(92caeb7f,400d043,6d36656c,8ffd5d45,6097cb51,cf512c00,1fe613e,8dcd5544,2096bc03,dfd088ca,25cb9aef,29b24b99,2b2aa00b,e3429cad,c0976a3f,162e47e2) +,S(2e6226d,574b687c,20dcd4a9,683697f8,afce56a3,1e11cdef,6f0ba6f0,dceb89b4,d9c4d7a7,a7aa5f8b,f30f0930,d6c3bbdd,b1963b1d,8cf24796,141bddb1,ba8ffcf7) +,S(33aab3f4,17d936de,b8c1f07a,9fd5024f,802fa5b3,a593a6b0,9fd42871,75f4ee7d,4c13dc95,7311dfaf,932eb4cc,68c82550,3b185530,13008dc6,878dd092,50edca9c) +,S(ed74a882,a947da53,fd62a242,b67dcd04,50896a43,e9882c84,ada77f47,691e5fc4,454a18f,a8fc6d8d,e673410b,213875ee,35190221,9f7cf88e,f363be08,571030d8) +,S(b5d3f084,56db930a,7d8b4728,2caaf807,be7bca65,bddf9738,67a56224,39723ebd,a89e0271,28d5872a,f4d6b4d7,c5a7efa3,b0339a32,89a12918,2077c106,b61e1a4a) +,S(5e40e90c,1a01e008,d5fde186,283919ef,eb859921,c3ec07ca,e34eedc2,b0f07967,e4be6ef4,26eb3c94,70ee3084,f431c68d,82b2df48,5286082,82cc1b2,afe77900) +,S(2f4b14a2,674a743a,4aefd302,7fb214f1,a7678336,3c9e7c8f,8ebee72d,c5f29830,11b13461,b6578710,677bc733,3d28e773,c78dec4b,27ca1aac,a17121b0,de9868e6) +,S(71909162,35890bbe,6a8f7a99,5b1cc3c,a68b3ff9,7551d09,59a97835,5b7167c7,f9aa3992,124fa99f,167f1351,865a1456,8ed9eb92,c7cb2050,5082d228,4b1532de) +,S(8df50d7d,d3cf99c7,b0269ae5,e70546dd,bed3f05e,260bd834,575d56e,e65f7f0,835405bf,3c84c4ba,5e253fef,f306bd1c,c1240ef,8c03da98,d7c092db,3a2606ca) +,S(5e0f6a7c,e9bc1e0b,852841ad,52045b02,b4fd545b,f2106c82,17a76bcb,441173ee,ad70f065,4d75c88f,e6654d56,fe65c57b,857d91e8,ad6abff,148f3577,7afa2aa7) +,S(27880a25,21a78fca,cddd0b78,5a3da1f4,2e832641,8f804a2a,42fe3c0e,f69b43b7,ac9f930,12402aad,c55c12bd,e450700,b0208d85,a6784586,d04f1c93,6df8624a) +,S(6578c4a0,dc25e068,97482b12,3f38cef3,39cfd6b2,ec06c89f,6da11449,de5e43a5,8a249d9a,41e6c1a5,a776ddfd,ea93ba78,15f2e908,b8b854c2,3a7e3ff2,cb99bf70) +,S(c66e890a,71beeba3,301bbbef,2bcf4cdd,def8e634,dcf476f4,6907a280,df3dd33e,f3510cb8,9c46f493,c4a70976,34a9c502,11532929,ddc883ab,d43bd360,1b028dff) +,S(393f0dcd,24b47380,81197794,58bf5e48,b2f5479c,8efd8925,a1f78bef,6bd16665,9898d880,e24f840f,f1b4662d,3d444c29,6527cfe8,2b6f1b4f,f0e5928c,bf09de74) +,S(337fc469,43942ce4,f1601877,874366fc,a8726f4a,65a9bb26,c6c2c013,856a3adb,95df242b,2d4446de,b2b792a4,d36ceb2c,add17365,380d78c6,3b23b101,1b3be914) +,S(b7edfbe5,118cfeb1,4c1aa23b,48154dbf,5e9d1057,a2758516,7fb8e030,a457874,bc1e5723,dabdfd76,c98f408d,1d8c13e5,7dee979e,83b3d610,981b9718,f1e61eee) +,S(4dffac46,6a507b9c,2e2ee5b6,ca81d8e4,d4e8aae6,3d73395b,dd29b024,51436e5b,af227fa8,ad0bfc48,eb469596,b9b2759b,f41eb169,1fb8f896,1451489,ebe0d5d7) +,S(553ab99,3448879,b42c72e2,97d597a6,24416a45,f5b35720,c93a303b,c6dd0e88,5ba2d3fb,222a03dd,c5302b25,ffce74cd,58de90a1,c3e41928,19717c28,52ad1b39) +,S(b351ad4e,4c7df853,8f6f71d4,e95554ca,3a07932e,7a812309,b0b0c807,f98cea2a,5ba5141d,b3d4ff44,7efe06c9,c624d447,1aa3c3f3,47af74af,49929de8,d8558c70) +,S(844b9bc0,ae73df50,e5b80fe2,fb24a35c,dbc91c61,2753c2e8,e3765e1e,47d44263,80eeb80c,414c3a08,a42d89b8,87883d48,84b38bd1,40f7bbee,e977ff5b,c4c57b90) +,S(f64b4ef6,8fc11491,38ed4ef8,ab2d6336,3d494b37,b56649d1,5d15777a,8cd315b9,c6f83010,5dcfc707,f435cfa0,b6bc32f3,8ce8afb6,28bf9139,dfc47279,cafa56a5) +,S(969ceb7a,441f8be1,f16c94bd,6065db17,942f88dd,e5506742,7cd30dee,cf9ba5c7,a08ae62c,6e6758f9,724baa45,d35f3e03,9f636265,d841b61a,f1b31d20,bc8d65f8) +,S(e465041b,78c33311,d4397b30,9a8ba4de,6b312d10,ec2ca906,583162ca,1c599102,3f21d5d4,416f1954,7af1ba97,6687dea3,520ac304,43c180ad,3892d46b,86618f55) +,S(87b2e548,b019224f,b1021a06,522073dd,46892847,308fffe9,910ffc28,5b702bd0,6e641d35,9e7ff12b,20123b72,f0e5ef16,338c3418,38c2f4ea,6dab94c,7c3f6940) +,S(f832d7b3,590a59d7,ec2c8a63,7ca0347a,893fe461,4eaba097,8707c353,8296ee14,3fb3e845,4624fe35,326062b4,a6f30c85,f0e7101b,a3532455,7687812e,412233e) +,S(52aff21f,fe1819f3,7f8b5974,ab004393,6e99d8cd,8342b7bb,ad46d333,5e4d6651,66d79c3c,c7d08828,d8646e4a,6a44853b,4a49df0e,85c95e85,d9c995c2,d09b427c) +,S(aae62778,8069bcdb,fc91bdb,946cedab,63896817,575a471b,315a47cc,d567c678,f254c548,832d95f8,4f20215e,ca4805fe,356e806d,9b3b7338,7dd36e85,214b70bf) +,S(fc15d494,b6580e0d,e1c769c3,95c5d047,202e8d07,ba94bd1a,f96064b8,d1a4bfbc,f9327fc8,75319184,c1876748,bdbbdd3c,bfee8baa,bf46844b,af465d4e,ec6be335) +,S(aacec857,fa4bc62c,82790a4a,496206f2,d79a31dd,e17d2db2,d99619d8,c3d880d9,6dd1e4a2,adc502ac,150293d9,42a1cbea,a576da49,f1de7d15,de70bd67,d95c5fb0) +,S(c7ba3155,bf34fb9a,2441832a,27396e1,99836557,9c9cb856,44c3ace2,9ade66bc,afccc814,243a1fa1,345fa46f,ee4b4190,96082bf0,7866fa8a,2a887d84,d24192f4) +,S(cf7a0525,3bee95d7,711d8f7b,7b301f5d,8036a487,a55e3860,900b25b1,c4599115,e8a4a9be,7b9cf99a,5dcb4db9,8249350b,7a71a12f,a9582620,eda5a35,1a8a0484) +,S(a4336248,6b999ad1,623c4c32,c79ebb3,4e8d6f3b,484f808b,9a088ffb,2885a11c,edf8eef9,74d3e5ae,2a991a28,6323597f,5a161f9,2eeb9256,207be548,f9b38d16) +,S(d3cdbd98,8cefc8ac,3a442587,51364a10,649243a8,d4a63927,f4fa3b10,b1a7dcc8,f10e26c8,11f4a219,da4f948c,51e8b81b,d8bb357a,182031cf,40ffb464,d5f7d7c4) +,S(fa038534,28dd093,26977fc,da344269,fe3c61fe,35567eef,909a2309,8e5ceaef,f31c5d30,9e234b3b,44fbb52b,8c973aa2,bd85afac,1f9f0798,788721a9,380d8606) +,S(718c2bc,26dba98f,24f34af5,18e18870,5510c0a7,4e228cd6,9d4e39d8,a00a577f,c41d0d81,8f093246,5675a326,d0615b0,294b8455,909af0c6,e557195e,11225152) +,S(378ade51,463d949,1ed22ab1,834cd7bd,6b99a123,52c65e18,70d5005b,e97e602f,76469796,d7758ba4,b3bed1eb,9f8389a2,2a421f5a,20f8df71,72821a8a,508e4c1) +,S(40bd7df9,1255680b,b50d3d08,fead6815,5f807759,87e9cf80,15e6359c,9f138b8b,ec0417d4,2eb1ab50,a469a853,edc65ca5,2fe00ee7,53b30b9c,56536e3b,36144e8a) +,S(f01b30bb,985dfb53,7bb4cd62,18cb0b00,b5a77215,4d84a802,8a4969,260d963f,3cf483df,d6b58eb8,46e8ba1b,f06c2e9,6784255a,2afbf68,613f39f1,44b82417) +,S(2392d86a,1bf9a636,38eaa5dd,76a7c6c9,eabd50bc,9f2ba568,183c0995,f7195900,806cd3da,ac23f93c,3b11cb5d,a3bc4482,ea49ed2b,444c6e64,dc557e46,3ac5c033) +,S(b0e7747e,c9496fb,aa7798db,e616fa42,5b0b7acb,7409265d,c989b8e9,20087133,32fa615e,d0286b64,b83cbfb1,e8c4b133,85527655,48071401,89f42d93,330491e1) +,S(8d1342f4,2f6dc3cb,9bb741c1,9daa08e2,25fb6352,ffe860e1,76a26fda,a0601624,82d35ed7,57cb6f31,81af31fc,36f53817,191fb9b,c9338a97,3757d0bf,50d79d77) +,S(ad09dcc1,d3ebbbd6,ecd7be45,d7eec5d,ef743851,2ce076e3,cfc4f8b9,449a2ccb,26bde63a,e1f7fbd8,46260a64,372d015a,fd3d5ae6,125dd801,523a94fc,8421d04f) +,S(128f5199,68435c1,a27591a3,2edff533,d12a725c,f0c7e121,260cbb74,925cc292,dd8945f7,42f1d013,92152dbd,1e4dd8e,53277da8,bab68acd,8c7c8d73,f5d7e190) +,S(118c1167,196e8eac,e519d83d,17ae1e30,36ff1fa0,cbd1cc58,41cc3763,d1d8a931,eea348d,54f47b73,d5d8c2b4,7eb7604b,53beb345,c82ceca3,4f8639e1,45b2e3b2) +,S(81ee4bba,6a84edb1,83e1f2b7,5103e453,2ba9613a,b612e0f1,27009ee7,7be3bfb,e58208,d152059b,73b42039,e0a7a489,df067fab,1d1c2c04,9eed00cf,893f4847) +,S(494a821f,6f4b2d75,7e5be34c,fb9949ba,b9271599,3e060005,dd807c83,adf04f2f,8ab15e9f,c37d368,3586a1ed,ef9ddc59,8dae7206,499cf53c,31a8cc4b,d7ba15e0) +,S(3749271a,da87c292,724a3ad7,2861a7df,9757e31,3c3156a1,72cd3735,608c865a,aeffa1c1,aaab4f09,3998b4ef,e046aaf0,f404d590,d6cd762f,1aea5745,1f8aa3f5) +,S(103c8721,321ddfbb,cc3ef6af,1ea8fab1,3de6aca0,294dbc79,3a1e4216,563dc1f5,fe9cca2d,b459596c,462fb268,a8115880,16c2894e,e8839caa,362e4813,e8e827cf) +,S(ddbfc655,6aff403b,10a643fb,f62a60ed,656baa39,b10febe6,92140bf6,7b78f2f9,1cd4169e,cc8ac589,de57b5a6,e02e03df,f3cc7bb3,45993d5c,4ea57e6,852a8417) +,S(d025f583,3e51a9c6,a1c785c5,1c579528,5af0c297,c0fdb82a,f555fd59,88dbb28,5170614c,110f31ce,d88424fc,7d569f4e,e93d5017,a8c676af,c7261ed3,340d22ef) +,S(3f349cbd,8ebac9e,c570b0ca,29fe8ce8,dbd98eba,103f131d,daaf193,4fe78516,ec9641f3,175ed56b,d0c8f26d,188f9fa4,b38d069f,cef8f4cf,71acf66f,1ef7dbc9) +,S(7624599c,61e71532,a177e838,ba92d789,5160e43f,ad798fe2,9170e6d9,bbcc11ce,409e8cbf,6aea70b8,21533902,150148a0,7e45dd61,c9c8d24a,b8cc3da3,f03c49a3) +,S(8a1e1b47,3c699dea,aa418ba2,85cf7467,51af1cb0,8bf78228,932dc6ed,845403f4,1bd300a2,7a9a8da,6ed2bce3,73b9d39e,661d02bd,b4605740,20934bc6,abf3c483) +,S(eeb91c38,d9b834bb,5e3945b0,9655b988,96efff11,1e3dde8c,add6ef2c,7ea51b09,899d841,24f83b43,e2ea82ad,3a6411dc,cf36fa86,17bdab35,d83829d1,456c56be) +,S(46360f69,8c023375,6f050969,60b3defc,2a1897dd,44e0e159,d185ac04,3315ef47,ec02a6d3,828246f0,684d2059,23ba73ee,10cc88c9,575fc005,6271fb8c,67e0a4a0) +,S(16e5cccc,b410c20,e8de1e76,e5b71649,64cabc26,f629f8be,36eff4da,66f875ad,a80de48e,e079d9c,bac312e0,70f10d6f,fb875c90,7dd3ff57,c9bf8b90,57c0fe14) +,S(c315230,c8ee5bd8,429efc06,bd089f49,5f4c5a1e,2fb188bd,81e41bfb,85acc82f,71430e8e,cee9c6f5,eb91eb14,20e07b5d,736217e5,4bc25cac,9767a749,a477599b) +,S(7731eb8c,1684092a,d9d2ec69,b50339d1,19436082,c9116366,8ce2bda7,ee80c0c9,e6636efc,22a4c339,f8100dea,a227a709,42d18222,8cc58d13,ae4d613c,a879de8d) +,S(2c1c200,4a5f04c0,b83d143f,ede81755,67d4d54e,b2dc4ffb,de00b83d,9802f68b,b3e2e434,30d409cd,26490c1c,818b24ed,b10e835b,d6292422,45c529f7,6e299159) +,S(2d984bc6,a2031a3e,1a57d0ae,d13d798d,fab45382,d29e4a7e,8e029fdf,2a9d95c2,b169c34f,9932f02,8320ed87,4a74da8b,5cba81bd,f20a9454,feb315fe,a0926720) +,S(f61abdda,f7673f75,74e966f1,c77096c7,7f6e8659,746e45e7,2c9fbf3d,5e0db5f6,1717dd6f,86edd17a,b242212c,91878ef8,9ff1b865,b32b4e24,cfdab7de,de90937f) +,S(a68f5871,bfbce14a,1097eced,68a9e906,c94599cf,b6dd4176,ef946fa7,e5552c3b,cbc07a08,86faa82e,d231eb0,739a24e3,62a717ed,30b0512b,96ac8dd9,56ab05f2) +,S(52035076,1af3e786,60906105,36a2ced0,6f8209d,a0eb2757,cba705a3,467ccbe2,7a01b944,5f63cf43,cba95191,262b1b53,ae0af9b,4b172b78,3970f84f,f8ace09c) +,S(bc8f1537,9d4b9862,a437065b,10f6c28c,8c3323f4,51f2847c,63251000,c9f144d6,894826ed,61d85e90,58c00e74,cc731dd5,d62684b1,ca996c07,ab176df0,e4b951f7) +,S(536b0cb5,81dbf6,ab3b364,64a397d7,2a513bd8,a7bb8237,70a725d2,2eb12a98,85bc95fe,6e160f2f,9a31b7e2,74c09023,90cb2f4a,22f15ac3,3d0ee72a,b666f5bb) +,S(267840ea,e2f49fe8,9889bac7,40eb797e,ee42f922,c1821a66,163a580a,a0df90d0,2c7fe7f3,4e06f09d,a1a2b1ba,79906a0b,18c3d51b,d9b6011f,688c69e9,1504a00) +,S(d8fd79cf,6beed8c,fa57bedc,ca06e367,e0667e9d,a057222b,81fba682,979808ec,39cab613,9cef186a,248562d4,fa581384,d6c81de5,a0f7fc49,140d0822,f6126034) +,S(601407de,9ecff4d0,836228ae,eeaa612f,2b659706,576e2eca,74bc32a1,d3d14b7b,6cfde694,2f0e4495,1e25ff02,2f2501e6,7101828f,8088c7bc,a8ef2b25,88036ec3) +,S(f518c5c,bc0e8541,48c40253,d500a2d,1ea1d25f,d31dc777,d6365050,d3b26804,8dcc6378,2b1ce6fb,9f15c8fb,70c5fd0e,53e4d80a,cf38261f,49a558e1,de637b6b) +,S(16a9bcff,334e35e2,80258378,b2e25d9a,56ce58c3,b3426bd,da82978f,370ee6f6,c7b6656e,baa3864e,bfbc5294,fe9836a9,9fdc095d,ceac6a32,642e6911,a6f3e933) +,S(9d940fce,5ecdc659,30c945db,7151b823,a9259d0a,2a3991c9,f71e8b00,bbe35d4f,32f533d,d96f2e36,2109a96,48ef55b2,e5887387,80de97ad,c7974227,b23fe647) +,S(19e973f7,69c2d02a,8bed34dd,b7591828,5036e724,22227a81,850f3d31,3128f586,f2f5fab4,fe79c177,752ee60b,cd85e625,e459b50e,de702010,a6fbcbd1,5b31aa6f) +,S(ff07bc26,473271d6,4371a4d2,9b59f858,b1b01e40,472bb4e0,1769ed2b,66bf2097,3eba7660,492ae09a,abd7bb8,c5d80e33,44539ab7,276edfd5,b599b02f,27c60b8a) +,S(175f786c,93d89acb,8959d846,934c21df,5dc4f6ce,a9c1e150,e7da469f,d27e6605,343366e5,7f5b9f7a,407cd566,7ef1f0f2,464a2938,61fd5f2c,b0363a5b,dc9c2f9a) +,S(a9027f8e,b662a7e0,d70aa1ac,d3e0b9ba,d4e0bd8e,8bf8c883,40b0a7f5,cbafa761,2f9dfc2c,57bfd835,271d63ac,e3cecdfe,f6e19e0a,fc19ac0f,71ef9ec2,7fac30e3) +,S(677daf40,728a6c89,6804ed3,1df283e,19b41c2d,36a3a98f,d4b93fa6,6699983,1affbe57,3a561872,37dafd1b,bdcaa594,e499b298,6af58591,c6a2ea3a,2016c039) +,S(1105aff4,d4761b77,68db74ca,d9fc7aa0,14c5417e,de1fe641,ed1dcdb1,9b5a3690,bfabb1aa,76906ada,4a1ea463,f4caff44,a41afa71,b82e2457,d2756ddd,14946ff0) +,S(3221d033,16be670b,e05ecc94,8b537ca7,9318eb65,f93ab3e7,32e7f36c,bd06249e,92f7b5c9,85ba3fd8,7b14a093,74d4ef94,130d3642,517369e8,f9de5fa1,c8ccb803) +,S(ac10037c,ad83fcbe,6aa7acf2,3043ed,831dcdb5,66921f16,246488de,6e012fc8,d530eaa8,ebe1d47c,8e57892d,9301c4a4,29b223b2,7344e433,f2bf77c4,d9a20205) +,S(b3ea670b,f5001657,913d5d49,ee1005ea,65fdd33c,4ad81987,efa0331d,b29a3e53,6d758db6,df4275e3,fc148e91,6536505f,6393daef,c54c3b0,b708e0d0,8de3f1bc) +,S(42762d8,bf60f678,924b7cf5,4e8c513b,fa1223cf,98e124d9,18d88cd9,a54c8d88,96be42a1,f0dadc84,64a3522d,e13f10ad,3272505,f7d4fc54,e6dc1a33,ef6b2eed) +,S(7b9e0117,167c51ed,c3f7d2b9,edb61bde,aa90efd,88349510,c4b1cf1a,43a9ae6e,c43e0d1d,8a673cb,1f0d9d1a,e3a4c985,bd47a068,2528ac36,67976881,1ead7a4) +,S(1e807fdf,c69acac4,ba5be7fc,9c617005,d34ff896,dae25e6c,428abb96,3255239e,7db7d6e8,8bf3b869,fe4f7c11,65d85faf,55bd677f,5670ebdd,89d2f8b9,f56d972c) +,S(9aadd434,75384190,a6289f2,32cc6491,fb7a1d86,b04ae9ea,94dfd2c8,449c3961,fc491907,3ffe94d1,3b945382,eb9c482e,9da5a764,d9aa1d1c,c3d973aa,5edcd3f3) +,S(5012b7eb,481fd85,db13c3fe,2bdd06a,720eb4c9,805193d2,b99b4bf7,39802f26,db8555d7,e2cc1858,21920564,3c288352,22086161,1a611dcb,d1e98518,7c46cd4e) +,S(78f9e5ba,91071270,5160654e,2393cd73,85e4681f,8efb4a45,cdce5ef3,d73cc7b1,24c4512f,911101c9,d3a4fe24,b7468585,36cb8137,e13578e,95cc016b,96d86e20) +,S(91a7d927,4de2c0fe,84a10579,891ea8cd,f87fcf5b,a0939411,4612efd4,6bb9f826,d5a5e511,b85436b,89e46211,ec69dfa8,d0ee87eb,7c0daa31,24d48462,10e6c40) +,S(3940b4e9,4626f86d,4592b96a,4f27f874,c37c6cbf,5940de,37dafc1f,35350b69,ecc6176c,43df3f71,cbf0160b,697afeec,1a9a0d69,5ebdb7bc,34b0efe9,2cc68b39) +,S(76e7ab54,8c63ee6a,30c736ff,11762061,283af0e5,5a7dbbd2,23fe467b,85c95d8b,f266c922,fc5e61f1,65bf521c,33235e05,113140db,6a481b0e,e4f9976d,2696fdce) +,S(ecdc2e5d,b8d5028f,f93de09,c9f5a6b3,c439b14b,3c322c53,94622a13,80f04067,e70df9f2,bf6b0a35,9029f937,5e74aa93,4014e78d,e68e29b0,9d96da05,5ff78112) +,S(ccfe93db,de087d5b,9194b286,99243dc0,91d4dd5d,7189a5e0,d5621311,9dee9a94,2b0a0a20,cfef0c73,addd2dc6,d9b4ba7e,9e44f2c,26d9f376,8ef90241,b2d907da) +,S(4e82a200,e64f5b3b,3e473e50,e437c224,e21bf875,ec8ac364,7e599ba7,84f02574,ff696d9d,2d9cc0be,217394da,85201a1d,208e4309,9b9372a8,19f6d069,88839c0a) +,S(a292e105,6f3f0a1e,e816a49f,51ef4760,91324316,2e3c734e,802550a2,c942c17f,479a2e95,7a05a686,1c08df3b,221ed2c6,5d192181,189269fe,9ef42a8,e71fd6ef) +,S(47279a82,8311aa4c,b6138c9b,ccb2fc6c,c4b9d27e,2e334389,1773fc1,ee09f461,2480a805,496e8bd3,e02b36cf,8081bc5a,254f821e,40c0ef48,291ecbb1,6699a10b) +,S(b903b4f8,2126fe06,44976643,5f0982f4,394db57f,b473401,9536740,595562fc,e8c97572,bfae91fd,61cfee63,3b24bece,e587291,f65a6aff,b71c6a3b,615e1361) +,S(16b9e3eb,eadf469d,368ab368,431afb79,214bc728,5df165e6,c3bf98a4,701b05a5,26e74ff0,64cf5de9,ec3d084f,8d75337d,c04918eb,f783c65e,b50b948,d48eb003) +,S(4927fd2b,c17b92c1,3b3ca52e,759324ca,353e8505,ba81ac24,9003091d,1cebbfa9,95a6c16d,c4c52f20,2883ab4c,a9c050c2,b2849b71,e19e0df0,8ff495cd,f62d73ac) +,S(70c503d,93e47,10262c8b,b1630409,979b673a,79ad08b0,8d855365,f51ffcaa,2ad207aa,5fe05144,95baf3f0,b0807efb,d10265f0,5de63d6b,563e4ac5,e70b89ff) +,S(cf598642,32972f7a,a6cf12ce,dc5aa95d,4bd0f96e,38ed546b,9ba9040a,e25a9e6e,67f2f83a,f5f09b52,caed83e5,1b9d6de0,58a6e9b8,96d1a6ed,d7ab4d40,30332027) +,S(617b9e5a,8d0b8c44,b186aa60,281cee51,dc224e2c,9e1c4f07,c342a180,78b271f0,b64d8d5f,bc2907bf,90b983cb,a6126586,dbb7e7f3,d95993e2,2bc1b8f8,9472d200) +,S(d52e0c90,c69cd94e,3c849ea7,dbba79d8,6aed2a3e,3ca3f106,d2baa2a3,59c50534,36c8390c,fe400769,fd2b2fe1,b6af62d0,7fbd667c,fcd9a132,b6b4f974,a7e454f7) +,S(ea474a01,36d16bc2,fae6f568,9ea3c035,aa6580e6,b238f42f,e2ab19be,81330a46,d09379ce,aa89765e,1164f438,4b0f0ef0,c1e8be86,427c7455,af98e4b5,c9ee8145) +,S(4e5dd22c,b6a4b205,97f71375,cc49ee10,ba6b82cf,b06cf065,a25d6f5d,bef51d70,d4ff2ed0,55279f96,344dc16e,10e3410,40378ff8,b8d912c3,a17cbfb0,70588cf0) +,S(774587f7,f3038136,131fa9eb,f1eb3407,9e473a8b,b9e5acb7,317ff5c9,17447878,9d3779a1,2b067b00,d2a2a3e9,46f8078b,e6279024,d94c83c6,28c0cd48,145f510e) +,S(ab807569,d1a3630c,e5447b36,c205e601,a6a23069,4d2c0786,19d9b97c,e0ba6611,2b9eef15,54f8ee6,e11af6b,6a1d045e,d47b8821,ec84c6da,366afe10,2730e9ea) +,S(91602928,ed3cea8f,4faa254c,28962b68,c4437602,3076a5c1,6bad95ff,3e328049,764faf56,2d8de3c1,89b7fef7,62012be8,112db4,a3201692,95c7e76d,fcbd3be9) +,S(6c1ecc2a,258a44b1,ca1d964b,c86c5600,49fdfd98,b362c35e,3c830647,cf1266d4,1f9d3edf,5e0e8550,e4534c33,5b07d731,19c49c4e,29397f6a,938fc1bc,ebf8fcef) +,S(e176821a,4006b429,999de3a4,ada09166,f6e5deaa,f09fa613,60bd3733,db8f7084,7d07d1a5,390325d0,27b05e18,d90e7659,f5ef4c8c,c7c6dd00,c7a5427,4ec91842) +,S(2ae0b70e,53536893,8a7faee5,da5d8dbe,e5af4873,32caf51d,7bade79f,eea50df2,e70be2e8,c8110c31,c3eb5e36,31dc5a5e,bebeb184,e6b9f081,bb7236dd,cadf903a) +,S(1c686fcb,d7a751b2,d420614b,56d37c8f,81c9a600,335fa911,835dad8a,7c663e24,4fe2eeae,7ea1b639,b893329a,a65bbfcd,b9fd8f07,28614bd8,6a5b0712,76aa576) +,S(b369d7e5,c31c9a56,f480b44b,3354be,84145c3,97dbed68,d87a4c3c,be31dc5c,50800690,17d31473,59bab021,c876d152,c17ea8e8,b5c95762,c749a2d,29adf3cb) +,S(522d3ac3,42a0ff3a,9a8eb5ba,54ed4dad,fbcdb48f,53bc6e1f,2c0c12a5,61cb1e9d,32ed883e,1e1f562a,50063d79,45075ad9,9ab55ba6,fdff0d58,9d2b4a4d,10df82fa) +,S(7d001803,7b722a7a,17d74696,fed9bbb5,f3d5f6f,d8a623b6,9c952a2e,f2be939e,81ee30e6,deb893d6,274c4b46,8533d845,38073ed8,68b101e9,515ebd84,70e368de) +,S(c76b074b,b228dc24,1dc9b704,75fcc52d,a3f3bf0a,5e954910,ca4e6f16,bd298983,4fcc807b,4c1e37cb,6a6c42da,b939a7bb,6f1d5ec2,87320d74,408622fa,ece22266) +,S(8497f267,99c7f525,83c620f6,e284a9a0,35130556,9d7caa1a,f118de41,c51b05e4,3b861f56,16ce6234,c6847273,16bfa629,7cac9d5,ff562f66,24b26146,413960d1) +,S(ddb10ff0,a217ab76,241a587a,8cd46cdf,ce6ff5ae,e39d2d85,7f47eeb7,6d2bd68e,a4110196,fd0813ea,19846dc7,12537cb6,8faf9333,19e7e49b,553e523,f07b004f) +,S(47eb53da,455cbbb9,a8330e12,e0210d80,cc565661,348fec72,529390e2,a75b812e,88e4a8f,91ada187,5734dcf,42b85e2b,a3f5fc53,1f1c1df1,300c3d5f,e811fb70) +,S(eb0a8903,42fb2710,a4c7811e,78384918,dedea7a2,9bb7da46,e49211bd,95da1426,8d69a88b,d85e2edc,d8264cb6,c44d8218,1ce8946a,818c9d4a,6f757bf8,5817ac56) +,S(d400c8ef,655d3879,579ba4c,488c3e55,af5af95c,1701bd15,482b2549,9334906d,e7bafda2,5a9f5934,6bcec6e2,a9408f18,e81b76f9,7a9d721f,496c27f6,42725e5c) +,S(bae81c3d,1772e104,66625f8b,ef08d4a4,5f07892c,72bcee05,fb7e382,2a6261fc,4ce5f14f,74f28b03,34a6cc64,452b9049,8460493f,3b64d9be,2ecf98ef,c0270377) +,S(7f575b9b,46bd0f74,555a363c,d80122c4,232e8c53,a6624d8,e13b5c06,74986961,edc0ffd5,952fd4d3,c752271b,7cdfaf3b,4cefecd8,66d722f0,3da1e97b,49aaa080) +,S(a86871d9,1292f7fa,7249ee8,e77270fe,e7bddafd,3255b4a1,16851ae,411293f3,c21ee1b0,bd897d82,566cf438,b66439dd,3dfab0ec,3c7a4038,ccb86039,3b0b0187) +,S(c320cfdf,9cbc6579,8c8b33c4,d97d690b,64ae90c9,a5070646,8c8791e9,1ee4a18a,8f1a295b,2a3c8c5c,3b5bd8ce,e3380a04,819a8658,7be87d03,73a0194c,fafac74b) +,S(169a1b4,f2eacec2,be263ced,2e0576b4,ae77b863,525b2a9f,f8fc05d2,c07a8fc4,7703f867,d997a2ca,bb697f87,b97ea986,78777183,aea81417,1dd0946,309e77c) +,S(218de686,ed51588b,1307d8b6,54f7f6fc,e673cb37,553d23b7,b8c23367,d6b7ea5f,98325ea9,150a100a,f5d2af49,2fa25b23,40ee9606,1553c3d7,edd4d870,5288b8cf) +,S(c7c2e438,d12ed0ac,6363564,8bf2899c,d1b39b1b,200ffeda,4ef9cae0,5d8381e5,93a36085,fd09ff08,b83d50a8,3b140edd,a63e2442,e4bf4d1c,7ae44963,c1646f41) +,S(12e834e5,605d6e35,8cbe550b,8fe917dc,59194c58,66b265cc,50b00e3c,38fe058,6a44ecf2,17f46865,2e0991b7,df3b3565,444e7e29,3a2d6378,61a8f3c1,5ec1517e) +,S(30f33c39,af77735c,749fd328,e228ed67,bd625fbe,79dc3b06,ab31c173,777308fe,29a00f66,1c998f1d,bd62935e,44794420,7ffd7b1c,24f63806,9206e1c6,5c3d9604) +,S(c5bd81b6,b057e687,19c47964,d55ab996,6c7ea99b,25c1c2cb,50d6fbd9,af492358,5a6b1332,8562599e,e87c475a,1e7da886,c460ec67,ad81372a,7ed39498,41225e5e) +,S(1fd0e769,9d931a80,dbcfaf1,46b5cebe,b9547f8b,b7fa75fd,b2bac9ae,ac0908ab,11770838,88607506,bad87ba6,38c9ae26,d79a9dc6,6746816a,b9f21d64,fea96838) +,S(ac14a06a,4679e9af,b2ea3aea,15f2749,bc9610a3,b576a506,f96fa41a,76df97de,5aafae08,5b8a0a7d,48ebb339,f4dec906,21bf5162,dcb85100,eb7524e3,a65a4921) +,S(ad583074,13a4eba9,ceecba6b,c568bfbb,30566031,c06e8e97,5c5d992b,9ed2bd33,c2bda9bf,d5c87e0f,a663a40,34162dcb,29b61800,c1dcf02a,c11fe615,25af1772) +,S(5a8bd45d,6fd468dd,41ecafd5,aa072227,6d0176be,81b92061,b4277b73,32acfaab,878a8d5f,7903d74f,6abe28f8,d94d4767,3698a7e,6acbc32d,9e92f9d6,bf31c2d5) +,S(6690c9c1,d9666be4,56d3540a,6a2ed706,372256f0,43265478,7b54e56d,f28df74a,7ad591,23772578,999c90c1,24704c13,a7193b62,64240aef,63d12d88,340762a4) +,S(3c051303,c113779a,6137f46d,38d1175d,8778e460,8b1e0abb,f7bc4539,80b64a2f,9d4d04a0,ad1c772b,4a523c13,cc48990,c733eb87,993cdbaf,61dbf75c,4f6a96c2) +,S(1fdff503,66319168,f5dc381e,8085ac92,223b3484,a8b362c2,26d1f00c,976f9f04,5cb328e8,56aaeb05,62017bf8,65da44b2,94ad7404,df11e117,8426b79c,25a49fa6) +,S(ae83da7,52ec2098,a4a593ac,f99dd58f,cd48da14,361feaae,6cd992d3,96b4fd8e,6dc92b41,f1e1474b,a259e96b,ec4f2b36,108745b9,a500ad9a,edd9c828,4c3d129) +,S(c0f86e7a,6c0fee54,a2f73d2b,6b1522e9,fee994cb,d5089886,d98a4748,161811d7,4aea0b92,2441c184,c347243e,5ad5a064,ba00768d,52d7153,a5e0838f,f497d551) +,S(8e5b23f8,85d683a6,a6a657ed,d2d2f403,1320d4c0,83340126,d2958dc2,4c5f5ba2,25c6db80,477f37e0,ed6c6e3c,c96b1c7c,f9a7ca16,8e940e8a,b2946c7,3b02e61f) +,S(6672b4db,bb16c672,2592c239,7d9ea25e,f081d48d,aeb42c89,ae6c42bb,af09b3c5,a3778252,e239ae3a,f64e3b91,7f646181,4f71753d,b4bc958c,b5bcd3ba,4b5b1a4e) +,S(e0af1a1,b894fe1c,1f7de814,1a393a3f,b12b31e3,fcbd8f2a,356e61f4,402d76d0,37913973,b4de9a2d,23f4f795,709fe825,8eee8aee,afec5996,83d924e7,21fb9b0e) +,S(94355dd3,c3d73a1,cabdbe7a,295cb015,335a5a79,dd301718,10c245b3,d0c840ff,31e96abe,22a16033,56681d3e,e5e8330,628d8090,bfdcb925,79074cb6,82845475) +,S(fc340c8d,1e3e2849,1470dfcd,1c2fb445,e807e1a3,9c525ce8,141b292c,596d2e36,738e7213,7580eb3,615b7eed,9b069cd2,b644447,24696a,7cd22257,7a931464) +,S(c0c4e03,61d923fc,4201872a,1ff525c6,1697412a,7bea7a92,596e9204,f1af90c3,25c4c2c6,d6593ef7,ff5f04fa,a5b0b2ca,736ab33f,5c36dc63,433821b5,382fc4b2) +,S(81afd4a8,d666b97f,dcdf0d36,f2dfdf7,bf7c3322,69728b75,26dcb3aa,df51365c,b7fe7653,2c8d48fb,8c3d0382,68d57839,edf80cb5,732ae303,5c1b51c7,cb8d3efc) +,S(140b32fa,62130c2f,1d49e39d,15f9c64,f5cf54af,3a0c65b2,298e91e3,21b9477d,bac2aca4,c96d4363,12107b2d,8996875e,6772eaea,a5070920,39c1171b,9113b516) +,S(17418ab7,46f1eaa,b98725ab,68bca72b,9cc645d9,cbe0835e,4bf91a7b,3939b98,dc964031,b1292c03,117a4ce8,b3341e23,da54a539,fdd31126,41706257,bb9382b6) +,S(8f0222bb,6cbf7491,12b95780,b50077d7,be2a27ec,5bb6dab4,923cf36d,3a12618d,8df2a149,abcd276,31265890,471094cc,fe6bd8ed,b75c2364,6f7dd54e,30c4c6fb) +,S(e3965324,1c543ba1,2d0ca0ad,88c26ace,b265f42a,41d2b7d4,f252ecf0,a48275d0,44467da5,18786654,5722fa15,36c187a6,f67f2e8f,5a424336,b0ce8bbc,a53f9cca) +,S(6a4b614c,41c4a6d4,ba4f8c53,26d08bc4,ecbc72cd,d2415c3,b7caf285,acb07c1d,76dd92d6,3f85e1dd,685faa18,283f8667,2425de4c,95a7985a,cf5f74c2,7b29b576) +,S(afdd252f,82037cb1,928d896,74f3ff64,57b94412,b563a4e0,1a32cf2d,1afde412,d57f319,300a6f93,1155b0b8,3dd83a5e,d2b4a0e0,5d58786a,8024627b,73360609) +,S(65adaf88,4297a087,6ec0d433,ea82bd5b,9e3590c4,921fc2ef,d1fa0b12,cc74808,30e4ac9,77b97c4d,b7516c02,df65de7c,d9e8ae08,6146716c,3da4b26b,eca17033) +,S(eba0dd63,c667395a,9e9eda33,93f5d101,8462b957,1aae6a09,cb723e2d,a45704e7,8314c569,49b7c144,197647da,baf857ca,a164e385,62c1cf46,bb30e7a7,a8dcb680) +,S(d3341d4f,1f967f0f,10932a5,351c6c22,c748af09,1d547cc,2766e6f3,1a9f570c,9694fb83,74177e3d,80775206,f58b2e12,32b87c9a,21f060ec,19152435,45502951) +,S(1596b717,8dceadc1,b5f3a5de,89c089f,62506b6e,2c6e49a7,f1cc4a11,e502079f,97157538,2aba92cd,8f009de0,9dc143c8,51b0f3ea,31067381,48a34858,8c085d49) +,S(138c0bbb,17c63e1a,a3e65b50,3c602d8c,74178847,8dc2bcce,65b84cfc,95f7ec41,bdf88a3e,34f69fc2,415fb95d,a4b6d3b7,f159651f,36a2d4e0,b4063e5a,ee86dafb) +,S(7d99662d,e6274432,65ab2842,a4ed79be,480404b3,1b847c01,c557e277,ee073176,e2ceda2,bada9b63,ff2fc022,44124d3c,b83dd4d1,f3fb74b2,763ecdb6,46e4cbf0) +,S(9e3f4ea0,b1db451b,7d713eae,35802229,fabbbfd,6f6d0ab0,af7483a5,37992e63,a9023199,10301c3d,78933143,b54e87d4,1419524b,16c9c00c,5550fafd,e6be8b65) +,S(108c8cda,d6ffc3d,b0863a66,43f0a4bb,efcdb0c7,202f630f,f971a7ce,dec3ff40,847ab4b9,8fba1fbd,15f6bb2a,4b3d1038,726c2d66,f4c9b8e9,f740af8f,5067d95f) +,S(5258a6a,7c85d4f3,e650f0e5,1e2d8254,8a768c0a,f276da55,27ab0050,6e97e710,e5605a14,31c8941e,4f2aa3c7,9ab94e3f,ffed156e,ba2159a2,7fde377e,e2ea7e26) +,S(c40820e7,f46acad2,5bffcc6d,745aa3e,7036f26a,b6ae85f0,e3cb8f95,29dc3f3,6ddf9217,88249ac7,6ac2c9b0,1dc5e62e,91587d15,c76fe26d,6d7c3b2f,feaf3b12) +,S(c135f50f,160d04e,43148abf,d76509c4,e55aadc7,554e4ea5,823e013e,a0490da7,f9a597a6,b26a1485,a7d5a91d,486d099,93de9a4,6484edc8,72f8f4be,710aae69) +,S(484be5a8,b903230f,991c3118,38d3ebdd,9759f5cb,11a9d0a3,9bb11a03,3924268,18f80a36,a3d70e67,5bd65253,a1ad3e40,a3152d55,c1141315,57f8585e,315ba462) +,S(af67562e,998a4032,77fc5827,cf222258,cb2f23a7,4dcd0d4b,315564c3,eb66da9c,dd5bf89e,c9b2c178,6adea201,d36f3a66,771b3f2a,cfba7acb,c30024fb,fa73ad6f) +,S(38dd6cd,475f2808,938d92be,8ad0c955,f3cf3255,c3602b99,3c177e06,553af411,1abcdd02,d82cc0f,680362bb,f898bf89,304d681b,6bc3afcf,65454ab5,8d44214) +,S(ee37f0ab,3db1f9b3,2da0031d,48f53766,3530b68a,f47bdb87,679426b0,d90fa6d5,6cdb12d8,136fc9c6,2f025cbe,7882ef21,4e7b09dc,9fba4cf9,b021c4d6,610c0397) +,S(670684dd,fcc19f15,ba9201b,ca36d143,47dabf31,bad07e8d,68e6fbd,2630a98e,77bd28ff,a9699737,1304d4f,82d29d1f,a69dc123,6f2ee438,cffe3f2d,358ce706) +,S(1654f447,78026345,64e3608,bb29004a,812ea39a,d96830f6,66a92f5c,54a79359,11d91962,3f81fda0,36d2d021,607d9750,cbd30359,83c4f47a,21fc8116,ca93cbe9) +,S(ccf0a89d,429a0274,7b000326,d62825ec,6978f24e,8f92f490,e8cab1ab,ff90bfa1,5f047694,375222bd,5968dbcf,a331db73,85b4df25,72791c53,42c62467,3d84400d) +,S(45d36700,32ab11c7,897d648,67ed4d03,a9504461,bf28f3df,7e1276fe,4c1de796,67e837fb,37108844,2338086a,d1506453,ed1f37ff,fb14e617,93908c7c,2a8e6fa4) +,S(9af3b6e1,627a2ffb,c18ddf33,b668fece,bbe7ebe0,986df82f,1b2fdfa1,56dbc565,55e9562e,882f6629,1eae4c6b,5a82b0b,b5bc2cb2,b8f884bc,3e45a126,aeee19e0) +,S(ecfe9d5e,d3b9fe15,c320e05c,7e0f3b1a,5fdaa9a4,5e1ff99f,88012642,a5d45b4a,b3cc1fd0,e0117151,f53ec671,e1d207ad,5f2b0755,8956cf28,2be5228d,db5d48bb) +,S(6e482326,6ef64478,dfa30c6c,f3a951f9,fd9d3108,dbe80e5d,3cbf2217,70f5483c,97a3f599,906b1738,372212da,80309562,d3d4179d,d2abc2b6,41ef2f4e,6561095e) +,S(3de89149,f6c939cc,5419e4ba,f0baa93a,390f01a3,4ad0fb7b,3b170e54,60a380c6,e9a07758,1c4617c0,b996ae3f,b250b723,874b66fb,85a6d826,cc5826e5,bb068491) +,S(d4d28193,53ace188,703643d3,84622505,d9020459,a600349e,69016cf4,faed2e25,9a494bcf,e15bcdb0,97513682,ef09890a,424d6bc1,ad1cb73f,123ff5f6,7babb364) +,S(f694a819,fd0f2035,1193eba,c18e2db7,9c219191,2bfcc60b,6af8e067,2281095a,d80d1652,1e43f18a,4b663898,bfce8670,6f53436d,a30b0663,9ee6f99e,ca87e667) +,S(af8595b8,8de7c459,7d1d1614,ac897de0,5dd9ff05,593dd3b6,cbac81ce,d2e1fb5d,e9dcce9c,83ee7217,857d5ca5,a48bb720,69d467b6,897be9ac,658dfbef,3d40e6a6) +,S(df4177f6,a7deccf4,c618b710,b096bb4e,b310e4e2,470b5795,6a633154,8ae8123e,3638e20,5d42ebc6,7184e567,c177f479,18fbf9b1,e4f69435,487b289c,35c7fedf) +,S(ef50482,30344ae2,70ec6d30,f4daea23,ce7b64bd,b101638b,5a52ff3d,6dbe9fd3,a6eec78f,e38a2e6f,a9c062bd,4ce28dde,c5d25fd5,a3204281,ae30d79d,99a2658d) +,S(f89596f3,ddd57abe,3344080c,a6d85d0c,492261ca,7a698aad,ae00dafc,75615954,f8d7d2eb,45dc2b9e,a0979550,8d9da016,20b53a19,b4150ca6,36bf0f86,ab3dc0dc) +,S(a7c2ffd7,50b99bde,92ac1419,57d8df27,56ca49e9,3f4c7434,b24899f1,24fb3cc5,a1672ade,aadad853,47d1440,d573e3dc,91987d6d,ce55c67d,665402d5,f8b0a289) +,S(463f5f25,b5c63801,a6b1accc,6662e6de,5256fce7,37e1c875,2b4a880f,19ceeee9,858e4a68,39eb48a7,f1a7de4a,514fdb46,1f4203c2,65e308d0,3fb9770f,1f8f13e5) +,S(4c99bf38,57073c27,cc92314c,f260dbf9,e0f4bb7d,1a5ffadd,a808783d,3bb602b8,aa107422,ac7dbbbb,f6e8064d,22a5526a,96bcbca9,9dbaac33,c1f35b2f,c6df568f) +,S(f6825035,64438569,aa7a5a4b,e2468453,8d8bfb88,f7e983d5,33ebffd,f8588520,84ff2ce6,9d79938d,fd910bf0,25a2fe8d,e6013c03,74784b73,168049e,c851cf15) +,S(62ea02ca,16b2e528,2f913a,36463494,c00df046,8afbeb34,cc9573,b71577fc,36be98bd,2c83e8cf,e0fc1aad,98ffd9e2,9ccbad8f,a25b9da8,23de20fb,fe91f9b3) +,S(ea34600a,7591c57,d0a7e351,de6e6d0,2c72220,62a980cb,bcca8966,356a2984,25eccb4f,a6102f52,60e4c545,57aa960,b427e372,80c35b8,edad5f52,1bc93aca) +,S(5b76cc79,2e78f177,97b32c46,92f2eca5,1ae1b7be,a753ce98,8e58d116,6c667027,2e01ba25,799e1b9b,3416493e,3fe9fff2,c46e634c,2175a30d,7458429,3ea60b5e) +,S(62a52d8c,d8562624,48ce5315,28213ad0,6fc6044,b6490db7,c27b7662,bb66f07a,e8f5e0aa,aaa65c7c,2b51e665,f3b31157,54ab9fdc,ac492ee5,fbb2a348,d8db5376) +,S(a276992a,5e155e29,d091e05a,5f0513d9,ff2dfbee,6ec1ffd9,a91f55b9,bca641c1,3d480cf4,e3f6efda,6cea9cc9,d769b16c,d1f3d64,23aefe9a,abc82b8a,adb22e48) +,S(bdb5fd64,bc99741f,a2a672d4,a895aacc,98886a9a,d38a486d,ed1915f1,f0b515f,d9744595,ae6e1e64,5a52a094,75ad094e,6af9655f,185ab90c,c03262cd,39794f93) +,S(cd6c6829,9d2b1c60,9b70153a,45259261,91b9b9d0,9fcf0682,d312960c,c3f82c04,2178ce3f,1bc21a2f,7accf32a,b20d625a,182f8733,e460e8b9,e1067dfa,fee6b36e) +,S(ebbfa9e1,8a4107a2,475f99a8,672be581,f32426a2,d774acdb,efe501c0,af97a0f1,1845a5fd,d71baefa,64cdf1f,d1211158,a70752b3,adf2b4d4,b5bf1a9f,7a0abdf2) +,S(bd5af866,4d51256f,455a3190,88b754a5,34223135,1491f763,3e090bd6,27414fa6,f8b5bbf2,2154786a,29f75090,fca2e149,60f84b47,50ea8db,d7c309d2,52233f3c) +,S(34ef0b38,5a8e776f,1c3ff95a,5852027a,ab6d1da6,6201548a,fa181c81,55382b77,958180ce,9afc501f,84d4d3b4,eb556ca2,e6ae8dcf,f949db6d,33cca5e2,9b357280) +,S(4b5f6663,11e6956c,e186fe3,85f00069,c0dfbf67,e4130bda,64e0e89,1abaf471,a6cf3571,2e790d5f,b500324,773281c,43f6d008,f6578ab2,b48fe4de,1ce3b545) +,S(cb22489c,bac94ccc,887a1d7d,8836cacc,c8c2a43a,4e09595c,39cc6064,ca04546c,dced75ef,d7ee6ae0,18ff2690,9abc82ca,da74e823,c62e4268,606334e2,969bf94d) +,S(b069007c,4a50bfdd,38ebcbe4,31a952ae,5356d63a,9f4179b5,e4cda3f,fe478c42,bb90d5c8,e66c6194,ec55acc7,6dae5f0b,dd498746,2d24a265,c314e93d,618a0f41) +,S(18722ce2,9d9cf99a,e52a420e,23fd8e85,e1582d02,c520d4f1,16c2b82d,464091f9,9fe257cb,5cd5f644,183c8461,ac2dde6,94cc84e9,76d9c623,584a9d94,40fea12b) +,S(a1562afa,6420b34f,92a78951,e9ab1bd7,8772a181,636df487,81bf4bc0,b16bd196,ce4435e8,7105d006,9b353734,5a503e0f,a692d3a,8571e8b9,66d9a722,48ecbd1c) +,S(f466db58,b4fae060,b12b780b,df11c7e5,ea8a08cb,cc50e68b,f5d85926,b9f3cd97,c86b4153,45515a2c,9a831ff1,d6377a8c,cae62456,f207df2c,42a1e767,684f79a4) +,S(686a1d05,e2bfaac8,e31def35,21876c81,27be2ad1,34ef3dcf,6de52778,37278176,111404e1,7f2153ab,43597a74,be1c278a,998b3695,5f4d465f,271a6a46,8e9e8986) +,S(d8433d5f,e5ec423c,73bb3ec4,95d06cf5,3a77474c,1e97ff97,f72a0457,9a60926e,3df114d5,a9d63dad,ada0ec4f,f98cb8ce,f1ad419a,e2c23dc2,f24048b4,1879be1c) +,S(3a9a0aed,4581937f,fe49392f,488053df,349f0194,9666418f,16e56fcc,533cb73d,c9db1a90,2d6676da,251b4be9,7a643bdd,d55c2b15,95ce51b3,281cc866,40cb558b) +,S(b35a204a,28884708,3091abf3,34be3696,b1082fc7,5caeb0d5,18387aa2,711a4190,65f951c8,78232345,487e8e,376c22bc,e5d9e8d5,ac04ecbf,24cafef9,4de358f8) +,S(81ff6fec,11f48691,59a2d23b,b2a6a9b5,68c5e6c5,1df9905f,ff73e1cc,a2c505a,c7b794cc,d657519,fc05632e,33e23474,654f1344,6ef1b4aa,1a1da18b,4acc1e49) +,S(3588a9e1,7feaaca1,a62fcdfb,3952beba,43116167,bb238f10,a41fdfa9,bc316d8e,acb24c1a,58ed9a0b,9744fa76,df4742b9,b440347a,4b4446ea,a3e55234,102d4789) +,S(7eb13fdc,9588b724,e7cddaec,498a8b15,d57a49af,529c8c9a,cc8303b5,e81f91c0,89f6ac3f,38351f7d,e4b293e,f61a87a4,2c08a4a3,ae0c160a,563ae5af,dc62dcfd) +,S(2f68c6ef,b363459d,862710a0,a0ae67c4,afc3cc00,85f02e21,ca4d764,3c76e00a,f8be9930,3a3aa7e5,c50d3f53,9b88bfad,60f05fb0,1461d7a8,225bb21e,18616cd7) +,S(b11994c2,5e3e6d0d,917ac215,c5f39606,3b9b764b,5dfc2b75,ab8ef880,3b57d802,4a7ae35e,c525d91a,cfbdea6f,cc9afbc9,b3cc8c80,acb4385e,9bc20158,f9f2b55b) +,S(d8e7881a,e1e4d04,c431c097,25dd4cd9,b4efb4c4,3896256b,7de47fc6,3a3b30bf,ccaf57cc,138f0bbf,5dbde16e,91d14875,c0d5ea,3842e864,be8de17d,875fef67) +,S(88e02abf,a37ffc97,f564cf3d,8a086c8a,62c05720,802319a2,30ab7cfe,b448c478,ec2d3169,15dd0c2d,6f03f851,97a96f9a,6c0772ee,df0c4524,c08f58f2,39c89308) +,S(ad258ffc,b42d127e,a875b181,a8883a5,31d18a64,d75a6dd4,4111d697,90752d1f,acf5ad9d,bfbb14cf,a25748e3,96bf23eb,aefe1bab,6550b234,90ca0278,276e9db4) +,S(a2bfdb6d,38159e5a,604d564e,af29cf09,a0a8ac79,1aef5a63,e1c05da5,fb6a0c39,7a45c5c,a7ee7c0e,74c05914,1e3d898f,ab62a8c7,31ca0a66,a937ef55,51dad999) +,S(7c7bb792,ef21cd53,bcf33a82,6a1ebf93,e9f3357,51131f9b,36f659d9,594f453d,bc98b32e,173d91ca,e9daf137,766c5ca5,6e0434f0,e2eb070e,7fa7f8b2,e7364635) +,S(40a2000c,dc0c1c9e,4c037a3f,3113b48,f26730ce,11e03b1f,d2f07217,7816f8c,1966929f,210afe16,9daee99b,7b48eef7,27e1703c,8bf42006,922c0496,888b690a) +,S(6427d169,cfd7e9fc,1b310f68,e3371720,28c17dd7,c6d5a32f,4ed6d41a,634f3f1a,b1a71fdc,6a030ca3,d7dc2ce9,27f3b9b3,ca7169f5,2fdecba4,bc85e32b,4e52fcff) +,S(723013b4,24fd897a,1e8ab77d,ee0618c9,3c832117,94f8b822,9d7a9e51,1ba8194f,21acfca6,e5e0cc31,479e5a97,17494692,9134f2e6,ebcef2ac,c7779251,77e9aede) +,S(1b18b7a5,43a284b8,3165bfa8,ca947da5,376fc4a0,8f4070e0,a20aa905,fd12acb9,713ab4fd,9e0bab6c,aadd2f63,1c5ef168,7cae85e7,6146319e,94b19a1e,f6a69584) +,S(65e5990a,4700f51c,9d3e61d4,26c92f88,5506817c,d4d60c66,a341cf91,9646ff81,2ebdd818,f69cd135,1405c63a,7160ad4f,17a6a7e2,d4353db4,7b554eab,3e737819) +,S(eb131661,eb78d37f,92a851f4,506c43b5,1f2a155a,dac7eee3,b1dbc29b,a0b1250c,45f2f418,47d2258c,3f78a2d2,794e9aa8,eab23395,8debf0e,b1440d56,dc728334) +,S(f20aaa98,ab7d6f1,d6de080e,ecd0bd28,b14cac9e,7f27c931,5576b039,16777203,4d0dc753,84c942d9,347f007d,543bc399,ee01e84,7625d5c1,a57cdd67,79c4dfba) +,S(9994a963,ef21ca0e,9657cbcb,3da57f3f,e28ce389,60ae5dd2,812b2949,96969047,93d75bb1,35572b75,4801509e,5b64858b,c0a415e0,3968efe4,2e558786,8516362b) +,S(4696ef39,95e5818f,d7894737,2fd68c75,fbb455fa,8477863b,b2687fca,fc2cd7b5,1cdc53f1,c52112c2,f58a6f66,7c1e4e9,110d83f9,d765347e,a724c784,d8e5d5ee) +,S(7b052f1f,e1af9537,ab3bb5b,3e0e510f,7e101cf0,999f85be,c403fd62,53e68d25,69c7f158,4b6c36c,f7d881a0,fe4efa5e,3f879753,641ce0f4,3e73bfe4,77ada27c) +,S(99452d74,3311867d,1d86c1b1,decd1ed4,7192a58b,3ef98cf0,7816823b,1296abc9,ffabb50d,a1a0451d,36b811ab,5e0c55d8,751a1851,3ca8bca4,8d6b3ffc,61ba36e3) +,S(40c6fec6,5ded4688,31f72de9,fb5c7f67,32c0c170,29f19b36,b00b0f85,5a12424,17aa0baa,eb3ba6e4,c5000e96,c3eb620d,ce1dfd81,b35a3e79,b27b8246,97dd5741) +,S(b9bd9e2f,c55ce5dc,2e46e4df,56401c72,e01ac3d5,201a3cbb,a6609fef,ae2e827b,f545efa7,f95e9a60,72cb9750,6f929b4c,e0360c8f,a9f058e6,5b87bd55,a72abdcf) +,S(867c0fa9,f885935,2756e3e4,11666eb2,59a416b4,7c2ff329,e30be462,13178921,6fdda875,4a50ee1b,d229d4f0,fa8876d6,9caf9fb2,a6af19fd,dbbd2a81,5dae486b) +,S(1cbe8374,3decb58f,f2fc9668,7ba45c64,812507ec,c2f71d66,eeea12c2,92fb36cb,799533ce,46d2c091,d0b553b5,18c82317,f516049c,4a4f50be,909c875e,b0bbe21b) +,S(c654f9fd,57426248,fd24097,2595d71d,80cf771f,cabed8d4,63bdda8,340398cd,898e9224,c9e94d14,3f96702d,c296bf50,9b2cee37,da574bdf,b7c09cec,18357a18) +,S(49e8e14f,4a9f09ff,48725eda,85ecae6c,3fe3400b,81012e00,991f6a69,2d75083c,815230c9,284924fa,57d08944,2a30c61b,8ce19644,7a8ede69,fb645864,ef35977f) +,S(43a6ecde,ed83f1fa,8946f584,99e71bd9,978f610,b46d1613,c15fcfc0,f79786af,2995f70c,11eb448e,68eb3d10,c84b36cd,7605e249,1df1fa3,2e9eb57c,c0275482) +,S(96861d91,678e5004,7c491950,5bbfc70a,e342c3d2,361729b0,4d0bcb5f,d93eceb5,6845ec37,9bee6269,464b2e9f,156ada30,c518bb8e,105153e1,c3b3e948,d38078e7) +,S(3c72be53,c9f82add,504a1955,7b9560a1,7716a058,26063408,79aca60,c55f4515,e584b72b,cc4744d9,6a00dc44,b03ba61f,c2269731,a8178755,2a6dce8,25d31b81) +,S(ce4b4d07,deae1fad,33192544,448ac5b2,77ba7f70,27b81a08,d7f84581,4f71787b,2013299b,2c744a5b,da6b243c,d04d95b7,e515848c,dc28eb40,892d40c,210bd1b2) +,S(37984db1,6d288866,78e1804b,9c94ebf8,f3a1aa05,1fefce96,65712f98,198ce116,20a25966,8ed14a5f,fc3aac09,6d2351b3,b6cb19ab,da4c833b,4a2a6c68,55d1ce59) +,S(ac01bcf,b02e627b,2c9c931c,f87beb2f,4ad7328f,9caf627a,2bf695ed,b7353acd,be4eacf4,77c92348,fe0feea9,3075e93b,bb3633c6,6747524a,e387df82,176ea252) +,S(d5d6af83,1a81b72f,efe5618b,ea43335,bf1d81f1,73382fda,860260d8,1a2faa83,865f9ee,4ff0fc6b,fa761709,db4c67ee,a3213d07,21b2facd,fcd8fa57,8945698f) +,S(3c16399c,4de35853,a6dac8c1,8eea4b40,92a22a8d,5e69ed0c,13b9c2a4,3cd5e39c,bffc2dbc,c2ce4b04,6a92b967,d1a04b5a,2fe40be0,fd9930d0,45b51f8a,15b53edf) +,S(f67018d4,23e50a73,68045b0d,ce803e35,a26d9a5c,288a3a7c,c25ebb03,dad28187,ee97afc5,1c73531f,ea8998f5,53086a59,cc67c6db,955baaa2,8f57153c,afc4e772) +,S(de67026,529a32fa,b3ae79f6,ef9ece7a,47008d2,46f89053,e9339c4c,dcb53b30,4daa8700,4b055005,90611f78,43d258b9,516f1fe8,61cf06ca,d466e000,d3a68783) +,S(a133627c,af6e7ed3,1d267608,19b69f45,7e75ecae,2169284a,48b5ee16,b5dc8c10,755ef12a,fb5c071a,36dbe2b7,1f858d87,31c93d81,d271c999,8f632982,d7e97ce6) +,S(d255c1e7,ccc88c4c,33887c9c,b9c15a2b,52b08471,90ad1420,5fb5909e,d36059c7,83e3e1ca,99a386e8,4b119391,2c20593c,f9573996,d42cb7c3,6db24a5f,cb413080) +,S(aca6c69b,9ea17803,4af67422,71b8062f,77e6dbe5,1df2a570,65fb3057,ea185b8c,40cb09f2,adef414c,816b22f8,d7a59f8c,f5197fb9,b31614d9,ac172436,d0f54647) +,S(fbc19c84,3b656fcb,21d99c3,5289d3e3,2bc58fdb,c2404309,a9d8831a,f2365f24,cc22999f,203a4fae,59eac72c,28bed6d9,291f204b,707bffca,ca6d8359,1e403124) +,S(ea308c88,c366677d,5e575457,cd3e6978,5b491a02,c542dcae,5dd5e149,2f839c55,c1916831,2f48555f,b80845fc,ba89eee7,a7967807,d10c6f6e,b516c190,94873ac9) +,S(d911d62a,33fefc48,abfd4409,7ee2d32f,d7e85816,2a8a00d1,342646ac,8dda6cd2,f160f933,41bb32f7,401d153b,4a2decf8,b793fb5b,4d5520c9,6d9cb9e,cba79aa3) +,S(bb75b497,7d698442,7b0ac74b,939ab3d8,fb94304f,602e102,1fdacf22,27022a4e,ee3cc171,8e9190df,9b45d8d3,54eeef9e,11639423,dc091128,ae09e451,fffe3468) +,S(358e7639,b4031852,b983b5c0,a6c0d33e,5edb304a,3f8bd15c,35d35794,e2cf90f0,5da4be1d,2e9bef5a,5da3cc59,d3c4f85a,e6624ee3,17395ded,398147a,12c56c45) +,S(e098fb9c,440a5cdf,bc570270,4b57eeed,f3087b7,e196522e,4b194618,f3c874fe,9a5b80e6,b22dd111,1f824c36,4830e723,18b7825e,2f2a0fe6,ca460d0c,34eb6449) +,S(62d607b2,d1a16e4e,cf60480a,be9416a7,15d70b5c,56734e7d,1498ba03,7632528e,70c5f4d1,4f5c900a,96291a4e,d0f795ff,439d35d5,2c5bddd2,ab10571b,1d7d20c2) +,S(a630c5bd,ec76f869,40842391,cba6cdfb,9109940b,e1034b87,c6a1e5e6,9662857c,8f28f55e,beed2883,3e347b10,92ff8938,133558c3,bfeac1f6,a6b938a4,c783b79f) +,S(e2a164aa,e17cb0c4,8ae1e911,872b0b3a,7c0e29f0,93cd5e18,97145211,d72147b,23ccf99c,afd1bfbf,a7ce1ade,1590d609,9a423b26,381f5761,c19ba373,290e6193) +,S(742526f5,b95051cf,2ee34994,8385fa72,425162e7,e46bba3,febe5ce8,595a8b37,d106a3be,638987e6,870acf8d,26d4f78c,e6aa0e9b,63e4eb19,114fc97a,eee3a12f) +,S(ce7837c2,31c32444,10dcc790,de465c06,75404a1a,68d23fe9,b69d887e,9c554f45,2c0be877,20cfdb11,8c37b2de,a2c355,d12279da,58f75570,7e738867,146257a3) +,S(601167cb,2788b146,998f0b91,d582cbd,27f4b866,40db7ec6,7f26214,f3ab9212,50525e40,1f2da57d,1f605f34,8f11ac23,19ad1827,41d7be11,46538e83,e03bbeeb) +,S(d2f657da,6f7c3c80,9d2e5291,b1161d46,393009ce,e2bd22ae,32b99eed,f76fc728,6df58d32,b795b6de,2a9c3b15,f4f1dc9,4e6e6757,e01891e2,79acde59,d13e3e75) +,S(e9fb6b74,f84973fe,7c7a0924,e0133b92,bb4c22d1,ce9a94e8,433f0c72,2a86e00d,f4df6cd9,df43c150,9d4b9580,eb87298a,551ebec5,2438597c,87dd46d4,3a8ad2c4) +,S(98d46b64,e43f3384,88c63da7,35af1141,e8b41981,b706ac5a,7aa1c0ac,1182afd3,3b2ce203,5bbd2cd7,f3206b3b,6aa3ac68,31e0e2d4,7f9e57f2,3e780fc9,cf865733) +,S(b358a4c6,a7130b1e,a00d8403,7164e68f,c6cf96ea,c6580ee5,b1cc2452,8d2bb5b,3bbb25ab,4645c17a,2a6f7e64,2d3952eb,86462564,5647abd1,2e80d965,be1d3854) +,S(fd8807c6,c456582e,d03114a6,2b42316d,4d0d386a,aee634cb,d33f2f82,c1ad6f05,c67d1611,e45c57d6,1f8d721c,437c0ca2,189488bc,f363aab0,f25314b0,14f896) +,S(cd53fa2a,1f989ceb,cedfb7a5,237addfb,2efe9469,8b6509c9,3081710b,f0db107a,47e61ca6,4d26e617,8192e993,411d0540,bf7c37b5,8c748eb7,6c1c197c,87c3f844) +,S(38cfdfb1,1b60a68,b00a4096,8f2da5e4,4a60868b,de9af728,fcb888b4,9a098c66,65f4f191,92667492,d717cfbe,bafd0076,59c08392,30da216c,315f2cfa,d3725184) +,S(cc179d39,1c6ab4f3,7fae6380,35886e2f,82038bca,768d1396,13fae8df,a167a271,a12fff68,84a967e6,fdd6e14b,4083c0ba,2a2bcf49,f7d6071,d708c70,4722b1f3) +,S(cdd61b33,75fd00cf,430d9d54,202c5c61,465fe7c0,a3f51660,ce74a3bc,58068c,46e5334d,bad31f3f,6c4bccbc,6812cf13,5c039a5d,d51c6516,49564f45,45f13ab) +,S(39ecf8d5,4fa9c3b,fef7d5e6,5ebe0e75,288f17df,4b33036b,d034be2d,fa5bdbbd,21991cec,ef62e421,70da3bf9,8b2f9bd7,790d5b13,25159727,a53a0735,5ab1d956) +,S(7b621836,342994d2,3185da8,67d47e69,a67a184e,925a3,524f5e7b,63639263,b08c269a,1569538e,653f2beb,3e6e348d,c61537e0,7afc5f13,f56d1f74,518b274e) +,S(28e5ec3b,38359a6e,7d3a965a,c5713365,44b91ea5,c9f350bc,d315c153,72133bb4,5bdc5a02,62734535,8621c1f1,492b3434,be731c25,f82c1a32,163ecf09,7f548465) +,S(37ac3ac2,3f6b2a1,a3a5a99c,707a6b8d,5f05e80,133ac522,107ae5ff,414d33c7,460c947e,76eb51c8,42bd0e6,6ccc0937,87f61bc3,554538b4,c2065fdd,533d0b02) +,S(275f5ef2,a4546ba0,9d96d138,e698cd32,78cf27f3,2ee297a,5ff8dd41,f16bea50,ca91a3b8,5b0a493c,a49168b4,c9eff873,66212b9a,c030fe6d,a9be42b7,45d0464a) +,S(6c43669f,a69bd51c,63cacca0,21c69bf7,9a94ef9f,3f0aaa92,3be9380,a6702e34,b416195a,1419771d,82fc2ce0,637cf5a,29823d1a,95614642,c93a979e,5ff3fff6) +,S(606c37c1,271b90f7,482e6ba1,81bd956c,44a44189,346bfa67,539c188,ac0eb61f,f6af64cd,3f04e30a,1b4a7019,c6caa84b,823bd00f,587eb58a,e190ef25,322154b0) +,S(e4136e15,b3fdf609,f779d0c0,70ce8521,2babc592,577361d0,47ada13a,2a83d43b,1af23c84,ad240ac8,50da2ec2,721531e7,18776ddc,5847edd8,b4d79d52,26e53125) +,S(a338d942,6ce420ac,c9fb29b9,cf572af0,72c0d144,46dc2c3c,75b9d5c9,f7fa244d,c88a4399,f6e3ef2c,619cd9d5,215d305d,3715b962,b02b29ca,231446cf,8ea7c40f) +,S(c454d1b2,6f77ad27,a168d032,fc1a73ca,fcc4aac3,ace31f2a,433599fa,7107fd9a,989b6091,ba2ec267,380c5139,47059d4d,2773109c,1afc21a4,3be54ea6,ad8f19ee) +,S(bbd7bd30,5bf1b36c,6cd6c180,2f41525d,75675d76,9352dc60,1a727931,ee6f40c8,3c3263d3,75bd412e,1d7f7d5e,72f73216,6415ef3,52d1fcf0,58e6c046,ceb46abc) +,S(acae6fb0,5d5b503,c2e3d841,19ce3bbe,1380b363,e5d8763d,3c520a3f,df39f7b6,6fab4b7b,daba880c,9167ae8f,5feb9aa4,3ca19f28,77ec5021,df36ac7,db730293) +,S(c9d4ba53,a44403b3,b06915f,6bd9bb43,4716a639,453797e,5b8e1cf5,abc78425,749cca45,6abc2a6a,4e970589,42cefba5,a2f55dc5,39bf4f3e,be5088cf,ae04bf70) +,S(3408e460,99f1a176,fd52f70,3c772f1d,a46d32db,246815d,a21826dc,c5657e61,a93bd344,de7afec8,2ea2842d,40fbcf60,732be8fb,738b8364,aaaab796,1e20974f) +,S(5e061a06,f97f61d1,5f66c3ff,17372621,4ce82af,3e606b4e,9f64fb62,e405376c,609064a0,bde996b2,d909e50f,726ed7be,b4698ec7,5e1c9c45,3ba18815,2915cb1) +,S(b12ca67f,739f4284,3a7adf58,d2a2f3ca,fd245ff4,b766793c,c79cdc31,45579113,b1deaf81,34f017f,b2bc20cd,da75fcb7,d219c353,98ee9887,612781a0,e3f3d1e5) +,S(95a72f2f,c241fa0f,c9500cea,d9cf069d,23820078,f61d4492,508d0fc4,34fc223d,832a3979,1fb9fd9b,79748643,64643bcb,b227c39a,e4cb5051,d136263c,293cd453) +,S(ab8ccb01,4b672660,b867e544,926749bf,7172a0f5,ac6317a1,a18b7d15,f039fc94,28471e3c,a2d6e77c,87700c4c,7e3df1e9,2fe91efc,77724df3,2f20ceba,1ba000fb) +,S(26131926,5261c0d3,ecfa9769,fa987347,1b9d4ebf,dccd830a,96bd160b,61b47278,dc9ab665,485133d2,59d7b604,5e1e4f52,9b099e9d,4db9f680,4935e712,f8402f66) +,S(87a4227d,2303f5c0,acace6e,96586b68,178dc65e,2c99583e,8e427ad7,167c4a65,5bce1d82,216355d6,5bbf33e0,9b3baec4,fb0befff,ebe48b24,cc01d454,7de6db8) +,S(a6576ea2,39af87ba,392a225f,bcec3045,8920b494,68c54ff3,92d2f509,519ce85f,deb950bb,6a767b3f,3603be36,6234480c,1851ae4b,1980f902,f8fec863,dfabde82) +,S(ed41c3a2,48285ad9,1642f6a6,feccdbb1,66298fa6,467b0ec0,ea256570,c8e343a4,dccf3578,aafbc34d,8ca5fb6c,b4482de,4b94dc65,a8d22845,ac800947,dc1042b8) +,S(227756ff,800f7eb5,4493181f,83050c32,9f27a35b,891a3bc1,ea5f0e89,b94e77e7,571c9345,e9e95238,3c7dc62,69aa0fff,46455825,a032f33a,154a89ed,e13a09c3) +,S(6f3b91f1,3f2d6787,454bc7a2,2ee780a2,3c251697,c0da9aa0,a03dcc3f,f03e2b0b,432b396f,c2dcd370,647eadde,ec058a01,53fac955,4b3f400c,435c4755,5e61afe8) +,S(aa79f0aa,767db1c0,3893c9c9,c75a1f8f,457f3f36,72c1d2ae,31e58658,a916fe5,4da2c69c,8033860c,14f8438b,8edf290c,5d02f2e5,153b68ed,fb945043,a6e6a1f0) +,S(48f2a720,df970127,2385a961,5a215d8a,3d41e0b4,ad439c9a,9d0453af,4699e527,11669dc9,26f70e96,e76178c5,7d698d05,b6e7da96,eef4e986,c4f6e6be,216f22ac) +,S(561d8010,a81a1191,3bb2436b,bbe0ce2a,6f1af6c6,fc064d57,59edaf45,c7f9781a,bfb2561,bc311bdd,707aee1f,af3d5c9d,faa9d564,a5121bae,9989665,b074f026) +,S(64d0fc68,6369a225,a15cefec,431fe434,1a424c78,85bdf2,51cccf53,9e266fed,694fdfa8,12f6bffd,b1c75baa,3b843d02,1b69cc8,20f2a8b8,69908a00,ac7050c) +,S(2b80d86d,341d05f6,218eb96c,fb227834,44bdcdf3,65cc3809,1bcba0ff,fa8b3d09,152eb516,2794fd0f,abf030cb,1968faa4,100e803c,e5b8046d,c36e3075,9317a8a5) +,S(62652ecc,daf7ff5,3aa255de,ecbcd653,7840a657,dd53e58a,514ec1bb,98c9b5b9,2a05c8cd,bcc4a512,1d2cafd0,6289fa14,178e91b5,b1fa1190,e4c7c13f,f50cef6c) +,S(f23fe7d7,69cd7bd8,5e0d97c5,4163e596,a0e7dce9,488e8f67,4ca6f3ca,81726ce0,eb1355f6,ecac2b79,dd299fce,c0f273fc,3767a3f3,3ac4777d,cb871a1a,99077e1c) +,S(91d4028d,1ea8e320,5718f427,b427c21f,4780a944,55ec46c4,2fb2a1cf,4772af1e,7a529f92,3756a212,24dcd316,bf9a3f6b,f5bfbc54,3b015c10,54ae51be,5c2e6b2) +,S(7a8fdf03,175969a7,80475dad,c43e5c66,fa75846f,63cfd62c,e82d2153,d185670a,b7b58ebb,fa0b2d3e,ec2a2638,accd965e,c7db6cf1,c847c1b7,9f0714b0,c1cf7dde) +,S(9d72d9af,5e9d7b2,7fb2b867,4aa35438,946c4ca9,eb9ea4be,e20b2eb5,e7cdb89,324214ce,d556acd2,3ac00175,f120d59e,50dc95e,96e6fda6,ff348bde,5ff7e701) +,S(33556ab7,bbf601ba,44dcb33e,aa5efc82,3c70f507,550f3d7c,22f4ba62,cf2d6bcb,a21d830f,233a657f,7857560f,c030f053,656aada8,f7812424,f38a2409,7505dcb7) +,S(e002b33d,93022868,60b39e1c,2820ad06,2063c344,bef98dec,3a9a0428,20e2c507,3133f829,1c81d970,f879d1eb,2128f21d,7540e135,31189576,191ac4bb,d83d99b7) +,S(9eeb1972,ffd49c0c,7982671c,59071b20,422a053e,394db993,8ef7b3d8,98795c5d,ae48763e,5ad78988,7a756827,4a17708f,8afdd8be,bc9c0316,73dd9485,319763c0) +,S(60f821e8,ad12907f,e445f049,141c7718,a495d1ea,3e39edbf,f0a73018,a5cb6854,6dc1b291,62b025ae,2a285e59,a5b406dd,927a743b,483454d1,20426fa7,50adb95d) +,S(5b8bcdc6,40f4a217,6d0661ef,f2ca5d6c,b1aa2069,557274c8,287fba59,dfd65a41,42ab52dc,cad04998,63e634db,ebaae018,c999eee4,c3cf05b9,4f18d218,23f21256) +,S(e764e748,4ec2a2ac,6843df3b,5316f29b,701b5191,778bda16,a23a20c1,69ed0cff,e1007e10,4ae52971,875bf7ea,9e9d9431,94c2e9b5,bc7b2844,7b7acded,de7d633c) +,S(37f0d948,48742a8b,e73ef1ad,495b88f,ea95f7ee,b343152d,85f9e442,771a22b4,bf960e80,467cf81,bc22380b,af2f57f0,d5938ccc,55f3f691,784be72,7fa68bb2) +,S(7ff13c43,7f2189a1,18b2095f,be268dfe,e1375a3d,f71e88b8,4cf5b94d,63b04612,10295e49,1f0a882e,aba663f8,f0202223,21c422d5,f3b453f4,8ab8bf4b,4319930a) +,S(74f6853e,f4a2d018,4cf113d7,62fe2a1c,33ff2729,5414a5bf,3f381989,551ceaa4,629f116d,37c1809,f4e2ecfd,19c2627,6deff6c5,b89249fc,d4f6e82e,58eeea79) +,S(d54d88bd,abdcc56,c1bb8cbf,cdaea6ac,16949256,f78d70f6,7a1416ba,b4cf51ce,996afb9c,5b36f588,812bad4,95c368da,f9e96035,4bb7dd1,3f457a6e,da159b59) +,S(a860ca66,3ecd7482,c862fac6,f6a7b0e5,f5f6bb26,ee950db9,2942fc89,4b6fbacf,3445137d,2047c17d,65b3cb88,8e1b0ba3,619db023,bd989a0d,c585a59d,14da7b9f) +,S(d794dc2,4e0e36fc,6f38fc8e,7a68cdac,8d547d42,b9667241,2dd7e6d2,c40f9aab,22a9a90c,10f1b80,e277be34,3c492125,24ebc477,1f838070,f2be48bf,cec3a7f5) +,S(7e28db65,2115f5a4,575293c3,d792fc97,9ea1adf9,dac468e4,60e5526f,6847657f,8025944c,16a12ac9,25e67f13,3835bcbd,33c338d6,824b1fba,f0ee001b,d79d66e3) +,S(d3f13a27,524f0c87,266f3d46,14d965a1,3865df67,5d20c5aa,99a4411c,dc6322c4,9a1025a3,845a4bc1,9f7cc175,9377c7f,e46ecaf7,53263433,baed836f,77e2e841) +,S(d845636c,db18d557,1759f6e6,bad6a60d,3a67141c,b0bfbbf9,33e628bf,8344c053,40de706,ef833427,80e5120b,ec6e61e4,a8a3726,32818317,729e60e6,3ab7e37) +,S(f40f53fb,c672573b,c020338b,71589d53,3709ac32,b38cb943,ed0ca0ff,e592e552,502145c,5f542a77,652a4ab7,d79791cd,e92f3e72,d9d0190a,2724e114,49b64e0b) +,S(2065a8bb,a0d61dde,921a0741,21ae5678,8766f712,bdb3c4c5,776af9e3,774120be,fd12cac4,a85d5b10,1aec6ee1,4b1301a9,950df948,86427be5,55f52736,3ca29847) +,S(a9b1e8dc,410466c2,df97cc8e,bbcb3af5,f981726c,2daf8803,ef06ef2f,a23e038f,b09dd4e2,77b1d10d,bfdd06e1,a42baf37,a5157017,ba026d98,fee13512,4a1c5419) +,S(c54ce1c,bbfa3808,f24b2661,793c3574,a58aeb0d,128d7e5b,ddcd98a6,d8c9bdbb,c1a2291f,d20e8a23,f4012b54,37a7be7d,5af5f776,bdbb2c53,193e07da,bc1a3212) +,S(41ad2d03,31f57724,6476d0c1,f2c46216,6156296d,8bfd3783,eec40892,835ec421,62777bb0,f8b6ba08,128f1727,9c237286,abc5d2a6,492b9c67,3edc903,7b0e3008) +,S(a8eddde5,eb761183,ef5cce4d,a7958b92,db28bab8,2f695fbb,597f6535,50048a3c,7f60d3aa,95ee5ae5,f4cf10ac,cb5729e2,bf89ba7,6b1070c7,ba385f41,a5912685) +,S(f1db8d40,2cee572f,6eb250bd,ed3d978b,1346ce96,d65291da,977b42cd,36bd073,9bdd0bdb,a546ce4d,774f79fc,3561c0fb,ca11f4fd,b46ab1c2,a7520913,f254f42c) +,S(55cee66c,7ebecc0c,7f22d03f,8f166b99,ec7b5e6a,776bcf60,b5f4d452,c861bfc7,772832cd,55b13c5,890c7ba9,96731ced,5a2e1c05,6ac89469,320c08f4,43159d36) +,S(61427868,7710db98,d4347d4c,aae4c70a,9efbfc7e,bfeffe5d,6f33bddc,4aeddedf,fe8b32bb,d0c7a7d3,b93dcb7a,99a5cc8f,e386bf89,7dcdcd86,ffaac641,6550dd85) +,S(9f3ac763,c117bd99,658f5379,119aa025,cd422ed3,b1ed2cc8,545d6f93,39baf4e4,41b2409d,cec0065e,4026e879,84b99d35,4eed93f4,15e8981,256e8734,a4eebb74) +,S(8510bf74,8f5255a1,8f408565,30f909d5,2bed111d,6347da9d,8da2a97e,751d4a98,2ed99b6,6af7cc01,37329730,1b0b63c9,f8732547,fc632eb7,7357e67e,df5549b4) +,S(d81fc0cf,9646ae0,7dad1a3f,e06adaf,1d3508fb,13af2309,c200c2e1,2228807d,cac833d6,c94e674c,a7aec186,42e4a501,ffbfed92,dfa1015e,c95740e6,57978cd5) +,S(32aa5e70,972a899e,e25e6c6d,e43c32ee,df07ebcf,e5ed13e,5095f7c3,3bb55622,38e82901,990a1e42,38639a42,66a93fb5,4368df0e,befe19a,7f234424,a8b68c0d) +,S(68f7b02a,ea38424f,decbbfc3,498c6193,62c732a3,b048800c,85d042d,b284f7d4,bef680d,90660176,f3d3d009,9f6cf818,a277dc5b,3d765a30,b7a4ee9,cf3bd46e) +,S(9437ace9,6b566bb3,87d9946c,2c32c06,f62f1158,dead214f,2b721c6f,b6e8888d,f8dee3bb,331e1e33,9963b7e2,316a1352,c8748f42,44463ffa,5bf2265a,243941d5) +,S(af40e909,85e5ce8d,dfb6d6d4,222d3c57,2ffae40f,53de2c06,55a74cc,70cd8dc5,2f08f237,3fc922c3,f0ed9d6c,b9538f4b,c661ccac,ea2f4975,50f47ec2,17d8e626) +,S(382e5a07,f1f236d5,ca1a68b8,f0fdb813,29e0393c,c375df88,f87914d,cef93c64,e24ee731,c0a88fa4,8ed3dba,87e97096,e0ec2224,dd657411,a9f1a9e8,2b0a6657) +,S(99fce288,c6ef1d18,ad630097,8ba82dd9,1c779a60,b266109a,288d51c3,978fe565,294c9e53,3cd42a54,c071d5c8,acb7edc9,897db8ac,d25b5f10,9eaf8dac,42a9c1a4) +,S(748326fa,c8dc9394,2de0a000,933dc18c,6ef92cfe,bac46939,f4405d89,627e6727,adf2d561,45581b4f,e706ccd1,8dc82bcc,14d76fa6,94ac8a61,a51d06d2,89e36d2d) +,S(43fef689,67074a2b,7e944b76,8f8b1ca,15aac3ad,c8f5590c,f1f02c3,afa82e90,5313cf6e,8cac44d9,fd548032,dbef3ab2,26e93880,644468bc,799c87d4,c0bc3f99) +,S(404341da,829f537a,c425050c,5ba93ca7,baa8a8b7,dfe51c23,e2ce7c72,43d57659,f91a0d59,bc35db64,b250adca,3cfbbaa2,2a82cfb4,d684e8db,e17484ee,af009f9b) +,S(3af33cb6,b4d553e5,50fd35f1,a0b569e3,eae05737,7b7d735b,545f7f00,d9acae67,42aa2cea,deab8cb3,b1ee9c3f,4b1b06df,e157cbfa,3912035b,585980bb,cf85279c) +,S(2e96133a,1da8a378,c138583e,86ba1de2,3450b285,3559a431,654ec9aa,1f64229f,3bfa5a75,4dbd936d,7a41266c,97472020,6cac86b4,d684bc1a,59dd1f27,fed8e76b) +,S(adc4b672,69fbb719,92bd6e22,3cf9ecb3,c9388b5c,45ffadd6,94c72e2f,b355984a,ed177eea,ac8cbd88,2a368fcc,4908ba4c,8a4054ae,3411d75d,b06939cc,72522a7c) +,S(68ac3244,49eac1e3,df997282,65a0176,bf6c6115,64daf79a,135bc6c2,5578b6e,407a75bd,b1e5e6be,a9b815ce,833c0be5,f5c462c5,c71a086e,59fbe0d2,5e7b1fca) +,S(5176afcc,b4235cc5,ea41eaa7,b657a77,bb383bf,aa71ef8d,d33990b9,9c2acab9,cb363792,9d249fc6,1c0931c,8a27dbfa,c8371574,52c40306,c3291814,ceb57095) +,S(4938cd76,e1aa6b28,2a89e883,8671e4e3,82d7bc76,dc4653c8,46323cd2,51d18542,2bfe67eb,6da39ea8,c8160621,158eac48,550c3730,664590a2,731247a1,399bc42f) +,S(9364dddd,dadbaa52,efc81971,75041c81,e7ebb48a,f20b82a8,125d85fb,a7fea192,ee568f7,53513b91,cf6720,2c45c4f4,181e855,ac0300bf,d7de30e7,317a6ea2) +,S(bdbc0937,243e563,df29781d,3b14d4ac,a664fe5e,70f3d9c1,39ef1b69,57839156,2a84b153,549c6d1b,27dd9ac2,1ab86f34,9ace0619,6f814d08,92a1958e,d137bb1f) +,S(b616b635,adf7b64c,43c4e242,32ffb330,bf28ee8e,48918093,9584c26c,28c82f2c,27fddaab,e5d47957,6344022b,68744822,eec7b937,d29b0631,93c7f6c5,6385cc89) +,S(55a3849a,50606886,abf6f0a6,5a3e657f,46031cd7,4c117365,8f27aa14,326f3cac,4a522c0c,17fcd116,61b11d9b,f88e0ad,c7a5761e,e01db8ff,a7bc3dca,a7976b00) +,S(d53e472b,439dc5dd,c8ff479,ff678dae,95b2e207,c92df108,728c3783,f8818542,3f3f7ecf,df3d9f89,1c723161,75a57931,4ebeadab,3c4dccf,bf2b834,c762d30f) +,S(1e27dd,f6186285,41f5d8a1,6587e2a4,ed38c34d,8393a6c9,fc0a7c07,cef36053,280b223,da8d01c2,12315c1c,ba7dd8d9,96d3202b,91c4eb4b,26c802e5,9494378c) +,S(b6d9d97c,64ba01fb,e8a9d29b,806d8a6,42413bfb,fbb4ae0c,10d8fe52,7ae6415d,894875dc,d912f8fa,845614de,a2b09796,d402c738,ca1f3c9e,c0796681,d715b8e4) +,S(2c97985a,5fd96164,e4c4d9d5,9a9fb52e,b2e6df0c,77ed4745,3dca6eac,7550756a,b3526bbd,de58e408,a4f45dd6,61f5c6fe,2f82d2ca,3e2172e1,c99d1fee,93d44c98) +,S(405deafb,528991e2,ef924f55,b7e4dfd8,185de449,cd6f71d6,53025999,4caae657,e959b7e,59cecac7,f813dc1b,a15bb71b,4a4832ca,54026e18,479d71d9,191c3ad) +,S(4276ecae,a14c0556,b4573b26,dba35226,4fff2c3d,12a3e4a8,4937ae9a,3f687bfa,7611836b,d3b335b,66f92914,6df0de13,d6ecd47e,88369ffb,6c9aa493,e67dfc71) +,S(6fd734de,6d2fadcb,d7b19f56,ae7153d9,1ddb396f,e0c1e51f,ae31fe80,8a35556f,aaa647c6,92865772,f31fdc1a,3b430ffb,e1647e10,3cd5d629,19bcc905,ff7ae633) +,S(4f0a22c,ad6ebf6c,e6b444dd,35a54e38,70017bae,eecc14cc,3f7ca88a,6d4e27c9,1386d40e,680060ca,bb46d678,d2be7209,418d6f72,d3917e20,7b833124,29b43ea1) +,S(873ccb39,5c10f57,6e50093d,44879f2,687d9321,441d8a7c,993c1083,ae7b0570,b261d029,dbe15f4,ff70ee42,36f558de,8984db4a,608d45f,4e28d001,e564c5e2) +,S(75d41857,5be3709c,5c732073,24f36089,b87532b8,e91db4e6,70a89117,9d25e039,47e29f54,fa62ef44,139db763,4b1c8f5c,e027b0d7,e1ec3501,1e8c6dfc,dcd1a105) +,S(b325bb90,cea81ac1,c79df75b,e7615ace,9b2a9d4c,fa1f4504,1a47e0d4,30b64b67,3024fffc,2005699d,5351615f,baee8c49,8a319a19,45ac8132,71c609b4,23e14a07) +,S(436c92bd,a6c7e124,5aaffb22,62036329,ddb8984e,624f2469,b30fab18,1269ee2b,2a9f90d,88c01880,62a152d7,e7ed5acd,33f12e92,4e36fab0,bc0602f8,2c1d3e3) +,S(c0105c64,4e51d333,c7ed28b3,c94292d8,6d9c04f1,89b3827d,f1f22fe2,99bc51cc,d73bc012,1233ba52,ef9727b3,1249babe,bf63cacf,ece0192b,5cbd618c,c48a9d35) +,S(9f2a01b0,46109d49,d11ee109,5e94c281,1cb6f76f,7773141f,632b3a9,2e5f3f7e,1e260290,fda1caa9,ea315380,781f633f,21c90765,2815251a,fa70b169,e4b0da58) +,S(4d805499,23dc1905,7fd35a86,feefb937,f2b621e,48946e53,b8390620,3aef584a,2cd9c060,d66be813,12a3fd9f,ebb9cbdd,4fc23431,c3e0531f,4a026f50,a40dbd30) +,S(76779423,b5e5acad,55137380,276c4033,a865ae5f,9ada0f30,dee6986c,444a1526,9a6fc30b,4f4c5093,b343c8d1,aa204ef3,7c2a6d5c,712ad8d6,39ef545d,1eaa9a57) +,S(1ccc1998,33f8b121,18227adc,2f27c3fe,8d328b26,684b271e,85f8368f,40378881,da21e917,94851bd5,a8859173,830ddd0e,988ffdd7,f7dcb263,f6755eab,e2d73f75) +,S(afeea14,e8306fb8,e69689a3,d12efe72,949b6b03,8c4cdc70,c95bc351,1f999030,cafbd04e,79378032,47c71954,d8c2a11f,d60e53b,35045507,8f6701ed,621e7d53) +,S(cefa268b,e551b02f,8fe50481,44920abc,3d03d97,3f2e9368,d2d2cb42,341c11b3,77440b02,64eb1972,91d2d69,ebdc1de7,66915a09,aa01615,e4001d62,7219d491) +,S(8625c163,58bfd43d,888ef97b,e33d9938,c62f7f2a,9e7b9735,26dd14ca,7c76abda,e1351920,59085272,3ea7b55f,49c4045e,2dda5ceb,c1a31841,1b6cf38b,b97bc1c4) +,S(43b8caf5,d4f72519,19630044,13bd459c,f5913edc,ff303fa6,dceb3412,f8e39c2,7d1df179,13186dc0,d7957f61,a3232180,21a6b50f,61a86f33,72623f5f,d3dc1a11) +,S(163fff8b,cece557b,6fd77b4d,e22e5b55,a6ed51a7,76dfe2b1,362040bc,9e7e4fe0,29204f73,5bc6428,3c510e0e,2192299a,7f6ed56d,1a0cc569,aa37f895,c0c4646a) +,S(fdbfcee1,69aa6724,b5839a55,e1c54856,86503b51,d1320b37,dcd9af73,2bfc4497,d7f75ba3,7af2f969,31bfa612,446c6807,a207af9a,17269199,77b0d71b,16b11a0e) +,S(f1981a9,aa585d6d,102b3a7d,e3509e0f,ed002866,b379b4e2,ba9d175e,4e5879ee,bad6366b,71a7cd67,163b6313,3dcd442d,24f9362e,5d0b9791,2a8dbfb5,74517e1a) +,S(dd3de17f,1cffd240,424096cf,effcaeee,87bf4d30,4a41d5db,6953102e,4b91853d,d136d363,1b9b968b,7c7d1a16,b2302e7a,7770e5ce,afae92a3,8f6e1299,6fb04718) +,S(b1d95fc1,4e35f77f,7e64f62a,36b26218,86397228,35ccadb8,39fa7d7b,834bdae3,75611c0a,920e0251,345b3213,422959c5,ac66c495,14d50c35,de7aa7ff,2a330a6d) +,S(1eeb92e6,75f25a35,9ed16c8b,51a5c130,d2210c35,ce954430,ea2cb3a3,af69187,cdefc1ac,40fac4de,e42ba496,eae80bc7,680e214,4117e6da,c2b3bc12,ce9eec45) +,S(aeef491a,fabae168,9d58c2f3,808b22fd,760e8607,c043c10b,591ed211,6fbb5ce9,b0db916,30810159,7e79aa7,82d8b643,d739bda2,c45ee36c,4f328108,4e55a33c) +,S(c56793cf,822c3da5,300c6c2d,cf06b5ef,413d51af,633ec77b,b9b68b1d,d3079e43,a423e25e,1eb466da,f521c5d1,6395805f,a2da609,fcfcffc1,2728add5,61eb2c0c) +,S(2aa824c3,c8c648eb,8bd0c151,b30452aa,c097bc38,a9f53db5,a8375631,25887e06,20aa4bfa,3bb2c5c2,a113299f,6c61102c,7586deaa,938a33f8,4a517dc,4ba78ada) +,S(4a0bb8dc,1833942d,9ae3428,ed493cb9,5716b50e,c96db120,c18ccac4,f6c3dd9,d0526d5d,c8be139f,53427e50,17cedc51,6b4960ac,bb98d4a4,f07fdf26,640b78b) +,S(2808616a,309b64c1,5d061adf,ae65711a,a561f8b8,345132e1,5b18fdb0,e476240,d2190f22,7320a55e,ad2dc736,671db631,9b18d6cc,b4d2bffc,cb4b692f,74eeaa0c) +,S(3dc4b015,13a95221,32ef431d,33435ba,8cf9e6d7,7e4ac75e,54848916,c23e7959,eaa2516b,9b13bc99,1f4b8ba,fa90a6dc,a007fea4,e26fbe0b,a2c5d1da,326d5420) +,S(473f6157,50af1d8,839ee0d0,eb5dfb8a,c14ce65a,e04e5f03,99fe8666,bd6efe6a,18d204d9,1b27527c,50823d5,222c4e4c,e3e193e5,a282daf2,75d2b43c,ffba8412) +,S(3b87175a,db1a5e49,1cf7565a,28250c51,9fff906b,ef0eecb,e8e50a7d,a190aaaf,fc58f2dd,16f1a5cf,1a728117,dcac3dbf,3a3963f,3859a518,2616b65b,59e96403) +,S(12f1b577,1410d1be,d0c4863,360e37d9,d36643d8,e0cf6fe7,8770478f,504174fa,be29140e,6b5a40a1,40559972,7e0727f8,ca904c3b,813897d2,bea089d9,dc2f17bf) +,S(8658f35b,902afb85,408280f2,3b4d98db,9526b57a,1e6cd0e9,37d8c629,ae174a3c,4060349d,47a69720,7d29e83,d8c82197,d32bb9ae,8c83879,1e09a7b7,1c3e7c28) +,S(530545eb,526d9657,2ce6cfc0,22e1c0a7,b9965c7c,3c2db355,cb5d414a,6c1ac8c7,99243b26,17f8ae2,898b96b4,1c3c65f9,96a9f8f5,83ff341c,671a2d5f,2d04637a) +,S(2e808732,bbab8507,e65936f3,fd1d1662,91ada8c4,c0d865ff,849e0a1a,5f08d265,96dbf7c9,53fd2f61,7e149f06,89b66431,88b091d5,1227a1a6,a0ebb140,18a79fdb) +,S(4272e028,b4b9c90c,44526fe6,b25f5e84,4b8baba6,34ceb2e2,33447413,cd5bb35a,6b4a4076,fc3706a7,50b0c824,93f5e363,f9fcdb64,9d683a1f,fc3bc2af,fc8470cc) +,S(78712f3,449d07ac,7f8171d5,42ee8b40,4761e054,eb0362c8,3b30cd52,6f9ac60,c7ff5ae1,38ca3c13,79457619,dd76061b,7b59778,79db2ca1,5b07ea47,7aa41bf7) +,S(be40166a,60ad9af2,d1bdfc7d,9b0660c1,640d4f1b,640ce485,8fb22eda,65d15a21,78c49afc,1d992bdc,b70bab6d,d3619305,a32fe90a,2f2b1b43,38d77c80,b208cf90) +,S(2fd5831e,6bd5a79b,35bc75f,92e83e4c,9acff5cf,61eaad7e,dacb149f,46d5e6ba,82f38222,4b6be0f2,f52318eb,7fe44a4c,4c0c1b05,8eae3f99,dbdea80f,a70ca3d0) +,S(32fc3fb,4574a651,472e0328,c15a71e3,bf9a12ca,15d341f1,c5102dab,2ee6de37,7e9398a6,760df809,e5eb57df,8fdc3234,eff1aa8,bef57008,c36e7953,c07f25a9) +,S(b9018d98,3452e952,7944f2fb,3354487d,a82f8b90,e52689d4,edb2a91a,a8faa6bf,e9cd0e4e,5c5efcbf,9ca25cf9,f271f9c,a2c46b4a,322cc966,e7789607,324348f8) +,S(a74ba662,32afb3e7,d5c22ad1,c792da33,f1bc88dc,244a8ce5,d4d582bb,b16ced23,444c5512,b49c2c63,4cc0328d,20f7321,a88db1ee,6d525be3,5d2de8df,cc381377) +,S(40f6df83,6d5e8c94,332174e2,2fa43556,d06f48a8,f52cfd69,820c2c46,2185dbfa,852c5b98,15ba4ef0,18f5d231,195fb62d,afafc08d,fbf9159a,eb5f6063,ca353424) +,S(e05800f5,f7890a14,6bbbabb1,27924cc2,e33e3c81,eb88606c,6bca020f,1aa71747,ab905ec6,3af1bc11,897a44e,89c2c2a8,3fb7255,c0e7f76e,8378e59f,1289158f) +,S(7b75dff9,a1afde87,be8528f7,9df63d70,e4df925b,a15f01c5,8e8162f0,89ee735e,bc057ff8,bdc9e37f,554a6ad2,3ebfeb2e,5d64adb7,69fa0082,2b2d4902,ca82712e) +,S(2fb81423,3b01e312,7ceabacd,a9ca518e,b1ab993c,bff855a5,20a96f52,afa9a0cf,a7e4bc57,b53affba,9e2cd875,9665cd9,215fcc,35dfc402,4d1db86b,9605c4b7) +,S(f346a33a,ec17d0e6,a10262f2,fd8185eb,f80a1fbb,f6b06bdd,1c04f18d,75dbaaeb,c09caf81,120586fc,33a6a0bc,97ef5cc7,56d20806,1340a1cc,ba9955ff,4a059e10) +,S(d128544f,a5f5dd38,62a759b8,5d538baa,63d112e2,f8c343a1,1bb3b8bb,ebf548d8,7893faee,b73f0530,bb67e8e0,9c2806d7,e303dd5e,116bc9e5,93e4dcdb,eac031f8) +,S(69046ec4,11c06822,59de20b1,a2a8f84c,58c56765,2ddcae,a26f533a,9c706f43,c17a9640,adc07d61,4a264ffe,272cd686,99b9af9f,6890cdc9,ac02c761,637dda8a) +,S(7b50f61a,9dd7b9ef,7af49c17,6ca5555f,eadf3b67,90998365,29379dd2,a3c85b5b,c08e18cc,bea8a970,7bc34d98,6b36475e,e2e24695,2304df65,bbe0347b,6052416) +,S(794a9728,9db4743e,c91a8560,e430b14,a7d8312,1fbacfbd,ec37a9bd,c749d3f,c57a5b9a,f0cb23a3,5e9b092f,386cda86,bf2f8242,1f74dfa1,837047c3,ae0d2235) +,S(fd8d1485,3d2fa064,c4682ee1,1c319a8a,49fa9b23,2cde9d1a,9a44b2dc,93b2f251,8cc4001d,f0121ce0,ad2119d1,7aaba363,ec45345,87fa10b0,c94a5043,f641b91c) +,S(7b5fbad,8105fe06,6962a72e,39a9a4fb,fac27794,e39a6660,133b9ef4,a6877557,b9b4c9c,1200d879,6013de67,958176c6,dc04ef69,b1021057,de8d3b40,564fbcd3) +,S(2c7ffc8b,40eda03e,20e64678,68959141,c66f01e8,b7cb050d,c60e8a48,6f6e41f9,cd0f3510,39aed3c1,56ae2b0d,1a117f78,c14a704c,992db297,60d22700,2f71ff7a) +,S(79533078,d81a6fe8,446dd750,b59ecdc3,8904f13b,48ca89a6,5644aa8c,9233de64,d7c95bff,77fa9894,74634aab,3b8f86e0,ee0bf92a,3a338fb7,f89881e6,e1fd746) +,S(be96c5e5,d3fb03a1,801a7760,16bf3824,aa16010e,884359b,d5e30658,5f13b214,d156346f,158d0c1a,2ef96a95,86cd8d34,20be21de,6997904,8299744,b40a5d9f) +,S(165c53d1,9ac89139,c063d934,511478aa,bc296cb9,7201dbca,fea4cac2,16a4fa02,4b002644,1e6f1369,d3603780,f33f74e8,42a812d8,b4e7ff7a,4aeea468,35f67348) +,S(508fb72e,dbd27f3c,76569185,a18af8bc,6242462e,cecffffb,3352ce3a,da5ccb5e,e1698f3e,1d53607b,4911423a,f2167466,a473a8f1,e2226849,f4dfe551,dfd14652) +,S(e9be0fb7,8e95dc1c,7b79f4eb,7976367,a85034ce,ea8642cb,19106dad,1d10ab92,b7867a7f,51f89779,a32a7b8e,273f9659,fb84367b,90ca3ff6,afc2cdac,7f596c45) +,S(e6ea5e6f,97116554,2de16c66,1f15d6e1,24aa449e,960b393a,e5337de1,d4c94800,bbd62bdd,1c235fea,60be143a,9155ffa8,204a1b11,3f19f4e,6e683c7d,e234ca7e) +,S(ab3f8a0,5b8f5ff4,149a390b,a858092c,9653d159,6d84bbc5,6e4a7a8b,fd54d7e8,41008916,311de07b,16c1b49,c6aa65ed,8baaebf,7a4e75b1,5aa1bc34,37483e53) +,S(515e02e9,52a347e7,5e0c5eed,a266242b,48bf33d0,70048562,c20feb3f,aecea1e3,797b3ef8,f6c35440,58517c56,ef5c6464,fcb63353,2bd6d2e2,83487a1d,8a403b36) +,S(520cf598,b3552fe0,a42438f8,55aefb81,3a3e10d3,f4985998,492e06a2,42ef46e1,c69de50e,2bf9658a,40567066,3cac0e4,8c8d2920,95ac1df9,9535b7e9,209324ed) +,S(26a8e655,4a2cf338,33bd27fb,d96880bc,bcc1d360,2a76920c,37075790,1c50bb1a,ba5a4560,5ddc5236,2a0d09df,3247a507,9c87e652,c4ad35f2,e19ecc9e,ec1ae4af) +,S(bd06a5a2,362ac91a,759dc578,dff3a3f8,102a67ae,a86ac11,5ddb2e14,bc1bba44,e8751dd7,153537ca,eec17988,98337cd2,abdfa554,52c597c8,61c364dd,78f49de7) +,S(ddbccf92,da0ab07a,e99fda1f,4a03927d,66b0bd21,f1e54fc5,afd4f329,35a0cae7,26fc18c1,52755bc5,d68dc3f2,461d60ee,b4dfc02e,a04b4779,6e7725b1,23acf8dd) +,S(650e1616,2a30c776,b54130c9,9fbbf567,32e2bdde,f667b09b,9b7f25ed,93c0737c,14972f76,429eb04c,1ebb0583,8c54fa0d,309fee09,a55d7eb3,700be0df,5801d56b) +,S(2920d280,41ad7365,cc0e33c8,7a3d6f3c,f9fec9c3,b00e5698,55ae3b83,8cf08973,3821fdd1,fe36668e,16f2cbd0,b2704fbc,24354f08,8ba19a1f,67d1b11a,b70c2d68) +,S(3842fb0f,1b26bfe7,535c9f5b,cee85ba5,6cd491dc,346829a2,a178ce65,c5294302,8e02342a,cb0e1233,9e638018,a125622c,5f66ab52,86a74a6c,28982c25,aa3a0fe2) +,S(9c21d89f,f1142d24,1e62c1df,e0481268,c2273d01,f153af5c,d31b3514,5b9b41ac,f5a924a1,d60e1eb3,72837535,4e252740,593c96f4,87328e9e,2a80cae,15fabdb) +,S(59320ba5,c9088701,f354a3a1,93391880,2829ce91,be9b4c14,c9018fe6,4fcd387a,610e48aa,705e2e7f,86a6a12a,817984a1,7bc60f9b,abc0ba9f,775f3446,8e3f3815) +,S(d800691f,83c2903b,1add209b,35d796e7,15b805a0,9bbe6120,3bf68a08,a13c46e5,21d194ed,bcb8bea0,cc35a9f2,328f1689,cdacc58a,73f65a28,56811e54,d96e5576) +,S(865588f8,66c21986,7b9643d8,7f1215fb,90fe186f,46478e8,522a5da6,724f6e8f,91a6b315,a7ddca8d,b4ecfbc3,9b55eb81,393f4c51,f573fef6,e7ca0c9f,cc551e7d) +,S(9dfe808f,cf7f574a,ddb251c0,4b053d00,8915f8fa,5a975479,d43c719a,b67aa4ad,4d40cc00,ea6720db,ff1f1339,7bb26c0b,281686a8,726fa430,bce0e4e4,ff01b01d) +,S(835f1c87,cf8d4420,72728601,ab6aef63,cd0d73a1,80f81f07,f5d57cc6,bab5ef7d,bac2d1d4,c8541f65,be0644c9,40a18f7f,d2c30360,2083a455,4d70a111,1c5bf07c) +,S(9562dc71,33c48e4,b46d73ac,d42db4c0,b0222c4d,dcd0e76e,b4f84969,348fa46,7cfe0965,96f691de,d358c00e,a292975d,465ef064,e9437556,40bc1d4a,33c3a0ba) +,S(21afe3b9,4237473c,dc032588,c4c1b7ec,853987a6,dcd1fce,2c48bbb6,8d0f3b45,1751c5ef,674cf88d,d5385943,b40a20a4,6d20cbd3,9876adc4,a4a4bba8,477e78a7) +,S(89809c4d,572cc5c1,2241ae09,fe1cee6f,71aaa292,c9ff8d6e,c3eb8a92,8e144ebe,462c023e,1710ed77,bd47d22e,e222598c,68cd7c56,b004369,a9356a47,ed6809d) +,S(b7c6164f,b9e175c1,5724c596,988b496a,b9f5b0d9,dd45d0e6,4a0f08cb,9000e3e9,1a13e8e5,a23b40a0,aba44bad,5cb4d37d,a6061157,aeab7a0d,d327242,ab2ad11f) +,S(62088450,24eef2d5,4fabe8f8,fabf519,72908ac3,23596378,c377c458,9719bba8,26216b3,a353295e,a1877547,b826c240,351f227e,293abcd2,e3967fed,30391f5a) +,S(dcfe82df,4049089,f3f8b275,120ca438,998fb22f,e11d40e0,9d09c4ce,c12ad036,388f9754,39b1c412,10014136,c3b58fe3,30ab524d,d7d3524b,37ce9133,5cb3bf3f) +,S(324ec5b0,12de7919,2f27f5ed,166344e1,934b3527,2b197d28,9a634044,5dd4bce1,99944794,579e12e8,c5c0c11f,a8eae5f1,88cb8cdb,3ce7814c,f89e3f1b,a3d3de0f) +,S(b3a70b0f,af96cb56,7dc4245,13ab7c6c,bbc38634,faa0c286,b81b9754,454a363f,b507745b,97843c90,170f8ffb,f731fee8,4532c1d0,6b2a077c,2aba5d94,189545ed) +,S(c4a6ff4e,cdf1ac83,29a1cdb7,b5165d88,2a1f1823,d1c38006,1b53144f,56187fce,6f7d0fc0,c08a7ba7,386f9a59,330996ef,b13d9d21,eb6d3915,4c8fb919,66159919) +,S(61d9ee96,1ef58634,5c4a73e3,a8c3df82,eac28aa2,6d740cbe,1833dcf6,d5a38811,c9e4a482,1700107,f2d4af3d,fcc74e68,8123b589,4da1c2bb,1fd926e7,11330892) +,S(67ecbd0f,4f4fe300,49390655,5289c9a5,cb6ac090,dff38502,75f7751,a84c6172,e422b1dd,10467cfe,921028f6,71cc75cd,2be5d8a6,75e644e5,d3c40b3a,2836726d) +,S(47f6c669,70898fa8,16dcd4d7,4553c644,2ce5bbe9,cda91324,ee3bba7a,868ff0f7,e56b9590,838bdfaa,1c2be1c3,95f775e,4a0b3982,d0eee531,26ec7ddc,9e3f77a6) +,S(e39ec9af,c8dccd35,4b155dd3,1d1750cb,ab096807,f89c8afc,fe61e6d2,e348cfa3,df3fca08,99158319,b93bac62,88c302f8,a59e175a,cda9fbf7,6f0ad59,8358088) +,S(2d1aae84,500037f9,8e08b64,341eab03,e0f1cdf,5a079b46,738746c2,18b3a0,747c23ac,8173adcc,de767d2e,ac156384,ddf40797,131a6167,c32486aa,12c89e5) +,S(ed1bbf04,d4570df5,8f584158,1fc47665,481ebf59,cb88322e,497d128a,678c2b4a,a40765c4,772da2d0,b3c8f107,22ec3931,ab3fc8cc,c28b003c,bea1a0da,279c8fba) +,S(bcbc3e1f,7bd268,93f377b2,eee4b76d,49a8a603,738de309,5353fde3,deff55f3,fb697a08,2f2570bd,1e9e4ec3,fc7f6c81,2a27a7e6,f7b8a53e,30da80ef,f59ef2cc) +,S(4f98b2d9,2f0b5d57,51ed3784,94cf4de5,65cf632e,982a270b,2746a5a6,3da9333d,43857e7e,437bdc02,6dcdbe68,d056784f,a2cc606d,7ce09a0e,12978a74,5b67e529) +,S(9dbb995d,d0667371,1731bf05,c8029035,2b413411,45318de8,2236df5c,87728582,c0a90e4c,6fbc0665,f8cd9fb6,fd59ea3e,f6ae9a16,9bfb71fc,5fe73e3a,4d665f86) +,S(83692208,1d099344,3d979c51,90940e44,5465624d,3a945c05,7885cd00,5ce6b9e,49be5e40,2e1d05e0,67b16279,855bc1de,6f0d8aad,35d8bc0e,142dbe87,33a14e13) +,S(f713e920,7a699b68,12d7ee9d,1475ba85,a6c56af2,8b73ace7,cf67ed6b,55650e97,a5a2c2a2,45012812,29fc71c8,103db717,48a51f88,61765d31,4b9ec278,3d0aab45) +,S(919f2d21,256ae682,fe514320,9c6551cc,d165de1b,8213fdbc,9c06578d,ef705725,9780da96,eeaac4e8,c96f3d6a,89c222cc,9b16b4c2,e8faad4d,96cc0136,a06021d3) +,S(1738093d,197a5ce3,cedd1fa7,e2a8ff03,959a6c23,6aedf9e8,9dbd74c4,d82b6e48,74363112,d16b829,d371a0c,f1b3bcd1,2000254e,196ea80c,a9d46570,1ee4a1d8) +,S(41242a81,35811b36,d4ffc40d,bbdeaa7c,cce36135,3c4fc9f2,d23191a4,b9c46379,7b894326,789f3071,374983c7,cd2a5ad7,e0ee49c5,e740dd33,817a31ed,97c388ba) +,S(894a6ec9,96eaa8e0,9e077b34,7b4f1e1,a387c930,a526c469,aaefc0c5,402d41a,a080fb43,c8e6bc6,388fa766,2398e096,b65032e8,26c5a9a8,47793924,4dcf5e41) +,S(a71f2131,3599cb7e,8c1058c9,52a5712e,661d01d5,79bc7ee5,1fbadd35,34ca5d5f,afe5b47b,663ebd7c,d788e0f,d3f963c9,ac63ee24,b7495e61,4a5d6553,9ab5f859) +,S(8f330e77,82eb62e4,4ea389f5,7f1c58b3,458c5d39,127d9783,6ddef8c1,27fa390,894e6142,bc359171,999489e1,1ed08224,4a46100,136fba84,e2b8732,e9bb626b) +,S(d2f0700d,6124c46f,a64cb709,1181cea9,34fe0406,21267334,c85ace2,cf05fc6f,8dc30ae9,83a95b74,2d800490,fbd8c290,bda64daf,f82d8fa5,e69243cb,43556cb4) +,S(c2478e89,8c075873,ba6cd5e9,6a730e1c,b6ade2f2,7fc9e7ec,93da9201,63f88c32,c6412063,9921d8c5,77dced53,76907410,82b1b4ff,4434bd,9a55b6c,8591ed5c) +,S(c5bc11a3,4e701898,d22e2920,2806c880,b24efa7a,c6d4ee36,cd440386,e4463a10,2c2b89fc,48feefc8,8bcb4ef5,68d16b44,cd7d8c7,485c9703,91c1c243,bf91003e) +,S(4b3930e8,21827b05,8c487bd2,fefa3458,6d0d3f20,5a2236fe,1b735d63,ac8c62b9,c38a29ad,c9b9941d,dc92a0db,4ce5f312,252c1f66,8a3189c5,595a371,19321c6c) +,S(fc646e3c,eab5a96a,1785da2b,1b50f7db,f0515091,76ade1f5,b057d05f,3aa3b8fe,b2014537,dbf2637d,6f683fb1,6af00d5c,63d4ed59,cdbdd673,f3bfbd48,e9574dd5) +,S(c0ada793,e2d9ed24,8ce307da,a6bebffd,3df2fc27,d2001dd4,5dbfc7be,c5f97a0c,6f3a787e,d40f073b,4965d52c,40700f66,da93f679,9efceafb,4894788f,5c9c7fd7) +,S(b1a45f3d,f2d45a,e21e43af,31ec3159,e8877d91,3efea814,b66f6fa4,a227b157,d988122a,eab167b9,f89db9e2,dd82405b,404f8a9c,a9acfd29,81c8bfa4,273ed248) +,S(4e19b9e2,ad3e421f,1b85a174,89d8841f,65672fad,9a17ad70,ca4fcd12,716d7a68,51412d39,59b158c1,3905c267,f5cf66e2,364aeb8,b66a11fd,ea6f5471,35db6dcd) +,S(533ee2b1,379a6ddd,6e5b3a2a,3a197e7d,eece722d,5c5b9c66,5e1be9dc,f3c09adc,b91b7477,fd0eabdd,bdc4047a,9bcad0cd,9da8496e,bd328fa3,a3ab20a6,3508a6d9) +,S(ccdb933a,816ac55e,c8fb97e1,504fa512,67408fd3,77aeeaf9,565ab66c,a2033b94,20299202,99b57beb,5d3817f5,26aae569,b490b24c,d5834dbe,8b05e8bc,89110de4) +,S(770d7c72,2e9964d6,84dead28,328b1925,287184b4,6e3abbdc,534eb87a,e0ea5873,363c73a7,bbb9b2af,3c0cc91,6f8ffe74,837a99c8,58b5464c,9f253764,e4a78285) +,S(d440dafd,b1d0609f,7c2354d5,74e711cf,852b364,8827fd41,88228ca5,98f71eeb,57d438de,c1aa78b7,c872cae5,c6803a2c,9844809c,7bca1a54,1be6f779,893aae1c) +,S(1602ca76,35ee0795,4fed3cea,d3e54470,41033887,2f060e19,990f3cd3,501b951e,1ea7f857,4b72d3e2,bd45fe36,c828f18a,5810812f,ab6e0936,a7854ed7,c7e32bd6) +,S(9c4d2a24,e4ad8226,bccab8ee,96960b1b,4722d2a1,88a429ad,f9d194ca,6687f7e,e3a4b46f,bf608018,ada2383,5c70fbe,cabbd446,78c9e5c1,35e91138,7d66b01b) +,S(fdf84be7,5be40fa8,db537848,e2fc8ba2,b7c58824,74fea4f4,6e8fcf15,f33d3bb1,2af57dd8,60ba0e6c,dc3606a9,a902420f,9283f721,70ce32d8,39c33673,5da1ff77) +,S(6083a785,fc5aedbf,34615139,e2f97964,ef65d254,a38251ba,203f8ea0,26eea81c,bb4d48bb,894fb656,22cd752f,6e3bc6e7,670a4bd2,64675035,8481561a,2c18439c) +,S(e03ad08e,5b4b9e01,5103e028,668f09a2,7d2f5254,25c6a985,6dfee667,6afffb82,f53acd57,1ab23ddb,d6b104b8,71d957c7,f254bc40,c37017ad,f7350e18,7a24865b) +,S(5a382a4c,88656b6c,4a5c8dcf,4052b1c0,a0bbc0a9,86289ab0,e212fd24,b852d9bc,912caa9a,32a10900,eadd0eec,423f710a,3e0aaba7,93f7b675,912223a2,6ba14f31) +,S(37dd526a,b5392b03,3bd05ff9,3952a31c,7bb0cfe1,f02f4f57,3b8d0ef0,c05d5ec0,7e329228,36595c82,14c8a776,15482931,98966225,4d4315c,c236c156,254e3249) +,S(ed4460f9,cd4bc957,aca653a0,5b6f0935,9dd7e19a,6d65c60,ca585ea3,ee2e1263,733af30e,6edd2b2b,317bba97,d24abd7e,41af6256,e7353f97,58357ff4,1a701829) +,S(eb01d9cd,50ff4778,b29e5096,93388ee1,12cfbc35,2c1b1382,7b3195e7,44a3bc3a,24877b7,99b7a2c9,db23047a,3194e9cb,91e5dd50,d0f1e252,b6f3bfca,f5b4d110) +,S(9fcfa274,b180ce82,14624545,22bb9289,1e0a8fc9,71949bfe,7aa25cde,88dc284e,6787be0a,12a76a23,9de45596,2a11f7f4,4051fbbe,3ba7dfb3,996c60ee,97be2b9) +,S(c8a0d869,87a7a854,99bd5663,30a07d67,70265d8e,cd3286ce,c9be4d02,6145bff,a65c64e4,af865e6a,893e902b,b06c43d6,10bb8181,134a4b71,d136b5fd,f42982a8) +,S(374294c5,932d3f74,a6e74731,6c6a84ca,dfda6d35,5edd914b,70b26161,50628735,ac47d048,8433754e,3deb79c6,7056d828,14d73bdd,703b299a,ca910180,e518672f) +,S(baa9e3a6,2b4bf099,1fde27ad,4b043b50,76a184cb,4f9a6da9,9b56ecd8,a2ab99e5,1e8e836f,f76043c2,c187ee45,7138cf3a,270e2d3f,5bc96979,c12c34cf,9205c63d) +,S(72f85ea,784a5ef1,71516c22,13abca1e,8017db34,4e00b397,4cb509de,a124654d,c78ec627,6cbc5072,fd75b28c,8d395f13,e84731f,7767448d,e06c0ba7,372968bf) +,S(c9173d63,bf5a1301,f0750b1d,e3cb7061,bb9cdd36,296b422e,d23513d1,10b61903,d26a6a0a,ceef78eb,73c6b031,a5455d2c,2a9c4ab2,d916b7cc,7b8e627d,6d581c56) +,S(865ff86a,58fb9853,8bcfe496,26c0bb89,e419083d,f21dbf6a,7b13e041,d5cd3f18,f0bdbabb,8118de57,bce9a90c,83529ec8,abfc2812,ab0088d2,8ade4bde,fe2fa383) +,S(3f14eb28,fd9852c9,bf4d4497,4d794ef1,c30f7748,5c7bb766,6f32fcb5,5ad910ad,e982971b,ec014b05,a9b5657c,a0bf45b7,adfe19d,22726075,80b42eeb,f4dc5217) +,S(61dfae27,c7bb68a1,ede331c,6499a7ed,e242457a,77e5a606,cea82e9f,f450d01,973739f2,c1e4ff77,cae3cf59,b481e730,5ebe8196,c5b62b9d,a96ae224,9b83efa7) +,S(e319690b,e944c297,f7c1bc1f,462ac3b5,a74fb913,9b963384,ac11046f,4343883a,3dadda66,538ea9c8,8fa0c02f,208ede8a,b6ef3480,82af4a32,2ddb5fa7,96d2efeb) +,S(f3db5e84,a9015b39,1617fea6,58143553,baa1975a,ab017012,38dc4243,7d9eaf9b,df55628b,c50cb2b1,be2ef193,a7f90e6a,3bfef4ac,63aaeee7,39907906,547d8b62) +,S(83a7dcd,58742725,8d17657c,ec64b5ed,4807db49,911296e7,10cf349d,c4fc709f,e5201a27,c37cca5f,2f7bf74a,fe000c0f,56643a5b,bafe9f91,de181e74,1d327183) +,S(b95b2363,28f51c80,b376dd90,a0f92d08,1e395132,deaa8f42,c142f642,3d3611ee,c111a08c,a6dbccad,2e784498,22816422,f2200f6b,bb24842a,f96c9502,13479f55) +,S(c3ff0645,921f2b9b,2fe590de,dfbac094,8475bdfc,a6446177,6422cca5,6fb549e6,e07ecccb,4b972834,e2711423,c0fba72f,eb0bb7c0,71a9e206,bf7715f2,62f03e04) +,S(96a37acc,527ee163,51c46241,1df94da3,eb0229b8,6a6e34d0,234bdcb0,5313c10a,46014617,fdd3f8b3,a67269d5,20a49680,9e5fa57e,76da4ef3,59ef862a,c58380c) +,S(b135c091,ec98a07d,b624fe48,4d336b85,62facf81,50346e2d,d0be2cfd,618d1e0e,24456a71,e8f2cc29,19f53594,6d7aaa79,e3d7dcfb,4af2feb5,ea0a2ad3,a23ec070) +,S(71d26219,81730b69,b0411b1c,f553c81,6f35a34,e09d086c,4500ba,94812017,c25357f,8915a2c4,98fe0d60,ca979ecd,8bd7ded3,ad6bc9ad,262db1d2,c3d3e7be) +,S(363cae8,ab2259ee,80283084,d98dc16,60c0934,68e3e854,dd86d9a0,d5e97884,756c60f7,c5e113d8,6e92df38,8fc9a1a2,a4889d86,f7440429,7661365a,ccfd8ce8) +,S(aef32d83,81ba3804,6e5b3305,6764ce3a,726c4e5a,ea61a17,ac114599,63f36247,dea5fc8b,d4ceba19,89640462,a957a8a7,44ca42d6,901716a,734e6f87,9aadb81e) +,S(65980f89,e4d0e342,d4b4fcf5,228692c0,9ebfed11,52d951c7,80963e6f,8c81313e,2d594cdd,a1f0b9db,7b3d8815,f7402a06,acba8e31,b9b0c597,8d2118a2,5dffa75d) +,S(f979280d,7e35cce4,8b9372cd,f73cebe3,6ee08388,e98e6069,fbeeb168,52329433,9181e8aa,bf7d4723,4cb851d5,6b3ca08,8c5f31eb,6b1b8c7,2879cfba,bd3ecaac) +,S(3b9f877e,286a13c8,a8463db3,b306ad62,c152065c,6708bbd5,68931e8a,2deb537f,12436d2a,5269a319,4f605dc1,4a34fcb0,445be9f4,5cc2bdc1,b96d86e8,b9465631) +,S(f2c70f82,1f86e94d,426e3e3c,e31ee519,f5a95b6f,38b663ae,9a6aba4e,f7bdc4e5,dc534655,4ba850bc,fef2485d,51e08c3,ab546119,49fee2ee,4dfc4e09,ff203b44) +,S(e2fb481,da8a356a,ab82098a,f622db2d,6f0a4349,2428dbac,922c1350,65801f15,5f735bb5,bb805980,d85ae242,4855bb2d,5de0c1f5,5018e1a8,e65bc2f4,86b7742d) +,S(d99e2001,33cf632a,f66c382e,d8ef862a,17092764,2c8f1f40,bd3d7bb,f0070324,d00f12db,cdb6e1ed,d190a754,fcbefdec,ee459be4,d5a46d69,afd6cbf8,4a4d30f2) +,S(dd765b6b,cb2dd356,f5965a8d,38108610,688fedc,eb3ce48d,352b095b,aa0daa,636258b3,58171669,f0dc68bd,3dff2a6d,bea6e5ef,20060913,66b12082,e2d7fa0) +,S(f549c14,f099a957,6267ad6c,3adc985b,9d0626b7,3f1f5849,d64ceb1e,266a9965,45a17dc8,30118c3d,28e73a3c,3d026afc,29ecf50d,198afdab,dff3d130,8f32f3d3) +,S(20d80860,90a192a8,51eddb84,f79b2882,ad7ce8a0,9374b365,61e6da34,427e8226,b48b6947,9febc104,880aa8b4,17344206,b19dd720,e5392bac,7e1954d4,a341eec1) +,S(b9f383ff,2545078a,c22cf9cb,83fc9e00,e9d37f30,e03ae03,5694437d,c1de2d7f,14f8b209,d1128a44,20dfb93d,3dc9ccb6,7ed22dd8,ecf5a181,2cd687dd,64a2996b) +,S(2ba0e5b,cec7a4f0,c6edd1c8,2d2f5927,2d97f4dc,3ecf353,8d3854aa,8d6f9739,8b10b217,6e56e5e6,5b99a617,eb71da00,3bee99af,b80e5ef7,3ca8c332,5ca7a75f) +,S(28b45a0f,3c308ecd,c0f7beca,c62d42b,500b704a,9af39931,b8debae8,8cef27e,9a3f95d,a17888ac,19eb4e42,1279c400,a60a0c1f,70a11696,4cf6943,9fc858d8) +,S(d8993bb9,e73af10,26ab41f0,9ec5adf7,437ce08a,4295cccb,283657f0,7a9ca3a5,ad8930d7,817534b1,e8407db9,bb8a608f,538b2bc6,9827a234,743382b,4381ddbd) +,S(77cd88a1,76bfed38,d7dd7152,32e2554a,a644b79,64a85f86,dbd6ffc6,69714e82,4394630a,42436802,1d0a0681,87fcc6a4,dfee0fe3,6db3bf2f,dac6fc58,34faccf5) +,S(d2557185,9c0fd15f,1f3666d3,aba99e38,89419099,ce7be94a,81ca1045,158f2da,90e94d6e,ac00b9d9,19832505,75bb2f,3242e7fb,fb429dc2,a90e3231,d1316cf0) +,S(f4e26c7d,4ccd80e2,7620917a,fdc72ca,94178f54,547eb330,77baa95c,d92a981e,c8ff014d,a388dcc4,c634304b,5973b274,785927e6,190c5557,773b9a0b,ef7d7005) +,S(da3a12a9,50dcd18d,c9e531e9,86f85a53,e7ce5bb8,8f2b5869,9830c44d,8c14cba2,7380a5b8,c01209e9,a1face4d,798f63ad,519a67fe,6bc90511,c763ca19,7e8c6b41) +,S(3565fae0,daf5d9ef,609bede3,6e19417a,45d8c0d2,59163f71,b4d9f54,43756fcc,7b1ef713,a88f9965,be7e6799,4a936960,c44f67ae,d5fa798d,8c0286af,e9da257c) +,S(6683fb20,d435a139,bd08c35f,adcc8aa5,8fbb8f48,7f9576d1,6f41d086,3a4e3de6,6a969f08,566afbc,dc98abfc,9d0d4d54,5076ebaf,efc9b966,957f1dd0,af52209f) +,S(900de92c,cbd4528f,57a72013,77dc1b51,7af67416,1013a20b,30d356bf,e011f508,cb55db4c,8799575d,9dea64f6,9fdf081d,959210eb,32b26bee,b903bf0b,80264c60) +,S(9d84bcf8,1be8a9f5,df2c6e80,d1b5679e,476e39c5,c30351ef,dc6b0b41,61c17613,8aa0cee8,cbc22e60,b71d9066,3533c2cc,a02b8d7f,7df93ce9,897154c6,2fae046d) +,S(6280fba,a3c3c8e4,4fcf0f55,a783eea5,2ebda748,501730de,71781be,abadd211,45b74c18,f0c18d3b,76cc1089,8741246b,202fd272,cdd0e866,5e1f4d86,ee527f5a) +,S(a4237add,7a5ea66e,8a1b48cd,7d5ef195,d90f25e5,6f2f148c,6d4eeff1,805b9024,d512d16e,632bd9ce,6cb1b2d4,c9a41e36,f9a2b83e,73fc8631,1e4dfa1b,b3bf71af) +,S(51effda3,e84027a,47afb48e,dc5c1937,9a685a24,ded2998c,c2b74422,b1e83fe0,346a9d82,cc07ed91,d785c6f0,dc32b62,e3e7877a,892007cf,c015444e,46001f19) +,S(87ac6bee,837ce155,29c005a1,6eca4540,de1480b6,91bc0ed8,90fed51c,de923cf4,9a9aa52f,1be1a33b,7280d0a7,3c19f5c5,b6baf99d,3c9c2d54,4a8d9bf3,a25ceb71) +,S(c8fd7df6,a3b0c0e2,5a931146,72a0af1a,1f995f1a,109e6e83,10b0d433,5dc2666a,3a853149,9b28c2ee,b5baf17d,dba8f57,3cf6e269,f4f21b1e,72bf38c7,79d239c4) +,S(890f9eed,47126c8a,355658f9,296b1845,b142eb17,4c2270d2,46293ba2,997e5a54,f294c38a,1c929ba4,2a9234d3,249690d,10a990cc,137bda3c,ada4b3,6d4e4b79) +,S(9329dbcf,45adc298,65c8defb,ee2ce008,a3474855,39826516,b417b9d3,bd47c86a,469a6cde,e1b0c094,f536fa91,f7617890,1be77c00,896efc5d,94cdd787,3886959f) +,S(6fa5326e,7b161c7c,742188d1,c47263a8,2f1f78e1,df83c664,2546c9ac,70660332,86cfd636,11879179,16d51a4,eac57709,5b8abab2,1024ce5d,35d64b4c,78559375) +,S(ece2e23b,8915d7fd,dab9e58e,8489b053,24eb1485,d18eff66,ee5013ac,3e0556aa,6a94e4cb,8fdf0549,a01621b4,438c2757,fe9753f5,13dcbb35,5655f9b2,ebaaea58) +,S(891b613f,413c155b,c2dedaf9,96d75e1b,54a5b5b0,3705808c,f575cdf,1f697ced,11904787,c1fb6f8f,8856aeb9,f7e05bae,f599b78,d7450bf9,13288e95,ff3f871f) +,S(b7bd8742,d1af6cb2,9b55a307,dd3c0318,6923be55,78ba2797,e38a7154,8d6231c,269e9a33,7a9421b4,cf45938,1961b0a4,3e4a0f6d,f6a0f10,2d7a831a,d7d4cd3f) +,S(7c6f5db3,1620a83f,b4388d45,75d244ca,1f38a0d8,611300b5,d4fdc9c4,34a16432,d5c0c35b,e4a371b0,3b85214e,f5e472de,e6c8175a,b140f05f,6e52b766,aa313f7a) +,S(18d303bb,d2bd6f9b,7f941879,6a23fbea,5ece2078,982064a5,e040c95f,c534ad3b,76eaa3dd,b73af546,7b1862c5,7b4385a0,28b03b7c,66729fce,94885373,1ed2dccc) +,S(31c0daf3,31aa6248,de302243,a768aac0,c8e27da2,c2b8e0a8,7fd74214,b49bb78b,e8e1f975,b77550bc,d404631b,12c72d38,55d3bf5e,5477a588,b11d57e0,e71e1ebe) +,S(940aa62e,e3bff798,327e806,b644a972,fae9eb09,dffb8394,61b080b4,708f715d,2853e12d,56898ea6,8e922497,3660a29b,37ec41c7,339b8059,2075c7a,2836c1b5) +,S(66db37fe,3bcfd7bb,25ca4a1f,b2ee09df,5c748061,1c3a6fb5,d0f079dc,cdbf9b7a,a6d37fd5,5d58ee33,73898711,69794421,9cd7a2f3,3becc8fe,761bcf83,ce603b9a) +,S(fb04bfa,a93a8ed9,3d755351,98895c8f,e90d545f,8eb1d08d,5d7282bc,66026e3f,e77f3c9e,afa2791,b4db2f69,3438d051,47edc983,a8541296,a8cae9a2,174e03b5) +,S(5792afeb,7766365d,e6b36beb,aafde8a1,8e556ac4,207965d7,9e18c1ca,63465c78,95fa5ad4,4b93db96,2c26d740,d2aa582d,da19b761,480ecadc,212452ef,cd885b40) +,S(186c0feb,6298e341,a2440465,547ad137,c56593dd,ed82b608,6824097f,3f83f8eb,b3b58cce,8375d9a1,e63500d,141feec1,38778c46,4be1ad43,7c63256f,33ac3b6c) +,S(d39114b7,c22beefe,6796b6ae,3f740a39,9e3c98bb,58b647b3,5cb23ead,76eae678,1df690f,383db8a3,86284ff8,f914925d,c688aa2a,8ec01a2a,243eb309,e79aa071) +,S(6195550f,8ce49ce2,f762011b,2e8feaca,509a0628,eaa93151,4c779616,721b39b3,ee8208f1,6d86fdbb,c75c265e,88090c85,aec112be,a1d803e1,211151d6,cfbeee2c) +,S(a8429368,37b33a8,2d41a26d,e11a0fd8,7af231bf,30d3eb64,73aa064e,acfd8740,18524c63,c0cf7a0a,b4e0eddd,61717f6c,3221a8f6,3522d35d,4eccee30,b6ed82c9) +,S(bf42ae9e,a64351a6,eb1d2c64,57d23481,f913de5a,d3c00359,5eb8cb5b,228fb202,2d74804a,34413cef,8d2cb488,ea780cf5,15faabd2,36a9db67,91549577,70a09d3) +,S(f1bdfcaa,ba133809,f915e0af,1a08fcbb,dd9cb3d8,b62f545d,6b71b44b,b130daa2,51fba8b2,2c7935ed,4241a87,f19c2b76,bc1a288e,3e53855d,c532f0b8,1ee382c9) +,S(7bf32637,4c6adf01,c7796f59,a11e5c3d,103e3339,a0cfbdc2,dec57f5e,69429bcd,8926e57c,a1fe7442,72d2e89,d037feff,df263831,e40e9ac4,8473336a,269f6b44) +,S(95b652a7,7f58b0d3,4c6d25e1,c294907f,a22a3ee0,f8e8478a,4e8458ef,37791c2f,e7dc4caf,b5bfdaa4,7185f0f3,a98876d,b50bfb35,a77a8b11,b522196,9f255845) +,S(d9f8c6ab,693f8058,8c73e2a,9221b0c4,c8f1d1bb,5e1e58e1,8468a48b,c74f50e1,cb38d48a,89c1ecc0,23e0e248,e1991ac4,3fbddf5a,9beeb53b,4cd9c49d,41f42a9e) +,S(43f62528,287e50,5cbf1a68,18bd99c,9f307e95,84e0d73a,f9fefeb5,b6dff92b,85fbb4ea,b81a0409,ce43ca05,3dfd5a1,9756fb5,f4b964bd,dc409efe,696c2ace) +,S(425a68ad,6d20661c,ca7d688,6bb9c66,f37dbf29,30ccc6da,dc34025a,5ea7a92b,7853cbea,d7816579,fa98ab94,875ebd2e,7ceebf73,20b50b2f,7e67f0f6,dfd2eeee) +,S(929ea74f,9b75c327,a7b26127,8828feca,821e4d8f,c5e308da,f3169a2,bf84bc2,f19e6cfe,d8c966da,bb070d42,3c62289a,5193146e,4297fa35,5908663a,a36b0578) +,S(83da36be,b1bedbd9,4a4ee417,f9faae5c,c20a9763,2c1ab2c8,b997f23c,f6d35c31,a91def1d,7871aa84,eed0bce6,12bf6a82,98d0ebb7,536d8e49,f6757a48,aa7a86ea) +,S(a2e1da8b,4318fad3,52c8c285,46f0a8d7,8fd6cf6a,b506f8ac,2d6746c6,75f2d5b3,584489cc,58b08663,1cdd1b7,3e61cac3,52c16814,493b611e,ffb94a71,2cd85699) +,S(5d7c1af4,4b257440,22b82ca2,9923a180,bb7fc209,1990b111,12061b6e,9eec4d2b,b40ca0f6,a974223,3a7b0253,9f0dbefa,1bf23dfc,cd59c747,c290f525,2e960b02) +,S(e2831933,6cce89c9,993bf230,ae4311ed,48fb0913,b5f35da2,b7531418,b512a75b,660aa9d9,8bfea898,810107e1,711abff0,88881efa,4d9d586d,91381b11,67cc2a21) +,S(722c1e28,498d3c21,66fb0f1b,f44e3ba6,181a962,75efeed6,ac83b36c,12426031,27a135d2,3b70006b,480c3aa3,bd057bfa,200da08f,f9eff741,6bff7885,4a1795be) +,S(f3cd71bd,f93f2100,c534d788,ba607845,cf6049e3,b94f5274,84e8608d,7adb9c99,b8e86285,db09b729,dd789293,7cf5fdc,989e00f4,5dcd4916,a6860bf8,d77cecfe) +,S(36341496,d986b096,5e5ad593,de6f88,67aa6130,889714a3,dc0d58b7,19647318,8cbeb984,a3f4bb5d,75cf77ce,14368b9b,77dfeeeb,7313f16a,8a573953,c7b898a2) +,S(a48443b4,3783c58d,4b7b2f27,17efafc5,e5ffe24c,a7c26bbc,dcbf93,538fbdea,33bd2bf6,9a64a742,c461fc0b,b0ae8770,9ed47a9a,26e7d05c,b71e4e2d,20c894a5) +,S(d4364d96,71f2876e,843dede5,9991ac5a,cf92268a,73212ab0,54b1c196,197dddfa,b30038a0,fd9f7387,fb37754e,9b050e80,e0f28596,d251d627,5149149e,880f6d43) +,S(ce277a60,19ac0b41,16b9d863,5a2555cf,30ef3408,f1a15769,91e48d0f,9465d250,5260ee90,65c89bc,7ef55fa3,d5f5d7ed,594fe592,322b7e97,965a9a3a,5654e710) +,S(587ecb1e,7c08da9d,75ed0249,b1281762,e9c71475,5c3ae35a,f7d66b53,c83117be,c6dda341,cb7d88b,b4a1b13e,313dcca6,1ec58063,376d38f2,cf142b56,87bafcb6) +,S(d87f96bc,69510c4f,19b84e93,cd8dd0b2,eee4fbb6,c5c5074f,ea76a209,e059f41d,a9b83947,b557c4b6,41952117,45ddff77,b5952798,66fb4095,6b5361a1,b463d326) +,S(af9f0d3a,78454c,eb8ca65,c9d7a324,312c01e9,dd8a00ad,e923f2f6,41fb0ead,2d3003ef,29a5ad10,20262c54,936411f0,f8082630,8506fcb1,e1848a7d,5d16482b) +,S(efd0467e,f4791ec9,9380be87,394225ac,637f906f,800abf9b,1ad5b3cd,cf9f017f,a14308d6,b0d16772,f36da4fd,d77945f7,1d82276c,ec4dddc0,de24f760,965c5725) +,S(e892235e,39ac312c,f30dfb97,97e88446,dc1f9a3,ef5cb8eb,d540c64f,d6b6129a,5b291ebe,7c055f52,b9fae6ff,cdcc6dbf,f84cad1e,4d35f495,4dc19b3d,64eb992) +,S(3158351a,542ff38b,12f82b5a,daa6ea3e,6e75caae,600b76a1,16ebe3f8,c9bcd66b,2006c258,a327481c,d324acda,b8ddc331,6a6aca81,44dba340,527babd6,4de975e2) +,S(f17bbac8,c0a7d2da,bbc5a5cd,4b28e96,4ab88639,546b2b22,d40c519d,25dd448d,14f9f488,e76663bc,278961f4,a33e11f6,98d6f5fc,1eaac638,79ccfae,1ab40991) +,S(9aa24eb3,44e010c2,d6fd3efd,fa03cfe6,aff67d25,2f08dda9,3d00332d,3065defb,494cc5bf,e60fff11,f42190dc,e607f067,7e355a9,52ccc682,6845111,322ac050) +,S(3f36168d,77711926,deb0f7ea,b6dad80b,8c755db8,e6705fa5,61285f96,84f1ccc5,486d57cd,b46d998a,5d064f9c,68511657,e53e544a,ee8c5521,87a1cd16,4121c6c2) +,S(fad18e89,219c449,87551525,6150e4a8,1fa2b23a,b6c1d90c,2e2f9152,ee8cd054,b285a7de,4eeff44b,751b4e51,f252f3a0,be7c2223,a715e301,23e9bcea,495ea7d4) +,S(1cb1cf55,9c56951f,58147d84,9482dba7,8dc6050e,2897f389,e30aa87c,519dadb6,b9e54a71,93a8e255,b2cf1fe1,80fe54e4,3e17470,60e9128d,bd527abd,c7ef1f97) +,S(74e68afc,9c8d9e0c,92675d9e,2fc12803,4ce7d22f,e31f5332,d18817a3,bd05efda,1d8442db,d55e8abd,aa1de803,f4fb1295,e9a8710a,3f25a242,7af9a5d0,b5dd786a) +,S(10336317,ec82d4e8,543dea2e,b8cb597d,3aec0e70,fb2971f8,7c5699aa,e4576de2,f2ccc066,5eae8645,54816dfe,c82e1162,226ab207,a17c6085,62925f5a,ffa3e021) +,S(b06a55cf,57668bef,6c51bb66,ac8ba7fc,6714c864,ca788279,2c8b759d,290342b3,7311f47e,5b526dbc,e4bc7833,e4c5b45a,190e3517,8f0f8137,2857e7b0,fb1f0528) +,S(af83a357,81306453,e576c819,d1cdacd2,689b0198,4f108d2b,6d9b8148,50df5523,14f52176,909c7e1b,eda13d20,7567f31e,161a80ac,112e4016,ad7c0bd6,20ec0ce7) +,S(f8f56d54,54faf536,3ea98913,827d57f2,a8983112,aa8809dc,594af919,3ae5c4a5,cc9d4182,bcb00a0d,cb73bfcf,da46ced0,ecee167d,fd7bbfc8,899063e8,d659dd7d) +,S(61aa26b7,415001ae,d6b3afd0,1c690177,879cac31,93a2e410,4148df74,733c4ea1,972510d3,697b93ad,60711b39,f3b3c237,771bfbc0,b7238e78,5a786707,dd179f23) +,S(781f196c,dde0f8e5,10ad45ad,6be062aa,1315c246,85d0ca97,21533c65,627ad492,6f3248fb,e7e61cad,1b01ec2c,fdb4dc4a,b1f4dc25,3666d4ae,27a88d50,c566d18b) +,S(c422d61,7f84ddc6,4483d55e,19228dcb,395f16fc,e85b5c93,2778f62f,ce8917bd,2f3cef48,deefbbe9,9477389b,be898cb3,90499b2a,615899bf,1e910e21,ed337652) +,S(c325955e,b56fe9a6,66555a32,72f637d7,3351b65,da5059f2,17748e68,4da4a4a8,3fa27721,2364140b,5b71526f,ad963d01,16889555,bdd42fda,c2b451c,fb70a3b4) +,S(e393cca1,49142f01,9be9a4a6,e8597354,e34f8d55,b400fa4e,8ac6b4c5,7e50b7a7,e40b69bb,44d6d1e5,22cc30f7,26b7a262,3e5b76e,7b190f07,10325a08,a99fb2ac) +,S(33e3686a,e4e69510,e939e53d,62fd669f,f1a39af5,c6179364,a190ae11,a600cbf1,cfe60b76,1306222e,7052b0f1,f799380,ed564d47,1f6418ac,dfb13d98,47f9154) +,S(1c35b5c8,3072f4d9,b3b294b7,69ff1b8a,ed2954cd,a013c7b3,34b53fec,c783b251,1c691a2e,782ff393,b0ac6c31,94f4cb0,f8dbd5f5,b51654a4,3914a458,6b855318) +,S(147255dd,3af5eb26,119e3d86,b2bed206,43579099,742c4ccd,974f7fb9,83e47fa6,5e0a0a01,7497235b,4766b44e,2fbe8902,aa0e2c2,69e7ceb1,d65c0f34,7a97f7f9) +,S(9524d71,57304a13,71d46aa,bc43986a,5ece70cb,ea008aa2,b8c97070,6436b237,a343af97,db30b94b,3d8d366f,1cd27b11,83c9f44a,75f0aa93,8c4932aa,52f6ea55) +,S(8502e7c6,e498d868,3816188,a99d0f35,79058887,dbeb3c03,676b3b91,be7481a0,28bda608,a9e18df9,c304896f,94efa7d2,46ee528a,6061afd0,322e052b,e7cfb68e) +,S(b89a0d8d,a21903a7,200b196e,46714aa5,ad49c5b0,8fc84de7,8e72ca76,2a3ad3b9,953bac1f,85e4f631,38464a99,e6e3be5c,328b3c10,7523701,c60aad8f,d57e6bee) +,S(49bf791d,67125d38,496d8ae6,ffcc25f8,97114f6f,9fcd5541,9876dca,4bdd7d7,6c2976ec,1b9078a9,a90f55eb,510b1a89,17efca39,d2fda494,b9013d07,7f4e05d8) +,S(c63bdf20,1ff5b07c,14273727,ff174322,422b6497,9ca8427f,5f868eb3,a1fcf05e,c4135e1f,1b5a09b5,d628674c,21ead97a,42957d31,92a44de9,b785986b,3269a782) +,S(58c8c84b,e9f85bd,b26f99b3,cde715b4,4b057d56,d5411c3e,a3000829,27ebe551,15de85b2,1467bee0,d4e0b0c5,114fdafd,410cf720,3ab35f1c,1eb2577e,fc2ec620) +,S(5fc5177f,e0b59e31,e4abef85,31f3fbaa,e3399bb4,126b6119,c7acac83,777cf9b8,adf27f69,b613fa62,3cff72eb,4dd10b4c,4009b73f,2cb885d9,57ab8c78,ca705fe9) +,S(1017a9b8,5116ce3a,498888e5,7a408f36,12a6e8b,b18f6961,d6e1d2e4,38902928,24f7a939,5e0d3c0a,579ae611,b733248a,640db7da,929edb24,b11bd617,3e573658) +,S(d9ea68f4,6af94d9d,232a5deb,c485fed0,d719cdf3,2afe4617,524958ed,751a2c47,e59f2193,db2fe578,642a774f,c4fc8515,f638d1c0,ae8081f,e9d3c0a0,fe20410e) +,S(61d975c7,e4d7e262,5b067179,667325c9,a32ef6de,a0bcbcb4,a825d89f,de6f7aea,b7a00d17,5a2d827d,37de6c8,667bebd9,da92ba42,4efeb706,54092342,e644db9f) +,S(2ff5cd3a,fefe0c25,bbb8245f,c9399409,83194bf8,f4599f3,101e9d79,b7f8d9bf,3c154b7,11964aee,5fe9175d,deacabe2,400350e5,3ea1ba23,20d9e675,5aac8fa9) +,S(cb438486,954c4a00,effd88db,29e0e61c,f9fef94,5b42bbca,8939e0a5,dad9e8a9,920ab096,41789957,6c3a8ab7,249ae2cc,73d1443f,5c650ad3,4da9d473,221de71e) +,S(9aaeefc2,889948cd,f59fa4ac,352204ab,46aa399a,c848041f,446be421,e0e4758d,8e4d2899,2ef8d6d7,3e1e118c,70729e7b,4e0bc28,69d7b5da,72df7b46,38fb3365) +,S(ace47cbf,846e95f2,9387dab7,6ed4e272,e32f6215,1e745738,69f2bfbc,720c78f0,a35997f8,37b8e86c,3b4377d9,71098d88,95d6a008,b9d65552,b1385a4b,49c53d3d) +,S(66610f69,1558942f,8285a9df,3081e431,5c946a5f,df958f03,b2ffde5b,c591850f,be93a2f6,53a8630a,ef037f8a,624e623,8f2ad9d7,3ff4624e,f4240cd8,d3495a98) +,S(db4bc8b3,7a12e950,706e148e,4f07df0d,a24d1de,615f2201,2dc1befe,f1ad95ca,fd55628c,c260a1a2,e56b95ee,ebd6b854,f548dfcf,2c4a6b99,7c4e95a0,a52c4894) +,S(a2a7aebf,58a9a58,24d5a996,da18958a,5fc23d8,452d13b2,b254d4fa,bcba959,d6440764,1642f25c,8b31a117,cd7ed90b,dcdc54f9,e652a818,bfa032cd,18bf085) +,S(2d8846f3,fa8a7a0d,408f8ad,bd76366f,4bf7bade,c255e2fe,595e4e22,cfe86684,2c0a7297,228185cd,3b21c10b,5c7f490c,b01bfe72,9513eb63,f2716d27,f0fbe19) +,S(27ba20c,a44821f,d6ebd41c,8c29e584,6237d8bd,13b3eedb,a82b5aaf,10a6fc59,68d65fe7,b511bde2,f922f119,4bb411a0,c000b4fd,268c2c86,e14279ae,9a63e42) +,S(c2f0b611,3a6bebe9,22ec3e97,a3962280,ab0b6713,76a6778e,5ceb73a7,e2894b13,27b90863,65989917,68a9635a,7f6c674e,71a433fa,ce4f1ec4,cd775277,89d290e8) +,S(8420787c,a0df74fc,5c81d19e,64f7ed56,8bc54a2c,ce1c5714,1706888d,bdf377f8,4a94b5e6,ad402877,dc4c0df,38c7fe41,d9e6e085,e70431e9,99c2b724,e35ae74) +,S(29d08c36,c45715f4,1eb5138f,a5c2f002,b4021f2b,bdc49592,e4242443,1f4d5f0a,903d61f7,2e81352f,582ce3b3,ead7b6f9,e0340c23,6925882a,cdb41285,6181bcab) +,S(ccabdbe,f68b6549,2158d4c8,91dd1d23,efa7a84a,a985252a,3a1e895d,757e5f10,94a0e915,2addabd3,d5adad5e,cbcb38ec,e1a045bb,9d7295a,92aee49c,a6f0bb4b) +,S(5bd30e4,9e2ba9a,745c6ebe,434b8d4f,1d8c34c7,6d478ffb,2871466f,a3ff23e4,1067b3c8,5980ea3a,dd1a4cba,8bb0b96f,ad988cc6,4dd8e206,51eee853,915226ae) +,S(eb233898,8f12eb2b,5369d9f1,56d754dc,8733745b,30967e17,697e69c4,4fa80493,c258bfa5,e993ff4a,4a9eb82f,ce1530ce,25fe74ec,2bbc2639,683464f8,a26b5667) +,S(4b44ca53,f01e1c64,8ff41a97,721e7c3,b0d62b4d,b15c5bd5,d84621c,4dee2ace,d8999254,b359a155,99e59761,f42639ad,27caf87f,ed4ddc57,203fef6c,9abbd922) +,S(ce5ef1f7,6cef6b65,35631e65,d4f47924,df370ac8,ce059a19,5455fb1e,b156f7a1,74c9b95a,a4dc212c,3e127bdd,266aa89c,a4773f27,5607dff1,4438647c,f0e50a60) +,S(563d7e99,40325aee,e66557d0,b14b7e8e,14f86643,de2b3300,1bcfa7f1,ef788bc4,ceebeb99,9878a305,1a8bd9df,bd6cb2f7,3ac18776,ea78df41,30fd22d1,bcdf37da) +,S(ff929868,fb5a1b53,6acca702,f5dc1e83,efe8cb96,f96a3303,d107c6ae,ab5dbee3,82828150,fe8fbb3c,f2bfe03a,3c79fa5e,67c33d97,b12faaaf,572b1455,6ae11969) +,S(1004e4ad,487212a5,8af57ea1,49e0edae,6aac884,2f488bc7,1b75a5bd,4a20204c,88d9a6,164cbc21,52d60ee2,7c8003b6,b39e418,b10c72d0,504a6a7,d7b8b2db) +,S(28dca143,206abca7,1c48137f,8bebd26e,6c79666d,ce164fdd,ef1ca7ac,8e141a25,ec1dea42,575e5cc0,804f6da3,21ee739b,ff244cb,2b299413,4b8539e3,88f7ccf7) +,S(cbb81690,a7e511bf,56a5190,b9366345,7b4fe8f9,64b8fb57,36df2067,28e1ca48,c2d2686a,5405dc79,d6a2deef,95a97813,4a434309,c5303985,f173015c,6571e5e) +,S(3e1e663e,378c44b9,b61d04ca,bfaf65fc,df6b59a2,ae83719,11b11582,978f008f,bbf4b3b8,2010fd76,70d23b07,6018708e,8f78d70a,b2da1efd,be668c9b,d5125d51) +,S(7f742a3b,9edf6aaf,cfbbf368,5a622318,1a6c3b5d,588b74de,c2d2c049,91d97784,238a4f6b,5cd25489,1b8aa5bb,41f253e6,6a59a020,bce98966,ed4c75f6,b7939e32) +,S(f073f95f,f6c809d0,9271eb48,abf35b2d,b760caa6,54b0969c,e327cff,f806f43b,6a7eb8ce,9e297e07,170e9287,7fc737cf,bf923cc1,e72efdbe,5b3b4920,6602746f) +,S(855f6451,5b98ef1,67d3a11a,fec74625,cf3801ab,75df42d2,1b33b1bc,c36d074b,6e8cb794,9990748b,f54a9291,e7ec374f,a31bef56,ed1812a7,7b2ef00,149938fd) +,S(f0164c7,f204384,d3235b4c,cc1bb9ed,bb10cabc,d69c02b5,aed1dfa9,56c74d49,872fc547,78580a6f,38792974,a64399b8,cd674622,659ec31a,91fea06e,77e27118) +,S(16e83238,e95e29f3,ebc297e7,fbbc77eb,53431f3,cc90f809,1e540457,aced09bf,3f3c0ff5,754630bf,88ec765c,a5c04da3,f6ca4ad5,e72d9c0,715cddeb,69c4f8b0) +,S(70d371c8,8b2e47a,47982dfc,bc98ffd8,324b6bcf,2f1aa2a8,f4815f66,dd4949bc,34cc039d,3c69b4d1,833375db,e7315340,bab2452b,2a82163b,dec73702,f4c8da46) +,S(db250b65,6848570b,5a59a2f2,d45e99d2,de1b3813,46fa6ce0,8bca0b34,57c27d10,2859a0e8,fde87061,d7ea8786,f5667aa8,b2633e8c,c52926cc,c5427d64,a7ae6494) +,S(d6ecb3fd,b1ef3350,a2a831e2,321cfe9b,6b22b38d,6a8fa0f,b256f2cd,ac73f949,ad83f35b,c1b5c568,49436cfe,6ff17f5e,8abc6891,e24f4a0c,524d88e0,6c3f1028) +,S(ee2059ff,a2c5bef0,646bf76d,ae2f3bfa,193b8a28,bc74cfbf,a96b48,921ac0d0,3a8f4693,15d6a6e2,2e57edb7,e5897039,153e0283,8d66b1ce,1814ac74,195379e7) +,S(6dd7fa4d,bc12da89,1669cf7f,b1024a8a,551d7281,83fd221a,7a0ca9a0,8c2aa725,67fe6a0d,fca0fc02,1fc89584,d2a5f19e,ce890708,490c79e3,cdbd43ad,ad24493e) +,S(15102e09,b966ca25,1a9b4609,16ca1229,7ab64d60,980582e5,e8bf0e4d,80fd6c35,7ebf61f9,956109c4,3cfb52ad,4e60078c,93ea653f,17c7328f,9120545c,48988be7) +,S(a0697816,4a0511f9,3a48efe1,de74992b,54679aaa,a99e328d,6771386,945e9039,92d24154,971add65,c40e6f32,a5b5fd01,765effb6,c8d64676,c9d97e8b,f857d630) +,S(ac925df1,3a9ce7db,18b9071f,f81880f7,c8ec97be,4b78a31b,27917d71,da0defce,6347aee9,abe9b2bb,1f1e3ab2,2792009e,ee009011,337fb184,d3f637f3,186acba6) +,S(74f3c7b4,e237db77,9229cb2f,1fdba8be,9ba990ed,6dd84976,ff92646e,55e21091,44e9a71e,a07e4254,c4dae620,9c437873,7c56187f,23f42224,3167e45,932055f2) +,S(78f0a024,f6a5bbaa,f3eaf550,92a55bae,73348e82,37dc095c,11ee34fc,3194eb00,54e9b6e7,2f758d54,23d5b9bd,b329262d,6745eb32,c93c2571,f86f40cd,1cfeeef9) +,S(83d3e538,92d722a4,8c006910,a22f32ad,2ff7bdec,d9bd2ea3,a2f315cb,550a1bc3,a4f3c8e1,732b23ae,9f21c03e,7c3711ff,687683c3,13455107,68278332,8d9a25d0) +,S(15deb2e3,f0f0b65,5edbb7d1,8d86cedd,7242a693,a271d853,b468d57a,52cbd647,7cb1ea70,8e12acb,6bbec5ac,26f513cf,51460493,9db6cccb,ba712561,a6f4a80) +,S(6fc5c841,eca2637b,67fcd5f1,3c3dbf40,3b00e4e5,270bccad,617c58af,ac54195,afc3fc7d,92f0f77c,5147ae41,8aae93d3,b5cb7785,d65e623a,391d6a06,1f82d4c4) +,S(154dad09,40e83686,d0942998,e220f8b6,bd106af7,beb9bc66,1f1a4c2e,29300f20,9a47095d,b2a357c7,16d8773f,18c953ff,dc0ed270,1cd881f,f3088176,e61bd7ed) +,S(a498ef6b,89b882d6,81ea0647,f83d53aa,d1fb39e6,6bba74bf,8008a43f,197b301a,cf4d289e,f723ad46,27edc96f,5315bc2c,9ad39c04,4e8e6785,222ca142,3f5c2881) +,S(5c01e4d2,465c3326,1828c45d,bbb2cf69,79cdb746,fb659a6b,44f0f2f1,f388fa3f,315dab9e,5e53f939,610e9729,3e686d33,e46f8262,5ddfb45d,46728b03,927a6837) +,S(d058f58b,255164fe,e6d60472,2b32624b,2eb523b,6c7f1e6a,7ce1c248,fb3fe505,21761abe,1bcb844,39645310,7a3dd2ee,28bb4dc9,93dcd0e9,a09d5176,1a7c6536) +,S(eb89dbf1,67c1352e,5ea2a7fb,206663b1,8c95d962,cec35412,3b9be6b3,51799ca1,9566074f,ec54174,a49a5f84,e4965174,408425f2,22d485ec,b020740c,74b08ef1) +,S(19ddc300,84dda580,db5b1230,b0fe9508,5575eb10,680181ff,ee0d521b,17b39cb8,6af18172,bfb03b77,db456836,b9617f05,bbcbcccf,f6ed2dd9,a9c6e734,c01d188f) +,S(66240aec,7e72f707,69560e0c,f31f2c41,9a8efab5,32f17f59,19bd56e2,93c41e13,16fad661,3600a79d,41eba5b2,d0721dca,afe94372,fe83b20f,7178e29a,e6f3949a) +,S(3c75905b,9e7c7751,9f4617ff,6010c39f,92b852fe,89dca73d,cb3f15b0,23f7a286,799ffb8,94fd4f3e,61dd489f,da746fdb,ae955eb1,3c8dd9eb,e4f73d41,2feccec1) +,S(9719a34,e765cca4,68ab3453,3c6dedd1,6247af51,b73295f6,8b936914,c03f10a,4d4e7f2d,ee3aec6f,71fa8978,f532e995,c0e1533c,5cf0b51d,f35d8f8,29cc10ec) +,S(e32f292e,e5c41e2d,bd262c45,eda0b729,713207c0,17fa5c47,c8bce6,ca550814,105716c5,5995ffa6,998f2209,b9d0b37e,f2bd78be,527f6c12,b707faf1,ef73a82c) +,S(76aa4115,595e7656,c76300d0,a60e3316,fd9c1b60,d41920a6,128e59f0,74a9dde5,f3ca0754,b6daef99,acd6e1e6,fb36d93d,e068c0d2,26b843a6,e7e111e9,9df8efda) +,S(215186c7,ba018fee,747c2030,f57d1105,945b021b,be053da,efb1136b,f0d6f0a9,62994ba3,62d9a8a0,7432690,689a859e,ef498860,3d52352b,e27e0f8f,d02e4de7) +,S(62e16f47,4d3ce3d8,a21f0c8c,875eea7c,111ca0f5,21c03f54,6bcee790,ab0d48bd,e9a8c8ab,99f916e0,4141972c,f60843be,72088d1,e044b27c,6a84b21f,c787abb) +,S(372b5966,8b00faaa,a714e7a8,2462107a,3d1226e4,988faafe,988d06a7,dfb27bd0,c6d349aa,6a53d0bb,185e0f59,a4c137c,8622be1c,5df205f3,4b090080,bf4e4035) +,S(b11cb8c,cd6302bd,e6005ed0,9a1ce2ea,a81fbd9c,748a17e8,fe1c139e,d2d1d725,29ec84f8,e8d627a6,b81a63c,4b13abb,88d7e5d4,9e56e2b9,a3f15f40,60efa38d) +,S(652b5427,f45d07c1,8cd9afb6,7d5743e2,836d78f3,528917fe,2a5c6162,c4a06d81,3e93d9e4,25ce53a4,915bd12d,4327e89b,64a7112c,5ebae53,35c631c9,64b2e5f9) +,S(c0812ee9,89fa0531,56847bb4,edd517a6,7d6d7d0,90ab5955,a59326da,f3833afa,2450338a,cf923109,d67b0501,3557f310,f3b0550a,8f1cd5fc,6eef8a5c,14b46c27) +,S(627c169e,fb0d9937,8ddd0fd5,a73afa16,2a317e56,7d957695,41e52a41,d9344ca1,11dfbcf7,75bafe74,eec503cc,22c8b485,90a17079,580acdd9,c51158f5,efd0cd7b) +,S(69916299,5b83ba3a,6bf16e2,97e8031e,74dc9054,c05ab59a,335a8296,d876a66d,39e45d50,aeceb888,8a1d64ab,9cb3b127,71269b7e,a14ca4eb,2179d762,4ee6d953) +,S(6693adae,579636f3,2332a418,7e49ffc6,921aa51d,852b5136,9a96c8e1,cc268574,ae73a660,580a4005,50865060,dbe9ab43,2f304ca5,506b9f4e,7e17f602,1456bfa2) +,S(ccc178c,7168ac1e,e7bf7579,f75f9645,5ca2b558,e1e709ee,de86df5e,5ebe0789,81c63b04,eddbf33b,432e00c5,9e76d319,fd1ef2f7,d6f31349,1f7a3c10,431a2130) +,S(d80687f6,89f7c28b,d6ef1531,c4e4b283,c6e5dabc,ad7fe5d9,6dc20d30,e1feeea2,71e24cd5,9d2c33ac,2b298946,bc90e0fe,d229720d,539a6f5,e128973a,9bd6c5fb) +,S(c53a6911,88f785f3,efc1fe1a,d142a259,cbda5f76,f3e9de36,895a8963,ffefcb74,7a225bd6,a348728d,951d55bf,257de9e9,d88df32c,ff2c4391,f4ddae8e,ce357cc0) +,S(d512c64d,1932fd1,5636740e,2bbd302c,3d8674e6,52a30d40,ce879145,bed9b7c1,52e336dd,3c7eca6a,469bc97e,a330fa03,1cda3c57,a4354ba2,acffcaa,a1e6b424) +,S(384aed3b,531098a1,99312d65,74b1b1bb,e79a8bf0,ea4f7a86,c5114fda,b32061d6,f2290bbb,2bbe7b53,eb64f87b,17a9e1,49356d9e,de3c0be4,28a4dc7d,709ef731) +,S(6db6c2c1,1fbd5b92,31a4e34f,ca2f9315,dde00dee,909b8d53,d7149c6,6e3cecb7,cb2f0b26,e1bcd464,6e6ee074,8efcd499,f535a8ba,f61a38e7,aaae3511,3c781649) +,S(6bc2f0f2,c0118efd,4fbab4c4,90c56da9,d66c0b1b,ec88e8b1,c8da967a,95d1ae60,a568f40f,24e51e2a,d01c13de,4490f34d,5a5bff13,e005ce77,94a59128,f6d871ae) +,S(12e4e92a,aa40ad9d,281316d2,358bb0d6,c69fac28,24114a9b,a96091d1,64ee29cb,f717cba6,b07eac9c,34b8821c,218519c3,886d5cc7,a22be959,54b3eefa,8819bb51) +,S(6dee0e1c,b887e155,e67996de,92716821,7874f9f0,a14c8673,1eaba91d,272705b3,28d9f2fc,23807874,9dd40ac1,8ace2dce,18ac3980,7c7a5922,43260eb8,ededbc3) +,S(f9d667ac,ec2120aa,50c2b6f0,810b54eb,4928bef4,779e2311,7d12eebf,d093f139,29c9458a,52d4cde7,e32a265b,fb537b3e,5a5fdbe6,ece9be95,b645b960,c160166d) +,S(e026f66,af79f4ea,52955b52,bca16e2f,b2cb05f4,38568c06,ebf1ca25,e6f5be17,6319ae60,3e733681,c8caa501,d7715b98,6244c1df,1c42d391,d8d47e15,a681df15) +,S(1ddd29c9,bbb37823,1185f631,23d5e1fd,39c6b03e,44e2a542,318a6f3e,8325ffb8,22d80158,cee2f596,8da360e5,93a2a86,ce1ed25b,77a4d66,a2e7592d,26c2c715) +,S(138f88f5,f9f46b81,2246373,6034958a,d5476a0f,348ca538,f789e980,9c799f30,adac6393,3e2de680,6fc38d7b,23ec5214,43ab505d,cedde216,6accf786,bd4e4aa5) +,S(b516a9a9,4630ba5e,7469d5e5,ee0f03c2,51bfdf5,a1983506,79baca9a,e6de6f6,9c184956,7ad68859,89a2013a,5a902fea,66d398e4,6c85203e,b7a143b1,90b42587) +,S(bb1a5499,548ee5a6,79500a49,a1466b11,9d56918a,735c3e07,31939ed0,2d47abe7,b946e966,2df43be8,6478e809,ac690d4d,b25398e8,de13731e,89867f80,63f8021e) +,S(394ee032,8be13bc3,ffa069f3,92b72070,36ad018b,503ed70b,9bbf9f7b,458faf36,3a494b0,dd538dc,fa3a10e9,70b83c4a,2169b4ea,255c6423,50f7ee72,40a6910d) +,S(a021889,ce4c941,606c0226,2b423afd,f44d6a75,483dc4cf,797b3512,8131e2ed,d8ae98ca,572b5a38,cd10a763,6638c47f,2867710,373af6a1,bfab6cc9,64b26547) +,S(99e2cf77,a0f389ad,a6c21457,d3e94ee5,95fded19,89c326da,3cef2e49,670f2572,8144a88c,a90a7685,ea3155ea,8fa5cc0c,c282fc25,532aa5da,84494b97,94810a1c) +,S(23c4b50e,80278869,b77c62de,8232a70e,52a4a3c3,4d0d6114,78989746,54e57aca,afba6a63,e35b15f3,1a24e5b5,844b0f3c,b247deee,a764b3c1,1075c3b8,c65bb0b5) +,S(ae0ea240,91b09648,6bd06ec7,ab6dd488,fd6669be,58c2e91d,e8486560,47493d5a,63e13a3,aed0b2f5,a11e914a,3617b1ea,abf62d4d,731eda05,62251d76,939aea63) +,S(d9e9ec51,cea0b150,28199afd,70fa86ef,dfa90e86,b9613831,9cbbeb86,c6573bf2,561519ee,f8dd5ebb,df47d4bb,c24eed76,5ff4342d,6ec6e537,8a2952e7,db51354a) +,S(e674a628,7472d602,8c0b888e,1dc86429,207e38a,af61d3e7,60708721,c1a44613,c145e723,eabf1dc7,f09fcef,1ae24116,1bc0d24e,9c96c83a,3c4e76e4,cdbb9e7f) +,S(19a43fb6,ad571142,42644af6,a3ce367d,329f44e5,bbbd8948,9368620d,944f413f,29a616f2,5f2bf4df,e516574,cbe840de,9ab9ee1d,abc86ca9,6413bfb7,a79a4095) +,S(cf1e1a87,32eb52e1,660186f9,6aaa4cac,9248d8ef,2738a6e7,5e600f3b,658825d,379dd9a1,8355ac8a,94a9614b,e3f51540,c17a76dd,3e3f853f,252f0e75,164dd346) +,S(342147b5,8a1ac1d0,baba5b2d,e924e7a3,b804e385,466f5ae8,29138bc9,5c5b386b,9d8792c5,8917aabb,6a3cbc4c,7f18d2b0,768dc9b9,1871bf48,8ebabc00,f51e2bf0) +,S(1c24e35d,35fda6b1,f6ae6b43,7599ec91,dff1fbb3,b3d26976,783c0539,a8b9af32,58591ff1,68290b12,d729c621,f5da504c,e697ef00,7d922152,9a76ed61,2dbe8608) +,S(d0fa4d47,a29e1101,baa08cca,73e00d6,660e2588,6e1b5cce,ee1c2a5a,9fb806da,918cb1f1,608f9e40,37a59bb7,28c25708,db898d76,a8b2e2b9,d4450c64,3606212) +,S(f3307ffb,7e72413e,2207918d,8a93f183,d5cc93e6,ae07d196,a6d22f1d,253b2499,8a44b83b,feffd6d2,78442d72,51929c0d,42b690a2,d91d99bc,c5dff056,d37e1f27) +,S(77e612a6,9931080c,7d910573,fe55582b,30eb4ca4,c7b7fe1c,9c4eeda9,b296097f,cc85c0f3,6f020bb0,9705f560,15268e36,bf61db2b,814b51b7,c958f1a8,656c26b8) +,S(fe3b3fdb,b8d768aa,8248087b,70e6d0de,592c95e9,b9816996,a3b4c88b,21bb9605,23b44ffb,20e8fc95,ad3c035e,3f52fb53,51291965,95fbda63,8a192cf9,43630e0d) +,S(e664460b,253050fd,8814a2,b2bc0f56,fd8d2f53,94673a67,9a76eee3,f7ae6e80,bf0a7515,a0a6351e,62bdf527,6974f06d,be87345b,438eea33,ddb980fc,788eec9c) +,S(b8ab3266,6cb96b06,a363d87a,a7ee820c,695b7372,b9341b,292dd0f1,d5fc35af,720da144,39ac9d53,c480dc25,5eb45ffa,b9e406c,8eb5bae5,1c145058,8120f900) +,S(38242b07,d1904c72,6da9ca1c,f1acced2,96c1c4a9,b37671c2,e529917d,a651b99,3d47a793,688603a,d6ddfc87,1c85a19f,e21ac51b,d292ff7c,69e219e5,7a0dea85) +,S(ae9a9354,e451abb4,454766fb,7eaac21,5982008e,6cd47d7d,df5a6289,27131913,46d291c0,7f99fbb8,2eea4c66,525602f9,6af5c16b,f4c31ca8,c26a831e,a39985f) +,S(59e59fd6,6a89a538,f5277950,816bf2dc,7070f70e,98d04b95,1b83a80,dab205a9,cec6b519,4d1122d6,dd3e39a6,fb3e80a3,2d829158,3ddf0bb0,3dc3086e,9f247f4d) +,S(59aade5,c117e92a,97ba1785,2e1ef3f6,d000620d,a8f82e2c,1d4272d5,34a8e22a,6a6b6ab1,bd9a69cb,181538fd,eb4a9e8b,eda75811,96ef31ae,deaf516c,e68c1cc3) +,S(f29d02a4,5b464774,fbc1bcd7,7caaf22f,12efcc9b,2a569966,b9adbe8,18a9f075,ba87956,5e0a1c56,fd03175b,a781110,3f34542,ded10367,6d44f706,7b8ab418) +,S(db630bf6,e9ff0092,eebeebb8,a5bc72e8,774c083,cafa0519,2e6d913d,112181a8,6b764e8,2213a7de,79b9abe7,edabf502,d9ac04c8,eb5a4b26,9d22b666,f657685f) +,S(45b9f064,71b848c7,48ff3fc3,34d425d2,57a71abc,27c4d002,dda26c77,1b09d2b8,c2119389,e4cecaa9,c0c72e4e,20c95cf9,1acb1698,c0bcfd42,f8620a9e,d781de57) +,S(d4919e2,3a278aa4,25bb55cd,2fdcde2,eac63058,4cd57f50,390c6a9a,1015ffb4,f8e9f461,950f17fd,8c46f04a,3a6f3c52,5318cb93,a0aa3f3b,bf90c02e,80e1c288) +,S(ea000677,2a76378f,3faa3c1f,c7227cc1,4b11764a,3c9a14c0,4f18f9d0,b55acc46,eafaf0b5,9a308182,8e6d07d7,2e16509f,bbf76fbd,e1473e35,18b795c8,87ff84c6) +,S(70b539a4,4750f763,be1145b5,b433e98,847545a2,8fc72986,2c17045b,f0d6fded,d5438ebf,18eb5feb,fcf6edae,4fcca2af,e0208adb,2f82648,2af428cf,bc761464) +,S(10b4a235,99ce2be7,fdc31f8e,ad91523a,47b8162f,8ed9387b,4c208657,25fa88d3,773ef1b3,a3943b86,729661bb,6ce6f4ae,e8c7165f,97a88fe9,5df9e027,3ccf9e7c) +,S(67d7633,499323f7,cc378c5e,2e62cc6a,5f34ff83,e11e6061,9ec4a404,d63b91b7,cd7616ed,60f0f4fc,1006dcf1,850807d7,e8730954,30db6761,cb7cbbf1,a9c2958b) +,S(5744c77f,8371057,61b1c782,1c9d9c53,14219e1c,5df80ea0,f772f9fe,ff157aa7,578459ee,13ec92b8,b685acda,a153f24,f6c844bb,e195ad58,77364ead,7a9e5fa4) +,S(7c6b254d,39ab709c,cd63c2c2,56c43483,183b1b27,25ca49a3,19753f68,6486ad02,5669fcba,d8662be6,2d12cde6,30102f3,70f7ef0b,5b347fa8,6000ae6f,497fad6a) +,S(8ec715c5,bda8f9ef,3b197ea8,a182a3dd,6cbc3b8a,88227e00,53a2eefb,b2006676,e59ecc81,aea7f2a5,4f659bdf,a317bada,3f8ccb7b,134ae21d,733b9710,335e73c9) +,S(fc7eb1e0,95d0b18,58d22b5,ad36fbac,1b513d86,2bb3c9ef,61b55a5e,985e642,7206dfc3,10056bcc,4071e9f8,13495744,dd903d72,2aa0d6b7,3fb35394,4b66c85d) +,S(4954bd00,308e205b,90c191ab,6262daf2,81939084,668c43dd,1ae998d7,e143f1dc,8efa802f,e67f72c2,5b4fc279,4e23608,7b343d89,255272d6,3c3968c8,7f26237) +,S(f27e6c84,f60858e8,2eb53d39,a6860189,9172da9c,e0d1ea70,9225effe,23de6969,90533e33,321f1f5a,ce37ff79,b4dd3109,a1efd6eb,de502aae,4dbdf58b,1e697c74) +,S(166f3aeb,cd040509,85df120,edf55c1b,f6eed0b5,fb24173d,c7d9125d,d0b2b29a,54b8de8b,c24b1cd7,8f89820f,d4b3ac6a,1588ebce,6de99b9c,81773ba,5fd32e20) +,S(c0797522,8dabaaf2,b46108c4,88ebd104,b0bfafdb,b344b5e0,72f6cb6a,f58f3cdb,bae0280c,704e0d0d,2d421b20,828cd00d,9b388f32,fcadb511,ad5ed4de,281a4a29) +,S(81366739,2085f96c,6a39c9f5,ff60b51c,4991a289,7106619d,1ab0de9b,34de87bc,d7b8599,2464c1e1,9f575cfd,de5bec08,987230b6,20d911d5,d6dd3d2a,8a75e079) +,S(335f446a,f3964e77,8f4985a5,c19e371b,876494b4,467ed700,482558a,9cab3c65,6e8fa42,24cd52c4,b78af9de,b7efa726,c26a94d,85bfeb6,fdb1b97f,674cbe6f) +,S(b6a34b42,bf5e4781,df14fe99,1a14b414,fa488da2,29314366,1ba83ecf,1e80d60c,b633c9f3,cd359dc9,2ce47287,670fe80e,131315c1,6fc17811,f319f1e9,82f88e8b) +,S(95f99013,a9e937e6,ff784b07,23287960,5eb4532,e16b3881,25a18012,17ee3ed9,2d0fa2ee,1aed211d,5b90915f,f3b2116a,28528f19,35b6b534,333b102d,177c08a2) +,S(9c0923b0,d681933,bc8bca36,a6af4058,682c5661,95d3a211,a1ef602f,933f6a45,a72df8d,a9a951e5,a63f0424,4974d74f,fb809cf5,fe7c24da,9c1715a7,2419c7d5) +,S(931cd34d,e32188a8,802b6a73,204eadf2,cae8d8de,52423daf,daf042cb,946657f1,d84b7406,d58c53e2,89ca15bb,4ba78db3,6bd2947,34d0ee9d,6939c15a,9f28b856) +,S(24be4b41,f845c43b,5fc594ac,90e3e4aa,b49cc79c,4b0a8408,1803c27b,ce62fe4,c6651cb0,be54ab0,78940179,6dca2448,3d9349ee,e45e78d4,b786a636,83861bb9) +,S(f19a51c2,ebff1d77,81b0e7f0,a29947fc,3ed9dd26,9f0b9cb9,c27c3f7,500c81eb,8e1cfe92,6128173f,556b3ec4,4c394ba0,201a4f93,e2db054f,63934b2,479a301e) +,S(f6e7e4cb,88ecad49,a1653a6c,5510571a,cec77024,2f490774,a8dd62a7,d6e16363,60842dbb,b8ae082e,9538e725,1a3dd7f9,8edabff3,5444719d,97134a3c,236c97b3) +,S(e7b7bb26,af8cc2ba,6e54e923,6af55e40,7ff704c6,1264cacc,74d96b52,81f2ca00,3abaca16,e20f74d7,6d11a942,415987c7,8da5ed50,3d781f2f,aba6d534,cbc3908c) +,S(c8acf1d3,89a29f6d,e0d03835,80a0a562,aefcaa99,b184f910,f2c8370b,bedc4c16,924e9b2e,2c6463ac,e8eda0b3,feee2f82,73050559,1071bbcd,72f6e323,31617359) +,S(1453b2dc,efe09d16,373ffc2d,42e79805,64ff194c,6b9944dc,b12d3cdb,1d84ae27,2d7faeab,7ca11212,a1aa9d4,a462c04b,8dacd2ec,1f7ee3b8,28fcdfb7,a26c6e17) +,S(ae92e090,b3c6ae15,68a12c6c,882d1b4,345f0a46,b9ad364,bc869243,dd533f4d,3f50449b,a3865900,ff63d944,27a0b967,56c00179,5b5f51cd,5996ca2b,19ad7abf) +,S(3086b503,ad8afe4d,fe2795f7,c972e0c0,8d6f040a,1be88309,606fee4d,b977fd06,b8631fad,80689ce2,7f62db6c,d6a56f3c,d3dc110e,610f3732,fa3f2c10,a4d588d9) +,S(7a17def1,e9c2b175,9944eb35,262908e7,c988f602,2440e151,928dfb44,462e2856,42171a1,f71ae8ea,d437a1d7,e1ec3394,b713044d,6c895930,2535787f,b93fcec3) +,S(97975e9e,b0698b70,995411da,37ce2a87,91198b90,e104476e,b86c4a77,dc5ce9c4,b8999b7,69b36de2,13cfc81c,c2fffc3,65e5dbc2,db1906a0,ec88e931,cd05bd41) +,S(839fa603,a2ec722d,1253328e,15f7d187,55ee80fd,b6bc7b09,bbca59eb,316d1b22,4e43cdca,1b33fa9,cf397ef3,91d40b46,fdcfa770,b2be8e9d,9ee22d61,6e12dfa9) +,S(ccfb8b97,7baefebd,eaf49c7c,1ddada20,861e1c0d,acba4caf,4e30f21b,ca3a05a7,7d9bced6,62579237,a348071,3ea1af91,256e9d62,1265fa27,cc80b5fc,cf75f99f) +,S(8f9f369b,3f325823,e8c9b16f,f2142ebc,3c6f7bfd,dd28c4df,63d1c92b,581cb6a4,114c7d9b,3f54f549,c10d93d4,25843477,9c297e2f,3f07b208,12335fe2,5771b12c) +,S(f0deaa5c,324c5ead,6f6f1cb0,cf1dac32,ef342606,3533435,65ac164a,ac8f0f2f,ef6dd597,e2203c03,f0ce0780,bcc1e963,621c1460,7a4ce616,9ee6624d,11c2eee9) +,S(638362c2,18c9e0e8,72dafa8e,fed86fcf,da5641eb,7cd01725,9a85103,f04fa408,3c224389,bff1fd09,338ea28c,7c9a93cb,32be8749,4a6c629,5c1c3dff,2b582877) +,S(49acbef2,64708117,a53f52e6,84bc15e9,d004baa2,fb3a756a,72d35efb,49871759,b678efb3,fa09158f,d1f9c74a,87a56883,b0a8316c,d4848ef5,1f35dfc0,8c4b5bb) +,S(a79d63c7,b718cd66,b393e70a,f032bc50,a90209b2,5f5b07c0,303eb8d1,1db618ee,ecf7f89d,2f6f9877,9b5e390,ce5837ba,49bc2b3,a7c1047b,7a7c852e,89f1551a) +,S(c922d543,f192f654,3445d3f9,c36a05b8,2ee043e0,92afcae5,a21b9b17,a06d0257,cf77d5eb,9e555f90,34ce1c14,63f7c4b6,a0202d81,deb02ddf,a26113ba,292554e7) +,S(dbb8f077,b411a4dd,faf0d89c,3dc20375,1bb20e16,2052ee46,915528e5,1f461387,a6c0d5df,91cc4ba1,cbba0588,774d47e1,7ef97281,63ca8950,7ff6b779,da12b7e6) +,S(dea21a21,eccb1733,14d76fcf,dc6109c8,88a633d9,645f86e4,e59ee237,cb18110c,a1390d1d,69a304f1,a2792ecc,675f2dae,1ddef908,2f2e3929,6b9a068,3933264b) +,S(f088ed85,750dd58a,cd03b3a9,93d88760,34f50780,985f7552,114f957a,ce8904a1,b810e652,f596cb80,c369f61,f632bc3c,fcfb1fc2,b906acaf,c1f39d02,5e3ae4dd) +,S(b85da431,16b898e8,56fe3c18,b60a48b7,c2ba9f65,ad67c31d,f45ac3b6,608b774c,357d324b,474ae7d8,97398506,c550a1fc,5353a00c,7e6f1245,c0f57683,80ac9e1f) +,S(eaac0d2c,276000ff,899dcb3c,61b41663,70123276,14585bea,7704de95,d164514b,aad696cb,1af2f12,1ba915ec,64afc13d,a689719d,8f188424,25d6068e,9bb06a69) +,S(7a3cfc7e,51fbf61f,ffed3430,eb9ac40,c84164b0,21220837,29f20ed8,eacac977,9015b896,e034d2b6,684f7352,185e959b,5c45406f,6187930f,82f62269,d3ba70a) +,S(5a9def12,e06f0ac4,35b9f853,53db864c,77288050,c349ed7d,a8d8b109,b001a856,b63b74ba,868df816,9dfc30a9,1efbae1e,1617a230,3ed20239,9ecf5798,5ec4bf99) +,S(b937b3d4,287a0f84,5323cc72,95b4a201,ba9d97d3,2d968533,7caccbdc,ce8623ed,6f2ad251,a66e5ff0,77384746,9208db13,2a396dc2,17e781ce,9aa8d556,83fc0adf) +,S(d44f7fc2,97e079f4,ba0689de,dc743d4,964c6ab,8c34bbff,f95bf22e,b7d3c209,b5afe3b6,f6b02542,e6ce811b,f4bb0fce,79e7916f,fed8845c,dd83de07,9320a2d1) +,S(5980fbb1,6be7acd7,b090a2b1,c83dbf80,9148cc99,75fd6834,edf564c5,50fdf2f2,72340269,8d22b946,ae51c9c8,33d5b44d,ee884a02,e12a6d4a,23957483,32abac9) +,S(94733aeb,dce57a89,16961f41,3eb04b5e,71f0a055,29baf93f,c9ff178a,12b70511,e591b62e,5cf92ea4,306e16b5,acc5958d,a5516bf5,7a7dab17,db38cef7,44302c47) +,S(1172b006,3d5ae491,8699e756,75ddfc59,fb5cc8d4,f332ce72,f99fb99e,c9799d96,2845be1b,b97830d3,f9d04a3b,36ae381c,5654bef3,f3fa8516,3a7b9738,ed867ef4) +,S(29afd093,5ca567f7,eb4cc1c2,ebbbe8c3,bc405691,b41a2812,b7c71312,81bbe691,77e9a59d,c0aebd28,9cf2960,ebe7fc19,236c1859,7882df0f,a8e6e0c2,6d92b821) +,S(191c7ed6,72c36def,576f645c,6b475eff,793119e3,ebc3a29b,71eee3c9,cb52a635,642bdce7,90d0f104,54ebe4d6,282be83a,443f8f44,faba4c76,5b1491d8,c7c83210) +,S(237eff13,89c20d30,9902a738,fa4543d4,c2a4a2b5,6731603,500997bb,40d28eda,973d696c,ba9eb05d,73ce7491,5c1cf3d1,5a998608,7ce85854,f7bdd157,3d5c7394) +,S(d4985b52,80673074,53ec0edb,f02b9d4c,b1ce9a0c,af7c675,77789b8d,f3b5ab33,ad8fa145,94c510a7,830f3353,4ac94a98,cdf2fa30,b6a1b572,9222969c,e27eb1ea) +,S(3baed9b6,25f5d0b2,6e0132c6,20a9015,f79bd8d1,8e5ce170,20fed78f,a2238914,6ef88df1,3c7a9023,1180edfd,d041b950,3ad89f22,4ec557b7,2e900bc8,fa820c19) +,S(6e2298a6,102268b1,af97bf67,c0aba783,5463165b,1df8a824,530ee5d7,86d354f6,c3864e52,3bb5cfe0,a64adc7a,9e8926e9,876516a4,c83767d8,5ebfc39a,e125c19c) +,S(f9e87f15,2412598d,775131de,abbd0272,4d658849,cb60aac6,92280e63,8e835e9,e843a3dd,a30f9685,70fcf86e,86206c22,af40ce3a,3beb620c,aa167e63,271d95ac) +,S(f9925b7e,80b8b8b1,b5c56f80,74bd5ee1,9e419678,2c5a33d2,c59f8016,56cfbb0e,3e2fda0b,50aa7671,5810a8d2,2d4778d8,66bd2515,acf87b79,7b2f4875,dee19719) +,S(6fc34efd,5d11ae35,2cca3254,c5f8a040,52b81357,556d4d67,dd02d22b,91f4e49b,f14c656,ec946492,a6af3f2f,56fd7355,71e41b2c,dfeda7bd,ed567658,202f6e61) +,S(ab504458,4b38c846,e282038,1f02f55d,fc6a5648,1b1830c1,e4ee94e3,d11af8d9,4ad3821e,3f5219c,aab31787,2a8fbccf,f0f445d7,da30f05,d9523f55,13eee3cc) +,S(2378d11,716b6d34,85bd5a57,5c5b2c96,1b817abe,e21b7d45,38244933,5ce7e7a5,33682ec0,8c59a158,c4ef12bd,d2a46d31,6abc6dd4,f81a1fef,5be40577,4e03fab) +,S(cfa95425,8608d9b,9c568a1c,fd4b078a,ff49150f,a4681324,ac56b6e9,df569016,e200a3ae,2d82ddc2,a71767e5,842ef30c,86cd9b17,7c5e52ff,ac316e50,1e7e2) +,S(585542d9,a3a582a3,bde74fef,112924c4,e00cafcb,61518d87,f524211d,bdb98993,2035bc19,7a0ea2b6,8d1d1333,b5aadc61,c9dff2c1,e4dea034,1539ff15,9a3d18ae) +,S(fab2433,905e5b46,e47103f2,e353d503,cb141e61,2167cb4d,34946a5c,cd2c06b,7097d735,3f17734f,8eff6993,77916c9,884f67db,42f7a96c,62a3e1d9,9e341547) +,S(b10db548,be55521c,de5edc26,fa39716,154e365d,a1b8b7fd,2265d78b,7edee8cd,389efe1c,7fd8b4a5,4a42e651,b5c06a2a,7c153664,e52ef30d,90eda2d5,9e9690c8) +,S(218a8a36,273fce14,85c0c9f7,1910aff8,64910b00,6254af75,e78a6b5b,3d5c7bad,4a1984e8,e90d4695,b8dcf34a,55eaf568,b0fd34cc,528a147c,bebb052a,8e6e8604) +,S(e120bc22,fe6dc81f,dc3ead1b,a2ca966f,c5702ec,479793b1,5f0ebae3,b6c5ff3,9f92f1d5,e8aa56f6,1ef20685,c8085782,be180658,c7d2b9e1,c020c98e,cd425835) +,S(e83373fa,f80d4560,5ac4da9a,c9cfa220,b2a2c656,26857035,a228c93b,495be15f,8b915652,3c532657,7945021,d6c1b1a6,3b1fd090,ea93cf01,90fdb791,a2397a91) +,S(b7d8a393,a10590ea,91d2a495,eec07262,f2f43e29,74f7b2e5,6ba6ee92,17e3e74b,4ad6671f,58b2c7ba,7a940613,5986b3f3,5a6e13ec,8243b0fa,c8bec130,2afbad0f) +,S(75a5ed46,b2103f5f,ee808803,bf419bbc,232cf5d3,84955e8b,1d4fbaee,5194ca35,51b9670c,4c65e969,a5a56e15,25f33dc9,458c317b,6faf484a,186d52d1,757e4857) +,S(6d8d67cb,c309ecc6,3c1e04d4,aa42683c,775d5f32,51111500,9166c574,b0dd66e4,e127b8c,f431cf09,5939712e,c96d299e,efbdeeec,eeca3d2a,9f6b3d29,fb8f72fd) +,S(51a6d684,463065c8,7d3e0fee,ac72e4f3,1e5187a4,dd14d59e,ef71ee93,85fb229,7fe1069c,b384178c,ae2241fa,6886e1fd,286347f0,d2488dbb,f4d6eaf9,e722a90a) +,S(5140ba9e,81a272eb,30ac5c96,a8b054bf,870b1785,9519cdbe,4f2e6573,2a56e6bc,3b6a2c0e,7421eab3,147b61e6,d8252326,1819bd94,9e3c805f,ca2a12b2,e13599a9) +,S(b94c7812,6c60a3b0,48b28f47,f9d461e,27ffdf7f,93a3ee70,ae38962c,8060166b,bab7aa94,385d224f,f20e7c60,7f7f11db,4ec3526a,c226cc96,16af6a3e,356208f2) +,S(45046678,76689fbc,a94ebd79,ddb5d655,3e97b788,c91cee0,b62ee75c,1fd12ff3,635b3d75,a0621530,d7ff26cf,f1878d52,2864a6ea,e82b220f,d35ae5a5,edea1895) +,S(45f4025d,7b88ddaf,e39566e4,27060b7c,ac59ae7a,526ac3d6,a489424b,d677a54d,d732c322,18307ace,354ade14,21d13438,ac4c7c3,5b5021a6,cea9137f,b47465ac) +,S(c6e8912e,a197f39b,817b743d,deb3320b,558af332,96e0ebb,58c258c4,f1c0d5cc,6e0c8ecc,fd97ccd,deb08f4a,73ca13cf,b48d3633,afb74139,36550e0a,c23f04ea) +,S(6fd13fd,c7d3809d,6a3bf6b1,5208d0ab,5f476e99,57a7fc71,29824154,a05a7dd7,95922641,32be31b4,c34ea614,df6b8c1a,c386dbc2,1318868d,b40869a7,17b862e6) +,S(54fc0732,968b0207,ea2c115f,d11bfb57,b9b28164,4644d82f,45af1100,6b63d0b3,318ef9f3,b2173c45,bba5ffdd,8345a08b,66c8e183,80ef9dbb,b5d80c1f,15f95bfb) +,S(9e6ac718,6e09f698,1f384cdc,b9c48703,a8ee3726,d6d8ee3,a10499f5,e17731e1,95b4c37f,ec98faca,b41c628e,12f606e,79829b17,96ef3dce,c4aba99e,3882bc0a) +,S(85732ae2,eb7944a2,6609aea5,607604c4,c30f25ca,c365fb2,e01c7600,40542ce6,928a62fb,b082f38b,52890540,7b20f9ac,1f4841a7,bde217ab,828780ee,94749fcb) +,S(3ea5ace,80e47aa1,9bf1406d,3559fd50,85d38504,93752563,de66393e,37a652a1,db5fa543,142d36f,fcc1cc8,36b1f4c4,e82d4980,f2b277c7,bec53324,fbdc8e9c) +,S(7d40f7ae,f1866d87,8e42f9c8,d5afff76,2a427567,f6130f73,439d67fe,d14be54d,5bee61f5,31e4ebb5,679c9645,d565cf,f93b391b,f48c5504,a5054e23,47859d2a) +,S(3dc80cd7,478ea38e,1d6e1e41,aca892c4,4e4d8339,acd72fb4,c27861ae,3e7d8664,98412c68,68af56ab,19876499,fa30c8b7,8bfa5d19,b4aea0ec,52787690,49b7e3b5) +,S(2dd92155,81bbbcdb,a1900b90,9018ea30,2e40ec35,cf2b74ca,6065e8d1,f3bcc057,cdb59ee3,b5d42deb,5a4ffe56,46f5dec0,218d0e9d,569cdd3f,b96610ab,2a382fe5) +,S(a245a185,ed85c547,3b78a561,76a32e45,b35efe75,36a1fef4,569f4f70,ba510ae5,93b66fc4,6fde9554,1363bdbd,117073cd,f3f5e406,75fc5710,34bef6bc,47a2519c) +,S(5136c2e4,5004c1fd,615fe81a,e4463153,2753c670,86d1bba0,b3a35bdc,47bbec08,1743f5c5,d0a58608,a66fab55,69f7134d,7fe49fad,2dbee1a6,d01c581d,18f97d85) +,S(b65423af,618b242b,71e258e8,c22f975b,621a8900,9e0a3f12,f9f8314d,7fc6ca54,e3c39b1c,e4159306,e730c2ad,4ecec430,720355a2,815b63a9,720ef623,b91e4230) +,S(d6db49c6,4e68f6b0,59cb5a00,3c826a59,bea1e9fe,7622a2e,6eca605e,fe9a7858,cff0a39d,83e246f1,efad5dad,72c5df0d,62e9cf8f,4da81a5a,68586187,3dfd758f) +,S(ff2f739,8e5aaae1,a589a82f,e8e36315,34ff1081,cb083933,d08473b4,bd16f03,1559e2e8,49dc5aeb,50f3de13,1478fa99,e110627,aa0c4c5d,43ab03ca,dde04cdf) +,S(a7c9398c,5938a3ca,e32d2947,d8e3a58,e42a669f,5cd9b219,d8acf6f5,2cef9bf5,43e2a5a3,dae4bd5e,64a30861,7056fce6,cf86d0b7,41c3b46e,3a3ed90e,98d2d51c) +,S(faa9724a,357b6806,7be30aa6,4fb85879,1969191e,346d5d73,8a85b27c,c6608d72,ea1f8a66,8f4881fc,4ecfc556,f0ca4e12,b93ee6ca,54a0fce,b2fe51ca,174d9713) +,S(28301cf8,328171c0,74cd585f,6e5870ac,815de8d0,9c9f15c5,5540de9a,b29a86df,31910e6f,15585710,74e87f41,e5cc9c73,4ddd15bd,4436ec8f,59806afe,7901c2e4) +,S(fbde2380,ae0cccc4,e044ca59,92be8e11,5fc782eb,c1d49bc2,cbdfd1f5,d7908a09,c1a1d67c,74777fbb,68919bf4,11de555a,6485436f,7e34062b,480b7516,8a03dba3) +,S(59d8ba7b,6c71ba1d,191d4cce,662483cb,9784ede7,d1908e81,815d0a48,4b84bf7d,8a32e968,1ecf963b,3c23a9d2,f382490b,1f229b27,a663f4a6,9819c33b,f9f6149f) +,S(6c3a61d7,1c999ae0,604511ad,23f620ad,dfc7891b,925eeed1,6a5ca37f,b41b47e4,f7115905,c696c2b3,e2b82a30,9728923e,b8eba53c,363f1456,73676b59,9b50b9c0) +,S(8e53027f,8e137bfa,73eb5167,35382ba,ab3468f4,d4227b19,a45c51c2,ef3d8339,2b5ea7b9,542a83ab,a1c402ba,be13437b,c621067,96e83b7a,2cdedc52,2bcff513) +,S(113aa35e,6a5f794b,a56b04a3,d639b1e1,64a790b5,8ff310c,fbeab588,f93be16a,227c17e7,d95583e7,fdcc3ab7,b24182b5,1bb11e91,9f28fd7b,3a2e4a40,4f333962) +,S(16c4c83f,5a06b2de,9d3f39e7,1f0a9de7,af6e8fc7,b0fecaf3,2c82f1aa,fe9a5343,b4cbf71e,c3ad4635,87f8e355,cffe1ea,a19f1dc6,d233d617,776a69a9,ab8dec03) +,S(4d97594c,613de84a,e685199a,ac639a56,e5c15a0e,c00282bd,197cc2ea,90f8fbb0,b9f39a44,24cbb1e2,f77afa90,ec7266ee,64ea987e,80a32b34,483c1f2e,b0c5844a) +,S(b679693a,b3fecff0,819e0598,65406521,1f9aee9c,1ea44417,eba86ebe,32414ac3,7bfe1ba0,ae17291d,71aac3f3,66e5a927,56b53312,a6818d1a,78b7d9ef,a5d01b2f) +,S(a97c2730,a78cf5b7,538b518a,87d8fc55,f95a367d,4e021d23,79f163eb,98b6eb9a,aed1e51c,3ce7e35e,ff69e7d9,3fd3a968,59f0f23a,7bbab9d8,3b60cabd,cebd34f) +,S(7dd4e84f,6547d66b,5e0b204c,ed1d0258,4fe92ed8,6b504ae4,eb1b3d66,d43b8ca4,7956148f,de975510,5e3b5126,f82e77b,89a77b68,ffc9364c,bfb596e8,187ea99b) +,S(5e856d1d,25acc306,e8c1a2b7,a9ccea1,beb3008d,c224b38f,e2f31376,65d07c3f,7dccf6b1,55c12be2,f3da02c9,12fdb666,816558b1,11a2a545,9d88aa28,9d855e6c) +,S(c85ee868,7f507429,e5c26af6,7ef1fe45,e782661c,1fa03aa3,ee9dd9c9,302e5dd6,732de6ad,d071a0b0,b77e47bc,14e176d4,c85b39d0,ac5b4ea,55f0d367,dba5ab5d) +,S(a97ba3a5,cc2d5148,3f65c65b,483b3e4f,3c68e46b,87bcfea1,42aeed8,4c42e42b,f4eb1271,3024d1,b7612c3b,7dc3dff8,ca336f23,5db7daf9,3ca6f7d8,1bdb4a21) +,S(3c0396cf,6ff0150c,5b6bd528,4a05d0a5,3b735c85,125bd49c,f62db5b6,4eaf54a7,6ec02c02,f8d9a61e,6bb38d64,daaf3c7d,5324462e,37e2df8d,4ad12bfa,37fd2cb2) +,S(e36fcebc,e406d2a4,ad42f7dd,cc00e9f3,cf385eeb,58cee004,5aab8174,82d84f94,7c98182f,6edd358e,76d66de0,b45ae9f6,5eb75092,1a25194c,1911bd9f,7e6a1a6b) +,S(171ea2ec,b9641746,7d7edcf,ecd6d85,8577322e,6ebac130,5ab57f33,62eb4e37,9f219970,753a7b9c,e4f0c6ce,5745596a,aca8df7b,a73660c9,10add5a9,d4c533d6) +,S(a81d720a,bf8047e8,ef67bf2,71a13f47,636a5f9e,ec425649,1cbdad65,39652f9e,92b37c88,275c022b,635df6b,9246edf5,5dbd8284,eaa4cd7e,3d3ce6d1,c0ca3794) +,S(fa3b6973,4bd9939c,4b6ecd3b,f0a06327,2dc11345,1bddd717,f17b745f,bc3f99b3,f38a4e1a,bcb35097,7acc8f2e,d7f73f75,d406e7f2,22fdeea,2c12d8b9,e5d2dfa3) +,S(c117681e,b55bff67,feda80a1,ae88b4be,c806860d,91916619,288a7ce0,b31aef86,d94ae124,dca678bc,b69c9421,f295405f,d6dc1fac,de96a2b4,58ba5fd2,72faa032) +,S(5ccc0619,92744a57,683de5e3,7b956fa1,fd7287d,b4516fc9,f8635be3,a0db42a9,af1f73ea,4d2168e1,7550ffc,dcbba288,8397931b,e457ce6f,3f8082f8,cfc5f03) +,S(858b019c,8a93524f,6c86738d,cb10b534,d8caaf86,5c0ce75c,fc9b83b0,7c661a0a,7c59d30,1ffc8ce1,b0767ed7,91f84bc5,60bb8ca,ed3464ba,698a53c,160ec570) +,S(e1e217b8,69da0c77,599dcc38,40fa1d8c,a8d08b1a,4ac9a882,da1476cc,cc76fa56,83f0ef77,905f0801,4bd86e17,63b8c2cf,ab2018a8,9586620a,b49a15,9fc314ca) +,S(15a1ae40,b4fc51dc,554b75d4,db0c2bfd,62dfbbfc,dede18e1,4edbb689,91525cff,4f0453b7,e4e0e99d,9663e5c6,bb018007,b52c8e14,d78a28d,c4a888e4,8c4326c2) +,S(1b9a142f,fc4d03ea,4b079f2d,b05fad98,8ddb2d32,b359967f,c173801f,63320825,59bda7ed,5b691c20,4fc8f8ac,f53be298,ae628954,a8134d0f,dd097e67,be9ff9b6) +#endif +}; +#undef S diff --git a/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.h b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.h new file mode 100644 index 000000000..17df10296 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult.h @@ -0,0 +1,38 @@ +/***************************************************************************************************** + * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************************************/ + +#ifndef SECP256K1_PRECOMPUTED_ECMULT_H +#define SECP256K1_PRECOMPUTED_ECMULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ecmult.h" +#include "group.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 7 +# define WINDOW_G 3 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define WINDOW_G 4 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define WINDOW_G 8 +# else +# error No known generator for the specified exhaustive test group order. +# endif +static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +#else /* !defined(EXHAUSTIVE_TEST_ORDER) */ +# define WINDOW_G ECMULT_WINDOW_SIZE +extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PRECOMPUTED_ECMULT_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.c b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.c new file mode 100644 index 000000000..248fb077e --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.c @@ -0,0 +1,1779 @@ +/* This file was automatically generated by precompute_ecmult_gen. */ +/* See ecmult_gen_impl.h for details about the contents of this file. */ +#include "group.h" +#include "ecmult_gen.h" +#include "precomputed_ecmult_gen.h" +#ifdef EXHAUSTIVE_TEST_ORDER +# error Cannot compile precomputed_ecmult_gen.c in exhaustive test mode +#endif /* EXHAUSTIVE_TEST_ORDER */ +#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u) +const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = { +#if 0 +#elif (COMB_BLOCKS == 2) && (COMB_TEETH == 5) && (COMB_SPACING == 26) +{S(7081b567,8cb87d01,99c9c76e,d1e0a5e0,1d784be9,27f6b135,161e0fd0,3f39b473,ad5222ac,f062cb39,21b234a7,15b626ae,f780b307,9b5122d1,53210f42,d9369242), +S(228af17e,df90d1cc,a40173e9,478fa445,9780dacd,c3f15b90,fda5d00e,1faa1b51,8ff47c4d,a4ba636a,f656da9,12a81f79,6252496d,1e519886,b2c2b073,25be2b4a), +S(b515ebe0,f48fb34e,9e01824c,d90553af,db116579,96667847,5ebaa700,242fd722,4cf08191,510fbf0,51f9e19a,198f11f6,ea31268c,2a6d384c,60557250,f0553c50), +S(c37581f1,35446ff3,e80cde04,ec987f08,5af3af9f,71d87494,99b03ba,dcb8f78c,9e46324a,8d8754fe,fbda7c34,2446cf72,b7472708,25cfb92f,a22a4e73,4f1e9bc7), +S(768392e3,b2ccbbc,21792f2d,6f43c63d,efcc249,bcd549cb,96abd8ef,4ae59e90,5d061a40,ac3f93d1,82f0f7a9,914fff5d,90bbacb9,1965882c,591e89bf,c49da994), +S(a9db5de9,2d96c715,8ce5ee00,3d186cf1,976f6a76,f1be0714,726594fb,6c1ba564,743df2a8,ee73fb4a,47b3d0f,2f2b8cab,5af5227,f232946a,82676e4e,8bb70c8b), +S(58921d8d,3712f640,657e762a,737ccd0a,cece1459,a2ba8323,20b43903,d4953f93,78c26959,7e422c02,c01fcbef,484a9d44,9f635c82,849bc2a3,2a9bf6ef,3e6f1e7e), +S(bae41760,ade541bb,60028015,f6906b78,aa41515a,d995dc40,afa091da,77ae8b9a,716ff74d,ad6dc24c,77ebe31f,abe19792,41d18b0f,43ff7598,c6ea04c6,6899219f), +S(e836ff6c,6f9e02e2,4e6f6bcc,2f2460b4,9de88730,6d69241f,b22fa574,7e100f80,77c41df1,4d87b6d3,de74deca,ad426635,f85daca0,ab966a4,5a26a972,32105c5), +S(c7f17d19,fbbf28e2,543fceb2,4268ff6f,1b85e189,79b09991,7457fca0,9ba1b5a4,23a6d4aa,83ee15bf,f1655575,3e4162c5,8acedadb,4c4abfc2,54b7018,f477514b), +S(79c337ad,8835046e,572eea35,df76276b,84e99172,7bbc68a6,8c0b743,28619a,af6cf2b3,9c6b51c9,f1f92e42,6598dcbe,39da6196,2abae0da,d5fc8d0a,aa16a875), +S(1e77739b,12d20887,2bfe200b,d202972a,544804f5,2b0969c5,c22fbe1c,b8b23837,880c7490,c0455322,a0f1e67d,34b3fd1e,33c1e7da,83b9b047,5aef7bc1,332ccee5), +S(b1d314c1,74d493f6,c36a893a,830d90b,f1e86d0c,6deceee0,edb77ff4,31e9607f,8a4ba010,ec3e47cb,29d8f056,e056eb73,3b6b35f6,4c742d06,9ab832f4,68bcd3be), +S(2498aea6,471f748a,f14e50e6,bc17e0a3,ee09514d,fccbd174,f8a21d02,dd0fae48,55a3949f,2e4188e2,b3d344ce,6f0276b5,99b121bc,358e8fe6,bc4f03f5,a8219d08), +S(42d0778e,27e87710,dd19285e,d531af1e,7064386d,11b1b3c9,fb788bf2,b0c112dc,37888909,d943825a,9610e37a,362549f,547b7c7d,ae64a27e,c34290f0,b4fc5fcc), +S(af09a9f8,3a21b2fd,69ce14c5,495c680e,df18e426,c1ca5a1c,af56246f,d6ea5bbd,8eae43ca,8e591017,62c4cb02,9e5cacd2,58f0fdb1,ddbef7e2,c5765208,107c96af)}, +{S(4a7f72ed,ebd8df1f,13db15be,3ab296a8,d67edee4,37965f03,eb501205,3518ddea,1f8c4dc1,2d0e59e7,7d30a326,fd4ecbf8,aacd5fb6,7dc7169,898a9708,ac46b972), +S(c4d4f8d4,949d1ff6,559925db,f4d34972,af16062b,d59493b8,b1e0d546,c2870874,cd7f93e6,c0ee3fdc,4267625a,a6620540,4f6d80c3,d0f7210a,ce6b52e,c350706e), +S(773627f7,dcc56184,7eabafa3,42fffade,325b8ee2,a96f2f77,cbe675a6,2942277d,fb0ad731,9bff4c9c,270d93d1,89a4c380,218ec9df,1f564228,641ab35c,46526bd6), +S(ff443101,befd0bd9,e1914864,3eceea06,b9cf711b,1405e3d5,3883a29f,906063ed,aa1b7d9f,59cbddf7,bc1ad03c,44c4295e,efb406ca,7960c683,eca508d1,b2a9a2dd), +S(cbfb6813,a6874b65,9234e866,c2875f70,e45f9f76,3d634752,3f86040c,880a2e56,ed85d1a,6620c1a4,85ba3038,d2ee6590,4e27206b,eaa531ec,1eb5b886,8232cbca), +S(4e85c77b,27788563,aaeba139,975f7125,f3c933b4,8d67ba6a,2e964243,bdd7bb51,200a9d9b,3400c87b,1fb98422,3200aeb8,e6a5af1d,58c061f0,d059c0b8,d431c08a), +S(d58178ed,f0ce32e3,39a524f7,ad389f7d,8817f41f,ed782612,45218816,2a67d4f0,4840df81,5dab9596,93f9284c,54bdee72,f4861d39,3944c648,ecd76ec5,6dd3225e), +S(670f8f7,9b66496d,13692558,d56d4cd7,a1eeb0d6,9e5133ab,4f0a064b,7152fce4,1a72206,6f530586,927c2e39,370d11f3,e251bd9e,eee10303,406b7592,716333d6), +S(10b41abd,ed4de2fe,b7a40050,e61e5982,89a8cf3,6eaa608c,f2a82c63,5788f1d0,532d168d,680e9c74,4d5111da,6aab902a,9a0f5283,7836b9d9,585dbc8b,1a407de4), +S(76abd21b,103aea9a,f04b4040,297894ce,a501474d,9d38d30,8ed02cc7,137bc7c9,b5a432ad,9e92935f,7040897e,3b04152f,693c5f2,cc1e1d53,2c33f70d,185318e1), +S(4335e10d,5e4f02e6,f1b58a0d,ffb473ec,15f735a3,bf96c140,50bae78c,37061db2,1301143b,1f29f122,afcd0230,d46b6b38,b154e589,92b7eeb4,16088968,a7d57485), +S(2b3966f0,7e37e771,ac4c68ad,b8eef3c0,977cb895,2f47676b,e658aa86,76057f67,5382a6c5,bcdd1a01,6d79d817,80faf650,c0a486bc,ea8fb592,1cd3492c,42c91c3e), +S(f7738800,b7fdf237,dc7f03fc,43724011,8b53aea4,4d7953d4,276f3b4d,bf5c0ff8,c1de7924,ef8dfeed,c4fb409,f1a15d4c,5e8ab42c,90ea9c92,867b5b5c,f2921605), +S(5cb07874,ac4ffb86,2da619be,4c8fa38b,e8b261ec,3ec73a12,cd4cf8fc,4f8d5dae,549d1896,4931dabf,ba4553a2,461f2660,87733454,ea8eec6b,f671e3de,60c70340), +S(5cc85d41,7b2ae9ac,dedb1b44,ce78d8a7,8f56b878,1a4b3af6,635a55c1,fead3be7,66a48c79,301e57d4,54cc8644,d2e778a8,45d85762,2c10eb98,d77eb873,e58bbeca), +S(f27211c9,a067b01c,7fe7fbf7,7b5d9b0,eb0f2475,9d541457,6eb24ba4,19fd3db8,e26d28eb,89f7b518,e9ae0b88,fadbfb9b,641d3a44,c59c6f93,ec28a541,486e041e)} +#elif (COMB_BLOCKS == 11) && (COMB_TEETH == 6) && (COMB_SPACING == 4) +{S(629bee58,a391595f,eb20c534,4933937a,cdb2eba1,86d49f8b,845c1b5f,4ca87182,8dae4162,73c6c068,2e2aede4,76efa86b,7612c07e,f72070d0,dc4486f1,47e95085), +S(6fd5e13c,a94b874b,28cd574b,726efdbf,143ab108,1089b846,7b5b2ebe,6c6a3c8f,4a4db306,52c9772a,868b2859,57c5a005,d83f6afa,6e65d87c,700da998,ce651396), +S(609b6576,191514f4,83f5b428,500cfbaf,96871b8b,3348fe5c,1a131768,bb266b6f,90abb9c1,1bf184d2,8dbc424a,bbf74eb8,de4e0582,2ea5dd93,7d1e8b30,e5f695e7), +S(b5ec0263,27cfd922,23a46abf,a755e6fc,547806ea,333666cf,a43865a3,f4ae647,143353c,cc733d02,617f7764,7dc29c65,67a2e245,aed27120,e5fc11b3,95ffb9c9), +S(ac1fff6,cd869ed5,ca920544,1ceb990c,ce304998,10e27587,6536dcd8,1d4cd15,67a7a012,3e5ea292,85dedf0a,9f138b80,58a1d23c,2a233c5d,783bec39,b6482126), +S(c1807552,644130a3,f9b8aea0,29fdccdd,59e03e27,ff2cb1f9,9d13cf0d,42da7b13,85e99587,f77a25b0,bc64b882,bd279fa3,5be0262e,c2f5253c,70a43261,bd1fe361), +S(42919187,2b3c6877,c3b91266,79266e49,9fa37a8d,74d094a8,8c4a3638,89c2717c,1e4bd2df,a9757d42,285cca1d,856b49b0,ad481ad,828d826e,8921f744,7e04d6ad), +S(d4b10124,283afe03,4b278e5a,91daf61b,be608417,fc845e1f,9b9f52a5,43659f2,fd070859,75e2bad6,b34e0396,47b81a87,cab9fb,fdba802f,6ae3cc8b,67cc98cb), +S(ec4c2c4c,722a54ae,edc37acd,cb6ac490,3077bdf6,3f2c145c,7eb25e74,87c046aa,327bfe37,d745283b,a385dfd0,8e30b61e,2b4e5499,4432be41,fd3f0d31,c00e9ed7), +S(559e40a7,e151eeeb,46442b86,aaf4922c,12030adf,7279bb2,2bca24c6,67566a05,5483756f,60d26b97,82033592,cec21681,c5b5496a,c47f600,2013e5e5,f2ea82df), +S(c1d2e92,19c0138a,9f0a34fd,acc92f4,eafe13cf,1c004b6a,3175133d,6cc7bf12,8fa653f2,a20c1262,be59c7db,20f12579,b2adb1ff,54d84ebc,e5ad4116,3d2ebc23), +S(1becc6c0,e4861825,576624e4,fa622c01,139d9cb0,50c12062,9b87ae6b,9622245,d8516472,656ea10f,5b23839d,43f64e,85fc727b,faafcb6c,fc9c6e89,bf9c038d), +S(c483c2b3,8ceefd35,a9fa9e7a,da242c,d618cd6c,8b3bcb62,e39d68e,c1effab2,71964aca,9101863a,d7c865f2,41e814ef,3c20face,f46246b6,4a742026,471b2495), +S(3487162e,40c7efa6,92bc827f,9af9121e,af5ac549,b4ab6585,6353d699,a94a3783,f5b29042,28833bd6,e3ce0deb,dc0396ca,42701752,f930f437,d042cab2,8f135c1a), +S(eb3b21fa,f733f15a,b94ee0e4,3378e9b6,47571aff,d69292ad,a1b107c8,ad511d5f,cd95b4ad,b8768858,cb750cbb,4fa64523,6b6fde59,ceb71dd4,73a7fe48,9e5a2304), +S(21c8dd7c,34d3f333,758d1d1b,72748fe0,8695af46,3d0bd9ad,e4a6498d,1d01e9df,634d8671,7b885f36,a54b6691,35c3c026,667f3cb6,f2577701,beb0d3bb,84f07940), +S(608e33b8,14998177,5d78e286,d5c6436f,99623417,4e887da0,a95274a0,d120b57d,5d094ca1,181f8dca,87d1e043,f798bfaa,f1004edf,a470fce0,7ff8b124,328397a5), +S(f77710b4,dbc5f7fb,ac6b015e,956ed26a,6bbfb540,6a931a30,d4215aed,de610c7,7508a762,a7333ca8,ac244d6,47e47647,c62c82d,387d8df6,175fb563,1de83d54), +S(f37040aa,b0347fe,976d5980,cbd83db5,4d8cb90e,7f2d2118,85159911,af769d61,df228dd7,67fa0d5c,d44c3f6d,b09e662b,99faa5c6,688b088d,949ddab1,6f11e42), +S(7bf929f3,25374a1b,a0cbaa50,db47fea2,a5d1e3f9,3c34bddc,ea5c2250,d8252071,8fe2d2bf,b23a6755,50f16760,a6511ae8,4e4d316c,45d7cd62,4411ad3f,c72805c), +S(261bc0f3,a69d636a,b82248,6132bf91,2ab7ca95,e9a4925,b3f68bb4,745ee63a,68f52f7,df1ec349,77856c74,7b280907,cb3d456f,988ff7a7,225c4ace,8457a804), +S(60ef138d,e7086d09,711defff,68dad211,88d7f878,d616efb6,dbd3d498,5b730243,ca7c3297,3c56b178,b0cfb8a,da98748a,c3d06cc0,7fe050d7,3a6a9695,52500f8e), +S(8bfef3d6,4be90cac,8b83bf20,906b4277,75a6d982,23d5141f,b74e3851,50bc5eec,ea8b6b4c,c7c8d9ba,809ca811,3621c72c,b82006d7,81ff5f25,32010fc9,57858324), +S(9ca85f3d,4ba47ab0,e9fc0a28,74cd10a4,a8ba9aeb,ff319405,6140fea9,6e395ff3,41182ce8,96554f45,93768fc3,a656981e,69719f05,5469f9e4,ba79de22,bcfe8a8e), +S(38cd0c79,437b1299,9567999a,f54d4f8e,82a6354c,8a93a5ef,56ca2ff5,8a1ce180,c96f5ed,d78de5,9f560716,82b60b13,f06de5f9,49206258,80544bfc,73dfa76a), +S(be37e05b,9369b159,6b390290,3eb8fa0f,f221f599,1270c5f0,47edf62e,a1d0e6e2,4fc860a7,1fa69a27,fbefd8c0,906fc68f,4713fa2a,b37aaa2a,7edd3c8c,d100963c), +S(aa640e99,b091512f,85faed73,a3ac8ede,ee120513,b661f812,9a046a74,d624aaaf,dfb48ad1,a01fd508,e5652406,b681cc9e,13d0d600,68411dae,72d68061,6f6b94ff), +S(d08bb931,f008a1a7,38a16200,9fbf1ab3,d3d455dd,47f45cd6,617e81,8b8e0245,18d92218,21c9a2ed,bcaa5d26,2b7aba18,1f7f1e,7f2007a9,ec6f7d18,f038d723), +S(4e6ed1f6,c39c894f,eaa53e1c,e115fda,75fecf8a,55794628,d9a2202a,9dd5c719,1bb97d73,2e0e137c,e9c94d4c,763f9a6d,e1496548,904460d,df1c3a2f,73b66c1e), +S(867e83ae,610a24bf,401119d,8e1af6dd,414a7161,52b2ffdc,50f71f77,2fa8409c,d5d21ad5,ef365994,b3ad0533,92df82a5,6f677cb3,8500781b,a769dd50,1f6d235), +S(6031361c,6dffc505,dc7e1887,bc75c1d9,5a9db023,8b7240e4,c254f855,b35686fa,b9a9a979,c6b8c576,11eeb783,8b4ac2ae,66506bb0,a203fdf6,3efa9b59,98c7643d), +S(8502d0f,34684503,68784822,f4510c5c,562ad30f,be29a792,f0667e83,b6f95773,cd0e6511,763674b5,57fac9f1,bb62f9e2,3163a0a4,cf08cd52,a6d10064,d8b02ade)}, +{S(840e41bf,13203a96,f41ea041,1ec034fd,db0dac3d,53b6bbc9,4f8a3a78,d0371235,71b51550,a79af319,56c9b3de,fcb167d0,c3e318eb,a852eedc,78490dc5,fdaaca85), +S(5678a034,a24a1607,d78036b2,23eaa3c3,845c9f9e,7293f656,7390354,2f714d5f,57f624be,ff5d1774,c6962dd4,d14cc565,acae170c,7aaf8c6d,b0552daf,e3bdf48c), +S(722012a5,57ed9c9f,9d737a87,39954469,ca12ab29,9dedbaca,507c1259,7a27c6f1,6c28881e,a0e62453,80d73a7f,499f05a4,d9a9c04f,c2ba11e6,9fdd0b6,7c5d5ee4), +S(70c638d9,3eeab892,8bccf1e4,82368eac,a03ca8f1,b30f7b2d,34258539,8c95c014,f8635082,3dc2a200,67dfb293,891929cf,18a810f2,5c85c169,159a4b44,b190a029), +S(2ce4a530,b5f6c77d,c0c4d891,6e89b24b,c25c04c2,723842d4,29300f82,5e260458,6f306154,4d1195ea,98b972e,91a962e2,95a2a4eb,9be03949,a789b01c,f61dd705), +S(89e71182,851bb441,c0af4e31,cad89dc7,3947369b,fef12eb6,b1dfa71a,72498c51,20b7ffd5,878718c2,2b5bfdc,ac422794,63aac0da,4bcdec2a,8f3b538e,3a9f574d), +S(f01f06b8,da0ba34c,e1045e83,adb95fbe,b76f134b,35235539,6b07f8de,9dd25869,afa0fb5b,45ad1f24,73460f17,5ff4bfd8,f162262,65c423fd,ebd92bc1,72f3aa7b), +S(f0c217c8,1dda2201,1f46648a,e096906d,71fba006,1b4dfdb9,85dfe59c,9d8f1894,d5ddd6b7,bdf2a6f6,cba166ae,4c01c60,b012c9ee,ad954a46,6f631f9f,928b3fc), +S(bd9acff2,87cc2a2b,396aef61,b0937a49,c43a2366,a2c3c461,c1283987,a7b6f53,828de0ad,b9067b2d,8f8fefe6,ce3a5c94,e7d63ea1,7c891d2c,5f266e8c,a5fac116), +S(ee314d97,2b9c10a4,fec9f8d,ccab0015,d4923e52,d915eae8,b319911c,7a8fe379,82057aef,ff05c496,ba8b4753,c4e57832,aba9a724,adf70a9f,1b3765ef,952ab52), +S(d39fa7b,9b87ee2a,aa32454a,13470406,c8024c39,cf387143,3364de62,cb94c103,5cf1309,530f9e09,c9b38ad9,3a778ec5,533f60f6,4a42e31,1cd97c2f,c984b9cc), +S(5ab1a07e,5f6aff68,16780e5a,23c9faff,b29cd7d7,5bfb8984,4834fb6b,c6b34a14,deac47fd,6567023e,b5ec7a94,a0133bbf,158c0425,c0a6d288,23558986,314d54bd), +S(b1a4ecc6,94bb5212,98e80464,cffacd32,331ebc7c,4d545141,a129b522,a4818830,9772044f,3722ec57,d76a049b,2afce2b6,319f0bbc,b17c7f06,175a288f,3ce3534d), +S(56015e42,81aed744,a0859e29,eb913a7c,b44ebd39,2ed8c0b7,1eb42f9c,9c93c8ba,8f973650,45f7d8a9,24a276ac,20056895,fb2b0aaa,4b35468a,a51f41f,722b9d33), +S(7d99a5c5,21543229,c8f9c7b,50dbaa64,b200bf86,47c71b35,a0105dde,2b3a8e0c,eae09ef,3ffdec8b,9a30291c,244c0a72,6466c26d,fe2c8d30,174f57fd,ec6aba60), +S(ab7d21f9,1e7dac68,afd6e4e4,794551d5,55a9f42,59825109,5b25652e,946ebdae,8805a806,710ed7b0,fb99ff30,130c074c,6a0be3d2,abe6e155,f9c07496,f8b92454), +S(b31a5f85,d65e5200,8f5261cd,fd6d36f6,4b2a1f3a,6f08d7b8,defc7e84,21d0f7db,2e6d46c3,3733b3b5,597a133f,7459ee2b,570ba333,4d1e7648,1980dda,1aa8d2d3), +S(30af789e,850c8ef8,9eeb226b,27786679,442a9a0c,35cb7337,98345400,29220fc5,f6651170,c83e24e1,eb6e8da,ffa0b0bb,a6c53676,72558d44,c5b77176,3d9b5d7f), +S(8d87f808,98fb8007,ffd5093a,bc6bad2d,23e09e90,e6967031,48d5418,4c60e0ae,3d14332c,21df527f,a2e98243,d3ed4bd0,6634d799,9f62efd,e8d6c919,8ed716a3), +S(a961c219,eb9ea127,205af30d,909ef732,8cc599a,b2080966,f615796e,1126dd98,3e235ae0,37b10074,32e5cee5,56778856,1d552e3e,bf40bb82,5b527cac,8e1e5b9c), +S(b9c2de21,40cea728,2aec5293,bb77dc7b,550a72c8,84389c05,310651bc,7570f2ea,74171cd9,4a5683b7,5bc7c5d9,b4c8fc10,1fecc3b1,b7349ce,840b6ca4,877fed21), +S(cd041ff2,e8191946,8fd7ef0,c33021d2,9533cd75,64772252,c686f718,7e33166b,3f54a9af,e8597bb,faccbbd2,9280e60,93d31bc5,b366aff2,2c95e21b,fbca6041), +S(adfce0b5,8a9cef85,e690b84a,c7ccc6,8f5aa4de,ada5e265,3720412b,e1f19ae,8ae2dcdb,c6ce83be,825593d6,87f9afbe,a88af079,564c60d5,c9b88898,897515ea), +S(833a50c2,cb5507c6,60bd450e,cde341c9,64f2809a,e400215,c52dfaa0,9825df96,de85e216,493cdb4c,4541f720,201f4c67,1472b6a,d61cf8ea,3cf54ccd,a4584b77), +S(3475027a,628ea423,2d689d70,d45e975d,39d62303,282b16b,1f94a427,3d7ea746,97c3052d,9270df78,6efbd2e7,beaa58cd,f864e28,905e3ab5,507cb9aa,e3c69160), +S(cbda2707,e61d9e40,124668ef,7ed83973,dd293dfd,221396a8,d27e7aa1,392edcb3,fd5023a8,af8eff08,f0e3c8b9,b6a22a99,b3ec3aeb,7e0104dc,1f8409cc,d83d8a02), +S(963722ec,aced2105,2bf447fe,619a8532,dc78816e,2e17a111,3ffc601d,9bec0381,f31feba,259f7d0e,3c326c69,53aae60c,1e0479da,5ca839ea,77c6f1a4,9419172c), +S(fc531e1d,49d2a984,83c861b2,b299b8fd,b26831e0,3bced6da,5c4449b0,18363be7,9f9cc9b0,8d72ced1,998c6329,a17695d9,c94cfc76,ba9f6943,1c5dab83,60f2942), +S(dab255f5,b47d96d8,ec5272b,5cde4ca4,33070920,84aa4866,d53b674a,330aea2,feeda13b,a544f090,b790514a,42064cea,509bb3f3,9dbd4567,6bd75414,37579d7c), +S(ac5b161c,fcc42998,71b49d1f,8cf35bd4,dd6bf98e,5f84f2f6,420bc363,b9cac257,4511d4d3,1fa26d7f,e56f671d,7467bbd0,41358b36,b60775f8,65f7d491,3d17b685), +S(b62fbfcc,2aca0706,b0fe67f4,ed5d96b,4a65b048,f73e8f4c,9782e1ee,36189e31,6549e8c2,f77bc824,4e1a90b4,e42ca64a,5ade1768,a0996d69,8d7b047,7bfbf862), +S(56938443,5e509000,5cf3dd18,ea629078,e15097e9,da7bb5c5,737cfa0a,a40e8818,f86a1815,4f379054,11016994,9b2eba6b,477c32b8,b68091a4,4b14990a,5e8eaf92)}, +{S(7c028bd1,75367939,74871a6b,cc957d95,3813331c,87ae606c,17aecbdf,a704ebb4,4fea040b,a0ef0319,91ff9b8b,7829c0c3,93895439,d506c5c3,1a1a3fd9,e32e7e59), +S(24e966d0,bf1227ca,11eb8fd7,8dc5369d,2bb9b681,927990b6,dd02b948,fc18a169,72b7fa7c,f929a6b1,c556a372,4149a279,8d57f504,4b50a1a7,922cfddc,17308ca7), +S(a2b7db3a,265b30aa,94823577,6d5ea839,c4fe564b,97a5e3da,313f7fc4,5de617c5,5e895546,a2778162,4a91ea4e,c104c911,85f3e954,f8378fc2,bea41a3,f1cc9e15), +S(e365c695,449c9976,cb67ede3,325d9229,ee526349,e6b255f7,f4e72184,6722580b,eff99cdf,a0920505,ac37e46,b812d47b,31a29113,e491208,a19e3edb,557ac2e), +S(c3d90905,297c3a65,2c6c3d5d,915cd9c2,d741f472,4a47c8cf,35e5cf3,cac9dd11,8e9ebbd,34a7dd02,24fa6e33,193cdd72,4906dc81,a5aa41ee,4a34d3d0,4b2ee5b3), +S(6e4e23cd,ee4388d6,e8b61f8a,af7678d1,a62b3e1a,3385d278,895a02a,de4c9f00,f69b843b,ae39cf41,11fe9b99,a0287057,5695421e,e1ea690e,2e76d937,e7e32c01), +S(92eb38a6,3743088a,39b58cad,4eb4a27e,a8b08c27,444d704,6d2aa5f4,89713217,22af8d6c,d3567a6d,cf7403ef,e0afea02,48ea4266,1577005a,9afb5f2a,19611864), +S(b3c84323,e2d022fd,d2a80d07,203f4a26,f5d32dae,62842072,9663a994,3a829d08,9a899de,82329d94,83b88e1e,1bce53ed,8714cad4,c68cd491,1b71bc0a,e3839821), +S(daae5199,57a6002,8958b22e,6dbbee20,c4bbd8e1,7ed589e,b8528f35,7a4dbb40,afec8a03,321586ec,ac38e941,7fa8e342,f0542193,59decf5e,56479a39,c32f92af), +S(7afb9a56,89fd1344,cdbc5c72,62dff7b,718c2e47,a6e19ec,665af795,86ed0161,d1c2c9cb,60a191a9,a3db7e20,2ebc2eff,444bbaa8,d81ba086,6f8825f3,8c765f53), +S(8d0c4a2a,e72b54c6,236d997d,61a2a24f,ddbd39c7,ee16f1e7,d7c45b22,b4bfdac8,15a58f4f,fdad9e3f,b4d33c7e,170747cc,6a5abfdd,bfbe5814,ef0c3611,6a0a9e91), +S(24d8c0ca,53400126,347e67f3,72f19298,595b6d33,76ba2f19,2fba6dd1,7b57bda1,7c01404f,bd316814,f10734a1,559049ca,d6f20e90,d6b13ed5,f9542630,db77f9ec), +S(4c2b7a58,87a49df4,f98cfc72,22fdd832,362b8cc4,c5f4fff4,d0a20674,c9749bde,c2a1cfcd,e8636288,31a5c450,fb5cf552,c76e581f,9274e5d9,888a3a68,c37ca349), +S(2028e381,f42cc2f7,a8829308,bb72881e,94e5b54e,3331d848,898ccabc,bf971cb,16debea0,203f0709,d9b55b0d,2b8651b5,cb085d8c,8f56708d,c1fe4d33,a616dfab), +S(d11e0753,f72b7c4e,641ed50f,84dfa24d,a0baea77,98fcf062,8b2696ba,a7ec2529,55af37fe,88324646,777387e5,a9b18059,ace20e9,becd7488,5e43fee5,fa6809e2), +S(72309865,b8a1a6f3,9d6d561f,43ddf5b7,f2d022ed,95df130b,2563eaff,9008a95,f3fca0be,3ce7d9eb,e1648964,58eba87e,934d000b,a535f223,868dae11,dd5230e), +S(adca4785,cbf38a0f,28de7b36,daccc761,89b8b918,f3fafa7b,abbbd9b1,4ed5485f,880d76a6,fbcce864,657edb9b,349f124d,1b22c7af,2b0ff833,40d7a0c4,84b49de0), +S(bb43e0c0,93d58c6f,3946e58e,4727d7e2,d223c84d,513c4e2,222406bc,aafb03c2,c00f7dc8,fcbd55b3,6a95f2f4,a3a07b7f,9599736f,af099a69,e2fc2630,a2aef1d5), +S(179eb588,d1c7aa5a,24e51f5e,6d86e4ed,2e6f0f98,bf956b71,ec1caca1,b7f775cf,42f461c8,a784f643,d5a8682a,6ec9b470,455f0ab9,f269140,b1ad2376,95f64afd), +S(9144fc75,b00f8608,714f027,16b30575,be19dc01,d3689e8d,2665d967,6a077d11,b168c324,7dc6c31e,8302b6df,a2e7c053,dd849538,f9d45b87,14d889ec,cc789704), +S(d6cd2a7a,b7253b86,34231eb3,2793f062,bdf103b2,4fade912,6206e745,a3b429a7,9903e507,dc5e3a61,d73fc83c,5c4ba476,6ae92655,9b208369,bee55948,4bfe444a), +S(264845ed,623bd3f3,808ca51e,517def45,1fbc237b,e47e3ded,70c3769b,391a9f83,cb5022fe,3d535f4d,192e73d8,5d9ede23,78e0824c,e560a97,d53aabdd,f8717377), +S(2df9621c,cf3e67da,54c47ddf,81e3ba7e,7b50e713,cc7d08ac,d64f47e9,85c4f334,8058f6e8,139d8e87,cce4a389,c470e3d8,45da3537,ccead4f3,abbccf42,a5fcc49f), +S(ccfd6c4,c5966144,32d2efc4,1ccfa0eb,3e0b44ed,a4558128,c3e4d68d,949a5cac,bc77b87b,5f50d3a9,6b28d5cf,fb371b4a,36cc1360,15c548b3,f98d661a,beda8acf), +S(4e2e6052,cd35d585,6531fcf1,73bf124d,3c569bf6,6cc54ed6,9a520d42,cb836296,6381d100,e5d9ae50,f1821122,b8e91a5e,f365edee,556fee1c,2fdb6d17,3fd29c65), +S(6603d715,ed0f8725,7d9c3f29,cf86ad4c,aa0500ca,fa16a708,3168e265,b87d0255,9d2eda4a,6195e2c4,a4576e4d,5d02383,a3a01b2c,f94ab8fd,fef2f338,15807d31), +S(f09ef30d,fade81df,2fcafe31,387ed34,5a8029cb,e93fec3b,eaaeb8ac,8adc9803,f9f3039e,5b73c7cc,cf841eb8,1c15203f,ba192e,9eb39aeb,36f56c29,44b286bb), +S(ebf4611f,cb3a44a9,f9d5b00a,c559dbb5,394840c8,41a06496,bbd2011a,2508cc34,1e183324,9a610584,5d62ef4b,685152e5,c75c7525,c703f81,51bdd87c,6fda0d43), +S(31fc3226,c19aea7b,4845ff2a,ddeca6a9,36505a49,92102cb3,499d66f8,a6e1a3b5,49babd41,b1e8a6c,a728f971,d8d8cb76,47cdb94b,89767a67,fd975ac6,93f144d1), +S(be1e37d9,dadc4b4b,7a5ba74d,fb7eb55c,2b0a4fdd,81564f8d,51038afe,f716e3d2,de6f0c3d,b6efc974,975a7d6d,3c6e9d44,a712879e,4e95c612,164273bc,5de1f4b), +S(f8034e14,2425cdce,31e82b49,cde33ba8,3630d1ae,283b8b47,73960539,c67f1652,a302e3b1,860252a5,e7114568,748746ad,1e02c2e4,280bc913,dd4b4d2f,92a561af), +S(21e709bf,369cdb2d,b7f51b10,f0ff56c1,2c1938d6,18419d00,34e57d94,7b83d5e2,d7e09ab1,2e7d04f5,aab3a75f,8cf75876,ddc3cf0d,cb4b9526,ea7f755a,dfe1e495)}, +{S(638b6618,c1498946,75a1a943,8755a68,30d7dd3c,9d8a9f20,d65a7161,9c8b477f,e4e66035,e947c73a,c34a48b,b43a3762,d1038e6,893dee23,cf658a12,190d2a56), +S(4b6ce93a,acd4954e,cf0febd1,fc9a965e,ae7fbc1e,e24a12d3,a4b86573,62eb255d,8cea4838,1bdf4e5d,79e25ed0,1aab94b3,5f00267b,3ec7eeb6,63833507,583407b3), +S(e2a42110,3e8e2a80,a6451f71,b348434d,7d508023,beeed16a,d87417b8,5c7b7913,5fc15b62,124014e7,fa8f95cf,78ce8415,d46a1f97,d88be55a,76431786,8de3d605), +S(6949956,91582c2c,2e14576f,5ec0dd37,65133237,a4e43369,633edf69,933d1f75,5ca8c2a6,329882f5,2daf48e2,e291c48d,febbbd29,9ccc9ff,3ad54ed,33ccef43), +S(55d836af,2dd4b8a5,7f20eb57,6886790e,a3ccfcf9,2a2940b3,646f263d,685f62cd,7cc1ffe6,37781c72,d3cc26dd,9d4147c2,183c8e0a,95b87742,52ac47ac,19db266), +S(442a3090,46bbf3ef,503a138,b60ddfa0,ea4a5901,ae801003,f3f18ad9,9703a44e,129d9913,eff78c49,16e67c4c,cb658784,fa47da35,92ea1c98,4054b371,a275639b), +S(76981efa,29944c2d,9463fc94,67a92e1f,9403c287,dd595292,4860aee4,b78626ca,c87cb5c9,ce93ff3c,23189404,cabf8e09,996c4cde,e67935d5,874c705d,6a7f95ae), +S(42ad08fc,2a1eafc3,d793f04e,304831e,c1bae89,c7d00b24,7785d870,904bef5c,c3913fd3,6b8c08c2,553b9c48,5b90221e,ecdc8d02,6d558bc2,5fdd6ba3,df78ed63), +S(4d70ffbe,efc6254d,cee74a89,70244bd3,384b3af5,8510ca61,258fcbf8,f0c82575,ba3e19d,b022a75b,c75cbaea,84ff912b,867124d,a20e0d28,a007fb74,9a9d1c7b), +S(4ec8dca8,7079487c,adfd516,da2df139,5477b524,df4aa6d6,4db5e206,cfb14b9f,e88e5bad,c8654d60,fe1f8f6a,73328209,63bb10cd,31aae381,ea1b4d9c,eaf9cb27), +S(2e5a47c9,a47cbbb5,ef701784,34798a6c,48244df9,dab1e5d8,83c7f732,b89c7d79,7c8202dd,cf7fb6ec,471856d5,830d59e6,99c04377,c553d835,f64cb333,cc405c35), +S(3ca98150,bc5f116a,e7034a07,628d698f,67cbb8d3,74869ab1,534464f5,5e8ed24f,fad702ec,c6b738de,5b653f78,f51c98d2,1e4bad57,4db97730,58324d1e,12b89f9), +S(f414495d,9093ad22,11e001f8,b07b38bd,f5430a11,72899bcc,2c553b55,a9d4a225,bc130e93,998db229,6aef128a,5b8e5b9,9cf67eb7,713aa7d9,9fc4c902,af660f4b), +S(44e794c9,5a28ee80,f9b64193,9c626a78,4a851a4f,84f28887,9eaec508,1b60e508,b219e000,1b07a275,f63dfb3b,e977a40a,f505be1e,d3eb8194,b919b9ea,70d7198a), +S(35024622,bc17bec1,9c352280,297ddf7f,41654c08,61c3744b,13c74ed5,6673b98,64aece4c,3ec0b19c,cdbc06b7,4eb15704,50ff689e,6c5bafb7,6ae99396,12f4cca0), +S(45c4f36c,ac4c4738,ab216363,e12b2475,50b8ef09,7a986ce1,60b0462f,f8725a58,fb944806,dee59834,7d256885,3761e3a,9ae666b,9b0ee095,fea33ec7,bbce9a5f), +S(20a0b4f7,cfb58bd8,d09d008d,70e7f807,b4fa61ff,65f2e15,f00bddeb,55df1124,7961d1de,e98ca40f,4d09e5fc,52ae4916,cafdd6e,2bdb9f9d,2776239c,a3480157), +S(fa10af8c,eb2de4c9,3c0c2cb0,95f95911,755b19d9,90f17e33,69930d6,6002fcd3,68a3bfb4,533bb5f0,54fbf91c,b771b08e,e388a61a,9727bb7f,a3a1f67e,60b2eba7), +S(d417d7dd,30ebe9f1,7d52edd6,c82d91f9,25d5987f,a6f53b0e,d769a34f,e557c11e,ea89c810,619e32f2,369258ae,8ad8a456,cc36d87e,b45a42d3,83956039,62e437c8), +S(349b002d,ecee0e4,1788a3c0,cabb9ff7,c17848e2,78ef8905,63924c55,52d59853,47583a2e,7ff61b9,6fa168b5,1191b363,efa3e0a1,ce825a3c,5bb04e5b,e403b4b0), +S(4b8efc8d,7eeb3554,b5128e8d,ce20c29,697f79cb,29f61b4e,a2f7ac28,57910bb,e3cef657,7b5c0d2f,dee52c96,b6353073,b099fc9c,65688969,24cd744b,981c5ff0), +S(f356e8cf,5785b05e,e99a2b4,d202b64,2b1e98c2,57741e60,7241fb9f,d3f5ea2f,9079fd65,59d5a93f,91370d16,20ba487a,a8c6ad3d,e67f2c83,a1c335,fb5398a2), +S(bfb74aa2,15e5ce36,97cb6156,c2666ef7,1b579a50,56ff60ba,d3d5e10a,7eb2d31f,3def8a80,ddc3f407,e30d11fb,232f0e31,191bba1,d51a7eaf,b86d7f97,45d78dce), +S(658748bc,bbc75ba,30c969fa,371fc1d7,76c32a5c,7e632201,264deb36,b296ad2a,c173fe4b,14ead07c,2c6574c,8887500b,53f6c02e,dbd4048b,e69aab41,9267ef9f), +S(f51a5ca6,fd6dde25,447fa46f,c0984d26,66004c02,8d402624,8886d0d4,604f6ad8,fd4290e1,7b2928aa,f2e03b98,97252b82,d481c4c5,ad4edda6,16dc1cd8,e7ee83b2), +S(20ef1ab3,491b8d0d,a1565e2,8dd92dff,efcb88f,e88c6c2f,6b100b30,b58249b6,6814d32,7b5b94c4,12fb770e,2fc4077f,fa9a336c,9e7db2a4,bc7dffa4,286eee0), +S(d98785a,82dfe5de,343bea0,d91cd8c4,93344b86,7fffe1e6,efd7758a,90cdd899,37ad7f7c,5783d262,5204bac3,4405c207,972b7fb4,cccc3585,ee152f0a,48ee16c4), +S(3885e910,18a66e64,2d3f0c76,bca6dc82,a6916cb,1e46a858,7aff5ea2,d9390689,20765590,83ba89c2,14be9178,46e40553,ea195c49,de203c9,d175296e,a4430819), +S(c88cf650,3b50f5eb,7bac15fe,2097ff76,9c57b983,1b5d05c9,fbd8dc58,d4a9a746,b6443b76,64984192,e7056478,e9f372cb,21a0c7c0,cfcb0e84,850443a0,25ff42b6), +S(2831fddb,2ba2d301,2dedd58,a3f47434,3450985e,80e4e4c1,646745cb,1abc69d4,1b04e1b7,db84b6c4,882f264c,7bba91d5,2256dc97,fdd22e58,483dec32,5020a257), +S(5e492bf,c9d19dcb,c3bcb9a8,b7bec84c,23c359de,a78aa0a1,e0522232,df037abc,614fe5b7,cffedd76,35d371b5,2d89baf0,55af687d,e6c12d80,b221d0b3,9d03d0ac), +S(bbc64d06,681957e9,685c9864,c5f9bfda,34b4dd02,6b749399,a12bd8de,87f311e7,3c525096,dd6b7d11,26c6ca50,5064da63,f7f6a203,87594f4f,e4ae0403,fb4d66b6)}, +{S(2b00c7db,16887372,753ab219,17092563,8c603992,f501b07c,9d8442b3,721addf9,8e7c5f66,4c2493ec,77cc74ef,d9221235,f26bd3bd,6f505347,39f0fe19,c41b9fad), +S(56b9a3eb,d9360224,56267f52,21ade9f9,674863ee,4bacb7c9,ef0155ca,b36b336e,2e2b1a4d,f6c150c8,6dcfe9d2,e2836579,f82ac4d4,2f8fa4d5,d814b952,e92da69e), +S(ff52bbc2,83bd15ad,523e6d08,873a8896,9449a1c1,c5ec8570,ed532000,5a92aa3f,dd9c534b,e59d3845,a1943435,1a20513d,1a829424,e65ed8ad,60342b38,6578b21), +S(84f79356,86b0d45a,13a1ce22,7e7c925e,d80be5d9,9fd7e671,270c4c35,7254e9ce,3dfe2058,1e91dc25,12c16951,c667fbe6,83192bf3,3fc0bdec,c760dff6,730f82be), +S(db14da0a,86bcd275,71cb9348,36268bb,85c306c8,9ee1b78b,83c247a1,71c7355d,66ba535e,81e877b4,71b0b75a,6545970d,6e33cbe0,ff011e3f,d653d026,f4fff395), +S(28bfbd9e,44554371,74a4c24a,cc65ef45,5fd4d39e,b466e94,358cef4b,b0eeaa5,5f5ce6de,2925acc9,e503d731,d46601aa,7e668001,669819cf,fa54b3e3,dbb98f32), +S(a7b21a3f,a07b4049,7f9f5087,c763b431,d5f04cd0,e7b7e0dc,f9c6c664,df7c6ac7,daf23f35,b903ecc,af4f50cf,459deac9,85d0d008,3b5afa73,7131a61d,8591bf9c), +S(12fac42a,40935aa,e881894d,245b9691,cd1f6ad0,e0481e1f,444e0ccb,6ee88781,c519e0b9,e3c19fc8,f67c07e4,f357f43d,589ec23c,7714f7a0,4347be96,4ca572fb), +S(5c2e28bc,94f8639e,50133dba,9b6c8a35,348eefdd,2fdbc18f,2abb792,eb8807dd,c546b3c2,5f2809e2,7977a8e2,3a1c3ddf,36229f31,434c90e9,1386ee84,b64e8fdb), +S(e8e73382,fbe8b94e,58bef90b,aeb28305,d27ea48d,9c5f6e08,ef47e4dd,5fad6b78,d3529a2e,86240f06,a63ba03b,ce419c05,24d22622,fab9107d,aaf3016c,6ff7fe3e), +S(26b93629,ebe68d1e,878e94b7,5babd663,6fe1f6f8,659b155a,e10801eb,c2cc51d9,f4630056,b3e532f7,32238911,555c0ffd,f4951c9a,b2f45119,cb12e774,aaa2666), +S(57b3b642,431f793f,24862328,dbd271ae,19d343eb,c3b0ca7c,affe4fcb,319d8d94,1d7ed35a,5abc7e39,1858a9fd,b90f907e,6a065648,c00f94a7,75f06d2b,1cacef1a), +S(c2123794,d98f0311,c1327522,1767236a,6f45cb14,8fcd65d7,e0be8d13,2a650953,d5a382f,fcc2ffba,3917763d,ebe0549d,66f358b,d727c281,288551f8,4ecd193b), +S(16789662,9208b510,7528efd1,36036980,994d6c3e,5b34c69f,ef3b86a4,3db9e8f2,217105f8,39b0ae0e,932b5207,e8e7c190,3ea463c5,40c043aa,e4f8b106,97ccc84b), +S(3a0b8ffc,83a1702e,214adfc3,79bec5a9,753274ef,9e3271ca,8ec5b067,a5f3b6cf,2c3de01b,f27dd574,4496c2a4,75a07e60,71ee60ef,7eaf1c94,c257418b,744d1338), +S(482e5ac2,6477feb7,6c848d58,40173d87,1687c5b7,3b2970ec,b8dd69e9,3393f923,dfb3995a,ca5b54a3,b48e1dc,107023d4,dbd7a918,6adf2af0,61f92160,76e7f78c), +S(3869373d,638a30cb,63177204,bfb194f0,2c6ff503,3cb4ef1f,b146741a,f3b495ed,f2ac9f3a,ca159c7,c2ce9f48,e895c543,d3f19066,74f335b9,efdc4b47,4ccc23c3), +S(98c16ec8,54b34ea2,f08aa4fd,3ce1877d,4a36f2a6,4e673191,17f74e5d,86e57f4e,3448646f,c9aaab0f,4d9ec298,8f7c07ef,448888e7,6318e0ac,552d7cc,b59820a3), +S(1b3a4ebc,8ad1c200,2847e182,de7c9eba,f0f7a408,e2aa172d,484bb9d3,ab897b73,b93decef,69cf2da4,5c3a2373,ac2abd77,311fc1f9,21e7df8,5f5b3504,a5ecbdb4), +S(57b5b2d2,87bec103,e4aa7b96,16129718,64780441,fb5ef847,19f16d,a1c909fe,2c2d983c,d8c37a7d,653716e6,15756121,9e5ad5ab,25664967,67a0fbd8,e8180c71), +S(cd7e277b,ae1498a1,8e7bc00c,2c299a49,69f6862b,bf96e6d9,f5143db8,7b582115,f9548ddf,c27108bb,38f80025,6ffdc25e,28621c17,c370a40e,5009b968,d40660bc), +S(80615f12,82ed7a8f,bdd70890,77c24f18,c03fa395,3cbea7bd,32a26c7c,260102e7,8d54a3a2,83383d6c,a633d17d,e2f4f756,3bcc3826,10cc1012,3f2f192b,e654c2cb), +S(9b16f5dd,c8c8c8d,53786b49,e2d025a6,838f6322,700fe105,7de6d78e,92281a9e,a36aa3c2,f2034285,76f5c570,63bb1bd7,e6e0410,2e1cd2dd,f100a54e,431ca08f), +S(f1d04075,35ffd40f,2a0b59f9,14ecf368,67700c5,b33e15c5,153fa9b1,c724d36c,22a8b48e,4db1d3d1,28cc735f,99db74d9,ba7457cc,67b8fb39,7b38fcbb,153f7c0a), +S(c252ae6b,cb711704,659c37a6,f425b215,1ac8a4c6,63420eba,899127e8,1d8df3b7,8e9a75ab,c5a2cd8c,d44331ea,b07e5d97,a30c6619,8e382261,642c0e10,8f6d46b3), +S(59f6fadb,4a8a3389,999b93d4,cdf1f8f0,4735b397,9fa5397e,64df420b,85876ed5,c6e8baae,fdeb7019,23a68b71,9c88596f,60742a38,db04d7e5,76bd1b8d,1ae25a6b), +S(3c2e03c9,3f610ffd,db519c7,80c201ce,b58ffed8,ee10e21f,d1610e99,33fd08c7,d339d979,38e1c5de,7492e7d2,d64fe34d,ed889d48,54670345,1c51432f,ec6c829), +S(59d16070,f9147ce5,5bac599e,aaace0ef,24c02ea6,85249cc6,ccfbeecb,a4bba83f,8105bf41,47f22f7b,18c73941,3a85ef06,40bf6805,51c68a10,e16be920,193977f), +S(3aca1182,3f31b2b,a12e628b,604b1010,62c45fce,22e15dd0,8b9b5ef9,a53dc02,bdca8ab2,d2dcab6e,3a98e7f8,7e192c19,cae60952,fc6f54bb,d46acb49,60d51c0a), +S(261e9b93,3648c7d8,d5255219,fd0634eb,112e1dd3,fcce0a04,135b2784,e67b5e32,e0eb5ec4,30b1f9ef,2bd10916,b21f4fe1,4cfc80c,2bc179e0,fceb8678,ff933068), +S(75918e0c,a0f03b34,40cd6239,c108bb72,f293a881,a1f2e9a,73c604b8,8c451c39,7f02a925,80e50aa2,5b786d10,422f1d80,2c42cb37,27f09ff1,1f5e0dd9,bf6a6c1c), +S(42025e76,3c05c64c,311a275d,d6f1fb3f,2da2108a,39ed24be,3de83123,b1c1d1e9,dba2eec,7405b67c,a1915b13,45702062,7bfeebb8,6b90dbd4,87849e5a,756921c6)}, +{S(ef2c5fa8,b23285e3,50d7f05d,bd8c96bc,6e662824,5b10e1cb,4b659bc5,ded5836f,1b37679e,1177b653,8975790a,4d5d2abe,3626d636,1d863e0e,1db5881e,8e0c54a8), +S(a1d5a92c,93df3c75,a06f9c2b,a604789d,fd487513,62d957be,68c033e8,3e202fe7,64c1c00a,3964fd5,b35fb52,b423b285,77c8d269,bb1ffd16,325c5e0f,7be08bdb), +S(ef13ec66,d46813ce,68038fcd,541e5e8,bdbc970d,337d7b5b,9099d0e4,3fa4288,7ad7f4f0,c8345229,96341248,b1455ebb,89aaeb6e,1ae9db25,1b86930c,9f779fd9), +S(aea7cf4c,afc1079e,e61396b6,2df9bac3,bf334745,54af4678,8621e337,4c7486c7,c0538605,5911c893,459b98b0,4be449f1,2e9f98cf,ef4cc292,9975d42a,f460d65), +S(8f082b3b,6476b4e9,ffb317e6,1fec0cbe,8e389041,1fdc87d6,8d4d26f5,44c2e6e3,eafc2bd0,d6570a7a,cf8bb5d1,6cdc1020,456473c9,e7fec1b7,fc6217cd,89d0a2a1), +S(e0d6310d,e5e664b3,164faddf,39c93676,4ddd3f0d,f5e007ef,5293ee35,980ae0cc,de093cfa,ca1033bf,47e88723,4978758a,74b93cc5,2cef48a3,daf4dda9,adc79ccb), +S(2518110d,5d064422,5ead0e2a,5ac8b8b6,b1fb7fe1,55e351c5,1d39673d,dab0f6a7,84f0d6e4,b497043a,95b6af9d,e72cd502,a7b6a68d,ecaa01b0,9e0d8ff9,9d8a16c9), +S(6dc820b8,5db42353,c97453eb,d7d768cc,af9732d7,c261bc6f,8399caab,34cf5b93,30b168c0,2509e2f7,2035f60,8be8b89d,577b6e72,540f521,934fe980,7412459c), +S(bddc1c75,5bca9911,3c9ae05d,c14441e,2c707fe5,8a329f8d,feaa36ff,12771376,8c0087ca,b7688dcf,5a3cf1a3,3c27c7b9,cee36007,3aeb9b9f,d7088623,af20f62a), +S(b6e5ef5a,a84c6d2c,a209d50e,8fa8e1d7,93c61ed9,bfbc22d5,2ecf293c,9489ac13,f76e3adc,a89cb983,b6b670f9,5a7e774a,c015de5,1ba56417,40ac1f68,e3df377a), +S(26699dfe,93788eb8,d91cb601,cae628e5,75e8468e,73f6cefe,588755b8,c396071c,e5f9e00f,bcf6f1cc,cd39ab13,41cd06b0,ef2e789a,17d761f6,6a7a83b1,c036791f), +S(72f7e16f,77f0a4f7,92db2cd0,354382af,34282dc0,7b8cb290,a89a5d60,894e8090,54d32ecc,2cd022c6,c03f1379,657450b0,db9f08e9,6e2be5ab,5233dd84,62733cf), +S(f84ae7f8,a03b60,af9cc359,36f0ae78,96935b2c,534f852,8ad159bb,6c0b44e7,68f4dfc6,20a354d9,d6904bae,67792622,337e3180,ab340828,80bf04fd,f47cc23b), +S(5dea33b1,b5207880,6debbcbf,83ca17db,4617488c,ac5c6997,ad4092a9,8a7bff7b,99976fe5,ae88d36f,597e16bc,6dbbd4b4,547f4dcd,7e85786c,d10af30e,1d81bbaa), +S(31be76bd,4f946e41,7de73037,ceaa0dd7,c6eccedd,74399e14,2ae6fb2f,d2b59def,54ad8748,ef129085,dc3172aa,904cc376,e203fa69,38783007,2af33889,52cc6549), +S(b6124d0b,f603a00a,22662897,8dd0da87,fcaca5c4,fb04ebaa,81a7d13b,39f2e307,34ce08c7,4463b06c,afb03c02,583288eb,7bfa6f2d,3eedfed4,91e31781,dcff10da), +S(6aa4bd60,90bee70a,295c451c,c8af72bd,3665680f,545f46c0,bf5af990,aab5f43d,9c2364d8,25406b76,94ec9db,a0ea2f9d,bb36fb2c,5bda62a2,bec941c6,874e68f7), +S(f72faef0,e268a7b0,a9b00a57,3674d846,c1f0dcab,c9a586da,be318b1c,d2874d8b,16b3cfda,65db0f3d,1b5274cd,20b1329e,61ea0404,1f702e71,cd98708e,28c9307), +S(1d26df15,98a6b9a8,7c0a6171,767539e1,86d51d1d,cef130da,1001226f,87872c5c,f227cd82,becf5493,e2fc7635,6a37bb48,3e681a19,ab4d9dc7,92edb114,3a7b072e), +S(28690cb1,db697840,13e9eec4,d9388723,4c28451c,cf9dd51a,746d1274,b13b4610,d9bc39ef,19228981,a1ead1f8,94deb254,162fed5d,cbb58a76,6d361e04,3d8f62ea), +S(4b0b5258,22dbc31b,1966b004,4d39c5de,f2e16d5,1e032045,f9973b1e,fe83ca12,2db33ff4,3631fdc3,b3608b40,7dd494f6,ae730212,9619ae35,f6ea08eb,51aded12), +S(a5b4e205,462ae419,8fffc1e7,393d366f,c5a9eea4,e98c67ee,1684d63f,cc09aa64,d3c11017,de4ad175,17cd076f,cf6c0ce0,4d3108ed,60eabdf0,935499f9,4226078b), +S(d4f1af69,2a3e9fee,1f92d892,b14eef6a,a0ec1f4e,d4d455f3,c70bcb19,52fa9837,115c7ee,73b90adf,f142191b,eca0be01,7d5a651f,93e2e90,5a36646e,21790294), +S(c275c715,9d6e9757,d2adef47,2ee53856,dcf067db,bd4f380e,892c9832,708d46b6,70da1cdd,853a0dc8,a6a9043,3c319371,25590c9,5807284c,ae168f65,62e4465e), +S(d2e38b27,83156e2a,a8e4eac0,149bf2bd,bc2918af,1cfa2a23,d1c7136e,15dca7b,738a0fe,751ecfa3,459e005f,72b7461f,a4b5e1ed,736420d2,22c5428e,2ec1348c), +S(f8f5b3d,b3659174,e0149fc6,fa747c22,9607c434,8f9eab60,900bfe92,b23f9a4d,d89eff33,94a093fb,549fece1,4e11028a,614cdce2,21d5ac26,1bc25f32,dca3919c), +S(5e266403,e49fb860,e6ed0928,45bc0811,a214a0e,dcd6174b,290ecca9,3539d862,ab300acf,5d8b8a14,2fc9e93f,ea995d2c,d7a2bdb8,6a146f65,2b8bd49c,4e8dac1e), +S(8ff869a7,60230ba6,aa5adf91,1ba61702,17cbfdc,5ffa4018,b8a09b9e,4088d634,db5a5aae,bdb946db,80e4c207,22ce38c9,4921bf41,47eea510,70e5aac5,c592f32a), +S(f3d39b65,95bd5ab9,aeedc43f,f49bdb20,73a211f4,5ec2c1b7,72226a97,a31c059b,ea41abf,9322d733,bb5971ac,194da6a0,a6d41c6c,a0d0acaf,a53e17bd,dabcdc68), +S(18ba0c34,10169914,7f7589f9,179b94f9,daed92c9,287f3468,d283bdcc,d71cc637,b3512d25,c199d2a4,c115bd11,eb53d6a1,6ef16c3d,97be6291,5ff76b76,890ba675), +S(2cf3354d,7f96c58f,3c6336a0,6fa30c83,8da767af,48f89fc5,5ced5b40,e0b86cee,403ac306,f6c3ad55,be1ee5bc,29cdd46e,2e3d83ac,71050909,5f117d21,7ef015cf), +S(5d31d140,f754d6c,5943deb7,6aa4d867,cac81abd,9911618b,82327795,da8d085f,c25f99d0,5bc5d583,a3a72b41,4e5eac5f,c14ced01,98247ded,79ba482c,882bec49)}, +{S(e0ad91c6,6ca95326,d440f44,df91c1cd,cd3ec344,e906d0ef,51fd4a48,31ce293d,3559f3c,e349f7b3,cf66c17b,2c3fe7e6,8ba3804e,438c0816,b68ecfe2,30da18d), +S(d8b8c50c,ae9f285f,d6d9282c,373607d8,5fda59dc,71ba0066,148b378b,37440076,ef83dd08,ddc115cc,24948009,f9eb4afe,dcd65c64,b6ef2194,bb4ddd0f,ece180e6), +S(881fbbf1,a9627bd,369abbc2,edda8026,a61b10f,4161e442,530a5e36,447a0290,6a63cb8f,7e5094d3,c8beba5a,2a1d7b54,bc33005c,efdd5a1b,20d51f74,d00c2fcc), +S(36bc0df,fd1441be,1a4efd6a,43ab9d83,243d44bc,a6e108dc,fa9a79fe,23106f0e,eeec58b7,dc37eedb,4432dcff,4de7f88b,2a0e0721,da2c0a72,eadac4dd,71037ed9), +S(7652c155,c2ca8a23,7680f015,a62c7c31,31682752,a99c4329,77ccfb9d,cb58b03e,5339a51b,36ad4548,197d3018,4bde4428,b38ed983,d624bd18,a5f8c4e7,21871c5), +S(904774bb,fb8b0c12,e2b3f91a,e5a2a0c1,a92971f9,86e29fda,9edc609e,e85b222d,ee843f1,8039e251,9c7b23b3,725ca099,114b4f0,26970111,35ded92b,94445e2d), +S(1c7c82cb,fc14b9b2,cdb3c12c,32df33b6,a08e7af9,df62f310,79fa0710,f28f5f95,93471b5a,17c84eea,a45948df,80c0f56,d8684f35,1aa2ce73,ab84b3c,1b8250a4), +S(bb060f5d,971ce062,427a5630,8f114532,40ec54fe,6479d5e7,9ce81444,27f07927,fcbeaa69,8278eff3,d4dad904,836c0233,40a866b2,d8f66774,70d1159e,201501dd), +S(287c5b8b,8dc168ea,197200ea,97c4f63d,db0b620c,7f30d623,7934f856,a558438a,260630e6,ce310eb0,366acd78,bb58f4ef,27fe4836,edc8ff0f,5d5ff987,b659bd20), +S(7d4c5c6a,d6bb0f0a,47b45a35,1264f4e6,a81ee0b1,65a7e665,4b226c95,feb59dbb,e89691f3,ceb4c57f,5aabc1b7,4acd9aef,41531851,b41ec1c6,608f16a2,2243ab5e), +S(ff806f2b,9eaea4f6,47d85077,d8aa5052,9d4b96d2,1e0b31e0,7c86b14b,73b7ab4f,9acc2f77,a994997c,7a2b1aa0,79c0b5d4,c84f6715,e4a50e33,628b871f,8885ef9), +S(3ce795ba,1d91a9bc,b0260654,3450ced8,c94184dc,8a41ac5,e1b84856,e88927de,3492e696,cd1ab2dd,587d4707,ae34fd67,3ab7902c,d0c0972f,ef419795,1ad88a1), +S(299ad528,afa3f36b,c80a757f,f081a8d,c4a6ddc2,d2b57fbe,1e3d361b,ee5a5d8c,9fe823da,74eda2f,266a8e9b,331d511b,623dcd32,ef9ab7a7,f1d1cb4a,7e6fa65c), +S(bc4b0549,16177aa9,b52b29b7,cb91673c,9ffce4c,7d0066b,e4249383,4467e3b9,55bc6436,7db68687,e699cf6c,f2db9dd8,c2b9a438,8202fef5,11acdce0,ab06f969), +S(a8e8b02c,ff5de02a,9e6652cc,6fbe41cf,6e87ae0a,abb14ac5,a178b3d9,e697d0a1,285d4af9,405b03da,c57c993e,4b40df8e,82c6979,f8de57ce,4543b7ef,3381e0a8), +S(e50aa8b6,d7dcc055,4f406959,b056dac5,21a7842c,ffaf09a1,ac24a3d9,8aef5228,46656395,ee84d061,a9f5788a,cb05975d,5ffa5fae,edced564,1f81b5cd,2491c23f), +S(cb516899,98a214c3,c31e4f2,692cd7d,fad6f1aa,eb8afd1f,b29c23ce,429c224b,2292b8a4,5a89eb80,167238ef,2027f975,98a2aea9,a4460c5,3646d088,82403c63), +S(ded04c06,74c6eb16,557b5bed,4b6703d2,cc37c6aa,bae466e,ee7b5665,6693c3c9,4f3ea70f,8e75b02b,76934cc3,645d2af,eee8e9d0,8d100117,40e8a16c,dbf01113), +S(f3d0a253,edb74436,897e6cc6,621c74e1,30457b41,e0690b6f,7b2a203e,8ccf8ac8,89cb07e0,97495bdf,403490fa,d58eefe3,e79ffa33,1deb5cfd,2c548ec0,8771be67), +S(d4c66267,aa73ed55,bd68fee3,2a166a4a,4ec660fc,4cb13e18,fb6ab0fb,19a5f330,7c2efa2e,4509b221,97589483,40b6c74a,8ee2b5b6,5fbb794,7f838c47,ee03e2f0), +S(dbe9a638,f262f9a4,b3a8955f,22293feb,50ef4b32,20df0184,f363a373,d7110981,4c563e83,5e957756,5e6a8996,97510c67,9561972e,5601c1cb,2f2f789a,c1e0b5dc), +S(70c7c07,1b1e6fd0,a97b55cc,5ee34297,166f4d02,417a796b,eadcfd43,96e1b338,b5c49a6e,2ab03e55,f4755f37,e5211d4b,e23339d9,d464fd28,6781bb29,56db23bb), +S(aabc501c,6d52961a,a613fe66,96f0bacf,fad74fcf,8386cbf8,b18704bc,a1392ffc,cb72ba86,70bc3f7c,85a00d3d,76b11596,6cfa0fc7,44b31e01,9129da9,a5b04b77), +S(47f72ec6,e7820788,f0f7814f,aefd6e2e,af5d90f3,f877677d,ae72569f,c6a2e8f5,6709731b,ef2dd880,4696a6,a0661d13,fe579704,5e0a9bc0,e5fdc0af,789c5830), +S(20026251,d9413e42,47a5884c,209b144c,98e36f7d,8ef3f56a,68efd475,8a2ba8c6,9c5531b6,94ba0d24,a943d0c0,94bb623,75c798ca,c9716181,a9d659af,2acb978c), +S(8dfc6293,9b300c9b,fb617d23,6885f652,424b4f12,d04f8bf1,151d1ccf,935e445d,9a519433,18e94107,5472aa9d,6ec3390,59bd3bcb,bbbf6937,c9290e48,9da25f8f), +S(afef3520,3b558495,6fde0eff,5cfab48d,8fb08806,3c1d7cbe,d7e352c2,9d49176f,a764e6e7,bd0c8fa0,8a6f7f30,aa38d7de,fe71773,fb7ea484,68b3fd9a,8adfd650), +S(354c0a98,1628dfff,8be8ede,ed809db4,bc39c686,39a26828,ff28dd47,90801c46,8ff40299,d607036b,acd7c0ab,66a102ab,38f8d3a8,a271e2a5,20b43cbb,687cce6e), +S(da2e7eb1,1a1e66d9,5001ec4,f7b66c1e,d9f7d0ba,ea3bb326,672b9069,5cf4bebb,cbc1c7da,b9bf7e0c,dea9297c,5f45ad0b,9c4fb093,318b55f6,1e4a8951,726c4021), +S(6f780994,d0662667,8fa74156,4232bafb,b3a7f54b,a5b66507,9df32545,c192c3fb,5f11f0f3,af1a763e,4c9fdcb1,1e5e57a5,6dfe0d0f,f27535b4,4343a312,90e375e3), +S(8e28948c,729c1438,5bd09316,31ed3eb8,7acfc5f4,2a9eb4f8,afa50362,33591cec,2c09fa1c,bf0044eb,a78ae81f,bdbd4271,2a89ffdc,f7d476af,881d29fa,2627f250), +S(4011cf05,a85ef14f,1875cf3f,4f78a51,a52a89bd,a8930a4b,8e13802d,b85f319f,35045b10,45c4f71c,c762fa78,5b8d4daf,aa2a1c07,ba37d82d,ee0592ae,ad807810)}, +{S(9089bcb7,1c1559bf,e17f6c0b,91fc098,c63785fa,18a42d69,798b063f,a0930175,de229175,5e4ebf17,1047f79a,37d81b9f,9004a7cf,df747589,7365e174,ae367969), +S(4d1caeb3,41f25459,3b06f715,9e9418df,e29ee076,76c26e6a,51d8add2,5c70a5d1,bf773e4e,4151d17,650aa7ed,1d6a5505,2d622264,75c50f31,3261aea2,cf68dc37), +S(b0760330,517c0d66,2571cfae,830da7fc,a7e0d86c,1ca7f75f,5150f625,db50ad2,d8d10ef3,9c84bc13,32c2cc01,4d4df0fb,45e5c546,1849fb1b,81b7fdd0,7484d35b), +S(3db731e4,273e5b20,2de984c9,74b4112a,d0feebe3,7bb0d2c7,db38c7a,21bd8c67,b425c1d3,46b6a61f,2893a3aa,a243d60f,5563cba2,40018cca,3f80925f,71f4f1b1), +S(3a74a50d,cfbf2ff2,5c99c4d0,1a13a917,9f510c2d,eca1d5a,7ac8fb69,7eb9795,d2b468b6,714681f4,57bc586f,40585c01,e1dc14a1,a42ce887,9ce044d9,ddb92d82), +S(b9139ad5,4f44fed8,4917ad55,c49c23c7,8d62aadc,e83c9ebd,9efde865,cb1eb298,18068856,c80abc3e,2a02a441,bb7a7609,aae8d2d7,8abf4e2e,378fa3d0,a27aa900), +S(bcf5cf94,5887f183,e58a0128,4ed9a4f9,fcf918dd,4e68d70c,5a54eeff,166cb44c,8235f63b,bb06a1a6,d9ad2ae8,47aeb2b3,4838c962,9608943a,93294c6d,e21a3ab9), +S(4b598ce3,a77680c4,c5f66e90,1b76627a,27f35301,9641520f,53ea3894,dcbbd187,357af043,f77cb9fe,c04ce1f4,dd9b610f,9151d15b,3b7383e4,ecc5384a,8ff7c5cd), +S(b588aec9,2dc045e9,a95abd7e,da929837,28b5a7dc,d637001,ce7f0917,1283b16e,e682f53b,5e94fd84,914b7bed,5afc28a,30ae6f53,e12d948b,3c0d88fd,adc5d0e6), +S(eb8f5080,218ac5c3,cd792042,b59e80ed,e3857a75,a81d67e0,7c2221de,d3b7a677,c5f272cc,3734e0f4,6a5cf40,626973ae,1aa76839,1953f211,eb52693d,254a7fc3), +S(87d119ee,65a60dd9,aac3e784,22049cfb,4123d262,ac9e7473,4c9cc418,fb7ce4f0,5185ac,7bcaee8f,f1334eeb,cdf2c39e,83b8b665,1ef9d8f5,48a029c6,464242da), +S(cfd0438b,186d0f5,c64b5f38,a190baf7,35b67512,a439f486,fb79d501,90294683,985edeea,243e9c6b,d9c57cb5,c7372202,7492156f,e10bd2e5,67edd14,8603daf6), +S(52abfb67,5fa8b12f,1b0cf0d,8e85f402,47696662,64c7252f,69562590,839ce4f8,8483ab43,2d4851d7,4f432c0a,8e3863b9,783cff58,3d4c390a,9865d7f7,d1aed67f), +S(52926df,cf12eebd,3008459d,3c91dc1,73532f1d,ce3c5d0a,874ea4c,67331787,18b48fe6,1bd74ac6,4b34f2d0,e7de8920,2c875625,bcad84bd,cb3c81dc,cc86dd87), +S(695e09db,8c4479cf,4c305005,b5737ca0,63f89d02,aced2010,5600d65f,58e26401,32123a91,8bb23fd8,79715cc7,488184b7,53e0eb00,6dbbc95a,ef9d815f,3833c08d), +S(97c35716,e5aac70c,45dcdd45,a5ca0155,5962f09a,cc22c16b,c79ec272,ce1c12d3,93869464,6470f8e3,c0db18b6,2e4378e6,5caa7203,c4d6a079,a10c8182,b8eaec3a), +S(35197cbb,8da9188a,fc60faf9,71cf08fe,73372e15,f857b93b,6afd77e6,bf4db7ed,4e0efeb5,2db601dc,a539c777,14f4aede,c5ff121d,77dbdeee,7f16fb0c,4cfc19af), +S(afb2f842,e0818237,46c294b5,9ae8afd2,279e834f,100f7d1a,58a9551a,98408d49,5bf5ac43,a3609b4f,f058d6dc,6ae09fec,19a19864,6d12096b,6bd3e06d,95d15ae8), +S(a37f6113,882459,b1dc6335,26253a8d,287c9285,b7862721,f9bee74a,d2c4c09b,9ed3252a,303c6d,e01c9985,c5b3edce,1074d478,db56b961,d91fdaf5,1b1d07cd), +S(4579a503,cb12a345,182b28f6,9a3fb98c,4a80579b,2ff592d1,ab18b32d,212098d8,8c61c503,df79dcf2,6083f15b,c3ee1f99,9e1e0960,8bf6af9f,b3175699,cb0e32d5), +S(545031f7,883a2c8e,bd56a405,52719096,4aa1d40d,b22a1730,242f3064,530ce326,ecb024e8,e762b456,f62072e,5f471180,bbc817e7,54e830ee,7757ed7b,df5c9300), +S(b127fb32,bb3e193c,99d232e,d50dcad0,3b45c072,e0d521dd,de72daa9,e20e97b4,b198428,12a344b9,2e8a8d26,f7964c66,82cb3652,66ab3e28,2ba56197,a159f1a), +S(28cb3582,d312cfcc,75ab637d,66c646f7,5157dc74,7a464e9b,933c0820,2326b6cd,a87042b8,510ef9b3,ecf918d,916128e5,f946f43,6f18fd5f,ad62c46c,5882a23c), +S(8a46cb3,27efbeb6,850e3861,c4845ab1,21414f12,9fb27387,4560826d,c9116886,ab09eda1,9156f1f7,194b7b17,fce15268,ba041c96,24765ce,fd964ede,d1f05b3e), +S(b73af914,10ad56f7,d490dc37,1a2584bb,633de0f5,3f00cd0f,6b8a6019,53c7ef16,3dbf4e52,753e5d33,3fd23cc1,c839f278,38eacb3d,5980cba5,bf1be426,b27641a4), +S(b38c1896,427a0108,3f24a917,2a64314c,d9dc1759,60971135,1b2db6f7,d66ab745,d3a71a74,f80d6919,b65629f9,80c7757a,cc49c2aa,78dc67d3,d6f76d06,91a90d85), +S(6f6ac108,aa819a27,6dae862e,276b3ebd,8ed5a3ad,9b0296e0,4f8b65a7,f6a5ac1a,e3048583,7aa2140e,de381363,788d6d95,25a7ee33,9e3a3ed1,2518619b,30d9f71), +S(72f5809c,7c282ab3,4dd81851,33070d85,53999a6f,14fd753f,2ed8deec,ed7adc5b,112bf5fc,8cfd71e1,84ca1967,d05da765,801f12b4,c852768f,60afa7f1,e9576534), +S(4c348833,10f7dd6f,b385ce25,e2d6eef9,8556a59b,5e79a084,ec83425b,37150085,9c4c97e1,be47b073,5209ecf1,5f05cd8a,58ece74c,1b35a92d,96a70287,11d95add), +S(f16e4513,2291b577,ab360b42,c1babcdd,ac61e623,da85819,e9c4c73d,463204b2,5556d7d3,a2d45955,28781d15,16b59aad,941ea356,1b5c88ec,94d09314,555ea64b), +S(3580d3f7,896fb70e,d48d40f8,1b31a72b,51405574,2c2b4369,e3e7dcb,aca4ca22,e38da3af,f409e459,82098305,87aa0eb3,b2339959,75af2e33,501115ce,648360ee), +S(407e63d2,c0cd6d37,84c27734,f7e517fb,4bdf7847,296dc7c,a8714fab,16199828,2dbe5da7,4b29bcc,fe9adabb,69157830,987ac51f,389c6001,2577f298,710025f1)}, +{S(f61f644b,e2414c07,66c6caf7,5d32683d,efafb133,cb4d341d,7eb565e8,9f6e4158,2848548f,15a6e7d7,2b2eefc1,1b76e318,15ebb4b2,1e3bb938,e0c2e9d4,5ad4f7d1), +S(5b891f8,ec902550,429a5ea8,33fc29c0,bfdddf6b,a6f62c19,87a14050,a9689a9e,77901539,1ef92985,6d3e3b35,4e4ba2db,3bad967c,dedf331a,c0bff08e,f25f2e99), +S(d8c5a617,62655ffa,c943ba35,3b595b46,88012282,af068e52,d918bbec,46bec87b,9263db7f,6f74aa,df0dbdaa,7e7ccd76,cb3a498b,44de2bd5,f9b23029,2ebc6009), +S(2e940645,cd189edd,2d6cc2f4,f9b49e4d,305cfe8a,46f2a596,fbb55200,89fa5b21,4c197028,e89ef8a5,b5b6cbb1,3733e90,408877fe,7425d58,1f4bd063,ce286fb2), +S(396c3bd0,9c6af07d,123a8441,c9f79ab3,a783b8f3,fdd69dba,ba61c7ec,f65e3098,534c8657,aeb8cdc6,ea34b372,68f1c70,70881797,46b8e335,477c8525,cd17aa8b), +S(c34e6be,b079f3e8,d1355754,4246d2b7,a82d551b,740b4b59,b9220bbb,768796fe,57806a7,653ff7f9,3d7cb6,b3acf68e,aed049c5,75988fa5,f03b1ab5,1103aee8), +S(5d2d6aa5,252fc9b2,55d89773,e920891e,7021f233,5f7d0ff8,c6bde5eb,b65c5149,1fdbd2c5,6b8bd095,2d16c304,8d9c588b,2a26379a,17f748d,f1345695,1c5959c4), +S(dec812f5,745fcbed,fc36c635,76874bc5,96dde8ef,68a8724c,201b6af3,be7c6e2c,1715328a,f75f9661,d58c667e,5c5514d4,c99dc881,8cfbe702,e0c3c8cf,662e6906), +S(32499061,83487250,f65684b9,9434489d,3a83ec93,61531dfe,48086b2e,b2bd18fa,53217af1,2a25fc6f,45555d93,98fe46df,4247d38d,7b162e34,945f8928,bfe148ba), +S(d3e9381d,83f31116,ee161490,c9b5d1e5,7e086c6c,1552160,2c913315,af033ddb,97ae863d,34271b26,a4d6577a,32028c12,f092a54,8a18ae1b,a83de384,3b8fb84), +S(1347dca6,d097faa5,7c6583c1,c292c6b3,ed87b31e,9f7afe8f,d0d151ee,50ebdeb0,570a9be,e4806ee3,e30696c9,71b5d905,65d09ee6,8b4fa8e2,8acc54c0,7fabb492), +S(691f9995,af2bccbb,f556f624,b28a1da0,67854c15,4f014e92,a56a8cdd,9a43c25c,81babe0,ae44984c,bfdfa958,4dc5c677,881d1b0f,63993075,a3fc462d,e986866a), +S(cbfb62c0,b91cedb2,5a9d4b3,ada43cac,7839dd18,33174711,24688ca5,5f162cb,77c12161,e8199410,b040dd57,4d90c39c,2f1b499e,6b7c17c7,fb21438d,aff4e674), +S(53627516,8de62d6,2c792f64,f87996af,3ed8ec88,653532a8,ad60942e,cae4a339,d8449a0c,c6ae32ff,45a11652,97b3d3a0,57e67c64,42d3bdb1,ea2cbcbc,cf0655cc), +S(2a81679,7505601c,763e6f6d,f7ed5c0c,14ee7fbf,d75b8755,7bd57f3b,e2d3c7c,99f26af2,10540397,b8423da2,c4809942,63734d99,f0d642d8,96b5f216,767b759e), +S(54b2c03b,7a7ea964,220a255b,bb688767,99ff1b83,f0934e4f,fd03c2bb,51490e22,b3cc56a9,ada9240a,a3730828,26733090,ace3d7e3,91200d08,2cbfacfc,bcdb9c08), +S(aac88c8b,7c96e629,6f023e5e,8f260324,9f4e645,bd701705,8f38e9f3,a034eb57,da03ca87,b98ab6fb,e4869756,7c2db04b,7f9948d9,ea65d93f,d222d52f,6d48c552), +S(bfdd8394,fb49f93d,630f6b8d,469da38b,105529d6,70b9a1ab,e3196816,d2a13978,39a97919,4249f78e,c336b00e,475722e8,7ca734d4,3d1e97d4,d2aed074,abfacbe9), +S(5b5dc3d8,66ba3647,d2aab2ac,3338abbe,4d1ca08c,6cc6fb26,4335f40d,4dfb2331,3432ba31,46a0f15a,beca45e4,1ded8729,e6a0a49e,70315745,bfcb3388,4e1b9e64), +S(77057b28,a1d139a1,91e05ad,a8d72f3a,c7bbd198,7647070a,b6a21355,7bc0c73c,46f32321,4519afd2,f830cf7d,567aacc9,47ae6b8f,8c841adf,988e39ad,e7b9757b), +S(f6c8d1da,e28a3d23,2a388998,1b638b23,f381618f,18dc81ed,67bfa696,4cf1626f,2ad8c92d,43378941,8d298dc8,2cbf288e,86d21467,ac73c0e3,383ef3e0,a03142fe), +S(b75b5cc3,77a55310,a3b97067,34f1929,fc0db732,3265e6da,71405f37,729d5a90,be077940,4dc94ea3,3cff505c,e1aef457,bc120359,521eae05,1de1963d,b1948053), +S(a66d54d4,4b4d06ea,f141307e,27e1c225,41274eef,5c0b1743,e6398b22,fbaa4068,51b6b8a8,48e1c27f,107f82cd,d0554643,b9e16611,fa93b789,a2199b3e,3bdce296), +S(56b2f9,ab707dde,3479d0ea,baeb62a7,6cb9bf03,66278eed,559e027e,a1ea6b3b,27c47e9d,646684dd,2a54db0f,c245fcdd,721416f7,22ed568b,736e3e1b,f195b379), +S(a9642a49,83b19c3f,f5f63ea2,9e76afbf,a25dd0c0,221b32b7,6e67373,36e7f5db,8ada3766,9207c6b6,a6b6006b,5240a4d6,cdb8b807,c0c16a56,91289b7d,62b3a051), +S(18eef8d,f9e64c1c,548db40,ad77d92b,11f3ac43,60c63792,5f7d598d,7d8d5155,806db24,eefc3a64,c84da338,937811e1,20c6d0e6,9cde79ee,9957a4fe,c53d0e12), +S(d11359fe,61861a36,8b3809cc,c727320e,42905036,774d0e83,98453ac0,68d404b9,d4182ce7,2500637c,8e14b977,34fcad09,f061838d,57c555fa,420fbd50,9abf6b81), +S(7ea072e8,f60ff273,9cad1d8f,c560f208,b54149a2,5748900b,50830e3f,738b2db2,af09e54b,d44feb44,b39956af,fdca6894,91c7c6fd,f029e71b,e780f8f6,77a48a0f), +S(f53406ab,9fb1317,b038dc28,f0165abc,115b37fa,77d23bc9,e51993a7,8a15ba00,a293f429,f7fb281,9cb60b53,b2e6f07,afb6537a,39a18be,a5ad4cfa,55aea13a), +S(b1674e5f,9f194a16,94fd12d1,4b64ac8,bba69432,241aefd9,9a1c49d,23287635,83cb0060,1f5c33be,9436d946,22c3b3ce,68d20733,ee1e2392,8c3d6c14,a7cde085), +S(22b72e08,66b96344,ee53b898,ea725f7a,b5832c12,7c0881ce,862ea945,5eafee85,b886e8e9,cba29b15,be5c22d6,ada99b02,1098be69,d1c500fe,6fd2ef8b,f1ecae25), +S(9b7151af,698a85d,2246c88e,8ffb14a0,c762c2e2,64ab70b7,e30e2434,9b8370b7,fd9c3d89,46ee9d90,e7fb6d26,796062eb,4cb6c160,76df4834,eecd2748,c8a7bb4b)}, +{S(5ba26c2d,53b04b63,d260c6cf,392786d9,41a1a7c,b88331c1,149cd3b9,9c207f5c,9c7f6303,bd72850e,d4da618,3427e7f3,eee078,6f67cf9,85d483ef,79c2eab7), +S(f7d26944,6d29f81e,39a44a88,49f12184,b9f42eef,16c5d88f,60c96a28,cf0c3e48,e7ec965e,d0a966a7,45087e09,a058421b,852c8a7c,3790a3ef,7abc6ccc,e17c6084), +S(98590b7d,36bd2ef9,37ce788b,22cab951,d921724b,87c3ad83,8263416f,b5a67dc9,b711c21e,5af72a36,5cc1b220,7ed09ebe,be918555,55e9239a,e9b03d75,c0261d5c), +S(92e1cc4e,5f57514e,9ed13535,5f3e2cda,b0b22f8,8f56a972,a657dba4,7263463d,14d296bd,452f2faa,7d6f42e1,550fe35b,3c47eb2e,fe7636c6,2eef90b2,e7822da8), +S(33de9b1b,e153bdd6,efaf9d1a,30aa9b3d,faf26a32,4486b6aa,ecb1f958,f11c4673,7ef29223,4d3a565b,c0f0e295,deffa3c9,a86a6bf1,933a084f,9334b790,51eb0270), +S(f9fad0b7,e1dfd4b2,47cd2cbe,bd863e1,95b3be25,6cf7a707,5d422b9b,f5631ca6,fd5262f9,e6ca0cee,e1c7e531,83d9f3c0,7ac518b,c024681b,56c06a1d,1826f5ef), +S(455ec5ea,f34c02c6,961469ed,27bc7883,c07c9a18,663e22ca,83830a66,569b2b36,4dbf1b57,a7de2fdd,7c0380c2,b38fa5d3,697a5995,8ca0c0f7,6405244d,bff4c9), +S(940fa05,d96fb400,bac8fa39,e696c536,71a490d7,c98b3851,ef76ed35,c62bac19,b6de17b4,1a045978,5755497f,1c2a953f,17554b4,20f2ccaa,9fcfedf3,5afb9b46), +S(16012402,4ded6478,72374af4,6daf9c2d,a9000841,9a7d4672,98b627c2,420981b,7c2607e0,a4b86f7a,d5df7371,60987d21,35d2ce2d,bc422ab9,b643d080,26f84323), +S(caf887e3,339046ff,42c629ff,c954873,2c629ecf,319c44be,6701a9f7,c81bf842,d253a688,3b3d51c5,a914ffb7,46e7ab68,70c2b1ab,5b7e46c1,7a5119e8,4ab6c878), +S(41a5b720,595bfc66,18406547,d59ec09b,4efba0ec,5bbd3191,9e9256ce,f40a7afb,87ee1be5,2233ba8c,82dc06a3,6fd0a1b,4ee8d7d3,ce89cb56,1dc96c19,dad79613), +S(8bdcbe80,fe8533a,174045a8,3cf9d89a,ca438ef0,8f6393cf,6e24d923,edb02586,8d21379f,c053e8dc,c628f0cb,83a7782c,b4e946e3,ca88d467,36232762,fc6f8fdf), +S(409a4482,6b6f0ff6,36178d65,aedd64cd,2d28b39f,3e9cd93d,a0afe712,b75fcd19,25a3bec4,74216dae,d686825b,bee6aac,487a6d07,606e5aed,7c3032df,f4911eba), +S(b7f414a8,4c0af927,64ed5b52,e96dad38,6995771c,2cd90af1,1986bdc3,cbeb61c0,702b0a68,4e93f0a6,26b807d8,8049db6a,3e65001a,d75a476c,e4be230,89574e8e), +S(58b0cdd7,bed4f327,bcecd493,d835c0f0,e45f6fa4,3687d1d2,f19de285,5bcb5c11,21b0a478,2c1d14db,9c67817d,7b23db21,a96e456e,62a85c3f,2a02c76d,78dcad10), +S(c75cbf00,893447ba,5b3f8462,9d6897ff,64be841a,9a6bb714,54adb849,8df03900,15f68903,ae20ae4b,9b3fc7c4,f8135936,c09de15,18317dde,bcf66190,2db79f72), +S(e6258fd4,b63be23f,38361a16,cf3f81cf,f2d7343e,515b2d0c,ea0bfe38,6d4400a9,aedca212,9b73e49b,9757cd7d,a39a1e92,f885b267,a188521b,32089ae7,6d351eb0), +S(7c61b66d,d76f759f,be92708,8b075147,2ba10db2,eee4f0a4,2eac1ad0,d2dac3a6,c2b79de,70372e1a,6c9449af,2612e34a,8e101cc2,81ef378b,97cd77aa,bff004af), +S(29c71194,bbe41f4e,b2f58bf5,799616c3,7b247283,c993bce4,630929d7,55f7c8c4,c0fb083f,d68f63d3,599c2da,9d0c1f03,b6903545,a47581ff,3caecbf4,359e0235), +S(f1cd983,5bd3eb61,f8207495,48da075b,ff4191ff,d5b1521a,a1f4413f,2173a68e,beac8102,13b643a9,4658cdbc,71713894,39b72abc,f8644697,2fe6310b,4ff0233f), +S(94f2137a,ae170855,3af3dd45,8f8fc9d3,c1bf07e4,35a62798,25d5b93a,37380144,e952d6af,b27f9b2b,80ccbe89,59fb8b15,5fe1b2db,f3ffbf14,cf9c1fe9,b8e8209d), +S(f4f0cd2,e28cb8a1,9b469b18,90033912,4a40a39e,67ae1642,a3a677b9,fa1a9a3c,75412f04,5c41770d,73d7cd77,bce0da96,1e6fc69,cfc6cb9,8f691d43,dce1e548), +S(15ba2fd,b652ea98,f2b326ee,e5e1629b,ec8f8e7a,36078d7,cb8a80c8,c943e98a,db416844,cf757376,cfcd5a9a,9a318b51,184f8c89,fcda3d97,e735c120,43d47c35), +S(5754903c,ffa8cb6a,3ffe3488,e484c498,69163b77,7c07183e,8d2da037,78b8da34,508312e,6c2fd008,fac12bd,afdf8e50,1940a81b,d05efd38,5277a85c,ccf125da), +S(3bc76f6b,8abc155a,dbba76a1,9c0fef85,373bb1bc,9775f431,1b3ccb12,9c7fb29c,48036702,aea467ec,daa8b809,97c41c07,9e38c414,f798bdc3,a531b08b,fb4ae303), +S(2992c410,306d3d40,313ef69c,a2e3383,88f592d4,a9c2bd36,ebd9f51e,883aa33,cdecc5df,41cd193a,ecb26700,baa42486,a0506372,d56de3e2,2fa09156,7b525519), +S(baa7d83d,6d70a528,e6392adb,b2af797c,72772b92,ace96a25,90d65c37,b0ff1bc,9943b555,4e44b480,28815d8b,e50189d3,6617e9b6,c8f07393,8309e04c,9978fad7), +S(935488ea,4c88c2e3,cda6c0ab,5b42d519,e7fabe09,fdd3e36a,7c78c9bd,730612fe,705c8f8b,228be0c5,539eae13,1f4f4bdc,2fecf6ce,6cc567c4,dc692af9,7c1d506d), +S(8edeb68d,e63c35e2,5e36bc8,61445a63,8b0637ab,d14557bc,f0b0648b,db43f86a,d20bd0ec,14ef4f35,68954130,6577ef85,baeeeed1,c1004130,80687a5a,94a9e9a3), +S(9a39617a,27c2ff2d,9869acff,b22fad1e,a7d04271,be154547,43234f54,7f21924b,917bf9f3,fe0563a9,8daacf90,dfdcd8eb,e657f023,3fb15711,79bc5ce6,e6f5dd56), +S(41dcb02d,21137ea3,a179b469,199f9ed7,9b831923,68719a4e,5c727ce0,d42e95d,4669d53,82147266,8327cd6b,31c21b80,d3394bf7,fa29a43c,2ed7441,d866f5e1), +S(d4e3e3cc,387e0364,6688a62d,9390d585,a69ff43e,1060811,431dea8,d868355e,3309af2c,b3d7ca6,55334f2e,c53de6aa,debf5d57,1618ecc2,9dc9830f,ec46144a)}, +{S(90edfd0,61871350,b7f1f029,c4114190,b050065b,2030a400,9a8a7a6f,4b92aae8,872d4f07,5f60ae2d,dcec2f12,98a22da2,53d54de4,fde85560,690dde89,1628db56), +S(27e3ce53,b4258f97,a499f408,ecab24f0,60aabae1,dafe992e,5a34952d,5e6e486,d393fad2,9be684f4,7ecec306,332ad969,75b79d29,b5863d98,5f959c4c,b8ffb442), +S(420f1078,27c75c95,d5bc657b,a46cbe2b,415a7d42,ad62cdf1,6c84ee89,22215379,8b257a28,e0b15fcc,ae0b555a,cdadf4a,be93bbb3,a208ee45,77710a9e,d58da7fa), +S(28859abc,b60a95e6,b26c0996,566bf798,60c1a194,2d3342f7,9655f286,32f9d5df,2a770426,5eeca5d8,87840cab,3923d868,aa7b7b18,f9d19941,738ca006,54ccba6b), +S(c33c317b,490e2266,2649a021,e87f6596,3897633c,90be208a,193f1d52,28614059,af850be0,d18708bf,d0e1f523,c1a4fda8,9a6c156a,55f82518,2bd99bb9,b999a358), +S(2333793d,b961d3d6,740fc725,6cf9d833,81b5dc92,85b6d83c,5c343aa8,5baea83b,accc199a,ced3012f,b6db99c4,7a36c30a,f88e7eee,b62c2ed4,1352b488,ba0167bd), +S(4834aa89,caa9c25,a99ee4da,e4a64c15,25a5d74f,9ce573ab,ff44b63f,c3a578aa,fb189539,448a265b,eb87a268,b71a18db,f12fe8ac,e502720,c83ca156,c1cc7a39), +S(432cc05f,c78b0d56,e605391f,e4708bda,a1ff3edc,96a729ca,aad3cb0,300c4d4d,6675d8ee,ece8c078,e1bad373,247ce383,d4c65519,4a6aed20,a7ca5eca,34a89c30), +S(874fda6c,b284ca2d,a216bbda,28249388,88da3968,7f615ab,52c8e61f,b72a1fd,2d7199e2,b0b88f45,18e6eeb1,240b2ffd,a9bfcee4,6f754a4a,3db7959,dfe857e6), +S(7fe21a0f,3ef67d60,1de05f67,2b163285,a5577948,ee78274b,19fc35cf,2d2f6801,62fb2ade,5e2fffe1,28542038,91a6ea73,aabfa35b,1f7fb000,95190adc,de6663f6), +S(cd0540e9,efe497b6,2beb2227,a2da819,a1ac3bed,8eae24c2,6e2991c0,a707dd69,446c3218,7d0c9229,d65dad2,1392e4a1,66445386,4a5c1620,bf768fad,20a45c06), +S(a533c295,74e78024,52218573,66c30001,6159d772,f5bedcff,28d7f7cc,3051457,b61a106e,e0166d54,5e1b945a,f3e4e285,31a34cb8,56a34dd0,cd21184a,9555eeee), +S(5e144f44,ed88845a,c089331c,eb58811e,4c164e02,5d1758ee,51a7a522,c66deb30,ff95cab7,597cf62f,e1aa8df8,a2cd3844,d71ab4dd,4eb02a9e,6175077d,261e2540), +S(97487a40,9562ee2,7620fc2b,c5bd55ac,6509d487,8ab41257,53884b97,7c5a84be,e52a282,1430c540,5f1143d0,62b69faa,16592f02,cb9b8602,d52c9fc3,70769091), +S(906f9ac1,d3db4690,d74771b7,f1940679,b0de7731,a68d7d35,89caae34,c3760eea,6f2be7,2275dd5,1e77a066,b8d3c303,f565cb97,b8fb0dd3,14445d18,876665a6), +S(4c355a31,d17617f3,5d4066c7,a125b2bf,1d6f77e6,27b585ba,2d271a29,a88c81b1,6a686e69,237b75a1,a1ecb86f,b715e858,35aa0686,e2ef10bb,38b762ca,5646e9db), +S(15aac1a8,9b6b7629,57375d4e,aad87c9d,e1fc2617,89e57d29,731fe96c,1380140c,2968c0b2,2c3dd83f,3286d37a,639bcc14,3d89e75f,cac1da56,7e07799a,62af1008), +S(4642f29b,37b87118,65767998,d00b41b9,fca6718d,bfc55785,1c459efc,2ea15037,a1ded31c,be33cc1,425df851,998ddd11,1518ed13,f84756c1,c7cc46cf,3f5e9a72), +S(9554abe,9e092bd2,c4ff46a0,abd0b7c7,fb73d85f,1c01fd96,83146559,306ea727,89e2c07d,db1fe6b0,9872ce91,66ce9ca8,1124986c,c7e48e09,f80aa3cd,70987711), +S(1c0977a,a773c56,2e36dd15,58b95fff,d35b4dea,ac464011,ad7b79cd,26227238,e04ce4c5,b0b165e9,87dfef97,d32094ea,3e86e6dc,33a4c96f,c9470336,34b0db68), +S(71d44171,60361c39,6295e5cf,b1540ef2,1ca046b5,98645a23,e8c9772,ac21be4f,7122d5b,32a654a0,1476a47f,d3317a25,ed51536,4a21253,f4068dc8,14660c55), +S(d906f59b,4d56bc12,f26d60e6,6fc31733,e5450707,89025ea3,8a6193c8,520ddbc7,cd7f414b,c6cc79aa,4c65b943,ff914234,a9d85cf1,9853be59,2a71fe1d,dbb20163), +S(11b7dfb3,17dd5c23,6b8084d4,f3cc157f,c25c0e70,8248b472,240963dd,9a3fbca7,dd2c8caa,2a2d14d7,fbec267c,9fe87ab2,8b1ddd92,dd100449,f75ef1da,97d4e5e), +S(3ef8274a,fca8fbb3,1894d7a2,d1ad59a9,4951b21,328b1e84,ecaa6df9,cc1ef473,2e4f0c04,f5da671d,4a2b641,46ae749,27bc35b5,98a54190,3883469b,3e7874de), +S(a861fc27,f5e6300d,ec0fbf6c,3315d053,98f90b84,2422992,bdfba11b,1c1c7e34,75a7458,5d98bca4,e3517897,afef848,8e524168,a586d8da,18834171,4b51846b), +S(9537019f,57d7869,2a358758,47e885bd,1594a426,4412c595,62eea9ba,4ab34de8,21bfd84e,a66650dd,79cc8c13,7217a351,57b9c046,938f20b7,246362c8,6637d5f4), +S(71c80c38,b1889d4f,507132a1,87af0c91,79994b84,1b816c8a,6d130a,df1b500f,8de1f76c,100e75b5,1572da6,d08c76b2,10cdc447,cf903e0e,2b00e002,5dee0ce2), +S(2fa9ce2f,59865d10,17880d74,d31cd446,5c28ff56,50f29e6b,d74a810,977ef9ec,6c5a2073,55c0dd3a,b994778a,6bd02b87,80ba8e1a,899330ee,cd8781b7,6e15cddc), +S(96ca6bb4,bf74c748,75703386,ae02dc29,13329d9e,a5395892,df1c6f57,4a84fa4a,fcb510b6,dcfe8da5,690f8fc9,4dea8ac0,e42af209,35c33347,b088cc79,52e98b1d), +S(36a066ae,694f2645,25cba884,956ebd46,ae568acf,11664965,63cee00d,a32f2199,5d1e975a,856ebd1a,cb1fe254,101e89ab,ea089e8a,b38bbd0f,1100e914,709fd965), +S(4922879f,800234c9,63f4b572,d236843,4c4da5c8,ff741982,c3d1e341,841d1309,9b259470,24b5f4cb,97c68d18,f7f8dfca,1e57f7de,63208765,2ce15770,98f35494), +S(ee27e2b,acf95f6d,dbb5ebae,bbf181bb,43322a3d,6db87e78,14e57a3d,41b581e0,3d6a18a,daf69ae4,88ecc9d8,7d6b1bf2,c8d65544,3f4b45b4,c5a0ac51,7b1dc3ca)} +#elif (COMB_BLOCKS == 43) && (COMB_TEETH == 6) && (COMB_SPACING == 1) +{S(e3adcb1a,fe947e6e,7cc4f5a2,df78310a,b235e2c3,bcd75eba,1904de80,c8814c50,e0b27ead,c4bbb9d2,37dad580,6e366674,4a9f9c3d,e024f2bd,1edb11d2,fafc0a22), +S(612c2ec6,f0e9c4ec,c2200d23,ddca77eb,d003be35,61e52b1,890bf846,3bb53ea5,9e944d7b,dfc7a952,c1c5ee15,485d7199,dda19551,2d729628,c215a9e0,285f656a), +S(42053dc0,9f90a7f7,86feca60,d68a5c3c,789e44d2,3479aa13,2d1a427c,621373a3,b338f891,f3930ec7,738669bb,3a29ae2d,637be08a,954f2a8c,acb661af,a660bd22), +S(4d227ea1,5194ed57,10f8ea4d,a639be04,fa68ecb4,f3d2d9c9,43ec32f2,80f74051,28a94075,bda4c195,40c20493,b5391df7,166b1264,b957fef9,683cfbec,4c6e6875), +S(8ec4abf4,d4db3b0,2b0712dc,ef54a405,54b6cac9,3f88fa9d,d8cad4c0,9b94eb1e,4e37e159,517346ee,17e948c4,a17912b0,b29c303e,497cfb38,16796752,99aaf9e8), +S(ab186398,117fb83d,db8b9392,cc888fe2,50d2f604,5a0c3f89,92d8a82c,382175c0,79437224,b3b1604c,fae64902,e3030448,51ef17b8,9af02d7c,54a92c34,7fa2abda), +S(2bd09ae7,1e8d85a2,ba550bf2,9c1787a2,3d2c8985,e2ed07bd,1d39e7b9,8ef8135,ddaebb19,195bfd6c,a44ce82f,b7f3c65a,8af935ae,52e2d2fb,33cc231d,c4b16082), +S(e6da6560,c8265e7c,8f62edca,78dc739b,74bd6543,44a939cd,bac0f489,12b920af,147f5ce4,a98377cb,981dfaf0,1a1e4740,238f1c5d,ee69cfff,a54f3aeb,e53980eb), +S(7df5abfa,d6b46a37,30bd5892,69edb6fa,b70a0d31,936c0787,407d5d6,96506263,bc5cbafd,1f5fee67,1aa449ff,bacefc67,cf7c529f,86100d7c,a8160e4c,376c76d4), +S(ad672823,cfe3ac01,50038d30,81a1a109,d8629b4a,a4e26779,373ee0db,44a466d9,c288397c,f91157e6,770c401e,dc84b328,87b22534,d11e11c,c8415a4b,743fef9b), +S(72032cac,3177c280,ceb3076d,7f510405,2413706c,956ecf38,acf410ad,a12473a6,8bbaf50b,95797824,2994e6d0,a4bf6d07,149792bf,f2a74847,1095f845,bb332036), +S(36a1f78c,3bebf8c7,1fae5e29,cf08485d,d9debdae,348a20,ad84ba5d,4308fec9,842f57e2,e900d07b,eefda7e5,9dc40139,c5deefcf,11c07c42,4629c59d,593e01af), +S(5f418454,72e80d51,1c1b8bc2,b6b89224,9119ed43,5b915809,f7b26d01,8427f579,dfc29fdc,f3c65221,a6615262,cebd9a14,acba91ba,cca22ec5,d84303cc,1fe0085e), +S(5577ced2,f6bf41f9,503aa4a7,c0060fae,6d33cda6,e3c8ec55,1eaec315,bb91fedb,858ded64,6c3d6231,87c0967a,84ee5253,2b21c4e5,b329bdbb,76f6a6d4,93cdcb4b), +S(bc74b56a,c94ef36f,2b356bc5,dfd11d2e,7a371087,653ad607,dbfcfeb8,27abc502,d57d74e7,39e758ee,96a422e2,f1fa61f7,4f6308f5,71e6dca6,3b0b0103,e83cf1f3), +S(727ed91f,be4c5086,50a0d365,b28ae4aa,c9434c0,735fce3c,7b3ebb42,f4be911a,8c595547,5e627c22,6bfa855a,22ebbc56,d3d0b331,9120d8e9,13bed868,7d3bf331), +S(6286bb90,71f8887b,c4fbb3f0,a9ecb19e,fcdd2cf1,5e286da7,1bb60c9b,5ff5e644,73731ec5,ea3e537c,c6060ac5,dde716b7,2aef4117,ba747b12,1c26fc9,eddbda74), +S(3905682b,72282a78,2b8d8dba,72cf147a,de0025dc,a21521e1,ea989040,c248852b,5da3bf52,dceaa14a,a3534068,c05bb015,2cf9c722,cc80c56,cf828ace,d96fc390), +S(561a2ccd,ca12b67f,dad28ee2,c3cee78a,cf811766,9e4a2543,c81b1ca6,eb4bd16e,3b386a9d,553c2746,893477f5,17a05e99,bbc8ddf0,896249e3,85e406d6,a57b9ed9), +S(75bdfa06,6a1a42a7,50f283e8,3ec91cc0,a5b68829,6e6aa24a,28a61e33,65f378e5,c73224ec,797d6736,c1a541ab,34523d91,e1ec3754,fe7fed44,474f9cba,29f305e5), +S(e881a840,847aa2e2,2417cd3d,3e798c56,1e630290,5dff6bf7,754d9419,98d401e3,8816d775,f1555452,f624e45,710a240e,90fc5e23,7536d217,cf555349,b5e31bac), +S(1fb527e9,4e9c70e8,657de745,8b81ef9e,e3c2b4e0,128a675b,f7e28980,e18b201e,bab00a09,1145407e,693d5353,7818bd30,49e1f364,757d228,58b8aac5,416e3e78), +S(1c2bd878,b94169da,722a9de0,c4e317ce,a8802aa9,60458301,11a89d1d,9de4270c,95b7d99,bc3df31e,f0dbf17a,a09ef148,71ae6c5d,870ebe75,1f52aaad,a48dfcc5), +S(41f7fa0a,9a59513a,e221e3b8,4b91995f,c9d40eb5,d120a6d8,e663452a,d92099c8,813dbbe,92ec4b62,25d1cc5e,5820ebb7,dbdc2964,d5dd1ab3,deabceb9,5e793d32), +S(e5cbd627,89c6a843,25a24407,89b88dbb,1dc55afb,9e8296e6,bb8af7de,57a50e60,2cf01cea,ae4f4fed,46c4efd7,86ca5e4d,ef5af524,e9393d74,e9dd224c,604b9408), +S(eb3bc68c,623b1f46,ab905412,c7f2d588,fa25abb7,7a7bd782,ba9bb3aa,c05a70ae,df9f46e0,5dc1d126,2f72ef3e,8db01fbc,11915af6,4aee0c51,da1cfa,b4d15ef0), +S(5702fb8a,2602f41f,52699f68,8d4b005a,128762e1,1dfd13fd,22ea751c,cbedb2ef,a77105b3,7af534e6,46f58c3,b02543fd,9e0666c1,58051952,a61f8389,73f5847), +S(66954eca,5434263,4036fc7,fc0fe33,81f5195e,88433bc3,2c5a8a60,341e2859,d8b1b14,40e9f123,f39c8658,f9d64e7d,fe4071f0,ada879ea,42eebad6,4d37f4fc), +S(592152c3,98d6c719,636a03a6,dad64246,a5a6814a,a62c156b,ce5332f,6759b031,8d22d1e2,d93dcccc,889f3b6e,dd5e2098,2f5586d4,bac06842,d689a37b,4b845c12), +S(5699b93f,c6e1bd29,e09a328d,657a607b,4155b61a,6b5fcbed,d7c12df7,c67df8f5,c147ee87,14325497,6b2e534c,e6902748,2a5c33dc,867732a5,8338f05,73368388), +S(c62c910e,502cb615,a27c5851,2b6cc2c9,4f5742f7,6cb3d12e,c993400a,3695d413,e80c2522,898d8a22,2c4dc0b9,8dc9ce88,740fe252,5144656a,c30f978d,dba83c1f), +S(0,0,3b,78ce563f,89a0ed94,14f5aa28,ad0d96d6,795f9c63,3f3979bf,72ae8202,983dc989,aec7f2ff,2ed91bdd,69ce02fc,700ca10,e59ddf3)}, +{S(efbbec14,ff6d7e18,a8015d68,ba3ceb19,d4cbfbb8,a1bbc09c,ce755a23,e9d4b3f4,a76faa08,2b02b8a4,405573c9,5ac067f3,ab936127,24bfc14e,a27f923d,3adf0133), +S(f02f6744,a0ee7b0c,7bf0abb3,c7ec0a5a,3275d109,92be2893,7e9ef649,23fa932d,955f3630,c5621787,13e6d8f,39efee26,d91a0947,8da36db9,4ab4a89f,aaf9019a), +S(1c6f9f0f,d6ecbca1,fbcfbe9d,1f3d2476,dbd3b6ca,ac8e18a5,949b993d,8c0063e5,e3e3770e,33081dc9,5125d69d,c631450e,5494d21b,2ddf48f1,fbc3169f,3cc1eb91), +S(2062725b,739b793d,c9798397,dfc7b1a7,24ebe8f7,5e5654df,536adff1,25970841,22f3e3e5,c0201265,5e6d8e58,b8ba633d,9a9216b5,445a7f78,a2605688,4a5b6092), +S(57ffda66,e0c29448,7a1570f7,e2f5dc58,ecf9b906,5f374046,5bd1734,841785df,22ae8728,a8800436,1264c380,3beddb65,a9dee575,6f0cfa97,c01dc047,3c806def), +S(4b49fa7d,463cbb43,b14928c6,7b3a85a6,8132ad9c,427d3cc3,bba76d1a,7c9a69dc,7e7e3133,3782b30,5c7c3bd6,94e3c306,b3f9829f,86f76f08,d44b1a76,a207f2c5), +S(411a3b18,c9b638fa,38a0e811,ee370f34,5c9476db,61df1843,863d6d7f,4e803ccf,bb306f97,e97e492d,e74afcd0,a771570a,8210b51,9e61df78,4e6e97e0,ac23e109), +S(c8227510,49de1572,37afdf55,d175196d,5d315001,3670b478,a0255a4c,ebe95075,16be5950,a3f12be9,5905fb52,8d5bd93,23eb5908,211d2e8c,26204b32,556c5c45), +S(e46bdb74,8692d0fa,e6fc9f50,6685487,31d61f8a,5717fb88,4e1f7a41,70e4997e,35398e06,48bea42,cc48fa4f,2805efbe,6bead663,c054eb08,2c15ad46,c0611052), +S(d18293cb,d0902dab,e4c014e1,22969601,84aedbbf,a01526a8,6978e144,88ca794f,3a5b423e,32c1d2f4,bf754f42,9da3c9b6,84bb798c,ea73f637,1777ba77,1aae6086), +S(7b9cbbfa,a53923fd,e9f50845,3130101,3b17548a,8097433,79d3a526,d1c90c31,3fd7b71,5b6801cf,30fe22a9,8b7895d8,1b483f6e,9fdefe7e,6c59fec8,fb9786b4), +S(ab6e185c,be9ee393,5ad6278c,167396fa,aa4d936,80524d16,27ca8e93,48fce67c,7154007d,3f96ce60,d09499a5,1262c7bc,3ab5e9aa,929e0594,994a9671,8f912987), +S(56ffb418,8b9c9c13,4a110c03,8df8636a,71141ff9,8448cb79,eb6dece8,a28b65b4,1d728ed5,23ab821,ac0c40e2,b9348e27,191536c6,79a73835,8bd9b3c,b43dcafe), +S(bdba1eff,bf6af786,dca1da26,cc226102,1f95d56f,245298c0,b87a40e1,fa9a0cbc,fa18673b,41f765b8,25d13f2d,7963f1c6,b3308a14,b033fecd,e1d0d597,583440b2), +S(d9a4a7f5,5b3af93b,1c49ffa7,4f8154e8,23aa1477,16b16441,39fbc86b,2d9346ef,19ca90e7,538ac3d8,a28e1aad,5d8b1dcc,756f8a84,240e5769,a0f561d,f53289b), +S(ee5c17b2,74c78b87,9eda9341,256b1506,25582835,60a0bdcc,c8eba320,32d58638,d7d02f4a,b81215b1,7843e3c6,abb63755,c7e05d20,6c61a4f6,bb08d1b0,256409ee), +S(6953ae81,7ec599fa,5f739bef,dc4cd8b,4670eac6,912bd03a,a3fbe91a,5122ba0b,61bca3fe,36245ced,31cae918,fab6d463,50856947,f64a3be,d0eb62d6,f9f16059), +S(3bd721f7,59f7c3a9,93474472,4ffd3e34,503cbe45,fa7fa5ef,40a5a173,b8bebcea,bd7cbfbb,797034c2,d293aa64,1bf175dc,74a44dba,84b8d99b,8182d2be,6512ef2), +S(ab6e36ae,f5b7ff2f,fd2f42f5,8c408b7f,3ac84253,e1d8a43a,55cac222,678dd38e,ff0dc59e,51e504b2,9a0ba824,3ef26eb1,2446f628,78293da2,d924028c,21f57342), +S(bf1a1f6d,7f73b09d,3efbd73,eb9ea2c6,23e17911,9063489b,42fb1303,7b53fce4,236566ae,5371fc97,b5449b9c,2db32175,90e02412,b44539d3,bda7a814,3cd4a634), +S(fa0c6aa3,4c4825de,304cfece,37a20bbb,f72044e3,94cad202,c9e1edc3,b288ed57,df8e64ba,5f5e8381,4b6891b6,14dd4753,fed5f566,956a6dd,95540bdd,25c73995), +S(d2ea634d,ab56961f,52e39ba8,ebc5c150,ba9eeb1c,6178aef9,64fa97d5,e80581c6,2928f71e,a09a35b9,6fc1976c,f6cd3c1c,7d1fcea0,2142eb80,9666917d,c9a0621b), +S(827d6a36,697cb2f1,cf19e27a,ac30c06d,20d818c9,fe869309,6435f1f2,171c9b75,53237d41,3781a1df,d0d977c2,9690d488,b051dc2a,841ba226,c552cc28,12ae7caf), +S(59dafec5,4df05695,e123004d,38d9aa12,6a06c399,e5215245,5392e5e3,f1a47dd6,ff7d173d,ceda39ec,ca8d2c95,ab1658a8,6ad99618,e3fdb7cb,b07b03c5,2f96a86b), +S(5c4f5b9,2acb30ee,8c7ec4b0,ec577f41,a9502af9,a5a384dd,3386f230,3e62a830,8aea5f7,145de3a3,679c86ce,72e8b36,f3d6ac81,bb1d2043,9d719c32,ca2f8b30), +S(38add3d6,209080c8,efb65551,3d9420aa,457f06ac,d3ec84e8,db84e208,a0664ba9,ad95a891,c60f01a1,5fcddf2c,923790e2,d5596334,4d83a21c,dfe5f6bc,4c2b32b3), +S(9038876f,21c3bc14,111d5f6a,4749d07,34e40a53,7d398c68,809355f,764cf1ba,da030216,5e661aff,53367578,4a4d3447,707f14af,cf0d771a,53e8e687,b9dc29e5), +S(b07d3e8,dbbe686e,5e163725,8402cac3,e1e4f29,fdf154f7,bf008c5f,9969da10,c8b668e0,56bf8173,2d9778e2,eaa069d0,cdfbf826,47f615c3,6d0b311a,b2e14922), +S(8bc89c2,f919ed15,8885c356,844d49,890905c7,9b357322,609c4570,6ce6b514,2cec0c32,283233e9,21889013,c4a76d3e,e8d2cfa9,eed8890f,909c0b30,5736aad8), +S(308913a2,7a52d922,2bc77683,8f73f576,a4d04712,2a9b184b,5ec32ad,51b03f6c,b5a4f6a,bc0141a0,6e1cace0,993fc8a2,57ccc015,7d42e0ed,9f54a102,1701afc8), +S(3f0e80e5,74456d8f,8fa64e04,4b2eb72e,a22eb53f,e1efe3a4,43933aca,7f8cb0e3,34992828,d693436e,16f463f7,b7a2fe4c,6afedac5,59a4ac5b,34fd761c,15a0bbe0), +S(d30199d7,4fb5a22d,47b6e054,e2f378ce,dacffcb8,9904a61d,75d0dbd4,7143e65,6afc7262,f51c2a3c,4c292136,167c7f9a,e089f33c,9b127e69,fa4c00df,dbef9176)}, +{S(983e1ca0,5dd64afe,8d39e15e,43c1cf9f,6badf550,12cdea89,5fd85021,b49f173b,18200e81,d75a745,c1ecfe5a,3ead988e,4327693b,7e3c0e04,329b0c80,3d9934ba), +S(4e1200fe,d3e5048f,f6c9fe53,cdff8ef7,5d78e601,4df471fe,369f3d1e,80e46674,a62aca58,4ecf32bd,cc297b38,c1951c71,a66966f,b9ceb2ad,de411da7,d175df94), +S(82f5f27b,83d49042,63e69f48,b676c9a9,2446955,cbc18ec7,fd4346fe,37e0b0a1,e523d039,d0b8ccae,737bfc11,9b83dfd3,d6878403,862618bd,40ddfc89,9a688557), +S(a8c0fd4e,ab1f0e3a,cab37da6,58fbab3d,949ad9a4,31d6461,b2648308,35762d19,950200a9,63c3dc2e,6d2771e2,eff401d1,f9ce037e,75782943,3fd3c560,a169713a), +S(25c1b464,33068900,bff89a4,ee973937,b03c11a,5b33d16c,4f672fd4,bfaa11f9,471f1f8c,df18e73a,e12cae35,43506cf2,c57894a8,f633ad4c,e1c5330f,eae42b43), +S(497e56ce,8793bfec,4dc6f972,dbaf4a72,aa5d8412,3bcac5d4,2aa9baf8,ccfd6723,1d3d028e,b70105b6,eae66785,5dfe7e0b,7c0a6b3a,b069a475,bd913aa9,c29cf426), +S(68a285b0,d30c2dbb,b543e480,f66824b1,69aa339f,7e2282c1,5dc60f50,8e3f2fa6,87529a0e,1d53588d,21064447,99a8fee8,ffc791a7,cacc9e26,f7a7d94b,25e74cdf), +S(721c92ae,931712f6,15f4d7c,498dda23,e1029dbc,944cea16,9442b22e,d755a100,7ef052e6,a0d2646c,a5dff39f,3b2a1019,de43e3b2,5e51913f,d636281d,cee74a85), +S(aae8418f,1b124d79,ad15f773,1bdcea1b,453493ad,4cb0cd6b,ee5c9a8e,34335ba3,c2558bb1,4a7addab,62d1f308,1a9e6fd5,92a06976,3be877d2,af9ae1e8,b510d98c), +S(b6a06052,b492d74,c68640de,8bd3251d,fbaaeb0,ce1eb997,f2127ead,4bd0b81,7bb4269c,4a9ece8b,e8ea2f0f,d663a193,2a571249,2814eb73,4ae1493a,6a97b39a), +S(42fbe048,38761203,11e43178,6af555ed,d7bea551,d4d5aa18,afaa4c05,2c6d0c19,9ba562c0,a4cdc664,87caf55c,291d8246,65c29f32,2a56360e,90138b06,f109d83b), +S(9d6dcb88,b378e7bd,233464e0,25e97bf9,97768e29,6e4aac31,301fa1c8,bfbcc27b,f434ea54,3f7269cb,1ae1279d,4178dd25,bbc337ad,2f0d5141,610dc061,80daa8c0), +S(fa6fa5c8,1e6713d8,90cd6f29,cc8b7d03,c5f8f2d5,88963652,7c199f6e,8f98e060,726194a,2a5da1b5,85eba1a5,5e06ce36,5aebb89d,ba5f7971,db3c1571,c848c5f9), +S(809167d6,85e432c7,372dc111,8573e620,d9ce7e9b,c3ebc15b,ea7e866a,3a8addf4,bf0cb694,f00fd1b4,b62119b3,9dd6c88a,22ef1fed,a94ac0a0,9cf33225,9298b968), +S(99d28ee0,962c1bd2,fa63109d,f5485653,964059df,bd514206,24117eb4,e582ad46,8cbdbb66,4ee209b3,419c0b80,36affa24,85cdfbc6,e6644429,33908490,f6f6353e), +S(559d0617,e0860cd1,87f1c68,e9a9951b,fef7dba,3a67594a,eade6e25,e2df593f,194595af,721e3b26,786fc25a,cf5b2d77,1fe00649,b0cc4938,7168a9ea,1fd2947e), +S(ab9a7228,f0d533a3,4a95af3a,51021b55,bb324229,8d101a66,eb362c97,eac48b02,80a6d111,e451eb09,cbebdd5,a3ce4fdb,42b3665,f8974df8,912221b0,fc7db6af), +S(42c6680d,18b0f528,274c2eb5,422e4731,560ea862,adcc4419,68bb5f3a,5bbfcf16,c8961934,e5bd6e7d,d64d4b1d,f7867c7b,978d182e,48315ae4,3fe2e082,a9455792), +S(e8bc0f9a,c3687bb,69627de1,df71fb34,21e0252a,e33d15da,3039a200,43ec3374,15de9e9e,2ac74839,5116ef76,1267300d,78c2e583,9286e6b6,366c8a6a,540036cf), +S(604ee928,4ea1c8a9,a0a75bf7,be3a5c02,8f52d71,b5fb6340,53401e8d,8f5d3d6,43bc16af,5875b25d,8e2427b3,3913f6e0,bda886a7,52a3b812,f8f191cf,f7bee54b), +S(7f589067,5b771ce,ac754412,a9984352,4f2a4a6b,a5cecae8,5106bb81,f7e4d9dd,a74f2eee,584696c6,88157a3f,fc27085c,6445c7eb,e363c6ed,7a1f5902,63de2024), +S(80aa63b3,1fdd0d2d,ef602bab,dd88a15,71abd052,270988a4,63abe269,fc489fcb,9a145d0f,6dcf0edb,a4873287,a2f221dc,4be613df,f70f7755,f28879a,6e7d9978), +S(ca9793bd,796ae0c1,d778f3,6445bb8b,aa50d859,4be28fe0,ea1e2d16,30972503,7304af4,4c56106e,f0064436,c09b411b,926c4c56,cd82577f,f8c01ab9,9f7c4c6), +S(4cca305c,baf6615e,8cdc8a58,f3a9e52e,97ee20f3,ef080793,ce105a03,a1f1d3d2,637ea84c,9578321b,b5dcc239,7f6206bd,abdfff2a,128d3645,47d474f4,8a8ae493), +S(cb7813b1,a7227a24,cc53b458,1985592a,a9077113,28fb2a05,1d4972a2,3127a913,208b7263,f8f8193b,76dbfb1a,6c4f9264,dd12f63f,e852aa8f,8375fd00,eef83482), +S(d61676be,a11dd1a5,79164cfb,b2488e54,555d7d55,23ddc8a5,454c49e,4a86d8ea,1875b5d5,6db950bc,60b1eeb8,17a94af6,5a19f690,d48aacb0,e483ad52,61995cd9), +S(7142872,6f59c2c8,b398b22f,2ab5c3ca,e803a34c,ab580947,9b7b4d83,1f8e8c0d,3702510e,324c0911,b3154c61,e064ba23,68eff5fe,6f05353a,34980ec1,87ab9ad), +S(72a73d15,9cf7f79b,950971b7,1c66f362,54d13783,c5ef67b8,4da61dcd,4cf432aa,77d711e5,c1793c36,eabf9b86,bf3a692d,234f02db,e4d5854f,5deef926,b9818d2f), +S(ab3b2de,c0a8f23a,a7d3b9d2,88870969,2e45ef47,37a792a5,d65af92b,e58f6347,ac4e4ac9,1bbb57cc,1437e612,e4d4ce37,3d4f0286,5905b621,56826d80,895cb48f), +S(fe5efdb4,32715fed,f9bbb16f,d65ddf6,4ce9bb13,14a491c3,3bfedeba,cb4704ef,e5dc36f5,5fac6974,eaf9d8e4,232a22c3,8aacc6b9,1225a97c,2e695940,ec795c21), +S(5f94851c,a4149e75,e44a0d8,17e81c75,132eb242,c96ae41f,53f30ab9,c8c828a,d9473c47,505e0117,1a0f8682,777d0ca1,7399208a,b03974fb,4014f5bf,c8cbaeaf), +S(5d1bdb4e,a172fa79,fce4cc29,83d8f8d9,fc318b85,f423de0d,edcb6306,9b920471,d7bc7d98,86c861d1,86b4466b,c75dd9a9,8614e166,693a9184,8fccf998,847cb2c)}, +{S(8cf1437b,d87e7faf,550fcbe8,81b0741c,ae0b48e6,e0b3c3d9,9b1b1924,2a925a26,17b40146,c313b1c5,3bdf52e0,efebda45,80d86783,910996fb,8b2d0acf,9bd253a8), +S(fedc65f0,d622743c,53fa6172,e68d983c,2c9b8fbc,58943f48,ad06a852,c98403e1,ca5dcf28,1a2f20d1,5fed06db,89dfd290,8c9d32a,cf40fe6,817e861f,7f168ea9), +S(846c6a48,e771b90,4ae1e8d9,d3daf1ff,d1cb4c88,bbd1de98,454bc817,954654f0,5a4947a5,8a0ab994,3cd0a90,6c1d1f0c,3fb73d2a,49b9c0d1,a9bd35b2,99475dd7), +S(4998795e,a7d80937,e4abee13,6c14585b,40b2dbbb,3fd3c80f,c8c61b45,cd1d59e8,8c817eab,e210398b,59b31660,267c099,baf29e4c,894e09d9,a50894b4,ebbe97f6), +S(76c29921,eb3f3d12,5c11b906,3d1ac276,a205804b,b3e7484b,72ae0483,e4b3c517,48d8a8a5,fe658e1a,4d736bd1,8f07b5ad,28cbb775,d9388e7c,4fecd837,c8eb964e), +S(78de8fb2,b15ff39a,487135a2,636bdcea,57bb3a14,efc329f5,a06bcefa,7ffeaf09,a55c9e98,5e1f529b,ba7ccb6d,3a5c00ce,28cb14f3,e9012d5f,9f66d8cd,5e45113d), +S(71fb3464,b0600c08,7fe70906,2792a676,27830e50,a0bfb473,ec909530,30799282,fe036726,cb928a8a,8affed30,38977377,2a016e7b,1dbde8f3,6db810d7,cd423f36), +S(f1f23de6,bf779cfc,d864dbc7,b46009cd,d2306b1d,cd0de2c3,65f3006e,565d9e21,84f5a011,74ff8e7c,c9a98f52,3f2980eb,4b013695,f6239016,9cc5a1d2,acd8193), +S(f18909a5,a5db0daa,ece22ac7,12ae04ee,53484793,6fd8355f,9ff5ffcc,ab6ca78d,6306f08d,13ce2b0c,b60b3b8a,b0bd5f46,b3ef2a83,7edce51f,2cb5ce41,79f46344), +S(7598d96b,189f476c,bcb1992d,9a38adcf,9d1b6ce9,6c87058e,24584514,a0df4770,7f288be1,b82da02c,a37f655b,d23643ba,bf3d5cff,3b6c2726,9ece7409,ed78bcd6), +S(1e44193e,8223b57d,8fc68641,924cded8,3a04d806,cf9dc18b,7af06010,4e6216eb,45ea3ada,fd726fbe,2b1d6fd1,858ccc2d,57b237bb,bc2965ca,ebcd1b63,53c2f2e1), +S(80954b78,4872286,8fe38891,2d76dfba,d676b4e7,7901e559,dd5983e4,e908f13b,6fe564cd,a0966639,e0237f29,46e92d29,4aee124f,cb33da53,974e8882,b0acf22f), +S(6dd8a9a9,ad7196c1,3c36464a,5cb9fb41,aad8b0cc,423b99fa,a281c5d5,a6ce6ead,79a51469,8767adcf,ed287aa4,914eedc5,8382af71,5485c2aa,c3a77c4,efe2aafe), +S(1895cc13,f99534a1,187a3d65,d1480669,f0d0c0bf,b42b2a9f,1a6392d8,7e1d2c6e,b7905afa,c0eb9b66,51de3583,2cfb9ac7,ae8d2355,1e334d59,32909de9,ed400a0c), +S(f1efcb8a,86f94997,65b38fa5,8edced68,7737b8e9,49dc05f2,190b359d,9ed2c0a9,79b2c874,22de216b,904572b7,a39f320d,f53e392,8dd8e533,a1a28d93,fdd4945e), +S(2944af80,c207d107,ce89fb90,ea6daa2a,c65c1360,503c36c5,ad798333,90432ce4,44b53d27,fd6730f2,33b8c29,f1256136,c637740,86e001a7,60bc1ff0,f8b6211a), +S(938a1dff,117540c8,f6ee7df6,2d3c2cf3,31b38593,131527c3,9804c6d9,874752fb,4683d049,f096bc21,2e0dc20,a8600b8a,a02133d5,d0ae8d6c,b26e4694,ed6f2aa9), +S(b1b3b2c9,54d1fb6e,98fcf939,efc18803,2f693989,81f19c32,f5e55b30,1f59eb16,423a6754,1a29bb01,95adfe15,c1df1c9d,81394e96,2bd1926c,cc789f5b,eef9ec29), +S(52e23f2b,19048d43,b1725695,e3bdfc7a,f4ebd2bf,594f013b,b80d6d0c,ec10632f,258a6236,67090b8a,73881e39,746906f8,eabb6683,4bc3473e,1c6fa8b6,54641cdc), +S(5799a463,cc817bfa,26bcc543,efe0e00b,ca9d2320,1989e854,620fc9b1,ffc14afe,645238d1,8c69338f,9c9395fa,5ef7c9b0,f62b7dc9,c4c6b9e,c545c850,95b6b7ad), +S(1c493b52,3f5a4467,6268220a,58246228,608a603d,f6edb1c9,1a90b060,70b16069,8d311a45,5af92640,e9fe08f0,2981db57,3b22bf4,8fd5e76f,31c175be,23e24fd4), +S(84f5a9c9,cda291c0,71aa9f8d,d7af5a8b,f2ee0dda,fb9139ed,fee08f0f,3f9cec2,df381327,16527be1,d86991a9,bc28966a,c3c6c081,4fc0def8,85e5d160,f59f4458), +S(712c18a0,ae87e7e,87856c8b,ff6e3f6d,996ae157,970e754f,bba80bee,421fcde7,b2788ba,e69d34ba,eb5dfd62,830396df,3b8934a9,551c6070,ae8203c,ccc50ac9), +S(a5104184,ee996a34,7122a460,cd2eba5a,11d04aaa,a47d2ede,25ea13fa,41ee01f4,f4b5f2b3,f7ec9061,7ab5f3cb,763233d0,afc8d4bf,fc535076,5dc5fd41,cc547ffc), +S(79383075,a46a8eb,559ac95e,7dbeb9ee,51b6e906,27e55b9b,922473fd,5f2eb63a,243f56e9,84fd2673,58754a67,2bac56a7,9ae71a5d,68150740,8eaf8c2d,b55ef1a0), +S(2b22635f,b83ab0d4,9b82edfa,a54d6234,8d3bee6f,edbe3315,9470b18a,96f97821,41d9f3a9,52f17182,ccf02725,b58ebd7a,1f37235,1fbb8f2c,15403890,e8b25b82), +S(272fdefe,148ef7e6,957fb8a1,4a07f0ad,b17c27ea,49532547,5114c1f4,76170a0,789b8eb,5846e50b,d489bf66,cebd873f,7cf05619,3674e7d7,147ea691,6a9b8451), +S(2c2da4c0,8a6e73c0,2efd6e7d,13006135,f09990a1,4c0a0eac,1f286108,f4a2a0e0,8011a521,d7fa0ab2,75765bcf,50dba163,9e89c9,300e8a25,31942cc3,fdade63d), +S(19a9e5f,1c4cae30,797a98db,a24051a4,38ea755c,7b062094,a34ed6e8,8a8ff2cf,e199e398,157a50a1,56f9d6d,afed48cf,f3181411,77b792ca,c5881898,24f1b8dd), +S(f7a4be3d,fc6579fb,43c5a960,890893a,f4026165,ed9e3ab2,e6929378,b63968b6,29221093,17dc39ea,de2d6fcf,c735ad2d,668fd047,2eefefa1,b6b225cc,2f3cb3ad), +S(e5380fe8,575f26ad,b7924ae0,d58138d2,68112776,b11bd34b,3eb5e196,33f0e9aa,4680278c,6f784be2,a496ec9c,6db371fe,9046b1a2,b97ce71,3b45bec8,bf7d8a20), +S(4c1b9866,ed9a7e9b,553973c6,c93b02bf,b62fb01,2edfb59d,d2712a5c,af92c541,3e086d2c,df4175f0,804348ac,31a91963,39ad1528,1bc14e52,8d3b0c01,39701c0f)}, +{S(5a13b9b2,5aa6944,1b0b5fb7,f7665dda,95aff48,e3250b4e,34cf8e28,87406c1c,245f250d,78fd66ef,24745e09,f067f16d,d400c387,66d2a1a9,af51e84f,733d0ba2), +S(617b41c6,8534072f,2302290a,4956171e,902634bb,4356bd27,ab83a377,13d8ef6,c867779b,97383817,dfd0971f,64c09c71,7c468a5d,e1bb8ed0,feb98f5a,305d8e6a), +S(ac118ae,ed46b08b,488202f6,96d9469a,e9af3cc7,ddc8eb71,44903a3c,ee43c654,f992fcea,8268ca6b,79f5ce69,c87dcfa8,42ea0345,d7c85a5e,a1b89f1c,9d0217aa), +S(741dc47d,2e0d1424,3f2bd96d,9033d8c2,9008c1e3,66bfb5a1,1434f1cb,3d85310f,c3135d44,e86f574c,266f97d0,f0279dc7,52aee0ab,8e3ed78b,ee0fc646,c133000e), +S(2e973138,f6cea9c0,5adfbb5f,49a7b928,5ae0c15d,120a8b1f,2d0c76ea,1fdcc7e,a05bc93e,68bc82da,7a7c7e38,95a647d8,7f724f20,c5b312b,738c6dee,90de771a), +S(9d938d6a,cf56104b,5522351a,3c424e01,e4d21c33,771ca94c,f55357fc,fe51f91e,881d05fd,4658b08b,edf87396,be3fbb95,ec9f371d,79ff4586,6ddc803b,65ae763f), +S(37a8ed2b,4085961b,84645ad9,8f2c901d,fe9a9a8b,4de8fc89,2cfbca5,c8909835,b1bdacde,94fdc3a8,78cd0eac,f8865d64,77e2cff5,efef834,97b93835,5b7b401a), +S(da1ba954,899cb05,dae6fea2,dc8ddd7c,5ef9e91c,3455838c,a49d2858,ec217d66,14051c3a,12332d70,f8ad8ffa,567765fb,def69640,4291b81e,d3978bf4,51f788a0), +S(92d2ef44,5a10dbc6,73f8c1e6,af093596,13bd1e3,c1b24705,bad2b3de,e8f11b81,adfed916,800d3e94,91a42c59,dd72e3ea,57d47081,b9afe668,f853cec2,c72cbab7), +S(e62208bd,52620df8,91b3ddbf,e6cf0641,6059ce50,be3b00ce,14e7a53,6d1acb07,1fb71455,53b2f4c,431fd86f,c72d51af,5e2edb41,dd3f69a1,9a971371,d9679dc5), +S(191fec47,a48ee268,35ed37ff,6758a80a,532f7011,ab099048,b024efbf,cde1d0ab,47b6389,b3f5534d,a632924d,5b65918d,f65c9c2a,2904ee95,4f24aeb8,c6a02557), +S(60c822fe,a74d52b7,d5203720,b2c2a361,b7628aea,d2a683bd,80655636,bed15714,5d9a9c0,120211b2,e8285b77,8f8d4bc0,b06240d9,22944248,e1cfce73,826bb67d), +S(f602da1c,788ea65b,cc339a38,c353bc08,1c43c2f2,6e05ea6d,ab52648f,890c9101,21468929,89348f8c,67cfdeda,31ef3429,23b5a450,9fbe9a49,f011d42e,57f998e6), +S(756240c0,5274101b,3059d23c,76d9ecdf,33e1312b,7a36af,ea21e6a6,c52cdbb5,ab24e853,900c7ff1,3e4f813d,a2acdd5f,53ce1710,b785ffbd,e74494ab,43e583ee), +S(8e815b45,7adf482e,e30e475a,4949e5ae,c7ff494a,a918f07f,c39441e2,360d112c,a966f04,2dd9edb9,436b0005,7473aa66,dd19b4d2,cbb3bd95,932ba98e,f1a1f406), +S(216d5970,36c661f2,cf6122c0,a136cc33,9660306f,1c190ee5,5f3bf438,e7189261,5bd23797,c6753eee,6fb934bf,dc897ec1,25b31c9b,9e797ef1,56d8cdda,2ec1d128), +S(a30ed06e,ce34d29,a92fdeef,6954b5ed,4065d592,3af09be4,f0ad4a73,e7c24346,f6aea418,6b38c188,b84fb6f4,2b6559be,f52dc13e,b7ddeccb,6e85a76a,8d4efeaa), +S(aa42d20d,8acf7c47,fe40ac15,3fcaf1ac,6c4ecc37,dfa39c39,fe5c7657,c78444d5,bc3becdf,464ce930,e42a05b2,c52d3589,fd45ff37,c7d1767e,f8462811,89634059), +S(7585f8cb,4812e306,de02393c,c06e9871,1953133c,bcb67ec5,c6a79228,69124ff5,c242853d,1a2c1c9,a1cd1b5b,364888fd,28bb23c1,2b0e169,67961b3,e7c8b95b), +S(b096a1aa,fb969483,185ba1fb,a5fa3f3a,d1da87dc,a10344a4,d74ef471,45cc45ce,edbc9490,23801861,44ee39a5,7bdec0a,230df57a,72649e04,c4c99883,a147f0f), +S(7034d8cf,df226df1,6b310628,35dc02c9,f3e3f91a,635ad93c,46be292d,56c0ec2d,f783b6e8,29447cf2,32769a13,7ff33f82,f9fb166a,aec8c3ad,1679c48,c1a913a0), +S(9f88b01b,b936defd,f61156a,b55ca290,cf282a2f,3718b0cc,2d32dd3c,49248b4f,c24ebc35,27052f77,41087cb0,e772ce12,1035042e,603f1301,e19cee0d,30029230), +S(14443190,51f05d23,343367e9,6add133d,fcb63209,2f218847,59ad81ba,c65e7445,745216d2,d11f2556,7e3b224b,6dce478c,bb988b96,a1240093,964e4ba6,f3b15554), +S(54aa2e02,3038fd83,f17a633f,d9ab441f,e039dd0c,57f9368,3da013f1,751c6813,f4d163ac,a9af3e08,c009b44c,b358ebaf,31aacc5e,e0bdb917,d1b4df5,420d2d34), +S(fd44e742,b04ca4df,693e3109,3ec52ad6,1f67264e,100618e5,88d638d6,d96efa41,7ac09cb1,2134a246,b17ce054,b38f3bb7,7d794f9b,2fca3786,a0ba665d,3eb0f14e), +S(f662f214,10cf6e6b,7f79fca8,7ea3925,6760d83,17478419,ff4671f0,2bd2ab6c,be4ad0b7,a56c87a4,8fbc166b,da8473ba,6518385d,bd004b5d,c85126bf,7b9309bb), +S(520e2755,1cd804d2,67f9b4ca,b3986952,612bb099,cbd3f3be,a54f505e,bba4db64,e3c75cd2,c831c539,b095ac18,3bb13a72,ba7cb152,5b9c214c,288509a3,98a9cc3b), +S(4d16fa3,2d74de13,111b3f22,c4133ea5,377921ba,e54af1d,666d6e9f,b01e117d,a63bdf75,78d73f03,75aed657,fbb8675,67230c3f,868f2cf7,b7275ec8,b02ac46f), +S(ab928c61,ad1c2f68,905b9e95,3c2629ad,9bb7c8cf,ad9f5a4b,35b35fad,69a92568,bf39ec2f,6c1ae222,ff383375,6bd83882,c05be6ae,692539a4,5124b972,e72159ee), +S(8731aaa4,93580732,66b96577,7bc24a46,17fb8363,51c5ad8f,c8bc053e,802dd07d,36957f16,1020430f,69a3b1c3,1a6df993,d9ca8e2a,8f487b7f,b2ccd44c,7f528ce9), +S(3514d41e,8b9388e4,33d1155c,c777c398,22ab36c6,3c2aaad7,ce674831,21231d11,7657cdaf,e9fe8147,10bb2ee1,a97c6100,6c7b0ce2,f5086141,ac2904be,1c7a9e3a), +S(9bb8a13,2dcad2f2,c8731a0b,37cbcafd,b3b2dd82,4f23cd3e,7f64eae,9ad1b1f7,6ba44d4d,50111c46,490622d7,b079c17a,f0ab57bf,b8ad2ac,9becf9d7,3c7edfaf)}, +{S(e60e88f1,dc24f079,f835b687,778307af,83446e,71809086,e6dac0db,9f191de4,25a0b86e,ff05c849,d79a176,1a634d82,29d2a759,fbd003c,b6ca4147,85726362), +S(55a5e6cd,c9e11103,749d469,dae84a88,9e744dd5,d9309762,15050a83,fef66fe,31278ace,a971a41,e2f9fb16,8e80ec03,37009cd5,b0a49938,c28c902c,a7c71fd2), +S(5f25326d,e99a7c5a,d81bf2ea,61a9195d,48832bfa,8caa9777,53e483f2,b5a62580,40b69a1b,baa2d0d1,5cb78a3d,3d184c08,5b4c16d2,90751ec9,bf3eb3c1,d3ec2ab5), +S(1a32cc7a,f88976b6,cbc89865,89e685ac,49381a29,1579bd2a,13f9488,c0333d19,4667a3e2,2048f781,11f009ae,5d7b1b97,850a3a5b,86f77880,b128c8c6,a9720acc), +S(1d78e74c,66247be9,352c9797,5fbc1299,743f9c74,68c64d1,f2d8affd,1b098769,37adf553,fa2a11e2,6913ab02,e59c4f2a,48133fe7,d9aa3c24,a76e9af9,48a29d8f), +S(8bb6f83f,6be5c2e2,b2bb265a,9bb3c931,bd5cce6a,48efccdf,daa040da,535dbc86,eb96a982,23278b81,6284fee7,b5b8a121,7350cdba,d56b6078,89602bba,bc003481), +S(a9f19ca8,1d2ebafc,4bb5d881,76bce19a,d2d2564e,185f905b,8f9eeca5,d6b12d6b,ab23a468,3279a9f8,e2e8f880,e0accbba,844bd4e9,4d3e4b43,74db2b55,d998771e), +S(19680305,c887467a,c3bfe44a,dbe65431,7323d8e5,62271e25,1a794b78,618befcc,48e9303a,3d6371f7,cf0a904c,cf16f606,b0007583,87ae0952,c6119521,dde25532), +S(18b3bd03,ed4696c4,7c3f896e,5df7481d,6f19a5ef,53d62ff8,2948f1b2,154175c,85fb04fd,6573a19f,2c136753,a1ca2585,d39dd64e,6e6e3fa5,fba362b4,ae9dad36), +S(38e3bee1,3cc3e18,a57aef97,4ffee58a,a392c311,14ac8baa,1376b56d,f8ac017e,8596c7f9,8abf3e44,4ab5491b,fe659619,f6defb58,f48e2b7b,57842193,cd48fb5c), +S(dba5da08,8cd17c33,3e892bcc,46261694,d2ff3a22,2a26f92c,17c5e1e2,797b235f,ebc15bfc,5729e986,85a19afb,d7f9a219,e60d2784,e9b283cd,3697f782,630fe222), +S(60456426,caea7fc4,48970eea,fab9c632,3e66fcee,50f92630,7b130937,25b85ee8,dd22df89,c5dae339,49459593,1433f2f6,5f719379,68e56f92,a38d1290,17881924), +S(f1ceac82,15670212,279f36e,f0c8ce28,3a192f66,460e4875,d90b2f51,a38f5712,ec11f026,c76c271e,fabd7d55,c8488d99,3298f6ff,c05ad4a1,26be9447,7d878b9e), +S(2c2fb5de,5dea249a,7bf6b196,8bdec8d6,1838da2c,12147045,18d6494,f09e50e,6c0d020a,d6bfd730,5ee73634,e939ac89,ca2b7d4f,dcbe760c,2d14ade2,659a5b8c), +S(2858ea8c,d40ce264,3c9a305,c0e2c758,af5b0b4d,5c57ed21,60cf7ec4,154ffdc2,33586bf,a61a3cde,4f402bea,123c69e2,2410c0e,590a71d8,9a1e8130,85cbb579), +S(2749a250,4e7cefa3,a3647088,6bec22fa,339fec0d,ec63c02,19e6af39,7fdec3e0,d3415104,a9070af8,b61acdf0,77954d37,57fcf742,a006129a,5c0d3529,3aa95407), +S(8edf3ad8,39e661b5,f7f16a85,dce3caf5,d571acf4,d0c6195c,53b618e,5311ac65,fca0efba,35a14d3a,9944367e,db4ac982,7dcb7aa0,12438c5b,aa5627c4,c4a15ed1), +S(dbb92358,8b083294,5d6d3b62,9cced57d,7085d3e2,d0890bde,95d80400,98c22745,42816661,5515429a,aa023737,5fb77804,624546f2,1f0a34ac,1ed4e4ee,dceddccd), +S(aaca9896,6196ce2,e13df3c7,d058a5e5,10566df0,5fefc04e,51f9dd,85a4349d,be389d02,789548e0,aaf67c57,3b91b389,c7e6ed80,ca3e637a,2a147262,80cd5620), +S(104804ab,e621b098,61fc540f,f4d6be9a,750e3cfb,706170db,e34c06ed,e0a431ea,14b700ed,a465915a,eff84ab9,fa568535,f63e4f44,1387ab4b,d841072d,97739071), +S(b2215070,a8ea71f9,b71f1a73,d6ce366,c322b8ac,4d135b3d,ccea68e5,a51f1c0f,9e415cce,3bcc4e62,6f3c8caf,fd632eea,862a046e,bb45e8bc,84fc05a7,a4b87e00), +S(600c6e28,be5ebd28,d83e6c86,bbbd9b0b,aca22006,42234634,6124133f,3348e6f7,822b1816,79e253db,a47ddd76,c0023991,5c0c0206,8f422415,94ac38b8,ff7994fc), +S(f8b9b45f,c6298dc7,13355bf1,3ee33ca9,c4c1aace,c09776e2,56b3746d,ccae0dc,bf4b7f96,1844aa2c,6ed8c8a5,6626386d,174e77fb,98c0c23e,e2b6de90,3f1f79cd), +S(63987b18,67fe5a17,333eef28,5385a0a6,576163e,2c74cd00,ba87b6fc,96a57faa,23ce6655,51d48ca3,c702a5be,87a05d98,b5aa1097,dd5877e8,11e32d76,4873e6cc), +S(2eb06c4f,5ea9ad2b,124a1202,cb13c1ae,aec4394f,4af7c96,d6a9ecba,540ee04d,b96173dc,77b46ef0,6f4141ec,96ce8d1,4adfcfde,f0bd7ea2,479ba6d7,522d037f), +S(5db39904,153002b3,1498bb01,16efd0b5,838e3495,62d9428c,912987f1,3aae5ae,2115b896,479d0d0f,75ffcb54,ff9e3f73,d1356ff1,4b14292c,6bfe8d54,e9e08861), +S(c0f14110,7f324ffc,f3d3e6c,78d5a628,6000d57d,7e85bc7c,fda15f75,79cef3ed,6eb03650,c8142b12,b330b96b,81214a4d,d01b068a,74827611,53d2c52e,e1315ce5), +S(7e3d1510,ed767345,bbb3515b,6f9819bf,33ed9dea,fab35d01,a7284cc2,371b0e66,4c6b3aca,5159023b,d43ec0b2,57e77e87,e5a6b745,178bb017,9960c89,361fd97), +S(f98b5dbc,3e54c227,b002f458,94850ff4,3b15b2d6,1607851c,50d1e4d1,8b20907d,1d2af742,b0b5ec05,bd6c648f,94563361,be03261f,da56f1ca,7caece63,a336d580), +S(188ef3bf,ab103784,37e1859a,7d53e899,6124c395,ca422c05,d6b21b3c,efc76ac1,19036685,fad04566,2ffa04e7,30c671c7,1b299217,c389c78a,cae9fcd4,ad70fb73), +S(b89070ae,96ead4dc,49be16f6,a1a30bc2,41b4e98b,c18d0227,4c9d9d87,dcbf00eb,90db373d,375d2770,b8dd6b1b,3e3b5899,34f274f9,49469598,e480e431,e4f195e1), +S(381c4ad7,a7a97bfd,a61c6031,c118495f,c4ea4bc0,8f6766d6,76bee908,47d297fd,6c950ac4,dc71111b,70c1a058,f66ea133,fbaefcd,246c63ff,6c531ce6,82b6bc6a)}, +{S(704a26e5,19071bb0,24eb2a16,48b66a6e,157b07a5,52fc4258,381f7d02,e8fd9b9e,d169ea55,8650aa3b,ce52c645,278422a3,69326e74,46039381,920f5857,fa3492fa), +S(705063f5,e481735,60afe9dd,5b2beeda,d6e46391,75ad7fb6,f73350df,51edf53c,32290956,61cacec9,472dd014,bda52364,3399d7cd,9ce2bb31,a5b23590,22c6ee5c), +S(972e7585,f8b1725f,4a7d18e7,77939aa6,3600a7b,a07c4d94,5da9511e,889473f5,aae4382a,49b4c97a,bc3edb7d,26ba7bad,16752047,dc99b434,f306c673,2851310b), +S(260530bb,e338f4a9,71930b12,4f18c82d,e33f22d7,32de9375,81e2b0d5,15e59d97,77c66c36,d6b09205,8ade9c0c,a311b60,a705c8c8,73fd2d4,8e6327cb,71eefd4a), +S(15464351,d21d2513,f792ee32,aca3eca7,a52cdaaf,9862172a,e7224a03,804581dd,d9ee19f4,502f1c44,f656ad4e,add6adbb,d8a04f5e,5344b554,894721eb,8e3e2285), +S(4fcc68a3,caf3ff91,dcce9770,11ad5157,6c844132,321791ca,a652593f,6cafcd04,e8db3aea,a35371bf,9700a9bf,b85e90b3,93cc088,9cd655e3,fb18635b,49fb59eb), +S(301c65ad,567952dc,6b39134e,c361030b,3f5203ed,da89784b,225548ec,45c75eee,95e2c0bc,7b4a7cde,8ce3dace,a691bafb,f78fb03f,3170b347,ee807f42,6b947560), +S(96ca5edd,8047ec6f,b5f8c37c,a734533d,13f0e6e7,f55d28,b8b10b5,121f4abe,1a21f1ba,f6a2e336,247f6ee0,88cca9ff,816b0667,3badc241,d9ed00fc,d2070f1f), +S(c94633f5,783c4e68,12143fc4,6e670978,8e8a526,819afea9,404dfa00,df1bd839,874f8760,33dba9,de463f86,b597219a,c1ea37f3,970bdadf,97c96c48,feec4ec5), +S(963146d4,5bdaa05a,b5115ac2,3ee862a0,2305ba9c,75003f4e,ab838f7,e9adcdfa,d75766de,299e5cf3,c8796234,5db9866c,cf011c5c,f108a794,5642a6b9,dd33eb0f), +S(dde8c870,ec4e9890,2a820a7b,c5784034,19ac261e,de5afd0b,82b8c5a0,7c2863df,e7833936,50d4af7,427158e4,6c753ac1,a5143c9b,c09de97b,3b27065,6f622b82), +S(546c6b00,c5e34a8c,4cc7255c,2edea33,d9f77e7a,c67ee629,bbdf1879,4622265e,5ae149da,f65aba8d,e214fa63,be9bbf11,3dd3c220,12d206bd,d56026e7,4a019897), +S(4340c850,d91b63fd,bdaf41bc,f8d8c010,d3f30eb5,79eeefc9,e67c127a,33324071,dd66033e,eb5ae8b3,3c47a940,2482bcdd,4db5c8e,dda3b422,35627434,dc3bad1f), +S(f796431f,679d9cb5,77bce62d,236d1fe9,b5042a83,fdd1cf94,1a2e00c0,5a261d11,718fffe7,68aa2591,d3fb1fd6,1a00537,3b529f9d,f9c27f79,31ad0df9,9aa74859), +S(f3d17ae9,d5b4cf41,27423894,916318bc,adfb5a9a,6c2ca219,1b918e43,eb5ed129,9da6d033,49c64d79,7ad09a33,bf71cf87,8e0ae6a7,9fa7bc3f,1451126,18415960), +S(23899a73,a4b52d27,29ab52a8,370ceef8,4c7684c,cd535f4a,ec360eab,cfa5a787,f1bcde3c,5c4740c7,37b066b3,8a1a88fa,c43357f7,f3fa23a7,b00815a3,85336320), +S(5805914f,5418971b,106305cf,c397dc12,f63a3b2d,8b451e5d,c1b60c2e,3d9e9208,616e2764,67a5f1b6,46279ee9,6e8645f3,76a80192,31e17a5,c92e26ec,1b76e62b), +S(85ffc326,1991848b,5e918c4a,53f291a8,31796b52,d56a5c38,8bebe625,d78cd07e,95fd6f12,7b155e6f,806c089f,3f5abe95,344e9014,e2c72fdb,e720bb8a,93d864a6), +S(6f1a57d0,6566bf81,f4b16329,19f477ef,aab4f829,e29dda4b,27627b96,1cbfe3eb,de1e8359,7ff20c63,3d28b909,caef273a,a57898f1,a797fd91,e00e2e7,da1872f4), +S(3d28eba0,4d0ae2f6,208adc71,cd6af3b0,e208860c,722903ab,e106feb0,af3185e9,cf8bad18,40d3d2b4,abfb5b28,b50702dc,512527d9,5bcd403d,9713ec7b,ef1dda13), +S(46511979,2b845113,1b32663e,baa14c4,20a5408c,1f53afb2,43cd496e,c4b18118,40bd602b,d740096e,842b40fd,8304ee73,842b074e,415d5ac,c5e2243,28b241f9), +S(393a8bb8,7ffe4265,51678524,8ac940c6,4aa70e71,512ebbc2,3485596c,a6d9da5,25773032,d2c1f80b,3954715a,6e4132a1,74b4468e,658f6cc,4d5f5d63,d458980b), +S(aeb37eed,35274696,2b85a21c,86b9fe34,60433606,9ae4ce6e,3a8235a5,e43c48ad,d94165e1,5372330a,7b5507f0,377a966a,541b6fcb,949398c8,dd6d6f52,2411d86d), +S(b0bbb4d3,100ce417,dec58f46,95ed8b30,4306f21f,ee11f899,585fb37e,a9905c59,89141fcc,9344e617,7742e31c,42c565d0,45c7ccb8,6f88df7c,5c36d23e,45e51d75), +S(49694de7,330b4c3,1431d452,f3e9e562,eddfe029,1cce58c,73b69cdc,b89e0f49,4715ea3,b6fdccf8,e224b93a,ffdfd1ac,ad8baf44,c5bce735,e7c9b4ef,3faa2656), +S(9a7720b3,ff0363dd,7263e1ad,83c32526,67b67d3b,72c2c14c,95f0804a,dd20f7a8,815a769c,494824a,a819ea,54b560ed,e1df9bca,d7df2d63,aae69c4,a02f9f20), +S(b89c399f,cdb3aacf,99796fd0,95c17cc9,786d79b4,9a1a255d,5c9ee510,38d3620e,ee3c4936,d4f9d1f9,d2642043,d25b21a1,aa32fa3e,ef44f409,73db47a,96965cdc), +S(add68bac,d7180ac1,4e9bbc5d,1e0c3911,f2202d90,1f9ba649,46b06507,b86ed5e9,fcffc13e,a9be67be,8d090a77,9fd9107b,f62bc785,3f98e97a,c0358b3b,7719944d), +S(9bf62cdc,cdabe928,c1ab44ce,38cd0611,135971ed,81ce6c6f,dfc5eb5b,d9c3996f,885b2381,e0e785d3,cc3f78c7,f9fd54b,ecdd9d9f,c2979e23,f97e9bd2,a4f10d3c), +S(bb223cee,f11450d5,c5e0b75d,20eb44be,9d44dcff,28574117,12fc5875,3b839339,8bb29985,87eb6f5c,c8cb615,285d9e69,71db8e31,8d81fd5d,6318909b,8311a00b), +S(9ed73f09,2263e84c,d022388e,da82361b,445f573d,b646cc62,fa0bf5c5,1d33fd27,49ce7698,144e1115,118a4b0c,bdb98dab,6b57dc1a,4d1bb6cb,a68d4d20,d8e937d7), +S(e747333f,d75d5175,5a0cc9f0,a7287084,65a02c58,7737a7b8,b8fa1b8b,4bb2629a,d5001fe,baf8f3ee,b33bc9fc,7fb3da7e,377c8955,91e56965,607269e4,96b90559)}, +{S(516ea742,3f956765,a15f856,182f1e7c,18d3e548,b9fdca94,ea46024a,1a8fcbc0,cfddd98f,be500604,28beb901,92c01282,aaf9ed93,76f0e26b,e912ac42,a378d542), +S(8ed072cb,13eb90c9,e5c107f6,ba576a87,ac75a431,53025e6a,86addb95,bba7862f,eece8a5a,f28d356b,f1a84c14,2549ae7f,894f7c07,305194f3,18e30e0c,873fb5b0), +S(3e0e488b,1c8acc24,f81bfa1a,f6761afd,b4fa5f5e,6317ba72,bfba2f07,6c2ff593,2c4ec39b,2f37b948,fdbc9e3b,a3fa82c0,dcfde2e2,57830a04,4c178759,ef5bbc8b), +S(f6b3f19f,cd7eac5a,13630ad1,bbf331b9,5608b7a0,ceaa67e2,4a1e830b,5eed9825,a2a64078,19ba0f7e,7a890df9,523c6736,50ad08d5,c2557cd1,53c6ee65,ef493ce5), +S(e2de599a,879285ad,398b1031,8e1a8387,21a5c4f7,1105469e,affc8e37,189548a,dd977e62,3dc05cd6,3155a71d,d87d91d1,d74d6e31,5f73434b,679b605d,9db264df), +S(bc52359,683840a8,59fc2c8e,22d72ec5,da2493a4,bb5073a7,f658517a,de83f867,76a13651,712ff42e,a0c10f09,45c4ce41,2cc8c4f2,ac3ae446,7cb383c8,656d3186), +S(d87e2b08,154e38c0,13847a5a,2f84c276,dc088b6f,c19a9bf3,90a8a433,fa937fda,d91447f,7c9042e4,6f64a9c6,40a5c294,1a6f08f5,d3eed464,b09b2a1,1c402c0c), +S(4359ac5c,5dd70bf1,d4f24f00,1301b9f6,17d9c69b,63350dad,9a8cd192,655ea801,c9e14f94,d8ec39aa,46092657,5d770426,350794a4,b1ef2410,a9b0118c,ac5d55c1), +S(3ab3f503,29e22bf6,8fe9882b,3b4dc989,36dfd840,be6af588,ab6d61de,48094b9e,4a40c435,9f4dd21b,11664095,4b55e6b9,f0308786,eec32fca,6bcdd5d5,8d055ac6), +S(a0f1ac27,d046d987,b9a98bf3,f770205,931fce93,59b75944,6494d221,dc2752b2,bf1bfdc6,47a15997,97b5b6cf,2d8a2a44,e9c36b9a,20b53abe,58ce9e0a,395fab70), +S(a9aa63ed,3b0260d2,b35b030c,7a5511c8,679b6170,b8a4f386,fae0bfa8,92735905,2f654620,4dba9b31,99bd648c,cb1605f7,62f312d1,67123d98,ed66f02e,4d794e90), +S(e51da157,5e566ef3,bad3fa66,e55432e1,29be6c36,32e390c0,f4d76719,bae34b7b,55930b79,2ffc91de,674820b1,eec290d7,74ecd79d,1ca07d6f,5ea2f817,4759984e), +S(8b69a891,b417ea65,7ba52bae,58920eb7,f101bb92,e150dc1b,c961c37e,73cd18b7,5b824edb,f4a68988,39de0d70,ec16ee1c,a01a4692,f29263e1,1069aec8,6b149214), +S(ee5c1186,77462649,6d37fba,e48e797,dc69f31c,d6ad22cc,937c7224,ef7ce8db,13f7987c,f2cc4551,e058d410,3d5c24d5,13c2d602,ddccadae,fddcab82,d14d5310), +S(b961cb45,5de8b5b6,c4c5c2d5,75303c81,35b5d278,503a15d2,371b0551,5b236b,3ed18486,5ca969ba,31c734a,19055129,1cd664be,576925a3,2a142769,4fc40df2), +S(83effa4,c127b5ad,7a0c53df,5be5596b,d4a42987,2eafd8f1,5498a6d2,47b87314,efa99759,c9360b14,7643de2d,64ad07ea,39cfabe0,2bc94e00,dc9b2e70,c2e2c217), +S(f253fc52,4fb0254e,e772f50e,5d6c16d8,48692455,c855d4be,15ea9f9e,9a5411dc,59bd1f8,2cece609,8a63fa1d,48e4166a,d79174ec,5f8216c3,16c48c1f,e5c9a0d7), +S(6b61024e,e6451d97,1446b55,1476c3ec,eb6b19ec,16155acd,317bc2be,11086411,8de5c6e,37b562da,ca5a203e,ea028b76,e6befaff,e54b49d2,6605f169,592242cd), +S(1691a90b,9cf72621,3680a72d,af59ef24,985448ff,5f35372a,ab6e2aef,df8b33e5,83d2032b,6ca761d1,286c1348,31250054,5a230558,cba391e6,f0db9c9f,97c2d618), +S(42a078dd,cf749f25,aec7a1f2,8e976f79,e268c36,a7b5b0cd,6aaee3e0,925746ea,c60f1846,6f025987,e0ea6ca0,3eb98df6,99389753,b57abbf4,f5739509,bfd09d1e), +S(21bfc1a7,16b09543,5142c31e,5038d4ea,4643d9c3,2fd4728d,1374dba8,1ca1f07a,a991d491,2601ca23,8e289e71,e9d743da,4385aed6,c732f808,6dc21406,74540acb), +S(e75223e8,fe247a98,5220cbfe,52151978,c98d1460,746f8de2,8696d235,71f3336b,dbbb8075,ab489582,52472982,c7b0c3bb,d82a0762,36c07c05,44417ff3,883f6f18), +S(7a756a,72fee88c,7a2758a5,3294da85,6b06129c,1978e217,2bc7952c,92b05265,c4ad3a0d,be72fd27,bfa475d0,fbd16a92,5e939362,bc0748c,c39ba9f0,3ad84133), +S(2bc697fa,d947fd62,63bb2841,1a274520,f5d582f6,7f039114,293438fc,9aad7c82,543109b9,82097efc,cb44d854,11fc5230,6c7a219f,2f58b37e,3dd354a8,2ffb28ad), +S(3862db95,1ed8994b,a8cc0178,f6dc97ef,db6e1380,c18719ab,cd24a88c,87039744,af1e8ac9,2b195d3,6fe1b1be,a68e9215,a453e638,67e65d88,64a8baf3,ff5c1267), +S(7b648cfa,40ce7274,59a6fae2,2836ea1d,b18ada4,9b18a61d,748127f7,7ceee771,f2a30c56,42887135,30124a69,da2c0355,8688bac3,dae6d95f,a252855,a85a9b4f), +S(f803d7c6,1820f980,ebe0b297,87aa688c,ddadefca,229b99b3,a6bde5e9,922f94d2,a5f8b450,34dc7de1,461dfb74,e7ed9c49,80407bf0,4b0d9159,af703a9e,1e0f9c61), +S(2247f630,9be2f3aa,e30c5907,c29095d4,b9198d25,1a17bb34,7cf5cb35,a2ecb1f1,82685964,20d87b07,1c5a4044,b79b069f,7fa6ecf2,cfc0f839,b2161475,5728c2f1), +S(1d770ace,ceb2183,fea7c924,a8fba197,579df37a,908992be,d42c8e80,8bd98ee1,d87077fa,b910a21,8769cfc7,49aad579,c809e35b,f1c2a813,6047e85,e2c6fc65), +S(5d134e5c,5da47f7b,a495f216,b4994d90,4a79057a,3d0076be,34f09013,99f1f366,fc4e10b2,c1f7bafb,d241d5b5,1c57d48c,30fd29e9,df5774c6,1d4f2c15,3b66ed03), +S(a49ed10e,aaab9323,3a5f485d,4bd18c06,28ab2629,f0b8c3db,4d05956d,6c953fa9,338d476b,99f0ac67,1fcb893f,5f202204,a5178acb,6971e7e4,984d42dc,b904afbd), +S(4d000b62,1adb87e1,c53261af,9db2e179,141ecae0,b331a187,aa4040a,ee752b08,95f2a470,e71f2daa,34927daa,7d268d33,34820a0e,e638d6c5,c18d7adf,b7cfcf45)}, +{S(44d42980,eb92b3e3,b16816f5,56858355,e031b88c,99117385,def6599e,f274e56f,6e3de5ba,4f693fdc,747caacd,b2cf0107,f29fa7c,9c6a1a09,a527cd16,4c2c1484), +S(9812d508,d6da303,6f08fa7b,54cae319,232f925d,6af91d71,fe6c2fb3,bc86be5,735081a0,35fc17f6,7547b9b8,f0f91ac7,f0ddb965,19f6f398,dea745a9,81441e2c), +S(5a022ba,a90ddc87,42246783,4f692ecf,dd2c2dcf,b054308f,4afeb17a,7ff6ddcf,6fc2a9a5,4c7a130d,fd26ca48,82406fb9,f67db0ab,7e6a6d95,1675fef,2e2d4256), +S(c181ffeb,a8ea7d69,c524cd42,18af3030,1cac8e97,69eaf6f6,ba73027d,30fb7bd6,e88959e5,b07b7d3e,693756a,f94590bf,997763b,afa7d850,a80dd9fb,88e6e904), +S(e29375b8,21c056c,30954b81,4f9ce795,c1493dfb,ebf06f6f,f32c92c8,c74839f1,a9040ad0,95c9d45b,1527c624,bac86841,a1f28b7,ccf8dd37,b7e950b4,858e6e18), +S(69445948,ebec5ae3,9fcb505d,7efb7902,6bc1e8fd,5d3024ac,2b772439,72142d80,5b6c2694,abac3938,db899396,62635c21,e64fe2aa,40d18678,9c246e9,fe3f4be6), +S(a86f3aad,85d0bbb3,8270956f,58c2fd65,f5425428,27d7a658,da1b111f,64c02c36,dec740b0,ee35208c,dbec5b7f,69bb94f0,7fccd075,7868a37,6ecec7b6,dcbe20e0), +S(ba2bf65f,aac92da5,6c252b50,8dd74e3e,99ace1bc,42b9d2db,9d0ead3d,b6820306,37bcd01a,75027b42,eb0d7b85,564bedf9,67153930,6fc97106,ab6623e9,90b031ba), +S(78419e61,4e8b5eb9,d09e0c09,79ce4eaa,26271696,fcc68269,4cddf1d9,6a4c7fa,a32dbb3b,46f9b6b4,9adf4dde,f1986af9,72662a6,2ed6b6a2,f8b920b6,82b32363), +S(71163271,204207c8,a84b5993,88beb505,640898ab,b24c4c10,42195dd8,15d77985,aab43609,9370f246,7035ddc2,e71d73f3,c0f1aa13,148303bd,840459da,ae307e8d), +S(473f52a1,fb7c3920,f09ba6e0,a3c891c3,3f4a13cd,9dbf51f0,f3d39ef2,d6bc07d0,b2c403d2,4aef71eb,1b834df2,8bc08b67,5130897f,a6d9855a,eb21ccf2,780444cc), +S(581e93b2,99b8c50e,e6338c0f,f426502a,d8699563,f17935dd,abe08a73,6932b71f,46e7c7c5,1e076fd8,9b8aa98c,f0b3933b,8ca82cc4,d21783a4,d74ae1b6,ca9896e6), +S(e65d9e24,e7340122,875a9d86,d6071a48,691ed5e5,a94b315c,76f169f7,f3d69c48,73575103,a70b7a59,90d9b880,8698b651,271c8c0c,ac93122a,66873bf1,fa3c6fab), +S(cceab216,41d0597,f9c7ab64,7f99154c,b22d4827,70395d6f,ddd6db5a,dc752825,4084c57d,5aafc328,e7a250d0,a7c3c0a9,627ddd70,c77c2be7,e5a1af34,359b9b86), +S(4222ee66,5baff421,17f47df5,c1c1df5a,dbafb790,d5c75bb7,2646cf85,7ae85923,43088d6c,a029903f,f5a789f8,16730345,5a5cd0af,cab57e15,12781396,fcc9b6da), +S(391c5d0b,17a8c11,3440cd30,83434841,969b0833,71758b30,27e38a25,e778da6a,69f3d295,be55f859,4bbb2fb4,116de5d0,b24b5a80,ed62c1e2,8fca9b8,3f6d7439), +S(803b7149,f87e86c0,13599898,b0c9050c,d4a6e030,e07e8d7c,a49c46a3,8a6ea6a1,6b367fcc,6d5916e,72f670a6,5ada9c39,54800e90,a8830fad,c9ea17c0,494cd9aa), +S(f7aa1c64,f8f92f20,1319f316,353d89bb,eaa4d65a,e148b01f,ab66aff6,c9deb179,e9b407d9,4c2b385a,74f22eba,93dc35e9,bebca7d5,17401b7b,576b7d2b,e13ff0c0), +S(f1c34d52,2b7493ec,cefd49da,99732e00,85ace2c9,fd14e9b0,69b67dcd,5acd5e23,29460fc7,dd77494e,a5a7764c,7ca6db5d,5d7a5e3f,65e865b9,e5f85d58,e77713e9), +S(db19a1f6,38ef7034,5340e3df,8d384944,7500640d,cdbc3be4,df3b191c,edb9db87,baac873,a76e0b91,c4847770,9dbe88e9,6195e9c4,ac4d7749,71ca204d,4a5e748b), +S(4ad12e00,f384c7f6,ea669c71,3649da6,55e0abec,67551a58,224b9f9d,de6bdaf9,2e0314a,8e3f32da,33a22ecf,ccac4965,1f1f6f5,20baeddf,39a02bd8,423cd40c), +S(c9130b88,cd451d4f,6eafffc8,357ba391,ae920c27,69e7c48b,49881070,fd088ad5,aac7c2f,4f2f8b90,bea9267,897e0079,7d6515e1,937fa4fb,1043111,6b5e1de), +S(88260ca,df81b391,be79bde7,b54f8a98,428aeacf,970cd843,d683e6e9,50686db9,3b9b187a,b998a22b,56b2933c,fcd09333,9c23889d,1180e365,10dc086,9869cf2c), +S(3984fce2,ab73c70f,a5538206,c2a61e60,2f160b1d,2eb61980,fe174cbe,fe464dac,b7e65c1a,46b50c72,621e3fc8,4f4c7cf3,6860567f,abf00743,5fd1b13f,7400326a), +S(e6b48495,c8277598,23b73f35,762c55fd,8cd20420,fe5be6ad,f27f12b0,68bdd63c,ccbb7124,3b0300fd,993dc9d3,4b55534a,12515243,e07ab78a,8d8fd528,46e5a69b), +S(6af5144f,342f492f,3f506ee7,fc515d3d,d3c93d02,27ba841d,74bc6548,97d4830e,b195d9e0,8113eeaf,fab92a2,81ddeaa0,95356053,a51cf84a,b5d60fec,5368f98), +S(14439b7f,e40ca407,374da12e,217edd9a,86c84397,e2fcf6fc,965023,ba984a1f,112ad656,47c47c30,f19ae62,e0c06b35,effd49bf,d5e604d,6d621471,9f088fee), +S(d4a7e4b3,863fece9,660baefc,ee57d09f,6f60cd25,f4aa178c,cb6f8a17,5fda9d4f,4985a973,ab0e8627,f6de7ef4,470de4c7,1adecaf9,f3766197,a86f4e40,14ea474c), +S(facc2a9b,9d3ad0e8,9fa479e0,ba777a0c,90a0c229,59d4b719,a9304df5,f1e96ff0,6e12c914,70c78733,3e5a65b9,8c01d342,827810aa,be3e4e33,cba0b7bf,eb283b91), +S(3d1b3f54,2809a7d7,79ca2416,a7b7d007,4a728599,e4f30cc9,14bbbba8,3daa091f,dccd0d01,e56c7e6b,90829ec1,f0fc733c,8f1cbcb8,79916982,3b466448,cc21674e), +S(a8c1ec56,3cf9596,d761e41a,bd6bc960,562eeaf5,b54eb83e,3d7e7259,f69671d5,a03c9fae,e160ba53,8aaf38cd,96ebe3a6,db59a04c,ce7074e7,dc3757f1,ccc244e9), +S(219b4f9c,ef6c6000,7659c79c,45b0533b,3cc9d916,ce29dbff,133b40ca,a2e96db8,db2639fa,26a61015,a5bbe7f,3fc8d591,c6b0753a,c16fa89a,d820fe57,72c49068)}, +{S(b445babc,55be50ee,bedb8c27,dfc6c37b,492649ef,8a65de02,111b9f74,29b8c3af,6f74c5b9,f9a022b1,8d3a706c,5c608b31,9f7ce25d,8424d893,4cbd2f90,84b78bcb), +S(dbed76fb,7e46e1d4,1b507edd,8994fefc,f94bd651,a9720d9f,8d62dc3e,9f329104,c047fc1a,41689ba6,9855f063,c563bfe8,49bd8b5d,37b3836b,d8bc57ca,fd02ef64), +S(844426e0,860ff2db,f012ed29,ad2919d6,f46eb102,68073862,c1792e99,f1b2b33c,243512c9,c6ca739f,fb181482,a901ecc6,a41893f1,371d6b12,31d5427b,fb486394), +S(1df697b5,9a2f9c91,b2c5d4a7,8035ea2a,351dc000,4e1c3bd5,5973020c,24836aa1,e89f949c,f6af652e,d7e79758,74a994ff,46475df5,4f7b17f2,a5c29cd9,7f722831), +S(cf4ffa86,87d9a39,7b4727ba,a033cd02,7d8a5377,46903db3,34c35f1d,855999a1,d1316b65,e027ed02,b4be11bc,4c21c1a8,585bb247,45cdfa67,5fb9cccc,faf0c546), +S(e3eed1d6,1813e3ec,d1b9fcfe,3e8bd700,bf3412ff,78a0a9b9,724d4dde,ddfd98b,dcb09803,b70d4c34,ee2bd7ae,6444724e,9ab27c20,5c3c736b,172af37f,cc673105), +S(3a202c1d,94a94eef,18fa396e,5cb8a867,8c3ae45a,e4ee64b0,822d207e,6c814fe7,147992e5,ab565bc2,ad1b1355,60f37dc6,b5cbee74,fef8e5ca,4e4f418f,811a0482), +S(6ce8f558,a853dacf,205db4a5,80c4cbab,8ef477a6,47bca6cc,9e676cb6,5f3f696a,e88e3934,b2857ec,6edb911f,acd132fa,f0078971,2805aa59,9afb3d80,942dc23c), +S(7fef9aa5,b2df37ac,99ca488a,ba598b4d,eb222149,55e1cb4d,c3ef1e7e,7bd38945,d4b7cb4a,8f9edfd2,3a0efd1,9882baf,98312b6f,7b5775ca,65e9dbf1,f2c32870), +S(6ec1ce91,d1eff7ed,9beba2b8,2f4a526f,736e717d,6442dd29,b55ae2e5,3371e0a2,28240ee,12e2b1ed,b40698e,ba6f087a,145eb772,caece880,b3e94b97,700dbd58), +S(645b9fba,2cb739ee,9b148b29,8fbe9884,f284893d,968c21d9,50696d2f,efbbf0bd,b06977a1,2d19836f,add50b7,b73399bc,698729fb,fd182026,d918a267,eab4b7c6), +S(7b930561,3a4a7cc5,ce1e7f5f,29314e1b,40bc8b93,40604f81,76578c18,69abf6c5,55a7e3e3,3f19805e,b5056d15,deaaa4f7,aea07a46,f9dc6a09,6ce15392,e146fb3c), +S(bbcc74ca,3697ef46,e7415ec6,b31a0808,1e6ade01,c7e2264c,f9d4d94d,d849ccaf,27bf64e,e1005f13,989639a0,8772c42c,b4249ba6,9d90cae,3f542ee1,78929f26), +S(4a45fd82,af96af67,9e640bbf,561cb385,2585a8e6,1b57df7a,e028ed33,a017c680,4ba76ea1,19a0267a,f019b3b9,89cde9ce,7b1c0b6e,da3c773d,ca31e44,61e048ed), +S(c3efb1ce,ddc6a749,a5db9daf,48032a6f,3f1a848b,aef9e44c,ebd76127,a9c90d0e,3de258cf,e593b489,8f92e8ac,50be894c,3636019b,a9f31f70,28468eac,687b8f89), +S(ec71a2a4,6f24acb2,8fda6bbd,ab9326e9,6590a96f,b9b9a4ef,405949a5,e3d2858d,31a91fa1,71207da3,1b0acc25,cace1e7c,5126ca2b,4c8d9733,4c50a7f5,29bc61d2), +S(65dc268e,cfd191fa,f07421f0,dcb16701,f979ad24,81ac5ddb,1f77d3ab,41a773e0,f8c9ac90,255d6460,15ddd1d3,57b92522,53bb55c7,e2f5d843,d7d9a025,2766d2c0), +S(62152eaf,df564900,4379891,4b53ddd7,3b91fb60,f16f2d18,941caa96,18d8ffd3,3a185ef0,a8d8a35d,112f678a,6a04a654,df565a8f,87e99abd,95fb4977,1b278ce1), +S(f68e6fcd,b2c49661,ae59bff1,f24e97e6,fffe7cfd,f185d0b8,133d58e3,bec1c89b,223dee27,5e9cc518,af12be21,ee7ef3a9,ab39c7d4,4f950fdd,9ce5c78e,b50514a2), +S(5d02e9c4,108860e8,2b1ae04a,4afbe1e2,9e0a8444,89876776,7e5b60d9,3fe5c753,25fdcc35,5f1970c1,43dae96c,a1ef0a7c,f95853e4,102548f3,d869d3d5,8bcf962d), +S(f6217e4d,4e6d06d1,27668a01,8225f88f,a1e0fcd8,e8654fd,ab26c8a5,4c6d4751,65a6acbc,19bb2835,13eea5d2,5fae521d,aeed63ca,50f9aed8,edb74dd9,c43d066b), +S(c18bb768,bae77077,35b4d3d0,e82cac24,fe3d7ee8,dcba20b6,a320ba6b,4695a406,b7a7ded3,a589153f,8ee504cf,fb5b45eb,b2d8e121,40f2f475,186153df,1fcf84d6), +S(36fc443c,1350b40b,881e41c4,d3c15952,31f8da9f,cdcac4be,f1d0c5da,ceb9844b,9843bb7b,fd0ebca1,762785cd,55669233,16c36aa2,d2c37b3f,2b196f78,bfa5830a), +S(ba7b8c09,d5293e6b,a2548e6f,ff3c939b,80d2ac54,34903039,dfb8b661,29e19cfc,54fe2a,9353fc1d,a0d34e07,b6d34d1f,f3a1f67d,f4aafa7e,57919142,95c2a5e3), +S(50a8ddf1,17a91c92,37a48fe8,f1a00e72,a5dff682,7398a4c5,d2f78b4d,d49ee339,f91d9b20,da28e51b,99fa102f,13f5e451,ab22e139,80052384,6b9c66bf,b7da1578), +S(642ece53,832d1859,c6543147,56b618f9,520a5888,2549277f,6b27f16,e08e3d1f,d9963beb,2c6da204,339a49c5,f253498c,48cc3e99,b715ea8f,a5eb00cb,1d6cffbb), +S(a68c0d3c,13d764d0,7b513390,5842c9,a7171e4f,755a9737,609db06e,1a44e5e0,a2c3fdd7,b7938a87,86f3756d,dbc66b29,72469e79,839a1448,b367db5a,2bc52c15), +S(5b33d730,288fde53,b123fdee,177758b1,ec113adf,74e79eac,513eadd4,cef377ac,1bbc10e,9d45cb00,db58fceb,bc4bcf4,a0e2bcd2,a7d3ec12,7d87beb7,a134a20b), +S(aa6dc4d3,ce531af3,e68590fc,acbe7816,c8293af0,d77914a3,c7119e23,e50ce56e,14386670,5dbe1ad6,91e09123,a19a199c,3ee67b25,708ef57,4620c5ca,821224f6), +S(180a4ece,d74ceaab,e0f7db3b,b038034e,5e659c61,3c66a534,8d962d14,efa32402,b675b2a8,b845281d,524403d0,db01417a,59fd3a6c,80232e74,cdfc87f1,3b76b0e1), +S(3a55690d,abb5e00d,c2d0d8a4,96d16c44,76ee767c,a9d0d1d3,694c856e,e5b7ad0d,3c1d71e6,8a5f9a84,4de0453,6810660c,fe353475,353cede7,2936786e,4d173828), +S(33b35baa,195e729d,c350f319,996950df,3bc15b8d,3d0389e7,77d2808b,f13f0351,5a75fe7a,9bf54078,6b9bfc9,db72ad43,559a9f10,4377648f,d43afc32,34728817)}, +{S(52f79560,fdfadd45,6165a204,6bf61bbb,726cd726,3a3ed2d2,45f07631,5b0b6ae8,e6c46e55,5b4a0410,bf38965e,5a7ba381,fd259482,2280482f,877a7ec5,84d14012), +S(29eeb07c,7b27f82a,1b031881,11d324a9,4df77713,a8cadb36,2ce4012f,52cafb19,b7538574,28faf258,f240d4a9,f464797c,dffd0a68,f9f978fc,476f9bf0,1a0a2df5), +S(2191ebbd,a95c29f8,e7062f21,a70cb368,ac67ed59,dc44b167,66e52120,cfe8e742,2812f1fe,557496f8,f21b1f11,2df7bd19,db6aad90,59494ad4,eaed4d77,49f66a4c), +S(3c29d849,e25364d7,576779ec,78755ff1,8aa64e2a,65140a2,bbcf22e3,da33a4f3,3658d9ff,e2e283c,f8973cc0,ede5af6b,69ac4970,3c6b1370,f6a2ba4a,78a28a97), +S(37230e16,e11db299,f54ca0f9,f5423ac6,5f05840a,e166175a,ff0732be,c72ba88d,2a26ac2c,e8f9ebdd,20f1f5f0,f628d3d,d0e02745,6132cbf8,78b614b4,51db28f2), +S(8fbb3be7,98e16bfd,b738a512,ceeea92c,1be8eeb8,5374702b,e927c614,ab1f1baa,8280f387,64a48061,26392be0,c95f0c58,3607343f,d0b24b98,afe3605b,8f7e79f4), +S(fb639ee6,29dd1f03,8e12330c,bf40ec7e,129d7da7,655c1c21,86452fe4,9589c89e,171adbae,2efe213c,8d01e273,ed9c5d47,c4e85503,de3849b4,d909823a,bb1da898), +S(2399064b,876b7584,8c977bf8,e35d6b32,2e45d1a0,c4243fe1,2a31a581,d1d5d826,79c1ef29,c1af9497,f3b3db13,17432d42,86fa014e,17e5d780,a0d39df,b61369c1), +S(dd5663da,63acee49,eb7fde29,6ac1215a,772512ee,6a080f3b,1266c7ef,51da5dd2,d19c7348,3754112e,9cb3a4ce,8986f748,3eba26ab,c415abdc,5effc956,27efb7dc), +S(30862c58,43b161ba,c127bea6,7b23d3cc,46b6c42f,8faaa281,6ae47092,8ae47993,44ea1101,26a7c448,dfed4995,46a0fc8a,3658e540,d7d0c2b4,18f8cba0,accf9537), +S(df7ebbdd,4e416e4d,6b1e67aa,34915da2,cc15bf8f,f6d79ebf,273b63a8,32d6610a,d05fddd7,e9618753,21f473b1,bfb5ff48,65b3c4f7,5cf4ae26,549989a9,e13056d8), +S(13adba8d,2485bda5,1ac7994b,c45a7e4a,1b21aa9e,8188e631,59b217a,29d4237c,6256a795,3f24b25a,c1f59384,aac3eabb,4458e504,af3b99c1,99ae614f,8def4ff4), +S(c160f7ac,9a453a1f,8811d031,9849be43,22d8bbe4,89cad7a9,cb815927,d4b54720,7958b41c,751ef3a1,fb985ea9,c7cc85f6,c16282a4,c374fed,5999d8d6,3227b720), +S(c66af931,82a7a9d6,588e9c7b,3eda3b49,40fdcb99,346aa55e,e6549d4f,f9382228,ffe4d0df,43f00af4,fe885b10,92ae38fb,97d21a8d,26aa5f69,9751d52c,a9ccea4b), +S(d3a4f4d7,d208b43e,c4c2fd00,798d882d,922f302d,a199b707,76a70f36,5ff404aa,8df220d9,63faa827,1c4ee360,67a536ab,25813239,82252483,311616d0,1458e1b), +S(47bdd428,d57ed451,cd8754ea,817c5f5f,9658274c,ef6757b8,70527b4e,96f372f9,fbcf0ee,9fb14de6,3c288dbd,b1888fcf,72f0265d,3fe2209e,12c85841,2c375b53), +S(6e6deb95,7f2eea30,5d625288,3cb311c7,f0365a42,480fb807,36315c4c,62495438,ba0fdd63,9b8678f2,ab0fe3e9,a16512e,ffd9ec23,e691cd4f,86146969,534978aa), +S(dcd2775,7cd691e8,28e21987,d6eb6b54,e8def24d,27238cd5,dfb36a3d,d0f05caf,40bf37e7,bd776a62,ab420209,c71df7df,74d185c,f0d6b038,dea9c8e0,c1dad163), +S(eda569f9,9bccdc21,580da94f,92d89312,cef87d13,f08d8ad5,f1574e12,30a64ce6,4e1da1ac,dd274e3,f9d7def7,746f0652,678e549,ad5476d1,410adbbf,aa3c1e42), +S(5d3d4a29,734fb7ad,2846ae12,4c803364,ea3d57bf,e8d77d9e,6a3b3f8c,9cff26b6,d3e598a7,1a469323,a357df08,319dcd1a,d7337a32,c9894b80,6a30c575,b19756b0), +S(10161fa4,61e87595,f269da7a,ae3ccf01,40e910fa,891276c2,df1bd91a,95e4d046,b36eb5f4,b8291a01,18691f1e,50235d8b,f66e14a7,f0641dd6,18ad7ddd,ea150196), +S(7ba1b276,3df207f3,cfd1d58d,5190eb91,99cf82f4,9d2d0927,f5f260f7,2ea0f178,cb9fcac,4be96ef5,3134f513,5509c178,99af24c6,4eabd650,afc599d8,3927969d), +S(4bd6edd3,aaa1802a,b0f46e05,418ada37,e75728e8,6ea4b293,6619c92f,57674dc3,c9e962d3,de71eafc,7fc9a329,3bfd721f,305e876e,a2a4755a,f9567dca,21aa3c0b), +S(95fa0b32,40b24ba,29a484d7,f8f022eb,b3f30349,9d8abc1,9a69b690,3e885b68,dfe6b88e,56d7b923,dcf8bac6,2241d663,3ac2ae55,c3a01fcb,9f966d62,8f3acadd), +S(d0fd4d10,18c37114,2d5f8a86,617c250e,b6c3d5,210ca465,6ec84e87,d0ae42b3,4e3bf443,290404a9,3af38e72,a54fa06c,3b2d6a81,161fc8de,554edd9b,f3399587), +S(992e1183,d4e7afde,166c45e1,37c71c88,d4039709,4262163,b4ae38e,538293f1,c29534fb,55e47a08,ecee311c,8f0ba4c0,39096edf,b2d7ed63,21a2810,32e85900), +S(9c124ecd,4e6ce167,f60dcf38,25976f33,64cc30ff,61f7dde,966f8c23,4c13a4d9,7ad73bdb,e0afe3c2,c89d9135,d445ba4c,796066eb,1909349,9e6ec14a,f74f664c), +S(b09cdc9b,d102f89f,bcca0ed5,888519b,7c5c02b1,64ccbfa0,3d0fe42,b1b113e4,f409865f,6ab4371d,f52790eb,88df67d,84b3b74,f17edbc1,29b802cb,d5e49a59), +S(6b4f628e,beb6d619,1d616e87,3233ae37,ca4cc3f2,ac881e59,9c2c8e3d,295ccdc0,1140b988,60f4ac7b,659eb012,6fdfb796,c0baa652,2202cce0,bf54b3a4,865f171b), +S(a728c830,10169439,3af3f780,b1ceae3a,6ca08ea,4bdc7554,2ae84564,f542c28b,7b68fde9,8c97db32,eb3cdbd7,15816e51,9aa58458,259dc74f,5d722dc,f48f1933), +S(21ce4401,4ce959de,f16b3912,e88ff48b,d44ef79f,5fed2d35,bdd2dc78,de8f7605,cdc598fd,c5d30508,a2690299,e0e25b91,b1ccb69,97b99fd3,eca1baed,76aae6d0), +S(89912259,11b9132d,28f5c6bc,763ceab7,d18c3706,e8bd1d7,ed44db75,60788c1e,2574b267,83365364,d84789ca,a64ec905,c969637b,21061ee,9ca3bddc,7170ed3e)}, +{S(5914f66e,28c1a0a3,47f461d8,1d7f2c55,845e35eb,3dc39945,584b5efa,8d71a215,cd2ac885,3f681e4d,884e308e,ed3ca185,b47e2d63,3fdfff6e,efb6dc67,4d7de056), +S(519834c0,d16c807a,7867b8fe,c99dc93c,3b9ed218,87a9ca17,9343729d,3ba9e294,b867d57e,fe2dd7c7,8586303,152f02fd,f67b5648,78a7727a,190d304e,64f97203), +S(959eda70,cbabcb05,fa8fae96,7227b6be,876db942,ae38bfea,a9c3d359,977e1c52,86373396,9338053b,b00d206c,5d67abd,f95d35e6,992ad69d,8d8a3322,7370fdc), +S(a40279c8,48dc042b,a3ee929c,2910e326,eded6051,9d9eb1a4,98fdd7e1,fc88a6bd,f2c962a9,f2950d2c,acbfcf29,35bad39e,2709c0e7,36378968,fa04d957,1dadc4ee), +S(650b8181,edcfe46c,eea03ec9,f8ee5af2,c288e618,7d634961,6c95554e,25957334,ce140ddc,c2e2b07,a57e5627,62da3eb5,ca1acba5,463e97,fff7eae3,55b954c0), +S(eb04688d,5f4c8d2e,4ccd509a,3d003b30,8c5539b2,dd160a45,cbe71efe,36fd9005,37d80690,2062bde0,b96fc8ba,7a7f751f,9461f774,a1d6f3e8,8999c676,a2ae76b), +S(f79206b6,7813cd64,9f946313,3bac4aca,3762975e,954e0ef5,a876b78e,4b5a5d24,6033d4ee,936e956a,af117dca,6086eb1f,6466ab18,d503503d,4b011315,365242d8), +S(539c99d7,728cf662,13e024c0,9f1226f5,ca5d09cf,67bac12d,47814b2b,b1e7d611,87efd14e,e58fbff,5491bf85,aafd48ae,6680f37,e0d928f0,13fb6cec,6f417f76), +S(2308281d,e761f602,66fb8228,45eec88b,e32f8fdd,4a06b8b9,3dfad9c3,75d64a8e,933f4071,e4f2a9ae,95f4a299,f4267098,94b661de,c96443c5,f03f6cb,f3be87ed), +S(a93d05ae,fa31c0c1,54c02f68,9184c1ff,344c670b,e13eb304,2de517f2,1f6124ed,b7549c5,4651fa60,61f4103e,27d316a5,db531e3e,d7396a46,e360341e,f53ed274), +S(35717dcb,4feada90,b039aa79,10cf064a,c8c998b5,fcbb037c,22bf9e92,eba560d8,b6ff9371,d98bf532,f82d7fdb,24fffa69,2afeb0e6,59ba30da,602b3399,2bbe5a5), +S(941d37ef,1671d5f5,675be9d0,d5cb1f0a,ab6dffdd,2bd342c5,c5b62be9,88d5a0aa,4834d5ee,a8f9ae8e,ba5cc8b,2fb52260,33e35767,d55b6aa6,d204e0e1,a38b42ed), +S(c22cecb,aff78c61,f6e34c9d,9367c4f4,1acc9c35,29e9d894,7989a874,1d70bccf,38a37fb0,5fd9036e,762e2f0c,fef8fcbd,c04a92a5,4cb72ee2,ba08213c,4b58f1e1), +S(7863ac2f,1704fd,5015f0ed,30edf5d4,33c5ea2c,e150833b,a15c1db8,a5e4d2f4,7468fa15,eeab5653,c9f982b4,ad9e4c99,2f44083f,a7a93e9a,25ff70e5,b8742b4d), +S(f702cfa6,f0cfd275,a2c7af50,b53d0c94,bb965063,c433f4f2,cfd13d99,800da48d,3da4a4e1,bc5f2c6d,2f8daec4,599a9704,7c1b930a,b37d6b2c,f8a586cd,ef7dce1), +S(c3a1da3c,6e6b8f2c,2a8eb81a,1875f2b9,1e9cd286,414862d6,57626b47,a413d7dd,983d0892,5983d42e,bdbce2d8,df116bc2,f5cf8c87,aeb833da,e5e7e9ca,f9699798), +S(df0a4106,d61fc3c6,b2a14ecf,ebea3dcf,7e38069b,8faac576,a0b8a1b,7c8e7b5e,dd97a06b,840d64db,1798cee4,9334b033,e8d3f4a,79da565d,c6130da,f0bea75b), +S(ee9901fd,9312a21c,879d4e1b,24d5a299,b8200a15,6e65e147,4a2055c8,a2363423,1bb2933c,8b10f8e8,ab93ecee,16f861ff,a86781ea,59b891b7,740fdc2d,f6c206d), +S(52890b99,c8dc48c4,b6b1e4ae,5b823fca,ad9495b9,8217fa4a,b4f8e960,77cdaf9,6ca2ba73,72606e82,9c3395fb,dd2e4b74,8c771231,e86fade,5e2d728f,e5e7391e), +S(a372b545,bf56b58,b7c4628d,aca9bc14,e8bc634d,d79d139d,8eb7a2d4,13465c3e,afde23df,fad41c68,df94abdf,90a642b,31d62f84,c6254c4b,4cad2934,376372f2), +S(89d02f41,f88b1f7c,90b01078,d7599a70,a1eb9c23,1059e856,4237b0a3,2c18010a,7e8e810b,b063d75b,c224f41,a842972d,6fe065c2,aa6b16e5,7bf224fe,e44b2275), +S(7ef367d7,23fedacf,86425861,f67c5ba2,2deaf04,69e31988,7a3a3a12,2f39576a,4b81e743,e00bfbc,1d98cbc2,5c98c516,55e574,fc7fa1f5,86f15d9b,1b5b7ac1), +S(2eec37a1,5fdd1caf,b4c0855f,e86c5534,1a78cdc,b3944798,311b1cf4,7df768ac,1c18cf5c,1a98fe9,70d1e635,ab133668,4e0d964b,4df0b16d,7c51ea01,c9a63), +S(72208b8c,fd9840d,76dfa6e0,f36cf57e,502f285b,422f0ba1,9b119500,6b2ddd11,fa09196e,a89ce6a,888415ec,a8eb92f4,149bb39a,50174a85,8a29bf63,65b4e577), +S(9f46479a,69411d57,c3c7ea6a,dfa833f9,1fb2109a,fd30c790,2ce323ae,4b14be0c,6cd6d7e0,8494cb95,9e67c258,1be426f6,4eee4514,83e9a9a1,278b073d,758487c3), +S(a9aaf56b,5016db58,5b8116dd,cbad1169,4b16de8d,9db5ea5a,279ccf4d,91b1d7a,218fed41,389a4abc,44fb2a83,7016eb50,99c40e86,bb419265,7f57714e,194a5900), +S(5f950f20,b610c06b,76949dab,52fc6149,97d254be,a1330a0,493f1ea2,1d608864,d9098481,823b3ff9,d1c0b7d0,bce90856,186b45ec,6f20da26,9b158283,8a4c96df), +S(ed621f77,98add722,b0dc5e52,9c6fec6b,dff60827,b0b12c85,18d798dc,761f1075,a8973e79,a9caf1fc,e3165145,df08b7db,6b7187a5,28b12712,6c62bb5d,4f0c46d7), +S(15b8390d,652d7338,e18ee091,97e0e176,74f8c4ba,fa2e7b85,8f5badc9,9c89240f,87930df3,710172f7,c5422833,385a6066,4cfc9854,a3e5ccca,d1d06106,1cd90be5), +S(ac2acb9b,21999a70,540708ab,68338266,aef650ee,d81c5b30,da1e87d8,a8a923b7,897bbd7a,ee3e8db2,e36505f2,ec2614c,9f4f2f40,ed2d85b0,5d23edb4,2832db89), +S(17c072d5,6bdd1382,a782481b,8aa4d223,2db79438,5870bcad,c3063330,a5cd5379,26fe420b,d7c25f9b,1883edb8,50e2fcb0,76a65389,d9a452f2,8351fad,4ef72f0a), +S(8d262002,50cebdae,120ef31b,4c80cd5,d4cddc8,eadbcf29,fc696d32,c0ade462,1412c44b,8ea40bc8,2ce090d2,3c11c945,e2b504b1,8d9874c5,271f5745,f0d9b523)}, +{S(ad9144f1,bdcc3673,26d51685,a047ea9c,3c4feb3c,da4b9b83,80e1ada6,300ba487,68003744,ab5b2c8a,cca5bcfd,e1c4262e,88ffbc0f,b0ad4206,2d57dcf8,62c93c47), +S(f3b90a0d,7a8cbf1d,9b994b19,7ce215f9,b8ed861d,d526228,59fe1811,68727bab,95f48e8b,c05a7bf1,e47fdc86,87513ae,5a56472a,44f384f6,1153a954,2db68b81), +S(24af6d7a,99122466,45b07a1d,29b4bb1,a68b5b0e,f9422065,b5bb0050,61d43cdb,f9dc7725,f628cc4e,d4e5554e,f0166b22,566d59e0,4d55c28,a4d0e975,8306c31a), +S(f704aa4c,2bf19c9b,128311c7,1bab5f8a,f2a3865b,728f4838,b8ccc7d7,82574cdf,ae7c46ce,c44d54a7,2e3f758a,e855710,dee6b189,1223d120,9e059620,38d12453), +S(f701adf5,a1bd988d,d7e1fadd,9903c453,e6798760,252579c8,b90cdce2,a046d9a7,db39a987,48aa20d0,5d8b8538,fc4b7d77,95e2810b,160198c7,ad98305,96407c31), +S(bfe36081,c492ed7e,3b91059d,bb1af376,47dca509,69be6665,50f94903,d948ca7c,a1fc9468,2c3dc954,764ee858,822b8c1a,5d0184e0,93f12bbe,21e9931,18911f03), +S(e707057a,297a3d7d,904a615d,ac1b8e81,78f52481,32fa166e,afb621e3,af3f4f34,9161a930,bfd583c0,bfd3b121,acf574a3,6eb534ab,5198aa84,ef38253d,9ca19bc1), +S(27a6c7a7,970a9e3a,7cd42b6b,4478be62,31f53ff8,481791c,4394e78a,968fdddb,e4bf1b16,6bd56269,9e2c341b,b1a51c8a,c2ac7d28,807899e1,3ab1f726,90f44108), +S(e65f799a,8fb3b6c,ad088351,614db5c3,d64660ef,8c977ec1,2bbe58fa,a53314d6,5897f680,253a948e,fc260fa2,8ac39377,4e6a445d,d2bde00e,4e01ff03,b4398e2), +S(8406a84c,e9e63204,761dd406,9651f20d,6fc3efe3,f98951d0,d0a2db9b,cf86e0a4,ef81aeb3,eac17e5,676f4455,b4372ccc,e405b786,f11a871b,d781e54c,6307d1f2), +S(c012cad9,4742fd49,8daaedfe,5b847f34,7a45c792,53c8a645,2192e905,e256c7a1,c4866f98,48f31660,8a81da9f,da112a71,34232f9c,75e388,7ff987b6,8404cd42), +S(73795313,e9de1efe,3d91ae5,15c620c4,4f9c6bb3,a21e3097,c8794710,b2032683,548ce754,93817f22,cb96c674,5d67708d,c7b9b133,c71cba5f,fede1316,c55245f7), +S(352b89f4,78a47e86,b5575fbe,ee1373bc,e93ca316,1f594564,9efaf048,a60bfebe,d784e6cd,88d7862a,d82747d9,b23340cd,b50235c7,65f30be2,ab5d313b,edb0624d), +S(8a0b3d0a,80d41abc,4b8a028c,6c523923,7b040445,525dc345,d2d8a319,c4708316,7b7a427a,f0e1f902,dd1b9bb4,65b6b376,ee68b9a3,f495cffa,c52fcb9c,705443e9), +S(b4bf6756,61462829,53f9a44a,ee3b5427,2485b45,951013a2,8d59346d,62f65894,85d0c26d,2987dbd9,e26c9673,71ca86af,3b8cfb4f,cbf97404,c99ef900,5379a1c6), +S(bff69744,3ac23a6e,574bd1ac,d0fea305,2f05ea65,14814f1c,65e86e9d,5b46a2a5,36961462,5b998565,9324f5f,c8714d9d,57ff314b,5d5c2cc6,99a4ab39,69add4f4), +S(ecb09f5d,122adf91,e68e98ea,d39e5790,27e7c4ca,405bcaf2,e086d4a3,e68242ed,aa214cca,8a601fa0,a92633cd,a353ca02,7a7dee71,cf335af8,fc75de56,a3405f60), +S(310d957f,10fb34ef,ca3a2a0b,35c901f5,35c0862c,68310134,10982d7d,e74af8ae,289cda3f,29a489a8,86121f4b,4e75a90d,2bc4ff20,e95aa103,4044ea80,cff56378), +S(3a5f1ad7,c59ee6cf,e090f210,7040b419,4ca15fa7,dc8e9f69,20825fc4,e012ac2e,8ac8986b,48d7bd1f,5ae99535,2505b0ad,78f855e,d8411b03,15725571,dc99c920), +S(725f136d,1b426894,c24f8782,43fdc1d3,79636a23,d682f389,dbaf71de,d4672067,db0ffaac,ec5ffadd,f32396be,3f01fe2f,45bb0cbe,eb0d98bc,2390f3ca,c3dfec84), +S(b28e523e,6fc68192,445180d9,5da3e411,2fe0db1a,5b3bd5e8,e00a1090,39c69d53,7c172a4b,31339fb3,47db74a6,beedf59d,c24e6aea,c71e2a0c,434714b4,d61a2f70), +S(b808db0c,e34b5607,8166b308,1dd4b2ca,cf9d2d51,3079648f,fc3c617b,8e45ba09,d69c4ab2,fc7e490f,6887f2c2,49e0b71a,746e3e2b,97a7415f,34475bd6,f6dee79), +S(5e0b091f,3144d7bd,c7e40dbc,98c716cf,d7e64eda,ee9c1fa4,6838bcd9,e0c6878f,1586cf7c,da66b005,8b2d0d49,f588d444,65eecf42,1d94c004,a078dbd,47e0bd20), +S(1c3e88b3,ba46410d,8e08f9fd,5db8b53f,8dff33c6,4f5314f5,e005442d,10cef1f8,ba365020,5f85aa9f,71a42c0,392345b7,4a17a5ab,9ff91109,4d81252c,d8c8f72f), +S(b4926018,fb0e9c,e80c5614,37c3f22c,cc223412,384321e3,6f408e4c,ec0d81ac,55544f6e,cea3575d,e81649b8,4950f225,8a94e78f,13325ffb,16debe1a,8387173d), +S(f4bfac1c,b0834e1a,e332b7b7,1ab84500,b1c8460d,c8c2efad,6a5efbb8,ae78cd1d,5faab691,59ce9d3f,6bdb1818,676684b1,cc2309af,1401b5d5,137e1c61,5fbe287), +S(220ed3d1,fe028d87,b96e8ad9,37ede03e,ed8f262,ce877c0a,42718ab9,cb2ddfb6,5ee2d60d,f96a1b8b,e11c9139,7abf9b4f,a0671966,34bf37a2,8d26864,31933fb6), +S(dca5fad2,d045526,b6a4c309,de1d95b5,23f9a7db,e669b558,edd75ca9,40c85878,f350337e,877c9c61,98fc912b,5d53876c,78ea94cb,bbf3744b,62a52fa5,f5ae4399), +S(486ba509,3272eb1d,16ece443,861eae7b,2d8604f3,37014bc5,11267485,9872642,688d4585,9fa732c4,f582d65c,45930567,8c27dc6e,5525d47c,3908daff,f0a534fe), +S(96bc1bd3,b4840354,14aa92eb,6db81f5,403e2858,c0552d5a,6b21d33e,c468f31a,83027873,f4066b5e,ba6f413d,6a7d4d18,d57f4a62,25cc9289,b514f153,91ede3b9), +S(9f131ffa,b53e20b4,e9cd9e33,793f4614,922c03df,7d11222c,7fffec33,42fddec6,c4deffeb,3f4cd90b,102cb6b,3f713728,2c5cdcab,bc6e7153,91ea890d,76207bdd), +S(c15c8c23,d90c8e35,c1a214dd,e2d4383c,735ae45,bef61f10,aa1a1c25,5984cf74,d456ab27,d7adddca,372390ba,1da02845,b84088d2,af4fea5d,3b5b7326,c6334c2f)}, +{S(e24b71ae,8fdea24b,2d42a2c6,5cb022a8,2aa9e03a,3067a889,e778caf8,34903fa,f87d5757,cae83263,1233b840,296d6066,52cd1ddc,e8334629,25c992db,7e0ee14a), +S(886a7626,6203c559,807acbf6,7e1631ae,1f6bcacf,3fde277b,ddcd795b,292c38f6,b1f590a1,52d3ecc3,2b699c23,a89b2601,de78be2d,fa11b20a,1ef1235d,93ed9e99), +S(3079f709,3d5270f2,95fee75e,a6c5cd3a,5638ee37,aef535b6,523604d2,eed0d57e,492dd2cf,d76705d7,42187f38,f38982d1,85efa30a,fd1639cb,984a8772,3e912a91), +S(7773469e,c557e3e9,4097bd55,33a87583,a79e3eb4,2e421cd6,592363c2,76641966,f827b0dd,46f4b5fb,4a656731,d827cf21,df1ec610,f36dc2d1,215f33fa,20a08020), +S(ebeec367,eb032a6f,7c421ae6,f8fb56f9,3fcdaa68,f6741e46,1992d019,7567336d,6e78af43,e10c742c,35467149,3323f8c4,a6cff91e,7b1f1c2c,65b21fa1,e63f3a6f), +S(b41658a,3683b512,c751d817,f5d92f8e,5d158632,1f2eb836,b446aebf,d276030,9396ba60,ca61b35e,4e52e879,a457ce5b,fee9121a,b2673c19,15e78236,483e069a), +S(2e2ed965,a926700a,1428af7b,68b7dbf7,61d1bf53,6eb9f75e,d56afa0b,63852cd6,8d77656e,d5f11224,3a94e462,3dcfbbdc,61749930,dfcca6cd,c4303cc4,617e9133), +S(4b54bd22,e5604384,9ff2268e,88c695d6,4766e0c8,4f598f5b,634e1dac,d03063ba,176c68e4,a1f25683,37c14fee,dcf9a64b,17cba4f7,283428c,1514990c,98d29d71), +S(b6cf7c38,2d4c63cf,78557116,55b5de99,1fd32da6,8b8d2dd4,cfcd6f5c,59c45251,c4c190ac,2870142f,2a13d7bd,5d6768b8,fb5ccdfa,b99d0e3f,6bda805f,7741ff52), +S(857b6db4,79177eca,82a6c801,bd763647,c1a49021,e5b4f405,ad02e6ec,7ccc3629,586cde8e,cbf7907f,704a6610,f7a8a910,16599e9a,93bc6a6b,1b70d59e,39c0db4b), +S(a18a23b7,6643d92a,9e1bd2c7,7bfee61d,c5171b33,12f64d7f,821fbe05,6a771ee2,321f460b,b9525303,c159fe3a,6762dd97,60432307,919a2f1d,6120c946,47cd8568), +S(19b91028,cc2e5434,b162cee8,c77351d9,d38d9eb6,8ff9b09b,f26cb25f,4b88510e,cbcf2e52,3335ee5c,56ee2a06,7c565627,a5c60f16,808ea8e9,94250c15,e427c883), +S(657e2f30,b1e0241,82c0e57d,996cccf4,7bdf8eec,5a4da875,1638b3f4,9bcdbd2e,8e0a3117,12da36b2,2d0cd048,a9a99b26,5faadec2,14162083,5210f1bc,bb79fe3), +S(576879e4,f4a8e697,45014bee,36ba4267,cf72038a,f5997d38,cf512f08,f0ccf6b0,3f313f,388c011c,18ba0938,51b0e7e,84627277,2e9da999,b839b58,92ede5c0), +S(ed72d681,6516c2f2,7a9e97c7,1a7c99f2,faeb8e31,a5f29260,faa0bbf8,6475117f,331fb25b,e71c24fe,f4d2133b,f1591f3f,e5f8830b,15615134,36fc47fc,522ad4b), +S(e4ed422d,9152f00b,96bce64b,bc3ddaee,6089e1a4,1ffbb58a,109c688e,ba44699f,6dae6420,2dc6cec2,e4a49203,6b16c9f5,9c517436,bf3b9d9b,7e8f458f,7fcba8e9), +S(fc3b8afc,fe39404c,29622db5,b06c989a,8d7a0c4d,85018796,d006bd5e,43dec087,7b77feef,2211c1a5,724af5e9,a841e09c,d7940bc5,43d70c7e,51676689,7682ef15), +S(9c2421ee,e2e7e66b,decbd152,a8839f1e,4cf03808,649399bd,ba55cfbd,9dda6360,8d9477c1,c66a532b,967895ae,66c7585e,608e9653,4f870bd2,c97d7398,74a84700), +S(22040517,334bb5cd,2252d1b9,8a9da91f,a0bd32b5,562c8218,4d991e01,d94e8f13,167d3dd5,738a467e,f8e03064,d6482c2d,64503892,b4f5b9d3,c4b04684,fe2f15c0), +S(b648a617,3c728243,f3c0c7ec,2aadcb13,dfab92fd,77da9aca,1602d47a,80022dd4,7199a3cf,89c596e0,d607d05e,de95c8db,ad763ac0,76fa7ee8,ba7ae6e1,4c14308a), +S(a7d7ab3,6722b9d7,940b2a15,c94bb9fb,41a139d4,26215286,bfff84ec,57386dae,25ea853a,c3e772b6,f400d850,a7cf5760,ed568add,a145ea75,6f20b77a,c32d9f28), +S(9787a21d,ea3dab74,366214b4,933a702c,7a07c4ab,696eddb7,3a84cb5f,80f2ba41,8663b959,2214a018,e373e360,a9e035be,f68d9e01,f6fff1ab,f8ad9b8d,3f6f324), +S(1d2ebbd0,65bd4f50,8dd697db,9c8bafff,b548edef,856fa4e,39f893cd,349ff205,85d0716b,109ab208,a96367e3,bd0a2314,ad2c8586,169096ef,9521d780,61df01a4), +S(d0a506ce,14e88414,46c08a61,98ea0aaf,75b9dfc2,c4d2cc58,1238a597,154981b4,dc8c863c,7c4611a1,85744975,34c8c02d,7cb7504b,dffa91f5,96765a25,98d1f506), +S(b6c4d103,a57d0af,27e93627,f55a34b7,75b2ef48,47d7612a,5fac0748,b41afee9,dc9440a1,596cbfd9,ff87fade,8b426091,4799dad1,ce0f7b60,d032e94b,bbaf53f9), +S(5b5d965c,f2f37462,86f088e8,b58887ab,2182f874,484686dd,43a245e3,dcbc55c7,6718ba28,cf43ba30,eeba6e49,a7234ec8,7f01762,e915ff12,41fb461b,6d87a875), +S(bc85aec9,55e6e99a,c5fa7738,c7972354,57b3935b,bb69e8e1,ddc69d01,d34a47f5,59dd49e8,cb3100a0,9c48ceaa,20cbde82,5072e13a,7af0a44e,601044a,361dd971), +S(66b7ffeb,a34d8cbc,e00b4d1b,a0558741,5123d8b2,89ebdba0,47587d66,b260bc99,43bafb96,c88a5917,c6333dd9,b4a546b5,1c37ab48,3f3873a3,6932ab97,efd79712), +S(3cf9208a,b230b73d,68470411,bf3d4899,e0f19675,f829e32f,cd148d,3c07d7c8,21fc39b3,ea5079a2,ae131935,9a3e98df,62b97b37,2a473a63,f3b56e24,25b30e27), +S(66e3fcef,b7b24cf7,af0f8de2,8e53c2df,2bd1dfb2,c0289b10,31239da0,948e129e,df4074b0,488f3f09,a674a40c,b3207f34,a0282661,2e5ac4ae,8d443c9e,d1184045), +S(28df781d,4ec05680,590f4658,713c8a91,fef23763,87ddb6dd,674a35c8,b0e74459,eb66159,95ecf0e8,34f24e87,6f0dd86b,5c86a45a,fe5190f5,721f833e,10a196c0), +S(85d8da47,48ad1a73,dec8409b,e84f1a13,16e65c51,96aad27e,766746f,3d477c2d,a76b74ac,99a3996f,a794ac9a,ce103843,6b4f5fdf,cc3b2a59,df867e8f,382e1ebf)}, +{S(39ca1e6b,9fd848fb,ac24c444,5a9f398b,8639fa6f,c0c2f2b0,8058d84e,6c0caf1a,8797227c,f956ba7e,5228a452,91cdd51f,8958ab7f,43f6c8b5,e06176b0,dc9048e4), +S(4c87e538,c9eac9ba,d5a2a81e,43a6f1e5,f8403c01,68ad5020,4adef77d,5e3aecde,6ee8b74d,dd0b9bb7,c8b7ed7a,728dd99d,a9fab941,f0132d0e,998e65b9,ffbcb9a), +S(1226617,9f5dabe4,6d963b7,e96247e1,e29f2440,f831c8be,578d628a,78561987,2d3552bf,ddb5ec6e,a7758830,9badce7b,41d71926,857962d3,c3bb28cd,5d68ce7f), +S(866c0a90,893b6b3d,807a96fe,3c67b928,67c1d95,e05146fb,40038476,26981201,8d8f3188,da86e510,b7a7642a,97778201,3926dae6,4ce80663,335bc448,d204413d), +S(8eeb2e94,9a66824,26a6f474,9e7578d3,1b356aa8,d1b42049,5fb83e5f,5d08f723,e439d710,c45063c6,d23aad9e,ac0cae8e,36552ab,ca6f2c02,6eeb03ff,6162a052), +S(ffc93fcd,85fd9502,78369b3d,291f1ffd,5da44964,888d5eba,3c3f60c,95082bfa,9aa66635,a4b0defc,b2514e97,515aa0ec,3f65ce8,6f6962f7,72eaca41,d5ea7983), +S(605ccd66,4f18c83d,edf36f62,e5089f14,4ed23f4,f88635fa,ab161567,fd20c8d5,cfccf020,363a805c,1d614aa5,b9a912ec,99cfea61,5c088789,275ef531,dddf2418), +S(d1e4f37e,7d3902aa,dfdd7254,fc727a44,98eb9303,a12fe71b,4d193be4,8dba6913,bdd29d53,4881cbc6,c2e301fb,7d757bc9,9224f12f,4296e834,9badb88f,84fcc289), +S(f30b6d53,f330e6b6,b23d21df,7b4350a0,c42ad202,4a92751a,5dfed94c,47bbe60f,b5ca6c03,b31d06cb,183b0b18,4432a06d,8143d511,8af4bc01,c364f024,b46e0c38), +S(540944cd,42101851,c2cdb0ad,61264e18,cbf948cf,2090df68,54482628,74271ecf,cd16820b,4ccf9131,476b8778,ba3e83,f5970507,7110686c,653be572,2e99db3f), +S(846e5478,5d9cad5b,5109c7e4,6fd62b04,f686c723,1fc3c0af,66bea20a,d9d60dd0,4b1a28c1,78bd097f,aeee951f,fd4f46a9,4658a76c,268ee7b7,9aea4bcd,e75fc8ff), +S(16e732f4,43b4c616,24a495d5,4497a23c,c95612d0,58df9f81,11d1340c,4b2b8b5f,61ee476f,30ac2be7,e3ff09f3,ebf0b3e,2d76177a,30573465,101f4cc4,ec0585be), +S(4f30ef37,2c730ba,a6a40ff1,94b6b58f,436111d6,848b4e60,10be9b9f,abef17b7,b579a133,7f3247f2,8c6afc05,644778f2,3668e73a,a7c6d14b,649bf948,ef126142), +S(595a0d2f,1668c0b4,9ba0994f,3b681c42,6e3a67be,e957bf52,47acd9c4,7cb7d009,fb10684b,3ef1b0ee,37684ba7,53858b3,3586b837,aba6d82a,958eb947,2eca319e), +S(85dfb59e,d7ef6e0e,355e0ce1,304fe5dc,8bc6a3ad,74de3352,2089f224,8894e0c4,7a9b9ad1,10099903,d0d84a33,6838d422,5f98abde,32d82ab1,a383969c,1fb98bb2), +S(c8e13980,cf58416d,8719bc94,96e21774,c29f2e1c,5a36e760,2ce7783e,2c810fd5,5bdcded7,bb484d46,48bc40e3,ee6a3761,cf995e36,2af21f0,10048a91,6fbd4717), +S(80b98fb8,e48f44e,db69fd8b,18eec95,2404fb59,45c8a35c,bf3616e8,c746aecd,d44010a7,20622d14,6af5319e,155fe4ff,591bb829,f5086c7b,1fc1ed6a,32ccbaa5), +S(17629b1,cf015e58,eccdc7a,de049215,fca806e7,805e0e35,951df2ed,5cb87d38,afd56698,44f6aefb,528dcea4,29438e0c,d10c4b21,23f02444,a950834,97a61f17), +S(592677f8,695479dc,b215af2d,bbc90621,e7f3cba8,650563fe,1b2a8765,6c44107b,3741e4e1,b39b0e2a,58373166,854a1d31,ed062a25,c4e3e1fe,bc82e941,eeaaf50d), +S(98d5f85a,a93c9d87,e34e3bb3,597d9380,f0a7e5c5,b03ec219,4025c89e,42126453,dbe42a83,66753aec,61f7f01d,e5dfde1e,b4b989cf,95bd36bc,a66ddc0e,ffeea196), +S(9187b546,70d2b9a6,b711c88d,353bee60,72a1f5d9,ce75288d,4e6c9111,80dd4126,80e73529,d211ea24,d4bccff2,b9de3e31,c6307ee2,3cd9267e,b2d372ef,78f8d2c0), +S(e38c81ad,8ddfd8ca,4e01f380,78eafecb,f8edba6,8e33e565,309a3ad9,f0abe0eb,9f0ace1,f05f0a85,a1488644,88cce81a,2cf55eb3,a91fc10a,e6b82f47,60dbe618), +S(7ee9955f,99e218e7,dadfed94,dad7054e,3e0b97ba,932338db,69ed056b,6f8adf55,5244e198,524a105e,2b5de11,81d7bfe9,ad56aa0,128a3d87,8cbcc5c0,25b41ca), +S(eb9e5ae8,cdf64b28,76349aab,c3f75c9c,9d95a335,3214d0cd,d43123c,265b08d,858611ee,f67a32b9,7b8a9090,6639e998,a05d9bbf,8ccb7c1b,9e5eb711,4216b877), +S(2aa74ebd,7e8b6b2d,952effaf,e5545eb9,e99b9678,a2515698,975247ac,c83ff081,1ec12cbe,6877aafc,f353f641,1a5edf9f,e4bcc09f,31422df,d076932d,8f0defbf), +S(1b7b8fee,a3ed4af1,cf9b07fe,b435ef76,1d081b1d,f1007697,f78fe5d9,89076aec,b4aa0d8a,efbc71d9,d338e998,197054f0,20c5a2df,7a9504b1,ca7cb603,6641f85d), +S(3f293b75,9f152a4c,b92e319d,e5d02b82,f5dcfbc,2ee7a53d,fdf7ef6c,e2595c32,b67babb8,d1d1963,fd742c22,5ad5bbe4,27e57d6e,b9e17bbb,f91d2c1e,a455c1d0), +S(3eb9968a,c9b01fd0,882ec65a,8f9f5a5a,b0fbec2d,e2dcbf88,cc9a70b7,887ca59a,1a4de130,4a46fcc7,6719c254,dad5e88e,9d6a0839,9a9a28ac,7f171aa5,9624ee2d), +S(a559381a,f41b944f,e2bab9d9,62ec7c53,efb25ce4,1ff1a456,54a99f46,d97ce20c,ebc6f66f,75ad7322,4c1319c6,4268c997,4142,11ca65b4,58c5f79a,be0ba0cd), +S(a8bc942f,c60ff2e1,140f9a97,3d7e0b8b,77698254,57098005,f9186e97,9e430593,2a82070f,25480267,c4fca773,3173b354,fcd5cc1b,ae497af8,58b7d451,8f048c73), +S(2f456ca2,c4f8806b,ce4caf12,32446b07,3405dcab,7b3cdcc0,247dd079,adc7a626,7308e58,5b9bafab,b2dee049,9bbf60ac,fdb37242,3e915156,15314ffe,5ad866fd), +S(b56f4e9f,9e4fd1fc,7d8edde0,98f935f8,4c750d70,5f0c132b,d8c465b6,6a540f17,cd171acb,d63357a9,2c23ee52,fa7d2e2,de2bd69c,343357ab,b95d0350,fdffec02)}, +{S(ec474055,43c52e68,5c9e6c75,97616fbe,edb70df4,fe3c375d,d7d24729,2b120851,22c1c1a7,30066375,5ef8c2fc,86452667,90347223,f11a32d7,9f1c0169,a467530c), +S(3f50e502,c45fd922,94fcc46c,b3118a86,43af00d1,634bd694,dfc0eeb8,be2dd4d5,7cb992e0,f29fbc5f,2887161e,6d1e266d,f11fb723,3b6c020f,26eee393,fe96b526), +S(443007f2,43c3f6f9,76914031,c41e0d49,61337340,9bd4a681,f20e4c79,934fc2de,df67adec,c9ce5f6a,e6c8312,699e0353,68ee87e3,1e96790f,f0bd3408,94af74e2), +S(1e15b9e9,c28f77df,75837a0,cc9504ab,a3a49aef,26a88d99,543fa7d2,a875620b,2a081093,6afbc025,3808ba31,f5597287,e32898ac,77fd0021,9e6fc298,26b0370c), +S(cfff0258,ff6c0d97,99823447,775b75b9,1881e06e,bbd72ba4,28f8248c,5cf2144e,61e63569,5c4a8fb4,f68f974,219bbf4e,e0c277dd,4b74b843,88f99041,f97809e8), +S(2824f4b,f72f9229,2aa04058,7a0c5395,4c87e7dd,bc5dd199,af6918e,6db62f1e,16ab1473,3bf8382c,521af6fd,27f8b2b3,b421dbdd,bcf06c62,3bcd86b6,4bf33274), +S(5dc7571e,27d6b955,6c789b4a,80d49fd3,17416fa4,e04a7eb2,3cdbb88c,9c253a44,b7261e2e,39327d68,a5456abc,9d4600c7,fb6d6e51,a732c7f6,c64cbd0d,56de4a17), +S(e93f3aaa,5d9edc53,6029d332,9ac0bffe,af27d4dd,40f550e5,3df879a2,a5c1d993,25b442d7,f2e2e03e,c7f1588,16a1af43,b5d2870f,e0cdf429,babb19e8,951c0982), +S(8f91f5a5,7aa40d62,ba407d8,6ea5678b,65c84ea8,f241e2aa,dd6df242,52635a86,e9333d7b,d6c319be,3ff4f5b6,f286a8eb,27d5a1bd,29646cdf,77441c40,f716a6f0), +S(77d398e0,228add30,e9e120ea,b16436be,30c254ae,65016672,8bea1198,de1fb17f,749a20c8,ad6f4312,fb6e6fa,c390a4a8,209704be,3355362f,31db9b45,f3876963), +S(96976a85,b6dfc4b6,13dde357,c21c3518,a5f55c7b,a2d22976,592d7632,3b5a8546,96dc660f,8ef3b0b6,adbe77b5,69024fb5,dd713566,617cfc51,c8013f2,5b424e9a), +S(49093c4d,26194278,623c2ff9,6c8e2f11,f9edf3b,13c33099,57b57f1,9db451c6,5d53ff56,50b82edc,9dee9f43,ed6db93b,f6a26233,2dbcd699,130aa9ce,5130384f), +S(49187f03,d5f5f628,b9210b88,8ac4f1b5,2f754015,541e9f38,162e969d,6a99f4f8,276aacaf,d38d0bbb,416bcd0b,8ea590d9,7735a3f2,8de72aaa,76bed0d,6644bd80), +S(7d64e446,65c03917,87fe0b14,16ab1048,3a6025af,b20e8c19,3bbba444,2864c587,2c0da181,6507f8b6,4c9e5684,a4d53d98,d6b88215,772def9f,fa5a7a1b,f2b2ccee), +S(2223484b,9ee12b26,2a21a18d,2682ab01,c291ee1c,fe3b4b9e,2e93fb67,aa08535d,4cd26418,bf0d62fd,b266a768,5f7aaffe,d7bc95e1,be41c6bc,7a0c9076,1ace3974), +S(aac92330,7d6a55d8,552ce6f3,9c531d5e,afdd5313,f801242c,21df07b3,a656c618,93d9be6c,590901a9,1413cc23,94cb426e,e6a61593,93511c,e67e1ffe,68b8f3c4), +S(6ec1a0c7,fe40c40a,f3515ff6,60f0b53b,8fb6be3d,d912f8b2,c7a473d2,3e49d201,b10f000c,191e9423,60fe6b5b,2b6b7b85,73c0c2ee,384dedd6,e3dc04a9,7834f93b), +S(bd982a5d,a4d0291c,38568fae,ebc76df3,f2b0e5b9,1cd0d3b6,d2f32077,6c35c43,48566068,d5142f6a,90b13105,e7841d32,38d869d4,fcc7319,3e3cc9ea,76739c5b), +S(25d54513,b9084ddc,a3f20e18,94382290,115ad5f2,dc72c267,ba845b3c,6ade39f9,e908508,7fc5efab,a6f62c41,ea8fe856,226c8e2f,95dc31fd,2b49a7c3,6aa53b39), +S(29ab6cd5,add595d0,cb64ead9,c3d275a6,ce383f15,9340faf5,118ec2d2,9bb9a62d,54584613,dc27c249,d5d1210e,9e121aa4,7d606fad,1c4621e1,67f67b90,d8f3434c), +S(4cfd960,86f86d5,bd805667,55979c32,d5419dbc,946d63a3,40dcc6f,6d6dcd48,f032b7b5,9d85d0a9,fdc290bd,a1fc703,55b5404c,f70d45c,d15fa9e1,33ee9319), +S(9c786066,b6642e11,139aa303,800314b0,6afd4d97,e8314a1,de9d7002,5b7bbbf4,463a2ded,e2185c8d,944f29f0,140f6b66,9ad6e3aa,8ab6e292,a2af551e,685e58ca), +S(4e98485,f15c506d,6cd29d7c,3f9a59ea,4bfab065,78d86b63,f25e74e3,e7aea96,2baf3fb1,c26f2b0b,1a0725b1,5d1ceeaa,7ccece9,a1dd8f2,7f80d825,d8cf1d71), +S(8412c389,bc88e9bc,b157d835,85af0dfd,48689532,e38044b9,117b8acd,ce3b62cb,17eaa404,ffc1f62a,38f7ce99,6216b1f,40bb62e9,6d1f7a5,8bca370,c0d30b44), +S(31b9b8dd,7d37b38e,892e94c7,a5e817c8,ffaa1c1c,f56979ff,7f25815b,758b6d09,cdb680a,ae795ef1,f94e7e87,50ad9077,7a55eec6,c6f0795a,ef951e3c,ab45d186), +S(2be45d05,e89c58b1,8212890b,b6eaf935,6f03e37a,fd957291,4ab71a97,7af8350d,c3b05f04,c9f7a1db,b6689fe0,6ecf7a80,3ecaa147,8d09a1ec,9a7d71dd,a75406da), +S(5185cfa5,fe6302c,b5573594,61f375dd,c483a66b,c615b5f9,30abbd4a,5c7ae0c,83cc447e,53c91e07,6f44d265,389bef06,549b8d78,9776000b,5c35ce36,5fcff98d), +S(cd42328d,e4a16323,c51ef888,b7e67ba,f9ee1c53,82161b90,65e1db15,bddcffd9,caed06b1,7e86b470,b665de93,74725fdc,94792c57,5509ebfd,f012133e,122302f3), +S(7a1ffea,8fe5114b,8a638306,3b7811c3,25a40c19,42451557,679e75e2,b304ab91,1ef3fbde,4f0283ab,96efbc83,bcbb5a6a,d781a215,e6ff6262,ca50b9c3,986816db), +S(cf0bdf47,a3f15b24,5c7136c2,3a3e38f2,661fa8a9,4df29fbd,8b41ef22,c291dc6e,c73d1fe3,919e0aee,5b3adc4b,1a86e709,4b039302,d44a0d56,638c3eba,24857a99), +S(3a571630,935c1f02,d6fd8744,2c082060,cd5e792a,1c6f92bd,c4eed01,686df50d,7a1ec78c,4a660cd0,ae90c00d,1a8f5f22,1f5507e1,4487e5ee,2dea74d6,17a69494), +S(1c5e5481,32b49a7f,66ae9fed,8323480e,d1ab974,622e7cf0,8993895e,ec87fac,b00309f0,7c80b970,d446a605,e2b3d52c,5c215314,d901cdb3,aaa284c1,a03d2740)}, +{S(2b081f0,268d6ff4,1090561d,79144bb9,554b1f3f,1f0f2cfb,c9344e2,b692157a,597920fb,c528543c,26499af1,8b5e7d7b,5ebf5ada,5df4a46c,edef52f2,1e2fda5e), +S(2ce45dc7,d84d3143,884d6696,73738e55,e30f6045,8bac95cc,c30e86f8,71779827,deb79108,80a1b675,a628fb09,725c9307,d1629b07,8027f566,29f8560c,2ea80458), +S(9dfa0cb6,2a63244a,35ce3a0c,f102e7c7,93a4530e,21c6c03f,15a4fb91,e116c480,b01c1aff,902f0831,bc8cd268,663f0ce3,6d8e22be,86026460,a8950636,ce44626b), +S(61a32d1d,cbd7e887,def51ffc,9c1dfd55,d06d72f6,a73ee2df,f83cfa0f,52d47bb4,69a3b17c,fa91e3d6,faf28d83,2695aa66,c87b14ee,7b2d987c,80242fc,ce2cc42e), +S(8cbbac63,5414c0ac,b6d7f659,5c6eca39,886c3ceb,82549f72,d07a4019,e3076eb8,c838dc49,fd5af1b5,e503a430,71901bcc,90e1ea38,9f735e31,236491ec,43e7b621), +S(d3f77c5f,663c6efa,670b46bf,dfa96af4,fc4720d8,e1df6e8c,1ffc5696,f37cb55,aeea0c3e,50eee6a9,16462a13,90ce5d47,c060efff,1fd3108,1db77513,34300332), +S(6f774118,4a0210a0,79695d20,f93f861b,658137c,3a072076,7d80e5fb,8b1ebdff,c12aecc9,b55bff04,bd6b6e73,870deadc,666973b8,ec498bfd,bcc4c33d,23f5d674), +S(fecfabd4,897a948e,5fab7200,969f9955,9eb1c9dd,2a31325f,34dc4f80,13da72c9,ba70c9bc,c8048aee,6fdaf5f1,8ef638ba,ce739c0c,76ec4c13,fd4dd6c1,1663d02d), +S(d1a1a1d4,24fb5ab1,3e985c86,9bd7c02f,f81b4633,dcd22e96,c3f33489,2e80d543,cd5b79ae,af62769f,dce99530,8b921b5e,39a60fd6,f989dd7e,1d0d7219,e9ee8865), +S(7099682a,c3c083a8,80467746,fb924d4a,56f23d16,a3b57f10,1a824b9e,653d45,6a9c296b,cdd72c93,df840003,24ce78b9,1f9df6b2,bfa33922,ef32733,fe49cb31), +S(1035866a,4e9ff0fe,6b0066c6,3f0a2392,c0b8cd61,36e13ada,21f6dae9,f22c39eb,6390f9ae,ec1989de,2146cd00,a5eee99e,76ea4536,423e9bf2,c778ff29,85538fa8), +S(e18351cf,163e4df7,d31851c0,409b5705,a5ffd472,dbda5dd3,bf05e66b,fae50fec,264c1d26,41f185e2,72b908d4,77222484,c651e8e1,9a9e1fb0,1ec5ed4a,8a4b6c08), +S(dfbee778,ae4bc89,24f32c18,bc0a740f,d01922b1,28e1a595,283bfb4a,fd8f2f76,d11f9b3c,25ae3619,99ec2c9c,2f1a5903,d80eae59,e096c5d,c5e37201,81756acb), +S(842cdb54,414fa977,58ae3fb1,9316ef32,af9c4f0d,649f0abd,cb94267a,124b59fe,a016f899,288f4caf,dcc6edcc,3cbcb561,fdb4047a,f789e1a8,51ad21b3,be62f5c8), +S(3deb5d22,a81540ef,cff29ac5,585a056a,204e4d67,2fb858f3,5c23e939,790c744f,20d73911,5b24b1a0,a4b31302,73321dc5,d8b74398,d6516439,4e1423f8,b4022d6f), +S(3108e61a,1e0f079,f76e3ab0,d69cf068,779674e6,49768aab,718a09b0,640251bc,245a9f2d,141f390c,f1a17bcc,a06c5a66,5cf3a87c,1096f5e9,b04c4fd6,737d9a56), +S(63b9eaa,ce6b32cb,e4cf4a69,6599f8fb,3797bff5,9103ba0,c1351e78,b16cb0fa,938ac414,ef911df6,bda32b5f,1f69cd7a,87a25d82,177763de,568ca95,e846fa5a), +S(f37a5a41,cc96a04c,c882c27e,e362d054,7d6267f1,c91c5403,2daa5c12,1700abda,108bd6ad,27aa72de,48406693,758a74df,53a3ff98,d490e303,54c45ffa,c64638bc), +S(52afb7fd,6a16dc6b,98f9d7d9,555068d2,c2317035,b7492e8a,fbf28aea,3b1fcaf3,548d8ca1,2cf7a11a,b0100455,c7240290,6cb2e92b,101d1e2e,32ab263a,3f3de413), +S(f644fce7,874e9154,8f3fb284,b7d1ba17,fad6eb6e,c581f57d,5aa11804,86de9889,b2acbd8f,5bed4270,ec131ea,1891c99d,ddb46648,60acaf39,d68d2a54,a58b92bc), +S(863cdfdc,66065a4,50c2b7c3,1d694c58,e63ccc09,fccfacdb,4fdf0b1a,b150e937,14d168dc,c84d859b,55a3d5af,9d17ce4e,83bd90ed,55e099f2,50932dad,b5d2693a), +S(9f5569e0,50a26288,5d91f82e,9cacdf9e,f4487676,730f4da1,46ce8769,3d8807ba,cba008af,547e01f,6a9c6c45,8f9d71e1,8ad062c4,4b305b52,3f3a6655,3979a2b9), +S(a0f14b6b,99f0bd74,cf9864bb,17b1c43d,51ade513,6cd72a15,89312dee,706d50c1,e2bd2d82,c549b4da,cebfb888,c1a7c5d2,f0757fe8,53e07fb4,747eb7a1,542137cc), +S(9e7bd727,fbab45a9,db36d17d,5e5437eb,f028a10b,392ea470,d5cff0d3,2e9bb0fc,fb52eb32,e43133db,28125280,e3cc55a6,76877c58,b4051f70,9c031f84,24f12d9f), +S(7d8b1a30,4c0c8931,2d5d712d,ab396efc,7a117483,7f62bb38,62a81a3,660b1068,472a2dbf,ee99c398,94d14c1e,ce87cf17,c8aee10a,4720357c,c5ce79a6,19aafe2b), +S(d5eb073c,a5afa126,70602de8,417fe50d,bd8f0768,d615ef2f,565e421b,4e7842f9,52571e4c,e4f0c424,fd288f3e,8b6c54b7,7481c3a,43230fc7,4c6f48b,d4041089), +S(3c41cd8a,77728b07,ea592254,5ac45462,2c7927fb,6a7aeefd,61635cc4,217acc90,eab0f00e,84099fcc,c2f4d339,77ff7d68,4c035b3f,34c6c4e6,aa812c9f,43af366c), +S(1eeeca5e,cadfae31,188218ae,7beda45,57f85c25,5c99dd64,1d00d8ce,2e6f7809,d7e5c2ff,4ddf421f,cf09b655,113b8cf1,a4c25e90,d02b871,91dbac55,d6606ef1), +S(54c13737,454414e1,76bfaf1e,b4402bf8,678daab1,555412d0,c6d3fd44,653510ae,753f6a,f382d0be,f1dab47c,1b9368f9,57d586c4,acef0d19,dc241ce,f008ea3a), +S(4d608c37,1fd6f635,9ffc57c1,9f1aa5b3,5b0f5702,55851cec,34278d2f,465fc8f4,12d1592d,c2cbccc3,7e5c9fae,4b864e9a,ca6967e,9d4852e,9adc9e31,1000670f), +S(71157d64,8c0a1a33,19b713af,f806cf9b,c91a446e,2ba48ca2,fdd1ed4e,8c43da59,c2ac2aeb,a298fcfa,c0d5eefc,6eae54ec,330f5c0,5b34952a,9821ded3,9b72d383), +S(327f876c,93652555,fa80a054,968b4712,930dc930,12ee6b8d,c10263ed,3b89a762,4d2bfb15,4cadbfd9,4f6696da,a1e66846,8aacaf8f,1428201,636026a5,46dfc92e)}, +{S(4d3b98d0,b5926a8b,3e5622d6,10b30e88,caa6e7ba,eb10bc3c,38aec3c9,c1267578,e84056d8,4726291d,e6880a2f,2d3b0b01,371dfa27,5b8c9cff,4805d18e,a5bdc788), +S(6e463689,111d1a5d,d10b09e1,5d0f438b,1cebdb67,7a6cd230,bf6349c3,70667db9,de10eb3f,5d2f4320,7265952f,b33fc23f,154972fd,d3394cc0,21b66276,1b51db3), +S(48235e7b,76c94c32,b0d21bf1,7fc215ed,df036366,a9ef494,19723485,78db8943,4f5ac8ce,36c77403,b2fa83ba,1fd0e88a,3da4c8cd,3c10ddb,aafe2d0,5da40a2d), +S(668af7c1,4063dfba,1a4187f3,f69cb457,cae4edbf,a3bf9669,4080b6de,bc3e2f0e,ec95f37c,7bac26a0,df23275a,283828a8,5a102d8,f33eef1e,87cb56c1,850740cf), +S(d4426fcd,cbdfd904,725fb501,656b9f2e,2a9f9ee3,c6522064,f078165f,61c31d97,e73f2a38,c56838a7,174ee704,948d28fa,5b5fdc34,7774df9f,72f27834,a85eb4d), +S(d0f49ec3,42076b68,4cd91172,f15584fc,ea38aaf0,a3201063,f854ff1d,f68d4600,28d95ef2,82dd7d6d,72be7854,e8858b1d,a142002b,ad7b7b4d,bd1e582e,94341e16), +S(8a36f3c3,50bc0f1a,1b1687ed,4ff83a68,1578d74c,c28fa875,f6969e52,4887bbb1,15ab9e05,c3ff823d,ba090e21,1033c34c,fa713d39,feec4346,88e3ecba,4b431e10), +S(4d1ef23b,b316e821,7d2cc409,a1baa273,cc06f79,8fdd4d16,5d5b6805,3718e238,fc37e62b,db18154a,2add98b0,ec221e8b,bd1a2096,ac2dd1fb,cf8e2e64,821301fe), +S(eec1f8e5,76e87803,bac48bb4,65ed923a,a68b2965,64365d45,bd1c24c4,cf7041b0,2c6985e4,7cccbc38,3b85be66,ab34a166,c98a8000,aad08f73,616e4d2,2a15a009), +S(9fbc20e4,de372a38,90443786,bd7cfc40,c6195b29,4cf51874,6ccd9ecb,cee223e9,f734bfc8,a6973209,903edaf8,52f63bca,b23fc1a4,879906b9,1c5df169,9d24683a), +S(7984c8ec,a2b02dd4,e8b9c69c,6f803418,48f108fc,b63d7038,de58e567,e64a894,49adeb11,13c705a0,9eb01e50,dea5be48,86e5d424,689282ba,6d64f745,74f45e8c), +S(29a7400b,16f5712a,2324becc,29fc4b98,57fbb926,f8741dcb,324c26d9,6cd178a3,90770be5,5c0a94a8,16bcfa38,aeab11aa,5ec3b7d9,eb4e7d29,1bee1c02,69e87267), +S(8299d2fc,84770bff,a4e630b9,8f2e6744,99b1c7f5,719e907a,d70515f5,140a00c0,c790968f,a3c3d4ee,3e25a1ee,8e1d4923,3c22f034,ba7c172,b5d7d91c,99eabfa8), +S(5cfbd498,5b608db3,5d1a2872,b9cd03fd,d775e498,4629f41,61a2bde4,fb2582f1,8288fa89,81056333,acd1720b,bde757b4,e83d0a49,9c5f2220,521a0bc8,dbe827f8), +S(281f1fb8,e144e39d,9ec2104a,96bf0f1d,494eaff3,57fe084,63825228,ecd286e1,ae40e075,d19ee5f1,1dd7e22b,f1c277ed,9a02abe9,975609c,a7c811f9,7c54e493), +S(51698bc6,73d3289d,6b4882b0,cab14e67,97d31221,e5bc6e53,af061aa1,9f546daf,7b850099,fe977f6c,f50abe00,bb3a0b68,90f47c45,24e9ae02,94304b6b,20bd986c), +S(db701e92,9b696c86,d7fb459c,97af90df,ef847bf5,1d235337,2a2a4792,5fa8ae53,edc7e98f,1a108bc4,8fdbe65c,2904058f,7da5e188,e71d194c,4e9dbfe6,8a55d18), +S(c900f57f,e9a31d4c,9715a822,5a906e90,22d81c12,714006d5,81be0c7b,aeb5a490,8493eb00,90517d9c,b70a4bc,39043ffb,e0863475,17cde2,a9bd0d95,f616bb66), +S(d74e842a,fe2da0df,df6342bb,582fc223,717e0641,f1ce0e14,584c5c63,f379ad72,cefdbd7b,b4ecbdaf,409a0fa3,9a0a305,b1bd986,4913f977,bec6c47d,5d525c10), +S(b00a5f4,f033d126,64366147,a1bbb9b6,ea60a38b,863c5f3a,e323e8e5,1aee200c,11e9f1f7,b7701a4c,26a881ce,30fac1e0,92e157d7,b9c2e4ce,cffeb38a,172ead87), +S(5772b134,68bf9f09,d26074c5,16dd7472,d3a83624,92306cc5,c7544ec0,d73de280,2e2a7931,aefe2a31,6dbad1c,e7f9d42b,7f38197f,43024f16,9e27fbc,7af31d0b), +S(8bf8af02,ccdafb15,598f6725,5f172fb4,ba8960e0,6c81ffa5,b4c1c313,6f95f29b,96041af,1efd128,ef133e5e,b0aa3d9a,6ac3a651,92598b09,ed649847,385a9b2c), +S(292889a2,d8329139,3410385f,cf5bf489,7e1ee23c,e0e3b5ed,82ceb340,d89f87a5,41099fb2,bcec7e07,d4d4ad14,3cf605d1,b0a32487,1736063b,e49b06f6,d648aa69), +S(ad227b2b,737dfd02,665c15d5,9b28c7e8,76413dfa,25c9068b,90efa79,ce83142b,82f1eef1,7e2f6b86,87137302,741f8486,26fad679,9c6a22fb,3a49e341,c7e51e9a), +S(b4245dc5,5df02839,4cff2610,4a4255ef,89f3e708,21541c3a,4631ee4c,145bf85,5a40f72b,7a67540b,6858e5e,b15005c1,3fee862f,3cc54a52,7643204f,d0b8be2f), +S(15aaef61,568537a4,695c1990,c05ecb9,2c605232,f705c3e3,729720de,7e9c2400,e6efd1fb,b74e9e43,ec1244e0,bb4cff2,2a5ede8c,848a4f5f,5eec6f8c,77b6f5af), +S(ade2e63d,4a828328,b4c53763,30790331,734d7f90,37c1a584,59570c8,f31e72d1,c42898ab,3633dc7b,f3a454f9,d5475c4e,fcf1f786,d1f609fa,23616f26,b23a1a97), +S(d8a9043d,297681ea,c5ed63a5,de306500,6b66e4fb,167aa5ec,c76a8e2e,df426e7a,cd3de058,a0a93d7d,7122d777,1446b2b4,d4cf53a7,1759fea3,78adcf03,5093f4f6), +S(30651cb,592d282b,5348f192,5be3f04d,da5033bc,39e2fc7b,1e61500d,9769b57c,dadf77cc,44853f67,53b1dbdc,17a97d3c,e6d5b2e7,8c6087fa,800c5af9,ccdc54c), +S(aa21c60d,6f7d6253,9d42bafe,95c58f30,33c0396c,fa0ceef9,6d2f91ed,d6569044,4d519779,3b19515,92e2d952,2be520b1,11a5453e,ec6d7ccb,3e6db3bd,3d0c84c9), +S(5335cea5,e99eeb23,765b3444,d9bc7be6,1da67d6,91bcc42f,d43ae543,e9c22bc,c4072fdf,8963addb,5f980f7f,f314795,373cf3dc,935e0e64,c3d3d98c,342530cf), +S(708a530e,9e52c73b,ee87c9d8,8161c810,5d5762,2c29ae69,1cf999a8,3a1187a5,6477b7ee,1e065768,569a923,4492c7d7,c13258c3,92cac175,a75b0e63,b8c2426f)}, +{S(3fbd5a4d,ebbeff54,8c2271e5,33dbaed3,fb8ccc23,e3fa2579,4c8f7fd4,47ae186e,fdee4625,45bf75f5,5c29a724,6496d970,4616c54,ba01d0ba,feb9155b,cafdb555), +S(c1483ec1,78ba8414,c371b57c,49c687fa,69669e2,e3e1067,cc6d2a93,b1a9d24e,edf94395,962adfed,c2ebb3bb,29346136,e4dc870c,5c76299e,3b07da35,6bb26bed), +S(26df4b09,693a3905,2cb7a1be,5bc2cc97,222b70e3,3d297a54,43741228,beb77017,a3d6b908,cc6d5f80,aecda93,99e17a8,ce33c423,f00cfc4,dea8354,af502760), +S(b6c265d5,90475506,e15b2388,b894718b,be67aee5,ba40ceca,51876946,e336d903,b451d3f1,2c666c85,bf9486cb,296c39f9,49f9f98e,96d50a19,80f86f85,a1efb999), +S(da6cf69c,feec7b1f,c848639a,7e27932a,f49cd695,a2e56a50,693fa862,6e257c66,4506f44e,e6e0d822,7e67dc4a,9f8e2ec2,d3ec0c3a,c2a70c7d,d25fa9c,34cbe3ae), +S(d57648db,adf18b77,db185ffe,3f86f859,6adeec05,ffb86215,4b894a0,75776eac,a3f2fec7,7186d81e,4228cb1f,691e00e4,82a125a5,bbe9e6ec,45a53604,4932491e), +S(4de6cc4,d64d52c8,49c0e8d2,45409ba0,88248399,1916df3c,238be4de,ee2504d2,b389e7f1,ca72e9e,1cec2ed7,70f21441,590f0bab,1b963f1c,411f9bff,d3df03f0), +S(15f1bb11,78b01439,f26412,1d36a44d,b8333fbc,eabeb471,da2e6c1,1b8b3ee3,bf137117,35e10854,95acf3ad,97fe510b,33d6628f,e67d0067,499169e6,6c12274c), +S(badc76d5,481e77,9df71d6e,223c6965,9e9ecba5,8415a95b,eb7118cc,b1f931a4,475e47ee,115d258,3f0607f1,7542ccde,626e6d57,6ea884f9,61b41354,aef37247), +S(13015ae5,d770f4a9,75825bae,a6cbbece,78536dcb,78d7116e,d304aaca,199add2b,f5e28585,7a99ff0d,a4fd15e,8ac650a,98421629,aa102bca,25df3930,7e5cfcbb), +S(7734d2ac,707b9b53,afbd2a64,50c9b609,1905c391,958d7215,f92353ee,fd3c7be5,751d38f,ef48bfea,8fa5de06,8188a658,ae6c9c75,a359a4ea,efaac5e0,b5e859aa), +S(91814384,7fe2ed34,e9cc9c61,3fc2c67f,2b76a208,561d0e06,271b812f,6c678856,9a97f6e0,9888e076,93c9ebec,b8773485,c3c5d208,c793a77c,6984fb09,cdfd67b2), +S(98c516fa,2a2c8073,70ca9d7c,b4187108,ea345652,c8f814b8,b4a9405f,b48c2469,7b3446f3,2e8c4764,a8eb0846,4be3bc6d,f42b8d14,b7da65a2,ac96a018,d0831c7a), +S(5691d1e3,713302c7,48bf633,189ce032,10832e4a,9af1dbc2,abc3e99b,cb4faa01,d802e21a,fab84c54,5d665ed3,54130d9d,f7f18283,30b3a1fe,e30c2298,8b71654b), +S(1f8cb624,6440b640,aadba62d,c02f4ce7,a0ba9be7,d535987,64072fed,95c0d1a1,647a9dea,abf8247e,f46b60c6,53cdcd5e,cff0d1c6,88b7519b,a778f9ff,c894e1f6), +S(1489af53,94878f07,5cfb2e20,931fa3a4,e585d494,78818e4,f47f05e1,2be54d14,cd5bd721,4e535822,43270bc2,dc692ba4,c57e494c,eba92d4c,dd2e13c8,e24d8550), +S(66159248,2b2229d,ea70ff76,d2a5e70f,ad1905c0,9211e3d6,2d1d652f,ccd709a7,8f5ab85,57948aec,67e7b538,fa9c704b,ae939c22,4041e6e1,65f6045b,a6fd0fdf), +S(bc894efc,d0fb7497,ba70d654,961aa79b,6ac5a795,95537c80,82c525c,2c44c3a1,d5254292,ef0fb6fc,db587393,3b17adfd,87d13320,858ff783,75e356fb,b0d3415e), +S(f117d7f6,85457601,9b559bf5,f5bc150c,13363e7b,72123435,b441d98b,d169dd27,a8f4a23e,dd0d8f2f,8950c124,1abac43e,e629b0e1,8505c3bf,780ea378,20c8623f), +S(2a8d99c2,65a66a51,56b60556,775c61bc,b2a81a62,34896a31,16238c2a,b7716ec3,5e842306,efe11f66,5a049c0b,fe3ac74d,d72c5033,6dbd04bf,2a77b0d2,4d7ea651), +S(ea747597,1a6b6d94,2e368bcd,9979876e,afa4622d,313d819d,5e8291c8,2da95830,41d4a478,e0950bb9,e6595bef,3c197e5,d0f77ae,6340ca8f,2947fec4,70465193), +S(114150c3,fe8853ed,9f3e26f7,bc9f3d6f,aa50ba0e,6ae2d8ff,97924b04,dd9678b4,5530c22f,4ac30716,2b272015,460426ba,9602256c,ab735174,1a2fbbfd,cd71d134), +S(65d96017,c91a746a,656eb595,d39dc9bb,3476dc0b,1a1036f2,df7a4ea8,1846631,de46bfad,6999b108,1f358edd,7809919e,4de768f1,fb21dc09,4b248bbd,56b3dc76), +S(f2aec214,61c040c0,ebd18204,bc277312,732b452,266bfd55,aa071853,e458bea7,52a1b71a,eefe2c48,5ae2918,e236f1d2,1622d37,13b4bc04,36124567,d48cc453), +S(370ef89d,c39e637e,8bf6be31,63a4f76,7cebb202,c868647e,db18f991,977681de,e6d402ba,9769363a,b963729,822bd6aa,9794592f,36e54461,579ae53d,4c8bc4cd), +S(8db6356c,4f31f46f,961e4342,a1ff50a1,8240629c,a0decc36,e1bb24af,f6742e57,8ee033bb,96958466,15626ad6,736e9025,fb76320b,c2d0ceb8,ce3400cd,743f934f), +S(14a1a08,502510e7,1060f291,1316ee01,b1fc2bd3,c88eaa1b,656cba0e,8e3515e4,5a4dc536,b62c349b,c9bfc6d7,fb677231,1368655e,fcb9c89e,572aa58d,a57f08c6), +S(d530fc7c,4d5b4fd1,5f44ba0,c0f08f24,889b278a,93ee30ab,935fc112,5e244a58,39c0ea88,5984c2d1,d5119a28,7cd842ca,d3cb54c8,ab6aa222,c01e7152,98aad10f), +S(50f3c13c,a474f604,ca992658,bca68207,76acff7d,d507d63a,b5e18b28,5c5be81,685e151c,7d8fddee,6c9d8513,dbf167e2,c32dd70f,b6932397,38eb63fb,3e4f7afe), +S(c0a72dda,13174682,726ede1f,7ecbaa68,b4b137f6,d44298d3,4e17b7fc,10e19d4a,1e45ff3e,4a4239ba,4a897489,a265a60d,9a91f3f2,83fe2e75,9e770156,c9ebb3ca), +S(7121e14e,7e2a2c57,76b5702e,c83a845c,28785c79,9099a007,54b50fca,b4d9279c,e6b3ff5,ce62fa35,adf45e69,2ccafb91,b805d7cc,b6eff2e1,38dfd680,d0684401), +S(c0c01f34,ae41b8cf,e466b4c9,c6a5d5f6,14f570d6,fcbef768,a81a6c8f,5ff4adb,f47b0a41,1bca80a3,836c85f4,bf8a4731,3243bc2e,8f2ea47a,3b1008b,53caebca)}, +{S(4f20ce51,84fb2949,443286cd,8ea201eb,15248749,6e15aab6,f3ea2597,d4cbf47c,bf37770,62691c5a,d6c6cb8d,c30fd3b1,73578a3,bcac43c2,c8404b6e,c085c97c), +S(17ceec36,7fad4365,520599d7,62c66c12,5abeff81,ce7242dc,bde4e799,402759c0,91e024e1,e2147fe9,73091001,984dd3c0,9f887257,73bbbedf,47f00c7b,c5c9f626), +S(dcffc4a,5557f2a6,ac7a3527,5a8228ec,325ea0bd,d9bf52c3,8a78217,6bd716,87658163,dcfc39e2,ad08a499,898a1505,988d9b86,72b6d1e9,64e6845b,cb41129e), +S(625fff43,45337aa2,1efa0884,73a6662e,d5340470,a79576a4,362e30dc,bcf762d4,92ad0a66,d0bea2a6,d7eedfe0,e33295b9,3a656e45,9220026a,5ff3be8f,83184187), +S(410b96fe,7db23faa,7d123e97,c1a82a9,7b24a26a,80143e50,dcc6d9a9,1a6e81d2,ca0da356,dce88799,5f8cc790,64d197aa,6532dcf1,20fe93c3,7e2ff4e2,f14394a7), +S(8136e51d,ca68170b,136d40fe,76980b4d,d4f435fd,e38f3017,99de734c,b2491551,823dd1ed,de1d326,676649a3,9d5ba083,7c48e180,ecd0a648,eaffe7c8,2894e819), +S(64a67d9a,a7a31390,3ed9e348,e7300917,6c1d52d0,be63f54b,aa3ee8f3,f1227a52,ef770581,df4aa013,6d191e99,cde7f42,a14fdfbb,11e1b709,bb540100,1dcda1ed), +S(5fcf0465,a905aa8a,a1da5073,d524e8a3,30af663e,f4307359,c03a4c6c,c423dd9a,58641e67,fa821fc1,2307a66e,fe0129e6,4ace7c36,c3f5395c,db87667e,5e742a42), +S(aae6747f,ac3d8c9a,148009ea,c2d25574,39a8b546,455fb3a4,5016891a,f9372dbc,66084f19,b1d97f2c,22e182c,d5450d43,d56636e4,92651cf6,22772a7c,5b46d9), +S(377dc2c8,13e36bb4,642d1e02,cafce754,2ac6d9fd,c2212edb,5432674f,38e242c7,8395dc2a,39d3b1cd,ae9d7d37,d0c4597a,11f931d8,75c8bcf5,8eab03d3,674d5841), +S(35c598c0,7ac5dc3,7afe6895,29d815e9,406e2608,292ffa0e,7b24df65,3278d8ce,e793aaf1,45f538f6,c133309e,53cb5343,dc1dcc74,985c57f,27361c6,aae23e7b), +S(e9666336,6bb286d6,c86f425a,2d5658cc,1d733223,9ec2e9de,c8ab7295,4b329845,908dc533,b6098e9e,9b737e4,b96e7345,e635f591,60bb3df2,75e165bd,d1cc5998), +S(46fab0d4,7fc6586a,31cf861d,ff5e0bb8,cc12b60a,53103007,c8974ab8,204af703,845ab7de,7654fb36,618dbfb1,287534a9,2d43db6f,2a2cdfe4,5365b4b1,893fbe9d), +S(4d80486f,fe748d1e,f88aabff,76bb82c6,a45db736,76ee0ff7,d77cdffa,2c69d07c,2a52044b,d4fc6a59,fd16dabb,df35bb6,8057ad4c,292e87b5,528a3847,c8784638), +S(2c1d108b,f4945c0e,df62cc15,6bf0830f,7a45ca,1baa636e,9f759bb8,bf078a55,81e34495,d269afbc,1be39ce7,5417ebf7,d45decb6,eaddb635,4480a7f7,8d7dd34d), +S(320a08af,eac009eb,7f254b8d,395d836f,ca6ea527,4e2f309d,dfb7f120,2f1b3cdb,75269a2,41199c0e,5f1cd9e2,d102a294,2324a3ea,cfae231f,99ccc5f3,e0af00c2), +S(8b893fcb,9a524af2,6de5aa38,8ac3dc,2159817c,7062e5c9,d5c9e7f7,dd889ad8,cec6a5ba,481f7e3,88c1cab,c11505f2,39afa143,68977ed6,52ea2d6a,19d2cbfd), +S(ea89b95b,36cd5203,22c8e5af,7461f9e1,a054f23d,2720469,fa74cd67,3a52aab5,5325d16c,4b866865,2437b6b8,598b31c4,59e6101,2cc1b147,e0473527,5935ada5), +S(cdfea79a,8c16ce78,75a9fa1c,5b7647fb,ad641ffc,5b73fb31,d9354a1c,3c1cabfc,184c309b,b0f52999,2a3f6b93,77b9e6a7,6da6b943,d8031408,b71223cf,b3ba9100), +S(3daaaf0f,785a6397,c652331,630931ee,a975c522,35899736,1b7e5fcb,409880fa,952efec1,ebd4c107,b26a98f3,c6683903,a498c840,ff4a36c7,ade569e4,c899919b), +S(7cea5226,a56d21cd,45bfdbb0,7fea6670,40247c70,ef43da28,d1f8bbf0,6e4ef2a6,b03edff9,6a5f32c5,6f8f63f6,ba9feb68,f43cca62,391ea587,81396c7,5d963b67), +S(1f5f4c27,847ba921,c63cef52,8b57fef5,5bdb5344,ea67a23,c173828d,c59199e1,d37f6918,e0b774ad,317dbcac,75c82188,c8a421f0,ff5756bd,853a05b0,c95ef089), +S(36cd4da9,2a77613b,6417deac,1d9a0dad,1bf0e506,de26b529,7fffbd03,4a4663f3,ec1dd8f6,6226bf5f,fedb071f,7027f9d8,d931e6af,e378396c,d0d296eb,a63737e3), +S(9835c156,1be21ce5,db788f1,3c0aea13,fde6861e,97cb2cc7,a67fbd37,17eefadc,7fad454b,7372d969,a6e754ef,c73415d7,fcd4d589,c8e255c5,1adf5a9a,82228f42), +S(5e218414,d9c9f0ad,35ded20e,76a484a1,d41b3894,ba9d3be4,bcb4546b,371d0e4d,76966ecf,9c8f1c9a,452cf971,10ca6555,2ca59d31,21092e93,333bbd61,6eb9cfcb), +S(b105f4f4,40e7ea66,e3272da9,d6b2b76e,d00e96a5,6f95224,34ca0df1,5340c585,9e8fea7f,35bc9eec,f82ae118,bcb6dc33,acae587b,f37b149,1f8312e2,4ffc86d8), +S(81d5713e,a732b4d,98d085a9,75cac9b5,3fa65171,e5cf49f4,684a7856,7c24fea9,32480cf7,a0bc0c50,a4de8200,9343b524,4a0f2aa8,ce67b11f,4a5482cc,6fa00bf2), +S(d47b4f1,88f5e7ed,a9eab2e5,8ad2c140,c6278d63,517bfaca,8cfb64aa,cfbcc7ec,524f6580,9d3ee034,afb1e64b,1a0f8ae1,1e464915,3722e345,bfda9671,1b94a5), +S(16e85ad8,6a953564,39b97957,7bedd0e9,6e2eed72,76ba269a,626fbd58,447996c0,8bf74f51,4bdbb6c1,4de81a3,1ff12aa5,de49bd52,63a962ab,b777439a,47eadee7), +S(c299c6b0,6e6c78ae,852bd55c,dea35f99,d264cb5a,e836b77d,ab209ac9,c05201e1,a558c66d,c9ee7fa4,c777b0db,288b328,428b230a,7c53d516,522ccec4,af0ae08c), +S(63c4624,35ef974b,393b05b3,7d1c89d7,b0d8958,ebd541d7,584e2bbc,7235c795,1d806446,ecfc7bfb,bce099f2,6ce37a49,61b53453,5b65642,c0cd23f5,a4eef9d7), +S(6d36d105,ed8cc5ce,53f2cb69,8ab620f9,469a3e5c,b25bf6e6,d413f414,c5af726a,1b45a3cb,1c889961,8d273993,6a3affd6,233a66c9,4bef75ca,3a8fb6e4,ec05ffb2)}, +{S(abdd85c7,a2f8bc31,343382d4,e405978,3874c8d0,1405ef14,85047cf7,f0f71d50,d5a03157,798fe828,a03ab63e,84bb007,b53a5315,1db7af14,e4ab612a,736232d4), +S(31297c6c,f567267b,3c8d65a9,72afc752,e8525eb3,de2958aa,76f72e14,5ad903d7,f4735877,a6c6d89b,d1beb50b,edd1235b,5f5e5d0a,878e4610,e7d756c5,34813389), +S(64706e69,11a7d0a1,2e587c86,91117a27,cbfa64ad,1d5617fc,81e55b8f,64e0da86,59d9af3a,419957d2,b3de7570,15fd8531,a5d07430,5cfd7444,5e7e70b3,57e62772), +S(a4988ed2,89d8397c,f1b897d3,b81d80fa,92658ce,2b935f4e,e2e3f0f9,b193af51,813fb8,73270570,50f23c3,f8082bcb,563ee366,1f6b2af3,f631f5f,916c8478), +S(3c2769bf,af401993,595a01d9,9c72a6f2,699591fe,4b869077,8c6b5ee0,f172a866,f3e0d8b6,cff168c,95873f44,871d27b,df1e79a2,d9e0bd4f,6f90f682,538c1f24), +S(49d93e09,df655edd,19548fbe,affce201,4c6822a7,e196eb98,b9ddfad7,3cb70125,26e6957f,84ced17b,c64f710f,b37656d,31ba088a,98350337,8f7323cf,c57f0eee), +S(53c06842,49997cb2,6e5b4cc,5f166fe7,db0ec0bd,52639a27,d8fedea7,214a78bb,8a8dd3f1,b3081dd4,948255ed,dd178089,a0fa7342,1ea616a5,1f639057,34a489c6), +S(7a8e7d18,3f2aa640,d0e2ea02,4cdca5fa,1767d9f,9ae38805,5d38e8e4,a81d33b7,c2fb92e3,5556fd14,4a894be2,3d97c6d4,30872ccb,25e239c0,d959a24f,aaa77397), +S(a5221a2d,29cf3ef2,f066897e,4ee74ac2,95b34cd7,54390814,297537ae,abdf603f,ec0ff395,8c3a1d1b,5a379417,5a61cd97,782c9683,aa2c7c07,5d147db0,2b134278), +S(3f49da9c,1d62eccc,afc4b88c,814e44dc,8440341d,f347de1,fb60126d,59578dbd,c3cf8e96,2fa9478a,f1be08dc,961734ca,5021a65d,b1b45f80,78fa8e8f,d2813a79), +S(47b16636,f5a64b07,534be14d,6ae37af1,9da79b42,666b201d,d0afda9a,2daeb6b6,f1218111,31ebd87e,e1fd7c9b,d24a0a11,a12e842c,6c00f445,6a342309,9b171f12), +S(a7b5a8ea,1f23ff1e,c1768eaa,2fef0d66,b75744c6,dc925d3f,9068beff,d69b32f4,fe01a23c,b0e5acac,e60058a2,889f9434,9ffce6c,b24f4a3a,662e0079,99bcb690), +S(3e14e2c,e7044716,d42e9b6e,54cb0500,a1e4374e,18917336,e3205e31,4a878b47,18af982d,2c78ac23,818644f1,ec657da8,ad66bdb,3d5a9b84,3f8bb988,4ef8dc3f), +S(71393e6,746d3072,830299c6,c1244303,750742be,361c5f08,6eb314a4,76f1736a,dc30a7ea,9b644339,ce8f1fe4,eeeba07,5bb08934,8135e819,cb061559,aa14e42f), +S(37721b73,e6861f15,7993696d,aded49d3,78994f3d,e2b573a7,defc907e,d6f301f2,ee0e1755,d8efb25a,5cf4d783,ec847425,746fa442,d460cead,56e73a69,42561de1), +S(7803c663,509fc9cc,55b372e1,dc0fa76f,149a0ca6,3db4516c,4abc0ad7,5961e4ac,356c72f7,794a70e4,db3463be,eaa847cb,256c58cd,b6a7d862,fde4feef,d896a46f), +S(32976d3d,a3d033cd,c073b0f,c7d2f445,25646893,fbded1c8,1a0a1761,a8703206,5e6b7900,a069ce4c,65cd84cd,f290f092,2b936bda,af6ea40d,9c36a321,a7c9dcfc), +S(c52c7b18,b5fae5fd,a4e3597f,39c96b8c,6d6c856a,80f1210d,a1ebfc15,34850763,b87e50f6,20b66865,307d0747,a02ba22a,b310712b,cb0bab6b,963c589c,c5a208b1), +S(7de59c8c,3922fd51,68f4151e,cb783775,cd0bc0b,1185ecd3,6ee075e1,14e66cf7,688e2cad,e4d49da7,fe691497,412c9372,c67288e8,ca4b64de,308eabeb,723fda15), +S(ac49d6f3,32cda691,c345f099,667ace08,f6496126,830c39ed,877223a8,cedc8be7,267e6a52,5ddae4f6,7e05f0e8,52b9dfe,5101c491,64d791c9,82249937,c3a7b031), +S(5a92401b,698cc394,c9b714c8,bdcd92d1,20fa72e9,b1311839,1c383024,f469ed22,e29f2926,84c255a9,a739ef0e,5d13cc55,987f5b3a,5c6ed623,29431033,70edb4a2), +S(3609dfba,51616095,ab060e77,d6779025,6456eddb,f4b651c6,442cd673,f893878b,f85fa9b9,442050d8,ad9d9314,9ede8698,91dfc99e,c05a2a48,5854cbeb,55a6c380), +S(332bb85e,92c90a15,3bf602f,45dc33ab,3dea5ef8,7034af81,944113a7,4edc94d9,59b6c879,5f2a824,96d631b5,ceff8708,507db41a,375c7257,7533d8f1,461fbaf1), +S(16e9e054,916b894e,730d7126,27b1bc81,e7689efc,23cfeacb,a423362,df49d87f,303d0428,b701f1e5,fe8ae460,e54adeb2,d4b5aa93,a9c7d7ec,7b903cdb,20e440f3), +S(4e62ab89,1d4c4cf0,2c44915a,4e2fd522,88d75aa8,e22b7463,30dbfbca,97ed9515,a7c21be3,3b5cd522,4de0bd25,faa9c2de,5d6b2f50,b50a6901,b7167b3,c4def4fc), +S(649eedbd,5612c429,2aedbacc,b846e759,4a2b5870,f21452f3,1ac9e697,fc055db9,ca694303,ee206a4a,acfc4cb3,1aa9f117,8fcbe37f,d6bd11a4,669289cc,7c37b0a), +S(e858f72a,5fe2314,951ca096,8ba59760,e3d2a667,e76dcae8,c3ae2d7a,4721afbc,f1c7131d,3e2d0468,ebb89bce,700e0eca,ae83afee,75620938,60e1fc70,cfc7810a), +S(cd351498,29ccb1e6,9b18e35a,72a24b30,e074793d,aab4028b,1c5eefe2,b7b3163d,6bbd52b2,93b43cb3,a19f6291,69ba5b2a,59785099,16842093,1e58dc1,a040c57b), +S(19ffe344,69ba3e43,7d901863,3be7c298,ad8b65a0,49c30dc1,bae30ca5,97ab38fb,c33ca345,efeec662,96802e95,69f0f34d,12ceb64f,30fc704b,b77261f0,ce5c98eb), +S(8a2f772a,a38a5b55,a7081d0a,61bc27d5,89f9832b,1326a230,d81b9f58,4d634293,a4707a0e,a7bf528c,ac62e361,6f09287c,182aa3b6,6862430,dcfef3c2,69d1567), +S(e583bee3,1dbc8f0e,572eb18f,366f88e9,3a7a0484,b4299b9d,335f7836,a222636,8a4fae1b,be122228,be9d8afe,be223c53,dac161ae,ca77ff4f,e14d9c78,894fdfec), +S(8b6e862a,35566848,50b6d4f4,39a25950,47abf695,c08b6414,f95a1335,8dd553fd,15a1f76e,f12ee34b,f2ef43d2,b14605e,db53c3a5,e7cc7c2f,27fc252b,c1641642)}, +{S(1c185b5d,e988ae93,eebe0aa4,a98396aa,fff2671d,8246ce2a,4394db96,7a541ad4,dddf4244,3532024f,d225f86d,133b8156,3ea8c92b,f0ddc354,88e6a04a,d41da5fc), +S(addee173,b29de510,58dc107a,47fad47e,c48bf332,2f7c138d,51060322,571faacd,3890624e,c6920ca8,6a9aadb9,90a15156,799dd771,901823e4,9f3bfcb6,8bf05d5c), +S(9e20bbed,ccdd5c05,d683b2ef,852760b8,e246e5d9,6a8900ea,999ac8bf,5e8f12e3,9f28e5a,b4257f6b,b826d076,ffff259e,1caeda5b,7d34f658,ddfa0401,7cd4768e), +S(dc825d1,5f707c17,46920014,9d7be56,acf2d1d3,c444fa27,cefe5019,6f5b317f,226d4960,2f349d4e,9cd10a57,6bf01681,e4981cb6,4235d347,72a1e5ce,7694a20c), +S(812e2cda,3f473919,1f2ac087,7d70d0e0,2ca0551f,10c96d95,51ba4199,22780f90,c8d05855,6b6364bc,d9aff119,5b9ef26b,85cffa72,1e880b83,eed73cbd,d23b91e1), +S(aebb0870,76f5918e,68194fce,42d0b925,cfd2a506,359af62,146c8ceb,8502231a,c1c19605,e0456cb1,3e57229b,45c83ff7,c3695a2a,31908bc0,31b08140,9c2040fb), +S(af7332f3,3ec274c8,d34f47ac,fcbacf8f,7980cca5,7220012b,8fd5ff94,cbf3d8b,d439f1a2,89799dc8,92b7e53d,a84a9e82,7bf7bdb,7240c34a,caef59a,777188a8), +S(baf71cf,7851a758,12d7e09b,192741f2,1b5d2a36,6e31892e,e54c282c,81163a6b,1ef3bf2c,a81acdfe,17cd6b45,266241a0,22caf299,ed4d87cd,68d3d4d4,526b4d38), +S(615991c5,d250cebf,8c7bd1b2,969213f0,403c7da1,a3ba913,44fd0490,88c2474d,4f014177,12142cca,163f29a1,f5790004,32726712,93c2e87e,f46d2138,c14040b6), +S(b1574b39,26ff27c7,b2dace6,6108b93f,3fc75d48,478567cc,66bba29e,750c0c86,2759967d,8d05be25,3f88a66f,830dfb83,5139e32d,6f42cf3a,43b199ce,ab85b55c), +S(5fe92a7f,d1c407fc,967dbb19,e9fd4d,8361aefc,a3d5a9a4,2f8237a3,458e5e90,9b89ce35,57d469b6,9b9034d6,cee93609,c291d023,d1d9349a,d9bcf47a,aed8b2a9), +S(d65b0a5c,41b2dc6b,e5aa87e4,adfef952,621f9d99,550e424d,176ee180,65f666e,a76fad91,3b80b0cc,3d3ceac3,9a465cb9,4d8c79de,92adf9cd,7a4efae7,c85c30a4), +S(61d7de65,fe34ec4c,f82f67b1,75887263,11683263,145cbeae,18ed192d,14ced48d,effac049,d7e5412c,5052160a,6d1b2230,7157669b,856af0e,e3e46a25,2d2ee19), +S(9a77de66,5165a9be,3dd2758c,39aa7a14,1f052358,fbac634,5ea701c8,c93bc4a9,1044e428,bb381024,70108d56,b8b3e3bc,7512300c,5a6ae44b,93b2098f,a13fc023), +S(4ccb2426,b6eed0f9,651f80d5,72b23e78,d84d6928,57648077,3663216a,bc8a418f,1840c,bf5ccdd7,19f7fa8a,33e7151,aa351d,2f620972,6ec67d1f,fdada8c6), +S(53f96bb7,86516e0f,2ac7611a,1aac61d3,cfbca76a,9609fe,e4cae036,52f68271,97e3acbc,468b777b,bd1c8263,5332dcc4,b08b9fb1,9608fb35,cd51e49b,f09d9087), +S(395253a1,b6a349a6,dfdb0d6e,65695572,2a597411,fdea9294,6e48d107,596d8ac8,c57110d4,dd0d35a7,663fb3aa,e15d8c4,dce5cb67,d3173d91,a6ff7ea2,1bd28107), +S(d7becbeb,c47d0de0,899ffdff,8620124d,b29c8e5a,fd71a0ed,76e0df76,bd4e26e6,d8b52fa3,e16e7f19,e925e769,3b5a731e,18f3163b,1ad4db34,7f878381,da75fc15), +S(fa3afae0,4f8c1fa2,778446af,88e29150,256b0413,d9bfeb44,45288e41,29be15a5,9dc76b39,574453ab,2d46cf23,ce8cdb06,cbe7df15,d03fd390,4470a86a,822028df), +S(da56da00,dfdd788f,90a12219,db03cac1,403efef3,ae706031,e153aa16,b3a52eb3,1012ca8e,ae20efdf,41c77128,93fce97,fc66b187,caec55db,7aaa81ef,cc12838f), +S(f07866f0,cca3474c,40e7fa59,26df41c0,e46fbfce,faab92e8,9ccd1170,3ccf79bf,37ed66d5,5e891f4,e644fa04,182f34b6,1f1aedbc,d2a71aac,dd1523bf,f579dace), +S(853f72d1,edc4d953,348528b8,3656894d,67032333,28a16801,64a84511,15c5e968,197737d0,de83e73b,247d861,510ac76c,3ca214d8,ebbb958a,74ce1c31,5e715e87), +S(7c7eae74,dce7ef76,9ef0ce86,cf6ac861,ffc3d4a9,6313f379,fb2c0325,daa91aba,131e1689,fb017e15,e869d858,2dcfc4f9,153d1e8d,246fd613,b3922302,5b5c3767), +S(56028652,bce9dc6c,c8b4ad5c,f9f222c3,412e5bb7,8d556225,2c06c2e4,25a6e31a,2aa8e093,d8653f6,2153972c,e54806ba,666d49ba,3787934a,a37bd65e,79374ac0), +S(2eb98b01,550a00dc,59d280b0,71e472b5,a65eea89,298fe4b0,9f6f0e07,9315ad7b,74e22fc5,3daecdee,6a0b50be,e17f1d7d,d9481e77,28778957,274c8d29,a0d89fdc), +S(7268b61b,f65d73aa,37766a99,9960d998,18aa4ef2,ae8a97b1,db8476fb,32f891a4,824e99db,3157b706,38573513,618f6901,ce1fcff8,f25019d7,c5c45bb2,f3bb4d47), +S(cdea8771,4a764e3f,a94e7356,879b7d9e,da7c5b6f,28c172a6,1c0ab012,9b9ddd7b,daf49b12,34ce20aa,263b4349,f9f88cc5,1334db26,59b7c587,212f407f,cbb2644b), +S(38831af3,193c8860,690a9d74,cc0079c0,9e3ae0fa,ebe0da02,67ad6e23,99059d19,be188500,5193f11f,e34e70a7,e470cedc,902bee92,e7041403,c2f1ae53,7a8bb077), +S(df3acf55,bc6d97ce,34ebeb46,34fe1010,ed3d6d6,383c11a7,53a93123,e9c8381f,94c22735,ae6f858a,59f663e2,12532e14,4efe6a81,981c7619,e5002968,dcb81df5), +S(a8b08b86,4946ac6d,a101eb85,ee7bdf55,24282ca1,a9956e4a,eeb1afe9,87a43ddc,80ff0174,375c95fe,cea6e00,20f17123,5cda4bba,d4ef893c,78ffe37c,205d5577), +S(fd9941ce,e1c26864,248f7035,352787d1,aba9e93e,f5edd333,d08c89b8,4bb9dc8f,85be138a,42bf190b,921681fa,8777a619,878d4d02,11016c72,8bc151ab,1a687b5a), +S(7e2cd40e,f8c94077,f44b1d15,48425e3d,7e125be6,46707bad,2818b0ed,a7dc0151,6fa48af7,d523054c,7d59e574,cde106a2,776411bf,5111f7d3,65c43ac5,df8ddd68)}, +{S(282c5bc7,5b9c3f76,73e244af,29f22b80,c171bcac,d7e39b4f,ac7ba6cc,656d9010,e8db2eb0,a56699f1,73d5b5f7,99d39e14,dde34648,f159ad0d,c1c7767a,19ae72aa), +S(d5a3eb7,cad9c548,839ceb7f,67145e0e,96c60d8d,68415f76,73b73700,5ce3a8b,34ae4e12,355d1df1,25149efb,1a9050fd,490e251c,4404fb37,31b6dcc9,e233b9f1), +S(68718b29,86197989,3c5f7b1b,48abc254,13bd23c8,96c8828,7000ebe6,6db742a2,bef9d2a1,bb596fdb,3caeef3b,4d950568,8a94b436,4fd85f37,30b20de,b9e9a4fe), +S(a5ed1709,7932011f,9a597511,a526e61d,f22d0bd8,ae3e15ce,655820e6,b1ff1238,dd6dc7d0,81e70b57,4f235c10,c7c3dbed,a57743c1,15e6fe01,a20ac751,34cdace), +S(ec37904d,9662a487,1a471d9f,778bdef3,430df9e2,26fc42e4,7fc4bf5f,80e3a9c4,8413f2f,1ed55d8b,8448e336,ac9d1418,c48846e2,acb43509,f1a3d935,8cd18ed6), +S(b09f9c76,1cbbb685,f695328,61c459a4,d2b16989,3cbbad2f,dd49c87,1d860db4,dbbf9049,31b18454,21c41f2d,2185e3d6,c8f55dad,f1514ab0,655c856e,3391278e), +S(ed1a335,48864e9d,b41abcad,3344f4e7,ebe57841,9371095a,6b95fe4e,ae59edd7,d1146be9,83adc77d,bd9c107f,3092a9c2,9c271248,d78ce913,7831127c,c403f44c), +S(d39507d2,6ba377f5,c7116aca,78df331d,a795cdfb,54e5c912,8558c0e,997b74f3,fa7971d4,32cb5a44,589dc705,de28ad0,382206f1,6e11229f,86ff82a,efef3131), +S(641dc311,baa77b14,35f408e1,528445df,53c5ac5c,32803a3d,84e8fb66,60d71d,2b355a47,76980bfc,8a4e0ac6,a3bd7b02,a6b20ffb,f8650b16,89010456,6953e49c), +S(c3dd73bc,cfb744bc,57bc95f9,3c260df7,7f3b7e74,9e4a5237,f3865f8f,f0c89489,15d58dfb,83654754,80e53bb2,a1ba430a,ce213c38,ea71c7b7,51b4143a,fe2bd124), +S(3f883fa2,e834df1a,6e9b5c46,b663880e,9a0b42f1,891b92c,eb30600d,5641813e,7acff194,a5fb76e5,bd3d8fd4,2c7f07a8,3a991ba6,7f0e4edd,c55e1d8d,3025d590), +S(70c8d4f5,21d808e7,221bd5c6,31f171a9,5e7aa358,4477068c,2549c59e,228688bf,52badf20,6106d5a8,d7bff921,580eb5f5,3a53aeff,e0369f9a,1bcb282d,7b4cc26c), +S(ae08db34,874d39ff,bfb9c92c,5e4253ca,7ed508fd,d12841e9,63600461,b2b3a0e1,dc0504ef,d209be71,381eefd2,91508120,fb6ec1e,df62d24a,cb1d77a9,4eebf1be), +S(627027ad,4aa88477,c6240517,87a25b88,7d5b98f,b968221e,8e45d584,3db6e0bc,34b553a7,c6ac7004,69367afd,17c5eaf8,7605ca18,6a57667b,650fd8c7,18ab76aa), +S(573ef2ae,72ae8fd5,eeb0b720,f8967b44,f7d9d96d,c8a4825c,23a3dbed,fd2bb442,264f508e,efe5e0a2,55e55a54,bbf739b5,757d0a15,994ea9b8,4e139738,7c484786), +S(28907848,cf84eec6,773a384,ce5f4a5a,24c8afc8,606488a2,ccdeff25,6f896dab,ea87d4f,41df8727,2fe84537,d11126d5,62618bee,a51008ca,895a8375,4f05ec5e), +S(163db4c4,536114f0,75521627,c61f62d9,14214d64,ac9e66b0,d85b9991,62c54c5b,7ffc24e1,11c0c845,1c574e9b,e4b56610,696d3667,a6e6abbe,9d1a5ea9,4122aa1f), +S(2ec11f2b,71ffc28c,fb5e779e,7739098e,c969bc78,3cca5a22,77d2bf53,e6574d1c,c5e9fdf2,89a3090d,e24d13a1,bc8377d9,de0bcf4,63482ebd,9620cbdf,8b238fb0), +S(30549ae0,9a46820f,f49423b8,9c6fdd48,703132fd,ac166dc9,90609a32,49039f0a,b8c94b4b,36d39247,732976e,fc16d500,ccdc07f0,d7b97db5,7a1d9fbf,d8cb5d2), +S(98685f94,a043399c,89e74674,240322ac,5a595bf5,41aaa44e,d781781a,10fe9225,4506b1ef,7561b811,53f44e8f,325f9222,e999013,30523885,d8c59864,db13a3ef), +S(9acba196,3014ea9,1baba28c,e273c6e5,b9a2e1a0,98216c3b,194a0b56,dbda7db6,f0a3358e,eec737af,2e313262,b29ddf6,2adb9e97,9f56def2,65102272,6b976290), +S(e81e91a1,7aeec75c,19df0ef7,fd07ce2b,e477c031,179e3f99,4ca13857,e2b5ff93,65236424,aaa8b6cb,fdb2fb20,46ae3c3d,839d97ed,217edc6c,c774f889,d2ce8b45), +S(61e60aeb,821c3f80,b53ca78,2c3b4d21,960eb0d2,c90202f0,a5fba651,1725ddba,b029275f,690d10bc,b52e8bb2,acceb071,f07834fe,64175088,a97e26f9,8ff34432), +S(a931c410,8fcb4346,6802dd4a,8ec2cf62,cf4c5558,8129299c,b3a87e95,6fba2a34,c21a8dd1,43d4a639,339fec49,f56d717c,658a55af,ad72da1,c754fb9a,117cf6e7), +S(fb5c106f,da32fcfe,ffe9b5a2,7ac8cfd8,d9a73da1,5fa6340f,e09d187a,7a83cb88,a3f4c60f,90003375,11c39100,ba4c4721,c6c138c1,cbae09dc,46d1a1d2,5baa95fb), +S(dc25e18a,18f0035c,2a05e80d,d6b38830,7fb3b176,a66ae451,8c5640db,7540dd24,3ba83beb,3e6b29c2,97a0ead6,148f9b93,711556e2,e5fd513e,ee649228,c62d8f3c), +S(ecf7b689,ca03b840,739283e9,c3003a01,65ea3f,3bd17e06,9260c0e9,ad403273,5e0dbad6,47997fca,c0d7ba2a,170a7954,67036ae8,e61dc532,b5fe184a,deb8a7ea), +S(263e593b,10c982d5,1bf89ec9,71f6a3f4,60e53bf4,cb2f6af3,2381214b,2e981bbc,e255bc11,11470eb8,894ead67,c618d7ca,a6b76ae1,a230ef05,3830d028,4a7faf37), +S(f79781e7,a4137ac4,7a9a9d00,9d239b37,6cd0fa3c,b9f5de46,8cba5a11,ffcdd69,d10ba78,896e086d,5e25444,165e79d9,7b3d485,1a448e03,26d8906b,2f27745b), +S(a4d28024,11f577c1,c5d08fbc,457a46bd,428f4d2a,b29475ea,ef622876,593e49f0,e4855491,ac0342b1,dc804bc2,7ae23877,82eeaf22,52874a00,4d4e0d66,b07b434f), +S(87195a80,dc83be4e,cfc9d4b8,29725cbe,11101c26,13c98f2,641753af,1ee840f8,f9fce233,66931c51,4ea09224,b565dec7,22763d8f,6f572057,fdd7d96e,9811289a), +S(210a917a,d9df2779,6746ff30,1ad9ccc8,78f61a5f,1ff4082b,5364dacd,57b4a278,98f1e4ab,af4a1a84,85c6417e,7298c82,c87619e5,500df403,80d8ec01,f384d9fe)}, +{S(6c16768c,433a000b,adc47b10,ba4e132c,f5480e65,ae83d1a6,8aec34d2,c00c76dd,ca1a47dd,66c2d74a,ddb69283,2ea289a6,ae679669,edd80bdd,4ffdab2a,defbb542), +S(f757e860,ed04db61,594bd647,5ae81b7e,d6d2fa58,80cad10a,7756fa26,810b8543,f2aad599,4e491e02,9b1ae256,2c90912a,1c9aa6cd,dfc2331d,a0069a79,861208a), +S(d9f269d2,9aa777c6,9989d706,91403dfd,9025b491,ba03ddf2,dab8c9,af7dc764,1b39b85c,cb4749fb,7f47086a,ce63924f,3ebb4213,af5dfc95,fda796e6,c6b0b8b0), +S(d05e14f6,fe6ca50,a23e9339,e449f771,98e842d4,80a72d5f,8f5e4c06,43547cb9,869e3bea,6b19e0f2,de83fa8a,e932086d,d66e838b,637ea603,5f0fa081,5912c8f1), +S(9f723d81,1818046f,b7512abb,faeb46d3,52d8da9b,3abe819f,3861f9c9,963c583b,37df0657,3f2bb428,6c8b3efe,f6941e2c,4e48d90b,931cd0a5,78a4b52c,6581ee7a), +S(e65f0b42,54ad9df9,681c0db,3428ccaa,11194df3,9e837aab,4564e1fa,254e6f97,43e59d10,54aa35b5,80373e08,cfc02aaa,4f581406,58341e67,7e50977e,5bd893dc), +S(605d61db,589fd91,78a65cb5,99697001,73afca81,23f663ac,5fffd0b9,8f5e7a64,a976a9d,a47745f,447ad4dd,7eb63875,c228b979,a7dda50a,d994df7b,545d0ede), +S(43298aaa,faf20e9d,c2240256,493ef19f,5630db6b,f6376e4a,356bd034,98f1be7e,737551c3,653af1cb,4f8c1e8a,347f50ca,142c03e0,29007f29,c76bb763,b52ed053), +S(8afba782,d6373f0c,54734f1b,4b854e63,bf2a3b4f,23f57a3e,6c2eae86,25c691c6,da3054aa,228b9757,b7321da0,64516249,652fd814,15017584,2c7683ce,1a3638a2), +S(3156d359,e01d64fa,9c8fd8b2,c47c3492,82dd459a,fe89d94f,35906da2,c6d0208,85a23f48,f0a7448f,c57ee545,3978e2cb,6f2bbe54,864477d8,a63775f7,7ff7289f), +S(88e1a44b,1e206eab,49fe97af,30be5e47,25e1011f,312a5222,e9e80819,b3f26357,63dfe52e,10317c4e,227b2a5a,d61b713e,2d93aba7,f0a51e0,b5621191,40c58ded), +S(d10de96b,f2e4a6f8,78e0f37e,15569f3c,b9717a38,7fb98928,6d65d171,4b81b301,2c0a46c9,6a2e3884,e7f3b146,acc170d2,6d12b959,4b75a901,dd535016,f0355ae2), +S(eb36b865,812ae4bd,7893e50,5aef6f14,bfc90c1b,42e75ea5,91615aa,a2101784,1523537b,790b2a61,fb6696d0,a622ff31,efea1255,e1dceb86,763985e2,6c5ca8df), +S(d54be697,e41396c6,3d63f96f,bde9bba2,36ab1649,3c156159,3df81d69,c906fe60,89de1769,433b5678,1f7a2206,ca98258,20d0c7dd,a6d5b672,f77029c2,6bb59f33), +S(d5aa72fc,9063c2f8,bd0fec97,da30dcd2,a5b36aee,7894463a,f7042795,1998c979,ed90095d,bf2d3a67,2d2f1a0f,9737c4d,e8f3e773,c04b77d3,a2345dda,ab662199), +S(ee8cd53e,8ab64281,b5cad323,f03fd06d,7aa166eb,df9185b4,8d0eb0e6,1bd0bc61,4781263d,fc518e4,809e5ea7,7f9df238,1ee7b6ee,ab25c1d9,5cbf3fce,72fdd615), +S(ddc5e95e,2a46736d,9bbeee74,74364bf9,e1d2724f,c43522c,cffa05a8,7d078be9,60908fb,809ae964,98a26cd9,67532df2,409491aa,73c46803,eb58861,7ad86745), +S(ae503a2b,b6250ff6,6ee615d8,41cae4e,751160fe,aef7f33b,dd1feaad,ab236b58,6e53d2a8,8f09f78f,96d49a6,2f98773b,a282b575,ab6e24f8,4d604c3c,8583a66c), +S(8a502d08,bb3cc1da,438c5780,e2120c50,12c1a972,8aaab6bc,5d908b6e,2a83dbdb,fa02e62b,85d7de78,8cf11d9e,ab406523,bba1f912,53006a89,f3a491cc,dd99575c), +S(b52891bf,5acb0019,a8d10b94,87fa47c4,22f83a00,ef539e91,44bd9f7a,d5075716,ae58653a,b167a9e4,b71eecd7,4f4a8786,19c19026,29c0018d,9f082e7d,5920b2f), +S(176170af,b40a3e79,8a88b98f,fb6c578c,d1ab56b5,b7f4142e,b2d84a59,1b009f97,6e1d5682,36176d58,ce5fcac6,4d4d2885,5db107dd,5215c71f,b4076aaf,d31c5d24), +S(27359f7e,8d3e3dcd,ea35f603,d8fb15c0,bd63c08c,3ae4d2fe,8cb6434a,ae2e716d,a0d64207,8fba00dd,4683d597,27f3c67f,3c25075d,802a4ea8,eb08c20b,47a941f9), +S(1e9d955a,2f68478,5227e866,491990a5,62c802ed,1b106bb5,42d02d29,93542067,fbf5f466,57707b3,3f116a23,fe5991a8,90a9583f,fd063943,37a19aa7,e125ccab), +S(b5c4c10b,1b0e0813,37deef6f,c089d2e1,ee14da2d,cbb48e6,74b7dbd4,429e22eb,fdac245,b109947,8f6a53a2,8a1ec4fe,da43b4a9,2ef49e25,8f9296c2,88c48378), +S(bd2f651c,ff6e614b,1d6535cf,c3a2c5d2,da5307b0,1cbd3f48,655623c2,55503916,3715b0bd,bcf29d97,63d7fb35,f9c5b54c,769a863,3517a2d6,8dde74e4,c4277779), +S(c4c2a8e8,f1e257a8,fcd0b11b,30635c5e,782fedcf,f99b0b95,828e1369,3ee0af73,3a08abb4,777a066b,49ec4c01,aa5b0868,f100a473,e555def1,7c5a9d84,b1fd9ae), +S(4aa77ce,15dd97ff,47c1125a,77bcf0e9,d302b79a,e8a919c6,a875e5ed,eab8c2ec,31a09dc4,89a90240,334836f6,302d7e81,57f19762,a9b5f727,6c276e63,560a9d10), +S(3731162e,66a8d2d8,ff4df3e,95950103,f5a03f9a,86bf37e5,605746,cf4be846,e19d7835,10af5daf,724be4b1,932dfac6,23899ccf,7e3e58ab,5bf3265c,667cbf28), +S(6e2114ed,297ba44f,c3926603,bc03a87c,af3e9f2c,8bd84e64,afcd9846,bd9c8f0a,faa6e5f3,3d90f91d,82592af0,7f3a26e2,f6f4138a,2f06a6a1,4286eb71,2e95cf94), +S(50d775b5,f72d186b,266a14e5,254cb5aa,49fd8633,81c36b09,842632d7,ff004130,cbfe11c4,f0b15aa8,3ae8dbcb,9feff9c0,d68a26ba,11095b3c,ba94739a,2091bbc2), +S(8f3ccf31,f8b74b9b,624a5d1b,7cb1096e,202fe5e7,233777aa,859864d3,775732c0,980e32c1,d2c61ace,7610b926,6831ac27,56f19788,ab7a77da,18c421a0,9a46bad4), +S(24cfc017,6da2b46f,a8bb5bf9,636be1ef,fd7e297f,29122fb3,e84c9ab0,c18ada5f,14007044,f8639e59,67978eb2,a21256d8,126a635e,5b07eb0d,97059ec5,6875a3c4)}, +{S(6efcde8b,e99d9ee8,ee0d6b8f,a76584bd,5deb67b1,415e729b,48f3d41a,f1cc1386,4ddcef4a,a6ad5be2,d1e83449,9eca4a8c,73219f80,464a4a9e,ebb7f3f1,b70c9fd2), +S(24fdd052,a1e535e2,4eb79ffd,f03093f8,5778241a,b845b548,31b9a82,730ee3e,c6ff8ebc,7edfd9df,9b7410a,7f54c93d,ff0c682b,152bf4db,1b79c0a6,9889797d), +S(aaaf86ed,31dbf395,687c959,6c445b6c,dcd1fe7e,ba2aa13d,1bf41867,dc87b30b,582b9683,729be5c,85fa83e,2ba2abac,e3037262,2a24aa35,c7753312,1de2fb93), +S(23930d0d,2400db1d,56525bb4,67172fe5,e930bf86,21124fa4,6c5a421e,10b059ea,5e11f202,beca3d5e,dc9b282c,2e86d5d9,30f8f5d,27a5c4d,d2cd6dde,6d1497ef), +S(76ad10d0,bc92ad8f,55b665a1,8ee84e01,2e92dcc9,37e0c604,59bd6fd4,ded2d9d2,d4ca7386,ce0c4c5,fd37da9b,eb8fb040,97d98891,35a5ecc0,320dfffc,95ed3c10), +S(10b324b,e959f0c8,c8a82142,4a8f87c1,fdeb7f88,258e1021,c9cfaa66,b131f3a4,590e672a,daa8d547,161f635f,153fa12,b3500694,677af3f8,90dd4ca6,9620bb56), +S(afdb2acb,ebfdc11b,3577177c,d8bcde00,65151495,79c6ad2b,f7386275,a9314317,87d7786f,5ba775c0,ea47b141,cd0d4274,c7e58634,b64e4c58,f7f0c595,5a307250), +S(574cddbd,59b34df5,30f5dc4,61884ebd,1c867ed5,6cb60832,4a11b1f5,29ebf733,1bfea852,34256807,1fdb4f5c,485caa73,7136e3c3,b4b8a39a,389d7dc8,724f16fa), +S(97ffea2b,5de34e1d,495ce082,d0097b72,e7daddb8,1cb622c,2c14e814,bb0ae278,45fd3d2a,9d1e6530,61b4a356,65aa9e70,43766950,622e1c25,2baab265,6d4ed95f), +S(de627f6a,a7b56d85,535c398,80d0276b,b910ce4a,6066435b,512e5e0,21ef55ef,753033a6,ef89f053,c0e662c8,1557e6cc,d8b4c8d4,5204f5d,e1c8c742,72b96277), +S(b126c35a,d7993bd0,164867c,58c88421,d2cddb6f,d16a5966,7d9683bb,1b428eb5,a9ed1bb9,e9eacf9e,e712bcda,be629143,ad0e7652,82cbfab8,e586cb07,131e5b1d), +S(847b90cb,8837f488,ef027a05,71b2be6c,620cf86f,ead235ad,e76e3408,d0dd1073,9a2667be,6ce36e7b,d76117a9,fdb8f1b8,7c7cb45e,1a03f53e,7b32bc63,6f274b4e), +S(8ea21457,6f1bc2c8,fbee9065,c2cf5c3e,7a3b9fe5,403fb980,96040c2e,c6fe1488,dd75b454,acef4d3b,1b355a63,f0cd17a6,66aa9e65,f1262629,f0c7d1e0,33571b58), +S(9e11bb60,ba4b2d5d,fe53bb9c,598edb16,f3926bea,1cc90eb4,3e05ca34,e83f1896,263d7ea,50d83b8,791fc911,a4f73cac,4d42a09a,85f5ae68,86cb268a,fd562dd0), +S(f741856e,f353a7c7,17db9a13,4ab4aaf9,13c1f7da,cef08bfd,6f81dce5,b1130e20,ee63dd2f,48e15f68,d1acbf49,705fe010,231e26b5,14146c47,1a689960,d568eca4), +S(671ef05a,410b41d9,3b092b04,e523468d,44837d2d,26dba670,27400715,eeefa2b5,686d318b,b49eccbf,40dc18af,f1938fa9,b16d4d2c,c19dd2ac,47c7830f,89b8d55c), +S(59ea10a1,e5bffd6,a34593f4,b986e37b,5294ddbc,60d92906,52c6e9d5,75f88c55,c0a2eb5,6d04ab99,abb5b76f,7b2b55c9,c09d44f3,3785e3d4,64554c3e,dc7a334c), +S(37f2c7c5,69c6fd15,9b721d8b,8d40138e,a8873b6b,452af0a7,89a50551,e9703c1e,d114109f,f9e6d7c0,c51a542f,b2e3ef5b,74654bef,5eb84aef,c87f5096,2a30c078), +S(1d280637,9d77e509,126a440e,b1e56f1a,8723728e,97c92420,5ed13081,98c868b9,85003989,93a4a600,dfd0f092,b13a1186,c1c52dd8,8fc8eace,9bd4f1c1,b47741d8), +S(39aed6e6,a123061c,228d3d1f,857e0c9b,29b70cdc,549b4ea1,9fb6802a,8d8beacf,6bf86967,98e3dbf6,75865a1a,b86d5bbb,10f16e8,4f9104a0,87602c,e6946aec), +S(aa770804,4a996b1d,5bda074c,941b30c1,d1474da6,47d7c4ed,248d3a9f,c3c3c525,10ba5652,b20482f,fc2434ce,ac185d8d,af6cc6e3,61e77d3f,258abc0b,55610879), +S(7626a96,9f9ef188,3ea82737,83e5571e,4054fb73,6190977a,299c2a05,d29f60c7,172d4618,e5f88055,ebfcdf9f,55267ee5,cdf18396,1d5a2a22,55b87ba3,c7d7d2b9), +S(1a550684,d1195da7,c4b09349,f149eae2,5a1ef23,c9a81109,115d93e4,c98cdbda,c31d7dc1,b7efd019,c491010e,30f90ed8,7503c4bb,1b37fbce,3dae199,6609e3b1), +S(8d2306d2,dd8c753f,2b093e62,86fc282,ba3e1dbd,7b4ba101,83d1070e,d2d06e67,97dd14c2,d2c1d147,486a3dfc,d608ba28,d63fc03,251a106c,9811b088,978e3a5e), +S(f31a69ab,97039589,940851f3,cdc98bc5,d400ff93,63794f81,4d88215,4f00db99,56e510be,7f41b009,89792401,13641590,40f5f305,f27fe1e2,db1cd7ae,887ff5e2), +S(ce96b3e9,6eb94b7c,8bdc7b57,efd2186f,62e23e72,f11337ab,be7405d3,43b4d762,cc0dc898,33e7a632,d0fed52d,487f2c60,96c69664,f698a71c,3f7f8a29,4f181add), +S(bed97e25,7d31b5fd,36b41227,462d9122,706da670,d432ceff,5d37d83e,fefda56c,c0cfe30a,2c3b3074,1af492b6,e3797c4f,3b00593c,6806e2e2,f2cff401,6e877ff6), +S(923bc6c9,960f6e4d,ca2a7070,6d160e19,83a16b6c,8535783f,12c5ac69,4aad226a,c47f08b,6b2056d2,8e9f119,9ec6d5ce,b48801b8,7ee56280,d6a48352,b2b42b1), +S(b3cb28fb,7465cdda,85823dcf,819400b,357bce11,23d9229a,eddb8262,53b246c3,cf035ed0,b624dd68,8a31eb5f,3b28e83e,c0bf9453,649dfe4f,44078eac,9345f2a6), +S(c69aa2b9,ab3c5e45,8713a912,e7f95bb,4e5498a6,d4090323,5cfed1c9,c2a60709,2e95e198,85637d55,744e32a7,98c02c7e,b29f3bf5,7cf7c870,7cafdf41,f6710f0c), +S(45996af,5795ea6e,43e0fd29,671e119b,8b8d6ad2,4eac90ec,d27d5db1,b4fb6a39,2c0651f3,1c7d93cc,98d79d7d,f21110fc,8c1dd74b,f1ffefac,a3d52484,f8da40cd), +S(264559d8,7829256b,ed116900,d82d0c37,9f0e4d12,53c68e6f,cf2d41ae,7cddab8b,861a42e6,d92caed3,108439c8,fcbf8d28,8579ce50,c6350e19,3609b4b9,ffe217bc)}, +{S(ac13e0db,846df259,fc38d6,3b0248ec,9fcfa8d4,bcee368b,1f4a66c6,d41f9163,6721b0df,2ed06fda,9b485cc2,aa56f1f3,3a913e99,f6809577,95280451,9ddc96ec), +S(b6b7227f,228da269,a0e5640b,8a2cfa34,555ccdec,2243dd0d,4b2da0a9,b4cb5e4,6afe41f9,dc129d28,4786bb76,17786c8d,42597435,240f998a,f970620,90d32059), +S(460672e4,4f2768b9,842a98a5,ca8b90df,7d9f52bc,3fa2665c,4272d7ad,5f48b992,6d7f8b36,13b38fa5,80ed1d4a,21d196bf,be491b46,49c96da8,342441d3,f4af4ca2), +S(1d3d4ab8,b7c06136,8dfd612a,25f04016,2bd3f6cd,cd9cf58d,c11647a0,d28b629f,434dca08,17bbf964,eb0a316c,b2b0df20,eb2e965d,c4d8d795,1d4a6e66,5ed23d38), +S(9c5d6342,303bc7c,73763cb9,2e3d7069,7d913f6c,1a6e2f47,39470da3,22b7c1b,825c1a54,395b9b41,ccc2e3b5,3fe1092,f04c382f,b2ee3a29,fd59e255,5f22fc15), +S(5c751285,a4b55535,fe24fe27,568868f3,afb43cf,aad1d2b1,c6367daa,ac9493b2,e2388ab4,414c4e4f,e34a4c78,c869dd93,7094ce2d,4f4666a8,2eef8047,3b681fb6), +S(8c1592f3,8d73e277,d3c18d4,ee3eabce,32e86f92,2b27c2f0,1f50509e,74dbc211,399c9507,43cd9e7b,200c255b,bd25670e,cc111462,2d5dfacf,9dbebdb,53ee59ab), +S(85320e36,5f40235e,621171d5,c8008845,890f521b,d7e2cccb,88c7fb7f,a08200c,96bbe8ec,74b5f1b1,2a6ecbee,2aea6f0c,b6d0657,aac3556c,ddc4e46f,17cd31f1), +S(5fc21f20,13403705,687b8ad3,387a725a,f2e6300e,13d28403,569d4cb6,5dda7f34,bb709fbf,be95aeef,c00846b6,a4645b72,dbb4e1ed,866edb57,7bc5d9a8,2b774b0b), +S(fa40e658,588f8a5e,29d380e9,c1a6482c,888f53e5,e331f8ed,9b1273a,56d094e5,5486cff5,3b7baaaa,de8a51a6,1d1a9255,95ecbea3,39955c0e,172de4c3,4762eca1), +S(9f87d04c,5fcc48f,375c40af,3197c28f,c62cf3c5,10fcdbde,5aec79a7,4e6a6bc0,9a6cc172,23a770c7,a03b5333,6922170d,e9409f3b,9846b9f4,41832ae1,f70f5c57), +S(bb66dd5b,2f88786e,736b50,e536a0f0,3d59b86,511e95ca,1bab2cb8,875bb187,f8215527,c76a5af,e5e76a33,eb2622d,5f822ad1,d284c68b,c840f65d,4f731c63), +S(74d223e4,bce2d6b9,b2fa9482,46327e04,18eda6c,cfdd76c7,cda8be62,3f6dd3a9,b7276bb3,817c0e72,e1ab002d,50531065,e1c4ca30,9c6d6f18,bb5796ee,457b4270), +S(80298b62,eb4d3ff2,e10607dd,dbcacda4,3bb30e57,f3c8c7e7,6f9f3968,bf391316,fc72362b,48c8b606,4e428e6d,1ef2ac87,931caf75,e936a33c,228a5caa,c460c5f0), +S(8519f27d,9560acdc,509fddee,9b4a4a7a,8b13496f,14760a08,22609f3b,2ae07963,193aa9db,b98293f8,e70d7253,51d3893,a9f5fc73,6f3c8e65,28a2dfd6,5dedc220), +S(49d734f9,c8eff915,fd66757b,d6484bc9,548f20a,d8c05959,f651eb36,e45cb88,4c594f79,7651b49e,929932a4,59e3bf21,3e74c0b8,acb20907,697a25a7,ed21057b), +S(6a528c6d,19b1e28d,b4d9ec9e,19c4f7be,184ef845,1f41b322,e5932f05,575bcc4a,7350b90b,c22ab41f,40c13a80,18749e8c,275d3e5e,5d687df0,ddd47133,c092eadc), +S(6f3df40f,5647143f,cb93b23,4795d9a7,708db6b8,2e2df53c,f214de4b,61eebaa9,dee10664,54b625ba,34ce4b54,f7285714,7874b5d0,6b38b1dc,37b7471f,9208dcbe), +S(5abfd7eb,c4c5dc14,cbf0e335,f2e87e7a,7db96a2c,b78000aa,64fa8aca,517ee1e5,d65a98d4,20d872e4,4c43997,55cca5c0,bb94ccc0,b25e30fe,8b5a4fcc,7006364f), +S(1bf3714b,da04d769,782e37cb,c4a4b347,f9fc769d,a18e4940,d19a205a,bdd22a23,d0852b21,33b04274,183f4de4,9a20769e,4a08ea16,ca8782bd,84a4da7c,64c928a2), +S(773ab884,a4e90454,ea467caf,f18c3b64,e316468c,b5789fa6,4958f73e,ec3204f1,62213b85,b4838d8a,fa3a14f9,32db7d79,dec538c7,d872d9d2,be1640a2,4e367caa), +S(33a283d9,9b7564ed,6ed10d88,ba26ba,fbf3a375,e00e10d1,577fce27,2c204324,bf84dac3,40736625,cf0e6be6,98072c6c,5fb8bf9d,2850be84,ded3f652,569370d2), +S(62bdb467,596ffefa,22b735fd,d3dfd959,d4a6e187,a19d4c1f,4d647b4e,db380c3b,210a8e93,d1a184d0,a3548be7,6283d180,8e4f32d9,52834c,515953f0,4ecf9acf), +S(ef16d3a3,233f03da,5864801a,c246756b,d1356137,971bc164,b5512067,b369dad2,480e3d32,7f1df8b0,646c3b58,a51126a3,e91522de,ab77d6d2,f2bedadf,1219b877), +S(a6834869,c006d044,a9dcfb9,8a5a14df,86469fd1,fd0cba06,a4e8ec1e,1fba89d6,c1a3e0ff,7abeb1e,8cac11a6,8c1b4c1c,f663e615,9f508c35,f4747f50,84b247e9), +S(203d13c6,53a3c36e,55a836de,b38c7443,681d7b7,c681d71a,38fb0fde,986ce9c3,5d7dba97,573ffd85,b3fd4417,f09192e1,92461c4c,125a9947,ced9c737,ecac65b2), +S(c48819,b8f32966,bd50f162,30f5c0a1,45cb3570,d9c4b104,4c306696,2f4d6667,feb08ff9,1f543c1,35b6e0f0,b21d7624,91ac096a,181bf093,fcf8f4b7,bf6559a2), +S(31441031,ceabfbf8,59bcdd8b,6e177f91,df7bfe08,f9015172,1ead3acd,ab64acff,e36315bf,6f087118,32894704,8d2fd259,6b8beae2,e1917341,d690a1f,786db5f9), +S(e3e4750a,310c48,38920654,b6afa032,79589d52,74e48139,6e22d9cd,3c05fbdd,f05868fe,5452da6f,fadcafb6,69e5edfb,4b9a7840,3a305004,345ddce1,eaca43ac), +S(3659ba70,60d8200c,9512facb,5c730111,4cdc2b9b,aa5bde14,8ad9bf9d,d8f8fb8c,b1185617,f91fe5e8,ec68da07,138b6780,e1ebd12b,1bb44eca,8a1b9472,8337585e), +S(1a46b7e9,fe99a4ea,492fbc90,3281b924,6831fe59,9360af53,bde4ce8b,43ed5996,97c317e1,5c0e23a8,f1c11f7b,5f9c140a,af786b56,10ad8ba3,d11b12ed,17379f81), +S(f16a409c,677a40be,402f8efb,3752373c,aced053c,6f702b82,8bda222c,a412b6fd,d5becee8,ebacd866,285958a5,8b1cf1b1,e9abf9a6,db61435b,d9725187,135fa955)}, +{S(32c932eb,6fa35974,90a408a6,ce962d7a,ef2bd22,72cdaa,cb80f798,9836abc3,3e145848,c2f8197e,f0264d7c,370d1784,7d21a09c,77fd9f7a,73245ce7,2ce5f3f6), +S(49d837bb,63890b4e,8a4a63ea,6d88599a,c9961c20,80dcc955,aca6a101,bc935f16,358a7f6d,b540ac03,78d83bc,304cabf1,84c7580c,46c258ec,58f22254,e3e03aa), +S(23516ddd,40dab9d8,63dcad6c,cd325503,b783379,d870ace0,9a0b238c,d7b6b2bf,b1fb8268,a7814efc,54f3d637,88956b67,a3997a31,10a738a4,94786d95,a5fa1c59), +S(6b4e215e,df56e6ce,6378fa98,5d604f68,e3561275,788283d6,c40cb249,6d16310e,cdf9537e,e6f4304,dbcb9df,f8b97a71,a12f014e,29867e5,6b09b388,78c9ce8d), +S(f4f30433,c933dddb,949ad868,cc0d52e5,247149a,7ec98f12,3e7f63b4,acf6b7b9,949123eb,9fb848fc,d7b94401,a64b21a3,53fde44c,d93dae3e,b7a2d3d4,78055af2), +S(dc3523f4,cd24be1b,30787dd7,5140fff,b66e4487,55e9a3c9,6124fe59,c07faa28,47b945d7,6d37b855,8ede59fe,e297a8e7,81d3ea96,f0a81588,b68db767,9b9641f5), +S(b92cace4,e31dc724,3b3530b1,f90de1c3,47cc39e5,5b247455,a1296912,4e3c2a09,78f89163,c735cb13,b1d8fe7e,547027f,68d8f864,a1f093b,22c0d9cb,95fe28c2), +S(8f7ed1f1,77238a68,bbe32e4d,ae6d67fd,be07c9a2,9fc6b940,6ef81a77,65a8fb75,98e627d8,d32095bd,5913daa5,920c5c60,334691be,537b08d6,da5b8c19,7bf81c8f), +S(47fa27ac,e035176f,34c59581,8d3dca2c,a2b40e53,29756c55,7cf81f75,4f99316a,ddee5921,f381ce26,3634a34d,1b4f9513,4d9f0e50,5e96bb79,b87d98b5,282aee7c), +S(7584cb68,60ae81f2,e0df701c,97d7aa29,8132cb96,fee4ad59,15424bec,2e280dcd,4b76458b,e3926b5b,bf59ad77,da4a96c9,1f9147bd,88a234c0,74b0e09c,a6993228), +S(2cd4c11e,70d432ff,38550aca,481667f4,d09ad11f,9aed62d4,968492d7,5de28dae,82514708,3e5bf46,341177e8,9ad2cfb3,a215578c,52f9436,d3952432,e9acd430), +S(2b524c99,2b18a6e0,30863716,362d236d,e385a10c,3679eec,2774edb7,a1a89be9,1abb3b28,3477769a,5c7b4580,93efb22e,f2e61296,da90d4d3,1d6b2ff9,1766f89d), +S(d642c258,9d0e47ef,f5b2b60d,9321db58,727315ad,522daf58,3bdf35d3,336f1081,1019505a,994030be,484e5340,abea0b7a,51276c99,29cd1f1b,9d19798d,aaacf3d9), +S(3e5e09b,451bcf5d,549f1d66,b96da0ea,25e63270,dae59606,bfc3165b,f89f29fd,2ce591f5,32d57be6,4fc48aa4,ba40231d,9c104615,b76ed6bf,11957694,16d2f0e9), +S(4756965b,82fc23bf,64041d23,a23cba32,cb71d3e7,ef3e6c03,51b20f3f,dec049b6,75f3a293,eae07f4,362c47e9,44a78561,323244ac,bcecef0c,6ba2f5fe,d1933679), +S(f296e9c1,41694ce2,c197ba85,bb9f172,54fc0bc7,f89347,a0e92b8,58491a39,73c7fbdd,91c88ce2,bbcadaae,df8880f6,aff07e8d,3a1ce05,a468e3c2,3008d98d), +S(b437d387,ddae39cf,e26edc85,b0e600bc,2a199b6d,b521f9c9,88d921dd,7e6fc761,ce2111f4,d937905e,2af7f2dc,559f9eb8,bef286dd,909a5965,53c7f61c,f51aed18), +S(bacd4a38,f3e1b7b1,b601fa5a,2a579e87,459fd189,a607314,5a0dcfb6,1ad3c21b,8be8d6b3,9553648f,2a94754f,4c6c14,c4917296,aa9987f0,deeb7e66,d81c3777), +S(d8164748,8ac6bca,945fce70,e8f6a256,90512c8c,dd4c8fbf,b553c131,96f7f607,16b75474,65a80a67,86b5246f,e086d32c,4db03b83,58271938,41877c38,2b5bebed), +S(9c2b0749,cef57b4e,36b31328,e01503dd,ddbd2834,5cd86ca2,5224b967,1b7897d5,f020f978,4eed44cf,cc4aa33f,b2eb4b71,f24b5f3a,a8dc1d72,569bdefb,5f6276fc), +S(ea277814,9f0ab428,63b05bb1,c113ea7b,91afb815,e8f0791,12c11573,eb044e4d,8199dc4f,4e72b691,1c562ded,1220aec3,ab967029,139d30ac,58c753d2,f4548030), +S(4be6fcf8,40673659,5a9e4f2e,877ad7bf,28e25177,63d74238,6e43e6da,1c1c43fd,eb5456f3,d1c40592,2eec37ab,3e0d08da,b7cd257d,9babab02,44e5b2d6,a827a7cb), +S(3f1e9ab5,160733e2,9e7aeb6a,378d169f,9be5c266,a6462e2d,e736be07,f88c1da1,907fa0b9,814da057,9bb11309,aab51902,a0699aad,9422e1f,b8f1a8c4,aa9d4399), +S(eb730dbb,1ba9b2f,50453837,35ec6da2,ac4b5019,86cf03f0,3f5061e2,a28285f9,41dc3a0f,f42fb1b5,d3b464a5,6e305fe5,c60c4561,d6e5a6a7,8cba87ce,15c392fa), +S(aeac891d,f7032059,54d0bab7,41927702,1a595a4c,37bfc34c,5d315876,3e85f3ce,168f8260,1331b5c5,edf941d9,9f1cfe0b,72fd2a1c,3e4bbc2c,c62d47e6,6399105d), +S(667e04e6,daca6315,4888ac26,a268876a,f4b754fb,87687ca7,3c4cff77,d6dac204,1826a26a,cdca828,8e2ac81b,855a4d40,86f3009b,162fba82,83cb1d17,b9f7aa4c), +S(240ec754,24e46326,8e2e4ce0,240f335c,78c46150,1e18cedc,b32e3c51,77ade3e5,be09c744,cf6e9c6a,75976c03,530329af,5e11e5ed,3fb13e8c,af40bc5f,95872645), +S(7b83e4b7,70e7a442,3efbb501,c23881c5,2bbde4b9,d5aacc38,7071decf,79690025,d242ed74,441d1ae6,61b97c83,70be2f52,dcbc2831,1e8707e0,1b44c827,420dcd45), +S(63589c41,fa8975f4,c8738f57,579cc0d8,447218c,69da1a34,ee06af0c,215f6c27,c34f2ede,7589760b,80dbae48,94a3c13c,7351bf5c,33a35351,9988ba67,c2a56d48), +S(db092b0f,4638ee45,190473c7,cb60cfec,45c94d96,99aaf289,82d28af,16ba1c66,8a96ecdf,29ad2fd6,3a85a7fc,b73ab6d7,719bbd6b,98d052b3,3a0cd91,ab924f46), +S(11c4dd8d,3eddc0cd,9a832dd2,dc91c8bd,491fdb51,f5da21c5,732dfb7a,362b8df9,ba4c2789,740b53d5,51bc9fbc,776f049b,e848182d,9d13abb7,e7cd860,96911eff), +S(a65a3a01,df3b5ef2,e620d431,49fbe1,4d71457f,19d1ed35,aea39d57,89303fdd,86715f6b,f300a390,470bc272,6f12d389,7979e2fd,b0512c35,252bb571,fd19752c)}, +{S(d8558716,b7033a9b,29afb346,fd71663a,79b6e86,2719bf12,6e532dc3,f581b7d,a790d460,1e5b2630,1ad6ec43,62f79120,d75449d,8a500e2e,6f17c021,8037a405), +S(842c01b3,54353026,c43dedc7,8829ead1,db35b63d,8c4d0d36,8cd7b661,2eb5e11,f173cab1,a37ee0d0,68e097af,17bf859c,13bb4823,255abddb,f0dbeffc,573e06e7), +S(acac5cae,414c3556,38e293fa,e7cda051,18924e9d,abb81bdd,29123768,c7f21443,5d17b909,5b997254,5f56770c,dcb8af40,e37e1a8b,6e01a989,34ec22fb,f7d04537), +S(c8e73810,c024c6eb,d5398bda,3784261e,542279e5,3438d49e,83b2639f,80889aea,7a2183e7,be4f81,b0337993,935657c4,c55d20df,729d2e8d,b25af238,f3d85f4b), +S(f78c5f53,5e7ccb53,555a6f2c,b1de1c5f,da379360,f6a7fc52,eaf86ecb,dbb3bf90,cf2d33f5,eab2ee1d,5a32eea3,18f9927b,cc982fed,cc9add2e,2461ba14,9def0292), +S(4cd40c43,bdb8a042,2babc95d,eb00a405,59519074,5906a8b7,b5ea00da,b7f995f5,a0bd1c74,79125d2f,5baec520,21fb7c62,415817f7,2afb80,b2315dda,40cf4c4b), +S(647c5950,f8a7fe9,e6945b3d,6da91932,b486a4fb,ed903836,9fbc20f9,a849ac08,d331cf32,d72e148,b47af547,6794a33d,55f49ffb,be47db02,7d2de73c,542bbbc5), +S(97664e78,980a49f0,8269ff19,649e86cd,7da88a76,eb1441d8,a5f3fd2a,6ea335d2,b2898268,9a8cd91b,b1b16be8,ee46b4bc,252f7016,f72432c0,431f1264,8d7450a7), +S(523f68b,b39c2ded,81d22a4e,575483ee,d8748c9f,52c06081,391c27d7,7afe3805,5c331672,4464dc47,cc9cfe32,864b6095,ee8bd6a8,42c1af98,b3e33183,a46e2471), +S(cad866de,5cbf4938,989b835d,5aed958,cd7c316b,980b7c76,2109d688,d7ef5b25,3ae79c30,e77d6d4e,fe404b8f,324179c2,f677f434,8a1c4367,2a0fb5eb,b706607a), +S(ba065cef,b47170a,d6796033,d157fd1c,f22052d0,7b7f9992,6cd58e03,316f95a5,26177c08,bc535702,7f5d03a4,9d982637,d74a6b20,696be76e,742243be,b9ecddca), +S(27ca8178,be756f12,22cebe6c,d05310d8,5a6c4f59,eec71613,7777b625,e6d44c97,de547a17,ddee9fc5,1fecee01,45f9cda1,b65f097,5d1b9544,aa2317f5,102537cb), +S(bfab1d94,d04f4909,dee00998,78f77cc7,d9de94a7,96b5b770,5f3c759d,2ae97ec1,6ec39a8d,9e900a79,b8b88098,d1e5d79d,b75ef91,e442cb2f,27ea531a,2db21bb9), +S(b48a4f25,9d82242,59f08a08,29b05ac8,ae6b97b5,56cccb84,20a479f5,df92701e,beef137f,9f9acdc,8d31a780,2290fe79,9d9470a7,3c8a01a,35abcbee,9730d17a), +S(e3f5d307,ed2f2f13,d23ae5b5,9dd567f0,8161996,776d506f,b53e14f2,70a52370,40ecc697,7da3771f,32a66438,cf70ea9e,550194be,1af85a08,c8a4515d,32365803), +S(818b0462,d5a815b1,57216ab2,4d795886,17cc99bb,7a7abd91,655cacb7,ba99335e,c6ad05a6,7d2a391,a15b6600,7716e02c,9fe40db2,f82283ef,c9c0a7d5,ebe854f4), +S(7e3c52ed,23220b73,ba47613a,bf39a9fb,b3a6bb6e,22c972a9,3ef21a61,50cdf830,b3e4a95b,875719b3,bec1b113,9e29670d,4ba8f39a,2fb76700,f69961fc,bd01fa2c), +S(594e4129,9c1a117e,ce8564bf,ba88ce04,297f2e14,7ecda07c,5f12913c,14d9a5cc,60bd54c8,7395fee2,7fedccfb,ca9524a9,b5750b2d,d712621d,e73e0692,46c2e347), +S(3686bf4c,f387e340,6fc314e,f02c637,ee6f5062,ee9bb567,235b00e6,4d516648,915e5904,b106e057,a0db43,151ac9f8,4871e843,126d5285,337dc3b4,52c67165), +S(338dbd1f,42480753,516d3cb2,c535492b,72849870,a7828b48,643dc143,b966ea61,e51f11ec,86104334,9e9dae17,78116032,949c66c5,3c4d441d,3c88cf4,c7ad61c9), +S(56f935ae,f58bb403,7649198d,1a5da704,26fd944e,c5694c18,38c94287,2130215e,a9c48fd0,3b059474,e528016f,9c998e02,cac7c40b,8c859852,b58b9082,b638222b), +S(1faadcd3,da472591,cc723754,82546c81,c4f53c14,d0d8dc5e,ab95a58f,379e6899,5bdcc45f,42d0ba3f,783a0806,a5d08c74,a1b1b9f5,a559248a,8681b153,74e74958), +S(532d8cd8,fdf838c7,70b87ca1,4703a884,116dd928,74acc660,6ddddd61,8eb053e8,67a31325,853db4d,3e5877b1,c76e7e39,468d2d77,37cb8a6d,af4f16b8,17cd8ad8), +S(8a8cbfd6,d45e5740,aa9f0a21,f40e3671,ef897fe,bf2bf753,ee2d2f75,844ab648,d00eed6,efefa26,46c36895,3a54045d,96da4cce,8ffc554b,9bc989ac,2f62acaf), +S(38ae095a,3c705343,38e542ff,6789902b,cc1b0b5,7763cc43,2f50cd9a,d26d0f1f,100de239,87026f09,e483839c,fe9e1f10,11bcfafa,662a9331,95a8e4ec,e4fc804c), +S(82d9e5a8,385de1f4,fa541796,a00533d9,a3aa4656,74583d07,c4b3c344,b6ff8cb6,70bf2bd3,5765165b,a466171e,f26439e8,f790e178,f67ef5,d2e15e98,435b4261), +S(1843988b,42ddec86,dcc6c9ab,36b381ad,a0ca745e,aba36bf0,237e2830,579aaafb,f1bdc95c,d76337e,cb3cfd65,d9c30b7a,e7c7d667,65c9db5a,6130edf5,e240cec4), +S(a32f7415,9c2743c7,2ef192bf,4a68e838,97a86a0a,3997d1ce,fda3c581,b4fbe683,8862903b,db791be1,dbab5031,ca57f161,b6449bcc,db061438,f45e610d,50ff3bef), +S(b09dcc04,d9c30c35,2bd63880,a766da1,f6314287,dc201bbf,9605516,3db2a09,7580cf9b,7e30dbf2,8f72e9c,a5152ff1,956ae42b,3e952b18,512824c4,7f4e5b9c), +S(ca07cbfb,b24ad1a5,edd9a12a,8ac54157,6f3f2ba1,4b878d82,ab7dc996,bd7e2c95,5123ceef,cd20f120,b575dd98,43ef9936,c53cf90c,c481f340,fa166452,72af1c8d), +S(f8058324,c6b9c2e7,e62147e9,a41ad78d,60e3ecf4,17524c05,80832add,f11349e2,6a39f1a5,f577a932,3217e559,f15eeddc,af6b674a,9d921772,a053b960,a4dfd633), +S(2e3c0532,6255d80f,a42fc69,d5c92aa4,cd326a5,3e8535f0,435efb7b,694a09ec,ffe0076e,9a93904a,42251dbf,47d03e54,1fb75ac3,8f8499ae,dacb797d,7738c9b1)}, +{S(7bd8469f,80f009fa,b4960cdc,bbfbd4ad,d8e37bb,a4b2a34e,d5c95d17,7a94c207,f3062154,c3bcc160,b2aee99,aac98446,516a277d,85b37fe9,34be9359,4af905c6), +S(139b7c10,ce844844,f5d0a9db,bd7e1679,17b37e93,9bb6fd2b,4f19643,f22a6af1,32d4e929,27f5951b,ffa4ddde,4b091ec8,531a6f23,f1772c9d,ada292db,2b88c1da), +S(f49cdd14,14b38e5a,2dd34bff,3d01e1cf,ddefb954,2a641edb,df698d83,774ee70,5c10a6d9,200253e4,a932a42d,2e770f18,69d0336f,3c44f480,ce4a3305,83050c31), +S(ee145304,4771c862,745f03b,4776ade3,104ea0cf,eda8710a,5fa108eb,1e946826,b91f14,b6127808,f1175b72,2c09e02c,66eae622,109f4156,261d65ff,506b88bd), +S(c9ebbdda,867f333d,39142483,2e4150a8,c98090ec,d8ba9c09,3673330a,8777d790,c46d72c6,6028477c,e4754960,d40bd10b,b2defc1a,17dbf018,538b71b2,d208372b), +S(707bf0e3,9f2c8c6c,73a5d0d3,3edb32e3,46e73ac5,dbeef6c,60fb5ebe,b95ece24,adc6edbe,151bcb7c,2ed5fab,1cb9b2de,3ba2f3c5,ca762082,902582cd,e9e27f54), +S(4a002722,9fda7d33,320fc533,27b6c9cb,88a09c2d,e95aad01,65f68f45,1c82e2a9,233416cf,1cc1ee38,90816a09,17c5fd0d,da0bb8f5,d33c709f,6f1b07b9,916282e0), +S(8efefe27,b45a4cc0,3088b6e2,2a0baeb0,3e772763,58af3217,f39c7222,1e20b59a,b9f3fcdf,65771acf,cc7b7486,9b10bc3f,b0e8fb2,960cad82,24ea2430,fdad1634), +S(7bd3815d,6779f321,195047a5,b1772b19,ab29a99f,cc082e93,c442e927,b1ddb235,eeeb4bb7,480f3dd0,92e627a,a042533d,a9eb598a,6cd1ed9,2d75aa89,a592ae8f), +S(883f939b,6bc9169a,3860d36,9894c4b5,2863b5d8,d0348c4c,62368a94,737fc3cb,96e37629,c05b7231,8800ad96,8e922f7e,5b8a2c39,62a25210,9b3e4949,4b24934f), +S(4ad8cfb8,e8ba3265,4d32a656,76822176,95c40b92,e97c6d3b,af26449e,149f4b3c,491d3eda,89930ffe,e401b994,54919947,7ef33a8d,6cfdfb9,eb28295a,c5ce94fa), +S(ff15cd1a,4b185632,c6f11ee7,19319bd3,abce5167,65539608,b1ee3a4e,1671369,24df322b,ab157296,40aeb039,c00ab8,91c96833,4142f87a,1e00d105,b08c63a2), +S(3fc8e63e,995fda97,1d09d96d,4c84e18c,3e0f4d6a,9f8bca41,20c7c832,c4e9d49b,e17b239d,8e6f7fe7,3c4e46d,3aef9040,6bd631f2,da1677c8,db698484,85922ae0), +S(d88b3d3,6bfe995e,45812e9f,63e8b6e7,d5a87562,1c4a23b7,ab46f6ad,2f7d1e81,63079694,7c97b00e,311bfdb6,198c2c4e,eda57d09,b17fd74f,7140b40e,d2842d06), +S(da6971d1,4c0e9c37,e5b1379b,9cedd83e,218ba47,95e4af56,7956922,c64750cc,a14a0bd1,ebd0727a,258c1246,3aaff478,fcb490f0,53d08a40,44cedc97,61be43fa), +S(d098ccf,e2fee442,74377e1c,57d0b924,45f0954f,7af643d8,b7ed5d9e,956fba23,85c99754,17df24ef,2786621b,c0be5069,a9c59da1,61e14759,ee26b524,e9587d18), +S(633f9b18,9dd98f3d,8c4de,528f7170,1c9d5972,cabe3219,cc4e5f0e,e7e094e0,3d69c877,28c859e5,d9e8ea27,3c04ec98,ca084df5,d7c9cb34,9fa537ad,f7da0b5e), +S(2e14be9,af0dda46,8d59df19,9ac9edb0,c875f829,5715cdda,5ba3bed5,d54fcab2,a04688b,64c5d34c,752396d7,f864a9e1,59eea9aa,db8c93c1,5b4d7cd2,539bfa0), +S(adc92567,7678b197,1e45ed31,38a991dd,a4cd3586,a1ce1498,3ea30be0,642a2dbf,70f2c69b,7e47aa55,cab6ab22,e6482571,e8e1ea52,a52df934,d5ab99d9,acce2770), +S(ab89aaff,b04be186,183e8076,46c64111,476c552d,10df84ba,10a1efdb,32c01162,fccc1e20,17ac63a4,b9f78ca5,af245a74,4174c952,cfe29491,11ce1d71,e4be8f87), +S(1195576c,ca3a49b9,4db3f827,1ff2308e,66b66739,a30d73cd,e8acda4,a382002c,6a2be3a1,c6ae9f0d,b314a7d4,728977f2,17e7c7d0,199868fb,c7f79d31,6cd7d32), +S(8a15bed9,bfa215f5,42c62c89,da0adb8,c68cbc33,d9c879d7,a2f2803,b7068556,ef437bc1,1786cd73,6dc321d0,a3360517,3e7572f5,bce04b7a,3c8cdb85,cb56e697), +S(b4521d6d,f9b20080,4d3799ca,4cdc87bc,ea970d60,a3005071,e910210f,5654da88,c4ddf348,2a23e98f,b86ab9e8,4decc6b6,ad18d879,e96435d7,4b944d8c,f7cc1587), +S(4074523e,b75634f7,6442c3bf,ed9a52d4,5f6636f0,77a10e84,5e6ed950,b673a9ea,d8889a02,ec95b511,aa74db1a,10c91547,45b89b57,981011a0,9d4ce57b,e4e1f032), +S(b2e71794,e6ac98d1,ce532974,df79215e,bed8c668,561dc391,505e9e26,8444a858,94d8ff19,b8a74599,fbe5f471,e7f3e1ff,e0238cc9,2504f99a,9c4f5fbc,2e482854), +S(2e672209,8a6b4ca3,905a8910,6d23daf5,aeee63e4,34e7bade,70395df0,e5a1af87,708e9fd2,a3c0a3b1,b0e03f96,c3d477d2,abf6dc0c,bb8a7181,ca4b18db,ed12e3f7), +S(7ec0fbda,63fe7404,438e36,d567d9b0,bdf18b09,d929329b,24a8bc91,816fd433,f80ab84a,99d214fa,5d288e3b,c2b5560f,a1791412,9c3d16ff,cabed23,736e4f85), +S(f166252a,34572146,8bf3a3d7,bdd2c67c,b0d36b02,d7a70033,add26f97,128b1637,134eea4a,42b482c7,ad625407,bb89a615,656e3a2d,232f4bbb,a33660b2,403d6f63), +S(7af860e0,27d3b1df,aa0244e2,51f9459e,488afbce,6a3aa610,e5e223b7,81ba2d93,6ad22116,415c668,7dd3f4f7,b5a00599,bd35705,951e1093,3f85f815,4d0c8af7), +S(e4ad03b7,e01c5d04,7030fe59,6e7e7960,77d9847a,e604d2c1,d801a5eb,e21c0731,c7757ea8,f57af58f,b64f3eb9,c7762bc9,544f28d,a80d760f,c46b0c9,589019e8), +S(ffb2f941,f27aa8ad,6a59ed01,24e83bb,d49f2588,a5602389,15329f6d,f77220dc,6812c00,7dd44185,fc3f0687,6f7a62d0,d31adc40,c0a1a060,c67df13b,e4cd4873), +S(42ca15ab,9f245041,ce991e19,3d696f4f,4c277df9,8cad603,8ad0772c,2da6e03,972d10d9,37e3a836,9b831b2e,347ff11,29917a59,7ef94158,7c977604,73cb849c)}, +{S(576abbcb,8b768480,882aefc,81380709,831625a4,b9de63a7,b9c3390b,9cb4c7fe,b49453e4,6e17bbae,2f1f8f9b,91c3ed04,80d5f194,33917cbb,d28b878,bc6e6c4e), +S(f9d8a157,c151181,3e085c1d,ef2958fb,df2a17b2,6b330a0b,2d512c87,69e5c14,7eacca29,26aa402f,f8b78d57,f5e02add,91087da9,d607bb41,b56a40f8,f7b19b78), +S(d31dff73,7d2d3422,7fe39dee,b2eb4bcf,dc84bd39,d6cfc4ea,ff09812,23400a80,4af55e8a,fe8e8ab1,2e2c4463,d41824df,7b53e44d,efd946ad,b6128214,4244055d), +S(9ff2bce8,a9fe6c7e,e68a8292,f0d2f4c4,8d963c47,63018a55,89a2c130,667bc861,eb138923,94aadfc9,6eca7c5,78c0fcc,bb31a40f,98d02e93,a140abd3,cdf041b3), +S(1397cd8b,aed3c601,b6eee616,243a61dc,fead22fa,da50db4c,1f9e2776,6e5bc9da,534a8e23,59316503,cae233f0,3b6ef0bf,1c7e0105,119d1a49,ee688f04,40695c66), +S(4ee38986,511024ab,5385f710,42bc3778,7cbedd0a,ad13ba24,b77f42c8,2ae935d6,cf87468,24a38404,f313965,a64c927e,4ba0b7e0,140f6b36,47e2049e,35a74e4f), +S(7614cd7f,9b5f1455,74d0d38a,370f69ca,f3050297,10af5242,e5ccf19b,187dd189,b946eded,e4b72db1,6dad876e,396e836a,875d7c9a,28a9c739,f665c741,29ab7648), +S(67fd2372,5bfb445e,5254bc42,f7dbc1a1,65bd4017,cd1019b0,8a3f96cb,7b3c7cec,b556e950,a144febd,a81dd3f2,f729ecb,fe43fc78,8658bb7d,2b9735d7,b06a920a), +S(57572b1f,1f17070e,e9b30b6b,c7168cb2,4741ec5a,b3496b1a,c06ec0f2,5f910fce,8cfe2940,3dc97084,7ab28da7,167e78fe,f2310c83,ca476a97,91ca35a9,610bc560), +S(1f111332,1e31a294,cab4df73,5a0ef333,e753c2f,7c83705c,9a5bf27,1321c4f8,8fed26de,202c92dc,5b51b13b,6e9bae41,3c7c88d7,b858dd72,a11f073b,e2945f9b), +S(23c9e313,b04eebff,15fb0625,43de6975,d19decf6,6416f4d1,855083bb,d738f882,90673370,f380ca49,e876d5f4,b6649de0,24f4454,29cf9d91,96f4f196,8a49ed99), +S(b9251407,6ef7f01e,379aafe8,8f22c156,65a85ead,f671d8c9,89602c5f,804725e7,b3a9409f,7bf973b4,aebe08e1,5ac65562,56983f89,23415e0d,eeda4f4a,c0d7c5f2), +S(1bf9deee,948b3fe1,b4345800,51c67266,8fdb7af2,99275a83,706f9716,7e38e38a,688fc563,771b7d27,f9c09953,c40cf009,a55d7329,5fae0b7d,8fc37710,729a3911), +S(34e20de5,9d00dd45,19a70b3f,2994fc4,588ca9b2,beaf6afe,4a1daae2,10692f33,7804aff0,a43f1ba0,438c05ff,8d013e3b,e5180bb7,3a969825,fc97ef52,6da1b6a8), +S(80fc119e,85e88b0c,8c84d23f,9e44e96,1c7722d8,51d4c9bf,f1824fb3,365823ef,efee941a,a60743a,28b6ffd,39762f9e,437d2b00,206e718,7fc423bf,4eff0caa), +S(89ab0f45,e3860393,f24b1845,7578fe79,b812926a,6bff3788,c8baf283,89fdbf0e,57d4fc21,42bf446f,8e4d9331,659e7673,90391fe6,62e77ee7,f7a4886c,8f440c8d), +S(1f092931,664bb98b,79d8fb4c,efb287a0,f72641fb,1cebe711,820c92e0,42f26437,59f63ca0,b8e2e959,a97b1c1d,1cfa4c02,380dc42f,db7cb5b0,995ceba1,d7e45d94), +S(95ac9f36,f447928f,344eb4e1,9ea806,717600e5,148ad222,fdd52a83,86bc3537,cdef5355,e928b1e8,225b5a53,bb976822,6fb50d1f,6c6cde20,758d5ab0,e9f28543), +S(a9ce5ddd,9941ea69,1343ea71,c85fcd73,6269826d,6eda5008,44cdd1b9,4a66044d,29504563,1fcb7590,27d904c5,4ffc325,2ce3c8a2,169f4649,907db751,2ef3ce43), +S(2edf81,45c4bcf9,62425707,ccb36a3e,7fa1fadb,4062d14d,f78771eb,f3ec15d9,dcfc961c,547548f2,73206d9e,aa0d829,a235f66c,5afbba92,68fdf9e6,abc8260b), +S(fcf5b985,c935e207,92907b93,e9976ceb,ed320a14,3cf286ad,b38540ad,b4077dee,8a0e0b4d,1ab114b1,caf7d0d,f749f219,b75acea5,6a71b3f6,aa18557b,1da85262), +S(2bd4391f,42b70803,2baf4816,54569f48,95f1434e,be6f146d,41447f45,f14581b3,dbc9937a,61f43af7,42635810,5cdfa02c,49a5186,ce67bbbd,7ced2842,19a37506), +S(eb00deae,6cf69ccb,abe6b93e,e5493e05,d22e53c1,b069a6c,4660330a,4e3bc069,18002f2f,61b08dbb,60c784b8,4c6d71d4,6b004e6a,3089a0d5,f853d659,83242d9b), +S(c7c62a5f,ce15326f,25b2fc5b,697cc7f7,26d231e9,e7e9f15f,5998b8b0,10605524,8ad4b370,ea0506f6,f25eb16a,78f87ef2,f408cd17,fa4ec63d,4ee21448,1d5286b7), +S(aa1c2baf,632673de,6f6704aa,5a76c077,be0c24b5,223de654,88d1386f,15a1a002,de4648e4,fda7db79,41efc5e8,6fec516b,c6aef164,62d6dc08,fe93ebc7,a85261f5), +S(11871161,13c3c670,e7f5366,edd22282,1f76ec98,d1a3500d,f0e483d1,e53f2666,d0042c9e,8dc1d72c,f53836f3,2c76b5b6,52fd5ec1,9e8fde42,aed1a7e0,9d242745), +S(e232a92c,9ffdabcf,24422182,34078534,6b6b79f5,983ddd57,2580c3df,e4ee4118,6c1144c7,471342d8,7a784fe1,587ef576,483f8980,bbab12f9,35aa0d84,83c1d76d), +S(1ab6237,3998ded,e50aec45,8043f830,8a7b4564,2dd3c9bb,4804f98e,a7c2e0c9,5528e158,6a23aec9,81f04b51,b90576a9,a9e7feb5,53200e51,e604898f,e55996f3), +S(3bc24bc9,cbc58de3,46644de9,b17ffa7,39a0f7d8,83eb9f52,af19eaf4,d8d52891,f71cf5b,7587c275,8014127b,f404b70b,b257bad7,f5b78d2e,c792e1d6,b2fa4493), +S(a2bf9afe,e6eec182,ef5866a,b4bdfe2e,9d045323,343aa422,8c1a13ae,fee515dd,a5ee438e,3aa35484,c5f5a1d5,43fa15d7,ff0d1c55,6571678b,a3c5694e,f93cfa1d), +S(a0b2b4f,ed0ddd23,8812806c,fccdfa9,7fb3b42a,748721ae,6477dc9b,18953133,325ee7d3,4a540d0,fc3e3935,79ba7372,905c7b17,4f12b456,b43db5c7,cb50ec66), +S(e7b9796b,5ca006d1,632f482d,7f0fe393,2cf16a5a,e104eea7,a7ea1c25,1073e879,ed476773,e6e961d0,20bdefd5,8c833e35,634a40da,1256750c,c718ef75,45575e97)}, +{S(a8565dfb,75f8eea8,ca9ca6e7,c7d18a5,bf3e437,5d1f4e87,68d5f51a,57199ac5,daa7d7c6,cb86b215,a682141f,2308d9b,4c204196,eb779f32,fcddf0a2,da194921), +S(974619cb,86016199,20f507ee,62d10295,44abdd66,456952a0,54e945bd,7890250f,6c8d8bc8,21da8234,1ffd0cf0,548be1dc,a1bb7e1f,47354dc8,3e5d96c8,2c9676f3), +S(24bbdc24,1396b6e1,75f23a6,4bfb41fe,f8329b80,d306586a,ecb69e41,2a2014b8,aa6448ec,f00a0710,27b46f09,d696642b,9274ce3a,11a3e986,e84536e3,7fd7b2f8), +S(eed9a6b4,68004486,e3bd388d,591d3b65,2f35a3f1,9401e5de,81a86f5e,b7cd972c,c81f9aaa,d7300671,b3dbdd73,a095c79a,d73ffbd5,9f845eed,9fe3a57f,a41e9468), +S(5260e0f6,fdc6858a,8d519d3f,6c71929e,36979b65,431a6f3a,a7507797,e54654e2,5af860e5,fbcf9676,bb00c329,d3e2e058,efc860e5,cb9006ad,224caa32,9fd49f07), +S(11e53f67,d844c511,b8118f28,de6ed9b8,66b70bf,214d4d1,ed79adfc,18f7d6bb,20dd984d,7b9eb626,77e411da,2e823045,685a4bc5,2a3f4e5a,3aedea95,1060b330), +S(98c9f3f6,81e220e6,d4bba711,fa8b212a,dcc21bc4,8219b813,eabdfac5,70e6fffe,bd0890be,d9cf4ec9,44f6abb1,56250329,a37d2cc4,64c931ba,8606c2ce,55127aa2), +S(f644f4f0,43d7713,ba4380d8,26ad0f3f,44106352,142fef13,7c6e05ce,5e9f1571,3192280b,f3971223,c00ed336,94779866,536020b6,79ba8cb5,c4f9c515,69d2f97d), +S(334ab869,32c4097c,8d8d8a23,d529b079,6a759d47,a907b047,548e735,5b3b766b,18f11736,d54c9d00,89149b07,35f5a9de,b15d9c,cde4ee06,155a4f3f,de98a7bb), +S(983542dc,61b43ee5,c4a7f36f,22da008e,832d4eac,6791d838,1a095d0e,6d8a14b5,cd225f2c,334d1ba9,94b0a681,d6be7696,16bfb2a2,426e9939,d2238cd4,43bebd02), +S(dbbac008,1b678270,4a0fcef0,73683822,a3d4107,d7f1a71b,41497da2,9cc942a0,cd25ef66,36f21a8b,532371ae,b91b67a,deea5797,983dc36f,54aed202,d9845515), +S(477949e6,9ed28a74,879bc8cc,660696cb,115e6392,5a63817b,60e5187f,1f77f3be,dd8ca490,fb8e3bc1,44f5fe9f,aa41ce73,56a1dce1,cc8e11c3,ca5725e,d1b764ae), +S(7616b9e8,b451d4e2,e4826586,9bfad6c8,ddbf5fd2,2342c6c8,42d6bbe0,398f94a2,4e3bb1a9,76efd345,3c4474ad,e6a494f6,4f97c6dc,c98cf68,72bca24b,dd9e946f), +S(b87fb86f,6ec4ad7d,5bec3bee,e8d68618,c8e4906d,1c584368,ec819f2f,871ca8c3,c64723c0,aa587911,4dda9c75,493f739b,e8c2221b,b2e75ee5,b25def54,a1d40c2f), +S(56ea4572,61a6ccfb,46fced99,1258b31e,8573a488,aa53b7ad,65333452,b06d41c4,d8529601,4145e12e,a72ae4d1,5ae6e5f6,9cc88ba1,4d79467a,3df3bfef,33d84290), +S(e4c6540a,19682e0d,e1f1258a,103037a0,af4df5ad,f27cbb7c,9e3ce67d,e23e13d8,a31e1b08,4bdb5728,36e53d93,1de035,c90b1efe,b5343b23,cac0e7a2,bf5b3868), +S(1902cf3b,90fae93,1855d758,24995b03,e1604861,199853c6,ece84903,c8bd67de,3b3d41e3,a2dd4c28,16d492c3,e6c53c83,e5203c7c,a8100d41,24cbdcd0,e12fe222), +S(6519f4d3,b5d731fe,eada6806,727623a4,daf924d9,b6337a51,56096ec4,16ab42d4,62e2c1ea,afa990bd,6dd91675,e3b2d1e2,acb2fee8,e56ec30b,eb25bdce,2d3ad30e), +S(e1128682,519b965e,a933f197,eb0997a0,16114459,4c0915cc,9c55ea4,a30c1ad1,cb1370ba,f8707c78,84817ee2,8227da3b,7b7c97c8,266af491,e0d52bc4,ea0f9614), +S(4366960c,6ff595d4,143d4cd4,f0f0df2d,3bf864d5,73790abc,23419c7d,6ed9201b,623faab8,2caebb5a,b4c42bf6,b2a686cd,4640cde1,a95a65a1,f8d32836,9e5ee0cb), +S(5acdf691,3c1e283,c1220355,6efd99c5,d347ef69,bda1d040,44cbf0d1,ae41b16a,1bca567a,71698c35,e35e031c,e8a98dd,e34270d1,4e2e2439,9276a7c3,6a1f35df), +S(807ecc04,81aae374,1efec46c,8c6c194b,faa0607c,cf5b7cda,fc270fb5,f5b416bd,cc60be6a,6736dd94,848fbb05,375f6459,d556866d,165a2c16,41984411,dda33fc3), +S(29c470bd,97737284,765adcaa,68a98af7,5e6c275f,fa4fcd5d,6c71d428,bd3bfd79,b19ab40f,33c15201,41fed31f,681f176,4a464373,23283677,a40b4018,99a6eec0), +S(41a6d6f9,40bb8abd,9e8748,dcfd23f0,5333eafc,4ce311a3,161440a6,619efabb,b2a3702e,900788cd,bf35204,27e0facd,b090804,62f65418,89a3c34f,ae2cc008), +S(d5f5096d,776ffdb,f694b9c5,c9a9ae0,ab5897ff,c5ca3320,82cb2a2b,8afcfe89,6461e24e,28560d11,336244da,2038e13,c69ed5,a7a435a6,d07a1d72,be43daa0), +S(f65a00d9,5707ce6c,6bd55e8b,4b0ef381,1eca65b2,9845433,d7b307e,518ea724,7ae079e,9aecabf0,4ec5210a,b85328f7,e60c8ff7,3deb037b,c8e6e1d3,34774734), +S(346cff42,23c9ed2d,a1082d46,eeaff341,f7866e72,d95561b9,678def2d,9f7cd187,f97f85d8,92002750,11efcc9e,f8ff58e4,894f105f,b94e7390,7e185806,575698b3), +S(d0e3cdff,a47417f3,86f64a2,4029e3fd,9bc7a464,6e839bf9,232a0d50,349ecaac,5bdbecfa,2a2b35d3,ce2e9837,222535c1,57ec5bda,5fd70186,1920803d,a279989e), +S(f6bbbd77,b8dba8fd,704a3f02,1bc418c0,f8524c49,ccfcd14d,fcbf7f04,c9a18d,38184001,f39b257b,6755a132,86bdfd92,1a8ff771,fdd5530d,48eb8227,ea70be1), +S(6717bbd0,f019990a,c01a2996,e34f0912,9bf60a3a,71d8124e,fd86c777,9cfad879,9581f790,a16825d8,f44f316f,db3f0bde,108643cc,b390bdc0,75f3dccb,6520029f), +S(417c765,ca91a120,2b07459e,3713d5e1,bbcdfa82,bbc26cc9,279fa2d2,59251fa2,8d281a2a,ed38a80a,cb697989,9839d7c5,265b4e78,8a9e1176,66cfb6fc,4143a935), +S(e2f349b0,f89c69bd,3c8cf2a4,10730dc5,8e0beed4,7048c58c,15f9ffc2,508d2cc2,e014d0d7,f07d8dc8,7e79f513,89fdea45,bdcbb417,1f63424c,81cb8426,1f2b3be0)}, +{S(aceb57c9,187a5202,118c4dbe,573906e1,646b0325,781c1352,574ed15,e02b87b,68ece7f4,4037ff05,d4b89120,d90f08c6,f0499fee,d4e9e02a,a2e68bcc,2d7b70a), +S(365e555e,de9130af,99f996b2,106229c,c36c1ea5,8b065cb5,38af3a5d,2cec1145,81fc523c,b4b97bd3,cccce1e1,d1980769,fbc25a9f,a403adba,8e7e8074,13c87f9c), +S(d0a3812c,b9244d7b,c1f5b652,adbb0df,22d15d41,b1724071,fd297d00,bc8cbb01,f8d7650e,fda2be30,24ded196,eb3baf7f,351d2013,2479640,16ee4c6,b469951), +S(8f4ce1e2,a51c0ebf,f5e34cb1,c6aedd87,85e415dc,e7307119,143bbe9a,3e7fc632,617009a,ee7d4d81,1ba2bf14,d1647911,bf1a3bbe,cba8dfda,9030ead3,803fc217), +S(ea23d837,54cb2e9f,9b884ef,f4d1a708,bc1826c6,59fea53b,f52c51b4,9fe0e21b,7e8c691b,cfc3b7e,56a7699c,4f56a11a,fca5710d,963d602b,b102e1c5,b36dc3f7), +S(e3c970b2,c764c9f4,ad8bdc15,cf995690,807f5d09,4a849787,9d278d18,eed6ceea,aad8c7d7,13ce5439,b9125d9e,c14b5d8a,1c694cfc,f84e6922,b7e58df1,4ab8a34), +S(8ade30a,94b236b9,9597be14,bd421130,b6843895,a85f3613,efcfa0ce,9781a96e,78e4bf57,974cfc0f,c310330e,6aa47de8,2b0f5009,5a703fa,50093d5b,a8e8f0ef), +S(fa5f1cd3,4427d71a,de7e79b2,b0a17ba9,66d05324,1f9996e,be8143c1,9186d24a,3481bd18,2319ddf8,f344e4b0,196b3ddb,10deef4,d8d75c0e,49fc5fe4,cbd6e1fc), +S(8b88b79e,8cd28dc8,58e3f1a6,155146b9,af1e3697,d57b7435,c649f6c3,bf8574ca,e736106c,8ffb9bf4,d83d79f2,4faf8fe2,ba5dc258,e4ae1b1b,b58a1a7e,4922c95b), +S(12078a5,5c46d721,96a148d2,fdf6505b,d059e423,c5d5295e,facc2b82,aec51f5d,66a4332d,cd265085,add9a141,2fae2562,17441d7,dd9596ad,46309a0d,bfb4e55e), +S(841523ef,29f5bffa,b31a526d,bf74b16b,fac3a3aa,391f7404,6675cba8,7808c171,7a3fc3f5,bac300b5,7ef843df,e334c995,cf66de11,2283fdfc,767cb57e,e7e7329c), +S(c8831ece,f4545c2b,387378b4,f88173d3,f1cc7db9,d064774d,60394f0a,ecaf5af6,f32f1a48,bb802757,34e66cbe,58a3ed3f,adf28dd9,374a42a,a824a095,6701322a), +S(30001ff3,7b1b1691,9a135a31,287e3a3d,383ef3ca,94748e33,a52c146,586dc4b9,9d71b25d,6fc35db7,26b58d1f,642dabb,46dfa64d,e0ec2a12,c53c414a,9dd2574b), +S(a17d3621,74d3c789,c4e00888,fd4b0f4e,ea3929cf,afea9e9f,7439901e,d6b0fe44,2bcf09ef,2d374194,510fc057,dc973fe1,bb687428,91e9056d,a5b4df7a,de79bf), +S(4725e2cb,19f95359,2da72565,d8405e09,92a64299,9ad74ed5,b41f5d24,44cb6b0f,be23fa82,7aec3121,7b90028d,b61d1092,764b2824,9f3fa0ef,91929db9,b2e0246b), +S(67c560dd,74c276c4,df3efbe3,b95dca4e,a56c4563,cc7ae225,ebea90e0,f5e212fa,2c9e3120,d52ef31d,7e9e36d6,eafbcdbf,ed8a28c6,7edefb94,1df7f38b,cb05c160), +S(8468da98,7b33b79b,e08da5fd,57cee298,ef86f624,3bb975da,2f4261e8,f7531d92,455d8a8e,b4f45693,2e8b6f77,ddefe070,591dd37f,d6ad3a27,5774055b,8a63e650), +S(3416d4bb,78de7570,b1e9e912,83a3e8fc,be6524d7,4463dee6,82e84e52,72c0953c,94e55458,2c17fffd,321364c9,16658093,986b56,f88b4818,129e19c8,ce685dcc), +S(5c66928c,a39a6e22,672c1dba,8bb6331b,41a7f43c,a72276a6,afd3e209,6416a9c5,181cdfc4,15e7d6a3,c24be94b,7fe328cc,ab624c0d,dfabb1b8,f9a73b56,cdfe1b28), +S(971f7a13,210680a3,ff6a12ad,17481a63,ef624d0c,e4121166,7e63aaf7,9cafce,5de2fd1b,3149e321,2980c7d,88a49018,26f83f18,7438061e,9bdb8d33,6a4b08f6), +S(650277a7,9ae7682d,c5f3526b,8411342e,b48277a4,9876caa7,61ec6815,9a1f13c3,a903255,fcf09808,cd97d92a,26dbd2e4,7a29571f,ae91107a,7cb6f0cc,3aea1985), +S(76a79cc9,7fb80ab3,e8d31e5a,d11f5ce4,74696d23,f1ee7aab,3928848b,556f483e,1779bc5d,c763d1ef,7611b402,4583f07d,c7dc9c96,7afcf83f,e6b6ee42,da75972e), +S(6e0b4015,474fe250,d372400f,13efa0b,70c4e8df,816c0e8b,8d27a7,a8168d54,f01dafc8,8178dcf7,15f8fcc2,e7163137,9e1dd4cb,6c88cfbd,e9a051f,ad204c3f), +S(ee5dd472,b5efeba9,d0e354dc,21228d22,40a69088,842d00dd,6b6358e4,309d1f5b,bce93ac,3fd4a098,9e74448f,5832643a,a2a172f2,eff1e2c6,c61ea99,cc6e7cdc), +S(df99a925,ef2e9f9e,57208fe6,5373ff94,876b1448,368dd453,436c59d0,f2a857e2,88dcfe81,4397f990,56f92a27,143c902a,2a6a66f7,f7e9652e,e0b16f13,33252a1e), +S(9186f095,43dc64db,ad582561,cab96a38,89be54ad,e1cdb27d,674af836,22b5d284,71ae31d5,a73b29f,54af1aa3,2d8e541b,14f7cebc,9279ac26,c846d466,aa975e20), +S(645da454,63357bfb,61b5b932,1897a73b,87af6077,81487bc8,af1a66ba,49bc5e37,4b925aab,aa7bbc19,5963025e,f1896cb5,b6463242,cd8a35f3,b1b404b0,7faf8e94), +S(5cd9a6c4,e9d372db,90a65f11,1f1a1b5,f28bc3b8,3d05f599,39979c91,5277eab1,c147420f,7dfc4ef4,d7d1f08c,1c523771,86a8d7a7,10cd7017,82b97c55,63287aa8), +S(4fd699b1,2c720ccd,7b977e5b,dc622671,18ac3028,bd635b26,fce648cf,335cacbb,3936f10c,aee5f51,26b86240,3249e1d3,5566714d,17ddc19e,cc4d1056,71e523f6), +S(b3fa0545,83510d6b,91226711,4bac7f4,ba4ae5fb,baad7230,3003efcc,4c3c18e1,57a3db8a,6cbf0a94,845e7d67,f9b01902,55aa5b66,ef31abd,34ee0410,ed55d0e0), +S(fd73c052,b194c6c6,dd46aca9,d640981a,ec796009,17a565eb,e77fd534,649a2115,9df8973e,37e877bb,fdf5454f,d9082926,fb09fea9,d162bde0,fb635483,59458f55), +S(2982dbbc,5f366c9f,78e29ebb,ecb1bb22,3deb5c4e,e638b458,3bd3a9af,3149f8ef,59e4a416,5099ddf5,4605acc6,384a4362,f6a2466b,ed1c127b,a918d94e,e93859e7)}, +{S(8aff982a,fbe09f67,6d6e0f49,e2b68f88,8f20dd2e,6387b420,8157ab24,d19027ed,f2350ea9,d00fd861,41259f03,b51b5326,6ce05a34,74508bd4,31ca74e1,366eaf92), +S(27ff285b,1e14961d,a042bd31,56aa44af,5e73717d,fa413a47,b300f358,e1960dd0,8b578851,264a8fea,2e29bbcb,cb9c90e4,93e8c731,983f4bba,65381e88,bc83a8a7), +S(fc6acf61,4a214859,1418ab5e,e0f0274a,309a8248,2cf01f73,db8a9790,825486df,190b9c0d,46953d99,c9de2bdc,bcc15d23,ee90485c,c4c152d8,e28322e5,4c927d54), +S(743bcc6,ac86b0be,a25cce81,1fdcfc13,73f23926,e3116fc8,9415b8c0,4c1983ac,f3df10fd,4afbd3b2,dc0678c9,102150e6,3d005680,6a5e45fe,c95ea495,9f2b8555), +S(bb165428,2c13362b,b1e017e6,6402613e,f82bbe22,9429f29c,6a1a522e,4956d67c,ec542c4f,7fbf3c6c,32e71aaa,86e3e4e7,e52b0d43,98589e15,1f17417a,40b31b07), +S(b3f74ed2,5a7fd474,5820a2f6,221349aa,e41af762,25c2b706,160a463d,1d59e7bc,a9af9d2d,89dcdfe0,21ca46e8,5f09bdb5,197c8f23,bc56d705,851974da,1608dad2), +S(20c0914e,f88902a8,6af0ff68,a08f96ea,25f15ea6,b1128900,120028a1,1049a77a,339567f2,71a1f1c7,16eb1d56,2f009537,68ff4cd3,9a81c6d9,6359d2f5,5d04db9c), +S(a3555aea,2e96f05,d25a145e,4ad0d2f7,fb453974,8c4a3097,a703c0f5,404a0e7a,ee236b76,8fa04380,b0448beb,d2589665,e43299ee,b9fc78fe,5a64db69,ac92b7df), +S(37191a66,1d2a7bd,c96a0767,ce47d97d,7acfb8c0,ce251e9a,1421e2d6,29230c2b,57093393,4783afd7,2df6524e,871c8e67,ff2f48c9,c73e2054,fb219cf,d3c2a68c), +S(1a2f5b6c,5fbe300,8b01407a,b0b28c3d,c823cca9,b4c71a1e,4fc814f1,e186e062,b2f1c632,a9d92a4c,82d31a55,f4fd50bd,d53ee99a,2e1452a4,e43e5ac4,b8cbb7c6), +S(2976575c,c5e70e47,cd9c10e1,32a593dd,12b65215,38613cb7,22390022,73fb41d0,c3f0b08d,a2a3a046,d87dcb13,38c35824,1a8b9959,e2567543,852dcf73,c4f5cba2), +S(bca28e75,5cd6ab74,85884b30,ef399f,44188695,fe9c4143,6016bdec,25d502f7,b67538d4,a571e935,cbefe237,c5a01f77,4ade337c,fec9f95f,3e9cf042,f0dbab6c), +S(3dfe1718,beafee83,b858048d,25d46ee6,7741d3bc,bec1e52d,3ce308cf,738b715,8499a8b3,a0c7c599,f62f056a,a8364494,ec6e0198,2c47bbf8,7e2df591,de0ff537), +S(bde6252e,a9e4823f,36bd1737,ce188fae,be4a271,9984c9e6,76f9f4ff,d070c1c1,2e5db82d,e02a1fe1,39d903,7e7adeef,12d40366,de0eb164,c04b2ef4,b1e849b6), +S(2c74b766,eebac93c,479fc0bd,78a3805,de50be2d,a6ad70c6,9048e43e,c91343af,ab7a929d,588ff993,55094f83,6e7b3b58,c6381bfb,b284f9bf,7dc44cc2,67cc741c), +S(f0e084a7,af9abfaf,b6ebf3c5,b526d545,b8b1cf5e,8e09a06c,3670aa37,6af83a3d,6bb279db,abdb2b2d,fcc97510,2b075dfe,b42d9e6a,5a8af760,f4b63788,c315f8dc), +S(715aa28f,4e52fc26,a2f4b9f,391894b0,6adc3b69,b508827b,4732396f,5eb7edb5,c5d0d68b,3a8c6532,2f6303ab,99b6c48a,88572c4c,56c780d1,d51d2441,86ba110c), +S(8f980e69,3511ec3,cca89b2c,362835bd,24d9c8a6,97deff86,5540f7c2,b0bacf8b,2d5e8470,f2041ca6,f158ac83,e92a2345,4059492f,af27ada2,92bbe51a,d67ee5aa), +S(6823a4e9,d80838b2,750dada3,cc31f59f,3cc9d6c8,3f33aa5,38d949aa,c4d6d657,e087127a,3ddc19cb,e4088a2a,6df61863,e8e81cf5,c5cea4a8,8cd2ab51,bfbcba8d), +S(8c9af14b,11add28a,818f85f3,276d1d7a,1e3478f4,23e74b72,caaf2440,24558538,a7c17174,da1eed2,7eeb7b6,c1d93e4e,9e4515c5,3cd888d5,e4527cdb,94a64fb1), +S(5fadb7c4,74b13592,a1a27f76,b7c2011a,102b66a0,c6ffbc02,a7306e1b,a9ccf49c,7bf61c4f,134f8b4,7a5f90a1,938918a1,4d151f2c,7f1c4bea,cb8c4773,cf11609d), +S(79a21b82,9325fbe5,c01ac979,8b89cc47,379eac4b,682fd747,47e0c04b,879b404d,abfa4d5c,7ff916c4,9f489c12,5235bd9d,a0395b6b,84d6699f,c96f9c0a,5a4cab2b), +S(b213d11d,e4b5601a,5f10827e,d39a7825,adc36bc0,1130a055,cf8b3e8e,fc96d10b,27c0e5b7,a739fcd0,5eb73321,3fd1bbb7,873de0a1,2b92cbc,21de57c6,2bc812b1), +S(299ef8e,e131f523,72949d7e,fc2f0f7f,9965e69b,56725b55,4d513435,ac8b0b3e,8ba93fa0,2a4d97b3,54d47c10,d5d791c5,f724b68,4f501eda,1931e563,2c6faf06), +S(5143ab76,43a21de7,7ffd0f3b,c4746fb0,589be22d,9d9ca2fb,89403a39,86d1cd37,20991000,a7c01e4b,26d9236a,45568bbd,91c968d6,c87dbe05,15063af,d8db5a03), +S(738ce787,49783066,923ceec9,a841d60b,56855e09,93e67cb9,9d52a0ca,7a64b5b2,aba44aa,272945fc,5eee0330,976b659a,a6455dde,feb5c894,cd274414,71610384), +S(6bb9bbe0,4c3dbaf,6c60adcf,5ec5fa59,29cdb04b,14633c10,5dfca2c,183e1d97,b7dac59b,5c35c3cc,15521da5,89c0d333,9dac05c6,614acaf1,d8b9e834,8e02c3c9), +S(f325eeb8,49a32b2a,fb19491d,8c3c112f,a7ca3443,438c8c19,99bdf791,6981472a,169df94,a26f26b1,e5aaf810,7a148faa,17742c3,10cac320,6daa69,f8aad67b), +S(d279bc0c,f7f58a85,b5abbe25,936d5088,4d8ae8a4,b415ea30,2c0f1133,de98603c,1e69875e,2e38f9af,222e03b1,6c833bd1,12bc10f8,1724da7e,bc780e6f,5228fd17), +S(224d079c,750eb1b4,2d70aa25,5fa0c3fd,c2d07c1d,ae4d6cb1,17c1e61c,5ec1c6b3,e54dc4fa,b0e05362,60d27fa7,ba53c37c,a37ce30e,617365dd,1c58a59d,2c93ed00), +S(f4741ca2,b3de5414,49426531,d546272d,ab8fc55d,8f65eb3d,5ea780a,d25cb53b,3b7290bf,dda0d0f,e3704f27,d8537063,f2fe9571,4a0791a3,e1a25865,96a5b0b1), +S(e931258e,8eb5559c,6d697272,8a704c17,b775a26,5b4527d4,a4d4d742,bbfd71fa,4e1ccc9,b3c0211f,17a14be9,636ab4bf,4c6b931e,44a1ca0c,c2642f2b,e8b2c928)}, +{S(fa01dd32,fada2843,c51845e6,3cdc1b76,79dee47b,d2f4b767,5133aa5e,62029057,6ea6596a,b0ea0201,b6c8bbbc,e9d07fd0,8040e1fa,198c8767,67ab6055,34a33), +S(97ec9d33,a9d88115,471619b5,3fc58a08,e6997662,7a28afc0,b75b2f49,55eba300,92ad1d6a,f8a0a100,27d9ba90,4f7fea6a,571f3c32,53393a7c,79abb0cf,9a558390), +S(ef364ba7,626d72a6,87bc9776,3f2c0833,50640bec,6ff4d80,9dabcf2,9ea9145c,7f8d7c48,1bd80ff4,8eccfa9d,2de5eeb9,800cb98,c02da539,3b3d6c83,8fe4a2ff), +S(45961303,a778b47a,89109231,3242304,30a17859,7d940e9f,fc2f25bd,1be61c00,5fa356b6,daad2b1d,7bb19cce,b9148d31,58d2651a,b4b436c0,b99193f6,61cb037d), +S(8aa677f4,d73c0725,e2163e5d,ed3dc312,7ad5ee29,f9bad8b8,5ab8f50d,ec6d77e9,1fcb9da0,d3fb9bc3,3a45bcdc,50aa2ba1,16c2b05e,836b539c,863163c7,2436c334), +S(8c6b2873,33082bf5,a3597a26,7cc14696,2b689f20,59caf1d9,35972c98,9b14c86b,aa86d282,a1107f8e,21307e0,2ad1420a,a4061fea,3e3dd6f5,9b5d6900,6bf4827c), +S(46c963f0,3bdbf433,cbd60858,5a4d659e,9815c286,9f684eaa,cd879d66,ceed05ed,be2a8d60,636c5b80,e443b13a,9e21c91e,90a9e781,1c35101a,dfd61a49,88193e86), +S(cdbe43bc,582f3936,314a88f9,fa21b29d,f4b5acf5,96cdac3,4667e9c4,b02b926b,8f2a5b62,4f20b20d,cce97348,d73d5653,8651dd41,dfedd476,8792fa61,1bac16fa), +S(6f9c5a84,1ffededc,ec45dc63,7ad15aea,207116aa,a3036ea,ddfb0656,1dfd074d,ddf1c22f,9168232d,cf9c36a5,dfb7835e,62d28405,bd32ec15,5e3ddb3e,df834088), +S(42000663,3223b99,e15a2a65,bd95b229,820abee9,5ba5be39,6f8879b7,3f421e7b,9f3f3d66,40de91bf,c6872619,87487226,57e60a4,3ac633cc,48f684c0,cf42696b), +S(f02335b9,9cb524b7,45fa9167,41da4259,f70279d8,efe851ab,f5b0b8a5,32a087ff,e1bc6767,ba068b22,cb7389e1,36805da5,c30ca62a,e59b92f5,48e4dd1d,5327cfbc), +S(5bbda2dc,cf8154e8,28ed49b1,2fdabc3e,eb8c3f9,d0da5878,77611ff4,49d72e7c,312377c3,6277addb,d5b044e,fe136626,d5f7e7e7,a73cfc4b,9751e8ec,e4f77084), +S(5cd5cb83,ba2f225d,1ef4faf6,22e226e1,eaa85a5e,99721d3,82aae23a,f9dff565,254f58ba,9c49244a,4178a067,b0e4bf6f,dd7f3e15,65e21637,bc41f9f3,55045908), +S(3b20ebc6,b453aa16,e5b61381,1d81ca1,f87dce6d,b54ba85b,d8578ee3,23bff228,8c9d3054,56627a,7313505b,4aa5140d,9fc40d83,bcc298a6,43842f04,70a335f4), +S(cd531999,cf33db75,df4430c6,bbcf32d0,642be18,5736d79b,f2947989,e52c8da8,c7e99c34,2a5c1112,400edc69,f58246e3,d3cebbef,2c43ff47,7520b027,e2aa7d78), +S(40b3856b,273bd2a5,145b70f,d16a2972,e488b33a,f3719143,db7bc567,26ff23c4,d8bf895f,71d96e6e,20d523dd,1256bd56,44e11442,c4757d74,f116ae44,69dc9b21), +S(1a0cf029,2d7cce75,32b74bae,acec6864,9e682788,3cef4bbd,c8b24fdb,53e885a5,32c87d92,6f969f69,7989837d,d8ec8ef1,c284d9db,2a86ecd3,5bbb6772,dea06692), +S(7fd5d251,93dd6c17,8d0be92c,342f94a3,c92c061,27998f4d,54f7dfb6,1326fefa,ea7d0755,e0a804bb,8b7ac8f2,dbe1dd7f,9ccd36ca,2fa94365,631ae455,5d080075), +S(51820145,6c07fa3e,70d7b24a,7754b11,e42828e9,c1b96b0f,fd79bead,2f44050e,126f5526,1a55b724,7d08c868,366d697f,a6898c66,d14094f3,44b0a6b3,613d043c), +S(86f2c87d,46038770,3be5ddc6,c2ba1ccc,7dfdd56c,a9986663,882f85da,345886da,ed34fc59,4b66f7e,f06f54de,84f3c7f6,ea1d877b,bbfc4185,3df800f2,fa805027), +S(7f7d8a69,5b86ca13,d6a0ba07,99e60cbe,f5c4e1f4,c74a62bb,93d94d4f,8c1f296e,44a14061,b2c741c4,6a52639e,9bf08776,5db5d496,92bb6d1b,e97f9ced,a89953e7), +S(ec61e956,83714c55,1b72ed5f,c5b09663,6dbdea9a,64d13ef8,c9cf0c55,89da5ae4,39a6e38f,9f7927cf,ffcd0847,df91e856,4188bf58,276bb4df,3721335a,5357c77a), +S(e5906c85,4a75bee9,322d70be,a5d31c76,31a59389,2f479bf,8dc11bef,9ad5101c,125b3a58,8c6c1c5f,288402f4,3ce74ec5,fe9c2dd3,3f3605df,9ab41210,32641524), +S(6c9faca8,b1b435b9,213fde17,ce967f05,46e6f27a,cf0e131,8496bcfd,d856b092,a04ac67d,4bb07624,6b59df97,2fbe2c1f,bb04be99,e269d33f,ccc81f76,3f567577), +S(61031a0c,730cf279,d929b4f,5608f16e,6b1b1440,c04e5a9,fa300ff8,27303def,acc4d732,afb4730e,39a10c0f,5ae2cee9,5099be03,bf5612ac,391900fd,b51238c2), +S(e58fa07f,ebc3aa4c,61ff4fe3,bfc8d04d,48a1e3c9,935317e1,83d537f9,7f35826b,d2402844,7e63c3e0,be630190,8139a75e,2e1a2b22,b05ce52b,e453ccf7,7c35f1fa), +S(4d4d2982,b45a339,1720af,cf6b92df,2c201d38,5b9b6c3a,8fc53b4f,fd3bfdd1,d72650fb,d130482d,116524fa,e2b3dd71,c68b4bbd,54fc55a8,f9824578,cff67503), +S(9adeb6f9,6ffcbb56,f171919c,a8a64c70,9b8ae835,828bd573,b7a1bbc1,3efb0360,6d920a2e,d2e3f41b,4820d838,ca342b66,9af35a7f,7b6d09fd,b1ba4298,9abe027c), +S(64ba9514,d8680f6c,dd66895d,9c5ad45f,6e29,33506f8e,d7be9770,822aa9b8,7ed8c0dd,59bce424,481f88d7,3e641b61,a010e490,97cf84ca,16c2e045,49e9c6ca), +S(9e4ac64d,9ca58a04,46ca18bf,c1700f2c,16937ef9,c82e8b55,9ccbd751,2a0c0222,315ba2e2,601b18b2,cf7f1720,9c4cff2f,e39dfcf0,c2546fb1,e930898b,5b023274), +S(f13a99e5,8dc72fcb,c62a492,d2850704,621ddf48,f1f433e6,9a9814c4,17d4b84a,cc3d3732,f0f4166a,55946e32,e1c01f91,491c82b8,ef0d269d,7a66f039,ac02dfae), +S(fd6451fb,84cfb18d,3ef0acf8,56c4ef4d,553c562,f7ae4d2a,303f2ea3,3e8f62bb,18ba314d,4e78ea87,490185a3,e43cbb33,5d54b6d,2dff17c0,2f526f78,ecd3f31e)}, +{S(f1a749e,6cab100e,2aeef8ee,6a654551,c0ff906e,e7d11d77,f390955e,9d29d783,a60f7295,3c8c3bf7,f1dc1358,e39baf76,3dba22a0,1ce7917e,aeabd996,e21e845b), +S(e8c45020,4c9d9ad,f7878aa4,184a1576,d4c65d5a,c1c4d494,ff427e86,8b42ec1e,aabff02d,8a715c2c,34414b27,808882c3,f656389c,71c26d6b,d7ac8013,83f4c57c), +S(c1febd79,1784fea9,bf378237,a05522de,1081df6c,27d22ea2,aad805dc,7c2f1c4c,c38782e9,fcc1004e,aa677f79,536aa069,7dd9002d,ac16936a,1f0b8736,8734174e), +S(91925564,4d9bdf2d,4522825b,5758b3f0,4d32da73,3a4e772,bfe3eb2c,9909f4ef,2568e18c,1a0448ab,d038ae62,a652d152,4bdec1c1,a0293695,9772bb65,d78450af), +S(25bb4202,9880c39,f5bde432,c1fa357c,7f4867f,6fee48b9,24ecc824,5e1a5253,5d43db2,64c23715,b4b0eeae,63127cf6,9b4bc79e,f96ea8cc,d17cb53c,c3ac0fc5), +S(2597e080,e772d36f,df500782,5f92f797,c61c72c7,8d801dd1,3deb1bfb,9e91b12a,fd5918b8,938ded17,a458d0ae,559c552f,bd45feb2,5b4f59a8,f5b735cb,bdab92c1), +S(70231b28,f578dc12,9f8ac54d,fd4e3577,73d0fcbf,65be0dcd,51132882,5a36e7e1,d12aaf89,4dff3e42,405a4140,58524e30,b7c6c4a1,83763268,6852acff,83d2b7cb), +S(f8ddfd5e,5f3b46a1,ab363169,12b74c97,b0bd654d,87824040,bf6d2cad,b4fcbf95,931fc58f,5b429636,5e080d5a,8fb35ba0,f92104d3,891d6584,8d24c0f7,fc95bda3), +S(a033f432,670a382c,57e2408d,3bdcd2a6,6758e63d,77574598,6b123e4,d927bf10,83b52f69,d79e7445,b6e33545,c23f16fd,52691151,96ee60d6,2ecf6de5,b2961a0c), +S(8e77f9ed,9a643f3c,bf197b09,80f92860,f37d8b83,93633230,6c902c38,3bb7f96d,71b4da9f,f736f9f1,f8c3c099,c34c1bc4,30bb5d26,3c861e2c,726fe891,cdf7d1ce), +S(f34153e2,29934c71,5d895102,778425f5,e92f4ee5,b96d1333,df207e62,6761b328,954584f1,64c8f35f,2c4e0188,76186ceb,3e91523a,5e8ac03,d5998253,49b7b8ac), +S(e133aa94,c0252f05,379b5bd7,75ba3f1f,92de2876,68613613,28946904,11b3ed52,40363801,613423b7,cc6c0cc5,af3641f4,dc2a7ac4,48b178ae,d1393605,103bd6dc), +S(28119c6f,a57d02ac,856edb00,f594c7be,22772b0d,700ad14,713affe5,7e385b5c,969b6cb2,8ef483a0,db4a96bb,92e2d332,6e6d86a1,73bc3d5,831bcbf2,5efc437d), +S(8c728d65,8b78d96,44003708,dadb48b,65dcf6f,6d9412c0,e31cce3d,b5384d00,bb3cf660,9908467d,285f1c7f,40f4f18,ca618093,92633beb,b4ce30c4,72680662), +S(477321b6,1fd5b4ef,3acd1e8d,8432ef5d,e70576ee,6b8490e6,839f1985,dec96490,88008466,2244e3f9,7d2ded5d,2193c70e,2d72c67b,9b7cd70e,9f14cb05,70306bee), +S(ebedd345,ccdd0e04,4bd3d4d7,e1f1cb6b,ec06ad10,5ec2cec8,821580f5,d08a63d4,4278bfb0,88e4ff81,a3fe15bb,e01be36,40450f85,885da0ae,e15c6b9f,e78ad14a), +S(f4795df9,41b315e2,24a98dac,d9149ff2,8b9a7bf,e758a1f3,5cb6336e,8e1f9814,6982bc20,285c27d8,12c5c648,d0635c7,fdab85e6,fc6905d8,65da387e,596da791), +S(65a5964e,ea76e30c,74c472bd,3ddd5169,11dcfb3e,1f2d7ff2,9661e254,4a38ea30,a7c394af,80ebbd32,e442271f,b061bb42,a7b1758f,44d7d952,89152fa2,a88fe3f9), +S(f3d10725,da6b6c76,6da6fb5b,969ba7c6,3e33b4f2,d062a446,4ffb20bc,dea2d376,4d65ff69,64518942,bc3142a6,2148137,7bb609dd,6545bc26,9678ea19,62812ddb), +S(f5fe0f35,cde00589,301584a2,f4f5b1e9,3977082e,9c9bd50d,7c2c672b,ef05cc9f,1b49ac82,486e6344,dea32ca3,c96cd5c1,446ac2fb,2a658a42,50425f32,e8d72e94), +S(fce17cd4,d9519a53,f0a100f,ca54d1f9,fa87eded,98a12654,769c95be,151e33c3,40d342ef,83a4d715,bd13df0,f21197c6,e189681b,efa0d925,248733f,5ee07b8), +S(fd5d90d4,a97c1d1c,4fe18a10,6808f46,f6ea4422,c4408860,c2256b66,618af8e0,7ffc76c3,539bdec8,f59a9a7b,b36fd534,99306cf3,2dd1fe43,a2db5b59,af2f7e3b), +S(1c71f824,1b147abd,9e3c1ca3,fad5146b,e531dae7,c9c0d586,4f2d8bd8,7a6457aa,23e7e758,2cfc92dd,e498c0af,b942182a,92e02bb0,7e95bc1b,763d8030,9ddc9137), +S(dfb018bd,9bc352,f36889b8,2a46512,8850a158,872554cb,3a3dad28,a0496f20,2daa780b,d615d778,3de8f5e8,25cbd934,5c021df1,9ef80a6d,39ff87db,67a1e5ca), +S(bbd320ee,dacc1282,d3fd2109,c26f6bcd,46205ec1,d96b806,dca35dc1,4baa823d,ae7beed,3b5f72bc,ba66c794,89c05666,efa85966,14bacc45,9a99d882,8edbdbfe), +S(c9cd8f21,a068f78b,ce5129c0,9084be52,e48d688b,f474e690,b7720360,e362dfce,a10b9fe2,78c7814e,37851b5a,36aa4246,54c6279e,89df8fc2,ed189ad8,11518f22), +S(ddcf39db,aba52181,72c36a53,50883245,39ccddd8,46ec4258,e72dcd71,40041491,85cadc4a,a569265d,412c8fa9,4872bce1,51a750f7,b43385e2,2db405e3,54428a5b), +S(391562c3,f19436b1,a6e41d06,7435fbe8,27de66b5,555540c5,3ca7a0cc,c7876457,c3a5d917,5b56f67c,66ff269f,72c0a1ac,74503106,9059aaad,f3e66dad,45a80ee0), +S(63d4b224,7b2d441d,680a0437,604533cf,1dc48c9,bdcb9e10,e0249960,f966b2d4,e25cb896,ba165d4,46f73344,61e6856d,4c186736,402dc6a0,d866f97e,bd5cdfff), +S(5fe057df,5d2508c7,611dc21d,412739fe,3e7cf9e9,670812df,cbb00255,4d44cb22,33b88e83,9f22a7bd,17c149bb,65bd4a49,29b2a29e,b975776c,e82189de,80c7d45c), +S(5ac83bf,498f7eb0,79507ac,d5fbc587,f758afa9,b6a1ee51,4c857f8d,608a7b1f,1c866393,8a91904,f0530bdd,ba15390a,4c10fc4c,ef8a2f07,d799c89f,69a33097), +S(b0f9e4b9,b29790b6,33bcc04f,d860cb0f,823d8d1a,4cc1a1c1,413c1606,cc9a8e2c,b617d40e,7bc52192,be344f46,f9021c0f,ccaf33fd,3e8e3118,93df993a,20c2ee7b)}, +{S(eccf169c,9514a854,8f7e1131,a7438469,4df7dc2,fab96462,20e5799d,6d3f672d,452e53a2,aaf17617,37055bb7,24b64f4a,8fef29ed,f8571ff9,a3a6d2c4,6acdb91e), +S(a77bcddd,a0fecd39,a99c6387,57bda1bf,30257248,6a3fa08a,e2d6ff17,e6e4b6ea,debf4c03,b4bb5c7a,8a386a7b,1e459426,6c78eec6,55f01cd9,f137ff18,c5fbdb1d), +S(a77b91ec,6db6a66e,a48de424,65079a2e,ce220fba,da221601,840546ec,2295c2a2,3c721fea,81f5fe05,163562a9,849bdb15,90bc818e,86674ea2,57fe8d0f,4050086c), +S(99a28a1a,3bf2af79,ef2bf134,d31880a,71c2aad3,824fb7df,23fc4fb7,d54b2910,620e2918,df14e3c5,dbfceada,1905941d,32d77592,89ec607a,f9851a6c,5592803d), +S(7eb52616,71402db8,905c7097,2af96b72,2bd77d,f124bbcc,5418f217,f6d8c7be,ce1e663c,8276bf42,99919592,11feb13b,66aefa37,5d6dca15,8b7b66a3,ffc6d7ec), +S(c88b1815,f183e6ea,3ce8469f,ada5b88b,805288d6,828473ba,368d52f,2145e7a4,55e78f2d,3784952e,cb47f6b0,113eb471,8cc58225,85f9d1e,2198dc60,af3f90c9), +S(dd893c5e,a2e4e70a,fcc161ac,47232d3b,77f16c95,54c98770,9a7a6f64,c0cf7ab1,a1a58b41,c7d4d0c5,6d6c908b,32d97467,b8b6ed20,73e6a677,54935665,6a92a480), +S(591b8422,eddbfaf9,d2c27c28,dd84dd30,712a15a0,deb752dd,dee682cc,34722ea7,877b0c99,6a248082,fd442509,b0ce4cc1,b181d4f8,8ff755dd,5f0dba66,ebf95d1f), +S(75f9e3a1,ffdd902,be5d1d2b,3ed18b37,62e42e95,8b024ce8,f892ee13,ab35c674,57fabc84,7c68cfdf,272effee,e7a6ee2c,5fecdeb4,8e4877c,ccf2a8de,2e2264cc), +S(c8a53d5,e1895cdf,db61c1a2,395a866b,ad803773,23ea43ca,775408f7,a4141cc6,ddeff9c9,97a11e4d,d0afab30,f63229f8,1b52ac,c25749ae,2749ddb4,2b201196), +S(8827d23,668f3006,b966cb19,698a066d,aea556b7,4108739d,d6414d8,e8dd78c9,3d009ac7,2baabb53,2e3658e1,8941d4b1,efe512b8,fd7696d5,14b12216,215f10e0), +S(dde6b713,5cf165c6,53c7f5db,542501bc,b0a41e3c,c6779aa6,194ac1d1,8a830b01,25c04b4a,937e16b6,e72616e2,d64a413b,6a7c29ac,71dfcbf6,826261dc,2507c16), +S(8cf6210c,5426b3a5,ed594699,da6cb8b9,8069a3d7,b926cae9,fedb2e96,25d20010,78017fc1,7915e3c8,62557896,acd002fc,7263bd7f,aed38fca,d63ccaa3,57391f30), +S(35772904,91661db6,340e7d1c,a98db8bc,2f50f557,283ccf11,8e446f71,925ade9b,fd8a4a56,b82dff95,a59e29ea,bd5d8e8b,a876bf95,4abf0537,60832d1b,d7edc31c), +S(60e4201c,4dbd9c99,c5eda030,f041f51d,f648f77b,13ec2072,4d89b6be,f249d793,ebd96057,d60b7cae,71349c51,1a3ca99e,847419ff,cdcaa0c8,54d75d40,8263d81b), +S(f39d686,b17ad518,3a7d300f,1bfd015c,57541f08,a96b5943,43d2ef82,bf20bb6e,f1298c9c,633a958a,a0d12b87,8c95836d,f9f93b5f,5e3a6bbd,93a75ba1,1b96d4d0), +S(37ea7dc7,2a3a0b4e,72412814,bc1e1233,17ea3e1c,c4ede35f,cab5d31c,93cc330b,aebaca93,8b14b315,708360e,5662e6a1,af25069b,cc07f581,225dd131,c656c607), +S(ff1f61ed,ba3cfc6f,2fdf3043,37205bab,301c965b,501e4f2f,fcacde00,dd127b25,fb1edca5,90e00f87,eeb56ef9,94e9bb12,b64ad1ea,f5ef0afe,6f0125b4,e100a483), +S(3376e0a5,b93f15b6,c46b92ea,e313ea2d,c5d0b961,a2623487,8919cf5e,25e9ae38,a4cfc1be,fd24647a,20ae014b,2041ab3f,6cb7585d,48a607f8,299e0c10,96bcfdf1), +S(be575f99,842187b,30bcb312,987ea218,3d613442,8878804,b5e7d920,12e58d9c,154e02b0,b573c81b,d2079a4f,4a6efe5f,5f37502b,33225064,4eb38b2c,3f0a1767), +S(5a215836,f1f2997d,9b09d4d0,6473c55c,46cd3006,70d85d6f,6b5531aa,c8da043f,ef5fba1e,b6e1deaf,bd83e480,fcd4984d,cf60f91f,4799e8b4,3f4edd15,f94b6d33), +S(d73fee2,16a503e3,a7d6b0a2,675adb1d,197c3fae,4d43835c,b6b043f5,d44909f5,6f2cc9ee,fbc36b4d,a5b3e704,c13daee9,cb81ce9d,470f1290,8b32f047,ae231053), +S(26fda2e4,d07ec613,ded58e14,ee84e421,ea58e5b9,5beed698,d847f6a6,db185f6,683c0002,bcd6d8b7,1d06e592,db4b961d,f2518fbb,47cb4ad9,96020d84,ed8a5909), +S(cd3d4e87,e433f2b5,5dc55c6,a3f280fc,57f899e1,f8f0777f,32705f3,eb24551c,2315d85b,7521e4e3,8e69f29b,a49a3203,abc7f280,ad49365a,4c78f21c,3ee12542), +S(652476ac,2c9b871c,e108fa13,6a739766,879a76ec,60d787ac,a1b7447a,67f8afd8,b66bf6db,cd3a1393,f70ac7b6,d53069d2,5f084dd7,f05c97a8,76f7f646,c7b67fa8), +S(61ab4f97,61c96446,ea7a75de,7ed36224,7b5ce8b9,e7b442c3,432f9fa0,ec74355e,f391652b,17a910f,6d476c29,89e854f7,d31a5f31,fead5fbd,5013ea56,e44985db), +S(36e4bb36,e62f78a6,a6155351,36a73637,13fe8be8,1c8c3460,a94bb642,4f7c80de,12b38983,c10079f9,b0016df7,fba0685d,5eb87518,234c65c0,7dff006,dbb6a563), +S(f5e4cb89,101e90d4,b2f50097,aa0b22fa,df076932,f4045e9b,7a9ce8d6,ba178780,c12ec4ae,56db7971,3a1bb0f,2559e3a1,de3f8200,650c809,74101940,181eb52b), +S(1138ad12,333790f9,20e979f6,a6471274,2a9bb567,2356e3c,80ffff89,a9de533,4caada48,a78ae26b,790f23c1,606a5820,98642f4,bab5bfff,95748f6a,2ccd6bc), +S(e0346d21,121ff741,fe4eaa23,938a4347,a71df442,9e55359e,aa20d691,c9f40840,c1197c8e,c36676a9,28a92b56,811845d5,d9632c65,9142cc12,3c65e54f,c282dbd), +S(d42011d6,1061388,fec6b7f,3f332b20,24ab318f,2a9ba7ed,23731207,3e32478e,451a2b16,5c82b1f3,e4d2a0a0,bb407b84,904db4d0,caaf733c,e31fa97d,2fb1735b), +S(63964eee,619074e0,780140fe,2e90836,e72328d2,448386d4,59c5be23,187f5048,c49304c5,947630be,5c60064e,3cb40436,c2a7f46c,b221937b,c7c5d7b1,76cf5e37)}, +{S(8f741868,43906722,ab9f5c6e,c796573b,622fa2ae,6d985bfe,ea4d51a1,8f141792,61ecd858,d6992c4a,bdc22472,fb8fd242,929dc5b5,36ea8e35,d1c8c513,bcb9e31e), +S(f2dd67e5,6f75c397,76b29366,149ba4ff,69385651,53afb385,3853acb7,9fc2bd59,3a24641c,d48ca39f,fe992bf1,50291604,79066af4,a0cf364c,9e52a9f,9b51eb66), +S(9386aa5e,c3452728,a8f65141,e2f43a14,c250173,9349c96d,e1968a4e,48cd30,a3a38a85,4f68048,d8f81002,3eef9966,780262cb,aacbe859,a8fc66fc,27c37f32), +S(6c9901ea,920c0f4c,ce51fde7,ab283f98,eebc30dd,c76a3219,1df4c4c9,db467aac,6773f8ae,e601201a,84dd4485,fa560e22,81d5eabb,25a3b3d8,525f4a56,65f79d05), +S(ed1eafec,876154e0,58597caa,8250b0ef,7262ff70,b719ec9b,63c0b2ff,9d167fe3,73505073,2b563f93,89078cc3,93ff9837,227ab8a6,c7d789c,6d2bc835,2018f77b), +S(515806b5,13d4d4bf,83533b56,3b39bf9c,4e808426,f2e4cf16,562e759,cf2d56ab,83c2fb,673a08a6,b8a86b1f,e1ba23d9,3347903a,d6855059,130d8d39,737ddead), +S(30a726d4,d8db1cfa,d59331a0,8f4b5376,36848547,914dcd75,37a80e40,109b8e35,8f628b92,6a11ddc0,dfb1cebb,934aeaa4,3840d442,a61145d1,803f771f,7bf65d7d), +S(116867a8,d72fb00e,80a6f267,e8163770,34affeff,36d667cd,38219f0a,e3c9038d,270f15be,b2a3d50a,4088720a,e9a2c3dd,df00817e,31e1a5b1,d850fe23,dfe51657), +S(abea2899,e4575c6a,201c96fb,a60a24ee,1f1fe0c9,b718b54d,18981938,4f33a1f4,d43d54e3,9e8d433a,ce66ad94,e52662fa,8013e778,f8bc2e3f,31938a6d,5681c660), +S(1fa796d,9f658aa8,6ccd0fb4,6a735651,102e3181,302e371b,8c965dd4,5f078b30,69815d18,43c3b4d9,f7fa4af7,3d2e5dda,390e5372,28608912,79826a53,a437031b), +S(f5022faa,c8caa29f,304ab6c3,d00931c5,e09085e2,73beab04,c1d18f87,1c0fde73,c6abd143,73213fe8,ffa5ec64,8a22dddd,fdf2cb25,e32afd58,4f92dca7,838e8249), +S(8190b10b,97bc72b9,301b1dc,cc60e69e,460e389e,ce7d5d11,4e2284de,853ea02f,f1ffb850,dbff0f06,561b75f6,5d2ae823,cb13881f,d1150eff,274db4cf,112d2253), +S(ea230fbe,c58d7e2f,1a3cea60,f9018562,d2fefb49,8efa312f,4beafcd3,139da094,6045d69d,b27bee6f,3357180c,e92d3866,b480faf4,2debc033,cfa118fb,b89c3bd2), +S(333d063,ccef6aa1,f78c81b3,4a84975c,82bc2cc2,bb897608,f0bed49d,cd08829,90ad105e,f72b7e4f,a927240d,9c69729b,a0aae3a2,3a45342,3be2c385,488840a1), +S(4d95cb48,58d808a3,be82f42c,da4f64a8,c64ae176,3b50257f,2e4ae655,fcc4802,5f6efffc,99bdde54,6d8ffde5,e9a551d0,121a39c3,86db540d,1caf74b4,894c5559), +S(b87b5eca,6e0111bc,5b756816,fa82acf9,77f81376,af796cdd,1e8fcb09,4d363d1,442fa845,9c2a7799,2c09015a,db80f26a,28428851,62432660,56026009,5f2f9d8), +S(34baf43a,a82cce1b,19945590,ef3cb582,2ab03142,6538ea5f,74571582,ee14cf00,9a76705b,c0141e29,75d11543,215377b5,3c051c31,156697cb,e8f56721,da386e2b), +S(f07c5d98,a2579c17,53b3fb58,22a139a1,53e7deeb,ae9304b,114bb188,d61cdd0a,ec18ce0c,1e51b8bc,e12f3d85,23739f8,bc25708f,32deb81d,a780cc4a,1010692d), +S(9a146c80,5ee261ad,3e708885,aa41041a,53bd3758,b3d1ab7a,1a44aa7e,29acca7,fc553e71,4ad8a192,90f94ed7,7c171f9d,9ad9a047,6791f045,4a3ab7d3,f8834f02), +S(c8088409,650feb74,9f9fe21,61772279,128db1d7,58610a9a,8b9fc4b,ef9683b7,692a6be3,132a08d3,82295ee7,1c469465,ae7d63d6,c20c7357,36935003,28799639), +S(53bdc8b2,3edd83b6,b149b79,c88130c6,b207f999,e7045285,7e828f81,b325b9d8,a9a039d1,79486167,8fda727b,1706e9ec,7ec3eba3,26e6a4a7,e27db3f0,8a6ee238), +S(fd08fb47,4af98207,3d8b4ef6,d39012f4,78225f1a,bde3c841,6fe3881b,4fd276c6,d38b53a9,100da1fd,1d2a987e,6907370e,7bca492e,98a22e5d,74a10c9b,93a197e1), +S(5c42ad93,2306363e,a0edf86d,31d14b04,c3f7bc09,c9fe1326,d1ad085d,c84fb7ca,1bdbf812,e9ad6486,ff572d4e,de5be4c9,59de7be3,f21e0dd8,76534091,f13ca3d3), +S(66257876,115e7eef,fc0e6132,9f177d3a,437c81c4,1150f86b,45904f86,30bae971,df830e1e,33aeded,721a0a6a,62a3a402,1d2b7ab7,438b7b3c,d834d67,3a857aed), +S(4feea8d8,2cc6601,c847deff,35581c1d,bf1f4070,402bb948,ce9a41ee,16661627,c09a7686,ad6bcec4,ea9ab0f7,8316adc0,7c7a2899,9332cee7,5d70c50d,249a0007), +S(2d3bb180,73f5345e,cff0c901,9a6f2fb4,e0a237a3,9315fc11,fd53c7d5,aec43670,58a9459c,2710ac75,ff2510ce,4c9c5fb8,b4f739c9,c6611494,daf896db,e43b080), +S(bd539f5f,47b25116,7159153,f402e0af,8650c17a,de7c5dde,2d9d9cc2,d0a3103d,407cab4f,ca581f10,eb386e20,9158541b,8649951e,b2f5e454,2a7032b6,53f0caa), +S(c7a72935,87ba5114,744c3d0,9030be19,9ccea57c,7f80be87,bfb5b79a,8f8e200,7c2a98f8,b4526422,b211bea0,875a81f1,d379012,486db005,e31b9682,404e14a3), +S(cdf20316,f4b63ca4,c472e1cd,b3a938be,291d98b9,3ad8f3f2,4f3e1a4d,f1a6cc80,ab993e8a,68988d4d,2749760f,241399c8,136ee9d2,3d4ae7d1,e6d26df4,6056587b), +S(1d341e6,2eca1f48,165bb2f3,86207da1,f2c7fc86,dff7a75,cb63976e,f21bb074,923b53ed,fe2f5bb5,56aa7cae,2a08ff86,160e3344,c4adc09a,e7aeadfd,f31e2b9c), +S(8704f69d,9d335975,f0e3bb83,5aa3024a,60103d89,e5578253,fbb3d537,1983ce4e,94f4adfa,31dbd13d,95c738b2,8a569453,cba45efd,1cfd20b6,78f6a724,e9a8d025), +S(7175407f,1b58f010,d4cda4c6,2511e59d,b7edcf28,f5476d99,5cf39944,b26b64f1,bc4baabc,bb1c2aaf,c92cbfe,ecb33791,4fe01748,8bb8e2d5,bd918104,4dbdc75a)}, +{S(a16a4734,9afd167f,d5e79d24,9784d87,5121fa24,2c3a54a,88f9b176,72669aa1,4df3fb81,7021efdc,e5296735,3a177b5c,51cc7762,4755ba28,1084db5c,4809e02c), +S(91d1abe3,8d3f9671,54337e03,d27fa6f8,c3007f32,323d15c8,31306b3a,30900328,b1b8c71d,b388009b,98000f9f,291b66e3,f890d42c,a5812f34,5c070f6,e73b89f6), +S(61b64b1c,f2a0e720,e9bb4853,537b9f38,66baff87,388df7f9,f14c06c7,12080b96,44444011,b6ddadc5,7ee00eed,b6af3772,e4116711,c3853f13,7f9c7b00,2bf2a1dc), +S(3b96b2ee,d9cf1ed6,3aaed8e9,aca3a464,d6a6fbf5,e6fd48f0,5aacc318,dfdbc87,51c41c26,506cac9e,bd0c5dbc,8ce8788a,3469e42d,de794707,9e0cd0d9,826e9c58), +S(7bbd147f,77b293ac,ff797b9,a52778de,5874b754,c08df397,72ed8ef7,53242efc,3e843df6,75abef2b,e4d32c83,205322cb,f53bde0,2563eb8e,b5dfbe6f,27d4cada), +S(becb7fc5,de84f994,9f97e55d,bdb6981e,f38c0c45,1e0e454,519c9411,5bae3d7,754145ec,ee6f9c7c,f91963fb,5b0a683a,ef24313f,1125570c,c9b9c7d2,afab99a8), +S(87936626,aa88346d,6d4330d9,3a188ed6,992bdbb8,387b395e,d21dab93,63d833eb,a28c868a,18dbe0e7,12ca5237,53f6a50b,9313e687,85f3b31f,ec778fac,87aa9327), +S(e79d4b2d,e33de1e2,e7eeeb44,d197aec1,f5883ad6,1394dd79,de274ef9,76e3b022,9c73ade7,7c661527,ec2ec6cd,b370c130,380bdd9a,4bcb668a,86e8259a,ca85f293), +S(863f0d65,34de1222,237a07bd,ebb066b5,2c1cdd83,d7a6d3df,278e57c8,bb59b8c7,c546940b,99d04ae2,5cf7c881,28a985cc,9b6223a6,ffc06fe9,8a3e0f68,439b9db6), +S(71e9b0d1,3972d9e0,2225bbda,5a1024e9,c373eeb,f6514eb1,c113ef88,dffdc3a,4436c52e,c58a34c,562638c7,8d76e3fa,29e3586d,fa667577,2fe0b932,c4a1ade2), +S(ef4a500d,c9369125,78fcfcbe,3c313bbf,f0323caa,75750b6b,a317e1e3,dd8054e3,e807e9cf,7911c919,fef82e40,a3ae1b9b,ed8ded38,e74126ed,863199de,c031f2a1), +S(806dd4e0,fbf72904,c7b0080b,4e7526bc,c71fc52d,f143da80,e571041,dd964915,2f4e2e67,3348c32d,6bcc0741,2e76f4fe,944f96bb,d73382c8,c6880cf6,629eac8a), +S(9ea889e8,acf0441d,6e299687,c532ea8f,8b9453ed,5fea0d47,f735056b,1eb3bfa1,e43f79a8,4d302f3c,88698896,5fa7b8f1,a92c620,dfcb3462,c4befe3f,4afbff5e), +S(9a990a22,1d27d8f3,40e79489,58cff3ca,2720dd3d,ac71688d,9c3c9e2f,afeee215,4957ac76,db370918,7992b0b,63370656,7e0f4a0a,9e5f1d9a,be8f7d5e,8a950eef), +S(d3291003,98ad3d92,1d6cbc6e,b37ac3f3,9360cea6,23edd794,64d34a51,fa7adc60,657c110,5bd8df6b,fe52addb,2fdfc41b,810a1ff7,8662021c,7c220b0d,b3509d14), +S(65eac576,e149d97,3cbd772c,60570870,e437e92c,2e5138ac,9c0534df,b7a45582,ebecb6a,edb87cc1,417e066e,fef8e52e,c61eb00c,dfd98205,91d63c08,9dfd5347), +S(b6976b99,c2515be2,2bc901fd,8671255b,f8fd76ca,1f3474cd,5eebe39e,98f6f14f,84ab17d,da67b61c,fd01881e,b1087e69,845aecc9,ce1535fe,1c7245fa,8df98181), +S(c7f5967f,f9910e10,54c93e1e,d0290102,9bf31787,15f53758,f5c53cd3,c79a52bf,bfb01210,5c1ec69c,847ceffc,d1105ac0,528129fe,3b4d3086,2b6e9562,836f5eb2), +S(ffa0da7a,e8984e4,d02a0fe3,acfb4e81,2a63d6b1,682dcd78,fd2635bf,88cfdf1d,49459ee5,3fad1097,2da786fe,45a2d201,e4a52260,7779b1d4,23defafe,29e70098), +S(5a53d683,3bc1740f,d02f278b,2ac15a87,f137f2,c798f157,725a4aac,63f1798d,ac5e7ec5,86d5960f,e25f9e25,7cf9ee05,110d9595,e440d032,c416d444,6242d10), +S(70f67487,9b030a4d,9ccc0bf2,90d5b78,c455f8bd,a1fa2b52,efaf0200,6b70a6cb,10f5b1c5,dc46c0c0,68757804,93805aa7,5a259dbd,95b4bd14,d031daef,a81bf7bb), +S(a4baf0d7,d3a53c29,e78ff81a,52d634a,e009391b,30a9aa91,df8f7bb6,13e3c16,c9f9d001,7f388f09,b6802c45,e1fa036e,99443467,c3847937,8b384a9,dada35cc), +S(351b8e4a,dd336c28,5d140c57,9f2b089d,3c656a05,b1ed6,4cdbaf7e,e5bc671b,b996e61c,cb14553c,b7b79803,c82332b6,704ce97,fb4e19a5,1f70b13d,f8e2732f), +S(d248350,92898c0,5dbb4465,18695efa,e59ac007,d58b5df5,bb3b7038,82f18e61,23455e7f,5104051a,44600be5,2e242a90,95213d25,b4fd65a7,62c3f9fc,9234c2a5), +S(d3fc6d75,10cb0b20,77b52b00,93e84d47,54dd1a28,4f3928f2,a9e3cc02,f1869588,26e86b02,c16171d4,4238aecf,666146f4,9386e0eb,52dfed87,7ac0b409,51ced10b), +S(1c611335,3d115906,182b0e4a,7eb3d39f,552c49f0,c5928aa1,15ae00dd,c23a3b70,1c3e3c4e,ed65ce47,ea82a33f,df8fa6b5,532977d9,53aed38a,f0f4dab3,98477c6b), +S(6487c5c6,abb6e673,821c4b0,2c485f83,3e149af1,83b3f025,71a81fbe,660e98e3,63c4f6b4,7eb37ed6,7668b41,1e83d9c8,9ea323f3,2d9e8918,20b65276,a8a7b7d6), +S(1b0baf63,6daaf2c4,28a62bce,bdd41de2,a4d7cf69,93f0b931,222a40cb,9f5f9a2f,af9a62cd,f91e2c6b,47f308af,e2de8f16,def4972f,24bf4c5b,2b1f92ac,f63a21d2), +S(95bbd974,78e1b8a4,1622e460,8aa82fe9,e77d43e7,492a0d21,1146d987,f9b8f255,412bc52e,d61c3880,210d3df7,f0d2f27,d458d51,388803e,fef1c016,d7c9e7f6), +S(a3466715,5b6ea598,2d3945fb,743a1510,c671b96f,a3494a57,e0349010,55ae087,de35a05a,1a943a42,7210165e,55d5cfae,3ac15490,dc6b0f43,34c0c99b,dd778608), +S(2ed76c11,52ac3600,7aa17c85,a5f902f1,7c845a05,a4e0aaa0,7b05e836,cbcad59,9c60b2bf,bc47a0dd,d3259151,37e89812,a08d39fe,cf5806be,eb538575,3b159531), +S(20e6e2e7,96946bb6,30c7071e,f1b92ea3,d53d280e,e450111,5f5da36f,840dd273,2c528501,b0eaa61b,b5f45e52,6878b9aa,7ee13686,c25796c3,3f8302e9,44b9469c)}, +{S(f040a2fa,b839c753,4e216425,6c2e8dd8,57c52dac,e75cab3d,512a7b1d,562075d2,9e211cf4,bab24e0e,f745e2a0,9b59565b,be7b2449,8123f6b2,ba383b25,29554b36), +S(c66813b,904831cc,12f89e3f,bde93eb3,11ade6dd,f6cfdf72,21cc61a2,ff46bf26,3b60c8c9,9da35a58,7b9650af,f85ca785,ece41146,e7ed8d6d,ef8d26d1,f3d055ce), +S(cd38ece8,7c7a9cbb,e23b58ef,59925633,734de285,f93b3ac4,eb01e03a,adab904b,a5f48fcd,afe414f4,1a44917a,5dcb80b9,30373af9,70e9f22d,c1af80f,a8b06320), +S(72d6f7db,199564a2,6e823a49,eb0171cb,ebb76a2a,add56c7c,6d3102a,9c3ee18c,bd2039ec,c390839f,e2d4451c,9437fef6,3e98dc62,3ab0eea4,c56376f2,e270f626), +S(2ea6c313,1e101867,2454e15c,d34d5fad,13829d5,4ca86062,f074e512,a274167e,67e3d34a,56f12e1b,43687f51,c2d56395,14355d7d,9cc52726,22f62ab8,91c8d5de), +S(d66bdd78,8b20da57,b2485804,a2f6e2ef,78c7ca87,ae1c5c66,fc533533,5b624162,1a8688a1,300e6d39,e130037d,3f074ccc,57addd1b,88977e64,2ab296ac,d6e054c9), +S(6d6458d5,d1683d85,8f9e40,15e5a94a,73868bda,54f6139c,446b5283,6d211542,e44c7ca8,33761e13,ca5458ff,dc682f22,3819411c,a3c5feb6,24f06412,471b9f5a), +S(49f8063,b3d98f6,f159f2e6,65b0e07,8ef8c7df,44da06c3,55b592ac,13402b9d,b0b2d838,4b24ab11,de895013,e897e825,45c3e8dd,6cdb0990,555cd871,5841f8cd), +S(8b2fb6bd,e60449da,2684f8e3,6267fff7,254051ac,faea37cb,102c9bfa,91abb2ca,c82cb9ab,c33c1817,10d3fb19,60f2850b,5072eb47,404266f7,c7964fb,f98027d3), +S(cf90331d,73644476,47c8f86e,eaa6e67b,f3fb4b3c,4c895b82,30ab2f38,80df1e42,9c493d94,3471efd5,ea90f723,db576a35,8cd1ee6,1a119b56,6c65b16,112eb2b4), +S(e70667cd,8d2759e,43f99417,ecc505a7,953d80dd,e7ce2cba,3c8c948b,d43a912a,92a534b3,51449a66,82395a3,b75877ae,851923a2,e791acc3,7293d728,777a2247), +S(4cc07d11,4a715e9f,4b4d0811,f0337c7e,f4bdff74,2fb008d2,1ce8a9ea,50520d47,478b279,613d92d3,dd24ae31,2658eda8,28a7d628,f0346e04,5d5d9dff,7178f093), +S(2a1cee60,4cdd3b2c,1f859bfa,af63d7e3,9aaad910,92c2a38f,a9362798,9753c30d,325c248e,d409e8f3,b96dccab,6fdb62a6,83b7eaf3,36d2864e,b821663d,ed31a6f5), +S(7c18d0bb,9a01969d,302616cb,bad8722e,d00103fa,9985a50b,765f0e2b,9a2ea14c,f6365a6c,b06e4749,c48c212c,63fff571,8f46e0cf,6fdc8c42,34d4db64,ceb72080), +S(a706754,65cde407,e853e882,8fb7a2fe,98638d7e,64b8df0f,b0a7a0b4,e629d0ee,fd694b2c,1354a5e9,415926d0,1590eaac,dbd1b36b,5ecc46b5,72467c3f,e2cc5393), +S(7ff57a63,36ec73da,cc1dc527,928cc6ff,4ec063b1,56b36292,23b8bbb0,a8ba2c7d,4d6dfc43,da0fe33a,1e75dbf5,5e5d669e,be6471d,eb8a4102,6db1a41e,9d5da637), +S(d4b1f7bc,87558c27,7e0fdf91,22bfe488,b3182555,599dd384,5cc039b5,93218e9f,992f79dd,c8f46682,5c44a54d,626b352f,7f59139b,d545f78b,44bd0b10,55c3c1fa), +S(897773f,a9de63a7,46ebf58e,248d0c21,10f90230,a792f0b6,ea5a25a0,9d1940d2,b7c7dd27,d561dde6,ca7588b,8e3a09c7,16297ba3,9d501744,f9639a25,b16b4f64), +S(2f9cb312,b071a600,e5d24cfc,79b0fdbb,f6da1527,10ec395d,53078453,1a3b07e7,49260f95,757b9b66,feeb5c20,16aa051,b444bfc8,836fd8a2,ab913e98,731fa97e), +S(5c53b27c,4c0ae241,8569c806,8dd43a5c,6fa23ac6,74d001b4,eee6a748,d86c9e6d,4e0e720a,f430972f,b0ab89b8,79a56eb4,f0af5161,cae83ca1,964a8099,f9d497c1), +S(2671ef50,5a321387,9560f0d9,e8588707,1c2b87b5,d06bb9d,dec3d179,6275b098,750ea18b,dbdcbd58,be994eb5,cb3539f5,8c3dc630,7d50bbf1,f69050d6,235826be), +S(59baa5ce,9d6e707b,b0738f4f,d37c9890,801ed796,a82afb2a,ecd2c5ba,195be65b,e6b66356,20a8a106,b58dc202,10cccdd1,e0e8c579,c92f3fbf,8b335765,b30d8291), +S(bb422d0,88abedca,e4686479,295aa1a1,77d7e68b,293bcd31,4097ddc1,af764b90,a96d33f6,46d4861d,a471f853,e0c6ae32,b1eea619,a7441504,a773f5e6,fc548805), +S(8d7df8a5,f08ba2b0,923662fc,e594f111,5295cf6e,c5aec9ca,df0f7236,fe51b362,26452215,7d8572d0,f057ec9,6f572f11,ebad3fd0,56032240,26b54df2,991f9046), +S(9e2b1637,352d8988,1e76fdec,c2dc8533,6a71b18b,3c98e59d,397602f5,8b9087d7,b997404f,1c0b1e64,90cff078,fdc47c42,aedf245a,e69d844c,18a146fa,6d8c3d13), +S(972c7bc4,6362bca6,b58f1d0b,87c0b8dc,fe91a217,7f0cd7af,404f6f06,47e09358,cfda778,a59d944b,4ec08bcb,3aabd70a,cd6f29c5,204c9161,fe2e5bd5,71d03f6c), +S(f7dd32ed,89ceaace,52e7f26b,202ea6a5,c7e8ff42,6c7ebc16,12106f7c,6fe51a54,7349c17d,d8ea6ad1,cb346e3d,26989950,3de00c11,4205b3b5,50d27ff7,67efe75d), +S(c9f96f88,3e34aed,97351928,fa77b07a,f4b01bb4,e4515f0,59745ee5,decc9fbc,6fd62453,dd6c9dab,10fb7d79,c15b4822,178eba31,258800e4,519e627e,91ef20c9), +S(9c28cc93,809b35b3,96a4c9cd,d6976391,17402ffb,5588cd76,7c41a92f,e971a9a,ca3b2634,28513516,86a661c4,747aece4,c8130d93,ff4108a6,3365e725,2bbb80ce), +S(263a3fca,437c4dbf,48ca36e6,aa892d61,abf58f6a,d3c82b1f,fe945dc,c45a15f8,604c5bec,69e0f1a7,3e8f8a80,4f762cda,96ba2198,35268887,910c8df0,e83d3044), +S(7fe42dfb,b3466ed4,d7cb8242,5e66b5e1,14a70516,b118911f,9170656a,3dbb04fa,d11385f4,b0a3a0bc,cf09374f,868cb30f,55175d77,2d3e463a,a298b6ed,1e6f6fa6), +S(53f2432b,a8171714,3fa9df3d,ff41ced2,4a29b314,bc5a8c96,f5f6400a,d7c0979,42ad1004,3e0f8648,332b1c1f,6ee4f821,b42a5b0a,361747ba,60816f2,ac84c58d)}, +{S(b8b52efd,bc367a5c,a1534bb2,f339a048,50fc4941,1668780,dcdb8b51,2daa7526,306a2236,856070ea,1e0fd846,cd571889,e20968cf,cd490bc9,facfc4e5,a5970b2a), +S(27e226b6,ed59c89,5bd20232,bc677c35,495d9601,5f37493f,5075718c,2017e42c,a130a5c8,54ed8ab3,ed657e0f,ee4a04cc,1b59a291,6e96465a,74b36144,7cc621f0), +S(1733f1c0,da38fa79,a7b37988,1822ef51,2392d8cb,59d1ad1e,afaf535a,e151fb64,a93ddb00,af779565,eeb230af,815f9434,958ad39b,387d9069,a03cfcb,8563a920), +S(e3f4b777,d06c8839,c63dfb41,73281787,72debac0,ed45b991,724c19bd,85ab3c58,2d6a84ea,745decd9,e6444b7a,dbb59fa3,21957b7c,3f8141e6,fd633d3f,7539dcdb), +S(a2b42fb8,9ac10df9,ebe804b6,c105e855,25cb05eb,7407d383,3031e216,64491ff5,d0973dbd,346a87b4,f4ddfddd,12be3131,e6c6a397,8e17be2c,bda23683,62f80765), +S(66d441a2,6b28378b,cf23d33b,ffac1163,7c23bbb7,7ad352e7,ff5cc09f,41bf6e91,982aa46e,5fa0b19a,28ecfdee,539c0ec,b5f06e2a,217f7687,6c3cbf1d,e92a6068), +S(3721fccc,20338f8a,779aceb8,eae3fc7f,bb0e4040,1de2c8e5,27941ad7,f789d0f7,d9516c54,8f457b6e,d44f6bbb,23f36c7c,e6fdc548,60e5042a,b3dd4f67,ad5ae3ea), +S(959e980,4618bed2,73b5cc48,5565df27,b8e09c9,a128a9e5,ea92e347,66e02015,cee3a227,1bddee01,3582d65d,c3e26c8a,f80a4601,abcff432,b1737127,91ca15a4), +S(f2e81d16,c19466a6,1b56931,935d03e2,aad6b8d0,7f193d97,bacdc29e,13cdcf38,afb8e973,8d563dc4,1e7688f6,c6b43b71,f366b576,9479f093,88fd09e5,faa1063f), +S(98305a48,800f92e0,bd815192,7b8658fc,60a97c64,c9f97383,68812614,3563910e,d32db8e2,6699b969,5b644c08,39f2399,f8ef45ad,a0d857c5,2d0c7c3f,96a62993), +S(8dbd4fba,113c50ba,ff3f251c,96aba9c0,440d8e69,8a1e4ec1,84fba97a,e497c443,f642b1d9,b012eef2,40c6ad38,fe441d11,cfb42ec2,a3c15540,45e64c76,c15be491), +S(deea5bb6,c7eac0a2,93e90817,836a3e55,2a7f1354,395296c8,97964c2a,4527a727,4cbe143c,c9fde617,c6142335,4323b9d8,bba13dd7,fbd46db5,cbf4ce2a,11c9c00), +S(349f46a5,8621034,9f207a07,4558787d,336cb0cf,a56c1e67,8dd3b04a,4d717f4b,a6479d8,f7f017a6,32c369c0,8679fecd,985b3c16,ff444ba0,3fe43575,8b96455a), +S(a6d818c9,dc182fd7,81343bc,b737811f,611c8499,e44a6cdb,33a36beb,7e44b545,1a8ee36e,d6e9b191,b9cbf840,3924e6b8,ac3c3f8a,cbc9a0b5,ff965d6c,734d741d), +S(f9cad333,7b82ea41,b00f3ef1,bba37b8b,fcb24e8a,175fe380,8e399b67,d21837e7,cb206854,4e7f2cda,28c035f1,b8b50009,319797da,bb498b99,d31e24e2,4fa27ca9), +S(25042b59,f9b29a9c,83d04515,c78f1c25,5b72f97f,7b387113,e88c36b9,9da3ebdc,d966ba9e,a7eb9734,e1481cb7,2df63252,7492e1c4,43f1fc9,c0efe0af,442b5a13), +S(e19c4319,b5c9a01e,b588c629,8a7c6b76,1b80bf4b,e39424e0,666ddc45,fd57e0f6,1b0a2c30,4a1bb1b1,9dd0b50d,29df625,bf958a73,46cc6b1d,81a213a3,b6636285), +S(59c26fc1,6d151c0c,7da0edf6,c474463c,587c45cb,7e407589,d15aad89,de223fa0,f7b227b5,4855c1c4,1e576431,8a7106eb,ea214686,ef815b42,db8c18ae,d5c940a5), +S(d967d546,e07ac1c2,31fd50df,a1d25a51,60594d88,3e816f6a,bd62c15c,446aeff6,8eee6c03,6e22a014,5d9cf3af,9b44e005,cd1d36ce,d7c420f5,e2db918b,e4fbf83a), +S(424b149d,9104254e,3f5772b3,7d973cf2,a46bd110,89d8f850,7666f04d,382c972b,7272ad07,54c18fbd,66e2abb3,952c526,d8113d5b,166283a3,9ac8ecb6,2b7a3e46), +S(40b4b2ac,bd299270,e64bc470,8607c586,3bb50913,45e573f3,a5e2461b,47dbc053,d094311e,fd81bb1f,4622d17e,68044107,a2a8ed54,3cd5ff8c,b531b28b,9b8ec99e), +S(79e79ded,6bc0d851,fa769b5e,8d65857c,f3c1c18e,6c990cb6,116fc45b,63e9f924,4fa89e89,ae4214fc,ba2aecdb,41984788,8154eaa6,bcbbe29f,f04a6262,7299f469), +S(a11ad5ea,59c644b2,8dd7402a,5f96a970,68d96e2e,eb77d59a,fe0c2fc,cc6b252f,38e379d5,150109df,36ed7ad3,a2daa41b,4fb9c731,718cf5e3,8f8f8cf7,d1f3d770), +S(b3002b00,ec5be154,cd8e5226,4b97f5c9,f444b305,8f59c4c,bcda5edf,9d10dc88,f7e9ae65,6ad2c823,8e8e0436,e007d821,b17d9405,984eccc4,617e3977,2f25d636), +S(8d1267b1,94da1334,fd20cb8f,77fa01cf,9e9ced90,43107e41,d1ec4057,eb6115a2,a7ba1b9e,2c6f0f19,5ff1f50a,7a8da22f,da3003fa,44b818b9,953b44d3,e6d6a0df), +S(dde6a3a0,87ef41db,2359e4e7,ca7cb064,424301e7,c5cbb5bc,4b6e504a,f3af4837,24175b1c,b4b39b7e,23718e26,be4a22bb,8bf54302,1f156234,e7f18010,d538aeb), +S(79efa584,2fb89f4e,85f556e,c4be170d,5c1ef88a,3f3f75cf,6b20fc1a,96984ad,b0704aaf,e4d8f30f,4f29fa85,6d55da13,91f5f3ce,36cdef6f,25133999,cc8541a), +S(3aa09dc0,5546977f,7369fa0a,7b60c94b,eab86a1,10d85af7,7b826475,7d67eaf5,343b4cf3,aa6c5ebc,ed041d7f,2381be57,f7fd32d0,29a2f42,a7c8821,4f425d8), +S(53fe8af9,8f9419fb,1445bb6a,94750d46,46be9f37,b7155763,88b11064,df2e6ffa,6cd77e81,84aeab9d,e9bf3093,bb9b21a3,a04a0719,fc428f3d,d5e14c8c,9b16cd7a), +S(fc395dc4,a5114dc8,bcb0f7f0,3a4d3e9,38a87a3d,78d33864,d1dc4cba,9e41e20e,c7991f6e,f72f82f6,b3147e56,74224929,fddeb8a5,97a1b1d4,8852733c,1830b941), +S(b1d25d51,b4558f5f,d0ccb868,3af9a9cf,62a169c6,91627fa5,92d80b18,36695f94,8f92258d,fcf16f4e,8415f53,e65457e8,9f090e72,5479c123,5a481464,a11cd4f9), +S(b866d6b1,42df940f,2cf28b54,c92f0c12,94e0b6a2,2a91f2ef,44bcd88c,4384480d,e6eb4f4c,bd95148f,765d8728,15652853,db1add7f,b4e27929,f19a64b7,f3b34c87)}, +{S(d4aaf32e,dd897f48,5ab16466,76d747cd,fec5b7a0,a05c917b,60c07311,45d16f89,4857e649,beff4089,2470f700,cadb73ae,d4866a84,c3f0b975,6fd8570e,df9d29d8), +S(4ebe5b8a,f3b1583c,9f41bd98,afaba549,f45c381e,c93ec9d1,4a543d87,9cefbaf3,63ed1d17,9b215f34,f1f580be,4b3f671f,2fa14689,74cd03d1,19fadae3,c92935ff), +S(20df6160,556dd3c5,a26620a8,70ff5323,cbbab94,be3e3bdd,ad8b936c,554f28f1,7168e7ab,cdbafad,26fbb5be,a09dadde,ed36c20f,c8deafaf,75a480b5,f980e981), +S(86c663f2,cc6f7ee2,50be25fd,fb35fd8e,5873481b,c477bf5b,c0f1bc1e,3f1320f,c13c5795,cce0ad92,e31240da,90a823d0,d2352314,f2852e67,cb62e0c2,8570994a), +S(3fd8085e,57f6870,b25e41d9,7df00126,150f6022,a7ede22f,d27da581,d234ccaa,c6657746,98d6ac03,ed1ea2d7,bd3f70be,86351c5d,407a4d7c,227fd7d0,c330ef04), +S(1510fcf0,b0fb5a23,c15e041,2a7f6d89,9fac4244,8ce316bf,d88fb58b,10e23118,1879dc07,b34d0a62,f0b9517f,3629ae0f,e8aa6d30,5a783f37,69bdf65,3b40408e), +S(67e9982b,c40f427,98df055c,2d8bdcc0,2ea97bad,68d34024,85498e27,d99e19e4,4f087caa,efc5fd7f,b099c134,a273635c,d1d5ace3,26e3103f,9b2fe22c,e95f288e), +S(e8eeab21,6c3395d6,d16338ea,de4108da,1c25e471,67fb13d5,99e8daaf,93e7345f,7fd2ba87,7c7266a5,65a31548,99950ea1,e5e3d73f,612addea,318ad5bc,a965228d), +S(ab20c7c8,9dd74c20,447bc762,e374c548,e7a8ac31,eec11123,1a040cd1,36e9a546,facacfb2,52eb9532,9106a26a,60128a0f,ae1d7e5c,fd39483c,aeb54dd9,231b55ee), +S(a9004211,b7cf5494,1c530a0e,d658fb6e,3b5d2ee1,37b7d7de,45fef6b5,efddbf0f,58cbaf67,5cc5a131,54eef7a1,462b5d1c,408d5d56,3553ca55,45388d77,c6391d4f), +S(8db64274,422ae0f5,6474b83a,89912fa,e3a39b6c,b3fb8370,308a572e,b6b3c020,9b71a72d,431fd44,aa8632ee,23bc678,61d96edd,b7ec72ab,4b1679b8,a4ba73e4), +S(301b330,c478189d,dce4314f,380cb2d8,38bbd416,5dfad8c4,90f2443f,2a56148b,737da0,1c05cf73,db36a1a4,5005f562,1327167f,d3b60ece,3da3705d,131903fe), +S(b9cbc7a3,4a1cbdd1,300e789d,b7ffec1c,dfe1f738,fbe1fe19,67dd7c14,92ee3ba7,5a816a0,9d08c4be,2b8d062f,200fde4c,534fbdbf,854c7e53,64532c08,60c97c01), +S(6a15e51,6f9f0a7c,25f2eac7,649285ea,d86a1e01,5a386dc,c7f94ba8,4782b45b,63eafaf4,660642ef,988aeee7,642e7c4b,71124a1c,2ca2f5c3,d4f2eec9,ea72d70e), +S(f4c696f3,34c56e08,2ab2e627,4d450f34,fa7fbce,29f3e14d,332bcadf,87d5fe0d,6ee44edf,f574d9a8,363f98b6,b863a648,27d3020,1e652935,be12041c,1bbcc7c3), +S(d2f3d5ad,237ba177,ed312bbb,1d02fb2a,e4bda20f,41f5c217,8b70dd9a,c26ee9b0,cc5912d4,2ea1af01,aa914b98,8c42cef8,46a5a059,664c8545,fc00b662,e0327920), +S(5588b0a4,757beb33,e668af5f,adf87fb3,2aed8e16,e6ceabf1,1576ae17,c6a2b843,70d8961b,ac203e89,c437b88b,ce331309,c4f7eca8,d614299c,74aef9b2,17c741de), +S(f993cd07,f6eb75ad,d41426d5,cc653886,18dde1f0,88aaf3cd,b2631eea,158373e0,1e74f804,5f60349e,a85b90e1,206f0ea4,b0cd3740,861186be,648063e8,58c2b395), +S(2cd04170,78291a50,750218b9,44a11a64,1cb75e7d,cd5cc4f9,64f53c8d,a1ef08f4,1f54a70f,f66ce343,c7ed3001,78d7b99e,49129e23,90b5a026,7ba25af5,3467b6d3), +S(52fc09a1,d4f0cc2e,c7ba6cba,1b30e1f0,b9e37f31,3bf59c33,60fc02e3,3b0c15e8,9bd14bcd,a7c7b6ab,dd7e17dd,ab81a1cf,846be336,a76858a1,8e8a0194,776f0a80), +S(90d29aba,764a9b49,1e2878c2,9b964bf6,e510af,3dd5aeb9,3fe29e13,b8f03b23,396b1f6d,e9b8fd1f,463ca064,11b09823,26cb6ab7,4bbbcaef,43031497,f149a620), +S(ce1d6e8e,ddd063f4,316cb006,b4a4213d,9e0952c8,43e6e1e7,570a35e,aad7fa53,a1abcd7,e2c23ad0,895c5aa8,82a805cd,1d7d434c,72f0c528,2ceec0b7,a7016f7c), +S(4df6e1d3,93a4be66,6fd88c75,e1e686a1,e2cb1844,f5f1303e,f7b0a751,99b42bf5,262d8b9,f7e202a3,78a51928,91ee3fc9,f269ef5d,e14dd0ff,f1fec9f4,4cdb9058), +S(f71b9bfa,bcc353a4,11a055eb,a7d6f48f,47c4e437,96382bcc,d5b882cd,a9059638,bfc1c3f8,fea7df8b,d1cd088c,b1f02e47,377d6656,9b3bd8a2,8b457ba5,e6453468), +S(ad5e9212,d3ef76d,8319fd98,72ee753f,ec99fab0,6244f4e2,a9567068,a635eb53,65fb538f,cb570092,7b0f775a,73ffb0c1,4e6c2274,e253f3a6,2dba9caa,27a3e5e4), +S(81a7dfa0,7659fdbd,57e1c8ae,20c14a80,ee8bfc51,46caa8db,b077b653,23bad4a,ac9d2438,3ef0d99f,26744be4,77e69d51,49d44ab9,84801bb,759d3a5b,7fed1e2e), +S(3bf8c1d0,a613316b,e90eab62,6788c8c3,b1641d65,d0e50245,9e5b19c1,ab1eb617,e1edb59a,8594d73,669e6f93,ca10e210,1254946b,8c9e8eac,3fa84a49,e4e2944f), +S(30f9283a,767c551c,e9fe87d9,5730eff6,fc302a4a,1810e4de,11ba62af,fa17eaae,1f383ac5,e714240d,67980617,d96b0c05,76008599,f8e3fa04,d57454e9,927e729b), +S(1c5d4ac6,91d37d0c,9db5e071,c809a59e,99056263,fbd83028,ee9530e9,c2b3f3c9,b98c7be9,7a2fb196,3d3d4a75,4f7fecce,2fbeb8fd,cf23c229,73b6875,86bd276a), +S(3dfe48e5,2f055be1,1db79fa4,501b44d8,f5ae8447,c5a1293a,a79f683f,1e1e9bf,2d7e8303,b988fc17,18c9b64c,1c03373d,27fd0c32,13c26e6c,b684ca94,49f79d5e), +S(adc4251b,c3ef6d5a,a4d6eb22,46ab2787,bc835b65,1d17ceae,489f181d,57d37248,4f0c489d,1c3a1814,a2f9c1c9,d6fe908f,4623aa44,ebaf4143,79fb8352,15234014), +S(edfe16b2,db401803,11f98920,7a2fef7,d05b2a3b,b676899f,9c6e2192,d38f93e0,1196fd0e,35a24c9,6b28b055,b4fa2f2d,a4c2aeff,3b91dd81,c2fe86c1,1d6bf682)}, +{S(b4b57b34,6e1b41b,7394e655,e059cc93,44c5d83e,f0ef17db,2789db5d,13777b78,6fa187a7,4d983b7e,cea6a268,61039430,63e599e7,cba73144,fe3eb23,677c6265), +S(9937238,7300054a,1a8713b7,6942f003,99818b28,6c6fba5d,ca60b9da,1aa7767,6c003e1,848ce30a,65601eb,e7b76acf,b2e122b6,882d7439,f463c042,ef1b31a), +S(ebd177f8,b5757665,58851c7f,a7ada38b,e3596080,f2679181,f994efd3,82714784,d0fe8eb0,97c852f7,b284d5f,bd81f77f,79c35af7,cc30338f,4e63211e,9e20a244), +S(367ef258,b279f923,a18215b7,67d396e4,c6bc874d,2be6b369,b01afffa,2e041741,bd961242,2452eddb,33831dcf,fb3a0273,30ef141f,6db77d91,5bec2ecb,553b6e6c), +S(d89f40c4,f752cff4,5bae5762,37f5096e,f27d46d0,d934d4de,c3011a28,59464e8e,9d32661e,e2319d6,f6427ea,a3014b5,cf98306c,666c4a9e,970dba2e,65e04886), +S(ef6ff862,1d84c5d5,22e490f4,db21181f,a17bafea,3e097868,4f1f0215,759772b9,ae006f11,aa85db2d,3624cf51,ae319ad2,8b4970e7,eac03301,1eb15db8,dc59d62b), +S(8b0a1b1b,d476bbfb,6da1d071,68d3a988,3b49802f,8ffa04a3,bbba1313,17c67a00,d8c74ae5,65c38597,8d9fda2e,dff6b932,1512e40b,ec5b62e2,59d4d81c,9b657b55), +S(9aa9250f,12ffde38,21384434,849d7eb7,bcafbae5,9a3b861f,68a3addb,d75d3715,19b4b1a8,8d8bfeee,38b54564,30d5f73e,ed0365fe,49092d4a,2f52fa12,b65e3ac7), +S(aaccc00f,55e96f0c,e66d9b43,12f9abd2,6772d8b4,30a6c62,edd2aab4,97acbc22,5af203cf,97d11147,82374056,f012f5f9,2825476a,820dce2e,6e1c4b33,cef5337c), +S(43c34546,2836b544,ddd6e432,6aa19b4a,9de7fdfb,86f43cae,ce98ce7c,32b1ccaf,dd518249,f1fbc1c7,1f905860,17a6f60b,15be97d4,18c66d42,f4f9adcd,d722c096), +S(9a38eb25,935441ab,8983097a,d58c821f,d784f091,5f85dc26,3f0c020b,b80c39a0,d8e6dc57,41e4ba5c,576179e8,9a6dcb4a,bd7178c6,13a1100b,e2bd731b,f3e819e2), +S(6b10527,204a4f7c,e8afcacc,fe771634,376f18da,f12774e,50f23a90,9efe0223,b443a451,529b4208,c8c98904,f5eb2ee,2e2ede2d,80ca50c5,aa29b95a,714181a), +S(1a88fecc,71d7550a,abf7faf0,8e884e95,835f6dc8,1815d2d7,7dab66ea,b238d6b2,82cf6711,1dd38ff,d0daebbc,ea2c064b,17b6b21d,34804f93,4a037936,9edec692), +S(a6b1751,f30507fe,5927b6d4,a92ebbbd,77358c02,9b750d05,a56e4d41,efb99144,ccf7c048,a2a0983d,fdcccfd,a071b80,e8035866,c479ea3a,3bbe7c80,12dfd618), +S(e186601e,8b545292,f23ae7fa,4cadc80f,1fcaa1a3,430ddec6,cfd2af47,c835cdf9,fd471f16,7c3683c9,2e5fc0c2,89b646a5,c8ebda6d,5b6da213,d862c3f6,2c292e9c), +S(91b3935,d8ce2b80,c179ee0b,87850140,4c418c7f,7cf94e4a,64b9fc9c,e396a093,45a5043b,8184546c,9083982f,550807d7,d61fe677,ce73ef21,9b3aa573,97c4eca1), +S(3fbe61fd,2a387654,dfc428e7,dac09e91,5e1ae7d6,d3794288,743f2535,20858ef5,206fd9a0,e3265118,e0a6475c,4df87e43,cc7c8898,59d8aa08,23b6dfff,b68b34d7), +S(31a35020,697d9d52,55476289,ce4fcbdc,4e1e0690,c2c36d1b,a4f4640f,e4c5ba18,91f660f9,159d463a,857f08ad,fc3c5ddd,804507c5,92f73de4,2ee44555,da538553), +S(7dc6b83a,10f26e71,e12c0bd,7ebcccc6,61b4394a,68f576fe,bfca1c23,256e8aa2,b4796977,bd386b98,f3e2fa8e,798b6548,fae52a80,40bb12ea,7e6ad675,64fc8736), +S(67a9c3ff,9c7b99b2,5318ff9e,2b85ee23,ec244655,8042ea8b,d880e23e,7d3ce221,a7bcbbbb,895ca7b1,847a43fa,98809ce4,98016123,bbb3c099,7d34debd,cb023f8d), +S(36602997,eba2c6c5,aab4cb65,8d4efd46,65ab3965,f643ff66,831646dc,f6443bf3,c82d0e80,ef775f9c,7ec7862a,e3158556,a57038d,e6850dd1,e349629c,2546239), +S(9eb9244b,299bfd76,f63bb140,ae2f42a1,4af1e072,83f8259f,6478ac03,d411df24,e43f91da,13c2ba21,a9d17d2f,7a8a629d,9051346,93a6552a,538d590,9d2bdd38), +S(ba4450fa,27d57993,3d949a1a,66013906,7d1a9716,6794993d,e45d9426,b4bfc5ed,8e3f3b9b,d8cb8210,7a5ae2af,92b96259,b73633f,6528ac04,20c3e101,6bb6d8a8), +S(e6d5335f,b67abd36,2712c7fe,575ee769,53d488b,236e8589,5664fb04,7f385248,9e255154,e070a5bb,e98e97f6,281fb999,a75e68ea,7681fdf6,fea093bd,919aa5a4), +S(63c099a9,300a331a,3bc4348a,a373e514,c84a810e,1ea8a8d1,4ac8d7cb,818eb534,ed7d4029,3cc4a086,b1d40c24,6086109,a02dbcb5,a864777,27939024,6fd6bf91), +S(7088617f,66cd93f,8130eaeb,874c3f77,3bcb0daa,78923b70,a65512a2,992554dc,5a3ff995,3c712066,291ac4a2,dfc2573e,1d0aed56,75ef526b,b15f61b0,d20f8156), +S(cc354aaf,746d756b,9387730f,2f12b999,4fcd815c,6d25cdab,2e1185aa,4aa639b3,fb1dead9,4fd76859,1aac8d79,5c337924,dc155fbe,5cd5c953,4d55ee31,f6d284a6), +S(e7e47c3a,e2bf4307,7f33ec3d,ac1ae2a7,5c669e61,e248f588,590cfe07,3e2186e0,46e9c4d5,4429fdcf,5efb375e,18f46cc8,3fa7a403,6013777f,e450e228,aebd4cd0), +S(c6ed5e63,28ec31b1,37041108,42d4ac23,fbb883bb,349d88db,1d747cf7,325fe9cc,21b8bfa4,b62807cf,d6cd11ed,a38084d5,7bb068d4,9f0dd30e,f3f431e2,b57022e4), +S(331924c7,50b3417e,48e279ff,6ed7f3dc,ba2e121e,9f69f8fb,e64093b6,c38a8cc6,357086be,e4cc0fe7,d45a49fe,41d004ce,80466165,316164ab,3b171f03,b9a7841f), +S(b4319cc9,f3e0d3b,313626ae,5385796b,c49b300c,88ba4553,dec0aa4a,77829372,b8f82bb6,6590afd4,48501f,63de3a5d,8f84edea,35c1ee44,88d6333e,f522a808), +S(da433d5e,11ceccc0,abc5c762,6ce7bab4,2e89b221,f785c409,282de545,f3fceb19,1b67242c,de57efcf,e214423b,506a1ade,718803d2,6dd84d88,97b18ede,590a2fcb)}, +{S(ebae7464,ece277b8,309d056c,cf3775e2,11a77aa,81c316a4,b6b7b953,6f90f539,62a4d6a2,95fdd811,f2051715,322f17e5,1753c9d0,835ef9a0,3e8dc9f5,c69bda31), +S(5b20700c,1af63394,a3e4cadb,b0ea682e,19cf495a,b908418a,d41f4c6c,ea4477f0,8435d15e,34b03a22,ca89c73d,326c2f88,142d2e23,8964ef6d,99287125,79738f78), +S(b2f25f91,138b974b,561328c0,92f50fdf,8a694004,fd4879d0,12a4a6cc,c8059d1d,d9ec0b2d,b8e81b2,f6feaf55,9776ff78,cda3401b,47826de0,ca06e579,9d866c09), +S(64e79790,7783d6fb,321eb785,acdeb2ff,4628270,fec3342c,527c8db0,a34c516e,c0c4da5d,abf3da9c,a8613f82,ca28e84,a1a18376,c9967c08,aaf70bea,7a2f34c2), +S(a50cae84,a08f4f32,4984853a,d4c6bdaf,77eaa788,9cb8fe95,72fd56e,9078ee73,120ecbf,76e47b38,503067c8,36853003,60ed261a,40fdf440,161ef2cd,19786b93), +S(76ff3ac8,80a451a9,6741fc70,82bc4c82,7bd51c08,95eea8c8,b422b8a9,96ba4794,25555d71,d4313a60,b189a154,58e0a40,c643c204,277334e,966e2abd,3a23f6c3), +S(307e5caa,8b708760,3d9f845b,b78f4f10,72c49c10,9747f91d,192f8d6e,70c0f4be,f5992f76,37167e1d,55cd31a6,1cdb4756,85eb1503,34fb6009,e0240a18,fa8302b8), +S(d8e62e47,b28fd165,4d420137,884dcf21,c10cb159,d9885843,da34b0d9,d09b2758,675c75b4,b903ad28,2055a71b,2c470e2b,1dce69bf,ecf160cf,3a027de2,55b723a9), +S(ec5639c7,73dac23d,3008dabf,732dc005,3154703d,26ee3bbc,7689286e,4a73e39f,aaa5ea4a,2cf5c23d,57cdd0d8,8accbbf9,9fd2c213,97bb45f8,83547876,3aab1248), +S(3d928ee3,2065557a,27722f08,5202f48f,40917ed6,c7ac1963,2a122226,8b0cb9df,ece112a4,e7a05ad6,17c2fd83,76f89102,9eb94eb0,930fb23c,a342d7f1,f021a0c7), +S(616228a5,cc6c3a92,cd694cec,4b2b8574,5dfffa90,b2a36d8f,32eaa6cc,2530de51,50d8d140,4d506a78,700f8e82,967b36a5,1b4de644,a8e22271,d509c8d2,4adf3148), +S(6f85f308,e847b145,c13a07be,bebdd4ba,6c138939,6afd8670,733f44a8,969406d0,864bcde1,be36c9c7,b7e04ef8,cd2366e2,b3c22902,5ee7efce,d005ef5b,ff7dae2b), +S(f3d1ecc3,53a82621,1bd78f0f,aa029076,c6ca779,9bdc54b2,128fa3d2,aec00c6d,75aa0cf9,fd0b7bed,19183e34,58142f66,c94a5aa9,3915435e,ae51c1fe,96625ccd), +S(a5918de3,f18cd8d1,2a234f9f,3a19fcaa,2d83671d,ad566f16,8aea2b1f,b9de41b0,c515dda6,43c0f6c8,d8fea16,5d595917,16b7f521,43d3b941,f28585ed,8a49c06c), +S(3c49e2ef,1d2d3464,81e05fa0,33366609,1615ebcf,535f68,be257f35,7bd91592,57901e0a,c8af3a31,aa404987,72c903fd,175c9b00,5c7458ee,ed667f11,57754132), +S(6c45ff2,c0c30320,83c343e6,dc80b4f7,bb64502a,52f412ff,ada521d4,a544a9f0,e9936037,f1e641eb,1cd6f801,a25271d3,cffe67d,c9bd7162,babf9855,9628a9a8), +S(66df5d95,acdf4260,ee0e465c,e3916d79,395df522,aa086aeb,6c283bb7,18296d46,cb1f3deb,8aea0337,625f46dd,903416d1,5647be91,1633c4c0,cf0e629a,413476fc), +S(428bbba5,ef351762,9eee4059,a3339213,40c7fee2,5ccb051c,88d75e53,ba618858,ef18809c,28227ccc,115876df,b3f378cd,374c0670,2c658501,7990e767,922c3999), +S(e8993820,d782657,ed8badc2,d515e360,df336730,860ef49e,65ca58dd,1a385815,feb41189,16c7e8f6,53c7f5a6,5fd7b6be,7a029814,149c4645,847073be,770959de), +S(2b77e42a,63502244,d6c7d1be,54b7857,9e2742d2,7143d689,fa3f70a3,5986ccf1,721e9da8,bee88ad4,2155dc9a,28be505,86648378,1d6af5b1,382cd47d,771e6428), +S(acffce3a,ed6beea3,2ad71633,21e1ca53,6f69ce76,fb5cd394,9d9dcc14,bbcee96,5384c97d,eac946c0,afc85b54,f3a56b79,fe263bff,63e1894c,6d52ef1b,9b456602), +S(e13d8d4b,25bece8d,90a008e4,c004824e,223b06b,7cf65ebd,1215e910,2e67b639,3e92b1f,14cbee57,9640b377,6ed5938f,9aee0e11,b139a678,3f207cf4,6dd7e20b), +S(d8f356d9,d2498eaa,b3fa12a,cb64562b,dff3e270,c7809a31,25a9ae65,9cb1f3c5,a5403cda,2d499a7c,7402b57c,c9f99e3,64f5085a,91fd8cfd,8a67c7a8,dbce04fb), +S(350062b5,22fb5d0a,8c79a5db,29e92216,79b9fbc6,3e1f95ca,e7d087f3,fedffc49,74cacf57,5e79c85b,d7e77a40,796e8750,a3ca57f2,a47cce8f,3d2de02d,b014df0b), +S(c159e630,9ab23135,58ebfb6b,22edaf93,eac8e16,77cd9f3b,1cd9492,20bf8e54,99244263,53f32608,831c6d74,da51d61,c344defe,f4c1e401,6a3db44b,4c57f4ae), +S(9e568b70,36a2daa2,fe7a3a52,49c56eb8,3fe4afa2,decebd60,c6c3245f,17bc6a13,b6643644,274eab9f,5e83c598,14978681,17c5a078,765156ae,3cb65fd3,830e06ae), +S(9bee7471,6b6c1ff5,62c1bc36,57a65de3,99a91d72,115703f4,4c3819a1,87828478,bb23a3da,ed34028a,7d39a7ed,fe2e23b,73e085a2,d6c2e51a,ef2a2076,a7c902ad), +S(c430c044,91228a7a,ea835698,ecf0f552,9aeef469,a36305cb,52902ccd,1c897473,40d0ee56,61cca82,80d11da,bffe97c4,f10c93aa,5e07224c,154b666e,bcd58c74), +S(2be073f6,b294a01b,eda0b0db,6832e4bc,23ef3889,7a859853,5ee726ef,ae0f15b1,6153f846,349c2a98,26008065,8be2a7d8,311a5e70,cc310ff8,7935a901,8d575813), +S(2934de46,a6d921f8,720567e6,b46e6362,36a7ed53,483b13ed,20958452,3225accd,5979698,26927cd7,abfe4c57,c53fc72a,48b71679,174c749d,aecdb057,e6a2d961), +S(4e9991b,92fa8c4e,4e8efe45,66966073,319e80d3,a54d4b7a,b61cfcc4,7ddaa5d5,9d03ea22,21d4d80e,261952e2,73f6a8cf,c31f6091,e5aa0a8f,2281ffbf,1345df9e), +S(ff3d6136,ffac5b0c,bfc6c5c0,c30dc01a,7ea3d56c,20bd3103,b178e3d3,ae180068,eccdc641,7b1bfff1,bf2fc8d3,2269523e,ab89890d,bffe0a19,8f594490,e7739bb8)} +#else +# error Configuration mismatch, invalid COMB_* parameters. Try deleting precomputed_ecmult_gen.c before the build. +#endif +}; +#undef S diff --git a/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.h b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.h new file mode 100644 index 000000000..283738a5c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/precomputed_ecmult_gen.h @@ -0,0 +1,26 @@ +/********************************************************************************* + * Copyright (c) 2013, 2014, 2015, 2021 Thomas Daede, Cory Fields, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php. * + *********************************************************************************/ + +#ifndef SECP256K1_PRECOMPUTED_ECMULT_GEN_H +#define SECP256K1_PRECOMPUTED_ECMULT_GEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "group.h" +#include "ecmult_gen.h" +#ifdef EXHAUSTIVE_TEST_ORDER +static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +#else +extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +#endif /* defined(EXHAUSTIVE_TEST_ORDER) */ + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PRECOMPUTED_ECMULT_GEN_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar.h b/crypto/secp256k1/libsecp256k1/src/scalar.h index 27e9d8375..70f49b1cf 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar.h @@ -1,40 +1,44 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_ -#define _SECP256K1_SCALAR_ +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H -#include "num.h" - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#include "util.h" #if defined(EXHAUSTIVE_TEST_ORDER) #include "scalar_low.h" -#elif defined(USE_SCALAR_4X64) +#elif defined(SECP256K1_WIDEMUL_INT128) #include "scalar_4x64.h" -#elif defined(USE_SCALAR_8X32) +#elif defined(SECP256K1_WIDEMUL_INT64) #include "scalar_8x32.h" #else -#error "Please select scalar implementation" +#error "Please select wide multiplication implementation" #endif /** Clear a scalar to prevent the leak of sensitive data. */ static void secp256k1_scalar_clear(secp256k1_scalar *r); -/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); +/** Access bits (1 < count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ +static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count); -/** Access bits from a scalar. Not constant time. */ -static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); +/** Access bits (1 < count <= 32) from a scalar. offset + count must be < 256. Not constant time in offset and count. */ +static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); -/** Set a scalar from a big endian byte array. */ +/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. + * In: bin: pointer to a 32-byte array. + * Out: r: scalar to be set. + * overflow: non-zero if the scalar was bigger or equal to `n` before reduction, zero otherwise (can be NULL). + */ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); +/** Set a scalar from a big endian byte array and returns 1 if it is a valid + * seckey and 0 otherwise. */ +static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin); + /** Set a scalar to an unsigned integer. */ static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); @@ -50,13 +54,6 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int /** Multiply two scalars (modulo the group order). */ static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Shift a scalar right by some amount strictly between 0 and 16, returning - * the low bits that were shifted off */ -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); - -/** Compute the square of a scalar (modulo the group order). */ -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); - /** Compute the inverse of a scalar (modulo the group order). */ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); @@ -66,6 +63,9 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc /** Compute the complement of a scalar (modulo the group order). */ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); +/** Multiply a scalar with the multiplicative inverse of 2. */ +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a); + /** Check whether a scalar equals zero. */ static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); @@ -82,25 +82,24 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a); * Returns -1 if the number was negated, 1 otherwise */ static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); -#ifndef USE_NUM_NONE -/** Convert a scalar to a number. */ -static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); - -/** Get the order of the group as a number. */ -static void secp256k1_scalar_order_get_num(secp256k1_num *r); -#endif - /** Compare two scalars. */ static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); -#ifdef USE_ENDOMORPHISM -/** Find r1 and r2 such that r1+r2*2^128 = a. */ -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -#endif +/** Find r1 and r2 such that r1+r2*2^128 = k. */ +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); +/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their + * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is + * required that r1, r2, and k all point to different objects. */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k); /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); -#endif +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag); + +/** Check invariants on a scalar (no-op unless VERIFY is enabled). */ +static void secp256k1_scalar_verify(const secp256k1_scalar *r); +#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r) + +#endif /* SECP256K1_SCALAR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_4x64.h b/crypto/secp256k1/libsecp256k1/src/scalar_4x64.h index cff406038..700964291 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_4x64.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_4x64.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include @@ -16,4 +16,4 @@ typedef struct { #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h index 56e7bd82a..807b9b70a 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h @@ -1,11 +1,16 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "int128.h" +#include "modinv64_impl.h" +#include "util.h" /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) @@ -24,33 +29,33 @@ #define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) #define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); - return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); + + return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 6 == offset >> 6) { - return secp256k1_scalar_get_bits(a, offset, count); + return secp256k1_scalar_get_bits_limb32(a, offset, count); } else { VERIFY_CHECK((offset >> 6) + 1 < 4); - return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count)); } } @@ -67,95 +72,177 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal } SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { - uint128_t t; + secp256k1_uint128 t; VERIFY_CHECK(overflow <= 1); - t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint64_t)r->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; - uint128_t t = (uint128_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - overflow = t + secp256k1_scalar_check_overflow(r); + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + + secp256k1_u128_from_u64(&t, a->d[0]); + secp256k1_u128_accum_u64(&t, b->d[0]); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[1]); + secp256k1_u128_accum_u64(&t, b->d[1]); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[2]); + secp256k1_u128_accum_u64(&t, b->d[2]); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[3]); + secp256k1_u128_accum_u64(&t, b->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - uint128_t t; + secp256k1_uint128 t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ - t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; -#ifdef VERIFY - VERIFY_CHECK((t >> 64) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = secp256k1_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; - r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; - r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; - r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; - r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; + r->d[0] = secp256k1_read_be64(&b32[24]); + r->d[1] = secp256k1_read_be64(&b32[16]); + r->d[2] = secp256k1_read_be64(&b32[8]); + r->d[3] = secp256k1_read_be64(&b32[0]); over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); if (overflow) { *overflow = over; } + + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; - bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; - bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; - bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_write_be64(&bin[0], a->d[3]); + secp256k1_write_be64(&bin[8], a->d[2]); + secp256k1_write_be64(&bin[16], a->d[1]); + secp256k1_write_be64(&bin[24], a->d[0]); } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); - uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_u128_from_u64(&t, ~a->d[0]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[1]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[2]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[3]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint64_t mask = -(uint64_t)(a->d[0] & 1U); + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63)); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask); +#ifdef VERIFY + /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation + * in full 128 bits to make sure the top 64 bits are indeed zero. */ + secp256k1_u128_accum_u64(&t, a->d[3] >> 1); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask); + secp256k1_u128_rshift(&t, 64); + VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0); + + SECP256K1_SCALAR_VERIFY(r); +#endif } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; + SECP256K1_SCALAR_VERIFY(a); + no |= (a->d[3] < SECP256K1_N_H_3); yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ @@ -168,16 +255,26 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { /* If we are flag = 0, mask = 00...00 and this is a no-op; * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint64_t mask = !flag - 1; + volatile int vflag = flag; + uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; - uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(r); + + secp256k1_u128_from_u64(&t, r->d[0] ^ mask); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); return 2 * (mask == 0) - 1; } @@ -187,14 +284,15 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { #define muladd(a,b) { \ uint64_t tl, th; \ { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ } \ c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ } @@ -202,51 +300,30 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { #define muladd_fast(a,b) { \ uint64_t tl, th; \ { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ } \ c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ c1 += th; /* never overflows by contract (verified in the next line) */ \ VERIFY_CHECK(c1 >= th); \ } -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint64_t tl, th, th2, tl2; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ - c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ - th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ unsigned int over; \ c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)) ? 1 : 0; \ + over = (c0 < (a)); \ c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ + c2 += (c1 < over); /* never overflows by contract */ \ } /** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ #define sumadd_fast(a) { \ c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ VERIFY_CHECK(c2 == 0); \ } @@ -375,10 +452,18 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %%r10, %q5\n" /* extract m6 */ "movq %%r8, %q6\n" - : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) - : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m0, sizeof(m0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m1, sizeof(m1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m2, sizeof(m2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m3, sizeof(m3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m4, sizeof(m4)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m5, sizeof(m5)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&m6, sizeof(m6)); + /* Reduce 385 bits into 258. */ __asm__ __volatile__( /* Preload */ @@ -455,9 +540,15 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) /* extract p4 */ "movq %%r9, %q4\n" : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) - : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p0, sizeof(p0)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p1, sizeof(p1)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p2, sizeof(p2)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p3, sizeof(p3)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&p4, sizeof(p4)); + /* Reduce 258 bits into 256. */ __asm__ __volatile__( /* Preload */ @@ -501,11 +592,15 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) /* Extract c */ "movq %%r9, %q0\n" : "=g"(c) - : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(r, sizeof(*r)); + SECP256K1_CHECKMEM_MSAN_DEFINE(&c, sizeof(c)); + #else - uint128_t c; - uint64_t c0, c1, c2; + secp256k1_uint128 c128; + uint64_t c, c0, c1, c2; uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; uint64_t m0, m1, m2, m3, m4, m5; uint32_t m6; @@ -562,21 +657,25 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) /* Reduce 258 bits into 256. */ /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; - r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; - r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p2 + (uint128_t)p4; - r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p3; - r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + secp256k1_u128_from_u64(&c128, p0); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4); + r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p1); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4); + r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p2); + secp256k1_u128_accum_u64(&c128, p4); + r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p3); + r->d[3] = secp256k1_u128_to_u64(&c128); + c = secp256k1_u128_hi_u64(&c128); #endif /* Final reduction of r. */ secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { +static void secp256k1_scalar_mul_512(uint64_t *l8, const secp256k1_scalar *a, const secp256k1_scalar *b) { #ifdef USE_ASM_X86_64 const uint64_t *pb = b->d; __asm__ __volatile__( @@ -591,7 +690,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c /* (rax,rdx) = a0 * b0 */ "movq %%r15, %%rax\n" "mulq %%r11\n" - /* Extract l0 */ + /* Extract l8[0] */ "movq %%rax, 0(%%rsi)\n" /* (r8,r9,r10) = (rdx) */ "movq %%rdx, %%r8\n" @@ -609,7 +708,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c "addq %%rax, %%r8\n" "adcq %%rdx, %%r9\n" "adcq $0, %%r10\n" - /* Extract l1 */ + /* Extract l8[1] */ "movq %%r8, 8(%%rsi)\n" "xorq %%r8, %%r8\n" /* (r9,r10,r8) += a0 * b2 */ @@ -630,7 +729,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c "addq %%rax, %%r9\n" "adcq %%rdx, %%r10\n" "adcq $0, %%r8\n" - /* Extract l2 */ + /* Extract l8[2] */ "movq %%r9, 16(%%rsi)\n" "xorq %%r9, %%r9\n" /* (r10,r8,r9) += a0 * b3 */ @@ -659,7 +758,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c "addq %%rax, %%r10\n" "adcq %%rdx, %%r8\n" "adcq $0, %%r9\n" - /* Extract l3 */ + /* Extract l8[3] */ "movq %%r10, 24(%%rsi)\n" "xorq %%r10, %%r10\n" /* (r8,r9,r10) += a1 * b3 */ @@ -680,7 +779,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c "addq %%rax, %%r8\n" "adcq %%rdx, %%r9\n" "adcq $0, %%r10\n" - /* Extract l4 */ + /* Extract l8[4] */ "movq %%r8, 32(%%rsi)\n" "xorq %%r8, %%r8\n" /* (r9,r10,r8) += a2 * b3 */ @@ -695,188 +794,54 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c "addq %%rax, %%r9\n" "adcq %%rdx, %%r10\n" "adcq $0, %%r8\n" - /* Extract l5 */ + /* Extract l8[5] */ "movq %%r9, 40(%%rsi)\n" /* (r10,r8) += a3 * b3 */ "movq %%r15, %%rax\n" "mulq %%r14\n" "addq %%rax, %%r10\n" "adcq %%rdx, %%r8\n" - /* Extract l6 */ + /* Extract l8[6] */ "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ + /* Extract l8[7] */ "movq %%r8, 56(%%rsi)\n" : "+d"(pb) - : "S"(l), "D"(a->d) + : "S"(l8), "D"(a->d) : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); + + SECP256K1_CHECKMEM_MSAN_DEFINE(l8, sizeof(*l8) * 8); + #else /* 160 bit accumulator. */ uint64_t c0 = 0, c1 = 0; uint32_t c2 = 0; - /* l[0..7] = a[0..3] * b[0..3]. */ + /* l8[0..7] = a[0..3] * b[0..3]. */ muladd_fast(a->d[0], b->d[0]); - extract_fast(l[0]); + extract_fast(l8[0]); muladd(a->d[0], b->d[1]); muladd(a->d[1], b->d[0]); - extract(l[1]); + extract(l8[1]); muladd(a->d[0], b->d[2]); muladd(a->d[1], b->d[1]); muladd(a->d[2], b->d[0]); - extract(l[2]); + extract(l8[2]); muladd(a->d[0], b->d[3]); muladd(a->d[1], b->d[2]); muladd(a->d[2], b->d[1]); muladd(a->d[3], b->d[0]); - extract(l[3]); + extract(l8[3]); muladd(a->d[1], b->d[3]); muladd(a->d[2], b->d[2]); muladd(a->d[3], b->d[1]); - extract(l[4]); + extract(l8[4]); muladd(a->d[2], b->d[3]); muladd(a->d[3], b->d[2]); - extract(l[5]); + extract(l8[5]); muladd_fast(a->d[3], b->d[3]); - extract_fast(l[6]); + extract_fast(l8[6]); VERIFY_CHECK(c1 == 0); - l[7] = c0; -#endif -} - -static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { -#ifdef USE_ASM_X86_64 - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r11\n" - "movq 8(%%rdi), %%r12\n" - "movq 16(%%rdi), %%r13\n" - "movq 24(%%rdi), %%r14\n" - /* (rax,rdx) = a0 * a0 */ - "movq %%r11, %%rax\n" - "mulq %%r11\n" - /* Extract l0 */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx,0) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a0 * a1 */ - "movq %%r11, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l1 */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a0 * a2 */ - "movq %%r11, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * a1 */ - "movq %%r12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l2 */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += 2 * a0 * a3 */ - "movq %%r11, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += 2 * a1 * a2 */ - "movq %%r12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l3 */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a1 * a3 */ - "movq %%r12, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * a2 */ - "movq %%r13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l4 */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a2 * a3 */ - "movq %%r13, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l5 */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * a3 */ - "movq %%r14, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l6 */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ - "movq %%r8, 56(%%rsi)\n" - : - : "S"(l), "D"(a->d) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd_fast(a->d[3], a->d[3]); - extract_fast(l[6]); - VERIFY_CHECK(c1 == 0); - l[7] = c0; + l8[7] = c0; #endif } @@ -884,48 +849,40 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { #undef sumadd_fast #undef muladd #undef muladd_fast -#undef muladd2 #undef extract #undef extract_fast static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint64_t l[8]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); -} -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); - r->d[3] = (r->d[3] >> n); - return ret; + SECP256K1_SCALAR_VERIFY(r); } -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint64_t l[8]; - secp256k1_scalar_sqr_512(l, a); - secp256k1_scalar_reduce_512(r, l); -} +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; r1->d[2] = 0; r1->d[3] = 0; - r2->d[0] = a->d[2]; - r2->d[1] = a->d[3]; + r2->d[0] = k->d[2]; + r2->d[1] = k->d[3]; r2->d[2] = 0; r2->d[3] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } -#endif SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; } @@ -934,7 +891,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, unsigned int shiftlimbs; unsigned int shiftlow; unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); shiftlimbs = shift >> 6; shiftlow = shift & 0x3F; @@ -944,6 +904,97 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint64_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint64_t)0); + mask1 = ~mask0; + r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); + r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); + r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); + r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) { + const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4]; + + /* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4). + */ + VERIFY_CHECK(a0 >> 62 == 0); + VERIFY_CHECK(a1 >> 62 == 0); + VERIFY_CHECK(a2 >> 62 == 0); + VERIFY_CHECK(a3 >> 62 == 0); + VERIFY_CHECK(a4 >> 8 == 0); + + r->d[0] = a0 | a1 << 62; + r->d[1] = a1 >> 2 | a2 << 60; + r->d[2] = a2 >> 4 | a3 << 58; + r->d[3] = a3 >> 6 | a4 << 56; + + SECP256K1_SCALAR_VERIFY(r); } +static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) { + const uint64_t M62 = UINT64_MAX >> 2; + const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; + SECP256K1_SCALAR_VERIFY(a); + + r->v[0] = a0 & M62; + r->v[1] = (a0 >> 62 | a1 << 2) & M62; + r->v[2] = (a1 >> 60 | a2 << 4) & M62; + r->v[3] = (a2 >> 58 | a3 << 6) & M62; + r->v[4] = a3 >> 56; +} + +static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_scalar = { + {{0x3FD25E8CD0364141LL, 0x2ABB739ABD2280EELL, -0x15LL, 0, 256}}, + 0x34F20099AA774EC1LL +}; + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed62(&s, x); + secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv64_signed62 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); #endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed62(&s, x); + secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed62(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(a->d[0] & 1); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_8x32.h b/crypto/secp256k1/libsecp256k1/src/scalar_8x32.h index 1319664f6..17863ef93 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_8x32.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_8x32.h @@ -1,11 +1,11 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include @@ -16,4 +16,4 @@ typedef struct { #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_8x32_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_8x32_impl.h index aae4f35c0..261049605 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_8x32_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_8x32_impl.h @@ -1,11 +1,15 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "checkmem.h" +#include "modinv32_impl.h" +#include "util.h" /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) @@ -34,17 +38,6 @@ #define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) #define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; -} - SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; @@ -54,21 +47,28 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig r->d[5] = 0; r->d[6] = 0; r->d[7] = 0; + + SECP256K1_SCALAR_VERIFY(r); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); - return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); + + return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count)); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { - return secp256k1_scalar_get_bits(a, offset, count); + return secp256k1_scalar_get_bits_limb32(a, offset, count); } else { VERIFY_CHECK((offset >> 5) + 1 < 8); - return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & (0xFFFFFFFF >> (32 - count)); } } @@ -93,6 +93,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { uint64_t t; VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; @@ -109,12 +110,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_ r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[7]; r->d[7] = t & 0xFFFFFFFFUL; + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[1] + b->d[1]; r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; @@ -133,13 +139,18 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, overflow = t + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); @@ -156,46 +167,53 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); r->d[7] = t & 0xFFFFFFFFULL; -#ifdef VERIFY + + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK((t >> 32) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; - r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; - r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; - r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; - r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; - r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; - r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; - r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; - r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; + r->d[0] = secp256k1_read_be32(&b32[28]); + r->d[1] = secp256k1_read_be32(&b32[24]); + r->d[2] = secp256k1_read_be32(&b32[20]); + r->d[3] = secp256k1_read_be32(&b32[16]); + r->d[4] = secp256k1_read_be32(&b32[12]); + r->d[5] = secp256k1_read_be32(&b32[8]); + r->d[6] = secp256k1_read_be32(&b32[4]); + r->d[7] = secp256k1_read_be32(&b32[0]); over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); if (overflow) { *overflow = over; } + + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; - bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; - bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; - bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; - bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; - bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; - bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; - bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_write_be32(&bin[0], a->d[7]); + secp256k1_write_be32(&bin[4], a->d[6]); + secp256k1_write_be32(&bin[8], a->d[5]); + secp256k1_write_be32(&bin[12], a->d[4]); + secp256k1_write_be32(&bin[16], a->d[3]); + secp256k1_write_be32(&bin[20], a->d[2]); + secp256k1_write_be32(&bin[24], a->d[1]); + secp256k1_write_be32(&bin[28], a->d[0]); } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + SECP256K1_SCALAR_VERIFY(a); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; r->d[1] = t & nonzero; t >>= 32; @@ -211,15 +229,69 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; r->d[7] = t & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint32_t mask = -(uint32_t)(a->d[0] & 1U); + uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31)); + SECP256K1_SCALAR_VERIFY(a); + + t += (SECP256K1_N_H_0 + 1U) & mask; + r->d[0] = t; t >>= 32; + t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31)); + t += SECP256K1_N_H_1 & mask; + r->d[1] = t; t >>= 32; + t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31)); + t += SECP256K1_N_H_2 & mask; + r->d[2] = t; t >>= 32; + t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31)); + t += SECP256K1_N_H_3 & mask; + r->d[3] = t; t >>= 32; + t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31)); + t += SECP256K1_N_H_4 & mask; + r->d[4] = t; t >>= 32; + t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31)); + t += SECP256K1_N_H_5 & mask; + r->d[5] = t; t >>= 32; + t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31)); + t += SECP256K1_N_H_6 & mask; + r->d[6] = t; t >>= 32; + r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask); + + /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation + * in full 64 bits to make sure the top 32 bits are indeed zero. */ + VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0); + + SECP256K1_SCALAR_VERIFY(r); } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; + SECP256K1_SCALAR_VERIFY(a); + no |= (a->d[7] < SECP256K1_N_H_7); yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ @@ -238,9 +310,12 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { /* If we are flag = 0, mask = 00...00 and this is a no-op; * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint32_t mask = !flag - 1; + volatile int vflag = flag; + uint32_t mask = -vflag; uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + SECP256K1_SCALAR_VERIFY(r); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); r->d[1] = t & nonzero; t >>= 32; @@ -256,6 +331,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); r->d[7] = t & nonzero; + + SECP256K1_SCALAR_VERIFY(r); return 2 * (mask == 0) - 1; } @@ -271,9 +348,9 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { tl = t; \ } \ c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + th += (c0 < tl); /* at most 0xFFFFFFFF */ \ c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + c2 += (c1 < th); /* never overflows by contract (verified in the next line) */ \ VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ } @@ -286,46 +363,24 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { tl = t; \ } \ c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + th += (c0 < tl); /* at most 0xFFFFFFFF */ \ c1 += th; /* never overflows by contract (verified in the next line) */ \ VERIFY_CHECK(c1 >= th); \ } -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint32_t tl, th, th2, tl2; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ - c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ - th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - /** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ #define sumadd(a) { \ unsigned int over; \ c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)) ? 1 : 0; \ + over = (c0 < (a)); \ c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ + c2 += (c1 < over); /* never overflows by contract */ \ } /** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ #define sumadd_fast(a) { \ c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + c1 += (c0 < (a)); /* never overflows by contract (verified the next line) */ \ VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ VERIFY_CHECK(c2 == 0); \ } @@ -576,124 +631,52 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con l[15] = c0; } -static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { - /* 96 bit accumulator. */ - uint32_t c0 = 0, c1 = 0, c2 = 0; - - /* l[0..15] = a[0..7]^2. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[0], a->d[4]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[0], a->d[5]); - muladd2(a->d[1], a->d[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd2(a->d[0], a->d[6]); - muladd2(a->d[1], a->d[5]); - muladd2(a->d[2], a->d[4]); - muladd(a->d[3], a->d[3]); - extract(l[6]); - muladd2(a->d[0], a->d[7]); - muladd2(a->d[1], a->d[6]); - muladd2(a->d[2], a->d[5]); - muladd2(a->d[3], a->d[4]); - extract(l[7]); - muladd2(a->d[1], a->d[7]); - muladd2(a->d[2], a->d[6]); - muladd2(a->d[3], a->d[5]); - muladd(a->d[4], a->d[4]); - extract(l[8]); - muladd2(a->d[2], a->d[7]); - muladd2(a->d[3], a->d[6]); - muladd2(a->d[4], a->d[5]); - extract(l[9]); - muladd2(a->d[3], a->d[7]); - muladd2(a->d[4], a->d[6]); - muladd(a->d[5], a->d[5]); - extract(l[10]); - muladd2(a->d[4], a->d[7]); - muladd2(a->d[5], a->d[6]); - extract(l[11]); - muladd2(a->d[5], a->d[7]); - muladd(a->d[6], a->d[6]); - extract(l[12]); - muladd2(a->d[6], a->d[7]); - extract(l[13]); - muladd_fast(a->d[7], a->d[7]); - extract_fast(l[14]); - VERIFY_CHECK(c1 == 0); - l[15] = c0; -} - #undef sumadd #undef sumadd_fast #undef muladd #undef muladd_fast -#undef muladd2 #undef extract #undef extract_fast static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint32_t l[16]; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); -} -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); - r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); - r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); - r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); - r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); - r->d[7] = (r->d[7] >> n); - return ret; + SECP256K1_SCALAR_VERIFY(r); } -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint32_t l[16]; - secp256k1_scalar_sqr_512(l, a); - secp256k1_scalar_reduce_512(r, l); -} +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + SECP256K1_SCALAR_VERIFY(k); -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; - r1->d[2] = a->d[2]; - r1->d[3] = a->d[3]; + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; + r1->d[2] = k->d[2]; + r1->d[3] = k->d[3]; r1->d[4] = 0; r1->d[5] = 0; r1->d[6] = 0; r1->d[7] = 0; - r2->d[0] = a->d[4]; - r2->d[1] = a->d[5]; - r2->d[2] = a->d[6]; - r2->d[3] = a->d[7]; + r2->d[0] = k->d[4]; + r2->d[1] = k->d[5]; + r2->d[2] = k->d[6]; + r2->d[3] = k->d[7]; r2->d[4] = 0; r2->d[5] = 0; r2->d[6] = 0; r2->d[7] = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } -#endif SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; } @@ -702,7 +685,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, unsigned int shiftlimbs; unsigned int shiftlow; unsigned int shifthigh; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); shiftlimbs = shift >> 5; shiftlow = shift & 0x1F; @@ -716,6 +702,115 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint32_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + + mask0 = vflag + ~((uint32_t)0); + mask1 = ~mask0; + r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); + r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); + r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); + r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + r->d[4] = (r->d[4] & mask0) | (a->d[4] & mask1); + r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1); + r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1); + r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) { + const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4], + a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8]; + + /* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and + * have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8). + */ + VERIFY_CHECK(a0 >> 30 == 0); + VERIFY_CHECK(a1 >> 30 == 0); + VERIFY_CHECK(a2 >> 30 == 0); + VERIFY_CHECK(a3 >> 30 == 0); + VERIFY_CHECK(a4 >> 30 == 0); + VERIFY_CHECK(a5 >> 30 == 0); + VERIFY_CHECK(a6 >> 30 == 0); + VERIFY_CHECK(a7 >> 30 == 0); + VERIFY_CHECK(a8 >> 16 == 0); + + r->d[0] = a0 | a1 << 30; + r->d[1] = a1 >> 2 | a2 << 28; + r->d[2] = a2 >> 4 | a3 << 26; + r->d[3] = a3 >> 6 | a4 << 24; + r->d[4] = a4 >> 8 | a5 << 22; + r->d[5] = a5 >> 10 | a6 << 20; + r->d[6] = a6 >> 12 | a7 << 18; + r->d[7] = a7 >> 14 | a8 << 16; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) { + const uint32_t M30 = UINT32_MAX >> 2; + const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3], + a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7]; + SECP256K1_SCALAR_VERIFY(a); + + r->v[0] = a0 & M30; + r->v[1] = (a0 >> 30 | a1 << 2) & M30; + r->v[2] = (a1 >> 28 | a2 << 4) & M30; + r->v[3] = (a2 >> 26 | a3 << 6) & M30; + r->v[4] = (a3 >> 24 | a4 << 8) & M30; + r->v[5] = (a4 >> 22 | a5 << 10) & M30; + r->v[6] = (a5 >> 20 | a6 << 12) & M30; + r->v[7] = (a6 >> 18 | a7 << 14) & M30; + r->v[8] = a7 >> 16; +} + +static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_scalar = { + {{0x10364141L, 0x3F497A33L, 0x348A03BBL, 0x2BB739ABL, -0x146L, 0, 0, 0, 65536}}, + 0x2A774EC1L +}; + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv32_signed30 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); +#endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed30(&s, x); + secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); } +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_modinv32_signed30 s; +#ifdef VERIFY + int zero_in = secp256k1_scalar_is_zero(x); #endif + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_to_signed30(&s, x); + secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar); + secp256k1_scalar_from_signed30(r, &s); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); +} + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + return !(a->d[0] & 1); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_impl.h index f5b237640..0232a8c22 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_impl.h @@ -1,316 +1,120 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_IMPL_H_ -#define _SECP256K1_SCALAR_IMPL_H_ +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H -#include "group.h" -#include "scalar.h" - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" +#ifdef VERIFY +#include #endif +#include "scalar.h" +#include "util.h" + #if defined(EXHAUSTIVE_TEST_ORDER) #include "scalar_low_impl.h" -#elif defined(USE_SCALAR_4X64) +#elif defined(SECP256K1_WIDEMUL_INT128) #include "scalar_4x64_impl.h" -#elif defined(USE_SCALAR_8X32) +#elif defined(SECP256K1_WIDEMUL_INT64) #include "scalar_8x32_impl.h" #else -#error "Please select scalar implementation" +#error "Please select wide multiplication implementation" #endif -#ifndef USE_NUM_NONE -static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { - unsigned char c[32]; - secp256k1_scalar_get_b32(c, a); - secp256k1_num_set_bin(r, c, 32); -} - -/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ -static void secp256k1_scalar_order_get_num(secp256k1_num *r) { -#if defined(EXHAUSTIVE_TEST_ORDER) - static const unsigned char order[32] = { - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER - }; -#else - static const unsigned char order[32] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, - 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, - 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 - }; -#endif - secp256k1_num_set_bin(r, order, 32); -} -#endif +static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { -#if defined(EXHAUSTIVE_TEST_ORDER) - int i; - *r = 0; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) - if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) - *r = i; - /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus - * have a composite group order; fix it in exhaustive_tests.c). */ - VERIFY_CHECK(*r != 0); +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { + secp256k1_memclear(r, sizeof(secp256k1_scalar)); } -#else - secp256k1_scalar *t; - int i; - /* First compute x ^ (2^N - 1) for some values of N. */ - secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; - - secp256k1_scalar_sqr(&x2, x); - secp256k1_scalar_mul(&x2, &x2, x); - - secp256k1_scalar_sqr(&x3, &x2); - secp256k1_scalar_mul(&x3, &x3, x); - - secp256k1_scalar_sqr(&x4, &x3); - secp256k1_scalar_mul(&x4, &x4, x); - - secp256k1_scalar_sqr(&x6, &x4); - secp256k1_scalar_sqr(&x6, &x6); - secp256k1_scalar_mul(&x6, &x6, &x2); - - secp256k1_scalar_sqr(&x7, &x6); - secp256k1_scalar_mul(&x7, &x7, x); - secp256k1_scalar_sqr(&x8, &x7); - secp256k1_scalar_mul(&x8, &x8, x); +static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) { + int overflow; + secp256k1_scalar_set_b32(r, bin, &overflow); - secp256k1_scalar_sqr(&x15, &x8); - for (i = 0; i < 6; i++) { - secp256k1_scalar_sqr(&x15, &x15); - } - secp256k1_scalar_mul(&x15, &x15, &x7); - - secp256k1_scalar_sqr(&x30, &x15); - for (i = 0; i < 14; i++) { - secp256k1_scalar_sqr(&x30, &x30); - } - secp256k1_scalar_mul(&x30, &x30, &x15); - - secp256k1_scalar_sqr(&x60, &x30); - for (i = 0; i < 29; i++) { - secp256k1_scalar_sqr(&x60, &x60); - } - secp256k1_scalar_mul(&x60, &x60, &x30); - - secp256k1_scalar_sqr(&x120, &x60); - for (i = 0; i < 59; i++) { - secp256k1_scalar_sqr(&x120, &x120); - } - secp256k1_scalar_mul(&x120, &x120, &x60); - - secp256k1_scalar_sqr(&x127, &x120); - for (i = 0; i < 6; i++) { - secp256k1_scalar_sqr(&x127, &x127); - } - secp256k1_scalar_mul(&x127, &x127, &x7); - - /* Then accumulate the final result (t starts at x127). */ - t = &x127; - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 3; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 5; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) { /* 000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 10; i++) { /* 0000000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 9; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) { /* 000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 4; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) { /* 000000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 6; i++) { /* 00000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(r, t, &x6); /* 111111 */ + SECP256K1_SCALAR_VERIFY(r); + return (!overflow) & (!secp256k1_scalar_is_zero(r)); } -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - return !(a->d[0] & 1); -} -#endif +static void secp256k1_scalar_verify(const secp256k1_scalar *r) { + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { -#if defined(USE_SCALAR_INV_BUILTIN) - secp256k1_scalar_inverse(r, x); -#elif defined(USE_SCALAR_INV_NUM) - unsigned char b[32]; - secp256k1_num n, m; - secp256k1_scalar t = *x; - secp256k1_scalar_get_b32(b, &t); - secp256k1_num_set_bin(&n, b, 32); - secp256k1_scalar_order_get_num(&m); - secp256k1_num_mod_inverse(&n, &n, &m); - secp256k1_num_get_bin(b, 32, &n); - secp256k1_scalar_set_b32(r, b, NULL); - /* Verify that the inverse was computed correctly, without GMP code. */ - secp256k1_scalar_mul(&t, &t, r); - CHECK(secp256k1_scalar_is_one(&t)); -#else -#error "Please select scalar inverse implementation" -#endif + (void)r; } -#ifdef USE_ENDOMORPHISM #if defined(EXHAUSTIVE_TEST_ORDER) +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +# if EXHAUSTIVE_TEST_ORDER == 7 +# define EXHAUSTIVE_TEST_LAMBDA 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define EXHAUSTIVE_TEST_LAMBDA 9 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define EXHAUSTIVE_TEST_LAMBDA 92 +# else +# error No known lambda for the specified exhaustive test group order. +# endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ + /** - * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the - * full case we don't bother making k1 and k2 be small, we just want them to be + * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the + * full case we don't bother making r1 and r2 be small, we just want them to be * nontrivial to get full test coverage for the exhaustive tests. We therefore - * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; - *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { + SECP256K1_SCALAR_VERIFY(k); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + + *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } #else /** * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where - * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, - * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * lambda is: */ +static const secp256k1_scalar secp256k1_const_lambda = SECP256K1_SCALAR_CONST( + 0x5363AD4CUL, 0xC05C30E0UL, 0xA5261C02UL, 0x8812645AUL, + 0x122E22EAUL, 0x20816678UL, 0xDF02967CUL, 0x1B23BD72UL +); + +#ifdef VERIFY +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k); +#endif + +/* + * Both lambda and beta are primitive cube roots of unity. That is lambda^3 == 1 mod n and + * beta^3 == 1 mod p, where n is the curve order and p is the field order. * - * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm - * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 - * and k2 have a small size. - * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * Furthermore, because (X^3 - 1) = (X - 1)(X^2 + X + 1), the primitive cube roots of unity are + * roots of X^2 + X + 1. Therefore lambda^2 + lambda == -1 mod n and beta^2 + beta == -1 mod p. + * (The other primitive cube roots of unity are lambda^2 and beta^2 respectively.) + * + * Let l = -1/2 + i*sqrt(3)/2, the complex root of X^2 + X + 1. We can define a ring + * homomorphism phi : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. The kernel of phi + * is a lattice over Z[l] (considering Z[l] as a Z-module). This lattice is generated by a + * reduced basis {a1 + b1*l, a2 + b2*l} where * * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} * - * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 are small in absolute value. + * + * The algorithm computes c1 = round(b2 * k / n) and c2 = round((-b1) * k / n), and gives * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and - * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * compute r2 = k2 mod n, and r1 = k1 mod n = (k - r2 * lambda) mod n, avoiding the need for + * the constants a1 and a2. * * g1, g2 are precomputed constants used to replace division with a rounded multiplication * when decomposing the scalar for an endomorphism-based point multiplication. @@ -322,21 +126,21 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), * Section 4.3 (here we use a somewhat higher-precision estimate): * d = a1*b2 - b1*a2 - * g1 = round((2^272)*b2/d) - * g2 = round((2^272)*b1/d) + * g1 = round(2^384 * b2/d) + * g2 = round(2^384 * (-b1)/d) + * + * (Note that d is also equal to the curve order, n, here because [a1,b1] and [a2,b2] + * can be found as outputs of the Extended Euclidean Algorithm on inputs n and lambda). * - * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found - * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * The function below splits k into r1 and r2, such that + * - r1 + lambda * r2 == k (mod n) + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128 * - * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + * See proof below. */ - -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { secp256k1_scalar c1, c2; - static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( - 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, - 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL - ); static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL @@ -346,25 +150,172 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, - 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + 0x3086D221UL, 0xA7D46BCDUL, 0xE86C90E4UL, 0x9284EB15UL, + 0x3DAA8A14UL, 0x71E8CA7FUL, 0xE893209AUL, 0x45DBB031UL ); static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, - 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, + 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL ); - VERIFY_CHECK(r1 != a); - VERIFY_CHECK(r2 != a); + SECP256K1_SCALAR_VERIFY(k); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); + /* these _var calls are constant time since the shift amount is constant */ - secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); - secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); + secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); secp256k1_scalar_mul(&c1, &c1, &minus_b1); secp256k1_scalar_mul(&c2, &c2, &minus_b2); secp256k1_scalar_add(r2, &c1, &c2); - secp256k1_scalar_mul(r1, r2, &minus_lambda); - secp256k1_scalar_add(r1, r1, a); -} -#endif -#endif + secp256k1_scalar_mul(r1, r2, &secp256k1_const_lambda); + secp256k1_scalar_negate(r1, r1); + secp256k1_scalar_add(r1, r1, k); + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); +#ifdef VERIFY + secp256k1_scalar_split_lambda_verify(r1, r2, k); #endif +} + +#ifdef VERIFY +/* + * Proof for secp256k1_scalar_split_lambda's bounds. + * + * Let + * - epsilon1 = 2^256 * |g1/2^384 - b2/d| + * - epsilon2 = 2^256 * |g2/2^384 - (-b1)/d| + * - c1 = round(k*g1/2^384) + * - c2 = round(k*g2/2^384) + * + * Lemma 1: |c1 - k*b2/d| < 2^-1 + epsilon1 + * + * |c1 - k*b2/d| + * = + * |c1 - k*g1/2^384 + k*g1/2^384 - k*b2/d| + * <= {triangle inequality} + * |c1 - k*g1/2^384| + |k*g1/2^384 - k*b2/d| + * = + * |c1 - k*g1/2^384| + k*|g1/2^384 - b2/d| + * < {rounding in c1 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g1/2^384 - b2/d| + * = {definition of epsilon1} + * 2^-1 + epsilon1 + * + * Lemma 2: |c2 - k*(-b1)/d| < 2^-1 + epsilon2 + * + * |c2 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384 + k*g2/2^384 - k*(-b1)/d| + * <= {triangle inequality} + * |c2 - k*g2/2^384| + |k*g2/2^384 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384| + k*|g2/2^384 - (-b1)/d| + * < {rounding in c2 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g2/2^384 - (-b1)/d| + * = {definition of epsilon2} + * 2^-1 + epsilon2 + * + * Let + * - k1 = k - c1*a1 - c2*a2 + * - k2 = - c1*b1 - c2*b2 + * + * Lemma 3: |k1| < (a1 + a2 + 1)/2 < 2^128 + * + * |k1| + * = {definition of k1} + * |k - c1*a1 - c2*a2| + * = {(a1*b2 - b1*a2)/n = 1} + * |k*(a1*b2 - b1*a2)/n - c1*a1 - c2*a2| + * = + * |a1*(k*b2/n - c1) + a2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (a1 + a2 + 1)/2 + * < {rounding up to a power of 2} + * 2^128 + * + * Lemma 4: |k2| < (-b1 + b2)/2 + 1 < 2^128 + * + * |k2| + * = {definition of k2} + * |- c1*a1 - c2*a2| + * = {(b1*b2 - b1*b2)/n = 0} + * |k*(b1*b2 - b1*b2)/n - c1*b1 - c2*b2| + * = + * |b1*(k*b2/n - c1) + b2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (-b1 + b2)/2 + 1 + * < {rounding up to a power of 2} + * 2^128 + * + * Let + * - r2 = k2 mod n + * - r1 = k - r2*lambda mod n. + * + * Notice that r1 is defined such that r1 + r2 * lambda == k (mod n). + * + * Lemma 5: r1 == k1 mod n. + * + * r1 + * == {definition of r1 and r2} + * k - k2*lambda + * == {definition of k2} + * k - (- c1*b1 - c2*b2)*lambda + * == + * k + c1*b1*lambda + c2*b2*lambda + * == {a1 + b1*lambda == 0 mod n and a2 + b2*lambda == 0 mod n} + * k - c1*a1 - c2*a2 + * == {definition of k1} + * k1 + * + * From Lemma 3, Lemma 4, Lemma 5 and the definition of r2, we can conclude that + * + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128. + * + * Q.E.D. + */ +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k) { + secp256k1_scalar s; + unsigned char buf1[32]; + unsigned char buf2[32]; + + /* (a1 + a2 + 1)/2 is 0xa2a8918ca85bafe22016d0b917e4dd77 */ + static const unsigned char k1_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xa8, 0x91, 0x8c, 0xa8, 0x5b, 0xaf, 0xe2, 0x20, 0x16, 0xd0, 0xb9, 0x17, 0xe4, 0xdd, 0x77 + }; + + /* (-b1 + b2)/2 + 1 is 0x8a65287bd47179fb2be08846cea267ed */ + static const unsigned char k2_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x65, 0x28, 0x7b, 0xd4, 0x71, 0x79, 0xfb, 0x2b, 0xe0, 0x88, 0x46, 0xce, 0xa2, 0x67, 0xed + }; + + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, r2); + secp256k1_scalar_add(&s, &s, r1); + VERIFY_CHECK(secp256k1_scalar_eq(&s, k)); + + secp256k1_scalar_negate(&s, r1); + secp256k1_scalar_get_b32(buf1, r1); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k1_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k1_bound, 32) < 0); + + secp256k1_scalar_negate(&s, r2); + secp256k1_scalar_get_b32(buf1, r2); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k2_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k2_bound, 32) < 0); +} +#endif /* VERIFY */ +#endif /* !defined(EXHAUSTIVE_TEST_ORDER) */ + +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_low.h b/crypto/secp256k1/libsecp256k1/src/scalar_low.h index 5574c44c7..2711eb932 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_low.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_low.h @@ -1,15 +1,24 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef uint32_t secp256k1_scalar; -#endif +/* A compile-time constant equal to 2^32 (modulo order). */ +#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U) + +/* Compute a*2^32 + b (modulo order). */ +#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER) + +/* Evaluates to the provided 256-bit constant reduced modulo order. */ +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0)) + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h index 4f94441f4..84e1a380a 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h @@ -1,114 +1,206 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H +#include "checkmem.h" #include "scalar.h" +#include "util.h" #include SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return !(*a & 1); } -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + *r = v % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); +} + +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - if (offset < 32) - return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); - else + VERIFY_CHECK(count > 0 && count <= 32); + if (offset < 32) { + return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); + } else { return 0; + } } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - return secp256k1_scalar_get_bits(a, offset, count); +SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + SECP256K1_SCALAR_VERIFY(a); + + return secp256k1_scalar_get_bits_limb32(a, offset, count); } SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); return *r < *b; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + SECP256K1_SCALAR_VERIFY(r); + if (flag && bit < 32) - *r += (1 << bit); -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif + *r += ((uint32_t)1 << bit); + + SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(bit < 32); + /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ + VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; int i; + int over = 0; *r = 0; for (i = 0; i < 32; i++) { - *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + *r = (*r * 0x100) + b32[i]; + if (*r >= EXHAUSTIVE_TEST_ORDER) { + over = 1; + *r %= EXHAUSTIVE_TEST_ORDER; + } } - /* just deny overflow, it basically always happens */ - if (overflow) *overflow = 0; + if (overflow) *overflow = over; + + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + SECP256K1_SCALAR_VERIFY(a); + memset(bin, 0, 32); bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return *a == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + if (*a == 0) { *r = 0; } else { *r = EXHAUSTIVE_TEST_ORDER - *a; } + + SECP256K1_SCALAR_VERIFY(r); } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return *a == 1; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return *a > EXHAUSTIVE_TEST_ORDER / 2; } static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + SECP256K1_SCALAR_VERIFY(r); + if (flag) secp256k1_scalar_negate(r, r); + + SECP256K1_SCALAR_VERIFY(r); return flag ? -1 : 1; } static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; -} + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = *r & ((1 << n) - 1); - *r >>= n; - return ret; -} + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + *r1 = *a; *r2 = 0; + + SECP256K1_SCALAR_VERIFY(r1); + SECP256K1_SCALAR_VERIFY(r2); } SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + return *a == *b; } -#endif +static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { + uint32_t mask0, mask1; + volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); + + mask0 = vflag + ~((uint32_t)0); + mask1 = ~mask0; + *r = (*r & mask0) | (*a & mask1); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + int i; + uint32_t res = 0; + SECP256K1_SCALAR_VERIFY(x); + + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) { + res = i; + break; + } + } + + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(res != 0); + *r = res; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + SECP256K1_SCALAR_VERIFY(x); + + secp256k1_scalar_inverse(r, x); + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1; + + SECP256K1_SCALAR_VERIFY(r); +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/scratch.h b/crypto/secp256k1/libsecp256k1/src/scratch.h new file mode 100644 index 000000000..6164330b3 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/scratch.h @@ -0,0 +1,44 @@ +/*********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCRATCH_H +#define SECP256K1_SCRATCH_H + +/* The typedef is used internally; the struct name is used in the public API + * (where it is exposed as a different typedef) */ +typedef struct secp256k1_scratch_space_struct { + /** guard against interpreting this object as other types */ + unsigned char magic[8]; + /** actual allocated data */ + void *data; + /** amount that has been allocated (i.e. `data + offset` is the next + * available pointer) */ + size_t alloc_size; + /** maximum size available to allocate */ + size_t max_size; +} secp256k1_scratch; + +typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); + +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); + +/** Returns an opaque object used to "checkpoint" a scratch space. Used + * with `secp256k1_scratch_apply_checkpoint` to undo allocations. */ +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch); + +/** Applies a check point received from `secp256k1_scratch_checkpoint`, + * undoing all allocations since that point. */ +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint); + +/** Returns the maximum allocation the scratch space will allow */ +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects); + +/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n); + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/scratch_impl.h b/crypto/secp256k1/libsecp256k1/src/scratch_impl.h new file mode 100644 index 000000000..f71a20b96 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/scratch_impl.h @@ -0,0 +1,99 @@ +/*********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SCRATCH_IMPL_H +#define SECP256K1_SCRATCH_IMPL_H + +#include "util.h" +#include "scratch.h" + +static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) { + const size_t base_alloc = ROUND_TO_ALIGN(sizeof(secp256k1_scratch)); + void *alloc = checked_malloc(error_callback, base_alloc + size); + secp256k1_scratch* ret = (secp256k1_scratch *)alloc; + if (ret != NULL) { + memset(ret, 0, sizeof(*ret)); + memcpy(ret->magic, "scratch", 8); + ret->data = (void *) ((char *) alloc + base_alloc); + ret->max_size = size; + } + return ret; +} + +static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { + if (scratch != NULL) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ + memset(scratch->magic, 0, sizeof(scratch->magic)); + free(scratch); + } +} + +static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return 0; + } + return scratch->alloc_size; +} + +static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return; + } + if (checkpoint > scratch->alloc_size) { + secp256k1_callback_call(error_callback, "invalid checkpoint"); + return; + } + scratch->alloc_size = checkpoint; +} + +static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return 0; + } + /* Ensure that multiplication will not wrap around */ + if (ALIGNMENT > 1 && objects > SIZE_MAX/(ALIGNMENT - 1)) { + return 0; + } + if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) { + return 0; + } + return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1); +} + +static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) { + void *ret; + size_t rounded_size; + + rounded_size = ROUND_TO_ALIGN(size); + /* Check that rounding did not wrap around */ + if (rounded_size < size) { + return NULL; + } + size = rounded_size; + + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { + secp256k1_callback_call(error_callback, "invalid scratch space"); + return NULL; + } + + if (size > scratch->max_size - scratch->alloc_size) { + return NULL; + } + ret = (void *) ((char *) scratch->data + scratch->alloc_size); + memset(ret, 0, size); + scratch->alloc_size += size; + + return ret; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/secp256k1.c b/crypto/secp256k1/libsecp256k1/src/secp256k1.c old mode 100755 new mode 100644 index 7d637bfad..a248519df --- a/crypto/secp256k1/libsecp256k1/src/secp256k1.c +++ b/crypto/secp256k1/libsecp256k1/src/secp256k1.c @@ -1,13 +1,29 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* This is a C project. It should not be compiled with a C++ compiler, + * and we error out if we detect one. + * + * We still want to be able to test the project with a C++ compiler + * because it is still good to know if this will lead to real trouble, so + * there is a possibility to override the check. But be warned that + * compiling with a C++ compiler is not supported. */ +#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) +#error Trying to compile a C project with a C++ compiler. +#endif + +#define SECP256K1_BUILD -#include "include/secp256k1.h" +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" +#include "assumptions.h" +#include "checkmem.h" #include "util.h" -#include "num_impl.h" + #include "field_impl.h" #include "scalar_impl.h" #include "group_impl.h" @@ -17,6 +33,14 @@ #include "ecdsa_impl.h" #include "eckey_impl.h" #include "hash_impl.h" +#include "int128_impl.h" +#include "scratch_impl.h" +#include "selftest.h" +#include "hsort_impl.h" + +#ifdef SECP256K1_NO_BUILD +# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" +#endif #define ARG_CHECK(cond) do { \ if (EXPECT(!(cond), 0)) { \ @@ -25,124 +49,202 @@ } \ } while(0) -static void default_illegal_callback_fn(const char* str, void* data) { - fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); - abort(); -} - -static const secp256k1_callback default_illegal_callback = { - default_illegal_callback_fn, - NULL -}; - -static void default_error_callback_fn(const char* str, void* data) { - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} - -static const secp256k1_callback default_error_callback = { - default_error_callback_fn, - NULL -}; - +#define ARG_CHECK_VOID(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return; \ + } \ +} while(0) +/* Note that whenever you change the context struct, you must also change the + * context_eq function. */ struct secp256k1_context_struct { - secp256k1_ecmult_context ecmult_ctx; secp256k1_ecmult_gen_context ecmult_gen_ctx; secp256k1_callback illegal_callback; secp256k1_callback error_callback; + int declassify; }; -secp256k1_context* secp256k1_context_create(unsigned int flags) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); - ret->illegal_callback = default_illegal_callback; - ret->error_callback = default_error_callback; +static const secp256k1_context secp256k1_context_static_ = { + { 0 }, + { secp256k1_default_illegal_callback_fn, 0 }, + { secp256k1_default_error_callback_fn, 0 }, + 0 +}; +const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; +const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; + +/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. + * + * This is intended for "context" functions such as secp256k1_context_clone. Functions that need specific + * features of a context should still check for these features directly. For example, a function that needs + * ecmult_gen should directly check for the existence of the ecmult_gen context. */ +static int secp256k1_context_is_proper(const secp256k1_context* ctx) { + return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx); +} + +void secp256k1_selftest(void) { + if (!secp256k1_selftest_passes()) { + secp256k1_callback_call(&default_error_callback, "self test failed"); + } +} + +size_t secp256k1_context_preallocated_size(unsigned int flags) { + size_t ret = sizeof(secp256k1_context); + /* A return value of 0 is reserved as an indicator for errors when we call this function internally. */ + VERIFY_CHECK(ret != 0); if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { - secp256k1_callback_call(&ret->illegal_callback, + secp256k1_callback_call(&default_illegal_callback, "Invalid flags"); - free(ret); - return NULL; + return 0; + } + + if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { + secp256k1_callback_call(&default_illegal_callback, + "Declassify flag requires running with memory checking"); + return 0; } - secp256k1_ecmult_context_init(&ret->ecmult_ctx); - secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + return ret; +} + +size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + return sizeof(secp256k1_context); +} + +secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { + size_t prealloc_size; + secp256k1_context* ret; - if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); + secp256k1_selftest(); + + prealloc_size = secp256k1_context_preallocated_size(flags); + if (prealloc_size == 0) { + return NULL; } - if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); + VERIFY_CHECK(prealloc != NULL); + ret = (secp256k1_context*)prealloc; + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + /* Flags have been checked by secp256k1_context_preallocated_size. */ + VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); + + return ret; +} + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + size_t const prealloc_size = secp256k1_context_preallocated_size(flags); + secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); + if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) { + free(ctx); + return NULL; } + return ctx; +} + +secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* ctx, void* prealloc) { + secp256k1_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + ret = (secp256k1_context*)prealloc; + *ret = *ctx; return ret; } secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); - ret->illegal_callback = ctx->illegal_callback; - ret->error_callback = ctx->error_callback; - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); + secp256k1_context* ret; + size_t prealloc_size; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + prealloc_size = secp256k1_context_preallocated_clone_size(ctx); + ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = secp256k1_context_preallocated_clone(ctx, ret); return ret; } +void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; + } + + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +} + void secp256k1_context_destroy(secp256k1_context* ctx) { - if (ctx != NULL) { - secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); - free(ctx); + /* Defined as noop */ + if (ctx == NULL) { + return; } + + secp256k1_context_preallocated_destroy(ctx); + free(ctx); } void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking secp256k1_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != secp256k1_context_static); if (fun == NULL) { - fun = default_illegal_callback_fn; + fun = secp256k1_default_illegal_callback_fn; } ctx->illegal_callback.fn = fun; ctx->illegal_callback.data = data; } void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + /* We compare pointers instead of checking secp256k1_context_is_proper() here + because setting callbacks is allowed on *copies* of the static context: + it's harmless and makes testing easier. */ + ARG_CHECK_VOID(ctx != secp256k1_context_static); if (fun == NULL) { - fun = default_error_callback_fn; + fun = secp256k1_default_error_callback_fn; } ctx->error_callback.fn = fun; ctx->error_callback.data = data; } +static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { + VERIFY_CHECK(ctx != NULL); + return secp256k1_scratch_create(&ctx->error_callback, max_size); +} + +static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { + VERIFY_CHECK(ctx != NULL); + secp256k1_scratch_destroy(&ctx->error_callback, scratch); +} + +/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour + * of the software. + */ +static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) { + if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); +} + static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - if (sizeof(secp256k1_ge_storage) == 64) { - /* When the secp256k1_ge_storage type is exactly 64 byte, use its - * representation inside secp256k1_pubkey, as conversion is very fast. - * Note that secp256k1_pubkey_save must use the same representation. */ - secp256k1_ge_storage s; - memcpy(&s, &pubkey->data[0], 64); - secp256k1_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - secp256k1_fe x, y; - secp256k1_fe_set_b32(&x, pubkey->data); - secp256k1_fe_set_b32(&y, pubkey->data + 32); - secp256k1_ge_set_xy(ge, &x, &y); - } + secp256k1_ge_from_bytes(ge, pubkey->data); ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); return 1; } static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - if (sizeof(secp256k1_ge_storage) == 64) { - secp256k1_ge_storage s; - secp256k1_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, 64); - } else { - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_normalize_var(&ge->y); - secp256k1_fe_get_b32(pubkey->data, &ge->x); - secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); - } + secp256k1_ge_to_bytes(pubkey->data, ge); } int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { @@ -155,6 +257,9 @@ int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pu if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { return 0; } + if (!secp256k1_ge_is_in_correct_subgroup(&Q)) { + return 0; + } secp256k1_pubkey_save(pubkey, &Q); secp256k1_ge_clear(&Q); return 1; @@ -167,7 +272,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o VERIFY_CHECK(ctx != NULL); ARG_CHECK(outputlen != NULL); - ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33u : 65u)); len = *outputlen; *outputlen = 0; ARG_CHECK(output != NULL); @@ -183,6 +288,60 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o return ret; } +int secp256k1_ec_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey0, const secp256k1_pubkey* pubkey1) { + unsigned char out[2][33]; + const secp256k1_pubkey* pk[2]; + int i; + + VERIFY_CHECK(ctx != NULL); + pk[0] = pubkey0; pk[1] = pubkey1; + for (i = 0; i < 2; i++) { + size_t out_size = sizeof(out[i]); + /* If the public key is NULL or invalid, ec_pubkey_serialize will call + * the illegal_callback and return 0. In that case we will serialize the + * key as all zeros which is less than any valid public key. This + * results in consistent comparisons even if NULL or invalid pubkeys are + * involved and prevents edge cases such as sorting algorithms that use + * this function and do not terminate as a result. */ + if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &out_size, pk[i], SECP256K1_EC_COMPRESSED)) { + /* Note that ec_pubkey_serialize should already set the output to + * zero in that case, but it's not guaranteed by the API, we can't + * test it and writing a VERIFY_CHECK is more complex than + * explicitly memsetting (again). */ + memset(out[i], 0, sizeof(out[i])); + } + } + return secp256k1_memcmp_var(out[0], out[1], sizeof(out[0])); +} + +static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *ctx) { + return secp256k1_ec_pubkey_cmp((secp256k1_context *)ctx, + *(secp256k1_pubkey **)pk1, + *(secp256k1_pubkey **)pk2); +} + +int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL); + + /* Suppress wrong warning (fixed in MSVC 19.33) */ + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(push) + #pragma warning(disable: 4090) + #endif + + /* Casting away const is fine because neither secp256k1_hsort nor + * secp256k1_ec_pubkey_sort_cmp modify the data pointed to by the cmp_data + * argument. */ + secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_ec_pubkey_sort_cmp, (void *)ctx); + + #if defined(_MSC_VER) && (_MSC_VER < 1933) + #pragma warning(pop) + #endif + + return 1; +} + static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { (void)ctx; if (sizeof(secp256k1_scalar) == 32) { @@ -288,122 +447,163 @@ int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ return ret; } -int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msghash32, const secp256k1_pubkey *pubkey) { secp256k1_ge q; secp256k1_scalar r, s; secp256k1_scalar m; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); + ARG_CHECK(msghash32 != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(pubkey != NULL); - secp256k1_scalar_set_b32(&m, msg32, NULL); + secp256k1_scalar_set_b32(&m, msghash32, NULL); secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); return (!secp256k1_scalar_is_high(&s) && secp256k1_pubkey_load(ctx, &q, pubkey) && - secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); + secp256k1_ecdsa_sig_verify(&r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; } static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; - int keylen = 64; - secp256k1_rfc6979_hmac_sha256_t rng; + unsigned int offset = 0; + secp256k1_rfc6979_hmac_sha256 rng; unsigned int i; + secp256k1_scalar msg; + unsigned char msgmod32[32]; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + secp256k1_scalar_get_b32(msgmod32, &msg); /* We feed a byte array to the PRNG as input, consisting of: - * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d. * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. * - optionally 16 extra bytes with the algorithm name. * Because the arguments have distinct fixed lengths it is not possible for * different argument mixtures to emulate each other and result in the same * nonces. */ - memcpy(keydata, key32, 32); - memcpy(keydata + 32, msg32, 32); + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msgmod32, 32); if (data != NULL) { - memcpy(keydata + 64, data, 32); - keylen = 96; + buffer_append(keydata, &offset, data, 32); } if (algo16 != NULL) { - memcpy(keydata + keylen, algo16, 16); - keylen += 16; + buffer_append(keydata, &offset, algo16, 16); } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); - memset(keydata, 0, sizeof(keydata)); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); for (i = 0; i <= counter; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_memclear(keydata, sizeof(keydata)); + secp256k1_rfc6979_hmac_sha256_clear(&rng); return 1; } const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; -int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar r, s; +static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { secp256k1_scalar sec, non, msg; int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); + int is_sec_valid; + unsigned char nonce32[32]; + unsigned int count = 0; + /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ + *r = secp256k1_scalar_zero; + *s = secp256k1_scalar_zero; + if (recid) { + *recid = 0; + } if (noncefp == NULL) { noncefp = secp256k1_nonce_function_default; } - secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - unsigned char nonce32[32]; - unsigned int count = 0; - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { + is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_one, !is_sec_valid); + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + int is_nonce_valid; + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32); + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ + secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); + if (is_nonce_valid) { + ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); + /* The final signature is no longer a secret, nor is the fact that we were successful or not. */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret) { break; } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - if (!overflow && !secp256k1_scalar_is_zero(&non)) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { - break; - } - } - count++; } - memset(nonce32, 0, 32); - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); + count++; } - if (ret) { - secp256k1_ecdsa_signature_save(signature, &r, &s); - } else { - memset(signature, 0, sizeof(*signature)); + /* We don't want to declassify is_sec_valid and therefore the range of + * seckey. As a result is_sec_valid is included in ret only after ret was + * used as a branching variable. */ + ret &= is_sec_valid; + secp256k1_memclear(nonce32, sizeof(nonce32)); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + secp256k1_scalar_cmov(r, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_cmov(s, &secp256k1_scalar_zero, !ret); + if (recid) { + const int zero = 0; + secp256k1_int_cmov(recid, &zero, !ret); } return ret; } +int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + int ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msghash32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata); + secp256k1_ecdsa_signature_save(signature, &r, &s); + return ret; +} + int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { secp256k1_scalar sec; int ret; - int overflow; VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = !overflow && !secp256k1_scalar_is_zero(&sec); + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { +static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) { secp256k1_gej pj; + int ret; + + ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey); + secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret); + + secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); + secp256k1_ge_set_gej(p, &pj); + secp256k1_gej_clear(&pj); + return ret; +} + +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { secp256k1_ge p; - secp256k1_scalar sec; - int overflow; + secp256k1_scalar seckey_scalar; int ret = 0; VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkey != NULL); @@ -411,101 +611,142 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(seckey != NULL); - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey); + secp256k1_pubkey_save(pubkey, &p); + secp256k1_memczero(pubkey, sizeof(*pubkey), !ret); + + secp256k1_scalar_clear(&seckey_scalar); + return ret; +} + +int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + secp256k1_scalar sec; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_negate(&sec, &sec); + secp256k1_scalar_get_b32(seckey, &sec); + + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + return secp256k1_ec_seckey_negate(ctx, seckey); +} + +int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { + int ret = 0; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + ret = secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_ge_set_gej(&p, &pj); + secp256k1_ge_neg(&p, &p); secp256k1_pubkey_save(pubkey, &p); } - secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + +static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak32) { secp256k1_scalar term; + int overflow = 0; + int ret = 0; + + secp256k1_scalar_set_b32(&term, tweak32, &overflow); + ret = (!overflow) & secp256k1_eckey_privkey_tweak_add(sec, &term); + secp256k1_scalar_clear(&term); + return ret; +} + +int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { secp256k1_scalar sec; int ret = 0; - int overflow = 0; VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak != NULL); - - secp256k1_scalar_set_b32(&term, tweak, &overflow); - secp256k1_scalar_set_b32(&sec, seckey, NULL); + ARG_CHECK(tweak32 != NULL); - ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); - memset(seckey, 0, 32); - if (ret) { - secp256k1_scalar_get_b32(seckey, &sec); - } + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + ret &= secp256k1_ec_seckey_tweak_add_helper(&sec, tweak32); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_get_b32(seckey, &sec); secp256k1_scalar_clear(&sec); - secp256k1_scalar_clear(&term); return ret; } -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { - secp256k1_ge p; +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak32); +} + +static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) { secp256k1_scalar term; - int ret = 0; int overflow = 0; + secp256k1_scalar_set_b32(&term, tweak32, &overflow); + return !overflow && secp256k1_eckey_pubkey_tweak_add(p, &term); +} + +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { + secp256k1_ge p; + int ret = 0; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak != NULL); + ARG_CHECK(tweak32 != NULL); - secp256k1_scalar_set_b32(&term, tweak, &overflow); - ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + ret = secp256k1_pubkey_load(ctx, &p, pubkey); memset(pubkey, 0, sizeof(*pubkey)); + ret = ret && secp256k1_ec_pubkey_tweak_add_helper(&p, tweak32); if (ret) { - if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { - secp256k1_pubkey_save(pubkey, &p); - } else { - ret = 0; - } + secp256k1_pubkey_save(pubkey, &p); } return ret; } -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { +int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { secp256k1_scalar factor; secp256k1_scalar sec; int ret = 0; int overflow = 0; VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak != NULL); + ARG_CHECK(tweak32 != NULL); - secp256k1_scalar_set_b32(&factor, tweak, &overflow); - secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); - memset(seckey, 0, 32); - if (ret) { - secp256k1_scalar_get_b32(seckey, &sec); - } + secp256k1_scalar_set_b32(&factor, tweak32, &overflow); + ret = secp256k1_scalar_set_b32_seckey(&sec, seckey); + ret &= (!overflow) & secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + secp256k1_scalar_cmov(&sec, &secp256k1_scalar_zero, !ret); + secp256k1_scalar_get_b32(seckey, &sec); secp256k1_scalar_clear(&sec); secp256k1_scalar_clear(&factor); return ret; } -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { + return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak32); +} + +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { secp256k1_ge p; secp256k1_scalar factor; int ret = 0; int overflow = 0; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak != NULL); + ARG_CHECK(tweak32 != NULL); - secp256k1_scalar_set_b32(&factor, tweak, &overflow); + secp256k1_scalar_set_b32(&factor, tweak32, &overflow); ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + if (secp256k1_eckey_pubkey_tweak_mul(&p, &factor)) { secp256k1_pubkey_save(pubkey, &p); } else { ret = 0; @@ -517,8 +758,11 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + + if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + } return 1; } @@ -527,6 +771,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * secp256k1_gej Qj; secp256k1_ge Q; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubnonce != NULL); memset(pubnonce, 0, sizeof(*pubnonce)); ARG_CHECK(n >= 1); @@ -535,6 +780,7 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * secp256k1_gej_set_infinity(&Qj); for (i = 0; i < n; i++) { + ARG_CHECK(pubnonces[i] != NULL); secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); secp256k1_gej_add_ge(&Qj, &Qj, &Q); } @@ -546,14 +792,40 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * return 1; } +int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) { + secp256k1_sha256 sha; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(hash32 != NULL); + ARG_CHECK(tag != NULL); + ARG_CHECK(msg != NULL); + + secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + secp256k1_sha256_write(&sha, msg, msglen); + secp256k1_sha256_finalize(&sha, hash32); + secp256k1_sha256_clear(&sha); + return 1; +} + #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/main_impl.h" #endif -#ifdef ENABLE_MODULE_SCHNORR -# include "modules/schnorr/main_impl.h" -#endif - #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/main_impl.h" #endif + +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/main_impl.h" +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/selftest.h b/crypto/secp256k1/libsecp256k1/src/selftest.h new file mode 100644 index 000000000..d083ac952 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/selftest.h @@ -0,0 +1,32 @@ +/*********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_SELFTEST_H +#define SECP256K1_SELFTEST_H + +#include "hash.h" + +#include + +static int secp256k1_selftest_sha256(void) { + static const char *input63 = "For this sample, this 63-byte string will be used as input data"; + static const unsigned char output32[32] = { + 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, + 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42, + }; + unsigned char out[32]; + secp256k1_sha256 hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); + secp256k1_sha256_finalize(&hasher, out); + return secp256k1_memcmp_var(out, output32, 32) == 0; +} + +static int secp256k1_selftest_passes(void) { + return secp256k1_selftest_sha256(); +} + +#endif /* SECP256K1_SELFTEST_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/testrand.h b/crypto/secp256k1/libsecp256k1/src/testrand.h index f8efa93c7..3c1ed3d45 100644 --- a/crypto/secp256k1/libsecp256k1/src/testrand.h +++ b/crypto/secp256k1/libsecp256k1/src/testrand.h @@ -1,38 +1,48 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_TESTRAND_H_ -#define _SECP256K1_TESTRAND_H_ +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#include "util.h" /* A non-cryptographic RNG used only for test infrastructure. */ /** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16); /** Generate a pseudorandom number in the range [0..2**32-1]. */ -static uint32_t secp256k1_rand32(void); +SECP256K1_INLINE static uint32_t testrand32(void); + +/** Generate a pseudorandom number in the range [0..2**64-1]. */ +SECP256K1_INLINE static uint64_t testrand64(void); /** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or * more. */ -static uint32_t secp256k1_rand_bits(int bits); +SECP256K1_INLINE static uint64_t testrand_bits(int bits); /** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t secp256k1_rand_int(uint32_t range); +static uint32_t testrand_int(uint32_t range); /** Generate a pseudorandom 32-byte array. */ -static void secp256k1_rand256(unsigned char *b32); +static void testrand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void secp256k1_rand256_test(unsigned char *b32); +static void testrand256_test(unsigned char *b32); /** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); +static void testrand_bytes_test(unsigned char *bytes, size_t len); + +/** Flip a single random bit in a byte array */ +static void testrand_flip(unsigned char *b, size_t len); + +/** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ +static void testrand_init(const char* hexseed); + +/** Print final test information. */ +static void testrand_finish(void); -#endif +#endif /* SECP256K1_TESTRAND_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/testrand_impl.h b/crypto/secp256k1/libsecp256k1/src/testrand_impl.h index 15c7b9f12..b84f5730a 100644 --- a/crypto/secp256k1/libsecp256k1/src/testrand_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/testrand_impl.h @@ -1,100 +1,110 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_TESTRAND_IMPL_H_ -#define _SECP256K1_TESTRAND_IMPL_H_ +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H #include +#include #include #include "testrand.h" #include "hash.h" +#include "util.h" -static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; -static uint32_t secp256k1_test_rng_precomputed[8]; -static int secp256k1_test_rng_precomputed_used = 8; -static uint64_t secp256k1_test_rng_integer; -static int secp256k1_test_rng_integer_bits_left = 0; +static uint64_t secp256k1_test_state[4]; -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); -} +SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { + static const unsigned char PREFIX[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', ' ', 't', 'e', 's', 't', ' ', 'i', 'n', 'i', 't'}; + unsigned char out32[32]; + secp256k1_sha256 hash; + int i; -SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { - if (secp256k1_test_rng_precomputed_used == 8) { - secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); - secp256k1_test_rng_precomputed_used = 0; + /* Use SHA256(PREFIX || seed16) as initial state. */ + secp256k1_sha256_initialize(&hash); + secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX)); + secp256k1_sha256_write(&hash, seed16, 16); + secp256k1_sha256_finalize(&hash, out32); + for (i = 0; i < 4; ++i) { + uint64_t s = 0; + int j; + for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; + secp256k1_test_state[i] = s; } - return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } -static uint32_t secp256k1_rand_bits(int bits) { - uint32_t ret; - if (secp256k1_test_rng_integer_bits_left < bits) { - secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); - secp256k1_test_rng_integer_bits_left += 32; - } - ret = secp256k1_test_rng_integer; - secp256k1_test_rng_integer >>= bits; - secp256k1_test_rng_integer_bits_left -= bits; - ret &= ((~((uint32_t)0)) >> (32 - bits)); - return ret; +SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); } -static uint32_t secp256k1_rand_int(uint32_t range) { - /* We want a uniform integer between 0 and range-1, inclusive. - * B is the smallest number such that range <= 2**B. - * two mechanisms implemented here: - * - generate B bits numbers until one below range is found, and return it - * - find the largest multiple M of range that is <= 2**(B+A), generate B+A - * bits numbers until one below M is found, and return it modulo range - * The second mechanism consumes A more bits of entropy in every iteration, - * but may need fewer iterations due to M being closer to 2**(B+A) then - * range is to 2**B. The array below (indexed by B) contains a 0 when the - * first mechanism is to be used, and the number A otherwise. - */ - static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; - uint32_t trange, mult; - int bits = 0; - if (range <= 1) { - return 0; - } - trange = range - 1; - while (trange > 0) { - trange >>= 1; - bits++; - } - if (addbits[bits]) { - bits = bits + addbits[bits]; - mult = ((~((uint32_t)0)) >> (32 - bits)) / range; - trange = range * mult; - } else { - trange = range; - mult = 1; +SECP256K1_INLINE static uint64_t testrand64(void) { + /* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */ + const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0]; + const uint64_t t = secp256k1_test_state[1] << 17; + secp256k1_test_state[2] ^= secp256k1_test_state[0]; + secp256k1_test_state[3] ^= secp256k1_test_state[1]; + secp256k1_test_state[1] ^= secp256k1_test_state[2]; + secp256k1_test_state[0] ^= secp256k1_test_state[3]; + secp256k1_test_state[2] ^= t; + secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45); + return result; +} + +SECP256K1_INLINE static uint64_t testrand_bits(int bits) { + if (bits == 0) return 0; + return testrand64() >> (64 - bits); +} + +SECP256K1_INLINE static uint32_t testrand32(void) { + return testrand64() >> 32; +} + +static uint32_t testrand_int(uint32_t range) { + uint32_t mask = 0; + uint32_t range_copy; + /* Reduce range by 1, changing its meaning to "maximum value". */ + VERIFY_CHECK(range != 0); + range -= 1; + /* Count the number of bits in range. */ + range_copy = range; + while (range_copy) { + mask = (mask << 1) | 1U; + range_copy >>= 1; } - while(1) { - uint32_t x = secp256k1_rand_bits(bits); - if (x < trange) { - return (mult == 1) ? x : (x % range); - } + /* Generation loop. */ + while (1) { + uint32_t val = testrand64() & mask; + if (val <= range) return val; } } -static void secp256k1_rand256(unsigned char *b32) { - secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); +static void testrand256(unsigned char *b32) { + int i; + for (i = 0; i < 4; ++i) { + uint64_t val = testrand64(); + b32[0] = val; + b32[1] = val >> 8; + b32[2] = val >> 16; + b32[3] = val >> 24; + b32[4] = val >> 32; + b32[5] = val >> 40; + b32[6] = val >> 48; + b32[7] = val >> 56; + b32 += 8; + } } -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { +static void testrand_bytes_test(unsigned char *bytes, size_t len) { size_t bits = 0; memset(bytes, 0, len); while (bits < len * 8) { int now; uint32_t val; - now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; - val = secp256k1_rand_bits(1); + now = 1 + (testrand_bits(6) * testrand_bits(5) + 16) / 31; + val = testrand_bits(1); while (now > 0 && bits < len * 8) { bytes[bits / 8] |= val << (bits % 8); now--; @@ -103,8 +113,55 @@ static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { } } -static void secp256k1_rand256_test(unsigned char *b32) { - secp256k1_rand_bytes_test(b32, 32); +static void testrand256_test(unsigned char *b32) { + testrand_bytes_test(b32, 32); +} + +static void testrand_flip(unsigned char *b, size_t len) { + b[testrand_int(len)] ^= (1 << testrand_bits(3)); +} + +static void testrand_init(const char* hexseed) { + unsigned char seed16[16] = {0}; + if (hexseed && strlen(hexseed) != 0) { + int pos = 0; + while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { + unsigned short sh; + if ((sscanf(hexseed, "%2hx", &sh)) == 1) { + seed16[pos] = sh; + } else { + break; + } + hexseed += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "rb"); + if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); + } + } + + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + testrand_seed(seed16); +} + +static void testrand_finish(void) { + unsigned char run32[32]; + testrand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); } -#endif +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/tests.c b/crypto/secp256k1/libsecp256k1/src/tests.c index 9ae7d3028..88628a14e 100644 --- a/crypto/secp256k1/libsecp256k1/src/tests.c +++ b/crypto/secp256k1/libsecp256k1/src/tests.c @@ -1,51 +1,89 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +/*********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include #include +#include #include +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif +#if defined(VERIFY) && defined(COVERAGE) + #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.") +#endif #include "secp256k1.c" -#include "include/secp256k1.h" + +#include "../include/secp256k1.h" +#include "../include/secp256k1_preallocated.h" #include "testrand_impl.h" +#include "checkmem.h" +#include "testutil.h" +#include "util.h" -#ifdef ENABLE_OPENSSL_TESTS -#include "openssl/bn.h" -#include "openssl/ec.h" -#include "openssl/ecdsa.h" -#include "openssl/obj_mac.h" -#endif +#include "../contrib/lax_der_parsing.c" +#include "../contrib/lax_der_privatekey_parsing.c" -#include "contrib/lax_der_parsing.c" -#include "contrib/lax_der_privatekey_parsing.c" - -#if !defined(VG_CHECK) -# if defined(VALGRIND) -# include -# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) -# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) -# else -# define VG_UNDEF(x,y) -# define VG_CHECK(x,y) -# endif +#include "modinv32_impl.h" +#ifdef SECP256K1_WIDEMUL_INT128 +#include "modinv64_impl.h" +#include "int128_impl.h" #endif -static int count = 64; -static secp256k1_context *ctx = NULL; +#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else + +static int COUNT = 16; +static secp256k1_context *CTX = NULL; +static secp256k1_context *STATIC_CTX = NULL; -static void counting_illegal_callback_fn(const char* str, void* data) { +static int all_bytes_equal(const void* s, unsigned char value, size_t n) { + const unsigned char *p = s; + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != value) { + return 0; + } + } + return 1; +} + +#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \ + int32_t _calls_to_callback = 0; \ + secp256k1_callback _saved_callback = ctx->callback; \ + callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \ + { expr_or_stmt; } \ + ctx->callback = _saved_callback; \ + CHECK(_calls_to_callback == 1); \ +} while(0); + +/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once + * + * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */ +#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, secp256k1_context_set_error_callback) +#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, secp256k1_context_set_illegal_callback) + +/* CHECK that + * - expr calls the illegal callback of ctx exactly once and, + * - expr == 0 (or equivalently, expr == NULL) + * + * Useful for checking functions that return an integer or a pointer. */ +#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) +#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0)) + +static void counting_callback_fn(const char* str, void* data) { /* Dummy callback function that just counts. */ int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MAX); (*p)++; } @@ -54,198 +92,375 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MIN); (*p)--; } -void random_field_element_test(secp256k1_fe *fe) { - do { - unsigned char b32[32]; - secp256k1_rand256_test(b32); - if (secp256k1_fe_set_b32(fe, b32)) { - break; +static void run_xoshiro256pp_tests(void) { + { + size_t i; + /* Sanity check that we run before the actual seeding. */ + for (i = 0; i < sizeof(secp256k1_test_state)/sizeof(secp256k1_test_state[0]); i++) { + CHECK(secp256k1_test_state[i] == 0); } - } while(1); -} - -void random_field_element_magnitude(secp256k1_fe *fe) { - secp256k1_fe zero; - int n = secp256k1_rand_int(9); - secp256k1_fe_normalize(fe); - if (n == 0) { - return; } - secp256k1_fe_clear(&zero); - secp256k1_fe_negate(&zero, &zero, 0); - secp256k1_fe_mul_int(&zero, n - 1); - secp256k1_fe_add(fe, &zero); - VERIFY_CHECK(fe->magnitude == n); + { + int i; + unsigned char buf32[32]; + unsigned char seed16[16] = { + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + 'C', 'H', 'I', 'C', 'K', 'E', 'N', '!', + }; + unsigned char buf32_expected[32] = { + 0xAF, 0xCC, 0xA9, 0x16, 0xB5, 0x6C, 0xE3, 0xF0, + 0x44, 0x3F, 0x45, 0xE0, 0x47, 0xA5, 0x08, 0x36, + 0x4C, 0xCC, 0xC1, 0x18, 0xB2, 0xD8, 0x8F, 0xEF, + 0x43, 0x26, 0x15, 0x57, 0x37, 0x00, 0xEF, 0x30, + }; + testrand_seed(seed16); + for (i = 0; i < 17; i++) { + testrand256(buf32); + } + CHECK(secp256k1_memcmp_var(buf32, buf32_expected, sizeof(buf32)) == 0); + } } -void random_group_element_test(secp256k1_ge *ge) { - secp256k1_fe fe; - do { - random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { - secp256k1_fe_normalize(&ge->y); - break; - } - } while(1); +static void run_selftest_tests(void) { + /* Test public API */ + secp256k1_selftest(); } -void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { - secp256k1_fe z2, z3; - do { - random_field_element_test(&gej->z); - if (!secp256k1_fe_is_zero(&gej->z)) { - break; - } - } while(1); - secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_mul(&z3, &z2, &gej->z); - secp256k1_fe_mul(&gej->x, &ge->x, &z2); - secp256k1_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; +static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { + return a->built == b->built + && secp256k1_scalar_eq(&a->scalar_offset, &b->scalar_offset) + && secp256k1_ge_eq_var(&a->ge_offset, &b->ge_offset) + && secp256k1_fe_equal(&a->proj_blind, &b->proj_blind); } -void random_scalar_order_test(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_rand256_test(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); +static int context_eq(const secp256k1_context *a, const secp256k1_context *b) { + return a->declassify == b->declassify + && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) + && a->illegal_callback.fn == b->illegal_callback.fn + && a->illegal_callback.data == b->illegal_callback.data + && a->error_callback.fn == b->error_callback.fn + && a->error_callback.data == b->error_callback.data; } -void random_scalar_order(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_rand256(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); +static void run_deprecated_context_flags_test(void) { + /* Check that a context created with any of the flags in the flags array is + * identical to the NONE context. */ + unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, + SECP256K1_CONTEXT_VERIFY, + SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY }; + secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + int i; + for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) { + secp256k1_context *tmp_ctx; + CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i])); + tmp_ctx = secp256k1_context_create(flags[i]); + CHECK(context_eq(none_ctx, tmp_ctx)); + secp256k1_context_destroy(tmp_ctx); + } + secp256k1_context_destroy(none_ctx); } -void run_context_tests(void) { +static void run_ec_illegal_argument_tests(void) { secp256k1_pubkey pubkey; + secp256k1_pubkey zero_pubkey; secp256k1_ecdsa_signature sig; unsigned char ctmp[32]; - int32_t ecount; - int32_t ecount2; - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* Setup */ + memset(ctmp, 1, 32); + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + /* Verify context-type checking illegal-argument errors. */ + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL)); + SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); + SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_negate(CTX, NULL)); + CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1); +} + +static void run_static_context_tests(int use_prealloc) { + /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ + CHECK(secp256k1_context_no_precomp == secp256k1_context_static); + + { + unsigned char seed[32] = {0x17}; + + /* Randomizing secp256k1_context_static is not supported. */ + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, seed)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, NULL)); + + /* Destroying or cloning secp256k1_context_static is not supported. */ + if (use_prealloc) { + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone_size(STATIC_CTX)); + { + secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); + CHECK(my_static_ctx != NULL); + memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx)); + CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); + free(my_static_ctx); + } + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_preallocated_destroy(STATIC_CTX)); + } else { + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_clone(STATIC_CTX)); + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_destroy(STATIC_CTX)); + } + } + + { + /* Verify that setting and resetting illegal callback works */ + int32_t dummy = 0; + secp256k1_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy); + CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == &dummy); + secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == NULL); + } +} + +static void run_proper_context_tests(int use_prealloc) { + int32_t dummy = 0; + secp256k1_context *my_ctx, *my_ctx_fresh; + void *my_ctx_prealloc = NULL; + unsigned char seed[32] = {0x17}; secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; - ecount = 0; - ecount2 = 10; - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); - CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* Fresh reference context for comparison */ + my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + if (use_prealloc) { + my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + my_ctx = secp256k1_context_preallocated_create(my_ctx_prealloc, SECP256K1_CONTEXT_NONE); + } else { + my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + } + + /* Randomize and reset randomization */ + CHECK(context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, seed) == 1); + CHECK(!context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */ + secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL); + CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); + + /* check if sizes for cloning are consistent */ + CHECK(secp256k1_context_preallocated_clone_size(my_ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); /*** clone and destroy all of them to make sure cloning was complete ***/ { secp256k1_context *ctx_tmp; - ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + if (use_prealloc) { + /* clone into a non-preallocated context and then again into a new preallocated one. */ + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); + + free(my_ctx_prealloc); + my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); + } else { + /* clone into a preallocated context and then again into a new non-preallocated one. */ + void *prealloc_tmp; + + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(prealloc_tmp != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + } } /* Verify that the error callback makes it across the clone. */ - CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); + CHECK(my_ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); /* And that it resets back to default. */ - secp256k1_context_set_error_callback(sign, NULL, NULL); - CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + secp256k1_context_set_error_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + + /* Verify that setting and resetting illegal callback works */ + secp256k1_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy); + CHECK(my_ctx->illegal_callback.fn == counting_callback_fn); + CHECK(my_ctx->illegal_callback.data == &dummy); + secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); + CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(my_ctx->illegal_callback.data == NULL); + CHECK(context_eq(my_ctx, my_ctx_fresh)); /*** attempt to use them ***/ - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - /* Verify context-type checking illegal-argument errors. */ - memset(ctmp, 1, 32); - CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); - CHECK(ecount == 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); - CHECK(ecount == 2); - VG_UNDEF(&sig, sizeof(sig)); - CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); - VG_CHECK(&sig, sizeof(sig)); - CHECK(ecount2 == 10); - CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); - CHECK(ecount2 == 11); - CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); - CHECK(ecount2 == 12); - CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); - CHECK(ecount2 == 13); - CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_context_randomize(sign, NULL) == 1); - CHECK(ecount2 == 13); - secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); - secp256k1_context_set_illegal_callback(sign, NULL, NULL); - - /* This shouldn't leak memory, due to already-set tests. */ - secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); - secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); - /* obtain a working nonce */ do { - random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + testutil_random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&my_ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); + if (use_prealloc) { + secp256k1_context_preallocated_destroy(my_ctx); + free(my_ctx_prealloc); + } else { + secp256k1_context_destroy(my_ctx); + } + secp256k1_context_destroy(my_ctx_fresh); + /* Defined as no-op. */ secp256k1_context_destroy(NULL); + secp256k1_context_preallocated_destroy(NULL); +} + +static void run_scratch_tests(void) { + const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; + + size_t checkpoint; + size_t checkpoint_2; + secp256k1_scratch_space *scratch; + secp256k1_scratch_space local_scratch; + + /* Test public API */ + scratch = secp256k1_scratch_space_create(CTX, 1000); + CHECK(scratch != NULL); + + /* Test internal API */ + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size == 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating 500 bytes succeeds */ + checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* Allocating another 501 bytes fails */ + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 501) == NULL); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(scratch->alloc_size != 0); + CHECK(scratch->alloc_size % ALIGNMENT == 0); + + /* ...but it succeeds once we apply the checkpoint to undo it */ + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + CHECK(scratch->alloc_size == 0); + CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) != NULL); + CHECK(scratch->alloc_size != 0); + + /* try to apply a bad checkpoint */ + checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ + + /* try to use badly initialized scratch space */ + secp256k1_scratch_space_destroy(CTX, scratch); + memset(&local_scratch, 0, sizeof(local_scratch)); + scratch = &local_scratch; + CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); + CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); + + /* Test that large integers do not wrap around in a bad way */ + scratch = secp256k1_scratch_space_create(CTX, 1000); + /* Try max allocation with a large number of objects. Only makes sense if + * ALIGNMENT is greater than 1 because otherwise the objects take no extra + * space. */ + CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); + /* Try allocating SIZE_MAX to test wrap around which only happens if + * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch + * space is too small. */ + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, SIZE_MAX) == NULL); + secp256k1_scratch_space_destroy(CTX, scratch); + + /* cleanup */ + secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ +} + +static void run_ctz_tests(void) { + static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; + static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; + int shift; + unsigned i; + for (i = 0; i < sizeof(b32) / sizeof(b32[0]); ++i) { + for (shift = 0; shift < 32; ++shift) { + CHECK(secp256k1_ctz32_var_debruijn(b32[i] << shift) == shift); + CHECK(secp256k1_ctz32_var(b32[i] << shift) == shift); + } + } + for (i = 0; i < sizeof(b64) / sizeof(b64[0]); ++i) { + for (shift = 0; shift < 64; ++shift) { + CHECK(secp256k1_ctz64_var_debruijn(b64[i] << shift) == shift); + CHECK(secp256k1_ctz64_var(b64[i] << shift) == shift); + } + } } /***** HASH TESTS *****/ -void run_sha256_tests(void) { - static const char *inputs[8] = { +static void run_sha256_known_output_tests(void) { + static const char *inputs[] = { "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "For this sample, this 63-byte string will be used as input data", - "This is exactly 64 bytes long, not counting the terminating byte" + "This is exactly 64 bytes long, not counting the terminating byte", + "aaaaa", }; - static const unsigned char outputs[8][32] = { + static const unsigned int repeat[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1000000/5 + }; + static const unsigned char outputs[][32] = { {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, @@ -253,28 +468,158 @@ void run_sha256_tests(void) { {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, - {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}, + {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}, }; - int i; - for (i = 0; i < 8; i++) { + unsigned int i, ninputs; + + /* Skip last input vector for low iteration counts */ + ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1; + CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++; + + for (i = 0; i < ninputs; i++) { unsigned char out[32]; - secp256k1_sha256_t hasher; + secp256k1_sha256 hasher; + unsigned int j; + /* 1. Run: simply write the input bytestrings */ + j = repeat[i]; secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + while (j > 0) { + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + j--; + } secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + /* 2. Run: split the input bytestrings randomly before writing */ if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); + int split = testrand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + j = repeat[i]; + while (j > 0) { + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + j--; + } secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } } -void run_hmac_sha256_tests(void) { +/** SHA256 counter tests + +The tests verify that the SHA256 counter doesn't wrap around at message length +2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the +implementation of the counter and it catches multiple natural 32-bit overflows +(e.g., counting bits, counting bytes, counting blocks, ...). + +The test vectors have been generated using following Python script which relies +on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2). + +``` +from sha256 import sha256 +from copy import copy + +def midstate_c_definition(hasher): + ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n' + ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}' + return ret + +def output_c_literal(hasher): + return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}' + +MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno' +assert(len(MESSAGE) == 64) +BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)] + +midstates = [] +digests = [] +hasher = sha256() +for i in range(BYTE_BOUNDARIES[-1] + 1): + if i in BYTE_BOUNDARIES: + midstates.append(midstate_c_definition(hasher)) + hasher_copy = copy(hasher) + hasher_copy.update(MESSAGE) + digests.append(output_c_literal(hasher_copy)) + hasher.update(MESSAGE) + +for x in midstates: + print(x + ',') + +for x in digests: + print(x + ',') +``` +*/ +static void run_sha256_counter_tests(void) { + static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; + static const secp256k1_sha256 midstates[] = { + {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, + {0x00}, 0xfffc0}, + {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26}, + {0x00}, 0x1fffc0}, + {{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1}, + {0x00}, 0x3fffc0}, + {{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6}, + {0x00}, 0x7fffc0}, + {{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c}, + {0x00}, 0xffffc0}, + {{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2}, + {0x00}, 0x1ffffc0}, + {{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c}, + {0x00}, 0x3ffffc0}, + {{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0}, + {0x00}, 0x7ffffc0}, + {{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad}, + {0x00}, 0xfffffc0}, + {{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023}, + {0x00}, 0x1fffffc0}, + {{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1}, + {0x00}, 0x3fffffc0}, + {{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec}, + {0x00}, 0x7fffffc0}, + {{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162}, + {0x00}, 0xffffffc0}, + {{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a}, + {0x00}, 0x1ffffffc0}, + }; + static const unsigned char outputs[][32] = { + {0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15}, + {0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb}, + {0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e}, + {0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9}, + {0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7}, + {0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07}, + {0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76}, + {0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0}, + {0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8}, + {0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6}, + {0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e}, + {0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b}, + {0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34}, + {0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e}, + }; + unsigned int i; + for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) { + unsigned char out[32]; + secp256k1_sha256 hasher = midstates[i]; + secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); + secp256k1_sha256_finalize(&hasher, out); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); + } +} + +/* Tests for the equality of two sha256 structs. This function only produces a + * correct result if an integer multiple of 64 many bytes have been written + * into the hash functions. This function is used by some module tests. */ +static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { + /* Is buffer fully consumed? */ + CHECK((sha1->bytes & 0x3F) == 0); + + CHECK(sha1->bytes == sha2->bytes); + CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); +} + +static void run_hmac_sha256_tests(void) { static const char *keys[6] = { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", "\x4a\x65\x66\x65", @@ -301,24 +646,24 @@ void run_hmac_sha256_tests(void) { }; int i; for (i = 0; i < 6; i++) { - secp256k1_hmac_sha256_t hasher; + secp256k1_hmac_sha256 hasher; unsigned char out[32]; secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); + int split = testrand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } } -void run_rfc6979_hmac_sha256_tests(void) { +static void run_rfc6979_hmac_sha256_tests(void) { static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; static const unsigned char out1[3][32] = { {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, @@ -333,322 +678,1354 @@ void run_rfc6979_hmac_sha256_tests(void) { {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; unsigned char out[32]; int i; secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) != 0); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out2[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); } -/***** RANDOM TESTS *****/ - -void test_rand_bits(int rand32, int bits) { - /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to - * get a false negative chance below once in a billion */ - static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; - /* We try multiplying the results with various odd numbers, which shouldn't - * influence the uniform distribution modulo a power of 2. */ - static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; - /* We only select up to 6 bits from the output to analyse */ - unsigned int usebits = bits > 6 ? 6 : bits; - unsigned int maxshift = bits - usebits; - /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit - number, track all observed outcomes, one per bit in a uint64_t. */ - uint64_t x[6][27] = {{0}}; - unsigned int i, shift, m; - /* Multiply the output of all rand calls with the odd number m, which - should not change the uniformity of its distribution. */ - for (i = 0; i < rounds[usebits]; i++) { - uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); - CHECK((((uint64_t)r) >> bits) == 0); - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - uint32_t rm = r * mults[m]; - for (shift = 0; shift <= maxshift; shift++) { - x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); +static void run_tagged_sha256_tests(void) { + unsigned char tag[32] = { 0 }; + unsigned char msg[32] = { 0 }; + unsigned char hash32[32]; + unsigned char hash_expected[32] = { + 0x04, 0x7A, 0x5E, 0x17, 0xB5, 0x86, 0x47, 0xC1, + 0x3C, 0xC6, 0xEB, 0xC0, 0xAA, 0x58, 0x3B, 0x62, + 0xFB, 0x16, 0x43, 0x32, 0x68, 0x77, 0x40, 0x6C, + 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 + }; + + /* API test */ + CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0)); + + /* Static test vector */ + memcpy(tag, "tag", 3); + memcpy(msg, "msg", 3); + CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, 3, msg, 3) == 1); + CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); +} + +/***** MODINV TESTS *****/ + +/* Compute the modular inverse of (odd) x mod 2^64. */ +static uint64_t modinv2p64(uint64_t x) { + /* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See + * Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for + * why. Start with L=0, for which it is true for every odd x that + * 1/x=1 mod 2. Iterating 6 times gives us 1/x mod 2^64. */ + int l; + uint64_t w = 1; + CHECK(x & 1); + for (l = 0; l < 6; ++l) w *= (2 - w*x); + return w; +} + + +/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity. + * + * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other + * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ +static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { + uint16_t mul[32]; + uint64_t c = 0; + int i, j; + int m_bitlen = 0; + int mul_bitlen = 0; + + if (b != NULL) { + /* Compute the product of a and b, and put it in mul. */ + for (i = 0; i < 32; ++i) { + for (j = i <= 15 ? 0 : i - 15; j <= i && j <= 15; j++) { + c += (uint64_t)a[j] * b[i - j]; + } + mul[i] = c & 0xFFFF; + c >>= 16; + } + CHECK(c == 0); + + /* compute the highest set bit in mul */ + for (i = 511; i >= 0; --i) { + if ((mul[i >> 4] >> (i & 15)) & 1) { + mul_bitlen = i; + break; + } + } + } else { + /* if b==NULL, set mul=a. */ + memcpy(mul, a, 32); + memset(mul + 16, 0, 32); + /* compute the highest set bit in mul */ + for (i = 255; i >= 0; --i) { + if ((mul[i >> 4] >> (i & 15)) & 1) { + mul_bitlen = i; + break; } } } - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - for (shift = 0; shift <= maxshift; shift++) { - /* Test that the lower usebits bits of x[shift] are 1 */ - CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + + if (m) { + /* Compute the highest set bit in m. */ + for (i = 255; i >= 0; --i) { + if ((m[i >> 4] >> (i & 15)) & 1) { + m_bitlen = i; + break; + } + } + + /* Try do mul -= m<= 0; --i) { + uint16_t mul2[32]; + int64_t cs; + + /* Compute mul2 = mul - m<= 0 && bitpos < 256) { + sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + } + } + /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ + cs += mul[j]; + cs -= sub; + mul2[j] = (cs & 0xFFFF); + cs >>= 16; + } + /* If remainder of subtraction is 0, set mul = mul2. */ + if (cs == 0) { + memcpy(mul, mul2, sizeof(mul)); + } + } + /* Sanity check: test that all limbs higher than m's highest are zero */ + for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { + CHECK(mul[i] == 0); } } + memcpy(out, mul, 32); } -/* Subrange must be a whole divisor of range, and at most 64 */ -void test_rand_int(uint32_t range, uint32_t subrange) { - /* (1-1/subrange)^rounds < 1/10^9 */ - int rounds = (subrange * 2073) / 100; +/* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */ +static void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { int i; - uint64_t x = 0; - CHECK((range % subrange) == 0); - for (i = 0; i < rounds; i++) { - uint32_t r = secp256k1_rand_int(range); - CHECK(r < range); - r = r % subrange; - x |= (((uint64_t)1) << r); + memset(out->v, 0, sizeof(out->v)); + for (i = 0; i < 256; ++i) { + out->v[i / 30] |= (int32_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 30); } - /* Test that the lower subrange bits of x are 1. */ - CHECK(((~x) << (64 - subrange)) == 0); } -void run_rand_bits(void) { - size_t b; - test_rand_bits(1, 32); - for (b = 1; b <= 32; b++) { - test_rand_bits(0, b); +/* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */ +static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { + int i; + memset(out, 0, 32); + for (i = 0; i < 256; ++i) { + out[i >> 4] |= (((in->v[i / 30]) >> (i % 30)) & 1) << (i & 15); } } -void run_rand_int(void) { - static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; - static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; - unsigned int m, s; - for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { - for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { - test_rand_int(ms[m] * ss[s], ss[s]); +/* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */ +static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { + int i; + for (i = 0; i < 16; ++i) { + int pos = testrand_bits(3); + if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) { + x->v[pos] -= 0x40000000; + x->v[pos + 1] += 1; + } else if (x->v[pos] < 0 && x->v[pos + 1] >= 0x3fffffff) { + x->v[pos] += 0x40000000; + x->v[pos + 1] -= 1; } } } -/***** NUM TESTS *****/ - -#ifndef USE_NUM_NONE -void random_num_negate(secp256k1_num *num) { - if (secp256k1_rand_bits(1)) { - secp256k1_num_negate(num); +/* Test secp256k1_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { + uint16_t tmp[16]; + secp256k1_modinv32_signed30 x; + secp256k1_modinv32_modinfo m; + int i, vartime, nonzero; + + uint16_to_signed30(&x, in); + nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0; + uint16_to_signed30(&m.modulus, mod); + + /* compute 1/modulus mod 2^30 */ + m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff; + CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1); + + /* Test secp256k1_jacobi32_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed30(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed30(&x, sqr); + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed30(&x, in); + mutate_sign_signed30(&m.modulus); + for (vartime = 0; vartime < 2; ++vartime) { + /* compute inverse */ + (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); + + /* produce output */ + signed30_to_uint16(out, &x); + + /* check if the inverse times the input is 1 (mod m), unless x is 0. */ + mulmod256(tmp, out, in, mod); + CHECK(tmp[0] == nonzero); + for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); + + /* invert again */ + (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); + + /* check if the result is equal to the input */ + signed30_to_uint16(tmp, &x); + for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); } } -void random_num_order_test(secp256k1_num *num) { - secp256k1_scalar sc; - random_scalar_order_test(&sc); - secp256k1_scalar_get_num(num, &sc); +#ifdef SECP256K1_WIDEMUL_INT128 +/* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */ +static void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { + int i; + memset(out->v, 0, sizeof(out->v)); + for (i = 0; i < 256; ++i) { + out->v[i / 62] |= (int64_t)(((in[i >> 4]) >> (i & 15)) & 1) << (i % 62); + } } -void random_num_order(secp256k1_num *num) { - secp256k1_scalar sc; - random_scalar_order(&sc); - secp256k1_scalar_get_num(num, &sc); -} - -void test_num_negate(void) { - secp256k1_num n1; - secp256k1_num n2; - random_num_order_test(&n1); /* n1 = R */ - random_num_negate(&n1); - secp256k1_num_copy(&n2, &n1); /* n2 = R */ - secp256k1_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */ - CHECK(secp256k1_num_is_zero(&n1)); - secp256k1_num_copy(&n1, &n2); /* n1 = R */ - secp256k1_num_negate(&n1); /* n1 = -R */ - CHECK(!secp256k1_num_is_zero(&n1)); - secp256k1_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */ - CHECK(secp256k1_num_is_zero(&n1)); - secp256k1_num_copy(&n1, &n2); /* n1 = R */ - secp256k1_num_negate(&n1); /* n1 = -R */ - CHECK(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2)); - secp256k1_num_negate(&n1); /* n1 = R */ - CHECK(secp256k1_num_eq(&n1, &n2)); -} - -void test_num_add_sub(void) { +/* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */ +static void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { int i; - secp256k1_scalar s; - secp256k1_num n1; - secp256k1_num n2; - secp256k1_num n1p2, n2p1, n1m2, n2m1; - random_num_order_test(&n1); /* n1 = R1 */ - if (secp256k1_rand_bits(1)) { - random_num_negate(&n1); - } - random_num_order_test(&n2); /* n2 = R2 */ - if (secp256k1_rand_bits(1)) { - random_num_negate(&n2); - } - secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ - secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ - secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ - secp256k1_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */ - CHECK(secp256k1_num_eq(&n1p2, &n2p1)); - CHECK(!secp256k1_num_eq(&n1p2, &n1m2)); - secp256k1_num_negate(&n2m1); /* n2m1 = -R2 + R1 */ - CHECK(secp256k1_num_eq(&n2m1, &n1m2)); - CHECK(!secp256k1_num_eq(&n2m1, &n1)); - secp256k1_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */ - CHECK(secp256k1_num_eq(&n2m1, &n1)); - CHECK(!secp256k1_num_eq(&n2p1, &n1)); - secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ - CHECK(secp256k1_num_eq(&n2p1, &n1)); - - /* check is_one */ - secp256k1_scalar_set_int(&s, 1); - secp256k1_scalar_get_num(&n1, &s); - CHECK(secp256k1_num_is_one(&n1)); - /* check that 2^n + 1 is never 1 */ - secp256k1_scalar_get_num(&n2, &s); - for (i = 0; i < 250; ++i) { - secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ - secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ - CHECK(!secp256k1_num_is_one(&n1p2)); - } -} - -void test_num_mod(void) { + memset(out, 0, 32); + for (i = 0; i < 256; ++i) { + out[i >> 4] |= (((in->v[i / 62]) >> (i % 62)) & 1) << (i & 15); + } +} + +/* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */ +static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { + static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); int i; - secp256k1_scalar s; - secp256k1_num order, n; - - /* check that 0 mod anything is 0 */ - random_scalar_order_test(&s); - secp256k1_scalar_get_num(&order, &s); - secp256k1_scalar_set_int(&s, 0); - secp256k1_scalar_get_num(&n, &s); - secp256k1_num_mod(&n, &order); - CHECK(secp256k1_num_is_zero(&n)); - - /* check that anything mod 1 is 0 */ - secp256k1_scalar_set_int(&s, 1); - secp256k1_scalar_get_num(&order, &s); - secp256k1_scalar_get_num(&n, &s); - secp256k1_num_mod(&n, &order); - CHECK(secp256k1_num_is_zero(&n)); - - /* check that increasing the number past 2^256 does not break this */ - random_scalar_order_test(&s); - secp256k1_scalar_get_num(&n, &s); - /* multiply by 2^8, which'll test this case with high probability */ for (i = 0; i < 8; ++i) { - secp256k1_num_add(&n, &n, &n); + int pos = testrand_bits(2); + if (x->v[pos] > 0 && x->v[pos + 1] <= M62) { + x->v[pos] -= (M62 + 1); + x->v[pos + 1] += 1; + } else if (x->v[pos] < 0 && x->v[pos + 1] >= -M62) { + x->v[pos] += (M62 + 1); + x->v[pos + 1] -= 1; + } } - secp256k1_num_mod(&n, &order); - CHECK(secp256k1_num_is_zero(&n)); } -void test_num_jacobi(void) { - secp256k1_scalar sqr; - secp256k1_scalar small; - secp256k1_scalar five; /* five is not a quadratic residue */ - secp256k1_num order, n; +/* Test secp256k1_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ +static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { + static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); + uint16_t tmp[16]; + secp256k1_modinv64_signed62 x; + secp256k1_modinv64_modinfo m; + int i, vartime, nonzero; + + uint16_to_signed62(&x, in); + nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0; + uint16_to_signed62(&m.modulus, mod); + + /* compute 1/modulus mod 2^62 */ + m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62; + CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1); + + /* Test secp256k1_jacobi64_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed62(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed62(&x, sqr); + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed62(&x, in); + mutate_sign_signed62(&m.modulus); + for (vartime = 0; vartime < 2; ++vartime) { + /* compute inverse */ + (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); + + /* produce output */ + signed62_to_uint16(out, &x); + + /* check if the inverse times the input is 1 (mod m), unless x is 0. */ + mulmod256(tmp, out, in, mod); + CHECK(tmp[0] == nonzero); + for (i = 1; i < 16; ++i) CHECK(tmp[i] == 0); + + /* invert again */ + (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); + + /* check if the result is equal to the input */ + signed62_to_uint16(tmp, &x); + for (i = 0; i < 16; ++i) CHECK(tmp[i] == in[i]); + } +} +#endif + +/* test if a and b are coprime */ +static int coprime(const uint16_t* a, const uint16_t* b) { + uint16_t x[16], y[16], t[16]; int i; - /* squares mod 5 are 1, 4 */ - const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + int iszero; + memcpy(x, a, 32); + memcpy(y, b, 32); + + /* simple gcd loop: while x!=0, (x,y)=(y%x,x) */ + while (1) { + iszero = 1; + for (i = 0; i < 16; ++i) { + if (x[i] != 0) { + iszero = 0; + break; + } + } + if (iszero) break; + mulmod256(t, y, NULL, x); + memcpy(y, x, 32); + memcpy(x, t, 32); + } - /* check some small values with 5 as the order */ - secp256k1_scalar_set_int(&five, 5); - secp256k1_scalar_get_num(&order, &five); - for (i = 0; i < 10; ++i) { - secp256k1_scalar_set_int(&small, i); - secp256k1_scalar_get_num(&n, &small); - CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + /* return whether y=1 */ + if (y[0] != 1) return 0; + for (i = 1; i < 16; ++i) { + if (y[i] != 0) return 0; } + return 1; +} - /** test large values with 5 as group order */ - secp256k1_scalar_get_num(&order, &five); - /* we first need a scalar which is not a multiple of 5 */ - do { - secp256k1_num fiven; - random_scalar_order_test(&sqr); - secp256k1_scalar_get_num(&fiven, &five); - secp256k1_scalar_get_num(&n, &sqr); - secp256k1_num_mod(&n, &fiven); - } while (secp256k1_num_is_zero(&n)); - /* next force it to be a residue. 2 is a nonresidue mod 5 so we can - * just multiply by two, i.e. add the number to itself */ - if (secp256k1_num_jacobi(&n, &order) == -1) { - secp256k1_num_add(&n, &n, &n); - } - - /* test residue */ - CHECK(secp256k1_num_jacobi(&n, &order) == 1); - /* test nonresidue */ - secp256k1_num_add(&n, &n, &n); - CHECK(secp256k1_num_jacobi(&n, &order) == -1); - - /** test with secp group order as order */ - secp256k1_scalar_order_get_num(&order); - random_scalar_order_test(&sqr); - secp256k1_scalar_sqr(&sqr, &sqr); - /* test residue */ - secp256k1_scalar_get_num(&n, &sqr); - CHECK(secp256k1_num_jacobi(&n, &order) == 1); - /* test nonresidue */ - secp256k1_scalar_mul(&sqr, &sqr, &five); - secp256k1_scalar_get_num(&n, &sqr); - CHECK(secp256k1_num_jacobi(&n, &order) == -1); - /* test multiple of the order*/ - CHECK(secp256k1_num_jacobi(&order, &order) == 0); - - /* check one less than the order */ - secp256k1_scalar_set_int(&small, 1); - secp256k1_scalar_get_num(&n, &small); - secp256k1_num_sub(&n, &order, &n); - CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ -} - -void run_num_smalltests(void) { +static void run_modinv_tests(void) { + /* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */ + static const uint16_t CASES[][3][16] = { + /* Test cases triggering edge cases in divsteps */ + + /* Test case known to need 713 divsteps */ + {{0x1513, 0x5389, 0x54e9, 0x2798, 0x1957, 0x66a0, 0x8057, 0x3477, + 0x7784, 0x1052, 0x326a, 0x9331, 0x6506, 0xa95c, 0x91f3, 0xfb5e}, + {0x2bdd, 0x8df4, 0xcc61, 0x481f, 0xdae5, 0x5ca7, 0xf43b, 0x7d54, + 0x13d6, 0x469b, 0x2294, 0x20f4, 0xb2a4, 0xa2d1, 0x3ff1, 0xfd4b}, + {0xffd8, 0xd9a0, 0x456e, 0x81bb, 0xbabd, 0x6cea, 0x6dbd, 0x73ab, + 0xbb94, 0x3d3c, 0xdf08, 0x31c4, 0x3e32, 0xc179, 0x2486, 0xb86b}}, + /* Test case known to need 589 divsteps, reaching delta=-140 and + delta=141. */ + {{0x3fb1, 0x903b, 0x4eb7, 0x4813, 0xd863, 0x26bf, 0xd89f, 0xa8a9, + 0x02fe, 0x57c6, 0x554a, 0x4eab, 0x165e, 0x3d61, 0xee1e, 0x456c}, + {0x9295, 0x823b, 0x5c1f, 0x5386, 0x48e0, 0x02ff, 0x4c2a, 0xa2da, + 0xe58f, 0x967c, 0xc97e, 0x3f5a, 0x69fb, 0x52d9, 0x0a86, 0xb4a3}, + {0x3d30, 0xb893, 0xa809, 0xa7a8, 0x26f5, 0x5b42, 0x55be, 0xf4d0, + 0x12c2, 0x7e6a, 0xe41a, 0x90c7, 0xebfa, 0xf920, 0x304e, 0x1419}}, + /* Test case known to need 650 divsteps, and doing 65 consecutive (f,g/2) steps. */ + {{0x8583, 0x5058, 0xbeae, 0xeb69, 0x48bc, 0x52bb, 0x6a9d, 0xcc94, + 0x2a21, 0x87d5, 0x5b0d, 0x42f6, 0x5b8a, 0x2214, 0xe9d6, 0xa040}, + {0x7531, 0x27cb, 0x7e53, 0xb739, 0x6a5f, 0x83f5, 0xa45c, 0xcb1d, + 0x8a87, 0x1c9c, 0x51d7, 0x851c, 0xb9d8, 0x1fbe, 0xc241, 0xd4a3}, + {0xcdb4, 0x275c, 0x7d22, 0xa906, 0x0173, 0xc054, 0x7fdf, 0x5005, + 0x7fb8, 0x9059, 0xdf51, 0x99df, 0x2654, 0x8f6e, 0x070f, 0xb347}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xe2e9, 0xee91, 0x4345, 0xe5ad, 0xf3ec, 0x8f42, 0x0364, 0xd5c9, + 0xff49, 0xbef5, 0x4544, 0x4c7c, 0xae4b, 0xfd9d, 0xb35b, 0xda9d}, + {0x36e7, 0x8cca, 0x2ed0, 0x47b3, 0xaca4, 0xb374, 0x7d2a, 0x0772, + 0x6bdb, 0xe0a7, 0x900b, 0xfe10, 0x788c, 0x6f22, 0xd909, 0xf298}, + {0xd8c6, 0xba39, 0x13ed, 0x198c, 0x16c8, 0xb837, 0xa5f2, 0x9797, + 0x0113, 0x882a, 0x15b5, 0x324c, 0xabee, 0xe465, 0x8170, 0x85ac}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xd5b7, 0x2966, 0x040e, 0xf59a, 0x0387, 0xd96d, 0xbfbc, 0xd850, + 0x2d96, 0x872a, 0xad81, 0xc03c, 0xbb39, 0xb7fa, 0xd904, 0xef78}, + {0x6279, 0x4314, 0xfdd3, 0x1568, 0x0982, 0x4d13, 0x625f, 0x010c, + 0x22b1, 0x0cc3, 0xf22d, 0x5710, 0x1109, 0x5751, 0x7714, 0xfcf2}, + {0xdb13, 0x5817, 0x232e, 0xe456, 0xbbbc, 0x6fbe, 0x4572, 0xa358, + 0xc76d, 0x928e, 0x0162, 0x5314, 0x8325, 0x5683, 0xe21b, 0xda88}}, + /* example needing 713 divsteps; delta=-2..3 */ + {{0xa06f, 0x71ee, 0x3bac, 0x9ebb, 0xdeaa, 0x09ed, 0x1cf7, 0x9ec9, + 0x7158, 0x8b72, 0x5d53, 0x5479, 0x5c75, 0xbb66, 0x9125, 0xeccc}, + {0x2941, 0xd46c, 0x3cd4, 0x4a9d, 0x5c4a, 0x256b, 0xbd6c, 0x9b8e, + 0x8fe0, 0x8a14, 0xffe8, 0x2496, 0x618d, 0xa9d7, 0x5018, 0xfb29}, + {0x437c, 0xbd60, 0x7590, 0x94bb, 0x0095, 0xd35e, 0xd4fe, 0xd6da, + 0x0d4e, 0x5342, 0x4cd2, 0x169b, 0x661c, 0x1380, 0xed2d, 0x85c1}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0xfde4, 0x68d6, 0x6c48, 0x7f77, 0x1c78, 0x96de, 0x2fd9, 0xa6c2, + 0xbbb5, 0xd319, 0x69cf, 0xd4b3, 0xa321, 0xcda0, 0x172e, 0xe530}, + {0xd9e3, 0x0f60, 0x3d86, 0xeeab, 0x25ee, 0x9582, 0x2d50, 0xfe16, + 0xd4e2, 0xe3ba, 0x94e2, 0x9833, 0x6c5e, 0x8982, 0x13b6, 0xe598}, + {0xe675, 0xf55a, 0x10f6, 0xabde, 0x5113, 0xecaa, 0x61ae, 0xad9f, + 0x0c27, 0xef33, 0x62e5, 0x211d, 0x08fa, 0xa78d, 0xc675, 0x8bae}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0x21bf, 0x52d5, 0x8fd4, 0xaa18, 0x156a, 0x7247, 0xebb8, 0x5717, + 0x4eb5, 0x1421, 0xb58f, 0x3b0b, 0x5dff, 0xe533, 0xb369, 0xd28a}, + {0x9f6b, 0xe463, 0x2563, 0xc74d, 0x6d81, 0x636a, 0x8fc8, 0x7a94, + 0x9429, 0x1585, 0xf35e, 0x7ff5, 0xb64f, 0x9720, 0xba74, 0xe108}, + {0xa5ab, 0xea7b, 0xfe5e, 0x8a85, 0x13be, 0x7934, 0xe8a0, 0xa187, + 0x86b5, 0xe477, 0xb9a4, 0x75d7, 0x538f, 0xdd70, 0xc781, 0xb67d}}, + /* example reaching delta=-64..65; 661 divsteps */ + {{0xa41a, 0x3e8d, 0xf1f5, 0x9493, 0x868c, 0x5103, 0x2725, 0x3ceb, + 0x6032, 0x3624, 0xdc6b, 0x9120, 0xbf4c, 0x8821, 0x91ad, 0xb31a}, + {0x5c0b, 0xdda5, 0x20f8, 0x32a1, 0xaf73, 0x6ec5, 0x4779, 0x43d6, + 0xd454, 0x9573, 0xbf84, 0x5a58, 0xe04e, 0x307e, 0xd1d5, 0xe230}, + {0xda15, 0xbcd6, 0x7180, 0xabd3, 0x04e6, 0x6986, 0xc0d7, 0x90bb, + 0x3a4d, 0x7c95, 0xaaab, 0x9ab3, 0xda34, 0xa7f6, 0x9636, 0x6273}}, + /* example doing 123 consecutive (f,g/2) steps; 615 divsteps */ + {{0xb4d6, 0xb38f, 0x00aa, 0xebda, 0xd4c2, 0x70b8, 0x9dad, 0x58ee, + 0x68f8, 0x48d3, 0xb5ff, 0xf422, 0x9e46, 0x2437, 0x18d0, 0xd9cc}, + {0x5c83, 0xfed7, 0x97f5, 0x3f07, 0xcaad, 0x95b1, 0xb4a4, 0xb005, + 0x23af, 0xdd27, 0x6c0d, 0x932c, 0xe2b2, 0xe3ae, 0xfb96, 0xdf67}, + {0x3105, 0x0127, 0xfd48, 0x039b, 0x35f1, 0xbc6f, 0x6c0a, 0xb572, + 0xe4df, 0xebad, 0x8edc, 0xb89d, 0x9555, 0x4c26, 0x1fef, 0x997c}}, + /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ + {{0x5138, 0xd474, 0x385f, 0xc964, 0x00f2, 0x6df7, 0x862d, 0xb185, + 0xb264, 0xe9e1, 0x466c, 0xf39e, 0xafaf, 0x5f41, 0x47e2, 0xc89d}, + {0x8607, 0x9c81, 0x46a2, 0x7dcc, 0xcb0c, 0x9325, 0xe149, 0x2bde, + 0x6632, 0x2869, 0xa261, 0xb163, 0xccee, 0x22ae, 0x91e0, 0xcfd5}, + {0x831c, 0xda22, 0xb080, 0xba7a, 0x26e2, 0x54b0, 0x073b, 0x5ea0, + 0xed4b, 0xcb3d, 0xbba1, 0xbec8, 0xf2ad, 0xae0d, 0x349b, 0x17d1}}, + /* example doing 123 consecutive (f,g/2) steps; 614 divsteps */ + {{0xe9a5, 0xb4ad, 0xd995, 0x9953, 0xcdff, 0x50d7, 0xf715, 0x9dc7, + 0x3e28, 0x15a9, 0x95a3, 0x8554, 0x5b5e, 0xad1d, 0x6d57, 0x3d50}, + {0x3ad9, 0xbd60, 0x5cc7, 0x6b91, 0xadeb, 0x71f6, 0x7cc4, 0xa58a, + 0x2cce, 0xf17c, 0x38c9, 0x97ed, 0x65fb, 0x3fa6, 0xa6bc, 0xeb24}, + {0xf96c, 0x1963, 0x8151, 0xa0cc, 0x299b, 0xf277, 0x001a, 0x16bb, + 0xfd2e, 0x532d, 0x0410, 0xe117, 0x6b00, 0x44ec, 0xca6a, 0x1745}}, + /* example doing 446 (f,g/2) steps; 523 divsteps */ + {{0x3758, 0xa56c, 0xe41e, 0x4e47, 0x0975, 0xa82b, 0x107c, 0x89cf, + 0x2093, 0x5a0c, 0xda37, 0xe007, 0x6074, 0x4f68, 0x2f5a, 0xbb8a}, + {0x4beb, 0xa40f, 0x2c42, 0xd9d6, 0x97e8, 0xca7c, 0xd395, 0x894f, + 0x1f50, 0x8067, 0xa233, 0xb850, 0x1746, 0x1706, 0xbcda, 0xdf32}, + {0x762a, 0xceda, 0x4c45, 0x1ca0, 0x8c37, 0xd8c5, 0xef57, 0x7a2c, + 0x6e98, 0xe38a, 0xc50e, 0x2ca9, 0xcb85, 0x24d5, 0xc29c, 0x61f6}}, + /* example doing 446 (f,g/2) steps; 523 divsteps */ + {{0x6f38, 0x74ad, 0x7332, 0x4073, 0x6521, 0xb876, 0xa370, 0xa6bd, + 0xcea5, 0xbd06, 0x969f, 0x77c6, 0x1e69, 0x7c49, 0x7d51, 0xb6e7}, + {0x3f27, 0x4be4, 0xd81e, 0x1396, 0xb21f, 0x92aa, 0x6dc3, 0x6283, + 0x6ada, 0x3ca2, 0xc1e5, 0x8b9b, 0xd705, 0x5598, 0x8ba1, 0xe087}, + {0x6a22, 0xe834, 0xbc8d, 0xcee9, 0x42fc, 0xfc77, 0x9c45, 0x1ca8, + 0xeb66, 0xed74, 0xaaf9, 0xe75f, 0xfe77, 0x46d2, 0x179b, 0xbf3e}}, + /* example doing 336 (f,(f+g)/2) steps; 693 divsteps */ + {{0x7ea7, 0x444e, 0x84ea, 0xc447, 0x7c1f, 0xab97, 0x3de6, 0x5878, + 0x4e8b, 0xc017, 0x03e0, 0xdc40, 0xbbd0, 0x74ce, 0x0169, 0x7ab5}, + {0x4023, 0x154f, 0xfbe4, 0x8195, 0xfda0, 0xef54, 0x9e9a, 0xc703, + 0x2803, 0xf760, 0x6302, 0xed5b, 0x7157, 0x6456, 0xdd7d, 0xf14b}, + {0xb6fb, 0xe3b3, 0x0733, 0xa77e, 0x44c5, 0x3003, 0xc937, 0xdd4d, + 0x5355, 0x14e9, 0x184e, 0xcefe, 0xe6b5, 0xf2e0, 0x0a28, 0x5b74}}, + /* example doing 336 (f,(f+g)/2) steps; 687 divsteps */ + {{0xa893, 0xb5f4, 0x1ede, 0xa316, 0x242c, 0xbdcc, 0xb017, 0x0836, + 0x3a37, 0x27fb, 0xfb85, 0x251e, 0xa189, 0xb15d, 0xa4b8, 0xc24c}, + {0xb0b7, 0x57ba, 0xbb6d, 0x9177, 0xc896, 0xc7f2, 0x43b4, 0x85a6, + 0xe6c4, 0xe50e, 0x3109, 0x7ca5, 0xd73d, 0x13ff, 0x0c3d, 0xcd62}, + {0x48ca, 0xdb34, 0xe347, 0x2cef, 0x4466, 0x10fb, 0x7ee1, 0x6344, + 0x4308, 0x966d, 0xd4d1, 0xb099, 0x994f, 0xd025, 0x2187, 0x5866}}, + /* example doing 267 (g,(g-f)/2) steps; 678 divsteps */ + {{0x0775, 0x1754, 0x01f6, 0xdf37, 0xc0be, 0x8197, 0x072f, 0x6cf5, + 0x8b36, 0x8069, 0x5590, 0xb92d, 0x6084, 0x47a4, 0x23fe, 0xddd5}, + {0x8e1b, 0xda37, 0x27d9, 0x312e, 0x3a2f, 0xef6d, 0xd9eb, 0x8153, + 0xdcba, 0x9fa3, 0x9f80, 0xead5, 0x134d, 0x2ebb, 0x5ec0, 0xe032}, + {0x1cb6, 0x5a61, 0x1bed, 0x77d6, 0xd5d1, 0x7498, 0xef33, 0x2dd2, + 0x1089, 0xedbd, 0x6958, 0x16ae, 0x336c, 0x45e6, 0x4361, 0xbadc}}, + /* example doing 267 (g,(g-f)/2) steps; 676 divsteps */ + {{0x0207, 0xf948, 0xc430, 0xf36b, 0xf0a7, 0x5d36, 0x751f, 0x132c, + 0x6f25, 0xa630, 0xca1f, 0xc967, 0xaf9c, 0x34e7, 0xa38f, 0xbe9f}, + {0x5fb9, 0x7321, 0x6561, 0x5fed, 0x54ec, 0x9c3a, 0xee0e, 0x6717, + 0x49af, 0xb896, 0xf4f5, 0x451c, 0x722a, 0xf116, 0x64a9, 0xcf0b}, + {0xf4d7, 0xdb47, 0xfef2, 0x4806, 0x4cb8, 0x18c7, 0xd9a7, 0x4951, + 0x14d8, 0x5c3a, 0xd22d, 0xd7b2, 0x750c, 0x3de7, 0x8b4a, 0x19aa}}, + + /* Test cases triggering edge cases in divsteps variant starting with delta=1/2 */ + + /* example needing 590 divsteps; delta=-5/2..7/2 */ + {{0x9118, 0xb640, 0x53d7, 0x30ab, 0x2a23, 0xd907, 0x9323, 0x5b3a, + 0xb6d4, 0x538a, 0x7637, 0xfe97, 0xfd05, 0x3cc0, 0x453a, 0xfb7e}, + {0x6983, 0x4f75, 0x4ad1, 0x48ad, 0xb2d9, 0x521d, 0x3dbc, 0x9cc0, + 0x4b60, 0x0ac6, 0xd3be, 0x0fb6, 0xd305, 0x3895, 0x2da5, 0xfdf8}, + {0xcec1, 0x33ac, 0xa801, 0x8194, 0xe36c, 0x65ef, 0x103b, 0xca54, + 0xfa9b, 0xb41d, 0x9b52, 0xb6f7, 0xa611, 0x84aa, 0x3493, 0xbf54}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0xb5f2, 0x42d0, 0x35e8, 0x8ca0, 0x4b62, 0x6e1d, 0xbdf3, 0x890e, + 0x8c82, 0x23d8, 0xc79a, 0xc8e8, 0x789e, 0x353d, 0x9766, 0xea9d}, + {0x6fa1, 0xacba, 0x4b7a, 0x5de1, 0x95d0, 0xc845, 0xebbf, 0x6f5a, + 0x30cf, 0x52db, 0x69b7, 0xe278, 0x4b15, 0x8411, 0x2ab2, 0xf3e7}, + {0xf12c, 0x9d6d, 0x95fa, 0x1878, 0x9f13, 0x4fb5, 0x3c8b, 0xa451, + 0x7182, 0xc4b6, 0x7e2a, 0x7bb7, 0x6e0e, 0x5b68, 0xde55, 0x9927}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0x229c, 0x4ef8, 0x1e93, 0xe5dc, 0xcde5, 0x6d62, 0x263b, 0xad11, + 0xced0, 0x88ff, 0xae8e, 0x3183, 0x11d2, 0xa50b, 0x350d, 0xeb40}, + {0x3157, 0xe2ea, 0x8a02, 0x0aa3, 0x5ae1, 0xb26c, 0xea27, 0x6805, + 0x87e2, 0x9461, 0x37c1, 0x2f8d, 0x85d2, 0x77a8, 0xf805, 0xeec9}, + {0x6f4e, 0x2748, 0xf7e5, 0xd8d3, 0xabe2, 0x7270, 0xc4e0, 0xedc7, + 0xf196, 0x78ca, 0x9139, 0xd8af, 0x72c6, 0xaf2f, 0x85d2, 0x6cd3}}, + /* example needing 590 divsteps; delta=-5/2..7/2 */ + {{0xdce8, 0xf1fe, 0x6708, 0x021e, 0xf1ca, 0xd609, 0x5443, 0x85ce, + 0x7a05, 0x8f9c, 0x90c3, 0x52e7, 0x8e1d, 0x97b8, 0xc0bf, 0xf2a1}, + {0xbd3d, 0xed11, 0x1625, 0xb4c5, 0x844c, 0xa413, 0x2569, 0xb9ba, + 0xcd35, 0xff84, 0xcd6e, 0x7f0b, 0x7d5d, 0x10df, 0x3efe, 0xfbe5}, + {0xa9dd, 0xafef, 0xb1b7, 0x4c8d, 0x50e4, 0xafbf, 0x2d5a, 0xb27c, + 0x0653, 0x66b6, 0x5d36, 0x4694, 0x7e35, 0xc47c, 0x857f, 0x32c5}}, + /* example needing 590 divsteps; delta=-3/2..5/2 */ + {{0x7902, 0xc9f8, 0x926b, 0xaaeb, 0x90f8, 0x1c89, 0xcce3, 0x96b7, + 0x28b2, 0x87a2, 0x136d, 0x695a, 0xa8df, 0x9061, 0x9e31, 0xee82}, + {0xd3a9, 0x3c02, 0x818c, 0x6b81, 0x34b3, 0xebbb, 0xe2c8, 0x7712, + 0xbfd6, 0x8248, 0xa6f4, 0xba6f, 0x03bb, 0xfb54, 0x7575, 0xfe89}, + {0x8246, 0x0d63, 0x478e, 0xf946, 0xf393, 0x0451, 0x08c2, 0x5919, + 0x5fd6, 0x4c61, 0xbeb7, 0x9a15, 0x30e1, 0x55fc, 0x6a01, 0x3724}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0x3eff, 0x926a, 0x77f5, 0x1fff, 0x1a5b, 0xf3ef, 0xf64b, 0x8681, + 0xf800, 0xf9bc, 0x761d, 0xe268, 0x62b0, 0xa032, 0xba9c, 0xbe56}, + {0xb8f9, 0x00e7, 0x47b7, 0xdffc, 0xfd9d, 0x5abb, 0xa19b, 0x1868, + 0x31fd, 0x3b29, 0x3674, 0x5449, 0xf54d, 0x1d19, 0x6ac7, 0xff6f}, + {0xf1d7, 0x3551, 0x5682, 0x9adf, 0xe8aa, 0x19a5, 0x8340, 0x71db, + 0xb7ab, 0x4cfd, 0xf661, 0x632c, 0xc27e, 0xd3c6, 0xdf42, 0xd306}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x3aff, 0x2ed7, 0xf2e0, 0xabc7, + 0x8aee, 0x166e, 0x7ed0, 0x9ac7, 0x714a, 0xb9c5, 0x4d58, 0xad6c}, + {0x9cf9, 0x47e2, 0xa421, 0xb277, 0xffc2, 0x2747, 0x6486, 0x94c1, + 0x1d99, 0xd49b, 0x1096, 0x991a, 0xe986, 0xae02, 0xe89b, 0xea36}, + {0x1fb4, 0x98d8, 0x19b7, 0x80e9, 0xcdac, 0xaa5a, 0xf1e6, 0x0074, + 0xe393, 0xed8b, 0x8d5c, 0xe17d, 0x81b3, 0xc16d, 0x54d3, 0x9be3}}, + /* example reaching delta=-127/2..129/2; 571 divsteps */ + {{0xd047, 0x7e36, 0x3157, 0x7ab6, 0xb4d9, 0x8dae, 0x7534, 0x4f5d, + 0x489e, 0xa8ab, 0x8a3d, 0xd52c, 0x62af, 0xa032, 0xba9c, 0xbe56}, + {0xb1f1, 0x737f, 0x5964, 0x5afb, 0x3712, 0x8ef9, 0x19f7, 0x9669, + 0x664d, 0x03ad, 0xc352, 0xf7a5, 0xf545, 0x1d19, 0x6ac7, 0xff6f}, + {0xa834, 0x5256, 0x27bc, 0x33bd, 0xba11, 0x5a7b, 0x791e, 0xe6c0, + 0x9ac4, 0x9370, 0x1130, 0x28b4, 0x2b2e, 0x231b, 0x082a, 0x796e}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0x6ab1, 0x6ea0, 0x1a99, 0xe0c2, 0xdd45, 0x645d, 0x8dbc, 0x466a, + 0xfa64, 0x4289, 0xd3f7, 0xfc8f, 0x2894, 0xe3c5, 0xa008, 0xcc14}, + {0xc75f, 0xc083, 0x4cc2, 0x64f2, 0x2aff, 0x4c12, 0x8461, 0xc4ae, + 0xbbfa, 0xb336, 0xe4b2, 0x3ac5, 0x2c22, 0xf56c, 0x5381, 0xe943}, + {0xcd80, 0x760d, 0x4395, 0xb3a6, 0xd497, 0xf583, 0x82bd, 0x1daa, + 0xbe92, 0x2613, 0xfdfb, 0x869b, 0x0425, 0xa333, 0x7056, 0xc9c5}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0x71d4, 0x64df, 0xec4f, 0x74d8, 0x7e0c, 0x40d3, 0x7073, 0x4cc8, + 0x2a2a, 0xb1ff, 0x8518, 0x6513, 0xb0ea, 0x640a, 0x62d9, 0xd5f4}, + {0xdc75, 0xd937, 0x3b13, 0x1d36, 0xdf83, 0xd034, 0x1c1c, 0x4332, + 0x4cc3, 0xeeec, 0x7d94, 0x6771, 0x3384, 0x74b0, 0x947d, 0xf2c4}, + {0x0a82, 0x37a4, 0x12d5, 0xec97, 0x972c, 0xe6bf, 0xc348, 0xa0a9, + 0xc50c, 0xdc7c, 0xae30, 0x19d1, 0x0fca, 0x35e1, 0xd6f6, 0x81ee}}, + /* example doing 123 consecutive (f,g/2) steps; 554 divsteps */ + {{0xa6b1, 0xabc5, 0x5bbc, 0x7f65, 0xdd32, 0xaa73, 0xf5a3, 0x1982, + 0xced4, 0xe949, 0x0fd6, 0x2bc4, 0x2bd7, 0xe3c5, 0xa008, 0xcc14}, + {0x4b5f, 0x8f96, 0xa375, 0xfbcf, 0x1c7d, 0xf1ec, 0x03f5, 0xb35d, + 0xb999, 0xdb1f, 0xc9a1, 0xb4c7, 0x1dd5, 0xf56c, 0x5381, 0xe943}, + {0xaa3d, 0x38b9, 0xf17d, 0xeed9, 0x9988, 0x69ee, 0xeb88, 0x1495, + 0x203f, 0x18c8, 0x82b7, 0xdcb2, 0x34a7, 0x6b00, 0x6998, 0x589a}}, + /* example doing 453 (f,g/2) steps; 514 divsteps */ + {{0xa478, 0xe60d, 0x3244, 0x60e6, 0xada3, 0xfe50, 0xb6b1, 0x2eae, + 0xd0ef, 0xa7b1, 0xef63, 0x05c0, 0xe213, 0x443e, 0x4427, 0x2448}, + {0x258f, 0xf9ef, 0xe02b, 0x92dd, 0xd7f3, 0x252b, 0xa503, 0x9089, + 0xedff, 0x96c1, 0xfe3a, 0x3a39, 0x198a, 0x981d, 0x0627, 0xedb7}, + {0x595a, 0x45be, 0x8fb0, 0x2265, 0xc210, 0x02b8, 0xdce9, 0xe241, + 0xcab6, 0xbf0d, 0x0049, 0x8d9a, 0x2f51, 0xae54, 0x5785, 0xb411}}, + /* example doing 453 (f,g/2) steps; 514 divsteps */ + {{0x48f0, 0x7db3, 0xdafe, 0x1c92, 0x5912, 0xe11a, 0xab52, 0xede1, + 0x3182, 0x8980, 0x5d2b, 0x9b5b, 0x8718, 0xda27, 0x1683, 0x1de2}, + {0x168f, 0x6f36, 0xce7a, 0xf435, 0x19d4, 0xda5e, 0x2351, 0x9af5, + 0xb003, 0x0ef5, 0x3b4c, 0xecec, 0xa9f0, 0x78e1, 0xdfef, 0xe823}, + {0x5f55, 0xfdcc, 0xb233, 0x2914, 0x84f0, 0x97d1, 0x9cf4, 0x2159, + 0xbf56, 0xb79c, 0x17a3, 0x7cef, 0xd5de, 0x34f0, 0x5311, 0x4c54}}, + /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ + {{0x2789, 0x2e04, 0x6e0e, 0xb6cd, 0xe4de, 0x4dbf, 0x228d, 0x7877, + 0xc335, 0x806b, 0x38cd, 0x8049, 0xa73b, 0xcfa2, 0x82f7, 0x9e19}, + {0xc08d, 0xb99d, 0xb8f3, 0x663d, 0xbbb3, 0x1284, 0x1485, 0x1d49, + 0xc98f, 0x9e78, 0x1588, 0x11e3, 0xd91a, 0xa2c7, 0xfff1, 0xc7b9}, + {0x1e1f, 0x411d, 0x7c49, 0x0d03, 0xe789, 0x2f8e, 0x5d55, 0xa95e, + 0x826e, 0x8de5, 0x52a0, 0x1abc, 0x4cd7, 0xd13a, 0x4395, 0x63e1}}, + /* example doing 510 (f,(f+g)/2) steps; 512 divsteps */ + {{0xd5a1, 0xf786, 0x555c, 0xb14b, 0x44ae, 0x535f, 0x4a49, 0xffc3, + 0xf497, 0x70d1, 0x57c8, 0xa933, 0xc85a, 0x1910, 0x75bf, 0x960b}, + {0xfe53, 0x5058, 0x496d, 0xfdff, 0x6fb8, 0x4100, 0x92bd, 0xe0c4, + 0xda89, 0xe0a4, 0x841b, 0x43d4, 0xa388, 0x957f, 0x99ca, 0x9abf}, + {0xe530, 0x05bc, 0xfeec, 0xfc7e, 0xbcd3, 0x1239, 0x54cb, 0x7042, + 0xbccb, 0x139e, 0x9076, 0x0203, 0x6068, 0x90c7, 0x1ddf, 0x488d}}, + /* example doing 228 (g,(g-f)/2) steps; 538 divsteps */ + {{0x9488, 0xe54b, 0x0e43, 0x81d2, 0x06e7, 0x4b66, 0x36d0, 0x53d6, + 0x2b68, 0x22ec, 0x3fa9, 0xc1a7, 0x9ad2, 0xa596, 0xb3ac, 0xdf42}, + {0xe31f, 0x0b28, 0x5f3b, 0xc1ff, 0x344c, 0xbf5f, 0xd2ec, 0x2936, + 0x9995, 0xdeb2, 0xae6c, 0x2852, 0xa2c6, 0xb306, 0x8120, 0xe305}, + {0xa56e, 0xfb98, 0x1537, 0x4d85, 0x619e, 0x866c, 0x3cd4, 0x779a, + 0xdd66, 0xa80d, 0xdc2f, 0xcae4, 0xc74c, 0x5175, 0xa65d, 0x605e}}, + /* example doing 228 (g,(g-f)/2) steps; 537 divsteps */ + {{0x8cd5, 0x376d, 0xd01b, 0x7176, 0x19ef, 0xcf09, 0x8403, 0x5e52, + 0x83c1, 0x44de, 0xb91e, 0xb33d, 0xe15c, 0x51e7, 0xbad8, 0x6359}, + {0x3b75, 0xf812, 0x5f9e, 0xa04e, 0x92d3, 0x226e, 0x540e, 0x7c9a, + 0x31c6, 0x46d2, 0x0b7b, 0xdb4a, 0xe662, 0x4950, 0x0265, 0xf76f}, + {0x09ed, 0x692f, 0xe8f1, 0x3482, 0xab54, 0x36b4, 0x8442, 0x6ae9, + 0x4329, 0x6505, 0x183b, 0x1c1d, 0x482d, 0x7d63, 0xb44f, 0xcc09}}, + + /* Test cases with the group order as modulus. */ + + /* Test case with the group order as modulus, needing 635 divsteps. */ + {{0x95ed, 0x6c01, 0xd113, 0x5ff1, 0xd7d0, 0x29cc, 0x5817, 0x6120, + 0xca8e, 0xaad1, 0x25ae, 0x8e84, 0x9af6, 0x30bf, 0xf0ed, 0x1686}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x1631, 0xbf4a, 0x286a, 0x2716, 0x469f, 0x2ac8, 0x1312, 0xe9bc, + 0x04f4, 0x304b, 0x9931, 0x113b, 0xd932, 0xc8f4, 0x0d0d, 0x01a1}}, + /* example with group size as modulus needing 631 divsteps */ + {{0x85ed, 0xc284, 0x9608, 0x3c56, 0x19b6, 0xbb5b, 0x2850, 0xdab7, + 0xa7f5, 0xe9ab, 0x06a4, 0x5bbb, 0x1135, 0xa186, 0xc424, 0xc68b}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x8479, 0x450a, 0x8fa3, 0xde05, 0xb2f5, 0x7793, 0x7269, 0xbabb, + 0xc3b3, 0xd49b, 0x3377, 0x03c6, 0xe694, 0xc760, 0xd3cb, 0x2811}}, + /* example with group size as modulus needing 565 divsteps starting at delta=1/2 */ + {{0x8432, 0x5ceb, 0xa847, 0x6f1e, 0x51dd, 0x535a, 0x6ddc, 0x70ce, + 0x6e70, 0xc1f6, 0x18f2, 0x2a7e, 0xc8e7, 0x39f8, 0x7e96, 0xebbf}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x257e, 0x449f, 0x689f, 0x89aa, 0x3989, 0xb661, 0x376c, 0x1e32, + 0x654c, 0xee2e, 0xf4e2, 0x33c8, 0x3f2f, 0x9716, 0x6046, 0xcaa3}}, + /* Test case with the group size as modulus, needing 981 divsteps with + broken eta handling. */ + {{0xfeb9, 0xb877, 0xee41, 0x7fa3, 0x87da, 0x94c4, 0x9d04, 0xc5ae, + 0x5708, 0x0994, 0xfc79, 0x0916, 0xbf32, 0x3ad8, 0xe11c, 0x5ca2}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0f12, 0x075e, 0xce1c, 0x6f92, 0xc80f, 0xca92, 0x9a04, 0x6126, + 0x4b6c, 0x57d6, 0xca31, 0x97f3, 0x1f99, 0xf4fd, 0xda4d, 0x42ce}}, + /* Test case with the group size as modulus, input = 0. */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the group size as modulus, input = 1. */ + {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the group size as modulus, input = 2. */ + {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x20a1, 0x681b, 0x2f46, 0xdfe9, 0x501d, 0x57a4, 0x6e73, 0x5d57, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, + /* Test case with the group size as modulus, input = group - 1. */ + {{0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x4141, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x4140, 0xd036, 0x5e8c, 0xbfd2, 0xa03b, 0xaf48, 0xdce6, 0xbaae, + 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, + + /* Test cases with the field size as modulus. */ + + /* Test case with the field size as modulus, needing 637 divsteps. */ + {{0x9ec3, 0x1919, 0xca84, 0x7c11, 0xf996, 0x06f3, 0x5408, 0x6688, + 0x1320, 0xdb8a, 0x632a, 0x0dcb, 0x8a84, 0x6bee, 0x9c95, 0xe34e}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x18e5, 0x19b6, 0xdf92, 0x1aaa, 0x09fb, 0x8a3f, 0x52b0, 0x8701, + 0xac0c, 0x2582, 0xda44, 0x9bcc, 0x6828, 0x1c53, 0xbd8f, 0xbd2c}}, + /* example with field size as modulus needing 637 divsteps */ + {{0xaec3, 0xa7cf, 0x2f2d, 0x0693, 0x5ad5, 0xa8ff, 0x7ec7, 0x30ff, + 0x0c8b, 0xc242, 0xcab2, 0x063a, 0xf86e, 0x6057, 0x9cbd, 0xf6d8}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0310, 0x579d, 0xcb38, 0x9030, 0x3ded, 0x9bb9, 0x1234, 0x63ce, + 0x0c63, 0x8e3d, 0xacfe, 0x3c20, 0xdc85, 0xf859, 0x919e, 0x1d45}}, + /* example with field size as modulus needing 564 divsteps starting at delta=1/2 */ + {{0x63ae, 0x8d10, 0x0071, 0xdb5c, 0xb454, 0x78d1, 0x744a, 0x5f8e, + 0xe4d8, 0x87b1, 0x8e62, 0x9590, 0xcede, 0xa070, 0x36b4, 0x7f6f}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfdc8, 0xe8d5, 0xbe15, 0x9f86, 0xa5fe, 0xf18e, 0xa7ff, 0xd291, + 0xf4c2, 0x9c87, 0xf150, 0x073e, 0x69b8, 0xf7c4, 0xee4b, 0xc7e6}}, + /* Test case with the field size as modulus, needing 935 divsteps with + broken eta handling. */ + {{0x1b37, 0xbdc3, 0x8bcd, 0x25e3, 0x1eae, 0x567d, 0x30b6, 0xf0d8, + 0x9277, 0x0cf8, 0x9c2e, 0xecd7, 0x631d, 0xe38f, 0xd4f8, 0x5c93}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x1622, 0xe05b, 0xe880, 0x7de9, 0x3e45, 0xb682, 0xee6c, 0x67ed, + 0xa179, 0x15db, 0x6b0d, 0xa656, 0x7ccb, 0x8ef7, 0xa2ff, 0xe279}}, + /* Test case with the field size as modulus, input = 0. */ + {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the field size as modulus, input = 1. */ + {{0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}}, + /* Test case with the field size as modulus, input = 2. */ + {{0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfe18, 0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x7fff}}, + /* Test case with the field size as modulus, input = field - 1. */ + {{0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {0xfc2e, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}}, + + /* Selected from a large number of random inputs to reach small/large + * d/e values in various configurations. */ + {{0x3a08, 0x23e1, 0x4d8c, 0xe606, 0x3263, 0x67af, 0x9bf1, 0x9d70, + 0xf5fd, 0x12e4, 0x03c8, 0xb9ca, 0xe847, 0x8c5d, 0x6322, 0xbd30}, + {0x8359, 0x59dd, 0x1831, 0x7c1a, 0x1e83, 0xaee1, 0x770d, 0xcea8, + 0xfbb1, 0xeed6, 0x10b5, 0xe2c6, 0x36ea, 0xee17, 0xe32c, 0xffff}, + {0x1727, 0x0f36, 0x6f85, 0x5d0c, 0xca6c, 0x3072, 0x9628, 0x5842, + 0xcb44, 0x7c2b, 0xca4f, 0x62e5, 0x29b1, 0x6ffd, 0x9055, 0xc196}}, + {{0x905d, 0x41c8, 0xa2ff, 0x295b, 0x72bb, 0x4679, 0x6d01, 0x2c98, + 0xb3e0, 0xc537, 0xa310, 0xe07e, 0xe72f, 0x4999, 0x1148, 0xf65e}, + {0x5b41, 0x4239, 0x3c37, 0x5130, 0x30e3, 0xff35, 0xc51f, 0x1a43, + 0xdb23, 0x13cf, 0x9f49, 0xf70c, 0x5e70, 0xd411, 0x3005, 0xf8c6}, + {0xc30e, 0x68f0, 0x201a, 0xe10c, 0x864a, 0x6243, 0xe946, 0x43ae, + 0xf3f1, 0x52dc, 0x1f7f, 0x50d4, 0x2797, 0x064c, 0x5ca4, 0x90e3}}, + {{0xf1b5, 0xc6e5, 0xd2c4, 0xff95, 0x27c5, 0x0c92, 0x5d19, 0x7ae5, + 0x4fbe, 0x5438, 0x99e1, 0x880d, 0xd892, 0xa05c, 0x6ffd, 0x7eac}, + {0x2153, 0xcc9d, 0xfc6c, 0x8358, 0x49a1, 0x01e2, 0xcef0, 0x4969, + 0xd69a, 0x8cef, 0xf5b2, 0xfd95, 0xdcc2, 0x71f4, 0x6ae2, 0xceeb}, + {0x9b2e, 0xcdc6, 0x0a5c, 0x7317, 0x9084, 0xe228, 0x56cf, 0xd512, + 0x628a, 0xce21, 0x3473, 0x4e13, 0x8823, 0x1ed0, 0x34d0, 0xbfa3}}, + {{0x5bae, 0x53e5, 0x5f4d, 0x21ca, 0xb875, 0x8ecf, 0x9aa6, 0xbe3c, + 0x9f96, 0x7b82, 0x375d, 0x4d3e, 0x491c, 0xb1eb, 0x04c9, 0xb6c8}, + {0xfcfd, 0x10b7, 0x73b2, 0xd23b, 0xa357, 0x67da, 0x0d9f, 0x8702, + 0xa037, 0xff8e, 0x0e8b, 0x1801, 0x2c5c, 0x4e6e, 0x4558, 0xfff2}, + {0xc50f, 0x5654, 0x6713, 0x5ef5, 0xa7ce, 0xa647, 0xc832, 0x69ce, + 0x1d5c, 0x4310, 0x0746, 0x5a01, 0x96ea, 0xde4b, 0xa88b, 0x5543}}, + {{0xdc7f, 0x5e8c, 0x89d1, 0xb077, 0xd521, 0xcf90, 0x32fa, 0x5737, + 0x839e, 0x1464, 0x007c, 0x09c6, 0x9371, 0xe8ea, 0xc1cb, 0x75c4}, + {0xe3a3, 0x107f, 0xa82a, 0xa375, 0x4578, 0x60f4, 0x75c9, 0x5ee4, + 0x3fd7, 0x2736, 0x2871, 0xd3d2, 0x5f1d, 0x1abb, 0xa764, 0xffff}, + {0x45c6, 0x1f2e, 0xb14c, 0x84d7, 0x7bb7, 0x5a04, 0x0504, 0x3f33, + 0x5cc1, 0xb07a, 0x6a6c, 0x786f, 0x647f, 0xe1d7, 0x78a2, 0x4cf4}}, + {{0xc006, 0x356f, 0x8cd2, 0x967b, 0xb49e, 0x2d4e, 0x14bf, 0x4bcb, + 0xddab, 0xd3f9, 0xa068, 0x2c1c, 0xd242, 0xa56d, 0xf2c7, 0x5f97}, + {0x465b, 0xb745, 0x0e0d, 0x69a9, 0x987d, 0xcb37, 0xf637, 0xb311, + 0xc4d6, 0x2ddb, 0xf68f, 0x2af9, 0x959d, 0x3f53, 0x98f2, 0xf640}, + {0xc0f2, 0x6bfb, 0xf5c3, 0x91c1, 0x6b05, 0x0825, 0x5ca0, 0x7df7, + 0x9d55, 0x6d9e, 0xfe94, 0x2ad9, 0xd9f0, 0xe68b, 0xa72b, 0xd1b2}}, + {{0x2279, 0x61ba, 0x5bc6, 0x136b, 0xf544, 0x717c, 0xafda, 0x02bd, + 0x79af, 0x1fad, 0xea09, 0x81bb, 0x932b, 0x32c9, 0xdf1d, 0xe576}, + {0x8215, 0x7817, 0xca82, 0x43b0, 0x9b06, 0xea65, 0x1291, 0x0621, + 0x0089, 0x46fe, 0xc5a6, 0xddd7, 0x8065, 0xc6a0, 0x214b, 0xfc64}, + {0x04bf, 0x6f2a, 0x86b2, 0x841a, 0x4a95, 0xc632, 0x97b7, 0x5821, + 0x2b18, 0x1bb0, 0x3e97, 0x935e, 0xcc7d, 0x066b, 0xd513, 0xc251}}, + {{0x76e8, 0x5bc2, 0x3eaa, 0x04fc, 0x9974, 0x92c1, 0x7c15, 0xfa89, + 0x1151, 0x36ee, 0x48b2, 0x049c, 0x5f16, 0xcee4, 0x925b, 0xe98e}, + {0x913f, 0x0a2d, 0xa185, 0x9fea, 0xda5a, 0x4025, 0x40d7, 0x7cfa, + 0x88ca, 0xbbe8, 0xb265, 0xb7e4, 0x6cb1, 0xed64, 0xc6f9, 0xffb5}, + {0x6ab1, 0x1a86, 0x5009, 0x152b, 0x1cc4, 0xe2c8, 0x960b, 0x19d0, + 0x3554, 0xc562, 0xd013, 0xcf91, 0x10e1, 0x7933, 0xe195, 0xcf49}}, + {{0x9cb5, 0xd2d7, 0xc6ed, 0xa818, 0xb495, 0x06ee, 0x0f4a, 0x06e3, + 0x4c5a, 0x80ce, 0xd49a, 0x4cd7, 0x7487, 0x92af, 0xe516, 0x676c}, + {0xd6e9, 0x6b85, 0x619a, 0xb52c, 0x20a0, 0x2f79, 0x3545, 0x1edd, + 0x5a6f, 0x8082, 0x9b80, 0xf8f8, 0xc78a, 0xd0a3, 0xadf4, 0xffff}, + {0x01c2, 0x2118, 0xef5e, 0xa877, 0x046a, 0xd2c2, 0x2ad5, 0x951c, + 0x8900, 0xa5c9, 0x8d0f, 0x6b61, 0x55d3, 0xd572, 0x48de, 0x9219}}, + {{0x5114, 0x0644, 0x23dd, 0x01d3, 0xc101, 0xa659, 0xea17, 0x640f, + 0xf767, 0x2644, 0x9cec, 0xd8ba, 0xd6da, 0x9156, 0x8aeb, 0x875a}, + {0xc1bf, 0xdae9, 0xe96b, 0xce77, 0xf7a1, 0x3e99, 0x5c2e, 0x973b, + 0xd048, 0x5bd0, 0x4e8a, 0xcb85, 0xce39, 0x37f5, 0x815d, 0xffff}, + {0x48cc, 0x35b6, 0x26d4, 0x2ea6, 0x50d6, 0xa2f9, 0x64b6, 0x03bf, + 0xd00c, 0xe057, 0x3343, 0xfb79, 0x3ce5, 0xf717, 0xc5af, 0xe185}}, + {{0x13ff, 0x6c76, 0x2077, 0x16e0, 0xd5ca, 0xf2ad, 0x8dba, 0x8f49, + 0x7887, 0x16f9, 0xb646, 0xfc87, 0xfa31, 0x5096, 0xf08c, 0x3fbe}, + {0x8139, 0x6fd7, 0xf6df, 0xa7bf, 0x6699, 0x5361, 0x6f65, 0x13c8, + 0xf4d1, 0xe28f, 0xc545, 0x0a8c, 0x5274, 0xb0a6, 0xffff, 0xffff}, + {0x22ca, 0x0cd6, 0xc1b5, 0xb064, 0x44a7, 0x297b, 0x495f, 0x34ac, + 0xfa95, 0xec62, 0xf08d, 0x621c, 0x66a6, 0xba94, 0x84c6, 0x8ee0}}, + {{0xaa30, 0x312e, 0x439c, 0x4e88, 0x2e2f, 0x32dc, 0xb880, 0xa28e, + 0xf795, 0xc910, 0xb406, 0x8dd7, 0xb187, 0xa5a5, 0x38f1, 0xe49e}, + {0xfb19, 0xf64a, 0xba6a, 0x8ec2, 0x7255, 0xce89, 0x2cf9, 0x9cba, + 0xe1fe, 0x50da, 0x1705, 0xac52, 0xe3d4, 0x4269, 0x0648, 0xfd77}, + {0xb4c8, 0x6e8a, 0x2b5f, 0x4c2d, 0x5a67, 0xa7bb, 0x7d6d, 0x5569, + 0xa0ea, 0x244a, 0xc0f2, 0xf73d, 0x58cf, 0xac7f, 0xd32b, 0x3018}}, + {{0xc953, 0x1ae1, 0xae46, 0x8709, 0x19c2, 0xa986, 0x9abe, 0x1611, + 0x0395, 0xd5ab, 0xf0f6, 0xb5b0, 0x5b2b, 0x0317, 0x80ba, 0x376d}, + {0xfe77, 0xbc03, 0xac2f, 0x9d00, 0xa175, 0x293d, 0x3b56, 0x0e3a, + 0x0a9c, 0xf40c, 0x690e, 0x1508, 0x95d4, 0xddc4, 0xe805, 0xffff}, + {0xb1ce, 0x0929, 0xa5fe, 0x4b50, 0x9d5d, 0x8187, 0x2557, 0x4376, + 0x11ba, 0xdcef, 0xc1f3, 0xd531, 0x1824, 0x93f6, 0xd81f, 0x8f83}}, + {{0xb8d2, 0xb900, 0x4a0c, 0x7188, 0xa5bf, 0x1b0b, 0x2ae5, 0xa35b, + 0x98e0, 0x610c, 0x86db, 0x2487, 0xa267, 0x002c, 0xebb6, 0xc5f4}, + {0x9cdd, 0x1c1b, 0x2f06, 0x43d1, 0xce47, 0xc334, 0x6e60, 0xc016, + 0x989e, 0x0ab2, 0x0cac, 0x1196, 0xe2d9, 0x2e04, 0xc62b, 0xffff}, + {0xdc36, 0x1f05, 0x6aa9, 0x7a20, 0x944f, 0x2fd3, 0xa553, 0xdb4f, + 0xbd5c, 0x3a75, 0x25d4, 0xe20e, 0xa387, 0x1410, 0xdbb1, 0x1b60}}, + {{0x76b3, 0x2207, 0x4930, 0x5dd7, 0x65a0, 0xd55c, 0xb443, 0x53b7, + 0x5c22, 0x818a, 0xb2e7, 0x9de8, 0x9985, 0xed45, 0x33b1, 0x53e8}, + {0x7913, 0x44e1, 0xf15b, 0x5edd, 0x34f3, 0x4eba, 0x0758, 0x7104, + 0x32d9, 0x28f3, 0x4401, 0x85c5, 0xb695, 0xb899, 0xc0f2, 0xffff}, + {0x7f43, 0xd202, 0x24c9, 0x69f3, 0x74dc, 0x1a69, 0xeaee, 0x5405, + 0x1755, 0x4bb8, 0x04e3, 0x2fd2, 0xada8, 0x39eb, 0x5b4d, 0x96ca}}, + {{0x807b, 0x7112, 0xc088, 0xdafd, 0x02fa, 0x9d95, 0x5e42, 0xc033, + 0xde0a, 0xeecf, 0x8e90, 0x8da1, 0xb17e, 0x9a5b, 0x4c6d, 0x1914}, + {0x4871, 0xd1cb, 0x47d7, 0x327f, 0x09ec, 0x97bb, 0x2fae, 0xd346, + 0x6b78, 0x3707, 0xfeb2, 0xa6ab, 0x13df, 0x76b0, 0x8fb9, 0xffb3}, + {0x179e, 0xb63b, 0x4784, 0x231e, 0x9f42, 0x7f1a, 0xa3fb, 0xdd8c, + 0xd1eb, 0xb4c9, 0x8ca7, 0x018c, 0xf691, 0x576c, 0xa7d6, 0xce27}}, + {{0x5f45, 0x7c64, 0x083d, 0xedd5, 0x08a0, 0x0c64, 0x6c6f, 0xec3c, + 0xe2fb, 0x352c, 0x9303, 0x75e4, 0xb4e0, 0x8b09, 0xaca4, 0x7025}, + {0x1025, 0xb482, 0xfed5, 0xa678, 0x8966, 0x9359, 0x5329, 0x98bb, + 0x85b2, 0x73ba, 0x9982, 0x6fdc, 0xf190, 0xbe8c, 0xdc5c, 0xfd93}, + {0x83a2, 0x87a4, 0xa680, 0x52a1, 0x1ba1, 0x8848, 0x5db7, 0x9744, + 0x409c, 0x0745, 0x0e1e, 0x1cfc, 0x00cd, 0xf573, 0x2071, 0xccaa}}, + {{0xf61f, 0x63d4, 0x536c, 0x9eb9, 0x5ddd, 0xbb11, 0x9014, 0xe904, + 0xfe01, 0x6b45, 0x1858, 0xcb5b, 0x4c38, 0x43e1, 0x381d, 0x7f94}, + {0xf61f, 0x63d4, 0xd810, 0x7ca3, 0x8a04, 0x4b83, 0x11fc, 0xdf94, + 0x4169, 0xbd05, 0x608e, 0x7151, 0x4fbf, 0xb31a, 0x38a7, 0xa29b}, + {0xe621, 0xdfa5, 0x3d06, 0x1d03, 0x81e6, 0x00da, 0x53a6, 0x965e, + 0x93e5, 0x2164, 0x5b61, 0x59b8, 0xa629, 0x8d73, 0x699a, 0x6111}}, + {{0x4cc3, 0xd29e, 0xf4a3, 0x3428, 0x2048, 0xeec9, 0x5f50, 0x99a4, + 0x6de9, 0x05f2, 0x5aa9, 0x5fd2, 0x98b4, 0x1adc, 0x225f, 0x777f}, + {0xe649, 0x37da, 0x5ba6, 0x5765, 0x3f4a, 0x8a1c, 0x2e79, 0xf550, + 0x1a54, 0xcd1e, 0x7218, 0x3c3c, 0x6311, 0xfe28, 0x95fb, 0xed97}, + {0xe9b6, 0x0c47, 0x3f0e, 0x849b, 0x11f8, 0xe599, 0x5e4d, 0xd618, + 0xa06d, 0x33a0, 0x9a3e, 0x44db, 0xded8, 0x10f0, 0x94d2, 0x81fb}}, + {{0x2e59, 0x7025, 0xd413, 0x455a, 0x1ce3, 0xbd45, 0x7263, 0x27f7, + 0x23e3, 0x518e, 0xbe06, 0xc8c4, 0xe332, 0x4276, 0x68b4, 0xb166}, + {0x596f, 0x0cf6, 0xc8ec, 0x787b, 0x04c1, 0x473c, 0xd2b8, 0x8d54, + 0x9cdf, 0x77f2, 0xd3f3, 0x6735, 0x0638, 0xf80e, 0x9467, 0xc6aa}, + {0xc7e7, 0x1822, 0xb62a, 0xec0d, 0x89cd, 0x7846, 0xbfa2, 0x35d5, + 0xfa38, 0x870f, 0x494b, 0x1697, 0x8b17, 0xf904, 0x10b6, 0x9822}}, + {{0x6d5b, 0x1d4f, 0x0aaf, 0x807b, 0x35fb, 0x7ee8, 0x00c6, 0x059a, + 0xddf0, 0x1fb1, 0xc38a, 0xd78e, 0x2aa4, 0x79e7, 0xad28, 0xc3f1}, + {0xe3bb, 0x174e, 0xe0a8, 0x74b6, 0xbd5b, 0x35f6, 0x6d23, 0x6328, + 0xc11f, 0x83e1, 0xf928, 0xa918, 0x838e, 0xbf43, 0xe243, 0xfffb}, + {0x9cf2, 0x6b8b, 0x3476, 0x9d06, 0xdcf2, 0xdb8a, 0x89cd, 0x4857, + 0x75c2, 0xabb8, 0x490b, 0xc9bd, 0x890e, 0xe36e, 0xd552, 0xfffa}}, + {{0x2f09, 0x9d62, 0xa9fc, 0xf090, 0xd6d1, 0x9d1d, 0x1828, 0xe413, + 0xc92b, 0x3d5a, 0x1373, 0x368c, 0xbaf2, 0x2158, 0x71eb, 0x08a3}, + {0x2f09, 0x1d62, 0x4630, 0x0de1, 0x06dc, 0xf7f1, 0xc161, 0x1e92, + 0x7495, 0x97e4, 0x94b6, 0xa39e, 0x4f1b, 0x18f8, 0x7bd4, 0x0c4c}, + {0xeb3d, 0x723d, 0x0907, 0x525b, 0x463a, 0x49a8, 0xc6b8, 0xce7f, + 0x740c, 0x0d7d, 0xa83b, 0x457f, 0xae8e, 0xc6af, 0xd331, 0x0475}}, + {{0x6abd, 0xc7af, 0x3e4e, 0x95fd, 0x8fc4, 0xee25, 0x1f9c, 0x0afe, + 0x291d, 0xcde0, 0x48f4, 0xb2e8, 0xf7af, 0x8f8d, 0x0bd6, 0x078d}, + {0x4037, 0xbf0e, 0x2081, 0xf363, 0x13b2, 0x381e, 0xfb6e, 0x818e, + 0x27e4, 0x5662, 0x18b0, 0x0cd2, 0x81f5, 0x9415, 0x0d6c, 0xf9fb}, + {0xd205, 0x0981, 0x0498, 0x1f08, 0xdb93, 0x1732, 0x0579, 0x1424, + 0xad95, 0x642f, 0x050c, 0x1d6d, 0xfc95, 0xfc4a, 0xd41b, 0x3521}}, + {{0xf23a, 0x4633, 0xaef4, 0x1a92, 0x3c8b, 0x1f09, 0x30f3, 0x4c56, + 0x2a2f, 0x4f62, 0xf5e4, 0x8329, 0x63cc, 0xb593, 0xec6a, 0xc428}, + {0x93a7, 0xfcf6, 0x606d, 0xd4b2, 0x2aad, 0x28b4, 0xc65b, 0x8998, + 0x4e08, 0xd178, 0x0900, 0xc82b, 0x7470, 0xa342, 0x7c0f, 0xffff}, + {0x315f, 0xf304, 0xeb7b, 0xe5c3, 0x1451, 0x6311, 0x8f37, 0x93a8, + 0x4a38, 0xa6c6, 0xe393, 0x1087, 0x6301, 0xd673, 0x4ec4, 0xffff}}, + {{0x892e, 0xeed0, 0x1165, 0xcbc1, 0x5545, 0xa280, 0x7243, 0x10c9, + 0x9536, 0x36af, 0xb3fc, 0x2d7c, 0xe8a5, 0x09d6, 0xe1d4, 0xe85d}, + {0xae09, 0xc28a, 0xd777, 0xbd80, 0x23d6, 0xf980, 0xeb7c, 0x4e0e, + 0xf7dc, 0x6475, 0xf10a, 0x2d33, 0x5dfd, 0x797a, 0x7f1c, 0xf71a}, + {0x4064, 0x8717, 0xd091, 0x80b0, 0x4527, 0x8442, 0xac8b, 0x9614, + 0xc633, 0x35f5, 0x7714, 0x2e83, 0x4aaa, 0xd2e4, 0x1acd, 0x0562}}, + {{0xdb64, 0x0937, 0x308b, 0x53b0, 0x00e8, 0xc77f, 0x2f30, 0x37f7, + 0x79ce, 0xeb7f, 0xde81, 0x9286, 0xafda, 0x0e62, 0xae00, 0x0067}, + {0x2cc7, 0xd362, 0xb161, 0x0557, 0x4ff2, 0xb9c8, 0x06fe, 0x5f2b, + 0xde33, 0x0190, 0x28c6, 0xb886, 0xee2b, 0x5a4e, 0x3289, 0x0185}, + {0x4215, 0x923e, 0xf34f, 0xb362, 0x88f8, 0xceec, 0xafdd, 0x7f42, + 0x0c57, 0x56b2, 0xa366, 0x6a08, 0x0826, 0xfb8f, 0x1b03, 0x0163}}, + {{0xa4ba, 0x8408, 0x810a, 0xdeba, 0x47a3, 0x853a, 0xeb64, 0x2f74, + 0x3039, 0x038c, 0x7fbb, 0x498e, 0xd1e9, 0x46fb, 0x5691, 0x32a4}, + {0xd749, 0xb49d, 0x20b7, 0x2af6, 0xd34a, 0xd2da, 0x0a10, 0xf781, + 0x58c9, 0x171f, 0x3cb6, 0x6337, 0x88cd, 0xcf1e, 0xb246, 0x7351}, + {0xf729, 0xcf0a, 0x96ea, 0x032c, 0x4a8f, 0x42fe, 0xbac8, 0xec65, + 0x1510, 0x0d75, 0x4c17, 0x8d29, 0xa03f, 0x8b7e, 0x2c49, 0x0000}}, + {{0x0fa4, 0x8e1c, 0x3788, 0xba3c, 0x8d52, 0xd89d, 0x12c8, 0xeced, + 0x9fe6, 0x9b88, 0xecf3, 0xe3c8, 0xac48, 0x76ed, 0xf23e, 0xda79}, + {0x1103, 0x227c, 0x5b00, 0x3fcf, 0xc5d0, 0x2d28, 0x8020, 0x4d1c, + 0xc6b9, 0x67f9, 0x6f39, 0x989a, 0xda53, 0x3847, 0xd416, 0xe0d0}, + {0xdd8e, 0xcf31, 0x3710, 0x7e44, 0xa511, 0x933c, 0x0cc3, 0x5145, + 0xf632, 0x5e1d, 0x038f, 0x5ce7, 0x7265, 0xda9d, 0xded6, 0x08f8}}, + {{0xe2c8, 0x91d5, 0xa5f5, 0x735f, 0x6b58, 0x56dc, 0xb39d, 0x5c4a, + 0x57d0, 0xa1c2, 0xd92f, 0x9ad4, 0xf7c4, 0x51dd, 0xaf5c, 0x0096}, + {0x1739, 0x7207, 0x7505, 0xbf35, 0x42de, 0x0a29, 0xa962, 0xdedf, + 0x53e8, 0x12bf, 0xcde7, 0xd8e2, 0x8d4d, 0x2c4b, 0xb1b1, 0x0628}, + {0x992d, 0xe3a7, 0xb422, 0xc198, 0x23ab, 0xa6ef, 0xb45d, 0x50da, + 0xa738, 0x014a, 0x2310, 0x85fb, 0x5fe8, 0x1b18, 0x1774, 0x03a7}}, + {{0x1f16, 0x2b09, 0x0236, 0xee90, 0xccf9, 0x9775, 0x8130, 0x4c91, + 0x9091, 0x310b, 0x6dc4, 0x86f6, 0xc2e8, 0xef60, 0xfc0e, 0xf3a4}, + {0x9f49, 0xac15, 0x02af, 0x110f, 0xc59d, 0x5677, 0xa1a9, 0x38d5, + 0x914f, 0xa909, 0x3a3a, 0x4a39, 0x3703, 0xea30, 0x73da, 0xffad}, + {0x15ed, 0xdd16, 0x83c7, 0x270a, 0x862f, 0xd8ad, 0xcaa1, 0x5f41, + 0x99a9, 0x3fc8, 0x7bb2, 0x360a, 0xb06d, 0xfadc, 0x1b36, 0xffa8}}, + {{0xc4e0, 0xb8fd, 0x5106, 0xe169, 0x754c, 0xa58c, 0xc413, 0x8224, + 0x5483, 0x63ec, 0xd477, 0x8473, 0x4778, 0x9281, 0x0000, 0x0000}, + {0x85e1, 0xff54, 0xb200, 0xe413, 0xf4f4, 0x4c0f, 0xfcec, 0xc183, + 0x60d3, 0x1b0c, 0x3834, 0x601c, 0x943c, 0xbe6e, 0x0002, 0x0000}, + {0xf4f8, 0xfd5e, 0x61ef, 0xece8, 0x9199, 0xe5c4, 0x05a6, 0xe6c3, + 0xc4ae, 0x8b28, 0x66b1, 0x8a95, 0x9ece, 0x8f4a, 0x0001, 0x0000}}, + {{0xeae9, 0xa1b4, 0xc6d8, 0x2411, 0x2b5a, 0x1dd0, 0x2dc9, 0xb57b, + 0x5ccd, 0x4957, 0xaf59, 0xa04b, 0x5f42, 0xab7c, 0x2826, 0x526f}, + {0xf407, 0x165a, 0xb724, 0x2f12, 0x2ea1, 0x470b, 0x4464, 0xbd35, + 0x606f, 0xd73e, 0x50d3, 0x8a7f, 0x8029, 0x7ffc, 0xbe31, 0x6cfb}, + {0x8171, 0x1f4c, 0xced2, 0x9c99, 0x6d7e, 0x5a0f, 0xfefb, 0x59e3, + 0xa0c8, 0xabd9, 0xc4c5, 0x57d3, 0xbfa3, 0x4f11, 0x96a2, 0x5a7d}}, + {{0xe068, 0x4cc0, 0x8bcd, 0xc903, 0x9e52, 0xb3e1, 0xd745, 0x0995, + 0xdd8f, 0xf14b, 0xd2ac, 0xd65a, 0xda1d, 0xa742, 0xbac5, 0x474c}, + {0x7481, 0xf2ad, 0x9757, 0x2d82, 0xb683, 0xb16b, 0x0002, 0x7b60, + 0x8f0c, 0x2594, 0x8f64, 0x3b7a, 0x3552, 0x8d9d, 0xb9d7, 0x67eb}, + {0xcaab, 0xb9a1, 0xf966, 0xe311, 0x5b34, 0x0fa0, 0x6abc, 0x8134, + 0xab3d, 0x90f6, 0x1984, 0x9232, 0xec17, 0x74e5, 0x2ceb, 0x434e}}, + {{0x0fb1, 0x7a55, 0x1a5c, 0x53eb, 0xd7b3, 0x7a01, 0xca32, 0x31f6, + 0x3b74, 0x679e, 0x1501, 0x6c57, 0xdb20, 0x8b7c, 0xd7d0, 0x8097}, + {0xb127, 0xb20c, 0xe3a2, 0x96f3, 0xe0d8, 0xd50c, 0x14b4, 0x0b40, + 0x6eeb, 0xa258, 0x99db, 0x3c8c, 0x0f51, 0x4198, 0x3887, 0xffd0}, + {0x0273, 0x9f8c, 0x9669, 0xbbba, 0x1c49, 0x767c, 0xc2af, 0x59f0, + 0x1366, 0xd397, 0x63ac, 0x6fe8, 0x1a9a, 0x1259, 0x01d0, 0x0016}}, + {{0x7876, 0x2a35, 0xa24a, 0x433e, 0x5501, 0x573c, 0xd76d, 0xcb82, + 0x1334, 0xb4a6, 0xf290, 0xc797, 0xeae9, 0x2b83, 0x1e2b, 0x8b14}, + {0x3885, 0x8aef, 0x9dea, 0x2b8c, 0xdd7c, 0xd7cd, 0xb0cc, 0x05ee, + 0x361b, 0x3800, 0xb0d4, 0x4c23, 0xbd3f, 0x5180, 0x9783, 0xff80}, + {0xab36, 0x3104, 0xdae8, 0x0704, 0x4a28, 0x6714, 0x824b, 0x0051, + 0x8134, 0x1f6a, 0x712d, 0x1f03, 0x03b2, 0xecac, 0x377d, 0xfef9}} + }; + + int i, j, ok; + + /* Test known inputs/outputs */ + for (i = 0; (size_t)i < sizeof(CASES) / sizeof(CASES[0]); ++i) { + uint16_t out[16]; + test_modinv32_uint16(out, CASES[i][0], CASES[i][1]); + for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); +#ifdef SECP256K1_WIDEMUL_INT128 + test_modinv64_uint16(out, CASES[i][0], CASES[i][1]); + for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]); +#endif + } + + for (i = 0; i < 100 * COUNT; ++i) { + /* 256-bit numbers in 16-uint16_t's notation */ + static const uint16_t ZERO[16] = {0}; + uint16_t xd[16]; /* the number (in range [0,2^256)) to be inverted */ + uint16_t md[16]; /* the modulus (odd, in range [3,2^256)) */ + uint16_t id[16]; /* the inverse of xd mod md */ + + /* generate random xd and md, so that md is odd, md>1, xd>= 16; + } +} + +/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ +static void neg256(uint16_t* out, const uint16_t* a) { + int i; + uint32_t carry = 1; + for (i = 0; i < 16; ++i) { + carry += (uint16_t)~a[i]; + out[i] = carry; + carry >>= 16; + } +} + +/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ +static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { + uint16_t sign = sign_extend && (a[15] >> 15); + int i, j; + for (i = 15; i >= 0; --i) { + uint16_t v = 0; + for (j = 0; j < 16; ++j) { + int frompos = i*16 + j + n; + if (frompos >= 256) { + v |= sign << j; + } else { + v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j; + } + } + out[i] = v; + } +} + +/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256u64(uint16_t* out, uint64_t v, int is_signed) { + int i; + uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = v >> (16 * i); + } + for (i = 4; i < 16; ++i) { + out[i] = sign; + } +} + +/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { + int i; + uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = lo >> (16 * i); + } + for (i = 4; i < 8; ++i) { + out[i] = hi >> (16 * (i - 4)); + } + for (i = 8; i < 16; ++i) { + out[i] = sign; + } +} + +/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ +static int int256is127(const uint16_t* v) { + int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); int i; - for (i = 0; i < 100*count; i++) { - test_num_negate(); - test_num_add_sub(); - test_num_mod(); - test_num_jacobi(); + for (i = 8; i < 16; ++i) { + if (v[i] != 0) all_0 = 0; + if (v[i] != 0xffff) all_1 = 0; + } + return all_0 || all_1; +} + +static void load256u128(uint16_t* out, const secp256k1_uint128* v) { + uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v); + load256two64(out, hi, lo, 0); +} + +static void load256i128(uint16_t* out, const secp256k1_int128* v) { + uint64_t lo; + int64_t hi; + secp256k1_int128 c = *v; + lo = secp256k1_i128_to_u64(&c); + secp256k1_i128_rshift(&c, 64); + hi = secp256k1_i128_to_i64(&c); + load256two64(out, hi, lo, 1); +} + +static void run_int128_test_case(void) { + unsigned char buf[32]; + uint64_t v[4]; + secp256k1_int128 swa, swz; + secp256k1_uint128 uwa, uwz; + uint64_t ub, uc; + int64_t sb, sc; + uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32]; + uint16_t rub[16], ruc[16], rsb[16], rsc[16]; + int i; + + /* Generate 32-byte random value. */ + testrand256_test(buf); + /* Convert into 4 64-bit integers. */ + for (i = 0; i < 4; ++i) { + uint64_t vi = 0; + int j; + for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j]; + v[i] = vi; + } + /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */ + secp256k1_u128_load(&uwa, v[1], v[0]); + secp256k1_i128_load(&swa, v[1], v[0]); + ub = v[2]; + sb = v[2]; + uc = v[3]; + sc = v[3]; + /* Load those also into 16-bit array representations. */ + load256u128(ruwa, &uwa); + load256i128(rswa, &swa); + load256u64(rub, ub, 0); + load256u64(rsb, sb, 1); + load256u64(ruc, uc, 0); + load256u64(rsc, sc, 1); + /* test secp256k1_u128_mul */ + mulmod256(ruwr, rub, ruc, NULL); + secp256k1_u128_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_mul */ + mulmod256(ruwr, rub, ruc, NULL); + add256(ruwr, ruwr, ruwa); + uwz = uwa; + secp256k1_u128_accum_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_u64 */ + add256(ruwr, rub, ruwa); + uwz = uwa; + secp256k1_u128_accum_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_rshift */ + rshift256(ruwr, ruwa, uc % 128, 0); + uwz = uwa; + secp256k1_u128_rshift(&uwz, uc % 128); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_to_u64 */ + CHECK(secp256k1_u128_to_u64(&uwa) == v[0]); + /* test secp256k1_u128_hi_u64 */ + CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]); + /* test secp256k1_u128_from_u64 */ + secp256k1_u128_from_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0); + /* test secp256k1_u128_check_bits */ + { + int uwa_bits = 0; + int j; + for (j = 0; j < 128; ++j) { + if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j; + } + for (j = 0; j < 128; ++j) { + CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j)); + } + } + /* test secp256k1_i128_mul */ + mulmod256(rswr, rsb, rsc, NULL); + secp256k1_i128_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_accum_mul */ + mulmod256(rswr, rsb, rsc, NULL); + add256(rswr, rswr, rswa); + if (int256is127(rswr)) { + swz = swa; + secp256k1_i128_accum_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_det */ + { + uint16_t rsd[16], rse[16], rst[32]; + int64_t sd = v[0], se = v[1]; + load256u64(rsd, sd, 1); + load256u64(rse, se, 1); + mulmod256(rst, rsc, rsd, NULL); + neg256(rst, rst); + mulmod256(rswr, rsb, rse, NULL); + add256(rswr, rswr, rst); + secp256k1_i128_det(&swz, sb, sc, sd, se); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_rshift */ + rshift256(rswr, rswa, uc % 127, 1); + swz = swa; + secp256k1_i128_rshift(&swz, uc % 127); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_to_u64 */ + CHECK(secp256k1_i128_to_u64(&swa) == v[0]); + /* test secp256k1_i128_from_i64 */ + secp256k1_i128_from_i64(&swz, sb); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0); + /* test secp256k1_i128_to_i64 */ + CHECK(secp256k1_i128_to_i64(&swz) == sb); + /* test secp256k1_i128_eq_var */ + { + int expect = (uc & 1); + swz = swa; + if (!expect) { + /* Make sure swz != swa */ + uint64_t v0c = v[0], v1c = v[1]; + if (ub & 64) { + v1c ^= (((uint64_t)1) << (ub & 63)); + } else { + v0c ^= (((uint64_t)1) << (ub & 63)); + } + secp256k1_i128_load(&swz, v1c, v0c); + } + CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == 1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly 2^pos. */ + uint64_t hi = 0; + uint64_t lo = 0; + if (pos >= 64) { + hi = (((uint64_t)1) << (pos & 63)); + } else { + lo = (((uint64_t)1) << (pos & 63)); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ + if (pos >= 64) { + if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == -1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly -2^pos. */ + uint64_t hi = ~(uint64_t)0; + uint64_t lo = ~(uint64_t)0; + if (pos >= 64) { + hi <<= (pos & 63); + lo = 0; + } else { + lo <<= (pos & 63); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ + if (pos >= 64) { + if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect); + } +} + +static void run_int128_tests(void) { + { /* secp256k1_u128_accum_mul */ + secp256k1_uint128 res; + + /* Check secp256k1_u128_accum_mul overflow */ + secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX); + secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX); + CHECK(secp256k1_u128_to_u64(&res) == 2); + CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U); + } + { /* secp256k1_u128_accum_mul */ + secp256k1_int128 res; + + /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX); + CHECK(secp256k1_i128_to_u64(&res) == 2); + secp256k1_i128_accum_mul(&res, 4, 9223372036854775807); + secp256k1_i128_accum_mul(&res, 1, 1); + CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX); + + /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == (uint64_t)INT64_MIN); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == 0); + secp256k1_i128_accum_mul(&res, 2, INT64_MIN); + CHECK(secp256k1_i128_to_u64(&res) == 0); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN); + } + { + /* Randomized tests. */ + int i; + for (i = 0; i < 256 * COUNT; ++i) run_int128_test_case(); } } #endif /***** SCALAR TESTS *****/ -void scalar_test(void) { +static void scalar_test(void) { secp256k1_scalar s; secp256k1_scalar s1; secp256k1_scalar s2; -#ifndef USE_NUM_NONE - secp256k1_num snum, s1num, s2num; - secp256k1_num order, half_order; -#endif unsigned char c[32]; /* Set 's' to a random scalar, with value 'snum'. */ - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); /* Set 's1' to a random scalar, with value 's1num'. */ - random_scalar_order_test(&s1); + testutil_random_scalar_order_test(&s1); /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - random_scalar_order_test(&s2); + testutil_random_scalar_order_test(&s2); secp256k1_scalar_get_b32(c, &s2); -#ifndef USE_NUM_NONE - secp256k1_scalar_get_num(&snum, &s); - secp256k1_scalar_get_num(&s1num, &s1); - secp256k1_scalar_get_num(&s2num, &s2); - - secp256k1_scalar_order_get_num(&order); - half_order = order; - secp256k1_num_shift(&half_order, 1); -#endif - { int i; /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ @@ -657,7 +2034,7 @@ void scalar_test(void) { for (i = 0; i < 256; i += 4) { secp256k1_scalar t; int j; - secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_limb32(&s, 256 - 4 - i, 4)); for (j = 0; j < 4; j++) { secp256k1_scalar_add(&n, &n, &n); } @@ -674,7 +2051,7 @@ void scalar_test(void) { while (i < 256) { secp256k1_scalar t; int j; - int now = secp256k1_rand_int(15) + 1; + int now = testrand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -688,122 +2065,6 @@ void scalar_test(void) { CHECK(secp256k1_scalar_eq(&n, &s)); } -#ifndef USE_NUM_NONE - { - /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ - secp256k1_num rnum; - secp256k1_num r2num; - secp256k1_scalar r; - secp256k1_num_add(&rnum, &snum, &s2num); - secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_add(&r, &s, &s2); - secp256k1_scalar_get_num(&r2num, &r); - CHECK(secp256k1_num_eq(&rnum, &r2num)); - } - - { - /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_scalar r; - secp256k1_num r2num; - secp256k1_num rnum; - secp256k1_num_mul(&rnum, &snum, &s2num); - secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_mul(&r, &s, &s2); - secp256k1_scalar_get_num(&r2num, &r); - CHECK(secp256k1_num_eq(&rnum, &r2num)); - /* The result can only be zero if at least one of the factors was zero. */ - CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2))); - /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */ - CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2))); - CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s))); - } - - { - secp256k1_scalar neg; - secp256k1_num negnum; - secp256k1_num negnum2; - /* Check that comparison with zero matches comparison with zero on the number. */ - CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); - /* Check that comparison with the half order is equal to testing for high scalar. */ - CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0)); - secp256k1_scalar_negate(&neg, &s); - secp256k1_num_sub(&negnum, &order, &snum); - secp256k1_num_mod(&negnum, &order); - /* Check that comparison with the half order is equal to testing for high scalar after negation. */ - CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0)); - /* Negating should change the high property, unless the value was already zero. */ - CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); - secp256k1_scalar_get_num(&negnum2, &neg); - /* Negating a scalar should be equal to (order - n) mod order on the number. */ - CHECK(secp256k1_num_eq(&negnum, &negnum2)); - secp256k1_scalar_add(&neg, &neg, &s); - /* Adding a number to its negation should result in zero. */ - CHECK(secp256k1_scalar_is_zero(&neg)); - secp256k1_scalar_negate(&neg, &neg); - /* Negating zero should still result in zero. */ - CHECK(secp256k1_scalar_is_zero(&neg)); - } - - { - /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar r; - secp256k1_num one; - secp256k1_num rnum; - secp256k1_num rnum2; - unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + secp256k1_rand_int(257); - secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); - secp256k1_num_mul(&rnum, &s1num, &s2num); - secp256k1_num_shift(&rnum, shift - 1); - secp256k1_num_set_bin(&one, cone, 1); - secp256k1_num_add(&rnum, &rnum, &one); - secp256k1_num_shift(&rnum, 1); - secp256k1_scalar_get_num(&rnum2, &r); - CHECK(secp256k1_num_eq(&rnum, &rnum2)); - } - - { - /* test secp256k1_scalar_shr_int */ - secp256k1_scalar r; - int i; - random_scalar_order_test(&r); - for (i = 0; i < 100; ++i) { - int low; - int shift = 1 + secp256k1_rand_int(15); - int expected = r.d[0] % (1 << shift); - low = secp256k1_scalar_shr_int(&r, shift); - CHECK(expected == low); - } - } -#endif - - { - /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ - if (!secp256k1_scalar_is_zero(&s)) { - secp256k1_scalar inv; -#ifndef USE_NUM_NONE - secp256k1_num invnum; - secp256k1_num invnum2; -#endif - secp256k1_scalar_inverse(&inv, &s); -#ifndef USE_NUM_NONE - secp256k1_num_mod_inverse(&invnum, &snum, &order); - secp256k1_scalar_get_num(&invnum2, &inv); - CHECK(secp256k1_num_eq(&invnum, &invnum2)); -#endif - secp256k1_scalar_mul(&inv, &inv, &s); - /* Multiplying a scalar with its inverse must result in one. */ - CHECK(secp256k1_scalar_is_one(&inv)); - secp256k1_scalar_inverse(&inv, &inv); - /* Inverting one must result in one. */ - CHECK(secp256k1_scalar_is_one(&inv)); -#ifndef USE_NUM_NONE - secp256k1_scalar_get_num(&invnum, &inv); - CHECK(secp256k1_num_is_one(&invnum)); -#endif - } - } - { /* Test commutativity of add. */ secp256k1_scalar r1, r2; @@ -817,7 +2078,7 @@ void scalar_test(void) { secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand_bits(8); + int bit = testrand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -874,72 +2135,117 @@ void scalar_test(void) { CHECK(secp256k1_scalar_eq(&r1, &r2)); } - { - /* Test square. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_sqr(&r1, &s1); - secp256k1_scalar_mul(&r2, &s1, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - { /* Test multiplicative identity. */ - secp256k1_scalar r1, v1; - secp256k1_scalar_set_int(&v1,1); - secp256k1_scalar_mul(&r1, &s1, &v1); + secp256k1_scalar r1; + secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_one); CHECK(secp256k1_scalar_eq(&r1, &s1)); } { /* Test additive identity. */ - secp256k1_scalar r1, v0; - secp256k1_scalar_set_int(&v0,0); - secp256k1_scalar_add(&r1, &s1, &v0); + secp256k1_scalar r1; + secp256k1_scalar_add(&r1, &s1, &secp256k1_scalar_zero); CHECK(secp256k1_scalar_eq(&r1, &s1)); } { /* Test zero product property. */ - secp256k1_scalar r1, v0; - secp256k1_scalar_set_int(&v0,0); - secp256k1_scalar_mul(&r1, &s1, &v0); - CHECK(secp256k1_scalar_eq(&r1, &v0)); + secp256k1_scalar r1; + secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_zero); + CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero)); + } + + { + /* Test halving. */ + secp256k1_scalar r; + secp256k1_scalar_add(&r, &s, &s); + secp256k1_scalar_half(&r, &r); + CHECK(secp256k1_scalar_eq(&r, &s)); } +} +static void run_scalar_set_b32_seckey_tests(void) { + unsigned char b32[32]; + secp256k1_scalar s1; + secp256k1_scalar s2; + + /* Usually set_b32 and set_b32_seckey give the same result */ + testutil_random_scalar_order_b32(b32); + secp256k1_scalar_set_b32(&s1, b32, NULL); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1); + CHECK(secp256k1_scalar_eq(&s1, &s2) == 1); + + memset(b32, 0, sizeof(b32)); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); + memset(b32, 0xFF, sizeof(b32)); + CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); } -void run_scalar_tests(void) { +static void run_scalar_tests(void) { int i; - for (i = 0; i < 128 * count; i++) { + for (i = 0; i < 128 * COUNT; i++) { scalar_test(); } + for (i = 0; i < COUNT; i++) { + run_scalar_set_b32_seckey_tests(); + } + + { + /* Check that the scalar constants secp256k1_scalar_zero and + secp256k1_scalar_one contain the expected values. */ + secp256k1_scalar zero, one; + + CHECK(secp256k1_scalar_is_zero(&secp256k1_scalar_zero)); + secp256k1_scalar_set_int(&zero, 0); + CHECK(secp256k1_scalar_eq(&zero, &secp256k1_scalar_zero)); + + CHECK(secp256k1_scalar_is_one(&secp256k1_scalar_one)); + secp256k1_scalar_set_int(&one, 1); + CHECK(secp256k1_scalar_eq(&one, &secp256k1_scalar_one)); + } { /* (-1)+1 should be zero. */ - secp256k1_scalar s, o; - secp256k1_scalar_set_int(&s, 1); - CHECK(secp256k1_scalar_is_one(&s)); - secp256k1_scalar_negate(&o, &s); - secp256k1_scalar_add(&o, &o, &s); + secp256k1_scalar o; + secp256k1_scalar_negate(&o, &secp256k1_scalar_one); + secp256k1_scalar_add(&o, &o, &secp256k1_scalar_one); CHECK(secp256k1_scalar_is_zero(&o)); secp256k1_scalar_negate(&o, &o); CHECK(secp256k1_scalar_is_zero(&o)); } -#ifndef USE_NUM_NONE { - /* A scalar with value of the curve order should be 0. */ - secp256k1_num order; - secp256k1_scalar zero; - unsigned char bin[32]; - int overflow = 0; - secp256k1_scalar_order_get_num(&order); - secp256k1_num_get_bin(bin, 32, &order); - secp256k1_scalar_set_b32(&zero, bin, &overflow); - CHECK(overflow == 1); - CHECK(secp256k1_scalar_is_zero(&zero)); + /* Test that halving and doubling roundtrips on some fixed values. */ + static const secp256k1_scalar HALF_TESTS[] = { + /* 0 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + /* 1 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + /* -1 */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul), + /* -2 (largest odd value) */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful), + /* Half the secp256k1 order */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul), + /* Half the secp256k1 order + 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul), + /* 2^255 */ + SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0), + /* 2^255 - 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful), + }; + unsigned n; + for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) { + secp256k1_scalar s; + secp256k1_scalar_half(&s, &HALF_TESTS[n]); + secp256k1_scalar_add(&s, &s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + secp256k1_scalar_add(&s, &s, &s); + secp256k1_scalar_half(&s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + } } -#endif { /* Does check_overflow check catch all ones? */ @@ -960,12 +2266,9 @@ void run_scalar_tests(void) { secp256k1_scalar y; secp256k1_scalar z; secp256k1_scalar zz; - secp256k1_scalar one; secp256k1_scalar r1; secp256k1_scalar r2; -#if defined(USE_SCALAR_INV_NUM) secp256k1_scalar zzv; -#endif int overflow; unsigned char chal[33][2][32] = { {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, @@ -1499,7 +2802,6 @@ void run_scalar_tests(void) { 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} }; - secp256k1_scalar_set_int(&one, 1); for (i = 0; i < 33; i++) { secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); CHECK(!overflow); @@ -1510,91 +2812,40 @@ void run_scalar_tests(void) { secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); CHECK(!overflow); secp256k1_scalar_mul(&z, &x, &y); - CHECK(!secp256k1_scalar_check_overflow(&z)); CHECK(secp256k1_scalar_eq(&r1, &z)); if (!secp256k1_scalar_is_zero(&y)) { secp256k1_scalar_inverse(&zz, &y); - CHECK(!secp256k1_scalar_check_overflow(&zz)); -#if defined(USE_SCALAR_INV_NUM) secp256k1_scalar_inverse_var(&zzv, &y); CHECK(secp256k1_scalar_eq(&zzv, &zz)); -#endif secp256k1_scalar_mul(&z, &z, &zz); - CHECK(!secp256k1_scalar_check_overflow(&z)); CHECK(secp256k1_scalar_eq(&x, &z)); secp256k1_scalar_mul(&zz, &zz, &y); - CHECK(!secp256k1_scalar_check_overflow(&zz)); - CHECK(secp256k1_scalar_eq(&one, &zz)); + CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz)); } secp256k1_scalar_mul(&z, &x, &x); - CHECK(!secp256k1_scalar_check_overflow(&z)); - secp256k1_scalar_sqr(&zz, &x); - CHECK(!secp256k1_scalar_check_overflow(&zz)); - CHECK(secp256k1_scalar_eq(&zz, &z)); - CHECK(secp256k1_scalar_eq(&r2, &zz)); + CHECK(secp256k1_scalar_eq(&r2, &z)); } } } /***** FIELD TESTS *****/ -void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_test(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256_test(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_non_zero(secp256k1_fe *nz) { - int tries = 10; - while (--tries >= 0) { - random_fe(nz); - secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) { - break; - } - } - /* Infinitesimal probability of spurious failure here */ - CHECK(tries >= 0); -} - -void random_fe_non_square(secp256k1_fe *ns) { +static void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; - random_fe_non_zero(ns); + testutil_random_fe_non_zero(ns); if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } -int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { +static int fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe an = *a; secp256k1_fe bn = *b; secp256k1_fe_normalize_weak(&an); - secp256k1_fe_normalize_var(&bn); - return secp256k1_fe_equal_var(&an, &bn); -} - -int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { - secp256k1_fe x; - secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_mul(&x, a, ai); - return check_fe_equal(&x, &one); + return secp256k1_fe_equal(&an, &bn); } -void run_field_convert(void) { +static void run_field_convert(void) { static const unsigned char b32[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, @@ -1613,63 +2864,204 @@ void run_field_convert(void) { unsigned char b322[32]; secp256k1_fe_storage fes2; /* Check conversions to fe. */ - CHECK(secp256k1_fe_set_b32(&fe2, b32)); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + CHECK(secp256k1_fe_set_b32_limit(&fe2, b32)); + CHECK(secp256k1_fe_equal(&fe, &fe2)); secp256k1_fe_from_storage(&fe2, &fes); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + CHECK(secp256k1_fe_equal(&fe, &fe2)); /* Check conversion from fe. */ secp256k1_fe_get_b32(b322, &fe); - CHECK(memcmp(b322, b32, 32) == 0); + CHECK(secp256k1_memcmp_var(b322, b32, 32) == 0); secp256k1_fe_to_storage(&fes2, &fe); - CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); + CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); } -int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe t = *b; +static void run_field_be32_overflow(void) { + { + static const unsigned char zero_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + }; + static const unsigned char zero[32] = { 0x00 }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, zero_overflow); + CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_is_zero(&fe) == 1); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, zero, 32) == 0); + } + { + static const unsigned char one_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30, + }; + static const unsigned char one[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, one_overflow); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, one, 32) == 0); + } + { + static const unsigned char ff_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + static const unsigned char ff[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0, + }; + unsigned char out[32]; + secp256k1_fe fe; + const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); + CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, ff_overflow); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, ff, 32) == 0); + } +} + +/* Returns true if two field elements have the same representation. */ +static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { + int ret = 1; + /* Compare the struct member that holds the limbs. */ + ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0); + return ret; +} + +static void run_field_half(void) { + secp256k1_fe t, u; + int m; + + /* Check magnitude 0 input */ + secp256k1_fe_get_bounds(&t, 0); + secp256k1_fe_half(&t); +#ifdef VERIFY + CHECK(t.magnitude == 1); + CHECK(t.normalized == 0); +#endif + CHECK(secp256k1_fe_normalizes_to_zero(&t)); + + /* Check non-zero magnitudes in the supported range */ + for (m = 1; m < 32; m++) { + /* Check max-value input */ + secp256k1_fe_get_bounds(&t, m); + + u = t; + secp256k1_fe_half(&u); #ifdef VERIFY - t.magnitude = a->magnitude; - t.normalized = a->normalized; + CHECK(u.magnitude == (m >> 1) + 1); + CHECK(u.normalized == 0); #endif - return memcmp(a, &t, sizeof(secp256k1_fe)); + secp256k1_fe_normalize_weak(&u); + secp256k1_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); + + /* Check worst-case input: ensure the LSB is 1 so that P will be added, + * which will also cause all carries to be 1, since all limbs that can + * generate a carry are initially even and all limbs of P are odd in + * every existing field implementation. */ + secp256k1_fe_get_bounds(&t, m); + CHECK(t.n[0] > 0); + CHECK((t.n[0] & 1) == 0); + --t.n[0]; + + u = t; + secp256k1_fe_half(&u); +#ifdef VERIFY + CHECK(u.magnitude == (m >> 1) + 1); + CHECK(u.normalized == 0); +#endif + secp256k1_fe_normalize_weak(&u); + secp256k1_fe_add(&u, &u); + CHECK(fe_equal(&t, &u)); + } } -void run_field_misc(void) { +static void run_field_misc(void) { secp256k1_fe x; secp256k1_fe y; secp256k1_fe z; secp256k1_fe q; + int v; secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); int i, j; - for (i = 0; i < 5*count; i++) { + for (i = 0; i < 1000 * COUNT; i++) { secp256k1_fe_storage xs, ys, zs; - random_fe(&x); - random_fe_non_zero(&y); + if (i & 1) { + testutil_random_fe(&x); + } else { + testutil_random_fe_test(&x); + } + testutil_random_fe_non_zero(&y); + v = testrand_bits(15); + /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ + secp256k1_fe_set_int(&q, v); /* q = v */ + z = x; /* z = x */ + secp256k1_fe_add(&z, &q); /* z = x+v */ + q = x; /* q = x */ + secp256k1_fe_add_int(&q, v); /* q = x+v */ + CHECK(fe_equal(&q, &z)); /* Test the fe equality and comparison operations. */ CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); - CHECK(secp256k1_fe_equal_var(&x, &x)); + CHECK(secp256k1_fe_equal(&x, &x)); z = x; secp256k1_fe_add(&z,&y); /* Test fe conditional move; z is not normalized here. */ q = x; secp256k1_fe_cmov(&x, &z, 0); - VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); +#ifdef VERIFY + CHECK(!x.normalized); + CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude)); + CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude)); +#endif + x = q; secp256k1_fe_cmov(&x, &x, 1); - CHECK(fe_memcmp(&x, &z) != 0); - CHECK(fe_memcmp(&x, &q) == 0); + CHECK(!fe_identical(&x, &z)); + CHECK(fe_identical(&x, &q)); secp256k1_fe_cmov(&q, &z, 1); - VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); - CHECK(fe_memcmp(&q, &z) == 0); +#ifdef VERIFY + CHECK(!q.normalized); + CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude)); + CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude)); +#endif + CHECK(fe_identical(&q, &z)); + q = z; secp256k1_fe_normalize_var(&x); secp256k1_fe_normalize_var(&z); - CHECK(!secp256k1_fe_equal_var(&x, &z)); + CHECK(!secp256k1_fe_equal(&x, &z)); secp256k1_fe_normalize_var(&q); secp256k1_fe_cmov(&q, &z, (i&1)); - VERIFY_CHECK(q.normalized && q.magnitude == 1); +#ifdef VERIFY + CHECK(q.normalized && q.magnitude == 1); +#endif for (j = 0; j < 6; j++) { - secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_negate_unchecked(&z, &z, j+1); secp256k1_fe_normalize_var(&q); secp256k1_fe_cmov(&q, &z, (j&1)); - VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); +#ifdef VERIFY + CHECK(!q.normalized && q.magnitude == z.magnitude); +#endif } secp256k1_fe_normalize_var(&z); /* Test storage conversion and conditional moves. */ @@ -1678,9 +3070,9 @@ void run_field_misc(void) { secp256k1_fe_to_storage(&zs, &z); secp256k1_fe_storage_cmov(&zs, &xs, 0); secp256k1_fe_storage_cmov(&zs, &zs, 1); - CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + CHECK(secp256k1_memcmp_var(&xs, &zs, sizeof(xs)) != 0); secp256k1_fe_storage_cmov(&ys, &xs, 1); - CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + CHECK(secp256k1_memcmp_var(&xs, &ys, sizeof(xs)) == 0); secp256k1_fe_from_storage(&x, &xs); secp256k1_fe_from_storage(&y, &ys); secp256k1_fe_from_storage(&z, &zs); @@ -1689,85 +3081,124 @@ void run_field_misc(void) { secp256k1_fe_add(&y, &x); z = x; secp256k1_fe_mul_int(&z, 3); - CHECK(check_fe_equal(&y, &z)); + CHECK(fe_equal(&y, &z)); secp256k1_fe_add(&y, &x); secp256k1_fe_add(&z, &x); - CHECK(check_fe_equal(&z, &y)); + CHECK(fe_equal(&z, &y)); z = x; secp256k1_fe_mul_int(&z, 5); secp256k1_fe_mul(&q, &x, &fe5); - CHECK(check_fe_equal(&z, &q)); + CHECK(fe_equal(&z, &q)); secp256k1_fe_negate(&x, &x, 1); secp256k1_fe_add(&z, &x); secp256k1_fe_add(&q, &x); - CHECK(check_fe_equal(&y, &z)); - CHECK(check_fe_equal(&q, &y)); + CHECK(fe_equal(&y, &z)); + CHECK(fe_equal(&q, &y)); + /* Check secp256k1_fe_half. */ + z = x; + secp256k1_fe_half(&z); + secp256k1_fe_add(&z, &z); + CHECK(fe_equal(&x, &z)); + secp256k1_fe_add(&z, &z); + secp256k1_fe_half(&z); + CHECK(fe_equal(&x, &z)); } } -void run_field_inv(void) { - secp256k1_fe x, xi, xii; +static void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) +{ + secp256k1_fe c, an, bn; + /* Variables in BE 32-byte format. */ + unsigned char a32[32], b32[32], c32[32]; + /* Variables in LE 16x uint16_t format. */ + uint16_t a16[16], b16[16], c16[16]; + /* Field modulus in LE 16x uint16_t format. */ + static const uint16_t m16[16] = { + 0xfc2f, 0xffff, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + }; + uint16_t t16[32]; int i; - for (i = 0; i < 10*count; i++) { - random_fe_non_zero(&x); - secp256k1_fe_inv(&xi, &x); - CHECK(check_fe_inverse(&x, &xi)); - secp256k1_fe_inv(&xii, &xi); - CHECK(check_fe_equal(&x, &xii)); + + /* Compute C = A * B in fe format. */ + c = *a; + if (use_sqr) { + secp256k1_fe_sqr(&c, &c); + } else { + secp256k1_fe_mul(&c, &c, b); } + + /* Convert A, B, C into LE 16x uint16_t format. */ + an = *a; + bn = *b; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_normalize_var(&an); + secp256k1_fe_normalize_var(&bn); + secp256k1_fe_get_b32(a32, &an); + secp256k1_fe_get_b32(b32, &bn); + secp256k1_fe_get_b32(c32, &c); + for (i = 0; i < 16; ++i) { + a16[i] = a32[31 - 2*i] + ((uint16_t)a32[30 - 2*i] << 8); + b16[i] = b32[31 - 2*i] + ((uint16_t)b32[30 - 2*i] << 8); + c16[i] = c32[31 - 2*i] + ((uint16_t)c32[30 - 2*i] << 8); + } + /* Compute T = A * B in LE 16x uint16_t format. */ + mulmod256(t16, a16, b16, m16); + /* Compare */ + CHECK(secp256k1_memcmp_var(t16, c16, 32) == 0); } -void run_field_inv_var(void) { - secp256k1_fe x, xi, xii; +static void run_fe_mul(void) { int i; - for (i = 0; i < 10*count; i++) { - random_fe_non_zero(&x); - secp256k1_fe_inv_var(&xi, &x); - CHECK(check_fe_inverse(&x, &xi)); - secp256k1_fe_inv_var(&xii, &xi); - CHECK(check_fe_equal(&x, &xii)); + for (i = 0; i < 100 * COUNT; ++i) { + secp256k1_fe a, b, c, d; + testutil_random_fe(&a); + testutil_random_fe_magnitude(&a, 8); + testutil_random_fe(&b); + testutil_random_fe_magnitude(&b, 8); + testutil_random_fe_test(&c); + testutil_random_fe_magnitude(&c, 8); + testutil_random_fe_test(&d); + testutil_random_fe_magnitude(&d, 8); + test_fe_mul(&a, &a, 1); + test_fe_mul(&c, &c, 1); + test_fe_mul(&a, &b, 0); + test_fe_mul(&a, &c, 0); + test_fe_mul(&c, &b, 0); + test_fe_mul(&c, &d, 0); } } -void run_field_inv_all_var(void) { - secp256k1_fe x[16], xi[16], xii[16]; +static void run_sqr(void) { int i; - /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all_var(xi, x, 0); - for (i = 0; i < count; i++) { - size_t j; - size_t len = secp256k1_rand_int(15) + 1; - for (j = 0; j < len; j++) { - random_fe_non_zero(&x[j]); - } - secp256k1_fe_inv_all_var(xi, x, len); - for (j = 0; j < len; j++) { - CHECK(check_fe_inverse(&x[j], &xi[j])); - } - secp256k1_fe_inv_all_var(xii, xi, len); - for (j = 0; j < len; j++) { - CHECK(check_fe_equal(&x[j], &xii[j])); - } - } -} + secp256k1_fe x, y, lhs, rhs, tmp; -void run_sqr(void) { - secp256k1_fe x, s; + secp256k1_fe_set_int(&x, 1); + secp256k1_fe_negate(&x, &x, 1); - { - int i; - secp256k1_fe_set_int(&x, 1); - secp256k1_fe_negate(&x, &x, 1); + for (i = 1; i <= 512; ++i) { + secp256k1_fe_mul_int(&x, 2); + secp256k1_fe_normalize(&x); - for (i = 1; i <= 512; ++i) { - secp256k1_fe_mul_int(&x, 2); - secp256k1_fe_normalize(&x); - secp256k1_fe_sqr(&s, &x); - } + /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */ + testutil_random_fe_test(&y); + + lhs = x; + secp256k1_fe_add(&lhs, &y); /* lhs = x+y */ + secp256k1_fe_negate(&tmp, &y, 1); /* tmp = -y */ + secp256k1_fe_add(&tmp, &x); /* tmp = x-y */ + secp256k1_fe_mul(&lhs, &lhs, &tmp); /* lhs = (x+y)*(x-y) */ + + secp256k1_fe_sqr(&rhs, &x); /* rhs = x^2 */ + secp256k1_fe_sqr(&tmp, &y); /* tmp = y^2 */ + secp256k1_fe_negate(&tmp, &tmp, 1); /* tmp = -y^2 */ + secp256k1_fe_add(&rhs, &tmp); /* rhs = x^2 - y^2 */ + + CHECK(fe_equal(&lhs, &rhs)); } } -void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { +static void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { secp256k1_fe r1, r2; int v = secp256k1_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); @@ -1781,7 +3212,7 @@ void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { } } -void run_sqrt(void) { +static void run_sqrt(void) { secp256k1_fe ns, x, s, t; int i; @@ -1803,11 +3234,13 @@ void run_sqrt(void) { for (i = 0; i < 10; i++) { int j; random_fe_non_square(&ns); - for (j = 0; j < count; j++) { - random_fe(&x); + for (j = 0; j < COUNT; j++) { + testutil_random_fe(&x); secp256k1_fe_sqr(&s, &x); + CHECK(secp256k1_fe_is_square_var(&s)); test_sqrt(&s, &x); secp256k1_fe_negate(&t, &s, 1); + CHECK(!secp256k1_fe_is_square_var(&t)); test_sqrt(&t, NULL); secp256k1_fe_mul(&t, &s, &ns); test_sqrt(&t, NULL); @@ -1815,19 +3248,394 @@ void run_sqrt(void) { } } -/***** GROUP TESTS *****/ +/***** FIELD/SCALAR INVERSE TESTS *****/ + +static const secp256k1_scalar scalar_minus_one = SECP256K1_SCALAR_CONST( + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, + 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364140 +); + +static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST( + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E +); + +/* These tests test the following identities: + * + * for x==0: 1/x == 0 + * for x!=0: x*(1/x) == 1 + * for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1) + */ + +static void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var) +{ + secp256k1_scalar l, r, t; + + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, x); /* l = 1/x */ + if (out) *out = l; + if (secp256k1_scalar_is_zero(x)) { + CHECK(secp256k1_scalar_is_zero(&l)); + return; + } + secp256k1_scalar_mul(&t, x, &l); /* t = x*(1/x) */ + CHECK(secp256k1_scalar_is_one(&t)); /* x*(1/x) == 1 */ + secp256k1_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */ + if (secp256k1_scalar_is_zero(&r)) return; + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&r, &r); /* r = 1/(x-1) */ + secp256k1_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */ + (var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse)(&l, &l); /* l = 1/(1/x-1) */ + secp256k1_scalar_add(&l, &l, &secp256k1_scalar_one); /* l = 1/(1/x-1)+1 */ + secp256k1_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */ +} + +static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) +{ + secp256k1_fe l, r, t; -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, x) ; /* l = 1/x */ + if (out) *out = l; + t = *x; /* t = x */ + if (secp256k1_fe_normalizes_to_zero_var(&t)) { + CHECK(secp256k1_fe_normalizes_to_zero(&l)); return; } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); + secp256k1_fe_mul(&t, x, &l); /* t = x*(1/x) */ + secp256k1_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */ + CHECK(secp256k1_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */ + r = *x; /* r = x */ + secp256k1_fe_add(&r, &fe_minus_one); /* r = x-1 */ + if (secp256k1_fe_normalizes_to_zero_var(&r)) return; + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */ + secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ + (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ + secp256k1_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */ + secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ + CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */ +} + +static void run_inverse_tests(void) +{ + /* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */ + static const secp256k1_fe fe_cases[][2] = { + /* 0 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), + SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, + /* 1 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), + SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, + /* -1 */ + {SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e), + SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e)}, + /* 2 */ + {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2), + SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18)}, + /* 2**128 */ + {SECP256K1_FE_CONST(0, 0, 0, 1, 0, 0, 0, 0), + SECP256K1_FE_CONST(0xbcb223fe, 0xdc24a059, 0xd838091d, 0xd2253530, 0xffffffff, 0xffffffff, 0xffffffff, 0x434dd931)}, + /* Input known to need 637 divsteps */ + {SECP256K1_FE_CONST(0xe34e9c95, 0x6bee8a84, 0x0dcb632a, 0xdb8a1320, 0x66885408, 0x06f3f996, 0x7c11ca84, 0x19199ec3), + SECP256K1_FE_CONST(0xbd2cbd8f, 0x1c536828, 0x9bccda44, 0x2582ac0c, 0x870152b0, 0x8a3f09fb, 0x1aaadf92, 0x19b618e5)}, + /* Input known to need 567 divsteps starting with delta=1/2. */ + {SECP256K1_FE_CONST(0xf6bc3ba3, 0x636451c4, 0x3e46357d, 0x2c21d619, 0x0988e234, 0x15985661, 0x6672982b, 0xa7549bfc), + SECP256K1_FE_CONST(0xb024fdc7, 0x5547451e, 0x426c585f, 0xbd481425, 0x73df6b75, 0xeef6d9d0, 0x389d87d4, 0xfbb440ba)}, + /* Input known to need 566 divsteps starting with delta=1/2. */ + {SECP256K1_FE_CONST(0xb595d81b, 0x2e3c1e2f, 0x482dbc65, 0xe4865af7, 0x9a0a50aa, 0x29f9e618, 0x6f87d7a5, 0x8d1063ae), + SECP256K1_FE_CONST(0xc983337c, 0x5d5c74e1, 0x49918330, 0x0b53afb5, 0xa0428a0b, 0xce6eef86, 0x059bd8ef, 0xe5b908de)}, + /* Set of 10 inputs accessing all 128 entries in the modinv32 divsteps_var table */ + {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0xe0ff1f80, 0x1f000000, 0x00000000, 0x00000000, 0xfeff0100, 0x00000000), + SECP256K1_FE_CONST(0x9faf9316, 0x77e5049d, 0x0b5e7a1b, 0xef70b893, 0x18c9e30c, 0x045e7fd7, 0x29eddf8c, 0xd62e9e3d)}, + {SECP256K1_FE_CONST(0x621a538d, 0x511b2780, 0x35688252, 0x53f889a4, 0x6317c3ac, 0x32ba0a46, 0x6277c0d1, 0xccd31192), + SECP256K1_FE_CONST(0x38513b0c, 0x5eba856f, 0xe29e882e, 0x9b394d8c, 0x34bda011, 0xeaa66943, 0x6a841a4c, 0x6ae8bcff)}, + {SECP256K1_FE_CONST(0x00000200, 0xf0ffff1f, 0x00000000, 0x0000e0ff, 0xffffffff, 0xfffcffff, 0xffffffff, 0xffff0100), + SECP256K1_FE_CONST(0x5da42a52, 0x3640de9e, 0x13e64343, 0x0c7591b7, 0x6c1e3519, 0xf048c5b6, 0x0484217c, 0xedbf8b2f)}, + {SECP256K1_FE_CONST(0xd1343ef9, 0x4b952621, 0x7c52a2ee, 0x4ea1281b, 0x4ab46410, 0x9f26998d, 0xa686a8ff, 0x9f2103e8), + SECP256K1_FE_CONST(0x84044385, 0x9a4619bf, 0x74e35b6d, 0xa47e0c46, 0x6b7fb47d, 0x9ffab128, 0xb0775aa3, 0xcb318bd1)}, + {SECP256K1_FE_CONST(0xb27235d2, 0xc56a52be, 0x210db37a, 0xd50d23a4, 0xbe621bdd, 0x5df22c6a, 0xe926ba62, 0xd2e4e440), + SECP256K1_FE_CONST(0x67a26e54, 0x483a9d3c, 0xa568469e, 0xd258ab3d, 0xb9ec9981, 0xdca9b1bd, 0x8d2775fe, 0x53ae429b)}, + {SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00e0ffff, 0xffffff83, 0xffffffff, 0x3f00f00f, 0x000000e0, 0xffffffff), + SECP256K1_FE_CONST(0x310e10f8, 0x23bbfab0, 0xac94907d, 0x076c9a45, 0x8d357d7f, 0xc763bcee, 0x00d0e615, 0x5a6acef6)}, + {SECP256K1_FE_CONST(0xfeff0300, 0x001c0000, 0xf80700c0, 0x0ff0ffff, 0xffffffff, 0x0fffffff, 0xffff0100, 0x7f0000fe), + SECP256K1_FE_CONST(0x28e2fdb4, 0x0709168b, 0x86f598b0, 0x3453a370, 0x530cf21f, 0x32f978d5, 0x1d527a71, 0x59269b0c)}, + {SECP256K1_FE_CONST(0xc2591afa, 0x7bb98ef7, 0x090bb273, 0x85c14f87, 0xbb0b28e0, 0x54d3c453, 0x85c66753, 0xd5574d2f), + SECP256K1_FE_CONST(0xfdca70a2, 0x70ce627c, 0x95e66fae, 0x848a6dbb, 0x07ffb15c, 0x5f63a058, 0xba4140ed, 0x6113b503)}, + {SECP256K1_FE_CONST(0xf5475db3, 0xedc7b5a3, 0x411c047e, 0xeaeb452f, 0xc625828e, 0x1cf5ad27, 0x8eec1060, 0xc7d3e690), + SECP256K1_FE_CONST(0x5eb756c0, 0xf963f4b9, 0xdc6a215e, 0xec8cc2d8, 0x2e9dec01, 0xde5eb88d, 0x6aba7164, 0xaecb2c5a)}, + {SECP256K1_FE_CONST(0x00000000, 0x00f8ffff, 0xffffffff, 0x01000000, 0xe0ff1f00, 0x00000000, 0xffffff7f, 0x00000000), + SECP256K1_FE_CONST(0xe0d2e3d8, 0x49b6157d, 0xe54e88c2, 0x1a7f02ca, 0x7dd28167, 0xf1125d81, 0x7bfa444e, 0xbe110037)}, + /* Selection of randomly generated inputs that reach high/low d/e values in various configurations. */ + {SECP256K1_FE_CONST(0x13cc08a4, 0xd8c41f0f, 0x179c3e67, 0x54c46c67, 0xc4109221, 0x09ab3b13, 0xe24d9be1, 0xffffe950), + SECP256K1_FE_CONST(0xb80c8006, 0xd16abaa7, 0xcabd71e5, 0xcf6714f4, 0x966dd3d0, 0x64767a2d, 0xe92c4441, 0x51008cd1)}, + {SECP256K1_FE_CONST(0xaa6db990, 0x95efbca1, 0x3cc6ff71, 0x0602e24a, 0xf49ff938, 0x99fffc16, 0x46f40993, 0xc6e72057), + SECP256K1_FE_CONST(0xd5d3dd69, 0xb0c195e5, 0x285f1d49, 0xe639e48c, 0x9223f8a9, 0xca1d731d, 0x9ca482f9, 0xa5b93e06)}, + {SECP256K1_FE_CONST(0x1c680eac, 0xaeabffd8, 0x9bdc4aee, 0x1781e3de, 0xa3b08108, 0x0015f2e0, 0x94449e1b, 0x2f67a058), + SECP256K1_FE_CONST(0x7f083f8d, 0x31254f29, 0x6510f475, 0x245c373d, 0xc5622590, 0x4b323393, 0x32ed1719, 0xc127444b)}, + {SECP256K1_FE_CONST(0x147d44b3, 0x012d83f8, 0xc160d386, 0x1a44a870, 0x9ba6be96, 0x8b962707, 0x267cbc1a, 0xb65b2f0a), + SECP256K1_FE_CONST(0x555554ff, 0x170aef1e, 0x50a43002, 0xe51fbd36, 0xafadb458, 0x7a8aded1, 0x0ca6cd33, 0x6ed9087c)}, + {SECP256K1_FE_CONST(0x12423796, 0x22f0fe61, 0xf9ca017c, 0x5384d107, 0xa1fbf3b2, 0x3b018013, 0x916a3c37, 0x4000b98c), + SECP256K1_FE_CONST(0x20257700, 0x08668f94, 0x1177e306, 0x136c01f5, 0x8ed1fbd2, 0x95ec4589, 0xae38edb9, 0xfd19b6d7)}, + {SECP256K1_FE_CONST(0xdcf2d030, 0x9ab42cb4, 0x93ffa181, 0xdcd23619, 0x39699b52, 0x08909a20, 0xb5a17695, 0x3a9dcf21), + SECP256K1_FE_CONST(0x1f701dea, 0xe211fb1f, 0x4f37180d, 0x63a0f51c, 0x29fe1e40, 0xa40b6142, 0x2e7b12eb, 0x982b06b6)}, + {SECP256K1_FE_CONST(0x79a851f6, 0xa6314ed3, 0xb35a55e6, 0xca1c7d7f, 0xe32369ea, 0xf902432e, 0x375308c5, 0xdfd5b600), + SECP256K1_FE_CONST(0xcaae00c5, 0xe6b43851, 0x9dabb737, 0x38cba42c, 0xa02c8549, 0x7895dcbf, 0xbd183d71, 0xafe4476a)}, + {SECP256K1_FE_CONST(0xede78fdd, 0xcfc92bf1, 0x4fec6c6c, 0xdb8d37e2, 0xfb66bc7b, 0x28701870, 0x7fa27c9a, 0x307196ec), + SECP256K1_FE_CONST(0x68193a6c, 0x9a8b87a7, 0x2a760c64, 0x13e473f6, 0x23ae7bed, 0x1de05422, 0x88865427, 0xa3418265)}, + {SECP256K1_FE_CONST(0xa40b2079, 0xb8f88e89, 0xa7617997, 0x89baf5ae, 0x174df343, 0x75138eae, 0x2711595d, 0x3fc3e66c), + SECP256K1_FE_CONST(0x9f99c6a5, 0x6d685267, 0xd4b87c37, 0x9d9c4576, 0x358c692b, 0x6bbae0ed, 0x3389c93d, 0x7fdd2655)}, + {SECP256K1_FE_CONST(0x7c74c6b6, 0xe98d9151, 0x72645cf1, 0x7f06e321, 0xcefee074, 0x15b2113a, 0x10a9be07, 0x08a45696), + SECP256K1_FE_CONST(0x8c919a88, 0x898bc1e0, 0x77f26f97, 0x12e655b7, 0x9ba0ac40, 0xe15bb19e, 0x8364cc3b, 0xe227a8ee)}, + {SECP256K1_FE_CONST(0x109ba1ce, 0xdafa6d4a, 0xa1cec2b2, 0xeb1069f4, 0xb7a79e5b, 0xec6eb99b, 0xaec5f643, 0xee0e723e), + SECP256K1_FE_CONST(0x93d13eb8, 0x4bb0bcf9, 0xe64f5a71, 0xdbe9f359, 0x7191401c, 0x6f057a4a, 0xa407fe1b, 0x7ecb65cc)}, + {SECP256K1_FE_CONST(0x3db076cd, 0xec74a5c9, 0xf61dd138, 0x90e23e06, 0xeeedd2d0, 0x74cbc4e0, 0x3dbe1e91, 0xded36a78), + SECP256K1_FE_CONST(0x3f07f966, 0x8e2a1e09, 0x706c71df, 0x02b5e9d5, 0xcb92ddbf, 0xcdd53010, 0x16545564, 0xe660b107)}, + {SECP256K1_FE_CONST(0xe31c73ed, 0xb4c4b82c, 0x02ae35f7, 0x4cdec153, 0x98b522fd, 0xf7d2460c, 0x6bf7c0f8, 0x4cf67b0d), + SECP256K1_FE_CONST(0x4b8f1faf, 0x94e8b070, 0x19af0ff6, 0xa319cd31, 0xdf0a7ffb, 0xefaba629, 0x59c50666, 0x1fe5b843)}, + {SECP256K1_FE_CONST(0x4c8b0e6e, 0x83392ab6, 0xc0e3e9f1, 0xbbd85497, 0x16698897, 0xf552d50d, 0x79652ddb, 0x12f99870), + SECP256K1_FE_CONST(0x56d5101f, 0xd23b7949, 0x17dc38d6, 0xf24022ef, 0xcf18e70a, 0x5cc34424, 0x438544c3, 0x62da4bca)}, + {SECP256K1_FE_CONST(0xb0e040e2, 0x40cc35da, 0x7dd5c611, 0x7fccb178, 0x28888137, 0xbc930358, 0xea2cbc90, 0x775417dc), + SECP256K1_FE_CONST(0xca37f0d4, 0x016dd7c8, 0xab3ae576, 0x96e08d69, 0x68ed9155, 0xa9b44270, 0x900ae35d, 0x7c7800cd)}, + {SECP256K1_FE_CONST(0x8a32ea49, 0x7fbb0bae, 0x69724a9d, 0x8e2105b2, 0xbdf69178, 0x862577ef, 0x35055590, 0x667ddaef), + SECP256K1_FE_CONST(0xd02d7ead, 0xc5e190f0, 0x559c9d72, 0xdaef1ffc, 0x64f9f425, 0xf43645ea, 0x7341e08d, 0x11768e96)}, + {SECP256K1_FE_CONST(0xa3592d98, 0x9abe289d, 0x579ebea6, 0xbb0857a8, 0xe242ab73, 0x85f9a2ce, 0xb6998f0f, 0xbfffbfc6), + SECP256K1_FE_CONST(0x093c1533, 0x32032efa, 0x6aa46070, 0x0039599e, 0x589c35f4, 0xff525430, 0x7fe3777a, 0x44b43ddc)}, + {SECP256K1_FE_CONST(0x647178a3, 0x229e607b, 0xcc98521a, 0xcce3fdd9, 0x1e1bc9c9, 0x97fb7c6a, 0x61b961e0, 0x99b10709), + SECP256K1_FE_CONST(0x98217c13, 0xd51ddf78, 0x96310e77, 0xdaebd908, 0x602ca683, 0xcb46d07a, 0xa1fcf17e, 0xc8e2feb3)}, + {SECP256K1_FE_CONST(0x7334627c, 0x73f98968, 0x99464b4b, 0xf5964958, 0x1b95870d, 0xc658227e, 0x5e3235d8, 0xdcab5787), + SECP256K1_FE_CONST(0x000006fd, 0xc7e9dd94, 0x40ae367a, 0xe51d495c, 0x07603b9b, 0x2d088418, 0x6cc5c74c, 0x98514307)}, + {SECP256K1_FE_CONST(0x82e83876, 0x96c28938, 0xa50dd1c5, 0x605c3ad1, 0xc048637d, 0x7a50825f, 0x335ed01a, 0x00005760), + SECP256K1_FE_CONST(0xb0393f9f, 0x9f2aa55e, 0xf5607e2e, 0x5287d961, 0x60b3e704, 0xf3e16e80, 0xb4f9a3ea, 0xfec7f02d)}, + {SECP256K1_FE_CONST(0xc97b6cec, 0x3ee6b8dc, 0x98d24b58, 0x3c1970a1, 0xfe06297a, 0xae813529, 0xe76bb6bd, 0x771ae51d), + SECP256K1_FE_CONST(0x0507c702, 0xd407d097, 0x47ddeb06, 0xf6625419, 0x79f48f79, 0x7bf80d0b, 0xfc34b364, 0x253a5db1)}, + {SECP256K1_FE_CONST(0xd559af63, 0x77ea9bc4, 0x3cf1ad14, 0x5c7a4bbb, 0x10e7d18b, 0x7ce0dfac, 0x380bb19d, 0x0bb99bd3), + SECP256K1_FE_CONST(0x00196119, 0xb9b00d92, 0x34edfdb5, 0xbbdc42fc, 0xd2daa33a, 0x163356ca, 0xaa8754c8, 0xb0ec8b0b)}, + {SECP256K1_FE_CONST(0x8ddfa3dc, 0x52918da0, 0x640519dc, 0x0af8512a, 0xca2d33b2, 0xbde52514, 0xda9c0afc, 0xcb29fce4), + SECP256K1_FE_CONST(0xb3e4878d, 0x5cb69148, 0xcd54388b, 0xc23acce0, 0x62518ba8, 0xf09def92, 0x7b31e6aa, 0x6ba35b02)}, + {SECP256K1_FE_CONST(0xf8207492, 0xe3049f0a, 0x65285f2b, 0x0bfff996, 0x00ca112e, 0xc05da837, 0x546d41f9, 0x5194fb91), + SECP256K1_FE_CONST(0x7b7ee50b, 0xa8ed4bbd, 0xf6469930, 0x81419a5c, 0x071441c7, 0x290d046e, 0x3b82ea41, 0x611c5f95)}, + {SECP256K1_FE_CONST(0x050f7c80, 0x5bcd3c6b, 0x823cb724, 0x5ce74db7, 0xa4e39f5c, 0xbd8828d7, 0xfd4d3e07, 0x3ec2926a), + SECP256K1_FE_CONST(0x000d6730, 0xb0171314, 0x4764053d, 0xee157117, 0x48fd61da, 0xdea0b9db, 0x1d5e91c6, 0xbdc3f59e)}, + {SECP256K1_FE_CONST(0x3e3ea8eb, 0x05d760cf, 0x23009263, 0xb3cb3ac9, 0x088f6f0d, 0x3fc182a3, 0xbd57087c, 0xe67c62f9), + SECP256K1_FE_CONST(0xbe988716, 0xa29c1bf6, 0x4456aed6, 0xab1e4720, 0x49929305, 0x51043bf4, 0xebd833dd, 0xdd511e8b)}, + {SECP256K1_FE_CONST(0x6964d2a9, 0xa7fa6501, 0xa5959249, 0x142f4029, 0xea0c1b5f, 0x2f487ef6, 0x301ac80a, 0x768be5cd), + SECP256K1_FE_CONST(0x3918ffe4, 0x07492543, 0xed24d0b7, 0x3df95f8f, 0xaffd7cb4, 0x0de2191c, 0x9ec2f2ad, 0x2c0cb3c6)}, + {SECP256K1_FE_CONST(0x37c93520, 0xf6ddca57, 0x2b42fd5e, 0xb5c7e4de, 0x11b5b81c, 0xb95e91f3, 0x95c4d156, 0x39877ccb), + SECP256K1_FE_CONST(0x9a94b9b5, 0x57eb71ee, 0x4c975b8b, 0xac5262a8, 0x077b0595, 0xe12a6b1f, 0xd728edef, 0x1a6bf956)} + }; + /* Fixed test cases for scalar inverses: pairs of (x, 1/x) mod n. */ + static const secp256k1_scalar scalar_cases[][2] = { + /* 0 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0)}, + /* 1 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1)}, + /* -1 */ + {SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140), + SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140)}, + /* 2 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 2), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5d576e73, 0x57a4501d, 0xdfe92f46, 0x681b20a1)}, + /* 2**128 */ + {SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0), + SECP256K1_SCALAR_CONST(0x50a51ac8, 0x34b9ec24, 0x4b0dff66, 0x5588b13e, 0x9984d5b3, 0xcf80ef0f, 0xd6a23766, 0xa3ee9f22)}, + /* Input known to need 635 divsteps */ + {SECP256K1_SCALAR_CONST(0xcb9f1d35, 0xdd4416c2, 0xcd71bf3f, 0x6365da66, 0x3c9b3376, 0x8feb7ae9, 0x32a5ef60, 0x19199ec3), + SECP256K1_SCALAR_CONST(0x1d7c7bba, 0xf1893d53, 0xb834bd09, 0x36b411dc, 0x42c2e42f, 0xec72c428, 0x5e189791, 0x8e9bc708)}, + /* Input known to need 566 divsteps starting with delta=1/2. */ + {SECP256K1_SCALAR_CONST(0x7e3c993d, 0xa4272488, 0xbc015b49, 0x2db54174, 0xd382083a, 0xebe6db35, 0x80f82eff, 0xcd132c72), + SECP256K1_SCALAR_CONST(0x086f34a0, 0x3e631f76, 0x77418f28, 0xcc84ac95, 0x6304439d, 0x365db268, 0x312c6ded, 0xd0b934f8)}, + /* Input known to need 565 divsteps starting with delta=1/2. */ + {SECP256K1_SCALAR_CONST(0xbad7e587, 0x3f307859, 0x60d93147, 0x8a18491e, 0xb38a9fd5, 0x254350d3, 0x4b1f0e4b, 0x7dd6edc4), + SECP256K1_SCALAR_CONST(0x89f2df26, 0x39e2b041, 0xf19bd876, 0xd039c8ac, 0xc2223add, 0x29c4943e, 0x6632d908, 0x515f467b)}, + /* Selection of randomly generated inputs that reach low/high d/e values in various configurations. */ + {SECP256K1_SCALAR_CONST(0x1950d757, 0xb37a5809, 0x435059bb, 0x0bb8997e, 0x07e1e3c8, 0x5e5d7d2c, 0x6a0ed8e3, 0xdbde180e), + SECP256K1_SCALAR_CONST(0xbf72af9b, 0x750309e2, 0x8dda230b, 0xfe432b93, 0x7e25e475, 0x4388251e, 0x633d894b, 0x3bcb6f8c)}, + {SECP256K1_SCALAR_CONST(0x9bccf4e7, 0xc5a515e3, 0x50637aa9, 0xbb65a13f, 0x391749a1, 0x62de7d4e, 0xf6d7eabb, 0x3cd10ce0), + SECP256K1_SCALAR_CONST(0xaf2d5623, 0xb6385a33, 0xcd0365be, 0x5e92a70d, 0x7f09179c, 0x3baaf30f, 0x8f9cc83b, 0x20092f67)}, + {SECP256K1_SCALAR_CONST(0x73a57111, 0xb242952a, 0x5c5dee59, 0xf3be2ace, 0xa30a7659, 0xa46e5f47, 0xd21267b1, 0x39e642c9), + SECP256K1_SCALAR_CONST(0xa711df07, 0xcbcf13ef, 0xd61cc6be, 0xbcd058ce, 0xb02cf157, 0x272d4a18, 0x86d0feb3, 0xcd5fa004)}, + {SECP256K1_SCALAR_CONST(0x04884963, 0xce0580b1, 0xba547030, 0x3c691db3, 0x9cd2c84f, 0x24c7cebd, 0x97ebfdba, 0x3e785ec2), + SECP256K1_SCALAR_CONST(0xaaaaaf14, 0xd7c99ba7, 0x517ce2c1, 0x78a28b4c, 0x3769a851, 0xe5c5a03d, 0x4cc28f33, 0x0ec4dc5d)}, + {SECP256K1_SCALAR_CONST(0x1679ed49, 0x21f537b1, 0x815cb8ae, 0x9efc511c, 0x5b9fa037, 0x0b0f275e, 0x6c985281, 0x6c4a9905), + SECP256K1_SCALAR_CONST(0xb14ac3d5, 0x62b52999, 0xef34ead1, 0xffca4998, 0x0294341a, 0x1f8172aa, 0xea1624f9, 0x302eea62)}, + {SECP256K1_SCALAR_CONST(0x626b37c0, 0xf0057c35, 0xee982f83, 0x452a1fd3, 0xea826506, 0x48b08a9d, 0x1d2c4799, 0x4ad5f6ec), + SECP256K1_SCALAR_CONST(0xe38643b7, 0x567bfc2f, 0x5d2f1c15, 0xe327239c, 0x07112443, 0x69509283, 0xfd98e77a, 0xdb71c1e8)}, + {SECP256K1_SCALAR_CONST(0x1850a3a7, 0x759efc56, 0x54f287b2, 0x14d1234b, 0xe263bbc9, 0xcf4d8927, 0xd5f85f27, 0x965bd816), + SECP256K1_SCALAR_CONST(0x3b071831, 0xcac9619a, 0xcceb0596, 0xf614d63b, 0x95d0db2f, 0xc6a00901, 0x8eaa2621, 0xabfa0009)}, + {SECP256K1_SCALAR_CONST(0x94ae5d06, 0xa27dc400, 0x487d72be, 0xaa51ebed, 0xe475b5c0, 0xea675ffc, 0xf4df627a, 0xdca4222f), + SECP256K1_SCALAR_CONST(0x01b412ed, 0xd7830956, 0x1532537e, 0xe5e3dc99, 0x8fd3930a, 0x54f8d067, 0x32ef5760, 0x594438a5)}, + {SECP256K1_SCALAR_CONST(0x1f24278a, 0xb5bfe374, 0xa328dbbc, 0xebe35f48, 0x6620e009, 0xd58bb1b4, 0xb5a6bf84, 0x8815f63a), + SECP256K1_SCALAR_CONST(0xfe928416, 0xca5ba2d3, 0xfde513da, 0x903a60c7, 0x9e58ad8a, 0x8783bee4, 0x083a3843, 0xa608c914)}, + {SECP256K1_SCALAR_CONST(0xdc107d58, 0x274f6330, 0x67dba8bc, 0x26093111, 0x5201dfb8, 0x968ce3f5, 0xf34d1bd4, 0xf2146504), + SECP256K1_SCALAR_CONST(0x660cfa90, 0x13c3d93e, 0x7023b1e5, 0xedd09e71, 0x6d9c9d10, 0x7a3d2cdb, 0xdd08edc3, 0xaa78fcfb)}, + {SECP256K1_SCALAR_CONST(0x7cd1e905, 0xc6f02776, 0x2f551cc7, 0x5da61cff, 0x7da05389, 0x1119d5a4, 0x631c7442, 0x894fd4f7), + SECP256K1_SCALAR_CONST(0xff20862a, 0x9d3b1a37, 0x1628803b, 0x3004ccae, 0xaa23282a, 0xa89a1109, 0xd94ece5e, 0x181bdc46)}, + {SECP256K1_SCALAR_CONST(0x5b9dade8, 0x23d26c58, 0xcd12d818, 0x25b8ae97, 0x3dea04af, 0xf482c96b, 0xa062f254, 0x9e453640), + SECP256K1_SCALAR_CONST(0x50c38800, 0x15fa53f4, 0xbe1e5392, 0x5c9b120a, 0x262c22c7, 0x18fa0816, 0x5f2baab4, 0x8cb5db46)}, + {SECP256K1_SCALAR_CONST(0x11cdaeda, 0x969c464b, 0xef1f4ab0, 0x5b01d22e, 0x656fd098, 0x882bea84, 0x65cdbe7a, 0x0c19ff03), + SECP256K1_SCALAR_CONST(0x1968d0fa, 0xac46f103, 0xb55f1f72, 0xb3820bed, 0xec6b359a, 0x4b1ae0ad, 0x7e38e1fb, 0x295ccdfb)}, + {SECP256K1_SCALAR_CONST(0x2c351aa1, 0x26e91589, 0x194f8a1e, 0x06561f66, 0x0cb97b7f, 0x10914454, 0x134d1c03, 0x157266b4), + SECP256K1_SCALAR_CONST(0xbe49ada6, 0x92bd8711, 0x41b176c4, 0xa478ba95, 0x14883434, 0x9d1cd6f3, 0xcc4b847d, 0x22af80f5)}, + {SECP256K1_SCALAR_CONST(0x6ba07c6e, 0x13a60edb, 0x6247f5c3, 0x84b5fa56, 0x76fe3ec5, 0x80426395, 0xf65ec2ae, 0x623ba730), + SECP256K1_SCALAR_CONST(0x25ac23f7, 0x418cd747, 0x98376f9d, 0x4a11c7bf, 0x24c8ebfe, 0x4c8a8655, 0x345f4f52, 0x1c515595)}, + {SECP256K1_SCALAR_CONST(0x9397a712, 0x8abb6951, 0x2d4a3d54, 0x703b1c2a, 0x0661dca8, 0xd75c9b31, 0xaed4d24b, 0xd2ab2948), + SECP256K1_SCALAR_CONST(0xc52e8bef, 0xd55ce3eb, 0x1c897739, 0xeb9fb606, 0x36b9cd57, 0x18c51cc2, 0x6a87489e, 0xffd0dcf3)}, + {SECP256K1_SCALAR_CONST(0xe6a808cc, 0xeb437888, 0xe97798df, 0x4e224e44, 0x7e3b380a, 0x207c1653, 0x889f3212, 0xc6738b6f), + SECP256K1_SCALAR_CONST(0x31f9ae13, 0xd1e08b20, 0x757a2e5e, 0x5243a0eb, 0x8ae35f73, 0x19bb6122, 0xb910f26b, 0xda70aa55)}, + {SECP256K1_SCALAR_CONST(0xd0320548, 0xab0effe7, 0xa70779e0, 0x61a347a6, 0xb8c1e010, 0x9d5281f8, 0x2ee588a6, 0x80000000), + SECP256K1_SCALAR_CONST(0x1541897e, 0x78195c90, 0x7583dd9e, 0x728b6100, 0xbce8bc6d, 0x7a53b471, 0x5dcd9e45, 0x4425fcaf)}, + {SECP256K1_SCALAR_CONST(0x93d623f1, 0xd45b50b0, 0x796e9186, 0x9eac9407, 0xd30edc20, 0xef6304cf, 0x250494e7, 0xba503de9), + SECP256K1_SCALAR_CONST(0x7026d638, 0x1178b548, 0x92043952, 0x3c7fb47c, 0xcd3ea236, 0x31d82b01, 0x612fc387, 0x80b9b957)}, + {SECP256K1_SCALAR_CONST(0xf860ab39, 0x55f5d412, 0xa4d73bcc, 0x3b48bd90, 0xc248ffd3, 0x13ca10be, 0x8fba84cc, 0xdd28d6a3), + SECP256K1_SCALAR_CONST(0x5c32fc70, 0xe0b15d67, 0x76694700, 0xfe62be4d, 0xeacdb229, 0x7a4433d9, 0x52155cd0, 0x7649ab59)}, + {SECP256K1_SCALAR_CONST(0x4e41311c, 0x0800af58, 0x7a690a8e, 0xe175c9ba, 0x6981ab73, 0xac532ea8, 0x5c1f5e63, 0x6ac1f189), + SECP256K1_SCALAR_CONST(0xfffffff9, 0xd075982c, 0x7fbd3825, 0xc05038a2, 0x4533b91f, 0x94ec5f45, 0xb280b28f, 0x842324dc)}, + {SECP256K1_SCALAR_CONST(0x48e473bf, 0x3555eade, 0xad5d7089, 0x2424c4e4, 0x0a99397c, 0x2dc796d8, 0xb7a43a69, 0xd0364141), + SECP256K1_SCALAR_CONST(0x634976b2, 0xa0e47895, 0x1ec38593, 0x266d6fd0, 0x6f602644, 0x9bb762f1, 0x7180c704, 0xe23a4daa)}, + {SECP256K1_SCALAR_CONST(0xbe83878d, 0x3292fc54, 0x26e71c62, 0x556ccedc, 0x7cbb8810, 0x4032a720, 0x34ead589, 0xe4d6bd13), + SECP256K1_SCALAR_CONST(0x6cd150ad, 0x25e59d0f, 0x74cbae3d, 0x6377534a, 0x1e6562e8, 0xb71b9d18, 0xe1e5d712, 0x8480abb3)}, + {SECP256K1_SCALAR_CONST(0xcdddf2e5, 0xefc15f88, 0xc9ee06de, 0x8a846ca9, 0x28561581, 0x68daa5fb, 0xd1cf3451, 0xeb1782d0), + SECP256K1_SCALAR_CONST(0xffffffd9, 0xed8d2af4, 0x993c865a, 0x23e9681a, 0x3ca3a3dc, 0xe6d5a46e, 0xbd86bd87, 0x61b55c70)}, + {SECP256K1_SCALAR_CONST(0xb6a18f1f, 0x04872df9, 0x08165ec4, 0x319ca19c, 0x6c0359ab, 0x1f7118fb, 0xc2ef8082, 0xca8b7785), + SECP256K1_SCALAR_CONST(0xff55b19b, 0x0f1ac78c, 0x0f0c88c2, 0x2358d5ad, 0x5f455e4e, 0x3330b72f, 0x274dc153, 0xffbf272b)}, + {SECP256K1_SCALAR_CONST(0xea4898e5, 0x30eba3e8, 0xcf0e5c3d, 0x06ec6844, 0x01e26fb6, 0x75636225, 0xc5d08f4c, 0x1decafa0), + SECP256K1_SCALAR_CONST(0xe5a014a8, 0xe3c4ec1e, 0xea4f9b32, 0xcfc7b386, 0x00630806, 0x12c08d02, 0x6407ccc2, 0xb067d90e)}, + {SECP256K1_SCALAR_CONST(0x70e9aea9, 0x7e933af0, 0x8a23bfab, 0x23e4b772, 0xff951863, 0x5ffcf47d, 0x6bebc918, 0x2ca58265), + SECP256K1_SCALAR_CONST(0xf4e00006, 0x81bc6441, 0x4eb6ec02, 0xc194a859, 0x80ad7c48, 0xba4e9afb, 0x8b6bdbe0, 0x989d8f77)}, + {SECP256K1_SCALAR_CONST(0x3c56c774, 0x46efe6f0, 0xe93618b8, 0xf9b5a846, 0xd247df61, 0x83b1e215, 0x06dc8bcc, 0xeefc1bf5), + SECP256K1_SCALAR_CONST(0xfff8937a, 0x2cd9586b, 0x43c25e57, 0xd1cefa7a, 0x9fb91ed3, 0x95b6533d, 0x8ad0de5b, 0xafb93f00)}, + {SECP256K1_SCALAR_CONST(0xfb5c2772, 0x5cb30e83, 0xe38264df, 0xe4e3ebf3, 0x392aa92e, 0xa68756a1, 0x51279ac5, 0xb50711a8), + SECP256K1_SCALAR_CONST(0x000013af, 0x1105bfe7, 0xa6bbd7fb, 0x3d638f99, 0x3b266b02, 0x072fb8bc, 0x39251130, 0x2e0fd0ea)} + }; + int i, var, testrand; + unsigned char b32[32]; + secp256k1_fe x_fe; + secp256k1_scalar x_scalar; + memset(b32, 0, sizeof(b32)); + /* Test fixed test cases through test_inverse_{scalar,field}, both ways. */ + for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) { + for (var = 0; var <= 1; ++var) { + test_inverse_field(&x_fe, &fe_cases[i][0], var); + CHECK(fe_equal(&x_fe, &fe_cases[i][1])); + test_inverse_field(&x_fe, &fe_cases[i][1], var); + CHECK(fe_equal(&x_fe, &fe_cases[i][0])); + } + } + for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) { + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var); + CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][1])); + test_inverse_scalar(&x_scalar, &scalar_cases[i][1], var); + CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][0])); + } + } + /* Test inputs 0..999 and their respective negations. */ + for (i = 0; i < 1000; ++i) { + b32[31] = i & 0xff; + b32[30] = (i >> 8) & 0xff; + secp256k1_scalar_set_b32(&x_scalar, b32, NULL); + secp256k1_fe_set_b32_mod(&x_fe, b32); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + secp256k1_scalar_negate(&x_scalar, &x_scalar); + secp256k1_fe_negate(&x_fe, &x_fe, 1); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + } + /* test 128*count random inputs; half with testrand256_test, half with testrand256 */ + for (testrand = 0; testrand <= 1; ++testrand) { + for (i = 0; i < 64 * COUNT; ++i) { + (testrand ? testrand256_test : testrand256)(b32); + secp256k1_scalar_set_b32(&x_scalar, b32, NULL); + secp256k1_fe_set_b32_mod(&x_fe, b32); + for (var = 0; var <= 1; ++var) { + test_inverse_scalar(NULL, &x_scalar, var); + test_inverse_field(NULL, &x_fe, var); + } + } + } +} + +/***** HSORT TESTS *****/ + +static void test_heap_swap(void) { + unsigned char a[600]; + unsigned char e[sizeof(a)]; + memset(a, 21, 200); + memset(a + 200, 99, 200); + memset(a + 400, 42, 200); + memset(e, 42, 200); + memset(e + 200, 99, 200); + memset(e + 400, 21, 200); + secp256k1_heap_swap(a, 0, 2, 200); + CHECK(secp256k1_memcmp_var(a, e, sizeof(a)) == 0); +} + +static void test_hsort_is_sorted(unsigned char *elements, size_t n, size_t len) { + size_t i; + for (i = 1; i < n; i++) { + CHECK(secp256k1_memcmp_var(&elements[(i-1) * len], &elements[i * len], len) <= 0); + } +} + +struct test_hsort_cmp_data { + size_t counter; + size_t element_len; +}; + + +static int test_hsort_cmp(const void *ele1, const void *ele2, void *data) { + struct test_hsort_cmp_data *d = (struct test_hsort_cmp_data *) data; + d->counter += 1; + return secp256k1_memcmp_var((unsigned char *)ele1, (unsigned char *)ele2, d->element_len); +} + +#define NUM 65 +#define MAX_ELEMENT_LEN 65 +static void test_hsort(size_t element_len) { + unsigned char elements[NUM * MAX_ELEMENT_LEN] = { 0 }; + struct test_hsort_cmp_data data; + int i; + + VERIFY_CHECK(element_len <= MAX_ELEMENT_LEN); + data.counter = 0; + data.element_len = element_len; + + secp256k1_hsort(elements, 0, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + secp256k1_hsort(elements, 1, element_len, test_hsort_cmp, &data); + CHECK(data.counter == 0); + secp256k1_hsort(elements, NUM, element_len, test_hsort_cmp, &data); + CHECK(data.counter >= NUM - 1); + test_hsort_is_sorted(elements, NUM, element_len); + + /* Test hsort with array of random length n */ + for (i = 0; i < COUNT; i++) { + int n = testrand_int(NUM); + testrand_bytes_test(elements, n*element_len); + secp256k1_hsort(elements, n, element_len, test_hsort_cmp, &data); + test_hsort_is_sorted(elements, n, element_len); + } +} +#undef NUM +#undef MAX_ELEMENT_LEN + + +static void run_hsort_tests(void) { + test_heap_swap(); + test_hsort(1); + test_hsort(64); + test_hsort(65); } +/***** GROUP TESTS *****/ + /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { +static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej a2; secp256k1_gej b2; int ret = 1; @@ -1848,101 +3656,70 @@ int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { return ret; } -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - secp256k1_fe_sqr(&z2s, &b->z); - secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); - secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); -} - -void test_ge(void) { +static void test_ge(void) { int i, i1; -#ifdef USE_ENDOMORPHISM int runs = 6; -#else - int runs = 4; -#endif - /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). - * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. - * All magnitudes are randomized. - * All 17*17 combinations of points are added to each other, using all applicable methods. - * - * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. + /* 25 points are used: + * - infinity + * - for each of four random points p1 p2 p3 p4, we add the point, its + * negation, and then those two again but with randomized Z coordinate. + * - The same is then done for lambda*p1 and lambda^2*p1. */ - secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs)); - secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs)); - secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); - secp256k1_fe zf; + secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe zf, r; secp256k1_fe zfi2, zfi3; secp256k1_gej_set_infinity(&gej[0]); - secp256k1_ge_clear(&ge[0]); - secp256k1_ge_set_gej_var(&ge[0], &gej[0]); + secp256k1_ge_set_infinity(&ge[0]); for (i = 0; i < runs; i++) { - int j; + int j, k; secp256k1_ge g; - random_group_element_test(&g); -#ifdef USE_ENDOMORPHISM + testutil_random_ge_test(&g); if (i >= runs - 2) { secp256k1_ge_mul_lambda(&g, &ge[1]); + CHECK(!secp256k1_ge_eq_var(&g, &ge[1])); } if (i >= runs - 1) { secp256k1_ge_mul_lambda(&g, &g); } -#endif ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; secp256k1_ge_neg(&ge[3 + 4 * i], &g); secp256k1_ge_neg(&ge[4 + 4 * i], &g); secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); - random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); - random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + testutil_random_ge_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); for (j = 0; j < 4; j++) { - random_field_element_magnitude(&ge[1 + j + 4 * i].x); - random_field_element_magnitude(&ge[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].x); - random_field_element_magnitude(&gej[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].z); + testutil_random_ge_x_magnitude(&ge[1 + j + 4 * i]); + testutil_random_ge_y_magnitude(&ge[1 + j + 4 * i]); + testutil_random_gej_x_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_y_magnitude(&gej[1 + j + 4 * i]); + testutil_random_gej_z_magnitude(&gej[1 + j + 4 * i]); } - } - /* Compute z inverses. */ - { - secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); - for (i = 0; i < 4 * runs + 1; i++) { - if (i == 0) { - /* The point at infinity does not have a meaningful z inverse. Any should do. */ - do { - random_field_element_test(&zs[i]); - } while(secp256k1_fe_is_zero(&zs[i])); - } else { - zs[i] = gej[i].z; + for (j = 0; j < 4; ++j) { + for (k = 0; k < 4; ++k) { + int expect_equal = (j >> 1) == (k >> 1); + CHECK(secp256k1_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal); } } - secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); - free(zs); } /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ - do { - random_field_element_test(&zf); - } while(secp256k1_fe_is_zero(&zf)); - random_field_element_magnitude(&zf); + testutil_random_fe_non_zero_test(&zf); + testutil_random_fe_magnitude(&zf, 8); secp256k1_fe_inv_var(&zfi3, &zf); secp256k1_fe_sqr(&zfi2, &zfi3); secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); + /* Generate random r */ + testutil_random_fe_non_zero_test(&r); + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { int i2; for (i2 = 0; i2 < 1 + 4 * runs; i2++) { @@ -1954,16 +3731,16 @@ void test_ge(void) { /* Check Z ratio. */ if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + CHECK(secp256k1_fe_equal(&zrz, &refj.z)); } secp256k1_ge_set_gej_var(&ref, &refj); /* Test gej + ge with Z ratio result (var). */ secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + CHECK(secp256k1_fe_equal(&zrz, &resj.z)); } /* Test gej + ge (var, with additional Z factor). */ @@ -1971,17 +3748,17 @@ void test_ge(void) { secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - random_field_element_magnitude(&ge2_zfi.x); - random_field_element_magnitude(&ge2_zfi.y); + testutil_random_ge_x_magnitude(&ge2_zfi); + testutil_random_ge_y_magnitude(&ge2_zfi); secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test gej + ge (const). */ if (i2 != 0) { /* secp256k1_gej_add_ge does not support its second argument being infinity. */ secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test doubling (var). */ @@ -1989,13 +3766,16 @@ void test_ge(void) { secp256k1_fe zr2; /* Normal doubling with Z ratio result. */ secp256k1_gej_double_var(&resj, &gej[i1], &zr2); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); /* Check Z ratio. */ secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + CHECK(secp256k1_fe_equal(&zr2, &resj.z)); /* Normal doubling. */ secp256k1_gej_double_var(&resj, &gej[i2], NULL); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); + /* Constant-time doubling. */ + secp256k1_gej_double(&resj, &gej[i2]); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test adding opposites. */ @@ -2007,12 +3787,12 @@ void test_ge(void) { if (i1 == 0) { CHECK(secp256k1_ge_is_infinity(&ge[i1])); CHECK(secp256k1_gej_is_infinity(&gej[i1])); - ge_equals_gej(&ref, &gej[i2]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i2], &ref)); } if (i2 == 0) { CHECK(secp256k1_ge_is_infinity(&ge[i2])); CHECK(secp256k1_gej_is_infinity(&gej[i2])); - ge_equals_gej(&ref, &gej[i1]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i1], &ref)); } } } @@ -2020,12 +3800,12 @@ void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej)); + secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand_int(4 * runs + 1 - i); + int swap = i + testrand_int(4 * runs + 1 - i); if (swap != i) { secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; @@ -2039,37 +3819,109 @@ void test_ge(void) { free(gej_shuffled); } - /* Test batch gej -> ge conversion with and without known z ratios. */ + /* Test batch gej -> ge conversion without known z ratios. */ { - secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe)); - secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); - secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); - for (i = 0; i < 4 * runs + 1; i++) { - /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ - if (i < 4 * runs) { - secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); - } - } - secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); - secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); + secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe s; - random_fe_non_zero(&s); + testutil_random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); - ge_equals_gej(&ge_set_table[i], &gej[i]); - ge_equals_gej(&ge_set_all[i], &gej[i]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); } - free(ge_set_table); free(ge_set_all); - free(zr); + } + + /* Test that all elements have X coordinates on the curve. */ + for (i = 1; i < 4 * runs + 1; i++) { + secp256k1_fe n; + CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x)); + /* And the same holds after random rescaling. */ + secp256k1_fe_mul(&n, &zf, &ge[i].x); + CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf)); + } + + /* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */ + { + secp256k1_fe n; + secp256k1_ge q; + int ret_on_curve, ret_frac_on_curve, ret_set_xo; + secp256k1_fe_mul(&n, &zf, &r); + ret_on_curve = secp256k1_ge_x_on_curve_var(&r); + ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf); + ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0); + CHECK(ret_on_curve == ret_frac_on_curve); + CHECK(ret_on_curve == ret_set_xo); + if (ret_set_xo) CHECK(secp256k1_fe_equal(&r, &q.x)); + } + + /* Test batch gej -> ge conversion with many infinities. */ + for (i = 0; i < 4 * runs + 1; i++) { + int odd; + testutil_random_ge_test(&ge[i]); + odd = secp256k1_fe_is_odd(&ge[i].x); + CHECK(odd == 0 || odd == 1); + /* randomly set half the points to infinity */ + if (odd == i % 2) { + secp256k1_ge_set_infinity(&ge[i]); + } + secp256k1_gej_set_ge(&gej[i], &ge[i]); + } + /* batch convert */ + secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + /* check result */ + for (i = 0; i < 4 * runs + 1; i++) { + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge[i])); + } + + /* Test batch gej -> ge conversion with all infinities. */ + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_set_infinity(&gej[i]); + } + /* batch convert */ + secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + /* check result */ + for (i = 0; i < 4 * runs + 1; i++) { + CHECK(secp256k1_ge_is_infinity(&ge[i])); } free(ge); free(gej); - free(zinv); } -void test_add_neg_y_diff_x(void) { +static void test_intialized_inf(void) { + secp256k1_ge p; + secp256k1_gej pj, npj, infj1, infj2, infj3; + secp256k1_fe zinv; + + /* Test that adding P+(-P) results in a fully initialized infinity*/ + testutil_random_ge_test(&p); + secp256k1_gej_set_ge(&pj, &p); + secp256k1_gej_neg(&npj, &pj); + + secp256k1_gej_add_var(&infj1, &pj, &npj, NULL); + CHECK(secp256k1_gej_is_infinity(&infj1)); + CHECK(secp256k1_fe_is_zero(&infj1.x)); + CHECK(secp256k1_fe_is_zero(&infj1.y)); + CHECK(secp256k1_fe_is_zero(&infj1.z)); + + secp256k1_gej_add_ge_var(&infj2, &npj, &p, NULL); + CHECK(secp256k1_gej_is_infinity(&infj2)); + CHECK(secp256k1_fe_is_zero(&infj2.x)); + CHECK(secp256k1_fe_is_zero(&infj2.y)); + CHECK(secp256k1_fe_is_zero(&infj2.z)); + + secp256k1_fe_set_int(&zinv, 1); + secp256k1_gej_add_zinv_var(&infj3, &npj, &p, &zinv); + CHECK(secp256k1_gej_is_infinity(&infj3)); + CHECK(secp256k1_fe_is_zero(&infj3.x)); + CHECK(secp256k1_fe_is_zero(&infj3.y)); + CHECK(secp256k1_fe_is_zero(&infj3.z)); + + +} + +static void test_add_neg_y_diff_x(void) { /* The point of this test is to check that we can add two points * whose y-coordinates are negatives of each other but whose x * coordinates differ. If the x-coordinates were the same, these @@ -2083,22 +3935,15 @@ void test_add_neg_y_diff_x(void) { * which this test is a regression test for. * * These points were generated in sage as - * # secp256k1 params - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (7)]) - * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) - * N = FiniteField(G.order()) * - * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) - * x = polygen(N) - * lam = (1 - x^3).roots()[1][0] + * load("secp256k1_params.sage") * * # random "bad pair" * P = C.random_element() - * Q = -int(lam) * P - * print " P: %x %x" % P.xy() - * print " Q: %x %x" % Q.xy() - * print "P + Q: %x %x" % (P + Q).xy() + * Q = -int(LAMBDA) * P + * print(" P: %x %x" % P.xy()) + * print(" Q: %x %x" % Q.xy()) + * print("P + Q: %x %x" % (P + Q).xy()) */ secp256k1_gej aj = SECP256K1_GEJ_CONST( 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, @@ -2125,27 +3970,101 @@ void test_add_neg_y_diff_x(void) { secp256k1_gej_add_var(&resj, &aj, &bj, NULL); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); secp256k1_gej_add_ge(&resj, &aj, &b); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); +} + +static void test_ge_bytes(void) { + int i; + + for (i = 0; i < COUNT + 1; i++) { + unsigned char buf[64]; + secp256k1_ge p, q; + + if (i == 0) { + secp256k1_ge_set_infinity(&p); + } else { + testutil_random_ge_test(&p); + } + + if (!secp256k1_ge_is_infinity(&p)) { + secp256k1_ge_to_bytes(buf, &p); + + secp256k1_ge_from_bytes(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } + secp256k1_ge_to_bytes_ext(buf, &p); + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } } -void run_ge(void) { +static void run_ge(void) { int i; - for (i = 0; i < count * 32; i++) { + for (i = 0; i < COUNT * 32; i++) { test_ge(); } test_add_neg_y_diff_x(); + test_intialized_inf(); + test_ge_bytes(); +} + +static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej t = *a; + secp256k1_gej_cmov(&t, b, 0); + CHECK(gej_xyz_equals_gej(&t, a)); + secp256k1_gej_cmov(&t, b, 1); + CHECK(gej_xyz_equals_gej(&t, b)); +} + +static void run_gej(void) { + int i; + secp256k1_gej a, b; + + /* Tests for secp256k1_gej_cmov */ + for (i = 0; i < COUNT; i++) { + secp256k1_gej_set_infinity(&a); + secp256k1_gej_set_infinity(&b); + test_gej_cmov(&a, &b); + + testutil_random_gej_test(&a); + test_gej_cmov(&a, &b); + test_gej_cmov(&b, &a); + + b = a; + test_gej_cmov(&a, &b); + + testutil_random_gej_test(&b); + test_gej_cmov(&a, &b); + test_gej_cmov(&b, &a); + } + + /* Tests for secp256k1_gej_eq_var */ + for (i = 0; i < COUNT; i++) { + secp256k1_fe fe; + testutil_random_gej_test(&a); + testutil_random_gej_test(&b); + CHECK(!secp256k1_gej_eq_var(&a, &b)); + + b = a; + testutil_random_fe_non_zero_test(&fe); + secp256k1_gej_rescale(&a, &fe); + CHECK(secp256k1_gej_eq_var(&a, &b)); + } } -void test_ec_combine(void) { - secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); +static void test_ec_combine(void) { + secp256k1_scalar sum = secp256k1_scalar_zero; secp256k1_pubkey data[6]; const secp256k1_pubkey* d[6]; secp256k1_pubkey sd; @@ -2155,103 +4074,148 @@ void test_ec_combine(void) { int i; for (i = 1; i <= 6; i++) { secp256k1_scalar s; - random_scalar_order_test(&s); + testutil_random_scalar_order_test(&s); secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); secp256k1_ge_set_gej(&Q, &Qj); secp256k1_pubkey_save(&data[i - 1], &Q); d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); secp256k1_ge_set_gej(&Q, &Qj); secp256k1_pubkey_save(&sd, &Q); - CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); - CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); + CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); } } -void run_ec_combine(void) { +static void run_ec_combine(void) { int i; - for (i = 0; i < count * 8; i++) { + for (i = 0; i < COUNT * 8; i++) { test_ec_combine(); } } -void test_group_decompress(const secp256k1_fe* x) { +static void test_group_decompress(const secp256k1_fe* x) { /* The input itself, normalized. */ secp256k1_fe fex = *x; - secp256k1_fe fez; - /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ - secp256k1_ge ge_quad, ge_even, ge_odd; - secp256k1_gej gej_quad; + /* Results of set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_even, ge_odd; /* Return values of the above calls. */ - int res_quad, res_even, res_odd; + int res_even, res_odd; secp256k1_fe_normalize_var(&fex); - res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); - CHECK(res_quad == res_even); - CHECK(res_quad == res_odd); + CHECK(res_even == res_odd); - if (res_quad) { - secp256k1_fe_normalize_var(&ge_quad.x); + if (res_even) { secp256k1_fe_normalize_var(&ge_odd.x); secp256k1_fe_normalize_var(&ge_even.x); - secp256k1_fe_normalize_var(&ge_quad.y); secp256k1_fe_normalize_var(&ge_odd.y); secp256k1_fe_normalize_var(&ge_even.y); /* No infinity allowed. */ - CHECK(!ge_quad.infinity); CHECK(!ge_even.infinity); CHECK(!ge_odd.infinity); /* Check that the x coordinates check out. */ - CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); - - /* Check that the Y coordinate result in ge_quad is a square. */ - CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); + CHECK(secp256k1_fe_equal(&ge_even.x, x)); + CHECK(secp256k1_fe_equal(&ge_odd.x, x)); /* Check odd/even Y in ge_odd, ge_even. */ CHECK(secp256k1_fe_is_odd(&ge_odd.y)); CHECK(!secp256k1_fe_is_odd(&ge_even.y)); - - /* Check secp256k1_gej_has_quad_y_var. */ - secp256k1_gej_set_ge(&gej_quad, &ge_quad); - CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); - do { - random_fe_test(&fez); - } while (secp256k1_fe_is_zero(&fez)); - secp256k1_gej_rescale(&gej_quad, &fez); - CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); - secp256k1_gej_neg(&gej_quad, &gej_quad); - CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); - do { - random_fe_test(&fez); - } while (secp256k1_fe_is_zero(&fez)); - secp256k1_gej_rescale(&gej_quad, &fez); - CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); - secp256k1_gej_neg(&gej_quad, &gej_quad); - CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); } } -void run_group_decompress(void) { +static void run_group_decompress(void) { int i; - for (i = 0; i < count * 4; i++) { + for (i = 0; i < COUNT * 4; i++) { secp256k1_fe fe; - random_fe_test(&fe); + testutil_random_fe_test(&fe); test_group_decompress(&fe); } } /***** ECMULT TESTS *****/ -void run_ecmult_chain(void) { +static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { + /* Tests the pre_g / pre_g_128 tables for consistency. + * For independent verification we take a "geometric" approach to verification. + * We check that every entry is on-curve. + * We check that for consecutive entries p and q, that p + gg - q = 0 by checking + * (1) p, gg, and -q are colinear. + * (2) p, gg, and -q are all distinct. + * where gg is twice the generator, where the generator is the first table entry. + * + * Checking the table's generators are correct is done in run_ecmult_pre_g. + */ + secp256k1_gej g2; + secp256k1_ge p, q, gg; + secp256k1_fe dpx, dpy, dqx, dqy; + size_t i; + + CHECK(0 < n); + + secp256k1_ge_from_storage(&p, &pre_g[0]); + CHECK(secp256k1_ge_is_valid_var(&p)); + + secp256k1_gej_set_ge(&g2, &p); + secp256k1_gej_double_var(&g2, &g2, NULL); + secp256k1_ge_set_gej_var(&gg, &g2); + for (i = 1; i < n; ++i) { + secp256k1_fe_negate(&dpx, &p.x, 1); secp256k1_fe_add(&dpx, &gg.x); secp256k1_fe_normalize_weak(&dpx); + secp256k1_fe_negate(&dpy, &p.y, 1); secp256k1_fe_add(&dpy, &gg.y); secp256k1_fe_normalize_weak(&dpy); + /* Check that p is not equal to gg */ + CHECK(!secp256k1_fe_normalizes_to_zero_var(&dpx) || !secp256k1_fe_normalizes_to_zero_var(&dpy)); + + secp256k1_ge_from_storage(&q, &pre_g[i]); + CHECK(secp256k1_ge_is_valid_var(&q)); + + secp256k1_fe_negate(&dqx, &q.x, 1); secp256k1_fe_add(&dqx, &gg.x); + dqy = q.y; secp256k1_fe_add(&dqy, &gg.y); + /* Check that -q is not equal to gg */ + CHECK(!secp256k1_fe_normalizes_to_zero_var(&dqx) || !secp256k1_fe_normalizes_to_zero_var(&dqy)); + + /* Check that -q is not equal to p */ + CHECK(!secp256k1_fe_equal(&dpx, &dqx) || !secp256k1_fe_equal(&dpy, &dqy)); + + /* Check that p, -q and gg are colinear */ + secp256k1_fe_mul(&dpx, &dpx, &dqy); + secp256k1_fe_mul(&dpy, &dpy, &dqx); + CHECK(secp256k1_fe_equal(&dpx, &dpy)); + + p = q; + } +} + +static void run_ecmult_pre_g(void) { + secp256k1_ge_storage gs; + secp256k1_gej gj; + secp256k1_ge g; + size_t i; + + /* Check that the pre_g and pre_g_128 tables are consistent. */ + test_pre_g_table(secp256k1_pre_g, ECMULT_TABLE_SIZE(WINDOW_G)); + test_pre_g_table(secp256k1_pre_g_128, ECMULT_TABLE_SIZE(WINDOW_G)); + + /* Check the first entry from the pre_g table. */ + secp256k1_ge_to_storage(&gs, &secp256k1_ge_const_g); + CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g[0], sizeof(gs)) == 0); + + /* Check the first entry from the pre_g_128 table. */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + for (i = 0; i < 128; ++i) { + secp256k1_gej_double_var(&gj, &gj, NULL); + } + secp256k1_ge_set_gej(&g, &gj); + secp256k1_ge_to_storage(&gs, &g); + CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g_128[0], sizeof(gs)) == 0); +} + +static void run_ecmult_chain(void) { /* random starting point A (on the curve) */ secp256k1_gej a = SECP256K1_GEJ_CONST( 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, @@ -2272,8 +4236,8 @@ void run_ecmult_chain(void) { static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar ae = secp256k1_scalar_one; + secp256k1_scalar ge = secp256k1_scalar_zero; /* actual points */ secp256k1_gej x; secp256k1_gej x2; @@ -2281,9 +4245,9 @@ void run_ecmult_chain(void) { /* the point being computed */ x = a; - for (i = 0; i < 200*count; i++) { + for (i = 0; i < 200*COUNT; i++) { /* in each iteration, compute X = xn*X + gn*G; */ - secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); + secp256k1_ecmult(&x, &x, &xn, &gn); /* also compute ae and ge: the actual accumulated factors for A and G */ /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ secp256k1_scalar_mul(&ae, &ae, &xn); @@ -2302,36 +4266,28 @@ void run_ecmult_chain(void) { 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 ); - - secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&rp)); + CHECK(secp256k1_gej_eq_var(&rp, &x)); } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ - secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); - secp256k1_gej_neg(&x2, &x2); - secp256k1_gej_add_var(&x2, &x2, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&x2)); + secp256k1_ecmult(&x2, &a, &ae, &ge); + CHECK(secp256k1_gej_eq_var(&x, &x2)); } -void test_point_times_order(const secp256k1_gej *point) { +static void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ secp256k1_scalar x; secp256k1_scalar nx; - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_gej res1, res2; secp256k1_ge res3; unsigned char pub[65]; size_t psize = 65; - random_scalar_order_test(&x); + testutil_random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ secp256k1_gej_add_var(&res1, &res1, &res2, NULL); CHECK(secp256k1_gej_is_infinity(&res1)); - CHECK(secp256k1_gej_is_valid_var(&res1) == 0); secp256k1_ge_set_gej(&res3, &res1); CHECK(secp256k1_ge_is_infinity(&res3)); CHECK(secp256k1_ge_is_valid_var(&res3) == 0); @@ -2339,18 +4295,98 @@ void test_point_times_order(const secp256k1_gej *point) { psize = 65; CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); /* check zero/one edge cases */ - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res3, &res1); CHECK(secp256k1_ge_is_infinity(&res3)); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res3, &res1); - ge_equals_gej(&res3, point); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + CHECK(secp256k1_gej_eq_ge_var(point, &res3)); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res3, &res1); - ge_equals_ge(&res3, &secp256k1_ge_const_g); + CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3)); +} + +/* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda. + * + * They are computed as: + * - For a in [-2, -1, 0, 1, 2]: + * - For b in [-3, -1, 1, 3]: + * - Output (a*LAMBDA + (ORDER+b)/2) % ORDER + */ +static const secp256k1_scalar scalars_near_split_bounds[20] = { + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fc), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fd), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fe), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6ff), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632d), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632e), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632f), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf76330), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b209f), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a0), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a1), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a2), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede11), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede12), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede13), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede14), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a42), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a43), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a44), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) +}; + +static void test_ecmult_target(const secp256k1_scalar* target, int mode) { + /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ + secp256k1_scalar n1, n2; + secp256k1_ge p; + secp256k1_gej pj, p1j, p2j, ptj; + + /* Generate random n1,n2 such that n1+n2 = -target. */ + testutil_random_scalar_order_test(&n1); + secp256k1_scalar_add(&n2, &n1, target); + secp256k1_scalar_negate(&n2, &n2); + + /* Generate a random input point. */ + if (mode != 0) { + testutil_random_ge_test(&p); + secp256k1_gej_set_ge(&pj, &p); + } + + /* EC multiplications */ + if (mode == 0) { + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); + } else if (mode == 1) { + secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); + secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); + secp256k1_ecmult(&ptj, &pj, target, &secp256k1_scalar_zero); + } else { + secp256k1_ecmult_const(&p1j, &p, &n1); + secp256k1_ecmult_const(&p2j, &p, &n2); + secp256k1_ecmult_const(&ptj, &p, target); + } + + /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ + secp256k1_gej_add_var(&ptj, &ptj, &p1j, NULL); + secp256k1_gej_add_var(&ptj, &ptj, &p2j, NULL); + CHECK(secp256k1_gej_is_infinity(&ptj)); +} + +static void run_ecmult_near_split_bound(void) { + int i; + unsigned j; + for (i = 0; i < 4*COUNT; ++i) { + for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) { + test_ecmult_target(&scalars_near_split_bounds[j], 0); + test_ecmult_target(&scalars_near_split_bounds[j], 1); + test_ecmult_target(&scalars_near_split_bounds[j], 2); + } + } } -void run_point_times_order(void) { +static void run_point_times_order(void) { int i; secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); static const secp256k1_fe xr = SECP256K1_FE_CONST( @@ -2363,16 +4399,15 @@ void run_point_times_order(void) { secp256k1_gej j; CHECK(secp256k1_ge_is_valid_var(&p)); secp256k1_gej_set_ge(&j, &p); - CHECK(secp256k1_gej_is_valid_var(&j)); test_point_times_order(&j); } secp256k1_fe_sqr(&x, &x); } secp256k1_fe_normalize_var(&x); - CHECK(secp256k1_fe_equal_var(&x, &xr)); + CHECK(secp256k1_fe_equal(&x, &xr)); } -void ecmult_const_random_mult(void) { +static void ecmult_const_random_mult(void) { /* random starting point A (on the curve) */ secp256k1_ge a = SECP256K1_GE_CONST( 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, @@ -2396,18 +4431,18 @@ void ecmult_const_random_mult(void) { secp256k1_ecmult_const(&b, &a, &xn); CHECK(secp256k1_ge_is_valid_var(&a)); - ge_equals_gej(&expected_b, &b); + CHECK(secp256k1_gej_eq_ge_var(&b, &expected_b)); } -void ecmult_const_commutativity(void) { +static void ecmult_const_commutativity(void) { secp256k1_scalar a; secp256k1_scalar b; secp256k1_gej res1; secp256k1_gej res2; secp256k1_ge mid1; secp256k1_ge mid2; - random_scalar_order_test(&a); - random_scalar_order_test(&b); + testutil_random_scalar_order_test(&a); + testutil_random_scalar_order_test(&b); secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); @@ -2417,32 +4452,134 @@ void ecmult_const_commutativity(void) { secp256k1_ecmult_const(&res2, &mid2, &a); secp256k1_ge_set_gej(&mid1, &res1); secp256k1_ge_set_gej(&mid2, &res2); - ge_equals_ge(&mid1, &mid2); + CHECK(secp256k1_ge_eq_var(&mid1, &mid2)); } -void ecmult_const_mult_zero_one(void) { - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); +static void ecmult_const_mult_zero_one(void) { + secp256k1_scalar s; secp256k1_scalar negone; secp256k1_gej res1; secp256k1_ge res2; secp256k1_ge point; - secp256k1_scalar_negate(&negone, &one); + secp256k1_ge inf; - random_group_element_test(&point); - secp256k1_ecmult_const(&res1, &point, &zero); - secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecmult_const(&res1, &point, &one); + testutil_random_scalar_order_test(&s); + secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); + testutil_random_ge_test(&point); + secp256k1_ge_set_infinity(&inf); + + /* 0*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* s*inf */ + secp256k1_ecmult_const(&res1, &inf, &s); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* 1*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); + CHECK(secp256k1_ge_eq_var(&res2, &point)); + + /* -1*point */ secp256k1_ecmult_const(&res1, &point, &negone); secp256k1_gej_neg(&res1, &res1); secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); + CHECK(secp256k1_ge_eq_var(&res2, &point)); +} + +static void ecmult_const_check_result(const secp256k1_ge *A, const secp256k1_scalar* q, const secp256k1_gej *res) { + secp256k1_gej pointj, res2j; + secp256k1_ge res2; + secp256k1_gej_set_ge(&pointj, A); + secp256k1_ecmult(&res2j, &pointj, q, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(&res2, &res2j); + CHECK(secp256k1_gej_eq_ge_var(res, &res2)); +} + +static void ecmult_const_edges(void) { + secp256k1_scalar q; + secp256k1_ge point; + secp256k1_gej res; + size_t i; + size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); + + /* We are trying to reach the following edge cases (variables are defined as + * in ecmult_const_impl.h): + * 1. i = 0: s = 0 <=> q = -K + * 2. i > 0: v1, v2 large values + * <=> s1, s2 large values + * <=> s = scalars_near_split_bounds[i] + * <=> q = 2*scalars_near_split_bounds[i] - K + */ + for (i = 0; i < cases; ++i) { + secp256k1_scalar_negate(&q, &secp256k1_ecmult_const_K); + if (i > 0) { + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + } + testutil_random_ge_test(&point); + secp256k1_ecmult_const(&res, &point, &q); + ecmult_const_check_result(&point, &q, &res); + } +} + +static void ecmult_const_mult_xonly(void) { + int i; + + /* Test correspondence between secp256k1_ecmult_const and secp256k1_ecmult_const_xonly. */ + for (i = 0; i < 2*COUNT; ++i) { + secp256k1_ge base; + secp256k1_gej basej, resj; + secp256k1_fe n, d, resx, v; + secp256k1_scalar q; + int res; + /* Random base point. */ + testutil_random_ge_test(&base); + /* Random scalar to multiply it with. */ + testutil_random_scalar_order_test(&q); + /* If i is odd, n=d*base.x for random non-zero d */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + secp256k1_fe_mul(&n, &base.x, &d); + } else { + n = base.x; + } + /* Perform x-only multiplication. */ + res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2); + CHECK(res); + /* Perform normal multiplication. */ + secp256k1_gej_set_ge(&basej, &base); + secp256k1_ecmult(&resj, &basej, &q, NULL); + /* Check that resj's X coordinate corresponds with resx. */ + secp256k1_fe_sqr(&v, &resj.z); + secp256k1_fe_mul(&v, &v, &resx); + CHECK(fe_equal(&v, &resj.x)); + } + + /* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */ + for (i = 0; i < 2*COUNT; ++i) { + secp256k1_fe x, n, d, r; + int res; + secp256k1_scalar q; + testutil_random_scalar_order_test(&q); + /* Generate random X coordinate not on the curve. */ + do { + testutil_random_fe_test(&x); + } while (secp256k1_ge_x_on_curve_var(&x)); + /* If i is odd, n=d*x for random non-zero d. */ + if (i & 1) { + testutil_random_fe_non_zero_test(&d); + secp256k1_fe_mul(&n, &x, &d); + } else { + n = x; + } + res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0); + CHECK(res == 0); + } } -void ecmult_const_chain_multiply(void) { +static void ecmult_const_chain_multiply(void) { /* Check known result (randomly generated test problem from sage) */ const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, @@ -2465,17 +4602,639 @@ void ecmult_const_chain_multiply(void) { secp256k1_ecmult_const(&point, &tmp, &scalar); } secp256k1_ge_set_gej(&res, &point); - ge_equals_gej(&res, &expected_point); + CHECK(secp256k1_gej_eq_ge_var(&expected_point, &res)); } -void run_ecmult_const_tests(void) { +static void run_ecmult_const_tests(void) { ecmult_const_mult_zero_one(); + ecmult_const_edges(); ecmult_const_random_mult(); ecmult_const_commutativity(); ecmult_const_chain_multiply(); + ecmult_const_mult_xonly(); +} + +typedef struct { + secp256k1_scalar *sc; + secp256k1_ge *pt; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + (void)sc; + (void)pt; + (void)idx; + (void)cbdata; + return 0; +} + +static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { + int ncount; + secp256k1_scalar sc[32]; + secp256k1_ge pt[32]; + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + + data.sc = sc; + data.pt = pt; + + /* No points to multiply */ + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + + /* Check 1- and 2-point multiplies against ecmult */ + for (ncount = 0; ncount < COUNT; ncount++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + testutil_random_scalar_order(&sc[0]); + testutil_random_scalar_order(&sc[1]); + + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[0] = ptg; + pt[1] = secp256k1_ge_const_g; + + /* only G scalar */ + secp256k1_ecmult(&r2, &ptgj, &secp256k1_scalar_zero, &sc[0]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* 1-point */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* Try to multiply 1 point, but callback returns false */ + CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_false_callback, &data, 1)); + + /* 2-point */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + + /* 2-point with G scalar */ + secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Check infinite outputs of various forms */ + for (ncount = 0; ncount < COUNT; ncount++) { + secp256k1_ge ptg; + size_t i, j; + size_t sizes[] = { 2, 10, 32 }; + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + testutil_random_scalar_order(&sc[i]); + secp256k1_ge_set_infinity(&pt[i]); + } + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + testutil_random_ge_test(&ptg); + pt[i] = ptg; + secp256k1_scalar_set_int(&sc[i], 0); + } + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + testutil_random_ge_test(&ptg); + for (i = 0; i < 16; i++) { + testutil_random_scalar_order(&sc[2*i]); + secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]); + pt[2 * i] = ptg; + pt[2 * i + 1] = ptg; + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + + testutil_random_scalar_order(&sc[0]); + for (i = 0; i < 16; i++) { + testutil_random_ge_test(&ptg); + + sc[2*i] = sc[0]; + sc[2*i+1] = sc[0]; + pt[2 * i] = ptg; + secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + testutil_random_ge_test(&ptg); + secp256k1_scalar_set_int(&sc[0], 0); + pt[0] = ptg; + for (i = 1; i < 32; i++) { + pt[i] = ptg; + + testutil_random_scalar_order(&sc[i]); + secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]); + secp256k1_scalar_negate(&sc[i], &sc[i]); + } + + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 32)); + CHECK(secp256k1_gej_is_infinity(&r)); + } + + /* Check random points, constant scalar */ + for (ncount = 0; ncount < COUNT; ncount++) { + size_t i; + secp256k1_gej_set_infinity(&r); + + testutil_random_scalar_order(&sc[0]); + for (i = 0; i < 20; i++) { + secp256k1_ge ptg; + sc[i] = sc[0]; + testutil_random_ge_test(&ptg); + pt[i] = ptg; + secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL); + } + + secp256k1_ecmult(&r2, &r, &sc[0], &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Check random scalars, constant point */ + for (ncount = 0; ncount < COUNT; ncount++) { + size_t i; + secp256k1_ge ptg; + secp256k1_gej p0j; + secp256k1_scalar rs; + secp256k1_scalar_set_int(&rs, 0); + + testutil_random_ge_test(&ptg); + for (i = 0; i < 20; i++) { + testutil_random_scalar_order(&sc[i]); + pt[i] = ptg; + secp256k1_scalar_add(&rs, &rs, &sc[i]); + } + + secp256k1_gej_set_ge(&p0j, &pt[0]); + secp256k1_ecmult(&r2, &p0j, &rs, &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); + } + + /* Sanity check that zero scalars don't cause problems */ + for (ncount = 0; ncount < 20; ncount++) { + testutil_random_scalar_order(&sc[ncount]); + testutil_random_ge_test(&pt[ncount]); + } + + secp256k1_scalar_set_int(&sc[0], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20)); + secp256k1_scalar_set_int(&sc[1], 0); + secp256k1_scalar_set_int(&sc[2], 0); + secp256k1_scalar_set_int(&sc[3], 0); + secp256k1_scalar_set_int(&sc[4], 0); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5)); + CHECK(secp256k1_gej_is_infinity(&r)); + + /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ + { + const size_t TOP = 8; + size_t s0i, s1i; + size_t t0i, t1i; + secp256k1_ge ptg; + secp256k1_gej ptgj; + + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + + for(t0i = 0; t0i < TOP; t0i++) { + for(t1i = 0; t1i < TOP; t1i++) { + secp256k1_gej t0p, t1p; + secp256k1_scalar t0, t1; + + secp256k1_scalar_set_int(&t0, (t0i + 1) / 2); + secp256k1_scalar_cond_negate(&t0, t0i & 1); + secp256k1_scalar_set_int(&t1, (t1i + 1) / 2); + secp256k1_scalar_cond_negate(&t1, t1i & 1); + + secp256k1_ecmult(&t0p, &ptgj, &t0, &secp256k1_scalar_zero); + secp256k1_ecmult(&t1p, &ptgj, &t1, &secp256k1_scalar_zero); + + for(s0i = 0; s0i < TOP; s0i++) { + for(s1i = 0; s1i < TOP; s1i++) { + secp256k1_scalar tmp1, tmp2; + secp256k1_gej expected, actual; + + secp256k1_ge_set_gej(&pt[0], &t0p); + secp256k1_ge_set_gej(&pt[1], &t1p); + + secp256k1_scalar_set_int(&sc[0], (s0i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[0], s0i & 1); + secp256k1_scalar_set_int(&sc[1], (s1i + 1) / 2); + secp256k1_scalar_cond_negate(&sc[1], s1i & 1); + + secp256k1_scalar_mul(&tmp1, &t0, &sc[0]); + secp256k1_scalar_mul(&tmp2, &t1, &sc[1]); + secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); + + secp256k1_ecmult(&expected, &ptgj, &tmp1, &secp256k1_scalar_zero); + CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2)); + CHECK(secp256k1_gej_eq_var(&actual, &expected)); + } + } + } + } + } +} + +static int test_ecmult_multi_random(secp256k1_scratch *scratch) { + /* Large random test for ecmult_multi_* functions which exercises: + * - Few or many inputs (0 up to 128, roughly exponentially distributed). + * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). + * - Including or excluding an nonzero a*G term (or such a term at all). + * - Final expected result equal to infinity or not (roughly 50%). + * - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch + */ + + /* These 4 variables define the eventual input to the ecmult_multi function. + * g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and + * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points + * which form its normal inputs. */ + int filled = 0; + secp256k1_scalar g_scalar = secp256k1_scalar_zero; + secp256k1_scalar scalars[128]; + secp256k1_gej gejs[128]; + /* The expected result, and the computed result. */ + secp256k1_gej expected, computed; + /* Temporaries. */ + secp256k1_scalar sc_tmp; + secp256k1_ge ge_tmp; + /* Variables needed for the actual input to ecmult_multi. */ + secp256k1_ge ges[128]; + ecmult_multi_data data; + + int i; + /* Which multiplication function to use */ + int fn = testrand_int(3); + secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var : + fn == 1 ? secp256k1_ecmult_strauss_batch_single : + secp256k1_ecmult_pippenger_batch_single; + /* Simulate exponentially distributed num. */ + int num_bits = 2 + testrand_int(6); + /* Number of (scalar, point) inputs (excluding g). */ + int num = testrand_int((1 << num_bits) + 1); + /* Number of those which are nonzero. */ + int num_nonzero = testrand_int(num + 1); + /* Whether we're aiming to create an input with nonzero expected result. */ + int nonzero_result = testrand_bits(1); + /* Whether we will provide nonzero g multiplicand. In some cases our hand + * is forced here based on num_nonzero and nonzero_result. */ + int g_nonzero = num_nonzero == 0 ? nonzero_result : + num_nonzero == 1 && !nonzero_result ? 1 : + (int)testrand_bits(1); + /* Which g_scalar pointer to pass into ecmult_multi(). */ + const secp256k1_scalar* g_scalar_ptr = (g_nonzero || testrand_bits(1)) ? &g_scalar : NULL; + /* How many EC multiplications were performed in this function. */ + int mults = 0; + /* How many randomization steps to apply to the input list. */ + int rands = (int)testrand_bits(3); + if (rands > num_nonzero) rands = num_nonzero; + + secp256k1_gej_set_infinity(&expected); + secp256k1_gej_set_infinity(&gejs[0]); + secp256k1_scalar_set_int(&scalars[0], 0); + + if (g_nonzero) { + /* If g_nonzero, set g_scalar to nonzero value r. */ + testutil_random_scalar_order_test(&g_scalar); + if (!nonzero_result) { + /* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */ + CHECK(num_nonzero > filled); + testutil_random_scalar_order_test(&sc_tmp); + secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); + secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); + secp256k1_scalar_negate(&sc_tmp, &sc_tmp); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); + ++filled; + ++mults; + } + } + + if (nonzero_result && filled < num_nonzero) { + /* If a nonzero result is desired, and there is space, add a random nonzero term. */ + testutil_random_scalar_order_test(&scalars[filled]); + testutil_random_ge_test(&ge_tmp); + secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); + ++filled; + } + + if (nonzero_result) { + /* Compute the expected result using normal ecmult. */ + CHECK(filled <= 1); + secp256k1_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar); + mults += filled + g_nonzero; + } + + /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */ + CHECK(filled <= 1 + !nonzero_result); + CHECK(filled <= num_nonzero); + + /* Add entries to scalars,gejs so that there are num of them. All the added entries + * either have scalar=0 or point=infinity, so these do not change the expected result. */ + while (filled < num) { + if (testrand_bits(1)) { + secp256k1_gej_set_infinity(&gejs[filled]); + testutil_random_scalar_order_test(&scalars[filled]); + } else { + secp256k1_scalar_set_int(&scalars[filled], 0); + testutil_random_ge_test(&ge_tmp); + secp256k1_gej_set_ge(&gejs[filled], &ge_tmp); + } + ++filled; + } + + /* Now perform cheapish transformations on gejs and scalars, for indices + * 0..num_nonzero-1, which do not change the expected result, but may + * convert some of them to be both non-0-scalar and non-infinity-point. */ + for (i = 0; i < rands; ++i) { + int j; + secp256k1_scalar v, iv; + /* Shuffle the entries. */ + for (j = 0; j < num_nonzero; ++j) { + int k = testrand_int(num_nonzero - j); + if (k != 0) { + secp256k1_gej gej = gejs[j]; + secp256k1_scalar sc = scalars[j]; + gejs[j] = gejs[j + k]; + scalars[j] = scalars[j + k]; + gejs[j + k] = gej; + scalars[j + k] = sc; + } + } + /* Perturb all consecutive pairs of inputs: + * a*P + b*Q -> (a+b)*P + b*(Q-P). */ + for (j = 0; j + 1 < num_nonzero; j += 2) { + secp256k1_gej gej; + secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]); + secp256k1_gej_neg(&gej, &gejs[j]); + secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL); + } + /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ + CHECK(num_nonzero >= 1); + testutil_random_scalar_order_test(&v); + secp256k1_scalar_inverse(&iv, &v); + secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v); + secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL); + ++mults; + } + + /* Shuffle all entries (0..num-1). */ + for (i = 0; i < num; ++i) { + int j = testrand_int(num - i); + if (j != 0) { + secp256k1_gej gej = gejs[i]; + secp256k1_scalar sc = scalars[i]; + gejs[i] = gejs[i + j]; + scalars[i] = scalars[i + j]; + gejs[i + j] = gej; + scalars[i + j] = sc; + } + } + + /* Compute affine versions of all inputs. */ + secp256k1_ge_set_all_gej_var(ges, gejs, filled); + /* Invoke ecmult_multi code. */ + data.sc = scalars; + data.pt = ges; + CHECK(ecmult_multi(&CTX->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); + mults += num_nonzero + g_nonzero; + /* Compare with expected result. */ + CHECK(secp256k1_gej_eq_var(&computed, &expected)); + return mults; +} + +static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { + secp256k1_scalar sc; + secp256k1_ge pt; + secp256k1_gej r; + ecmult_multi_data data; + secp256k1_scratch *scratch_empty; + + testutil_random_ge_test(&pt); + testutil_random_scalar_order(&sc); + data.sc = ≻ + data.pt = &pt; + + /* Try to multiply 1 point, but scratch space is empty.*/ + scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0); + CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty); +} + +static void test_secp256k1_pippenger_bucket_window_inv(void) { + int i; + + CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); + for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { + /* Bucket_window of 8 is not used with endo */ + if (i == 8) { + continue; + } + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i); + if (i != PIPPENGER_MAX_BUCKET_WINDOW) { + CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i); + } + } +} + +/** + * Probabilistically test the function returning the maximum number of possible points + * for a given scratch space. + */ +static void test_ecmult_multi_pippenger_max_points(void) { + size_t scratch_size = testrand_bits(8); + size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); + secp256k1_scratch *scratch; + size_t n_points_supported; + int bucket_window = 0; + + for(; scratch_size < max_size; scratch_size+=256) { + size_t i; + size_t total_alloc; + size_t checkpoint; + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size); + CHECK(scratch != NULL); + checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); + n_points_supported = secp256k1_pippenger_max_points(&CTX->error_callback, scratch); + if (n_points_supported == 0) { + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + continue; + } + bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); + /* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */ + total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window); + for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) { + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 1)); + total_alloc--; + } + CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, total_alloc)); + secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + } + CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); +} + +static void test_ecmult_multi_batch_size_helper(void) { + size_t n_batches, n_batch_points, max_n_batch_points, n; + + max_n_batch_points = 0; + n = 1; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0); + + max_n_batch_points = 1; + n = 0; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 0); + CHECK(n_batch_points == 0); + + max_n_batch_points = 2; + n = 5; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 3); + CHECK(n_batch_points == 2); + + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH; + n = ECMULT_MAX_POINTS_PER_BATCH; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 1); + CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH); + + max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1; + n = ECMULT_MAX_POINTS_PER_BATCH + 1; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == 2); + CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1); + + max_n_batch_points = 1; + n = SIZE_MAX; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == SIZE_MAX); + CHECK(n_batch_points == 1); + + max_n_batch_points = 2; + n = SIZE_MAX; + CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1); + CHECK(n_batches == SIZE_MAX/2 + 1); + CHECK(n_batch_points == 2); +} + +/** + * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to + * 1 <= i <= num points. + */ +static void test_ecmult_multi_batching(void) { + static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; + secp256k1_scalar scG; + secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points); + secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points); + secp256k1_gej r; + secp256k1_gej r2; + ecmult_multi_data data; + int i; + secp256k1_scratch *scratch; + + secp256k1_gej_set_infinity(&r2); + + /* Get random scalars and group elements and compute result */ + testutil_random_scalar_order(&scG); + secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG); + for(i = 0; i < n_points; i++) { + secp256k1_ge ptg; + secp256k1_gej ptgj; + testutil_random_ge_test(&ptg); + secp256k1_gej_set_ge(&ptgj, &ptg); + pt[i] = ptg; + testutil_random_scalar_order(&sc[i]); + secp256k1_ecmult(&ptgj, &ptgj, &sc[i], NULL); + secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL); + } + data.sc = sc; + data.pt = pt; + secp256k1_gej_neg(&r2, &r2); + + /* Test with empty scratch space. It should compute the correct result using + * ecmult_mult_simple algorithm which doesn't require a scratch space. */ + scratch = secp256k1_scratch_create(&CTX->error_callback, 0); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + /* Test with space for 1 point in pippenger. That's not enough because + * ecmult_multi selects strauss which requires more memory. It should + * therefore select the simple algorithm. */ + scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + for(i = 1; i <= n_points; i++) { + if (i > ECMULT_PIPPENGER_THRESHOLD) { + int bucket_window = secp256k1_pippenger_bucket_window(i); + size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window); + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + } else { + size_t scratch_size = secp256k1_strauss_scratch_size(i); + scratch = secp256k1_scratch_create(&CTX->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + } + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_gej_is_infinity(&r)); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + } + free(sc); + free(pt); +} + +static void run_ecmult_multi_tests(void) { + secp256k1_scratch *scratch; + int64_t todo = (int64_t)320 * COUNT; + + test_secp256k1_pippenger_bucket_window_inv(); + test_ecmult_multi_pippenger_max_points(); + scratch = secp256k1_scratch_create(&CTX->error_callback, 819200); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + test_ecmult_multi(NULL, secp256k1_ecmult_multi_var); + test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single); + test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); + test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single); + while (todo > 0) { + todo -= test_ecmult_multi_random(scratch); + } + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + /* Run test_ecmult_multi with space for exactly one point */ + scratch = secp256k1_scratch_create(&CTX->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); + secp256k1_scratch_destroy(&CTX->error_callback, scratch); + + test_ecmult_multi_batch_size_helper(); + test_ecmult_multi_batching(); } -void test_wnaf(const secp256k1_scalar *number, int w) { +static void test_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, two, t; int wnaf[256]; int zeroes = -1; @@ -2509,43 +5268,23 @@ void test_wnaf(const secp256k1_scalar *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } -void test_constant_wnaf_negate(const secp256k1_scalar *number) { - secp256k1_scalar neg1 = *number; - secp256k1_scalar neg2 = *number; - int sign1 = 1; - int sign2 = 1; - - if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { - secp256k1_scalar_negate(&neg1, &neg1); - sign1 = -1; - } - sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); - CHECK(sign1 == sign2); - CHECK(secp256k1_scalar_eq(&neg1, &neg2)); -} - -void test_constant_wnaf(const secp256k1_scalar *number, int w) { +static void test_fixed_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; int skew; - secp256k1_scalar num = *number; + secp256k1_scalar num, unused; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); - /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ -#ifdef USE_ENDOMORPHISM - for (i = 0; i < 16; ++i) { - secp256k1_scalar_shr_int(&num, 8); - } -#endif - skew = secp256k1_wnaf_const(wnaf, num, w); + /* Make num a 128-bit scalar. */ + secp256k1_scalar_split_128(&num, &unused, number); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); - for (i = WNAF_SIZE(w); i >= 0; --i) { + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { secp256k1_scalar t; int v = wnaf[i]; - CHECK(v != 0); /* check nonzero */ - CHECK(v & 1); /* check parity */ + CHECK(v == 0 || v & 1); /* check parity */ CHECK(v > -(1 << w)); /* check range above */ CHECK(v < (1 << w)); /* check range below */ @@ -2558,27 +5297,88 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { } secp256k1_scalar_add(&x, &x, &t); } - /* Skew num because when encoding numbers as odd we use an offset */ - secp256k1_scalar_cadd_bit(&num, skew == 2, 1); - CHECK(secp256k1_scalar_eq(&x, &num)); + /* If skew is 1 then add 1 to num */ + secp256k1_scalar_cadd_bit(&num, 0, skew == 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + +/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the + * rest is 0.*/ +static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { + int i; + for (i = WNAF_SIZE(w)-1; i >= 8; --i) { + CHECK(wnaf[i] == 0); + } + for (i = 7; i >= 0; --i) { + CHECK(wnaf[i] == wnaf_expected[i]); + } +} + +static void test_fixed_wnaf_small(void) { + int w = 4; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num; + + secp256k1_scalar_set_int(&num, 0); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(skew == 0); + + secp256k1_scalar_set_int(&num, 1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 1; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(wnaf[0] == 1); + CHECK(skew == 0); + + { + int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; + secp256k1_scalar_set_int(&num, 0xffffffff); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; + secp256k1_scalar_set_int(&num, 0xeeeeeeee); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 1); + } + { + int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01010101); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; + secp256k1_scalar_set_int(&num, 0x01ef1ef1); + skew = secp256k1_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } } -void run_wnaf(void) { +static void run_wnaf(void) { int i; - secp256k1_scalar n = {{0}}; - - /* Sanity check: 1 and 2 are the smallest odd and even numbers and should - * have easier-to-diagnose failure modes */ - n.d[0] = 1; - test_constant_wnaf(&n, 4); - n.d[0] = 2; - test_constant_wnaf(&n, 4); + secp256k1_scalar n; + + /* Test 0 for fixed wnaf */ + test_fixed_wnaf_small(); /* Random tests */ - for (i = 0; i < count; i++) { - random_scalar_order(&n); + for (i = 0; i < COUNT; i++) { + testutil_random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); - test_constant_wnaf_negate(&n); - test_constant_wnaf(&n, 4 + (i % 10)); + test_fixed_wnaf(&n, 4 + (i % 10)); } secp256k1_scalar_set_int(&n, 0); CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); @@ -2587,96 +5387,243 @@ void run_wnaf(void) { CHECK(secp256k1_scalar_is_zero(&n)); } -void test_ecmult_constants(void) { - /* Test ecmult_gen() for [0..36) and [order-36..0). */ - secp256k1_scalar x; - secp256k1_gej r; - secp256k1_ge ng; - int i; - int j; - secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); - for (i = 0; i < 36; i++ ) { - secp256k1_scalar_set_int(&x, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); - for (j = 0; j < i; j++) { - if (j == i - 1) { - ge_equals_gej(&secp256k1_ge_const_g, &r); - } - secp256k1_gej_add_ge(&r, &r, &ng); - } - CHECK(secp256k1_gej_is_infinity(&r)); +static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, size_t idx, void* data) { + const secp256k1_scalar* indata = (const secp256k1_scalar*)data; + *sc = *indata; + *pt = secp256k1_ge_const_g; + CHECK(idx == 0); + return 1; +} + +static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) { + /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */ + secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; + secp256k1_ge r; + unsigned char bytes[65]; + size_t size = 65; + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + secp256k1_gej_set_infinity(&infj); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x); + secp256k1_ecmult(&rj2, &gj, x, &secp256k1_scalar_zero); + secp256k1_ecmult(&rj3, &infj, &secp256k1_scalar_zero, x); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj4, x, NULL, NULL, 0)); + CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj5, &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1)); + secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x); + secp256k1_ge_set_gej_var(&r, &rj1); + CHECK(secp256k1_gej_eq_ge_var(&rj2, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj3, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj4, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj5, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj6, &r)); + if (secp256k1_ge_is_infinity(&r)) { + /* Store infinity as 0x00 */ + const unsigned char zerobyte[1] = {0}; + secp256k1_sha256_write(acc, zerobyte, 1); + } else { + /* Store other points using their uncompressed serialization. */ + secp256k1_eckey_pubkey_serialize(&r, bytes, &size, 0); + CHECK(size == 65); + secp256k1_sha256_write(acc, bytes, size); } - for (i = 1; i <= 36; i++ ) { +} + +static void test_ecmult_constants_2bit(void) { + /* Using test_ecmult_accumulate, test ecmult for: + * - For i in 0..36: + * - Key i + * - Key -i + * - For i in 0..255: + * - For j in 1..255 (only odd values): + * - Key (j*2^i) mod order + */ + secp256k1_scalar x; + secp256k1_sha256 acc; + unsigned char b32[32]; + int i, j; + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); + + /* Expected hash of all the computed points; created with an independent + * implementation. */ + static const unsigned char expected32[32] = { + 0xe4, 0x71, 0x1b, 0x4d, 0x14, 0x1e, 0x68, 0x48, + 0xb7, 0xaf, 0x47, 0x2b, 0x4c, 0xd2, 0x04, 0x14, + 0x3a, 0x75, 0x87, 0x60, 0x1a, 0xf9, 0x63, 0x60, + 0xd0, 0xcb, 0x1f, 0xaa, 0x85, 0x9a, 0xb7, 0xb4 + }; + secp256k1_sha256_initialize(&acc); + for (i = 0; i <= 36; ++i) { secp256k1_scalar_set_int(&x, i); + test_ecmult_accumulate(&acc, &x, scratch); secp256k1_scalar_negate(&x, &x); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); - for (j = 0; j < i; j++) { - if (j == i - 1) { - ge_equals_gej(&ng, &r); - } - secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); + test_ecmult_accumulate(&acc, &x, scratch); + }; + for (i = 0; i < 256; ++i) { + for (j = 1; j < 256; j += 2) { + int k; + secp256k1_scalar_set_int(&x, j); + for (k = 0; k < i; ++k) secp256k1_scalar_add(&x, &x, &x); + test_ecmult_accumulate(&acc, &x, scratch); } - CHECK(secp256k1_gej_is_infinity(&r)); } + secp256k1_sha256_finalize(&acc, b32); + CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); + + secp256k1_scratch_space_destroy(CTX, scratch); +} + +static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { + /* Using test_ecmult_accumulate, test ecmult for: + * - Key 0 + * - Key 1 + * - Key -1 + * - For i in range(iter): + * - Key SHA256(LE32(prefix) || LE16(i)) + */ + secp256k1_scalar x; + secp256k1_sha256 acc; + unsigned char b32[32]; + unsigned char inp[6]; + size_t i; + secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); + + inp[0] = prefix & 0xFF; + inp[1] = (prefix >> 8) & 0xFF; + inp[2] = (prefix >> 16) & 0xFF; + inp[3] = (prefix >> 24) & 0xFF; + secp256k1_sha256_initialize(&acc); + secp256k1_scalar_set_int(&x, 0); + test_ecmult_accumulate(&acc, &x, scratch); + secp256k1_scalar_set_int(&x, 1); + test_ecmult_accumulate(&acc, &x, scratch); + secp256k1_scalar_negate(&x, &x); + test_ecmult_accumulate(&acc, &x, scratch); + + for (i = 0; i < iter; ++i) { + secp256k1_sha256 gen; + inp[4] = i & 0xff; + inp[5] = (i >> 8) & 0xff; + secp256k1_sha256_initialize(&gen); + secp256k1_sha256_write(&gen, inp, sizeof(inp)); + secp256k1_sha256_finalize(&gen, b32); + secp256k1_scalar_set_b32(&x, b32, NULL); + test_ecmult_accumulate(&acc, &x, scratch); + } + secp256k1_sha256_finalize(&acc, b32); + CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); + + secp256k1_scratch_space_destroy(CTX, scratch); } -void run_ecmult_constants(void) { - test_ecmult_constants(); +static void run_ecmult_constants(void) { + /* Expected hashes of all points in the tests below. Computed using an + * independent implementation. */ + static const unsigned char expected32_6bit20[32] = { + 0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f, + 0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e, + 0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e, + 0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e + }; + static const unsigned char expected32_8bit8[32] = { + 0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95, + 0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec, + 0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12, + 0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6 + }; + /* For every combination of 6 bit positions out of 256, restricted to + * 20-bit windows (i.e., the first and last bit position are no more than + * 19 bits apart), all 64 bit patterns occur in the input scalars used in + * this test. */ + CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") { + test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20); + } + + /* For every combination of 8 consecutive bit positions, all 256 bit + * patterns occur in the input scalars used in this test. */ + CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") { + test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8); + } + + CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") { + test_ecmult_constants_2bit(); + } } -void test_ecmult_gen_blind(void) { +static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; secp256k1_scalar b; unsigned char seed32[32]; secp256k1_gej pgej; secp256k1_gej pgej2; - secp256k1_gej i; + secp256k1_ge p; secp256k1_ge pge; - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); - secp256k1_rand256(seed32); - b = ctx->ecmult_gen_ctx.blind; - i = ctx->ecmult_gen_ctx.initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); + testrand256(seed32); + b = CTX->ecmult_gen_ctx.scalar_offset; + p = CTX->ecmult_gen_ctx.ge_offset; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key); CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); - CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); secp256k1_ge_set_gej(&pge, &pgej); - ge_equals_gej(&pge, &pgej2); + CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge)); } -void test_ecmult_gen_blind_reset(void) { +static void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ secp256k1_scalar b; - secp256k1_gej initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - b = ctx->ecmult_gen_ctx.blind; - initial = ctx->ecmult_gen_ctx.initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); + secp256k1_ge p1, p2; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + b = CTX->ecmult_gen_ctx.scalar_offset; + p1 = CTX->ecmult_gen_ctx.ge_offset; + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); + p2 = CTX->ecmult_gen_ctx.ge_offset; + CHECK(secp256k1_ge_eq_var(&p1, &p2)); +} + +/* Verify that ecmult_gen for scalars gn for which gn + scalar_offset = {-1,0,1}. */ +static void test_ecmult_gen_edge_cases(void) { + int i; + secp256k1_gej res1, res2, res3; + secp256k1_scalar gn = secp256k1_scalar_one; /* gn = 1 */ + secp256k1_scalar_add(&gn, &gn, &CTX->ecmult_gen_ctx.scalar_offset); /* gn = 1 + scalar_offset */ + secp256k1_scalar_negate(&gn, &gn); /* gn = -1 - scalar_offset */ + + for (i = -1; i < 2; ++i) { + /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); + secp256k1_ecmult(&res2, NULL, &secp256k1_scalar_zero, &gn); + secp256k1_ecmult_const(&res3, &secp256k1_ge_const_g, &gn); + CHECK(secp256k1_gej_eq_var(&res1, &res2)); + CHECK(secp256k1_gej_eq_var(&res1, &res3)); + secp256k1_scalar_add(&gn, &gn, &secp256k1_scalar_one); + } } -void run_ecmult_gen_blind(void) { +static void run_ecmult_gen_blind(void) { int i; test_ecmult_gen_blind_reset(); + test_ecmult_gen_edge_cases(); for (i = 0; i < 10; i++) { test_ecmult_gen_blind(); } } -#ifdef USE_ENDOMORPHISM /***** ENDOMORPHISH TESTS *****/ -void test_scalar_split(void) { - secp256k1_scalar full; - secp256k1_scalar s1, slam; +static void test_scalar_split(const secp256k1_scalar* full) { + secp256k1_scalar s, s1, slam; const unsigned char zero[32] = {0}; unsigned char tmp[32]; - random_scalar_order_test(&full); - secp256k1_scalar_split_lambda(&s1, &slam, &full); + secp256k1_scalar_split_lambda(&s1, &slam, full); + + /* check slam*lambda + s1 == full */ + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, &slam); + secp256k1_scalar_add(&s, &s, &s1); + CHECK(secp256k1_scalar_eq(&s, full)); /* check that both are <= 128 bits in size */ if (secp256k1_scalar_is_high(&s1)) { @@ -2687,29 +5634,44 @@ void test_scalar_split(void) { } secp256k1_scalar_get_b32(tmp, &s1); - CHECK(memcmp(zero, tmp, 16) == 0); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); secp256k1_scalar_get_b32(tmp, &slam); - CHECK(memcmp(zero, tmp, 16) == 0); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); } -void run_endomorphism_tests(void) { - test_scalar_split(); + +static void run_endomorphism_tests(void) { + unsigned i; + static secp256k1_scalar s; + test_scalar_split(&secp256k1_scalar_zero); + test_scalar_split(&secp256k1_scalar_one); + secp256k1_scalar_negate(&s,&secp256k1_scalar_one); + test_scalar_split(&s); + test_scalar_split(&secp256k1_const_lambda); + secp256k1_scalar_add(&s, &secp256k1_const_lambda, &secp256k1_scalar_one); + test_scalar_split(&s); + + for (i = 0; i < 100U * COUNT; ++i) { + secp256k1_scalar full; + testutil_random_scalar_order_test(&full); + test_scalar_split(&full); + } + for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { + test_scalar_split(&scalars_near_split_bounds[i]); + } } -#endif -void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { +static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { unsigned char pubkeyc[65]; secp256k1_pubkey pubkey; secp256k1_ge ge; size_t pubkeyclen; - int32_t ecount; - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { /* Smaller sizes are tested exhaustively elsewhere. */ int32_t i; memcpy(&pubkeyc[1], input, 64); - VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen); for (i = 0; i < 256; i++) { /* Try all type bytes. */ int xpass; @@ -2728,51 +5690,45 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali unsigned char pubkeyo[65]; size_t outl; memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - ecount = 0; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 33); - CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); if (ypass) { /* This test isn't always done because we decode with alternative signs, so the y won't match. */ CHECK(pubkeyo[0] == ysign); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); secp256k1_pubkey_save(&pubkey, &ge); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 65); CHECK(pubkeyo[0] == 4); - CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); } - CHECK(ecount == 0); } else { /* These cases must fail to parse. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } } } - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } -void run_ec_pubkey_parse_test(void) { +static void run_ec_pubkey_parse_test(void) { #define SECP256K1_EC_PARSE_TEST_NVALID (12) const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { { @@ -2952,141 +5908,99 @@ void run_ec_pubkey_parse_test(void) { 0xB8, 0x00 }; unsigned char sout[65]; - unsigned char shortkey[2]; + unsigned char shortkey[2] = { 0 }; secp256k1_ge ge; secp256k1_pubkey pubkey; size_t len; int32_t i; - int32_t ecount; - int32_t ecount2; - ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ - VG_UNDEF(&pubkeyc[65], 1); - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); /* Zero length claimed, fail, zeroize, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(shortkey, 2); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* Length one claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 256 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i; - VG_UNDEF(&shortkey[1], 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } /* Length two claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 65536 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i & 255; shortkey[1] = i >> 8; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65)); /* NULL input string. Illegal arg and zeroize output. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 1); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* Valid parse. */ memset(&pubkey, 0, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - VG_UNDEF(&ge, sizeof(ge)); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); - VG_CHECK(&ge.x, sizeof(ge.x)); - VG_CHECK(&ge.y, sizeof(ge.y)); - VG_CHECK(&ge.infinity, sizeof(ge.infinity)); - ge_equals_ge(&secp256k1_ge_const_g, &ge); - CHECK(ecount == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); + CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); + SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); + SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); + SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); + CHECK(secp256k1_ge_eq_var(&ge, &secp256k1_ge_const_g)); /* secp256k1_ec_pubkey_serialize illegal args. */ - ecount = 0; len = 65; - CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED)); CHECK(len == 0); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED)); len = 65; - VG_UNDEF(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); - VG_CHECK(sout, 65); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED)); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(len == 0); len = 65; - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0)); CHECK(len == 0); len = 65; - VG_UNDEF(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(sout, 65); - CHECK(ecount == 4); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(len == 65); /* Multiple illegal args. Should still set arg error only once. */ - ecount = 0; - ecount2 = 11; - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - /* Does the illegal arg callback actually change the behavior? */ - secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - CHECK(ecount2 == 10); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65)); /* Try a bunch of prefabbed points with all possible encodings. */ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { ec_pubkey_parse_pointtest(valid[i], 1, 1); @@ -3099,7 +6013,7 @@ void run_ec_pubkey_parse_test(void) { } } -void run_eckey_edge_case_test(void) { +static void run_eckey_edge_case_test(void) { const unsigned char orderc[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, @@ -3115,259 +6029,284 @@ void run_eckey_edge_case_test(void) { secp256k1_pubkey pubkey_negone; const secp256k1_pubkey *pubkeys[3]; size_t len; - int32_t ecount; /* Group order is too large, reject. */ - CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, orderc) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Maximum value is too large, reject. */ memset(ctmp, 255, 32); - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Zero is too small, reject. */ memset(ctmp, 0, 32); - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* One must be accepted. */ ctmp[31] = 0x01; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_one = pubkey; /* Group order + 1 is too large, reject. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x42; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* -1 must be accepted. */ ctmp[31] = 0x40; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_negone = pubkey; - /* Tweak of zero leaves the value changed. */ + /* Tweak of zero leaves the value unchanged. */ memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); - CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); memcpy(&pubkey2, &pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Multiply tweak of zero zeroizes the output. */ - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Overflowing key tweak zeroizes. */ + /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing + seckey, the seckey is zeroized. */ + memcpy(ctmp, orderc, 32); + memset(ctmp2, 0, 32); + ctmp2[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp2) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); + /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing + tweak, the seckey is zeroized. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, orderc) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, orderc) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing + tweak, the pubkey is zeroized. */ + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, orderc) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, orderc) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Private key tweaks results in a key of zero. */ + /* If the resulting key in secp256k1_ec_seckey_tweak_add and + * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter + * case the pubkey is zeroized. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + memset(ctmp2, 0, 32); ctmp2[31] = 1; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); - CHECK(memcmp(zeros, ctmp2, 32) == 0); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp2, 32) == 0); ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* Tweak computation wraps and results in a key of 1. */ ctmp2[31] = 2; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); - CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp2, ctmp) == 1); + CHECK(secp256k1_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Tweak mul * 2 = 1+1. */ - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 1); ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Test argument errors. */ - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(ecount == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Zeroize pubkey on parse error. */ memset(&pubkey, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); memset(&pubkey2, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); - CHECK(ecount == 2); - CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2)); + CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); /* Plain argument errors. */ - ecount = 0; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); - CHECK(ecount == 1); - ecount = 0; + CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_verify(CTX, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 1; - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, NULL, ctmp)); memset(&pubkey, 1, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* secp256k1_ec_pubkey_combine tests. */ - ecount = 0; pubkeys[0] = &pubkey_one; - VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *)); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); pubkeys[0] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); len = 33; - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); /* Result is infinity. */ pubkeys[0] = &pubkey_one; pubkeys[1] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Passes through infinity but comes out one. */ pubkeys[2] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); len = 33; - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); /* Adds to two. */ pubkeys[1] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); +} + +static void run_eckey_negate_test(void) { + unsigned char seckey[32]; + unsigned char seckey_tmp[32]; + + testutil_random_scalar_order_b32(seckey); + memcpy(seckey_tmp, seckey, 32); + + /* Verify negation changes the key and changes it back */ + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) != 0); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Check that privkey alias gives same result */ + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); + CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Negating all 0s fails */ + memset(seckey, 0, 32); + memset(seckey_tmp, 0, 32); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); + /* Check that seckey is not modified */ + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); + + /* Negating an overflowing seckey fails and the seckey is zeroed. In this + * test, the seckey has 16 random bytes to ensure that ec_seckey_negate + * doesn't just set seckey to a constant value in case of failure. */ + testutil_random_scalar_order_b32(seckey); + memset(seckey, 0xFF, 16); + memset(seckey_tmp, 0, 32); + CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); } -void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { +static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { - random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); + testutil_random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&CTX->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } -void test_ecdsa_sign_verify(void) { +static void test_ecdsa_sign_verify(void) { secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar one; secp256k1_scalar msg, key; secp256k1_scalar sigr, sigs; - int recid; int getrec; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); + int recid; + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand_bits(1); - random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); + getrec = testrand_bits(1); + /* The specific way in which this conditional is written sidesteps a potential bug in clang. + See the commit messages of the commit that introduced this comment for details. */ if (getrec) { + random_sign(&sigr, &sigs, &key, &msg, &recid); CHECK(recid >= 0 && recid < 4); + } else { + random_sign(&sigr, &sigs, &key, &msg, NULL); } - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); } -void run_ecdsa_sign_verify(void) { +static void run_ecdsa_sign_verify(void) { int i; - for (i = 0; i < 10*count; i++) { + for (i = 0; i < 10*COUNT; i++) { test_ecdsa_sign_verify(); } } @@ -3419,12 +6358,12 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_signature(const secp256k1_ecdsa_signature *sig) { +static int is_empty_signature(const secp256k1_ecdsa_signature *sig) { static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; - return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; + return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; } -void test_ecdsa_end_to_end(void) { +static void test_ecdsa_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; @@ -3436,139 +6375,161 @@ void test_ecdsa_end_to_end(void) { unsigned char pubkeyc[65]; size_t pubkeyclen = 65; secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey_tmp; unsigned char seckey[300]; size_t seckeylen = 300; /* Generate a random key and message. */ { secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); + testutil_random_scalar_order_test(&msg); + testutil_random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_scalar_get_b32(message, &msg); } /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyc, &pubkeyclen, &pubkey, testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); memset(&pubkey, 0, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify negation changes the key and changes it back */ + memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey_tmp) == 1); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); - CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); - CHECK(memcmp(privkey, privkey2, 32) == 0); + CHECK(ec_privkey_export_der(CTX, seckey, &seckeylen, privkey, testrand_bits(1) == 1)); + CHECK(ec_privkey_import_der(CTX, privkey2, seckey, seckeylen) == 1); + CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; + int ret3; unsigned char rnd[32]; + unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); + testrand256_test(rnd); + memcpy(privkey_tmp, privkey, 32); + ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); + /* Check that privkey alias gives same result */ + ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); + CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand_int(3) == 0) { + if (testrand_int(3) == 0) { int ret1; int ret2; + int ret3; unsigned char rnd[32]; + unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); + testrand256_test(rnd); + memcpy(privkey_tmp, privkey, 32); + ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); + /* Check that privkey alias gives same result */ + ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); + CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); - CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); - CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_ecdsa_sign(CTX, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[3], message, &pubkey) == 1); /* Test lower-S form, malleate, verify and fail, test again, malleate again */ - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(CTX, &r, &s, &signature[0]); secp256k1_scalar_negate(&s, &s); secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); - CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); secp256k1_scalar_negate(&s, &s); secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + CHECK(!secp256k1_ecdsa_signature_normalize(CTX, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[5], message, &pubkey) == 1); + CHECK(secp256k1_memcmp_var(&signature[5], &signature[0], 64) == 0); /* Serialize/parse DER and verify again */ - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); memset(&signature[0], 0, sizeof(signature[0])); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 1); /* Serialize/destroy/parse DER and verify again. */ siglen = 74; - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || - secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, sig, &siglen, &signature[0]) == 1); + sig[testrand_int(siglen)] += 1 + testrand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(CTX, &signature[0], message, &pubkey) == 0); } -void test_random_pubkeys(void) { +static void test_random_pubkeys(void) { secp256k1_ge elem; secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; - if (secp256k1_rand_bits(2) == 0) { - len = secp256k1_rand_bits(6); + size_t len = testrand_bits(2) == 0 ? 65 : 33; + if (testrand_bits(2) == 0) { + len = testrand_bits(6); } if (len == 65) { - in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); + in[0] = testrand_bits(1) ? 4 : (testrand_bits(1) ? 6 : 7); } else { - in[0] = secp256k1_rand_bits(1) ? 2 : 3; + in[0] = testrand_bits(1) ? 2 : 3; } - if (secp256k1_rand_bits(3) == 0) { - in[0] = secp256k1_rand_bits(8); + if (testrand_bits(3) == 0) { + in[0] = testrand_bits(8); } if (len > 1) { - secp256k1_rand256(&in[1]); + testrand256(&in[1]); } if (len > 33) { - secp256k1_rand256(&in[33]); + testrand256(&in[33]); } if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { unsigned char out[65]; @@ -3579,7 +6540,7 @@ void test_random_pubkeys(void) { /* If the pubkey can be parsed, it should round-trip... */ CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); CHECK(size == len); - CHECK(memcmp(&in[1], &out[1], len-1) == 0); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ if ((in[0] != 6) && (in[0] != 7)) { CHECK(in[0] == out[0]); @@ -3588,9 +6549,9 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); CHECK(size == 65); CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); - ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_ge_eq_var(&elem2, &elem)); /* Check that the X9.62 hybrid type is checked. */ - in[0] = secp256k1_rand_bits(1) ? 6 : 7; + in[0] = testrand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -3600,37 +6561,221 @@ void test_random_pubkeys(void) { } } if (res) { - ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_ge_eq_var(&elem, &elem2)); CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); - CHECK(memcmp(&in[1], &out[1], 64) == 0); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); + } + } +} + +static void run_pubkey_comparison(void) { + unsigned char pk1_ser[33] = { + 0x02, + 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, + 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 + }; + const unsigned char pk2_ser[33] = { + 0x02, + 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, + 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c + }; + secp256k1_pubkey pk1; + secp256k1_pubkey pk2; + + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); + + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0)); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0); + { + secp256k1_pubkey pk_tmp; + memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */ + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0)); + } + + /* Make pk2 the same as pk1 but with 3 rather than 2. Note that in + * an uncompressed encoding, these would have the opposite ordering */ + pk1_ser[0] = 3; + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk1_ser, sizeof(pk1_ser)) == 1); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); +} + +static void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) { + size_t i; + const secp256k1_pubkey *pk_test[5]; + + for (i = 0; i < n_pk; i++) { + pk_test[i] = &pk[pk_order[i]]; + } + secp256k1_ec_pubkey_sort(CTX, pk_test, n_pk); + for (i = 0; i < n_pk; i++) { + CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0); + } +} + +static void permute(size_t *arr, size_t n) { + size_t i; + for (i = n - 1; i >= 1; i--) { + size_t tmp, j; + j = testrand_int(i + 1); + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } +} + +static void test_sort_api(void) { + secp256k1_pubkey pks[2]; + const secp256k1_pubkey *pks_ptr[2]; + + pks_ptr[0] = &pks[0]; + pks_ptr[1] = &pks[1]; + + testutil_random_pubkey_test(&pks[0]); + testutil_random_pubkey_test(&pks[1]); + + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2)); + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 0) == 1); + /* Test illegal public keys */ + memset(&pks[0], 0, sizeof(pks[0])); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1)); + memset(&pks[1], 0, sizeof(pks[1])); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } +} + +static void test_sort(void) { + secp256k1_pubkey pk[5]; + unsigned char pk_ser[5][33] = { + { 0x02, 0x08 }, + { 0x02, 0x0b }, + { 0x02, 0x0c }, + { 0x03, 0x05 }, + { 0x03, 0x0a }, + }; + int i; + size_t pk_order[5] = { 0, 1, 2, 3, 4 }; + + for (i = 0; i < 5; i++) { + CHECK(secp256k1_ec_pubkey_parse(CTX, &pk[i], pk_ser[i], sizeof(pk_ser[i]))); + } + + permute(pk_order, 1); + test_sort_helper(pk, pk_order, 1); + permute(pk_order, 2); + test_sort_helper(pk, pk_order, 2); + permute(pk_order, 3); + test_sort_helper(pk, pk_order, 3); + for (i = 0; i < COUNT; i++) { + permute(pk_order, 4); + test_sort_helper(pk, pk_order, 4); + } + for (i = 0; i < COUNT; i++) { + permute(pk_order, 5); + test_sort_helper(pk, pk_order, 5); + } + /* Check that sorting also works for random pubkeys */ + for (i = 0; i < COUNT; i++) { + int j; + const secp256k1_pubkey *pk_ptr[5]; + for (j = 0; j < 5; j++) { + testutil_random_pubkey_test(&pk[j]); + pk_ptr[j] = &pk[j]; } + secp256k1_ec_pubkey_sort(CTX, pk_ptr, 5); + for (j = 1; j < 5; j++) { + CHECK(secp256k1_ec_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], CTX) <= 0); + } + } +} + +/* Test vectors from BIP-MuSig2 */ +static void test_sort_vectors(void) { + enum { N_PUBKEYS = 6 }; + unsigned char pk_ser[N_PUBKEYS][33] = { + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }, + { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, + 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, + 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, + { 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, + 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, + 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }, + { 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, + 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, + 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF }, + { 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F, + 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09, + 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 } + }; + secp256k1_pubkey pubkeys[N_PUBKEYS]; + secp256k1_pubkey *sorted[N_PUBKEYS]; + const secp256k1_pubkey *pks_ptr[N_PUBKEYS]; + int i; + + sorted[0] = &pubkeys[3]; + sorted[1] = &pubkeys[0]; + sorted[2] = &pubkeys[0]; + sorted[3] = &pubkeys[4]; + sorted[4] = &pubkeys[1]; + sorted[5] = &pubkeys[2]; + + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i]))); + pks_ptr[i] = &pubkeys[i]; } + CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, N_PUBKEYS) == 1); + for (i = 0; i < N_PUBKEYS; i++) { + CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0); + } +} + +static void run_pubkey_sort(void) { + test_sort_api(); + test_sort(); + test_sort_vectors(); } -void run_random_pubkeys(void) { + +static void run_random_pubkeys(void) { int i; - for (i = 0; i < 10*count; i++) { + for (i = 0; i < 10*COUNT; i++) { test_random_pubkeys(); } } -void run_ecdsa_end_to_end(void) { +static void run_ecdsa_end_to_end(void) { int i; - for (i = 0; i < 64*count; i++) { + for (i = 0; i < 64*COUNT; i++) { test_ecdsa_end_to_end(); } } -int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { +static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { static const unsigned char zeroes[32] = {0}; -#ifdef ENABLE_OPENSSL_TESTS - static const unsigned char max_scalar[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 - }; -#endif int ret = 0; @@ -3646,32 +6791,24 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ size_t len_der_lax = 2048; int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; -#ifdef ENABLE_OPENSSL_TESTS - ECDSA_SIG *sig_openssl; - const unsigned char *sigptr; - unsigned char roundtrip_openssl[2048]; - int len_openssl = 2048; - int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; -#endif - - parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + parsed_der = secp256k1_ecdsa_signature_parse_der(CTX, &sig_der, sig, siglen); if (parsed_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; - valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der, &sig_der)) << 0; + valid_der = (secp256k1_memcmp_var(compact_der, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der + 32, zeroes, 32) != 0); } if (valid_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; - roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && secp256k1_memcmp_var(roundtrip_der, sig, siglen) == 0; } - parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + parsed_der_lax = ecdsa_signature_parse_der_lax(CTX, &sig_der_lax, sig, siglen); if (parsed_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; - valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + ret |= (!secp256k1_ecdsa_signature_serialize_compact(CTX, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (secp256k1_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); } if (valid_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; - roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + ret |= (!secp256k1_ecdsa_signature_serialize_der(CTX, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && secp256k1_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; } if (certainly_der) { @@ -3687,49 +6824,13 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ if (valid_der) { ret |= (!roundtrips_der_lax) << 12; ret |= (len_der != len_der_lax) << 13; - ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + ret |= ((len_der != len_der_lax) || (secp256k1_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; } ret |= (roundtrips_der != roundtrips_der_lax) << 15; if (parsed_der) { ret |= (!parsed_der_lax) << 16; } -#ifdef ENABLE_OPENSSL_TESTS - sig_openssl = ECDSA_SIG_new(); - sigptr = sig; - parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); - if (parsed_openssl) { - valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; - if (valid_openssl) { - unsigned char tmp[32] = {0}; - BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; - } - if (valid_openssl) { - unsigned char tmp[32] = {0}; - BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; - } - } - len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); - if (len_openssl <= 2048) { - unsigned char *ptr = roundtrip_openssl; - CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); - roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); - } else { - len_openssl = 0; - } - ECDSA_SIG_free(sig_openssl); - - ret |= (parsed_der && !parsed_openssl) << 4; - ret |= (valid_der && !valid_openssl) << 5; - ret |= (roundtrips_openssl && !parsed_der) << 6; - ret |= (roundtrips_der != roundtrips_openssl) << 7; - if (roundtrips_openssl) { - ret |= (len_der != (size_t)len_openssl) << 8; - ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; - } -#endif return ret; } @@ -3747,27 +6848,27 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { static void damage_array(unsigned char *sig, size_t *len) { int pos; - int action = secp256k1_rand_bits(3); + int action = testrand_bits(3); if (action < 1 && *len > 3) { /* Delete a byte. */ - pos = secp256k1_rand_int(*len); + pos = testrand_int(*len); memmove(sig + pos, sig + pos + 1, *len - pos - 1); (*len)--; return; } else if (action < 2 && *len < 2048) { /* Insert a byte. */ - pos = secp256k1_rand_int(1 + *len); + pos = testrand_int(1 + *len); memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = secp256k1_rand_bits(8); + sig[pos] = testrand_bits(8); (*len)++; return; } else if (action < 4) { /* Modify a byte. */ - sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + sig[testrand_int(*len)] += 1 + testrand_int(255); return; } else { /* action < 8 */ /* Modify a bit. */ - sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + sig[testrand_int(*len)] ^= 1 << testrand_bits(3); return; } } @@ -3780,23 +6881,23 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly int n; *len = 0; - der = secp256k1_rand_bits(2) == 0; + der = testrand_bits(2) == 0; *certainly_der = der; *certainly_not_der = 0; - indet = der ? 0 : secp256k1_rand_int(10) == 0; + indet = der ? 0 : testrand_int(10) == 0; for (n = 0; n < 2; n++) { /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + nlow[n] = der ? 1 : (testrand_bits(3) != 0); /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + nlen[n] = nlow[n] ? testrand_int(33) : 32 + testrand_int(200) * testrand_bits(3) / 8; CHECK(nlen[n] <= 232); /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : testrand_bits(1)); /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + testrand_bits(7) : 1 + testrand_int(127)); /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? testrand_int(3) : testrand_int(300 - nlen[n]) * testrand_bits(3) / 8); if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { *certainly_not_der = 1; } @@ -3805,7 +6906,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); if (!der) { /* nlenlen[n] max 127 bytes */ - int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + int add = testrand_int(127 - nlenlen[n]) * testrand_bits(4) * testrand_bits(4) / 256; nlenlen[n] += add; if (add != 0) { *certainly_not_der = 1; @@ -3819,7 +6920,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 856); /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + elen = (der || indet) ? 0 : testrand_int(980 - tlen) * testrand_bits(3) / 8; if (elen != 0) { *certainly_not_der = 1; } @@ -3827,7 +6928,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 980); /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + glen = der ? 0 : testrand_int(990 - tlen) * testrand_bits(3) / 8; if (glen != 0) { *certainly_not_der = 1; } @@ -3842,7 +6943,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly } else { int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); if (!der) { - int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + int add = testrand_int(127 - tlenlen) * testrand_bits(4) * testrand_bits(4) / 256; tlenlen += add; if (add != 0) { *certainly_not_der = 1; @@ -3893,13 +6994,13 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlen[n]--; } /* Generate remaining random bytes of number */ - secp256k1_rand_bytes_test(sig + *len, nlen[n]); + testrand_bytes_test(sig + *len, nlen[n]); *len += nlen[n]; nlen[n] = 0; } /* Generate random garbage inside tuple. */ - secp256k1_rand_bytes_test(sig + *len, elen); + testrand_bytes_test(sig + *len, elen); *len += elen; /* Generate end-of-contents bytes. */ @@ -3911,16 +7012,16 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen + glen <= 1121); /* Generate random garbage outside tuple. */ - secp256k1_rand_bytes_test(sig + *len, glen); + testrand_bytes_test(sig + *len, glen); *len += glen; tlen += glen; CHECK(tlen <= 1121); CHECK(tlen == *len); } -void run_ecdsa_der_parse(void) { +static void run_ecdsa_der_parse(void) { int i,j; - for (i = 0; i < 200 * count; i++) { + for (i = 0; i < 200 * COUNT; i++) { unsigned char buffer[2048]; size_t buflen = 0; int certainly_der = 0; @@ -3950,7 +7051,7 @@ void run_ecdsa_der_parse(void) { } /* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { +static void test_ecdsa_edge_cases(void) { int t; secp256k1_ecdsa_signature sig; @@ -3964,10 +7065,10 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&ss, &ss); secp256k1_scalar_inverse(&ss, &ss); secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); + secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); msg = ss; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Verify signature with r of zero fails. */ @@ -3986,7 +7087,7 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_set_int(&msg, 0); secp256k1_scalar_set_int(&sr, 0); CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify( &sr, &ss, &key, &msg) == 0); } /* Verify signature with s of zero fails. */ @@ -4005,7 +7106,7 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_set_int(&msg, 0); secp256k1_scalar_set_int(&sr, 1); CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Verify signature with message 0 passes. */ @@ -4033,14 +7134,14 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_set_int(&sr, 2); CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); secp256k1_scalar_set_int(&ss, 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); } /* Verify signature with message 1 passes. */ @@ -4074,15 +7175,15 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_set_b32(&sr, csr, NULL); CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 1); secp256k1_scalar_set_int(&ss, 2); secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key2, &msg) == 0); } /* Verify signature with message -1 passes. */ @@ -4108,19 +7209,18 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&msg, &msg); secp256k1_scalar_set_b32(&sr, csr, NULL); CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 1); secp256k1_scalar_set_int(&ss, 3); secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } /* Signature where s would be zero. */ { secp256k1_pubkey pubkey; size_t siglen; - int32_t ecount; unsigned char signature[72]; static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -4146,72 +7246,42 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 7); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL)); + CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey)); siglen = 72; - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); - CHECK(ecount == 10); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); - CHECK(ecount == 11); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); - CHECK(ecount == 11); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); - CHECK(ecount == 13); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); - CHECK(ecount == 13); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); + CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); siglen = 10; /* Too little room for a signature does not fail via ARGCHECK. */ - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); - CHECK(ecount == 13); - ecount = 0; - CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); - CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL)); + CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); memset(signature, 255, 64); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); - CHECK(ecount == 5); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); } /* Nonce function corner cases. */ @@ -4228,33 +7298,33 @@ void test_ecdsa_edge_cases(void) { msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0); CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1); CHECK(!is_empty_signature(&sig)); - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function is deterministic. */ - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } @@ -4265,9 +7335,9 @@ void test_ecdsa_edge_cases(void) { for(i = 256; i < 512; i++) { int j; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } @@ -4282,24 +7352,24 @@ void test_ecdsa_edge_cases(void) { unsigned char nonce2[32]; unsigned char nonce3[32]; unsigned char nonce4[32]; - VG_UNDEF(nonce,32); - VG_UNDEF(nonce2,32); - VG_UNDEF(nonce3,32); - VG_UNDEF(nonce4,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce2,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce3,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce4,32); CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); - VG_CHECK(nonce,32); + SECP256K1_CHECKMEM_CHECK(nonce,32); CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); - VG_CHECK(nonce2,32); + SECP256K1_CHECKMEM_CHECK(nonce2,32); CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); - VG_CHECK(nonce3,32); + SECP256K1_CHECKMEM_CHECK(nonce3,32); CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); - VG_CHECK(nonce4,32); - CHECK(memcmp(nonce, nonce2, 32) != 0); - CHECK(memcmp(nonce, nonce3, 32) != 0); - CHECK(memcmp(nonce, nonce4, 32) != 0); - CHECK(memcmp(nonce2, nonce3, 32) != 0); - CHECK(memcmp(nonce2, nonce4, 32) != 0); - CHECK(memcmp(nonce3, nonce4, 32) != 0); + SECP256K1_CHECKMEM_CHECK(nonce4,32); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce3, nonce4, 32) != 0); } @@ -4313,175 +7383,399 @@ void test_ecdsa_edge_cases(void) { 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; size_t outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0)); outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); + CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1)); } } -void run_ecdsa_edge_cases(void) { +static void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } -#ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const unsigned char *key32) { - unsigned char privkey[300]; - size_t privkeylen; - const unsigned char* pbegin = privkey; - int compr = secp256k1_rand_bits(1); - EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); - CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); - CHECK(EC_KEY_check_key(ec_key)); - return ec_key; -} +/** Wycheproof tests -void test_ecdsa_openssl(void) { - secp256k1_gej qj; - secp256k1_ge q; - secp256k1_scalar sigr, sigs; - secp256k1_scalar one; - secp256k1_scalar msg2; - secp256k1_scalar key, msg; - EC_KEY *ec_key; - unsigned int sigsize = 80; - size_t secp_sigsize = 80; - unsigned char message[32]; - unsigned char signature[80]; - unsigned char key32[32]; - secp256k1_rand256_test(message); - secp256k1_scalar_set_b32(&msg, message, NULL); - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(key32, &key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); - secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(key32); - CHECK(ec_key != NULL); - CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); - secp256k1_scalar_set_int(&one, 1); - secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); +The tests check for known attacks (range checks in (r,s), arithmetic errors, malleability). +*/ +static void test_ecdsa_wycheproof(void) { + #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h" - random_sign(&sigr, &sigs, &key, &msg, NULL); - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); - CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); + int t; + for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { + secp256k1_ecdsa_signature signature; + secp256k1_sha256 hasher; + secp256k1_pubkey pubkey; + const unsigned char *msg, *sig, *pk; + unsigned char out[32] = {0}; + int actual_verify = 0; - EC_KEY_free(ec_key); -} + memset(&pubkey, 0, sizeof(pubkey)); + pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset]; + CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1); -void run_ecdsa_openssl(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_ecdsa_openssl(); + secp256k1_sha256_initialize(&hasher); + msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; + secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len); + secp256k1_sha256_finalize(&hasher, out); + + sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset]; + if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) { + actual_verify = secp256k1_ecdsa_verify(CTX, (const secp256k1_ecdsa_signature *)&signature, out, &pubkey); + } + CHECK(testvectors[t].expected_verify == actual_verify); } } -#endif + +/* Tests cases from Wycheproof test suite. */ +static void run_ecdsa_wycheproof(void) { + test_ecdsa_wycheproof(); +} #ifdef ENABLE_MODULE_ECDH # include "modules/ecdh/tests_impl.h" #endif -#ifdef ENABLE_MODULE_SCHNORR -# include "modules/schnorr/tests_impl.h" -#endif - #ifdef ENABLE_MODULE_RECOVERY # include "modules/recovery/tests_impl.h" #endif +#ifdef ENABLE_MODULE_EXTRAKEYS +# include "modules/extrakeys/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT +# include "modules/ellswift/tests_impl.h" +#endif + +static void run_secp256k1_memczero_test(void) { + unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; + unsigned char buf2[sizeof(buf1)]; + + /* secp256k1_memczero(..., ..., 0) is a noop. */ + memcpy(buf2, buf1, sizeof(buf1)); + secp256k1_memczero(buf1, sizeof(buf1), 0); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); + + /* secp256k1_memczero(..., ..., 1) zeros the buffer. */ + memset(buf2, 0, sizeof(buf2)); + secp256k1_memczero(buf1, sizeof(buf1) , 1); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); +} + + +static void run_secp256k1_is_zero_array_test(void) { + unsigned char buf1[3] = {0, 1}; + unsigned char buf2[3] = {1, 0}; + + CHECK(secp256k1_is_zero_array(buf1, 0) == 1); + CHECK(secp256k1_is_zero_array(buf1, 1) == 1); + CHECK(secp256k1_is_zero_array(buf1, 2) == 0); + CHECK(secp256k1_is_zero_array(buf2, 1) == 0); + CHECK(secp256k1_is_zero_array(buf2, 2) == 0); +} + +static void run_secp256k1_byteorder_tests(void) { + { + const uint32_t x = 0xFF03AB45; + const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; + unsigned char buf[4]; + uint32_t x_; + + secp256k1_write_be32(buf, x); + CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); + + x_ = secp256k1_read_be32(buf); + CHECK(x == x_); + } + + { + const uint64_t x = 0xCAFE0123BEEF4567; + const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67}; + unsigned char buf[8]; + uint64_t x_; + + secp256k1_write_be64(buf, x); + CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0); + + x_ = secp256k1_read_be64(buf); + CHECK(x == x_); + } +} + +static void int_cmov_test(void) { + int r = INT_MAX; + int a = 0; + + secp256k1_int_cmov(&r, &a, 0); + CHECK(r == INT_MAX); + + r = 0; a = INT_MAX; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == INT_MAX); + + a = 0; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == 0); + + a = 1; + secp256k1_int_cmov(&r, &a, 1); + CHECK(r == 1); + + r = 1; a = 0; + secp256k1_int_cmov(&r, &a, 0); + CHECK(r == 1); + +} + +static void fe_cmov_test(void) { + static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_fe max = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_fe r = max; + secp256k1_fe a = zero; + + secp256k1_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &max)); + + r = zero; a = max; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &max)); + + a = zero; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &zero)); + + a = one; + secp256k1_fe_cmov(&r, &a, 1); + CHECK(fe_identical(&r, &one)); + + r = one; a = zero; + secp256k1_fe_cmov(&r, &a, 0); + CHECK(fe_identical(&r, &one)); +} + +static void fe_storage_cmov_test(void) { + static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_fe_storage r = max; + secp256k1_fe_storage a = zero; + + secp256k1_fe_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = zero; a = max; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = zero; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); + + a = one; + secp256k1_fe_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + + r = one; a = zero; + secp256k1_fe_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); +} + +static void scalar_cmov_test(void) { + static const secp256k1_scalar max = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL + ); + secp256k1_scalar r = max; + secp256k1_scalar a = secp256k1_scalar_zero; + + secp256k1_scalar_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = secp256k1_scalar_zero; a = max; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = secp256k1_scalar_zero; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_zero, sizeof(r)) == 0); + + a = secp256k1_scalar_one; + secp256k1_scalar_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); + + r = secp256k1_scalar_one; a = secp256k1_scalar_zero; + secp256k1_scalar_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); +} + +static void ge_storage_cmov_test(void) { + static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); + static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + secp256k1_ge_storage r = max; + secp256k1_ge_storage a = zero; + + secp256k1_ge_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + r = zero; a = max; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); + + a = zero; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); + + a = one; + secp256k1_ge_storage_cmov(&r, &a, 1); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + + r = one; a = zero; + secp256k1_ge_storage_cmov(&r, &a, 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); +} + +static void run_cmov_tests(void) { + int_cmov_test(); + fe_cmov_test(); + fe_storage_cmov_test(); + scalar_cmov_test(); + ge_storage_cmov_test(); +} + int main(int argc, char **argv) { - unsigned char seed16[16] = {0}; - unsigned char run32[32] = {0}; + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + /* find iteration count */ if (argc > 1) { - count = strtol(argv[1], NULL, 0); - } - - /* find random seed */ - if (argc > 2) { - int pos = 0; - const char* ch = argv[2]; - while (pos < 16 && ch[0] != 0 && ch[1] != 0) { - unsigned short sh; - if (sscanf(ch, "%2hx", &sh)) { - seed16[pos] = sh; - } else { - break; - } - ch += 2; - pos++; - } + COUNT = strtol(argv[1], NULL, 0); } else { - FILE *frand = fopen("/dev/urandom", "r"); - if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { - uint64_t t = time(NULL) * (uint64_t)1337; - seed16[0] ^= t; - seed16[1] ^= t >> 8; - seed16[2] ^= t >> 16; - seed16[3] ^= t >> 24; - seed16[4] ^= t >> 32; - seed16[5] ^= t >> 40; - seed16[6] ^= t >> 48; - seed16[7] ^= t >> 56; + const char* env = getenv("SECP256K1_TEST_ITERS"); + if (env && strlen(env) > 0) { + COUNT = strtol(env, NULL, 0); } - fclose(frand); } - secp256k1_rand_seed(seed16); + if (COUNT <= 0) { + fputs("An iteration count of 0 or less is not allowed.\n", stderr); + return EXIT_FAILURE; + } + printf("test count = %i\n", COUNT); - printf("test count = %i\n", count); - printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + /* run test RNG tests (must run before we really initialize the test RNG) */ + run_xoshiro256pp_tests(); - /* initialize */ - run_context_tests(); - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if (secp256k1_rand_bits(1)) { - secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); - } + /* find random seed */ + testrand_init(argc > 2 ? argv[2] : NULL); + + /*** Setup test environment ***/ + + /* Create a global context available to all tests */ + CTX = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + /* Randomize the context only with probability 15/16 + to make sure we test without context randomization from time to time. + TODO Reconsider this when recalibrating the tests. */ + if (testrand_bits(4)) { + unsigned char rand32[32]; + testrand256(rand32); + CHECK(secp256k1_context_randomize(CTX, rand32)); + } + /* Make a writable copy of secp256k1_context_static in order to test the effect of API functions + that write to the context. The API does not support cloning the static context, so we use + memcpy instead. The user is not supposed to copy a context but we should still ensure that + the API functions handle copies of the static context gracefully. */ + STATIC_CTX = malloc(sizeof(*secp256k1_context_static)); + CHECK(STATIC_CTX != NULL); + memcpy(STATIC_CTX, secp256k1_context_static, sizeof(secp256k1_context)); + CHECK(!secp256k1_context_is_proper(STATIC_CTX)); + + /*** Run actual tests ***/ + + /* selftest tests */ + run_selftest_tests(); + + /* context tests */ + run_proper_context_tests(0); run_proper_context_tests(1); + run_static_context_tests(0); run_static_context_tests(1); + run_deprecated_context_flags_test(); + + /* scratch tests */ + run_scratch_tests(); + + /* integer arithmetic tests */ +#ifdef SECP256K1_WIDEMUL_INT128 + run_int128_tests(); +#endif + run_ctz_tests(); + run_modinv_tests(); + run_inverse_tests(); - run_rand_bits(); - run_rand_int(); + /* sorting tests */ + run_hsort_tests(); - run_sha256_tests(); + /* hash tests */ + run_sha256_known_output_tests(); + run_sha256_counter_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); - -#ifndef USE_NUM_NONE - /* num tests */ - run_num_smalltests(); -#endif + run_tagged_sha256_tests(); /* scalar tests */ run_scalar_tests(); /* field tests */ - run_field_inv(); - run_field_inv_var(); - run_field_inv_all_var(); + run_field_half(); run_field_misc(); run_field_convert(); + run_field_be32_overflow(); + run_fe_mul(); run_sqr(); run_sqrt(); /* group tests */ run_ge(); + run_gej(); run_group_decompress(); /* ecmult tests */ + run_ecmult_pre_g(); run_wnaf(); run_point_times_order(); + run_ecmult_near_split_bound(); run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); run_ecmult_const_tests(); + run_ecmult_multi_tests(); run_ec_combine(); /* endomorphism tests */ -#ifdef USE_ENDOMORPHISM run_endomorphism_tests(); -#endif /* EC point parser test */ run_ec_pubkey_parse_test(); @@ -4489,37 +7783,59 @@ int main(int argc, char **argv) { /* EC key edge cases */ run_eckey_edge_case_test(); + /* EC key arithmetic test */ + run_eckey_negate_test(); + #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); #endif /* ecdsa tests */ + run_ec_illegal_argument_tests(); + run_pubkey_comparison(); + run_pubkey_sort(); run_random_pubkeys(); run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); -#ifdef ENABLE_OPENSSL_TESTS - run_ecdsa_openssl(); -#endif - -#ifdef ENABLE_MODULE_SCHNORR - /* Schnorr tests */ - run_schnorr_tests(); -#endif + run_ecdsa_wycheproof(); #ifdef ENABLE_MODULE_RECOVERY /* ECDSA pubkey recovery tests */ run_recovery_tests(); #endif - secp256k1_rand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); +#ifdef ENABLE_MODULE_EXTRAKEYS + run_extrakeys_tests(); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + run_schnorrsig_tests(); +#endif + +#ifdef ENABLE_MODULE_MUSIG + run_musig_tests(); +#endif + +#ifdef ENABLE_MODULE_ELLSWIFT + run_ellswift_tests(); +#endif + + /* util tests */ + run_secp256k1_memczero_test(); + run_secp256k1_is_zero_array_test(); + run_secp256k1_byteorder_tests(); + + run_cmov_tests(); - /* shutdown */ - secp256k1_context_destroy(ctx); + /*** Tear down test environment ***/ + free(STATIC_CTX); + secp256k1_context_destroy(CTX); + + testrand_finish(); printf("no problems found\n"); - return 0; + return EXIT_SUCCESS; } diff --git a/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c b/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c index b040bb073..f8bbcaaf5 100644 --- a/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c +++ b/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c @@ -1,75 +1,48 @@ /*********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ #include #include - #include -#undef USE_ECMULT_STATIC_PRECOMPUTATION - #ifndef EXHAUSTIVE_TEST_ORDER /* see group_impl.h for allowable values */ #define EXHAUSTIVE_TEST_ORDER 13 -#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ #endif -#include "include/secp256k1.h" -#include "group.h" -#include "secp256k1.c" -#include "testrand_impl.h" +/* These values of B are all values in [1, 8] that result in a curve with even order. */ +#define EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER (SECP256K1_B == 1 || SECP256K1_B == 6 || SECP256K1_B == 8) -#ifdef ENABLE_MODULE_RECOVERY -#include "src/modules/recovery/main_impl.h" -#include "include/secp256k1_recovery.h" +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS #endif +#include "secp256k1.c" -/** stolen from tests.c */ -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); -} +#include "../include/secp256k1.h" +#include "assumptions.h" +#include "group.h" +#include "testrand_impl.h" +#include "ecmult_compute_table_impl.h" +#include "ecmult_gen_compute_table_impl.h" +#include "testutil.h" +#include "util.h" -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - secp256k1_fe_sqr(&z2s, &b->z); - secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); - secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); -} +static int count = 2; -void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); +static uint32_t num_cores = 1; +static uint32_t this_core = 0; + +SECP256K1_INLINE static int skip_section(uint64_t* iter) { + if (num_cores == 1) return 0; + *iter += 0xe7037ed1a0b428dbULL; + return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; } -/** END stolen from tests.c */ -int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, +static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int attempt) { secp256k1_scalar s; @@ -89,115 +62,184 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha return 1; } -#ifdef USE_ENDOMORPHISM -void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { +static void test_exhaustive_endomorphism(const secp256k1_ge *group) { int i; - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge res; secp256k1_ge_mul_lambda(&res, &group[i]); - ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res)); } } -#endif -void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { +static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j; + uint64_t iter = 0; /* Sanity-check (and check infinity functions) */ CHECK(secp256k1_ge_is_infinity(&group[0])); CHECK(secp256k1_gej_is_infinity(&groupj[0])); - for (i = 1; i < order; i++) { + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { CHECK(!secp256k1_ge_is_infinity(&group[i])); CHECK(!secp256k1_gej_is_infinity(&groupj[i])); } /* Check all addition formulae */ - for (j = 0; j < order; j++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { secp256k1_fe fe_inv; + if (skip_section(&iter)) continue; secp256k1_fe_inv(&fe_inv, &groupj[j].z); - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge zless_gej; secp256k1_gej tmp; /* add_var */ secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); /* add_ge */ if (j > 0) { secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); - ge_equals_gej(&group[(i + j) % order], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); } /* add_ge_var */ secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); /* add_zinv_var */ zless_gej.infinity = groupj[j].infinity; zless_gej.x = groupj[j].x; zless_gej.y = groupj[j].y; secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - ge_equals_gej(&group[(i + j) % order], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); } } /* Check doubling */ - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_gej tmp; - if (i > 0) { - secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % order], &tmp); - } + secp256k1_gej_double(&tmp, &groupj[i]); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); secp256k1_gej_double_var(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % order], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); } /* Check negation */ - for (i = 1; i < order; i++) { + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge tmp; secp256k1_gej tmpj; secp256k1_ge_neg(&tmp, &group[i]); - ge_equals_ge(&group[order - i], &tmp); + CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i])); secp256k1_gej_neg(&tmpj, &groupj[i]); - ge_equals_gej(&group[order - i], &tmpj); + CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i])); } } -void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { +static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j, r_log; - for (r_log = 1; r_log < order; r_log++) { - for (j = 0; j < order; j++) { - for (i = 0; i < order; i++) { + uint64_t iter = 0; + for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + if (skip_section(&iter)) continue; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_gej tmp; secp256k1_scalar na, ng; secp256k1_scalar_set_int(&na, i); secp256k1_scalar_set_int(&ng, j); - secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); - ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER])); + } + } + } + + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + int ret; + secp256k1_gej tmp; + secp256k1_fe xn, xd, tmpf; + secp256k1_scalar ng; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&ng, j); + + /* Test secp256k1_ecmult_const. */ + secp256k1_ecmult_const(&tmp, &group[i], &ng); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER])); + + if (i != 0 && j != 0) { + /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ + ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); + CHECK(ret); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + + /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ + testutil_random_fe_non_zero(&xd); + secp256k1_fe_mul(&xn, &xd, &group[i].x); + ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); + CHECK(ret); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + } + } + } +} + +typedef struct { + secp256k1_scalar sc[2]; + secp256k1_ge pt[2]; +} ecmult_multi_data; - if (i > 0) { - secp256k1_ecmult_const(&tmp, &group[i], &ng); - ge_equals_gej(&group[(i * j) % order], &tmp); +static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k, x, y; + uint64_t iter = 0; + secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { + if (skip_section(&iter)) continue; + for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { + secp256k1_gej tmp; + secp256k1_scalar g_sc; + ecmult_multi_data data; + + secp256k1_scalar_set_int(&data.sc[0], i); + secp256k1_scalar_set_int(&data.sc[1], j); + secp256k1_scalar_set_int(&g_sc, k); + data.pt[0] = group[x]; + data.pt[1] = group[y]; + + secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER])); + } } } } } + secp256k1_scratch_destroy(&ctx->error_callback, scratch); } -void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { +static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { secp256k1_fe x; unsigned char x_bin[32]; k %= EXHAUSTIVE_TEST_ORDER; x = group[k].x; secp256k1_fe_normalize(&x); secp256k1_fe_get_b32(x_bin, &x); - secp256k1_scalar_set_b32(r, x_bin, NULL); + secp256k1_scalar_set_b32(r, x_bin, overflow); } -void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { +static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { secp256k1_ge nonconst_ge; secp256k1_ecdsa_signature sig; secp256k1_pubkey pk; @@ -206,6 +248,8 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr int k, should_verify; unsigned char msg32[32]; + if (skip_section(&iter)) continue; + secp256k1_scalar_set_int(&s_s, s); secp256k1_scalar_set_int(&r_s, r); secp256k1_scalar_set_int(&msg_s, msg); @@ -215,9 +259,9 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr /* Run through every k value that gives us this r and check that *one* works. * Note there could be none, there could be multiple, ECDSA is weird. */ should_verify = 0; - for (k = 0; k < order; k++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); + r_from_k(&check_x_s, group, k, NULL); if (r_s == check_x_s) { secp256k1_scalar_set_int(&s_times_k_s, k); secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); @@ -242,14 +286,17 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr } } -void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { +static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k; + uint64_t iter = 0; /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ const int starting_k = k; + int ret; secp256k1_ecdsa_signature sig; secp256k1_scalar sk, msg, r, s, expected_r; unsigned char sk32[32], msg32[32]; @@ -258,16 +305,17 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou secp256k1_scalar_get_b32(sk32, &sk); secp256k1_scalar_get_b32(msg32, &msg); - secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + ret = secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + CHECK(ret == 1); secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); /* Note that we compute expected_r *after* signing -- this is important * because our nonce-computing function function might change k during * signing. */ - r_from_k(&expected_r, group, k); + r_from_k(&expected_r, group, k, NULL); CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); /* Overflow means we've tried every possible nonce */ if (k < starting_k) { @@ -288,183 +336,131 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou } #ifdef ENABLE_MODULE_RECOVERY -void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - int i, j, k; - - /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ - const int starting_k = k; - secp256k1_fe r_dot_y_normalized; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - int expected_recid; - int recid; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); +#include "modules/recovery/tests_exhaustive_impl.h" +#endif - secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); +#ifdef ENABLE_MODULE_EXTRAKEYS +#include "modules/extrakeys/tests_exhaustive_impl.h" +#endif - /* Check directly */ - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); - /* In computing the recid, there is an overflow condition that is disabled in - * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value - * will exceed the group order, and our signing code always holds out for r - * values that don't overflow, so with a proper overflow check the tests would - * loop indefinitely. */ - r_dot_y_normalized = group[k].y; - secp256k1_fe_normalize(&r_dot_y_normalized); - /* Also the recovery id is flipped depending if we hit the low-s branch */ - if ((k * s) % order == (i + r * j) % order) { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; - } else { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; - } - CHECK(recid == expected_recid); +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "modules/schnorrsig/tests_exhaustive_impl.h" +#endif - /* Convert to a standard sig then check */ - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); +#ifdef ENABLE_MODULE_ELLSWIFT +#include "modules/ellswift/tests_exhaustive_impl.h" +#endif - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } +int main(int argc, char** argv) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + unsigned char rand32[32]; + secp256k1_context *ctx; + + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + + printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); + + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + printf("test count = %i\n", count); + + /* find random seed */ + testrand_init(argc > 2 ? argv[2] : NULL); + + /* set up split processing */ + if (argc > 4) { + num_cores = strtol(argv[3], NULL, 0); + this_core = strtol(argv[4], NULL, 0); + if (num_cores < 1 || this_core >= num_cores) { + fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); + return EXIT_FAILURE; } + printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); } -} -void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - /* This is essentially a copy of test_exhaustive_verify, with recovery added */ - int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int recid = 0; - int k, should_verify; - unsigned char msg32[32]; + /* Recreate the ecmult{,_gen} tables using the right generator (as selected via EXHAUSTIVE_TEST_ORDER) */ + secp256k1_ecmult_gen_compute_table(&secp256k1_ecmult_gen_prec_table[0][0], &secp256k1_ge_const_g, COMB_BLOCKS, COMB_TEETH, COMB_SPACING); + secp256k1_ecmult_compute_two_tables(secp256k1_pre_g, secp256k1_pre_g_128, WINDOW_G, &secp256k1_ge_const_g); + + while (count--) { + /* Build context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + testrand256(rand32); + CHECK(secp256k1_context_randomize(ctx, rand32)); + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + if (count != 0) { + /* Set a different random z-value for each Jacobian point, except z=1 + is used in the last iteration. */ + secp256k1_fe z; + testutil_random_fe(&z); + secp256k1_gej_rescale(&groupj[i], &z); + } - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - secp256k1_scalar_get_b32(msg32, &msg_s); + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < order; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); - /* We would like to try recovering the pubkey and checking that it matches, - * but pubkey recovery is impossible in the exhaustive tests (the reason - * being that there are 12 nonzero r values, 12 nonzero points, and no - * overlap between the sets, so there are no valid signatures). */ - - /* Verify by converting to a standard signature and calling verify */ - secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal(&generated.y, &group[i].y)); } } - } -} -#endif -int main(void) { - int i; - secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; - secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + /* Run the tests */ + test_exhaustive_endomorphism(group); + test_exhaustive_addition(group, groupj); + test_exhaustive_ecmult(group, groupj); + test_exhaustive_ecmult_multi(ctx, group); + test_exhaustive_sign(ctx, group); + test_exhaustive_verify(ctx, group); - /* Build context */ - secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - /* TODO set z = 1, then do num_tests runs with random z values */ +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery(ctx, group); +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + test_exhaustive_extrakeys(ctx, group); +#endif +#ifdef ENABLE_MODULE_SCHNORRSIG + test_exhaustive_schnorrsig(ctx); +#endif +#ifdef ENABLE_MODULE_ELLSWIFT + /* The ellswift algorithm does have additional edge cases when operating on + * curves of even order, which are not included in the code as secp256k1 is + * of odd order. Skip the ellswift tests if the used exhaustive tests curve + * is even-ordered accordingly. */ + #if !EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER + test_exhaustive_ellswift(ctx, group); + #endif +#endif - /* Generate the entire group */ - secp256k1_gej_set_infinity(&groupj[0]); - secp256k1_ge_set_gej(&group[0], &groupj[0]); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - /* Set a different random z-value for each Jacobian point */ - secp256k1_fe z; - random_fe(&z); - - secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); - secp256k1_ge_set_gej(&group[i], &groupj[i]); - secp256k1_gej_rescale(&groupj[i], &z); - - /* Verify against ecmult_gen */ - { - secp256k1_scalar scalar_i; - secp256k1_gej generatedj; - secp256k1_ge generated; - - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); - - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); - } + secp256k1_context_destroy(ctx); } - /* Run the tests */ -#ifdef USE_ENDOMORPHISM - test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); -#endif - test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + testrand_finish(); -#ifdef ENABLE_MODULE_RECOVERY - test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); -#endif - - secp256k1_context_destroy(ctx); - return 0; + printf("no problems found\n"); + return EXIT_SUCCESS; } - diff --git a/crypto/secp256k1/libsecp256k1/src/testutil.h b/crypto/secp256k1/libsecp256k1/src/testutil.h new file mode 100644 index 000000000..64b3bb41c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/testutil.h @@ -0,0 +1,148 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTUTIL_H +#define SECP256K1_TESTUTIL_H + +#include "field.h" +#include "group.h" +#include "testrand.h" +#include "util.h" + +static void testutil_random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + testrand256(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero(secp256k1_fe *nz) { + do { + testutil_random_fe(nz); + } while (secp256k1_fe_is_zero(nz)); +} + +static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) { + secp256k1_fe zero; + int n = testrand_int(m + 1); + secp256k1_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_fe_set_int(&zero, 0); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int_unchecked(&zero, n - 1); + secp256k1_fe_add(fe, &zero); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif +} + +static void testutil_random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + testrand256_test(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void testutil_random_fe_non_zero_test(secp256k1_fe *fe) { + do { + testutil_random_fe_test(fe); + } while(secp256k1_fe_is_zero(fe)); +} + +static void testutil_random_ge_x_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); +} + +static void testutil_random_ge_y_magnitude(secp256k1_ge *ge) { + testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_x_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); +} + +static void testutil_random_gej_y_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); +} + +static void testutil_random_gej_z_magnitude(secp256k1_gej *gej) { + testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); +} + +static void testutil_random_ge_test(secp256k1_ge *ge) { + secp256k1_fe fe; + do { + testutil_random_fe_test(&fe); + if (secp256k1_ge_set_xo_var(ge, &fe, testrand_bits(1))) { + secp256k1_fe_normalize(&ge->y); + break; + } + } while(1); + ge->infinity = 0; +} + +static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; + testutil_random_fe_non_zero_test(&gej->z); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +static void testutil_random_gej_test(secp256k1_gej *gej) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + testutil_random_ge_jacobian_test(gej, &ge); +} + +static void testutil_random_pubkey_test(secp256k1_pubkey *pk) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + secp256k1_pubkey_save(pk, &ge); +} + +static void testutil_random_scalar_order_test(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256_test(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + testrand256(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +static void testutil_random_scalar_order_b32(unsigned char *b32) { + secp256k1_scalar num; + testutil_random_scalar_order(&num); + secp256k1_scalar_get_b32(b32, &num); +} + +#endif /* SECP256K1_TESTUTIL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/util.h b/crypto/secp256k1/libsecp256k1/src/util.h index 4092a86c9..5f29f4076 100644 --- a/crypto/secp256k1/libsecp256k1/src/util.h +++ b/crypto/secp256k1/libsecp256k1/src/util.h @@ -1,19 +1,88 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ +/*********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ -#ifndef _SECP256K1_UTIL_H_ -#define _SECP256K1_UTIL_H_ +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif +#include "../include/secp256k1.h" +#include "checkmem.h" +#include #include #include #include +#include +#if defined(_MSC_VER) +/* For SecureZeroMemory */ +#include +#endif + +#define STR_(x) #x +#define STR(x) STR_(x) +#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x +#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) + +/* Debug helper for printing arrays of unsigned char. */ +#define PRINT_BUF(buf, len) do { \ + printf("%s[%lu] = ", #buf, (unsigned long)len); \ + print_buf_plain(buf, len); \ +} while(0) + +static void print_buf_plain(const unsigned char *buf, size_t len) { + size_t i; + printf("{"); + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + printf("\n "); + } else { + printf(" "); + } + printf("0x%02X,", buf[i]); + } + printf("\n}\n"); +} + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +/** Assert statically that expr is true. + * + * This is a statement-like macro and can only be used inside functions. + */ +#define STATIC_ASSERT(expr) do { \ + switch(0) { \ + case 0: \ + /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ + case /* ERROR: static assertion failed */ (expr): \ + ; \ + } \ +} while(0) + +/** Assert statically that expr is an integer constant expression, and run stmt. + * + * Useful for example to enforce that magnitude arguments are constant. + */ +#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ + switch(42) { \ + /* C allows only integer constant expressions as case labels. */ \ + case /* ERROR: integer argument is not constant */ (expr): \ + break; \ + default: ; \ + } \ + stmt; \ +} while(0) typedef struct { void (*fn)(const char *text, void* data); @@ -24,6 +93,33 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * cb->fn(text, (void*)cb->data); } +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +static void secp256k1_default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} +static void secp256k1_default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} +#else +void secp256k1_default_illegal_callback_fn(const char* str, void* data); +void secp256k1_default_error_callback_fn(const char* str, void* data); +#endif + +static const secp256k1_callback default_illegal_callback = { + secp256k1_default_illegal_callback_fn, + NULL +}; + +static const secp256k1_callback default_error_callback = { + secp256k1_default_error_callback_fn, + NULL +}; + + #ifdef DETERMINISTIC #define TEST_FAILURE(msg) do { \ fprintf(stderr, "%s\n", msg); \ @@ -36,7 +132,7 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * } while(0) #endif -#ifdef HAVE_BUILTIN_EXPECT +#if SECP256K1_GNUC_PREREQ(3, 0) #define EXPECT(x,c) __builtin_expect((x),(c)) #else #define EXPECT(x,c) (x) @@ -56,16 +152,11 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * } while(0) #endif -/* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#if defined(COVERAGE) -#define VERIFY_CHECK(check) -#define VERIFY_SETUP(stmt) -#elif defined(VERIFY) +/* Like assert(), but when VERIFY is defined. */ +#if defined(VERIFY) #define VERIFY_CHECK CHECK -#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else -#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) -#define VERIFY_SETUP(stmt) +#define VERIFY_CHECK(cond) #endif static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { @@ -76,6 +167,20 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ return ret; } +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +/* ceil(x/y) for integers x > 0 and y > 0. Here, / denotes rational division. */ +#define CEIL_DIV(x, y) (1 + ((x) - 1) / (y)) + +#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT) + /* Macro for restrict, when available and not in a VERIFY build. */ #if defined(SECP256K1_BUILD) && defined(VERIFY) # define SECP256K1_RESTRICT @@ -93,21 +198,254 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ # endif #endif -#if defined(_WIN32) -# define I64FORMAT "I64d" -# define I64uFORMAT "I64u" +#if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ #else -# define I64FORMAT "lld" -# define I64uFORMAT "llu" +# define SECP256K1_GNUC_EXT #endif -#if defined(HAVE___INT128) -# if defined(__GNUC__) -# define SECP256K1_GNUC_EXT __extension__ -# else -# define SECP256K1_GNUC_EXT -# endif -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +/* Zero memory if flag == 1. Flag must be 0 or 1. Constant time. */ +static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) { + unsigned char *p = (unsigned char *)s; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + unsigned char mask = -(unsigned char) vflag; + while (len) { + *p &= ~mask; + p++; + len--; + } +} + +/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ +static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it + * is pretty efficient, because the compiler can still implement the memset() efficiently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); #endif +#ifdef VERIFY + SECP256K1_CHECKMEM_UNDEFINE(ptr, len); +#endif +} + +/** Semantics like memcmp. Variable-time. + * + * We use this to avoid possible compiler bugs with memcmp, e.g. + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 + */ +static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1, *p2 = s2; + size_t i; + for (i = 0; i < n; i++) { + int diff = p1[i] - p2[i]; + if (diff != 0) { + return diff; + } + } + return 0; +} + +/* Return 1 if all elements of array s are 0 and otherwise return 0. + * Constant-time. */ +static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size_t len) { + unsigned char acc = 0; + int ret; + size_t i; + + for (i = 0; i < len; i++) { + acc |= s[i]; + } + ret = (acc == 0); + /* acc may contain secret values. Try to explicitly clear it. */ + secp256k1_memclear(&acc, sizeof(acc)); + return ret; +} + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ +static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) { + unsigned int mask0, mask1, r_masked, a_masked; + /* Access flag with a volatile-qualified lvalue. + This prevents clang from figuring out (after inlining) that flag can + take only be 0 or 1, which leads to variable time code. */ + volatile int vflag = flag; + + /* Casting a negative int to unsigned and back to int is implementation defined behavior */ + VERIFY_CHECK(*r >= 0 && *a >= 0); + + mask0 = (unsigned int)vflag + ~0u; + mask1 = ~mask0; + r_masked = ((unsigned int)*r & mask0); + a_masked = ((unsigned int)*a & mask1); + + *r = (int)(r_masked | a_masked); +} + +#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) +/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif defined(USE_FORCE_WIDEMUL_INT128) +/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(USE_FORCE_WIDEMUL_INT64) +/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ +# define SECP256K1_WIDEMUL_INT64 1 +#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) +/* If a native 128-bit integer type exists, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) +/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct + * (which has special logic to implement using intrinsics on those systems). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif SIZE_MAX > 0xffffffff +/* Systems with 64-bit pointers (and thus registers) very likely benefit from + * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based + * multiplication logic). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#else +/* Lastly, fall back to int64 based arithmetic. */ +# define SECP256K1_WIDEMUL_INT64 1 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 #endif + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. + * This function is only intended to be used as fallback for + * secp256k1_ctz32_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) { + static const uint8_t debruijn[32] = { + 0x00, 0x01, 0x02, 0x18, 0x03, 0x13, 0x06, 0x19, 0x16, 0x04, 0x14, 0x0A, + 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, + 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B + }; + return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. + * This function is only intended to be used as fallback for + * secp256k1_ctz64_var, but permits it to be tested separately. */ +static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) { + static const uint8_t debruijn[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; +} + +/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ +static SECP256K1_INLINE int secp256k1_ctz32_var(uint32_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned type is sufficient to represent the largest uint32_t, consider __builtin_ctz. */ + if (((unsigned)UINT32_MAX) == UINT32_MAX) { + return __builtin_ctz(x); + } +#endif +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzl (the unsigned long type is always at least 32 bits). */ + return __builtin_ctzl(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return secp256k1_ctz32_var_debruijn(x); +#endif +} + +/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. */ +static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) { + VERIFY_CHECK(x != 0); +#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4)) + /* If the unsigned long type is sufficient to represent the largest uint64_t, consider __builtin_ctzl. */ + if (((unsigned long)UINT64_MAX) == UINT64_MAX) { + return __builtin_ctzl(x); + } +#endif +#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4)) + /* Otherwise consider __builtin_ctzll (the unsigned long long type is always at least 64 bits). */ + return __builtin_ctzll(x); +#else + /* If no suitable CTZ builtin is available, use a (variable time) software emulation. */ + return secp256k1_ctz64_var_debruijn(x); +#endif +} + +/* Read a uint32_t in big endian */ +SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) { + return (uint32_t)p[0] << 24 | + (uint32_t)p[1] << 16 | + (uint32_t)p[2] << 8 | + (uint32_t)p[3]; +} + +/* Write a uint32_t in big endian */ +SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) { + p[3] = x; + p[2] = x >> 8; + p[1] = x >> 16; + p[0] = x >> 24; +} + +/* Read a uint64_t in big endian */ +SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) { + return (uint64_t)p[0] << 56 | + (uint64_t)p[1] << 48 | + (uint64_t)p[2] << 40 | + (uint64_t)p[3] << 32 | + (uint64_t)p[4] << 24 | + (uint64_t)p[5] << 16 | + (uint64_t)p[6] << 8 | + (uint64_t)p[7]; +} + +/* Write a uint64_t in big endian */ +SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) { + p[7] = x; + p[6] = x >> 8; + p[5] = x >> 16; + p[4] = x >> 24; + p[3] = x >> 32; + p[2] = x >> 40; + p[1] = x >> 48; + p[0] = x >> 56; +} + +/* Rotate a uint32_t to the right. */ +SECP256K1_INLINE static uint32_t secp256k1_rotr32(const uint32_t x, const unsigned int by) { +#if defined(_MSC_VER) + return _rotr(x, by); /* needs */ +#else + /* Reduce rotation amount to avoid UB when shifting. */ + const unsigned int mask = CHAR_BIT * sizeof(x) - 1; + /* Turned into a rot instruction by GCC and clang. */ + return (x >> (by & mask)) | (x << ((-by) & mask)); +#endif +} + +#endif /* SECP256K1_UTIL_H */ diff --git a/crypto/secp256k1/libsecp256k1/src/wycheproof/WYCHEPROOF_COPYING b/crypto/secp256k1/libsecp256k1/src/wycheproof/WYCHEPROOF_COPYING new file mode 100644 index 000000000..cddf9d918 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/wycheproof/WYCHEPROOF_COPYING @@ -0,0 +1,212 @@ +* The file `ecdsa_secp256k1_sha256_bitcoin_test.json` in this directory + comes from Google's project Wycheproof with git commit + `b063b4aedae951c69df014cd25fa6d69ae9e8cb9`, see + https://github.com/google/wycheproof/blob/b063b4aedae951c69df014cd25fa6d69ae9e8cb9/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json + +* The file `ecdsa_secp256k1_sha256_bitcoin_test.h` is generated from + `ecdsa_secp256k1_sha256_bitcoin_test.json` using the script + `tests_wycheproof_generate.py`. + +------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h b/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h new file mode 100644 index 000000000..736737fd6 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h @@ -0,0 +1,1564 @@ +/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */ +#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS (463) + +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; + +static const unsigned char wycheproof_ecdsa_messages[] = { 0x31,0x32,0x33,0x34,0x30,0x30, + 0x32,0x35,0x35,0x38,0x35, + 0x34,0x32,0x36,0x34,0x37,0x39,0x37,0x32,0x34, + 0x37,0x31,0x33,0x38,0x36,0x38,0x34,0x38,0x39,0x31, + 0x31,0x30,0x33,0x35,0x39,0x33,0x33,0x31,0x36,0x36,0x38, + 0x33,0x39,0x34,0x39,0x34,0x30,0x31,0x32,0x31,0x35, + 0x31,0x33,0x34,0x34,0x32,0x39,0x33,0x30,0x37,0x39, + 0x33,0x37,0x30,0x36,0x32,0x31,0x31,0x37,0x31,0x32, + 0x33,0x34,0x33,0x36,0x38,0x38,0x37,0x31,0x32, + 0x31,0x33,0x35,0x31,0x35,0x33,0x30,0x33,0x37,0x30, + 0x36,0x35,0x35,0x33,0x32,0x30,0x33,0x31,0x32,0x36, + 0x31,0x35,0x36,0x34,0x33,0x34,0x36,0x36,0x30,0x33, + 0x34,0x34,0x32,0x39,0x35,0x33,0x39,0x31,0x31,0x37, + 0x31,0x30,0x39,0x35,0x33,0x32,0x36,0x31,0x33,0x35,0x31, + 0x35,0x39,0x38,0x37,0x33,0x35,0x30,0x30,0x34,0x31, + 0x33,0x34,0x36,0x33,0x30,0x30,0x36,0x38,0x37,0x38, + 0x39,0x38,0x31,0x37,0x33,0x32,0x30,0x32,0x38,0x37, + 0x33,0x32,0x32,0x32,0x30,0x34,0x31,0x30,0x34,0x36, + 0x36,0x36,0x36,0x36,0x33,0x30,0x37,0x31,0x30,0x34, + 0x31,0x30,0x33,0x35,0x39,0x35,0x31,0x38,0x39,0x38, + 0x31,0x38,0x34,0x36,0x35,0x39,0x37,0x31,0x39,0x35, + 0x33,0x31,0x33,0x36,0x30,0x34,0x36,0x31,0x38,0x39, + 0x32,0x36,0x36,0x33,0x37,0x38,0x34,0x32,0x35,0x34, + 0x31,0x36,0x35,0x32,0x31,0x30,0x30,0x35,0x32,0x34, + 0x35,0x37,0x34,0x38,0x30,0x38,0x31,0x36,0x39,0x36, + 0x36,0x33,0x34,0x33,0x39,0x31,0x33,0x34,0x36,0x38, + 0x31,0x35,0x34,0x31,0x31,0x30,0x33,0x35,0x39,0x38, + 0x31,0x30,0x34,0x37,0x38,0x35,0x38,0x30,0x31,0x32,0x38, + 0x31,0x30,0x35,0x33,0x36,0x32,0x38,0x35,0x35,0x36,0x38, + 0x39,0x35,0x33,0x39,0x30,0x34,0x31,0x30,0x35, + 0x39,0x37,0x38,0x38,0x34,0x38,0x30,0x33,0x39, + 0x33,0x36,0x31,0x30,0x36,0x37,0x32,0x34,0x34,0x32, + 0x31,0x30,0x35,0x34,0x32,0x34,0x30,0x37,0x30,0x35, + 0x35,0x31,0x37,0x34,0x34,0x34,0x38,0x31,0x39,0x37, + 0x31,0x39,0x36,0x37,0x35,0x36,0x31,0x32,0x35,0x31, + 0x33,0x34,0x34,0x37,0x32,0x35,0x33,0x33,0x34,0x33, + 0x33,0x36,0x38,0x32,0x36,0x34,0x33,0x31,0x38, + 0x33,0x32,0x36,0x31,0x31,0x39,0x38,0x36,0x30,0x38, + 0x39,0x36,0x37,0x38,0x37,0x38,0x31,0x30,0x39,0x34, + 0x34,0x39,0x35,0x38,0x38,0x32,0x33,0x38,0x32,0x33, + 0x38,0x32,0x34,0x36,0x33,0x37,0x38,0x33,0x37, + 0x31,0x31,0x30,0x32,0x30,0x38,0x33,0x33,0x37,0x37,0x36, + 0x31,0x33,0x33,0x38,0x37,0x31,0x36,0x34,0x38, + 0x33,0x32,0x32,0x31,0x34,0x34,0x31,0x36,0x32, + 0x31,0x30,0x36,0x38,0x36,0x36,0x35,0x35,0x35,0x34,0x36, + 0x36,0x32,0x31,0x35,0x35,0x32,0x34,0x36, + 0x37,0x30,0x33,0x30,0x38,0x31,0x38,0x37,0x37,0x34, + 0x35,0x39,0x32,0x34,0x35,0x32,0x33,0x37,0x34,0x34, + 0x31,0x34,0x39,0x35,0x35,0x38,0x36,0x36,0x32,0x31, + 0x34,0x30,0x30,0x35,0x33,0x31,0x34,0x34,0x30,0x36, + 0x33,0x30,0x39,0x36,0x34,0x35,0x37,0x35,0x31,0x32, + 0x32,0x37,0x38,0x34,0x30,0x32,0x35,0x36,0x32,0x30, + 0x32,0x36,0x31,0x38,0x37,0x38,0x37,0x34,0x31,0x38, + 0x31,0x36,0x34,0x32,0x36,0x32,0x35,0x32,0x36,0x32, + 0x36,0x38,0x32,0x34,0x31,0x38,0x39,0x34,0x33,0x36, + 0x34,0x38,0x34,0x32,0x34,0x35,0x34,0x32,0x35, + 0x4d,0x73,0x67, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; + +static const unsigned char wycheproof_ecdsa_public_keys[] = { 0x04,0xb8,0x38,0xff,0x44,0xe5,0xbc,0x17,0x7b,0xf2,0x11,0x89,0xd0,0x76,0x60,0x82,0xfc,0x9d,0x84,0x32,0x26,0x88,0x7f,0xc9,0x76,0x03,0x71,0x10,0x0b,0x7e,0xe2,0x0a,0x6f,0xf0,0xc9,0xd7,0x5b,0xfb,0xa7,0xb3,0x1a,0x6b,0xca,0x19,0x74,0x49,0x6e,0xeb,0x56,0xde,0x35,0x70,0x71,0x95,0x5d,0x83,0xc4,0xb1,0xba,0xda,0xa0,0xb2,0x18,0x32,0xe9, + 0x04,0x07,0x31,0x0f,0x90,0xa9,0xea,0xe1,0x49,0xa0,0x84,0x02,0xf5,0x41,0x94,0xa0,0xf7,0xb4,0xac,0x42,0x7b,0xf8,0xd9,0xbd,0x6c,0x76,0x81,0x07,0x1d,0xc4,0x7d,0xc3,0x62,0x26,0xa6,0xd3,0x7a,0xc4,0x6d,0x61,0xfd,0x60,0x0c,0x0b,0xf1,0xbf,0xf8,0x76,0x89,0xed,0x11,0x7d,0xda,0x6b,0x0e,0x59,0x31,0x8a,0xe0,0x10,0xa1,0x97,0xa2,0x6c,0xa0, + 0x04,0xbc,0x97,0xe7,0x58,0x5e,0xec,0xad,0x48,0xe1,0x66,0x83,0xbc,0x40,0x91,0x70,0x8e,0x1a,0x93,0x0c,0x68,0x3f,0xc4,0x70,0x01,0xd4,0xb3,0x83,0x59,0x4f,0x2c,0x4e,0x22,0x70,0x59,0x89,0xcf,0x69,0xda,0xea,0xdd,0x4e,0x4e,0x4b,0x81,0x51,0xed,0x88,0x8d,0xfe,0xc2,0x0f,0xb0,0x17,0x28,0xd8,0x9d,0x56,0xb3,0xf3,0x8f,0x2a,0xe9,0xc8,0xc5, + 0x04,0x44,0xad,0x33,0x9a,0xfb,0xc2,0x1e,0x9a,0xbf,0x7b,0x60,0x2a,0x5c,0xa5,0x35,0xea,0x37,0x81,0x35,0xb6,0xd1,0x0d,0x81,0x31,0x0b,0xdd,0x82,0x93,0xd1,0xdf,0x32,0x52,0xb6,0x3f,0xf7,0xd0,0x77,0x47,0x70,0xf8,0xfe,0x1d,0x17,0x22,0xfa,0x83,0xac,0xd0,0x2f,0x43,0x4e,0x4f,0xc1,0x10,0xa0,0xcc,0x8f,0x6d,0xdd,0xd3,0x7d,0x56,0xc4,0x63, + 0x04,0x12,0x60,0xc2,0x12,0x2c,0x9e,0x24,0x4e,0x1a,0xf5,0x15,0x1b,0xed,0xe0,0xc3,0xae,0x23,0xb5,0x4d,0x7c,0x59,0x68,0x81,0xd3,0xee,0xba,0xd2,0x1f,0x37,0xdd,0x87,0x8c,0x5c,0x9a,0x0c,0x1a,0x9a,0xde,0x76,0x73,0x7a,0x88,0x11,0xbd,0x6a,0x7f,0x92,0x87,0xc9,0x78,0xee,0x39,0x6a,0xa8,0x9c,0x11,0xe4,0x72,0x29,0xd2,0xcc,0xb5,0x52,0xf0, + 0x04,0x18,0x77,0x04,0x5b,0xe2,0x5d,0x34,0xa1,0xd0,0x60,0x0f,0x9d,0x5c,0x00,0xd0,0x64,0x5a,0x2a,0x54,0x37,0x9b,0x6c,0xee,0xfa,0xd2,0xe6,0xbf,0x5c,0x2a,0x33,0x52,0xce,0x82,0x1a,0x53,0x2c,0xc1,0x75,0x1e,0xe1,0xd3,0x6d,0x41,0xc3,0xd6,0xab,0x4e,0x9b,0x14,0x3e,0x44,0xec,0x46,0xd7,0x34,0x78,0xea,0x6a,0x79,0xa5,0xc0,0xe5,0x41,0x59, + 0x04,0x45,0x54,0x39,0xfc,0xc3,0xd2,0xde,0xec,0xed,0xde,0xae,0xce,0x60,0xe7,0xbd,0x17,0x30,0x4f,0x36,0xeb,0xb6,0x02,0xad,0xf5,0xa2,0x2e,0x0b,0x8f,0x1d,0xb4,0x6a,0x50,0xae,0xc3,0x8f,0xb2,0xba,0xf2,0x21,0xe9,0xa8,0xd1,0x88,0x7c,0x7b,0xf6,0x22,0x2d,0xd1,0x83,0x46,0x34,0xe7,0x72,0x63,0x31,0x5a,0xf6,0xd2,0x36,0x09,0xd0,0x4f,0x77, + 0x04,0x2e,0x1f,0x46,0x6b,0x02,0x4c,0x0c,0x3a,0xce,0x24,0x37,0xde,0x09,0x12,0x7f,0xed,0x04,0xb7,0x06,0xf9,0x4b,0x19,0xa2,0x1b,0xb1,0xc2,0xac,0xf3,0x5c,0xec,0xe7,0x18,0x04,0x49,0xae,0x35,0x23,0xd7,0x25,0x34,0xe9,0x64,0x97,0x2c,0xfd,0x3b,0x38,0xaf,0x0b,0xdd,0xd9,0x61,0x9e,0x5a,0xf2,0x23,0xe4,0xd1,0xa4,0x0f,0x34,0xcf,0x9f,0x1d, + 0x04,0x8e,0x7a,0xbd,0xbb,0xd1,0x8d,0xe7,0x45,0x23,0x74,0xc1,0x87,0x9a,0x1c,0x3b,0x01,0xd1,0x32,0x61,0xe7,0xd4,0x57,0x1c,0x3b,0x47,0xa1,0xc7,0x6c,0x55,0xa2,0x33,0x73,0x26,0xed,0x89,0x7c,0xd5,0x17,0xa4,0xf5,0x34,0x9d,0xb8,0x09,0x78,0x0f,0x6d,0x2f,0x2b,0x9f,0x62,0x99,0xd8,0xb5,0xa8,0x90,0x77,0xf1,0x11,0x9a,0x71,0x8f,0xd7,0xb3, + 0x04,0x7b,0x33,0x3d,0x43,0x40,0xd3,0xd7,0x18,0xdd,0x3e,0x6a,0xff,0x7d,0xe7,0xbb,0xf8,0xb7,0x2b,0xfd,0x61,0x6c,0x84,0x20,0x05,0x60,0x52,0x84,0x23,0x76,0xb9,0xaf,0x19,0x42,0x11,0x7c,0x5a,0xfe,0xac,0x75,0x5d,0x6f,0x37,0x6f,0xc6,0x32,0x9a,0x7d,0x76,0x05,0x1b,0x87,0x12,0x3a,0x4a,0x5d,0x0b,0xc4,0xa5,0x39,0x38,0x0f,0x03,0xde,0x7b, + 0x04,0xd3,0x0c,0xa4,0xa0,0xdd,0xb6,0x61,0x6c,0x85,0x1d,0x30,0xce,0xd6,0x82,0xc4,0x0f,0x83,0xc6,0x27,0x58,0xa1,0xf2,0x75,0x99,0x88,0xd6,0x76,0x3a,0x88,0xf1,0xc0,0xe5,0x03,0xa8,0x0d,0x54,0x15,0x65,0x0d,0x41,0x23,0x97,0x84,0xe8,0xe2,0xfb,0x12,0x35,0xe9,0xfe,0x99,0x1d,0x11,0x2e,0xbb,0x81,0x18,0x6c,0xbf,0x0d,0xa2,0xde,0x3a,0xff, + 0x04,0x48,0x96,0x9b,0x39,0x99,0x12,0x97,0xb3,0x32,0xa6,0x52,0xd3,0xee,0x6e,0x01,0xe9,0x09,0xb3,0x99,0x04,0xe7,0x1f,0xa2,0x35,0x4a,0x78,0x30,0xc7,0x75,0x0b,0xaf,0x24,0xb4,0x01,0x2d,0x1b,0x83,0x0d,0x19,0x9c,0xcb,0x1f,0xc9,0x72,0xb3,0x2b,0xfd,0xed,0x55,0xf0,0x9c,0xd6,0x2d,0x25,0x7e,0x5e,0x84,0x4e,0x27,0xe5,0x7a,0x15,0x94,0xec, + 0x04,0x02,0xef,0x4d,0x6d,0x6c,0xfd,0x5a,0x94,0xf1,0xd7,0x78,0x42,0x26,0xe3,0xe2,0xa6,0xc0,0xa4,0x36,0xc5,0x58,0x39,0x61,0x9f,0x38,0xfb,0x44,0x72,0xb5,0xf9,0xee,0x77,0x7e,0xb4,0xac,0xd4,0xee,0xbd,0xa5,0xcd,0x72,0x87,0x5f,0xfd,0x2a,0x2f,0x26,0x22,0x9c,0x2d,0xc6,0xb4,0x65,0x00,0x91,0x9a,0x43,0x2c,0x86,0x73,0x9f,0x3a,0xe8,0x66, + 0x04,0x46,0x4f,0x4f,0xf7,0x15,0x72,0x9c,0xae,0x50,0x72,0xca,0x3b,0xd8,0x01,0xd3,0x19,0x5b,0x67,0xae,0xc6,0x5e,0x9b,0x01,0xaa,0xd2,0x0a,0x29,0x43,0xdc,0xbc,0xb5,0x84,0xb1,0xaf,0xd2,0x9d,0x31,0xa3,0x9a,0x11,0xd5,0x70,0xaa,0x15,0x97,0x43,0x9b,0x3b,0x2d,0x19,0x71,0xbf,0x2f,0x1a,0xbf,0x15,0x43,0x2d,0x02,0x07,0xb1,0x0d,0x1d,0x08, + 0x04,0x15,0x7f,0x8f,0xdd,0xf3,0x73,0xeb,0x5f,0x49,0xcf,0xcf,0x10,0xd8,0xb8,0x53,0xcf,0x91,0xcb,0xcd,0x7d,0x66,0x5c,0x35,0x22,0xba,0x7d,0xd7,0x38,0xdd,0xb7,0x9a,0x4c,0xde,0xad,0xf1,0xa5,0xc4,0x48,0xea,0x3c,0x9f,0x41,0x91,0xa8,0x99,0x9a,0xbf,0xcc,0x75,0x7a,0xc6,0xd6,0x45,0x67,0xef,0x07,0x2c,0x47,0xfe,0xc6,0x13,0x44,0x3b,0x8f, + 0x04,0x09,0x34,0xa5,0x37,0x46,0x6c,0x07,0x43,0x0e,0x2c,0x48,0xfe,0xb9,0x90,0xbb,0x19,0xfb,0x78,0xce,0xcc,0x9c,0xee,0x42,0x4e,0xa4,0xd1,0x30,0x29,0x1a,0xa2,0x37,0xf0,0xd4,0xf9,0x2d,0x23,0xb4,0x62,0x80,0x4b,0x5b,0x68,0xc5,0x25,0x58,0xc0,0x1c,0x99,0x96,0xdb,0xf7,0x27,0xfc,0xca,0xbb,0xee,0xdb,0x96,0x21,0xa4,0x00,0x53,0x5a,0xfa, + 0x04,0xd6,0xef,0x20,0xbe,0x66,0xc8,0x93,0xf7,0x41,0xa9,0xbf,0x90,0xd9,0xb7,0x46,0x75,0xd1,0xc2,0xa3,0x12,0x96,0x39,0x7a,0xcb,0x3e,0xf1,0x74,0xfd,0x0b,0x30,0x0c,0x65,0x4a,0x0c,0x95,0x47,0x8c,0xa0,0x03,0x99,0x16,0x2d,0x7f,0x0f,0x2d,0xc8,0x9e,0xfd,0xc2,0xb2,0x8a,0x30,0xfb,0xab,0xe2,0x85,0x85,0x72,0x95,0xa4,0xb0,0xc4,0xe2,0x65, + 0x04,0xb7,0x29,0x1d,0x14,0x04,0xe0,0xc0,0xc0,0x7d,0xab,0x93,0x72,0x18,0x9f,0x4b,0xd5,0x8d,0x2c,0xea,0xa8,0xd1,0x5e,0xde,0x54,0x4d,0x95,0x14,0x54,0x5b,0xa9,0xee,0x06,0x29,0xc9,0xa6,0x3d,0x5e,0x30,0x87,0x69,0xcc,0x30,0xec,0x27,0x6a,0x41,0x0e,0x64,0x64,0xa2,0x7e,0xea,0xfd,0x9e,0x59,0x9d,0xb1,0x0f,0x05,0x3a,0x4f,0xe4,0xa8,0x29, + 0x04,0x6e,0x28,0x30,0x33,0x05,0xd6,0x42,0xcc,0xb9,0x23,0xb7,0x22,0xea,0x86,0xb2,0xa0,0xbc,0x8e,0x37,0x35,0xec,0xb2,0x6e,0x84,0x9b,0x19,0xc9,0xf7,0x6b,0x2f,0xdb,0xb8,0x18,0x6e,0x80,0xd6,0x4d,0x8c,0xab,0x16,0x4f,0x52,0x38,0xf5,0x31,0x84,0x61,0xbf,0x89,0xd4,0xd9,0x6e,0xe6,0x54,0x4c,0x81,0x6c,0x75,0x66,0x94,0x77,0x74,0xe0,0xf6, + 0x04,0x37,0x5b,0xda,0x93,0xf6,0xaf,0x92,0xfb,0x5f,0x8f,0x4b,0x1b,0x5f,0x05,0x34,0xe3,0xba,0xfa,0xb3,0x4c,0xb7,0xad,0x9f,0xb9,0xd0,0xb7,0x22,0xe4,0xa5,0xc3,0x02,0xa9,0xa0,0x0b,0x9f,0x38,0x7a,0x5a,0x39,0x60,0x97,0xaa,0x21,0x62,0xfc,0x5b,0xbc,0xf4,0xa5,0x26,0x33,0x72,0xf6,0x81,0xc9,0x4d,0xa5,0x1e,0x97,0x99,0x12,0x09,0x90,0xfd, + 0x04,0xd7,0x5b,0x68,0x21,0x6b,0xab,0xe0,0x3a,0xe2,0x57,0xe9,0x4b,0x4e,0x3b,0xf1,0xc5,0x2f,0x44,0xe3,0xdf,0x26,0x6d,0x15,0x24,0xff,0x8c,0x5e,0xa6,0x9d,0xa7,0x31,0x97,0xda,0x4b,0xff,0x9e,0xd1,0xc5,0x3f,0x44,0x91,0x7a,0x67,0xd7,0xb9,0x78,0x59,0x8e,0x89,0xdf,0x35,0x9e,0x3d,0x59,0x13,0xea,0xea,0x24,0xf3,0xae,0x25,0x9a,0xbc,0x44, + 0x04,0x78,0xbc,0xda,0x14,0x0a,0xed,0x23,0xd4,0x30,0xcb,0x23,0xc3,0xdc,0x0d,0x01,0xf4,0x23,0xdb,0x13,0x4e,0xe9,0x4a,0x3a,0x8c,0xb4,0x83,0xf2,0xde,0xac,0x2a,0xc6,0x53,0x11,0x81,0x14,0xf6,0xf3,0x30,0x45,0xd4,0xe9,0xed,0x91,0x07,0x08,0x50,0x07,0xbf,0xbd,0xdf,0x8f,0x58,0xfe,0x7a,0x1a,0x24,0x45,0xd6,0x6a,0x99,0x00,0x45,0x47,0x6e, + 0x04,0xbb,0x79,0xf6,0x18,0x57,0xf7,0x43,0xbf,0xa1,0xb6,0xe7,0x11,0x1c,0xe4,0x09,0x43,0x77,0x25,0x69,0x69,0xe4,0xe1,0x51,0x59,0x12,0x3d,0x95,0x48,0xac,0xc3,0xbe,0x6c,0x1f,0x9d,0x9f,0x88,0x60,0xdc,0xff,0xd3,0xeb,0x36,0xdd,0x6c,0x31,0xff,0x2e,0x72,0x26,0xc2,0x00,0x9c,0x4c,0x94,0xd8,0xd7,0xd2,0xb5,0x68,0x6b,0xf7,0xab,0xd6,0x77, + 0x04,0x93,0x59,0x18,0x27,0xd9,0xe6,0x71,0x3b,0x4e,0x9f,0xae,0xa6,0x2c,0x72,0xb2,0x8d,0xfe,0xfa,0x68,0xe0,0xc0,0x51,0x60,0xb5,0xd6,0xaa,0xe8,0x8f,0xd2,0xe3,0x6c,0x36,0x07,0x3f,0x55,0x45,0xad,0x5a,0xf4,0x10,0xaf,0x26,0xaf,0xff,0x68,0x65,0x4c,0xf7,0x2d,0x45,0xe4,0x93,0x48,0x93,0x11,0x20,0x32,0x47,0x34,0x7a,0x89,0x0f,0x45,0x18, + 0x04,0x31,0xed,0x30,0x81,0xae,0xfe,0x00,0x1e,0xb6,0x40,0x20,0x69,0xee,0x2c,0xcc,0x18,0x62,0x93,0x7b,0x85,0x99,0x51,0x44,0xdb,0xa9,0x50,0x39,0x43,0x58,0x7b,0xf0,0xda,0xda,0x01,0xb8,0xcc,0x4d,0xf3,0x4f,0x5a,0xb3,0xb1,0xa3,0x59,0x61,0x52,0x08,0x94,0x6e,0x5e,0xe3,0x5f,0x98,0xee,0x77,0x5b,0x8c,0xce,0xcd,0x86,0xcc,0xc1,0x65,0x0f, + 0x04,0x7d,0xff,0x66,0xfa,0x98,0x50,0x9f,0xf3,0xe2,0xe5,0x10,0x45,0xf4,0x39,0x05,0x23,0xdc,0xcd,0xa4,0x3a,0x3b,0xc2,0x88,0x5e,0x58,0xc2,0x48,0x09,0x09,0x90,0xee,0xa8,0x54,0xc7,0x6c,0x2b,0x9a,0xde,0xb6,0xbb,0x57,0x18,0x23,0xe0,0x7f,0xd7,0xc6,0x5c,0x86,0x39,0xcf,0x9d,0x90,0x52,0x60,0x06,0x4c,0x8e,0x76,0x75,0xce,0x6d,0x98,0xb4, + 0x04,0x42,0x80,0x50,0x9a,0xab,0x64,0xed,0xfc,0x0b,0x4a,0x29,0x67,0xe4,0xcb,0xce,0x84,0x9c,0xb5,0x44,0xe4,0xa7,0x73,0x13,0xc8,0xe6,0xec,0xe5,0x79,0xfb,0xd7,0x42,0x0a,0x2e,0x89,0xfe,0x5c,0xc1,0x92,0x7d,0x55,0x4e,0x6a,0x3b,0xb1,0x40,0x33,0xea,0x7c,0x92,0x2c,0xd7,0x5c,0xba,0x2c,0x74,0x15,0xfd,0xab,0x52,0xf2,0x0b,0x18,0x60,0xf1, + 0x04,0x4f,0x8d,0xf1,0x45,0x19,0x4e,0x3c,0x4f,0xc3,0xee,0xa2,0x6d,0x43,0xce,0x75,0xb4,0x02,0xd6,0xb1,0x74,0x72,0xdd,0xcb,0xb2,0x54,0xb8,0xa7,0x9b,0x0b,0xf3,0xd9,0xcb,0x2a,0xa2,0x0d,0x82,0x84,0x4c,0xb2,0x66,0x34,0x4e,0x71,0xca,0x78,0xf2,0xad,0x27,0xa7,0x5a,0x09,0xe5,0xbc,0x0f,0xa5,0x7e,0x4e,0xfd,0x9d,0x46,0x5a,0x08,0x88,0xdb, + 0x04,0x95,0x98,0xa5,0x7d,0xd6,0x7e,0xc3,0xe1,0x6b,0x58,0x7a,0x33,0x8a,0xa3,0xa1,0x0a,0x3a,0x39,0x13,0xb4,0x1a,0x3a,0xf3,0x2e,0x3e,0xd3,0xff,0x01,0x35,0x8c,0x6b,0x14,0x12,0x28,0x19,0xed,0xf8,0x07,0x4b,0xbc,0x52,0x1f,0x7d,0x4c,0xdc,0xe8,0x2f,0xef,0x7a,0x51,0x67,0x06,0xaf,0xfb,0xa1,0xd9,0x3d,0x9d,0xea,0x9c,0xca,0xe1,0xa2,0x07, + 0x04,0x91,0x71,0xfe,0xc3,0xca,0x20,0x80,0x6b,0xc0,0x84,0xf1,0x2f,0x07,0x60,0x91,0x1b,0x60,0x99,0x0b,0xd8,0x0e,0x5b,0x2a,0x71,0xca,0x03,0xa0,0x48,0xb2,0x0f,0x83,0x7e,0x63,0x4f,0xd1,0x78,0x63,0x76,0x1b,0x29,0x58,0xd2,0xbe,0x4e,0x14,0x9f,0x8d,0x3d,0x7a,0xbb,0xdc,0x18,0xbe,0x03,0xf4,0x51,0xab,0x6c,0x17,0xfa,0x0a,0x1f,0x83,0x30, + 0x04,0x77,0x7c,0x89,0x30,0xb6,0xe1,0xd2,0x71,0x10,0x0f,0xe6,0x8c,0xe9,0x3f,0x16,0x3f,0xa3,0x76,0x12,0xc5,0xff,0xf6,0x7f,0x4a,0x62,0xfc,0x3b,0xaf,0xaf,0x3d,0x17,0xa9,0xed,0x73,0xd8,0x6f,0x60,0xa5,0x1b,0x5e,0xd9,0x13,0x53,0xa3,0xb0,0x54,0xed,0xc0,0xaa,0x92,0xc9,0xeb,0xcb,0xd0,0xb7,0x5d,0x18,0x8f,0xdc,0x88,0x27,0x91,0xd6,0x8d, + 0x04,0xea,0xbc,0x24,0x8f,0x62,0x6e,0x0a,0x63,0xe1,0xeb,0x81,0xc4,0x3d,0x46,0x1a,0x39,0xa1,0xdb,0xa8,0x81,0xeb,0x6e,0xe2,0x15,0x2b,0x07,0xc3,0x2d,0x71,0xbc,0xf4,0x70,0x06,0x03,0xca,0xa8,0xb9,0xd3,0x3d,0xb1,0x3a,0xf4,0x4c,0x6e,0xfb,0xec,0x8a,0x19,0x8e,0xd6,0x12,0x4a,0xc9,0xeb,0x17,0xea,0xaf,0xd2,0x82,0x4a,0x54,0x5e,0xc0,0x00, + 0x04,0x9f,0x7a,0x13,0xad,0xa1,0x58,0xa5,0x5f,0x9d,0xdf,0x1a,0x45,0xf0,0x44,0xf0,0x73,0xd9,0xb8,0x00,0x30,0xef,0xdc,0xfc,0x9f,0x9f,0x58,0x41,0x8f,0xbc,0xea,0xf0,0x01,0xf8,0xad,0xa0,0x17,0x50,0x90,0xf8,0x0d,0x47,0x22,0x7d,0x67,0x13,0xb6,0x74,0x0f,0x9a,0x00,0x91,0xd8,0x8a,0x83,0x7d,0x0a,0x1c,0xd7,0x7b,0x58,0xa8,0xf2,0x8d,0x73, + 0x04,0x11,0xc4,0xf3,0xe4,0x61,0xcd,0x01,0x9b,0x5c,0x06,0xea,0x0c,0xea,0x4c,0x40,0x90,0xc3,0xcc,0x3e,0x3c,0x5d,0x9f,0x3c,0x6d,0x65,0xb4,0x36,0x82,0x6d,0xa9,0xb4,0xdb,0xbb,0xeb,0x7a,0x77,0xe4,0xcb,0xfd,0xa2,0x07,0x09,0x7c,0x43,0x42,0x37,0x05,0xf7,0x2c,0x80,0x47,0x6d,0xa3,0xda,0xc4,0x0a,0x48,0x3b,0x0a,0xb0,0xf2,0xea,0xd1,0xcb, + 0x04,0xe2,0xe1,0x86,0x82,0xd5,0x31,0x23,0xaa,0x01,0xa6,0xc5,0xd0,0x0b,0x0c,0x62,0x3d,0x67,0x1b,0x46,0x2e,0xa8,0x0b,0xdd,0xd6,0x52,0x27,0xfd,0x51,0x05,0x98,0x8a,0xa4,0x16,0x19,0x07,0xb3,0xfd,0x25,0x04,0x4a,0x94,0x9e,0xa4,0x1c,0x8e,0x2e,0xa8,0x45,0x9d,0xc6,0xf1,0x65,0x48,0x56,0xb8,0xb6,0x1b,0x31,0x54,0x3b,0xb1,0xb4,0x5b,0xdb, + 0x04,0x90,0xf8,0xd4,0xca,0x73,0xde,0x08,0xa6,0x56,0x4a,0xaf,0x00,0x52,0x47,0xb6,0xf0,0xff,0xe9,0x78,0x50,0x4d,0xce,0x52,0x60,0x5f,0x46,0xb7,0xc3,0xe5,0x61,0x97,0xda,0xfa,0xdb,0xe5,0x28,0xeb,0x70,0xd9,0xee,0x7e,0xa0,0xe7,0x07,0x02,0xdb,0x54,0xf7,0x21,0x51,0x4c,0x7b,0x86,0x04,0xac,0x2c,0xb2,0x14,0xf1,0xde,0xcb,0x7e,0x38,0x3d, + 0x04,0x82,0x4c,0x19,0x5c,0x73,0xcf,0xfd,0xf0,0x38,0xd1,0x01,0xbc,0xe1,0x68,0x7b,0x5c,0x3b,0x61,0x46,0xf3,0x95,0xc8,0x85,0x97,0x6f,0x77,0x53,0xb2,0x37,0x6b,0x94,0x8e,0x3c,0xde,0xfa,0x6f,0xc3,0x47,0xd1,0x3e,0x4d,0xcb,0xc6,0x3a,0x0b,0x03,0xa1,0x65,0x18,0x0c,0xd2,0xbe,0x14,0x31,0xa0,0xcf,0x74,0xce,0x1e,0xa2,0x50,0x82,0xd2,0xbc, + 0x04,0x27,0x88,0xa5,0x2f,0x07,0x8e,0xb3,0xf2,0x02,0xc4,0xfa,0x73,0xe0,0xd3,0x38,0x6f,0xaf,0x3d,0xf6,0xbe,0x85,0x60,0x03,0x63,0x6f,0x59,0x99,0x22,0xd4,0xf5,0x26,0x8f,0x30,0xb4,0xf2,0x07,0xc9,0x19,0xbb,0xdf,0x5e,0x67,0xa8,0xbe,0x42,0x65,0xa8,0x17,0x47,0x54,0xb3,0xab,0xa8,0xf1,0x6e,0x57,0x5b,0x77,0xff,0x4d,0x5a,0x7e,0xb6,0x4f, + 0x04,0xd5,0x33,0xb7,0x89,0xa4,0xaf,0x89,0x0f,0xa7,0xa8,0x2a,0x1f,0xae,0x58,0xc4,0x04,0xf9,0xa6,0x2a,0x50,0xb4,0x9a,0xda,0xfa,0xb3,0x49,0xc5,0x13,0xb4,0x15,0x08,0x74,0x01,0xb4,0x17,0x1b,0x80,0x3e,0x76,0xb3,0x4a,0x98,0x61,0xe1,0x0f,0x7b,0xc2,0x89,0xa0,0x66,0xfd,0x01,0xbd,0x29,0xf8,0x4c,0x98,0x7a,0x10,0xa5,0xfb,0x18,0xc2,0xd4, + 0x04,0x3a,0x31,0x50,0x79,0x8c,0x8a,0xf6,0x9d,0x1e,0x6e,0x98,0x1f,0x3a,0x45,0x40,0x2b,0xa1,0xd7,0x32,0xf4,0xbe,0x83,0x30,0xc5,0x16,0x4f,0x49,0xe1,0x0e,0xc5,0x55,0xb4,0x22,0x1b,0xd8,0x42,0xbc,0x5e,0x4d,0x97,0xef,0xf3,0x71,0x65,0xf6,0x0e,0x39,0x98,0xa4,0x24,0xd7,0x2a,0x45,0x0c,0xf9,0x5e,0xa4,0x77,0xc7,0x82,0x87,0xd0,0x34,0x3a, + 0x04,0x3b,0x37,0xdf,0x5f,0xb3,0x47,0xc6,0x9a,0x0f,0x17,0xd8,0x5c,0x0c,0x7c,0xa8,0x37,0x36,0x88,0x3a,0x82,0x5e,0x13,0x14,0x3d,0x0f,0xcf,0xc8,0x10,0x1e,0x85,0x1e,0x80,0x0d,0xe3,0xc0,0x90,0xb6,0xca,0x21,0xba,0x54,0x35,0x17,0x33,0x0c,0x04,0xb1,0x2f,0x94,0x8c,0x6b,0xad,0xf1,0x4a,0x63,0xab,0xff,0xdf,0x4e,0xf8,0xc7,0x53,0x70,0x26, + 0x04,0xfe,0xb5,0x16,0x3b,0x0e,0xce,0x30,0xff,0x3e,0x03,0xc7,0xd5,0x5c,0x43,0x80,0xfa,0x2f,0xa8,0x1e,0xe2,0xc0,0x35,0x49,0x42,0xff,0x6f,0x08,0xc9,0x9d,0x0c,0xd8,0x2c,0xe8,0x7d,0xe0,0x5e,0xe1,0xbd,0xa0,0x89,0xd3,0xe4,0xe2,0x48,0xfa,0x0f,0x72,0x11,0x02,0xac,0xff,0xfd,0xf5,0x0e,0x65,0x4b,0xe2,0x81,0x43,0x39,0x99,0xdf,0x89,0x7e, + 0x04,0x23,0x8c,0xed,0x00,0x1c,0xf2,0x2b,0x88,0x53,0xe0,0x2e,0xdc,0x89,0xcb,0xec,0xa5,0x05,0x0b,0xa7,0xe0,0x42,0xa7,0xa7,0x7f,0x93,0x82,0xcd,0x41,0x49,0x22,0x89,0x76,0x40,0x68,0x3d,0x30,0x94,0x64,0x38,0x40,0xf2,0x95,0x89,0x0a,0xa4,0xc1,0x8a,0xa3,0x9b,0x41,0xd7,0x7d,0xd0,0xfb,0x3b,0xb2,0x70,0x0e,0x4f,0x9e,0xc2,0x84,0xff,0xc2, + 0x04,0x96,0x1c,0xf6,0x48,0x17,0xc0,0x6c,0x0e,0x51,0xb3,0xc2,0x73,0x6c,0x92,0x2f,0xde,0x18,0xbd,0x8c,0x49,0x06,0xfc,0xd7,0xf5,0xef,0x66,0xc4,0x67,0x85,0x08,0xf3,0x5e,0xd2,0xc5,0xd1,0x81,0x68,0xcf,0xbe,0x70,0xf2,0xf1,0x23,0xbd,0x74,0x19,0x23,0x2b,0xb9,0x2d,0xd6,0x91,0x13,0xe2,0x94,0x10,0x61,0x88,0x94,0x81,0xc5,0xa0,0x27,0xbf, + 0x04,0x13,0x68,0x1e,0xae,0x16,0x8c,0xd4,0xea,0x7c,0xf2,0xe2,0xa4,0x5d,0x05,0x27,0x42,0xd1,0x0a,0x9f,0x64,0xe7,0x96,0x86,0x7d,0xbd,0xcb,0x82,0x9f,0xe0,0xb1,0x02,0x88,0x16,0x52,0x87,0x60,0xd1,0x77,0x37,0x6c,0x09,0xdf,0x79,0xde,0x39,0x55,0x7c,0x32,0x9c,0xc1,0x75,0x35,0x17,0xac,0xff,0xe8,0xfa,0x2e,0xc2,0x98,0x02,0x6b,0x83,0x84, + 0x04,0x5a,0xa7,0xab,0xfd,0xb6,0xb4,0x08,0x6d,0x54,0x33,0x25,0xe5,0xd7,0x9c,0x6e,0x95,0xce,0x42,0xf8,0x66,0xd2,0xbb,0x84,0x90,0x96,0x33,0xa0,0x4b,0xb1,0xaa,0x31,0xc2,0x91,0xc8,0x00,0x88,0x79,0x49,0x05,0xe1,0xda,0x33,0x33,0x6d,0x87,0x4e,0x2f,0x91,0xcc,0xf4,0x5c,0xc5,0x91,0x85,0xbe,0xde,0x5d,0xd6,0xf3,0xf7,0xac,0xaa,0xe1,0x8b, + 0x04,0x00,0x27,0x77,0x91,0xb3,0x05,0xa4,0x5b,0x2b,0x39,0x59,0x0b,0x2f,0x05,0xd3,0x39,0x2a,0x6c,0x81,0x82,0xce,0xf4,0xeb,0x54,0x01,0x20,0xe0,0xf5,0xc2,0x06,0xc3,0xe4,0x64,0x10,0x82,0x33,0xfb,0x0b,0x8c,0x3a,0xc8,0x92,0xd7,0x9e,0xf8,0xe0,0xfb,0xf9,0x2e,0xd1,0x33,0xad,0xdb,0x45,0x54,0x27,0x01,0x32,0x58,0x4d,0xc5,0x2e,0xef,0x41, + 0x04,0x6e,0xfa,0x09,0x2b,0x68,0xde,0x94,0x60,0xf0,0xbc,0xc9,0x19,0x00,0x5a,0x5f,0x6e,0x80,0xe1,0x9d,0xe9,0x89,0x68,0xbe,0x3c,0xd2,0xc7,0x70,0xa9,0x94,0x9b,0xfb,0x1a,0xc7,0x5e,0x6e,0x50,0x87,0xd6,0x55,0x0d,0x5f,0x9b,0xeb,0x1e,0x79,0xe5,0x02,0x93,0x07,0xbc,0x25,0x52,0x35,0xe2,0xd5,0xdc,0x99,0x24,0x1a,0xc3,0xab,0x88,0x6c,0x49, + 0x04,0x72,0xd4,0xa1,0x9c,0x4f,0x9d,0x2c,0xf5,0x84,0x8e,0xa4,0x04,0x45,0xb7,0x0d,0x46,0x96,0xb5,0xf0,0x2d,0x63,0x2c,0x0c,0x65,0x4c,0xc7,0xd7,0xee,0xb0,0xc6,0xd0,0x58,0xe8,0xc4,0xcd,0x99,0x43,0xe4,0x59,0x17,0x4c,0x7a,0xc0,0x1f,0xa7,0x42,0x19,0x8e,0x47,0xe6,0xc1,0x9a,0x6b,0xdb,0x0c,0x4f,0x6c,0x23,0x78,0x31,0xc1,0xb3,0xf9,0x42, + 0x04,0x2a,0x8e,0xa2,0xf5,0x0d,0xcc,0xed,0x0c,0x21,0x75,0x75,0xbd,0xfa,0x7c,0xd4,0x7d,0x1c,0x6f,0x10,0x00,0x41,0xec,0x0e,0x35,0x51,0x27,0x94,0xc1,0xbe,0x7e,0x74,0x02,0x58,0xf8,0xc1,0x71,0x22,0xed,0x30,0x3f,0xda,0x71,0x43,0xeb,0x58,0xbe,0xde,0x70,0x29,0x5b,0x65,0x32,0x66,0x01,0x3b,0x0b,0x0e,0xbd,0x3f,0x05,0x31,0x37,0xf6,0xec, + 0x04,0x88,0xde,0x68,0x9c,0xe9,0xaf,0x1e,0x94,0xbe,0x6a,0x20,0x89,0xc8,0xa8,0xb1,0x25,0x3f,0xfd,0xbb,0x6c,0x8e,0x9c,0x86,0x24,0x9b,0xa2,0x20,0x00,0x1a,0x4a,0xd3,0xb8,0x0c,0x49,0x98,0xe5,0x48,0x42,0xf4,0x13,0xb9,0xed,0xb1,0x82,0x5a,0xcb,0xb6,0x33,0x5e,0x81,0xe4,0xd1,0x84,0xb2,0xb0,0x1c,0x8b,0xeb,0xdc,0x85,0xd1,0xf2,0x89,0x46, + 0x04,0xfe,0xa2,0xd3,0x1f,0x70,0xf9,0x0d,0x5f,0xb3,0xe0,0x0e,0x18,0x6a,0xc4,0x2a,0xb3,0xc1,0x61,0x5c,0xee,0x71,0x4e,0x0b,0x4e,0x11,0x31,0xb3,0xd4,0xd8,0x22,0x5b,0xf7,0xb0,0x37,0xa1,0x8d,0xf2,0xac,0x15,0x34,0x3f,0x30,0xf7,0x40,0x67,0xdd,0xf2,0x9e,0x81,0x7d,0x5f,0x77,0xf8,0xdc,0xe0,0x57,0x14,0xda,0x59,0xc0,0x94,0xf0,0xcd,0xa9, + 0x04,0x72,0x58,0x91,0x1e,0x3d,0x42,0x33,0x49,0x16,0x64,0x79,0xdb,0xe0,0xb8,0x34,0x1a,0xf7,0xfb,0xd0,0x3d,0x0a,0x7e,0x10,0xed,0xcc,0xb3,0x6b,0x6c,0xee,0xa5,0xa3,0xdb,0x17,0xac,0x2b,0x89,0x92,0x79,0x11,0x28,0xfa,0x3b,0x96,0xdc,0x2f,0xbd,0x4c,0xa3,0xbf,0xa7,0x82,0xef,0x28,0x32,0xfc,0x66,0x56,0x94,0x3d,0xb1,0x8e,0x73,0x46,0xb0, + 0x04,0x4f,0x28,0x46,0x1d,0xea,0x64,0x47,0x4d,0x6b,0xb3,0x4d,0x14,0x99,0xc9,0x7d,0x37,0xb9,0xe9,0x56,0x33,0xdf,0x1c,0xee,0xea,0xac,0xd4,0x50,0x16,0xc9,0x8b,0x39,0x14,0xc8,0x81,0x88,0x10,0xb8,0xcc,0x06,0xdd,0xb4,0x0e,0x8a,0x12,0x61,0xc5,0x28,0xfa,0xa5,0x89,0x45,0x5d,0x5a,0x6d,0xf9,0x3b,0x77,0xbc,0x5e,0x0e,0x49,0x3c,0x74,0x70, + 0x04,0x74,0xf2,0xa8,0x14,0xfb,0x5d,0x8e,0xca,0x91,0xa6,0x9b,0x5e,0x60,0x71,0x27,0x32,0xb3,0x93,0x7d,0xe3,0x28,0x29,0xbe,0x97,0x4e,0xd7,0xb6,0x8c,0x5c,0x2f,0x5d,0x66,0xef,0xf0,0xf0,0x7c,0x56,0xf9,0x87,0xa6,0x57,0xf4,0x21,0x96,0x20,0x5f,0x58,0x8c,0x0f,0x1d,0x96,0xfd,0x8a,0x63,0xa5,0xf2,0x38,0xb4,0x8f,0x47,0x87,0x88,0xfe,0x3b, + 0x04,0x19,0x5b,0x51,0xa7,0xcc,0x4a,0x21,0xb8,0x27,0x4a,0x70,0xa9,0x0d,0xe7,0x79,0x81,0x4c,0x3c,0x8c,0xa3,0x58,0x32,0x82,0x08,0xc0,0x9a,0x29,0xf3,0x36,0xb8,0x2d,0x6a,0xb2,0x41,0x6b,0x7c,0x92,0xff,0xfd,0xc2,0x9c,0x3b,0x12,0x82,0xdd,0x2a,0x77,0xa4,0xd0,0x4d,0xf7,0xf7,0x45,0x20,0x47,0x39,0x3d,0x84,0x99,0x89,0xc5,0xce,0xe9,0xad, + 0x04,0x62,0x2f,0xc7,0x47,0x32,0x03,0x4b,0xec,0x2d,0xdf,0x3b,0xc1,0x6d,0x34,0xb3,0xd1,0xf7,0xa3,0x27,0xdd,0x2a,0x8c,0x19,0xba,0xb4,0xbb,0x4f,0xe3,0xa2,0x4b,0x58,0xaa,0x73,0x6b,0x2f,0x2f,0xae,0x76,0xf4,0xdf,0xae,0xcc,0x90,0x96,0x33,0x3b,0x01,0x32,0x8d,0x51,0xeb,0x3f,0xda,0x9c,0x92,0x27,0xe9,0x0d,0x0b,0x44,0x99,0x83,0xc4,0xf0, + 0x04,0x1f,0x7f,0x85,0xca,0xf2,0xd7,0x55,0x0e,0x7a,0xf9,0xb6,0x50,0x23,0xeb,0xb4,0xdc,0xe3,0x45,0x03,0x11,0x69,0x23,0x09,0xdb,0x26,0x99,0x69,0xb8,0x34,0xb6,0x11,0xc7,0x08,0x27,0xf4,0x5b,0x78,0x02,0x0e,0xcb,0xba,0xf4,0x84,0xfd,0xd5,0xbf,0xaa,0xe6,0x87,0x0f,0x11,0x84,0xc2,0x15,0x81,0xba,0xf6,0xef,0x82,0xbd,0x7b,0x53,0x0f,0x93, + 0x04,0x49,0xc1,0x97,0xdc,0x80,0xad,0x1d,0xa4,0x7a,0x43,0x42,0xb9,0x38,0x93,0xe8,0xe1,0xfb,0x0b,0xb9,0x4f,0xc3,0x3a,0x83,0xe7,0x83,0xc0,0x0b,0x24,0xc7,0x81,0x37,0x7a,0xef,0xc2,0x0d,0xa9,0x2b,0xac,0x76,0x29,0x51,0xf7,0x24,0x74,0xbe,0xcc,0x73,0x4d,0x4c,0xc2,0x2b,0xa8,0x1b,0x89,0x5e,0x28,0x2f,0xda,0xc4,0xdf,0x7a,0xf0,0xf3,0x7d, + 0x04,0xd8,0xcb,0x68,0x51,0x7b,0x61,0x6a,0x56,0x40,0x0a,0xa3,0x86,0x86,0x35,0xe5,0x4b,0x6f,0x69,0x95,0x98,0xa2,0xf6,0x16,0x77,0x57,0x65,0x49,0x80,0xba,0xf6,0xac,0xbe,0x7e,0xc8,0xcf,0x44,0x9c,0x84,0x9a,0xa0,0x34,0x61,0xa3,0x0e,0xfa,0xda,0x41,0x45,0x3c,0x57,0xc6,0xe6,0xfb,0xc9,0x3b,0xbc,0x6f,0xa4,0x9a,0xda,0x6d,0xc0,0x55,0x5c, + 0x04,0x03,0x07,0x13,0xfb,0x63,0xf2,0xaa,0x6f,0xe2,0xca,0xdf,0x1b,0x20,0xef,0xc2,0x59,0xc7,0x74,0x45,0xda,0xfa,0x87,0xda,0xc3,0x98,0xb8,0x40,0x65,0xca,0x34,0x7d,0xf3,0xb2,0x27,0x81,0x8d,0xe1,0xa3,0x9b,0x58,0x9c,0xb0,0x71,0xd8,0x3e,0x53,0x17,0xcc,0xcd,0xc2,0x33,0x8e,0x51,0xe3,0x12,0xfe,0x31,0xd8,0xdc,0x34,0xa4,0x80,0x17,0x50, + 0x04,0xba,0xbb,0x36,0x77,0xb0,0x95,0x58,0x02,0xd8,0xe9,0x29,0xa4,0x13,0x55,0x64,0x0e,0xaf,0x1e,0xa1,0x35,0x3f,0x8a,0x77,0x13,0x31,0xc4,0x94,0x6e,0x34,0x80,0xaf,0xa7,0x25,0x2f,0x19,0x6c,0x87,0xed,0x3d,0x2a,0x59,0xd3,0xb1,0xb5,0x59,0x13,0x7f,0xed,0x00,0x13,0xfe,0xce,0xfc,0x19,0xfb,0x5a,0x92,0x68,0x2b,0x9b,0xca,0x51,0xb9,0x50, + 0x04,0x1a,0xab,0x20,0x18,0x79,0x34,0x71,0x11,0x1a,0x8a,0x0e,0x9b,0x14,0x3f,0xde,0x02,0xfc,0x95,0x92,0x07,0x96,0xd3,0xa6,0x3d,0xe3,0x29,0xb4,0x24,0x39,0x6f,0xba,0x60,0xbb,0xe4,0x13,0x07,0x05,0x17,0x47,0x92,0x44,0x1b,0x31,0x8d,0x3a,0xa3,0x1d,0xfe,0x85,0x77,0x82,0x1e,0x9b,0x44,0x6e,0xc5,0x73,0xd2,0x72,0xe0,0x36,0xc4,0xeb,0xe9, + 0x04,0x8c,0xb0,0xb9,0x09,0x49,0x9c,0x83,0xea,0x80,0x6c,0xd8,0x85,0xb1,0xdd,0x46,0x7a,0x01,0x19,0xf0,0x6a,0x88,0xa0,0x27,0x6e,0xb0,0xcf,0xda,0x27,0x45,0x35,0xa8,0xff,0x47,0xb5,0x42,0x88,0x33,0xbc,0x3f,0x2c,0x8b,0xf9,0xd9,0x04,0x11,0x58,0xcf,0x33,0x71,0x8a,0x69,0x96,0x1c,0xd0,0x17,0x29,0xbc,0x00,0x11,0xd1,0xe5,0x86,0xab,0x75, + 0x04,0x8f,0x03,0xcf,0x1a,0x42,0x27,0x2b,0xb1,0x53,0x27,0x23,0x09,0x3f,0x72,0xe6,0xfe,0xea,0xc8,0x5e,0x17,0x00,0xe9,0xfb,0xe9,0xa6,0xa2,0xdd,0x64,0x2d,0x74,0xbf,0x5d,0x3b,0x89,0xa7,0x18,0x9d,0xad,0x8c,0xf7,0x5f,0xc2,0x2f,0x6f,0x15,0x8a,0xa2,0x7f,0x9c,0x2c,0xa0,0x0d,0xac,0xa7,0x85,0xbe,0x33,0x58,0xf2,0xbd,0xa3,0x86,0x2c,0xa0, + 0x04,0x44,0xde,0x3b,0x9c,0x7a,0x57,0xa8,0xc9,0xe8,0x20,0x95,0x27,0x53,0x42,0x1e,0x7d,0x98,0x7b,0xb3,0xd7,0x9f,0x71,0xf0,0x13,0x80,0x5c,0x89,0x7e,0x01,0x8f,0x8a,0xce,0xa2,0x46,0x07,0x58,0xc8,0xf9,0x8d,0x3f,0xdc,0xe1,0x21,0xa9,0x43,0x65,0x9e,0x37,0x2c,0x32,0x6f,0xff,0x2e,0x5f,0xc2,0xae,0x7f,0xa3,0xf7,0x9d,0xaa,0xe1,0x3c,0x12, + 0x04,0x6f,0xb8,0xb2,0xb4,0x8e,0x33,0x03,0x12,0x68,0xad,0x6a,0x51,0x74,0x84,0xdc,0x88,0x39,0xea,0x90,0xf6,0x66,0x9e,0xa0,0xc7,0xac,0x32,0x33,0xe2,0xac,0x31,0x39,0x4a,0x0a,0xc8,0xbb,0xe7,0xf7,0x3c,0x2f,0xf4,0xdf,0x99,0x78,0x72,0x7a,0xc1,0xdf,0xc2,0xfd,0x58,0x64,0x7d,0x20,0xf3,0x1f,0x99,0x10,0x53,0x16,0xb6,0x46,0x71,0xf2,0x04, + 0x04,0xbe,0xa7,0x11,0x22,0xa0,0x48,0x69,0x3e,0x90,0x5f,0xf6,0x02,0xb3,0xcf,0x9d,0xd1,0x8a,0xf6,0x9b,0x9f,0xc9,0xd8,0x43,0x1d,0x2b,0x1d,0xd2,0x6b,0x94,0x2c,0x95,0xe6,0xf4,0x3c,0x7b,0x8b,0x95,0xeb,0x62,0x08,0x2c,0x12,0xdb,0x9d,0xbd,0xa7,0xfe,0x38,0xe4,0x5c,0xbe,0x4a,0x48,0x86,0x90,0x7f,0xb8,0x1b,0xdb,0x0c,0x5e,0xa9,0x24,0x6c, + 0x04,0xda,0x91,0x8c,0x73,0x1b,0xa0,0x6a,0x20,0xcb,0x94,0xef,0x33,0xb7,0x78,0xe9,0x81,0xa4,0x04,0xa3,0x05,0xf1,0x94,0x1f,0xe3,0x36,0x66,0xb4,0x5b,0x03,0x35,0x31,0x56,0xe2,0xbb,0x26,0x94,0xf5,0x75,0xb4,0x51,0x83,0xbe,0x78,0xe5,0xc9,0xb5,0x21,0x0b,0xf3,0xbf,0x48,0x8f,0xd4,0xc8,0x29,0x45,0x16,0xd8,0x95,0x72,0xca,0x4f,0x53,0x91, + 0x04,0x30,0x07,0xe9,0x2c,0x39,0x37,0xda,0xde,0x79,0x64,0xdf,0xa3,0x5b,0x0e,0xff,0x03,0x1f,0x7e,0xb0,0x2a,0xed,0x0a,0x03,0x14,0x41,0x11,0x06,0xcd,0xeb,0x70,0xfe,0x3d,0x5a,0x75,0x46,0xfc,0x05,0x52,0x99,0x7b,0x20,0xe3,0xd6,0xf4,0x13,0xe7,0x5e,0x2c,0xb6,0x6e,0x11,0x63,0x22,0x69,0x71,0x14,0xb7,0x9b,0xac,0x73,0x4b,0xfc,0x4d,0xc5, + 0x04,0x60,0xe7,0x34,0xef,0x56,0x24,0xd3,0xcb,0xf0,0xdd,0xd3,0x75,0x01,0x1b,0xd6,0x63,0xd6,0xd6,0xae,0xbc,0x64,0x4e,0xb5,0x99,0xfd,0xf9,0x8d,0xbd,0xcd,0x18,0xce,0x9b,0xd2,0xd9,0x0b,0x3a,0xc3,0x1f,0x13,0x9a,0xf8,0x32,0xcc,0xcf,0x6c,0xcb,0xbb,0x2c,0x6e,0xa1,0x1f,0xa9,0x73,0x70,0xdc,0x99,0x06,0xda,0x47,0x4d,0x7d,0x8a,0x75,0x67, + 0x04,0x85,0xa9,0x00,0xe9,0x78,0x58,0xf6,0x93,0xc0,0xb7,0xdf,0xa2,0x61,0xe3,0x80,0xda,0xd6,0xea,0x04,0x6d,0x1f,0x65,0xdd,0xee,0xed,0xd5,0xf7,0xd8,0xaf,0x0b,0xa3,0x37,0x69,0x74,0x4d,0x15,0xad,0xd4,0xf6,0xc0,0xbc,0x3b,0x0d,0xa2,0xae,0xc9,0x3b,0x34,0xcb,0x8c,0x65,0xf9,0x34,0x0d,0xdf,0x74,0xe7,0xb0,0x00,0x9e,0xee,0xcc,0xce,0x3c, + 0x04,0x38,0x06,0x6f,0x75,0xd8,0x8e,0xfc,0x4c,0x93,0xde,0x36,0xf4,0x9e,0x03,0x7b,0x23,0x4c,0xc1,0x8b,0x1d,0xe5,0x60,0x87,0x50,0xa6,0x2c,0xab,0x03,0x45,0x40,0x10,0x46,0xa3,0xe8,0x4b,0xed,0x8c,0xfc,0xb8,0x19,0xef,0x4d,0x55,0x04,0x44,0xf2,0xce,0x4b,0x65,0x17,0x66,0xb6,0x9e,0x2e,0x29,0x01,0xf8,0x88,0x36,0xff,0x90,0x03,0x4f,0xed, + 0x04,0x98,0xf6,0x81,0x77,0xdc,0x95,0xc1,0xb4,0xcb,0xfa,0x52,0x45,0x48,0x8c,0xa5,0x23,0xa7,0xd5,0x62,0x94,0x70,0xd0,0x35,0xd6,0x21,0xa4,0x43,0xc7,0x2f,0x39,0xaa,0xbf,0xa3,0x3d,0x29,0x54,0x6f,0xa1,0xc6,0x48,0xf2,0xc7,0xd5,0xcc,0xf7,0x0c,0xf1,0xce,0x4a,0xb7,0x9b,0x5d,0xb1,0xac,0x05,0x9d,0xbe,0xcd,0x06,0x8d,0xbd,0xff,0x1b,0x89, + 0x04,0x5c,0x2b,0xbf,0xa2,0x3c,0x9b,0x9a,0xd0,0x7f,0x03,0x8a,0xa8,0x9b,0x49,0x30,0xbf,0x26,0x7d,0x94,0x01,0xe4,0x25,0x5d,0xe9,0xe8,0xda,0x0a,0x50,0x78,0xec,0x82,0x77,0xe3,0xe8,0x82,0xa3,0x1d,0x5e,0x6a,0x37,0x9e,0x07,0x93,0x98,0x3c,0xcd,0xed,0x39,0xb9,0x5c,0x43,0x53,0xab,0x2f,0xf0,0x1e,0xa5,0x36,0x9b,0xa4,0x7b,0x0c,0x31,0x91, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0x35,0x47,0x80,0x82,0x98,0x44,0x8e,0xdb,0x5e,0x70,0x1a,0xde,0x84,0xcd,0x5f,0xb1,0xac,0x95,0x67,0xba,0x5e,0x8f,0xb6,0x8a,0x6b,0x93,0x3e,0xc4,0xb5,0xcc,0x84,0xcc, + 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0xca,0xb8,0x7f,0x7d,0x67,0xbb,0x71,0x24,0xa1,0x8f,0xe5,0x21,0x7b,0x32,0xa0,0x4e,0x53,0x6a,0x98,0x45,0xa1,0x70,0x49,0x75,0x94,0x6c,0xc1,0x3a,0x4a,0x33,0x77,0x63, + 0x04,0x8a,0xa2,0xc6,0x4f,0xa9,0xc6,0x43,0x75,0x63,0xab,0xfb,0xcb,0xd0,0x0b,0x20,0x48,0xd4,0x8c,0x18,0xc1,0x52,0xa2,0xa6,0xf4,0x90,0x36,0xde,0x76,0x47,0xeb,0xe8,0x2e,0x1c,0xe6,0x43,0x87,0x99,0x5c,0x68,0xa0,0x60,0xfa,0x3b,0xc0,0x39,0x9b,0x05,0xcc,0x06,0xee,0xc7,0xd5,0x98,0xf7,0x50,0x41,0xa4,0x91,0x7e,0x69,0x2b,0x7f,0x51,0xff, + 0x04,0x39,0x14,0x27,0xff,0x7e,0xe7,0x80,0x13,0xc1,0x4a,0xec,0x7d,0x96,0xa8,0xa0,0x62,0x20,0x92,0x98,0xa7,0x83,0x83,0x5e,0x94,0xfd,0x65,0x49,0xd5,0x02,0xff,0xf7,0x1f,0xdd,0x66,0x24,0xec,0x34,0x3a,0xd9,0xfc,0xf4,0xd9,0x87,0x21,0x81,0xe5,0x9f,0x84,0x2f,0x9b,0xa4,0xcc,0xca,0xe0,0x9a,0x6c,0x09,0x72,0xfb,0x6a,0xc6,0xb4,0xc6,0xbd, + 0x04,0xe7,0x62,0xb8,0xa2,0x19,0xb4,0xf1,0x80,0x21,0x9c,0xc7,0xa9,0x05,0x92,0x45,0xe4,0x96,0x1b,0xd1,0x91,0xc0,0x38,0x99,0x78,0x9c,0x7a,0x34,0xb8,0x9e,0x8c,0x13,0x8e,0xc1,0x53,0x3e,0xf0,0x41,0x9b,0xb7,0x37,0x6e,0x0b,0xfd,0xe9,0x31,0x9d,0x10,0xa0,0x69,0x68,0x79,0x1d,0x9e,0xa0,0xee,0xd9,0xc1,0xce,0x63,0x45,0xae,0xd9,0x75,0x9e, + 0x04,0x9a,0xed,0xb0,0xd2,0x81,0xdb,0x16,0x4e,0x13,0x00,0x00,0xc5,0x69,0x7f,0xae,0x0f,0x30,0x5e,0xf8,0x48,0xbe,0x6f,0xff,0xb4,0x3a,0xc5,0x93,0xfb,0xb9,0x50,0xe9,0x52,0xfa,0x6f,0x63,0x33,0x59,0xbd,0xcd,0x82,0xb5,0x6b,0x0b,0x9f,0x96,0x5b,0x03,0x77,0x89,0xd4,0x6b,0x9a,0x81,0x41,0xb7,0x91,0xb2,0xae,0xfa,0x71,0x3f,0x96,0xc1,0x75, + 0x04,0x8a,0xd4,0x45,0xdb,0x62,0x81,0x62,0x60,0xe4,0xe6,0x87,0xfd,0x18,0x84,0xe4,0x8b,0x9f,0xc0,0x63,0x6d,0x03,0x15,0x47,0xd6,0x33,0x15,0xe7,0x92,0xe1,0x9b,0xfa,0xee,0x1d,0xe6,0x4f,0x99,0xd5,0xf1,0xcd,0x8b,0x6e,0xc9,0xcb,0x0f,0x78,0x7a,0x65,0x4a,0xe8,0x69,0x93,0xba,0x3d,0xb1,0x00,0x8e,0xf4,0x3c,0xff,0x06,0x84,0xcb,0x22,0xbd, + 0x04,0x1f,0x57,0x99,0xc9,0x5b,0xe8,0x90,0x63,0xb2,0x4f,0x26,0xe4,0x0c,0xb9,0x28,0xc1,0xa8,0x68,0xa7,0x6f,0xb0,0x09,0x46,0x07,0xe8,0x04,0x3d,0xb4,0x09,0xc9,0x1c,0x32,0xe7,0x57,0x24,0xe8,0x13,0xa4,0x19,0x1e,0x3a,0x83,0x90,0x07,0xf0,0x8e,0x2e,0x89,0x73,0x88,0xb0,0x6d,0x4a,0x00,0xde,0x6d,0xe6,0x0e,0x53,0x6d,0x91,0xfa,0xb5,0x66, + 0x04,0xa3,0x33,0x1a,0x4e,0x1b,0x42,0x23,0xec,0x2c,0x02,0x7e,0xdd,0x48,0x2c,0x92,0x8a,0x14,0xed,0x35,0x8d,0x93,0xf1,0xd4,0x21,0x7d,0x39,0xab,0xf6,0x9f,0xcb,0x5c,0xcc,0x28,0xd6,0x84,0xd2,0xaa,0xab,0xcd,0x63,0x83,0x77,0x5c,0xaa,0x62,0x39,0xde,0x26,0xd4,0xc6,0x93,0x7b,0xb6,0x03,0xec,0xb4,0x19,0x60,0x82,0xf4,0xcf,0xfd,0x50,0x9d, + 0x04,0x3f,0x39,0x52,0x19,0x97,0x74,0xc7,0xcf,0x39,0xb3,0x8b,0x66,0xcb,0x10,0x42,0xa6,0x26,0x0d,0x86,0x80,0x80,0x38,0x45,0xe4,0xd4,0x33,0xad,0xba,0x3b,0xb2,0x48,0x18,0x5e,0xa4,0x95,0xb6,0x8c,0xbc,0x7e,0xd4,0x17,0x3e,0xe6,0x3c,0x90,0x42,0xdc,0x50,0x26,0x25,0xc7,0xeb,0x7e,0x21,0xfb,0x02,0xca,0x9a,0x91,0x14,0xe0,0xa3,0xa1,0x8d, + 0x04,0xcd,0xfb,0x8c,0x0f,0x42,0x2e,0x14,0x4e,0x13,0x7c,0x24,0x12,0xc8,0x6c,0x17,0x1f,0x5f,0xe3,0xfa,0x3f,0x5b,0xbb,0x54,0x4e,0x90,0x76,0x28,0x8f,0x3c,0xed,0x78,0x6e,0x05,0x4f,0xd0,0x72,0x1b,0x77,0xc1,0x1c,0x79,0xbe,0xac,0xb3,0xc9,0x42,0x11,0xb0,0xa1,0x9b,0xda,0x08,0x65,0x2e,0xfe,0xaf,0x92,0x51,0x3a,0x3b,0x0a,0x16,0x36,0x98, + 0x04,0x73,0x59,0x8a,0x6a,0x1c,0x68,0x27,0x8f,0xa6,0xbf,0xd0,0xce,0x40,0x64,0xe6,0x82,0x35,0xbc,0x1c,0x0f,0x6b,0x20,0xa9,0x28,0x10,0x8b,0xe3,0x36,0x73,0x0f,0x87,0xe3,0xcb,0xae,0x61,0x25,0x19,0xb5,0x03,0x2e,0xcc,0x85,0xae,0xd8,0x11,0x27,0x1a,0x95,0xfe,0x79,0x39,0xd5,0xd3,0x46,0x01,0x40,0xba,0x31,0x8f,0x4d,0x14,0xab,0xa3,0x1d, + 0x04,0x58,0xde,0xbd,0x9a,0x7e,0xe2,0xc9,0xd5,0x91,0x32,0x47,0x8a,0x54,0x40,0xae,0x4d,0x5d,0x7e,0xd4,0x37,0x30,0x83,0x69,0xf9,0x2e,0xa8,0x6c,0x82,0x18,0x3f,0x10,0xa1,0x67,0x73,0xe7,0x6f,0x5e,0xdb,0xf4,0xda,0x0e,0x4f,0x1b,0xdf,0xfa,0xc0,0xf5,0x72,0x57,0xe1,0xdf,0xa4,0x65,0x84,0x29,0x31,0x30,0x9a,0x24,0x24,0x5f,0xda,0x6a,0x5d, + 0x04,0x8b,0x90,0x4d,0xe4,0x79,0x67,0x34,0x0c,0x5f,0x8c,0x35,0x72,0xa7,0x20,0x92,0x4e,0xf7,0x57,0x86,0x37,0xfe,0xab,0x19,0x49,0xac,0xb2,0x41,0xa5,0xa6,0xac,0x3f,0x5b,0x95,0x09,0x04,0x49,0x6f,0x98,0x24,0xb1,0xd6,0x3f,0x33,0x13,0xba,0xe2,0x1b,0x89,0xfa,0xe8,0x9a,0xfd,0xfc,0x81,0x1b,0x5e,0xce,0x03,0xfd,0x5a,0xa3,0x01,0x86,0x4f, + 0x04,0xf4,0x89,0x2b,0x6d,0x52,0x5c,0x77,0x1e,0x03,0x5f,0x2a,0x25,0x27,0x08,0xf3,0x78,0x4e,0x48,0x23,0x86,0x04,0xb4,0xf9,0x4d,0xc5,0x6e,0xaa,0x1e,0x54,0x6d,0x94,0x1a,0x34,0x6b,0x1a,0xa0,0xbc,0xe6,0x8b,0x1c,0x50,0xe5,0xb5,0x2f,0x50,0x9f,0xb5,0x52,0x2e,0x5c,0x25,0xe0,0x28,0xbc,0x8f,0x86,0x34,0x02,0xed,0xb7,0xbc,0xad,0x8b,0x1b, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4,0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,0xd4,0xb8, + 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0xb7,0xc5,0x25,0x88,0xd9,0x5c,0x3b,0x9a,0xa2,0x5b,0x04,0x03,0xf1,0xee,0xf7,0x57,0x02,0xe8,0x4b,0xb7,0x59,0x7a,0xab,0xe6,0x63,0xb8,0x2f,0x6f,0x04,0xef,0x27,0x77, + 0x04,0x78,0x2c,0x8e,0xd1,0x7e,0x3b,0x2a,0x78,0x3b,0x54,0x64,0xf3,0x3b,0x09,0x65,0x2a,0x71,0xc6,0x78,0xe0,0x5e,0xc5,0x1e,0x84,0xe2,0xbc,0xfc,0x66,0x3a,0x3d,0xe9,0x63,0xaf,0x9a,0xcb,0x42,0x80,0xb8,0xc7,0xf7,0xc4,0x2f,0x4e,0xf9,0xab,0xa6,0x24,0x5e,0xc1,0xec,0x17,0x12,0xfd,0x38,0xa0,0xfa,0x96,0x41,0x8d,0x8c,0xd6,0xaa,0x61,0x52, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0x00,0x00,0x00,0x01,0x06,0x04,0x92,0xd5,0xa5,0x67,0x3e,0x0f,0x25,0xd8,0xd5,0x0f,0xb7,0xe5,0x8c,0x49,0xd8,0x6d,0x46,0xd4,0x21,0x69,0x55,0xe0,0xaa,0x3d,0x40,0xe1, + 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfb,0x6d,0x2a,0x5a,0x98,0xc1,0xf0,0xda,0x27,0x2a,0xf0,0x48,0x1a,0x73,0xb6,0x27,0x92,0xb9,0x2b,0xde,0x96,0xaa,0x1e,0x55,0xc2,0xbb,0x4e, + 0x04,0x00,0x00,0x00,0x01,0x3f,0xd2,0x22,0x48,0xd6,0x4d,0x95,0xf7,0x3c,0x29,0xb4,0x8a,0xb4,0x86,0x31,0x85,0x0b,0xe5,0x03,0xfd,0x00,0xf8,0x46,0x8b,0x5f,0x0f,0x70,0xe0,0xf6,0xee,0x7a,0xa4,0x3b,0xc2,0xc6,0xfd,0x25,0xb1,0xd8,0x26,0x92,0x41,0xcb,0xdd,0x9d,0xbb,0x0d,0xac,0x96,0xdc,0x96,0x23,0x1f,0x43,0x07,0x05,0xf8,0x38,0x71,0x7d, + 0x04,0x25,0xaf,0xd6,0x89,0xac,0xab,0xae,0xd6,0x7c,0x1f,0x29,0x6d,0xe5,0x94,0x06,0xf8,0xc5,0x50,0xf5,0x71,0x46,0xa0,0xb4,0xec,0x2c,0x97,0x87,0x6d,0xff,0xff,0xff,0xff,0xfa,0x46,0xa7,0x6e,0x52,0x03,0x22,0xdf,0xbc,0x49,0x1e,0xc4,0xf0,0xcc,0x19,0x74,0x20,0xfc,0x4e,0xa5,0x88,0x3d,0x8f,0x6d,0xd5,0x3c,0x35,0x4b,0xc4,0xf6,0x7c,0x35, + 0x04,0xd1,0x2e,0x6c,0x66,0xb6,0x77,0x34,0xc3,0xc8,0x4d,0x26,0x01,0xcf,0x5d,0x35,0xdc,0x09,0x7e,0x27,0x63,0x7f,0x0a,0xca,0x4a,0x4f,0xdb,0x74,0xb6,0xaa,0xdd,0x3b,0xb9,0x3f,0x5b,0xdf,0xf8,0x8b,0xd5,0x73,0x6d,0xf8,0x98,0xe6,0x99,0x00,0x6e,0xd7,0x50,0xf1,0x1c,0xf0,0x7c,0x58,0x66,0xcd,0x7a,0xd7,0x0c,0x71,0x21,0xff,0xff,0xff,0xff, + 0x04,0x6d,0x4a,0x7f,0x60,0xd4,0x77,0x4a,0x4f,0x0a,0xa8,0xbb,0xde,0xdb,0x95,0x3c,0x7e,0xea,0x79,0x09,0x40,0x7e,0x31,0x64,0x75,0x56,0x64,0xbc,0x28,0x00,0x00,0x00,0x00,0xe6,0x59,0xd3,0x4e,0x4d,0xf3,0x8d,0x9e,0x8c,0x9e,0xaa,0xdf,0xba,0x36,0x61,0x2c,0x76,0x91,0x95,0xbe,0x86,0xc7,0x7a,0xac,0x3f,0x36,0xe7,0x8b,0x53,0x86,0x80,0xfb}; + +static const unsigned char wycheproof_ecdsa_signatures[] = { 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x00,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7d,0xb3,0x7c,0x21,0xf4,0xaf,0xd3,0x20,0x3a,0xe8,0xdc,0x4a,0xe7,0x79,0x4b,0x0f,0x87, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0x01,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x7f,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0x80,0x00,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x84,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x85,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x49,0x81,0x77,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x25,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x4d,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x29,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x28,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x81, + 0x30,0x4b,0xaa,0x02,0xaa,0xbb,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x80,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x05,0x00, + 0x2e,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x2f,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x32,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0xff,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x00, + 0x30,0x49,0x30,0x01,0x02,0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x06,0x08,0x11,0x22,0x00,0x00, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0xfe,0x02,0xbe,0xef, + 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x02,0xbe,0xef, + 0x30,0x47,0x30,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x30,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x01,0x00, + 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xbf,0x7f,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x02,0x05,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x00, + 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65, + 0x30,0x67,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x64,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xca,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x13,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x08,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x81,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x82,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0x01,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x7f,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0x80,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x84,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x80,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x23,0x02,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x22,0x26,0x49,0x81,0x77,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x25,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x22,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x04,0xde,0xad,0xbe,0xef,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x81,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4b,0x22,0x27,0xaa,0x02,0xaa,0xbb,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x80,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x01,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x04,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0xff,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x24,0x02,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x22,0x25,0x02,0x01,0x00,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x02,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0xe5,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x82,0x10,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x09,0x01,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x01,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xbb, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa4,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf7,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x01,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0x01,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4e,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x7f,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x80,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x80,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00, + 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x25,0x49,0x81,0x77,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x25,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81, + 0x30,0x4b,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x26,0xaa,0x02,0xaa,0xbb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x01,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x04,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0xff,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x00, + 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x02,0x01,0x6f,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6d,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0x3a, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31, + 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x82,0x10,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x10,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x09,0x01,0x80, + 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x83,0xb9,0x0d,0xea,0xbc,0xa4,0xb0,0x5c,0x45,0x74,0xe4,0x9b,0x58,0x99,0xb9,0x64,0xa6,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x86,0x43,0xb0,0x30,0xef,0x46,0x1f,0x1b,0xcd,0xf5,0x3f,0xde,0x3e,0xf9,0x4c,0xe2,0x24,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x84,0x3f,0xad,0x3b,0xf4,0x85,0x3e,0x07,0xf7,0xc9,0x87,0x70,0xc9,0x9b,0xff,0xc4,0x64,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7b,0x01,0xa0,0xf2,0x2a,0x0a,0x98,0x43,0xf6,0x4a,0xed,0xc3,0x34,0x36,0x7c,0xdc,0x9b,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x79,0xbc,0x4f,0xcf,0x10,0xb9,0xe0,0xe4,0x32,0x0a,0xc0,0x21,0xc1,0x06,0xb3,0x1d,0xdc,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7c,0x46,0xf2,0x15,0x43,0x5b,0x4f,0xa3,0xba,0x8b,0x1b,0x64,0xa7,0x66,0x46,0x9b,0x5a,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x7f,0xc1,0xe1,0x97,0xd8,0xae,0xbe,0x20,0x3c,0x96,0xc8,0x72,0x32,0x27,0x21,0x72,0xfb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x82,0x4c,0x83,0xde,0x0b,0x50,0x2c,0xdf,0xc5,0x17,0x23,0xb5,0x18,0x86,0xb4,0xf0,0x79,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x46,0x02,0x22,0x01,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9a,0x3b,0xb6,0x0f,0xa1,0xa1,0x48,0x15,0xbb,0xc0,0xa9,0x54,0xa0,0x75,0x8d,0x2c,0x72,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x44,0x02,0x20,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7e,0xf8,0xcd,0x45,0x0e,0x00,0x8a,0x7f,0xff,0x29,0x09,0xec,0x5a,0xa9,0x14,0xce,0x46,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xfe,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x80,0x3e,0x1e,0x68,0x27,0x51,0x41,0xdf,0xc3,0x69,0x37,0x8d,0xcd,0xd8,0xde,0x8d,0x05,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x00, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0xff, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0xff, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f, + 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30, + 0x30,0x08,0x02,0x01,0x00,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x00,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x00,0x05,0x00, + 0x30,0x05,0x02,0x01,0x00,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x00,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x00,0x30,0x00, + 0x30,0x08,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0x01,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0x01,0x05,0x00, + 0x30,0x05,0x02,0x01,0x01,0x0c,0x00, + 0x30,0x06,0x02,0x01,0x01,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0x01,0x30,0x00, + 0x30,0x08,0x02,0x01,0x01,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x02,0x01,0xff,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x02,0x01,0xff,0x09,0x01,0x42, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x01, + 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x00, + 0x30,0x05,0x02,0x01,0xff,0x05,0x00, + 0x30,0x05,0x02,0x01,0xff,0x0c,0x00, + 0x30,0x06,0x02,0x01,0xff,0x0c,0x01,0x30, + 0x30,0x05,0x02,0x01,0xff,0x30,0x00, + 0x30,0x08,0x02,0x01,0xff,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x03,0x02,0x01,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x01,0x42, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x01, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x05,0x00, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x00, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x01,0x30, + 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x00, + 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x03,0x02,0x01,0x00, + 0x30,0x0a,0x09,0x03,0x80,0xfe,0x01,0x09,0x03,0x80,0xfe,0x01, + 0x30,0x06,0x09,0x01,0x42,0x09,0x01,0x42, + 0x30,0x06,0x01,0x01,0x01,0x01,0x01,0x01, + 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00, + 0x30,0x04,0x05,0x00,0x05,0x00, + 0x30,0x04,0x0c,0x00,0x0c,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x0c,0x01,0x30, + 0x30,0x04,0x30,0x00,0x30,0x00, + 0x30,0x0a,0x30,0x03,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00, + 0x30,0x08,0x09,0x03,0x80,0xfe,0x01,0x02,0x01,0x00, + 0x30,0x06,0x09,0x01,0x42,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x00, + 0x30,0x06,0x01,0x01,0x00,0x02,0x01,0x00, + 0x30,0x05,0x05,0x00,0x02,0x01,0x00, + 0x30,0x05,0x0c,0x00,0x02,0x01,0x00, + 0x30,0x06,0x0c,0x01,0x30,0x02,0x01,0x00, + 0x30,0x05,0x30,0x00,0x02,0x01,0x00, + 0x30,0x08,0x30,0x03,0x02,0x01,0x00,0x02,0x01,0x00, + 0x30,0x45,0x02,0x21,0x00,0xdd,0x1b,0x7d,0x09,0xa7,0xbd,0x82,0x18,0x96,0x10,0x34,0xa3,0x9a,0x87,0xfe,0xcf,0x53,0x14,0xf0,0x0c,0x4d,0x25,0xeb,0x58,0xa0,0x7a,0xc8,0x5e,0x85,0xea,0xb5,0x16,0x02,0x20,0x35,0x13,0x8c,0x40,0x1e,0xf8,0xd3,0x49,0x3d,0x65,0xc9,0x00,0x2f,0xe6,0x2b,0x43,0xae,0xe5,0x68,0x73,0x1b,0x74,0x45,0x48,0x35,0x89,0x96,0xd9,0xcc,0x42,0x7e,0x06, + 0x30,0x45,0x02,0x21,0x00,0x95,0xc2,0x92,0x67,0xd9,0x72,0xa0,0x43,0xd9,0x55,0x22,0x45,0x46,0x22,0x2b,0xba,0x34,0x3f,0xc1,0xd4,0xdb,0x0f,0xec,0x26,0x2a,0x33,0xac,0x61,0x30,0x56,0x96,0xae,0x02,0x20,0x6e,0xdf,0xe9,0x67,0x13,0xae,0xd5,0x6f,0x8a,0x28,0xa6,0x65,0x3f,0x57,0xe0,0xb8,0x29,0x71,0x2e,0x5e,0xdd,0xc6,0x7f,0x34,0x68,0x2b,0x24,0xf0,0x67,0x6b,0x26,0x40, + 0x30,0x44,0x02,0x20,0x28,0xf9,0x4a,0x89,0x4e,0x92,0x02,0x46,0x99,0xe3,0x45,0xfe,0x66,0x97,0x1e,0x3e,0xdc,0xd0,0x50,0x02,0x33,0x86,0x13,0x5a,0xb3,0x93,0x9d,0x55,0x08,0x98,0xfb,0x25,0x02,0x20,0x32,0x96,0x3e,0x5b,0xd4,0x1f,0xa5,0x91,0x1e,0xd8,0xf3,0x7d,0xeb,0x86,0xda,0xe0,0xa7,0x62,0xbb,0x61,0x21,0xc8,0x94,0x61,0x50,0x83,0xc5,0xd9,0x5e,0xa0,0x1d,0xb3, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x26,0xb1,0x8f,0x95,0x49,0xf8,0x9f,0x41,0x1a,0x9b,0x52,0x53,0x6b,0x15,0xaa,0x27,0x0b,0x84,0x54,0x8d,0x0e,0x85,0x9a,0x19,0x52,0xa2,0x7a,0xf1,0xa7,0x7a,0xc6,0x02,0x20,0x70,0xc1,0xd4,0xfa,0x9c,0xd0,0x3c,0xc8,0xea,0xa8,0xd5,0x06,0xed,0xb9,0x7e,0xed,0x7b,0x83,0x58,0xb4,0x53,0xc8,0x8a,0xef,0xbb,0x88,0x0a,0x3f,0x0e,0x8d,0x47,0x2f, + 0x30,0x45,0x02,0x21,0x00,0xb1,0xa4,0xb1,0x47,0x8e,0x65,0xcc,0x3e,0xaf,0xdf,0x22,0x5d,0x12,0x98,0xb4,0x3f,0x2d,0xa1,0x9e,0x4b,0xcf,0xf7,0xea,0xcc,0x0a,0x2e,0x98,0xcd,0x4b,0x74,0xb1,0x14,0x02,0x20,0x17,0x9a,0xa3,0x1e,0x30,0x4c,0xc1,0x42,0xcf,0x50,0x73,0x17,0x17,0x51,0xb2,0x8f,0x3f,0x5e,0x0f,0xa8,0x8c,0x99,0x4e,0x7c,0x55,0xf1,0xbc,0x07,0xb8,0xd5,0x6c,0x16, + 0x30,0x44,0x02,0x20,0x32,0x53,0x32,0x02,0x12,0x61,0xf1,0xbd,0x18,0xf2,0x71,0x2a,0xa1,0xe2,0x25,0x2d,0xa2,0x37,0x96,0xda,0x8a,0x4b,0x1f,0xf6,0xea,0x18,0xca,0xfe,0xc7,0xe1,0x71,0xf2,0x02,0x20,0x40,0xb4,0xf5,0xe2,0x87,0xee,0x61,0xfc,0x3c,0x80,0x41,0x86,0x98,0x23,0x60,0x89,0x1e,0xaa,0x35,0xc7,0x5f,0x05,0xa4,0x3e,0xcd,0x48,0xb3,0x5d,0x98,0x4a,0x66,0x48, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x3a,0xd1,0x8d,0x8f,0xc6,0x6d,0x81,0xaf,0x09,0x03,0x89,0x0c,0xbd,0x45,0x3a,0x55,0x4c,0xb0,0x4c,0xdc,0x1a,0x8c,0xa7,0xf7,0xf7,0x8e,0x53,0x67,0xed,0x88,0xa0,0x02,0x20,0x23,0xe3,0xeb,0x2c,0xe1,0xc0,0x4e,0xa7,0x48,0xc3,0x89,0xbd,0x97,0x37,0x4a,0xa9,0x41,0x3b,0x92,0x68,0x85,0x1c,0x04,0xdc,0xd9,0xf8,0x8e,0x78,0x81,0x3f,0xee,0x56, + 0x30,0x44,0x02,0x20,0x2b,0xde,0xa4,0x1c,0xda,0x63,0xa2,0xd1,0x4b,0xf4,0x73,0x53,0xbd,0x20,0x88,0x0a,0x69,0x09,0x01,0xde,0x7c,0xd6,0xe3,0xcc,0x6d,0x8e,0xd5,0xba,0x0c,0xdb,0x10,0x91,0x02,0x20,0x3c,0xea,0x66,0xbc,0xcf,0xc9,0xf9,0xbf,0x8c,0x7c,0xa4,0xe1,0xc1,0x45,0x7c,0xc9,0x14,0x5e,0x13,0xe9,0x36,0xd9,0x0b,0x3d,0x9c,0x77,0x86,0xb8,0xb2,0x6c,0xf4,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xd7,0xcd,0x76,0xec,0x01,0xc1,0xb1,0x07,0x9e,0xba,0x9e,0x2a,0xa2,0xa3,0x97,0x24,0x3c,0x47,0x58,0xc9,0x8a,0x1b,0xa0,0xb7,0x40,0x4a,0x34,0x0b,0x9b,0x00,0xce,0xd6,0x02,0x20,0x35,0x75,0x00,0x1e,0x19,0xd9,0x22,0xe6,0xde,0x8b,0x3d,0x6c,0x84,0xea,0x43,0xb5,0xc3,0x33,0x81,0x06,0xcf,0x29,0x99,0x01,0x34,0xe7,0x66,0x9a,0x82,0x6f,0x78,0xe6, + 0x30,0x45,0x02,0x21,0x00,0xa8,0x72,0xc7,0x44,0xd9,0x36,0xdb,0x21,0xa1,0x0c,0x36,0x1d,0xd5,0xc9,0x06,0x33,0x55,0xf8,0x49,0x02,0x21,0x96,0x52,0xf6,0xfc,0x56,0xdc,0x95,0xa7,0x13,0x9d,0x96,0x02,0x20,0x40,0x0d,0xf7,0x57,0x5d,0x97,0x56,0x21,0x0e,0x9c,0xcc,0x77,0x16,0x2c,0x6b,0x59,0x3c,0x77,0x46,0xcf,0xb4,0x8a,0xc2,0x63,0xc4,0x27,0x50,0xb4,0x21,0xef,0x4b,0xb9, + 0x30,0x45,0x02,0x21,0x00,0x9f,0xa9,0xaf,0xe0,0x77,0x52,0xda,0x10,0xb3,0x6d,0x3a,0xfc,0xd0,0xfe,0x44,0xbf,0xc4,0x02,0x44,0xd7,0x52,0x03,0x59,0x9c,0xf8,0xf5,0x04,0x7f,0xa3,0x45,0x38,0x54,0x02,0x20,0x50,0xe0,0xa7,0xc0,0x13,0xbf,0xbf,0x51,0x81,0x97,0x36,0x97,0x2d,0x44,0xb4,0xb5,0x6b,0xc2,0xa2,0xb2,0xc1,0x80,0xdf,0x6e,0xc6,0x72,0xdf,0x17,0x14,0x10,0xd7,0x7a, + 0x30,0x45,0x02,0x21,0x00,0x88,0x56,0x40,0x38,0x4d,0x0d,0x91,0x0e,0xfb,0x17,0x7b,0x46,0xbe,0x6c,0x3d,0xc5,0xca,0xc8,0x1f,0x0b,0x88,0xc3,0x19,0x0b,0xb6,0xb5,0xf9,0x9c,0x26,0x41,0xf2,0x05,0x02,0x20,0x73,0x8e,0xd9,0xbf,0xf1,0x16,0x30,0x6d,0x9c,0xaa,0x0f,0x8f,0xc6,0x08,0xbe,0x24,0x3e,0x0b,0x56,0x77,0x79,0xd8,0xda,0xb0,0x3e,0x8e,0x19,0xd5,0x53,0xf1,0xdc,0x8e, + 0x30,0x44,0x02,0x20,0x2d,0x05,0x1f,0x91,0xc5,0xa9,0xd4,0x40,0xc5,0x67,0x69,0x85,0x71,0x04,0x83,0xbc,0x4f,0x1a,0x6c,0x61,0x1b,0x10,0xc9,0x5a,0x2f,0xf0,0x36,0x3d,0x90,0xc2,0xa4,0x58,0x02,0x20,0x6d,0xdf,0x94,0xe6,0xfb,0xa5,0xbe,0x58,0x68,0x33,0xd0,0xc5,0x3c,0xf2,0x16,0xad,0x39,0x48,0xf3,0x79,0x53,0xc2,0x6c,0x1c,0xf4,0x96,0x8e,0x9a,0x9e,0x82,0x43,0xdc, + 0x30,0x45,0x02,0x21,0x00,0xf3,0xac,0x25,0x23,0x96,0x74,0x82,0xf5,0x3d,0x50,0x85,0x22,0x71,0x2d,0x58,0x3f,0x43,0x79,0xcd,0x82,0x41,0x01,0xff,0x63,0x5e,0xa0,0x93,0x51,0x17,0xba,0xa5,0x4f,0x02,0x20,0x27,0xf1,0x08,0x12,0x22,0x73,0x97,0xe0,0x2c,0xea,0x96,0xfb,0x0e,0x68,0x07,0x61,0x63,0x6d,0xab,0x2b,0x08,0x0d,0x1f,0xc5,0xd1,0x16,0x85,0xcb,0xe8,0x50,0x0c,0xfe, + 0x30,0x45,0x02,0x21,0x00,0x96,0x44,0x7c,0xf6,0x8c,0x3a,0xb7,0x26,0x6e,0xd7,0x44,0x7d,0xe3,0xac,0x52,0xfe,0xd7,0xcc,0x08,0xcb,0xdf,0xea,0x39,0x1c,0x18,0xa9,0xb8,0xab,0x37,0x0b,0xc9,0x13,0x02,0x20,0x0f,0x5e,0x78,0x74,0xd3,0xac,0x0e,0x91,0x8f,0x01,0xc8,0x85,0xa1,0x63,0x91,0x77,0xc9,0x23,0xf8,0x66,0x0d,0x1c,0xeb,0xa1,0xca,0x1f,0x30,0x1b,0xc6,0x75,0xcd,0xbc, + 0x30,0x44,0x02,0x20,0x53,0x0a,0x08,0x32,0xb6,0x91,0xda,0x0b,0x56,0x19,0xa0,0xb1,0x1d,0xe6,0x87,0x7f,0x3c,0x09,0x71,0xba,0xaa,0x68,0xed,0x12,0x27,0x58,0xc2,0x9c,0xaa,0xf4,0x6b,0x72,0x02,0x20,0x6c,0x89,0xe4,0x4f,0x5e,0xb3,0x30,0x60,0xea,0x4b,0x46,0x31,0x8c,0x39,0x13,0x8e,0xae,0xde,0xc7,0x2d,0xe4,0x2b,0xa5,0x76,0x57,0x9a,0x6a,0x46,0x90,0xe3,0x39,0xf3, + 0x30,0x45,0x02,0x21,0x00,0x9c,0x54,0xc2,0x55,0x00,0xbd,0xe0,0xb9,0x2d,0x72,0xd6,0xec,0x48,0x3d,0xc2,0x48,0x2f,0x36,0x54,0x29,0x4c,0xa7,0x4d,0xe7,0x96,0xb6,0x81,0x25,0x5e,0xd5,0x8a,0x77,0x02,0x20,0x67,0x74,0x53,0xc6,0xb5,0x6f,0x52,0x76,0x31,0xc9,0xf6,0x7b,0x3f,0x3e,0xb6,0x21,0xfd,0x88,0x58,0x2b,0x4a,0xff,0x15,0x6d,0x2f,0x15,0x67,0xd6,0x21,0x1a,0x2a,0x33, + 0x30,0x45,0x02,0x21,0x00,0xe7,0x90,0x9d,0x41,0x43,0x9e,0x2f,0x6a,0xf2,0x91,0x36,0xc7,0x34,0x8c,0xa2,0x64,0x1a,0x2b,0x07,0x0d,0x5b,0x64,0xf9,0x1e,0xa9,0xda,0x70,0x70,0xc7,0xa2,0x61,0x8b,0x02,0x20,0x42,0xd7,0x82,0xf1,0x32,0xfa,0x1d,0x36,0xc2,0xc8,0x8b,0xa2,0x7c,0x3d,0x67,0x8d,0x80,0x18,0x4a,0x5d,0x1e,0xcc,0xac,0x75,0x01,0xf0,0xb4,0x7e,0x3d,0x20,0x50,0x08, + 0x30,0x44,0x02,0x20,0x59,0x24,0x87,0x32,0x09,0x59,0x31,0x35,0xa4,0xc3,0xda,0x7b,0xb3,0x81,0x22,0x7f,0x8a,0x4b,0x6a,0xa9,0xf3,0x4f,0xe5,0xbb,0x7f,0x8f,0xbc,0x13,0x1a,0x03,0x9f,0xfe,0x02,0x20,0x1f,0x1b,0xb1,0x1b,0x44,0x1c,0x8f,0xea,0xa4,0x0f,0x44,0x21,0x3d,0x9a,0x40,0x5e,0xd7,0x92,0xd5,0x9f,0xb4,0x9d,0x5b,0xcd,0xd9,0xa4,0x28,0x5a,0xe5,0x69,0x30,0x22, + 0x30,0x45,0x02,0x21,0x00,0xee,0xb6,0x92,0xc9,0xb2,0x62,0x96,0x9b,0x23,0x1c,0x38,0xb5,0xa7,0xf6,0x06,0x49,0xe0,0xc8,0x75,0xcd,0x64,0xdf,0x88,0xf3,0x3a,0xa5,0x71,0xfa,0x3d,0x29,0xab,0x0e,0x02,0x20,0x21,0x8b,0x3a,0x1e,0xb0,0x63,0x79,0xc2,0xc1,0x8c,0xf5,0x1b,0x06,0x43,0x07,0x86,0xd1,0xc6,0x4c,0xd2,0xd2,0x4c,0x9b,0x23,0x2b,0x23,0xe5,0xba,0xc7,0x98,0x9a,0xcd, + 0x30,0x45,0x02,0x21,0x00,0xa4,0x00,0x34,0x17,0x7f,0x36,0x09,0x1c,0x2b,0x65,0x36,0x84,0xa0,0xe3,0xeb,0x5d,0x4b,0xff,0x18,0xe4,0xd0,0x9f,0x66,0x4c,0x28,0x00,0xe7,0xca,0xfd,0xa1,0xda,0xf8,0x02,0x20,0x3a,0x3e,0xc2,0x98,0x53,0x70,0x4e,0x52,0x03,0x1c,0x58,0x92,0x7a,0x80,0x0a,0x96,0x83,0x53,0xad,0xc3,0xd9,0x73,0xbe,0xba,0x91,0x72,0xcb,0xbe,0xab,0x4d,0xd1,0x49, + 0x30,0x45,0x02,0x21,0x00,0xb5,0xd7,0x95,0xcc,0x75,0xce,0xa5,0xc4,0x34,0xfa,0x41,0x85,0x18,0x0c,0xd6,0xbd,0x21,0x22,0x3f,0x3d,0x5a,0x86,0xda,0x66,0x70,0xd7,0x1d,0x95,0x68,0x0d,0xad,0xbf,0x02,0x20,0x54,0xe4,0xd8,0x81,0x0a,0x00,0x1e,0xcb,0xb9,0xf7,0xca,0x1c,0x2e,0xbf,0xdb,0x9d,0x00,0x9e,0x90,0x31,0xa4,0x31,0xac,0xa3,0xc2,0x0a,0xb4,0xe0,0xd1,0x37,0x4e,0xc1, + 0x30,0x44,0x02,0x20,0x07,0xdc,0x24,0x78,0xd4,0x3c,0x12,0x32,0xa4,0x59,0x56,0x08,0xc6,0x44,0x26,0xc3,0x55,0x10,0x05,0x1a,0x63,0x1a,0xe6,0xa5,0xa6,0xeb,0x11,0x61,0xe5,0x7e,0x42,0xe1,0x02,0x20,0x4a,0x59,0xea,0x0f,0xdb,0x72,0xd1,0x21,0x65,0xce,0xa3,0xbf,0x1c,0xa8,0x6b,0xa9,0x75,0x17,0xbd,0x18,0x8d,0xb3,0xdb,0xd2,0x1a,0x5a,0x15,0x78,0x50,0x02,0x19,0x84, + 0x30,0x45,0x02,0x21,0x00,0xdd,0xd2,0x0c,0x4a,0x05,0x59,0x6c,0xa8,0x68,0xb5,0x58,0x83,0x9f,0xce,0x9f,0x65,0x11,0xdd,0xd8,0x3d,0x1c,0xcb,0x53,0xf8,0x2e,0x52,0x69,0xd5,0x59,0xa0,0x15,0x52,0x02,0x20,0x5b,0x91,0x73,0x47,0x29,0xd9,0x30,0x93,0xff,0x22,0x12,0x3c,0x4a,0x25,0x81,0x9d,0x7f,0xeb,0x66,0xa2,0x50,0x66,0x3f,0xc7,0x80,0xcb,0x66,0xfc,0x7b,0x6e,0x6d,0x17, + 0x30,0x45,0x02,0x21,0x00,0x9c,0xde,0x6e,0x0e,0xde,0x0a,0x00,0x3f,0x02,0xfd,0xa0,0xa0,0x1b,0x59,0xfa,0xcf,0xe5,0xde,0xc0,0x63,0x31,0x8f,0x27,0x9c,0xe2,0xde,0x7a,0x9b,0x10,0x62,0xf7,0xb7,0x02,0x20,0x28,0x86,0xa5,0xb8,0xc6,0x79,0xbd,0xf8,0x22,0x4c,0x66,0xf9,0x08,0xfd,0x62,0x05,0x49,0x2c,0xb7,0x0b,0x00,0x68,0xd4,0x6a,0xe4,0xf3,0x3a,0x41,0x49,0xb1,0x2a,0x52, + 0x30,0x45,0x02,0x21,0x00,0xc5,0x77,0x10,0x16,0xd0,0xdd,0x63,0x57,0x14,0x3c,0x89,0xf6,0x84,0xcd,0x74,0x04,0x23,0x50,0x25,0x54,0xc0,0xc5,0x9a,0xa8,0xc9,0x95,0x84,0xf1,0xff,0x38,0xf6,0x09,0x02,0x20,0x54,0xb4,0x05,0xf4,0x47,0x75,0x46,0x68,0x6e,0x46,0x4c,0x54,0x63,0xb4,0xfd,0x41,0x90,0x57,0x2e,0x58,0xd0,0xf7,0xe7,0x35,0x7f,0x6e,0x61,0x94,0x7d,0x20,0x71,0x5c, + 0x30,0x45,0x02,0x21,0x00,0xa2,0x4e,0xbc,0x0e,0xc2,0x24,0xbd,0x67,0xae,0x39,0x7c,0xbe,0x6f,0xa3,0x7b,0x31,0x25,0xad,0xbd,0x34,0x89,0x1a,0xbe,0x2d,0x7c,0x73,0x56,0x92,0x19,0x16,0xdf,0xe6,0x02,0x20,0x34,0xf6,0xeb,0x63,0x74,0x73,0x1b,0xbb,0xaf,0xc4,0x92,0x4f,0xb8,0xb0,0xbd,0xcd,0xda,0x49,0x45,0x6d,0x72,0x4c,0xda,0xe6,0x17,0x8d,0x87,0x01,0x4c,0xb5,0x3d,0x8c, + 0x30,0x44,0x02,0x20,0x25,0x57,0xd6,0x4a,0x7a,0xee,0x2e,0x09,0x31,0xc0,0x12,0xe4,0xfe,0xa1,0xcd,0x3a,0x2c,0x33,0x4e,0xda,0xe6,0x8c,0xde,0xb7,0x15,0x8c,0xaf,0x21,0xb6,0x8e,0x5a,0x24,0x02,0x20,0x7f,0x06,0xcd,0xbb,0x6a,0x90,0x02,0x3a,0x97,0x38,0x82,0xed,0x97,0xb0,0x80,0xfe,0x6b,0x05,0xaf,0x3e,0xc9,0x3d,0xb6,0xf1,0xa4,0x39,0x9a,0x69,0xed,0xf7,0x67,0x0d, + 0x30,0x45,0x02,0x21,0x00,0xc4,0xf2,0xec,0xcb,0xb6,0xa2,0x43,0x50,0xc8,0x46,0x64,0x50,0xb9,0xd6,0x1b,0x20,0x7e,0xe3,0x59,0xe0,0x37,0xb3,0xdc,0xed,0xb4,0x2a,0x3f,0x2e,0x6d,0xd6,0xae,0xb5,0x02,0x20,0x32,0x63,0xc6,0xb5,0x9a,0x2f,0x55,0xcd,0xd1,0xc6,0xe1,0x48,0x94,0xd5,0xe5,0x96,0x3b,0x28,0xbc,0x3e,0x24,0x69,0xac,0x9b,0xa1,0x19,0x79,0x91,0xca,0x7f,0xf9,0xc7, + 0x30,0x45,0x02,0x21,0x00,0xef,0xf0,0x47,0x81,0xc9,0xcb,0xcd,0x16,0x2d,0x0a,0x25,0xa6,0xe2,0xeb,0xcc,0xa4,0x35,0x06,0xc5,0x23,0x38,0x5c,0xb5,0x15,0xd4,0x9e,0xa3,0x8a,0x1b,0x12,0xfc,0xad,0x02,0x20,0x15,0xac,0xd7,0x31,0x94,0xc9,0x1a,0x95,0x47,0x85,0x34,0xf2,0x30,0x15,0xb6,0x72,0xeb,0xed,0x21,0x3e,0x45,0x42,0x4d,0xd2,0xc8,0xe2,0x6a,0xc8,0xb3,0xeb,0x34,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xf5,0x8b,0x4e,0x31,0x10,0xa6,0x4b,0xf1,0xb5,0xdb,0x97,0x63,0x9e,0xe0,0xe5,0xa9,0xc8,0xdf,0xa4,0x9d,0xc5,0x9b,0x67,0x98,0x91,0xf5,0x20,0xfd,0xf0,0x58,0x4c,0x87,0x02,0x20,0x2c,0xd8,0xfe,0x51,0x88,0x8a,0xee,0x9d,0xb3,0xe0,0x75,0x44,0x0f,0xd4,0xdb,0x73,0xb5,0xc7,0x32,0xfb,0x87,0xb5,0x10,0xe9,0x70,0x93,0xd6,0x64,0x15,0xf6,0x2a,0xf7, + 0x30,0x45,0x02,0x21,0x00,0xf8,0xab,0xec,0xaa,0x4f,0x0c,0x50,0x2d,0xe4,0xbf,0x59,0x03,0xd4,0x84,0x17,0xf7,0x86,0xbf,0x92,0xe8,0xad,0x72,0xfe,0xc0,0xbd,0x7f,0xcb,0x78,0x00,0xc0,0xbb,0xe3,0x02,0x20,0x4c,0x7f,0x9e,0x23,0x10,0x76,0xa3,0x0b,0x7a,0xe3,0x6b,0x0c,0xeb,0xe6,0x9c,0xce,0xf1,0xcd,0x19,0x4f,0x7c,0xce,0x93,0xa5,0x58,0x8f,0xd6,0x81,0x4f,0x43,0x7c,0x0e, + 0x30,0x44,0x02,0x20,0x5d,0x5b,0x38,0xbd,0x37,0xad,0x49,0x8b,0x22,0x27,0xa6,0x33,0x26,0x8a,0x8c,0xca,0x87,0x9a,0x5c,0x7c,0x94,0xa4,0xe4,0x16,0xbd,0x0a,0x61,0x4d,0x09,0xe6,0x06,0xd2,0x02,0x20,0x12,0xb8,0xd6,0x64,0xea,0x99,0x91,0x06,0x2e,0xcb,0xb8,0x34,0xe5,0x84,0x00,0xe2,0x5c,0x46,0x00,0x7a,0xf8,0x4f,0x60,0x07,0xd7,0xf1,0x68,0x54,0x43,0x26,0x9a,0xfe, + 0x30,0x44,0x02,0x20,0x0c,0x1c,0xd9,0xfe,0x40,0x34,0xf0,0x86,0xa2,0xb5,0x2d,0x65,0xb9,0xd3,0x83,0x4d,0x72,0xae,0xbe,0x7f,0x33,0xdf,0xe8,0xf9,0x76,0xda,0x82,0x64,0x81,0x77,0xd8,0xe3,0x02,0x20,0x13,0x10,0x57,0x82,0xe3,0xd0,0xcf,0xe8,0x5c,0x27,0x78,0xde,0xc1,0xa8,0x48,0xb2,0x7a,0xc0,0xae,0x07,0x1a,0xa6,0xda,0x34,0x1a,0x95,0x53,0xa9,0x46,0xb4,0x1e,0x59, + 0x30,0x45,0x02,0x21,0x00,0xae,0x79,0x35,0xfb,0x96,0xff,0x24,0x6b,0x7b,0x5d,0x56,0x62,0x87,0x0d,0x1b,0xa5,0x87,0xb0,0x3d,0x6e,0x13,0x60,0xba,0xf4,0x79,0x88,0xb5,0xc0,0x2c,0xcc,0x1a,0x5b,0x02,0x20,0x5f,0x00,0xc3,0x23,0x27,0x20,0x83,0x78,0x2d,0x4a,0x59,0xf2,0xdf,0xd6,0x5e,0x49,0xde,0x06,0x93,0x62,0x70,0x16,0x90,0x0e,0xf7,0xe6,0x14,0x28,0x05,0x66,0x64,0xb3, + 0x30,0x44,0x02,0x20,0x00,0xa1,0x34,0xb5,0xc6,0xcc,0xbc,0xef,0xd4,0xc8,0x82,0xb9,0x45,0xba,0xeb,0x49,0x33,0x44,0x41,0x72,0x79,0x5f,0xa6,0x79,0x6a,0xae,0x14,0x90,0x67,0x54,0x70,0x98,0x02,0x20,0x56,0x6e,0x46,0x10,0x5d,0x24,0xd8,0x90,0x15,0x1e,0x3e,0xea,0x3e,0xbf,0x88,0xf5,0xb9,0x2b,0x3f,0x5e,0xc9,0x3a,0x21,0x77,0x65,0xa6,0xdc,0xbd,0x94,0xf2,0xc5,0x5b, + 0x30,0x44,0x02,0x20,0x2e,0x47,0x21,0x36,0x3a,0xd3,0x99,0x2c,0x13,0x9e,0x5a,0x1c,0x26,0x39,0x5d,0x2c,0x2d,0x77,0x78,0x24,0xaa,0x24,0xfd,0xe0,0x75,0xe0,0xd7,0x38,0x11,0x71,0x30,0x9d,0x02,0x20,0x74,0x0f,0x7c,0x49,0x44,0x18,0xe1,0x30,0x0d,0xd4,0x51,0x2f,0x78,0x2a,0x58,0x80,0x0b,0xff,0x6a,0x7a,0xbd,0xfd,0xd2,0x0f,0xbb,0xd4,0xf0,0x55,0x15,0xca,0x1a,0x4f, + 0x30,0x44,0x02,0x20,0x68,0x52,0xe9,0xd3,0xcd,0x9f,0xe3,0x73,0xc2,0xd5,0x04,0x87,0x79,0x67,0xd3,0x65,0xab,0x14,0x56,0x70,0x7b,0x68,0x17,0xa0,0x42,0x86,0x46,0x94,0xe1,0x96,0x0c,0xcf,0x02,0x20,0x06,0x4b,0x27,0xea,0x14,0x2b,0x30,0x88,0x7b,0x84,0xc8,0x6a,0xdc,0xcb,0x2f,0xa3,0x9a,0x69,0x11,0xad,0x21,0xfc,0x7e,0x81,0x9f,0x59,0x3b,0xe5,0x2b,0xc4,0xf3,0xbd, + 0x30,0x44,0x02,0x20,0x18,0x8a,0x8c,0x56,0x48,0xdc,0x79,0xea,0xce,0x15,0x8c,0xf8,0x86,0xc6,0x2b,0x54,0x68,0xf0,0x5f,0xd9,0x5f,0x03,0xa7,0x63,0x5c,0x5b,0x4c,0x31,0xf0,0x9a,0xf4,0xc5,0x02,0x20,0x36,0x36,0x1a,0x0b,0x57,0x1a,0x00,0xc6,0xcd,0x5e,0x68,0x6c,0xcb,0xfc,0xfa,0x70,0x3c,0x4f,0x97,0xe4,0x89,0x38,0x34,0x6d,0x0c,0x10,0x3f,0xdc,0x76,0xdc,0x58,0x67, + 0x30,0x45,0x02,0x21,0x00,0xa7,0x4f,0x1f,0xb9,0xa8,0x26,0x3f,0x62,0xfc,0x44,0x16,0xa5,0xb7,0xd5,0x84,0xf4,0x20,0x6f,0x39,0x96,0xbb,0x91,0xf6,0xfc,0x8e,0x73,0xb9,0xe9,0x2b,0xad,0x0e,0x13,0x02,0x20,0x68,0x15,0x03,0x2e,0x8c,0x7d,0x76,0xc3,0xab,0x06,0xa8,0x6f,0x33,0x24,0x9c,0xe9,0x94,0x01,0x48,0xcb,0x36,0xd1,0xf4,0x17,0xc2,0xe9,0x92,0xe8,0x01,0xaf,0xa3,0xfa, + 0x30,0x44,0x02,0x20,0x07,0x24,0x48,0x65,0xb7,0x2f,0xf3,0x7e,0x62,0xe3,0x14,0x6f,0x0d,0xc1,0x46,0x82,0xba,0xdd,0x71,0x97,0x79,0x91,0x35,0xf0,0xb0,0x0a,0xde,0x76,0x71,0x74,0x2b,0xfe,0x02,0x20,0x0d,0x80,0xc2,0x23,0x8e,0xdb,0x4e,0x4a,0x7a,0x86,0xa8,0xc5,0x7c,0xa9,0xaf,0x17,0x11,0xf4,0x06,0xf7,0xf5,0xda,0x02,0x99,0xaa,0x04,0xe2,0x93,0x2d,0x96,0x07,0x54, + 0x30,0x45,0x02,0x21,0x00,0xda,0x7f,0xdd,0x05,0xb5,0xba,0xda,0xbd,0x61,0x9d,0x80,0x5c,0x4e,0xe7,0xd9,0xa8,0x4f,0x84,0xdd,0xd5,0xcf,0x9c,0x5b,0xf4,0xd4,0x33,0x81,0x40,0xd6,0x89,0xef,0x08,0x02,0x20,0x28,0xf1,0xcf,0x4f,0xa1,0xc3,0xc5,0x86,0x2c,0xfa,0x14,0x9c,0x00,0x13,0xcf,0x5f,0xe6,0xcf,0x50,0x76,0xca,0xe0,0x00,0x51,0x10,0x63,0xe7,0xde,0x25,0xbb,0x38,0xe5, + 0x30,0x45,0x02,0x21,0x00,0xd3,0x02,0x7c,0x65,0x6f,0x6d,0x4f,0xdf,0xd8,0xed,0xe2,0x20,0x93,0xe3,0xc3,0x03,0xb0,0x13,0x3c,0x34,0x0d,0x61,0x5e,0x77,0x56,0xf6,0x25,0x3a,0xea,0x92,0x72,0x38,0x02,0x20,0x09,0xae,0xf0,0x60,0xc8,0xe4,0xce,0xf9,0x72,0x97,0x40,0x11,0x55,0x8d,0xf1,0x44,0xfe,0xd2,0x5c,0xa6,0x9a,0xe8,0xd0,0xb2,0xea,0xf1,0xa8,0xfe,0xef,0xbe,0xc4,0x17, + 0x30,0x44,0x02,0x20,0x0b,0xf6,0xc0,0x18,0x8d,0xc9,0x57,0x1c,0xd0,0xe2,0x1e,0xec,0xac,0x5f,0xbb,0x19,0xd2,0x43,0x49,0x88,0xe9,0xcc,0x10,0x24,0x45,0x93,0xef,0x3a,0x98,0x09,0x9f,0x69,0x02,0x20,0x48,0x64,0xa5,0x62,0x66,0x1f,0x92,0x21,0xec,0x88,0xe3,0xdd,0x0b,0xc2,0xf6,0xe2,0x7a,0xc1,0x28,0xc3,0x0c,0xc1,0xa8,0x0f,0x79,0xec,0x67,0x0a,0x22,0xb0,0x42,0xee, + 0x30,0x45,0x02,0x21,0x00,0xae,0x45,0x96,0x40,0xd5,0xd1,0x17,0x9b,0xe4,0x7a,0x47,0xfa,0x53,0x8e,0x16,0xd9,0x4d,0xde,0xa5,0x58,0x5e,0x7a,0x24,0x48,0x04,0xa5,0x17,0x42,0xc6,0x86,0x44,0x3a,0x02,0x20,0x6c,0x8e,0x30,0xe5,0x30,0xa6,0x34,0xfa,0xe8,0x0b,0x3c,0xeb,0x06,0x29,0x78,0xb3,0x9e,0xdb,0xe1,0x97,0x77,0xe0,0xa2,0x45,0x53,0xb6,0x88,0x86,0x18,0x1f,0xd8,0x97, + 0x30,0x44,0x02,0x20,0x1c,0xf3,0x51,0x7b,0xa3,0xbf,0x2a,0xb8,0xb9,0xea,0xd4,0xeb,0xb6,0xe8,0x66,0xcb,0x88,0xa1,0xde,0xac,0xb6,0xa7,0x85,0xd3,0xb6,0x3b,0x48,0x3c,0xa0,0x2a,0xc4,0x95,0x02,0x20,0x24,0x9a,0x79,0x8b,0x73,0x60,0x6f,0x55,0xf5,0xf1,0xc7,0x0d,0xe6,0x7c,0xb1,0xa0,0xcf,0xf9,0x5d,0x7d,0xc5,0x0b,0x3a,0x61,0x7d,0xf8,0x61,0xba,0xd3,0xc6,0xb1,0xc9, + 0x30,0x45,0x02,0x21,0x00,0xe6,0x9b,0x52,0x38,0x26,0x5e,0xa3,0x5d,0x77,0xe4,0xdd,0x17,0x22,0x88,0xd8,0xce,0xa1,0x98,0x10,0xa1,0x02,0x92,0x61,0x7d,0x59,0x76,0x51,0x9d,0xc5,0x75,0x7c,0xb8,0x02,0x20,0x4b,0x03,0xc5,0xbc,0x47,0xe8,0x26,0xbd,0xb2,0x73,0x28,0xab,0xd3,0x8d,0x30,0x56,0xd7,0x74,0x76,0xb2,0x13,0x0f,0x3d,0xf6,0xec,0x48,0x91,0xaf,0x08,0xba,0x1e,0x29, + 0x30,0x44,0x02,0x20,0x5f,0x9d,0x7d,0x7c,0x87,0x0d,0x08,0x5f,0xc1,0xd4,0x9f,0xff,0x69,0xe4,0xa2,0x75,0x81,0x28,0x00,0xd2,0xcf,0x89,0x73,0xe7,0x32,0x58,0x66,0xcb,0x40,0xfa,0x2b,0x6f,0x02,0x20,0x6d,0x1f,0x54,0x91,0xd9,0xf7,0x17,0xa5,0x97,0xa1,0x5f,0xd5,0x40,0x40,0x64,0x86,0xd7,0x6a,0x44,0x69,0x7b,0x3f,0x0d,0x9d,0x6d,0xce,0xf6,0x66,0x9f,0x8a,0x0a,0x56, + 0x30,0x44,0x02,0x20,0x0a,0x7d,0x5b,0x19,0x59,0xf7,0x1d,0xf9,0xf8,0x17,0x14,0x6e,0xe4,0x9b,0xd5,0xc8,0x9b,0x43,0x1e,0x79,0x93,0xe2,0xfd,0xec,0xab,0x68,0x58,0x95,0x7d,0xa6,0x85,0xae,0x02,0x20,0x0f,0x8a,0xad,0x2d,0x25,0x46,0x90,0xbd,0xc1,0x3f,0x34,0xa4,0xfe,0xc4,0x4a,0x02,0xfd,0x74,0x5a,0x42,0x2d,0xf0,0x5c,0xcb,0xb5,0x46,0x35,0xa8,0xb8,0x6b,0x96,0x09, + 0x30,0x44,0x02,0x20,0x79,0xe8,0x8b,0xf5,0x76,0xb7,0x4b,0xc0,0x7c,0xa1,0x42,0x39,0x5f,0xda,0x28,0xf0,0x3d,0x3d,0x5e,0x64,0x0b,0x0b,0x4f,0xf0,0x75,0x2c,0x6d,0x94,0xcd,0x55,0x34,0x08,0x02,0x20,0x32,0xce,0xa0,0x5b,0xd2,0xd7,0x06,0xc8,0xf6,0x03,0x6a,0x50,0x7e,0x2a,0xb7,0x76,0x60,0x04,0xf0,0x90,0x4e,0x2e,0x5c,0x58,0x62,0x74,0x9c,0x00,0x73,0x24,0x5d,0x6a, + 0x30,0x45,0x02,0x21,0x00,0x9d,0x54,0xe0,0x37,0xa0,0x02,0x12,0xb3,0x77,0xbc,0x88,0x74,0x79,0x8b,0x8d,0xa0,0x80,0x56,0x4b,0xbd,0xf7,0xe0,0x75,0x91,0xb8,0x61,0x28,0x58,0x09,0xd0,0x14,0x88,0x02,0x20,0x18,0xb4,0xe5,0x57,0x66,0x7a,0x82,0xbd,0x95,0x96,0x5f,0x07,0x06,0xf8,0x1a,0x29,0x24,0x3f,0xbd,0xd8,0x69,0x68,0xa7,0xeb,0xeb,0x43,0x06,0x9d,0xb3,0xb1,0x8c,0x7f, + 0x30,0x44,0x02,0x20,0x26,0x64,0xf1,0xff,0xa9,0x82,0xfe,0xdb,0xcc,0x7c,0xab,0x1b,0x8b,0xc6,0xe2,0xcb,0x42,0x02,0x18,0xd2,0xa6,0x07,0x7a,0xd0,0x8e,0x59,0x1b,0xa9,0xfe,0xab,0x33,0xbd,0x02,0x20,0x49,0xf5,0xc7,0xcb,0x51,0x5e,0x83,0x87,0x2a,0x3d,0x41,0xb4,0xcd,0xb8,0x5f,0x24,0x2a,0xd9,0xd6,0x1a,0x5b,0xfc,0x01,0xde,0xbf,0xbb,0x52,0xc6,0xc8,0x4b,0xa7,0x28, + 0x30,0x44,0x02,0x20,0x58,0x27,0x51,0x83,0x44,0x84,0x4f,0xd6,0xa7,0xde,0x73,0xcb,0xb0,0xa6,0xbe,0xfd,0xea,0x7b,0x13,0xd2,0xde,0xe4,0x47,0x53,0x17,0xf0,0xf1,0x8f,0xfc,0x81,0x52,0x4b,0x02,0x20,0x4f,0x5c,0xcb,0x4e,0x0b,0x48,0x8b,0x5a,0x5d,0x76,0x0a,0xac,0xdd,0xb2,0xd7,0x91,0x97,0x0f,0xe4,0x3d,0xa6,0x1e,0xb3,0x0e,0x2e,0x90,0x20,0x8a,0x81,0x7e,0x46,0xdb, + 0x30,0x45,0x02,0x21,0x00,0x97,0xab,0x19,0xbd,0x13,0x9c,0xac,0x31,0x93,0x25,0x86,0x92,0x18,0xb1,0xbc,0xe1,0x11,0x87,0x5d,0x63,0xfb,0x12,0x09,0x8a,0x04,0xb0,0xcd,0x59,0xb6,0xfd,0xd3,0xa3,0x02,0x20,0x43,0x1d,0x9c,0xea,0x3a,0x24,0x38,0x47,0x30,0x3c,0xeb,0xda,0x56,0x47,0x64,0x31,0xd0,0x34,0x33,0x9f,0x31,0xd7,0x85,0xee,0x88,0x52,0xdb,0x4f,0x04,0x0d,0x49,0x21, + 0x30,0x44,0x02,0x20,0x52,0xc6,0x83,0x14,0x4e,0x44,0x11,0x9a,0xe2,0x01,0x37,0x49,0xd4,0x96,0x4e,0xf6,0x75,0x09,0x27,0x8f,0x6d,0x38,0xba,0x86,0x9a,0xdc,0xfa,0x69,0x97,0x0e,0x12,0x3d,0x02,0x20,0x34,0x79,0x91,0x01,0x67,0x40,0x8f,0x45,0xbd,0xa4,0x20,0xa6,0x26,0xec,0x9c,0x4e,0xc7,0x11,0xc1,0x27,0x4b,0xe0,0x92,0x19,0x8b,0x41,0x87,0xc0,0x18,0xb5,0x62,0xca, + 0x30,0x16,0x02,0x11,0x01,0x45,0x51,0x23,0x19,0x50,0xb7,0x5f,0xc4,0x40,0x2d,0xa1,0x72,0x2f,0xc9,0xba,0xeb,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2c,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x3f,0x02,0x01,0x03, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x9a,0x75,0x82,0x88,0x60,0x89,0xc6,0x2f,0xb8,0x40,0xcf,0x3b,0x83,0x06,0x1c,0xd1,0xcf,0xf3,0xae,0x43,0x41,0x80,0x8b,0xb5,0xbd,0xee,0x61,0x91,0x17,0x41,0x77, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x24,0x23,0x8e,0x70,0xb4,0x31,0xb1,0xa6,0x4e,0xfd,0xf9,0x03,0x26,0x69,0x93,0x9d,0x4b,0x77,0xf2,0x49,0x50,0x3f,0xc6,0x90,0x5f,0xeb,0x75,0x40,0xde,0xa3,0xe6,0xd2, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x03, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x01, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x02, + 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x03, + 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x43,0x02,0x01,0x03, + 0x30,0x08,0x02,0x01,0x02,0x02,0x03,0xed,0x29,0x79, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0x9f,0x8a,0xb3,0x73,0x2a,0x0a,0x89,0x60,0x4a,0x09,0xbc,0xe5,0xb2,0x91,0x6d,0xa4, + 0x30,0x2b,0x02,0x07,0x2d,0x9b,0x4d,0x34,0x79,0x52,0xcc,0x02,0x20,0x03,0x43,0xae,0xfc,0x2f,0x25,0xd9,0x8b,0x88,0x2e,0x86,0xeb,0x9e,0x30,0xd5,0x5a,0x6e,0xb5,0x08,0xb5,0x16,0x51,0x0b,0x34,0x02,0x4a,0xe4,0xb6,0x36,0x23,0x30,0xb3, + 0x30,0x31,0x02,0x0d,0x10,0x33,0xe6,0x7e,0x37,0xb3,0x2b,0x44,0x55,0x80,0xbf,0x4e,0xfc,0x02,0x20,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x8f,0xe1,0xca,0xb5,0xee,0xfd,0xb2,0x14,0x06,0x1d,0xce,0x3b,0x22,0x78,0x9f,0x1d,0x6f, + 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x31,0x02,0x0d,0x06,0x25,0x22,0xbb,0xd3,0xec,0xbe,0x7c,0x39,0xe9,0x3e,0x7c,0x26,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57, + 0x30,0x45,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x40,0xc1,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x16,0x02,0x09,0x00,0x9c,0x44,0xfe,0xbf,0x31,0xc3,0x59,0x4d,0x02,0x09,0x00,0x83,0x9e,0xd2,0x82,0x47,0xc2,0xb0,0x6b, + 0x30,0x1e,0x02,0x0d,0x09,0xdf,0x8b,0x68,0x24,0x30,0xbe,0xef,0x6f,0x5f,0xd7,0xc7,0xcf,0x02,0x0d,0x0f,0xd0,0xa6,0x2e,0x13,0x77,0x8f,0x42,0x22,0xa0,0xd6,0x1c,0x8a, + 0x30,0x26,0x02,0x11,0x00,0x8a,0x59,0x8e,0x56,0x3a,0x89,0xf5,0x26,0xc3,0x2e,0xbe,0xc8,0xde,0x26,0x36,0x7a,0x02,0x11,0x00,0x84,0xf6,0x33,0xe2,0x04,0x26,0x30,0xe9,0x9d,0xd0,0xf1,0xe1,0x6f,0x7a,0x04,0xbf, + 0x30,0x2e,0x02,0x15,0x00,0xaa,0x6e,0xeb,0x58,0x23,0xf7,0xfa,0x31,0xb4,0x66,0xbb,0x47,0x37,0x97,0xf0,0xd0,0x31,0x4c,0x0b,0xdf,0x02,0x15,0x00,0xe2,0x97,0x7c,0x47,0x9e,0x6d,0x25,0x70,0x3c,0xeb,0xbc,0x6b,0xd5,0x61,0x93,0x8c,0xc9,0xd1,0xbf,0xb9, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x01, + 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x00, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x41,0x9d,0x98,0x1c,0x51,0x5a,0xf8,0xcc,0x82,0x54,0x5a,0xac,0x0c,0x85,0xe9,0xe3,0x08,0xfb,0xb2,0xea,0xb6,0xac,0xd7,0xed,0x49,0x7e,0x0b,0x41,0x45,0xa1,0x8f,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x1b,0x21,0x71,0x7a,0xd7,0x1d,0x23,0xbb,0xac,0x60,0xa9,0xad,0x0b,0xaf,0x75,0xb0,0x63,0xc9,0xfd,0xf5,0x2a,0x00,0xeb,0xf9,0x9d,0x02,0x21,0x72,0x91,0x09,0x93,0xc9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x2f,0x58,0x8f,0x66,0x01,0x8f,0x3d,0xd1,0x4d,0xb3,0xe2,0x8e,0x77,0x99,0x64,0x87,0xe3,0x24,0x86,0xb5,0x21,0xed,0x8e,0x5a,0x20,0xf0,0x65,0x91,0x95,0x17,0x77,0xe9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x09,0x1a,0x08,0x87,0x0f,0xf4,0xda,0xf9,0x12,0x3b,0x30,0xc2,0x0e,0x8c,0x4f,0xc8,0x50,0x57,0x58,0xdc,0xf4,0x07,0x4f,0xca,0xff,0x21,0x70,0xc9,0xbf,0xcf,0x74,0xf4, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7c,0x37,0x0d,0xc0,0xce,0x8c,0x59,0xa8,0xb2,0x73,0xcb,0xa4,0x4a,0x7c,0x11,0x91,0xfc,0x31,0x86,0xdc,0x03,0xca,0xb9,0x6b,0x05,0x67,0x31,0x2d,0xf0,0xd0,0xb2,0x50, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x70,0xb5,0x9a,0x7d,0x1e,0xe7,0x7a,0x2f,0x9e,0x04,0x91,0xc2,0xa7,0xcf,0xcd,0x0e,0xd0,0x4d,0xf4,0xa3,0x51,0x92,0xf6,0x13,0x2d,0xcc,0x66,0x8c,0x79,0xa6,0x16,0x0e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x27,0x36,0xd7,0x6e,0x41,0x22,0x46,0xe0,0x97,0x14,0x8e,0x2b,0xf6,0x29,0x15,0x61,0x4e,0xb7,0xc4,0x28,0x91,0x3a,0x58,0xeb,0x5e,0x9c,0xd4,0x67,0x4a,0x94,0x23,0xde, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4a,0x1e,0x12,0x83,0x1f,0xbe,0x93,0x62,0x7b,0x02,0xd6,0xe7,0xf2,0x4b,0xcc,0xdd,0x6e,0xf4,0xb2,0xd0,0xf4,0x67,0x39,0xea,0xf3,0xb1,0xea,0xf0,0xca,0x11,0x77,0x70, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x06,0xc7,0x78,0xd4,0xdf,0xff,0x7d,0xee,0x06,0xed,0x88,0xbc,0x4e,0x0e,0xd3,0x4f,0xc5,0x53,0xaa,0xd6,0x7c,0xaf,0x79,0x6f,0x2a,0x1c,0x64,0x87,0xc1,0xb2,0xe8,0x77, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4d,0xe4,0x59,0xef,0x91,0x59,0xaf,0xa0,0x57,0xfe,0xb3,0xec,0x40,0xfe,0xf0,0x1c,0x45,0xb8,0x09,0xf4,0xab,0x29,0x6e,0xa4,0x8c,0x20,0x6d,0x42,0x49,0xa2,0xb4,0x51, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x74,0x5d,0x29,0x49,0x78,0x00,0x73,0x02,0x03,0x35,0x02,0xe1,0xac,0xc4,0x8b,0x63,0xae,0x65,0x00,0xbe,0x43,0xad,0xbe,0xa1,0xb2,0x58,0xd6,0xb4,0x23,0xdb,0xb4,0x16, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7b,0x2a,0x78,0x5e,0x38,0x96,0xf5,0x9b,0x2d,0x69,0xda,0x57,0x64,0x8e,0x80,0xad,0x3c,0x13,0x3a,0x75,0x0a,0x28,0x47,0xfd,0x20,0x98,0xcc,0xd9,0x02,0x04,0x2b,0x6c, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x71,0xae,0x94,0xa7,0x2c,0xa8,0x96,0x87,0x5e,0x7a,0xa4,0xa4,0xc3,0xd2,0x9a,0xfd,0xb4,0xb3,0x5b,0x69,0x96,0x27,0x3e,0x63,0xc4,0x7a,0xc5,0x19,0x25,0x6c,0x5e,0xb1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x0f,0xa5,0x27,0xfa,0x73,0x43,0xc0,0xbc,0x9e,0xc3,0x5a,0x62,0x78,0xbf,0xbf,0xf4,0xd8,0x33,0x01,0xb1,0x54,0xfc,0x4b,0xd1,0x4a,0xee,0x7e,0xb9,0x34,0x45,0xb5,0xf9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x65,0x39,0xc0,0xad,0xad,0xd0,0x52,0x5f,0xf4,0x26,0x22,0x16,0x4c,0xe9,0x31,0x43,0x48,0xbd,0x08,0x63,0xb4,0xc8,0x0e,0x93,0x6b,0x23,0xca,0x04,0x14,0x26,0x46,0x71, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa1, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x1c,0x94,0x0f,0x31,0x3f,0x92,0x64,0x7b,0xe2,0x57,0xec,0xcd,0x7e,0xd0,0x8b,0x0b,0xae,0xf3,0xf0,0x47,0x8f,0x25,0x87,0x1b,0x53,0x63,0x53,0x02,0xc5,0xf6,0x31,0x4a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x15,0xd9,0x4a,0x85,0x07,0x7b,0x49,0x3f,0x91,0xcb,0x71,0x01,0xec,0x63,0xe1,0xb0,0x1b,0xe5,0x8b,0x59,0x4e,0x85,0x5f,0x45,0x05,0x0a,0x8c,0x14,0x06,0x2d,0x68,0x9b, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x1d,0x27,0xa7,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9d,0x9e,0xf3,0xb9,0xfb,0x58,0x38,0x54,0x18,0xd9,0xc9,0x82,0x10,0x50,0x77,0xd1,0xb7, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2d,0x85,0x89,0x6b,0x3e,0xb9,0xdb,0xb5,0xa5,0x2f,0x42,0xf9,0xc9,0x26,0x1e,0xd3,0xfc,0x46,0x64,0x4e,0xc6,0x5f,0x06,0xad,0xe3,0xfd,0x78,0xf2,0x57,0xe4,0x34,0x32, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x0b,0x12,0xd6,0x7d,0x73,0xb7,0x6b,0x4a,0x5e,0x85,0xf3,0x92,0x4c,0x3d,0xa7,0xf8,0x8c,0xc8,0x9d,0x8c,0xbe,0x0d,0x5b,0xc7,0xfa,0xf1,0xe4,0xaf,0xc8,0x68,0x64, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x09,0xe6,0x0e,0x68,0xb9,0x0d,0x0b,0x5e,0x6c,0x5d,0xdd,0xd0,0xcb,0x69,0x4d,0x87,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3d,0x7f,0x48,0x7c,0x07,0xbf,0xc5,0xf3,0x08,0x46,0x93,0x8a,0x3d,0xce,0xf6,0x96,0x44,0x47,0x07,0xcf,0x96,0x77,0x25,0x4a,0x92,0xb0,0x6c,0x63,0xab,0x86,0x7d,0x22, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6c,0x76,0x48,0xfc,0x0f,0xbf,0x8a,0x06,0xad,0xb8,0xb8,0x39,0xf9,0x7b,0x4f,0xf7,0xa8,0x00,0xf1,0x1b,0x1e,0x37,0xc5,0x93,0xb2,0x61,0x39,0x45,0x99,0x79,0x2b,0xa4, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x1c,0x9c,0x5d,0x79,0x0d,0xc0,0x9c,0xdd,0x3d,0xfa,0xbb,0x62,0xcd,0xf4,0x53,0xe6,0x97,0x47,0xa7,0xe3,0xd7,0xaa,0x1a,0x71,0x41,0x89,0xef,0x53,0x17,0x1a,0x99, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x29,0x79,0x8c,0x5c,0x45,0xbd,0xf5,0x8b,0x4a,0x7b,0x2f,0xdc,0x2c,0x46,0xab,0x4a,0xf1,0x21,0x8c,0x7e,0xeb,0x9f,0x0f,0x27,0xa8,0x8f,0x12,0x67,0x67,0x4d,0xe3,0xb0, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x0b,0x70,0xf2,0x2c,0xa2,0xbb,0x3c,0xef,0xad,0xca,0x1a,0x57,0x11,0xfa,0x3a,0x59,0xf4,0x69,0x53,0x85,0xeb,0x5a,0xed,0xf3,0x49,0x5d,0x0b,0x6d,0x00,0xf8,0xfd,0x85, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x22,0x52,0xd6,0x85,0xe8,0x31,0xb6,0xcf,0x09,0x5e,0x4f,0x05,0x35,0xee,0xaf,0x0d,0xdd,0x3b,0xfa,0x91,0xc2,0x10,0xc9,0xd9,0xdc,0x17,0x22,0x47,0x02,0xea,0xf8,0x8f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x75,0x13,0x5a,0xbd,0x7c,0x42,0x5b,0x60,0x37,0x1a,0x47,0x7f,0x09,0xce,0x0f,0x27,0x4f,0x64,0xa8,0xc6,0xb0,0x61,0xa0,0x7b,0x5d,0x63,0xe9,0x3c,0x65,0x04,0x6c,0x53, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x88,0x83,0x77,0xac,0x6c,0x71,0xac,0x9d,0xec,0x3f,0xdb,0x9b,0x56,0xc9,0xfe,0xaf,0x0c,0xfa,0xca,0x9f,0x82,0x7f,0xc5,0xeb,0x65,0xfc,0x3e,0xac,0x81,0x12,0x10, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x30,0xbb,0xb7,0x94,0xdb,0x58,0x83,0x63,0xb4,0x06,0x79,0xf6,0xc1,0x82,0xa5,0x0d,0x3c,0xe9,0x67,0x9a,0xcd,0xd3,0xff,0xbe,0x36,0xd7,0x81,0x3d,0xac,0xbd,0xc8,0x18, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2c,0x37,0xfd,0x99,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc7,0xce,0xe7,0x45,0x11,0x0c,0xb4,0x5a,0xb5,0x58,0xed,0x7c,0x90,0xc1,0x5a,0x2f, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x7f,0xd9,0x95,0x62,0x2c,0x4f,0xb7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x88,0x3f,0xfa,0xb5,0xb3,0x26,0x52,0xcc,0xdc,0xaa,0x29,0x0f,0xcc,0xb9,0x7d, + 0x30,0x43,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x1f,0x4c,0xd5,0x3b,0xa7,0x60,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9e,0x5c,0xf1,0x43,0xe2,0x53,0x96,0x26,0x19,0x0a,0x3a,0xb0,0x9c,0xce,0x47, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x92,0x8a,0x8f,0x1c,0x7a,0xc7,0xbe,0xc1,0x80,0x8b,0x9f,0x61,0xc0,0x1e,0xc3,0x27, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x44,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x03,0xb8,0x78,0x53,0xfd,0x3b,0x7d,0x3f,0x8e,0x17,0x51,0x25,0xb4,0x38,0x2f,0x25,0xed, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x27,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x05,0x56,0x02,0x98,0xd1,0xf2,0xf0,0x8d,0xc4,0x19,0xac,0x27,0x3a,0x5b,0x54,0xd9, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x48,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x31,0xc8,0x3a,0xe8,0x2e,0xbe,0x08,0x98,0x77,0x6b,0x4c,0x69,0xd1,0x1f,0x88,0xde, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x06,0xdd,0x3a,0x19,0xb8,0xd5,0xfb,0x87,0x52,0x35,0x96,0x3c,0x59,0x3b,0xd2,0xd3, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x15, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe, + 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x18,0x5d,0xdb,0xca,0x6d,0xac,0x41,0xb1,0xda,0x03,0x3c,0xfb,0x60,0xc1,0x52,0x86,0x9e,0x74,0xb3,0xcd,0x66,0xe9,0xff,0xdf,0x1b,0x6b,0xc0,0x9e,0xd6,0x5e,0xe4,0x0c, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9, + 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,0x02,0x20,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x32,0xf2,0x22,0xf8,0xfa,0xef,0xdb,0x53,0x3f,0x26,0x5d,0x46,0x1c,0x29,0xa4,0x73,0x73, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5, + 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52, + 0x30,0x45,0x02,0x21,0x00,0xf8,0x0a,0xe4,0xf9,0x6c,0xdb,0xc9,0xd8,0x53,0xf8,0x3d,0x47,0xaa,0xe2,0x25,0xbf,0x40,0x7d,0x51,0xc5,0x6b,0x77,0x76,0xcd,0x67,0xd0,0xdc,0x19,0x5d,0x99,0xa9,0xdc,0x02,0x20,0x4c,0xfc,0x1d,0x94,0x1e,0x08,0xcb,0x9a,0xce,0xad,0xde,0x0f,0x4c,0xce,0xad,0x76,0xb3,0x0d,0x33,0x2f,0xc4,0x42,0x11,0x5d,0x50,0xe6,0x73,0xe2,0x86,0x86,0xb7,0x0b, + 0x30,0x44,0x02,0x20,0x10,0x9c,0xd8,0xae,0x03,0x74,0x35,0x89,0x84,0xa8,0x24,0x9c,0x0a,0x84,0x36,0x28,0xf2,0x83,0x5f,0xfa,0xd1,0xdf,0x1a,0x9a,0x69,0xaa,0x2f,0xe7,0x23,0x55,0x54,0x5c,0x02,0x20,0x53,0x90,0xff,0x25,0x0a,0xc4,0x27,0x4e,0x1c,0xb2,0x5c,0xd6,0xca,0x64,0x91,0xf6,0xb9,0x12,0x81,0xe3,0x2f,0x5b,0x26,0x4d,0x87,0x97,0x7a,0xed,0x4a,0x94,0xe7,0x7b, + 0x30,0x45,0x02,0x21,0x00,0xd0,0x35,0xee,0x1f,0x17,0xfd,0xb0,0xb2,0x68,0x1b,0x16,0x3e,0x33,0xc3,0x59,0x93,0x26,0x59,0x99,0x0a,0xf7,0x7d,0xca,0x63,0x20,0x12,0xb3,0x0b,0x27,0xa0,0x57,0xb3,0x02,0x20,0x19,0x39,0xd9,0xf3,0xb2,0x85,0x8b,0xc1,0x3e,0x34,0x74,0xcb,0x50,0xe6,0xa8,0x2b,0xe4,0x4f,0xaa,0x71,0x94,0x0f,0x87,0x6c,0x1c,0xba,0x4c,0x3e,0x98,0x92,0x02,0xb6, + 0x30,0x44,0x02,0x20,0x4f,0x05,0x3f,0x56,0x3a,0xd3,0x4b,0x74,0xfd,0x8c,0x99,0x34,0xce,0x59,0xe7,0x9c,0x2e,0xb8,0xe6,0xec,0xa0,0xfe,0xf5,0xb3,0x23,0xca,0x67,0xd5,0xac,0x7e,0xd2,0x38,0x02,0x20,0x4d,0x4b,0x05,0xda,0xa0,0x71,0x9e,0x77,0x3d,0x86,0x17,0xdc,0xe5,0x63,0x1c,0x5f,0xd6,0xf5,0x9c,0x9b,0xdc,0x74,0x8e,0x4b,0x55,0xc9,0x70,0x04,0x0a,0xf0,0x1b,0xe5, + 0x30,0x44,0x02,0x20,0x6d,0x6a,0x4f,0x55,0x6c,0xcc,0xe1,0x54,0xe7,0xfb,0x9f,0x19,0xe7,0x6c,0x3d,0xec,0xa1,0x3d,0x59,0xcc,0x2a,0xeb,0x4e,0xca,0xd9,0x68,0xaa,0xb2,0xde,0xd4,0x59,0x65,0x02,0x20,0x53,0xb9,0xfa,0x74,0x80,0x3e,0xde,0x0f,0xc4,0x44,0x1b,0xf6,0x83,0xd5,0x6c,0x56,0x4d,0x3e,0x27,0x4e,0x09,0xcc,0xf4,0x73,0x90,0xba,0xdd,0x14,0x71,0xc0,0x5f,0xb7, + 0x30,0x44,0x02,0x21,0x00,0xaa,0xd5,0x03,0xde,0x9b,0x9f,0xd6,0x6b,0x94,0x8e,0x9a,0xcf,0x59,0x6f,0x0a,0x0e,0x65,0xe7,0x00,0xb2,0x8b,0x26,0xec,0x56,0xe6,0xe4,0x5e,0x84,0x64,0x89,0xb3,0xc4,0x02,0x1f,0x0d,0xdc,0x3a,0x2f,0x89,0xab,0xb8,0x17,0xbb,0x85,0xc0,0x62,0xce,0x02,0xf8,0x23,0xc6,0x3f,0xc2,0x6b,0x26,0x9e,0x0b,0xc9,0xb8,0x4d,0x81,0xa5,0xaa,0x12,0x3d, + 0x30,0x45,0x02,0x21,0x00,0x91,0x82,0xce,0xbd,0x3b,0xb8,0xab,0x57,0x2e,0x16,0x71,0x74,0x39,0x72,0x09,0xef,0x4b,0x1d,0x43,0x9a,0xf3,0xb2,0x00,0xcd,0xf0,0x03,0x62,0x00,0x89,0xe4,0x32,0x25,0x02,0x20,0x54,0x47,0x7c,0x98,0x2e,0xa0,0x19,0xd2,0xe1,0x00,0x04,0x97,0xfc,0x25,0xfc,0xee,0x1b,0xcc,0xae,0x55,0xf2,0xac,0x27,0x53,0x0a,0xe5,0x3b,0x29,0xc4,0xb3,0x56,0xa4, + 0x30,0x44,0x02,0x20,0x38,0x54,0xa3,0x99,0x8a,0xeb,0xdf,0x2d,0xbc,0x28,0xad,0xac,0x41,0x81,0x46,0x2c,0xca,0xc7,0x87,0x39,0x07,0xab,0x7f,0x21,0x2c,0x42,0xdb,0x0e,0x69,0xb5,0x6e,0xd8,0x02,0x20,0x3e,0xd3,0xf6,0xb8,0xa3,0x88,0xd0,0x2f,0x3e,0x4d,0xf9,0xf2,0xae,0x9c,0x1b,0xd2,0xc3,0x91,0x6a,0x68,0x64,0x60,0xdf,0xfc,0xd4,0x29,0x09,0xcd,0x7f,0x82,0x05,0x8e, + 0x30,0x45,0x02,0x21,0x00,0xe9,0x4d,0xbd,0xc3,0x87,0x95,0xfe,0x5c,0x90,0x4d,0x8f,0x16,0xd9,0x69,0xd3,0xb5,0x87,0xf0,0xa2,0x5d,0x2d,0xe9,0x0b,0x6d,0x8c,0x5c,0x53,0xff,0x88,0x7e,0x36,0x07,0x02,0x20,0x7a,0x94,0x73,0x69,0xc1,0x64,0x97,0x25,0x21,0xbb,0x8a,0xf4,0x06,0x81,0x3b,0x2d,0x9f,0x94,0xd2,0xae,0xaa,0x53,0xd4,0xc2,0x15,0xaa,0xa0,0xa2,0x57,0x8a,0x2c,0x5d, + 0x30,0x44,0x02,0x20,0x49,0xfc,0x10,0x2a,0x08,0xca,0x47,0xb6,0x0e,0x08,0x58,0xcd,0x02,0x84,0xd2,0x2c,0xdd,0xd7,0x23,0x3f,0x94,0xaa,0xff,0xbb,0x2d,0xb1,0xdd,0x2c,0xf0,0x84,0x25,0xe1,0x02,0x20,0x5b,0x16,0xfc,0xa5,0xa1,0x2c,0xdb,0x39,0x70,0x16,0x97,0xad,0x8e,0x39,0xff,0xd6,0xbd,0xec,0x00,0x24,0x29,0x8a,0xfa,0xa2,0x32,0x6a,0xea,0x09,0x20,0x0b,0x14,0xd6, + 0x30,0x44,0x02,0x20,0x41,0xef,0xa7,0xd3,0xf0,0x5a,0x00,0x10,0x67,0x5f,0xcb,0x91,0x8a,0x45,0xc6,0x93,0xda,0x4b,0x34,0x8d,0xf2,0x1a,0x59,0xd6,0xf9,0xcd,0x73,0xe0,0xd8,0x31,0xd6,0x7a,0x02,0x20,0x44,0x54,0xad,0xa6,0x93,0xe5,0xe2,0x6b,0x7b,0xd6,0x93,0x23,0x6d,0x34,0x0f,0x80,0x54,0x5c,0x83,0x45,0x77,0xb6,0xf7,0x3d,0x37,0x8c,0x7b,0xcc,0x53,0x42,0x44,0xda, + 0x30,0x45,0x02,0x21,0x00,0xb6,0x15,0x69,0x8c,0x35,0x8b,0x35,0x92,0x0d,0xd8,0x83,0xec,0xa6,0x25,0xa6,0xc5,0xf7,0x56,0x39,0x70,0xcd,0xfc,0x37,0x8f,0x8f,0xe0,0xce,0xe1,0x70,0x92,0x14,0x4c,0x02,0x20,0x25,0xf4,0x7b,0x32,0x6b,0x5b,0xe1,0xfb,0x61,0x0b,0x88,0x51,0x53,0xea,0x84,0xd4,0x1e,0xb4,0x71,0x6b,0xe6,0x6a,0x99,0x4e,0x87,0x79,0x98,0x9d,0xf1,0xc8,0x63,0xd4, + 0x30,0x45,0x02,0x21,0x00,0x87,0xcf,0x8c,0x0e,0xb8,0x2d,0x44,0xf6,0x9c,0x60,0xa2,0xff,0x54,0x57,0xd3,0xaa,0xa3,0x22,0xe7,0xec,0x61,0xae,0x5a,0xec,0xfd,0x67,0x8a,0xe1,0xc1,0x93,0x2b,0x0e,0x02,0x20,0x3a,0xdd,0x3b,0x11,0x58,0x15,0x04,0x7d,0x6e,0xb3,0x40,0xa3,0xe0,0x08,0x98,0x9e,0xaa,0x0f,0x87,0x08,0xd1,0x79,0x48,0x14,0x72,0x90,0x94,0xd0,0x8d,0x24,0x60,0xd3, + 0x30,0x44,0x02,0x20,0x62,0xf4,0x8e,0xf7,0x1a,0xce,0x27,0xbf,0x5a,0x01,0x83,0x4d,0xe1,0xf7,0xe3,0xf9,0x48,0xb9,0xdc,0xe1,0xca,0x1e,0x91,0x1d,0x5e,0x13,0xd3,0xb1,0x04,0x47,0x1d,0x82,0x02,0x20,0x5e,0xa8,0xf3,0x3f,0x0c,0x77,0x89,0x72,0xc4,0x58,0x20,0x80,0xde,0xda,0x9b,0x34,0x18,0x57,0xdd,0x64,0x51,0x4f,0x08,0x49,0xa0,0x5f,0x69,0x64,0xc2,0xe3,0x40,0x22, + 0x30,0x45,0x02,0x21,0x00,0xf6,0xb0,0xe2,0xf6,0xfe,0x02,0x0c,0xf7,0xc0,0xc2,0x01,0x37,0x43,0x43,0x44,0xed,0x7a,0xdd,0x6c,0x4b,0xe5,0x18,0x61,0xe2,0xd1,0x4c,0xbd,0xa4,0x72,0xa6,0xff,0xb4,0x02,0x20,0x64,0x16,0xc8,0xdd,0x3e,0x5c,0x52,0x82,0xb3,0x06,0xe8,0xdc,0x8f,0xf3,0x4a,0xb6,0x4c,0xc9,0x95,0x49,0x23,0x2d,0x67,0x8d,0x71,0x44,0x02,0xeb,0x6c,0xa7,0xaa,0x0f, + 0x30,0x45,0x02,0x21,0x00,0xdb,0x09,0xd8,0x46,0x0f,0x05,0xef,0xf2,0x3b,0xc7,0xe4,0x36,0xb6,0x7d,0xa5,0x63,0xfa,0x4b,0x4e,0xdb,0x58,0xac,0x24,0xce,0x20,0x1f,0xa8,0xa3,0x58,0x12,0x50,0x57,0x02,0x20,0x46,0xda,0x11,0x67,0x54,0x60,0x29,0x40,0xc8,0x99,0x9c,0x8d,0x66,0x5f,0x78,0x6c,0x50,0xf5,0x77,0x2c,0x0a,0x3c,0xdb,0xda,0x07,0x5e,0x77,0xea,0xbc,0x64,0xdf,0x16, + 0x30,0x44,0x02,0x20,0x59,0x2c,0x41,0xe1,0x65,0x17,0xf1,0x2f,0xca,0xbd,0x98,0x26,0x76,0x74,0xf9,0x74,0xb5,0x88,0xe9,0xf3,0x5d,0x35,0x40,0x6c,0x1a,0x7b,0xb2,0xed,0x1d,0x19,0xb7,0xb8,0x02,0x20,0x3e,0x65,0xa0,0x6b,0xd9,0xf8,0x3c,0xaa,0xeb,0x7b,0x00,0xf2,0x36,0x8d,0x7e,0x0d,0xec,0xe6,0xb1,0x22,0x21,0x26,0x9a,0x9b,0x5b,0x76,0x51,0x98,0xf8,0x40,0xa3,0xa1, + 0x30,0x45,0x02,0x21,0x00,0xbe,0x0d,0x70,0x88,0x7d,0x5e,0x40,0x82,0x1a,0x61,0xb6,0x80,0x47,0xde,0x4e,0xa0,0x3d,0xeb,0xfd,0xf5,0x1c,0xdf,0x4d,0x4b,0x19,0x55,0x58,0xb9,0x59,0xa0,0x32,0xb2,0x02,0x20,0x7d,0x99,0x4b,0x2d,0x8f,0x1d,0xbb,0xeb,0x13,0x53,0x4e,0xb3,0xf6,0xe5,0xdc,0xcd,0x85,0xf5,0xc4,0x13,0x3c,0x27,0xd9,0xe6,0x42,0x71,0xb1,0x82,0x6c,0xe1,0xf6,0x7d, + 0x30,0x45,0x02,0x21,0x00,0xfa,0xe9,0x2d,0xfc,0xb2,0xee,0x39,0x2d,0x27,0x0a,0xf3,0xa5,0x73,0x9f,0xaa,0x26,0xd4,0xf9,0x7b,0xfd,0x39,0xed,0x3c,0xbe,0xe4,0xd2,0x9e,0x26,0xaf,0x3b,0x20,0x6a,0x02,0x20,0x6c,0x9b,0xa3,0x7f,0x9f,0xaa,0x6a,0x1f,0xd3,0xf6,0x5f,0x23,0xb4,0xe8,0x53,0xd4,0x69,0x2a,0x72,0x74,0x24,0x0a,0x12,0xdb,0x7b,0xa3,0x88,0x48,0x30,0x63,0x0d,0x16, + 0x30,0x44,0x02,0x20,0x17,0x6a,0x25,0x57,0x56,0x6f,0xfa,0x51,0x8b,0x11,0x22,0x66,0x94,0xeb,0x98,0x02,0xed,0x20,0x98,0xbf,0xe2,0x78,0xe5,0x57,0x0f,0xe1,0xd5,0xd7,0xaf,0x18,0xa9,0x43,0x02,0x20,0x12,0x91,0xdf,0x6a,0x0e,0xd5,0xfc,0x0d,0x15,0x09,0x8e,0x70,0xbc,0xf1,0x3a,0x00,0x92,0x84,0xdf,0xd0,0x68,0x9d,0x3b,0xb4,0xbe,0x6c,0xee,0xb9,0xbe,0x14,0x87,0xc4, + 0x30,0x44,0x02,0x20,0x60,0xbe,0x20,0xc3,0xdb,0xc1,0x62,0xdd,0x34,0xd2,0x67,0x80,0x62,0x1c,0x10,0x4b,0xbe,0x5d,0xac,0xe6,0x30,0x17,0x1b,0x2d,0xae,0xf0,0xd8,0x26,0x40,0x9e,0xe5,0xc2,0x02,0x20,0x42,0x7f,0x7e,0x4d,0x88,0x9d,0x54,0x91,0x70,0xbd,0xa6,0xa9,0x40,0x9f,0xb1,0xcb,0x8b,0x0e,0x76,0x3d,0x13,0xee,0xa7,0xbd,0x97,0xf6,0x4c,0xf4,0x1d,0xc6,0xe4,0x97, + 0x30,0x45,0x02,0x21,0x00,0xed,0xf0,0x3c,0xf6,0x3f,0x65,0x88,0x83,0x28,0x9a,0x1a,0x59,0x3d,0x10,0x07,0x89,0x5b,0x9f,0x23,0x6d,0x27,0xc9,0xc1,0xf1,0x31,0x30,0x89,0xaa,0xed,0x6b,0x16,0xae,0x02,0x20,0x1a,0x4d,0xd6,0xfc,0x08,0x14,0xdc,0x52,0x3d,0x1f,0xef,0xa8,0x1c,0x64,0xfb,0xf5,0xe6,0x18,0xe6,0x51,0xe7,0x09,0x6f,0xcc,0xad,0xbb,0x94,0xcd,0x48,0xe5,0xe0,0xcd}; + +static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = { + /* tcId: 1. Signature malleability */ + {0, 0, 6, 0, 72, 0 }, + /* tcId: 2. valid */ + {0, 0, 6, 72, 71, 1 }, + /* tcId: 3. length of sequence [r, s] uses long form encoding */ + {0, 0, 6, 143, 72, 0 }, + /* tcId: 4. length of sequence [r, s] contains a leading 0 */ + {0, 0, 6, 215, 73, 0 }, + /* tcId: 5. length of sequence [r, s] uses 70 instead of 69 */ + {0, 0, 6, 288, 71, 0 }, + /* tcId: 6. length of sequence [r, s] uses 68 instead of 69 */ + {0, 0, 6, 359, 71, 0 }, + /* tcId: 7. uint32 overflow in length of sequence [r, s] */ + {0, 0, 6, 430, 76, 0 }, + /* tcId: 8. uint64 overflow in length of sequence [r, s] */ + {0, 0, 6, 506, 80, 0 }, + /* tcId: 9. length of sequence [r, s] = 2**31 - 1 */ + {0, 0, 6, 586, 75, 0 }, + /* tcId: 10. length of sequence [r, s] = 2**31 */ + {0, 0, 6, 661, 75, 0 }, + /* tcId: 11. length of sequence [r, s] = 2**32 - 1 */ + {0, 0, 6, 736, 75, 0 }, + /* tcId: 12. length of sequence [r, s] = 2**40 - 1 */ + {0, 0, 6, 811, 76, 0 }, + /* tcId: 13. length of sequence [r, s] = 2**64 - 1 */ + {0, 0, 6, 887, 79, 0 }, + /* tcId: 14. incorrect length of sequence [r, s] */ + {0, 0, 6, 966, 71, 0 }, + /* tcId: 15. replaced sequence [r, s] by an indefinite length tag without termination */ + {0, 0, 6, 1037, 71, 0 }, + /* tcId: 16. removing sequence [r, s] */ + {0, 0, 6, 1108, 0, 0 }, + /* tcId: 17. lonely sequence tag */ + {0, 0, 6, 1108, 1, 0 }, + /* tcId: 18. appending 0's to sequence [r, s] */ + {0, 0, 6, 1109, 73, 0 }, + /* tcId: 19. prepending 0's to sequence [r, s] */ + {0, 0, 6, 1182, 73, 0 }, + /* tcId: 20. appending unused 0's to sequence [r, s] */ + {0, 0, 6, 1255, 73, 0 }, + /* tcId: 21. appending null value to sequence [r, s] */ + {0, 0, 6, 1328, 73, 0 }, + /* tcId: 22. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1401, 76, 0 }, + /* tcId: 23. prepending garbage to sequence [r, s] */ + {0, 0, 6, 1477, 75, 0 }, + /* tcId: 24. appending garbage to sequence [r, s] */ + {0, 0, 6, 1552, 79, 0 }, + /* tcId: 25. including undefined tags */ + {0, 0, 6, 1631, 79, 0 }, + /* tcId: 26. including undefined tags */ + {0, 0, 6, 1710, 79, 0 }, + /* tcId: 27. including undefined tags */ + {0, 0, 6, 1789, 79, 0 }, + /* tcId: 28. truncated length of sequence [r, s] */ + {0, 0, 6, 1868, 2, 0 }, + /* tcId: 29. including undefined tags to sequence [r, s] */ + {0, 0, 6, 1870, 77, 0 }, + /* tcId: 30. using composition with indefinite length for sequence [r, s] */ + {0, 0, 6, 1947, 75, 0 }, + /* tcId: 31. using composition with wrong tag for sequence [r, s] */ + {0, 0, 6, 2022, 75, 0 }, + /* tcId: 32. Replacing sequence [r, s] with NULL */ + {0, 0, 6, 2097, 2, 0 }, + /* tcId: 33. changing tag value of sequence [r, s] */ + {0, 0, 6, 2099, 71, 0 }, + /* tcId: 34. changing tag value of sequence [r, s] */ + {0, 0, 6, 2170, 71, 0 }, + /* tcId: 35. changing tag value of sequence [r, s] */ + {0, 0, 6, 2241, 71, 0 }, + /* tcId: 36. changing tag value of sequence [r, s] */ + {0, 0, 6, 2312, 71, 0 }, + /* tcId: 37. changing tag value of sequence [r, s] */ + {0, 0, 6, 2383, 71, 0 }, + /* tcId: 38. dropping value of sequence [r, s] */ + {0, 0, 6, 2454, 2, 0 }, + /* tcId: 39. using composition for sequence [r, s] */ + {0, 0, 6, 2456, 75, 0 }, + /* tcId: 40. truncated sequence [r, s] */ + {0, 0, 6, 2531, 70, 0 }, + /* tcId: 41. truncated sequence [r, s] */ + {0, 0, 6, 2601, 70, 0 }, + /* tcId: 42. sequence [r, s] of size 4166 to check for overflows */ + {0, 0, 6, 2671, 4170, 0 }, + /* tcId: 43. indefinite length */ + {0, 0, 6, 6841, 73, 0 }, + /* tcId: 44. indefinite length with truncated delimiter */ + {0, 0, 6, 6914, 72, 0 }, + /* tcId: 45. indefinite length with additional element */ + {0, 0, 6, 6986, 75, 0 }, + /* tcId: 46. indefinite length with truncated element */ + {0, 0, 6, 7061, 77, 0 }, + /* tcId: 47. indefinite length with garbage */ + {0, 0, 6, 7138, 77, 0 }, + /* tcId: 48. indefinite length with nonempty EOC */ + {0, 0, 6, 7215, 75, 0 }, + /* tcId: 49. prepend empty sequence */ + {0, 0, 6, 7290, 73, 0 }, + /* tcId: 50. append empty sequence */ + {0, 0, 6, 7363, 73, 0 }, + /* tcId: 51. append zero */ + {0, 0, 6, 7436, 74, 0 }, + /* tcId: 52. append garbage with high tag number */ + {0, 0, 6, 7510, 74, 0 }, + /* tcId: 53. append null with explicit tag */ + {0, 0, 6, 7584, 75, 0 }, + /* tcId: 54. append null with implicit tag */ + {0, 0, 6, 7659, 73, 0 }, + /* tcId: 55. sequence of sequence */ + {0, 0, 6, 7732, 73, 0 }, + /* tcId: 56. truncated sequence: removed last 1 elements */ + {0, 0, 6, 7805, 37, 0 }, + /* tcId: 57. repeating element in sequence */ + {0, 0, 6, 7842, 105, 0 }, + /* tcId: 58. flipped bit 0 in r */ + {0, 0, 6, 7947, 69, 0 }, + /* tcId: 59. flipped bit 32 in r */ + {0, 0, 6, 8016, 69, 0 }, + /* tcId: 60. flipped bit 48 in r */ + {0, 0, 6, 8085, 69, 0 }, + /* tcId: 61. flipped bit 64 in r */ + {0, 0, 6, 8154, 69, 0 }, + /* tcId: 62. length of r uses long form encoding */ + {0, 0, 6, 8223, 72, 0 }, + /* tcId: 63. length of r contains a leading 0 */ + {0, 0, 6, 8295, 73, 0 }, + /* tcId: 64. length of r uses 34 instead of 33 */ + {0, 0, 6, 8368, 71, 0 }, + /* tcId: 65. length of r uses 32 instead of 33 */ + {0, 0, 6, 8439, 71, 0 }, + /* tcId: 66. uint32 overflow in length of r */ + {0, 0, 6, 8510, 76, 0 }, + /* tcId: 67. uint64 overflow in length of r */ + {0, 0, 6, 8586, 80, 0 }, + /* tcId: 68. length of r = 2**31 - 1 */ + {0, 0, 6, 8666, 75, 0 }, + /* tcId: 69. length of r = 2**31 */ + {0, 0, 6, 8741, 75, 0 }, + /* tcId: 70. length of r = 2**32 - 1 */ + {0, 0, 6, 8816, 75, 0 }, + /* tcId: 71. length of r = 2**40 - 1 */ + {0, 0, 6, 8891, 76, 0 }, + /* tcId: 72. length of r = 2**64 - 1 */ + {0, 0, 6, 8967, 79, 0 }, + /* tcId: 73. incorrect length of r */ + {0, 0, 6, 9046, 71, 0 }, + /* tcId: 74. replaced r by an indefinite length tag without termination */ + {0, 0, 6, 9117, 71, 0 }, + /* tcId: 75. removing r */ + {0, 0, 6, 9188, 36, 0 }, + /* tcId: 76. lonely integer tag */ + {0, 0, 6, 9224, 37, 0 }, + /* tcId: 77. lonely integer tag */ + {0, 0, 6, 9261, 38, 0 }, + /* tcId: 78. appending 0's to r */ + {0, 0, 6, 9299, 73, 0 }, + /* tcId: 79. prepending 0's to r */ + {0, 0, 6, 9372, 73, 0 }, + /* tcId: 80. appending unused 0's to r */ + {0, 0, 6, 9445, 73, 0 }, + /* tcId: 81. appending null value to r */ + {0, 0, 6, 9518, 73, 0 }, + /* tcId: 82. prepending garbage to r */ + {0, 0, 6, 9591, 76, 0 }, + /* tcId: 83. prepending garbage to r */ + {0, 0, 6, 9667, 75, 0 }, + /* tcId: 84. appending garbage to r */ + {0, 0, 6, 9742, 79, 0 }, + /* tcId: 85. truncated length of r */ + {0, 0, 6, 9821, 38, 0 }, + /* tcId: 86. including undefined tags to r */ + {0, 0, 6, 9859, 77, 0 }, + /* tcId: 87. using composition with indefinite length for r */ + {0, 0, 6, 9936, 75, 0 }, + /* tcId: 88. using composition with wrong tag for r */ + {0, 0, 6, 10011, 75, 0 }, + /* tcId: 89. Replacing r with NULL */ + {0, 0, 6, 10086, 38, 0 }, + /* tcId: 90. changing tag value of r */ + {0, 0, 6, 10124, 71, 0 }, + /* tcId: 91. changing tag value of r */ + {0, 0, 6, 10195, 71, 0 }, + /* tcId: 92. changing tag value of r */ + {0, 0, 6, 10266, 71, 0 }, + /* tcId: 93. changing tag value of r */ + {0, 0, 6, 10337, 71, 0 }, + /* tcId: 94. changing tag value of r */ + {0, 0, 6, 10408, 71, 0 }, + /* tcId: 95. dropping value of r */ + {0, 0, 6, 10479, 38, 0 }, + /* tcId: 96. using composition for r */ + {0, 0, 6, 10517, 75, 0 }, + /* tcId: 97. modifying first byte of r */ + {0, 0, 6, 10592, 71, 0 }, + /* tcId: 98. modifying last byte of r */ + {0, 0, 6, 10663, 71, 0 }, + /* tcId: 99. truncated r */ + {0, 0, 6, 10734, 70, 0 }, + /* tcId: 100. truncated r */ + {0, 0, 6, 10804, 70, 0 }, + /* tcId: 101. r of size 4130 to check for overflows */ + {0, 0, 6, 10874, 4172, 0 }, + /* tcId: 102. leading ff in r */ + {0, 0, 6, 15046, 72, 0 }, + /* tcId: 103. replaced r by infinity */ + {0, 0, 6, 15118, 39, 0 }, + /* tcId: 104. replacing r with zero */ + {0, 0, 6, 15157, 39, 0 }, + /* tcId: 105. flipped bit 0 in s */ + {0, 0, 6, 15196, 69, 0 }, + /* tcId: 106. flipped bit 32 in s */ + {0, 0, 6, 15265, 69, 0 }, + /* tcId: 107. flipped bit 48 in s */ + {0, 0, 6, 15334, 69, 0 }, + /* tcId: 108. flipped bit 64 in s */ + {0, 0, 6, 15403, 69, 0 }, + /* tcId: 109. length of s uses long form encoding */ + {0, 0, 6, 15472, 72, 0 }, + /* tcId: 110. length of s contains a leading 0 */ + {0, 0, 6, 15544, 73, 0 }, + /* tcId: 111. length of s uses 33 instead of 32 */ + {0, 0, 6, 15617, 71, 0 }, + /* tcId: 112. length of s uses 31 instead of 32 */ + {0, 0, 6, 15688, 71, 0 }, + /* tcId: 113. uint32 overflow in length of s */ + {0, 0, 6, 15759, 76, 0 }, + /* tcId: 114. uint64 overflow in length of s */ + {0, 0, 6, 15835, 80, 0 }, + /* tcId: 115. length of s = 2**31 - 1 */ + {0, 0, 6, 15915, 75, 0 }, + /* tcId: 116. length of s = 2**31 */ + {0, 0, 6, 15990, 75, 0 }, + /* tcId: 117. length of s = 2**32 - 1 */ + {0, 0, 6, 16065, 75, 0 }, + /* tcId: 118. length of s = 2**40 - 1 */ + {0, 0, 6, 16140, 76, 0 }, + /* tcId: 119. length of s = 2**64 - 1 */ + {0, 0, 6, 16216, 79, 0 }, + /* tcId: 120. incorrect length of s */ + {0, 0, 6, 16295, 71, 0 }, + /* tcId: 121. replaced s by an indefinite length tag without termination */ + {0, 0, 6, 16366, 71, 0 }, + /* tcId: 122. appending 0's to s */ + {0, 0, 6, 16437, 73, 0 }, + /* tcId: 123. prepending 0's to s */ + {0, 0, 6, 16510, 73, 0 }, + /* tcId: 124. appending null value to s */ + {0, 0, 6, 16583, 73, 0 }, + /* tcId: 125. prepending garbage to s */ + {0, 0, 6, 16656, 76, 0 }, + /* tcId: 126. prepending garbage to s */ + {0, 0, 6, 16732, 75, 0 }, + /* tcId: 127. appending garbage to s */ + {0, 0, 6, 16807, 79, 0 }, + /* tcId: 128. truncated length of s */ + {0, 0, 6, 16886, 39, 0 }, + /* tcId: 129. including undefined tags to s */ + {0, 0, 6, 16925, 77, 0 }, + /* tcId: 130. using composition with indefinite length for s */ + {0, 0, 6, 17002, 75, 0 }, + /* tcId: 131. using composition with wrong tag for s */ + {0, 0, 6, 17077, 75, 0 }, + /* tcId: 132. Replacing s with NULL */ + {0, 0, 6, 17152, 39, 0 }, + /* tcId: 133. changing tag value of s */ + {0, 0, 6, 17191, 71, 0 }, + /* tcId: 134. changing tag value of s */ + {0, 0, 6, 17262, 71, 0 }, + /* tcId: 135. changing tag value of s */ + {0, 0, 6, 17333, 71, 0 }, + /* tcId: 136. changing tag value of s */ + {0, 0, 6, 17404, 71, 0 }, + /* tcId: 137. changing tag value of s */ + {0, 0, 6, 17475, 71, 0 }, + /* tcId: 138. dropping value of s */ + {0, 0, 6, 17546, 39, 0 }, + /* tcId: 139. using composition for s */ + {0, 0, 6, 17585, 75, 0 }, + /* tcId: 140. modifying first byte of s */ + {0, 0, 6, 17660, 71, 0 }, + /* tcId: 141. modifying last byte of s */ + {0, 0, 6, 17731, 71, 0 }, + /* tcId: 142. truncated s */ + {0, 0, 6, 17802, 70, 0 }, + /* tcId: 143. truncated s */ + {0, 0, 6, 17872, 70, 0 }, + /* tcId: 144. s of size 4129 to check for overflows */ + {0, 0, 6, 17942, 4172, 0 }, + /* tcId: 145. leading ff in s */ + {0, 0, 6, 22114, 72, 0 }, + /* tcId: 146. replaced s by infinity */ + {0, 0, 6, 22186, 40, 0 }, + /* tcId: 147. replacing s with zero */ + {0, 0, 6, 22226, 40, 0 }, + /* tcId: 148. replaced r by r + n */ + {0, 0, 6, 22266, 71, 0 }, + /* tcId: 149. replaced r by r - n */ + {0, 0, 6, 22337, 70, 0 }, + /* tcId: 150. replaced r by r + 256 * n */ + {0, 0, 6, 22407, 72, 0 }, + /* tcId: 151. replaced r by -r */ + {0, 0, 6, 22479, 71, 0 }, + /* tcId: 152. replaced r by n - r */ + {0, 0, 6, 22550, 70, 0 }, + /* tcId: 153. replaced r by -n - r */ + {0, 0, 6, 22620, 71, 0 }, + /* tcId: 154. replaced r by r + 2**256 */ + {0, 0, 6, 22691, 71, 0 }, + /* tcId: 155. replaced r by r + 2**320 */ + {0, 0, 6, 22762, 79, 0 }, + /* tcId: 156. replaced s by s + n */ + {0, 0, 6, 22841, 71, 0 }, + /* tcId: 157. replaced s by s - n */ + {0, 0, 6, 22912, 71, 0 }, + /* tcId: 158. replaced s by s + 256 * n */ + {0, 0, 6, 22983, 72, 0 }, + /* tcId: 159. replaced s by -s */ + {0, 0, 6, 23055, 70, 0 }, + /* tcId: 160. replaced s by -n - s */ + {0, 0, 6, 23125, 71, 0 }, + /* tcId: 161. replaced s by s + 2**256 */ + {0, 0, 6, 23196, 71, 0 }, + /* tcId: 162. replaced s by s - 2**256 */ + {0, 0, 6, 23267, 71, 0 }, + /* tcId: 163. replaced s by s + 2**320 */ + {0, 0, 6, 23338, 79, 0 }, + /* tcId: 164. Signature with special case values r=0 and s=0 */ + {0, 0, 6, 23417, 8, 0 }, + /* tcId: 165. Signature with special case values r=0 and s=1 */ + {0, 0, 6, 23425, 8, 0 }, + /* tcId: 166. Signature with special case values r=0 and s=-1 */ + {0, 0, 6, 23433, 8, 0 }, + /* tcId: 167. Signature with special case values r=0 and s=n */ + {0, 0, 6, 23441, 40, 0 }, + /* tcId: 168. Signature with special case values r=0 and s=n - 1 */ + {0, 0, 6, 23481, 40, 0 }, + /* tcId: 169. Signature with special case values r=0 and s=n + 1 */ + {0, 0, 6, 23521, 40, 0 }, + /* tcId: 170. Signature with special case values r=0 and s=p */ + {0, 0, 6, 23561, 40, 0 }, + /* tcId: 171. Signature with special case values r=0 and s=p + 1 */ + {0, 0, 6, 23601, 40, 0 }, + /* tcId: 172. Signature with special case values r=1 and s=0 */ + {0, 0, 6, 23641, 8, 0 }, + /* tcId: 173. Signature with special case values r=1 and s=1 */ + {0, 0, 6, 23649, 8, 0 }, + /* tcId: 174. Signature with special case values r=1 and s=-1 */ + {0, 0, 6, 23657, 8, 0 }, + /* tcId: 175. Signature with special case values r=1 and s=n */ + {0, 0, 6, 23665, 40, 0 }, + /* tcId: 176. Signature with special case values r=1 and s=n - 1 */ + {0, 0, 6, 23705, 40, 0 }, + /* tcId: 177. Signature with special case values r=1 and s=n + 1 */ + {0, 0, 6, 23745, 40, 0 }, + /* tcId: 178. Signature with special case values r=1 and s=p */ + {0, 0, 6, 23785, 40, 0 }, + /* tcId: 179. Signature with special case values r=1 and s=p + 1 */ + {0, 0, 6, 23825, 40, 0 }, + /* tcId: 180. Signature with special case values r=-1 and s=0 */ + {0, 0, 6, 23865, 8, 0 }, + /* tcId: 181. Signature with special case values r=-1 and s=1 */ + {0, 0, 6, 23873, 8, 0 }, + /* tcId: 182. Signature with special case values r=-1 and s=-1 */ + {0, 0, 6, 23881, 8, 0 }, + /* tcId: 183. Signature with special case values r=-1 and s=n */ + {0, 0, 6, 23889, 40, 0 }, + /* tcId: 184. Signature with special case values r=-1 and s=n - 1 */ + {0, 0, 6, 23929, 40, 0 }, + /* tcId: 185. Signature with special case values r=-1 and s=n + 1 */ + {0, 0, 6, 23969, 40, 0 }, + /* tcId: 186. Signature with special case values r=-1 and s=p */ + {0, 0, 6, 24009, 40, 0 }, + /* tcId: 187. Signature with special case values r=-1 and s=p + 1 */ + {0, 0, 6, 24049, 40, 0 }, + /* tcId: 188. Signature with special case values r=n and s=0 */ + {0, 0, 6, 24089, 40, 0 }, + /* tcId: 189. Signature with special case values r=n and s=1 */ + {0, 0, 6, 24129, 40, 0 }, + /* tcId: 190. Signature with special case values r=n and s=-1 */ + {0, 0, 6, 24169, 40, 0 }, + /* tcId: 191. Signature with special case values r=n and s=n */ + {0, 0, 6, 24209, 72, 0 }, + /* tcId: 192. Signature with special case values r=n and s=n - 1 */ + {0, 0, 6, 24281, 72, 0 }, + /* tcId: 193. Signature with special case values r=n and s=n + 1 */ + {0, 0, 6, 24353, 72, 0 }, + /* tcId: 194. Signature with special case values r=n and s=p */ + {0, 0, 6, 24425, 72, 0 }, + /* tcId: 195. Signature with special case values r=n and s=p + 1 */ + {0, 0, 6, 24497, 72, 0 }, + /* tcId: 196. Signature with special case values r=n - 1 and s=0 */ + {0, 0, 6, 24569, 40, 0 }, + /* tcId: 197. Signature with special case values r=n - 1 and s=1 */ + {0, 0, 6, 24609, 40, 0 }, + /* tcId: 198. Signature with special case values r=n - 1 and s=-1 */ + {0, 0, 6, 24649, 40, 0 }, + /* tcId: 199. Signature with special case values r=n - 1 and s=n */ + {0, 0, 6, 24689, 72, 0 }, + /* tcId: 200. Signature with special case values r=n - 1 and s=n - 1 */ + {0, 0, 6, 24761, 72, 0 }, + /* tcId: 201. Signature with special case values r=n - 1 and s=n + 1 */ + {0, 0, 6, 24833, 72, 0 }, + /* tcId: 202. Signature with special case values r=n - 1 and s=p */ + {0, 0, 6, 24905, 72, 0 }, + /* tcId: 203. Signature with special case values r=n - 1 and s=p + 1 */ + {0, 0, 6, 24977, 72, 0 }, + /* tcId: 204. Signature with special case values r=n + 1 and s=0 */ + {0, 0, 6, 25049, 40, 0 }, + /* tcId: 205. Signature with special case values r=n + 1 and s=1 */ + {0, 0, 6, 25089, 40, 0 }, + /* tcId: 206. Signature with special case values r=n + 1 and s=-1 */ + {0, 0, 6, 25129, 40, 0 }, + /* tcId: 207. Signature with special case values r=n + 1 and s=n */ + {0, 0, 6, 25169, 72, 0 }, + /* tcId: 208. Signature with special case values r=n + 1 and s=n - 1 */ + {0, 0, 6, 25241, 72, 0 }, + /* tcId: 209. Signature with special case values r=n + 1 and s=n + 1 */ + {0, 0, 6, 25313, 72, 0 }, + /* tcId: 210. Signature with special case values r=n + 1 and s=p */ + {0, 0, 6, 25385, 72, 0 }, + /* tcId: 211. Signature with special case values r=n + 1 and s=p + 1 */ + {0, 0, 6, 25457, 72, 0 }, + /* tcId: 212. Signature with special case values r=p and s=0 */ + {0, 0, 6, 25529, 40, 0 }, + /* tcId: 213. Signature with special case values r=p and s=1 */ + {0, 0, 6, 25569, 40, 0 }, + /* tcId: 214. Signature with special case values r=p and s=-1 */ + {0, 0, 6, 25609, 40, 0 }, + /* tcId: 215. Signature with special case values r=p and s=n */ + {0, 0, 6, 25649, 72, 0 }, + /* tcId: 216. Signature with special case values r=p and s=n - 1 */ + {0, 0, 6, 25721, 72, 0 }, + /* tcId: 217. Signature with special case values r=p and s=n + 1 */ + {0, 0, 6, 25793, 72, 0 }, + /* tcId: 218. Signature with special case values r=p and s=p */ + {0, 0, 6, 25865, 72, 0 }, + /* tcId: 219. Signature with special case values r=p and s=p + 1 */ + {0, 0, 6, 25937, 72, 0 }, + /* tcId: 220. Signature with special case values r=p + 1 and s=0 */ + {0, 0, 6, 26009, 40, 0 }, + /* tcId: 221. Signature with special case values r=p + 1 and s=1 */ + {0, 0, 6, 26049, 40, 0 }, + /* tcId: 222. Signature with special case values r=p + 1 and s=-1 */ + {0, 0, 6, 26089, 40, 0 }, + /* tcId: 223. Signature with special case values r=p + 1 and s=n */ + {0, 0, 6, 26129, 72, 0 }, + /* tcId: 224. Signature with special case values r=p + 1 and s=n - 1 */ + {0, 0, 6, 26201, 72, 0 }, + /* tcId: 225. Signature with special case values r=p + 1 and s=n + 1 */ + {0, 0, 6, 26273, 72, 0 }, + /* tcId: 226. Signature with special case values r=p + 1 and s=p */ + {0, 0, 6, 26345, 72, 0 }, + /* tcId: 227. Signature with special case values r=p + 1 and s=p + 1 */ + {0, 0, 6, 26417, 72, 0 }, + /* tcId: 228. Signature encoding contains incorrect types: r=0, s=0.25 */ + {0, 0, 6, 26489, 10, 0 }, + /* tcId: 229. Signature encoding contains incorrect types: r=0, s=nan */ + {0, 0, 6, 26499, 8, 0 }, + /* tcId: 230. Signature encoding contains incorrect types: r=0, s=True */ + {0, 0, 6, 26507, 8, 0 }, + /* tcId: 231. Signature encoding contains incorrect types: r=0, s=False */ + {0, 0, 6, 26515, 8, 0 }, + /* tcId: 232. Signature encoding contains incorrect types: r=0, s=Null */ + {0, 0, 6, 26523, 7, 0 }, + /* tcId: 233. Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string */ + {0, 0, 6, 26530, 7, 0 }, + /* tcId: 234. Signature encoding contains incorrect types: r=0, s="0" */ + {0, 0, 6, 26537, 8, 0 }, + /* tcId: 235. Signature encoding contains incorrect types: r=0, s=empty list */ + {0, 0, 6, 26545, 7, 0 }, + /* tcId: 236. Signature encoding contains incorrect types: r=0, s=list containing 0 */ + {0, 0, 6, 26552, 10, 0 }, + /* tcId: 237. Signature encoding contains incorrect types: r=1, s=0.25 */ + {0, 0, 6, 26562, 10, 0 }, + /* tcId: 238. Signature encoding contains incorrect types: r=1, s=nan */ + {0, 0, 6, 26572, 8, 0 }, + /* tcId: 239. Signature encoding contains incorrect types: r=1, s=True */ + {0, 0, 6, 26580, 8, 0 }, + /* tcId: 240. Signature encoding contains incorrect types: r=1, s=False */ + {0, 0, 6, 26588, 8, 0 }, + /* tcId: 241. Signature encoding contains incorrect types: r=1, s=Null */ + {0, 0, 6, 26596, 7, 0 }, + /* tcId: 242. Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string */ + {0, 0, 6, 26603, 7, 0 }, + /* tcId: 243. Signature encoding contains incorrect types: r=1, s="0" */ + {0, 0, 6, 26610, 8, 0 }, + /* tcId: 244. Signature encoding contains incorrect types: r=1, s=empty list */ + {0, 0, 6, 26618, 7, 0 }, + /* tcId: 245. Signature encoding contains incorrect types: r=1, s=list containing 0 */ + {0, 0, 6, 26625, 10, 0 }, + /* tcId: 246. Signature encoding contains incorrect types: r=-1, s=0.25 */ + {0, 0, 6, 26635, 10, 0 }, + /* tcId: 247. Signature encoding contains incorrect types: r=-1, s=nan */ + {0, 0, 6, 26645, 8, 0 }, + /* tcId: 248. Signature encoding contains incorrect types: r=-1, s=True */ + {0, 0, 6, 26653, 8, 0 }, + /* tcId: 249. Signature encoding contains incorrect types: r=-1, s=False */ + {0, 0, 6, 26661, 8, 0 }, + /* tcId: 250. Signature encoding contains incorrect types: r=-1, s=Null */ + {0, 0, 6, 26669, 7, 0 }, + /* tcId: 251. Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string */ + {0, 0, 6, 26676, 7, 0 }, + /* tcId: 252. Signature encoding contains incorrect types: r=-1, s="0" */ + {0, 0, 6, 26683, 8, 0 }, + /* tcId: 253. Signature encoding contains incorrect types: r=-1, s=empty list */ + {0, 0, 6, 26691, 7, 0 }, + /* tcId: 254. Signature encoding contains incorrect types: r=-1, s=list containing 0 */ + {0, 0, 6, 26698, 10, 0 }, + /* tcId: 255. Signature encoding contains incorrect types: r=n, s=0.25 */ + {0, 0, 6, 26708, 42, 0 }, + /* tcId: 256. Signature encoding contains incorrect types: r=n, s=nan */ + {0, 0, 6, 26750, 40, 0 }, + /* tcId: 257. Signature encoding contains incorrect types: r=n, s=True */ + {0, 0, 6, 26790, 40, 0 }, + /* tcId: 258. Signature encoding contains incorrect types: r=n, s=False */ + {0, 0, 6, 26830, 40, 0 }, + /* tcId: 259. Signature encoding contains incorrect types: r=n, s=Null */ + {0, 0, 6, 26870, 39, 0 }, + /* tcId: 260. Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string */ + {0, 0, 6, 26909, 39, 0 }, + /* tcId: 261. Signature encoding contains incorrect types: r=n, s="0" */ + {0, 0, 6, 26948, 40, 0 }, + /* tcId: 262. Signature encoding contains incorrect types: r=n, s=empty list */ + {0, 0, 6, 26988, 39, 0 }, + /* tcId: 263. Signature encoding contains incorrect types: r=n, s=list containing 0 */ + {0, 0, 6, 27027, 42, 0 }, + /* tcId: 264. Signature encoding contains incorrect types: r=p, s=0.25 */ + {0, 0, 6, 27069, 42, 0 }, + /* tcId: 265. Signature encoding contains incorrect types: r=p, s=nan */ + {0, 0, 6, 27111, 40, 0 }, + /* tcId: 266. Signature encoding contains incorrect types: r=p, s=True */ + {0, 0, 6, 27151, 40, 0 }, + /* tcId: 267. Signature encoding contains incorrect types: r=p, s=False */ + {0, 0, 6, 27191, 40, 0 }, + /* tcId: 268. Signature encoding contains incorrect types: r=p, s=Null */ + {0, 0, 6, 27231, 39, 0 }, + /* tcId: 269. Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string */ + {0, 0, 6, 27270, 39, 0 }, + /* tcId: 270. Signature encoding contains incorrect types: r=p, s="0" */ + {0, 0, 6, 27309, 40, 0 }, + /* tcId: 271. Signature encoding contains incorrect types: r=p, s=empty list */ + {0, 0, 6, 27349, 39, 0 }, + /* tcId: 272. Signature encoding contains incorrect types: r=p, s=list containing 0 */ + {0, 0, 6, 27388, 42, 0 }, + /* tcId: 273. Signature encoding contains incorrect types: r=0.25, s=0.25 */ + {0, 0, 6, 27430, 12, 0 }, + /* tcId: 274. Signature encoding contains incorrect types: r=nan, s=nan */ + {0, 0, 6, 27442, 8, 0 }, + /* tcId: 275. Signature encoding contains incorrect types: r=True, s=True */ + {0, 0, 6, 27450, 8, 0 }, + /* tcId: 276. Signature encoding contains incorrect types: r=False, s=False */ + {0, 0, 6, 27458, 8, 0 }, + /* tcId: 277. Signature encoding contains incorrect types: r=Null, s=Null */ + {0, 0, 6, 27466, 6, 0 }, + /* tcId: 278. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string */ + {0, 0, 6, 27472, 6, 0 }, + /* tcId: 279. Signature encoding contains incorrect types: r="0", s="0" */ + {0, 0, 6, 27478, 8, 0 }, + /* tcId: 280. Signature encoding contains incorrect types: r=empty list, s=empty list */ + {0, 0, 6, 27486, 6, 0 }, + /* tcId: 281. Signature encoding contains incorrect types: r=list containing 0, s=list containing 0 */ + {0, 0, 6, 27492, 12, 0 }, + /* tcId: 282. Signature encoding contains incorrect types: r=0.25, s=0 */ + {0, 0, 6, 27504, 10, 0 }, + /* tcId: 283. Signature encoding contains incorrect types: r=nan, s=0 */ + {0, 0, 6, 27514, 8, 0 }, + /* tcId: 284. Signature encoding contains incorrect types: r=True, s=0 */ + {0, 0, 6, 27522, 8, 0 }, + /* tcId: 285. Signature encoding contains incorrect types: r=False, s=0 */ + {0, 0, 6, 27530, 8, 0 }, + /* tcId: 286. Signature encoding contains incorrect types: r=Null, s=0 */ + {0, 0, 6, 27538, 7, 0 }, + /* tcId: 287. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0 */ + {0, 0, 6, 27545, 7, 0 }, + /* tcId: 288. Signature encoding contains incorrect types: r="0", s=0 */ + {0, 0, 6, 27552, 8, 0 }, + /* tcId: 289. Signature encoding contains incorrect types: r=empty list, s=0 */ + {0, 0, 6, 27560, 7, 0 }, + /* tcId: 290. Signature encoding contains incorrect types: r=list containing 0, s=0 */ + {0, 0, 6, 27567, 10, 0 }, + /* tcId: 291. Edge case for Shamir multiplication */ + {0, 6, 5, 27577, 71, 1 }, + /* tcId: 292. special case hash */ + {0, 11, 9, 27648, 71, 1 }, + /* tcId: 293. special case hash */ + {0, 20, 10, 27719, 70, 1 }, + /* tcId: 294. special case hash */ + {0, 30, 11, 27789, 71, 1 }, + /* tcId: 295. special case hash */ + {0, 41, 10, 27860, 71, 1 }, + /* tcId: 296. special case hash */ + {0, 51, 10, 27931, 70, 1 }, + /* tcId: 297. special case hash */ + {0, 61, 10, 28001, 71, 1 }, + /* tcId: 298. special case hash */ + {0, 71, 9, 28072, 70, 1 }, + /* tcId: 299. special case hash */ + {0, 80, 10, 28142, 71, 1 }, + /* tcId: 300. special case hash */ + {0, 90, 10, 28213, 71, 1 }, + /* tcId: 301. special case hash */ + {0, 100, 10, 28284, 71, 1 }, + /* tcId: 302. special case hash */ + {0, 110, 10, 28355, 71, 1 }, + /* tcId: 303. special case hash */ + {0, 120, 11, 28426, 70, 1 }, + /* tcId: 304. special case hash */ + {0, 131, 10, 28496, 71, 1 }, + /* tcId: 305. special case hash */ + {0, 141, 10, 28567, 71, 1 }, + /* tcId: 306. special case hash */ + {0, 151, 10, 28638, 70, 1 }, + /* tcId: 307. special case hash */ + {0, 161, 10, 28708, 71, 1 }, + /* tcId: 308. special case hash */ + {0, 171, 10, 28779, 71, 1 }, + /* tcId: 309. special case hash */ + {0, 181, 10, 28850, 70, 1 }, + /* tcId: 310. special case hash */ + {0, 191, 10, 28920, 71, 1 }, + /* tcId: 311. special case hash */ + {0, 201, 10, 28991, 71, 1 }, + /* tcId: 312. special case hash */ + {0, 211, 10, 29062, 71, 1 }, + /* tcId: 313. special case hash */ + {0, 221, 10, 29133, 70, 1 }, + /* tcId: 314. special case hash */ + {0, 231, 10, 29203, 71, 1 }, + /* tcId: 315. special case hash */ + {0, 241, 10, 29274, 71, 1 }, + /* tcId: 316. special case hash */ + {0, 251, 10, 29345, 71, 1 }, + /* tcId: 317. special case hash */ + {0, 261, 11, 29416, 71, 1 }, + /* tcId: 318. special case hash */ + {0, 272, 11, 29487, 70, 1 }, + /* tcId: 319. special case hash */ + {0, 283, 9, 29557, 71, 1 }, + /* tcId: 320. special case hash */ + {0, 292, 9, 29628, 71, 1 }, + /* tcId: 321. special case hash */ + {0, 301, 10, 29699, 71, 1 }, + /* tcId: 322. special case hash */ + {0, 311, 10, 29770, 71, 1 }, + /* tcId: 323. special case hash */ + {0, 321, 10, 29841, 70, 1 }, + /* tcId: 324. special case hash */ + {0, 331, 10, 29911, 70, 1 }, + /* tcId: 325. special case hash */ + {0, 341, 10, 29981, 71, 1 }, + /* tcId: 326. special case hash */ + {0, 351, 9, 30052, 70, 1 }, + /* tcId: 327. special case hash */ + {0, 360, 10, 30122, 70, 1 }, + /* tcId: 328. special case hash */ + {0, 370, 10, 30192, 70, 1 }, + /* tcId: 329. special case hash */ + {0, 380, 10, 30262, 70, 1 }, + /* tcId: 330. special case hash */ + {0, 390, 9, 30332, 71, 1 }, + /* tcId: 331. special case hash */ + {0, 399, 11, 30403, 70, 1 }, + /* tcId: 332. special case hash */ + {0, 410, 9, 30473, 71, 1 }, + /* tcId: 333. special case hash */ + {0, 419, 9, 30544, 71, 1 }, + /* tcId: 334. special case hash */ + {0, 428, 11, 30615, 70, 1 }, + /* tcId: 335. special case hash */ + {0, 439, 8, 30685, 71, 1 }, + /* tcId: 336. special case hash */ + {0, 447, 10, 30756, 70, 1 }, + /* tcId: 337. special case hash */ + {0, 457, 10, 30826, 71, 1 }, + /* tcId: 338. special case hash */ + {0, 467, 10, 30897, 70, 1 }, + /* tcId: 339. special case hash */ + {0, 477, 10, 30967, 70, 1 }, + /* tcId: 340. special case hash */ + {0, 487, 10, 31037, 70, 1 }, + /* tcId: 341. special case hash */ + {0, 497, 10, 31107, 71, 1 }, + /* tcId: 342. special case hash */ + {0, 507, 10, 31178, 70, 1 }, + /* tcId: 343. special case hash */ + {0, 517, 10, 31248, 70, 1 }, + /* tcId: 344. special case hash */ + {0, 527, 10, 31318, 71, 1 }, + /* tcId: 345. special case hash */ + {0, 537, 9, 31389, 70, 1 }, + /* tcId: 346. k*G has a large x-coordinate */ + {65, 0, 6, 31459, 24, 1 }, + /* tcId: 347. r too large */ + {65, 0, 6, 31483, 40, 0 }, + /* tcId: 348. r,s are large */ + {130, 0, 6, 31523, 40, 1 }, + /* tcId: 349. r and s^-1 have a large Hamming weight */ + {195, 0, 6, 31563, 70, 1 }, + /* tcId: 350. r and s^-1 have a large Hamming weight */ + {260, 0, 6, 31633, 70, 1 }, + /* tcId: 351. small r and s */ + {325, 0, 6, 31703, 8, 1 }, + /* tcId: 352. small r and s */ + {390, 0, 6, 31711, 8, 1 }, + /* tcId: 353. small r and s */ + {455, 0, 6, 31719, 8, 1 }, + /* tcId: 354. small r and s */ + {520, 0, 6, 31727, 8, 1 }, + /* tcId: 355. small r and s */ + {585, 0, 6, 31735, 8, 1 }, + /* tcId: 356. small r and s */ + {650, 0, 6, 31743, 8, 1 }, + /* tcId: 357. r is larger than n */ + {650, 0, 6, 31751, 40, 0 }, + /* tcId: 358. s is larger than n */ + {715, 0, 6, 31791, 10, 0 }, + /* tcId: 359. small r and s^-1 */ + {780, 0, 6, 31801, 40, 1 }, + /* tcId: 360. smallish r and s^-1 */ + {845, 0, 6, 31841, 45, 1 }, + /* tcId: 361. 100-bit r and small s^-1 */ + {910, 0, 6, 31886, 51, 1 }, + /* tcId: 362. small r and 100 bit s^-1 */ + {975, 0, 6, 31937, 40, 1 }, + /* tcId: 363. 100-bit r and s^-1 */ + {1040, 0, 6, 31977, 51, 1 }, + /* tcId: 364. r and s^-1 are close to n */ + {1105, 0, 6, 32028, 71, 1 }, + /* tcId: 365. r and s are 64-bit integer */ + {1170, 0, 6, 32099, 24, 1 }, + /* tcId: 366. r and s are 100-bit integer */ + {1235, 0, 6, 32123, 32, 1 }, + /* tcId: 367. r and s are 128-bit integer */ + {1300, 0, 6, 32155, 40, 1 }, + /* tcId: 368. r and s are 160-bit integer */ + {1365, 0, 6, 32195, 48, 1 }, + /* tcId: 369. s == 1 */ + {1430, 0, 6, 32243, 39, 1 }, + /* tcId: 370. s == 0 */ + {1430, 0, 6, 32282, 39, 0 }, + /* tcId: 371. edge case modular inverse */ + {1495, 0, 6, 32321, 70, 1 }, + /* tcId: 372. edge case modular inverse */ + {1560, 0, 6, 32391, 70, 1 }, + /* tcId: 373. edge case modular inverse */ + {1625, 0, 6, 32461, 70, 1 }, + /* tcId: 374. edge case modular inverse */ + {1690, 0, 6, 32531, 70, 1 }, + /* tcId: 375. edge case modular inverse */ + {1755, 0, 6, 32601, 70, 1 }, + /* tcId: 376. edge case modular inverse */ + {1820, 0, 6, 32671, 70, 1 }, + /* tcId: 377. edge case modular inverse */ + {1885, 0, 6, 32741, 70, 1 }, + /* tcId: 378. edge case modular inverse */ + {1950, 0, 6, 32811, 70, 1 }, + /* tcId: 379. edge case modular inverse */ + {2015, 0, 6, 32881, 70, 1 }, + /* tcId: 380. edge case modular inverse */ + {2080, 0, 6, 32951, 70, 1 }, + /* tcId: 381. edge case modular inverse */ + {2145, 0, 6, 33021, 70, 1 }, + /* tcId: 382. edge case modular inverse */ + {2210, 0, 6, 33091, 70, 1 }, + /* tcId: 383. edge case modular inverse */ + {2275, 0, 6, 33161, 70, 1 }, + /* tcId: 384. edge case modular inverse */ + {2340, 0, 6, 33231, 70, 1 }, + /* tcId: 385. edge case modular inverse */ + {2405, 0, 6, 33301, 70, 1 }, + /* tcId: 386. point at infinity during verify */ + {2470, 0, 6, 33371, 70, 0 }, + /* tcId: 387. edge case for signature malleability */ + {2535, 0, 6, 33441, 70, 1 }, + /* tcId: 388. edge case for signature malleability */ + {2600, 0, 6, 33511, 70, 0 }, + /* tcId: 389. u1 == 1 */ + {2665, 0, 6, 33581, 70, 1 }, + /* tcId: 390. u1 == n - 1 */ + {2730, 0, 6, 33651, 70, 1 }, + /* tcId: 391. u2 == 1 */ + {2795, 0, 6, 33721, 70, 1 }, + /* tcId: 392. u2 == n - 1 */ + {2860, 0, 6, 33791, 70, 1 }, + /* tcId: 393. edge case for u1 */ + {2925, 0, 6, 33861, 70, 1 }, + /* tcId: 394. edge case for u1 */ + {2990, 0, 6, 33931, 70, 1 }, + /* tcId: 395. edge case for u1 */ + {3055, 0, 6, 34001, 70, 1 }, + /* tcId: 396. edge case for u1 */ + {3120, 0, 6, 34071, 70, 1 }, + /* tcId: 397. edge case for u1 */ + {3185, 0, 6, 34141, 70, 1 }, + /* tcId: 398. edge case for u1 */ + {3250, 0, 6, 34211, 70, 1 }, + /* tcId: 399. edge case for u1 */ + {3315, 0, 6, 34281, 70, 1 }, + /* tcId: 400. edge case for u1 */ + {3380, 0, 6, 34351, 70, 1 }, + /* tcId: 401. edge case for u1 */ + {3445, 0, 6, 34421, 70, 1 }, + /* tcId: 402. edge case for u1 */ + {3510, 0, 6, 34491, 70, 1 }, + /* tcId: 403. edge case for u1 */ + {3575, 0, 6, 34561, 70, 1 }, + /* tcId: 404. edge case for u1 */ + {3640, 0, 6, 34631, 70, 1 }, + /* tcId: 405. edge case for u1 */ + {3705, 0, 6, 34701, 70, 1 }, + /* tcId: 406. edge case for u1 */ + {3770, 0, 6, 34771, 70, 1 }, + /* tcId: 407. edge case for u1 */ + {3835, 0, 6, 34841, 70, 1 }, + /* tcId: 408. edge case for u2 */ + {3900, 0, 6, 34911, 70, 1 }, + /* tcId: 409. edge case for u2 */ + {3965, 0, 6, 34981, 70, 1 }, + /* tcId: 410. edge case for u2 */ + {4030, 0, 6, 35051, 70, 1 }, + /* tcId: 411. edge case for u2 */ + {4095, 0, 6, 35121, 70, 1 }, + /* tcId: 412. edge case for u2 */ + {4160, 0, 6, 35191, 70, 1 }, + /* tcId: 413. edge case for u2 */ + {4225, 0, 6, 35261, 69, 1 }, + /* tcId: 414. edge case for u2 */ + {4290, 0, 6, 35330, 70, 1 }, + /* tcId: 415. edge case for u2 */ + {4355, 0, 6, 35400, 70, 1 }, + /* tcId: 416. edge case for u2 */ + {4420, 0, 6, 35470, 70, 1 }, + /* tcId: 417. edge case for u2 */ + {4485, 0, 6, 35540, 70, 1 }, + /* tcId: 418. edge case for u2 */ + {4550, 0, 6, 35610, 70, 1 }, + /* tcId: 419. edge case for u2 */ + {4615, 0, 6, 35680, 70, 1 }, + /* tcId: 420. edge case for u2 */ + {4680, 0, 6, 35750, 70, 1 }, + /* tcId: 421. edge case for u2 */ + {4745, 0, 6, 35820, 70, 1 }, + /* tcId: 422. edge case for u2 */ + {4810, 0, 6, 35890, 70, 1 }, + /* tcId: 423. point duplication during verification */ + {4875, 0, 6, 35960, 70, 1 }, + /* tcId: 424. duplication bug */ + {4940, 0, 6, 36030, 70, 0 }, + /* tcId: 425. comparison with point at infinity */ + {5005, 0, 6, 36100, 70, 0 }, + /* tcId: 426. extreme value for k and edgecase s */ + {5070, 0, 6, 36170, 71, 1 }, + /* tcId: 427. extreme value for k and s^-1 */ + {5135, 0, 6, 36241, 71, 1 }, + /* tcId: 428. extreme value for k and s^-1 */ + {5200, 0, 6, 36312, 71, 1 }, + /* tcId: 429. extreme value for k and s^-1 */ + {5265, 0, 6, 36383, 71, 1 }, + /* tcId: 430. extreme value for k and s^-1 */ + {5330, 0, 6, 36454, 71, 1 }, + /* tcId: 431. extreme value for k */ + {5395, 0, 6, 36525, 71, 1 }, + /* tcId: 432. extreme value for k and edgecase s */ + {5460, 0, 6, 36596, 70, 1 }, + /* tcId: 433. extreme value for k and s^-1 */ + {5525, 0, 6, 36666, 70, 1 }, + /* tcId: 434. extreme value for k and s^-1 */ + {5590, 0, 6, 36736, 70, 1 }, + /* tcId: 435. extreme value for k and s^-1 */ + {5655, 0, 6, 36806, 70, 1 }, + /* tcId: 436. extreme value for k and s^-1 */ + {5720, 0, 6, 36876, 70, 1 }, + /* tcId: 437. extreme value for k */ + {5785, 0, 6, 36946, 70, 1 }, + /* tcId: 438. public key shares x-coordinate with generator */ + {5850, 0, 6, 37016, 71, 0 }, + /* tcId: 439. public key shares x-coordinate with generator */ + {5850, 0, 6, 37087, 70, 0 }, + /* tcId: 440. public key shares x-coordinate with generator */ + {5915, 0, 6, 37157, 71, 0 }, + /* tcId: 441. public key shares x-coordinate with generator */ + {5915, 0, 6, 37228, 70, 0 }, + /* tcId: 442. pseudorandom signature */ + {5980, 546, 0, 37298, 71, 1 }, + /* tcId: 443. pseudorandom signature */ + {5980, 546, 3, 37369, 70, 1 }, + /* tcId: 444. pseudorandom signature */ + {5980, 0, 6, 37439, 71, 1 }, + /* tcId: 445. pseudorandom signature */ + {5980, 549, 20, 37510, 70, 1 }, + /* tcId: 446. y-coordinate of the public key is small */ + {6045, 569, 7, 37580, 70, 1 }, + /* tcId: 447. y-coordinate of the public key is small */ + {6045, 569, 7, 37650, 70, 1 }, + /* tcId: 448. y-coordinate of the public key is small */ + {6045, 569, 7, 37720, 71, 1 }, + /* tcId: 449. y-coordinate of the public key is large */ + {6110, 569, 7, 37791, 70, 1 }, + /* tcId: 450. y-coordinate of the public key is large */ + {6110, 569, 7, 37861, 71, 1 }, + /* tcId: 451. y-coordinate of the public key is large */ + {6110, 569, 7, 37932, 70, 1 }, + /* tcId: 452. x-coordinate of the public key is small */ + {6175, 569, 7, 38002, 70, 1 }, + /* tcId: 453. x-coordinate of the public key is small */ + {6175, 569, 7, 38072, 71, 1 }, + /* tcId: 454. x-coordinate of the public key is small */ + {6175, 569, 7, 38143, 71, 1 }, + /* tcId: 455. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38214, 70, 1 }, + /* tcId: 456. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38284, 71, 1 }, + /* tcId: 457. x-coordinate of the public key has many trailing 1's */ + {6240, 569, 7, 38355, 71, 1 }, + /* tcId: 458. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38426, 70, 1 }, + /* tcId: 459. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38496, 71, 1 }, + /* tcId: 460. y-coordinate of the public key has many trailing 1's */ + {6305, 569, 7, 38567, 71, 1 }, + /* tcId: 461. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38638, 70, 1 }, + /* tcId: 462. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38708, 70, 1 }, + /* tcId: 463. x-coordinate of the public key has many trailing 0's */ + {6370, 569, 7, 38778, 71, 1 }, + +}; diff --git a/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json new file mode 100644 index 000000000..9c9074799 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json @@ -0,0 +1,6360 @@ +{ + "algorithm" : "ECDSA", + "schema" : "ecdsa_bitcoin_verify_schema.json", + "generatorVersion" : "0.9rc5", + "numberOfTests" : 463, + "header" : [ + "Test vectors of type EcdsaBitcoinVerify are meant for the verification", + "of a ECDSA variant used for bitcoin, that add signature non-malleability." + ], + "notes" : { + "ArithmeticError" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.", + "cves" : [ + "CVE-2017-18146" + ] + }, + "BerEncodedSignature" : { + "bugType" : "BER_ENCODING", + "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.", + "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.", + "cves" : [ + "CVE-2020-14966", + "CVE-2020-13822", + "CVE-2019-14859", + "CVE-2016-1000342" + ] + }, + "EdgeCasePublicKey" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector uses a special case public key. " + }, + "EdgeCaseShamirMultiplication" : { + "bugType" : "EDGE_CASE", + "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used." + }, + "IntegerOverflow" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidEncoding" : { + "bugType" : "CAN_OF_WORMS", + "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "InvalidSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449", + "CVE-2021-43572", + "CVE-2022-24884" + ] + }, + "InvalidTypesInSignature" : { + "bugType" : "AUTH_BYPASS", + "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.", + "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.", + "cves" : [ + "CVE-2022-21449" + ] + }, + "ModifiedInteger" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModifiedSignature" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "ModularInverse" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "CVE-2019-0865" + ] + }, + "PointDuplication" : { + "bugType" : "EDGE_CASE", + "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.", + "cves" : [ + "2020-12607", + "CVE-2015-2730" + ] + }, + "RangeCheck" : { + "bugType" : "CAN_OF_WORMS", + "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.", + "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures." + }, + "SignatureMalleabilityBitcoin" : { + "bugType" : "SIGNATURE_MALLEABILITY", + "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.", + "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals", + "links" : [ + "https://en.bitcoin.it/wiki/Transaction_malleability", + "https://en.bitcoinwiki.org/wiki/Transaction_Malleability" + ] + }, + "SmallRandS" : { + "bugType" : "EDGE_CASE", + "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.", + "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.", + "cves" : [ + "2020-13895" + ] + }, + "SpecialCaseHash" : { + "bugType" : "EDGE_CASE", + "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits." + }, + "ValidSignature" : { + "bugType" : "BASIC", + "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported." + } + }, + "testGroups" : [ + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f", + "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 1, + "comment" : "Signature malleability", + "flags" : [ + "SignatureMalleabilityBitcoin" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87", + "result" : "invalid" + }, + { + "tcId" : 2, + "comment" : "valid", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "valid" + }, + { + "tcId" : 3, + "comment" : "length of sequence [r, s] uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 4, + "comment" : "length of sequence [r, s] contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 5, + "comment" : "length of sequence [r, s] uses 70 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 6, + "comment" : "length of sequence [r, s] uses 68 instead of 69", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 7, + "comment" : "uint32 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 8, + "comment" : "uint64 overflow in length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 9, + "comment" : "length of sequence [r, s] = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 10, + "comment" : "length of sequence [r, s] = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 11, + "comment" : "length of sequence [r, s] = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 12, + "comment" : "length of sequence [r, s] = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 13, + "comment" : "length of sequence [r, s] = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 14, + "comment" : "incorrect length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 15, + "comment" : "replaced sequence [r, s] by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 16, + "comment" : "removing sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "", + "result" : "invalid" + }, + { + "tcId" : 17, + "comment" : "lonely sequence tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30", + "result" : "invalid" + }, + { + "tcId" : 18, + "comment" : "appending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 19, + "comment" : "prepending 0's to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 20, + "comment" : "appending unused 0's to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 21, + "comment" : "appending null value to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 22, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 23, + "comment" : "prepending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 24, + "comment" : "appending garbage to sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 25, + "comment" : "including undefined tags", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 26, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 27, + "comment" : "including undefined tags", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 28, + "comment" : "truncated length of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3081", + "result" : "invalid" + }, + { + "tcId" : 29, + "comment" : "including undefined tags to sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 30, + "comment" : "using composition with indefinite length for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 31, + "comment" : "using composition with wrong tag for sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 32, + "comment" : "Replacing sequence [r, s] with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "0500", + "result" : "invalid" + }, + { + "tcId" : 33, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 34, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 35, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 36, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 37, + "comment" : "changing tag value of sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 38, + "comment" : "dropping value of sequence [r, s]", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3000", + "result" : "invalid" + }, + { + "tcId" : 39, + "comment" : "using composition for sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 40, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 41, + "comment" : "truncated sequence [r, s]", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 42, + "comment" : "sequence [r, s] of size 4166 to check for overflows", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 43, + "comment" : "indefinite length", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 44, + "comment" : "indefinite length with truncated delimiter", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00", + "result" : "invalid" + }, + { + "tcId" : 45, + "comment" : "indefinite length with additional element", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000", + "result" : "invalid" + }, + { + "tcId" : 46, + "comment" : "indefinite length with truncated element", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000", + "result" : "invalid" + }, + { + "tcId" : 47, + "comment" : "indefinite length with garbage", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef", + "result" : "invalid" + }, + { + "tcId" : 48, + "comment" : "indefinite length with nonempty EOC", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef", + "result" : "invalid" + }, + { + "tcId" : 49, + "comment" : "prepend empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 50, + "comment" : "append empty sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000", + "result" : "invalid" + }, + { + "tcId" : 51, + "comment" : "append zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100", + "result" : "invalid" + }, + { + "tcId" : 52, + "comment" : "append garbage with high tag number", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00", + "result" : "invalid" + }, + { + "tcId" : 53, + "comment" : "append null with explicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500", + "result" : "invalid" + }, + { + "tcId" : 54, + "comment" : "append null with implicit tag", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000", + "result" : "invalid" + }, + { + "tcId" : 55, + "comment" : "sequence of sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 56, + "comment" : "truncated sequence: removed last 1 elements", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365", + "result" : "invalid" + }, + { + "tcId" : 57, + "comment" : "repeating element in sequence", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 58, + "comment" : "flipped bit 0 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 59, + "comment" : "flipped bit 32 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 60, + "comment" : "flipped bit 48 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 61, + "comment" : "flipped bit 64 in r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 62, + "comment" : "length of r uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 63, + "comment" : "length of r contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 64, + "comment" : "length of r uses 34 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 65, + "comment" : "length of r uses 32 instead of 33", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 66, + "comment" : "uint32 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 67, + "comment" : "uint64 overflow in length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 68, + "comment" : "length of r = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 69, + "comment" : "length of r = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 70, + "comment" : "length of r = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 71, + "comment" : "length of r = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 72, + "comment" : "length of r = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 73, + "comment" : "incorrect length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 74, + "comment" : "replaced r by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 75, + "comment" : "removing r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 76, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 77, + "comment" : "lonely integer tag", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502", + "result" : "invalid" + }, + { + "tcId" : 78, + "comment" : "appending 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 79, + "comment" : "prepending 0's to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 80, + "comment" : "appending unused 0's to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 81, + "comment" : "appending null value to r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 82, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 83, + "comment" : "prepending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 84, + "comment" : "appending garbage to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 85, + "comment" : "truncated length of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 86, + "comment" : "including undefined tags to r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 87, + "comment" : "using composition with indefinite length for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 88, + "comment" : "using composition with wrong tag for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 89, + "comment" : "Replacing r with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 90, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 91, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 92, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 93, + "comment" : "changing tag value of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 94, + "comment" : "changing tag value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 95, + "comment" : "dropping value of r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 96, + "comment" : "using composition for r", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 97, + "comment" : "modifying first byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 98, + "comment" : "modifying last byte of r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 99, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 100, + "comment" : "truncated r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 101, + "comment" : "r of size 4130 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 102, + "comment" : "leading ff in r", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 103, + "comment" : "replaced r by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 104, + "comment" : "replacing r with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 105, + "comment" : "flipped bit 0 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb", + "result" : "invalid" + }, + { + "tcId" : 106, + "comment" : "flipped bit 32 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba", + "result" : "invalid" + }, + { + "tcId" : 107, + "comment" : "flipped bit 48 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 108, + "comment" : "flipped bit 64 in s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 109, + "comment" : "length of s uses long form encoding", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 110, + "comment" : "length of s contains a leading 0", + "flags" : [ + "BerEncodedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 111, + "comment" : "length of s uses 33 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 112, + "comment" : "length of s uses 31 instead of 32", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 113, + "comment" : "uint32 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 114, + "comment" : "uint64 overflow in length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 115, + "comment" : "length of s = 2**31 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 116, + "comment" : "length of s = 2**31", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 117, + "comment" : "length of s = 2**32 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 118, + "comment" : "length of s = 2**40 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 119, + "comment" : "length of s = 2**64 - 1", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 120, + "comment" : "incorrect length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 121, + "comment" : "replaced s by an indefinite length tag without termination", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 122, + "comment" : "appending 0's to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 123, + "comment" : "prepending 0's to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 124, + "comment" : "appending null value to s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500", + "result" : "invalid" + }, + { + "tcId" : 125, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 126, + "comment" : "prepending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 127, + "comment" : "appending garbage to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef", + "result" : "invalid" + }, + { + "tcId" : 128, + "comment" : "truncated length of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281", + "result" : "invalid" + }, + { + "tcId" : 129, + "comment" : "including undefined tags to s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 130, + "comment" : "using composition with indefinite length for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 131, + "comment" : "using composition with wrong tag for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000", + "result" : "invalid" + }, + { + "tcId" : 132, + "comment" : "Replacing s with NULL", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500", + "result" : "invalid" + }, + { + "tcId" : 133, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 134, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 135, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 136, + "comment" : "changing tag value of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 137, + "comment" : "changing tag value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 138, + "comment" : "dropping value of s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200", + "result" : "invalid" + }, + { + "tcId" : 139, + "comment" : "using composition for s", + "flags" : [ + "InvalidEncoding" + ], + "msg" : "313233343030", + "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 140, + "comment" : "modifying first byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 141, + "comment" : "modifying last byte of s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a", + "result" : "invalid" + }, + { + "tcId" : 142, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31", + "result" : "invalid" + }, + { + "tcId" : 143, + "comment" : "truncated s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 144, + "comment" : "s of size 4129 to check for overflows", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "result" : "invalid" + }, + { + "tcId" : 145, + "comment" : "leading ff in s", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 146, + "comment" : "replaced s by infinity", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180", + "result" : "invalid" + }, + { + "tcId" : 147, + "comment" : "replacing s with zero", + "flags" : [ + "ModifiedSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100", + "result" : "invalid" + }, + { + "tcId" : 148, + "comment" : "replaced r by r + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 149, + "comment" : "replaced r by r - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 150, + "comment" : "replaced r by r + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 151, + "comment" : "replaced r by -r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 152, + "comment" : "replaced r by n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 153, + "comment" : "replaced r by -n - r", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 154, + "comment" : "replaced r by r + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 155, + "comment" : "replaced r by r + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 156, + "comment" : "replaced s by s + n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 157, + "comment" : "replaced s by s - n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 158, + "comment" : "replaced s by s + 256 * n", + "flags" : [ + "RangeCheck" + ], + "msg" : "313233343030", + "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 159, + "comment" : "replaced s by -s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 160, + "comment" : "replaced s by -n - s", + "flags" : [ + "ModifiedInteger" + ], + "msg" : "313233343030", + "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 161, + "comment" : "replaced s by s + 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 162, + "comment" : "replaced s by s - 2**256", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 163, + "comment" : "replaced s by s + 2**320", + "flags" : [ + "IntegerOverflow" + ], + "msg" : "313233343030", + "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba", + "result" : "invalid" + }, + { + "tcId" : 164, + "comment" : "Signature with special case values r=0 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020100", + "result" : "invalid" + }, + { + "tcId" : 165, + "comment" : "Signature with special case values r=0 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100020101", + "result" : "invalid" + }, + { + "tcId" : 166, + "comment" : "Signature with special case values r=0 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000201ff", + "result" : "invalid" + }, + { + "tcId" : 167, + "comment" : "Signature with special case values r=0 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 168, + "comment" : "Signature with special case values r=0 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 169, + "comment" : "Signature with special case values r=0 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 170, + "comment" : "Signature with special case values r=0 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 171, + "comment" : "Signature with special case values r=0 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 172, + "comment" : "Signature with special case values r=1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020100", + "result" : "invalid" + }, + { + "tcId" : 173, + "comment" : "Signature with special case values r=1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "invalid" + }, + { + "tcId" : 174, + "comment" : "Signature with special case values r=1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010201ff", + "result" : "invalid" + }, + { + "tcId" : 175, + "comment" : "Signature with special case values r=1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 176, + "comment" : "Signature with special case values r=1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 177, + "comment" : "Signature with special case values r=1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 178, + "comment" : "Signature with special case values r=1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 179, + "comment" : "Signature with special case values r=1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 180, + "comment" : "Signature with special case values r=-1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020100", + "result" : "invalid" + }, + { + "tcId" : 181, + "comment" : "Signature with special case values r=-1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff020101", + "result" : "invalid" + }, + { + "tcId" : 182, + "comment" : "Signature with special case values r=-1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0201ff", + "result" : "invalid" + }, + { + "tcId" : 183, + "comment" : "Signature with special case values r=-1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 184, + "comment" : "Signature with special case values r=-1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 185, + "comment" : "Signature with special case values r=-1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 186, + "comment" : "Signature with special case values r=-1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 187, + "comment" : "Signature with special case values r=-1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 188, + "comment" : "Signature with special case values r=n and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100", + "result" : "invalid" + }, + { + "tcId" : 189, + "comment" : "Signature with special case values r=n and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101", + "result" : "invalid" + }, + { + "tcId" : 190, + "comment" : "Signature with special case values r=n and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff", + "result" : "invalid" + }, + { + "tcId" : 191, + "comment" : "Signature with special case values r=n and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 192, + "comment" : "Signature with special case values r=n and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 193, + "comment" : "Signature with special case values r=n and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 194, + "comment" : "Signature with special case values r=n and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 195, + "comment" : "Signature with special case values r=n and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 196, + "comment" : "Signature with special case values r=n - 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100", + "result" : "invalid" + }, + { + "tcId" : 197, + "comment" : "Signature with special case values r=n - 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101", + "result" : "invalid" + }, + { + "tcId" : 198, + "comment" : "Signature with special case values r=n - 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff", + "result" : "invalid" + }, + { + "tcId" : 199, + "comment" : "Signature with special case values r=n - 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 200, + "comment" : "Signature with special case values r=n - 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 201, + "comment" : "Signature with special case values r=n - 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 202, + "comment" : "Signature with special case values r=n - 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 203, + "comment" : "Signature with special case values r=n - 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 204, + "comment" : "Signature with special case values r=n + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100", + "result" : "invalid" + }, + { + "tcId" : 205, + "comment" : "Signature with special case values r=n + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101", + "result" : "invalid" + }, + { + "tcId" : 206, + "comment" : "Signature with special case values r=n + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff", + "result" : "invalid" + }, + { + "tcId" : 207, + "comment" : "Signature with special case values r=n + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 208, + "comment" : "Signature with special case values r=n + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 209, + "comment" : "Signature with special case values r=n + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 210, + "comment" : "Signature with special case values r=n + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 211, + "comment" : "Signature with special case values r=n + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 212, + "comment" : "Signature with special case values r=p and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100", + "result" : "invalid" + }, + { + "tcId" : 213, + "comment" : "Signature with special case values r=p and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101", + "result" : "invalid" + }, + { + "tcId" : 214, + "comment" : "Signature with special case values r=p and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff", + "result" : "invalid" + }, + { + "tcId" : 215, + "comment" : "Signature with special case values r=p and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 216, + "comment" : "Signature with special case values r=p and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 217, + "comment" : "Signature with special case values r=p and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 218, + "comment" : "Signature with special case values r=p and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 219, + "comment" : "Signature with special case values r=p and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 220, + "comment" : "Signature with special case values r=p + 1 and s=0", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100", + "result" : "invalid" + }, + { + "tcId" : 221, + "comment" : "Signature with special case values r=p + 1 and s=1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101", + "result" : "invalid" + }, + { + "tcId" : 222, + "comment" : "Signature with special case values r=p + 1 and s=-1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff", + "result" : "invalid" + }, + { + "tcId" : 223, + "comment" : "Signature with special case values r=p + 1 and s=n", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "result" : "invalid" + }, + { + "tcId" : 224, + "comment" : "Signature with special case values r=p + 1 and s=n - 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "result" : "invalid" + }, + { + "tcId" : 225, + "comment" : "Signature with special case values r=p + 1 and s=n + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142", + "result" : "invalid" + }, + { + "tcId" : 226, + "comment" : "Signature with special case values r=p + 1 and s=p", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "result" : "invalid" + }, + { + "tcId" : 227, + "comment" : "Signature with special case values r=p + 1 and s=p + 1", + "flags" : [ + "InvalidSignature" + ], + "msg" : "313233343030", + "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30", + "result" : "invalid" + }, + { + "tcId" : 228, + "comment" : "Signature encoding contains incorrect types: r=0, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020100090380fe01", + "result" : "invalid" + }, + { + "tcId" : 229, + "comment" : "Signature encoding contains incorrect types: r=0, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100090142", + "result" : "invalid" + }, + { + "tcId" : 230, + "comment" : "Signature encoding contains incorrect types: r=0, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010101", + "result" : "invalid" + }, + { + "tcId" : 231, + "comment" : "Signature encoding contains incorrect types: r=0, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020100010100", + "result" : "invalid" + }, + { + "tcId" : 232, + "comment" : "Signature encoding contains incorrect types: r=0, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000500", + "result" : "invalid" + }, + { + "tcId" : 233, + "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201000c00", + "result" : "invalid" + }, + { + "tcId" : 234, + "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201000c0130", + "result" : "invalid" + }, + { + "tcId" : 235, + "comment" : "Signature encoding contains incorrect types: r=0, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201003000", + "result" : "invalid" + }, + { + "tcId" : 236, + "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201003003020100", + "result" : "invalid" + }, + { + "tcId" : 237, + "comment" : "Signature encoding contains incorrect types: r=1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008020101090380fe01", + "result" : "invalid" + }, + { + "tcId" : 238, + "comment" : "Signature encoding contains incorrect types: r=1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101090142", + "result" : "invalid" + }, + { + "tcId" : 239, + "comment" : "Signature encoding contains incorrect types: r=1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010101", + "result" : "invalid" + }, + { + "tcId" : 240, + "comment" : "Signature encoding contains incorrect types: r=1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006020101010100", + "result" : "invalid" + }, + { + "tcId" : 241, + "comment" : "Signature encoding contains incorrect types: r=1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010500", + "result" : "invalid" + }, + { + "tcId" : 242, + "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201010c00", + "result" : "invalid" + }, + { + "tcId" : 243, + "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201010c0130", + "result" : "invalid" + }, + { + "tcId" : 244, + "comment" : "Signature encoding contains incorrect types: r=1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201013000", + "result" : "invalid" + }, + { + "tcId" : 245, + "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201013003020100", + "result" : "invalid" + }, + { + "tcId" : 246, + "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff090380fe01", + "result" : "invalid" + }, + { + "tcId" : 247, + "comment" : "Signature encoding contains incorrect types: r=-1, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff090142", + "result" : "invalid" + }, + { + "tcId" : 248, + "comment" : "Signature encoding contains incorrect types: r=-1, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010101", + "result" : "invalid" + }, + { + "tcId" : 249, + "comment" : "Signature encoding contains incorrect types: r=-1, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff010100", + "result" : "invalid" + }, + { + "tcId" : 250, + "comment" : "Signature encoding contains incorrect types: r=-1, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0500", + "result" : "invalid" + }, + { + "tcId" : 251, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff0c00", + "result" : "invalid" + }, + { + "tcId" : 252, + "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060201ff0c0130", + "result" : "invalid" + }, + { + "tcId" : 253, + "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050201ff3000", + "result" : "invalid" + }, + { + "tcId" : 254, + "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30080201ff3003020100", + "result" : "invalid" + }, + { + "tcId" : 255, + "comment" : "Signature encoding contains incorrect types: r=n, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01", + "result" : "invalid" + }, + { + "tcId" : 256, + "comment" : "Signature encoding contains incorrect types: r=n, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142", + "result" : "invalid" + }, + { + "tcId" : 257, + "comment" : "Signature encoding contains incorrect types: r=n, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101", + "result" : "invalid" + }, + { + "tcId" : 258, + "comment" : "Signature encoding contains incorrect types: r=n, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100", + "result" : "invalid" + }, + { + "tcId" : 259, + "comment" : "Signature encoding contains incorrect types: r=n, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500", + "result" : "invalid" + }, + { + "tcId" : 260, + "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00", + "result" : "invalid" + }, + { + "tcId" : 261, + "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130", + "result" : "invalid" + }, + { + "tcId" : 262, + "comment" : "Signature encoding contains incorrect types: r=n, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000", + "result" : "invalid" + }, + { + "tcId" : 263, + "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100", + "result" : "invalid" + }, + { + "tcId" : 264, + "comment" : "Signature encoding contains incorrect types: r=p, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01", + "result" : "invalid" + }, + { + "tcId" : 265, + "comment" : "Signature encoding contains incorrect types: r=p, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142", + "result" : "invalid" + }, + { + "tcId" : 266, + "comment" : "Signature encoding contains incorrect types: r=p, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101", + "result" : "invalid" + }, + { + "tcId" : 267, + "comment" : "Signature encoding contains incorrect types: r=p, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100", + "result" : "invalid" + }, + { + "tcId" : 268, + "comment" : "Signature encoding contains incorrect types: r=p, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500", + "result" : "invalid" + }, + { + "tcId" : 269, + "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00", + "result" : "invalid" + }, + { + "tcId" : 270, + "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130", + "result" : "invalid" + }, + { + "tcId" : 271, + "comment" : "Signature encoding contains incorrect types: r=p, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000", + "result" : "invalid" + }, + { + "tcId" : 272, + "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100", + "result" : "invalid" + }, + { + "tcId" : 273, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a090380fe01090380fe01", + "result" : "invalid" + }, + { + "tcId" : 274, + "comment" : "Signature encoding contains incorrect types: r=nan, s=nan", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142090142", + "result" : "invalid" + }, + { + "tcId" : 275, + "comment" : "Signature encoding contains incorrect types: r=True, s=True", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101010101", + "result" : "invalid" + }, + { + "tcId" : 276, + "comment" : "Signature encoding contains incorrect types: r=False, s=False", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100010100", + "result" : "invalid" + }, + { + "tcId" : 277, + "comment" : "Signature encoding contains incorrect types: r=Null, s=Null", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300405000500", + "result" : "invalid" + }, + { + "tcId" : 278, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30040c000c00", + "result" : "invalid" + }, + { + "tcId" : 279, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c01300c0130", + "result" : "invalid" + }, + { + "tcId" : 280, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300430003000", + "result" : "invalid" + }, + { + "tcId" : 281, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "300a30030201003003020100", + "result" : "invalid" + }, + { + "tcId" : 282, + "comment" : "Signature encoding contains incorrect types: r=0.25, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3008090380fe01020100", + "result" : "invalid" + }, + { + "tcId" : 283, + "comment" : "Signature encoding contains incorrect types: r=nan, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006090142020100", + "result" : "invalid" + }, + { + "tcId" : 284, + "comment" : "Signature encoding contains incorrect types: r=True, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010101020100", + "result" : "invalid" + }, + { + "tcId" : 285, + "comment" : "Signature encoding contains incorrect types: r=False, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "3006010100020100", + "result" : "invalid" + }, + { + "tcId" : 286, + "comment" : "Signature encoding contains incorrect types: r=Null, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050500020100", + "result" : "invalid" + }, + { + "tcId" : 287, + "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30050c00020100", + "result" : "invalid" + }, + { + "tcId" : 288, + "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30060c0130020100", + "result" : "invalid" + }, + { + "tcId" : 289, + "comment" : "Signature encoding contains incorrect types: r=empty list, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30053000020100", + "result" : "invalid" + }, + { + "tcId" : 290, + "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0", + "flags" : [ + "InvalidTypesInSignature" + ], + "msg" : "313233343030", + "sig" : "30083003020100020100", + "result" : "invalid" + }, + { + "tcId" : 291, + "comment" : "Edge case for Shamir multiplication", + "flags" : [ + "EdgeCaseShamirMultiplication" + ], + "msg" : "3235353835", + "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06", + "result" : "valid" + }, + { + "tcId" : 292, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343236343739373234", + "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640", + "result" : "valid" + }, + { + "tcId" : 293, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37313338363834383931", + "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3", + "result" : "valid" + }, + { + "tcId" : 294, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130333539333331363638", + "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f", + "result" : "valid" + }, + { + "tcId" : 295, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33393439343031323135", + "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16", + "result" : "valid" + }, + { + "tcId" : 296, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333434323933303739", + "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648", + "result" : "valid" + }, + { + "tcId" : 297, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33373036323131373132", + "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56", + "result" : "valid" + }, + { + "tcId" : 298, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333433363838373132", + "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7", + "result" : "valid" + }, + { + "tcId" : 299, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31333531353330333730", + "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6", + "result" : "valid" + }, + { + "tcId" : 300, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36353533323033313236", + "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9", + "result" : "valid" + }, + { + "tcId" : 301, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353634333436363033", + "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a", + "result" : "valid" + }, + { + "tcId" : 302, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34343239353339313137", + "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e", + "result" : "valid" + }, + { + "tcId" : 303, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130393533323631333531", + "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc", + "result" : "valid" + }, + { + "tcId" : 304, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393837333530303431", + "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe", + "result" : "valid" + }, + { + "tcId" : 305, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343633303036383738", + "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc", + "result" : "valid" + }, + { + "tcId" : 306, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39383137333230323837", + "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3", + "result" : "valid" + }, + { + "tcId" : 307, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323232303431303436", + "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33", + "result" : "valid" + }, + { + "tcId" : 308, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36363636333037313034", + "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008", + "result" : "valid" + }, + { + "tcId" : 309, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303335393531383938", + "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022", + "result" : "valid" + }, + { + "tcId" : 310, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31383436353937313935", + "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd", + "result" : "valid" + }, + { + "tcId" : 311, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33313336303436313839", + "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149", + "result" : "valid" + }, + { + "tcId" : 312, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363633373834323534", + "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1", + "result" : "valid" + }, + { + "tcId" : 313, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363532313030353234", + "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984", + "result" : "valid" + }, + { + "tcId" : 314, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35373438303831363936", + "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17", + "result" : "valid" + }, + { + "tcId" : 315, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36333433393133343638", + "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52", + "result" : "valid" + }, + { + "tcId" : 316, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31353431313033353938", + "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c", + "result" : "valid" + }, + { + "tcId" : 317, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130343738353830313238", + "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c", + "result" : "valid" + }, + { + "tcId" : 318, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130353336323835353638", + "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d", + "result" : "valid" + }, + { + "tcId" : 319, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393533393034313035", + "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7", + "result" : "valid" + }, + { + "tcId" : 320, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "393738383438303339", + "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5", + "result" : "valid" + }, + { + "tcId" : 321, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33363130363732343432", + "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7", + "result" : "valid" + }, + { + "tcId" : 322, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31303534323430373035", + "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e", + "result" : "valid" + }, + { + "tcId" : 323, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35313734343438313937", + "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe", + "result" : "valid" + }, + { + "tcId" : 324, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31393637353631323531", + "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59", + "result" : "valid" + }, + { + "tcId" : 325, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33343437323533333433", + "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3", + "result" : "valid" + }, + { + "tcId" : 326, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333638323634333138", + "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b", + "result" : "valid" + }, + { + "tcId" : 327, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33323631313938363038", + "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f", + "result" : "valid" + }, + { + "tcId" : 328, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "39363738373831303934", + "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd", + "result" : "valid" + }, + { + "tcId" : 329, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34393538383233383233", + "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867", + "result" : "valid" + }, + { + "tcId" : 330, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "383234363337383337", + "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa", + "result" : "valid" + }, + { + "tcId" : 331, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3131303230383333373736", + "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754", + "result" : "valid" + }, + { + "tcId" : 332, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "313333383731363438", + "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5", + "result" : "valid" + }, + { + "tcId" : 333, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "333232313434313632", + "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417", + "result" : "valid" + }, + { + "tcId" : 334, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3130363836363535353436", + "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee", + "result" : "valid" + }, + { + "tcId" : 335, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "3632313535323436", + "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897", + "result" : "valid" + }, + { + "tcId" : 336, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "37303330383138373734", + "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9", + "result" : "valid" + }, + { + "tcId" : 337, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "35393234353233373434", + "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29", + "result" : "valid" + }, + { + "tcId" : 338, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31343935353836363231", + "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56", + "result" : "valid" + }, + { + "tcId" : 339, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "34303035333134343036", + "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609", + "result" : "valid" + }, + { + "tcId" : 340, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "33303936343537353132", + "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a", + "result" : "valid" + }, + { + "tcId" : 341, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32373834303235363230", + "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f", + "result" : "valid" + }, + { + "tcId" : 342, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "32363138373837343138", + "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728", + "result" : "valid" + }, + { + "tcId" : 343, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "31363432363235323632", + "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db", + "result" : "valid" + }, + { + "tcId" : 344, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "36383234313839343336", + "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921", + "result" : "valid" + }, + { + "tcId" : 345, + "comment" : "special case hash", + "flags" : [ + "SpecialCaseHash" + ], + "msg" : "343834323435343235", + "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362", + "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 346, + "comment" : "k*G has a large x-coordinate", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103", + "result" : "valid" + }, + { + "tcId" : 347, + "comment" : "r too large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22", + "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 348, + "comment" : "r,s are large", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252", + "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 349, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c", + "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 350, + "comment" : "r and s^-1 have a large Hamming weight", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce", + "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 351, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50", + "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 352, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718", + "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 353, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020101020103", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373", + "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 354, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020101", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19", + "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 355, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020102", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5", + "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 356, + "comment" : "small r and s", + "flags" : [ + "SmallRandS", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3006020102020103", + "result" : "valid" + }, + { + "tcId" : 357, + "comment" : "r is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24", + "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 358, + "comment" : "s is larger than n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30080201020203ed2979", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77", + "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 359, + "comment" : "small r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584", + "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 360, + "comment" : "smallish r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c", + "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 361, + "comment" : "100-bit r and small s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0", + "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 362, + "comment" : "small r and 100 bit s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65", + "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 363, + "comment" : "100-bit r and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06", + "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 364, + "comment" : "r and s^-1 are close to n", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8", + "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 365, + "comment" : "r and s are 64-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9", + "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 366, + "comment" : "r and s are 100-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197", + "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 367, + "comment" : "r and s are 128-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653", + "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 368, + "comment" : "r and s are 160-bit integer", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c", + "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 369, + "comment" : "s == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101", + "result" : "valid" + }, + { + "tcId" : 370, + "comment" : "s == 0", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36", + "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 371, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da", + "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 372, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8", + "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 373, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a", + "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 374, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb", + "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 375, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14", + "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 376, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e", + "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 377, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9", + "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 378, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470", + "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 379, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001", + "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 380, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db", + "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 381, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4", + "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 382, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da", + "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 383, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e", + "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 384, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f", + "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 385, + "comment" : "edge case modular inverse", + "flags" : [ + "ModularInverse", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874", + "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 386, + "comment" : "point at infinity during verify", + "flags" : [ + "PointDuplication", + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4", + "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 387, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80", + "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 388, + "comment" : "edge case for signature malleability", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c", + "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 389, + "comment" : "u1 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976", + "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 390, + "comment" : "u1 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e", + "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 391, + "comment" : "u2 == 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288", + "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 392, + "comment" : "u2 == n - 1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2", + "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 393, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4", + "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 394, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a", + "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 395, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058", + "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 396, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402", + "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 397, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8", + "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 398, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7", + "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 399, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db", + "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 400, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914", + "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 401, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66", + "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 402, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a", + "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 403, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa", + "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 404, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7", + "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 405, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a", + "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 406, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe", + "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 407, + "comment" : "edge case for u1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3", + "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 408, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7", + "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 409, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60", + "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 410, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff", + "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 411, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d", + "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 412, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace", + "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 413, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a", + "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 414, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6", + "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 415, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156", + "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 416, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d", + "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 417, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b", + "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 418, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337", + "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 419, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046", + "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 420, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf", + "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 421, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277", + "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 422, + "comment" : "edge case for u2", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 423, + "comment" : "point duplication during verification", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385", + "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 424, + "comment" : "duplication bug", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e", + "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 425, + "comment" : "comparison with point at infinity ", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f", + "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 426, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e", + "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 427, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952", + "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 428, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee", + "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 429, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32", + "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 430, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc", + "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 431, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818", + "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 432, + "comment" : "extreme value for k and edgecase s", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e", + "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 433, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3", + "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 434, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1", + "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 435, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b", + "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 436, + "comment" : "extreme value for k and s^-1", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a", + "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 437, + "comment" : "extreme value for k", + "flags" : [ + "ArithmeticError" + ], + "msg" : "313233343030", + "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 438, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 439, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 440, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + }, + { + "tcId" : 441, + "comment" : "public key shares x-coordinate with generator", + "flags" : [ + "PointDuplication" + ], + "msg" : "313233343030", + "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952", + "result" : "invalid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963", + "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 442, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "", + "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b", + "result" : "valid" + }, + { + "tcId" : 443, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "4d7367", + "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b", + "result" : "valid" + }, + { + "tcId" : 444, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "313233343030", + "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6", + "result" : "valid" + }, + { + "tcId" : 445, + "comment" : "pseudorandom signature", + "flags" : [ + "ValidSignature" + ], + "msg" : "0000000000000000000000000000000000000000", + "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 446, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7", + "result" : "valid" + }, + { + "tcId" : 447, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d", + "result" : "valid" + }, + { + "tcId" : 448, + "comment" : "y-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff", + "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 449, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e", + "result" : "valid" + }, + { + "tcId" : 450, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d", + "result" : "valid" + }, + { + "tcId" : 451, + "comment" : "y-coordinate of the public key is large", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0", + "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 452, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da", + "result" : "valid" + }, + { + "tcId" : 453, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4", + "result" : "valid" + }, + { + "tcId" : 454, + "comment" : "x-coordinate of the public key is small", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff", + "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 455, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022", + "result" : "valid" + }, + { + "tcId" : 456, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f", + "result" : "valid" + }, + { + "tcId" : 457, + "comment" : "x-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9", + "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 458, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1", + "result" : "valid" + }, + { + "tcId" : 459, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d", + "result" : "valid" + }, + { + "tcId" : 460, + "comment" : "y-coordinate of the public key has many trailing 1's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16", + "result" : "valid" + } + ] + }, + { + "type" : "EcdsaBitcoinVerify", + "publicKey" : { + "type" : "EcPublicKey", + "curve" : "secp256k1", + "keySize" : 256, + "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000", + "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb" + }, + "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb", + "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n", + "sha" : "SHA-256", + "tests" : [ + { + "tcId" : 461, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4", + "result" : "valid" + }, + { + "tcId" : 462, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497", + "result" : "valid" + }, + { + "tcId" : 463, + "comment" : "x-coordinate of the public key has many trailing 0's", + "flags" : [ + "EdgeCasePublicKey" + ], + "msg" : "4d657373616765", + "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd", + "result" : "valid" + } + ] + } + ] +} diff --git a/crypto/secp256k1/libsecp256k1/tools/check-abi.sh b/crypto/secp256k1/libsecp256k1/tools/check-abi.sh new file mode 100755 index 000000000..601a64ba9 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/tools/check-abi.sh @@ -0,0 +1,74 @@ +#!/bin/sh + +set -eu + +default_base_version="$(git describe --match "v*.*.*" --abbrev=0)" +default_new_version="HEAD" + +display_help_and_exit() { + echo "Usage: $0 [ []]" + echo "" + echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI" + echo " of a new version of libsecp256k1 has changed in a backward-incompatible way." + echo "" + echo "Options:" + echo " base_ver Specify the base version as a git commit-ish" + echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")" + echo " new_ver Specify the new version as a git commit-ish" + echo " (default: $default_new_version)" + echo " -h, --help Display this help message" + exit 0 +} + +if [ "$#" -eq 0 ]; then + base_version="$default_base_version" + new_version="$default_new_version" +elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then + display_help_and_exit +elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then + base_version="$1" + if [ "$#" -eq 2 ]; then + new_version="$2" + fi +else + echo "Invalid usage. See help:" + echo "" + display_help_and_exit +fi + +checkout_and_build() { + _orig_dir="$(pwd)" + git worktree add --detach "$1" "$2" + cd "$1" + mkdir build && cd build + cmake -S .. --preset dev-mode \ + -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DSECP256K1_BUILD_CTIME_TESTS=OFF \ + -DSECP256K1_BUILD_EXAMPLES=OFF + cmake --build . -j "$(nproc)" + # FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is + # released. + if [ -f "src/libsecp256k1.so" ]; then + LIBPATH="src/libsecp256k1.so" + else + LIBPATH="lib/libsecp256k1.so" + fi + abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/ + cd "$_orig_dir" +} + +echo "Comparing $base_version (base version) to $new_version (new version)" +echo + +base_source_dir="$(mktemp -d)" +checkout_and_build "$base_source_dir" "$base_version" + +new_source_dir="$(mktemp -d)" +checkout_and_build "$new_source_dir" "$new_version" + +abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump" +git worktree remove "$base_source_dir" +git worktree remove "$new_source_dir" diff --git a/crypto/secp256k1/libsecp256k1/tools/test_vectors_musig2_generate.py b/crypto/secp256k1/libsecp256k1/tools/test_vectors_musig2_generate.py new file mode 100755 index 000000000..97424419f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/tools/test_vectors_musig2_generate.py @@ -0,0 +1,656 @@ +#!/usr/bin/env python3 + +import sys +import json +import textwrap + +max_pubkeys = 0 + +if len(sys.argv) < 2: + print( + "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework." + ) + print("Usage: %s " % sys.argv[0]) + sys.exit(1) + + +def hexstr_to_intarray(str): + return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)]) + + +def create_init(name): + return """ +static const struct musig_%s_vector musig_%s_vector = { +""" % ( + name, + name, + ) + + +def init_array(key): + return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ") + + +def init_arrays(key): + s = textwrap.indent("{\n", 4 * " ") + s += textwrap.indent( + ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " " + ) + s += textwrap.indent("\n},\n", 4 * " ") + return s + + +def init_indices(array): + return " %d, { %s }" % ( + len(array), + ", ".join(map(str, array) if len(array) > 0 else "0"), + ) + + +def init_is_xonly(case): + if len(case["tweak_indices"]) > 0: + return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"])) + return "0" + + +def init_optional_expected(case): + return hexstr_to_intarray(case["expected"]) if "expected" in case else 0 + + +def init_cases(cases, f): + s = textwrap.indent("{\n", 4 * " ") + for (i, case) in enumerate(cases): + s += textwrap.indent("%s\n" % f(case), 8 * " ") + s += textwrap.indent("},\n", 4 * " ") + return s + + +def finish_init(): + return "};\n" + + +s = ( + """/** + * Automatically generated by %s. + * + * The test vectors for the KeySort function are included in this file. They can + * be found in src/modules/extrakeys/tests_impl.h. */ +""" + % sys.argv[0] +) + + +s += """ +enum MUSIG_ERROR { + MUSIG_PUBKEY, + MUSIG_TWEAK, + MUSIG_PUBNONCE, + MUSIG_AGGNONCE, + MUSIG_SECNONCE, + MUSIG_SIG, + MUSIG_SIG_VERIFY, + MUSIG_OTHER +}; +""" + +# key agg vectors +with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f: + data = json.load(f) + + max_key_indices = max( + len(test_case["key_indices"]) for test_case in data["valid_test_cases"] + ) + max_tweak_indices = max( + len(test_case["tweak_indices"]) for test_case in data["error_test_cases"] + ) + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + # Add structures for valid and error cases + s += ( + """ +struct musig_key_agg_valid_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + s += """ +struct musig_key_agg_error_test_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_key_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + struct musig_key_agg_valid_test_case valid_case[%d]; + struct musig_key_agg_error_test_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + + s += create_init("key_agg") + # Add pubkeys and tweaks to the vector + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + + # Add valid cases to the vector + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, { %s }}," + % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])), + ) + + def comment_to_error(case): + comment = case["comment"] + if "public key" in comment.lower(): + return "MUSIG_PUBKEY" + elif "tweak" in comment.lower(): + return "MUSIG_TWEAK" + else: + sys.exit("Unknown error") + + # Add error cases to the vector + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, { %s }, %s }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + comment_to_error(case), + ), + ) + + s += finish_init() + +# nonce gen vectors +with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + data["test_cases"] = list( + filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"]) + ) + + num_tests = len(data["test_cases"]) + + s += """ +struct musig_nonce_gen_test_case { + unsigned char rand_[32]; + int has_sk; + unsigned char sk[32]; + unsigned char pk[33]; + int has_aggpk; + unsigned char aggpk[32]; + int has_msg; + unsigned char msg[32]; + int has_extra_in; + unsigned char extra_in[32]; + unsigned char expected_secnonce[97]; + unsigned char expected_pubnonce[66]; +}; +""" + + s += ( + """ +struct musig_nonce_gen_vector { + struct musig_nonce_gen_test_case test_case[%d]; +}; +""" + % num_tests + ) + + s += create_init("nonce_gen") + + def init_array_maybe(array): + return "%d , { %s }" % ( + 0 if array is None else 1, + hexstr_to_intarray(array) if array is not None else 0, + ) + + s += init_cases( + data["test_cases"], + lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } }," + % ( + hexstr_to_intarray(case["rand_"]), + init_array_maybe(case["sk"]), + hexstr_to_intarray(case["pk"]), + init_array_maybe(case["aggpk"]), + init_array_maybe(case["msg"]), + init_array_maybe(case["extra_in"]), + hexstr_to_intarray(case["expected_secnonce"]), + hexstr_to_intarray(case["expected_pubnonce"]), + ), + ) + + s += finish_init() + +# nonce agg vectors +with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pnonces = len(data["pnonces"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + pnonce_indices_len = 2 + for case in data["valid_test_cases"] + data["error_test_cases"]: + assert len(case["pnonce_indices"]) == pnonce_indices_len + + # Add structures for valid and error cases + s += """ +struct musig_nonce_agg_test_case { + size_t pnonce_indices[2]; + /* if valid case */ + unsigned char expected[66]; + /* if error case */ + int invalid_nonce_idx; +}; +""" + # Add structure for entire vector + s += """ +struct musig_nonce_agg_vector { + unsigned char pnonces[%d][66]; + struct musig_nonce_agg_test_case valid_case[%d]; + struct musig_nonce_agg_test_case error_case[%d]; +}; +""" % ( + num_pnonces, + num_valid_cases, + num_error_cases, + ) + + s += create_init("nonce_agg") + s += init_arrays("pnonces") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ { %s }, { %s }, %d }," + % ( + ", ".join(map(str, case["pnonce_indices"])), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() + +# sign/verify vectors +with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f: + data = json.load(f) + + # The MuSig2 implementation only allows messages of length 32 + assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0] + data["msgs"] = [data["msgs"][0]] + + def filter_msg32(k): + return list(filter(lambda x: x["msg_index"] == 0, data[k])) + + data["valid_test_cases"] = filter_msg32("valid_test_cases") + data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases") + data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases") + data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases") + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_secnonces = len(data["secnonces"]) + num_pubnonces = len(data["pnonces"]) + num_aggnonces = len(data["aggnonces"]) + num_msgs = len(data["msgs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_sign_error_cases = len(data["sign_error_test_cases"]) + num_verify_fail_cases = len(data["verify_fail_test_cases"]) + num_verify_error_cases = len(data["verify_error_test_cases"]) + + all_cases = ( + data["valid_test_cases"] + + data["sign_error_test_cases"] + + data["verify_error_test_cases"] + + data["verify_fail_test_cases"] + ) + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_nonce_indices = max( + len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0 + for test_case in all_cases + ) + # Add structures for valid and error cases + s += ( + """ +/* Omit pubnonces in the test vectors because our partial signature verification + * implementation is able to accept the aggnonce directly. */ +struct musig_valid_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t signer_index; + unsigned char expected[32]; +}; +""" + % max_key_indices + ) + + s += ( + """ +struct musig_sign_error_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t aggnonce_index; + size_t msg_index; + size_t secnonce_index; + enum MUSIG_ERROR error; +}; +""" + % max_key_indices + ) + + s += """ +struct musig_verify_fail_error_case { + unsigned char sig[32]; + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t msg_index; + size_t signer_index; + enum MUSIG_ERROR error; +}; +""" % ( + max_key_indices, + max_nonce_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sign_verify_vector { + unsigned char sk[32]; + unsigned char pubkeys[%d][33]; + unsigned char secnonces[%d][194]; + unsigned char pubnonces[%d][194]; + unsigned char aggnonces[%d][66]; + unsigned char msgs[%d][32]; + struct musig_valid_case valid_case[%d]; + struct musig_sign_error_case sign_error_case[%d]; + struct musig_verify_fail_error_case verify_fail_case[%d]; + struct musig_verify_fail_error_case verify_error_case[%d]; +}; +""" % ( + num_pubkeys, + num_secnonces, + num_pubnonces, + num_aggnonces, + num_msgs, + num_valid_cases, + num_sign_error_cases, + num_verify_fail_cases, + num_verify_error_cases, + ) + + s += create_init("sign_verify") + s += init_array("sk") + s += init_arrays("pubkeys") + s += init_arrays("secnonces") + s += init_arrays("pnonces") + s += init_arrays("aggnonces") + s += init_arrays("msgs") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %d, %d, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["signer_index"], + init_optional_expected(case), + ), + ) + + def sign_error(case): + comment = case["comment"] + if "pubkey" in comment or "public key" in comment: + return "MUSIG_PUBKEY" + elif "Aggregate nonce" in comment: + return "MUSIG_AGGNONCE" + elif "Secnonce" in comment: + return "MUSIG_SECNONCE" + else: + sys.exit("Unknown sign error") + + s += init_cases( + data["sign_error_test_cases"], + lambda case: "{ %s, %d, %d, %d, %s }," + % ( + init_indices(case["key_indices"]), + case["aggnonce_index"], + case["msg_index"], + case["secnonce_index"], + sign_error(case), + ), + ) + + def verify_error(case): + comment = case["comment"] + if "exceeds" in comment: + return "MUSIG_SIG" + elif "Wrong signer" in comment or "Wrong signature" in comment: + return "MUSIG_SIG_VERIFY" + elif "pubnonce" in comment: + return "MUSIG_PUBNONCE" + elif "pubkey" in comment: + return "MUSIG_PUBKEY" + else: + sys.exit("Unknown verify error") + + for cases in ("verify_fail_test_cases", "verify_error_test_cases"): + s += init_cases( + data[cases], + lambda case: "{ { %s }, %s, %s, %d, %d, %s }," + % ( + hexstr_to_intarray(case["sig"]), + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + case["msg_index"], + case["signer_index"], + verify_error(case), + ), + ) + + s += finish_init() + +# tweak vectors +with open(sys.argv[1] + "/tweak_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_pubnonces = len(data["pnonces"]) + num_tweaks = len(data["tweaks"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases) + # Add structures for valid and error cases + s += """ +struct musig_tweak_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t nonce_indices_len; + size_t nonce_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + size_t signer_index; + unsigned char expected[32]; +}; +""" % ( + max_key_indices, + max_nonce_indices, + max_tweak_indices, + max_tweak_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_tweak_vector { + unsigned char sk[32]; + unsigned char secnonce[97]; + unsigned char aggnonce[66]; + unsigned char msg[32]; + unsigned char pubkeys[%d][33]; + unsigned char pubnonces[%d][194]; + unsigned char tweaks[%d][32]; + struct musig_tweak_case valid_case[%d]; + struct musig_tweak_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_pubnonces, + num_tweaks, + num_valid_cases, + num_error_cases, + ) + s += create_init("tweak") + s += init_array("sk") + s += init_array("secnonce") + s += init_array("aggnonce") + s += init_array("msg") + s += init_arrays("pubkeys") + s += init_arrays("pnonces") + s += init_arrays("tweaks") + + s += init_cases( + data["valid_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += init_cases( + data["error_test_cases"], + lambda case: "{ %s, %s, %s, { %s }, %d, { %s }}," + % ( + init_indices(case["key_indices"]), + init_indices(case["nonce_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + case["signer_index"], + init_optional_expected(case), + ), + ) + + s += finish_init() + +# sigagg vectors +with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f: + data = json.load(f) + + num_pubkeys = len(data["pubkeys"]) + max_pubkeys = max(num_pubkeys, max_pubkeys) + num_tweaks = len(data["tweaks"]) + num_psigs = len(data["psigs"]) + num_valid_cases = len(data["valid_test_cases"]) + num_error_cases = len(data["error_test_cases"]) + + all_cases = data["valid_test_cases"] + data["error_test_cases"] + max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases) + max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases) + max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases) + + # Add structures for valid and error cases + s += """ +/* Omit pubnonces in the test vectors because they're only needed for + * implementations that do not directly accept an aggnonce. */ +struct musig_sig_agg_case { + size_t key_indices_len; + size_t key_indices[%d]; + size_t tweak_indices_len; + size_t tweak_indices[%d]; + int is_xonly[%d]; + unsigned char aggnonce[66]; + size_t psig_indices_len; + size_t psig_indices[%d]; + /* if valid case */ + unsigned char expected[64]; + /* if error case */ + int invalid_sig_idx; +}; +""" % ( + max_key_indices, + max_tweak_indices, + max_tweak_indices, + max_psig_indices, + ) + + # Add structure for entire vector + s += """ +struct musig_sig_agg_vector { + unsigned char pubkeys[%d][33]; + unsigned char tweaks[%d][32]; + unsigned char psigs[%d][32]; + unsigned char msg[32]; + struct musig_sig_agg_case valid_case[%d]; + struct musig_sig_agg_case error_case[%d]; +}; +""" % ( + num_pubkeys, + num_tweaks, + num_psigs, + num_valid_cases, + num_error_cases, + ) + + s += create_init("sig_agg") + s += init_arrays("pubkeys") + s += init_arrays("tweaks") + s += init_arrays("psigs") + s += init_array("msg") + + for cases in (data["valid_test_cases"], data["error_test_cases"]): + s += init_cases( + cases, + lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d }," + % ( + init_indices(case["key_indices"]), + init_indices(case["tweak_indices"]), + init_is_xonly(case), + hexstr_to_intarray(case["aggnonce"]), + init_indices(case["psig_indices"]), + init_optional_expected(case), + case["error"]["signer"] if "error" in case else 0, + ), + ) + s += finish_init() +s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys +print(s) diff --git a/crypto/secp256k1/libsecp256k1/tools/tests_wycheproof_generate.py b/crypto/secp256k1/libsecp256k1/tools/tests_wycheproof_generate.py new file mode 100755 index 000000000..b26dfa89d --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/tools/tests_wycheproof_generate.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php. +''' +Generate a C file with ECDSA testvectors from the Wycheproof project. +''' + +import json +import sys + +filename_input = sys.argv[1] + +with open(filename_input) as f: + doc = json.load(f) + +num_groups = len(doc['testGroups']) + +def to_c_array(x): + if x == "": + return "" + s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2])) + return "0x" + s + + +num_vectors = 0 +offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0 +out = "" +messages = "" +signatures = "" +public_keys = "" +cache_msgs = {} +cache_public_keys = {} + +for i in range(num_groups): + group = doc['testGroups'][i] + num_tests = len(group['tests']) + public_key = group['publicKey'] + for j in range(num_tests): + test_vector = group['tests'][j] + # // 2 to convert hex to byte length + sig_size = len(test_vector['sig']) // 2 + msg_size = len(test_vector['msg']) // 2 + + if test_vector['result'] == "invalid": + expected_verify = 0 + elif test_vector['result'] == "valid": + expected_verify = 1 + else: + raise ValueError("invalid result field") + + if num_vectors != 0 and sig_size != 0: + signatures += ",\n " + + new_msg = False + msg = to_c_array(test_vector['msg']) + msg_offset = offset_msg_running + # check for repeated msg + if msg not in cache_msgs: + if num_vectors != 0 and msg_size != 0: + messages += ",\n " + cache_msgs[msg] = offset_msg_running + messages += msg + new_msg = True + else: + msg_offset = cache_msgs[msg] + + new_pk = False + pk = to_c_array(public_key['uncompressed']) + pk_offset = offset_pk_running + # check for repeated pk + if pk not in cache_public_keys: + if num_vectors != 0: + public_keys += ",\n " + cache_public_keys[pk] = offset_pk_running + public_keys += pk + new_pk = True + else: + pk_offset = cache_public_keys[pk] + + signatures += to_c_array(test_vector['sig']) + + out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n" + out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n" + if new_msg: + offset_msg_running += msg_size + if new_pk: + offset_pk_running += 65 + offset_sig += sig_size + num_vectors += 1 + +struct_definition = """ +typedef struct { + size_t pk_offset; + size_t msg_offset; + size_t msg_len; + size_t sig_offset; + size_t sig_len; + int expected_verify; +} wycheproof_ecdsa_testvector; +""" + + +print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */") +print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})") + +print(struct_definition) + +print("static const unsigned char wycheproof_ecdsa_messages[] = { " + messages + "};\n") +print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n") +print("static const unsigned char wycheproof_ecdsa_signatures[] = { " + signatures + "};\n") + +print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {") +print(out) +print("};") diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 61abc1eaf..60ae7d9e5 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -12,25 +12,14 @@ package secp256k1 #cgo CFLAGS: -I./libsecp256k1 #cgo CFLAGS: -I./libsecp256k1/src/ -#ifdef __SIZEOF_INT128__ -# define HAVE___INT128 -# define USE_FIELD_5X52 -# define USE_SCALAR_4X64 -#else -# define USE_FIELD_10X26 -# define USE_SCALAR_8X32 -#endif - #ifndef NDEBUG # define NDEBUG #endif -#define USE_ENDOMORPHISM -#define USE_NUM_NONE -#define USE_FIELD_INV_BUILTIN -#define USE_SCALAR_INV_BUILTIN #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" +#include "./libsecp256k1/src/precomputed_ecmult.c" +#include "./libsecp256k1/src/precomputed_ecmult_gen.c" #include "ext.h" typedef void (*callbackFunc) (const char* msg, void* data); From b9b7e4d41b97aed91113e86f0ac0d65dcd207503 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 13 Mar 2025 11:43:00 +0100 Subject: [PATCH 197/354] eth/ethconfig: add HistoryMode (#31365) Here I am adding a config option and geth flag (`--history.chain`) for configuring history pruning. There are two options available: - `--history.chain all` is the default and will keep all history like before. - `--history.chain postmerge` will configure the history cutoff point to the merge block. The option doesn't actually do anything right now, but we need it as a precursor for other history pruning changes. --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 21 +++++++-- core/blockchain.go | 10 ++++ core/genesis.go | 15 +++--- eth/backend.go | 43 ++++++++++++----- eth/ethconfig/config.go | 4 ++ eth/ethconfig/gen_config.go | 6 +++ eth/ethconfig/historymode.go | 90 ++++++++++++++++++++++++++++++++++++ 8 files changed, 168 insertions(+), 22 deletions(-) create mode 100644 eth/ethconfig/historymode.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8c596731a..1f7c59539 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -95,6 +95,7 @@ var ( utils.SnapshotFlag, utils.TxLookupLimitFlag, // deprecated utils.TransactionHistoryFlag, + utils.ChainHistoryFlag, utils.StateHistoryFlag, utils.LightServeFlag, // deprecated utils.LightIngressFlag, // deprecated diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 173bb6626..425762e94 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -273,6 +273,12 @@ var ( Value: ethconfig.Defaults.TransactionHistory, Category: flags.StateCategory, } + ChainHistoryFlag = &cli.StringFlag{ + Name: "history.chain", + Usage: `Blockchain history retention ("all" or "postmerge")`, + Value: ethconfig.Defaults.HistoryMode.String(), + Category: flags.StateCategory, + } // Beacon client light sync settings BeaconApiFlag = &cli.StringSliceFlag{ Name: "beacon.api", @@ -1716,10 +1722,19 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(SyncTargetFlag.Name) { cfg.SyncMode = downloader.FullSync // dev sync target forces full sync } else if ctx.IsSet(SyncModeFlag.Name) { - if err = cfg.SyncMode.UnmarshalText([]byte(ctx.String(SyncModeFlag.Name))); err != nil { - Fatalf("invalid --syncmode flag: %v", err) + value := ctx.String(SyncModeFlag.Name) + if err = cfg.SyncMode.UnmarshalText([]byte(value)); err != nil { + Fatalf("--%v: %v", SyncModeFlag.Name, err) + } + } + + if ctx.IsSet(ChainHistoryFlag.Name) { + value := ctx.String(ChainHistoryFlag.Name) + if err = cfg.HistoryMode.UnmarshalText([]byte(value)); err != nil { + Fatalf("--%s: %v", ChainHistoryFlag.Name, err) } } + if ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = ctx.Uint64(NetworkIdFlag.Name) } @@ -2261,7 +2276,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh gspec = MakeGenesis(ctx) chainDb = MakeChainDatabase(ctx, stack, readonly) ) - config, err := core.LoadChainConfig(chainDb, gspec) + config, _, err := core.LoadChainConfig(chainDb, gspec) if err != nil { Fatalf("%v", err) } diff --git a/core/blockchain.go b/core/blockchain.go index bdad7bbe7..ee132d178 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -157,6 +157,10 @@ type CacheConfig struct { SnapshotNoBuild bool // Whether the background generation is allowed SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it + + // This defines the cutoff block for history expiry. + // Blocks before this number may be unavailable in the chain database. + HistoryPruningCutoff uint64 } // triedbConfig derives the configures for trie database. @@ -2745,6 +2749,12 @@ func (bc *BlockChain) GetTrieFlushInterval() time.Duration { return time.Duration(bc.flushInterval.Load()) } +// HistoryPruningCutoff returns the configured history pruning point. +// Blocks before this might not be available in the database. +func (bc *BlockChain) HistoryPruningCutoff() uint64 { + return bc.cacheConfig.HistoryPruningCutoff +} + // getParentState retrieves statedb and parent header by hash or block number func (bc *BlockChain) getParentState(block *types.Block) (*state.StateDB, *types.Header, error) { parent := bc.GetBlockByHash(block.ParentHash()) diff --git a/core/genesis.go b/core/genesis.go index edbad8a10..19deb0401 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -392,7 +392,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g // LoadChainConfig loads the stored chain config if it is already present in // database, otherwise, return the config in the provided genesis specification. -func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, error) { +func LoadChainConfig(db ethdb.Database, genesis *Genesis) (cfg *params.ChainConfig, ghash common.Hash, err error) { // Load the stored chain config from the database. It can be nil // in case the database is empty. Notably, we only care about the // chain config corresponds to the canonical chain. @@ -400,27 +400,28 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, if stored != (common.Hash{}) { storedcfg := rawdb.ReadChainConfig(db, stored) if storedcfg != nil { - return storedcfg, nil + return storedcfg, stored, nil } } // Load the config from the provided genesis specification if genesis != nil { // Reject invalid genesis spec without valid chain config if genesis.Config == nil { - return nil, errGenesisNoConfig + return nil, common.Hash{}, errGenesisNoConfig } // If the canonical genesis header is present, but the chain // config is missing(initialize the empty leveldb with an // external ancient chain segment), ensure the provided genesis // is matched. - if stored != (common.Hash{}) && genesis.ToBlock().Hash() != stored { - return nil, &GenesisMismatchError{stored, genesis.ToBlock().Hash()} + ghash := genesis.ToBlock().Hash() + if stored != (common.Hash{}) && ghash != stored { + return nil, ghash, &GenesisMismatchError{stored, ghash} } - return genesis.Config, nil + return genesis.Config, ghash, nil } // There is no stored chain config and no new config provided, // In this case the default chain config(mainnet) will be used - return params.MainnetChainConfig, nil + return params.MainnetChainConfig, params.MainnetGenesisHash, nil } // chainConfigOrDefault retrieves the attached chain configuration. If the genesis diff --git a/eth/backend.go b/eth/backend.go index 1ec153db5..f1876e857 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -119,6 +119,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } + if !config.HistoryMode.IsValid() { + return nil, fmt.Errorf("invalid history mode %d", config.HistoryMode) + } if config.Miner.GasPrice == nil || config.Miner.GasPrice.Sign() <= 0 { log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) @@ -134,7 +137,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) - // Assemble the Ethereum object chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) if err != nil { return nil, err @@ -149,8 +151,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { log.Error("Failed to recover state", "error", err) } } - // Transfer mining-related config to the ethash config. - chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) + + // Here we determine genesis hash and active ChainConfig. + // We need these to figure out the consensus parameters and to set up history pruning. + chainConfig, genesisHash, err := core.LoadChainConfig(chainDb, config.Genesis) if err != nil { return nil, err } @@ -158,10 +162,24 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } + + // Validate history pruning configuration. + var historyPruningCutoff uint64 + if config.HistoryMode == ethconfig.PostMergeHistory { + prunecfg, ok := ethconfig.HistoryPrunePoints[genesisHash] + if !ok { + return nil, fmt.Errorf("no history pruning point is defined for genesis %x", genesisHash) + } + historyPruningCutoff = prunecfg.BlockNumber + } + + // Set networkID to chainID by default. networkID := config.NetworkId if networkID == 0 { networkID = chainConfig.ChainID.Uint64() } + + // Assemble the Ethereum object. eth := &Ethereum{ config: config, chainDb: chainDb, @@ -205,15 +223,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { EnablePreimageRecording: config.EnablePreimageRecording, } cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: scheme, + TrieCleanLimit: config.TrieCleanCache, + TrieCleanNoPrefetch: config.NoPrefetch, + TrieDirtyLimit: config.TrieDirtyCache, + TrieDirtyDisabled: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + Preimages: config.Preimages, + StateHistory: config.StateHistory, + StateScheme: scheme, + HistoryPruningCutoff: historyPruningCutoff, } ) if config.VMTrace != "" { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 0de8f3ca2..4aeb0048e 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -50,6 +50,7 @@ var FullNodeGPO = gasprice.Config{ // Defaults contains default settings for use on the Ethereum main net. var Defaults = Config{ + HistoryMode: AllHistory, SyncMode: downloader.SnapSync, NetworkId: 0, // enable auto configuration of networkID == chainID TxLookupLimit: 2350000, @@ -83,6 +84,9 @@ type Config struct { NetworkId uint64 SyncMode downloader.SyncMode + // HistoryMode configures chain history retention. + HistoryMode HistoryMode + // This can be set to list of enrtree:// URLs which will be queried for // nodes to connect to. EthDiscoveryURLs []string diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 84aea7cd1..db29c1441 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -20,6 +20,7 @@ func (c Config) MarshalTOML() (interface{}, error) { Genesis *core.Genesis `toml:",omitempty"` NetworkId uint64 SyncMode downloader.SyncMode + HistoryMode HistoryMode EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning bool @@ -56,6 +57,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Genesis = c.Genesis enc.NetworkId = c.NetworkId enc.SyncMode = c.SyncMode + enc.HistoryMode = c.HistoryMode enc.EthDiscoveryURLs = c.EthDiscoveryURLs enc.SnapDiscoveryURLs = c.SnapDiscoveryURLs enc.NoPruning = c.NoPruning @@ -96,6 +98,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { Genesis *core.Genesis `toml:",omitempty"` NetworkId *uint64 SyncMode *downloader.SyncMode + HistoryMode *HistoryMode EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning *bool @@ -141,6 +144,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.SyncMode != nil { c.SyncMode = *dec.SyncMode } + if dec.HistoryMode != nil { + c.HistoryMode = *dec.HistoryMode + } if dec.EthDiscoveryURLs != nil { c.EthDiscoveryURLs = dec.EthDiscoveryURLs } diff --git a/eth/ethconfig/historymode.go b/eth/ethconfig/historymode.go new file mode 100644 index 000000000..cf904ab59 --- /dev/null +++ b/eth/ethconfig/historymode.go @@ -0,0 +1,90 @@ +// Copyright 2025 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 . + +package ethconfig + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" +) + +// HistoryMode configures history pruning. +type HistoryMode uint32 + +const ( + // AllHistory (default) means that all chain history down to genesis block will be kept. + AllHistory HistoryMode = iota + + // PostMergeHistory sets the history pruning point to the merge activation block. + PostMergeHistory +) + +func (m HistoryMode) IsValid() bool { + return m <= PostMergeHistory +} + +func (m HistoryMode) String() string { + switch m { + case AllHistory: + return "all" + case PostMergeHistory: + return "postmerge" + default: + return fmt.Sprintf("invalid HistoryMode(%d)", m) + } +} + +// MarshalText implements encoding.TextMarshaler. +func (m HistoryMode) MarshalText() ([]byte, error) { + if m.IsValid() { + return []byte(m.String()), nil + } + return nil, fmt.Errorf("unknown history mode %d", m) +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (m *HistoryMode) UnmarshalText(text []byte) error { + switch string(text) { + case "all": + *m = AllHistory + case "postmerge": + *m = PostMergeHistory + default: + return fmt.Errorf(`unknown sync mode %q, want "all" or "postmerge"`, text) + } + return nil +} + +type HistoryPrunePoint struct { + BlockNumber uint64 + BlockHash common.Hash +} + +// HistoryPrunePoints contains the pre-defined history pruning cutoff blocks for known networks. +var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{ + // mainnet + params.MainnetGenesisHash: { + BlockNumber: 15537394, + BlockHash: common.HexToHash("0x56a9bb0302da44b8c0b3df540781424684c3af04d0b7a38d72842b762076a664"), + }, + // sepolia + params.SepoliaGenesisHash: { + BlockNumber: 1735371, + BlockHash: common.HexToHash("0x36fb89fba5b7857cf0ca78b5a9625b4043ff4555dfce9b7bcdcdd758a11eb946"), + }, +} From c7f411420026586d550f56652752f068c84ceef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 13 Mar 2025 12:35:10 +0100 Subject: [PATCH 198/354] core: update blockProcFeed in insertChain (#31065) This PR moves the updating of the `blockProcFeed` event feed from `InsertChain` to `insertChain` in order to ensure that the feed subscribers are notified whenever block processing happens. Note that this event is not subscribed to anywhere in our codebase at the moment, earlier it was used by the LES server to avoid slowing down block processing. Now I want to do the same with the log indexer, the problem is that back then every block insertion was done by `InsertChain`, now the regular payload insertion is done by `InsertBlockWithoutSetHead`. Both of these (and also `SetCanonical` if needed) calls `insertChain` so I moved the feed update there. --- core/blockchain.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index ee132d178..5c7c553e1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -245,6 +245,7 @@ type BlockChain struct { logsFeed event.Feed blockProcFeed event.Feed finalizedHeaderFeed event.Feed + blockProcCounter int32 scope event.SubscriptionScope genesisBlock *types.Block @@ -1701,8 +1702,6 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { if len(chain) == 0 { return 0, nil } - bc.blockProcFeed.Send(true) - defer bc.blockProcFeed.Send(false) // Do a sanity check that the provided chain is actually ordered and linked. for i := 1; i < len(chain); i++ { @@ -1743,6 +1742,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness return nil, 0, nil } + if atomic.AddInt32(&bc.blockProcCounter, 1) == 1 { + bc.blockProcFeed.Send(true) + } + defer func() { + if atomic.AddInt32(&bc.blockProcCounter, -1) == 0 { + bc.blockProcFeed.Send(false) + } + }() + // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) SenderCacher().RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) From bcf745f69a107ad1e34226a68fced6f6960a6667 Mon Sep 17 00:00:00 2001 From: Chen Kai <281165273grape@gmail.com> Date: Thu, 13 Mar 2025 15:16:01 +0100 Subject: [PATCH 199/354] p2p/discover: expose discv5 functions for portal JSON-RPC interface (#31117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #31093 Here we add some API functions on the UDPv5 object for the purpose of implementing the Portal Network JSON-RPC API in the shisui client. --------- Signed-off-by: Chen Kai <281165273grape@gmail.com> --- cmd/devp2p/discv4cmd.go | 2 +- cmd/devp2p/discv5cmd.go | 3 +- p2p/discover/table.go | 8 ++++ p2p/discover/v4_udp.go | 19 ++++++--- p2p/discover/v5_udp.go | 82 +++++++++++++++++++++++++++++-------- p2p/discover/v5_udp_test.go | 4 +- 6 files changed, 92 insertions(+), 26 deletions(-) diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 8c48b3a55..84c7ef0c4 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -163,7 +163,7 @@ func discv4Ping(ctx *cli.Context) error { defer disc.Close() start := time.Now() - if err := disc.Ping(n); err != nil { + if _, err := disc.Ping(n); err != nil { return fmt.Errorf("node didn't respond: %v", err) } fmt.Printf("node responded to ping (RTT %v).\n", time.Since(start)) diff --git a/cmd/devp2p/discv5cmd.go b/cmd/devp2p/discv5cmd.go index 2422ef664..dd253dd08 100644 --- a/cmd/devp2p/discv5cmd.go +++ b/cmd/devp2p/discv5cmd.go @@ -84,7 +84,8 @@ func discv5Ping(ctx *cli.Context) error { disc, _ := startV5(ctx) defer disc.Close() - fmt.Println(disc.Ping(n)) + _, err := disc.Ping(n) + fmt.Println(err) return nil } diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 392279f90..6a3d1af3a 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -694,3 +694,11 @@ func pushNode(list []*tableNode, n *tableNode, max int) ([]*tableNode, *tableNod list[0] = n return list, removed } + +// deleteNode removes a node from the table. +func (tab *Table) deleteNode(n *enode.Node) { + tab.mutex.Lock() + defer tab.mutex.Unlock() + b := tab.bucket(n.ID()) + tab.deleteInBucket(b, n.ID()) +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 29ae5f2c0..dd3f363f7 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -210,12 +210,6 @@ func (t *UDPv4) ourEndpoint() v4wire.Endpoint { return v4wire.NewEndpoint(addr, uint16(node.TCP())) } -// Ping sends a ping message to the given node. -func (t *UDPv4) Ping(n *enode.Node) error { - _, err := t.ping(n) - return err -} - // ping sends a ping message to the given node and waits for a reply. func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { addr, ok := n.UDPEndpoint() @@ -229,6 +223,19 @@ func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { return seq, err } +// Ping calls PING on a node and waits for a PONG response. +func (t *UDPv4) Ping(n *enode.Node) (pong *v4wire.Pong, err error) { + addr, ok := n.UDPEndpoint() + if !ok { + return nil, errNoUDPEndpoint + } + rm := t.sendPing(n.ID(), addr, nil) + if err = <-rm.errc; err == nil { + pong = rm.reply.(*v4wire.Pong) + } + return pong, err +} + // sendPing sends a ping message to the given node and invokes the callback // when the reply arrives. func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher { diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 48256ea4d..9e849751c 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -200,12 +200,6 @@ func (t *UDPv5) Close() { }) } -// Ping sends a ping message to the given node. -func (t *UDPv5) Ping(n *enode.Node) error { - _, err := t.ping(n) - return err -} - // Resolve searches for a specific node with the given ID and tries to get the most recent // version of the node record for it. It returns n if the node could not be resolved. func (t *UDPv5) Resolve(n *enode.Node) *enode.Node { @@ -226,6 +220,36 @@ func (t *UDPv5) Resolve(n *enode.Node) *enode.Node { return n } +// ResolveNodeId searches for a specific Node with the given ID. +// It returns nil if the nodeId could not be resolved. +func (t *UDPv5) ResolveNodeId(id enode.ID) *enode.Node { + if id == t.Self().ID() { + return t.Self() + } + + n := t.tab.getNode(id) + if n != nil { + // Try asking directly. This works if the Node is still responding on the endpoint we have. + if resp, err := t.RequestENR(n); err == nil { + return resp + } + } + + // Otherwise do a network lookup. + result := t.Lookup(id) + for _, rn := range result { + if rn.ID() == id { + if n != nil && rn.Seq() <= n.Seq() { + return n + } else { + return rn + } + } + } + + return n +} + // AllNodes returns all the nodes stored in the local table. func (t *UDPv5) AllNodes() []*enode.Node { t.tab.mutex.Lock() @@ -240,7 +264,18 @@ func (t *UDPv5) AllNodes() []*enode.Node { return nodes } -// LocalNode returns the current local node running the +// AddKnownNode adds a node to the routing table. +// The function should be used for testing only. +func (t *UDPv5) AddKnownNode(n *enode.Node) bool { + return t.tab.addFoundNode(n, true) +} + +// DeleteNode removes a node from the routing table. Used for Portal discv5 DeleteEnr API. +func (t *UDPv5) DeleteNode(n *enode.Node) { + t.tab.deleteNode(n) +} + +// LocalNode returns the current local Node running the // protocol. func (t *UDPv5) LocalNode() *enode.LocalNode { return t.localNode @@ -328,7 +363,7 @@ func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.No err error ) var r []*enode.Node - r, err = t.findnode(destNode, dists) + r, err = t.Findnode(destNode, dists) if errors.Is(err, errClosed) { return nil, err } @@ -359,21 +394,31 @@ func lookupDistances(target, dest enode.ID) (dists []uint) { // ping calls PING on a node and waits for a PONG response. func (t *UDPv5) ping(n *enode.Node) (uint64, error) { + pong, err := t.Ping(n) + if err != nil { + return 0, err + } + + return pong.ENRSeq, nil +} + +// Ping calls PING on a node and waits for a PONG response. +func (t *UDPv5) Ping(n *enode.Node) (*v5wire.Pong, error) { req := &v5wire.Ping{ENRSeq: t.localNode.Node().Seq()} resp := t.callToNode(n, v5wire.PongMsg, req) defer t.callDone(resp) select { case pong := <-resp.ch: - return pong.(*v5wire.Pong).ENRSeq, nil + return pong.(*v5wire.Pong), nil case err := <-resp.err: - return 0, err + return nil, err } } // RequestENR requests n's record. func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { - nodes, err := t.findnode(n, []uint{0}) + nodes, err := t.Findnode(n, []uint{0}) if err != nil { return nil, err } @@ -383,8 +428,8 @@ func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { return nodes[0], nil } -// findnode calls FINDNODE on a node and waits for responses. -func (t *UDPv5) findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) { +// Findnode calls FINDNODE on a node and waits for responses. +func (t *UDPv5) Findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) { resp := t.callToNode(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances}) return t.waitForNodes(resp, distances) } @@ -736,8 +781,8 @@ func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr netip.AddrPort, p v return true } -// getNode looks for a node record in table and database. -func (t *UDPv5) getNode(id enode.ID) *enode.Node { +// GetNode looks for a node record in table and database. +func (t *UDPv5) GetNode(id enode.ID) *enode.Node { if n := t.tab.getNode(id); n != nil { return n } @@ -747,6 +792,11 @@ func (t *UDPv5) getNode(id enode.ID) *enode.Node { return nil } +// Nodes returns the nodes in the routing table. +func (t *UDPv5) Nodes() [][]BucketNode { + return t.tab.Nodes() +} + // handle processes incoming packets according to their message type. func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort) { switch p := p.(type) { @@ -776,7 +826,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr netip.AddrPort) { challenge := &v5wire.Whoareyou{Nonce: p.Nonce} crand.Read(challenge.IDNonce[:]) - if n := t.getNode(fromID); n != nil { + if n := t.GetNode(fromID); n != nil { challenge.Node = n challenge.RecordSeq = n.Seq() } diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 8631b918f..371f41476 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -288,7 +288,7 @@ func TestUDPv5_findnodeCall(t *testing.T) { ) go func() { var err error - response, err = test.udp.findnode(remote, distances) + response, err = test.udp.Findnode(remote, distances) done <- err }() @@ -398,7 +398,7 @@ func TestUDPv5_callTimeoutReset(t *testing.T) { done = make(chan error, 1) ) go func() { - _, err := test.udp.findnode(remote, []uint{distance}) + _, err := test.udp.Findnode(remote, []uint{distance}) done <- err }() From 6750e96475f73c1e269df094ce2c42df32140975 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 13 Mar 2025 15:21:47 +0100 Subject: [PATCH 200/354] cmd/workload: implement checks for history-pruned node (#31355) Co-authored-by: Felix Lange --- cmd/workload/filtertest.go | 15 +++++---- cmd/workload/filtertestgen.go | 4 +-- cmd/workload/filtertestperf.go | 2 +- cmd/workload/historytest.go | 56 ++++++++++++++++++++++++---------- cmd/workload/testsuite.go | 37 +++++++++++++++++++--- 5 files changed, 85 insertions(+), 29 deletions(-) diff --git a/cmd/workload/filtertest.go b/cmd/workload/filtertest.go index 0e709ac0f..bc7685791 100644 --- a/cmd/workload/filtertest.go +++ b/cmd/workload/filtertest.go @@ -108,7 +108,7 @@ func (s *filterTestSuite) filterFullRange(t *utesting.T) { } func (s *filterTestSuite) queryAndCheck(t *utesting.T, query *filterQuery) { - query.run(s.cfg.client) + query.run(s.cfg.client, s.cfg.historyPruneBlock) if query.Err != nil { t.Errorf("Filter query failed (fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics, query.Err) return @@ -125,7 +125,7 @@ func (s *filterTestSuite) fullRangeQueryAndCheck(t *utesting.T, query *filterQue Address: query.Address, Topics: query.Topics, } - frQuery.run(s.cfg.client) + frQuery.run(s.cfg.client, s.cfg.historyPruneBlock) if frQuery.Err != nil { t.Errorf("Full range filter query failed (addresses: %v topics: %v error: %v)", frQuery.Address, frQuery.Topics, frQuery.Err) return @@ -197,7 +197,7 @@ func (fq *filterQuery) calculateHash() common.Hash { return crypto.Keccak256Hash(enc) } -func (fq *filterQuery) run(client *client) { +func (fq *filterQuery) run(client *client, historyPruneBlock *uint64) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() logs, err := client.Eth.FilterLogs(ctx, ethereum.FilterQuery{ @@ -207,10 +207,13 @@ func (fq *filterQuery) run(client *client) { Topics: fq.Topics, }) if err != nil { + if err = validateHistoryPruneErr(fq.Err, uint64(fq.FromBlock), historyPruneBlock); err == errPrunedHistory { + return + } else if err != nil { + fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n", + fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err) + } fq.Err = err - fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n", - fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err) - return } fq.results = logs } diff --git a/cmd/workload/filtertestgen.go b/cmd/workload/filtertestgen.go index 29aad9ddd..e50ec57b4 100644 --- a/cmd/workload/filtertestgen.go +++ b/cmd/workload/filtertestgen.go @@ -70,7 +70,7 @@ func filterGenCmd(ctx *cli.Context) error { f.updateFinalizedBlock() query := f.newQuery() - query.run(f.client) + query.run(f.client, nil) if query.Err != nil { f.errors = append(f.errors, query) continue @@ -81,7 +81,7 @@ func filterGenCmd(ctx *cli.Context) error { if extQuery == nil { break } - extQuery.run(f.client) + extQuery.run(f.client, nil) if extQuery.Err == nil && len(extQuery.results) < len(query.results) { extQuery.Err = fmt.Errorf("invalid result length; old range %d %d; old length %d; new range %d %d; new length %d; address %v; Topics %v", query.FromBlock, query.ToBlock, len(query.results), diff --git a/cmd/workload/filtertestperf.go b/cmd/workload/filtertestperf.go index c1f2aff58..7f4cad4ab 100644 --- a/cmd/workload/filtertestperf.go +++ b/cmd/workload/filtertestperf.go @@ -70,7 +70,7 @@ func filterPerfCmd(ctx *cli.Context) error { queries[pick] = queries[len(queries)-1] queries = queries[:len(queries)-1] start := time.Now() - qt.query.run(cfg.client) + qt.query.run(cfg.client, cfg.historyPruneBlock) qt.runtime = append(qt.runtime, time.Since(start)) slices.Sort(qt.runtime) qt.medianTime = qt.runtime[len(qt.runtime)/2] diff --git a/cmd/workload/historytest.go b/cmd/workload/historytest.go index a68151042..29fe3f509 100644 --- a/cmd/workload/historytest.go +++ b/cmd/workload/historytest.go @@ -108,8 +108,11 @@ func (s *historyTestSuite) testGetBlockByHash(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] b, err := s.cfg.client.getBlockByHash(ctx, bhash, false) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } if b == nil { t.Errorf("block %d (hash %v): not found", num, bhash) @@ -127,8 +130,11 @@ func (s *historyTestSuite) testGetBlockByNumber(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] b, err := s.cfg.client.getBlockByNumber(ctx, num, false) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } if b == nil { t.Errorf("block %d (hash %v): not found", num, bhash) @@ -146,8 +152,11 @@ func (s *historyTestSuite) testGetBlockTransactionCountByHash(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] count, err := s.cfg.client.getBlockTransactionCountByHash(ctx, bhash) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } expectedCount := uint64(s.tests.TxCounts[i]) if count != expectedCount { @@ -162,8 +171,11 @@ func (s *historyTestSuite) testGetBlockTransactionCountByNumber(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] count, err := s.cfg.client.getBlockTransactionCountByNumber(ctx, num) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } expectedCount := uint64(s.tests.TxCounts[i]) if count != expectedCount { @@ -178,8 +190,11 @@ func (s *historyTestSuite) testGetBlockReceiptsByHash(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] receipts, err := s.cfg.client.getBlockReceipts(ctx, bhash) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } hash := calcReceiptsHash(receipts) expectedHash := s.tests.ReceiptsHashes[i] @@ -195,8 +210,11 @@ func (s *historyTestSuite) testGetBlockReceiptsByNumber(t *utesting.T) { for i, num := range s.tests.BlockNumbers { bhash := s.tests.BlockHashes[i] receipts, err := s.cfg.client.getBlockReceipts(ctx, hexutil.Uint64(num)) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } hash := calcReceiptsHash(receipts) expectedHash := s.tests.ReceiptsHashes[i] @@ -218,8 +236,11 @@ func (s *historyTestSuite) testGetTransactionByBlockHashAndIndex(t *utesting.T) } tx, err := s.cfg.client.getTransactionByBlockHashAndIndex(ctx, bhash, uint64(txIndex)) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } if tx == nil { t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex) @@ -243,8 +264,11 @@ func (s *historyTestSuite) testGetTransactionByBlockNumberAndIndex(t *utesting.T } tx, err := s.cfg.client.getTransactionByBlockNumberAndIndex(ctx, num, uint64(txIndex)) - if err != nil { - t.Fatalf("block %d (hash %v): error %v", num, bhash, err) + if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory { + continue + } else if err != nil { + t.Errorf("block %d (hash %v): error %v", num, bhash, err) + continue } if tx == nil { t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex) diff --git a/cmd/workload/testsuite.go b/cmd/workload/testsuite.go index 3e3ea1d00..e7019e205 100644 --- a/cmd/workload/testsuite.go +++ b/cmd/workload/testsuite.go @@ -18,13 +18,17 @@ package main import ( "embed" + "fmt" "io/fs" "os" "slices" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" ) @@ -77,10 +81,31 @@ var ( // testConfig holds the parameters for testing. type testConfig struct { - client *client - fsys fs.FS - filterQueryFile string - historyTestFile string + client *client + fsys fs.FS + filterQueryFile string + historyTestFile string + historyPruneBlock *uint64 +} + +var errPrunedHistory = fmt.Errorf("attempt to access pruned history") + +// validateHistoryPruneErr checks whether the given error is caused by access +// to history before the pruning threshold block (it is an rpc.Error with code 4444). +// In this case, errPrunedHistory is returned. +// If the error is a pruned history error that occurs when accessing a block past the +// historyPrune block, an error is returned. +// Otherwise, the original value of err is returned. +func validateHistoryPruneErr(err error, blockNum uint64, historyPruneBlock *uint64) error { + if err != nil { + if rpcErr, ok := err.(rpc.Error); ok && rpcErr.ErrorCode() == 4444 { + if historyPruneBlock != nil && blockNum > *historyPruneBlock { + return fmt.Errorf("pruned history error returned after pruning threshold") + } + return errPrunedHistory + } + } + return err } func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) { @@ -98,10 +123,14 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) { cfg.fsys = builtinTestFiles cfg.filterQueryFile = "queries/filter_queries_mainnet.json" cfg.historyTestFile = "queries/history_mainnet.json" + cfg.historyPruneBlock = new(uint64) + *cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.MainnetGenesisHash].BlockNumber case ctx.Bool(testSepoliaFlag.Name): cfg.fsys = builtinTestFiles cfg.filterQueryFile = "queries/filter_queries_sepolia.json" cfg.historyTestFile = "queries/history_sepolia.json" + cfg.historyPruneBlock = new(uint64) + *cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.SepoliaGenesisHash].BlockNumber default: cfg.fsys = os.DirFS(".") cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name) From fb273baebcc3d46fd971a614a8dd37e34589969f Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 13 Mar 2025 18:54:20 +0100 Subject: [PATCH 201/354] eth/ethconfig: fix history prune blocks (#31383) --- eth/ethconfig/historymode.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/eth/ethconfig/historymode.go b/eth/ethconfig/historymode.go index cf904ab59..c3661004e 100644 --- a/eth/ethconfig/historymode.go +++ b/eth/ethconfig/historymode.go @@ -76,15 +76,17 @@ type HistoryPrunePoint struct { } // HistoryPrunePoints contains the pre-defined history pruning cutoff blocks for known networks. +// They point to the first post-merge block. Any pruning should truncate *up to* but excluding +// given block. var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{ // mainnet params.MainnetGenesisHash: { - BlockNumber: 15537394, - BlockHash: common.HexToHash("0x56a9bb0302da44b8c0b3df540781424684c3af04d0b7a38d72842b762076a664"), + BlockNumber: 15537393, + BlockHash: common.HexToHash("0x55b11b918355b1ef9c5db810302ebad0bf2544255b530cdce90674d5887bb286"), }, // sepolia params.SepoliaGenesisHash: { - BlockNumber: 1735371, - BlockHash: common.HexToHash("0x36fb89fba5b7857cf0ca78b5a9625b4043ff4555dfce9b7bcdcdd758a11eb946"), + BlockNumber: 1450409, + BlockHash: common.HexToHash("0x229f6b18ca1552f1d5146deceb5387333f40dc6275aebee3f2c5c4ece07d02db"), }, } From 3d6aaba677923dd1646d32699a59b56630d52442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 13 Mar 2025 19:04:16 +0100 Subject: [PATCH 202/354] core/filtermaps: FilterMaps log index generator and search logic (#31079) This PR is #1 of a 3-part series that implements the new log index intended to replace core/bloombits. Replaces https://github.com/ethereum/go-ethereum/pull/30370 This part implements the new data structure, the log index generator and the search logic. This PR has most of the complexity but it does not affect any existing code yet so maybe it is easier to review separately. FilterMaps data structure explanation: https://gist.github.com/zsfelfoldi/a60795f9da7ae6422f28c7a34e02a07e Log index generator code overview: https://gist.github.com/zsfelfoldi/97105dff0b1a4f5ed557924a24b9b9e7 Search pattern matcher code overview: https://gist.github.com/zsfelfoldi/5981735641c956afb18065e84f8aff34 Note that the possibility of a tree hashing scheme and remote proof protocol are mentioned in the documents above but they are not exactly specified yet. These specs are WIP and will be finalized after the local log indexer/filter code is finalized and merged. --------- Co-authored-by: Felix Lange --- core/filtermaps/chain_view.go | 156 ++++ core/filtermaps/checkpoints.go | 63 ++ core/filtermaps/checkpoints_holesky.json | 20 + core/filtermaps/checkpoints_mainnet.json | 256 +++++++ core/filtermaps/checkpoints_sepolia.json | 63 ++ core/filtermaps/filtermaps.go | 726 ++++++++++++++++++ core/filtermaps/indexer.go | 395 ++++++++++ core/filtermaps/indexer_test.go | 444 +++++++++++ core/filtermaps/map_renderer.go | 768 +++++++++++++++++++ core/filtermaps/matcher.go | 934 +++++++++++++++++++++++ core/filtermaps/matcher_backend.go | 206 +++++ core/filtermaps/matcher_test.go | 87 +++ core/filtermaps/math.go | 212 +++++ core/filtermaps/math_test.go | 149 ++++ core/rawdb/accessors_indexes.go | 305 ++++++++ core/rawdb/database.go | 4 + core/rawdb/schema.go | 37 + 17 files changed, 4825 insertions(+) create mode 100644 core/filtermaps/chain_view.go create mode 100644 core/filtermaps/checkpoints.go create mode 100644 core/filtermaps/checkpoints_holesky.json create mode 100644 core/filtermaps/checkpoints_mainnet.json create mode 100644 core/filtermaps/checkpoints_sepolia.json create mode 100644 core/filtermaps/filtermaps.go create mode 100644 core/filtermaps/indexer.go create mode 100644 core/filtermaps/indexer_test.go create mode 100644 core/filtermaps/map_renderer.go create mode 100644 core/filtermaps/matcher.go create mode 100644 core/filtermaps/matcher_backend.go create mode 100644 core/filtermaps/matcher_test.go create mode 100644 core/filtermaps/math.go create mode 100644 core/filtermaps/math_test.go diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go new file mode 100644 index 000000000..bc0de47de --- /dev/null +++ b/core/filtermaps/chain_view.go @@ -0,0 +1,156 @@ +// Copyright 2025 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 . + +package filtermaps + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +// blockchain represents the underlying blockchain of ChainView. +type blockchain interface { + GetHeader(hash common.Hash, number uint64) *types.Header + GetCanonicalHash(number uint64) common.Hash + GetReceiptsByHash(hash common.Hash) types.Receipts +} + +// ChainView represents an immutable view of a chain with a block id and a set +// of receipts associated to each block number and a block hash associated with +// all block numbers except the head block. This is because in the future +// ChainView might represent a view where the head block is currently being +// created. Block id is a unique identifier that can also be calculated for the +// head block. +// Note that the view's head does not have to be the current canonical head +// of the underlying blockchain, it should only possess the block headers +// and receipts up until the expected chain view head. +type ChainView struct { + chain blockchain + headNumber uint64 + hashes []common.Hash // block hashes starting backwards from headNumber until first canonical hash +} + +// NewChainView creates a new ChainView. +func NewChainView(chain blockchain, number uint64, hash common.Hash) *ChainView { + cv := &ChainView{ + chain: chain, + headNumber: number, + hashes: []common.Hash{hash}, + } + cv.extendNonCanonical() + return cv +} + +// getBlockHash returns the block hash belonging to the given block number. +// Note that the hash of the head block is not returned because ChainView might +// represent a view where the head block is currently being created. +func (cv *ChainView) getBlockHash(number uint64) common.Hash { + if number >= cv.headNumber { + panic("invalid block number") + } + return cv.blockHash(number) +} + +// getBlockId returns the unique block id belonging to the given block number. +// Note that it is currently equal to the block hash. In the future it might +// be a different id for future blocks if the log index root becomes part of +// consensus and therefore rendering the index with the new head will happen +// before the hash of that new head is available. +func (cv *ChainView) getBlockId(number uint64) common.Hash { + if number > cv.headNumber { + panic("invalid block number") + } + return cv.blockHash(number) +} + +// getReceipts returns the set of receipts belonging to the block at the given +// block number. +func (cv *ChainView) getReceipts(number uint64) types.Receipts { + if number > cv.headNumber { + panic("invalid block number") + } + return cv.chain.GetReceiptsByHash(cv.blockHash(number)) +} + +// limitedView returns a new chain view that is a truncated version of the parent view. +func (cv *ChainView) limitedView(newHead uint64) *ChainView { + if newHead >= cv.headNumber { + return cv + } + return NewChainView(cv.chain, newHead, cv.blockHash(newHead)) +} + +// equalViews returns true if the two chain views are equivalent. +func equalViews(cv1, cv2 *ChainView) bool { + if cv1 == nil || cv2 == nil { + return false + } + return cv1.headNumber == cv2.headNumber && cv1.getBlockId(cv1.headNumber) == cv2.getBlockId(cv2.headNumber) +} + +// matchViews returns true if the two chain views are equivalent up until the +// specified block number. If the specified number is higher than one of the +// heads then false is returned. +func matchViews(cv1, cv2 *ChainView, number uint64) bool { + if cv1 == nil || cv2 == nil { + return false + } + if cv1.headNumber < number || cv2.headNumber < number { + return false + } + if number == cv1.headNumber || number == cv2.headNumber { + return cv1.getBlockId(number) == cv2.getBlockId(number) + } + return cv1.getBlockHash(number) == cv2.getBlockHash(number) +} + +// extendNonCanonical checks whether the previously known reverse list of head +// hashes still ends with one that is canonical on the underlying blockchain. +// If necessary then it traverses further back on the header chain and adds +// more hashes to the list. +func (cv *ChainView) extendNonCanonical() bool { + for { + hash, number := cv.hashes[len(cv.hashes)-1], cv.headNumber-uint64(len(cv.hashes)-1) + if cv.chain.GetCanonicalHash(number) == hash { + return true + } + if number == 0 { + log.Error("Unknown genesis block hash found") + return false + } + header := cv.chain.GetHeader(hash, number) + if header == nil { + log.Error("Header not found", "number", number, "hash", hash) + return false + } + cv.hashes = append(cv.hashes, header.ParentHash) + } +} + +// blockHash returns the given block hash without doing the head number check. +func (cv *ChainView) blockHash(number uint64) common.Hash { + if number+uint64(len(cv.hashes)) <= cv.headNumber { + hash := cv.chain.GetCanonicalHash(number) + if !cv.extendNonCanonical() { + return common.Hash{} + } + if number+uint64(len(cv.hashes)) <= cv.headNumber { + return hash + } + } + return cv.hashes[cv.headNumber-number] +} diff --git a/core/filtermaps/checkpoints.go b/core/filtermaps/checkpoints.go new file mode 100644 index 000000000..f8d6500aa --- /dev/null +++ b/core/filtermaps/checkpoints.go @@ -0,0 +1,63 @@ +// Copyright 2025 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 . + +package filtermaps + +import ( + _ "embed" + "encoding/json" + + "github.com/ethereum/go-ethereum/common" +) + +// checkpointList lists checkpoints for finalized epochs of a given chain. +// This allows the indexer to start indexing from the latest available +// checkpoint and then index tail epochs in reverse order. +type checkpointList []epochCheckpoint + +// epochCheckpoint specified the last block of the epoch and the first log +// value index where that block starts. This allows a log value iterator to +// be initialized at the epoch boundary. +type epochCheckpoint struct { + BlockNumber uint64 // block that generated the last log value of the given epoch + BlockId common.Hash + FirstIndex uint64 // first log value index of the given block +} + +//go:embed checkpoints_mainnet.json +var checkpointsMainnetJSON []byte + +//go:embed checkpoints_sepolia.json +var checkpointsSepoliaJSON []byte + +//go:embed checkpoints_holesky.json +var checkpointsHoleskyJSON []byte + +// checkpoints lists sets of checkpoints for multiple chains. The matching +// checkpoint set is autodetected by the indexer once the canonical chain is +// known. +var checkpoints = []checkpointList{ + decodeCheckpoints(checkpointsMainnetJSON), + decodeCheckpoints(checkpointsSepoliaJSON), + decodeCheckpoints(checkpointsHoleskyJSON), +} + +func decodeCheckpoints(encoded []byte) (result checkpointList) { + if err := json.Unmarshal(encoded, &result); err != nil { + panic(err) + } + return +} diff --git a/core/filtermaps/checkpoints_holesky.json b/core/filtermaps/checkpoints_holesky.json new file mode 100644 index 000000000..c30856db4 --- /dev/null +++ b/core/filtermaps/checkpoints_holesky.json @@ -0,0 +1,20 @@ +[ +{"blockNumber": 814411, "blockId": "0xf763e96fc3920359c5f706803024b78e83796a3a8563bb5a83c3ddd7cbfde287", "firstIndex": 67107637}, +{"blockNumber": 914278, "blockId": "0x0678cf8d53c0d6d27896df657d98cc73bc63ca468b6295068003938ef9b0f927", "firstIndex": 134217671}, +{"blockNumber": 1048874, "blockId": "0x3620c3d52a40ff4d9fc58c3104cfa2f327f55592caf6a2394c207a5e00b4f740", "firstIndex": 201326382}, +{"blockNumber": 1144441, "blockId": "0x438fb42850f5a0d8e1666de598a4d0106b62da0f7448c62fe029b8cbad35d08d", "firstIndex": 268435440}, +{"blockNumber": 1230411, "blockId": "0xf0ee07e60a93910723b259473a253dd9cf674e8b78c4f153b32ad7032efffeeb", "firstIndex": 335543079}, +{"blockNumber": 1309112, "blockId": "0xc1646e5ef4b4343880a85b1a4111e3321d609a1225e9cebbe10d1c7abf99e58d", "firstIndex": 402653100}, +{"blockNumber": 1380522, "blockId": "0x1617cae91989d97ac6335c4217aa6cc7f7f4c2837e20b3b5211d98d6f9e97e44", "firstIndex": 469761917}, +{"blockNumber": 1476962, "blockId": "0xd978455d2618d093dfc685d7f43f61be6dae0fa8a9cb915ae459aa6e0a5525f0", "firstIndex": 536870773}, +{"blockNumber": 1533518, "blockId": "0xe7d39d71bd9d5f1f3157c35e0329531a7950a19e3042407e38948b89b5384f78", "firstIndex": 603979664}, +{"blockNumber": 1613787, "blockId": "0xa793168d135c075732a618ec367faaed5f359ffa81898c73cb4ec54ec2caa696", "firstIndex": 671088003}, +{"blockNumber": 1719099, "blockId": "0xc4394c71a8a24efe64c5ff2afcdd1594f3708524e6084aa7dadd862bd704ab03", "firstIndex": 738196914}, +{"blockNumber": 1973165, "blockId": "0xee3a9e959a437c707a3036736ec8d42a9261ac6100972c26f65eedcde315a81d", "firstIndex": 805306333}, +{"blockNumber": 2274844, "blockId": "0x76e2d33653ed9282c63ad09d721e1f2e29064aa9c26202e20fc4cc73e8dfe5f6", "firstIndex": 872415141}, +{"blockNumber": 2530503, "blockId": "0x59f4e45345f8b8f848be5004fe75c4a28f651864256c3aa9b2da63369432b718", "firstIndex": 939523693}, +{"blockNumber": 2781903, "blockId": "0xc981e91c6fb69c5e8146ead738fcfc561831f11d7786d39c7fa533966fc37675", "firstIndex": 1006632906}, +{"blockNumber": 3101713, "blockId": "0xc7baa577c91d8439e3fc79002d2113d07ca54a4724bf2f1f5af937b7ba8e1f32", "firstIndex": 1073741382}, +{"blockNumber": 3221770, "blockId": "0xa6b8240b7883fcc71aa5001b5ba66c889975c5217e14c16edebdd6f6e23a9424", "firstIndex": 1140850360} +] + diff --git a/core/filtermaps/checkpoints_mainnet.json b/core/filtermaps/checkpoints_mainnet.json new file mode 100644 index 000000000..d2b031a47 --- /dev/null +++ b/core/filtermaps/checkpoints_mainnet.json @@ -0,0 +1,256 @@ +[ +{"blockNumber": 4166218, "blockId": "0xdd767e0426256179125551e8e40f33565a96d1c94076c7746fa79d767ed4ad65", "firstIndex": 67108680}, +{"blockNumber": 4514014, "blockId": "0x33a0879bdabea4a7a3f2b424388cbcbf2fbd519bddadf13752a259049c78e95d", "firstIndex": 134217343}, +{"blockNumber": 4817415, "blockId": "0x4f0e8c7dd04fbe0985b9394575b19f13ea66a2a628fa5b08178ce4b138c6db80", "firstIndex": 201326352}, +{"blockNumber": 5087733, "blockId": "0xc84cd5e9cda999c919803c7a53a23bb77a18827fbde401d3463f1e9e52536424", "firstIndex": 268435343}, +{"blockNumber": 5306107, "blockId": "0x13f028b5fc055d23f55a92a2eeecfbcfbda8a08e4cd519ce451ba2e70428f5f9", "firstIndex": 335544094}, +{"blockNumber": 5509918, "blockId": "0x1ed770a58a7b4d4a828b7bb44c8820a674d562b23a6a0139981abe4c489d4dad", "firstIndex": 402652853}, +{"blockNumber": 5670390, "blockId": "0x3923ee6a62e6cc5132afdadf1851ae4e73148e6fbe0a8319cafd2a120c98efa3", "firstIndex": 469761897}, +{"blockNumber": 5826139, "blockId": "0xe61bc6ef03c333805f26319e1688f82553f98aa5e902b200e0621a3371b69050", "firstIndex": 536870853}, +{"blockNumber": 5953029, "blockId": "0x43d710b1b7243b848400975048ccefdfaba091c692c7f01c619d988886cc160f", "firstIndex": 603979580}, +{"blockNumber": 6102846, "blockId": "0xa100b2018f6545cc689656b4b846677b138955b7efd30e850cd14c246430ba18", "firstIndex": 671088291}, +{"blockNumber": 6276718, "blockId": "0xb832ac448b06c104ba50faefd58b0b94d53c0fba5cb268086adad4db99c2f35f", "firstIndex": 738197399}, +{"blockNumber": 6448696, "blockId": "0x48e8ae6f729ad6c76b6cf632bd52a6df7886ed55be09d43c5004fcc1463e533b", "firstIndex": 805305988}, +{"blockNumber": 6655974, "blockId": "0xac395971a6ffc30f807848f68b97b2834f8ea13478a7615860b6a69e3d0823ca", "firstIndex": 872415033}, +{"blockNumber": 6873949, "blockId": "0xc522ddb1113b1e9a87b2bdcb11ce78756beba6454a890122f121a032b5769354", "firstIndex": 939523784}, +{"blockNumber": 7080953, "blockId": "0x3606de577d80120d1edbb64bad7fa6795e788bae342866a98cc58ce2f7575045", "firstIndex": 1006632796}, +{"blockNumber": 7267002, "blockId": "0xad770882a69d216e955e34fef84851e56c0de82deacd6187a7a41f6170cd6c6d", "firstIndex": 1073741045}, +{"blockNumber": 7466708, "blockId": "0x17a48817b3a65aba333a5b56f3ff2e86fbcc19e184b046a5305a5182fdd8eb8a", "firstIndex": 1140850680}, +{"blockNumber": 7661807, "blockId": "0xa74731ee775fbd3f4d9313c68562737dd7c8d2c9eb968791d8abe167e16ddc96", "firstIndex": 1207959112}, +{"blockNumber": 7834556, "blockId": "0xe4b4812448075508cb05a0e3257f91b49509dc78cd963676a633864db6e78956", "firstIndex": 1275068095}, +{"blockNumber": 7990068, "blockId": "0x07bd4ca38abb4584a6209e04035646aa545ebbb6c948d438d4c25bfd9cb205fa", "firstIndex": 1342176620}, +{"blockNumber": 8143032, "blockId": "0x0e3149e9637290b044ee693b8fcb66e23d22db3ad0bdda32962138ba18e59f3f", "firstIndex": 1409285949}, +{"blockNumber": 8297660, "blockId": "0x34cd24f80247f7dfaf316b2e637f4b62f72ecc90703014fb25cb98ad044fc2c0", "firstIndex": 1476394911}, +{"blockNumber": 8465137, "blockId": "0x4452fa296498248d7f10c9dc6ec1e4ae7503aa07f491e6d38b21aea5d2c658a8", "firstIndex": 1543503744}, +{"blockNumber": 8655820, "blockId": "0x7bdb9008b30be420f7152cc294ac6e5328eed5b4abd954a34105de3da24f3cc6", "firstIndex": 1610612619}, +{"blockNumber": 8807187, "blockId": "0xde03e3bfddc722c019f0b59bc55efabcd5ab68c6711f4c08d0390a56f396590d", "firstIndex": 1677721589}, +{"blockNumber": 8911171, "blockId": "0xe44f342de74ab05a2a994f8841bdf88f720b9dc260177ba4030d0f7077901324", "firstIndex": 1744830310}, +{"blockNumber": 8960320, "blockId": "0x79764f9ff6e0fe4848eda1805687872021076e4e603112861af84181395ac559", "firstIndex": 1811938893}, +{"blockNumber": 9085994, "blockId": "0x24a101d1c8a63367a0953d10dc79c3b587a93bd7fd382084708adefce0b8363f", "firstIndex": 1879047965}, +{"blockNumber": 9230924, "blockId": "0xb176a98d3acd855cbb75265fb6be955a8d51abc771e021e13275d5b3ecb07eeb", "firstIndex": 1946156668}, +{"blockNumber": 9390535, "blockId": "0x640f5e2d511a5141878d57ae7a619f19b72a2bd3ef019cf0a22d74d93d9acf07", "firstIndex": 2013265733}, +{"blockNumber": 9515674, "blockId": "0xff4a7b6b21aeaeb6e1a75ecd22b1f34c058a0ce1477ce90a8ce78165fd1d0941", "firstIndex": 2080374553}, +{"blockNumber": 9659426, "blockId": "0xc351455249343b41e9171e183612b68c3c895271c62bd2c53d9e3ab1aa865aa1", "firstIndex": 2147483567}, +{"blockNumber": 9794018, "blockId": "0xde98035b4b7f9449c256239b65c7ff2c0330de44dee190106d0a96fb6f683238", "firstIndex": 2214592213}, +{"blockNumber": 9923840, "blockId": "0x881da313a1e2b6fab58a1d6fa65b5dacfdc9d68a3112a647104955b5233f84e3", "firstIndex": 2281701302}, +{"blockNumber": 10042435, "blockId": "0x451f6459640a6f54e2a535cc3a49cfc469861da3ddc101840ab3aef9e17fa424", "firstIndex": 2348810174}, +{"blockNumber": 10168883, "blockId": "0x5d16ff5adf0df1e4dc810da60af37399ef733be7870f21112b8c2cfff4995dd9", "firstIndex": 2415918783}, +{"blockNumber": 10289554, "blockId": "0x85d5690f15a787c43b9a49e8dd6e324f0b3e0c9796d07c0cfb128e5c168f5488", "firstIndex": 2483027930}, +{"blockNumber": 10386676, "blockId": "0x20f675ea72db448024a8a0b8e3ec180cac37a5910575bc32f8d9f5cdfe3c2649", "firstIndex": 2550136212}, +{"blockNumber": 10479675, "blockId": "0x014abb07acf2330cc78800ca1f564928f2daccca4b389bf5c59f4b840d843ec0", "firstIndex": 2617245218}, +{"blockNumber": 10562661, "blockId": "0xd437607a3f81ce8b7c605e167ce5e52bf8a3e02cdc646997bd0ccc57a50ad7d1", "firstIndex": 2684354520}, +{"blockNumber": 10641508, "blockId": "0x2e8ab6470c29f90ac23dcfc58310f0208f5d0e752a0c7982a77a223eca104082", "firstIndex": 2751462730}, +{"blockNumber": 10717156, "blockId": "0x8820447b6429dd12be603c1c130be532e9db065bb4bc6b2a9d4551794d63789a", "firstIndex": 2818571831}, +{"blockNumber": 10784549, "blockId": "0xc557daab80a7cdc963d62aa881faf3ab1baceff8e027046bcd203e432e0983b3", "firstIndex": 2885680800}, +{"blockNumber": 10848651, "blockId": "0xede1b0de5db6685a6f589096ceb8fccb08d3ff60e8b00a93caa4a775b48e07fc", "firstIndex": 2952789740}, +{"blockNumber": 10909166, "blockId": "0x989db675899d13323006a4d6174557e3c5501c672afd60d8bd902fc98d37e92e", "firstIndex": 3019897599}, +{"blockNumber": 10972902, "blockId": "0x5484050cc2c7d774bc5cd6af1c2ef8c19d1de12dabe25867c9b365924ea10434", "firstIndex": 3087007422}, +{"blockNumber": 11036597, "blockId": "0x1e3686e19056587c385262d5b0a07b3ec04e804c2d59e9aaca1e5876e78f69ae", "firstIndex": 3154116231}, +{"blockNumber": 11102520, "blockId": "0x339cf302fe813cce3bb9318b860dfa8be7f688413f38a6ea1987a1b84d742b4b", "firstIndex": 3221224863}, +{"blockNumber": 11168162, "blockId": "0xc0fa21ea090627610bcac4732dff702633f310cabafc42bc500d3d4805198fe0", "firstIndex": 3288334273}, +{"blockNumber": 11233707, "blockId": "0x491c37a479b8cf22eaa3654ae34c5ddc4627df8c58ca8a6979159e1710428576", "firstIndex": 3355442691}, +{"blockNumber": 11300526, "blockId": "0xb7366d2a24df99002cffe0c9a00959c93ef0dcfc3fd17389e2020bf5caa788eb", "firstIndex": 3422551480}, +{"blockNumber": 11367621, "blockId": "0xce53df5080c5b5238bb7717dfbfd88c2f574cfbb3d91f92b57171a00e9776cd2", "firstIndex": 3489660710}, +{"blockNumber": 11431881, "blockId": "0x2a08ff9c4f6fd152166213d902f0870822429f01d5f90e384ac54a3eac0ceb3a", "firstIndex": 3556768626}, +{"blockNumber": 11497107, "blockId": "0x1f99c6b65f2b1cb06ed1786c6a0274ff1b9eacab6cb729fcd386f10ebbd88123", "firstIndex": 3623878389}, +{"blockNumber": 11560104, "blockId": "0xebe6924817bbdfe52af49667da1376bae5a2994b375d4b996e8ff2683744e37a", "firstIndex": 3690986640}, +{"blockNumber": 11625129, "blockId": "0xbe6eee325329ee2fe632d8576864c29dd1c79bab891dc0a22d5b2ac87618d26e", "firstIndex": 3758095773}, +{"blockNumber": 11690397, "blockId": "0xc28bf55f858ddf5b82d1ceb3b5258b90a9ca34df8863a1c652c4d359f5748fdf", "firstIndex": 3825204492}, +{"blockNumber": 11755087, "blockId": "0x0c10cde6ce1bbe24dc57347fe4aaebc17b7d8e8d7d97e3db573133477f494740", "firstIndex": 3892314051}, +{"blockNumber": 11819674, "blockId": "0x36b694a1776c94e4c6ae4a410931b2086de47a83e437517040e3290ce9afff67", "firstIndex": 3959422445}, +{"blockNumber": 11883358, "blockId": "0x21f447aca9ddf94ed71df9fa3648a12acc2ba603f89f24c4784936864c41945f", "firstIndex": 4026531743}, +{"blockNumber": 11948524, "blockId": "0x71a52b6cce80d3a552b0daa18beb952facf81a89bc7ca769d08ac297f317507a", "firstIndex": 4093640009}, +{"blockNumber": 12013168, "blockId": "0x9a7fb369b8d8cd0edd0d890d636096f20c63abb7eb5798ad1e578cac599e3db8", "firstIndex": 4160748475}, +{"blockNumber": 12078711, "blockId": "0x5de09329413b0c2f58d926f225197552a335ba3d5544d7bdb45e7574f78c9b8d", "firstIndex": 4227858275}, +{"blockNumber": 12143640, "blockId": "0xbeafc0e1e0586f5a95f00f2a796d7df122c79c187aa2d917129297f24b8306bd", "firstIndex": 4294967145}, +{"blockNumber": 12208005, "blockId": "0x052487095cdd4a604808e6c14e30fb68b3fa546d35585b315f287219d38ef77c", "firstIndex": 4362075289}, +{"blockNumber": 12272465, "blockId": "0x82c8a50413bd67a0d6f53b085adcd9ae8c25ecc07ed766fa80297a8dcae63b29", "firstIndex": 4429184610}, +{"blockNumber": 12329418, "blockId": "0x294c147e48d32c217ff3f27a3c8c989f15eee57a911408ec4c28d4f13a36bb3b", "firstIndex": 4496292968}, +{"blockNumber": 12382388, "blockId": "0x8c2555965ff735690d2d94ececc48df4700e079c7b21b8e601a30d4e99bc4b5b", "firstIndex": 4563401809}, +{"blockNumber": 12437052, "blockId": "0x2e38362031f36a0f3394da619dcc03be03c19700594cbd1df84c2c476a87de63", "firstIndex": 4630511012}, +{"blockNumber": 12490026, "blockId": "0x122749c02a55c9c2a1e69068f54b6c1d25419eb743e3553aba91acf1daeadc35", "firstIndex": 4697619920}, +{"blockNumber": 12541747, "blockId": "0xfb9f12aa2902da798ac05fab425434f8c7ce98050d67d416dbb32f98c21f66f7", "firstIndex": 4764728267}, +{"blockNumber": 12597413, "blockId": "0x9a7a399c2904ac8d0fec580550525e7e1a73d8f65f739bf7c05d86e389d0d3f7", "firstIndex": 4831837757}, +{"blockNumber": 12651950, "blockId": "0xb78dcb572cdafb9c4e2f3863ef518a3b2df0cd4f76faa26a423b2ca0c1cde734", "firstIndex": 4898946491}, +{"blockNumber": 12706472, "blockId": "0xfd21f41ec6b0c39287d7d48c134d1212a261c53d65db99739994b003150bbad1", "firstIndex": 4966054796}, +{"blockNumber": 12762929, "blockId": "0xc94d994bc40b2ae7dc23cf2b92cc01e84915f090bb57c0d9a67584bd564d3916", "firstIndex": 5033164307}, +{"blockNumber": 12816689, "blockId": "0x7770c72f22cbf6ccf7ab85d203088f7ede89632cf0042c690102f926a90bd09d", "firstIndex": 5100273412}, +{"blockNumber": 12872408, "blockId": "0x2e008b8c952d828875d777f7912f472af96ffc977f2ceae884006682cab6b8ed", "firstIndex": 5167381625}, +{"blockNumber": 12929718, "blockId": "0x85eb0ed3c5910c6a01b65ef0a5b76c59c2cdb5094e6e27eb87c751d77bcc2c88", "firstIndex": 5234491305}, +{"blockNumber": 12988757, "blockId": "0xdf12045bea73af18d4e71f8be8e334160f78b85f96a3535a4056409d8b61355a", "firstIndex": 5301600237}, +{"blockNumber": 13049172, "blockId": "0xf07608d97a101cd9a95fee9d9062a15bcb333263e555f8cfa31da037e0468f30", "firstIndex": 5368709080}, +{"blockNumber": 13108936, "blockId": "0x42739341db582d2f39b91ec9e8cc758777ca3f6ff9f25cd98883619fd5f026a7", "firstIndex": 5435817013}, +{"blockNumber": 13175495, "blockId": "0x564f25eacb229350b7c648b5828169e7a0344ae62e866206828e2cfad8947f10", "firstIndex": 5502926476}, +{"blockNumber": 13237721, "blockId": "0x0973425abec0fa6319701b46e07c2373b0580e3adbed6900aad27d5bf26dcb95", "firstIndex": 5570035419}, +{"blockNumber": 13298771, "blockId": "0xf3a16fec5be808c9f7782fb578dc8cef7f8e2110f7289bd03c0cc13977dd1518", "firstIndex": 5637143840}, +{"blockNumber": 13361281, "blockId": "0x3c0b6364201ca9221b61af3de27a3a87e111870b8c7efc43a6d8496e98c68690", "firstIndex": 5704253046}, +{"blockNumber": 13421819, "blockId": "0x2f472e57997b95558b99e3e5e7e0e8d4dbf8b71c081aac6536c9ff5925dac2ce", "firstIndex": 5771361231}, +{"blockNumber": 13480620, "blockId": "0xc4d689e87464a0c83c661c8e3a0614c370631de857f7e385b161dfe8bacd3e71", "firstIndex": 5838469468}, +{"blockNumber": 13535793, "blockId": "0xe7674bacc8edce9fb3efd59b92c97da48fe7ace1de314b4a67d7d032fc3bb680", "firstIndex": 5905578026}, +{"blockNumber": 13590588, "blockId": "0x6a3e86bdce7dd7d8792e1af9156edd8c3ffee7c20fed97001f58a9a2699f6594", "firstIndex": 5972687757}, +{"blockNumber": 13646707, "blockId": "0xab404a5d3709cf571b04e9493f37116eeb5dd2bc9dc10c48387c1e0199013d69", "firstIndex": 6039797165}, +{"blockNumber": 13703025, "blockId": "0x20e2fde15b8fe56f5dd7ab0f324c552038167ed44864bf3978e531ae68d6d138", "firstIndex": 6106905803}, +{"blockNumber": 13761024, "blockId": "0x2ae49275e13e780f1d29aea8507b2a708ff7bfe977efac93e050273b8b3a8164", "firstIndex": 6174015107}, +{"blockNumber": 13819468, "blockId": "0xb9d19cb31dedb1128b11cad9ffd6e58c70fe7ba65ba68f1ac63668ac5160ad85", "firstIndex": 6241124350}, +{"blockNumber": 13877932, "blockId": "0x80b1ff0bb069a8479360a15eaa84ba30da02cfacadc564837f4b1c90478addb8", "firstIndex": 6308232256}, +{"blockNumber": 13935384, "blockId": "0xe1f5469a559a6114dd469af61b118b9d9551a69bbd49a4e88f2a2d724830c871", "firstIndex": 6375341632}, +{"blockNumber": 13994042, "blockId": "0x25188fb75f2328c870ade7c38ef42ff5fddef9c4e364eebe4c5d8d9cc3ecabab", "firstIndex": 6442449799}, +{"blockNumber": 14051123, "blockId": "0xf4ef2bce9ee9222bdcf6b3a0c204676d9345e211e10c983e523930274e041ef1", "firstIndex": 6509559107}, +{"blockNumber": 14109189, "blockId": "0x80b730c28f75d8cb5ec2fb736341cd87cb4ecb2c9c614e0a4ecc0f9812675d50", "firstIndex": 6576667347}, +{"blockNumber": 14166822, "blockId": "0xf662a24b91684fa8ac462b31071f406de8d6183dba46d30d690f4407bc6af36f", "firstIndex": 6643777079}, +{"blockNumber": 14222488, "blockId": "0x7333e324c96b12f11a38d1fc2ddb4860e018b90f5dc10f3dbe19f7679bb95535", "firstIndex": 6710885890}, +{"blockNumber": 14277180, "blockId": "0x4373c1000e8e10179657689e2f0e42f88bd1601ecb4a5d83970d10287f6654cc", "firstIndex": 6777994595}, +{"blockNumber": 14331080, "blockId": "0x9c708a750a3f284ec0ee950110b36fd488cb1ec24cd0c2ea72c19551ec5c42a5", "firstIndex": 6845103719}, +{"blockNumber": 14384243, "blockId": "0x34ce7503b76335aa18dec880b0cefd388a29e0fcff6f2e1ddda8fb8c0ac1daf0", "firstIndex": 6912212376}, +{"blockNumber": 14437670, "blockId": "0x79842efd3e406b41f51935fe2e6ad20a7dd5a9db2280ebd7f602ed93da1e3c24", "firstIndex": 6979320543}, +{"blockNumber": 14489204, "blockId": "0xcd12addf0afdc229e9fe3bd0a34677a3826c5e78d4baf715f8ed36b736d6627a", "firstIndex": 7046430591}, +{"blockNumber": 14541688, "blockId": "0x55f617abf208a73fc467e8cb5feead586b671dbb0f6281570b3c44b8eabb2b9e", "firstIndex": 7113538755}, +{"blockNumber": 14594551, "blockId": "0xc7211bf772e93c8c2f945fcb6098b47c3455604cb8b94a505cb5cb720914c369", "firstIndex": 7180646025}, +{"blockNumber": 14645065, "blockId": "0x6d5b0326f4b22e2b0196986a514f23ec6e9a62f70f53300a22b21ff661a6ef7e", "firstIndex": 7247756883}, +{"blockNumber": 14695926, "blockId": "0x0a77272250e43b4bb46c02eb76944881a3c6b00a21bb9086a8229199bd62d97a", "firstIndex": 7314865843}, +{"blockNumber": 14746330, "blockId": "0xd677fdbaf8efb1bfdc138ac6b2bd5d0e890a29acb1f52f40169181ad517b0d31", "firstIndex": 7381974956}, +{"blockNumber": 14798546, "blockId": "0xbb277e8623acd2ce2340cf32f6c0ddab70fd95d862287f68a3c37250a70619cd", "firstIndex": 7449082890}, +{"blockNumber": 14848230, "blockId": "0x587b39f11bdaa2091291c7c3947e88df2e91e7997f2375dfd43b6e310a538582", "firstIndex": 7516192636}, +{"blockNumber": 14897646, "blockId": "0xf5b5c9d0c024ca0c0f0c6171871f609687f4ccb064ededbd61176cf23a9011e8", "firstIndex": 7583299602}, +{"blockNumber": 14950782, "blockId": "0x50549486afaf92a4c3520012b325e914ef77a82e4d6530a71f9b1cca31bfae18", "firstIndex": 7650409868}, +{"blockNumber": 15004101, "blockId": "0x7edac55dea3ee4308db60b9bc0524836226fe301e085b3ce39105bd145ba7fc3", "firstIndex": 7717517503}, +{"blockNumber": 15056903, "blockId": "0xb4cfd02d435718598179cdba3f5c11eb8653fe97ec8d89c60673e3e07b8dfc94", "firstIndex": 7784627997}, +{"blockNumber": 15108302, "blockId": "0x53c77a7de4515e9e93467a76f04cc401834bcdd64e9dfa03cf6d2844a6930293", "firstIndex": 7851736988}, +{"blockNumber": 15159526, "blockId": "0x1a31ad84b423254d7ff24e7eca54048ed8cc13cec5eb7289bf3f98ed4de9f724", "firstIndex": 7918844431}, +{"blockNumber": 15211013, "blockId": "0xe5d491e1d6cc5322454143b915c106be1bf28114a41b054ba5e5cfe0abecafba", "firstIndex": 7985953942}, +{"blockNumber": 15264389, "blockId": "0xd9939bb9e58e95d2672c1148b4ec5730204527d3f3fc98ca03a67dc85cf3d710", "firstIndex": 8053063187}, +{"blockNumber": 15315862, "blockId": "0x7254f99c4bb05235d5b437984c9132164e33182d4ce11a3847999da5c28b4092", "firstIndex": 8120172147}, +{"blockNumber": 15364726, "blockId": "0x11b57547579d9009679e327f57e308fe86856391805bc3c86e7b39daae890f52", "firstIndex": 8187281042}, +{"blockNumber": 15412886, "blockId": "0xbe3602b1dbef9015a3ec7968ac7652edf4424934b6bf7b713b99d8556f1d9444", "firstIndex": 8254390023}, +{"blockNumber": 15462792, "blockId": "0x3348ca4e14ac8d3c6ac6df676deaf3e3b5e0a11b599f73bd9739b74ebd693efe", "firstIndex": 8321499024}, +{"blockNumber": 15509914, "blockId": "0xbc98fd6b71438d5a169f9373172fea799fa3d22a8e6fe648d35e1070f2261113", "firstIndex": 8388606521}, +{"blockNumber": 15558748, "blockId": "0x5fa2cf499276ae74a5b8618990e71ed11a063619afe25c01b46e6252eba14c19", "firstIndex": 8455716577}, +{"blockNumber": 15604217, "blockId": "0x78a608e13d2eb3c5fed81a19b829ede88071cf01ea9ff58112a7472435f97c30", "firstIndex": 8522825668}, +{"blockNumber": 15651869, "blockId": "0xd465d861d925d1475440782ff16c2b3361ba3c8e169d7cc90eb8dfc0f31b0aac", "firstIndex": 8589934080}, +{"blockNumber": 15700968, "blockId": "0x71e3def131271e02c06ca945d14a995703a48faac1334a9e2e2321edd0b504d0", "firstIndex": 8657043390}, +{"blockNumber": 15762986, "blockId": "0x9b1b51dca2eae29162ca66968a77b45175f134b44aea3defadcb924f83e0b944", "firstIndex": 8724151376}, +{"blockNumber": 15814455, "blockId": "0x3c04a509cb6304d3df4bef57e0119d9e615ab737ec0b4a7deada6e5f57d9f873", "firstIndex": 8791260562}, +{"blockNumber": 15865639, "blockId": "0x9e9e26148c774518ecf362c0e7c65a5c1b054a8a3e4e36036c70e273fac6147c", "firstIndex": 8858368894}, +{"blockNumber": 15920564, "blockId": "0x9efe1d4dbfd9aa891ac0cffd3e1422a27ba2ea4add211b6900a2242cdb0f0ca0", "firstIndex": 8925477950}, +{"blockNumber": 15974371, "blockId": "0xc63ccef7bc35a0b431a411f99fe581b322d00cfc6422d078696808a5658a32ac", "firstIndex": 8992587107}, +{"blockNumber": 16032913, "blockId": "0x3e60957224964669a8646914e3166553b9f4256d5be160b17995d838af3ef137", "firstIndex": 9059696632}, +{"blockNumber": 16091057, "blockId": "0x12b346047bb49063ab6d9e737775924cf05c52114202ddb1a2bdaf9caabbfe0c", "firstIndex": 9126804912}, +{"blockNumber": 16150977, "blockId": "0x49318a32ff0ce979c4061c1c34db2a94fb06e7669c93742b75aff14a134fa598", "firstIndex": 9193913896}, +{"blockNumber": 16207432, "blockId": "0xf7870865edf81be4389a0be01468da959de703df0d431610814d16ed480176e4", "firstIndex": 9261019778}, +{"blockNumber": 16262582, "blockId": "0x25818e0f4d54af6c44ef7b23add34409a47de3ab1c905889478f3ec8ad173ec3", "firstIndex": 9328131320}, +{"blockNumber": 16319695, "blockId": "0x25de4b1c18cc503f5d12b4fa9072d33a11fa503a3dbeb9ab3d016b57c1e5cd4d", "firstIndex": 9395240790}, +{"blockNumber": 16373605, "blockId": "0x3794a5e0d2aa10baf1e6a5ec623d6089fdd39799eff633017d8df5144526939f", "firstIndex": 9462349509}, +{"blockNumber": 16423494, "blockId": "0xe0217d947ba3865dfc9288e0c890b0996457bb9d18467bd125e86bbb0052b57f", "firstIndex": 9529458033}, +{"blockNumber": 16474853, "blockId": "0xd454f033d190f22f9e56f0209ea1eeb3b6257805d5d88650d2759eb4d24821b7", "firstIndex": 9596567055}, +{"blockNumber": 16525689, "blockId": "0x8a23cbbf3e258e13f5a1ada434366796cb4a3e5b1062455582fb2bc3ab991541", "firstIndex": 9663674943}, +{"blockNumber": 16574203, "blockId": "0xc1a5b7d26e8222bd2d56ef4108f75d69f7c116707d348950834e00962241a4f8", "firstIndex": 9730785112}, +{"blockNumber": 16622622, "blockId": "0x3ddb3ef7a4309bd788258fb0d62613c89a0b4de715f4e12f6017a194d19d6481", "firstIndex": 9797893665}, +{"blockNumber": 16672585, "blockId": "0x8aa5e9f72b261f9e2a9eb768483d1bbd84d3a88fdb1346f6a9a7f262fd28ba41", "firstIndex": 9865002893}, +{"blockNumber": 16720124, "blockId": "0x2128f8baf264166e37554d5c31a06de58d9ccfb663117358251da548a23a060f", "firstIndex": 9932111275}, +{"blockNumber": 16769162, "blockId": "0x6b3e849482d3222032740ad6b8f98e24636c82682a6a3572b1ef76dfebc66821", "firstIndex": 9999217824}, +{"blockNumber": 16818311, "blockId": "0xe45f57381978a2bfc85bd20af1c41e2b630412642ac4f606b477f05f030ef5d9", "firstIndex": 10066328668}, +{"blockNumber": 16869531, "blockId": "0xa154555266d24dc1f4885af5fafcf8cab3de788998cf69e1d28f56aa13a40c43", "firstIndex": 10133437302}, +{"blockNumber": 16921611, "blockId": "0xf1f829b4ab5eec6e243916dd530993fa11eef5510fd730e8d09ead6b380355a1", "firstIndex": 10200547185}, +{"blockNumber": 16974870, "blockId": "0x1a33202b95926ae4cb8e6e99d8d150f3c50d817b3a316452bdf428c971dabde5", "firstIndex": 10267655914}, +{"blockNumber": 17031277, "blockId": "0x706c9dd0dc81e7ac29d2ea0f826e6b8a1dcb5adb1b904ff6e43260729c9fd0a7", "firstIndex": 10334764934}, +{"blockNumber": 17086330, "blockId": "0x085a80cafe96b520105b9a1f8e7a2bbc9474da24da7e6344ca7c4d32db822f92", "firstIndex": 10401871892}, +{"blockNumber": 17141311, "blockId": "0x33ec6513dfa515bc5f6356476b4eb075a8064181d6aaf6aa1a1e18887e342f74", "firstIndex": 10468982364}, +{"blockNumber": 17190907, "blockId": "0x6f41273d3bf30d3347e7eb68872a49b3ac947f314543478be7a28a55e5c41a3c", "firstIndex": 10536090817}, +{"blockNumber": 17237199, "blockId": "0x9a87a14a128c0345a366940f821a14f16719de628658ac0628e410a72d723e90", "firstIndex": 10603200178}, +{"blockNumber": 17287181, "blockId": "0x9c6e78adcf562ac63c103e3e5a02f025023079aca79bdd6ef18f7bd2a6271c29", "firstIndex": 10670309183}, +{"blockNumber": 17338652, "blockId": "0x1b747da97b2397a293602af57514dab4ca1010bb6c601ff05cb2012dd1124ebb", "firstIndex": 10737418023}, +{"blockNumber": 17389337, "blockId": "0xbc3c0ca1e5989605b9b59c94b418562eb17ccbce30e45ac8531cf0b3867a6b2c", "firstIndex": 10804522857}, +{"blockNumber": 17442261, "blockId": "0x1ec341be1cbd09f559bfa3d3e39a341d8e21052eeb7880931d43d086651733b7", "firstIndex": 10871635535}, +{"blockNumber": 17497787, "blockId": "0x6069880d486f2548599df1e14e12752d3eb9bc99843a98cd6631c22be1b58554", "firstIndex": 10938744657}, +{"blockNumber": 17554322, "blockId": "0x69b2564bc00b1f310f6b416912869d7530d7864bf7d70d55c7ace554f129b989", "firstIndex": 11005852829}, +{"blockNumber": 17608492, "blockId": "0x7d590653d5fa52c0d3ee453a77d2088504f57adcef35cd57c567afb554608457", "firstIndex": 11072961972}, +{"blockNumber": 17664272, "blockId": "0xdc16159d3500cdc7410873102f41fc55de2a8a41e3779c4b70e6224a541e2b9e", "firstIndex": 11140070967}, +{"blockNumber": 17715101, "blockId": "0x655e33c4e81182464ea0b0e1fdbc53ce53902431db5107326b816091a4564652", "firstIndex": 11207179487}, +{"blockNumber": 17764042, "blockId": "0x54439184f31cd83ba06b48b6dbfdd744ae7246355be1327b44744058711d05c0", "firstIndex": 11274287303}, +{"blockNumber": 17814383, "blockId": "0xfb453bc951360c76fb09bb1b9a3e39d23ececa0adb93368cc3f41f0457845089", "firstIndex": 11341397984}, +{"blockNumber": 17864648, "blockId": "0x32a68823ef4ec0cbab2fe50c97e3f462b575e8b117da40d00c710b4c66ee1d6d", "firstIndex": 11408505657}, +{"blockNumber": 17913366, "blockId": "0x04b944aab8a4ff91b77c2191817cf051766100c227616a3746af53407e740124", "firstIndex": 11475614351}, +{"blockNumber": 17961690, "blockId": "0x08bee7cc0b764106ca01dd5370b617879487ffb423688c96e948dce125990f45", "firstIndex": 11542723488}, +{"blockNumber": 18011048, "blockId": "0x94c39d3a64f3e9a91b1d98554cd29e1390e30fa61cfa4e909c503eee2fd9f165", "firstIndex": 11609833142}, +{"blockNumber": 18061209, "blockId": "0x2ee9ade68955c030488c8a30537bdf948355f7dd5ae64942b5bfce1be6650e19", "firstIndex": 11676941316}, +{"blockNumber": 18111692, "blockId": "0xd6c4fd0c1cc20ed5e7960bb5043e9e5e9c66a4d2ec5709ac9797fff678435640", "firstIndex": 11744050346}, +{"blockNumber": 18166212, "blockId": "0x3262588c2ef79a3b3f6a3db6435202d22f5667cd48c136b0797404901525c9ff", "firstIndex": 11811159686}, +{"blockNumber": 18218743, "blockId": "0x935bd9a4164ff7ecd09a37b916ce5bf78487bd19377b5b17be153e39318aee74", "firstIndex": 11878268593}, +{"blockNumber": 18271236, "blockId": "0xe58ebb821f27e3665898f390802a3d129d217b3a3ee36d890a85cf22a0a8aa33", "firstIndex": 11945376750}, +{"blockNumber": 18323007, "blockId": "0x3997a841468efa1bc614bfc3de4502274901b04b428f87a1f3086dfd78cda1eb", "firstIndex": 12012485748}, +{"blockNumber": 18372443, "blockId": "0xc44a13a5d02e8dc39f355de5e21ce7bb311ce7f4d9114ff480dce235a169e416", "firstIndex": 12079595370}, +{"blockNumber": 18421829, "blockId": "0x7da63a0b613d8745597b2ac64fd5cc8b2fb14b24d163b12a0a39d7d3d4ff7b5c", "firstIndex": 12146703582}, +{"blockNumber": 18471706, "blockId": "0xd632a1893f415ff618f4b612a7687e6af1f12feeed81f46f0022090829c1eb4c", "firstIndex": 12213812677}, +{"blockNumber": 18522301, "blockId": "0x44fa2cf08145ae40e8e42f4e6b4ab7df360a17c5a065ce45fcc41b51bee011f4", "firstIndex": 12280921639}, +{"blockNumber": 18572935, "blockId": "0x72b8ab4c78c90425ee054b4806a8be703da0febdf1d51866358ec2bd21ba9529", "firstIndex": 12348029751}, +{"blockNumber": 18623431, "blockId": "0x8c4cb2f13501d9788820280c6f16692d0737258c3896f1e4bded32d838febf7f", "firstIndex": 12415138965}, +{"blockNumber": 18675470, "blockId": "0x523b73c19ea8b3ae32ef141a83ef9855e667ebf51443cfcabd1a06659359062a", "firstIndex": 12482247454}, +{"blockNumber": 18725728, "blockId": "0x0cfbd131eb5dad51488238079fba29a63eebb5c32d1a543cb072e48dc2104ef3", "firstIndex": 12549356369}, +{"blockNumber": 18778387, "blockId": "0xc4906c77af8058b9f172a4f0e8788c7887f05caa5ac752b38b5387080f74ae49", "firstIndex": 12616465992}, +{"blockNumber": 18835044, "blockId": "0x49c5e07f409a841dc81f3ef8417f1951f8fcc13c90134f9d2a0cd11938f9fa36", "firstIndex": 12683575082}, +{"blockNumber": 18883308, "blockId": "0x386a58dd5f79a419eeb05075b07b3ff3bc836a265c9688854a504223b1d6a830", "firstIndex": 12750683753}, +{"blockNumber": 18933635, "blockId": "0xd3881292147589bd2e192769e5c9175b5d03a453fe1ef3c4b5b6858ac9402a2f", "firstIndex": 12817792470}, +{"blockNumber": 18988254, "blockId": "0xcbe72dfa15428ac21b9c59c703ceaa0eb4b2205927687261d7aaed3dbb3783ea", "firstIndex": 12884882858}, +{"blockNumber": 19041325, "blockId": "0x92b077e1c2f8819da728f0307c914fdcd57eba14ea07d9a45c28d1ed8ffff576", "firstIndex": 12952010530}, +{"blockNumber": 19089163, "blockId": "0x43f8ab2d3dfc34c8e18cba903074d54e235dc546f19c4eb78245a522c266c84e", "firstIndex": 13019119228}, +{"blockNumber": 19140629, "blockId": "0xab7b7ae5424b18105a13b657fa6099d4ab67fde5baff39fe6e4de707397e995c", "firstIndex": 13086228236}, +{"blockNumber": 19192118, "blockId": "0x451327e6a5cf6ce1c8c14c01687dc5f719f3c2176f46bac4f264616256e30d1c", "firstIndex": 13153337116}, +{"blockNumber": 19237836, "blockId": "0x9b260d6be369557d1dc88aca423e2697e697d941d1b726c183015b5649e248c8", "firstIndex": 13220445421}, +{"blockNumber": 19291271, "blockId": "0x4878c28d79e1f71bc11e062eb61cb52ae6a18b670b0f9bea38b477944615078e", "firstIndex": 13287554254}, +{"blockNumber": 19344448, "blockId": "0x56243b9ad863bf90953fe9aa6e64a426629384db1190e70dce79575d30595f7e", "firstIndex": 13354663659}, +{"blockNumber": 19394948, "blockId": "0x195173b64dda7908d6aa39a63c8bdd29ec181d401e369d513be1308550d0ddcb", "firstIndex": 13421771935}, +{"blockNumber": 19443075, "blockId": "0xd39c1d60996475e65d1ab5b4e755f510ca466564a8155d35db6667988d6c0e44", "firstIndex": 13488880427}, +{"blockNumber": 19488383, "blockId": "0x28956eb8856fa8db59c02585016b8baf43bc44bc35b00bdaf8a6babe51101c5c", "firstIndex": 13555977105}, +{"blockNumber": 19534584, "blockId": "0x2421c97b0f140185d4c20943cd4ed7d7424468482feb76e3003a1cc69da3fd7b", "firstIndex": 13623097580}, +{"blockNumber": 19579602, "blockId": "0x25f96529028e9f51c59aec9ce8de282b7dd67066fd46a1694130698ed0f40d8b", "firstIndex": 13690207623}, +{"blockNumber": 19621517, "blockId": "0x4f6f6e0a0488f3d51823bc4b07c292348c259b1866968f77ee76b66b37101c75", "firstIndex": 13757315529}, +{"blockNumber": 19665085, "blockId": "0x00f9315f89681b44bff46f1bad8894bc6dfae1c459d3d6520f9881861304a496", "firstIndex": 13824425382}, +{"blockNumber": 19709229, "blockId": "0x24e022b21ae1ba8a3e8c87cb9734aa1d1810fc4a69fe147d3ebb1ff0df8bcc15", "firstIndex": 13891534799}, +{"blockNumber": 19755387, "blockId": "0x77f184b7183b1a351760d242041249464b42cfaa6fbc4326f352b06bb3b21a02", "firstIndex": 13958642483}, +{"blockNumber": 19803894, "blockId": "0xf37eb1b054a6d61272940361f386eb744cded84d15c3250a7eabadede257371c", "firstIndex": 14025751618}, +{"blockNumber": 19847885, "blockId": "0x4659649fa8a3b4bbe8978673ba9a22ae20352c7052b676d373b5a51b1967ffa4", "firstIndex": 14092848654}, +{"blockNumber": 19894193, "blockId": "0x15606bdc0f1a710bd69443c7154d4979aece9329977b65990c9b39d6df84ed5c", "firstIndex": 14159970181}, +{"blockNumber": 19938551, "blockId": "0x6a8f4571924ed902bd8e71bf8ed9cc9d72cabeabc410277c8f0fc2b477d00eb7", "firstIndex": 14227077892}, +{"blockNumber": 19985354, "blockId": "0x7b6fb6376410b4d9e5d7ee02f78b2054e005dd2976eea47fc714f66b967dc285", "firstIndex": 14294187965}, +{"blockNumber": 20028440, "blockId": "0x9b37440b71c24756b8855b8012432b84276ae94c80aa1ccc8b70a7705992103c", "firstIndex": 14361296503}, +{"blockNumber": 20071780, "blockId": "0xa2ed129f343f3d60419772ec5635edcd36b8680c9419b6626e2bc84b230c709b", "firstIndex": 14428405230}, +{"blockNumber": 20113832, "blockId": "0xe7a610e8bcbf8ded141ebc7142de03dfc54b1bcc79e3bf8d07fad4e42b665bba", "firstIndex": 14495512019}, +{"blockNumber": 20156854, "blockId": "0xbe09704f65a70ef8843d9c8e511ddc989ea139dbe94cdfe37f52b03620d62385", "firstIndex": 14562622430}, +{"blockNumber": 20200135, "blockId": "0x9a58c34d5f77342e94065d119905c000223cd988c4b11f1539fff20737159630", "firstIndex": 14629731923}, +{"blockNumber": 20244389, "blockId": "0x1e733f0db9ef21183107259b3c2408c78fa5a01469928cd295f3ea7e8eedda45", "firstIndex": 14696840011}, +{"blockNumber": 20288489, "blockId": "0xb5ad7edd86b181226c8c7be0a08069e3955234e797426843fff9de0f57ec59cc", "firstIndex": 14763949714}, +{"blockNumber": 20333582, "blockId": "0x8040c209f5cd1738ee0f85c2f1db7c43a420d148680c7390fd1701b9f0bb671a", "firstIndex": 14831058335}, +{"blockNumber": 20377087, "blockId": "0x08fdc4cd246b6ae9d4a45646b0aed6af3bb330eb6cd4c8b93646157e7b002b84", "firstIndex": 14898167722}, +{"blockNumber": 20421699, "blockId": "0x5a2912b5fc2f02df33b655155990f92dcaacda5b75427fe3d87fb38f36b1c17d", "firstIndex": 14965275691}, +{"blockNumber": 20467194, "blockId": "0x3deaf4325c461004b090b0261996c645ab529c1471feaf7dc2bbe1f128180297", "firstIndex": 15032385211}, +{"blockNumber": 20512397, "blockId": "0x37e39697ec1b7683a6202be250ffaee7a1102e8030f87550b94af05ec66cec83", "firstIndex": 15099493973}, +{"blockNumber": 20557443, "blockId": "0x8e9c04468f3111eab8b1f6a58b277862c624861c237cadecc53ec249bd811bda", "firstIndex": 15166602882}, +{"blockNumber": 20595899, "blockId": "0x9787555fe57e4650002257eb2c88f1ef435b99d406e33fe2f889be180123ef25", "firstIndex": 15233709908}, +{"blockNumber": 20638606, "blockId": "0x70681cffd159ce2e580dbbbe8fa6b5343dbcb081429cdda6c577e615bef4ef05", "firstIndex": 15300820678}, +{"blockNumber": 20683605, "blockId": "0xb32662d5e241132ffe2249caea67f5746a6f4382297b2ac87c81e2794faf1f7a", "firstIndex": 15367929350}, +{"blockNumber": 20728630, "blockId": "0x15a817c846928b673032d5eacd0cff7a04217d268457aa30a322ecca32be4d49", "firstIndex": 15435037830}, +{"blockNumber": 20771519, "blockId": "0x542bc7b9804bbc45f4be470f4dc56f215a4dec71fed71eba2ffc804afd262b95", "firstIndex": 15502145990}, +{"blockNumber": 20815097, "blockId": "0x798cdd51c964fcf18561d70095d9613b84ba836817972799c9dfd0bfbe1e042b", "firstIndex": 15569256033}, +{"blockNumber": 20857859, "blockId": "0xfb5bb066d419a651d8e0186569eb4e8d8bcd5181d8f02e0d578b5dfe2fc738dd", "firstIndex": 15636364671}, +{"blockNumber": 20896890, "blockId": "0x834b8d6fad779e4cf8214128f6c93d7387b6d6279e517f6f0a284b5d831cc3ae", "firstIndex": 15703472902}, +{"blockNumber": 20939387, "blockId": "0x7adee7c78420c711efa216c61e0b561e581d7ff0331efd91ee16a609b34cfdc2", "firstIndex": 15770582325}, +{"blockNumber": 20981303, "blockId": "0x6f5d7b0cc6dad5eb258176e07de21795a8347d68f7303f06934046e0236bea6d", "firstIndex": 15837691713}, +{"blockNumber": 21023216, "blockId": "0x96cfe35a45df1297a36f42c59ebe706ab0473dfbf59ce910b5c5a8dbf696de1c", "firstIndex": 15904799667}, +{"blockNumber": 21068378, "blockId": "0x93753875ff330d922b23f823203198f3b1bb8833367c6b6a8f896ff54be2c12d", "firstIndex": 15971909040}, +{"blockNumber": 21112445, "blockId": "0x6ac02fa6ae486b86aba562eaf6f3d883befaa8ebedcfd8d74bdb7368d42deee3", "firstIndex": 16039003625}, +{"blockNumber": 21155992, "blockId": "0x25f76896b4b693bafb79e9a535e2bf00ed62a577e35209749346e8e79a60bb71", "firstIndex": 16106126344}, +{"blockNumber": 21200962, "blockId": "0x725f2befe913cb2659d262e2d3b6f79a706b31c557d52669471da22347ec8287", "firstIndex": 16173235265}, +{"blockNumber": 21244663, "blockId": "0x6778c4194f54e70939da38853daddb22bfaf160d35617ab05d0f5c476741147b", "firstIndex": 16240344735}, +{"blockNumber": 21290273, "blockId": "0x433ac819c40bd3061205fe0ece0645eec73f54a0a5c1559c981f983345bc0154", "firstIndex": 16307453543}, +{"blockNumber": 21336156, "blockId": "0x261dc8c1639d505624150d2388d15ed10bfb4c3ce9c0c327a4ec26531689a097", "firstIndex": 16374562466}, +{"blockNumber": 21378880, "blockId": "0x5c78b2b70553140dfdfdd4f415b98f88e74f74662315834038fd99042277d917", "firstIndex": 16441671104}, +{"blockNumber": 21421613, "blockId": "0x854532f9d1c77627b763f9cbc7099a653d59554ed57fa763bc218834c82955fe", "firstIndex": 16508780351}, +{"blockNumber": 21466875, "blockId": "0xb8b83cc62084e948235ef4b5973bf7fd988fa28bcaa72f7d38ad8e50de729618", "firstIndex": 16575888599}, +{"blockNumber": 21511942, "blockId": "0xe806a28bc1b7f8cd752c8ceedbe081d49773d4558a9fb95e3357c0c07172522d", "firstIndex": 16642996907}, +{"blockNumber": 21550291, "blockId": "0x1f3e26d303e7a2a9b0614f12f62b189da365b3947c5fe2d99ed2711b37fe7daa", "firstIndex": 16710106826}, +{"blockNumber": 21592690, "blockId": "0xa1408cfbc693faee4425e8fd9e83a181be535c33f874b56c3a7a114404c4f686", "firstIndex": 16777215566}, +{"blockNumber": 21636275, "blockId": "0x704734c2d0351f8ccd38721a9a4b80c063368afaaa857518d98498180a502bba", "firstIndex": 16844323959}, +{"blockNumber": 21681066, "blockId": "0x1e738568ed393395c498b109ad61c0286747318aae0364936f19a7b6aba94aef", "firstIndex": 16911433076}, +{"blockNumber": 21725592, "blockId": "0xee87b7948e25a7498a247c616a0fbaa27f21b004e11fc56f2a20c03791ed8122", "firstIndex": 16978540993} +] + diff --git a/core/filtermaps/checkpoints_sepolia.json b/core/filtermaps/checkpoints_sepolia.json new file mode 100644 index 000000000..3e3ea23b2 --- /dev/null +++ b/core/filtermaps/checkpoints_sepolia.json @@ -0,0 +1,63 @@ +[ +{"blockNumber": 3246675, "blockId": "0x36bf7de9e1f151963088ca3efa206b6e78411d699d2f64f3bf86895294275e0b", "firstIndex": 67107286}, +{"blockNumber": 3575582, "blockId": "0x08931012467636d3b67ae187790951daed2bb6423f9cd94e166df787b856788d", "firstIndex": 134217672}, +{"blockNumber": 3694264, "blockId": "0x1f35f276a3c78e5942ee285fcbd0c687691853c599a2f5b174ea88f653bc9514", "firstIndex": 201326578}, +{"blockNumber": 3725632, "blockId": "0x3bcb264c56c3eeab6c8588145f09dff3fb5f821d9fc1e7b92264b14314dae553", "firstIndex": 268433636}, +{"blockNumber": 3795390, "blockId": "0x2d1ef2815bb8e018b275fa65540b98265285016aff12596bd89a3b1442d248eb", "firstIndex": 335542953}, +{"blockNumber": 3856683, "blockId": "0x8a9a46d6f53975cd9ec829c3c307a99fb62b8428cefb63ffe06d17143649c3ee", "firstIndex": 402648835}, +{"blockNumber": 3869370, "blockId": "0x2e8c04e7e5e96d09260b65d77b1770b4105b0db2ee7d638c48f086b8afac17db", "firstIndex": 469759276}, +{"blockNumber": 3938357, "blockId": "0xf20f2cdbcc412d5340e31955d14a6526ea748ba99b5ec70b6615bdb18bcd4cfb", "firstIndex": 536868027}, +{"blockNumber": 3984894, "blockId": "0x0bcd886b3cebb884d5beeaf5ad15ee1514968b5ad07177297c7d9c00f27aa406", "firstIndex": 603968430}, +{"blockNumber": 4002664, "blockId": "0x7d3575b6ca685468fa5a5fa9ff9d5fac4415b0a67a3ed87d3530f127db32fff4", "firstIndex": 671088417}, +{"blockNumber": 4113187, "blockId": "0x3a5313ac5b602134bb73535b22801261e891ccb7bd660ab20e0a536dc46d3e13", "firstIndex": 738197016}, +{"blockNumber": 4260758, "blockId": "0xe30fb9a304d3602896a5716d310f67ba34ccef7f809a3ead4b2d991cb9ee4eb0", "firstIndex": 805306270}, +{"blockNumber": 4391131, "blockId": "0x3958478c1c3be9b7caedbcc96230ed446d711e56580e324bc2fcf903fc87c90f", "firstIndex": 872415115}, +{"blockNumber": 4515650, "blockId": "0x46a3a7b97a9dff4ef4dc2c1cc5cd501f2182d9548655b77b5e07a2dbb41071a4", "firstIndex": 939523930}, +{"blockNumber": 4634818, "blockId": "0x2197d0dd3925c1d7ba3e2c4eef20035b68efc0a2506f76ddd9e481e0ce8ca6e1", "firstIndex": 1006628557}, +{"blockNumber": 4718295, "blockId": "0xcce7bb4af1a41e6056ef68192e60c738be01ac3e071ed1ec52cead08a39995ce", "firstIndex": 1073734698}, +{"blockNumber": 4753438, "blockId": "0xa60e043728a369cdf39a399bd7a903085ee9386f38176947578e5692b4b01f65", "firstIndex": 1140843192}, +{"blockNumber": 4786522, "blockId": "0x10629cadc00e65f193fa4d10ecd2bf1855e442814c4a409d19aae9eb895dce13", "firstIndex": 1207956586}, +{"blockNumber": 4811706, "blockId": "0xf1e94111f0086733bdcb4a653486a8b94ec998b61dda0af0fd465c9b4e344f87", "firstIndex": 1275058221}, +{"blockNumber": 4841796, "blockId": "0xa530f7dd72881ac831affdc579c9d75f6d4b6853b1f1894d320bd9047df5f9eb", "firstIndex": 1342177155}, +{"blockNumber": 4914835, "blockId": "0xbd8321e354f72c4190225f8ed63d4aba794b3b568677d985e099cb62d9d36bae", "firstIndex": 1409286143}, +{"blockNumber": 4992519, "blockId": "0x4a06a5a4aa5bc52151937cc1c0f8da691a0282e94aab8b73b9faa87da8d028de", "firstIndex": 1476384367}, +{"blockNumber": 5088668, "blockId": "0xb7d5ee03c08ed3936348eeb3931be8f804e61f2b09debf305967c6a7bbf007e0", "firstIndex": 1543502599}, +{"blockNumber": 5155029, "blockId": "0x84f590dfc2e11f1ca53c1757ac3c508d56f55ee24d6ca5501895974be4250d76", "firstIndex": 1610605837}, +{"blockNumber": 5204413, "blockId": "0xeaf2c3fb6f927c16d38fab08b34303867b87470558612404c7f9e3256b80c5b9", "firstIndex": 1677720841}, +{"blockNumber": 5269957, "blockId": "0x596e0b2e8e4c18c803b61767320fe32c063153d870c94e4a08e9a68cbaa582a9", "firstIndex": 1744825147}, +{"blockNumber": 5337678, "blockId": "0x7b2d54f8af1ecaaaab994e137d4421d8236c1c10d9a7bdcb9e5500db7a3fe9a3", "firstIndex": 1811939316}, +{"blockNumber": 5399058, "blockId": "0xb61ef16d55c96682fb62b0110a2dbc50d8eff2526be4121ece3690700611c71b", "firstIndex": 1879046044}, +{"blockNumber": 5422707, "blockId": "0xdabcab7c0cc9cb9f22f7507a1076c87831cb1afed9d0aa5bcd93f22266720c91", "firstIndex": 1946156915}, +{"blockNumber": 5454264, "blockId": "0xe1bde812906605ce662f5fd9f01b49c7331fb25f52ab5b12d35ea2b4da5458fe", "firstIndex": 2013259168}, +{"blockNumber": 5498898, "blockId": "0x9533d9c5353d22f8a235e95831cfbf4d5a7220a430ca23494526a9d3aa866fe8", "firstIndex": 2080374321}, +{"blockNumber": 5554801, "blockId": "0xe7b320bbecb19f1e99dd6ce4aed1efc754d7b2022e1f80389e8a21413c465f55", "firstIndex": 2147476253}, +{"blockNumber": 5594725, "blockId": "0xce6750be4a5b3e0fe152dd02308e94f7d56b254852a7e9acef6e14105053d7d1", "firstIndex": 2214591591}, +{"blockNumber": 5645198, "blockId": "0x5d42d39999c546f37001d5f613732fb54032384dd71a686d3664d2c8a1337752", "firstIndex": 2281696503}, +{"blockNumber": 5687659, "blockId": "0x3ed941be39a33ffa69cf3531a67f5a25f712ba05db890ff377f60d26842e4b1c", "firstIndex": 2348801751}, +{"blockNumber": 5727823, "blockId": "0xaf699b6c4cd58181bd609a66990b8edb5d1b94d5ff1ab732ded35ce7b8373353", "firstIndex": 2415917178}, +{"blockNumber": 5784505, "blockId": "0x621c740d04ea41f70a2f0537e21e5b96169aea8a8efee0ae5527717e5c40aa64", "firstIndex": 2483024581}, +{"blockNumber": 5843958, "blockId": "0xec122204a4e4698748f55a1c9f8582c46bacda029aee4de1a234e67e3288e6b1", "firstIndex": 2550136761}, +{"blockNumber": 5906359, "blockId": "0x8af5ce73fbd7a6110fb8b19b75a7322456ece88fcfa1614c745f1a65f4e915c1", "firstIndex": 2617245617}, +{"blockNumber": 5977944, "blockId": "0xbc8186258298a4f376124989cfb7b22c2bea6603a5245bb6c505c5fc45844bbd", "firstIndex": 2684350982}, +{"blockNumber": 6051571, "blockId": "0x54f9df9d9d73d1aa1cfcd6f372377c6013ecba2a1ed158d3c304f4fca51dae58", "firstIndex": 2751463209}, +{"blockNumber": 6118461, "blockId": "0xfea757fad3f763c62a514a9c24924934539ca56620bd811f83e9cc2e671f0cf0", "firstIndex": 2818572283}, +{"blockNumber": 6174385, "blockId": "0x2d8d0226e58f7516c13f9e1c9cf3ea65bb520fa1dfd7249dc9ea34a4e1fd430d", "firstIndex": 2885681036}, +{"blockNumber": 6276318, "blockId": "0xa922e9d54fd062b658c4866ed218632ddd51f250d671628a42968bb912d3ed5d", "firstIndex": 2952789983}, +{"blockNumber": 6368452, "blockId": "0x8d3d7466a7c9ca7298f82c37c38b0f64ec04522d2ed2e2349f8edc020c57f2c4", "firstIndex": 3019898695}, +{"blockNumber": 6470810, "blockId": "0x9887c35542835ee81153fa0e4d8a9e6f170b6e14fc78d8c7f3d900d0a70434f1", "firstIndex": 3087007578}, +{"blockNumber": 6553334, "blockId": "0x7b0d89a0282c18785fcc108dbdc9d45dd9d63b7084ddc676df9e9504585a5969", "firstIndex": 3154115987}, +{"blockNumber": 6663825, "blockId": "0xff6cec99324a89d6d36275c17a4569f0cba203fe5b0350f155a7d5445e0ed419", "firstIndex": 3221224775}, +{"blockNumber": 6767082, "blockId": "0xe10a96a7194f98bf262f0cb1cdfb4d3b9a2072139dfcbe3f1eb01419e353044e", "firstIndex": 3288334139}, +{"blockNumber": 6886709, "blockId": "0x20f6a5d986913025ad5b6b6387d818e49a3caf838326f4002c1439ca61313be5", "firstIndex": 3355442979}, +{"blockNumber": 6978948, "blockId": "0xd7c3024765245ec49e6a48b076d540bc91f57f2ccc125e17d60dd37bb669f843", "firstIndex": 3422551908}, +{"blockNumber": 7098891, "blockId": "0x05114c037e1b4d69a46d74a974be9bce45e87ad2226a59b44dd17f98dd2fd0d1", "firstIndex": 3489659530}, +{"blockNumber": 7203157, "blockId": "0xc0f610014fcd9f2850274b58179d474f0947676fd0639b2884316467c631811d", "firstIndex": 3556769512}, +{"blockNumber": 7256735, "blockId": "0x0324c15b3b23fd82c2962dd167618e77e60ebeac5a2c87f672caddc9732337b3", "firstIndex": 3623876508}, +{"blockNumber": 7307851, "blockId": "0x8e23280d1a3aec877d7758413ed20299d381aa43e7e2fc6f381ad96e8ff0acef", "firstIndex": 3690987098}, +{"blockNumber": 7369389, "blockId": "0xbf6436eb2b88539945d6673141a14cb79ffc1e7db2b57176acf8e02ff3b6fcd3", "firstIndex": 3758096287}, +{"blockNumber": 7445220, "blockId": "0x147619f74815283d834ac08ff494fb4791207b3949c64b2623f11ff6141ee7a7", "firstIndex": 3825204992}, +{"blockNumber": 7511632, "blockId": "0x5094d64868f419e6ac3d253d19d5feda76564a0d56d7bbf8a822dff1c2261b30", "firstIndex": 3892314047}, +{"blockNumber": 7557280, "blockId": "0x54aba9351a1ba51873645221aa7c991024da1fe468a600ddb6e2559351d9c28f", "firstIndex": 3959422859}, +{"blockNumber": 7606304, "blockId": "0xbbe2fed08cf0b0ff2cb6ae9fd7257843f77a04a7d4cafb06d7a4bedea6ab0c98", "firstIndex": 4026531690} +] + diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go new file mode 100644 index 000000000..95dd18155 --- /dev/null +++ b/core/filtermaps/filtermaps.go @@ -0,0 +1,726 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "bytes" + "errors" + "fmt" + "os" + "slices" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/leveldb" + "github.com/ethereum/go-ethereum/log" +) + +const ( + cachedLastBlocks = 1000 // last block of map pointers + cachedLvPointers = 1000 // first log value pointer of block pointers + cachedBaseRows = 100 // groups of base layer filter row data + cachedFilterMaps = 3 // complete filter maps (cached by map renderer) + cachedRenderSnapshots = 8 // saved map renderer data at block boundaries +) + +// FilterMaps is the in-memory representation of the log index structure that is +// responsible for building and updating the index according to the canonical +// chain. +// +// Note that FilterMaps implements the same data structure as proposed in EIP-7745 +// without the tree hashing and consensus changes: +// https://eips.ethereum.org/EIPS/eip-7745 +type FilterMaps struct { + // If disabled is set, log indexing is fully disabled. + // This is configured by the --history.logs.disable Geth flag. + // We chose to implement disabling this way because it requires less special + // case logic in eth/filters. + disabled bool + + closeCh chan struct{} + closeWg sync.WaitGroup + history uint64 + exportFileName string + Params + + db ethdb.KeyValueStore + + // fields written by the indexer and read by matcher backend. Indexer can + // read them without a lock and write them under indexLock write lock. + // Matcher backend can read them under indexLock read lock. + indexLock sync.RWMutex + indexedRange filterMapsRange + indexedView *ChainView // always consistent with the log index + + // also accessed by indexer and matcher backend but no locking needed. + filterMapCache *lru.Cache[uint32, filterMap] + lastBlockCache *lru.Cache[uint32, lastBlockOfMap] + lvPointerCache *lru.Cache[uint64, uint64] + baseRowsCache *lru.Cache[uint64, [][]uint32] + + // the matchers set and the fields of FilterMapsMatcherBackend instances are + // read and written both by exported functions and the indexer. + // Note that if both indexLock and matchersLock needs to be locked then + // indexLock should be locked first. + matchersLock sync.Mutex + matchers map[*FilterMapsMatcherBackend]struct{} + + // fields only accessed by the indexer (no mutex required). + renderSnapshots *lru.Cache[uint64, *renderedMap] + startedHeadIndex, startedTailIndex, startedTailUnindex bool + startedHeadIndexAt, startedTailIndexAt, startedTailUnindexAt time.Time + loggedHeadIndex, loggedTailIndex bool + lastLogHeadIndex, lastLogTailIndex time.Time + ptrHeadIndex, ptrTailIndex, ptrTailUnindexBlock uint64 + ptrTailUnindexMap uint32 + + targetView *ChainView + matcherSyncRequest *FilterMapsMatcherBackend + finalBlock, lastFinal uint64 + lastFinalEpoch uint32 + stop bool + targetViewCh chan *ChainView + finalBlockCh chan uint64 + blockProcessingCh chan bool + blockProcessing bool + matcherSyncCh chan *FilterMapsMatcherBackend + waitIdleCh chan chan bool + tailRenderer *mapRenderer + + // test hooks + testDisableSnapshots, testSnapshotUsed bool +} + +// filterMap is a full or partial in-memory representation of a filter map where +// rows are allowed to have a nil value meaning the row is not stored in the +// structure. Note that therefore a known empty row should be represented with +// a zero-length slice. +// It can be used as a memory cache or an overlay while preparing a batch of +// changes to the structure. In either case a nil value should be interpreted +// as transparent (uncached/unchanged). +type filterMap []FilterRow + +// copy returns a copy of the given filter map. Note that the row slices are +// copied but their contents are not. This permits extending the rows further +// (which happens during map rendering) without affecting the validity of +// copies made for snapshots during rendering. +func (fm filterMap) copy() filterMap { + c := make(filterMap, len(fm)) + copy(c, fm) + return c +} + +// FilterRow encodes a single row of a filter map as a list of column indices. +// Note that the values are always stored in the same order as they were added +// and if the same column index is added twice, it is also stored twice. +// Order of column indices and potential duplications do not matter when searching +// for a value but leaving the original order makes reverting to a previous state +// simpler. +type FilterRow []uint32 + +// Equal returns true if the given filter rows are equivalent. +func (a FilterRow) Equal(b FilterRow) bool { + return slices.Equal(a, b) +} + +// filterMapsRange describes the rendered range of filter maps and the range +// of fully rendered blocks. +type filterMapsRange struct { + initialized bool + headBlockIndexed bool + headBlockDelimiter uint64 // zero if afterLastIndexedBlock != targetBlockNumber + // if initialized then all maps are rendered between firstRenderedMap and + // afterLastRenderedMap-1 + firstRenderedMap, afterLastRenderedMap uint32 + // if tailPartialEpoch > 0 then maps between firstRenderedMap-mapsPerEpoch and + // firstRenderedMap-mapsPerEpoch+tailPartialEpoch-1 are rendered + tailPartialEpoch uint32 + // if initialized then all log values belonging to blocks between + // firstIndexedBlock and afterLastIndexedBlock are fully rendered + // blockLvPointers are available between firstIndexedBlock and afterLastIndexedBlock-1 + firstIndexedBlock, afterLastIndexedBlock uint64 +} + +// hasIndexedBlocks returns true if the range has at least one fully indexed block. +func (fmr *filterMapsRange) hasIndexedBlocks() bool { + return fmr.initialized && fmr.afterLastIndexedBlock > fmr.firstIndexedBlock +} + +// lastBlockOfMap is used for caching the (number, id) pairs belonging to the +// last block of each map. +type lastBlockOfMap struct { + number uint64 + id common.Hash +} + +// Config contains the configuration options for NewFilterMaps. +type Config struct { + History uint64 // number of historical blocks to index + Disabled bool // disables indexing completely + + // This option enables the checkpoint JSON file generator. + // If set, the given file will be updated with checkpoint information. + ExportFileName string +} + +// NewFilterMaps creates a new FilterMaps and starts the indexer. +func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, config Config) *FilterMaps { + rs, initialized, err := rawdb.ReadFilterMapsRange(db) + if err != nil { + log.Error("Error reading log index range", "error", err) + } + params.deriveFields() + f := &FilterMaps{ + db: db, + closeCh: make(chan struct{}), + waitIdleCh: make(chan chan bool), + targetViewCh: make(chan *ChainView, 1), + finalBlockCh: make(chan uint64, 1), + blockProcessingCh: make(chan bool, 1), + history: config.History, + disabled: config.Disabled, + exportFileName: config.ExportFileName, + Params: params, + indexedRange: filterMapsRange{ + initialized: initialized, + headBlockIndexed: rs.HeadBlockIndexed, + headBlockDelimiter: rs.HeadBlockDelimiter, + firstIndexedBlock: rs.FirstIndexedBlock, + afterLastIndexedBlock: rs.AfterLastIndexedBlock, + firstRenderedMap: rs.FirstRenderedMap, + afterLastRenderedMap: rs.AfterLastRenderedMap, + tailPartialEpoch: rs.TailPartialEpoch, + }, + matcherSyncCh: make(chan *FilterMapsMatcherBackend), + matchers: make(map[*FilterMapsMatcherBackend]struct{}), + filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), + lastBlockCache: lru.NewCache[uint32, lastBlockOfMap](cachedLastBlocks), + lvPointerCache: lru.NewCache[uint64, uint64](cachedLvPointers), + baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), + renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), + } + + // Set initial indexer target. + f.targetView = initView + if f.indexedRange.initialized { + f.indexedView = f.initChainView(f.targetView) + f.indexedRange.headBlockIndexed = f.indexedRange.afterLastIndexedBlock == f.indexedView.headNumber+1 + if !f.indexedRange.headBlockIndexed { + f.indexedRange.headBlockDelimiter = 0 + } + } + if f.indexedRange.hasIndexedBlocks() { + log.Info("Initialized log indexer", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "first map", f.indexedRange.firstRenderedMap, "last map", f.indexedRange.afterLastRenderedMap-1, + "head indexed", f.indexedRange.headBlockIndexed) + } + return f +} + +// Start starts the indexer. +func (f *FilterMaps) Start() { + if !f.testDisableSnapshots && f.indexedRange.initialized && f.indexedRange.headBlockIndexed && + f.indexedRange.firstRenderedMap < f.indexedRange.afterLastRenderedMap { + // previous target head rendered; load last map as snapshot + if err := f.loadHeadSnapshot(); err != nil { + log.Error("Could not load head filter map snapshot", "error", err) + } + } + f.closeWg.Add(1) + go f.indexerLoop() +} + +// Stop ensures that the indexer is fully stopped before returning. +func (f *FilterMaps) Stop() { + close(f.closeCh) + f.closeWg.Wait() +} + +// initChainView returns a chain view consistent with both the current target +// view and the current state of the log index as found in the database, based +// on the last block of stored maps. +// Note that the returned view might be shorter than the existing index if +// the latest maps are not consistent with targetView. +func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView { + mapIndex := f.indexedRange.afterLastRenderedMap + for { + var ok bool + mapIndex, ok = f.lastMapBoundaryBefore(mapIndex) + if !ok { + break + } + lastBlockNumber, lastBlockId, err := f.getLastBlockOfMap(mapIndex) + if err != nil { + log.Error("Could not initialize indexed chain view", "error", err) + break + } + if lastBlockNumber <= chainView.headNumber && chainView.getBlockId(lastBlockNumber) == lastBlockId { + return chainView.limitedView(lastBlockNumber) + } + } + return chainView.limitedView(0) +} + +// reset un-initializes the FilterMaps structure and removes all related data from +// the database. The function returns true if everything was successfully removed. +func (f *FilterMaps) reset() bool { + f.indexLock.Lock() + f.indexedRange = filterMapsRange{} + f.indexedView = nil + f.filterMapCache.Purge() + f.renderSnapshots.Purge() + f.lastBlockCache.Purge() + f.lvPointerCache.Purge() + f.baseRowsCache.Purge() + f.indexLock.Unlock() + // deleting the range first ensures that resetDb will be called again at next + // startup and any leftover data will be removed even if it cannot finish now. + rawdb.DeleteFilterMapsRange(f.db) + return f.removeDbWithPrefix([]byte(rawdb.FilterMapsPrefix), "Resetting log index database") +} + +// init initializes an empty log index according to the current targetView. +func (f *FilterMaps) init() error { + f.indexLock.Lock() + defer f.indexLock.Unlock() + + var bestIdx, bestLen int + for idx, checkpointList := range checkpoints { + // binary search for the last matching epoch head + min, max := 0, len(checkpointList) + for min < max { + mid := (min + max + 1) / 2 + cp := checkpointList[mid-1] + if cp.BlockNumber <= f.targetView.headNumber && f.targetView.getBlockId(cp.BlockNumber) == cp.BlockId { + min = mid + } else { + max = mid - 1 + } + } + if max > bestLen { + bestIdx, bestLen = idx, max + } + } + batch := f.db.NewBatch() + for epoch := range bestLen { + cp := checkpoints[bestIdx][epoch] + f.storeLastBlockOfMap(batch, (uint32(epoch+1)< 0 { + cp := checkpoints[bestIdx][bestLen-1] + fmr.firstIndexedBlock = cp.BlockNumber + 1 + fmr.afterLastIndexedBlock = cp.BlockNumber + 1 + fmr.firstRenderedMap = uint32(bestLen) << f.logMapsPerEpoch + fmr.afterLastRenderedMap = uint32(bestLen) << f.logMapsPerEpoch + } + f.setRange(batch, f.targetView, fmr) + return batch.Write() +} + +// removeDbWithPrefix removes data with the given prefix from the database and +// returns true if everything was successfully removed. +func (f *FilterMaps) removeDbWithPrefix(prefix []byte, action string) bool { + it := f.db.NewIterator(prefix, nil) + hasData := it.Next() + it.Release() + if !hasData { + return true + } + + end := bytes.Clone(prefix) + end[len(end)-1]++ + start := time.Now() + var retry bool + for { + err := f.db.DeleteRange(prefix, end) + if err == nil { + log.Info(action+" finished", "elapsed", time.Since(start)) + return true + } + if err != leveldb.ErrTooManyKeys { + log.Error(action+" failed", "error", err) + return false + } + select { + case <-f.closeCh: + return false + default: + } + if !retry { + log.Info(action + " in progress...") + retry = true + } + } +} + +// setRange updates the indexed chain view and covered range and also adds the +// changes to the given batch. +// Note that this function assumes that the index write lock is being held. +func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, newRange filterMapsRange) { + f.indexedView = newView + f.indexedRange = newRange + f.updateMatchersValidRange() + if newRange.initialized { + rs := rawdb.FilterMapsRange{ + HeadBlockIndexed: newRange.headBlockIndexed, + HeadBlockDelimiter: newRange.headBlockDelimiter, + FirstIndexedBlock: newRange.firstIndexedBlock, + AfterLastIndexedBlock: newRange.afterLastIndexedBlock, + FirstRenderedMap: newRange.firstRenderedMap, + AfterLastRenderedMap: newRange.afterLastRenderedMap, + TailPartialEpoch: newRange.tailPartialEpoch, + } + rawdb.WriteFilterMapsRange(batch, rs) + } else { + rawdb.DeleteFilterMapsRange(batch) + } +} + +// getLogByLvIndex returns the log at the given log value index. If the index does +// not point to the first log value entry of a log then no log and no error are +// returned as this can happen when the log value index was a false positive. +// Note that this function assumes that the log index structure is consistent +// with the canonical chain at the point where the given log value index points. +// If this is not the case then an invalid result or an error may be returned. +// Note that this function assumes that the indexer read lock is being held when +// called from outside the indexerLoop goroutine. +func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { + mapIndex := uint32(lvIndex >> f.logValuesPerMap) + if mapIndex < f.indexedRange.firstRenderedMap || mapIndex >= f.indexedRange.afterLastRenderedMap { + return nil, nil + } + // find possible block range based on map to block pointers + lastBlockNumber, _, err := f.getLastBlockOfMap(mapIndex) + if err != nil { + return nil, fmt.Errorf("failed to retrieve last block of map %d containing searched log value index %d: %v", mapIndex, lvIndex, err) + } + var firstBlockNumber uint64 + if mapIndex > 0 { + firstBlockNumber, _, err = f.getLastBlockOfMap(mapIndex - 1) + if err != nil { + return nil, fmt.Errorf("failed to retrieve last block of map %d before searched log value index %d: %v", mapIndex, lvIndex, err) + } + } + if firstBlockNumber < f.indexedRange.firstIndexedBlock { + firstBlockNumber = f.indexedRange.firstIndexedBlock + } + // find block with binary search based on block to log value index pointers + for firstBlockNumber < lastBlockNumber { + midBlockNumber := (firstBlockNumber + lastBlockNumber + 1) / 2 + midLvPointer, err := f.getBlockLvPointer(midBlockNumber) + if err != nil { + return nil, fmt.Errorf("failed to retrieve log value pointer of block %d while binary searching log value index %d: %v", midBlockNumber, lvIndex, err) + } + if lvIndex < midLvPointer { + lastBlockNumber = midBlockNumber - 1 + } else { + firstBlockNumber = midBlockNumber + } + } + // get block receipts + receipts := f.indexedView.getReceipts(firstBlockNumber) + if receipts == nil { + return nil, fmt.Errorf("failed to retrieve receipts for block %d containing searched log value index %d: %v", firstBlockNumber, lvIndex, err) + } + lvPointer, err := f.getBlockLvPointer(firstBlockNumber) + if err != nil { + return nil, fmt.Errorf("failed to retrieve log value pointer of block %d containing searched log value index %d: %v", firstBlockNumber, lvIndex, err) + } + // iterate through receipts to find the exact log starting at lvIndex + for _, receipt := range receipts { + for _, log := range receipt.Logs { + if lvPointer > lvIndex { + // lvIndex does not point to the first log value (address value) + // generated by a log as true matches should always do, so it + // is considered a false positive (no log and no error returned). + return nil, nil + } + if lvPointer == lvIndex { + return log, nil // potential match + } + lvPointer += uint64(len(log.Topics) + 1) + } + } + return nil, nil +} + +// getFilterMap fetches an entire filter map from the database. +func (f *FilterMaps) getFilterMap(mapIndex uint32) (filterMap, error) { + if fm, ok := f.filterMapCache.Get(mapIndex); ok { + return fm, nil + } + fm := make(filterMap, f.mapHeight) + for rowIndex := range fm { + var err error + fm[rowIndex], err = f.getFilterMapRow(mapIndex, uint32(rowIndex), false) + if err != nil { + return nil, fmt.Errorf("failed to load filter map %d from database: %v", mapIndex, err) + } + } + f.filterMapCache.Add(mapIndex, fm) + return fm, nil +} + +// getFilterMapRow fetches the given filter map row. If baseLayerOnly is true +// then only the first baseRowLength entries are returned. +func (f *FilterMaps) getFilterMapRow(mapIndex, rowIndex uint32, baseLayerOnly bool) (FilterRow, error) { + baseMapRowIndex := f.mapRowIndex(mapIndex&-f.baseRowGroupLength, rowIndex) + baseRows, ok := f.baseRowsCache.Get(baseMapRowIndex) + if !ok { + var err error + baseRows, err = rawdb.ReadFilterMapBaseRows(f.db, baseMapRowIndex, f.baseRowGroupLength, f.logMapWidth) + if err != nil { + return nil, fmt.Errorf("failed to retrieve filter map %d base rows %d: %v", mapIndex, rowIndex, err) + } + f.baseRowsCache.Add(baseMapRowIndex, baseRows) + } + baseRow := baseRows[mapIndex&(f.baseRowGroupLength-1)] + if baseLayerOnly { + return baseRow, nil + } + extRow, err := rawdb.ReadFilterMapExtRow(f.db, f.mapRowIndex(mapIndex, rowIndex), f.logMapWidth) + if err != nil { + return nil, fmt.Errorf("failed to retrieve filter map %d extended row %d: %v", mapIndex, rowIndex, err) + } + return FilterRow(append(baseRow, extRow...)), nil +} + +// storeFilterMapRows stores a set of filter map rows at the corresponding map +// indices and a shared row index. +func (f *FilterMaps) storeFilterMapRows(batch ethdb.Batch, mapIndices []uint32, rowIndex uint32, rows []FilterRow) error { + for len(mapIndices) > 0 { + baseMapIndex := mapIndices[0] & -f.baseRowGroupLength + groupLength := 1 + for groupLength < len(mapIndices) && mapIndices[groupLength]&-f.baseRowGroupLength == baseMapIndex { + groupLength++ + } + if err := f.storeFilterMapRowsOfGroup(batch, mapIndices[:groupLength], rowIndex, rows[:groupLength]); err != nil { + return err + } + mapIndices, rows = mapIndices[groupLength:], rows[groupLength:] + } + return nil +} + +// storeFilterMapRowsOfGroup stores a set of filter map rows at map indices +// belonging to the same base row group. +func (f *FilterMaps) storeFilterMapRowsOfGroup(batch ethdb.Batch, mapIndices []uint32, rowIndex uint32, rows []FilterRow) error { + baseMapIndex := mapIndices[0] & -f.baseRowGroupLength + baseMapRowIndex := f.mapRowIndex(baseMapIndex, rowIndex) + var baseRows [][]uint32 + if uint32(len(mapIndices)) != f.baseRowGroupLength { // skip base rows read if all rows are replaced + var ok bool + baseRows, ok = f.baseRowsCache.Get(baseMapRowIndex) + if !ok { + var err error + baseRows, err = rawdb.ReadFilterMapBaseRows(f.db, baseMapRowIndex, f.baseRowGroupLength, f.logMapWidth) + if err != nil { + return fmt.Errorf("failed to retrieve filter map %d base rows %d for modification: %v", mapIndices[0]&-f.baseRowGroupLength, rowIndex, err) + } + } + } else { + baseRows = make([][]uint32, f.baseRowGroupLength) + } + for i, mapIndex := range mapIndices { + if mapIndex&-f.baseRowGroupLength != baseMapIndex { + panic("mapIndices are not in the same base row group") + } + baseRow := []uint32(rows[i]) + var extRow FilterRow + if uint32(len(rows[i])) > f.baseRowLength { + extRow = baseRow[f.baseRowLength:] + baseRow = baseRow[:f.baseRowLength] + } + baseRows[mapIndex&(f.baseRowGroupLength-1)] = baseRow + rawdb.WriteFilterMapExtRow(batch, f.mapRowIndex(mapIndex, rowIndex), extRow, f.logMapWidth) + } + f.baseRowsCache.Add(baseMapRowIndex, baseRows) + rawdb.WriteFilterMapBaseRows(batch, baseMapRowIndex, baseRows, f.logMapWidth) + return nil +} + +// mapRowIndex calculates the unified storage index where the given row of the +// given map is stored. Note that this indexing scheme is the same as the one +// proposed in EIP-7745 for tree-hashing the filter map structure and for the +// same data proximity reasons it is also suitable for database representation. +// See also: +// https://eips.ethereum.org/EIPS/eip-7745#hash-tree-structure +func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 { + epochIndex, mapSubIndex := mapIndex>>f.logMapsPerEpoch, mapIndex&(f.mapsPerEpoch-1) + return (uint64(epochIndex)<= f.indexedRange.afterLastIndexedBlock && f.indexedRange.headBlockIndexed { + return f.indexedRange.headBlockDelimiter, nil + } + if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok { + return lvPointer, nil + } + lvPointer, err := rawdb.ReadBlockLvPointer(f.db, blockNumber) + if err != nil { + return 0, fmt.Errorf("failed to retrieve log value pointer of block %d: %v", blockNumber, err) + } + f.lvPointerCache.Add(blockNumber, lvPointer) + return lvPointer, nil +} + +// storeBlockLvPointer stores the starting log value index where the log values +// generated by the given block are located. +func (f *FilterMaps) storeBlockLvPointer(batch ethdb.Batch, blockNumber, lvPointer uint64) { + f.lvPointerCache.Add(blockNumber, lvPointer) + rawdb.WriteBlockLvPointer(batch, blockNumber, lvPointer) +} + +// deleteBlockLvPointer deletes the starting log value index where the log values +// generated by the given block are located. +func (f *FilterMaps) deleteBlockLvPointer(batch ethdb.Batch, blockNumber uint64) { + f.lvPointerCache.Remove(blockNumber) + rawdb.DeleteBlockLvPointer(batch, blockNumber) +} + +// getLastBlockOfMap returns the number and id of the block that generated the +// last log value entry of the given map. +func (f *FilterMaps) getLastBlockOfMap(mapIndex uint32) (uint64, common.Hash, error) { + if lastBlock, ok := f.lastBlockCache.Get(mapIndex); ok { + return lastBlock.number, lastBlock.id, nil + } + number, id, err := rawdb.ReadFilterMapLastBlock(f.db, mapIndex) + if err != nil { + return 0, common.Hash{}, fmt.Errorf("failed to retrieve last block of map %d: %v", mapIndex, err) + } + f.lastBlockCache.Add(mapIndex, lastBlockOfMap{number: number, id: id}) + return number, id, nil +} + +// storeLastBlockOfMap stores the number of the block that generated the last +// log value entry of the given map. +func (f *FilterMaps) storeLastBlockOfMap(batch ethdb.Batch, mapIndex uint32, number uint64, id common.Hash) { + f.lastBlockCache.Add(mapIndex, lastBlockOfMap{number: number, id: id}) + rawdb.WriteFilterMapLastBlock(batch, mapIndex, number, id) +} + +// deleteLastBlockOfMap deletes the number of the block that generated the last +// log value entry of the given map. +func (f *FilterMaps) deleteLastBlockOfMap(batch ethdb.Batch, mapIndex uint32) { + f.lastBlockCache.Remove(mapIndex) + rawdb.DeleteFilterMapLastBlock(batch, mapIndex) +} + +// deleteTailEpoch deletes index data from the earliest, either fully or partially +// indexed epoch. The last block pointer for the last map of the epoch and the +// corresponding block log value pointer are retained as these are always assumed +// to be available for each epoch. +func (f *FilterMaps) deleteTailEpoch(epoch uint32) error { + f.indexLock.Lock() + defer f.indexLock.Unlock() + + firstMap := epoch << f.logMapsPerEpoch + lastBlock, _, err := f.getLastBlockOfMap(firstMap + f.mapsPerEpoch - 1) + if err != nil { + return fmt.Errorf("failed to retrieve last block of deleted epoch %d: %v", epoch, err) + } + var firstBlock uint64 + if epoch > 0 { + firstBlock, _, err = f.getLastBlockOfMap(firstMap - 1) + if err != nil { + return fmt.Errorf("failed to retrieve last block before deleted epoch %d: %v", epoch, err) + } + firstBlock++ + } + fmr := f.indexedRange + if f.indexedRange.firstRenderedMap == firstMap && + f.indexedRange.afterLastRenderedMap > firstMap+f.mapsPerEpoch && + f.indexedRange.tailPartialEpoch == 0 { + fmr.firstRenderedMap = firstMap + f.mapsPerEpoch + fmr.firstIndexedBlock = lastBlock + 1 + } else if f.indexedRange.firstRenderedMap == firstMap+f.mapsPerEpoch { + fmr.tailPartialEpoch = 0 + } else { + return errors.New("invalid tail epoch number") + } + f.setRange(f.db, f.indexedView, fmr) + rawdb.DeleteFilterMapRows(f.db, f.mapRowIndex(firstMap, 0), f.mapRowIndex(firstMap+f.mapsPerEpoch, 0)) + for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch; mapIndex++ { + f.filterMapCache.Remove(mapIndex) + } + rawdb.DeleteFilterMapLastBlocks(f.db, firstMap, firstMap+f.mapsPerEpoch-1) // keep last enrty + for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch-1; mapIndex++ { + f.lastBlockCache.Remove(mapIndex) + } + rawdb.DeleteBlockLvPointers(f.db, firstBlock, lastBlock) // keep last enrty + for blockNumber := firstBlock; blockNumber < lastBlock; blockNumber++ { + f.lvPointerCache.Remove(blockNumber) + } + return nil +} + +// exportCheckpoints exports epoch checkpoints in the format used by checkpoints.go. +func (f *FilterMaps) exportCheckpoints() { + finalLvPtr, err := f.getBlockLvPointer(f.finalBlock + 1) + if err != nil { + log.Error("Error fetching log value pointer of finalized block", "block", f.finalBlock, "error", err) + return + } + epochCount := uint32(finalLvPtr >> (f.logValuesPerMap + f.logMapsPerEpoch)) + if epochCount == f.lastFinalEpoch { + return + } + w, err := os.Create(f.exportFileName) + if err != nil { + log.Error("Error creating checkpoint export file", "name", f.exportFileName, "error", err) + return + } + defer w.Close() + + log.Info("Exporting log index checkpoints", "epochs", epochCount, "file", f.exportFileName) + w.WriteString("[\n") + comma := "," + for epoch := uint32(0); epoch < epochCount; epoch++ { + lastBlock, lastBlockId, err := f.getLastBlockOfMap((epoch+1)<. + +package filtermaps + +import ( + "math" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" +) + +const ( + logFrequency = time.Second * 20 // log info frequency during long indexing/unindexing process + headLogDelay = time.Second // head indexing log info delay (do not log if finished faster) +) + +// updateLoop initializes and updates the log index structure according to the +// current targetView. +func (f *FilterMaps) indexerLoop() { + defer f.closeWg.Done() + + if f.disabled { + f.reset() + return + } + log.Info("Started log indexer") + + for !f.stop { + if !f.indexedRange.initialized { + if err := f.init(); err != nil { + log.Error("Error initializing log index", "error", err) + f.waitForEvent() + continue + } + } + if !f.targetHeadIndexed() { + if !f.tryIndexHead() { + f.waitForEvent() + } + } else { + if f.finalBlock != f.lastFinal { + if f.exportFileName != "" { + f.exportCheckpoints() + } + f.lastFinal = f.finalBlock + } + if f.tryIndexTail() && f.tryUnindexTail() { + f.waitForEvent() + } + } + } +} + +// SetTargetView sets a new target chain view for the indexer to render. +// Note that SetTargetView never blocks. +func (f *FilterMaps) SetTargetView(targetView *ChainView) { + if targetView == nil { + panic("nil targetView") + } + for { + select { + case <-f.targetViewCh: + case f.targetViewCh <- targetView: + return + } + } +} + +// SetFinalBlock sets the finalized block number used for exporting checkpoints. +// Note that SetFinalBlock never blocks. +func (f *FilterMaps) SetFinalBlock(finalBlock uint64) { + for { + select { + case <-f.finalBlockCh: + case f.finalBlockCh <- finalBlock: + return + } + } +} + +// SetBlockProcessing sets the block processing flag that temporarily suspends +// log index rendering. +// Note that SetBlockProcessing never blocks. +func (f *FilterMaps) SetBlockProcessing(blockProcessing bool) { + for { + select { + case <-f.blockProcessingCh: + case f.blockProcessingCh <- blockProcessing: + return + } + } +} + +// WaitIdle blocks until the indexer is in an idle state while synced up to the +// latest targetView. +func (f *FilterMaps) WaitIdle() { + if f.disabled { + f.closeWg.Wait() + return + } + for { + ch := make(chan bool) + f.waitIdleCh <- ch + if <-ch { + return + } + } +} + +// waitForEvent blocks until an event happens that the indexer might react to. +func (f *FilterMaps) waitForEvent() { + for !f.stop && (f.blockProcessing || f.targetHeadIndexed()) { + f.processSingleEvent(true) + } +} + +// processEvents processes all events, blocking only if a block processing is +// happening and indexing should be suspended. +func (f *FilterMaps) processEvents() { + for !f.stop && f.processSingleEvent(f.blockProcessing) { + } +} + +// processSingleEvent processes a single event either in a blocking or +// non-blocking manner. +func (f *FilterMaps) processSingleEvent(blocking bool) bool { + if f.matcherSyncRequest != nil && f.targetHeadIndexed() { + f.matcherSyncRequest.synced() + f.matcherSyncRequest = nil + } + if blocking { + select { + case targetView := <-f.targetViewCh: + f.setTargetView(targetView) + case f.finalBlock = <-f.finalBlockCh: + case f.matcherSyncRequest = <-f.matcherSyncCh: + case f.blockProcessing = <-f.blockProcessingCh: + case <-f.closeCh: + f.stop = true + case ch := <-f.waitIdleCh: + select { + case targetView := <-f.targetViewCh: + f.setTargetView(targetView) + default: + } + ch <- !f.blockProcessing && f.targetHeadIndexed() + } + } else { + select { + case targetView := <-f.targetViewCh: + f.setTargetView(targetView) + case f.finalBlock = <-f.finalBlockCh: + case f.matcherSyncRequest = <-f.matcherSyncCh: + case f.blockProcessing = <-f.blockProcessingCh: + case <-f.closeCh: + f.stop = true + default: + return false + } + } + return true +} + +// setTargetView updates the target chain view of the iterator. +func (f *FilterMaps) setTargetView(targetView *ChainView) { + f.targetView = targetView +} + +// tryIndexHead tries to render head maps according to the current targetView +// and returns true if successful. +func (f *FilterMaps) tryIndexHead() bool { + headRenderer, err := f.renderMapsBefore(math.MaxUint32) + if err != nil { + log.Error("Error creating log index head renderer", "error", err) + return false + } + if headRenderer == nil { + return true + } + if !f.startedHeadIndex { + f.lastLogHeadIndex = time.Now() + f.startedHeadIndexAt = f.lastLogHeadIndex + f.startedHeadIndex = true + f.ptrHeadIndex = f.indexedRange.afterLastIndexedBlock + } + if _, err := headRenderer.run(func() bool { + f.processEvents() + return f.stop + }, func() { + f.tryUnindexTail() + if f.indexedRange.hasIndexedBlocks() && f.indexedRange.afterLastIndexedBlock >= f.ptrHeadIndex && + ((!f.loggedHeadIndex && time.Since(f.startedHeadIndexAt) > headLogDelay) || + time.Since(f.lastLogHeadIndex) > logFrequency) { + log.Info("Log index head rendering in progress", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex, + "remaining", f.indexedView.headNumber+1-f.indexedRange.afterLastIndexedBlock, + "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) + f.loggedHeadIndex = true + f.lastLogHeadIndex = time.Now() + } + }); err != nil { + log.Error("Log index head rendering failed", "error", err) + return false + } + if f.loggedHeadIndex { + log.Info("Log index head rendering finished", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex, + "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) + } + f.loggedHeadIndex, f.startedHeadIndex = false, false + return true +} + +// tryIndexTail tries to render tail epochs until the tail target block is +// indexed and returns true if successful. +// Note that tail indexing is only started if the log index head is fully +// rendered according to targetView and is suspended as soon as the targetView +// is changed. +func (f *FilterMaps) tryIndexTail() bool { + for firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch; firstEpoch > 0 && f.needTailEpoch(firstEpoch-1); { + f.processEvents() + if f.stop || !f.targetHeadIndexed() { + return false + } + // resume process if tail rendering was interrupted because of head rendering + tailRenderer := f.tailRenderer + f.tailRenderer = nil + if tailRenderer != nil && tailRenderer.afterLastMap != f.indexedRange.firstRenderedMap { + tailRenderer = nil + } + if tailRenderer == nil { + var err error + tailRenderer, err = f.renderMapsBefore(f.indexedRange.firstRenderedMap) + if err != nil { + log.Error("Error creating log index tail renderer", "error", err) + return false + } + } + if tailRenderer == nil { + return true + } + if !f.startedTailIndex { + f.lastLogTailIndex = time.Now() + f.startedTailIndexAt = f.lastLogTailIndex + f.startedTailIndex = true + f.ptrTailIndex = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks() + } + done, err := tailRenderer.run(func() bool { + f.processEvents() + return f.stop || !f.targetHeadIndexed() + }, func() { + tpb, ttb := f.tailPartialBlocks(), f.tailTargetBlock() + remaining := uint64(1) + if f.indexedRange.firstIndexedBlock > ttb+tpb { + remaining = f.indexedRange.firstIndexedBlock - ttb - tpb + } + if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.firstIndexedBlock && + (!f.loggedTailIndex || time.Since(f.lastLogTailIndex) > logFrequency) { + log.Info("Log index tail rendering in progress", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock+tpb, + "remaining", remaining, + "next tail epoch percentage", f.indexedRange.tailPartialEpoch*100/f.mapsPerEpoch, + "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) + f.loggedTailIndex = true + f.lastLogTailIndex = time.Now() + } + }) + if err != nil { + log.Error("Log index tail rendering failed", "error", err) + } + if !done { + f.tailRenderer = tailRenderer // only keep tail renderer if interrupted by stopCb + return false + } + } + if f.loggedTailIndex { + log.Info("Log index tail rendering finished", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock, + "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) + f.loggedTailIndex = false + } + return true +} + +// tryUnindexTail removes entire epochs of log index data as long as the first +// fully indexed block is at least as old as the tail target. +// Note that unindexing is very quick as it only removes continuous ranges of +// data from the database and is also called while running head indexing. +func (f *FilterMaps) tryUnindexTail() bool { + for { + firstEpoch := (f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch + if f.needTailEpoch(firstEpoch) { + break + } + f.processEvents() + if f.stop { + return false + } + if !f.startedTailUnindex { + f.startedTailUnindexAt = time.Now() + f.startedTailUnindex = true + f.ptrTailUnindexMap = f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch + f.ptrTailUnindexBlock = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks() + } + if err := f.deleteTailEpoch(firstEpoch); err != nil { + log.Error("Log index tail epoch unindexing failed", "error", err) + return false + } + } + if f.startedTailUnindex { + log.Info("Log index tail unindexing finished", + "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, + "removed maps", f.indexedRange.firstRenderedMap-f.ptrTailUnindexMap, + "removed blocks", f.indexedRange.firstIndexedBlock-f.tailPartialBlocks()-f.ptrTailUnindexBlock, + "elapsed", common.PrettyDuration(time.Since(f.startedTailUnindexAt))) + f.startedTailUnindex = false + } + return true +} + +// needTailEpoch returns true if the given tail epoch needs to be kept +// according to the current tail target, false if it can be removed. +func (f *FilterMaps) needTailEpoch(epoch uint32) bool { + firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch + if epoch > firstEpoch { + return true + } + if epoch+1 < firstEpoch { + return false + } + tailTarget := f.tailTargetBlock() + if tailTarget < f.indexedRange.firstIndexedBlock { + return true + } + tailLvIndex, err := f.getBlockLvPointer(tailTarget) + if err != nil { + log.Error("Could not get log value index of tail block", "error", err) + return true + } + return uint64(epoch+1)<<(f.logValuesPerMap+f.logMapsPerEpoch) >= tailLvIndex +} + +// tailTargetBlock returns the target value for the tail block number according +// to the log history parameter and the current index head. +func (f *FilterMaps) tailTargetBlock() uint64 { + if f.history == 0 || f.indexedView.headNumber < f.history { + return 0 + } + return f.indexedView.headNumber + 1 - f.history +} + +// tailPartialBlocks returns the number of rendered blocks in the partially +// rendered next tail epoch. +func (f *FilterMaps) tailPartialBlocks() uint64 { + if f.indexedRange.tailPartialEpoch == 0 { + return 0 + } + end, _, err := f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - 1) + if err != nil { + log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch-1, "error", err) + } + var start uint64 + if f.indexedRange.firstRenderedMap-f.mapsPerEpoch > 0 { + start, _, err = f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch - 1) + if err != nil { + log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch-1, "error", err) + } + } + return end - start +} + +// targetHeadIndexed returns true if the current log index is consistent with +// targetView with its head block fully rendered. +func (f *FilterMaps) targetHeadIndexed() bool { + return equalViews(f.targetView, f.indexedView) && f.indexedRange.headBlockIndexed +} diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go new file mode 100644 index 000000000..17ad765e0 --- /dev/null +++ b/core/filtermaps/indexer_test.go @@ -0,0 +1,444 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + crand "crypto/rand" + "crypto/sha256" + "math/big" + "math/rand" + "sync" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" +) + +var testParams = Params{ + logMapHeight: 2, + logMapWidth: 24, + logMapsPerEpoch: 4, + logValuesPerMap: 4, + baseRowGroupLength: 4, + baseRowLengthRatio: 2, + logLayerDiff: 2, +} + +func TestIndexerRandomRange(t *testing.T) { + ts := newTestSetup(t) + defer ts.close() + + forks := make([][]common.Hash, 10) + ts.chain.addBlocks(1000, 5, 2, 4, false) // 51 log values per block + for i := range forks { + if i != 0 { + forkBlock := rand.Intn(1000) + ts.chain.setHead(forkBlock) + ts.chain.addBlocks(1000-forkBlock, 5, 2, 4, false) // 51 log values per block + } + forks[i] = ts.chain.getCanonicalChain() + } + lvPerBlock := uint64(51) + ts.setHistory(0, false) + var ( + history int + noHistory bool + fork, head = len(forks) - 1, 1000 + checkSnapshot bool + ) + ts.fm.WaitIdle() + for i := 0; i < 200; i++ { + switch rand.Intn(3) { + case 0: + // change history settings + switch rand.Intn(10) { + case 0: + history, noHistory = 0, false + case 1: + history, noHistory = 0, true + default: + history, noHistory = rand.Intn(1000)+1, false + } + ts.testDisableSnapshots = rand.Intn(2) == 0 + ts.setHistory(uint64(history), noHistory) + case 1: + // change head to random position of random fork + fork, head = rand.Intn(len(forks)), rand.Intn(1001) + ts.chain.setCanonicalChain(forks[fork][:head+1]) + case 2: + if head < 1000 { + checkSnapshot = !noHistory && head != 0 // no snapshot generated for block 0 + // add blocks after the current head + head += rand.Intn(1000-head) + 1 + ts.fm.testSnapshotUsed = false + ts.chain.setCanonicalChain(forks[fork][:head+1]) + } + } + ts.fm.WaitIdle() + if checkSnapshot { + if ts.fm.testSnapshotUsed == ts.fm.testDisableSnapshots { + ts.t.Fatalf("Invalid snapshot used state after head extension (used: %v, disabled: %v)", ts.fm.testSnapshotUsed, ts.fm.testDisableSnapshots) + } + checkSnapshot = false + } + if noHistory { + if ts.fm.indexedRange.initialized { + t.Fatalf("filterMapsRange initialized while indexing is disabled") + } + continue + } + if !ts.fm.indexedRange.initialized { + t.Fatalf("filterMapsRange not initialized while indexing is enabled") + } + var tailBlock uint64 + if history > 0 && history <= head { + tailBlock = uint64(head + 1 - history) + } + var tailEpoch uint32 + if tailBlock > 0 { + tailLvPtr := (tailBlock - 1) * lvPerBlock // no logs in genesis block, only delimiter + tailEpoch = uint32(tailLvPtr >> (testParams.logValuesPerMap + testParams.logMapsPerEpoch)) + } + var expTailBlock uint64 + if tailEpoch > 0 { + tailLvPtr := uint64(tailEpoch) << (testParams.logValuesPerMap + testParams.logMapsPerEpoch) // first available lv ptr + // (expTailBlock-1)*lvPerBlock >= tailLvPtr + expTailBlock = (tailLvPtr + lvPerBlock*2 - 1) / lvPerBlock + } + if ts.fm.indexedRange.afterLastIndexedBlock != uint64(head+1) { + ts.t.Fatalf("Invalid index head (expected #%d, got #%d)", head, ts.fm.indexedRange.afterLastIndexedBlock-1) + } + if ts.fm.indexedRange.headBlockDelimiter != uint64(head)*lvPerBlock { + ts.t.Fatalf("Invalid index head delimiter pointer (expected %d, got %d)", uint64(head)*lvPerBlock, ts.fm.indexedRange.headBlockDelimiter) + } + if ts.fm.indexedRange.firstIndexedBlock != expTailBlock { + ts.t.Fatalf("Invalid index tail block (expected #%d, got #%d)", expTailBlock, ts.fm.indexedRange.firstIndexedBlock) + } + } +} + +func TestIndexerCompareDb(t *testing.T) { + ts := newTestSetup(t) + defer ts.close() + + ts.chain.addBlocks(500, 10, 3, 4, true) + ts.setHistory(0, false) + ts.fm.WaitIdle() + // revert points are stored after block 500 + ts.chain.addBlocks(500, 10, 3, 4, true) + ts.fm.WaitIdle() + chain1 := ts.chain.getCanonicalChain() + ts.storeDbHash("chain 1 [0, 1000]") + + ts.chain.setHead(600) + ts.fm.WaitIdle() + ts.storeDbHash("chain 1/2 [0, 600]") + + ts.chain.addBlocks(600, 10, 3, 4, true) + ts.fm.WaitIdle() + chain2 := ts.chain.getCanonicalChain() + ts.storeDbHash("chain 2 [0, 1200]") + + ts.chain.setHead(600) + ts.fm.WaitIdle() + ts.checkDbHash("chain 1/2 [0, 600]") + + ts.setHistory(800, false) + ts.chain.setCanonicalChain(chain1) + ts.fm.WaitIdle() + ts.storeDbHash("chain 1 [201, 1000]") + + ts.setHistory(0, false) + ts.fm.WaitIdle() + ts.checkDbHash("chain 1 [0, 1000]") + + ts.setHistory(800, false) + ts.chain.setCanonicalChain(chain2) + ts.fm.WaitIdle() + ts.storeDbHash("chain 2 [401, 1200]") + + ts.setHistory(0, true) + ts.fm.WaitIdle() + ts.storeDbHash("no index") + + ts.chain.setCanonicalChain(chain2[:501]) + ts.setHistory(0, false) + ts.fm.WaitIdle() + ts.chain.setCanonicalChain(chain2) + ts.fm.WaitIdle() + ts.checkDbHash("chain 2 [0, 1200]") + + ts.chain.setCanonicalChain(chain1) + ts.fm.WaitIdle() + ts.setHistory(800, false) + ts.fm.WaitIdle() + ts.checkDbHash("chain 1 [201, 1000]") + + ts.chain.setCanonicalChain(chain2) + ts.fm.WaitIdle() + ts.checkDbHash("chain 2 [401, 1200]") + + ts.setHistory(0, true) + ts.fm.WaitIdle() + ts.checkDbHash("no index") +} + +type testSetup struct { + t *testing.T + fm *FilterMaps + db ethdb.Database + chain *testChain + params Params + dbHashes map[string]common.Hash + testDisableSnapshots bool +} + +func newTestSetup(t *testing.T) *testSetup { + params := testParams + params.deriveFields() + ts := &testSetup{ + t: t, + db: rawdb.NewMemoryDatabase(), + params: params, + dbHashes: make(map[string]common.Hash), + } + ts.chain = ts.newTestChain() + return ts +} + +func (ts *testSetup) setHistory(history uint64, noHistory bool) { + if ts.fm != nil { + ts.fm.Stop() + } + head := ts.chain.CurrentBlock() + view := NewChainView(ts.chain, head.Number.Uint64(), head.Hash()) + config := Config{ + History: history, + Disabled: noHistory, + } + ts.fm = NewFilterMaps(ts.db, view, ts.params, config) + ts.fm.testDisableSnapshots = ts.testDisableSnapshots + ts.fm.Start() +} + +func (ts *testSetup) storeDbHash(id string) { + dbHash := ts.fmDbHash() + for otherId, otherHash := range ts.dbHashes { + if otherHash == dbHash { + ts.t.Fatalf("Unexpected equal database hashes `%s` and `%s`", id, otherId) + } + } + ts.dbHashes[id] = dbHash +} + +func (ts *testSetup) checkDbHash(id string) { + if ts.fmDbHash() != ts.dbHashes[id] { + ts.t.Fatalf("Database `%s` hash mismatch", id) + } +} + +func (ts *testSetup) fmDbHash() common.Hash { + hasher := sha256.New() + it := ts.db.NewIterator(nil, nil) + for it.Next() { + hasher.Write(it.Key()) + hasher.Write(it.Value()) + } + it.Release() + var result common.Hash + hasher.Sum(result[:0]) + return result +} + +func (ts *testSetup) close() { + if ts.fm != nil { + ts.fm.Stop() + } + ts.db.Close() + ts.chain.db.Close() +} + +type testChain struct { + ts *testSetup + db ethdb.Database + lock sync.RWMutex + canonical []common.Hash + blocks map[common.Hash]*types.Block + receipts map[common.Hash]types.Receipts +} + +func (ts *testSetup) newTestChain() *testChain { + return &testChain{ + ts: ts, + blocks: make(map[common.Hash]*types.Block), + receipts: make(map[common.Hash]types.Receipts), + } +} + +func (tc *testChain) CurrentBlock() *types.Header { + tc.lock.RLock() + defer tc.lock.RUnlock() + + if len(tc.canonical) == 0 { + return nil + } + return tc.blocks[tc.canonical[len(tc.canonical)-1]].Header() +} + +func (tc *testChain) GetHeader(hash common.Hash, number uint64) *types.Header { + tc.lock.RLock() + defer tc.lock.RUnlock() + + if block := tc.blocks[hash]; block != nil { + return block.Header() + } + return nil +} + +func (tc *testChain) GetCanonicalHash(number uint64) common.Hash { + tc.lock.RLock() + defer tc.lock.RUnlock() + + if uint64(len(tc.canonical)) <= number { + return common.Hash{} + } + return tc.canonical[number] +} + +func (tc *testChain) GetReceiptsByHash(hash common.Hash) types.Receipts { + tc.lock.RLock() + defer tc.lock.RUnlock() + + return tc.receipts[hash] +} + +func (tc *testChain) addBlocks(count, maxTxPerBlock, maxLogsPerReceipt, maxTopicsPerLog int, random bool) { + tc.lock.Lock() + blockGen := func(i int, gen *core.BlockGen) { + var txCount int + if random { + txCount = rand.Intn(maxTxPerBlock + 1) + } else { + txCount = maxTxPerBlock + } + for k := txCount; k > 0; k-- { + receipt := types.NewReceipt(nil, false, 0) + var logCount int + if random { + logCount = rand.Intn(maxLogsPerReceipt + 1) + } else { + logCount = maxLogsPerReceipt + } + receipt.Logs = make([]*types.Log, logCount) + for i := range receipt.Logs { + log := &types.Log{} + receipt.Logs[i] = log + crand.Read(log.Address[:]) + var topicCount int + if random { + topicCount = rand.Intn(maxTopicsPerLog + 1) + } else { + topicCount = maxTopicsPerLog + } + log.Topics = make([]common.Hash, topicCount) + for j := range log.Topics { + crand.Read(log.Topics[j][:]) + } + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, gen.BaseFee(), nil)) + } + } + + var ( + blocks []*types.Block + receipts []types.Receipts + engine = ethash.NewFaker() + ) + + if len(tc.canonical) == 0 { + gspec := &core.Genesis{ + Alloc: types.GenesisAlloc{}, + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + tc.db, blocks, receipts = core.GenerateChainWithGenesis(gspec, engine, count, blockGen) + gblock := gspec.ToBlock() + ghash := gblock.Hash() + tc.canonical = []common.Hash{ghash} + tc.blocks[ghash] = gblock + tc.receipts[ghash] = types.Receipts{} + } else { + blocks, receipts = core.GenerateChain(params.TestChainConfig, tc.blocks[tc.canonical[len(tc.canonical)-1]], engine, tc.db, count, blockGen) + } + + for i, block := range blocks { + num, hash := int(block.NumberU64()), block.Hash() + if len(tc.canonical) != num { + panic("canonical chain length mismatch") + } + tc.canonical = append(tc.canonical, hash) + tc.blocks[hash] = block + if receipts[i] != nil { + tc.receipts[hash] = receipts[i] + } else { + tc.receipts[hash] = types.Receipts{} + } + } + tc.lock.Unlock() + tc.setTargetHead() +} + +func (tc *testChain) setHead(headNum int) { + tc.lock.Lock() + tc.canonical = tc.canonical[:headNum+1] + tc.lock.Unlock() + tc.setTargetHead() +} + +func (tc *testChain) setTargetHead() { + head := tc.CurrentBlock() + if tc.ts.fm != nil { + if !tc.ts.fm.disabled { + //tc.ts.fm.targetViewCh <- NewChainView(tc, head.Number.Uint64(), head.Hash()) + tc.ts.fm.SetTargetView(NewChainView(tc, head.Number.Uint64(), head.Hash())) + } + } +} + +func (tc *testChain) getCanonicalChain() []common.Hash { + tc.lock.RLock() + defer tc.lock.RUnlock() + + cc := make([]common.Hash, len(tc.canonical)) + copy(cc, tc.canonical) + return cc +} + +// restore an earlier state of the chain +func (tc *testChain) setCanonicalChain(cc []common.Hash) { + tc.lock.Lock() + tc.canonical = make([]common.Hash, len(cc)) + copy(tc.canonical, cc) + tc.lock.Unlock() + tc.setTargetHead() +} diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go new file mode 100644 index 000000000..5bd48a4b2 --- /dev/null +++ b/core/filtermaps/map_renderer.go @@ -0,0 +1,768 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "errors" + "fmt" + "math" + "sort" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +const ( + maxMapsPerBatch = 32 // maximum number of maps rendered in memory + valuesPerCallback = 1024 // log values processed per event process callback + cachedRowMappings = 10000 // log value to row mappings cached during rendering + + // Number of rows written to db in a single batch. + // The map renderer splits up writes like this to ensure that regular + // block processing latency is not affected by large batch writes. + rowsPerBatch = 1024 +) + +var ( + errChainUpdate = errors.New("rendered section of chain updated") +) + +// mapRenderer represents a process that renders filter maps in a specified +// range according to the actual targetView. +type mapRenderer struct { + f *FilterMaps + afterLastMap uint32 + currentMap *renderedMap + finishedMaps map[uint32]*renderedMap + firstFinished, afterLastFinished uint32 + iterator *logIterator +} + +// renderedMap represents a single filter map that is being rendered in memory. +type renderedMap struct { + filterMap filterMap + mapIndex uint32 + lastBlock uint64 + lastBlockId common.Hash + blockLvPtrs []uint64 // start pointers of blocks starting in this map; last one is lastBlock + finished bool // iterator finished; all values rendered + headDelimiter uint64 // if finished then points to the future block delimiter of the head block +} + +// firstBlock returns the first block number that starts in the given map. +func (r *renderedMap) firstBlock() uint64 { + return r.lastBlock + 1 - uint64(len(r.blockLvPtrs)) +} + +// renderMapsBefore creates a mapRenderer that renders the log index until the +// specified map index boundary, starting from the latest available starting +// point that is consistent with the current targetView. +// The renderer ensures that filterMapsRange, indexedView and the actual map +// data are always consistent with each other. If afterLastMap is greater than +// the latest existing rendered map then indexedView is updated to targetView, +// otherwise it is checked that the rendered range is consistent with both +// views. +func (f *FilterMaps) renderMapsBefore(afterLastMap uint32) (*mapRenderer, error) { + nextMap, startBlock, startLvPtr, err := f.lastCanonicalMapBoundaryBefore(afterLastMap) + if err != nil { + return nil, err + } + if snapshot := f.lastCanonicalSnapshotBefore(afterLastMap); snapshot != nil && snapshot.mapIndex >= nextMap { + return f.renderMapsFromSnapshot(snapshot) + } + if nextMap >= afterLastMap { + return nil, nil + } + return f.renderMapsFromMapBoundary(nextMap, afterLastMap, startBlock, startLvPtr) +} + +// renderMapsFromSnapshot creates a mapRenderer that starts rendering from a +// snapshot made at a block boundary. +func (f *FilterMaps) renderMapsFromSnapshot(cp *renderedMap) (*mapRenderer, error) { + f.testSnapshotUsed = true + iter, err := f.newLogIteratorFromBlockDelimiter(cp.lastBlock) + if err != nil { + return nil, fmt.Errorf("failed to create log iterator from block delimiter %d: %v", cp.lastBlock, err) + } + return &mapRenderer{ + f: f, + currentMap: &renderedMap{ + filterMap: cp.filterMap.copy(), + mapIndex: cp.mapIndex, + lastBlock: cp.lastBlock, + blockLvPtrs: cp.blockLvPtrs, + }, + finishedMaps: make(map[uint32]*renderedMap), + firstFinished: cp.mapIndex, + afterLastFinished: cp.mapIndex, + afterLastMap: math.MaxUint32, + iterator: iter, + }, nil +} + +// renderMapsFromMapBoundary creates a mapRenderer that starts rendering at a +// map boundary. +func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, afterLastMap uint32, startBlock, startLvPtr uint64) (*mapRenderer, error) { + iter, err := f.newLogIteratorFromMapBoundary(firstMap, startBlock, startLvPtr) + if err != nil { + return nil, fmt.Errorf("failed to create log iterator from map boundary %d: %v", firstMap, err) + } + return &mapRenderer{ + f: f, + currentMap: &renderedMap{ + filterMap: f.emptyFilterMap(), + mapIndex: firstMap, + lastBlock: iter.blockNumber, + }, + finishedMaps: make(map[uint32]*renderedMap), + firstFinished: firstMap, + afterLastFinished: firstMap, + afterLastMap: afterLastMap, + iterator: iter, + }, nil +} + +// lastCanonicalSnapshotBefore returns the latest cached snapshot that matches +// the current targetView. +func (f *FilterMaps) lastCanonicalSnapshotBefore(afterLastMap uint32) *renderedMap { + var best *renderedMap + for _, blockNumber := range f.renderSnapshots.Keys() { + if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.afterLastIndexedBlock && + blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId && + cp.mapIndex < afterLastMap && (best == nil || blockNumber > best.lastBlock) { + best = cp + } + } + return best +} + +// lastCanonicalMapBoundaryBefore returns the latest map boundary before the +// specified map index that matches the current targetView. This can either +// be a checkpoint (hardcoded or left from a previously unindexed tail epoch) +// or the boundary of a currently rendered map. +// Along with the next map index where the rendering can be started, the number +// and starting log value pointer of the last block is also returned. +func (f *FilterMaps) lastCanonicalMapBoundaryBefore(afterLastMap uint32) (nextMap uint32, startBlock, startLvPtr uint64, err error) { + if !f.indexedRange.initialized { + return 0, 0, 0, nil + } + mapIndex := afterLastMap + for { + var ok bool + if mapIndex, ok = f.lastMapBoundaryBefore(mapIndex); !ok { + return 0, 0, 0, nil + } + lastBlock, lastBlockId, err := f.getLastBlockOfMap(mapIndex) + if err != nil { + return 0, 0, 0, fmt.Errorf("failed to retrieve last block of reverse iterated map %d: %v", mapIndex, err) + } + if lastBlock >= f.indexedView.headNumber || lastBlock >= f.targetView.headNumber || + lastBlockId != f.targetView.getBlockId(lastBlock) { + // map is not full or inconsistent with targetView; roll back + continue + } + lvPtr, err := f.getBlockLvPointer(lastBlock) + if err != nil { + return 0, 0, 0, fmt.Errorf("failed to retrieve log value pointer of last canonical boundary block %d: %v", lastBlock, err) + } + return mapIndex + 1, lastBlock, lvPtr, nil + } +} + +// lastMapBoundaryBefore returns the latest map boundary before the specified +// map index. +func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) { + if !f.indexedRange.initialized || f.indexedRange.afterLastRenderedMap == 0 { + return 0, false + } + if mapIndex > f.indexedRange.afterLastRenderedMap { + mapIndex = f.indexedRange.afterLastRenderedMap + } + if mapIndex > f.indexedRange.firstRenderedMap { + return mapIndex - 1, true + } + if mapIndex+f.mapsPerEpoch > f.indexedRange.firstRenderedMap { + if mapIndex > f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch { + mapIndex = f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch + } + } else { + mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch + } + if mapIndex == 0 { + return 0, false + } + return mapIndex - 1, true +} + +// emptyFilterMap returns an empty filter map. +func (f *FilterMaps) emptyFilterMap() filterMap { + return make(filterMap, f.mapHeight) +} + +// loadHeadSnapshot loads the last rendered map from the database and creates +// a snapshot. +func (f *FilterMaps) loadHeadSnapshot() error { + fm, err := f.getFilterMap(f.indexedRange.afterLastRenderedMap - 1) + if err != nil { + return fmt.Errorf("failed to load head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err) + } + lastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 1) + if err != nil { + return fmt.Errorf("failed to retrieve last block of head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err) + } + var firstBlock uint64 + if f.indexedRange.afterLastRenderedMap > 1 { + prevLastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 2) + if err != nil { + return fmt.Errorf("failed to retrieve last block of map %d before head snapshot: %v", f.indexedRange.afterLastRenderedMap-2, err) + } + firstBlock = prevLastBlock + 1 + } + lvPtrs := make([]uint64, lastBlock+1-firstBlock) + for i := range lvPtrs { + lvPtrs[i], err = f.getBlockLvPointer(firstBlock + uint64(i)) + if err != nil { + return fmt.Errorf("failed to retrieve log value pointer of head snapshot block %d: %v", firstBlock+uint64(i), err) + } + } + f.renderSnapshots.Add(f.indexedRange.afterLastIndexedBlock-1, &renderedMap{ + filterMap: fm, + mapIndex: f.indexedRange.afterLastRenderedMap - 1, + lastBlock: f.indexedRange.afterLastIndexedBlock - 1, + lastBlockId: f.indexedView.getBlockId(f.indexedRange.afterLastIndexedBlock - 1), + blockLvPtrs: lvPtrs, + finished: true, + headDelimiter: f.indexedRange.headBlockDelimiter, + }) + return nil +} + +// makeSnapshot creates a snapshot of the current state of the rendered map. +func (r *mapRenderer) makeSnapshot() { + r.f.renderSnapshots.Add(r.iterator.blockNumber, &renderedMap{ + filterMap: r.currentMap.filterMap.copy(), + mapIndex: r.currentMap.mapIndex, + lastBlock: r.iterator.blockNumber, + lastBlockId: r.f.targetView.getBlockId(r.currentMap.lastBlock), + blockLvPtrs: r.currentMap.blockLvPtrs, + finished: true, + headDelimiter: r.iterator.lvIndex, + }) +} + +// run does the actual map rendering. It periodically calls the stopCb callback +// and if it returns true the process is interrupted an can be resumed later +// by calling run again. The writeCb callback is called after new maps have +// been written to disk and the index range has been updated accordingly. +func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) { + for { + if done, err := r.renderCurrentMap(stopCb); !done { + return done, err // stopped or failed + } + // map finished + r.finishedMaps[r.currentMap.mapIndex] = r.currentMap + r.afterLastFinished++ + if len(r.finishedMaps) >= maxMapsPerBatch || r.afterLastFinished&(r.f.baseRowGroupLength-1) == 0 { + if err := r.writeFinishedMaps(stopCb); err != nil { + return false, err + } + writeCb() + } + if r.afterLastFinished == r.afterLastMap || r.iterator.finished { + if err := r.writeFinishedMaps(stopCb); err != nil { + return false, err + } + writeCb() + return true, nil + } + r.currentMap = &renderedMap{ + filterMap: r.f.emptyFilterMap(), + mapIndex: r.afterLastFinished, + } + } +} + +// renderCurrentMap renders a single map. +func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { + if !r.iterator.updateChainView(r.f.targetView) { + return false, errChainUpdate + } + var waitCnt int + + if r.iterator.lvIndex == 0 { + r.currentMap.blockLvPtrs = []uint64{0} + } + type lvPos struct{ rowIndex, layerIndex uint32 } + rowMappingCache := lru.NewCache[common.Hash, lvPos](cachedRowMappings) + defer rowMappingCache.Purge() + + for r.iterator.lvIndex < uint64(r.currentMap.mapIndex+1)<= valuesPerCallback { + if stopCb() { + return false, nil + } + if !r.iterator.updateChainView(r.f.targetView) { + return false, errChainUpdate + } + waitCnt = 0 + } + r.currentMap.lastBlock = r.iterator.blockNumber + if r.iterator.delimiter { + r.currentMap.lastBlock++ + r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex+1) + } + if logValue := r.iterator.getValueHash(); logValue != (common.Hash{}) { + lvp, cached := rowMappingCache.Get(logValue) + if !cached { + lvp = lvPos{rowIndex: r.f.rowIndex(r.currentMap.mapIndex, 0, logValue)} + } + for uint32(len(r.currentMap.filterMap[lvp.rowIndex])) >= r.f.maxRowLength(lvp.layerIndex) { + lvp.layerIndex++ + lvp.rowIndex = r.f.rowIndex(r.currentMap.mapIndex, lvp.layerIndex, logValue) + cached = false + } + r.currentMap.filterMap[lvp.rowIndex] = append(r.currentMap.filterMap[lvp.rowIndex], r.f.columnIndex(r.iterator.lvIndex, &logValue)) + if !cached { + rowMappingCache.Add(logValue, lvp) + } + } + if err := r.iterator.next(); err != nil { + return false, fmt.Errorf("failed to advance log iterator at %d while rendering map %d: %v", r.iterator.lvIndex, r.currentMap.mapIndex, err) + } + if !r.f.testDisableSnapshots && r.afterLastMap >= r.f.indexedRange.afterLastRenderedMap && + (r.iterator.delimiter || r.iterator.finished) { + r.makeSnapshot() + } + } + if r.iterator.finished { + r.currentMap.finished = true + r.currentMap.headDelimiter = r.iterator.lvIndex + } + r.currentMap.lastBlockId = r.f.targetView.getBlockId(r.currentMap.lastBlock) + return true, nil +} + +// writeFinishedMaps writes rendered maps to the database and updates +// filterMapsRange and indexedView accordingly. +func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { + if len(r.finishedMaps) == 0 { + return nil + } + r.f.indexLock.Lock() + defer r.f.indexLock.Unlock() + + oldRange := r.f.indexedRange + tempRange, err := r.getTempRange() + if err != nil { + return fmt.Errorf("failed to get temporary rendered range: %v", err) + } + newRange, err := r.getUpdatedRange() + if err != nil { + return fmt.Errorf("failed to get updated rendered range: %v", err) + } + renderedView := r.f.targetView // stopCb callback might still change targetView while writing finished maps + + batch := r.f.db.NewBatch() + var writeCnt int + checkWriteCnt := func() { + writeCnt++ + if writeCnt == rowsPerBatch { + writeCnt = 0 + if err := batch.Write(); err != nil { + log.Crit("Error writing log index update batch", "error", err) + } + // do not exit while in partially written state but do allow processing + // events and pausing while block processing is in progress + pauseCb() + batch = r.f.db.NewBatch() + } + } + + r.f.setRange(batch, r.f.indexedView, tempRange) + // add or update filter rows + for rowIndex := uint32(0); rowIndex < r.f.mapHeight; rowIndex++ { + var ( + mapIndices []uint32 + rows []FilterRow + ) + for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + row := r.finishedMaps[mapIndex].filterMap[rowIndex] + if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && row.Equal(fm[rowIndex]) { + continue + } + mapIndices = append(mapIndices, mapIndex) + rows = append(rows, row) + } + if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries + for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && len(fm[rowIndex]) == 0 { + continue + } + mapIndices = append(mapIndices, mapIndex) + rows = append(rows, nil) + } + } + if err := r.f.storeFilterMapRows(batch, mapIndices, rowIndex, rows); err != nil { + return fmt.Errorf("failed to store filter maps %v row %d: %v", mapIndices, rowIndex, err) + } + checkWriteCnt() + } + // update filter map cache + if newRange.afterLastRenderedMap == r.afterLastFinished { + // head updated; cache new head maps and remove future entries + for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + r.f.filterMapCache.Add(mapIndex, r.finishedMaps[mapIndex].filterMap) + } + for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + r.f.filterMapCache.Remove(mapIndex) + } + } else { + // head not updated; do not cache maps during tail rendering because we + // need head maps to be available in the cache + for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + r.f.filterMapCache.Remove(mapIndex) + } + } + // add or update block pointers + blockNumber := r.finishedMaps[r.firstFinished].firstBlock() + for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + renderedMap := r.finishedMaps[mapIndex] + r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId) + checkWriteCnt() + if blockNumber != renderedMap.firstBlock() { + panic("non-continuous block numbers") + } + for _, lvPtr := range renderedMap.blockLvPtrs { + r.f.storeBlockLvPointer(batch, blockNumber, lvPtr) + checkWriteCnt() + blockNumber++ + } + } + if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries + for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + r.f.deleteLastBlockOfMap(batch, mapIndex) + checkWriteCnt() + } + for ; blockNumber < oldRange.afterLastIndexedBlock; blockNumber++ { + r.f.deleteBlockLvPointer(batch, blockNumber) + checkWriteCnt() + } + } + r.finishedMaps = make(map[uint32]*renderedMap) + r.firstFinished = r.afterLastFinished + r.f.setRange(batch, renderedView, newRange) + if err := batch.Write(); err != nil { + log.Crit("Error writing log index update batch", "error", err) + } + return nil +} + +// getTempRange returns a temporary filterMapsRange that is committed to the +// database while the newly rendered maps are partially written. Writing all +// processed maps in a single database batch would be a serious hit on db +// performance so instead safety is ensured by first reverting the valid map +// range to the unchanged region until all new map data is committed. +func (r *mapRenderer) getTempRange() (filterMapsRange, error) { + tempRange := r.f.indexedRange + if err := tempRange.addRenderedRange(r.firstFinished, r.firstFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil { + return filterMapsRange{}, fmt.Errorf("failed to update temporary rendered range: %v", err) + } + if tempRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap { + // first rendered map changed; update first indexed block + if tempRange.firstRenderedMap > 0 { + lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.firstRenderedMap - 1) + if err != nil { + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before temporary range: %v", tempRange.firstRenderedMap-1, err) + } + tempRange.firstIndexedBlock = lastBlock + 1 + } else { + tempRange.firstIndexedBlock = 0 + } + } + if tempRange.afterLastRenderedMap != r.f.indexedRange.afterLastRenderedMap { + // first rendered map changed; update first indexed block + if tempRange.afterLastRenderedMap > 0 { + lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.afterLastRenderedMap - 1) + if err != nil { + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d at the end of temporary range: %v", tempRange.afterLastRenderedMap-1, err) + } + tempRange.afterLastIndexedBlock = lastBlock + } else { + tempRange.afterLastIndexedBlock = 0 + } + tempRange.headBlockDelimiter = 0 + } + return tempRange, nil +} + +// getUpdatedRange returns the updated filterMapsRange after writing the newly +// rendered maps. +func (r *mapRenderer) getUpdatedRange() (filterMapsRange, error) { + // update filterMapsRange + newRange := r.f.indexedRange + if err := newRange.addRenderedRange(r.firstFinished, r.afterLastFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil { + return filterMapsRange{}, fmt.Errorf("failed to update rendered range: %v", err) + } + if newRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap { + // first rendered map changed; update first indexed block + if newRange.firstRenderedMap > 0 { + lastBlock, _, err := r.f.getLastBlockOfMap(newRange.firstRenderedMap - 1) + if err != nil { + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before rendered range: %v", newRange.firstRenderedMap-1, err) + } + newRange.firstIndexedBlock = lastBlock + 1 + } else { + newRange.firstIndexedBlock = 0 + } + } + if newRange.afterLastRenderedMap == r.afterLastFinished { + // last rendered map changed; update last indexed block and head pointers + lm := r.finishedMaps[r.afterLastFinished-1] + newRange.headBlockIndexed = lm.finished + if lm.finished { + newRange.afterLastIndexedBlock = r.f.targetView.headNumber + 1 + if lm.lastBlock != r.f.targetView.headNumber { + panic("map rendering finished but last block != head block") + } + newRange.headBlockDelimiter = lm.headDelimiter + } else { + newRange.afterLastIndexedBlock = lm.lastBlock + newRange.headBlockDelimiter = 0 + } + } else { + // last rendered map not replaced; ensure that target chain view matches + // indexed chain view on the rendered section + if lastBlock := r.finishedMaps[r.afterLastFinished-1].lastBlock; !matchViews(r.f.indexedView, r.f.targetView, lastBlock) { + return filterMapsRange{}, errChainUpdate + } + } + return newRange, nil +} + +// addRenderedRange adds the range [firstRendered, afterLastRendered) and +// removes [afterLastRendered, afterLastRemoved) from the set of rendered maps. +func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, afterLastRemoved, mapsPerEpoch uint32) error { + if !fmr.initialized { + return errors.New("log index not initialized") + } + + // Here we create a slice of endpoints for the rendered sections. There are two endpoints + // for each section: the index of the first map, and the index after the last map in the + // section. We then iterate the endpoints -- adding d values -- to determine whether the + // sections are contiguous or whether they have a gap. + type endpoint struct { + m uint32 + d int + } + endpoints := []endpoint{{fmr.firstRenderedMap, 1}, {fmr.afterLastRenderedMap, -1}, {firstRendered, 1}, {afterLastRendered, -101}, {afterLastRemoved, 100}} + if fmr.tailPartialEpoch > 0 { + endpoints = append(endpoints, []endpoint{{fmr.firstRenderedMap - mapsPerEpoch, 1}, {fmr.firstRenderedMap - mapsPerEpoch + fmr.tailPartialEpoch, -1}}...) + } + sort.Slice(endpoints, func(i, j int) bool { return endpoints[i].m < endpoints[j].m }) + var ( + sum int + merged []uint32 + last bool + ) + for i, e := range endpoints { + sum += e.d + if i < len(endpoints)-1 && endpoints[i+1].m == e.m { + continue + } + if (sum > 0) != last { + merged = append(merged, e.m) + last = !last + } + } + + switch len(merged) { + case 0: + // Initialized database, but no finished maps yet. + fmr.tailPartialEpoch = 0 + fmr.firstRenderedMap = firstRendered + fmr.afterLastRenderedMap = firstRendered + + case 2: + // One rendered section (no partial tail epoch). + fmr.tailPartialEpoch = 0 + fmr.firstRenderedMap = merged[0] + fmr.afterLastRenderedMap = merged[1] + + case 4: + // Two rendered sections (with a gap). + // First section (merged[0]-merged[1]) is for the partial tail epoch, + // and it has to start exactly one epoch before the main section. + if merged[2] != merged[0]+mapsPerEpoch { + return fmt.Errorf("invalid tail partial epoch: %v", merged) + } + fmr.tailPartialEpoch = merged[1] - merged[0] + fmr.firstRenderedMap = merged[2] + fmr.afterLastRenderedMap = merged[3] + + default: + return fmt.Errorf("invalid number of rendered sections: %v", merged) + } + return nil +} + +// logIterator iterates on the linear log value index range. +type logIterator struct { + chainView *ChainView + blockNumber uint64 + receipts types.Receipts + blockStart, delimiter, finished bool + txIndex, logIndex, topicIndex int + lvIndex uint64 +} + +var errUnindexedRange = errors.New("unindexed range") + +// newLogIteratorFromBlockDelimiter creates a logIterator starting at the +// given block's first log value entry (the block delimiter), according to the +// current targetView. +func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logIterator, error) { + if blockNumber > f.targetView.headNumber { + return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.headNumber) + } + if blockNumber < f.indexedRange.firstIndexedBlock || blockNumber >= f.indexedRange.afterLastIndexedBlock { + return nil, errUnindexedRange + } + var lvIndex uint64 + if f.indexedRange.headBlockIndexed && blockNumber+1 == f.indexedRange.afterLastIndexedBlock { + lvIndex = f.indexedRange.headBlockDelimiter + } else { + var err error + lvIndex, err = f.getBlockLvPointer(blockNumber + 1) + if err != nil { + return nil, fmt.Errorf("failed to retrieve log value pointer of block %d after delimiter: %v", blockNumber+1, err) + } + lvIndex-- + } + finished := blockNumber == f.targetView.headNumber + return &logIterator{ + chainView: f.targetView, + blockNumber: blockNumber, + finished: finished, + delimiter: !finished, + lvIndex: lvIndex, + }, nil +} + +// newLogIteratorFromMapBoundary creates a logIterator starting at the given +// map boundary, according to the current targetView. +func (f *FilterMaps) newLogIteratorFromMapBoundary(mapIndex uint32, startBlock, startLvPtr uint64) (*logIterator, error) { + if startBlock > f.targetView.headNumber { + return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", startBlock, f.targetView.headNumber) + } + // get block receipts + receipts := f.targetView.getReceipts(startBlock) + if receipts == nil { + return nil, fmt.Errorf("receipts not found for start block %d", startBlock) + } + // initialize iterator at block start + l := &logIterator{ + chainView: f.targetView, + blockNumber: startBlock, + receipts: receipts, + blockStart: true, + lvIndex: startLvPtr, + } + l.nextValid() + targetIndex := uint64(mapIndex) << f.logValuesPerMap + if l.lvIndex > targetIndex { + return nil, fmt.Errorf("log value pointer %d of last block of map is after map boundary %d", l.lvIndex, targetIndex) + } + // iterate to map boundary + for l.lvIndex < targetIndex { + if l.finished { + return nil, fmt.Errorf("iterator already finished at %d before map boundary target %d", l.lvIndex, targetIndex) + } + if err := l.next(); err != nil { + return nil, fmt.Errorf("failed to advance log iterator at %d before map boundary target %d: %v", l.lvIndex, targetIndex, err) + } + } + return l, nil +} + +// updateChainView updates the iterator's chain view if it still matches the +// previous view at the current position. Returns true if successful. +func (l *logIterator) updateChainView(cv *ChainView) bool { + if !matchViews(cv, l.chainView, l.blockNumber) { + return false + } + l.chainView = cv + return true +} + +// getValueHash returns the log value hash at the current position. +func (l *logIterator) getValueHash() common.Hash { + if l.delimiter || l.finished { + return common.Hash{} + } + log := l.receipts[l.txIndex].Logs[l.logIndex] + if l.topicIndex == 0 { + return addressValue(log.Address) + } + return topicValue(log.Topics[l.topicIndex-1]) +} + +// next moves the iterator to the next log value index. +func (l *logIterator) next() error { + if l.finished { + return nil + } + if l.delimiter { + l.delimiter = false + l.blockNumber++ + l.receipts = l.chainView.getReceipts(l.blockNumber) + if l.receipts == nil { + return fmt.Errorf("receipts not found for block %d", l.blockNumber) + } + l.txIndex, l.logIndex, l.topicIndex, l.blockStart = 0, 0, 0, true + } else { + l.topicIndex++ + l.blockStart = false + } + l.lvIndex++ + l.nextValid() + return nil +} + +// nextValid updates the internal transaction, log and topic index pointers +// to the next existing log value of the given block if necessary. +// Note that nextValid does not advance the log value index pointer. +func (l *logIterator) nextValid() { + for ; l.txIndex < len(l.receipts); l.txIndex++ { + receipt := l.receipts[l.txIndex] + for ; l.logIndex < len(receipt.Logs); l.logIndex++ { + log := receipt.Logs[l.logIndex] + if l.topicIndex <= len(log.Topics) { + return + } + l.topicIndex = 0 + } + l.logIndex = 0 + } + if l.blockNumber == l.chainView.headNumber { + l.finished = true + } else { + l.delimiter = true + } +} diff --git a/core/filtermaps/matcher.go b/core/filtermaps/matcher.go new file mode 100644 index 000000000..19acbd762 --- /dev/null +++ b/core/filtermaps/matcher.go @@ -0,0 +1,934 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "context" + "errors" + "fmt" + "math" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +const doRuntimeStats = false + +// ErrMatchAll is returned when the specified filter matches everything. +// Handling this case in filtermaps would require an extra special case and +// would actually be slower than reverting to legacy filter. +var ErrMatchAll = errors.New("match all patterns not supported") + +// MatcherBackend defines the functions required for searching in the log index +// data structure. It is currently implemented by FilterMapsMatcherBackend but +// once EIP-7745 is implemented and active, these functions can also be trustlessly +// served by a remote prover. +type MatcherBackend interface { + GetParams() *Params + GetBlockLvPointer(ctx context.Context, blockNumber uint64) (uint64, error) + GetFilterMapRow(ctx context.Context, mapIndex, rowIndex uint32, baseLayerOnly bool) (FilterRow, error) + GetLogByLvIndex(ctx context.Context, lvIndex uint64) (*types.Log, error) + SyncLogIndex(ctx context.Context) (SyncRange, error) + Close() +} + +// SyncRange is returned by MatcherBackend.SyncLogIndex. It contains the latest +// chain head, the indexed range that is currently consistent with the chain +// and the valid range that has not been changed and has been consistent with +// all states of the chain since the previous SyncLogIndex or the creation of +// the matcher backend. +type SyncRange struct { + HeadNumber uint64 + // block range where the index has not changed since the last matcher sync + // and therefore the set of matches found in this region is guaranteed to + // be valid and complete. + Valid bool + FirstValid, LastValid uint64 + // block range indexed according to the given chain head. + Indexed bool + FirstIndexed, LastIndexed uint64 +} + +// GetPotentialMatches returns a list of logs that are potential matches for the +// given filter criteria. If parts of the log index in the searched range are +// missing or changed during the search process then the resulting logs belonging +// to that block range might be missing or incorrect. +// Also note that the returned list may contain false positives. +func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock, lastBlock uint64, addresses []common.Address, topics [][]common.Hash) ([]*types.Log, error) { + params := backend.GetParams() + var getLogStats runtimeStats + // find the log value index range to search + firstIndex, err := backend.GetBlockLvPointer(ctx, firstBlock) + if err != nil { + return nil, fmt.Errorf("failed to retrieve log value pointer for first block %d: %v", firstBlock, err) + } + lastIndex, err := backend.GetBlockLvPointer(ctx, lastBlock+1) + if err != nil { + return nil, fmt.Errorf("failed to retrieve log value pointer after last block %d: %v", lastBlock, err) + } + if lastIndex > 0 { + lastIndex-- + } + firstMap, lastMap := uint32(firstIndex>>params.logValuesPerMap), uint32(lastIndex>>params.logValuesPerMap) + firstEpoch, lastEpoch := firstMap>>params.logMapsPerEpoch, lastMap>>params.logMapsPerEpoch + + // build matcher according to the given filter criteria + matchers := make([]matcher, len(topics)+1) + // matchAddress signals a match when there is a match for any of the given + // addresses. + // If the list of addresses is empty then it creates a "wild card" matcher + // that signals every index as a potential match. + matchAddress := make(matchAny, len(addresses)) + for i, address := range addresses { + matchAddress[i] = &singleMatcher{backend: backend, value: addressValue(address)} + } + matchers[0] = matchAddress + for i, topicList := range topics { + // matchTopic signals a match when there is a match for any of the topics + // specified for the given position (topicList). + // If topicList is empty then it creates a "wild card" matcher that signals + // every index as a potential match. + matchTopic := make(matchAny, len(topicList)) + for j, topic := range topicList { + matchTopic[j] = &singleMatcher{backend: backend, value: topicValue(topic)} + } + matchers[i+1] = matchTopic + } + // matcher is the final sequence matcher that signals a match when all underlying + // matchers signal a match for consecutive log value indices. + matcher := newMatchSequence(params, matchers) + + // processEpoch returns the potentially matching logs from the given epoch. + processEpoch := func(epochIndex uint32) ([]*types.Log, error) { + var logs []*types.Log + // create a list of map indices to process + fm, lm := epochIndex< lastMap { + lm = lastMap + } + // + mapIndices := make([]uint32, lm+1-fm) + for i := range mapIndices { + mapIndices[i] = fm + uint32(i) + } + // find potential matches + matches, err := getAllMatches(ctx, matcher, mapIndices) + if err != nil { + return logs, err + } + // get the actual logs located at the matching log value indices + var st int + getLogStats.setState(&st, stGetLog) + defer getLogStats.setState(&st, stNone) + for _, m := range matches { + if m == nil { + return nil, ErrMatchAll + } + mlogs, err := getLogsFromMatches(ctx, backend, firstIndex, lastIndex, m) + if err != nil { + return logs, err + } + logs = append(logs, mlogs...) + } + getLogStats.addAmount(st, int64(len(logs))) + return logs, nil + } + + type task struct { + epochIndex uint32 + logs []*types.Log + err error + done chan struct{} + } + + taskCh := make(chan *task) + var wg sync.WaitGroup + defer func() { + close(taskCh) + wg.Wait() + }() + + worker := func() { + for task := range taskCh { + if task == nil { + break + } + task.logs, task.err = processEpoch(task.epochIndex) + close(task.done) + } + wg.Done() + } + + start := time.Now() + for i := 0; i < 4; i++ { + wg.Add(1) + go worker() + } + + var logs []*types.Log + // startEpoch is the next task to send whenever a worker can accept it. + // waitEpoch is the next task we are waiting for to finish in order to append + // results in the correct order. + startEpoch, waitEpoch := firstEpoch, firstEpoch + tasks := make(map[uint32]*task) + tasks[startEpoch] = &task{epochIndex: startEpoch, done: make(chan struct{})} + for waitEpoch <= lastEpoch { + select { + case taskCh <- tasks[startEpoch]: + startEpoch++ + if startEpoch <= lastEpoch { + if tasks[startEpoch] == nil { + tasks[startEpoch] = &task{epochIndex: startEpoch, done: make(chan struct{})} + } + } + case <-tasks[waitEpoch].done: + logs = append(logs, tasks[waitEpoch].logs...) + if err := tasks[waitEpoch].err; err != nil { + if err == ErrMatchAll { + return logs, err + } + return logs, fmt.Errorf("failed to process log index epoch %d: %v", waitEpoch, err) + } + delete(tasks, waitEpoch) + waitEpoch++ + if waitEpoch <= lastEpoch { + if tasks[waitEpoch] == nil { + tasks[waitEpoch] = &task{epochIndex: waitEpoch, done: make(chan struct{})} + } + } + } + } + if doRuntimeStats { + log.Info("Log search finished", "elapsed", time.Since(start)) + for i, ma := range matchers { + for j, m := range ma.(matchAny) { + log.Info("Single matcher stats", "matchSequence", i, "matchAny", j) + m.(*singleMatcher).stats.print() + } + } + log.Info("Get log stats") + getLogStats.print() + } + return logs, nil +} + +// getLogsFromMatches returns the list of potentially matching logs located at +// the given list of matching log indices. Matches outside the firstIndex to +// lastIndex range are not returned. +func getLogsFromMatches(ctx context.Context, backend MatcherBackend, firstIndex, lastIndex uint64, matches potentialMatches) ([]*types.Log, error) { + var logs []*types.Log + for _, match := range matches { + if match < firstIndex || match > lastIndex { + continue + } + log, err := backend.GetLogByLvIndex(ctx, match) + if err != nil { + return logs, fmt.Errorf("failed to retrieve log at index %d: %v", match, err) + } + if log != nil { + logs = append(logs, log) + } + } + return logs, nil +} + +// matcher defines a general abstraction for any matcher configuration that +// can instantiate a matcherInstance. +type matcher interface { + newInstance(mapIndices []uint32) matcherInstance +} + +// matcherInstance defines a general abstraction for a matcher configuration +// working on a specific set of map indices and eventually returning a list of +// potentially matching log value indices. +// Note that processing happens per mapping layer, each call returning a set +// of results for the maps where the processing has been finished at the given +// layer. Map indices can also be dropped before a result is returned for them +// in case the result is no longer interesting. Dropping indices twice or after +// a result has been returned has no effect. Exactly one matcherResult is +// returned per requested map index unless dropped. +type matcherInstance interface { + getMatchesForLayer(ctx context.Context, layerIndex uint32) ([]matcherResult, error) + dropIndices(mapIndices []uint32) +} + +// matcherResult contains the list of potentially matching log value indices +// for a given map index. +type matcherResult struct { + mapIndex uint32 + matches potentialMatches +} + +// getAllMatches creates an instance for a given matcher and set of map indices, +// iterates through mapping layers and collects all results, then returns all +// results in the same order as the map indices were specified. +func getAllMatches(ctx context.Context, matcher matcher, mapIndices []uint32) ([]potentialMatches, error) { + instance := matcher.newInstance(mapIndices) + resultsMap := make(map[uint32]potentialMatches) + for layerIndex := uint32(0); len(resultsMap) < len(mapIndices); layerIndex++ { + results, err := instance.getMatchesForLayer(ctx, layerIndex) + if err != nil { + return nil, err + } + for _, result := range results { + resultsMap[result.mapIndex] = result.matches + } + } + matches := make([]potentialMatches, len(mapIndices)) + for i, mapIndex := range mapIndices { + matches[i] = resultsMap[mapIndex] + } + return matches, nil +} + +// singleMatcher implements matcher by returning matches for a single log value hash. +type singleMatcher struct { + backend MatcherBackend + value common.Hash + stats runtimeStats +} + +// singleMatcherInstance is an instance of singleMatcher. +type singleMatcherInstance struct { + *singleMatcher + mapIndices []uint32 + filterRows map[uint32][]FilterRow +} + +// newInstance creates a new instance of singleMatcher. +func (m *singleMatcher) newInstance(mapIndices []uint32) matcherInstance { + filterRows := make(map[uint32][]FilterRow) + for _, idx := range mapIndices { + filterRows[idx] = []FilterRow{} + } + copiedIndices := make([]uint32, len(mapIndices)) + copy(copiedIndices, mapIndices) + return &singleMatcherInstance{ + singleMatcher: m, + mapIndices: copiedIndices, + filterRows: filterRows, + } +} + +// getMatchesForLayer implements matcherInstance. +func (m *singleMatcherInstance) getMatchesForLayer(ctx context.Context, layerIndex uint32) (results []matcherResult, err error) { + var st int + m.stats.setState(&st, stOther) + params := m.backend.GetParams() + maskedMapIndex, rowIndex := uint32(math.MaxUint32), uint32(0) + for _, mapIndex := range m.mapIndices { + filterRows, ok := m.filterRows[mapIndex] + if !ok { + continue + } + if mm := params.maskedMapIndex(mapIndex, layerIndex); mm != maskedMapIndex { + // only recalculate rowIndex when necessary + maskedMapIndex = mm + rowIndex = params.rowIndex(mapIndex, layerIndex, m.value) + } + if layerIndex == 0 { + m.stats.setState(&st, stFetchFirst) + } else { + m.stats.setState(&st, stFetchMore) + } + filterRow, err := m.backend.GetFilterMapRow(ctx, mapIndex, rowIndex, layerIndex == 0) + if err != nil { + m.stats.setState(&st, stNone) + return nil, fmt.Errorf("failed to retrieve filter map %d row %d: %v", mapIndex, rowIndex, err) + } + m.stats.addAmount(st, int64(len(filterRow))) + m.stats.setState(&st, stOther) + filterRows = append(filterRows, filterRow) + if uint32(len(filterRow)) < params.maxRowLength(layerIndex) { + m.stats.setState(&st, stProcess) + matches := params.potentialMatches(filterRows, mapIndex, m.value) + m.stats.addAmount(st, int64(len(matches))) + results = append(results, matcherResult{ + mapIndex: mapIndex, + matches: matches, + }) + m.stats.setState(&st, stOther) + delete(m.filterRows, mapIndex) + } else { + m.filterRows[mapIndex] = filterRows + } + } + m.cleanMapIndices() + m.stats.setState(&st, stNone) + return results, nil +} + +// dropIndices implements matcherInstance. +func (m *singleMatcherInstance) dropIndices(dropIndices []uint32) { + for _, mapIndex := range dropIndices { + delete(m.filterRows, mapIndex) + } + m.cleanMapIndices() +} + +// cleanMapIndices removes map indices from the list if there is no matching +// filterRows entry because a result has been returned or the index has been +// dropped. +func (m *singleMatcherInstance) cleanMapIndices() { + var j int + for i, mapIndex := range m.mapIndices { + if _, ok := m.filterRows[mapIndex]; ok { + if i != j { + m.mapIndices[j] = mapIndex + } + j++ + } + } + m.mapIndices = m.mapIndices[:j] +} + +// matchAny combinines a set of matchers and returns a match for every position +// where any of the underlying matchers signaled a match. A zero-length matchAny +// acts as a "wild card" that signals a potential match at every position. +type matchAny []matcher + +// matchAnyInstance is an instance of matchAny. +type matchAnyInstance struct { + matchAny + childInstances []matcherInstance + childResults map[uint32]matchAnyResults +} + +// matchAnyResults is used by matchAnyInstance to collect results from all +// child matchers for a specific map index. Once all results has been received +// a merged result is returned for the given map and this structure is discarded. +type matchAnyResults struct { + matches []potentialMatches + done []bool + needMore int +} + +// newInstance creates a new instance of matchAny. +func (m matchAny) newInstance(mapIndices []uint32) matcherInstance { + if len(m) == 1 { + return m[0].newInstance(mapIndices) + } + childResults := make(map[uint32]matchAnyResults) + for _, idx := range mapIndices { + childResults[idx] = matchAnyResults{ + matches: make([]potentialMatches, len(m)), + done: make([]bool, len(m)), + needMore: len(m), + } + } + childInstances := make([]matcherInstance, len(m)) + for i, matcher := range m { + childInstances[i] = matcher.newInstance(mapIndices) + } + return &matchAnyInstance{ + matchAny: m, + childInstances: childInstances, + childResults: childResults, + } +} + +// getMatchesForLayer implements matcherInstance. +func (m *matchAnyInstance) getMatchesForLayer(ctx context.Context, layerIndex uint32) (mergedResults []matcherResult, err error) { + if len(m.matchAny) == 0 { + // return "wild card" results (potentialMatches(nil) is interpreted as a + // potential match at every log value index of the map). + mergedResults = make([]matcherResult, len(m.childResults)) + var i int + for mapIndex := range m.childResults { + mergedResults[i] = matcherResult{mapIndex: mapIndex, matches: nil} + i++ + } + return mergedResults, nil + } + for i, childInstance := range m.childInstances { + results, err := childInstance.getMatchesForLayer(ctx, layerIndex) + if err != nil { + return nil, fmt.Errorf("failed to evaluate child matcher on layer %d: %v", layerIndex, err) + } + for _, result := range results { + mr, ok := m.childResults[result.mapIndex] + if !ok || mr.done[i] { + continue + } + mr.done[i] = true + mr.matches[i] = result.matches + mr.needMore-- + if mr.needMore == 0 || result.matches == nil { + mergedResults = append(mergedResults, matcherResult{ + mapIndex: result.mapIndex, + matches: mergeResults(mr.matches), + }) + delete(m.childResults, result.mapIndex) + } else { + m.childResults[result.mapIndex] = mr + } + } + } + return mergedResults, nil +} + +// dropIndices implements matcherInstance. +func (m *matchAnyInstance) dropIndices(dropIndices []uint32) { + for _, childInstance := range m.childInstances { + childInstance.dropIndices(dropIndices) + } + for _, mapIndex := range dropIndices { + delete(m.childResults, mapIndex) + } +} + +// mergeResults merges multiple lists of matches into a single one, preserving +// ascending order and filtering out any duplicates. +func mergeResults(results []potentialMatches) potentialMatches { + if len(results) == 0 { + return nil + } + var sumLen int + for _, res := range results { + if res == nil { + // nil is a wild card; all indices in map range are potential matches + return nil + } + sumLen += len(res) + } + merged := make(potentialMatches, 0, sumLen) + for { + best := -1 + for i, res := range results { + if len(res) == 0 { + continue + } + if best < 0 || res[0] < results[best][0] { + best = i + } + } + if best < 0 { + return merged + } + if len(merged) == 0 || results[best][0] > merged[len(merged)-1] { + merged = append(merged, results[best][0]) + } + results[best] = results[best][1:] + } +} + +// matchSequence combines two matchers, a "base" and a "next" matcher with a +// positive integer offset so that the resulting matcher signals a match at log +// value index X when the base matcher returns a match at X and the next matcher +// gives a match at X+offset. Note that matchSequence can be used recursively to +// detect any log value sequence. +type matchSequence struct { + params *Params + base, next matcher + offset uint64 + statsLock sync.Mutex + baseStats, nextStats matchOrderStats +} + +// newInstance creates a new instance of matchSequence. +func (m *matchSequence) newInstance(mapIndices []uint32) matcherInstance { + // determine set of indices to request from next matcher + nextIndices := make([]uint32, 0, len(mapIndices)*3/2) + needMatched := make(map[uint32]struct{}) + baseRequested := make(map[uint32]struct{}) + nextRequested := make(map[uint32]struct{}) + for _, mapIndex := range mapIndices { + needMatched[mapIndex] = struct{}{} + baseRequested[mapIndex] = struct{}{} + if _, ok := nextRequested[mapIndex]; !ok { + nextIndices = append(nextIndices, mapIndex) + nextRequested[mapIndex] = struct{}{} + } + nextIndices = append(nextIndices, mapIndex+1) + nextRequested[mapIndex+1] = struct{}{} + } + return &matchSequenceInstance{ + matchSequence: m, + baseInstance: m.base.newInstance(mapIndices), + nextInstance: m.next.newInstance(nextIndices), + needMatched: needMatched, + baseRequested: baseRequested, + nextRequested: nextRequested, + baseResults: make(map[uint32]potentialMatches), + nextResults: make(map[uint32]potentialMatches), + } +} + +// matchOrderStats collects statistics about the evaluating cost and the +// occurrence of empty result sets from both base and next child matchers. +// This allows the optimization of the evaluation order by evaluating the +// child first that is cheaper and/or gives empty results more often and not +// evaluating the other child in most cases. +// Note that matchOrderStats is specific to matchSequence and the results are +// carried over to future instances as the results are mostly useful when +// evaluating layer zero of each instance. For this reason it should be used +// in a thread safe way as is may be accessed from multiple worker goroutines. +type matchOrderStats struct { + totalCount, nonEmptyCount, totalCost uint64 +} + +// add collects statistics after a child has been evaluated for a certain layer. +func (ms *matchOrderStats) add(empty bool, layerIndex uint32) { + if empty && layerIndex != 0 { + // matchers may be evaluated for higher layers after all results have + // been returned. Also, empty results are not relevant when previous + // layers yielded matches already, so these cases can be ignored. + return + } + ms.totalCount++ + if !empty { + ms.nonEmptyCount++ + } + ms.totalCost += uint64(layerIndex + 1) +} + +// mergeStats merges two sets of matchOrderStats. +func (ms *matchOrderStats) mergeStats(add matchOrderStats) { + ms.totalCount += add.totalCount + ms.nonEmptyCount += add.nonEmptyCount + ms.totalCost += add.totalCost +} + +// baseFirst returns true if the base child matcher should be evaluated first. +func (m *matchSequence) baseFirst() bool { + m.statsLock.Lock() + bf := float64(m.baseStats.totalCost)*float64(m.nextStats.totalCount)+ + float64(m.baseStats.nonEmptyCount)*float64(m.nextStats.totalCost) < + float64(m.baseStats.totalCost)*float64(m.nextStats.nonEmptyCount)+ + float64(m.nextStats.totalCost)*float64(m.baseStats.totalCount) + m.statsLock.Unlock() + return bf +} + +// mergeBaseStats merges a set of matchOrderStats into the base matcher stats. +func (m *matchSequence) mergeBaseStats(stats matchOrderStats) { + m.statsLock.Lock() + m.baseStats.mergeStats(stats) + m.statsLock.Unlock() +} + +// mergeNextStats merges a set of matchOrderStats into the next matcher stats. +func (m *matchSequence) mergeNextStats(stats matchOrderStats) { + m.statsLock.Lock() + m.nextStats.mergeStats(stats) + m.statsLock.Unlock() +} + +// newMatchSequence creates a recursive sequence matcher from a list of underlying +// matchers. The resulting matcher signals a match at log value index X when each +// underlying matcher matchers[i] returns a match at X+i. +func newMatchSequence(params *Params, matchers []matcher) matcher { + if len(matchers) == 0 { + panic("zero length sequence matchers are not allowed") + } + if len(matchers) == 1 { + return matchers[0] + } + return &matchSequence{ + params: params, + base: newMatchSequence(params, matchers[:len(matchers)-1]), + next: matchers[len(matchers)-1], + offset: uint64(len(matchers) - 1), + } +} + +// matchSequenceInstance is an instance of matchSequence. +type matchSequenceInstance struct { + *matchSequence + baseInstance, nextInstance matcherInstance + baseRequested, nextRequested, needMatched map[uint32]struct{} + baseResults, nextResults map[uint32]potentialMatches +} + +// getMatchesForLayer implements matcherInstance. +func (m *matchSequenceInstance) getMatchesForLayer(ctx context.Context, layerIndex uint32) (matchedResults []matcherResult, err error) { + // decide whether to evaluate base or next matcher first + baseFirst := m.baseFirst() + if baseFirst { + if err := m.evalBase(ctx, layerIndex); err != nil { + return nil, err + } + } + if err := m.evalNext(ctx, layerIndex); err != nil { + return nil, err + } + if !baseFirst { + if err := m.evalBase(ctx, layerIndex); err != nil { + return nil, err + } + } + // evaluate and return matched results where possible + for mapIndex := range m.needMatched { + if _, ok := m.baseRequested[mapIndex]; ok { + continue + } + if _, ok := m.nextRequested[mapIndex]; ok { + continue + } + if _, ok := m.nextRequested[mapIndex+1]; ok { + continue + } + matchedResults = append(matchedResults, matcherResult{ + mapIndex: mapIndex, + matches: m.params.matchResults(mapIndex, m.offset, m.baseResults[mapIndex], m.nextResults[mapIndex], m.nextResults[mapIndex+1]), + }) + delete(m.needMatched, mapIndex) + } + return matchedResults, nil +} + +// dropIndices implements matcherInstance. +func (m *matchSequenceInstance) dropIndices(dropIndices []uint32) { + for _, mapIndex := range dropIndices { + delete(m.needMatched, mapIndex) + } + var dropBase, dropNext []uint32 + for _, mapIndex := range dropIndices { + if m.dropBase(mapIndex) { + dropBase = append(dropBase, mapIndex) + } + } + m.baseInstance.dropIndices(dropBase) + for _, mapIndex := range dropIndices { + if m.dropNext(mapIndex) { + dropNext = append(dropNext, mapIndex) + } + if m.dropNext(mapIndex + 1) { + dropNext = append(dropNext, mapIndex+1) + } + } + m.nextInstance.dropIndices(dropNext) +} + +// evalBase evaluates the base child matcher and drops map indices from the +// next matcher if possible. +func (m *matchSequenceInstance) evalBase(ctx context.Context, layerIndex uint32) error { + results, err := m.baseInstance.getMatchesForLayer(ctx, layerIndex) + if err != nil { + return fmt.Errorf("failed to evaluate base matcher on layer %d: %v", layerIndex, err) + } + var ( + dropIndices []uint32 + stats matchOrderStats + ) + for _, r := range results { + m.baseResults[r.mapIndex] = r.matches + delete(m.baseRequested, r.mapIndex) + stats.add(r.matches != nil && len(r.matches) == 0, layerIndex) + } + m.mergeBaseStats(stats) + for _, r := range results { + if m.dropNext(r.mapIndex) { + dropIndices = append(dropIndices, r.mapIndex) + } + if m.dropNext(r.mapIndex + 1) { + dropIndices = append(dropIndices, r.mapIndex+1) + } + } + if len(dropIndices) > 0 { + m.nextInstance.dropIndices(dropIndices) + } + return nil +} + +// evalNext evaluates the next child matcher and drops map indices from the +// base matcher if possible. +func (m *matchSequenceInstance) evalNext(ctx context.Context, layerIndex uint32) error { + results, err := m.nextInstance.getMatchesForLayer(ctx, layerIndex) + if err != nil { + return fmt.Errorf("failed to evaluate next matcher on layer %d: %v", layerIndex, err) + } + var ( + dropIndices []uint32 + stats matchOrderStats + ) + for _, r := range results { + m.nextResults[r.mapIndex] = r.matches + delete(m.nextRequested, r.mapIndex) + stats.add(r.matches != nil && len(r.matches) == 0, layerIndex) + } + m.mergeNextStats(stats) + for _, r := range results { + if r.mapIndex > 0 && m.dropBase(r.mapIndex-1) { + dropIndices = append(dropIndices, r.mapIndex-1) + } + if m.dropBase(r.mapIndex) { + dropIndices = append(dropIndices, r.mapIndex) + } + } + if len(dropIndices) > 0 { + m.baseInstance.dropIndices(dropIndices) + } + return nil +} + +// dropBase checks whether the given map index can be dropped from the base +// matcher based on the known results from the next matcher and removes it +// from the internal requested set and returns true if possible. +func (m *matchSequenceInstance) dropBase(mapIndex uint32) bool { + if _, ok := m.baseRequested[mapIndex]; !ok { + return false + } + if _, ok := m.needMatched[mapIndex]; ok { + if next := m.nextResults[mapIndex]; next == nil || + (len(next) > 0 && next[len(next)-1] >= (uint64(mapIndex)< 0 && nextNext[0] < (uint64(mapIndex+1)< 0 && prevBase[len(prevBase)-1]+m.offset >= (uint64(mapIndex)< 0 && base[0]+m.offset < (uint64(mapIndex+1)< 0 { + // discard items from nextRes whose corresponding base matcher results + // with the negative offset applied would be located at mapIndex-1. + start := 0 + for start < len(nextRes) && nextRes[start] < uint64(mapIndex)< 0 { + // discard items from nextNextRes whose corresponding base matcher results + // with the negative offset applied would still be located at mapIndex+1. + stop := 0 + for stop < len(nextNextRes) && nextNextRes[stop] < uint64(mapIndex+1)< 0 && len(baseRes) > 0 { + if nextRes[0] > baseRes[0]+offset { + baseRes = baseRes[1:] + } else if nextRes[0] < baseRes[0]+offset { + nextRes = nextRes[1:] + } else { + matchedRes = append(matchedRes, baseRes[0]) + baseRes = baseRes[1:] + nextRes = nextRes[1:] + } + } + } else { + // baseRes is a wild card so just return next matcher results with + // negative offset. + for len(nextRes) > 0 { + matchedRes = append(matchedRes, nextRes[0]-offset) + nextRes = nextRes[1:] + } + } + } + return matchedRes +} + +// runtimeStats collects processing time statistics while searching in the log +// index. Used only when the doRuntimeStats global flag is true. +type runtimeStats struct { + dt, cnt, amount [stCount]int64 +} + +const ( + stNone = iota + stFetchFirst + stFetchMore + stProcess + stGetLog + stOther + stCount +) + +var stNames = []string{"", "fetchFirst", "fetchMore", "process", "getLog", "other"} + +// set sets the processing state to one of the pre-defined constants. +// Processing time spent in each state is measured separately. +func (ts *runtimeStats) setState(state *int, newState int) { + if !doRuntimeStats || newState == *state { + return + } + now := int64(mclock.Now()) + atomic.AddInt64(&ts.dt[*state], now) + atomic.AddInt64(&ts.dt[newState], -now) + atomic.AddInt64(&ts.cnt[newState], 1) + *state = newState +} + +func (ts *runtimeStats) addAmount(state int, amount int64) { + atomic.AddInt64(&ts.amount[state], amount) +} + +// print prints the collected statistics. +func (ts *runtimeStats) print() { + for i := 1; i < stCount; i++ { + log.Info("Matcher stats", "name", stNames[i], "dt", time.Duration(ts.dt[i]), "count", ts.cnt[i], "amount", ts.amount[i]) + } +} diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go new file mode 100644 index 000000000..66f95f214 --- /dev/null +++ b/core/filtermaps/matcher_backend.go @@ -0,0 +1,206 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "context" + + "github.com/ethereum/go-ethereum/core/types" +) + +// FilterMapsMatcherBackend implements MatcherBackend. +type FilterMapsMatcherBackend struct { + f *FilterMaps + + // these fields should be accessed under f.matchersLock mutex. + valid bool + firstValid, lastValid uint64 + syncCh chan SyncRange +} + +// NewMatcherBackend returns a FilterMapsMatcherBackend after registering it in +// the active matcher set. +// Note that Close should always be called when the matcher is no longer used. +func (f *FilterMaps) NewMatcherBackend() *FilterMapsMatcherBackend { + f.indexLock.RLock() + f.matchersLock.Lock() + defer func() { + f.matchersLock.Unlock() + f.indexLock.RUnlock() + }() + + fm := &FilterMapsMatcherBackend{ + f: f, + valid: f.indexedRange.initialized && f.indexedRange.afterLastIndexedBlock > f.indexedRange.firstIndexedBlock, + firstValid: f.indexedRange.firstIndexedBlock, + lastValid: f.indexedRange.afterLastIndexedBlock - 1, + } + f.matchers[fm] = struct{}{} + return fm +} + +// GetParams returns the filtermaps parameters. +// GetParams implements MatcherBackend. +func (fm *FilterMapsMatcherBackend) GetParams() *Params { + return &fm.f.Params +} + +// Close removes the matcher from the set of active matchers and ensures that +// any SyncLogIndex calls are cancelled. +// Close implements MatcherBackend. +func (fm *FilterMapsMatcherBackend) Close() { + fm.f.matchersLock.Lock() + defer fm.f.matchersLock.Unlock() + + delete(fm.f.matchers, fm) +} + +// GetFilterMapRow returns the given row of the given map. If the row is empty +// then a non-nil zero length row is returned. If baseLayerOnly is true then +// only the first baseRowLength entries of the row are guaranteed to be +// returned. +// Note that the returned slices should not be modified, they should be copied +// on write. +// GetFilterMapRow implements MatcherBackend. +func (fm *FilterMapsMatcherBackend) GetFilterMapRow(ctx context.Context, mapIndex, rowIndex uint32, baseLayerOnly bool) (FilterRow, error) { + return fm.f.getFilterMapRow(mapIndex, rowIndex, baseLayerOnly) +} + +// GetBlockLvPointer returns the starting log value index where the log values +// generated by the given block are located. If blockNumber is beyond the current +// head then the first unoccupied log value index is returned. +// GetBlockLvPointer implements MatcherBackend. +func (fm *FilterMapsMatcherBackend) GetBlockLvPointer(ctx context.Context, blockNumber uint64) (uint64, error) { + fm.f.indexLock.RLock() + defer fm.f.indexLock.RUnlock() + + return fm.f.getBlockLvPointer(blockNumber) +} + +// GetLogByLvIndex returns the log at the given log value index. +// Note that this function assumes that the log index structure is consistent +// with the canonical chain at the point where the given log value index points. +// If this is not the case then an invalid result may be returned or certain +// logs might not be returned at all. +// No error is returned though because of an inconsistency between the chain and +// the log index. It is the caller's responsibility to verify this consistency +// using SyncLogIndex and re-process certain blocks if necessary. +// GetLogByLvIndex implements MatcherBackend. +func (fm *FilterMapsMatcherBackend) GetLogByLvIndex(ctx context.Context, lvIndex uint64) (*types.Log, error) { + fm.f.indexLock.RLock() + defer fm.f.indexLock.RUnlock() + + return fm.f.getLogByLvIndex(lvIndex) +} + +// synced signals to the matcher that has triggered a synchronisation that it +// has been finished and the log index is consistent with the chain head passed +// as a parameter. +// Note that if the log index head was far behind the chain head then it might not +// be synced up to the given head in a single step. Still, the latest chain head +// should be passed as a parameter and the existing log index should be consistent +// with that chain. +func (fm *FilterMapsMatcherBackend) synced() { + fm.f.indexLock.RLock() + fm.f.matchersLock.Lock() + defer func() { + fm.f.matchersLock.Unlock() + fm.f.indexLock.RUnlock() + }() + + var ( + indexed bool + lastIndexed, subLastIndexed uint64 + ) + if !fm.f.indexedRange.headBlockIndexed { + subLastIndexed = 1 + } + if fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed > fm.f.indexedRange.firstIndexedBlock { + indexed, lastIndexed = true, fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed-1 + } + fm.syncCh <- SyncRange{ + HeadNumber: fm.f.indexedView.headNumber, + Valid: fm.valid, + FirstValid: fm.firstValid, + LastValid: fm.lastValid, + Indexed: indexed, + FirstIndexed: fm.f.indexedRange.firstIndexedBlock, + LastIndexed: lastIndexed, + } + fm.valid = indexed + fm.firstValid = fm.f.indexedRange.firstIndexedBlock + fm.lastValid = lastIndexed + fm.syncCh = nil +} + +// SyncLogIndex ensures that the log index is consistent with the current state +// of the chain and is synced up to the current head. It blocks until this state +// is achieved or the context is cancelled. +// If successful, it returns a SyncRange that contains the latest chain head, +// the indexed range that is currently consistent with the chain and the valid +// range that has not been changed and has been consistent with all states of the +// chain since the previous SyncLogIndex or the creation of the matcher backend. +func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange, error) { + if fm.f.disabled { + return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil + } + + syncCh := make(chan SyncRange, 1) + fm.f.matchersLock.Lock() + fm.syncCh = syncCh + fm.f.matchersLock.Unlock() + + select { + case fm.f.matcherSyncCh <- fm: + case <-ctx.Done(): + return SyncRange{}, ctx.Err() + } + select { + case vr := <-syncCh: + return vr, nil + case <-ctx.Done(): + return SyncRange{}, ctx.Err() + } +} + +// updateMatchersValidRange iterates through active matchers and limits their +// valid range with the current indexed range. This function should be called +// whenever a part of the log index has been removed, before adding new blocks +// to it. +// Note that this function assumes that the index read lock is being held. +func (f *FilterMaps) updateMatchersValidRange() { + f.matchersLock.Lock() + defer f.matchersLock.Unlock() + + for fm := range f.matchers { + if !f.indexedRange.hasIndexedBlocks() { + fm.valid = false + } + if !fm.valid { + continue + } + if fm.firstValid < f.indexedRange.firstIndexedBlock { + fm.firstValid = f.indexedRange.firstIndexedBlock + } + if fm.lastValid >= f.indexedRange.afterLastIndexedBlock { + fm.lastValid = f.indexedRange.afterLastIndexedBlock - 1 + } + if fm.firstValid > fm.lastValid { + fm.valid = false + } + } +} diff --git a/core/filtermaps/matcher_test.go b/core/filtermaps/matcher_test.go new file mode 100644 index 000000000..5a49ce66e --- /dev/null +++ b/core/filtermaps/matcher_test.go @@ -0,0 +1,87 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "context" + crand "crypto/rand" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestMatcher(t *testing.T) { + ts := newTestSetup(t) + defer ts.close() + + ts.chain.addBlocks(100, 10, 10, 4, true) + ts.setHistory(0, false) + ts.fm.WaitIdle() + + for i := 0; i < 2000; i++ { + bhash := ts.chain.canonical[rand.Intn(len(ts.chain.canonical))] + receipts := ts.chain.receipts[bhash] + if len(receipts) == 0 { + continue + } + receipt := receipts[rand.Intn(len(receipts))] + if len(receipt.Logs) == 0 { + continue + } + log := receipt.Logs[rand.Intn(len(receipt.Logs))] + var ok bool + addresses := make([]common.Address, rand.Intn(3)) + for i := range addresses { + crand.Read(addresses[i][:]) + } + if len(addresses) > 0 { + addresses[rand.Intn(len(addresses))] = log.Address + ok = true + } + topics := make([][]common.Hash, rand.Intn(len(log.Topics)+1)) + for j := range topics { + topics[j] = make([]common.Hash, rand.Intn(3)) + for i := range topics[j] { + crand.Read(topics[j][i][:]) + } + if len(topics[j]) > 0 { + topics[j][rand.Intn(len(topics[j]))] = log.Topics[j] + ok = true + } + } + if !ok { + continue // cannot search for match-all pattern + } + mb := ts.fm.NewMatcherBackend() + logs, err := GetPotentialMatches(context.Background(), mb, 0, 1000, addresses, topics) + mb.Close() + if err != nil { + t.Fatalf("Log search error: %v", err) + } + var found bool + for _, l := range logs { + if l == log { + found = true + break + } + } + if !found { + t.Fatalf("Log search did not return expected log (addresses: %v, topics: %v, expected log: %v)", addresses, topics, *log) + } + } +} diff --git a/core/filtermaps/math.go b/core/filtermaps/math.go new file mode 100644 index 000000000..762a99be9 --- /dev/null +++ b/core/filtermaps/math.go @@ -0,0 +1,212 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + "crypto/sha256" + "encoding/binary" + "hash/fnv" + "math" + "sort" + + "github.com/ethereum/go-ethereum/common" +) + +// Params defines the basic parameters of the log index structure. +type Params struct { + logMapHeight uint // log2(mapHeight) + logMapWidth uint // log2(mapWidth) + logMapsPerEpoch uint // log2(mapsPerEpoch) + logValuesPerMap uint // log2(logValuesPerMap) + baseRowLengthRatio uint // baseRowLength / average row length + logLayerDiff uint // maxRowLength log2 growth per layer + // derived fields + mapHeight uint32 // filter map height (number of rows) + mapsPerEpoch uint32 // number of maps in an epoch + baseRowLength uint32 // maximum number of log values per row on layer 0 + valuesPerMap uint64 // number of log values marked on each filter map + // not affecting consensus + baseRowGroupLength uint32 // length of base row groups in local database +} + +// DefaultParams is the set of parameters used on mainnet. +var DefaultParams = Params{ + logMapHeight: 16, + logMapWidth: 24, + logMapsPerEpoch: 10, + logValuesPerMap: 16, + baseRowGroupLength: 32, + baseRowLengthRatio: 8, + logLayerDiff: 4, +} + +// RangeTestParams puts one log value per epoch, ensuring block exact tail unindexing for testing +var RangeTestParams = Params{ + logMapHeight: 4, + logMapWidth: 24, + logMapsPerEpoch: 0, + logValuesPerMap: 0, + baseRowGroupLength: 32, + baseRowLengthRatio: 16, // baseRowLength >= 1 + logLayerDiff: 4, +} + +// deriveFields calculates the derived fields of the parameter set. +func (p *Params) deriveFields() { + p.mapHeight = uint32(1) << p.logMapHeight + p.mapsPerEpoch = uint32(1) << p.logMapsPerEpoch + p.valuesPerMap = uint64(1) << p.logValuesPerMap + p.baseRowLength = uint32(p.valuesPerMap * uint64(p.baseRowLengthRatio) / uint64(p.mapHeight)) +} + +// addressValue returns the log value hash of a log emitting address. +func addressValue(address common.Address) common.Hash { + var result common.Hash + hasher := sha256.New() + hasher.Write(address[:]) + hasher.Sum(result[:0]) + return result +} + +// topicValue returns the log value hash of a log topic. +func topicValue(topic common.Hash) common.Hash { + var result common.Hash + hasher := sha256.New() + hasher.Write(topic[:]) + hasher.Sum(result[:0]) + return result +} + +// rowIndex returns the row index in which the given log value should be marked +// on the given map and mapping layer. Note that row assignments are re-shuffled +// with a different frequency on each mapping layer, allowing efficient disk +// access and Merkle proofs for long sections of short rows on lower order +// layers while avoiding putting too many heavy rows next to each other on +// higher order layers. +func (p *Params) rowIndex(mapIndex, layerIndex uint32, logValue common.Hash) uint32 { + hasher := sha256.New() + hasher.Write(logValue[:]) + var indexEnc [8]byte + binary.LittleEndian.PutUint32(indexEnc[0:4], p.maskedMapIndex(mapIndex, layerIndex)) + binary.LittleEndian.PutUint32(indexEnc[4:8], layerIndex) + hasher.Write(indexEnc[:]) + var hash common.Hash + hasher.Sum(hash[:0]) + return binary.LittleEndian.Uint32(hash[:4]) % p.mapHeight +} + +// columnIndex returns the column index where the given log value at the given +// position should be marked. +func (p *Params) columnIndex(lvIndex uint64, logValue *common.Hash) uint32 { + var indexEnc [8]byte + binary.LittleEndian.PutUint64(indexEnc[:], lvIndex) + // Note: reusing the hasher brings practically no performance gain and would + // require passing it through the entire matcher logic because of multi-thread + // matching + hasher := fnv.New64a() + hasher.Write(indexEnc[:]) + hasher.Write(logValue[:]) + hash := hasher.Sum64() + hashBits := p.logMapWidth - p.logValuesPerMap + return uint32(lvIndex%p.valuesPerMap)<>(64-hashBits)) ^ uint32(hash)>>(32-hashBits)) +} + +// maxRowLength returns the maximum length filter rows are populated up to +// when using the given mapping layer. A log value can be marked on the map +// according to a given mapping layer if the row mapping on that layer points +// to a row that has not yet reached the maxRowLength belonging to that layer. +// This means that a row that is considered full on a given layer may still be +// extended further on a higher order layer. +// Each value is marked on the lowest order layer possible, assuming that marks +// are added in ascending log value index order. +// When searching for a log value one should consider all layers and process +// corresponding rows up until the first one where the row mapped to the given +// layer is not full. +func (p *Params) maxRowLength(layerIndex uint32) uint32 { + logLayerDiff := uint(layerIndex) * p.logLayerDiff + if logLayerDiff > p.logMapsPerEpoch { + logLayerDiff = p.logMapsPerEpoch + } + return p.baseRowLength << logLayerDiff +} + +// maskedMapIndex returns the index used for row mapping calculation on the +// given layer. On layer zero the mapping changes once per epoch, then the +// frequency of re-mapping increases with every new layer until it reaches +// the frequency where it is different for every mapIndex. +func (p *Params) maskedMapIndex(mapIndex, layerIndex uint32) uint32 { + logLayerDiff := uint(layerIndex) * p.logLayerDiff + if logLayerDiff > p.logMapsPerEpoch { + logLayerDiff = p.logMapsPerEpoch + } + return mapIndex & (uint32(math.MaxUint32) << (p.logMapsPerEpoch - logLayerDiff)) +} + +// potentialMatches returns the list of log value indices potentially matching +// the given log value hash in the range of the filter map the row belongs to. +// Note that the list of indices is always sorted and potential duplicates are +// removed. Though the column indices are stored in the same order they were +// added and therefore the true matches are automatically reverse transformed +// in the right order, false positives can ruin this property. Since these can +// only be separated from true matches after the combined pattern matching of the +// outputs of individual log value matchers and this pattern matcher assumes a +// sorted and duplicate-free list of indices, we should ensure these properties +// here. +func (p *Params) potentialMatches(rows []FilterRow, mapIndex uint32, logValue common.Hash) potentialMatches { + results := make(potentialMatches, 0, 8) + mapFirst := uint64(mapIndex) << p.logValuesPerMap + for i, row := range rows { + rowLen, maxLen := len(row), int(p.maxRowLength(uint32(i))) + if rowLen > maxLen { + rowLen = maxLen // any additional entries are generated by another log value on a higher mapping layer + } + for i := 0; i < rowLen; i++ { + if potentialMatch := mapFirst + uint64(row[i]>>(p.logMapWidth-p.logValuesPerMap)); row[i] == p.columnIndex(potentialMatch, &logValue) { + results = append(results, potentialMatch) + } + } + if rowLen < maxLen { + break + } + if i == len(rows)-1 { + panic("potentialMatches: insufficient list of row alternatives") + } + } + sort.Sort(results) + // remove duplicates + j := 0 + for i, match := range results { + if i == 0 || match != results[i-1] { + results[j] = results[i] + j++ + } + } + return results[:j] +} + +// potentialMatches is a strictly monotonically increasing list of log value +// indices in the range of a filter map that are potential matches for certain +// filter criteria. +// potentialMatches implements sort.Interface. +// Note that nil is used as a wildcard and therefore means that all log value +// indices in the filter map range are potential matches. If there are no +// potential matches in the given map's range then an empty slice should be used. +type potentialMatches []uint64 + +func (p potentialMatches) Len() int { return len(p) } +func (p potentialMatches) Less(i, j int) bool { return p[i] < p[j] } +func (p potentialMatches) Swap(i, j int) { p[i], p[j] = p[j], p[i] } diff --git a/core/filtermaps/math_test.go b/core/filtermaps/math_test.go new file mode 100644 index 000000000..a4c160905 --- /dev/null +++ b/core/filtermaps/math_test.go @@ -0,0 +1,149 @@ +// Copyright 2024 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 . + +package filtermaps + +import ( + crand "crypto/rand" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestSingleMatch(t *testing.T) { + params := DefaultParams + params.deriveFields() + + for count := 0; count < 100000; count++ { + // generate a row with a single random entry + mapIndex := rand.Uint32() + lvIndex := uint64(mapIndex)< 0; i-- { + j := rand.Intn(i) + row[i], row[j] = row[j], row[i] + } + // split up into a list of rows if longer than allowed + var rows []FilterRow + for layerIndex := uint32(0); row != nil; layerIndex++ { + maxLen := int(params.maxRowLength(layerIndex)) + if len(row) > maxLen { + rows = append(rows, row[:maxLen]) + row = row[maxLen:] + } else { + rows = append(rows, row) + row = nil + } + } + // check retrieved matches while also counting false positives + for i, lvHash := range lvHashes { + matches := params.potentialMatches(rows, mapIndex, lvHash) + if i < testPmLen { + // check single entry match + if len(matches) < 1 { + t.Fatalf("Invalid length of matches (got %d, expected >=1)", len(matches)) + } + var found bool + for _, lvi := range matches { + if lvi == lvIndices[i] { + found = true + } else { + falsePositives++ + } + } + if !found { + t.Fatalf("Expected match not found (got %v, expected %d)", matches, lvIndices[i]) + } + } else { + // check "long series" match + if len(matches) < testPmLen { + t.Fatalf("Invalid length of matches (got %d, expected >=%d)", len(matches), testPmLen) + } + // since results are ordered, first testPmLen entries should always match exactly + for j := 0; j < testPmLen; j++ { + if matches[j] != lvStart+uint64(j) { + t.Fatalf("Incorrect match at index %d (got %d, expected %d)", j, matches[j], lvStart+uint64(j)) + } + } + // the rest are false positives + falsePositives += len(matches) - testPmLen + } + } + } + // Whenever looking for a certain log value hash, each entry in the row that + // was generated by another log value hash (a "foreign entry") has a + // valuesPerMap // 2^32 chance of yielding a false positive if the reverse + // transformed 32 bit integer is by random chance less than valuesPerMap and + // is therefore considered a potentially valid match. + // We have testPmLen unique hash entries and a testPmLen long series of entries + // for the same hash. For each of the testPmLen unique hash entries there are + // testPmLen*2-1 foreign entries while for the long series there are testPmLen + // foreign entries. This means that after performing all these filtering runs, + // we have processed 2*testPmLen^2 foreign entries, which given us an estimate + // of how many false positives to expect. + expFalse := int(uint64(testPmCount*testPmLen*testPmLen*2) * params.valuesPerMap >> params.logMapWidth) + if falsePositives < expFalse/2 || falsePositives > expFalse*3/2 { + t.Fatalf("False positive rate out of expected range (got %d, expected %d +-50%%)", falsePositives, expFalse) + } +} diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 4f2ef0a88..f679c3aeb 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -18,6 +18,8 @@ package rawdb import ( "bytes" + "encoding/binary" + "errors" "math/big" "github.com/ethereum/go-ethereum/common" @@ -179,3 +181,306 @@ func DeleteBloombits(db ethdb.Database, bit uint, from uint64, to uint64) { log.Crit("Failed to delete bloom bits", "err", it.Error()) } } + +// ReadFilterMapRow retrieves a filter map row at the given mapRowIndex +// (see filtermaps.mapRowIndex for the storage index encoding). +// Note that zero length rows are not stored in the database and therefore all +// non-existent entries are interpreted as empty rows and return no error. +// Also note that the mapRowIndex indexing scheme is the same as the one +// proposed in EIP-7745 for tree-hashing the filter map structure and for the +// same data proximity reasons it is also suitable for database representation. +// See also: +// https://eips.ethereum.org/EIPS/eip-7745#hash-tree-structure +func ReadFilterMapExtRow(db ethdb.KeyValueReader, mapRowIndex uint64, bitLength uint) ([]uint32, error) { + byteLength := int(bitLength) / 8 + if int(bitLength) != byteLength*8 { + panic("invalid bit length") + } + key := filterMapRowKey(mapRowIndex, false) + has, err := db.Has(key) + if err != nil { + return nil, err + } + if !has { + return nil, nil + } + encRow, err := db.Get(key) + if err != nil { + return nil, err + } + if len(encRow)%byteLength != 0 { + return nil, errors.New("Invalid encoded extended filter row length") + } + row := make([]uint32, len(encRow)/byteLength) + var b [4]byte + for i := range row { + copy(b[:byteLength], encRow[i*byteLength:(i+1)*byteLength]) + row[i] = binary.LittleEndian.Uint32(b[:]) + } + return row, nil +} + +func ReadFilterMapBaseRows(db ethdb.KeyValueReader, mapRowIndex uint64, rowCount uint32, bitLength uint) ([][]uint32, error) { + byteLength := int(bitLength) / 8 + if int(bitLength) != byteLength*8 { + panic("invalid bit length") + } + key := filterMapRowKey(mapRowIndex, true) + has, err := db.Has(key) + if err != nil { + return nil, err + } + rows := make([][]uint32, rowCount) + if !has { + return rows, nil + } + encRows, err := db.Get(key) + if err != nil { + return nil, err + } + encLen := len(encRows) + var ( + entryCount, entriesInRow, rowIndex, headerLen, headerBits int + headerByte byte + ) + for headerLen+byteLength*entryCount < encLen { + if headerBits == 0 { + headerByte = encRows[headerLen] + headerLen++ + headerBits = 8 + } + if headerByte&1 > 0 { + entriesInRow++ + entryCount++ + } else { + if entriesInRow > 0 { + rows[rowIndex] = make([]uint32, entriesInRow) + entriesInRow = 0 + } + rowIndex++ + } + headerByte >>= 1 + headerBits-- + } + if headerLen+byteLength*entryCount > encLen { + return nil, errors.New("Invalid encoded base filter rows length") + } + if entriesInRow > 0 { + rows[rowIndex] = make([]uint32, entriesInRow) + } + nextEntry := headerLen + for _, row := range rows { + for i := range row { + var b [4]byte + copy(b[:byteLength], encRows[nextEntry:nextEntry+byteLength]) + row[i] = binary.LittleEndian.Uint32(b[:]) + nextEntry += byteLength + } + } + return rows, nil +} + +// WriteFilterMapRow stores a filter map row at the given mapRowIndex or deletes +// any existing entry if the row is empty. +func WriteFilterMapExtRow(db ethdb.KeyValueWriter, mapRowIndex uint64, row []uint32, bitLength uint) { + byteLength := int(bitLength) / 8 + if int(bitLength) != byteLength*8 { + panic("invalid bit length") + } + var err error + if len(row) > 0 { + encRow := make([]byte, len(row)*byteLength) + for i, c := range row { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], c) + copy(encRow[i*byteLength:(i+1)*byteLength], b[:byteLength]) + } + err = db.Put(filterMapRowKey(mapRowIndex, false), encRow) + } else { + err = db.Delete(filterMapRowKey(mapRowIndex, false)) + } + if err != nil { + log.Crit("Failed to store extended filter map row", "err", err) + } +} + +func WriteFilterMapBaseRows(db ethdb.KeyValueWriter, mapRowIndex uint64, rows [][]uint32, bitLength uint) { + byteLength := int(bitLength) / 8 + if int(bitLength) != byteLength*8 { + panic("invalid bit length") + } + var entryCount, zeroBits int + for i, row := range rows { + if len(row) > 0 { + entryCount += len(row) + zeroBits = i + } + } + var err error + if entryCount > 0 { + headerLen := (zeroBits + entryCount + 7) / 8 + encRows := make([]byte, headerLen+entryCount*byteLength) + nextEntry := headerLen + + headerPtr, headerByte := 0, byte(1) + addHeaderBit := func(bit bool) { + if bit { + encRows[headerPtr] += headerByte + } + if headerByte += headerByte; headerByte == 0 { + headerPtr++ + headerByte = 1 + } + } + + for _, row := range rows { + for _, entry := range row { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], entry) + copy(encRows[nextEntry:nextEntry+byteLength], b[:byteLength]) + nextEntry += byteLength + addHeaderBit(true) + } + if zeroBits == 0 { + break + } + addHeaderBit(false) + zeroBits-- + } + err = db.Put(filterMapRowKey(mapRowIndex, true), encRows) + } else { + err = db.Delete(filterMapRowKey(mapRowIndex, true)) + } + if err != nil { + log.Crit("Failed to store base filter map rows", "err", err) + } +} + +func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, firstMapRowIndex, afterLastMapRowIndex uint64) { + if err := db.DeleteRange(filterMapRowKey(firstMapRowIndex, false), filterMapRowKey(afterLastMapRowIndex, false)); err != nil { + log.Crit("Failed to delete range of filter map rows", "err", err) + } +} + +// ReadFilterMapLastBlock retrieves the number of the block that generated the +// last log value entry of the given map. +func ReadFilterMapLastBlock(db ethdb.KeyValueReader, mapIndex uint32) (uint64, common.Hash, error) { + enc, err := db.Get(filterMapLastBlockKey(mapIndex)) + if err != nil { + return 0, common.Hash{}, err + } + if len(enc) != 40 { + return 0, common.Hash{}, errors.New("Invalid block number and id encoding") + } + var id common.Hash + copy(id[:], enc[8:]) + return binary.BigEndian.Uint64(enc[:8]), id, nil +} + +// WriteFilterMapLastBlock stores the number of the block that generated the +// last log value entry of the given map. +func WriteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32, blockNumber uint64, id common.Hash) { + var enc [40]byte + binary.BigEndian.PutUint64(enc[:8], blockNumber) + copy(enc[8:], id[:]) + if err := db.Put(filterMapLastBlockKey(mapIndex), enc[:]); err != nil { + log.Crit("Failed to store filter map last block pointer", "err", err) + } +} + +// DeleteFilterMapLastBlock deletes the number of the block that generated the +// last log value entry of the given map. +func DeleteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32) { + if err := db.Delete(filterMapLastBlockKey(mapIndex)); err != nil { + log.Crit("Failed to delete filter map last block pointer", "err", err) + } +} + +func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, firstMapIndex, afterLastMapIndex uint32) { + if err := db.DeleteRange(filterMapLastBlockKey(firstMapIndex), filterMapLastBlockKey(afterLastMapIndex)); err != nil { + log.Crit("Failed to delete range of filter map last block pointers", "err", err) + } +} + +// ReadBlockLvPointer retrieves the starting log value index where the log values +// generated by the given block are located. +func ReadBlockLvPointer(db ethdb.KeyValueReader, blockNumber uint64) (uint64, error) { + encPtr, err := db.Get(filterMapBlockLVKey(blockNumber)) + if err != nil { + return 0, err + } + if len(encPtr) != 8 { + return 0, errors.New("Invalid log value pointer encoding") + } + return binary.BigEndian.Uint64(encPtr), nil +} + +// WriteBlockLvPointer stores the starting log value index where the log values +// generated by the given block are located. +func WriteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber, lvPointer uint64) { + var encPtr [8]byte + binary.BigEndian.PutUint64(encPtr[:], lvPointer) + if err := db.Put(filterMapBlockLVKey(blockNumber), encPtr[:]); err != nil { + log.Crit("Failed to store block log value pointer", "err", err) + } +} + +// DeleteBlockLvPointer deletes the starting log value index where the log values +// generated by the given block are located. +func DeleteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber uint64) { + if err := db.Delete(filterMapBlockLVKey(blockNumber)); err != nil { + log.Crit("Failed to delete block log value pointer", "err", err) + } +} + +func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, firstBlockNumber, afterLastBlockNumber uint64) { + if err := db.DeleteRange(filterMapBlockLVKey(firstBlockNumber), filterMapBlockLVKey(afterLastBlockNumber)); err != nil { + log.Crit("Failed to delete range of block log value pointers", "err", err) + } +} + +// FilterMapsRange is a storage representation of the block range covered by the +// filter maps structure and the corresponting log value index range. +type FilterMapsRange struct { + HeadBlockIndexed bool + HeadBlockDelimiter uint64 + FirstIndexedBlock, AfterLastIndexedBlock uint64 + FirstRenderedMap, AfterLastRenderedMap, TailPartialEpoch uint32 +} + +// ReadFilterMapsRange retrieves the filter maps range data. Note that if the +// database entry is not present, that is interpreted as a valid non-initialized +// state and returns a blank range structure and no error. +func ReadFilterMapsRange(db ethdb.KeyValueReader) (FilterMapsRange, bool, error) { + if has, err := db.Has(filterMapsRangeKey); !has || err != nil { + return FilterMapsRange{}, false, err + } + encRange, err := db.Get(filterMapsRangeKey) + if err != nil { + return FilterMapsRange{}, false, err + } + var fmRange FilterMapsRange + if err := rlp.DecodeBytes(encRange, &fmRange); err != nil { + return FilterMapsRange{}, false, err + } + return fmRange, true, err +} + +// WriteFilterMapsRange stores the filter maps range data. +func WriteFilterMapsRange(db ethdb.KeyValueWriter, fmRange FilterMapsRange) { + encRange, err := rlp.EncodeToBytes(&fmRange) + if err != nil { + log.Crit("Failed to encode filter maps range", "err", err) + } + if err := db.Put(filterMapsRangeKey, encRange); err != nil { + log.Crit("Failed to store filter maps range", "err", err) + } +} + +// DeleteFilterMapsRange deletes the filter maps range data which is interpreted +// as reverting to the un-initialized state. +func DeleteFilterMapsRange(db ethdb.KeyValueWriter) { + if err := db.Delete(filterMapsRangeKey); err != nil { + log.Crit("Failed to delete filter maps range", "err", err) + } +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 53418d164..6b52668bc 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -376,6 +376,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { storageSnaps stat preimages stat bloomBits stat + filterMaps stat beaconHeaders stat cliqueSnaps stat @@ -440,6 +441,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bloomBits.Add(size) case bytes.HasPrefix(key, BloomBitsIndexPrefix): bloomBits.Add(size) + case bytes.HasPrefix(key, []byte(FilterMapsPrefix)): + filterMaps.Add(size) case bytes.HasPrefix(key, skeletonHeaderPrefix) && len(key) == (len(skeletonHeaderPrefix)+8): beaconHeaders.Add(size) case bytes.HasPrefix(key, CliqueSnapshotPrefix) && len(key) == 7+common.HashLength: @@ -505,6 +508,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Block hash->number", hashNumPairings.Size(), hashNumPairings.Count()}, {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, + {"Key-Value store", "Log search index", filterMaps.Size(), filterMaps.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, {"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()}, {"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 17aa9e280..177f4a67f 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -145,6 +145,12 @@ var ( FixedCommitteeRootKey = []byte("fixedRoot-") // bigEndian64(syncPeriod) -> committee root hash SyncCommitteeKey = []byte("committee-") // bigEndian64(syncPeriod) -> serialized committee + FilterMapsPrefix = "fm-" + filterMapsRangeKey = []byte(FilterMapsPrefix + "R") + filterMapRowPrefix = []byte(FilterMapsPrefix + "r") // filterMapRowPrefix + mapRowIndex (uint64 big endian) -> filter row + filterMapLastBlockPrefix = []byte(FilterMapsPrefix + "b") // filterMapLastBlockPrefix + mapIndex (uint32 big endian) -> block number (uint64 big endian) + filterMapBlockLVPrefix = []byte(FilterMapsPrefix + "p") // filterMapBlockLVPrefix + num (uint64 big endian) -> log value pointer (uint64 big endian) + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) @@ -347,3 +353,34 @@ func IsStorageTrieNode(key []byte) bool { ok, _, _ := ResolveStorageTrieNode(key) return ok } + +// filterMapRowKey = filterMapRowPrefix + mapRowIndex (uint64 big endian) +func filterMapRowKey(mapRowIndex uint64, base bool) []byte { + extLen := 8 + if base { + extLen = 9 + } + l := len(filterMapRowPrefix) + key := make([]byte, l+extLen) + copy(key[:l], filterMapRowPrefix) + binary.BigEndian.PutUint64(key[l:l+8], mapRowIndex) + return key +} + +// filterMapLastBlockKey = filterMapLastBlockPrefix + mapIndex (uint32 big endian) +func filterMapLastBlockKey(mapIndex uint32) []byte { + l := len(filterMapLastBlockPrefix) + key := make([]byte, l+4) + copy(key[:l], filterMapLastBlockPrefix) + binary.BigEndian.PutUint32(key[l:], mapIndex) + return key +} + +// filterMapBlockLVKey = filterMapBlockLVPrefix + num (uint64 big endian) +func filterMapBlockLVKey(number uint64) []byte { + l := len(filterMapBlockLVPrefix) + key := make([]byte, l+8) + copy(key[:l], filterMapBlockLVPrefix) + binary.BigEndian.PutUint64(key[l:], number) + return key +} From 7e2a1d57ee5060a8402c9b82b06cbe5e334d6354 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 14 Mar 2025 15:27:38 +0100 Subject: [PATCH 203/354] accounts/abi: improve unpack performance (#31387) Slightly improves performance of abi.Unpack ``` Before BenchmarkUnpack/0-14 5965714 210.9 ns/op 280 B/op 5 allocs/op BenchmarkUnpack/1-14 2148283 569.7 ns/op 688 B/op 16 allocs/op After: BenchmarkUnpack/0-14 7693365 151.2 ns/op 136 B/op 4 allocs/op BenchmarkUnpack/1-14 2261294 508.9 ns/op 544 B/op 15 allocs/op ``` replaces https://github.com/ethereum/go-ethereum/pull/31292 since I was unable to push to your branch @Exca-DK --------- Co-authored-by: Exca-DK --- accounts/abi/argument.go | 33 ++++++++++++++++++------------ accounts/abi/unpack_test.go | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 227a088b7..e48f76389 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -77,18 +77,18 @@ func (arguments Arguments) isTuple() bool { } // Unpack performs the operation hexdata -> Go format. -func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) { +func (arguments Arguments) Unpack(data []byte) ([]any, error) { if len(data) == 0 { if len(arguments.NonIndexed()) != 0 { return nil, errors.New("abi: attempting to unmarshal an empty string while arguments are expected") } - return make([]interface{}, 0), nil + return make([]any, 0), nil } return arguments.UnpackValues(data) } // UnpackIntoMap performs the operation hexdata -> mapping of argument name to argument value. -func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error { +func (arguments Arguments) UnpackIntoMap(v map[string]any, data []byte) error { // Make sure map is not nil if v == nil { return errors.New("abi: cannot unpack into a nil map") @@ -110,7 +110,7 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) } // Copy performs the operation go format -> provided struct. -func (arguments Arguments) Copy(v interface{}, values []interface{}) error { +func (arguments Arguments) Copy(v any, values []any) error { // make sure the passed value is arguments pointer if reflect.Ptr != reflect.ValueOf(v).Kind() { return fmt.Errorf("abi: Unpack(non-pointer %T)", v) @@ -128,7 +128,7 @@ func (arguments Arguments) Copy(v interface{}, values []interface{}) error { } // copyAtomic copies ( hexdata -> go ) a single value -func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{}) error { +func (arguments Arguments) copyAtomic(v any, marshalledValues any) error { dst := reflect.ValueOf(v).Elem() src := reflect.ValueOf(marshalledValues) @@ -139,7 +139,7 @@ func (arguments Arguments) copyAtomic(v interface{}, marshalledValues interface{ } // copyTuple copies a batch of values from marshalledValues to v. -func (arguments Arguments) copyTuple(v interface{}, marshalledValues []interface{}) error { +func (arguments Arguments) copyTuple(v any, marshalledValues []any) error { value := reflect.ValueOf(v).Elem() nonIndexedArgs := arguments.NonIndexed() @@ -181,11 +181,17 @@ func (arguments Arguments) copyTuple(v interface{}, marshalledValues []interface // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, // without supplying a struct to unpack into. Instead, this method returns a list containing the // values. An atomic argument will be a list with one element. -func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { - nonIndexedArgs := arguments.NonIndexed() - retval := make([]interface{}, 0, len(nonIndexedArgs)) - virtualArgs := 0 - for index, arg := range nonIndexedArgs { +func (arguments Arguments) UnpackValues(data []byte) ([]any, error) { + var ( + retval = make([]any, 0) + virtualArgs = 0 + index = 0 + ) + + for _, arg := range arguments { + if arg.Indexed { + continue + } marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) if err != nil { return nil, err @@ -208,18 +214,19 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { virtualArgs += getTypeSize(arg.Type)/32 - 1 } retval = append(retval, marshalledValue) + index++ } return retval, nil } // PackValues performs the operation Go format -> Hexdata. // It is the semantic opposite of UnpackValues. -func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) { +func (arguments Arguments) PackValues(args []any) ([]byte, error) { return arguments.Pack(args...) } // Pack performs the operation Go format -> Hexdata. -func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { +func (arguments Arguments) Pack(args ...any) ([]byte, error) { // Make sure arguments match up and pack them abiArgs := arguments if len(args) != len(abiArgs) { diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 7df7b9c40..74db298b3 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -31,6 +31,46 @@ import ( "github.com/stretchr/testify/require" ) +func BenchmarkUnpack(b *testing.B) { + testCases := []struct { + def string + packed string + }{ + { + def: `[{"type": "uint32"}]`, + packed: "0000000000000000000000000000000000000000000000000000000000000001", + }, + { + def: `[{"type": "uint32[]"}]`, + packed: "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002", + }, + } + for i, test := range testCases { + b.Run(strconv.Itoa(i), func(b *testing.B) { + def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def) + abi, err := JSON(strings.NewReader(def)) + if err != nil { + b.Fatalf("invalid ABI definition %s: %v", def, err) + } + encb, err := hex.DecodeString(test.packed) + if err != nil { + b.Fatalf("invalid hex %s: %v", test.packed, err) + } + + b.ResetTimer() + + var result any + for range b.N { + result, _ = abi.Unpack("method", encb) + } + _ = result + }) + } +} + // TestUnpack tests the general pack/unpack tests in packing_test.go func TestUnpack(t *testing.T) { t.Parallel() From 7a4f698e213ac9c1b5086ef165d722214f19319a Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Fri, 14 Mar 2025 11:56:53 -0400 Subject: [PATCH 204/354] log: fix SetDefault for custom loggers (#31368) Currently, even though it takes in a `Logger` interface, `log.SetDefualt` enforces that the concrete type of the provided logger is `*logger` because: 1. in `init` `root.Store` is called with a `*logger` 2. `atomic.Value` panics if the concrete type provided in `Store` is not consistent across calls. ([ref](https://pkg.go.dev/sync/atomic#Value.Store)) > All calls to Store for a given Value must use values of the same concrete type. This PR changes to use `sync.RWMutex` and adds a test that panics on `master`. --- log/root.go | 19 ++++++++++++++----- log/root_test.go | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 log/root_test.go diff --git a/log/root.go b/log/root.go index 91209c46a..c09a36b11 100644 --- a/log/root.go +++ b/log/root.go @@ -3,18 +3,24 @@ package log import ( "log/slog" "os" - "sync/atomic" + "sync" ) -var root atomic.Value +var ( + rootLock sync.RWMutex + root Logger +) func init() { - root.Store(&logger{slog.New(DiscardHandler())}) + root = &logger{slog.New(DiscardHandler())} } // SetDefault sets the default global logger func SetDefault(l Logger) { - root.Store(l) + rootLock.Lock() + defer rootLock.Unlock() + + root = l if lg, ok := l.(*logger); ok { slog.SetDefault(lg.inner) } @@ -22,7 +28,10 @@ func SetDefault(l Logger) { // Root returns the root logger func Root() Logger { - return root.Load().(Logger) + rootLock.RLock() + defer rootLock.RUnlock() + + return root } // The following functions bypass the exported logger methods (logger.Debug, diff --git a/log/root_test.go b/log/root_test.go new file mode 100644 index 000000000..b9b22af66 --- /dev/null +++ b/log/root_test.go @@ -0,0 +1,19 @@ +package log + +import ( + "testing" +) + +// SetDefault should properly set the default logger when custom loggers are +// provided. +func TestSetDefaultCustomLogger(t *testing.T) { + type customLogger struct { + Logger // Implement the Logger interface + } + + customLog := &customLogger{} + SetDefault(customLog) + if Root() != customLog { + t.Error("expected custom logger to be set as default") + } +} From 2c193392cdf620675183f573454aca6f2124b9ec Mon Sep 17 00:00:00 2001 From: danceratopz Date: Fri, 14 Mar 2025 17:56:24 +0100 Subject: [PATCH 205/354] cmd/evm: fix statetest with multi-fork statetest fixtures (#31374) Fixes `evm statetest` for state test fixtures with multiple fork entries in their `post` field (e.g., [chainId.json](https://github.com/ethereum/tests/blob/81862e4848585a438d64f911a19b3825f0f4cd95/GeneralStateTests/stChainId/chainId.json#L39)). When these re-activated flags aren't exposed, `statetest` only executes the fixture for a single fork entry instead of all of the forks as expected. This only affects ethereum/tests state test fixtures, not ethereum/execution-spec-tests (EEST) state tests. EEST writes a separate fixture/test case (i.e. a separate top-level dict entry in the .json) for each fork configuration as apposed to combining multiple forks in one fixture test case: New EEST state tests targeting Prague behavior are not affected. --- cmd/evm/staterunner.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 8f81a9531..1b0eb2ca2 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -53,7 +53,9 @@ var stateTestCommand = &cli.Command{ Flags: slices.Concat([]cli.Flag{ BenchFlag, DumpFlag, + forkFlag, HumanReadableFlag, + idxFlag, RunFlag, }, traceFlags), } From 962cd63bacd938e60ace5c5be7ede0d98d9774db Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 14 Mar 2025 18:53:05 +0100 Subject: [PATCH 206/354] tests: update ethereum/tests to v17.0 (#31381) Get the re-filled tests (plus removal of outdated EIP-2537 tests) --- tests/block_test.go | 3 ++ tests/state_test.go | 9 ---- tests/testdata | 2 +- tests/transaction_test.go | 7 +-- tests/transaction_test_util.go | 88 ++++++++++++++++++++-------------- 5 files changed, 57 insertions(+), 52 deletions(-) diff --git a/tests/block_test.go b/tests/block_test.go index 15806b3ef..f146e4ee6 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -63,6 +63,9 @@ func TestBlockchain(t *testing.T) { // With chain history removal, TDs become unavailable, this transition tests based on TTD are unrunnable bt.skipLoad(`.*bcArrowGlacierToParis/powToPosBlockRejection.json`) + // This directory contains no test. + bt.skipLoad(`.*\.meta/.*`) + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { execBlockTest(t, bt, test) }) diff --git a/tests/state_test.go b/tests/state_test.go index e7525118e..301bc3a7a 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -54,18 +54,9 @@ func initMatcher(st *testMatcher) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) - // Out-of-date EIP-2537 tests - // TODO (@s1na) reenable in the future - st.skipLoad(`^stEIP2537/`) - // Broken tests: // EOF is not part of cancun st.skipLoad(`^stEOF/`) - - // The tests under Pyspecs are the ones that are published as execution-spec tests. - // We run these tests separately, no need to _also_ run them as part of the - // reference tests. - st.skipLoad(`^Pyspecs/`) } func TestState(t *testing.T) { diff --git a/tests/testdata b/tests/testdata index faf33b471..81862e484 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 +Subproject commit 81862e4848585a438d64f911a19b3825f0f4cd95 diff --git a/tests/transaction_test.go b/tests/transaction_test.go index 814717390..6260df0f3 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -20,7 +20,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/params" ) func TestTransaction(t *testing.T) { @@ -58,8 +57,7 @@ func TestTransaction(t *testing.T) { txt.skipLoad("^ttEIP1559/GasLimitPriceProductOverflow.json") txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { - cfg := params.MainnetChainConfig - if err := txt.checkFailure(t, test.Run(cfg)); err != nil { + if err := txt.checkFailure(t, test.Run()); err != nil { t.Error(err) } }) @@ -75,8 +73,7 @@ func TestExecutionSpecTransaction(t *testing.T) { st.skipLoad("^prague/eip7702_set_code_tx/invalid_tx/empty_authorization_list.json") st.walk(t, executionSpecTransactionTestDir, func(t *testing.T, name string, test *TransactionTest) { - cfg := params.MainnetChainConfig - if err := st.checkFailure(t, test.Run(cfg)); err != nil { + if err := st.checkFailure(t, test.Run()); err != nil { t.Error(err) } }) diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 3f91a82ec..b2efabe82 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -18,6 +18,7 @@ package tests import ( "fmt" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -65,11 +66,11 @@ func (tt *TransactionTest) validateFork(fork *ttFork) error { return nil } -func (tt *TransactionTest) Run(config *params.ChainConfig) error { +func (tt *TransactionTest) Run() error { if err := tt.validate(); err != nil { return err } - validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead, isIstanbul, isShanghai bool) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { + validateTx := func(rlpData hexutil.Bytes, signer types.Signer, rules *params.Rules) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { tx := new(types.Transaction) if err = tx.UnmarshalBinary(rlpData); err != nil { return @@ -79,62 +80,75 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return } // Intrinsic gas - requiredGas, err = core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, isShanghai) + requiredGas, err = core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return } if requiredGas > tx.Gas() { return sender, hash, 0, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) } + + if rules.IsPrague { + var floorDataGas uint64 + floorDataGas, err = core.FloorDataGas(tx.Data()) + if err != nil { + return + } + if tx.Gas() < floorDataGas { + return sender, hash, 0, fmt.Errorf("%w: have %d, want %d", core.ErrFloorDataGas, tx.Gas(), floorDataGas) + } + } hash = tx.Hash() return sender, hash, requiredGas, nil } for _, testcase := range []struct { - name string - signer types.Signer - fork *ttFork - isHomestead bool - isIstanbul bool - isShanghai bool + name string + isMerge bool }{ - {"Frontier", types.FrontierSigner{}, tt.Result["Frontier"], false, false, false}, - {"Homestead", types.HomesteadSigner{}, tt.Result["Homestead"], true, false, false}, - {"EIP150", types.HomesteadSigner{}, tt.Result["EIP150"], true, false, false}, - {"EIP158", types.NewEIP155Signer(config.ChainID), tt.Result["EIP158"], true, false, false}, - {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Result["Byzantium"], true, false, false}, - {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Result["Constantinople"], true, false, false}, - {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Result["Istanbul"], true, true, false}, - {"Berlin", types.NewEIP2930Signer(config.ChainID), tt.Result["Berlin"], true, true, false}, - {"London", types.NewLondonSigner(config.ChainID), tt.Result["London"], true, true, false}, - {"Paris", types.NewLondonSigner(config.ChainID), tt.Result["Paris"], true, true, false}, - {"Shanghai", types.NewLondonSigner(config.ChainID), tt.Result["Shanghai"], true, true, true}, - {"Cancun", types.NewCancunSigner(config.ChainID), tt.Result["Cancun"], true, true, true}, - {"Prague", types.NewPragueSigner(config.ChainID), tt.Result["Prague"], true, true, true}, + {"Frontier", false}, + {"Homestead", false}, + {"EIP150", false}, + {"EIP158", false}, + {"Byzantium", false}, + {"Constantinople", false}, + {"Istanbul", false}, + {"Berlin", false}, + {"London", false}, + {"Paris", true}, + {"Shanghai", true}, + {"Cancun", true}, + {"Prague", true}, } { - if testcase.fork == nil { + expected := tt.Result[testcase.name] + if expected == nil { continue } - sender, hash, gas, err := validateTx(tt.Txbytes, testcase.signer, testcase.isHomestead, testcase.isIstanbul, testcase.isShanghai) + config, ok := Forks[testcase.name] + if !ok || config == nil { + return UnsupportedForkError{Name: testcase.name} + } + var ( + rules = config.Rules(new(big.Int), testcase.isMerge, 0) + signer = types.MakeSigner(config, new(big.Int), 0) + ) + sender, hash, gas, err := validateTx(tt.Txbytes, signer, &rules) if err != nil { - if testcase.fork.Hash != nil { - return fmt.Errorf("unexpected error: %v", err) + if expected.Hash != nil { + return fmt.Errorf("unexpected error fork %s: %v", testcase.name, err) } continue } - if testcase.fork.Exception != nil { - return fmt.Errorf("expected error %v, got none (%v)", *testcase.fork.Exception, err) - } - if common.Hash(*testcase.fork.Hash) != hash { - return fmt.Errorf("hash mismatch: got %x, want %x", hash, common.Hash(*testcase.fork.Hash)) + if expected.Exception != nil { + return fmt.Errorf("expected error %v, got none (%v), fork %s", *expected.Exception, err, testcase.name) } - if common.Address(*testcase.fork.Sender) != sender { - return fmt.Errorf("sender mismatch: got %x, want %x", sender, testcase.fork.Sender) + if common.Hash(*expected.Hash) != hash { + return fmt.Errorf("hash mismatch: got %x, want %x", hash, common.Hash(*expected.Hash)) } - if hash != common.Hash(*testcase.fork.Hash) { - return fmt.Errorf("hash mismatch: got %x, want %x", hash, testcase.fork.Hash) + if common.Address(*expected.Sender) != sender { + return fmt.Errorf("sender mismatch: got %x, want %x", sender, expected.Sender) } - if uint64(testcase.fork.IntrinsicGas) != gas { - return fmt.Errorf("intrinsic gas mismatch: got %d, want %d", gas, uint64(testcase.fork.IntrinsicGas)) + if uint64(expected.IntrinsicGas) != gas { + return fmt.Errorf("intrinsic gas mismatch: got %d, want %d", gas, uint64(expected.IntrinsicGas)) } } return nil From dca8100b7c57ff9091b0a76954e431f943158e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladimir=20T=C3=A1mara=20Pati=C3=B1o?= Date: Sat, 15 Mar 2025 13:35:10 -0400 Subject: [PATCH 207/354] cmd/utils: fix geth test issue on OpenBSD (#31357) --- cmd/utils/cmd.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 13b20b518..40116beb5 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -62,8 +62,8 @@ var ErrImportInterrupted = errors.New("interrupted") // is redirected to a different file. func Fatalf(format string, args ...interface{}) { w := io.MultiWriter(os.Stdout, os.Stderr) - if runtime.GOOS == "windows" { - // The SameFile check below doesn't work on Windows. + if runtime.GOOS == "windows" || runtime.GOOS == "openbsd" { + // The SameFile check below doesn't work on Windows neither OpenBSD. // stdout is unlikely to get redirected though, so just print there. w = os.Stdout } else { From 4f1afc9fa44ddd290cfb2488c916283006403645 Mon Sep 17 00:00:00 2001 From: Mike Weyandt Date: Sun, 16 Mar 2025 21:48:08 -0400 Subject: [PATCH 208/354] metrics: spin up meter ticker routine when enabling metric system (#31400) Addresses https://github.com/ethereum/go-ethereum/issues/31244 --- metrics/meter.go | 17 +++++++++-------- metrics/metrics.go | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/metrics/meter.go b/metrics/meter.go index 194bd1f30..197e5abbe 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -131,19 +131,15 @@ var arbiter = meterTicker{meters: make(map[*Meter]struct{})} type meterTicker struct { mu sync.RWMutex - started bool - meters map[*Meter]struct{} + once sync.Once + meters map[*Meter]struct{} } -// add adds another *Meter ot the arbiter, and starts the arbiter ticker. +// add a *Meter to the arbiter func (ma *meterTicker) add(m *Meter) { ma.mu.Lock() defer ma.mu.Unlock() ma.meters[m] = struct{}{} - if !ma.started { - ma.started = true - go ma.loop() - } } // remove removes a meter from the set of ticked meters. @@ -153,7 +149,7 @@ func (ma *meterTicker) remove(m *Meter) { ma.mu.Unlock() } -// loop ticks meters on a 5 second interval. +// loop ticks meters on a 5-second interval. func (ma *meterTicker) loop() { ticker := time.NewTicker(5 * time.Second) for range ticker.C { @@ -167,3 +163,8 @@ func (ma *meterTicker) loop() { ma.mu.RUnlock() } } + +// startMeterTickerLoop will start the arbiter ticker. +func startMeterTickerLoop() { + arbiter.once.Do(func() { go arbiter.loop() }) +} diff --git a/metrics/metrics.go b/metrics/metrics.go index c4c43b757..088948d40 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -30,6 +30,7 @@ func Enabled() bool { // the program, before any metrics collection will happen. func Enable() { metricsEnabled = true + startMeterTickerLoop() } var threadCreateProfile = pprof.Lookup("threadcreate") From c3a64dddd15abebd726f8e5a0150d57207d18650 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 17 Mar 2025 14:13:12 +0800 Subject: [PATCH 209/354] eth/catalyst: fix flaky test (#31403) This pull request enhances the unit test, avoiding unnecessary failure in CI. ``` --- FAIL: TestSimulatedBeaconSendWithdrawals (12.08s) simulated_beacon_test.go:139: timed out without including all withdrawals/txs FAIL ``` --- eth/catalyst/simulated_beacon_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index 1c65bbe30..493675d7c 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -121,7 +121,7 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { includedTxs := make(map[common.Hash]struct{}) var includedWithdrawals []uint64 - timer := time.NewTimer(12 * time.Second) + timer := time.NewTimer(30 * time.Second) for { select { case ev := <-chainHeadCh: @@ -132,8 +132,8 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) { for _, includedWithdrawal := range block.Withdrawals() { includedWithdrawals = append(includedWithdrawals, includedWithdrawal.Index) } - // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10 - if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) && ev.Header.Number.Cmp(big.NewInt(2)) == 0 { + // ensure all withdrawals/txs included. this will at least take two blocks b/c number of withdrawals > 10 + if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) { return } case <-timer.C: From 7c3a485f677bfb1e740bb8752843a0cfb1f69c52 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Mon, 17 Mar 2025 16:32:44 +0800 Subject: [PATCH 210/354] eth/catalyst: set FeeRecipient in dev mode (#31316) this adds 2 features to improve `geth --dev` experience. 1. we don't need to use `dev_SetFeeRecipient` to set initial coinbase address. it was a pain. 2. we don't need to unlock keystore if we don't use it. we had it because of clique. --- cmd/geth/config.go | 2 +- cmd/utils/flags.go | 7 +++++-- eth/catalyst/simulated_beacon.go | 3 ++- eth/catalyst/simulated_beacon_test.go | 2 +- ethclient/simulated/backend.go | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 0d8b6f03c..bfd164c40 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -234,7 +234,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if ctx.IsSet(utils.DeveloperFlag.Name) { // Start dev mode. - simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth) + simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), cfg.Eth.Miner.Etherbase, eth) if err != nil { utils.Fatalf("failed to register dev mode catalyst service: %v", err) } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 425762e94..fe1caa60f 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1929,8 +1929,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // the miner will fail to start. cfg.Miner.Etherbase = developer.Address - if err := ks.Unlock(developer, passphrase); err != nil { - Fatalf("Failed to unlock developer account: %v", err) + // try to unlock the first keystore account + if len(ks.Accounts()) > 0 { + if err := ks.Unlock(developer, passphrase); err != nil { + Fatalf("Failed to unlock developer account: %v", err) + } } log.Info("Using developer account", "address", developer.Address) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index c71add93b..dd9d8f906 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -108,7 +108,7 @@ func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersi } // NewSimulatedBeacon constructs a new simulated beacon chain. -func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) { +func NewSimulatedBeacon(period uint64, feeRecipient common.Address, eth *eth.Ethereum) (*SimulatedBeacon, error) { block := eth.BlockChain().CurrentBlock() current := engine.ForkchoiceStateV1{ HeadBlockHash: block.Hash(), @@ -131,6 +131,7 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err engineAPI: engineAPI, lastBlockTime: block.Time, curForkchoiceState: current, + feeRecipient: feeRecipient, }, nil } diff --git a/eth/catalyst/simulated_beacon_test.go b/eth/catalyst/simulated_beacon_test.go index 493675d7c..f6b7923d0 100644 --- a/eth/catalyst/simulated_beacon_test.go +++ b/eth/catalyst/simulated_beacon_test.go @@ -56,7 +56,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis, period t.Fatal("can't create eth service:", err) } - simBeacon, err := NewSimulatedBeacon(period, ethservice) + simBeacon, err := NewSimulatedBeacon(period, common.Address{}, ethservice) if err != nil { t.Fatal("can't create simulated beacon:", err) } diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go index 6e07aa68d..2a4aa4f2d 100644 --- a/ethclient/simulated/backend.go +++ b/ethclient/simulated/backend.go @@ -121,7 +121,7 @@ func newWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Backe return nil, err } // Set up the simulated beacon - beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, backend) + beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, common.Address{}, backend) if err != nil { return nil, err } From 65c2661e94611dc712969c4b22b7005af3d03f7b Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 17 Mar 2025 15:56:55 +0100 Subject: [PATCH 211/354] cmd/abigen, accounts/abi/bind: implement abigen version 2 (#31379) This PR implements a new version of the abigen utility (v2) which exists along with the pre-existing v1 version. Abigen is a utility command provided by go-ethereum that, given a solidity contract ABI definition, will generate Go code to transact/call the contract methods, converting the method parameters/results and structures defined in the contract into corresponding Go types. This is useful for preventing the need to write custom boilerplate code for contract interactions. Methods in the generated bindings perform encoding between Go types and Solidity ABI-encoded packed bytecode, as well as some action (e.g. `eth_call` or creating and submitting a transaction). This limits the flexibility of how the generated bindings can be used, and prevents easily adding new functionality, as it will make the generated bindings larger for each feature added. Abigen v2 was conceived of by the observation that the only functionality that generated Go bindings ought to perform is conversion between Go types and ABI-encoded packed data. Go-ethereum already provides various APIs which in conjunction with conversion methods generated in v2 bindings can cover all functionality currently provided by v1, and facilitate all other previously-desired use-cases. To generate contract bindings using abigen v2, invoke the `abigen` command with the `--v2` flag. The functionality of all other flags is preserved between the v2 and v1 versions. The execution of `abigen --v2` generates Go code containing methods which convert between Go types and corresponding ABI-encoded data expected by the contract. For each input-accepting contract method and the constructor, a "packing" method is generated in the binding which converts from Go types to the corresponding packed solidity expected by the contract. If a method returns output, an "unpacking" method is generated to convert this output from ABI-encoded data to the corresponding Go types. For contracts which emit events, an unpacking method is defined for each event to unpack the corresponding raw log to the Go type that it represents. Likewise, where custom errors are defined by contracts, an unpack method is generated to unpack raw error data into a Go type. For a smooth user-experience, abigen v2 comes with a number of utility functions to be used in conjunction with the generated bindings for performing common contract interaction use-cases. These include: * filtering for historical logs of a given topic * watching the chain for emission of logs with a given topic * contract deployment methods * Call/Transact methods https://geth.ethereum.org will be updated to include a new tutorial page for abigen v2 with full code examples. The page currently exists in a PR: https://github.com/ethereum/go-ethereum/pull/31390 . There are also extensive examples of interactions with contract bindings in [test cases](https://github.com/ethereum/go-ethereum/blob/cc855c7ede460270ae9c83bba278b23cb4f26a00/accounts/abi/bind/v2/lib_test.go) provided with this PR. --------- Co-authored-by: Sina Mahmoodi Co-authored-by: Felix Lange --- accounts/abi/{bind => abigen}/bind.go | 141 ++-- accounts/abi/{bind => abigen}/bind_test.go | 14 +- accounts/abi/abigen/bindv2.go | 373 ++++++++++ accounts/abi/abigen/bindv2_test.go | 342 +++++++++ accounts/abi/{bind => abigen}/source.go.tpl | 0 accounts/abi/abigen/source2.go.tpl | 238 +++++++ accounts/abi/{bind => abigen}/template.go | 67 +- .../abigen/testdata/v2/callbackparam.go.txt | 64 ++ .../abi/abigen/testdata/v2/crowdsale.go.txt | 304 ++++++++ accounts/abi/abigen/testdata/v2/dao.go.txt | 655 ++++++++++++++++++ .../testdata/v2/deeplynestedarray.go.txt | 114 +++ accounts/abi/abigen/testdata/v2/empty.go.txt | 52 ++ .../abigen/testdata/v2/eventchecker.go.txt | 261 +++++++ accounts/abi/abigen/testdata/v2/getter.go.txt | 89 +++ .../testdata/v2/identifiercollision.go.txt | 102 +++ .../abigen/testdata/v2/inputchecker.go.txt | 123 ++++ .../abi/abigen/testdata/v2/interactor.go.txt | 126 ++++ .../abigen/testdata/v2/nameconflict.go.txt | 137 ++++ .../testdata/v2/numericmethodname.go.txt | 129 ++++ .../abigen/testdata/v2/outputchecker.go.txt | 253 +++++++ .../abi/abigen/testdata/v2/overload.go.txt | 159 +++++ .../abigen/testdata/v2/rangekeyword.go.txt | 64 ++ accounts/abi/abigen/testdata/v2/slicer.go.txt | 152 ++++ .../abi/abigen/testdata/v2/structs-abi.go.txt | 116 ++++ .../abi/abigen/testdata/v2/structs.go.txt | 119 ++++ accounts/abi/abigen/testdata/v2/token.go.txt | 319 +++++++++ accounts/abi/abigen/testdata/v2/tuple.go.txt | 228 ++++++ accounts/abi/abigen/testdata/v2/tupler.go.txt | 89 +++ .../abi/abigen/testdata/v2/underscorer.go.txt | 322 +++++++++ accounts/abi/bind/auth.go | 179 ----- accounts/abi/bind/old.go | 294 ++++++++ accounts/abi/bind/v2/auth.go | 96 +++ accounts/abi/bind/{ => v2}/backend.go | 13 + accounts/abi/bind/{ => v2}/base.go | 148 ++-- accounts/abi/bind/{ => v2}/base_test.go | 2 +- accounts/abi/bind/v2/dep_tree.go | 167 +++++ accounts/abi/bind/v2/dep_tree_test.go | 370 ++++++++++ accounts/abi/bind/v2/generate_test.go | 102 +++ .../bind/v2/internal/contracts/db/bindings.go | 293 ++++++++ .../internal/contracts/db/combined-abi.json | 1 + .../v2/internal/contracts/db/contract.sol | 66 ++ .../v2/internal/contracts/events/bindings.go | 160 +++++ .../contracts/events/combined-abi.json | 1 + .../v2/internal/contracts/events/contract.sol | 36 + .../contracts/nested_libraries/abi.json | 1 + .../contracts/nested_libraries/bindings.go | 486 +++++++++++++ .../nested_libraries/combined-abi.json | 1 + .../contracts/nested_libraries/contract.sol | 76 ++ .../contracts/solc_errors/bindings.go | 217 ++++++ .../contracts/solc_errors/combined-abi.json | 1 + .../contracts/solc_errors/contract.sol | 36 + .../contracts/uint256arrayreturn/bindings.go | 77 ++ .../uint256arrayreturn/combined-abi.json | 1 + .../contracts/uint256arrayreturn/contract.sol | 10 + accounts/abi/bind/v2/lib.go | 243 +++++++ accounts/abi/bind/v2/lib_test.go | 361 ++++++++++ accounts/abi/bind/{ => v2}/util.go | 32 +- accounts/abi/bind/{ => v2}/util_test.go | 13 +- cmd/abigen/main.go | 36 +- 59 files changed, 8270 insertions(+), 401 deletions(-) rename accounts/abi/{bind => abigen}/bind.go (75%) rename accounts/abi/{bind => abigen}/bind_test.go (99%) create mode 100644 accounts/abi/abigen/bindv2.go create mode 100644 accounts/abi/abigen/bindv2_test.go rename accounts/abi/{bind => abigen}/source.go.tpl (100%) create mode 100644 accounts/abi/abigen/source2.go.tpl rename accounts/abi/{bind => abigen}/template.go (64%) create mode 100644 accounts/abi/abigen/testdata/v2/callbackparam.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/crowdsale.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/dao.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/deeplynestedarray.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/empty.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/eventchecker.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/getter.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/identifiercollision.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/inputchecker.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/interactor.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/nameconflict.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/numericmethodname.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/outputchecker.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/overload.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/rangekeyword.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/slicer.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/structs-abi.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/structs.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/token.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/tuple.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/tupler.go.txt create mode 100644 accounts/abi/abigen/testdata/v2/underscorer.go.txt delete mode 100644 accounts/abi/bind/auth.go create mode 100644 accounts/abi/bind/old.go create mode 100644 accounts/abi/bind/v2/auth.go rename accounts/abi/bind/{ => v2}/backend.go (90%) rename accounts/abi/bind/{ => v2}/base.go (85%) rename accounts/abi/bind/{ => v2}/base_test.go (99%) create mode 100644 accounts/abi/bind/v2/dep_tree.go create mode 100644 accounts/abi/bind/v2/dep_tree_test.go create mode 100644 accounts/abi/bind/v2/generate_test.go create mode 100644 accounts/abi/bind/v2/internal/contracts/db/bindings.go create mode 100644 accounts/abi/bind/v2/internal/contracts/db/combined-abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/db/contract.sol create mode 100644 accounts/abi/bind/v2/internal/contracts/events/bindings.go create mode 100644 accounts/abi/bind/v2/internal/contracts/events/combined-abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/events/contract.sol create mode 100644 accounts/abi/bind/v2/internal/contracts/nested_libraries/abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/nested_libraries/bindings.go create mode 100644 accounts/abi/bind/v2/internal/contracts/nested_libraries/combined-abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/nested_libraries/contract.sol create mode 100644 accounts/abi/bind/v2/internal/contracts/solc_errors/bindings.go create mode 100644 accounts/abi/bind/v2/internal/contracts/solc_errors/combined-abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/solc_errors/contract.sol create mode 100644 accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/bindings.go create mode 100644 accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/combined-abi.json create mode 100644 accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/contract.sol create mode 100644 accounts/abi/bind/v2/lib.go create mode 100644 accounts/abi/bind/v2/lib_test.go rename accounts/abi/bind/{ => v2}/util.go (60%) rename accounts/abi/bind/{ => v2}/util_test.go (88%) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/abigen/bind.go similarity index 75% rename from accounts/abi/bind/bind.go rename to accounts/abi/abigen/bind.go index 71357c7a8..56e5e214d 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/abigen/bind.go @@ -14,11 +14,11 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package bind generates Ethereum contract Go bindings. +// Package abigen generates Ethereum contract Go bindings. // // Detailed usage document and tutorial available on the go-ethereum Wiki page: -// https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts -package bind +// https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings +package abigen import ( "bytes" @@ -33,13 +33,6 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// Lang is a target programming language selector to generate bindings for. -type Lang int - -const ( - LangGo Lang = iota -) - func isKeyWord(arg string) bool { switch arg { case "break": @@ -81,7 +74,7 @@ func isKeyWord(arg string) bool { // to be used as is in client code, but rather as an intermediate struct which // enforces compile time type safety and naming convention as opposed to having to // manually maintain hard coded strings that break on runtime. -func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) { +func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, libs map[string]string, aliases map[string]string) (string, error) { var ( // contracts is the map of each individual contract requested binding contracts = make(map[string]*tmplContract) @@ -125,14 +118,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] for _, input := range evmABI.Constructor.Inputs { if hasStruct(input.Type) { - bindStructType[lang](input.Type, structs) + bindStructType(input.Type, structs) } } for _, original := range evmABI.Methods { // Normalize the method for capital cases and non-anonymous inputs/outputs normalized := original - normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) + normalizedName := abi.ToCamelCase(alias(aliases, original.Name)) // Ensure there is no duplicated identifier var identifiers = callIdentifiers if !original.IsConstant() { @@ -159,17 +152,17 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } if hasStruct(input.Type) { - bindStructType[lang](input.Type, structs) + bindStructType(input.Type, structs) } } normalized.Outputs = make([]abi.Argument, len(original.Outputs)) copy(normalized.Outputs, original.Outputs) for j, output := range normalized.Outputs { if output.Name != "" { - normalized.Outputs[j].Name = capitalise(output.Name) + normalized.Outputs[j].Name = abi.ToCamelCase(output.Name) } if hasStruct(output.Type) { - bindStructType[lang](output.Type, structs) + bindStructType(output.Type, structs) } } // Append the methods to the call or transact lists @@ -188,7 +181,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized := original // Ensure there is no duplicated identifier - normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) + normalizedName := abi.ToCamelCase(alias(aliases, original.Name)) // Name shouldn't start with a digit. It will make the generated code invalid. if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) { normalizedName = fmt.Sprintf("E%s", normalizedName) @@ -213,14 +206,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // Event is a bit special, we need to define event struct in binding, // ensure there is no camel-case-style name conflict. for index := 0; ; index++ { - if !used[capitalise(normalized.Inputs[j].Name)] { - used[capitalise(normalized.Inputs[j].Name)] = true + if !used[abi.ToCamelCase(normalized.Inputs[j].Name)] { + used[abi.ToCamelCase(normalized.Inputs[j].Name)] = true break } normalized.Inputs[j].Name = fmt.Sprintf("%s%d", normalized.Inputs[j].Name, index) } if hasStruct(input.Type) { - bindStructType[lang](input.Type, structs) + bindStructType(input.Type, structs) } } // Append the event to the accumulator list @@ -233,8 +226,9 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] if evmABI.HasReceive() { receive = &tmplMethod{Original: evmABI.Receive} } + contracts[types[i]] = &tmplContract{ - Type: capitalise(types[i]), + Type: abi.ToCamelCase(types[i]), InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""), InputBin: strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"), Constructor: evmABI.Constructor, @@ -245,6 +239,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] Events: events, Libraries: make(map[string]string), } + // Function 4-byte signatures are stored in the same sequence // as types, if available. if len(fsigs) > i { @@ -270,6 +265,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] _, ok := isLib[types[i]] contracts[types[i]].Library = ok } + // Generate the contract template data content and render it data := &tmplData{ Package: pkg, @@ -280,36 +276,25 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] buffer := new(bytes.Buffer) funcs := map[string]interface{}{ - "bindtype": bindType[lang], - "bindtopictype": bindTopicType[lang], - "namedtype": namedType[lang], - "capitalise": capitalise, + "bindtype": bindType, + "bindtopictype": bindTopicType, + "capitalise": abi.ToCamelCase, "decapitalise": decapitalise, } - tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang])) + tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource)) if err := tmpl.Execute(buffer, data); err != nil { return "", err } - // For Go bindings pass the code through gofmt to clean it up - if lang == LangGo { - code, err := format.Source(buffer.Bytes()) - if err != nil { - return "", fmt.Errorf("%v\n%s", err, buffer) - } - return string(code), nil + // Pass the code through gofmt to clean it up + code, err := format.Source(buffer.Bytes()) + if err != nil { + return "", fmt.Errorf("%v\n%s", err, buffer) } - // For all others just return as is for now - return buffer.String(), nil -} - -// bindType is a set of type binders that convert Solidity types to some supported -// programming language types. -var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindTypeGo, + return string(code), nil } -// bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go ones. -func bindBasicTypeGo(kind abi.Type) string { +// bindBasicType converts basic solidity types(except array, slice and tuple) to Go ones. +func bindBasicType(kind abi.Type) string { switch kind.T { case abi.AddressTy: return "common.Address" @@ -332,32 +317,26 @@ func bindBasicTypeGo(kind abi.Type) string { } } -// bindTypeGo converts solidity types to Go ones. Since there is no clear mapping +// bindType converts solidity types to Go ones. Since there is no clear mapping // from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly // mapped will use an upscaled type (e.g. BigDecimal). -func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { +func bindType(kind abi.Type, structs map[string]*tmplStruct) string { switch kind.T { case abi.TupleTy: return structs[kind.TupleRawName+kind.String()].Name case abi.ArrayTy: - return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem, structs) + return fmt.Sprintf("[%d]", kind.Size) + bindType(*kind.Elem, structs) case abi.SliceTy: - return "[]" + bindTypeGo(*kind.Elem, structs) + return "[]" + bindType(*kind.Elem, structs) default: - return bindBasicTypeGo(kind) + return bindBasicType(kind) } } -// bindTopicType is a set of type binders that convert Solidity types to some -// supported programming language topic types. -var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindTopicTypeGo, -} - -// bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same +// bindTopicType converts a Solidity topic type to a Go one. It is almost the same // functionality as for simple types, but dynamic types get converted to hashes. -func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { - bound := bindTypeGo(kind, structs) +func bindTopicType(kind abi.Type, structs map[string]*tmplStruct) string { + bound := bindType(kind, structs) // todo(rjl493456442) according solidity documentation, indexed event // parameters that are not value types i.e. arrays and structs are not @@ -371,16 +350,10 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { return bound } -// bindStructType is a set of type binders that convert Solidity tuple types to some supported -// programming language struct definition. -var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindStructTypeGo, -} - -// bindStructTypeGo converts a Solidity tuple type to a Go one and records the mapping -// in the given map. -// Notably, this function will resolve and record nested struct recursively. -func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { +// bindStructType converts a Solidity tuple type to a Go one and records the mapping +// in the given map. Notably, this function will resolve and record nested struct +// recursively. +func bindStructType(kind abi.Type, structs map[string]*tmplStruct) string { switch kind.T { case abi.TupleTy: // We compose a raw struct name and a canonical parameter expression @@ -398,16 +371,20 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { fields []*tmplField ) for i, elem := range kind.TupleElems { - name := capitalise(kind.TupleRawNames[i]) + name := abi.ToCamelCase(kind.TupleRawNames[i]) name = abi.ResolveNameConflict(name, func(s string) bool { return names[s] }) names[name] = true - fields = append(fields, &tmplField{Type: bindStructTypeGo(*elem, structs), Name: name, SolKind: *elem}) + fields = append(fields, &tmplField{ + Type: bindStructType(*elem, structs), + Name: name, + SolKind: *elem, + }) } name := kind.TupleRawName if name == "" { name = fmt.Sprintf("Struct%d", len(structs)) } - name = capitalise(name) + name = abi.ToCamelCase(name) structs[id] = &tmplStruct{ Name: name, @@ -415,20 +392,14 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { } return name case abi.ArrayTy: - return fmt.Sprintf("[%d]", kind.Size) + bindStructTypeGo(*kind.Elem, structs) + return fmt.Sprintf("[%d]", kind.Size) + bindStructType(*kind.Elem, structs) case abi.SliceTy: - return "[]" + bindStructTypeGo(*kind.Elem, structs) + return "[]" + bindStructType(*kind.Elem, structs) default: - return bindBasicTypeGo(kind) + return bindBasicType(kind) } } -// namedType is a set of functions that transform language specific types to -// named versions that may be used inside method names. -var namedType = map[Lang]func(string, abi.Type) string{ - LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, -} - // alias returns an alias of the given string based on the aliasing rules // or returns itself if no rule is matched. func alias(aliases map[string]string, n string) string { @@ -438,21 +409,11 @@ func alias(aliases map[string]string, n string) string { return n } -// methodNormalizer is a name transformer that modifies Solidity method names to -// conform to target language naming conventions. -var methodNormalizer = map[Lang]func(string) string{ - LangGo: abi.ToCamelCase, -} - -// capitalise makes a camel-case string which starts with an upper case character. -var capitalise = abi.ToCamelCase - // decapitalise makes a camel-case string which starts with a lower case character. func decapitalise(input string) string { if len(input) == 0 { return input } - goForm := abi.ToCamelCase(input) return strings.ToLower(goForm[:1]) + goForm[1:] } @@ -471,7 +432,7 @@ func structured(args abi.Arguments) bool { } // If the field name is empty when normalized or collides (var, Var, _var, _Var), // we can't organize into a struct - field := capitalise(out.Name) + field := abi.ToCamelCase(out.Name) if field == "" || exists[field] { return false } diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/abigen/bind_test.go similarity index 99% rename from accounts/abi/bind/bind_test.go rename to accounts/abi/abigen/bind_test.go index a390a3c47..387156091 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/abigen/bind_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package bind +package abigen import ( "fmt" @@ -2072,20 +2072,22 @@ var bindTests = []struct { // Tests that packages generated by the binder can be successfully compiled and // the requested tester run against it. -func TestGolangBindings(t *testing.T) { +func TestBindings(t *testing.T) { t.Parallel() // Skip the test if no Go command can be found gocmd := runtime.GOROOT() + "/bin/go" if !common.FileExist(gocmd) { t.Skip("go sdk not found for testing") } - // Create a temporary workspace for the test suite - ws := t.TempDir() - pkg := filepath.Join(ws, "bindtest") + // Create a temporary workspace for the test suite + path := t.TempDir() + pkg := filepath.Join(path, "bindtest") if err := os.MkdirAll(pkg, 0700); err != nil { t.Fatalf("failed to create package: %v", err) } + t.Log("tmpdir", pkg) + // Generate the test suite for all the contracts for i, tt := range bindTests { t.Run(tt.name, func(t *testing.T) { @@ -2096,7 +2098,7 @@ func TestGolangBindings(t *testing.T) { types = []string{tt.name} } // Generate the binding and create a Go source file in the workspace - bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases) + bind, err := Bind(types, tt.abi, tt.bytecode, tt.fsigs, "bindtest", tt.libs, tt.aliases) if err != nil { t.Fatalf("test %d: failed to generate binding: %v", i, err) } diff --git a/accounts/abi/abigen/bindv2.go b/accounts/abi/abigen/bindv2.go new file mode 100644 index 000000000..ef4b769bb --- /dev/null +++ b/accounts/abi/abigen/bindv2.go @@ -0,0 +1,373 @@ +// Copyright 2024 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 . + +package abigen + +import ( + "bytes" + "fmt" + "go/format" + "reflect" + "regexp" + "slices" + "sort" + "strings" + "text/template" + "unicode" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +// underlyingBindType returns a string representation of the Go type +// that corresponds to the given ABI type, panicking if it is not a +// pointer. +func underlyingBindType(typ abi.Type) string { + goType := typ.GetType() + if goType.Kind() != reflect.Pointer { + panic("trying to retrieve underlying bind type of non-pointer type.") + } + return goType.Elem().String() +} + +// isPointerType returns true if the underlying type is a pointer. +func isPointerType(typ abi.Type) bool { + return typ.GetType().Kind() == reflect.Pointer +} + +// OLD: +// binder is used during the conversion of an ABI definition into Go bindings +// (as part of the execution of BindV2). In contrast to contractBinder, binder +// contains binding-generation-state that is shared between contracts: +// +// a global struct map of structs emitted by all contracts is tracked and expanded. +// Structs generated in the bindings are not prefixed with the contract name +// that uses them (to keep the generated bindings less verbose). +// +// This contrasts to other per-contract state (constructor/method/event/error, +// pack/unpack methods) which are guaranteed to be unique because of their +// association with the uniquely-named owning contract (whether prefixed in the +// generated symbol name, or as a member method on a contract struct). +// +// In addition, binder contains the input alias map. In BindV2, a binder is +// instantiated to produce a set of tmplContractV2 and tmplStruct objects from +// the provided ABI definition. These are used as part of the input to rendering +// the binding template. + +// NEW: +// binder is used to translate an ABI definition into a set of data-structures +// that will be used to render the template and produce Go bindings. This can +// be thought of as the "backend" that sanitizes the ABI definition to a format +// that can be directly rendered with minimal complexity in the template. +// +// The input data to the template rendering consists of: +// - the set of all contracts requested for binding, each containing +// methods/events/errors to emit pack/unpack methods for. +// - the set of structures defined by the contracts, and created +// as part of the binding process. +type binder struct { + // contracts is the map of each individual contract requested binding. + // It is keyed by the contract name provided in the ABI definition. + contracts map[string]*tmplContractV2 + + // structs is the map of all emitted structs from contracts being bound. + // it is keyed by a unique identifier generated from the name of the owning contract + // and the solidity type signature of the struct + structs map[string]*tmplStruct + + // aliases is a map for renaming instances of named events/functions/errors + // to specified values. it is keyed by source symbol name, and values are + // what the replacement name should be. + aliases map[string]string +} + +// BindStructType registers the type to be emitted as a struct in the +// bindings. +func (b *binder) BindStructType(typ abi.Type) { + bindStructType(typ, b.structs) +} + +// contractBinder holds state for binding of a single contract. It is a type +// registry for compiling maps of identifiers that will be emitted in generated +// bindings. +type contractBinder struct { + binder *binder + + // all maps are keyed by the original (non-normalized) name of the symbol in question + // from the provided ABI definition. + calls map[string]*tmplMethod + events map[string]*tmplEvent + errors map[string]*tmplError + callIdentifiers map[string]bool + eventIdentifiers map[string]bool + errorIdentifiers map[string]bool +} + +func newContractBinder(binder *binder) *contractBinder { + return &contractBinder{ + binder, + make(map[string]*tmplMethod), + make(map[string]*tmplEvent), + make(map[string]*tmplError), + make(map[string]bool), + make(map[string]bool), + make(map[string]bool), + } +} + +// registerIdentifier applies alias renaming, name normalization (conversion +// from snake to camel-case), and registers the normalized name in the specified identifier map. +// It returns an error if the normalized name already exists in the map. +func (cb *contractBinder) registerIdentifier(identifiers map[string]bool, original string) (normalized string, err error) { + normalized = abi.ToCamelCase(alias(cb.binder.aliases, original)) + + // Name shouldn't start with a digit. It will make the generated code invalid. + if len(normalized) > 0 && unicode.IsDigit(rune(normalized[0])) { + normalized = fmt.Sprintf("E%s", normalized) + normalized = abi.ResolveNameConflict(normalized, func(name string) bool { + _, ok := identifiers[name] + return ok + }) + } + if _, ok := identifiers[normalized]; ok { + return "", fmt.Errorf("duplicate symbol '%s'", normalized) + } + identifiers[normalized] = true + return normalized, nil +} + +// bindMethod registers a method to be emitted in the bindings. The name, inputs +// and outputs are normalized. If any inputs are struct-type their structs are +// registered to be emitted in the bindings. Any methods that return more than +// one output have their results gathered into a struct. +func (cb *contractBinder) bindMethod(original abi.Method) error { + normalized := original + normalizedName, err := cb.registerIdentifier(cb.callIdentifiers, original.Name) + if err != nil { + return err + } + normalized.Name = normalizedName + + normalized.Inputs = normalizeArgs(original.Inputs) + for _, input := range normalized.Inputs { + if hasStruct(input.Type) { + cb.binder.BindStructType(input.Type) + } + } + normalized.Outputs = normalizeArgs(original.Outputs) + for _, output := range normalized.Outputs { + if hasStruct(output.Type) { + cb.binder.BindStructType(output.Type) + } + } + + var isStructured bool + // If the call returns multiple values, gather them into a struct + if len(normalized.Outputs) > 1 { + isStructured = true + } + cb.calls[original.Name] = &tmplMethod{ + Original: original, + Normalized: normalized, + Structured: isStructured, + } + return nil +} + +// normalize a set of arguments by stripping underscores, giving a generic name +// in the case where the arg name collides with a reserved Go keyword, and finally +// converting to camel-case. +func normalizeArgs(args abi.Arguments) abi.Arguments { + args = slices.Clone(args) + used := make(map[string]bool) + + for i, input := range args { + if isKeyWord(input.Name) { + args[i].Name = fmt.Sprintf("arg%d", i) + } + args[i].Name = abi.ToCamelCase(args[i].Name) + if args[i].Name == "" { + args[i].Name = fmt.Sprintf("arg%d", i) + } else { + args[i].Name = strings.ToLower(args[i].Name[:1]) + args[i].Name[1:] + } + + for index := 0; ; index++ { + if !used[args[i].Name] { + used[args[i].Name] = true + break + } + args[i].Name = fmt.Sprintf("%s%d", args[i].Name, index) + } + } + return args +} + +// normalizeErrorOrEventFields normalizes errors/events for emitting through +// bindings: Any anonymous fields are given generated names. +func (cb *contractBinder) normalizeErrorOrEventFields(originalInputs abi.Arguments) abi.Arguments { + normalizedArguments := normalizeArgs(originalInputs) + for _, input := range normalizedArguments { + if hasStruct(input.Type) { + cb.binder.BindStructType(input.Type) + } + } + return normalizedArguments +} + +// bindEvent normalizes an event and registers it to be emitted in the bindings. +func (cb *contractBinder) bindEvent(original abi.Event) error { + // Skip anonymous events as they don't support explicit filtering + if original.Anonymous { + return nil + } + normalizedName, err := cb.registerIdentifier(cb.eventIdentifiers, original.Name) + if err != nil { + return err + } + + normalized := original + normalized.Name = normalizedName + normalized.Inputs = cb.normalizeErrorOrEventFields(original.Inputs) + cb.events[original.Name] = &tmplEvent{Original: original, Normalized: normalized} + return nil +} + +// bindError normalizes an error and registers it to be emitted in the bindings. +func (cb *contractBinder) bindError(original abi.Error) error { + normalizedName, err := cb.registerIdentifier(cb.errorIdentifiers, original.Name) + if err != nil { + return err + } + + normalized := original + normalized.Name = normalizedName + normalized.Inputs = cb.normalizeErrorOrEventFields(original.Inputs) + cb.errors[original.Name] = &tmplError{Original: original, Normalized: normalized} + return nil +} + +// parseLibraryDeps extracts references to library dependencies from the unlinked +// hex string deployment bytecode. +func parseLibraryDeps(unlinkedCode string) (res []string) { + reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`) + if err != nil { + panic(err) + } + for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(unlinkedCode, -1) { + res = append(res, match[1]) + } + return res +} + +// iterSorted iterates the map in the lexicographic order of the keys calling +// onItem on each. If the callback returns an error, iteration is halted and +// the error is returned from iterSorted. +func iterSorted[V any](inp map[string]V, onItem func(string, V) error) error { + var sortedKeys []string + for key := range inp { + sortedKeys = append(sortedKeys, key) + } + sort.Strings(sortedKeys) + + for _, key := range sortedKeys { + if err := onItem(key, inp[key]); err != nil { + return err + } + } + return nil +} + +// BindV2 generates a Go wrapper around a contract ABI. This wrapper isn't meant +// to be used as is in client code, but rather as an intermediate struct which +// enforces compile time type safety and naming convention as opposed to having to +// manually maintain hard coded strings that break on runtime. +func BindV2(types []string, abis []string, bytecodes []string, pkg string, libs map[string]string, aliases map[string]string) (string, error) { + b := binder{ + contracts: make(map[string]*tmplContractV2), + structs: make(map[string]*tmplStruct), + aliases: aliases, + } + for i := 0; i < len(types); i++ { + // Parse the actual ABI to generate the binding for + evmABI, err := abi.JSON(strings.NewReader(abis[i])) + if err != nil { + return "", err + } + + for _, input := range evmABI.Constructor.Inputs { + if hasStruct(input.Type) { + bindStructType(input.Type, b.structs) + } + } + + cb := newContractBinder(&b) + err = iterSorted(evmABI.Methods, func(_ string, original abi.Method) error { + return cb.bindMethod(original) + }) + if err != nil { + return "", err + } + err = iterSorted(evmABI.Events, func(_ string, original abi.Event) error { + return cb.bindEvent(original) + }) + if err != nil { + return "", err + } + err = iterSorted(evmABI.Errors, func(_ string, original abi.Error) error { + return cb.bindError(original) + }) + if err != nil { + return "", err + } + b.contracts[types[i]] = newTmplContractV2(types[i], abis[i], bytecodes[i], evmABI.Constructor, cb) + } + + invertedLibs := make(map[string]string) + for pattern, name := range libs { + invertedLibs[name] = pattern + } + data := tmplDataV2{ + Package: pkg, + Contracts: b.contracts, + Libraries: invertedLibs, + Structs: b.structs, + } + + for typ, contract := range data.Contracts { + for _, depPattern := range parseLibraryDeps(contract.InputBin) { + data.Contracts[typ].Libraries[libs[depPattern]] = depPattern + } + } + buffer := new(bytes.Buffer) + funcs := map[string]interface{}{ + "bindtype": bindType, + "bindtopictype": bindTopicType, + "capitalise": abi.ToCamelCase, + "decapitalise": decapitalise, + "ispointertype": isPointerType, + "underlyingbindtype": underlyingBindType, + } + tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSourceV2)) + if err := tmpl.Execute(buffer, data); err != nil { + return "", err + } + // Pass the code through gofmt to clean it up + code, err := format.Source(buffer.Bytes()) + if err != nil { + return "", fmt.Errorf("%v\n%s", err, buffer) + } + return string(code), nil +} diff --git a/accounts/abi/abigen/bindv2_test.go b/accounts/abi/abigen/bindv2_test.go new file mode 100644 index 000000000..2756ba083 --- /dev/null +++ b/accounts/abi/abigen/bindv2_test.go @@ -0,0 +1,342 @@ +// Copyright 2024 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 . + +package abigen + +import ( + "fmt" + "os" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/crypto" +) + +type bindV2Test struct { + name string + abis []string + bytecodes []string + types []string + aliases map[string]string +} + +func bindCombinedJSON(test *bindV2Test) (string, error) { + var ( + abis []string + bins []string + types []string + ) + libs := make(map[string]string) + for i := 0; i < len(test.types); i++ { + // fully qualified name is of the form : + typeName := test.types[i] + abis = append(abis, test.abis[i]) + bins = append(bins, test.bytecodes[i]) + types = append(types, typeName) + + // Derive the library placeholder which is a 34 character prefix of the + // hex encoding of the keccak256 hash of the fully qualified library name. + // Note that the fully qualified library name is the path of its source + // file and the library name separated by ":". + libPattern := crypto.Keccak256Hash([]byte(typeName)).String()[2:36] // the first 2 chars are 0x + libs[libPattern] = typeName + } + if test.aliases == nil { + test.aliases = make(map[string]string) + } + code, err := BindV2(types, abis, bins, "bindtests", libs, test.aliases) + if err != nil { + return "", fmt.Errorf("error creating bindings: %v", err) + } + return code, nil +} + +var combinedJSONBindTestsV2 = []bindV2Test{ + { + "Empty", + []string{`[]`}, + []string{`606060405260068060106000396000f3606060405200`}, + nil, + nil, + }, + { + "Token", + []string{`[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"spentAllowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`}, + []string{`60606040526040516107fd3803806107fd83398101604052805160805160a05160c051929391820192909101600160a060020a0333166000908152600360209081526040822086905581548551838052601f6002600019610100600186161502019093169290920482018390047f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390810193919290918801908390106100e857805160ff19168380011785555b506101189291505b8082111561017157600081556001016100b4565b50506002805460ff19168317905550505050610658806101a56000396000f35b828001600101855582156100ac579182015b828111156100ac5782518260005055916020019190600101906100fa565b50508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017557805160ff19168380011785555b506100c89291506100b4565b5090565b82800160010185558215610165579182015b8281111561016557825182600050559160200191906001019061018756606060405236156100775760e060020a600035046306fdde03811461007f57806323b872dd146100dc578063313ce5671461010e57806370a082311461011a57806395d89b4114610132578063a9059cbb1461018e578063cae9ca51146101bd578063dc3080f21461031c578063dd62ed3e14610341575b610365610002565b61036760008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b6103d5600435602435604435600160a060020a038316600090815260036020526040812054829010156104f357610002565b6103e760025460ff1681565b6103d560043560036020526000908152604090205481565b610367600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b610365600435602435600160a060020a033316600090815260036020526040902054819010156103f157610002565b60806020604435600481810135601f8101849004909302840160405260608381526103d5948235946024803595606494939101919081908382808284375094965050505050505060006000836004600050600033600160a060020a03168152602001908152602001600020600050600087600160a060020a031681526020019081526020016000206000508190555084905080600160a060020a0316638f4ffcb1338630876040518560e060020a0281526004018085600160a060020a0316815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156102f25780820380516001836020036101000a031916815260200191505b50955050505050506000604051808303816000876161da5a03f11561000257505050509392505050565b6005602090815260043560009081526040808220909252602435815220546103d59081565b60046020818152903560009081526040808220909252602435815220546103d59081565b005b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a03821660009081526040902054808201101561041357610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b820191906000526020600020905b8154815290600101906020018083116104ce57829003601f168201915b505050505081565b600160a060020a03831681526040812054808301101561051257610002565b600160a060020a0380851680835260046020908152604080852033949094168086529382528085205492855260058252808520938552929052908220548301111561055c57610002565b816003600050600086600160a060020a03168152602001908152602001600020600082828250540392505081905550816003600050600085600160a060020a03168152602001908152602001600020600082828250540192505081905550816005600050600086600160a060020a03168152602001908152602001600020600050600033600160a060020a0316815260200190815260200160002060008282825054019250508190555082600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3939250505056`}, + nil, + nil, + }, + { + "Crowdsale", + []string{`[{"constant":false,"inputs":[],"name":"checkGoalReached","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"deadline","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"tokenReward","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"fundingGoal","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"amountRaised","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"price","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"funders","outputs":[{"name":"addr","type":"address"},{"name":"amount","type":"uint256"}],"type":"function"},{"inputs":[{"name":"ifSuccessfulSendTo","type":"address"},{"name":"fundingGoalInEthers","type":"uint256"},{"name":"durationInMinutes","type":"uint256"},{"name":"etherCostOfEachToken","type":"uint256"},{"name":"addressOfTokenUsedAsReward","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"backer","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"isContribution","type":"bool"}],"name":"FundTransfer","type":"event"}]`}, + []string{`606060408190526007805460ff1916905560a0806105a883396101006040529051608051915160c05160e05160008054600160a060020a03199081169095178155670de0b6b3a7640000958602600155603c9093024201600355930260045560058054909216909217905561052f90819061007990396000f36060604052361561006c5760e060020a600035046301cb3b20811461008257806329dcb0cf1461014457806338af3eed1461014d5780636e66f6e91461015f5780637a3a0e84146101715780637b3e5e7b1461017a578063a035b1fe14610183578063dc0d3dff1461018c575b61020060075460009060ff161561032357610002565b61020060035460009042106103205760025460015490106103cb576002548154600160a060020a0316908290606082818181858883f150915460025460408051600160a060020a039390931683526020830191909152818101869052517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6945090819003909201919050a15b60405160008054600160a060020a039081169230909116319082818181858883f150506007805460ff1916600117905550505050565b6103a160035481565b6103ab600054600160a060020a031681565b6103ab600554600160a060020a031681565b6103a160015481565b6103a160025481565b6103a160045481565b6103be60043560068054829081101561000257506000526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f8101547ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d409190910154600160a060020a03919091169082565b005b505050815481101561000257906000526020600020906002020160005060008201518160000160006101000a815481600160a060020a030219169083021790555060208201518160010160005055905050806002600082828250540192505081905550600560009054906101000a9004600160a060020a0316600160a060020a031663a9059cbb3360046000505484046040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506000604051808303816000876161da5a03f11561000257505060408051600160a060020a03331681526020810184905260018183015290517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf692509081900360600190a15b50565b5060a0604052336060908152346080819052600680546001810180835592939282908280158290116102025760020281600202836000526020600020918201910161020291905b8082111561039d57805473ffffffffffffffffffffffffffffffffffffffff19168155600060019190910190815561036a565b5090565b6060908152602090f35b600160a060020a03166060908152602090f35b6060918252608052604090f35b5b60065481101561010e576006805482908110156100025760009182526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0190600680549254600160a060020a0316928490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460405190915082818181858883f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf660066000508281548110156100025760008290526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01548154600160a060020a039190911691908490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460408051600160a060020a0394909416845260208401919091526000838201525191829003606001919050a16001016103cc56`}, + nil, + nil, + }, + { + "DAO", + []string{`[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"description","type":"string"},{"name":"votingDeadline","type":"uint256"},{"name":"executed","type":"bool"},{"name":"proposalPassed","type":"bool"},{"name":"numberOfVotes","type":"uint256"},{"name":"currentResult","type":"int256"},{"name":"proposalHash","type":"bytes32"}],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"executeProposal","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"memberId","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"numProposals","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"member","type":"address"},{"name":"canVote","type":"bool"},{"name":"name","type":"string"},{"name":"memberSince","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"debatingPeriodInMinutes","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"minimumQuorum","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"targetMember","type":"address"},{"name":"canVote","type":"bool"},{"name":"memberName","type":"string"}],"name":"changeMembership","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"majorityMargin","outputs":[{"name":"","type":"int256"}],"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"JobDescription","type":"string"},{"name":"transactionBytecode","type":"bytes"}],"name":"newProposal","outputs":[{"name":"proposalID","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"}],"name":"changeVotingRules","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"supportsProposal","type":"bool"},{"name":"justificationText","type":"string"}],"name":"vote","outputs":[{"name":"voteID","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"checkProposalCode","outputs":[{"name":"codeChecksOut","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"type":"function"},{"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"},{"name":"congressLeader","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"position","type":"bool"},{"indexed":false,"name":"voter","type":"address"},{"indexed":false,"name":"justification","type":"string"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"result","type":"int256"},{"indexed":false,"name":"quorum","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"ProposalTallied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"member","type":"address"},{"indexed":false,"name":"isMember","type":"bool"}],"name":"MembershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"minimumQuorum","type":"uint256"},{"indexed":false,"name":"debatingPeriodInMinutes","type":"uint256"},{"indexed":false,"name":"majorityMargin","type":"int256"}],"name":"ChangeOfRules","type":"event"}]`}, + []string{`606060405260405160808061145f833960e06040529051905160a05160c05160008054600160a060020a03191633179055600184815560028490556003839055600780549182018082558280158290116100b8576003028160030283600052602060002091820191016100b891906101c8565b50506060919091015160029190910155600160a060020a0381166000146100a65760008054600160a060020a031916821790555b505050506111f18061026e6000396000f35b505060408051608081018252600080825260208281018290528351908101845281815292820192909252426060820152600780549194509250811015610002579081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889050815181546020848101517401000000000000000000000000000000000000000002600160a060020a03199290921690921760a060020a60ff021916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f9081018390048201949192919091019083901061023e57805160ff19168380011785555b50610072929150610226565b5050600060028201556001015b8082111561023a578054600160a860020a031916815560018181018054600080835592600290821615610100026000190190911604601f81901061020c57506101bb565b601f0160209004906000526020600020908101906101bb91905b8082111561023a5760008155600101610226565b5090565b828001600101855582156101af579182015b828111156101af57825182600050559160200191906001019061025056606060405236156100b95760e060020a6000350463013cf08b81146100bb578063237e9492146101285780633910682114610281578063400e3949146102995780635daf08ca146102a257806369bd34361461032f5780638160f0b5146103385780638da5cb5b146103415780639644fcbd14610353578063aa02a90f146103be578063b1050da5146103c7578063bcca1fd3146104b5578063d3c0715b146104dc578063eceb29451461058d578063f2fde38b1461067b575b005b61069c6004356004805482908110156100025790600052602060002090600a02016000506005810154815460018301546003840154600485015460068601546007870154600160a060020a03959095169750929560020194919360ff828116946101009093041692919089565b60408051602060248035600481810135601f81018590048502860185019096528585526107759581359591946044949293909201918190840183828082843750949650505050505050600060006004600050848154811015610002575090527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19e600a8402908101547f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b909101904210806101e65750600481015460ff165b8061026757508060000160009054906101000a9004600160a060020a03168160010160005054846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816007016000505414155b8061027757506001546005820154105b1561109257610002565b61077560043560066020526000908152604090205481565b61077560055481565b61078760043560078054829081101561000257506000526003026000805160206111d18339815191528101547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a820154600160a060020a0382169260a060020a90920460ff16917fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c689019084565b61077560025481565b61077560015481565b610830600054600160a060020a031681565b604080516020604435600481810135601f81018490048402850184019095528484526100b9948135946024803595939460649492939101918190840183828082843750949650505050505050600080548190600160a060020a03908116339091161461084d57610002565b61077560035481565b604080516020604435600481810135601f8101849004840285018401909552848452610775948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024909101945090925082915084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806104ab5750604081205460078054909190811015610002579082526003026000805160206111d1833981519152015460a060020a900460ff16155b15610ce557610002565b6100b960043560243560443560005433600160a060020a03908116911614610b1857610002565b604080516020604435600481810135601f810184900484028501840190955284845261077594813594602480359593946064949293910191819084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806105835750604081205460078054909190811015610002579082526003026000805160206111d18339815191520181505460a060020a900460ff16155b15610f1d57610002565b604080516020606435600481810135601f81018490048402850184019095528484526107759481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600460005086815481101561000257908252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01815090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005054149150610cdc565b6100b960043560005433600160a060020a03908116911614610f0857610002565b604051808a600160a060020a031681526020018981526020018060200188815260200187815260200186815260200185815260200184815260200183815260200182810382528981815460018160011615610100020316600290048152602001915080546001816001161561010002031660029004801561075e5780601f106107335761010080835404028352916020019161075e565b820191906000526020600020905b81548152906001019060200180831161074157829003601f168201915b50509a505050505050505050505060405180910390f35b60408051918252519081900360200190f35b60408051600160a060020a038616815260208101859052606081018390526080918101828152845460026001821615610100026000190190911604928201839052909160a08301908590801561081e5780601f106107f35761010080835404028352916020019161081e565b820191906000526020600020905b81548152906001019060200180831161080157829003601f168201915b50509550505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b600160a060020a03851660009081526006602052604081205414156108a957604060002060078054918290556001820180825582801582901161095c5760030281600302836000526020600020918201910161095c9190610a4f565b600160a060020a03851660009081526006602052604090205460078054919350908390811015610002575060005250600381026000805160206111d183398151915201805474ff0000000000000000000000000000000000000000191660a060020a85021781555b60408051600160a060020a03871681526020810186905281517f27b022af4a8347100c7a041ce5ccf8e14d644ff05de696315196faae8cd50c9b929181900390910190a15050505050565b505050915081506080604051908101604052808681526020018581526020018481526020014281526020015060076000508381548110156100025790600052602060002090600302016000508151815460208481015160a060020a02600160a060020a03199290921690921774ff00000000000000000000000000000000000000001916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f90810183900482019491929190910190839010610ad357805160ff19168380011785555b50610b03929150610abb565b5050600060028201556001015b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610aa15750610a42565b601f016020900490600052602060002090810190610a4291905b80821115610acf5760008155600101610abb565b5090565b82800160010185558215610a36579182015b82811115610a36578251826000505591602001919060010190610ae5565b50506060919091015160029190910155610911565b600183905560028290556003819055604080518481526020810184905280820183905290517fa439d3fa452be5e0e1e24a8145e715f4fd8b9c08c96a42fd82a855a85e5d57de9181900360600190a1505050565b50508585846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005081905550600260005054603c024201816003016000508190555060008160040160006101000a81548160ff0219169083021790555060008160040160016101000a81548160ff02191690830217905550600081600501600050819055507f646fec02522b41e7125cfc859a64fd4f4cefd5dc3b6237ca0abe251ded1fa881828787876040518085815260200184600160a060020a03168152602001838152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610cc45780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1600182016005555b50949350505050565b6004805460018101808355909190828015829011610d1c57600a0281600a028360005260206000209182019101610d1c9190610db8565b505060048054929450918491508110156100025790600052602060002090600a02016000508054600160a060020a031916871781556001818101879055855160028381018054600082815260209081902096975091959481161561010002600019011691909104601f90810182900484019391890190839010610ed857805160ff19168380011785555b50610b6c929150610abb565b50506001015b80821115610acf578054600160a060020a03191681556000600182810182905560028381018054848255909281161561010002600019011604601f819010610e9c57505b5060006003830181905560048301805461ffff191690556005830181905560068301819055600783018190556008830180548282559082526020909120610db2916002028101905b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610eba57505b5050600101610e44565b601f016020900490600052602060002090810190610dfc9190610abb565b601f016020900490600052602060002090810190610e929190610abb565b82800160010185558215610da6579182015b82811115610da6578251826000505591602001919060010190610eea565b60008054600160a060020a0319168217905550565b600480548690811015610002576000918252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905033600160a060020a0316600090815260098201602052604090205490915060ff1660011415610f8457610002565b33600160a060020a031660009081526009820160205260409020805460ff1916600190811790915560058201805490910190558315610fcd576006810180546001019055610fda565b6006810180546000190190555b7fc34f869b7ff431b034b7b9aea9822dac189a685e0b015c7d1be3add3f89128e8858533866040518085815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561107a5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1509392505050565b6006810154600354901315611158578060000160009054906101000a9004600160a060020a0316600160a060020a03168160010160005054670de0b6b3a76400000284604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111225780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f15050505060048101805460ff191660011761ff00191661010017905561116d565b60048101805460ff191660011761ff00191690555b60068101546005820154600483015460408051888152602081019490945283810192909252610100900460ff166060830152517fd220b7272a8b6d0d7d6bcdace67b936a8f175e6d5c1b3ee438b72256b32ab3af9181900360800190a1509291505056a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688`}, + nil, + nil, + }, + { + "InputChecker", + []string{` + [ + {"type":"function","name":"noInput","constant":true,"inputs":[],"outputs":[]}, + {"type":"function","name":"namedInput","constant":true,"inputs":[{"name":"str","type":"string"}],"outputs":[]}, + {"type":"function","name":"anonInput","constant":true,"inputs":[{"name":"","type":"string"}],"outputs":[]}, + {"type":"function","name":"namedInputs","constant":true,"inputs":[{"name":"str1","type":"string"},{"name":"str2","type":"string"}],"outputs":[]}, + {"type":"function","name":"anonInputs","constant":true,"inputs":[{"name":"","type":"string"},{"name":"","type":"string"}],"outputs":[]}, + {"type":"function","name":"mixedInputs","constant":true,"inputs":[{"name":"","type":"string"},{"name":"str","type":"string"}],"outputs":[]} + ] + `}, + []string{``}, + nil, + nil, + }, + { + "OutputChecker", + []string{` + [ + {"type":"function","name":"noOutput","constant":true,"inputs":[],"outputs":[]}, + {"type":"function","name":"namedOutput","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"}]}, + {"type":"function","name":"anonOutput","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"}]}, + {"type":"function","name":"namedOutputs","constant":true,"inputs":[],"outputs":[{"name":"str1","type":"string"},{"name":"str2","type":"string"}]}, + {"type":"function","name":"collidingOutputs","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"},{"name":"Str","type":"string"}]}, + {"type":"function","name":"anonOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"","type":"string"}]}, + {"type":"function","name":"mixedOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"str","type":"string"}]} + ] + `}, + []string{``}, + nil, + nil, + }, + { + "EventChecker", + []string{` + [ + {"type":"event","name":"empty","inputs":[]}, + {"type":"event","name":"indexed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int256","indexed":true}]}, + {"type":"event","name":"mixed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int256"}]}, + {"type":"event","name":"anonymous","anonymous":true,"inputs":[]}, + {"type":"event","name":"dynamic","inputs":[{"name":"idxStr","type":"string","indexed":true},{"name":"idxDat","type":"bytes","indexed":true},{"name":"str","type":"string"},{"name":"dat","type":"bytes"}]}, + {"type":"event","name":"unnamed","inputs":[{"name":"","type":"uint256","indexed": true},{"name":"","type":"uint256","indexed":true}]} + ] + `}, + []string{``}, + nil, + nil, + }, + { + "Interactor", + []string{`[{"constant":true,"inputs":[],"name":"transactString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":true,"inputs":[],"name":"deployString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"str","type":"string"}],"name":"transact","outputs":[],"type":"function"},{"inputs":[{"name":"str","type":"string"}],"type":"constructor"}]`}, + []string{`6060604052604051610328380380610328833981016040528051018060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10608d57805160ff19168380011785555b50607c9291505b8082111560ba57838155600101606b565b50505061026a806100be6000396000f35b828001600101855582156064579182015b828111156064578251826000505591602001919060010190609e565b509056606060405260e060020a60003504630d86a0e181146100315780636874e8091461008d578063d736c513146100ea575b005b610190600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b61019060008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b60206004803580820135601f81018490049093026080908101604052606084815261002f946024939192918401918190838280828437509496505050505050508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023157805160ff19168380011785555b506102619291505b808211156102665760008155830161017d565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156101f05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b820191906000526020600020905b81548152906001019060200180831161020c57829003601f168201915b505050505081565b82800160010185558215610175579182015b82811115610175578251826000505591602001919060010190610243565b505050565b509056`}, + nil, + nil, + }, + { + "Getter", + []string{`[{"constant":true,"inputs":[],"name":"getter","outputs":[{"name":"","type":"string"},{"name":"","type":"int256"},{"name":"","type":"bytes32"}],"type":"function"}]`}, + []string{`606060405260dc8060106000396000f3606060405260e060020a6000350463993a04b78114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3`}, + nil, + nil, + }, + { + "Tupler", + []string{`[{"constant":true,"inputs":[],"name":"tuple","outputs":[{"name":"a","type":"string"},{"name":"b","type":"int256"},{"name":"c","type":"bytes32"}],"type":"function"}]`}, + []string{`606060405260dc8060106000396000f3606060405260e060020a60003504633175aae28114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3`}, + nil, + nil, + }, + { + "Slicer", + []string{`[{"constant":true,"inputs":[{"name":"input","type":"address[]"}],"name":"echoAddresses","outputs":[{"name":"output","type":"address[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"uint24[23]"}],"name":"echoFancyInts","outputs":[{"name":"output","type":"uint24[23]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"int256[]"}],"name":"echoInts","outputs":[{"name":"output","type":"int256[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"bool[]"}],"name":"echoBools","outputs":[{"name":"output","type":"bool[]"}],"type":"function"}]`}, + []string{`606060405261015c806100126000396000f3606060405260e060020a6000350463be1127a3811461003c578063d88becc014610092578063e15a3db71461003c578063f637e5891461003c575b005b604080516020600480358082013583810285810185019096528085526100ee959294602494909392850192829185019084908082843750949650505050505050604080516020810190915260009052805b919050565b604080516102e0818101909252610138916004916102e491839060179083908390808284375090955050505050506102e0604051908101604052806017905b60008152602001906001900390816100d15790505081905061008d565b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600f02600301f1509050019250505060405180910390f35b60405180826102e0808381846000600461015cf15090500191505060405180910390f3`}, + nil, + nil, + }, + { + "Structs", + []string{`[{"inputs":[],"name":"F","outputs":[{"components":[{"internalType":"bytes32","name":"B","type":"bytes32"}],"internalType":"structStructs.A[]","name":"a","type":"tuple[]"},{"internalType":"uint256[]","name":"c","type":"uint256[]"},{"internalType":"bool[]","name":"d","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"G","outputs":[{"components":[{"internalType":"bytes32","name":"B","type":"bytes32"}],"internalType":"structStructs.A[]","name":"a","type":"tuple[]"}],"stateMutability":"view","type":"function"}]`}, + []string{`608060405234801561001057600080fd5b50610278806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806328811f591461003b5780636fecb6231461005b575b600080fd5b610043610070565b604051610052939291906101a0565b60405180910390f35b6100636100d6565b6040516100529190610186565b604080516002808252606082810190935282918291829190816020015b610095610131565b81526020019060019003908161008d575050805190915061026960611b9082906000906100be57fe5b60209081029190910101515293606093508392509050565b6040805160028082526060828101909352829190816020015b6100f7610131565b8152602001906001900390816100ef575050805190915061026960611b90829060009061012057fe5b602090810291909101015152905090565b60408051602081019091526000815290565b815260200190565b6000815180845260208085019450808401835b8381101561017b578151518752958201959082019060010161015e565b509495945050505050565b600060208252610199602083018461014b565b9392505050565b6000606082526101b3606083018661014b565b6020838203818501528186516101c98185610239565b91508288019350845b818110156101f3576101e5838651610143565b9484019492506001016101d2565b505084810360408601528551808252908201925081860190845b8181101561022b57825115158552938301939183019160010161020d565b509298975050505050505050565b9081526020019056fea2646970667358221220eb85327e285def14230424c52893aebecec1e387a50bb6b75fc4fdbed647f45f64736f6c63430006050033`}, + nil, + nil, + }, + { + `Underscorer`, + []string{`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_under_scored_func","outputs":[{"name":"_int","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`}, []string{`6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029`}, + nil, + nil, + }, + { + `DeeplyNestedArray`, + []string{`[{"constant":false,"inputs":[{"name":"arr","type":"uint64[3][4][5]"}],"name":"storeDeepUintArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"retrieveDeepArray","outputs":[{"name":"","type":"uint64[3][4][5]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"deepUint64Array","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]`}, + []string{`6060604052341561000f57600080fd5b6106438061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063344248551461005c5780638ed4573a1461011457806398ed1856146101ab575b600080fd5b341561006757600080fd5b610112600480806107800190600580602002604051908101604052809291906000905b828210156101055783826101800201600480602002604051908101604052809291906000905b828210156100f25783826060020160038060200260405190810160405280929190826003602002808284378201915050505050815260200190600101906100b0565b505050508152602001906001019061008a565b5050505091905050610208565b005b341561011f57600080fd5b61012761021d565b604051808260056000925b8184101561019b578284602002015160046000925b8184101561018d5782846020020151600360200280838360005b8381101561017c578082015181840152602081019050610161565b505050509050019260010192610147565b925050509260010192610132565b9250505091505060405180910390f35b34156101b657600080fd5b6101de6004808035906020019091908035906020019091908035906020019091905050610309565b604051808267ffffffffffffffff1667ffffffffffffffff16815260200191505060405180910390f35b80600090600561021992919061035f565b5050565b6102256103b0565b6000600580602002604051908101604052809291906000905b8282101561030057838260040201600480602002604051908101604052809291906000905b828210156102ed578382016003806020026040519081016040528092919082600380156102d9576020028201916000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116102945790505b505050505081526020019060010190610263565b505050508152602001906001019061023e565b50505050905090565b60008360058110151561031857fe5b600402018260048110151561032957fe5b018160038110151561033757fe5b6004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b826005600402810192821561039f579160200282015b8281111561039e5782518290600461038e9291906103df565b5091602001919060040190610375565b5b5090506103ac919061042d565b5090565b610780604051908101604052806005905b6103c9610459565b8152602001906001900390816103c15790505090565b826004810192821561041c579160200282015b8281111561041b5782518290600361040b929190610488565b50916020019190600101906103f2565b5b5090506104299190610536565b5090565b61045691905b8082111561045257600081816104499190610562565b50600401610433565b5090565b90565b610180604051908101604052806004905b6104726105a7565b81526020019060019003908161046a5790505090565b82600380016004900481019282156105255791602002820160005b838211156104ef57835183826101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555092602001926008016020816007010492830192600103026104a3565b80156105235782816101000a81549067ffffffffffffffff02191690556008016020816007010492830192600103026104ef565b505b50905061053291906105d9565b5090565b61055f91905b8082111561055b57600081816105529190610610565b5060010161053c565b5090565b90565b50600081816105719190610610565b50600101600081816105839190610610565b50600101600081816105959190610610565b5060010160006105a59190610610565b565b6060604051908101604052806003905b600067ffffffffffffffff168152602001906001900390816105b75790505090565b61060d91905b8082111561060957600081816101000a81549067ffffffffffffffff0219169055506001016105df565b5090565b90565b50600090555600a165627a7a7230582087e5a43f6965ab6ef7a4ff056ab80ed78fd8c15cff57715a1bf34ec76a93661c0029`}, + nil, + nil, + }, + { + `CallbackParam`, + []string{`[ + { + "constant": false, + "inputs": [ + { + "name": "callback", + "type": "function" + } + ], + "name": "test", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ]`}, + []string{`608060405234801561001057600080fd5b5061015e806100206000396000f3fe60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063d7a5aba214610040575b600080fd5b34801561004c57600080fd5b506100be6004803603602081101561006357600080fd5b810190808035806c0100000000000000000000000090049068010000000000000000900463ffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff169091602001919093929190939291905050506100c0565b005b818160016040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561011657600080fd5b505af115801561012a573d6000803e3d6000fd5b50505050505056fea165627a7a7230582062f87455ff84be90896dbb0c4e4ddb505c600d23089f8e80a512548440d7e2580029`}, + nil, + nil, + }, + { + `Tuple`, + []string{` +[{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"indexed":false,"internalType":"struct Tuple.S","name":"a","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"indexed":false,"internalType":"struct Tuple.T[2][]","name":"b","type":"tuple[2][]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"indexed":false,"internalType":"struct Tuple.T[][2]","name":"c","type":"tuple[][2]"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"indexed":false,"internalType":"struct Tuple.S[]","name":"d","type":"tuple[]"},{"indexed":false,"internalType":"uint256[]","name":"e","type":"uint256[]"}],"name":"TupleEvent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint8","name":"x","type":"uint8"},{"internalType":"uint8","name":"y","type":"uint8"}],"indexed":false,"internalType":"struct Tuple.P[]","name":"","type":"tuple[]"}],"name":"TupleEvent2","type":"event"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S","name":"a","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[2][]","name":"b","type":"tuple[2][]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[][2]","name":"c","type":"tuple[][2]"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S[]","name":"d","type":"tuple[]"},{"internalType":"uint256[]","name":"e","type":"uint256[]"}],"name":"func1","outputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S","name":"","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[2][]","name":"","type":"tuple[2][]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[][2]","name":"","type":"tuple[][2]"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S","name":"a","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[2][]","name":"b","type":"tuple[2][]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[][2]","name":"c","type":"tuple[][2]"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256[]","name":"b","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Tuple.T[]","name":"c","type":"tuple[]"}],"internalType":"struct Tuple.S[]","name":"d","type":"tuple[]"},{"internalType":"uint256[]","name":"e","type":"uint256[]"}],"name":"func2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint16","name":"x","type":"uint16"},{"internalType":"uint16","name":"y","type":"uint16"}],"internalType":"struct Tuple.Q[]","name":"","type":"tuple[]"}],"name":"func3","outputs":[],"payable":false,"stateMutability":"pure","type":"function"}]`}, + []string{`60806040523480156100115760006000fd5b50610017565b6110b2806100266000396000f3fe60806040523480156100115760006000fd5b50600436106100465760003560e01c8063443c79b41461004c578063d0062cdd14610080578063e4d9a43b1461009c57610046565b60006000fd5b610066600480360361006191908101906107b8565b6100b8565b604051610077959493929190610ccb565b60405180910390f35b61009a600480360361009591908101906107b8565b6100ef565b005b6100b660048036036100b19190810190610775565b610136565b005b6100c061013a565b60606100ca61015e565b606060608989898989945094509450945094506100e2565b9550955095509550959050565b7f18d6e66efa53739ca6d13626f35ebc700b31cced3eddb50c70bbe9c082c6cd008585858585604051610126959493929190610ccb565b60405180910390a15b5050505050565b5b50565b60405180606001604052806000815260200160608152602001606081526020015090565b60405180604001604052806002905b606081526020019060019003908161016d57905050905661106e565b600082601f830112151561019d5760006000fd5b81356101b06101ab82610d6f565b610d41565b915081818352602084019350602081019050838560808402820111156101d65760006000fd5b60005b8381101561020757816101ec888261037a565b8452602084019350608083019250505b6001810190506101d9565b5050505092915050565b600082601f83011215156102255760006000fd5b600261023861023382610d98565b610d41565b9150818360005b83811015610270578135860161025588826103f3565b8452602084019350602083019250505b60018101905061023f565b5050505092915050565b600082601f830112151561028e5760006000fd5b81356102a161029c82610dbb565b610d41565b915081818352602084019350602081019050838560408402820111156102c75760006000fd5b60005b838110156102f857816102dd888261058b565b8452602084019350604083019250505b6001810190506102ca565b5050505092915050565b600082601f83011215156103165760006000fd5b813561032961032482610de4565b610d41565b9150818183526020840193506020810190508360005b83811015610370578135860161035588826105d8565b8452602084019350602083019250505b60018101905061033f565b5050505092915050565b600082601f830112151561038e5760006000fd5b60026103a161039c82610e0d565b610d41565b915081838560408402820111156103b85760006000fd5b60005b838110156103e957816103ce88826106fe565b8452602084019350604083019250505b6001810190506103bb565b5050505092915050565b600082601f83011215156104075760006000fd5b813561041a61041582610e30565b610d41565b915081818352602084019350602081019050838560408402820111156104405760006000fd5b60005b83811015610471578161045688826106fe565b8452602084019350604083019250505b600181019050610443565b5050505092915050565b600082601f830112151561048f5760006000fd5b81356104a261049d82610e59565b610d41565b915081818352602084019350602081019050838560208402820111156104c85760006000fd5b60005b838110156104f957816104de8882610760565b8452602084019350602083019250505b6001810190506104cb565b5050505092915050565b600082601f83011215156105175760006000fd5b813561052a61052582610e82565b610d41565b915081818352602084019350602081019050838560208402820111156105505760006000fd5b60005b8381101561058157816105668882610760565b8452602084019350602083019250505b600181019050610553565b5050505092915050565b60006040828403121561059e5760006000fd5b6105a86040610d41565b905060006105b88482850161074b565b60008301525060206105cc8482850161074b565b60208301525092915050565b6000606082840312156105eb5760006000fd5b6105f56060610d41565b9050600061060584828501610760565b600083015250602082013567ffffffffffffffff8111156106265760006000fd5b6106328482850161047b565b602083015250604082013567ffffffffffffffff8111156106535760006000fd5b61065f848285016103f3565b60408301525092915050565b60006060828403121561067e5760006000fd5b6106886060610d41565b9050600061069884828501610760565b600083015250602082013567ffffffffffffffff8111156106b95760006000fd5b6106c58482850161047b565b602083015250604082013567ffffffffffffffff8111156106e65760006000fd5b6106f2848285016103f3565b60408301525092915050565b6000604082840312156107115760006000fd5b61071b6040610d41565b9050600061072b84828501610760565b600083015250602061073f84828501610760565b60208301525092915050565b60008135905061075a8161103a565b92915050565b60008135905061076f81611054565b92915050565b6000602082840312156107885760006000fd5b600082013567ffffffffffffffff8111156107a35760006000fd5b6107af8482850161027a565b91505092915050565b6000600060006000600060a086880312156107d35760006000fd5b600086013567ffffffffffffffff8111156107ee5760006000fd5b6107fa8882890161066b565b955050602086013567ffffffffffffffff8111156108185760006000fd5b61082488828901610189565b945050604086013567ffffffffffffffff8111156108425760006000fd5b61084e88828901610211565b935050606086013567ffffffffffffffff81111561086c5760006000fd5b61087888828901610302565b925050608086013567ffffffffffffffff8111156108965760006000fd5b6108a288828901610503565b9150509295509295909350565b60006108bb8383610a6a565b60808301905092915050565b60006108d38383610ac2565b905092915050565b60006108e78383610c36565b905092915050565b60006108fb8383610c8d565b60408301905092915050565b60006109138383610cbc565b60208301905092915050565b600061092a82610f0f565b6109348185610fb7565b935061093f83610eab565b8060005b8381101561097157815161095788826108af565b975061096283610f5c565b9250505b600181019050610943565b5085935050505092915050565b600061098982610f1a565b6109938185610fc8565b9350836020820285016109a585610ebb565b8060005b858110156109e257848403895281516109c285826108c7565b94506109cd83610f69565b925060208a019950505b6001810190506109a9565b50829750879550505050505092915050565b60006109ff82610f25565b610a098185610fd3565b935083602082028501610a1b85610ec5565b8060005b85811015610a585784840389528151610a3885826108db565b9450610a4383610f76565b925060208a019950505b600181019050610a1f565b50829750879550505050505092915050565b610a7381610f30565b610a7d8184610fe4565b9250610a8882610ed5565b8060005b83811015610aba578151610aa087826108ef565b9650610aab83610f83565b9250505b600181019050610a8c565b505050505050565b6000610acd82610f3b565b610ad78185610fef565b9350610ae283610edf565b8060005b83811015610b14578151610afa88826108ef565b9750610b0583610f90565b9250505b600181019050610ae6565b5085935050505092915050565b6000610b2c82610f51565b610b368185611011565b9350610b4183610eff565b8060005b83811015610b73578151610b598882610907565b9750610b6483610faa565b9250505b600181019050610b45565b5085935050505092915050565b6000610b8b82610f46565b610b958185611000565b9350610ba083610eef565b8060005b83811015610bd2578151610bb88882610907565b9750610bc383610f9d565b9250505b600181019050610ba4565b5085935050505092915050565b6000606083016000830151610bf76000860182610cbc565b5060208301518482036020860152610c0f8282610b80565b91505060408301518482036040860152610c298282610ac2565b9150508091505092915050565b6000606083016000830151610c4e6000860182610cbc565b5060208301518482036020860152610c668282610b80565b91505060408301518482036040860152610c808282610ac2565b9150508091505092915050565b604082016000820151610ca36000850182610cbc565b506020820151610cb66020850182610cbc565b50505050565b610cc581611030565b82525050565b600060a0820190508181036000830152610ce58188610bdf565b90508181036020830152610cf9818761091f565b90508181036040830152610d0d818661097e565b90508181036060830152610d2181856109f4565b90508181036080830152610d358184610b21565b90509695505050505050565b6000604051905081810181811067ffffffffffffffff82111715610d655760006000fd5b8060405250919050565b600067ffffffffffffffff821115610d875760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610db05760006000fd5b602082029050919050565b600067ffffffffffffffff821115610dd35760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610dfc5760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e255760006000fd5b602082029050919050565b600067ffffffffffffffff821115610e485760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e715760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e9a5760006000fd5b602082029050602081019050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600061ffff82169050919050565b6000819050919050565b61104381611022565b811415156110515760006000fd5b50565b61105d81611030565b8114151561106b5760006000fd5b50565bfea365627a7a72315820d78c6ba7ee332581e6c4d9daa5fc07941841230f7ce49edf6e05b1b63853e8746c6578706572696d656e74616cf564736f6c634300050c0040`}, + nil, + nil, + }, + { + "Overload", + []string{`[{"constant":false,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`}, + []string{`608060405234801561001057600080fd5b50610153806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806304bc52f81461003b5780632fbebd3814610073575b600080fd5b6100716004803603604081101561005157600080fd5b8101908080359060200190929190803590602001909291905050506100a1565b005b61009f6004803603602081101561008957600080fd5b81019080803590602001909291905050506100e4565b005b7fae42e9514233792a47a1e4554624e83fe852228e1503f63cd383e8a431f4f46d8282604051808381526020018281526020019250505060405180910390a15050565b7f0423a1321222a0a8716c22b92fac42d85a45a612b696a461784d9fa537c81e5c816040518082815260200191505060405180910390a15056fea265627a7a72305820e22b049858b33291cbe67eeaece0c5f64333e439d27032ea8337d08b1de18fe864736f6c634300050a0032`}, + nil, + nil, + }, + { + "IdentifierCollision", + []string{`[{"constant":true,"inputs":[],"name":"MyVar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_myVar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]`}, + []string{"60806040523480156100115760006000fd5b50610017565b60c3806100256000396000f3fe608060405234801560105760006000fd5b506004361060365760003560e01c806301ad4d8714603c5780634ef1f0ad146058576036565b60006000fd5b60426074565b6040518082815260200191505060405180910390f35b605e607d565b6040518082815260200191505060405180910390f35b60006000505481565b60006000600050549050608b565b9056fea265627a7a7231582067c8d84688b01c4754ba40a2a871cede94ea1f28b5981593ab2a45b46ac43af664736f6c634300050c0032"}, + nil, + map[string]string{"_myVar": "pubVar"}, // alias MyVar to PubVar,\ + }, + { + "NameConflict", + []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, + []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"}, + nil, + nil, + }, + { + "RangeKeyword", + []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`}, + []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"}, + nil, + nil, + }, + { + "NumericMethodName", + []string{`[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_param","type":"address"}],"name":"_1TestEvent","type":"event"},{"inputs":[],"name":"_1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__2test","outputs":[],"stateMutability":"pure","type":"function"}]`}, + []string{"0x6080604052348015600f57600080fd5b5060958061001e6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80639d993132146041578063d02767c7146049578063ffa02795146051575b600080fd5b60476059565b005b604f605b565b005b6057605d565b005b565b565b56fea26469706673582212200382ca602dff96a7e2ba54657985e2b4ac423a56abe4a1f0667bc635c4d4371f64736f6c63430008110033"}, + nil, + nil, + }, + { + "Structs", + []string{`[{"inputs":[],"name":"F","outputs":[{"components":[{"internalType":"bytes32","name":"B","type":"bytes32"}],"internalType":"structStructs.A[]","name":"a","type":"tuple[]"},{"internalType":"uint256[]","name":"c","type":"uint256[]"},{"internalType":"bool[]","name":"d","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"G","outputs":[{"components":[{"internalType":"bytes32","name":"B","type":"bytes32"}],"internalType":"structStructs.A[]","name":"a","type":"tuple[]"}],"stateMutability":"view","type":"function"}]`}, + []string{`608060405234801561001057600080fd5b50610278806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806328811f591461003b5780636fecb6231461005b575b600080fd5b610043610070565b604051610052939291906101a0565b60405180910390f35b6100636100d6565b6040516100529190610186565b604080516002808252606082810190935282918291829190816020015b610095610131565b81526020019060019003908161008d575050805190915061026960611b9082906000906100be57fe5b60209081029190910101515293606093508392509050565b6040805160028082526060828101909352829190816020015b6100f7610131565b8152602001906001900390816100ef575050805190915061026960611b90829060009061012057fe5b602090810291909101015152905090565b60408051602081019091526000815290565b815260200190565b6000815180845260208085019450808401835b8381101561017b578151518752958201959082019060010161015e565b509495945050505050565b600060208252610199602083018461014b565b9392505050565b6000606082526101b3606083018661014b565b6020838203818501528186516101c98185610239565b91508288019350845b818110156101f3576101e5838651610143565b9484019492506001016101d2565b505084810360408601528551808252908201925081860190845b8181101561022b57825115158552938301939183019160010161020d565b509298975050505050505050565b9081526020019056fea2646970667358221220eb85327e285def14230424c52893aebecec1e387a50bb6b75fc4fdbed647f45f64736f6c63430006050033`}, + nil, + nil, + }, +} + +// TestBindingV2ConvertedV1Tests regenerates contracts from the v1 binding test +// cases (using v2 binding mode) and ensures that no mutations occurred compared +// to the expected output included under testdata/v2. +func TestBindingV2ConvertedV1Tests(t *testing.T) { + for _, tc := range combinedJSONBindTestsV2 { + fname := fmt.Sprintf("testdata/v2/%v.go.txt", strings.ToLower(tc.name)) + t.Run(tc.name, func(t *testing.T) { + if tc.types == nil { + tc.types = []string{tc.name} + } + have, err := bindCombinedJSON(&tc) + if err != nil { + t.Fatalf("got error from bindCombinedJSON: %v", err) + } + // Set this environment variable to regenerate the test outputs. + if os.Getenv("WRITE_TEST_FILES") != "" { + if err := os.WriteFile((fname), []byte(have), 0666); err != nil { + t.Fatalf("err writing expected output to file: %v\n", err) + } + } + // Verify the generated code + want, err := os.ReadFile(fname) + if err != nil { + t.Fatalf("failed to read file %v", fname) + } + if have != string(want) { + t.Fatalf("wrong output: %v", prettyDiff(have, string(want))) + } + }) + } +} + +func TestNormalizeArgs(t *testing.T) { + type normalizeArgsTc struct { + inp []string + expected []string + } + for i, tc := range []normalizeArgsTc{ + {[]string{"arg1", "arg1"}, []string{"arg1", "arg10"}}, + {[]string{"", ""}, []string{"arg0", "arg1"}}, + {[]string{"var", "const"}, []string{"arg0", "arg1"}}, + {[]string{"_res", "Res"}, []string{"res", "res0"}}, + {[]string{"_", "__"}, []string{"arg0", "arg1"}}} { + var inpArgs abi.Arguments + for _, inpArgName := range tc.inp { + inpArgs = append(inpArgs, abi.Argument{ + Name: inpArgName, + }) + } + res := normalizeArgs(inpArgs) + for j, resArg := range res { + if resArg.Name != tc.expected[j] { + t.Fatalf("mismatch for test index %d, arg index %d: expected %v. got %v", i, j, tc.expected[j], resArg.Name) + } + } + } +} + +// returns a "pretty diff" on two strings. Useful if the strings are large. +func prettyDiff(have, want string) string { + if have == want { + return "" + } + var i = 0 + for ; i < len(want) && i < len(have); i++ { + if want[i] != have[i] { + break + } + } + s := max(0, i-50) + he := min(len(have), i+50) + we := min(len(want), i+50) + return fmt.Sprintf("diff after %d characters\nhave: ...%q...\nwant: ...%q...\n", + i, have[s:he], want[s:we]) +} diff --git a/accounts/abi/bind/source.go.tpl b/accounts/abi/abigen/source.go.tpl similarity index 100% rename from accounts/abi/bind/source.go.tpl rename to accounts/abi/abigen/source.go.tpl diff --git a/accounts/abi/abigen/source2.go.tpl b/accounts/abi/abigen/source2.go.tpl new file mode 100644 index 000000000..8f9d4d410 --- /dev/null +++ b/accounts/abi/abigen/source2.go.tpl @@ -0,0 +1,238 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package {{.Package}} + +import ( + "bytes" + "math/big" + "errors" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +{{$structs := .Structs}} +{{range $structs}} + // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. + type {{.Name}} struct { + {{range $field := .Fields}} + {{capitalise $field.Name}} {{$field.Type}}{{end}} + } +{{end}} + +{{range $contract := .Contracts}} + // {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract. + var {{.Type}}MetaData = bind.MetaData{ + ABI: "{{.InputABI}}", + {{if (index $.Libraries .Type) -}} + ID: "{{index $.Libraries .Type}}", + {{ else -}} + ID: "{{.Type}}", + {{end -}} + {{if .InputBin -}} + Bin: "0x{{.InputBin}}", + {{end -}} + {{if .Libraries -}} + Deps: []*bind.MetaData{ + {{- range $name, $pattern := .Libraries}} + &{{$name}}MetaData, + {{- end}} + }, + {{end}} + } + + // {{.Type}} is an auto generated Go binding around an Ethereum contract. + type {{.Type}} struct { + abi abi.ABI + } + + // New{{.Type}} creates a new instance of {{.Type}}. + func New{{.Type}}() *{{.Type}} { + parsed, err := {{.Type}}MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &{{.Type}}{abi: *parsed} + } + + // Instance creates a wrapper for a deployed contract instance at the given address. + // Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. + func (c *{{.Type}}) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) + } + + {{ if .Constructor.Inputs }} + // PackConstructor is the Go binding used to pack the parameters required for + // contract deployment. + // + // Solidity: {{.Constructor.String}} + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) PackConstructor({{range .Constructor.Inputs}} {{.Name}} {{bindtype .Type $structs}}, {{end}}) []byte { + enc, err := {{ decapitalise $contract.Type}}.abi.Pack("" {{range .Constructor.Inputs}}, {{.Name}}{{end}}) + if err != nil { + panic(err) + } + return enc + } + {{ end }} + + {{range .Calls}} + // Pack{{.Normalized.Name}} is the Go binding used to pack the parameters required for calling + // the contract method with ID 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Pack{{.Normalized.Name}}({{range .Normalized.Inputs}} {{.Name}} {{bindtype .Type $structs}}, {{end}}) []byte { + enc, err := {{ decapitalise $contract.Type}}.abi.Pack("{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + if err != nil { + panic(err) + } + return enc + } + + {{/* Unpack method is needed only when there are return args */}} + {{if .Normalized.Outputs }} + {{ if .Structured }} + // {{.Normalized.Name}}Output serves as a container for the return parameters of contract + // method {{ .Normalized.Name }}. + type {{.Normalized.Name}}Output struct { + {{range .Normalized.Outputs}} + {{capitalise .Name}} {{bindtype .Type $structs}}{{end}} + } + {{ end }} + + // Unpack{{.Normalized.Name}} is the Go binding that unpacks the parameters returned + // from invoking the contract method with ID 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Unpack{{.Normalized.Name}}(data []byte) ( + {{- if .Structured}} {{.Normalized.Name}}Output,{{else}} + {{- range .Normalized.Outputs}} {{bindtype .Type $structs}},{{- end }} + {{- end }} error) { + out, err := {{ decapitalise $contract.Type}}.abi.Unpack("{{.Original.Name}}", data) + {{- if .Structured}} + outstruct := new({{.Normalized.Name}}Output) + if err != nil { + return *outstruct, err + } + {{- range $i, $t := .Normalized.Outputs}} + {{- if ispointertype .Type}} + outstruct.{{capitalise .Name}} = abi.ConvertType(out[{{$i}}], new({{underlyingbindtype .Type }})).({{bindtype .Type $structs}}) + {{- else }} + outstruct.{{capitalise .Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}) + {{- end }} + {{- end }} + return *outstruct, err + {{else}} + if err != nil { + return {{range $i, $_ := .Normalized.Outputs}}{{if ispointertype .Type}}new({{underlyingbindtype .Type }}), {{else}}*new({{bindtype .Type $structs}}), {{end}}{{end}} err + } + {{- range $i, $t := .Normalized.Outputs}} + {{- if ispointertype .Type }} + out{{$i}} := abi.ConvertType(out[{{$i}}], new({{underlyingbindtype .Type}})).({{bindtype .Type $structs}}) + {{- else }} + out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}) + {{- end }} + {{- end}} + return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err + {{- end}} + } + {{end}} + {{end}} + + {{range .Events}} + // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Original.Name}} event raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}} struct { + {{- range .Normalized.Inputs}} + {{ capitalise .Name}} + {{- if .Indexed}} {{ bindtopictype .Type $structs}}{{- else}} {{ bindtype .Type $structs}}{{ end }} + {{- end}} + Raw *types.Log // Blockchain specific contextual infos + } + + const {{$contract.Type}}{{.Normalized.Name}}EventName = "{{.Original.Name}}" + + // ContractEventName returns the user-defined event name. + func ({{$contract.Type}}{{.Normalized.Name}}) ContractEventName() string { + return {{$contract.Type}}{{.Normalized.Name}}EventName + } + + // Unpack{{.Normalized.Name}}Event is the Go binding that unpacks the event data emitted + // by contract. + // + // Solidity: {{.Original.String}} + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Unpack{{.Normalized.Name}}Event(log *types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { + event := "{{.Original.Name}}" + if log.Topics[0] != {{ decapitalise $contract.Type}}.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new({{$contract.Type}}{{.Normalized.Name}}) + if len(log.Data) > 0 { + if err := {{ decapitalise $contract.Type}}.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range {{ decapitalise $contract.Type}}.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil + } + {{end}} + + {{ if .Errors }} + // UnpackError attempts to decode the provided error data using user-defined + // error definitions. + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) UnpackError(raw []byte) (any, error) { + {{- range $k, $v := .Errors}} + if bytes.Equal(raw[:4], {{ decapitalise $contract.Type}}.abi.Errors["{{.Normalized.Name}}"].ID.Bytes()[:4]) { + return {{ decapitalise $contract.Type}}.Unpack{{.Normalized.Name}}Error(raw[4:]) + } + {{- end }} + return nil, errors.New("Unknown error") + } + {{ end }} + + {{range .Errors}} + // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Original.Name}} error raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} + {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}} + } + + // ErrorID returns the hash of canonical representation of the error's signature. + // + // Solidity: {{.Original.String}} + func {{$contract.Type}}{{.Normalized.Name}}ErrorID() common.Hash { + return common.HexToHash("{{.Original.ID}}") + } + + // Unpack{{.Normalized.Name}}Error is the Go binding used to decode the provided + // error data into the corresponding Go error struct. + // + // Solidity: {{.Original.String}} + func ({{ decapitalise $contract.Type}} *{{$contract.Type}}) Unpack{{.Normalized.Name}}Error(raw []byte) (*{{$contract.Type}}{{.Normalized.Name}}, error) { + out := new({{$contract.Type}}{{.Normalized.Name}}) + if err := {{ decapitalise $contract.Type}}.abi.UnpackIntoInterface(out, "{{.Normalized.Name}}", raw); err != nil { + return nil, err + } + return out, nil + } + {{end}} +{{end}} diff --git a/accounts/abi/bind/template.go b/accounts/abi/abigen/template.go similarity index 64% rename from accounts/abi/bind/template.go rename to accounts/abi/abigen/template.go index 4a0062af0..cbb21037a 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/abigen/template.go @@ -14,10 +14,12 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package bind +package abigen import ( _ "embed" + "strings" + "unicode" "github.com/ethereum/go-ethereum/accounts/abi" ) @@ -42,10 +44,48 @@ type tmplContract struct { Fallback *tmplMethod // Additional special fallback function Receive *tmplMethod // Additional special receive function Events map[string]*tmplEvent // Contract events accessors - Libraries map[string]string // Same as tmplData, but filtered to only keep what the contract needs + Libraries map[string]string // Same as tmplData, but filtered to only keep direct deps that the contract needs Library bool // Indicator whether the contract is a library } +type tmplContractV2 struct { + Type string // Type name of the main contract binding + InputABI string // JSON ABI used as the input to generate the binding from + InputBin string // Optional EVM bytecode used to generate deploy code from + Constructor abi.Method // Contract constructor for deploy parametrization + Calls map[string]*tmplMethod // All contract methods (excluding fallback, receive) + Events map[string]*tmplEvent // Contract events accessors + Libraries map[string]string // all direct library dependencies + Errors map[string]*tmplError // all errors defined +} + +func newTmplContractV2(typ string, abiStr string, bytecode string, constructor abi.Method, cb *contractBinder) *tmplContractV2 { + // Strip any whitespace from the JSON ABI + strippedABI := strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return -1 + } + return r + }, abiStr) + return &tmplContractV2{ + abi.ToCamelCase(typ), + strings.ReplaceAll(strippedABI, "\"", "\\\""), + strings.TrimPrefix(strings.TrimSpace(bytecode), "0x"), + constructor, + cb.calls, + cb.events, + make(map[string]string), + cb.errors, + } +} + +type tmplDataV2 struct { + Package string // Name of the package to use for the generated bindings + Contracts map[string]*tmplContractV2 // Contracts that will be emitted in the bindings (keyed by contract name) + Libraries map[string]string // Map of the contract's name to link pattern + Structs map[string]*tmplStruct // Contract struct type definitions +} + // tmplMethod is a wrapper around an abi.Method that contains a few preprocessed // and cached data fields. type tmplMethod struct { @@ -61,6 +101,13 @@ type tmplEvent struct { Normalized abi.Event // Normalized version of the parsed fields } +// tmplError is a wrapper around an abi.Error that contains a few preprocessed +// and cached data fields. +type tmplError struct { + Original abi.Error + Normalized abi.Error +} + // tmplField is a wrapper around a struct field with binding language // struct type definition and relative filed name. type tmplField struct { @@ -76,14 +123,14 @@ type tmplStruct struct { Fields []*tmplField // Struct fields definition depends on the binding language. } -// tmplSource is language to template mapping containing all the supported -// programming languages the package can generate to. -var tmplSource = map[Lang]string{ - LangGo: tmplSourceGo, -} - -// tmplSourceGo is the Go source template that the generated Go contract binding +// tmplSource is the Go source template that the generated Go contract binding // is based on. // //go:embed source.go.tpl -var tmplSourceGo string +var tmplSource string + +// tmplSourceV2 is the Go source template that the generated Go contract binding +// for abigen v2 is based on. +// +//go:embed source2.go.tpl +var tmplSourceV2 string diff --git a/accounts/abi/abigen/testdata/v2/callbackparam.go.txt b/accounts/abi/abigen/testdata/v2/callbackparam.go.txt new file mode 100644 index 000000000..e3205bde0 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/callbackparam.go.txt @@ -0,0 +1,64 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// CallbackParamMetaData contains all meta data concerning the CallbackParam contract. +var CallbackParamMetaData = bind.MetaData{ + ABI: "[{\"constant\":false,\"inputs\":[{\"name\":\"callback\",\"type\":\"function\"}],\"name\":\"test\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ID: "949f96f86d3c2e1bcc15563ad898beaaca", + Bin: "0x608060405234801561001057600080fd5b5061015e806100206000396000f3fe60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063d7a5aba214610040575b600080fd5b34801561004c57600080fd5b506100be6004803603602081101561006357600080fd5b810190808035806c0100000000000000000000000090049068010000000000000000900463ffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff169091602001919093929190939291905050506100c0565b005b818160016040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561011657600080fd5b505af115801561012a573d6000803e3d6000fd5b50505050505056fea165627a7a7230582062f87455ff84be90896dbb0c4e4ddb505c600d23089f8e80a512548440d7e2580029", +} + +// CallbackParam is an auto generated Go binding around an Ethereum contract. +type CallbackParam struct { + abi abi.ABI +} + +// NewCallbackParam creates a new instance of CallbackParam. +func NewCallbackParam() *CallbackParam { + parsed, err := CallbackParamMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &CallbackParam{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *CallbackParam) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackTest is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd7a5aba2. +// +// Solidity: function test(function callback) returns() +func (callbackParam *CallbackParam) PackTest(callback [24]byte) []byte { + enc, err := callbackParam.abi.Pack("test", callback) + if err != nil { + panic(err) + } + return enc +} diff --git a/accounts/abi/abigen/testdata/v2/crowdsale.go.txt b/accounts/abi/abigen/testdata/v2/crowdsale.go.txt new file mode 100644 index 000000000..60d8b4ec1 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/crowdsale.go.txt @@ -0,0 +1,304 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// CrowdsaleMetaData contains all meta data concerning the Crowdsale contract. +var CrowdsaleMetaData = bind.MetaData{ + ABI: "[{\"constant\":false,\"inputs\":[],\"name\":\"checkGoalReached\",\"outputs\":[],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"deadline\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"beneficiary\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tokenReward\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"fundingGoal\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"amountRaised\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"price\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"funders\",\"outputs\":[{\"name\":\"addr\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"inputs\":[{\"name\":\"ifSuccessfulSendTo\",\"type\":\"address\"},{\"name\":\"fundingGoalInEthers\",\"type\":\"uint256\"},{\"name\":\"durationInMinutes\",\"type\":\"uint256\"},{\"name\":\"etherCostOfEachToken\",\"type\":\"uint256\"},{\"name\":\"addressOfTokenUsedAsReward\",\"type\":\"address\"}],\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"backer\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"isContribution\",\"type\":\"bool\"}],\"name\":\"FundTransfer\",\"type\":\"event\"}]", + ID: "84d7e935785c5c648282d326307bb8fa0d", + Bin: "0x606060408190526007805460ff1916905560a0806105a883396101006040529051608051915160c05160e05160008054600160a060020a03199081169095178155670de0b6b3a7640000958602600155603c9093024201600355930260045560058054909216909217905561052f90819061007990396000f36060604052361561006c5760e060020a600035046301cb3b20811461008257806329dcb0cf1461014457806338af3eed1461014d5780636e66f6e91461015f5780637a3a0e84146101715780637b3e5e7b1461017a578063a035b1fe14610183578063dc0d3dff1461018c575b61020060075460009060ff161561032357610002565b61020060035460009042106103205760025460015490106103cb576002548154600160a060020a0316908290606082818181858883f150915460025460408051600160a060020a039390931683526020830191909152818101869052517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6945090819003909201919050a15b60405160008054600160a060020a039081169230909116319082818181858883f150506007805460ff1916600117905550505050565b6103a160035481565b6103ab600054600160a060020a031681565b6103ab600554600160a060020a031681565b6103a160015481565b6103a160025481565b6103a160045481565b6103be60043560068054829081101561000257506000526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f8101547ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d409190910154600160a060020a03919091169082565b005b505050815481101561000257906000526020600020906002020160005060008201518160000160006101000a815481600160a060020a030219169083021790555060208201518160010160005055905050806002600082828250540192505081905550600560009054906101000a9004600160a060020a0316600160a060020a031663a9059cbb3360046000505484046040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506000604051808303816000876161da5a03f11561000257505060408051600160a060020a03331681526020810184905260018183015290517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf692509081900360600190a15b50565b5060a0604052336060908152346080819052600680546001810180835592939282908280158290116102025760020281600202836000526020600020918201910161020291905b8082111561039d57805473ffffffffffffffffffffffffffffffffffffffff19168155600060019190910190815561036a565b5090565b6060908152602090f35b600160a060020a03166060908152602090f35b6060918252608052604090f35b5b60065481101561010e576006805482908110156100025760009182526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0190600680549254600160a060020a0316928490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460405190915082818181858883f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf660066000508281548110156100025760008290526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01548154600160a060020a039190911691908490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460408051600160a060020a0394909416845260208401919091526000838201525191829003606001919050a16001016103cc56", +} + +// Crowdsale is an auto generated Go binding around an Ethereum contract. +type Crowdsale struct { + abi abi.ABI +} + +// NewCrowdsale creates a new instance of Crowdsale. +func NewCrowdsale() *Crowdsale { + parsed, err := CrowdsaleMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Crowdsale{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Crowdsale) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(address ifSuccessfulSendTo, uint256 fundingGoalInEthers, uint256 durationInMinutes, uint256 etherCostOfEachToken, address addressOfTokenUsedAsReward) returns() +func (crowdsale *Crowdsale) PackConstructor(ifSuccessfulSendTo common.Address, fundingGoalInEthers *big.Int, durationInMinutes *big.Int, etherCostOfEachToken *big.Int, addressOfTokenUsedAsReward common.Address) []byte { + enc, err := crowdsale.abi.Pack("", ifSuccessfulSendTo, fundingGoalInEthers, durationInMinutes, etherCostOfEachToken, addressOfTokenUsedAsReward) + if err != nil { + panic(err) + } + return enc +} + +// PackAmountRaised is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x7b3e5e7b. +// +// Solidity: function amountRaised() returns(uint256) +func (crowdsale *Crowdsale) PackAmountRaised() []byte { + enc, err := crowdsale.abi.Pack("amountRaised") + if err != nil { + panic(err) + } + return enc +} + +// UnpackAmountRaised is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x7b3e5e7b. +// +// Solidity: function amountRaised() returns(uint256) +func (crowdsale *Crowdsale) UnpackAmountRaised(data []byte) (*big.Int, error) { + out, err := crowdsale.abi.Unpack("amountRaised", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackBeneficiary is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x38af3eed. +// +// Solidity: function beneficiary() returns(address) +func (crowdsale *Crowdsale) PackBeneficiary() []byte { + enc, err := crowdsale.abi.Pack("beneficiary") + if err != nil { + panic(err) + } + return enc +} + +// UnpackBeneficiary is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x38af3eed. +// +// Solidity: function beneficiary() returns(address) +func (crowdsale *Crowdsale) UnpackBeneficiary(data []byte) (common.Address, error) { + out, err := crowdsale.abi.Unpack("beneficiary", data) + if err != nil { + return *new(common.Address), err + } + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + return out0, err +} + +// PackCheckGoalReached is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x01cb3b20. +// +// Solidity: function checkGoalReached() returns() +func (crowdsale *Crowdsale) PackCheckGoalReached() []byte { + enc, err := crowdsale.abi.Pack("checkGoalReached") + if err != nil { + panic(err) + } + return enc +} + +// PackDeadline is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x29dcb0cf. +// +// Solidity: function deadline() returns(uint256) +func (crowdsale *Crowdsale) PackDeadline() []byte { + enc, err := crowdsale.abi.Pack("deadline") + if err != nil { + panic(err) + } + return enc +} + +// UnpackDeadline is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x29dcb0cf. +// +// Solidity: function deadline() returns(uint256) +func (crowdsale *Crowdsale) UnpackDeadline(data []byte) (*big.Int, error) { + out, err := crowdsale.abi.Unpack("deadline", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackFunders is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xdc0d3dff. +// +// Solidity: function funders(uint256 ) returns(address addr, uint256 amount) +func (crowdsale *Crowdsale) PackFunders(arg0 *big.Int) []byte { + enc, err := crowdsale.abi.Pack("funders", arg0) + if err != nil { + panic(err) + } + return enc +} + +// FundersOutput serves as a container for the return parameters of contract +// method Funders. +type FundersOutput struct { + Addr common.Address + Amount *big.Int +} + +// UnpackFunders is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xdc0d3dff. +// +// Solidity: function funders(uint256 ) returns(address addr, uint256 amount) +func (crowdsale *Crowdsale) UnpackFunders(data []byte) (FundersOutput, error) { + out, err := crowdsale.abi.Unpack("funders", data) + outstruct := new(FundersOutput) + if err != nil { + return *outstruct, err + } + outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.Amount = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackFundingGoal is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x7a3a0e84. +// +// Solidity: function fundingGoal() returns(uint256) +func (crowdsale *Crowdsale) PackFundingGoal() []byte { + enc, err := crowdsale.abi.Pack("fundingGoal") + if err != nil { + panic(err) + } + return enc +} + +// UnpackFundingGoal is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x7a3a0e84. +// +// Solidity: function fundingGoal() returns(uint256) +func (crowdsale *Crowdsale) UnpackFundingGoal(data []byte) (*big.Int, error) { + out, err := crowdsale.abi.Unpack("fundingGoal", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackPrice is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xa035b1fe. +// +// Solidity: function price() returns(uint256) +func (crowdsale *Crowdsale) PackPrice() []byte { + enc, err := crowdsale.abi.Pack("price") + if err != nil { + panic(err) + } + return enc +} + +// UnpackPrice is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xa035b1fe. +// +// Solidity: function price() returns(uint256) +func (crowdsale *Crowdsale) UnpackPrice(data []byte) (*big.Int, error) { + out, err := crowdsale.abi.Unpack("price", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackTokenReward is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x6e66f6e9. +// +// Solidity: function tokenReward() returns(address) +func (crowdsale *Crowdsale) PackTokenReward() []byte { + enc, err := crowdsale.abi.Pack("tokenReward") + if err != nil { + panic(err) + } + return enc +} + +// UnpackTokenReward is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x6e66f6e9. +// +// Solidity: function tokenReward() returns(address) +func (crowdsale *Crowdsale) UnpackTokenReward(data []byte) (common.Address, error) { + out, err := crowdsale.abi.Unpack("tokenReward", data) + if err != nil { + return *new(common.Address), err + } + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + return out0, err +} + +// CrowdsaleFundTransfer represents a FundTransfer event raised by the Crowdsale contract. +type CrowdsaleFundTransfer struct { + Backer common.Address + Amount *big.Int + IsContribution bool + Raw *types.Log // Blockchain specific contextual infos +} + +const CrowdsaleFundTransferEventName = "FundTransfer" + +// ContractEventName returns the user-defined event name. +func (CrowdsaleFundTransfer) ContractEventName() string { + return CrowdsaleFundTransferEventName +} + +// UnpackFundTransferEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event FundTransfer(address backer, uint256 amount, bool isContribution) +func (crowdsale *Crowdsale) UnpackFundTransferEvent(log *types.Log) (*CrowdsaleFundTransfer, error) { + event := "FundTransfer" + if log.Topics[0] != crowdsale.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(CrowdsaleFundTransfer) + if len(log.Data) > 0 { + if err := crowdsale.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range crowdsale.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/dao.go.txt b/accounts/abi/abigen/testdata/v2/dao.go.txt new file mode 100644 index 000000000..72a80949f --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/dao.go.txt @@ -0,0 +1,655 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// DAOMetaData contains all meta data concerning the DAO contract. +var DAOMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"proposals\",\"outputs\":[{\"name\":\"recipient\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"votingDeadline\",\"type\":\"uint256\"},{\"name\":\"executed\",\"type\":\"bool\"},{\"name\":\"proposalPassed\",\"type\":\"bool\"},{\"name\":\"numberOfVotes\",\"type\":\"uint256\"},{\"name\":\"currentResult\",\"type\":\"int256\"},{\"name\":\"proposalHash\",\"type\":\"bytes32\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"proposalNumber\",\"type\":\"uint256\"},{\"name\":\"transactionBytecode\",\"type\":\"bytes\"}],\"name\":\"executeProposal\",\"outputs\":[{\"name\":\"result\",\"type\":\"int256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"memberId\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"numProposals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"members\",\"outputs\":[{\"name\":\"member\",\"type\":\"address\"},{\"name\":\"canVote\",\"type\":\"bool\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"memberSince\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"debatingPeriodInMinutes\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minimumQuorum\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"targetMember\",\"type\":\"address\"},{\"name\":\"canVote\",\"type\":\"bool\"},{\"name\":\"memberName\",\"type\":\"string\"}],\"name\":\"changeMembership\",\"outputs\":[],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"majorityMargin\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"beneficiary\",\"type\":\"address\"},{\"name\":\"etherAmount\",\"type\":\"uint256\"},{\"name\":\"JobDescription\",\"type\":\"string\"},{\"name\":\"transactionBytecode\",\"type\":\"bytes\"}],\"name\":\"newProposal\",\"outputs\":[{\"name\":\"proposalID\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"minimumQuorumForProposals\",\"type\":\"uint256\"},{\"name\":\"minutesForDebate\",\"type\":\"uint256\"},{\"name\":\"marginOfVotesForMajority\",\"type\":\"int256\"}],\"name\":\"changeVotingRules\",\"outputs\":[],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"proposalNumber\",\"type\":\"uint256\"},{\"name\":\"supportsProposal\",\"type\":\"bool\"},{\"name\":\"justificationText\",\"type\":\"string\"}],\"name\":\"vote\",\"outputs\":[{\"name\":\"voteID\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"proposalNumber\",\"type\":\"uint256\"},{\"name\":\"beneficiary\",\"type\":\"address\"},{\"name\":\"etherAmount\",\"type\":\"uint256\"},{\"name\":\"transactionBytecode\",\"type\":\"bytes\"}],\"name\":\"checkProposalCode\",\"outputs\":[{\"name\":\"codeChecksOut\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"type\":\"function\"},{\"inputs\":[{\"name\":\"minimumQuorumForProposals\",\"type\":\"uint256\"},{\"name\":\"minutesForDebate\",\"type\":\"uint256\"},{\"name\":\"marginOfVotesForMajority\",\"type\":\"int256\"},{\"name\":\"congressLeader\",\"type\":\"address\"}],\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"proposalID\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"description\",\"type\":\"string\"}],\"name\":\"ProposalAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"proposalID\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"position\",\"type\":\"bool\"},{\"indexed\":false,\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"justification\",\"type\":\"string\"}],\"name\":\"Voted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"proposalID\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"result\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"quorum\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"active\",\"type\":\"bool\"}],\"name\":\"ProposalTallied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"member\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"isMember\",\"type\":\"bool\"}],\"name\":\"MembershipChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"minimumQuorum\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"debatingPeriodInMinutes\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"majorityMargin\",\"type\":\"int256\"}],\"name\":\"ChangeOfRules\",\"type\":\"event\"}]", + ID: "d0a4ad96d49edb1c33461cebc6fb260919", + Bin: "0x606060405260405160808061145f833960e06040529051905160a05160c05160008054600160a060020a03191633179055600184815560028490556003839055600780549182018082558280158290116100b8576003028160030283600052602060002091820191016100b891906101c8565b50506060919091015160029190910155600160a060020a0381166000146100a65760008054600160a060020a031916821790555b505050506111f18061026e6000396000f35b505060408051608081018252600080825260208281018290528351908101845281815292820192909252426060820152600780549194509250811015610002579081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889050815181546020848101517401000000000000000000000000000000000000000002600160a060020a03199290921690921760a060020a60ff021916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f9081018390048201949192919091019083901061023e57805160ff19168380011785555b50610072929150610226565b5050600060028201556001015b8082111561023a578054600160a860020a031916815560018181018054600080835592600290821615610100026000190190911604601f81901061020c57506101bb565b601f0160209004906000526020600020908101906101bb91905b8082111561023a5760008155600101610226565b5090565b828001600101855582156101af579182015b828111156101af57825182600050559160200191906001019061025056606060405236156100b95760e060020a6000350463013cf08b81146100bb578063237e9492146101285780633910682114610281578063400e3949146102995780635daf08ca146102a257806369bd34361461032f5780638160f0b5146103385780638da5cb5b146103415780639644fcbd14610353578063aa02a90f146103be578063b1050da5146103c7578063bcca1fd3146104b5578063d3c0715b146104dc578063eceb29451461058d578063f2fde38b1461067b575b005b61069c6004356004805482908110156100025790600052602060002090600a02016000506005810154815460018301546003840154600485015460068601546007870154600160a060020a03959095169750929560020194919360ff828116946101009093041692919089565b60408051602060248035600481810135601f81018590048502860185019096528585526107759581359591946044949293909201918190840183828082843750949650505050505050600060006004600050848154811015610002575090527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19e600a8402908101547f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b909101904210806101e65750600481015460ff165b8061026757508060000160009054906101000a9004600160a060020a03168160010160005054846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816007016000505414155b8061027757506001546005820154105b1561109257610002565b61077560043560066020526000908152604090205481565b61077560055481565b61078760043560078054829081101561000257506000526003026000805160206111d18339815191528101547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a820154600160a060020a0382169260a060020a90920460ff16917fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c689019084565b61077560025481565b61077560015481565b610830600054600160a060020a031681565b604080516020604435600481810135601f81018490048402850184019095528484526100b9948135946024803595939460649492939101918190840183828082843750949650505050505050600080548190600160a060020a03908116339091161461084d57610002565b61077560035481565b604080516020604435600481810135601f8101849004840285018401909552848452610775948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024909101945090925082915084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806104ab5750604081205460078054909190811015610002579082526003026000805160206111d1833981519152015460a060020a900460ff16155b15610ce557610002565b6100b960043560243560443560005433600160a060020a03908116911614610b1857610002565b604080516020604435600481810135601f810184900484028501840190955284845261077594813594602480359593946064949293910191819084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806105835750604081205460078054909190811015610002579082526003026000805160206111d18339815191520181505460a060020a900460ff16155b15610f1d57610002565b604080516020606435600481810135601f81018490048402850184019095528484526107759481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600460005086815481101561000257908252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01815090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005054149150610cdc565b6100b960043560005433600160a060020a03908116911614610f0857610002565b604051808a600160a060020a031681526020018981526020018060200188815260200187815260200186815260200185815260200184815260200183815260200182810382528981815460018160011615610100020316600290048152602001915080546001816001161561010002031660029004801561075e5780601f106107335761010080835404028352916020019161075e565b820191906000526020600020905b81548152906001019060200180831161074157829003601f168201915b50509a505050505050505050505060405180910390f35b60408051918252519081900360200190f35b60408051600160a060020a038616815260208101859052606081018390526080918101828152845460026001821615610100026000190190911604928201839052909160a08301908590801561081e5780601f106107f35761010080835404028352916020019161081e565b820191906000526020600020905b81548152906001019060200180831161080157829003601f168201915b50509550505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b600160a060020a03851660009081526006602052604081205414156108a957604060002060078054918290556001820180825582801582901161095c5760030281600302836000526020600020918201910161095c9190610a4f565b600160a060020a03851660009081526006602052604090205460078054919350908390811015610002575060005250600381026000805160206111d183398151915201805474ff0000000000000000000000000000000000000000191660a060020a85021781555b60408051600160a060020a03871681526020810186905281517f27b022af4a8347100c7a041ce5ccf8e14d644ff05de696315196faae8cd50c9b929181900390910190a15050505050565b505050915081506080604051908101604052808681526020018581526020018481526020014281526020015060076000508381548110156100025790600052602060002090600302016000508151815460208481015160a060020a02600160a060020a03199290921690921774ff00000000000000000000000000000000000000001916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f90810183900482019491929190910190839010610ad357805160ff19168380011785555b50610b03929150610abb565b5050600060028201556001015b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610aa15750610a42565b601f016020900490600052602060002090810190610a4291905b80821115610acf5760008155600101610abb565b5090565b82800160010185558215610a36579182015b82811115610a36578251826000505591602001919060010190610ae5565b50506060919091015160029190910155610911565b600183905560028290556003819055604080518481526020810184905280820183905290517fa439d3fa452be5e0e1e24a8145e715f4fd8b9c08c96a42fd82a855a85e5d57de9181900360600190a1505050565b50508585846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005081905550600260005054603c024201816003016000508190555060008160040160006101000a81548160ff0219169083021790555060008160040160016101000a81548160ff02191690830217905550600081600501600050819055507f646fec02522b41e7125cfc859a64fd4f4cefd5dc3b6237ca0abe251ded1fa881828787876040518085815260200184600160a060020a03168152602001838152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610cc45780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1600182016005555b50949350505050565b6004805460018101808355909190828015829011610d1c57600a0281600a028360005260206000209182019101610d1c9190610db8565b505060048054929450918491508110156100025790600052602060002090600a02016000508054600160a060020a031916871781556001818101879055855160028381018054600082815260209081902096975091959481161561010002600019011691909104601f90810182900484019391890190839010610ed857805160ff19168380011785555b50610b6c929150610abb565b50506001015b80821115610acf578054600160a060020a03191681556000600182810182905560028381018054848255909281161561010002600019011604601f819010610e9c57505b5060006003830181905560048301805461ffff191690556005830181905560068301819055600783018190556008830180548282559082526020909120610db2916002028101905b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610eba57505b5050600101610e44565b601f016020900490600052602060002090810190610dfc9190610abb565b601f016020900490600052602060002090810190610e929190610abb565b82800160010185558215610da6579182015b82811115610da6578251826000505591602001919060010190610eea565b60008054600160a060020a0319168217905550565b600480548690811015610002576000918252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905033600160a060020a0316600090815260098201602052604090205490915060ff1660011415610f8457610002565b33600160a060020a031660009081526009820160205260409020805460ff1916600190811790915560058201805490910190558315610fcd576006810180546001019055610fda565b6006810180546000190190555b7fc34f869b7ff431b034b7b9aea9822dac189a685e0b015c7d1be3add3f89128e8858533866040518085815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561107a5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1509392505050565b6006810154600354901315611158578060000160009054906101000a9004600160a060020a0316600160a060020a03168160010160005054670de0b6b3a76400000284604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111225780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f15050505060048101805460ff191660011761ff00191661010017905561116d565b60048101805460ff191660011761ff00191690555b60068101546005820154600483015460408051888152602081019490945283810192909252610100900460ff166060830152517fd220b7272a8b6d0d7d6bcdace67b936a8f175e6d5c1b3ee438b72256b32ab3af9181900360800190a1509291505056a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688", +} + +// DAO is an auto generated Go binding around an Ethereum contract. +type DAO struct { + abi abi.ABI +} + +// NewDAO creates a new instance of DAO. +func NewDAO() *DAO { + parsed, err := DAOMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &DAO{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *DAO) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(uint256 minimumQuorumForProposals, uint256 minutesForDebate, int256 marginOfVotesForMajority, address congressLeader) returns() +func (dAO *DAO) PackConstructor(minimumQuorumForProposals *big.Int, minutesForDebate *big.Int, marginOfVotesForMajority *big.Int, congressLeader common.Address) []byte { + enc, err := dAO.abi.Pack("", minimumQuorumForProposals, minutesForDebate, marginOfVotesForMajority, congressLeader) + if err != nil { + panic(err) + } + return enc +} + +// PackChangeMembership is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x9644fcbd. +// +// Solidity: function changeMembership(address targetMember, bool canVote, string memberName) returns() +func (dAO *DAO) PackChangeMembership(targetMember common.Address, canVote bool, memberName string) []byte { + enc, err := dAO.abi.Pack("changeMembership", targetMember, canVote, memberName) + if err != nil { + panic(err) + } + return enc +} + +// PackChangeVotingRules is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xbcca1fd3. +// +// Solidity: function changeVotingRules(uint256 minimumQuorumForProposals, uint256 minutesForDebate, int256 marginOfVotesForMajority) returns() +func (dAO *DAO) PackChangeVotingRules(minimumQuorumForProposals *big.Int, minutesForDebate *big.Int, marginOfVotesForMajority *big.Int) []byte { + enc, err := dAO.abi.Pack("changeVotingRules", minimumQuorumForProposals, minutesForDebate, marginOfVotesForMajority) + if err != nil { + panic(err) + } + return enc +} + +// PackCheckProposalCode is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xeceb2945. +// +// Solidity: function checkProposalCode(uint256 proposalNumber, address beneficiary, uint256 etherAmount, bytes transactionBytecode) returns(bool codeChecksOut) +func (dAO *DAO) PackCheckProposalCode(proposalNumber *big.Int, beneficiary common.Address, etherAmount *big.Int, transactionBytecode []byte) []byte { + enc, err := dAO.abi.Pack("checkProposalCode", proposalNumber, beneficiary, etherAmount, transactionBytecode) + if err != nil { + panic(err) + } + return enc +} + +// UnpackCheckProposalCode is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xeceb2945. +// +// Solidity: function checkProposalCode(uint256 proposalNumber, address beneficiary, uint256 etherAmount, bytes transactionBytecode) returns(bool codeChecksOut) +func (dAO *DAO) UnpackCheckProposalCode(data []byte) (bool, error) { + out, err := dAO.abi.Unpack("checkProposalCode", data) + if err != nil { + return *new(bool), err + } + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + return out0, err +} + +// PackDebatingPeriodInMinutes is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x69bd3436. +// +// Solidity: function debatingPeriodInMinutes() returns(uint256) +func (dAO *DAO) PackDebatingPeriodInMinutes() []byte { + enc, err := dAO.abi.Pack("debatingPeriodInMinutes") + if err != nil { + panic(err) + } + return enc +} + +// UnpackDebatingPeriodInMinutes is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x69bd3436. +// +// Solidity: function debatingPeriodInMinutes() returns(uint256) +func (dAO *DAO) UnpackDebatingPeriodInMinutes(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("debatingPeriodInMinutes", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackExecuteProposal is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x237e9492. +// +// Solidity: function executeProposal(uint256 proposalNumber, bytes transactionBytecode) returns(int256 result) +func (dAO *DAO) PackExecuteProposal(proposalNumber *big.Int, transactionBytecode []byte) []byte { + enc, err := dAO.abi.Pack("executeProposal", proposalNumber, transactionBytecode) + if err != nil { + panic(err) + } + return enc +} + +// UnpackExecuteProposal is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x237e9492. +// +// Solidity: function executeProposal(uint256 proposalNumber, bytes transactionBytecode) returns(int256 result) +func (dAO *DAO) UnpackExecuteProposal(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("executeProposal", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackMajorityMargin is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xaa02a90f. +// +// Solidity: function majorityMargin() returns(int256) +func (dAO *DAO) PackMajorityMargin() []byte { + enc, err := dAO.abi.Pack("majorityMargin") + if err != nil { + panic(err) + } + return enc +} + +// UnpackMajorityMargin is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xaa02a90f. +// +// Solidity: function majorityMargin() returns(int256) +func (dAO *DAO) UnpackMajorityMargin(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("majorityMargin", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackMemberId is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x39106821. +// +// Solidity: function memberId(address ) returns(uint256) +func (dAO *DAO) PackMemberId(arg0 common.Address) []byte { + enc, err := dAO.abi.Pack("memberId", arg0) + if err != nil { + panic(err) + } + return enc +} + +// UnpackMemberId is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x39106821. +// +// Solidity: function memberId(address ) returns(uint256) +func (dAO *DAO) UnpackMemberId(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("memberId", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackMembers is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x5daf08ca. +// +// Solidity: function members(uint256 ) returns(address member, bool canVote, string name, uint256 memberSince) +func (dAO *DAO) PackMembers(arg0 *big.Int) []byte { + enc, err := dAO.abi.Pack("members", arg0) + if err != nil { + panic(err) + } + return enc +} + +// MembersOutput serves as a container for the return parameters of contract +// method Members. +type MembersOutput struct { + Member common.Address + CanVote bool + Name string + MemberSince *big.Int +} + +// UnpackMembers is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x5daf08ca. +// +// Solidity: function members(uint256 ) returns(address member, bool canVote, string name, uint256 memberSince) +func (dAO *DAO) UnpackMembers(data []byte) (MembersOutput, error) { + out, err := dAO.abi.Unpack("members", data) + outstruct := new(MembersOutput) + if err != nil { + return *outstruct, err + } + outstruct.Member = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.CanVote = *abi.ConvertType(out[1], new(bool)).(*bool) + outstruct.Name = *abi.ConvertType(out[2], new(string)).(*string) + outstruct.MemberSince = abi.ConvertType(out[3], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackMinimumQuorum is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x8160f0b5. +// +// Solidity: function minimumQuorum() returns(uint256) +func (dAO *DAO) PackMinimumQuorum() []byte { + enc, err := dAO.abi.Pack("minimumQuorum") + if err != nil { + panic(err) + } + return enc +} + +// UnpackMinimumQuorum is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x8160f0b5. +// +// Solidity: function minimumQuorum() returns(uint256) +func (dAO *DAO) UnpackMinimumQuorum(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("minimumQuorum", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackNewProposal is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xb1050da5. +// +// Solidity: function newProposal(address beneficiary, uint256 etherAmount, string JobDescription, bytes transactionBytecode) returns(uint256 proposalID) +func (dAO *DAO) PackNewProposal(beneficiary common.Address, etherAmount *big.Int, jobDescription string, transactionBytecode []byte) []byte { + enc, err := dAO.abi.Pack("newProposal", beneficiary, etherAmount, jobDescription, transactionBytecode) + if err != nil { + panic(err) + } + return enc +} + +// UnpackNewProposal is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xb1050da5. +// +// Solidity: function newProposal(address beneficiary, uint256 etherAmount, string JobDescription, bytes transactionBytecode) returns(uint256 proposalID) +func (dAO *DAO) UnpackNewProposal(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("newProposal", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackNumProposals is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x400e3949. +// +// Solidity: function numProposals() returns(uint256) +func (dAO *DAO) PackNumProposals() []byte { + enc, err := dAO.abi.Pack("numProposals") + if err != nil { + panic(err) + } + return enc +} + +// UnpackNumProposals is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x400e3949. +// +// Solidity: function numProposals() returns(uint256) +func (dAO *DAO) UnpackNumProposals(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("numProposals", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackOwner is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x8da5cb5b. +// +// Solidity: function owner() returns(address) +func (dAO *DAO) PackOwner() []byte { + enc, err := dAO.abi.Pack("owner") + if err != nil { + panic(err) + } + return enc +} + +// UnpackOwner is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x8da5cb5b. +// +// Solidity: function owner() returns(address) +func (dAO *DAO) UnpackOwner(data []byte) (common.Address, error) { + out, err := dAO.abi.Unpack("owner", data) + if err != nil { + return *new(common.Address), err + } + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + return out0, err +} + +// PackProposals is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x013cf08b. +// +// Solidity: function proposals(uint256 ) returns(address recipient, uint256 amount, string description, uint256 votingDeadline, bool executed, bool proposalPassed, uint256 numberOfVotes, int256 currentResult, bytes32 proposalHash) +func (dAO *DAO) PackProposals(arg0 *big.Int) []byte { + enc, err := dAO.abi.Pack("proposals", arg0) + if err != nil { + panic(err) + } + return enc +} + +// ProposalsOutput serves as a container for the return parameters of contract +// method Proposals. +type ProposalsOutput struct { + Recipient common.Address + Amount *big.Int + Description string + VotingDeadline *big.Int + Executed bool + ProposalPassed bool + NumberOfVotes *big.Int + CurrentResult *big.Int + ProposalHash [32]byte +} + +// UnpackProposals is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x013cf08b. +// +// Solidity: function proposals(uint256 ) returns(address recipient, uint256 amount, string description, uint256 votingDeadline, bool executed, bool proposalPassed, uint256 numberOfVotes, int256 currentResult, bytes32 proposalHash) +func (dAO *DAO) UnpackProposals(data []byte) (ProposalsOutput, error) { + out, err := dAO.abi.Unpack("proposals", data) + outstruct := new(ProposalsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Recipient = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.Amount = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + outstruct.Description = *abi.ConvertType(out[2], new(string)).(*string) + outstruct.VotingDeadline = abi.ConvertType(out[3], new(big.Int)).(*big.Int) + outstruct.Executed = *abi.ConvertType(out[4], new(bool)).(*bool) + outstruct.ProposalPassed = *abi.ConvertType(out[5], new(bool)).(*bool) + outstruct.NumberOfVotes = abi.ConvertType(out[6], new(big.Int)).(*big.Int) + outstruct.CurrentResult = abi.ConvertType(out[7], new(big.Int)).(*big.Int) + outstruct.ProposalHash = *abi.ConvertType(out[8], new([32]byte)).(*[32]byte) + return *outstruct, err + +} + +// PackTransferOwnership is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (dAO *DAO) PackTransferOwnership(newOwner common.Address) []byte { + enc, err := dAO.abi.Pack("transferOwnership", newOwner) + if err != nil { + panic(err) + } + return enc +} + +// PackVote is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd3c0715b. +// +// Solidity: function vote(uint256 proposalNumber, bool supportsProposal, string justificationText) returns(uint256 voteID) +func (dAO *DAO) PackVote(proposalNumber *big.Int, supportsProposal bool, justificationText string) []byte { + enc, err := dAO.abi.Pack("vote", proposalNumber, supportsProposal, justificationText) + if err != nil { + panic(err) + } + return enc +} + +// UnpackVote is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xd3c0715b. +// +// Solidity: function vote(uint256 proposalNumber, bool supportsProposal, string justificationText) returns(uint256 voteID) +func (dAO *DAO) UnpackVote(data []byte) (*big.Int, error) { + out, err := dAO.abi.Unpack("vote", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// DAOChangeOfRules represents a ChangeOfRules event raised by the DAO contract. +type DAOChangeOfRules struct { + MinimumQuorum *big.Int + DebatingPeriodInMinutes *big.Int + MajorityMargin *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const DAOChangeOfRulesEventName = "ChangeOfRules" + +// ContractEventName returns the user-defined event name. +func (DAOChangeOfRules) ContractEventName() string { + return DAOChangeOfRulesEventName +} + +// UnpackChangeOfRulesEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event ChangeOfRules(uint256 minimumQuorum, uint256 debatingPeriodInMinutes, int256 majorityMargin) +func (dAO *DAO) UnpackChangeOfRulesEvent(log *types.Log) (*DAOChangeOfRules, error) { + event := "ChangeOfRules" + if log.Topics[0] != dAO.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DAOChangeOfRules) + if len(log.Data) > 0 { + if err := dAO.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dAO.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// DAOMembershipChanged represents a MembershipChanged event raised by the DAO contract. +type DAOMembershipChanged struct { + Member common.Address + IsMember bool + Raw *types.Log // Blockchain specific contextual infos +} + +const DAOMembershipChangedEventName = "MembershipChanged" + +// ContractEventName returns the user-defined event name. +func (DAOMembershipChanged) ContractEventName() string { + return DAOMembershipChangedEventName +} + +// UnpackMembershipChangedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event MembershipChanged(address member, bool isMember) +func (dAO *DAO) UnpackMembershipChangedEvent(log *types.Log) (*DAOMembershipChanged, error) { + event := "MembershipChanged" + if log.Topics[0] != dAO.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DAOMembershipChanged) + if len(log.Data) > 0 { + if err := dAO.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dAO.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// DAOProposalAdded represents a ProposalAdded event raised by the DAO contract. +type DAOProposalAdded struct { + ProposalID *big.Int + Recipient common.Address + Amount *big.Int + Description string + Raw *types.Log // Blockchain specific contextual infos +} + +const DAOProposalAddedEventName = "ProposalAdded" + +// ContractEventName returns the user-defined event name. +func (DAOProposalAdded) ContractEventName() string { + return DAOProposalAddedEventName +} + +// UnpackProposalAddedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event ProposalAdded(uint256 proposalID, address recipient, uint256 amount, string description) +func (dAO *DAO) UnpackProposalAddedEvent(log *types.Log) (*DAOProposalAdded, error) { + event := "ProposalAdded" + if log.Topics[0] != dAO.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DAOProposalAdded) + if len(log.Data) > 0 { + if err := dAO.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dAO.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// DAOProposalTallied represents a ProposalTallied event raised by the DAO contract. +type DAOProposalTallied struct { + ProposalID *big.Int + Result *big.Int + Quorum *big.Int + Active bool + Raw *types.Log // Blockchain specific contextual infos +} + +const DAOProposalTalliedEventName = "ProposalTallied" + +// ContractEventName returns the user-defined event name. +func (DAOProposalTallied) ContractEventName() string { + return DAOProposalTalliedEventName +} + +// UnpackProposalTalliedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event ProposalTallied(uint256 proposalID, int256 result, uint256 quorum, bool active) +func (dAO *DAO) UnpackProposalTalliedEvent(log *types.Log) (*DAOProposalTallied, error) { + event := "ProposalTallied" + if log.Topics[0] != dAO.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DAOProposalTallied) + if len(log.Data) > 0 { + if err := dAO.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dAO.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// DAOVoted represents a Voted event raised by the DAO contract. +type DAOVoted struct { + ProposalID *big.Int + Position bool + Voter common.Address + Justification string + Raw *types.Log // Blockchain specific contextual infos +} + +const DAOVotedEventName = "Voted" + +// ContractEventName returns the user-defined event name. +func (DAOVoted) ContractEventName() string { + return DAOVotedEventName +} + +// UnpackVotedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event Voted(uint256 proposalID, bool position, address voter, string justification) +func (dAO *DAO) UnpackVotedEvent(log *types.Log) (*DAOVoted, error) { + event := "Voted" + if log.Topics[0] != dAO.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DAOVoted) + if len(log.Data) > 0 { + if err := dAO.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dAO.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/deeplynestedarray.go.txt b/accounts/abi/abigen/testdata/v2/deeplynestedarray.go.txt new file mode 100644 index 000000000..00f717d02 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/deeplynestedarray.go.txt @@ -0,0 +1,114 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// DeeplyNestedArrayMetaData contains all meta data concerning the DeeplyNestedArray contract. +var DeeplyNestedArrayMetaData = bind.MetaData{ + ABI: "[{\"constant\":false,\"inputs\":[{\"name\":\"arr\",\"type\":\"uint64[3][4][5]\"}],\"name\":\"storeDeepUintArray\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"retrieveDeepArray\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64[3][4][5]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"deepUint64Array\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]", + ID: "3a44c26b21f02743d5dbeb02d24a67bf41", + Bin: "0x6060604052341561000f57600080fd5b6106438061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063344248551461005c5780638ed4573a1461011457806398ed1856146101ab575b600080fd5b341561006757600080fd5b610112600480806107800190600580602002604051908101604052809291906000905b828210156101055783826101800201600480602002604051908101604052809291906000905b828210156100f25783826060020160038060200260405190810160405280929190826003602002808284378201915050505050815260200190600101906100b0565b505050508152602001906001019061008a565b5050505091905050610208565b005b341561011f57600080fd5b61012761021d565b604051808260056000925b8184101561019b578284602002015160046000925b8184101561018d5782846020020151600360200280838360005b8381101561017c578082015181840152602081019050610161565b505050509050019260010192610147565b925050509260010192610132565b9250505091505060405180910390f35b34156101b657600080fd5b6101de6004808035906020019091908035906020019091908035906020019091905050610309565b604051808267ffffffffffffffff1667ffffffffffffffff16815260200191505060405180910390f35b80600090600561021992919061035f565b5050565b6102256103b0565b6000600580602002604051908101604052809291906000905b8282101561030057838260040201600480602002604051908101604052809291906000905b828210156102ed578382016003806020026040519081016040528092919082600380156102d9576020028201916000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116102945790505b505050505081526020019060010190610263565b505050508152602001906001019061023e565b50505050905090565b60008360058110151561031857fe5b600402018260048110151561032957fe5b018160038110151561033757fe5b6004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b826005600402810192821561039f579160200282015b8281111561039e5782518290600461038e9291906103df565b5091602001919060040190610375565b5b5090506103ac919061042d565b5090565b610780604051908101604052806005905b6103c9610459565b8152602001906001900390816103c15790505090565b826004810192821561041c579160200282015b8281111561041b5782518290600361040b929190610488565b50916020019190600101906103f2565b5b5090506104299190610536565b5090565b61045691905b8082111561045257600081816104499190610562565b50600401610433565b5090565b90565b610180604051908101604052806004905b6104726105a7565b81526020019060019003908161046a5790505090565b82600380016004900481019282156105255791602002820160005b838211156104ef57835183826101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555092602001926008016020816007010492830192600103026104a3565b80156105235782816101000a81549067ffffffffffffffff02191690556008016020816007010492830192600103026104ef565b505b50905061053291906105d9565b5090565b61055f91905b8082111561055b57600081816105529190610610565b5060010161053c565b5090565b90565b50600081816105719190610610565b50600101600081816105839190610610565b50600101600081816105959190610610565b5060010160006105a59190610610565b565b6060604051908101604052806003905b600067ffffffffffffffff168152602001906001900390816105b75790505090565b61060d91905b8082111561060957600081816101000a81549067ffffffffffffffff0219169055506001016105df565b5090565b90565b50600090555600a165627a7a7230582087e5a43f6965ab6ef7a4ff056ab80ed78fd8c15cff57715a1bf34ec76a93661c0029", +} + +// DeeplyNestedArray is an auto generated Go binding around an Ethereum contract. +type DeeplyNestedArray struct { + abi abi.ABI +} + +// NewDeeplyNestedArray creates a new instance of DeeplyNestedArray. +func NewDeeplyNestedArray() *DeeplyNestedArray { + parsed, err := DeeplyNestedArrayMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &DeeplyNestedArray{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *DeeplyNestedArray) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDeepUint64Array is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x98ed1856. +// +// Solidity: function deepUint64Array(uint256 , uint256 , uint256 ) view returns(uint64) +func (deeplyNestedArray *DeeplyNestedArray) PackDeepUint64Array(arg0 *big.Int, arg1 *big.Int, arg2 *big.Int) []byte { + enc, err := deeplyNestedArray.abi.Pack("deepUint64Array", arg0, arg1, arg2) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDeepUint64Array is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x98ed1856. +// +// Solidity: function deepUint64Array(uint256 , uint256 , uint256 ) view returns(uint64) +func (deeplyNestedArray *DeeplyNestedArray) UnpackDeepUint64Array(data []byte) (uint64, error) { + out, err := deeplyNestedArray.abi.Unpack("deepUint64Array", data) + if err != nil { + return *new(uint64), err + } + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + return out0, err +} + +// PackRetrieveDeepArray is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x8ed4573a. +// +// Solidity: function retrieveDeepArray() view returns(uint64[3][4][5]) +func (deeplyNestedArray *DeeplyNestedArray) PackRetrieveDeepArray() []byte { + enc, err := deeplyNestedArray.abi.Pack("retrieveDeepArray") + if err != nil { + panic(err) + } + return enc +} + +// UnpackRetrieveDeepArray is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x8ed4573a. +// +// Solidity: function retrieveDeepArray() view returns(uint64[3][4][5]) +func (deeplyNestedArray *DeeplyNestedArray) UnpackRetrieveDeepArray(data []byte) ([5][4][3]uint64, error) { + out, err := deeplyNestedArray.abi.Unpack("retrieveDeepArray", data) + if err != nil { + return *new([5][4][3]uint64), err + } + out0 := *abi.ConvertType(out[0], new([5][4][3]uint64)).(*[5][4][3]uint64) + return out0, err +} + +// PackStoreDeepUintArray is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x34424855. +// +// Solidity: function storeDeepUintArray(uint64[3][4][5] arr) returns() +func (deeplyNestedArray *DeeplyNestedArray) PackStoreDeepUintArray(arr [5][4][3]uint64) []byte { + enc, err := deeplyNestedArray.abi.Pack("storeDeepUintArray", arr) + if err != nil { + panic(err) + } + return enc +} diff --git a/accounts/abi/abigen/testdata/v2/empty.go.txt b/accounts/abi/abigen/testdata/v2/empty.go.txt new file mode 100644 index 000000000..7082e2079 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/empty.go.txt @@ -0,0 +1,52 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// EmptyMetaData contains all meta data concerning the Empty contract. +var EmptyMetaData = bind.MetaData{ + ABI: "[]", + ID: "c4ce3210982aa6fc94dabe46dc1dbf454d", + Bin: "0x606060405260068060106000396000f3606060405200", +} + +// Empty is an auto generated Go binding around an Ethereum contract. +type Empty struct { + abi abi.ABI +} + +// NewEmpty creates a new instance of Empty. +func NewEmpty() *Empty { + parsed, err := EmptyMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Empty{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Empty) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} diff --git a/accounts/abi/abigen/testdata/v2/eventchecker.go.txt b/accounts/abi/abigen/testdata/v2/eventchecker.go.txt new file mode 100644 index 000000000..92558c5ef --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/eventchecker.go.txt @@ -0,0 +1,261 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// EventCheckerMetaData contains all meta data concerning the EventChecker contract. +var EventCheckerMetaData = bind.MetaData{ + ABI: "[{\"type\":\"event\",\"name\":\"empty\",\"inputs\":[]},{\"type\":\"event\",\"name\":\"indexed\",\"inputs\":[{\"name\":\"addr\",\"type\":\"address\",\"indexed\":true},{\"name\":\"num\",\"type\":\"int256\",\"indexed\":true}]},{\"type\":\"event\",\"name\":\"mixed\",\"inputs\":[{\"name\":\"addr\",\"type\":\"address\",\"indexed\":true},{\"name\":\"num\",\"type\":\"int256\"}]},{\"type\":\"event\",\"name\":\"anonymous\",\"anonymous\":true,\"inputs\":[]},{\"type\":\"event\",\"name\":\"dynamic\",\"inputs\":[{\"name\":\"idxStr\",\"type\":\"string\",\"indexed\":true},{\"name\":\"idxDat\",\"type\":\"bytes\",\"indexed\":true},{\"name\":\"str\",\"type\":\"string\"},{\"name\":\"dat\",\"type\":\"bytes\"}]},{\"type\":\"event\",\"name\":\"unnamed\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"indexed\":true},{\"name\":\"\",\"type\":\"uint256\",\"indexed\":true}]}]", + ID: "253d421f98e29b25315bde79c1251ab27c", +} + +// EventChecker is an auto generated Go binding around an Ethereum contract. +type EventChecker struct { + abi abi.ABI +} + +// NewEventChecker creates a new instance of EventChecker. +func NewEventChecker() *EventChecker { + parsed, err := EventCheckerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &EventChecker{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *EventChecker) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// EventCheckerDynamic represents a dynamic event raised by the EventChecker contract. +type EventCheckerDynamic struct { + IdxStr common.Hash + IdxDat common.Hash + Str string + Dat []byte + Raw *types.Log // Blockchain specific contextual infos +} + +const EventCheckerDynamicEventName = "dynamic" + +// ContractEventName returns the user-defined event name. +func (EventCheckerDynamic) ContractEventName() string { + return EventCheckerDynamicEventName +} + +// UnpackDynamicEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event dynamic(string indexed idxStr, bytes indexed idxDat, string str, bytes dat) +func (eventChecker *EventChecker) UnpackDynamicEvent(log *types.Log) (*EventCheckerDynamic, error) { + event := "dynamic" + if log.Topics[0] != eventChecker.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(EventCheckerDynamic) + if len(log.Data) > 0 { + if err := eventChecker.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range eventChecker.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// EventCheckerEmpty represents a empty event raised by the EventChecker contract. +type EventCheckerEmpty struct { + Raw *types.Log // Blockchain specific contextual infos +} + +const EventCheckerEmptyEventName = "empty" + +// ContractEventName returns the user-defined event name. +func (EventCheckerEmpty) ContractEventName() string { + return EventCheckerEmptyEventName +} + +// UnpackEmptyEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event empty() +func (eventChecker *EventChecker) UnpackEmptyEvent(log *types.Log) (*EventCheckerEmpty, error) { + event := "empty" + if log.Topics[0] != eventChecker.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(EventCheckerEmpty) + if len(log.Data) > 0 { + if err := eventChecker.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range eventChecker.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// EventCheckerIndexed represents a indexed event raised by the EventChecker contract. +type EventCheckerIndexed struct { + Addr common.Address + Num *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const EventCheckerIndexedEventName = "indexed" + +// ContractEventName returns the user-defined event name. +func (EventCheckerIndexed) ContractEventName() string { + return EventCheckerIndexedEventName +} + +// UnpackIndexedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event indexed(address indexed addr, int256 indexed num) +func (eventChecker *EventChecker) UnpackIndexedEvent(log *types.Log) (*EventCheckerIndexed, error) { + event := "indexed" + if log.Topics[0] != eventChecker.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(EventCheckerIndexed) + if len(log.Data) > 0 { + if err := eventChecker.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range eventChecker.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// EventCheckerMixed represents a mixed event raised by the EventChecker contract. +type EventCheckerMixed struct { + Addr common.Address + Num *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const EventCheckerMixedEventName = "mixed" + +// ContractEventName returns the user-defined event name. +func (EventCheckerMixed) ContractEventName() string { + return EventCheckerMixedEventName +} + +// UnpackMixedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event mixed(address indexed addr, int256 num) +func (eventChecker *EventChecker) UnpackMixedEvent(log *types.Log) (*EventCheckerMixed, error) { + event := "mixed" + if log.Topics[0] != eventChecker.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(EventCheckerMixed) + if len(log.Data) > 0 { + if err := eventChecker.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range eventChecker.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// EventCheckerUnnamed represents a unnamed event raised by the EventChecker contract. +type EventCheckerUnnamed struct { + Arg0 *big.Int + Arg1 *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const EventCheckerUnnamedEventName = "unnamed" + +// ContractEventName returns the user-defined event name. +func (EventCheckerUnnamed) ContractEventName() string { + return EventCheckerUnnamedEventName +} + +// UnpackUnnamedEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event unnamed(uint256 indexed arg0, uint256 indexed arg1) +func (eventChecker *EventChecker) UnpackUnnamedEvent(log *types.Log) (*EventCheckerUnnamed, error) { + event := "unnamed" + if log.Topics[0] != eventChecker.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(EventCheckerUnnamed) + if len(log.Data) > 0 { + if err := eventChecker.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range eventChecker.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/getter.go.txt b/accounts/abi/abigen/testdata/v2/getter.go.txt new file mode 100644 index 000000000..8e6e7debb --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/getter.go.txt @@ -0,0 +1,89 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// GetterMetaData contains all meta data concerning the Getter contract. +var GetterMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"getter\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"int256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"type\":\"function\"}]", + ID: "e23a74c8979fe93c9fff15e4f51535ad54", + Bin: "0x606060405260dc8060106000396000f3606060405260e060020a6000350463993a04b78114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3", +} + +// Getter is an auto generated Go binding around an Ethereum contract. +type Getter struct { + abi abi.ABI +} + +// NewGetter creates a new instance of Getter. +func NewGetter() *Getter { + parsed, err := GetterMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Getter{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Getter) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackGetter is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x993a04b7. +// +// Solidity: function getter() returns(string, int256, bytes32) +func (getter *Getter) PackGetter() []byte { + enc, err := getter.abi.Pack("getter") + if err != nil { + panic(err) + } + return enc +} + +// GetterOutput serves as a container for the return parameters of contract +// method Getter. +type GetterOutput struct { + Arg0 string + Arg1 *big.Int + Arg2 [32]byte +} + +// UnpackGetter is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x993a04b7. +// +// Solidity: function getter() returns(string, int256, bytes32) +func (getter *Getter) UnpackGetter(data []byte) (GetterOutput, error) { + out, err := getter.abi.Unpack("getter", data) + outstruct := new(GetterOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.Arg1 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + outstruct.Arg2 = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + return *outstruct, err + +} diff --git a/accounts/abi/abigen/testdata/v2/identifiercollision.go.txt b/accounts/abi/abigen/testdata/v2/identifiercollision.go.txt new file mode 100644 index 000000000..60554aac1 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/identifiercollision.go.txt @@ -0,0 +1,102 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// IdentifierCollisionMetaData contains all meta data concerning the IdentifierCollision contract. +var IdentifierCollisionMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"MyVar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_myVar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]", + ID: "1863c5622f8ac2c09c42f063ca883fe438", + Bin: "0x60806040523480156100115760006000fd5b50610017565b60c3806100256000396000f3fe608060405234801560105760006000fd5b506004361060365760003560e01c806301ad4d8714603c5780634ef1f0ad146058576036565b60006000fd5b60426074565b6040518082815260200191505060405180910390f35b605e607d565b6040518082815260200191505060405180910390f35b60006000505481565b60006000600050549050608b565b9056fea265627a7a7231582067c8d84688b01c4754ba40a2a871cede94ea1f28b5981593ab2a45b46ac43af664736f6c634300050c0032", +} + +// IdentifierCollision is an auto generated Go binding around an Ethereum contract. +type IdentifierCollision struct { + abi abi.ABI +} + +// NewIdentifierCollision creates a new instance of IdentifierCollision. +func NewIdentifierCollision() *IdentifierCollision { + parsed, err := IdentifierCollisionMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &IdentifierCollision{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *IdentifierCollision) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackMyVar is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x4ef1f0ad. +// +// Solidity: function MyVar() view returns(uint256) +func (identifierCollision *IdentifierCollision) PackMyVar() []byte { + enc, err := identifierCollision.abi.Pack("MyVar") + if err != nil { + panic(err) + } + return enc +} + +// UnpackMyVar is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x4ef1f0ad. +// +// Solidity: function MyVar() view returns(uint256) +func (identifierCollision *IdentifierCollision) UnpackMyVar(data []byte) (*big.Int, error) { + out, err := identifierCollision.abi.Unpack("MyVar", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackPubVar is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x01ad4d87. +// +// Solidity: function _myVar() view returns(uint256) +func (identifierCollision *IdentifierCollision) PackPubVar() []byte { + enc, err := identifierCollision.abi.Pack("_myVar") + if err != nil { + panic(err) + } + return enc +} + +// UnpackPubVar is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x01ad4d87. +// +// Solidity: function _myVar() view returns(uint256) +func (identifierCollision *IdentifierCollision) UnpackPubVar(data []byte) (*big.Int, error) { + out, err := identifierCollision.abi.Unpack("_myVar", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} diff --git a/accounts/abi/abigen/testdata/v2/inputchecker.go.txt b/accounts/abi/abigen/testdata/v2/inputchecker.go.txt new file mode 100644 index 000000000..7b226aa90 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/inputchecker.go.txt @@ -0,0 +1,123 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// InputCheckerMetaData contains all meta data concerning the InputChecker contract. +var InputCheckerMetaData = bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"noInput\",\"constant\":true,\"inputs\":[],\"outputs\":[]},{\"type\":\"function\",\"name\":\"namedInput\",\"constant\":true,\"inputs\":[{\"name\":\"str\",\"type\":\"string\"}],\"outputs\":[]},{\"type\":\"function\",\"name\":\"anonInput\",\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"string\"}],\"outputs\":[]},{\"type\":\"function\",\"name\":\"namedInputs\",\"constant\":true,\"inputs\":[{\"name\":\"str1\",\"type\":\"string\"},{\"name\":\"str2\",\"type\":\"string\"}],\"outputs\":[]},{\"type\":\"function\",\"name\":\"anonInputs\",\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"outputs\":[]},{\"type\":\"function\",\"name\":\"mixedInputs\",\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"str\",\"type\":\"string\"}],\"outputs\":[]}]", + ID: "e551ce092312e54f54f45ffdf06caa4cdc", +} + +// InputChecker is an auto generated Go binding around an Ethereum contract. +type InputChecker struct { + abi abi.ABI +} + +// NewInputChecker creates a new instance of InputChecker. +func NewInputChecker() *InputChecker { + parsed, err := InputCheckerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &InputChecker{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *InputChecker) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackAnonInput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x3e708e82. +// +// Solidity: function anonInput(string ) returns() +func (inputChecker *InputChecker) PackAnonInput(arg0 string) []byte { + enc, err := inputChecker.abi.Pack("anonInput", arg0) + if err != nil { + panic(err) + } + return enc +} + +// PackAnonInputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x28160527. +// +// Solidity: function anonInputs(string , string ) returns() +func (inputChecker *InputChecker) PackAnonInputs(arg0 string, arg1 string) []byte { + enc, err := inputChecker.abi.Pack("anonInputs", arg0, arg1) + if err != nil { + panic(err) + } + return enc +} + +// PackMixedInputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xc689ebdc. +// +// Solidity: function mixedInputs(string , string str) returns() +func (inputChecker *InputChecker) PackMixedInputs(arg0 string, str string) []byte { + enc, err := inputChecker.abi.Pack("mixedInputs", arg0, str) + if err != nil { + panic(err) + } + return enc +} + +// PackNamedInput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x0d402005. +// +// Solidity: function namedInput(string str) returns() +func (inputChecker *InputChecker) PackNamedInput(str string) []byte { + enc, err := inputChecker.abi.Pack("namedInput", str) + if err != nil { + panic(err) + } + return enc +} + +// PackNamedInputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x63c796ed. +// +// Solidity: function namedInputs(string str1, string str2) returns() +func (inputChecker *InputChecker) PackNamedInputs(str1 string, str2 string) []byte { + enc, err := inputChecker.abi.Pack("namedInputs", str1, str2) + if err != nil { + panic(err) + } + return enc +} + +// PackNoInput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x53539029. +// +// Solidity: function noInput() returns() +func (inputChecker *InputChecker) PackNoInput() []byte { + enc, err := inputChecker.abi.Pack("noInput") + if err != nil { + panic(err) + } + return enc +} diff --git a/accounts/abi/abigen/testdata/v2/interactor.go.txt b/accounts/abi/abigen/testdata/v2/interactor.go.txt new file mode 100644 index 000000000..cc0900856 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/interactor.go.txt @@ -0,0 +1,126 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// InteractorMetaData contains all meta data concerning the Interactor contract. +var InteractorMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"transactString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"deployString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"str\",\"type\":\"string\"}],\"name\":\"transact\",\"outputs\":[],\"type\":\"function\"},{\"inputs\":[{\"name\":\"str\",\"type\":\"string\"}],\"type\":\"constructor\"}]", + ID: "f63980878028f3242c9033fdc30fd21a81", + Bin: "0x6060604052604051610328380380610328833981016040528051018060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10608d57805160ff19168380011785555b50607c9291505b8082111560ba57838155600101606b565b50505061026a806100be6000396000f35b828001600101855582156064579182015b828111156064578251826000505591602001919060010190609e565b509056606060405260e060020a60003504630d86a0e181146100315780636874e8091461008d578063d736c513146100ea575b005b610190600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b61019060008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156102295780601f106101fe57610100808354040283529160200191610229565b60206004803580820135601f81018490049093026080908101604052606084815261002f946024939192918401918190838280828437509496505050505050508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023157805160ff19168380011785555b506102619291505b808211156102665760008155830161017d565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156101f05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b820191906000526020600020905b81548152906001019060200180831161020c57829003601f168201915b505050505081565b82800160010185558215610175579182015b82811115610175578251826000505591602001919060010190610243565b505050565b509056", +} + +// Interactor is an auto generated Go binding around an Ethereum contract. +type Interactor struct { + abi abi.ABI +} + +// NewInteractor creates a new instance of Interactor. +func NewInteractor() *Interactor { + parsed, err := InteractorMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Interactor{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Interactor) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(string str) returns() +func (interactor *Interactor) PackConstructor(str string) []byte { + enc, err := interactor.abi.Pack("", str) + if err != nil { + panic(err) + } + return enc +} + +// PackDeployString is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x6874e809. +// +// Solidity: function deployString() returns(string) +func (interactor *Interactor) PackDeployString() []byte { + enc, err := interactor.abi.Pack("deployString") + if err != nil { + panic(err) + } + return enc +} + +// UnpackDeployString is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x6874e809. +// +// Solidity: function deployString() returns(string) +func (interactor *Interactor) UnpackDeployString(data []byte) (string, error) { + out, err := interactor.abi.Unpack("deployString", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} + +// PackTransact is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd736c513. +// +// Solidity: function transact(string str) returns() +func (interactor *Interactor) PackTransact(str string) []byte { + enc, err := interactor.abi.Pack("transact", str) + if err != nil { + panic(err) + } + return enc +} + +// PackTransactString is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x0d86a0e1. +// +// Solidity: function transactString() returns(string) +func (interactor *Interactor) PackTransactString() []byte { + enc, err := interactor.abi.Pack("transactString") + if err != nil { + panic(err) + } + return enc +} + +// UnpackTransactString is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x0d86a0e1. +// +// Solidity: function transactString() returns(string) +func (interactor *Interactor) UnpackTransactString(data []byte) (string, error) { + out, err := interactor.abi.Unpack("transactString", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} diff --git a/accounts/abi/abigen/testdata/v2/nameconflict.go.txt b/accounts/abi/abigen/testdata/v2/nameconflict.go.txt new file mode 100644 index 000000000..6228bf7cc --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/nameconflict.go.txt @@ -0,0 +1,137 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// Oraclerequest is an auto generated low-level Go binding around an user-defined struct. +type Oraclerequest struct { + Data []byte + Data0 []byte +} + +// NameConflictMetaData contains all meta data concerning the NameConflict contract. +var NameConflictMetaData = bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"msg\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"_msg\",\"type\":\"int256\"}],\"name\":\"log\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"internalType\":\"structoracle.request\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"addRequest\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"internalType\":\"structoracle.request\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "8f6e2703b307244ae6bd61ed94ce959cf9", + Bin: "0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033", +} + +// NameConflict is an auto generated Go binding around an Ethereum contract. +type NameConflict struct { + abi abi.ABI +} + +// NewNameConflict creates a new instance of NameConflict. +func NewNameConflict() *NameConflict { + parsed, err := NameConflictMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &NameConflict{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *NameConflict) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackAddRequest is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xcce7b048. +// +// Solidity: function addRequest((bytes,bytes) req) pure returns() +func (nameConflict *NameConflict) PackAddRequest(req Oraclerequest) []byte { + enc, err := nameConflict.abi.Pack("addRequest", req) + if err != nil { + panic(err) + } + return enc +} + +// PackGetRequest is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xc2bb515f. +// +// Solidity: function getRequest() pure returns((bytes,bytes)) +func (nameConflict *NameConflict) PackGetRequest() []byte { + enc, err := nameConflict.abi.Pack("getRequest") + if err != nil { + panic(err) + } + return enc +} + +// UnpackGetRequest is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xc2bb515f. +// +// Solidity: function getRequest() pure returns((bytes,bytes)) +func (nameConflict *NameConflict) UnpackGetRequest(data []byte) (Oraclerequest, error) { + out, err := nameConflict.abi.Unpack("getRequest", data) + if err != nil { + return *new(Oraclerequest), err + } + out0 := *abi.ConvertType(out[0], new(Oraclerequest)).(*Oraclerequest) + return out0, err +} + +// NameConflictLog represents a log event raised by the NameConflict contract. +type NameConflictLog struct { + Msg *big.Int + Msg0 *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const NameConflictLogEventName = "log" + +// ContractEventName returns the user-defined event name. +func (NameConflictLog) ContractEventName() string { + return NameConflictLogEventName +} + +// UnpackLogEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event log(int256 msg, int256 _msg) +func (nameConflict *NameConflict) UnpackLogEvent(log *types.Log) (*NameConflictLog, error) { + event := "log" + if log.Topics[0] != nameConflict.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(NameConflictLog) + if len(log.Data) > 0 { + if err := nameConflict.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range nameConflict.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/numericmethodname.go.txt b/accounts/abi/abigen/testdata/v2/numericmethodname.go.txt new file mode 100644 index 000000000..5a2208e0d --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/numericmethodname.go.txt @@ -0,0 +1,129 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// NumericMethodNameMetaData contains all meta data concerning the NumericMethodName contract. +var NumericMethodNameMetaData = bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_param\",\"type\":\"address\"}],\"name\":\"_1TestEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"_1test\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__1test\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__2test\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "a691b347afbc44b90dd9a1dfbc65661904", + Bin: "0x6080604052348015600f57600080fd5b5060958061001e6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80639d993132146041578063d02767c7146049578063ffa02795146051575b600080fd5b60476059565b005b604f605b565b005b6057605d565b005b565b565b56fea26469706673582212200382ca602dff96a7e2ba54657985e2b4ac423a56abe4a1f0667bc635c4d4371f64736f6c63430008110033", +} + +// NumericMethodName is an auto generated Go binding around an Ethereum contract. +type NumericMethodName struct { + abi abi.ABI +} + +// NewNumericMethodName creates a new instance of NumericMethodName. +func NewNumericMethodName() *NumericMethodName { + parsed, err := NumericMethodNameMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &NumericMethodName{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *NumericMethodName) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackE1test is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xffa02795. +// +// Solidity: function _1test() pure returns() +func (numericMethodName *NumericMethodName) PackE1test() []byte { + enc, err := numericMethodName.abi.Pack("_1test") + if err != nil { + panic(err) + } + return enc +} + +// PackE1test0 is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd02767c7. +// +// Solidity: function __1test() pure returns() +func (numericMethodName *NumericMethodName) PackE1test0() []byte { + enc, err := numericMethodName.abi.Pack("__1test") + if err != nil { + panic(err) + } + return enc +} + +// PackE2test is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x9d993132. +// +// Solidity: function __2test() pure returns() +func (numericMethodName *NumericMethodName) PackE2test() []byte { + enc, err := numericMethodName.abi.Pack("__2test") + if err != nil { + panic(err) + } + return enc +} + +// NumericMethodNameE1TestEvent represents a _1TestEvent event raised by the NumericMethodName contract. +type NumericMethodNameE1TestEvent struct { + Param common.Address + Raw *types.Log // Blockchain specific contextual infos +} + +const NumericMethodNameE1TestEventEventName = "_1TestEvent" + +// ContractEventName returns the user-defined event name. +func (NumericMethodNameE1TestEvent) ContractEventName() string { + return NumericMethodNameE1TestEventEventName +} + +// UnpackE1TestEventEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event _1TestEvent(address _param) +func (numericMethodName *NumericMethodName) UnpackE1TestEventEvent(log *types.Log) (*NumericMethodNameE1TestEvent, error) { + event := "_1TestEvent" + if log.Topics[0] != numericMethodName.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(NumericMethodNameE1TestEvent) + if len(log.Data) > 0 { + if err := numericMethodName.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range numericMethodName.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/outputchecker.go.txt b/accounts/abi/abigen/testdata/v2/outputchecker.go.txt new file mode 100644 index 000000000..6f1f8e679 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/outputchecker.go.txt @@ -0,0 +1,253 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// OutputCheckerMetaData contains all meta data concerning the OutputChecker contract. +var OutputCheckerMetaData = bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"noOutput\",\"constant\":true,\"inputs\":[],\"outputs\":[]},{\"type\":\"function\",\"name\":\"namedOutput\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"str\",\"type\":\"string\"}]},{\"type\":\"function\",\"name\":\"anonOutput\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\"}]},{\"type\":\"function\",\"name\":\"namedOutputs\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"str1\",\"type\":\"string\"},{\"name\":\"str2\",\"type\":\"string\"}]},{\"type\":\"function\",\"name\":\"collidingOutputs\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"str\",\"type\":\"string\"},{\"name\":\"Str\",\"type\":\"string\"}]},{\"type\":\"function\",\"name\":\"anonOutputs\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}]},{\"type\":\"function\",\"name\":\"mixedOutputs\",\"constant\":true,\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\"},{\"name\":\"str\",\"type\":\"string\"}]}]", + ID: "cc1d4e235801a590b506d5130b0cca90a1", +} + +// OutputChecker is an auto generated Go binding around an Ethereum contract. +type OutputChecker struct { + abi abi.ABI +} + +// NewOutputChecker creates a new instance of OutputChecker. +func NewOutputChecker() *OutputChecker { + parsed, err := OutputCheckerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &OutputChecker{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *OutputChecker) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackAnonOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x008bda05. +// +// Solidity: function anonOutput() returns(string) +func (outputChecker *OutputChecker) PackAnonOutput() []byte { + enc, err := outputChecker.abi.Pack("anonOutput") + if err != nil { + panic(err) + } + return enc +} + +// UnpackAnonOutput is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x008bda05. +// +// Solidity: function anonOutput() returns(string) +func (outputChecker *OutputChecker) UnpackAnonOutput(data []byte) (string, error) { + out, err := outputChecker.abi.Unpack("anonOutput", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} + +// PackAnonOutputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x3c401115. +// +// Solidity: function anonOutputs() returns(string, string) +func (outputChecker *OutputChecker) PackAnonOutputs() []byte { + enc, err := outputChecker.abi.Pack("anonOutputs") + if err != nil { + panic(err) + } + return enc +} + +// AnonOutputsOutput serves as a container for the return parameters of contract +// method AnonOutputs. +type AnonOutputsOutput struct { + Arg0 string + Arg1 string +} + +// UnpackAnonOutputs is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x3c401115. +// +// Solidity: function anonOutputs() returns(string, string) +func (outputChecker *OutputChecker) UnpackAnonOutputs(data []byte) (AnonOutputsOutput, error) { + out, err := outputChecker.abi.Unpack("anonOutputs", data) + outstruct := new(AnonOutputsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.Arg1 = *abi.ConvertType(out[1], new(string)).(*string) + return *outstruct, err + +} + +// PackCollidingOutputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xeccbc1ee. +// +// Solidity: function collidingOutputs() returns(string str, string Str) +func (outputChecker *OutputChecker) PackCollidingOutputs() []byte { + enc, err := outputChecker.abi.Pack("collidingOutputs") + if err != nil { + panic(err) + } + return enc +} + +// CollidingOutputsOutput serves as a container for the return parameters of contract +// method CollidingOutputs. +type CollidingOutputsOutput struct { + Str string + Str0 string +} + +// UnpackCollidingOutputs is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xeccbc1ee. +// +// Solidity: function collidingOutputs() returns(string str, string Str) +func (outputChecker *OutputChecker) UnpackCollidingOutputs(data []byte) (CollidingOutputsOutput, error) { + out, err := outputChecker.abi.Unpack("collidingOutputs", data) + outstruct := new(CollidingOutputsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Str = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.Str0 = *abi.ConvertType(out[1], new(string)).(*string) + return *outstruct, err + +} + +// PackMixedOutputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x21b77b44. +// +// Solidity: function mixedOutputs() returns(string, string str) +func (outputChecker *OutputChecker) PackMixedOutputs() []byte { + enc, err := outputChecker.abi.Pack("mixedOutputs") + if err != nil { + panic(err) + } + return enc +} + +// MixedOutputsOutput serves as a container for the return parameters of contract +// method MixedOutputs. +type MixedOutputsOutput struct { + Arg0 string + Str string +} + +// UnpackMixedOutputs is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x21b77b44. +// +// Solidity: function mixedOutputs() returns(string, string str) +func (outputChecker *OutputChecker) UnpackMixedOutputs(data []byte) (MixedOutputsOutput, error) { + out, err := outputChecker.abi.Unpack("mixedOutputs", data) + outstruct := new(MixedOutputsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.Str = *abi.ConvertType(out[1], new(string)).(*string) + return *outstruct, err + +} + +// PackNamedOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x5e632bd5. +// +// Solidity: function namedOutput() returns(string str) +func (outputChecker *OutputChecker) PackNamedOutput() []byte { + enc, err := outputChecker.abi.Pack("namedOutput") + if err != nil { + panic(err) + } + return enc +} + +// UnpackNamedOutput is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x5e632bd5. +// +// Solidity: function namedOutput() returns(string str) +func (outputChecker *OutputChecker) UnpackNamedOutput(data []byte) (string, error) { + out, err := outputChecker.abi.Unpack("namedOutput", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} + +// PackNamedOutputs is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x7970a189. +// +// Solidity: function namedOutputs() returns(string str1, string str2) +func (outputChecker *OutputChecker) PackNamedOutputs() []byte { + enc, err := outputChecker.abi.Pack("namedOutputs") + if err != nil { + panic(err) + } + return enc +} + +// NamedOutputsOutput serves as a container for the return parameters of contract +// method NamedOutputs. +type NamedOutputsOutput struct { + Str1 string + Str2 string +} + +// UnpackNamedOutputs is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x7970a189. +// +// Solidity: function namedOutputs() returns(string str1, string str2) +func (outputChecker *OutputChecker) UnpackNamedOutputs(data []byte) (NamedOutputsOutput, error) { + out, err := outputChecker.abi.Unpack("namedOutputs", data) + outstruct := new(NamedOutputsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Str1 = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.Str2 = *abi.ConvertType(out[1], new(string)).(*string) + return *outstruct, err + +} + +// PackNoOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x625f0306. +// +// Solidity: function noOutput() returns() +func (outputChecker *OutputChecker) PackNoOutput() []byte { + enc, err := outputChecker.abi.Pack("noOutput") + if err != nil { + panic(err) + } + return enc +} diff --git a/accounts/abi/abigen/testdata/v2/overload.go.txt b/accounts/abi/abigen/testdata/v2/overload.go.txt new file mode 100644 index 000000000..ed7c0b543 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/overload.go.txt @@ -0,0 +1,159 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// OverloadMetaData contains all meta data concerning the Overload contract. +var OverloadMetaData = bind.MetaData{ + ABI: "[{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"uint256\"},{\"name\":\"j\",\"type\":\"uint256\"}],\"name\":\"foo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"foo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"bar\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"i\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"j\",\"type\":\"uint256\"}],\"name\":\"bar\",\"type\":\"event\"}]", + ID: "f49f0ff7ed407de5c37214f49309072aec", + Bin: "0x608060405234801561001057600080fd5b50610153806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806304bc52f81461003b5780632fbebd3814610073575b600080fd5b6100716004803603604081101561005157600080fd5b8101908080359060200190929190803590602001909291905050506100a1565b005b61009f6004803603602081101561008957600080fd5b81019080803590602001909291905050506100e4565b005b7fae42e9514233792a47a1e4554624e83fe852228e1503f63cd383e8a431f4f46d8282604051808381526020018281526020019250505060405180910390a15050565b7f0423a1321222a0a8716c22b92fac42d85a45a612b696a461784d9fa537c81e5c816040518082815260200191505060405180910390a15056fea265627a7a72305820e22b049858b33291cbe67eeaece0c5f64333e439d27032ea8337d08b1de18fe864736f6c634300050a0032", +} + +// Overload is an auto generated Go binding around an Ethereum contract. +type Overload struct { + abi abi.ABI +} + +// NewOverload creates a new instance of Overload. +func NewOverload() *Overload { + parsed, err := OverloadMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Overload{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Overload) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackFoo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x04bc52f8. +// +// Solidity: function foo(uint256 i, uint256 j) returns() +func (overload *Overload) PackFoo(i *big.Int, j *big.Int) []byte { + enc, err := overload.abi.Pack("foo", i, j) + if err != nil { + panic(err) + } + return enc +} + +// PackFoo0 is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2fbebd38. +// +// Solidity: function foo(uint256 i) returns() +func (overload *Overload) PackFoo0(i *big.Int) []byte { + enc, err := overload.abi.Pack("foo0", i) + if err != nil { + panic(err) + } + return enc +} + +// OverloadBar represents a bar event raised by the Overload contract. +type OverloadBar struct { + I *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const OverloadBarEventName = "bar" + +// ContractEventName returns the user-defined event name. +func (OverloadBar) ContractEventName() string { + return OverloadBarEventName +} + +// UnpackBarEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event bar(uint256 i) +func (overload *Overload) UnpackBarEvent(log *types.Log) (*OverloadBar, error) { + event := "bar" + if log.Topics[0] != overload.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(OverloadBar) + if len(log.Data) > 0 { + if err := overload.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range overload.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// OverloadBar0 represents a bar0 event raised by the Overload contract. +type OverloadBar0 struct { + I *big.Int + J *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const OverloadBar0EventName = "bar0" + +// ContractEventName returns the user-defined event name. +func (OverloadBar0) ContractEventName() string { + return OverloadBar0EventName +} + +// UnpackBar0Event is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event bar(uint256 i, uint256 j) +func (overload *Overload) UnpackBar0Event(log *types.Log) (*OverloadBar0, error) { + event := "bar0" + if log.Topics[0] != overload.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(OverloadBar0) + if len(log.Data) > 0 { + if err := overload.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range overload.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/rangekeyword.go.txt b/accounts/abi/abigen/testdata/v2/rangekeyword.go.txt new file mode 100644 index 000000000..c7f142539 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/rangekeyword.go.txt @@ -0,0 +1,64 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// RangeKeywordMetaData contains all meta data concerning the RangeKeyword contract. +var RangeKeywordMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"range\",\"type\":\"uint256\"}],\"name\":\"functionWithKeywordParameter\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "cec8c872ba06feb1b8f0a00e7b237eb226", + Bin: "0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033", +} + +// RangeKeyword is an auto generated Go binding around an Ethereum contract. +type RangeKeyword struct { + abi abi.ABI +} + +// NewRangeKeyword creates a new instance of RangeKeyword. +func NewRangeKeyword() *RangeKeyword { + parsed, err := RangeKeywordMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &RangeKeyword{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *RangeKeyword) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackFunctionWithKeywordParameter is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x527a119f. +// +// Solidity: function functionWithKeywordParameter(uint256 range) pure returns() +func (rangeKeyword *RangeKeyword) PackFunctionWithKeywordParameter(arg0 *big.Int) []byte { + enc, err := rangeKeyword.abi.Pack("functionWithKeywordParameter", arg0) + if err != nil { + panic(err) + } + return enc +} diff --git a/accounts/abi/abigen/testdata/v2/slicer.go.txt b/accounts/abi/abigen/testdata/v2/slicer.go.txt new file mode 100644 index 000000000..b66c05cf0 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/slicer.go.txt @@ -0,0 +1,152 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// SlicerMetaData contains all meta data concerning the Slicer contract. +var SlicerMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[{\"name\":\"input\",\"type\":\"address[]\"}],\"name\":\"echoAddresses\",\"outputs\":[{\"name\":\"output\",\"type\":\"address[]\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"input\",\"type\":\"uint24[23]\"}],\"name\":\"echoFancyInts\",\"outputs\":[{\"name\":\"output\",\"type\":\"uint24[23]\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"input\",\"type\":\"int256[]\"}],\"name\":\"echoInts\",\"outputs\":[{\"name\":\"output\",\"type\":\"int256[]\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"input\",\"type\":\"bool[]\"}],\"name\":\"echoBools\",\"outputs\":[{\"name\":\"output\",\"type\":\"bool[]\"}],\"type\":\"function\"}]", + ID: "082c0740ab6537c7169cb573d097c52112", + Bin: "0x606060405261015c806100126000396000f3606060405260e060020a6000350463be1127a3811461003c578063d88becc014610092578063e15a3db71461003c578063f637e5891461003c575b005b604080516020600480358082013583810285810185019096528085526100ee959294602494909392850192829185019084908082843750949650505050505050604080516020810190915260009052805b919050565b604080516102e0818101909252610138916004916102e491839060179083908390808284375090955050505050506102e0604051908101604052806017905b60008152602001906001900390816100d15790505081905061008d565b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600f02600301f1509050019250505060405180910390f35b60405180826102e0808381846000600461015cf15090500191505060405180910390f3", +} + +// Slicer is an auto generated Go binding around an Ethereum contract. +type Slicer struct { + abi abi.ABI +} + +// NewSlicer creates a new instance of Slicer. +func NewSlicer() *Slicer { + parsed, err := SlicerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Slicer{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Slicer) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackEchoAddresses is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xbe1127a3. +// +// Solidity: function echoAddresses(address[] input) returns(address[] output) +func (slicer *Slicer) PackEchoAddresses(input []common.Address) []byte { + enc, err := slicer.abi.Pack("echoAddresses", input) + if err != nil { + panic(err) + } + return enc +} + +// UnpackEchoAddresses is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xbe1127a3. +// +// Solidity: function echoAddresses(address[] input) returns(address[] output) +func (slicer *Slicer) UnpackEchoAddresses(data []byte) ([]common.Address, error) { + out, err := slicer.abi.Unpack("echoAddresses", data) + if err != nil { + return *new([]common.Address), err + } + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + return out0, err +} + +// PackEchoBools is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xf637e589. +// +// Solidity: function echoBools(bool[] input) returns(bool[] output) +func (slicer *Slicer) PackEchoBools(input []bool) []byte { + enc, err := slicer.abi.Pack("echoBools", input) + if err != nil { + panic(err) + } + return enc +} + +// UnpackEchoBools is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xf637e589. +// +// Solidity: function echoBools(bool[] input) returns(bool[] output) +func (slicer *Slicer) UnpackEchoBools(data []byte) ([]bool, error) { + out, err := slicer.abi.Unpack("echoBools", data) + if err != nil { + return *new([]bool), err + } + out0 := *abi.ConvertType(out[0], new([]bool)).(*[]bool) + return out0, err +} + +// PackEchoFancyInts is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd88becc0. +// +// Solidity: function echoFancyInts(uint24[23] input) returns(uint24[23] output) +func (slicer *Slicer) PackEchoFancyInts(input [23]*big.Int) []byte { + enc, err := slicer.abi.Pack("echoFancyInts", input) + if err != nil { + panic(err) + } + return enc +} + +// UnpackEchoFancyInts is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xd88becc0. +// +// Solidity: function echoFancyInts(uint24[23] input) returns(uint24[23] output) +func (slicer *Slicer) UnpackEchoFancyInts(data []byte) ([23]*big.Int, error) { + out, err := slicer.abi.Unpack("echoFancyInts", data) + if err != nil { + return *new([23]*big.Int), err + } + out0 := *abi.ConvertType(out[0], new([23]*big.Int)).(*[23]*big.Int) + return out0, err +} + +// PackEchoInts is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe15a3db7. +// +// Solidity: function echoInts(int256[] input) returns(int256[] output) +func (slicer *Slicer) PackEchoInts(input []*big.Int) []byte { + enc, err := slicer.abi.Pack("echoInts", input) + if err != nil { + panic(err) + } + return enc +} + +// UnpackEchoInts is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xe15a3db7. +// +// Solidity: function echoInts(int256[] input) returns(int256[] output) +func (slicer *Slicer) UnpackEchoInts(data []byte) ([]*big.Int, error) { + out, err := slicer.abi.Unpack("echoInts", data) + if err != nil { + return *new([]*big.Int), err + } + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + return out0, err +} diff --git a/accounts/abi/abigen/testdata/v2/structs-abi.go.txt b/accounts/abi/abigen/testdata/v2/structs-abi.go.txt new file mode 100644 index 000000000..aab624270 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/structs-abi.go.txt @@ -0,0 +1,116 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package v1bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// Struct0 is an auto generated low-level Go binding around an user-defined struct. +type Struct0 struct { + B [32]byte +} + +// StructsMetaData contains all meta data concerning the Structs contract. +var StructsMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"F\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"c\",\"type\":\"uint256[]\"},{\"internalType\":\"bool[]\",\"name\":\"d\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"G\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ID: "Structs", +} + +// Structs is an auto generated Go binding around an Ethereum contract. +type Structs struct { + abi abi.ABI +} + +// NewStructs creates a new instance of Structs. +func NewStructs() *Structs { + parsed, err := StructsMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Structs{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +<<<<<<< HEAD +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Structs) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +======= +// Use this to create the instance object passed to abigen v2 library functions Call, +// Transact, etc. +func (c *Structs) Instance(backend bind.ContractBackend, addr common.Address) bind.BoundContract { + return bind.NewBoundContract(backend, addr, c.abi) +>>>>>>> 854c25e086 (accounts/abi/abigen: improve v2 template) +} + +// F is the Go binding used to pack the parameters required for calling +// the contract method 0x28811f59. +// +// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d) +func (structs *Structs) PackF() ([]byte, error) { + return structs.abi.Pack("F") +} + +// FOutput serves as a container for the return parameters of contract +// method F. +type FOutput struct { + A []Struct0 + C []*big.Int + D []bool +} + +// UnpackF is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x28811f59. +// +// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d) +func (structs *Structs) UnpackF(data []byte) (*FOutput, error) { + out, err := structs.abi.Unpack("F", data) + if err != nil { + return nil, err + } + ret := new(FOutput) + ret.A = *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0) + ret.C = *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int) + ret.D = *abi.ConvertType(out[2], new([]bool)).(*[]bool) + return ret, nil +} + +// G is the Go binding used to pack the parameters required for calling +// the contract method 0x6fecb623. +// +// Solidity: function G() view returns((bytes32)[] a) +func (structs *Structs) PackG() ([]byte, error) { + return structs.abi.Pack("G") +} + +// UnpackG is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x6fecb623. +// +// Solidity: function G() view returns((bytes32)[] a) +func (structs *Structs) UnpackG(data []byte) (*[]Struct0, error) { + out, err := structs.abi.Unpack("G", data) + if err != nil { + return nil, err + } + out0 := *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0) + return &out0, nil +} diff --git a/accounts/abi/abigen/testdata/v2/structs.go.txt b/accounts/abi/abigen/testdata/v2/structs.go.txt new file mode 100644 index 000000000..7fe59c561 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/structs.go.txt @@ -0,0 +1,119 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// Struct0 is an auto generated low-level Go binding around an user-defined struct. +type Struct0 struct { + B [32]byte +} + +// StructsMetaData contains all meta data concerning the Structs contract. +var StructsMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"F\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"c\",\"type\":\"uint256[]\"},{\"internalType\":\"bool[]\",\"name\":\"d\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"G\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ID: "920a35318e7581766aec7a17218628a91d", + Bin: "0x608060405234801561001057600080fd5b50610278806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806328811f591461003b5780636fecb6231461005b575b600080fd5b610043610070565b604051610052939291906101a0565b60405180910390f35b6100636100d6565b6040516100529190610186565b604080516002808252606082810190935282918291829190816020015b610095610131565b81526020019060019003908161008d575050805190915061026960611b9082906000906100be57fe5b60209081029190910101515293606093508392509050565b6040805160028082526060828101909352829190816020015b6100f7610131565b8152602001906001900390816100ef575050805190915061026960611b90829060009061012057fe5b602090810291909101015152905090565b60408051602081019091526000815290565b815260200190565b6000815180845260208085019450808401835b8381101561017b578151518752958201959082019060010161015e565b509495945050505050565b600060208252610199602083018461014b565b9392505050565b6000606082526101b3606083018661014b565b6020838203818501528186516101c98185610239565b91508288019350845b818110156101f3576101e5838651610143565b9484019492506001016101d2565b505084810360408601528551808252908201925081860190845b8181101561022b57825115158552938301939183019160010161020d565b509298975050505050505050565b9081526020019056fea2646970667358221220eb85327e285def14230424c52893aebecec1e387a50bb6b75fc4fdbed647f45f64736f6c63430006050033", +} + +// Structs is an auto generated Go binding around an Ethereum contract. +type Structs struct { + abi abi.ABI +} + +// NewStructs creates a new instance of Structs. +func NewStructs() *Structs { + parsed, err := StructsMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Structs{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Structs) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackF is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x28811f59. +// +// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d) +func (structs *Structs) PackF() []byte { + enc, err := structs.abi.Pack("F") + if err != nil { + panic(err) + } + return enc +} + +// FOutput serves as a container for the return parameters of contract +// method F. +type FOutput struct { + A []Struct0 + C []*big.Int + D []bool +} + +// UnpackF is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x28811f59. +// +// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d) +func (structs *Structs) UnpackF(data []byte) (FOutput, error) { + out, err := structs.abi.Unpack("F", data) + outstruct := new(FOutput) + if err != nil { + return *outstruct, err + } + outstruct.A = *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0) + outstruct.C = *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int) + outstruct.D = *abi.ConvertType(out[2], new([]bool)).(*[]bool) + return *outstruct, err + +} + +// PackG is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x6fecb623. +// +// Solidity: function G() view returns((bytes32)[] a) +func (structs *Structs) PackG() []byte { + enc, err := structs.abi.Pack("G") + if err != nil { + panic(err) + } + return enc +} + +// UnpackG is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x6fecb623. +// +// Solidity: function G() view returns((bytes32)[] a) +func (structs *Structs) UnpackG(data []byte) ([]Struct0, error) { + out, err := structs.abi.Unpack("G", data) + if err != nil { + return *new([]Struct0), err + } + out0 := *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0) + return out0, err +} diff --git a/accounts/abi/abigen/testdata/v2/token.go.txt b/accounts/abi/abigen/testdata/v2/token.go.txt new file mode 100644 index 000000000..aca18cb22 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/token.go.txt @@ -0,0 +1,319 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// TokenMetaData contains all meta data concerning the Token contract. +var TokenMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"},{\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"approveAndCall\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"address\"}],\"name\":\"spentAllowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"},{\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialSupply\",\"type\":\"uint256\"},{\"name\":\"tokenName\",\"type\":\"string\"},{\"name\":\"decimalUnits\",\"type\":\"uint8\"},{\"name\":\"tokenSymbol\",\"type\":\"string\"}],\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"}]", + ID: "1317f51c845ce3bfb7c268e5337a825f12", + Bin: "0x60606040526040516107fd3803806107fd83398101604052805160805160a05160c051929391820192909101600160a060020a0333166000908152600360209081526040822086905581548551838052601f6002600019610100600186161502019093169290920482018390047f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390810193919290918801908390106100e857805160ff19168380011785555b506101189291505b8082111561017157600081556001016100b4565b50506002805460ff19168317905550505050610658806101a56000396000f35b828001600101855582156100ac579182015b828111156100ac5782518260005055916020019190600101906100fa565b50508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017557805160ff19168380011785555b506100c89291506100b4565b5090565b82800160010185558215610165579182015b8281111561016557825182600050559160200191906001019061018756606060405236156100775760e060020a600035046306fdde03811461007f57806323b872dd146100dc578063313ce5671461010e57806370a082311461011a57806395d89b4114610132578063a9059cbb1461018e578063cae9ca51146101bd578063dc3080f21461031c578063dd62ed3e14610341575b610365610002565b61036760008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b6103d5600435602435604435600160a060020a038316600090815260036020526040812054829010156104f357610002565b6103e760025460ff1681565b6103d560043560036020526000908152604090205481565b610367600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b610365600435602435600160a060020a033316600090815260036020526040902054819010156103f157610002565b60806020604435600481810135601f8101849004909302840160405260608381526103d5948235946024803595606494939101919081908382808284375094965050505050505060006000836004600050600033600160a060020a03168152602001908152602001600020600050600087600160a060020a031681526020019081526020016000206000508190555084905080600160a060020a0316638f4ffcb1338630876040518560e060020a0281526004018085600160a060020a0316815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156102f25780820380516001836020036101000a031916815260200191505b50955050505050506000604051808303816000876161da5a03f11561000257505050509392505050565b6005602090815260043560009081526040808220909252602435815220546103d59081565b60046020818152903560009081526040808220909252602435815220546103d59081565b005b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a03821660009081526040902054808201101561041357610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b820191906000526020600020905b8154815290600101906020018083116104ce57829003601f168201915b505050505081565b600160a060020a03831681526040812054808301101561051257610002565b600160a060020a0380851680835260046020908152604080852033949094168086529382528085205492855260058252808520938552929052908220548301111561055c57610002565b816003600050600086600160a060020a03168152602001908152602001600020600082828250540392505081905550816003600050600085600160a060020a03168152602001908152602001600020600082828250540192505081905550816005600050600086600160a060020a03168152602001908152602001600020600050600033600160a060020a0316815260200190815260200160002060008282825054019250508190555082600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3939250505056", +} + +// Token is an auto generated Go binding around an Ethereum contract. +type Token struct { + abi abi.ABI +} + +// NewToken creates a new instance of Token. +func NewToken() *Token { + parsed, err := TokenMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Token{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Token) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) returns() +func (token *Token) PackConstructor(initialSupply *big.Int, tokenName string, decimalUnits uint8, tokenSymbol string) []byte { + enc, err := token.abi.Pack("", initialSupply, tokenName, decimalUnits, tokenSymbol) + if err != nil { + panic(err) + } + return enc +} + +// PackAllowance is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xdd62ed3e. +// +// Solidity: function allowance(address , address ) returns(uint256) +func (token *Token) PackAllowance(arg0 common.Address, arg1 common.Address) []byte { + enc, err := token.abi.Pack("allowance", arg0, arg1) + if err != nil { + panic(err) + } + return enc +} + +// UnpackAllowance is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xdd62ed3e. +// +// Solidity: function allowance(address , address ) returns(uint256) +func (token *Token) UnpackAllowance(data []byte) (*big.Int, error) { + out, err := token.abi.Unpack("allowance", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackApproveAndCall is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xcae9ca51. +// +// Solidity: function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns(bool success) +func (token *Token) PackApproveAndCall(spender common.Address, value *big.Int, extraData []byte) []byte { + enc, err := token.abi.Pack("approveAndCall", spender, value, extraData) + if err != nil { + panic(err) + } + return enc +} + +// UnpackApproveAndCall is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xcae9ca51. +// +// Solidity: function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns(bool success) +func (token *Token) UnpackApproveAndCall(data []byte) (bool, error) { + out, err := token.abi.Unpack("approveAndCall", data) + if err != nil { + return *new(bool), err + } + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + return out0, err +} + +// PackBalanceOf is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x70a08231. +// +// Solidity: function balanceOf(address ) returns(uint256) +func (token *Token) PackBalanceOf(arg0 common.Address) []byte { + enc, err := token.abi.Pack("balanceOf", arg0) + if err != nil { + panic(err) + } + return enc +} + +// UnpackBalanceOf is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x70a08231. +// +// Solidity: function balanceOf(address ) returns(uint256) +func (token *Token) UnpackBalanceOf(data []byte) (*big.Int, error) { + out, err := token.abi.Unpack("balanceOf", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackDecimals is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x313ce567. +// +// Solidity: function decimals() returns(uint8) +func (token *Token) PackDecimals() []byte { + enc, err := token.abi.Pack("decimals") + if err != nil { + panic(err) + } + return enc +} + +// UnpackDecimals is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x313ce567. +// +// Solidity: function decimals() returns(uint8) +func (token *Token) UnpackDecimals(data []byte) (uint8, error) { + out, err := token.abi.Unpack("decimals", data) + if err != nil { + return *new(uint8), err + } + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + return out0, err +} + +// PackName is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x06fdde03. +// +// Solidity: function name() returns(string) +func (token *Token) PackName() []byte { + enc, err := token.abi.Pack("name") + if err != nil { + panic(err) + } + return enc +} + +// UnpackName is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x06fdde03. +// +// Solidity: function name() returns(string) +func (token *Token) UnpackName(data []byte) (string, error) { + out, err := token.abi.Unpack("name", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} + +// PackSpentAllowance is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xdc3080f2. +// +// Solidity: function spentAllowance(address , address ) returns(uint256) +func (token *Token) PackSpentAllowance(arg0 common.Address, arg1 common.Address) []byte { + enc, err := token.abi.Pack("spentAllowance", arg0, arg1) + if err != nil { + panic(err) + } + return enc +} + +// UnpackSpentAllowance is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xdc3080f2. +// +// Solidity: function spentAllowance(address , address ) returns(uint256) +func (token *Token) UnpackSpentAllowance(data []byte) (*big.Int, error) { + out, err := token.abi.Unpack("spentAllowance", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackSymbol is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x95d89b41. +// +// Solidity: function symbol() returns(string) +func (token *Token) PackSymbol() []byte { + enc, err := token.abi.Pack("symbol") + if err != nil { + panic(err) + } + return enc +} + +// UnpackSymbol is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x95d89b41. +// +// Solidity: function symbol() returns(string) +func (token *Token) UnpackSymbol(data []byte) (string, error) { + out, err := token.abi.Unpack("symbol", data) + if err != nil { + return *new(string), err + } + out0 := *abi.ConvertType(out[0], new(string)).(*string) + return out0, err +} + +// PackTransfer is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xa9059cbb. +// +// Solidity: function transfer(address _to, uint256 _value) returns() +func (token *Token) PackTransfer(to common.Address, value *big.Int) []byte { + enc, err := token.abi.Pack("transfer", to, value) + if err != nil { + panic(err) + } + return enc +} + +// PackTransferFrom is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x23b872dd. +// +// Solidity: function transferFrom(address _from, address _to, uint256 _value) returns(bool success) +func (token *Token) PackTransferFrom(from common.Address, to common.Address, value *big.Int) []byte { + enc, err := token.abi.Pack("transferFrom", from, to, value) + if err != nil { + panic(err) + } + return enc +} + +// UnpackTransferFrom is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x23b872dd. +// +// Solidity: function transferFrom(address _from, address _to, uint256 _value) returns(bool success) +func (token *Token) UnpackTransferFrom(data []byte) (bool, error) { + out, err := token.abi.Unpack("transferFrom", data) + if err != nil { + return *new(bool), err + } + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + return out0, err +} + +// TokenTransfer represents a Transfer event raised by the Token contract. +type TokenTransfer struct { + From common.Address + To common.Address + Value *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const TokenTransferEventName = "Transfer" + +// ContractEventName returns the user-defined event name. +func (TokenTransfer) ContractEventName() string { + return TokenTransferEventName +} + +// UnpackTransferEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (token *Token) UnpackTransferEvent(log *types.Log) (*TokenTransfer, error) { + event := "Transfer" + if log.Topics[0] != token.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(TokenTransfer) + if len(log.Data) > 0 { + if err := token.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range token.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/tuple.go.txt b/accounts/abi/abigen/testdata/v2/tuple.go.txt new file mode 100644 index 000000000..65af76546 --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/tuple.go.txt @@ -0,0 +1,228 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// TupleP is an auto generated low-level Go binding around an user-defined struct. +type TupleP struct { + X uint8 + Y uint8 +} + +// TupleQ is an auto generated low-level Go binding around an user-defined struct. +type TupleQ struct { + X uint16 + Y uint16 +} + +// TupleS is an auto generated low-level Go binding around an user-defined struct. +type TupleS struct { + A *big.Int + B []*big.Int + C []TupleT +} + +// TupleT is an auto generated low-level Go binding around an user-defined struct. +type TupleT struct { + X *big.Int + Y *big.Int +} + +// TupleMetaData contains all meta data concerning the Tuple contract. +var TupleMetaData = bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structTuple.S\",\"name\":\"a\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTuple.T[2][]\",\"name\":\"b\",\"type\":\"tuple[2][]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTuple.T[][2]\",\"name\":\"c\",\"type\":\"tuple[][2]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structTuple.S[]\",\"name\":\"d\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"e\",\"type\":\"uint256[]\"}],\"name\":\"TupleEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"x\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"y\",\"type\":\"uint8\"}],\"indexed\":false,\"internalType\":\"structTuple.P[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"TupleEvent2\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S\",\"name\":\"a\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[2][]\",\"name\":\"b\",\"type\":\"tuple[2][]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[][2]\",\"name\":\"c\",\"type\":\"tuple[][2]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S[]\",\"name\":\"d\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"e\",\"type\":\"uint256[]\"}],\"name\":\"func1\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[2][]\",\"name\":\"\",\"type\":\"tuple[2][]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[][2]\",\"name\":\"\",\"type\":\"tuple[][2]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S\",\"name\":\"a\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[2][]\",\"name\":\"b\",\"type\":\"tuple[2][]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[][2]\",\"name\":\"c\",\"type\":\"tuple[][2]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"a\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"b\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"structTuple.T[]\",\"name\":\"c\",\"type\":\"tuple[]\"}],\"internalType\":\"structTuple.S[]\",\"name\":\"d\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"e\",\"type\":\"uint256[]\"}],\"name\":\"func2\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"x\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"y\",\"type\":\"uint16\"}],\"internalType\":\"structTuple.Q[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"func3\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "96ee1e2b1b89f8c495f200e4956278a4d4", + Bin: "0x60806040523480156100115760006000fd5b50610017565b6110b2806100266000396000f3fe60806040523480156100115760006000fd5b50600436106100465760003560e01c8063443c79b41461004c578063d0062cdd14610080578063e4d9a43b1461009c57610046565b60006000fd5b610066600480360361006191908101906107b8565b6100b8565b604051610077959493929190610ccb565b60405180910390f35b61009a600480360361009591908101906107b8565b6100ef565b005b6100b660048036036100b19190810190610775565b610136565b005b6100c061013a565b60606100ca61015e565b606060608989898989945094509450945094506100e2565b9550955095509550959050565b7f18d6e66efa53739ca6d13626f35ebc700b31cced3eddb50c70bbe9c082c6cd008585858585604051610126959493929190610ccb565b60405180910390a15b5050505050565b5b50565b60405180606001604052806000815260200160608152602001606081526020015090565b60405180604001604052806002905b606081526020019060019003908161016d57905050905661106e565b600082601f830112151561019d5760006000fd5b81356101b06101ab82610d6f565b610d41565b915081818352602084019350602081019050838560808402820111156101d65760006000fd5b60005b8381101561020757816101ec888261037a565b8452602084019350608083019250505b6001810190506101d9565b5050505092915050565b600082601f83011215156102255760006000fd5b600261023861023382610d98565b610d41565b9150818360005b83811015610270578135860161025588826103f3565b8452602084019350602083019250505b60018101905061023f565b5050505092915050565b600082601f830112151561028e5760006000fd5b81356102a161029c82610dbb565b610d41565b915081818352602084019350602081019050838560408402820111156102c75760006000fd5b60005b838110156102f857816102dd888261058b565b8452602084019350604083019250505b6001810190506102ca565b5050505092915050565b600082601f83011215156103165760006000fd5b813561032961032482610de4565b610d41565b9150818183526020840193506020810190508360005b83811015610370578135860161035588826105d8565b8452602084019350602083019250505b60018101905061033f565b5050505092915050565b600082601f830112151561038e5760006000fd5b60026103a161039c82610e0d565b610d41565b915081838560408402820111156103b85760006000fd5b60005b838110156103e957816103ce88826106fe565b8452602084019350604083019250505b6001810190506103bb565b5050505092915050565b600082601f83011215156104075760006000fd5b813561041a61041582610e30565b610d41565b915081818352602084019350602081019050838560408402820111156104405760006000fd5b60005b83811015610471578161045688826106fe565b8452602084019350604083019250505b600181019050610443565b5050505092915050565b600082601f830112151561048f5760006000fd5b81356104a261049d82610e59565b610d41565b915081818352602084019350602081019050838560208402820111156104c85760006000fd5b60005b838110156104f957816104de8882610760565b8452602084019350602083019250505b6001810190506104cb565b5050505092915050565b600082601f83011215156105175760006000fd5b813561052a61052582610e82565b610d41565b915081818352602084019350602081019050838560208402820111156105505760006000fd5b60005b8381101561058157816105668882610760565b8452602084019350602083019250505b600181019050610553565b5050505092915050565b60006040828403121561059e5760006000fd5b6105a86040610d41565b905060006105b88482850161074b565b60008301525060206105cc8482850161074b565b60208301525092915050565b6000606082840312156105eb5760006000fd5b6105f56060610d41565b9050600061060584828501610760565b600083015250602082013567ffffffffffffffff8111156106265760006000fd5b6106328482850161047b565b602083015250604082013567ffffffffffffffff8111156106535760006000fd5b61065f848285016103f3565b60408301525092915050565b60006060828403121561067e5760006000fd5b6106886060610d41565b9050600061069884828501610760565b600083015250602082013567ffffffffffffffff8111156106b95760006000fd5b6106c58482850161047b565b602083015250604082013567ffffffffffffffff8111156106e65760006000fd5b6106f2848285016103f3565b60408301525092915050565b6000604082840312156107115760006000fd5b61071b6040610d41565b9050600061072b84828501610760565b600083015250602061073f84828501610760565b60208301525092915050565b60008135905061075a8161103a565b92915050565b60008135905061076f81611054565b92915050565b6000602082840312156107885760006000fd5b600082013567ffffffffffffffff8111156107a35760006000fd5b6107af8482850161027a565b91505092915050565b6000600060006000600060a086880312156107d35760006000fd5b600086013567ffffffffffffffff8111156107ee5760006000fd5b6107fa8882890161066b565b955050602086013567ffffffffffffffff8111156108185760006000fd5b61082488828901610189565b945050604086013567ffffffffffffffff8111156108425760006000fd5b61084e88828901610211565b935050606086013567ffffffffffffffff81111561086c5760006000fd5b61087888828901610302565b925050608086013567ffffffffffffffff8111156108965760006000fd5b6108a288828901610503565b9150509295509295909350565b60006108bb8383610a6a565b60808301905092915050565b60006108d38383610ac2565b905092915050565b60006108e78383610c36565b905092915050565b60006108fb8383610c8d565b60408301905092915050565b60006109138383610cbc565b60208301905092915050565b600061092a82610f0f565b6109348185610fb7565b935061093f83610eab565b8060005b8381101561097157815161095788826108af565b975061096283610f5c565b9250505b600181019050610943565b5085935050505092915050565b600061098982610f1a565b6109938185610fc8565b9350836020820285016109a585610ebb565b8060005b858110156109e257848403895281516109c285826108c7565b94506109cd83610f69565b925060208a019950505b6001810190506109a9565b50829750879550505050505092915050565b60006109ff82610f25565b610a098185610fd3565b935083602082028501610a1b85610ec5565b8060005b85811015610a585784840389528151610a3885826108db565b9450610a4383610f76565b925060208a019950505b600181019050610a1f565b50829750879550505050505092915050565b610a7381610f30565b610a7d8184610fe4565b9250610a8882610ed5565b8060005b83811015610aba578151610aa087826108ef565b9650610aab83610f83565b9250505b600181019050610a8c565b505050505050565b6000610acd82610f3b565b610ad78185610fef565b9350610ae283610edf565b8060005b83811015610b14578151610afa88826108ef565b9750610b0583610f90565b9250505b600181019050610ae6565b5085935050505092915050565b6000610b2c82610f51565b610b368185611011565b9350610b4183610eff565b8060005b83811015610b73578151610b598882610907565b9750610b6483610faa565b9250505b600181019050610b45565b5085935050505092915050565b6000610b8b82610f46565b610b958185611000565b9350610ba083610eef565b8060005b83811015610bd2578151610bb88882610907565b9750610bc383610f9d565b9250505b600181019050610ba4565b5085935050505092915050565b6000606083016000830151610bf76000860182610cbc565b5060208301518482036020860152610c0f8282610b80565b91505060408301518482036040860152610c298282610ac2565b9150508091505092915050565b6000606083016000830151610c4e6000860182610cbc565b5060208301518482036020860152610c668282610b80565b91505060408301518482036040860152610c808282610ac2565b9150508091505092915050565b604082016000820151610ca36000850182610cbc565b506020820151610cb66020850182610cbc565b50505050565b610cc581611030565b82525050565b600060a0820190508181036000830152610ce58188610bdf565b90508181036020830152610cf9818761091f565b90508181036040830152610d0d818661097e565b90508181036060830152610d2181856109f4565b90508181036080830152610d358184610b21565b90509695505050505050565b6000604051905081810181811067ffffffffffffffff82111715610d655760006000fd5b8060405250919050565b600067ffffffffffffffff821115610d875760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610db05760006000fd5b602082029050919050565b600067ffffffffffffffff821115610dd35760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610dfc5760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e255760006000fd5b602082029050919050565b600067ffffffffffffffff821115610e485760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e715760006000fd5b602082029050602081019050919050565b600067ffffffffffffffff821115610e9a5760006000fd5b602082029050602081019050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600061ffff82169050919050565b6000819050919050565b61104381611022565b811415156110515760006000fd5b50565b61105d81611030565b8114151561106b5760006000fd5b50565bfea365627a7a72315820d78c6ba7ee332581e6c4d9daa5fc07941841230f7ce49edf6e05b1b63853e8746c6578706572696d656e74616cf564736f6c634300050c0040", +} + +// Tuple is an auto generated Go binding around an Ethereum contract. +type Tuple struct { + abi abi.ABI +} + +// NewTuple creates a new instance of Tuple. +func NewTuple() *Tuple { + parsed, err := TupleMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Tuple{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Tuple) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackFunc1 is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x443c79b4. +// +// Solidity: function func1((uint256,uint256[],(uint256,uint256)[]) a, (uint256,uint256)[2][] b, (uint256,uint256)[][2] c, (uint256,uint256[],(uint256,uint256)[])[] d, uint256[] e) pure returns((uint256,uint256[],(uint256,uint256)[]), (uint256,uint256)[2][], (uint256,uint256)[][2], (uint256,uint256[],(uint256,uint256)[])[], uint256[]) +func (tuple *Tuple) PackFunc1(a TupleS, b [][2]TupleT, c [2][]TupleT, d []TupleS, e []*big.Int) []byte { + enc, err := tuple.abi.Pack("func1", a, b, c, d, e) + if err != nil { + panic(err) + } + return enc +} + +// Func1Output serves as a container for the return parameters of contract +// method Func1. +type Func1Output struct { + Arg0 TupleS + Arg1 [][2]TupleT + Arg2 [2][]TupleT + Arg3 []TupleS + Arg4 []*big.Int +} + +// UnpackFunc1 is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x443c79b4. +// +// Solidity: function func1((uint256,uint256[],(uint256,uint256)[]) a, (uint256,uint256)[2][] b, (uint256,uint256)[][2] c, (uint256,uint256[],(uint256,uint256)[])[] d, uint256[] e) pure returns((uint256,uint256[],(uint256,uint256)[]), (uint256,uint256)[2][], (uint256,uint256)[][2], (uint256,uint256[],(uint256,uint256)[])[], uint256[]) +func (tuple *Tuple) UnpackFunc1(data []byte) (Func1Output, error) { + out, err := tuple.abi.Unpack("func1", data) + outstruct := new(Func1Output) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = *abi.ConvertType(out[0], new(TupleS)).(*TupleS) + outstruct.Arg1 = *abi.ConvertType(out[1], new([][2]TupleT)).(*[][2]TupleT) + outstruct.Arg2 = *abi.ConvertType(out[2], new([2][]TupleT)).(*[2][]TupleT) + outstruct.Arg3 = *abi.ConvertType(out[3], new([]TupleS)).(*[]TupleS) + outstruct.Arg4 = *abi.ConvertType(out[4], new([]*big.Int)).(*[]*big.Int) + return *outstruct, err + +} + +// PackFunc2 is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xd0062cdd. +// +// Solidity: function func2((uint256,uint256[],(uint256,uint256)[]) a, (uint256,uint256)[2][] b, (uint256,uint256)[][2] c, (uint256,uint256[],(uint256,uint256)[])[] d, uint256[] e) returns() +func (tuple *Tuple) PackFunc2(a TupleS, b [][2]TupleT, c [2][]TupleT, d []TupleS, e []*big.Int) []byte { + enc, err := tuple.abi.Pack("func2", a, b, c, d, e) + if err != nil { + panic(err) + } + return enc +} + +// PackFunc3 is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe4d9a43b. +// +// Solidity: function func3((uint16,uint16)[] ) pure returns() +func (tuple *Tuple) PackFunc3(arg0 []TupleQ) []byte { + enc, err := tuple.abi.Pack("func3", arg0) + if err != nil { + panic(err) + } + return enc +} + +// TupleTupleEvent represents a TupleEvent event raised by the Tuple contract. +type TupleTupleEvent struct { + A TupleS + B [][2]TupleT + C [2][]TupleT + D []TupleS + E []*big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const TupleTupleEventEventName = "TupleEvent" + +// ContractEventName returns the user-defined event name. +func (TupleTupleEvent) ContractEventName() string { + return TupleTupleEventEventName +} + +// UnpackTupleEventEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event TupleEvent((uint256,uint256[],(uint256,uint256)[]) a, (uint256,uint256)[2][] b, (uint256,uint256)[][2] c, (uint256,uint256[],(uint256,uint256)[])[] d, uint256[] e) +func (tuple *Tuple) UnpackTupleEventEvent(log *types.Log) (*TupleTupleEvent, error) { + event := "TupleEvent" + if log.Topics[0] != tuple.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(TupleTupleEvent) + if len(log.Data) > 0 { + if err := tuple.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range tuple.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// TupleTupleEvent2 represents a TupleEvent2 event raised by the Tuple contract. +type TupleTupleEvent2 struct { + Arg0 []TupleP + Raw *types.Log // Blockchain specific contextual infos +} + +const TupleTupleEvent2EventName = "TupleEvent2" + +// ContractEventName returns the user-defined event name. +func (TupleTupleEvent2) ContractEventName() string { + return TupleTupleEvent2EventName +} + +// UnpackTupleEvent2Event is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event TupleEvent2((uint8,uint8)[] arg0) +func (tuple *Tuple) UnpackTupleEvent2Event(log *types.Log) (*TupleTupleEvent2, error) { + event := "TupleEvent2" + if log.Topics[0] != tuple.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(TupleTupleEvent2) + if len(log.Data) > 0 { + if err := tuple.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range tuple.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/abigen/testdata/v2/tupler.go.txt b/accounts/abi/abigen/testdata/v2/tupler.go.txt new file mode 100644 index 000000000..caa692dad --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/tupler.go.txt @@ -0,0 +1,89 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// TuplerMetaData contains all meta data concerning the Tupler contract. +var TuplerMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"tuple\",\"outputs\":[{\"name\":\"a\",\"type\":\"string\"},{\"name\":\"b\",\"type\":\"int256\"},{\"name\":\"c\",\"type\":\"bytes32\"}],\"type\":\"function\"}]", + ID: "a8f4d2061f55c712cfae266c426a1cd568", + Bin: "0x606060405260dc8060106000396000f3606060405260e060020a60003504633175aae28114601a575b005b600060605260c0604052600260809081527f486900000000000000000000000000000000000000000000000000000000000060a05260017fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060e0829052610100819052606060c0908152600261012081905281906101409060a09080838184600060046012f1505081517fffff000000000000000000000000000000000000000000000000000000000000169091525050604051610160819003945092505050f3", +} + +// Tupler is an auto generated Go binding around an Ethereum contract. +type Tupler struct { + abi abi.ABI +} + +// NewTupler creates a new instance of Tupler. +func NewTupler() *Tupler { + parsed, err := TuplerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Tupler{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Tupler) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackTuple is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x3175aae2. +// +// Solidity: function tuple() returns(string a, int256 b, bytes32 c) +func (tupler *Tupler) PackTuple() []byte { + enc, err := tupler.abi.Pack("tuple") + if err != nil { + panic(err) + } + return enc +} + +// TupleOutput serves as a container for the return parameters of contract +// method Tuple. +type TupleOutput struct { + A string + B *big.Int + C [32]byte +} + +// UnpackTuple is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x3175aae2. +// +// Solidity: function tuple() returns(string a, int256 b, bytes32 c) +func (tupler *Tupler) UnpackTuple(data []byte) (TupleOutput, error) { + out, err := tupler.abi.Unpack("tuple", data) + outstruct := new(TupleOutput) + if err != nil { + return *outstruct, err + } + outstruct.A = *abi.ConvertType(out[0], new(string)).(*string) + outstruct.B = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + outstruct.C = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + return *outstruct, err + +} diff --git a/accounts/abi/abigen/testdata/v2/underscorer.go.txt b/accounts/abi/abigen/testdata/v2/underscorer.go.txt new file mode 100644 index 000000000..ef9eb864f --- /dev/null +++ b/accounts/abi/abigen/testdata/v2/underscorer.go.txt @@ -0,0 +1,322 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindtests + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// UnderscorerMetaData contains all meta data concerning the Underscorer contract. +var UnderscorerMetaData = bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"LowerUpperCollision\",\"outputs\":[{\"name\":\"_res\",\"type\":\"int256\"},{\"name\":\"Res\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"_under_scored_func\",\"outputs\":[{\"name\":\"_int\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"UnderscoredOutput\",\"outputs\":[{\"name\":\"_int\",\"type\":\"int256\"},{\"name\":\"_string\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"PurelyUnderscoredOutput\",\"outputs\":[{\"name\":\"_\",\"type\":\"int256\"},{\"name\":\"res\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"UpperLowerCollision\",\"outputs\":[{\"name\":\"_Res\",\"type\":\"int256\"},{\"name\":\"res\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"AllPurelyUnderscoredOutput\",\"outputs\":[{\"name\":\"_\",\"type\":\"int256\"},{\"name\":\"__\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"UpperUpperCollision\",\"outputs\":[{\"name\":\"_Res\",\"type\":\"int256\"},{\"name\":\"Res\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"LowerLowerCollision\",\"outputs\":[{\"name\":\"_res\",\"type\":\"int256\"},{\"name\":\"res\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]", + ID: "5873a90ab43c925dfced86ad53f871f01d", + Bin: "0x6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029", +} + +// Underscorer is an auto generated Go binding around an Ethereum contract. +type Underscorer struct { + abi abi.ABI +} + +// NewUnderscorer creates a new instance of Underscorer. +func NewUnderscorer() *Underscorer { + parsed, err := UnderscorerMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &Underscorer{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *Underscorer) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackAllPurelyUnderscoredOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xb564b34d. +// +// Solidity: function AllPurelyUnderscoredOutput() view returns(int256 _, int256 __) +func (underscorer *Underscorer) PackAllPurelyUnderscoredOutput() []byte { + enc, err := underscorer.abi.Pack("AllPurelyUnderscoredOutput") + if err != nil { + panic(err) + } + return enc +} + +// AllPurelyUnderscoredOutputOutput serves as a container for the return parameters of contract +// method AllPurelyUnderscoredOutput. +type AllPurelyUnderscoredOutputOutput struct { + Arg0 *big.Int + Arg1 *big.Int +} + +// UnpackAllPurelyUnderscoredOutput is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xb564b34d. +// +// Solidity: function AllPurelyUnderscoredOutput() view returns(int256 _, int256 __) +func (underscorer *Underscorer) UnpackAllPurelyUnderscoredOutput(data []byte) (AllPurelyUnderscoredOutputOutput, error) { + out, err := underscorer.abi.Unpack("AllPurelyUnderscoredOutput", data) + outstruct := new(AllPurelyUnderscoredOutputOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Arg1 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackLowerLowerCollision is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe409ca45. +// +// Solidity: function LowerLowerCollision() view returns(int256 _res, int256 res) +func (underscorer *Underscorer) PackLowerLowerCollision() []byte { + enc, err := underscorer.abi.Pack("LowerLowerCollision") + if err != nil { + panic(err) + } + return enc +} + +// LowerLowerCollisionOutput serves as a container for the return parameters of contract +// method LowerLowerCollision. +type LowerLowerCollisionOutput struct { + Res *big.Int + Res0 *big.Int +} + +// UnpackLowerLowerCollision is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xe409ca45. +// +// Solidity: function LowerLowerCollision() view returns(int256 _res, int256 res) +func (underscorer *Underscorer) UnpackLowerLowerCollision(data []byte) (LowerLowerCollisionOutput, error) { + out, err := underscorer.abi.Unpack("LowerLowerCollision", data) + outstruct := new(LowerLowerCollisionOutput) + if err != nil { + return *outstruct, err + } + outstruct.Res = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Res0 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackLowerUpperCollision is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x03a59213. +// +// Solidity: function LowerUpperCollision() view returns(int256 _res, int256 Res) +func (underscorer *Underscorer) PackLowerUpperCollision() []byte { + enc, err := underscorer.abi.Pack("LowerUpperCollision") + if err != nil { + panic(err) + } + return enc +} + +// LowerUpperCollisionOutput serves as a container for the return parameters of contract +// method LowerUpperCollision. +type LowerUpperCollisionOutput struct { + Res *big.Int + Res0 *big.Int +} + +// UnpackLowerUpperCollision is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x03a59213. +// +// Solidity: function LowerUpperCollision() view returns(int256 _res, int256 Res) +func (underscorer *Underscorer) UnpackLowerUpperCollision(data []byte) (LowerUpperCollisionOutput, error) { + out, err := underscorer.abi.Unpack("LowerUpperCollision", data) + outstruct := new(LowerUpperCollisionOutput) + if err != nil { + return *outstruct, err + } + outstruct.Res = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Res0 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackPurelyUnderscoredOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x9df48485. +// +// Solidity: function PurelyUnderscoredOutput() view returns(int256 _, int256 res) +func (underscorer *Underscorer) PackPurelyUnderscoredOutput() []byte { + enc, err := underscorer.abi.Pack("PurelyUnderscoredOutput") + if err != nil { + panic(err) + } + return enc +} + +// PurelyUnderscoredOutputOutput serves as a container for the return parameters of contract +// method PurelyUnderscoredOutput. +type PurelyUnderscoredOutputOutput struct { + Arg0 *big.Int + Res *big.Int +} + +// UnpackPurelyUnderscoredOutput is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x9df48485. +// +// Solidity: function PurelyUnderscoredOutput() view returns(int256 _, int256 res) +func (underscorer *Underscorer) UnpackPurelyUnderscoredOutput(data []byte) (PurelyUnderscoredOutputOutput, error) { + out, err := underscorer.abi.Unpack("PurelyUnderscoredOutput", data) + outstruct := new(PurelyUnderscoredOutputOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Res = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackUnderscoredOutput is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x67e6633d. +// +// Solidity: function UnderscoredOutput() view returns(int256 _int, string _string) +func (underscorer *Underscorer) PackUnderscoredOutput() []byte { + enc, err := underscorer.abi.Pack("UnderscoredOutput") + if err != nil { + panic(err) + } + return enc +} + +// UnderscoredOutputOutput serves as a container for the return parameters of contract +// method UnderscoredOutput. +type UnderscoredOutputOutput struct { + Int *big.Int + String string +} + +// UnpackUnderscoredOutput is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x67e6633d. +// +// Solidity: function UnderscoredOutput() view returns(int256 _int, string _string) +func (underscorer *Underscorer) UnpackUnderscoredOutput(data []byte) (UnderscoredOutputOutput, error) { + out, err := underscorer.abi.Unpack("UnderscoredOutput", data) + outstruct := new(UnderscoredOutputOutput) + if err != nil { + return *outstruct, err + } + outstruct.Int = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.String = *abi.ConvertType(out[1], new(string)).(*string) + return *outstruct, err + +} + +// PackUpperLowerCollision is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xaf7486ab. +// +// Solidity: function UpperLowerCollision() view returns(int256 _Res, int256 res) +func (underscorer *Underscorer) PackUpperLowerCollision() []byte { + enc, err := underscorer.abi.Pack("UpperLowerCollision") + if err != nil { + panic(err) + } + return enc +} + +// UpperLowerCollisionOutput serves as a container for the return parameters of contract +// method UpperLowerCollision. +type UpperLowerCollisionOutput struct { + Res *big.Int + Res0 *big.Int +} + +// UnpackUpperLowerCollision is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xaf7486ab. +// +// Solidity: function UpperLowerCollision() view returns(int256 _Res, int256 res) +func (underscorer *Underscorer) UnpackUpperLowerCollision(data []byte) (UpperLowerCollisionOutput, error) { + out, err := underscorer.abi.Unpack("UpperLowerCollision", data) + outstruct := new(UpperLowerCollisionOutput) + if err != nil { + return *outstruct, err + } + outstruct.Res = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Res0 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackUpperUpperCollision is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe02ab24d. +// +// Solidity: function UpperUpperCollision() view returns(int256 _Res, int256 Res) +func (underscorer *Underscorer) PackUpperUpperCollision() []byte { + enc, err := underscorer.abi.Pack("UpperUpperCollision") + if err != nil { + panic(err) + } + return enc +} + +// UpperUpperCollisionOutput serves as a container for the return parameters of contract +// method UpperUpperCollision. +type UpperUpperCollisionOutput struct { + Res *big.Int + Res0 *big.Int +} + +// UnpackUpperUpperCollision is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xe02ab24d. +// +// Solidity: function UpperUpperCollision() view returns(int256 _Res, int256 Res) +func (underscorer *Underscorer) UnpackUpperUpperCollision(data []byte) (UpperUpperCollisionOutput, error) { + out, err := underscorer.abi.Unpack("UpperUpperCollision", data) + outstruct := new(UpperUpperCollisionOutput) + if err != nil { + return *outstruct, err + } + outstruct.Res = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Res0 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackUnderScoredFunc is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x46546dbe. +// +// Solidity: function _under_scored_func() view returns(int256 _int) +func (underscorer *Underscorer) PackUnderScoredFunc() []byte { + enc, err := underscorer.abi.Pack("_under_scored_func") + if err != nil { + panic(err) + } + return enc +} + +// UnpackUnderScoredFunc is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x46546dbe. +// +// Solidity: function _under_scored_func() view returns(int256 _int) +func (underscorer *Underscorer) UnpackUnderScoredFunc(data []byte) (*big.Int, error) { + out, err := underscorer.abi.Unpack("_under_scored_func", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go deleted file mode 100644 index b5e6e349c..000000000 --- a/accounts/abi/bind/auth.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2016 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 . - -package bind - -import ( - "context" - "crypto/ecdsa" - "errors" - "io" - "math/big" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/external" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" -) - -// ErrNoChainID is returned whenever the user failed to specify a chain id. -var ErrNoChainID = errors.New("no chain id specified") - -// ErrNotAuthorized is returned when an account is not properly unlocked. -var ErrNotAuthorized = errors.New("not authorized to sign this account") - -// NewTransactor is a utility method to easily create a transaction signer from -// an encrypted json key stream and the associated passphrase. -// -// Deprecated: Use NewTransactorWithChainID instead. -func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { - log.Warn("WARNING: NewTransactor has been deprecated in favour of NewTransactorWithChainID") - json, err := io.ReadAll(keyin) - if err != nil { - return nil, err - } - key, err := keystore.DecryptKey(json, passphrase) - if err != nil { - return nil, err - } - return NewKeyedTransactor(key.PrivateKey), nil -} - -// NewKeyStoreTransactor is a utility method to easily create a transaction signer from -// a decrypted key from a keystore. -// -// Deprecated: Use NewKeyStoreTransactorWithChainID instead. -func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) { - log.Warn("WARNING: NewKeyStoreTransactor has been deprecated in favour of NewTransactorWithChainID") - signer := types.HomesteadSigner{} - return &TransactOpts{ - From: account.Address, - Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != account.Address { - return nil, ErrNotAuthorized - } - signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - Context: context.Background(), - }, nil -} - -// NewKeyedTransactor is a utility method to easily create a transaction signer -// from a single private key. -// -// Deprecated: Use NewKeyedTransactorWithChainID instead. -func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { - log.Warn("WARNING: NewKeyedTransactor has been deprecated in favour of NewKeyedTransactorWithChainID") - keyAddr := crypto.PubkeyToAddress(key.PublicKey) - signer := types.HomesteadSigner{} - return &TransactOpts{ - From: keyAddr, - Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != keyAddr { - return nil, ErrNotAuthorized - } - signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - Context: context.Background(), - } -} - -// NewTransactorWithChainID is a utility method to easily create a transaction signer from -// an encrypted json key stream and the associated passphrase. -func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.Int) (*TransactOpts, error) { - json, err := io.ReadAll(keyin) - if err != nil { - return nil, err - } - key, err := keystore.DecryptKey(json, passphrase) - if err != nil { - return nil, err - } - return NewKeyedTransactorWithChainID(key.PrivateKey, chainID) -} - -// NewKeyStoreTransactorWithChainID is a utility method to easily create a transaction signer from -// a decrypted key from a keystore. -func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accounts.Account, chainID *big.Int) (*TransactOpts, error) { - if chainID == nil { - return nil, ErrNoChainID - } - signer := types.LatestSignerForChainID(chainID) - return &TransactOpts{ - From: account.Address, - Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != account.Address { - return nil, ErrNotAuthorized - } - signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - Context: context.Background(), - }, nil -} - -// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer -// from a single private key. -func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) { - if chainID == nil { - return nil, ErrNoChainID - } - keyAddr := crypto.PubkeyToAddress(key.PublicKey) - signer := types.LatestSignerForChainID(chainID) - return &TransactOpts{ - From: keyAddr, - Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { - if address != keyAddr { - return nil, ErrNotAuthorized - } - signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) - if err != nil { - return nil, err - } - return tx.WithSignature(signer, signature) - }, - Context: context.Background(), - }, nil -} - -// NewClefTransactor is a utility method to easily create a transaction signer -// with a clef backend. -func NewClefTransactor(clef *external.ExternalSigner, account accounts.Account) *TransactOpts { - return &TransactOpts{ - From: account.Address, - Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { - if address != account.Address { - return nil, ErrNotAuthorized - } - return clef.SignTx(account, transaction, nil) // Clef enforces its own chain id - }, - Context: context.Background(), - } -} diff --git a/accounts/abi/bind/old.go b/accounts/abi/bind/old.go new file mode 100644 index 000000000..b09f5f3c7 --- /dev/null +++ b/accounts/abi/bind/old.go @@ -0,0 +1,294 @@ +// Copyright 2016 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 . + +// Package bind is the runtime for abigen v1 generated contract bindings. +// Deprecated: please use github.com/ethereum/go-ethereum/bind/v2 +package bind + +import ( + "context" + "crypto/ecdsa" + "errors" + "io" + "math/big" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/abigen" + bind2 "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/accounts/external" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" +) + +// Bind generates a v1 contract binding. +// Deprecated: binding generation has moved to github.com/ethereum/go-ethereum/accounts/abi/abigen +func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, libs map[string]string, aliases map[string]string) (string, error) { + return abigen.Bind(types, abis, bytecodes, fsigs, pkg, libs, aliases) +} + +// auth.go + +// ErrNoChainID is returned whenever the user failed to specify a chain id. +var ErrNoChainID = errors.New("no chain id specified") + +// ErrNotAuthorized is returned when an account is not properly unlocked. +var ErrNotAuthorized = bind2.ErrNotAuthorized + +// NewTransactor is a utility method to easily create a transaction signer from +// an encrypted json key stream and the associated passphrase. +// +// Deprecated: Use NewTransactorWithChainID instead. +func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { + log.Warn("WARNING: NewTransactor has been deprecated in favour of NewTransactorWithChainID") + json, err := io.ReadAll(keyin) + if err != nil { + return nil, err + } + key, err := keystore.DecryptKey(json, passphrase) + if err != nil { + return nil, err + } + return NewKeyedTransactor(key.PrivateKey), nil +} + +// NewKeyStoreTransactor is a utility method to easily create a transaction signer from +// a decrypted key from a keystore. +// +// Deprecated: Use NewKeyStoreTransactorWithChainID instead. +func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) { + log.Warn("WARNING: NewKeyStoreTransactor has been deprecated in favour of NewTransactorWithChainID") + signer := types.HomesteadSigner{} + return &TransactOpts{ + From: account.Address, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != account.Address { + return nil, ErrNotAuthorized + } + signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) + if err != nil { + return nil, err + } + return tx.WithSignature(signer, signature) + }, + Context: context.Background(), + }, nil +} + +// NewKeyedTransactor is a utility method to easily create a transaction signer +// from a single private key. +// +// Deprecated: Use NewKeyedTransactorWithChainID instead. +func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { + log.Warn("WARNING: NewKeyedTransactor has been deprecated in favour of NewKeyedTransactorWithChainID") + keyAddr := crypto.PubkeyToAddress(key.PublicKey) + signer := types.HomesteadSigner{} + return &TransactOpts{ + From: keyAddr, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != keyAddr { + return nil, ErrNotAuthorized + } + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) + if err != nil { + return nil, err + } + return tx.WithSignature(signer, signature) + }, + Context: context.Background(), + } +} + +// NewTransactorWithChainID is a utility method to easily create a transaction signer from +// an encrypted json key stream and the associated passphrase. +func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.Int) (*TransactOpts, error) { + json, err := io.ReadAll(keyin) + if err != nil { + return nil, err + } + key, err := keystore.DecryptKey(json, passphrase) + if err != nil { + return nil, err + } + return NewKeyedTransactorWithChainID(key.PrivateKey, chainID) +} + +// NewKeyStoreTransactorWithChainID is a utility method to easily create a transaction signer from +// a decrypted key from a keystore. +func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accounts.Account, chainID *big.Int) (*TransactOpts, error) { + // New version panics for chainID == nil, catch it here. + if chainID == nil { + return nil, ErrNoChainID + } + return bind2.NewKeyStoreTransactor(keystore, account, chainID), nil +} + +// NewKeyedTransactorWithChainID is a utility method to easily create a transaction signer +// from a single private key. +func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*TransactOpts, error) { + // New version panics for chainID == nil, catch it here. + if chainID == nil { + return nil, ErrNoChainID + } + return bind2.NewKeyedTransactor(key, chainID), nil +} + +// NewClefTransactor is a utility method to easily create a transaction signer +// with a clef backend. +func NewClefTransactor(clef *external.ExternalSigner, account accounts.Account) *TransactOpts { + return bind2.NewClefTransactor(clef, account) +} + +// backend.go + +var ( + // ErrNoCode is returned by call and transact operations for which the requested + // recipient contract to operate on does not exist in the state db or does not + // have any code associated with it (i.e. self-destructed). + ErrNoCode = bind2.ErrNoCode + + // ErrNoPendingState is raised when attempting to perform a pending state action + // on a backend that doesn't implement PendingContractCaller. + ErrNoPendingState = bind2.ErrNoPendingState + + // ErrNoBlockHashState is raised when attempting to perform a block hash action + // on a backend that doesn't implement BlockHashContractCaller. + ErrNoBlockHashState = bind2.ErrNoBlockHashState + + // ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves + // an empty contract behind. + ErrNoCodeAfterDeploy = bind2.ErrNoCodeAfterDeploy +) + +// ContractCaller defines the methods needed to allow operating with a contract on a read +// only basis. +type ContractCaller = bind2.ContractCaller + +// PendingContractCaller defines methods to perform contract calls on the pending state. +// Call will try to discover this interface when access to the pending state is requested. +// If the backend does not support the pending state, Call returns ErrNoPendingState. +type PendingContractCaller = bind2.PendingContractCaller + +// BlockHashContractCaller defines methods to perform contract calls on a specific block hash. +// Call will try to discover this interface when access to a block by hash is requested. +// If the backend does not support the block hash state, Call returns ErrNoBlockHashState. +type BlockHashContractCaller = bind2.BlockHashContractCaller + +// ContractTransactor defines the methods needed to allow operating with a contract +// on a write only basis. Besides the transacting method, the remainder are helpers +// used when the user does not provide some needed values, but rather leaves it up +// to the transactor to decide. +type ContractTransactor = bind2.ContractTransactor + +// DeployBackend wraps the operations needed by WaitMined and WaitDeployed. +type DeployBackend = bind2.DeployBackend + +// ContractFilterer defines the methods needed to access log events using one-off +// queries or continuous event subscriptions. +type ContractFilterer = bind2.ContractFilterer + +// ContractBackend defines the methods needed to work with contracts on a read-write basis. +type ContractBackend = bind2.ContractBackend + +// base.go + +type SignerFn = bind2.SignerFn + +type CallOpts = bind2.CallOpts + +type TransactOpts = bind2.TransactOpts + +type FilterOpts = bind2.FilterOpts + +type WatchOpts = bind2.WatchOpts + +type BoundContract = bind2.BoundContract + +func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract { + return bind2.NewBoundContract(address, abi, caller, transactor, filterer) +} + +func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { + packed, err := abi.Pack("", params...) + if err != nil { + return common.Address{}, nil, nil, err + } + addr, tx, err := bind2.DeployContract(opts, bytecode, backend, packed) + if err != nil { + return common.Address{}, nil, nil, err + } + contract := NewBoundContract(addr, abi, backend, backend, backend) + return addr, tx, contract, nil +} + +// MetaData collects all metadata for a bound contract. +type MetaData struct { + Bin string // runtime bytecode (as a hex string) + ABI string // the raw ABI definition (JSON) + Sigs map[string]string // 4byte identifier -> function signature + mu sync.Mutex + parsedABI *abi.ABI +} + +// GetAbi returns the parsed ABI definition. +func (m *MetaData) GetAbi() (*abi.ABI, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.parsedABI != nil { + return m.parsedABI, nil + } + if parsed, err := abi.JSON(strings.NewReader(m.ABI)); err != nil { + return nil, err + } else { + m.parsedABI = &parsed + } + return m.parsedABI, nil +} + +// util.go + +// WaitMined waits for tx to be mined on the blockchain. +// It stops waiting when the context is canceled. +func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) { + return bind2.WaitMined(ctx, b, tx.Hash()) +} + +// WaitMinedHash waits for a transaction with the provided hash to be mined on the blockchain. +// It stops waiting when the context is canceled. +func WaitMinedHash(ctx context.Context, b DeployBackend, hash common.Hash) (*types.Receipt, error) { + return bind2.WaitMined(ctx, b, hash) +} + +// WaitDeployed waits for a contract deployment transaction and returns the on-chain +// contract address when it is mined. It stops waiting when ctx is canceled. +func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) (common.Address, error) { + if tx.To() != nil { + return common.Address{}, errors.New("tx is not contract creation") + } + return bind2.WaitDeployed(ctx, b, tx.Hash()) +} + +// WaitDeployedHash waits for a contract deployment transaction with the provided hash and returns the on-chain +// contract address when it is mined. It stops waiting when ctx is canceled. +func WaitDeployedHash(ctx context.Context, b DeployBackend, hash common.Hash) (common.Address, error) { + return bind2.WaitDeployed(ctx, b, hash) +} diff --git a/accounts/abi/bind/v2/auth.go b/accounts/abi/bind/v2/auth.go new file mode 100644 index 000000000..0a452a2c7 --- /dev/null +++ b/accounts/abi/bind/v2/auth.go @@ -0,0 +1,96 @@ +// Copyright 2016 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 . + +package bind + +import ( + "context" + "crypto/ecdsa" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/external" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +// ErrNotAuthorized is returned when an account is not properly unlocked. +var ErrNotAuthorized = errors.New("not authorized to sign this account") + +// NewKeyStoreTransactor is a utility method to easily create a transaction signer from +// a decrypted key from a keystore. +func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account, chainID *big.Int) *TransactOpts { + if chainID == nil { + panic("nil chainID") + } + signer := types.LatestSignerForChainID(chainID) + return &TransactOpts{ + From: account.Address, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != account.Address { + return nil, ErrNotAuthorized + } + signature, err := keystore.SignHash(account, signer.Hash(tx).Bytes()) + if err != nil { + return nil, err + } + return tx.WithSignature(signer, signature) + }, + Context: context.Background(), + } +} + +// NewKeyedTransactor is a utility method to easily create a transaction signer +// from a single private key. +func NewKeyedTransactor(key *ecdsa.PrivateKey, chainID *big.Int) *TransactOpts { + if chainID == nil { + panic("nil chainID") + } + keyAddr := crypto.PubkeyToAddress(key.PublicKey) + signer := types.LatestSignerForChainID(chainID) + return &TransactOpts{ + From: keyAddr, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + if address != keyAddr { + return nil, ErrNotAuthorized + } + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) + if err != nil { + return nil, err + } + return tx.WithSignature(signer, signature) + }, + Context: context.Background(), + } +} + +// NewClefTransactor is a utility method to easily create a transaction signer +// with a clef backend. +func NewClefTransactor(clef *external.ExternalSigner, account accounts.Account) *TransactOpts { + return &TransactOpts{ + From: account.Address, + Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { + if address != account.Address { + return nil, ErrNotAuthorized + } + return clef.SignTx(account, transaction, nil) // Clef enforces its own chain id + }, + Context: context.Background(), + } +} diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/v2/backend.go similarity index 90% rename from accounts/abi/bind/backend.go rename to accounts/abi/bind/v2/backend.go index 38b304697..2f5f17b31 100644 --- a/accounts/abi/bind/backend.go +++ b/accounts/abi/bind/v2/backend.go @@ -43,6 +43,11 @@ var ( // ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves // an empty contract behind. ErrNoCodeAfterDeploy = errors.New("no contract code after deployment") + + // ErrNoAddressInReceipt is returned by WaitDeployed when the receipt for the + // transaction hash does not contain a contract address. This error may indicate + // that the transaction hash was not a CREATE transaction. + ErrNoAddressInReceipt = errors.New("no contract address in receipt") ) // ContractCaller defines the methods needed to allow operating with a contract on a read @@ -118,3 +123,11 @@ type ContractBackend interface { ContractTransactor ContractFilterer } + +// Backend combines all backend methods used in this package. This type is provided for +// convenience. It is meant to be used when you need to hold a reference to a backend that +// is used for both deployment and contract interaction. +type Backend interface { + DeployBackend + ContractBackend +} diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/v2/base.go similarity index 85% rename from accounts/abi/bind/base.go rename to accounts/abi/bind/v2/base.go index 0504089c7..a9b667e69 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/v2/base.go @@ -25,10 +25,10 @@ import ( "sync" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" ) @@ -89,25 +89,42 @@ type WatchOpts struct { // MetaData collects all metadata for a bound contract. type MetaData struct { - mu sync.Mutex - Sigs map[string]string - Bin string - ABI string - ab *abi.ABI + Bin string // deployer bytecode (as a hex string) + ABI string // the raw ABI definition (JSON) + Deps []*MetaData // library dependencies of the contract + + // For bindings that were compiled from combined-json ID is the Solidity + // library pattern: a 34 character prefix of the hex encoding of the keccak256 + // hash of the fully qualified 'library name', i.e. the path of the source file. + // + // For contracts compiled from the ABI definition alone, this is the type name + // of the contract (as specified in the ABI definition or overridden via the + // --type flag). + // + // This is a unique identifier of a contract within a compilation unit. When + // used as part of a multi-contract deployment with library dependencies, the + // ID is used to link contracts during deployment using [LinkAndDeploy]. + ID string + + mu sync.Mutex + parsedABI *abi.ABI } -func (m *MetaData) GetAbi() (*abi.ABI, error) { +// ParseABI returns the parsed ABI specification, or an error if the string +// representation of the ABI set in the MetaData instance could not be parsed. +func (m *MetaData) ParseABI() (*abi.ABI, error) { m.mu.Lock() defer m.mu.Unlock() - if m.ab != nil { - return m.ab, nil + + if m.parsedABI != nil { + return m.parsedABI, nil } if parsed, err := abi.JSON(strings.NewReader(m.ABI)); err != nil { return nil, err } else { - m.ab = &parsed + m.parsedABI = &parsed } - return m.ab, nil + return m.parsedABI, nil } // BoundContract is the base wrapper object that reflects a contract on the @@ -133,125 +150,125 @@ func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller } } -// DeployContract deploys a contract onto the Ethereum blockchain and binds the -// deployment address with a Go wrapper. -func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { - // Otherwise try to deploy the contract - c := NewBoundContract(common.Address{}, abi, backend, backend, backend) - - input, err := c.abi.Pack("", params...) - if err != nil { - return common.Address{}, nil, nil, err - } - tx, err := c.transact(opts, nil, append(bytecode, input...)) - if err != nil { - return common.Address{}, nil, nil, err - } - c.address = crypto.CreateAddress(opts.From, tx.Nonce()) - return c.address, tx, c, nil -} - // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (c *BoundContract) Call(opts *CallOpts, results *[]interface{}, method string, params ...interface{}) error { - // Don't crash on a lazy user - if opts == nil { - opts = new(CallOpts) - } +func (c *BoundContract) Call(opts *CallOpts, results *[]any, method string, params ...any) error { if results == nil { - results = new([]interface{}) + results = new([]any) } // Pack the input, call and unpack the results input, err := c.abi.Pack(method, params...) if err != nil { return err } + + output, err := c.call(opts, input) + if err != nil { + return err + } + + if len(*results) == 0 { + res, err := c.abi.Unpack(method, output) + *results = res + return err + } + res := *results + return c.abi.UnpackIntoInterface(res[0], method, output) +} + +// CallRaw executes an eth_call against the contract with the raw calldata as +// input. It returns the call's return data or an error. +func (c *BoundContract) CallRaw(opts *CallOpts, input []byte) ([]byte, error) { + return c.call(opts, input) +} + +func (c *BoundContract) call(opts *CallOpts, input []byte) ([]byte, error) { + // Don't crash on a lazy user + if opts == nil { + opts = new(CallOpts) + } var ( msg = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input} ctx = ensureContext(opts.Context) code []byte output []byte + err error ) if opts.Pending { pb, ok := c.caller.(PendingContractCaller) if !ok { - return ErrNoPendingState + return nil, ErrNoPendingState } output, err = pb.PendingCallContract(ctx, msg) if err != nil { - return err + return nil, err } if len(output) == 0 { // Make sure we have a contract to operate on, and bail out otherwise. if code, err = pb.PendingCodeAt(ctx, c.address); err != nil { - return err + return nil, err } else if len(code) == 0 { - return ErrNoCode + return nil, ErrNoCode } } } else if opts.BlockHash != (common.Hash{}) { bh, ok := c.caller.(BlockHashContractCaller) if !ok { - return ErrNoBlockHashState + return nil, ErrNoBlockHashState } output, err = bh.CallContractAtHash(ctx, msg, opts.BlockHash) if err != nil { - return err + return nil, err } if len(output) == 0 { // Make sure we have a contract to operate on, and bail out otherwise. if code, err = bh.CodeAtHash(ctx, c.address, opts.BlockHash); err != nil { - return err + return nil, err } else if len(code) == 0 { - return ErrNoCode + return nil, ErrNoCode } } } else { output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber) if err != nil { - return err + return nil, err } if len(output) == 0 { // Make sure we have a contract to operate on, and bail out otherwise. if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil { - return err + return nil, err } else if len(code) == 0 { - return ErrNoCode + return nil, ErrNoCode } } } - - if len(*results) == 0 { - res, err := c.abi.Unpack(method, output) - *results = res - return err - } - res := *results - return c.abi.UnpackIntoInterface(res[0], method, output) + return output, nil } // Transact invokes the (paid) contract method with params as input values. -func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { +func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...any) (*types.Transaction, error) { // Otherwise pack up the parameters and invoke the contract input, err := c.abi.Pack(method, params...) if err != nil { return nil, err } - // todo(rjl493456442) check whether the method is payable or not, - // reject invalid transaction at the first place return c.transact(opts, &c.address, input) } // RawTransact initiates a transaction with the given raw calldata as the input. // It's usually used to initiate transactions for invoking **Fallback** function. func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) { - // todo(rjl493456442) check whether the method is payable or not, - // reject invalid transaction at the first place return c.transact(opts, &c.address, calldata) } +// RawCreationTransact creates and submits a contract-creation transaction with +// the given calldata as the input. +func (c *BoundContract) RawCreationTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) { + return c.transact(opts, nil, calldata) +} + // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { @@ -433,14 +450,13 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i // FilterLogs filters contract logs for past blocks, returning the necessary // channels to construct a strongly typed bound iterator on top of them. -func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { +func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error) { // Don't crash on a lazy user if opts == nil { opts = new(FilterOpts) } // Append the event selector to the query parameters and construct the topic set - query = append([][]interface{}{{c.abi.Events[name].ID}}, query...) - + query = append([][]any{{c.abi.Events[name].ID}}, query...) topics, err := abi.MakeTopics(query...) if err != nil { return nil, nil, err @@ -479,13 +495,13 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int // WatchLogs filters subscribes to contract logs for future blocks, returning a // subscription object that can be used to tear down the watcher. -func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { +func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]any) (chan types.Log, event.Subscription, error) { // Don't crash on a lazy user if opts == nil { opts = new(WatchOpts) } // Append the event selector to the query parameters and construct the topic set - query = append([][]interface{}{{c.abi.Events[name].ID}}, query...) + query = append([][]any{{c.abi.Events[name].ID}}, query...) topics, err := abi.MakeTopics(query...) if err != nil { @@ -509,7 +525,7 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter } // UnpackLog unpacks a retrieved log into the provided output structure. -func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { +func (c *BoundContract) UnpackLog(out any, event string, log types.Log) error { // Anonymous events are not supported. if len(log.Topics) == 0 { return errNoEventSignature @@ -532,7 +548,7 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) } // UnpackLogIntoMap unpacks a retrieved log into the provided map. -func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { +func (c *BoundContract) UnpackLogIntoMap(out map[string]any, event string, log types.Log) error { // Anonymous events are not supported. if len(log.Topics) == 0 { return errNoEventSignature diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/v2/base_test.go similarity index 99% rename from accounts/abi/bind/base_test.go rename to accounts/abi/bind/v2/base_test.go index f7eb7d14d..80d0f22f2 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/v2/base_test.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" diff --git a/accounts/abi/bind/v2/dep_tree.go b/accounts/abi/bind/v2/dep_tree.go new file mode 100644 index 000000000..72a646895 --- /dev/null +++ b/accounts/abi/bind/v2/dep_tree.go @@ -0,0 +1,167 @@ +// Copyright 2025 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 . + +package bind + +import ( + "encoding/hex" + "fmt" + "maps" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// DeploymentParams contains parameters needed to deploy one or more contracts via LinkAndDeploy +type DeploymentParams struct { + // list of all contracts targeted for the deployment + Contracts []*MetaData + + // optional map of ABI-encoded constructor inputs keyed by the MetaData.ID. + Inputs map[string][]byte + + // optional map of override addresses for specifying already-deployed + // contracts. It is keyed by the MetaData.ID. + Overrides map[string]common.Address +} + +// validate determines whether the contracts specified in the DeploymentParams +// instance have embedded deployer code in their provided MetaData instances. +func (d *DeploymentParams) validate() error { + for _, meta := range d.Contracts { + if meta.Bin == "" { + return fmt.Errorf("cannot deploy contract %s: deployer code missing from metadata", meta.ID) + } + } + return nil +} + +// DeploymentResult contains information about the result of a pending +// deployment made by LinkAndDeploy. +type DeploymentResult struct { + // Map of contract MetaData.ID to pending deployment transaction + Txs map[string]*types.Transaction + + // Map of contract MetaData.ID to the address where it will be deployed + Addresses map[string]common.Address +} + +// DeployFn deploys a contract given a deployer and optional input. It returns +// the address and a pending transaction, or an error if the deployment failed. +type DeployFn func(input, deployer []byte) (common.Address, *types.Transaction, error) + +// depTreeDeployer is responsible for taking a dependency, deploying-and-linking +// its components in the proper order. A depTreeDeployer cannot be used after +// calling LinkAndDeploy other than to retrieve the deployment result. +type depTreeDeployer struct { + deployedAddrs map[string]common.Address + deployerTxs map[string]*types.Transaction + inputs map[string][]byte // map of the root contract pattern to the constructor input (if there is any) + deployFn DeployFn +} + +func newDepTreeDeployer(deployParams *DeploymentParams, deployFn DeployFn) *depTreeDeployer { + deployedAddrs := maps.Clone(deployParams.Overrides) + if deployedAddrs == nil { + deployedAddrs = make(map[string]common.Address) + } + inputs := deployParams.Inputs + if inputs == nil { + inputs = make(map[string][]byte) + } + return &depTreeDeployer{ + deployFn: deployFn, + deployedAddrs: deployedAddrs, + deployerTxs: make(map[string]*types.Transaction), + inputs: inputs, + } +} + +// linkAndDeploy deploys a contract and it's dependencies. Because libraries +// can in-turn have their own library dependencies, linkAndDeploy performs +// deployment recursively (deepest-dependency first). The address of the +// pending contract deployment for the top-level contract is returned. +func (d *depTreeDeployer) linkAndDeploy(metadata *MetaData) (common.Address, error) { + // Don't re-deploy aliased or previously-deployed contracts + if addr, ok := d.deployedAddrs[metadata.ID]; ok { + return addr, nil + } + // If this contract/library depends on other libraries deploy them + // (and their dependencies) first + deployerCode := metadata.Bin + for _, dep := range metadata.Deps { + addr, err := d.linkAndDeploy(dep) + if err != nil { + return common.Address{}, err + } + // Link their deployed addresses into the bytecode to produce + deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.ID+"$__", strings.ToLower(addr.String()[2:])) + } + // Finally, deploy the top-level contract. + code, err := hex.DecodeString(deployerCode[2:]) + if err != nil { + panic(fmt.Sprintf("error decoding contract deployer hex %s:\n%v", deployerCode[2:], err)) + } + addr, tx, err := d.deployFn(d.inputs[metadata.ID], code) + if err != nil { + return common.Address{}, err + } + d.deployedAddrs[metadata.ID] = addr + d.deployerTxs[metadata.ID] = tx + return addr, nil +} + +// result returns a DeploymentResult instance referencing contracts deployed +// and not including any overrides specified for this deployment. +func (d *depTreeDeployer) result() *DeploymentResult { + // filter the override addresses from the deployed address set. + for pattern := range d.deployedAddrs { + if _, ok := d.deployerTxs[pattern]; !ok { + delete(d.deployedAddrs, pattern) + } + } + return &DeploymentResult{ + Txs: d.deployerTxs, + Addresses: d.deployedAddrs, + } +} + +// LinkAndDeploy performs the contract deployment specified by params using the +// provided DeployFn to create, sign and submit transactions. +// +// Contracts can depend on libraries, which in-turn can have their own library +// dependencies. Therefore, LinkAndDeploy performs the deployment recursively, +// starting with libraries (and contracts) that don't have dependencies, and +// progressing through the contracts that depend upon them. +// +// If an error is encountered, the returned DeploymentResult only contains +// entries for the contracts whose deployment submission succeeded. +// +// LinkAndDeploy performs creation and submission of creation transactions, +// but does not ensure that the contracts are included in the chain. +func LinkAndDeploy(params *DeploymentParams, deploy DeployFn) (*DeploymentResult, error) { + if err := params.validate(); err != nil { + return nil, err + } + deployer := newDepTreeDeployer(params, deploy) + for _, contract := range params.Contracts { + if _, err := deployer.linkAndDeploy(contract); err != nil { + return deployer.result(), err + } + } + return deployer.result(), nil +} diff --git a/accounts/abi/bind/v2/dep_tree_test.go b/accounts/abi/bind/v2/dep_tree_test.go new file mode 100644 index 000000000..e686e3fec --- /dev/null +++ b/accounts/abi/bind/v2/dep_tree_test.go @@ -0,0 +1,370 @@ +// Copyright 2024 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 . + +package bind + +import ( + "fmt" + "regexp" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "golang.org/x/exp/rand" +) + +type linkTestCase struct { + // map of pattern to unlinked bytecode (for the purposes of tests just contains the patterns of its dependencies) + libCodes map[string]string + contractCodes map[string]string + + overrides map[string]common.Address +} + +func copyMetaData(m *MetaData) *MetaData { + m.mu.Lock() + defer m.mu.Unlock() + + var deps []*MetaData + if len(m.Deps) > 0 { + for _, dep := range m.Deps { + deps = append(deps, copyMetaData(dep)) + } + } + return &MetaData{ + Bin: m.Bin, + ABI: m.ABI, + Deps: deps, + ID: m.ID, + parsedABI: m.parsedABI, + } +} + +func makeLinkTestCase(input map[rune][]rune, overrides map[rune]common.Address) *linkTestCase { + codes := make(map[string]string) + libCodes := make(map[string]string) + contractCodes := make(map[string]string) + + inputMap := make(map[rune]map[rune]struct{}) + // set of solidity patterns for all contracts that are known to be libraries + libs := make(map[string]struct{}) + + // map of test contract id (rune) to the solidity library pattern (hash of that rune) + patternMap := map[rune]string{} + + for contract, deps := range input { + inputMap[contract] = make(map[rune]struct{}) + if _, ok := patternMap[contract]; !ok { + patternMap[contract] = crypto.Keccak256Hash([]byte(string(contract))).String()[2:36] + } + + for _, dep := range deps { + if _, ok := patternMap[dep]; !ok { + patternMap[dep] = crypto.Keccak256Hash([]byte(string(dep))).String()[2:36] + } + codes[patternMap[contract]] = codes[patternMap[contract]] + fmt.Sprintf("__$%s$__", patternMap[dep]) + inputMap[contract][dep] = struct{}{} + libs[patternMap[dep]] = struct{}{} + } + } + overridesPatterns := make(map[string]common.Address) + for contractId, overrideAddr := range overrides { + pattern := crypto.Keccak256Hash([]byte(string(contractId))).String()[2:36] + overridesPatterns[pattern] = overrideAddr + } + + for _, pattern := range patternMap { + if _, ok := libs[pattern]; ok { + // if the library didn't depend on others, give it some dummy code to not bork deployment logic down-the-line + if len(codes[pattern]) == 0 { + libCodes[pattern] = "ff" + } else { + libCodes[pattern] = codes[pattern] + } + } else { + contractCodes[pattern] = codes[pattern] + } + } + + return &linkTestCase{ + libCodes, + contractCodes, + overridesPatterns, + } +} + +var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + +type linkTestCaseInput struct { + input map[rune][]rune + overrides map[rune]struct{} + expectDeployed map[rune]struct{} +} + +// linkDeps will return a set of root dependencies and their sub-dependencies connected via the Deps field +func linkDeps(deps map[string]*MetaData) []*MetaData { + roots := make(map[string]struct{}) + for pattern := range deps { + roots[pattern] = struct{}{} + } + + connectedDeps := make(map[string]*MetaData) + for pattern, dep := range deps { + connectedDeps[pattern] = internalLinkDeps(dep, deps, &roots) + } + + var rootMetadatas []*MetaData + for pattern := range roots { + dep := connectedDeps[pattern] + rootMetadatas = append(rootMetadatas, dep) + } + return rootMetadatas +} + +// internalLinkDeps is the internal recursing logic of linkDeps: +// It links the contract referred to by MetaData given the depMap (map of solidity +// link pattern to contract metadata object), deleting contract entries from the +// roots map if they were referenced as dependencies. It returns a new MetaData +// object which is the linked version of metadata parameter. +func internalLinkDeps(metadata *MetaData, depMap map[string]*MetaData, roots *map[string]struct{}) *MetaData { + linked := copyMetaData(metadata) + depPatterns := parseLibraryDeps(metadata.Bin) + for _, pattern := range depPatterns { + delete(*roots, pattern) + connectedDep := internalLinkDeps(depMap[pattern], depMap, roots) + linked.Deps = append(linked.Deps, connectedDep) + } + return linked +} + +func testLinkCase(tcInput linkTestCaseInput) error { + var ( + testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + overridesAddrs = make(map[common.Address]struct{}) + overrideAddrs = make(map[rune]common.Address) + ) + // generate deterministic addresses for the override set. + rand.Seed(42) + for contract := range tcInput.overrides { + var addr common.Address + rand.Read(addr[:]) + overrideAddrs[contract] = addr + overridesAddrs[addr] = struct{}{} + } + + tc := makeLinkTestCase(tcInput.input, overrideAddrs) + allContracts := make(map[rune]struct{}) + + for contract, deps := range tcInput.input { + allContracts[contract] = struct{}{} + for _, dep := range deps { + allContracts[dep] = struct{}{} + } + } + + var testAddrNonce uint64 + mockDeploy := func(input []byte, deployer []byte) (common.Address, *types.Transaction, error) { + contractAddr := crypto.CreateAddress(testAddr, testAddrNonce) + testAddrNonce++ + + if len(deployer) >= 20 { + // assert that this contract only references libs that are known to be deployed or in the override set + for i := 0; i < len(deployer); i += 20 { + var dep common.Address + dep.SetBytes(deployer[i : i+20]) + if _, ok := overridesAddrs[dep]; !ok { + return common.Address{}, nil, fmt.Errorf("reference to dependent contract that has not yet been deployed: %x\n", dep) + } + } + } + overridesAddrs[contractAddr] = struct{}{} + // we don't care about the txs themselves for the sake of the linking tests. so we can return nil for them in the mock deployer + return contractAddr, nil, nil + } + + contracts := make(map[string]*MetaData) + overrides := make(map[string]common.Address) + + for pattern, bin := range tc.contractCodes { + contracts[pattern] = &MetaData{ID: pattern, Bin: "0x" + bin} + } + for pattern, bin := range tc.libCodes { + contracts[pattern] = &MetaData{ + Bin: "0x" + bin, + ID: pattern, + } + } + + contractsList := linkDeps(contracts) + + for pattern, override := range tc.overrides { + overrides[pattern] = override + } + + deployParams := &DeploymentParams{ + Contracts: contractsList, + Overrides: overrides, + } + res, err := LinkAndDeploy(deployParams, mockDeploy) + if err != nil { + return err + } + + if len(res.Txs) != len(tcInput.expectDeployed) { + return fmt.Errorf("got %d deployed contracts. expected %d.\n", len(res.Addresses), len(tcInput.expectDeployed)) + } + for contract := range tcInput.expectDeployed { + pattern := crypto.Keccak256Hash([]byte(string(contract))).String()[2:36] + if _, ok := res.Addresses[pattern]; !ok { + return fmt.Errorf("expected contract %s was not deployed\n", string(contract)) + } + } + return nil +} + +func TestContractLinking(t *testing.T) { + for i, tc := range []linkTestCaseInput{ + // test simple contract without any dependencies or overrides + { + map[rune][]rune{ + 'a': {}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}}, + }, + // test deployment of a contract that depends on somes libraries. + { + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}}, + }, + // test deployment of a contract that depends on some libraries, + // one of which has its own library dependencies. + { + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'e': {'f', 'g', 'h', 'i'}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}}, + }, + // test single contract only without deps + { + map[rune][]rune{ + 'a': {}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, + }, + }, + // test that libraries at different levels of the tree can share deps, + // and that these shared deps will only be deployed once. + { + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'e': {'f', 'g', 'h', 'i', 'm'}, + 'i': {'j', 'k', 'l', 'm'}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}, 'j': {}, 'k': {}, 'l': {}, 'm': {}, + }, + }, + // test two contracts can be deployed which don't share deps + linkTestCaseInput{ + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'f': {'g', 'h', 'i', 'j'}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'i': {}, 'j': {}, + }, + }, + // test two contracts can be deployed which share deps + linkTestCaseInput{ + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'f': {'g', 'c', 'd', 'h'}}, + map[rune]struct{}{}, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, + }, + }, + // test one contract with overrides for all lib deps + linkTestCaseInput{ + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}}, + map[rune]struct{}{'b': {}, 'c': {}, 'd': {}, 'e': {}}, + map[rune]struct{}{ + 'a': {}}, + }, + // test one contract with overrides for some lib deps + linkTestCaseInput{ + map[rune][]rune{ + 'a': {'b', 'c'}}, + map[rune]struct{}{'b': {}, 'c': {}}, + map[rune]struct{}{ + 'a': {}}, + }, + // test deployment of a contract with overrides + linkTestCaseInput{ + map[rune][]rune{ + 'a': {}}, + map[rune]struct{}{'a': {}}, + map[rune]struct{}{}, + }, + // two contracts ('a' and 'f') share some dependencies. contract 'a' is marked as an override. expect that any of + // its depdencies that aren't shared with 'f' are not deployed. + linkTestCaseInput{map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'f': {'g', 'c', 'd', 'h'}}, + map[rune]struct{}{'a': {}}, + map[rune]struct{}{ + 'f': {}, 'g': {}, 'c': {}, 'd': {}, 'h': {}}, + }, + // test nested libraries that share deps at different levels of the tree... with override. + // same condition as above test: no sub-dependencies of + { + map[rune][]rune{ + 'a': {'b', 'c', 'd', 'e'}, + 'e': {'f', 'g', 'h', 'i', 'm'}, + 'i': {'j', 'k', 'l', 'm'}, + 'l': {'n', 'o', 'p'}}, + map[rune]struct{}{ + 'i': {}, + }, + map[rune]struct{}{ + 'a': {}, 'b': {}, 'c': {}, 'd': {}, 'e': {}, 'f': {}, 'g': {}, 'h': {}, 'm': {}}, + }, + } { + if err := testLinkCase(tc); err != nil { + t.Fatalf("test case %d failed: %v", i, err) + } + } +} + +func parseLibraryDeps(unlinkedCode string) (res []string) { + reMatchSpecificPattern, err := regexp.Compile(`__\$([a-f0-9]+)\$__`) + if err != nil { + panic(err) + } + for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(unlinkedCode, -1) { + res = append(res, match[1]) + } + return res +} diff --git a/accounts/abi/bind/v2/generate_test.go b/accounts/abi/bind/v2/generate_test.go new file mode 100644 index 000000000..ae35e0b47 --- /dev/null +++ b/accounts/abi/bind/v2/generate_test.go @@ -0,0 +1,102 @@ +// Copyright 2024 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 . + +package bind_test + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/abigen" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common/compiler" + "github.com/ethereum/go-ethereum/crypto" +) + +// Run go generate to recreate the test bindings. +// +//go:generate go run github.com/ethereum/go-ethereum/cmd/abigen -v2 -combined-json internal/contracts/db/combined-abi.json -type DBStats -pkg db -out internal/contracts/db/bindings.go +//go:generate go run github.com/ethereum/go-ethereum/cmd/abigen -v2 -combined-json internal/contracts/events/combined-abi.json -type C -pkg events -out internal/contracts/events/bindings.go +//go:generate go run github.com/ethereum/go-ethereum/cmd/abigen -v2 -combined-json internal/contracts/nested_libraries/combined-abi.json -type C1 -pkg nested_libraries -out internal/contracts/nested_libraries/bindings.go +//go:generate go run github.com/ethereum/go-ethereum/cmd/abigen -v2 -combined-json internal/contracts/solc_errors/combined-abi.json -type C -pkg solc_errors -out internal/contracts/solc_errors/bindings.go +//go:generate go run github.com/ethereum/go-ethereum/cmd/abigen -v2 -combined-json internal/contracts/uint256arrayreturn/combined-abi.json -type C -pkg uint256arrayreturn -out internal/contracts/uint256arrayreturn/bindings.go + +// TestBindingGeneration tests that re-running generation of bindings does not result in +// mutations to the binding code. +func TestBindingGeneration(t *testing.T) { + matches, _ := filepath.Glob("internal/contracts/*") + var dirs []string + for _, match := range matches { + f, _ := os.Stat(match) + if f.IsDir() { + dirs = append(dirs, f.Name()) + } + } + + for _, dir := range dirs { + var ( + abis []string + bins []string + types []string + libs = make(map[string]string) + ) + basePath := filepath.Join("internal/contracts", dir) + combinedJsonPath := filepath.Join(basePath, "combined-abi.json") + abiBytes, err := os.ReadFile(combinedJsonPath) + if err != nil { + t.Fatalf("error trying to read file %s: %v", combinedJsonPath, err) + } + contracts, err := compiler.ParseCombinedJSON(abiBytes, "", "", "", "") + if err != nil { + t.Fatalf("Failed to read contract information from json output: %v", err) + } + + for name, contract := range contracts { + // fully qualified name is of the form : + nameParts := strings.Split(name, ":") + typeName := nameParts[len(nameParts)-1] + abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse + if err != nil { + utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) + } + abis = append(abis, string(abi)) + bins = append(bins, contract.Code) + types = append(types, typeName) + + // Derive the library placeholder which is a 34 character prefix of the + // hex encoding of the keccak256 hash of the fully qualified library name. + // Note that the fully qualified library name is the path of its source + // file and the library name separated by ":". + libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x + libs[libPattern] = typeName + } + code, err := abigen.BindV2(types, abis, bins, dir, libs, make(map[string]string)) + if err != nil { + t.Fatalf("error creating bindings for package %s: %v", dir, err) + } + + existingBindings, err := os.ReadFile(filepath.Join(basePath, "bindings.go")) + if err != nil { + t.Fatalf("ReadFile returned error: %v", err) + } + if code != string(existingBindings) { + t.Fatalf("code mismatch for %s", dir) + } + } +} diff --git a/accounts/abi/bind/v2/internal/contracts/db/bindings.go b/accounts/abi/bind/v2/internal/contracts/db/bindings.go new file mode 100644 index 000000000..6291160fe --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/db/bindings.go @@ -0,0 +1,293 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package db + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// DBStats is an auto generated low-level Go binding around an user-defined struct. +type DBStats struct { + Gets *big.Int + Inserts *big.Int + Mods *big.Int +} + +// DBMetaData contains all meta data concerning the DB contract. +var DBMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"key\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"Insert\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"key\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"KeyedInsert\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"k\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNamedStatParams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gets\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"inserts\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mods\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStatParams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStatsStruct\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gets\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"inserts\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"mods\",\"type\":\"uint256\"}],\"internalType\":\"structDB.Stats\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"k\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"v\",\"type\":\"uint256\"}],\"name\":\"insert\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + ID: "253cc2574e2f8b5e909644530e4934f6ac", + Bin: "0x60806040525f5f553480156011575f5ffd5b5060405180606001604052805f81526020015f81526020015f81525060035f820151815f015560208201518160010155604082015181600201559050506105f78061005b5f395ff3fe60806040526004361061004d575f3560e01c80631d834a1b146100cb5780636fcb9c70146101075780639507d39a14610133578063e369ba3b1461016f578063ee8161e01461019b5761006a565b3661006a57345f5f82825461006291906103eb565b925050819055005b348015610075575f5ffd5b505f36606082828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050915050805190602001f35b3480156100d6575f5ffd5b506100f160048036038101906100ec919061044c565b6101c5565b6040516100fe9190610499565b60405180910390f35b348015610112575f5ffd5b5061011b6102ef565b60405161012a939291906104b2565b60405180910390f35b34801561013e575f5ffd5b50610159600480360381019061015491906104e7565b61030e565b6040516101669190610499565b60405180910390f35b34801561017a575f5ffd5b50610183610341565b604051610192939291906104b2565b60405180910390f35b3480156101a6575f5ffd5b506101af610360565b6040516101bc9190610561565b60405180910390f35b5f5f82036101da5760028054905090506102e9565b5f60015f8581526020019081526020015f20540361023757600283908060018154018082558091505060019003905f5260205f20015f909190919091505560036001015f81548092919061022d9061057a565b9190505550610252565b60036002015f81548092919061024c9061057a565b91905055505b8160015f8581526020019081526020015f20819055507f8b39ff47dca36ab5b8b80845238af53aa579625ac7fb173dc09376adada4176983836002805490506040516102a0939291906104b2565b60405180910390a1827f40bed843c6c5f72002f9b469cf4c1ee9f7fb1eb48f091c1267970f98522ac02d836040516102d89190610499565b60405180910390a260028054905090505b92915050565b5f5f5f60035f0154600360010154600360020154925092509250909192565b5f60035f015f8154809291906103239061057a565b919050555060015f8381526020019081526020015f20549050919050565b5f5f5f60035f0154600360010154600360020154925092509250909192565b610368610397565b60036040518060600160405290815f820154815260200160018201548152602001600282015481525050905090565b60405180606001604052805f81526020015f81526020015f81525090565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6103f5826103b5565b9150610400836103b5565b9250828201905080821115610418576104176103be565b5b92915050565b5f5ffd5b61042b816103b5565b8114610435575f5ffd5b50565b5f8135905061044681610422565b92915050565b5f5f604083850312156104625761046161041e565b5b5f61046f85828601610438565b925050602061048085828601610438565b9150509250929050565b610493816103b5565b82525050565b5f6020820190506104ac5f83018461048a565b92915050565b5f6060820190506104c55f83018661048a565b6104d2602083018561048a565b6104df604083018461048a565b949350505050565b5f602082840312156104fc576104fb61041e565b5b5f61050984828501610438565b91505092915050565b61051b816103b5565b82525050565b606082015f8201516105355f850182610512565b5060208201516105486020850182610512565b50604082015161055b6040850182610512565b50505050565b5f6060820190506105745f830184610521565b92915050565b5f610584826103b5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036105b6576105b56103be565b5b60018201905091905056fea264697066735822122063e58431f2afdc667f8e687d3e6a99085a93c1fd3ce40b218463b8ddd3cc093664736f6c634300081c0033", +} + +// DB is an auto generated Go binding around an Ethereum contract. +type DB struct { + abi abi.ABI +} + +// NewDB creates a new instance of DB. +func NewDB() *DB { + parsed, err := DBMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &DB{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *DB) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackGet is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x9507d39a. +// +// Solidity: function get(uint256 k) returns(uint256) +func (dB *DB) PackGet(k *big.Int) []byte { + enc, err := dB.abi.Pack("get", k) + if err != nil { + panic(err) + } + return enc +} + +// UnpackGet is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x9507d39a. +// +// Solidity: function get(uint256 k) returns(uint256) +func (dB *DB) UnpackGet(data []byte) (*big.Int, error) { + out, err := dB.abi.Unpack("get", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// PackGetNamedStatParams is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe369ba3b. +// +// Solidity: function getNamedStatParams() view returns(uint256 gets, uint256 inserts, uint256 mods) +func (dB *DB) PackGetNamedStatParams() []byte { + enc, err := dB.abi.Pack("getNamedStatParams") + if err != nil { + panic(err) + } + return enc +} + +// GetNamedStatParamsOutput serves as a container for the return parameters of contract +// method GetNamedStatParams. +type GetNamedStatParamsOutput struct { + Gets *big.Int + Inserts *big.Int + Mods *big.Int +} + +// UnpackGetNamedStatParams is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xe369ba3b. +// +// Solidity: function getNamedStatParams() view returns(uint256 gets, uint256 inserts, uint256 mods) +func (dB *DB) UnpackGetNamedStatParams(data []byte) (GetNamedStatParamsOutput, error) { + out, err := dB.abi.Unpack("getNamedStatParams", data) + outstruct := new(GetNamedStatParamsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Gets = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Inserts = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + outstruct.Mods = abi.ConvertType(out[2], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackGetStatParams is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x6fcb9c70. +// +// Solidity: function getStatParams() view returns(uint256, uint256, uint256) +func (dB *DB) PackGetStatParams() []byte { + enc, err := dB.abi.Pack("getStatParams") + if err != nil { + panic(err) + } + return enc +} + +// GetStatParamsOutput serves as a container for the return parameters of contract +// method GetStatParams. +type GetStatParamsOutput struct { + Arg0 *big.Int + Arg1 *big.Int + Arg2 *big.Int +} + +// UnpackGetStatParams is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x6fcb9c70. +// +// Solidity: function getStatParams() view returns(uint256, uint256, uint256) +func (dB *DB) UnpackGetStatParams(data []byte) (GetStatParamsOutput, error) { + out, err := dB.abi.Unpack("getStatParams", data) + outstruct := new(GetStatParamsOutput) + if err != nil { + return *outstruct, err + } + outstruct.Arg0 = abi.ConvertType(out[0], new(big.Int)).(*big.Int) + outstruct.Arg1 = abi.ConvertType(out[1], new(big.Int)).(*big.Int) + outstruct.Arg2 = abi.ConvertType(out[2], new(big.Int)).(*big.Int) + return *outstruct, err + +} + +// PackGetStatsStruct is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xee8161e0. +// +// Solidity: function getStatsStruct() view returns((uint256,uint256,uint256)) +func (dB *DB) PackGetStatsStruct() []byte { + enc, err := dB.abi.Pack("getStatsStruct") + if err != nil { + panic(err) + } + return enc +} + +// UnpackGetStatsStruct is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xee8161e0. +// +// Solidity: function getStatsStruct() view returns((uint256,uint256,uint256)) +func (dB *DB) UnpackGetStatsStruct(data []byte) (DBStats, error) { + out, err := dB.abi.Unpack("getStatsStruct", data) + if err != nil { + return *new(DBStats), err + } + out0 := *abi.ConvertType(out[0], new(DBStats)).(*DBStats) + return out0, err +} + +// PackInsert is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x1d834a1b. +// +// Solidity: function insert(uint256 k, uint256 v) returns(uint256) +func (dB *DB) PackInsert(k *big.Int, v *big.Int) []byte { + enc, err := dB.abi.Pack("insert", k, v) + if err != nil { + panic(err) + } + return enc +} + +// UnpackInsert is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x1d834a1b. +// +// Solidity: function insert(uint256 k, uint256 v) returns(uint256) +func (dB *DB) UnpackInsert(data []byte) (*big.Int, error) { + out, err := dB.abi.Unpack("insert", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// DBInsert represents a Insert event raised by the DB contract. +type DBInsert struct { + Key *big.Int + Value *big.Int + Length *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const DBInsertEventName = "Insert" + +// ContractEventName returns the user-defined event name. +func (DBInsert) ContractEventName() string { + return DBInsertEventName +} + +// UnpackInsertEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event Insert(uint256 key, uint256 value, uint256 length) +func (dB *DB) UnpackInsertEvent(log *types.Log) (*DBInsert, error) { + event := "Insert" + if log.Topics[0] != dB.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DBInsert) + if len(log.Data) > 0 { + if err := dB.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dB.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// DBKeyedInsert represents a KeyedInsert event raised by the DB contract. +type DBKeyedInsert struct { + Key *big.Int + Value *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const DBKeyedInsertEventName = "KeyedInsert" + +// ContractEventName returns the user-defined event name. +func (DBKeyedInsert) ContractEventName() string { + return DBKeyedInsertEventName +} + +// UnpackKeyedInsertEvent is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event KeyedInsert(uint256 indexed key, uint256 value) +func (dB *DB) UnpackKeyedInsertEvent(log *types.Log) (*DBKeyedInsert, error) { + event := "KeyedInsert" + if log.Topics[0] != dB.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(DBKeyedInsert) + if len(log.Data) > 0 { + if err := dB.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range dB.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/bind/v2/internal/contracts/db/combined-abi.json b/accounts/abi/bind/v2/internal/contracts/db/combined-abi.json new file mode 100644 index 000000000..38a67f745 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/db/combined-abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:DB":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"key","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"length","type":"uint256"}],"name":"Insert","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"key","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"KeyedInsert","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"internalType":"uint256","name":"k","type":"uint256"}],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getNamedStatParams","outputs":[{"internalType":"uint256","name":"gets","type":"uint256"},{"internalType":"uint256","name":"inserts","type":"uint256"},{"internalType":"uint256","name":"mods","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStatParams","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStatsStruct","outputs":[{"components":[{"internalType":"uint256","name":"gets","type":"uint256"},{"internalType":"uint256","name":"inserts","type":"uint256"},{"internalType":"uint256","name":"mods","type":"uint256"}],"internalType":"struct DB.Stats","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"uint256","name":"v","type":"uint256"}],"name":"insert","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}],"bin":"60806040525f5f553480156011575f5ffd5b5060405180606001604052805f81526020015f81526020015f81525060035f820151815f015560208201518160010155604082015181600201559050506105f78061005b5f395ff3fe60806040526004361061004d575f3560e01c80631d834a1b146100cb5780636fcb9c70146101075780639507d39a14610133578063e369ba3b1461016f578063ee8161e01461019b5761006a565b3661006a57345f5f82825461006291906103eb565b925050819055005b348015610075575f5ffd5b505f36606082828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050915050805190602001f35b3480156100d6575f5ffd5b506100f160048036038101906100ec919061044c565b6101c5565b6040516100fe9190610499565b60405180910390f35b348015610112575f5ffd5b5061011b6102ef565b60405161012a939291906104b2565b60405180910390f35b34801561013e575f5ffd5b50610159600480360381019061015491906104e7565b61030e565b6040516101669190610499565b60405180910390f35b34801561017a575f5ffd5b50610183610341565b604051610192939291906104b2565b60405180910390f35b3480156101a6575f5ffd5b506101af610360565b6040516101bc9190610561565b60405180910390f35b5f5f82036101da5760028054905090506102e9565b5f60015f8581526020019081526020015f20540361023757600283908060018154018082558091505060019003905f5260205f20015f909190919091505560036001015f81548092919061022d9061057a565b9190505550610252565b60036002015f81548092919061024c9061057a565b91905055505b8160015f8581526020019081526020015f20819055507f8b39ff47dca36ab5b8b80845238af53aa579625ac7fb173dc09376adada4176983836002805490506040516102a0939291906104b2565b60405180910390a1827f40bed843c6c5f72002f9b469cf4c1ee9f7fb1eb48f091c1267970f98522ac02d836040516102d89190610499565b60405180910390a260028054905090505b92915050565b5f5f5f60035f0154600360010154600360020154925092509250909192565b5f60035f015f8154809291906103239061057a565b919050555060015f8381526020019081526020015f20549050919050565b5f5f5f60035f0154600360010154600360020154925092509250909192565b610368610397565b60036040518060600160405290815f820154815260200160018201548152602001600282015481525050905090565b60405180606001604052805f81526020015f81526020015f81525090565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6103f5826103b5565b9150610400836103b5565b9250828201905080821115610418576104176103be565b5b92915050565b5f5ffd5b61042b816103b5565b8114610435575f5ffd5b50565b5f8135905061044681610422565b92915050565b5f5f604083850312156104625761046161041e565b5b5f61046f85828601610438565b925050602061048085828601610438565b9150509250929050565b610493816103b5565b82525050565b5f6020820190506104ac5f83018461048a565b92915050565b5f6060820190506104c55f83018661048a565b6104d2602083018561048a565b6104df604083018461048a565b949350505050565b5f602082840312156104fc576104fb61041e565b5b5f61050984828501610438565b91505092915050565b61051b816103b5565b82525050565b606082015f8201516105355f850182610512565b5060208201516105486020850182610512565b50604082015161055b6040850182610512565b50505050565b5f6060820190506105745f830184610521565b92915050565b5f610584826103b5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036105b6576105b56103be565b5b60018201905091905056fea264697066735822122063e58431f2afdc667f8e687d3e6a99085a93c1fd3ce40b218463b8ddd3cc093664736f6c634300081c0033"}},"version":"0.8.28+commit.7893614a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/db/contract.sol b/accounts/abi/bind/v2/internal/contracts/db/contract.sol new file mode 100644 index 000000000..f24aa8d38 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/db/contract.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; + +contract DB { + uint balance = 0; + mapping(uint => uint) private _store; + uint[] private _keys; + struct Stats { + uint gets; + uint inserts; + uint mods; // modifications + } + Stats _stats; + + event KeyedInsert(uint indexed key, uint value); + event Insert(uint key, uint value, uint length); + + constructor() { + _stats = Stats(0, 0, 0); + } + + // insert adds a key value to the store, returning the new length of the store. + function insert(uint k, uint v) external returns (uint) { + // No need to store 0 values + if (v == 0) { + return _keys.length; + } + // Check if a key is being overriden + if (_store[k] == 0) { + _keys.push(k); + _stats.inserts++; + } else { + _stats.mods++; + } + _store[k] = v; + emit Insert(k, v, _keys.length); + emit KeyedInsert(k, v); + + return _keys.length; + } + + function get(uint k) public returns (uint) { + _stats.gets++; + return _store[k]; + } + + function getStatParams() public view returns (uint, uint, uint) { + return (_stats.gets, _stats.inserts, _stats.mods); + } + + function getNamedStatParams() public view returns (uint gets, uint inserts, uint mods) { + return (_stats.gets, _stats.inserts, _stats.mods); + } + + function getStatsStruct() public view returns (Stats memory) { + return _stats; + } + + receive() external payable { + balance += msg.value; + } + + fallback(bytes calldata _input) external returns (bytes memory _output) { + _output = _input; + } +} \ No newline at end of file diff --git a/accounts/abi/bind/v2/internal/contracts/events/bindings.go b/accounts/abi/bind/v2/internal/contracts/events/bindings.go new file mode 100644 index 000000000..580bffa23 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/events/bindings.go @@ -0,0 +1,160 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package events + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// CMetaData contains all meta data concerning the C contract. +var CMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"basic1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"basic2\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EmitMulti\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"EmitOne\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ID: "55ef3c19a0ab1c1845f9e347540c1e51f5", + Bin: "0x6080604052348015600e575f5ffd5b506101a08061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063cb49374914610038578063e8e49a7114610042575b5f5ffd5b61004061004c565b005b61004a6100fd565b005b60017f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd207600260405161007e9190610151565b60405180910390a260037f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd20760046040516100b89190610151565b60405180910390a25f15157f3b29b9f6d15ba80d866afb3d70b7548ab1ffda3ef6e65f35f1cb05b0e2b29f4e60016040516100f39190610151565b60405180910390a2565b60017f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd207600260405161012f9190610151565b60405180910390a2565b5f819050919050565b61014b81610139565b82525050565b5f6020820190506101645f830184610142565b9291505056fea26469706673582212207331c79de16a73a1639c4c4b3489ea78a3ed35fe62a178824f586df12672ac0564736f6c634300081c0033", +} + +// C is an auto generated Go binding around an Ethereum contract. +type C struct { + abi abi.ABI +} + +// NewC creates a new instance of C. +func NewC() *C { + parsed, err := CMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &C{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *C) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackEmitMulti is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xcb493749. +// +// Solidity: function EmitMulti() returns() +func (c *C) PackEmitMulti() []byte { + enc, err := c.abi.Pack("EmitMulti") + if err != nil { + panic(err) + } + return enc +} + +// PackEmitOne is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xe8e49a71. +// +// Solidity: function EmitOne() returns() +func (c *C) PackEmitOne() []byte { + enc, err := c.abi.Pack("EmitOne") + if err != nil { + panic(err) + } + return enc +} + +// CBasic1 represents a basic1 event raised by the C contract. +type CBasic1 struct { + Id *big.Int + Data *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const CBasic1EventName = "basic1" + +// ContractEventName returns the user-defined event name. +func (CBasic1) ContractEventName() string { + return CBasic1EventName +} + +// UnpackBasic1Event is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event basic1(uint256 indexed id, uint256 data) +func (c *C) UnpackBasic1Event(log *types.Log) (*CBasic1, error) { + event := "basic1" + if log.Topics[0] != c.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(CBasic1) + if len(log.Data) > 0 { + if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range c.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} + +// CBasic2 represents a basic2 event raised by the C contract. +type CBasic2 struct { + Flag bool + Data *big.Int + Raw *types.Log // Blockchain specific contextual infos +} + +const CBasic2EventName = "basic2" + +// ContractEventName returns the user-defined event name. +func (CBasic2) ContractEventName() string { + return CBasic2EventName +} + +// UnpackBasic2Event is the Go binding that unpacks the event data emitted +// by contract. +// +// Solidity: event basic2(bool indexed flag, uint256 data) +func (c *C) UnpackBasic2Event(log *types.Log) (*CBasic2, error) { + event := "basic2" + if log.Topics[0] != c.abi.Events[event].ID { + return nil, errors.New("event signature mismatch") + } + out := new(CBasic2) + if len(log.Data) > 0 { + if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { + return nil, err + } + } + var indexed abi.Arguments + for _, arg := range c.abi.Events[event].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + if err := abi.ParseTopics(out, indexed, log.Topics[1:]); err != nil { + return nil, err + } + out.Raw = log + return out, nil +} diff --git a/accounts/abi/bind/v2/internal/contracts/events/combined-abi.json b/accounts/abi/bind/v2/internal/contracts/events/combined-abi.json new file mode 100644 index 000000000..bd6b7c3a6 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/events/combined-abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:C":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data","type":"uint256"}],"name":"basic1","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"flag","type":"bool"},{"indexed":false,"internalType":"uint256","name":"data","type":"uint256"}],"name":"basic2","type":"event"},{"inputs":[],"name":"EmitMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"EmitOne","outputs":[],"stateMutability":"nonpayable","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506101a08061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063cb49374914610038578063e8e49a7114610042575b5f5ffd5b61004061004c565b005b61004a6100fd565b005b60017f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd207600260405161007e9190610151565b60405180910390a260037f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd20760046040516100b89190610151565b60405180910390a25f15157f3b29b9f6d15ba80d866afb3d70b7548ab1ffda3ef6e65f35f1cb05b0e2b29f4e60016040516100f39190610151565b60405180910390a2565b60017f8f17dc823e2f9fcdf730b8182c935574691e811e7d46399fe0ff0087795cd207600260405161012f9190610151565b60405180910390a2565b5f819050919050565b61014b81610139565b82525050565b5f6020820190506101645f830184610142565b9291505056fea26469706673582212207331c79de16a73a1639c4c4b3489ea78a3ed35fe62a178824f586df12672ac0564736f6c634300081c0033"}},"version":"0.8.28+commit.7893614a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/events/contract.sol b/accounts/abi/bind/v2/internal/contracts/events/contract.sol new file mode 100644 index 000000000..a30b38a9d --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/events/contract.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +contract C { + event basic1( + uint256 indexed id, + uint256 data + ); + event basic2( + bool indexed flag, + uint256 data + ); + + function EmitOne() public { + emit basic1( + uint256(1), + uint256(2)); + } + + // emit multiple events, different types + function EmitMulti() public { + emit basic1( + uint256(1), + uint256(2)); + emit basic1( + uint256(3), + uint256(4)); + emit basic2( + false, + uint256(1)); + } + + constructor() { + // do something with these + } +} \ No newline at end of file diff --git a/accounts/abi/bind/v2/internal/contracts/nested_libraries/abi.json b/accounts/abi/bind/v2/internal/contracts/nested_libraries/abi.json new file mode 100644 index 000000000..7cfcdaa93 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/nested_libraries/abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:Array":{"abi":[],"bin":"61044261004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c8063677ca2d814610038575b5f80fd5b818015610043575f80fd5b5061005e60048036038101906100599190610235565b610060565b005b5f8280549050116100a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161009d906102cd565b60405180910390fd5b81600183805490506100b89190610318565b815481106100c9576100c861034b565b5b905f5260205f2001548282815481106100e5576100e461034b565b5b905f5260205f2001819055508181815481106101045761010361034b565b5b905f5260205f20015473__$e0273646c631009d12385ab5282af2d432$__63ee05608590916040518263ffffffff1660e01b81526004016101459190610387565b602060405180830381865af4158015610160573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061018491906103b4565b8282815481106101975761019661034b565b5b905f5260205f200181905550818054806101b4576101b36103df565b5b600190038181905f5260205f20015f905590555050565b5f80fd5b5f819050919050565b6101e1816101cf565b81146101eb575f80fd5b50565b5f813590506101fc816101d8565b92915050565b5f819050919050565b61021481610202565b811461021e575f80fd5b50565b5f8135905061022f8161020b565b92915050565b5f806040838503121561024b5761024a6101cb565b5b5f610258858286016101ee565b925050602061026985828601610221565b9150509250929050565b5f82825260208201905092915050565b7f43616e27742072656d6f76652066726f6d20656d7074792061727261790000005f82015250565b5f6102b7601d83610273565b91506102c282610283565b602082019050919050565b5f6020820190508181035f8301526102e4816102ab565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61032282610202565b915061032d83610202565b9250828203905081811115610345576103446102eb565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b61038181610202565b82525050565b5f60208201905061039a5f830184610378565b92915050565b5f815190506103ae8161020b565b92915050565b5f602082840312156103c9576103c86101cb565b5b5f6103d6848285016103a0565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212200680afb351728e7eaa7168f68e59cd7151eff98288314447ad7638a444ed11de64736f6c634300081a0033"},"contract.sol:RecursiveDep":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"AddOne","outputs":[{"internalType":"uint256","name":"ret","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61019d61004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c8063ee05608514610038575b5f80fd5b610052600480360381019061004d91906100b4565b610068565b60405161005f91906100ee565b60405180910390f35b5f6001826100769190610134565b9050919050565b5f80fd5b5f819050919050565b61009381610081565b811461009d575f80fd5b50565b5f813590506100ae8161008a565b92915050565b5f602082840312156100c9576100c861007d565b5b5f6100d6848285016100a0565b91505092915050565b6100e881610081565b82525050565b5f6020820190506101015f8301846100df565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61013e82610081565b915061014983610081565b925082820190508082111561016157610160610107565b5b9291505056fea2646970667358221220d392325a1e387a65c76bff6fecec456650b48856b1e00afc4fa76fb9181da23c64736f6c634300081a0033"},"contract.sol:TestArray":{"abi":[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"arr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"testArrayRemove","outputs":[],"stateMutability":"nonpayable","type":"function"}],"bin":"6080604052348015600e575f80fd5b506103438061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806371e5ee5f14610038578063807fc49a14610068575b5f80fd5b610052600480360381019061004d91906101f0565b610084565b60405161005f919061022a565b60405180910390f35b610082600480360381019061007d91906101f0565b6100a3565b005b5f8181548110610092575f80fd5b905f5260205f20015f915090505481565b5f5b60038110156100e0575f81908060018154018082558091505060019003905f5260205f20015f909190919091505580806001019150506100a5565b505f73__$37f5055d0d00ca8ab20a50453e6986094c$__63677ca2d8909160016040518363ffffffff1660e01b815260040161011d92919061028c565b5f6040518083038186803b158015610133575f80fd5b505af4158015610145573d5f803e3d5ffd5b5050505060025f805490501461015e5761015d6102b3565b5b5f805f81548110610172576101716102e0565b5b905f5260205f20015414610189576101886102b3565b5b60025f60018154811061019f5761019e6102e0565b5b905f5260205f200154146101b6576101b56102b3565b5b50565b5f80fd5b5f819050919050565b6101cf816101bd565b81146101d9575f80fd5b50565b5f813590506101ea816101c6565b92915050565b5f60208284031215610205576102046101b9565b5b5f610212848285016101dc565b91505092915050565b610224816101bd565b82525050565b5f60208201905061023d5f83018461021b565b92915050565b8082525050565b5f819050919050565b5f819050919050565b5f61027661027161026c8461024a565b610253565b6101bd565b9050919050565b6102868161025c565b82525050565b5f60408201905061029f5f830185610243565b6102ac602083018461027d565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea26469706673582212204be2c6230af664b290f016e88cfac62bf7c08823b1fd1bcce8bdcd7fbb785b8a64736f6c634300081a0033"}},"version":"0.8.26+commit.8a97fa7a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/nested_libraries/bindings.go b/accounts/abi/bind/v2/internal/contracts/nested_libraries/bindings.go new file mode 100644 index 000000000..6fd6a1b28 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/nested_libraries/bindings.go @@ -0,0 +1,486 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package nested_libraries + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// C1MetaData contains all meta data concerning the C1 contract. +var C1MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"v1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"v2\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"res\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "ae26158f1824f3918bd66724ee8b6eb7c9", + Bin: "0x6080604052348015600e575f5ffd5b506040516103983803806103988339818101604052810190602e91906066565b5050609d565b5f5ffd5b5f819050919050565b6048816038565b81146051575f5ffd5b50565b5f815190506060816041565b92915050565b5f5f6040838503121560795760786034565b5b5f6084858286016054565b92505060206093858286016054565b9150509250929050565b6102ee806100aa5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80632ad112721461002d575b5f5ffd5b6100476004803603810190610042919061019e565b61005d565b60405161005491906101d8565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad112725f6040518263ffffffff1660e01b81526004016100979190610200565b602060405180830381865af41580156100b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d6919061022d565b73__$5f33a1fab8ea7d932b4bc8c5e7dcd90bc2$__632ad11272856040518263ffffffff1660e01b815260040161010d9190610200565b602060405180830381865af4158015610128573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061014c919061022d565b6101569190610285565b6101609190610285565b9050919050565b5f5ffd5b5f819050919050565b61017d8161016b565b8114610187575f5ffd5b50565b5f8135905061019881610174565b92915050565b5f602082840312156101b3576101b2610167565b5b5f6101c08482850161018a565b91505092915050565b6101d28161016b565b82525050565b5f6020820190506101eb5f8301846101c9565b92915050565b6101fa8161016b565b82525050565b5f6020820190506102135f8301846101f1565b92915050565b5f8151905061022781610174565b92915050565b5f6020828403121561024257610241610167565b5b5f61024f84828501610219565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61028f8261016b565b915061029a8361016b565b92508282019050808211156102b2576102b1610258565b5b9291505056fea26469706673582212205d4715a8d20a3a0a43113e268ec8868b3c3ce24f7cbdb8735b4eeeebf0b5565164736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L1MetaData, + &L4MetaData, + }, +} + +// C1 is an auto generated Go binding around an Ethereum contract. +type C1 struct { + abi abi.ABI +} + +// NewC1 creates a new instance of C1. +func NewC1() *C1 { + parsed, err := C1MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &C1{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *C1) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(uint256 v1, uint256 v2) returns() +func (c1 *C1) PackConstructor(v1 *big.Int, v2 *big.Int) []byte { + enc, err := c1.abi.Pack("", v1, v2) + if err != nil { + panic(err) + } + return enc +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256 res) +func (c1 *C1) PackDo(val *big.Int) []byte { + enc, err := c1.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256 res) +func (c1 *C1) UnpackDo(data []byte) (*big.Int, error) { + out, err := c1.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// C2MetaData contains all meta data concerning the C2 contract. +var C2MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"v1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"v2\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"res\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "78ef2840de5b706112ca2dbfa765501a89", + Bin: "0x6080604052348015600e575f5ffd5b506040516103983803806103988339818101604052810190602e91906066565b5050609d565b5f5ffd5b5f819050919050565b6048816038565b81146051575f5ffd5b50565b5f815190506060816041565b92915050565b5f5f6040838503121560795760786034565b5b5f6084858286016054565b92505060206093858286016054565b9150509250929050565b6102ee806100aa5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80632ad112721461002d575b5f5ffd5b6100476004803603810190610042919061019e565b61005d565b60405161005491906101d8565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad112725f6040518263ffffffff1660e01b81526004016100979190610200565b602060405180830381865af41580156100b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d6919061022d565b73__$6070639404c39b5667691bb1f9177e1eac$__632ad11272856040518263ffffffff1660e01b815260040161010d9190610200565b602060405180830381865af4158015610128573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061014c919061022d565b6101569190610285565b6101609190610285565b9050919050565b5f5ffd5b5f819050919050565b61017d8161016b565b8114610187575f5ffd5b50565b5f8135905061019881610174565b92915050565b5f602082840312156101b3576101b2610167565b5b5f6101c08482850161018a565b91505092915050565b6101d28161016b565b82525050565b5f6020820190506101eb5f8301846101c9565b92915050565b6101fa8161016b565b82525050565b5f6020820190506102135f8301846101f1565b92915050565b5f8151905061022781610174565b92915050565b5f6020828403121561024257610241610167565b5b5f61024f84828501610219565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61028f8261016b565b915061029a8361016b565b92508282019050808211156102b2576102b1610258565b5b9291505056fea2646970667358221220dd394981f1e9fefa4d88bac1c4f1da4131779c7d3bd4189958d278e57e96d96f64736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L1MetaData, + &L4bMetaData, + }, +} + +// C2 is an auto generated Go binding around an Ethereum contract. +type C2 struct { + abi abi.ABI +} + +// NewC2 creates a new instance of C2. +func NewC2() *C2 { + parsed, err := C2MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &C2{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *C2) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackConstructor is the Go binding used to pack the parameters required for +// contract deployment. +// +// Solidity: constructor(uint256 v1, uint256 v2) returns() +func (c2 *C2) PackConstructor(v1 *big.Int, v2 *big.Int) []byte { + enc, err := c2.abi.Pack("", v1, v2) + if err != nil { + panic(err) + } + return enc +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256 res) +func (c2 *C2) PackDo(val *big.Int) []byte { + enc, err := c2.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256 res) +func (c2 *C2) UnpackDo(data []byte) (*big.Int, error) { + out, err := c2.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L1MetaData contains all meta data concerning the L1 contract. +var L1MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "ffc1393672b8ed81d0c8093ffcb0e7fbe8", + Bin: "0x61011c61004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106032575f3560e01c80632ad11272146036575b5f5ffd5b604c600480360381019060489190609c565b6060565b6040516057919060cf565b60405180910390f35b5f60019050919050565b5f5ffd5b5f819050919050565b607e81606e565b81146087575f5ffd5b50565b5f813590506096816077565b92915050565b5f6020828403121560ae5760ad606a565b5b5f60b984828501608a565b91505092915050565b60c981606e565b82525050565b5f60208201905060e05f83018460c2565b9291505056fea26469706673582212200161c5f22d130a2b7ec6cf22e0910e42e32c2881fa4a8a01455f524f63cf218d64736f6c634300081c0033", +} + +// L1 is an auto generated Go binding around an Ethereum contract. +type L1 struct { + abi abi.ABI +} + +// NewL1 creates a new instance of L1. +func NewL1() *L1 { + parsed, err := L1MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L1{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L1) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l1 *L1) PackDo(val *big.Int) []byte { + enc, err := l1.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l1 *L1) UnpackDo(data []byte) (*big.Int, error) { + out, err := l1.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L2MetaData contains all meta data concerning the L2 contract. +var L2MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "2ce896a6dd38932d354f317286f90bc675", + Bin: "0x61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea264697066735822122026999f96e14b0e279909ca5972343113c358e93a904569409a86866e2064f0fa64736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L1MetaData, + }, +} + +// L2 is an auto generated Go binding around an Ethereum contract. +type L2 struct { + abi abi.ABI +} + +// NewL2 creates a new instance of L2. +func NewL2() *L2 { + parsed, err := L2MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L2{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L2) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l2 *L2) PackDo(val *big.Int) []byte { + enc, err := l2.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l2 *L2) UnpackDo(data []byte) (*big.Int, error) { + out, err := l2.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L2bMetaData contains all meta data concerning the L2b contract. +var L2bMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "fd1474cf57f7ed48491e8bfdfd0d172adf", + Bin: "0x61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea2646970667358221220d6e7078682642d273736fd63baaa28538fe72495816c810fa0e77034de385dc564736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L1MetaData, + }, +} + +// L2b is an auto generated Go binding around an Ethereum contract. +type L2b struct { + abi abi.ABI +} + +// NewL2b creates a new instance of L2b. +func NewL2b() *L2b { + parsed, err := L2bMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L2b{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L2b) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l2b *L2b) PackDo(val *big.Int) []byte { + enc, err := l2b.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l2b *L2b) UnpackDo(data []byte) (*big.Int, error) { + out, err := l2b.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L3MetaData contains all meta data concerning the L3 contract. +var L3MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "d03b97f5e1a564374023a72ac7d1806773", + Bin: "0x61011c61004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106032575f3560e01c80632ad11272146036575b5f5ffd5b604c600480360381019060489190609c565b6060565b6040516057919060cf565b60405180910390f35b5f60019050919050565b5f5ffd5b5f819050919050565b607e81606e565b81146087575f5ffd5b50565b5f813590506096816077565b92915050565b5f6020828403121560ae5760ad606a565b5b5f60b984828501608a565b91505092915050565b60c981606e565b82525050565b5f60208201905060e05f83018460c2565b9291505056fea264697066735822122094cfcb0ce039318885cc58f6d8e609e6e4bec575e1a046d3d15ea2e01e97241e64736f6c634300081c0033", +} + +// L3 is an auto generated Go binding around an Ethereum contract. +type L3 struct { + abi abi.ABI +} + +// NewL3 creates a new instance of L3. +func NewL3() *L3 { + parsed, err := L3MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L3{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L3) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l3 *L3) PackDo(val *big.Int) []byte { + enc, err := l3.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l3 *L3) UnpackDo(data []byte) (*big.Int, error) { + out, err := l3.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L4MetaData contains all meta data concerning the L4 contract. +var L4MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "5f33a1fab8ea7d932b4bc8c5e7dcd90bc2", + Bin: "0x6102d161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d91906101a9565b610068565b60405161005f91906101e3565b60405180910390f35b5f600173__$d03b97f5e1a564374023a72ac7d1806773$__632ad11272846040518263ffffffff1660e01b81526004016100a291906101e3565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610210565b73__$2ce896a6dd38932d354f317286f90bc675$__632ad11272856040518263ffffffff1660e01b815260040161011891906101e3565b602060405180830381865af4158015610133573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101579190610210565b6101619190610268565b61016b9190610268565b9050919050565b5f5ffd5b5f819050919050565b61018881610176565b8114610192575f5ffd5b50565b5f813590506101a38161017f565b92915050565b5f602082840312156101be576101bd610172565b5b5f6101cb84828501610195565b91505092915050565b6101dd81610176565b82525050565b5f6020820190506101f65f8301846101d4565b92915050565b5f8151905061020a8161017f565b92915050565b5f6020828403121561022557610224610172565b5b5f610232848285016101fc565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61027282610176565b915061027d83610176565b92508282019050808211156102955761029461023b565b5b9291505056fea2646970667358221220531485f0b9ff78ba5ef06ef345aaddccec3ad15d1460014ccd7c2a58d36d0d4464736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L2MetaData, + &L3MetaData, + }, +} + +// L4 is an auto generated Go binding around an Ethereum contract. +type L4 struct { + abi abi.ABI +} + +// NewL4 creates a new instance of L4. +func NewL4() *L4 { + parsed, err := L4MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L4{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L4) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l4 *L4) PackDo(val *big.Int) []byte { + enc, err := l4.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l4 *L4) UnpackDo(data []byte) (*big.Int, error) { + out, err := l4.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} + +// L4bMetaData contains all meta data concerning the L4b contract. +var L4bMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"Do\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "6070639404c39b5667691bb1f9177e1eac", + Bin: "0x61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$fd1474cf57f7ed48491e8bfdfd0d172adf$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea264697066735822122008a2478fd2427f180ace529e137b69337cb655dc21d6426de37054c32e821c6a64736f6c634300081c0033", + Deps: []*bind.MetaData{ + &L2bMetaData, + }, +} + +// L4b is an auto generated Go binding around an Ethereum contract. +type L4b struct { + abi abi.ABI +} + +// NewL4b creates a new instance of L4b. +func NewL4b() *L4b { + parsed, err := L4bMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &L4b{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *L4b) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackDo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l4b *L4b) PackDo(val *big.Int) []byte { + enc, err := l4b.abi.Pack("Do", val) + if err != nil { + panic(err) + } + return enc +} + +// UnpackDo is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0x2ad11272. +// +// Solidity: function Do(uint256 val) pure returns(uint256) +func (l4b *L4b) UnpackDo(data []byte) (*big.Int, error) { + out, err := l4b.abi.Unpack("Do", data) + if err != nil { + return new(big.Int), err + } + out0 := abi.ConvertType(out[0], new(big.Int)).(*big.Int) + return out0, err +} diff --git a/accounts/abi/bind/v2/internal/contracts/nested_libraries/combined-abi.json b/accounts/abi/bind/v2/internal/contracts/nested_libraries/combined-abi.json new file mode 100644 index 000000000..61e928aab --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/nested_libraries/combined-abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:C1":{"abi":[{"inputs":[{"internalType":"uint256","name":"v1","type":"uint256"},{"internalType":"uint256","name":"v2","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"res","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506040516103983803806103988339818101604052810190602e91906066565b5050609d565b5f5ffd5b5f819050919050565b6048816038565b81146051575f5ffd5b50565b5f815190506060816041565b92915050565b5f5f6040838503121560795760786034565b5b5f6084858286016054565b92505060206093858286016054565b9150509250929050565b6102ee806100aa5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80632ad112721461002d575b5f5ffd5b6100476004803603810190610042919061019e565b61005d565b60405161005491906101d8565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad112725f6040518263ffffffff1660e01b81526004016100979190610200565b602060405180830381865af41580156100b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d6919061022d565b73__$5f33a1fab8ea7d932b4bc8c5e7dcd90bc2$__632ad11272856040518263ffffffff1660e01b815260040161010d9190610200565b602060405180830381865af4158015610128573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061014c919061022d565b6101569190610285565b6101609190610285565b9050919050565b5f5ffd5b5f819050919050565b61017d8161016b565b8114610187575f5ffd5b50565b5f8135905061019881610174565b92915050565b5f602082840312156101b3576101b2610167565b5b5f6101c08482850161018a565b91505092915050565b6101d28161016b565b82525050565b5f6020820190506101eb5f8301846101c9565b92915050565b6101fa8161016b565b82525050565b5f6020820190506102135f8301846101f1565b92915050565b5f8151905061022781610174565b92915050565b5f6020828403121561024257610241610167565b5b5f61024f84828501610219565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61028f8261016b565b915061029a8361016b565b92508282019050808211156102b2576102b1610258565b5b9291505056fea26469706673582212205d4715a8d20a3a0a43113e268ec8868b3c3ce24f7cbdb8735b4eeeebf0b5565164736f6c634300081c0033"},"contract.sol:C2":{"abi":[{"inputs":[{"internalType":"uint256","name":"v1","type":"uint256"},{"internalType":"uint256","name":"v2","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"res","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506040516103983803806103988339818101604052810190602e91906066565b5050609d565b5f5ffd5b5f819050919050565b6048816038565b81146051575f5ffd5b50565b5f815190506060816041565b92915050565b5f5f6040838503121560795760786034565b5b5f6084858286016054565b92505060206093858286016054565b9150509250929050565b6102ee806100aa5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80632ad112721461002d575b5f5ffd5b6100476004803603810190610042919061019e565b61005d565b60405161005491906101d8565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad112725f6040518263ffffffff1660e01b81526004016100979190610200565b602060405180830381865af41580156100b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d6919061022d565b73__$6070639404c39b5667691bb1f9177e1eac$__632ad11272856040518263ffffffff1660e01b815260040161010d9190610200565b602060405180830381865af4158015610128573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061014c919061022d565b6101569190610285565b6101609190610285565b9050919050565b5f5ffd5b5f819050919050565b61017d8161016b565b8114610187575f5ffd5b50565b5f8135905061019881610174565b92915050565b5f602082840312156101b3576101b2610167565b5b5f6101c08482850161018a565b91505092915050565b6101d28161016b565b82525050565b5f6020820190506101eb5f8301846101c9565b92915050565b6101fa8161016b565b82525050565b5f6020820190506102135f8301846101f1565b92915050565b5f8151905061022781610174565b92915050565b5f6020828403121561024257610241610167565b5b5f61024f84828501610219565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61028f8261016b565b915061029a8361016b565b92508282019050808211156102b2576102b1610258565b5b9291505056fea2646970667358221220dd394981f1e9fefa4d88bac1c4f1da4131779c7d3bd4189958d278e57e96d96f64736f6c634300081c0033"},"contract.sol:L1":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61011c61004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106032575f3560e01c80632ad11272146036575b5f5ffd5b604c600480360381019060489190609c565b6060565b6040516057919060cf565b60405180910390f35b5f60019050919050565b5f5ffd5b5f819050919050565b607e81606e565b81146087575f5ffd5b50565b5f813590506096816077565b92915050565b5f6020828403121560ae5760ad606a565b5b5f60b984828501608a565b91505092915050565b60c981606e565b82525050565b5f60208201905060e05f83018460c2565b9291505056fea26469706673582212200161c5f22d130a2b7ec6cf22e0910e42e32c2881fa4a8a01455f524f63cf218d64736f6c634300081c0033"},"contract.sol:L2":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea264697066735822122026999f96e14b0e279909ca5972343113c358e93a904569409a86866e2064f0fa64736f6c634300081c0033"},"contract.sol:L2b":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$ffc1393672b8ed81d0c8093ffcb0e7fbe8$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea2646970667358221220d6e7078682642d273736fd63baaa28538fe72495816c810fa0e77034de385dc564736f6c634300081c0033"},"contract.sol:L3":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61011c61004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106032575f3560e01c80632ad11272146036575b5f5ffd5b604c600480360381019060489190609c565b6060565b6040516057919060cf565b60405180910390f35b5f60019050919050565b5f5ffd5b5f819050919050565b607e81606e565b81146087575f5ffd5b50565b5f813590506096816077565b92915050565b5f6020828403121560ae5760ad606a565b5b5f60b984828501608a565b91505092915050565b60c981606e565b82525050565b5f60208201905060e05f83018460c2565b9291505056fea264697066735822122094cfcb0ce039318885cc58f6d8e609e6e4bec575e1a046d3d15ea2e01e97241e64736f6c634300081c0033"},"contract.sol:L4":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"6102d161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d91906101a9565b610068565b60405161005f91906101e3565b60405180910390f35b5f600173__$d03b97f5e1a564374023a72ac7d1806773$__632ad11272846040518263ffffffff1660e01b81526004016100a291906101e3565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610210565b73__$2ce896a6dd38932d354f317286f90bc675$__632ad11272856040518263ffffffff1660e01b815260040161011891906101e3565b602060405180830381865af4158015610133573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101579190610210565b6101619190610268565b61016b9190610268565b9050919050565b5f5ffd5b5f819050919050565b61018881610176565b8114610192575f5ffd5b50565b5f813590506101a38161017f565b92915050565b5f602082840312156101be576101bd610172565b5b5f6101cb84828501610195565b91505092915050565b6101dd81610176565b82525050565b5f6020820190506101f65f8301846101d4565b92915050565b5f8151905061020a8161017f565b92915050565b5f6020828403121561022557610224610172565b5b5f610232848285016101fc565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61027282610176565b915061027d83610176565b92508282019050808211156102955761029461023b565b5b9291505056fea2646970667358221220531485f0b9ff78ba5ef06ef345aaddccec3ad15d1460014ccd7c2a58d36d0d4464736f6c634300081c0033"},"contract.sol:L4b":{"abi":[{"inputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"name":"Do","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"bin":"61025161004d600b8282823980515f1a6073146041577f4e487b71000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c80632ad1127214610038575b5f5ffd5b610052600480360381019061004d9190610129565b610068565b60405161005f9190610163565b60405180910390f35b5f600173__$fd1474cf57f7ed48491e8bfdfd0d172adf$__632ad11272846040518263ffffffff1660e01b81526004016100a29190610163565b602060405180830381865af41580156100bd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e19190610190565b6100eb91906101e8565b9050919050565b5f5ffd5b5f819050919050565b610108816100f6565b8114610112575f5ffd5b50565b5f81359050610123816100ff565b92915050565b5f6020828403121561013e5761013d6100f2565b5b5f61014b84828501610115565b91505092915050565b61015d816100f6565b82525050565b5f6020820190506101765f830184610154565b92915050565b5f8151905061018a816100ff565b92915050565b5f602082840312156101a5576101a46100f2565b5b5f6101b28482850161017c565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6101f2826100f6565b91506101fd836100f6565b9250828201905080821115610215576102146101bb565b5b9291505056fea264697066735822122008a2478fd2427f180ace529e137b69337cb655dc21d6426de37054c32e821c6a64736f6c634300081c0033"}},"version":"0.8.28+commit.7893614a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/nested_libraries/contract.sol b/accounts/abi/bind/v2/internal/contracts/nested_libraries/contract.sol new file mode 100644 index 000000000..1794e72ac --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/nested_libraries/contract.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + + +// L1 +// \ +// L2 L3 L1 +// \ / / +// L4 / +// \ / +// C1 +// +library L1 { + function Do(uint256 val) public pure returns (uint256) { + return uint256(1); + } +} + +library L2 { + function Do(uint256 val) public pure returns (uint256) { + return L1.Do(val) + uint256(1); + } +} + +library L3 { + function Do(uint256 val) public pure returns (uint256) { + return uint256(1); + } +} + +library L4 { + function Do(uint256 val) public pure returns (uint256) { + return L2.Do(uint256(val)) + L3.Do(uint256(val)) + uint256(1); + } +} + +contract C1 { + function Do(uint256 val) public pure returns (uint256 res) { + return L4.Do(uint256(val)) + L1.Do(uint256(0)) + uint256(1); + } + + constructor(uint256 v1, uint256 v2) { + // do something with these + } +} + +// second contract+libraries: slightly different library deps than V1, but sharing several +// L1 +// \ +// L2b L3 L1 +// \ / / +// L4b / +// \ / +// C2 +// +library L4b { + function Do(uint256 val) public pure returns (uint256) { + return L2b.Do(uint256(val)) + uint256(1); + } +} + +library L2b { + function Do(uint256 val) public pure returns (uint256) { + return L1.Do(uint256(val)) + uint256(1); + } +} + +contract C2 { + function Do(uint256 val) public pure returns (uint256 res) { + return L4b.Do(uint256(val)) + L1.Do(uint256(0)) + uint256(1); + } + + constructor(uint256 v1, uint256 v2) { + // do something with these + } +} \ No newline at end of file diff --git a/accounts/abi/bind/v2/internal/contracts/solc_errors/bindings.go b/accounts/abi/bind/v2/internal/contracts/solc_errors/bindings.go new file mode 100644 index 000000000..067fb2b0e --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/solc_errors/bindings.go @@ -0,0 +1,217 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package solc_errors + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// CMetaData contains all meta data concerning the C contract. +var CMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arg1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg2\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg3\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"arg4\",\"type\":\"bool\"}],\"name\":\"BadThing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arg1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg2\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg3\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg4\",\"type\":\"uint256\"}],\"name\":\"BadThing2\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Bar\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Foo\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "55ef3c19a0ab1c1845f9e347540c1e51f5", + Bin: "0x6080604052348015600e575f5ffd5b506101c58061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063b0a378b014610038578063bfb4ebcf14610042575b5f5ffd5b61004061004c565b005b61004a610092565b005b5f6001600260036040517fd233a24f00000000000000000000000000000000000000000000000000000000815260040161008994939291906100ef565b60405180910390fd5b5f600160025f6040517fbb6a82f10000000000000000000000000000000000000000000000000000000081526004016100ce949392919061014c565b60405180910390fd5b5f819050919050565b6100e9816100d7565b82525050565b5f6080820190506101025f8301876100e0565b61010f60208301866100e0565b61011c60408301856100e0565b61012960608301846100e0565b95945050505050565b5f8115159050919050565b61014681610132565b82525050565b5f60808201905061015f5f8301876100e0565b61016c60208301866100e0565b61017960408301856100e0565b610186606083018461013d565b9594505050505056fea26469706673582212206a82b4c28576e4483a81102558271cfefc891cd63b95440dea521185c1ff6a2a64736f6c634300081c0033", +} + +// C is an auto generated Go binding around an Ethereum contract. +type C struct { + abi abi.ABI +} + +// NewC creates a new instance of C. +func NewC() *C { + parsed, err := CMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &C{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *C) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackBar is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xb0a378b0. +// +// Solidity: function Bar() pure returns() +func (c *C) PackBar() []byte { + enc, err := c.abi.Pack("Bar") + if err != nil { + panic(err) + } + return enc +} + +// PackFoo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xbfb4ebcf. +// +// Solidity: function Foo() pure returns() +func (c *C) PackFoo() []byte { + enc, err := c.abi.Pack("Foo") + if err != nil { + panic(err) + } + return enc +} + +// UnpackError attempts to decode the provided error data using user-defined +// error definitions. +func (c *C) UnpackError(raw []byte) (any, error) { + if bytes.Equal(raw[:4], c.abi.Errors["BadThing"].ID.Bytes()[:4]) { + return c.UnpackBadThingError(raw[4:]) + } + if bytes.Equal(raw[:4], c.abi.Errors["BadThing2"].ID.Bytes()[:4]) { + return c.UnpackBadThing2Error(raw[4:]) + } + return nil, errors.New("Unknown error") +} + +// CBadThing represents a BadThing error raised by the C contract. +type CBadThing struct { + Arg1 *big.Int + Arg2 *big.Int + Arg3 *big.Int + Arg4 bool +} + +// ErrorID returns the hash of canonical representation of the error's signature. +// +// Solidity: error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4) +func CBadThingErrorID() common.Hash { + return common.HexToHash("0xbb6a82f123854747ef4381e30e497f934a3854753fec99a69c35c30d4b46714d") +} + +// UnpackBadThingError is the Go binding used to decode the provided +// error data into the corresponding Go error struct. +// +// Solidity: error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4) +func (c *C) UnpackBadThingError(raw []byte) (*CBadThing, error) { + out := new(CBadThing) + if err := c.abi.UnpackIntoInterface(out, "BadThing", raw); err != nil { + return nil, err + } + return out, nil +} + +// CBadThing2 represents a BadThing2 error raised by the C contract. +type CBadThing2 struct { + Arg1 *big.Int + Arg2 *big.Int + Arg3 *big.Int + Arg4 *big.Int +} + +// ErrorID returns the hash of canonical representation of the error's signature. +// +// Solidity: error BadThing2(uint256 arg1, uint256 arg2, uint256 arg3, uint256 arg4) +func CBadThing2ErrorID() common.Hash { + return common.HexToHash("0xd233a24f02271fe7c9470e060d0fda6447a142bf12ab31fed7ab65affd546175") +} + +// UnpackBadThing2Error is the Go binding used to decode the provided +// error data into the corresponding Go error struct. +// +// Solidity: error BadThing2(uint256 arg1, uint256 arg2, uint256 arg3, uint256 arg4) +func (c *C) UnpackBadThing2Error(raw []byte) (*CBadThing2, error) { + out := new(CBadThing2) + if err := c.abi.UnpackIntoInterface(out, "BadThing2", raw); err != nil { + return nil, err + } + return out, nil +} + +// C2MetaData contains all meta data concerning the C2 contract. +var C2MetaData = bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arg1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg2\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"arg3\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"arg4\",\"type\":\"bool\"}],\"name\":\"BadThing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Foo\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "78ef2840de5b706112ca2dbfa765501a89", + Bin: "0x6080604052348015600e575f5ffd5b506101148061001c5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063bfb4ebcf14602a575b5f5ffd5b60306032565b005b5f600160025f6040517fbb6a82f1000000000000000000000000000000000000000000000000000000008152600401606c949392919060a3565b60405180910390fd5b5f819050919050565b6085816075565b82525050565b5f8115159050919050565b609d81608b565b82525050565b5f60808201905060b45f830187607e565b60bf6020830186607e565b60ca6040830185607e565b60d560608301846096565b9594505050505056fea2646970667358221220e90bf647ffc897060e44b88d54995ed0c03c988fbccaf034375c2ff4e594690764736f6c634300081c0033", +} + +// C2 is an auto generated Go binding around an Ethereum contract. +type C2 struct { + abi abi.ABI +} + +// NewC2 creates a new instance of C2. +func NewC2() *C2 { + parsed, err := C2MetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &C2{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *C2) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackFoo is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xbfb4ebcf. +// +// Solidity: function Foo() pure returns() +func (c2 *C2) PackFoo() []byte { + enc, err := c2.abi.Pack("Foo") + if err != nil { + panic(err) + } + return enc +} + +// UnpackError attempts to decode the provided error data using user-defined +// error definitions. +func (c2 *C2) UnpackError(raw []byte) (any, error) { + if bytes.Equal(raw[:4], c2.abi.Errors["BadThing"].ID.Bytes()[:4]) { + return c2.UnpackBadThingError(raw[4:]) + } + return nil, errors.New("Unknown error") +} + +// C2BadThing represents a BadThing error raised by the C2 contract. +type C2BadThing struct { + Arg1 *big.Int + Arg2 *big.Int + Arg3 *big.Int + Arg4 bool +} + +// ErrorID returns the hash of canonical representation of the error's signature. +// +// Solidity: error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4) +func C2BadThingErrorID() common.Hash { + return common.HexToHash("0xbb6a82f123854747ef4381e30e497f934a3854753fec99a69c35c30d4b46714d") +} + +// UnpackBadThingError is the Go binding used to decode the provided +// error data into the corresponding Go error struct. +// +// Solidity: error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4) +func (c2 *C2) UnpackBadThingError(raw []byte) (*C2BadThing, error) { + out := new(C2BadThing) + if err := c2.abi.UnpackIntoInterface(out, "BadThing", raw); err != nil { + return nil, err + } + return out, nil +} diff --git a/accounts/abi/bind/v2/internal/contracts/solc_errors/combined-abi.json b/accounts/abi/bind/v2/internal/contracts/solc_errors/combined-abi.json new file mode 100644 index 000000000..a8fdf9dc3 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/solc_errors/combined-abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:C":{"abi":[{"inputs":[{"internalType":"uint256","name":"arg1","type":"uint256"},{"internalType":"uint256","name":"arg2","type":"uint256"},{"internalType":"uint256","name":"arg3","type":"uint256"},{"internalType":"bool","name":"arg4","type":"bool"}],"name":"BadThing","type":"error"},{"inputs":[{"internalType":"uint256","name":"arg1","type":"uint256"},{"internalType":"uint256","name":"arg2","type":"uint256"},{"internalType":"uint256","name":"arg3","type":"uint256"},{"internalType":"uint256","name":"arg4","type":"uint256"}],"name":"BadThing2","type":"error"},{"inputs":[],"name":"Bar","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"Foo","outputs":[],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506101c58061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063b0a378b014610038578063bfb4ebcf14610042575b5f5ffd5b61004061004c565b005b61004a610092565b005b5f6001600260036040517fd233a24f00000000000000000000000000000000000000000000000000000000815260040161008994939291906100ef565b60405180910390fd5b5f600160025f6040517fbb6a82f10000000000000000000000000000000000000000000000000000000081526004016100ce949392919061014c565b60405180910390fd5b5f819050919050565b6100e9816100d7565b82525050565b5f6080820190506101025f8301876100e0565b61010f60208301866100e0565b61011c60408301856100e0565b61012960608301846100e0565b95945050505050565b5f8115159050919050565b61014681610132565b82525050565b5f60808201905061015f5f8301876100e0565b61016c60208301866100e0565b61017960408301856100e0565b610186606083018461013d565b9594505050505056fea26469706673582212206a82b4c28576e4483a81102558271cfefc891cd63b95440dea521185c1ff6a2a64736f6c634300081c0033"},"contract.sol:C2":{"abi":[{"inputs":[{"internalType":"uint256","name":"arg1","type":"uint256"},{"internalType":"uint256","name":"arg2","type":"uint256"},{"internalType":"uint256","name":"arg3","type":"uint256"},{"internalType":"bool","name":"arg4","type":"bool"}],"name":"BadThing","type":"error"},{"inputs":[],"name":"Foo","outputs":[],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506101148061001c5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063bfb4ebcf14602a575b5f5ffd5b60306032565b005b5f600160025f6040517fbb6a82f1000000000000000000000000000000000000000000000000000000008152600401606c949392919060a3565b60405180910390fd5b5f819050919050565b6085816075565b82525050565b5f8115159050919050565b609d81608b565b82525050565b5f60808201905060b45f830187607e565b60bf6020830186607e565b60ca6040830185607e565b60d560608301846096565b9594505050505056fea2646970667358221220e90bf647ffc897060e44b88d54995ed0c03c988fbccaf034375c2ff4e594690764736f6c634300081c0033"}},"version":"0.8.28+commit.7893614a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/solc_errors/contract.sol b/accounts/abi/bind/v2/internal/contracts/solc_errors/contract.sol new file mode 100644 index 000000000..541352a1d --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/solc_errors/contract.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +error BadThing(uint256 arg1, uint256 arg2, uint256 arg3, bool arg4); +error BadThing2(uint256 arg1, uint256 arg2, uint256 arg3, uint256 arg4); + +contract C { + function Foo() public pure { + revert BadThing({ + arg1: uint256(0), + arg2: uint256(1), + arg3: uint256(2), + arg4: false + }); + } + function Bar() public pure { + revert BadThing2({ + arg1: uint256(0), + arg2: uint256(1), + arg3: uint256(2), + arg4: uint256(3) + }); + } +} + +// purpose of this is to test that generation of metadata for contract that emits one error produces valid Go code +contract C2 { + function Foo() public pure { + revert BadThing({ + arg1: uint256(0), + arg2: uint256(1), + arg3: uint256(2), + arg4: false + }); + } +} \ No newline at end of file diff --git a/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/bindings.go b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/bindings.go new file mode 100644 index 000000000..4999cc75d --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/bindings.go @@ -0,0 +1,77 @@ +// Code generated via abigen V2 - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package uint256arrayreturn + +import ( + "bytes" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = bytes.Equal + _ = errors.New + _ = big.NewInt + _ = common.Big1 + _ = types.BloomLookup + _ = abi.ConvertType +) + +// MyContractMetaData contains all meta data concerning the MyContract contract. +var MyContractMetaData = bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"GetNums\",\"outputs\":[{\"internalType\":\"uint256[5]\",\"name\":\"\",\"type\":\"uint256[5]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ID: "e48e83c9c45b19a47bd451eedc725a6bff", + Bin: "0x6080604052348015600e575f5ffd5b506101a78061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063bd6d10071461002d575b5f5ffd5b61003561004b565b6040516100429190610158565b60405180910390f35b610053610088565b5f6040518060a001604052805f8152602001600181526020016002815260200160038152602001600481525090508091505090565b6040518060a00160405280600590602082028036833780820191505090505090565b5f60059050919050565b5f81905092915050565b5f819050919050565b5f819050919050565b6100d9816100c7565b82525050565b5f6100ea83836100d0565b60208301905092915050565b5f602082019050919050565b61010b816100aa565b61011581846100b4565b9250610120826100be565b805f5b8381101561015057815161013787826100df565b9650610142836100f6565b925050600181019050610123565b505050505050565b5f60a08201905061016b5f830184610102565b9291505056fea2646970667358221220ef76cc678ca215c3e9e5261e3f33ac1cb9901c3186c2af167bfcd8f03b3b864c64736f6c634300081c0033", +} + +// MyContract is an auto generated Go binding around an Ethereum contract. +type MyContract struct { + abi abi.ABI +} + +// NewMyContract creates a new instance of MyContract. +func NewMyContract() *MyContract { + parsed, err := MyContractMetaData.ParseABI() + if err != nil { + panic(errors.New("invalid ABI: " + err.Error())) + } + return &MyContract{abi: *parsed} +} + +// Instance creates a wrapper for a deployed contract instance at the given address. +// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc. +func (c *MyContract) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract { + return bind.NewBoundContract(addr, c.abi, backend, backend, backend) +} + +// PackGetNums is the Go binding used to pack the parameters required for calling +// the contract method with ID 0xbd6d1007. +// +// Solidity: function GetNums() pure returns(uint256[5]) +func (myContract *MyContract) PackGetNums() []byte { + enc, err := myContract.abi.Pack("GetNums") + if err != nil { + panic(err) + } + return enc +} + +// UnpackGetNums is the Go binding that unpacks the parameters returned +// from invoking the contract method with ID 0xbd6d1007. +// +// Solidity: function GetNums() pure returns(uint256[5]) +func (myContract *MyContract) UnpackGetNums(data []byte) ([5]*big.Int, error) { + out, err := myContract.abi.Unpack("GetNums", data) + if err != nil { + return *new([5]*big.Int), err + } + out0 := *abi.ConvertType(out[0], new([5]*big.Int)).(*[5]*big.Int) + return out0, err +} diff --git a/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/combined-abi.json b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/combined-abi.json new file mode 100644 index 000000000..f0b424b82 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/combined-abi.json @@ -0,0 +1 @@ +{"contracts":{"contract.sol:MyContract":{"abi":[{"inputs":[],"name":"GetNums","outputs":[{"internalType":"uint256[5]","name":"","type":"uint256[5]"}],"stateMutability":"pure","type":"function"}],"bin":"6080604052348015600e575f5ffd5b506101a78061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063bd6d10071461002d575b5f5ffd5b61003561004b565b6040516100429190610158565b60405180910390f35b610053610088565b5f6040518060a001604052805f8152602001600181526020016002815260200160038152602001600481525090508091505090565b6040518060a00160405280600590602082028036833780820191505090505090565b5f60059050919050565b5f81905092915050565b5f819050919050565b5f819050919050565b6100d9816100c7565b82525050565b5f6100ea83836100d0565b60208301905092915050565b5f602082019050919050565b61010b816100aa565b61011581846100b4565b9250610120826100be565b805f5b8381101561015057815161013787826100df565b9650610142836100f6565b925050600181019050610123565b505050505050565b5f60a08201905061016b5f830184610102565b9291505056fea2646970667358221220ef76cc678ca215c3e9e5261e3f33ac1cb9901c3186c2af167bfcd8f03b3b864c64736f6c634300081c0033"}},"version":"0.8.28+commit.7893614a.Darwin.appleclang"} diff --git a/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/contract.sol b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/contract.sol new file mode 100644 index 000000000..cb2aa54b3 --- /dev/null +++ b/accounts/abi/bind/v2/internal/contracts/uint256arrayreturn/contract.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +contract MyContract { + // emit multiple events, different types + function GetNums() public pure returns (uint256[5] memory) { + uint256[5] memory myNums = [uint256(0), uint256(1), uint256(2), uint256(3), uint256(4)]; + return myNums; + } +} \ No newline at end of file diff --git a/accounts/abi/bind/v2/lib.go b/accounts/abi/bind/v2/lib.go new file mode 100644 index 000000000..383116134 --- /dev/null +++ b/accounts/abi/bind/v2/lib.go @@ -0,0 +1,243 @@ +// Copyright 2024 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 . + +// Package bind implements utilities for interacting with Solidity contracts. +// This is the 'runtime' for contract bindings generated with the abigen command. +// It includes methods for calling/transacting, filtering chain history for +// specific custom Solidity event types, and creating event subscriptions to monitor the +// chain for event occurrences. +// +// Two methods for contract deployment are provided: +// - [DeployContract] is intended to be used for deployment of a single contract. +// - [LinkAndDeploy] is intended for the deployment of multiple +// contracts, potentially with library dependencies. +package bind + +import ( + "errors" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/event" +) + +// ContractEvent is a type constraint for ABI event types. +type ContractEvent interface { + ContractEventName() string +} + +// FilterEvents filters a historical block range for instances of emission of a +// specific event type from a specified contract. It returns an error if the +// provided filter opts are invalid or the backend is closed. +// +// FilterEvents is intended to be used with contract event unpack methods in +// bindings generated with the abigen --v2 flag. It should be +// preferred over BoundContract.FilterLogs. +func FilterEvents[Ev ContractEvent](c *BoundContract, opts *FilterOpts, unpack func(*types.Log) (*Ev, error), topics ...[]any) (*EventIterator[Ev], error) { + var e Ev + logs, sub, err := c.FilterLogs(opts, e.ContractEventName(), topics...) + if err != nil { + return nil, err + } + return &EventIterator[Ev]{unpack: unpack, logs: logs, sub: sub}, nil +} + +// WatchEvents creates an event subscription to notify when logs of the +// specified event type are emitted from the given contract. Received logs are +// unpacked and forwarded to sink. If topics are specified, only events are +// forwarded which match the topics. +// +// WatchEvents returns a subscription or an error if the provided WatchOpts are +// invalid or the backend is closed. +// +// WatchEvents is intended to be used with contract event unpack methods in +// bindings generated with the abigen --v2 flag. It should be +// preferred over BoundContract.WatchLogs. +func WatchEvents[Ev ContractEvent](c *BoundContract, opts *WatchOpts, unpack func(*types.Log) (*Ev, error), sink chan<- *Ev, topics ...[]any) (event.Subscription, error) { + var e Ev + logs, sub, err := c.WatchLogs(opts, e.ContractEventName(), topics...) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + ev, err := unpack(&log) + if err != nil { + return err + } + + select { + case sink <- ev: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// EventIterator is an object for iterating over the results of a event log +// filter call. +type EventIterator[T any] struct { + current *T + unpack func(*types.Log) (*T, error) + logs <-chan types.Log + sub ethereum.Subscription + fail error // error to hold reason for iteration failure + closed bool // true if Close has been called +} + +// Value returns the current value of the iterator, or nil if there isn't one. +func (it *EventIterator[T]) Value() *T { + return it.current +} + +// Next advances the iterator to the subsequent event (if there is one), +// returning true if the iterator advanced. +// +// If the attempt to convert the raw log object to an instance of T using the +// unpack function provided via FilterEvents returns an error: that error is +// returned and subsequent calls to Next will not advance the iterator. +func (it *EventIterator[T]) Next() (advanced bool) { + // If the iterator failed with an error, don't proceed + if it.fail != nil || it.closed { + return false + } + // if the iterator is still active, block until a log is received or the + // underlying subscription terminates. + select { + case log := <-it.logs: + res, err := it.unpack(&log) + if err != nil { + it.fail = err + return false + } + it.current = res + return true + case <-it.sub.Err(): + // regardless of how the subscription ends, still be able to iterate + // over any unread logs. + select { + case log := <-it.logs: + res, err := it.unpack(&log) + if err != nil { + it.fail = err + return false + } + it.current = res + return true + default: + return false + } + } +} + +// Error returns an error if iteration has failed. +func (it *EventIterator[T]) Error() error { + return it.fail +} + +// Close releases any pending underlying resources. Any subsequent calls to +// Next will not advance the iterator, but the current value remains accessible. +func (it *EventIterator[T]) Close() error { + it.closed = true + it.sub.Unsubscribe() + return nil +} + +// Call performs an eth_call to a contract with optional call data. +// +// To call a function that doesn't return any output, pass nil as the unpack +// function. This can be useful if you just want to check that the function +// doesn't revert. +// +// Call is intended to be used with contract method unpack methods in +// bindings generated with the abigen --v2 flag. It should be +// preferred over BoundContract.Call +func Call[T any](c *BoundContract, opts *CallOpts, calldata []byte, unpack func([]byte) (T, error)) (T, error) { + var defaultResult T + packedOutput, err := c.CallRaw(opts, calldata) + if err != nil { + return defaultResult, err + } + if unpack == nil { + if len(packedOutput) > 0 { + return defaultResult, errors.New("contract returned data, but no unpack function was given") + } + return defaultResult, nil + } + res, err := unpack(packedOutput) + if err != nil { + return defaultResult, err + } + return res, err +} + +// Transact creates and submits a transaction to a contract with optional input +// data. +// +// Transact is identical to BoundContract.RawTransact, and is provided as a +// package-level method so that interactions with contracts whose bindings were +// generated with the abigen --v2 flag are consistent (they do not require +// calling methods on the BoundContract instance). +func Transact(c *BoundContract, opt *TransactOpts, data []byte) (*types.Transaction, error) { + return c.RawTransact(opt, data) +} + +// DeployContract creates and submits a deployment transaction based on the +// deployer bytecode and optional ABI-encoded constructor input. It returns +// the address and creation transaction of the pending contract, or an error +// if the creation failed. +// +// To initiate the deployment of multiple contracts with one method call, see the +// [LinkAndDeploy] method. +func DeployContract(opts *TransactOpts, bytecode []byte, backend ContractBackend, constructorInput []byte) (common.Address, *types.Transaction, error) { + c := NewBoundContract(common.Address{}, abi.ABI{}, backend, backend, backend) + + tx, err := c.RawCreationTransact(opts, append(bytecode, constructorInput...)) + if err != nil { + return common.Address{}, nil, err + } + return crypto.CreateAddress(opts.From, tx.Nonce()), tx, nil +} + +// DefaultDeployer returns a DeployFn that signs and submits creation transactions +// using the given signer. +// +// The DeployFn returned by DefaultDeployer should be used by LinkAndDeploy in +// almost all cases, unless a custom DeployFn implementation is needed. +func DefaultDeployer(opts *TransactOpts, backend ContractBackend) DeployFn { + return func(input []byte, deployer []byte) (common.Address, *types.Transaction, error) { + addr, tx, err := DeployContract(opts, deployer, backend, input) + if err != nil { + return common.Address{}, nil, err + } + return addr, tx, nil + } +} diff --git a/accounts/abi/bind/v2/lib_test.go b/accounts/abi/bind/v2/lib_test.go new file mode 100644 index 000000000..fc895edad --- /dev/null +++ b/accounts/abi/bind/v2/lib_test.go @@ -0,0 +1,361 @@ +// Copyright 2024 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 . + +package bind_test + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2/internal/contracts/events" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2/internal/contracts/nested_libraries" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2/internal/contracts/solc_errors" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/ethclient/simulated" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" +) + +var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") +var testAddr = crypto.PubkeyToAddress(testKey.PublicKey) + +func testSetup() (*backends.SimulatedBackend, error) { + backend := simulated.NewBackend( + types.GenesisAlloc{ + testAddr: {Balance: big.NewInt(10000000000000000)}, + }, + func(nodeConf *node.Config, ethConf *ethconfig.Config) { + ethConf.Genesis.Difficulty = big.NewInt(0) + }, + ) + + // we should just be able to use the backend directly, instead of using + // this deprecated interface. However, the simulated backend no longer + // implements backends.SimulatedBackend... + bindBackend := backends.SimulatedBackend{ + Backend: backend, + Client: backend.Client(), + } + return &bindBackend, nil +} + +func makeTestDeployer(backend simulated.Client) func(input, deployer []byte) (common.Address, *types.Transaction, error) { + chainId, _ := backend.ChainID(context.Background()) + return bind.DefaultDeployer(bind.NewKeyedTransactor(testKey, chainId), backend) +} + +// test that deploying a contract with library dependencies works, +// verifying by calling method on the deployed contract. +func TestDeploymentLibraries(t *testing.T) { + bindBackend, err := testSetup() + if err != nil { + t.Fatalf("err setting up test: %v", err) + } + defer bindBackend.Backend.Close() + + c := nested_libraries.NewC1() + constructorInput := c.PackConstructor(big.NewInt(42), big.NewInt(1)) + deploymentParams := &bind.DeploymentParams{ + Contracts: []*bind.MetaData{&nested_libraries.C1MetaData}, + Inputs: map[string][]byte{nested_libraries.C1MetaData.ID: constructorInput}, + } + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend.Client)) + if err != nil { + t.Fatalf("err: %+v\n", err) + } + bindBackend.Commit() + + if len(res.Addresses) != 5 { + t.Fatalf("deployment should have generated 5 addresses. got %d", len(res.Addresses)) + } + for _, tx := range res.Txs { + _, err = bind.WaitDeployed(context.Background(), bindBackend, tx.Hash()) + if err != nil { + t.Fatalf("error deploying library: %+v", err) + } + } + + doInput := c.PackDo(big.NewInt(1)) + contractAddr := res.Addresses[nested_libraries.C1MetaData.ID] + callOpts := &bind.CallOpts{From: common.Address{}, Context: context.Background()} + instance := c.Instance(bindBackend, contractAddr) + internalCallCount, err := bind.Call(instance, callOpts, doInput, c.UnpackDo) + if err != nil { + t.Fatalf("err unpacking result: %v", err) + } + if internalCallCount.Uint64() != 6 { + t.Fatalf("expected internal call count of 6. got %d.", internalCallCount.Uint64()) + } +} + +// Same as TestDeployment. However, stagger the deployments with overrides: +// first deploy the library deps and then the contract. +func TestDeploymentWithOverrides(t *testing.T) { + bindBackend, err := testSetup() + if err != nil { + t.Fatalf("err setting up test: %v", err) + } + defer bindBackend.Backend.Close() + + // deploy all the library dependencies of our target contract, but not the target contract itself. + deploymentParams := &bind.DeploymentParams{ + Contracts: nested_libraries.C1MetaData.Deps, + } + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend)) + if err != nil { + t.Fatalf("err: %+v\n", err) + } + bindBackend.Commit() + + if len(res.Addresses) != 4 { + t.Fatalf("deployment should have generated 4 addresses. got %d", len(res.Addresses)) + } + for _, tx := range res.Txs { + _, err = bind.WaitDeployed(context.Background(), bindBackend, tx.Hash()) + if err != nil { + t.Fatalf("error deploying library: %+v", err) + } + } + + c := nested_libraries.NewC1() + constructorInput := c.PackConstructor(big.NewInt(42), big.NewInt(1)) + overrides := res.Addresses + + // deploy the contract + deploymentParams = &bind.DeploymentParams{ + Contracts: []*bind.MetaData{&nested_libraries.C1MetaData}, + Inputs: map[string][]byte{nested_libraries.C1MetaData.ID: constructorInput}, + Overrides: overrides, + } + res, err = bind.LinkAndDeploy(deploymentParams, makeTestDeployer(bindBackend)) + if err != nil { + t.Fatalf("err: %+v\n", err) + } + bindBackend.Commit() + + if len(res.Addresses) != 1 { + t.Fatalf("deployment should have generated 1 address. got %d", len(res.Addresses)) + } + for _, tx := range res.Txs { + _, err = bind.WaitDeployed(context.Background(), bindBackend, tx.Hash()) + if err != nil { + t.Fatalf("error deploying library: %+v", err) + } + } + + // call the deployed contract and make sure it returns the correct result + doInput := c.PackDo(big.NewInt(1)) + instance := c.Instance(bindBackend, res.Addresses[nested_libraries.C1MetaData.ID]) + callOpts := new(bind.CallOpts) + internalCallCount, err := bind.Call(instance, callOpts, doInput, c.UnpackDo) + if err != nil { + t.Fatalf("error calling contract: %v", err) + } + if internalCallCount.Uint64() != 6 { + t.Fatalf("expected internal call count of 6. got %d.", internalCallCount.Uint64()) + } +} + +// returns transaction auth to send a basic transaction from testAddr +func defaultTxAuth() *bind.TransactOpts { + signer := types.LatestSigner(params.AllDevChainProtocolChanges) + opts := &bind.TransactOpts{ + From: testAddr, + Nonce: nil, + Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) + if err != nil { + return nil, err + } + signedTx, err := tx.WithSignature(signer, signature) + if err != nil { + return nil, err + } + return signedTx, nil + }, + Context: context.Background(), + } + return opts +} + +func TestEvents(t *testing.T) { + // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) + backend, err := testSetup() + if err != nil { + t.Fatalf("error setting up testing env: %v", err) + } + deploymentParams := &bind.DeploymentParams{ + Contracts: []*bind.MetaData{&events.CMetaData}, + } + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(backend)) + if err != nil { + t.Fatalf("error deploying contract for testing: %v", err) + } + + backend.Commit() + if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[events.CMetaData.ID].Hash()); err != nil { + t.Fatalf("WaitDeployed failed %v", err) + } + + c := events.NewC() + instance := c.Instance(backend, res.Addresses[events.CMetaData.ID]) + + newCBasic1Ch := make(chan *events.CBasic1) + newCBasic2Ch := make(chan *events.CBasic2) + watchOpts := &bind.WatchOpts{} + sub1, err := bind.WatchEvents(instance, watchOpts, c.UnpackBasic1Event, newCBasic1Ch) + if err != nil { + t.Fatalf("WatchEvents returned error: %v", err) + } + sub2, err := bind.WatchEvents(instance, watchOpts, c.UnpackBasic2Event, newCBasic2Ch) + if err != nil { + t.Fatalf("WatchEvents returned error: %v", err) + } + defer sub1.Unsubscribe() + defer sub2.Unsubscribe() + + packedInput := c.PackEmitMulti() + tx, err := bind.Transact(instance, defaultTxAuth(), packedInput) + if err != nil { + t.Fatalf("failed to send transaction: %v", err) + } + backend.Commit() + if _, err := bind.WaitMined(context.Background(), backend, tx.Hash()); err != nil { + t.Fatalf("error waiting for tx to be mined: %v", err) + } + + timeout := time.NewTimer(2 * time.Second) + e1Count := 0 + e2Count := 0 + for { + select { + case <-newCBasic1Ch: + e1Count++ + case <-newCBasic2Ch: + e2Count++ + case <-timeout.C: + goto done + } + if e1Count == 2 && e2Count == 1 { + break + } + } +done: + if e1Count != 2 { + t.Fatalf("expected event type 1 count to be 2. got %d", e1Count) + } + if e2Count != 1 { + t.Fatalf("expected event type 2 count to be 1. got %d", e2Count) + } + + // now, test that we can filter those same logs after they were included in the chain + + filterOpts := &bind.FilterOpts{ + Start: 0, + Context: context.Background(), + } + it, err := bind.FilterEvents(instance, filterOpts, c.UnpackBasic1Event) + if err != nil { + t.Fatalf("error filtering logs %v\n", err) + } + it2, err := bind.FilterEvents(instance, filterOpts, c.UnpackBasic2Event) + if err != nil { + t.Fatalf("error filtering logs %v\n", err) + } + + e1Count = 0 + e2Count = 0 + for it.Next() { + if err := it.Error(); err != nil { + t.Fatalf("got error while iterating events for e1: %v", err) + } + e1Count++ + } + for it2.Next() { + if err := it2.Error(); err != nil { + t.Fatalf("got error while iterating events for e2: %v", err) + } + e2Count++ + } + if e1Count != 2 { + t.Fatalf("expected e1Count of 2 from filter call. got %d", e1Count) + } + if e2Count != 1 { + t.Fatalf("expected e2Count of 1 from filter call. got %d", e1Count) + } +} + +func TestErrors(t *testing.T) { + // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) + backend, err := testSetup() + if err != nil { + t.Fatalf("error setting up testing env: %v", err) + } + deploymentParams := &bind.DeploymentParams{ + Contracts: []*bind.MetaData{&solc_errors.CMetaData}, + } + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployer(backend)) + if err != nil { + t.Fatalf("error deploying contract for testing: %v", err) + } + + backend.Commit() + if _, err := bind.WaitDeployed(context.Background(), backend, res.Txs[solc_errors.CMetaData.ID].Hash()); err != nil { + t.Fatalf("WaitDeployed failed %v", err) + } + + c := solc_errors.NewC() + instance := c.Instance(backend, res.Addresses[solc_errors.CMetaData.ID]) + packedInput := c.PackFoo() + opts := &bind.CallOpts{From: res.Addresses[solc_errors.CMetaData.ID]} + _, err = bind.Call[struct{}](instance, opts, packedInput, nil) + if err == nil { + t.Fatalf("expected call to fail") + } + raw, hasRevertErrorData := ethclient.RevertErrorData(err) + if !hasRevertErrorData { + t.Fatalf("expected call error to contain revert error data.") + } + rawUnpackedErr, err := c.UnpackError(raw) + if err != nil { + t.Fatalf("expected to unpack error") + } + + unpackedErr, ok := rawUnpackedErr.(*solc_errors.CBadThing) + if !ok { + t.Fatalf("unexpected type for error") + } + if unpackedErr.Arg1.Cmp(big.NewInt(0)) != 0 { + t.Fatalf("bad unpacked error result: expected Arg1 field to be 0. got %s", unpackedErr.Arg1.String()) + } + if unpackedErr.Arg2.Cmp(big.NewInt(1)) != 0 { + t.Fatalf("bad unpacked error result: expected Arg2 field to be 1. got %s", unpackedErr.Arg2.String()) + } + if unpackedErr.Arg3.Cmp(big.NewInt(2)) != 0 { + t.Fatalf("bad unpacked error result: expected Arg3 to be 2. got %s", unpackedErr.Arg3.String()) + } + if unpackedErr.Arg4 != false { + t.Fatalf("bad unpacked error result: expected Arg4 to be false. got true") + } +} diff --git a/accounts/abi/bind/util.go b/accounts/abi/bind/v2/util.go similarity index 60% rename from accounts/abi/bind/util.go rename to accounts/abi/bind/v2/util.go index c83116e9a..438848a75 100644 --- a/accounts/abi/bind/util.go +++ b/accounts/abi/bind/v2/util.go @@ -29,19 +29,13 @@ import ( // WaitMined waits for tx to be mined on the blockchain. // It stops waiting when the context is canceled. -func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) { - return WaitMinedHash(ctx, b, tx.Hash()) -} - -// WaitMinedHash waits for a transaction with the provided hash to be mined on the blockchain. -// It stops waiting when the context is canceled. -func WaitMinedHash(ctx context.Context, b DeployBackend, hash common.Hash) (*types.Receipt, error) { +func WaitMined(ctx context.Context, b DeployBackend, txHash common.Hash) (*types.Receipt, error) { queryTicker := time.NewTicker(time.Second) defer queryTicker.Stop() - logger := log.New("hash", hash) + logger := log.New("hash", txHash) for { - receipt, err := b.TransactionReceipt(ctx, hash) + receipt, err := b.TransactionReceipt(ctx, txHash) if err == nil { return receipt, nil } @@ -61,24 +55,16 @@ func WaitMinedHash(ctx context.Context, b DeployBackend, hash common.Hash) (*typ } } -// WaitDeployed waits for a contract deployment transaction and returns the on-chain -// contract address when it is mined. It stops waiting when ctx is canceled. -func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) (common.Address, error) { - if tx.To() != nil { - return common.Address{}, errors.New("tx is not contract creation") - } - return WaitDeployedHash(ctx, b, tx.Hash()) -} - -// WaitDeployedHash waits for a contract deployment transaction with the provided hash and returns the on-chain -// contract address when it is mined. It stops waiting when ctx is canceled. -func WaitDeployedHash(ctx context.Context, b DeployBackend, hash common.Hash) (common.Address, error) { - receipt, err := WaitMinedHash(ctx, b, hash) +// WaitDeployed waits for a contract deployment transaction with the provided hash and +// returns the on-chain contract address when it is mined. It stops waiting when ctx is +// canceled. +func WaitDeployed(ctx context.Context, b DeployBackend, hash common.Hash) (common.Address, error) { + receipt, err := WaitMined(ctx, b, hash) if err != nil { return common.Address{}, err } if receipt.ContractAddress == (common.Address{}) { - return common.Address{}, errors.New("zero address") + return common.Address{}, ErrNoAddressInReceipt } // Check that code has indeed been deployed at the address. // This matters on pre-Homestead chains: OOG in the constructor diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/v2/util_test.go similarity index 88% rename from accounts/abi/bind/util_test.go rename to accounts/abi/bind/v2/util_test.go index 04d1bb63b..b1b647a7b 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/v2/util_test.go @@ -23,7 +23,7 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -31,8 +31,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - var waitDeployedTests = map[string]struct { code string gas uint64 @@ -77,7 +75,7 @@ func TestWaitDeployed(t *testing.T) { ctx = context.Background() ) go func() { - address, err = bind.WaitDeployed(ctx, backend.Client(), tx) + address, err = bind.WaitDeployed(ctx, backend.Client(), tx.Hash()) close(mined) }() @@ -122,9 +120,8 @@ func TestWaitDeployedCornerCases(t *testing.T) { t.Errorf("failed to send transaction: %q", err) } backend.Commit() - notContractCreation := errors.New("tx is not contract creation") - if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() { - t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err) + if _, err := bind.WaitDeployed(ctx, backend.Client(), tx.Hash()); err != bind.ErrNoAddressInReceipt { + t.Errorf("error mismatch: want %q, got %q, ", bind.ErrNoAddressInReceipt, err) } // Create a transaction that is not mined. @@ -133,7 +130,7 @@ func TestWaitDeployedCornerCases(t *testing.T) { go func() { contextCanceled := errors.New("context canceled") - if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != contextCanceled.Error() { + if _, err := bind.WaitDeployed(ctx, backend.Client(), tx.Hash()); err.Error() != contextCanceled.Error() { t.Errorf("error mismatch: want %q, got %q, ", contextCanceled, err) } }() diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 10343190c..c82358be4 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -24,7 +24,7 @@ import ( "regexp" "strings" - "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/abigen" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common/compiler" "github.com/ethereum/go-ethereum/crypto" @@ -63,14 +63,13 @@ var ( Name: "out", Usage: "Output file for the generated binding (default = stdout)", } - langFlag = &cli.StringFlag{ - Name: "lang", - Usage: "Destination language for the bindings (go)", - Value: "go", - } aliasFlag = &cli.StringFlag{ Name: "alias", - Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2", + Usage: "Comma separated aliases for function and event renaming. If --v2 is set, errors are aliased as well. e.g. original1=alias1, original2=alias2", + } + v2Flag = &cli.BoolFlag{ + Name: "v2", + Usage: "Generates v2 bindings", } ) @@ -86,13 +85,13 @@ func init() { excFlag, pkgFlag, outFlag, - langFlag, aliasFlag, + v2Flag, } - app.Action = abigen + app.Action = generate } -func abigen(c *cli.Context) error { +func generate(c *cli.Context) error { flags.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. if c.String(pkgFlag.Name) == "" { @@ -101,13 +100,6 @@ func abigen(c *cli.Context) error { if c.String(abiFlag.Name) == "" && c.String(jsonFlag.Name) == "" { utils.Fatalf("Either contract ABI source (--abi) or combined-json (--combined-json) are required") } - var lang bind.Lang - switch c.String(langFlag.Name) { - case "go": - lang = bind.LangGo - default: - utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name)) - } // If the entire solidity code was specified, build and bind based on that var ( abis []string @@ -219,7 +211,15 @@ func abigen(c *cli.Context) error { } } // Generate the contract binding - code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs, aliases) + var ( + code string + err error + ) + if c.IsSet(v2Flag.Name) { + code, err = abigen.BindV2(types, abis, bins, c.String(pkgFlag.Name), libs, aliases) + } else { + code, err = abigen.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), libs, aliases) + } if err != nil { utils.Fatalf("Failed to generate ABI binding: %v", err) } From e0f389f06973cd66a5ae8d7e6685f2664437c451 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 17 Mar 2025 16:01:37 +0100 Subject: [PATCH 212/354] core/rawdb: allow for truncation in the freezer (#31362) Here we add the notion of prunable tables for the `TruncateTail` operation in the freezer. TruncateTail for the chain freezer now only truncates the body and receipts tables, leaving headers and hashes as-is. This change also requires changing the validation/repair at startup to allow for tables with different tail. For the header and hash tables, we now require them to start at number zero. --------- Co-authored-by: Felix Lange Co-authored-by: Gary Rong --- core/rawdb/ancient_scheme.go | 42 ++++++++------ core/rawdb/ancient_utils.go | 12 ++-- core/rawdb/chain_freezer.go | 4 +- core/rawdb/freezer.go | 88 ++++++++++++++++++----------- core/rawdb/freezer_batch.go | 2 +- core/rawdb/freezer_memory.go | 28 +++++---- core/rawdb/freezer_memory_test.go | 14 +++-- core/rawdb/freezer_resettable.go | 2 +- core/rawdb/freezer_table.go | 50 ++++++++-------- core/rawdb/freezer_table_test.go | 94 +++++++++++++++---------------- core/rawdb/freezer_test.go | 28 +++++---- ethdb/database.go | 2 + 12 files changed, 209 insertions(+), 157 deletions(-) diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 3e16d5c04..540922b20 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -40,14 +40,22 @@ const ( ChainFreezerDifficultyTable = "diffs" ) -// chainFreezerNoSnappy configures whether compression is disabled for the ancient-tables. -// Hashes and difficulties don't compress well. -var chainFreezerNoSnappy = map[string]bool{ - ChainFreezerHeaderTable: false, - ChainFreezerHashTable: true, - ChainFreezerBodiesTable: false, - ChainFreezerReceiptTable: false, - ChainFreezerDifficultyTable: true, +// chainFreezerTableConfigs configures the settings for tables in the chain freezer. +// Compression is disabled for hashes as they don't compress well. Additionally, +// tail truncation is disabled for the header and hash tables, as these are intended +// to be retained long-term. +var chainFreezerTableConfigs = map[string]freezerTableConfig{ + ChainFreezerHeaderTable: {noSnappy: false, prunable: false}, + ChainFreezerHashTable: {noSnappy: true, prunable: false}, + ChainFreezerBodiesTable: {noSnappy: false, prunable: true}, + ChainFreezerReceiptTable: {noSnappy: false, prunable: true}, + ChainFreezerDifficultyTable: {noSnappy: true, prunable: false}, +} + +// freezerTableConfig contains the settings for a freezer table. +type freezerTableConfig struct { + noSnappy bool // disables item compression + prunable bool // true for tables that can be pruned by TruncateTail } const ( @@ -62,13 +70,13 @@ const ( stateHistoryStorageData = "storage.data" ) -// stateFreezerNoSnappy configures whether compression is disabled for the state freezer. -var stateFreezerNoSnappy = map[string]bool{ - stateHistoryMeta: true, - stateHistoryAccountIndex: false, - stateHistoryStorageIndex: false, - stateHistoryAccountData: false, - stateHistoryStorageData: false, +// stateFreezerTableConfigs configures the settings for tables in the state freezer. +var stateFreezerTableConfigs = map[string]freezerTableConfig{ + stateHistoryMeta: {noSnappy: true, prunable: true}, + stateHistoryAccountIndex: {noSnappy: false, prunable: true}, + stateHistoryStorageIndex: {noSnappy: false, prunable: true}, + stateHistoryAccountData: {noSnappy: false, prunable: true}, + stateHistoryStorageData: {noSnappy: false, prunable: true}, } // The list of identifiers of ancient stores. @@ -89,7 +97,7 @@ var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFre // state freezer. func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) { if ancientDir == "" { - return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil + return NewMemoryFreezer(readOnly, stateFreezerTableConfigs), nil } var name string if verkle { @@ -97,5 +105,5 @@ func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.Reset } else { name = filepath.Join(ancientDir, MerkleStateFreezerName) } - return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) + return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerTableConfigs) } diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 6804d7a91..f4909d86e 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -51,7 +51,7 @@ func (info *freezerInfo) size() common.StorageSize { return total } -func inspect(name string, order map[string]bool, reader ethdb.AncientReader) (freezerInfo, error) { +func inspect(name string, order map[string]freezerTableConfig, reader ethdb.AncientReader) (freezerInfo, error) { info := freezerInfo{name: name} for t := range order { size, err := reader.AncientSize(t) @@ -82,7 +82,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { for _, freezer := range freezers { switch freezer { case ChainFreezerName: - info, err := inspect(ChainFreezerName, chainFreezerNoSnappy, db) + info, err := inspect(ChainFreezerName, chainFreezerTableConfigs, db) if err != nil { return nil, err } @@ -99,7 +99,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { } defer f.Close() - info, err := inspect(freezer, stateFreezerNoSnappy, f) + info, err := inspect(freezer, stateFreezerTableConfigs, f) if err != nil { return nil, err } @@ -119,13 +119,13 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64) error { var ( path string - tables map[string]bool + tables map[string]freezerTableConfig ) switch freezerName { case ChainFreezerName: - path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy + path, tables = resolveChainFreezerDir(ancient), chainFreezerTableConfigs case MerkleStateFreezerName, VerkleStateFreezerName: - path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy + path, tables = filepath.Join(ancient, freezerName), stateFreezerTableConfigs default: return fmt.Errorf("unknown freezer, supported ones: %v", freezers) } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 7a0b819b6..886a06aef 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -62,9 +62,9 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre freezer ethdb.AncientStore ) if datadir == "" { - freezer = NewMemoryFreezer(readonly, chainFreezerNoSnappy) + freezer = NewMemoryFreezer(readonly, chainFreezerTableConfigs) } else { - freezer, err = NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy) + freezer, err = NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerTableConfigs) } if err != nil { return nil, err diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index c5a72eff7..105d3af93 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -78,7 +78,7 @@ type Freezer struct { // // The 'tables' argument defines the data tables. If the value of a map // entry is true, snappy compression is disabled for the table. -func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*Freezer, error) { +func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]freezerTableConfig) (*Freezer, error) { // Create the initial freezer object var ( readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil) @@ -121,8 +121,8 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui } // Create the tables. - for name, disableSnappy := range tables { - table, err := newTable(datadir, name, readMeter, writeMeter, sizeGauge, maxTableSize, disableSnappy, readonly) + for name, config := range tables { + table, err := newTable(datadir, name, readMeter, writeMeter, sizeGauge, maxTableSize, config, readonly) if err != nil { for _, table := range freezer.tables { table.Close() @@ -301,7 +301,8 @@ func (f *Freezer) TruncateHead(items uint64) (uint64, error) { return oitems, nil } -// TruncateTail discards any recent data below the provided threshold number. +// TruncateTail discards all data below the specified threshold. Note that only +// 'prunable' tables will be truncated. func (f *Freezer) TruncateTail(tail uint64) (uint64, error) { if f.readonly { return 0, errReadOnly @@ -314,8 +315,10 @@ func (f *Freezer) TruncateTail(tail uint64) (uint64, error) { return old, nil } for _, table := range f.tables { - if err := table.truncateTail(tail); err != nil { - return 0, err + if table.config.prunable { + if err := table.truncateTail(tail); err != nil { + return 0, err + } } } f.tail.Store(tail) @@ -343,56 +346,77 @@ func (f *Freezer) validate() error { return nil } var ( - head uint64 - tail uint64 - name string + head uint64 + prunedTail *uint64 ) - // Hack to get boundary of any table - for kind, table := range f.tables { + // get any head value + for _, table := range f.tables { head = table.items.Load() - tail = table.itemHidden.Load() - name = kind break } - // Now check every table against those boundaries. for kind, table := range f.tables { + // all tables have to have the same head if head != table.items.Load() { - return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, table.items.Load(), head) + return fmt.Errorf("freezer table %s has a differing head: %d != %d", kind, table.items.Load(), head) } - if tail != table.itemHidden.Load() { - return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, table.itemHidden.Load(), tail) + if !table.config.prunable { + // non-prunable tables have to start at 0 + if table.itemHidden.Load() != 0 { + return fmt.Errorf("non-prunable freezer table '%s' has a non-zero tail: %d", kind, table.itemHidden.Load()) + } + } else { + // prunable tables have to have the same length + if prunedTail == nil { + tmp := table.itemHidden.Load() + prunedTail = &tmp + } + if *prunedTail != table.itemHidden.Load() { + return fmt.Errorf("freezer table %s has differing tail: %d != %d", kind, table.itemHidden.Load(), *prunedTail) + } } } + + if prunedTail == nil { + tmp := uint64(0) + prunedTail = &tmp + } + f.frozen.Store(head) - f.tail.Store(tail) + f.tail.Store(*prunedTail) return nil } // repair truncates all data tables to the same length. func (f *Freezer) repair() error { var ( - head = uint64(math.MaxUint64) - tail = uint64(0) + head = uint64(math.MaxUint64) + prunedTail = uint64(0) ) + // get the minimal head and the maximum tail for _, table := range f.tables { - items := table.items.Load() - if head > items { - head = items - } - hidden := table.itemHidden.Load() - if hidden > tail { - tail = hidden - } + head = min(head, table.items.Load()) + prunedTail = max(prunedTail, table.itemHidden.Load()) } - for _, table := range f.tables { + // apply the pruning + for kind, table := range f.tables { + // all tables need to have the same head if err := table.truncateHead(head); err != nil { return err } - if err := table.truncateTail(tail); err != nil { - return err + if !table.config.prunable { + // non-prunable tables have to start at 0 + if table.itemHidden.Load() != 0 { + panic(fmt.Sprintf("non-prunable freezer table %s has non-zero tail: %v", kind, table.itemHidden.Load())) + } + } else { + // prunable tables have to have the same length + if err := table.truncateTail(prunedTail); err != nil { + return err + } } } + f.frozen.Store(head) - f.tail.Store(tail) + f.tail.Store(prunedTail) return nil } diff --git a/core/rawdb/freezer_batch.go b/core/rawdb/freezer_batch.go index 801d30f73..99b63df4d 100644 --- a/core/rawdb/freezer_batch.go +++ b/core/rawdb/freezer_batch.go @@ -96,7 +96,7 @@ type freezerTableBatch struct { // newBatch creates a new batch for the freezer table. func (t *freezerTable) newBatch() *freezerTableBatch { batch := &freezerTableBatch{t: t} - if !t.noCompression { + if !t.config.noSnappy { batch.sb = new(snappyBuffer) } batch.reset() diff --git a/core/rawdb/freezer_memory.go b/core/rawdb/freezer_memory.go index 2d3dbb07d..4274546de 100644 --- a/core/rawdb/freezer_memory.go +++ b/core/rawdb/freezer_memory.go @@ -30,17 +30,19 @@ import ( // memoryTable is used to store a list of sequential items in memory. type memoryTable struct { - name string // Table name items uint64 // Number of stored items in the table, including the deleted ones offset uint64 // Number of deleted items from the table data [][]byte // List of rlp-encoded items, sort in order size uint64 // Total memory size occupied by the table lock sync.RWMutex + + name string + config freezerTableConfig } // newMemoryTable initializes the memory table. -func newMemoryTable(name string) *memoryTable { - return &memoryTable{name: name} +func newMemoryTable(name string, config freezerTableConfig) *memoryTable { + return &memoryTable{name: name, config: config} } // has returns an indicator whether the specified data exists. @@ -218,10 +220,10 @@ type MemoryFreezer struct { } // NewMemoryFreezer initializes an in-memory freezer instance. -func NewMemoryFreezer(readonly bool, tableName map[string]bool) *MemoryFreezer { +func NewMemoryFreezer(readonly bool, tableName map[string]freezerTableConfig) *MemoryFreezer { tables := make(map[string]*memoryTable) - for name := range tableName { - tables[name] = newMemoryTable(name) + for name, cfg := range tableName { + tables[name] = newMemoryTable(name, cfg) } return &MemoryFreezer{ writeBatch: newMemoryBatch(), @@ -368,7 +370,9 @@ func (f *MemoryFreezer) TruncateHead(items uint64) (uint64, error) { return old, nil } -// TruncateTail discards any recent data below the provided threshold number. +// TruncateTail discards all data below the provided threshold number. +// Note this will only truncate 'prunable' tables. Block headers and canonical +// hashes cannot be truncated at this time. func (f *MemoryFreezer) TruncateTail(tail uint64) (uint64, error) { f.lock.Lock() defer f.lock.Unlock() @@ -381,8 +385,10 @@ func (f *MemoryFreezer) TruncateTail(tail uint64) (uint64, error) { return old, nil } for _, table := range f.tables { - if err := table.truncateTail(tail); err != nil { - return 0, err + if table.config.prunable { + if err := table.truncateTail(tail); err != nil { + return 0, err + } } } f.tail = tail @@ -412,8 +418,8 @@ func (f *MemoryFreezer) Reset() error { defer f.lock.Unlock() tables := make(map[string]*memoryTable) - for name := range f.tables { - tables[name] = newMemoryTable(name) + for name, table := range f.tables { + tables[name] = newMemoryTable(name, table.config) } f.tables = tables f.items, f.tail = 0, 0 diff --git a/core/rawdb/freezer_memory_test.go b/core/rawdb/freezer_memory_test.go index e71de0f62..4bd31d802 100644 --- a/core/rawdb/freezer_memory_test.go +++ b/core/rawdb/freezer_memory_test.go @@ -25,16 +25,22 @@ import ( func TestMemoryFreezer(t *testing.T) { ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore { - tables := make(map[string]bool) + tables := make(map[string]freezerTableConfig) for _, kind := range kinds { - tables[kind] = true + tables[kind] = freezerTableConfig{ + noSnappy: true, + prunable: true, + } } return NewMemoryFreezer(false, tables) }) ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore { - tables := make(map[string]bool) + tables := make(map[string]freezerTableConfig) for _, kind := range kinds { - tables[kind] = true + tables[kind] = freezerTableConfig{ + noSnappy: true, + prunable: true, + } } return NewMemoryFreezer(false, tables) }) diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 7c77a06ef..2e64e6074 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -49,7 +49,7 @@ type resettableFreezer struct { // // The reset function will delete directory atomically and re-create the // freezer from scratch. -func newResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*resettableFreezer, error) { +func newResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]freezerTableConfig) (*resettableFreezer, error) { if err := cleanup(datadir); err != nil { return nil, err } diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index e553df702..aec24b207 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -100,11 +100,11 @@ type freezerTable struct { // should never be lower than itemOffset. itemHidden atomic.Uint64 - noCompression bool // if true, disables snappy compression. Note: does not work retroactively - readonly bool - maxFileSize uint32 // Max file size for data-files - name string - path string + config freezerTableConfig // if true, disables snappy compression. Note: does not work retroactively + readonly bool + maxFileSize uint32 // Max file size for data-files + name string + path string head *os.File // File descriptor for the data head of the table index *os.File // File descriptor for the indexEntry file of the table @@ -125,20 +125,20 @@ type freezerTable struct { } // newFreezerTable opens the given path as a freezer table. -func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) { - return newTable(path, name, metrics.NewInactiveMeter(), metrics.NewInactiveMeter(), metrics.NewGauge(), freezerTableSize, disableSnappy, readonly) +func newFreezerTable(path, name string, config freezerTableConfig, readonly bool) (*freezerTable, error) { + return newTable(path, name, metrics.NewInactiveMeter(), metrics.NewInactiveMeter(), metrics.NewGauge(), freezerTableSize, config, readonly) } // newTable opens a freezer table, creating the data and index files if they are // non-existent. Both files are truncated to the shortest common length to ensure // they don't go out of sync. -func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, sizeGauge *metrics.Gauge, maxFilesize uint32, noCompression, readonly bool) (*freezerTable, error) { +func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, sizeGauge *metrics.Gauge, maxFilesize uint32, config freezerTableConfig, readonly bool) (*freezerTable, error) { // Ensure the containing directory exists and open the indexEntry file if err := os.MkdirAll(path, 0755); err != nil { return nil, err } var idxName string - if noCompression { + if config.noSnappy { idxName = fmt.Sprintf("%s.ridx", name) // raw index file } else { idxName = fmt.Sprintf("%s.cidx", name) // compressed index file @@ -176,19 +176,19 @@ func newTable(path string, name string, readMeter, writeMeter *metrics.Meter, si } // Create the table and repair any past inconsistency tab := &freezerTable{ - index: index, - metadata: metadata, - lastSync: time.Now(), - files: make(map[uint32]*os.File), - readMeter: readMeter, - writeMeter: writeMeter, - sizeGauge: sizeGauge, - name: name, - path: path, - logger: log.New("database", path, "table", name), - noCompression: noCompression, - readonly: readonly, - maxFileSize: maxFilesize, + index: index, + metadata: metadata, + lastSync: time.Now(), + files: make(map[uint32]*os.File), + readMeter: readMeter, + writeMeter: writeMeter, + sizeGauge: sizeGauge, + name: name, + path: path, + logger: log.New("database", path, "table", name), + config: config, + readonly: readonly, + maxFileSize: maxFilesize, } if err := tab.repair(); err != nil { tab.Close() @@ -871,7 +871,7 @@ func (t *freezerTable) openFile(num uint32, opener func(string) (*os.File, error var exist bool if f, exist = t.files[num]; !exist { var name string - if t.noCompression { + if t.config.noSnappy { name = fmt.Sprintf("%s.%04d.rdat", t.name, num) } else { name = fmt.Sprintf("%s.%04d.cdat", t.name, num) @@ -987,13 +987,13 @@ func (t *freezerTable) RetrieveItems(start, count, maxBytes uint64) ([][]byte, e item := diskData[offset : offset+diskSize] offset += diskSize decompressedSize := diskSize - if !t.noCompression { + if !t.config.noSnappy { decompressedSize, _ = snappy.DecodedLen(item) } if i > 0 && maxBytes != 0 && uint64(outputSize+decompressedSize) > maxBytes { break } - if !t.noCompression { + if !t.config.noSnappy { data, err := snappy.Decode(nil, item) if err != nil { return nil, err diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 9a72af6cc..96edac7e4 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -39,7 +39,7 @@ func TestFreezerBasics(t *testing.T) { // set cutoff at 50 bytes f, err := newTable(os.TempDir(), fmt.Sprintf("unittest-%d", rand.Uint64()), - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, false) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -84,7 +84,7 @@ func TestFreezerBasicsClosing(t *testing.T) { f *freezerTable err error ) - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -98,7 +98,7 @@ func TestFreezerBasicsClosing(t *testing.T) { require.NoError(t, batch.commit()) f.Close() - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -115,7 +115,7 @@ func TestFreezerBasicsClosing(t *testing.T) { t.Fatalf("test %d, got \n%x != \n%x", y, got, exp) } f.Close() - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -130,7 +130,7 @@ func TestFreezerRepairDanglingHead(t *testing.T) { // Fill table { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -159,7 +159,7 @@ func TestFreezerRepairDanglingHead(t *testing.T) { // Now open it again { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -182,7 +182,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) { // Fill a table and close it { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -208,7 +208,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) { // Now open it again { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -231,7 +231,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) { // And if we open it, we should now be able to read all of them (new values) { - f, _ := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, _ := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) for y := 1; y < 255; y++ { exp := getChunk(15, ^y) got, err := f.Retrieve(uint64(y)) @@ -253,7 +253,7 @@ func TestSnappyDetection(t *testing.T) { // Open with snappy { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -264,7 +264,7 @@ func TestSnappyDetection(t *testing.T) { // Open with snappy { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -277,7 +277,7 @@ func TestSnappyDetection(t *testing.T) { // Open without snappy { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, false, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: false}, false) if err != nil { t.Fatal(err) } @@ -308,7 +308,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { // Fill a table and close it { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -344,7 +344,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { // 45, 45, 15 // with 3+3+1 items { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -365,7 +365,7 @@ func TestFreezerTruncate(t *testing.T) { // Fill table { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -381,7 +381,7 @@ func TestFreezerTruncate(t *testing.T) { // Reopen, truncate { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -406,7 +406,7 @@ func TestFreezerRepairFirstFile(t *testing.T) { // Fill table { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -439,7 +439,7 @@ func TestFreezerRepairFirstFile(t *testing.T) { // Reopen { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -474,7 +474,7 @@ func TestFreezerReadAndTruncate(t *testing.T) { // Fill table { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -490,7 +490,7 @@ func TestFreezerReadAndTruncate(t *testing.T) { // Reopen and read all files { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -521,7 +521,7 @@ func TestFreezerOffset(t *testing.T) { fname := fmt.Sprintf("offset-%d", rand.Uint64()) // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -545,7 +545,7 @@ func TestFreezerOffset(t *testing.T) { f.Close() // Now open again - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -597,7 +597,7 @@ func TestFreezerOffset(t *testing.T) { // Check that existing items have been moved to index 1M. { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -631,7 +631,7 @@ func TestTruncateTail(t *testing.T) { fname := fmt.Sprintf("truncate-tail-%d", rand.Uint64()) // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -682,7 +682,7 @@ func TestTruncateTail(t *testing.T) { // Reopen the table, the deletion information should be persisted as well f.Close() - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -716,7 +716,7 @@ func TestTruncateTail(t *testing.T) { // Reopen the table, the above testing should still pass f.Close() - f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err = newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -772,7 +772,7 @@ func TestTruncateHead(t *testing.T) { fname := fmt.Sprintf("truncate-head-blow-tail-%d", rand.Uint64()) // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -883,7 +883,7 @@ func TestSequentialRead(t *testing.T) { rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge() fname := fmt.Sprintf("batchread-%d", rand.Uint64()) { // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -893,7 +893,7 @@ func TestSequentialRead(t *testing.T) { f.Close() } { // Open it, iterate, verify iteration - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -914,7 +914,7 @@ func TestSequentialRead(t *testing.T) { } { // Open it, iterate, verify byte limit. The byte limit is less than item // size, so each lookup should only return one item - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 40, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -943,7 +943,7 @@ func TestSequentialReadByteLimit(t *testing.T) { rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge() fname := fmt.Sprintf("batchread-2-%d", rand.Uint64()) { // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -965,7 +965,7 @@ func TestSequentialReadByteLimit(t *testing.T) { {100, 109, 10}, } { { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -993,7 +993,7 @@ func TestSequentialReadNoByteLimit(t *testing.T) { rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge() fname := fmt.Sprintf("batchread-3-%d", rand.Uint64()) { // Fill table - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1011,7 +1011,7 @@ func TestSequentialReadNoByteLimit(t *testing.T) { {31, 30}, } { { - f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, true, false) + f, err := newTable(os.TempDir(), fname, rm, wm, sg, 100, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1038,7 +1038,7 @@ func TestFreezerReadonly(t *testing.T) { // Case 1: Check it fails on non-existent file. _, err := newTable(tmpdir, fmt.Sprintf("readonlytest-%d", rand.Uint64()), - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, true) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, true) if err == nil { t.Fatal("readonly table instantiation should fail for non-existent table") } @@ -1053,7 +1053,7 @@ func TestFreezerReadonly(t *testing.T) { idxFile.Write(make([]byte, 17)) idxFile.Close() _, err = newTable(tmpdir, fname, - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, true) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, true) if err == nil { t.Errorf("readonly table instantiation should fail for invalid index size") } @@ -1063,7 +1063,7 @@ func TestFreezerReadonly(t *testing.T) { // again in readonly triggers an error. fname = fmt.Sprintf("readonlytest-%d", rand.Uint64()) f, err := newTable(tmpdir, fname, - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, false) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatalf("failed to instantiate table: %v", err) } @@ -1076,7 +1076,7 @@ func TestFreezerReadonly(t *testing.T) { t.Fatal(err) } _, err = newTable(tmpdir, fname, - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, true) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, true) if err == nil { t.Errorf("readonly table instantiation should fail for corrupt table file") } @@ -1085,7 +1085,7 @@ func TestFreezerReadonly(t *testing.T) { // Should be successful. fname = fmt.Sprintf("readonlytest-%d", rand.Uint64()) f, err = newTable(tmpdir, fname, - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, false) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatalf("failed to instantiate table: %v\n", err) } @@ -1094,7 +1094,7 @@ func TestFreezerReadonly(t *testing.T) { t.Fatal(err) } f, err = newTable(tmpdir, fname, - metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, true) + metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, true) if err != nil { t.Fatal(err) } @@ -1234,7 +1234,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { func runRandTest(rt randTest) bool { fname := fmt.Sprintf("randtest-%d", rand.Uint64()) - f, err := newTable(os.TempDir(), fname, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, false) + f, err := newTable(os.TempDir(), fname, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, false) if err != nil { panic("failed to initialize table") } @@ -1243,7 +1243,7 @@ func runRandTest(rt randTest) bool { switch step.op { case opReload: f.Close() - f, err = newTable(os.TempDir(), fname, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, true, false) + f, err = newTable(os.TempDir(), fname, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 50, freezerTableConfig{noSnappy: true}, false) if err != nil { rt[i].err = fmt.Errorf("failed to reload table %v", err) } @@ -1381,7 +1381,7 @@ func TestIndexValidation(t *testing.T) { } for _, c := range cases { fn := fmt.Sprintf("t-%d", rand.Uint64()) - f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 10*dataSize, true, false) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 10*dataSize, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1392,7 +1392,7 @@ func TestIndexValidation(t *testing.T) { f.Close() // reopen the table, corruption should be truncated - f, err = newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 100, true, false) + f, err = newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), 100, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1422,7 +1422,7 @@ func TestFlushOffsetTracking(t *testing.T) { fileSize = 100 ) fn := fmt.Sprintf("t-%d", rand.Uint64()) - f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1533,7 +1533,7 @@ func TestTailTruncationCrash(t *testing.T) { fileSize = 100 ) fn := fmt.Sprintf("t-%d", rand.Uint64()) - f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + f, err := newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } @@ -1563,7 +1563,7 @@ func TestTailTruncationCrash(t *testing.T) { // the offset f.metadata.setFlushOffset(31*indexEntrySize, true) - f, err = newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, true, false) + f, err = newTable(os.TempDir(), fn, metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge(), fileSize, freezerTableConfig{noSnappy: true}, false) if err != nil { t.Fatal(err) } diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 7d82ea305..150734d3a 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -31,7 +31,7 @@ import ( "github.com/stretchr/testify/require" ) -var freezerTestTableDef = map[string]bool{"test": true} +var freezerTestTableDef = map[string]freezerTableConfig{"test": {noSnappy: true}} func TestFreezerModify(t *testing.T) { t.Parallel() @@ -47,7 +47,7 @@ func TestFreezerModify(t *testing.T) { valuesRLP = append(valuesRLP, iv) } - tables := map[string]bool{"raw": true, "rlp": false} + tables := map[string]freezerTableConfig{"raw": {noSnappy: true}, "rlp": {noSnappy: false}} f, _ := newFreezerForTesting(t, tables) defer f.Close() @@ -111,7 +111,7 @@ func TestFreezerModifyRollback(t *testing.T) { f.Close() // Reopen and check that the rolled-back data doesn't reappear. - tables := map[string]bool{"test": true} + tables := map[string]freezerTableConfig{"test": {noSnappy: true}} f2, err := NewFreezer(dir, "", false, 2049, tables) if err != nil { t.Fatalf("can't reopen freezer after failed ModifyAncients: %v", err) @@ -249,7 +249,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) { } func TestFreezerReadonlyValidate(t *testing.T) { - tables := map[string]bool{"a": true, "b": true} + tables := map[string]freezerTableConfig{"a": {noSnappy: true}, "b": {noSnappy: true}} dir := t.TempDir() // Open non-readonly freezer and fill individual tables // with different amount of data. @@ -285,7 +285,7 @@ func TestFreezerReadonlyValidate(t *testing.T) { func TestFreezerConcurrentReadonly(t *testing.T) { t.Parallel() - tables := map[string]bool{"a": true} + tables := map[string]freezerTableConfig{"a": {noSnappy: true}} dir := t.TempDir() f, err := NewFreezer(dir, "", false, 2049, tables) @@ -333,7 +333,7 @@ func TestFreezerConcurrentReadonly(t *testing.T) { } } -func newFreezerForTesting(t *testing.T, tables map[string]bool) (*Freezer, string) { +func newFreezerForTesting(t *testing.T, tables map[string]freezerTableConfig) (*Freezer, string) { t.Helper() dir := t.TempDir() @@ -379,7 +379,7 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) { func TestFreezerCloseSync(t *testing.T) { t.Parallel() - f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true}) + f, _ := newFreezerForTesting(t, map[string]freezerTableConfig{"a": {noSnappy: true}, "b": {noSnappy: true}}) defer f.Close() // Now, close and sync. This mimics the behaviour if the node is shut down, @@ -401,17 +401,23 @@ func TestFreezerCloseSync(t *testing.T) { func TestFreezerSuite(t *testing.T) { ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore { - tables := make(map[string]bool) + tables := make(map[string]freezerTableConfig) for _, kind := range kinds { - tables[kind] = true + tables[kind] = freezerTableConfig{ + noSnappy: true, + prunable: true, + } } f, _ := newFreezerForTesting(t, tables) return f }) ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore { - tables := make(map[string]bool) + tables := make(map[string]freezerTableConfig) for _, kind := range kinds { - tables[kind] = true + tables[kind] = freezerTableConfig{ + noSnappy: true, + prunable: true, + } } f, _ := newResettableFreezer(t.TempDir(), "", false, 2048, tables) return f diff --git a/ethdb/database.go b/ethdb/database.go index 323f8f5d6..b1577512f 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -128,6 +128,8 @@ type AncientWriter interface { // is item_n(start from 0). The deleted items may not be removed from the ancient store // immediately, but only when the accumulated deleted data reach the threshold then // will be removed all together. + // + // Note that data marked as non-prunable will still be retained and remain accessible. TruncateTail(n uint64) (uint64, error) // Sync flushes all in-memory ancient store data to disk. From 13db5be35884126a80dc7f1bc7aa4b7bf6e4701e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 17 Mar 2025 18:59:04 +0100 Subject: [PATCH 213/354] eth/filters: implement log filter using new log index (#31080) This PR is #2 of a 3-part series that implements the new log index intended to replace core/bloombits. Based on https://github.com/ethereum/go-ethereum/pull/31079 Replaces https://github.com/ethereum/go-ethereum/pull/30370 This part replaces the old bloombits based log search logic in `eth/filters` to use the new `core/filtermaps` logic. FilterMaps data structure explanation: https://gist.github.com/zsfelfoldi/a60795f9da7ae6422f28c7a34e02a07e Log index generator code overview: https://gist.github.com/zsfelfoldi/97105dff0b1a4f5ed557924a24b9b9e7 Search pattern matcher code overview: https://gist.github.com/zsfelfoldi/5981735641c956afb18065e84f8aff34 Note that the possibility of a tree hashing scheme and remote proof protocol are mentioned in the documents above but they are not exactly specified yet. These specs are WIP and will be finalized after the local log indexer/filter code is finalized and merged. --------- Co-authored-by: Felix Lange --- cmd/geth/chaincmd.go | 3 + cmd/geth/main.go | 3 + cmd/utils/flags.go | 26 ++ common/range.go | 115 +++++ common/range_test.go | 36 ++ core/filtermaps/checkpoints_holesky.json | 37 +- core/filtermaps/checkpoints_mainnet.json | 516 ++++++++++++----------- core/filtermaps/checkpoints_sepolia.json | 127 +++--- core/filtermaps/filtermaps.go | 116 ++--- core/filtermaps/indexer.go | 144 ++++--- core/filtermaps/indexer_test.go | 52 ++- core/filtermaps/map_renderer.go | 270 ++++++------ core/filtermaps/matcher.go | 287 ++++++------- core/filtermaps/matcher_backend.go | 56 +-- core/rawdb/accessors_indexes.go | 21 +- eth/api_backend.go | 5 + eth/backend.go | 74 ++++ eth/ethconfig/config.go | 8 +- eth/filters/filter.go | 384 +++++++++++------ eth/filters/filter_system.go | 5 +- eth/filters/filter_system_test.go | 88 ++-- eth/filters/filter_test.go | 196 ++++++++- internal/ethapi/api_test.go | 6 +- internal/ethapi/backend.go | 6 +- internal/ethapi/transaction_args_test.go | 10 +- 25 files changed, 1585 insertions(+), 1006 deletions(-) create mode 100644 common/range.go create mode 100644 common/range_test.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c30927d9f..95239bd64 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -100,6 +100,9 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.VMTraceFlag, utils.VMTraceJsonConfigFlag, utils.TransactionHistoryFlag, + utils.LogHistoryFlag, + utils.LogNoHistoryFlag, + utils.LogExportCheckpointsFlag, utils.StateHistoryFlag, }, utils.DatabaseFlags), Description: ` diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1f7c59539..e52765bf3 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -96,6 +96,9 @@ var ( utils.TxLookupLimitFlag, // deprecated utils.TransactionHistoryFlag, utils.ChainHistoryFlag, + utils.LogHistoryFlag, + utils.LogNoHistoryFlag, + utils.LogExportCheckpointsFlag, utils.StateHistoryFlag, utils.LightServeFlag, // deprecated utils.LightIngressFlag, // deprecated diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fe1caa60f..01e1f6485 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -279,6 +279,23 @@ var ( Value: ethconfig.Defaults.HistoryMode.String(), Category: flags.StateCategory, } + LogHistoryFlag = &cli.Uint64Flag{ + Name: "history.logs", + Usage: "Number of recent blocks to maintain log search index for (default = about one year, 0 = entire chain)", + Value: ethconfig.Defaults.LogHistory, + Category: flags.StateCategory, + } + LogNoHistoryFlag = &cli.BoolFlag{ + Name: "history.logs.disable", + Usage: "Do not maintain log search index", + Category: flags.StateCategory, + } + LogExportCheckpointsFlag = &cli.StringFlag{ + Name: "history.logs.export", + Usage: "Export checkpoints to file in go source file format", + Category: flags.StateCategory, + Value: "", + } // Beacon client light sync settings BeaconApiFlag = &cli.StringSliceFlag{ Name: "beacon.api", @@ -1786,6 +1803,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.StateScheme = rawdb.HashScheme log.Warn("Forcing hash state-scheme for archive mode") } + if ctx.IsSet(LogHistoryFlag.Name) { + cfg.LogHistory = ctx.Uint64(LogHistoryFlag.Name) + } + if ctx.IsSet(LogNoHistoryFlag.Name) { + cfg.LogNoHistory = true + } + if ctx.IsSet(LogExportCheckpointsFlag.Name) { + cfg.LogExportCheckpoints = ctx.String(LogExportCheckpointsFlag.Name) + } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } diff --git a/common/range.go b/common/range.go new file mode 100644 index 000000000..c3a26ea7f --- /dev/null +++ b/common/range.go @@ -0,0 +1,115 @@ +// Copyright 2025 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 . + +package common + +import ( + "iter" +) + +// Range represents a range of integers. +type Range[T uint32 | uint64] struct { + first, afterLast T +} + +// NewRange creates a new range based of first element and number of elements. +func NewRange[T uint32 | uint64](first, count T) Range[T] { + return Range[T]{first, first + count} +} + +// First returns the first element of the range. +func (r Range[T]) First() T { + return r.first +} + +// Last returns the last element of the range. This panics for empty ranges. +func (r Range[T]) Last() T { + if r.first == r.afterLast { + panic("last item of zero length range is not allowed") + } + return r.afterLast - 1 +} + +// AfterLast returns the first element after the range. This allows obtaining +// information about the end part of zero length ranges. +func (r Range[T]) AfterLast() T { + return r.afterLast +} + +// Count returns the number of elements in the range. +func (r Range[T]) Count() T { + return r.afterLast - r.first +} + +// IsEmpty returns true if the range is empty. +func (r Range[T]) IsEmpty() bool { + return r.first == r.afterLast +} + +// Includes returns true if the given element is inside the range. +func (r Range[T]) Includes(v T) bool { + return v >= r.first && v < r.afterLast +} + +// SetFirst updates the first element of the list. +func (r *Range[T]) SetFirst(v T) { + r.first = v + if r.afterLast < r.first { + r.afterLast = r.first + } +} + +// SetAfterLast updates the end of the range by specifying the first element +// after the range. This allows setting zero length ranges. +func (r *Range[T]) SetAfterLast(v T) { + r.afterLast = v + if r.afterLast < r.first { + r.first = r.afterLast + } +} + +// SetLast updates last element of the range. +func (r *Range[T]) SetLast(v T) { + r.SetAfterLast(v + 1) +} + +// Intersection returns the intersection of two ranges. +func (r Range[T]) Intersection(q Range[T]) Range[T] { + i := Range[T]{first: max(r.first, q.first), afterLast: min(r.afterLast, q.afterLast)} + if i.first > i.afterLast { + return Range[T]{} + } + return i +} + +// Union returns the union of two ranges. Panics for gapped ranges. +func (r Range[T]) Union(q Range[T]) Range[T] { + if max(r.first, q.first) > min(r.afterLast, q.afterLast) { + panic("cannot create union; gap between ranges") + } + return Range[T]{first: min(r.first, q.first), afterLast: max(r.afterLast, q.afterLast)} +} + +// Iter iterates all integers in the range. +func (r Range[T]) Iter() iter.Seq[T] { + return func(yield func(T) bool) { + for i := r.first; i < r.afterLast; i++ { + if !yield(i) { + break + } + } + } +} diff --git a/common/range_test.go b/common/range_test.go new file mode 100644 index 000000000..878b6d66c --- /dev/null +++ b/common/range_test.go @@ -0,0 +1,36 @@ +// Copyright 2025 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 . + +package common + +import ( + "slices" + "testing" +) + +func TestRangeIter(t *testing.T) { + r := NewRange[uint32](1, 7) + values := slices.Collect(r.Iter()) + if !slices.Equal(values, []uint32{1, 2, 3, 4, 5, 6, 7}) { + t.Fatalf("wrong iter values: %v", values) + } + + empty := NewRange[uint32](1, 0) + values = slices.Collect(empty.Iter()) + if !slices.Equal(values, []uint32{}) { + t.Fatalf("wrong iter values: %v", values) + } +} diff --git a/core/filtermaps/checkpoints_holesky.json b/core/filtermaps/checkpoints_holesky.json index c30856db4..b8f6be9ca 100644 --- a/core/filtermaps/checkpoints_holesky.json +++ b/core/filtermaps/checkpoints_holesky.json @@ -1,20 +1,21 @@ [ -{"blockNumber": 814411, "blockId": "0xf763e96fc3920359c5f706803024b78e83796a3a8563bb5a83c3ddd7cbfde287", "firstIndex": 67107637}, -{"blockNumber": 914278, "blockId": "0x0678cf8d53c0d6d27896df657d98cc73bc63ca468b6295068003938ef9b0f927", "firstIndex": 134217671}, -{"blockNumber": 1048874, "blockId": "0x3620c3d52a40ff4d9fc58c3104cfa2f327f55592caf6a2394c207a5e00b4f740", "firstIndex": 201326382}, -{"blockNumber": 1144441, "blockId": "0x438fb42850f5a0d8e1666de598a4d0106b62da0f7448c62fe029b8cbad35d08d", "firstIndex": 268435440}, -{"blockNumber": 1230411, "blockId": "0xf0ee07e60a93910723b259473a253dd9cf674e8b78c4f153b32ad7032efffeeb", "firstIndex": 335543079}, -{"blockNumber": 1309112, "blockId": "0xc1646e5ef4b4343880a85b1a4111e3321d609a1225e9cebbe10d1c7abf99e58d", "firstIndex": 402653100}, -{"blockNumber": 1380522, "blockId": "0x1617cae91989d97ac6335c4217aa6cc7f7f4c2837e20b3b5211d98d6f9e97e44", "firstIndex": 469761917}, -{"blockNumber": 1476962, "blockId": "0xd978455d2618d093dfc685d7f43f61be6dae0fa8a9cb915ae459aa6e0a5525f0", "firstIndex": 536870773}, -{"blockNumber": 1533518, "blockId": "0xe7d39d71bd9d5f1f3157c35e0329531a7950a19e3042407e38948b89b5384f78", "firstIndex": 603979664}, -{"blockNumber": 1613787, "blockId": "0xa793168d135c075732a618ec367faaed5f359ffa81898c73cb4ec54ec2caa696", "firstIndex": 671088003}, -{"blockNumber": 1719099, "blockId": "0xc4394c71a8a24efe64c5ff2afcdd1594f3708524e6084aa7dadd862bd704ab03", "firstIndex": 738196914}, -{"blockNumber": 1973165, "blockId": "0xee3a9e959a437c707a3036736ec8d42a9261ac6100972c26f65eedcde315a81d", "firstIndex": 805306333}, -{"blockNumber": 2274844, "blockId": "0x76e2d33653ed9282c63ad09d721e1f2e29064aa9c26202e20fc4cc73e8dfe5f6", "firstIndex": 872415141}, -{"blockNumber": 2530503, "blockId": "0x59f4e45345f8b8f848be5004fe75c4a28f651864256c3aa9b2da63369432b718", "firstIndex": 939523693}, -{"blockNumber": 2781903, "blockId": "0xc981e91c6fb69c5e8146ead738fcfc561831f11d7786d39c7fa533966fc37675", "firstIndex": 1006632906}, -{"blockNumber": 3101713, "blockId": "0xc7baa577c91d8439e3fc79002d2113d07ca54a4724bf2f1f5af937b7ba8e1f32", "firstIndex": 1073741382}, -{"blockNumber": 3221770, "blockId": "0xa6b8240b7883fcc71aa5001b5ba66c889975c5217e14c16edebdd6f6e23a9424", "firstIndex": 1140850360} +{"blockNumber": 814410, "blockId": "0x6c38f0d4ff2c23ae187f581cebb0963c0ec2dbf051b289de1582c369c98a3244", "firstIndex": 67107349}, +{"blockNumber": 914268, "blockId": "0xeff161573a11eb6e2ab930674a5245b2c5ffc5e9e63093503344ec6fa60578a3", "firstIndex": 134216064}, +{"blockNumber": 1048866, "blockId": "0xebd3b95415dad9ab7f2b1d25e48c791e299063c09427bbde54217029c3e215ad", "firstIndex": 201325914}, +{"blockNumber": 1144433, "blockId": "0x0c895438ef12a2c835b4372c209e40a499ba2b18ed0e658846813784de391392", "firstIndex": 268434935}, +{"blockNumber": 1230406, "blockId": "0xd3512e7241efc9853e46b1ad565403d302f62457b6dd84917c31ff375fabf487", "firstIndex": 335544096}, +{"blockNumber": 1309104, "blockId": "0xcf108c6e002e7a5657bf7587adde03edf5f20d03e95b66a194eb8080daaf4f97", "firstIndex": 402653143}, +{"blockNumber": 1380499, "blockId": "0x984b0f8b6bf06f1240bbca8c1df9bef3880bedafd5b5c2a55cbc2f64c9efb974", "firstIndex": 469759822}, +{"blockNumber": 1476950, "blockId": "0x8323b528bb8d80a96b172de92452be0f45078a9ca311cb4be6675f089e25a426", "firstIndex": 536870335}, +{"blockNumber": 1533506, "blockId": "0x737dc416070aa3b522a0c2ab813a70c1820f062c718f27597394f309f0004106", "firstIndex": 603979618}, +{"blockNumber": 1613764, "blockId": "0x9d6a5a505afdda86b1ebcc2b10cb687a1f89c2e2b74315945a3ddc6a0b3c9cd6", "firstIndex": 671088253}, +{"blockNumber": 1719073, "blockId": "0x17bf6a51d9c55a908c3e9e652f80b2aa464b049c697abf3bd5a537e461aff0b9", "firstIndex": 738197366}, +{"blockNumber": 1973133, "blockId": "0x14b288d70e688de3334d09283670301aacfed21c193da8a56fd63767f8177705", "firstIndex": 805305624}, +{"blockNumber": 2274761, "blockId": "0xf02790b273b04219e001d2fcc93e8e47708cb228364e96ad754bc8050d08a9aa", "firstIndex": 872414871}, +{"blockNumber": 2530470, "blockId": "0x157ea98b1a7e66dd3f045da8e25219800671f9a000211d3d94006efd33d89a80", "firstIndex": 939523234}, +{"blockNumber": 2781706, "blockId": "0xa723663a584e280700d2302eba03d1b3b6549333db70c6152576d33e2911f594", "firstIndex": 1006632936}, +{"blockNumber": 3101669, "blockId": "0xa6e66a18fed64d33178c7088f273c404be597662c34f6e6884cf2e24f3ea4ace", "firstIndex": 1073741353}, +{"blockNumber": 3221725, "blockId": "0xe771f897dece48b1583cc1d1d10de8015da57407eb1fdf239fdbe46eaab85143", "firstIndex": 1140850137}, +{"blockNumber": 3357164, "blockId": "0x6252d0aa54c79623b0680069c88d7b5c47983f0d5c4845b6c811b8d9b5e8ff3c", "firstIndex": 1207959453}, +{"blockNumber": 3447019, "blockId": "0xeb7d585e1e063f3cc05ed399fbf6c2df63c271f62f030acb804e9fb1e74b6dc1", "firstIndex": 1275067542} ] - diff --git a/core/filtermaps/checkpoints_mainnet.json b/core/filtermaps/checkpoints_mainnet.json index d2b031a47..ca30280e0 100644 --- a/core/filtermaps/checkpoints_mainnet.json +++ b/core/filtermaps/checkpoints_mainnet.json @@ -1,256 +1,264 @@ [ -{"blockNumber": 4166218, "blockId": "0xdd767e0426256179125551e8e40f33565a96d1c94076c7746fa79d767ed4ad65", "firstIndex": 67108680}, -{"blockNumber": 4514014, "blockId": "0x33a0879bdabea4a7a3f2b424388cbcbf2fbd519bddadf13752a259049c78e95d", "firstIndex": 134217343}, -{"blockNumber": 4817415, "blockId": "0x4f0e8c7dd04fbe0985b9394575b19f13ea66a2a628fa5b08178ce4b138c6db80", "firstIndex": 201326352}, -{"blockNumber": 5087733, "blockId": "0xc84cd5e9cda999c919803c7a53a23bb77a18827fbde401d3463f1e9e52536424", "firstIndex": 268435343}, -{"blockNumber": 5306107, "blockId": "0x13f028b5fc055d23f55a92a2eeecfbcfbda8a08e4cd519ce451ba2e70428f5f9", "firstIndex": 335544094}, -{"blockNumber": 5509918, "blockId": "0x1ed770a58a7b4d4a828b7bb44c8820a674d562b23a6a0139981abe4c489d4dad", "firstIndex": 402652853}, -{"blockNumber": 5670390, "blockId": "0x3923ee6a62e6cc5132afdadf1851ae4e73148e6fbe0a8319cafd2a120c98efa3", "firstIndex": 469761897}, -{"blockNumber": 5826139, "blockId": "0xe61bc6ef03c333805f26319e1688f82553f98aa5e902b200e0621a3371b69050", "firstIndex": 536870853}, -{"blockNumber": 5953029, "blockId": "0x43d710b1b7243b848400975048ccefdfaba091c692c7f01c619d988886cc160f", "firstIndex": 603979580}, -{"blockNumber": 6102846, "blockId": "0xa100b2018f6545cc689656b4b846677b138955b7efd30e850cd14c246430ba18", "firstIndex": 671088291}, -{"blockNumber": 6276718, "blockId": "0xb832ac448b06c104ba50faefd58b0b94d53c0fba5cb268086adad4db99c2f35f", "firstIndex": 738197399}, -{"blockNumber": 6448696, "blockId": "0x48e8ae6f729ad6c76b6cf632bd52a6df7886ed55be09d43c5004fcc1463e533b", "firstIndex": 805305988}, -{"blockNumber": 6655974, "blockId": "0xac395971a6ffc30f807848f68b97b2834f8ea13478a7615860b6a69e3d0823ca", "firstIndex": 872415033}, -{"blockNumber": 6873949, "blockId": "0xc522ddb1113b1e9a87b2bdcb11ce78756beba6454a890122f121a032b5769354", "firstIndex": 939523784}, -{"blockNumber": 7080953, "blockId": "0x3606de577d80120d1edbb64bad7fa6795e788bae342866a98cc58ce2f7575045", "firstIndex": 1006632796}, -{"blockNumber": 7267002, "blockId": "0xad770882a69d216e955e34fef84851e56c0de82deacd6187a7a41f6170cd6c6d", "firstIndex": 1073741045}, -{"blockNumber": 7466708, "blockId": "0x17a48817b3a65aba333a5b56f3ff2e86fbcc19e184b046a5305a5182fdd8eb8a", "firstIndex": 1140850680}, -{"blockNumber": 7661807, "blockId": "0xa74731ee775fbd3f4d9313c68562737dd7c8d2c9eb968791d8abe167e16ddc96", "firstIndex": 1207959112}, -{"blockNumber": 7834556, "blockId": "0xe4b4812448075508cb05a0e3257f91b49509dc78cd963676a633864db6e78956", "firstIndex": 1275068095}, -{"blockNumber": 7990068, "blockId": "0x07bd4ca38abb4584a6209e04035646aa545ebbb6c948d438d4c25bfd9cb205fa", "firstIndex": 1342176620}, -{"blockNumber": 8143032, "blockId": "0x0e3149e9637290b044ee693b8fcb66e23d22db3ad0bdda32962138ba18e59f3f", "firstIndex": 1409285949}, -{"blockNumber": 8297660, "blockId": "0x34cd24f80247f7dfaf316b2e637f4b62f72ecc90703014fb25cb98ad044fc2c0", "firstIndex": 1476394911}, -{"blockNumber": 8465137, "blockId": "0x4452fa296498248d7f10c9dc6ec1e4ae7503aa07f491e6d38b21aea5d2c658a8", "firstIndex": 1543503744}, -{"blockNumber": 8655820, "blockId": "0x7bdb9008b30be420f7152cc294ac6e5328eed5b4abd954a34105de3da24f3cc6", "firstIndex": 1610612619}, -{"blockNumber": 8807187, "blockId": "0xde03e3bfddc722c019f0b59bc55efabcd5ab68c6711f4c08d0390a56f396590d", "firstIndex": 1677721589}, -{"blockNumber": 8911171, "blockId": "0xe44f342de74ab05a2a994f8841bdf88f720b9dc260177ba4030d0f7077901324", "firstIndex": 1744830310}, -{"blockNumber": 8960320, "blockId": "0x79764f9ff6e0fe4848eda1805687872021076e4e603112861af84181395ac559", "firstIndex": 1811938893}, -{"blockNumber": 9085994, "blockId": "0x24a101d1c8a63367a0953d10dc79c3b587a93bd7fd382084708adefce0b8363f", "firstIndex": 1879047965}, -{"blockNumber": 9230924, "blockId": "0xb176a98d3acd855cbb75265fb6be955a8d51abc771e021e13275d5b3ecb07eeb", "firstIndex": 1946156668}, -{"blockNumber": 9390535, "blockId": "0x640f5e2d511a5141878d57ae7a619f19b72a2bd3ef019cf0a22d74d93d9acf07", "firstIndex": 2013265733}, -{"blockNumber": 9515674, "blockId": "0xff4a7b6b21aeaeb6e1a75ecd22b1f34c058a0ce1477ce90a8ce78165fd1d0941", "firstIndex": 2080374553}, -{"blockNumber": 9659426, "blockId": "0xc351455249343b41e9171e183612b68c3c895271c62bd2c53d9e3ab1aa865aa1", "firstIndex": 2147483567}, -{"blockNumber": 9794018, "blockId": "0xde98035b4b7f9449c256239b65c7ff2c0330de44dee190106d0a96fb6f683238", "firstIndex": 2214592213}, -{"blockNumber": 9923840, "blockId": "0x881da313a1e2b6fab58a1d6fa65b5dacfdc9d68a3112a647104955b5233f84e3", "firstIndex": 2281701302}, -{"blockNumber": 10042435, "blockId": "0x451f6459640a6f54e2a535cc3a49cfc469861da3ddc101840ab3aef9e17fa424", "firstIndex": 2348810174}, -{"blockNumber": 10168883, "blockId": "0x5d16ff5adf0df1e4dc810da60af37399ef733be7870f21112b8c2cfff4995dd9", "firstIndex": 2415918783}, -{"blockNumber": 10289554, "blockId": "0x85d5690f15a787c43b9a49e8dd6e324f0b3e0c9796d07c0cfb128e5c168f5488", "firstIndex": 2483027930}, -{"blockNumber": 10386676, "blockId": "0x20f675ea72db448024a8a0b8e3ec180cac37a5910575bc32f8d9f5cdfe3c2649", "firstIndex": 2550136212}, -{"blockNumber": 10479675, "blockId": "0x014abb07acf2330cc78800ca1f564928f2daccca4b389bf5c59f4b840d843ec0", "firstIndex": 2617245218}, -{"blockNumber": 10562661, "blockId": "0xd437607a3f81ce8b7c605e167ce5e52bf8a3e02cdc646997bd0ccc57a50ad7d1", "firstIndex": 2684354520}, -{"blockNumber": 10641508, "blockId": "0x2e8ab6470c29f90ac23dcfc58310f0208f5d0e752a0c7982a77a223eca104082", "firstIndex": 2751462730}, -{"blockNumber": 10717156, "blockId": "0x8820447b6429dd12be603c1c130be532e9db065bb4bc6b2a9d4551794d63789a", "firstIndex": 2818571831}, -{"blockNumber": 10784549, "blockId": "0xc557daab80a7cdc963d62aa881faf3ab1baceff8e027046bcd203e432e0983b3", "firstIndex": 2885680800}, -{"blockNumber": 10848651, "blockId": "0xede1b0de5db6685a6f589096ceb8fccb08d3ff60e8b00a93caa4a775b48e07fc", "firstIndex": 2952789740}, -{"blockNumber": 10909166, "blockId": "0x989db675899d13323006a4d6174557e3c5501c672afd60d8bd902fc98d37e92e", "firstIndex": 3019897599}, -{"blockNumber": 10972902, "blockId": "0x5484050cc2c7d774bc5cd6af1c2ef8c19d1de12dabe25867c9b365924ea10434", "firstIndex": 3087007422}, -{"blockNumber": 11036597, "blockId": "0x1e3686e19056587c385262d5b0a07b3ec04e804c2d59e9aaca1e5876e78f69ae", "firstIndex": 3154116231}, -{"blockNumber": 11102520, "blockId": "0x339cf302fe813cce3bb9318b860dfa8be7f688413f38a6ea1987a1b84d742b4b", "firstIndex": 3221224863}, -{"blockNumber": 11168162, "blockId": "0xc0fa21ea090627610bcac4732dff702633f310cabafc42bc500d3d4805198fe0", "firstIndex": 3288334273}, -{"blockNumber": 11233707, "blockId": "0x491c37a479b8cf22eaa3654ae34c5ddc4627df8c58ca8a6979159e1710428576", "firstIndex": 3355442691}, -{"blockNumber": 11300526, "blockId": "0xb7366d2a24df99002cffe0c9a00959c93ef0dcfc3fd17389e2020bf5caa788eb", "firstIndex": 3422551480}, -{"blockNumber": 11367621, "blockId": "0xce53df5080c5b5238bb7717dfbfd88c2f574cfbb3d91f92b57171a00e9776cd2", "firstIndex": 3489660710}, -{"blockNumber": 11431881, "blockId": "0x2a08ff9c4f6fd152166213d902f0870822429f01d5f90e384ac54a3eac0ceb3a", "firstIndex": 3556768626}, -{"blockNumber": 11497107, "blockId": "0x1f99c6b65f2b1cb06ed1786c6a0274ff1b9eacab6cb729fcd386f10ebbd88123", "firstIndex": 3623878389}, -{"blockNumber": 11560104, "blockId": "0xebe6924817bbdfe52af49667da1376bae5a2994b375d4b996e8ff2683744e37a", "firstIndex": 3690986640}, -{"blockNumber": 11625129, "blockId": "0xbe6eee325329ee2fe632d8576864c29dd1c79bab891dc0a22d5b2ac87618d26e", "firstIndex": 3758095773}, -{"blockNumber": 11690397, "blockId": "0xc28bf55f858ddf5b82d1ceb3b5258b90a9ca34df8863a1c652c4d359f5748fdf", "firstIndex": 3825204492}, -{"blockNumber": 11755087, "blockId": "0x0c10cde6ce1bbe24dc57347fe4aaebc17b7d8e8d7d97e3db573133477f494740", "firstIndex": 3892314051}, -{"blockNumber": 11819674, "blockId": "0x36b694a1776c94e4c6ae4a410931b2086de47a83e437517040e3290ce9afff67", "firstIndex": 3959422445}, -{"blockNumber": 11883358, "blockId": "0x21f447aca9ddf94ed71df9fa3648a12acc2ba603f89f24c4784936864c41945f", "firstIndex": 4026531743}, -{"blockNumber": 11948524, "blockId": "0x71a52b6cce80d3a552b0daa18beb952facf81a89bc7ca769d08ac297f317507a", "firstIndex": 4093640009}, -{"blockNumber": 12013168, "blockId": "0x9a7fb369b8d8cd0edd0d890d636096f20c63abb7eb5798ad1e578cac599e3db8", "firstIndex": 4160748475}, -{"blockNumber": 12078711, "blockId": "0x5de09329413b0c2f58d926f225197552a335ba3d5544d7bdb45e7574f78c9b8d", "firstIndex": 4227858275}, -{"blockNumber": 12143640, "blockId": "0xbeafc0e1e0586f5a95f00f2a796d7df122c79c187aa2d917129297f24b8306bd", "firstIndex": 4294967145}, -{"blockNumber": 12208005, "blockId": "0x052487095cdd4a604808e6c14e30fb68b3fa546d35585b315f287219d38ef77c", "firstIndex": 4362075289}, -{"blockNumber": 12272465, "blockId": "0x82c8a50413bd67a0d6f53b085adcd9ae8c25ecc07ed766fa80297a8dcae63b29", "firstIndex": 4429184610}, -{"blockNumber": 12329418, "blockId": "0x294c147e48d32c217ff3f27a3c8c989f15eee57a911408ec4c28d4f13a36bb3b", "firstIndex": 4496292968}, -{"blockNumber": 12382388, "blockId": "0x8c2555965ff735690d2d94ececc48df4700e079c7b21b8e601a30d4e99bc4b5b", "firstIndex": 4563401809}, -{"blockNumber": 12437052, "blockId": "0x2e38362031f36a0f3394da619dcc03be03c19700594cbd1df84c2c476a87de63", "firstIndex": 4630511012}, -{"blockNumber": 12490026, "blockId": "0x122749c02a55c9c2a1e69068f54b6c1d25419eb743e3553aba91acf1daeadc35", "firstIndex": 4697619920}, -{"blockNumber": 12541747, "blockId": "0xfb9f12aa2902da798ac05fab425434f8c7ce98050d67d416dbb32f98c21f66f7", "firstIndex": 4764728267}, -{"blockNumber": 12597413, "blockId": "0x9a7a399c2904ac8d0fec580550525e7e1a73d8f65f739bf7c05d86e389d0d3f7", "firstIndex": 4831837757}, -{"blockNumber": 12651950, "blockId": "0xb78dcb572cdafb9c4e2f3863ef518a3b2df0cd4f76faa26a423b2ca0c1cde734", "firstIndex": 4898946491}, -{"blockNumber": 12706472, "blockId": "0xfd21f41ec6b0c39287d7d48c134d1212a261c53d65db99739994b003150bbad1", "firstIndex": 4966054796}, -{"blockNumber": 12762929, "blockId": "0xc94d994bc40b2ae7dc23cf2b92cc01e84915f090bb57c0d9a67584bd564d3916", "firstIndex": 5033164307}, -{"blockNumber": 12816689, "blockId": "0x7770c72f22cbf6ccf7ab85d203088f7ede89632cf0042c690102f926a90bd09d", "firstIndex": 5100273412}, -{"blockNumber": 12872408, "blockId": "0x2e008b8c952d828875d777f7912f472af96ffc977f2ceae884006682cab6b8ed", "firstIndex": 5167381625}, -{"blockNumber": 12929718, "blockId": "0x85eb0ed3c5910c6a01b65ef0a5b76c59c2cdb5094e6e27eb87c751d77bcc2c88", "firstIndex": 5234491305}, -{"blockNumber": 12988757, "blockId": "0xdf12045bea73af18d4e71f8be8e334160f78b85f96a3535a4056409d8b61355a", "firstIndex": 5301600237}, -{"blockNumber": 13049172, "blockId": "0xf07608d97a101cd9a95fee9d9062a15bcb333263e555f8cfa31da037e0468f30", "firstIndex": 5368709080}, -{"blockNumber": 13108936, "blockId": "0x42739341db582d2f39b91ec9e8cc758777ca3f6ff9f25cd98883619fd5f026a7", "firstIndex": 5435817013}, -{"blockNumber": 13175495, "blockId": "0x564f25eacb229350b7c648b5828169e7a0344ae62e866206828e2cfad8947f10", "firstIndex": 5502926476}, -{"blockNumber": 13237721, "blockId": "0x0973425abec0fa6319701b46e07c2373b0580e3adbed6900aad27d5bf26dcb95", "firstIndex": 5570035419}, -{"blockNumber": 13298771, "blockId": "0xf3a16fec5be808c9f7782fb578dc8cef7f8e2110f7289bd03c0cc13977dd1518", "firstIndex": 5637143840}, -{"blockNumber": 13361281, "blockId": "0x3c0b6364201ca9221b61af3de27a3a87e111870b8c7efc43a6d8496e98c68690", "firstIndex": 5704253046}, -{"blockNumber": 13421819, "blockId": "0x2f472e57997b95558b99e3e5e7e0e8d4dbf8b71c081aac6536c9ff5925dac2ce", "firstIndex": 5771361231}, -{"blockNumber": 13480620, "blockId": "0xc4d689e87464a0c83c661c8e3a0614c370631de857f7e385b161dfe8bacd3e71", "firstIndex": 5838469468}, -{"blockNumber": 13535793, "blockId": "0xe7674bacc8edce9fb3efd59b92c97da48fe7ace1de314b4a67d7d032fc3bb680", "firstIndex": 5905578026}, -{"blockNumber": 13590588, "blockId": "0x6a3e86bdce7dd7d8792e1af9156edd8c3ffee7c20fed97001f58a9a2699f6594", "firstIndex": 5972687757}, -{"blockNumber": 13646707, "blockId": "0xab404a5d3709cf571b04e9493f37116eeb5dd2bc9dc10c48387c1e0199013d69", "firstIndex": 6039797165}, -{"blockNumber": 13703025, "blockId": "0x20e2fde15b8fe56f5dd7ab0f324c552038167ed44864bf3978e531ae68d6d138", "firstIndex": 6106905803}, -{"blockNumber": 13761024, "blockId": "0x2ae49275e13e780f1d29aea8507b2a708ff7bfe977efac93e050273b8b3a8164", "firstIndex": 6174015107}, -{"blockNumber": 13819468, "blockId": "0xb9d19cb31dedb1128b11cad9ffd6e58c70fe7ba65ba68f1ac63668ac5160ad85", "firstIndex": 6241124350}, -{"blockNumber": 13877932, "blockId": "0x80b1ff0bb069a8479360a15eaa84ba30da02cfacadc564837f4b1c90478addb8", "firstIndex": 6308232256}, -{"blockNumber": 13935384, "blockId": "0xe1f5469a559a6114dd469af61b118b9d9551a69bbd49a4e88f2a2d724830c871", "firstIndex": 6375341632}, -{"blockNumber": 13994042, "blockId": "0x25188fb75f2328c870ade7c38ef42ff5fddef9c4e364eebe4c5d8d9cc3ecabab", "firstIndex": 6442449799}, -{"blockNumber": 14051123, "blockId": "0xf4ef2bce9ee9222bdcf6b3a0c204676d9345e211e10c983e523930274e041ef1", "firstIndex": 6509559107}, -{"blockNumber": 14109189, "blockId": "0x80b730c28f75d8cb5ec2fb736341cd87cb4ecb2c9c614e0a4ecc0f9812675d50", "firstIndex": 6576667347}, -{"blockNumber": 14166822, "blockId": "0xf662a24b91684fa8ac462b31071f406de8d6183dba46d30d690f4407bc6af36f", "firstIndex": 6643777079}, -{"blockNumber": 14222488, "blockId": "0x7333e324c96b12f11a38d1fc2ddb4860e018b90f5dc10f3dbe19f7679bb95535", "firstIndex": 6710885890}, -{"blockNumber": 14277180, "blockId": "0x4373c1000e8e10179657689e2f0e42f88bd1601ecb4a5d83970d10287f6654cc", "firstIndex": 6777994595}, -{"blockNumber": 14331080, "blockId": "0x9c708a750a3f284ec0ee950110b36fd488cb1ec24cd0c2ea72c19551ec5c42a5", "firstIndex": 6845103719}, -{"blockNumber": 14384243, "blockId": "0x34ce7503b76335aa18dec880b0cefd388a29e0fcff6f2e1ddda8fb8c0ac1daf0", "firstIndex": 6912212376}, -{"blockNumber": 14437670, "blockId": "0x79842efd3e406b41f51935fe2e6ad20a7dd5a9db2280ebd7f602ed93da1e3c24", "firstIndex": 6979320543}, -{"blockNumber": 14489204, "blockId": "0xcd12addf0afdc229e9fe3bd0a34677a3826c5e78d4baf715f8ed36b736d6627a", "firstIndex": 7046430591}, -{"blockNumber": 14541688, "blockId": "0x55f617abf208a73fc467e8cb5feead586b671dbb0f6281570b3c44b8eabb2b9e", "firstIndex": 7113538755}, -{"blockNumber": 14594551, "blockId": "0xc7211bf772e93c8c2f945fcb6098b47c3455604cb8b94a505cb5cb720914c369", "firstIndex": 7180646025}, -{"blockNumber": 14645065, "blockId": "0x6d5b0326f4b22e2b0196986a514f23ec6e9a62f70f53300a22b21ff661a6ef7e", "firstIndex": 7247756883}, -{"blockNumber": 14695926, "blockId": "0x0a77272250e43b4bb46c02eb76944881a3c6b00a21bb9086a8229199bd62d97a", "firstIndex": 7314865843}, -{"blockNumber": 14746330, "blockId": "0xd677fdbaf8efb1bfdc138ac6b2bd5d0e890a29acb1f52f40169181ad517b0d31", "firstIndex": 7381974956}, -{"blockNumber": 14798546, "blockId": "0xbb277e8623acd2ce2340cf32f6c0ddab70fd95d862287f68a3c37250a70619cd", "firstIndex": 7449082890}, -{"blockNumber": 14848230, "blockId": "0x587b39f11bdaa2091291c7c3947e88df2e91e7997f2375dfd43b6e310a538582", "firstIndex": 7516192636}, -{"blockNumber": 14897646, "blockId": "0xf5b5c9d0c024ca0c0f0c6171871f609687f4ccb064ededbd61176cf23a9011e8", "firstIndex": 7583299602}, -{"blockNumber": 14950782, "blockId": "0x50549486afaf92a4c3520012b325e914ef77a82e4d6530a71f9b1cca31bfae18", "firstIndex": 7650409868}, -{"blockNumber": 15004101, "blockId": "0x7edac55dea3ee4308db60b9bc0524836226fe301e085b3ce39105bd145ba7fc3", "firstIndex": 7717517503}, -{"blockNumber": 15056903, "blockId": "0xb4cfd02d435718598179cdba3f5c11eb8653fe97ec8d89c60673e3e07b8dfc94", "firstIndex": 7784627997}, -{"blockNumber": 15108302, "blockId": "0x53c77a7de4515e9e93467a76f04cc401834bcdd64e9dfa03cf6d2844a6930293", "firstIndex": 7851736988}, -{"blockNumber": 15159526, "blockId": "0x1a31ad84b423254d7ff24e7eca54048ed8cc13cec5eb7289bf3f98ed4de9f724", "firstIndex": 7918844431}, -{"blockNumber": 15211013, "blockId": "0xe5d491e1d6cc5322454143b915c106be1bf28114a41b054ba5e5cfe0abecafba", "firstIndex": 7985953942}, -{"blockNumber": 15264389, "blockId": "0xd9939bb9e58e95d2672c1148b4ec5730204527d3f3fc98ca03a67dc85cf3d710", "firstIndex": 8053063187}, -{"blockNumber": 15315862, "blockId": "0x7254f99c4bb05235d5b437984c9132164e33182d4ce11a3847999da5c28b4092", "firstIndex": 8120172147}, -{"blockNumber": 15364726, "blockId": "0x11b57547579d9009679e327f57e308fe86856391805bc3c86e7b39daae890f52", "firstIndex": 8187281042}, -{"blockNumber": 15412886, "blockId": "0xbe3602b1dbef9015a3ec7968ac7652edf4424934b6bf7b713b99d8556f1d9444", "firstIndex": 8254390023}, -{"blockNumber": 15462792, "blockId": "0x3348ca4e14ac8d3c6ac6df676deaf3e3b5e0a11b599f73bd9739b74ebd693efe", "firstIndex": 8321499024}, -{"blockNumber": 15509914, "blockId": "0xbc98fd6b71438d5a169f9373172fea799fa3d22a8e6fe648d35e1070f2261113", "firstIndex": 8388606521}, -{"blockNumber": 15558748, "blockId": "0x5fa2cf499276ae74a5b8618990e71ed11a063619afe25c01b46e6252eba14c19", "firstIndex": 8455716577}, -{"blockNumber": 15604217, "blockId": "0x78a608e13d2eb3c5fed81a19b829ede88071cf01ea9ff58112a7472435f97c30", "firstIndex": 8522825668}, -{"blockNumber": 15651869, "blockId": "0xd465d861d925d1475440782ff16c2b3361ba3c8e169d7cc90eb8dfc0f31b0aac", "firstIndex": 8589934080}, -{"blockNumber": 15700968, "blockId": "0x71e3def131271e02c06ca945d14a995703a48faac1334a9e2e2321edd0b504d0", "firstIndex": 8657043390}, -{"blockNumber": 15762986, "blockId": "0x9b1b51dca2eae29162ca66968a77b45175f134b44aea3defadcb924f83e0b944", "firstIndex": 8724151376}, -{"blockNumber": 15814455, "blockId": "0x3c04a509cb6304d3df4bef57e0119d9e615ab737ec0b4a7deada6e5f57d9f873", "firstIndex": 8791260562}, -{"blockNumber": 15865639, "blockId": "0x9e9e26148c774518ecf362c0e7c65a5c1b054a8a3e4e36036c70e273fac6147c", "firstIndex": 8858368894}, -{"blockNumber": 15920564, "blockId": "0x9efe1d4dbfd9aa891ac0cffd3e1422a27ba2ea4add211b6900a2242cdb0f0ca0", "firstIndex": 8925477950}, -{"blockNumber": 15974371, "blockId": "0xc63ccef7bc35a0b431a411f99fe581b322d00cfc6422d078696808a5658a32ac", "firstIndex": 8992587107}, -{"blockNumber": 16032913, "blockId": "0x3e60957224964669a8646914e3166553b9f4256d5be160b17995d838af3ef137", "firstIndex": 9059696632}, -{"blockNumber": 16091057, "blockId": "0x12b346047bb49063ab6d9e737775924cf05c52114202ddb1a2bdaf9caabbfe0c", "firstIndex": 9126804912}, -{"blockNumber": 16150977, "blockId": "0x49318a32ff0ce979c4061c1c34db2a94fb06e7669c93742b75aff14a134fa598", "firstIndex": 9193913896}, -{"blockNumber": 16207432, "blockId": "0xf7870865edf81be4389a0be01468da959de703df0d431610814d16ed480176e4", "firstIndex": 9261019778}, -{"blockNumber": 16262582, "blockId": "0x25818e0f4d54af6c44ef7b23add34409a47de3ab1c905889478f3ec8ad173ec3", "firstIndex": 9328131320}, -{"blockNumber": 16319695, "blockId": "0x25de4b1c18cc503f5d12b4fa9072d33a11fa503a3dbeb9ab3d016b57c1e5cd4d", "firstIndex": 9395240790}, -{"blockNumber": 16373605, "blockId": "0x3794a5e0d2aa10baf1e6a5ec623d6089fdd39799eff633017d8df5144526939f", "firstIndex": 9462349509}, -{"blockNumber": 16423494, "blockId": "0xe0217d947ba3865dfc9288e0c890b0996457bb9d18467bd125e86bbb0052b57f", "firstIndex": 9529458033}, -{"blockNumber": 16474853, "blockId": "0xd454f033d190f22f9e56f0209ea1eeb3b6257805d5d88650d2759eb4d24821b7", "firstIndex": 9596567055}, -{"blockNumber": 16525689, "blockId": "0x8a23cbbf3e258e13f5a1ada434366796cb4a3e5b1062455582fb2bc3ab991541", "firstIndex": 9663674943}, -{"blockNumber": 16574203, "blockId": "0xc1a5b7d26e8222bd2d56ef4108f75d69f7c116707d348950834e00962241a4f8", "firstIndex": 9730785112}, -{"blockNumber": 16622622, "blockId": "0x3ddb3ef7a4309bd788258fb0d62613c89a0b4de715f4e12f6017a194d19d6481", "firstIndex": 9797893665}, -{"blockNumber": 16672585, "blockId": "0x8aa5e9f72b261f9e2a9eb768483d1bbd84d3a88fdb1346f6a9a7f262fd28ba41", "firstIndex": 9865002893}, -{"blockNumber": 16720124, "blockId": "0x2128f8baf264166e37554d5c31a06de58d9ccfb663117358251da548a23a060f", "firstIndex": 9932111275}, -{"blockNumber": 16769162, "blockId": "0x6b3e849482d3222032740ad6b8f98e24636c82682a6a3572b1ef76dfebc66821", "firstIndex": 9999217824}, -{"blockNumber": 16818311, "blockId": "0xe45f57381978a2bfc85bd20af1c41e2b630412642ac4f606b477f05f030ef5d9", "firstIndex": 10066328668}, -{"blockNumber": 16869531, "blockId": "0xa154555266d24dc1f4885af5fafcf8cab3de788998cf69e1d28f56aa13a40c43", "firstIndex": 10133437302}, -{"blockNumber": 16921611, "blockId": "0xf1f829b4ab5eec6e243916dd530993fa11eef5510fd730e8d09ead6b380355a1", "firstIndex": 10200547185}, -{"blockNumber": 16974870, "blockId": "0x1a33202b95926ae4cb8e6e99d8d150f3c50d817b3a316452bdf428c971dabde5", "firstIndex": 10267655914}, -{"blockNumber": 17031277, "blockId": "0x706c9dd0dc81e7ac29d2ea0f826e6b8a1dcb5adb1b904ff6e43260729c9fd0a7", "firstIndex": 10334764934}, -{"blockNumber": 17086330, "blockId": "0x085a80cafe96b520105b9a1f8e7a2bbc9474da24da7e6344ca7c4d32db822f92", "firstIndex": 10401871892}, -{"blockNumber": 17141311, "blockId": "0x33ec6513dfa515bc5f6356476b4eb075a8064181d6aaf6aa1a1e18887e342f74", "firstIndex": 10468982364}, -{"blockNumber": 17190907, "blockId": "0x6f41273d3bf30d3347e7eb68872a49b3ac947f314543478be7a28a55e5c41a3c", "firstIndex": 10536090817}, -{"blockNumber": 17237199, "blockId": "0x9a87a14a128c0345a366940f821a14f16719de628658ac0628e410a72d723e90", "firstIndex": 10603200178}, -{"blockNumber": 17287181, "blockId": "0x9c6e78adcf562ac63c103e3e5a02f025023079aca79bdd6ef18f7bd2a6271c29", "firstIndex": 10670309183}, -{"blockNumber": 17338652, "blockId": "0x1b747da97b2397a293602af57514dab4ca1010bb6c601ff05cb2012dd1124ebb", "firstIndex": 10737418023}, -{"blockNumber": 17389337, "blockId": "0xbc3c0ca1e5989605b9b59c94b418562eb17ccbce30e45ac8531cf0b3867a6b2c", "firstIndex": 10804522857}, -{"blockNumber": 17442261, "blockId": "0x1ec341be1cbd09f559bfa3d3e39a341d8e21052eeb7880931d43d086651733b7", "firstIndex": 10871635535}, -{"blockNumber": 17497787, "blockId": "0x6069880d486f2548599df1e14e12752d3eb9bc99843a98cd6631c22be1b58554", "firstIndex": 10938744657}, -{"blockNumber": 17554322, "blockId": "0x69b2564bc00b1f310f6b416912869d7530d7864bf7d70d55c7ace554f129b989", "firstIndex": 11005852829}, -{"blockNumber": 17608492, "blockId": "0x7d590653d5fa52c0d3ee453a77d2088504f57adcef35cd57c567afb554608457", "firstIndex": 11072961972}, -{"blockNumber": 17664272, "blockId": "0xdc16159d3500cdc7410873102f41fc55de2a8a41e3779c4b70e6224a541e2b9e", "firstIndex": 11140070967}, -{"blockNumber": 17715101, "blockId": "0x655e33c4e81182464ea0b0e1fdbc53ce53902431db5107326b816091a4564652", "firstIndex": 11207179487}, -{"blockNumber": 17764042, "blockId": "0x54439184f31cd83ba06b48b6dbfdd744ae7246355be1327b44744058711d05c0", "firstIndex": 11274287303}, -{"blockNumber": 17814383, "blockId": "0xfb453bc951360c76fb09bb1b9a3e39d23ececa0adb93368cc3f41f0457845089", "firstIndex": 11341397984}, -{"blockNumber": 17864648, "blockId": "0x32a68823ef4ec0cbab2fe50c97e3f462b575e8b117da40d00c710b4c66ee1d6d", "firstIndex": 11408505657}, -{"blockNumber": 17913366, "blockId": "0x04b944aab8a4ff91b77c2191817cf051766100c227616a3746af53407e740124", "firstIndex": 11475614351}, -{"blockNumber": 17961690, "blockId": "0x08bee7cc0b764106ca01dd5370b617879487ffb423688c96e948dce125990f45", "firstIndex": 11542723488}, -{"blockNumber": 18011048, "blockId": "0x94c39d3a64f3e9a91b1d98554cd29e1390e30fa61cfa4e909c503eee2fd9f165", "firstIndex": 11609833142}, -{"blockNumber": 18061209, "blockId": "0x2ee9ade68955c030488c8a30537bdf948355f7dd5ae64942b5bfce1be6650e19", "firstIndex": 11676941316}, -{"blockNumber": 18111692, "blockId": "0xd6c4fd0c1cc20ed5e7960bb5043e9e5e9c66a4d2ec5709ac9797fff678435640", "firstIndex": 11744050346}, -{"blockNumber": 18166212, "blockId": "0x3262588c2ef79a3b3f6a3db6435202d22f5667cd48c136b0797404901525c9ff", "firstIndex": 11811159686}, -{"blockNumber": 18218743, "blockId": "0x935bd9a4164ff7ecd09a37b916ce5bf78487bd19377b5b17be153e39318aee74", "firstIndex": 11878268593}, -{"blockNumber": 18271236, "blockId": "0xe58ebb821f27e3665898f390802a3d129d217b3a3ee36d890a85cf22a0a8aa33", "firstIndex": 11945376750}, -{"blockNumber": 18323007, "blockId": "0x3997a841468efa1bc614bfc3de4502274901b04b428f87a1f3086dfd78cda1eb", "firstIndex": 12012485748}, -{"blockNumber": 18372443, "blockId": "0xc44a13a5d02e8dc39f355de5e21ce7bb311ce7f4d9114ff480dce235a169e416", "firstIndex": 12079595370}, -{"blockNumber": 18421829, "blockId": "0x7da63a0b613d8745597b2ac64fd5cc8b2fb14b24d163b12a0a39d7d3d4ff7b5c", "firstIndex": 12146703582}, -{"blockNumber": 18471706, "blockId": "0xd632a1893f415ff618f4b612a7687e6af1f12feeed81f46f0022090829c1eb4c", "firstIndex": 12213812677}, -{"blockNumber": 18522301, "blockId": "0x44fa2cf08145ae40e8e42f4e6b4ab7df360a17c5a065ce45fcc41b51bee011f4", "firstIndex": 12280921639}, -{"blockNumber": 18572935, "blockId": "0x72b8ab4c78c90425ee054b4806a8be703da0febdf1d51866358ec2bd21ba9529", "firstIndex": 12348029751}, -{"blockNumber": 18623431, "blockId": "0x8c4cb2f13501d9788820280c6f16692d0737258c3896f1e4bded32d838febf7f", "firstIndex": 12415138965}, -{"blockNumber": 18675470, "blockId": "0x523b73c19ea8b3ae32ef141a83ef9855e667ebf51443cfcabd1a06659359062a", "firstIndex": 12482247454}, -{"blockNumber": 18725728, "blockId": "0x0cfbd131eb5dad51488238079fba29a63eebb5c32d1a543cb072e48dc2104ef3", "firstIndex": 12549356369}, -{"blockNumber": 18778387, "blockId": "0xc4906c77af8058b9f172a4f0e8788c7887f05caa5ac752b38b5387080f74ae49", "firstIndex": 12616465992}, -{"blockNumber": 18835044, "blockId": "0x49c5e07f409a841dc81f3ef8417f1951f8fcc13c90134f9d2a0cd11938f9fa36", "firstIndex": 12683575082}, -{"blockNumber": 18883308, "blockId": "0x386a58dd5f79a419eeb05075b07b3ff3bc836a265c9688854a504223b1d6a830", "firstIndex": 12750683753}, -{"blockNumber": 18933635, "blockId": "0xd3881292147589bd2e192769e5c9175b5d03a453fe1ef3c4b5b6858ac9402a2f", "firstIndex": 12817792470}, -{"blockNumber": 18988254, "blockId": "0xcbe72dfa15428ac21b9c59c703ceaa0eb4b2205927687261d7aaed3dbb3783ea", "firstIndex": 12884882858}, -{"blockNumber": 19041325, "blockId": "0x92b077e1c2f8819da728f0307c914fdcd57eba14ea07d9a45c28d1ed8ffff576", "firstIndex": 12952010530}, -{"blockNumber": 19089163, "blockId": "0x43f8ab2d3dfc34c8e18cba903074d54e235dc546f19c4eb78245a522c266c84e", "firstIndex": 13019119228}, -{"blockNumber": 19140629, "blockId": "0xab7b7ae5424b18105a13b657fa6099d4ab67fde5baff39fe6e4de707397e995c", "firstIndex": 13086228236}, -{"blockNumber": 19192118, "blockId": "0x451327e6a5cf6ce1c8c14c01687dc5f719f3c2176f46bac4f264616256e30d1c", "firstIndex": 13153337116}, -{"blockNumber": 19237836, "blockId": "0x9b260d6be369557d1dc88aca423e2697e697d941d1b726c183015b5649e248c8", "firstIndex": 13220445421}, -{"blockNumber": 19291271, "blockId": "0x4878c28d79e1f71bc11e062eb61cb52ae6a18b670b0f9bea38b477944615078e", "firstIndex": 13287554254}, -{"blockNumber": 19344448, "blockId": "0x56243b9ad863bf90953fe9aa6e64a426629384db1190e70dce79575d30595f7e", "firstIndex": 13354663659}, -{"blockNumber": 19394948, "blockId": "0x195173b64dda7908d6aa39a63c8bdd29ec181d401e369d513be1308550d0ddcb", "firstIndex": 13421771935}, -{"blockNumber": 19443075, "blockId": "0xd39c1d60996475e65d1ab5b4e755f510ca466564a8155d35db6667988d6c0e44", "firstIndex": 13488880427}, -{"blockNumber": 19488383, "blockId": "0x28956eb8856fa8db59c02585016b8baf43bc44bc35b00bdaf8a6babe51101c5c", "firstIndex": 13555977105}, -{"blockNumber": 19534584, "blockId": "0x2421c97b0f140185d4c20943cd4ed7d7424468482feb76e3003a1cc69da3fd7b", "firstIndex": 13623097580}, -{"blockNumber": 19579602, "blockId": "0x25f96529028e9f51c59aec9ce8de282b7dd67066fd46a1694130698ed0f40d8b", "firstIndex": 13690207623}, -{"blockNumber": 19621517, "blockId": "0x4f6f6e0a0488f3d51823bc4b07c292348c259b1866968f77ee76b66b37101c75", "firstIndex": 13757315529}, -{"blockNumber": 19665085, "blockId": "0x00f9315f89681b44bff46f1bad8894bc6dfae1c459d3d6520f9881861304a496", "firstIndex": 13824425382}, -{"blockNumber": 19709229, "blockId": "0x24e022b21ae1ba8a3e8c87cb9734aa1d1810fc4a69fe147d3ebb1ff0df8bcc15", "firstIndex": 13891534799}, -{"blockNumber": 19755387, "blockId": "0x77f184b7183b1a351760d242041249464b42cfaa6fbc4326f352b06bb3b21a02", "firstIndex": 13958642483}, -{"blockNumber": 19803894, "blockId": "0xf37eb1b054a6d61272940361f386eb744cded84d15c3250a7eabadede257371c", "firstIndex": 14025751618}, -{"blockNumber": 19847885, "blockId": "0x4659649fa8a3b4bbe8978673ba9a22ae20352c7052b676d373b5a51b1967ffa4", "firstIndex": 14092848654}, -{"blockNumber": 19894193, "blockId": "0x15606bdc0f1a710bd69443c7154d4979aece9329977b65990c9b39d6df84ed5c", "firstIndex": 14159970181}, -{"blockNumber": 19938551, "blockId": "0x6a8f4571924ed902bd8e71bf8ed9cc9d72cabeabc410277c8f0fc2b477d00eb7", "firstIndex": 14227077892}, -{"blockNumber": 19985354, "blockId": "0x7b6fb6376410b4d9e5d7ee02f78b2054e005dd2976eea47fc714f66b967dc285", "firstIndex": 14294187965}, -{"blockNumber": 20028440, "blockId": "0x9b37440b71c24756b8855b8012432b84276ae94c80aa1ccc8b70a7705992103c", "firstIndex": 14361296503}, -{"blockNumber": 20071780, "blockId": "0xa2ed129f343f3d60419772ec5635edcd36b8680c9419b6626e2bc84b230c709b", "firstIndex": 14428405230}, -{"blockNumber": 20113832, "blockId": "0xe7a610e8bcbf8ded141ebc7142de03dfc54b1bcc79e3bf8d07fad4e42b665bba", "firstIndex": 14495512019}, -{"blockNumber": 20156854, "blockId": "0xbe09704f65a70ef8843d9c8e511ddc989ea139dbe94cdfe37f52b03620d62385", "firstIndex": 14562622430}, -{"blockNumber": 20200135, "blockId": "0x9a58c34d5f77342e94065d119905c000223cd988c4b11f1539fff20737159630", "firstIndex": 14629731923}, -{"blockNumber": 20244389, "blockId": "0x1e733f0db9ef21183107259b3c2408c78fa5a01469928cd295f3ea7e8eedda45", "firstIndex": 14696840011}, -{"blockNumber": 20288489, "blockId": "0xb5ad7edd86b181226c8c7be0a08069e3955234e797426843fff9de0f57ec59cc", "firstIndex": 14763949714}, -{"blockNumber": 20333582, "blockId": "0x8040c209f5cd1738ee0f85c2f1db7c43a420d148680c7390fd1701b9f0bb671a", "firstIndex": 14831058335}, -{"blockNumber": 20377087, "blockId": "0x08fdc4cd246b6ae9d4a45646b0aed6af3bb330eb6cd4c8b93646157e7b002b84", "firstIndex": 14898167722}, -{"blockNumber": 20421699, "blockId": "0x5a2912b5fc2f02df33b655155990f92dcaacda5b75427fe3d87fb38f36b1c17d", "firstIndex": 14965275691}, -{"blockNumber": 20467194, "blockId": "0x3deaf4325c461004b090b0261996c645ab529c1471feaf7dc2bbe1f128180297", "firstIndex": 15032385211}, -{"blockNumber": 20512397, "blockId": "0x37e39697ec1b7683a6202be250ffaee7a1102e8030f87550b94af05ec66cec83", "firstIndex": 15099493973}, -{"blockNumber": 20557443, "blockId": "0x8e9c04468f3111eab8b1f6a58b277862c624861c237cadecc53ec249bd811bda", "firstIndex": 15166602882}, -{"blockNumber": 20595899, "blockId": "0x9787555fe57e4650002257eb2c88f1ef435b99d406e33fe2f889be180123ef25", "firstIndex": 15233709908}, -{"blockNumber": 20638606, "blockId": "0x70681cffd159ce2e580dbbbe8fa6b5343dbcb081429cdda6c577e615bef4ef05", "firstIndex": 15300820678}, -{"blockNumber": 20683605, "blockId": "0xb32662d5e241132ffe2249caea67f5746a6f4382297b2ac87c81e2794faf1f7a", "firstIndex": 15367929350}, -{"blockNumber": 20728630, "blockId": "0x15a817c846928b673032d5eacd0cff7a04217d268457aa30a322ecca32be4d49", "firstIndex": 15435037830}, -{"blockNumber": 20771519, "blockId": "0x542bc7b9804bbc45f4be470f4dc56f215a4dec71fed71eba2ffc804afd262b95", "firstIndex": 15502145990}, -{"blockNumber": 20815097, "blockId": "0x798cdd51c964fcf18561d70095d9613b84ba836817972799c9dfd0bfbe1e042b", "firstIndex": 15569256033}, -{"blockNumber": 20857859, "blockId": "0xfb5bb066d419a651d8e0186569eb4e8d8bcd5181d8f02e0d578b5dfe2fc738dd", "firstIndex": 15636364671}, -{"blockNumber": 20896890, "blockId": "0x834b8d6fad779e4cf8214128f6c93d7387b6d6279e517f6f0a284b5d831cc3ae", "firstIndex": 15703472902}, -{"blockNumber": 20939387, "blockId": "0x7adee7c78420c711efa216c61e0b561e581d7ff0331efd91ee16a609b34cfdc2", "firstIndex": 15770582325}, -{"blockNumber": 20981303, "blockId": "0x6f5d7b0cc6dad5eb258176e07de21795a8347d68f7303f06934046e0236bea6d", "firstIndex": 15837691713}, -{"blockNumber": 21023216, "blockId": "0x96cfe35a45df1297a36f42c59ebe706ab0473dfbf59ce910b5c5a8dbf696de1c", "firstIndex": 15904799667}, -{"blockNumber": 21068378, "blockId": "0x93753875ff330d922b23f823203198f3b1bb8833367c6b6a8f896ff54be2c12d", "firstIndex": 15971909040}, -{"blockNumber": 21112445, "blockId": "0x6ac02fa6ae486b86aba562eaf6f3d883befaa8ebedcfd8d74bdb7368d42deee3", "firstIndex": 16039003625}, -{"blockNumber": 21155992, "blockId": "0x25f76896b4b693bafb79e9a535e2bf00ed62a577e35209749346e8e79a60bb71", "firstIndex": 16106126344}, -{"blockNumber": 21200962, "blockId": "0x725f2befe913cb2659d262e2d3b6f79a706b31c557d52669471da22347ec8287", "firstIndex": 16173235265}, -{"blockNumber": 21244663, "blockId": "0x6778c4194f54e70939da38853daddb22bfaf160d35617ab05d0f5c476741147b", "firstIndex": 16240344735}, -{"blockNumber": 21290273, "blockId": "0x433ac819c40bd3061205fe0ece0645eec73f54a0a5c1559c981f983345bc0154", "firstIndex": 16307453543}, -{"blockNumber": 21336156, "blockId": "0x261dc8c1639d505624150d2388d15ed10bfb4c3ce9c0c327a4ec26531689a097", "firstIndex": 16374562466}, -{"blockNumber": 21378880, "blockId": "0x5c78b2b70553140dfdfdd4f415b98f88e74f74662315834038fd99042277d917", "firstIndex": 16441671104}, -{"blockNumber": 21421613, "blockId": "0x854532f9d1c77627b763f9cbc7099a653d59554ed57fa763bc218834c82955fe", "firstIndex": 16508780351}, -{"blockNumber": 21466875, "blockId": "0xb8b83cc62084e948235ef4b5973bf7fd988fa28bcaa72f7d38ad8e50de729618", "firstIndex": 16575888599}, -{"blockNumber": 21511942, "blockId": "0xe806a28bc1b7f8cd752c8ceedbe081d49773d4558a9fb95e3357c0c07172522d", "firstIndex": 16642996907}, -{"blockNumber": 21550291, "blockId": "0x1f3e26d303e7a2a9b0614f12f62b189da365b3947c5fe2d99ed2711b37fe7daa", "firstIndex": 16710106826}, -{"blockNumber": 21592690, "blockId": "0xa1408cfbc693faee4425e8fd9e83a181be535c33f874b56c3a7a114404c4f686", "firstIndex": 16777215566}, -{"blockNumber": 21636275, "blockId": "0x704734c2d0351f8ccd38721a9a4b80c063368afaaa857518d98498180a502bba", "firstIndex": 16844323959}, -{"blockNumber": 21681066, "blockId": "0x1e738568ed393395c498b109ad61c0286747318aae0364936f19a7b6aba94aef", "firstIndex": 16911433076}, -{"blockNumber": 21725592, "blockId": "0xee87b7948e25a7498a247c616a0fbaa27f21b004e11fc56f2a20c03791ed8122", "firstIndex": 16978540993} +{"blockNumber": 4166212, "blockId": "0xd94b724fc1c7dceb3251b51b81f7a0f3220ae5b9add1e62917004f14f2a3532c", "firstIndex": 67108840}, +{"blockNumber": 4513996, "blockId": "0xc0fd25fef5888609d05fa8c5620d8e18c31cdd675dd4ee926ff966668f0e5d76", "firstIndex": 134217480}, +{"blockNumber": 4817399, "blockId": "0x8573c3166fb7f716e97cf6109d382f86441238e0b85828944a072ae8583a6cfa", "firstIndex": 201326547}, +{"blockNumber": 5087706, "blockId": "0xcd2dfae45901e299b25faa04c10df60983d5c0a3d0e478e789c7aeec980cf691", "firstIndex": 268435422}, +{"blockNumber": 5306085, "blockId": "0xe8026984c85873f2b24018a7e0bdf8c2df136b2fc49666b4addf0d2e067890da", "firstIndex": 335544018}, +{"blockNumber": 5509898, "blockId": "0x41bc63dc8184f9a7d4b9a5a554e00eee32fee60ccfa2339264be11270ac28de1", "firstIndex": 402652789}, +{"blockNumber": 5670367, "blockId": "0xe61c2ba463f2f458817ed1bf0ff9fb9d07e9d7354f46b48175b2d784b817bf3b", "firstIndex": 469761896}, +{"blockNumber": 5826113, "blockId": "0xfbbb1fc5e03a5562bf6b7f1799d7a572d9ef66c7fd0e0b9f4fed7262767b5c86", "firstIndex": 536870852}, +{"blockNumber": 5953008, "blockId": "0x6bbdccd094928e846de3c615a33f2952e3259afaa1929f4ee241a56907d0593b", "firstIndex": 603979150}, +{"blockNumber": 6102812, "blockId": "0x2403f2502088a1fa26c1294f5245032fe3b7f3a8bb14c12d0ba8d577156bbc1b", "firstIndex": 671087962}, +{"blockNumber": 6276672, "blockId": "0xeaa05a0e0574fbb164244628a7d14d9d47f1692941098aa737059d44104401df", "firstIndex": 738197399}, +{"blockNumber": 6448662, "blockId": "0xe6f097fa18a2cef425514e863659e42e1aa8d74df49cb0bed5877e82a08d1f84", "firstIndex": 805306056}, +{"blockNumber": 6655925, "blockId": "0xee5c9d87b06dc0c2e850fead07bcd13f85d45ad6b5a6e7ebee53cc8618772786", "firstIndex": 872415229}, +{"blockNumber": 6873878, "blockId": "0x9a0ea103146da21fa1d9cab7ff609ec2c5e7f1856288a1f744239588e33904c2", "firstIndex": 939524080}, +{"blockNumber": 7080893, "blockId": "0x35ad45055d7a1a3ef94efeb05e4122757bcc126ff1bc2b4ac72dc78ab3c0fd75", "firstIndex": 1006632327}, +{"blockNumber": 7266955, "blockId": "0x7b80f70520f2c16eb5890f4963af8f60446f50af82b589ceaf009d09e704b302", "firstIndex": 1073741608}, +{"blockNumber": 7466649, "blockId": "0xea8980b5c692c729013f9cc4c9f66e94d5ef2c5caad23f370be0953b6d85f32c", "firstIndex": 1140850335}, +{"blockNumber": 7661736, "blockId": "0x615cdb03dbf29a22d59bbc769c03f3647c2c9abb7d1767f3f6529708209e7073", "firstIndex": 1207959232}, +{"blockNumber": 7834494, "blockId": "0x05b7dd13e2eb8a833e4b278f9151ca01b294ae5fc5617769422ec85ffb446215", "firstIndex": 1275068098}, +{"blockNumber": 7989998, "blockId": "0x4b5026add7f2fc2c02993b82c61bceba1b75cfcb8a78c5112cc2832bc0413be6", "firstIndex": 1342177025}, +{"blockNumber": 8142950, "blockId": "0x9f56b7753a0e9964973f3e096e1385215e3aef232b448359e5bec05046b016a3", "firstIndex": 1409285545}, +{"blockNumber": 8297598, "blockId": "0x2ddfeb161fe34ff73c4a995bb94256c3b522b39348169edb97bb3d876ccdf77d", "firstIndex": 1476394898}, +{"blockNumber": 8465061, "blockId": "0xfdbe5435da5ae9fb34a9154e5ebe515afac9a128e383f798f1e69952be404fcd", "firstIndex": 1543503805}, +{"blockNumber": 8655740, "blockId": "0x305137325a39a44aba997e214c05f32d965658f7e3fe20322f2e57e72f239977", "firstIndex": 1610612406}, +{"blockNumber": 8807102, "blockId": "0xc32f9fd9a43d2b502dbcc4a683ffe324fca9a871753478bcb1f4fb9573da96a5", "firstIndex": 1677721343}, +{"blockNumber": 8911110, "blockId": "0x806eabee7dc429b57afcb6c0b72b61728b4f13c62ee9942f1813790463f9ab5b", "firstIndex": 1744830172}, +{"blockNumber": 8960262, "blockId": "0xa69f24032e9d5761565e726d484926a0932c6ca7fdb4c04a55bfc5e8f5879c4d", "firstIndex": 1811938729}, +{"blockNumber": 9085906, "blockId": "0x922b4d6aeca64517f5048fa1ffa98d3e813bc415716a1763d07cf2bdea236896", "firstIndex": 1879048062}, +{"blockNumber": 9230838, "blockId": "0xd892f513c48c95a859ae59c4e00ec4be0d684c549456c90e9c36669c11092f50", "firstIndex": 1946156580}, +{"blockNumber": 9390449, "blockId": "0xcc0ced78fa66b570f338d129794d574560a23958e28d0d5288003d4542cec734", "firstIndex": 2013264376}, +{"blockNumber": 9515554, "blockId": "0xc06d04737813c3e2c8e910b2d4543c5c684c7bfe235bb501445f68fd0663f3d9", "firstIndex": 2080374749}, +{"blockNumber": 9659367, "blockId": "0x765fa33d9418b1ed648e88b497b4bf4aa66990e6413dfc155525cda61e3cc813", "firstIndex": 2147483344}, +{"blockNumber": 9793940, "blockId": "0x9527dcbd85a100c51aee4ba90828fee23312f5f041859f3416a54fd87a437ce2", "firstIndex": 2214591669}, +{"blockNumber": 9923756, "blockId": "0xc4da5fdd2de077459fe84f721d7fc01ef69683e03e634b0c5443186486792246", "firstIndex": 2281700949}, +{"blockNumber": 10042325, "blockId": "0x6f554f195d20e4ba1262f73cf2c1cd44b14a71befe5ef0a5318fc309f8cde9fa", "firstIndex": 2348810131}, +{"blockNumber": 10168768, "blockId": "0xdcdf88ec2c197d552343c80d01375a35d6462aff39c5bd976160f7176d2add64", "firstIndex": 2415918723}, +{"blockNumber": 10289467, "blockId": "0x5ece23babcf6b8838695b891b044c3dcf8120cdc15acd83018e96ffc590f6cd0", "firstIndex": 2483027720}, +{"blockNumber": 10386601, "blockId": "0xd398ee129aea1247019fa39dc2f5083819687d8f5ad17ec39ba1803d178fbcda", "firstIndex": 2550136043}, +{"blockNumber": 10479586, "blockId": "0x61c1cccd60a546eacc29f2ae2a6facab402b4f35e2986c6629b302e6b1ebca3e", "firstIndex": 2617245577}, +{"blockNumber": 10562579, "blockId": "0x14fd6a079050e3e110140372605c050945d6db03746fa5b84a8718cb2a0e9b86", "firstIndex": 2684353802}, +{"blockNumber": 10641438, "blockId": "0x1998dcae09111b2c1bf6d0592e2f0b4a0143fe7db7115ff94b2b73b74542cee4", "firstIndex": 2751463334}, +{"blockNumber": 10717094, "blockId": "0x9ce45a150bb6bd13687d0692c86716911ffc6aff5831a03f4015bdffb85f5093", "firstIndex": 2818571144}, +{"blockNumber": 10784494, "blockId": "0xf65c936cf578e673696477f7db7189b47222fdf7ed13096564b9d47b15c86eb9", "firstIndex": 2885680709}, +{"blockNumber": 10848591, "blockId": "0x84ea8e9d5789302ebe88888115488f91cfb75fd89e282dfbd29ba9d6225ab0ca", "firstIndex": 2952789491}, +{"blockNumber": 10909102, "blockId": "0x22275047f643f4a3b82c349274a53d56a00da25beac89655877fb8cbfa3182c8", "firstIndex": 3019898024}, +{"blockNumber": 10972828, "blockId": "0x38e8acfec19bb53ab9fe70dd3577ccd8bd7c41b4d468b8f099a19bf06ce56518", "firstIndex": 3087006561}, +{"blockNumber": 11036532, "blockId": "0x478dac03f520e987a6e845cac1b3a756d69e4f5257f20758b8fc38456e7b6884", "firstIndex": 3154116463}, +{"blockNumber": 11102457, "blockId": "0x1a36616b03351ebe481330fc86578f57d9da5c0dda59f4406d49b53a2fa9b6f6", "firstIndex": 3221224961}, +{"blockNumber": 11168092, "blockId": "0xb23af483ca6dbc2fb8d2fada1f8189de2e155758ed9ecbbb20c234a30c7e093c", "firstIndex": 3288333510}, +{"blockNumber": 11233640, "blockId": "0xdc4c80d8370823773425b31e70b3af59582b556514857d1e9a9b4c53b880a424", "firstIndex": 3355442901}, +{"blockNumber": 11300454, "blockId": "0xdbd4d8e9c1756093037f431330db4604e5a3e67bb74f425f667633d5298fe34c", "firstIndex": 3422551962}, +{"blockNumber": 11367550, "blockId": "0x9e00816bd5b39353657a99421d278091599a39f246bbf8c0898f83e6d70b7c7c", "firstIndex": 3489660743}, +{"blockNumber": 11431820, "blockId": "0xd32d5e5871ce71acc9dcc7cf9d8cb9d964646182529c327a0ddf617814e27d74", "firstIndex": 3556769150}, +{"blockNumber": 11497031, "blockId": "0xed823054d4b293294e3301d3131e2ae9f0ce63c9f07d2d80fc144e42d535d61d", "firstIndex": 3623878513}, +{"blockNumber": 11560027, "blockId": "0x7098177efe77cfb5912dc63069fe366033111041ca5c539907a89e439c861d8f", "firstIndex": 3690987092}, +{"blockNumber": 11625049, "blockId": "0x61fccb47104a076b905d390498a1b38c317348bb1567e69aa1b670bed7a6a13f", "firstIndex": 3758096043}, +{"blockNumber": 11690298, "blockId": "0xaf6f9e9c92db9e155f1ffb35eb68765c09de1206c353c9a56a5d5fa53e2d88d2", "firstIndex": 3825204430}, +{"blockNumber": 11755003, "blockId": "0xf9efb54f08a2b59086a607541005928f1bda54fa2c46fcc48352fa6aa461c03a", "firstIndex": 3892313541}, +{"blockNumber": 11819591, "blockId": "0xa551deb3bd2ec0ca2683cb76adb8fb295d171a3787aa5ff071bd1fa94d3af82e", "firstIndex": 3959422322}, +{"blockNumber": 11883278, "blockId": "0x60c7a359d4aeb09b63b64487fa7794aee87c41b11446f69ba83e24d5bce6947f", "firstIndex": 4026531239}, +{"blockNumber": 11948436, "blockId": "0x1c46fb22653e5f9eb9503fe532151519845d05b121291766715973e027eb9c0c", "firstIndex": 4093639741}, +{"blockNumber": 12013084, "blockId": "0x0b8d1da9e70c4494ba61190390c891230846e69d9b0be605df8b04c4199ffd1b", "firstIndex": 4160749561}, +{"blockNumber": 12078612, "blockId": "0xb049af260be25c6153b67c227689b0556d8fb7d6033c3f61b8218f5c4ac5917a", "firstIndex": 4227857310}, +{"blockNumber": 12143549, "blockId": "0x685dce41efbe2bab0ac9a4b9026d9e5faa3e01ae4637c8181cd2f1eac326fe6a", "firstIndex": 4294966232}, +{"blockNumber": 12207918, "blockId": "0x53644ea8f781c6270f1136ed4bbcb956c98f12a4793c2f56f49b3105282b13ea", "firstIndex": 4362075410}, +{"blockNumber": 12272370, "blockId": "0x503523e1a01cb7d68be0eb22f36280c0ee7a1fc802061a704e326fbb8efcfe27", "firstIndex": 4429184831}, +{"blockNumber": 12329342, "blockId": "0xe6a1bf78dd827def078e23c768cf6e96666ee06b5fdc113380a4769d85f4bd33", "firstIndex": 4496293151}, +{"blockNumber": 12382311, "blockId": "0x352fe793c16b1d8aea195af86ee9aec3dbaa83e7a32872a0d222a77e96fc0e57", "firstIndex": 4563402486}, +{"blockNumber": 12436970, "blockId": "0x90276349edf0941bb3327dc1d749d0371fe550eaddafb5141fcacdd281de0976", "firstIndex": 4630510187}, +{"blockNumber": 12489954, "blockId": "0x71894b1e1608aeba777662a6055e601ce6f17950dbe3844c3601e0f88cbd5848", "firstIndex": 4697619586}, +{"blockNumber": 12541655, "blockId": "0xc34c7299041df72a81c4b86e81639d2dfcebfae603e287fc143881a636ce1188", "firstIndex": 4764728948}, +{"blockNumber": 12597319, "blockId": "0x4c4dc71d8d2f1223ad0469ddfe09fa8934f64e3712ed83708d6e1b9c64eceebb", "firstIndex": 4831837390}, +{"blockNumber": 12651863, "blockId": "0x406a642c8364fb61cbd896512a2d19ecdba3932ab09ac67cf48d91aa1a03f24e", "firstIndex": 4898946362}, +{"blockNumber": 12706391, "blockId": "0xa7fc3739898f7ff5733896313b248fb0b306a132681609b8b9e2671b42dac3a1", "firstIndex": 4966054748}, +{"blockNumber": 12762840, "blockId": "0x5a1048966dfa55a48248517c45683ce342671bf544117d2bac13d8e343563136", "firstIndex": 5033164303}, +{"blockNumber": 12816597, "blockId": "0x97f5b87f422870a8ffeff70c12f4377dde96d248aa912cb64ebfaea51dc086b6", "firstIndex": 5100272541}, +{"blockNumber": 12872315, "blockId": "0x432f7df7973fdea4e5abe2c09b634ca3b724e37a19d5ec23ca5810e4854c6b33", "firstIndex": 5167382243}, +{"blockNumber": 12929620, "blockId": "0xa4524e3b4c5dadac91df2f29696532cfed377f47469fe7cfabf10baac945eea2", "firstIndex": 5234490748}, +{"blockNumber": 12988653, "blockId": "0x9be70e31aeea164c370d8d183a1af45120693b13d360edc78214535c40ef1d63", "firstIndex": 5301600248}, +{"blockNumber": 13049074, "blockId": "0x3076857bd17959c2a3df18357eab3ecbb7ca25457785b07074d2e885eb566fc2", "firstIndex": 5368707746}, +{"blockNumber": 13108823, "blockId": "0x67b2764f6b53779e3d683def2c7659c6d92814152574073d24f10cd67200a22b", "firstIndex": 5435817680}, +{"blockNumber": 13175389, "blockId": "0x0d41e34dbca58dec45e0509b6cbf027b2377220845a85caebbf3a14b8505e8ce", "firstIndex": 5502925085}, +{"blockNumber": 13237624, "blockId": "0x723e0818d54ab1b1c53efc2f2f448c16c1f943af2033575c612c3c71228d4ddf", "firstIndex": 5570034948}, +{"blockNumber": 13298658, "blockId": "0xd7f9f477b20bcf1379ccaaae701c9658a02b177861e0af9e873c63fe8b854f4b", "firstIndex": 5637144562}, +{"blockNumber": 13361166, "blockId": "0x9f9e4130093269d59045f91344a13eb2786023e02099f53dd44854d50a7f5ffb", "firstIndex": 5704253260}, +{"blockNumber": 13421716, "blockId": "0x28752f35ad2adeba342ef6aa51bca1c0abc757c4f712cf620c8a5e6a8576636e", "firstIndex": 5771361775}, +{"blockNumber": 13480516, "blockId": "0x43f4ecf24c17b7a77621e2ca09c88c53b3407fb018f4bb3a032c212015b4e18d", "firstIndex": 5838469616}, +{"blockNumber": 13535688, "blockId": "0x99ffcd9982219a4be45fa5f15622b288afe4f85da536956d39dccac1ec416444", "firstIndex": 5905579739}, +{"blockNumber": 13590487, "blockId": "0xff7b74464a318037e0670c0be7a5b1b79418d1a42c7a3587c46adc1ef720c819", "firstIndex": 5972688013}, +{"blockNumber": 13646596, "blockId": "0xd555ce5f2b65ffeec9b9e3e75a56f5f23d7353a1014bcc861efd7df6e5dc2c92", "firstIndex": 6039797525}, +{"blockNumber": 13702902, "blockId": "0x3e8feab590c6631c63931fee83bf7e10234890bdf377b1b374fb70221b9ac9c0", "firstIndex": 6106905641}, +{"blockNumber": 13760908, "blockId": "0x18e96fa585c57aad1f2a8dc9639d9f4fe53c3f38894862471b7cec17f97f3cb1", "firstIndex": 6174014330}, +{"blockNumber": 13819340, "blockId": "0x25384bf2cef178e30c4d9e0abae59357055241fc715133b2bb078e8278e5296a", "firstIndex": 6241123906}, +{"blockNumber": 13877817, "blockId": "0x4a84a0a7035dbfed0e1281fb1df162a195f2c516686a2e2a6ad605e6f2b3cf57", "firstIndex": 6308232690}, +{"blockNumber": 13935260, "blockId": "0x6c14a8e563614edbad66698ebe911e997e27844f9d33c7069795379540e71a44", "firstIndex": 6375341148}, +{"blockNumber": 13993914, "blockId": "0xc0991d1bc431c5215fb0218b0b541f2b4fae0994775e5eddb016965fe5b4a0c7", "firstIndex": 6442448947}, +{"blockNumber": 14051007, "blockId": "0x854803ce364b6fe4446800e74448a5ee883e7d472e8a0347f1ad13bd347fa69f", "firstIndex": 6509558964}, +{"blockNumber": 14109063, "blockId": "0xa3fadce7ab18a5fedcfed9e3b1f0cf2fb32151172c362327c602343bc26dde8f", "firstIndex": 6576668017}, +{"blockNumber": 14166701, "blockId": "0xaa2443a38e2b0d6b01cf4b73de54d2b7e92c99475bd0802beebd86845c126d1b", "firstIndex": 6643774648}, +{"blockNumber": 14222367, "blockId": "0xa27c78134c1fbf432c8caee7c9d2ef323fdde519a065804c9c8da6ca1615e04f", "firstIndex": 6710886238}, +{"blockNumber": 14277029, "blockId": "0x5d0ed08b65db01e382c339dcb2715b2927fb472b0c1f4256841c386d785c3f3a", "firstIndex": 6777995247}, +{"blockNumber": 14330955, "blockId": "0x3e5014d82c416549acfe2e26b13ff5ddf29ad74943ef5b94a65eca0a4d72d82e", "firstIndex": 6845102969}, +{"blockNumber": 14384139, "blockId": "0x720e1fd687292019c3fa1812c39c73d20fde783c0196f43378a51cb4e0b46d65", "firstIndex": 6912212078}, +{"blockNumber": 14437534, "blockId": "0xe4342ab6f363066d9c2514a870241ceb63df232d33659fdb3928faf433360bb4", "firstIndex": 6979321493}, +{"blockNumber": 14489073, "blockId": "0xeb2f9923d816e773460eccfa42eb4ff2bbfc353b756ba274e98dc85c64ab1536", "firstIndex": 7046428879}, +{"blockNumber": 14541559, "blockId": "0x55cc33721fa9022964f47c30f4146fee7cc80f5b4158d7ecea0ff661cbba3487", "firstIndex": 7113538857}, +{"blockNumber": 14594432, "blockId": "0x676441bdc1ec430a9fbc05e56a0437a475606a253f9fdffc86f5f6286c159b5d", "firstIndex": 7180647956}, +{"blockNumber": 14644942, "blockId": "0x03232a1d3c9b2f1f0c2a4b780c83bce66238d9abdeed71c2a8af9e97a53011b0", "firstIndex": 7247754981}, +{"blockNumber": 14695793, "blockId": "0x6017f6d1d79188692e1a1a18de5f93b83b97905c8ff5bed5cef4b2e9f4d4d41b", "firstIndex": 7314863646}, +{"blockNumber": 14746186, "blockId": "0x332c8ac0b2960fb1627407d45443201a0f6de7421b52af077b32fa6e018e5401", "firstIndex": 7381974499}, +{"blockNumber": 14798403, "blockId": "0x4507ae1d9f27a3eada874dcf04112a5d4ee7155701afd3fb857fe58201a2dede", "firstIndex": 7449082752}, +{"blockNumber": 14848093, "blockId": "0xff98c820c66c3beaaa3b195158c94f099148573a7f032295ba7156c13f78eaa8", "firstIndex": 7516191978}, +{"blockNumber": 14897508, "blockId": "0x49c31d3433b197585f733d7c382ae16d9d78bf59c333a9b76362cc6c5fed270c", "firstIndex": 7583300663}, +{"blockNumber": 14950638, "blockId": "0xf1a1609206788977841927271808fe1c42d059026385d025bf4cea0c0a05966b", "firstIndex": 7650408992}, +{"blockNumber": 15003958, "blockId": "0xf9e6b41108d907672f29ba1df97ed83aca2ba933335e6b5ccfb5d4001807b33f", "firstIndex": 7717519105}, +{"blockNumber": 15056783, "blockId": "0x126a5a5c22e878a4c42bea890d48cfe00edf7fbc27d805c88a5269540bc94a42", "firstIndex": 7784628173}, +{"blockNumber": 15108163, "blockId": "0x5f8494ccacefce9fef8a95a52247f2670ed30bb5a3b3deb85c645e72c115d506", "firstIndex": 7851735261}, +{"blockNumber": 15159385, "blockId": "0x0fed6c5aafb53e9cdb0d8620c3eef9b619fb3ae9559296618f634eddae33f0c6", "firstIndex": 7918844299}, +{"blockNumber": 15210872, "blockId": "0x37bdb94b57044b67fbd9b9a7cdc728fcfd2066cf1904cab478fd42d41ec6e1f0", "firstIndex": 7985954119}, +{"blockNumber": 15264226, "blockId": "0xc173ad8a791e2293efd8e0b2c9f088fac49233aabb1e72db6a045aa9904f4728", "firstIndex": 8053061840}, +{"blockNumber": 15315693, "blockId": "0x985cf97bf28f0becb2b16abfe629a5f520596e45fc23f4936bc2f6298b8145f9", "firstIndex": 8120172048}, +{"blockNumber": 15364606, "blockId": "0x593362ef8a82140f3dd3ff13d0ce50287dcb0b8b3d31ffcc7813c6be16f7438d", "firstIndex": 8187281275}, +{"blockNumber": 15412727, "blockId": "0x5a6ff10acc48e9e8bcf963b042012ea094628b9488b8bf569783b3297c67eedd", "firstIndex": 8254388575}, +{"blockNumber": 15462642, "blockId": "0x137f15c5d112b0fdc6e4c84393032030646122c3b0d86286143a1ab8bfacbac4", "firstIndex": 8321497214}, +{"blockNumber": 15509781, "blockId": "0xe58a8ca223b7c03755d046a6212bc33fa9814f73efe52804d8eea7ae4b4bd7f9", "firstIndex": 8388606496}, +{"blockNumber": 15558625, "blockId": "0x4127d527b58c7685a1237d228508ea77d40f33dbeffb5cc30e47e83a4b6152a5", "firstIndex": 8455714910}, +{"blockNumber": 15604075, "blockId": "0x7d1c1bccfe5c23a1edd81246e6e55277f271cffef30bde22c9d1202f764dd96f", "firstIndex": 8522823324}, +{"blockNumber": 15651742, "blockId": "0x732e5203a504fd97510325c1fb876476ca132831e78182367cd4b4efae1232c3", "firstIndex": 8589934155}, +{"blockNumber": 15700810, "blockId": "0xe031decb5e42a69dafcc814441227085508cf51c9c77f35d06487db19bd05a6a", "firstIndex": 8657041374}, +{"blockNumber": 15762855, "blockId": "0xbdff9b1e193c44f35bf38945d2523c74ef59c4f352efc93fad02ef34eef1c5f0", "firstIndex": 8724150924}, +{"blockNumber": 15814304, "blockId": "0x524a226d9f48e37db00e252c7f6a1350d1829d38fe83c756021cc11c56d3b2dd", "firstIndex": 8791259373}, +{"blockNumber": 15865514, "blockId": "0x4e4ad46f3ae7fb2a2e7cb94aa804929cb7353c79c78cc2cbcee710da5f0ec4b5", "firstIndex": 8858369571}, +{"blockNumber": 15920411, "blockId": "0xa39e4cbd8e84b427e44b8d06b5b1149652f3af5fa88633b802665b8677772bc5", "firstIndex": 8925477782}, +{"blockNumber": 15974193, "blockId": "0x4a3f82935e6fcda6ce7636001989b65b79422d362e60833e01185a7960b2fa55", "firstIndex": 8992587369}, +{"blockNumber": 16032739, "blockId": "0x7f50bb76dfd01125e0a4a7595106e43329eb8bd02e819be2ade4248a403c714a", "firstIndex": 9059696611}, +{"blockNumber": 16090896, "blockId": "0xdc4db130973ef793d2223844e35122a2477e642d86c69616fb3604d2a79805c4", "firstIndex": 9126804425}, +{"blockNumber": 16150783, "blockId": "0xb46294fe1cbcbbdff7309ebf0bf481e78e2589d386b95fa4c781c437e02e0aec", "firstIndex": 9193912139}, +{"blockNumber": 16207278, "blockId": "0x8a3af0387572b56989bb6c98d8860e07b5cdefb2ebe7b1dc58be07c24a53e056", "firstIndex": 9261022215}, +{"blockNumber": 16262389, "blockId": "0xec5a03d88cfc1bf8c278ddce7ace5032c3f7ed5032b4575df54779ec1abca131", "firstIndex": 9328130680}, +{"blockNumber": 16319525, "blockId": "0x74ae702375e242205fe4986448b0ee494d4a38ccc813981489c4b0488e58a949", "firstIndex": 9395240779}, +{"blockNumber": 16373441, "blockId": "0x5f404555cf45c547ef0fc044f2701bc7a28ce1e432de06e0264dbfd1c17447d0", "firstIndex": 9462347671}, +{"blockNumber": 16423343, "blockId": "0xe4af890b6c4dd3b10af2e6c08f14563bd2a3121b22a3cc6a0db29d438c1dcc59", "firstIndex": 9529457704}, +{"blockNumber": 16474687, "blockId": "0x019a8b374cf150fcda1c8af2a3e7ba63603ae81744d6343897c4b17ee58411d5", "firstIndex": 9596566169}, +{"blockNumber": 16525504, "blockId": "0xad394ce7e84e1c904cc5dd6dabd51b1a575c0b2fb006f10f272875b7f921904e", "firstIndex": 9663675287}, +{"blockNumber": 16574051, "blockId": "0x098e2dca2eda0d700aa3127bdfb679ce16e3ca297a305978c6ecfff044269511", "firstIndex": 9730784563}, +{"blockNumber": 16622457, "blockId": "0x8627f1237731c1127116898724f1b6420b8e7bcd8e18a0ea568f192bbd2cd55d", "firstIndex": 9797893241}, +{"blockNumber": 16672410, "blockId": "0x3e32b46faa670b191b89bea84a68022d5ea8b90008b388a948ff27f871d17292", "firstIndex": 9865002964}, +{"blockNumber": 16719964, "blockId": "0x1668c3ea6cb256f306e93851cc2c00612f85df5cf7b5527ffce14c89088d7fdf", "firstIndex": 9932111708}, +{"blockNumber": 16769014, "blockId": "0xed9a6f88e47b5bfe4d5bc92e1c1bfeb252f716f0990ffa1f907655c0f5e3a365", "firstIndex": 9999220312}, +{"blockNumber": 16818134, "blockId": "0x93504ba617500698a1b46f3110cd26827b8efe468190b2a91d3595784e34a1b6", "firstIndex": 10066329167}, +{"blockNumber": 16869369, "blockId": "0x94ca4b395a5c36c4e9d07cbb08271f0680455af4e4659906b647e16abebd7d4e", "firstIndex": 10133438415}, +{"blockNumber": 16921428, "blockId": "0x66650775bff4cb95de56099c10b06f3dfe302a731b391f406d1aa551121308ba", "firstIndex": 10200547148}, +{"blockNumber": 16974677, "blockId": "0x58d5fc4cd45047dac10d55a036e0a4448faacc1041b29c4c7fb41a6e9394c3ff", "firstIndex": 10267655623}, +{"blockNumber": 17031050, "blockId": "0x9d15b831979e95fc4149ecae46478cac1e54470b277d57d7102d19a72f28eeba", "firstIndex": 10334764441}, +{"blockNumber": 17086163, "blockId": "0x978ff48863fcdb50b274ea4220e7635c13c41bae91912db9e24205fb917fde85", "firstIndex": 10401873176}, +{"blockNumber": 17141086, "blockId": "0x4084d442499893361731f17534944d260cccd8e07d41c52d7160910555770b90", "firstIndex": 10468982462}, +{"blockNumber": 17190735, "blockId": "0x42ed86fb42def23870df6ec23204f557669ec7cd8de59c9f3ef9ab90704e4b11", "firstIndex": 10536090726}, +{"blockNumber": 17237026, "blockId": "0x9a49d943f82a7335f8049df4d953080f25920e3b098f6a2d872520166b225961", "firstIndex": 10603199938}, +{"blockNumber": 17287007, "blockId": "0xac3d189676d24eadc62adcf97d8730a001a7766fe3ac27b18e745ca9727f6c46", "firstIndex": 10670308186}, +{"blockNumber": 17338498, "blockId": "0xe50e251aa0a3209fa8a0030b237cf8357b08eeb80492a432c8aa5969a820ee42", "firstIndex": 10737417623}, +{"blockNumber": 17389178, "blockId": "0x1e18cedcfa6c81bc845c9136fc92f9f27ca8fff8847289bb139f374f0f6ba733", "firstIndex": 10804526769}, +{"blockNumber": 17442038, "blockId": "0x07f47ebbee99938fb96beb1ffadf8266f71d0d73f393172f0e24facd40d45c97", "firstIndex": 10871635940}, +{"blockNumber": 17497589, "blockId": "0x247a5e852e36e46f7897ad1875e93d810ff4434bb835b469afae3a3d3d4a9c9a", "firstIndex": 10938744251}, +{"blockNumber": 17554111, "blockId": "0x420e420a1b599e4dc3bd115652b4d6f5eedc391086ef064f97a9cbffc02b62f9", "firstIndex": 11005853686}, +{"blockNumber": 17608282, "blockId": "0xb2ba644d3593d3c832f932f14ffec532e26e9e1cdcd8fbe7477f46e238c6bffd", "firstIndex": 11072962303}, +{"blockNumber": 17664091, "blockId": "0x6d0bfff8145652a617bfe03ab87e3af09219cdb822c9c214b42b16f20742c1eb", "firstIndex": 11140070260}, +{"blockNumber": 17714917, "blockId": "0x61509544b5174d3ff5d48816ff54f2929c8a400ef21454116056baa136b607b6", "firstIndex": 11207179013}, +{"blockNumber": 17763850, "blockId": "0x8da83012621f42670601406c902ce6e48e77c6285dcc6983e108e69b3a8d5d2d", "firstIndex": 11274288732}, +{"blockNumber": 17814186, "blockId": "0xc37bda200856589c220dc206e31186d6c12761fd193f5bc7123cf331fbbed7f5", "firstIndex": 11341397343}, +{"blockNumber": 17864461, "blockId": "0x99af43893dc9f54c55abbdbd7b000e27248145371e9b00db116dfb961b36749c", "firstIndex": 11408506122}, +{"blockNumber": 17913212, "blockId": "0x9b642236d63d756fcd3404713bc6abe97804b46a9e665ae5f1d9aa48e693fe78", "firstIndex": 11475614347}, +{"blockNumber": 17961497, "blockId": "0xaec9b1e851cf51646673ec7698e1d5964d44eb04729ad11385f6ae84d497070a", "firstIndex": 11542723713}, +{"blockNumber": 18010859, "blockId": "0xb15fb7fc308516cad5f1dadfb7dd92fd3fe612308f67154cf2a241990aa15bc4", "firstIndex": 11609833204}, +{"blockNumber": 18061052, "blockId": "0xd8ea94b8b8a7380d21dc433abb69973f3de2eeb339f4aaffdb79f85a5d86929d", "firstIndex": 11676938565}, +{"blockNumber": 18111466, "blockId": "0x5b5cc6d182bffaf06692a7efda8cad5d4742fdbce5c1146b3be3c5be10ea046a", "firstIndex": 11744048539}, +{"blockNumber": 18166001, "blockId": "0x901d8401c795542c75069cd917781fa587ad416da0a5298f144fae2f14305705", "firstIndex": 11811159949}, +{"blockNumber": 18218505, "blockId": "0x5894285023f34ec6fd501cd90b605e118b9688ca7c01082289bf69a6987142bc", "firstIndex": 11878268395}, +{"blockNumber": 18271037, "blockId": "0x3f0fce315fd993d966b6c599ebd360462466e67046d512dc430ac07f75243bae", "firstIndex": 11945377050}, +{"blockNumber": 18322778, "blockId": "0xfa6536b3b06e7b579e53a8d01368182808c950586e39e12485be3145c3acbf43", "firstIndex": 12012486036}, +{"blockNumber": 18372240, "blockId": "0x5531859d5b8a4093020e2fb971808d0eeaddd7d61dc58d70f34923081f97336f", "firstIndex": 12079595358}, +{"blockNumber": 18421630, "blockId": "0xfeadff676fe8f04d0362b77ea2d7c3ea59b05d68cc6b2cc95cfe751558b1bfa7", "firstIndex": 12146703872}, +{"blockNumber": 18471472, "blockId": "0x352b0a17e4160d334b876eb180d686fd67c7ddc40a78219b0bc4b59f5ae5912d", "firstIndex": 12213813174}, +{"blockNumber": 18522088, "blockId": "0xf7d408309246089531b47c787049c7ffd2820c1b87b4804033a458bc193a3432", "firstIndex": 12280921181}, +{"blockNumber": 18572725, "blockId": "0x44126d4a5b43594b09d26e0b0a5dc859c074865cb9b11ab78c80f28406fd0240", "firstIndex": 12348029615}, +{"blockNumber": 18623223, "blockId": "0xd3aec1f98cea30e870d0f530194e9a72e225eb45eefe435e38da5967eb2fa470", "firstIndex": 12415139522}, +{"blockNumber": 18675228, "blockId": "0x24deaef2508038bddf8e9020f95128ae34eb1786f786c3f98df0bdf95f3e97cc", "firstIndex": 12482248123}, +{"blockNumber": 18725495, "blockId": "0x2e5a7edd7337b20e862741e116680a472089426dbc2b0eb5f1c984f8d6da935b", "firstIndex": 12549357121}, +{"blockNumber": 18778174, "blockId": "0xe734a1084fa5eeff427bba8e8d3623181a30dd9bad128fc22de9b15dffd0e549", "firstIndex": 12616466131}, +{"blockNumber": 18834807, "blockId": "0x0924a55ef4f9c2605261433c5b236d47645484efa44b34dc9f15b7c2e6b47a74", "firstIndex": 12683575000}, +{"blockNumber": 18883054, "blockId": "0xef638ec491a1cf685b22bf4072e41710440d6133a53e31250762825247d3eb64", "firstIndex": 12750683712}, +{"blockNumber": 18933405, "blockId": "0x6e9eefc2e121d13e6c04544ea370fe8543afeb36fef3a8e2ea68afb079738c8c", "firstIndex": 12817792510}, +{"blockNumber": 18988033, "blockId": "0x4c98c0dbb6a7217609c4b277fe7ff9e2c32c8d000ee628a3f37b2b296e1ca421", "firstIndex": 12884901389}, +{"blockNumber": 19041096, "blockId": "0x61a219a23d111cd07861ff47b89d4b2840c0ab5421d5d55a6f1fe43da3f33b98", "firstIndex": 12952010147}, +{"blockNumber": 19088914, "blockId": "0xefb26ba58447e50e9b820e0b0d16c08da45793a824af12a2e1f38b6f46b7e36a", "firstIndex": 13019118891}, +{"blockNumber": 19140413, "blockId": "0x91dbb13623fc4d5a4e462dfa0a03c92bf5301948dd4b2c3e5fddd2bc88856d47", "firstIndex": 13086228137}, +{"blockNumber": 19191876, "blockId": "0xdd7f97af7ad206b2636656ed4722fe1c47c6ba9fa5531066785acbe4f8d4c4ad", "firstIndex": 13153336551}, +{"blockNumber": 19237651, "blockId": "0xf1e875f314314abe3654b667c6443c772dd67c525c52877b06515ea8fc5a391b", "firstIndex": 13220444812}, +{"blockNumber": 19291032, "blockId": "0x9eda269ac47957b619d2a8c408b5efc8cfb168a46bfde351f43325fa337fce47", "firstIndex": 13287553967}, +{"blockNumber": 19344225, "blockId": "0x62859b78d45f589f679fc6a3bf266a2e0aa906fd61d787755ec51cfadc05eaf6", "firstIndex": 13354663338}, +{"blockNumber": 19394709, "blockId": "0x7cda3d193bcfe8ddbc89b85e98c814dbbe31a54ccab52ab7738ecd003061f3c8", "firstIndex": 13421772549}, +{"blockNumber": 19442850, "blockId": "0xd95f3f8bab5b91c3e1f848c9455936850bf92cf6a5086b817f6f81031bc0f81e", "firstIndex": 13488880704}, +{"blockNumber": 19488177, "blockId": "0x3a1a9623ee332d6decada9359cf84eeafb81fffa997d6cf4f3efcc92e98e9310", "firstIndex": 13555989570}, +{"blockNumber": 19534365, "blockId": "0x5c7a8ee7cbba4894ea412cc335895a9a7d3369d35779bcdc97a6c24b6a81a7ba", "firstIndex": 13623097446}, +{"blockNumber": 19579409, "blockId": "0x4280f5f76cb0f9947f9da1cb9de6c4b6e65b37b3a3c174f5fb29d360cf389ffb", "firstIndex": 13690206790}, +{"blockNumber": 19621406, "blockId": "0x0a98ca72e97fd295c7c73263b17185d74dbe427f41c616a5d5454faa5a1c63a0", "firstIndex": 13757316653}, +{"blockNumber": 19664868, "blockId": "0xc8c53d89b7a849861f3daaf9503e6397a0340cecb085850c3636bee6ea2b7189", "firstIndex": 13824424608}, +{"blockNumber": 19709011, "blockId": "0xf65babc88ef6a9eb2ffce9a6844adf895995f65a2facd1956f5df17ca68dbf94", "firstIndex": 13891534141}, +{"blockNumber": 19755170, "blockId": "0xf903882449eeb86d69af33b6797099275e82d8787334a02a42a2168dbd739b95", "firstIndex": 13958642627}, +{"blockNumber": 19803666, "blockId": "0xa8a975f570db082a3771790bb1fe405667dde4674ff49e31092687fa92727e36", "firstIndex": 14025752433}, +{"blockNumber": 19847730, "blockId": "0x89d479a4b4d9faa7af3e3f61d13a7a9c80a11c4adf7cd018859eb0ddba30bdd5", "firstIndex": 14092860598}, +{"blockNumber": 19894138, "blockId": "0x740278e6dc79cfd2b030780868a1b8e1520dbae0e8d3ee0a3ef43c84c83c6e0a", "firstIndex": 14159952129}, +{"blockNumber": 19938334, "blockId": "0x05ae7ce9813235c19baa57658bc5c8e160130328a1fd2cc58d2baf2d9a4ae097", "firstIndex": 14227078393}, +{"blockNumber": 19985138, "blockId": "0x511c8876a93a77fa473ae0d29e25d8163162c09b7212f506be0ea73840ea3971", "firstIndex": 14294187397}, +{"blockNumber": 20028221, "blockId": "0x64379baedf429cfa65df076142a7d9909d7e369d6aa6b8e161bb686944d169ff", "firstIndex": 14361296446}, +{"blockNumber": 20071555, "blockId": "0x4f43d8b1091d2bd0c6b080ce51bce08aae6be605e00889be3cdd17cb80614ff8", "firstIndex": 14428405409}, +{"blockNumber": 20113611, "blockId": "0xebbf87409ef6732a53513414926b0aa998a7269f9e9717a3acbe96a33c2de937", "firstIndex": 14495514255}, +{"blockNumber": 20156628, "blockId": "0x70218108c0669f42c4ac1afff80947cf4a0a2fd8e9300b31d45bbe330a5159c9", "firstIndex": 14562622257}, +{"blockNumber": 20199886, "blockId": "0x1d6aaa4b041eb0cc9caed34347bb943e50a139caf8998d781ff4f06d4aa727dc", "firstIndex": 14629732017}, +{"blockNumber": 20244148, "blockId": "0x37fed57b6945a815ec56c84c6261e90cf9f3883d9cbffc62b70d9722c1f0f363", "firstIndex": 14696839730}, +{"blockNumber": 20288249, "blockId": "0x1d9fe664431e093c4ef6139ad35fea767a2e66825e605cfea9e91d1738665619", "firstIndex": 14763948803}, +{"blockNumber": 20333358, "blockId": "0x1ac7c1362791507057b7e87d7118b4f61c2919c8ebdb498ecf7d64a59ba3d2e2", "firstIndex": 14831058814}, +{"blockNumber": 20376855, "blockId": "0xf6a19eac8a402f591079a4aa7ff57349c350ec96d683a031e4d85c05bc0541b2", "firstIndex": 14898167076}, +{"blockNumber": 20421474, "blockId": "0xe8767aa7516b632dc8c0fed3a366273ef14bd7b8c2212998b7105fb80b4c0d9b", "firstIndex": 14965276285}, +{"blockNumber": 20466974, "blockId": "0xafa2d2e6c9594762c163c339069cb15aa9fd27d301268892e12f99a3f2912ade", "firstIndex": 15032384674}, +{"blockNumber": 20512183, "blockId": "0xc1c51f9372d781d7ac0a1a7aa052503bbde3e1706bf65f225b0f6a6eed93d055", "firstIndex": 15099493832}, +{"blockNumber": 20557251, "blockId": "0xa905087c15e2b12b19cd23f20089b471cd9815dcff73842d2043e13a276fcc55", "firstIndex": 15166601921}, +{"blockNumber": 20595654, "blockId": "0x9e7772dd946f65e7569f34f6896d8e597ac8ff88700b871de21ff578c0c995e6", "firstIndex": 15233711474}, +{"blockNumber": 20638340, "blockId": "0xc08b46af83db6f0e5d1acad7020bacd59d0f18df72651d32c9b60edd0351a886", "firstIndex": 15300820584}, +{"blockNumber": 20683359, "blockId": "0x7ec93a1f1d211c24d93ce7e344634efef680a6388374cf3831d250ecd63711f9", "firstIndex": 15367929168}, +{"blockNumber": 20728401, "blockId": "0x4ad4124c2595abcf4477cac4eb70c0c9372bbd48f2066c7ac5b8e9f94817ab48", "firstIndex": 15435038303}, +{"blockNumber": 20771272, "blockId": "0x68fd6b12fdb4add8b2957105a21b571c7dcb114c6c2ca02f5fa40730a108f864", "firstIndex": 15502146509}, +{"blockNumber": 20814862, "blockId": "0x4e7f640bf3c135b2442ca4c744023021af163e8d45e8d776fb7051c49d79fcff", "firstIndex": 15569256173}, +{"blockNumber": 20857627, "blockId": "0x9b023bffed12530b5a68db263bb621a147e0cf02b30ec39a82b82a1fdeb7ca36", "firstIndex": 15636364955}, +{"blockNumber": 20896662, "blockId": "0x8c3adf694b8520ed1edd38282b2f58cf383426176628b5be6330a56882e2a07e", "firstIndex": 15703473445}, +{"blockNumber": 20939156, "blockId": "0x0649e2559f767da945a674c9d6c700628109e18d0757ad33496a228a827413a4", "firstIndex": 15770581979}, +{"blockNumber": 20981054, "blockId": "0xebf0ecca671b833f77df70106cf1171d4dd3fa0f062607e4845569073997f1cd", "firstIndex": 15837691319}, +{"blockNumber": 21022980, "blockId": "0x07479520c08a727c42e3616aca7fc4435773f4ef277d84369190263159606d71", "firstIndex": 15904799391}, +{"blockNumber": 21068139, "blockId": "0x669cfd03b293a61815588cb9cef928a512d328c1fe9191fe6b281573f429f8b8", "firstIndex": 15971908604}, +{"blockNumber": 21112368, "blockId": "0x98957aedaf8b0483be208e8d16a3e6d73ff217e732f3649650671c92c8fb57a5", "firstIndex": 16039007815}, +{"blockNumber": 21155756, "blockId": "0xc301e40988fbe19b1254ab3abe2f78fe0cd35259898be02476179a041926f777", "firstIndex": 16106127130}, +{"blockNumber": 21200717, "blockId": "0x8d35b199ee65c5ccf4ca0fc22b50282850cd88b72580679f1568eea67d3431e8", "firstIndex": 16173235593}, +{"blockNumber": 21244396, "blockId": "0xe7ec084eb8a7125fe26c4ef64fdbb3e0a727b2d882fb1e4fdad1d7fa3dc55fd2", "firstIndex": 16240343803}, +{"blockNumber": 21290031, "blockId": "0x8bb31b883d30875b7ed8a01c35a6f51e603b8d974c4e74af20fb9c723e5ac5df", "firstIndex": 16307452772}, +{"blockNumber": 21335893, "blockId": "0xd0976b7c946a7556e607e47a02d2cfcccd259508e2828b9c4faa5c7105a597a8", "firstIndex": 16374562657}, +{"blockNumber": 21378611, "blockId": "0x72d42953f013aeb7c84bb22c9e07828b92f73885b20c208af612874df8fe85ed", "firstIndex": 16441671192}, +{"blockNumber": 21421343, "blockId": "0x663b3cddcf3f7cfa59ed29b4894e43fa784c07576cfec897ff1a3838235ecb50", "firstIndex": 16508779766}, +{"blockNumber": 21466598, "blockId": "0xe04ebd60289dbcc09a27e053e7b240a59e928e2a76a85a6fa4044ee387c46d18", "firstIndex": 16575888836}, +{"blockNumber": 21511717, "blockId": "0x5ea9863a0b504f381010ff383d60a56390ba9cef162d9d5a077b1884d2adac98", "firstIndex": 16642998234}, +{"blockNumber": 21550050, "blockId": "0x2a7b3e635c80521887ca3ebda04541090ec720dd817cd06fcba61e7ae0f78a4f", "firstIndex": 16710106733}, +{"blockNumber": 21592440, "blockId": "0xc7095268d0d53cb5a069c2ea7107cc42172bb1b817f04154938e6b52bdbb369c", "firstIndex": 16777215261}, +{"blockNumber": 21636007, "blockId": "0x55f463b932053ebfc02728a12c2cdfb2cb4700a115cde686c9ab22bb4c336ecb", "firstIndex": 16844324844}, +{"blockNumber": 21680799, "blockId": "0x4521d473aa7f5150f920c66fe639b20f30cb373b32e425fcb7dcce9803b506be", "firstIndex": 16911431255}, +{"blockNumber": 21725330, "blockId": "0x793876007ce3594df603628766b139a02273ceee43d5b3ca2d0ca2f13a5fc5d9", "firstIndex": 16978541626}, +{"blockNumber": 21771310, "blockId": "0xd0db23bb28d6e39917348b1879dd560c73354ea6d7d0bbee0b7a8fcbcede1091", "firstIndex": 17045650902}, +{"blockNumber": 21811348, "blockId": "0x8165948c08db34aeb8cc2a3e331a00af2d09fbff9c466019fb2f2892ca3f7b71", "firstIndex": 17112760024}, +{"blockNumber": 21851615, "blockId": "0x3083e8f4fbb4d726ef19b1a5bce20e639a0418eac384f9967f24c7697a7e2dfc", "firstIndex": 17179868870}, +{"blockNumber": 21894041, "blockId": "0x9b0776a020374e4985f6a7e1199596bedd387ff085f65224d724ab11955c56fe", "firstIndex": 17246977342}, +{"blockNumber": 21932218, "blockId": "0xe9c50eddc21759d3ab790e2babba56f4b8d38eb739f1b561bc337a1ba6e15393", "firstIndex": 17314085541}, +{"blockNumber": 21959188, "blockId": "0x6b9c482cc4822af2ad62a359b923062556ab6a046d1a39a8243b764848690601", "firstIndex": 17381193886}, +{"blockNumber": 21994911, "blockId": "0x0d99ef9dd42dd1c62fc5249eb4f618e7672ab93fa0ba7545c77360371cf972e5", "firstIndex": 17448302795}, +{"blockNumber": 22026007, "blockId": "0xf7cdc7f6694f2c2ed31fa8a607f65cfa59d0dd7d7424ab5c017f959ae2982c71", "firstIndex": 17515413036}, +{"blockNumber": 22059890, "blockId": "0x82b768a0dddefda2eefd3a33596ea2be075312f1dd4b01f6b0d377faca2af98b", "firstIndex": 17582521768} ] - diff --git a/core/filtermaps/checkpoints_sepolia.json b/core/filtermaps/checkpoints_sepolia.json index 3e3ea23b2..c6d3cd908 100644 --- a/core/filtermaps/checkpoints_sepolia.json +++ b/core/filtermaps/checkpoints_sepolia.json @@ -1,63 +1,68 @@ [ -{"blockNumber": 3246675, "blockId": "0x36bf7de9e1f151963088ca3efa206b6e78411d699d2f64f3bf86895294275e0b", "firstIndex": 67107286}, -{"blockNumber": 3575582, "blockId": "0x08931012467636d3b67ae187790951daed2bb6423f9cd94e166df787b856788d", "firstIndex": 134217672}, -{"blockNumber": 3694264, "blockId": "0x1f35f276a3c78e5942ee285fcbd0c687691853c599a2f5b174ea88f653bc9514", "firstIndex": 201326578}, -{"blockNumber": 3725632, "blockId": "0x3bcb264c56c3eeab6c8588145f09dff3fb5f821d9fc1e7b92264b14314dae553", "firstIndex": 268433636}, -{"blockNumber": 3795390, "blockId": "0x2d1ef2815bb8e018b275fa65540b98265285016aff12596bd89a3b1442d248eb", "firstIndex": 335542953}, -{"blockNumber": 3856683, "blockId": "0x8a9a46d6f53975cd9ec829c3c307a99fb62b8428cefb63ffe06d17143649c3ee", "firstIndex": 402648835}, -{"blockNumber": 3869370, "blockId": "0x2e8c04e7e5e96d09260b65d77b1770b4105b0db2ee7d638c48f086b8afac17db", "firstIndex": 469759276}, -{"blockNumber": 3938357, "blockId": "0xf20f2cdbcc412d5340e31955d14a6526ea748ba99b5ec70b6615bdb18bcd4cfb", "firstIndex": 536868027}, -{"blockNumber": 3984894, "blockId": "0x0bcd886b3cebb884d5beeaf5ad15ee1514968b5ad07177297c7d9c00f27aa406", "firstIndex": 603968430}, -{"blockNumber": 4002664, "blockId": "0x7d3575b6ca685468fa5a5fa9ff9d5fac4415b0a67a3ed87d3530f127db32fff4", "firstIndex": 671088417}, -{"blockNumber": 4113187, "blockId": "0x3a5313ac5b602134bb73535b22801261e891ccb7bd660ab20e0a536dc46d3e13", "firstIndex": 738197016}, -{"blockNumber": 4260758, "blockId": "0xe30fb9a304d3602896a5716d310f67ba34ccef7f809a3ead4b2d991cb9ee4eb0", "firstIndex": 805306270}, -{"blockNumber": 4391131, "blockId": "0x3958478c1c3be9b7caedbcc96230ed446d711e56580e324bc2fcf903fc87c90f", "firstIndex": 872415115}, -{"blockNumber": 4515650, "blockId": "0x46a3a7b97a9dff4ef4dc2c1cc5cd501f2182d9548655b77b5e07a2dbb41071a4", "firstIndex": 939523930}, -{"blockNumber": 4634818, "blockId": "0x2197d0dd3925c1d7ba3e2c4eef20035b68efc0a2506f76ddd9e481e0ce8ca6e1", "firstIndex": 1006628557}, -{"blockNumber": 4718295, "blockId": "0xcce7bb4af1a41e6056ef68192e60c738be01ac3e071ed1ec52cead08a39995ce", "firstIndex": 1073734698}, -{"blockNumber": 4753438, "blockId": "0xa60e043728a369cdf39a399bd7a903085ee9386f38176947578e5692b4b01f65", "firstIndex": 1140843192}, -{"blockNumber": 4786522, "blockId": "0x10629cadc00e65f193fa4d10ecd2bf1855e442814c4a409d19aae9eb895dce13", "firstIndex": 1207956586}, -{"blockNumber": 4811706, "blockId": "0xf1e94111f0086733bdcb4a653486a8b94ec998b61dda0af0fd465c9b4e344f87", "firstIndex": 1275058221}, -{"blockNumber": 4841796, "blockId": "0xa530f7dd72881ac831affdc579c9d75f6d4b6853b1f1894d320bd9047df5f9eb", "firstIndex": 1342177155}, -{"blockNumber": 4914835, "blockId": "0xbd8321e354f72c4190225f8ed63d4aba794b3b568677d985e099cb62d9d36bae", "firstIndex": 1409286143}, -{"blockNumber": 4992519, "blockId": "0x4a06a5a4aa5bc52151937cc1c0f8da691a0282e94aab8b73b9faa87da8d028de", "firstIndex": 1476384367}, -{"blockNumber": 5088668, "blockId": "0xb7d5ee03c08ed3936348eeb3931be8f804e61f2b09debf305967c6a7bbf007e0", "firstIndex": 1543502599}, -{"blockNumber": 5155029, "blockId": "0x84f590dfc2e11f1ca53c1757ac3c508d56f55ee24d6ca5501895974be4250d76", "firstIndex": 1610605837}, -{"blockNumber": 5204413, "blockId": "0xeaf2c3fb6f927c16d38fab08b34303867b87470558612404c7f9e3256b80c5b9", "firstIndex": 1677720841}, -{"blockNumber": 5269957, "blockId": "0x596e0b2e8e4c18c803b61767320fe32c063153d870c94e4a08e9a68cbaa582a9", "firstIndex": 1744825147}, -{"blockNumber": 5337678, "blockId": "0x7b2d54f8af1ecaaaab994e137d4421d8236c1c10d9a7bdcb9e5500db7a3fe9a3", "firstIndex": 1811939316}, -{"blockNumber": 5399058, "blockId": "0xb61ef16d55c96682fb62b0110a2dbc50d8eff2526be4121ece3690700611c71b", "firstIndex": 1879046044}, -{"blockNumber": 5422707, "blockId": "0xdabcab7c0cc9cb9f22f7507a1076c87831cb1afed9d0aa5bcd93f22266720c91", "firstIndex": 1946156915}, -{"blockNumber": 5454264, "blockId": "0xe1bde812906605ce662f5fd9f01b49c7331fb25f52ab5b12d35ea2b4da5458fe", "firstIndex": 2013259168}, -{"blockNumber": 5498898, "blockId": "0x9533d9c5353d22f8a235e95831cfbf4d5a7220a430ca23494526a9d3aa866fe8", "firstIndex": 2080374321}, -{"blockNumber": 5554801, "blockId": "0xe7b320bbecb19f1e99dd6ce4aed1efc754d7b2022e1f80389e8a21413c465f55", "firstIndex": 2147476253}, -{"blockNumber": 5594725, "blockId": "0xce6750be4a5b3e0fe152dd02308e94f7d56b254852a7e9acef6e14105053d7d1", "firstIndex": 2214591591}, -{"blockNumber": 5645198, "blockId": "0x5d42d39999c546f37001d5f613732fb54032384dd71a686d3664d2c8a1337752", "firstIndex": 2281696503}, -{"blockNumber": 5687659, "blockId": "0x3ed941be39a33ffa69cf3531a67f5a25f712ba05db890ff377f60d26842e4b1c", "firstIndex": 2348801751}, -{"blockNumber": 5727823, "blockId": "0xaf699b6c4cd58181bd609a66990b8edb5d1b94d5ff1ab732ded35ce7b8373353", "firstIndex": 2415917178}, -{"blockNumber": 5784505, "blockId": "0x621c740d04ea41f70a2f0537e21e5b96169aea8a8efee0ae5527717e5c40aa64", "firstIndex": 2483024581}, -{"blockNumber": 5843958, "blockId": "0xec122204a4e4698748f55a1c9f8582c46bacda029aee4de1a234e67e3288e6b1", "firstIndex": 2550136761}, -{"blockNumber": 5906359, "blockId": "0x8af5ce73fbd7a6110fb8b19b75a7322456ece88fcfa1614c745f1a65f4e915c1", "firstIndex": 2617245617}, -{"blockNumber": 5977944, "blockId": "0xbc8186258298a4f376124989cfb7b22c2bea6603a5245bb6c505c5fc45844bbd", "firstIndex": 2684350982}, -{"blockNumber": 6051571, "blockId": "0x54f9df9d9d73d1aa1cfcd6f372377c6013ecba2a1ed158d3c304f4fca51dae58", "firstIndex": 2751463209}, -{"blockNumber": 6118461, "blockId": "0xfea757fad3f763c62a514a9c24924934539ca56620bd811f83e9cc2e671f0cf0", "firstIndex": 2818572283}, -{"blockNumber": 6174385, "blockId": "0x2d8d0226e58f7516c13f9e1c9cf3ea65bb520fa1dfd7249dc9ea34a4e1fd430d", "firstIndex": 2885681036}, -{"blockNumber": 6276318, "blockId": "0xa922e9d54fd062b658c4866ed218632ddd51f250d671628a42968bb912d3ed5d", "firstIndex": 2952789983}, -{"blockNumber": 6368452, "blockId": "0x8d3d7466a7c9ca7298f82c37c38b0f64ec04522d2ed2e2349f8edc020c57f2c4", "firstIndex": 3019898695}, -{"blockNumber": 6470810, "blockId": "0x9887c35542835ee81153fa0e4d8a9e6f170b6e14fc78d8c7f3d900d0a70434f1", "firstIndex": 3087007578}, -{"blockNumber": 6553334, "blockId": "0x7b0d89a0282c18785fcc108dbdc9d45dd9d63b7084ddc676df9e9504585a5969", "firstIndex": 3154115987}, -{"blockNumber": 6663825, "blockId": "0xff6cec99324a89d6d36275c17a4569f0cba203fe5b0350f155a7d5445e0ed419", "firstIndex": 3221224775}, -{"blockNumber": 6767082, "blockId": "0xe10a96a7194f98bf262f0cb1cdfb4d3b9a2072139dfcbe3f1eb01419e353044e", "firstIndex": 3288334139}, -{"blockNumber": 6886709, "blockId": "0x20f6a5d986913025ad5b6b6387d818e49a3caf838326f4002c1439ca61313be5", "firstIndex": 3355442979}, -{"blockNumber": 6978948, "blockId": "0xd7c3024765245ec49e6a48b076d540bc91f57f2ccc125e17d60dd37bb669f843", "firstIndex": 3422551908}, -{"blockNumber": 7098891, "blockId": "0x05114c037e1b4d69a46d74a974be9bce45e87ad2226a59b44dd17f98dd2fd0d1", "firstIndex": 3489659530}, -{"blockNumber": 7203157, "blockId": "0xc0f610014fcd9f2850274b58179d474f0947676fd0639b2884316467c631811d", "firstIndex": 3556769512}, -{"blockNumber": 7256735, "blockId": "0x0324c15b3b23fd82c2962dd167618e77e60ebeac5a2c87f672caddc9732337b3", "firstIndex": 3623876508}, -{"blockNumber": 7307851, "blockId": "0x8e23280d1a3aec877d7758413ed20299d381aa43e7e2fc6f381ad96e8ff0acef", "firstIndex": 3690987098}, -{"blockNumber": 7369389, "blockId": "0xbf6436eb2b88539945d6673141a14cb79ffc1e7db2b57176acf8e02ff3b6fcd3", "firstIndex": 3758096287}, -{"blockNumber": 7445220, "blockId": "0x147619f74815283d834ac08ff494fb4791207b3949c64b2623f11ff6141ee7a7", "firstIndex": 3825204992}, -{"blockNumber": 7511632, "blockId": "0x5094d64868f419e6ac3d253d19d5feda76564a0d56d7bbf8a822dff1c2261b30", "firstIndex": 3892314047}, -{"blockNumber": 7557280, "blockId": "0x54aba9351a1ba51873645221aa7c991024da1fe468a600ddb6e2559351d9c28f", "firstIndex": 3959422859}, -{"blockNumber": 7606304, "blockId": "0xbbe2fed08cf0b0ff2cb6ae9fd7257843f77a04a7d4cafb06d7a4bedea6ab0c98", "firstIndex": 4026531690} +{"blockNumber": 3246675, "blockId": "0x36bf7de9e1f151963088ca3efa206b6e78411d699d2f64f3bf86895294275e0b", "firstIndex": 67108765}, +{"blockNumber": 3575560, "blockId": "0x4652e3bee440f946aeaa3358c9a62b9bc4d41f663737ab00fded00c2662bfa29", "firstIndex": 134217644}, +{"blockNumber": 3694262, "blockId": "0x433573f97e563ca04fa53e0d0eb019d0ffe9dd032a05ee5b33ce7705aedfd34d", "firstIndex": 201316990}, +{"blockNumber": 3725628, "blockId": "0x1e25ebd76b9e2a2007bfdd7c82433cce7dae8beb190d249c82bf83d0cd177735", "firstIndex": 268426577}, +{"blockNumber": 3795378, "blockId": "0xca999083e01d5947212fb878d529abecdd18a6012997b0d5326afcf6908f17e5", "firstIndex": 335543438}, +{"blockNumber": 3856681, "blockId": "0x48148cd35de3de6c626f76ce5d97cfc6acd88772af69c0aef3d640c29ba82096", "firstIndex": 402641717}, +{"blockNumber": 3869367, "blockId": "0x08bafccf9ece7b72e4e069fc3c7493fbf25732881758917df2e8f9a51fc2c75f", "firstIndex": 469761225}, +{"blockNumber": 3938346, "blockId": "0xc638eb890c0e65ce1169ef0bb6b74dede2f4f6144ff8a5739c4894ff41a22fa2", "firstIndex": 536865235}, +{"blockNumber": 3984892, "blockId": "0x6a7782f0765b0f0c406b3cb107fd8bb14c6906293d9bdc5cc00e081bfd1ae59f", "firstIndex": 603972697}, +{"blockNumber": 4002660, "blockId": "0xda473de053602bc42fcbb074a32c908303f7f6db2ed8c38192665dce80276702", "firstIndex": 671087183}, +{"blockNumber": 4113149, "blockId": "0xd1782f677262226194725028858da83e672748e409fe1c21bdd77c07be0662c8", "firstIndex": 738197365}, +{"blockNumber": 4260733, "blockId": "0xc356600819e49d311963312157c481fd9be43a36ad040a0512fd17559c78d394", "firstIndex": 805305957}, +{"blockNumber": 4391073, "blockId": "0x06f903dc765b4b0ca1a40847eb74d30b0b51904a70c46f2e836dc5b3ea3dd8d3", "firstIndex": 872415067}, +{"blockNumber": 4515567, "blockId": "0xe99d3849755a1b4ec9a65d003260c111d4886e29ad6243fc750c72dbc79dbe4c", "firstIndex": 939523746}, +{"blockNumber": 4634815, "blockId": "0x9f281e749b192ef58242ff9fccd496a9075c30bd28c61ed4ce6487fc2d167e5c", "firstIndex": 1006629595}, +{"blockNumber": 4718286, "blockId": "0x23d2a40ec3ae059a45006ba651a70f308b6b282829b9cfdf2534e4311e34050f", "firstIndex": 1073731435}, +{"blockNumber": 4753427, "blockId": "0x6df7295f9ccb45a95e6cc72a8ee56bda992513b3bf4baa3d62219871a0b5a912", "firstIndex": 1140843105}, +{"blockNumber": 4786511, "blockId": "0x705c79435411c1af81385a1eca34343427eceb3f6af72e7f665552d6b0eceb6c", "firstIndex": 1207957185}, +{"blockNumber": 4811696, "blockId": "0x69a6e60d1b958b469feafb1dca97f38f97620a90c21ed92f90080f6443ee6c78", "firstIndex": 1275061401}, +{"blockNumber": 4841770, "blockId": "0x0a0e9d2d3d177601a478428297b5b9a42124166fefe42f2221c7a612c31e7ca1", "firstIndex": 1342174442}, +{"blockNumber": 4914785, "blockId": "0x5ca0e12230aeacbce9064dff15dafb9f24e20b4a737f7d04df8549008b829fa3", "firstIndex": 1409284680}, +{"blockNumber": 4992516, "blockId": "0xb9cb1700d8b65615fc3a019b2e9b2ece3b4f1e0e2fcfc01ff40bcf53e7291b10", "firstIndex": 1476387066}, +{"blockNumber": 5088617, "blockId": "0x33122f693a264fb2ab626232fac5e2714010fd65bdceb772109511f7c9497333", "firstIndex": 1543503849}, +{"blockNumber": 5155024, "blockId": "0x187716822dd6ab9c21138ae5a8e763197a5e7ec48bf0e756c5e6fa2c9f2f24bf", "firstIndex": 1610604247}, +{"blockNumber": 5204373, "blockId": "0x753b6495979ca90a1b915edad6af33c58bbabe68b45f95c7645113ec1d35d0e6", "firstIndex": 1677721200}, +{"blockNumber": 5269952, "blockId": "0xcbb0409ed824631120d6951b55537143d9a1c82ca6dd6255d2eb31c57844685c", "firstIndex": 1744829248}, +{"blockNumber": 5337623, "blockId": "0x0b460658511c4ae5205c038430789f9b31f3c08ba4acc06d273b7a13a149cf8b", "firstIndex": 1811939255}, +{"blockNumber": 5399044, "blockId": "0x9d07e37321e2b019f4837cc4f95f103da87ecdcb77e131e9d42d8643b0446524", "firstIndex": 1879041131}, +{"blockNumber": 5422692, "blockId": "0x9d9e27614635989788e32f15cd7a0abf7470dccf3336b77547baeb3423b629ca", "firstIndex": 1946154968}, +{"blockNumber": 5454259, "blockId": "0x01e694443d471d3411fe0b52720fd4a189e687b14cc8ede116f5e93f0ad96bb6", "firstIndex": 2013265148}, +{"blockNumber": 5498863, "blockId": "0xc4cb906c96d9f80b830b8add25318c38b3ff857c1bd577cd9cae0a324a068ffc", "firstIndex": 2080373677}, +{"blockNumber": 5554788, "blockId": "0x9b934b2d66723559d82e0f4cd49a2497234fe892248cb2f46c13f6a9585cfddd", "firstIndex": 2147475372}, +{"blockNumber": 5594711, "blockId": "0x840c0b7889b8c882cfa0eceb516dd73043b51c0e5a0c1be849a0e2a5dda7e842", "firstIndex": 2214592267}, +{"blockNumber": 5645179, "blockId": "0x188873a43506fee33349bc33df4a55059401e98dc7f0a5d488a0bc5c87dfd431", "firstIndex": 2281695869}, +{"blockNumber": 5687634, "blockId": "0x7ea8d7a2afccf795a2a02eb00746d89db57f13f8936cf7ab0f0a7db1b1ceb341", "firstIndex": 2348806824}, +{"blockNumber": 5727808, "blockId": "0x3f3eaf36c8e0271403737676907eac15312927c1d60ce814337654b7d7f2b2bd", "firstIndex": 2415915517}, +{"blockNumber": 5784480, "blockId": "0x10ec5adf01449c29550f5117f09ecafc49fc614d7da5886cf01619950827f850", "firstIndex": 2483023750}, +{"blockNumber": 5843906, "blockId": "0x9e6e14b3fba395a9ae7b3f1295f33a12d0f8b9f10e1aaab1649a90a56a323676", "firstIndex": 2550136398}, +{"blockNumber": 5906280, "blockId": "0x2188869a164e9c19232f6702a5233dc27a2304839159dd7230cc93ebdfc6c048", "firstIndex": 2617245012}, +{"blockNumber": 5977929, "blockId": "0xb247181ed597d9473c2c6e5762ae45a05f328d8df215fdac83d19ae4c028109a", "firstIndex": 2684347033}, +{"blockNumber": 6051479, "blockId": "0x0e8634c95dac31b7c835b44d0a14290e9212b31b9c3f621997ad1cca2d8ab0ba", "firstIndex": 2751463372}, +{"blockNumber": 6118422, "blockId": "0xa642c4457d4b63d68a5502bdba2355616e34495bf3ab2d8518a45ded54a16be4", "firstIndex": 2818563217}, +{"blockNumber": 6174274, "blockId": "0xbb9808bc56b5f14636e654bdd6d50d35b31345255926341ef3ddb54840095bcc", "firstIndex": 2885680274}, +{"blockNumber": 6276207, "blockId": "0x7ae027a18889e1b60a46ea3e5f2759035f3d9041de68eca0b154068ec533db59", "firstIndex": 2952789656}, +{"blockNumber": 6368344, "blockId": "0x8b4401f89589d9e99259e6c05c18b1780e96b65027caf9d83edf80390d317f66", "firstIndex": 3019898378}, +{"blockNumber": 6470718, "blockId": "0x0e2f8de093392c38750581c41e93c2fb1c0f6676b65c9af52792f3c56e894457", "firstIndex": 3087007589}, +{"blockNumber": 6553237, "blockId": "0xa6c4f3a1fe3b4e116c367fcbb1ae98e0f25570fdb2f1eadee2681deb39462c1e", "firstIndex": 3154116356}, +{"blockNumber": 6663750, "blockId": "0x9049748ddf655c7cc2ccbe2d36010b3a67ae011d114d32b1c812a7a53102f27f", "firstIndex": 3221225375}, +{"blockNumber": 6766894, "blockId": "0xc98188fb313b1beb7fc4f415b4a74c363903b3b5e0172437d79446bc011238b5", "firstIndex": 3288334172}, +{"blockNumber": 6886576, "blockId": "0x4ae8237a94198c82c266f01e472fdcd3ae150c84ecf714205a9be672f1e705b8", "firstIndex": 3355443040}, +{"blockNumber": 6978746, "blockId": "0xb2b69ce29c5c9c46c5cbc6e96260c34313d8b0b4a739cf4091c98f37093aa732", "firstIndex": 3422552017}, +{"blockNumber": 7098871, "blockId": "0x9ab2b681feeb38287a1b689fa64a50efd3407b6331fd6896187cad98a29ce107", "firstIndex": 3489660879}, +{"blockNumber": 7203023, "blockId": "0xdedfff5985c1c93d476120d2afbaa61967bae4edabb9711c7794a1b1cd453aa1", "firstIndex": 3556769365}, +{"blockNumber": 7256709, "blockId": "0xc078041cffc1802b6342fd2ba5a92ff8076ac0f5b72b4a77ba75cd486fe1b3c9", "firstIndex": 3623876563}, +{"blockNumber": 7307744, "blockId": "0xdf8dcdd4af9213a79587eb2f4d91f4111da74f99207ee05e4ae50bcb4f8d5435", "firstIndex": 3690986225}, +{"blockNumber": 7369268, "blockId": "0x62315823621a38a1f138e193b85259988fcc15f4a74d0cf19a412920bcdcad98", "firstIndex": 3758096030}, +{"blockNumber": 7445109, "blockId": "0x8b668ac1274a8dcc9526eb115c2f67bd56f6657b5072c7542da2252daca10fef", "firstIndex": 3825204921}, +{"blockNumber": 7511512, "blockId": "0x056ad7411652aa64849c67705a86e42221cb88f7fb6a7012ab7d3d5b9a30eb76", "firstIndex": 3892313524}, +{"blockNumber": 7557259, "blockId": "0xef660b97661f073b7c7319b69451e16d26ecaed54f9237e209999d137da2bfd4", "firstIndex": 3959415096}, +{"blockNumber": 7606260, "blockId": "0x9f5f06ad381166261780864bf17ad4d3cdd475f87ba51fa7f9ba621bf0ac0acb", "firstIndex": 4026521703}, +{"blockNumber": 7654244, "blockId": "0xefe5b537435001203741bf445ca26466baf7ad3f63c2bba94f0f658aed8c244b", "firstIndex": 4093627258}, +{"blockNumber": 7700433, "blockId": "0x89af6e8c5aa934a9139944b3de7a15232069479dba387e0fdd043ad36156c8bf", "firstIndex": 4160749200}, +{"blockNumber": 7730079, "blockId": "0x08e0d511a93e2a9c004b3456d77d687ae86247417ada1cdd1f85332a62dfed1d", "firstIndex": 4227846795}, +{"blockNumber": 7777515, "blockId": "0xeba8faed2e12bb9ed5e7fad19dd82662f15f6f4f512a0d232eedf1e676712428", "firstIndex": 4294966082}, +{"blockNumber": 7828860, "blockId": "0x62c054bd24be351dc4777460ee922a75fdcea5c9830455cbac6fa29552719c85", "firstIndex": 4362076087}, +{"blockNumber": 7869890, "blockId": "0x5664bcfa6151f798781e22bea4f9a2c796d097402350cb131e4e3c78e13e461a", "firstIndex": 4429183267} ] - diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index 95dd18155..fe75c1ea7 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -95,11 +95,11 @@ type FilterMaps struct { targetView *ChainView matcherSyncRequest *FilterMapsMatcherBackend + historyCutoff uint64 finalBlock, lastFinal uint64 lastFinalEpoch uint32 stop bool - targetViewCh chan *ChainView - finalBlockCh chan uint64 + targetCh chan targetUpdate blockProcessingCh chan bool blockProcessing bool matcherSyncCh chan *FilterMapsMatcherBackend @@ -145,24 +145,23 @@ func (a FilterRow) Equal(b FilterRow) bool { // filterMapsRange describes the rendered range of filter maps and the range // of fully rendered blocks. type filterMapsRange struct { - initialized bool - headBlockIndexed bool - headBlockDelimiter uint64 // zero if afterLastIndexedBlock != targetBlockNumber - // if initialized then all maps are rendered between firstRenderedMap and - // afterLastRenderedMap-1 - firstRenderedMap, afterLastRenderedMap uint32 + initialized bool + headIndexed bool + headDelimiter uint64 // zero if headIndexed is false + // if initialized then all maps are rendered in the maps range + maps common.Range[uint32] // if tailPartialEpoch > 0 then maps between firstRenderedMap-mapsPerEpoch and // firstRenderedMap-mapsPerEpoch+tailPartialEpoch-1 are rendered tailPartialEpoch uint32 - // if initialized then all log values belonging to blocks between - // firstIndexedBlock and afterLastIndexedBlock are fully rendered - // blockLvPointers are available between firstIndexedBlock and afterLastIndexedBlock-1 - firstIndexedBlock, afterLastIndexedBlock uint64 + // if initialized then all log values in the blocks range are fully + // rendered + // blockLvPointers are available in the blocks range + blocks common.Range[uint64] } // hasIndexedBlocks returns true if the range has at least one fully indexed block. func (fmr *filterMapsRange) hasIndexedBlocks() bool { - return fmr.initialized && fmr.afterLastIndexedBlock > fmr.firstIndexedBlock + return fmr.initialized && !fmr.blocks.IsEmpty() && !fmr.maps.IsEmpty() } // lastBlockOfMap is used for caching the (number, id) pairs belonging to the @@ -183,7 +182,7 @@ type Config struct { } // NewFilterMaps creates a new FilterMaps and starts the indexer. -func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, config Config) *FilterMaps { +func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, finalBlock uint64, params Params, config Config) *FilterMaps { rs, initialized, err := rawdb.ReadFilterMapsRange(db) if err != nil { log.Error("Error reading log index range", "error", err) @@ -193,22 +192,19 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, c db: db, closeCh: make(chan struct{}), waitIdleCh: make(chan chan bool), - targetViewCh: make(chan *ChainView, 1), - finalBlockCh: make(chan uint64, 1), + targetCh: make(chan targetUpdate, 1), blockProcessingCh: make(chan bool, 1), history: config.History, disabled: config.Disabled, exportFileName: config.ExportFileName, Params: params, indexedRange: filterMapsRange{ - initialized: initialized, - headBlockIndexed: rs.HeadBlockIndexed, - headBlockDelimiter: rs.HeadBlockDelimiter, - firstIndexedBlock: rs.FirstIndexedBlock, - afterLastIndexedBlock: rs.AfterLastIndexedBlock, - firstRenderedMap: rs.FirstRenderedMap, - afterLastRenderedMap: rs.AfterLastRenderedMap, - tailPartialEpoch: rs.TailPartialEpoch, + initialized: initialized, + headIndexed: rs.HeadIndexed, + headDelimiter: rs.HeadDelimiter, + blocks: common.NewRange(rs.BlocksFirst, rs.BlocksAfterLast-rs.BlocksFirst), + maps: common.NewRange(rs.MapsFirst, rs.MapsAfterLast-rs.MapsFirst), + tailPartialEpoch: rs.TailPartialEpoch, }, matcherSyncCh: make(chan *FilterMapsMatcherBackend), matchers: make(map[*FilterMapsMatcherBackend]struct{}), @@ -223,24 +219,23 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, params Params, c f.targetView = initView if f.indexedRange.initialized { f.indexedView = f.initChainView(f.targetView) - f.indexedRange.headBlockIndexed = f.indexedRange.afterLastIndexedBlock == f.indexedView.headNumber+1 - if !f.indexedRange.headBlockIndexed { - f.indexedRange.headBlockDelimiter = 0 + f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.headNumber+1 + if !f.indexedRange.headIndexed { + f.indexedRange.headDelimiter = 0 } } if f.indexedRange.hasIndexedBlocks() { log.Info("Initialized log indexer", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "first map", f.indexedRange.firstRenderedMap, "last map", f.indexedRange.afterLastRenderedMap-1, - "head indexed", f.indexedRange.headBlockIndexed) + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "first map", f.indexedRange.maps.First(), "last map", f.indexedRange.maps.Last(), + "head indexed", f.indexedRange.headIndexed) } return f } // Start starts the indexer. func (f *FilterMaps) Start() { - if !f.testDisableSnapshots && f.indexedRange.initialized && f.indexedRange.headBlockIndexed && - f.indexedRange.firstRenderedMap < f.indexedRange.afterLastRenderedMap { + if !f.testDisableSnapshots && f.indexedRange.hasIndexedBlocks() && f.indexedRange.headIndexed { // previous target head rendered; load last map as snapshot if err := f.loadHeadSnapshot(); err != nil { log.Error("Could not load head filter map snapshot", "error", err) @@ -262,7 +257,7 @@ func (f *FilterMaps) Stop() { // Note that the returned view might be shorter than the existing index if // the latest maps are not consistent with targetView. func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView { - mapIndex := f.indexedRange.afterLastRenderedMap + mapIndex := f.indexedRange.maps.AfterLast() for { var ok bool mapIndex, ok = f.lastMapBoundaryBefore(mapIndex) @@ -332,10 +327,8 @@ func (f *FilterMaps) init() error { } if bestLen > 0 { cp := checkpoints[bestIdx][bestLen-1] - fmr.firstIndexedBlock = cp.BlockNumber + 1 - fmr.afterLastIndexedBlock = cp.BlockNumber + 1 - fmr.firstRenderedMap = uint32(bestLen) << f.logMapsPerEpoch - fmr.afterLastRenderedMap = uint32(bestLen) << f.logMapsPerEpoch + fmr.blocks = common.NewRange(cp.BlockNumber+1, 0) + fmr.maps = common.NewRange(uint32(bestLen)<> f.logValuesPerMap) - if mapIndex < f.indexedRange.firstRenderedMap || mapIndex >= f.indexedRange.afterLastRenderedMap { + if !f.indexedRange.maps.Includes(mapIndex) { return nil, nil } // find possible block range based on map to block pointers @@ -425,8 +418,8 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { return nil, fmt.Errorf("failed to retrieve last block of map %d before searched log value index %d: %v", mapIndex, lvIndex, err) } } - if firstBlockNumber < f.indexedRange.firstIndexedBlock { - firstBlockNumber = f.indexedRange.firstIndexedBlock + if firstBlockNumber < f.indexedRange.blocks.First() { + firstBlockNumber = f.indexedRange.blocks.First() } // find block with binary search based on block to log value index pointers for firstBlockNumber < lastBlockNumber { @@ -453,6 +446,11 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { // iterate through receipts to find the exact log starting at lvIndex for _, receipt := range receipts { for _, log := range receipt.Logs { + l := uint64(len(log.Topics) + 1) + r := f.valuesPerMap - lvPointer%f.valuesPerMap + if l > r { + lvPointer += r // skip to map boundary + } if lvPointer > lvIndex { // lvIndex does not point to the first log value (address value) // generated by a log as true matches should always do, so it @@ -462,7 +460,7 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { if lvPointer == lvIndex { return log, nil // potential match } - lvPointer += uint64(len(log.Topics) + 1) + lvPointer += l } } return nil, nil @@ -580,8 +578,8 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 { // Note that this function assumes that the indexer read lock is being held when // called from outside the indexerLoop goroutine. func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) { - if blockNumber >= f.indexedRange.afterLastIndexedBlock && f.indexedRange.headBlockIndexed { - return f.indexedRange.headBlockDelimiter, nil + if blockNumber >= f.indexedRange.blocks.AfterLast() && f.indexedRange.headIndexed { + return f.indexedRange.headDelimiter, nil } if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok { return lvPointer, nil @@ -658,26 +656,28 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) error { firstBlock++ } fmr := f.indexedRange - if f.indexedRange.firstRenderedMap == firstMap && - f.indexedRange.afterLastRenderedMap > firstMap+f.mapsPerEpoch && + if f.indexedRange.maps.First() == firstMap && + f.indexedRange.maps.AfterLast() > firstMap+f.mapsPerEpoch && f.indexedRange.tailPartialEpoch == 0 { - fmr.firstRenderedMap = firstMap + f.mapsPerEpoch - fmr.firstIndexedBlock = lastBlock + 1 - } else if f.indexedRange.firstRenderedMap == firstMap+f.mapsPerEpoch { + fmr.maps.SetFirst(firstMap + f.mapsPerEpoch) + fmr.blocks.SetFirst(lastBlock + 1) + } else if f.indexedRange.maps.First() == firstMap+f.mapsPerEpoch { fmr.tailPartialEpoch = 0 } else { return errors.New("invalid tail epoch number") } f.setRange(f.db, f.indexedView, fmr) - rawdb.DeleteFilterMapRows(f.db, f.mapRowIndex(firstMap, 0), f.mapRowIndex(firstMap+f.mapsPerEpoch, 0)) + first := f.mapRowIndex(firstMap, 0) + count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first + rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count)) for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch; mapIndex++ { f.filterMapCache.Remove(mapIndex) } - rawdb.DeleteFilterMapLastBlocks(f.db, firstMap, firstMap+f.mapsPerEpoch-1) // keep last enrty + rawdb.DeleteFilterMapLastBlocks(f.db, common.NewRange(firstMap, f.mapsPerEpoch-1)) // keep last enrty for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch-1; mapIndex++ { f.lastBlockCache.Remove(mapIndex) } - rawdb.DeleteBlockLvPointers(f.db, firstBlock, lastBlock) // keep last enrty + rawdb.DeleteBlockLvPointers(f.db, common.NewRange(firstBlock, lastBlock-firstBlock)) // keep last enrty for blockNumber := firstBlock; blockNumber < lastBlock; blockNumber++ { f.lvPointerCache.Remove(blockNumber) } diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 54a368764..addda03df 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -66,28 +66,25 @@ func (f *FilterMaps) indexerLoop() { } } +type targetUpdate struct { + targetView *ChainView + historyCutoff, finalBlock uint64 +} + // SetTargetView sets a new target chain view for the indexer to render. // Note that SetTargetView never blocks. -func (f *FilterMaps) SetTargetView(targetView *ChainView) { +func (f *FilterMaps) SetTarget(targetView *ChainView, historyCutoff, finalBlock uint64) { if targetView == nil { panic("nil targetView") } for { select { - case <-f.targetViewCh: - case f.targetViewCh <- targetView: - return - } - } -} - -// SetFinalBlock sets the finalized block number used for exporting checkpoints. -// Note that SetFinalBlock never blocks. -func (f *FilterMaps) SetFinalBlock(finalBlock uint64) { - for { - select { - case <-f.finalBlockCh: - case f.finalBlockCh <- finalBlock: + case <-f.targetCh: + case f.targetCh <- targetUpdate{ + targetView: targetView, + historyCutoff: historyCutoff, + finalBlock: finalBlock, + }: return } } @@ -145,26 +142,24 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool { } if blocking { select { - case targetView := <-f.targetViewCh: - f.setTargetView(targetView) - case f.finalBlock = <-f.finalBlockCh: + case target := <-f.targetCh: + f.setTarget(target) case f.matcherSyncRequest = <-f.matcherSyncCh: case f.blockProcessing = <-f.blockProcessingCh: case <-f.closeCh: f.stop = true case ch := <-f.waitIdleCh: select { - case targetView := <-f.targetViewCh: - f.setTargetView(targetView) + case target := <-f.targetCh: + f.setTarget(target) default: } ch <- !f.blockProcessing && f.targetHeadIndexed() } } else { select { - case targetView := <-f.targetViewCh: - f.setTargetView(targetView) - case f.finalBlock = <-f.finalBlockCh: + case target := <-f.targetCh: + f.setTarget(target) case f.matcherSyncRequest = <-f.matcherSyncCh: case f.blockProcessing = <-f.blockProcessingCh: case <-f.closeCh: @@ -177,8 +172,10 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool { } // setTargetView updates the target chain view of the iterator. -func (f *FilterMaps) setTargetView(targetView *ChainView) { - f.targetView = targetView +func (f *FilterMaps) setTarget(target targetUpdate) { + f.targetView = target.targetView + f.historyCutoff = target.historyCutoff + f.finalBlock = target.finalBlock } // tryIndexHead tries to render head maps according to the current targetView @@ -196,20 +193,20 @@ func (f *FilterMaps) tryIndexHead() bool { f.lastLogHeadIndex = time.Now() f.startedHeadIndexAt = f.lastLogHeadIndex f.startedHeadIndex = true - f.ptrHeadIndex = f.indexedRange.afterLastIndexedBlock + f.ptrHeadIndex = f.indexedRange.blocks.AfterLast() } if _, err := headRenderer.run(func() bool { f.processEvents() return f.stop }, func() { f.tryUnindexTail() - if f.indexedRange.hasIndexedBlocks() && f.indexedRange.afterLastIndexedBlock >= f.ptrHeadIndex && + if f.indexedRange.hasIndexedBlocks() && f.indexedRange.blocks.AfterLast() >= f.ptrHeadIndex && ((!f.loggedHeadIndex && time.Since(f.startedHeadIndexAt) > headLogDelay) || time.Since(f.lastLogHeadIndex) > logFrequency) { log.Info("Log index head rendering in progress", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex, - "remaining", f.indexedView.headNumber+1-f.indexedRange.afterLastIndexedBlock, + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex, + "remaining", f.indexedView.headNumber-f.indexedRange.blocks.Last(), "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) f.loggedHeadIndex = true f.lastLogHeadIndex = time.Now() @@ -218,10 +215,10 @@ func (f *FilterMaps) tryIndexHead() bool { log.Error("Log index head rendering failed", "error", err) return false } - if f.loggedHeadIndex { + if f.loggedHeadIndex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index head rendering finished", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "processed", f.indexedRange.afterLastIndexedBlock-f.ptrHeadIndex, + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex, "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) } f.loggedHeadIndex, f.startedHeadIndex = false, false @@ -234,7 +231,11 @@ func (f *FilterMaps) tryIndexHead() bool { // rendered according to targetView and is suspended as soon as the targetView // is changed. func (f *FilterMaps) tryIndexTail() bool { - for firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch; firstEpoch > 0 && f.needTailEpoch(firstEpoch-1); { + for { + firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch + if firstEpoch == 0 || !f.needTailEpoch(firstEpoch-1) { + break + } f.processEvents() if f.stop || !f.targetHeadIndexed() { return false @@ -242,25 +243,25 @@ func (f *FilterMaps) tryIndexTail() bool { // resume process if tail rendering was interrupted because of head rendering tailRenderer := f.tailRenderer f.tailRenderer = nil - if tailRenderer != nil && tailRenderer.afterLastMap != f.indexedRange.firstRenderedMap { + if tailRenderer != nil && tailRenderer.renderBefore != f.indexedRange.maps.First() { tailRenderer = nil } if tailRenderer == nil { var err error - tailRenderer, err = f.renderMapsBefore(f.indexedRange.firstRenderedMap) + tailRenderer, err = f.renderMapsBefore(f.indexedRange.maps.First()) if err != nil { log.Error("Error creating log index tail renderer", "error", err) return false } } if tailRenderer == nil { - return true + break } if !f.startedTailIndex { f.lastLogTailIndex = time.Now() f.startedTailIndexAt = f.lastLogTailIndex f.startedTailIndex = true - f.ptrTailIndex = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks() + f.ptrTailIndex = f.indexedRange.blocks.First() - f.tailPartialBlocks() } done, err := tailRenderer.run(func() bool { f.processEvents() @@ -268,14 +269,14 @@ func (f *FilterMaps) tryIndexTail() bool { }, func() { tpb, ttb := f.tailPartialBlocks(), f.tailTargetBlock() remaining := uint64(1) - if f.indexedRange.firstIndexedBlock > ttb+tpb { - remaining = f.indexedRange.firstIndexedBlock - ttb - tpb + if f.indexedRange.blocks.First() > ttb+tpb { + remaining = f.indexedRange.blocks.First() - ttb - tpb } - if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.firstIndexedBlock && + if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.blocks.First() && (!f.loggedTailIndex || time.Since(f.lastLogTailIndex) > logFrequency) { log.Info("Log index tail rendering in progress", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock+tpb, + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "processed", f.ptrTailIndex-f.indexedRange.blocks.First()+tpb, "remaining", remaining, "next tail epoch percentage", f.indexedRange.tailPartialEpoch*100/f.mapsPerEpoch, "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) @@ -283,7 +284,8 @@ func (f *FilterMaps) tryIndexTail() bool { f.lastLogTailIndex = time.Now() } }) - if err != nil { + if err != nil && f.needTailEpoch(firstEpoch-1) { + // stop silently if cutoff point has move beyond epoch boundary while rendering log.Error("Log index tail rendering failed", "error", err) } if !done { @@ -291,10 +293,10 @@ func (f *FilterMaps) tryIndexTail() bool { return false } } - if f.loggedTailIndex { + if f.loggedTailIndex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index tail rendering finished", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "processed", f.ptrTailIndex-f.indexedRange.firstIndexedBlock, + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "processed", f.ptrTailIndex-f.indexedRange.blocks.First(), "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) f.loggedTailIndex = false } @@ -307,7 +309,7 @@ func (f *FilterMaps) tryIndexTail() bool { // data from the database and is also called while running head indexing. func (f *FilterMaps) tryUnindexTail() bool { for { - firstEpoch := (f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch + firstEpoch := (f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch if f.needTailEpoch(firstEpoch) { break } @@ -318,19 +320,19 @@ func (f *FilterMaps) tryUnindexTail() bool { if !f.startedTailUnindex { f.startedTailUnindexAt = time.Now() f.startedTailUnindex = true - f.ptrTailUnindexMap = f.indexedRange.firstRenderedMap - f.indexedRange.tailPartialEpoch - f.ptrTailUnindexBlock = f.indexedRange.firstIndexedBlock - f.tailPartialBlocks() + f.ptrTailUnindexMap = f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch + f.ptrTailUnindexBlock = f.indexedRange.blocks.First() - f.tailPartialBlocks() } if err := f.deleteTailEpoch(firstEpoch); err != nil { log.Error("Log index tail epoch unindexing failed", "error", err) return false } } - if f.startedTailUnindex { + if f.startedTailUnindex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index tail unindexing finished", - "first block", f.indexedRange.firstIndexedBlock, "last block", f.indexedRange.afterLastIndexedBlock-1, - "removed maps", f.indexedRange.firstRenderedMap-f.ptrTailUnindexMap, - "removed blocks", f.indexedRange.firstIndexedBlock-f.tailPartialBlocks()-f.ptrTailUnindexBlock, + "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "removed maps", f.indexedRange.maps.First()-f.ptrTailUnindexMap, + "removed blocks", f.indexedRange.blocks.First()-f.tailPartialBlocks()-f.ptrTailUnindexBlock, "elapsed", common.PrettyDuration(time.Since(f.startedTailUnindexAt))) f.startedTailUnindex = false } @@ -340,23 +342,29 @@ func (f *FilterMaps) tryUnindexTail() bool { // needTailEpoch returns true if the given tail epoch needs to be kept // according to the current tail target, false if it can be removed. func (f *FilterMaps) needTailEpoch(epoch uint32) bool { - firstEpoch := f.indexedRange.firstRenderedMap >> f.logMapsPerEpoch + firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch if epoch > firstEpoch { return true } if epoch+1 < firstEpoch { return false } - tailTarget := f.tailTargetBlock() - if tailTarget < f.indexedRange.firstIndexedBlock { - return true + if epoch > 0 { + lastBlockOfPrevEpoch, _, err := f.getLastBlockOfMap(epoch<= firstEpoch + } + if f.historyCutoff > lastBlockOfPrevEpoch { + return false + } } - tailLvIndex, err := f.getBlockLvPointer(tailTarget) + lastBlockOfEpoch, _, err := f.getLastBlockOfMap((epoch+1)<= firstEpoch } - return uint64(epoch+1)<<(f.logValuesPerMap+f.logMapsPerEpoch) >= tailLvIndex + return f.tailTargetBlock() <= lastBlockOfEpoch } // tailTargetBlock returns the target value for the tail block number according @@ -374,15 +382,15 @@ func (f *FilterMaps) tailPartialBlocks() uint64 { if f.indexedRange.tailPartialEpoch == 0 { return 0 } - end, _, err := f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - 1) + end, _, err := f.getLastBlockOfMap(f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - 1) if err != nil { - log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch-1, "error", err) + log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch-1, "error", err) } var start uint64 - if f.indexedRange.firstRenderedMap-f.mapsPerEpoch > 0 { - start, _, err = f.getLastBlockOfMap(f.indexedRange.firstRenderedMap - f.mapsPerEpoch - 1) + if f.indexedRange.maps.First()-f.mapsPerEpoch > 0 { + start, _, err = f.getLastBlockOfMap(f.indexedRange.maps.First() - f.mapsPerEpoch - 1) if err != nil { - log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.firstRenderedMap-f.mapsPerEpoch-1, "error", err) + log.Error("Error fetching last block of map", "mapIndex", f.indexedRange.maps.First()-f.mapsPerEpoch-1, "error", err) } } return end - start @@ -391,5 +399,5 @@ func (f *FilterMaps) tailPartialBlocks() uint64 { // targetHeadIndexed returns true if the current log index is consistent with // targetView with its head block fully rendered. func (f *FilterMaps) targetHeadIndexed() bool { - return equalViews(f.targetView, f.indexedView) && f.indexedRange.headBlockIndexed + return equalViews(f.targetView, f.indexedView) && f.indexedRange.headIndexed } diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go index 17ad765e0..a02f8d245 100644 --- a/core/filtermaps/indexer_test.go +++ b/core/filtermaps/indexer_test.go @@ -48,16 +48,35 @@ func TestIndexerRandomRange(t *testing.T) { defer ts.close() forks := make([][]common.Hash, 10) - ts.chain.addBlocks(1000, 5, 2, 4, false) // 51 log values per block + ts.chain.addBlocks(1000, 5, 2, 4, false) for i := range forks { if i != 0 { forkBlock := rand.Intn(1000) ts.chain.setHead(forkBlock) - ts.chain.addBlocks(1000-forkBlock, 5, 2, 4, false) // 51 log values per block + ts.chain.addBlocks(1000-forkBlock, 5, 2, 4, false) } forks[i] = ts.chain.getCanonicalChain() } - lvPerBlock := uint64(51) + expspos := func(block uint64) uint64 { // expected position of block start + if block == 0 { + return 0 + } + logCount := (block - 1) * 5 * 2 + mapIndex := logCount / 3 + spos := mapIndex*16 + (logCount%3)*5 + if mapIndex == 0 || logCount%3 != 0 { + spos++ + } + return spos + } + expdpos := func(block uint64) uint64 { // expected position of delimiter + if block == 0 { + return 0 + } + logCount := block * 5 * 2 + mapIndex := (logCount - 1) / 3 + return mapIndex*16 + (logCount-mapIndex*3)*5 + } ts.setHistory(0, false) var ( history int @@ -115,23 +134,26 @@ func TestIndexerRandomRange(t *testing.T) { } var tailEpoch uint32 if tailBlock > 0 { - tailLvPtr := (tailBlock - 1) * lvPerBlock // no logs in genesis block, only delimiter + tailLvPtr := expspos(tailBlock) - 1 tailEpoch = uint32(tailLvPtr >> (testParams.logValuesPerMap + testParams.logMapsPerEpoch)) } + tailLvPtr := uint64(tailEpoch) << (testParams.logValuesPerMap + testParams.logMapsPerEpoch) // first available lv ptr var expTailBlock uint64 if tailEpoch > 0 { - tailLvPtr := uint64(tailEpoch) << (testParams.logValuesPerMap + testParams.logMapsPerEpoch) // first available lv ptr - // (expTailBlock-1)*lvPerBlock >= tailLvPtr - expTailBlock = (tailLvPtr + lvPerBlock*2 - 1) / lvPerBlock + for expspos(expTailBlock) <= tailLvPtr { + expTailBlock++ + } } - if ts.fm.indexedRange.afterLastIndexedBlock != uint64(head+1) { - ts.t.Fatalf("Invalid index head (expected #%d, got #%d)", head, ts.fm.indexedRange.afterLastIndexedBlock-1) + if ts.fm.indexedRange.blocks.Last() != uint64(head) { + ts.t.Fatalf("Invalid index head (expected #%d, got #%d)", head, ts.fm.indexedRange.blocks.Last()) } - if ts.fm.indexedRange.headBlockDelimiter != uint64(head)*lvPerBlock { - ts.t.Fatalf("Invalid index head delimiter pointer (expected %d, got %d)", uint64(head)*lvPerBlock, ts.fm.indexedRange.headBlockDelimiter) + expHeadDelimiter := expdpos(uint64(head)) + if ts.fm.indexedRange.headDelimiter != expHeadDelimiter { + ts.t.Fatalf("Invalid index head delimiter pointer (expected %d, got %d)", expHeadDelimiter, ts.fm.indexedRange.headDelimiter) } - if ts.fm.indexedRange.firstIndexedBlock != expTailBlock { - ts.t.Fatalf("Invalid index tail block (expected #%d, got #%d)", expTailBlock, ts.fm.indexedRange.firstIndexedBlock) + + if ts.fm.indexedRange.blocks.First() != expTailBlock { + ts.t.Fatalf("Invalid index tail block (expected #%d, got #%d)", expTailBlock, ts.fm.indexedRange.blocks.First()) } } } @@ -235,7 +257,7 @@ func (ts *testSetup) setHistory(history uint64, noHistory bool) { History: history, Disabled: noHistory, } - ts.fm = NewFilterMaps(ts.db, view, ts.params, config) + ts.fm = NewFilterMaps(ts.db, view, 0, 0, ts.params, config) ts.fm.testDisableSnapshots = ts.testDisableSnapshots ts.fm.Start() } @@ -420,7 +442,7 @@ func (tc *testChain) setTargetHead() { if tc.ts.fm != nil { if !tc.ts.fm.disabled { //tc.ts.fm.targetViewCh <- NewChainView(tc, head.Number.Uint64(), head.Hash()) - tc.ts.fm.SetTargetView(NewChainView(tc, head.Number.Uint64(), head.Hash())) + tc.ts.fm.SetTarget(NewChainView(tc, head.Number.Uint64(), head.Hash()), 0, 0) } } } diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 5bd48a4b2..4f45a7f2b 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -46,12 +46,12 @@ var ( // mapRenderer represents a process that renders filter maps in a specified // range according to the actual targetView. type mapRenderer struct { - f *FilterMaps - afterLastMap uint32 - currentMap *renderedMap - finishedMaps map[uint32]*renderedMap - firstFinished, afterLastFinished uint32 - iterator *logIterator + f *FilterMaps + renderBefore uint32 + currentMap *renderedMap + finishedMaps map[uint32]*renderedMap + finished common.Range[uint32] + iterator *logIterator } // renderedMap represents a single filter map that is being rendered in memory. @@ -74,22 +74,22 @@ func (r *renderedMap) firstBlock() uint64 { // specified map index boundary, starting from the latest available starting // point that is consistent with the current targetView. // The renderer ensures that filterMapsRange, indexedView and the actual map -// data are always consistent with each other. If afterLastMap is greater than +// data are always consistent with each other. If renderBefore is greater than // the latest existing rendered map then indexedView is updated to targetView, // otherwise it is checked that the rendered range is consistent with both // views. -func (f *FilterMaps) renderMapsBefore(afterLastMap uint32) (*mapRenderer, error) { - nextMap, startBlock, startLvPtr, err := f.lastCanonicalMapBoundaryBefore(afterLastMap) +func (f *FilterMaps) renderMapsBefore(renderBefore uint32) (*mapRenderer, error) { + nextMap, startBlock, startLvPtr, err := f.lastCanonicalMapBoundaryBefore(renderBefore) if err != nil { return nil, err } - if snapshot := f.lastCanonicalSnapshotBefore(afterLastMap); snapshot != nil && snapshot.mapIndex >= nextMap { + if snapshot := f.lastCanonicalSnapshotBefore(renderBefore); snapshot != nil && snapshot.mapIndex >= nextMap { return f.renderMapsFromSnapshot(snapshot) } - if nextMap >= afterLastMap { + if nextMap >= renderBefore { return nil, nil } - return f.renderMapsFromMapBoundary(nextMap, afterLastMap, startBlock, startLvPtr) + return f.renderMapsFromMapBoundary(nextMap, renderBefore, startBlock, startLvPtr) } // renderMapsFromSnapshot creates a mapRenderer that starts rendering from a @@ -108,17 +108,16 @@ func (f *FilterMaps) renderMapsFromSnapshot(cp *renderedMap) (*mapRenderer, erro lastBlock: cp.lastBlock, blockLvPtrs: cp.blockLvPtrs, }, - finishedMaps: make(map[uint32]*renderedMap), - firstFinished: cp.mapIndex, - afterLastFinished: cp.mapIndex, - afterLastMap: math.MaxUint32, - iterator: iter, + finishedMaps: make(map[uint32]*renderedMap), + finished: common.NewRange(cp.mapIndex, 0), + renderBefore: math.MaxUint32, + iterator: iter, }, nil } // renderMapsFromMapBoundary creates a mapRenderer that starts rendering at a // map boundary. -func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, afterLastMap uint32, startBlock, startLvPtr uint64) (*mapRenderer, error) { +func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, renderBefore uint32, startBlock, startLvPtr uint64) (*mapRenderer, error) { iter, err := f.newLogIteratorFromMapBoundary(firstMap, startBlock, startLvPtr) if err != nil { return nil, fmt.Errorf("failed to create log iterator from map boundary %d: %v", firstMap, err) @@ -130,22 +129,21 @@ func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, afterLastMap uint32, st mapIndex: firstMap, lastBlock: iter.blockNumber, }, - finishedMaps: make(map[uint32]*renderedMap), - firstFinished: firstMap, - afterLastFinished: firstMap, - afterLastMap: afterLastMap, - iterator: iter, + finishedMaps: make(map[uint32]*renderedMap), + finished: common.NewRange(firstMap, 0), + renderBefore: renderBefore, + iterator: iter, }, nil } // lastCanonicalSnapshotBefore returns the latest cached snapshot that matches // the current targetView. -func (f *FilterMaps) lastCanonicalSnapshotBefore(afterLastMap uint32) *renderedMap { +func (f *FilterMaps) lastCanonicalSnapshotBefore(renderBefore uint32) *renderedMap { var best *renderedMap for _, blockNumber := range f.renderSnapshots.Keys() { - if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.afterLastIndexedBlock && + if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.blocks.AfterLast() && blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId && - cp.mapIndex < afterLastMap && (best == nil || blockNumber > best.lastBlock) { + cp.mapIndex < renderBefore && (best == nil || blockNumber > best.lastBlock) { best = cp } } @@ -158,11 +156,11 @@ func (f *FilterMaps) lastCanonicalSnapshotBefore(afterLastMap uint32) *renderedM // or the boundary of a currently rendered map. // Along with the next map index where the rendering can be started, the number // and starting log value pointer of the last block is also returned. -func (f *FilterMaps) lastCanonicalMapBoundaryBefore(afterLastMap uint32) (nextMap uint32, startBlock, startLvPtr uint64, err error) { +func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMap uint32, startBlock, startLvPtr uint64, err error) { if !f.indexedRange.initialized { return 0, 0, 0, nil } - mapIndex := afterLastMap + mapIndex := renderBefore for { var ok bool if mapIndex, ok = f.lastMapBoundaryBefore(mapIndex); !ok { @@ -188,18 +186,18 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(afterLastMap uint32) (nextMa // lastMapBoundaryBefore returns the latest map boundary before the specified // map index. func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) { - if !f.indexedRange.initialized || f.indexedRange.afterLastRenderedMap == 0 { + if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 { return 0, false } - if mapIndex > f.indexedRange.afterLastRenderedMap { - mapIndex = f.indexedRange.afterLastRenderedMap + if mapIndex > f.indexedRange.maps.AfterLast() { + mapIndex = f.indexedRange.maps.AfterLast() } - if mapIndex > f.indexedRange.firstRenderedMap { + if mapIndex > f.indexedRange.maps.First() { return mapIndex - 1, true } - if mapIndex+f.mapsPerEpoch > f.indexedRange.firstRenderedMap { - if mapIndex > f.indexedRange.firstRenderedMap-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch { - mapIndex = f.indexedRange.firstRenderedMap - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch + if mapIndex+f.mapsPerEpoch > f.indexedRange.maps.First() { + if mapIndex > f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch { + mapIndex = f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch } } else { mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch @@ -218,19 +216,19 @@ func (f *FilterMaps) emptyFilterMap() filterMap { // loadHeadSnapshot loads the last rendered map from the database and creates // a snapshot. func (f *FilterMaps) loadHeadSnapshot() error { - fm, err := f.getFilterMap(f.indexedRange.afterLastRenderedMap - 1) + fm, err := f.getFilterMap(f.indexedRange.maps.Last()) if err != nil { - return fmt.Errorf("failed to load head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err) + return fmt.Errorf("failed to load head snapshot map %d: %v", f.indexedRange.maps.Last(), err) } - lastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 1) + lastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.maps.Last()) if err != nil { - return fmt.Errorf("failed to retrieve last block of head snapshot map %d: %v", f.indexedRange.afterLastRenderedMap-1, err) + return fmt.Errorf("failed to retrieve last block of head snapshot map %d: %v", f.indexedRange.maps.Last(), err) } var firstBlock uint64 - if f.indexedRange.afterLastRenderedMap > 1 { - prevLastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.afterLastRenderedMap - 2) + if f.indexedRange.maps.AfterLast() > 1 { + prevLastBlock, _, err := f.getLastBlockOfMap(f.indexedRange.maps.Last() - 1) if err != nil { - return fmt.Errorf("failed to retrieve last block of map %d before head snapshot: %v", f.indexedRange.afterLastRenderedMap-2, err) + return fmt.Errorf("failed to retrieve last block of map %d before head snapshot: %v", f.indexedRange.maps.Last()-1, err) } firstBlock = prevLastBlock + 1 } @@ -241,14 +239,14 @@ func (f *FilterMaps) loadHeadSnapshot() error { return fmt.Errorf("failed to retrieve log value pointer of head snapshot block %d: %v", firstBlock+uint64(i), err) } } - f.renderSnapshots.Add(f.indexedRange.afterLastIndexedBlock-1, &renderedMap{ + f.renderSnapshots.Add(f.indexedRange.blocks.Last(), &renderedMap{ filterMap: fm, - mapIndex: f.indexedRange.afterLastRenderedMap - 1, - lastBlock: f.indexedRange.afterLastIndexedBlock - 1, - lastBlockId: f.indexedView.getBlockId(f.indexedRange.afterLastIndexedBlock - 1), + mapIndex: f.indexedRange.maps.Last(), + lastBlock: f.indexedRange.blocks.Last(), + lastBlockId: f.indexedView.getBlockId(f.indexedRange.blocks.Last()), blockLvPtrs: lvPtrs, finished: true, - headDelimiter: f.indexedRange.headBlockDelimiter, + headDelimiter: f.indexedRange.headDelimiter, }) return nil } @@ -277,14 +275,14 @@ func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) { } // map finished r.finishedMaps[r.currentMap.mapIndex] = r.currentMap - r.afterLastFinished++ - if len(r.finishedMaps) >= maxMapsPerBatch || r.afterLastFinished&(r.f.baseRowGroupLength-1) == 0 { + r.finished.SetLast(r.finished.AfterLast()) + if len(r.finishedMaps) >= maxMapsPerBatch || r.finished.AfterLast()&(r.f.baseRowGroupLength-1) == 0 { if err := r.writeFinishedMaps(stopCb); err != nil { return false, err } writeCb() } - if r.afterLastFinished == r.afterLastMap || r.iterator.finished { + if r.finished.AfterLast() == r.renderBefore || r.iterator.finished { if err := r.writeFinishedMaps(stopCb); err != nil { return false, err } @@ -293,7 +291,7 @@ func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) { } r.currentMap = &renderedMap{ filterMap: r.f.emptyFilterMap(), - mapIndex: r.afterLastFinished, + mapIndex: r.finished.AfterLast(), } } } @@ -323,11 +321,6 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { } waitCnt = 0 } - r.currentMap.lastBlock = r.iterator.blockNumber - if r.iterator.delimiter { - r.currentMap.lastBlock++ - r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex+1) - } if logValue := r.iterator.getValueHash(); logValue != (common.Hash{}) { lvp, cached := rowMappingCache.Get(logValue) if !cached { @@ -346,9 +339,15 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { if err := r.iterator.next(); err != nil { return false, fmt.Errorf("failed to advance log iterator at %d while rendering map %d: %v", r.iterator.lvIndex, r.currentMap.mapIndex, err) } - if !r.f.testDisableSnapshots && r.afterLastMap >= r.f.indexedRange.afterLastRenderedMap && - (r.iterator.delimiter || r.iterator.finished) { - r.makeSnapshot() + if !r.iterator.skipToBoundary { + r.currentMap.lastBlock = r.iterator.blockNumber + if r.iterator.blockStart { + r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex) + } + if !r.f.testDisableSnapshots && r.renderBefore >= r.f.indexedRange.maps.AfterLast() && + (r.iterator.delimiter || r.iterator.finished) { + r.makeSnapshot() + } } } if r.iterator.finished { @@ -402,7 +401,7 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { mapIndices []uint32 rows []FilterRow ) - for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + for mapIndex := range r.finished.Iter() { row := r.finishedMaps[mapIndex].filterMap[rowIndex] if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && row.Equal(fm[rowIndex]) { continue @@ -410,8 +409,8 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { mapIndices = append(mapIndices, mapIndex) rows = append(rows, row) } - if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries - for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + if newRange.maps.AfterLast() == r.finished.AfterLast() { // head updated; remove future entries + for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ { if fm, _ := r.f.filterMapCache.Get(mapIndex); fm != nil && len(fm[rowIndex]) == 0 { continue } @@ -425,24 +424,24 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { checkWriteCnt() } // update filter map cache - if newRange.afterLastRenderedMap == r.afterLastFinished { + if newRange.maps.AfterLast() == r.finished.AfterLast() { // head updated; cache new head maps and remove future entries - for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + for mapIndex := range r.finished.Iter() { r.f.filterMapCache.Add(mapIndex, r.finishedMaps[mapIndex].filterMap) } - for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ { r.f.filterMapCache.Remove(mapIndex) } } else { // head not updated; do not cache maps during tail rendering because we // need head maps to be available in the cache - for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + for mapIndex := range r.finished.Iter() { r.f.filterMapCache.Remove(mapIndex) } } // add or update block pointers - blockNumber := r.finishedMaps[r.firstFinished].firstBlock() - for mapIndex := r.firstFinished; mapIndex < r.afterLastFinished; mapIndex++ { + blockNumber := r.finishedMaps[r.finished.First()].firstBlock() + for mapIndex := range r.finished.Iter() { renderedMap := r.finishedMaps[mapIndex] r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId) checkWriteCnt() @@ -455,18 +454,18 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { blockNumber++ } } - if newRange.afterLastRenderedMap == r.afterLastFinished { // head updated; remove future entries - for mapIndex := r.afterLastFinished; mapIndex < oldRange.afterLastRenderedMap; mapIndex++ { + if newRange.maps.AfterLast() == r.finished.AfterLast() { // head updated; remove future entries + for mapIndex := r.finished.AfterLast(); mapIndex < oldRange.maps.AfterLast(); mapIndex++ { r.f.deleteLastBlockOfMap(batch, mapIndex) checkWriteCnt() } - for ; blockNumber < oldRange.afterLastIndexedBlock; blockNumber++ { + for ; blockNumber < oldRange.blocks.AfterLast(); blockNumber++ { r.f.deleteBlockLvPointer(batch, blockNumber) checkWriteCnt() } } r.finishedMaps = make(map[uint32]*renderedMap) - r.firstFinished = r.afterLastFinished + r.finished.SetFirst(r.finished.AfterLast()) r.f.setRange(batch, renderedView, newRange) if err := batch.Write(); err != nil { log.Crit("Error writing log index update batch", "error", err) @@ -481,33 +480,33 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { // range to the unchanged region until all new map data is committed. func (r *mapRenderer) getTempRange() (filterMapsRange, error) { tempRange := r.f.indexedRange - if err := tempRange.addRenderedRange(r.firstFinished, r.firstFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil { + if err := tempRange.addRenderedRange(r.finished.First(), r.finished.First(), r.renderBefore, r.f.mapsPerEpoch); err != nil { return filterMapsRange{}, fmt.Errorf("failed to update temporary rendered range: %v", err) } - if tempRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap { + if tempRange.maps.First() != r.f.indexedRange.maps.First() { // first rendered map changed; update first indexed block - if tempRange.firstRenderedMap > 0 { - lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.firstRenderedMap - 1) + if tempRange.maps.First() > 0 { + firstBlock, _, err := r.f.getLastBlockOfMap(tempRange.maps.First() - 1) if err != nil { - return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before temporary range: %v", tempRange.firstRenderedMap-1, err) + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before temporary range: %v", tempRange.maps.First()-1, err) } - tempRange.firstIndexedBlock = lastBlock + 1 + tempRange.blocks.SetFirst(firstBlock + 1) // firstBlock is probably partially rendered } else { - tempRange.firstIndexedBlock = 0 + tempRange.blocks.SetFirst(0) } } - if tempRange.afterLastRenderedMap != r.f.indexedRange.afterLastRenderedMap { - // first rendered map changed; update first indexed block - if tempRange.afterLastRenderedMap > 0 { - lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.afterLastRenderedMap - 1) + if tempRange.maps.AfterLast() != r.f.indexedRange.maps.AfterLast() { + // last rendered map changed; update last indexed block + if !tempRange.maps.IsEmpty() { + lastBlock, _, err := r.f.getLastBlockOfMap(tempRange.maps.Last()) if err != nil { - return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d at the end of temporary range: %v", tempRange.afterLastRenderedMap-1, err) + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d at the end of temporary range: %v", tempRange.maps.Last(), err) } - tempRange.afterLastIndexedBlock = lastBlock + tempRange.blocks.SetAfterLast(lastBlock) // lastBlock is probably partially rendered } else { - tempRange.afterLastIndexedBlock = 0 + tempRange.blocks.SetAfterLast(0) } - tempRange.headBlockDelimiter = 0 + tempRange.headDelimiter = 0 } return tempRange, nil } @@ -517,39 +516,39 @@ func (r *mapRenderer) getTempRange() (filterMapsRange, error) { func (r *mapRenderer) getUpdatedRange() (filterMapsRange, error) { // update filterMapsRange newRange := r.f.indexedRange - if err := newRange.addRenderedRange(r.firstFinished, r.afterLastFinished, r.afterLastMap, r.f.mapsPerEpoch); err != nil { + if err := newRange.addRenderedRange(r.finished.First(), r.finished.AfterLast(), r.renderBefore, r.f.mapsPerEpoch); err != nil { return filterMapsRange{}, fmt.Errorf("failed to update rendered range: %v", err) } - if newRange.firstRenderedMap != r.f.indexedRange.firstRenderedMap { + if newRange.maps.First() != r.f.indexedRange.maps.First() { // first rendered map changed; update first indexed block - if newRange.firstRenderedMap > 0 { - lastBlock, _, err := r.f.getLastBlockOfMap(newRange.firstRenderedMap - 1) + if newRange.maps.First() > 0 { + firstBlock, _, err := r.f.getLastBlockOfMap(newRange.maps.First() - 1) if err != nil { - return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before rendered range: %v", newRange.firstRenderedMap-1, err) + return filterMapsRange{}, fmt.Errorf("failed to retrieve last block of map %d before rendered range: %v", newRange.maps.First()-1, err) } - newRange.firstIndexedBlock = lastBlock + 1 + newRange.blocks.SetFirst(firstBlock + 1) // firstBlock is probably partially rendered } else { - newRange.firstIndexedBlock = 0 + newRange.blocks.SetFirst(0) } } - if newRange.afterLastRenderedMap == r.afterLastFinished { + if newRange.maps.AfterLast() == r.finished.AfterLast() { // last rendered map changed; update last indexed block and head pointers - lm := r.finishedMaps[r.afterLastFinished-1] - newRange.headBlockIndexed = lm.finished + lm := r.finishedMaps[r.finished.Last()] + newRange.headIndexed = lm.finished if lm.finished { - newRange.afterLastIndexedBlock = r.f.targetView.headNumber + 1 + newRange.blocks.SetLast(r.f.targetView.headNumber) if lm.lastBlock != r.f.targetView.headNumber { panic("map rendering finished but last block != head block") } - newRange.headBlockDelimiter = lm.headDelimiter + newRange.headDelimiter = lm.headDelimiter } else { - newRange.afterLastIndexedBlock = lm.lastBlock - newRange.headBlockDelimiter = 0 + newRange.blocks.SetAfterLast(lm.lastBlock) // lastBlock is probably partially rendered + newRange.headDelimiter = 0 } } else { // last rendered map not replaced; ensure that target chain view matches // indexed chain view on the rendered section - if lastBlock := r.finishedMaps[r.afterLastFinished-1].lastBlock; !matchViews(r.f.indexedView, r.f.targetView, lastBlock) { + if lastBlock := r.finishedMaps[r.finished.Last()].lastBlock; !matchViews(r.f.indexedView, r.f.targetView, lastBlock) { return filterMapsRange{}, errChainUpdate } } @@ -571,9 +570,9 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a m uint32 d int } - endpoints := []endpoint{{fmr.firstRenderedMap, 1}, {fmr.afterLastRenderedMap, -1}, {firstRendered, 1}, {afterLastRendered, -101}, {afterLastRemoved, 100}} + endpoints := []endpoint{{fmr.maps.First(), 1}, {fmr.maps.AfterLast(), -1}, {firstRendered, 1}, {afterLastRendered, -101}, {afterLastRemoved, 100}} if fmr.tailPartialEpoch > 0 { - endpoints = append(endpoints, []endpoint{{fmr.firstRenderedMap - mapsPerEpoch, 1}, {fmr.firstRenderedMap - mapsPerEpoch + fmr.tailPartialEpoch, -1}}...) + endpoints = append(endpoints, []endpoint{{fmr.maps.First() - mapsPerEpoch, 1}, {fmr.maps.First() - mapsPerEpoch + fmr.tailPartialEpoch, -1}}...) } sort.Slice(endpoints, func(i, j int) bool { return endpoints[i].m < endpoints[j].m }) var ( @@ -596,14 +595,12 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a case 0: // Initialized database, but no finished maps yet. fmr.tailPartialEpoch = 0 - fmr.firstRenderedMap = firstRendered - fmr.afterLastRenderedMap = firstRendered + fmr.maps = common.NewRange(firstRendered, 0) case 2: // One rendered section (no partial tail epoch). fmr.tailPartialEpoch = 0 - fmr.firstRenderedMap = merged[0] - fmr.afterLastRenderedMap = merged[1] + fmr.maps = common.NewRange(merged[0], merged[1]-merged[0]) case 4: // Two rendered sections (with a gap). @@ -613,8 +610,7 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a return fmt.Errorf("invalid tail partial epoch: %v", merged) } fmr.tailPartialEpoch = merged[1] - merged[0] - fmr.firstRenderedMap = merged[2] - fmr.afterLastRenderedMap = merged[3] + fmr.maps = common.NewRange(merged[2], merged[3]-merged[2]) default: return fmt.Errorf("invalid number of rendered sections: %v", merged) @@ -624,12 +620,13 @@ func (fmr *filterMapsRange) addRenderedRange(firstRendered, afterLastRendered, a // logIterator iterates on the linear log value index range. type logIterator struct { - chainView *ChainView - blockNumber uint64 - receipts types.Receipts - blockStart, delimiter, finished bool - txIndex, logIndex, topicIndex int - lvIndex uint64 + params *Params + chainView *ChainView + blockNumber uint64 + receipts types.Receipts + blockStart, delimiter, skipToBoundary, finished bool + txIndex, logIndex, topicIndex int + lvIndex uint64 } var errUnindexedRange = errors.New("unindexed range") @@ -641,12 +638,12 @@ func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logI if blockNumber > f.targetView.headNumber { return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.headNumber) } - if blockNumber < f.indexedRange.firstIndexedBlock || blockNumber >= f.indexedRange.afterLastIndexedBlock { + if !f.indexedRange.blocks.Includes(blockNumber) { return nil, errUnindexedRange } var lvIndex uint64 - if f.indexedRange.headBlockIndexed && blockNumber+1 == f.indexedRange.afterLastIndexedBlock { - lvIndex = f.indexedRange.headBlockDelimiter + if f.indexedRange.headIndexed && blockNumber+1 == f.indexedRange.blocks.AfterLast() { + lvIndex = f.indexedRange.headDelimiter } else { var err error lvIndex, err = f.getBlockLvPointer(blockNumber + 1) @@ -656,13 +653,16 @@ func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logI lvIndex-- } finished := blockNumber == f.targetView.headNumber - return &logIterator{ + l := &logIterator{ chainView: f.targetView, + params: &f.Params, blockNumber: blockNumber, finished: finished, delimiter: !finished, lvIndex: lvIndex, - }, nil + } + l.enforceValidState() + return l, nil } // newLogIteratorFromMapBoundary creates a logIterator starting at the given @@ -679,12 +679,13 @@ func (f *FilterMaps) newLogIteratorFromMapBoundary(mapIndex uint32, startBlock, // initialize iterator at block start l := &logIterator{ chainView: f.targetView, + params: &f.Params, blockNumber: startBlock, receipts: receipts, blockStart: true, lvIndex: startLvPtr, } - l.nextValid() + l.enforceValidState() targetIndex := uint64(mapIndex) << f.logValuesPerMap if l.lvIndex > targetIndex { return nil, fmt.Errorf("log value pointer %d of last block of map is after map boundary %d", l.lvIndex, targetIndex) @@ -713,7 +714,7 @@ func (l *logIterator) updateChainView(cv *ChainView) bool { // getValueHash returns the log value hash at the current position. func (l *logIterator) getValueHash() common.Hash { - if l.delimiter || l.finished { + if l.delimiter || l.finished || l.skipToBoundary { return common.Hash{} } log := l.receipts[l.txIndex].Logs[l.logIndex] @@ -725,6 +726,13 @@ func (l *logIterator) getValueHash() common.Hash { // next moves the iterator to the next log value index. func (l *logIterator) next() error { + if l.skipToBoundary { + l.lvIndex++ + if l.lvIndex%l.params.valuesPerMap == 0 { + l.skipToBoundary = false + } + return nil + } if l.finished { return nil } @@ -741,18 +749,26 @@ func (l *logIterator) next() error { l.blockStart = false } l.lvIndex++ - l.nextValid() + l.enforceValidState() return nil } -// nextValid updates the internal transaction, log and topic index pointers +// enforceValidState updates the internal transaction, log and topic index pointers // to the next existing log value of the given block if necessary. -// Note that nextValid does not advance the log value index pointer. -func (l *logIterator) nextValid() { +// Note that enforceValidState does not advance the log value index pointer. +func (l *logIterator) enforceValidState() { + if l.delimiter || l.finished || l.skipToBoundary { + return + } for ; l.txIndex < len(l.receipts); l.txIndex++ { receipt := l.receipts[l.txIndex] for ; l.logIndex < len(receipt.Logs); l.logIndex++ { log := receipt.Logs[l.logIndex] + if l.topicIndex == 0 && uint64(len(log.Topics)+1) > l.params.valuesPerMap-l.lvIndex%l.params.valuesPerMap { + // next log would be split by map boundary; skip to boundary + l.skipToBoundary = true + return + } if l.topicIndex <= len(log.Topics) { return } diff --git a/core/filtermaps/matcher.go b/core/filtermaps/matcher.go index 19acbd762..6c05672cb 100644 --- a/core/filtermaps/matcher.go +++ b/core/filtermaps/matcher.go @@ -61,11 +61,9 @@ type SyncRange struct { // block range where the index has not changed since the last matcher sync // and therefore the set of matches found in this region is guaranteed to // be valid and complete. - Valid bool - FirstValid, LastValid uint64 + ValidBlocks common.Range[uint64] // block range indexed according to the given chain head. - Indexed bool - FirstIndexed, LastIndexed uint64 + IndexedBlocks common.Range[uint64] } // GetPotentialMatches returns a list of logs that are potential matches for the @@ -75,7 +73,6 @@ type SyncRange struct { // Also note that the returned list may contain false positives. func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock, lastBlock uint64, addresses []common.Address, topics [][]common.Hash) ([]*types.Log, error) { params := backend.GetParams() - var getLogStats runtimeStats // find the log value index range to search firstIndex, err := backend.GetBlockLvPointer(ctx, firstBlock) if err != nil { @@ -88,8 +85,6 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock if lastIndex > 0 { lastIndex-- } - firstMap, lastMap := uint32(firstIndex>>params.logValuesPerMap), uint32(lastIndex>>params.logValuesPerMap) - firstEpoch, lastEpoch := firstMap>>params.logMapsPerEpoch, lastMap>>params.logMapsPerEpoch // build matcher according to the given filter criteria matchers := make([]matcher, len(topics)+1) @@ -117,45 +112,45 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock // matchers signal a match for consecutive log value indices. matcher := newMatchSequence(params, matchers) - // processEpoch returns the potentially matching logs from the given epoch. - processEpoch := func(epochIndex uint32) ([]*types.Log, error) { - var logs []*types.Log - // create a list of map indices to process - fm, lm := epochIndex< lastMap { - lm = lastMap - } - // - mapIndices := make([]uint32, lm+1-fm) - for i := range mapIndices { - mapIndices[i] = fm + uint32(i) - } - // find potential matches - matches, err := getAllMatches(ctx, matcher, mapIndices) - if err != nil { - return logs, err - } - // get the actual logs located at the matching log value indices - var st int - getLogStats.setState(&st, stGetLog) - defer getLogStats.setState(&st, stNone) - for _, m := range matches { - if m == nil { - return nil, ErrMatchAll - } - mlogs, err := getLogsFromMatches(ctx, backend, firstIndex, lastIndex, m) - if err != nil { - return logs, err + m := &matcherEnv{ + ctx: ctx, + backend: backend, + params: params, + matcher: matcher, + firstIndex: firstIndex, + lastIndex: lastIndex, + firstMap: uint32(firstIndex >> params.logValuesPerMap), + lastMap: uint32(lastIndex >> params.logValuesPerMap), + } + + start := time.Now() + res, err := m.process() + + if doRuntimeStats { + log.Info("Log search finished", "elapsed", time.Since(start)) + for i, ma := range matchers { + for j, m := range ma.(matchAny) { + log.Info("Single matcher stats", "matchSequence", i, "matchAny", j) + m.(*singleMatcher).stats.print() } - logs = append(logs, mlogs...) } - getLogStats.addAmount(st, int64(len(logs))) - return logs, nil + log.Info("Get log stats") + m.getLogStats.print() } + return res, err +} +type matcherEnv struct { + getLogStats runtimeStats // 64 bit aligned + ctx context.Context + backend MatcherBackend + params *Params + matcher matcher + firstIndex, lastIndex uint64 + firstMap, lastMap uint32 +} + +func (m *matcherEnv) process() ([]*types.Log, error) { type task struct { epochIndex uint32 logs []*types.Log @@ -175,18 +170,18 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock if task == nil { break } - task.logs, task.err = processEpoch(task.epochIndex) + task.logs, task.err = m.processEpoch(task.epochIndex) close(task.done) } wg.Done() } - start := time.Now() - for i := 0; i < 4; i++ { + for range 4 { wg.Add(1) go worker() } + firstEpoch, lastEpoch := m.firstMap>>m.params.logMapsPerEpoch, m.lastMap>>m.params.logMapsPerEpoch var logs []*types.Log // startEpoch is the next task to send whenever a worker can accept it. // waitEpoch is the next task we are waiting for to finish in order to append @@ -220,30 +215,58 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock } } } - if doRuntimeStats { - log.Info("Log search finished", "elapsed", time.Since(start)) - for i, ma := range matchers { - for j, m := range ma.(matchAny) { - log.Info("Single matcher stats", "matchSequence", i, "matchAny", j) - m.(*singleMatcher).stats.print() - } + return logs, nil +} + +// processEpoch returns the potentially matching logs from the given epoch. +func (m *matcherEnv) processEpoch(epochIndex uint32) ([]*types.Log, error) { + var logs []*types.Log + // create a list of map indices to process + fm, lm := epochIndex< m.lastMap { + lm = m.lastMap + } + // + mapIndices := make([]uint32, lm+1-fm) + for i := range mapIndices { + mapIndices[i] = fm + uint32(i) + } + // find potential matches + matches, err := m.getAllMatches(mapIndices) + if err != nil { + return logs, err + } + // get the actual logs located at the matching log value indices + var st int + m.getLogStats.setState(&st, stGetLog) + defer m.getLogStats.setState(&st, stNone) + for _, match := range matches { + if match == nil { + return nil, ErrMatchAll } - log.Info("Get log stats") - getLogStats.print() + mlogs, err := m.getLogsFromMatches(match) + if err != nil { + return logs, err + } + logs = append(logs, mlogs...) } + m.getLogStats.addAmount(st, int64(len(logs))) return logs, nil } // getLogsFromMatches returns the list of potentially matching logs located at // the given list of matching log indices. Matches outside the firstIndex to // lastIndex range are not returned. -func getLogsFromMatches(ctx context.Context, backend MatcherBackend, firstIndex, lastIndex uint64, matches potentialMatches) ([]*types.Log, error) { +func (m *matcherEnv) getLogsFromMatches(matches potentialMatches) ([]*types.Log, error) { var logs []*types.Log for _, match := range matches { - if match < firstIndex || match > lastIndex { + if match < m.firstIndex || match > m.lastIndex { continue } - log, err := backend.GetLogByLvIndex(ctx, match) + log, err := m.backend.GetLogByLvIndex(m.ctx, match) if err != nil { return logs, fmt.Errorf("failed to retrieve log at index %d: %v", match, err) } @@ -254,6 +277,28 @@ func getLogsFromMatches(ctx context.Context, backend MatcherBackend, firstIndex, return logs, nil } +// getAllMatches creates an instance for a given matcher and set of map indices, +// iterates through mapping layers and collects all results, then returns all +// results in the same order as the map indices were specified. +func (m *matcherEnv) getAllMatches(mapIndices []uint32) ([]potentialMatches, error) { + instance := m.matcher.newInstance(mapIndices) + resultsMap := make(map[uint32]potentialMatches) + for layerIndex := uint32(0); len(resultsMap) < len(mapIndices); layerIndex++ { + results, err := instance.getMatchesForLayer(m.ctx, layerIndex) + if err != nil { + return nil, err + } + for _, result := range results { + resultsMap[result.mapIndex] = result.matches + } + } + matches := make([]potentialMatches, len(mapIndices)) + for i, mapIndex := range mapIndices { + matches[i] = resultsMap[mapIndex] + } + return matches, nil +} + // matcher defines a general abstraction for any matcher configuration that // can instantiate a matcherInstance. type matcher interface { @@ -281,28 +326,6 @@ type matcherResult struct { matches potentialMatches } -// getAllMatches creates an instance for a given matcher and set of map indices, -// iterates through mapping layers and collects all results, then returns all -// results in the same order as the map indices were specified. -func getAllMatches(ctx context.Context, matcher matcher, mapIndices []uint32) ([]potentialMatches, error) { - instance := matcher.newInstance(mapIndices) - resultsMap := make(map[uint32]potentialMatches) - for layerIndex := uint32(0); len(resultsMap) < len(mapIndices); layerIndex++ { - results, err := instance.getMatchesForLayer(ctx, layerIndex) - if err != nil { - return nil, err - } - for _, result := range results { - resultsMap[result.mapIndex] = result.matches - } - } - matches := make([]potentialMatches, len(mapIndices)) - for i, mapIndex := range mapIndices { - matches[i] = resultsMap[mapIndex] - } - return matches, nil -} - // singleMatcher implements matcher by returning matches for a single log value hash. type singleMatcher struct { backend MatcherBackend @@ -550,24 +573,18 @@ type matchSequence struct { // newInstance creates a new instance of matchSequence. func (m *matchSequence) newInstance(mapIndices []uint32) matcherInstance { // determine set of indices to request from next matcher - nextIndices := make([]uint32, 0, len(mapIndices)*3/2) needMatched := make(map[uint32]struct{}) baseRequested := make(map[uint32]struct{}) nextRequested := make(map[uint32]struct{}) for _, mapIndex := range mapIndices { needMatched[mapIndex] = struct{}{} baseRequested[mapIndex] = struct{}{} - if _, ok := nextRequested[mapIndex]; !ok { - nextIndices = append(nextIndices, mapIndex) - nextRequested[mapIndex] = struct{}{} - } - nextIndices = append(nextIndices, mapIndex+1) - nextRequested[mapIndex+1] = struct{}{} + nextRequested[mapIndex] = struct{}{} } return &matchSequenceInstance{ matchSequence: m, baseInstance: m.base.newInstance(mapIndices), - nextInstance: m.next.newInstance(nextIndices), + nextInstance: m.next.newInstance(mapIndices), needMatched: needMatched, baseRequested: baseRequested, nextRequested: nextRequested, @@ -687,12 +704,9 @@ func (m *matchSequenceInstance) getMatchesForLayer(ctx context.Context, layerInd if _, ok := m.nextRequested[mapIndex]; ok { continue } - if _, ok := m.nextRequested[mapIndex+1]; ok { - continue - } matchedResults = append(matchedResults, matcherResult{ mapIndex: mapIndex, - matches: m.params.matchResults(mapIndex, m.offset, m.baseResults[mapIndex], m.nextResults[mapIndex], m.nextResults[mapIndex+1]), + matches: m.params.matchResults(mapIndex, m.offset, m.baseResults[mapIndex], m.nextResults[mapIndex]), }) delete(m.needMatched, mapIndex) } @@ -715,9 +729,6 @@ func (m *matchSequenceInstance) dropIndices(dropIndices []uint32) { if m.dropNext(mapIndex) { dropNext = append(dropNext, mapIndex) } - if m.dropNext(mapIndex + 1) { - dropNext = append(dropNext, mapIndex+1) - } } m.nextInstance.dropIndices(dropNext) } @@ -743,9 +754,6 @@ func (m *matchSequenceInstance) evalBase(ctx context.Context, layerIndex uint32) if m.dropNext(r.mapIndex) { dropIndices = append(dropIndices, r.mapIndex) } - if m.dropNext(r.mapIndex + 1) { - dropIndices = append(dropIndices, r.mapIndex+1) - } } if len(dropIndices) > 0 { m.nextInstance.dropIndices(dropIndices) @@ -771,9 +779,6 @@ func (m *matchSequenceInstance) evalNext(ctx context.Context, layerIndex uint32) } m.mergeNextStats(stats) for _, r := range results { - if r.mapIndex > 0 && m.dropBase(r.mapIndex-1) { - dropIndices = append(dropIndices, r.mapIndex-1) - } if m.dropBase(r.mapIndex) { dropIndices = append(dropIndices, r.mapIndex) } @@ -792,12 +797,7 @@ func (m *matchSequenceInstance) dropBase(mapIndex uint32) bool { return false } if _, ok := m.needMatched[mapIndex]; ok { - if next := m.nextResults[mapIndex]; next == nil || - (len(next) > 0 && next[len(next)-1] >= (uint64(mapIndex)< 0 && nextNext[0] < (uint64(mapIndex+1)< 0 { return false } } @@ -812,15 +812,8 @@ func (m *matchSequenceInstance) dropNext(mapIndex uint32) bool { if _, ok := m.nextRequested[mapIndex]; !ok { return false } - if _, ok := m.needMatched[mapIndex-1]; ok { - if prevBase := m.baseResults[mapIndex-1]; prevBase == nil || - (len(prevBase) > 0 && prevBase[len(prevBase)-1]+m.offset >= (uint64(mapIndex)< 0 && base[0]+m.offset < (uint64(mapIndex+1)< 0 { return false } } @@ -833,59 +826,39 @@ func (m *matchSequenceInstance) dropNext(mapIndex uint32) bool { // results at mapIndex and mapIndex+1. Note that acquiring nextNextRes may be // skipped and it can be substituted with an empty list if baseRes has no potential // matches that could be sequence matched with anything that could be in nextNextRes. -func (params *Params) matchResults(mapIndex uint32, offset uint64, baseRes, nextRes, nextNextRes potentialMatches) potentialMatches { +func (params *Params) matchResults(mapIndex uint32, offset uint64, baseRes, nextRes potentialMatches) potentialMatches { if nextRes == nil || (baseRes != nil && len(baseRes) == 0) { // if nextRes is a wild card or baseRes is empty then the sequence matcher // result equals baseRes. return baseRes } - if len(nextRes) > 0 { - // discard items from nextRes whose corresponding base matcher results - // with the negative offset applied would be located at mapIndex-1. - start := 0 - for start < len(nextRes) && nextRes[start] < uint64(mapIndex)< 0 { - // discard items from nextNextRes whose corresponding base matcher results - // with the negative offset applied would still be located at mapIndex+1. - stop := 0 - for stop < len(nextNextRes) && nextNextRes[stop] < uint64(mapIndex+1)<= min { + result = append(result, v-offset) + } } - nextNextRes = nextNextRes[:stop] - } - maxLen := len(nextRes) + len(nextNextRes) - if maxLen == 0 { - return nextRes + return result } - if len(baseRes) < maxLen { - maxLen = len(baseRes) + // iterate through baseRes and nextRes in parallel and collect matching results. + maxLen := len(baseRes) + if l := len(nextRes); l < maxLen { + maxLen = l } - // iterate through baseRes, nextRes and nextNextRes and collect matching results. matchedRes := make(potentialMatches, 0, maxLen) - for _, nextRes := range []potentialMatches{nextRes, nextNextRes} { - if baseRes != nil { - for len(nextRes) > 0 && len(baseRes) > 0 { - if nextRes[0] > baseRes[0]+offset { - baseRes = baseRes[1:] - } else if nextRes[0] < baseRes[0]+offset { - nextRes = nextRes[1:] - } else { - matchedRes = append(matchedRes, baseRes[0]) - baseRes = baseRes[1:] - nextRes = nextRes[1:] - } - } + for len(nextRes) > 0 && len(baseRes) > 0 { + if nextRes[0] > baseRes[0]+offset { + baseRes = baseRes[1:] + } else if nextRes[0] < baseRes[0]+offset { + nextRes = nextRes[1:] } else { - // baseRes is a wild card so just return next matcher results with - // negative offset. - for len(nextRes) > 0 { - matchedRes = append(matchedRes, nextRes[0]-offset) - nextRes = nextRes[1:] - } + matchedRes = append(matchedRes, baseRes[0]) + baseRes = baseRes[1:] + nextRes = nextRes[1:] } } return matchedRes diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index 66f95f214..4c4668e32 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -19,6 +19,7 @@ package filtermaps import ( "context" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) @@ -27,9 +28,8 @@ type FilterMapsMatcherBackend struct { f *FilterMaps // these fields should be accessed under f.matchersLock mutex. - valid bool - firstValid, lastValid uint64 - syncCh chan SyncRange + validBlocks common.Range[uint64] + syncCh chan SyncRange } // NewMatcherBackend returns a FilterMapsMatcherBackend after registering it in @@ -43,11 +43,9 @@ func (f *FilterMaps) NewMatcherBackend() *FilterMapsMatcherBackend { f.indexLock.RUnlock() }() - fm := &FilterMapsMatcherBackend{ - f: f, - valid: f.indexedRange.initialized && f.indexedRange.afterLastIndexedBlock > f.indexedRange.firstIndexedBlock, - firstValid: f.indexedRange.firstIndexedBlock, - lastValid: f.indexedRange.afterLastIndexedBlock - 1, + fm := &FilterMapsMatcherBackend{f: f} + if f.indexedRange.initialized { + fm.validBlocks = f.indexedRange.blocks } f.matchers[fm] = struct{}{} return fm @@ -122,28 +120,16 @@ func (fm *FilterMapsMatcherBackend) synced() { fm.f.indexLock.RUnlock() }() - var ( - indexed bool - lastIndexed, subLastIndexed uint64 - ) - if !fm.f.indexedRange.headBlockIndexed { - subLastIndexed = 1 - } - if fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed > fm.f.indexedRange.firstIndexedBlock { - indexed, lastIndexed = true, fm.f.indexedRange.afterLastIndexedBlock-subLastIndexed-1 + indexedBlocks := fm.f.indexedRange.blocks + if !fm.f.indexedRange.headIndexed && !indexedBlocks.IsEmpty() { + indexedBlocks.SetAfterLast(indexedBlocks.Last()) // remove partially indexed last block } fm.syncCh <- SyncRange{ - HeadNumber: fm.f.indexedView.headNumber, - Valid: fm.valid, - FirstValid: fm.firstValid, - LastValid: fm.lastValid, - Indexed: indexed, - FirstIndexed: fm.f.indexedRange.firstIndexedBlock, - LastIndexed: lastIndexed, + HeadNumber: fm.f.indexedView.headNumber, + ValidBlocks: fm.validBlocks, + IndexedBlocks: indexedBlocks, } - fm.valid = indexed - fm.firstValid = fm.f.indexedRange.firstIndexedBlock - fm.lastValid = lastIndexed + fm.validBlocks = indexedBlocks fm.syncCh = nil } @@ -187,20 +173,10 @@ func (f *FilterMaps) updateMatchersValidRange() { defer f.matchersLock.Unlock() for fm := range f.matchers { - if !f.indexedRange.hasIndexedBlocks() { - fm.valid = false - } - if !fm.valid { + if !f.indexedRange.initialized { + fm.validBlocks = common.Range[uint64]{} continue } - if fm.firstValid < f.indexedRange.firstIndexedBlock { - fm.firstValid = f.indexedRange.firstIndexedBlock - } - if fm.lastValid >= f.indexedRange.afterLastIndexedBlock { - fm.lastValid = f.indexedRange.afterLastIndexedBlock - 1 - } - if fm.firstValid > fm.lastValid { - fm.valid = false - } + fm.validBlocks = fm.validBlocks.Intersection(f.indexedRange.blocks) } } diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index f679c3aeb..9f3d55aa3 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -356,8 +356,8 @@ func WriteFilterMapBaseRows(db ethdb.KeyValueWriter, mapRowIndex uint64, rows [] } } -func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, firstMapRowIndex, afterLastMapRowIndex uint64) { - if err := db.DeleteRange(filterMapRowKey(firstMapRowIndex, false), filterMapRowKey(afterLastMapRowIndex, false)); err != nil { +func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, mapRows common.Range[uint64]) { + if err := db.DeleteRange(filterMapRowKey(mapRows.First(), false), filterMapRowKey(mapRows.AfterLast(), false)); err != nil { log.Crit("Failed to delete range of filter map rows", "err", err) } } @@ -396,8 +396,8 @@ func DeleteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32) { } } -func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, firstMapIndex, afterLastMapIndex uint32) { - if err := db.DeleteRange(filterMapLastBlockKey(firstMapIndex), filterMapLastBlockKey(afterLastMapIndex)); err != nil { +func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, maps common.Range[uint32]) { + if err := db.DeleteRange(filterMapLastBlockKey(maps.First()), filterMapLastBlockKey(maps.AfterLast())); err != nil { log.Crit("Failed to delete range of filter map last block pointers", "err", err) } } @@ -433,8 +433,8 @@ func DeleteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber uint64) { } } -func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, firstBlockNumber, afterLastBlockNumber uint64) { - if err := db.DeleteRange(filterMapBlockLVKey(firstBlockNumber), filterMapBlockLVKey(afterLastBlockNumber)); err != nil { +func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, blocks common.Range[uint64]) { + if err := db.DeleteRange(filterMapBlockLVKey(blocks.First()), filterMapBlockLVKey(blocks.AfterLast())); err != nil { log.Crit("Failed to delete range of block log value pointers", "err", err) } } @@ -442,10 +442,11 @@ func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, firstBlockNumber, afte // FilterMapsRange is a storage representation of the block range covered by the // filter maps structure and the corresponting log value index range. type FilterMapsRange struct { - HeadBlockIndexed bool - HeadBlockDelimiter uint64 - FirstIndexedBlock, AfterLastIndexedBlock uint64 - FirstRenderedMap, AfterLastRenderedMap, TailPartialEpoch uint32 + HeadIndexed bool + HeadDelimiter uint64 + BlocksFirst, BlocksAfterLast uint64 + MapsFirst, MapsAfterLast uint32 + TailPartialEpoch uint32 } // ReadFilterMapsRange retrieves the filter maps range data. Note that if the diff --git a/eth/api_backend.go b/eth/api_backend.go index 175cb215d..578b339f8 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" @@ -453,6 +454,10 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma } } +func (b *EthAPIBackend) NewMatcherBackend() filtermaps.MatcherBackend { + return b.eth.filterMaps.NewMatcherBackend() +} + func (b *EthAPIBackend) Engine() consensus.Engine { return b.eth.engine } diff --git a/eth/backend.go b/eth/backend.go index f1876e857..1466f6320 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/dbft" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" "github.com/ethereum/go-ethereum/core/txpool" @@ -96,6 +97,9 @@ type Ethereum struct { bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports closeBloomHandler chan struct{} + filterMaps *filtermaps.FilterMaps + closeFilterMaps chan chan struct{} + APIBackend *EthAPIBackend miner *miner.Miner @@ -263,6 +267,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, err } eth.bloomIndexer.Start(eth.blockchain) + fmConfig := filtermaps.Config{History: config.LogHistory, Disabled: config.LogNoHistory, ExportFileName: config.LogExportCheckpoints} + chainView := eth.newChainView(eth.blockchain.CurrentBlock()) + eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, 0, 0, filtermaps.DefaultParams, fmConfig) + eth.closeFilterMaps = make(chan chan struct{}) if config.BlobPool.Datadir != "" { config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) @@ -598,9 +606,71 @@ func (s *Ethereum) Start() error { // Start the networking layer s.handler.Start(s.p2pServer.MaxPeers) + + // start log indexer + s.filterMaps.Start() + go s.updateFilterMapsHeads() return nil } +func (s *Ethereum) newChainView(head *types.Header) *filtermaps.ChainView { + if head == nil { + return nil + } + return filtermaps.NewChainView(s.blockchain, head.Number.Uint64(), head.Hash()) +} + +func (s *Ethereum) updateFilterMapsHeads() { + headEventCh := make(chan core.ChainEvent, 10) + blockProcCh := make(chan bool, 10) + sub := s.blockchain.SubscribeChainEvent(headEventCh) + sub2 := s.blockchain.SubscribeBlockProcessingEvent(blockProcCh) + defer func() { + sub.Unsubscribe() + sub2.Unsubscribe() + for { + select { + case <-headEventCh: + case <-blockProcCh: + default: + return + } + } + }() + + var head *types.Header + setHead := func(newHead *types.Header) { + if newHead == nil { + return + } + if head == nil || newHead.Hash() != head.Hash() { + head = newHead + chainView := s.newChainView(head) + historyCutoff := s.blockchain.HistoryPruningCutoff() + var finalBlock uint64 + if fb := s.blockchain.CurrentFinalBlock(); fb != nil { + finalBlock = fb.Number.Uint64() + } + s.filterMaps.SetTarget(chainView, historyCutoff, finalBlock) + } + } + setHead(s.blockchain.CurrentBlock()) + + for { + select { + case ev := <-headEventCh: + setHead(ev.Header) + case blockProc := <-blockProcCh: + s.filterMaps.SetBlockProcessing(blockProc) + case <-time.After(time.Second * 10): + setHead(s.blockchain.CurrentBlock()) + case ch := <-s.closeFilterMaps: + close(ch) + return + } + } +} + func (s *Ethereum) setupDiscovery() error { eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) @@ -643,6 +713,10 @@ func (s *Ethereum) Stop() error { // Then stop everything else. s.bloomIndexer.Close() close(s.closeBloomHandler) + ch := make(chan struct{}) + s.closeFilterMaps <- ch + <-ch + s.filterMaps.Stop() s.txPool.Close() s.miner.Close() s.blockchain.Stop() diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 4aeb0048e..b734e5db1 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -55,6 +55,7 @@ var Defaults = Config{ NetworkId: 0, // enable auto configuration of networkID == chainID TxLookupLimit: 2350000, TransactionHistory: 2350000, + LogHistory: 2350000, StateHistory: params.FullImmutabilityThreshold, DatabaseCache: 512, TrieCleanCache: 154, @@ -99,8 +100,11 @@ type Config struct { // Deprecated: use 'TransactionHistory' instead. TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. - TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. - StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved. + TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. + LogHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head where a log search index is maintained. + LogNoHistory bool `toml:",omitempty"` // No log search index is maintained. + LogExportCheckpoints string // export log index checkpoints to file + StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved. // State scheme represents the scheme used to store ethereum states and trie // nodes on top. It can be 'hash', 'path', or none which means use the scheme diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 09ccb9390..cedb5b351 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -19,12 +19,15 @@ package filters import ( "context" "errors" + "math" "math/big" "slices" + "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" ) @@ -38,36 +41,14 @@ type Filter struct { block *common.Hash // Block hash if filtering a single block begin, end int64 // Range interval if filtering multiple blocks - matcher *bloombits.Matcher + rangeLogsTestHook chan rangeLogsTestEvent } // NewRangeFilter creates a new filter which uses a bloom filter on blocks to // figure out whether a particular block is interesting or not. func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter { - // Flatten the address and topic filter clauses into a single bloombits filter - // system. Since the bloombits are not positional, nil topics are permitted, - // which get flattened into a nil byte slice. - var filters [][][]byte - if len(addresses) > 0 { - filter := make([][]byte, len(addresses)) - for i, address := range addresses { - filter[i] = address.Bytes() - } - filters = append(filters, filter) - } - for _, topicList := range topics { - filter := make([][]byte, len(topicList)) - for i, topic := range topicList { - filter[i] = topic.Bytes() - } - filters = append(filters, filter) - } - size, _ := sys.backend.BloomStatus() - // Create a generic filter and convert it into a range filter filter := newFilter(sys, addresses, topics) - - filter.matcher = bloombits.NewMatcher(size, filters) filter.begin = begin filter.end = end @@ -113,161 +94,304 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return nil, errPendingLogsUnsupported } - resolveSpecial := func(number int64) (int64, error) { - var hdr *types.Header + resolveSpecial := func(number int64) (uint64, error) { switch number { - case rpc.LatestBlockNumber.Int64(), rpc.PendingBlockNumber.Int64(): - // we should return head here since we've already captured - // that we need to get the pending logs in the pending boolean above - hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) - if hdr == nil { - return 0, errors.New("latest header not found") - } + case rpc.LatestBlockNumber.Int64(): + // when searching from and/or until the current head, we resolve it + // to MaxUint64 which is translated by rangeLogs to the actual head + // in each iteration, ensuring that the head block will be searched + // even if the chain is updated during search. + return math.MaxUint64, nil case rpc.FinalizedBlockNumber.Int64(): - hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) + hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) if hdr == nil { return 0, errors.New("finalized header not found") } + return hdr.Number.Uint64(), nil case rpc.SafeBlockNumber.Int64(): - hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber) + hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber) if hdr == nil { return 0, errors.New("safe header not found") } - default: - return number, nil + return hdr.Number.Uint64(), nil + } + if number < 0 { + return 0, errors.New("negative block number") } - return hdr.Number.Int64(), nil + return uint64(number), nil } - var err error // range query need to resolve the special begin/end block number - if f.begin, err = resolveSpecial(f.begin); err != nil { + begin, err := resolveSpecial(f.begin) + if err != nil { return nil, err } - if f.end, err = resolveSpecial(f.end); err != nil { + end, err := resolveSpecial(f.end) + if err != nil { return nil, err } - - logChan, errChan := f.rangeLogsAsync(ctx) - var logs []*types.Log - for { - select { - case log := <-logChan: - logs = append(logs, log) - case err := <-errChan: - return logs, err - } - } + return f.rangeLogs(ctx, begin, end) } -// rangeLogsAsync retrieves block-range logs that match the filter criteria asynchronously, -// it creates and returns two channels: one for delivering log data, and one for reporting errors. -func (f *Filter) rangeLogsAsync(ctx context.Context) (chan *types.Log, chan error) { - var ( - logChan = make(chan *types.Log) - errChan = make(chan error) - ) - - go func() { - defer func() { - close(errChan) - close(logChan) - }() - - // Gather all indexed logs, and finish with non indexed ones - var ( - end = uint64(f.end) - size, sections = f.sys.backend.BloomStatus() - err error - ) - if indexed := sections * size; indexed > uint64(f.begin) { - if indexed > end { - indexed = end + 1 - } - if err = f.indexedLogs(ctx, indexed-1, logChan); err != nil { - errChan <- err - return - } - } - - if err := f.unindexedLogs(ctx, end, logChan); err != nil { - errChan <- err - return - } +const ( + rangeLogsTestSync = iota + rangeLogsTestTrimmed + rangeLogsTestIndexed + rangeLogsTestUnindexed + rangeLogsTestDone +) - errChan <- nil - }() +type rangeLogsTestEvent struct { + event int + begin, end uint64 +} - return logChan, errChan +// searchSession represents a single search session. +type searchSession struct { + ctx context.Context + filter *Filter + mb filtermaps.MatcherBackend + syncRange filtermaps.SyncRange // latest synchronized state with the matcher + firstBlock, lastBlock uint64 // specified search range; each can be MaxUint64 + searchRange common.Range[uint64] // actual search range; end trimmed to latest head + matchRange common.Range[uint64] // range in which we have results (subset of searchRange) + matches []*types.Log // valid set of matches in matchRange + forceUnindexed bool // revert to unindexed search } -// indexedLogs returns the logs matching the filter criteria based on the bloom -// bits indexed available locally or via the network. -func (f *Filter) indexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error { - // Create a matcher session and request servicing from the backend - matches := make(chan uint64, 64) +// newSearchSession returns a new searchSession. +func newSearchSession(ctx context.Context, filter *Filter, mb filtermaps.MatcherBackend, firstBlock, lastBlock uint64) (*searchSession, error) { + s := &searchSession{ + ctx: ctx, + filter: filter, + mb: mb, + firstBlock: firstBlock, + lastBlock: lastBlock, + } + // enforce a consistent state before starting the search in order to be able + // to determine valid range later + if err := s.syncMatcher(0); err != nil { + return nil, err + } + return s, nil +} - session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches) +// syncMatcher performs a synchronization step with the matcher. The resulting +// syncRange structure holds information about the latest range of indexed blocks +// and the guaranteed valid blocks whose log index have not been changed since +// the previous synchronization. +// The function also performs trimming of the match set in order to always keep +// it consistent with the synced matcher state. +// Tail trimming is only performed if the first block of the valid log index range +// is higher than trimTailThreshold. This is useful because unindexed log search +// is not affected by the valid tail (on the other hand, valid head is taken into +// account in order to provide reorg safety, even though the log index is not used). +// In case of indexed search the tail is only trimmed if the first part of the +// recently obtained results might be invalid. If guaranteed valid new results +// have been added at the head of previously validated results then there is no +// need to discard those even if the index tail have been unindexed since that. +func (s *searchSession) syncMatcher(trimTailThreshold uint64) error { + if s.filter.rangeLogsTestHook != nil && !s.matchRange.IsEmpty() { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestSync, begin: s.matchRange.First(), end: s.matchRange.Last()} + } + var err error + s.syncRange, err = s.mb.SyncLogIndex(s.ctx) if err != nil { return err } - defer session.Close() + // update actual search range based on current head number + first := min(s.firstBlock, s.syncRange.HeadNumber) + last := min(s.lastBlock, s.syncRange.HeadNumber) + s.searchRange = common.NewRange(first, last+1-first) + // discard everything that is not needed or might be invalid + trimRange := s.syncRange.ValidBlocks + if trimRange.First() <= trimTailThreshold { + // everything before this point is already known to be valid; if this is + // valid then keep everything before + trimRange.SetFirst(0) + } + trimRange = trimRange.Intersection(s.searchRange) + s.trimMatches(trimRange) + if s.filter.rangeLogsTestHook != nil { + if !s.matchRange.IsEmpty() { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: s.matchRange.First(), end: s.matchRange.Last()} + } else { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: 0, end: 0} + } + } + return nil +} - f.sys.backend.ServiceFilter(ctx, session) +// trimMatches removes any entries from the current set of matches that is outside +// the given range. +func (s *searchSession) trimMatches(trimRange common.Range[uint64]) { + s.matchRange = s.matchRange.Intersection(trimRange) + if s.matchRange.IsEmpty() { + s.matches = nil + return + } + for len(s.matches) > 0 && s.matches[0].BlockNumber < s.matchRange.First() { + s.matches = s.matches[1:] + } + for len(s.matches) > 0 && s.matches[len(s.matches)-1].BlockNumber > s.matchRange.Last() { + s.matches = s.matches[:len(s.matches)-1] + } +} - for { - select { - case number, ok := <-matches: - // Abort if all matches have been fulfilled - if !ok { - err := session.Error() - if err == nil { - f.begin = int64(end) + 1 - } - return err - } - f.begin = int64(number) + 1 +// searchInRange performs a single range search, either indexed or unindexed. +func (s *searchSession) searchInRange(r common.Range[uint64], indexed bool) ([]*types.Log, error) { + first, last := r.First(), r.Last() + if indexed { + if s.filter.rangeLogsTestHook != nil { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestIndexed, first, last} + } + results, err := s.filter.indexedLogs(s.ctx, s.mb, first, last) + if err != filtermaps.ErrMatchAll { + return results, err + } + // "match all" filters are not supported by filtermaps; fall back to + // unindexed search which is the most efficient in this case + s.forceUnindexed = true + // fall through to unindexed case + } + if s.filter.rangeLogsTestHook != nil { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestUnindexed, first, last} + } + return s.filter.unindexedLogs(s.ctx, first, last) +} + +// doSearchIteration performs a search on a range missing from an incomplete set +// of results, adds the new section and removes invalidated entries. +func (s *searchSession) doSearchIteration() error { + switch { + case s.syncRange.IndexedBlocks.IsEmpty(): + // indexer is not ready; fallback to completely unindexed search, do not check valid range + var err error + s.matchRange = s.searchRange + s.matches, err = s.searchInRange(s.searchRange, false) + return err - // Retrieve the suggested block and pull any truly matching logs - header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(number)) - if header == nil || err != nil { + case s.matchRange.IsEmpty(): + // no results yet; try search in entire range + indexedSearchRange := s.searchRange.Intersection(s.syncRange.IndexedBlocks) + var err error + if s.forceUnindexed = indexedSearchRange.IsEmpty(); !s.forceUnindexed { + // indexed search on the intersection of indexed and searched range + s.matchRange = indexedSearchRange + s.matches, err = s.searchInRange(indexedSearchRange, true) + if err != nil { return err } - found, err := f.checkMatches(ctx, header) + return s.syncMatcher(0) // trim everything that the matcher considers potentially invalid + } else { + // no intersection of indexed and searched range; unindexed search on the whole searched range + s.matchRange = s.searchRange + s.matches, err = s.searchInRange(s.searchRange, false) if err != nil { return err } - for _, log := range found { - logChan <- log + return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range + } + + case !s.matchRange.IsEmpty() && s.matchRange.First() > s.searchRange.First(): + // we have results but tail section is missing; do unindexed search for + // the tail part but still allow indexed search for missing head section + tailRange := common.NewRange(s.searchRange.First(), s.matchRange.First()-s.searchRange.First()) + tailMatches, err := s.searchInRange(tailRange, false) + if err != nil { + return err + } + s.matches = append(tailMatches, s.matches...) + s.matchRange = tailRange.Union(s.matchRange) + return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range + + case !s.matchRange.IsEmpty() && s.matchRange.First() == s.searchRange.First() && s.searchRange.AfterLast() > s.matchRange.AfterLast(): + // we have results but head section is missing + headRange := common.NewRange(s.matchRange.AfterLast(), s.searchRange.AfterLast()-s.matchRange.AfterLast()) + if !s.forceUnindexed { + indexedHeadRange := headRange.Intersection(s.syncRange.IndexedBlocks) + if !indexedHeadRange.IsEmpty() && indexedHeadRange.First() == headRange.First() { + // indexed head range search is possible + headRange = indexedHeadRange + } else { + s.forceUnindexed = true } + } + headMatches, err := s.searchInRange(headRange, !s.forceUnindexed) + if err != nil { + return err + } + s.matches = append(s.matches, headMatches...) + s.matchRange = s.matchRange.Union(headRange) + if s.forceUnindexed { + return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range + } else { + return s.syncMatcher(headRange.First()) // trim if the tail of latest head search results might be invalid + } - case <-ctx.Done(): - return ctx.Err() + default: + panic("invalid search session state") + } +} + +func (f *Filter) rangeLogs(ctx context.Context, firstBlock, lastBlock uint64) ([]*types.Log, error) { + if f.rangeLogsTestHook != nil { + defer func() { + f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestDone, 0, 0} + close(f.rangeLogsTestHook) + }() + } + + if firstBlock > lastBlock { + return nil, nil + } + mb := f.sys.backend.NewMatcherBackend() + defer mb.Close() + + session, err := newSearchSession(ctx, f, mb, firstBlock, lastBlock) + if err != nil { + return nil, err + } + for session.searchRange != session.matchRange { + if err := session.doSearchIteration(); err != nil { + return session.matches, err } } + return session.matches, nil +} + +func (f *Filter) indexedLogs(ctx context.Context, mb filtermaps.MatcherBackend, begin, end uint64) ([]*types.Log, error) { + start := time.Now() + potentialMatches, err := filtermaps.GetPotentialMatches(ctx, mb, begin, end, f.addresses, f.topics) + matches := filterLogs(potentialMatches, nil, nil, f.addresses, f.topics) + log.Trace("Performed indexed log search", "begin", begin, "end", end, "true matches", len(matches), "false positives", len(potentialMatches)-len(matches), "elapsed", common.PrettyDuration(time.Since(start))) + return matches, err } // unindexedLogs returns the logs matching the filter criteria based on raw block // iteration and bloom matching. -func (f *Filter) unindexedLogs(ctx context.Context, end uint64, logChan chan *types.Log) error { - for ; f.begin <= int64(end); f.begin++ { - header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) +func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) { + start := time.Now() + log.Warn("Performing unindexed log search", "begin", begin, "end", end) + var matches []*types.Log + for blockNumber := begin; blockNumber <= end; blockNumber++ { + select { + case <-ctx.Done(): + return matches, ctx.Err() + default: + } + header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(blockNumber)) if header == nil || err != nil { - return err + return matches, err } found, err := f.blockLogs(ctx, header) if err != nil { - return err - } - for _, log := range found { - select { - case logChan <- log: - case <-ctx.Done(): - return ctx.Err() - } + return matches, err } + matches = append(matches, found...) } - return nil + log.Trace("Performed unindexed log search", "begin", begin, "end", end, "matches", len(matches), "elapsed", common.PrettyDuration(time.Since(start))) + return matches, nil } // blockLogs returns the logs matching the filter criteria within a single block. diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 83d626b41..4b2c3d83c 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -71,8 +71,7 @@ type Backend interface { SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - BloomStatus() (uint64, uint64) - ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) + NewMatcherBackend() filtermaps.MatcherBackend StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 26e84f8c8..a0af3856e 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -20,7 +20,6 @@ import ( "context" "errors" "math/big" - "math/rand" "reflect" "runtime" "testing" @@ -29,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -42,7 +41,7 @@ import ( type testBackend struct { db ethdb.Database - sections uint64 + fm *filtermaps.FilterMaps txFeed event.Feed logsFeed event.Feed rmLogsFeed event.Feed @@ -61,10 +60,28 @@ func (b *testBackend) CurrentHeader() *types.Header { return hdr } +func (b *testBackend) CurrentBlock() *types.Header { + return b.CurrentHeader() +} + func (b *testBackend) ChainDb() ethdb.Database { return b.db } +func (b *testBackend) GetCanonicalHash(number uint64) common.Hash { + return rawdb.ReadCanonicalHash(b.db, number) +} + +func (b *testBackend) GetHeader(hash common.Hash, number uint64) *types.Header { + hdr, _ := b.HeaderByHash(context.Background(), hash) + return hdr +} + +func (b *testBackend) GetReceiptsByHash(hash common.Hash) types.Receipts { + r, _ := b.GetReceipts(context.Background(), hash) + return r +} + func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { var ( hash common.Hash @@ -143,35 +160,26 @@ func (b *testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHead return b.finalizedHeaderFeed.Subscribe(ch) } -func (b *testBackend) BloomStatus() (uint64, uint64) { - return params.BloomBitsBlocks, b.sections +func (b *testBackend) NewMatcherBackend() filtermaps.MatcherBackend { + return b.fm.NewMatcherBackend() } -func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { - requests := make(chan chan *bloombits.Retrieval) - - go session.Multiplex(16, 0, requests) - go func() { - for { - // Wait for a service request or a shutdown - select { - case <-ctx.Done(): - return - - case request := <-requests: - task := <-request +func (b *testBackend) startFilterMaps(history uint64, disabled bool, params filtermaps.Params) { + head := b.CurrentBlock() + chainView := filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash()) + config := filtermaps.Config{ + History: history, + Disabled: disabled, + ExportFileName: "", + } + b.fm = filtermaps.NewFilterMaps(b.db, chainView, 0, 0, params, config) + b.fm.Start() + b.fm.WaitIdle() +} - task.Bitsets = make([][]byte, len(task.Sections)) - for i, section := range task.Sections { - if rand.Int()%4 != 0 { // Handle occasional missing deliveries - head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) - task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head) - } - } - request <- task - } - } - }() +func (b *testBackend) stopFilterMaps() { + b.fm.Stop() + b.fm = nil } func (b *testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { @@ -184,7 +192,7 @@ func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) { b.pendingReceipts = receipts } -func newTestFilterSystem(t testing.TB, db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { +func newTestFilterSystem(db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { backend := &testBackend{db: db} sys := NewFilterSystem(backend, cfg) return backend, sys @@ -200,7 +208,7 @@ func TestBlockSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) + backend, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) genesis = &core.Genesis{ Config: params.TestChainConfig, @@ -255,7 +263,7 @@ func TestPendingTxFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) + backend, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) transactions = []*types.Transaction{ @@ -311,7 +319,7 @@ func TestPendingTxFilterFullTx(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) + backend, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) transactions = []*types.Transaction{ @@ -367,7 +375,7 @@ func TestPendingTxFilterFullTx(t *testing.T) { func TestLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(t, db, Config{}) + _, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) testCases = []struct { @@ -414,7 +422,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(t, db, Config{}) + _, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) ) @@ -440,7 +448,7 @@ func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(t, db, Config{}) + _, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -466,7 +474,7 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(t, db, Config{}) + _, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) ) @@ -481,7 +489,7 @@ func TestLogFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) + backend, sys = newTestFilterSystem(db, Config{}) api = NewFilterAPI(sys) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") @@ -586,7 +594,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{Timeout: timeout}) + backend, sys = newTestFilterSystem(db, Config{Timeout: timeout}) api = NewFilterAPI(sys) done = make(chan struct{}) ) @@ -610,7 +618,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { // Create a bunch of filters that will // timeout either in 100ms or 200ms subs := make([]*Subscription, 20) - for i := 0; i < len(subs); i++ { + for i := range subs { fid := api.NewPendingTransactionFilter(nil) api.filtersMu.Lock() f, ok := api.filters[fid] diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index fa958e62d..478cead0e 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -46,15 +47,27 @@ func makeReceipt(addr common.Address) *types.Receipt { return receipt } -func BenchmarkFilters(b *testing.B) { +func BenchmarkFiltersIndexed(b *testing.B) { + benchmarkFilters(b, 0, false) +} + +func BenchmarkFiltersHalfIndexed(b *testing.B) { + benchmarkFilters(b, 50000, false) +} + +func BenchmarkFiltersUnindexed(b *testing.B) { + benchmarkFilters(b, 0, true) +} + +func benchmarkFilters(b *testing.B, history uint64, noHistory bool) { var ( - db = rawdb.NewMemoryDatabase() - _, sys = newTestFilterSystem(b, db, Config{}) - key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - addr1 = crypto.PubkeyToAddress(key1.PublicKey) - addr2 = common.BytesToAddress([]byte("jeff")) - addr3 = common.BytesToAddress([]byte("ethereum")) - addr4 = common.BytesToAddress([]byte("random addresses please")) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(db, Config{}) + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = common.BytesToAddress([]byte("jeff")) + addr3 = common.BytesToAddress([]byte("ethereum")) + addr4 = common.BytesToAddress([]byte("random addresses please")) gspec = &core.Genesis{ Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, @@ -94,9 +107,12 @@ func BenchmarkFilters(b *testing.B) { rawdb.WriteHeadBlockHash(db, block.Hash()) rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i]) } + backend.startFilterMaps(history, noHistory, filtermaps.DefaultParams) + defer backend.stopFilterMaps() + b.ResetTimer() - filter := sys.NewRangeFilter(0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil) + filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr1, addr2, addr3, addr4}, nil) for i := 0; i < b.N; i++ { filter.begin = 0 @@ -107,10 +123,22 @@ func BenchmarkFilters(b *testing.B) { } } -func TestFilters(t *testing.T) { +func TestFiltersIndexed(t *testing.T) { + testFilters(t, 0, false) +} + +func TestFiltersHalfIndexed(t *testing.T) { + testFilters(t, 500, false) +} + +func TestFiltersUnindexed(t *testing.T) { + testFilters(t, 0, true) +} + +func testFilters(t *testing.T, history uint64, noHistory bool) { var ( db = rawdb.NewMemoryDatabase() - backend, sys = newTestFilterSystem(t, db, Config{}) + backend, sys = newTestFilterSystem(db, Config{}) // Sender account key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) @@ -279,6 +307,9 @@ func TestFilters(t *testing.T) { }) backend.setPending(pchain[0], preceipts[0]) + backend.startFilterMaps(history, noHistory, filtermaps.DefaultParams) + defer backend.stopFilterMaps() + for i, tc := range []struct { f *Filter want string @@ -387,3 +418,146 @@ func TestFilters(t *testing.T) { } }) } + +func TestRangeLogs(t *testing.T) { + var ( + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(db, Config{}) + gspec = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + ) + _, err := gspec.Commit(db, triedb.NewDatabase(db, nil)) + if err != nil { + t.Fatal(err) + } + chain, _ := core.GenerateChain(gspec.Config, gspec.ToBlock(), ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) {}) + var l uint64 + bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l) + if err != nil { + t.Fatal(err) + } + _, err = bc.InsertChain(chain[:600]) + if err != nil { + t.Fatal(err) + } + + backend.startFilterMaps(200, false, filtermaps.RangeTestParams) + defer backend.stopFilterMaps() + + var ( + testCase, event int + filter *Filter + addresses = []common.Address{{}} + ) + + expEvent := func(exp rangeLogsTestEvent) { + event++ + ev := <-filter.rangeLogsTestHook + if ev != exp { + t.Fatalf("Test case #%d: wrong test event #%d received (got %v, expected %v)", testCase, event, ev, exp) + } + } + + newFilter := func(begin, end int64) { + testCase++ + event = 0 + filter = sys.NewRangeFilter(begin, end, addresses, nil) + filter.rangeLogsTestHook = make(chan rangeLogsTestEvent) + go func(filter *Filter) { + filter.Logs(context.Background()) + // ensure that filter will not be blocked if we exit early + for range filter.rangeLogsTestHook { + } + }(filter) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) + } + + updateHead := func() { + head := bc.CurrentBlock() + backend.fm.SetTarget(filtermaps.NewChainView(backend, head.Number.Uint64(), head.Hash()), 0, 0) + backend.fm.WaitIdle() + } + + // test case #1 + newFilter(300, 500) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 401, 500}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 401, 500}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 401, 500}) + expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 300, 400}) + if _, err := bc.InsertChain(chain[600:700]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 300, 500}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 300, 500}) // unindexed search is not affected by trimmed tail + expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + + // test case #2 + newFilter(400, int64(rpc.LatestBlockNumber)) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 501, 700}) + if _, err := bc.InsertChain(chain[700:800]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 501, 700}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 601, 698}) + expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 600}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 698}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 698}) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 699, 800}) + if err := bc.SetHead(750); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 800}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 748}) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 749, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + + // test case #3 + newFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber)) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750}) + if err := bc.SetHead(740); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 740, 740}) + if _, err := bc.InsertChain(chain[740:750]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 740, 740}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 750, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + + // test case #4 + newFilter(400, int64(rpc.LatestBlockNumber)) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 551, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 551, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 551, 750}) + expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 550}) + if _, err := bc.InsertChain(chain[750:1000]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750}) + // indexed range affected by tail pruning so we have to discard the entire + // match set + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) + expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 801, 1000}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 801, 1000}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 801, 1000}) + expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 800}) + expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 1000}) + expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 1000}) +} diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index dbbe83e68..31a2e52b2 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -46,7 +46,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -633,11 +633,9 @@ func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { panic("implement me") } -func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") } -func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { +func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { panic("implement me") } - func TestEstimateGas(t *testing.T) { t.Parallel() // Initialize test accounts diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5a045b6a7..19f6028ac 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -27,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -96,9 +96,9 @@ type Backend interface { GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - BloomStatus() (uint64, uint64) - ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription + + NewMatcherBackend() filtermaps.MatcherBackend } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 145346c79..83b3523eb 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -406,12 +406,12 @@ func (b *backendMock) TxPoolContent() (map[common.Address][]*types.Transaction, func (b *backendMock) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { return nil, nil } -func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } -func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 } -func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {} -func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } +func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } +func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { return nil } func (b *backendMock) Engine() consensus.Engine { return nil } + +func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil } From 0bb4ad323917740221f2db502d1d0f6a4f21f6ac Mon Sep 17 00:00:00 2001 From: Shahar Rosenberg Date: Tue, 18 Mar 2025 11:05:12 +0000 Subject: [PATCH 214/354] eth/tracers: fix precompile move feat for debug_traceCall (#31348) `debug_traceCall` was ignoring the override `movePrecompileToAddress`. Now it is at feature-parity with eth_call. --- eth/tracers/api.go | 26 ++++++++++++++----------- eth/tracers/api_test.go | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 224f31ac2..fcd66e5c8 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -279,7 +279,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config, nil) if err != nil { task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) @@ -632,7 +632,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, nil) if err != nil { return nil, err } @@ -676,7 +676,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // concurrent use. // See: https://github.com/ethereum/go-ethereum/issues/29114 blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, nil) if err != nil { results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} continue @@ -894,7 +894,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * TxIndex: int(index), TxHash: hash, } - return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config) + return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, nil) } // TraceCall lets you trace a given eth_call. It collects the structured logs @@ -907,10 +907,11 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) { // Try to retrieve the specified block var ( - err error - block *types.Block - statedb *state.StateDB - release StateReleaseFunc + err error + block *types.Block + statedb *state.StateDB + release StateReleaseFunc + precompiles vm.PrecompiledContracts ) if hash, ok := blockNrOrHash.Hash(); ok { block, err = api.blockByHash(ctx, hash) @@ -952,7 +953,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc config.BlockOverrides.Apply(&vmctx) rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) - precompiles := vm.ActivePrecompiledContracts(rules) + precompiles = vm.ActivePrecompiledContracts(rules) if err := config.StateOverrides.Apply(statedb, precompiles); err != nil { return nil, err } @@ -977,13 +978,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig) + return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig, precompiles) } // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will // be tracer dependent. -func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { +func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, precompiles vm.PrecompiledContracts) (interface{}, error) { var ( tracer *Tracer err error @@ -1009,6 +1010,9 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } tracingStateDB := state.NewHookedState(statedb, tracer.Hooks) evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + if precompiles != nil { + evm.SetPrecompiles(precompiles) + } // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 5b07e39ef..7383d4012 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -642,6 +642,7 @@ func TestTracingWithOverrides(t *testing.T) { t.Parallel() // Initialize test accounts accounts := newAccounts(3) + ecRecoverAddress := common.HexToAddress("0x0000000000000000000000000000000000000001") storageAccount := common.Address{0x13, 37} genesis := &core.Genesis{ Config: params.TestChainConfig, @@ -940,6 +941,48 @@ func TestTracingWithOverrides(t *testing.T) { }, want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`, }, + { // Call to precompile ECREC (0x01), but code was modified to add 1 to input + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &ecRecoverAddress, + Data: newRPCBytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")), + }, + config: &TraceCallConfig{ + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{ + Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))), + }, + ecRecoverAddress: override.OverrideAccount{ + // The code below adds one to input + Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")), + MovePrecompileTo: &randomAccounts[2].addr, + }, + }, + }, + want: `{"gas":21167,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000002"}`, + }, + { // Call to ECREC Precompiled on a different address, expect the original behaviour of ECREC precompile + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, // Moved EcRecover + Data: newRPCBytes(common.Hex2Bytes("82f3df49d3645876de6313df2bbe9fbce593f21341a7b03acdb9423bc171fcc9000000000000000000000000000000000000000000000000000000000000001cba13918f50da910f2d55a7ea64cf716ba31dad91856f45908dde900530377d8a112d60f36900d18eb8f9d3b4f85a697b545085614509e3520e4b762e35d0d6bd")), + }, + config: &TraceCallConfig{ + StateOverrides: &override.StateOverride{ + randomAccounts[0].addr: override.OverrideAccount{ + Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))), + }, + ecRecoverAddress: override.OverrideAccount{ + // The code below adds one to input + Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")), + MovePrecompileTo: &randomAccounts[2].addr, // Move EcRecover to this address + }, + }, + }, + want: `{"gas":25664,"failed":false,"returnValue":"000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`, + }, } for i, tc := range testSuite { result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) From d261dee0b45c92c2a941a1dc2f46748d4d0ff06b Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 18 Mar 2025 12:07:49 +0100 Subject: [PATCH 215/354] params: add hoodi testnet definition (#31406) Adds support for the new hoodi testnet. Hoodi is meant for stakers to test their setup. For more info please refer to https://hoodi.ethpandaops.io/. --- beacon/params/networks.go | 13 +++++++++++ cmd/blsync/main.go | 1 + cmd/devp2p/nodesetcmd.go | 2 ++ cmd/geth/main.go | 4 ++++ cmd/utils/flags.go | 27 ++++++++++++++++++++-- core/filtermaps/checkpoints.go | 4 ++++ core/filtermaps/checkpoints_hoodi.json | 1 + core/forkid/forkid_test.go | 11 +++++++++ core/genesis.go | 16 +++++++++++++ core/genesis_alloc.go | 1 + core/genesis_test.go | 11 +++++++++ core/rawdb/accessors_indexes_test.go | 8 +++++++ params/bootnodes.go | 11 +++++++++ params/config.go | 32 ++++++++++++++++++++++++++ 14 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 core/filtermaps/checkpoints_hoodi.json diff --git a/beacon/params/networks.go b/beacon/params/networks.go index eda225e0f..c54798697 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -55,4 +55,17 @@ var ( AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}). AddFork("DENEB", 29696, []byte{5, 1, 112, 0}). AddFork("ELECTRA", 115968, []byte{6, 1, 112, 0}) + + HoodiLightConfig = (&ChainConfig{ + GenesisValidatorsRoot: common.HexToHash("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f"), + GenesisTime: 1742212800, + Checkpoint: common.HexToHash(""), + }). + AddFork("GENESIS", 0, common.FromHex("0x10000910")). + AddFork("ALTAIR", 0, common.FromHex("0x20000910")). + AddFork("BELLATRIX", 0, common.FromHex("0x30000910")). + AddFork("CAPELLA", 0, common.FromHex("0x40000910")). + AddFork("DENEB", 0, common.FromHex("0x50000910")). + AddFork("ELECTRA", 2048, common.FromHex("0x60000910")). + AddFork("FULU", 18446744073709551615, common.FromHex("0x70000910")) ) diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index 57bc46c36..60caa4aa2 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -47,6 +47,7 @@ func main() { utils.MainnetFlag, utils.SepoliaFlag, utils.HoleskyFlag, + utils.HoodiFlag, utils.BlsyncApiFlag, utils.BlsyncJWTSecretFlag, }, diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index c8177f049..d7725fadb 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -234,6 +234,8 @@ func ethFilter(args []string) (nodeFilter, error) { filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock()) case "holesky": filter = forkid.NewStaticFilter(params.HoleskyChainConfig, core.DefaultHoleskyGenesisBlock().ToBlock()) + case "hoodi": + filter = forkid.NewStaticFilter(params.HoodiChainConfig, core.DefaultHoodiGenesisBlock().ToBlock()) default: return nil, fmt.Errorf("unknown network %q", args[0]) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e52765bf3..f1a1ebfa7 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -316,6 +316,9 @@ func prepare(ctx *cli.Context) { case ctx.IsSet(utils.HoleskyFlag.Name): log.Info("Starting Geth on Holesky testnet...") + case ctx.IsSet(utils.HoodiFlag.Name): + log.Info("Starting Geth on Hoodi testnet...") + case ctx.IsSet(utils.DeveloperFlag.Name): log.Info("Starting Geth in ephemeral dev mode...") log.Warn(`You are running Geth in --dev mode. Please note the following: @@ -342,6 +345,7 @@ func prepare(ctx *cli.Context) { // Make sure we're not on any supported preconfigured testnet either if !ctx.IsSet(utils.HoleskyFlag.Name) && !ctx.IsSet(utils.SepoliaFlag.Name) && + !ctx.IsSet(utils.HoodiFlag.Name) && !ctx.IsSet(utils.DeveloperFlag.Name) { // Nope, we're really on mainnet. Bump that cache up! log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 01e1f6485..da8d54a40 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -135,7 +135,7 @@ var ( } NetworkIdFlag = &cli.Uint64Flag{ Name: "networkid", - Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)", + Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky, --hoodi instead)", Value: ethconfig.Defaults.NetworkId, Category: flags.EthCategory, } @@ -154,6 +154,11 @@ var ( Usage: "Holesky network: pre-configured proof-of-stake test network", Category: flags.EthCategory, } + HoodiFlag = &cli.BoolFlag{ + Name: "hoodi", + Usage: "Hoodi network: pre-configured proof-of-stake test network", + Category: flags.EthCategory, + } // Dev mode DeveloperFlag = &cli.BoolFlag{ Name: "dev", @@ -1048,6 +1053,7 @@ var ( TestnetFlags = []cli.Flag{ SepoliaFlag, HoleskyFlag, + HoodiFlag, } // NetworkFlags is the flag group of all built-in supported networks. NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...) @@ -1074,6 +1080,9 @@ func MakeDataDir(ctx *cli.Context) string { if ctx.Bool(HoleskyFlag.Name) { return filepath.Join(path, "holesky") } + if ctx.Bool(HoodiFlag.Name) { + return filepath.Join(path, "hoodi") + } return path } Fatalf("Cannot determine default data directory, please set manually (--datadir)") @@ -1134,6 +1143,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.HoleskyBootnodes case ctx.Bool(SepoliaFlag.Name): urls = params.SepoliaBootnodes + case ctx.Bool(HoodiFlag.Name): + urls = params.HoodiBootnodes } } cfg.BootstrapNodes = mustParseBootnodes(urls) @@ -1572,6 +1583,8 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia") case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "holesky") + case ctx.Bool(HoodiFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + cfg.DataDir = filepath.Join(node.DefaultDataDir(), "hoodi") } } @@ -1704,7 +1717,7 @@ func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags - flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag) + flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag, HoodiFlag) flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer // Set configurations from CLI flags @@ -1912,6 +1925,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } cfg.Genesis = core.DefaultSepoliaGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash) + case ctx.Bool(HoodiFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { + cfg.NetworkId = 560048 + } + cfg.Genesis = core.DefaultHoodiGenesisBlock() + SetDNSDiscoveryDefaults(cfg, params.HoodiGenesisHash) case ctx.Bool(DeveloperFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 @@ -2027,6 +2046,8 @@ func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig { config.ChainConfig = *bparams.SepoliaLightConfig case ctx.Bool(HoleskyFlag.Name): config.ChainConfig = *bparams.HoleskyLightConfig + case ctx.Bool(HoodiFlag.Name): + config.ChainConfig = *bparams.HoodiLightConfig default: if !customConfig { config.ChainConfig = *bparams.MainnetLightConfig @@ -2293,6 +2314,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { genesis = core.DefaultHoleskyGenesisBlock() case ctx.Bool(SepoliaFlag.Name): genesis = core.DefaultSepoliaGenesisBlock() + case ctx.Bool(HoodiFlag.Name): + genesis = core.DefaultHoodiGenesisBlock() case ctx.Bool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } diff --git a/core/filtermaps/checkpoints.go b/core/filtermaps/checkpoints.go index f8d6500aa..face4ea5d 100644 --- a/core/filtermaps/checkpoints.go +++ b/core/filtermaps/checkpoints.go @@ -46,6 +46,9 @@ var checkpointsSepoliaJSON []byte //go:embed checkpoints_holesky.json var checkpointsHoleskyJSON []byte +//go:embed checkpoints_hoodi.json +var checkpointsHoodiJSON []byte + // checkpoints lists sets of checkpoints for multiple chains. The matching // checkpoint set is autodetected by the indexer once the canonical chain is // known. @@ -53,6 +56,7 @@ var checkpoints = []checkpointList{ decodeCheckpoints(checkpointsMainnetJSON), decodeCheckpoints(checkpointsSepoliaJSON), decodeCheckpoints(checkpointsHoleskyJSON), + decodeCheckpoints(checkpointsHoodiJSON), } func decodeCheckpoints(encoded []byte) (result checkpointList) { diff --git a/core/filtermaps/checkpoints_hoodi.json b/core/filtermaps/checkpoints_hoodi.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/core/filtermaps/checkpoints_hoodi.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index bebc20ad9..31e2b534b 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -112,6 +112,17 @@ func TestCreation(t *testing.T) { {123, 2740434112, ID{Hash: checksumToBytes(0xdfbd9bed), Next: 0}}, // Future Prague block }, }, + // Hoodi test cases + { + params.HoodiChainConfig, + core.DefaultHoodiGenesisBlock().ToBlock(), + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0xbef71d30), Next: 1742999832}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin, London, Paris, Shanghai, Cancun block + {123, 1742999831, ID{Hash: checksumToBytes(0xbef71d30), Next: 1742999832}}, // Last Cancun block + {123, 1742999832, ID{Hash: checksumToBytes(0x0929e24e), Next: 0}}, // First Prague block + {123, 2740434112, ID{Hash: checksumToBytes(0x0929e24e), Next: 0}}, // Future Prague block + }, + }, } for i, tt := range tests { for j, ttt := range tt.cases { diff --git a/core/genesis.go b/core/genesis.go index 19deb0401..48d781f3b 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -223,6 +223,8 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene genesis = DefaultSepoliaGenesisBlock() case params.HoleskyGenesisHash: genesis = DefaultHoleskyGenesisBlock() + case params.HoodiGenesisHash: + genesis = DefaultHoodiGenesisBlock() } if genesis != nil { return genesis.Alloc, nil @@ -437,6 +439,8 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo return params.HoleskyChainConfig case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig + case ghash == params.HoodiGenesisHash: + return params.HoodiChainConfig default: return stored } @@ -701,6 +705,18 @@ func DefaultHoleskyGenesisBlock() *Genesis { } } +// DefaultHoodiGenesisBlock returns the Hoodi network genesis block. +func DefaultHoodiGenesisBlock() *Genesis { + return &Genesis{ + Config: params.HoodiChainConfig, + Nonce: 0x1234, + GasLimit: 0x2255100, + Difficulty: big.NewInt(0x01), + Timestamp: 1742212800, + Alloc: decodePrealloc(hoodiAllocData), + } +} + // DeveloperGenesisBlock returns the 'geth --dev' genesis block. func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { // Override the default period to the user requested one diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 28bb2d5c1..68a1838d9 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -24,3 +24,4 @@ package core const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908'\x80t2\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x17bC\x0e\xa9\u00e2nWI\xaf\xdbp\xda_x\u077b\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x1d\x14\x80K9\x9cn\xf8\x0edWoev`\x80O\xec\v\x89\u3bb5sr@\xa0\x00\x00\u07932@5\x87\x94{\x9f\x15b*h\xd1\x04\xd5M3\xdb\xd1\u0349\x043\x87Oc,\xc6\x00\x00\u0793I~\x92\xcd\xc0\xe0\xb9c\xd7R\xb2)j\u02c7\u0682\x8b$\x89\n\x8fd\x9f\xe7\xc6\x18\x00\x00\u0793K\xfb\xe1Tk\xc6\xc6[\\~\xaaU0K8\xbb\xfe\xc6\u04c9lk\x93[\x8b\xbd@\x00\x00\u0793Z\x9c\x03\xf6\x9d\x17\xd6l\xbb\x8a\xd7!\x00\x8a\x9e\xbb\xb86\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u0793]\x0e\xe8\x15^\xc0\xa6\xffh\bU,\xa5\xf1k\xb5\xbe2:\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u0793v\"\xd8J#K\xb8\xb0x#\x0f\u03c4\xb6z\u9a2c\xae\x89%\xe1\xccQ\x99R\xf8\x00\x00\u0793{\x9f\xc3\x19\x05\xb4\x99K\x04\xc9\xe2\xcf\xdc^'pP?B\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u0793\u007fJ#\xca\x00\xcd\x04=%\u0088\x8c\x1a\xa5h\x8f\x81\xa3D\x89)\xf0\xa9[\xfb\xf7)\x00\x00\u0793\x869\u06bb\u3bac\x88{]\xc0\xe4>\x13\xbc\u0487\xd7l\x89\x10\xd0\xe3\xc8}n,\x00\x00\u0793\x89P\x86y\xab\xf8\xc7\x1b\xf6x\x16\x87\x12\x0e>j\x84XM\x89a\x94\x04\x9f0\xf7 \x00\x00\u0793\x8f\xc7\u02ed\xff\xbd\r\u007f\xe4O\x8d\xfd`\xa7\x9dr\x1a\x1c\x9c\x8965\u026d\xc5\u07a0\x00\x00\u0793\x95`\xa3\xdebxh\xf9\x1f\xa8\xbf\xe1\xc1\xb7\xaf\xaf\b\x18k\x89\x1cg\xf5\xf7\xba\xa0\xb0\x00\x00\u0793\x96\x97G\xf7\xa5\xb3\x06E\xfe\x00\xe4I\x01CZ\xce$\xcc7\x89\\(=A\x03\x94\x10\x00\x00\u0793\x9am}\xb3&g\x9bw\xc9\x03\x91\xa7Gm#\x8f;\xa3>\x89\n\xdaUGK\x814\x00\x00\u0793\x9e\xef\n\b\x86\x05n?i!\x18S\xb9\xb7E\u007f7\x82\u4262\xa8x\x06\x9b(\xe0\x00\x00\u0793\x9f\xdb\xf4N\x1fJcb\xb7i\u00daG_\x95\xa9l+\u01c9\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d3\xa5y\u007fR\xc9\u054f\x18\x9f6\xb1\xd4]\x1b\xf6\x04\x1f/k\x8a\x01'\u0473F\x1a\xcd\x1a\x00\x00\u0793\xaaS\x81\xb2\x13\x8e\xbe\xff\xc1\x91\xd5\xd8\u00d1u;p\x98\u04895\xab\xb0\x9f\xfe\u07b6\x80\x00\u0793\xaa\xda%\xea\"\x86p\x9a\xbbB-A\x92?\u04c0\xcd\x04\u01c9#=\xf3)\x9far\x00\x00\u0793\xac\xbf\xb2\xf2ZT\x85\xc79\xefp\xa4N\xee\xeb|e\xa6o\x89\x05k\xc7^-c\x10\x00\x00\u07d3\xac\xc6\xf0\x82\xa4B\x82\x87d\xd1\x1fX\u0589J\xe4\b\xf0s\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u0793\xb2w\xb0\x99\xa8\xe8f\xca\x0e\xc6[\u02c7(O\xd1B\xa5\x82\x89j\xcb=\xf2~\x1f\x88\x00\x00\u0753\xbd\xd4\x01:\xa3\x1c\x04al+\xc9x_'\x88\xf9\x15g\x9b\x88\xb9\xf6]\x00\xf6<\x00\x00\u0793\xc2}c\xfd\xe2K\x92\xee\x8a\x1e~\xd5\xd2m\x8d\xc5\xc8;\x03\x89lk\x93[\x8b\xbd@\x00\x00\u0553\xc4\x0f\xe2\tT#P\x9b\x9f\u0677T21X\xaf#\x10\xf3\x80\u0793\xd7^\xd6\fwO\x8b:ZQs\xfb\x183\xadq\x05\xa2\u0649l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d3\u05cd\x89\xb3_G'\x16\xec\xea\xfe\xbf`\x05'\u04e1\xf9i\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u0793\xda\xe2{5\v\xae \xc5e!$\xaf]\x8b\\\xba\x00\x1e\xc1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u0793\xdc\x01\xcb\xf4Ix\xa4.\x8d\xe8\xe46\xed\xf9B\x05\u03f6\xec\x89O\x0f\xeb\xbc\u068c\xb4\x00\x00\u07d3\u607c-\x10\xdbb\u0785\x84\x83$I\"P4\x8e\x90\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d3\xf4c\xe17\xdc\xf6%\xfb\U000fc8de\u0298\u04b9h\xcf\u007f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\x01\x00\a9K\x8bue\xa1e\x8a\xf8\x8c\xe4cI\x915\u05b7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x01\r\xf1\xdfK\xed#v\r-\x1c\x03x\x15\x86\xdd\xf7\x91\x8eT\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x01\x0fJ\x98\u07e1\xd9y\x9b\xf5\u01d6\xfbU\x0e\xfb\xe7\xec\xd8w\x8a\x01\xb2\xf2\x92#b\x92\xc7\x00\x00\u07d4\x01\x15PW\x00/k\r\x18\xac\xb98\x8d;\xc8\x12\x9f\x8fz \x89H\xa4\xa9\x0f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01k`\xbbmg\x92\x8c)\xfd\x03\x13\xc6f\u068f\x16\x98\xd9\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\x01l\x85\xe1a;\x90\x0f\xa3W\xb8(;\x12\x0ee\xae\xfc\xdd\b\x89+]\x97\x84\xa9|\xd5\x00\x00\u07d4\x01\x84\x92H\x8b\xa1\xa2\x924\"G\xb3\x18U\xa5Y\x05\xfe\xf2i\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x01\x8f \xa2{'\xecD\x1a\xf7#\xfd\x90\x99\xf2\u02f7\x9dbc\x89uy*\x8a\xbd\xef|\x00\x00\u07d4\x01\x91\xebT~{\xf6\x97k\x9b\x1bWuFv\x1d\xe6V\"\xe2\x89lkLM\xa6\u077e\x00\x00\u07d4\x01\x9dp\x95y\xffK\xc0\x9f\xdc\xdd\xe41\xdc\x14G\xd2\xc2`\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x01\xa2Z_Z\xf0\x16\x9b0\x86L;\xe4\xd7V<\xcdD\xf0\x9e\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\x01\xa7\xd9\xfa}\x0e\xb1\x18\\g\xe5M\xa8<.u\xdbi\u37ca\x01\x9dJ\xdd\xd0\u063c\x96\x00\x00\u07d4\x01\xa8\x18\x13ZAB\x10\xc3|b\xb6%\xac\xa1\xa5F\x11\xac6\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x01\xb1\xca\xe9\x1a;\x95Y\xaf\xb3<\xdcmh\x94B\xfd\xbf\xe07\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xb5\xb5\xbcZ\x11\u007f\xa0\x8b4\xed\x1d\xb9D\x06\bYz\xc5H\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xbb\xc1Og\xaf\x069\xaa\xb1D\x1ej\b\xd4\xceqb\t\x0f\x89F\xfc\xf6\x8f\xf8\xbe\x06\x00\x00\xe0\x94\x01\xd08\x15\xc6\x1fAkq\xa2a\n-\xab\xa5\x9f\xf6\xa6\xde[\x8a\x02\x05\xdf\xe5\v\x81\xc8.\x00\x00\u07d4\x01\u0559\xee\r_\x8c8\xab-9.,e\xb7L<\xe3\x18 \x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\x01\xe4\x05!\x12%0\u066c\x91\x11<\x06\xa0\x19\vmc\x85\v\x89Hz\x9a0E9D\x00\x00\u07d4\x01\xe6A]X{\x06T\x90\xf1\xed\u007f!\xd6\xe0\xf3\x86\xeegG\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x01\xe8d\xd3Tt\x1bB>oB\x85\x17$F\x8ct\xf5\xaa\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x01\xed_\xba\x8d.\xabg:\xec\x04-0\xe4\xe8\xa6\x11\xd8\xc5Z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01\xfb\x8e\xc1$%\xa0O\x81>F\xc5L\x05t\x8c\xa6\xb2\x9a\xa9\x89\x0e\x15s\x03\x85F|\x00\x00\u07d4\x01\xff\x1e\xb1\u07adP\xa7\xf2\xf9c\x8f\xde\xe6\xec\xcf:{*\u0209 \x86\xac5\x10R`\x00\x00\u07d4\x02\x03b\u00ed\xe8x\u0290\u05b2\u0609\xa4\xccU\x10\xee\xd5\xf3\x898\x88\xe8\xb3\x11\xad\xb3\x80\x00\u07d4\x02\x03\xae\x01\xd4\xc4\x1c\xae\x18e\xe0K\x1f[S\xcd\xfa\xec\xae1\x896\x89\xcd\u03b2\x8c\xd7\x00\x00\u07d4\x02\b\x93a\xa3\xfetQ\xfb\x1f\x87\xf0\x1a-\x86fS\xdc\v\a\x89\x02*\xc7H2\xb5\x04\x00\x00\u07d4\x02\x1fi\x04=\xe8\x8cI\x17\xca\x10\xf1\x84(\x97\xee\xc0X\x9c|\x89kD\u03f8\x14\x87\xf4\x00\x00\u07d4\x02)\x0f\xb5\xf9\xa5\x17\xf8(E\xac\xde\xca\x0f\xc8F\x03\x9b\xe23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x029\xb4\xf2\x1f\x8e\x05\xcd\x01Q++\xe7\xa0\xe1\x8am\x97F\a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x02Gr\x12\xff\xddu\xe5\x15VQ\xb7e\x06\xb1dfq\xa1\xeb\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x02J\t\x8a\xe7\x02\xbe\xf5@l\x9c\"\xb7\x8b\xd4\xeb,\u01e2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x02K\xdd,{\xfdP\x0e\xe7@O\u007f\xb3\xe9\xfb1\xdd \xfb\u0449\t\xc2\x00vQ\xb2P\x00\x00\u07d4\x02Sg\x96\x03\x04\xbe\xee4Y\x11\x18\xe9\xac-\x13X\xd8\x02\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x02V\x14\x9f[Pc\xbe\xa1N\x15f\x1f\xfbX\xf9\xb4Y\xa9W\x89&)\xf6n\fS\x00\x00\x00\u07d4\x02`=z;\xb2\x97\xc6|\x87~]4\xfb\u0579\x13\xd4\xc6:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x02a\xad:\x17*\xbf\x13\x15\xf0\xff\xec2p\x98j\x84\t\xcb%\x89\v\b!;\u03cf\xfe\x00\x00\u07d4\x02d2\xaf7\xdcQ\x13\xf1\xf4mH\nM\u0c80R#~\x89\x13I\xb7\x86\xe4\v\xfc\x00\x00\u07d4\x02f\xab\x1ck\x02\x16#\v\x93\x95D=_\xa7^hEh\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x02u\x1d\u018c\xb5\xbdsp'\xab\xf7\u0777s\x90\xcdw\xc1k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x02w\x8e9\x0f\xa1u\x10\xa3B\x8a\xf2\x87\fBsT}8l\x8a\x03lw\x80\x18\x8b\xf0\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x037|\x0eUkd\x01\x03(\x9aa\x89\u1baecI4g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03IcM\u00a9\xe8\f?w!\xee+PF\xae\xaa\xed\xfb\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x03U\xbc\xac\xbd!D\x1e\x95\xad\xee\xdc0\xc1r\x18\u0224\b\u0389\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x03n\xef\xf5\xba\x90\xa6\x87\x9a\x14\xdf\xf4\xc5\x04;\x18\xca\x04`\u0249\x05k\xc7^-c\x10\x00\x00\xe0\x94\x03qKA\u04a6\xf7Q\x00\x8e\xf8\xddM+)\xae\u02b8\xf3n\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x03r\xe8RX.\t44J\x0f\xed!x0M\xf2]F(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03r\xeeU\b\xbf\x81c\xed(N^\xef\x94\xceMsg\xe5\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x03}\xd0V\xe7\xfd\xbdd\x1d\xb5\xb6\xbe\xa2\xa8x\n\x83\xfa\u1009\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\x03\x83#\xb1\x84\xcf\xf7\xa8*\xe2\u1f67y?\xe41\x9c\xa0\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03\x87y\xca-\xbef>c\xdb?\xe7V\x83\xea\x0e\xc6.#\x83\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x03\x8eE\xea\xdd=\x88\xb8\u007f\xe4\u06b0fh\x05\"\xf0\xdf\xc8\xf9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x03\x92T\x9ar\u007f\x81eT)\u02d2\x8bR\x9f%\xdfM\x13\x85\x89\x01lC\xa0\xee\xa0t\x00\x00\u07d4\x03\x94\xb9\x0f\xad\xb8`O\x86\xf4?\xc1\xe3]1$\xb3*Y\x89\x89)j\xa1@'\x8ep\x00\x00\u0794\x03\x9ezN\xbc(N,\xcdB\xb1\xbd\xd6\v\xd6Q\x1c\x0fw\x06\x88\xf0\x15\xf2W6B\x00\x00\u07d4\x03\x9e\xf1\xceR\xfeyc\xf1f\u0562u\u0131\x06\x9f\xe3\xa82\x89\x15\xaf9\u4ab2t\x00\x00\u07d4\x03\xa2l\xfcL\x181op\u055e\x9e\x1ay\xee>\x8b\x96/L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xaab(\x81#m\xd0\xf4\x94\f$\xc3$\xff\x8b{~!\x86\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\x03\xafz\xd9\xd5\"<\xf7\xc8\xc1? \xdfg\xeb\xe5\xff\u017bA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xb0\xf1|\xd4F\x9d\xdc\u03f7\xdai~\x82\xa9\x1a_\x9ewt\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xb4\x1bQ\xf4\x1d\xf2\r\xd2y\xba\xe1\x8c\x12w_w\xadw\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x03\xbe[F)\xae\xfb\xbc\xab\x9d\xe2m9Wl\xb7\xf6\x91\xd7d\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x03\xc6G\xa9\xf9)\xb0x\x1f\xe9\xae\x01\u02a3\xe1\x83\xe8vw~\x89\x18*\xb7\xc2\f\xe5$\x00\x00\u07d4\x03\xc9\x1d\x92\x946\x03\xe7R >\x054\x0eV`\x13\xb9\x00E\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x03\xcbLOE\x16\xc4\xffy\xa1\xb6$O\xbfW.\x1c\u007f\xeay\x89\x94\x89#z\u06daP\x00\x00\u07d4\x03\u02d8\u05ec\xd8\x17\u079d\x88m\"\xfa\xb3\xf1\xb5}\x92\xa6\b\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x03\u031d-!\xf8k\x84\xac\x8c\xea\xf9q\u06e7\x8a\x90\xe6%p\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x03\xd1rO\xd0\x0eT\xaa\xbc\xd2\xde*\x91\xe8F+\x10I\xdd:\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\x03\xde\xdf\xcd\v<.\x17\xc7\x05\xda$\x87\x90\uf626\xbdWQ\x89Hz\x9a0E9D\x00\x00\u07d4\x03\u8c04SuW\xe7\t\xea\xe2\xe1\u1966\xbc\xe1\xef\x83\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xeam&\u0400\xe5z\xee9&\xb1\x8e\x8e\xd7:N[(&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xeb<\xb8`\xf6\x02\x8d\xa5T\xd3D\xa2\xbbZP\n\xe8\xb8o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xeb\xc6?\xdaf`\xa4e\x04^#_\xben\\\xf1\x95s_\x89\a\xb0l\xe8\u007f\xddh\x00\x00\xe0\x94\x03\xefj\xd2\x0f\xf7\xbdO\x00+\xacX\xd4uD\u03c7\x9a\xe7(\x8a\x01u\xc7X\u0439n\\\x00\x00\u07d4\x03\xf7\xb9 \b\x81:\xe0\xa6v\xeb!(\x14\xaf\xab5\"\x10i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\x11p\xf5\x81\u0780\xe5\x8b*\x04\\\x8f|\x14\x93\xb0\x01\xb7\u02c90\xc8\xeca2\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\x04i\xe8\xc4@E\v\x0eQ&&\xfe\x81~gT\xa8\x15(0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04m'K\x1a\xf6\x15\xfbPZvJ\xd8\u0767p\xb1\xdb/=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x04}Z&\u05ed\x8f\x8ep`\x0fp\xa3\x98\u076a\x1c-\xb2o\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x04~\x87\xc8\xf7\xd1\xfc\xe3\xb0\x13S\xa8Xb\xa9H\xac\x04\x9f>\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x04\u007f\x9b\xf1R\x9d\xaf\x87\xd4\a\x17^o\x17\x1b^Y\xe9\xff>\x89#<\x8f\xe4'\x03\xe8\x00\x00\xe0\x94\x04\x85'2\xb4\xc6R\xf6\xc2\u53b3e\x87\xe6\nb\xda\x14\u06ca\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x04\x8a\x89p\xeaAE\xc6MU\x17\xb8\xde[F\xd0YZ\xad\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x04\x9c]K\xc6\xf2]NEli{R\xa0x\x11\xcc\u045f\xb1\x89\x10D\x00\xa2G\x0eh\x00\x00\u07d4\x04\xa1\xca\xda\x1c\xc7Q\b/\xf8\u0692\x8e<\xfa\x00\b \xa9\xe9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x04\xa8\n\xfa\xd5>\xf1\xf8Ae\xcf\xd8R\xb0\xfd\xf1\xb1\xc2K\xa8\x89\x03$\xe9d\xb3\xec\xa8\x00\x00\u07d4\x04\xaa\xfc\x8a\xe5\xceoI\x03\u021d\u007f\xac\x9c\xb1\x95\x12\"Gw\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x04\xbaK\xb8q@\x02,!Jo\xacB\xdbZ\x16\u0755@E\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xba\x8a?\x03\xf0\x8b\x89P\x95\x99M\xdaa\x9e\u06ac\xee>z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xc2\xc6K\xb5L>\xcc\xd0U\x85\xe1\x0e\xc6\xf9\x9a\f\xdb\x01\xa3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x04\xceE\xf6\x00\xdb\x18\xa9\u0405\x1b)\xd99>\xbd\xaa\xfe=\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x04\u05b8\xd4\u0686t\a\xbb\x99wI\u07bb\xcd\xc0\xb3XS\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xd78\x96\xcfe\x93\xa6\x91\x97*\x13\xa6\xe4\x87\x1f\xf2\xc4+\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xd8*\xf9\xe0\x1a\x93m\x97\xf8\xf8Y@\xb9p\xf9\xd4\u06d96\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x04\xe5\xf5\xbc|\x92?\xd1\xe3\x175\xe7.\xf9h\xfdg\x11\fn\x89WU\x1d\xbc\x8ebL\x00\x00\u07d4\x04\xec\xa5\x01c\n\xbc\xe3R\x18\xb1t\x95k\x89\x1b\xa2^\xfb#\x8966\x9e\xd7t}&\x00\x00\u07d4\x05\x05\xa0\x8e\"\xa1\t\x01Z\"\xf6\x850STf*U1\u0549\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x05\x14\x95L\xe8\x81\xc807\x03d\x00\x89lO\xd1\xee$nx\x00\x00\u07d4\x05\x1dBBv\xb2\x129fQ\x86\x13=e;\xb8\xb1\x86/\x89\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05!\xbc:\x9f\x87\x11\xfe\xcb\x10\xf5\a\x97\xd7\x10\x83\xe3A\ub749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05#mL\x90\xd0e\xf9\u34c3X\xaa\xff\xd7w\xb8j\xecI\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x05*X\xe05\xf1\xfe\x9c\xdd\x16\x9b\xcf \x97\x03E\xd1+\x9cQ\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x05.\xab\x1fa\xb6\xd4U\x17(?A\xd1D\x18$\x87\x87I\u0409\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x053n\x9ar'(\xd9c\xe7\xa1\xcf'Y\xfd\x02tS\x0f\u02891\xa2D?\x88\x8ay\x80\x00\u07d4\x054q\u035aA\x92[9\x04\xa5\xa8\xff\xca6Y\xe04\xbe#\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4\x056\x1d\x8e\xb6\x94\x1dN\x90\xfb~\x14\x18\xa9Z2\xd5%w2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05B:T\xc8\xd0\xf9p~pAs\xd9#\xb9F\xed\xc8\xe7\x00\x89\x06\xea\x03\u00bf\x8b\xa5\x80\x00\u07d4\x05D\f[\a;R\x9bH) \x9d\xff\x88\t\x0e\a\xc4\xf6\xf5\x89E\u04977\xe2/ \x00\x00\u07d4\x05Z\xb6X\xc6\xf0\xedO\x87^\xd6t.K\xc7)-\x1a\xbb\xf0\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x05[\xd0,\xaf\x19\xd6 +\xbc\u0703m\x18{\xd1\xc0\x1c\xf2a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05^\xacO\x1a\xd3\xf5\x8f\v\xd0$\u058e\xa6\r\xbe\x01\u01af\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05fQU\xccI\xcb\xf6\xaa\xbd\u056e\x92\xcb\xfa\xad\x82\xb8\xc0\xc1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x05f\x86\a\x8f\xb6\xbc\xf9\xba\n\x8a\x8d\xc6:\x90o_\xea\xc0\xea\x89\x1b\x18\x1eK\xf24<\x00\x00\u07d4\x05iks\x91k\xd3\x03>\x05R\x1e2\x11\xdf\xec\x02n\x98\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x05k\x15F\x89O\x9a\x85\xe2\x03\xfb3m\xb5i\xb1l%\xe0O\x89\t.\xdb\t\xff\b\u0600\x00\u07d4\x05yI\xe1\xca\x05pF\x9eL\xe3\u0190\xaea:k\x01\xc5Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x05}\u049f-\x19\xaa=\xa4#'\xeaP\xbc\xe8o\xf5\xc9\x11\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x05\u007f\u007f\x81\xcdz@o\xc4Y\x94@\x8bPI\x91,Vdc\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x05\x91]N\"Zf\x81b\xae\xe7\xd6\xc2_\xcf\xc6\xed\x18\xdb\x03\x89\x03\x98\xc3ry%\x9e\x00\x00\u07d4\x05\x96\xa2}\xc3\xee\x11_\xce/\x94\xb4\x81\xbc z\x9e&\x15%\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05\xa80rC\x02\xbc\x0fn\xbd\xaa\x1e\xbe\xee\xb4nl\xe0\v9\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\x05\xae\u007f\u053b\u0300\xca\x11\xa9\n\x1e\u01e3\x01\xf7\xcc\u0303\u06c91T\xc9r\x9d\x05x\x00\x00\u07d4\x05\xbbd\xa9\x16\xbef\xf4`\xf5\xe3\xb6C2\x11\r \x9e\x19\xae\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\x05\xbfO\xcf\xe7r\xe4[\x82dC\x85.l5\x13P\xcer\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\x05\xc6@\x04\xa9\xa8&\xe9N^N\xe2g\xfa*v2\xddNo\x8a\x03m\xc4.\xbf\xf9\v\u007f\x80\x00\xe0\x94\x05\xc76\xd3e\xaa7\xb5\xc0\xbe\x9c\x12\u022d\\\xd9\x03\xc3,\xf9\x8a\x01E^{\x80\n\x86\x88\x00\x00\xe0\x94\x05\xcbl;\x00r\xd3\x11ga\xb52\xb2\x18D;S\xe8\xf6\u014a\x1e\x02\xc3\xd7\xfc\xa9\xb6(\x00\x00\u07d4\x05\xd0\xf4\xd7(\xeb\xe8.\x84\xbfYu\x15\xadA\xb6\v\xf2\x8b9\x89\u3bb5sr@\xa0\x00\x00\u07d4\x05\u058d\xada\u04fb\u07f3\xf7y&\\IGJ\xff?\xcd0\x89\x02\"\xc5]\xc1Q\x9d\x80\x00\u07d4\x05\xe6q\xdeU\xaf\xec\x96K\aM\xe5t\xd5\x15\x8d]!\xb0\xa3\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x05\xe9{\tI,\u058fc\xb1+\x89.\xd1\xd1\x1d\x15,\x0e\u02897\b\xba\xed=h\x90\x00\x00\u07d4\x05\xf3c\x1fVd\xbd\xad]\x012\xc88\x8d6\xd7\u0612\t\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x06\t\xd8:l\xe1\xff\u0276\x90\xf3\xe9\xa8\x1e\x98>\x8b\xdcM\x9d\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4\x06\x1e\xa4\x87|\u0409D\xebd\u0096n\x9d\xb8\xde\xdc\xfe\xc0k\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06%\xd0`V\x96\x8b\x00\"\x06\xff\x91\x98\x01@$+\xfa\xa4\x99\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06(\xbf\xbeU5x/\xb5\x88@k\xc9f`\xa4\x9b\x01\x1a\xf5\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x061\u044b\xbb\xbd0\xd9\xe1s+\xf3n\xda\xe2\u0389\x01\xab\x80\x89\xa3\xf9\x88U\xec9\x90\x00\x00\u07d4\x061\xdc@\xd7NP\x95\xe3r\x9e\xdd\xf4\x95D\xec\xd49og\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\x067Y\xdd\x1cN6.\xb1\x93\x98\x95\x1f\xf9\xf8\xfa\xd1\xd3\x10h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06_\xf5u\xfd\x9c\x16\xd3\xcbo\u058f\xfc\x8fH?\xc3.\xc85\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06a\x8e\x9dWb\xdfb\x02\x86\x01\xa8\x1dD\x87\u05a0\xec\xb8\x0e\x89Hz\x9a0E9D\x00\x00\xe0\x94\x06fG\xcf\xc8]#\xd3v\x05W= \x8c\xa1T\xb2D\xd7l\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06xeJ\xc6v\x1d\xb9\x04\xa2\xf7\xe8Y^\xc1\xea\xacsC\b\x89/\x98\xb2\x9c(\x18\xf8\x00\x00\u07d4\x06\x86\n\x93RYU\xffbI@\xfa\xdc\xff\xb8\xe1I\xfdY\x9c\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94\x06\x8c\xe8\xbdn\x90*E\u02c3\xb5\x15A\xb4\x0f9\xc4F\x97\x12\x8a\x01\x1c\x0f\x9b\xadJF\xe0\x00\x00\u07d4\x06\x8e)\xb3\xf1\x91\xc8\x12\xa699\x18\xf7\x1a\xb93\xaehG\xf2\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x06\x8eeWf\xb9D\xfb&6\x19e\x87@\xb8P\xc9J\xfa1\x89\x01\xe8\u007f\x85\x80\x9d\xc0\x00\x00\u0794\x06\x96N-\x17\xe9\x18\x9f\x88\xa8 96\xb4\n\xc9nS<\x06\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x06\x99L\xd8:\xa2d\n\x97\xb2`\vA3\x9d\x1e\r>\xdel\x89\r\x8drkqw\xa8\x00\x00\u07d4\x06\x9e\u042bz\xa7}\xe5q\xf1a\x06\x05\x1d\x92\xaf\xe1\x95\xf2\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06\xac&\xad\x92\u02c5\x9b\u0550]\xdc\xe4&j\xa0\xecP\xa9\u0149*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x06\xb0\xc1\xe3\u007fZ^\u013b\xf5\b@T\x8f\x9d:\xc0(\x88\x97\x89\xd8\u0602\u148e}\x00\x00\u07d4\x06\xb0\xff\x83@s\xcc\xe1\xcb\xc9\xeaU~\xa8{`Yc\u8d09\x10CV\x1a\x88)0\x00\x00\xe0\x94\x06\xb1\x06d\x9a\xa8\xc4!\xdd\xcd\x1b\x8c2\xcd\x04\x18\xcf0\xda\x1f\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x06\xb5\xed\xe6\xfd\xf1\xd6\xe9\xa3G!7\x9a\xea\xa1|q=\xd8*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x06\xcb\xfa\b\xcd\xd4\xfb\xa77\xba\xc4\a\xbe\x82$\xf4\xee\xf3X(\x89 +\xe5\xe88.\x8b\x80\x00\u07d4\x06\xd6\xcb0\x84\x81\xc36\xa6\xe1\xa2%\xa9\x12\xf6\xe65Y@\xa1\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x06\xdc\u007f\x18\xce\xe7\xed\xab[yS7\xb1\xdfj\x9e\x8b\u062eY\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x06\xf6\x8d\xe3\xd79\xdbA\x12\x1e\xac\xf7y\xaa\xda=\xe8v!\a\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x06\xf7\u070d\x1b\x94b\xce\xf6\xfe\xb13h\xa7\xe3\x97K\t\u007f\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\a\x01\xf9\xf1G\xecHhV\xf5\xe1\xb7\x1d\xe9\xf1\x17\xe9\x9e!\x05\x89\te\xdaq\u007f\u0578\x00\x00\u07d4\a\r]6L\xb7\xbb\xf8\"\xfc,\xa9\x1a5\xbd\xd4A\xb2\x15\u0549lk\x93[\x8b\xbd@\x00\x00\xe0\x94\a\x1d\xd9\r\x14\xd4\x1fO\xf7\xc4\x13\xc2B8\xd35\x9c\xd6\x1a\a\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4\a&\xc4.\x00\xf4T\x04\x83n\xb1\xe2\x80\xd0s\xe7\x05\x96\x87\xf5\x89X\x00>?\xb9G\xa3\x80\x00\xe0\x94\a'\xbe\n*\x00! H\xb5R\x0f\xbe\xfb\x95>\xbc\x9dT\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a)\xa8\xa4\xa5\xba#\xf5y\xd0\x02[\x1a\xd0\xf8\xa0\xd3\\\xdf\u048a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\a)\xb4\xb4|\t\xeb\x16\x15\x84d\u022a\u007f\xd9i\vC\x889\x89lh\xcc\u041b\x02,\x00\x00\u0794\a4\xa0\xa8\x1c\x95b\xf4\xd9\xe9\xe1\n\x85\x03\xda\x15\xdbF\xd7n\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\a\xa7\xef[G\x00\x00\xe0\x94\ap\xc6\x1b\xe7\x87r#\f\xb5\xa3\xbb$)\xa7&\x14\xa0\xb36\x8a\x01n\u0899\xb7\x13A\x80\x00\u07d4\ar><0\xe8\xb71\xeeEj)\x1e\xe0\u7630 Jw\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\as\xee\xac\xc0P\xf7G \xb4\xa1\xbdW\x89[\x1c\xce\xebI]\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a\x80\r/\x80h\xe4H\u01daOi\xb1\xf1^\xf6\x82\xaa\xe5\xf6\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\a\xa8\xda\xde\xc1BW\x1a}S\xa4)pQxm\a,\xbaU\x89\x01;m\xa1\x13\x9b\u0680\x00\u07d4\a\xaf\x93\x8c\x127\xa2|\x900\tM\xcf$\aP$n=,\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\a\xb1\xa3\x06\xcbC\x12\xdffH,,\xaer\xd1\xe0a@\x0f\u034a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\a\xb7\xa5p3\xf8\xf1\x130\xe4f^\x18]#N\x83\xec\x14\v\x89\xea~\xe9*\f\x9a\v\x80\x00\u07d4\a\xbc,\xc8\xee\xdc\x01\x97\a\x00\xef\xc9\xc4\xfb6s^\x98\xcdq\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd4\x12\x17\xba\u0725\xe0\xe6\x03'\xd8E\xa3FO\x0f'\xf8J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd43N\u00c5\xe8\xaaT\xee\xda\xea\xdb0\x02/\f\u07e4\xab\x89\x8e\x91\xd5 \xf2\xeby\x00\x00\u07d4\a\xda\xe6\"c\r\x1168\x193\u04adk\"\xb89\xd8!\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\a\xdc+\xf8;\u01af\x19\xa8B\xff\xeaf\x1a\xf5\xb4\x1bg\xfd\xa1\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\a\u070c\x8b\x92z\xdb\xed\xfa\x8f]c\x9bCR5\x1f/6\u0489\x11\n\xed;U0\xdb\x00\x00\u07d4\a\xdd\xd0B,\x86\xefe\xbf\f\u007f\xc3E(b\xb1\"\x8b\b\xb8\x89o\xf5\u04aa\x8f\x9f\xcf\x00\x00\u07d4\a\xe1\x16,\xea\xe3\xcf!\xa3\xf6-\x10Y\x900.0\u007fN;\x89R\xf1\x03\xed\xb6k\xa8\x00\x00\u07d4\a\xe2\xb4\xcd\xee\xd9\u0407\xb1.Um\x9ew\f\x13\xc0\x99a_\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\a\xfe\xefT\xc16\x85\b)\xba\xdcKI\xc3\xf2\xa7<\x89\xfb\x9e\x89\x06hZ\xc1\xbf\xe3,\x00\x00\u07d4\b\x05FP\x8a=&\x82\u0239\x88O\x13c{\x88G\xb4M\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\t\bv\xba\xad\xfe\xe6\\=6;\xa5S\x12t\x8c\xfa\x87=\x89\\*\x997\x1c\xff\xe1\x00\x00\u07d4\b\x16o\x021?\xea\u12f0D\xe7\x87|\x80\x8bU\xb5\xbfX\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b)\xd0\xf7\xbb|Dl\xfb\xb0\u07ad\xb29M\x9d\xb7$\x9a\x87\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\b0m\xe5\x19\x81\u7b21\x85hY\xb7\xc7xijki\xf9\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\b7S\x9b_jR*H,\xdc\u04e9\xbbpC\xaf9\xbd\u048a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\b8\xa7v\x8d\x9c*\u028b\xa2y\xad\xfe\xe4\xb1\xf4\x91\xe3&\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\bA\x16R\xc8qq6\t\xaf\x00b\xa8\xa1(\x1b\xf1\xbb\xcf\u0649K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\bM\x102Tu\x9b4<\xb2\xb9\xc2\xd8\xff\x9e\x1a\xc5\xf1E\x96\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4\bPO\x05d?\xabY\x19\xf5\xee\xa5Y%\u05e3\xed}\x80z\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b[J\xb7]\x83b\xd9\x14C\\\xed\xee\x1d\xaa+\x1e\xe1\xa2;\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\b[\xa6_\xeb\xe2>\xef\xc2\xc8\x02fj\xb1&#\x82\xcf\u0114\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\bt\x98\xc0FFh\xf3\x11P\xf4\xd3\u013c\u0765\"\x1b\xa1\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\bw\uebabx\xd5\xc0\x0e\x83\xc3+-\x98\xfay\xadQH/\x89\x17\xd2-q\xdab&\x00\x00\u0794\b\x93j7\u07c5\xb3\xa1X\xca\xfd\x9d\xe0!\xf5\x817h\x13G\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\b\xa9\xa4N\x1fA\xde=\xbb\xa7\xa3c\xa3\xabA,\x12L\xd1^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xb7\xbd\u03d4MUp\x83\x8b\xe7\x04`$:\x86\x94HXX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xb8E6\xb7L\x8c\x01T=\xa8\x8b\x84\u05cb\xb9WG\xd8\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xc2\xf26\xacJ\xdc\xd3\xfd\xa9\xfb\xc6\xe4S\"S\xf9\xda;\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b\xc8\x02\xf8wX4\x9f\xa0>k\xc2\xe2\xfd\a\x91\x19~\ua689lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xc9\U0007fd89\xfd\xf8\x04\xd7i\xf8!#6\x02\x15\xaf\xf9;\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b\xca\u0215&A\xd8\xfcRn\xc1\xabO-\xf8&\xa5\xe7q\x0f\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\b\xcc\xdaP\xe4\xb2j\x0f\xfc\x0e\xf9.\x92\x051\a\x06\xbe\xc2\u01ca\x01Iul8W\xc6\x00\x00\x00\u07d4\b\u0406M\xc3/\x9a\xcb6\xbfN\xa4G\xe8\xddg&\x90j\x15\x89lnY\xe6|xT\x00\x00\u07d4\b\xd4&\u007f\xeb\x15\u0697\x00\xf7\xcc\xc3\xc8J\x89\x18\xbf\x17\xcf\u0789a\t=|,m8\x00\x00\xe0\x94\b\xd41\x1c\x9c\x1b\xba\xf8\u007f\xab\xe1\xa1\xd0\x14c\x82\x8d]\x98\u038a\x13\x0e\xe8\xe7\x17\x90D@\x00\x00\u07d4\b\xd5N\x83\xadHj\x93L\xfa\xea\u20e3>\xfd\"|\x0e\x99\x898S\x05\x83$^\xdc\x00\x00\u07d4\b\xd9~\xad\xfc\xb7\xb0d\xe1\xcc\xd9\u0217\x9f\xbe\xe5\xe7z\x97\x19\x89\x0el]\xa8\xd6z\xc1\x80\x00\u07d4\b\xda:z\x0fE!a\u03fc\xec1\x1b\xb6\x8e\xbf\xde\xe1~\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xe3\x8e\xe0\xceH\xc9\xcad\\\x10\x19\xf7;SUX\x1cV\xe6\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\b\xef?\xa4\xc4<\xcd\xc5{\"\xa4\xb9\xb23\x1a\x82\xe58\x18\xf2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\td\x8c\x18\xa3\xce[\xaez\x04~\xc2\xf8h\xd2L\u0768\x1d\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\t\f\xd6{`\xe8\x1dT\xe7\xb5\xf6\a\x8f>\x02\x1b\xa6[\x9a\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\f\xeb\xef),>\xb0\x81\xa0_\u062a\xf7\u04db\xf0{\x89\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\x0f\xa96{\xdaW\xd0\xd3%:\n\x8f\xf7l\xe0\xb8\xe1\x9as\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x14n\xa3\x88Qv\xf0w\x82\xe1\xfe0\xdc\xe3\xce$\u011e\x1f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\t!`_\x99\x16N;\xcc(\xf3\x1c\xae\xcex\x971\x82V\x1d\x89+\ai*\x90e\xa8\x00\x00\xe0\x94\t&\x1f\x9a\xcbE\x1c7\x88\x84O\f\x14Q\xa3[\xadP\x98\xe3\x8a\x01\u056d'P) `\x00\x00\xe0\x94\t'\"\x04\x92\x19K.\u069f\u013b\xe3\x8f%\u0581\xdf\xd3l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\t*\xcbbK\b\xc0U\x10\x18\x9b\xbb\xe2\x1ee$\xd6D\u032d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t.\x81UX@-g\xf9\rk\xfem\xa0\xb2\xff\xfa\x91EZ\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\tP0\xe4\xb8&\x92\xdc\xf8\xb8\u0411$\x94\xb9\xb3x\xec\x93(\x89H\xa4zu\x80\x00\u07d4\t\x89\xc2\x00D\v\x87\x89\x91\xb6\x9d`\x95\xdf\xe6\x9e3\xa2.p\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\t\x90\xe8\x1c\u05c5Y\x9e\xa26\xbd\x19f\xcfRc\x02\xc3[\x9c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x98\xd8'1\x15\xb5j\xf4%\xff\xc8>!\x8c\x1e\n\xfe\x89(\u01c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t\xaeI\xe3\u007f\x12\x1d\xf5\xdc\x15\x8c\xfd\xe8\x06\xf1s\xa0k\f\u007f\x89\xd80\x9e&\xab\xa1\xd0\x00\x00\u07d4\t\xaf\xa7;\xc0G\xefF\xb9w\xfd\x97c\xf8r\x86\xa6\xbeh\u0189\x1b/\xb5\xe8\xf0jf\x00\x00\u07d4\t\xb4f\x86\x96\xf8j\b\x0f\x8b\xeb\xb9\x1d\xb8\xe6\xf8p\x15\x91Z\x89#\x8f\xf7\xb3O`\x01\x00\x00\xe0\x94\t\xb5\x9b\x86\x98\xa7\xfb\xd3\xd2\xf8\xc7:\x00\x89\x88\xde>@k+\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\t\xb7\xa9\x88\xd1?\xf8\x91\x86so\x03\xfd\xf4au\xb5=\x16\xe0\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xc1w\xf1\xaeD$\x11\u076c\xf1\x87\xd4m\xb9V\x14\x83`\xe7\x8a\x01\xe5.3l\xde\"\x18\x00\x00\xe0\x94\t\u020f\x91~Mj\xd4s\xfa\x12\u93a3\xc4G*^\xd6\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\t\u0438\xcd\a|i\xd9\xf3-\x9c\xcaC\xb3\xc2\b\xa2\x1e\u050b\x89\b!\xd2!\xb5)\x1f\x80\x00\xe0\x94\t\xd6\xce\xfdu\xb0\u0133\xf8\xf1\u0587\xa5\"\xc9a#\xf1\xf59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xe47\xd4H\x86\x12(\xa22\xb6.\xe8\xd3ye\xa9\x04\ud70a\x04\x98\xcf@\x1d\xf8\x84.\x80\x00\u07d4\t\xee\x12\xb1\xb4+\x05\xaf\x9c\xf2\a\xd5\xfc\xac%[.\xc4\x11\xf2\x89\x031\xcd\xddG\xe0\xfe\x80\x00\u07d4\t\xf3\xf6\x01\xf6\x05D\x11@Xl\xe0eo\xa2J\xa5\xb1\u066e\x89Sswo\xe8\xc4T\x00\x00\u07d4\t\xf9W[\xe5}\x00G\x93\u01e4\ub137\x15\x87\xf9|\xbbj\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\x06P\x86\x1fx^\xd8\xe4\xbf\x10\x05\xc4P\xbb\xd0n\xb4\x8f\xb6\x89\xa6A;y\x14N~\x00\x00\u07d4\n\x06\xfa\xd7\xdc\u05e4\x92\xcb\xc0S\xee\xab\xdei4\xb3\x9d\x867\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n\a}\xb1?\xfe\xb0\x94\x84\xc2\x17p\x9dX\x86\xb8\xbf\x9cZ\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n\x0e\u0366cow\x16\xef\x19saF\x87\xfd\x89\xa8 \xa7\x06\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\n)\xa8\xa4\xd5\xfd\x95\x00u\xff\xb3Mw\xaf\xeb-\x82;\u0589\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n*\u0795\xb2\xe8\xc6m\x8a\xe6\xf0\xbad\xcaW\u05c3\xbemD\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n+O\xc5\xd8\x1a\xceg\xdcK\xba\x03\xf7\xb4UA=F\xfe=\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\n-\xcbzg\x17\x01\u06f8\xf4\x95r\x80\x88&Xs5l\x8e\x89\b?\x16\xce\b\xa0l\x00\x00\u07d4\n=\xe1U\xd5\xec\xd8\xe8\x1c\x1f\xf9\xbb\xf07\x83\x01\xf8\xd4\xc6#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\nG\xad\x90Y\xa2I\xfc\x93k&b5=\xa6\x90_u\u00b9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\nH)ov1p\x8c\x95\u04b7Iu\xbcJ\xb8\x8a\xc19*\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\nJ\x01\x19\x95\u0181\xbc\x99\x9f\xddyuN\x9a2J\xe3\xb3y\x8a\b\xc1\x9a\xb0n\xb8\x9a\xf6\x00\x00\u07d4\nX\xfd\xddq\x89\x8d\xe7s\xa7O\xda\xe4^{\xd8N\xf46F\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n[y\xd8\xf2;d\x83\xdb\u2f6ab\xb1\x06L\xc7cf\xae\x89j\u0202\x10\tR\u01c0\x00\u07d4\ne.*\x8bw\xbd\x97\xa7\x90\xd0\xe9\x13a\u0248\x90\u06f0N\x8965\u026d\xc5\u07a0\x00\x00\u07d4\nn\xber;n\xd1\xf9\xa8ji\xdd\xdah\xdcGF\\+\x1b\x89@=-\xb5\x99\xd5\xe4\x00\x00\u07d4\nw\xe7\xf7+C{WO\x00\x12\x8b!\xf2\xac&Q3R\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\n\x91\u007f;\\\xb0\xb8\x83\x04\u007f\u0676Y=\xbc\xd5W\xf4S\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\n\x93\x1bD\x9e\xa8\xf1,\xdb\xd5\xe2\xc8\xccv\xba\xd2\xc2|\x069\x89\x01?\x9e\x8cy\xfe\x05\x80\x00\u0794\n\x98\x04\x13x\x03\xbahh\xd9:U\xf9\x98_\xcdT\x04Q\u4239\x8b\xc8)\xa6\xf9\x00\x00\u07d4\n\x9a\xb2c\x8b\x1c\xfdeM%\u06b0\x18\xa0\xae\xbd\u07c5\xfdU\x89\x01.\x8c\xb5\xfeLJ\x80\x00\u07d4\n\xb3f\xe6\xe7\u056b\xbc\xe6\xb4JC\x8di\xa1\u02bb\x90\xd13\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\n\xb4(\x1e\xbb1\x85\x90\xab\xb8\x9a\x81\xdf\a\xfa:\xf9\x04%\x8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\n\xb5\x9d9\a\x02\xc9\xc0Y\xdb\x14\x8e\xb4\xf3\xfc\xfa}\x04\xc7\xe7\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\n\xbf\xb3\x9b\x11HmyW(f\x19[\xa2lc\vg\x84\u06ca\x19\xba\x877\xf9i(\xf0\x00\x00\u07d4\n\u029aV&\x91;\b\xcf\u0266m@P\x8d\xceR\xb6\x0f\x87\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\n\xd3\xe4M<\x00\x1f\xa2\x90\xb3\x93ap0TA\b\xacn\xb9\x89j\xbd\xa0\xbc0\xb2\u07c0\x00\u07d4\n\xec.Bn\xd6\xcc\f\xf3\xc2I\xc1\x89~\xacG\xa7\xfa\xa9\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\xf6_\x14xNU\xa6\xf9Vg\xfds%*\x1c\x94\a-*\x89\nv;\x8e\x02\xd4O\x80\x00\u07d4\n\xf6\xc8\xd59\xc9mP%\x9e\x1b\xa6q\x9e\x9c\x80`\xf3\x88\u008965\u026d\xc5\u07a0\x00\x00\u07d4\v\x069\x0f$7\xb2\x0e\u0123\xd3C\x1b2y\xc6X>^\u05c9\n\x84Jt$\xd9\xc8\x00\x00\u07d4\v\v8b\x11*\xee\u00e04\x92\xb1\xb0_D\x0e\xcaT%n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\x0e\x05[(\xcb\xd0=\xc5\xffD\xaad\xf3\xdc\xe0O^c\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x11\x9d\xf9\x9ck\x8d\xe5\x8a\x1e,?)zgD\xbfU\"w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x14\x89\x19\x99\xa6\\\x9e\xf73\b\xef\xe3\x10\f\xa1\xb2\x0e\x81\x92\x89+^:\xf1k\x18\x80\x00\x00\u07d4\v!\x13PE4d*\x1d\xaf\x10.\xee\x10\xb9\xeb\xdev\xe2a\x89\x94,\xdd|\x95\xf2\xbd\x80\x00\xe0\x94\v(\x8aZ\x8bu\xf3\xdcA\x91\xeb\x04W\xe1\xc8=\xbd M%\x8a\x01\a\x14\xe7{\xb4:\xb4\x00\x00\u07d4\v6\x9e\x00.\x1bLy\x13\xfc\xf0\x0f-^\x19\u0141eG\x8f\x89\x03\u007fe\x16(\x8c4\x00\x00\u07d4\vC\xbd#\x91\x02U\x81\u0615l\xe4*\a%y\u02ff\xcb\x14\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\vP|\xf5SV\x8d\xaa\xf6U\x04\xaeN\xaa\x17\xa8\xea<\xdb\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v]f\xb1<\x87\xb3\x92\xe9M\x91\xd5\xf7l\rE\nU(C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v^ \x11\xeb\xc2Z\x00\u007f!6)`I\x8a\xfb\x8a\xf2\x80\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vd\x9d\xa3\xb9j\x10,\xdcm\xb6R\xa0\xc0}e\xb1\xe4C\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vi \xa6K6;\x8d]\x90\x80$\x94\xcfVKT|C\r\x89A\rXj \xa4\xc0\x00\x00\u07d4\vp\x11\x01\xa4\x10\x9f\x9c\xb3`\xdcW\xb7tBg=^Y\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vq\xf5T\x12$i\uf5ce/\x1f\xef\xd7\u02f4\x10\x98'r\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\xe0\x94\v{\xb3B\xf0\x1b\u0248\x8ej\x9a\xf4\xa8\x87\xcb\xf4\xc2\xdd,\xaf\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\v}3\x93q\xe5\xbeg'\xe6\xe31\xb5\x82\x1f\xa2K\u06ddZ\x89.\u007f\x81\x86\x82b\x01\x00\x00\u07d4\v\u007f\xc9\xdd\xf7\x05v\xf63\x06i\xea\xaaq\xb6\xa81\xe9\x95(\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\v\x80\xfcp(,\xbd\xd5\xfd\xe3[\xf7\x89\x84\xdb;\xdb\x12\x01\x88\x8968\x02\x1c\xec\u06b0\x00\x00\u07d4\v\x92M\xf0\a\xe9\xc0\x87\x84\x17\xcf\xe6;\x97n\xa1\xa3\x82\xa8\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\v\x93\xfc\xa4\xa4\xf0\x9c\xac \xdb`\xe0e\xed\xcc\xcc\x11\u0976\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\v\x9d\xf8\x0f\xbe# \t\xda\xcf\n\xa8\xca\u0153v\xe2Gb\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xa6\xe4j\xf2Z\x13\xf5qi%Z4\xa4\xda\xc7\xce\x12\xbe\x04\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\v\xa8p[\xf5\\\xf2\x19\xc0\x95k^?\xc0\x1cDt\xa6\xcd\xc1\x89\x05%\xe0Y]Mk\x80\x00\u07d4\v\xafn\u0379\x1a\xcb6\x06\xa85|\v\xc4\xf4\\\xfd-~o\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xb0_r$\xbbX\x04\x85eV\xc0~\xea\xdb\ud1fa\x8f|\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\v\xb0\xc1&\x82\xa2\xf1\\\x9bWA\xb28\\\xbeA\xf04\x06\x8e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\v\xb2\\\xa7\u0448\xe7\x1eMi={\x17\a\x17\xd6\xf8\xf0\xa7\n\x89\x12C\x02\xa8/\xad\xd7\x00\x00\u07d4\v\xb2e\x0e\xa0\x1a\xcau[\xc0\xc0\x17\xb6K\x1a\xb5\xa6m\x82\xe3\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb5Lr\xfdf\x10\xbf\xa463\x97\xe0 8K\x02+\fI\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb7\x16\n\xba)7b\xf8sO>\x03&\xff\u0264\xca\xc1\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xc9\\\xb3-\xbbWL\x83/\xa8\x17J\x815m8\xbc\x92\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xd6}\xbd\xe0z\x85n\xbd\x89;^\xdcO:[\xe4 &\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xdb\xc5L\u023d\xbb\xb4\x02\xa0\x89\x11\xe2#*T`\u0386k\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\v\xddX\xb9n|\x91m\xd2\xfb05o*\xeb\xfa\xaf\x1d\x860\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\v\u1f39\x03C\xfa\xe501s\xf4a\xbd\x91JH9\x05l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\v\xe1\xfd\xf6&\xeea\x89\x10-p\xd1;1\x01,\x95\xcd\x1c\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xe2\xb9J\xd9P\xa2\xa6&@\xc3[\xfc\xcdlg\xda\xe4P\xf6\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\v\u681eC\a\xfeH\xd4\x12\xb8\u0461\xa8(M\xceHba\x8a\x04\x0f\xbf\xf8\\\x0180\x00\x00\u07d4\v\xef\xb5G\a\xf6\x1b,\x9f\xb0G\x15\xab\x02n\x1b\xb7 B\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\xf0dB\x8f\x83bg\"\xa7\xb5\xb2j\x9a\xb2\x04!\xa7r>\x89\a?u\u0460\x85\xba\x00\x00\u07d4\v\xfb\xb6\x92]\xc7^R\xcf&\x84\"K\xbe\x05P\xfe\xa6\x85\u04c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\f\b\x80\x06\xc6K0\xc4\u076f\xbc6\xcb_\x05F\x9e\xb6(4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f s\xbaD\xd3\u077d\xb69\xc0N\x19\x109\xa7\x17\x16#\u007f\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\f\",|A\u0270H\xef\xcc\xe0\xa22CCb\xe1-g;\x8a\x02\x1e\x83Yivw8\x00\x00\xe0\x94\f(\b\xb9Q\ud787-{2y\x0f\xccY\x94\xaeA\xff\u070a\x15\x99n[<\u05b3\xc0\x00\x00\u07d4\f(\x84~O\t\xdf\xce_\x9b%\xaf|NS\x0fY\u0200\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f-\\\x92\x058\xe9S\u02af$\xf0s\u007fUL\u0192wB\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f0\xca\xcc?r&\x9f\x8bO\x04\xcf\a=+\x05\xa8=\x9a\u0449lyt\x12?d\xa4\x00\x00\u07d4\f29\xe2\xe8A$-\xb9\x89\xa6\x15\x18\xc2\"G\xe8\xc5R\b\x89\x0eJ\xf6G\x174d\x00\x00\xe0\x94\fH\r\xe9\xf7F\x10\x02\x90\x8bI\xf6\x0f\xc6\x1e+b\xd3\x14\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\fH\xaeb\xd1S\x97\x88\xeb\xa0\x13\xd7^\xa6\vd\xee\xbaN\x80\x89w\xfb\xdcC\xe00\x99\x80\x00\u07d4\fU\x89\xa7\xa8\x9b\x9a\xd1[\x02u\x190AYH\xa8u\xfb\xef\x89\x06\u0519\xeclc8\x00\x00\u07d4\fg\x03=\xd8\xee\u007f\f\x8a\xe54\xd4*Q\xf7\xd9\xd4\xf7\x97\x8f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\fhE\xbfA\xd5\xee'<>\u6d70\u059fo\xd5\xea\xbb\xf7\x89\xa2\xa1\xb9h.X\t\x00\x00\xe0\x94\f\u007f\x86\x9f\x8e\x90\xd5?\xdc\x03\u8c81\x9b\x01k\x9d\x18\xeb&\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\f\x86\x92\xee\xff*S\xd6\xd1h\x8e\xd5j\x9d\u06fdh\u06bb\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\x8ff\xc6\x01{\xce[ 4r\x04\xb6\x02\xb7C\xba\u05cd`\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\f\x8f\xd7w^T\xa6\xd9\u0263\xbf\x89\x0ev\x1fewi?\xf0\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\f\x92Z\xd5\xeb5,\x8e\xf7m\f\"-\x11[\a\x91\xb9b\xa1\x89\xacc]\u007f\xa3N0\x00\x00\u07d4\f\x96~0a\xb8zu>\x84P~\xb6\t\x86x,\x8f0\x13\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\f\xa1*\xb0\xb9fl\xf0\xce\xc6g\x1a\x15)/&SGj\xb2\x8a,x'\xc4-\"\xd0|\x00\x00\u07d4\f\xa6p\xeb,\x8b\x96\u02e3y!\u007fY)\u00b8\x92\xf3\x9e\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\xae\x10\x8em\xb9\x9b\x9ecxv\xb0d\xc60>\u068ae\u0209\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\f\xbd\x92\x1d\xbe\x12\x15c\xb9\x8ahq\xfe\xcb\x14\xf1\xcc~\x88\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\f\xbf\x87p\xf0\xd1\b.\\ \u016e\xad4\xe5\xfc\xa9\xaez\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f\xc6\u007f\x82s\xe1\xba\xe0\x86\u007f\xd4.\x8b\x81\x93\xd7&y\xdb\xf8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\f\u05a1A\x91\x8d\x12k\x10m\x9f.\xbfi\xe1\x02\xdeM2w\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\f\xda\x12\xbfr\xd4a\xbb\xc4y\xeb\x92\xe6I\x1d\x05~kZ\u044a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\f\u0716\v\x99\x8c\x14\x19\x98\x16\r\xc1y\xb3l\x15\u0484p\xed\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\f\xfb\x17#5\xb1l\x87\xd5\x19\xcd\x14uS\r W\u007f^\x0e\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\r\x1f*Wq>\xbcn\x94\xde)\x84n\x88D\xd3vfWc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\r2e\xd3\u7f79=^\x8e\x8b\x1c\xa4\u007f!\ny>\u030e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r5@\x8f\"ef\x11o\xb8\xac\u06a9\xe2\xc9\u055bvh?\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\rU\x1e\xc1\xa2\x13<\x98\x1d_\u01a8\xc8\x17?\x9e|OG\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r]\x98V\\d|\xa5\xf1w\xa2\xad\xb9\xd3\x02/\xac(\u007f!\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\re\x80\x14\xa1\x99\x06\x1c\xf6\xb3\x943\x14\x03\x03\xc2\x0f\xfdNZ\x8a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\rg\x87\x06\xd07\x18\u007f>\"\xe6\xf6\x9b\x99\xa5\x92\xd1\x1e\xbcY\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\ri\x10\f9\\\xe6\xc5\xea\xad\xf9]\x05\xd8r\x83~\xde\xdd!\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\rt~\u559b\xf7\x9dW8\x1do\xe3\xa2@l\xd0\xd8\xce'\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\r\x80#\x92\x9d\x91r4\xae@Q+\x1a\xab\xb5\xe8\xa4Q'q\x89\b\x05\xe9\x9f\xdc\xc5\xd0\x00\x00\xe0\x94\r\x8a\xab\x8ft\xea\x86,\xdfvh\x05\x00\x9d?>B\xd8\xd0\v\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\r\x8c@\xa7\x9e\x18\x99O\xf9\x9e\xc2Q\xee\x10\u0408\u00d1.\x80\x89\x066d\xfc\u04bb\xc4\x00\x00\u07d4\r\x8e\xd7\xd0\xd1V83\x0e\xd7\xe4\xea\u032b\x8aE\x8dus~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\x92X/\u06e0^\xab\xc3\xe5\x158\xc5m\xb8\x817\x85\xb3(\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\r\x94C\xa7\x94h\xa5\xbb\xf7\xc1\xe5\xb9\x15\xb3d\x87\xf9\x16\x1f\x19\x84m\x10\x1431\x8a\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\r\xbdA|7+\x8b\r\x01\xbc\xd9Dpk\xd3.`\xae(\u0449\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\r\xc1\x00\xb1\a\x01\x1c\u007f\xc0\xa13\x96\x12\xa1l\xce\xc3(R\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\u03dd\x8c\x98\x04E\x9fd|\x14\x13\x8e\xd5\x0f\xadV;AT\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\r\xcf\xe87\xea\x1c\xf2\x8ce\xfc\xce\u00fe\xf1\xf8NY\xd1P\xc0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r\xd4\xe6t\xbb\xad\xb1\xb0\u0702D\x98q=\xce;QV\xda)\x89\t79SM(h\x00\x00\u07d4\r\xfb\u0501pP\xd9\x1d\x9db\\\x02\x05<\xf6\x1a>\xe2\x85r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x0e\x02N\u007f\x02\x9cj\xaf:\x8b\x91\x0f^\b\bs\xb8W\x95\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\tdl\x99\xafC\x8e\x99\xfa'L\xb2\xf9\xc8V\xcbe\xf76\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x0e\f\x9d\x00^\xa0\x16\u0095\xcdy\\\xc9!>\x87\xfe\xbc3\xeb\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\x0e\rf3\xdb\x1e\f\u007f#Jm\xf1c\xa1\x0e\n\xb3\x9c \x0f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x0e\x11\xd7z\x89w\xfa\xc3\r&\x84E\xe51\x14\x9b1T\x1a$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x12=}\xa6\xd1\xe6\xfa\xc2\u072d\xd2p)$\v\xb3\x90R\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\x18\x01\xe7\vbb\x86\x1b\x114\u033c9\x1fV\x8a\xfc\x92\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e \x94\xac\x16T\xa4k\xa1\xc4\u04e4\v\xb8\xc1}\xa7\U000d6209\x13h?\u007f<\x15\xd8\x00\x00\u07d4\x0e!\xaf\x1b\x8d\xbf'\xfc\xf6?7\xe0G\xb8z\x82\\\xbe|'\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x0e.PJ-\x11\"\xb5\xa9\xfe\xee\\\xb1E\x1b\xf4\u00ac\xe8{\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x0e/\x8e(\xa6\x81\xf7|X;\xd0\xec\xde\x16cK\xdd~\x00\u0349\x05'8\xf6Y\xbc\xa2\x00\x00\u07d4\x0e2\x02\x19\x83\x8e\x85\x9b/\x9f\x18\xb7.=@s\xcaP\xb3}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e3\xfc\xbb\xc0\x03Q\v\xe3W\x85\xb5*\x9c]!k\xc0\x05\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x0e6\x96\xcf\x1fB\x17\xb1c\u047c\x12\xa5\xeas\x0f\x1c2\xa1J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e9\x0fD\x05=\xdf\xce\xf0\xd6\b\xb3^M\x9c,\xbe\x98q\xbb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x0e:(\xc1\u07ef\xb0P[\xdc\xe1\x9f\xe0%\xf5\x06\xa6\xd0\x1c\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e=\xd7\xd4\xe4)\xfe90\xa6A@5\xf5+\xdcY\x9dxM\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\x0eGey\x03Rek\xc6Vh,$\xfc^\xf3\xe7j#\u01c9\x02\x86\xd7\xfc\f\xb4\xf5\x00\x00\u07d4\x0eI\x88\x00Dqw\xb8\u022f\xc3\xfd\xfa\u007fi\xf4\x05\x1b\xb6)\x89t\x05\xb6\x9b\x8d\xe5a\x00\x00\u07d4\x0ek\xaa\xa3\u07b9\x89\xf2\x89b\x00vf\x86\x18\xe9\xac3(e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x0el\xd6d\xad\x9c\x1e\xd6K\xf9\x87I\xf4\x06D\xb6&\xe3y,\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\xe0\x94\x0em\xfdU;.\x87=*\xec\x15\xbd_\xbb?\x84r\xd8\u04d4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\x0en\xc3\x137bq\xdf\xf5T#\xabT\"\xcc:\x8b\x06\xb2+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x0en\u0399\x11\x1c\xad\x19a\xc7H\xed=\xf5\x1e\xddi\u04a3\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x0e\x83\xb8PH\x1a\xb4MI\xe0\xa2)\xa2\xe4d\x90,iS\x9b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\x89\xed\xdd?\xa0\xd7\x1d\x8a\xb0\xff\x8d\xa5X\x06\x86\xe3\xd4\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x90\x96\xd3C\xc0`\xdbX\x1a\x12\x01\x12\xb2x`~\xc6\xe5+\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x0e\x9cQ\x18d\xa1w\xf4\x9b\xe7\x82\x02w?`H\x9f\xe0NR\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x0e\xa2\xa2\x101+>\x86~\xe0\xd1\xcch,\xe1\xd6f\xf1\x8e\u054a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0e\xb1\x89\xef,-Wb\xa9c\u05b7\xbd\xf9i\x8e\xa8\u7d0a\x89Hz\x9a0E9D\x00\x00\xe0\x94\x0e\xb5\xb6b\xa1\xc7\x18`\x8f\xd5/\f%\xf97\x880\x17\x85\x19\x8a\x01J7(\x1aa.t\x00\x00\xe0\x94\x0e\xc4f\x96\xff\xac\x1fX\x00_\xa8C\x98$\xf0\x8e\xed\x1d\xf8\x9b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x0e\xc5\n\xa8#\xf4e\xb9FK\v\xc0\u0125w$\xa5U\xf5\u058a\f\x83\xd1Bj\u01f1\xf0\x00\x00\u07d4\x0e\xc50\x8b1(.!\x8f\xc9\xe7Y\xd4\xfe\xc5\xdb7\b\xce\u01096C\xaady\x86\x04\x00\x00\u07d4\x0e\xcc\xf6\x17\x84O\xd6\x1f\xbab\xcb\x0eD[z\u018b\xcc\x1f\xbe\x89\x14\xfeO\xe65e\xc6\x00\x00\u07d4\x0e\u04fb:N\xb5T\xcf\u0297\x94}WU\a\xcd\xfdm!\u0609\x1d\xb3 _\xcc#\u0540\x00\u07d4\x0e\xd7l,;]P\xff\x8f\xb5\v>\xea\xcdh\x15\x90\xbe\x1c-\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\u0680\xf4\xed\aJ\xeaiz\xed\xdf(;c\xdb\xca=\xc4\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\xddKX\x0f\xf1\x0f\xe0lJ\x03\x11b9\xef\x96b+\xae5\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x0e\xe3\x91\xf0^\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0f\x92\x9c\xf8\x95\xdb\x01z\xf7\x9f>\xad\"\x16\xb1\xbdi\xc3}\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa0\x10\xce\fs\x1d;b\x8e6\xb9\x1fW\x13\x00\u477e\xab\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\x0f\xa5\xd8\u0173\xf2\x94\xef\u0515\xabi\xd7h\xf8\x18rP\x85H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa6\u01f0\x97=\v\xae)@T\x0e$}6'\xe3|\xa3G\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0f\xad\x05P|\u070f$\xb2\xbeL\xb7\xfa]\x92}\u06d1\x1b\x88\x89\xa2\xdf\x13\xf4A\xf0\t\x80\x00\u07d4\x0f\xb5\xd2\xc6s\xbf\xb1\xdd\xca\x14\x1b\x98\x94\xfdm?\x05\xdag \x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0f\u0260\xe3AE\xfb\xfd\xd2\xc9\u04a4\x99\xb6\x17\u05e0)i\xb9\x89\t\xc2\x00vQ\xb2P\x00\x00\xe0\x94\x0f\xcf\xc4\x06P\b\xcf\xd3#0_b\x86\xb5zM\xd7\xee\xe2;\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x0f\xdde@#\x95\u07db\u045f\xeeE\a\xefSE\xf7E\x10L\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x0f\xecN\xe0\xd7\xca\x18\x02\x90\xb6\xbd \xf9\x99#B\xf6\x0f\xf6\x8d\x89\x12 \u007f\x0e\xdc\xe9q\x80\x00\u07d4\x0f\ue06c3\x1e\xfd\x8f\x81\x16\x1cW8+\xb4P{\xb9\xeb\xec\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\u07d4\x0f\xfe\xa0mq\x13\xfbj\xec(i\xf4\xa9\u07f0\x90\a\xfa\xce\xf4\x89\f8F\x81\xb1\xe1t\x00\x00\u07d4\x10\tq\x98\xb4\xe7\xee\x91\xff\x82\xcc/;\xd9_\xeds\xc5@\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x10\vM\tw\xfc\xba\xd4\u07bd^d\xa0Iz\xea\xe5\x16\x8f\xab\x89\x11\f\x90s\xb5$Z\x00\x00\xe0\x94\x10\x1a\nd\xf9\xaf\xccD\x8a\x8a\x13\rM\xfc\xbe\xe8\x957\xd8T\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\u07d4\x10,G}i\xaa\u06e9\xa0\xb0\xf6+tY\xe1\u007f\xbb\x1c\x15a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x101\xe0\xec\xb5I\x85\xae!\xaf\x17\x93\x95\r\xc8\x11\x88\x8f\xde|\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x104d\x14\xbe\xc6\xd3\xdc\xc4NP\xe5MT\u00b8\xc3sN>\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x108\x98X\xb8\x00\xe8\xc0\xec2\xf5\x1e\xd6\x1a5YF\xcc@\x9b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x10Y\xcb\xc6>6\xc4>\x88\xf3\x00\b\xac\xa7\xce\x05\x8e\ua816\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\x10n\xd5\xc7\x19\xb5&\x14w\x89\x04%\xaeuQ\xdcY\xbd%\\\x8a\x02\x89jX\xc9[\xe5\x88\x00\x00\u07d4\x10q\x1c=\xda21x\x85\xf0\xa2\xfd\x8a\xe9.\x82\x06\x9b\r\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x10sy\xd4\xc4gFO#[\xc1\x8eU\x93\x8a\xad>h\x8a\u05c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x10v!-Ou\x8c\x8e\xc7\x12\x1c\x1c}t%I&E\x92\x84\x8a\ai[Y\xb5\xc1{L\x00\x00\u07d4\x10x\xd7\xf6\x1b\x0eV\xc7N\xe6c[.\x18\x19\xef\x1e=\x87\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x10z\x03\xcf\bB\xdb\u07b0a\x8f\xb5\x87\xcai\x18\x9e\xc9/\xf5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x10\x80\xc1\xd85\x8a\x15\xbc\x84\xda\xc8%\x89\u0392\xb9\x81\x89t\xc1\xfa\xb8\xad\xb4T\x00\x00\u07d4\x10\xe1\xe37x\x85\xc4-}\xf2\x18R.\xe7vh\x87\xc0^j\x89\x10C\xc4<\xde\x1d9\x80\x00\u07d4\x10\u342d+\xa3=\x82\xb3s\x88\u041cED\u01b0\"]\xe5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x10\xf4\xbf\xf0\u02a5\x02|\nj-\xcf\xc9R\x82M\xe2\x94\t\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\x00\x1b\x89\xed\x87>:\xae\xc1\x15V4\xb4h\x16C\x98c#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x11\x027\u03d1\x17\xe7g\x92/\u0121\xb7\x8dyd\u0682\xdf \x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x11\x11\xe5\xdb\xf4^o\x90mb\x86o\x17\b\x10\x17\x88\xdd\xd5q\x89F{\xe6S>\xc2\xe4\x00\x00\xe0\x94\x11\x17+'\x8d\xddD\xee\xa2\xfd\xf4\xcb\x1d\x16\x96#\x91\xc4S\u064a\xc6/=\x9b\xfdH\x95\xf0\x00\x00\u07d4\x11&4\xb4\xec0\xffxn\x02AY\xf7\x96\xa5y9\xea\x14N\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x110l}WX\x867x\x0f\xc9\xfd\xe8\xe9\x8e\xcb\x00\x8f\x01d\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x116\x12\xbc;\xa0\xeeH\x98\xb4\x9d\xd2\x023\x90_/E\x8fb\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x11A_\xaba\xe0\xdf\u0539\x06v\x14\x1aUz\x86\x9b\xa0\xbd\xe9\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x11L\xbb\xbfo\xb5*\xc4\x14\xbe~\xc6\x1f{\xb7\x14\x95\xce\x1d\xfa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x11L\xfe\xfeP\x17\r\xd9z\xe0\x8f\nDTIx\u0159T\x8d\x89.\u0207\xe7\xa1J\x1c\x00\x00\u07d4\x11a\b\xc1 \x84a.\xed\xa7\xa9=\xdc\xf8\xd2`.'\x9e\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11d\u02aa\x8c\u0157z\xfe\x1f\xad\x8a}`(\xce-W)\x9b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x11gZ%UF\a\xa3\xb6\xc9*\x9e\xe8\xf3ou\xed\xd3\xe36\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x11j\t\xdff\xcb\x15\x0e\x97W\x8e)\u007f\xb0n\x13\x04\f\x89<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11o\xef^`\x16B\xc9\x18\u02c9\x16\x0f\xc2);\xa7\x1d\xa96\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x11xP\x1f\xf9J\xdd\x1cX\x81\xfe\x88a6\xf6\xdf\xdb\xe6\x1a\x94\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x11y\xc6\r\xbd\x06\x8b\x15\v\aM\xa4\xbe#\x03; \u0185X\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\x11}\x9a\xa3\xc4\xd1;\xee\x12\xc7P\x0f\t\xf5\xdd\x1cf\xc4e\x04\x89\v*\xd3\x04\x90\xb2x\x00\x00\xe0\x94\x11}\xb867\u007f\xe1TU\xe0,.\xbd\xa4\v\x1c\xebU\x1b\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x11\x8c\x18\xb2\xdc\xe1p\xe8\xf4Eu;\xa5\xd7Q<\xb7cm-\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\x11\x8f\xbdu;\x97\x929Z\xefzMx\xd2c\xcd\u02ab\xd4\xf7\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94\x11\x92\x83x\xd2}U\xc5 \xce\xed\xf2L\xeb\x1e\x82-\x89\r\xf0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x11\x9a\xa6M[}\x18\x1d\xae\x9d<\xb4I\x95\\\x89\xc1\xf9c\xfa\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\x11\xc05\x8a\xa6G\x9d\xe2\x18f\xfe!\a\x19$\xb6^p\xf8\xb9\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\xe0\x94\x11\xd2$z\"\x1ep\xc2\xd6m\x17\xee\x13\x8d8\xc5_\xfb\x86@\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x11\u05c4JG\x1e\xf8\x9a\x8d\x87uUX<\xee\xbd\x149\xea&\x8a\x02#i\u6e80\u0188\x00\x00\u07d4\x11\xdda\x85\u0668\xd7=\xdf\u06a7\x1e\x9bwtC\x1cM\xfe\u008965\u026d\xc5\u07a0\x00\x00\u07d4\x11\xe7\x99~\u0750E\x03\xd7}\xa6\x03\x8a\xb0\xa4\xc84\xbb\xd5c\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x11\xec\x00\xf8I\xb61\x9c\xf5\x1a\xa8\u074ff\xb3U)\xc0\xbew\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\ufe22\x04Q\x16\x1bdJ\x8c\u03bb\xc1\xd3C\xa3\xbb\xcbR\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\x11\xfe\xfb]\xc1\xa4Y\x8a\xa7\x12d\fQwu\u07e1\xd9\x1f\x8c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x12\x0f\x9d\xe6\xe0\xaf~\xc0*\a\xc6\t\u0284G\xf1W\xe64L\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x12\x10\xf8\v\u06c2l\x17Tb\xab\a\x16\xe6\x9eF\xc2J\xd0v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12\x13N\u007fk\x01{\xf4\x8e\x85Z9\x9c\xa5\x8e.\x89/\xa5\u020965\u026d\xc5\u07a0\x00\x00\u07d4\x12\x170t\x98\x01S\xae\xaaK\r\xcb\xc7\x13.\xad\xce\xc2\x1bd\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\x12\x1f\x85[p\x14\x9a\xc84s\xb9po\xb4MG\x82\x8b\x98;\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x12'\xe1\nM\xbf\x9c\xac\xa3\x1b\x17\x80#\x9fUv\x15\xfc5\xc1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x12-\xcf\xd8\x1a\u0779}\x1a\x0eI%\u0135I\x80n\x9f;\xeb\x89R 5\xccn\x01!\x00\x00\u07d4\x12/V\x12%I\xd1h\xa5\xc5\xe2g\xf5&b\xe5\xc5\xcc\xe5\u0209\n\ad\a\xd3\xf7D\x00\x00\xe0\x94\x121o\xc7\xf1x\xea\xc2.\xb2\xb2Z\xed\xea\xdf=u\xd0\x01w\x8a\x04<3\xbe\x05\xf6\xbf\xb9\x80\x00\xe0\x94\x127Y\xf33\xe1>0i\xe2\x03KO\x059\x89\x18\x11\x9d6\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x12\\\xc5\xe4\xd5k+\xcc.\xe1\xc7\t\xfb\x9eh\xfb\x17t@\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x12c#\x88\xb2v^\xe4E+P\x16\x1d\x1f\xff\xd9\x1a\xb8\x1fJ\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\x12h\x97\xa3\x11\xa1J\xd4;x\xe0\x92\x01\x00\xc4Bk\xfdk\u07494\xc7&\x89?-\x94\x80\x00\u07d4\x12m\x91\xf7\xad\x86\u07bb\x05W\xc6\x12\xca'n\xb7\xf9m\x00\xa1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12}?\xc5\x00;\xf6<\r\x83\xe99W\x83e\x15\xfd'\x90E\x89\x06\x10\xc9\".nu\x00\x00\xe0\x94\x12}\xb1\xca\xdf\x1bw\x1c\xbdtu\xe1\xb2ri\x0fU\x8c\x85e\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x12\x84\xf0\xce\xe9\xd2\xff)\x89\xb6Ut\xd0o\xfd\x9a\xb0\xf7\xb8\x05\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x12\x8b\x90\x8f\xe7C\xa44 =\xe2\x94\xc4A\xc7\xe2\n\x86\xeag\x89&\xab\x14\xe0\xc0\xe1<\x00\x00\xe0\x94\x12\x93\u01cc}jD;\x9dt\xb0\xba^\xe7\xbbG\xfdA\x85\x88\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x12\x96\xac\xde\xd1\xe0c\xaf9\xfe\x8b\xa0\xb4\xb6=\xf7\x89\xf7\x05\x17\x89\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\x12\xaa}\x86\xdd\xfb\xad0\x16\x92\xfe\xac\x8a\b\xf8A\xcb!\\7\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94\x12\xaf\xbc\xba\x14'\xa6\xa3\x9e{\xa4\x84\x9fz\xb1\xc45\x8a\xc3\x1b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x12\xb5\xe2\x89E\xbb)i\xf9\xc6Lc\xcc\x05\xb6\xf1\xf8\xd6\xf4\u054a\x01\xa2\x9e\x86\x91;t\x05\x00\x00\u0794\x12\u03cb\x0eFR\x13!\x1a[S\u07f0\xdd'\x1a(,\x12\u0248\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x12\xd2\a\x90\xb7\xd3\xdb\u060c\x81\xa2y\xb8\x12\x03\x9e\x8a`;\u0409V\xf9\x85\u04c6D\xb8\x00\x00\xe0\x94\x12\xd6\re\xb7\xd9\xfcH\x84\v\xe5\xf8\x91\xc7E\xcev\xeeP\x1e\x8a\x04\x85\xe58\x8d\fv\x84\x00\x00\u0794\x12\xd9\x1a\x92\xd7O\xc8a\xa7)dm\xb1\x92\xa1%\xb7\x9fSt\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\x12\u992d*\xd5t\x84\xddp\x05e\xbd\xdbFB;\u067d1\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x12\xf3,\n\x1f-\xaa\xb6v\xfei\xab\xd9\xe0\x185-L\xcdE\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x12\xf4`\xaedl\xd2x\x0f\xd3\\P\xa6\xafK\x9a\xcc\xfa\x85\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x12\xff\xc1\x12\x86\x05\xcb\f\x13p\x9ar\x90Po&\x90\x97q\x93\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x13\x03$F\xe7\xd6\x10\xaa\x00\xec\x8cV\u0275t\xd3l\xa1\xc0\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\x1cy,\x19}\x18\xbd\x04]p$\x93|\x1f\x84\xb6\x0fD8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x1d\xf8\xd30\xeb|\xc7\x14}\nUWo\x05\u078d&\xa8\xb7\x89\n1\x06+\xee\xedp\x00\x00\u07d4\x13\x1f\xae\xd1%a\xbbz\xee\x04\xe5\x18Z\xf8\x02\xb1\xc3C\x8d\x9b\x89\v\xdf\x0e\u0733\x90\xc9\xc8V\b\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13!\xcc\xf2\x979\xb9t\xe5\xa5\x16\xf1\x8f:\x846q\xe3\x96B\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13'\xd7Y\xd5n\n\xb8z\xf3~\xcfc\xfe\x01\xf3\x10\xbe\x10\n\x89#\xbc<\xdbh\xa1\x80\x00\x00\u07d4\x13)\xdd\x19\xcdK\xaa\x9f\xc6C\x10\xef\xec\xea\xb2!\x17%\x1f\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x137\x1f\x92\xa5n\xa88\x1eC\x05\x9a\x95\x12\x8b\xdcMC\u0166\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x13O\x15\xe1\xe3\x9cSCY0\xaa\xed\xf3\xe0\xfeV\xfd\xe8C\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x13Ac\xbe\x9f\xbb\xe1\xc5in\xe2U\xe9\v\x13%C\x95\xc3\x18\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x13\\\xec\xd9U\xe5y\x83pv\x920\x15\x93\x03\u0671\x83\x9ff\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x13]\x17\x19\xbf\x03\xe3\xf8f1$y\xfe3\x81\x18\xcd8~p\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x13^\xb8\xc0\xe9\xe1\x01\xde\xed\xec\x11\xf2\xec\xdbf\xae\x1a\xae\x88g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x13`\xe8}\xf2Li\xeemQ\xc7nsv\u007f\xfe\x19\xa2\x13\x1c\x89\x04\xfc\xc1\xa8\x90'\xf0\x00\x00\u07d4\x13l\x83K\xf1\x112m s\x95)[.X>\xa7\xf35r\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x13mKf+\xbd\x10\x80\xcf\xe4D[\x0f\xa2\x13\x86D5\xb7\xf1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13oI\a\u02b4\x1e'\bK\x98E\x06\x9f\xf2\xfd\f\x9a\xdey\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13t\xfa\xcd{?\x8dhd\x9d`\xd4U\x0e\xe6\x9f\xf0HA3\x89\x0e\x9e\xd6\xe1\x11r\xda\x00\x00\u07d4\x13|\xf3A\xe8Ql\x81X\x14\xeb\xcds\xe6V\x9a\xf1L\xf7\xbc\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x13\x84\x8bF\xeau\xbe\xb7\xea\xa8_Y\xd8f\xd7\u007f\xd2L\xf2\x1a\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x13\x9d51\u0252*\xd5bi\xf60\x9a\xa7\x89\xfb$\x85\xf9\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x9eG\x97d\xb4\x99\xd6f \x8cJ\x8a\x04z\x97\x041c\u0749 w!*\xffm\xf0\x00\x00\u07d4\x13\xa5\xee\xcb80]\xf9Iq\xef-\x9e\x17\x9a\xe6\u03ba\xb37\x89\x11\u3ac3\x95\xc6\xe8\x00\x00\u07d4\x13\xac\xad\xa8\x98\n\xff\xc7PI!\xbe\x84\xebID\xc8\xfb\xb2\xbd\x89V\u04aa:\\\t\xa0\x00\x00\u07d4\x13\xb9\xb1\a\x15qL\t\xcf\xd6\x10\u03dc\x98F\x05\x1c\xb1\xd5\x13\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x13\xce3-\xffe\xa6\xab\x938\x97X\x8a\xa2>\x00\t\x80\xfa\x82\x89\x0e\x02\x056\xf0(\xf0\x00\x00\u07d4\x13\xd6z~%\xf2\xb1,\u06c5XP\t\xf8\xac\u011b\x96s\x01\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x13\xde\xe0>7\x99\x95-\a8\x84=K\xe8\xfc\n\x80?\xb2\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe0/\xb4H\xd6\xc8J\xe1}\xb3\x10\xad(m\x05a`\u0695\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe3!r\x8c\x9cWb\x80X\xe9?\xc8f\xa02\xdd\v\u0690\x89&\xbc\xca#\xfe.\xa2\x00\x00\u07d4\x13\xec\x81\"\x84\x02n@\x9b\xc0f\xdf\xeb\xf9\u0564\xa2\xbf\x80\x1e\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\x14\x01)\xea\xa7f\xb5\xa2\x9f[:\xf2WND\t\xf8\xf6\xd3\xf1\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u07d4\x14\x05\x18\xa3\x19K\xad\x13P\xb8\x94\x9ee\x05e\u07bem\xb3\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\x06\x85M\x14\x9e\b\x1a\xc0\x9c\xb4\xcaV\r\xa4c\xf3\x120Y\x89Hz\x9a0E9D\x00\x00\u07d4\x14\f\xa2\x8f\xf3;\x9ff\xd7\xf1\xfc\x00x\xf8\xc1\xee\xf6\x9a\x1b\xc0\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x14\x0f\xbaX\xdb\xc0H\x03\xd8L!0\xf0\x19x\xf9\xe0\xc71)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x14\x1a^9\xee/h\n`\x0f\xbfo\xa2\x97\u0790\xf3\"\\\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x14%N\xa1&\xb5-\x01B\xda\n~\x18\x8c\xe2U\xd8\xc4qx\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x14+\x87\xc5\x04?\xfbZ\x91\xdf\x18\xc2\xe1\t\xce\xd6\xfeJq\u06c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\x87\xf5\xa5$\u0288Q^\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\x14\xa75 f6D\x04\xdbP\xf0\xd0\u05cduJ\"\x19\x8e\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x14\xab\x16K;RL\x82\u05ab\xfb\xc0\u0783\x11&\xae\x8d\x13u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\xb1`>\xc6+ \x02 3\xee\xc4\xd6\xd6eZ\xc2J\x01Z\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x14\xc6;\xa2\u0731\xddM\xf3=\u06b1\x1cO\x00\a\xfa\x96\xa6-\x8a\x03HA\xb6\x05z\xfa\xb0\x00\x00\xe0\x94\x14\xcd\u077c\x8b\t\xe6gZ\x9e\x9e\x05\t\x1c\xb9\"8\u00de\x1e\x8a\x01\x14x\xb7\xc3\n\xbc0\x00\x00\u07d4\x14\xd0\n\xad9\xa0\xa7\u045c\xa0SP\xf7\xb07'\xf0\x8d\xd8.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x14\xee\xc0\x9b\xf0>5+\xd6\xff\x1b\x1e\x87k\xe6d\xce\xff\xd0\u03c9\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\x14\xf2!\x15\x95\x18x;\u0127\x06go\xc4\xf3\xc5\xee@X)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\xfc\xd19\x1e}s/Avl\xda\u0344\xfa\x1d\xeb\x9f\xfd\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x0e=\xbc\xbc\xfc\x84\xcc\xf8\x9bsBwc\xa5e\xc2>`\u0409\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\x15\x18b{\x885\x1f\xed\xe7\x96\xd3\xf3\b3d\xfb\u0508{\f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u0794\x15\"J\xd1\xc0\xfa\xceF\xf9\xf5V\xe4wJ0%\xad\x06\xbdR\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x15/+\xd2)\xdd\xf3\xcb\x0f\xda\xf4U\xc1\x83 \x9c\x0e\x1e9\xa2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15/N\x86\x0e\xf3\xee\x80jP'w\xa1\xb8\xdb\xc9\x1a\x90vh\x89 \x86\xac5\x10R`\x00\x00\u07d4\x15<\b\xaa\x8b\x96\xa6\x11\xefc\xc0%>*C4\x82\x9eW\x9d\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x15<\xf2\x84,\xb9\u0787l'o\xa6Gg\u0468\xec\xf5s\xbb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15>\xf5\x8a\x1e.z>\xb6\xb4Y\xa8\n\xb2\xa5G\xc9A\x82\xa2\x8a\x14T+\xa1*3|\x00\x00\x00\u07d4\x15DY\xfa/!1\x8e44D\x97\x89\xd8&\xcd\xc1W\f\xe5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15G\xb9\xbfz\xd6bt\xf3A8'#\x1b\xa4\x05\ue308\xc1\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\x15H\xb7p\xa5\x11\x8e\u0787\u06e2\xf6\x903\u007fam\u60eb\x89\x1c\x99V\x85\u0fc7\x00\x00\u07d4\x15R\x83P\xe0\xd9g\n.\xa2\u007f{J3\xb9\xc0\xf9b\x1d!\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x15[7y\xbbmV4./\u0681{[-\x81\xc7\xf4\x13'\x89\x02\xb8\xaa:\al\x9c\x00\x00\u07d4\x15e\xaf\x83~\xf3\xb0\xbdN+#V\x8dP#\xcd4\xb1d\x98\x89\x15Q\xe9rJ\u013a\x00\x00\u07d4\x15f\x91\x80\xde\u2558\x86\x9b\b\xa7!\xc7\xd2LL\x0e\xe6?\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x15r\xcd\xfa\xb7*\x01\u0396\x8ex\xf5\xb5D\x8d\xa2\x98S\xfb\u074a\x01\x12blI\x06\x0f\xa6\x00\x00\xe0\x94\x15uY\xad\xc5Wd\xccm\xf7\x93#\t%4\xe3\xd6dZf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x15x\xbd\xbc7\x1bM$8E3\x05V\xff\xf2\xd5\xefM\xffg\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x15~\xb3\xd3\x11;\u04f5\x97qM:\x95N\xdd\x01\x89\x82\xa5\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x84\xa2\xc0f\xb7\xa4U\xdb\u05ae(\a\xa73N\x83\xc3_\xa5\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\u07d4\x15\x87F\x86\xb6s=\x10\xd7\x03\xc9\xf9\xbe\xc6\xc5.\xb8b\x8dg\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x8a\ra\x92S\xbfD2\xb5\xcd\x02\u01f8b\xf7\u00b7V6\x89\a[\xac|[\x12\x18\x80\x00\u07d4\x15\x98\x12y\x82\xf2\xf8\xad;k\x8f\xc3\xcf'\xbfax\x01\xba+\x89\t`\xdbwh\x1e\x94\x00\x00\xe0\x94\x15\x9a\xdc\xe2z\xa1\vG#d)\xa3JZ\xc4,\xad[d\x16\x8a\x06\xbf\x90\xa9n\xdb\xfaq\x80\x00\u07d4\x15\xa0\xae\xc3\u007f\xf9\xff=T\t\xf2\xa4\xf0\xc1!*\xac\xcb\x02\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x15\xaaS\r\xc3iX\xb4\xed\xb3\x8e\xeem\xd9\xe3\xc7}L\x91E\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\xac\xb6\x15h\xecJ\xf7\xea(\x198a\x81\xb1\x16\xa6\xc5\xeep\x8a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\x15\xb9o0\xc2;\x86d\xe7I\x06Q\x06k\x00\xc49\x1f\xbf\x84\x89\x16B\xe9\xdfHv)\x00\x00\u07d4\x15\xc7\xed\xb8\x11\x8e\xe2{4\"\x85\xebY&\xb4z\x85[\u01e5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x15\u0654hPz\xa0A?\xb6\r\xca*\xdc\u007fV\x9c\xb3kT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\u06f4\x8c\x980\x97d\xf9\x9c\xed6\x92\xdc\xca5\xee0k\xac\x8a\x1f\u00c4+\xd1\xf0q\xc0\x00\x00\xe0\x94\x15\u072f\xcc+\xac\xe7\xb5[T\xc0\x1a\x1cQF&\xbfa\xeb\u060a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x15\u3d44\x05kb\xc9s\xcf^\xb0\x96\xf1s>T\xc1\\\x91\x892\xc7Z\x02#\xdd\xf3\x00\x00\u07d4\x15\xeb\xd1\xc7\xca\u04af\xf1\x92u\xc6W\xc4\xd8\b\xd0\x10\xef\xa0\xf5\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x15\xee\x0f\xc6>\xbf\x1b\x1f\u011d{\xb3\x8f\x88c\x82:.\x17\u0489g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x15\xf1\xb3R\x11\rh\x90\x1d\x8fg\xaa\xc4jl\xfa\xfe\x03\x14w\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x15\xf2\xb7\xb1d2\xeeP\xa5\xf5[A#/c4\xedX\xbd\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x16\x01\x9aM\xaf\xabC\xf4\u067fAc\xfa\xe0\x84}\x84\x8a\xfc\xa2\x89\x01[\xc7\x019\xf7J\x00\x00\u07d4\x16\x02&\xef\xe7\xb5:\x8a\xf4b\xd1\x17\xa0\x10\x80\x89\xbd\xec\xc2\u0449\n\xdf0\xbap\u0217\x00\x00\u07d4\x16\f\xebo\x98\x0e\x041_S\xc4\xfc\x98\x8b+\xf6\x9e(M}\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94\x16\x1c\xafZ\x97*\u0383y\xa6\u0420J\xe6\xe1c\xfe!\xdf+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x16\x1d&\xefgY\xba[\x9f \xfd\xcdf\xf1a2\xc3RA^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16!\x10\xf2\x9e\xac_}\x02\xb5C\xd8\xdc\u057bY\xa5\xe3;s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16+\xa5\x03'b\x14\xb5\t\xf9u\x86\xbd\x84!\x10\xd1\x03\xd5\x17\x8a\x01\xe7\xff\u0609\\\"h\x00\x00\u07d4\x16-v\xc2\xe6QJ:\xfbo\xe3\xd3\u02d3\xa3\\Z\xe7\x83\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16;\xadJ\x12+E}d\xe8\x15\nA>\xaeM\a\x02>k\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\x16<\u023e\"vF\xcb\tq\x91Y\xf2\x8e\u041c]\xc0\xdc\xe0\x89Hz\x9a0E9D\x00\x00\u07d4\x16=\xcas\xd7\xd6\xea?>`b2*\x874\x18\f\vx\uf25ft \x03\xcb}\xfc\x00\x00\u07d4\x16Mz\xac>\xec\xba\uc86dQ\x91\xb7S\xf1s\xfe\x12\xec3\x89(VR\xb8\xa4hi\x00\x00\u07d4\x16Rl\x9e\u07d4>\xfaOm\x0f\v\xae\x81\xe1\x8b1\xc5@y\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x16S\x05\xb7\x872.%\xdcj\xd0\xce\xfelo3Fx\xd5i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16e\xab\x179\xd7\x11\x19\xeea2\xab\xbd\x92j'\x9f\xe6yH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x16k\xf6\u06b2-\x84\x1bHl8\xe7\xbaj\xb3:\x14\x87\ud30a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x16v\x99\xf4\x8ax\xc6\x15Q%\x15s\x99X\x993\x12WO\a\x89\x02\x1d;\xd5^\x80<\x00\x00\u07d4\x16x\xc5\xf2\xa5\"92%\x19ca\x89OS\xccu/\xe2\xf3\x89h\xf3e\xae\xa1\xe4@\x00\x00\u07d4\x16|\xe7\xdee\xe8G\bYZRT\x97\xa3\xeb^ZfPs\x89\x1f1Gsfo\xc4\x00\x00\u07d4\x16~>:\xe2\x003HE\x93\x92\xf7\xdf\xceD\xaf|!\xadY\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x16\x80\xce\xc5\x02\x1e\xe90P\xf8\xae\x12rQ\x83\x9et\xc1\xf1\xfd\x8a\x02\xc6\x14a\xe5\xd7C\u0580\x00\u07d4\x16\x81j\xac\x0e\xde\r-<\xd4B\xday\xe0c\x88\x0f\x0f\x1dg\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16\x8bP\x19\xb8\x18i\x16D\x83_\xe6\x9b\xf2)\xe1q\x12\xd5,\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\u07d4\x16\x8b\xde\xc8\x18\xea\xfcm)\x92\xe5\xefT\xaa\x0e\x16\x01\xe3\xc5a\x8967Pz0\xab\xeb\x00\x00\u07d4\x16\x8d0\xe5?\xa6\x81\t+R\xe9\xba\xe1Z\r\xcbA\xa8\u027b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x16\x9b\xbe\xfcA\xcf\xd7\xd7\u02f8\xdf\xc60 \xe9\xfb\x06\u0515F\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xa5\x8e\x98]\xcc\xd7\a\xa5\x94\u0453\xe7\u0327\x8b]\x02xI\x89I\xb9\u029aiC@\x00\x00\u07d4\x16\xa9\xe9\xb7:\u92c6M\x17(y\x8b\x87f\xdb\xc6\xea\x8d\x12\x893\xe7\xb4K\r\xb5\x04\x00\x00\u07d4\x16\xaaR\xcb\vUG#\xe7\x06\x0f!\xf3'\xb0\xa6\x83\x15\xfe\xa3\x89\r\x8drkqw\xa8\x00\x00\u07d4\x16\xab\xb8\xb0!\xa7\x10\xbd\u01ce\xa54\x94\xb2\x06\x14\xffN\xaf\xe8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x16\xaf\xa7\x87\xfc\x9f\x94\xbd\xffiv\xb1\xa4/C\n\x8b\xf6\xfb\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xba\xe5\xd2N\xff\x91w\x8c\u064bM:\x1c\xc3\x16/D\xaaw\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\x16\xbc@!Z\xbb\u066e](\v\x95\xb8\x01\vE\x14\xff\x12\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x16\xbeu\u9299Z9R\"\xd0\v\u05df\xf4\xb6\xe68\u144a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\x16\xc1\xbf[}\xc9\xc8<\x17\x9e\xfa\xcb\xcf.\xb1t\xe3V\x1c\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x16\u01f3\x1e\x8c7b\x82\xac\"qr\x8c1\xc9^5\xd9R\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xf3\x13\u03ca\xd0\x00\x91J\n\x17m\u01a44+y\xec%8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xff\xac\x84\x03)@\xf0\x12\x1a\tf\x8b\x85\x8a~y\xff\xa3\xbb\x89\xd2J\xdan\x10\x87\x11\x00\x00\xe0\x94\x17\x03\xb4\xb2\x92\xb8\xa9\xde\xdd\xed\xe8\x1b\xb2]\x89\x17\x9fdF\xb6\x8a\x04+e\xa4U\xe8\xb1h\x00\x00\u07d4\x17\x04\x93\x11\x10\x1d\x81~\xfb\x1de\x91\x0ff6b\xa6\x99\u024c\x89lh\xcc\u041b\x02,\x00\x00\u07d4\x17\x04\xce\xfc\xfb\x131\xeczx8\x8b)9>\x85\xc1\xafy\x16\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\n\x88\xa8\x99\u007f\x92\xd287\x0f\x1a\xff\xde\xe64pP\xb0\x13\x89\xa2\xacw5\x14\x880\x00\x00\u07d4\x17\x10\x8d\xab,P\xf9\x9d\xe1\x10\u1cf3\xb4\u0342\xf5\xdf(\xe7\x895 ;g\xbc\xca\xd0\x00\x00\xe0\x94\x17\x12[Y\xacQ\xce\xe0)\xe4\xbdx\xd7\xf5\x94}\x1e\xa4\x9b\xb2\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4\x17\x1a\u0660K\xed\u0238a\xe8\xedK\xdd\xf5qx\x13\xb1\xbbH\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\x1c\xa0*\x8bmb\xbfL\xa4~\x90i\x14\a\x98a\x97,\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\"\xc4\xcb\xe7\n\x94\xb6U\x9dBP\x84\xca\xee\xd4\xd6\xe6n!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17X\vvotSR\\\xa4\u01a8\x8b\x01\xb5\x05p\xea\b\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x17X\x9al\x00jT\xca\xd7\x01\x03\x12:\xae\n\x82\x13_\u07b4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x17Z\x18::#_\xfb\xb0;\xa85gRg\"\x94\x17\xa0\x91\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x17_\xee\xea*\xa4\xe0\xef\xda\x12\xe1X\x8d/H2\x90\xed\xe8\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x17e6\x1c.\xc2\xf86\x16\u0383c\xaa\xe2\x10%\xf2Vo@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17gR\\_Z\"\xed\x80\xe9\xd4\xd7q\x0f\x03b\u049e\xfa3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17v%`\xe8*\x93\xb3\xf5\"\xe0\xe5$\xad\xb8a,:tp\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x17}\xaex\xbc\x01\x13\xd8\u04dcD\x02\xf2\xa6A\xae*\x10Z\xb8\x89b\x92BV \xb4H\x00\x00\xe0\x94\x17\x84\x94\x8b\xf9\x98H\u021eDV8PM\u0598'\x1bY$\x8a\x01GLA\r\x87\xba\xee\x00\x00\u07d4\x17\x88\u069bW\xfd\x05\xed\xc4\xff\x99\xe7\xfe\xf3\x01Q\x9c\x8a\n\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\x8e\xafk\x85T\xc4]\xfd\xe1kx\xce\f\x15\u007f.\xe3\x13Q\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x17\x96\x1dc;\xcf \xa7\xb0)\xa7\xd9K}\xf4\xda.\xc5B\u007f\x89\fo\xf0p\U000532c0\x00\u07d4\x17\x96\xbc\xc9{\x8a\xbcq\u007fKJ|k\x106\xea!\x82c\x9f\x89\x13A\xf9\x1c\xd8\xe3Q\x00\x00\u07d4\x17\x99=1*\xa1\x10iW\x86\x8fjU\xa5\xe8\xf1/w\xc8C\x89\x18e\xe8\x14\xf4\x14.\x80\x00\u07d4\x17\x9a\x82^\x0f\x1fn\x98S\tf\x84e\xcf\xfe\xd46\xf6\xae\xa9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xb2\xd6\xcfe\xc6\xf4\xa3G\xdd\xc6W&U5M\x8aA+)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xb8\a\xaf\xa3\xdd\xd6G\xe7#T.{R\xfe\xe3\x95'\xf3\x06\x89\x15\xaf@\xff\xa7\xfc\x01\x00\x00\u07d4\x17\xc0G\x86W\xe1\xd3\xd1z\xaa3\x1d\xd4)\xce\u03d1\xf8\xae]\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\x17\xc0\xfe\xf6\x98l\xfb.@A\xf9\x97\x9d\x99@\xb6\x9d\xff=\xe2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17\u0511\x8d\xfa\xc1]w\xc4\u007f\x9e\xd4\x00\xa8P\x19\rd\xf1Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xd5!\xa8\xd9w\x90#\xf7\x16M#<;d \xff\xd2#\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xd91\xd4\xc5b\x94\u073ew\xc8e[\xe4i_\x00mJ<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xdfIQ\x8ds\xb1)\xf0\xda6\xb1\u0274\f\xb6d \xfd\u01ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x17\xe4\xa0\xe5+\xac>\xe4N\xfe\tT\xe7S\u0538]dN\x05\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xe5\x84\xe8\x10\xe5gp,a\xd5]CK4\u0375\xee0\xf6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17\xe8.px\xdcO\xd9\xe8y\xfb\x8aPf\u007fS\xa5\xc5E\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\xe8o;[0\xc0\xbaY\xf2\xb2\xe8XB[\xa8\x9f\n\x10\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xee\x9fT\xd4\xdd\xc8Mg\x0e\xff\x11\xe5Je\x9f\xd7/DU\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94\x17\xefJ\xcc\x1b\xf1G\xe3&t\x9d\x10\xe6w\xdc\xff\xd7o\x9e\x06\x8a\bwQ\xf4\xe0\xe1\xb50\x00\x00\u07d4\x17\xf1F2\xa7\xe2\x82\v\xe6\xe8\xf6\u07c25X(=\xad\xab-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xf5#\xf1\x17\xbc\x9f\xe9x\xaaH\x1e\xb4\xf5V\x17\x117\x1b\u0209li\xf7>)\x13N\x00\x00\u07d4\x17\xfd\x9bU\x1a\x98\xcba\xc2\xe0\u007f\xbfA\xd3\xe8\u02650\u02e5\x89\x01v\x8c0\x81\x93\x04\x80\x00\u07d4\x18\x04x\xa6U\u05cd\x0f;\fO +aH[\xc4\x00/\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\x13l\x9d\xf1g\xaa\x17\xb6\xf1\x8e\"\xa7\x02\u020fK\u0082E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x18\x15'\x9d\xff\x99R\xda;\xe8\xf7rI\xdb\xe2\"C7{\xe7\x8a\x01\x01|\xb7n{&d\x00\x00\u07d4\x18\x1f\xbb\xa8R\xa7\xf5\x01x\xb1\xc7\xf0>\xd9\xe5\x8dT\x16))\x89$\x1a\x9bOaz(\x00\x00\xe0\x94\x18'\x03\x9f\tW\x02\x94\b\x8f\xdd\xf0G\x16\\3\u65a4\x92\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x18-\xb8R\x93\xf6\x06\u8248\xc3pL\xb3\xf0\xc0\xbb\xbf\xcaZ\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18H\x00<%\xbf\u052a\x90\xe7\xfc\xb5\u05f1k\xcd\f\xff\xc0\u060965\u026d\xc5\u07a0\x00\x00\xe0\x94\x18JO\v\xebq\xff\xd5X\xa6\xb6\xe8\xf2(\xb7\x87\x96\xc4\xcf>\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94\x18M\x86\xf3Fj\xe6h;\x19r\x99\x82\xe7\xa7\u1903G\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x18Q\xa0c\xcc\xdb0T\x90w\xf1\xd19\xe7-\xe7\x97\x11\x97\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18UF\xe8v\x8dPhs\x81\x8a\xc9u\x1c\x1f\x12\x11j;\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x18X\xcf\x11\xae\xa7\x9fS\x98\xad+\xb2\"g\xb5\xa3\xc9R\xeat\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\xe0\x94\x18Z\u007f\u012c\xe3h\xd23\xe6 \xb2\xa4Y5f\x12\x92\xbd\xf2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x18d\xa3\u01f4\x81UD\x8cT\u020cp\x8f\x16g\tsm1\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18j\xfd\xc0\x85\xf2\xa3\xdc\xe4a^\xdf\xfb\xad\xf7\x1a\x11x\x0fP\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x18k\x95\xf8\xe5\xef\xfd\xdc\xc9O\x1a1[\xf0)];\x1e\xa5\x88\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x18}\x9f\f\a\xf8\xebt\xfa\xaa\xd1^\xbc{\x80Dt\x17\xf7\x82\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x18\x95\xa0\xebJCrr/\xcb\u016f\xe6\x93o(\x9c\x88\xa4\x19\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x18\x99\xf6\x9fe;\x05\xa5\xa6\xe8\x1fH\a\x11\u041b\xbf\x97X\x8c\x89i\xfb\x13=\xf7P\xac\x00\x00\u07d4\x18\xa6\xd2\xfcR\xbes\b@#\xc9\x18\x02\xf0[\xc2JK\xe0\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\xb0@|\xda\xd4\xceR`\x06#\xbd^\x1fj\x81\xaba\xf0&\x89\x11Q\xcc\xf0\xc6T\u0180\x00\u07d4\x18\xb8\xbc\xf9\x83!\xdaa\xfbN>\xac\xc1\xecT\x17'-\xc2~\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\x18\xc6r:gS)\x9c\xb9\x14G}\x04\xa3\xbd!\x8d\xf8\xc7u\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x18\xe1\x13\xd8\x17|i\x1aa\xbexXR\xfa[\xb4z\uef6f\x89Hz\x9a0E9D\x00\x00\xe0\x94\x18\xe4\xceGH;S\x04\n\u06eb5\x17,\x01\xefdPn\f\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x18\xe52C\x98\x1a\xab\xc8v}\xa1\fsD\x9f\x13\x91V\x0e\xaa\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x18\xfa\x86%\xc9\u0704>\x00\x15\x9e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\x193\xe34\xc4\x0f:\u02ed\f\v\x85\x11X i$\xbe\xca:\x8a\x01\x99^\xaf\x01\xb8\x96\x18\x80\x00\xe0\x94\x197\xc5\xc5\x15\x05uS\u033dF\u0546dU\xcef)\x02\x84\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u07d4\x19:\xc6Q\x83e\x18\x00\xe25\x80\xf8\xf0\xea\u04fbY~\xb8\xa4\x89\x02\xb6*\xbc\xfb\x91\n\x00\x00\u07d4\x19=7\xed4}\x1c/N55\r\x9aDK\xc5|\xa4\xdbC\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x19@\u0713d\xa8R\x16_GAN'\xf5\x00$E\xa4\xf1C\x8a\x02L-\xffj<|H\x00\x00\u07d4\x19E\xfe7\u007f\xe6\u0537\x1e>y\x1fo\x17\xdb$<\x9b\x8b\x0f\x89vy\u7fb9\x886\x00\x00\u07d4\x19Jk\xb3\x02\xb8\xab\xa7\xa5\xb5y\u07d3\xe0\xdf\x15t\x96v%\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x19L\ubd12\x98\x82\xbf;K\xf9\x86L+\x1b\x0fb\u0083\xf9\x89\x1e\xf8aS\x1ft\xaa\x00\x00\u07d4\x19O\xf4J\xef\xc1{\xd2\x0e\xfdz LG\xd1b\f\x86\xdb]\x89\xa2\x99\th\u007fj\xa4\x00\x00\xe0\x94\x19O\xfex\xbb\xf5\xd2\r\u044a\x1f\x01\xdaU.\x00\xb7\xb1\x1d\xb1\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x19S1>*\xd7F#\x9c\xb2'\x0fH\xaf4\u063b\x9cDe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19W\x1a+\x8f\x81\u01bc\xf6j\xb3\xa1\x00\x83)V\x17\x15\x00\x03\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\x19h}\xaa9\xc3h\x13\x9bn{\xe6\r\xc1u:\x9f\f\xbe\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x19l\x02!\nE\n\xb0\xb3cpe_qz\xa8{\xd1\xc0\x04\x89\x0e\x10\xac\xe1W\xdb\xc0\x00\x00\u07d4\x19n\x85\xdf~s+J\x8f\x0e\xd06#\xf4\u06dd\xb0\xb8\xfa1\x89\x01%\xb9/\\\xef$\x80\x00\u07d4\x19s+\xf9s\x05]\xbd\x91\xa4S:\u06a2\x14\x9a\x91\u04c3\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19vr\xfd9\xd6\xf2F\xcef\xa7\x90\xd1:\xa9\"\xd7\x0e\xa1\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x19y\x8c\xbd\xa7\x15\ua69b\x9dj\xab\x94,U\x12\x1e\x98\xbf\x91\x89A\rXj \xa4\xc0\x00\x00\u07d4\x19\x8b\xfc\xf1\xb0z\xe3\b\xfa,\x02\x06\x9a\xc9\xda\xfeq5\xfbG\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x19\x8e\xf1\xec2Z\x96\xcc5Lrf\xa08\xbe\x8b\\U\x8fg\x8a\x80\xd1\xe47>\u007f!\xda\x00\x00\xe0\x94\x19\x91\x8a\xa0\x9e}IN\x98\xff\xa5\xdbP5\b\x92\xf7\x15j\u018a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x19\xb3k\f\x87\xeafN\xd8\x03\x18\xdcw\xb6\x88\xdd\xe8}\x95\xa5\x89i\x9fI\x98\x020=\x00\x00\u07d4\x19\u07d4E\xa8\x1c\x1b=\x80J\xea\xebon NB6f?\x89\x02\x06\xd9NjI\x87\x80\x00\u07d4\x19\xe5\u07a37\n,tj\xae4\xa3|S\x1fA\xda&N\x83\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x19\xe7\xf3\xeb{\xf6\u007f5\x99 \x9e\xbe\b\xb6*\xd32\u007f\x8c\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xe9Nb\x00P\xaa\xd7f\xb9\xe1\xba\xd91#\x83\x12\u053fI\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4\x19\xec\xf2\xab\xf4\f\x9e\x85{%/\xe1\xdb\xfd=L]\x8f\x81n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xf5\xca\xf4\xc4\x0ei\b\x81<\aE\xb0\xae\xa9Xm\x9d\xd91\x89#\xfe\xd9\xe1\xfa+`\x00\x00\u07d4\x19\xf6C\xe1\xa8\xfa\x04\xae\x16\x00`(\x13\x833\xa5\x9a\x96\u0787\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x19\xf9\x9f,\vF\u0389\x06\x87]\xc9\xf9\n\xe1\x04\xda\xe3U\x94\x89\xf4WZ]M\x16*\x00\x00\u07d4\x19\xff$O\xcf\xe3\xd4\xfa/O\u065f\x87\xe5[\xb3\x15\xb8\x1e\xb6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1a\x04\xce\xc4 \xadC\"\x15$mw\xfe\x17\x8d3\x9e\u0435\x95\x89\x11!a\x85\u009fp\x00\x00\xe0\x94\x1a\x04\xd58\x9e\xb0\x06\xf9\u0388\f0\xd1SS\xf8\xd1\x1cK1\x8a\x03\x9d\x84\xb2\x18m\xc9\x10\x00\x00\u07d4\x1a\bA\xb9*\u007fpuV\x9d\xc4b~kv\u02b0Z\u0791\x89Rf<\u02b1\xe1\xc0\x00\x00\xe0\x94\x1a\b]C\xec\x92AN\xa2{\x91O\xe7g\xb6\xd4k\x1e\xefD\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\x1a\t\xfd\xc2\u01e2\x0e#WK\x97\u019e\x93\u07bag\xd3r \x89lO\xd1\xee$nx\x00\x00\u07d4\x1a\n\x1d\u07f01\xe5\xc8\xcc\x1dF\xcf\x05\x84-P\xfd\xdcq0\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1a\x1c\x9a&\xe0\xe0$\x18\xa5\xcfh}\xa7Z'\\b,\x94@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1a \x1bC'\u03a7\xf3\x99\x04bF\xa3\xc8~n\x03\xa3\u0368\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a$4\xccwD\"\u050dS\u055c]V,\u0384\a\xc9K\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\x1a%\xe1\u017c~_P\xec\x16\xf8\x88_!\x0e\xa1\xb98\x80\x0e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1a&\x94\xec\a\xcf^Mh\xba@\xf3\xe7\xa1LS\xf3\x03\x8cn\x8966\xcd\x06\xe2\xdb:\x80\x00\u07d4\x1a5 E5\x82\xc7\x18\xa2\x1cB7[\xc5\as%RS\xe1\x89*\xd3s\xcef\x8e\x98\x00\x00\xe0\x94\x1a7n\x1b-/Y\ai\xbb\x85\x8dEu2\rN\x14\x99p\x8a\x01\x06q%v9\x1d\x18\x00\x00\u07d4\x1a:3\x0eO\xcbi\xdb\xef^i\x01x;\xf5\x0f\xd1\xc1SB\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1aN\u01a0\xae\u007fZ\x94'\xd2=\xb9rL\r\f\xff\xb2\xab/\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\x1aP^b\xa7N\x87\xe5wG>O:\xfa\x16\xbe\xdd<\xfaR\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x1a^\xe53\xac\xbf\xb3\xa2\xd7m[hRw\xb7\x96\xc5j\x05+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1adJP\xcb\u00ae\xe8#\xbd+\xf2C\xe8%\xbeMG\xdf\x02\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x1apD\xe28?\x87\b0[I[\xd1\x17k\x92\xe7\xef\x04:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1ay\xc7\xf4\x03\x9cg\xa3\x9du\x13\x88L\xdc\x0e,4\"$\x90\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\x89\x89\x9c\xbe\xbd\xbbd\xbb&\xa1\x95\xa6<\bI\x1f\u035e\xee\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\x8a\\\xe4\x14\u079c\xd1r\x93~7\xf2\u055c\xffq\xceW\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1a\x95\xa8\xa8\b.FR\xe4\x17\r\xf9'\x1c\xb4\xbbC\x05\xf0\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x1a\x95\u0277Tk]\x17\x86\u00c5\x8f\xb1#dF\xbc\f\xa4\u0389j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1a\x98~?\x83\xdeu\xa4/\x1b\xde|\x99|\x19!{J_$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1a\x9ep/8]\xcd\x10^\x8b\x9f\xa4(\xee\xa2\x1cW\xffR\x8a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1a\xa1\x02\x1fU\n\xf1X\xc7Gf\x8d\xd1;F1`\xf9Z@\x89O\xb0Y\x1b\x9b08\x00\x00\u07d4\x1a\xa2v\x99\xca\u068d\u00e7oy3\xaaf\xc7\x19\x19\x04\x0e\x88\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x1a\xa4\x02p\xd2\x1e\\\u0786\xb61m\x1a\xc3\xc53IKy\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\xb5:\x11\xbc\xc6=\u07ea@\xa0+\x9e\x18d\x96\u037b\x8a\xff\x89l?*\xac\x80\f\x00\x00\x00\u07d4\x1a\xbcN%;\b\n\xebCy\x84\xab\x05\xbc\xa0\x97\x9a\xa4>\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xc0\x89\u00fcM\x82\xf0j \x05\x1a\x9ds-\xc0\xe74\xcba\x89%\xf6\x9dc\xa6\xce\x0e\x00\x00\xe0\x94\x1a\xd4V>\xa5xk\xe1\x15\x995\xab\xb0\xf1\u0547\x9c>sr\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xd7- \xa7n\u007f\xcckv@X\xf4\x8dA}Io\xa6\u0349lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\xda\xf4\xab\xfa\x86}\xb1\u007f\x99\xafj\xbe\xbfpz<\xf5]\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xf6\x03C6\x0e\v-u%R\x107W \xdf!\xdb\\}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xfc\u0145\x89l\xd0\xed\xe1)\xee-\xe5\xc1\x9e\xa8\x11T\vd\x89\xaf*\xba\f\x8e[\xef\x80\x00\u07d4\x1b\x05\xeajj\u022f|\xb6\xa8\xb9\x11\xa8\xcc\xe8\xfe\x1a*\xcf\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\v1\xaf\xffKm\xf3e:\x94\xd7\xc8yx\xae5\xf3J\xae\x89\x139\x10E?\xa9\x84\x00\x00\u07d4\x1b\r\ah\x17\xe8\u058e\xe2\xdfN\x1d\xa1\xc1\x14-\x19\x8cD5\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x1b\x13\ro\xa5\x1d\\H\xec\x8d\x1dR\u070a\"{\xe8s\\\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b#\u02c6cUHq\xfb\xbe\r\x9e`9~\xfbo\xae\xdc>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1b&9X\x8bU\xc3D\xb0#\xe8\xde_\xd4\b{\x1f\x04\x03a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x1b9 \xd0\x01\xc4>r\xb2N|\xa4o\x0f\xd6\xe0\xc2\n_\xf2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1b<\xb8\x1eQ\x01\x1bT\x9dx\xbfr\v\r\x92J\xc7c\xa7\u008av\x95\xa9, \xd6\xfe\x00\x00\x00\u07d4\x1bC#,\xcdH\x80\xd6\xf4o\xa7Q\xa9l\xd8$s1XA\x89\x04V9\x18$O@\x00\x00\u07d4\x1bK\xbc\xb1\x81e!\x1b&[(\a\x16\xcb?\x1f!!v\xe8\x89\x19\x9a\xd3}\x03\xd0`\x80\x00\u07d4\x1bM\a\xac\u04c1\x83\xa6\x1b\xb2x=+{\x17\x8d\xd5\x02\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1bckzIo\x04MsYYn5:\x10F\x16Cok\x89\x13\x88\xea\x95\xc3?\x1d\x00\x00\u07d4\x1bd\x95\x89\x12@\xe6NYD\x93\xc2f!q\xdb^0\xce\x13\x89\tX\x87\u0595\xedX\x00\x00\u07d4\x1bf\x10\xfbh\xba\xd6\xed\x1c\xfa\xa0\xbb\xe3:$\xeb.\x96\xfa\xfb\x89\b=lz\xabc`\x00\x00\u07d4\x1by\x903\xefm\xc7\x12x\"\xf7EB\xbb\"\xdb\xfc\t\xa3\b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1b~\xd9t\xb6\xe24\u0381$t\x98B\x9a[\u0520\xa2\xd19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x82o\xb3\xc0\x12\xb0\xd1Y\u253a[\x8aI\x9f\xf3\xc0\xe0<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x8a\xa0\x16\f\u05df\x00_\x88Q\nqI\x13\xd7\n\u04fe3\x89\n\xef\xfb\x83\a\x9a\xd0\x00\x00\xe0\x94\x1b\x8b\xd6\xd2\xec\xa2\x01\x85\xa7\x8e}\x98\xe8\xe1\x85g\x8d\xacH0\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x1b\x9b-\u0096\x0eL\xb9@\x8ft\x05\x82|\x9bY\a\x16\x12\xfd\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1b\xa9\"\x8d8\x87'\xf3\x89\x15\x0e\xa0;s\xc8-\xe8\xeb.\t\x8a\x01\x89t\xfb\xe1w\xc9(\x00\x00\u07d4\x1b\xa9\xf7\x99~S\x87\xb6\xb2\xaa\x015\xac$R\xfe6\xb4\xc2\r\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\x1b\xba\x03\xffkJ\u057f\x18\x18J\xcb!\xb1\x88\xa3\x99\xe9\xebJ\x89a\t=|,m8\x00\x00\u07d4\x1b\xbc\x19\x9eXg\x90\xbe\x87\xaf\xed\xc8I\xc0G&t\\]{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1b\xbc`\xbc\xc8\x0e\\\xdc5\xc5Aj\x1f\n@\xa8=\xae\x86{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xc4L\x87a#\x1b\xa1\xf1\x1f_\xaa@\xfaf\x9a\x01>\x12\u0389\v\tR\xc4Z\xea\xad\x00\x00\u07d4\x1b\xcf4A\xa8f\xbd\xbe\x960\t\xce3\xc8\x1c\xbb\x02a\xb0,\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\x1b\u048c\xd5\u01ca\xeeQ5|\x95\xc1\xef\x925\xe7\xc1\x8b\xc8T\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xd8\xeb\xaavt\xbb\x18\u1458\xdb$OW\x03\x13\a_C\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\x1b\xd9\t\xac\rJ\x11\x02\xec\x98\xdc\xf2\u0329j\n\xdc\u05e9Q\x89\x01\x16Q\xac>zu\x80\x00\u07d4\x1b\xe3T,6\x13hte\xf1Zp\xae\xeb\x81f+e\u0328\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xeaM\xf5\x12/\xaf\u07b3`~\xdd\xda\x1e\xa4\xff\u06da\xbf*\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4\x1b\xecM\x02\u0385\xfcH\xfe\xb6$\x89\x84\x1d\x85\xb1pXj\x9b\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\x1b\xf9t\u0650OE\u0381\xa8E\xe1\x1e\xf4\xcb\xcf'\xafq\x9e\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x1c\x04VI\xcdS\xdc#T\x1f\x8e\xd4\xd3A\x81(\b\xd5\u075c\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1c\x12\x8b\xd6\u0365\xfc\xa2uu\xe4\xb4;2S\xc8\xc4\x17*\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\x13\u04c67\xb9\xa4|\xe7\x9d7\xa8oP\xfb@\x9c\x06\a(\x89Hz\x9a0E9D\x00\x00\u07d4\x1c \x10\xbdf-\xf4\x17\xf2\xa2q\x87\x9a\xfb\x13\xefL\x88\xa3\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1c%z\u0525Q\x05\xea;X\xed7K\x19\x8d\xa2f\xc8_c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x1c.6\a\xe1'\xca\xca\x0f\xbd\\YH\xad\xad}\xd80\xb2\x85\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x1c5l\xfd\xb9_\xeb\xb7\x14c;(\xd5\xc12\u0744\xa9\xb46\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4\x1c5\xaa\xb6\x88\xa0\u034e\xf8.vT\x1b\xa7\xac9R\u007ft;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x1c>\xf0]\xae\x9d\xcb\u0509\xf3\x02D\bf\x9d\xe2D\xc5*\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x1cJ\xf0\xe8c\xd2el\x865\xbco\xfe\xc8\u0759(\x90\x8c\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c`\x19\x93x\x92\a\xf9e\xbb\x86\\\xbbL\xd6W\xcc\xe7o\xc0\x89\x05T\x1ap7P?\x00\x00\u07d4\x1cc\xfa\x9e,\xbb\xf21a\xda3\xa1\xda}\xf7\r\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1c\xb6\xb2\xd7\xcf\xc5Y\xb7\xf4\x1eoV\xab\x95\xc7\xc9X\xcd\x0eL\x89Hz\x9a0E9D\x00\x00\u07d4\x1c\xc1\xd3\xc1O\x0f\xb8d\x0e6rM\xc42)\xd2\xeaz\x1eH\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x1c\xc9\bv\x00A\t\xcdy\xa3\u07a8f\u02c4\n\xc3d\xba\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xd1\xf0\xa3\x14\u02f2\x00\xde\n\f\xb1\xef\x97\xe9 p\x9d\x97\u0089lk\x93[\x8b\xbd@\x00\x00\u0794\x1c\xdaA\x1b\xd5\x16;\xae\xca\x1eU\x85c`\x1c\xe7 \xe2N\xe1\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1c\xe8\x1d1\xa7\x920\"\xe1%\xbfH\xa3\xe06\x93\xb9\x8d\xc9\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xeb\xf0\x98]\u007fh\n\xaa\x91\\D\xccb\xed\xb4\x9e\xab&\x9e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1c\xedg\x15\xf8b\xb1\xff\x86\x05\x82\x01\xfc\xceP\x82\xb3nb\xb2\x8a\x01j^`\xbe\xe2s\xb1\x00\x00\u07d4\x1c\xf0L\xb1C\x80\x05\x9e\xfd?#\x8be\u057e\xb8j\xfa\x14\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1c\xf1\x05\xab#\x02;ULX>\x86\u05d2\x11y\xee\x83\x16\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1c\xf2\xebz\x8c\xca\u00ad\xea\xef\x0e\xe8sG\xd55\u04f9@X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xfc\xf7Q\u007f\f\bE\x97 \x94+dz\u0452\xaa\x9c\x88(\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x1d\t\xad$\x12i\x1c\u0141\xc1\xab6\xb6\xf9CL\xd4\xf0\x8bT\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1d\x15|Xv\xc5\xca\xd5S\xc9\x12\xca\xf6\xce-Rw\xe0\\s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1d&\x15\xf8\xb6\xcaP\x12\xb6c\xbd\u0414\xb0\xc5\x13|w\x8d\u07ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1d)\u01ea\xb4+ H\u04b2R%\u0518\u06e6z\x03\xfb\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794\x1d4\x1f\xa5\xa3\xa1\xbd\x05\x1f}\xb8\a\xb6\xdb/\u01faO\x9bE\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1d4N\x96%g\xcb'\xe4M\xb9\xf2\xfa\u01f6\x8d\xf1\xc1\xe6\xf7\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x1d6h0c\xb7\xe9\xeb\x99F-\xab\xd5i\xbd\xdc\xe7\x16\x86\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d7aky?\x94\x91\x188\xac\x8e\x19\xee\x94I\u07d2\x1e\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94\x1d9[0\xad\xda\x1c\xf2\x1f\t\x1aOJ{u3q\x18\x94A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x1dEXn\xb8\x03\xca!\x90e\v\xf7H\xa2\xb1t1+\xb5\a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1dW.\xdd-\x87\xca'\x1ag\x14\xc1Z;7v\x1d\u0320\x05\x89\x06\xeb\xd5*\x8d\xdd9\x00\x00\u07d4\x1dc0\x97\xa8R%\xa1\xffC!\xb1)\x88\xfd\xd5\\+8D\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1di\xc8=(\xff\x04t\xce\xeb\xea\xcb:\xd2'\xa1D\xec\u78ca\x01(\xcc\x03\x92\nb\u0480\x00\u07d4\x1d\x96\xbc\u0544W\xbb\xf1\xd3\u00a4o\xfa\xf1m\xbf}\x83hY\x89\tIr\t\xd8F~\x80\x00\u07d4\x1d\x9ej\xaf\x80\x19\xa0_#\x0e]\xef\x05\xaf]\x88\x9b\xd4\xd0\xf2\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x1d\xab\x17.\xff\xa6\xfb\xeeSL\x94\xb1~yN\xda\xc5OU\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1d\xb9\xac\x9a\x9e\xae\xec\nR7W\x05\fq\xf4rx\xc7-P\x89Hz\x9a0E9D\x00\x00\u07d4\x1d\xbe\x8e\x1c+\x8a\x00\x9f\x85\xf1\xad<\xe8\r.\x055\x0e\u3709\aW\rn\x9e\xbb\xe4\x00\x00\u07d4\x1d\xc7\xf7\xda\xd8]\xf5?\x12q\x15$\x03\xf4\xe1\xe4\xfd\xb3\xaf\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1d\u03bc\xb7em\xf5\u072a3h\xa0U\xd2/\x9e\xd6\xcd\xd9@\x89\x1b\x18\x1eK\xf24<\x00\x00\xe0\x94\x1d\xd7tA\x84J\xfe\x9c\xc1\x8f\x15\xd8\xc7{\xcc\xfbe^\xe04\x8a\x01\x06\xebEW\x99D\x88\x00\x00\u07d4\x1d\xde\xfe\xfd5\xab\x8fe\x8b$q\xe5G\x90\xbc\x17\xaf\x98\u07a4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d\xee\xc0\x1a\xbe\\\r\x95-\xe9\x10l=\xc3\x069\xd8P\x05\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1d\xf6\x91\x16rg\x9b\xb0\xef5\t\x03\x8c\f'\xe3\x94\xfd\xfe0\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\x1d\xfa\xee\ar\x12\xf1\xbe\xaf\x0eo/\x18@Sz\xe1T\xad\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1e\x06\r\xc6\xc5\xf1\u02cc\xc7\xe1E.\x02\xee\x16u\b\xb5eB\x8a\x02\xb1O\x02\xc8d\xc7~\x00\x00\xe0\x94\x1e\x13\xecQ\x14,\ubde2`\x83A,<\xe3QD\xbaV\xa1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1e\x1aH(\x11\x9b\xe3\t\xbd\x88#nMH+PM\xc5W\x11\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x1e\x1a\ud178leb\u02cf\xa1\xebo\x8f;\xc9\u072eny\x89\xf4\xd2\u0744%\x9b$\x00\x00\u07d4\x1e\x1ccQwj\xc3\x10\x919~\xcf\x16\x00-\x97\x9a\x1b-Q\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1e\x1dz_$h\xb9N\xa8&\x98-\xbf!%yR*\xb7\xdf\n\u02ac\x9e\xee\xd3Y09\xe5\xacuy\x8a+\x14F\xddj\xef\xe4\x1c\x00\x00\u07d4\x1e{^M\x1fW+\xec\xf2\xc0\x0f\xc9\f\xb4v{Jn3\u0509\x06\x1f\xc6\x10u\x93\xe1\x00\x00\u07d4\x1e\x8eh\x9b\x02\x91|\xdc)$]\f\x9ch\xb0\x94\xb4\x1a\x9e\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xa34\xb5u\b\a\xeat\xaa\u016b\x86\x94\xec_(\xaaw\u03c9\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x1e\xa4qU\x04\u01af\x10{\x01\x94\xf4\xf7\xb1\xcbo\xcc\xcdoK\x89 \x041\x97\xe0\xb0'\x00\x00\u07d4\x1e\xa4\x92\xbc\xe1\xad\x10~3\u007fK\u0527\xac\x9a{\xab\xcc\u036b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1e\xa6\xbf/\x15\xae\x9c\x1d\xbcd\u06a7\xf8\xeaM\r\x81\xaa\xd3\xeb\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1e\xb4\xbfs\x15j\x82\xa0\xa6\x82 \x80\xc6\xed\xf4\x9cF\x9a\xf8\xb9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\x1e\xba\xcbxD\xfd\xc3\"\xf8\x05\x90O\xbf\x19b\x80-\xb1S|\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1e\xc4\xecKw\xbf\x19\u0411\xa8h\xe6\xf4\x91T\x18\x05A\xf9\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xd0n\xe5\x16b\xa8lcE\x88\xfbb\xdcC\xc8\xf2~|\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1e\u063b?\x06w\x8b\x03\x9e\x99a\xd8\x1c\xb7\x1as\xe6x|\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xda\bNye\x00\xba\x14\xc5\x12\x1c\r\x90\x84of\xe4\xbeb\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4\x1e\xeel\xbe\xe4\xfe\x96\xadaZ\x9c\xf5\x85zdy@\u07ccx\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4\x1e\xf2\u073f\xe0\xa5\x00A\x1d\x95n\xb8\u0213\x9c=l\xfef\x9d\x89*\x11)\u0413g \x00\x00\xe0\x94\x1e\xf5\xc9\xc76P\u03fb\xde\\\x88U1\xd4'\xc7\xc3\xfeUD\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1f\x04\x12\xbf\xed\u0356N\x83}\t,q\xa5\xfc\xba\xf3\x01&\xe2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x17O@\xa0Dr4\xe6fS\x91Mu\xbc\x00>V\x90\u0709\b\xacr0H\x9e\x80\x00\x00\u07d4\x1f!\x86\xde\xd2>\f\xf9R\x16\x94\xe4\xe1dY>i\n\x96\x85\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x1f*\xfc\n\xed\x11\xbf\xc7\x1ew\xa9\ae{6\xeav\xe3\xfb\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x1f9Y\xfc)\x11\x10\xe8\x822\xc3kvg\xfcx\xa3ya?\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1f=\xa6\x8f\xe8~\xafC\xa8)\xabm~\u0166\xe0\t\xb2\x04\xfb\x89\x1e\x16\x01u\x8c,~\x00\x00\u07d4\x1fI\xb8m\r9EY\x06\x98\xa6\xaa\xf1g<7u\\\xa8\r\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\x1f_;4\xbd\x13K'\x81\xaf\xe5\xa0BJ\u0144l\xde\xfd\x11\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\u07d4\x1fo\x0004\x97R\x06\x1c\x96\a+\xc3\xd6\xeb5I \x8dk\x89\x01K\x8d\xe1\xeb\x88\u06c0\x00\u07d4\x1f}\x8e\x86\xd6\xee\xb0%E\xaa\xd9\x0e\x912{\xd3i\xd7\xd2\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x81\x16\xbd\n\xf5W\x0e\xaf\fV\u011cz\xb5\xe3zX\x04X\x89lk\x93[\x8b\xbd@\x00\x00\u0794\x1f\x88\xf8\xa13\x8f\xc7\xc1\tv\xab\xcd?\xb8\u04c5T\xb5\uc708\xb9\xf6]\x00\xf6<\x00\x00\u07d4\x1f\x9c2hE\x8d\xa3\x01\xa2\xbeZ\xb0\x82W\xf7{\xb5\xa9\x8a\xa4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1f\xa21\x9f\xed\x8c-F*\xdf.\x17\xfe\xecjo0Qn\x95\x89\x06\xca\xe3\x06!\xd4r\x00\x00\u07d4\x1f\xb4c\xa08\x99\x83\xdf}Y?{\xddmxI\u007f\xed\x88y\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\xb7\xbd1\r\x95\xf2\xa6\u067a\xaf\x8a\x8aC\n\x9a\x04E:\x8b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x1f\xcc|\xe6\xa8HX\x95\xa3\x19\x9e\x16H\x1fr\xe1\xf7b\xde\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1f\xcf\xd1\xd5\u007f\x87\"\x90V\f\xb6-`\x0e\x1d\xef\xbe\xfc\xcc\x1c\x89P\xc5\xe7a\xa4D\b\x00\x00\u0794\x1f\u0496\xbe\x03\xads|\x92\xf9\u0186\x9e\x8d\x80\xa7\x1cW\x14\xaa\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x1f\xdd\xd8_\u024b\xe9\xc4\x04Ya\xf4\x0f\x93\x80^\xccEI\xe5\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4 \x01\xbe\xf7{f\xf5\x1e\x15\x99\xb0/\xb1\x10\x19J\x00\x99\xb7\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \x02d\xa0\x9f\x8ch\xe3\xe6b\x97\x95(\x0fV%O\x86@\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x03qy\a\xa7%`\xf40\u007f\x1b\xee\xccT6\xf4=!\xe7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \r\xfc\vq\xe3Y\xb2\xb4eD\n6\xa6\xcd\xc3Rw0\a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4 \x13L\xbf\xf8\x8b\xfa\xdcFkR\xec\ua9d8W\x89\x1d\x83\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4 \x14&\x1f\x01\b\x9fSyV0\xba\x9d\xd2O\x9a4\xc2\xd9B\x89Hz\x9a0E9D\x00\x00\u07d4 \x16\x89]\xf3,\x8e\xd5G\x82iF\x84#\xae\xa7\xb7\xfb\xceP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x18\x1cKA\xf6\xf9r\xb6iX!_\x19\xf5p\xc1]\xdf\xf1\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4 \x18d\xa8\xf7\x84\xc2'{\v|\x9e\xe74\xf7\xb3w\xea\xb6H\x89\xf2(\x14\x00\xd1\xd5\xec\x00\x00\u07d4 \xb8\x1a\xe59&\xac\xe9\xf7\xd7AZ\x05\f\x03\x1dX_ \x89\x12\u007f\x19\xe8>\xb3H\x00\x00\xe0\x94 \x1d\x9e\xc1\xbc\v\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4 \xa1RV\xd5\f\xe0X\xbf\x0e\xacC\xaaS:\xa1n\u0273\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \xa2\x9cPy\xe2k?\x181\x8b\xb2\xe5\x0e\x8e\x8b4n[\xe8\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4 \xa8\x16\x80\xe4e\xf8\x87\x90\xf0\aO`\xb4\xf3_]\x1ej\xa5\x89Ea\x80'\x8f\fw\x80\x00\u07d4 \xb9\xa9\u6f48\x80\u0659J\xe0\r\u0439(*\v\xea\xb8\x16\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \u0084\xba\x10\xa2\b0\xfc=i\x9e\xc9}-\xfa'\xe1\xb9^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \xd1A\u007f\x99\xc5i\u3fb0\x95\x85e0\xfe\x12\xd0\xfc\uaa89@\x15\xf9K\x11\x83i\x80\x00\u07d4 \u074f\u02f4n\xa4o\u3066\x8b\x8c\xa0\xea[\xe2\x1f\u9949lk\x93[\x8b\xbd@\x00\x00\xe0\x94 \xff>\u078c\xad\xb5\xc3{H\xcb\x14X\x0f\xb6^#\t\n{\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\xe0\x94!\x008\x1d`\xa5\xb5J\xdc\t\u0456\x83\xa8\xf6\u057bK\xfb\u02ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x18\xc1\x16\xab\f\xdfo\xd1\x1dT\xa40\x93\a\xb4w\xc3\xfc\x0f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x1b)\xce\xfcy\xae\x97gD\xfd\xeb\u03bd<\xbb2\xc5\x13\x03\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4! l\xe2.\xa4\x80\xe8Y@\xd3\x13\x14\xe0\xd6ONM:\x04\x8965\u026d\xc5\u07a0\x00\x00\u07d4!2\xc0Qj.\x17\x17J\xc5G\xc4;{\x00 \xd1\xebLY\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94!@\x8bMz,\x0en\xcaAC\xf2\xca\u037b\u033a\x12\x1b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d4!Kt9U\xa5\x12\xden\r\x88j\x8c\xbd\x02\x82\xbe\xe6\u04a2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!L\x89\u017d\x8e}\"\xbcWK\xb3^H\x95\x02\x11\xc6\xf7v\x89\x01\x06T\xf2X\xfd5\x80\x00\xe0\x94!Ti\x14\xdf\u04ef*\xddA\xb0\xff>\x83\xff\xdat\x14\xe1\xe0\x8a\x01C\x95\xe78ZP.\x00\x00\u07d4!X.\x99\xe5\x02\xcb\xf3\xd3\xc2;\xdf\xfbv\xe9\x01\xacmV\xb2\x89\x05k\xc7^-c\x10\x00\x00\u07d4!Y$\b\x13\xa70\x95\xa7\xeb\xf7\u00f3t>\x80(\xae_\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!`\xb4\xc0,\xac\n\x81\u0791\b\xdeCE\x90\xa8\xbf\xe6\x875\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94!nA\x86N\xf9\x8f\x06\r\xa0\x8e\xca\xe1\x9a\xd1\x16j\x17\xd06\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4!\x84o/\xdfZA\xed\x8d\xf3n^\xd8TM\xf7Y\x88\xec\xe3\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94!\xa6\xdbe'F{\xc6\xda\xd5K\xc1n\x9f\xe2\x95;g\x94\xed\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4!\xa6\xfe\xb6\xab\x11\xc7f\xfd\xd9w\xf8\xdfA!\x15_G\xa1\xc0\x89\x03\x19\xcf8\xf1\x00X\x00\x00\u07d4!\xb1\x82\xf2\xda+8D\x93\xcf_5\xf8=\x9d\x1e\xe1O*!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xbf\xe1\xb4\\\xac\xdebt\xfd\x86\b\u0661x\xbf>\xebn\u0709l\xee\x06\u077e\x15\xec\x00\x00\u07d4!\xc0s\x80HOl\xbc\x87$\xad2\xbc\x86L;Z\xd5\x00\xb7\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94!\u00e8\xbb\xa2g\xc8\u0322{\x1a\x9a\xfa\xba\xd8o`z\xf7\b\x8a\x01\xe4\xa3lI\u06580\x00\x00\u07d4!\xcem[\x90\x18\xce\xc0J\u0596yD\xbe\xa3\x9e\x800\xb6\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4!\xd0'\x05\xf3\xf6I\x05\xd8\x0e\xd9\x14y\x13\xea\x8cs\a\u0595\x89I\xed\xb1\xc0\x98\x876\x00\x00\u07d4!\xd1?\f@$\xe9g\xd9G\a\x91\xb5\x0f\"\xde:\xfe\xcf\x1b\x89\xf1Z\xd3^.1\xe5\x00\x00\xe0\x94!\xdb\u06c1z\r\x84\x04\u01bd\xd6\x15\x047N\x9cC\xc9!\x0e\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\xe0\x94!\xdf\x1e\xc2KNK\xfey\xb0\xc0\x95\u03ba\xe1\x98\xf2\x91\xfb\u044a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94!\xdf-\u036ft\xb2\xbf\x804\x04\xddM\xe6\xa3^\xab\xec\x1b\xbd\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4!\xe2\x19\u021c\xa8\xac\x14\xaeL\xbaa0\xee\xb7}\x9em9b\x89*\u035f\xaa\xa08\xee\x00\x00\u07d4!\xe5\u04ba\xe9\x95\xcc\xfd\b\xa5\xc1k\xb5$\xe1\xf60D\x8f\x82\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4!\xe5\xd7s 0L \x1c\x1eS\xb2a\xa1#\u0421\x06>\x81\x89\x04\xb6\xfa\x9d3\xddF\x00\x00\xe0\x94!\xea\xe6\xfe\xff\xa9\xfb\xf4\u0347OG9\xac\xe50\u033eY7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4!\xec\xb2\u07e6Wy\xc7Y-\x04\x1c\xd2\x10Z\x81\xf4\xfdNF\x8965\u026d\xc5\u07a0\x00\x00\u07d4!\uff20\x9b5\x80\xb9\x8es\xf5\xb2\xf7\xf4\xdc\v\xf0,R\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xfd\v\xad\xe5\xf4\xeftt\xd0X\xb7\xf3\xd8T\xcb\x13\x00RN\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94!\xfdG\xc5%`\x12\x19\x8f\xa5\xab\xf11\xc0mj\xa1\x96_u\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4!\xfdl]\x97\xf9\xc6\x00\xb7h!\xdd\xd4\xe7v5\x0f\xce+\xe0\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\"\r\u018d\xf0\x19\xb6\xb0\u033f\xfbxKZZ\xb4\xb1]@`\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\"\x0e+\x92\xc0\xf6\xc9\x02\xb5\x13\xd9\xf1\xe6\xfa\xb6\xa8\xb0\xde\xf3\u05c9+^:\xf1k\x18\x80\x00\x00\u07d4\"V\x1cY1\x14560\x9c\x17\xe82X{b\\9\v\x9a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"W\xfc\xa1jn\\*d|<)\xf3l\xe2)\xab\x93\xb1~\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"]5\xfa\xed\xb3\x91\u01fc-\xb7\xfa\x90q\x16\x04\x05\x99m\x00\x89\t\x18T\xfc\x18bc\x00\x00\u07d4\"_\x9e\xb3\xfbo\xf3\xe9\xe3\xc8D~\x14\xa6n\x8dO7y\xf6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\"r\x18n\xf2}\xcb\xe2\xf5\xfc70P\xfd\xae\u007f*\xce#\x16\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4\"s\xba\u05fcNHv\"\xd1u\xefzf\x98\x8bj\x93\xc4\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\"v&K\xec\x85&\xc0\xc0\xf2pgz\xba\xf4\xf0\xe4A\xe1g\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\"\x82B\xf83n\xec\xd8$.\x1f\x00\x0fA\x93~q\xdf\xfb\xbf\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\"\x84*\xb80\xdaP\x99\x13\xf8\x1d\xd1\xf0O\x10\xaf\x9e\xdd\x1cU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x94O\xbc\xa9\xb5yc\bN\xb8M\xf7\xc8_\xb9\xbc\u07f8V\x89\xfc\x11\x8f\uf43a8\x80\x00\u07d4\"\x9c\xc4q\x1bbu^\xa2\x96DZ\u00f7\u007f\xc63\x82\x1c\xf2\x89\x02#\xe8\xb0R\x192\x80\x00\u0794\"\x9eC\r\xe2\xb7OD&Q\xdd\u0377\x01v\xbc\x05L\xadT\x88\xbb\xf9\x81\xbcJ\xaa\x80\x00\u07d4\"\x9fO\x1a*OT\atP[G\a\xa8\x1d\xe4D\x10%[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x9f\xf8\v\xf5p\x80\t\xa9\xf79\xe0\xf8\xb5`\x91@\x16\u0566\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4\"\xa2X\x12\xabV\xdc\xc4#\x17^\xd1\u062d\xac\xce3\xcd\x18\x10\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\"\xb9j\xb2\xca\xd5]\xb1\x00\xb50\x01\xf9\xe4\xdb7\x81\x04\xc8\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\"\xbd\xff\xc2@\xa8\x8f\xf7C\x1a\xf3\xbf\xf5\x0e\x14\xda7\xd5\x18>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xce4\x91Y\xee\xb1D\xef\x06\xff&6X\x8a\xefy\xf6(2\x89\n1\x06+\xee\xedp\x00\x00\u07d4\"\xdbU\x9f,<\x14u\xa2\xe6\xff\xe8:YyY\x91\x96\xa7\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xe1QX\xb5\xee>\x86\xeb\x032\xe3\u6a6cl\u0675^\u0349\b\xacr0H\x9e\x80\x00\x00\u07d4\"\xe2H\x8e-\xa2jI\xae\x84\xc0\x1b\xd5K!\xf2\x94x\x91\u0189]\u0212\xaa\x111\xc8\x00\x00\u07d4\"\xe5\x12\x14\x9a\x18\xd3i\xb7\x86\xc9\xed\xab\xaf\x1d\x89N\xe0.g\x14a\\\x00\x00\u07d4\"\xeb}\xb0\xbaV\xb0\xf8\xb8\x16\u0332\x06\xe6\x15\xd9)\x18[\r\x89\x04])s~\"\xf2\x00\x00\u07d4\"\xee\xd3'\xf8\xeb\x1d\x138\xa3\xcb{\x0f\x8aK\xaaY\a\u0355\x89\x01E]_Hw\b\x80\x00\xe0\x94\"\xf0\x04\u07cd\xe9\xe6\xeb\xf5#\u032c\xe4W\xac\xcb&\xf9r\x81\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\"\xf2\xdc\xffZ\u05cc>\xb6\x85\v\\\xb9Q\x12{e\x95\"\u623e -j\x0e\xda\x00\x00\u07d4\"\xf3\xc7y\xddy\x02>\xa9*x\xb6\\\x1a\x17\x80\xf6-\\J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\"\xfe\x88M\x907)\x1bMR\xe6(Z\xe6\x8d\xea\v\xe9\xff\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x06\u07d3\x1a\x94\rX\xc0\x16e\xfaM\b\x00\x80,\x02\xed\xfe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94#\t\xd3@\x91D[22Y\v\xd7\x0fO\x10\x02[,\x95\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#\x12\x00F\xf6\x83!\x02\xa7R\xa7fVi\x1c\x86>\x17\u5709\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4#\x1a\x15\xac\xc1\x99\u021f\xa9\xcb\"D\x1c\xc7\x030\xbd\xcc\xe6\x17\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4#\x1d\x94\x15]\xbc\xfe*\x93\xa3\x19\xb6\x17\x1fc\xb2\v\u04b6\xfa\x89\xcf\x14{\xb9\x06\xe2\xf8\x00\x00\u07d4#(2\xcdYw\xe0\nL0\xd0\x16?.$\xf0\x88\xa6\xcb\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4#,m\x03\xb5\xb6\xe6q\x1e\xff\xf1\x90\xe4\x9c(\xee\xf3l\x82\xb0\x89Hz\x9a0E9D\x00\x00\xe0\x94#,\xb1\xcdI\x99<\x14J?\x88\xb3a\x1e#5i\xa8k\u058a\x03L`lB\u042c`\x00\x00\u07d4#,\xe7\x82Pb%\xfd\x98`\xa2\xed\xc1Jz0Gsm\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4#/R]U\x85\x9b}N`\x8d H\u007f\xaa\xdb\x00)15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94#4\u0150\u01e4\x87i\x100E\u0176SL\x8a4i\xf4J\x8a\x03\xb1\x99\a=\xf7-\xc0\x00\x00\u07d4#7n\u02bftl\xe53!\xcfB\xc8fI\xb9+g\xb2\xff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#7\x8fB\x92m\x01\x84\xb7\x93\xb0\xc8'\xa6\xdd>=3O\u0349\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4#8B\xb1\xd0i/\xd1\x11@\xcfZ\u0364\xbf\x960\xba\xe5\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#9\xe9I(p\xaf\xea%7\xf3\x89\xac/\x83\x83\x02\xa3<\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#;\xdd\xdd]\xa9HR\xf4\xad\xe8\xd2\x12\x88V\x82\xd9\ak\u0189\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#OF\xba\xb7?\xe4]1\xbf\x87\xf0\xa1\xe0Fa\x99\xf2\ubb09\x1aJ\xba\"\\ t\x00\x00\u07d4#U\x1fV\x97_\xe9+1\xfaF\x9cI\xeaf\xeefb\xf4\x1e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4#V\x95B\xc9}V`\x18\xc9\a\xac\xfc\xf3\x91\xd1@g\xe8~\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94#_\xa6l\x02^\xf5T\x00p\xeb\xcf\r7-\x81w\xc4g\xab\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\xe0\x94#r\xc4\xc1\u0253\x9fz\xafl\xfa\xc0@\x90\xf0\x04t\x84\n\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#s\f5z\x91\x02nD\xb1\xd0\xe2\xfc*Q\xd0q\xd8\xd7{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#v\xad\xa9\x033\xb1\u0441\bL\x97\xe6E\xe8\x10\xaa[v\xf1\x89(\xa8WBTf\xf8\x00\x00\u07d4#x\xfdC\x82Q\x1e\x96\x8e\u0452\x10g7\xd3$\xf4T\xb55\x8965\u026d\xc5\u07a0\x00\x00\u07d4#\x82\xa9\u050e\xc8>\xa3e(\x90\xfd\x0e\u7710{[-\xc1\x89\a?u\u0460\x85\xba\x00\x00\u07d4#\x83\xc2\"\xe6~\x96\x91\x90\xd3!\x9e\xf1M\xa3xP\xe2lU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x8akv5%/RDHl\n\xf0\xa7: s\x85\xe09\x89JD\x91\xbdm\xcd(\x00\x00\u07d4#\x9as>k\x85Z\u0152\xd6c\x15a\x86\xa8\xa1t\xd2D\x9e\x89X\xbe7X\xb2A\xf6\x00\x00\xe0\x94#\xab\t\xe7?\x87\xaa\x0f;\xe0\x13\x9d\xf0\xc8\xebk\xe5cO\x95\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94#\xab\xd9\xe9>yW\xe5\xb66\xbeey\x05\x1c\x15\xe5\xce\v\x0e\x8a\x03\xa3\xc8\xf7\xcb\xf4,8\x00\x00\u07d4#\xb1\u0111\u007f\xbd\x93\xee=H8\x93\x06\x95s\x84\xa5Il\xbf\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94#\xba8d\xdaX=\xabV\xf4 \x87<7g\x96\x90\xe0/\x00\x8a\x02\x13BR\r_\xec \x00\x00\u07d4#\xc5Z\xebW9\x87o\n\xc8\xd7\xeb\xea\x13\xber\x96\x85\xf0\x00\x89Hz\x9a0E9D\x00\x00\u07d4#\u025b\xa0\x87D\x8e\x19\xc9p\x1d\xf6n\f\xabR6\x831\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xcc\xc3\u01ac\xd8\\.F\fO\xfd\xd8+\xc7]\xc8I\xea\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#\xcd%\x98\xa2\x0e\x14\x9e\xad*\u0593yWn\xce\xdb`\u3389lk\x93[\x8b\xbd@\x00\x00\u07d4#\u07cfH\xee\x00\x92V\xeay~\x1f\xa3i\xbe\xeb\xcfk\xc6c\x89|\xd3\xfa\xc2m\x19\x81\x80\x00\u07d4#\xe2\u01a8\xbe\x8e\n\u03e5\xc4\xdf^6\x05\x8b\xb7\u02ecZ\x81\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xeaf\x9e5d\x81\x9a\x83\xb0\xc2l\x00\xa1m\x9e\x82olF\x89M\x8dl\xa9h\xca\x13\x00\x00\u07d4#\xebo\xd8Vq\xa9\x06:\xb7g\x8e\xbe&Z \xf6\x1a\x02\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xf9\xec\xf3\xe5\xdd\u0723\x88\x15\xd3\xe5\x9e\xd3K[\x90\xb4\xa3S\x89\v\x17\x81\xa3\xf0\xbb \x00\x00\u07d4#\xfa~\xb5\x1aH\"\x95\x98\xf9~v+\xe0\x86\x96R\xdf\xfcf\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94$\x03\x05rs\x13\xd0\x1esT,w_\xf5\x9d\x11\xcd5\xf8\x19\x8a\x01A\x88Vf\x80\u007f\\\x80\x00\u07d4$\x04k\x91\u069ba\xb6)\u02cb\x8e\xc0\xc3Q\xa0~\a\x03\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\x0eU\x9e'J\xae\xf0\xc2X\x99\x8c\x97\x9fg\x1d\x11s\xb8\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94$\x13aU\x9f\xee\xf8\x0e\xf170!S\xbd\x9e\xd2\xf2]\xb3\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94$;;\xcaj)\x93Y\xe8\x86\xce3\xa3\x03A\xfa\xfeMW=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4$<\x84\xd1$ W\f\xc4\xef;\xab\xa1\xc9Y\u0083$\x95 \x89\u007f\x1fi\x93\xa8S\x04\x00\x00\xe0\x94$CJ>2\xe5N\xcf'/\xe3G\v_oQ/gU \x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4$HYo\x91\xc0\x9b\xaa0\xbc\x96\x10j-7\xb5p^](\x89lk\x93[\x8b\xbd@\x00\x00\u0794$Xn\xc5E\x175\xee\xaa\xebG\r\xc8sj\xaeu/\x82\xe5\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4$X\xd6U_\xf9\x8a\x12\x9c\xce@7\x95=\x00 n\xffB\x87\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4$b\x91\x16[Y3-\xf5\xf1\x8c\xe5\u0248V\xfa\xe9X\x97\u0589\\(=A\x03\x94\x10\x00\x00\u07d4$g\u01a5\u0196\xed\xe9\xa1\xe5B\xbf\x1a\xd0k\xccK\x06\xac\xa0\x89\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4$v\xb2\xbbu\x1c\xe7H\xe1\xa4\xc4\xff{#\v\xe0\xc1]\"E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4$z\n\x11\xc5\u007f\x03\x83\xb9I\xdeT\vf\xde\xe6\x86\x04\xb0\xa1\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4$\x87\xc3\u013e\x86\xa2r=\x91|\x06\xb4XU\x01p\xc3\xed\xba\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x89\xac\x12i4\xd4\u05a9M\xf0\x87C\xda{v\x91\xe9y\x8e\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x9d\xb2\x9d\xbc\x19\xd1#]\xa7)\x8a\x04\b\x1c1WB\u9b09a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4$\xa4\xeb6\xa7\xe4\x98\xc3o\x99\x97\\\x1a\x8dr\x9f\u05b3\x05\u05c9\r\xfcx!\x0e\xb2\xc8\x00\x00\u07d4$\xa7P\xea\xe5\x87G\x11\x11m\xd7\xd4{q\x86\u0399\r1\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xaa\x11Q\xbbv_\xa3\xa8\x9c\xa5\x0e\xb6\xe1\xb1\xc7\x06A\u007f\u0509\xa8\r$g~\xfe\xf0\x00\x00\u0794$\xac\xa0\x8d[\xe8^\xbb\x9f12\xdf\xc1\xb6 \x82N\xdf\xed\xf9\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4$\xb2\xbe\x11\x8b\x16\u0632\x17Gi\xd1{L\xf8O\a\u0294m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\xb8\xb4F\u07bd\x19G\x95]\u0404\xf2\xc5D\x933F\u04ed\x89\xeaim\x90@9\xbd\x80\x00\u07d4$\xb9^\xbe\xf7\x95\x00\xba\xa0\xed\xa7.w\xf8wA]\xf7\\3\x891T\xc9r\x9d\x05x\x00\x00\u07d4$\xb9\xe6dOk\xa4\xcd\xe1&'\r\x81\xf6\xab`\xf2\x86\xdf\xf4\x89\a?u\u0460\x85\xba\x00\x00\u07d4$\xbdY\x04\x05\x90\x91\xd2\xf9\xe1-j&\xa0\x10\xca\"\xab\x14\xe8\x89e\xea=\xb7UF`\x00\x00\u07d4$\xc0\u020bT\xa3TG\t\x82\x8a\xb4\xab\x06\x84\x05Y\xf6\xc5\u2250\xf54`\x8ar\x88\x00\x00\u07d4$\xc1\x17\xd1\u04b3\xa9z\xb1\x1aFy\u025awJ\x9e\xad\xe8\u044965\u026d\xc5\u07a0\x00\x00\u07d4$\xcf\xf0\xe93j\x9f\x80\xf9\xb1\u02d6\x8c\xafk\x1d\x1cI2\xa4\x89\n\xdaUGK\x814\x00\x00\u07d4$\u06aa\xdd\xf7\xb0k\xbc\ua6c0Y\x00\x85\xa8\x85gh+N\x89\x11K \x15\u04bb\xd0\x00\x00\u07d4$\xdc\xc2K\xd9\xc7!\f\xea\u03f3\r\xa9\x8a\xe0JM{\x8a\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\xf7E\r\xdb\xf1\x8b\x02\x0f\xeb\x1a 2\xd9\xd5Kc>\xdf7\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4$\xfcs\xd2\a\x93\t\x8e\t\u076bW\x98Pb$\xfa\x1e\x18P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xfd\x9al\x87L/\xab?\xf3n\x9a\xfb\xf8\xce\r2\xc7\u0792\x89Hz\x9a0E9D\x00\x00\u07d4%\n@\xce\xf3 #\x97\xf2@F\x95H\xbe\xb5bj\xf4\xf2<\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\u07d4%\niC\av\xf64w\x03\xf9R\x97\x83\x95Za\x97\xb6\x82\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4%\x0e\xb7\xc6o\x86\x9d\xdfI\u0685\xf39>\x98\f\x02\x9a\xa44\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x10j\xb6u]\xf8mkc\xa1\x87p;\f\xfe\xa0\u5520\x89\x01|@Z\xd4\x1d\xb4\x00\x00\xe0\x94%\x18_2Z\xcf-dP\x06\x98\xf6\\v\x9d\xdfh0\x16\x02\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x1c\x12r,hy\"y\x92\xa3\x04\xeb5v\xcd\x18CN\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\x1eh8\xf7\xce\u0173\x83\xc1\xd9\x01F4\x12t\xda\xf8\xe5\x02\x89\a\xff\x1c\xcbua\xdf\x00\x00\u07d4%%\x9d\x97Z!\xd8:\xe3\x0e3\xf8\x00\xf5?7\u07e0\x198\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4%({\x81_\\\x828\ns\xb0\xb1?\xba\xf9\x82\xbe$\xc4\u04c9\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94%+eU\xaf\u0700\xf2\xd9m\x97-\x17\u06c4\xeaZ\xd5!\xac\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4%8S)6\x81<\x91\xe6S(O\x01|\x80\u00f8\xf8\xa3o\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94%>2\xb7N\xa4I\n\xb9&\x06\xfd\xa0\xaa%{\xf2=\u02cb\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94%?\x1et*,\uc1b0\u05f3\x06\xe5\xea\xcbl\xcb/\x85T\x8a\x04>^\xde\x1f\x87\x8c \x00\x00\u07d4%A1J\v@\x8e\x95\xa6\x94DIwq*Pq5\x91\xab\x89X\x9e\x1a]\xf4\u05f5\x00\x00\u07d4%L\x1e\xccc\f(w\u0780\x95\xf0\xa8\u06e1\xe8\xbf\x1fU\f\x89\\(=A\x03\x94\x10\x00\x00\u07d4%Z\xbc\x8d\b\xa0\x96\xa8\x8f=j\xb5_\xbcsR\xbd\u0739\u0389\x04t6\x821>\u0780\x00\u07d4%[\xdddt\u0302b\xf2j\"\u00cfE\x94\x0e\x1c\ue99b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%`\xb0\x9b\x89\xa4\xaehI\xedZ<\x99XBf1qDf\x89\\(=A\x03\x94\x10\x00\x00\u07d4%a\xa18\xdc\xf8;\xd8\x13\xe0\xe7\xf1\bd+\xe3\xde=o\x05\x8964\xf4\x84\x17@\x1a\x00\x00\u0794%a\xec\x0f7\x92\x18\xfe^\xd4\xe0(\xa3\xf7D\xaaAuLr\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u0794%b\x92\xa1\x91\xbd\xda4\xc4\xdakk\u0591G\xbfu\u2a6b\x88\xc2\xff.\r\xfb\x03\x80\x00\u07d4%i~\xf2\f\u032ap\xd3-7o\x82r\xd9\xc1\a\f=x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%o\xa1P\u0307\xb5\x05j\a\xd0\x04\xef\xc8E$s\x9eb\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%r\x1c\x87\xb0\xdc!7|r\x00\xe5$\xb1J\"\xf0\xafi\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x899\xbb\xf0\f\x9d\xe9\xafS8\xf5\xd7\x14\xab\xf6\xd0\xc1\xc6q\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94%\x90\x12hp\xe0\xbd\xe8\xa6c\xab\x04\nr\xa5W=\x8dA\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x9e\xc4\xd2e\xf3\xabSk|p\xfa\x97\xac\xa1Bi,\x13\xfc\x89\x01\x1b\x1b[\xea\x89\xf8\x00\x00\xe0\x94%\xa5\x00\xee\xeczf*\x84\x15R\xb5\x16\x8bp{\r\xe2\x1e\x9e\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\xe0\x94%\xa5\xa4M8\xa2\xf4Lj\x9d\xb9\u037ck\x1e.\x97\xab\xb5\t\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4%\xa7L*\xc7]\u023a\xa8\xb3\x1a\x9c|\xb4\xb7\x82\x9b$V\u0689lk\x93[\x8b\xbd@\x00\x00\xe0\x94%\xad\xb8\xf9o9I,\x9b\xb4|^\u0708bNF\aV\x97\x8a\x05\xa9\x94\v\xc5hyP\x00\x00\u07d4%\xae\xe6\x8d\t\xaf\xb7\x1d\x88\x17\xf3\xf1\x84\xecV/x\x97\xb74\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xb0S;\x81\xd0*a{\x92)\xc7\xec]o/g.[Z\x8965\u026d\xc5\u07a0\x00\x00\u07d4%\xb7\x8c\x9f\xad\x85\xb43C\xf0\xbf\xcd\x0f\xac\x11\u0254\x9c\xa5\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xbcI\xef(\x8c\xd1e\xe5%\xc6a\xa8\x12\u03c4\xfb\xec\x8f3\x89\x12Y!\xae\xbd\xa9\xd0\x00\x00\u07d4%\xbd\xfa>\xe2o8Ia{#\x00bX\x8a\x97\xe3\xca\xe7\x01\x8965\xe6\x19\xbb\x04\xd4\x00\x00\u07d4%\xc1\xa3~\xe5\xf0\x82e\xa1\xe1\r=\x90\xd5G)U\xf9x\x06\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4%\xc6\xe7O\xf1\xd9(\u07d8\x13z\xf4\u07c40\xdf$\xf0|\u05c9\x15$VU\xb1\x02X\x00\x00\xe0\x94%\xcf\xc4\xe2\\5\xc1;i\xf7\xe7}\xbf\xb0\x8b\xafXuk\x8d\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94%\xda\u0515\xa1\x1a\x86\xb9\xee\xec\xe1\xee\xec\x80^W\xf1W\xfa\xff\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94%\xe07\xf0\n\x18'\v\xa5\xec4 \"\x9d\xdb\n,\u33e2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4%\xe6a\xc99\x86:\xcc\x04No\x17\xb5i\x8c\xce7\x9e\xc3\u0309JD\x91\xbdm\xcd(\x00\x00\u07d4&\x04\x8f\xe8M\x9b\x01\nb\xe71b~I\xbc.\xb7?@\x8f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\x06\u00f3\xb4\xca\x1b\t\x14\x98`,\xb1\x97\x8b\xf3\xb9R!\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4&\n#\x0eDe\a~\v\x14\xeeDB\xa4\x82\u0570\xc9\x14\xbf\x89Z\xf6\x06\xa0k[\x11\x80\x00\u07d4&\r\xf8\x94:\x8c\x9a]\xbayE2\u007f\xd7\xe0\x83|\x11\xad\a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4&\x14\xf4-]\xa8D7ux\xe6\xb4H\xdc$0[\xef+\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\x15\x10\x0e\xa7\xe2[\xba\x9b\xcat`X\xaf\xbb\xb4\xff\xbeBD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4&\x15u\xe9\xcfY\xc8\"o\xa7\xaa\xf9\x1d\xe8o\xb7\x0fZ\u00ee\x89\x10C\xa4CjR?\x00\x00\xe0\x94&\x1e\x0f\xa6LQ\x13te\xee\xcf[\x90\xf1\x97\xf7\x93\u007f\xdb\x05\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4&*\x8b\xfd}\x9d\xc5\xdd:\u05c1a\xb6\xbbV\b$76U\x89?j\x83\x84\a+v\x00\x00\xe0\x94&*\xedK\xc0\xf4\xa4\xb2\xc6\xfb5y>\x83ZI\x18\x9c\xdf\xec\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94&-\xc16L\xcfm\xf8\\C&\x8e\xe1\x82UM\xaei.)\x8a\x01\v /\xect\xce\xd8\x00\x00\u07d4&8\x140\x9d\xe4\xe65\xcfX^\r6Tw\xfc@\xe6l\xf7\x89\a\xea(2uw\b\x00\x00\u07d4&9\xee\xe9\x87<\xee\xc2o\u0314T\xb5H\xb9\xe7\xc5J\xa6\\\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94&>W\xda\xcb\xe0\x14\x9f\x82\xfee\xa2fH\x98\x86o\xf5\xb4c\x8a\b\v\xfb\xef\xcb_\v\xc0\x00\x00\u07d4>\x19\xc0m_\x14z\xa5\x97$\x8e\xb4l\xf7\xbe\xfad\xa5\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4&L\xc8\bj\x87\x10\xf9\x1b!r\t\x05\x91,\u05d6J\xe8h\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94&S\x83\u058bR\xd04\x16\x1b\xfa\xb0\x1a\xe1\xb0G\x94/\xbc2\x8a\x04rq\xde\xe2\rt\\\x00\x00\u07d4&Y\xfa\xcb\x1e\x83CeS\xb5\xb4)\x89\xad\xb8\a_\x99S\xed\x89\x01\x97evw\x1a^\x00\x00\xe0\x94&o-\xa7\xf0\b^\xf3\xf3\xfa\t\xba\xee#+\x93\xc7D\xdb.\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4&qH\xfdr\xc5Ob\nY/\xb9'\x991\x9c\xc4S+\\\x89\x169\u46fa\x16(\x00\x00\xe0\x94&xJ\u0791\u0228:\x8e9e\x8c\x8d\x82wA<\u0319T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4&z~n\x82\xe1\xb9\x1dQ\xde\u0776D\xf0\xe9m\xbb\x1f\u007f~\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\x80q=@\x80\x8e*P\xed\x011P\xa2\xa6\x94\xb9j\u007f\x1d\x89a\t=|,m8\x00\x00\u07d4&\x97\xb39\x81;\f-\x96K$q\xeb\x1c`oN\u02d6\x16\x89>\x8e\xf7\x95\u0610\xc8\x00\x00\u07d4&\xa6\x8e\xab\x90Z\x8b=\xce\x00\xe3\x170\x82%\u06b1\xb9\xf6\xb8\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4&\xb1\x1d\x06e\x88\xcet\xa5r\xa8Zc(s\x92\x12\xaa\x8b@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xba\xbfB\xb2g\xfd\xcf8a\xfd\xd4#j^GHH\xb3X\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xc0\x05Kp\r:|-\xcb\xe2uh\x9dOL\xad\x16\xa35\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xc2\xff\xc3\x0e\xfd\xc5'>v\x18:\x16\xc2i\x8dnS\x12\x86\x89*\x11)\u0413g \x00\x00\u07d4&\u025f\x88I\u0240+\x83\xc8a!\u007f\xd0z\x9e\x84\u0377\x9d\x89\x10CV\x1a\x88)0\x00\x00\u07d4&\xcf\xff\xd0R\x15+\xb3\xf9W\xb4x\xd5\xf9\x8b#:|+\x92\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\u0521h\x91\xf5)\"x\x92\x17\xfc\u0606\xf7\xfc\xe2\x96\xd4\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xd4\xec\x17\xd5\u03b2\u0214\xbd\u015d\nji]\xad+C\u0309\x9f\x1fxv\x1d4\x1a\x00\x00\u07d4&\xe8\x01\xb6,\x82q\x91\xddh\xd3\x1a\x01\x19\x90\x94\u007f\xd0\xeb\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\xe9\xe2\xadr\x97\x02bd\x17\xef%\xde\r\xc8\x00\xf7\xa7y\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xf9\xf7\xce\xfd~9K\x9d9$A+\xf2\u0083\x1f\xaf\x1f\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94&\xfe\x17L\xbfRfP\xe0\xcd\x00\x9b\xd6\x12e\x02\u038ehM\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\xe0\x94&\xff\nQ\xe7\xce\u0384\x00'ix\xdb\xd6#n\xf1b\xc0\xe6\x8a\x15.\x18V'T\nP\x00\x00\u07d4'\x10\x1a\x0fV\u04da\x88\u0168O\x9b2L\xdd\xe3>\\\xb6\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x14L\xa9\xa7w\x1a\x83j\xd5\x0f\x80?d\xd8i\xb2\xae+ \x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4'\x14i\x13V:\xa7E\xe2X\x840\xd94\x8e\x86\xea|5\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4'\x1d=H\x1c\xb8\x8evq\xad!iI\xb66^\x060=\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4' \xf9\xcaBn\xf2\xf2\xcb\xd2\xfe\xcd9\x92\fO\x1a\x89\xe1m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'*\x13\x1aZejz:\xca5\u023d \"\"\xa7Y\"X\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4'D\xffgFA!\xe3Z\xfc)\"\x17qd\xfa/\xcb\x02g\x89\x05k\xc7^-c\x10\x00\x00\u07d4'J=w\x1a=p\x97\x96\xfb\xc4\xd5\xf4\x8f\xce/\xe3\x8cy\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4'Mi\x17\x0f\xe7\x14\x14\x01\x88+\x88j\xc4a\x8cj\xe4\x0e\u06c93\xc5I\x901r\f\x00\x00\u07d4'R\x1d\xeb;n\xf1An\xa4\u01c1\xa2\xe5\u05f3n\xe8\x1ca\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'Xu\xffO\xbb\f\xf3\xa40!1'H\u007fv\b\xd0L\xba\x89\x1b\x1c\x01\x0evmX\x00\x00\u07d4'j\x00n0(\xec\xd4L\xdbb\xba\nw\u0394\xeb\xd9\xf1\x0f\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4'k\x05!\xb0\xe6\x8b'}\xf0\xbb2\xf3\xfdH2cP\xbf\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4'o\xd7\xd2O\x8f\x88?Zz()[\xf1qQ\u01e8K\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'p\xf1N\xfb\x16]\u07bay\xc1\v\xb0\xaf1\xc3\x1eY3L\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4'vw\xab\xa1\xe5,;S\xbf\xa2\a\x1dN\x85\x9a\n\xf7\xe8\xe1\x8965\u026d\xc5\u07a0\x00\x00\u07d4'\x82Ff\xd2x\xd7\x04#\xf0=\xfe\x1d\u01e3\xf0/C\u2d4966\xc2^f\xec\xe7\x00\x00\u07d4'\x83\f_`#\xaf\xaa\xf7\x97Egl J\x0f\xac\u0360\xba\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94'\x84\x90?\x1d|\x1b\\\xd9\x01\xf8\x87]\x14\xa7\x9b<\xbe*V\x8a\x04\xbd\xa7\xe9\xd7J\xd5P\x00\x00\u07d4'\x8c\v\xdec\x0e\u00d3\xb1\xe7&\u007f\xc9\xd7\xd9p\x19\xe4\x14[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x98q\x10\"\x1a\x88\b&\xad\xb2\xe7\xab^\xcax\xc6\xe3\x1a\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94'\xac\a;\xe7\x9c\xe6W\xa9:\xa6\x93\xeeC\xbf\x0f\xa4\x1f\xef\x04\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4'\xb1iN\xaf\xa1e\xeb\xd7\xcc{\u025et\x81J\x95\x14\x19\u0709+^:\xf1k\x18\x80\x00\x00\u07d4'\xb6(\x16\xe1\xe3\xb8\u045by\xd1Q=]\xfa\x85[\f:*\x89\x05j\xf5\xc1\xfdiP\x80\x00\u07d4'\xbf\x94<\x163\xfe2\xf8\xbc\xcc\xdbc\x02\xb4\a\xa5rND\x892\xf8Lm\xf4\b\xc0\x80\x00\u07d4'\xbf\x9fD\xba}\x05\xc35@\u00e5;\xb0,\xbb\xff\xe7\xc3\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4'\xc2\xd7\xcaPM\xaa=\x90f\xdc\t\x13}\xc4/:\xaa\xb4R\x89 \x86\xac5\x10R`\x00\x00\u07d4'\xd1X\xac=>\x11\t\xabnW\x0e\x90\xe8]8\x92\xcdv\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4'\xe69\x89\xca\x1e\x90;\xc6 \xcf\x1b\x9c?g\xb9\xe2\xaee\x81\x89Hz\x9a0E9D\x00\x00\xe0\x94'\xf0<\xf1\xab\xc5\xe1\xb5\x1d\xbcDK(\x9eT,\x9d\u07f0\xe6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4'\xfc\x85\xa4\x9c\xff\x90\xdb\xcf\xda\u071d\xdd@\u05b9\xa2!\nl\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\x05A^\x1d\u007f\xde\xc6\xde\u07f8\x9eR\x1d\x10Y-t<\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\a>\xfc\x17\xd0\\\xab1\x95\xc2\xdb3+a\x98Gw\xa6\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x12P\xa2\x91!'\nN\xe5\u05cd$\xfe\xaf\xe8,p\xba:\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x13\xd2c\xfc_\xf2G\x9e\x97\x05\x95\u05b6\xb5`\xf8\xd6\xd6\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4(.\x80\xa5T\x87ZVy\x9f\xa0\xa9\u007fU\x10\u7557LN\x8965\u026d\xc5\u07a0\x00\x00\u07d4(3\x96\xce<\xac9\x8b\xcb\xe7\"\u007f2>x\xff\x96\u0407g\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4(4\x9f~\xf9t\xeaU\xfe6\xa1X;4\xce\xc3\xc4Pe\xf0\x89\f\xb63\u051eeY\x00\x00\u07d4(6\x120F\xb2\x84\xe5\xef\x10+\xfd\"\xb1v^P\x81\x16\xad\x89\x16S\xfb\xb5\xc4'\xe4\x00\x00\u07d4(<#\x14(<\x92\u0530d\xf0\xae\xf9\xbbRF\xa7\x00\u007f9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(>\x11 7I\xb1\xfaO2\xfe\xbbq\xe4\x9d\x13Y\x198*\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(>bR\xb4\xef\xcfFT9\x1a\xcbu\xf9\x03\u015bx\xc5\xfb\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94(Q\x0en\xff\x1f\xc8)\xb6WoC(\xbc98\xecze\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4(X\xac\xac\xaf!\xea\x81\u02b7Y\x8f\xdb\xd8kE.\x9e\x8e\x15\x89$\x1a\x9bOaz(\x00\x00\u07d4(Z\xe5\x1b\x95\x00\u014dT\x13e\xd9ui\xf1K\xb2\xa3p\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(f\xb8\x1d\xec\xb0.\xe7\n\xe2P\xce\xe5\xcd\xc7{Y\u05f6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(i\x06\xb6\xbdIr\xe3\xc7\x16U\xe0K\xaf6&\f|\xb1S\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4(k\x18ma\xea\x1f\u05cd\x990\xfe\x12\xb0e7\xb0\\=Q\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(t\xf3\xe2\x98]_{@f'\xe1{\xaaw+\x01\xab\u031e\x8a\x01F\x05\x04\x10v_8\x00\x00\xe0\x94(|\xf9\u0410.\xf8\x19\xa7\xa5\xf1ID[\xf1w^\xe8\xc4|\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4(\x81\x8e\x18\xb6\x10\x00\x13!\xb3\x1d\xf6\xfe}(\x15\u036d\xc9\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x86\x83$3~\x11\xba\x10l\xb4\x81\u0696/:\x84S\x80\x8d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94(\x90K\xb7\xc40)C\xb7\t\xb1Myp\xe4+\x83$\u184a\x02\x1f\x97\x84j\a-~\x00\x00\u07d4(\x95\xe8\t\x99\xd4\x06\xadY.+&'7\xd3_}\xb4\xb6\x99\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4(\x96r\x80!N!\x8a\x12\f]\xda7\x04\x1b\x11\x1e\xa3mt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(\xa3\xda\t\xa8\x19H\x19\xae\x19\x9f.m\x9d\x13\x04\x81~(\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(\xab\x16_\xfbi\xed\xa0\xc5I\xae8\xe9\x82o_\u007f\x92\xf8S\x89FM\xf6\xd7\xc8DY\x00\x00\u07d4(\xb7u\x85\xcb=U\xa1\x99\xab)\x1d:\x18\u018f\u8684\x8a\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94(\xd4\xeb\xf4\x1e=\x95\xf9\xbb\x9a\x89u#\\\x1d\x009>\x80\x00\u07d4)\nV\xd4\x1fn\x9e\xfb\xdc\xea\x03B\u0dd2\x9a\x8c\xdf\xcb\x05\x89\x12\xa5\xf5\x81h\xee`\x00\x00\u07d4)\x15bK\xcbg\x917\xb8\xda\xe9\xabW\xd1\x1bI\x05\xea\xeeK\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4)\x1e\xfe\x00\x81\xdc\xe8\xc1G\x99\xf7\xb2\xa46\x19\xc0\u00f3\xfc\x1f\x89A\rXj \xa4\xc0\x00\x00\u07d4)\x1f\x92\x9c\xa5\x9bT\xf8D>=Mu\xd9]\xee$<\xefx\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x94))\x8c\xcb\xdf\xf6\x89\xf8\u007f\xe4\x1a\xa6\xe9\x8f\u07f5=\xea\xf3z\x8a\x041\\2\xd7\x1a\x9e`\x00\x00\u07d4)/\"\x8b\n\x94t\x8c\x8e\xeca-$o\x98\x93c\xe0\x8f\b\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4)3\x84\xc4+o\x8f)\x05\xceR\xb7 \\\"t7la+\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4)4\xc0\xdf{\xbc\x17+l\x18k\vrTz\u038b\xf7TT\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4)<#\x06\xdf6\x04\xaeO\xda\r z\xbasog\xde\a\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)I\xfd\x1d\xef\\v\xa2\x86\xb3\x87$$\x80\x9a\a\xdb9f\xf3\x8a\x01\x1b\xd9\x06\u06a0\xc9C\x80\x00\u07d4)OIK?.\x14\xa3\xf8\xab\x00\x00\x00\u07d4)U\xc3W\xfd\x8fu\xd5\x15\x9a=\xfai\u0178z5\x9d\ua309lk\x93[\x8b\xbd@\x00\x00\u07d4)a\xfb9\x1ca\x95|\xb5\xc9\xe4\a\u0762\x938\u04f9,\x80\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4)h\x1d\x99\x12\xdd\xd0~\xaa\xbb\x88\xd0]\x90\xf7f\xe8bA}\x8965\u026d\xc5\u07a0\x00\x00\u07d4)kq\xc0\x01X\x19\xc2B\xa7\x86\x1eo\xf7\xed\xed\x8a_q\xe3\x89lh\xcc\u041b\x02,\x00\x00\u07d4)mf\xb5!W\x1aNA\x03\xa7\xf5b\xc5\x11\xe6\xaas-\x81\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4)o\x00\xde\x1d\u00fb\x01\xd4z\x8c\xcd\x1e]\x1d\u0661\xebw\x91\x8965\u026d\xc5\u07a0\x00\x00\u07d4)s\x85\xe8\x864FV\x85\xc21\xa3\x14\xa0\xd5\xdc\xd1F\xaf\x01\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4)v=\xd6\u069a|\x16\x11s\x88\x83!\ub9b6<\x8f\xb8E\x89\x11\xc7\xea\x16.x \x00\x00\u07d4)yt\x11t\xa8\xc1\xea\v\u007f\x9e\xdfe\x81w\x85\x94\x17\xf5\x12\x89\x19\x01\x96l\x84\x96\x83\x80\x00\u07d4)z\x88\x92\x1b_\xca\x10\u5edd\xed`\x02T7\xae\"\x16\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)}]\xbe\"//\xb5%1\xac\xbd\v\x01=\xc4F\xacsh\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\x82N\x94\xccCH\xbc\x962y\xdc\xdfG9\x17\x152L\u04c9i*\xe8\x89p\x81\xd0\x00\x00\u07d4)\x82\xd7j\x15\xf8G\xddA\xf1\x92*\xf3h\xfeg\x8d\x0eh\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\x88\x87\xba\xb5|[\xa4\xf0aR)\xd7R_\xa1\x13\xb7\ua249\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94)\x8e\xc7kD\r\x88\a\xb3\xf7\x8b_\x90\x97\x9b\xeeB\xedC\u06ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4)\x93h`\x90B\xa8X\xd1\xec\xdf\x1f\xc0\xad\xa5\xea\xce\xca)\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4)\x9e\v\xcaU\xe0i\u0785\x04\xe8\x9a\xcan\xca!\u04ca\x9a]\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4)\xac+E\x84T\xa3l~\x96\xc7:\x86g\"*\x12$,q\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xad\u03c3\xb6\xb2\n\u01a44\xab\xb1\x99<\xbd\x05\xc6\x0e\xa2\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94)\xae\xf4\x8d\xe8\xc9\xfb\xadK\x9eL\xa9pyzU3\xebr-\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4)\xb3\xf5a\xeezn%\x94\x1e\x98\xa52[x\xad\u01d7\x85\xf3\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\xbd\xc4\xf2\x8d\xe0\x18\x0fC<&\x94\xebt\xf5PL\xe9C7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\u0300M\x92+\xe9\x1fY\t\xf3H\xb0\xaa\xa5\xd2\x1b`x0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xda>5\xb2;\xb1\xf7/\x8e\"X\xcf\u007fU3Y\xd2K\xac\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94)\xe6y\x90\xe1\xb6\xd5.\x10U\xff\xe0I\xc51\x95\xa8\x15B\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\uab82v\x17b\xf4\xd2\xdbS\xa9\u018b\x0fk\vmNf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\xeb~\xef\xda\xe9\xfe\xb4I\xc6?\xf5\xf2y\xd6u\x10\xeb\x14\"\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4)\xf0\xed\xc6\x038\xe7\x11 \x85\xa1\xd1\x14\u068cB\u038fU\u0589\xa0Z\u007f\x0f\xd8%x\x00\x00\u07d4)\xf8\xfb\xa4\xc3\ar\xb0W\xed\xbb\xe6*\xe7B\f9\x05r\xe1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94)\xf9(l\x0es\x8d\x17!\xa6\x91\u01b9Z\xb3\u0667\x97\xed\xe8\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4*\b^%\xb6Hb\xf5\xe6\x8dv\x8e+\x0fz\x85)\x85\x8e\xee\x89k\x88:\xcdWf\xcd\x00\x00\u07d4**\xb6\xb7Lz\xf1\xd9Gk\xb5\xbc\xb4RG\x97\xbe\xdc5R\x8965\u026d\xc5\u07a0\x00\x00\u07d4*9\x19\nO\u0783\u07f3\xdd\xcbL_\xbb\x83\xaclIu\\\x8965\u026d\xc5\u07a0\x00\x00\u07d4*@\r\xff\x85\x94\xder(\xb4\xfd\x15\xc3#\"\xb7[\xb8}\xa8\x89\x051\xa1\u007f`z-\x00\x00\xe0\x94*D\xa7!\x8f\xe4Me\xa1\xb4\xb7\xa7\u0671\xc2\xc5,\x8c>4\x8a\r-\x06\xc3\x05\xa1\xebW\x80\x00\u07d4*F\xd3Swqv\xff\x8e\x83\xff\xa8\x00\x1fOp\xf9s:\xa5\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4*Y_\x16\xee\xe4\xcb\f\x17\u0662\xd99\xb3\xc1\x0flgrC\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4*Y\xe4~\xa5\xd8\xf0\xe7\xc0(\xa3\xe8\xe0\x93\xa4\x9c\x1bP\xb9\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*[\xa9\xe3L\u054d\xa5L\x9a'\x12f:;\xe2t\xc8\xe4{\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94*^:@\xd2\xcd\x03%vm\xe7:=g\x18\x96\xb3b\xc7;\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94*cY\x0e\xfe\x99\x86\xc3\xfe\xe0\x9b\n\n3\x8b\x15\xbe\xd9\x1f!\x8a\x01^\x1cN\x05\xee&\xd0\x00\x00\u07d4*gf\n\x13h\xef\xcdbn\xf3k+\x1b`\x19\x80\x94\x1c\x05\x89\a?u\u0460\x85\xba\x00\x00\u07d4*t+\x89\x10\x94\x1e\t2\x83\n\x1d\x96\x92\xcf\u0484\x94\xcf@\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4*tl\xd4@'\xaf>\xbd7\xc3x\xc8^\xf7\xf7T\xab_(\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4*\x81\xd2|\xb6\xd4w\x0f\xf4\xf3\u0123\xba\x18\xe5\xe5\u007f\aQ|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*\x91\xa9\xfe\xd4\x1b}\x0e\\\xd2\xd81X\xd3\xe8\xa4\x1a\x9a-q\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94*\x9cW\xfe{k\x13\x8a\x92\rgo{\x1a%\x10\x80\xff\xb9\x8a4\xf0\x86\xf3\xb3;h@\x00\x00\u07d4+p\x1d\x16\xc0\xd3\xcc\x1eL\xd8TE\xe6\xad\x02\ue92c\x01-\x89 \x86\xac5\x10R`\x00\x00\xe0\x94+q|\xd42\xa3#\xa4e\x909\x84\x8d;\x87\xde&\xfc\x95F\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4+t\xc3s\xd0K\xfb\x0f\xd6\n\x18\xa0\x1a\x88\xfb\xe8Gp\u5309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4+w\xa4\u060c\rV\xa3\xdb\xe3\xba\xe0J\x05\xf4\xfc\u0477W\xe1\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94+\x84\x88\xbd-<\x19z=&\x15\x18\x15\xb5\xa7\x98\xd2qh\u070a\x01j\x1f\x9f_\xd7\xd9`\x00\x00\u07d4+\x8a\r\xee\\\xb0\xe1\xe9~\x15\xcf\xcan\x19\xad!\xf9\x95\ufb49\x1bUC\x8d\x9a$\x9b\x00\x00\xe0\x94+\x8f\xe4\x16n#\xd1\x19c\xc0\x93+\x8a\u078e\x01E\xea\ap\x8a\t(\x96R\x9b\xad\u0708\x00\x00\xe0\x94+\x99\xb4.OBa\x9e\xe3k\xaa~J\xf2\xd6^\xac\xfc\xba5\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4+\xab\x0f\xbe(\u0544 \xb5 6w\n\x12\xf9\x95*\xeai\x11\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4+\xad\xe9\x1d\x15E\x17b\x0f\u05349\xac\x97\x15zA\x02\xa9\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4+\xaf\x8dn\"\x11t\x12H \xeeI+\x94Y\xecO\xad\xaf\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xaf\xbf\x9e\x9e\xd2\xc2\x19\xf7\xf2y\x13t\xe7\xd0\\\xb0gw\xe7\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94+\xb3f\xb9\xed\xcb\r\xa6\x80\xf0\xe1\v;n(t\x81\x90\xd6\u00ca\x01:b\u05f5v@d\x00\x00\xe0\x94+\xb6\xf5x\xad\xfb\u7ca1\x16\xb3UO\xac\xf9\x96\x98\x13\xc3\x19\x8a\x01\x91'\xa19\x1e\xa2\xa0\x00\x00\u07d4+\xbeb\xea\xc8\f\xa7\xf4\xd6\xfd\xee~}\x8e(\xb6:\xcfw\x0e\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4+\xbeg*\x18WP\x8fc\x0f*^\xdbV=\x9e\x9d\xe9(\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xc4)\xd6\x18\xa6jL\xf8-\xbb-\x82N\x93V\xef\xfa\x12j\x89lj\xccg\u05f1\xd4\x00\x00\u07d4+\xd2R\xe0\xd72\xff\x1d|x\xf0\xa0.l\xb2T#\xcf\x1b\x1a\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4+\xdd\x03\xbe\xbb\xee';l\xa1\x05\x9b4\x99\x9a[\xbda\xbby\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\x04\x11\\>R\x96\x1b\r\xc0\xb0\xbf1\xfb\xa4ToYf\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94,\x06\u0752+aQJ\xaf\xed\xd8D\x88\xc0\u008em\xcf\x0e\x99\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94,\f\xc3\xf9QH,\u0222\x92X\x15hN\xb9\xf9N\x06\x02\x00\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4,\x0e\xe14\u0633aE\xb4{\xee\u7bcd'8\xdb\xda\b\xe8\x89\n\xe5os\x0em\x84\x00\x00\u07d4,\x0f[\x9d\xf46%y\x8e~\x03\xc1\xa5\xfdjm\t\x1a\xf8+\x89\x01\xb0\xfc\xaa\xb2\x000\x00\x00\u07d4,\x12\x8c\x95\xd9W!Q\x01\xf0C\u074f\u0142EmA\x01m\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4,\x18\x00\xf3_\xa0->\xb6\xff[%(_^J\xdd\x13\xb3\x8d\x891\"\u04ed\xaf\xde\x10\x00\x00\u07d4,\x1c\x19\x11N=m\xe2xQHK\x8d'\x15\xe5\x0f\x8a\x10e\x89\x05k\xc7^-c\x10\x00\x00\u07d4,\x1c\xc6\xe1\x8c\x15$\x88\xba\x11\xc2\xcc\x1b\xce\xfa-\xf3\x06\xab\u0449Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94,\x1d\xf8\xa7oH\xf6\xb5K\u03dc\xafV\xf0\xee\x1c\xf5z\xb3=\x8a\x02$\u007fu\x00\x89\xdaX\x00\x00\u07d4,!G\x94z\xe3?\xb0\x98\xb4\x89\xa5\xc1k\xff\xf9\xab\xcdN*\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,#OP\\\xa8\xdc\xc7}\x9b~\x01\xd2W\xc3\x18\xcc\x199m\x89\x05k\xc7^-c\x10\x00\x00\u07d4,$(\xe4\xa6it\xed\xc8\"\xd5\xdb\xfb$\x1b'(\aQX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,-\x15\xff9V\x1c\x1br\xed\xa1\xcc\x02\u007f\xfe\xf27C\xa1D\x89\u0500\xed\x9e\xf3+@\x00\x00\u07d4,-\xb2\x8c3\t7^\xea1\x82\x1b\x84\xd4\b\x93\x0e\xfa\x1a\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4,Z-\n\xbd\xa0;\xbe!W\x81\xb4\xff)l\x8ca\xbd\xba\xf6\x89\x01\xa8\xe5oH\xc0\"\x80\x00\u07d4,[}{\x19Z7\x1b\xf9\xab\u0774/\xe0O/\x1d\x9a\x99\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,]\xf8ffj\x19K&\u03bb@~J\x1f\xd7> \x8d^\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94,`?\xf0\xfe\x93alCW>\xf2y\xbf\xea@\x88\x8dj\xe7\x8a\x01\x00\xf4\xb6\xd6gW\x90\x00\x00\xe0\x94,hF\xa1\xaa\x99\x9a\"F\xa2\x87\x05`\x00\xbaM\u02e8\xe6=\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\u0794,j\xfc\xd4\x03|\x1e\xd1O\xa7O\xf6u\x8e\tE\xa1\x85\xa8\xe8\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4,ki\x9d\x9e\xad4\x9f\x06\u007fEq\x1a\aJd\x1d\xb6\xa8\x97\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,o\\\x12L\u01c9\xf8\xbb9\x8e?\x88\x97Q\xbcK`-\x9e\x89\x01Y\xf2\v\xed\x00\xf0\x00\x00\u07d4,\x83\xae\xb0/\xcf\x06}e\xa4p\x82\xfd\x97x3\xab\x1c\uc449\b'8#%\x8a\xc0\x00\x00\xe0\x94,\x89\xf5\xfd\xca=\x15T\t\xb68\xb9\x8at.U\xebFR\xb7\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4,\x96HI\xb1\xf6\x9c\xc7\u03a4D%8\xed\x87\xfd\xf1l\xfc\x8f\x89lk\x93[\x8b\xbd@\x00\x00\u0794,\x9f\xa7,\x95\xf3}\b\xe9\xa3`\t\u7930\u007f)\xba\xd4\x1a\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4,\xafk\xf4\xec}Z\x19\xc5\xe0\x89z^\xeb\x01\x1d\xce\xceB\x10\x89\a\x93H5\xa01\x16\x00\x00\u07d4,\xb4\xc3\xc1k\xb1\xc5^|kz\x19\xb1'\xa1\xac\x93\x90\xcc\t\x89\xb8'\x94\xa9$O\f\x80\x00\xe0\x94,\xb5IZPS6\xc2FT\x10\xd1\xca\xe0\x95\xb8\xe1\xba\\\u074a\x04<3\xc1\x93ud\x80\x00\x00\u07d4,\xb6\x15\a:@\xdc\u06d9\xfa\xa8HW.\x98{;\x05n\xfb\x89+X\xad\u06c9\xa2X\x00\x00\u07d4,\xbam]\r\xc2\x04\xea\x8a%\xad\xa2\xe2oVu\xbd_/\u0709H#\xef}\u06da\xf3\x80\x00\u07d4,\xbb\fs\u07d1\xb9\x17@\xb6i;wJ}\x05\x17~\x8eX\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4,\xcbfIM\n\xf6\x89\xab\xf9H=6]x$D\xe7\u07ad\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\xcc\x1f\x1c\xb5\xf4\xa8\x00.\x18k \x88]\x9d\xbc\x03\f\b\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u03c0\xe2\x18\x98\x12^\xb4\xe8\a\u0342\xe0\x9b\x9d(Y/n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u0456\x94\u0452j\x0f\xa9\x18\x9e\u07ba\xfcg\x1c\xf1\xb2\u02a5\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\u04d34\xac~\xacyrW\xab\xe3sa\x95\xf5\xb4\xb5\xce\x0f\x89\x05kGx^7&\x00\x00\u07d4,\u05de\xb5 '\xb1,\x18\x82\x8e>\xaa\xb2\x96\x9b\xfc\u0487\xe9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\xd8xfV\x8d\xd8\x1a\xd4}\x9d:\u0404nZePss\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4,\xdb9De\x06\x16\xe4|\xb1\x82\xe0`2/\xa1Hyx\u0389b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4,\xe1\x1a\x92\xfa\xd0$\xff+>\x87\xe3\xb5B\xe6\xc6\r\xcb\u0656\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4-\x03&\xb2?\x04\t\xc0\xc0\xe9#hc\xa13\aZ\x94\xba\x18\x89\vg\x9b\xe7[\xe6\xae\x00\x00\u07d4-\r\xecQ\xa6\xe8s0\xa6\xa8\xfa*\x0fe\u060dJ\xbc\xdfs\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4-#vkok\x05s}\xad\x80\xa4\x19\xc4\x0e\xdaMw\x10>\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4-+\x03#Y\xb3c\x96O\xc1\x1aQ\x82c\xbf\xd0T1\xe8g\x89\b\x1c\x1d\xf7b\x9ep\x00\x00\u07d4-4\x80\xbf\be\aJr\xc7u\x9e\xe5\x13{Mp\xc5\x1c\xe9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-5\xa9\xdfbu\u007f\u007f\xfa\xd1\x04\x9a\xfb\x06\xcaJ\xfcFLQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-@U\x8b\x06\xf9\n9#\x14U\x92\x12;gt\xe4n1\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4-Bi\x12\xd0Y\xfa\xd9t\v.9\n.\xea\xc0To\xf0\x1b\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4-S-\xf4\xc69\x11\xd1\u0391\xf6\xd1\xfc\xbf\xf7\x96\x0fx\xa8\x85\x89Z\x85\x96\x8aXx\u0680\x00\u07d4-S\x91\xe98\xb3HX\u03d6[\x84\x051\xd5\xef\xdaA\v\t\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94-[B\xfcY\xeb\xda\r\xfdf\xae\x91K\u008c\x1b\nn\xf8:\x8a+\u0235\x9f\xdc\xd86c\x80\x00\u07d4-]s5\xac\xb06+G\u07e3\xa8\xa4\xd3\xf5\x94\x95D\u04c0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-a\xbf\xc5hs\x92<+\x00\t]\xc3\xea\xa0\xf5\x90\u062e\x0f\x8a\x04ef\xdf\xf8\xceU`\x00\x00\u07d4-e\x11\xfdz8\x00\xb2hT\xc7\xec9\xc0\u0735\xf4\xc4\xe8\xe8\x89\x15\xad\u077a/\x9ew\x00\x00\u07d4-}\\@\u076f\xc4P\xb0Jt\xa4\u06bc+\xb5\xd6e\x00.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\x89\xa8\x00jO\x13z \xdc+\xecF\xfe.\xb3\x12\xea\x96T\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-\x8cR2\x9f8\u04a2\xfa\x9c\xba\xf5\u0143\xda\xf1I\v\xb1\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-\x8e\x06\x18\x92\xa5\xdc\xce!\x96j\xe1\xbb\a\x88\xfd>\x8b\xa0Y\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4-\x8e[\xb8\xd3R\x16\x95\xc7~|\x83N\x02\x91\xbf\xac\xeet\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4-\x90\xb4\x15\xa3\x8e.\x19\xcd\xd0/\U000ed069z\xf7\xcb\xf6r\x89\x05\xf3\xc7\xf6A1\xe4\x00\x00\u07d4-\x9b\xado\x1e\xe0*p\xf1\xf1=\xef\\\u0332z\x9a'@1\x89a\t=|,m8\x00\x00\u07d4-\x9c_\xec\u04b4O\xbbj\x1e\xc72\xea\x05\x9fO\x1f\x9d+\\\x896\xca2f\x1d\x1a\xa7\x00\x00\xe0\x94-\xa6\x17iP\t\xccW\xd2j\u0510\xb3*]\xfb\xeb\x93N^\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4-\xa7k|9\xb4 \u323a,\x10 \xb0\x85k\x02pd\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\u01ddn\u007fU\xbc\xe2\xe2\xd0\xc0*\xd0|\uca3bR\x93T\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94-\xca\x0eD\x9a\xb6F\xdb\xdf\u04d3\xa9fb\x96\v\u02b5\xae\x1e\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4-\xd3%\xfd\xff\xb9{\x19\x99R\x84\xaf\xa5\xab\xdbWJ\x1d\xf1j\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4-\xd5x\xf7@}\xfb\xd5H\xd0^\x95\xcc\u00dcHT)bj\x89\u3bb5sr@\xa0\x00\x00\u07d4-\xd8\xee\xef\x87\x19J\xbc,\xe7X]\xa1\xe3[|\xeax\f\xb7\x8965\xc6 G9\u0640\x00\u07d4-\xdf@\x90Wi\xbc\xc4&\xcb,)8\xff\xe0w\xe1\u8758\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4-\xe0\x96D\x00\u0082\xbd\u05ca\x91\x9ck\xf7|k_yay\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\xe3\x1a\xfd\x18\x9a\x13\xa7o\xf6\xfes\xea\xd9\xf7K\xb5\u0126)\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4-\xec\x982\x9d\x1f\x96\u00e5\x9c\xaay\x81uTR\xd4\xdaI\u0549\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\ue422\x8f\x19-gj\x87s#+V\xf1\x8f#\x9e/\xad\x8a\x03\xef\xa7\xe7G\xb6\u046d\x00\x00\xe0\x94.\b\x80\xa3E\x96#\a \xf0Z\xc8\xf0e\xaf\x86\x81\u0736\u008a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4.\fW\xb4qP\xf9Z\xa6\xa7\xe1j\xb9\xb1\xcb\xf5C(\x97\x9a\x89\x05k\xc7^-c\x10\x00\x00\u07d4.\x10\x91\v\xa6\xe0\xbc\x17\xe0UUf\x14\u02c7\t\x0fM~[\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94.$\xb5\x97\x87;\xb1A\xbd\xb27\xea\x8aZ\xb7Gy\x9a\xf0-\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.(\x10\xde\xe4J\xe4\xdf\xf3\xd8cB\xab\x12fW\xd6S\xc36\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.,\xbdz\xd8%G\xb4\xf5\xff\x8b:\xb5o\x94*dE\xa3\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.-~\xa6k\x9fG\xd8\xccR\xc0\x1cR\xb6\u147c}G\x86\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4.C\x93H\u07caBw\xb2*v\x84W\xd1\x15\x8e\x97\xc4\t\x04\x89*\x1e\x9f\xf2o\xbfA\x00\x00\xe0\x94.F\xfc\xeej;\xb1E\xb5\x94\xa2C\xa3\x91?\xce]\xado\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794.G\xf2\x87\xf4\x98#7\x13\x85\r1&\x82<\xc6}\xce\xe2U\x88\u029d\x9e\xa5X\xb4\x00\x00\u07d4.N\u1b99j\xa0\xa1\xd9$(\xd0fR\xa6\xbe\xa6\xd2\xd1]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.R\x91+\xc1\x0e\xa3\x9dT\xe2\x93\xf7\xae\u05b9\x9a\x0fLs\xbe\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4.a\x9fW\xab\xc1\u91ea\x93j\xe3\xa2&Ib\xe7\xeb-\x9a\x89(\xfb\x9b\x8a\x8aSP\x00\x00\u07d4.d\xa8\xd7\x11\x11\xa2/L]\xe1\xe09\xb36\xf6\x8d9\x8a|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.i3T=O,\xc0\vSP\xbd\x80h\xba\x92C\u05be\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94.~\x05\xe2\x9e\u0767\xe4\xae%\xc5\x175C\xef\xd7\x1fm=\x80\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4.\u007fFU \xec5\xcc#\u058eue\x1b\xb6h\x95D\xa1\x96\x898\xec[r\x1a\x1a&\x80\x00\u07d4.\x8e\xb3\nqn_\xe1\\t#>\x03\x9b\xfb\x11\x06\xe8\x1d\x12\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94.\x98$\xb5\xc12\x11\x1b\xca$\xdd\xfb\xa7\xe5u\xa5\xcdr\x96\xc1\x8a\x03\xa4\x84Qnm\u007f\xfe\x00\x00\u07d4.\xa5\xfe\xe6?3z7nK\x91\x8e\xa8!H\xf9MH\xa6&\x89e\x0f\x8e\r\u0493\xc5\x00\x00\u07d4.\xafN*F\xb7\x89\xcc\u0088\xc8\xd1\xd9)N?\xb0\x858\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.\xaf\xf9\xf8\xf8\x110d\u04d5z\xc6\xd6\xe1\x1e\xeeB\xc8\x19]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4.\xba\fn\xe5\xa1\x14\\\x1cW9\x84\x96:`]\x88\nz \x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4.\xc9X\"\xeb\x88{\xc1\x13\xb4q*M\xfd\u007f\x13\xb0\x97\xb5\xe7\x8965\u026d\xc5\u07a0\x00\x00\u07d4.\xcaj<]\x9fD\x9d\tV\xbdC\xfa{M{\xe8CYX\x89lk\xdaip\x9c\xc2\x00\x00\xe0\x94.\xca\xc5\x04\xb23\x86n\xb5\xa4\xa9\x9e{\u0490\x13Y\xe4;=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.\xeb\xf5\x942\xb5(\x92\xf98\v\xd1@\xaa\x99\xdc\xf8\xad\f\x0f\x89\b=lz\xabc`\x00\x00\u07d4.\xee\xd5\x04q\xa1\xa2\xbfS\xee0\xb1#.n\x9d\x80\xef\x86m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4.\xefk\x14\x17\u05f1\x0e\xcf\xc1\x9b\x12:\x8a\x89\xe7>RlX\x89 \x86\xac5\x10R`\x00\x00\u07d4.\xf8i\xf05\vW\xd54x\xd7\x01\xe3\xfe\xe5)\xbc\x91\x1cu\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4.\xf9\xe4eqj\xca\u03f8\xc8%/\xa8\xe7\xbcyi\xeb\xf6\u4255\x9e\xb1\xc0\xe4\xae \x00\x00\xe0\x94.\xfcLd}\xacj\xca\xc3Uw\xad\"\x17X\xfe\xf6ao\xaa\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4/\x13eu&\xb1w\xca\xd5G\u00d0\x8c\x84\x0e\xffd{E\u0649?v\x84\x9c\xf1\xee,\x80\x00\u07d4/\x18}ZpMZ3\x8c[(v\xa0\x90\xdc\xe9d(N)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94/%#\u0303O\x00\x86\x05$\x02bb\x96gQ\x86\xa8\u508a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4/(*\xbb\xb6\u0523\xc3\xcd;\\\xa8\x12\xf7d>\x800_\x06\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4/+\xba\x1b\x17\x96\x82\x1avo\xced\xb8O(\xech\xf1Z\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4/1]\x90\x16\xe8\xee_Sf\x81 /\x90\x84\xb02TMM\x898<\xd1+\x9e\x86<\x00\x00\u07d4/M\xa7SC\x0f\xc0\x9es\xac\xbc\xcd\xcd\xe9\xdad\u007f+]7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/P\x80\xb8?~-\xc0\xa1\xdd\x11\xb0\x92\xad\x04+\xffx\x8fL\x89\xb4\xf8\xfby#\x1d+\x80\x00\u07d4/a\uf941\x9dp_+\x1eN\xe7T\xae\xb8\xa8\x19Pju\x89O%\x91\xf8\x96\xa6P\x00\x00\xe0\x94/f\xbf\xbf\"b\xef\u030d+\xd0DO\u0170ib\x98\xff\x1e\x8a\x02\x1a\xd95\xf7\x9fv\xd0\x00\x00\u07d4/m\xce\x130\u015e\xf9!`!TW-MK\xac\xbd\x04\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4/}2\x90\x85\x1b\xe5\u01b4\xb4?}Et2\x9fa\xa7\x92\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4/\x858\x17\xaf\u04f8\xf3\xb8n\x9f`\xeew\xb5\xd9ws\xc0\xe3\x89N\xae\xeaD\xe3h\xb9\x00\x00\u07d4/\xa4\x91\xfbY \xa6WN\xbd(\x9f9\xc1\xb2C\r-\x9aj\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xb5f\xc9K\xbb\xa4\xe3\xcbg\xcd\xda}_\xadq1S\x91\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xbbPJ]\xc5'\xd3\xe3\xeb\x00\x85\xe2\xfc<}\xd58\xcbz\x89C\u00b1\x8a\xec<\n\x80\x00\u07d4/\xbc\x85y\x8aX5\x98\xb5\"\x16mn\x9d\xda\x12\x1db}\xbc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/\xbc\xef3\x84\xd4 \xe4\xbfa\xa0f\x99\x90\xbcpT\U00065bc9lk\x93[\x8b\xbd@\x00\x00\xe0\x94/\xc8.\xf0v\x93#A&Oaz\f\x80\xddW\x1ej\xe99\x8a\x01\x84$\xf5\xf0\xb1\xb4\xe0\x00\x00\u07d4/\u075by\u07cd\xf50\xadc\xc2\x0eb\xafC\x1a\xe9\x92\x16\xb8\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4/\xe0\x02?W\"e\x0f:\x8a\xc0\x10\t\x12^t\xe3\xf8.\x9b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4/\xe0\xccBKS\xa3\x1f\t\x16\xbe\b\xec\x81\xc5\v\xf8\xea\xb0\xc1\x89 \x86\xac5\x10R`\x00\x00\u07d4/\xe1:\x8d\a\x85\u0787X\xa5\xe4\x18v\xc3n\x91l\xf7Pt\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4/\xea\x1b/\x83O\x02\xfcT3?\x8a\x80\x9f\x048\xe5\x87\n\xa9\x89\x01\x18T\xd0\xf9\xce\xe4\x00\x00\u07d4/\xee6\xa4\x9e\xe5\x0e\xcfqo\x10G\x91VFw\x9f\x8b\xa0?\x899B\"\xc4\u0686\xd7\x00\x00\u07d4/\xef\x81G\x8aK.\x80\x98\xdb_\xf3\x87\xba!S\xf4\xe2+y\x896'\xe8\xf7\x127<\x00\x00\u07d4/\xf1`\xc4Or\xa2\x99\xb5\xec-q\xe2\x8c\xe5Dm/\u02ef\x89\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4/\xf1\xcaU\xfd\x9c\xec\x1b\x1f\xe9\U00029af7LQ<\x1e*\xaa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94/\xf5\u02b1,\r\x95\u007f\xd33\xf3\x82\xee\xb7Q\a\xa6L\xb8\xe8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94/\xf80\xcfU\xfb\x00\u0560\xe05\x14\xfe\xcdD1K\xd6\xd9\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4/\xfe\x93\xec\x1aV6\xe9\xee4\xafp\xdf\xf5&\x82\xe6\xffpy\x89lk\x93[\x8b\xbd@\x00\x00\u07d40\x03y\x88p&q\xac\xbe\x89,\x03\xfeW\x88\xaa\x98\xaf(z\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d40$\x8dX\xe4\x14\xb2\x0f\xed:lH+Y\xd9\xd8\xf5\xa4\xb7\xe2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4019\xbcYd\x03\xd5\u04d3\x1fwLf\u013aFtT\u06c9\\%\xe1J\xea(?\x00\x00\u079408\x00\x87xie\x14\x9e\x81B;\x15\xe3\x13\xba2\xc5\u01c3\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d40:0\xacB\x86\xae\x17\xcfH=\xad{\x87\fk\xd6M{J\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40?\xba\xeb\xbeF\xb3[n[t\x94j_\x99\xbc\x15\x85\xca\xe7\x89/\x9a\xc0i_[\xba\x00\x00\u07d40ADZ3\xba\x15\x87A\x16\r\x9c4N\xb8\x8e\\0o\x94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d40H\x01d\xbc\xd8It\xeb\xc0\xd9\f\x9b\x9a\xfa\xb6&\xcd\x1cs\x89+^:\xf1k\x18\x80\x00\x00\u07d40N\u019atTW!\xd71j\xefM\u03f4\x1a\u015e\xe2\xf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x940Q\x182\x91\x8d\x804\xa7\xbe\xe7.\xf2\xbf\xeeD\x0e\u02fc\xf6\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d40Q?\u029f6\xfdx\x8c\xfe\xa7\xa3@\xe8m\xf9\x82\x94\xa2D\x89\x18;_\x03\xb1G\x9c\x00\x00\u07d40U\xef\xd2`)\xe0\xd1\x1b\x93\r\xf4\xf5;\x16,\x8c?\xd2\u0389\x1b\x1a\b\x927\a=\x00\x00\u07d40]&\xc1\v\xdc\x10?k\x9c!'.\xb7\xcb-\x91\b\xc4~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40_x\xd6\x18\xb9\x90\xb4)[\xac\x8a-\xfa&(\x84\xf8\x04\xea\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x940d\x89\x9a\x96\x1a>\x1d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d40\x98\xb6]\xb9>\xca\xca\xf75\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d40\uc4d2$J!\b\u0247\xbc\\\xdd\xe0\ud7c3z\x81{\x89T\x99%\xf6\xc9\xc5%\x00\x00\xe0\x940\xed\x11\xb7{\xc1~^f\x94\u023c[nG\x98\xf6\x8d\x9c\xa7\x8a\x1eo\xb3B\x1f\xe0)\x9e\x00\x00\u07d40\xf7\xd0%\xd1o{\xee\x10U\x80Ho\x9fV\x1c{\xae?\xef\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x940\xfb\xe5\x88_\x9f\xcc\xe9\xea^\u06c2\xedJ\x11\x96\xdd%\x9a\xed\x8a\x01\x19\xe4\u007f!8\x1f@\x00\x00\u07d41\x04}p?c\xb94$\xfb\xbdn/\x1f\x9et\xde\x13\xe7\t\x89\x9a\x81f\xf7\u6ca7\x80\x00\u07d411?\xfdc[\xf2\xf32HA\xa8\x8c\a\xed\x14aD\xce\xeb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d41Y\xe9\fH\xa9\x15\x90J\xdf\u24b2/\xa5\xfd^ryk\x896\xaf\xe9\x8f&\x06\x10\x00\x00\u07d41]\xb7C\x9f\xa1\u0574#\xaf\xa7\xddq\x98\xc1\xcft\xc9\x18\xbc\x89 \x86\xac5\x10R`\x00\x00\u07d41^\xf2\xdab\x0f\xd30\xd1.\xe5]\xe5\xf3)\xa6\x96\xe0\xa9h\x89\b!\xab\rD\x14\x98\x00\x00\u07d41n\x92\xa9\x1b\xbd\xa6\x8b\x9e/\x98\xb3\xc0H\x93N<\xc0\xb4\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d41n\xb4\xe4}\xf7\x1bB\xe1mo\xe4h%\xb72{\xaf1$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41q\x87~\x9d\x82\f\xc6\x18\xfc\t\x19\xb2\x9e\xfd3?\xdaI4\x8965\u026d\xc5\u07a0\x00\x00\u07d41|\xf4\xa2<\xb1\x91\xcd\xc5c\x12\u009d\x15\xe2\x10\xb3\xb9\xb7\x84\x89\a\xcef\xc5\x0e(@\x00\x00\u07d41\x8b.\xa5\xf0\xaa\xa8y\xc4\xd5\xe5H\xac\x9d\x92\xa0\xc6t\x87\xb7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d41\x8cv\xec\xfd\x8a\xf6\x8dpUSR\xe1\xf6\x01\xe3Y\x88\x04-\x89\x1b1\x19.h\xc7\xf0\x00\x00\u07d41\x8f\x1f\x8b\xd2 \xb0U\x8b\x95\xfb3\x10\x0f\xfd\xbbd\r|\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41\xaa;\x1e\xbe\x8cM\xbc\xb6\xa7\b\xb1\xd7H1\xe6\x0eIv`\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d41\xab\b\x89f\xec\xc7\"\x92X\xf6\t\x8f\xceh\xcf9\xb3\x84\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x941\xadM\x99F\xef\t\xd8\xe9\x88\xd9F\xb1\"\u007f\x91A\x90\x176\x8a\x04\xd8S\xc8\xf8\x90\x89\x80\x00\x00\xe0\x941\xb4;\x01]\x00\x81d~h\x00\x00\u07d424\x86\xcad\xb3uGO\xb2\xb7Y\xa9\xe7\xa15\x85\x9b\xd9\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d427I\xa3\xb9q\x95\x9eF\u0234\x82-\xca\xfa\xf7\xaa\xf9\xbdn\x89\x01\x16q\xa5\xb2Ep\x00\x00\u07d42:\xadA\xdfKo\xc8\xfe\u038c\x93\x95\x8a\xa9\x01\xfah\bC\x894\x95tD\xb8@\xe8\x00\x00\xe0\x942;<\xfe>\xe6+\xbd\xe2\xa2a\xe5<\xb3\xec\xc0X\x10\xf2\u018a\x02\ub3b1\xa1r\u0738\x00\x00\u07d42?\xca^\xd7\u007fi\x9f\x9d\x990\xf5\xce\xef\xf8\xe5oY\xf0<\x89Hz\x9a0E9D\x00\x00\u07d42H\\\x81\x87(\xc1\x97\xfe\xa4\x87\xfb\xb6\xe8)\x15\x9e\xba\x83p\x899!\xb4\x13\xbcN\xc0\x80\x00\xe0\x942P\xe3\xe8X\xc2j\xde\u032d\xf3jVc\xc2*\xa8LAp\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x942Y\xbd/\xdd\xfb\xbco\xba\u04f6\xe8t\xf0\xbb\xc0,\xda\x18\xb5\x8a\x02\x84`VI[\r\x18\x80\x00\u07d42uIo\xd4\u07491\xfdi\xfb\n\v\x04\xc4\xd1\xff\x87\x9e\xf5\x89\x18-~L\xfd\xa08\x00\x00\u07d42{\xb4\x9euOo\xb4\xf73\xc6\xe0o9\x89\xb4\xf6]K\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d42\x82y\x1do\xd7\x13\xf1\xe9OK\xfdV^\xaax\xb3\xa0Y\x9d\x89Hz\x9a0E9D\x00\x00\u07d42\x83\xeb\u007f\x917\xdd9\xbe\xd5_\xfek\x8d\xc8E\xf3\xe1\xa0y\x89\x03\x97\n\xe9!Ux\x00\x00\u07d42\x86\t\x97\xd70\xb2\xd8;s$\x1a%\xd3f}Q\xc9\b\xef\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x942\x86\u047cez1,\x88G\xd9<\xb3\xcbyP\xf2\xb0\xc6\xe3\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x942\xa2\r\x02\x8e,b\x18\xb9\xd9[D\\w\x15$cj\"\xef\x8a\x02\x02\xfe\xfb\xf2\xd7\xc2\xf0\x00\x00\u07d42\xa7\x06\x91%\\\x9f\xc9y\x1aOu\u0238\x1f8\x8e\n%\x03\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d42\xb7\xfe\xeb\xc5\u015b\xf6^\x86\x1cL\v\xe4*v\x11\xa5T\x1a\x89w\u9aa8R\\\x10\x00\x00\xe0\x942\xba\x9a}\x04#\xe0:R_\xe2\xeb\xebf\x1d \x85w\x8b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d42\xbb.\x96\x93\xe4\xe0\x854M/\r\xbdF\xa2\x83\u3807\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x942\xc2\xfd\u2daa\xbb\x80\u5ba2\xb9I\xa2\x17\xf3\xcb\t\"\x83\x8a\x010a`\xaf\xdf 7\x80\x00\u07d42\xd9P\xd5\xe9>\xa1\u0574\x8d\xb4qO\x86{\x03 \xb3\x1c\x0f\x897\b\xba\xed=h\x90\x00\x00\u07d42\u06f6qlT\xe81e\x82\x9aJ\xbb6uxI\xb6\xe4}\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xebd\xbe\x1b]\xed\xe4\b\u01bd\xef\xben@\\\x16\xb7\xed\x02\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d42\xef\\\xdcg\x1d\xf5V*\x90\x1a\xee]\xb7\x16\xb9\xbev\xdc\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d42\xf2\x9e\x87'\xa7LkC\x01\xe3\xff\xff\x06\x87\xc1\xb8p\xda\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xfa\x0e\x86\xcd\b}\u058di1\x90\xf3-\x931\t\t\xedS\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d42\xfb\xee\xd6\xf6&\xfc\xdf\xd5\x1a\xca\xfbs\v\x9e\xef\xf6\x12\xf5d\x89lk\x93[\x8b\xbd@\x00\x00\u07943\x00\xfb\x14\x9a\xde\xd6[\u02e6\xc0N\x9c\u05b7\xa0;\x89;\xb1\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x943\x01\xd9\xca/;\xfe\x02by\xcdh\x19\xf7\x9a)=\x98\x15n\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x943\b\xb04f\xc2z\x17\xdf\xe1\xaa\xfc\xeb\x81\xe1m)4Vo\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07943\x1a\x1c&\xcci\x94\xcd\xd3\xc1K\xec\xe2v\xff\xffK\x9d\xf7|\x88\xfaz\xed\xdfO\x06\x80\x00\xe0\x943&\xb8\x8d\xe8\x06\x18DT\xc4\v'\xf3\t\xd9\xddm\u03f9x\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x943)\xeb;\xafCE\xd6\x00\xce\xd4\x0en\x99ueo\x117B\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d432\r\xd9\x0f+\xaa\x11\r\xd34\x87*\x99\x8f\x14\x84&E<\x8965f3\xeb\xd8\xea\x00\x00\u07d436\xc3\xefn\x8bP\xee\x90\xe07\xb1d\xb7\xa8\xea_\xaa\xc6]\x89\x0e\u0223\xa7\x1c\"T\x00\x00\xe0\x9438\fo\xffZ\xcd&Q0\x96)\u06daq\xbf? \u017a\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d43:\xd1Yd\x01\xe0Z\xea-6\xcaG1\x8e\xf4\xcd,\xb3\u07c9\x9d\xc0\\\xce(\u00b8\x00\x00\u07d43C@\xeeK\x9c\u0701\xf8P\xa7Q\x16\xd5\x0e\u9d98%\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d43H\x1e\x85n\xbe\u050e\xa7\b\xa2t&\xef(\xe8g\xf5|\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943V[\xa9\xda,\x03\xe7x\xce\x12)O\b\x1d\xfe\x81\x06M$\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07943X\x1c\xee#0\x88\xc0\x86\r\x94N\f\xf1\u03ab\xb8&\x1c.\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d43XX\xf7I\xf1i\u02bc\xfeR\xb7\x96\xe3\xc1\x1e\xc4~\xa3\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943^\"\x02[zw\u00e0t\u01cb\x8e=\xfe\a\x13A\x94n\x8a\x02'\xcas\n\xb3\xf6\xac\x00\x00\u07d43b\x9b\xd5/\x0e\x10{\xc0q\x17ld\xdf\x10\x8fdw}I\x89\x01\xcf\xddth!n\x80\x00\u07d43{;\u07c6\xd7\x13\xdb\xd0{]\xbf\xcc\x02+z{\x19F\xae\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d43|\xfe\x11W\xa5\u0191 \x10\xddV\x153y\x17i\u00b6\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xb36\xf5\xba^\xdb{\x1c\xcc~\xb1\xa0\u0644\xc1#\x1d\x0e\u0709lk\x93[\x8b\xbd@\x00\x00\u07d43\xc4\a\x13;\x84\xb3\xcaL=\xed\x1fFX\x90\f8\x10\x16$\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\xe0\x943\xd1r\xab\a\\Q\xdb\x1c\xd4\n\x8c\xa8\xdb\xff\r\x93\xb8C\xbb\x8a\x016x\x05\x10\xd1-\xe3\x80\x00\u07d43\xe9\xb7\x18#\x95.\x1ff\x95\x8c'\x8f\u008b\x11\x96\xa6\u0164\x89\x05k\xc7^-c\x10\x00\x00\u07d43\xeakxU\xe0[\a\xab\x80\u06b1\xe1M\xe9\xb6I\xe9\x9bl\x89\x1c\xd6\xfb\xadW\xdb\xd0\x00\x00\u07d43\xf1R#1\rD\u078bf6h_:L=\x9cVU\xa5\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d43\xf4\xa6G\x1e\xb1\xbc\xa6\xa9\xf8[;Hr\xe1\aU\xc8+\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d43\xfbWzM!O\xe0\x10\xd3,\xca|>\xed\xa6?\x87\xce\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xfdq\x8f\v\x91\xb5\xce\u020a]\xc1^\xec\xf0\xec\xef\xa4\xef=\x89\x17r$\xaa\x84Lr\x00\x00\u07d44\x14\x80\u030c\xb4v\xf8\xd0\x1f\xf3\b\x12\xe7\xc7\x0e\x05\xaf\xaf]\x89lk\x93[\x8b\xbd@\x00\x00\u07d44'-^ut1]\xca\u9afd1{\xac\x90(\x9dGe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x9440\xa1c\x81\xf8i\xf6\xeaT#\x91XU\xe8\x00\x885%\xa9\x8a\x03\xca\\f\u067cD0\x00\x00\u07d441\x86%\x81\x8e\xc1?\x11\x83Z\xe9sS\xce7}oY\n\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d449<]\x91\xb9\xdeYr\x03\xe7[\xacC\t\xb5\xfa=(\u00c9\n\x84Jt$\xd9\xc8\x00\x00\u07d449\x99\x8b$|\xb4\xbf\x8b\xc8\nm+5'\xf1\xdf\xe9\xa6\u0489\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d44C}\x14ed\v\x13l\xb5\x84\x1c?\x93O\x9b\xa0\xb7\t}\x89\t`\xdbwh\x1e\x94\x00\x00\u07d44J\x8d\xb0\x86\xfa\xedN\xfc7\x13\x1b:\"\xb0x-\xadp\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x944fM\"\x0f\xa7\xf3yX\x02J32\u0584\xbc\xc6\xd4\u023d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44f\xf6~9cl\x01\xf4;:!\xa0\xe8R\x93%\xc0\x86$\x89-\xb1\x16vP\xac\xd8\x00\x00\u07d44\x856\x1e\xe6\xbf\x06\xefe\b\xcc\xd2=\x94d\x1f\x81M>/\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x85\xf6!%d3\xb9\x8aB\x00\xda\xd8W\xef\xe5Y7\uc609lk\x93[\x8b\xbd@\x00\x00\u07d44\x95\x8aF\xd3\x0e0\xb2s\xec\xc6\xe5\xd3X\xa2\x12\xe50~\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x97\xddf\xfd\x11\x80q\xa7\x8c,\xb3n@\xb6e\x1c\xc8%\x98\x89\x05\xf1\x01kPv\xd0\x00\x00\xe0\x944\x9a\x81k\x17\xab='\xbb\xc0\xae\x00Q\xf6\xa0p\xbe\x1f\xf2\x9d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44\x9d,\x91\x8f\u041e(\a1\x8ef\xceC)\t\x17k\xd5\v\x89<\xb7\x1fQ\xfcU\x80\x00\x00\u07d44\xa0C\x1f\xff^\xad\x92\u007f\xb6`\f\x1e\xa8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d44\xff&\xeb`\xa8\u0469ZH\x9f\xae\x13n\xe9\x1dNX\bL\x89 \x86\xac5\x10R`\x00\x00\u07d44\xffX)R\xff$E\x8f{\x13\xd5\x1f\vO\x98p\"\xc1\xfe\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d45\x10k\xa9N\x85c\u0533\xcb<\\i,\x10\xe6\x04\xb7\xce\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x945\x14_b\x03\x97\u019c\xb8\xe0\tb\x96\x1f\x0fH\x86d9\x89\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d45\x14t0\xc3\x10e\x00\u77e2\xf5\x02F.\x94p<#\xb1\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x945\x17\x87\x845\x05\xf8\xe4\xef\xf4ef\xcc\u695fM\x1c_\xe7\x8a\x01\xf5q\x89\x87fKH\x00\x00\xe0\x945\x1f\x16\xe5\xe0sZ\xf5gQ\xb0\xe2%\xb2B\x11q9@\x90\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\xe0\x945$\xa0\x00#N\xba\xaf\a\x89\xa14\xa2\xa4\x178<\xe5(*\x8a\x011yU\x94}\x8e,\x00\x00\u07d45&\xee\xce\x1ak\xdc>\xe7\xb4\x00\xfe\x93[HF?1\xbe\u05c9\x04w\x87\x9bm\x140\x00\x00\u07d45*x_J\x92\x162PL\xe5\xd0\x15\xf8\xd7FO\xa3\xdb\x14\xe7r\x92\x13\u03aa7\x8c\t^\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d45\xaf\x04\n\f\xc23zv\xaf(\x81T\xc7V\x1e\x1a#3I\x8965\u026d\xc5\u07a0\x00\x00\u07d45\xb0>\xa4$W6\xf5{\x85\xd2\xebyb\x8f\x03m\xdc\xd7\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xbd$he\xfa\xb4\x90\xac\bz\xc1\xf1\xd4\xf2\xc1\r\f\xda\x03\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x945\xbff\x88R/5Fz\u007fu0#\x14\xc0+\xa1v\x80\x0e\x8a\x03\xafA\x82\x02\xd9T\xe0\x00\x00\u07d45\u022d\xc1\x11%C+;w\xac\xd6F%\xfeX\xeb\xee\x9df\x89lk\x93[\x8b\xbd@\x00\x00\u07d45\u0497\x0fI\xdc\xc8\x1e\xa9\xeep~\x9c\x8a\n\xb2\xa8\xbbtc\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d45\xe0\x96\x12\r\xea\xa5\xc1\xec\xb1d^,\u02cbN\xdb\xd9)\x9a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d45\xea!c\xa3\x8c\u07da\x12?\x82\xa5\xec\x00%\x8d\xae\v\xc7g\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xf1\xda\x12{\x837o\x1b\x88\xc8*3Y\xf6z^g\xddP\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d45\xf2\x94\x9c\xf7\x8b\xc2\x19\xbbO\x01\x90|\xf3\xb4\xb3\u04c6T\x82\x89\x0f\xb5\xc8l\x92\xe44\x00\x00\u07d45\xf5\x86\x01I\xe4\xbb\xc0K\x8a\u0172r\xbeU\xad\x1a\xcaX\xe0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x02E\x8d\xa8omj\x9d\x9e\xb0=\xaf\x97\xfeV\x19\xd4B\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x057-\x93\xa9\x01\t\x88\x01\x8f\x9f1]\x03.\u0448\x0f\xa1\x89\x1b\x1b\xcfQ\x89j}\x00\x00\u07d46\x16\xd4H\x98_]2\xae\xfa\x8b\x93\xa9\x93\xe0\x94\xbd\x85I\x86\x89\v\"\u007fc\xbe\x81<\x00\x00\u07d46\x16\xfbF\xc8\x15x\xc9\xc8\xebM;\xf8\x80E\x1a\x887\x9d}\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x1cu\x93\x16\x96\xbc=B}\x93\xe7lw\xfd\x13\xb2A\xf6\xf4\x89\x1d\xc5\xd8\xfc&m\xd6\x00\x00\u07d46\x1d\x9e\xd8\v[\xd2|\xf9\xf1\"o&u2X\xee_\x9b?\x89\xbfi\x14\xba}r\xc2\x00\x00\u07d46\x1f;\xa9\xed\x95kw\x0f%}6r\xfe\x1f\xf9\xf7\xb0$\f\x89 \x86\xac5\x10R`\x00\x00\u07d46\"|\u07e0\xfd;\x9d~jtF\x85\xf5\xbe\x9a\xa3f\xa7\xf0\x89\n\xc2s\x0e\xe9\xc6\xc1\x80\x00\u07d46/\xbc\xb1\x06b7\n\x06\x8f\xc2e&\x02\xa2Wy7\xcc\xe6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d460\xc5\xe5e\u03aa\x8a\x0f\x0f\xfe2\x87^\xae*l\xe6<\x19\x89\t7r+7t\xd0\x00\x00\u07d463\x9f\x84\xa5\u00b4L\xe5=\xfd\xb6\xd4\xf9}\xf7\x82\x12\xa7\u07c9\x11o\x18\xb8\x17\x15\xa0\x00\x00\u07d464:\xec\xa0{n\u054a\x0eb\xfaN\xcbI\x8a\x12O\xc9q\x89\x10CV\x1a\x88)0\x00\x00\u07d46au@4\x81\xe0\xab\x15\xbbQF\x15\u02f9\x89\xeb\u018f\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d46ro;\x88Z$\xf9)\x96\u0681b^\u022d\x16\xd8\xcb\xe6\x89S\xafu\u0441HW\x80\x00\xe0\x946s\x95C\x99\xf6\u07feg\x18\x18%\x9b\xb2x\xe2\xe9.\xe3\x15\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d46u\x8e\x04\x9c\u064b\u03a1\"w\xa6v\xf9)sb\x89\x00#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d46\u007fY\u0302yS)8NA\xe1(1\x15\xe7\x91\xf2j\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x81\x0f\xf9\xd2\x13\xa2q\xed\xa2\xb8\xaay\x8b\xe6T\xfaK\xbe\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x8cT\x14\xb5k\x84U\x17\x1f\xbf\ab \xc1\u02e4\xb5\xca1\x89\x1e>\xf9\x11\xe8=r\x00\x00\xe0\x946\x90$k\xa3\xc8\x06y\xe2.\xacD\x12\xa1\xae\xfc\xe6\xd7\u0342\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\x92\x8bU\xbc\x86\x15\t\xd5\x1c\x8c\xf1\xd5F\xbf\xecn>\x90\xaf\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d46\x98\"\xf5W\x8b@\xdd\x1fDqpk\"\u0357\x13R\xdak\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d46\x9e\xf7a\x19_:7>$\xec\xe6\xcd\"R\x0f\xe0\xb9\xe8n\x89\x1c\xff\xaf\xc9M\xb2\b\x80\x00\u07d46\xa0\x8f\xd6\xfd\x1a\xc1|\xe1^\xd5~\xef\xb1*+\u2048\xbf\x89Hz\x9a0E9D\x00\x00\u07d46\xa0\xe6\x1e\x1b\xe4\u007f\xa8~0\xd3(\x88\xee\x030\x90\x1c\xa9\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x946\xb2\xc8^:\xee\xeb\xb7\rc\u0124s\f\xe2\xe8\xe8\x8a6$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x946\xbfC\xff5\u07d0\x90\x88$3l\x9b1\xce3\x06~/P\x8aIr\x15\x10\xc1\xc1\xe9H\x00\x00\u07d46\xbf\xe1\xfa;{p\xc1r\xeb\x04/h\x19\xa8\x97%\x95A>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x946\xc5\x10\xbf\x8dnV\x9b\xf2\xf3}G&]\xbc\xb5\x02\xff+\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x946\xd8]\xc3h1V\xe6;\xf8\x80\xa9\xfa\xb7x\x8c\xf8\x14:'\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\u07cf\x88<\x12s\xec\x8a\x17\x1fz3\xcf\xd6I\xb1\xfe`u\x89\fRHJ\xc4\x16\x89\x00\x00\xe0\x946\xe1Va\f\xd8\xffd\xe7\x80\u061d\x00T8\\\xa7gU\xaa\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d46\xfe\xc6,,B^!\x9b\x18D\x8a\xd7W\x00\x9d\x8cT\x02o\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d47\x00\xe3\x02t$\xd99\xdb\xde]B\xfbx\xf6\xc4\xdb\xec\x1a\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d47\x02\xe7\x04\xcc!at9\xadN\xa2zW\x14\xf2\xfd\xa1\xe92\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x035\fMo\xe374,\xdd\xc6[\xf1\xe28k\xf3\xf9\xb2\x89m\x81!\xa1\x94\xd1\x10\x00\x00\xe0\x947\b\xe5\x9d\xe6\xb4\x05P\x88x)\x02\xe0W\x9cr\x01\xa8\xbfP\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d47\x126~^U\xa9mZ\x19\x16\x8fn\xb2\xbc~\x99q\xf8i\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x19Zc]\xccb\xf5jq\x80I\xd4~\x8f\x9f\x96\x83(\x91\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d47'4\x1f&\xc1 \x01\xe3x@^\xe3\x8b-\x84d\xecq@\x89lk\x93[\x8b\xbd@\x00\x00\u07d47.E:kb\x9f'g\x8c\u022e\xb5\xe5|\xe8^\xc0\xae\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d474\xcb\x18t\x91\xed\xe7\x13\xae[;-\x12(J\xf4k\x81\x01\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d477!n\xe9\x1f\x17w2\xfbX\xfa@\x97&r\a\xe2\xcfU\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d47M;\xbb\x057Q\xf9\xf6\x8d\xdb\a\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d48r\xf4\x8d\xc5\xe3\xf8\x17\xbck*\xd2\xd00\xfc^\x04q\x19=\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48~\xea\xfdk@\t\u07af\x8b\u0578Zr\x98:\x8d\xcc4\x87\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48\x81\xde\xfa\xe1\xc0{<\xe0Lx\xab\xe2k\f\u070ds\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d48\x83\xbe\xcc\b\xb9\xbeh\xad;\b6\xaa\u00f6 \xdc\x00\x17\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d48\x85\xfe\xe6q\a\xdc:\xa9\x8a\x1d\x99:t\xdf\\\xd7T\xb9\x8dR\x9a\x89a\t=|,m8\x00\x00\u07d48\xe4m\xe4E<8\xe9A\xe7\x93\x0fC0O\x94\xbb{+\xe8\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d48\xe7\u06e8\xfdO\x1f\x85\r\xbc&I\xd8\xe8O\tR\xe3\xeb<\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d48\xe8\xa3\x1a\xf2\xd2e\xe3\x1a\x9f\xff-\x8fF(m\x12E\xa4g\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d48\xeao[Z{\x88AuQ\xb4\x12=\xc1'\xdf\xe94-\xa6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d48\xee\xc6\xe2\x17\xf4\xd4\x1a\xa9 \xe4$\xb9RQ\x97\x04\x1c\xd4\u0189\xf0\r%\xeb\x92.g\x00\x00\xe0\x948\xf3\x87\xe1\xa4\xedJs\x10n\xf2\xb4b\xe4t\xe2\xe3\x14:\u040a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\x11a\xb0\xe4<0 f\u898d,\xe7\xe1\x99\xec\xdb\x1dW\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x949\x15\uad6b.Yw\xd0u\xde\xc4}\x96\xb6\x8bK\\\xf5\x15\x8a\r\a\x01\x81\x85\x12\x0f@\x00\x00\u07d49\x1aw@\\\t\xa7+^\x846#z\xaa\xf9]h\xda\x17\t\x89\x02\xa9&J\xf3\u0479\x00\x00\u07d49\x1f \x17m\x126\rrMQG\n\x90p6uYJM\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d49$3\xd2\u0383\xd3\xfbJv\x02\u0323\xfa\xcaN\xc1@\xa4\xb0\x89\x02\xc3\xc4e\xcaX\xec\x00\x00\xe0\x949?x;\\\u06c6\"\x1b\xf0)O\xb7\x14\x95\x9c{E\x89\x9c\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d49?\xf4%^\\e\x8f.\u007f\x10\xec\xbd)%rg\x1b\xc2\u0489lk\x93[\x8b\xbd@\x00\x00\u07d49A2`\x0fAU\xe0\u007fME\xbc>\xb8\xd9\xfbr\xdc\u05c4\x89\x9fn\x92\xed\xea\a\xd4\x00\x00\u07d49Q\xe4\x8e<\x86\x9ekr\xa1C\xb6\xa4Ph\u0379\xd4f\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x949T\xbd\xfe\v\xf5\x87\u0195\xa3\x05\xd9$L=[\xdd\xda\u027b\x8a\x04\x10'\x83'\xf9\x85`\x80\x00\u07d49]m%U \xa8\xdb)\xab\xc4}\x83\xa5\u06ca\x1a}\xf0\x87\x89\x05k\xc7^-c\x10\x00\x00\u07d49ck%\x81\x1b\x17j\xbf\xcf\xee\xcad\xbc\x87E/\x1f\xdf\xf4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d49i\xb4\xf7\x1b\xb8u\x1e\xdeC\xc0\x166:zaOv\x11\x8e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x949x/\xfe\x06\xacx\x82*<:\x8a\xfe0^P\xa5a\x88\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d49zn\xf8v:\x18\xf0\x0f\xac!~\x05\\\r0\x94\x10\x10\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d49|\u06cc\x80\xc6yP\xb1\x8deB)a\x0e\x93\xbf\xa6\xee\x1a\x89?\x95\xc8\xe0\x82\x15!\x00\x00\u07d49\x82O\x8b\xce\xd1v\xfd>\xa2.\u01a4\x93\xd0\xcc\xc3?\xc1G\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\x93l'\x19E\v\x94 \xcc%\"\u03d1\xdb\x01\xf2'\xc1\xc1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d49\x95\xe0\x96\xb0\x8aZrh\x00\xfc\xd1}\x9cd\xc6N\b\x8d+\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\x9a\xa6\xf5\xd0x\xcb\tp\x88+\u0259 \x06\xf8\xfb\xdf4q\x8965\u026d\xc5\u07a0\x00\x00\u07d49\xaa\x05\xe5m}28T!\u03d36\xe9\r=\x15\xa9\xf8Y\x89\x01h\u048e?\x00(\x00\x00\u07d49\xaa\xf0\x85M\xb6\xeb9\xbc{.C\x84jv\x17\x1c\x04E\u0789dI\xe8NG\xa8\xa8\x00\x00\u07d49\xb1\xc4q\xae\x94\xe1!dE.\x81\x1f\xbb\xe2\xb3\xcdru\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xb2\x992t\x90\xd7/\x9a\x9e\xdf\xf1\x1b\x83\xaf\xd0\xe9\xd3\xc4P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\xba\u018d\x94xY\xf5\x9e\x92&\b\x9c\x96\xd6.\x9f\xbe<\u0789\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x949\xbf\xd9xh\x9b\xec\x04\x8f\xc7v\xaa\x15$\u007f^\x1d|9\xa2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d49\xc7s6|\x88%\xd3YlhoB\xbf\r\x141\x9e?\x84\x89\a?u\u0460\x85\xba\x00\x00\u07d49\u05291@,\fy\xc4W\x18o$\u07c7)\u03d5p1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\xd6\xca\xca\"\xbc\xcdjr\xf8~\xe7\u05b5\x9e\v\xde!\xd7\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d49\xe0\xdbM`V\x8c\x80\v\x8cU\x00\x02l%\x94\xf5v\x89`\x8965\u026d\xc5\u07a0\x00\x00\xe0\x949\xeeO\xe0\x0f\xbc\xeddph\xd4\xf5|\x01\xcb\"\xa8\v\xcc\u044a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\xf1\x983\x1eK!\xc1\xb7`\xa3\x15_J\xb2\xfe\x00\xa7F\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xf4Fc\xd9%a\t\x1b\x82\xa7\r\xcfY=u@\x05\x97:\x89\n\u05cb.\xdc!Y\x80\x00\u07d4:\x03U\x94\xc7GGmB\xd1\xee\x96l6\"L\xdd\"I\x93\x89\x13J\xf7Ei\xf9\xc5\x00\x00\u07d4:\x04W(G\xd3\x1e\x81\xf7v\\\xa5\xbf\xc9\xd5W\x15\x9f6\x83\x89\a6-\r\xab\xea\xfd\x80\x00\xe0\x94:\x06\xe3\xbb\x1e\xdc\xfd\fD\xc3\aM\xe0\xbb`k\x04\x98\x94\xa2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794:\x10\x88\x8b~\x14\x9c\xae',\x010,2}\n\xf0\x1a\v$\x88\xeb\xec!\xee\x1d\xa4\x00\x00\u07d4:1\b\xc1\u6023;3l!\x13\x134@\x9d\x97\xe5\xad\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4:6\x8e\xfeJ\u05c6\xe2c\x95\xec\x9f\u01adi\x8c\xae)\xfe\x01\x89\"E\x89\x96u\xf9\xf4\x00\x00\u07d4:=\xd1\x04\xcd~\xb0O!\x93/\xd43\xeaz\xff\u04d3i\xf5\x89\x13aO#\xe2B&\x00\x00\u07d4:B\x97\xda\xc4.\x1eO\xb8\xcb1\xec\xddC\xaew<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94:\x99`&m\xf6I cS\x8a\x99\xf4\x87\xc9P\xa3\xa5\uc78a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4:\x9b\x11\x10)\xce\x1f \xc9\x10\x9czt\xee\xee\xf3OO.\xb2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4:\x9eTA\xd4K$;\xe5[u\x02z\x1c\ub7ac\xf5\r\xf2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94:\xa0z4\xa1\xaf\u0216}=\x13\x83\xb9kb\u03d6\xd5\xfa\x90\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94:\xa4,!\xb9\xb3\x1c>'\xcc\xd1~\t\x9a\xf6y\xcd\xf5i\a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4:\xa9H\xea\x029wU\xef\xfb/\x9d\xc99-\xf1\x05\x8f~3\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4:\xad\xf9\x8ba\xe5\u0216\xe7\xd1\x00\xa39\x1d2P\"]a\u07c9\f\xafg\x007\x01h\x00\x00\u07d4:\xaeHr\xfd\x90\x93\xcb\xca\xd1@o\x1e\x80x\xba\xb5\x03Y\xe2\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4:\xbb\x8a\xdf\xc6\x04\xf4\x8dY\x84\x81\x1d\u007f\x1dR\xfe\xf6u\x82p\x89\xf2\x97\x19\xb6o\x11\f\x00\x00\u07d4:\xc2\xf0\xff\x16\x12\xe4\xa1\xc3F\xd53\x82\xab\xf6\u0622[\xaaS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xc9\xdczCj\xe9\x8f\xd0\x1cz\x96!\xaa\x8e\x9d\v\x8bS\x1d\x89a\t=|,m8\x00\x00\xe0\x94:\xd0aI\xb2\x1cU\xff\x86|\xc3\xfb\x97@\u04bc\xc7\x10\x121\x8a)\xb7d2\xb9DQ \x00\x00\u07d4:\xd7\x02C\u060b\xf0@\x0fW\xc8\xc1\xfdW\x81\x18H\xaf\x16*\x89.\x9e\xe5\u00c6S\xf0\x00\x00\u07d4:\xd9\x15\xd5P\xb7#AV \xf5\xa9\xb5\xb8\x8a\x85\xf3\x82\xf05\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xe1`\xe3\xcd`\xae1\xb9\xd6t-h\xe1Nv\xbd\x96\xc5\x17\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4:\xe6+\xd2q\xa7`c\u007f\xady\xc3\x1c\x94\xffb\xb4\xcd\x12\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xeaN\x82\xd2@\x02H\xf9\x98q\xa4\x1c\xa2W\x06\r:\"\x1b\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xf6[>(\x89ZJ\x00\x11S9\x1d\x1ei\xc3\x1f\xb9\xdb9\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4;\a\xdbZ5\u007fZ\xf2HL\xbc\x9dw\xd7;\x1f\xd0Q\x9f\u01c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4;\n\u032fK`|\xfea\xd1s4\xc2\x14\xb7\\\xde\xfd\xbd\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x13c\x1a\x1b\x89\xcbVeH\x89\x9a\x1d`\x91\\\xdc\xc4 [\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x15\x90\x99\aR\a\u0180vc\xb1\xf0\xf7\xed\xa5J\xc8\xcc\xe3\x89j\xc4\xe6[i\xf9-\x80\x00\u07d4;\x197\xd5\u74f8\x9bc\xfb\x8e\xb5\xf1\xb1\xc9\xcak\xa0\xfa\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\"\xda*\x02q\xc8\xef\xe1\x02S'scji\xb1\xc1~\t\x89\x1b6\xa6DJ>\x18\x00\x00\u07d4;\"\u07a3\xc2_\x1bY\u01fd'\xbb\x91\u04e3\xea\xec\xef9\x84\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94;#g\xf8IK_\xe1\x8dh<\x05]\x89\x99\x9c\x9f=\x1b4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;,E\x99\x0e!GDQ\xcfOY\xf0\x19U\xb31\xc7\xd7\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94;A\x00\xe3\ns\xb0\xc74\xb1\x8f\xfa\x84&\u045b\x191/\x1a\x8a\v\xb5\u046ap\n\xfd\x90\x00\x00\u07d4;B\xa6m\x97\x9fX(4tz\x8b`B\x8e\x9bN\xec\xcd#\x89!\xa1\u01d0\xfa\xdcX\x00\x00\u07d4;Gh\xfdq\xe2\xdb,\xbe\u007f\xa0PH<'\xb4\xeb\x93\x1d\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;Vj\x8a\xfa\u0456\x82\xdc,\xe8g\x9a<\xe4D\xa5\xb0\xfdO\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\\%\x1d\u007f\u05c9;\xa2\t\xfeT\x1c\xec\xd0\xce%:\x99\r\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4;^\x8b\x17w\xca\x18A\x896\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\x93\xb1a6\xf1\x1e\xaf\x10\x99l\x95\x99\r;'9\xcc\xea_\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;\xabK\x01\xa7\xc8K\xa1?\uea70\xbb\x19\x1bw\xa3\xaa\u0723\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4;\xb55\x98\xcc \xe2\x05]\xc5S\xb0I@J\u0277\xdd\x1e\x83\x89!W\x1d\xf7|\x00\xbe\x00\x00\u07d4;\xbc\x13\xd0J\xcc\xc0pz\xeb\u072e\xf0\x87\u0438~\v^\u327e\xd1\xd0&=\x9f\x00\x00\x00\u07d4;\xc6\xe3\xeezV\u038f\x14\xa3u2Y\x0fcqk\x99f\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\xc8]ls[\x9c\xdaK\xba_H\xb2K\x13\xe7\x0600{\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4;\xd6$\xb5H\xcbe\x976\x90~\u062a<\fp^$\xb5u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\u0660m\x1b\xd3lN\xdd'\xfc\r\x1f[\b\x8d\xda\xe3\xc7*\x89\x1b\x1azB\v\xa0\r\x00\x00\u0794;\u077c\x814\xf7}UY\u007f\xc9|&\xd2f\x98\t\x06\x04\ub23e -j\x0e\xda\x00\x00\xe0\x94;\xf8n\u0623\x15>\xc93xj\x02\xac\t\x03\x01\x85^Wk\x8a_J\x8c\x83u\xd1U@\x00\x00\u07d4;\xfb\u04c4|\x17\xa6\x1c\xf3\xf1{R\xf8\ub879`\xb3\U000df262\xa1]\tQ\x9b\xe0\x00\x00\u07d4<\x03\xbb\xc0#\xe1\xe9?\xa3\xa3\xa6\xe4(\xcf\f\xd8\xf9^\x1e\u0189Rf<\u02b1\xe1\xc0\x00\x00\u07d4<\f=\ufb1c\xeaz\xcc1\x9a\x96\xc3\v\x8e\x1f\xed\xabEt\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4<\x15\xb3Q\x1d\xf6\xf04.sH\u0309\xaf9\xa1h\xb7s\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x1f\x91\xf3\x01\xf4\xb5e\xbc\xa2GQ\xaa\x1fv\x13\"p\x9d\u0749a\t=|,m8\x00\x00\xe0\x94<(l\xfb0\x14n_\u05d0\xc2\xc8T\x15RW\x8d\xe34\u060a\x02)\x1b\x11\xaa0n\x8c\x00\x00\u07d4<2.a\x1f\u06c2\rG\xc6\xf8\xfcd\xb6\xfa\xd7L\xa9_^\x89\r%\x8e\xce\x1b\x13\x15\x00\x00\u07d4\xa5\xe5\xbfb\xbb\u0309\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4<\x86\x9c\tie#\xce\xd8$\xa0pAF\x05\xbbv#\x1f\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x92V\x19\u02731DF?\x057\u06165\x87\x06\xc5 \xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\x98YK\xf6\x8bW5\x1e\x88\x14\xae\x9em\xfd-%J\xa0o\x89\x10CV\x1a\x88)0\x00\x00\u07d4<\xad\xeb=>\xed?b1\x1dRU>p\xdfJ\xfc\xe5o#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94<\xae\xdbS\x19\xfe\x80eC\xc5nP!\xd3r\xf7\x1b\xe9\x06.\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4<\xaf\xaf^bPV\x15\x06\x8a\xf8\xeb\"\xa1:\u0629\xe5Pp\x89lf\x06E\xaaG\x18\x00\x00\u07d4<\xb1y\xcbH\x01\xa9\x9b\x95\u00f0\xc3$\xa2\xbd\xc1\x01\xa6S`\x89\x01h\u048e?\x00(\x00\x00\u07d4<\xb5a\u0386BK5\x98\x91\xe3d\xec\x92_\xfe\xff'}\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xcbq\xaah\x80\xcb\v\x84\x01-\x90\xe6\a@\xec\x06\xac\u05cf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\xce\xf8\x86yW9G\xe9I\x97y\x8a\x1e2~\b`:e\x89+\xc9\x16\u059f;\x02\x00\x00\xe0\x94<\xd1\xd9s\x1b\xd5H\xc1\xddo\u03a6\x1b\xebu\xd9\x17T\xf7\u04ca\x01\x16\x1d\x01\xb2\x15\xca\xe4\x80\x00\u07d4<\u04e6\xe95y\xc5mIAq\xfcS>z\x90\xe6\xf5\x94d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\u05b7Y<\xbe\xe7x0\xa8\xb1\x9d\b\x01\x95\x8f\xcdK\xc5z\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4<\xd7\xf7\xc7\xc257\x80\xcd\xe0\x81\xee\xecE\x82+%\xf2\x86\f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xe1\u0717\xfc\u05f7\xc4\u04e1\x8aI\xd6\xf2\xa5\xc1\xb1\xa9\x06\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xea0*G*\x94\x03y\xdd9\x8a$\xea\xfd\xba\u07c8\xady\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94<\xec\xa9k\xb1\xcd\xc2\x14\x02\x9c\xbc^\x18\x1d9\x8a\xb9M=A\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4<\xf4\x84RO\xbd\xfa\xda\xe2m\xc1\x85\xe3++c\x0f\xd2\xe7&\x89\x18TR\xcb*\x91\xc3\x00\x00\u07d4<\xf9\xa1\xd4e\xe7\x8bp9\xe3iDx\xe2b{6\xfc\xd1A\x89J`S*\xd5\x1b\xf0\x00\x00\u07d4<\xfb\xf0fVYpc\x9e\x13\r\xf2\xa7\xd1k\x0e\x14\xd6\t\x1c\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94=\th\x8d\x93\xad\a\xf3\xab\xe6\x8cr'#\xcdh\t\x90C^\x8a\x06ZL\xe9\x9fv\x9en\x00\x00\u07d4=1X{_\u0546\x98Ex\x87%\xa6c)\nI\xd3g\x8c\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4=?\xadI\xc9\xe5\xd2u\x9c\x8e\x8eZzM`\xa0\xdd\x13V\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=WO\xcf\x00\xfa\xe1\u064c\u023f\x9d\u07e1\xb3\x95;\x97A\xbc\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4=Z\x8b+\x80\xbe\x8b5\xd8\xec\xf7\x89\xb5\xedz\au\xc5\al\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=f\xcdK\xd6M\\\x8c\x1b^\xea(\x1e\x10m\x1cZ\xad#s\x89i\xc4\xf3\xa8\xa1\x10\xa6\x00\x00\u0794=j\xe0S\xfc\xbc1\x8do\xd0\xfb\xc3S\xb8\xbfT.h\r'\x88\xc6s\xce<@\x16\x00\x00\u07d4=o\xf8,\x93w\x05\x9f\xb3\r\x92\x15r?`\xc7u\u0211\xfe\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4=y\xa8S\xd7\x1b\xe0b\x1bD\xe2\x97Yel\xa0u\xfd\xf4\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=~\xa5\xbf\x03R\x81\x00\xed\x8a\xf8\xae\xd2e>\x92\x1bng%\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\x81?\xf2\xb6\xedW\xb97\u06bf+8\x1d\x14\x8aA\x1f\xa0\x85\x89\x05k\xc7^-c\x10\x00\x00\u07d4=\x88\x143\xf0J}\r'\xf8ID\xe0\x8aQ-\xa3UR\x87\x89A\rXj \xa4\xc0\x00\x00\u07d4=\x89\xe5\x05\xcbF\xe2\x11\xa5?2\xf1g\xa8w\xbe\xc8\u007fK\n\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94=\x8d\a#r\x1es\xa6\xc0\xd8`\xaa\x05W\xab\xd1L\x1e\xe3b\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4=\x8f9\x88\x1b\x9e\xdf\xe9\x12'\xc3?\xa4\xcd\xd9\x1eg\x85D\xb0\x89\x04\xab\a\xbaC\xad\xa9\x80\x00\u07d4=\x9dk\xe5\u007f\xf8>\x06Y\x85fO\x12VD\x83\xf2\xe6\x00\xb2\x89n\xac\xe4?#\xbd\x80\x00\x00\u07d4=\xa3\x9c\xe3\xefJz9f\xb3.\xe7\xeaN\xbc#5\xa8\xf1\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=\xaa\x01\u03b7\x0e\xaf\x95\x91\xfaR\x1b\xa4\xa2~\xa9\xfb\x8e\xdeJ\x89Zc\xd2\u027cvT\x00\x00\u07d4=\xb5\xfejh\xbd6\x12\xac\x15\xa9\x9aa\xe5U\x92\x8e\xec\xea\xf3\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4=\xb9\xed\u007f\x02L~&7/\xea\xcf+\x05\b\x03D^8\x10\x89E\xb1H\xb4\x99j0\x00\x00\u07d4=\xbf\r\xbf\xd7x\x90\x80\x053\xf0\x9d\xea\x83\x01\xb9\xf0%\u04a6\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\xce\U0005c18b\x15\xd3N\xdaBn\xc7\xe0K\x18\xb6\x01p\x02\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94=\xd1.Uj`76\xfe\xbaJo\xa8\xbdJ\xc4]f*\x04\x8a#u{\x91\x83\xe0x(\x00\x00\u07d4=\u078b\x15\xb3\u033a\xa5x\x01\x12\xc3\xd6t\xf3\x13\xbb\xa6\x80&\x89`\x1dQZ>O\x94\x00\x00\xe0\x94=\xde\xdb\xe4\x89#\xfb\xf9\xe56\xbf\x9f\xfb\aG\xc9\xcd\u04de\xef\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4=\xea\xe43'\x91?b\x80\x8f\xaa\x1bbv\xa2\xbdch\xea\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4=\xf7b\x04\x9e\u068a\u0192}\x90Lz\xf4/\x94\xe5Q\x96\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\x04\r@\u02c0\xba\x01%\xf3\xb1_\xde\xfc\xc8?0\x05\xda\x1b\x898E$\xccp\xb7x\x00\x00\u07d4>\v\x8e\xd8n\xd6i\xe1'#\xafur\xfb\xac\xfe\x82\x9b\x1e\x16\x89QM\xe7\xf9\xb8\x12\xdc\x00\x00\xe0\x94>\f\xbejm\xcba\xf1\x10\xc4[\xa2\xaa6\x1d\u007f\xca\xd3\xdas\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4>\x19KN\xce\xf8\xbbq\x1e\xa2\xff$\xfe\xc4\xe8{\xd02\xf7\u0449\x8b\x9d\xc1\xbc\x1a\x03j\x80\x00\xe0\x94>\x1b\"0\xaf\xbb\xd3\x10\xb4\x92jLwmZ\u705cf\x1d\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4>\x1cS0\x0eL\x16\x89\x12\x16<~\x99\xb9]\xa2h\xad(\n\x896b2\\\u044f\xe0\x00\x00\u07d4>\x1c\x96 c\xe0\xd5)YA\xf2\x10\u0723\xabS\x1e\xec\x88\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4>,\xa0\xd24\xba\xf6\a\xadFj\x1b\x85\xf4\xa6H\x8e\xf0\n\xe7\x89\x04\xda!\xa3H=V\x80\x00\u07d4>/&#^\x13zs$\xe4\xdc\x15K]\xf5\xafF\xea\x1aI\x89\x017\xaa\xd8\x03-\xb9\x00\x00\xe0\x94>1a\xf1\xea/\xbf\x12ny\xda\x18\x01\u0695\x12\xb3y\x88\u024a\nm\xd9\f\xaeQ\x14H\x00\x00\xe0\x94>6\xc1rS\xc1\x1c\xf3\x89t\xed\r\xb1\xb7Y\x16\r\xa67\x83\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4><\u04fe\xc0e\x91\xd64o%Kb\x1e\xb4\x1c\x89\x00\x8d1\x895\u07fe\u069f74\x00\x00\u07d4>E\xbdU\u06d0`\xec\xed\x92;\xb9\xcbs<\xb3W?\xb51\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4>M\x13\xc5Z\x84\xe4n\xd7\xe9\u02d0\xfd5^\x8a\u0651\u33c965\u026d\xc5\u07a0\x00\x00\u07d4>N\x92e\"<\x9782L\xf2\v\xd0`\x06\xd0\a>\u06cc\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94>O\xbdf\x10\x15\xf6F\x1e\xd6s\\\xef\xef\x01\xf3\x14E\xde:\x8a\x03n4)\x98\xb8\xb0 \x00\x00\xe0\x94>S\xff!\a\xa8\u07be3(I:\x92\xa5\x86\xa7\xe1\xf4\x97X\x8a\x04\xe6\x9c*q\xa4\x05\xab\x00\x00\u07d4>Z9\xfd\xdap\xdf\x11&\xab\r\u011asx1\x1aSz\x1f\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\xe0\x94>Z\xbd\t\xceZ\xf7\xba\x84\x87\xc3Y\xe0\xf2\xa9:\x98k\v\x18\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4>\\\xb8\x92\x8cAx%\xc0:;\xfc\xc5!\x83\xe5\xc9\x1eB\u05c9\xe71\xd9\xc5,\x96/\x00\x00\u07d4>^\x93\xfbL\x9c\x9d\x12F\xf8\xf2G5\x8e\"\xc3\xc5\xd1{j\x89\b!\xab\rD\x14\x98\x00\x00\u07d4>a\x83P\xfa\x01ez\xb0\xef>\xba\xc8\xe3p\x12\xf8\xfc+o\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d4>c\xce;$\xca(e\xb4\u0166\x87\xb7\xae\xa3Y~\xf6\xe5H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>f\xb8GiVj\xb6yE\xd5\xfa\x8175V\xbc\u00e1\xfa\x89\b=lz\xabc`\x00\x00\xe0\x94>v\xa6-\xb1\x87\xaat\xf68\x17S;0l\xea\xd0\xe8\u03be\x8a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4>z\x96k]\xc3W\xff\xb0~\x9f\xe0g\xc4W\x91\xfd\x8e0I\x89\x034-`\xdf\xf1\x96\x00\x00\xe0\x94>\x81w!u#~\xb4\xcb\xe0\xfe-\xca\xfd\xad\xff\xebj\x19\x99\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4>\x83I\xb6\u007fWED\x9fe\x93g\u066dG\x12\xdb[\x89Z\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4>\x83TO\x00\x82U%r\u01c2\xbe\xe5\xd2\x18\xf1\xef\x06J\x9d\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4>\x84\xb3\\[\"ePpa\xd3\vo\x12\xda\x03?\xe6\xf8\xb9\x89a\t=|,m8\x00\x00\u07d4>\x86A\xd4\x87E\xba2/_\xd6\xcbP\x12N\xc4f\x88\u01e6\x9a\u007f\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4>\x91N0\x18\xac\x00D\x93A\u011d\xa7\x1d\x04\xdf\xee\xedb!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4>\x94\x10\u04f9\xa8~\xd5\xe4Q\xa6\xb9\x1b\xb8\x92?\xe9\x0f\xb2\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4>\x94\xdfS\x13\xfaR\x05p\xef#+\xc31\x1d_b/\xf1\x83\x89lk\x93[\x8b\xbd@\x00\x00\u0794>\x9b4\xa5\u007f3u\xaeY\xc0\xa7^\x19\u0136A\"\x8d\x97\x00\x88\xf8i\x93)g~\x00\x00\u07d4>\xad\xa8\xc9/V\x06~\x1b\xb7<\xe3x\xdaV\xdc,\xdf\xd3e\x89w\xcd\xe9:\xeb\rH\x00\x00\xe0\x94>\xaf\by\xb5\xb6\xdb\x15\x9bX\x9f\x84W\x8bjt\xf6\xc1\x03W\x8a\x01\x898\xb6q\xfae\xa2\x80\x00\u07d4>\xaf1k\x87a]\x88\xf7\xad\xc7|X\xe7\x12\xedMw\x96k\x89\x05m\xbcL\xee$d\x80\x00\u07d4>\xb8\xb3;!\xd2<\u0686\xd8(\x88\x84\xabG\x0e\x16F\x91\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4>\xb9\xef\x06\xd0\xc2Y\x04\x03\x19\x94~\x8czh\x12\xaa\x02S\u0609\t\r\x97/22<\x00\x00\u07d4>\u030e\x16h\xdd\xe9\x95\xdcW\x0f\xe4\x14\xf4B\x11\xc54\xa6\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\u03752\xe3\x97W\x96b\xb2\xa4aA\u73c25\x93j_\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4>\xeeo\x1e\x966\vv\x89\xb3\x06\x9a\xda\xf9\xaf\x8e\xb6\f\u404965\u026d\xc5\u07a0\x00\x00\xe0\x94?\b\u066d\x89O\x81>\x8e!H\xc1`\xd2K5:\x8et\xb0\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4?\f\x83\xaa\xc5qybsN\\\xea\xea\xec\u04db(\xad\x06\xbe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94?\x10\x80\x02\x82\u0477\xdd\u01cf\xa9-\x820\aN\x1b\xf6\xae\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4?\x123qO M\xe9\xdeN\xe9m\a;6\x8d\x81\x97\x98\x9f\x89\x02\x17\xc4\x10t\xe6\xbb\x00\x00\u07d4?\x17:\xa6\xed\xf4i\u0445\xe5\x9b\xd2j\xe4#k\x92\xb4\xd8\xe1\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4?\x1b\xc4 \xc5<\x00,\x9e\x90\x03|D\xfej\x8e\xf4\xdd\xc9b\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4?#a\b\xee\xc7\"\x89\xba\u00e6\\\u0483\xf9^\x04\x1d\x14L\x8964\xbf9\xab\x98x\x80\x00\u07d4?-\xa0\x93\xbb\x16\xeb\x06O\x8b\xfa\x9e0\xb9)\xd1_\x8e\x1cL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?-\xd5]\xb7\xea\xb0\xeb\xeee\xb3>\xd8 ,\x1e\x99.\x95\x8b\x89,s\xc97t,P\x00\x00\u07d4?/8\x14\x91y|\xc5\xc0\u0502\x96\xc1O\xd0\xcd\x00\xcd\xfa-\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4?0\u04fc\x9f`\"2\xbcrB\x88\xcaF\xcd\v\a\x88\xf7\x15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4?<\x8ea\xe5`L\xef\x06\x05\xd46\xdd\"\xac\u0346\"\x17\xfc\x89Hz\x9a0E9D\x00\x00\u07d4??F\xb7\\\xab\xe3{\xfa\u0307`(\x1fCA\xca\u007fF=\x89 \xacD\x825\xfa\xe8\x80\x00\u07d4?G)c\x19x\x83\xbb\xdaZ\x9b}\xfc\xb2-\xb1\x14@\xad1\x89\x1a\x19d<\xb1\xef\xf0\x80\x00\u07d4?L\xd19\x9f\x8a4\xed\u06da\x17\xa4q\xfc\x92+Xp\xaa\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?U\x1b\xa9<\xd5F\x93\xc1\x83\xfb\x9a\xd6\re\xe1`\x96s\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94?bzv\x9ej\x95\x0e\xb8p\x17\xa7\u035c\xa2\bq\x13h1\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4?m\xd3e\x0e\xe4(\u0737u\x95S\xb0\x17\xa9j\x94(j\u0249Hz\x9a0E9D\x00\x00\u07d4?tr7\x80o\xed?\x82\x8ahR\xeb\bg\xf7\x90'\xaf\x89\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4?u\xaea\xcc\x1d\x80Be;[\xae\xc4D>\x05\x1c^z\xbd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4?\xb7\u0457\xb3\xbaO\xe0E\xef\xc2=P\xa1E\x85\xf5X\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94?\xbc\x1eE\x18\xd74\x00\xc6\xd0F5\x949\xfbh\xea\x1aI\xf4\x8a\x03y\v\xb8U\x13v@\x00\x00\u07d4?\xbe\xd6\xe7\xe0\u029c\x84\xfb\xe9\xeb\u03ddN\xf9\xbbIB\x81e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\u043bGy\x8c\xf4L\u07feM3=\xe67\xdfJ\x00\xe4\\\x89\x05lUy\xf7\"\x14\x00\x00\xe0\x94?\xe4\x0f\xbd\x91\x9a\xad(\x18\xdf\x01\xeeM\xf4lF\x84*\xc59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4?\xe8\x01\xe6\x135\xc5\x14\r\xc7\xed\xa2\xefR\x04F\nP\x120\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\xf86\xb6\xf5{\x90\x1bD\f0\xe4\xdb\xd0e\xcf7\xd3\u050c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?\xfc\xb8p\xd4\x02=%]Qg\u0625\a\xce\xfc6kh\xba\x89#4^\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4@s\xfaI\xb8q\x17\u02d0\x8c\xf1\xabQ-\xa7T\xa92\xd4w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4@\x8ai\xa4\a\x15\xe1\xb3\x13\xe15N`\b\x00\xa1\xe6\xdc\x02\xa5\x89\x01\u7e11\u0312T\x00\x00\u07d4@\x9b\xd7P\x85\x82\x1c\x1d\xe7\f\xdc;\x11\xff\xc3\xd9#\xc7@\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\x9dZ\x96.\xde\uefa1x\x01\x8c\x0f8\xb9\u0372\x13\xf2\x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4@\xa31\x19[\x97s%\u00aa(\xfa/B\xcb%\xec<%<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4@\xa7\xf7(g\xa7\u0706w\v\x16+uW\xa44\xedP\xcc\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xab\n>\x83\xd0\u022c\x93f\x91\x05 \xea\xb1w+\xac;\x1a\x894\xf1\f-\xc0^|\x00\x00\u07d4@\xabf\xfe!>\xa5l:\xfb\x12\xc7[\xe3?\x8e2\xfd\b]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94@\xadt\xbc\v\xce*E\xe5/6\xc3\u07bb\x1b:\xda\x1bv\x19\x8a\x01p\x16-\xe1\t\xc6X\x00\x00\u07d4@\u03c9\x05\x91\xea\u484f\x81*)T\xcb)_c3'\xe6\x89\x02\x9b\xf76\xfcY\x1a\x00\x00\u07d4@\u03d0\xef[v\x8c]\xa5\x85\x00,\xcb\xe6avP\xd8\xe87\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94@\xd4]\x9dv%\xd1QV\xc92\xb7q\xca{\x05'\x13\tX\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4@\xdb\x1b\xa5\x85\xce4S\x1e\xde\xc5IHI9\x13\x81\xe6\xcc\u04c9a\t=|,m8\x00\x00\xe0\x94@\xdfI^\xcf?\x8bL\xef*l\x18\x99W$\x8f\u813c+\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4@\xe0\xdb\xf3\xef\uf404\xea\x1c\xd7\xe5\x03\xf4\v;J\x84C\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\xe2D\n\xe1B\u02006j\x12\xc6\xd4\x10/K\x844\xb6*\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xe3\u0083\xf7\xe2M\xe0A\f\x12\x1b\xee`\xa5`\u007f>)\xa6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94@\xeaPD\xb2\x04\xb20v\xb1\xa5\x80;\xf1\xd3\f\x0f\x88\x87\x1a\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94@\xed\xdbD\x8di\x0e\xd7.\x05\xc2%\xd3O\xc85\x0f\xa1\xe4\u014a\x01{x\x83\xc0i\x16`\x00\x00\xe0\x94@\xf4\xf4\xc0ls,\xd3[\x11\x9b\x89;\x12~}\x9d\aq\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\x01\x0f\u023a\xf8C}\x17\xa0Ci\x80\x9a\x16\x8a\x17\xcaV\xfb\x89\x05k\xc7^-c\x10\x00\x00\u07d4A\x03)\x96q\xd4gc\x97\x8f\xa4\xaa\x19\xee4\xb1\xfc\x95'\x84\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4A\x03<\x1bm\x05\xe1\u0289\xb0\x94\x8f\xc6DS\xfb\xe8z\xb2^\x89Hz\x9a0E9D\x00\x00\u07d4A\t\x8a\x81E#\x17\xc1\x9e>\xef\v\xd1#\xbb\xe1x\xe9\xe9\u0289\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4A\x16\x10\xb1x\xd5a}\xfa\xb94\u0493\xf5\x12\xa9>\\\x10\xe1\x89\t79SM(h\x00\x00\u07d4A\x1c\x83\x1c\xc6\xf4O\x19e\xecWW\xabN[<\xa4\xcf\xfd\x1f\x89\x17\n\x0fP@\xe5\x04\x00\x00\xe0\x94A*h\xf6\xc6EU\x9c\xc9w\xfcId\x04z \x1d\x1b\xb0\xe2\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4A?K\x02f\x9c\xcf\xf6\x80k\xc8&\xfc\xb7\xde\xca;\x0e\xa9\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4AE\x99\t.\x87\x9a\xe2Sr\xa8MsZ\xf5\xc4\xe5\x10\xcdm\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4AHV\x12\xd04F\xecL\x05\xe5$NV?\x1c\xba\xe0\xf1\x97\x894\x95tD\xb8@\xe8\x00\x00\u07d4A]\tj\xb0b\x93\x18?<\x03=%\xf6\xcfqx\xac;\u01c9\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4Af\xfc\b\u0285\xf7f\xfd\xe81F\x0e\x9d\xc9<\x0e!\xaal\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ag\x84\xaf`\x960\xb0p\u051a\x8b\xcd\x12#\\d(\xa4\b\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Ag\xcdH\xe73A\x8e\x8f\x99\xff\xd14\x12\x1cJJ\xb2x\u0109\xc5S%\xcat\x15\xe0\x00\x00\u07d4Al\x86\xb7 \x83\xd1\xf8\x90}\x84\xef\xd2\xd2\u05c3\xdf\xfa>\xfb\x89lj\xccg\u05f1\xd4\x00\x00\u07d4AsA\x9d\\\x9fc)U\x1d\xc4\xd3\xd0\u03ac\x1bp\x1b\x86\x9e\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4At\xfa\x1b\xc1*;q\x83\u02eb\xb7z\vYU{\xa5\xf1\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4Axj\x10\xd4G\xf4\x84\xd32D\u0337\xfa\u034bB{[\x8c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Az<\u0454\x96S\nmB\x04\u00f5\xa1|\xe0\xf2\a\xb1\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4A~N&\x88\xb1\xfdf\xd8!R\x9eF\xedOB\xf8\xb3\xdb=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94A\x9aq\xa3l\x11\xd1\x05\xe0\xf2\xae\xf5\xa3\xe5\x98\a\x8e\x85\xc8\v\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94A\x9b\xdes\x16\xcc\x1e\u0495\u0205\xac\xe3B\u01db\xf7\xee3\xea\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4A\xa2\xf2\xe6\xec\xb8c\x94\xec\x0e3\x8c\x0f\xc9~\x9cU\x83\xde\u0489l\xee\x06\u077e\x15\xec\x00\x00\u07d4A\xa8\u0083\x00\x81\xb1\x02\xdfn\x011e|\a\xabc[T\u0389lj\xccg\u05f1\xd4\x00\x00\u07d4A\xa8\xe26\xa3\x0emc\xc1\xffdM\x13*\xa2\\\x89S~\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4A\xa9\xa4\x04\xfc\x9f[\xfe\xe4\x8e\xc2e\xb1%#3\x8e)\xa8\xbf\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4A\xad6\x9fu\x8f\xef8\xa1\x9a\xa3\x14\x93y\x83,\x81\x8e\xf2\xa0\x8966\x9e\xd7t}&\x00\x00\u07d4A\xb2\xd3O\xde\v\x10)&+Ar\xc8\x1c\x15\x90@[\x03\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4A\xb2\xdb\u05dd\u069b\x86Ojp0'T\x19\u00dd>\xfd;\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4A\xc3\xc26u4\xd1;\xa2\xb3?\x18\\\xdb\xe6\xacC\xc2\xfa1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4A\u02d8\x96D_p\xa1\n\x14!R\x96\xda\xf6\x14\xe3,\xf4\u0549g\x8a\x93 b\xe4\x18\x00\x00\u07d4A\xcey\x95\t5\xcf\xf5[\xf7\x8eL\xce\xc2\xfec\x17\x85\u06d5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4A\u04f71\xa3&\xe7hX\xba\xa5\xf4\xbd\x89\xb5{6\x93#C\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94A\xe4\xa2\x02u\xe3\x9b\xdc\xef\xebe\\\x03\"tKvQ@\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\xed-\x8ep\x81H,\x91\x9f\xc2=\x8f\x00\x91\xb3\xc8,F\x85\x89F:\x1ev[\u05ca\x00\x00\xe0\x94A\xf2~tK\u049d\xe2\xb0Y\x8f\x02\xa0\xbb\x9f\x98\xe6\x81\ua90a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4A\xf4\x89\xa1\xect{\u009c>_\x9d\x8d\xb9xw\xd4\u0474\xe9\x89\a?u\u0460\x85\xba\x00\x00\u07d4B\x0f\xb8n}+Q@\x1f\xc5\xe8\xc7 \x15\xde\xcbN\xf8\xfc.\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\x16\x84\xba\xa9\xc0\xb4\xb5\xf5S8\xe6\xf6\xe7\xc8\xe1F\xd4\x1c\xb7\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4B9\x96Y\xac\xa6\xa5\xa8c\xea\"E\xc93\xfe\x9a5\xb7\x88\x0e\x89n\xce2\xc2l\x82p\x00\x00\xe0\x94B;\xcaG\xab\xc0\fpW\xe3\xad4\xfc\xa6>7_\xbd\x8bJ\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4B<1\a\xf4\xba\xceANI\x9cd9\nQ\xf7F\x15\xca^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B<\xc4YL\xf4\xab\xb66\x8d\xe5\x9f\u04b1#\a4a!C\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BD\xf13\x11X\xb9\xce&\xbb\xe0\xb9#k\x92\x03\xca5\x144\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794BQw\xebt\xad\n\x9d\x9aWR\"\x81G\xeemcV\xa6\u6239\x8b\xc8)\xa6\xf9\x00\x00\u07d4BW%\xc0\xf0\x8f\b\x11\xf5\xf0\x06\xee\xc9\x1c\\\\\x12k\x12\xae\x89\b!\xab\rD\x14\x98\x00\x00\xe0\x94BX\xfdf/\xc4\xce2\x95\xf0\xd4\xed\x8f{\xb1D\x96\x00\xa0\xa9\x8a\x01lE.\xd6\b\x8a\xd8\x00\x00\xe0\x94B\\\x18\x16\x86\x8fww\xcc+\xa6\xc6\u048c\x9e\x1eylR\xb3\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\\3\x8a\x13%\xe3\xa1W\x8e\xfa)\x9eW\u0646\xebGO\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BbY\xb0\xa7Vp\x1a\x8bf5(R!V\xc0(\x8f\x0f$\x8a\x02\x18\xae\x19k\x8dO0\x00\x00\u07d4Bm\x15\xf4\a\xa0\x115\xb1:kr\xf8\xf2R\v51\xe3\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Box\xf7\r\xb2Y\xac\x854\x14[)4\xf4\xef\x10\x98\xb5\u0609\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4Bs-\x8e\xf4\x9f\xfd\xa0K\x19x\x0f\xd3\xc1\x84i\xfb7A\x06\x89\x17\v\x00\xe5\u4a7e\x00\x00\u07d4Bt\x17\xbd\x16\xb1\xb3\xd2-\xbb\x90-\x8f\x96W\x01o$\xa6\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Btj\xee\xa1O'\xbe\xff\f\r\xa6BS\xf1\xe7\x97\x18\x90\xa0\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4B{F*\xb8NP\x91\xf4\x8aF\xeb\f\u0712\xdd\xcb&\xe0x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B~GQ\u00fa\xbex\xcf\xf8\x83\b\x86\xfe\xbc\x10\xf9\x90\x8dt\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94B~\xc6h\xac\x94\x04\xe8\x95\u0306\x15\x11\xd1b\nI\x12\xbe\x98\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4B\x80\xa5\x8f\x8b\xb1\v\x94@\u0794\xf4+OY! \x82\x01\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B\x8a\x1e\xe0\xed3\x1dyR\u033e\x1cyt\xb2\x85+\u0453\x8a\x89w\xb7JN\x8d\xe5e\x00\x00\u0794B\x9c\x06\xb4\x87\xe8Tj\xbd\xfc\x95\x8a%\xa3\xf0\xfb\xa5?o\x00\x88\xbbdJ\xf5B\x19\x80\x00\xe0\x94B\xa9\x8b\xf1`'\xceX\x9cN\xd2\xc9X1\xe2rB\x05\x06N\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\xc6\xed\xc5\x15\xd3UW\x80\x8d\x13\xcdD\xdc\xc4@\v%\x04\xe4\x89\n\xba\x14\u015b\xa72\x00\x00\u07d4B\xce\xcf\u0492\x10y\xc2\xd7\xdf?\b\xb0z\xa3\xbe\xee^!\x9a\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\u04669\x9b0\x16\xa8Y\u007f\x8bd\t'\xb8\xaf\xbc\xe4\xb2\x15\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4B\xd3I@\xed\xd2\xe7\x00]F\xe2\x18\x8eL\xfe\u0383\x11\xd7M\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4B\u04e5\xa9\x01\xf2\xf6\xbd\x93V\xf1\x12\xa7\x01\x80\xe5\xa1U\v`\x892$\xf4'#\xd4T\x00\x00\u07d4B\u05b2c\xd9\xe9\xf4\x11lA\x14$\xfc\x99Ux;\xa1\xc5\x1b\x81\x0f\xc4g\u057aM\xeaB\xf7\xa9\x88^i\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94C>\xb9J3\x90\x86\xed\x12\u067d\xe9\xcd\x1dE\x86\x03\xc9}\u058a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4CI\"Zb\xf7\n\xeaH\n\x02\x99\x15\xa0\x1eSy\xe6O\xa5\x89\x8c\xd6~#4\xc0\xd8\x00\x00\u07d4CT\"\x1eb\xdc\t\xe6@d6\x16:\x18^\xf0m\x11J\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94CTC\xb8\x1d\xfd\xb9\xbd\x8cg\x87\xbc%\x18\xe2\xd4~W\xc1_\x8a\x01C\x8d\x93\x97\x88\x1e\xf2\x00\x00\u07d4Ca\u0504o\xaf\xb3w\xb6\xc0\xeeI\xa5\x96\xa7\x8d\xdf5\x16\xa3\x89\xc2\x12z\xf8X\xdap\x00\x00\xe0\x94Cd0\x9a\x9f\xa0p\x95`\x0fy\xed\xc6Q \xcd\xcd#\xdcd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Cg\xaeK\f\xe9d\xf4\xa5J\xfdK\\6\x84\x96\xdb\x16\x9e\x9a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Ct\x89(\xe8\xc3\xecD6\xa1\u0412\xfb\xe4:\xc7I\xbe\x12Q\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4Cv{\xf7\xfd*\xf9[r\xe91-\xa9D<\xb1h\x8eCC\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94Cy\x838\x8a\xb5\x9aO\xfc!_\x8e\x82iF\x10)\xc3\xf1\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4C\x89\x8cI\xa3MP\x9b\xfe\xd4\xf7`A\xee\x91\xca\xf3\xaaj\xa5\x89\x10CV\x1a\x88)0\x00\x00\u07d4C\x8c/T\xff\x8eb\x9b\xab6\xb1D+v\v\x12\xa8\x8f\x02\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\x98b\x8e\xa6c-9>\x92\x9c\xbd\x92\x84d\xc5h\xaaJ\f\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4C\x9d//Q\x10\xa4\u054b\x17W\x93P\x15@\x87@\xfe\xc7\xf8\x89\u03e5\xc5\x15\x0fL\x88\x80\x00\u07d4C\x9d\xee?vy\xff\x100s?\x93@\xc0\x96hkI9\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xb0y\xba\xf0ry\x99\xe6k\xf7C\u057c\xbfwl;\t\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xbc-M\xdc\xd6X;\xe2\u01fc\tK(\xfbr\xe6+\xa8;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xc7\xeb\u0173\xe7\xaf\x16\xf4}\xc5az\xb1\x0e\x0f9\xb4\xaf\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4C\u02d6R\x81\x8coMg\x96\xb0\xe8\x94\t0ly\xdbcI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xcc\b\xd0s*\xa5\x8a\xde\xf7a\x9b\xedFU\x8a\xd7wAs\x89\xf0\xe7\u0730\x12*\x8f\x00\x00\xe0\x94C\u0567\x1c\xe8\xb8\xf8\xae\x02\xb2\xea\xf8\xea\xf2\xca(@\xb9?\xb6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794C\xdb\u007f\xf9Z\bm(\ubff8/\xb8\xfb_#\n^\xbc\u0348\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4C\xe7\xec\x84cX\xd7\xd0\xf97\xad\x1c5\v\xa0i\u05ffr\xbf\x89\x06p\xaeb\x92\x14h\x00\x00\u07d4C\xf1o\x1eu\xc3\xc0j\x94x\xe8\u0157\xa4\n<\xb0\xbf\x04\u0309\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4C\xf4p\xede\x9e)\x91\xc3u\x95~]\xde\u017d\x1d8\"1\x89\x05k\xc7^-c\x10\x00\x00\u07d4C\xf7\xe8n8\x1e\xc5\x1e\u0110m\x14v\u02e9z=\xb5\x84\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4C\xff8t>\xd0\xcdC0\x8c\x06e\t\u030e~r\xc8b\xaa\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94C\xff\x88S\xe9\x8e\xd8@k\x95\x00\n\u0684\x83b\u05a09*\x8a\x04\xae\v\x1cM.\x84\xd0\x00\x00\u07d4D\t\x88f\xa6\x9bh\xc0\xb6\xbc\x16\x82)\xb9`5\x87\x05\x89g\x89\n1\x06+\xee\xedp\x00\x00\u07d4D\x19\xaca\x8d]\xea|\xdc`w o\xb0}\xbd\xd7\x1c\x17\x02\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4D\x1aR\x00\x16a\xfa\xc7\x18\xb2\u05f3Q\xb7\xc6\xfbR\x1az\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94D\x1a\u0282c\x13$\xac\xbf\xa2F\x8b\xda2[\xbdxG{\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4D\x1f7\xe8\xa0)\xfd\x02H/(\x9cI\xb5\xd0m\x00\xe4\b\xa4\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4D \xaa5F[\xe6\x17\xad$\x98\xf3p\xde\n<\xc4\xd20\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4D#/\xf6m\xda\xd1\xfd\x84\x12f8\x006\xaf\xd7\xcf}\u007fB\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D%\rGn\x06$\x84\xe9\b\n9g\xbf:Js*\xd7?\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4D)\xa2\x9f\xee\x19\x84Pg,\f\x1d\a1b%\v\xecdt\x896*\xaf\x82\x02\xf2P\x00\x00\u07d4D5RS\xb2wH\xe3\xf3O\xe9\xca\xe1\xfbq\x8c\x8f$\x95)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D8\xe8\x80\xcb'f\xb0\xc1\u03ae\xc9\xd2A\x8f\u03b9R\xa0D\x89\a?\xa0s\x90?\b\x00\x00\u07d4DL\xafy\xb7\x138\ue6a7\xc73\xb0*\u02a7\xdc\x02YH\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4D\\\xb8\xde^=\xf5 \xb4\x99\xef\u0240\xf5+\xff@\xf5\\v\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Dj\x809\xce\u03dd\xceHy\xcb\xca\xf3I;\xf5E\xa8\x86\x10\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4Dt)\x9d\x0e\xe0\x90\u0710x\x9a\x14\x86H\x9c=\rd^m\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\x8b\xf4\x10\xad\x9b\xbc/\xec\xc4P\x8d\x87\xa7\xfc.K\x85a\xad\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4D\x90\x1e\r\x0e\b\xac=^\x95\xb8\xec\x9d^\x0f\xf5\xf1.\x03\x93\x89\x16\xa1\xf9\xf5\xfd}\x96\x00\x00\xe0\x94D\x93\x12<\x02\x1e\xce;3\xb1\xa4R\xc9&\x8d\xe1@\a\xf9\u04ca\x01je\x02\xf1Z\x1eT\x00\x00\xe0\x94D\x9a\xc4\xfb\xe3\x83\xe3g8\x85^6JW\xf4q\xb2\xbf\xa11\x8a)\xb7d2\xb9DQ \x00\x00\u07d4D\xa0\x1f\xb0J\xc0\xdb,\xce]\xbe(\x1e\x1cF\xe2\x8b9\xd8x\x89lj\xccg\u05f1\xd4\x00\x00\u07d4D\xa6=\x18BE\x87\xb9\xb3\a\xbf\xc3\xc3d\xae\x10\xcd\x04\xc7\x13\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94D\xa8\x98\x9e20\x81!\xf7$f\x97\x8d\xb3\x95\xd1\xf7l:K\x8a\x01\x88P)\x9fB\xb0j\x00\x00\u07d4D\xc1\x11\v\x18\x87\x0e\xc8\x11x\xd9=!X8\xc5Q\u050ed\x89\n\xd6\xf9\x85\x93\xbd\x8f\x00\x00\u07d4D\xc1Ge\x12|\xde\x11\xfa\xb4l],\xf4\u0532\x89\x00#\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94D\xc5N\xaa\x8a\xc9@\xf9\xe8\x0f\x1et\xe8/\xc1O\x16v\x85j\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4D\xcdwSZ\x89?\xa7\xc4\xd5\xeb:$\x0ey\u0419\xa7--\x89,s\xc97t,P\x00\x00\u07d4D\u07faP\xb8)\xbe\xcc_O\x14\u0470J\xab3 \xa2\x95\xe5\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\xe2\xfd\xc6y\xe6\xbe\xe0\x1e\x93\xefJ:\xb1\xbc\xce\x01*\xbc|\x89\x16=\x19I\x00\xc5E\x80\x00\xe0\x94D\xf6/*\xaa\xbc)\xad:k\x04\xe1\xffo\x9c\xe4R\xd1\xc1@\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4D\xff\xf3{\xe0\x1a8\x88\u04f8\xb8\u1200\xa7\xdd\xef\xee\xea\u04c9\x0e\f[\xfc}\xae\x9a\x80\x00\u07d4E\x06\xfe\x19\xfaK\x00k\xaa9\x84R\x9d\x85\x16\xdb++P\xab\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\x1b6\x99G[\xed]y\x05\xf8\x90Z\xa3Eo\x1e\u05c8\xfc\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u0794E\x1bpp%\x9b\u06e2q\x00\xe3n#B\x8aS\xdf\xe3\x04\u9239\x8b\xc8)\xa6\xf9\x00\x00\u07d4E'+\x8fb\xe9\xf9\xfa\x8c\xe0D \u1ba3\xeb\xa9hn\xac\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94E+d\u06ce\xf7\xd6\u07c7\u01c8c\x9c\"\x90\xbe\x84\x82\xd5u\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E>5\x9a3\x97\x94LZ'Z\xb1\xa2\xf7\n^Z?i\x89\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4EI\xb1Yy%_~e\xe9\x9b\rV\x04\u06d8\xdf\xca\u023f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4EKa\xb3D\xc0\xef\x96Qy#\x81U\xf2w\u00c2\x9d\v8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94EO\x01A\xd7!\xd3<\xbd\xc4\x10\x18\xbd\x01\x11\x9a\xa4xH\x18\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4ES3\x90\xe3@\xfe\r\xe3\xb3\xcf_\xb9\xfc\x8e\xa5R\xe2\x9eb\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4ES\x96\xa4\xbb\u067a\u8bdf\xb7\xc4\xd6MG\x1d\xb9\xc2E\x05\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4E[\x92\x96\x92\x1at\xd1\xfcAa\u007fC\xb80>o>\xd7l\x89\u3bb5sr@\xa0\x00\x00\u07d4E\\\xb8\xee9\xff\xbcu#1\xe5\xae\xfcX\x8e\xf0\xeeY4T\x8965F:x\r\xef\x80\x00\u07d4Ej\u0b24\x8e\xbc\xfa\xe1f\x06\x02PR_c\x96^v\x0f\x89\x10CV\x1a\x88)0\x00\x00\u07d4Eo\x8dtf\x82\xb2$g\x93I\x06M\x1b6\x8c|\x05\xb1v\x89\u0213\u041c\x8fQP\x00\x00\u07d4Ep)\xc4i\xc4T\x8d\x16\x8c\xec>e\x87.D(\xd4+g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Eq\xdeg+\x99\x04\xba\xd8t6\x92\xc2\x1cO\xdc\xeaL.\x01\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Ex\x1b\xbew\x14\xa1\xc8\xf7;\x1cty!\xdfO\x84'\x8bp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E{\xce\xf3}\xd3\xd6\v-\xd0\x19\xe3\xfea\xd4k?\x1erR\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94E\x8e<\u025e\x94xD\xa1\x8ejB\x91\x8f\xef~\u007f_^\xb3\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4E\x93\x93\xd6:\x06>\xf3r\x1e\x16\xbd\x9f\xdeE\ue77dw\xfb\x89j\xba\u05a3\xc1S\x05\x00\x00\u07d4E\xa5p\xdc\xc2\t\f\x86\xa6\xb3\xea)\xa6\bc\xdd\xe4\x1f\x13\xb5\x89\f\x9a\x95\xee)\x86R\x00\x00\u07d4E\xa8 \xa0g/\x17\xdct\xa0\x81\x12\xbcd?\xd1\x16w6\u00c9\n\xd6\xc4;(\x15\xed\x80\x00\u07d4E\xb4q\x05\xfeB\xc4q-\xcen*!\xc0[\xff\xd5\xeaG\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\xbb\x82\x96R\u063f\xb5\x8b\x85'\xf0\xec\xb6!\u009e!.\u00c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\xc0\u045f\v\x8e\x05O\x9e\x8986\xd5\xec\xaey\x01\xaf(\x12\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4E\xc4\xec\xb4\xee\x89\x1e\xa9\x84\xa7\xc5\xce\xfd\x8d\xfb\x001\v(P\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4E\u028d\x95f\b\xf9\xe0\n/\x99t\x02\x86@\x88\x84ef\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u0298b\x00;N@\xa3\x17\x1f\xb5\xca\xfa\x90(\xca\xc8\xde\x19\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4E\xd1\xc9\xee\xdf|\xabA\xa7y\x05{y9_T(\xd8\x05(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\u0535M7\xa8\xcfY\x98!#_\x06/\xa9\xd1p\xed\u8909\x11\x90g;_\u0690\x00\x00\xe0\x94E\xdb\x03\xbc\xcf\u05a5\xf4\xd0&k\x82\xa2*6\x87\x92\xc7}\x83\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E\xe3\xa9>r\x14J\u0686\f\xbcV\xff\x85\x14Z\xda8\xc6\u0689WG=\x05\u06ba\xe8\x00\x00\u07d4E\u6378\u06fa\xba_\xc2\xcb3|b\xbc\xd0\xd6\x1b\x05\x91\x89\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u6379L}\n\xb7\xacA\x85zq\xd6qG\x87\x0fNq\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4E\xf4\xfc`\xf0\x8e\xac\xa1\x05\x98\xf03c)\x80\x1e<\x92\xcbF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F\rSU\xb2\xce\xebnb\x10}\x81\xe5\x12p\xb2k\xf4V \x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94F\"O2\xf4\xec\xe5\u0206p\x90\xd4@\x9dU\xe5\v\x18C-\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4F'\xc6\x06\x84&q\xab\u0782\x95\xee]\xd9L\u007fT\x954\xf4\x89\x0f\x89_\xbd\x872\xf4\x00\x00\u07d4F+g\x8bQ\xb5\x84\xf3\xedz\xda\a\v\\\u065c\v\xf7\xb8\u007f\x89\x05k\xc7^-c\x10\x00\x00\u07d4FM\x9c\x89\xcc\xe4\x84\xdf\x00\x02w\x19\x8e\xd8\a_\xa65r\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4FPNj!Z\xc8;\xcc\xf9V\xbe\xfc\x82\xabZg\x93q\u0209\x1c!(\x05\u00b4\xa5\x00\x00\xe0\x94FQ\xdcB\x0e\b\xc3);'\xd2Ix\x90\xebP\":\xe2\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4FS\x1e\x8b\x1b\xde\t\u007f\u07c4\x9dm\x11\x98\x85`\x8a\x00\x8d\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Fb\x92\xf0\xe8\rC\xa7\x87t'u\x90\xa9\xebE\x96\x12\x14\xf4\x894\x95tD\xb8@\xe8\x00\x00\xe0\x94Fb\xa1v^\xe9!\x84-\u0708\x89\x8d\x1d\xc8bu\x97\xbd~\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Fe\xe4s\x96\xc7\u06d7\xeb*\x03\xd9\bc\xd5\u053a1\x9a\x94\x89 \x86\xac5\x10R`\x00\x00\u07d4Fo\xdak\x9bX\xc5S'P0j\x10\xa2\xa8\xc7h\x10;\a\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4Fq$\xae\u007fE/&\xb3\xd5t\xf6\b\x88\x94\xfa]\x1c\xfb;\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u0794Fr*6\xa0\x1e\x84\x1d\x03\xf7\x80\x93^\x91}\x85\u0566z\xbd\x88\xce\xc7o\x0eqR\x00\x00\u07d4Fw\x9aVV\xff\x00\xd7>\xac:\xd0\u00cbl\x850\x94\xfb@\x89\f\x82S\xc9lj\xf0\x00\x00\u07d4Fw\xb0N\x03C\xa3!1\xfdj\xbb9\xb1\xb6\x15k\xba=[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F}Y\x88$\x9ahaG\x16e\x98@\xed\n\xe6\xf6\xf4W\xbc\x89\x15\x01\xa4\x8c\xef\xdf\xde\x00\x00\u07d4F~\x0e\xd5O;v\xae\x066\x17n\aB\b\x15\xa0!sn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F~\xa1\x04E\x82~\xf1\xe5\x02\xda\xf7k\x92\x8a \x9e\r@2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94F\u007f\xbfAD\x16\x00u\u007f\xe1X0\xc8\xcd_O\xfb\xbb\xd5`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94F\x93Xp\x932\xc8+\x88~ \xbc\xdd\xd0\"\x0f\x8e\u06e7\u040a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4F\x97\xba\xaf\x9c\xcb`?\xd3\x040h\x9dCTE\xe9\u024b\xf5\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4F\xa3\v\x8a\x80\x891!tE\xc3\xf5\xa9>\x88,\x03E\xb4&\x89\r\x8d\xb5\xeb\u05f2c\x80\x00\u07d4F\xa40\xa2\u0528\x94\xa0\u062a?\xea\xc6\x156\x14\x15\xc3\xf8\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F\xaaP\x18pg~\u007f\nPHv\xb4\xe8\x80\x1a\n\xd0\x1cF\x89+^:\xf1k\x18\x80\x00\x00\u07d4F\xbf\u0172\a\xeb \x13\xe2\xe6\x0fw_\xec\xd7\x18\x10\u0159\f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4F\xc1\xaa\"D\xb9\u0229W\u028f\xacC\x1b\x05\x95\xa3\xb8h$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4F\xd8\x061(B\x03\xf6(\x8e\xcdNWX\xbb\x9dA\xd0]\xbe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\n\xc5\xd1\xf3\xef\xe2\x8f8\x02\xaf\x92[W\x1ec\x86\x8b9}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\x10\x10\xdaI/@\x18\x83;\b\x8d\x98r\x90\x1e\x06\x12\x91t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4G\x12T\x02e\xcb\xee\u00c4p\"\u015f\x1b1\x8dC@\n\x9e\x89\xbd\xbcA\xe04\x8b0\x00\x00\xe0\x94G\x14\u03e4\xf4k\u05bdps}u\x87\x81\x97\xe0\x8f\x88\xe61\x8a\x02\u007f>\u07f3Nn@\x00\x00\u07d4G H\xcc`\x9a\xeb$!e\uaa87\x05\x85\f\xf3\x12]\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4G!\x92)\xe8\xcdVe\x9ae\u00a9C\xe2\u075a\x8fK\xfd\x89\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4G7\xd0B\xdcj\xe7>\xc7:\xe2Qz\u03a2\xfd\xd9d\x87\u014965\u026d\xc5\u07a0\x00\x00\u07d4GAX\xa1\xa9\xdci<\x13?e\xe4{\\:\xe2\xf7s\xa8o\x89\n\xdaUGK\x814\x00\x00\u07d4GE\xab\x18\x1a6\xaa\x8c\xbf\"\x89\xd0\xc4Qe\xbc~\xbe#\x81\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4GPf\xf9\xad&eQ\x96\xd5SS'\xbb\xeb\x9by)\xcb\x04\x89\xa4\xccy\x95c\u00c0\x00\x00\xe0\x94GR!\x8eT\xdeB?\x86\xc0P\x193\x91z\xea\b\xc8\xfe\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4GZa\x93W-JNY\u05fe\t\u02d6\r\u074cS\x0e/\x89$,\xf7\x8c\xdf\a\xff\x80\x00\u07d4Gd\x8b\xed\x01\xf3\xcd2I\bNc]\x14\u06a9\xe7\xec<\x8a\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4Gh\x84\x10\xff%\xd6T\xd7.\xb2\xbc\x06\xe4\xad$\xf83\xb0\x94\x89\b\xb2\x8da\xf3\u04ec\x00\x00\u07d4GkU\x99\b\x9a?\xb6\xf2\x9clr\xe4\x9b.G@\ua00d\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4Gs\x0f_\x8e\xbf\x89\xacr\xef\x80\xe4l\x12\x19P8\xec\xdcI\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94G{$\xee\u80deO\u045d\x12P\xbd\vfEyJa\u028a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4G\x81\xa1\nM\xf5\uef02\xf4\xcf\xe1\a\xba\x1d\x8av@\xbdf\x89a\t=|,m8\x00\x00\u07d4G\x88Z\xba\xbe\xdfM\x92\x8e\x1c\x88\x83\xa6a\x9cl(\x11\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94G\xe2]\xf8\x82%8\xa8Yk(\xc67\x89kM\x14<5\x1d\x8a\x11\v\xe9\xeb$\xb8\x81P\x00\x00\u07d4G\xf4ik\xd4b\xb2\r\xa0\x9f\xb8>\xd2\x03\x98\x18\xd7v%\xb3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4G\xfe\xf5\x85\x84FRH\xa0\x81\r`F>\xe9>Zn\xe8\u04c9\x0fX\xcd>\x12i\x16\x00\x00\u07d4G\xffo\xebC! `\xbb\x15\x03\u05e3\x97\xfc\b\xf4\xe7\x03R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\xff\xf4,g\x85Q\xd1A\xebu\xa6\xee9\x81\x17\xdf>J\x8d\x89\x05k\xea\xe5\x1f\xd2\xd1\x00\x00\u07d4H\x01\x0e\xf3\xb8\xe9^?0\x8f0\xa8\xcb\u007fN\xb4\xbf`\xd9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4H\n\xf5 v\x00\x9c\xa77\x81\xb7\x0eC\xb9Y\x16\xa6\"\x03\xab\x892\x19r\xf4\b=\x87\x80\x00\u07d4H\x0f1\xb9\x891\x1eA$\u01a7F_ZD\tM6\xf9\u04097\x90\xbb\x85Q7d\x00\x00\xe0\x94H\x11\x15)j\xb7\xdbRI/\xf7\xb6G\xd63)\xfb\\\xbck\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4H\x1e:\x91\xbf\xdc/\x1c\x84(\xa0\x11\x9d\x03\xa4\x16\x01A~\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4H(\xe4\xcb\xe3N\x15\x10\xaf\xb7,+\ueb0aE\x13\xea\xeb\u0649\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94H)\x82\xac\x1f\x1cm\x17!\xfe\xec\u0679\xc9l\xd9I\x80PU\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4H0,1\x1e\xf8\xe5\xdcfAX\xddX<\x81\x19Mn\rX\x89\xb6gl\xe0\xbc\xcb\\\x00\x00\u07d4H;\xa9\x904\xe9\x00\xe3\xae\xdfaI\x9d;+\xce9\xbe\xb7\xaa\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4HT\x8bK\xa6+\xcb/\r4\xa8\x8d\u019ah\x0eS\x9c\xf0F\x89\x05l\xf1\u02fbt2\x00\x00\u07d4Hc\x84\x979&Zc\xb0\xa2\xbf#jY\x13\xe6\xf9Y\xce\x15\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4He\x9d\x8f\x8c\x9a/\xd4Oh\u06a5]#\xa6\b\xfb\xe5\x00\u0709lk\x93[\x8b\xbd@\x00\x00\xe0\x94Hf\x9e\xb5\xa8\x01\u0637_\xb6\xaaX\xc3E\x1bpX\xc2C\xbf\x8a\x06\x8dB\xc18\u06b9\xf0\x00\x00\u07d4Hjl\x85\x83\xa8D\x84\xe3\xdfC\xa1#\x83\u007f\x8c~#\x17\u0409\x11\x87\xc5q\xab\x80E\x00\x00\u07d4Hz\xdf}p\xa6t\x0f\x8dQ\xcb\xddh\xbb?\x91\u0125\xceh\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4H~\x10\x85\x02\xb0\xb1\x89\uf70cm\xa4\xd0\xdbba\xee\xc6\xc0\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94H\x88\xfb%\xcdP\u06f9\xe0H\xf4\x1c\xa4}x\xb7\x8a'\xc7\u064a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u0794H\x934\u00b6\x95\xc8\xee\a\x94\xbd\x86B\x17\xfb\x9f\xd8\xf8\xb15\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4H\xa3\r\xe1\xc9\x19\xd3\xfd1\x80\xe9}_+*\x9d\xbd\x96M-\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4H\xbf\x14\u05f1\xfc\x84\xeb\xf3\xc9k\xe1/{\xce\x01\xaai\xb0>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4H\xc2\ue465\aV\xd8\u039a\xbe\xebu\x89\xd2,o\xee]\xfb\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4H\xc5\u0197\v\x91a\xbb\x1c{z\xdf\xed\x9c\xde\u078a\x1b\xa8d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94H\xd2CKz}\xbb\xff\b\";c\x87\xb0]\xa2\xe5\t1&\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4H\xd4\xf2F\x8f\x96?\u05da\x00a\x98\xbbg\x89]-Z\xa4\u04c9K\xe4\xe7&{j\xe0\x00\x00\u07d4H\xe0\xcb\xd6\u007f\x18\xac\xdbzb\x91\xe1%M\xb3.\trs\u007f\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4H\xf6\n5HO\xe7y+\u030a{c\x93\xd0\u0761\xf6\xb7\x17\x89\xc3(\t>a\xee@\x00\x00\u07d4H\xf8\x83\xe5g\xb46\xa2{\xb5\xa3\x12M\xbc\x84\xde\xc7u\xa8\x00\x89)\xd7n\x86\x9d\u0340\x00\x00\xe0\x94I\x01E\xaf\xa8\xb5E\"\xbb!\xf3R\xf0m\xa5\xa7\x88\xfa\x8f\x1d\x8a\x01\xf4lb\x90\x1a\x03\xfb\x00\x00\u07d4I\t\xb3\x19\x98\xea\xd4\x14\xb8\xfb\x0e\x84k\xd5\xcb\xde995\xbe\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x12\xd9\x02\x93\x16v\xff9\xfc4\xfe<<\xc8\xfb!\x82\xfaz\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4I\x13o\xe6\xe2\x8btS\xfc\xb1kk\xbb\u9aac\xba\x837\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94I\x15a\u06cbo\xaf\xb9\x00~b\xd0P\u0082\xe9,Kk\u020a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4I\x18]\xd7\xc262\xf4lu\x94s\ubb96`\b\xcd5\x98\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4I,\xb5\xf8a\xb1\x87\xf9\xdf!\xcdD\x85\xbe\xd9\vP\xff\xe2-\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4I-\xe4j\xaf\x8f\x1dp\x8dY\u05da\xf1\xd0:\xd2\xcb`\x90/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I.p\xf0M\x18@\x8c\xb4\x1e%`70Pk5\xa2\x87k\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4I:g\xfe#\xde\xccc\xb1\r\xdau\xf3(v\x95\xa8\x1b\u056b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4I=H\xbd\xa0\x15\xa9\xbf\xcf\x16\x03\x93n\xabh\x02L\xe5Q\xe0\x89\x018\xa3\x88\xa4<\x00\x00\x00\xe0\x94IBV\xe9\x9b\x0f\x9c\xd6\xe5\xeb\xca8\x99\x862R\x90\x01e\u020a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4IM\xecM^\xe8\x8a'q\xa8\x15\xf1\xeerd\x94/\xb5\x8b(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I[d\x1b\x1c\u07a3b\u00f4\u02fd\x0f\\\xc5\v\x1e\x17k\x9c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ih\xa2\xce\xdbEuU\xa19)Z\xea(wnT\x00<\x87\x8a\x02#\x1a\xef\u0266b\x8f\x00\x00\u07d4Im6U4S\n_\xc1W|\nRA\u02c8\xc4\xdapr\x89a\t=|,m8\x00\x00\xe0\x94In1\x95\x92\xb3A\xea\xcc\xd7x\u0767\xc8\x19mT\xca\xc7u\x8a\x01\xf5q\x89\x87fKH\x00\x00\u07d4IoXC\xf6\xd2L\u064d%^L#\xd1\xe1\xf0#\"uE\x89_\x17\x9f\u0526\xee\t\x80\x00\xe0\x94Ip\u04ec\xf7+[\x1f2\xa7\x00<\xf1\x02\xc6N\xe0TyA\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\u07d4Iw\xa7\x93\x9d\t9h\x94U\xce&9\xd0\xeeZL\xd9\x10\xed\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4Iy\x19N\xc9\xe9}\xb9\xbe\xe84;|w\xd9\xd7\xf3\xf1\u071f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Iy4c\xe1h\x10\x83\u05ab\xd6\xe7%\u057b\xa7E\xdc\xcd\xe8\x89\x1d\x98\xe9LNG\x1f\x00\x00\u07d4I\x81\xc5\xfff\xccN\x96\x80%\x1f\xc4\xcd/\xf9\a\xcb2xe\x89(\xa8WBTf\xf8\x00\x00\u07d4I\x89\u007f\xe92\xbb\xb3\x15L\x95\u04fc\xe6\xd9;ms)\x04\u0749\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x89\xe1\xab^|\xd0\aF\xb3\x93\x8e\xf0\xf0\xd0d\xa2\x02[\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I\x8a\xbd\xeb\x14\xc2k{r4\xd7\x0f\u03ae\xf3a\xa7m\xffr\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4I\xa6E\xe0f}\xfd{2\xd0u\xcc$g\u074ch\t\a\u0109\a\x06\x01\x95\x8f\u02dc\x00\x00\xe0\x94I\xb7N\x16\x92e\xf0\x1a\x89\xecL\x90r\u0164\xcdr\xe4\xe85\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4I\xbd\xbc{\xa5\xab\xeb\xb68\x9e\x91\xa3(R \xd3E\x1b\xd2S\x8965\u026d\xc5\u07a0\x00\x00\u07d4I\xc9A\xe0\xe5\x01\x87&\xb7)\x0f\xc4s\xb4q\xd4\x1d\xae\x80\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94I\xc9w\x1f\xca\x19\u0579\xd2E\u0211\xf8\x15\x8f\xe4\x9fG\xa0b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4I\xcf\x1eT\xbe61\x06\xb9 r\x9d-\v\xa4o\bg\x98\x9a\x89\x0e\x87?D\x13<\xb0\x00\x00\u07d4I\xd2\u008e\xe9\xbcT^\xaa\xf7\xfd\x14\xc2|@s\xb4\xbb_\x1a\x89O\xe9\xb8\x06\xb4\r\xaf\x00\x00\u07d4I\xdd\xee\x90.\x1d\f\x99\u0471\x1a\xf3\u030a\x96\xf7\x8eM\xcf\x1a\x89\n\u03a5\xe4\xc1\x8cS\x00\x00\u07d4I\xf0(9[Z\x86\xc9\xe0\u007fwxc\x0eL.=7:w\x89\x06\xa7JP8\u06d1\x80\x00\xe0\x94J\x19 5\xe2a\x9b$\xb0p\x9dVY\x0e\x91\x83\xcc\xf2\xc1\u064a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4J@S\xb3\x1d\x0e\xe5\u06ef\xb1\xd0k\u05ec\u007f\xf3\",G\u0589K\xe4\xe7&{j\xe0\x00\x00\u07d4JC\x01p\x15-\xe5\x17&3\u0742b\xd1\a\xa0\xaf\xd9j\x0f\x89\xabM\xcf9\x9a:`\x00\x00\u07d4JG\xfc>\x17\u007fVz\x1e8\x93\xe0\x00\xe3k\xba#R\n\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4JR\xba\xd2\x03W\"\x8f\xaa\x1e\x99k\xedy\f\x93gK\xa7\u0409Hz\x9a0E9D\x00\x00\u07d4JS\xdc\xdbV\xceL\xdc\xe9\xf8.\xc0\xeb\x13\xd6sR\xe7\u020b\x89\u3bb5sr@\xa0\x00\x00\u07d4J_\xae;\x03r\xc20\xc1%\xd6\xd4p\x14\x037\xab\x91VV\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4Jq\x90a\xf5(T\x95\xb3{\x9d~\xf8\xa5\x1b\a\xd6\u6b2c\x89\n\xd4\xc81j\v\f\x00\x00\u07d4Js8\x92\x98\x03\x1b\x88\x16\u0329FB\x1c\x19\x9e\x18\xb3C\u0589\"8h\xb8y\x14o\x00\x00\u07d4Js]\"G\x927m3\x13g\xc0\x93\xd3\x1c\x87\x944\x15\x82\x89f\xff\xcb\xfd^Z0\x00\x00\u07d4Jt\x94\xcc\xe4HU\u0300X(B\xbe\x95\x8a\r\x1c\x00r\ue242\x1a\xb0\xd4AI\x80\x00\x00\u07d4Ju\xc3\xd4\xfao\u033d]\u0567\x03\xc1Sy\xa1\xe7\x83\u9dc9b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94J\x81\xab\xe4\x98L|k\xefc\u0598 \xe5WC\xc6\x1f \x1c\x8a\x03d\x01\x00N\x9a\xa3G\x00\x00\u07d4J\x82iO\xa2\x9d\x9e!2\x02\xa1\xa2\t(]\xf6\xe7E\xc2\t\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\x83\\%\x82LG\xec\xbf\u01d49\xbf?\\4\x81\xaau\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4J\x91\x802C\x91Y\xbb1[g%\xb6\x83\r\xc86\x97s\x9f\x89\x12\xa3.\xf6x3L\x00\x00\u07d4J\x97\xe8\xfc\xf4c^\xa7\xfc^\x96\xeeQu.\u00c8qk`\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4J\x9a&\xfd\n\x8b\xa1\x0f\x97}\xa4\xf7|1\x90\x8d\xabJ\x80\x16\x89a\t=|,m8\x00\x00\u07d4J\xa1H\xc2\xc34\x01\xe6j+Xnew\u0132\x92\xd3\xf2@\x89\v\xb8`\xb2\x85\xf7t\x00\x00\u07d4J\xa6\x93\xb1\"\xf3\x14H*G\xb1\x1c\xc7|h\xa4\x97\x87ab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xb2\xd3O\x04\x83O\xbftyd\x9c\xab\x92=,G%\xc5S\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4J\xc0vs\xe4/d\xc1\xa2^\xc2\xfa-\x86\xe5\xaa+4\xe09\x89lk\x93[\x8b\xbd@\x00\x00\u07d4J\u016c\xad\x00\v\x88w!L\xb1\xae\x00\xea\u0263}Y\xa0\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\u0250ZL\xb6\xab\x1c\xfdbTn\xe5\x91s\x00\xb8|O\u07897\b\xba\xed=h\x90\x00\x00\u07d4J\u03e9\xd9N\xdaf%\xc9\u07e5\xf9\xf4\xf5\xd1\a\xc4\x03\x1f\u07c9\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4J\xd0G\xfa\xe6~\xf1b\xfeh\xfe\xdb\xc2};e\xca\xf1\f6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xd9]\x18\x8dddp\x9a\xdd%U\xfbM\x97\xfe\x1e\xbf1\x1f\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4J\xdb\xf4\xaa\xe0\xe3\xefD\xf7\xddM\x89\x85\u03ef\tn\u010e\x98\x89\b!\xab\rD\x14\x98\x00\x00\u07d4J\xe2\xa0M9\t\xefENTL\xcf\xd6\x14\xbf\xef\xa7\x10\x89\xae\x89\x18\x01\x15\x9d\xf1\xee\xf8\x00\x00\xe0\x94J\xe90\x82\xe4Q\x87\xc2a`\xe6g\x92\xf5\u007f\xad5Q\xc7:\x8a\x04\x96\x15 \xda\xff\x82(\x00\x00\u07d4J\xf0\xdb\a{\xb9\xba^D>!\xe1H\xe5\x9f7\x91\x05\u0152\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x06\x19\xd9\u062a1:\x951\xac}\xbe\x04\xca\rjZ\u0476\x89lk\x93[\x8b\xbd@\x00\x00\u07d4K\v\u062c\xfc\xbcS\xa6\x01\v@\xd4\u040d\xdd-\x9dib-\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\x19\xeb\f5K\xc199`\xeb\x06\x06;\x83\x92o\rg\xb2\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4K)C|\x97\xb4\xa8D\xbeq\u0323\xb6H\xd4\xca\x0f\u075b\xa4\x89\b$q\x984\u03ec\x00\x00\u07d4K1\xbfA\xab\xc7\\\x9a\xe2\u034f\u007f5\x16;n+tPT\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4K:|\u00e7\u05f0\x0e\xd5(\"!\xa6\x02Y\xf2[\xf6S\x8a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K:\xab3^\xbb\xfa\xa8p\xccM`^}.t\xc6h6\x9f\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4K\xcd\xc1\x8a`\x00\x00\u07d4K`\xa3\xe2S\xbf8\xc8\xd5f \x10\xbb\x93\xa4s\xc9e\xc3\xe5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Kt\xf5\xe5\x8e.\xdfv\xda\xf7\x01Q\x96J\v\x8f\x1d\xe0f<\x89\x11\x90\xaeID\xba\x12\x00\x00\u07d4Kv!f\xdd\x11\x18\xe8Ci\xf8\x04\xc7_\x9c\xd6W\xbfs\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Ky.)h>\xb5\x86\u353b3Rl`\x01\xb3\x97\x99\x9e\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x90N\x93K\xd0\u030b p_\x87\x9e\x90[\x93\xea\f\xcc0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94K\x92\x06\xbakT\x9a\x1a\u007f\x96\x9e\x1d]\xba\x86u9\xd1\xfag\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4K\x98N\xf2lWn\x81Z.\xae\xd2\xf5\x17\u007f\a\u06f1\xc4v\x89T\x91YV\xc4\t`\x00\x00\u07d4K\x9e\x06\x8f\xc4h\tv\xe6\x15\x04\x91)\x85\xfd\\\xe9K\xab\r\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\xa0\xd9\xe8\x96\x01w+IhG\xa2\xbbC@\x18g\x87\xd2e\x8965\u026d\xc5\u07a0\x00\x00\u07d4K\xa5:\xb5I\xe2\x01m\xfa\"<\x9e\u0563\x8f\xad\x91(\x8d\a\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94K\xa8\xe0\x11\u007f\xc0\xb6\xa3\xe5k$\xa3\xa5\x8f\xe6\xce\xf4B\xff\x98\x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4K\xac\x84j\xf4\x16\x9f\x1d\x95C\x1b4\x1d\x88\x00\xb2!\x80\xaf\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4K\xb6\xd8k\x83\x14\xc2-\x8d7\xeaQm\x00\x19\xf1V\xaa\xe1-\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K\xb9e\\\xfb*6\xea|cz{\x85\x9bJ1T\xe2n\xbe\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94K\xbc\xbf8\xb3\xc9\x01c\xa8K\x1c\u04a9;X\xb2\xa34\x8d\x87\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94K\xd6\xdd\f\xff#@\x0e\x170\xba{\x89E\x04W}\x14\xe7J\x8a+\xa0\xcc\xdd\xd0\xdfs\xb0\x00\x00\u07d4K\xe8b\x8a\x81T\x87N\x04\x8d\x80\xc1B\x18\x10\"\xb1\x80\xbc\xc1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4K\xe9\rA!)\u0564\xd0BCa\xd6d\x9dNG\xa6#\x16\x897\b\xba\xed=h\x90\x00\x00\xe0\x94K\xea(\x8e\xeaB\u0115^\xb9\xfa\xad*\x9f\xafG\x83\xcb\u076c\x8a\x06\x18\xbe\x16c\u012fI\x00\x00\u07d4K\xf4G\x97\x99\xef\x82\xee\xa2\tC7OV\xa1\xbfT\x00\x1e^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4K\xf8\xbf\x1d5\xa211Wd\xfc\x80\x01\x80\x9a\x94\x92\x94\xfcI\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4K\xf8\xe2oL'\x90\xdae3\xa2\xac\x9a\xba\xc3\u019a\x19\x943\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794L\n\xcaP\x8b<\xaf^\xe0(\xbcp}\xd1\xe8\x00\xb88\xf4S\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94L\v\x15\x15\xdf\xce\u05e1>\x13\xee\x12\xc0\xf5#\xaePO\x03+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4L\x13\x98\f2\xdc\xf3\x92\vx\xa4\xa7\x903\x12\x90|\x1b\x12?\x89\x03A\x00\x15\xfa\xae\f\x00\x00\u07d4L\x15y\xaf3\x12\xe4\xf8\x8a\xe9\x95\xcc9W\xd2R\xce\v\xf0\xc8}[O\"4g.p\x89\x87\x86x2n\xac\x90\x00\x00\u07d4LB1y\x82i\x1d\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4LZ\xfe@\xf1\x8f\xfcH\u04e1\xae\xc4\x1f\u009d\xe1y\xf4\u0497\x89lk\x93[\x8b\xbd@\x00\x00\u07d4L[=\xc0\xe2\xb96\x0f\x91(\x9b\x1f\xe1<\xe1,\x0f\xbd\xa3\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lfk\x86\xf1\xc5\ue324\x12\x85\xf5\xbd\xe4\xf7\x90R\b\x14\x06\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Lik\xe9\x9f:i\x04@\xc3CjY\xa7\xd7\xe97\u05ba\r\x89\xbb\x91%T\"c\x90\x00\x00\u07d4Lj$\x8f\xc9}p]\xefI\\\xa2\aY\x16\x9e\xf0\xd3dq\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4Lj\x9d\xc2\u02b1\n\xbb.|\x13p\x06\xf0\x8f\ucd77y\xe1\x89\x1b\r\x04 /G\xec\x00\x00\u07d4Lk\x93\xa3\xbe\xc1cIT\f\xbf\xca\xe9l\x96!\xd6dP\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lu\x98\x13\xad\x13\x86\xbe\xd2\u007f\xfa\xe9\xe4\x81^60\u0323\x12\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Lv\f\xd9\xe1\x95\xeeO-k\xce%\x00\xff\x96\xda|C\ue44a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4Lv{e\xfd\x91\x16\x1fO\xbd\xccji\xe2\xf6\xadq\x1b\xb9\x18\x89'\b\x01\xd9F\xc9@\x00\x00\u07d4L~.+w\xad\f\xd6\xf4J\xcb(a\xf0\xfb\x8b(u\x0e\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4L\x85\xed6/$\xf6\xb9\xf0L\xdf\xcc\xd0\"\xaeSQG\u02f9\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4L\x93[\xb2Pw\x8b0\x9b==\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4L\xee\x90\x1bJ\u0231V\xc5\xe2\xf8\xa6\xf1\xbe\xf5r\xa7\xdc\xeb~\x8965\u026d\xc5\u07a0\x00\x00\u07d4L\xef\xbe#\x98\xe4}R\u73743L\x8bivu\U00053b89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4L\xf5S{\x85\x84/\x89\xcf\xee5\x9e\xaeP\x0f\xc4I\xd2\x11\x8f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94M\bG\x1dh\x00z\xff*\xe2y\xbc^?\xe4\x15o\xbb\xe3\u078a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4M \x01\x10\x12@\b\xd5ov\x98\x12VB\f\x94jo\xf4\\\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4M$\xb7\xacG\xd2\xf2}\xe9\tt\xba=\xe5\xea\xd2\x03TK\u0349\x05k\xc7^-c\x10\x00\x00\u0794M)\xfcR:,\x16)S!!\u0699\x98\u9d6b\x9d\x1bE\x88\xdbD\xe0I\xbb,\x00\x00\u07d4M8\xd9\x0f\x83\xf4Q\\\x03\xccx2j\x15M5\x8b\u0602\xb7\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4ML\xf5\x80t)a^0\xcd\xfa\xce\x1eZ\xaeM\xad0U\xe6\x89 \x86\xac5\x10R`\x00\x00\u07d4MW\xe7\x16\x87l\f\x95\xef^\xae\xbd5\xc8\xf4\x1b\x06\x9bk\xfe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Mg\U000ab159\xfe\xf5\xfcA9\x99\xaa\x01\xfd\u007f\xcep\xb4=\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Mn\x8f\xe1\t\xcc\xd2\x15\x8eM\xb1\x14\x13/\xe7_\xec\u023e[\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94Mq\xa6\xeb=\u007f2~\x184'\x8e(\v\x03\x9e\xdd\xd3\x1c/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4M|\xfa\xa8L\xb31\x06\x80\n\x8c\x80/\xb8\xaaF8\x96\u0159\x89a\t=|,m8\x00\x00\u07d4M\x80\x10\x93\xc1\x9c\xa9\xb8\xf3B\xe3<\xc9\xc7{\xbdL\x83\x12\u03c9\x12\xb3\xe7\xfb\x95\u0364\x80\x00\u07d4M\x82\x88\x94u/o%\x17]\xaf!w\tD\x87\x95Ko\x9f\x89O!+\xc2\u011c\x83\x80\x00\xe0\x94M\x82\xd7p\f\x12;\xb9\x19A\x9b\xba\xf0Fy\x9ck\x0e,f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4M\x83m\x9d;\x0e,\xbdM\xe0PYo\xaaI\f\xff\xb6\r]\x89\x10CV\x1a\x88)0\x00\x00\u07d4M\x86\x97\xaf\x0f\xbf,\xa3n\x87h\xf4\xaf\"\x135phZ`\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\x92y\x96 )\xa8\xbdEc\x977\xe9\x8bQ\x1e\xff\aL!\x89Hz\x9a0E9D\x00\x00\u07d4M\x93io\xa2HY\xf5\u0493\x9a\xeb\xfaT\xb4\xb5\x1a\xe1\xdc\u0309\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4M\x9cw\xd0u\f^o\xbc$\u007f/\u05d2thl\xb3S\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\xa5\xed\u0188\xb0\xcbb\xe1@=\x17\x00\xd9\u0739\x9f\xfe?\u04c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xa8\x03\ai\x84K\xc3A\x86\xb8\\\xd4\xc74\x88I\xffI\xe9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xb1\xc4:\x0f\x83M}\x04x\xb8\x96\ag\xec\x1a\xc4L\x9a\xeb\x89/Q\x810V'7\x00\x00\u07d4M\xb2\x12\x84\xbc\xd4\xf7\x87\xa7Ue\x00\xd6\xd7\xd8\xf3f#\xcf5\x89i(7Ow\xa3c\x00\x00\u07d4M\xc3\xda\x13\xb2\xb4\xaf\xd4O]\r1\x89\xf4D\xd4\xdd\xf9\x1b\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4M\u013f^u\x89\xc4{(7\x8du\x03\u03d6H\x80a\u06fd\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4M\xc9\u057bK\x19\xce\u0354\xf1\x9e\xc2] \x0e\xa7/%\xd7\xed\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xcd\x11\x81X\x18\xae)\xb8]\x016sI\xa8\xa7\xfb\x12\xd0k\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\u07d4M\xcfb\xa3\xde?\x06\x1d\xb9\x14\x98\xfda\x06\x0f\x1fc\x98\xffs\x89lj\xccg\u05f1\xd4\x00\x00\u07d4M\xd11\xc7J\x06\x8a7\xc9\n\xde\xd4\xf3\t\xc2@\x9fdx\u04c9\x15\xaf9\u4ab2t\x00\x00\xe0\x94M\u0767Xk\"7\xb0S\xa7\xf3(\x9c\xf4`\xdcW\xd3z\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xe3\xfe4\xa6\xfb\xf64\xc0Q\x99\u007fG\xcc\u007fHy\x1fX$\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4M\xf1@\xbaye\x85\xddT\x891[\xcaK\xbah\n\u06f8\x18\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4N\x02\ay\xb5\xdd\xd3\xdf\"\x8a\x00\xcbH\xc2\xfc\x97\x9d\xa6\xae8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N\v\xd3$s\xc4\xc5\x1b\xf2VT\xde\xf6\x9fy|k)\xa22\x89V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4N\"%\xa1\xbbY\xbc\x88\xa21ft\xd33\xb9\xb0\xaf\xcafU\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4N#\x10\x19\x1e\xad\x8d;\xc6H\x98s\xa5\xf0\xc2\xeck\x87\u1f8965\u026d\xc5\u07a0\x00\x00\u07d4N#-S\xb3\u6f8f\x89Sa\xd3\x1c4\xd4v+\x12\xc8.\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4N+\xfaJFo\x82g\x1b\x80\x0e\xeeBj\xd0\f\a\x1b\xa1p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4N>\xda\u0506M\xabd\xca\xe4\xc5Azvw@S\xdcd2\x89 \b\xfbG\x8c\xbf\xa9\x80\x00\u07d4NC\x18\xf5\xe1>\x82JT\xed\xfe0\xa7\xedO&\xcd=\xa5\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N[w\xf9\x06aY\xe6\x15\x93?-\xdatw\xfaNG\xd6H\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94Nf\x00\x80b\x89EJ\u03630\xa2\xa3U`\x10\u07ec\xad\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Ns\xcf#y\xf1$\x86\x0fs\xd6\xd9\x1b\xf5\x9a\xcc\\\xfc\x84[\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94Nz\xa6~\x12\x18>\xf9\xd7F\x8e\xa2\x8a\xd29\xc2\xee\xf7\x1bv\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94N{TGM\x01\xfe\xfd8\x8d\xfc\xd5;\x9ff&$A\x8a\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94N\x89.\x80\x81\xbf6\xe4\x88\xfd\xdb;&0\xf3\xf1\xe8\xda0\u048a\x02\x8a\xba0u$Q\xfc\x00\x00\xe0\x94N\x8amcH\x9c\xcc\x10\xa5\u007f\x88_\x96\xeb\x04\xec\xbbT`$\x8a\x03\xea\xe3\x13\x0e\u0316\x90\x00\x00\u07d4N\x8eG\xae;\x1e\xf5\f\x9dT\xa3\x8e\x14 \x8c\x1a\xbd6\x03\u0089y(\xdb\x12vf\f\x00\x00\u0794N\x90\u03312X\xac\xaa\x9fO\xeb\xc0\xa3B\x92\xf9Y\x91\xe20\x88\xdbD\xe0I\xbb,\x00\x00\u07d4N\xa5n\x11\x12d\x1c\x03\x8d\x05e\xa9\u0096\xc4c\xaf\xef\xc1~\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94N\xa7\x0f\x041?\xaee\xc3\xff\"J\x05\\=-\xab(\xdd\u07ca\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4N\xb1EKW8\x05\u022c\xa3~\xde\xc7\x14\x9aA\xf6\x12\x02\xf4\x89\x10CV\x1a\x88)0\x00\x00\u07d4N\xb8{\xa8x\x8e\xba\r\xf8~[\x9b\xd5\n\x8eE6\x80\x91\xc1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4N\xbcV)\xf9\xa6\xa6k,\xf36:\u0109\\\x03H\u8fc7\x8967\tlK\xcci\x00\x00\u07d4N\xc7h)^\xea\xba\xfcB\x95\x84\x15\xe2+\xe2\x16\xcd\xe7v\x18\x89\x03;\x1d\xbc9\xc5H\x00\x00\u07d4N\xcc\x19\x94\x8d\xd9\u0347\xb4\xc7 \x1a\xb4\x8eu\x8f(\xe7\xccv\x89\x1b\x1d\xaba\u04ead\x00\x00\u07d4N\xd1M\x81\xb6\v#\xfb%\x05M\x89%\u07e5s\u072eah\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94N\xe1<\rA \vF\u045d\xee\\K\xce\xc7\x1d\x82\xbb\x8e8\x8a\x01\xab\xee\x13\u033e\ufbc0\x00\u07d4N\xea\xd4\n\xad\x8cs\xef\b\xfc\x84\xbc\n\x92\xc9\t/j6\xbf\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4N\xeb\xe8\f\xb6\xf3\xaeY\x04\xf6\xf4\xb2\x8d\x90\u007f\x90q\x89\xfc\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4N\xeb\xf1 ]\f\xc2\f\xeel\u007f\x8f\xf3\x11_V\u050f\xba&\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4N\xf1\xc2\x14c:\xd9\xc0p;N#t\xa2\xe3>>B\x92\x91\x89Hz\x9a0E9D\x00\x00\u07d4N\xfc\xd9\u01df\xb43L\xa6${\n3\xbd\x9c\xc32\b\xe2r\x89Hz\x9a0E9D\x00\x00\xe0\x94O\x06$k\x8dK\u0496a\xf4>\x93v\"\x01\u0486\x93Z\xb1\x8a\x01\x059O\xfcF6\x11\x00\x00\u07d4O\x15+/\xb8e\x9dCwn\xbb\x1e\x81g:\xa8Ai\xbe\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4O\x17\u007f\x9dV\x95=\xedq\xa5a\x1f93\"\xc3\x02y\x89\\\x89\rU\uf422\xda\x18\x00\x00\u07d4O\x1a-\xa5JLm\xa1\x9d\x14$\x12\xe5n\x81WA\xdb#%\x89\x05k\xc7^-c\x10\x00\x00\u07d4O#\xb6\xb8\x17\xff\xa5\xc6d\xac\xda\u05db\xb7\xb7&\xd3\n\xf0\xf9\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94O&i\f\x99+z1*\xb1.\x13\x85\xd9J\xcdX(\x8e{\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4O+G\xe2wZ\x1f\xa7\x17\x8d\xad\x92\x98Z[\xbeI;\xa6\u0589\n\u05ce\xbcZ\xc6 \x00\x00\u07d4O:HT\x91\x11E\xea\x01\xc6D\x04K\xdb.Z\x96\n\x98/\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4O?,g0i\xac\x97\xc2\x026\a\x15)\x81\xf5\xcd`c\xa0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94OJ\x9b\xe1\f\xd5\xd3\xfb]\xe4\x8c\x17\xbe)o\x89V\x90d[\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4OR\xadap\xd2[*.\x85\x0e\xad\xbbRA?\xf20>\u007f\x89\xa4\xccy\x95c\u00c0\x00\x00\u07d4OX\x01\xb1\xeb0\xb7\x12\u0620WZ\x9aq\xff\x96]O4\xeb\x89\x10CV\x1a\x88)0\x00\x00\u07d4O]\xf5\xb9CW\u0794\x86\x04\xc5\x1bx\x93\xcd\xdf`v\xba\xad\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4Od\xa8^\x8e\x9a@I\x8c\fu\xfc\xeb\x037\xfbI\b>^\x8965\u026d\xc5\u07a0\x00\x00\u07d4Og9m%S\xf9\x98x_pN\a\xa69\x19}\u0454\x8d\x89\x10DrR\x1b\xa78\x00\x00\u07d4OmG7\u05e9@8$\x87&H\x86i|\xf7c\u007f\x80\x15\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4Os0\toy\xed&N\xe0\x12\u007f]0\xd2\xf7?!\xcb\u007f\x04\x89\x04\x82\xfe&\f\xbc\xa9\x00\x00\u07d4O\xeeP\xc5\xf9\x88 k\t\xa5sF\x9f\xb1\u0434.\xbbm\u0389l\xee\x06\u077e\x15\xec\x00\x00\u07d4O\xf6v\xe2\u007fh\x1a\x98-\x8f\xd9\xd2\x0ed\x8b=\xce\x05\xe9E\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4O\xf6\u007f\xb8\u007fn\xfb\xa9'\x990\u03fd\x1bz4L\u057a\x8bN\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94PFf\u03891\x17^\x11\xa5\xed\x11\xc1\u072a\x06\xe5\u007fNf\x8a\x02\u007f>\u07f3Nn@\x00\x00\u0794PXM\x92\x06\xa4l\xe1\\0\x11\x17\xee(\xf1\\0\xe6\x0eu\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94PZ3\xa1\x864\xddH\x00i)\x13N\x00\x00\u07d4P\u0286\xb5\xeb\x1d\x01\x87M\xf8\xe5\xf3IE\u051cl\x1a\xb8H\x8965\u026d\xc5\u07a0\x00\x00\u07d4P\u0357\xe97\x8b\\\xf1\x8f\x179c#l\x99Q\xeft8\xa5\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4P\u073c'\xbc\xad\x98@\x93\xa2\x12\xa9\xb4\x17\x8e\xab\xe9\x01ua\x89\a\xe3by\v\\\xa4\x00\x00\u07d4P\xe10#\xbd\x9c\xa9j\xd4\xc5?\xdf\xd4\x10\xcbk\x1fB\v\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94P\xe1\xc8\xec\x98A[\xefD&\x18p\x87\x99C{\x86\xe6\xc2\x05\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4P\xf8\xfaK\xb9\xe2g|\x99\nN\xe8\xcep\xdd\x15#%\x1eO\x89\x01i=#\x16Ok\x00\x00\u07d4P\xfb6\xc2q\a\xee,\xa9\xa3#n'F\u0321\x9a\xcekI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4P\xfe\xf2\x96\x95U\x88\u02aet\xc6.\xc3*#\xa4T\xe0\x9a\xb8\x89A\x1d\xff\xab\xc5\a8\x00\x00\u07d4Q\x02\xa4\xa4 w\xe1\x1cX\xdfGs\u3b14F#\xa6m\x9f\x89lp\x15\xfdR\xed@\x80\x00\u07d4Q\x03\x93w\xee\xd0\xc5s\xf9\x86\xc5\xe8\xa9_\xb9\x9aY\xe93\x0f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Q\x03\xbc\t\x93>\x99!\xfdS\xdcSo\x11\xf0]\rG\x10}\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94Q\x04\xec\xc0\xe30\xdd\x1f\x81\xb5\x8a\xc9\u06f1\xa9\xfb\xf8\x8a<\x85\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4Q\r\x81Y\u0314Wh\xc7E\a\x90\xba\a>\xc0\xd9\xf8\x9e0\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u07d4Q\x0e\xdaV\x01I\x9a\r^\x1a\x00k\xff\xfd\x836r\xf2\xe2g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x12dF\xab=\x802U~\x8e\xbaeY}u\xfa\u0701\\\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94Q\x18U}`\r\x05\xc2\xfc\xbf8\x06\xff\xbd\x93\xd0 %\xd70\x8a\x02g\u04ebd#\xf5\x80\x00\x00\u07d4Q\x1e\x0e\xfb\x04\xacN?\xf2\xe6U\x0eI\x82\x95\xbf\xcdV\xff\u0549$=M\x18\"\x9c\xa2\x00\x00\u07d4Q!\x16\x81{\xa9\xaa\xf8C\xd1P|e\xa5\xead\n{\x9e\xec\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4Q&F\ri,q\u026fo\x05WM\x93\x99\x83h\xa27\x99\x89\x02\u0465\x1c~\x00P\x00\x00\u07d4Q'\u007f\xe7\xc8\x1e\xeb\xd2R\xa0=\xf6\x9ak\x9f2n'\"\a\x89\x03@.y\u02b4L\x80\x00\u07d4Q)oPD'\r\x17pvF\x12\x9c\x86\xaa\xd1d^\xad\xc1\x89H|r\xb3\x10\xd4d\x80\x00\xe0\x94Q+\x91\xbb\xfa\xa9\xe5\x81\xefh?\xc9\r\x9d\xb2*\x8fI\xf4\x8b\x8aA\xa5\"8m\x9b\x95\xc0\x00\x00\u07d4Q5\xfb\x87W`\f\xf4tTbR\xf7M\xc0tm\x06&,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4QF2\xef\xbdd,\x04\xdel\xa3B1]@\u0750\xa2\u06e6\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4QKu\x12\u026e^\xa6<\xbf\x11q[c\xf2\x1e\x18\u0496\xc1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4QS\xa0\xc3\u0211(\x81\xbf\x1c5\x01\xbfd\xb4VI\xe4\x82\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94QVQ\xd6\xdbO\xaf\x9e\xcd\x10:\x92\x1b\xbb\xbej\xe9p\xfd\u050a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94Q_0\xbc\x90\xcd\xf4W~\xe4}e\u05c5\xfb\xe2\xe87\u01bc\x8a\x02'\x1b^\x01\x8b\xa0X\x00\x00\u07d4Q`\xeda.\x1bH\xe7??\xc1[\xc42\x1b\x8f#\xb8\xa2K\x89\x1e\x82kB(e\xd8\x00\x00\u07d4Qa\xfdI\xe8G\xf6tU\xf1\u023bz\xbb6\xe9\x85&\r\x03\x89A\rXj \xa4\xc0\x00\x00\u07d4QiT\x02_\xca&\b\xf4}\xa8\x1c!^\xed\xfd\x84J\t\xff\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4Qi\xc6\n\xeeL\xee\u0444\x9a\xb3mfL\xff\x97\x06\x1e\x8e\xa8\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4Q|uC\r\xe4\x01\xc3A\x03&\x86\x11'\x90\xf4mM6\x9e\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4Q|\xd7`\x8e]\r\x83\xa2kq\u007f6\x03\xda\xc2'}\u00e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x86]\xb1H\x88\x19Q\xf5\x12Qq\x0e\x82\xb9\xbe\r~\xad\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x89\x1b,\xcd\xd2\xf5\xa4K*\x8b\u011a]\x9b\xcadw%\x1c\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4Q\x8c\xef'\xb1\x05\x82\xb6\xd1OiH=\u06a0\xdd<\x87\xbb\\\x89 \x86\xac5\x10R`\x00\x00\u07d4Q\xa6\xd6'\xf6j\x89#\u060d`\x94\xc4qS\x80\xd3\x05|\xb6\x89>s\xd2z5\x94\x1e\x00\x00\u07d4Q\xa8\xc2\x166\x02\xa3.\xe2L\xf4\xaa\x97\xfd\x9e\xa4\x14QiA\x89\x03h\xf7\xe6\xb8g,\x00\x00\u07d4Q\xb4u\x8e\x9e\x14P\xe7\xafBh\xc3\u01f1\xe7\xbdo\\uP\x8965\u026d\xc5\u07a0\x00\x00\u07d4Q\u028b\xd4\xdcdO\xacG\xafgUc\u0540J\r\xa2\x1e\xeb\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4Q\xd2K\xc3so\x88\xddc\xb7\" &\x88f0\xb6\ub1cd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\u05cb\x17\x8dp~9n\x87\x10\x96\\OA\xb1\xa1\xd9\x17\x9d\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\u07d4Q\xe3/\x14\xf4\xca^(|\xda\xc0W\xa7y^\xa9\xe0C\x99S\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Q\xe4?\xe0\xd2\\x(`\xaf\x81\xea\x89\xddy<\x13\xf0\u02f1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4Q\xe7\xb5\\/\x98 \xee\xd78\x846\x1bPf\xa5\x9boE\u0189lk\x93[\x8b\xbd@\x00\x00\xe0\x94Q\xea\x1c\t4\xe3\xd0@\"\ud715\xa0\x87\xa1P\xefp^\x81\x8a\x01Tp\x81\xe7\"M \x00\x00\u07d4Q\xee\f\xca;\xcb\x10\xcd>\x987\"\xce\xd8I=\x92l\bf\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94Q\xf4f:\xb4O\xf7\x93E\xf4'\xa0\xf6\xf8\xa6\u0225?\xf24\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Q\xf5^\xf4~dV\xa4\x18\xab2\xb9\"\x1e\xd2}\xbaf\b\xee\x89\u3bb5sr@\xa0\x00\x00\xe0\x94Q\xf9\xc42\xa4\xe5\x9a\xc8b\x82\u05ad\xabL.\xb8\x91\x91`\xeb\x8ap;[\x89\u00e6\xe7@\x00\x00\u07d4R\x0ff\xa0\xe2e\u007f\xf0\xacA\x95\xf2\xf0d\xcf/\xa4\xb2BP\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4R\x10#T\xa6\xac\xa9]\x8a.\x86\xd5\u07bd\xa6\xdei4`v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\x13\xf4Y\xe0x\xad:\xb9Z\t #\x9f\xcf\x163\xdc\x04\u0289\x8c\xf2\x18|*\xfb\x18\x80\x00\u07d4R\x15\x18;\x8f\x80\xa9\xbc\x03\xd2l\xe9\x12\a\x83*\r9\xe6 \x8965\u026d\xc5\u07a0\x00\x00\xe0\x94R!Cx\xb5@\x04\x05j|\xc0\x8c\x89\x13'y\x8a\u01b2H\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\xe0\x94R##\xaa\xd7\x1d\xbc\x96\xd8Z\xf9\x0f\bK\x99\xc3\xf0\x9d\ucdca\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4R>\x14\r\xc8\x11\xb1\x86\xde\xe5\xd6\u020b\xf6\x8e\x90\xb8\xe0\x96\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R?mdi\x0f\xda\u0354(SY\x1b\xb0\xff \xd3em\x95\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4RO\xb2\x10R,^#\xbbg\u07ff\x8c&\xaaam\xa4\x99U\x8965b\xa6m4#\x80\x00\u07d4RU\xdci\x15ZE\xb9p\xc6\x04\xd3\x00G\xe2\xf50i\x0e\u007f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R`\xdcQ\xee\a\xbd\u06ab\xab\xb9\xeetK9<\u007fG\x93\xa6\x89\x01\xd8f_\xa5\xfaL\x00\x00\u07d4Rg\xf4\xd4\x12\x92\xf3p\x86<\x90\u05d3)i\x03\x846%\u01c9K\xe4\xe7&{j\xe0\x00\x00\u07d4Rk\xb53\xb7n \xc8\xee\x1e\xbf\x12?\x1e\x9f\xf4\x14\x8e@\xbe\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Rl\xb0\x9c\u3b63g.\xec\x1d\xebF [\xe8\x9aKV>\x89\x85\xcaa[\xf9\xc0\x10\x00\x00\u07d4Rs\x8c\x90\xd8`\xe0L\xb1/I\x8d\x96\xfd\xb5\xbf6\xfc4\x0e\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4Rz\x8c\xa1&\x863\xa6\xc99\xc5\xde\x1b\x92\x9a\ue4ae\xac\x8d\x890\xca\x02O\x98{\x90\x00\x00\u07d4R\x81\x01\xceF\xb7 \xa2!M\u036ef\x18\xa51w\xff\xa3w\x89\x1b\x96\x12\xb9\xdc\x01\xae\x00\x00\xe0\x94R\x81s4s\xe0\r\x87\xf1\x1e\x99U\u5275\x9fJ\u008ez\x8a\x8b\xd6/\xf4\xee\xc5Y \x00\x00\u07d4R\x98\xab\x18*\x195\x9f\xfc\xec\xaf\xd7\u0475\xfa!-\xed\xe6\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R\x9a\xa0\x02\u0196*:\x85E\x02\u007f\u0630_\"\xb5\xbf\x95d\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4R\x9e\x82O\xa0rX+@2h:\xc7\xee\xcc\x1c\x04\xb4\xca\xc1\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94R\xa5\xe4\xdeC\x93\xee\xcc\xf0X\x1a\xc1\x1bR\u0183\xc7n\xa1]\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4R\xb4%|\xf4\x1bn(\x87\x8dP\xd5{\x99\x91O\xfa\x89\x87:\x89\xd5\r\u026a,Aw\x00\x00\u07d4R\xb8\xa9Y&4\xf70\v|\\Y\xa34[\x83_\x01\xb9\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xbd\u066fYx\x85\v\xc2A\x10q\x8b7#u\x9bC~Y\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4R\xcd @;\xa7\xed\xa6\xbc0z=c\xb5\x91\x1b\x81|\x12c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794R\u04c0Q\x1d\xf1\x9d^\u0080{\xbc\xb6vX\x1bg\xfd7\xa3\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94R\xe1s\x13P\xf9\x83\xcc,A\x89\x84/\xde\x06\x13\xfa\xd5\f\xe1\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4R\xe4g\x832\x9av\x93\x01\xb1u\x00\x9d4gh\xf4\xc8~\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xf0X\xd4aG\xe9\x00m)\xbf,\t0J\xd1\xcd\xddn\x15\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4R\xf1T#2<$\xf1\x9a\xe2\xabg7\x17\"\x9d?t}\x9b\x897\xa04\xcb\xe8\xe3\xf3\x80\x00\u07d4R\xf8\xb5\t\xfe\xe1\xa8t\xabo\x9d\x876\u007f\xbe\xaf\x15\xac\x13\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4R\xfbF\xac]\x00\xc3Q\x8b,:\x1c\x17}D/\x81eU_\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4S\x00w\xc9\xf7\xb9\a\xff\x9c\xec\fw\xa4\x1ap\xe9\x02\x9a\xddJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x03\x19\xdb\n\x8f\x93\xe5\xbb}M\xbfH\x161O\xbe\xd86\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x04}\u022c\x90\x83\xd9\x06r\xe8\xb3G<\x10\f\xcd'\x83#\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4S\va\xe4/9Bm$\b\xd4\bR\xb9\xe3J\xb5\xeb\xeb\u0149\x0e~\xeb\xa3A\vt\x00\x00\u07d4S\x0f\xfa\u00fc4\x12\xe2\xec\x0e\xa4{y\x81\xc7p\xf5\xbb/5\x89\a?u\u0460\x85\xba\x00\x00\u07d4S\x17\xec\xb0#\x05,\xa7\xf5e+\xe2\xfa\x85L\xfeEc\xdfM\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4S\x19M\x8a\xfa>\x885\x02v~\xdb\xc3\x05\x86\xaf3\xb1\x14\u04c9lk\x93[\x8b\xbd@\x00\x00\u07d4S*}\xa0\xa5\xadt\aF\x8d;\xe8\xe0~i\xc7\xddd\xe8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4S-2\xb0\x0f0[\xcc$\xdc\xefV\x81}b/4\xfb,$\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4S4DX@\x82\xeb\xa6T\xe1\xad0\xe1Is\\o{\xa9\"\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4S8\xefp\xea\xc9\u075a\xf5\xa0P;^\xfa\xd1\x03\x9eg\xe7%\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94S9oJ&\u00b4`D\x960lTB\xe7\xfc\xba'.6\x8a\x04?/\b\xd4\x0eZ\xfc\x00\x00\xe0\x94S:s\xa4\xa2\"\x8e\xee\x05\xc4\xff\xd7\x18\xbb\xf3\xf9\xc1\xb1)\xa7\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4S<\x06\x92\x8f\x19\u0429V\xcc(\x86k\xf6\xc8\xd8\xf4\x19\x1a\x94\x89\x0f\xd8\xc1C8\xe60\x00\x00\u07d4S@e6\x1c\xb8T\xfa\xc4+\xfb\\\x9f\xcd\xe0`J\xc9\x19\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4SC\u007f\xec\xf3J\xb9\xd45\xf4\u07b8\xca\x18\x15\x19\xe2Y 5\x89\n1\x06+\xee\xedp\x00\x00\u07d4SR\x01\xa0\xa1\xd74\"\x80\x1fU\xde\xd4\u07ee\xe4\xfb\xaan;\x89\x02&!\x1fy\x15B\x80\x00\xe0\x94S`\x81\x05\xceK\x9e\x11\xf8k\xf4\x97\xff\xca;x\x96{_\x96\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4SnM\x80)\xb7?Uy\u0723>p\xb2N\xba\x89\xe1\x1d~\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Sp\rS%MC\x0f\"x\x1aJv\xa4c\x93;]k\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94S\u007f\x9dM1\xefp\x83\x9d\x84\xb0\xd9\u0377+\x9a\xfe\xdb\xdf5\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\xe0\x94S\x81D\x85\x03\xc0\xc7\x02T+\x1d\xe7\xcc_\xb5\xf6\xab\x1c\xf6\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94S\x94.yI\xd6x\x8b\xb7\x80\xa7\xe8\xa0y'\x81\xb1aK\x84\x8a\x03]\xebFhO\x10\xc8\x00\x00\u07d4S\x95\xa4E]\x95\xd1x\xb4S*\xa4r[\x19?\xfeQ)a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94S\x98\x9e\xd30V?\xd5}\xfe\u027d4<7`\xb0y\x93\x90\x8a\x01P\x89N\x84\x9b9\x00\x00\x00\u07d4S\xa2Dg(\x95H\x0fJ+\x1c\xdf}\xa5\xe5\xa2B\xecM\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4S\xa7\x14\xf9\x9f\xa0\x0f\xefu\x8e#\xa2\xe7F2m\xad$|\xa7\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4S\xaf2\xc2/\uf640?\x17\x8c\xf9\v\x80/\xb5q\xc6\x1c\xb9\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4S\xc0\xbb\u007f\u020e\xa4\"\xd2\xef~T\x0e-\x8f(\xb1\xbb\x81\x83\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94S\xc5\xfe\x01\x19\xe1\xe8Hd\f\xee0\xad\ua594\x0f*]\x8b\x8a\x04\x9a\xda_\xa8\xc1\f\x88\x00\x00\u07d4S\xc9\xec\xa4\ts\xf6;\xb5\x92{\xe0\xbcj\x8a\x8b\xe1\x95\x1ft\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\u0388\xe6lZ\xf2\U0009bf4fY*V\xa3\xd1_ l2\x89\a\xa2\x8c1\xcc6\x04\x00\x00\u07d4S\xce\xc6\u0200\x92\xf7V\xef\xe5o}\xb1\x12(\xa2\xdbE\xb1\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4S\xe3[\x12#\x1f\x19\xc3\xfdwL\x88\xfe\xc8\xcb\xee\xdf\x14\b\xb2\x89\x1b\xc1mgN\xc8\x00\x00\x00\u07d4S\xe4\xd9im\xcb?M{?p\u072aN\xec\xb7\x17\x82\xff\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4S\xfa\xf1e\xbe\x03\x1e\xc1\x830\xd9\xfc\xe5\xbd\x12\x81\xa1\xaf\b\u06c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4T\n\x18\x19\xbd|5\x86\x1ey\x18\x04\xe5\xfb\xb3\xbc\x97\u026b\xb1\x89N\xd7\xda\xc6B0 \x00\x00\xe0\x94T\f\a(\x02\x01N\xf0\xd5a4Z\xecH\x1e\x8e\x11\xcb5p\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94T\f\xf2=\xd9\\MU\x8a'\x9dw\x8d+75\xb3\x16A\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\x10`\xfcX\xc7P\xc4\x05\x12\xf83i\xc0\xa63@\xc1\"\xb6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\x13\xc9\u007f\xfaJn*{\xba\x89a\u071f\u03850\xa7\x87\u05c965\u026d\xc5\u07a0\x00\x00\u07d4T\x1d\xb2\n\x80\xcf;\x17\xf1b\x1f\x1b?\xf7\x9b\x88/P\xde\xf3\x8965\u026d\xc5\u07a0\x00\x00\u07d4T.\x80\x96\xba\xfb\x88\x16&\x06\x00.\x8c\x8a>\u0458\x14\xae\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\v:\xa8\x87\x03\xa7%\u07e5}\xe6\xe6F\x93Qd\x80,\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4T1\xb1\u0447Q\xb9\x8f\xc9\u220a\xc7u\x9f\x155\xa2\xdbG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\xcaB~ae\xa6D\xba\xe3&\xbd\tu\n\x17\x8ce\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T5\xc6\xc1y3\x17\xd3,\xe1;\xbaLO\xfe\xb9s\xb7\x8a\u0709\r\x8ek\x1c\x12\x85\xef\x00\x00\xe0\x94T6)\xc9\\\xde\xf4(\xad7\xd4S\u02958\xa9\xf9\t\x00\xac\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4T9\x1bM\x17mGl\xea\x16N_\xb55\u0197\x00\xcb%5\x89\x05l\xd5_\xc6M\xfe\x00\x00\xe0\x94T:\x8c\x0e\xfb\x8b\xcd\x15\xc5C\u29a4\xf8\aYv1\xad\xef\x8a\x01?\x80\xe7\xe1O-D\x00\x00\u07d4T?\x8cgN$b\xd8\xd5\u06a0\xe8\x01\x95\xa8p\x8e\x11\xa2\x9e\x89\x03wX\x83;:z\x00\x00\xe0\x94TK[5\x1d\x1b\xc8.\x92\x97C\x99H\xcfHa\xda\u026e\x11\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4TM\xdaB\x1d\xc1\xebs\xbb$\xe3\xe5j$\x80\x13\xb8|\x0fD\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4TW\\1\x14u\x1e\x14o\xfe\u00c7nE\xf2\x0e\xe8AJ\u07ba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\xb4B\x9b\x18/\x03w\xbe~bi9\xc5\xdbd@\xf7]z\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\xbc\xb8\xe7\xf7<\xda=s\xf4\u04cb-\bG\xe6\x00\xba\r\xf8\x89:pAX\x82\xdf\x18\x00\x00\u07d4T\xc9>\x03\xa9\xb2\xe8\xe4\xc3g(5\xa9\xeev\xf9a[\xc1N\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4T\u0388'YV\xde\xf5\xf9E\x8e;\x95\xde\xca\xcdH@!\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T\xdb^\x06\xb4\x81]1\xcbV\xa8q\x9b\xa3:\xf2\xd7>rR\x89$R\x1e*0\x17\xb8\x00\x00\xe0\x94T\xe0\x12\x83\u030b8E8\xdddgp\xb3W\xc9`\xd6\xca\u034a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4T\xecs\x00\xb8\x1a\xc8C3\xed\x1b\x03<\xd5\u05e39r\xe24\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4T\xfe\xbc\xce \xfez\x90\x98\xa7U\xbd\x90\x98\x86\x02\xa4\x8c\b\x9e\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4U\n\xad\xae\x12!\xb0z\xfe\xa3\x9f\xba.\xd6.\x05\u5df5\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4U\f0o\x81\xef]\x95\x80\xc0l\xb1\xab \x1b\x95\xc7H\xa6\x91\x89$\x17\xd4\xc4p\xbf\x14\x00\x00\xe0\x94U\x19\x99\xdd\xd2\x05V3'\xb9\xb50xZ\xcf\xf9\xbcs\xa4\xba\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4U\x1ew\x84w\x8e\xf8\xe0H\xe4\x95\xdfI\xf2aO\x84\xa4\xf1\u0709 \x86\xac5\x10R`\x00\x00\xe0\x94U)\x83\na\xc1\xf1<\x19~U\v\xed\xdf\u05bd\x19\\\x9d\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U)\x87\xf0e\x1b\x91[.\x1eS(\xc1!\x96\rK\xddj\xf4\x89a\t=|,m8\x00\x00\u07d4U;k\x1cW\x05\x0e\x88\xcf\f1\x06{\x8dL\xd1\xff\x80\xcb\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U?7\xd9$fU\x0e\x9f\xd7u\xaet6-\xf00\x17\x912\x89lk\x93[\x8b\xbd@\x00\x00\u07d4UC6\xeeN\xa1U\xf9\xf2O\x87\xbc\xa9\xcar\xe2S\xe1,\u0489\x05k\xc7^-c\x10\x00\x00\u0794UC\xddm\x16\x9e\xec\x8a!;\xbfz\x8a\xf9\xff\xd1]O\xf7Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4UG\xfd\xb4\xae\x11\x95>\x01)+x\a\xfa\x92#\xd0\xe4`j\x89\x05]\x11}\xcb\x1d&\x00\x00\u07d4UR\xf4\xb3\xed>\x1d\xa7\x9a/x\xbb\x13\xe8\xaeZh\xa9\xdf;\x8965\u026d\xc5\u07a0\x00\x00\u07d4U\\\xa9\xf0\\\xc14\xabT\xae\x9b\xea\x1c?\xf8z\xa8Q\x98\u0289\x05k\xc7^-c\x10\x00\x00\xe0\x94U]\x8d<\xe1y\x8a\u0290'T\xf1d\xb8\xbe*\x022\x9cl\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U]\xf1\x93\x90\xc1m\x01)\x87r\xba\xe8\xbc:\x11R\x19\x9c\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U^\xbe\x84\u06a4+\xa2V\xeax\x91\x05\xce\u0136\x93\xf1/\x18\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94U\u007f^e\xe0\xda3\x99\x82\x19\xadN\x99W\x05E\xb2\xa9\xd5\x11\x8a\x02U\x9c\xbb\x98XB@\x00\x00\u07d4U\x83` h\x83\xdd\x1bmJYc\x9eV)\xd0\xf0\xc6u\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4U\x84B0P\xe3\xc2\x05\x1f\v\xbd\x8fD\xbdm\xbc'\xec\xb6,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4U\x85)CI)p\xf8\xd6)\xa1Sf\xcd\xda\x06\xa9OE\x13\x89lk\x93[\x8b\xbd@\x00\x00\u0794U\x86d\x86\xec\x16\x8fy\xdb\xe0\u1af1\x88d\u0649\x91\xae,\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4U\x8cTd\x9a\x8an\x94r+\xd6\xd2\x1d\x14qOqx\x054\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\x91\x940O\x14\xb1\xb9:\xfeDO\x06$\xe0S\xc2:\x00\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U\x93\xc9\u0536ds\x0f\xd9<\xa6\x01Q\xc2\\.\xae\xd9<;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U\x97\x06\xc32\xd2\ay\xc4_\x8am\x04ji\x91Y\xb7I!\x89\x14\x9bD.\x85\xa3\u03c0\x00\u07d4U\x98\xb3\xa7\x9aH\xf3+\x1f_\xc9\x15\xb8{d]\x80]\x1a\xfe\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4U\xa3\xdfW\xb7\xaa\xec\x16\xa1b\xfdS\x16\xf3[\xec\b(!\u03c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa4\xca\xc0\u02cbX-\x9f\xef8\xc5\xc9\xff\xf9\xbdS\t=\x1f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa6\x1b\x10\x94\x80\xb5\xb2\xc4\xfc\xfd\xef\x92\xd9\x05\x84\x16\f\r5\x89\x02lVM+S\xf6\x00\x00\u07d4U\xaa]1>\xbb\bM\xa0\xe7\x80\x10\x91\u2792\xc5\xde\u00ea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xab\x99\xb0\xe0\xe5]{\xb8t\xb7\xcf\xe84\xdec\x1c\x97\xec#\x897\xe9\x8c\xe3h\x99\xe4\x00\x00\u07d4U\xaf\t/\x94\xbajy\x91\x8b\f\xf99\xea\xb3\xf0\x1b?Q\u01c9\b \xd5\xe3\x95v\x12\x00\x00\u07d4U\xc5dfAf\xa1\xed\xf3\x91>\x01i\xf1\xcdE\x1f\xdb]\f\x89\x82\x17\xeaIP\x8el\x00\x00\xe0\x94U\xcaj\xbey\xea$\x97\xf4o\u06f804`\x10\xfeF\x9c\xbe\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4U\xca\xffK\xba\x04\xd2 \u0265\xd2\x01\x86r\xec\x85\xe3\x1e\xf8>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xd0W\xbc\xc0K\xd0\xf4\xaf\x96BQ:\xa5\t\v\xb3\xff\x93\xfe\x89;\xfeE,\x8e\xddL\x00\x00\u07d4U\xd4.\xb4\x95\xbfF\xa64\x99{_.\xa3b\x81I\x18\u2c09\x05\xc0\xd2e\xb5\xb2\xa8\x00\x00\u07d4U\u069d\xcd\xcaa\xcb\xfe\x1f\x13<{\xce\xfc\x86{\x9c\x81\"\xf9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4U\xe2 \x87bb\xc2\x18\xafOVxG\x98\xc7\xe5]\xa0\x9e\x91\x89\a=\x99\xc1VE\xd3\x00\x00\u07d4U\xfd\b\u0440d\xbd ,\x0e\xc3\xd2\xcc\xe0\xce\v\x9d\x16\x9cM\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x00s\nU\xf6\xb2\x0e\xbd$\x81\x1f\xaa=\xe9m\x16b\xab\xab\x89e\xea=\xb7UF`\x00\x00\u07d4V\x03$\x1e\xb8\xf0\x8fr\x1e4\x8c\x9d\x9a\xd9/H\u342a$\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4V\x056yJ\x9e+\x00I\xd1\x023\xc4\x1a\xdc_A\x8a&J\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\aY\x00Y\xa9\xfe\xc1\x88\x11I\xa4K6\x94\x9a\xef\x85\xd5`\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V\v\xec\xdfR\xb7\x1f=\x88'\xd9'a\x0f\x1a\x98\x0f3qo\x89\x17GMp_V\u0400\x00\xe0\x94V\r\xa3~\x95m\x86/\x81\xa7_\u0540\xa7\x13\\\x1b$cR\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94V\x0f\xc0\x8d\a\x9f\x04~\xd8\xd7\xdfuU\x1a\xa55\x01\xf5p\x13\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4V\x1b\xe9)\x9b>k>c\xb7\x9b\t\x16\x9d\x1a\x94\x8a\xe6\xdb\x01\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94V \xe3\xedy-/\x185\xfe_UA}Q\x11F\fj\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4V \xf4m\x14Q\xc25=bC\xa5\u0534'\x13\v\xe2\xd4\a\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94V!\x05\xe8+\t\x975\xdeI\xf6&\x92\u0307\xcd8\xa8\xed\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94V*\x8d\u02fe\xee\xf7\xb3`h]'0;\u059e\tJ\xcc\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4V+\xce\u04ca\xb2\xabl\b\x0f;\x05A\xb8Enp\x82K?\x89\"\xca5\x87\xcfN\xb0\x00\x00\xe0\x94V+\xe9Z\xba\x17\xc57\x1f\u2e82\x87\x99\xb1\xf5]!w\u058a\b\x16\xd3~\x87\xb9\xd1\xe0\x00\x00\u07d4V/\x16\u05da\xbf\xce\u00d4>4\xb2\x0f\x05\xf9{\xdf\u0366\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4V7=\xaa\xb4c\x16\xfd~\x15v\xc6\x1ej\xff\xcbeY\xdd\u05c9\v\xacq]\x14l\x9e\x00\x00\u07d4V9v8\xbb<\xeb\xf1\xf6 byK^\xb9B\xf9\x16\x17\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V:\x03\xab\x9cV\xb6\x00\xf6\xd2[f\f!\xe1c5Qzu\x8965\u026d\xc5\u07a0\x00\x00\u07d4V<\xb8\x80<\x1d2\xa2['\xb6A\x14\x85+\xd0M\x9c \u0349\v\x14\x9e\xad\n\xd9\xd8\x00\x00\u07d4VXc\x91\x04\fW\xee\xc6\xf5\xaf\xfd\x8c\u052b\xde\x10\xb5\n\u0309\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Vl\x10\xd68\u8e0bG\xd6\xe6\xa4\x14Iz\xfd\xd0\x06\x00\u0509\x05k9Bc\xa4\f\x00\x00\u07d4Vl(\xe3L8\b\xd9vo\xe8B\x1e\xbfO+\x1cO}w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x8d\xf3\x18Vi\x9b\xb5\xac\xfc\x1f\xe1\u0580\u07d9`\xcaCY\x89J\xcfUR\xf3\xb2I\x80\x00\u07d4V\x91\xdd/gE\xf2\x0e\"\xd2\xe1\u0479U\xaa)\x03\xd6VV\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4V\xa1\xd6\r@\xf5\u007f0\x8e\xeb\xf0\x87\xde\xe3\xb3\u007f\x1e|,\xba\x89>\u072e\xc8-\x06\xf8\x00\x00\u07d4V\xac \xd6;\xd8\x03Y\\\xec\x03m\xa7\xed\x1d\xc6n\n\x9e\a\x89\x03w*S\xcc\xdce\x80\x00\u07d4V\xb6\xc2=\xd2\uc434r\x8f;\xb2\xe7d\xc3\xc5\f\x85\xf1D\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xdf\x05\xba\xd4l?\x00\xaeGn\xcf\x01{\xb8\xc8w8?\xf1\x89\n\xb1]\xaa\xefp@\x00\x00\u07d4V\xee\x19\u007fK\xbf\x9f\x1b\x06b\xe4\x1c+\xbd\x9a\xa1\xf7\x99\xe8F\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xf4\x93\xa3\xd1\b\xaa\xa2\u044d\x98\x92/\x8e\xfe\x16b\u03f7=\x89m\x81!\xa1\x94\xd1\x10\x00\x00\u07d4V\xfc\x1a{\xad@G#|\xe1\x16\x14b\x96#\x8e\a\x8f\x93\xad\x89\t\xa6?\b\xeac\x88\x00\x00\u07d4V\xfe\xbf\x9e\x10\x03\xaf\x15\xb1\xbdI\a\xec\b\x9aJ\x1b\x91\xd2h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4W\x17\u0313\x01Q\x1dJ\x81\xb9\xf5\x83\x14\x8b\xee\xd3\xd3\u0303\t\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4W\x17\xf2\xd8\xf1\x8f\xfc\xc0\xe5\xfe$}:B\x19\x03|:d\x9c\x89\u063beI\xb0+\xb8\x00\x00\u07d4W\x19P\xea,\x90\xc1B}\x93\x9da\xb4\xf2\xdeL\xf1\u03ff\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4W\x19\xf4\x9br\r\xa6\x88V\xf4\xb9\xe7\b\xf2VE\xbd\xbcKA\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4W*\xc1\xab\xa0\xde#\xaeA\xa7\xca\xe1\xdc\bB\u062b\xfc\x10;\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94W-\xd8\xcd?\xe3\x99\xd1\xd0\xec(\x121\xb7\xce\xfc \xb9\u4eca\x023\xc8\xfeBp>\x80\x00\x00\xe0\x94WI!\x83\x8c\xc7}l\x98\xb1}\x90::\xe0\xee\r\xa9[\u040a\vS(\x17\x8a\xd0\xf2\xa0\x00\x00\u07d4WJ\xd95S\x90\u421e\xf4*\xcd\x13\x8b*'\xe7\x8c\x00\xae\x89Tg\xb72\xa9\x134\x00\x00\u07d4WM\xe1\xb3\xf3\x8d\x91XF\xae7\x18VJZ\xda \xc2\xf3\xed\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94W\\\x00\u0081\x82\x10\u0085U\xa0\xff)\x01\x02\x89\xd3\xf8#\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94Ws\xb6\x02g!\xa1\xdd\x04\xb7\x82\x8c\xd6+Y\x1b\xfb4SL\x8a\x05\xb7\xacES\xdez\xe0\x00\x00\xe0\x94WwD\x1c\x83\xe0?\v\xe8\xdd4\v\xdechP\x84|b\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Wx\xff\u071b\x94\u0165\x9e\"N\xb9e\xb6\u0790\xf2\"\xd1p\x89\x12-\u007f\xf3f\x03\xfc\x00\x00\u07d4Wz\xee\xe8\u053c\b\xfc\x97\xab\x15n\xd5\u007f\xb9p\x92Sf\xbe\x89\x12\r\xf1\x14rX\xbf\x00\x00\u07d4W{-\a\xe9\xcfRJ\x18\u04c9\x15Vak\x96\x06g\x00\x00\u07d4W\xd5\xfd\x0e=0I3\x0f\xfc\xdc\xd0 Ei\x17e{\xa2\u0689k\xf2\x01\x95\xf5T\xd4\x00\x00\u07d4W\u0754q\xcb\xfa&'\t\xf5\U00106f37t\xc5\xf5'\xb8\xf8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4W\xdf#\xbe\xbd\xc6^\xb7_\ub732\xfa\xd1\xc0si++\xaf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4X\x00\u03410\x83\x9e\x94I]-\x84\x15\xa8\xea,\x90\xe0\xc5\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94X\x03\xe6\x8b4\xda\x12\x1a\xef\b\xb6\x02\xba\u06ef\xb4\xd1$\x81\u028a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\xe0\x94X\x16\xc2hww\xb6\xd7\u04a2C-Y\xa4\x1f\xa0Y\xe3\xa4\x06\x8a\x1cO\xe4:\xdb\n^\x90\x00\x00\u07d4X\x1a:\xf2\x97\xef\xa4Cj)\xaf\x00r\x92\x9a\xbf\x98&\xf5\x8b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\x1b\x9f\xd6\xea\xe3r\xf3P\x1fB\xeb\x96\x19\xee\xc8 \xb7\x8a\x84\x8a\x04+\xe2\xc0\f\xa5;\x8d\x80\x00\u07d4X\x1b\xdf\x1b\xb2v\xdb\u0746\xae\xdc\xdb9z\x01\xef\xc0\xe0\f[\x8965\u026d\xc5\u07a0\x00\x00\u07d4X\x1f4\xb5#\xe5\xb4\x1c\t\xc8|)\x8e)\x9c\xbc\x0e)\xd0f\x89=X3\xaa\xfd9u\x80\x00\xe0\x94X$\xa7\xe2(8'q40\x8c_KP\u06b6^C\xbb1\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4X+pf\x9c\x97\xaa\xb7\u0581H\xd8\xd4\xe9\x04\x11\xe2\x81\rV\x8965f3\xeb\xd8\xea\x00\x00\u07d4X.|\xc4o\x1d{Nn\x9d\x95\x86\x8b\xfd7\x05s\x17\x8fL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X>\x83\xbaU\xe6~\x13\xe0\xe7o\x83\x92\xd8s\xcd!\xfb\xf7\x98\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Xi\xfb\x86}q\xf18\u007f\x86;i\x8d\t\xfd\xfb\x87\u011b\\\x89\u01bb\xf8X\xb3\x16\b\x00\x00\u07d4X}hI\xb1h\xf6\xc33+z\xba\xe7\xeblB\xc3\u007fH\xbf\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4X\x87\xdcj3\xdf\xedZ\xc1\xed\xef\xe3^\xf9\x1a!b1\xac\x96\x89\r\x8drkqw\xa8\x00\x00\xe0\x94X\x8e\u0650\xa2\xaf\xf4J\x94\x10]X\xc3\x05%w5\xc8h\xac\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4X\xae-\xdc_L\x8a\u0697\xe0l\x00\x86\x17\x17g\xc4#\xf5\u05c9WG=\x05\u06ba\xe8\x00\x00\u07d4X\xae\xd6gJ\xff\xd9\xf6B3'*W\x8d\xd98k\x99\xc2c\x89\xb8Pz\x82\a( \x00\x00\xe0\x94X\xb8\b\xa6[Q\xe63\x89i\xaf\xb9^\xc7\a5\xe4Q\xd5&\x8a\bxK\xc1\xb9\x83z8\x00\x00\u07d4X\xb8\xae\x8fc\xef5\xed\ab\xf0\xb6#=J\xc1Nd\xb6M\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X\xba\x15ie\x0e[\xbb\xb2\x1d5\xd3\xe1u\xc0\u05b0\xc6Q\xa9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4X\xc5U\xbc)<\xdb\x16\xc66.\xd9z\xe9U\v\x92\xea\x18\x0e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4X\xc6P\xce\xd4\v\xb6VA\xb8\xe8\xa9$\xa09\xde\xf4hT\u07c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4X\xc9\aT\xd2\xf2\n\x1c\xb1\xdd3\x06%\xe0KE\xfaa\x9d\\\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xe2\xf1\x12#\xfc\x827\xf6\x9d\x99\xc6(\x9c\x14\x8c\x06\x04\xf7B\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4X\xe5T\xaf=\x87b\x96 \xdaa\xd58\xc7\xf5\xb4\xb5LJ\xfe\x89FP\x9diE4r\x80\x00\u07d4X\xe5\xc9\xe3D\xc8\x06e\r\xac\xfc\x90M3\xed\xbaQ\a\xb0\u0789\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4X\xe6a\u043as\xd6\xcf$\t\x9aUb\xb8\b\xf7\xb3g;h\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xf0[&%`P<\xa7a\xc6\x18\x90\xa4\x03_Lsr\x80\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4X\xfb\x94sd\xe7iWe6\x1e\xbb\x1e\x80\x1f\xfb\x8b\x95\xe6\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Y\x01\x81\xd4E\x00{\u0407Z\xaf\x06\x1c\x8dQ\x159\x00\x83j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x02\xe4J\xf7i\xa8rF\xa2\x1e\a\x9c\b\xbf6\xb0n\xfe\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4Y\n\xcb\xda7)\f\r>\xc8O\xc2\x00\rv\x97\xf9\xa4\xb1]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94Y\f\xcbY\x11\xcfx\xf6\xf6\"\xf55\xc4t7_J\x12\xcf\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y\x10\x10m\xeb\u0491\xa1\u0340\xb0\xfb\xbb\x8d\x8d\x9e\x93\xa7\xcc\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x16\x17I\xfe\xdc\xf1\xc7!\xf2 -\x13\xad\xe2\xab\xcfF\v=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Y\x1b\xef1q\xd1\u0155w\x17\xa4\xe9\x8d\x17\xeb\x14,!NV\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y <\xc3u\x99\xb6H1*|\xc9\xe0m\xac\xb5\x89\xa9\xaej\x89\b\x0fyq\xb6@\x0e\x80\x00\u07d4Y&\x81q\xb83\xe0\xaa\x13\xc5KR\xcc\xc0B.O\xa0:\ub262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94Y'w&\x1e;\xd8R\u010e\u0295\xb3\xa4L[\u007f-B,\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y0Dg\x0f\xae\xff\x00\xa5[Z\xe0Q\xeb{\xe8p\xb1\x16\x94\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94Y;E\xa1\x86J\xc5\xc7\xe8\xf0\u02ae\xba\r\x87<\xd5\xd1\x13\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Y_^\xdajV\xf1N%\xe0\xc6\xf3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Z\x1a3ib\xd6\xe0\xc601\u0303\u01a5\u01a6\xf4G\x8e\u02c965\u026d\xc5\u07a0\x00\x00\u07d4Z\x1d--\x1dR\x03\x04\xb6 \x88IW\x047\xeb0\x91\xbb\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Z&s1\xfa\xcb&-\xaa\xec\xd9\xddc\xa9p\f_RY\u07c9\x05k\xc7^-c\x10\x00\x00\xe0\x94Z(WU9\x1e\x91NX\x02_\xaaH\xcch_O\xd4\xf5\xb8\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4Z)\x16\xb8\xd2\xe8\xcc\x12\xe2\a\xabFMC>#p\xd8#\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4Z+\x1c\x85:\xeb(\xc4U9\xafv\xa0\n\xc2\u0628$(\x96\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4Z-\xaa\xb2\\1\xa6\x1a\x92\xa4\xc8,\x99%\xa1\xd2\xefXX^\x89\f8\r\xa9\u01d5\f\x00\x00\u07d4Z0\xfe\xac7\xac\x9fr\u05f4\xaf\x0f+\xc79R\xc7O\xd5\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4ZTh\xfa\\\xa2&\xc7S.\xcf\x06\xe1\xbc\x1cE\"]~\u0249g\x8a\x93 b\xe4\x18\x00\x00\u07d4ZVR\x857JI\xee\xddPL\x95}Q\bt\xd0\x04U\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4Z^\xe8\xe9\xbb\x0e\x8a\xb2\xfe\xcbK3\u0494x\xbeP\xbb\xd4K\x89*\x11)\u0413g \x00\x00\xe0\x94Z_\x85\b\xda\x0e\xbe\xbb\x90\xbe\x903\xbdM\x9e'A\x05\xae\x00\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4Z`q\xbc\xeb\xfc\xbaJ\xb5\u007fM\xb9o\u01e6\x8b\xec\xe2\xba[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z`\xc9$\x16(s\xfc~\xa4\xda\u007f\x97.5\x01g7`1\x89\x04\x87\xf2w\xa8\x85y\x80\x00\u07d4Zf\x86\xb0\xf1~\a\xed\xfcY\xb7Y\xc7}[\xef\x16M8y\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Zp\x10o \xd6?\x87Re\xe4\x8e\r5\xf0\x0e\x17\xd0+\u0249\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794Zt\xbab\xe7\xc8\x1a4t\xe2}\x89O\xed3\xdd$\xad\x95\xfe\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94Zw5\x00}p\xb0hD\u0699\x01\xcd\xfa\xdb\x11\xa2X,/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Z\x82\xf9l\u0537\xe2\xd9=\x10\xf3\x18]\xc8\xf4=Ku\xaai\x89lc?\xba\xb9\x8c\x04\x00\x00\u07d4Z\x87\xf04\xe6\xf6\x8fNt\xff\xe6\fd\x81\x946\x03l\xf7\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\x89\x11U\xf5\x0eB\aCt\xc79\xba\xad\xf7\xdf&Q\x15:\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\u07d4Z\x9c\x8bi\xfcaMiVI\x99\xb0\r\xcbB\xdbg\xf9~\x90\x89\xb9\xe6\x15\xab\xad:w\x80\x00\xe0\x94Z\xaf\x1c1%Jn\x00_\xba\u007fZ\xb0\xecy\xd7\xfc+c\x0e\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4Z\xb1\xa5aSH\x00\x1c|w]\xc7WHf\x9b\x8b\xe4\xde\x14\x89%jr\xfb)\xe6\x9c\x00\x00\xe1\x94Z\xbf\xec%\xf7L\u06047c\x1aw1\x90i2wcV\xf9\x8b\t\xd8<\xc0\u07e1\x11w\xff\x80\x00\u07d4Z\u0090\x8b\x0f9\x8c\r\xf5\xba\xc2\xcb\x13\xcas\x14\xfb\xa8\xfa=\x89\n\xd4\xc81j\v\f\x00\x00\xe0\x94Z\u025a\u05c1j\xe9\x02\x0f\xf8\xad\xf7\x9f\xa9\x86\x9b|\xeaf\x01\x8a\x04ri\x8bA;C \x00\x00\u07d4Z\xd1,^\xd4\xfa\x82~!P\u03e0\u058c\n\xa3{\x17i\xb8\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94Z\xd5\xe4 uV\x13\x88o5\xaaV\xac@>\xeb\xdf\xe4\xb0\u040a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4Z\xdew\xfd\x81\xc2\\\n\xf7\x13\xb1\a\x02v\x8c\x1e\xb2\xf9u\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Z\xe6N\x85;\xa0\xa5\x12\x82\u02cd\xb5.Aa^|\x9fs?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xed\x0el\xfe\x95\xf9\u0580\xc7dr\xa8\x1a+h\n\u007f\x93\xe2\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Z\xef\x16\xa2&\xddh\a\x1f$\x83\xe1\xdaBY\x83\x19\xf6\x9b,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xf4j%\xac\t\xcbsakS\xb1O\xb4/\xf0\xa5\x1c\u0772\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Z\xf7\xc0r\xb2\u016c\xd7\x1cv\xad\xdc\xceS\\\xf7\xf8\xf95\x85\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\xfd\xa9@\\\x8e\x976QEt\u0692\x8d\xe6tV\x01\t\x18\x8a\x01E\xb8\xb0#\x9aF\x92\x00\x00\u07d4[\x06\xd1\xe6\x93\f\x10Ti+y\xe3\xdb\xe6\xec\xceS\x96d \x89\v\"\u007fc\xbe\x81<\x00\x00\u07d4[%\xca\xe8m\xca\xfa*`\xe7r61\xfc_\xa4\x9c\x1a\xd8}\x89\x87\fXQ\x0e\x85 \x00\x00\u07d4[(|~sB\x99\xe7'bo\x93\xfb\x11\x87\xa6\rPW\xfe\x89\x05|\xd94\xa9\x14\xcb\x00\x00\u07d4[)\f\x01\x96|\x81.M\xc4\xc9\v\x17L\x1b@\x15\xba\xe7\x1e\x89\b \xeb4\x8dR\xb9\x00\x00\u07d4[+d\xe9\xc0X\u30a8\xb2\x99\"N\xec\xaa\x16\xe0\x9c\x8d\x92\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\xe0\x94[./\x16\x18U.\xab\r\xb9\x8a\xddUc|)Q\xf1\xfb\x19\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4[0`\x8cg\x8e\x1a\xc4d\xa8\x99L;3\xe5\xcd\xf3Iq\x12\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[36\x96\xe0L\xca\x16\x92\xe7\x19\x86W\x9c\x92\rk)\x16\xf9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94[C\rw\x96\x96\xa3e?\xc6\x0et\xfb\u02ec\xf6\xb9\u00ba\xf1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4[Cse\xae:\x9a/\xf9|h\xe6\xf9\nv \x18\x8c}\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d4[I\xaf\xcduDx8\xf6\xe7\xce\u068d!w}O\xc1\xc3\xc0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4[L\f`\xf1\x0e\u0489K\xdbB\xd9\xdd\x1d!\x05\x87\x81\n\r\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4[N\xa1m\xb6\x80\x9b\x03R\u0536\xe8\x1c9\x13\xf7jQ\xbb2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[[\xe0\xd8\xc6rv\xba\xab\xd8\xed\xb3\rH\xeaud\v\x8b)\x89,\xb1\xf5_\xb7\xbe\x10\x00\x00\u07d4[]Qp)2\x15b\x11\x1bC\bm\v\x045\x91\x10\x9ap\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94[]\x8c\x8e\xedl\x85\xac!Va\xde\x02fv\x82?\xaa\n\f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4[mU\xf6q)g@\\e\x91)\xf4\xb1\xde\t\xac\xf2\xcb{\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4[p\u011c\u024b=\xf3\xfb\xe2\xb1Y\u007f\\\x1bcG\xa3\x88\xb7\x894\x95tD\xb8@\xe8\x00\x00\u07d4[sn\xb1\x83Sb\x9b\u0796v\xda\xdd\x16P4\xce^\xcch\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[u\x9f\xa1\x10\xa3\x1c\x88F\x9fT\xd4K\xa3\x03\xd5}\xd3\xe1\x0f\x89[F\xdd/\x0e\xa3\xb8\x00\x00\u07d4[w\x84\xca\xea\x01y\x9c\xa3\x02'\x82vg\xce |\\\xbcv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4[x\xec\xa2\u007f\xbd\xeao&\xbe\xfb\xa8\x97+)^x\x146K\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94[\x80\v\xfd\x1b>\u0525}\x87Z\xed&\xd4/\x1aw\b\xd7*\x8a\x01Z\x82\xd1\u057b\x88\xe0\x00\x00\u07d4[\x85\xe6\x0e*\xf0TO/\x01\xc6N 2\x90\x0e\xbd8\xa3\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4[\xa2\xc6\xc3]\xfa\xec)h&Y\x19\x04\xd5DFJ\xea\xbd^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94[\xafmt\x96 \x80>\x83H\xaf7\x10\xe5\xc4\xfb\xf2\x0f\u0214\x8a\x01\x0f@\x02a]\xfe\x90\x00\x00\u07d4[\xc1\xf9U\a\xb1\x01\x86B\xe4\\\xd9\xc0\xe2'3\xb9\xb1\xa3&\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94[\xd25GG\u007fm\t\u05f2\xa0\x05\xc5\xeee\fQ\fV\u05ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4[\xd2J\xac6\x12\xb2\f`\x9e\xb4gy\xbf\x95i\x84\a\xc5|\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[\u0586-Q}M\xe4U\x9dN\xec\n\x06\xca\xd0^/\x94n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4[\xe0EQ*\x02n?\x1c\xeb\xfdZ~\xc0\xcf\xc3o-\xc1k\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94[\xf9\xf2\"nZ\xea\xcf\x1d\x80\xae\nY\xc6\xe3\x808\xbc\x8d\xb5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4[\xfa\xfe\x97\xb1\xdd\x1dq+\xe8mA\xdfy\x89SE\x87Z\x87\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\\\x0f.Q7\x8fk\r{\xabas1X\vn9\xad<\xa5\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\\)\xf9\xe9\xa5#\xc1\xf8f\x94H\xb5\\H\xcb\xd4|%\xe6\x10\x894F\xa0\xda\xd0L\xb0\x00\x00\xe0\x94\\0\x8b\xacHW\xd3;\xae\xa0t\xf3\x95m6!\xd9\xfa(\xe1\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\\1*V\u01c4\xb1\"\t\x9bvM\x05\x9c!\xec\xe9^\x84\u0289\x05&c\u032b\x1e\x1c\x00\x00\u07d4\\1\x99m\xca\xc0\x15\xf9\xbe\x98[a\x1fF\x870\xef$M\x90\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\\24W\xe1\x87v\x1a\x82v\xe3Y\xb7\xb7\xaf?;n=\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\<\x1cd[\x91uC\x11;>l\x1c\x05M\xa1\xfet+\x9a\x89+^:\xf1k\x18\x80\x00\x00\u0794\\=\x19D\x1d\x19l\xb4Cf \xfc\xad\u007f\xbby\xb2\x9ex\x88\xc6s\xce<@\x16\x00\x00\u07d4\\?V\u007f\xaf\xf7\xba\u0475\x12\x00\"\xe8\xcb\u02a8+I\x17\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\\Ch\x91\x8a\xced\t\u01de\u0280\u036a\xe49\x1d+bN\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\\FA\x97y\x1c\x8a=\xa3\xc9%Co'z\xb1;\xf2\xfa\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\\H\x81\x16\\\xb4+\xb8.\x979l\x8e\xf4J\xdb\xf1s\xfb\x99\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\xe0\x94\\H\x92\x90z\a \xdfo\xd3A>c\xffv}k9\x80#\x8a\x02\xcb\x00\x9f\u04f5y\x0f\x80\x00\u07d4\\O$\xe9\x94\ud3c5\x0e\xa7\x81\x8fG\x1c\x8f\xac;\xcf\x04R\x89]\x80h\x8d\x9e1\xc0\x00\x00\u07d4\\T\x19V\\:\xadNqN\a92\x8e5!\u024f\x05\u0309\x1c\x9fx\u0489>@\x00\x00\u07d4\\a6\xe2\x18\xde\na\xa17\xb2\xb3\x96-*a\x12\xb8\t\u05c9\x0f\xf3\u06f6_\xf4\x86\x80\x00\xe0\x94\\a\xaby\xb4\b\xdd2)\xf6bY7\x05\xd7/\x1e\x14{\xb8\x8a\x04\xd0$=4\x98\u0344\x00\x00\u07d4\\m\x04\x1d\xa7\xafD\x87\xb9\xdcH\xe8\xe1\xf6\af\u0425m\xbc\x89O\a\n\x00>\x9ct\x00\x00\u07d4\\o6\xaf\x90\xab\x1aeln\xc8\xc7\xd5!Q'b\xbb\xa3\xe1\x89lh\xcc\u041b\x02,\x00\x00\u07d4\\{\x9e\u01e2C\x8d\x1eD*\x86\x0f\x8a\x02\x1e\x18\x99\xf07z\xea\x00\x00\u07d4\\\xcc\xf1P\x8b\xfd5\xc2\x050\xaad%\x00\xc1\r\xeee\xea\xed\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\\\xcer\xd0h\xc7\xc3\xf5[\x1d(\x19T^w1|\xae\x82@\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\\\xd0\xe4u\xb5D!\xbd\xfc\f\x12\xea\x8e\b+\u05e5\xaf\nj\x89\x032\xca\x1bg\x94\f\x00\x00\u07d4\\\u0548\xa1N\xc6H\xcc\xf6G)\xf9\x16z\xa7\xbf\x8b\xe6\xeb=\x8965\u026d\xc5\u07a0\x00\x00\u07d4\\\u062f`\xdee\xf2M\xc3\xceW0\xba\x92e0\"\xdcYc\x89a\t=|,m8\x00\x00\u07d4\\\xdcG\b\xf1O@\xdc\xc1Zy_}\xc8\xcb\v\u007f\xaa\x9en\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\\\u0d86,\u0391b\xe8~\bI\xe3\x87\xcb]\xf4\xf9\x11\x8c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\\\xe2\xe7\u03aa\xa1\x8a\xf0\xf8\xaa\xfa\u007f\xba\xd7L\u021e<\xd46\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\\\xe4@h\xb8\xf4\xa3\xfey\x9ej\x83\x11\xdb\xfd\xed\xa2\x9d\xee\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u0794\\\xeb\xe3\v*\x95\xf4\xae\xfd\xa6ee\x1d\xc0\xcf~\xf5u\x81\x99\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\\\xf1\x8f\xa7\u0227\xc0\xa2\xb3\xd5\xef\u0459\x0fd\xdd\xc5i$,\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\\\xf4N\x10T\reqd#\xb1\xbc\xb5B\xd2\x1f\xf8:\x94\u034a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\\xf8\xc0>\xb3\xe8r\xe5\x0f|\xfd\f/\x8d;?,\xb5\x18:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\\\xfa\x8dV\x85ue\x8c\xa4\xc1\xa5\x93\xacL]\x0eD\xc6\aE\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\\\xfa\x98w\xf7\x19\u01dd\x9eIJ\b\xd1\xe4\x1c\xf1\x03\xfc\x87\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4]\x1d\xc38{G\xb8E\x1eU\x10l\f\xc6}m\xc7+\u007f\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4]#\x1ap\xc1\xdf\xeb6\n\xbd\x97\xf6\x16\xe2\xd1\r9\xf3\u02b5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4]$\xbd\xbc\x1cG\xf0\xeb\x83\xd1(\xca\xe4\x8a\xc3\xf4\xb5\x02bt\a\xda'/g\x81Jk\xec\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4]\x83\xb2\x1b\xd2q#`Ckg\xa5\x97\xee3x\xdb>z\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94]\x87+\x12.\x99N\xf2|q\xd7\u07b4W\xbfeB\x9e\xcal\x8a\x01\xb1\xad\xed\x81\u04d4\x10\x80\x00\xe0\x94]\x8d1\xfa\xa8d\xe2!Y\xcdoQu\xcc\xec\xc5?\xa5Mr\x8a\x05\xb6\x96\xb7\r\xd5g\x10\x00\x00\xe0\x94]\x95\x8a\x9b\u0449\u0098_\x86\u014a\x8ci\xa7\xa7\x88\x06\xe8\u068a\x02(\xf1o\x86\x15x`\x00\x00\u07d4]\xa2\xa9\xa4\xc2\xc0\xa4\xa9$\xcb\xe0\xa5:\xb9\xd0\xc6'\xa1\u03e0\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4]\xa4\u0288\x93\\'\xf5\\1\x10H\x84\x0eX\x9e\x04\xa8\xa0I\x89\x04V9\x18$O@\x00\x00\u07d4]\xa5G\x85\u027d0W\\\x89\u07b5\x9d A\xd2\n9\xe1{\x89j\xa2\t\xf0\xb9\x1de\x80\x00\xe0\x94]\xb6\x9f\xe9>o\xb6\xfb\xd4P\x96k\x97#\x8b\x11\n\xd8'\x9a\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4]\xb7\xbb\xa1\xf9W?$\x11]\x8c\x8cb\xe9\u0388\x95\x06\x8e\x9f\x89\x02\xb5\xaa\xd7,e \x00\x00\xe0\x94]\xb8D\x00W\x00i\xa9W<\xab\x04\xb4\u6d955\xe2\x02\xb8\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4]\xc3m\xe55\x94P\xa1\xec\t\xcb\fD\xcf+\xb4+:\xe45\x89<\x94m\x89;3\x06\x00\x00\u07d4]\xc6\xf4_\xef&\xb0n3\x021?\x88M\xafH\xe2to\xb9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94]\u0376\xb8zP\xa9\xde\x02C\x80\x00\x00\u07d4^Q\xb8\xa3\xbb\t\xd3\x03\xea|\x86\x05\x15\x82\xfd`\x0f\xb3\xdc\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794^X\xe2U\xfc\x19\x87\n\x040_\xf2\xa0F1\xf2\xff)K\xb1\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4^ZD\x19t\xa8=t\u0187\xeb\xdcc?\xb1\xa4\x9e{\x1a\u05c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^eE\x8b\xe9d\xaeD\x9fqw7\x04\x97\x97f\xf8\x89\x87a\x89\x1c\xa7\xccs[o|\x00\x00\u07d4^g\u07c9i\x10\x1a\u06bd\x91\xac\xcdk\xb1\x99\x12t\xaf\x8d\xf2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4^n\x97G\xe1b\xf8\xb4\\en\x0fl\xaez\x84\xba\xc8\x0eN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^s\x1bU\xce\xd4R\xbb??\xe8q\xdd\xc3\xed~\xe6Q\n\x8f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^t\xed\x80\xe9eW\x88\xe1\xbb&\x97R1\x96g\xfeuNZ\x89\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4^w.'\xf2\x88\x00\xc5\r\u0697;\xb3>\x10v.n\xea \x89a\t=|,m8\x00\x00\u07d4^{\x8cT\xdcW\xb0@ bq\x9d\xee~\xf5\xe3~\xa3]b\x89\x9b\xf9\x81\x0f\xd0\\\x84\x00\x00\u07d4^\u007fp7\x87uX\x9f\xc6j\x81\xd3\xf6S\xe9T\xf5U`\ub243\xf2\x89\x18\x1d\x84\xc8\x00\x00\xe0\x94^\x80n\x84W0\xf8\a>l\xc9\x01\x8e\xe9\x0f\\\x05\xf9\t\xa3\x8a\x02\x01\xe9m\xac\u03af \x00\x00\u07d4^\x8eM\xf1\x8c\xf0\xafw\tx\xa8\u07cd\xac\x90\x93\x15\x10\xa6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^\x90\xc8Xw\x19\x87V\xb06l\x0e\x17\xb2\x8eR\xb4FPZ\x89\x14JJ\x18\xef\xebh\x00\x00\u07d4^\x95\xfe_\xfc\xf9\x98\xf9\xf9\xac\x0e\x9a\x81\u06b8>\xadw\x00=\x89\x1dB\xc2\r2y\u007f\x00\x00\u07d4^\xad)\x03z\x12\x89dx\xb1)j\xb7\x14\xe9\u02d5B\x8c\x81\x89\x03\xe0C\a-@n\x00\x00\u07d4^\xb3q\xc4\a@lB{;}\xe2q\xad<\x1e\x04&\x95y\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^\u037a\xea\xb9\x10o\xfe]{Q\x96\x96`\x9a\x05\xba\ub16d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4^\xd0\xd63\x85Y\xefD\xdcza\xed\xeb\x89?\xa5\xd8?\xa1\xb5\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94^\u04fb\xc0R@\xe0\u04d9\xebm\xdf\xe6\x0fb\xdeM\x95\t\xaf\x8a)\x14\xc0$u\xf9\xd6\xd3\x00\x00\u0594^\xd3\xf1\xeb\xe2\xaegV\xb5\xd8\xdc\x19\xca\xd0,A\x9a\xa5w\x8b\x80\u07d4^\xd5a\x15\xbde\x05\xa8\x82s\xdf\\V\x83\x94p\xd2J-\xb7\x89\x03\x8ee\x91\xeeVf\x80\x00\xe0\x94^\xf8\xc9a\x86\xb3y\x84\xcb\xfe\x04\u0158@n;\n\xc3\x17\x1f\x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4^\xfb\xdf\xe58\x99\x99c<&`Z[\xfc,\x1b\xb5\x95\x93\x93\x89\x03\xc0W\xc9\\\xd9\b\x00\x00\xe0\x94_\x13\x15F1Fm\xcb\x13S\u0210\x93*|\x97\xe0\x87\x8e\x90\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4_\x16z\xa2B\xbcL\x18\x9a\xde\xcb:\u0127\xc4R\xcf\x19/\u03c9lkLM\xa6\u077e\x00\x00\xe0\x94_\x1c\x8a\x04\xc9\rs[\x8a\x15)\t\xae\xaeco\xb0\xce\x16e\x8a\x01{x'a\x8cZ7\x00\x00\u07d4_#\xba\x1f7\xa9lE\xbcI\x02YS\x8aT\u008b\xa3\xb0\u0549A\rXj \xa4\xc0\x00\x00\u07d4_&\xcf4Y\x9b\xc3n\xa6{\x9ez\x9f\x9bC0\xc9\xd5B\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4_)\xc9\xdev]\xde%\x85*\xf0}3\xf2\xceF\x8f\xd2\t\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_/\a\xd2\u0597\xe8\xc5g\xfc\xfd\xfe\x02\x0fI\xf3`\xbe!9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_2\x1b=\xaa\xa2\x96\xca\xdf)C\x9f\x9d\xab\x06*K\xff\xed\u0589\x04p%\x90>\xa7\xae\x00\x00\u07d4_3:;#\x10vZ\r\x182\xb9\xbeL\n\x03pL\x1c\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4_4K\x01\xc7\x19\x1a2\xd0v*\xc1\x88\xf0\xec-\xd4`\x91\x1d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94_6>\n\xb7G\xe0-\x1b;f\xab\xb6\x9e\xa5<{\xafR:\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4_7[\x86`\f@\u0328\xb2gkz\x1a\x1d\x16D\xc5\xf5,\x89\x04F\x18\xd7Lb?\x00\x00\u07d4_>\x1eg9\xb0\xc6\"\x00\xe0\n\x006\x91\xd9\xef\xb28\u061f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_H?\xfb\x8fh\n\xed\xf2\xa3\x8fx3\xaf\xdc\xdeY\xb6\x1eK\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94_J\xceL\x1c\xc13\x91\xe0\x1f\x00\xb1\x98\xe1\xf2\v_\x91\xcb\xf5\x8a\x01\x0f\x0f\xa8\xb9\u04c1\x1a\x00\x00\xe0\x94_R\x12\x82\xe9\xb2x\u070c\x03Lr\xafS\xee)\xe5D=x\x8a\x01as-/\x8f:\xe0\x00\x00\u07d4_h\xa2L~\xb4\x11vgs{39?\xb3\xc2\x14\x8aS\xb6\x89\x02\xce\u0791\x8dE<\x00\x00\u07d4_p\x8e\xaf9\xd8#\x94lQ\xb3\xa3\u9df3\xc0\x03\xe2cA\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4_t.H~:\xb8\x1a\xf2\xf9J\xfd\xbe\x1b\x9b\x8f\\\u0301\xbc\x89u\xc4E\xd4\x11c\xe6\x00\x00\u07d4_t\xed\x0e$\xff\x80\u0672\u0124K\xaa\x99uB\x8c\u05b95\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4_v\xf0\xa3\x06&\x9cx0k=e\r\xc3\xe9\xc3p\x84\xdba\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4_w\xa1\a\xab\x12&\xb3\xf9_\x10\ue0ee\xfcl]\xff>\u0709\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4_{;\xba\xc1m\xab\x83\x1aJ\x0f\xc5;\fT\x9d\xc3l1\u0289i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94_\x93\xff\x83't\xdbQ\x14\xc5[\xb4\xbfD\xcc\U000f53d0?\x8a(\xa9\xc9\x1a&4X)\x00\x00\u07d4_\x96\x16\xc4{Jg\xf4\x06\xb9Z\x14\xfeo\xc2h9o\x17!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4_\x98\x109\xfc\xf5\x02%\xe2\xad\xf7bu!\x12\xd1\xcc&\xb6\xe3\x89\x1b\x1aAj!S\xa5\x00\x00\u07d4_\x99\u070eI\xe6\x1dW\xda\xef`j\xcd\xd9\x1bMp\a2j\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_\xa6\x1f\x15-\xe6\x125\x16\xc7Q$)y(_yj\u01d1\x89\v\x0f\x11\x97)c\xb0\x00\x00\u07d4_\xa7\xbf\xe0C\x88a'\xd4\x01\x1d\x83V\xa4~\x94yc\xac\xa8\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94_\xa8\xa5Nh\x17lO\xe2\xc0\x1c\xf6q\xc5\x15\xbf\xbd\xd5(\xa8\x8aE\xe1U\xfa\x01\x10\xfa@\x00\x00\u07d4_\xad\x96\x0fk,\x84V\x9c\x9fMG\xbf\x19\x85\xfc\xb2\xc6]\xa6\x8965f3\xeb\xd8\xea\x00\x00\u07d4_\xc6\xc1\x14&\xb4\xa1\xea\xe7\xe5\x1d\xd5\x12\xad\x10\x90\xc6\xf1\xa8[\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4_\u0344Th\x96\xdd\b\x1d\xb1\xa3 \xbdM\x8c\x1d\xd1R\x8cL\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4_\u0368G\xaa\xf8\xd7\xfa\x8b\xca\b\x02\x9c\xa2\x84\x91f\xaa\x15\xa3\x89!\u02b8\x12Y\xa3\xbf\x00\x00\u07d4_\xd1\xc3\xe3\x17x'l\xb4.\xa7@\xf5\xea\xe9\xc6A\xdb\xc7\x01\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4_\xd3\xd6w~\xc2b\n\xe8:\x05R\x8e\xd4%\a-<\xa8\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_\xd9s\xaf6j\xa5\x15|Te\x9b\u03f2|\xbf\xa5\xac\x15\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4_\xe7w\x03\x80\x8f\x82>l9\x93R\x10\x8b\xdb,R|\xb8|\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94_\xecI\xc6e\xe6N\xe8\x9d\xd4A\xeet\x05n\x1f\x01\xe9(p\x8a\x01V\x9b\x9es4t\xc0\x00\x00\u07d4_\xf3&\xcd`\xfd\x13k$^)\xe9\bzj\u04e6R\u007f\r\x89e\xea=\xb7UF`\x00\x00\u07d4_\xf9=\xe6\xee\x05L\xadE\x9b-^\xb0\xf6\x87\x03\x89\xdf\xcbt\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4`\x06\xe3m\x92\x9b\xf4]\x8f\x16#\x1b\x12j\x01\x1a\xe2\x83\xd9%\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4`!\xe8Z\x88\x14\xfc\xe1\xe8*A\xab\xd1\u04f2\xda\xd2\xfa\xef\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4`8t\n\xe2\x8df\xba\x93\xb0\xbe\bH+2\x05\xa0\xf7\xa0{\x89\x11!a\x85\u009fp\x00\x00\u07d4`?/\xabz\xfbn\x01{\x94v`i\xa4\xb4;8\x96I#\x89Y\xd2\xdb$\x14\u0699\x00\x00\u07d4`B'm\xf2\x98?\xe2\xbcGY\xdc\x19C\xe1\x8f\xdb\xc3Ow\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4`B\xc6D\xba\xe2\xb9o%\xf9M1\xf6x\xc9\r\xc9f\x90\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4`L\xdf\x18b\x8d\xbf\xa82\x91\x94\xd4x\xddR\x01\xee\xccK\xe7\x89\x01?0j$\t\xfc\x00\x00\u07d4`N\x94w\xeb\xf4r|t[\u02bb\xed\xcbl\xcf)\x99@\"\x8966\x9e\xd7t}&\x00\x00\u07d4`gm\x1f\xa2\x1f\xca\x05\"\x97\xe2K\xf9c\x89\u0171*p\u05c9\r\x17|Zzh\xd6\x00\x00\u07d4`gn\x92\u044b\x00\x05\t\xc6\x1d\xe5@\xe6\xc5\u0776v\xd5\t\x89A\rXj \xa4\xc0\x00\x00\u07d4`o\x17q!\xf7\x85\\!\xa5\x06#0\xc8v\"d\xa9{1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\x86B6\x93\r\x04\xd8@+]\xcb\xeb\x80\u007f<\xafa\x1e\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\xabq\xcd&\xeamnY\xa7\xa0\xf6'\xee\a\x9c\x88^\xbb\xf6\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4`\xaf\x0e\xe1\x18D<\x9b7\xd2\xfe\xadw\xf5\xe5!\u07be\x15s\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4`\xb3X\xcb=\xbe\xfa7\xf4}\xf2\xd76X@\u068e;\u024c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4`\xb8\u05b7;ySO\xb0\x8b\xb8\xcb\xce\xfa\xc7\xf3\x93\xc5{\xfe\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4`\xbeo\x95?*M%\xb6%o\xfd$#\xac\x148%.N\x89\b!\xab\rD\x14\x98\x00\x00\u0794`\xc3qO\xdd\xdbcFY\u48b1\xeaB\xc4r\x8c\u01f8\xba\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4`\xcc=D^\xbd\xf7j}z\xe5q\u0197\x1d\xffh\u0305\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94`\xd5fq@\xd1&\x14\xb2\x1c\x8e^\x8a3\b.2\xdf\xcf#\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4`\xde\"\xa1Pt2\xa4{\x01\xcch\xc5*\v\xf8\xa2\xe0\u0418\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4`\xe0\xbd\u0422Y\xbb\x9c\xb0\x9d?7\xe5\u034b\x9d\xac\uafca\x89JD\x91\xbdm\xcd(\x00\x00\u07d4`\xe3\xccC\xbc\xdb\x02j\xadu\x9cpf\xf5U\xbb\xf2\xacf\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x04+\x80\xfd`\x95\u0478{\xe2\xf0\x0f\x10\x9f\xab\xaf\xd1W\xa6\x89\x05k\xc7^-c\x10\x00\x00\u07d4a\a\xd7\x1d\xd6\xd0\xee\xfb\x11\xd4\xc9\x16@L\xb9\x8cu>\x11}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x0f\xd6\xeeN\xeb\xab\x10\xa8\xc5]\vK\xd2\xe7\xd6\xef\x81qV\x89\x01\x15\x95a\x06]]\x00\x00\u07d4a\x14\xb0\xea\xe5Wi\x03\xf8\v\xfb\x98\x84-$\xed\x92#\u007f\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4a!\xaf9\x8a[-\xa6\x9fe\xc68\x1a\xec\x88\u039c\xc6D\x1f\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4a&g\xf1r\x13[\x95\v,\xd1\xde\x10\xaf\xde\xcehW\xb8s\x8965\u026d\xc5\u07a0\x00\x00\u07d4a,\xed\x8d\xc0\u071e\x89\x9e\xe4oyb33\x15\xf3\xf5^D\x89\x12^5\xf9\xcd=\x9b\x00\x00\u07d4a4\xd9B\xf07\xf2\xcc=BJ#\f`=g\xab\xd3\xed\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a:\xc5;\xe5e\xd4e6\xb8 q[\x9b\x8d:\xe6\x8aK\x95\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4a?\xabD\xb1k\xbeUMD\xaf\xd1x\xab\x1d\x02\xf3z\ua949lk\x93[\x8b\xbd@\x00\x00\u07d4aN\x8b\xef=\xd2\u015bY\xa4\x14Vt@\x10\x185\x18\x84\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4aQ\x84d\xfd\u0637<\x1b\xb6\xacm\xb6\x00eI8\xdb\xf1z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4aT}7nSi\xbc\xf9x\xfc\x16,1\xc9\b\"3\xb8%\xd0%\xbe?{\x10V\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4a\x91\xdd\u0276J\x8e\b\x90\xb427\t\u05e0|H\xb9*d\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4a\x96\xc3\xd3\xc0\x90\x8d%Cf\xb7\xbc\xa5WE\"-\x9dM\xb1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\x9f\x17\x14E\xd4+\x02\xe2\xe0p\x04\xad\x8a\xfeiO\xa5=j\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4a\xad\xf5\x92\x9a^)\x81hN\xa2C\xba\xa0\x1f}\x1f^\x14\x8a\x89\x05\xfa\xbfl\x98O#\x00\x00\u07d4a\xb1\xb8\xc0\x12\xcdLx\xf6\x98\xe4p\xf9\x02V\xe6\xa3\x0fH\u0749\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xb3\xdf.\x9e\x9f\xd9h\x13\x1f\x1e\x88\xf0\xa0\xeb[\xd7eFM\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\xb9\x02\u0166s\x88X&\x82\r\x1f\xe1EI\xe4\x86_\xbd\u0089\x12$\xef\xed*\u1440\x00\u07d4a\xb9\x05\xdef?\xc1s\x86R;:(\xe2\xf7\xd07\xa6U\u0349\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xba\x87\xc7~\x9bYm\xe7\xba\x0e2o\xdd\xfe\xec!c\xeff\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xbf\x84\u056b\x02oX\xc8s\xf8o\xf0\xdf\u0282\xb5W3\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xc4\xee|\x86LMk^7\xea\x131\xc2\x03s\x9e\x82k/\x89\x01\xa15;8*\x91\x80\x00\u07d4a\xc80\xf1eG\x18\xf0u\u032b\xa3\x16\xfa\xac\xb8[}\x12\v\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4a\xc8\xf1\xfaC\xbf\x84i\x99\xec\xf4{+2M\xfbkc\xfe:\x89+^:\xf1k\x18\x80\x00\x00\u07d4a\xc9\xdc\u8c98\x1c\xb4\x0e\x98\xb0@+\xc3\xeb(4\x8f\x03\xac\x89\n\xac\xac\u0679\xe2+\x00\x00\u07d4a\u03a7\x1f\xa4d\xd6*\a\x06?\x92\v\f\xc9\x17S\x973\u0609Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4a\xd1\x01\xa03\xee\x0e.\xbb1\x00\xed\xe7f\xdf\x1a\xd0$IT\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xedU\x96\u0197 \u007f=U\xb2\xa5\x1a\xa7\xd5\x0f\a\xfa\t\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xff\x8eg\xb3M\x9e\xe6\xf7\x8e\xb3o\xfe\xa1\xb9\xf7\xc1W\x87\xaf\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4b\x05\xc2\xd5dtp\x84\x8a8@\xf3\x88~\x9b\x01]4u\\\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4b(\xad\xe9^\x8b\xb1}\x1a\xe2;\xfb\x05\x18AMI~\x0e\xb8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94b)\xdc\xc2\x03\xb1\xed\xcc\xfd\xf0n\x87\x91\fE*\x1fMzr\x8a\x06\xe1\xd4\x1a\x8f\x9e\xc3P\x00\x00\u0794b+\xe4\xb4T\x95\xfc\xd91C\xef\xc4\x12\u0599\xd6\xcd\xc2=\u0148\xf0\x15\xf2W6B\x00\x00\u07d4b3\x1d\xf2\xa3\xcb\xee5 \xe9\x11\u07a9\xf7>\x90_\x89%\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4bVD\xc9Z\x87>\xf8\xc0l\u06de\x9fm\x8dv\x80\x04=b\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4be\xb2\xe7s\x0f6\xb7v\xb5-\f\x9d\x02\xad\xa5]\x8e<\xb6\x8965\u026d\xc5\u07a0\x00\x00\u07d4bh\n\x15\xf8\u0338\xbd\xc0/s`\xc2Z\xd8\u03f5{\x8c\u034965\u026d\xc5\u07a0\x00\x00\u07d4b\x94\xea\xe6\xe4 \xa3\xd5`\n9\xc4\x14\x1f\x83\x8f\xf8\xe7\xccH\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4b\x97\x1b\xf2cL\xee\v\xe3\u0249\x0fQ\xa5`\x99\u06f9Q\x9b\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4b\x9b\xe7\xab\x12jS\x98\xed\xd6\u069f\x18D~x\u0192\xa4\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4b\xb4\xa9\"nah\a\x1el\xbea\x11\xfe\xf0\xbcc\x8a\x03\xba\x19\x10\xbf4\x1b\x00\x00\x00\xe0\x94c\n\x91:\x901\xc9I*\xbdLA\u06f1PT\xcf\xecD\x16\x8a\x014X\xdbg\xaf5\xe0\x00\x00\xe0\x94c\fRs\x12mQ|\xe6q\x01\x81\x1c\xab\x16\xb8SL\xf9\xa8\x8a\x01\xfe\xcc\xc6%s\xbb\u04c0\x00\u07d4c\x100\xa5\xb2{\a(\x8aEio\x18\x9e\x11\x14\xf1*\x81\xc0\x89\x1b\x1azB\v\xa0\r\x00\x00\u07d4c\x10\xb0 \xfd\x98\x04IW\x99P\x92\t\x0f\x17\xf0NR\xcd\xfd\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4c+\x91I\xd7\x01x\xa7364'^\x82\u0555?'\x96{\x89%\xf2s\x93=\xb5p\x00\x00\u07d4c,\xec\xb1\f\xfc\xf3\x8e\u0246\xb4;\x87p\xad\xec\xe9 \x02!\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c1\x02\x8c\xbbZ!H[\xc5\x1bVQB\x99;\xdb%\x82\xa9\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4c3O\xcf\x17E\x84\x0eK\tJ;\xb4\v\xb7o\x96\x04\xc0L\x89\u05e5\xd7\x03\xa7\x17\xe8\x00\x00\u07d4c4\nWqk\xfac\xebl\xd13r\x12\x02W[\xf7\x96\xf0\x89\va\xe0\xa2\f\x12q\x80\x00\u07d4cN\xfc$7\x11\a\xb4\xcb\xf0?y\xa9=\xfd\x93\xe41\xd5\xfd\x89B5\x82\xe0\x8e\xdc\\\x80\x00\xe0\x94c\\\x00\xfd\xf05\xbc\xa1_\xa3a\r\xf38N\x0f\xb7\x90h\xb1\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4ca.xb\xc2{X|\xfbm\xaf\x99\x12\xcb\x05\x1f\x03\n\x9f\x89\x02[\x19\u053f\xe8\xed\x00\x00\u07d4cfgU\xbdA\xb5\x98i\x97x<\x13\x040\b$+<\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4c{\xe7\x1b:\xa8\x15\xffE=VB\xf70tE\vd\xc8*\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94c}g\xd8\u007fXo\nZG\x9e \xee\x13\xea1\n\x10\xb6G\x8a\n:Y&\xaf\xa1\xe70\x00\x00\u07d4c\u007fXi\xd6\xe4i_\x0e\xb9\xe2s\x11\u0107\x8a\xff33\x80\x89j\xc0Nh\xaa\xec\x86\x00\x00\u07d4c\x97|\xad}\r\xcd\xc5+\x9a\xc9\xf2\xff\xa16\xe8d(\x82\xb8\x89\x04\x10\u0546\xa2\nL\x00\x00\u07d4c\xa6\x1d\xc3\n\x8e;0\xa7c\xc4!<\x80\x1c\xbf\x98s\x81x\x8965\u026d\xc5\u07a0\x00\x00\u07d4c\xacT\\\x99\x12C\xfa\x18\xae\xc4\x1dOoY\x8eUP\x15\u0709 \x86\xac5\x10R`\x00\x00\u07d4c\xb9uMu\xd1-8@9\xeci\x06<\v\xe2\x10\xd5\xe0\u3252\v\x86\f\xc8\xec\xfd\x80\x00\u07d4c\xbbfO\x91\x17\x03v(YM\xa7\xe3\xc5\b\x9f\xd6\x18\xb5\xb5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c\u00a3\xd25\xe5\xee\xab\xd0\u0526\xaf\u06c9\xd9F'9d\x95\x89CN\xf0[\x9d\x84\x82\x00\x00\u07d4c\xc8\xdf\xde\v\x8e\x01\xda\xdc.t\x8c\x82L\xc06\x9d\U00010cc9\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4c\xd5Z\u065b\x917\xfd\x1b \xcc+O\x03\xd4,\xba\xdd\xf34\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4c\xd8\x00H\x87u\x96\xe0\u0084\x89\xe6P\xcdJ\xc1\x80\tjI\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94c\xe4\x14`>\x80\xd4\xe5\xa0\xf5\xc1\x87t FB%\x82\b\xe4\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94c\xe8\x8e.S\x9f\xfbE\x03\x86\xb4\xe4g\x89\xb2#\xf5GlE\x8a\x01U\x17\nw\x8e%\xd0\x00\x00\u07d4c\xef/\xbc=\xaf^\xda\xf4\xa2\x95b\x9c\xcf1\xbc\xdf@8\xe5\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4c\xf0\xe5\xa7R\xf7\x9fg\x12N\xedc:\xd3\xfd'\x05\xa3\x97\u0509\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94c\xf5\xb5=y\xbf.A\x14\x89Re0\"8E\xfa\xc6\xf6\x01\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4c\xfc\x93\x00\x13\x05\xad\xfb\u0278])\xd9)\x1a\x05\xf8\xf1A\v\x8965\u026d\xc5\u07a0\x00\x00\u0794c\xfek\xccK\x8a\x98P\xab\xbeu\x8070\xc92%\x1f\x14[\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4d\x03\xd0bT\x96\x90\xc8\xe8\xb6>\xaeA\xd6\xc1\tGn%\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4d\x04+\xa6\x8b\x12\xd4\xc1Qe\x1c\xa2\x81;sR\xbdV\xf0\x8e\x89 \x86\xac5\x10R`\x00\x00\u0794d\x05\xdd\x13\xe9:\xbc\xff7~p\x0e<\x1a\x00\x86\xec\xa2})\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94d\n\xbam\xe9\x84\xd9E\x177x\x03p^\xae\xa7\t_J\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4d\v\xf8t\x15\xe0\xcf@s\x01\xe5Y\x9ah6m\xa0\x9b\xba\u0209\x1a\xbc\x9fA`\x98\x15\x80\x00\u07d4d \xf8\xbc\xc8\x16JaR\xa9\x9dk\x99i0\x05\xcc\xf7\xe0S\x8965f3\xeb\xd8\xea\x00\x00\u07d4d$\x1axD)\x0e\n\xb8U\xf1\u052au\xb5SE\x03\"$\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4d&J\xed\xd5-\xca\xe9\x18\xa0\x12\xfb\xcd\f\x03\x0e\xe6\xf7\x18!\x8965\u026d\xc5\u07a0\x00\x00\u07d4d7\x0e\x87 &E\x12Z5\xb2\a\xaf\x121\xfb`r\xf9\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4d=\x9a\xee\u0531\x80\x94~\u04b9 |\xceL=\xdcU\xe1\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4dC\xb8\xaec\x9d\xe9\x1c\xf7\xf0p\xa5G\x03\xb7\x18NH'l\\\x00w\xefK4\x89\x11X\xe4`\x91=\x00\x00\x00\xe0\x94d\xe2\xde! \v\x18\x99\u00e0\xc0e;P@\x13m\r\xc8B\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4d\xec\x8a[t?4y\xe7\a\xda\xe9\xee \u076aO@\xf1\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e\x03\x86\v\x19\x10\b\xc1U\x83\xbf\u0201X\t\x93\x01v((\x8965\u026d\xc5\u07a0\x00\x00\u07d4e\x051\x911\x9e\x06z%\xe66\x1dG\xf3\u007fc\x18\xf84\x19\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4e\t;#\x9b\xbf\xba#\xc7w\\\xa7\xdaZ\x86H\xa9\xf5L\xf7\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4e\t\xee\xb14~\x84/\xfbA>7\x15^,\xbcs\x82s\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94e\vBUU\xe4\xe4\xc5\x17\x18\x14h6\xa2\xc1\xeew\xa5\xb4!\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4e\f\xf6}\xb0`\xcc\xe1uh\xd5\xf2\xa4#h|Idv\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4e\x10\xdfB\xa5\x99\xbc\xb0\xa5\x19\u0329a\xb4\x88u\x9aogw\x89lk\x93[\x8b\xbd@\x00\x00\u07d4e6u\xb8B\xd7\u0634a\xf7\"\xb4\x11|\xb8\x1d\xac\x8ec\x9d\x89\x01\xae6\x1f\xc1E\x1c\x00\x00\u07d4eK~\x80\x87\x99\xa8=r\x87\xc6w\x06\xf2\xab\xf4\x9aId\x04\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94eORHG\xb3\xa6\xac\xc0\xd3\xd5\xf1\xf3b\xb6\x03\xed\xf6_\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4eY4\u068etN\xaa=\xe3M\xbb\xc0\x89LN\xda\va\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e]\\\xd7H\x96)\xe2ANIb?\xabb\xa1~M6\x11\x89\x05\fL\xb2\xa1\f`\x00\x00\u07d4e\xaf\x8d\x8b[\x1d\x1e\xed\xfaw\xbc\xbc\x96\xc1\xb13\xf83\x06\u07c9\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4e\xaf\x90\x87\xe0QgqT\x97\u0265\xa7I\x18\x94\x89\x00M\xef\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u0794e\xb4/\xae\xcc\x1e\u07f1B\x83\u0297\x9a\xf5E\xf6;0\xe6\f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u0794e\xd3>\xb3\x9c\xdadS\xb1\x9ea\xc1\xfeM\xb91p\xef\x9d4\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4e\xd8\xddN%\x1c\xbc\x02\x1f\x05\xb0\x10\xf2\xd5\xdcR\f8r\xe0\x89-CW\x9a6\xa9\x0e\x00\x00\u07d4e\xea&\xea\xbb\xe2\xf6L\xcc\xcf\xe0h)\xc2]F7R\x02%\x89%\xf2s\x93=\xb5p\x00\x00\u07d4e\xeag\xad?\xb5j\xd5\xfb\x948}\u04ce\xb3\x83\x00\x1d|h\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94e\xeb\xae\xd2~\u06dd\xcc\x19W\xae\xe5\xf4R\xac!\x05\xa6\\\x0e\x8a\t7\u07ed\xae%\u26c0\x00\u07d4e\xee \xb0m\x9a\u0549\xa7\xe7\xce\x04\xb9\xf5\xf7\x95\xf4\x02\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4e\xf544m/\xfbx\u007f\xa9\xcf\x18]t[\xa4)\x86\xbdn\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94e\xf5\x87\x0f&\xbc\xe0\x89g}\xfc#\xb5\x00\x1e\xe4\x92H4(\x8a\x01\x12\xb1\xf1U\xaa2\xa3\x00\x00\u07d4e\xfd\x02\xd7\x04\xa1*M\xac\xe9G\x1b\x06E\xf9b\xa8\x96q\u0209\x01\x8d\x1c\xe6\xe4'\u0340\x00\u07d4e\xff\x87O\xaf\xceM\xa3\x18\xd6\xc9=W\xe2\u00ca\rs\xe8 \x8968\x02\x1c\xec\u06b0\x00\x00\xe0\x94f\x05W\xbbC\xf4\xbe:\x1b\x8b\x85\xe7\xdf{<[\xcdT\x80W\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4f\b,u\xa8\xde1\xa59\x13\xbb\xd4M\xe3\xa07O\u007f\xaaA\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4f\x11\xceY\xa9\x8b\a*\xe9Y\xdcI\xadQ\x1d\xaa\xaa\xa1\x9dk\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4f \x1b\xd2'\xaem\u01bd\xfe\xd5\xfb\u0781\x1f\xec\xfe^\x9d\u0649 >\x9e\x84\x92x\x8c\x00\x00\u07d4f#4\x81G$\x93[y1\xdd\xcaa\x00\xe0\rFw'\u0349\"\x88&\x9d\a\x83\xd4\x00\x00\u07d4f'O\xea\x82\xcd0\xb6\u009b#5\x0eOO=1\nX\x99\x89p7\x05P\xab\x82\x98\x00\x00\u07d4f,\xfa\x03\x8f\xab7\xa0\x17E\xa3d\u1e41'\xc5\x03tm\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4f5\xb4oq\x1d-\xa6\xf0\xe1cp\u034e\xe4>\xfb,-R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4f6\x04\xb0P0F\xe6$\xcd&\xa8\xb6\xfbGB\xdc\xe0*o\x89\x03\x8b\x9by~\xf6\x8c\x00\x00\u07d4f6\u05ecczH\xf6\x1d8\xb1L\xfdHe\xd3m\x14(\x05\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f@\xcc\xf0SU\\\x13\n\xe2\xb6Vd~\xa6\xe3\x167\xb9\xab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4fBK\xd8x[\x8c\xb4a\x10*\x90\x02\x83\xc3]\xfa\a\xefj\x89\x02.-\xb2ff\xfc\x80\x00\u07d4fL\xd6}\xcc\u026c\x82(\xb4\\U\u06cdvU\ve\x9c\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4fNC\x11\x98p\xaf\x10zD\x8d\xb1'\x8b\x04H8\xff\u036f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4fQso\xb5\x9b\x91\xfe\xe9\xc9:\xa0\xbdn\xa2\xf7\xb2Pa\x80\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f[\x00\x0f\vw'P\xcc\x89k\x91\x8a\xacIK\x16\x80\x00\xe0\x94g]\\\xaa`\x9b\xf7\n\x18\xac\xa5\x80F]\x8f\xb71\r\x1b\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4gc F\u0732ZT\x93i(\xa9oB?3 \xcb\ud489lk\x93[\x8b\xbd@\x00\x00\u07d4ge\xdf%(\x0e\x8eO8\u0531\xcfDo\xc5\xd7\xebe\x9e4\x89\x05k\xc7^-c\x10\x00\x00\u07d4gv\xe13\xd9\xdc5L\x12\xa9Q\b{c\x96P\xf59\xa43\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4g\x85Q<\xf72\xe4~\x87g\ap\xb5A\x9b\xe1\f\xd1\xfct\x89lk\x93[\x8b\xbd@\x00\x00\u07d4g\x947\xea\xcfCxx\xdc)=H\xa3\x9c\x87\xb7B\x1a!l\x89\x03\u007f\x81\x82\x1d\xb2h\x00\x00\u07d4g\x9b\x9a\x10\x990Q~\x89\x99\t\x9c\xcf*\x91LL\x8d\xd94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4g\xa8\x0e\x01\x90r\x1f\x949\rh\x02r\x9d\xd1,1\xa8\x95\xad\x89lk\x13u\xbc\x91V\x00\x00\u07d4g\xb8\xa6\xe9\x0f\xdf\n\x1c\xacD\x17\x930\x1e\x87P\xa9\xfayW\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4g\xbc\x85\xe8}\xc3LN\x80\xaa\xfa\x06k\xa8\u049d\xbb\x8eC\x8e\x89\x15\xd1\xcfAv\xae\xba\x00\x00\u07d4g\xc9&\t>\x9b\x89'\x938\x10\u0642\"\xd6.+\x82\x06\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4g\xcf\xdanp\xbfvW\u04d0Y\xb5\x97\x90\xe5\x14Z\xfd\xbea\x89#\x05\r\tXfX\x00\x00\u07d4g\u0582\xa2\x82\xefs\xfb\x8dn\x90q\xe2aOG\xab\x1d\x0f^\x8965\u026d\xc5\u07a0\x00\x00\u07d4g\u05a8\xaa\x1b\xf8\xd6\xea\xf78N\x99=\xfd\xf1\x0f\n\xf6\x8aa\x89\n\xbc\xbbW\x18\x97K\x80\x00\u07d4g\u0692.\xff\xa4r\xa6\xb1$\xe8N\xa8\xf8k$\xe0\xf5\x15\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4g\xdf$-$\r\u0538\a\x1dr\xf8\xfc\xf3[\xb3\x80\x9dq\xe8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4g\xee@n\xa4\xa7\xaej:8\x1e\xb4\xed\xd2\xf0\x9f\x17KI(\x898)c_\th\xb0\x00\x00\u07d4g\xf2\xbbx\xb8\xd3\xe1\x1f|E\x8a\x10\xb5\xc8\xe0\xa1\xd3tF}\x89a\t=|,m8\x00\x00\u07d4g\xfcR}\xce\x17\x85\xf0\xfb\x8b\xc7\xe5\x18\xb1\xc6i\xf7\xec\u07f5\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4h\x02}\x19U\x8e\xd73\x9a\b\xae\xe8\xde5Y\xbe\x06>\xc2\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\x06@\x83\x8b\xd0zD{\x16\x8dm\x92;\x90\xcflC\xcd\u0289]\u0212\xaa\x111\xc8\x00\x00\u07d4h\a\xdd\u020d\xb4\x89\xb03\xe6\xb2\xf9\xa8\x15SW\x1a\xb3\xc8\x05\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94h\rY\x11\xed\x8d\xd9\xee\xc4\\\x06\f\"?\x89\xa7\xf6 \xbb\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4h\x11\xb5L\u0456c\xb1\x1b\x94\xda\x1d\xe2D\x82\x85\u035fh\u0649;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4h\x19\f\xa8\x85\xdaB1\x87L\x1c\xfbB\xb1X\n!s\u007f8\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94h(\x97\xbcO\x8e\x89\x02\x91 \xfc\xff\xb7\x87\xc0\x1a\x93\xe6A\x84\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h)^\x8e\xa5\xaf\xd9\t?\xc0\xa4e\xd1W\x92+]*\xe24\x89\x01\x15NS!}\xdb\x00\x00\u07d4h.\x96'oQ\x8d1\xd7\xe5n0\u07f0\t\xc1!\x82\x01\xbd\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4h5\xc8\xe8\xb7J,\xa2\xae?J\x8d\x0fk\x95J>*\x83\x92\x89\x03B\x9c3]W\xfe\x00\x00\u07d4h63\x01\n\x88hk\xeaZ\x98\xeaS\xe8y\x97\xcb\xf7>i\x89\x05k9Bc\xa4\f\x00\x00\u07d4h=\xba6\xf7\xe9O@\xeaj\xea\ry\xb8\xf5!\xdeU\an\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4hA\x9cm\xd2\xd3\xceo\u02f3\xc7>/\xa0y\xf0`Q\xbd\xe6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4hG;z}\x96Y\x04\xbe\u06e5V\u07fc\x17\x13l\xd5\xd44\x89\x05k\xc7^-c\x10\x00\x00\u07d4hG\x82[\xde\xe8$\x0e(\x04,\x83\xca\xd6B\U000868fd\u0709QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94hJD\xc0i3\x9d\b\xe1\x9auf\x8b\u06e3\x03\xbe\x85S2\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4hS\x1fM\u0680\x8fS vz\x03\x114(\xca\f\xe2\xf3\x89\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4hy'\xe3\x04\x8b\xb5\x16*\xe7\xc1\\\xf7k\xd1$\xf9I{\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94h\x80\x9a\xf5\xd52\xa1\x1c\x1aMn2\xaa\xc7\\LR\xb0\x8e\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h\x86\xad\xa7\xbb\xb0a{\u0684!\x91\u018c\x92.\xa3\xa8\xac\x82\x89>\xe2;\xde\x0e} \x00\x00\xe0\x94h\x88>\x15.V`\xfe\xe5\x96&\xe7\xe3\xb4\xf0Q\x10\xe6\"/\x8a\v\x94c;\xe9u\xa6*\x00\x00\u07d4h\x8aV\x9e\x96U$\xeb\x1d\n\xc3\xd3s>\xab\x90\x9f\xb3\xd6\x1e\x89G\x8e\xae\x0eW\x1b\xa0\x00\x00\xe0\x94h\x8e\xb3\x85;\xbc\xc5\x0e\xcf\xee\x0f\xa8\u007f\n\xb6\x93\u02bd\xef\x02\x8a\x06\xb1\n\x18@\x06G\xc0\x00\x00\u07d4h\xa7B_\xe0\x9e\xb2\x8c\xf8n\xb1y>A\xb2\x11\xe5{\u058d\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4h\xa8l@#\x88\xfd\xdcY\x02\x8f\xecp!\u933f\x83\x0e\xac\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94h\xac\u06a9\xfb\x17\xd3\xc3\t\x91\x1aw\xb0_S\x91\xfa\x03N\xe9\x8a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4h\xad\xdf\x01\x9dk\x9c\xabp\xac\xb1?\v1\x17\x99\x9f\x06.\x12\x89\x02\xb5\x12\x12\xe6\xb7\u0200\x00\u07d4h\xb3\x186\xa3\n\x01j\xda\x15{c\x8a\xc1]\xa7?\x18\xcf\u0789\x01h\u048e?\x00(\x00\x00\xe0\x94h\xb6\x85G\x88\xa7\xc6Il\xdb\xf5\xf8K\x9e\xc5\xef9+x\xbb\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4h\xc0\x84\x90\u021b\xf0\u05b6\xf3 \xb1\xac\xa9\\\x83\x12\xc0\x06\b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4h\xc7\xd1q\x1b\x01\x1a3\xf1o\x1fU\xb5\xc9\x02\xcc\xe9p\xbd\u05c9\b=lz\xabc`\x00\x00\u07d4h\xc8y\x1d\xc3B\xc3sv\x9e\xa6\x1f\xb7\xb5\x10\xf2Q\xd3 \x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\u07d4|I[\ubbb8\u8273\xf9S\xd53\x87K\xf1\x06\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4h\xe8\x02'@\xf4\xaf)\xebH\xdb2\xbc\xec\xdd\xfd\x14\x8d=\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\xecy\u057eqUql@\x94\x1cy\u05cd\x17\u079e\xf8\x03\x89\x1b#8w\xb5 \x8c\x00\x00\u07d4h\xee\xc1\u222c1\xb6\xea\xba~\x1f\xbdO\x04\xadW\x9ak]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\xf5%\x92\x1d\xc1\x1c2\x9buO\xbf>R\x9f\xc7#\xc84\u0349WG=\x05\u06ba\xe8\x00\x00\u07d4h\xf7\x19\xae4+\xd7\xfe\xf1\x8a\x05\u02f0/pZ\u04ce\u0572\x898\xeb\xad\\\u0710(\x00\x00\xe0\x94h\xf7W<\xd4W\xe1L\x03\xfe\xa4>0-04|\x10p\\\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4h\xf8\xf4QU\xe9\x8cP)\xa4\xeb\u0175'\xa9.\x9f\xa81 \x89\xf0{D\xb4\a\x93 \x80\x00\u07d4h\xfe\x13W!\x8d\tXI\xcdW\x98B\u012a\x02\xff\x88\x8d\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x02(\xe4\xbb\x12\xa8\u0535\u09d7\xb0\xc5\xcf*u\t\x13\x1e\x89e\xea=\xb7UF`\x00\x00\u07d4i\x05\x94\xd3\x06a<\xd3\xe2\xfd$\xbc\xa9\x99J\u064a=s\xf8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94i\a2ir\x9ed\x14\xb2n\xc8\xdc\x0f\xd95\xc7;W\x9f\x1e\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94i\x19\xdd^]\xfb\x1a\xfa@G\x03\xb9\xfa\xea\x8c\xee5\xd0\rp\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4i4\x92\xa5\xc5\x13\x96\xa4\x82\x88\x16i\xcc\xf6\xd8\xd7y\xf0\tQ\x89\x12\xbfPP:\xe3\x03\x80\x00\u07d4i=\x83\xbe\tE\x9e\xf89\v.0\xd7\xf7\u008d\xe4\xb4(N\x89lk\x93[\x8b\xbd@\x00\x00\u07d4iQp\x83\xe3\x03\xd4\xfb\xb6\xc2\x11E\x14!]i\xbcF\xa2\x99\x89\x05k\xc7^-c\x10\x00\x00\u07d4iUPel\xbf\x90\xb7]\x92\xad\x91\"\xd9\r#\xcah\xcaM\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94iX\xf8;\xb2\xfd\xfb'\xce\x04\t\xcd\x03\xf9\xc5\xed\xbfL\xbe\u074a\x04<3\xc1\x93ud\x80\x00\x00\u0794i[\x0fRBu7\x01\xb2d\xa6pq\xa2\u0708\b6\xb8\u06c8\u3601\x1b\xech\x00\x00\xe0\x94i[L\xce\bXV\xd9\xe1\xf9\xff>y\x94 #5\x9e_\xbc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94if\x06:\xa5\xde\x1d\xb5\xc6q\xf3\xddi\x9dZ\xbe!>\xe9\x02\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4it\u0224\x14\u03ae\xfd<.M\xfd\xbe\xf40V\x8d\x9a\x96\v\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\xe0\x94iximQP\xa9\xa2cQ?\x8ft\u0196\xf8\xb19|\xab\x8a\x01g\xf4\x82\xd3\u0171\xc0\x00\x00\xe0\x94iy{\xfb\x12\u027e\u0582\xb9\x1f\xbcY5\x91\xd5\xe4\x027(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94i\u007fUSk\xf8Z\xdaQ\x84\x1f\x02\x87b:\x9f\x0e\u041a\x17\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4i\x82\xfe\x8a\x86~\x93\xebJ\v\xd0QX\x93\x99\xf2\xec\x9aR\x92\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x8a\x8ao\x01\xf9\xabh/c|yi\xbe\x88_lS\x02\xbf\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4i\x8a\xb9\xa2\xf33\x81\xe0|\fGC=\r!\xd6\xf36\xb1'\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4i\x94\xfb21\xd7\xe4\x1dI\x1a\x9dh\xd1\xfaL\xae,\xc1Y`\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\x9c\x9e\xe4q\x95Q\x1f5\xf8b\xcaL\"\xfd5\xae\x8f\xfb\xf4\x89\x04V9\x18$O@\x00\x00\u07d4i\x9f\xc6\u058aGuW<\x1d\u036e\xc80\xfe\xfdP9|N\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4i\xaf(\xb0tl\xac\r\xa1p\x84\xb99\x8c^6\xbb:\r\xf2\x896w\x03n\xdf\n\xf6\x00\x00\u07d4i\xb8\x0e\xd9\x0f\x84\x83J\xfa?\xf8.\xb9dp;V\tw\u0589\x01s\x17\x90SM\xf2\x00\x00\xe0\x94i\xb8\x1dY\x81\x14\x1e\u01e7\x14\x10`\xdf\u03cf5\x99\xff\xc6>\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4i\xbc\xfc\x1dC\xb4\xba\x19\xde{'K\xdf\xfb5\x13\x94\x12\xd3\u05c95e\x9e\xf9?\x0f\xc4\x00\x00\u07d4i\xbd%\xad\xe1\xa34lY\xc4\xe90\xdb*\x9dq^\xf0\xa2z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\xc0\x8dtGT\xdep\x9c\xe9n\x15\xae\r\x1d9[:\"c\x8965\u026d\xc5\u07a0\x00\x00\u07d4i\xc2\xd85\xf1>\xe9\x05\x80@\x8ej2\x83\xc8\u0326\xa44\xa2\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4i\xc9N\a\u0129\xbe3\x84\xd9]\xfa<\xb9)\x00Q\x87;{\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4i\xcb>!S\x99\x8d\x86\xe5\xee \xc1\xfc\u0466\xba\uec86?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\u04ddQ\b\x89\xe5R\xa3\x96\x13[\xfc\xdb\x06\xe3~8v3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94i\u064f8\xa3\xba=\xbc\x01\xfa\\,\x14'\xd8b\x83//p\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94i\xe2\xe2\xe7\x040|\xcc[\\\xa3\xf1d\xfe\xce.\xa7\xb2\xe5\x12\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4i\xffB\x90t\u02dblc\xbc\x91B\x84\xbc\xe5\xf0\xc8\xfb\xf7\u0409\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4i\xff\x89\x01\xb5Av?\x81|_)\x98\xf0-\xcf\xc1\xdf)\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4j\x02:\xf5}XM\x84^i\x876\xf10\u06dd\xb4\r\xfa\x9a\x89\x05[ \x1c\x89\x00\x98\x00\x00\u07d4j\x04\xf5\xd5?\xc0\xf5\x15\xbe\x94+\x8f\x12\xa9\xcbz\xb0\xf3\x97x\x89\xa9\xaa\xb3E\x9b\xe1\x94\x00\x00\u07d4j\x05\xb2\x1cO\x17\xf9\xd7?_\xb2\xb0\u02c9\xffSV\xa6\xcc~\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94j\x0f\x05`f\xc2\xd5f(\x85\x02s\xd7\xec\xb7\xf8\xe6\xe9\x12\x9e\x8a\x01\x0f\r)<\u01e5\x88\x00\x00\u07d4j\x13\xd5\xe3,\x1f\xd2m~\x91\xffn\x051`\xa8\x9b,\x8a\xad\x89\x02\xe6/ \xa6\x9b\xe4\x00\x00\u07d4j.\x86F\x9a[\xf3|\xee\x82\xe8\x8bL8c\x89](\xfc\xaf\x89\x1c\"\x92f8[\xbc\x00\x00\u07d4j6\x94BL|\u01b8\xbc\u067c\u02baT\f\xc1\xf5\xdf\x18\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94jB\u0297\x1cex\u056d\xe2\x95\xc3\xe7\xf4\xad3\x1d\xd3BN\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4jD\xaf\x96\xb3\xf02\xaed\x1b\xebg\xf4\xb6\xc83B\xd3|]\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4jL\x89\a\xb6\x00$\x80W\xb1\xe4cT\xb1\x9b\u0705\x9c\x99\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jQNbB\xf6\xb6\x8c\x13~\x97\xfe\xa1\u73b5U\xa7\xe5\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jS\xd4\x1a\xe4\xa7R\xb2\x1a\xbe\xd57FI\x95:Q=\xe5\xe5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4jaY\aJ\xb5s\xe0\xeeX\x1f\x0f=\xf2\u05a5\x94b\x9bt\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4jc7\x83?\x8fjk\xf1\f\xa7\xec!\xaa\x81\x0e\xd4D\xf4\u02c97\xbd$4\\\xe8\xa4\x00\x00\u07d4jcS\xb9qX\x9f\x18\xf2\x95\\\xba(\xab\xe8\xac\xcejWa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4jc\xfc\x89\xab\xc7\xf3n(-\x80x{{\x04\xaf\xd6U>q\x89\b\xacr0H\x9e\x80\x00\x00\u07d4jg\x9e7\x8f\xdc\xe6\xbf\xd9\u007f\xe6/\x04)Z$\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4j\x8c\xea-\xe8J\x8d\xf9\x97\xfd?\x84\xe3\b=\x93\xdeW\u0369\x89\x05k\xe0<\xa3\xe4}\x80\x00\xe0\x94j\x97Xt;`>\xea:\xa0RKB\x88\x97#\xc4\x159H\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4j\xa5s/;\x86\xfb\x8c\x81\xef\xbek[G\xb5cs\v\x06\u020965\u026d\xc5\u07a0\x00\x00\u07d4j\xb3#\xaePV\xed\nE0r\u016b\xe2\xe4/\xcf]q9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4j\xb5\xb4\xc4\x1c\u0778)i\f/\xda\u007f \xc8^b\x9d\xd5\u0549d\u052fqL2\x90\x00\x00\u07d4j\xc4\x0fS-\xfe\xe5\x11\x81\x17\u04ad5-\xa7}Om\xa2\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xc4\u053e-\xb0\u065d\xa3\xfa\xaa\xf7RZ\xf2\x82\x05\x1dj\x90\x89\x04X\xcaX\xa9b\xb2\x80\x00\u07d4j\xcd\u0723\xcd+I\x90\xe2\\\xd6\\$\x14\x9d\t\x12\t\x9ey\x89\xa2\xa1\xe0|\x9fl\x90\x80\x00\u07d4j\xd9\v\xe2R\xd9\xcdFM\x99\x81%\xfa\xb6\x93\x06\v\xa8\xe4)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4j\u0753!\x93\xcd8IJ\xa3\xf0:\xec\xccKz\xb7\xfa\xbc\xa2\x89\x04\xdbs%Gc\x00\x00\x00\xe0\x94j\xe5\u007f'\x91|V*\x13*M\x1b\xf7\xec\n\u01c5\x83)&\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4j\xeb\x9ftt.\xa4\x91\x81=\xbb\xf0\xd6\xfc\xde\x1a\x13\x1dM\xb3\x89\x17\xe5T0\x8a\xa00\x00\x00\u07d4j\xf25\u04bb\xe0P\xe6)\x16\x15\xb7\x1c\xa5\x82\x96X\x81\x01B\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf6\xc7\xee\x99\xdf'\x1b\xa1[\xf3\x84\xc0\xb7d\xad\xcbM\xa1\x82\x8965f3\xeb\xd8\xea\x00\x00\u07d4j\xf8\xe5Yih,q_H\xadO\xc0\xfb\xb6~\xb5\x97\x95\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4j\xf9@\xf6>\u0278\xd8v'*\u0296\xfe\xf6\\\xda\xce\xcd\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf9\xf0\xdf\uebbb_d\xbf\x91\xabw\x16i\xbf\x05)US\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xff\x14f\xc2b6u\xe3\xcb\x0eu\xe4#\xd3z%\xe4B\xeb\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94k\r\xa2Z\xf2g\u05c3l\"k\xca\xe8\xd8r\xd2\xceR\xc9A\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4k\x10\xf8\xf8\xb3\xe3\xb6\r\xe9\n\xa1-\x15_\x9f\xf5\xff\xb2,P\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x17Y\x8a\x8e\xf5Oyz\xe5\x15\u0336Q}\x18Y\xbf\x80\x11\x89\x05k\xc7^-c\x10\x00\x00\u07d4k \xc0\x80`jy\xc7;\xd8\xe7[\x11qzN\x8d\xb3\xf1\u00c9\x10?sX\x03\xf0\x14\x00\x00\u07d4k\"\x84D\x02!\xce\x16\xa88-\xe5\xff\x02)G\"i\xde\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4k0\xf1\x829\x10\xb8m:\xcbZj\xfc\x9d\xef\xb6\xf3\xa3\v\xf8\x89\u3bb5sr@\xa0\x00\x00\u07d4k8\u0784\x1f\xad\u007fS\xfe\x02\xda\x11[\xd8j\xaff$f\xbd\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4kK\x99\xcb?\xa9\xf7\xb7L\u3903\x17\xb1\xcd\x13\t\n\x1az\x89\x03\x1b2~i]\xe2\x00\x00\u07d4kZ\xe7\xbfx\xecu\xe9\f\xb5\x03\xc7x\xcc\u04f2KO\x1a\xaf\x89+^:\xf1k\x18\x80\x00\x00\u07d4kc\xa2\u07f2\xbc\xd0\xca\xec\x00\"\xb8\x8b\xe3\f\x14Q\xeaV\xaa\x89+\xdbk\xf9\x1f\u007fL\x80\x00\u07d4kew\xf3\x90\x9aMm\xe0\xf4\x11R-Ep8d\x004\\\x89e\xea=\xb7UF`\x00\x00\u07d4kr\xa8\xf0a\xcf\xe6\x99j\xd4G\xd3\xc7,(\xc0\xc0\x8a\xb3\xa7\x89\xe7\x8cj\u01d9\x12b\x00\x00\u07d4kv\rHw\xe6\xa6'\xc1\xc9g\xbe\xe4Q\xa8P}\xdd\u06eb\x891T\xc9r\x9d\x05x\x00\x00\u07d4k\x83\xba\xe7\xb5e$EXU[\xcfK\xa8\xda \x11\x89\x1c\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x92]\xd5\xd8\xeda2\xabm\b`\xb8,D\xe1\xa5\x1f\x1f\xee\x89P; >\x9f\xba \x00\x00\xe0\x94k\x94a]\xb7Pej\u00cc~\x1c\xf2\x9a\x9d\x13g\u007fN\x15\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4k\x95\x1aC'N\xea\xfc\x8a\t\x03\xb0\xaf.\xc9+\xf1\xef\xc89\x89\x05k\xc7^-c\x10\x00\x00\u07d4k\x99%!\xec\x85#p\x84\x8a\u0597\xcc-\xf6Nc\xcc\x06\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xa8\xf7\xe2_\xc2\xd8qa\x8e$\xe4\x01\x84\x19\x917\xf9\xf6\xaa\x89\x15\xafd\x86\x9ak\xc2\x00\x00\u07d4k\xa9\xb2\x1b5\x10k\xe1Y\xd1\xc1\xc2ez\xc5l\u049f\xfdD\x89\xf2\xdc}G\xf1V\x00\x00\x00\u07d4k\xafz*\x02\xaex\x80\x1e\x89\x04\xadz\xc0Q\b\xfcV\xcf\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94k\xb2\xac\xa2?\xa1bm\x18\xef\xd6w\u007f\xb9}\xb0-\x8e\n\xe4\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4k\xb4\xa6a\xa3:q\xd4$\u051b\xb5\xdf(b.\xd4\xdf\xfc\xf4\x89\",\x8e\xb3\xfff@\x00\x00\u07d4k\xb5\b\x13\x14j\x9a\xddB\xee\"\x03\x8c\x9f\x1fti\xd4\u007fG\x89\n\xdaUGK\x814\x00\x00\u07d4k\xbc?5\x8af\x8d\u0461\x1f\x03\x80\xf3\xf71\bBj\xbdJ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4k\xbd\x1eq\x93\x90\xe6\xb9\x10C\xf8\xb6\xb9\u07c9\x8e\xa8\x00\x1b4\x89llO\xa6\xc3\xdaX\x80\x00\u07d4k\xc8Z\xcdY(r.\xf5\tS1\xee\x88\xf4\x84\xb8\u03c3W\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4k\xd3\xe5\x9f#\x9f\xaf\xe4wk\xb9\xbd\xddk\ue0fa]\x9d\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xd4W\xad\xe0Qy]\xf3\xf2F\\89\xae\xd3\xc5\xde\xe9x\x8964\xbf9\xab\x98x\x80\x00\u07d4k\xe1c\x13d>\xbc\x91\xff\x9b\xb1\xa2\xe1\x16\xb8T\xea\x93:E\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4k\xe7Y^\xa0\xf0hH\x9a'\x01\xecFI\x15\x8d\xdcC\xe1x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\xe9\x03\x0e\xe6\xe2\xfb\u0111\xac\xa3\xde@\"\xd3\x01w+{}\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94k\xec1\x1a\xd0P\b\xb4\xaf5<\x95\x8c@\xbd\x06s\x9a?\xf3\x8a\x03w\xf6*\x0f\nbp\x00\x00\u07d4k\xf7\xb3\xc0e\xf2\xc1\xe7\xc6\xeb\t+\xa0\xd1Pf\xf3\x93\u0478\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4k\xf8o\x1e/+\x802\xa9\\Mw8\xa1\t\xd3\xd0\xed\x81\x04\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4l\x05\xe3N^\xf2\xf4.\u041d\xef\xf1\x02l\xd6k\xcbi`\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4l\b\xa6\xdc\x01s\xc74)U\xd1\xd3\xf2\xc0e\xd6/\x83\xae\u01c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\n\xe9\xf0C\xc84\xd4Bq\xf14\x06Y=\xfe\tO8\x9f\x89RD*\xe13\xb6*\x80\x00\u07d4l\f\xc9\x17\xcb\xee}|\t\x97c\xf1Nd\xdf}4\xe2\xbf\t\x89\r\x8drkqw\xa8\x00\x00\xe0\x94l\x0eq/@\\Yr_\xe8)\xe9wK\xf4\xdf\u007fM\xd9e\x8a\f(h\x88\x9c\xa6\x8aD\x00\x00\xe0\x94l\x10\x12\x05\xb3#\xd7uD\xd6\xdcR\xaf7\xac\xa3\xce\xc6\xf7\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4l\x15\xec5 \xbf\x8e\xbb\xc8 \xbd\x0f\xf1\x97x7T\x94\u03dd\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94l\x1d\xdd3\xc8\x19f\u0706!w`q\xa4\x12\x94\x82\xf2\xc6_\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4l%2\u007f\x8d\u02f2\xf4^V\x1e\x86\xe3]\x88P\xe5:\xb0Y\x89;\xcd\xf9\xba\xfe\xf2\xf0\x00\x00\u07d4l.\x9b\xe6\u052bE\x0f\xd1%1\xf3?\x02\x8caFt\xf1\x97\x89\xc2\x12z\xf8X\xdap\x00\x00\u07d4l5\x9eX\xa1=Ex\xa93\x8e3\\g\xe7c\x9f_\xb4\u05c9\v\xd1[\x94\xfc\x8b(\x00\x00\u07d4l=\x18pA&\xaa\x99\xee3B\xce`\xf5\xd4\xc8_\x18g\u0349\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4lGK\xc6jTx\x00f\xaaOQ.\xef\xa7s\xab\xf9\x19\u01c9\x05\x18\x83\x15\xf7v\xb8\x00\x00\u07d4lNBn\x8d\xc0\x05\u07e3Ql\xb8\xa6\x80\xb0.\ua56e\x8e\x89Hz\x9a0E9D\x00\x00\u07d4lR\xcf\b\x95\xbb5\xe6V\x16\x1eM\xc4j\xe0\xe9m\xd3\xe6,\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4lT\"\xfbK\x14\xe6\u064b`\x91\xfd\xecq\xf1\xf0\x86@A\x9d\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4l\\:T\u0367\xc2\xf1\x18\xed\xbaCN\xd8\x1en\xbb\x11\xddz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4lc\xf8EV\u0490\xbf\u0359\xe44\ue657\xbf\xd7yWz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4lc\xfc\x85\x02\x9a&T\u05db+\xeaM\xe3I\xe4REw\u0149#\xc7W\a+\x8d\xd0\x00\x00\u07d4led\xe5\xc9\xc2N\xaa\xa7D\xc9\xc7\xc9h\xc9\xe2\xc9\xf1\xfb\xae\x89I\x9bB\xa2\x119d\x00\x00\xe0\x94lg\xd6\xdb\x1d\x03Ql\x12\x8b\x8f\xf24\xbf=I\xb2m)A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4lg\xe0\u05f6.*\bPiE\xa5\xdf\xe3\x82c3\x9f\x1f\"\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4lj\xa0\xd3\vdr\x19\x90\xb9PJ\x86?\xa0\xbf\xb5\xe5}\xa7\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u07d4lqJX\xff\xf6\xe9}\x14\xb8\xa5\xe3\x05\xeb$@eh\x8b\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4l\x80\rKI\xba\a%\x04`\xf9\x93\xb8\xcb\xe0\v&j%S\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4l\x80\x8c\xab\xb8\xff_\xbbc\x12\xd9\xc8\xe8J\xf8\xcf\x12\xef\bu\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94l\x82 )!\x8a\xc8\xe9\x8a&\f\x1e\x06@)4\x889\x87[\x8a\x01\x0f\x97\xb7\x87\xe1\xe3\b\x00\x00\u07d4l\x84\u02e7|m\xb4\xf7\xf9\x0e\xf1=^\xe2\x1e\x8c\xfc\u007f\x83\x14\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\x86\x87\xe3Aw\x10\xbb\x8a\x93U\x90!\xa1F\x9ej\x86\xbcw\x8a\x02[-\xa2x\xd9k{\x80\x00\xe0\x94l\x88,'s,\xef\\|\x13\xa6\x86\xf0\xa2\xeawUZ\u0089\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4l\xa5\xde\x00\x81}\xe0\xce\xdc\xe5\xfd\x00\x01(\xde\xde\x12d\x8b<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\xa6\xa12\xce\x1c\u0488\xbe\xe3\x0e\xc7\xcf\xef\xfb\x85\xc1\xf5\nT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\xb1\x1e\xcb2\xd3\u0382\x96\x011\x066\xf5\xa1\f\xf7\u03db_\x8a\x04?\u851c8\x01\xf5\x00\x00\u07d4l\xc1\xc8x\xfal\u078a\x9a\v\x83\x11$~t\x1eFB\xfem\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94l\xcb\x03\xac\xf7\xf5<\xe8z\xad\xcc!\xa9\x93-\xe9\x15\xf8\x98\x04\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4l\xd2\x12\xae\xe0N\x01?=*\xba\u04a0#`k\xfb\\j\u01c9lj\xccg\u05f1\xd4\x00\x00\u07d4l\xd2(\xdcq!i0\u007f\xe2|\xebtw\xb4\x8c\xfc\x82r\xe5\x89\x044\xea\x94\u06caP\x00\x00\u07d4l\xe1\xb0\xf6\xad\xc4pQ\xe8\xab8\xb3\x9e\xdbA\x86\xb0;\xab\u0309Ay\x97\x94\xcd$\xcc\x00\x00\u07d4l\xea\xe3s=\x8f\xa4=l\xd8\f\x1a\x96\xe8\xeb\x93\x10\x9c\x83\xb7\x89\x10'\x94\xad \xdah\x00\x00\u07d4m\x05i\xe5U\x8f\xc7\xdf'f\xf2\xba\x15\u070a\xef\xfc[\xebu\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4m\x12\x0f\f\xaa\xe4O\xd9K\xca\xfeU\xe2\xe2y\uf5ba\\z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\x14V\xff\xf0\x10N\xe8D\xa31G7\x8438\xd2L\xd6l\x89\a\xb0l\xe8\u007f\xddh\x00\x00\u07d4m \xef\x97\x04g\nP\v\xb2i\xb5\x83.\x85\x98\x02\x04\x9f\x01\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\xe0\x94m/\x97g4\xb9\xd0\a\r\x18\x83\xcfz\u02b8\xb3\xe4\x92\x0f\xc1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m9\xa9\u93c1\xf7i\xd7:\xad,\xea\xd2v\xac\x13\x87\xba\xbe\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4m;x6\xa2\xb9\u0619r\x1aM#{R#\x85\xdc\xe8\xdf\u034966\xc2^f\xec\xe7\x00\x00\u07d4m?+\xa8V\u033b\x027\xfava\x15k\x14\xb0\x13\xf2\x12@\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94m@\b\xb4\xa8\x88\xa8&\xf2H\xeej\v\r\xfd\xe9\xf92\x10\xb9\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4m@\xca'\x82m\x97s\x1b>\x86\xef\xfc\u05f9*Aa\xfe\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mD\x97J1\u0447\xed\xa1m\xddG\xb9\xc7\xecP\x02\xd6\x1f\xbe\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94mK\\\x05\xd0j \x95~\x17H\xabm\xf2\x06\xf3C\xf9/\x01\x8a\x02\x1f6\x06\x99\xbf\x82_\x80\x00\xe0\x94mL\xbf=\x82\x84\x83:\xe9\x93D0>\b\xb4\xd6\x14\xbf\xda;\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4mY\xb2\x1c\xd0\xe2t\x88\x04\u066b\xe0d\xea\u00be\xf0\xc9_'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mc\u04ce\xe8\xb9\x0e\x0en\xd8\xf1\x92\xed\xa0Q\xb2\u05a5\x8b\xfd\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4mf4\xb5\xb8\xa4\x01\x95\xd9I\x02z\xf4\x82\x88\x02\t,\ued89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94m}\x1c\x94\x95\x11\xf8\x83\x03\x80\x8c`\xc5\xea\x06@\xfc\xc0&\x83\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m\x84m\xc1&W\xe9\x1a\xf2P\bQ\x9c>\x85\u007fQp}\u0589\xf8\xd3\v\xc9#B\xf8\x00\x00\u07d4m\x91\x93\x99k\x19F\x17!\x11\x06\xd1c^\xb2l\u0136ll\x89\x15\xaa\x1e~\x9d\xd5\x1c\x00\x00\u07d4m\x99\x97P\x98\x82\x02~\xa9G#\x14$\xbe\xde\xde)e\u043a\x89l\x81\u01f3\x11\x95\xe0\x00\x00\u07d4m\xa0\xed\x8f\x1di3\x9f\x05\x9f*\x0e\x02G\x1c\xb4O\xb8\u00fb\x892\xbc8\xbbc\xa8\x16\x00\x00\u07d4m\xb7+\xfdC\xfe\xf4e\xcaV2\xb4Z\xabra@N\x13\xbf\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xbe\x8a\xbf\xa1t(\x06&9\x817\x1b\xf3\xd3U\x90\x80kn\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xc3\xf9+\xaa\x1d!\u06b78+\x892a\xa05o\xa7\xc1\x87\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4m\xc7\x05:q\x86\x16\xcf\u01cb\xeec\x82\xeeQ\xad\xd0\xc7\x030\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xcc~d\xfc\xaf\xcb\xc2\xdcl\x0e^f,\xb3G\xbf\xfc\xd7\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xda_x\x8alh\x8d\u07d2\x1f\xa3\x85.\xb6\xd6\xc6\xc6)f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4m\xdb`\x92w\x9dXB\xea\xd3x\xe2\x1e\x81 \xfdLk\xc12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4m\xdf\xefc\x91U\u06ab\n\\\xb4\x95:\xa8\u016f\xaa\x88\x04S\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4m\xe0/-\xd6~\xfd\xb794\x02\xfa\x9e\xaa\xcb\xcfX\x9d.V\x89@\x13\x8b\x91~\u07f8\x00\x00\u07d4m\u4d418\\\xf7\xfc\x9f\xe8\xc7}\x13\x1f\xe2\xeew$\xc7j\x89})\x97s=\xcc\xe4\x00\x00\u07d4m\xe4\xd1R\x19\x18/\xaf:\xa2\xc5\xd4\xd2Y_\xf20\x91\xa7'\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4m\xed\xf6.t?M,*K\x87\xa7\x87\xf5BJz\xeb9<\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4m\xf2Of\x85\xa6/y\x1b\xa37\xbf?\xf6~\x91\xf3\u053c:\x89ukI\xd4\nH\x18\x00\x00\u07d4m\xf5\xc8O{\x90\x9a\xab>a\xfe\x0e\xcb\x1b;\xf2`\"*\u0489\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\xff\x90\xe6\xdc5\x9d%\x90\x88+\x14\x83\xed\xbc\xf8\x87\xc0\xe4#\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\x01\xe4\xadV\x9c\x95\xd0\a\xad\xa3\r^-\xb1(\x88I\"\x94\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\a;f\u0478\xc6gD\u0600\x96\xa8\u0759\xec~\x02(\u0689\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x0e\xe7\x06\x12\xc9v(}I\x9d\u07e6\xc0\xdc\xc1,\x06\xde\xea\x89\a\v\u0579V!F\x00\x00\xe0\x94n\x12\xb5\x1e\"[JCr\xe5\x9a\u05e2\xa1\xa1>\xa3\u04e17\x8a\x03\x00F\xc8\xccw_\x04\x00\x00\u07d4n\x1a\x04l\xaf[JW\xf4\xfdK\xc1sb!&\xb4\xe2\xfd\x86\x89a\t=|,m8\x00\x00\u07d4n\x1e\xa4\xb1\x83\xe2R\u027bwg\xa0\x06\u05346\x96\u02ca\xe9\x89\x0f\xf3x<\x85\xee\u0400\x00\u07d4n%[p\n\xe7\x13\x8aK\xac\xf2(\x88\xa9\xe2\xc0\n(^\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n'\n\xd5)\xf1\xf0\xb8\xd9\xcbm$'\xec\x1b~-\xc6Jt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4n.\xab\x85\u0709\xfe)\xdc\n\xa1\x852G\u06b4:R=V\x89\x04V9\x18$O@\x00\x00\u07d4n:Q\xdbt=3M/\xe8\x82$\xb5\xfe|\x00\x8e\x80\xe6$\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4nL*\xb7\xdb\x02i9\xdb\u04fch8J\xf6`\xa6\x18\x16\xb2\x89\t\r\x97/22<\x00\x00\u07d4nM.9\u0203f)\u5d07\xb1\x91\x8af\x9a\xeb\u07556\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\\-\x9b\x1cTj\x86\xee\xfd]\nQ \xc9\xe4\xe70\x19\x0e\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4n`\xae\u19cf\x8e\u068bBLs\xe3S5J\xe6|0B\x89\xbd5\xa4\x8d\x99\x19\xe6\x00\x00\u07d4nd\xe6\x12\x9f\"N7\x8c\x0ensj~z\x06\xc2\x11\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4nm[\xbb\xb9\x05;\x89\xd7D\xa2s\x16\u00a7\xb8\xc0\x9bT}\x891Rq\n\x02>m\x80\x00\u07d4nr\xb2\xa1\x18j\x8e)\x16T;\x1c\xb3jh\x87\x0e\xa5\u0457\x89\n\x15D\xbe\x87\x9e\xa8\x00\x00\u07d4nv\x1e\xaa\x0f4_w{TA\xb7:\x0f\xa5\xb5k\x85\xf2-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4ny\xed\u0504[\anL\u060d\x18\x8bnC-\xd9?5\xaa\x893\xc5I\x901r\f\x00\x00\u07d4n\x82\x12\xb7\"\xaf\xd4\b\xa7\xa7>\xd3\xe29^\xe6EJ\x030\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\u07d4n\x84\x87m\xbb\x95\xc4\vfV\xe4+\xa9\xae\xa0\x8a\x99;T\u0709;\xbc`\xe3\xb6\u02fe\x00\x00\u07d4n\x84\xc2\xfd\x18\xd8\tW\x14\xa9h\x17\x18\x9c\xa2\x1c\xcab\xba\xb1\x89\x12{lp&!\u0340\x00\u07d4n\x86m\x03-@Z\xbd\xd6\\\xf6QA\x1d\x807\x96\xc2#\x11\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94n\x89\x9eY\xa9\xb4\x1a\xb7\xeaA\xdfu\x17\x86\x0f*\xcbY\xf4\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4n\x89\xc5\x1e\xa6\xde\x13\xe0l\xdct\x8bg\xc4A\x0f\u9f2b\x03\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x8a&h\x9fz/\xde\xfd\x00\x9c\xba\xaaS\x10%4P\u06ba\x89o!7\x17\xba\xd8\xd3\x00\x00\u07d4n\x96\xfa\xed\xa3\x05C\x02\xc4_X\xf1a2L\x99\xa3\xee\xbbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xb0\xa5\xa9\xae\x96\xd2,\xf0\x1d\x8f\xd6H;\x9f8\xf0\x8c,\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xb3\x81\x96\x17@@X&\x8f\f<\xff5\x96\xbf\xe9\x14\x8c\x1c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94n\xb5W\x8ak\xb7\xc3!S\x19[\r\x80 \xa6\x91HR\xc0Y\x8a\x8b\u00ab\xf4\x02!\xf4\x80\x00\x00\u07d4n\xbb^iW\xaa\x82\x1e\xf6Y\xb6\x01\x8a9:PL\xaeDP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\xbc\xf9\x95\u007f_\xc5\u916d\xd4u\";\x04\xb8\xc1Jz\xed\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4n\xc3e\x95q\xb1\x1f\x88\x9d\xd49\xbc\xd4\xd6u\x10\xa2[\xe5~\x89\x06\xaa\xf7\xc8Qm\f\x00\x00\u07d4n\u021b9\xf9\xf5'jU>\x8d\xa3\x0en\xc1z\xa4~\xef\u01c9\x18BO_\v\x1bN\x00\x00\u07d4n\xc9m\x13\xbd\xb2M\u01e5W)?\x02\x9e\x02\xddt\xb9zU\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xca\xef\xa6\xfc>\xe54bm\xb0,o\x85\xa0\u00d5W\x1ew\x89 \x86\xac5\x10R`\x00\x00\u07d4n\u04a1+\x02\xf8\u0188\u01f5\u04e6\xea\x14\xd66\x87\u06b3\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\u0604E\x9f\x80\x9d\xfa\x10\x16\xe7p\xed\xaf>\x9f\xefF\xfa0\x89\xb8R\xd6x \x93\xf1\x00\x00\xe0\x94n\xdf\u007fR\x83r\\\x95>\xe6C\x17\xf6a\x88\xaf\x11\x84\xb03\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4n\xe8\xaa\xd7\xe0\xa0e\u0605-|;\x9an_\xdcK\xf5\f\x00\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xef\u0705\x0e\x87\xb7\x15\xc7'\x91w<\x03\x16\xc3U\x9bX\xa4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xf9\xe8\u0276!}Vv\x9a\xf9}\xbb\x1c\x8e\x1b\x8b\xe7\x99\u0489\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4n\xfb\xa8\xfb*\u0176s\a)\xa9r\xec\"D&\xa2\x87\u00ed\x89\x0fY\x85\xfb\xcb\xe1h\x00\x00\xe0\x94n\xfd\x90\xb55\xe0\v\xbd\x88\x9f\xda~\x9c1\x84\xf8y\xa1Q\u06ca\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4o\x05\x16f\xcbO{\u04b1\x90r!\xb8)\xb5U\u05e3\xdbt\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4o\x0e\xdd#\xbc\xd8_`\x15\xf9(\x9c(\x84\x1f\xe0L\x83\xef\xeb\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4o\x13zq\xa6\xf1\x97\xdf,\xbb\xf0\x10\u073d\x89a\t=|,m8\x00\x00\u07d4p\x10\xbe-\xf5{\u042b\x9a\xe8\x19l\xd5\n\xb0\xc5!\xab\xa9\xf9\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4p#\xc7\tV\xe0J\x92\xd7\x00%\xaa\u0497\xb59\xaf5Xi\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p%\x96]+\x88\xda\x19}DY\xbe=\xc98cD\xcc\x1f1\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d4p(\x02\xf3m\x00%\x0f\xabS\xad\xbc\u0596\xf0\x17oc\x8aI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pH\x19\xd2\xe4Mn\xd1\xda%\xbf\u0384\u011f\u0322V\x13\xe5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4pJn\xb4\x1b\xa3O\x13\xad\xdd\xe7\xd2\xdb}\xf0I\x15\u01e2!\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4pJ\xb1\x15\r^\x10\xf5\xe3I\x95\b\xf0\xbfpe\x0f\x02\x8dK\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4pJ\xe2\x1dv-n\x1d\xde(\xc25\xd11\x04Yr6\xdb\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pM$<)x\xe4l,\x86\xad\xbe\xcd$n;)_\xf63\x89m\x12\x1b\xeb\xf7\x95\xf0\x00\x00\u07d4pM]\xe4\x84m9\xb5<\xd2\x1d\x1cI\xf0\x96\xdb\\\x19\xba)\x89\b=lz\xabc`\x00\x00\u07d4p]\xdd85T\x82\xb8\xc7\u04f5\x15\xbd\xa1P\r\xd7\u05e8\x17\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94pan(\x92\xfa&\x97\x05\xb2\x04k\x8f\xe3\xe7/\xa5X\x16\u04ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4pg\x0f\xbb\x05\xd30\x14DK\x8d\x1e\x8ew\x00%\x8b\x8c\xaam\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\x81\xfak\xaa\xd6\u03f7\xf5\x1b,\xca\x16\xfb\x89p\x99\x1ad\xba\x89\f\xae\xc0\x05\xf6\xc0\xf6\x80\x00\xe0\x94p\x85\xae~~M\x93!\x97\xb5\u01c5\x8c\x00\xa3gF&\xb7\xa5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4p\x86\xb4\xbd\xe3\xe3]J\xeb$\xb8%\xf1\xa2\x15\xf9\x9d\x85\xf7E\x89lh\xcc\u041b\x02,\x00\x00\u07d4p\x8a*\xf4%\u03b0\x1e\x87\xff\xc1\xbeT\xc0\xf52\xb2\x0e\xac\u0589\aE\u0503\xb1\xf5\xa1\x80\x00\u07d4p\x8e\xa7\a\xba\xe45\u007f\x1e\xbe\xa9Y\u00e2P\xac\u05aa!\xb3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794p\x8f\xa1\x1f\xe3=\x85\xad\x1b\xef\u02ee8\x18\xac\xb7\x1fj}~\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4p\x9101\x16\xd5\xf28\x9b##\x8bMej\x85\x96\u0644\u04c9;N~\x80\xaaX3\x00\x00\u07d4p\x99\xd1/n\xc6V\x89\x9b\x04\x9avW\x06]b\x99h\x92\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4p\x9f\xe9\xd2\xc1\xf1\xceB |\x95\x85\x04J`\x89\x9f5\x94/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xa05I\xaaah\xe9~\x88\xa5\b3\nZ\v\xeatq\x1a\x89Hz\x9a0E9D\x00\x00\u07d4p\xa4\x06}D\x8c\xc2]\xc8\xe7\x0ee\x1c\xea|\xf8N\x92\x10\x9e\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4p\xab4\xbc\x17\xb6o\x9c;c\xf1Q'O*r|S\x92c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xc2\x13H\x8a\x02\f<\xfb9\x01N\xf5\xbad\x04rK\u02a3\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4p\xd2^\xd2\u022d\xa5\x9c\b\x8c\xf7\r\xd2+\xf2\u06d3\xac\xc1\x8a\x899GEE\u4b7c\x00\x00\u07d4p\xe5\xe9\xdas_\xf0w$\x9d\u02da\xaf=\xb2\xa4\x8d\x94\x98\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4p\xfe\xe0\x8b\x00\xc6\xc2\xc0Jp\xc0\xce=\x92\u03ca\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794q\v\xe8\xfd^)\x18F\x8b\u2abe\xa8\r\x82\x845\u05d6\x12\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4q\x13]\x8f\x05\x96<\x90ZJ\a\x92)\t#Z\x89jR\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4q\x1e\xcfw\xd7\x1b=\x0e\xa9\\\xe4u\x8a\xfe\u0379\xc11\a\x9d\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4q!?\xca14\x04 N\u02e8q\x97t\x1a\xa9\xdf\xe9c8\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94q+vQ\x02\x14\xdcb\x0fl:\x1d\u049a\xa2+\xf6\xd2\x14\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4q/\xf77\n\x13\xed6\ts\xfe\u071f\xf5\xd2\xc9:P^\x9e\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4q3\x84:x\xd99\u019dD\x86\xe1\x0e\xbc{`*4\x9f\xf7\x89\x11\xd5\xca\xcc\xe2\x1f\x84\x00\x00\u07d4qH\xae\xf32a\xd8\x03\x1f\xac?q\x82\xff5\x92\x8d\xafT\u0649\xdeB\xee\x15D\u0750\x00\x00\u07d4qcu\x8c\xbblLR^\x04\x14\xa4\n\x04\x9d\xcc\xcc\xe9\x19\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4qh\xb3\xbb\x8c\x16s!\u067d\xb0#\xa6\xe9\xfd\x11\xaf\u026f\u0649a\t=|,m8\x00\x00\u07d4qirN\xe7\"q\xc54\xca\xd6B\x0f\xb0N\xe6D\u02c6\xfe\x89\x16<+@\u06e5R\x00\x00\u07d4qj\xd3\xc3:\x9b\x9a\n\x18\x96sW\x96\x9b\x94\xee}*\xbc\x10\x89\x1a!\x17\xfeA*H\x00\x00\xe0\x94qk\xa0\x1e\xad*\x91'\x065\xf9_%\xbf\xaf-\xd6\x10\xca#\x8a\ty\xe7\x01 V\xaax\x00\x00\u07d4qmP\u0320\x1e\x93\x85\x00\xe6B\x1c\xc0p\xc3P|g\u04c7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qv,cg\x8c\x18\xd1\xc67\x8c\xe0h\xe6f8\x13\x15\x14~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qxL\x10Q\x17\xc1\xf6\x895y\u007f\xe1Y\xab\xc7NC\xd1j\x89l\x81\u01f3\x11\x95\xe0\x00\x00\xe0\x94qyro\\q\xae\x1bm\x16\xa6\x84(\x17Nk4\xb26F\x8a\x01\x8e\xa2P\t|\xba\xf6\x00\x00\xe0\x94q|\xf9\xbe\xab680\x8d\xed~\x19^\f\x86\x13-\x16?\xed\x8a\x032n\xe6\xf8e\xf4\"\x00\x00\u07d4q\x80\xb8>\xe5WC\x17\xf2\x1c\x80r\xb1\x91\u0615\xd4aS\u00c9\x18\xef\xc8J\xd0\u01f0\x00\x00\u07d4q\x94kq\x17\xfc\x91^\xd1\a8_B\u065d\xda\xc62I\u0089lk\x93[\x8b\xbd@\x00\x00\xe0\x94q\x9e\x89\x1f\xbc\xc0\xa3>\x19\xc1-\xc0\xf0 9\xca\x05\xb8\x01\u07ca\x01OU8F:\x1bT\x00\x00\u07d4q\xc7#\n\x1d5\xbd\u0581\x9e\u0539\xa8\x8e\x94\xa0\xeb\a\x86\u0749\uc80b5=$\x14\x00\x00\u07d4q\xd2\xccm\x02W\x8ce\xf7\r\xf1\x1bH\xbe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4r\x83\xcdFu\xdaX\u0116UaQ\xda\xfd\x80\xc7\xf9\x95\xd3\x18\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4r\x86\xe8\x9c\xd9\u078fz\x8a\x00\xc8o\xfd\xb59\x92\u0752Q\u0449i*\xe8\x89p\x81\xd0\x00\x00\u07d4r\x8f\x9a\xb0\x80\x15}\xb3\a1V\xdb\xca\x1a\x16\x9e\xf3\x17\x94\a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4r\x94\xc9\x18\xb1\xae\xfbM%\x92~\xf9\u05d9\xe7\x1f\x93\xa2\x8e\x85\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94r\x94\uc763\x10\xbckK\xbd\xf5C\xb0\xefE\xab\xfc>\x1bM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4r\x9a\xadF'tNS\xf5\xd6c\t\xaatD\x8b:\xcd\xf4o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xa2\xfc\x86u\xfe\xb9r\xfaA\xb5\r\xff\u06fa\xe7\xfa*\u07f7\x89\x9a\xb4\xfcg\xb5(\xc8\x00\x00\u07d4r\xa8&\b&)G&\xa7[\xf3\x9c\u066a\x9e\a\xa3\xea\x14\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb0Yb\xfb*\u0549\xd6Z\xd1j\"U\x9e\xba\x14X\xf3\x87\x89\a?u\u0460\x85\xba\x00\x00\u07d4r\xb5c?\xe4w\xfeT.t/\xac\xfdi\f\x13xT\xf2\x16\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4r\xb7\xa0=\xda\x14\u029cf\x1a\x1dF\x9f\xd376\xf6s\xc8\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb9\x04D\x0e\x90\xe7 \u05ac\x1c*\u05dc2\x1d\xcc\x1c\x1a\x86\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94r\xb9\nM\xc0\x97#\x94\x92\u0179w}\xcd\x1eR\xba+\xe2\u008a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4r\xbb'\u02d9\xf3\xe2\xc2\u03d0\xa9\x8fp}0\xe4\xa2\x01\xa0q\x89X\xe7\x92n\xe8X\xa0\x00\x00\xe0\x94r\xc0\x83\xbe\xad\xbd\xc2'\xc5\xfbC\x88\x15\x97\xe3.\x83\xc2`V\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4r\xcd\x04\x8a\x11\x05tH)\x83I-\xfb\x1b\xd2yB\xa6\x96\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xd0=M\xfa\xb3P\f\xf8\x9b\x86\x86o\x15\xd4R\x8e\x14\xa1\x95\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4r\u06bb[n\ud799\xbe\x91X\x88\xf6V\x80V8\x16\b\xf8\x89\vL\x96\xc5,\xb4\xfe\x80\x00\u07d4r\xfbI\u009d#\xa1\x89P\u0132\xdc\r\xdfA\x0fS-oS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xfe\xaf\x12EyR9Td[\u007f\xaf\xff\x03x\xd1\xc8$.\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\x01\xdcL\xf2mq\x86\xf2\xa1\x1b\xf8\xb0\x8b\xf2)F?d\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x04G\xf9|\xe9\xb2_\"\xba\x1a\xfb6\xdf'\xf9Xk\ub6c9,s\xc97t,P\x00\x00\u07d4s\x06\xde\x0e(\x8bV\xcf\u07d8~\xf0\xd3\xcc)f\a\x93\xf6\u0749\x1b\x8a\xbf\xb6.\xc8\xf6\x00\x00\xe0\x94s\r\x87c\u01a4\xfd\x82J\xb8\xb8Y\x16\x1e\xf7\xe3\xa9j\x12\x00\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4s\x12\x81sH\x95(\x01.v\xb4\x1a^(\u018b\xa4\xe3\xa9\u050965\u026d\xc5\u07a0\x00\x00\u07d4s\x13F\x12\bETUFTE\xa4Y\xb0l7s\xb0\xeb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s/\xea\xd6\x0f{\xfd\u05a9\xde\u0101%\xe3s]\xb1\xb6eO\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sB#\xd2\u007f\xf2>Y\x06\xca\xed\"YW\x01\xbb4\x83\f\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4sG>r\x11Q\x10\xd0\xc3\xf1\x17\b\xf8nw\xbe+\xb0\x98<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sRXm\x02\x1a\xd0\xcfw\xe0\xe9(@JY\xf3t\xffE\x82\x89\xb8Pz\x82\a( \x00\x00\u07d4sU\v\xebs+\xa9\u076f\xdaz\xe4\x06\xe1\x8f\u007f\xeb\x0f\x8b\xb2\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4s[\x97\xf2\xfc\x1b\xd2K\x12\an\xfa\xf3\xd1(\x80s\xd2\f\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4s^2\x86f\xedV7\x14+3\x06\xb7|\xccT`\xe7,=\x89j\xb8\xf3xy\u0251\x00\x00\u07d4sc\u0350\xfb\xab[\xb8\u011a\xc2\x0f\xc6,9\x8f\xe6\xfbtL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4skDP=\xd2\xf6\xddTi\xffL[-\xb8\xeaO\xece\u0409\x11\x04\xeeu\x9f!\xe3\x00\x00\xe0\x94sk\xf1@,\x83\x80\x0f\x89>X1\x92X*\x13N\xb52\xe9\x8a\x02\x1e\x19\u0493\xc0\x1f&\x00\x00\xe0\x94s\x8c\xa9M\xb7\u038b\xe1\xc3\x05l\u0598\x8e\xb3v5\x9f3S\x8a\x05f[\x96\xcf5\xac\xf0\x00\x00\u07d4s\x91K\"\xfc/\x13\x15\x84$}\x82\xbeO\ucfd7\x8a\u053a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x93'\t\xa9\u007f\x02\u024eQ\xb0\x911(e\x12#\x85\xae\x8e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4s\x93\xcb\xe7\xf9\xba!e\xe5\xa7U5\x00\xb6\xe7]\xa3\xc3:\xbf\x89\x05k\xc7^-c\x10\x00\x00\u07d4s\xb4\u0519\xde?8\xbf5\xaa\xf7i\xa6\xe3\x18\xbcm\x126\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\xbe\xddo\xda{\xa3'!\x85\b{cQ\xfc\x13=HN7\x8a\x01\x12&\xbf\x9d\xceYx\x00\x00\u07d4s\xbf\xe7q\x0f1\u02b9I\xb7\xa2`O\xbfR9\xce\xe7\x90\x15\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\u03c0\xae\x96\x88\xe1X\x0eh\xe7\x82\xcd\b\x11\xf7\xaaIM,\x8a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\xe0\x94s\xd7&\x9f\xf0l\x9f\xfd3uL\xe5\x88\xf7J\x96j\xbb\xbb\xba\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4s\xd8\xfe\xe3\u02c6M\xce\"\xbb&\u029c/\bm^\x95\xe6;\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\xdf<>yU\xf4\xf2\xd8Y\x83\x1b\xe3\x80\x00\xb1\ak8\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4s\u48b6\f\U0010e2ef+w~\x17Z[\x1eM\f-\x8f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94t\n\xf1\xee\xfd3e\u05cb\xa7\xb1,\xb1\xa6s\xe0j\arF\x8a\x04+\xf0kx\xed;P\x00\x00\xe0\x94t\v\xfdR\xe0\x16g\xa3A\x9b\x02\x9a\x1b\x8eEWj\x86\xa2\u06ca\x03\x8e\xba\xd5\xcd\xc9\x02\x80\x00\x00\u07d4t\x0fd\x16\x14w\x9d\u03e8\x8e\xd1\xd4%\xd6\r\xb4*\x06\f\xa6\x896\"\xc6v\b\x10W\x00\x00\u07d4t\x12\u027c0\xb4\xdfC\x9f\x021\x00\xe69$\x06j\xfdS\xaf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4t\x16\x93\xc3\x03vP\x85\x13\b \xcc+c\xe9\xfa\x92\x13\x1b\x89A\rXj \xa4\xc0\x00\x00\u07d4t!\xce[\xe3\x81s\x8d\u0703\xf0&!\x97O\xf0hly\xb8\x89Xx\x8c\xb9K\x1d\x80\x00\x00\u07d4t1j\xdf%7\x8c\x10\xf5v\u0574\x1aoG\xfa\x98\xfc\xe3=\x89\x128\x13\x1e\\z\xd5\x00\x00\u07d4t6Q\xb5^\xf8B\x9d\xf5\f\xf8\x198\xc2P\x8d\xe5\u0207\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t=\xe5\x00&\xcag\xc9M\xf5O\x06b`\xe1\xd1J\xcc\x11\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tE /\ft)z\x00N\xb3rj\xa6\xa8-\xd7\xc0/\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tK\x03\xbb\xa8X*\xe5I\x8e-\xc2-\x19\x94\x94g\xabS\xfc\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4tL\fw\xba\u007f#i \xd1\xe44\xde]\xa3>H\xeb\xf0,\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4tP\xff\u007f\x99\xea\xa9\x11bu\u07ach\xe4(\xdf[\xbc\u0639\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tV\u0172\xc5Cn>W\x10\b\x93?\x18\x05\xcc\xfe4\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4tZ\u04eb\xc6\xee\xeb$qh\x9bS\x9ex\x9c\xe2\xb8&\x83\x06\x89=A\x94\xbe\xa0\x11\x92\x80\x00\xe0\x94tZ\xec\xba\xf9\xbb9\xb7Jg\xea\x1c\xe6#\xde6\x84\x81\xba\xa6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4t\\\xcf-\x81\x9e\u06fd\u07a8\x11{\\I\xed<*\x06n\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4tb\u021c\xaa\x9d\x8dx\x91\xb2T]\xef!otd\u057b!\x89\x05\xea\xedT\xa2\x8b1\x00\x00\u07d4td\x8c\xaa\xc7H\xdd\x13\\\xd9\x1e\xa1L(\xe1\xbdM\u007f\xf6\xae\x89\xa8\r$g~\xfe\xf0\x00\x00\xe0\x94tq\xf7.\xeb0\x06$\xeb(.\xabM\x03r\x00\x00\x00\xe0\x94t\x84\xd2k\xec\xc1\xee\xa8\xc61^\xc3\xee\nE\x01\x17\u0706\xa0\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4t\x86:\xce\xc7]\x03\xd5>\x86\x0ed\x00/,\x16^S\x83w\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x89\u030a\xbeu\u0364\xef\r\x01\xce\xf2`^G\xed\xa6z\xb1\x89\a?u\u0460\x85\xba\x00\x00\u07d4t\x8c(^\xf1#?\xe4\xd3\x1c\x8f\xb17\x833r\x1c\x12\xe2z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\x90\x87\xac\x0fZ\x97\xc6\xfa\xd0!S\x8b\xf1\xd6\u0361\x8e\r\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x95\xaex\xc0\xd9\x02a\xe2\x14\x0e\xf2\x061\x04s\x1a`\xd1\xed\x89\x01\xdbPq\x89%!\x00\x00\u07d4t\x9aJv\x8b_#rH\x93\x8a\x12\xc6#\x84{\xd4\xe6\x88\u0709\x03\xe73b\x87\x14 \x00\x00\u07d4t\x9a\xd6\xf2\xb5pk\xbe/h\x9aD\u0136@\xb5\x8e\x96\xb9\x92\x89\x05k\xc7^-c\x10\x00\x00\u07d4t\xa1\u007f\x06K4N\x84\xdbce\u0695\x91\xff\x16(%vC\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4t\xae\xec\x91]\xe0\x1c\u019b,\xb5\xa65o\xee\xa1FX\xc6\u0149\f\x9a\x95\xee)\x86R\x00\x00\u07d4t\xaf\xe5I\x02\xd6\x15x%v\xf8\xba\xac\x13\xac\x97\f\x05\x0fn\x89\t\xa1\xaa\xa3\xa9\xfb\xa7\x00\x00\u07d4t\xb7\xe0\"\x8b\xae\xd6YW\xae\xbbM\x91m3:\xae\x16O\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbcJ^ E\xf4\xff\x8d\xb1\x84\xcf:\x9b\f\x06Z\xd8\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbc\xe9\xec86-l\x94\u032c&\xd5\xc0\xe1:\x8b;\x1d@\x8965&A\x04B\xf5\x00\x00\u07d4t\xbfzZ\xb5\x92\x93\x14\x9b\\`\xcf6Bc\xe5\xeb\xf1\xaa\r\x89\x06G\f>w\x1e<\x00\x00\xe0\x94t\xc7<\x90R\x8a\x15s6\xf1\xe7\xea b\n\xe5?\xd2G(\x8a\x01\xe6:.S\x8f\x16\xe3\x00\x00\u07d4t\u0464\xd0\xc7RN\x01\x8dN\x06\xed;d\x80\x92\xb5\xb6\xaf,\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94t\xd3f\xb0{/VG}|pw\xaco\xe4\x97\xe0\xebeY\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4t\xd3zQt{\xf8\xb7q\xbf\xbfC\x9493\xd1\x00\xd2\x14\x83\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xd6q\u065c\xbe\xa1\xabW\x90cu\xb6?\xf4+PE\x1d\x17\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xeb\xf4BVF\xe6\u03c1\xb1\t\xce{\xf4\xa2\xa6=\x84\x81_\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4t\xed3\xac\xf4?5\xb9\x8c\x920\xb9\xe6d.\xcbS0\x83\x9e\x89$\xf6\xdf\xfbI\x8d(\x00\x00\u07d4t\xef(i\xcb\xe6\b\x85`E\xd8\xc2\x04\x11\x18W\x9f\"6\xea\x89\x03<\xd6E\x91\x95n\x00\x00\u07d4t\xfcZ\x99\xc0\xc5F\x05\x03\xa1;\x05\tE\x9d\xa1\x9c\xe7\u0350\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4u\v\xbb\x8c\x06\xbb\xbf$\bC\xccux.\xe0/\b\xa9tS\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4u\x14\xad\xbd\xc6?H?0M\x8e\x94\xb6\u007f\xf30\x9f\x18\v\x82\x89!\u0120n-\x13Y\x80\x00\u0794u\x17\xf1l(\xd12\xbb@\xe3\xba6\u01ae\xf11\xc4b\xda\x17\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4u\x1a,\xa3Nq\x87\xc1c\u048e6\x18\xdb(\xb1<\x19m&\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94u\x1a\xbc\xb6\xcc\x030Y\x91\x18\x15\xc9o\u04516\n\xb0D-\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4u&\xe4\x82R\x9f\n\x14\xee\u0248q\xdd\xdd\x0er\x1b\f\u0662\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4u)\xf3y{\xb6\xa2\x0f~\xa6I$\x19\xc8L\x86vA\xd8\x1c\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94u*^\xe22a,\xd3\x00_\xb2n[Y}\xe1\x9fwk\xe6\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4u,\x9f\xeb\xf4/f\xc4x{\xfa~\xb1|\xf53;\xbaPp\x89j\x99\xf2\xb5O\xddX\x00\x00\u07d4u930F\u07b1\xef\x8e\u07b9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94u\xc1\xad#\xd2?$\xb3\x84\xd0\xc3\x14\x91w\xe8f\x97a\r!\x8a\x01\\[\xcdl(\x8b\xbd\x00\x00\u07d4u\xc2\xff\xa1\xbe\xf5I\x19\xd2\t\u007fz\x14-.\x14\xf9\xb0JX\x89\x90\xf3XP@2\xa1\x00\x00\u07d4u\xd6|\xe1N\x8d)\xe8\xc2\xff\u3051{\x93\v\x1a\xff\x1a\x87\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4u\xde~\x93R\xe9\v\x13\xa5\x9aXx\xff\xec\u01c3\x1c\xacM\x82\x89\x94\x89#z\u06daP\x00\x00\u07d4u\xf7S\x9d0\x9e\x909\x98\x9e\xfe.\x8b-\xbd\x86Z\r\xf0\x88\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4v\b\xf47\xb3\x1f\x18\xbc\vd\u04c1\xae\x86\xfd\x97\x8e\u05f3\x1f\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94v\x0f\xf35N\x0f\u0793\x8d\x0f\xb5\xb8,\xef[\xa1\\=)\x16\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v\x1an6,\x97\xfb\xbd|Yw\xac\xba-\xa7F\x876_I\x89\t\xf7J\xe1\xf9S\xd0\x00\x00\u07d4v\x1el\xae\xc1\x89\xc20\xa1b\xec\x00e0\x19>g\u03dd\x19\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94v\x1f\x8a:*\U00028f7e\x1d\xa0\t2\x1f\xb2\x97d\xebb\xa1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v)\x98\xe1\xd7R'\xfc\xedzp\xbe\x10\x9aL\vN\xd8d\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v-o0\u06b9\x915\xe4\xec\xa5\x1dRC\xd6\xc8b\x11\x02\u0549\x0fI\x89A\xe6d(\x00\x00\u07d4v3\x1e0yl\xe6d\xb2p\x0e\rASp\x0e\u0706\x97w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v8\x86\xe33\xc5o\xef\xf8[\xe3\x95\x1a\xb0\xb8\x89\xce&.\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v:|\xba\xb7\rzd\u0427\xe5)\x80\xf6\x81G%\x93I\f\x89 \x86\xac5\x10R`\x00\x00\u07d4v>\xec\u0c0a\u021e2\xbf\xa4\xbe\xcev\x95\x14\xd8\xcb[\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4v@\xa3\u007f\x80R\x98\x15\x15\xbc\xe0x\u0693\xaf\xa4x\x9bW4\x89lk\x93[\x8b\xbd@\x00\x00\u0794vA\xf7\xd2j\x86\xcd\xdb+\xe10\x81\x81\x0e\x01\xc9\xc8E\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94vO\xc4mB\x8bm\xbc\"\x8a\x0f_U\xc9P\x8cw.\xab\x9f\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4vPn\xb4\xa7\x80\xc9Q\xc7J\x06\xb0=;\x83b\xf0\x99\x9dq\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94v[\xe2\xe1/b\x9ecI\xb9}!\xb6*\x17\xb7\xc80\xed\xab\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94vb\x81P\xe2\x99[['\x9f\xc8>\r\xd5\xf1\x02\xa6q\xdd\x1c\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4vk7Y\xe8yN\x92m\xacG=\x91:\x8f\xb6\x1a\xd0\xc2\u0249\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4vp\xb0/,<\xf8\xfdOG0\xf38\x1aq\xeaC\x1c3\u01c9\x0e~\xeb\xa3A\vt\x00\x00\u07d4vz\x03eZ\xf3`\x84\x1e\x81\r\x83\xf5\xe6\x1f\xb4\x0fL\xd1\x13\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4vz\u0190y\x1c.#E\x10\x89\xfelp\x83\xfeU\u07b6+\x89,s\xc97t,P\x00\x00\u07d4v\u007f\xd7y}Qi\xa0_sd2\x1c\x19\x84:\x8c4\x8e\x1e\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u0794v\x84o\r\xe0;Zv\x97\x1e\xad)\x8c\xdd\b\x84:K\xc6\u0188\xd7\x1b\x0f\u088e\x00\x00\xe0\x94v\x84\x98\x93N7\xe9\x05\xf1\xd0\xe7{D\xb5t\xbc\xf3\xecJ\xe8\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4v\x8c\xe0\u06a0)\xb7\xde\xd0\"\xe5\xfcWM\x11\xcd\xe3\xec\xb5\x17\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94v\x93\xbd\xebo\xc8+[\xcar\x13U\"1u\xd4z\bKM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4v\xaa\xf8\xc1\xac\x01/\x87R\xd4\xc0\x9b\xb4f\a\xb6e\x1d\\\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v\xab\x87\xddZ\x05\xad\x83\x9aN/\xc8\xc8Z\xa6\xba\x05d\x170\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v\xaf\xc2%\xf4\xfa0}\xe4\x84U+\xbe\x1d\x9d?\x15\aLJ\x89\xa2\x90\xb5\u01ed9h\x00\x00\xe0\x94v\xbe\xca\xe4\xa3\x1d6\xf3\xcbW\u007f*CYO\xb1\xab\xc1\xbb\x96\x8a\x05C\xa9\xce\x0e\x132\xf0\x00\x00\u07d4v\xc2u5\xbc\xb5\x9c\xe1\xfa-\x8c\x91\x9c\xab\xebJk\xba\x01\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4v\xca\"\xbc\xb8y\x9eS'\u012a*}\tI\xa1\xfc\xce_)\x89R\xa0?\"\x8cZ\xe2\x00\x00\u07d4v\xca\u0108\x11\x1aO\u0555\xf5h\xae:\x85\x87p\xfc\x91]_\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94v\u02dc\x8bi\xf48vu\u0102S\xe24\xcb~\rt\xa4&\x8a\x01\x90\xf4H.\xb9\x1d\xae\x00\x00\u07d4v\xf8:\xc3\xda0\xf7\t&(\xc73\x9f \x8b\xfc\x14,\xb1\ue25a\x18\xff\xe7B}d\x00\x00\xe0\x94v\xf9\xad=\x9b\xbd\x04\xae\x05\\\x14w\xc0\xc3^u\x92\xcb* \x8a\b\x83?\x11\xe3E\x8f \x00\x00\u07d4v\xff\xc1W\xadk\xf8\xd5m\x9a\x1a\u007f\u077c\x0f\xea\x01\n\xab\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\x02\x8e@\x9c\xc4:;\xd3=!\xa9\xfcS\xec`n\x94\x91\x0e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4w\f/\xb2\u0128\x17S\xac\x01\x82\xeaF\x0e\xc0\x9c\x90\xa5\x16\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\r\x98\xd3\x1bCS\xfc\xee\xe8V\fL\u03c0>\x88\xc0\xc4\xe0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94w\x13\xab\x807A\x1c\t\xbah\u007fo\x93d\xf0\xd3#\x9f\xac(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4w\x15\a\xae\xeej%]\xc2\u035d\xf5QT\x06-\b\x97\xb2\x97\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4w\x19\x88\x87\x95\xadtY$\xc7W`\u0771\x82}\xff\xd8\u0368\x89lkLM\xa6\u077e\x00\x00\u07d4w'\xaf\x10\x1f\n\xab\xa4\xd2:\x1c\xaf\xe1|n\xb5\u06b1\xc6\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4w,)\u007f\n\u0454H.\xe8\xc3\xf06\xbd\xeb\x01\xc2\x01\xd5\u0309\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94w0o\xfe.J\x8f<\xa8&\xc1\xa2I\xf7!-\xa4:\xef\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4w1A\x12}\x8c\xf3\x18\xae\xbf\x886Z\xdd=U'\xd8[j\x8966\u05ef^\u024e\x00\x00\u07d4wF\xb6\xc6i\x9c\x8f4\xca'h\xa8 \xf1\xff\xa4\xc2\a\xfe\x05\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4wQ\xf3c\xa0\xa7\xfd\x053\x19\b\t\u076f\x93@\xd8\xd1\x12\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4wW\xa4\xb9\xcc=\x02G\u032a\xeb\x99\t\xa0\xe5n\x1d\xd6\xdc\u0089\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\\\x10\xc9>\r\xb7 [&CE\x823\xc6O\xc3?\xd7[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4wa~\xbcK\xeb\xc5\xf5\xdd\xeb\x1bzp\xcd\xebj\xe2\xff\xa0$\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4wiC\xff\xb2\xef\\\xdd5\xb8<(\xbc\x04k\xd4\xf4gp\x98\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94wp\x1e,I=\xa4|\x1bX\xf4!\xb5I]\xeeE\xbe\xa3\x9b\x8a\x01H\xf6I\xcfaB\xa5\x80\x00\u07d4wy\x8f \x12W\xb9\xc3R\x04\x95pW\xb5Ft\xae\xfaQ\u07c9\b\x13\xcaV\x90m4\x00\x00\u07d4w\x8cC\xd1\x1a\xfe;Xo\xf3t\x19-\x96\xa7\xf2=+\x9b\u007f\x89\x8b\xb4\xfc\xfa;}k\x80\x00\u07d4w\x8cy\xf4\xde\x19S\xeb\u0398\xfe\x80\x06\xd5:\x81\xfbQ@\x12\x8963\x03\"\xd5#\x8c\x00\x00\u07d4w\x92t\xbf\x18\x03\xa36\xe4\u04f0\r\u0753\xf2\xd4\xf5\xf4\xa6.\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xa1q\"\xfa1\xb9\x8f\x17\x11\xd3*\x99\xf0>\xc3&\xf3=\b\x89\\(=A\x03\x94\x10\x00\x00\u07d4w\xa3I\a\xf3\x05\xa5L\x85\xdb\t\xc3c\xfd\xe3\xc4~j\xe2\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4w\xa7i\xfa\xfd\xec\xf4\xa68v-[\xa3\x96\x9d\xf61 \xa4\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xbekd\xd7\xc73\xa46\xad\xec^\x14\xbf\x9a\xd7@+\x1bF\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xbf\xe9<\u0367P\x84~A\xa1\xaf\xfe\xe6\xb2\u0696\xe7!N\x89\x10CV\x1a\x88)0\x00\x00\u07d4w\u0126\x97\xe6\x03\xd4+\x12\x05l\xbb\xa7a\xe7\xf5\x1d\x04C\xf5\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4w\xcc\x02\xf6#\xa9\u03d8S\t\x97\xeag\xd9\\;I\x18Y\xae\x89Is\x03\xc3n\xa0\xc2\x00\x00\u07d4w\xd4?\xa7\xb4\x81\xdb\xf3\xdbS\f\xfb\xf5\xfd\xce\xd0\xe6W\x181\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xda^lr\xfb6\xbc\xe1\xd9y\x8f{\xcd\xf1\u044fE\x9c.\x89\x016\x95\xbbl\xf9>\x00\x00\u07d4w\xf4\xe3\xbd\xf0V\x88<\xc8r\x80\xdb\xe6@\xa1\x8a\r\x02\xa2\a\x89\n\x81\x99:+\xfb[\x00\x00\u0794w\xf6\t\u0287 \xa0#&,U\xc4o-&\xfb90\xaci\x88\xf0\x15\xf2W6B\x00\x00\u07d4w\xf8\x1b\x1b&\xfc\x84\xd6\u0797\uf2df\xbdr\xa310\xccJ\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\x19\xb0E\x8e1N+S\xbf\xe0\f8I_\u0539\xfd\xf8\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4x\x1b\x15\x01dz.\x06\xc0\xedC\xff\x19\u007f\xcc\xec5\xe1p\v\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4x/R\xf0\xa6v\xc7w\x16\xd5t\xc8\x1e\xc4hO\x9a\x02\n\x97\x89.\x14\xe2\x06\xb70\xad\x80\x00\u07d4x5]\xf0\xa20\xf8=\x03,p1TAM\xe3\xee\u06b5W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x6\xf7\xefk\u01fd\x0f\xf3\xac\xafD\x9c\x84\xddk\x1e,\x93\x9f\x89\xe0\x8d\xe7\xa9,\xd9|\x00\x00\u07d4x7\xfc\xb8v\xda\x00\xd1\xeb;\x88\xfe\xb3\xdf?\xa4\x04/\xac\x82\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4x>\uc2a5\xda\xc7{.f#\xedQ\x98\xa41\xab\xba\xee\a\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4x\\\x8e\xa7t\xd70D\xa74\xfay\n\x1b\x1et>w\xed|\x89\f\xf1Rd\f\\\x83\x00\x00\u07d4x`\xa3\xde8\xdf8*\xe4\xa4\xdc\xe1\x8c\f\a\xb9\x8b\xce=\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94xcCq\xe1s\x04\xcb\xf39\xb1E*L\xe48\xdcvL\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4xd\u0719\x9f\xe4\xf8\xe0\x03\xc0\xf4=\xec\u00da\xae\x15\"\xdc\x0f\x89\x05\x1e\x10+\xd8\xec\xe0\x00\x00\u07d4xtj\x95\x8d\xce\xd4\xc7d\xf8vP\x8cAJh4,\uce49\x02\xbe7O\xe8\xe2\xc4\x00\x00\xe0\x94x}1?\xd3k\x05>\xee\xae\xdb\xcet\xb9\xfb\x06x32\x89\x8a\x05\xc0X\xb7\x84'\x19`\x00\x00\u07d4x\x85\x9c[T\x8bp\r\x92\x84\xce\xe4\xb6c=GJ\x8a\x04{\x92\xc4\x15B$-\n\b\xc7\x0f\x99\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4x\u03c36\xb3(\xdb=\x87\x81:G+\x9e\x89\xb7^\f\xf3\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\xd4\xf8\xc7\x1c\x1eh\xa6\x9a\x98\xf5/\xcbE\u068a\xf5n\xa1\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x\xdf&\x81\xd6\xd6\x02\xe2!B\xd5A\x16\u07a1]EIW\xaa\x89\x10'\x94\xad \xdah\x00\x00\u07d4x\xe0\x8b\xc53A<&\u2473\x14?\xfa|\u026f\xb9{x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4x\xe8?\x80\xb3g\x8cz\nN>\x8c\x84\xdc\xcd\xe0dBbw\x89a\t=|,m8\x00\x00\u07d4x\xf5\xc7G\x85\xc5f\x8a\x83\x80r\x04\x8b\xf8\xb4SYM\u06ab\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\x0f\x91\xbd]\x1c\\\xc4s\x9a\xe9\x13\x00\u06c9\xe1\xc10<\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\x17\u5f42\xa9y\x0f\xd6P\xd0C\xcd\xd90\xf7y\x963\u06c9\xd8\xd4`,&\xbfl\x00\x00\u07d4y\x19\xe7b\u007f\x9b}T\xea;\x14\xbbM\xd4d\x9fO9\xde\xe0\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4y\x1f`@\xb4\xe3\xe5\r\xcf5S\xf1\x82\u0357\xa9\x060\xb7]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4y0\xc2\xd9\xcb\xfa\x87\xf5\x10\xf8\xf9\x87w\xff\x8a\x84H\xcaV)\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4yE)\u041d\x01rq5\x970\x02pu\xb8z\xd8=\xaen\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4yKQ\u00deS\xd9\xe7b\xb0a;\x82\x9aD\xb4r\xf4\xff\xf3\x89$5\xe0dxA\u0300\x00\xe0\x94yU\x1c\xed\xe3v\xf7G\xe3ql\x8dy@\rvm.\x01\x95\x8a\t\xcb7\xaf\xa4\xffxh\x00\x00\u07d4y^\xbc&&\xfc9\xb0\xc8b\x94\xe0\xe87\xdc\xf5#U0\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4yn\xbb\xf4\x9b>6\xd6v\x94\xady\xf8\xff6vz\xc6\xfa\xb0\x89\x03K\xc4\xfd\xde'\xc0\x00\x00\u07d4yo\x87\xbaaz)0\xb1g\v\xe9.\xd1(\x1f\xb0\xb3F\xe1\x89\x06\xf5\xe8o\xb5((\x00\x00\u07d4yt'\xe3\xdb\xf0\xfe\xaez%\x06\xf1-\xf1\xdc@2n\x85\x05\x8965\u026d\xc5\u07a0\x00\x00\u07d4yu\x10\xe3\x86\xf5c\x93\xce\xd8\xf4w7\x8aDLHO}\xad\x8965\u026d\xc5\u07a0\x00\x00\u07d4y{\xb7\xf1W\xd9\xfe\xaa\x17\xf7m\xa4\xf7\x04\xb7M\xc1\x03\x83A\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4y\x88\x90\x131\xe3\x87\xf7\x13\xfa\u03b9\x00\\\xb9\xb6Q6\xeb\x14\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4y\x89\u041f8&\xc3\u5bccu*\x81\x15r:\x84\xd8\tp\x89\x16\x86\xf8aL\xf0\xad\x00\x00\xe0\x94y\x95\xbd\x8c\xe2\xe0\xc6{\xf1\u01e51\xd4w\xbc\xa1\xb2\xb9ua\x8a\x01BH\xd6\x17\x82\x9e\xce\x00\x00\u07d4y\xae\xb3Ef\xb9t\xc3ZX\x81\xde\xc0 \x92}\xa7\xdf]%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xb1 \xeb\x88\x06s#!(\x8fgZ'\xa9\"_\x1c\xd2\ub245\xa0\xbf7\xde\xc9\xe4\x00\x00\u07d4y\xb4\x8d-a7\u00c5Ma\x1c\x01\xeaBBz\x0fY{\xb7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4y\xb8\xaa\xd8y\xdd0V~\x87x\xd2\xd21\xc8\xf3z\xb8sN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xbf/{n2\x8a\xaf&\xe0\xbb\t?\xa2-\xa2\x9e\xf2\xf4q\x89a\t=|,m8\x00\x00\u07d4y\xc10\xc7b\xb8v[\x19\u04ab\u0260\x83\xab\x8f:\xady@\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4y\xc1\xbe\x19q\x1fs\xbe\xe4\xe61j\xe7T\x94Y\xaa\u03a2\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\xc6\x00/\x84R\xca\x15\u007f\x13\x17\xe8\n/\xaf$GUY\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4y\xca\xc6IO\x11\xef'\x98t\x8c\xb52\x85\xbd\x8e\"\xf9|\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4y\u03e9x\n\xe6\xd8{,1\x88?\t'i\x86\u021ag5\x8965\u026d\xc5\u07a0\x00\x00\u07d4y\u06e2VG-\xb4\xe0X\xf2\xe4\xcd\xc3\xeaN\x8aBw83\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4y\xed\x10\xcf\x1fm\xb4\x82\x06\xb5\t\x19\xb9\xb6\x97\b\x1f\xbd\xaa\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xf0\x8e\x01\xce\t\x88\xe6<\u007f\x8f)\b\xfa\xdeC\xc7\xf9\xf5\u0248\xfc\x93c\x92\x80\x1c\x00\x00\u07d4y\xfdmH1Pf\xc2\x04\xf9e\x18i\xc1\tl\x14\xfc\x97\x81\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xff\xb4\xac\x13\x81*\vx\u0123{\x82u\">\x17k\xfd\xa5\x88\xf0\x15\xf2W6B\x00\x00\u07d4z\x05\x89\xb1C\xa8\xe5\xe1\a\u026cf\xa9\xf9\xf8Yz\xb3\u7ac9Q\xe92\xd7n\x8f{\x00\x00\u07d4z\nx\xa9\xcc9?\x91\xc3\xd9\xe3\x9ak\x8c\x06\x9f\a^k\xf5\x89Hz\x9a0E9D\x00\x00\u07d4z\x13p\xa7B\xec&\x87\xe7a\xa1\x9a\u0167\x942\x9e\xe6t\x04\x89\xa2\xa12ga\xe2\x92\x00\x00\xe0\x94z-\xfcw\x0e$6\x811\xb7\x84w\x95\xf2\x03\xf3\xd5\r[V\x8a\x02i\xfe\xc7\xf06\x1d \x00\x00\u07d4z3\x83N\x85\x83s>-R\xae\xadX\x9b\u046f\xfb\x1d\xd2V\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94z6\xab\xa5\xc3\x1e\xa0\xca~'{\xaa2\xecF\u0393\xcfu\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94z8\x11\"\xba\xday\x1az\xb1\xf6\x03}\xac\x80C'S\xba\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94zH\xd8w\xb6:\x8f\x8f\x93\x83\xe9\xd0\x1eS\xe8\fR\x8e\x95_\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4zO\x9b\x85\x06\x90\xc7\xc9F\x00\xdb\xee\f\xa4\xb0\xa4\x11\xe9\xc2!\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4zc\x86\x9f\xc7g\xa4\u01b1\xcd\x0e\x06I\xf3cL\xb1!\xd2K\x89\x043\x87Oc,\xc6\x00\x00\u07d4zg\xdd\x04:PO\xc2\xf2\xfcq\x94\xe9\xbe\xcfHL\xec\xb1\xfb\x89\r\x8drkqw\xa8\x00\x00\xe0\x94zk&\xf48\u0663RD\x91U\xb8\x87l\xbd\x17\xc9\u065bd\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4zmx\x1cw\u013a\x1f\xca\xdfhsA\xc1\xe3\x17\x99\xe9='\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4zph\xe1\xc37\\\x0eY\x9d\xb1\xfb\xe6\xb2\xea#\xb8\xf4\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4zt\xce\xe4\xfa\x0fcp\xa7\x89O\x11l\xd0\f\x11G\xb8>Y\x89+^:\xf1k\x18\x80\x00\x00\u07d4zy\xe3\x0f\xf0W\xf7\n=\x01\x91\xf7\xf5?v\x157\xaf}\xff\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94zzO\x80sW\xa4\xbb\xe6\x8e\x1a\xa8\x0692\x10\xc4\x11\u0333\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4z\x85c\x86y\x01 o?+\xf0\xfa>\x1c\x81\t\u02bc\u0345\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94z\x87\x97i\n\xb7{Tp\xbf|\f\x1b\xbaa%\b\xe1\xac}\x8a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4z\x8c\x89\xc0\x14P\x9dV\u05f6\x810f\x8f\xf6\xa3\xec\xecsp\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94z\x94\xb1\x99\x92\u03b8\xcec\xbc\x92\xeeKZ\xde\xd1\fM\x97%\x8a\x03\x8d\x1a\x80d\xbbd\xc8\x00\x00\u07d4z\xa7\x9a\xc0C\x16\u030d\b\xf2\x00e\xba\xa6\xd4\x14(\x97\xd5N\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4z\xadM\xbc\u04ec\xf9\x97\u07d3XiV\xf7+d\u062d\x94\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94z\xb2V\xb2\x04\x80\n\xf2\x017\xfa\xbc\xc9\x16\xa22Xu%\x01\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\xbaV\xf6:H\xbc\b\x17\u05b9p9\x03\x9az\xd6/\xae.\x89 \x86\xac5\x10R`\x00\x00\xe0\x94z\xbb\x10\xf5\xbd\x9b\xc3;\x8e\xc1\xa8-d\xb5[k\x18wuA\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\u010d@\xc6d\u031am\x89\xf1\xc5\xf5\xc8\n\x1cp\xe7D\u6263\x10b\xbe\xee\xd7\x00\x00\x00\u07d4z\u014fo\xfcO\x81\a\xaen07\x8eN\x9f\x99\xc5\u007f\xbb$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4z\xd3\xf3\aao\x19\u0731C\xe6DM\xab\x9c<3a\x1fR\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4z\xd8,\xae\xa1\xa8\xb4\xed\x051\x9b\x9c\x98p\x17<\x81N\x06\xee\x89!d\xb7\xa0J\u0220\x00\x00\u07d4z\xde]f\xb9D\xbb\x86\f\x0e\xfd\xc8bv\u054fFS\xf7\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xdf\xed\xb0m\x91\xf3\xccs\x90E\v\x85U\x02p\x88<{\xb7\x89\x11x\xfa@Q]\xb4\x00\x00\u07d4z\xe1\xc1\x9eS\xc7\x1c\xeeLs\xfa\xe2\xd7\xfcs\xbf\x9a\xb5\u348965\u026d\xc5\u07a0\x00\x00\u07d4z\xe6Y\xeb;\xc4hR\xfa\x86\xfa\xc4\xe2\x1cv\x8dP8\x89E\x89\x0f\x81\f\x1c\xb5\x01\xb8\x00\x00\u07d4z\xea%\xd4+&\x12(n\x99\xc56\x97\u01bcA\x00\xe2\u06ff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xef{U\x1f\v\x9cF\xe7U\xc0\xf3\x8e[:s\xfe\x11\x99\xf5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4{\v1\xffn$t^\xad\x8e\u067b\x85\xfc\v\xf2\xfe\x1dU\u0509+^:\xf1k\x18\x80\x00\x00\xe0\x94{\x0f\xea\x11v\xd5!Y3:\x14<)IC\xda6\xbb\u0774\x8a\x01\xfc}\xa6N\xa1L\x10\x00\x00\u07d4{\x11g<\xc0\x19bk)\f\xbd\xce&\x04o~m\x14\x1e!\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x12!b\xc9\x13\xe7\x14l\xad\v~\xd3z\xff\xc9*\v\xf2\u007f\x89Q\xaf\tk#\x01\u0440\x00\u07d4{\x1b\xf5:\x9c\xbe\x83\xa7\u07a44W\x9f\xe7*\xac\x8d*\f\u0409\n\xd4\xc81j\v\f\x00\x00\u07d4{\x1d\xaf\x14\x89\x1b\x8a\x1e\x1b\xd4)\u0633k\x9aJ\xa1\u066f\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x1f\xe1\xabM\xfd\x00\x88\xcd\xd7\xf6\x01c\xefY\xec*\xee\x06\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4{%\xbb\x9c\xa8\xe7\x02!~\x933\"RP\xe5<6\x80MH\x89e\xea=\xb7UF`\x00\x00\u07d4{'\xd0\xd1\xf3\xdd<\x14\x02\x94\xd0H\x8bx>\xbf@\x15'}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94{@\a\xc4^ZW?\u06f6\xf8\xbdtk\xf9J\xd0J<&\x8a\x038!\xf5\x13]%\x9a\x00\x00\u07d4{C\xc7\xee\xa8\xd6#U\xb0\xa8\xa8\x1d\xa0\x81\xc6Dk3\xe9\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4{M*8&\x90i\xc1\x85Ww\rY\x1d$\xc5\x12\x1f^\x83\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94{au\xec\x9b\xef\xc78$\x955\xdd\xde4h\x8c\xd3n\xdf%\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94{f\x12hy\x84M\xfa4\xfee\xc9\xf2\x88\x11\u007f\xef\xb4I\xad\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4{j\x84q\x8d\xd8nc3\x84)\xac\x81\x1d|\x8a\x86\x0f!\xf1\x89a\t=|,m8\x00\x00\xe0\x94{q,z\xf1\x16v\x00jf\xd2\xfc\\\x1a\xb4\xc4y\xce`7\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4{s$-u\u029a\xd5X\xd6P)\r\xf1v\x92\xd5L\u0638\x89lnY\xe6|xT\x00\x00\u07d4{v\x1f\xeb\u007f\u03e7\xde\xd1\xf0\xeb\x05\x8fJ`\v\xf3\xa7\b\u02c9\xf9]\xd2\xec'\xcc\xe0\x00\x00\xe0\x94{\x82|\xae\u007f\xf4t\t\x18\xf2\xe00\xab&\u02d8\xc4\xf4l\xf5\x8a\x01\x94hL\v9\xde\x10\x00\x00\xe0\x94{\x892\x86B~r\xdb!\x9a!\xfcM\xcd_\xbfY(<1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4{\x92&\xd4o\xe7Q\x94\v\xc4\x16\xa7\x98\xb6\x9c\xcf\r\xfa\xb6g\x89\u3bb5sr@\xa0\x00\x00\u07d4{\x98\xe2<\xb9k\xee\xe8\n\x16\x80i\ube8f \xed\xd5\\\u03c9\v\xa0\xc9\x15\x87\xc1J\x00\x00\u07d4{\xb0\xfd\xf5\xa6c\xb5\xfb\xa2\x8d\x9c\x90*\xf0\xc8\x11\xe2R\xf2\x98\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4{\xb9W\x1f9K\v\x1a\x8e\xbaVd\xe9\u0635\xe8@g{\xea\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94{\xb9\x84\xc6\u06f9\xe2y\x96j\xfa\xfd\xa5\x9c\x01\xd0&'\xc8\x04\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4{\xbb\xec^p\xbd\xea\u063b2\xb4(\x05\x98\x8e\x96H\xc0\xaa\x97\x8966\u05ef^\u024e\x00\x00\u07d4{\xca\x1d\xa6\xc8\nf\xba\xa5\xdbZ\u0245A\u013e'kD}\x89$\xcf\x04\x96\x80\xfa<\x00\x00\u07d4{\u0772\xee\x98\xde\x19\xeeL\x91\xf6a\xee\x8eg\xa9\x1d\x05K\x97\x8965\u026d\xc5\u07a0\x00\x00\u0794{\xe2\xf7h\f\x80-\xa6\x15L\x92\xc0\x19J\xe72Qzqi\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4{\xe7\xf2Eiq\x88;\x9a\x8d\xbeL\x91\xde\xc0\x8a\xc3N\x88b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4{\xe8\u0334\xf1\x1bf\xcan\x1dW\xc0\xb59b!\xa3\x1b\xa5:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94{\xeb\x81\xfb/^\x91Rk*\xc9y^v\u019b\xcf\xf0K\xc0\x8a\x0e\xb2.yO\n\x8d`\x00\x00\u07d4|\b\x83\x05L-\x02\xbcz\x85+\x1f\x86\xc4'w\xd0\xd5\xc8V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\x0f^\a C\xc9\xeet\x02B\x19~x\xccK\x98\xcd\xf9`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|\x1d\xf2JO\u007f\xb2\u01f4r\xe0\xbb\x00l\xb2}\xcd\x16AV\x8965\u026d\xc5\u07a0\x00\x00\u07d4|)\xd4}W\xa73\xf5k\x9b!pc\xb5\x13\xdc;1Y#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4|+\x96\x03\x88JO.FN\u03b9}\x17\x93\x8d\x82\x8b\xc0,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4|8,\x02\x96a.N\x97\xe4@\xe0-8q';U\xf5;\x89\n\xb6@9\x12\x010\x00\x00\u07d4|>\xb7\x13\xc4\xc9\xe08\x1c\xd8\x15L|\x9a}\xb8d\\\xde\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|D\x01\xae\x98\xf1.\xf6\xde9\xae$\u03df\xc5\x1f\x80\xeb\xa1k\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|E\xf0\xf8D*V\xdb\u04dd\xbf\x15\x99\x95A\\R\xedG\x9b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|S-\xb9\xe0\xc0l&\xfd@\xac\xc5j\xc5\\\x1e\xe9-<:\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4|`\xa0_zJ_\x8c\xf2xC\x916.uZ\x83A\xefY\x89f\x94\xf0\x18*7\xae\x00\x00\u07d4|`\xe5\x1f\v\xe2(\xe4\xd5o\xdd)\x92\xc8\x14\xdaw@\u01bc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|i$\xd0|>\xf5\x89\x19f\xfe\nxV\xc8{\xef\x9d 4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|\x8b\xb6Zo\xbbI\xbdA3\x96\xa9\xd7\xe3\x10S\xbb\xb3z\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94|\x9a\x11\f\xb1\x1f%\x98\xb2\xb2\x0e,\xa4\x002^A\xe9\xdb3\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4|\xbc\xa8\x8f\xcaj\x00`\xb9`\x98\\\x9a\xa1\xb0%4\xdc\"\b\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4|\xbe\xb9\x992\xe9~n\x02\x05\x8c\xfcb\u0432k\xc7\u0325+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xc2Jj\x95\x8c \xc7\xd1$\x96`\xf7Xb&\x95\v\r\x9a\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4|\xd2\x0e\u0335\x18\xb6\f\xab\t[r\x0fW\x15p\u02aaD~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\xd5\xd8\x1e\xab7\xe1\x1ebv\xa3\xa1\t\x12Q`~\r~8\x89\x03hM^\xf9\x81\xf4\x00\x00\u07d4|\xdft!9E\x95=\xb3\x9a\xd0\xe8\xa9x\x1a\xddy.M\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xe4hdF\U000547be\xd6r\x15\xeb\rZ\x1d\xd7,\x11\xb8\x89x9\xd3!\xb8\x1a\xb8\x00\x00\u07d4|\xefMC\xaaA\u007f\x9e\xf8\xb7\x87\xf8\xb9\x9dS\xf1\xfe\xa1\ue209g\x8a\x93 b\xe4\x18\x00\x00\u07d4}\x03P\xe4\v3\x8d\xdasfa\x87+\xe3?\x1f\x97R\xd7U\x89\x02\xb4\xf5\xa6\U00051500\x00\xe0\x94}\x04\xd2\xed\xc0X\xa1\xaf\xc7a\xd9\u025a\xe4\xfc\\\x85\xd4\u0226\x8aB\xa9\xc4g\\\x94g\xd0\x00\x00\u07d4}\v%^\xfbW\xe1\x0fp\b\xaa\"\xd4\x0e\x97R\xdf\xcf\x03x\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94}\x13\xd6pX\x84\xab!W\u074d\xccpF\xca\xf5\x8e\xe9K\xe4\x8a\x1d\r\xa0|\xbb>\xe9\xc0\x00\x00\u07d4}'>c~\xf1\xea\u0101\x11\x94\x13\xb9\x1c\x98\x9d\xc5\xea\xc1\"\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4}*R\xa7\xcf\f\x846\xa8\xe0\a\x97kl&\xb7\"\x9d\x1e\x15\x89\x17\xbf\x06\xb3*$\x1c\x00\x00\u07d4}4\x805i\xe0\v\u05b5\x9f\xff\b\x1d\xfa\\\n\xb4\x19zb\x89\\\xd8|\xb7\xb9\xfb\x86\x00\x00\u07d4}4\xffY\xae\x84\nt\x13\u01baL[\xb2\xba,u\xea\xb0\x18\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4}9(R\xf3\xab\xd9/\xf4\xbb[\xb2l\xb6\bt\xf2\xbeg\x95\x8966\xc2^f\xec\xe7\x00\x00\u07d4}DRg\u015a\xb8\u04a2\xd9\xe7\t\x99\x0e\th%\x80\u011f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94}U\x13\x97\xf7\x9a)\x88\xb0d\xaf\xd0\xef\xeb\xee\x80,w!\xbc\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\u07d4}Z\xa3?\xc1KQ\x84\x1a\x06\x90n\xdb+\xb4\x9c*\x11ri\x89\x10D\x00\xa2G\x0eh\x00\x00\xe0\x94}]/s\x94\x9d\xad\xda\bV\xb2\x06\x98\x9d\xf0\a\x8dQ\xa1\xe5\x8a\x02\xc4:H\x1d\xf0M\x01wb\xed\xcb\\\xaab\x9bZ\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4~\x8f\x96\xcc)\xf5{\tu\x12\f\xb5\x93\xb7\u0743=`kS\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4~\x97*\x8a|*D\xc9;!Cl8\xd2\x1b\x92R\xc3E\xfe\x89a\t=|,m8\x00\x00\u07d4~\x99\u07fe\x98\x9d;\xa5)\u0457Q\xb7\xf41\u007f\x89S\xa3\xe2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4~\xa0\xf9n\xe0\xa5s\xa30\xb5h\x97v\x1f=L\x010\xa8\xe3\x89Hz\x9a0E9D\x00\x00\u0794~\xa7\x91\xeb\xab\x04E\xa0\x0e\xfd\xfcNJ\x8e\x9a~ue\x13m\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4~\xab\xa05\xe2\xaf7\x93\xfdtgK\x10%@\xcf\x19\n\u0779\x89E\x02l\x83[`D\x00\x00\xe0\x94~\xb4\xb0\x18\\\x92\xb6C\x9a\b\xe72!h\xcb5<\x8awJ\x8a\x02'\x19l\xa0I\x83\xca\x00\x00\xe0\x94~\xbd\x95\xe9\xc4p\xf7(5\x83\xdcn\x9d,M\xce\v\ua3c4\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4~\u0425\xa8G\xbe\xf9\xa9\xda|\xba\x1dd\x11\xf5\xc3\x161&\x19\x89\x02(\xeb7\xe8u\x1d\x00\x00\u07d4~\xda\xfb\xa8\x98K\xafc\x1a\x82\vk\x92\xbb\xc2\xc56U\xf6\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4~\xdb\x02\xc6\x1a\"r\x87a\x1a\xd9Pici\xccNdzh\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4~\xe5\u0280]\xce#\xaf\x89\xc2\xd4D\xe7\xe4\af\xc5Lt\x04\x89\r\v\xd4\x12\xed\xbd\x82\x00\x00\xe0\x94~\xe6\x04\u01e9\xdc)\t\xce2\x1d\u6e72OWgWuU\x8a\x01+\xf9\u01d8\\\xf6-\x80\x00\u07d4~\xf1o\xd8\xd1[7\x8a\x0f\xba0k\x8d\x03\u0758\xfc\x92a\x9f\x89%\xf2s\x93=\xb5p\x00\x00\u07d4~\xf9\x8bR\xbe\xe9S\xbe\xf9\x92\xf3\x05\xfd\xa0'\xf8\x91\x1cXQ\x89\x1b\xe7\" i\x96\xbc\x80\x00\u07d4~\xfc\x90vj\x00\xbcR7,\xac\x97\xfa\xbd\x8a<\x83\x1f\x8e\u0349\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4~\xfe\xc0\xc6%<\xaf9\u007fq(|\x1c\a\xf6\xc9X+[\x86\x89\x1a,\xbc\xb8O0\u0540\x00\u07d4\u007f\x01\xdc|7G\xca`\x8f\x98=\xfc\x8c\x9b9\xe7U\xa3\xb9\x14\x89\v8l\xad_zZ\x00\x00\u07d4\u007f\x06b\xb4\x10)\x8c\x99\xf3\x11\u04e1EJ\x1e\xed\xba/\xeav\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u007f\x06\u021dY\x80\u007f\xa6\v\xc6\x016\xfc\xf8\x14\u02ef%C\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u007f\v\x90\xa1\xfd\u050f'\xb2h\xfe\xb3\x83\x82\xe5]\xdbP\xef\x0f\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\u007f\x0e\xc3\u06c0F\x92\xd4\xd1\xea2E6Z\xab\x05\x90\a[\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u007f\x0f\x04\xfc\xf3zS\xa4\xe2N\xden\x93\x10Nx\xbe\x1d<\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007f\x13\xd7`I\x8dq\x93\xcahY\xbc\x95\xc9\x018d#\xd7l\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u007f\x15\n\xfb\x1aw\u00b4Y(\xc2h\xc1\u9f74d\x1dG\u0609lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\x16\x19\x98\x8f7\x15\xe9O\xf1\xd2S&-\xc5X\x1d\xb3\xde\x1c\x890\xca\x02O\x98{\x90\x00\x00\u07d4\u007f\x1c\x81\xee\x16\x97\xfc\x14K|\v\xe5I;V\x15\xae\u007f\xdd\u0289\x1b\x1d\xaba\u04ead\x00\x00\u07d4\u007f#\x82\xff\xd8\xf89VFy7\xf9\xbar7F#\xf1\x1b8\x89 \x86\xac5\x10R`\x00\x00\u07d4\u007f7\t9\x1f?\xbe\xba5\x92\xd1u\xc7@\xe8z\tT\x1d\x02\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\u007f8\x9c\x12\xf3\xc6\x16OdFVlwf\x95\x03\xc2y%'\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\u007f:\x1eE\xf6~\x92\u0200\xe5s\xb43y\xd7\x1e\xe0\x89\xdbT\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\u007f=r\x03\u0224G\xf7\xbf6\u060a\xe9\xb6\x06*^\xeex\xae\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u007fF\xbb%F\r\xd7\xda\xe4!\x1c\xa7\xf1Z\xd3\x12\xfc}\xc7\\\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\u007fI\xe7\xa4&\x98\x82\xbd\x87\"\u0526\xf5f4v)b@y\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007fI\xf2\a&G\x1a\xc1\u01e8>\xf1\x06\xe9w\\\xebf%f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\u007fK^'\x85x\xc0F\xcc\xea\xf6W0\xa0\xe0h2\x9e\u0576\x89e\xea=\xb7UF`\x00\x00\u07d4\u007fOY;a\x8c3\v\xa2\xc3\xd5\xf4\x1e\xce\xeb\x92\xe2~Bl\x89\x96n\xdcuk|\xfc\x00\x00\u07d4\u007fT\x14\x91\u04ac\x00\xd2a/\x94\xaa\u007f\v\xcb\x01FQ\xfb\u0509\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\u007fZ\xe0Z\xe0\xf8\xcb\xe5\xdf\xe7!\xf0D\u05e7\xbe\xf4\xc2y\x97\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u007f`:\xec\x17Y\xea_\a\xc7\xf8\xd4\x1a\x14(\xfb\xba\xf9\xe7b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u007falo\x00\x8a\u07e0\x82\xf3M\xa7\xd0e\x04`6\x80u\xfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u007fa\xfal\xf5\xf8\x98\xb4@\xda\u016b\xd8`\rmi\x1f\xde\xf9\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u007fe\\g\x89\xed\xdfE\\\xb4\xb8\x80\x99r\x0698\x9e\ubb0a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u007fk(\u0204!\xe4\x85~E\x92\x81\u05c4ai$\x89\xd3\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007fn\xfboC\x18\x87m.\xe6$\xe2u\x95\xf4DF\xf6\x8e\x93\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u007fq\x92\xc0\xdf\x1c}\xb6\xd9\xede\xd7\x11\x84\xd8\xe4\x15Z\x17\xba\x89\x04Sr\x8d3\x94,\x00\x00\u07d4\u007fz:!\xb3\xf5\xa6]\x81\xe0\xfc\xb7\xd5-\xd0\n\x1a\xa3m\xba\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u007f\x8d\xbc\xe1\x80\xed\x9cV65\xaa\xd2\xd9{L\xbcB\x89\x06\u0649\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\u007f\x99=\xdb~\x02\u0082\xb8\x98\xf6\x15_h\x0e\xf5\xb9\xaf\xf9\a\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u007f\x9f\x9bV\xe4(\x9d\xfbX\xe7\x0f\xd5\xf1*\x97\xb5m5\u01a5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u007f\xa3~\xd6x\x87u\x1aG\x1f\x0e\xb3\x06\xbeD\xe0\xdb\xcd`\x89\x899vt\u007f\xe1\x1a\x10\x00\x00\u07d4\u007f\xaa0\xc3\x15\x19\xb5\x84\xe9rP\xed*<\xf38^\xd5\xfdP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xcf[\xa6fo\x96lTH\xc1{\xf1\xcb\v\xbc\xd8\x01\x9b\x06\x89\x05k\xc3\u042e\xbeI\x80\x00\xe0\x94\u007f\xd6y\xe5\xfb\r\xa2\xa5\xd1\x16\x19M\xcbP\x83\x18\xed\u0140\xf3\x8a\x01c\x9eI\xbb\xa1b\x80\x00\x00\u07d4\u007f\u06e01\u01cf\x9c\tmb\xd0Z6\x9e\uac3c\xccU\u5257\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\u007f\xdb\u00e8D\xe4\r\x96\xb2\xf3\xa652.`e\xf4\xca\x0e\x84\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xdf\u020dx\xbf\x1b(Z\xc6O\x1a\xdb5\xdc\x11\xfc\xb09Q\x89|\x06\xfd\xa0/\xb06\x00\x00\u07d4\u007f\xea\x19b\xe3]b\x05\x97h\xc7I\xbe\u0756\u02b90\xd3x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xef\x8c8w\x9f\xb3\a\xeco\x04K\xeb\xe4\u007f<\xfa\xe7\x96\xf1\x89\t#@\xf8l\xf0\x9e\x80\x00\u07d4\u007f\xf0\xc6?p$\x1b\xec\xe1\x9bs~SA\xb1+\x10\x901\u0609\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\u007f\xfa\xbf\xbc9\f\xbeC\u0389\x18\x8f\bh\xb2}\xcb\x0f\f\xad\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\u007f\xfd\x02\xed7\fp`\xb2\xaeS\xc0x\xc8\x01!\x90\u07fbu\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\x80\x02*\x12\a\xe9\x10\x91\x1f\xc9(I\xb0i\xab\f\xda\xd0C\u04c8\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x80\t\xa7\xcb\u0452\xb3\xae\u052d\xb9\x83\xd5(ER\xc1ltQ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\x0e}c\x1cnW:\x903/\x17\xf7\x1f_\u045bR\x8c\xb9\x89\b=lz\xabc`\x00\x00\u07d4\x80\x15m\x10\ufa320\u0254\x10c\r7\xe2i\xd4\t<\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\x172\xa4\x81\u00c0\xe5~\xd6-l)\u0799\x8a\xf3\xfa;\x13\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x1de\xc5\x18\xb1\x1d\x0e?OG\x02!Ap\x13\xc8\xe5>\u0149\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80&CZ\xacr\x8dI{\x19\xb3\xe7\xe5|(\xc5c\x95O+\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x80-\xc3\xc4\xff-}\x92^\u215fJ\x06\u05fa`\xf10\x8c\x89\x05P\x94\f\x8f\xd3L\x00\x00\u07d4\x800\xb1\x11\u0198?\x04\x85\u076c\xa7b$\xc6\x18\x064x\x9f\x89\x04V9\x18$O@\x00\x00\u07d4\x805\xbc\xff\xae\xfd\xee\xea5\x83\fI}\x14(\x9d6 #\u0789\x10CV\x1a\x88)0\x00\x00\u07d4\x805\xfeNkj\xf2z\u44a5xQ^\x9d9\xfao\xa6[\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80C\xed\"\xf9\x97\u58a4\xc1n6D\x86\xaed\x97V\x92\u0109=I\x04\xff\xc9\x11.\x80\x00\u07d4\x80C\xfd\u043cL\x97=\x16c\xd5_\xc15P\x8e\xc5\xd4\xf4\xfa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80L\xa9IrcOc:Q\xf3V\v\x1d\x06\xc0\xb2\x93\xb3\xb1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x80R-\u07d4N\xc5.'\xd7$\xedL\x93\xe1\xf7\xbe`\x83\u0589\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80Y\x1aB\x17\x9f4\xe6M\x9d\xf7]\xcdF;(hoUt\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x80\\\xe5\x12\x97\xa0y;\x81 g\xf0\x17\xb3\xe7\xb2\u07db\xb1\xf9\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x80]\x84o\xb0\xbc\x02\xa73r&\u0585\xbe\x9e\xe7s\xb9\x19\x8a\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x80c7\x9a{\xf2\u02d2:\x84\xc5\t>h\xda\xc7\xf7T\x81\u0149\x11v\x10.n2\xdf\x00\x00\u07d4\x80hTX\x8e\xcc\xe5AI_\x81\u008a)\x03s\xdf\x02t\xb2\x89\x1f\x8c\xdf\\n\x8dX\x00\x00\u07d4\x80oD\xbd\xebh\x807\x01^\x84\xff!\x80I\xe3\x823*3\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\x80tF\x18\xde9jT1\x97\xeeH\x94\xab\xd0c\x98\xdd|'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80w\xc3\xe4\xc4EXn\tL\xe1\x02\x93\u007f\xa0[s{V\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x90\u007fY1H\xb5|F\xc1w\xe2=%\xab\u012a\xe1\x83a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x97s\x16\x94NYB\xe7\x9b\x0e:\xba\u04cd\xa7F\be\x19\x89\x02\x1auJm\xc5(\x00\x00\xe0\x94\x80\xa0\xf6\xcc\x18l\xf6 \x14\x00sn\x06Z9\x1fR\xa9\xdfJ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x80\xab\xecZ\xa3n\\\x9d\t\x8f\x1b\x94(\x81\xbdZ\xca\u0196=\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb2=8\v\x82\\F\xe098\x99\xa8UVF-\xa0\u1309lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb4-\xe1p\xdb\xd7#\xf4T\xe8\x8fw\x16E-\x92\x98P\x92\x89\x10F#\xc0v-\xd1\x00\x00\u07d4\x80\xb7\x9f3\x83\x90\u047a\x1b77\xa2\x9a\x02W\xe5\xd9\x1e\a1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80\xbf\x99^\u063a\x92p\x1d\x10\xfe\u011f\x9e}\x01M\xbe\xe0&\x89\x1f\x047\xca\x1a~\x12\x80\x00\u07d4\x80\xc0N\xfd1\x0fD\x04\x83\xc7?tK[\x9edY\x9c\xe3\xec\x89A\rXj \xa4\xc0\x00\x00\u07d4\x80\u00e9\xf6\x95\xb1m\xb1Yr\x86\u0473\xa8\xb7il9\xfa'\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\xc5>\xe7\xe35\u007f\x94\xce\rxh\x00\x9c \x8bJ\x13\x01%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xcc!\xbd\x99\xf3\x90\x05\u014f\xe4\xa4H\x90\x92 !\x8ff\u02c966\xc9yd6t\x00\x00\u07d4\x80\xd5\xc4\fY\xc7\xf5N\xa3\xa5_\xcf\xd1uG\x1e\xa3P\x99\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x80\xda/\u0762\x9a\x9e'\xf9\xe1\x15\x97^i\xae\x9c\xfb\xf3\xf2~\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80\xe7\xb3 R0\xa5f\xa1\xf0a\xd9\"\x81\x9b\xb4\xd4\u04a0\xe1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x80\xea\x1a\xcc\x13n\xcaKh\xc8B\xa9Z\xdfk\u007f\xee~\xb8\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\xf0z\xc0\x9e{,<\n=\x1e\x94\x13\xa5D\xc7:A\xbe\u02c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81\r\xb2Vu\xf4^\xa4\xc7\xf3\x17\u007f7\xce)\xe2-g\x99\x9c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81\x13\x9b\xfd\u0326V\xc40 ?r\x95\x8cT;e\x80\xd4\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\x14a\xa2\xb0\u0290\xba\xda\xc0j\x9e\xa1nx{3\xb1\x96\u0309\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\x81\x16M\xeb\x10\x81J\xe0\x83\x91\xf3,\bf{bH\xc2}z\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x81\x18i1\x18A7\xd1\x19*\u020c\xd3\xe1\xe5\xd0\xfd\xb8jt\x89\x9d5\x95\xab$8\xd0\x00\x00\u0794\x81*U\xc4<\xae\xdcYr\x187\x90\x00\xceQ\rT\x886\xfd\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x81.\xa7\xa3\xb2\xc8n\xed2\xffO,sQL\xc6;\xac\xfb\u038965\u026d\xc5\u07a0\x00\x00\u07d4\x814\xdd\x1c\x9d\xf0\xd6\u0225\x81$&\xbbU\xc7a\u0283\x1f\b\x89\x06\xa2\x16\v\xb5|\xcc\x00\x00\u07d4\x81A5\u068f\x98\x11\aW\x83\xbf\x1a\xb6pb\xaf\x8d>\x9f@\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81I\x8c\xa0{\x0f/\x17\xe8\xbb\xc7\xe6\x1a\u007fJ\xe7\xbef\xb7\x8b\x89\x05\x81\xfb\xb5\xb3;\xb0\x00\x00\u07d4\x81Um\xb2sI\xab\x8b'\x00ID\xedP\xa4n\x94\x1a\x0f_\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x81U\xfalQ\xeb1\xd8\bA-t\x8a\xa0\x86\x10P\x18\x12/\x89e\xea=\xb7UF`\x00\x00\xe0\x94\x81V6\v\xbd7\ta\xce\xcakf\x91\xd7P\x06\xad L\xf2\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x81a\xd9@\xc3v\x01\x00\xb9\b\x05)\xf8\xa6\x03%\x03\x0fn\u0709\x10CV\x1a\x88)0\x00\x00\xe0\x94\x81d\xe7\x83\x14\xae\x16\xb2\x89&\xccU=,\xcb\x16\xf3V'\r\x8a\x01\xca\x13N\x95\xfb2\xc8\x00\x00\u07d4\x81e\u02b0\xea\xfbZ2\x8f\xc4\x1a\xc6M\xaeq[.\xef,e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81h\xed\xce\u007f)a\xcf)[\x9f\xcdZE\xc0l\xde\xdan\xf5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81m\x97r\xcf\x119\x91\x16\xcc\x1er\xc2lgt\xc9\xed\xd79\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81s\xc85djg.\x01R\xbe\x10\xff\xe8Ab\xdd%nL\x89\x1a\xab\xdf!E\xb40\x00\x00\u07d4\x81t\x93\u035b\xc6#p*$\xa5o\x9f\x82\xe3\xfdH\xf3\xcd1\x89\x9eK#\xf1-L\xa0\x00\x00\u07d4\x81y\xc8\tp\x18,\u0177\xd8*M\xf0n\xa9M\xb6:%\xf3\x89'o%\x9d\xe6k\xf4\x00\x00\u07d4\x81z\xc3;\xd8\xf8GVsr\x95\x1fJ\x10\u05e9\x1c\xe3\xf40\x89\n\xd7\xc4\x06\xc6m\xc1\x80\x00\xe0\x94\x81\x8f\xfe'\x1f\u00d75e\xc3\x03\xf2\x13\xf6\xd2\u0689\x89~\xbd\x8a\x016\xe0SB\xfe\u1e40\x00\u07d4\x81\x97\x94\x81!s.c\xd9\xc1H\x19N\xca\xd4n0\xb7I\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\x9a\xf9\xa1\xc2s2\xb1\xc3i\xbb\xda\x1b=\xe1\xc6\xe93\xd6@\x89\x11\t\xe6T\xb9\x8fz\x00\x00\xe0\x94\x81\x9c\u06a506x\xef|\xecY\u050c\x82\x16:\xcc`\xb9R\x8a\x03\x13QT_y\x81l\x00\x00\u07d4\x81\x9e\xb4\x99\vZ\xbaUG\t=\xa1+k<\x10\x93\xdfmF\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xa8\x81\x96\xfa\xc5\xf2<>\x12\xa6\x9d\xecK\x88\x0e\xb7\xd9s\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\xbc\xcb\xff\x8fD4~\xb7\xfc\xa9['\xce|\x95$\x92\xaa\xad\x89\b@\xc1!e\xddx\x00\x00\u07d4\x81\xbdu\xab\xd8e\xe0\xc3\xf0J\vO\xdb\xcbt\xd3@\x82\xfb\xb7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\xc1\x8c*#\x8d\xdcL\xba#\n\a-\xd7\xdc\x10\x1eb\x02s\x89Hz\x9a0E9D\x00\x00\u07d4\x81\xc9\xe1\xae\xe2\xd36]S\xbc\xfd\u0356\xc7\xc58\xb0\xfd~\xec\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x81\u03edv\t\x13\xd3\xc3\"\xfc\xc7{I\u00ae9\a\xe7On\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x81\xd6\x19\xffW&\xf2@_\x12\x90Lr\xeb\x1e$\xa0\xaa\xeeO\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x81\xef\u25aev\xc8`\xd1\xc5\xfb\xd3=G\xe8\u0399\x96\xd1W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xf8\xde,(=_\u052f\xbd\xa8]\xed\xf9v\x0e\xab\xbb\xb5r\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x82\f\x19)\x11\x96P[e\x05\x9d\x99\x14\xb7\t\v\xe1\u06c7\u0789\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x82\x1c\xb5\xcd\x05\xc7\uf41f\xe1\xbe`s=\x89c\xd7`\xdcA\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x82\x1dy\x8a\xf1\x99\x89\u00ee[\x84\xa7\xa7(<\xd7\xfd\xa1\xfa\xbe\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x82\x1e\xb9\t\x94\xa2\xfb\xf9K\xdc23\x91\x02\x96\xf7o\x9b\xf6\xe7\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x82$\x9f\xe7\x0fa\u01b1o\x19\xa3$\x84\x0f\xdc\x02\x021\xbb\x02\x8a\x02\x036\xb0\x8a\x93c[\x00\x00\u07d4\x82(\xeb\xc0\x87H\x0f\xd6EG\xca(\x1f^\xac\xe3\x04\x14S\xb9\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\x82)\u03b9\xf0\xd7\b9I\x8dD\xe6\xab\xed\x93\xc5\xca\x05\x9f]\x8a\x1a\x1c\x1b<\x98\x9a \x10\x00\x00\u07d4\x82.\xdf\xf66V:a\x06\xe5.\x9a%\x98\xf7\xe6\xd0\xef'\x82\x89\x01\xf4\xf9i=B\u04c0\x00\u07d4\x822\x19\xa2Yv\xbb*\xa4\xaf\x8b\xadA\xac5&\xb4\x936\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x822\xd1\xf9t.\u07cd\xd9'\xda5;*\xe7\xb4\xcb\xceu\x92\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x824\xf4c\u0444\x85P\x1f\x8f\x85\xac\xe4\x97,\x9bc-\xbc\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x827htg7\xcem\xa3\x12\xd5>TSN\x10o\x96|\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82;\xa7dr8\xd1\x13\xbc\xe9\x96JC\u0420\x98\x11\x8b\xfeM\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x82@t1(\x06\xdaGHCBf\xee\x00!@\u305a\u0089Q\xb1\u04c3\x92a\xac\x00\x00\u07d4\x82C\x8f\u04b3*\x9b\xddgKI\xd8\xcc_\xa2\xef\xf9x\x18G\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82HW(\xd0\xe2\x81V7X\xc7Z\xb2~\xd9\u80a0\x00-\x89\a\xf8\b\xe9)\x1el\x00\x00\u07d4\x82K<\x19)]~\xf6\xfa\xa7\xf3t\xa4y\x84\x86\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82Q5\x8c\xa4\xe0`\u0775Y\xcaX\xbc\v\u077e\xb4\a\x02\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82Q5\xb1\xa7\xfc\x16\x05aL\x8a\xa4\u042cm\xba\u040fH\x0e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\x82S\t\xa7\xd4]\x18\x12\xf5\x1en\x8d\xf5\xa7\xb9ol\x90\x88\x87\x89\x804\xf7\u0671f\xd4\x00\x00\u07d4\x82Z\u007fN\x10\x94\x9c\xb6\xf8\x96Bh\xf1\xfa_W\xe7\x12\xb4\u0109\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82a\xfa#\f\x90\x1dC\xffW\x9fG\x80\u04d9\xf3\x1e`v\xbc\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82b\x16\x9baXp\x13N\xb4\xacl_G\x1ck\xf2\xf7\x89\xfc\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4\x82c\xec\xe5\xd7\t\xe0\u05eeq\u0328h\xed7\xcd/\xef\x80{\x895\xab\x02\x8a\xc1T\xb8\x00\x00\xe0\x94\x82l\xe5y\x052\xe0T\x8ca\x02\xa3\r>\xac\x83k\xd68\x8f\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4\x82n\xb7\xcds\x19\xb8-\xd0z\x1f;@\x90q\xd9n9g\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x82u1\xa6\u0141z\xe3_\x82\xb0\v\x97T\xfc\xf7LU\xe22\x89\xc3(\t>a\xee@\x00\x00\u0794\x82u\xcdhL6y\u0548}\x03fN3\x83E\xdc<\xdd\xe1\x88\xdbD\xe0I\xbb,\x00\x00\u07d4\x82\x84\x92;b\u62ff|+\x9f4\x14\xd1>\xf6\xc8\x12\xa9\x04\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\x82\x8b\xa6Q\u02d3\x0e\xd9xqV)\x9a=\xe4L\u040br\x12\x89Hz\x9a0E9D\x00\x00\u07d4\x82\xa1\\\xef\x1dl\x82`\xea\xf1Y\xea?\x01\x80\xd8g}\xce\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xa8\xb9kl\x9e\x13\xeb\xec\x1e\x9f\x18\xac\x02\xa6\x0e\xa8\x8aH\xff\x89lk\x8c@\x8es\xb3\x00\x00\u07d4\x82\xa8\u02ff\xdf\xf0+.8\xaeK\xbf\xca\x15\xf1\xf0\xe8;\x1a\xea\x89\x04\x9b\x99\x1c'\xefm\x80\x00\u07d4\x82\xe4F\x1e\xb9\xd8I\xf0\x04\x1c\x14\x04!\x9eBr\u0110\n\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xe5w\xb5\x15\xcb+\b`\xaa\xfe\x1c\xe0\x9aY\xe0\x9f\xe7\xd0@\x89 \x86\xac5\x10R`\x00\x00\u07d4\x82\xea\x01\xe3\xbf.\x83\x83nqpN\"\xa2q\x93w\xef\xd9\u00c9\xa4\xccy\x95c\u00c0\x00\x00\u07d4\x82\xf2\xe9\x91\xfd2L_]\x17v\x8e\x9fa3]\xb61\x9dl\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x82\xf3\x9b'X\xaeB'{\x86\u059fu\xe6(\xd9X\xeb\u02b0\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\x82\xf8T\xc9\xc2\xf0\x87\xdf\xfa\x98Z\xc8 \x1ebl\xa5Fv\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x82\xffqo\xdf\x03>\xc7\xe9B\xc9\t\u0643\x18g\xb8\xb6\xe2\xef\x89a\t=|,m8\x00\x00\u07d4\x83\b\xed\n\xf7\xf8\xa3\xc1u\x1f\xaf\xc8w\xb5\xa4*\xf7\xd3X\x82\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x83\x1cD\xb3\b@G\x18K*\xd2\x18h\x06@\x907P\xc4]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x83!\x05\x83\xc1jN\x1e\x1d\xac\x84\xeb\xd3~=\x0f|W\ub909lk\x93[\x8b\xbd@\x00\x00\u07d4\x83,T\x17k\xdfC\xd2\u027c\u05f8\b\xb8\x95V\xb8\x9c\xbf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x833\x16\x98]Gt+\xfe\xd4\x10`J\x91\x95<\x05\xfb\x12\xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x834vK{9zNW\x8fP6M`\xceD\x89\x9b\xff\x94\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\xe0\x94\x83;j\x8e\xc8\xda@\x81\x86\xac\x8a}*m\xd6\x15#\xe7\u0384\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x83=?\xaeT*\xd5\xf8\xb5\f\xe1\x9b\xde+\xecW\x91\x80\u020c\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x83=\xb4,\x14\x16<{\xe4\u02b8j\u0153\xe0bf\u0599\u054a$\xe4\r+iC\xef\x90\x00\x00\xe0\x94\x83V;\xc3d\ud060\xc6\xda;V\xffI\xbb\xf2g\x82z\x9c\x8a\x03\xab\x91\xd1{ \xdeP\x00\x00\u07d4\x83zd]\xc9\\IT\x9f\x89\x9cN\x8b\u03c7S$\xb2\xf5|\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\x83\x8b\xd5e\xf9\x9f\xdeH\x05?y\x17\xfe3<\xf8J\xd5H\xab\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x83\x90\x8a\xa7G\x8am\x1c\x9b\x9b\x02\x81\x14\x8f\x8f\x9f$+\x9f\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x83\x92\xe57vq5x\x01[\xffI@\xcfC\x84\x9d}\u02e1\x89\bM\xf05]V\x17\x00\x00\xe0\x94\x83\x97\xa1\xbcG\xac\xd6GA\x81Y\xb9\x9c\xeaW\xe1\xe6S-n\x8a\x01\xf1\x0f\xa8'\xb5P\xb4\x00\x00\u07d4\x83\x98\xe0~\xbc\xb4\xf7_\xf2\x11m\xe7|\x1c*\x99\xf3\x03\xa4\u03c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xa3\x14\x883\xd9dI\x84\xf7\xc4u\xa7\x85\a\x16\ufd00\xff\x89\xb8Pz\x82\a( \x00\x00\u07d4\x83\xa4\x02C\x8e\x05\x19w=TH2k\xfba\xf8\xb2\f\xf5-\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x83\xa9;[\xa4\x1b\xf8\x87 \xe4\x15y\f\xdc\vg\xb4\xaf4\u0109\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x83\xc2=\x8aP!$\xee\x15\x0f\b\xd7\x1d\xc6rt\x10\xa0\xf9\x01\x8a\a3\x1f;\xfef\x1b\x18\x00\x00\u07d4\x83\u0217\xa8Ki^\xeb\xe4fy\xf7\xda\x19\xd7vb\x1c&\x94\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xd52\u04cdm\xee?`\xad\u018b\x93a3\u01e2\xa1\xb0\u0749\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xdb\xf8\xa1(S\xb4\n\xc6\x19\x96\xf8\xbf\x1d\xc8\xfd\xba\xdd\xd3)\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x83\xdb\xfd\x8e\xda\x01\xd0\u078e\x15\x8b\x16\u0413_\xc28\n]\u01c9 \x86\xac5\x10R`\x00\x00\u07d4\x83\xe4\x80U2|(\xb5\x93o\xd9\xf4D~s\xbd\xb2\xdd3v\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\x83\xfeZ\x1b2\x8b\xaeD\a\x11\xbe\xafj\xad`&\xed\xa6\xd2 \x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x84\x00\x8ar\xf8\x03o?\xeb\xa5B\xe3Px\xc0W\xf3*\x88%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84\x0e\xc8>\xa96!\xf04\xe7\xbb7b\xbb\x8e)\xde\xd4\xc4y\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\x84\x11E\xb4H@\xc9F\xe2\x1d\xbc\x19\x02d\xb8\xe0\xd5\x02\x93i\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4\x84#!\a\x93+\x12\xe01\x86X5%\xce\x02:p>\xf8\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\x84$O\xc9ZiW\xed|\x15\x04\xe4\x9f0\xb8\xc3^\xcaKy\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x841'}{\xdd\x10E}\xc0\x17@\x8c\x8d\xbb\xbdAJ\x8d\xf3\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4\x847Z\xfb\xf5\x9b:\x1da\xa1\xbe2\xd0u\xe0\xe1ZO\xbc\xa5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84;\xd3P/E\xf8\xbcM\xa3p\xb3#\xbd\xac?\xcf_\x19\xa6\x89P\x03\x9dc\xd1\x1c\x90\x00\x00\u07d4\x84P34c\rw\xf7AG\xf6\x8b.\bf\x13\xc8\xf1\xad\xe9\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x84R\x03u\x0fqH\xa9\xaa&)!\xe8mC\xbfd\x19t\xfd\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84a\xec\u0126\xa4^\xb1\xa5\xb9G\xfb\x86\xb8\x80i\xb9\x1f\xcdo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84g^\x91wrmE\xea\xa4k9\x92\xa3@\xba\u007fq\f\x95\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x84hl{\xadv,T\xb6g\u055f\x90\x94<\xd1M\x11z&\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\x89\xf6\xad\x1d\x9a\x94\xa2\x97x\x91V\x89\x9d\xb6AT\xf1\u06f5\x89\x13t\a\xc0<\x8c&\x80\x00\u07d4\x84\x8c\x99Jy\x00?\xe7\xb7\xc2l\xc62\x12\xe1\xfc/\x9c\x19\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x8f\xbd)\xd6|\xf4\xa0\x13\xcb\x02\xa4\xb1v\xef$N\x9e\u6349\x01\x17*ck\xbd\xc2\x00\x00\u07d4\x84\x94\x9d\xbaU\x9ac\xbf\xc8E\xde\xd0n\x9f-\x9b\u007f\x11\xef$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x9a\xb8\a\x90\xb2\x8f\xf1\xff\u05ba9N\xfctc\x10\\6\xf7\x89\x01\xe0+\xe4\xael\x84\x00\x00\u07d4\x84\x9b\x11oYc\x01\xc5\u063bb\xe0\xe9z\x82H\x12n9\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x84\xa7L\xee\xcf\xf6\\\xb9;/\x94\x9dw>\xf1\xad\u007f\xb4\xa2E\x89\x05\n\x9bDF\x85\xc7\x00\x00\u07d4\x84\xaa\xc7\xfa\x19\u007f\xf8\\0\xe0;zS\x82\xb9W\xf4\x1f:\xfb\x89\b\x8b#\xac\xff\u0650\x00\x00\u07d4\x84\xaf\x1b\x15sB\xd5Ch&\r\x17\x87b0\xa54\xb5K\x0e\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x84\xb0\xeek\xb87\u04e4\xc4\xc5\x01\x1c:\"\x8c\x0e\u06b4cJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb4\xb7Nf#\xba\x9d\x15\x83\xe0\u03feId?\x168AI\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb6\xb6\xad\xbe/[>-h,f\xaf\x1b\u0110S@\xc3\xed\x89!\x92\xf8\xd2\"\x15\x00\x80\x00\xe0\x94\x84\xb9\x1e.)\x02\xd0^+Y\x1bA\b;\u05fe\xb2\xd5,t\x8a\x02\x15\xe5\x12\x8bE\x04d\x80\x00\u07d4\x84\xbc\xbf\"\xc0\x96\a\xac\x844\x1d.\xdb\xc0;\xfb\x179\xd7D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x84\xbf\xce\xf0I\x1a\n\xe0iK7\u03ac\x02E\x84\xf2\xaa\x04g\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x84\xcb}\xa0P-\xf4\\\xf5a\x81{\xbd#b\xf4Q\xbe\x02\u0689Hz\x9a0E9D\x00\x00\u07d4\x84\xccxx\xda`_\xdb\x01\x9f\xab\x9bL\xcf\xc1Wp\x9c\u0765\x89Hy\x85\x13\xaf\x04\xc9\x00\x00\u07d4\x84\xdb\x14Y\xbb\x00\x81.\xa6~\xcb=\xc1\x89\xb7!\x87\xd9\xc5\x01\x89\b\x11\xb8\xfb\u0685\xab\x80\x00\u07d4\x84\u9516\x80\xbe\xcehA\xb9\xa7\xe5%\r\b\xac\xd8}\x16\u0349\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84\xe9\u03c1f\xc3j\xbf\xa4\x90S\xb7\xa1\xad@6 &\x81\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\xec\x06\xf2G\x00\xfeBAL\xb9\x89|\x15L\x88\xde/a2\x89Hz\x9a0E9D\x00\x00\xe0\x94\x84\xf5\"\xf0R\x0e\xbaR\xdd\x18\xad!\xfaK\x82\x9f+\x89\u02d7\x8a\x01\fQ\x06\xd5\x13O\x13\x00\x00\u07d4\x85\v\x9d\xb1\x8f\xf8K\xf0\xc7\xdaI\xea7\x81\xd9 \x90\xad~d\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x85\x10\xee\x93O\f\xbc\x90\x0e\x10\a\xeb8\xa2\x1e*Q\x01\xb8\xb2\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4\x85\x16\xfc\xafw\u0213\x97\x0f\xcd\x1a\x95\x8b\xa9\xa0\x0eI\x04@\x19\x89\n\xa3\xeb\x16\x91\xbc\xe5\x80\x00\u07d4\x85\x1a\xa9\x1c\x82\xf4/\xad]\xd8\xe8\xbb^\xa6\x9c\x8f:Yw\u0449\b\x0eV\x1f%xy\x80\x00\u07d4\x85\x1c\rb\xbeF5\xd4w~\x805\xe3~K\xa8Q|a2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x85\x1d\u00ca\xdbE\x93r\x9av\xf3:\x86\x16\u06b6\xf5\xf5\x9aw\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x852I\b\x97\xbb\xb4\u038b\u007fk\x83~L\xba\x84\x8f\xbe\x99v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x85>j\xba\xf4Di\xc7/\x15\x1dN\"8\x19\xac\xedN7(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85F\x91\xceqO2\\\xedU\xceY(\u039b\xa1/\xac\u0478\x89\xedp\xb5\xe9\xc3\xf2\xf0\x00\x00\u07d4\x85L\fF\x9c$k\x83\xb5\u0473\xec\xa4C\xb3\x9a\xf5\xee\x12\x8a\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x85]\x9a\xef,9\xc6#\r\t\u025e\xf6II\x89\xab\u61c5\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x85c\u0113a\xb6%\xe7hw\x1c\x96\x15\x1d\xbf\xbd\x1c\x90iv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85fa\t\x01\xaa\xce8\xb82D\xf3\xa9\xc810jg\xb9\u0709\xb0\x82\x13\xbc\xf8\xff\xe0\x00\x00\xe0\x94\x85j\xa2<\x82\xd7![\xec\x8dW\xf6\n\xd7^\xf1O\xa3_D\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x85nZ\xb3\xf6L\x9a\xb5k\x00\x93\x93\xb0\x16d\xfc\x03$\x05\x0e\x89a\t=|,m8\x00\x00\u07d4\x85n\xb2\x04$\x1a\x87\x83\x0f\xb2)\x03\x13C\xdc0\x85OX\x1a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x85s,\x06\\\xbdd\x11\x99A\xae\xd40\xacYg\vlQ\u0109'\xa5sb\xab\n\x0e\x80\x00\xe0\x94\x85x\xe1\x02\x12\xca\x14\xff\a2\xa8$\x1e7F}\xb8V2\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x85y\xda\xdf\x1a9Z4q\xe2\vov=\x9a\x0f\xf1\x9a?o\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x85\u007f\x10\v\x1aY0\"^\xfc~\x90 \u05c3'\xb4\x1c\x02\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x85\x94mV\xa4\xd3q\xa93hS\x96\x90\xb6\x0e\xc8%\x10tT\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94\x85\x99\xcb\u0566\xa9\xdc\u0539f\xbe8}iw]\xa5\xe3C'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86$_Yf\x91\t>\xce?=<\xa2&>\xac\xe8\x19A\u0649\n1\x06+\xee\xedp\x00\x00\u07d4\x86%i!\x1e\x8cc'\xb5A^:g\xe5s\x8b\x15\xba\xafn\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x86)}s\x0f\xe0\xf7\xa9\xee$\xe0\x8f\xb1\b{1\xad\xb3\x06\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86D\xcc(\x1b\xe32\xcc\xce\xd3m\xa4\x83\xfb*\aF\u067a.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86I\x9a\x12(\xff-~\xe3\au\x93dPo\x8e\x8c\x83\a\xa5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x86K\xecPi\xf8U\xa4\xfdX\x92\xa6\xc4I\x1d\xb0|\x88\xff|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86W\n\xb2Y\u0271\xc3,\x97) /w\xf5\x90\xc0}\xd6\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86c\xa2A\xa0\xa8\x9ep\xe1\x82\xc8E\xe2\x10\\\x8a\xd7&K\u03ca\x03#\xb1=\x83\x98\xf3#\x80\x00\u07d4\x86g\xfa\x11U\xfe\xd72\u03f8\u0725\xa0\xd7e\xce\r\a\x05\xed\x89\x04n\xc9e\u00d3\xb1\x00\x00\u07d4\x86h\xaf\x86\x8a\x1e\x98\x88_\x93\u007f&\x15\xde\xd6u\x18\x04\xeb-\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x86t\nFd\x8e\x84Z]\x96F\x1b\x18\t\x1f\xf5{\xe8\xa1o\x8a\x14\xc0\x974\x85\xbf9@\x00\x00\xe0\x94\x86~\xbaVt\x8aY\x045\r,\xa2\xa5\u039c\xa0\vg\n\x9b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x86\x80dt\xc3X\x04}\x94\x06\xe6\xa0\u007f@\x94[\xc82\x8eg\x8a\x01u.\xb0\xf7\x01=\x10\x00\x00\u07d4\x86\x88=T\xcd9\x15\xe5I\tU0\xf9\xab\x18\x05\xe8\xc5C-\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\x8c#\xbe\x874f\xd4\xc7L\"\n\x19\xb2E\xd1x~\x80\u007f\x89J\x13\xbb\xbd\x92\u020e\x80\x00\xe0\x94\x86\x92O\xb2\x11\xaa\xd2<\xf5\xce`\x0e\n\xae\x80c\x96D@\x87\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\x93\u9e3e\x94B^\xefyi\xbci\xf9\xd4/|\xadg\x1e\x8967\tlK\xcci\x00\x00\xe0\x94\x86\x9f\x1a\xa3\x0eDU\xbe\xb1\x82 \x91\xde\\\xad\xecy\xa8\xf9F\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x86\xa1\xea\xde\xeb0F\x13E\xd9\xefk\xd0R\x16\xfa$|\r\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xa5\xf8%\x9e\u0570\x9e\x18\x8c\xe3F\xee\x92\xd3J\xa5\u0753\xfa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xb7\xbdV<\uad86\xf9bD\xf9\xdd\xc0*\u05f0\xb1K\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\u008bVx\xaf7\xd7'\xec\x05\xe4Dw\x90\xf1_q\xf2\xea\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xc4\xce\x06\u066c\x18[\xb1H\xd9o{z\xbes\xf4A\x00m\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\xc8\xd0\u0642\xb59\xf4\x8f\x980\xf9\x89\x1f\x9d`z\x94&Y\x8a\x02\xce\xd3wa\x82O\xb0\x00\x00\u07d4\x86\xc94\xe3\x8eS\xbe;3\xf2t\xd0S\x9c\xfc\xa1Y\xa4\xd0\u04494\x95tD\xb8@\xe8\x00\x00\xe0\x94\x86\xca\x01E\x95~k\r\xfe6\x87_\xbez\r\xecU\xe1z(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\u02af\xac\xf3*\xa01|\x03*\xc3k\xab\xed\x97G\x91\xdc\x03\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x86\u0377\xe5\x1a\xc4Gr\xbe6\x90\xf6\x1d\x0eYvn\x8b\xfc\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\xdfs\xbd7\u007f,\t\xdec\xc4]g\xf2\x83\xea\xef\xa0\xf4\xab\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86\xe3\xfe\x86\xe9=\xa4\x86\xb1Bf\xea\xdf\x05l\xbf\xa4\xd9\x14C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xe8g\x0e'Y\x8e\xa0\x9c8\x99\xabw\x11\u04f9\xfe\x90\x1c\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xefd&!\x19I\xcc7\xf4\xc7^xP6\x9d\f\xf5\xf4y\x8a\x02\xd6_2\xea\x04Z\xf6\x00\x00\u07d4\x86\xf0]\x19\x06>\x93i\xc6\x00N\xb3\xf1#\x94:|\xffN\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x86\xf2>\x9c\n\xaf\u01cb\x9c@M\xcd`3\x9a\x92[\xff\xa2f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86\xf4\xf4\n\u0644\xfb\xb8\t3\xaebn\x0eB\xf93?\xddA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x86\xf9\\[\x11\xa2\x93\x94\x0e5\xc0\xb8\x98\u0637_\b\xaa\xb0m\x8a\x06D\xe3\xe8u\xfc\xcft\x00\x00\u07d4\x86\xff\xf2 \xe5\x93\x05\xc0\x9fH8`\xd6\xf9N\x96\xfb\xe3/W\x89\x02S[j\xb4\xc0B\x00\x00\u07d4\x87\a\x96\xab\xc0\u06c4\xaf\x82\xdaR\xa0\xedhsM\xe7\xe66\xf5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x87\x0f\x15\xe5\u07cb\x0e\xab\xd0%iSz\x8e\xf9;Vx\\B\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x87\x181`\xd1r\xd2\xe0\x84\xd3'\xb8k\xcb|\x1d\x8eg\x84\xef\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94\x87\x1b\x8a\x8bQ\u07a1\x98\x9aY!\xf1>\xc1\xa9U\xa5\x15\xadG\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x87%\xe8\xc7S\xb3\xac\xbf\u0725_I\x13\\3\x91\x99\x10`)\n\xa7\xf6\u0338\xf8Zx\u06c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x87Pa\xee\x12\xe8 \x04\x1a\x01\x94,\xb0\xe6[\xb4'\xb0\x00`\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x87XJ?a;\xd4\xfa\xc7L\x1ex\v\x86\xd6\xca\xeb\x89\f\xb2\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x87d\xd0'\"\x00\t\x96\xec\xd4u\xb43)\x8e\x9fT\v\x05\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x87l?!\x8bGv\xdf<\xa9\xdb\xfb'\r\xe1R\xd9N\xd2R\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x87u\xa6\x10\xc5\x02\xb9\xf1\xe6\xadL\xda\u06cc\xe2\x9b\xffu\xf6\xe4\x89 \x86\xac5\x10R`\x00\x00\u07d4\x87vN6w\xee\xf6\x04\xcb\u015a\xed$\xab\xdcVk\t\xfc%\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\x87\x87\xd1&w\xa5\xec)\x1eW\xe3\x1f\xfb\xfa\xd1\x05\xc32K\x87\x8a\x02\xa2N\xb52\b\xf3\x12\x80\x00\u07d4\x87\x94\xbfG\xd5E@\xec\xe5\xc7\"7\xa1\xff\xb5\x11\u0777Gb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x87\xa5>\xa3\x9fY\xa3[\xad\xa85%!dU\x94\xa1\xa7\x14\u02c9g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x87\xa7\xc5\b\xefqX-\u0665Cr\xf8\x9c\xb0\x1f%/\xb1\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x87\xaf%\xd3\xf6\xf8\xee\xa1S\x13\xd5\xfeEW\xe8\x10\xc5$\xc0\x83\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x87\xb1\x0f\x9c(\x00\x98\x17\x9a+v\xe9\u0390\xbea\xfc\x84M\r\x89Hz\x9a0E9D\x00\x00\u07d4\x87\xbf|\xd5\u0629)\xe1\u01c5\xf9\xe5D\x91\x06\xac#$c\u0249\x047\xb1\x1f\xccEd\x00\x00\u07d4\x87\u0118\x17\t4\xb8#=\x1a\xd1\xe7i1}\\G_/@\x897\b\xba\xed=h\x90\x00\x00\u07d4\x87\xcf6\xad\x03\xc9\xea\xe9\x05:\xbbRB\u0791\x17\xbb\x0f*\v\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x87\u05ec\x06S\xcc\xc6z\xa9\xc3F\x9e\xefCR\x19?}\xbb\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\x87\xe3\x06+#!\xe9\u07f0\x87\\\u311c\x9b.5\"\xd5\n\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x87\xe6\x03N\xcf#\xf8\xb5c\x9d_\x0e\xa7\n\"S\x8a\x92\x04#\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\x87\xefm\x8bj|\xbf\x9b\\\x8c\x97\xf6~\xe2\xad\u00a7;?w\x89\n\xdd\x1b\xd2<\x00L\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x88F\x92\x8dh2\x89\xa2\xd1\x1d\xf8\xdbz\x94t\x98\x8e\xf0\x13H\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x88I\x80\xebEe\xc1\x04\x83\x17\xa8\xf4\u007f\u06f4a\x96[\u4049\xd8\xd6\x11\x9a\x81F\x05\x00\x00\xe0\x94\x88Jz9\u0411n\x05\xf1\xc2B\xdfU`\u007f7\u07cc_\u068a\x04\xf4\x84<\x15|\x8c\xa0\x00\x00\u07d4\x88T\x93\xbd\xa3j\x042\x97eF\xc1\xdd\xceq\xc3\xf4W\x00!\x89\v\xbfQ\r\xdf\xcb&\x00\x00\xe0\x94\x88`\x9e\nF[n\x99\xfc\xe9\a\x16mW\xe9\xda\b\x14\xf5\u020a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88m\n\x9e\x17\xc9\xc0\x95\xaf.\xa25\x8b\x89\xecpR\x12\ue509\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x88y~Xg^\xd5\xccL\x19\x98\a\x83\xdb\xd0\xc9V\bQS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88|\xacA\xcdpo3E\xf2\xd3J\xc3N\x01u*nY\t\x89 F\\\ue7617\x00\x00\u07d4\x88\x88\x8aW\xbd\x96\x87\xcb\xf9P\xae\xea\u03d7@\xdc\xc4\xd1\xefY\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u0794\x88\x89D\x83\x16\xcc\xf1N\xd8m\xf8\xe2\xf4x\xdcc\xc43\x83@\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x88\x8c\x16\x14I3\x19|\xac&PM\xd7n\x06\xfdf\x00\u01c9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x88\x8e\x94\x91p\x83\xd1R +S\x1699\x86\x9d'\x11u\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\x90\x87\xf6o\xf2\x84\xf8\xb5\xef\xbd)I;pg3\xab\x14G\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\x88\x95\xebrb&\xed\xc3\xf7\x8c\u01a5\x15\a{2\x96\xfd\xb9^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x88\x97Z_\x1e\xf2R\x8c0\v\x83\xc0\xc6\a\xb8\xe8}\u0593\x15\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x88\x9d\xa4\x0f\xb1\xb6\x0f\x9e\xa9\xbdzE>XL\xf7\xb1\xb4\xd9\xf7\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x88\x9d\xa6b\xebJ\n*\x06\x9d+\xc2K\x05\xb4\xee.\x92\xc4\x1b\x89Z,\x8cTV\xc9\xf2\x80\x00\u07d4\x88\xa1\"\xa28,R91\xfbQ\xa0\u032d;\xeb[rY\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xa2\x15D0\xc0\xe4\x11G\xd3\xc1\xfe\u3cf0\x06\xf8Q\xed\xbd\x8965f3\xeb\xd8\xea\x00\x00\u07d4\x88\xb2\x17\u0337\x86\xa2T\xcfM\xc5\u007f]\x9a\xc3\xc4U\xa3\x04\x83\x892$\xf4'#\xd4T\x00\x00\xe0\x94\x88\xbcC\x01.\xdb\x0e\xa9\xf0b\xacCxC%\n9\xb7\x8f\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88\xc2Qj|\xdb\t\xa6'mr\x97\xd3\x0fZM\xb1\xe8K\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\xc3ad\rki7;\b\x1c\xe0\xc43\xbdY\x02\x87\xd5\xec\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x88\xd5A\xc8@\xceC\xce\xfb\xafm\x19\xafk\x98Y\xb5s\xc1E\x89\t79SM(h\x00\x00\u07d4\x88\xde\x13\xb0\x991\x87|\x91\rY1e\xc3d\u0221d\x1b\u04c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x88\xde\u017d?N\xba-\x18\xb8\xaa\xce\xfa{r\x15H\xc3\x19\xba\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\x88\xe6\xf9\xb2G\xf9\x88\xf6\xc0\xfc\x14\xc5o\x1d\xe5>\u019dC\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x88\xee\u007f\x0e\xfc\x8fw\x8ckh~\xc3+\xe9\xe7\xd6\xf0 \xb6t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xf1\x04_\x19\xf2\xd3\x19\x18\x16\xb1\xdf\x18\xbbn\x145\xad\x1b8\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x89\x00\x9e\a\xe3\xfahc\xa7x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89Wr~r\xcfb\x90 \xf4\xe0^\xdfy\x9a\xa7E\x80b\u0409wC\"\x17\xe6\x83`\x00\x00\u07d4\x89]iN\x88\v\x13\xcc\u0404\x8a\x86\xc5\xceA\x1f\x88Gk\xbf\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x89^\xc5TVD\u0dc30\xff\xfa\xb8\xdd\xea\xc9\xe83\x15l\x89 \x86\xac5\x10R`\x00\x00\u07d4\x89`\tRj,{\f\t\xa6\xf6:\x80\xbd\U0009d707\u079c\x89\xbb\xb8k\x82#\xed\xeb\x00\x00\u07d4\x89g\u05f9\xbd\xb7\xb4\xae\xd2.e\xa1]\xc8\x03\xcbz!?\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x89n3\\\xa4z\xf5yb\xfa\x0fM\xbf>E\xe6\x88\u02e5\x84\x89J/\xc0\xab`R\x12\x00\x00\u07d4\x89s\xae\xfd^\xfa\xee\x96\t]\x9e(\x8fj\x04l\x977KC\x89\a\xa4\u0120\xf32\x14\x00\x00\u07d4\x89\x8cr\xddseX\xef\x9eK\xe9\xfd\xc3O\xefT\xd7\xfc~\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\x9b<$\x9f\fK\x81\xdfu\xd2\x12\x00M=m\x95/\xd2#\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x89\xab\x13\xee&mw\x9c5\xe8\xbb\x04\u034a\x90\xcc!\x03\xa9[\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x89\xc43\xd6\x01\xfa\xd7\x14\xdaci0\x8f\xd2l\x1d\u0254+\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89\xd7[\x8e\b1\xe4o\x80\xbc\x17A\x88\x18N\x00o\xde\x0e\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\u3d5a\x15\x86G7\u0513\xc1\xd2<\xc5=\xbf\x8d\xcb\x13b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x89\xfc\x8eM8k\r\v\xb4\xa7\a\xed\xf3\xbdV\r\xf1\xad\x8fN\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x89\xfe\xe3\r\x17(\xd9l\xec\xc1\u06b3\xda.w\x1a\xfb\u03eaA\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8a\x1c\u016c\x11\x1cI\xbf\xcf\xd8H\xf3}\xd7h\xaae\u0208\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x8a \xe5\xb5\xce\xe7\xcd\x1fU\x15\xba\xce;\xf4\xf7\u007f\xfd\xe5\xcc\a\x89\x04V9\x18$O@\x00\x00\xe0\x94\x8a!}\xb3\x8b\xc3_!_\xd9)\x06\xbeBCo\xe7\xe6\xed\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x8a$:\n\x9f\xeaI\xb89TwE\xff-\x11\xaf?K\x05\"\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x8a$}\x18e\x10\x80\x9fq\xcf\xfcEYG\x1c9\x10\x85\x81!\x89a\t=|,m8\x00\x00\u07d4\x8a4p(-^**\xef\u05e7P\x94\xc8\"\xc4\xf5\xae\uf289\r(\xbc`dx\xa5\x80\x00\u07d4\x8a6\x86\x9a\xd4x\x99|\xbfm\x89$\xd2\n<\x80\x18\xe9\x85[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8aC\x14\xfba\u0353\x8f\xc3>\x15\xe8\x16\xb1\x13\U000ac267\xfb\x89\x17vNz\xede\x10\x00\x00\u07d4\x8aOJ\u007fR\xa3U\xba\x10_\xca r\xd3\x06_\xc8\xf7\x94K\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8aX1(,\xe1Jezs\r\xc1\x88&\xf7\xf9\xb9\x9d\xb9h\x89\uaf8a[A\xc16\x00\x00\u07d4\x8a_\xb7W\x93\xd0C\xf1\xbc\xd48\x85\xe07\xbd0\xa5(\xc9'\x89\x13Snm.\x9a\xc2\x00\x00\u07d4\x8af\xab\xbc-0\xce!\xa83\xb0\u06ceV\x1dQ\x05\xe0\xa7,\x89%\xf1\xde\\v\xac\xdf\x00\x00\u07d4\x8atl]g\x06G\x11\xbf\xcah[\x95\xa4\xfe)\x1a'\x02\x8e\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8ax\n\xb8z\x91E\xfe\x10\xed`\xfaGjt\n\xf4\u02b1\u0489\x12\x1b.^ddx\x00\x00\u07d4\x8az\x06\xbe\x19\x9a:X\x01\x9d\x84j\xc9\xcb\xd4\xd9]\xd7W\u0789\xa2\xa4#\x94BV\xf4\x00\x00\u07d4\x8a\x81\x01\x14\xb2\x02]\xb9\xfb\xb5\x00\x99\xa6\xe0\u02de.\xfak\u0709g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8a\x86\xe4\xa5\x1c\x01;\x1f\xb4\xc7k\xcf0f|x\xd5.\xed\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\x9e\u029cZ\xba\x8e\x13\x9f\x80\x03\xed\xf1\x16:\xfbp\xaa:\xa9\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\x8a\xb89\xae\xaf*\xd3|\xb7\x8b\xac\xbb\xb63\xbc\xc5\xc0\x99\xdcF\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\u021b\u06780\x1ek\x06w\xfa%\xfc\xf0\xf5\x8f\f\u01f6\x11\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x8a\xdcS\xef\x8c\x18\xed0Qx]\x88\xe9\x96\xf3\xe4\xb2\x0e\xcdQ\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\u07d4\x8a\xe6\xf8\vp\xe1\xf2<\x91\xfb\u0569f\xb0\xe4\x99\xd9]\xf82\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x8a\xe9\uf30a\x8a\u07e6\xaby\x8a\xb2\xcd\xc4\x05\b*\x1b\xbbp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\xf6&\xa5\xf3'\xd7Pe\x89\xee\xb7\x01\x0f\xf9\xc9D` \u0489K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\x8b\x01\xda4\xd4p\xc1\xd1\x15\xac\xf4\xd8\x11\xe1\x01\xdb\x1e\x14\xec\xc7\xd3\"\xc7+\x8c\x04s\x89\x18\xb2j1>\x8a\xe9\x00\x00\xe0\x94\x8bH\xe1\x9d9\xdd5\xb6nn\x1b\xb6\xb9\xc6W\xcb,\xf5\x9d\x04\x8a\x03\xc7U\xac\x9c\x02J\x01\x80\x00\xe0\x94\x8bP^(q\xf7\u07b7\xa68\x95 \x8e\x82'\u072a\x1b\xff\x05\x8a\f\xf6\x8e\xfc0\x8dy\xbc\x00\x00\u07d4\x8bW\xb2\xbc\x83\u030dM\xe31 N\x89?/;\x1d\xb1\a\x9a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8b\\\x91K\x12\x8b\xf1i\\\b\x89#\xfaF~y\x11\xf3Q\xfa\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\x8b_)\xcc/\xaa&,\xde\xf3\x0e\xf5T\xf5\x0e\xb4\x88\x14n\xac\x8a\x01;hp\\\x97 \x81\x00\x00\u07d4\x8bpV\xf6\xab\xf3\xb1\x18\xd0&\xe9D\xd5\xc0sC<\xa4Q\u05c965\xc6 G9\u0640\x00\u07d4\x8bqE\"\xfa(9b\x04p\xed\xcf\fD\x01\xb7\x13f=\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8bt\xa7\xcb\x1b\xb8\u014f\xce&tf\xa3\x03X\xad\xafR\u007fa\x8a\x02\xe2WxN%\xb4P\x00\x00\u07d4\x8b~\x9fo\x05\xf7\xe3dv\xa1n>q\x00\xc9\x03\x1c\xf4\x04\xaf\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8b\x81\x15ni\x869\x94<\x01\xa7Rr\xad=5\x85\x1a\xb2\x82\x89\x12\xb3\x16_e\xd3\xe5\x00\x00\u07d4\x8b\x95w\x92\x00S\xb1\xa0\x01\x890M\x88\x80\x10\xd9\xef,\xb4\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8b\x98A\x86.w\xfb\xbe\x91\x94p\x93U\x83\xa9<\xf0'\xe4P\x89llS4B\u007f\x1f\x00\x00\u07d4\x8b\x99}\xbc\a\x8a\xd0)a5]\xa0\xa1Y\xf2\x92~\xd4=d\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8b\x9f\xda}\x98\x1f\xe9\xd6B\x87\xf8\\\x94\xd8?\x90t\x84\x9f\u030a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x8b\xb0!/2\x95\xe0)\u02b1\xd9a\xb0A3\xa1\x80\x9e{\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8b\xbe\xac\xfc)\xcf\xe94\x02\xdb\xd6j\x1a\xcbvv\x85c7\xb9;\xf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8b\xf3s\xd0v\x81L\xbcW\xe1\xc6\xd1j\x82\u017e\x13\xc7=7\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8c\x10#\xfd\xe1WM\xb8\xbbT\xf1s\x96p\x15|\xa4}\xa6R\x8a\x01y\u03da\u00e1\xb1w\x00\x00\u07d4\x8c\x1f\xbe_\n\xea5\x9cZ\xa1\xfa\b\u0209T\x12\u028e\x05\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\"B`U\xb7o\x11\xf0\xa2\xde\x1a\u007f\x81\x9aa\x96\x85\xfe`\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4\x8c+}\x8b`\x8d(\xb7\u007f\\\xaa\x9c\xd6E$*\x82>L\u0649b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x8c/\xbe\ue3ac\xc5\xc5\xd7|\x16\xab\xd4b\ue701E\xf3K\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8c:\x9e\xe7\x1fr\x9f#l\xba8g\xb4\u05dd\x8c\xee\xe2]\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8cP\xaa*\x92\x12\xbc\xdeVA\x8a\xe2a\xf0\xb3^z\x9d\xbb\x82\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8cT\xc7\xf8\xb9\x89nu\xd7\xd5\xf5\xc7`%\x86\x99\x95qB\xad\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8c]\x16\xede\xe3\xed~\x8b\x96\u0297+\xc8as\xe3P\v\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8cj\xa8\x82\xee2,\xa8HW\x8c\x06\xcb\x0f\xa9\x11\xd3`\x83\x05\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\x8cj\xe7\xa0Z\x1d\xe5u\x82\xae'h Bv\xc0\xffG\xed\x03\x8a,\v\xb3\xdd0\xc4\xe2\x00\x00\x00\u07d4\x8co\x9fN[z\xe2v\xbfXI{\u05ff*}%$_d\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4\x8cu\x95n\x8f\xedP\xf5\xa7\xdd|\xfd'\xda \x0fgF\xae\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c|\xb4\xe4\x8b%\x03\x1a\xa1\xc4\xf9)%\xd61\xa8\xc3\xed\xc7a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\u007f\xa5\xca\xe8/\xed\xb6\x9a\xb1\x89\xd3\xff'\xae \x92\x93\xfb\x93\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\xe0\x94\x8c\x81A\x0e\xa85L\xc5\xc6\\A\xbe\x8b\xd5\xdes<\v\x11\x1d\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x8c\x83\xd4$\xa3\xcf$\xd5\x1f\x01\x92=\xd5J\x18\u05b6\xfe\xde{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8c\x90\n\x826\xb0\x8c+e@]9\xd7_ \x06*ua\xfd\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\x8c\x93\xc3\xc6\u06dd7q}\xe1e\u00e1\xb4\xfeQ\x95,\b\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8c\x99\x95\x91\xfdr\xefq\x11\xef\xcaz\x9e\x97\xa25k;\x00\n\x89\xddd\xe2\xaa\ngP\x00\x00\u07d4\x8c\xa6\x98\x97F\xb0n2\xe2Hta\xb1\u0399j':\xcf\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8c\xb3\xaa?\xcd!(T\xd7W\x8f\xcc0\xfd\xed\xe6t*1*\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x8c\xc0\xd7\xc0\x16\xfaz\xa9P\x11J\xa1\xdb\tH\x82\xed\xa2t\xea\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x8c\xc6R\xdd\x13\xe7\xfe\x14\u06bb\xb3m]2\r\xb9\xff\xee\x8aT\x89a\t=|,m8\x00\x00\u07d4\x8c\u02bf%\a\u007f:\xa4\x15E4MS\xbe\x1b+\x9c3\x90\x00\x89[\xe8f\xc5b\xc5D\x00\x00\u07d4\x8c\xcf:\xa2\x1a\xb7BWj\xd8\xc4\"\xf7\x1b\xb1\x88Y\x1d\ua28965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\xd0\xcd\"\xe6 \xed\xa7\x9c\x04a\xe8\x96\xc9\xd1b)\x12K_z\xfb\xec\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x8c\xe2/\x9f\xa3rD\x9aB\x06\x10\xb4z\xe0\xc8\xd5eH\x122\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x8c\u451d\x8a\x16T-B<\x17\x98Ng9\xfar\u03b1w\x8a\x05K@Y&\xf4\xa6=\x80\x00\u07d4\x8c\xe5\xe3\xb5\xf5\x91\xd5\uc8ca\xbf\"\x8f.<5\x13K\xda\xc0\x89}\xc3[\x84\x89|8\x00\x00\xe0\x94\x8c\xee8\xd6YW\x88\xa5n?\xb9F4\xb3\xff\xe1\xfb\xdb&\u058a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8c\xee\xa1^\xec;\xda\xd8\x02?\x98\xec\xf2[+\x8f\xef'\xdb)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8c\xf3To\xd1\u0363=X\x84_\xc8\xfc\xfe\u02bc\xa7\xc5d*\x89\x1f\x1e9\x93,\xb3'\x80\x00\u07d4\x8c\xf6\xda\x02\x04\xdb\u0106\vF\xad\x97?\xc1\x11\x00\x8d\x9e\fF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x8c\xfe\xde\xf1\x98\xdb\n\x91C\xf0\x91)\xb3\xfdd\u073b\x9bIV\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x04\xa5\xeb\xfb]\xb4\t\xdb\x06\x17\xc9\xfaV1\xc1\x92\x86\x1fJ\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x8d\x06\xe4d$\\\xadaI9\xe0\xaf\bE\xe6\xd70\xe2\x03t\x89\n\u070a(\xf3\xd8}\x80\x00\u07d4\x8d\a\xd4-\x83\x1c-|\x83\x8a\xa1\x87+:\xd5\xd2w\x17h#\x89\x12\xee\x1f\x9d\xdb\xeeh\x00\x00\u07d4\x8d\v\x9e\xa5?\xd2cA^\xac\x119\x1f|\xe9\x12V\xb9\xfb\x06`\xf6\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8dy\\_JV\x89\xadb\u0696\x16q\xf0(\x06R\x86\xd5T\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x8d\u007f>a)\x9c-\xb9\xb9\xc0H|\xf6'Q\x9e\xd0\n\x91#\x89^t\xa8P^\x80\xa0\x00\x00\xe0\x94\x8d\x89\x17\v\x92\xb2\xbe,\b\xd5|H\xa7\xb1\x90\xa2\xf1Fr\x0f\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x8d\x93\xda\u01c5\xf8\x8f\x1a\x84\xbf\x92}Se+E\xa1T\xcc\u0749\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x8d\x99R\u043bN\xbf\xa0\xef\xd0\x1a:\xa9\xe8\xe8\u007f\x05%t.\x89\xbb\x91%T\"c\x90\x00\x00\u07d4\x8d\x9a\fp\xd2& B\xdf\x10\x17\xd6\xc3\x03\x13 $w'\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x9e\xd7\xf4U0X\xc2ox6\xa3\x80-0d\xeb\x1b6=\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\x8d\xa1\x17\x8fU\xd9wr\xbb\x1d$\x11\x1a@JO\x87\x15\xb9]\x89/\x9a\xc3\xf6\xde\x00\x80\x80\x00\u07d4\x8d\xa1\xd3Y\xbal\xb4\xbc\xc5}zCw \xd5]\xb2\xf0\x1cr\x89\x04V9\x18$O@\x00\x00\u07d4\x8d\xab\x94\x8a\xe8\x1d\xa3\x01\xd9r\xe3\xf6\x17\xa9\x12\xe5\xa7Sq.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8d\xad\xdfR\xef\xbdt\u0695\xb9i\xa5GoO\xbb\xb5c\xbf\u0489-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x8d\xb1\x85\xfe\x1bp\xa9Jj\b\x0e~#\xa8\xbe\xdcJ\xcb\xf3K\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x8d\xb5\x8e@n -\xf9\xbcpl\xb43\xe1\x94\xf4\x0f\x82\xb4\x0f\xaa\xdb\x1f\x8b\x85a\x16\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8d\xc1\xd5\x11\x1d\t\xaf%\xfd\xfc\xacE\\|\xec(>mgu\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\u0504\xff\x8a0sd\xebf\xc5%\xa5q\xaa\xc7\x01\xc5\xc3\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\u05a9\xba\xe5\u007fQ\x85I\xad\xa6wFo\ua2b0O\u0674\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde<\xb8\x11\x85h\xefE\x03\xfe\x99\x8c\xcd\xf56\xbf\x19\xa0\x98\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde`\xeb\b\xa0\x99\xd7\u06a3V\u06aa\xb2G\r{\x02Zk\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8d\xf39!Kj\u0472Fc\xceq`4t\x9dn\xf88\u064a\x02TO\xaaw\x80\x90\xe0\x00\x00\xe0\x94\x8d\xf5=\x96\x19\x14q\xe0Y\xdeQ\xc7\x18\xb9\x83\xe4\xa5\x1d*\xfd\x8a\x06\u01b95\xb8\xbb\xd4\x00\x00\x00\u07d4\x8d\xfb\xaf\xbc\x0e[\\\x86\xcd\x1a\u0597\xfe\xea\x04\xf41\x88\u0796\x89\x15%+\u007f_\xa0\xde\x00\x00\u07d4\x8e\a;\xad%\xe4\"\x18a_J\x0ek.\xa8\xf8\xde\"0\xc0\x89\x82=b\x9d\x02k\xfa\x00\x00\u07d4\x8e\x0f\xee8hZ\x94\xaa\xbc\xd7\u0385{k\x14\t\x82Ou\xb8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e#\xfa\xcd\x12\xc7e\xc3j\xb8\x1am\xd3M\x8a\xa9\xe6\x89\x18\xae\x89\t\x11\u418d\xba\x9b\x00\x00\xe0\x94\x8e/\x904\xc9%G\x19\u00ceP\u026ad0^\u0596\xdf\x1e\x8a\x01\x00N.E\xfb~\xe0\x00\x00\u07d4\x8e2@\xb0\x81\x0e\x1c\xf4\a\xa5\x00\x80G@\u03cdad2\xa4\x89\x02/fU\xef\v8\x80\x00\u07d4\x8eHj\x04B\xd1q\xc8`[\xe3H\xfe\xe5~\xb5\b^\xff\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8eaV3k\xe2\u037e2\x14\r\xf0\x8a+\xa5_\u0425\x84c\x89\x04\t\x9e\x1dcW\x18\x00\x00\u07d4\x8eg\b\x15\xfbg\xae\xae\xa5{\x86SN\xdc\x00\xcd\xf5d\xfe\u5272\xe4\xb3#\xd9\xc5\x10\x00\x00\u07d4\x8emt\x85\xcb\u942c\xc1\xad\x0e\xe9\xe8\xcc\xf3\x9c\f\x93D\x0e\x893\xc5I\x901r\f\x00\x00\xe0\x94\x8et\xe0\u0477~\xbc\x82:\xca\x03\xf1\x19\x85L\xb1 '\xf6\u05ca\x16\xb3R\xda^\x0e\xd3\x00\x00\x00\u07d4\x8ex\xf3QE}\x01oJ\xd2u^\xc7BN\\!\xbamQ\x89\a\xea(2uw\b\x00\x00\u07d4\x8ey6\u0552\x00\x8f\xdcz\xa0N\xde\xebuZ\xb5\x13\u06f8\x9d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\u007f\xd28H\xf4\xdb\a\x90j}\x10\xc0K!\x80;\xb0\x82'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8e\x92\xab\xa3\x8er\xa0\x98\x17\v\x92\x95\x92FSz.UV\xc0\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x8e\x98ve$\xb0\xcf'G\xc5\r\xd4;\x95gYM\x971\u0789lD\xb7\xc2a\x82(\x00\x00\u07d4\x8e\x9b5\xadJ\n\x86\xf7XDo\xff\xde4&\x9d\x94\f\xea\u0349\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8e\x9c\b\xf78f\x1f\x96v#n\xff\x82\xbaba\xdd?H\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\x9cB\x92f\xdf\x05~\xfax\xdd\x1d_w\xfc@t*\xd4f\x89\x10D.\u0475l|\x80\x00\u07d4\x8e\xa6V\xe7\x1e\xc6Q\xbf\xa1|ZWY\xd8`1\xcc5\x99w\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\xae)CU\x98\xba\x8f\x1c\x93B\x8c\xdb>+M1\a\x8e\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb1\xfb\xe4\xe5\xd3\x01\x9c\xd7\xd3\r\xae\x9c\r[Lv\xfbc1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb5\x17t\xaf k\x96k\x89\t\xc4Z\xa6r'H\x80,\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xb8\xc7\x19\x82\xa0\x0f\xb8Bu)2S\xf8\x04ED\xb6kI\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x8e\xcb\u03ec\xbf\xaf\xe9\xf0\f9\"\xa2N,\xf0\x02gV\xca \x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4\x8e\u03b2\xe1$Sl[_\xfcd\x0e\xd1O\xf1^\u0668\xcbq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\u042f\x11\xff(p\xda\x06\x81\x00J\xfe\x18\xb0\x13\xf7\xbd8\x82\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x8e\xd1Cp\x1f/r(\x0f\xd0J{Ad(\x19y\xea\x87\u0248\xc2I\xfd\xd3'x\x00\x00\u07d4\x8e\xd1R\x8bD~\xd4)y\x02\xf69\xc5\x14\u0414J\x88\xf8\u0209\n\xc6\xe7z\xb6c\xa8\x00\x00\u07d4\x8e\xd4(L\x0fGD\x9c\x15\xb8\u0673$]\u8fb6\u0380\xbf\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x8e\xde~=\xc5\aI\xc6\xc5\x0e.(\x16\x84x\xc3M\xb8\x19F\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x8e\xe5\x843}\xdb\xc8\x0f\x9e4\x98\xdfU\xf0\xa2\x1e\xac\xb5\u007f\xb1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\xeb\xec\x1ab\xc0\x8b\x05\xa7\xd1\u0551\x80\xaf\x9f\xf0\u044e?6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xf4\u0622\xc2o\xf7\x14\xb6u\x89\x19\x80\x1c\x83\xb6\xc7\xc0\x00\x00\u07d4\x8fM\x1dAi>F,\xf9\x82\xfd\x81\u042ap\x1d:St\u0249\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fM\x1e~Ea(J4\xfe\xf9g<\r4\xe1*\xf4\xaa\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8fO\xb1\xae\xa7\xcd\x0fW\x0e\xa5\xe6\x1b@\xa4\xf4Q\vbd\xe4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fV\x1bA\xb2\t\xf2H\u0229\x9f\x85\x87\x887bP`\x9c\xf3\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\x8fX\xd84\x8f\xc1\xdcN\r\xd84;eC\xc8W\x04^\xe9@\x8a\x02\xe3\x03\x8d\xf4s\x03(\x00\x00\u07d4\x8f`\x89_\xbe\xbb\xb5\x01\u007f\xcb\xff<\u0763\x97)+\xf2[\xa6\x89\x17D\x06\xff\x9fo\u0480\x00\u07d4\x8fd\xb9\xc1$m\x85x1d1\a\xd3U\xb5\xc7_\xef]O\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8ff\x0f\x8b.L|\u00b4\xac\x9cG\xed(P\x8d_\x8f\x86P\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8fi\xea\xfd\x023\xca\xdb@Y\xabw\x9cF\xed\xf2\xa0PnH\x89`\xf0f \xa8IE\x00\x00\xe0\x94\x8fq~\xc1U/LD\x00\x84\xfb\xa1\x15J\x81\xdc\x00>\xbd\xc0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x8f\x8a\xcb\x10v\a8\x84y\xf6K\xaa\xab\xea\x8f\xf0\a\xad\xa9}\x8a\x05\xc6\xf3\b\n\xd4#\xf4\x00\x00\u07d4\x8f\x8c\xd2n\x82\xe7\xc6\xde\xfd\x02\u07ed\a\x97\x90!\xcb\xf7\x15\f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x8f\x8f7\u042d\x8f3]*q\x01\xb4\x11V\xb6\x88\xa8\x1a\x9c\xbe\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\x8f\x92\x84O(*\x92\x99\x9e\u5d28\xd7s\xd0kiM\xbd\x9f\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8f\xact\x8fxJ\x0f\xedh\u06e43\x19\xb4*u\xb4d\x9cn\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x8f\u0665\xc3:}\x9e\xdc\xe0\x99{\xdfw\xab0d$\xa1\x1e\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xef\xfa\xdb8z\x15G\xfb(M\xa9\xb8\x14\u007f>|m\xc6\u0689-b{\xe4S\x05\b\x00\x00\u07d4\x8f\xf4`Ehw#\xdc3\xe4\u0419\xa0i\x04\xf1\ubd44\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xfa\x06!\"\xac0t\x18\x82\x1a\u06d3\x11\aZ7\x03\xbf\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8f\xfe2)\x97\xb8\xe4\x04B-\x19\xc5J\xad\xb1\x8f[\xc8\u9dc9\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x90\x01\x94\u0131\aC\x05\u045d\xe4\x05\xb0\xacx(\x0e\xca\xf9g\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90\x03\xd2p\x89\x1b\xa2\xdfd=\xa84\x15\x83\x195E\xe3\xe0\x00\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x90\x05z\xf9\xaaf0~\xc9\xf03\xb2\x97$\u04f2\xf4\x1e\xb6\xf9\x8a\x19\xd1\u05aa\xdb,R\xe8\x00\x00\u07d4\x90\x0f\v\x8e5\xb6h\xf8\x1e\xf2R\xb18U\xaaP\a\xd0\x12\xe7\x89\x17\n\x0fP@\xe5\x04\x00\x00\u07d4\x90\x18\xcc\x1fH\xd20\x8e%*\xb6\b\x9f\xb9\x9a|\x1dV\x94\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x90\x1d\x99\xb6\x99\xe5\u0191\x15\x19\xcb v\xb4\xc7c0\xc5M\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x90-t\xa1W\xf7\u04b9\xa37\x8b\x1fVp70\xe0:\x17\x19\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x904\x13\x87\x8a\xea;\xc1\bc\t\xa3\xfev\x8beU\x9e\x8c\xab\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x90If\xcc\"\x13\xb5\xb8\xcb[\xd6\b\x9e\xf9\xcd\xdb\xef~\xdf\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x90L\xaaB\x9ca\x9d\x94\x0f\x8egA\x82j\r\xb6\x92\xb1\x97(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90R\xf2\xe4\xa3\xe3\xc1-\xd1\xc7\x1b\xf7\x8aN\xc3\x04=\u020b~\x89\x0e~\xeb\xa3A\vt\x00\x00\u0794\x90U&V\x8a\xc1#\xaf\xc0\xe8J\xa7\x15\x12O\xeb\xe8=\xc8|\x88\xf8i\x93)g~\x00\x00\u07d4\x90\x92\x91\x87\a\xc6!\xfd\xbd\x1d\x90\xfb\x80\xebx\u007f\xd2osP\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4\x90\x9b^v:9\xdc\u01d5\"=s\xa1\u06f7\xd9L\xa7Z\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x90\xac\xce\xd7\xe4\x8c\b\u01b94dm\xfa\n\xdf)\u0714\aO\x89\x03\vK\x15{\xbdI\x00\x00\u07d4\x90\xb1\xf3p\xf9\xc1\xeb\v\xe0\xfb\x8e+\x8a\xd9jAcq\u074a\x890\xca\x02O\x98{\x90\x00\x00\u07d4\x90\xb6/\x13\x1a_)\xb4UqQ>\xe7\xa7J\x8f\v#\"\x02\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x90\xbdb\xa0P\x84Ra\xfaJ\x9f|\xf2A\xeac\v\x05\ufe09\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x90\xc4\x1e\xba\x00\x8e \xcb\xe9'\xf3F`?\u0206\x98\x12Yi\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x90\u0480\x9a\xe1\xd1\xff\xd8\xf6>\xda\x01\xdeI\xddU-\xf3\u047c\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x90\xdc\t\xf7\x17\xfc*[i\xfd`\xba\b\xeb\xf4\v\xf4\xe8$l\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x90\xe3\x00\xacqE\x1e@\x1f\x88\u007fnw(\x85\x16G\xa8\x0e\a\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x90\xe3Z\xab\xb2\xde\xef@\x8b\xb9\xb5\xac\xefqDW\xdf\xdebr\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\x90\xe7\a\x0fM\x03?\xe6\x91\f\x9e\xfeZ'\x8e\x1f\xc6#M\xef\x89\x05q8\b\x19\xb3\x04\x00\x00\u07d4\x90\xe9>M\xc1q!HyR36\x14\x00+\xe4#VI\x8e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x90\u9a68.\u06a8\x14\u0084\xd22\xb6\u9e90p\x1dIR\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x90\xf7t\xc9\x14}\u0790\x85=\xdcC\xf0\x8f\x16\xd4U\x17\x8b\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x90\xfcS{!\x06Xf\n\x83\xba\xa9\xacJ\x84\x02\xf6WF\xa8\x89e\xea=\xb7UF`\x00\x00\u07d4\x91\x05\n\\\xff\xad\xed\xb4\xbbn\xaa\xfb\xc9\xe5\x014(\xe9l\x80\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x91\x05\x17d\xafk\x80\x8eB\x12\xc7~0\xa5W.\xaa1pp\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x91\v}Wz~9\xaa#\xac\xf6*\xd7\xf1\xef4)4\xb9h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x91\x0e\x99eC4Lh\x15\xfb\x97\u0367\xafK\x86\x98vZ[\x89\x05\x9a\xf6\x98)\xcfd\x00\x00\u07d4\x91\x1f\xee\xa6\x1f\xe0\xedP\u0179\xe5\xa0\xd6`q9\x9d(\xbd\u0189\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x91\x1f\xf23\xe1\xa2\x11\xc0\x17,\x92\xb4l\xf9\x97\x03\x05\x82\xc8:\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x91 \xe7\x11s\xe1\xba\x19\xba\x8f\x9fO\xdb\u072a4\xe1\u05bbx\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91!\x17\x12q\x9f+\bM;8u\xa8Pi\xf4f61A\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91#\x04\x11\x8b\x80G=\x9e\x9f\xe3\xeeE\x8f\xbea\x0f\xfd\xa2\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x91Tky\xec\xf6\x9f\x93kZV\x15\b\xb0\xd7\xe5\f\u0159/\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x91V\u0440)5\x0eG\x04\b\xf1_\x1a\xa3\xbe\x9f\x04\ng\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x91b\x0f>\xb3\x04\xe8\x13\u048b\x02\x97Ume\xdcN]\u5a89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\x91k\xf7\xe3\xc5E\x92\x1d2\x06\xd9\x00\xc2O\x14\x12|\xbd^p\x8a\x03\xd0\u077c}\xf2\xbb\x10\x00\x00\u0794\x91l\xf1}qA(\x05\xf4\xaf\xc3DJ\v\x8d\xd1\xd93\x9d\x16\x88\xc6s\xce<@\x16\x00\x00\u07d4\x91{\x8f\x9f:\x8d\t\xe9 ,R\u009erA\x96\xb8\x97\xd3^\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x91\x89g\x91\x8c\u0617\xdd\x00\x05\xe3m\xc6\u0203\xefC\x8f\xc8\u01c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x91\x89\x8e\xab\x8c\x05\xc0\"(\x83\xcdM\xb2;w\x95\xe1\xa2J\u05c9lk\x93[\x8b\xbd@\x00\x00\u0794\x91\x91\xf9F\x98!\x05\x16\xcfc!\xa1B\a\x0e Yvt\xed\x88\xee\x9d[\xe6\xfc\x11\x00\x00\u07d4\x91\xa4\x14\x9a,{\x1b:g\xea(\xaf\xf3G%\u0fcdu$\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x91\xa7\x87\xbcQ\x96\xf3HW\xfe\f7/M\xf3v\xaa\xa7f\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xa8\xba\xae\xd0\x12\xea.c\x80;Y=\r\f*\xabL[\n\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x91\xac\\\xfeg\xc5J\xa7\xeb\xfb\xa4HflF\x1a;\x1f\xe2\xe1\x89\x15\xc94\x92\xbf\x9d\xfc\x00\x00\u07d4\x91\xbb?y\x02+\xf3\xc4S\xf4\xff%n&\x9b\x15\xcf,\x9c\xbd\x89RX\\\x13\xfe:\\\x00\x00\u07d4\x91\xc7^<\xb4\xaa\x89\xf3F\x19\xa1d\xe2\xa4x\x98\xf5gM\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xc8\f\xaa\b\x1b85\x1d*\x0e\x0e\x00\xf8\n4\xe5dt\xc1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91\xccF\xaa7\x9f\x85jf@\xdc\xcdZd\x8ay\x02\xf8I\u0649\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x91\u04a9\xee\x1am\xb2\x0fS\x17\u0327\xfb\xe218\x95\u06ce\xf8\x8a\x01\xcc\u00e5/0n(\x00\x00\u07d4\x91\xd6n\xa6(\x8f\xaaK=`l*\xa4\\{k\x8a%'9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\u06f6\xaa\xad\x14\x95\x85\xbeG7\\]m\xe5\xff\t\x19\x15\x18\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x91\xe8\x81\x06R\xe8\xe6\x16\x15%\xd6;\xb7u\x1d\xc2\x0fg`v\x89'Mej\xc9\x0e4\x00\x00\u07d4\x91\xf5\x16\x14l\xda (\x17\x19\x97\x80`\u01beAI\x06|\x88\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\xf6$\xb2J\x1f\xa5\xa0V\xfeW\x12)\xe77\x9d\xb1K\x9a\x1e\x8a\x02\x8a\x85\x17\xc6i\xb3W\x00\x00\xe0\x94\x91\xfe\x8aLad\u07cf\xa6\x06\x99]k\xa7\xad\xca\xf1\u0213\u038a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4\x92\x1fRa\xf4\xf6\x12v\a\x06\x89&%\xc7^{\u0396\xb7\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92!\xc9\xce\x01#&et\x10\x96\xac\a#Y\x03\xad\x1f\xe2\xfc\x89\x06\xdbc3U\"b\x80\x00\u07d4\x92%\x988`\xa1\xcbF#\xc7$\x80\xac\x16'+\f\x95\xe5\xf5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x92%\xd4jZ\x80\x949$\xa3\x9e[\x84\xb9m\xa0\xacE\x05\x81\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x92* \u01da\x1d:&\xdd8)g{\xf1\xd4\\\x8fg+\xb6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x92C\x8eR\x03\xb64o\xf8\x86\xd7\xc3b\x88\xaa\xcc\xccx\xce\u028965\u026d\xc5\u07a0\x00\x00\u07d4\x92C\xd7v-w({\x12c\x86\x88\xb9\x85N\x88\xa7i\xb2q\x8965\u026d\xc5\u07a0\x00\x00\u0794\x92K\xcez\x85<\x97\v\xb5\xec{\xb7Y\xba\xeb\x9ct\x10\x85{\x88\xbe -j\x0e\xda\x00\x00\u07d4\x92N\xfam\xb5\x95\xb7\x93\x13'~\x881\x96%\akX\n\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92U\x82&\xb3\x84bl\xadH\xe0\x9d\x96k\xf19^\xe7\xea]\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\x92`\x82\xcb~\xedK\x19\x93\xad$ZGrg\xe1\xc3<\xd5h\x89\x14Jt\xba\u07e4\xb6\x00\x00\u07d4\x92b\t\xb7\xfd\xa5N\x8d\u06dd\x9eM=\x19\xeb\u070e\x88\u009f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92h\xd6&FV6\x11\xdc;\x83*0\xaa#\x94\xc6F\x13\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92i\x8e4Sx\xc6-\x8e\xda\x18M\x946j\x14K\f\x10[\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x92y:\u0173rhwJq0\xde+\xbd3\x04\x05f\x17s\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94\x92y\xb2\"\x8c\xec\x8f{M\xda?2\x0e\x9a\x04f\xc2\xf5\x85\u028a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x92|\xb7\xdc\x18p6\xb5B{\xc7\xe2\x00\xc5\xecE\f\x1d'\u0509\v\xb5\x9a'\x95<`\x00\x00\u07d4\x92|\u00bf\xda\x0e\b\x8d\x02\xef\xf7\v8\xb0\x8a\xa5<\xc3\tA\x89do`\xa1\xf9\x866\x00\x00\xe0\x94\x92\x84\xf9m\xdbG\xb5\x18n\xe5X\xaa12M\xf56\x1c\x0fs\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x92\x9d6\x8e\xb4j-\x1f\xbd\xc8\xff\xa0`~\xdeK\xa8\x8fY\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa7\u0166Cb\xe9\xf8B\xa2=\xec\xa2\x105\x85\u007f\x88\x98\x00\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x92\xa8\x98\xd4o\x19q\x9c8\x12j\x8a<'\x86z\xe2\xce\u5589lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa9q\xa79y\x9f\x8c\xb4\x8e\xa8G]r\xb2\xd2GAr\xe6\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x92\xaa\xe5\x97h\xed\xdf\xf8<\xfe`\xbbQ.s\n\x05\xa1a\u05c9\\\x97xA\fv\u0440\x00\u07d4\x92\xad\x1b=u\xfb\xa6}Tf=\xa9\xfc\x84\x8a\x8a\xde\x10\xfag\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xae[|~\xb4\x92\xff\x1f\xfa\x16\xddB\xad\x9c\xad@\xb7\xf8\u0709.\xe4IU\b\x98\xe4\x00\x00\u07d4\x92\xc0\xf5s\xec\xcfb\xc5H\x10\xeek\xa8\xd1\xf1\x13T+0\x1b\x89\xb7ro\x16\u0331\xe0\x00\x00\u07d4\x92\xc1?\xe0\xd6\u0387\xfdP\xe0=\uf7e6@\x05\t\xbdps\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x92\xc9L( \xdf\xcfqV\xe6\xf10\x88\xec\u754b6v\xfd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\x92\xcf\xd6\x01\x88\xef\u07f2\xf8\xc2\xe7\xb1i\x8a\xbb\x95&\xc1Q\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\u062d\x9aMah;\x80\u0526g.\x84\xc2\rbB\x1e\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x92\u0725\xe1\x02\xb3\xb8\x1b`\xf1\xa5\x04cIG\xc3t\xa8\x8c\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xe454\x0e\x9d%<\x00%c\x89\xf5+\x06}U\x97Nv\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x92\xe49(\x16\xe5\xf2\xef_\xb6X7\xce\xc2\xc22\\\xc6I\"\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x92\xe6X\x1e\x1d\xa1\xf9\xb8F\xe0\x93G3=\xc8\x18\xe2\u04acf\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\x93\x1d\xf3M\x12%\xbc\xd4\"Nch\r\\L\t\xbc\xe75\xa6\x89\x03\xaf\xb0\x87\xb8v\x90\x00\x00\u07d4\x93\x1f\xe7\x12\xf6B\a\xa2\xfdP\"r\x88CT\x8b\xfb\x8c\xbb\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x93#_4\r(c\xe1\x8d/LR\x99e\x16\x13\x8d\"\x02g\x89\x04\x00.D\xfd\xa7\xd4\x00\x00\u07d4\x93%\x82U\xb3|\u007fX\xf4\xb1\x06s\xa92\xdd:\xfd\x90\xf4\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93(\xd5\\\xcb?\xceS\x1f\x19\x93\x823\x9f\x0eWn\xe8@\xa3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x93)\xff\xdc&\x8b\xab\u0788t\xb3f@l\x81D[\x9b-5\x89\x16\xe6/\x8cs\f\xa1\x80\x00\u07d4\x93+\x9c\x04\xd4\r*\xc80\x83\xd9B\x98\x16\x9d\xae\x81\xab.\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4\x9346\xc8G&U\xf6L:\xfa\xaf|Lb\x1c\x83\xa6+8\x8965\u026d\xc5\u07a0\x00\x00\u0794\x93;\xf3?\x82\x99p+:\x90&B\xc3>\v\xfa\xea\\\x1c\xa3\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x93@4\\\xa6\xa3\uaf77sc\xf2X`C\xf2\x948\xce\v\x89\x1c\xc8\x05\xda\r\xff\xf1\x00\x00\xe0\x94\x93@\xb5\xf6x\xe4^\xe0^\xb7\b\xbbz\xbbn\xc8\xf0\x8f\x1bk\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x93J\xf2\x1b~\xbf\xa4g\xe2\xce\xd6Z\xa3N\xdd:\x0e\xc7\x132\x8a\a\x80\x1f>\x80\xcc\x0f\xf0\x00\x00\xe0\x94\x93PiDJj\x98M\xe2\bNFi*\xb9\x9fg\x1f\xc7'\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x93P~\x9e\x81\x19\xcb\xce\u068a\xb0\x87\xe7\xec\xb0q8=i\x81\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x93g\x8a\x00\x00\xe0\x94\x93m\xcf\x00\x01\x94\xe3\xbf\xf5\n\u0174$:;\xa0\x14\xd6a\u060a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x93o8\x13\xf5\xf6\xa1;\x8eO\xfe\xc8?\xe7\xf8&\x18jq\u0349\x1c0s\x1c\xec\x03 \x00\x00\u07d4\x93t\x86\x9dJ\x99\x11\xee\x1e\xafU\x8b\xc4\u00b6>\xc6:\xcf\u074965\u026d\xc5\u07a0\x00\x00\u07d4\x93uc\u0628\x0f\u05657\xb0\xe6m \xa0%%\xd5\u0606`\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\x93v\xdc\xe2\xaf.\xc8\xdc\xdat\x1b~sEfF\x81\xd96h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93\x86\x8d\xdb*yM\x02\xeb\xda/\xa4\x80|v\xe3`\x98X\u0709m\xee\x15\xfc|$\xa7\x80\x00\xe0\x94\x93\x9cC\x13\xd2(\x0e\xdf^\a\x1b\xce\xd8F\x06?\n\x97]T\x8a\x19i6\x89t\xc0[\x00\x00\x00\xe0\x94\x93\xa6\xb3\xabB0\x10\xf9\x81\xa7H\x9dJ\xad%\xe2b\\WA\x8a\x04F\x80\xfej\x1e\xdeN\x80\x00\u07d4\x93\xaa\x8f\x92\xeb\xff\xf9\x91\xfc\x05^\x90ne\x1a\xc7h\xd3+\u02092\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x93\xb4\xbf?\xdf\xf6\xde?NV\xbamw\x99\xdcK\x93\xa6T\x8f\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\x93\xbc}\x9aJ\xbdD\u023b\xb8\xfe\x8b\xa8\x04\xc6\x1a\xd8\xd6Wl\x89\xd8\xd6\x11\x9a\x81F\x05\x00\x00\u07d4\x93\xc2\xe6N]\xe5X\x9e\xd2P\x06\xe8C\x19n\xe9\xb1\xcf\v>\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x93\u020e-\x88b\x1e0\xf5\x8a\x95\x86\xbe\xd4\t\x89\x99\xebg\u074a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4\x93\xe0\xf3~\xcd\xfb\x00\x86\xe3\xe8b\xa9p4D{\x1eM\xec\x1a\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\x93\xe3\x03A\x1a\xfa\xf6\xc1\a\xa4A\x01\u026c[6\xe9\xd6S\x8b\x8a\r\xf9\xdd\xfe\xcd\x03e@\x00\x00\u07d4\x93\xf1\x8c\xd2R`@v\x14\x88\xc5\x13\x17M\x1eycv\x8b,\x89\x82\xff\xac\x9a\u0553r\x00\x00\u07d4\x94\x0fqQ@P\x9f\xfa\xbf\x97EF\xfa\xb3\x90\"\xa4\x19R\u0489K\xe4\xe7&{j\xe0\x00\x00\u07d4\x94,k\x8c\x95[\xc0\u0608\x12g\x8a#g%\xb3'9\xd9G\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x94=7\x86JJS}5\xc8\u0657#\xcdd\x06\xce%b\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94C\x9c\xa9\xcc\x16\x9ay\u0520\x9c\xae^gvJo\x87\x1a!\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x94D\x9c\x01\xb3*\u007f\xa5Z\xf8\x10OB\xcd\xd8D\xaa\x8c\xbc@\x8a\x03\x81\x11\xa1\xf4\xf0<\x10\x00\x00\xe0\x94\x94E\xba\\0\xe9\x89a\xb8`$a\xd08]@\xfb\xd8\x03\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94O\a\xb9o\x90\xc5\xf0\xd7\xc0\u0140S1I\xf3\xf5\x85\xa0x\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\x94T\xb3\xa8\xbf\xf9p\x9f\xd0\u1407~l\xb6\u0219t\xdb\u0589\x90\xf54`\x8ar\x88\x00\x00\u07d4\x94]\x96\xeaW>\x8d\xf7&+\xbf\xa5r\"\x9bK\x16\x01k\x0f\x89\vX\x9e\xf9\x14\xc1B\x00\x00\u07d4\x94^\x18v\x9d~\xe7'\xc7\x01?\x92\xde$\xd1\x17\x96\u007f\xf3\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94a'\x81\x03;W\xb1F\xeet\xe7S\xc6r\x01\u007fS\x85\xe4\x89\xc3(\t>a\xee@\x00\x00\xe0\x94\x94dJ\xd1\x16\xa4\x1c\xe2\xca\u007f\xbe\xc6\t\xbd\xefs\x8a*\xc7\u01ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x94p\xcc6YE\x86\x82\x18!\xc5\u0256\xb6\xed\xc8;mZ2\x89\x01M\x11 \u05f1`\x00\x00\xe0\x94\x94u\xc5\x10\xec\x9a&\x97\x92GtL=\x8c;\x0e\v_D\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94~\x11\xe5\xea)\ro\u00f3\x80H\x97\x9e\f\xd4N\xc7\xc1\u007f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\x83\u064f\x14\xa3?\xdc\x11\x8d@9U\u00995\xed\xfc_p\x89\x18\xea;4\xefQ\x88\x00\x00\u07d4\x94\x911\xf2\x89C\x92\\\xfc\x97\xd4\x1e\f\xea\v&)s\xa70\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x94\x9f\x84\xf0\xb1\xd7\u0127\xcfI\xee\u007f\x8b,J\x13M\xe3(x\x89%\"H\u07b6\xe6\x94\x00\x00\u07d4\x94\x9f\x8c\x10{\xc7\xf0\xac\xea\xa0\xf1pR\xaa\xdb\xd2\xf9s+.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\xa7\u0368\xf4\x81\xf9\u061dB\xc3\x03\xae\x162\xb3\xb7\t\xdb\x1d\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x94\xa9\xa7\x16\x911| d'\x1bQ\xc95?\xbd\xed5\x01\xa8\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x94\xadK\xad\x82K\xd0\ub7a4\x9cX\u03bc\xc0\xff^\b4k\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x94\xbb\xc6}\x13\xf8\x9e\xbc\xa5\x94\xbe\x94\xbcQp\x92\f0\xd9\xf3\x89\x04X\xff\xa3\x15\nT\x00\x00\u07d4\x94\xbe:\xe5Ob\xd6c\xb0\xd4\u031e\x1e\xa8\xfe\x95V\ua7bf\x89\x01C\x13,\xa8C\x18\x00\x00\xe0\x94\x94\xc0U\xe8X5z\xaa0\xcf A\xfa\x90Y\xce\x16J\x1f\x91\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\xe0\x94\x94\xc7B\xfdz\x8by\x06\xb3\xbf\xe4\xf8\x90O\xc0\xbe\\v\x803\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x94\xcaV\xdew\u007f\xd4S\x17\u007f^\x06\x94\xc4x\xe6j\xff\x8a\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x94\xd8\x10t\xdbZ\xe1\x97\u04bb\x13s\xab\x80\xa8}\x12\x1cK\u04ca\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x94\u06c0xs\x86\n\xac=Z\xea\x1e\x88^R\xbf\xf2\x86\x99T\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4\x94\xe1\xf5\u02db\x8a\xba\xce\x03\xa1\xa6B\x82VU;i\f#U\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x94\xef\x8b\xe4Pw\xc7\xd4\xc5e'@\u0794jbbOq?\x89\x05l\xf5Y:\x18\xf8\x80\x00\u07d4\x94\xf1?\x9f\b6\xa3\xee$7\xa8I\"\u0498M\xc0\xf7\xd5;\x89\xa2\xa02\x9b\u00ca\xbe\x00\x00\u07d4\x94\xf8\xf0W\xdb~`\xe6u\xad\x94\x0f\x15X\x85\u0464w4\x8e\x89\x15\xbeat\xe1\x91.\x00\x00\xe0\x94\x94\xfc\u03ad\xfe\\\x10\x9c^\xae\xafF-C\x871B\u020e\"\x8a\x01\x045a\xa8\x82\x93\x00\x00\x00\u07d4\x95\x03N\x16!\x86Q7\xcdG9\xb3F\xdc\x17\xda:'\xc3N\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\x95\fh\xa4\t\x88\x15M#\x93\xff\xf8\xda|\u0369\x96\x14\xf7,\x89\xf9AF\xfd\x8d\xcd\xe5\x80\x00\xe0\x94\x95\x0f\xe9\xc6\xca\xd5\f\x18\xf1\x1a\x9e\xd9\xc4W@\xa6\x18\x06\x12\u040a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x95!\x83\xcf\u04ce5.W\x9d6\xde\xce\u0171\x84P\xf7\xfb\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95'\x8b\b\xde\xe7\xc0\xf2\xc8\xc0\xf7\"\xf9\xfc\xbb\xb9\xa5$\x1f\u0689\x82\x93\t\xf6O\r\xb0\x00\x00\u07d4\x95,W\xd2\xfb\x19Q\a\xd4\xcd\\\xa3\x00wA\x19\u07ed/x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x955r\xf0\xeam\xf9\xb1\x97\xca\xe4\x0eK\x8e\xcc\x05lCq\u014965\u026d\xc5\u07a0\x00\x00\u07d4\x95>\xf6R\xe7\xb7i\xf5=nxjX\x95/\xa9>\xe6\xab\u725b\ny\x1f\x12\x110\x00\x00\u07d4\x95DpF1;/:^\x19\xb9H\xfd;\x8b\xed\xc8,q|\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x95]\xb3\xb7C`\xb9\xa2hg~s\u03a8!f\x8a\xf6\xfa\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\x95`\xe8\xacg\x18\xa6\xa1\xcd\xcf\xf1\x89\xd6\x03\xc9\x06>A=\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x95g\xa0\u0781\x1d\xe6\xff\t[~\xe6N\u007f\x1b\x83\xc2a[\x80\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x95h\x1c\xda\xe6\x9b I\xce\x10\x1e2\\u\x98\x92\xca\xc3\xf8\x11\x89\x9a\xe9*\x9b\xc9L@\x00\x00\xe0\x94\x95h\xb7\xdeuV(\xaf5\x9a\x84T=\xe25\x04\xe1^A\xe6\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x95i\xc6:\x92\x84\xa8\x05bm\xb3\xa3.\x9d#c\x93GaQ\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\x80\x9e\x8d\xa3\xfb\xe4\xb7\xf2\x81\xf0\xb8\xb1q_B\x0f}}c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\x9fW\xfd\xedj\xe3y\x13\xd9\x00\xb8\x1e_H\xa7\x93\"\xc6'\x89\r\xdb&\x10GI\x11\x80\x00\u07d4\x95\x9f\xf1\u007f\x1dQ\xb4s\xb4@\x10\x05'U\xa7\xfa\x8cu\xbdT\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\xa5w\xdc.\xb3\xael\xb9\xdf\xc7z\xf6\x97\xd7\xef\xdf\xe8\x9a\x01\x89\a_a\x0fp\xed \x00\x00\u07d4\x95\xcbm\x8acy\xf9J\xba\x8b\x88ViV,MD\x8eV\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\xd5PB{ZQLu\x1ds\xa0\xf6\u049f\xb6]\"\xed\x10\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x95\u064d\f\x10i\x90\x8f\x06zR\xac\xac+\x8bSM\xa3z\xfd\x89oY\xb60\xa9)p\x80\x00\xe0\x94\x95\xdfN4E\xd7f&$\u010e\xbat\u03de\nS\xe9\xf72\x8a\v\xdb\xc4\x1e\x03H\xb3\x00\x00\x00\u07d4\x95\xe6\xa5K-_g\xa2JHu\xafu\x10|\xa7\xea\x9f\xd2\xfa\x89Hz\x9a0E9D\x00\x00\xe0\x94\x95\xe6\xf9=\xac\"\x8b\xc7XZ%sZ\xc2\xd0v\xcc:@\x17\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x95\xe7ad$\xcd\ta\xa7\x17'$t7\xf0\x06\x92r(\x0e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x95\xe8\n\x82\xc2\f\xbe= `$,\xb9-sX\x10\xd04\xa2\x89\x01\xc3.F?\u0539\x80\x00\u07d4\x95\xf6-\x02C\xed\xe6\x1d\xad\x9a1e\xf59\x05'\rT\xe2B\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x95\xfbZ\xfb\x14\xc1\uf6b7\xd1y\xc5\xc3\x00P?\xd6j^\xe2\x89\x01\xda\xf7\xa0+\r\xbe\x80\x00\u07d4\x96\x10Y\"\x02\u0082\xab\x9b\u0628\x84Q\x8b>\v\xd4u\x817\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x96\x1cY\xad\xc7E\x05\u0446M\x1e\xcf\u02ca\xfa\x04\x12Y<\x93\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x96,\r\xec\x8a=FK\xf3\x9b\x12\x15\xea\xfd&H\n\xe4\x90\u0349l\x82\xe3\xea\xa5\x13\xe8\x00\x00\u07d4\x96,\xd2*\x8e\xdf\x1eONU\xb4\xb1]\xdb\xfb]\x9dT\x19q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x963K\xfe\x04\xff\xfaY\x02\x13\xea\xb3e\x14\xf38\xb8d\xb76\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x967\xdc\x12r=\x9cxX\x85B\uac02fO?\x03\x8d\x9d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96N\xabK'kL\u0618>\x15\xcar\xb1\x06\x90\x0f\xe4\x1f\u0389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96b\xee\x02\x19&h+1\xc5\xf2\x00\xceEz\xbe\xa7ll\xe9\x89$Y\x0e\x85\x89\xebj\x00\x00\xe0\x94\x96l\x04x\x1c\xb5\xe6}\xde25\xd7\xf8b\x0e\x1a\xb6c\xa9\xa5\x8a\x10\r P\xdacQ`\x00\x00\u07d4\x96pv\xa8w\xb1\x8e\xc1ZA[\xb1\x16\xf0n\xf3&E\u06e3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96{\xfa\xf7bC\u0379@\t\xae<\x8d5\x05\xe9\xc0\x80EK\xe0\xe8\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x96\x92A\x91\xb7\xdfe[3\x19\xdcma7\xf4\x81\xa7:\x0f\xf3\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\x96\x96\x05!83\x8cr/\x11@\x81\\\xf7t\x9d\r;:t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96\xa5_\x00\xdf\xf4\x05\xdcM\xe5\xe5\x8cW\xf6\xf6\xf0\xca\xc5]/\x89jf\x167\x9c\x87\xb5\x80\x00\u07d4\x96\xaaW?\xed/#4\x10\u06eeQ\x80\x14[#\xc3\x1a\x02\xf0\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x96\xadW\x9b\xbf\xa8\u06ce\xbe\xc9\u0486\xa7.Fa\xee\xd8\xe3V\x89:\v\xa4+\xeca\x83\x00\x00\u07d4\x96\xb44\xfe\x06W\xe4*\u0302\x12\xb6\x86Q9\xde\xde\x15\x97\x9c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xb9\x06\xear\x9fFU\xaf\xe3\xe5}5'|\x96}\xfa\x15w\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96\xd6-\xfdF\b\u007fb@\x9d\x93\xdd`a\x88\xe7\x0e8\x12W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xd9\u0328\xf5^\xea\x00@\xecn\xb3H\xa1wK\x95\xd9>\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xe7\xc0\xc9\u057f\x10\x82\x1b\xf1@\xc5X\xa1E\xb7\xca\xc2\x13\x97\x899>\xf1\xa5\x12|\x80\x00\x00\u07d4\x96\xeaj\u021a+\xac\x954{Q\u06e6=\x8b\xd5\xeb\xde\xdc\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xea\xfb\xf2\xfboM\xb9\xa46\xa7LE\xb5eDR\xe28\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x96\xebR>\x83/P\n\x01}\xe1>\xc2\u007f]6lV\x0e\xff\x89\x10\xac\u03baC\xee(\x00\x00\u07d4\x96\xf0F*\xe6\xf8\xb9`\x88\xf7\xe9\u018ct\xb9\u062d4\xb3G\x89a\t=|,m8\x00\x00\u07d4\x96\xf8 P\vp\xf4\xa3\xe3#\x9da\x9c\xff\x8f\" u\xb15\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x96\xfeY\xc3\u06f3\xaa|\xc8\xcbbH\fe\xe5nb\x04\xa7\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x96\xffoP\x99h\xf3l\xb4,\xbaH\xdb2\xf2\x1fVv\xab\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x97\t8R*\xfb^\x8f\x99Hs\xc9\xfb\xdc&\xe3\xb3~1L\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\n\xbdS\xa5O\xcaJd) |\x18-MW\xbb9\u0520\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\r\x8b\x8a\x00\x16\xd1C\x05O\x14\x9f\xb3\xb8\xe5P\xdc\a\x97\u01c965\u026d\xc5\u07a0\x00\x00\u07d4\x97,/\x96\xaa\x00\u03ca/ Z\xbc\xf8\x93|\fu\xf5\xd8\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97?N6\x1f\xe5\xde\u0358\x9dL\x8f}|\xc9y\x908]\xaf\x89\x15\x0f\x85C\xa3\x87B\x00\x00\u07d4\x97M\x05A\xabJG\xec\u007fu6\x9c\x00i\xb6J\x1b\x81w\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\x97M/\x17\x89_)\x02\x04\x9d\xea\xae\xcf\t\xc3\x04e\a@-\x88\xcc\x19\u00947\xab\x80\x00\u07d4\x97R\xd1O^\x10\x93\xf0qq\x1c\x1a\xdb\xc4\xe3\xeb\x1e\\W\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97V\xe1v\xc9\xefi>\xe1\xee\u01b9\xf8\xb1Q\xd3\x13\xbe\xb0\x99\x89A\rXj \xa4\xc0\x00\x00\u07d4\x97_7d\xe9{\xbc\xcfv|\xbd;y[\xa8m\x8b\xa9\x84\x0e\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x97j\x18Sj\xf4\x18tBc\b\x87\x1b\xcd\x15\x12\xa7u\xc9\xf8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97n<\xea\xf3\xf1\xafQ\xf8\u009a\xff]\u007f\xa2\x1f\x03\x86\xd8\xee\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x97w\xcca\xcfuk\xe3\xb3\xc2\f\xd4I\x1ci\xd2u\xe7\xa1 \x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97\x81\v\xaf\xc3~\x840c2\xaa\xcb5\xe9*\xd9\x11\xd2=$\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\x8cC\f\xe45\x9b\x06\xbc,\xdf\\)\x85\xfc\x95\x0eP\xd5\u0209\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\x97\x95\xf6C\x19\xfc\x17\xdd\x0f\x82a\xf9\xd2\x06\xfbf\xb6L\xd0\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\x99\xca!\xdb\xcfi\xbf\xa1\xb3\xf7+\xacQ\xb9\xe3\xcaX|\xf9\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x97\x9c\xbf!\xdf\xec\x8a\xce?\x1c\x19m\x82\u07d6%4\xdf9O\x89\x99\x91\xd4x\xddM\x16\x00\x00\u07d4\x97\x9dh\x1ca}\xa1o!\xbc\xac\xa1\x01\xed\x16\xed\x01Z\xb6\x96\x89e\xea=\xb7UF`\x00\x00\u07d4\x97\x9f0\x15\x8bWK\x99\x9a\xab4\x81\a\xb9\xee\xd8[\x1f\xf8\xc1\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x97\xa8o\x01\xce?|\xfdDA3\x0e\x1c\x9b\x19\xe1\xb1\x06\x06\xef\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x97\xb9\x1e\xfesP\xc2\xd5~~@k\xab\x18\xf3a{\xcd\xe1J\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\x97\xd0\xd9r^;p\xe6u\x841s\x93\x8e\xd3q\xb6,\u007f\xac\x89\t79SM(h\x00\x00\u07d4\x97\xd9\xe4jv\x04\u05f5\xa4\xeaN\xe6\x1aB\xb3\xd25\x0f\xc3\xed\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\xdc&\xecg\n1\xe0\"\x1d*u\xbc]\xc9\xf9\f\x1fo\u0509\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x97\xde!\xe4!\xc3\u007f\xe4\xb8\x02_\x9aQ\xb7\xb3\x90\xb5\xdfx\x04\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\x97\xe2\x89s\xb8`\xc5g@(\x00\xfb\xb6<\xe3\x9a\x04\x8a=y\x89\x05B%:\x12l\xe4\x00\x00\u07d4\x97\xe5\xcca'\xc4\xf8\x85\xbe\x02\xf4KB\xd1\u0230\xac\x91\u44c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\xf1\xfeL\x80\x83\xe5\x96!*\x18w(\xdd\\\xf8\n1\xbe\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x97\xf7v\x06W\xc1\xe2\x02u\x90\x86\x96>\xb4!\x1c_\x819\xb9\x8a\n\x8a\t\u007f\xcb=\x17h\x00\x00\xe0\x94\x97\xf9\x9bk\xa3\x13F\u0358\xa9\xfeL0\x8f\x87\u0165\x8cQQ\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x98\n\x84\xb6\x86\xfc1\xbd\xc8<\"\x10XTjq\xb1\x1f\x83\x8a\x89*AUH\xaf\x86\x81\x80\x00\u07d4\x98\x10\xe3J\x94\xdbn\xd1V\xd08\x9a\x0e+\x80\xf4\xfdk\n\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\x1d\xdf\x04\x04\xe4\xd2-\xdaUj\a&\xf0\v-\x98\xab\x95i\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94\x98\x1fq'u\xc0\xda\xd9u\x18\xff\xed\xcbG\xb9\xad\x1dl'b\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x984h!\x80\xb9\x82\xd1f\xba\u06dd\x9d\x1d\x9b\xbf\x01m\x87\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x986\xb4\xd3\x04sd\x1a\xb5j\xee\xe1\x92Bv\x1drrQx\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x989sB\xec_=L\xb8w\xe5N\xf5\xd6\xf1\xd3fs\x1b\u050a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\x98Fd\x886\xa3\a\xa0W\x18O\xd5\x1fb\x8a_\x8c\x12B|\x8a\x04\vi\xbfC\xdc\xe8\xf0\x00\x00\xe0\x94\x98Jy\x85\xe3\xcc~\xb5\xc96\x91\xf6\xf8\xcc{\x8f$]\x01\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x98]p\xd2\a\x89+\xed9\x85\x90\x02N$!\xb1\xcc\x11\x93Y\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x98m\xf4~v\xe4\u05e7\x89\xcd\xee\x91<\u0243\x16P\x93l\x9d\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x98t\x80?\xe1\xf3\xa06^y\"\xb1Bp\xea\xeb\x03,\xc1\xb5\x89<\xf5\x92\x88$\xc6\xc2\x00\x00\u07d4\x98ub4\x95\xa4l\xdb\xf2YS\x0f\xf88\xa1y\x9e\u00c9\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98v\x18\xc8VV |{\xac\x15\a\xc0\xff\xef\xa2\xfbd\xb0\x92\x89\x03}\xfeC1\x89\xe3\x80\x00\u07d4\x98|\x9b\xcdn?9\x90\xa5+\xe3\xed\xa4q\f'Q\x8fOr\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x98\x82\x96|\xeeh\u04a89\xfa\u062bJ|=\xdd\xf6\xc0\xad\u0209Hx\xbe\x1f\xfa\xf9]\x00\x00\u07d4\x98\x85\\}\xfb\xee3SD\x90J\x12\xc4\fs\x17\x95\xb1:T\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4\x98\x9c\f\xcf\xf6T\xda\x03\xae\xb1\x1a\xf7\x01\x05Ea\xd6)~\x1d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xa0\xe5Lm\x9d\u023e\x96'l\xeb\xf4\xfe\xc4`\xf6#]\x85\x89j\u0202\x10\tR\u01c0\x00\u07d4\x98\xb7i\xcc0\\\xec\xfbb\x9a\x00\xc9\a\x06\x9d~\xf9\xbc:\x12\x89\x01h\u048e?\x00(\x00\x00\xe0\x94\x98\xbaN\x9c\xa7/\xdd\xc2\fi\xb49ov\xf8\x18?z*N\x8a\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\x00\u07d4\x98\xbeimQ\xe3\x90\xff\x1cP\x1b\x8a\x0fc1\xb6(\xdd\u016d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbe\u04e7.\xcc\xfb\xaf\xb9#H\x92\x93\xe4)\xe7\x03\xc7\xe2[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbfJ\xf3\x81\v\x84#\x87\xdbp\xc1MF\t\x96&\x00=\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xc1\x0e\xbf,O\x97\u02e5\xa1\xab?*\xaf\xe1\xca\xc4#\xf8\u02c9\x10CV\x1a\x88)0\x00\x00\u07d4\x98\xc1\x9d\xba\x81\v\xa6\x11\xe6\x8f/\x83\xee\x16\xf6\xe7tO\f\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x98\xc5IJ\x03\xac\x91\xa7h\xdf\xfc\x0e\xa1\xdd\u0b3f\x88\x90\x19\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\x98\xd2\x04\xf9\b_\x8c\x8e}\xe2>X\x9bd\xc6\xef\xf6\x92\xccc\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x98\xd3s\x19\x92\xd1\xd4\x0e\x12\x11\xc7\xf75\xf2\x18\x9a\xfa\a\x02\xe0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x98\xe2\xb6\xd6\x06\xfd-i\x91\xc9\xd6\xd4\a\u007f\xdf?\xddE\x85\u06890\xdf\x1ao\x8a\xd6(\x00\x00\u07d4\x98\xe3\xe9\v(\xfc\xca\ue087y\xb8\xd4\nUh\xc4\x11n!\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x98\xe6\xf5G\u06c8\xe7_\x1f\x9c\x8a\xc2\xc5\xcf\x16'\xbaX\v>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x98\xf4\xaf:\xf0\xae\xde_\xaf\xdcB\xa0\x81\xec\xc1\xf8\x9e<\xcf \x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x98\xf6\xb8\xe6!=\xbc\x9aU\x81\xf4\xcc\xe6e_\x95%+\xdb\a\x89\x11Xr\xb0\xbc\xa40\x00\x00\u07d4\x99\te\r\u05719{\x8b\x8b\x0e\xb6\x94\x99\xb2\x91\xb0\xad\x12\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x99\x11s`\x19G\xc2\bJb\xd69R~\x96\x15\x12W\x9a\xf9\x89 \x86\xac5\x10R`\x00\x00\u07d4\x99\x12\x9d[<\f\xdeG\xea\r\xefM\xfc\a\r\x1fJY\x95'\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x99\x17\u058dJ\xf3A\xd6Q\xe7\xf0\a\\m\xe6\xd7\x14Nt\t\x8a\x012\xd4Gl\b\xe6\xf0\x00\x00\u07d4\x99\x1a\xc7\xcap\x97\x11_& ^\xee\x0e\xf7\xd4\x1e\xb4\xe3\x11\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\x99#e\xd7d\xc5\xce5@9\xdd\xfc\x91.\x02:u\xb8\xe1h\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x99&F\xac\x1a\u02ab\xf5\u076b\xa8\xf9B\x9a\xa6\xa9Nt\x96\xa7\x8967Pz0\xab\xeb\x00\x00\u07d4\x99&\x83'\xc3s3.\x06\xc3\xf6\x16B\x87\xd4U\xb9\xd5\xfaK\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99(\xffqZ\xfc:+`\xf8\xebL\u013aN\xe8\u06b6\u5749\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\x992\xef\x1c\x85\xb7Z\x9b*\x80\x05}P\x874\xc5\x10\x85\xbe\u0309\x02\xb8?\xa50\x1dY\x00\x00\xe0\x94\x99?\x14ax`^f\xd5\x17\xbex.\xf0\xb3\xc6\x1aN\x19%\x8a\x01|\x1f\x055\u05e5\x83\x00\x00\xe0\x94\x99A7\x04\xb1\xa3.p\xf3\xbc\ri\u0748\x1c8VkT\u02ca\x05\xcckiF1\xf7\x12\x00\x00\u07d4\x99AR\xfc\x95\xd5\xc1\u028b\x88\x11:\xbb\xadMq\x0e@\xde\xf6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x99D\xfe\xe9\xd3JJ\x88\x00#\u01c92\xc0\vY\xd5\xc8*\x82\x89(\xa8\xa5k6\x90\a\x00\x00\u07d4\x99L\u00b5\"~\xc3\xcf\x04\x85\x12F|A\xb7\xb7\xb7H\x90\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99q\xdf`\xf0\xaef\xdc\xe9\xe8\xc8N\x17\x14\x9f\t\xf9\xc5/d\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x99v\x94~\xff_j\xe5\xda\b\xddT\x11\x92\xf3x\xb4(\xff\x94\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x99}e\x92\xa3\x15\x89\xac\xc3\x1b\x99\x01\xfb\xeb<\xc3\xd6[2\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x82\xa5\x89\x0f\xfbT\x06\u04ec\xa8\u04bf\xc1\xddp\xaa\xa8\n\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x87\x8f\x9dn\n~\u066e\u01c2\x97\xb78y\xa8\x01\x95\xaf\xe0\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d4\x99\x8c\x1f\x93\xbc\xdbo\xf2<\x10\xd0\u0712G(\xb7;\xe2\xff\x9f\x896[\xf3\xa43\xea\xf3\x00\x00\u07d4\x99\x91aL[\xaaG\xddl\x96\x87FE\xf9z\xdd,=\x83\x80\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x99\x92J\x98\x16\xbb}\xdf?\xec\x18D\x82\x8e\x9a\xd7\xd0k\xf4\xe6\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x99\x99vh\xf7\xc1\xa4\xff\x9e1\xf9\x97z\xe3\"K\u02c8z\x85\x89\x0f\xc969(\x01\xc0\x00\x00\u07d4\x99\x9cI\xc1t\xca\x13\xbc\x83l\x1e\n\x92\xbf\xf4\x8b'\x15C\u0289\xb1\xcf$\xdd\u0431@\x00\x00\u07d4\x99\xa4\xde\x19\xde\u05d0\b\xcf\xdc\xd4]\x01M.XK\x89\x14\xa8\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x99\xa9k\xf2$.\xa1\xb3\x9e\xceo\xcc\r\x18\xae\xd0\f\x01y\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x99\xb0\x18\x93+\xca\xd3U\xb6y+%]\xb6p-\xec\x8c\xe5\u0749\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x99\xb7C\xd1\xd9\xef\xf9\r\x9a\x194\xb4\xdb!\xd5\x19\u061bJ8\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x99\xb8\xc8$\x86\x9d\xe9\xed$\xf3\xbf\xf6\x85L\xb6\xddE\xcc?\x9f\x89e\xea=\xb7UF`\x00\x00\u07d4\x99\xc0\x17L\xf8N\a\x83\xc2 \xb4\xebj\xe1\x8f\xe7\x03\x85J\u04c9py\xa2W=\fx\x00\x00\u07d4\x99\xc1\xd9\xf4\fj\xb7\xf8\xa9/\xce/\xdc\xe4zT\xa5\x86\xc5?\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x99\xc26\x14\x1d\xae\xc87\xec\xe0O\xda\xee\x1d\x90\u03cb\xbd\xc1\x04\x89ve\x16\xac\xac\r \x00\x00\u07d4\x99\xc3\x1f\xe7HX7\x87\xcd\xd3\xe5%\xb2\x81\xb2\x18\x96\x179\xe3\x897\b\xba\xed=h\x90\x00\x00\u07d4\x99\xc4u\xbf\x02\xe8\xb9!J\xda_\xad\x02\xfd\xfd\x15\xba6\\\f\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\x99\u0203%\x85F\xcc~N\x97\x1fR.8\x99\x18\xda^\xa6:\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x99\xc9\xf9>E\xfe<\x14\x18\xc3S\xe4\u016c8\x94\xee\xf8\x12\x1e\x89\x05\x85\xba\xf1E\x05\v\x00\x00\xe0\x94\x99\xd1W\x9c\xd4&\x82\xb7dN\x1dOq(D\x1e\xef\xfe3\x9d\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x99\u0475\x85\x96_@jB\xa4\x9a\x1c\xa7\x0fv\x9evZ?\x98\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x99\xdf\xd0PL\x06\xc7C\xe4e4\xfd{U\xf1\xf9\xc7\xec3)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xf4\x14|\xcck\u02c0\u0304.i\xf6\xd0\x0e0\xfaA3\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x99\xf7\u007f\x99\x8b \xe0\xbc\xdc\xd9\xfc\x83\x86ARl\xf2Y\x18\xef\x89a\t=|,m8\x00\x00\u07d4\x99\xfa\xd5\x008\xd0\xd9\xd4\xc3\xfb\xb4\xbc\xe0V\x06\xec\xad\xcdQ!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xfe\r \x12(\xa7S\x14VU\xd4(\xeb\x9f\xd9I\x85\xd3m\x89i \xbf\xf3QZ:\x00\x00\u07d4\x9a\a\x9c\x92\xa6)\xca\x15\xc8\xca\xfa.\xb2\x8d[\xc1z\xf8(\x11\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9a\r<\xee=\x98\x92\xea;7\x00\xa2\u007f\xf8A@\xd9\x02T\x93\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9a$\u038dH\\\xc4\xc8nI\u07b3\x90\"\xf9,t0\xe6~\x89Fy\x1f\xc8N\a\xd0\x00\x00\u07d4\x9a,\xe4;]\x89\u0593k\x8e\x8c5G\x91\xb8\xaf\xff\x96$%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9a9\x01bS^9\x88w\xe4\x16x}b9\xe0uN\x93|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a=\xa6P#\xa10 \xd2!E\xcf\xc1\x8b\xab\x10\xbd\x19\xceN\x89\x18\xbfn\xa3FJ:\x00\x00\xe0\x94\x9a>+\x1b\xf3F\xdd\a\v\x02sW\xfe\xacD\xa4\xb2\xc9}\xb8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9aL\xa8\xb8!\x17\x89NC\xdbr\xb9\xfax\xf0\xb9\xb9:\xce\t\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9aR.R\xc1\x95\xbf\xb7\xcf_\xfa\xae\u06d1\xa3\xbath\x16\x1d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9aZ\xf3\x1c~\x063\x9a\u0234b\x8d|M\xb0\xce\x0fE\u0224\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\x9ac?\xcd\x11,\xce\xebv_\xe0A\x81ps*\x97\x05\u7708\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9ac\u0445\xa7\x91)\xfd\xab\x19\xb5\x8b\xb61\xea6\xa4 TN\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x9ag\b\u0778\x90<(\x9f\x83\xfe\x88\x9c\x1e\xdc\xd6\x1f\x85D#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9ao\xf5\xf6\xa7\xaf{z\xe0\xed\x9c \xec\xecP#\u0481\xb7\x86\x89\x8a\x12\xb9\xbdjg\xec\x00\x00\xe0\x94\x9a\x82\x82m<)H\x1d\xcc+\u0495\x00G\xe8\xb6\x04\x86\xc38\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9a\x8e\xcaA\x89\xffJ\xa8\xff~\u0536\xb7\x03\x9f\t\x02!\x9b\x15\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9a\x95;[\xccp\x93y\xfc\xb5Y\u05f9\x16\xaf\u06a5\f\xad\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x9a\x99\v\x8a\xebX\x8d~\xe7\xec.\xd8\xc2\xe6Os\x82\xa9\xfe\xe2\x89\x01\xd1'\xdbi\xfd\x8b\x00\x00\u07d4\x9a\x9d\x1d\xc0\xba\xa7}n \xc3\xd8I\u01c8b\xdd\x1c\x05L\x87\x89/\xb4t\t\x8fg\xc0\x00\x00\xe0\x94\x9a\xa4\x8cf\xe4\xfbJ\u0419\x93N2\x02.\x82t'\xf2w\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xa80\x8fB\x91\x0eZ\xde\t\xc1\xa5\xe2\x82\xd6\xd9\x17\x10\xbd\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9a\xaa\xfa\x00gd~\u0659\x06kzL\xa5\xb4\xb3\xf3\xfe\xaao\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a\xb9\x88\xb5\x05\xcf\xee\x1d\xbe\x9c\u044e\x9bTs\xb9\xa2\xd4\xf56\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x9a\xb9\x8dm\xbb\x1e\xaa\xe1mE\xa0EhT\x1a\xd3\xd8\xfe\x06\u0309\x0e\xc5\x04d\xfe#\xf3\x80\x00\xe0\x94\x9a\xba+^'\xffx\xba\xaa\xb5\xcd\u0248\xb7\xbe\x85\\\xeb\xbd\u038a\x02\x1e\f\x00\x13\a\n\xdc\x00\x00\u07d4\x9a\xc4\xdaQ\xd2x\"\xd1\xe2\b\xc9n\xa6J\x1e[U)\x97#\x89\x05lUy\xf7\"\x14\x00\x00\u0794\x9a\xc8S\x97y*i\u05cf(k\x86C*\a\xae\u03b6\x0ed\x88\xc6s\xce<@\x16\x00\x00\xe0\x94\x9a\xc9\a\xee\x85\xe6\xf3\xe2#E\x99\x92\xe2V\xa4?\xa0\x8f\xa8\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xd4\u007f\xdc\xf9\u0354-(\xef\xfd[\x84\x11[1\xa6X\xa1>\x89\xb2Y\xec\x00\xd5;(\x00\x00\u07d4\x9a\xdb\u04fc{\n\xfc\x05\xd1\xd2\xed\xa4\x9f\xf8c\x93\x9cH\xdbF\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9a\xdfE\x8b\xff5\x99\xee\xe1\xa2c\x98\x85\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9a\xf9\xdb\xe4t\"\xd1w\xf9E\xbd\xea\xd7\xe6\xd8)05b0\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9a\xfaSkLf\xbc8\xd8u\u0133\x00\x99\xd9&\x1f\xdb8\xeb\x89\v*\x8f\x84*w\xbc\x80\x00\u07d4\x9b\x06\xad\x84\x1d\xff\xbeL\xcfF\xf1\x03\x9f\u00c6\xf3\xc3!Dn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\x11h\u078a\xb6KGU/3\x89\x80\n\x9c\xc0\x8bFf\u03c9]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9b\x18\x11\xc3\x05\x1fF\xe6d\xaeK\xc9\xc8$\u0445\x92\xc4WJ\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9b\x18G\x86U\xa4\x85\x1c\xc9\x06\xe6`\xfe\xaca\xf7\xf4\u023f\xfc\x89\xe2G\x8d8\x90}\x84\x00\x00\u07d4\x9b\"\xa8\r\\{3t\xa0[D`\x81\xf9}\n4\a\x9e\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9b+\xe7\xf5gT\xf5\x05\xe3D\x1a\x10\xf7\xf0\xe2\x0f\xd3\xdd\xf8I\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x9b2\xcfOQ\x15\xf4\xb3J\x00\xa6La}\xe0c\x875C#\x89\x05\xb8\x1e\u0608 |\x80\x00\u07d4\x9bC\u0739_\xde1\x80u\xa5g\xf1\xe6\xb5v\x17\x05^\xf9\xe8\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9bDO\xd37\xe5\xd7R\x93\xad\xcf\xffp\xe1\xea\x01\xdb\x022\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bH$\xff\x9f\xb2\xab\xdaUM\xeeO\xb8\xcfT\x91eW\x061\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bL'\x15x\f\xa4\xe9\x9e`\xeb\xf2\x19\xf1Y\f\x8c\xadP\n\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x9bY\xeb!;\x1eue\xe4PG\xe0N\xa07O\x10v-\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\\9\xf7\xe0\xac\x16\x8c\x8e\xd0\xed4\x04w\x11}\x1bh.\xe9\x89\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4\x9b^\xc1\x8e\x83\x13\x88}\xf4a\u0490.\x81\xe6z\x8f\x11;\xb1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bd\xd3\u034d+s\xf6hA\xb5\xc4k\xb6\x95\xb8\x8a\x9a\xb7]\x89\x01 :Ov\f\x16\x80\x00\u07d4\x9be\x8f\xb3a\xe0F\xd4\xfc\xaa\x8a\xefm\x02\xa9\x91\x11\"6%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9bfA\xb1>\x17/\xc0r\xcaK\x83'\xa3\xbc(\xa1[f\xa9\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94\x9bh\xf6t\x16\xa6;\xf4E\x1a1\x16L\x92\xf6r\xa6\x87Y\xe9\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x9bw6i\xe8}v\x01\x8c\t\x0f\x82U\xe5D\t\xb9\u0728\xb2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bw\xeb\xce\xd7\xe2\x15\xf0\x92\x0e\x8c+\x87\x00$\xf6\xec\xb2\xff1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b|\x88\x10\xcc|\u021e\x80Nm>8\x12\x18PG(w\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\xa5=\xc8\xc9^\x9aG/\xeb\xa2\xc4\xe3,\x1d\xc4\xdd{\xabF\x89Hz\x9a0E9D\x00\x00\xe0\x94\x9b\xac\xd3\xd4\x0f;\x82\xac\x91\xa2d\xd9\u060d\x90\x8e\xac\x86d\xb9\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9b\xb7`\xd5\u0089\xa3\xe1\xdb\x18\xdb\tSE\xcaA;\x9aC\u0089\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x9b\xb7b\x04\x18j\xf2\xf6;\xe7\x91h`\x16\x87\xfc\x9b\xadf\x1f\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9b\xb9\xb0*&\xbf\xe1\xcc\xc3\xf0\xc6!\x9e&\x1c9\u007f\xc5\xcax\x89Hz\x9a0E9D\x00\x00\u07d4\x9b\xc5s\xbc\xda#\xb8\xb2o\x90s\xd9\f#\x0e\x8eq\xe0'\v\x896/u\xa40]\f\x00\x00\u07d4\x9b\xd7\u00caB\x100JMe>\xde\xff\x1b<\xe4_\xcexC\x89\x0fI\x89A\xe6d(\x00\x00\xe0\x94\x9b\u0600h\xe10u\xf3\xa8\xca\xc4d\xa5\xf9I\xd6\xd8\x18\xc0\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9b\xd9\x05\xf1q\x9f\u01ec\xd0\x15\x9dM\xc1\xf8\xdb/!G#8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b\xdb\u071b\x9741\xd1<\x89\xa3\xf9u~\x9b;bu\xbf\u01c9\x1b\x1a}\u03caD\u04c0\x00\u07d4\x9b\xe3\xc3)\xb6*(\xb8\xb0\x88l\xbd\x8b\x99\xf8\xbc\x93\f\xe3\xe6\x89\x04\t\xe5+H6\x9a\x00\x00\xe0\x94\x9b\xf5\x8e\xfb\xea\a\x84\xeb\x06\x8a\xde\u03e0\xbb!P\x84\xc7:5\x8a\x01:k+VHq\xa0\x00\x00\u07d4\x9b\xf6r\xd9y\xb3fR\xfcR\x82Tzjk\xc2\x12\xaeCh\x89#\x8f\xd4,\\\xf0@\x00\x00\xe0\x94\x9b\xf7\x03\xb4\x1c6$\xe1_@T\x96#\x90\xbc\xba0R\xf0\xfd\x8a\x01H>\x01S<.<\x00\x00\u07d4\x9b\xf7\x1f\u007f\xb57\xacT\xf4\xe5\x14\x94\u007f\xa7\xffg(\xf1m/\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\x9b\xf9\xb3\xb2\xf2<\xf4a\xebY\x1f(4\v\xc7\x19\x93\x1c\x83d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9b\xfce\x9c\x9c`\x1e\xa4*k!\xb8\xf1p\x84\xec\x87\xd7\x02\x12\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9b\xff\xf5\r\xb3jxUU\xf0vR\xa1S\xb0\xc4+\x1b\x8bv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\x05\xe9\xd0\xf0u\x8eyS\x03q~1\xda!<\xa1W\u618965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\x1bw\x1f\t\xaf\x88*\xf0d0\x83\xde*\xa7\x9d\xc0\x97\xc4\x0e\x89\x86p\xe9\xece\x98\xc0\x00\x00\u07d4\x9c(\xa2\xc4\b`\x91\xcb]\xa2&\xa6W\xce2H\xe8\xea{o\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\x9c/\xd5@\x89\xaff]\xf5\x97\x1ds\xb8\x04a`9dsu\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c4@\x98\xbaaZ9\x8f\x11\xd0\t\x90[\x17|D\xa7\xb6\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c=\x06\x92\xce\xee\xf8\n\xa4\x96\\\xee\xd2b\xff\xc7\xf0i\xf2\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c@\\\xf6\x97\x95a8\x06^\x11\xc5\xf7U\x9eg$[\u0465\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cE *%\xf6\xad\x00\x11\xf1\x15\xa5\xa7\"\x04\xf2\xf2\x19\x88f\x8a\x01\x0f\xcf:b\xb0\x80\x98\x00\x00\xe0\x94\x9cI\xde\xffG\b_\xc0\x97\x04\u02a2\u0728\u0087\xa9\xa17\u068a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x9cK\xbc\xd5\xf1dJo\aX$\xdd\xfe\x85\xc5q\u05ab\xf6\x9c\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4\x9cRj\x14\x06\x83\xed\xf1C\x1c\xfa\xa1(\xa95\xe2\xb6\x14\u060b\x89\x06\x04o7\xe5\x94\\\x00\x00\xe0\x94\x9cT\xe4\xedG\x9a\x85h)\u01bbB\u069f\vi*u\xf7(\x8a\x01\x97\xa8\xf6\xddU\x19\x80\x00\x00\xe0\x94\x9cX\x1a`\xb6\x10(\xd94\x16y)\xb2-p\xb3\x13\xc3O\u040a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x9c\\\xc1\x11\t,\x12!\x16\xf1\xa8_N\xe3\x14\bt\x1a}/\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x9ck\u0264k\x03\xaeT\x04\xf0C\xdf\xcf!\x88>A\x10\xcc3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cx\x96?\xbc&<\t\xbdr\xe4\xf8\xde\xf7J\x94u\xf7\x05\\\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4\x9cx\xfb\xb4\xdfv\x9c\xe2\xc1V\x92\f\xfe\xdf\xda\x03:\x0e%J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9c{m\xc5\x19\x0f\xe2\x91)c\xfc\xd5yh>\xc79Q\x16\xb0\x89*\x11)\u0413g \x00\x00\u07d4\x9c\x80\xbc\x18\xe9\xf8\u0516\x8b\x18]\xa8\u01df\xa6\xe1\x1f\xfc>#\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x9c\x98\xfd\xf1\xfd\u034b\xa8\xf4\u0170L:\xe8X~\xfd\xf0\xf6\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x9c\x99\xa1\u0691\u0552\v\xc1N\f\xb9\x14\xfd\xf6+\x94\u02c3X\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9c\x99\xb6&\x06(\x1b\\\xef\xab\xf3aV\xc8\xfeb\x83\x9e\xf5\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9c\x9a\a\xa8\xe5|1r\xa9\x19\xefdx\x94tI\x0f\r\x9fQ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\x9d\xe4G$\xa4\x05M\xa0\xea\xa6\x05\xab\u0300&hw\x8b\xea\x89\n\xd7\xd5\xca?\xa5\xa2\x00\x00\u07d4\x9c\x9f;\x8a\x81\x1b!\xf3\xff?\xe2\x0f\xe9p\x05\x1c\xe6j\x82O\x89>\xc2\u07bc\a\u053e\x00\x00\xe0\x94\x9c\x9f\x89\xa3\x91\x0fj*\xe8\xa9\x10G\xa1z\xb7\x88\xbd\xde\xc1p\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\xa0B\x9f\x87O\x8d\xce\xe2\xe9\xc0b\xa9\x02\n\x84*Xz\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xa4.\u7838\x98\xf6\xa5\xcc`\xb5\xa5\u05f1\xbf\xa3\xc321\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xb2\x8a\xc1\xa2\n\x10o\u007f76\x92\xc5\xceLs\xf172\xa1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\xcd\u0732\xcf\u00b2[\br\x9a\n\x98\xd9\xe6\xf0 .\xa2\xc1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9c\xe2\u007f$^\x02\xd1\xc3\x12\xc1\xd5\x00x\x8c\x9d\xefv\x90E;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c\xe56;\x13\xe8#\x8a\xa4\xdd\x15\xac\u0432\xe8\xaf\xe0\x872G\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9c\xf2\x92\x8b\xee\xf0\x9a@\xf9\xbf\xc9S\xbe\x06\xa2Q\x11a\x82\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9d\x06\x91\x97\xd1\xdeP\x04Z\x18o^\xc7D\xac@\u8bd1\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d\x0e}\x92\xfb0XS\u05d8&;\xf1^\x97\xc7+\xf9\xd7\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9d\x0f4~\x82k}\u03aa\xd2y\x06\n5\xc0\x06\x1e\xcf3K\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d u\x17B,\xc0\xd6\r\xe7\xc27\tzMO\xce \x94\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x9d%\n\xe4\xf1\x10\xd7\x1c\xaf\u01f0\xad\xb5.\x8d\x9a\xcbfy\xb8\x8a\x02\x15mn\x99r\x13\xc0\x00\x00\xe0\x94\x9d+\xfc6\x10o\x03\x82P\xc0\x18\x01hW\x85\xb1l\x86\xc6\r\x8aPw\xd7]\xf1\xb6u\x80\x00\x00\xe0\x94\x9d0\xcb#{\xc0\x96\xf1p6\xfc\x80\xdd!\xcah\x99,\xa2\u064a\x06n\xe71\x8f\u070f0\x00\x00\u07d4\x9d2\x96.\xa9\x97\x00\xd92(\xe9\xdb\xda\xd2\xcc7\xbb\x99\xf0~\x89\xb4c+\xed\xd4\xde\xd4\x00\x00\u07d4\x9d4\xda\xc2[\xd1X(\xfa\xef\xaa\xf2\x8fq\aS\xb3\x9e\x89\u0709;\x1cV\xfe\xd0-\xf0\x00\x00\u07d4\x9d6\x91e\xfbp\xb8\x1a:v_\x18\x8f\xd6\f\xbe^{\th\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d@\xe0\x12\xf6\x04%\xa3@\xd8-\x03\xa1\xc7W\xbf\xab\xc7\x06\xfb\x89\t4o:\xdd\u020d\x80\x00\u07d4\x9dAt\xaaj\xf2\x84v\xe2)\xda\xdbF\x18\b\b\xc6u\x05\xc1\x89B\x1a\xfd\xa4.\u0597\x00\x00\u07d4\x9dB\x133\x9a\x01U\x18avL\x87\xa9<\xe8\xf8_\x87\x95\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9dF\f\x1b7\x9d\xdb\x19\xa8\xc8[LgG\x05\r\xdf\x17\xa8u\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x9dG\xba[L\x85\x05\xad\x8d\xa4)4(\va\xa0\xe1\xe8\xb9q\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9dM2\x11w%n\xbd\x9a\xfb\xda0A5\xd5\x17\xc3\xdcV\x93\x89!d\xb7\xa0J\u0220\x00\x00\u07d4\x9dO\xf9\x89\xb7\xbe\u066b\x10\x9d\x10\xc8\xc7\xe5_\x02\xd7g4\xad\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9dQ\x15C\xb3\xd9\xdc`\xd4\u007f\t\u051d\x01\xb6\u0118\xd8 x\x8a\x02a\x97\xb9Qo\u00d4\x00\x00\u07d4\x9dn\u03e0:\xf2\xc6\xe1D\xb7\xc4i*\x86\x95\x1e\x90.\x9e\x1f\x89\xa2\xa5\xaa`\xad$?\x00\x00\u07d4\x9dvU\xe9\xf3\xe5\xba]n\x87\xe4\x12\xae\xbe\x9e\xe0\u0512G\ue24e\t1\x1c\x1d\x80\xfa\x00\x00\u07d4\x9dx1\xe84\xc2\v\x1b\xaaiz\xf1\xd8\xe0\xc6!\u016f\xff\x9a\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\x9dx\xa9u\xb7\xdb^M\x8e(\x84\\\xfb\xe7\xe3\x14\x01\xbe\r\u0649H\xa40k\xa2\u5e5c\x8ahX\u02f5,\f\xf75\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\x9d\u007f\xdapp\xbf>\xe9\xbb\u0664\x1fU\xca\u0505J\xe6\xc2,\x8a\x02U\u02e3\xc4o\xcf\x12\x00\x00\u07d4\x9d\x81\xae\xa6\x9a\xedj\xd0p\x89\xd6\x14E4\x8c\x17\xf3K\xfc[\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9d\x91\x1f6\x82\xf3/\xe0y.\x9f\xb6\xff<\xfcG\xf5\x89\xfc\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\x91;]3\x9c\x95\xd8wEV%c\xfe\xa9\x8b#\xc6\f\u0109\tA0,\u007fM#\x00\x00\u07d4\x9d\x93\xfa\xb6\xe2(E\xf8\xf4Z\aIo\x11\xdeqS\r\xeb\u01c9lO\xd1\xee$nx\x00\x00\u07d4\x9d\x99\xb1\x89\xbb\u0664\x8f\xc2\xe1n\x8f\u0363;\xb9\x9a1{\xbb\x89=\x16\xe1\vm\x8b\xb2\x00\x00\u07d4\x9d\x9cN\xfe\x9fC9\x89\xe2;\xe9@I!S)\xfaU\xb4\u02c9\r\u3c89\x03\u01b5\x80\x00\u07d4\x9d\x9eW\xfd\xe3\x0ePh\xc0>I\x84\x8e\xdc\xe3C\xb7\x02\x83X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9d\xa30\"@\xaf\x05\x11\xc6\xfd\x18W\xe6\u07779Ow\xabk\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\x9d\xa4\xec@pw\xf4\xb9p{-\x9d.\xde^\xa5(+\xf1\u07c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xa6\t\xfa:~l\xf2\xcc\x0ep\u036b\xe7\x8d\xc4\xe3\x82\xe1\x1e\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\x9d\xa6\x1c\xcdb\xbf\x86\x06V\xe02]qW\xe2\xf1`\xd9;\xb5\x8a\x01\x0f\f\xa9V\xf8y\x9e\x00\x00\xe0\x94\x9d\xa6\xe0u\x98\x9ct\x19\tL\xc9\xf6\xd2\u44d3\xbb\x19\x96\x88\x8a\x02Y\xbbq\u056d\xf3\xf0\x00\x00\u07d4\x9d\xa8\xe2,\xa1\x0eg\xfe\xa4NR^GQ\xee\xac6\xa3\x11\x94\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x9d\xb2\xe1\\\xa6\x81\xf4\xc6`H\xf6\xf9\xb7\x94\x1e\u040b\x1f\xf5\x06\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xc1\x0f\xa3\x8f\x9f\xb0h\x10\xe1\x1f`\x17>\xc3\xd2\xfdju\x1e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9d\xd2\x19f$\xa1\xdd\xf1J\x9d7^_\a\x15+\xaf\"\xaf\xa2\x89A\xb0^$c\xa5C\x80\x00\u07d4\x9d\xd4k\x1cm?\x05\u279co\x03~\xed\x9aYZ\xf4\xa9\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9d\xdd5^cN\xe9\x92~K\u007fl\x97\xe7\xbf:/\x1ehz\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9d\xe2\n\xe7j\xa0\x82c\xb2\x05\xd5\x14$a\x96\x1e$\b\xd2f\x89\r\xa93\xd8\xd8\xc6p\x00\x00\u07d4\x9d\xe2\v\xc3~\u007fH\xa8\x0f\xfdz\xd8O\xfb\xf1\xa1\xab\xe1s\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9d\xe78m\xde@\x1c\xe4\xc6{q\xb6U?\x8a\xa3N\xa5\xa1}\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9d\xeb9\x02z\xf8w\x99+\x89\xf2\xecJ\x1f\x82.\xcd\xf1&\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xef\xe5j\x0f\xf1\xa1\x94}\xba\t#\xf7\xdd%\x8d\x8f\x12\xfaE\x8a\x05\xb1*\ufbe8\x04\x00\x00\x00\u07d4\x9d\xf0W\xcd\x03\xa4\xe2~\x8e\x03/\x85y\x85\xfd\u007f\x01\xad\xc8\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xf3*P\x1c\vx\x1c\x02\x81\x02/B\xa1)?\xfd{\x89*\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\x9e\x01vZ\xff\b\xbc\"\x05P\xac\xa5\xea.\x1c\xe8\u5c19#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9e \xe5\xfd6\x1e\xab\xcfc\x89\x1f[\x87\xb0\x92h\xb8\xeb7\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e#,\b\xc1M\xc1\xa6\xed\v\x8a;(h\x97{\xa5\xc1}\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e#\xc5\u4dc2\xb0\n_\xad\U0006eb47\xda\xcf[\x03g\xa1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e59\x90q\xa4\xa1\x01\xe9\x19M\xaa?\t\xf0J\v_\x98p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e>\xb5\t'\x8f\xe0\xdc\xd8\xe0\xbb\xe7\x8a\x19N\x06\xb6\x809C\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x9eBrrQk>g\xd4\xfc\xbf\x82\xf5\x93\x90\xd0L\x8e(\xe5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9eL\xec5:\xc3\u3043^<\t\x91\xf8\xfa\xa5\xb7\u0428\xe6\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\u07d4\x9eX\x11\xb4\v\xe1\xe2\xa1\xe1\u048c;\at\xac\xde\n\t`=\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9eZ1\x1d\x9fi\x89\x8a|j\x9dc`h\x048\xe6z{/\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x9e| P\xa2'\xbb\xfd`\x93~&\x8c\xea>h\xfe\xa8\xd1\xfe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e\u007fe\xa9\x0e\x85\b\x86{\xcc\xc9\x14%j\x1e\xa5t\xcf\a\xe3\x89C8t\xf62\xcc`\x00\x00\xe0\x94\x9e\x81D\xe0\x8e\x89dx\x11\xfekr\xd4E\u05a5\xf8\n\xd2D\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9e\x8fd\xdd\xcd\u9e34Q\xba\xfa\xa25\xa9\xbfQ\x1a%\xac\x91\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\x9e\x95\x1fm\xc5\xe3R\xaf\xb8\xd0B\x99\xd2G\x8aE\x12Y\xbfV\x89\x03\xe7A\x98\x81\xa7:\x00\x00\u07d4\x9e\x96\r\xcd\x03\u057a\x99\xcb\x11]\x17\xffL\t$\x8a\xd4\u043e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9e\xafj2\x8a@v\x02N\xfakg\xb4\x8b!\xee\xdc\xc0\xf0\xb8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x9e\xb1\xffqy\x8f(\xd6\xe9\x89\xfa\x1e\xa0X\x8e'\xba\x86\xcb}\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\x9e\xb2\x81\xc3'\x19\xc4\x0f\xdb>!m\xb0\xf3\u007f\xbcs\xa0&\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e\xb3\xa7\xcb^g&Bz:6\x1c\xfa\x8dad\xdb\u043a\x16\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4\x9e\xb7\x83N\x17\x1dA\xe0i\xa7yG\xfc\xa8v\"\xf0\xbaNH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x9e\xc0>\x02\u51f7v\x9d\xefS\x84\x13\xe9\u007f~U\xbeq\u060a\x04+\xf0kx\xed;P\x00\x00\u07d4\x9e\u02eb\xb0\xb2'\x82\xb3uD)\xe1uz\xab\xa0K\x81\x18\x9f\x89,\xa7\xbb\x06\x1f^\x99\x80\x00\u07d4\x9e\xce\x14\x00\x80\t6\xc7\xc6H_\xcd\xd3b`\x17\u041a\xfb\xf6\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\x9e\xd4\xe6?ReB\xd4O\xdd\xd3MY\xcd%8\x8f\xfdk\u0689\u049b4\xa4cH\x94\x00\x00\u07d4\x9e\xd8\x0e\xda\u007fU\x05M\xb9\xfbR\x82E\x16\x88\xf2k\xb3t\xc1\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9e\u0710\xf4\xbe!\be!J\xb5\xb3^Z\x8d\xd7t\x15'\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e\u07acL\x02k\x93\x05M\u0171\xd6a\fo9`\xf2\xads\x89A\rXj \xa4\xc0\x00\x00\u07d4\x9e\xe9?3\x9eg&\xece\xee\xa4O\x8aK\xfe\x10\xda=2\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9e\xe9v\f\xc2s\xd4pj\xa0\x83u\xc3\xe4o\xa20\xaf\xf3\u054a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4\x9e\xeb\a\xbd+x\x90\x19^}F\xbd\xf2\a\x1bf\x17QM\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x9e\xefD-)\x1aD}t\xc5\xd2S\u011e\xf3$\xea\xc1\xd8\xf0\x89\xb9f\b\xc8\x10;\xf0\x00\x00\u07d4\x9e\xf1\x89k\x00|2\xa1Q\x14\xfb\x89\xd7=\xbdG\xf9\x12+i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9f\x01w\x06\xb80\xfb\x9c0\ufc20\x9fPk\x91WEu4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x10\xf2\xa0F;e\xae0\xb0p\xb3\xdf\x18\xcfF\xf5\x1e\x89\xbd\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x9f\x19\xfa\u0223$7\xd8\n\u0183z\v\xb7\x84\x17)\xf4\x97.\x89#=\xf3)\x9far\x00\x00\u07d4\x9f\x1a\xa8\xfc\xfc\x89\xa1\xa52\x8c\xbdcD\xb7\x1f'\x8a,\xa4\xa0\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9f!0,\xa5\tk\xeat\x02\xb9\x1b\x0f\xd5\x06%O\x99\x9a=\x89C\x97E\x1a\x00=\xd8\x00\x00\u07d4\x9f'\x1d(U\x00\xd78F\xb1\x8fs>%\u074bO]J\x8b\x89'#\xc3F\xae\x18\b\x00\x00\u07d4\x9f4\x97\xf5\xef_\xe60\x95\x83l\x00N\xb9\xce\x02\xe9\x01;K\x89\"V\x86\x1b\xf9\xcf\b\x00\x00\xe0\x94\x9f:t\xfd^~\xdc\xc1\x16)\x93\x17\x13\x81\u02f62\xb7\xcf\xf0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9fF\xe7\xc1\xe9\a\x8c\xae\x860Z\xc7\x06\v\x01F}f\x85\xee\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x9fIl\xb2\x06\x95c\x14M\b\x11g{\xa0\xe4q:\nAC\x89<\xd2\xe0\xbfc\xa4H\x00\x00\u07d4\x9fJq\x95\xac|\x15\x1c\xa2X\xca\xfd\xa0\u02b0\x83\xe0I\xc6\x02\x89SS\x8c2\x18\\\xee\x00\x00\u07d4\x9fJ\xc9\xc9\xe7\xe2L\xb2DJ\x04T\xfa[\x9a\xd9\xd9-8S\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x9f_D\x02kWjJ\xdbA\xe9YaV\x1dA\x03\x9c\xa3\x91\x89\r\x8drkqw\xa8\x00\x00\u07d4\x9f`{?\x12F\x9fDa!\u03bf4u5kq\xb42\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9fa\xbe\xb4o^\x85=\n\x85!\xc7Dnh\xe3L}\ts\x89\x1e[\x8f\xa8\xfe*\xc0\x00\x00\u07d4\x9fd\xa8\xe8\xda\xcfJ\xde0\xd1\x0fMY\xb0\xa3\u056b\xfd\xbft\x8966\x9e\xd7t}&\x00\x00\u07d4\x9ff.\x95'A!\xf1wVncm#\x96L\xf1\xfdho\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9fj2*mF\x99\x81Bj\xe8D\x86]~\xe0\xbb\x15\u01f3\x89\x02\xb5\xeeW\x92\x9f\u06c0\x00\u07d4\x9fy\x86\x92J\xeb\x02h|\xd6A\x89\x18\x9f\xb1g\xde\xd2\xdd\\\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x9fz\x03\x92\xf8Ws.0\x04\xa3u\xe6\xb1\x06\x8dI\xd801\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x82E\u00eb}\x171d\x86\x1c\u04d9\x1b\x94\xf1\xba@\xa9:\x89\x9b\ny\x1f\x12\x110\x00\x00\u07d4\x9f\x83\xa2\x93\xc3$\xd4\x10l\x18\xfa\xa8\x88\x8fd\u0499\x05L\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9f\x86\xa0f\xed\xb6\x1f\xcbXV\u0793\xb7\\\x8cy\x18d\xb9{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x98\xeb4\xd4iy\xb0\xa6\u078b\x05\xaaS:\x89\xb8%\xdc\xf1\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\xe0\x94\x9f\x9f\xe0\xc9_\x10\xfe\xe8z\xf1\xaf r6\xc8\xf3aN\xf0/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9f\xae\xa1\xc5\xe8\x1ez\xcb?\x17\xf1\xc3Q\xee.\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0\b\x01\x98c\xc1\xa7|\x14\x99\xeb9\xbb\u05ff-\u05e3\x1c\xb9\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xa0\t\xbf\ao\x1b\xa3\xfaW\u04a7!r\x18\xbe\xd5VZzz\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0\x1e\x94v\u07c4C\x18%\xc86\xe8\x80:\x97\xe2/\xa5\xa0\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xa0\x1f\x12\xd7\x0fD\xaa{\x11;(\\\"\xdc\xdbE\x874T\xa7\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa0\x1f\u0450j\x90\x85\x06\xde\xda\xe1\xe2\b\x12\x88r\xb5n\u7489\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa0\"\x82@\xf9\x9e\x1d\xe9\xcb2\xd8,\x0f/\xa9\xa3\xd4K\v\xf3\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xa0+\xdedahn\x19\xace\f\x97\r\x06r\xe7m\xcbO\u008a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4\xa0,\x1e4\x06O\x04u\xf7\xfa\x83\x1c\xcb%\x01L:\xa3\x1c\xa2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xa0-\u01aa2\x8b\x88\r\u97acTh#\xfc\xcfw@G\xfb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa0.?\x8fYY\xa7\xaa\xb7A\x86\x12\x12\x9bp\x1c\xa1\xb8\x00\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa04\u007f\n\x98wc\x90\x16\\\x16m2\x96;\xf7M\xcd\n/\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa05\xa3e$x\xf8-\xbdm\x11_\xaa\x8c\xa9F\xec\x9eh\x1d\x89\x05\xf4\xe4-\u052f\xec\x00\x00\u07d4\xa0:=\xc7\xc53\xd1tB\x95\xbe\x95]a\xaf?R\xb5\x1a\xf5\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa0E\x9e\xf3i:\xac\xd1d|\xd5\u0612\x989 L\xefS\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0O*\xe0*\xdd\x14\xc1/\xafe\xcb%\x90\"\u0403\n\x8e&\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xa0l\xd1\xf3\x969l\ndFFQ\xd7\xc2\x05\xef\xaf8|\xa3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa0ri\x1c\x8d\xd7\xcdB7\xffr\xa7\\\x1a\x95\x06\xd0\xce[\x9e\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xa0r\u03beb\xa9\xe9\xf6\x1c\xc3\xfb\xf8\x8a\x9e\xfb\xfe>\x9a\x8dp\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0v\x82\x00\v\x1b\xcf0\x02\xf8\\\x80\xc0\xfa)I\xbd\x1e\x82\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0z\xa1mt\xae\u8a63(\x8dR\xdb\x15Q\u0553\x882\x97\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x8d![[j\xacHa\xa2\x81\xac~@\vx\xfe\xf0L\xbf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa0\x95\x19p\xdf\u0403/\xb8;\xda\x12\xc25E\xe7\x90Aul\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x9fM^\xaae\xa2\xf4\xcbu\nI\x924\x01\xda\u5410\xaf\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\xa0\xa0\xe6R\x04T\x1f\u029b/\xb2\x82\u0355\x13\x8f\xae\x16\xf8\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa0\xaa_\x02\x01\xf0M;\xbe\xb8\x98\x13/|\x11g\x94f\xd9\x01\x89\x01\xfb\xedR\x15\xbbL\x00\x00\u07d4\xa0\xaa\xdb\xd9P\x97\"p_m#X\xa5\u01df7\x97\x0f\x00\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa0\xb7q\x95\x1c\xe1\xde\xee6:\xe2\xb7q\xb7>\a\u0135\xe8\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa0\xde\\`\x1eif5\u0198\xb7\xae\x9c\xa4S\x9f\u01f9A\xec\x89\x12\xc3\xcb\xd7\x04\xc9w\x00\x00\u07d4\xa0\xe8\xbaf\x1bH\x15L\xf8C\xd4\u00a5\xc0\xf7\x92\xd5(\xee)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0\xfc~S\xc5\xeb\xd2z*\xbd\xacE&\x1f\x84\xab;Q\xae\xfb\x89\xa3\x13\xda\xec\x9b\xc0\xd9\x00\x00\xe0\x94\xa0\xff[L\xf0\x16\x02~\x83#I}D(\xd3\xe5\xa8;\x87\x95\x8a\x01e\x98\xd3\xc8>\xc0B\x00\x00\u07d4\xa1\x06F[\xbd\x19\u1dbc\xe5\r\x1b\x11W\xdcY\tZ60\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa1\x06\xe6\x92>\xddS\u028e\xd6P\x96\x8a\x91\b\xd6\xcc\xfd\x96p\x8a\x02\x02\xfe\x15\x05\xaf\uc240\x00\u07d4\xa1\t\u12f0\xa3\x9c\x9e\xf8/\xa1\x95\x97\xfc^\xd8\xe9\xebmX\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xa1\x1a\x03\u013b&\xd2\x1e\xffg}]U\\\x80\xb2TS\xeez\x89\x03\xcb'Y\xbcA\x0f\x80\x00\u07d4\xa1\x1e\xff\xabl\xf0\xf5\x97,\xff\xe4\xd5e\x96\xe9\x89h\x14J\x8f\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xa1 M\xad_V\a(\xa3\\\r\x8f\u01d4\x81\x05{\xf7s\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa1&#\xe6)\u07d3\tg\x04\xb1`\x84\xbe,\u061dV-\xa4\x8a\x01\xcc\xc92E\x11\xe4P\x00\x00\xe0\x94\xa1*l-\x98]\xaf\x0eO_ z\xe8Q\xaa\xf7)\xb32\u034a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa13m\xfb\x96\xb6\xbc\xbeK>\xdf2\x05\xbeW#\xc9\x0f\xadR\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa1;\x9d\x82\xa9\x9b<\x9b\xbaZ\xe7.\xf2\x19\x9e\xdc};\xb3l\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa1<\xfe\x82mm\x18A\u072eD;\xe8\u00c7Q\x816\xb5\xe8\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\xe0\x94\xa1C.\xd2\u01b7wz\x88\xe8\xd4m8\x8epG\u007f \x8c\xa5\x8a\x01\xb1\xa7\xe4\x13\xa1\x96\xc5\x00\x00\u07d4\xa1D\xf6\xb6\x0fr\xd6J!\xe30\xda\xdbb\u0619\n\xde+\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1P%\xf5\x95\xac\xdb\xf3\x11\x0fw\u017f$G~eH\xf9\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1X\x14\x8a.\x0f>\x92\xdc,\xe3\x8f\xeb\xc2\x01\a\xe3%<\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1a`\x85\x1d+\x9c4\x9b\x92\xe4o\x82\x9a\xbf\xb2\x10\x945\x95\x89a\t=|,m8\x00\x00\u07d4\xa1f\xf9\x11\xc6D\xac2\x13\u049e\x0e\x1a\xe0\x10\xf7\x94\u056d&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1m\x9e=c\x98aY\xa8\x00\xb4h7\xf4^\x8b\xb9\x80\xee\v\x89n\x11u\xdaz\xd1 \x00\x00\u07d4\xa1pp\xc2\xe9\u0169@\xa4\xec\x0eIT\xc4\xd7\xd6C\xbe\x8fI\x89lk\x17\x03;6\x1c\x80\x00\u07d4\xa1|\x9eC#\x06\x95\x18\x18\x9dR\a\xa0r\x8d\u02d20j?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\x83`\xe9\x85\xf2\x06.\x8f\x8e\xfe\x02\xad,\xbc\x91\xad\x9aZ\xad\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa1\x91\x14\x05\xcfn\x99\x9e\xd0\x11\xf0\xdd\xcd*O\xf7\u008f%&\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa1\x92i\x80\a\xcc\x11\xaa`=\"\x1d_\xee\xa0v\xbc\xf7\xc3\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\x92\xf0j\xb0R\xd5\xfd\u007f\x94\xee\xa81\x8e\x82x\x15\xfegz\x89\a\x1f\x8a\x93\xd0\x1eT\x00\x00\u07d4\xa1\x99\x81D\x96\x8a\\p\xa6AUT\xce\xfe\u0082F\x90\u0125\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa1\xa1\xf0\xfam \xb5\nyO\x02\xefR\b\\\x9d\x03j\xa6\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\xae\x8dE@\xd4\xdbo\xdd\xe7\x14oA[C\x1e\xb5\\y\x83\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xa1\xb4|M\x0e\xd6\x01\x88B\xe6\xcf\xc8c\n\u00e3\x14.^k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xa1\xc4\xf4Z\x82\xe1\xc4x\xd8E\b.\xb1\x88u\xc4\xeae9\xab\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa1\xdc\xd0\xe5\xb0Z\x97|\x96#\xe5\xae/Y\xb9\xad\xa2\xf3>1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa1\xe48\n;\x1ft\x96s\xe2p\"\x99\x93\xeeU\xf3Vc\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf1\x93\xa0Y/\x1f\xeb\x9f\xdf\xc9\n\xa8\x13xN\xb8\x04q\u0249K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa1\xf2\x85@P\xf8re\x8e\xd8.R\xb0\xad{\xbc\x1c\xb9!\xf6\x89m\x03\x17\xe2\xb3&\xf7\x00\x00\u07d4\xa1\xf5\xb8@\x14\rZ\x9a\xce\xf4\x02\xac<\u00c8jh\xca\xd2H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf7e\xc4O\xe4_y\x06w\x94HD\xbeO-B\x16_\xbd\x89\xc7\xe9\xcf\xdev\x8e\xc7\x00\x00\u07d4\xa1\xf7\xdd\xe1\xd78\xd8\xcdg\x9e\xa1\xee\x96[\xee\"K\xe7\xd0M\x89=\x18DP\xe5\xe9<\x00\x00\u07d4\xa1\xf8\u063c\xf9\x0ew\u007f\x19\xb3\xa6Iu\x9a\xd9P'\xab\xdf\u00c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x02TrB\x80onp\xe7@X\xd6\xe5)-\xef\xc8\xc8\u0509l\x87T\xc8\xf3\f\b\x00\x00\u07d4\xa2\r\a\x1b\x1b\x000cI}y\x90\xe1$\x9d\xab\xf3l5\xf7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\r\x8f\xf6\f\xaa\xe3\x1d\x02\xe0\xb6e\xfaC]v\xf7|\x94B\x89\x1a\x8a\x90\x9d\xfc\xef@\x00\x00\u07d4\xa2\x11\xda\x03\xcc\x0e1\xec\xceS\t\x99\x87\x18QU(\xa0\x90\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x14B\xab\x054\n\xdeh\xc9\x15\xf3\xc39\x9b\x99U\xf3\xf7\xeb\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xa2\"\"Y\u075c>=\xed\x12p\x84\xf8\b\xe9*\x18\x870,\x89\b\xc83\x9d\xaf\xedH\x00\x00\u07d4\xa2*\xde\r\xdb\\n\xf8\xd0\u034d\xe9M\x82\xb1\x10\x82\xcb.\x91\x897KW\xf3\xce\xf2p\x00\x00\u07d4\xa2L:\xb6!\x81\xe9\xa1[x\xc4b\x1eL|X\x81'\xbe&\x89\b\xcd\xe4:\x83\xd31\x00\x00\u07d4\xa2W\xadYK\u0603(\xa7\xd9\x0f\xc0\xa9\a\u07d5\xee\xca\xe3\x16\x89\x1c7\x86\xff8F\x93\x00\x00\u07d4\xa2[\bd7\xfd!\x92\u0420\xf6On\xd0D\xf3\x8e\xf3\xda2\x89\x12)\x0f\x15\x18\v\xdc\x00\x00\u07d4\xa2v\xb0X\u02d8\u060b\xee\xdbg\xe5CPl\x9a\r\x94p\u0609\x90\xaa\xfcv\xe0/\xbe\x00\x00\u07d4\xa2\x82\xe9i\xca\xc9\xf7\xa0\xe1\xc0\u0350\xf5\xd0\xc48\xacW\r\xa3\x89\"\a\xeb\x89\xfc'8\x00\x00\xe0\x94\xa2\x91\xe9\u01d9\rU-\u046e\x16\u03bc?\xca4,\xba\xf1\u044a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa2\x93\x19\xe8\x10i\xe5\xd6\r\xf0\x0f=\xe5\xad\xee5\x05\xec\xd5\xfb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa2\x96\x8f\xc1\xc6K\xac\vz\xe0\u058b\xa9I\x87Mm\xb2S\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa2\x9d[\xdat\xe0\x03GHr\xbdX\x94\xb8\x853\xffd\u00b5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa2\x9df\x1acv\xf6m\vt\xe2\xfe\x9d\x8f&\xc0$~\xc8L\x89\xdf3\x04\a\x9c\x13\xd2\x00\x00\u07d4\xa2\xa45\xdeD\xa0\x1b\xd0\ucc9eD\xe4vD\xe4j\f\xdf\xfb\x89\x1b\x1dDZz\xff\xe7\x80\x00\u07d4\xa2\xac\xe4\u0253\xbb\x1eS\x83\xf8\xact\xe1y\x06n\x81O\x05\x91\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa2\xb7\x01\xf9\xf5\xcd\u041eK\xa6+\xae\xba\u3a02W\x10X\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\u0145O\xf1Y\x9f\x98\x89,W%\xd2b\xbe\x1d\xa9\x8a\xad\xac\x89\x11\t\xff30\x10\xe7\x80\x00\u07d4\xa2\xc7\xea\xff\xdc,\x9d\x93sE l\x90\x9aR\u07f1LG\x8f\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa2\u04aabk\t\xd6\xd4\xe4\xb1?\u007f\xfcZ\x88\xbdz\xd3gB\x89\xfb\x80xPuS\x83\x00\x00\u07d4\xa2\u04cd\xe1\xc79\x06\xf6\xa7\xcan\xfe\xb9|\xf6\xf6\x9c\xc4!\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa2\xdce\xee%kY\xa5\xbdy)wO\x90K5\x8d\U000ed84a\x04\x83\xbc\xe2\x8b\xeb\t\xf8\x00\x00\u07d4\xa2\xe0h:\x80]\xe6\xa0^\xdb/\xfb\xb5\xe9o\x05p\xb67\u00c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa2\u1e2a\x90\x0e\x9c\x13\x9b?\xa1\"5OaV\xd9*\x18\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa2\u2d54\x1e\f\x01\x94K\xfe\x1d_\xb4\xe8\xa3K\x92,\u03f1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xe4`\xa9\x89\xcb\x15V_\x9e\u0327\xd1!\xa1\x8eN\xb4\x05\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa2\xec\xce,I\xf7*\t\x95\xa0\xbd\xa5z\xac\xf1\xe9\xf0\x01\xe2*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa2\xf4r\xfeO\"\xb7}\xb4\x89!\x9e\xa4\x02=\x11X*\x93)\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa2\xf7\x98\xe0w\xb0}\x86\x12N\x14\a\xdf2\x89\r\xbbKcy\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xf8k\xc0a\x88N\x9e\xef\x05d\x0e\xddQ\xa2\xf7\xc0Yli\x89llD\xfeG\xec\x05\x00\x00\u07d4\xa2\xfa\x17\xc0\xfbPl\xe4\x94\x00\x8b\x95W\x84\x1c?d\x1b\x8c\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa3\x04X\x8f\r\x85\f\xd8\u04cfv\xe9\xe8<\x1b\xf6>3>\u0789\x02(V\x01!l\x8c\x00\x00\u07d4\xa3\x05\x8cQszN\x96\xc5_.\xf6\xbd{\xb3X\x16~\u00a7\x89 \xdb:\xe4H\x1a\u0500\x00\u07d4\xa3\t\xdfT\u02bc\xe7\f\x95\xec03\x14\x9c\xd6g\x8ao\xd4\u03c9\f\x1f\x12\xc7Q\x01X\x00\x00\u07d4\xa3\nER\x0eR\x06\xd9\x00@p\xe6\xaf>{\xb2\xe8\xddS\x13\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3\x0e\n\xcbSL\x9b0\x84\xe8P\x1d\xa0\x90\xb4\xeb\x16\xa2\xc0\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3 0\x95\xed\xb7\x02\x8ehq\xce\n\x84\xf5HE\x9f\x830\n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa3!\t\x1d0\x18\x06By\xdb9\x9d+*\x88\xa6\xf4@\xae$\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\xa3#-\x06\x8dP\x06I\x03\xc9\xeb\xc5c\xb5\x15\xac\u0237\xb0\x97\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94\xa3$\x1d\x89\n\x92\xba\xf5)\b\xdcJ\xa0Irk\xe4&\xeb\u04ca\x04<-\xa6a\xca/T\x00\x00\u07d4\xa3)F&\xec)\x84\xc4;C\xdaM]\x8eFi\xb1\x1dKY\x896\xa4\xcfcc\x19\xc0\x00\x00\u07d4\xa3,\xf7\xdd\xe2\f=\xd5g\x9f\xf5\xe3%\x84\\p\u0156&b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa39\xa3\xd8\xca(\x0e'\xd2A[&\xd1\xfcy2(\xb6`C\x896\U00086577\x8f\xf0\x00\x00\u07d4\xa3<\xb4P\xf9[\xb4n%\xaf\xb5\x0f\xe0_\xee\xe6\xfb\x8c\xc8\xea\x89*\x11)\u0413g \x00\x00\u07d4\xa3?p\xdaru\xef\x05q\x04\u07e7\xdbd\xf4r\xe9\xf5\xd5S\x89\x04YF\xb0\xf9\xe9\xd6\x00\x00\u07d4\xa3@v\xf8K\xd9\x17\xf2\x0f\x83B\u024b\xa7\x9eo\xb0\x8e\xcd1\x89\u3bb5sr@\xa0\x00\x00\u07d4\xa3C\x0e\x1fd\u007f2\x1e\xd3G9V##\xc7\xd6#A\vV\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xa3O\x9dV\x8b\xf7\xaf\xd9L*[\x8a_\xf5\\f\xc4\by\x99\x89\x84}P;\"\x0e\xb0\x00\x00\u07d4\xa3V\x06\xd5\x12 \xee\u007f!F\xd4\x11X.\xe4\xeeJEYn\x89\u062a\xbe\b\v\xc9@\x00\x00\u07d4\xa3VU\x1b\xb7}OE\xa6\xd7\xe0\x9f\n\b\x9ey\u0322I\u02c9\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xa3\\\x19\x13,\xac\x195Wj\xbf\xedl\x04\x95\xfb\a\x88\x1b\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3e\x91\x8b\xfe?&'\xb9\xf3\xa8gu\xd8un\x0f\u0629K\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3n\r\x94\xb9Sd\xa8&q\xb6\b\xcb-72Ea)\t\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xa3u\xb4\xbc$\xa2N\x1fyu\x93\xcc0+/3\x10c\xfa\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3v\"\xac\x9b\xbd\xc4\xd8+u\x01]t[\x9f\x8d\xe6Z(\uc25d\xc0\\\xce(\u00b8\x00\x00\xe0\x94\xa3y\xa5\a\fP=/\xac\x89\xb8\xb3\xaf\xa0\x80\xfdE\xedK\xec\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xa3\x80-\x8ae\x9e\x89\xa2\xc4~\x90T0\xb2\xa8'\x97\x89P\xa7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa3\x83\x06\xcbp\xba\xa8\u4446\xbdh\xaap\xa8=$/)\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x84vi\x1d4\x94.\xeak/v\x88\x92#\x04}\xb4az\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x87\xceN\x96\x1axG\xf5`\a\\d\xe1YkVA\xd2\x1c\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xa3\x87\xec\xde\x0e\xe4\xc8\a\x94\x99\xfd\x8e\x03G;\u060a\xd7R*\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\x88:$\xf7\xf1f _\x1aj\x99I\al&\xa7nqx\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xa3\x8b[\xd8\x1a\x9d\xb9\u04b2\x1d^\xc7\xc6\x05R\xcd\x02\xedV\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa3\x90\xca\x12+\x85\x01\xee>^\a\xa8\xcaKA\x9f~M\xae\x15\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x93*1\xd6\xffu\xfb;\x12q\xac\xe7\u02a7\xd5\xe1\xff\x10Q\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa3\x94\xadO\xd9\xe6S\x0eo\\S\xfa\xec\xbe\u0781\xcb\x17-\xa1\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xa3\x97\x9a\x92v\n\x13Z\xdfi\xd7/u\xe1gu_\x1c\xb8\u00c9\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x9b\xfe\xe4\xae\u027du\xbd\"\u01b6r\x89\x8c\xa9\xa1\xe9]2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa3\xa2b\xaf\u0493h\x19#\b\x92\xfd\xe8O-ZYJ\xb2\x83\x89e\xea=\xb7UF`\x00\x00\u07d4\xa3\xa2\xe3\x19\xe7\u04e1D\x8bZ\xa2F\x89S\x16\f-\xbc\xbaq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\xa5{\a\x16\x13(\x04\xd6\n\xac(\x11\x97\xff+=#{\x01\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa3\xa9>\xf9\xdb\xea&6&=\x06\xd8I/jA\u0790|\"\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xa3\xae\x18y\x00}\x80\x1c\xb5\xf3RqjM\u063a'!\xde=\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa3\xba\r:6\x17\xb1\xe3\x1bNB,\xe2i\xe8s\x82\x8d]i\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xa3\xbc\x97\x9bp\x80\t/\xa1\xf9/n\x0f\xb3G\u2359PE\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa3\xbf\xf1\u07e9\x97\x16h6\f\r\x82\x82\x842\xe2{\xf5Ng\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa3\xc1J\xce(\xb1\x92\u02f0b\x14_\u02fdXi\xc6rq\xf6\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa3\xc3:\xfc\x8c\xb4pN#\x15=\xe2\x04\x9d5\xaeq3$r\x89+X\xad\u06c9\xa2X\x00\x00\u07d4\xa3\u0430<\xff\xbb&\x9fyj\u009d\x80\xbf\xb0}\xc7\u01ad\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\u0543\xa7\xb6[#\xf6\vy\x05\xf3\xe4\xaab\xaa\xc8\u007fB'\x898\xbe\xfa\x12mZ\x9f\x80\x00\u07d4\xa3\xdb6J3-\x88K\xa9;&\x17\xaeM\x85\xa1H\x9b\xeaG\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xa3\xe0Q\xfbtJ\xa3A\f;\x88\xf8\x99\xf5\xd5\u007f\x16\x8d\xf1-\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xa3\xe3\xa6\xeaP\x95s\xe2\x1b\xd0#\x9e\xce\x05#\xa7\xb7\u061b/\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\xf4\xad\x14\xe0\xbbD\xe2\xce,\x145\x9cu\xb8\xe72\xd3pT\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3\xfa\xccP\x19\\\vI3\xc8X\x97\xfe\xcc[\xbd\x99\\4\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\x03Z\xb1\xe5\x18\b!\xf0\xf3\x80\xf1\x13\x1bs\x87\xc8\u0641\u0349\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\n\xa2\xbb\xce\fr\xb4\xd0\xdf\xff\xccBq[+T\xb0\x1b\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x19\xa9\x84\x14#c&uuV`\x894\x0e\xea\x0e\xa2\b\x19\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa4!\u06f8\x9b:\aA\x90\x84\xad\x10\xc3\xc1]\xfe\x9b2\xd0\u008a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\"\xe4\xbf\v\xf7AG\u0309[\xed\x8f\x16\xd3\xce\xf3BaT\x89\x12\xef?b\xee\x116\x80\x00\u07d4\xa4%\x9f\x83E\xf7\u3a37+\x0f\xec,\xf7^2\x1f\xdaM\u0089g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xa4)\b\xe7\xfeS\x98\n\x9a\xbf@D\xe9W\xa5Kp\u973e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4)\xfa\x88s\x1f\xdd5\x0e\x8e\xcdn\xa5B\x96\xb6HO\u6549j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\xa40\x99]\xdb\x18[\x98e\xdb\xe6%9\xad\x90\xd2.Ks\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa46\xc7TS\xcc\xcaJ\x1f\x1bb\xe5\u0123\r\x86\xdd\xe4\xbeh\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa47\xfen\xc1\x03\u028d\x15\x8fc\xb34\"N\u032c[>\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4;m\xa6\xcbz\xacW\x1d\xff'\xf0\x9d9\xf8F\xf57i\xb1\x89\x14\x99\x8f2\xacxp\x00\x00\u07d4\xa4;\x81\xf9\x93V\xc0\xaf\x14\x1a\x03\x01\rw\xbd\x04,q\xc1\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4>\x19G\xa9$+5Ua\xc3\n\x82\x9d\xfe\uc881Z\xf8\x89\xd2=\x99\x96\x9f\u0591\x80\x00\u07d4\xa4H\x9aP\xea\xd5\xd5DZ{\xeeM-U6\u00a7lA\xf8\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4O\xe8\x00\xd9o\xca\xd7;qp\xd0\xf6\x10\u02cc\x06\x82\xd6\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa4T2\xa6\xf2\xac\x9dVW{\x93\x8a7\xfa\xba\xc8\xcc|F\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4f\xd7p\u0618\xd8\xc9\xd4\x05\xe4\xa0\xe5Q\xef\xaf\xcd\xe5<\xf9\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\xa4g\a1\x17X\x93\xbb\xcf\xf4\xfa\x85\u0397\xd9O\xc5\x1cK\xa8\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4kC\x87\xfbM\xcc\xe0\x11\xe7nMsT}D\x81\xe0\x9b\xe5\x89Hz\x9a0E9D\x00\x00\u07d4\xa4l\xd27\xb6>\xeaC\x8c\x8e;e\x85\xf6y\xe4\x86\b2\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4wy\u063c\x1c{\xce\x0f\x01\x1c\xcb9\xefh\xb8T\xf8\u078f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4\x82kl8\x82\xfa\xd0\xed\\\x8f\xbb%\xcc@\xccO3u\x9f\x89p\x1bC\xe3D3\xd0\x00\x00\u07d4\xa4\x87Y(E\x8e\xc2\x00]\xbbW\x8c\\\xd35\x80\xf0\xcf\x14R\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x9fR:\xa5\x13d\xcb\xc7\u0655\x16=4\xebY\r\xed/\b\x89\x90'B\x1b*\x9f\xbc\x00\x00\u07d4\xa4\xa4\x9f\v\xc8h\x8c\xc9\xe6\xdc\x04\xe1\xe0\x8dR\x10&\xe6Ut\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4\xa7\xd3\x06\xf5\x10\xcdX5\x94(\xc0\xd2\xf7\xc3`\x9dVt\u05c9\xb5\x8c\xb6\x1c<\xcf4\x00\x00\u07d4\xa4\xa8:\a8y\x9b\x97\x1b\xf2\xdep\x8c.\xbf\x91\x1c\xa7\x9e\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa4\xb0\x9d\xe6\xe7\x13\xdciTnv\xef\n\xcf@\xb9O\x02A\xe6\x89\x11}\xc0b~\xc8p\x00\x00\xe0\x94\xa4\u04b4)\xf1\xadSI\xe3\x17\x04\x96\x9e\xdc_%\xee\x8a\xca\x10\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xa4\xd6\xc8.\u076eYG\xfb\xe9\xcd\xfb\xd5H\xae3\xd9\x1aq\x91\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4\xda4E\r\"\xec\x0f\xfc\xed\xe0\x00K\x02\xf7\x87.\xe0\xb7:\x89\x05\x0fafs\xf0\x83\x00\x00\xe0\x94\xa4\xddY\xab^Q}9\x8eI\xfaS\u007f\x89\x9f\xedL\x15\xe9]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\xe6#E\x1e~\x94\xe7\u86e5\xed\x95\u0228:b\xff\xc4\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\xed\x11\xb0r\u061f\xb16u\x9f\u019bB\x8cH\xaa]L\xed\x89\x0e?\x15'\xa0<\xa8\x00\x00\u07d4\xa4\xfb\x14@\x9ag\xb4V\x88\xa8Y>\\\xc2\xcfYl\xedo\x11\x89a\t=|,m8\x00\x00\xe0\x94\xa5\x14\xd0\x0e\xddq\b\xa6\xbe\x83\x9ac\x8d\xb2AT\x18\x17A\x96\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94\xa5\"\xde~\xb6\xae\x12PR*Q13\xa9;\xd4(IG\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa5$\xa8\xcc\xccIQ\x8d\x17\n2\x82p\xa2\xf8\x813\xfb\xaf]\x89\x0f\xf7\x02-\xac\x10\x8a\x00\x00\u07d4\xa59\xb4\xa4\x01\xb5\x84\xdf\xe0\xf3D\xb1\xb4\"\xc6UC\x16~.\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa5>\xadT\xf7\x85\n\xf2\x148\xcb\xe0z\xf6\x86'\x9a1[\x86\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5C\xa0f\xfb2\xa8f\x8a\xa0sj\f\x9c\xd4\rx\t\x87'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa5gw\vj\xe3 \xbd\xdeP\xf9\x04\xd6c\xe7F\xa6\x1d\xac\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5h\xdbMW\xe4\xd6tb\xd73\u019a\x9e\x0f\xe2n!\x83'\x89;k\xff\x92f\xc0\xae\x00\x00\u07d4\xa5i\x8059\x1eg\xa4\x90\x13\xc0\x00 yY1\x14\xfe\xb3S\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\xa5p\":\xe3\u02a8QA\x8a\x98C\xa1\xacU\xdbH$\xf4\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa5s`\xf0\x02\xe0\xd6M-tE}\x8c\xa4\x85~\xe0\v\xcd\u07c9\x123\xe22\xf6\x18\xaa\x00\x00\u07d4\xa5u\xf2\x89\x1d\xcf\u0368<\\\xf0\x14t\xaf\x11\xee\x01\xb7-\u0089\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\xa5x;\xf342\xff\x82\xacI\x89\x85\xd7\xd4`\xaeg\xec6s\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xa5\x87MuF5\xa7b\xb3\x81\xa5\xc4\u01d2H:\xf8\xf2=\x1d\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa5\xa4\"\u007fl\xf9\x88%\xc0\u057a\xffS\x15u,\xcc\x1a\x13\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5\xabK\xd3X\x8fF\xcb'.V\xe9=\xee\u04c6\xba\x8bu=\x89HB\xf0A\x05\x87,\x80\x00\xe0\x94\xa5\xba\xd8e\t\xfb\xe0\xe0\xe3\xc0\xe9?m8\x1f\x1a\xf6\xe9\u0501\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa5\xc36\b;\x04\xf9G\x1b\x8cn\xd76y\xb7Mf\xc3c\uc263e\nL\x9d \xe2\x00\x00\u07d4\xa5\xcd\x129\x92\x19K4\xc4x\x13\x140;\x03\xc5IH\xf4\xb9\x89l\xfc\xc3\xd9\x1d\xa5c\x00\x00\u07d4\xa5\u0578\xb6-\x00-\xef\x92A7\x10\xd1;o\xf8\xd4\xfc}\u04c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xa5\xd9ni}F5\x8d\x11\x9a\xf7\x81\x9d\xc7\b\u007fj\xe4\u007f\xef\x8a\x03\x17\xbe\xe8\xaf3\x15\xa7\x80\x00\u07d4\xa5\xde^CO\xdc\xddh\x8f\x1c1\xb6\xfbQ,\xb1\x96rG\x01\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xa5\xe0\xfc<:\xff\xed=\xb6q\tG\xd1\xd6\xfb\x01\u007f>'m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9;I\xea|P\x9d\xe7\xc4Ml\xfe\xdd\xefY\x10\u07aa\xf2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9\xcdKt%]\"\xb7\u0672z\xe8\xddC\xedn\xd0%+\x89)\x8d\xb2\xf5D\x11\u0640\x00\xe0\x94\xa5\xf0\a{5\x1flP\\\xd5\x15\u07e6\xd2\xfa\u007f\\L\u0487\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa5\xf0u\xfd@\x135W{f\x83\u0081\xe6\xd1\x01C-\xc6\xe0\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xa5\xfe,\xe9\u007f\x0e\x8c8V\xbe\r\xe5\xf4\u0732\xce]8\x9a\x16\x89\x01=\xb0\xb8\xb6\x86>\x00\x00\u07d4\xa5\xffb\"-\x80\xc0\x13\xce\xc1\xa0\xe8\x85\x0e\xd4\xd3T\xda\xc1m\x89\vA\a\\\x16\x8b\x18\x00\x00\u07d4\xa6\t\xc2m\xd3P\xc25\xe4K+\x9c\x1d\xdd\xcc\u0429\xd9\xf87\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\f\x12\tuO]\x87\xb1\x81\xdaO\b\x17\xa8\x18Y\xef\x9f\u0609\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa6\x10\x1c\x96\x1e\x8e\x1c\x15y\x8f\xfc\xd0\xe3 \x1dw\x86\xec7:\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa6\x13Ei\x96@\x8a\xf1\xc2\xe9>\x17w\x88\xabU\x89^+2\x8a\x01Y\x19\xffG|\x88\xb8\x00\x00\u07d4\xa6\x18\x87\x81\x8f\x91J \xe3\x10w)\v\x83qZk-n\xf9\x89e\xea=\xb7UF`\x00\x00\u07d4\xa6\x1aT\xdfxJD\xd7\x1bw\x1b\x871u\t!\x13\x81\xf2\x00\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\x1c\u06ed\xf0K\x1eT\u0203\xde`\x05\xfc\xdf\x16\xbe\xb8\xeb/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa69\xac\xd9k1\xbaS\xb0\u0407c\"\x9e\x1f\x06\xfd\x10^\x9d\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6BP\x10\x04\xc9\x0e\xa9\xc9\xed\x19\x98\xba\x14\nL\xd6,o_\x89\r\x94\xfb\x8b\x10\xf8\xb1\x80\x00\u07d4\xa6D\xed\x92,\xc27\xa3\xe5\u0117\x9a\x99Tw\xf3nP\xbcb\x89\x1f\xa7=\x84]~\x96\x00\x00\u07d4\xa6F\xa9\\moY\xf1\x04\xc6T\x1dw`uz\xb3\x92\xb0\x8c\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\xa6HL\u0184\xc4\xc9\x1d\xb5>\xb6\x8aM\xa4Zjk\xda0g\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa6N_\xfbpL,\x919\xd7~\xf6\x1d\x8c\u07e3\x1dz\x88\xe9\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xa6T&\xcf\xf3x\xed#%5\x13\xb1\x9fIm\xe4_\xa7\u13ca\x01\x86P\x12|\xc3\u0700\x00\x00\u07d4\xa6jIc\xb2\u007f\x1e\xe1\x93+\x17+\xe5\x96N\r:\xe5KQ\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\xa6\u007f8\x81\x95eB:\xa8_>:\xb6\x1b\xc7c\u02eb\x89\u0749sw\xb0\"\u01be\b\x00\x00\u07d4\xa6\x8c14E\xc2-\x91\x9e\xe4l\xc2\xd0\xcd\xff\x04:uX%\x89\x04\x13t\xfd!\xb0\u0600\x00\u07d4\xa6\x8e\f0\u02e3\xbcZ\x88>T\x03 \xf9\x99\xc7\xcdU\x8e\\\x89a\x9237b\xa5\x8c\x80\x00\u07d4\xa6\x90\xf1\xa4\xb2\n\xb7\xba4b\x86 \u079c\xa0@\xc4<\x19c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa6\x9d|\xd1}HB\xfe\x03\xf6*\x90\xb2\xfb\xf8\xf6\xaf{\xb3\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa6\xa0\x82R\xc8YQw\xcc.`\xfc'Y>#y\xc8\x1f\xb1\x89\x01\x16Q\xac>zu\x80\x00\u07d4\xa6\xa0\xdeB\x1a\xe5Om\x17(\x13\b\xf5dm/9\xf7w]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa6\xb2\xd5s)s`\x10,\a\xa1\x8f\xc2\x1d\xf2\xe7I\x9f\xf4\xeb\x89\xd9o\u0390\u03eb\xcc\x00\x00\xe0\x94\xa6\xc9\x10\xceMIJ\x91\x9c\u036a\xa1\xfc;\x82\xaat\xba\x06\u03ca\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6\u3ea3\x8e\x10J\x1e'\xa4\xd8(i\xaf\xb1\xc0\xaen\xff\x8d\x89\x01\x11@\ueb4bq\x00\x00\u07d4\xa6\xee\xbb\xe4d\u04d1\x87\xbf\x80\u029c\x13\xd7 '\xec[\xa8\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa6\xf6+\x8a=\u007f\x11\"\a\x01\xab\x9f\xff\xfc\xb3'\x95\x9a'\x85\x89\x1bn)\x1f\x18\u06e8\x00\x00\u07d4\xa6\xf93\a\xf8\xbc\xe01\x95\xfe\u0387 C\xe8\xa0?{\xd1\x1a\x89\x9csK\xadQ\x11X\x00\x00\u07d4\xa7\x01\xdfy\xf5\x94\x90\x1a\xfe\x14DH^k \u00fd\xa2\xb9\xb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa7\x02L\xfdt,\x1e\xc1<\x01\xfe\xa1\x8d0B\xe6_\x1d]\xee\x8a\x02c\x11\x9a(\xab\u0430\x80\x00\u07d4\xa7\x18\xaa\xadY\xbf9\\\xba+#\xe0\x9b\x02\xfe\f\x89\x81bG\x8960<\x97\xe4hx\x00\x00\u07d4\xa7$|S\xd0Y\xeb|\x93\x10\xf6(\xd7\xfclj\nw?\b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xa7%7c\xcfJu\u07d2\xca\x1evm\xc4\xee\x8a'E\x14{\x8a\x02F7p\xe9\n\x8fP\x00\x00\u07d4\xa7.\xe6f\u0133^\x82\xa5\x06\x80\x8bD<\xeb\xd5\xc62\xc7\u0749+^:\xf1k\x18\x80\x00\x00\u07d4\xa7DD\xf9\x0f\xbbT\xe5o:\u0276\xcf\u032aH\x19\xe4aJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa7GC\x9a\xd0\u04d3\xb5\xa08a\xd7r\x962m\u8edd\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa7`{BW;\xb6\xf6\xb4\xd4\xf2<~*&\xb3\xa0\xf6\xb6\xf0\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xa7i)\x89\n{G\xfb\x85\x91\x96\x01lo\u0742\x89\u03b7U\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u0794\xa7kt?\x98\x1bi0r\xa11\xb2+\xa5\x10\x96\\/\xef\u05c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa7m?\x15bQ\xb7,\f\xcfKG\xa39<\xbdoI\xa9\u0149Hz\x9a0E9D\x00\x00\u07d4\xa7t(\xbc\xb2\xa0\xdbv\xfc\x8e\xf1\xe2\x0eF\x1a\n2\u016c\x15\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xa7u\x8c\xec\xb6\x0e\x8faL\u0396\x13~\xf7+O\xbd\awJ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7w^J\xf6\xa2:\xfa \x1f\xb7\x8b\x91^Q\xa5\x15\xb7\xa7(\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xa7\u007f>\u1793\x88\xbb\xbb\"\x15\xc6#\x97\xb9e`\x13#`\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa7\x85\x9f\xc0\u007fun\xa7\xdc\xeb\xbc\xcdB\xf0X\x17X-\x97?\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa7\x96lH\x9fLt\x8az\u902a'\xa5t%\x17g\xca\xf9\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa7\xa3\xbba9\xb0\xad\xa0\f\x1f\u007f\x1f\x9fV\u0654\xbaM\x1f\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa7\xa3\xf1S\xcd\u00c8!\xc2\f]\x8c\x82A\xb2\x94\xa3\xf8+$\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7\xa5\x17\u05ed5\x82\v\t\u0517\xfa~U@\xcd\xe9IXS\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa7\xc9\u04c8\xeb\xd8s\xe6k\x17\x13D\x83\x97\xd0\xf3\u007f\x8b\u04e8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa7\u073b\xa9\xb9\xbfgb\xc1EAlPjq\u3d17 \x9c\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa7\xe7O\v\xdb'\x8f\xf0\xa8\x05\xa6Ha\x8e\xc5+\x16o\xf1\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa7\xe87r\xbc \x0f\x90\x06\xaa*&\r\xba\xa8H=\xc5+0\x89\vB\xd56f7\xe5\x00\x00\xe0\x94\xa7\xef5\u0387\xed\xa6\u008d\xf2HxX\x15\x05>\xc9zPE\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xa7\xf9\"\f\x80G\x82k\xd5\xd5\x18?Ngjmw\xbf\xed6\x89\bPh\x97k\xe8\x1c\x00\x00\u07d4\xa8\a\x10O'\x03\xd6y\xf8\u07af\xc4B\xbe\xfe\x84\x9eB\x95\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\f\xb1s\x8b\xac\b\xd4\xf9\xc0\x8bM\xef\xf5\x15T_\xa8XO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa8\x19\xd2\xec\xe1\"\xe0(\xc8\xe8\xa0J\x06M\x02\xb9\x02\x9b\b\xb9\x8965\u026d\xc5\u07a0\x00\x00\u0794\xa8%\xfdZ\xbby&\xa6|\xf3k\xa2F\xa2K\xd2{\xe6\xf6\xed\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4\xa8(U9\x86\x9d\x88\xf8\xa9aS7Uq}~\xb6Uv\xae\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa83\x82\xb6\xe1Rg\x97J\x85P\xb9\x8fqv\xc1\xa3S\xf9\xbe\x89\xbf\xfd\xaf/\xc1\xb1\xa4\x00\x00\xe0\x94\xa8DlG\x81\xa77\xacC(\xb1\xe1[\x8a\v?\xbb\x0f\xd6h\x8a\x04\x87\x94\xd1\xf2F\x19*\x00\x00\u07d4\xa8E[A\x17e\u0590\x1e1\x1erd\x03\t\x1eB\xc5f\x83\x89\xb7:\xec;\xfe\x14P\x00\x00\xe0\x94\xa8f\x13\xe6\u0124\xc9\xc5_\\\x10\xbc\xda2\x17]\u02f4\xaf`\x8a\x02C\xd6\xc2\xe3k\xe6\xae\x00\x00\u07d4\xa8m\xb0}\x9f\x81/G\x96b-@\xe0=\x13Xt\xa8\x8at\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa8\u007fz\xbdo\xa3\x11\x94(\x96x\xef\xb6<\xf5\x84\xee^*a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa8\x80\u2a3f\x88\xa1\xa8&H\xb4\x01W\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\x9d\xf3HY\xed\xd7\xc8 \u06c8w@\xd8\xff\x9e\x15\x15|{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xa4<\x00\x91\x00al\xb4\xaeN\x03?\x1f\xc5\xd7\xe0\xb6\xf1R\x89\u0548\xd0x\xb4?M\x80\x00\u07d4\xa8\xa7\b\xe8O\x82\u06c6\xa3U\x02\x19;Ln\xe9\xa7n\xbe\x8f\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xa8\xa7\xb6\x8a\u06b4\xe3\xea\xdf\xf1\x9f\xfaX\xe3J?\xce\xc0\xd9j\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa8\xa8\xdb\xdd\x1a\x85\u047e\xee%i\xe9\x1c\xccM\t\xae\u007fn\xa1\x8a\x01:k+VHq\xa0\x00\x00\u07d4\xa8\xac\xa7H\xf9\xd3\x12\xect\u007f\x8bex\x14&\x94\xc7\xe9\xf3\x99\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xb6[\xa3\x17\x1a?w\xa65\v\x9d\xaf\x1f\x8dU\xb4\xd2\x01\xeb\x89(b\xf3\xb0\xd2\"\x04\x00\x00\u07d4\xa8\xbe\xb9\x1c+\x99\u0216J\xa9[kJ\x18K\x12i\xfc4\x83\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\xa8\xc0\xb0/\xaf\x02\xcbU\x19\u0768\x84\xde{\xbc\x8c\x88\xa2\u0681\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xa8\xc1\u05aaA\xfe=e\xf6{\xd0\x1d\xe2\xa8f\xed\x1e\u066eR\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xa8\xca\xfa\xc3\"\x80\xd0!\x02\v\xf6\xf2\xa9x(\x83\u05ea\xbe\x12\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa8\xdb\v\x9b \x14S3A<;\fb\xf5\xf5.\u0544\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\xf3\u007f\n\xb3\xa1\xd4H\xa9\xe3\xce@\x96_\x97\xa6F\b:4\x89\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4\xa8\xf8\x9d\xd5\xccnd\u05f1\xee\xac\xe0\a\x02\x02,\xd7\xd2\xf0=\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xa9\x04v\xe2\xef\xdf\xeeO8{\x0f2\xa5\x06x\xb0\xef\xb5s\xb5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\x14PF\xfa6(\xcf_\xd4\xc6\x13\x92{\xe51\xe6\xdb\x1f\u0749\x06\x12O\xee\x99;\xc0\x00\x00\u07d4\xa9\x14\u0375q\xbf\xd9=d\xdaf\xa4\xe1\b\xea\x13NP\xd0\x00\x89M\x878\x99G\x13y\x80\x00\xe0\x94\xa9\x1aZ{4\x1f\x99\xc55\x14N \xbe\x9ck;\xb4\u008eM\x8a\x01&u:\xa2$\xa7\v\x00\x00\u07d4\xa9%%Q\xa6$\xaeQ7\x19\u06beR\a\xfb\xef\xb2\xfdwI\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa9'\u050b\xb6\u02c1K\xc6\t\xcb\u02a9\x15\x1f]E\x9a'\xe1\x89\x0e\xb95\t\x00d\x18\x00\x00\u07d4\xa9)\u023dq\xdb\f0\x8d\xac\x06\b\n\x17G\xf2\x1b\x14e\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa9K\xbb\x82\x14\u03cd\xa0\xc2\xf6h\xa2\xacs\xe8bHR\x8dK\x894\n\xad!\xb3\xb7\x00\x00\x00\u07d4\xa9Q\xb2D\xffP\u03eeY\x1d^\x1a\x14\x8d\xf6\xa98\xef*\x1a\x89^\x00\x15\x84\xdf\xcfX\x00\x00\u07d4\xa9`\xb1\xca\xdd;\\\x1a\x8el\xb3\xab\xca\xf5.\xe7\xc3\xd9\xfa\x88\x89R\x8b\xc3T^Rh\x00\x00\u07d4\xa9a\x17\x1fSB\xb1s\xddp\xe7\xbf\xe5\xb5\xca#\x8b\x13\xbc\u0749\xb8'\x94\xa9$O\f\x80\x00\u07d4\xa9u\xb0w\xfc\xb4\u030e\xfc\xbf\x83\x84Y\xb6\xfa$:AY\u0589\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xa9{\xeb:H\xc4_\x15((L\xb6\xa9_}\xe4S5\x8e\u018a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\xa9~\a!DI\x9f\xe5\xeb\xbd5J\xcc~~\xfbX\x98]\b\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xa9\x86v/zO)O.\v\x172y\xad,\x81\xa2\"4X\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa9\x8f\x10\x985\xf5\xea\xcd\x05Cd|4\xa6\xb2i\xe3\x80/\xac\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa9\x97\xdf\u01d8j'\x05\bH\xfa\x1cd\u05e7\xd6\xe0z\u0322\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa9\x99\x91\u03bd\x98\xd9\xc88\xc2_zt\x16\xd9\xe2D\xca%\r\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa9\xa1\xcd\xc3;\xfd7o\x1c\rv\xfbl\x84\xb6\xb4\xac'Mh\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa9\xa8\xec\xa1\x1a#\xd6F\x89\xa2\xaa>A}\xbb=3k\xb5\x9a\x89\x0e4S\xcd;g\xba\x80\x00\u07d4\xa9\xac\xf6\x00\b\x1b\xb5[\xb6\xbf\xba\xb1\x81_\xfcN\x17\xe8Z\x95\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa9\xad\x19&\xbcf\xbd\xb31X\x8e\xa8\x197\x88SM\x98,\x98\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xa9\xaf!\xac\xbeH/\x811\x89j\"\x806\xbaQ\xb1\x94S\u00c9\x02\xb5\xe0!\x98\f\xc1\x80\x00\xe0\x94\xa9\xb2\xd2\xe0IN\xab\x18\xe0}7\xbb\xb8V\xd8\x0e\x80\xf8L\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\xbaoA;\x82\xfc\xdd\xf3\xaf\xfb\xbd\u0412\x87\xdc\xf5\x04\x15\u0289\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa9\xbe\x88\xad\x1eQ\x8b\v\xbb\x02J\xb1\xd8\xf0\xe7?y\x0e\fv\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa9\xbf\xc4\x10\xdd\xdb q\x1eE\xc0s\x87\xea\xb3\n\x05N\x19\xac\x89>\x99`\x1e\xdfNS\x00\x00\u07d4\xa9\u0522\xbc\xbe[\x9e\bi\xd7\x0f\x0f\xe2\xe1\u05aa\xcdE\xed\u0149\n\xc6\xe7z\xb6c\xa8\x00\x00\xe0\x94\xa9\xd6KO;\xb7\x85\a\"\xb5\x8bG\x8b\xa6\x917^\"NB\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa9\xd6\xf8q\xcax\x1au\x9a \xac:\u06d7,\xf1()\xa2\b\x892$\xf4'#\xd4T\x00\x00\xe0\x94\xa9\xdc\x04$\u0196\x9dy\x83X\xb3\x93\xb1\x93:\x1fQ\xbe\xe0\n\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa9\xe1\x94f\x1a\xacpN\xe9\u07a0C\x97N\x96\x92\xde\xd8J]\x89\x1a&\xa5\x14\"\xa0p\x00\x00\u07d4\xa9\xe2\x837\xe65q\x93\xd9\xe2\xcb#k\x01\xbeD\xb8\x14'\u07c9wC\"\x17\xe6\x83`\x00\x00\u07d4\xa9\xe6\xe2^ekv%Xa\x9f\x14z!\x98[\x88t\xed\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa9\xe9\xdb\xcez,\xb06\x94y\x98\x97\xbe\xd7\xc5M\x15_\u06a8\x89\n\xb5\xae\x8f\u025de\x80\x00\u07d4\xa9\xed7{}n\xc2Yq\xc1\xa5\x97\xa3\xb0\xf3\xbe\xadW\u024f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x02\x00\xf1\xd1~\x9cT\xda\x06G\xbb\x969]W\xa7\x858\u06099>\xf1\xa5\x12|\x80\x00\x00\u07d4\xaa\f\xa3ss7\x17\x8a\f\xaa\xc3\t\x9cXK\x05lV0\x1c\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xaa\x13kG\x96+\xb8\xb4\xfbT\r\xb4\xcc\xf5\xfd\xd0B\xff\xb8\u03c9\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xaa\x14B-o\n\xe5\xa7X\x19N\xd1W\x80\xc88\xd6\u007f\x1e\xe1\x8a\x06\t2\x05lD\x9d\xe8\x00\x00\u07d4\xaa\x16&\x9a\xac\x9c\r\x800h\xd8/\u01d1Q\xda\xdd3Kf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xaa\x16p&\u04da\xb7\xa8V5\x94N\xd9\xed\xb2\xbf\xeb\xa1\x18P\x8a\x01\xc1\xd5\xe2\x1bO\xcfh\x00\x00\u07d4\xaa\x1b7h\xc1m\x82\x1fX\x0ev\xc8\xe4\xc8\xe8m}\u01c8S\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x1d\xf9.Q\xdf\xf7\v\x19s\xe0\xe9$\xc6b\x87\xb4\x94\xa1x\x89\x1c\xf8J0\xa0\xa0\xc0\x00\x00\u07d4\xaa,g\x00\x96\xd3\xf990S%B~\xb9U\xa8\xa6\r\xb3\u0149l\x95Y\x06\x99#-\x00\x00\u07d4\xaa15\xcbT\xf1\x02\xcb\xef\xe0\x9e\x96\x10:\x1ayg\x18\xffT\x89\x03\"\"\xd9\xc31\x94\x00\x00\u07d4\xaa2\x1f\xdb\xd4I\x18\r\xb8\xdd\xd3O\x0f\xe9\x06\xec\x18\xee\t\x14\x89%\"H\u07b6\xe6\x94\x00\x00\xe0\x94\xaa9%\xdc\"\v\xb4\xae!w\xb2\x880x\xb6\xdc4l\xa1\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xaa?)`\x1a\x131t^\x05\xc4(0\xa1^q\x93\x8ab7\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\xaaG\xa4\xff\xc9y622\u025b\x99\xfa\xda\x0f'4\xb0\xae\xee\x8a\x01\xb8H\x9d\xf4\xdb\xff\x94\x00\x00\u07d4\xaaI=?O\xb8fI\x1c\xf8\xf8\x00\xef\xb7\xe22N\xd7\xcf\xe5\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xaaV\xa6]\u012b\xb7/\x11\xba\xe3+o\xbb\aDG\x91\xd5\u0249(\x94\xe9u\xbfIl\x00\x00\xe0\x94\xaaZ\xfc\xfd\x83\t\xc2\u07dd\x15\xbe^jPN}pf$\u014a\x01<\xf4\"\xe3\x05\xa17\x80\x00\u07d4\xaa\x8e\xb0\x82;\a\xb0\xe6\xd2\n\xad\xda\x0e\x95\xcf85\xbe\x19.\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xaa\x91#~t\r%\xa9/\u007f\xa1F\xfa\xa1\x8c\xe5m\xc6\xe1\xf3\x892$\xf4'#\xd4T\x00\x00\u07d4\xaa\x96\x0e\x10\xc5#\x91\xc5N\x158|\xc6z\xf8'\xb51m\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\x9b\xd4X\x955\xdb'\xfa+\xc9\x03\xca\x17\xd6y\xddeH\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xa8\xde\xfe\x11\xe3a?\x11\x06\u007f\xb9\x83bZ\b\x99Z\x8d\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xaa\xe6\x8b2\x14\x02\xc8\xeb\xc14h\xf3A\xc6<\f\xf0?\u0389Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xaa\xad\x1b\xaa\xdeZ\xf0N+\x17C\x9e\x93Y\x87\xbf\x8c+\xb4\xb9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xaa\xb0\n\xbfX(\xd7\xeb\xf2kG\u03ac\u0378\xba\x032Qf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaa\xbd\xb3\\\x15\x14\x98J\x03\x92\x13y?3E\xa1h\xe8\x1f\xf1\x89\x10\xca\u0216\xd29\x00\x00\x00\u07d4\xaa\xca`\xd9\xd7\x00\u7156\xbb\xbb\xb1\xf1\xe2\xf7\x0fF'\xf9\u060965\xbbw\xcbK\x86\x00\x00\u07d4\xaa\xce\u0629V;\x1b\xc3\x11\xdb\xdf\xfc\x1a\xe7\xf5u\x19\xc4D\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\u04b7\xf8\x10f\x95\a\x8el\x13\x8e\xc8\x1at\x86\xaa\xca\x1e\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xe6\x1eC\xcb\r\f\x96\xb3\x06\x99\xf7~\x00\xd7\x11\u0423\x97\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaa\xe72\xed\xa6Y\x88\u00e0\f\u007fG/5\x1cF;\x1c\x96\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xf0#\xfe\U0009091b\xb7\x8b\xb7\xab\xc9]f\x9cP\xd5(\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xaa\xf5\xb2\a\xb8\x8b\r\xe4\xac@\xd7G\xce\xe0n\x17-\xf6\xe7E\x8a\x06\xa7\xb7\x1d\u007fQ\u0410\x00\x00\u07d4\xaa\xf9\xeeK\x88lm\x1e\x95Io\xd2t#[\xf4\xec\xfc\xb0}\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xaa\xfb{\x01:\xa1\xf8T\x1c~2{\xf6P\xad\xbd\x19L \x8f\x89I\x9e\t-\x01\xf4x\x00\x00\xe0\x94\xab\t\x863\xee\xee\f\xce\xfd\xf62\xf9WTV\xf6\u0740\xfc\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xab\f\xedv.\x16a\xfa\xe1\xa9*\xfb\x14\b\x88\x94\x13yH%\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab\x14\xd2!\xe3=TF)\x19\x8c\u0416\xedc\u07e2\x8d\x9fG\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xab \x9f\u0729y\u0426G\x01\n\xf9\xa8\xb5/\xc7\xd2\r\x8c\u044a\x01\xee\xe2S,|-\x04\x00\x00\u07d4\xab'\xbax\xc8\xe5\xe3\xda\xef1\xad\x05\xae\xf0\xff\x03%r\x1e\b\x89\x19^\xce\x00n\x02\xd0\x00\x00\u07d4\xab(q\xe5\a\u01fe9eI\x8e\x8f\xb4b\x02Z\x1a\x1cBd\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xab8a\"o\xfe\xc1(\x91\x87\xfb\x84\xa0\x8e\xc3\xed\x042d\xe8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab=\x86\xbc\x82\x92~\f\xd4!\xd1F\xe0\u007f\x91\x93'\xcd\xf6\xf9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab>b\xe7z\x8b\"^A\x15\x92\xb1\xaf0\aR\xfeA$c\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xab>x)K\xa8\x86\xa0\xcf\xd5\xd3H\u007f\xb3\xa3\a\x8d3\x8dn\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xab@\x04\xc0@?~\xab\xb0\xeaXo!!V\xc4 =g\xf1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xabAo\xe3\rX\xaf\xe5\xd9EL\u007f\xce\u007f\x83\v\xccu\x03V\x89\x0657\x01\xc6\x05\u06c0\x00\u07d4\xabEr\xfb\xb1\xd7+W]i\xecj\xd1s3\x87>\x85R\xfc\x89lj\xc5L\xdahG\x00\x00\u07d4\xabZy\x01av2\ts\xe8\xcd8\xf67U0\x02%1\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab]\xfc\x1e\xa2\x1a\xdcB\u03cc?n6\x1e$?\xd0\xdaa\xe5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xabke\xea\xb8\xdf\xc9\x17\xec\x02Q\xb9\xdb\x0e\u03e0\xfa\x03(I\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xabp\x91\x93.K\u00dd\xbbU#\x80\u0293O\xd7\x16m\x1en\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xabt\x16\xff2%IQ\u02fcbN\xc7\xfbE\xfc~\u02a8r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xab|B\xc5\xe5-d\x1a\a\xadu\t\x9cb\x92\x8b\u007f\x86b/\x89\x126\x1a\xa2\x1d\x14\xba\x00\x00\u07d4\xab}T\xc7\xc6W\x0e\xfc\xa5\xb4\xb8\xcep\xf5*Ws\xe5\xd5;\x89\x0f(:\xbe\x9d\x9f8\x00\x00\u07d4\xab~\v\x83\xed\x9aBLm\x1ejo\x87\xa4\xdb\xf0d\t\xc7\u0589\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xab\x84\xa0\xf1G\xad&T\x00\x00+\x85\x02\x9aA\xfc\x9c\xe5\u007f\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab\x93\xb2n\xce\n\n\xa2\x13e\xaf\xed\x1f\xa9\xae\xa3\x1c\xd5Dh\x89W+{\x98sl \x00\x00\u07d4\xab\x94\x8aJ\xe3y\\\xbc\xa11&\xe1\x92S\xbd\xc2\x1d:\x85\x14\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xab\x9a\xd3n\\t\xce.\x969\x9fW\x83\x941\xd0\u77d6\xab\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xab\xb2\xe6\xa7*@\xban\xd9\b\u037c\xec\x91\xac\xfdwx0\xd1dcG\x8a\xe0\xfcw \x89\a?u\u0460\x85\xba\x00\x00\xe0\x94\xab\u071f\x1b\xcfM\x19\xee\x96Y\x100\xe7r\xc340/}\x83\x8a\b~^\x11\xa8\x1c\xb5\xf8\x00\x00\u07d4\xab\xde\x14{*\xf7\x89\ua946T~f\xc4\xfa&d\xd3(\xa4\x89\rk`\x81\xf3L\x12\x80\x00\xe0\x94\xab\xe0|\xedj\xc5\xdd\xf9\x91\xef\xf6\xc3\xda\"jt\x1b\xd2C\xfe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xab\xf1/\xa1\x9e\x82\xf7lq\x8f\x01\xbd\xca\x00\x03gE#\xef0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xab\xf7(\u03d3\x12\xf2!(\x02NpF\xc2Q\xf5\xdcY\x01\xed\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\xab\xf8\xff\xe0p\x8a\x99\xb5(\xcc\x1e\xd4\xe9\xceK\r\x060\xbe\x8c\x89z\xb5\u00ae\xee\xe68\x00\x00\u07d4\xab\xfc\xf5\xf2P\x91\xceW\x87_\xc6t\xdc\xf1\x04\xe2\xa7=\xd2\xf2\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xab\xfe\x93d%\xdc\u01f7K\x95P\x82\xbb\xaa\xf2\xa1\x1dx\xbc\x05\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xac\x02OYO\x95X\xf0ICa\x8e\xb0\xe6\xb2\xeeP\x1d\xc2r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\x12*\x03\xcd\x05\x8c\x12._\xe1{\x87/Hw\xf9\u07d5r\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xac\x14.\xda\x11W\xb9\xa9\xa6C\x90\xdf~j\xe6\x94\xfa\u0249\x05\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\x1d\xfc\x98Kq\xa1\x99)\xa8\x1d\x81\xf0J|\xbb\x14\a7\x03\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xac!\xc1\xe5\xa3\xd7\xe0\xb5\x06\x81g\x9d\xd6\u01d2\xdb\u0287\xde\u02ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xac(\x89\xb5\x96o\f\u007f\x9e\xdbB\x89\\\xb6\x9d\x1c\x04\xf9#\xa2\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xac(\xb5\xed\xea\x05\xb7o\x8c_\x97\bEA'|\x96ijL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac,\x8e\t\xd0d\x93\xa68XC{\xd2\v\xe0\x19bE\x03e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xac.vm\xac?d\x8fcz\xc6q?\u0770h\xe4\xa4\xf0M\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xac9\x00)\x8d\xd1M|\xc9mJ\xbbB\x8d\xa1\xba\xe2\x13\xff\xed\x8a\x05<\xa1)t\x85\x1c\x01\x00\x00\u07d4\xac=\xa5&\xcf\u0388)s\x02\xf3LI\xcaR\r\xc2q\xf9\xb2\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xacD`\xa7nm\xb2\xb9\xfc\xd1R\xd9\xc7q\x8d\x9a\xc6\xed\x8co\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xacJ\xcf\xc3n\xd6\tJ'\xe1\x18\xec\xc9\x11\xcdG>\x8f\xb9\x1f\x89a\x91>\x14@<\f\x00\x00\u07d4\xacL\xc2V\xaet\xd6$\xac\xe8\r\xb0x\xb2 \u007fW\x19\x8fk\x89lyt\x12?d\xa4\x00\x00\u07d4\xacN\xe9\xd5\x02\xe7\xd2\xd2\xe9\x9eY\xd8\xca}_\x00\xc9KM\u058965\u026d\xc5\u07a0\x00\x00\u07d4\xacR\xb7~\x15fH\x14\xf3\x9eO'\x1b\xe6A0\x8d\x91\xd6\u0309\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4\xacY\x99\xa8\x9d-\u0486\u0568\fm\xee~\x86\xaa\xd4\x0f\x9e\x12\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xac_br1H\r\r\x950.m\x89\xfc2\xcb\x1dO\xe7\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xac`\x8e+\xac\x9d\xd2\a(\u0494~\xff\xbb\xbf\x90\n\x9c\xe9K\x8a\x01EK\r\xb3uh\xfc\x00\x00\u07d4\xacm\x02\xe9\xa4k7\x9f\xacJ\u0271\u05f5\xd4{\xc8P\xce\x16\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xacoh\xe87\xcf\x19a\xcb\x14\xabGDm\xa1h\xa1m\u0789\x89Hz\x9a0E9D\x00\x00\u07d4\xacw\xbd\xf0\x0f\u0558[]\xb1+\xbe\xf8\x008\n\xbc*\x06w\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xac~\x03p'#\xcb\x16\xee'\xe2-\u0438\x15\xdc-\\\xae\x9f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xac\x8bP\x9a\xef\xea\x1d\xbf\xaf+\xb35\x00\xd6W\vo\xd9mQ\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xac\x8e\x87\xdd\xda^x\xfc\xbc\xb9\xfa\u007f\xc3\xce\x03\x8f\x9f}.4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xac\x9f\xffh\xc6\x1b\x01\x1e\xfb\xec\xf08\xedr\u06d7\xbb\x9er\x81\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xac\xa1\xe6\xbcd\xcc1\x80\xf6 \xe9M\u0171\xbc\xfd\x81X\xe4]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xa2\xa883\v\x170-\xa71\xd3\r\xb4\x8a\x04\xf0\xf2\a\xc1\x89Hz\x9a0E9D\x00\x00\u07d4\xac\xaa\xdd\xcb\xf2\x86\xcb\x0e!]\xdaUY\x8f\u007f\xf0\xf4\xad\xa5\u018965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xb9C8UK\u0108\u0308\xae-\x9d\x94\b\rk\u07c4\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xbc-\x19\xe0l;\xab\xbb[o\x05+k\xf7\xfc7\xe0r)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xbd\x18U\x89\xf7\xa6\x8ag\xaaK\x1b\xd6Pw\xf8\xc6NN!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xc0bp,Ya]4D\xefb\x14\xb8\x86+\x00\x9a\x02\xed\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xac\xc0\x90\x9f\xda.\xa6\xb7\xb7\xa8\x8d\xb7\xa0\xaa\xc8h\t\x1d\xdb\xf6\x89\x013v_\x1e&\u01c0\x00\u07d4\xac\xc1\u01c7\x86\xabM+;'q5\xb5\xba\x12>\x04\x00Hk\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xac\xc4j*U\\t\xde\u0522\xbd\tN\x82\x1b\x97\x84;@\xc0\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xac\u015f;0\xce\xff\xc5da\xcc[\x8d\xf4\x89\x02$\x0e\x0e{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xce\x01\xe0\xa7\x06\x10\xdcp\xbb\x91\xe9\x92o\xa9\x95\u007f7/\xba\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\xac\xd8\u0751\xf7\x14vLEg|c\xd8R\xe5n\xb9\xee\xce.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\u2af6;\x06\x04@\x9f\xbd\xe3\xe7\x16\u0487mD\xe8\xe5\u0749\b=lz\xabc`\x00\x00\xe0\x94\xac\xec\x91\xefiA\xcfc\v\xa9\xa3\u71e0\x12\xf4\xa2\xd9\x1d\u050a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xad\nJ\xe4x\xe9cn\x88\xc6\x04\xf2B\xcfT9\xc6\xd4V9\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4\xad\x17\x99\xaa\xd7`+E@\u0343/\x9d\xb5\xf1\x11P\xf1hz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\x1dh\xa08\xfd%\x86\x06~\xf6\xd15\xd9b\x8ey\xc2\xc9$\x89\xfe\t\xa5'\x9e*\xbc\x00\x00\u07d4\xad*\\\x00\xf9#\xaa\xf2\x1a\xb9\xf3\xfb\x06n\xfa\n\x03\xde/\xb2\x8965\xbbw\xcbK\x86\x00\x00\u07d4\xad5e\xd5+h\x8a\xdd\xed\b\x16\x8b-8r\xd1}\n&\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xad7|\xd2^\xb5>\x83\xae\t\x1a\n\x1d+E\x16\xf4\x84\xaf\u0789i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xadAM)\xcb~\xe9s\xfe\xc5N\"\xa3\x88I\x17\x86\xcfT\x02\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xadD5~\x01~$OGi1\u01f8\x18\x9e\xfe\xe8\n]\n\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xadW\xaa\x9d\x00\xd1\fC\x9b5\xef\xcc\v\xec\xac.9U\xc3\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xadY\xa7\x8e\xb9\xa7J\u007f\xbd\xae\xfa\xfa\x82\xea\u0684u\xf0\u007f\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xadZ\x8dV\x01L\xfc\xb3`\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xadr\x81!\x87?\x04V\xd0Q\x8b\x80\xabe\x80\xa2\x03pe\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xads,\x97e\x93\xee\xc4x;N.\xcdy9yx\v\xfe\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xad}\xd0S\x85\x9e\xdf\xf1\xcbo\x9d*\xcb\xedm\xd5\xe32Bo\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xad\x80\xd8e\xb8\\4\xd2\xe6IK.z\xef\xeak\x9a\xf1\x84\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xad\x8b\xfe\xf8\u018aH\x16\xb3\x91o5\xcb{\xfc\xd7\xd3\x04\tv\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xad\x8eH\xa3wi]\xe0\x146:R:(\xb1\xa4\fx\xf2\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xad\x91\n#\u0585\x06\x13eJ\xf7\x863z\u04a7\bh\xacm\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xad\x92~\x03\xd1Y\x9ax\xca+\xf0\xca\u04a1\x83\xdc\xebq\xea\xc0\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xad\x92\xca\x06n\xdb|q\x1d\xfc[\x16a\x92\xd1\xed\xf8\xe7q\x85\x8a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\xad\x94#_\u00f3\xf4z$\x13\xaf1\u8111I\b\xef\fE\x89\x1b\x1b\x01B\xd8\x15\x84\x00\x00\u07d4\xad\x9e\x97\xa0H/5:\x05\xc0\xf7\x92\xb9w\xb6\xc7\xe8\x11\xfa_\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xad\x9fL\x89\n;Q\x1c\xeeQ\xdf\xe6\xcf\xd7\xf1\t;vA,\x89\x1bv|\xbf\xeb\f\xe4\x00\x00\u07d4\xad\xaa\x0eT\x8c\x03Z\xff\xedd\xcag\x8a\x96?\xab\xe9\xa2k\xfd\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xad\xb9H\xb1\xb6\xfe\xfe }\xe6^\x9b\xbc-\xe9\x8e`]\vW\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\xc1\x9e\xc85\xaf\xe3\u5347\u0713\xa8\xa9!<\x90E\x13&\x89j\xdb\xe54\"\x82\x00\x00\x00\u07d4\xad\xc8\"\x8e\xf9(\xe1\x8b*\x80}\x00\xfb1\xfcgX\x15\xaa\x00\x00\u07d4\xad\xff\r\x1d\v\x97G\x1ev\u05c9\xd2\u470at\xf9\xbdT\xff\x89e\xea=\xb7UF`\x00\x00\u07d4\xae\x06,D\x86\x18d0u\xdez\x0004-\xce\xd6=\xba\u05c9,\xc6\u034c\u0082\xb3\x00\x00\xe0\x94\xae\x10\xe2z\x01O\r0k\xaf&mH\x97\u021a\xee\xe2\xe9t\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xae\x12k8,\xf2W\xfa\xd7\xf0\xbc}\x16)~T\xccrg\u0689\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x13\xa0\x85\x11\x11\x0f2\xe5;\xe4\x12xE\xc8C\xa1\xa5|{\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xae\x17\x9aF\r\xb6c&t=$\xe6u#\xa5{$m\xaf\u007f\x8a\x01\x00\a\xae|\xe5\xbb\xe4\x00\x00\u07d4\xae\"(ey\x90y\xaa\xf4\xf0gJ\f\u06ab\x02\xa6\xd5p\xff\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xae#\x9a\xcf\xfdN\xbe.\x1b\xa5\xb4\x17\x05r\xdcy\xcce3\xec\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xae/\x9c\x19\xacv\x13e\x94C#\x93\xb0G\x1d\b\x90!d\u04c9%\xdf\x05\u01a8\x97\xe4\x00\x00\u07d4\xae4\x86\x1d4\"S\x19O\xfcfR\xdf\xdeQ\xabD\xca\xd3\xfe\x89\x19F\bhc\x16\xbd\x80\x00\u07d4\xae6\xf7E!!\x91>\x80\x0e\x0f\xcd\x1ae\xa5G\x1c#\x84o\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xae?\x98\xa4C\xef\xe0\x0f>q\x1dR]\x98\x94\u071aa\x15{\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xaeG\xe2`\x9c\xfa\xfe6\x9df\xd4\x15\xd99\xde\x05\b\x1a\x98r\x8a\x05\xba\xec\xf0%\xf9\xb6P\x00\x00\u07d4\xaeO\x12.5\xc0\xb1\xd1\xe4\x06\x92\x91E|\x83\xc0\u007f\x96_\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaePU\x81L\xb8\xbe\f\x11{\xb8\xb1\xc8\u04b6;F\x98\xb7(\x89\x01\xbc\x93.\xc5s\xa3\x80\x00\u07d4\xaeS\x8cs\u0173\x8d\x8dXM~\xbd\xad\xef\xb1\\\xab\xe4\x83W\x896'\xe8\xf7\x127<\x00\x00\u07d4\xaeW\xcc\x12\x9a\x96\xa8\x99\x81\xda\xc6\r/\xfb\x87}]\xc5\xe42\x89<:#\x94\xb3\x96U\x00\x00\u07d4\xaeZ\xa1\xe6\u00b6\x0fo\xd3\xef\xe7!\xbbJq\x9c\xbe=o]\x89+$\u01b5Z^b\x00\x00\u07d4\xae\\\x9b\xda\xd3\xc5\u0221\"\x04D\xae\xa5\xc2)\xc1\x83\x9f\x1dd\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xae\\\xe35Z{\xa9\xb32v\f\tP\u00bcE\xa8_\xa9\xa0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xae]\"\x1a\xfc\xd3\u0493U\xf5\b\xea\xdf\xca@\x8c\xe3<\xa9\x03\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xaec[\xf781\x11\x9d-)\xc0\xd0O\xf8\xf8\xd8\u0425zF\x89Hz\x9a0E9D\x00\x00\xe0\x94\xaed\x81U\xa6X7\x0f\x92\x9b\xe3\x84\xf7\xe0\x01\x04~I\xddF\x8a\x02\xdf$\xae2\xbe D\x00\x00\xe0\x94\xaeo\fs\xfd\xd7|H\x97'Q!t\u0675\x02\x96a\x1cL\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xaep\xe6\x9d,J\n\xf8\x18\x80{\x1a'\x05\xf7\x9f\u0435\xdb\u01095e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xaew9\x12N\xd1S\x05%\x03\xfc\x10\x14\x10\xd1\xff\xd8\xcd\x13\xb7\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xaex\xbb\x84\x919\xa6\xba8\xae\x92\xa0\x9ai`\x1c\xc4\xcbb\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xae\x84\"\x10\xf4M\x14\u0124\u06d1\xfc\x9d;;P\x01O{\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xae\x84.\x81\x85\x8e\xcf\xed\xf6Plhm\xc2\x04\xac\x15\xbf\x8b$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xae\x89T\xf8\xd6\x16m\xe5\a\xcfa)}\x0f\xc7\xcak\x9eq(\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x9e\xcdk\u0755.\xf4\x97\xc0\x05\n\u0aca\x82\xa9\x18\x98\u0389\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xae\x9f\\?\xbb\xe0\u027c\xbf\x1a\xf8\xfft\xea(\v:]\x8b\b\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xae\xad\x88\u0589Ak\x1c\x91\xf26D!7[}\x82\xd0RR\n\xfb\\Wm\x9f~\xb9>\u048a\r\xd0A \xba\t\xcf\xe6\x00\x00\u07d4\xae\xc2\u007f\xf5\xd7\xf9\xdd\u0691\x18?F\xf9\xd5%C\xb6\xcd+/\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xae\xe4\x9dh\xad\xed\xb0\x81\xfdCpZ_x\xc7x\xfb\x90\xdeH\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xae\xf5\xb1\"X\xa1\x8d\xec\a\xd5\xec.1et\x91\x9dy\xd6\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xae\xfc\xfe\x88\xc8&\xcc\xf11\xd5N\xb4\ua7b8\x0ea\xe1\xee%\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xaf\x06\xf5\xfam\x12\x14\xecC\x96}\x1b\xd4\xdd\xe7J\xb8\x14\xa98\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4\xaf\x11H\xefl\x8e\x10=u0\xef\xc9\x16y\u026c'\x00\t\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaf >\"\x9d~mA\x9d\xf47\x8e\xa9\x87\x15Q_c\x14\x85\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xaf X\xc7(,\xf6|\x8c<\xf90\x13<\x89a|\xe7])\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\xaf&\xf7\u01bfE> x\xf0\x89S\u4c80\x04\xa2\xc1\xe2\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xaf0\x87\xe6.\x04\xbf\x90\rZT\xdc>\x94bt\u0692B;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf6\x14\u0736\x8a6\xe4ZN\x91\x1ebybG\"-Y[\x89z\x81\x06_\x11\x03\xbc\x00\x00\u07d4\xaf6\x15\u01c9\u0431\x15*\xd4\xdb%\xfe]\xcf\"(\x04\xcfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaf<\xb5\x96Y3\xe7\xda\u0603i;\x9c>\x15\xbe\xb6\x8aHs\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xafD\x93\xe8R\x1c\xa8\x9d\x95\xf5&|\x1a\xb6?\x9fEA\x1e\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xafL\xf4\x17\x85\x16\x1fW\x1d\f\xa6\x9c\x94\xf8\x02\x1fA)N\u028a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xafR\x9b\xdbE\x9c\xc1\x85\xbe\xe5\xa1\u014b\xf7\xe8\xcc\xe2\\\x15\r\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xafg\xfd>\x12\u007f\xd9\xdc6\xeb?\xcdj\x80\u01feOu2\xb2\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xafw\x1094Z40\x01\xbc\x0f\x8aY#\xb1&\xb6\rP\x9c\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xaf\u007fy\xcbAZ\x1f\xb8\u06fd\tF\a\xee\x8dA\xfb|Z;\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaf\x87\xd27\x1e\xf3x\x95\u007f\xbd\x05\xba/\x1df\x93\x1b\x01\u2e09%\xf2s\x93=\xb5p\x00\x00\u07d4\xaf\x88\x0f\xc7V}U\x95\xca\xcc\xe1\\?\xc1L\x87B\xc2l\x9e\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xaf\x8e\x1d\xcb1L\x95\r6\x87CM0\x98X\xe1\xa8s\x9c\u0509\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xaf\x99-\xd6i\xc0\x88>U\x15\xd3\xf3\x11*\x13\xf6\x17\xa4\xc3g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xa1\u056d8\xfe\xd4GY\xc0[\x89\x93\xc1\xaa\r\xac\xe1\x9f@\x89\x04V9\x18$O@\x00\x00\xe0\x94\xaf\xa59XnG\x19\x17J;F\xb9\xb3\xe6c\xa7\u0475\xb9\x87\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xa6\x94n\xff\xd5\xffS\x15O\x82\x01\x02S\xdfG\xae(\f\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xaf\xc8\xeb\u860b\xd4\x10Z\xccL\x01\x8eTj\x1e\x8f\x9cx\x88\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xaf\xcc}\xbb\x83V\xd8B\xd4:\xe7\xe2<\x84\"\xb0\"\xa3\b\x03\x8a\x06o\xfc\xbf\xd5\xe5\xa3\x00\x00\x00\u07d4\xaf\xd0\x19\xff6\xa0\x91U4ki\x97H\x15\xa1\xc9\x12\xc9\n\xa4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xda\xc5\xc1\xcbV\xe2E\xbfp3\x00f\xa8\x17\uabecL\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xdd\x1bxab\xb81~ \xf0\xe9y\xf4\xb2\xceHmv]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xf1\x04Z\xdf'\xa1\xaa2\x94a\xb2M\xe1\xba\u950ai\x8b\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\xaf\xf1\a\x96\v~\xc3N\u0590\xb6e\x02M`\x83\x8c\x19\x0fp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xaf\xf1\x1c\xcfi\x93\x04\xd5\xf5\x86*\xf8`\x83E\x1c&\xe7\x9a\xe5\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xaf\xf1at\nm\x90\x9f\xe9\x9cY\xa9\xb7yE\xc9\x1c\xc9\x14H\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xaf\xfc\x99\xd5\ubd28O\xe7x\x8d\x97\xdc\xe2t\xb08$\x048\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xfe\xa0G7\"\xcb\u007f\x0e\x0e\x86\xb9\xe1\x18\x83\xbfB\x8d\x8dT\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xb0\t\x96\xb0Vn\xcb>rC\xb8\"y\x88\u0733R\xc2\x18\x99\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xb0\x1e8\x9b(\xa3\x1d\x8eI\x95\xbd\xd7\xd7\xc8\x1b\xee\xab\x1eA\x19\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0-\x06(s3EE\u03a2\x92\x18\xe4\x05w`Y\x0ft#\x89\xac\xb6\xa1\xc7\xd9:\x88\x00\x00\u07d4\xb0/\xa2\x93\x87\xec\x12\xe3\u007fi\"\xacL\xe9\x8c[\t\xe0\xb0\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb06\x91k\xda\u03d4\xb6\x9eZ\x8ae`)u\xeb\x02a\x04\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb0A1\x0f\xe9\xee\u0586L\xed\u053e\xe5\x8d\xf8\x8e\xb4\xed<\xac\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb0U\xafL\xad\xfc\xfd\xb4%\xcfe\xbad1\a\x8f\a\xec\u056b\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0W\x11S\xdb\x1cN\u05ec\xae\xfe\x13\xec\xdf\xdbr\xe7\xe4\xf0j\x8a\x11\f\xffyj\xc1\x95 \x00\x00\u07d4\xb0n\xab\t\xa6\x10\u01a5=V\xa9F\xb2\xc44\x87\xac\x1d[-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0rI\xe0U\x04J\x91U5\x9a@)7\xbb\xd9T\xfeH\xb6\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0v\x182\x8a\x90\x13\a\xa1\xb7\xa0\xd0X\xfc\xd5xn\x9er\xfe\x8a\x06gI]JC0\xce\x00\x00\u07d4\xb0y\xbbM\x98f\x14:m\xa7*\xe7\xac\x00\"\x06)\x811\\\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4\xb0{\xcc\bZ\xb3\xf7)\xf2D\x00Ah7\xb6\x996\xba\x88s\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xb0{\xcf\x1c\xc5\xd4F.Q$\xc9e\xec\xf0\xd7\r\xc2z\xcau\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xb0|\xb9\xc1$\x05\xb7\x11\x80uC\u0113De\xf8\u007f\x98\xbd-\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb0\u007f\u07af\xf9\x1dD`\xfel\xd0\u8870\xbd\x8d\"\xa6.\x87\x8a\x01\x1d%)\xf3SZ\xb0\x00\x00\xe0\x94\xb0\x9f\xe6\xd44\x9b\x99\xbc7\x93\x80T\x02-T\xfc\xa3f\xf7\xaf\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\xb0\xaa\x00\x95\f\x0e\x81\xfa2\x10\x17>r\x9a\xaf\x16:'\xcdq\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb0\xacN\xfff\x80\xee\x14\x16\x9c\xda\xdb\xff\xdb0\x80Om%\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb0\xb3j\xf9\xae\xee\u07d7\xb6\xb0\"\x80\xf1\x14\xf19\x84\xea2`\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xb0\xb7y\xb9K\xfa<.\x1fX{\u031c~!x\x92\"7\x8f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xb0\xba\xeb0\xe3\x13wlLm$t\x02\xbaAg\xaf\u0361\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb0\xbb)\xa8a\xea\x1dBME\xac\u053f\u0112\xfb\x8e\xd8\t\xb7\x89\x04V9\x18$O@\x00\x00\xe0\x94\xb0\xc1\xb1w\xa2 \xe4\x1f|t\xd0|\u0785i\xc2\x1cu\xc2\xf9\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xb0\xc7\xceL\r\xc3\u00bb\xb9\x9c\xc1\x85{\x8aE_a\x17\x11\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb0\xce\xf8\xe8\xfb\x89\x84\xa6\x01\x9f\x01\xc6y\xf2r\xbb\xe6\x8f\\w\x89\b=lz\xabc`\x00\x00\xe0\x94\xb0\xd3+\xd7\xe4\u6577\xb0\x1a\xa3\xd0Ao\x80U}\xba\x99\x03\x8a\x03s\x9f\xf0\xf6\xe6\x130\x00\x00\xe0\x94\xb0\xd3\u0247+\x85\x05n\xa0\xc0\xe6\xd1\xec\xf7\xa7~<\u6ac5\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xb0\xe4i\u0206Y8\x15\xb3IV8Y]\xae\xf0f_\xaeb\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xb0\xe7`\xbb\a\xc0\x81wsE\xe0W\x8e\x8b\u0218\"mN;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\x040\x04\xec\x19A\xa8\xcfO+\x00\xb1W\x00\u076co\xf1~\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\x05\xdd=\x98|\xff\xd8\x13\xe9\xc8P\n\x80\xa1\xad%}V\u0189lj\xccg\u05f1\xd4\x00\x00\u07d4\xb1\x0f\u04a6G\x10/\x88\x1ft\xc9\xfb\xc3}\xa62\x94\x9f#u\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb1\x15\xee:\xb7d\x1e\x1a\xa6\xd0\x00\xe4\x1b\xfc\x1e\xc7!\f/2\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xb1\x17\x8a\xd4s\x83\xc3\x1c\x814\xa1\x94\x1c\xbc\xd4t\xd0bD\xe2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb1\x17\x95\x89\u1779\xd4\x15W\xbb\xec\x1c\xb2L\xcc-\xec\x1c\u007f\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb1\x19\u76a9\xb9\x16Re\x81\xcb\xf5!\xefGJ\xe8M\xcf\xf4\x89O\xba\x10\x01\xe5\xbe\xfe\x00\x00\u07d4\xb1\x1f\xa7\xfb'\n\xbc\xdfZ.\xab\x95\xaa0\u013566\uffc9+^:\xf1k\x18\x80\x00\x00\u07d4\xb1$\xbc\xb6\xff\xa40\xfc\xae.\x86\xb4_'\xe3\xf2\x1e\x81\xee\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1)\xa5\xcbq\x05\xfe\x81\v\u0615\xdcr\x06\xa9\x91\xa4TT\x88\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\xb1.\xd0{\x8a8\xadU\x066?\xc0z\vmy\x996\xbd\xaf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb14\xc0\x049\x1a\xb4\x99(x3zQ\xec$/B(WB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1?\x93\xaf0\xe8\xd7fs\x81\xb2\xb9[\xc1\xa6\x99\xd5\xe3\xe1)\x89\x16\u012b\xbe\xbe\xa0\x10\x00\x00\u07d4\xb1E\x92\x85\x86>\xa2\xdb7Y\xe5F\u03b3\xfb7a\xf5\x90\x9c\x89<\xd7*\x89@\x87\xe0\x80\x00\u07d4\xb1F\xa0\xb9%U<\xf0o\xca\xf5J\x1bM\xfe\xa6!)\aW\x89lnY\xe6|xT\x00\x00\xe0\x94\xb1Jz\xaa\x8fI\xf2\xfb\x9a\x81\x02\u05bb\xe4\u010a\xe7\xc0o\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1K\xbe\xffpr\tu\xdca\x91\xb2\xa4O\xf4\x9f&r\x87<\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xb1L\xc8\xde3\xd63\x826S\x9aH\x90 \xceFU\xa3+\u018a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1M\xdb\x03\x86\xfb`c\x98\xb8\xccGVZ\xfa\xe0\x0f\xf1\xd6j\x89\xa1*\xff\b>f\xf0\x00\x00\u07d4\xb1S\xf8(\xdd\amJ|\x1c%t\xbb-\xee\x1aD\xa3\x18\xa8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1T\x0e\x94\xcf\xf3F\\\xc3\u0447\xe7\xc8\u3f6f\x98FY\u2262\x15\xe4C\x90\xe33\x00\x00\u07d4\xb1X\xdbC\xfab\xd3\x0ee\xf3\u041b\xf7\x81\u01f6sr\uba89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1ar_\xdc\xed\xd1yR\xd5{#\xef([~K\x11i\xe8\x89\x02\xb6\xdf\xed6d\x95\x80\x00\u07d4\xb1dy\xba\x8e}\xf8\xf6>\x1b\x95\xd1I\u0345)\xd75\xc2\u0689-\xe3:j\xac2T\x80\x00\u07d4\xb1f\xe3}.P\x1a\xe7<\x84\x14+_\xfbZ\xa6U\xddZ\x99\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1\x83\xeb\xeeO\xcbB\xc2 \xe4wt\xf5\x9dlT\xd5\xe3*\xb1\x89V\xf7\xa9\xc3<\x04\xd1\x00\x00\u07d4\xb1\x88\a\x84D\x02~8g\x98\xa8\xaehi\x89\x19\xd5\xcc#\r\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xb1\x89j7\xe5\u0602Z-\x01vZ\xe5\xdeb\x99w\u0783R\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb1\x8eg\xa5\x05\n\x1d\xc9\xfb\x19\t\x19\xa3=\xa88\xefDP\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb1\xa2\xb4:t3\xdd\x15\v\xb8\"'\xedQ\x9c\u05b1B\u04c2\x89\x94mb\rtK\x88\x00\x00\u07d4\xb1\xc0\u040b6\xe1\x84\xf9\x95*@7\xe3\xe5:f}\a\nN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\xc3(\xfb\x98\xf2\xf1\x9a\xb6do\n|\x8cVo\xdaZ\x85@\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\xb1\xc7Qxi9\xbb\xa0\xd6q\xa6w\xa1X\u01ab\xe7&^F\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xb1\xcdK\xdf\xd1\x04H\x9a\x02n\u025dYs\a\xa0By\xf1s\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb1\u03d4\xf8\t\x15\x05\x05_\x01\n\xb4\xba\u0196\xe0\xca\x0fg\xa1\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xb1\u05b0\x1b\x94\xd8T\xfe\x8b7J\xa6^\x89\\\xf2*\xa2V\x0e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\xb1\u06e5%\v\xa9bWU$n\x06yg\xf2\xad/\a\x91\u078a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xb1\xe2\u0755\xe3\x9a\xe9w\\U\xae\xb1?\x12\xc2\xfa#0S\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\xe6\xe8\x10\xc2J\xb0H\x8d\xe9\xe0\x1eWH7\x82\x9f|w\u0409\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1\xe9\xc5\xf1\xd2\x1eauzk.\xe7Y\x13\xfcZ\x1aA\x01\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\x03\u049elV\xb9&\x99\u0139-\x1fo\x84d\x8d\xc4\u03fc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x16\xdcY\xe2|=ry\xf5\xcd[\xb2\xbe\u03f2`n\x14\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x1byy\xbf|\\\xa0\x1f\xa8-\xd6@\xb4\x1c9\xe6\u01bcu\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb2#\xbf\x1f\xbf\x80H\\\xa2\xb5V}\x98\xdb{\xc3SM\xd6i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2-PU\xd9b15\x96\x1ej\xbd'<\x90\xde\xea\x16\xa3\xe7\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb2-\xad\xd7\xe1\xe0R2\xa927\xba\xed\x98\xe0\u07d2\xb1\x86\x9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb24\x03_uDF<\xe1\xe2+\xc5S\x06F\x84\xc5\x13\xcdQ\x89\r\x89\xfa=\u010d\xcf\x00\x00\u07d4\xb2G\u03dcr\xecH*\xf3\xea\xa7Ye\x8fy=g\nW\f\x891p\x8a\xe0\x04T@\x00\x00\u07d4\xb2ghA\xee\x9f-1\xc1r\xe8#\x03\xb0\xfe\x9b\xbf\x9f\x1e\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb2y\xc7\xd3U\u0088\x03\x92\xaa\u046a!\xee\x86|;5\a\u07c9D[\xe3\xf2\uf1d4\x00\x00\u07d4\xb2|\x1a$ L\x1e\x11\x8du\x14\x9d\xd1\t1\x1e\a\xc0s\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb2\x81\x81\xa4X\xa4@\xf1\u01bb\x1d\xe8@\x02\x81\xa3\x14\x8fL5\x89\x14b\fW\xdd\xda\xe0\x00\x00\xe0\x94\xb2\x82E\x03|\xb1\x92\xf7W\x85\u02c6\xcb\xfe|\x93\r\xa2X\xb0\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xb2\x87\xf7\xf8\xd8\u00c7,\x1bXk\xcd}\n\xed\xbf~s'2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb2\x8b\xb3\x9f4fQ|\xd4o\x97\x9c\xf5\x96S\xee}\x8f\x15.\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xb2\x8d\xbf\xc6I\x98\x94\xf7:q\xfa\xa0\n\xbe\x0fK\xc9\u045f*\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\x96\x8f}5\xf2\b\x87\x161\xc6h{?=\xae\xab\xc6al\x89\bu\xc4\u007f(\x9fv\x00\x00\u07d4\xb2\x9f[|\x190\xd9\xf9z\x11^\x06pf\xf0\xb5M\xb4K;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb2\xa1D\xb1\xeag\xb9Q\x0f\"g\xf9\xda9\xd3\xf9=\xe2fB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xa2\xc2\x11\x16\x12\xfb\x8b\xbb\x8e}\xd97\x8dg\xf1\xa3\x84\xf0P\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb2\xa4\x98\xf0;\xd7\x17\x8b\u0627\x89\xa0\x0fR7\xafy\xa3\xe3\xf8\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\xb2\xaa/\x1f\x8e\x93\xe7\x97\x13\xd9,\xea\x9f\xfc\xe9\xa4\n\xf9\xc8-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xb5\x16\xfd\u045e\u007f8d\xb6\xd2\xcf\x1b%*AV\xf1\xb0;\x89\x02\xe9\x83\xc7a\x15\xfc\x00\x00\u07d4\xb2\xb7\u0374\xffKa\u0577\xce\v\"p\xbb\xb5&\x97C\xec\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xbd\xbe\u07d5\x90\x84v\xd7\x14\x8a7\f\u0193t6(\x05\u007f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2\xbf\xaaX\xb5\x19l\\\xb7\xf8\x9d\xe1_G\x9d\x188\xdeq=\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xb2\xc5>\xfa3\xfeJ:\x1a\x80 \\s\xec;\x1d\xbc\xad\x06\x02\x89h\x01\u06b3Y\x18\x93\x80\x00\xe0\x94\xb2\xd06\x05\x15\xf1}\xab\xa9\x0f\u02ec\x82\x05\xd5i\xb9\x15\u05ac\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xb2\xd1\xe9\x9a\xf9\x121\x85\x8epe\xdd\x19\x183\r\xc4\xc7G\u054a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xb2\u066b\x96d\xbc\xf6\xdf <4o\u0192\xfd\x9c\xba\xb9 ^\x89\x17\xbex\x97`e\x18\x00\x00\u07d4\xb2\u0777\x86\xd3yN'\x01\x87\xd0E\x1a\xd6\u0237\x9e\x0e\x87E\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\xe0\x85\xfd\xdd\x14h\xba\aA['NsN\x11#\u007f\xb2\xa9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\xe9\xd7k\xf5\x0f\xc3k\xf7\u04d4Kc\xe9\u0288\x9bi\x99h\x89\x902\xeab\xb7K\x10\x00\x00\xe0\x94\xb2\xf9\xc9r\xc1\xe9swU\xb3\xff\x1b0\x88s\x83\x969[&\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xb2\xfc\x84\xa3\xe5\nP\xaf\x02\xf9M\xa08>\u055fq\xff\x01\u05ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xb3\x05\v\xef\xf9\xde3\xc8\x0e\x1f\xa1R%\xe2\x8f,A:\xe3\x13\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xb3\x11\x96qJH\xdf\xf7&\xea\x943\xcd)\x12\xf1\xa4\x14\xb3\xb3\x89\x91Hx\xa8\xc0^\xe0\x00\x00\xe0\x94\xb3\x14[tPm\x1a\x8d\x04|\xdc\xdcU9*{SPy\x9a\x8a\x1bb)t\x1c\r=]\x80\x00\u07d4\xb3 \x83H6\xd1\xdb\xfd\xa9\xe7\xa3\x18M\x1a\xd1\xfdC \xcc\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3#\u073f.\xdd\xc58.\u4efb \x1c\xa3\x93\x1b\xe8\xb48\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb3$\x00\xfd\x13\xc5P\t\x17\xcb\x03{)\xfe\"\xe7\xd5\"\x8f-\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb3%gL\x01\xe3\xf7)\rR&3\x9f\xbe\xacg\xd2!'\x9f\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xb3(%\xd5\xf3\xdb$\x9e\xf4\xe8\\\xc4\xf31S\x95\x89v\u8f09\x1b-\xf9\xd2\x19\xf5y\x80\x00\u07d4\xb3*\xf3\xd3\xe8\xd0u4I&To.2\x88{\xf9;\x16\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3/\x1c&\x89\xa5\xcey\xf1\xbc\x97\v1XO\x1b\xcf\"\x83\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3<\x03#\xfb\xf9\xc2l\x1d\x8a\xc4N\xf7C\x91\u0400F\x96\u0689\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb3O\x04\xb8\xdbe\xbb\xa9\xc2n\xfcL\xe6\xef\xc5\x04\x81\xf3\xd6]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3U}9\xb5A\x1b\x84D__T\xf3\x8fb\xd2qM\x00\x87\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xb3X\xe9|p\xb6\x05\xb1\xd7\xd7)\u07f6@\xb4<^\xaf\xd1\xe7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xb3^\x8a\x1c\r\xac~\x0ef\u06ecsjY*\xbdD\x01%a\x88\xcf\xceU\xaa\x12\xb3\x00\x00\xe0\x94\xb3fx\x94\xb7\x86<\x06\x8a\xd3D\x87?\xcf\xf4\xb5g\x1e\x06\x89\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3qw1\xda\xd6Q2\xday-\x87`0\xe4j\xc2'\xbb\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3s\x1b\x04l\x8a\u0195\xa1'\xfdy\u0425\xd5\xfaj\xe6\xd1.\x89lO\xd1\xee$nx\x00\x00\u07d4\xb3|+\x9fPc{\xec\xe0\u0295\x92\b\xae\xfe\xe6F;\xa7 \x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb3\x88\xb5\xdf\xec\xd2\xc5\u4d56W|d%V\xdb\xfe'xU\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3\x8cNS{]\xf90\xd6Zt\xd0C\x83\x1dkH[\xbd\xe4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb3\x919Wa\x94\xa0\x86a\x95\x15\x1f3\xf2\x14\n\xd1\u0306\u03ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb3\x9fL\x00\xb2c\f\xab}\xb7)^\xf4=G\xd5\x01\xe1\u007f\u05c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb3\xa6K\x11vrOT\t\xe1AJ5#f\x1b\xae\xe7KJ\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xb3\xa6\xbdA\xf9\xd9\xc3 \x1e\x05\v\x87\x19\x8f\xbd\xa3\x994\"\x10\x89\xc4a\xe1\xdd\x10)\xb5\x80\x00\u07d4\xb3\xa8\xc2\xcb}5\x8eW9\x94\x1d\x94[\xa9\x04Z\x02:\x8b\xbb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xaeT\xfb\xa0\x9d>\xe1\u05bd\xd1\xe9W\x929\x19\x02L5\xfa\x89\x03\x8d,\xeee\xb2*\x80\x00\u07d4\xb3\xb7\xf4\x93\xb4J,\x8d\x80\xecx\xb1\xcd\xc7Ze+s\xb0l\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb3\xc2(s\x1d\x18m-\xed[_\xbe\x00Lfl\x8eF\x9b\x86\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4\xb3\xc2``\x9b\x9d\xf4\t^l]\xff9\x8e\xeb^-\xf4\x99\x85\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xb3\xc6[\x84Z\xbal\xd8\x16\xfb\xaa\xe9\x83\xe0\xe4l\x82\xaa\x86\"\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xc9H\x11\xe7\x17[\x14\x8b(\x1c\x1a\x84[\xfc\x9b\xb6\xfb\xc1\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3\xe2\x0e\xb4\xde\x18\xbd\x06\x02!h\x98\x94\xbe\u5bb2SQ\xee\x89\x03\xfc\x80\xcc\xe5\x16Y\x80\x00\u07d4\xb3\xe3\xc49\x06\x98\x80\x15f\x00\u0089.D\x8dA6\xc9-\x9b\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xb3\xf8*\x87\xe5\x9a9\xd0\u0480\x8f\aQ\xebr\xc22\x9c\xdc\u014a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb3\xfc\x1dh\x81\xab\xfc\xb8\xbe\xcc\v\xb0!\xb8\xb7;r3\u0751\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xb4\x05\x94\xc4\xf3fN\xf8I\u0326\"{\x8a%\xaai\t%\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb4\x1e\xaf]Q\xa5\xba\x1b\xa3\x9b\xb4\x18\u06f5O\xabu\x0e\xfb\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4$\u058d\x9d\r\x00\xce\xc1\x93\x8c\x85N\x15\xff\xb8\x80\xba\x01p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4%bs\x96+\xf61\xd0\x14U\\\xc1\xda\r\xcc1akI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb40g\xfep\u0675Ys\xbaX\xdcd\xdd\u007f1\x1eUBY\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb46W\xa5\x0e\xec\xbc0w\xe0\x05\xd8\xf8\xd9O7xv\xba\u0509\x01\xec\x1b:\x1f\xf7Z\x00\x00\u07d4\xb4<'\xf7\xa0\xa1\"\bK\x98\xf4\x83\x92%A\u0203l\xee,\x89&\u009eG\u0104L\x00\x00\xe0\x94\xb4A5v\x86\x9c\b\xf9Q*\xd3\x11\xfe\x92Y\x88\xa5-4\x14\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb4F\x05U$q\xa6\xee\xe4\u06abq\xff;\xb4\x13&\xd4s\xe0\x89-~=Q\xbaS\xd0\x00\x00\u07d4\xb4GW\x1d\xac\xbb>\u02f6\xd1\xcf\v\f\x8f88\xe5#$\xe2\x89\x01\xa3\x18f\u007f\xb4\x05\x80\x00\u07d4\xb4G\x83\xc8\xe5{H\a\x93\xcb\u059aE\xd9\f{O\fH\xac\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb4H\x15\xa0\xf2\x8eV\x9d\x0e\x92\x1aJ\u078f\xb2d%&Iz\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4\xb4Im\xdb'y\x9a\"$W\xd79y\x11g(\u8844[\x89\x8d\x81\x9e\xa6_\xa6/\x80\x00\xe0\x94\xb4RL\x95\xa7\x86\x0e!\x84\x02\x96\xa6\x16$@\x19B\x1cJ\xba\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb4\\\xca\r6\x82fbh<\xf7\u0432\xfd\xach\u007f\x02\xd0\u010965\u026d\xc5\u07a0\x00\x00\u0794\xb4d@\u01d7\xa5V\xe0L}\x91\x04f\x04\x91\xf9k\xb0v\xbf\x88\xce\xc7o\x0eqR\x00\x00\u07d4\xb4j\u0386^,P\xeaF\x98\xd2\x16\xabE]\xffZ\x11\xcdr\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4m\x11\x82\xe5\xaa\xca\xff\r&\xb2\xfc\xf7/<\x9f\xfb\xcd\xd9}\x89\xaa*`<\xdd\u007f,\x00\x00\u07d4\xb4\x89!\xc9h}U\x10tE\x84\x93n\x88\x86\xbd\xbf-\xf6\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\x98\xbb\x0fR\x00\x05\xb6!jD%\xb7Z\xa9\xad\xc5-b+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb4\xb1\x1d\x10\x9f`\x8f\xa8\xed\xd3\xfe\xa9\xf8\xc3\x15d\x9a\xeb=\x11\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb4\xb1K\xf4TU\u042b\b\x035\x8bu$\xa7+\xe1\xa2\x04[\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb4\xb1\x85\xd9C\xee+Xc\x1e3\xdf\xf5\xafhT\xc1y\x93\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xbf$\u02c3hk\xc4i\x86\x9f\xef\xb0D\xb9\tqi\x93\xe2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb4\xc2\x00@\xcc\u0661\xa3(=\xa4\u0522\xf3e\x82\bC\xd7\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xc8\x17\x0f{*\xb56\xd1\u0662[\xdd :\xe1(\x8d\xc3\u0549\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4\xd8/.i\x94?}\xe0\xf5\xf7t8y@o\xac.\x9c\xec\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb4\xddF\f\xd0\x16rZd\xb2.\xa4\xf8\xe0n\x06gN\x03>\x8a\x01#\x1b\xb8t\x85G\xa8\x00\x00\u07d4\xb4\xddT\x99\xda\xeb%\a\xfb-\xe1\"\x97s\x1dLr\xb1k\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb5\x04l\xb3\xdc\x1d\xed\xbd6E\x14\xa2\x84\x8eD\xc1\xdeN\xd1G\x8a\x03{}\x9b\xb8 @^\x00\x00\xe0\x94\xb5\b\xf9\x87\xb2\xde4\xaeL\xf1\x93\u0785\xbf\xf6\x13\x89b\x1f\x88\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb5\tU\xaan4\x15q\x98f\b\xbd\u0211\xc2\x13\x9fT\f\u07c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5\f\x14\x9a\x19\x06\xfa\xd2xo\xfb\x13Z\xabP\x177\xe9\xe5o\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\xb5\f\x9fW\x89\xaeD\xe2\xdc\xe0\x17\xc7\x14\xca\xf0\f\x83\x00\x84\u0089\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xb5\x14\x88,\x97\x9b\xb6B\xa8\r\u04c7T\u0578\xc8)m\x9a\a\x893\xc5I\x901r\f\x00\x00\u07d4\xb5\x1d\u0734\xddN\x8a\xe6\xbe3m\xd9eIq\xd9\xfe\xc8kA\x89\x16\xd4d\xf8=\u2500\x00\u07d4\xb5\x1eU\x8e\xb5Q/\xbc\xfa\x81\xf8\u043d\x93\x8cy\xeb\xb5$+\x89&\u009eG\u0104L\x00\x00\u07d4\xb5#\xff\xf9t\x98q\xb3S\x88C\x887\xf7\xe6\xe0\u07a9\xcbk\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb5-\xfbE\xde]t\xe3\xdf \x832\xbcW\x1c\x80\x9b\x8d\xcf2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb55\xf8\u06c7\x9f\xc6\u007f\xecX\x82J\\\xbenT\x98\xab\xa6\x92\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xb57\xd3jp\xee\xb8\xd3\xe5\xc8\r\xe8\x15\"\\\x11X\u02d2\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xb5;\xcb\x17L%\x184\x8b\x81\x8a\xec\xe0 6E\x96Fk\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5I>\xf1srDE\xcf4\\\x03]'\x9b\xa7Y\xf2\x8dQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb5S\xd2]kT!\xe8\x1c*\xd0^\v\x8b\xa7Q\xf8\xf0\x10\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5Tt\xbaX\xf0\xf2\xf4\x0el\xba\xbe\xd4\xea\x17n\x01\x1f\xca\u0589j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5U\xd0\x0f\x91\x90\xcc6w\xae\xf3\x14\xac\xd7?\xdc99\x92Y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5W\xab\x949\xefP\xd27\xb5S\xf0%\b6JFj\\\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5jx\x00(\x03\x9c\x81\xca\xf3{gu\xc6 \u7195Gd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5j\u04ae\xc6\xc8\xc3\xf1\x9e\x15\x15\xbb\xb7\u0751(RV\xb69\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5t\x13\x06\n\xf3\xf1N\xb4y\x06_\x1e\x9d\x19\xb3uz\xe8\u0309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xb5uI\xbf\xbc\x9b\xdd\x18\xf76\xb2&P\xe4\x8as`\x1f\xa6\\\x89\x18-~L\xfd\xa08\x00\x00\xe0\x94\xb5w\xb6\xbe\xfa\x05N\x9c\x04\x04a\x85P\x94\xb0\x02\xd7\xf5{\u05ca\x18#\xf3\xcfb\x1d#@\x00\x00\u07d4\xb5{\x04\xfa#\xd1 ?\xae\x06\x1e\xacEB\xcb`\xf3\xa5v7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xb5\x87\f\xe3B\xd43C36s\x03\x8bGd\xa4n\x92_>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\x87\xb4J,\xa7\x9eK\xc1\u074b\xfd\xd4: qP\xf2\xe7\xe0\x89\",\x8e\xb3\xfff@\x00\x00\u07d4\xb5\x89gm\x15\xa0DH4B0\xd4\xff'\xc9^\xdf\x12,I\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb5\x8bR\x86^\xa5]\x806\xf2\xfa\xb2`\x98\xb3R\u0283~\x18\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xb5\x90k\n\u9881X\xe8\xacU\x0e9\xda\bn\xe3\x15v#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xa4g\x96\x85\xfa\x14\x19l.\x920\xc8\xc4\xe3;\xff\xbc\x10\xe2\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb5\xa5\x89\u075f@q\u06f6\xfb\xa8\x9b?]]\xae}\x96\xc1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xa6\x06\xf4\xdd\u02f9G\x1e\xc6\u007fe\x8c\xaf+\x00\xees\x02^\x89\xeaun\xa9*\xfct\x00\x00\u07d4\xb5\xadQW\u0769!\xe6\xba\xfa\u0350\x86\xaes\xae\x1fa\x1d?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xad\xd1\u701f}\x03\x06\x9b\xfe\x88;\n\x93\"\x10\xbe\x87\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\xba)\x91|x\xa1\xd9\xe5\xc5\xc7\x13fl\x1eA\x1d\u007fi:\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb5\xc8\x16\xa8(<\xa4\xdfh\xa1\xa7=c\xbd\x80&\x04\x88\xdf\b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xca\xc5\xed\x03G}9\v\xb2g\xd4\xeb\xd4a\x01\xfb\xc2\xc3\u0689\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xb5\u037cA\x15@oR\u5a85\xd0\xfe\xa1p\u0497\x9c\u01fa\x89Hz\x9a0E9D\x00\x00\u0794\xb5\u0653M{)+\xcf`;(\x80t\x1e\xb7`(\x83\x83\xa0\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xb5\xddP\xa1]\xa3Ih\x89\nS\xb4\xf1?\xe1\xaf\b\x1b\xaa\xaa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb5\xfa\x81\x84\xe4>\xd3\u0e2b\x91!da\xb3R\x8d\x84\xfd\t\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb5\xfb~\xa2\xdd\xc1Y\x8bfz\x9dW\xdd9\xe8Z8\xf3]V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb6\x00B\x97R\xf3\x99\xc8\r\a4tK\xae\n\x02.\xcag\u0189\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x00\xfe\xabJ\xa9lSu\x04\xd9`W\"1Ai,\x19:\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb6\x04|\u07d3-\xb3\xe4\x04_Iv\x12#AS~\u0556\x1e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x15\xe9@\x14>\xb5\u007f\x87X\x93\xbc\x98\xa6\x1b=a\x8c\x1e\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb6\x1c4\xfc\xac\xdap\x1aZ\xa8p$Y\u07b0\u4b83\x8d\xf8\x8a\aiZ\x92\xc2\ro\xe0\x00\x00\xe0\x94\xb60d\xbd3U\xe6\xe0~-7p$\x12Z3wlJ\xfa\x8a\b7Z*\xbc\xca$@\x00\x00\u07d4\xb65\xa4\xbcq\xfb(\xfd\xd5\xd2\xc3\"\x98:V\u0084Bni\x89\t79SM(h\x00\x00\u07d4\xb6F\u07d8\xb4\x94BtkaR\\\x81\xa3\xb0K\xa3\x10bP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb6YA\xd4LP\xd2Ffg\r6Gf\xe9\x91\xc0.\x11\u0089 \x86\xac5\x10R`\x00\x00\xe0\x94\xb6[\u05c0\xc7CA\x15\x16 'VR#\xf4NT\x98\xff\x8c\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xb6d\x11\xe3\xa0-\xed\xb7&\xfay\x10}\xc9\v\xc1\xca\xe6MH\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb6fu\x14.1\x11\xa1\xc2\xea\x1e\xb2A\x9c\xfaB\xaa\xf7\xa24\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb6o\x92\x12K^c\x03XY\xe3\x90b\x88i\xdb\u07a9H^\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xb6rsJ\xfc\xc2$\xe2\xe6\t\xfcQ\xd4\xf0Ys'D\xc9H\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xb6w\x1b\v\xf3B\u007f\x9a\xe7\xa9>|.a\xeec\x94\x1f\xdb\b\x8a\x03\xfb&i)T\xbf\xc0\x00\x00\u07d4\xb6z\x80\xf1p\x19}\x96\xcd\xccJ\xb6\u02e6'\xb4\xaf\xa6\xe1,\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xb6\x88\x99\xe7a\rL\x93\xa255\xbc\xc4H\x94[\xa1fo\x1c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb6\xa8)3\xc9\xea\u06bd\x98\x1e]m`\xa6\x81\x8f\xf8\x06\xe3k\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb6\xaa\u02cc\xb3\v\xab*\xe4\xa2BF&\xe6\xe1+\x02\xd0F\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb6\xb3J&?\x10\xc3\xd2\xec\xeb\n\xccU\x9a{*\xb8\\\xe5e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xbf\xe1\xc3\xef\x94\xe1\x84o\xb9\xe3\xac\xfe\x9bP\xc3\xe9\x06\x923\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb6\xcdt2\xd5\x16\x1b\xe7\x97h\xadE\xde>Dz\a\x98 c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xceM\xc5`\xfcs\xdci\xfbzb\xe3\x88\xdb~r\xeavO\x894]\xf1i\xe9\xa3X\x00\x00\u07d4\xb6\xde\u03c2\x96\x98\x19\xba\x02\xde)\xb9\xb5\x93\xf2\x1bd\xee\xda\x0f\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\xe0\x94\xb6\xe6\xc3\"+ko\x9b\xe2\x87]*\x89\xf1'\xfbd\x10\x0f\xe2\x8a\x01\xb2\x1dS#\xcc0 \x00\x00\u07d4\xb6\xe8\xaf\xd9=\xfa\x9a\xf2\u007f9\xb4\xdf\x06\ag\x10\xbe\xe3\u07eb\x89\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xb6\xf7\x8d\xa4\xf4\xd0A\xb3\xbc\x14\xbc[\xa5\x19\xa5\xba\f2\xf1(\x8a$}\xd3,?\xe1\x95\x04\x80\x00\xe0\x94\xb6\xfb9xbP\b\x14&\xa3B\xc7\rG\xeeR\x1e[\xc5c\x8a\x03-&\xd1.\x98\v`\x00\x00\u07d4\xb7\r\xba\x93\x91h+J6Nw\xfe\x99%c\x01\xa6\xc0\xbf\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x16#\xf3Q\a\xcft1\xa8?\xb3\xd2\x04\xb2\x9e\u0c67\xf4\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xb7\x1a\x13\xba\x8e\x95\x16{\x803\x1bR\u059e7\x05O\xe7\xa8&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x1bb\xf4\xb4H\xc0+\x12\x01\xcb^9J\xe6'\xb0\xa5`\xee\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb7\" \xad\xe3d\xd06\x9f--\xa7\x83\xcaGM{\x9b4\u0389\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\xe0\x94\xb7#\r\x1d\x1f\xf2\xac\xa3f\x969\x14\xa7\x9d\xf9\xf7\xc5\xea,\x98\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xb7$\n\U000af433<\b\xae\x97d\x10>5\xdc\xe3c\x84(\x8a\x01\xca\xdd/\xe9hnc\x80\x00\u07d4\xb7'\xa9\xfc\x82\xe1\xcf\xfc\\\x17_\xa1HZ\x9b\xef\xa2\u037d\u04496'\xe8\xf7\x127<\x00\x00\u07d4\xb7,*\x01\x1c\r\xf5\x0f\xbbn(\xb2\n\xe1\xaa\xd2\x17\x88g\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb78-7\xdb\x03\x98\xacrA\f\xf9\x81=\xe9\xf8\xe1\uc36d\x8966\xc2^f\xec\xe7\x00\x00\u07d4\xb7;O\xf9\x9e\xb8\x8f\u061b\vmW\xa9\xbc3\x8e\x88o\xa0j\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xb7=jwU\x9c\x86\xcfet$)\x039K\xac\xf9n5p\x89\x04\xf1\xa7|\xcd;\xa0\x00\x00\u07d4\xb7Cr\xdb\xfa\x18\x1d\xc9$/9\xbf\x1d71\xdf\xfe+\xda\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7G\x9d\xabP\"\xc4\xd5\u06ea\xf8\xde\x17\x1bN\x95\x1d\u0464W\x89\x04V9\x18$O@\x00\x00\u07d4\xb7I\xb5N\x04\u0571\x9b\xdc\xed\xfb\x84\xdaw\x01\xabG\x8c'\xae\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb7N\xd2f`\x01\xc1c3\xcfz\xf5\x9eJ=H`6;\x9c\x89\n~\xbd^Cc\xa0\x00\x00\u07d4\xb7QI\xe1\x85\xf6\xe3\x92pWs\x90s\xa1\x82*\xe1\xcf\r\xf2\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xb7S\xa7_\x9e\xd1\v!d:\n=\xc0Qz\xc9k\x1a@h\x89\x15\xc8\x18[,\x1f\xf4\x00\x00\xe0\x94\xb7V\xadR\xf3\xbft\xa7\xd2LgG\x1e\b\x87Ci6PL\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb7Wn\x9d1M\xf4\x1e\xc5Pd\x94):\xfb\x1b\xd5\xd3\xf6]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb7X\x89o\x1b\xaa\x86O\x17\xeb\xed\x16\xd9S\x88o\xeeh\xaa\xe6\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb7h\xb5#N\xba:\x99h\xb3Mm\xdbH\x1c\x84\x19\xb3e]\x88\xcf\xceU\xaa\x12\xb3\x00\x00\u07d4\xb7\x82\xbf\xd1\xe2\xdep\xf4gdo\x9b\xc0\x9e\xa5\xb1\xfc\xf4P\xaf\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xb7\xa2\xc1\x03r\x8bs\x05\xb5\xaen\x96\x1c\x94\xee\x99\xc9\xfe\x8e+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xb7\xa3\x1a|8\xf3\xdb\t2.\xae\x11\xd2'!A\xea\"\x99\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xa6y\x1c\x16\xebN!b\xf1Ke7\xa0+=c\xbf\xc6\x02\x89*Rc\x91\xac\x93v\x00\x00\u07d4\xb7\xa7\xf7|4\x8f\x92\xa9\xf1\x10\fk\xd8)\xa8\xacm\u007f\u03d1\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xb7\xc0w\x94ft\xba\x93A\xfbLtz]P\xf5\xd2\xdad\x15\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb7\xc0\xd0\xcc\vM4-@b\xba\xc6$\xcc\xc3\xc7\f\xc6\xda?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb7\xc9\xf1+\x03\x8esCm\x17\xe1\xc1/\xfe\x1a\xec\u0373\xf5\x8c\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xb7\xcck\x1a\xcc2\u0632\x95\xdfh\xed\x9d^`\xb8\xf6L\xb6{\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xb7\xcehK\t\xab\xdaS8\x9a\x87Si\xf7\x19X\xae\xac;\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xd1.\x84\xa2\xe4\u01264Z\xf1\xdd\x1d\xa9\xf2PJ*\x99n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\xd2R\xee\x94\x02\xb0\xee\xf1D)_\x0ei\xf0\xdbXl\bq\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\xb7\u0541\xfe\n\xf1\xec8?;\xce\x00\xaf\x91\x99\xf3\xcf_\xe0\xcc\xe2\x8c\xd1J\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xb8R\x18\xf3B\xf8\x01.\u069f'Nc\xce!R\xb2\xdc\xfd\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb8UP\x10wn<\\\xb3\x11\xa5\xad\xee\xfe\x9e\x92\xbb\x9ad\xb9\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb8_&\xdd\x0er\xd9\u009e\xba\xf6\x97\xa8\xafwG,+X\xb5\x8a\x02\x85\x19\xac\xc7\x19\fp\x00\x00\u07d4\xb8_\xf0>{_\xc4\"\x98\x1f\xae^\x99A\xda\xcb\u06bau\x84\x89Hz\x9a0E9D\x00\x00\xe0\x94\xb8f\a\x02\x1bb\xd3@\xcf&R\xf3\xf9_\xd2\xdcgi\x8b\u07ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb8}\xe1\xbc\u0492i\xd5!\xb8v\x1c\u00dc\xfbC\x19\xd2\xea\u054965\u026d\xc5\u07a0\x00\x00\u07d4\xb8\u007fSv\xc2\xde\vl\xc3\xc1y\xc0`\x87\xaaG=kFt\x89Hz\x9a0E9D\x00\x00\u07d4\xb8\x84\xad\u060d\x83\xdcVJ\xb8\xe0\xe0,\xbd\xb69\x19\xae\xa8D\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x8a7\xc2\u007fx\xa6\x17\xd5\xc0\x91\xb7\u0577:7a\xe6_*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x94x\"\u056c\u79ad\x83&\xe9T\x96\"\x1e\v\xe6\xb7=\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\x9c\x03n\xd7\u0112\x87\x99!\xbeA\xe1\f\xa1i\x81\x98\xa7L\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xb8\x9fF2\xdfY\t\xe5\x8b*\x99d\xf7O\xeb\x9a;\x01\xe0\u014a\x04\x88u\xbc\xc6\xe7\xcb\xeb\x80\x00\u07d4\xb8\xa7\x9c\x84\x94^G\xa9\xc3C\x86\x83\u05b5\x84,\xffv\x84\xb1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\xa9y5'Y\xba\t\xe3Z\xa5\x93]\xf1u\xbf\xf6x\xa1\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\xab9\x80[\xd8!\x18Ol\xbd=$s4{\x12\xbf\x17\\\x89\x06hZ\xc1\xbf\xe3,\x00\x00\xe0\x94\xb8\xac\x11}\x9f\r\xba\x80\x90\x14E\x82:\x92\x11\x03\xa51o\x85Zew\x9d\x1b\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xb9\xe9\f\x11\x92\xb3\xd5\xd3\xe3\xab\a\x00\xf1\xbfe_]\xd44z\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4\xb9\xfd83\xe8\x8e|\xf1\xfa\x98y\xbd\xf5Z\xf4\xb9\x9c\xd5\xce?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xba\x02I\xe0\x1d\x94[\xef\x93\xee^\xc6\x19%\xe0<\\\xa5\t\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\x0f9\x02;\xdb)\xeb\x18b\xa9\xf9\x05\x9c\xab]0nf/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x10\xf2vB\x90\xf8uCCr\xf7\x9d\xbfq8\x01\u02ac\x01\x893\xc5I\x901r\f\x00\x00\u07d4\xba\x151\xfb\x9ey\x18\x96\xbc\xf3\xa8\x05X\xa3Y\xf6\xe7\xc1D\xbd\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xba\x17m\xbe2I\xe3E\xcdO\xa9g\xc0\xed\x13\xb2LG\u5189\x15\xae\xf9\xf1\xc3\x1c\u007f\x00\x00\xe0\x94\xba\x1f\x0e\x03\u02da\xa0!\xf4\xdc\xeb\xfa\x94\xe5\u0209\xc9\u01fc\x9e\x8a\x06\u0450\xc4u\x16\x9a \x00\x00\u07d4\xba\x1f\xca\xf2#\x93~\xf8\x9e\x85gU\x03\xbd\xb7\xcaj\x92\x8bx\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\xe0\x94\xba$\xfcCgS\xa79\xdb,\x8d@\xe6\xd4\xd0LR\x8e\x86\xfa\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xbaB\xf9\xaa\xceL\x18E\x04\xab\xf5BWb\xac\xa2oq\xfb\u0709\x02\a\a}\u0627\x9c\x00\x00\u07d4\xbaF\x9a\xa5\u00c6\xb1\x92\x95\u0521\xb5G;T\x03S9\f\x85\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbad@\xae\xb3s{\x8e\xf0\xf1\xaf\x9b\f\x15\xf4\xc2\x14\xff\xc7\u03c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbam1\xb9\xa2a\xd6@\xb5\u07a5\x1e\xf2\x16,1\t\xf1\uba0a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xbap\xe8\xb4u\x9c\f<\x82\xcc\x00\xacN\x9a\x94\xdd[\xaf\xb2\xb8\x890C\xfa3\xc4\x12\xd7\x00\x00\u07d4\xba\x8ac\xf3\xf4\r\u4a03\x88\xbcP!/\xea\x8e\x06O\xbb\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x8eF\u059d.#C\xd8l`\xd8,\xf4, A\xa0\xc1\u0089\x05k\xc7^-c\x10\x00\x00\u07d4\xba\xa4\xb6L+\x15\xb7\x9f_ BF\xfdp\xbc\xbd\x86\xe4\xa9*\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xba\u0212,J\xcc},\xb6\xfdY\xa1N\xb4\\\xf3\xe7\x02!K\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xba\xd25\xd5\b]\u01f0h\xa6|A&w\xb0>\x186\x88L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\xd4B^\x17\x1c>r\x97^\xb4j\xc0\xa0\x15\xdb1Z]\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xba\xdc*\xef\x9fYQ\xa8\u05cak5\xc3\u0433\xa4\xe6\xe2\xe79\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xba\xdeCY\x9e\x02\xf8OL0\x14W\x1c\x97k\x13\xa3le\xab\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\xe9\xb8/r\x99c\x14\be\x9d\xd7N\x89\x1c\xb8\xf3\x86\x0f\xe5\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xbb\x03f\xa7\u03fd4E\xa7\r\xb7\xfeZ\xe3H\x85uO\xd4h\x8a\x01M\xef,B\xeb\xd6@\x00\x00\u07d4\xbb\aj\xac\x92 \x80i\xea1\x8a1\xff\x8e\xeb\x14\xb7\xe9\x96\xe3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4\xbb\bW\xf1\xc9\x11\xb2K\x86\u0227\x06\x81G?\u6aa1\xcc\xe2\x89\x05k\xc7^-c\x10\x00\x00\u0794\xbb\x19\xbf\x91\u02edt\xcc\xeb_\x81\x1d\xb2~A\x1b\xc2\xea\x06V\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xbb'\u01a7\xf9\x10uGZ\xb2)a\x90@\xf8\x04\xc8\xeczj\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xbb7\x1cr\xc9\xf01l\xea+\xd9\xc6\xfb\xb4\a\x9ewT)\xef\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94\xbb;\x01\v\x18\xe6\xe2\xbe\x115\x87\x10&\xb7\xba\x15\xea\x0f\xde$\x8a\x02 |\x800\x9bwp\x00\x00\xe0\x94\xbb;\x90\x05\xf4o\xd2\xca;0\x16%\x99\x92\x8cw\xd9\xf6\xb6\x01\x8a\x01\xb1\xae\u007f+\x1b\xf7\xdb\x00\x00\u07d4\xbb?\xc0\xa2\x9c\x03Mq\b\x12\xdc\xc7u\xc8\u02b9\u048diu\x899\xd4\xe8D\xd1\xcf_\x00\x00\u07d4\xbbH\xea\xf5\x16\xce-\xec>A\xfe\xb4\xc6y\xe4\x95vA\x16O\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xbbKJKT\x80p\xffAC,\x9e\b\xa0\xcao\xa7\xbc\x9fv\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xbbV\xa4\x04r<\xff \xd0hT\x88\xb0Z\x02\xcd\xc3Z\xac\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbba\x8e%\"\x1a\u0667@\xb2\x99\xed\x14\x06\xbc94\xb0\xb1m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbba\xa0K\xff\xd5|\x10G\rE\u00d1\x03\xf6FP4v\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbbh#\xa1\xbd\x81\x9f\x13QU8&J-\xe0R\xb4D\"\b\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xbbl(J\xac\x8ai\xb7\\\u0770\x0f(\xe1EX;V\xbe\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xbbu\xcbPQ\xa0\xb0\x94KFs\xcau*\x97\x03\u007f|\x8c\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbb\x99;\x96\xee\x92Z\xda}\x99\u05c6W=?\x89\x18\f\u3a89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa3\u0180\x04$\x8eH\x95s\xab\xb2t6w\x06k$\u0227\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa4\xfa\xc3\xc4 9\xd8(\xe7B\xcd\xe0\xef\xff\xe7t\x94\x1b9\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\xbb\xa8\xab\"\xd2\xfe\xdb\xcf\xc6?hL\b\xaf\xdf\x1c\x17P\x90\xb5\x89\x05_)\xf3~N;\x80\x00\u07d4\xbb\xa9v\xf1\xa1!_u\x12\x87\x18\x92\xd4_pH\xac\xd3V\u0209lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbb\xab\x00\v\x04\b\xed\x01Z7\xc0GG\xbcF\x1a\xb1N\x15\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xbb\xab\xf6d;\xebK\xd0\x1c\x12\v\xd0Y\x8a\t\x87\xd8)g\u0449\xb52\x81x\xad\x0f*\x00\x00\u07d4\xbb\xb4\xee\x1d\x82\xf2\xe1VD,\xc938\xa2\xfc(o\xa2\x88d\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\xbb\xb5\xa0\xf4\x80,\x86H\x00\x9e\x8ai\x98\xaf5,\u0787TO\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\xbb\xb6C\xd2\x18{6J\xfc\x10\xa6\xfd6\x8d}U\xf5\r\x1a<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbb\xb8\xff\xe4?\x98\u078e\xae\x18F#\xaeRd\xe4$\u0438\u05c9\x05\xd5?\xfd\xe9(\b\x00\x00\u07d4\xbb\xbdn\u02f5u(\x91\xb4\u03b3\xcc\xe7:\x8fGpY7o\x89\x01\xf3\x99\xb1C\x8a\x10\x00\x00\u07d4\xbb\xbf9\xb1\xb6y\x95\xa4\"APO\x97\x03\u04a1JQV\x96\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbb\xc8\xea\xffc~\x94\xfc\u014d\x91\xdb\\\x89\x12\x1d\x06\xe1/\xff\x98\x80\x00\u07d4\xbc\u065e\xdc!`\xf2\x10\xa0^:\x1f\xa0\xb0CL\xed\x00C\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbc\u07ec\xb9\xd9\x02<4\x17\x18.\x91\x00\xe8\xea\x1d73\x93\xa3\x89\x034-`\xdf\xf1\x96\x00\x00\u07d4\xbc\xe1>\"2*\u03f3U\xcd!\xfd\r\xf6\f\xf9:\xdd&\u0189\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xbc\xe4\x04u\xd3E\xb0q-\xeep=\x87\xcdvW\xfc\u007f;b\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\xbc\xed\xc4&|\u02c9\xb3\x1b\xb7d\xd7!\x11q\x00\x8d\x94\xd4M\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbc\xfc\x98\xe5\xc8+j\xdb\x18\n?\xcb\x12\v\x9av\x90\xc8j?\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\x04;g\xc6>`\xf8A\xcc\xca\x15\xb1)\xcd\xfee\x90\xc8\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd\x04\u007f\xf1\xe6\x9c\u01b2\x9a\xd2d\x97\xa9\xa6\xf2z\x90?\xc4\u0749.\xe4IU\b\x98\xe4\x00\x00\u07d4\xbd\b\xe0\xcd\xde\xc0\x97\xdby\x01\ua05a=\x1f\xd9\u0789Q\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbd\t\x12l\x89\x1cJ\x83\x06\x80Y\xfe\x0e\x15ylFa\xa9\xf4\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xbd\f\\\u05d9\xeb\u0106B\xef\x97\xd7N\x8eB\x90d\xfe\u4489\x11\xac(\xa8\xc7)X\x00\x00\u07d4\xbd\x17\xee\xd8+\x9a%\x92\x01\x9a\x1b\x1b<\x0f\xba\xd4\\@\x8d\"\x89\r\x8drkqw\xa8\x00\x00\u07d4\xbd\x18\x037\v\u0771)\xd29\xfd\x16\xea\x85&\xa6\x18\x8a\u5389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbd+p\xfe\xcc7d\x0fiQO\xc7\xf3@IF\xaa\xd8k\x11\x89A\rXj \xa4\xc0\x00\x00\u07d4\xbd0\x97\xa7\x9b<\r.\xbf\xf0\xe6\xe8j\xb0\xed\xad\xbe\xd4p\x96\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xbd2]@)\xe0\xd8r\x9fm9\x9cG\x82$\xae\x9ez\xe4\x1e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xbdC*9\x16$\x9bG$):\xf9\x14nI\xb8(\n\u007f*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbdG\xf5\xf7n;\x93\x0f\xd9HR\t\xef\xa0\xd4v=\xa0uh\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbdK`\xfa\xect\n!\xe3\a\x13\x91\xf9j\xa54\xf7\xc1\xf4N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xbdK\u0571\"\xd8\xef{|\x8f\x06gE\x03 \xdb!\x16\x14.\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbdQ\xee.\xa1C\u05f1\u05b7~~D\xbd\xd7\xda\x12\U00105b09G~\x06\u0332\xb9(\x00\x00\u07d4\xbdY\tN\aO\x8dy\x14*\xb1H\x9f\x14\x8e2\x15\x1f \x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbdZ\x8c\x94\xbd\x8b\xe6G\x06D\xf7\f\x8f\x8a3\xa8\xa5\\cA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd^G:\xbc\xe8\xf9zi2\xf7|/\xac\xaf\x9c\xc0\xa0\x05\x14\x89<\x92X\xa1\x06\xa6\xb7\x00\x00\u07d4\xbd_F\u02ab,=K(\x93\x96\xbb\xb0\u007f *\x06\x11>\xd4\xc3\xfb\xa1\xa8\x91;\x19@~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\x9eV\xe9\x02\xf4\xbe\x1f\xc8v\x8d\x808\xba\xc6>*\u02ff\x8e\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xbd\xa4\xbe1~~K\xed\x84\xc0I^\xee2\xd6\a\xec8\xcaR\x89}2'yx\xefN\x80\x00\u07d4\xbd\xb6\v\x82:\x11s\xd4Z\a\x92$_\xb4\x96\xf1\xfd3\x01\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xba\xf6CM@\xd65[\x1e\x80\xe4\f\u012b\x9ch\xd9a\x16\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbd\xc0,\xd43\f\x93\xd6\xfb\xdaOm\xb2\xa8]\xf2/C\xc23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc4aF+c\"\xb4b\xbd\xb3?\"y\x9e\x81\b\xe2A}\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xbd\xc79\xa6\x99p\v.\x8e,JL{\x05\x8a\x0eQ=\u07be\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc7Hs\xaf\x92+\x9d\xf4t\x85;\x0f\xa7\xff\v\xf8\xc8&\x95\x89\xd8\xc9F\x00c\xd3\x1c\x00\x00\u07d4\xbd\xca*\x0f\xf3E\x88\xafb_\xa8\xe2\x8f\xc3\x01Z\xb5\xa3\xaa\x00\x89~\xd7?w5R\xfc\x00\x00\u07d4\xbd\xd3%N\x1b:m\xc6\xcc,i}Eq\x1a\xca!\xd5\x16\xb2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbd\u07e3M\x0e\xbf\x1b\x04\xafS\xb9\x9b\x82IJ\x9e=\x8a\xa1\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xbd\xe4\xc7?\x96\x9b\x89\xe9\u03aef\xa2\xb5\x18DH\x0e\x03\x8e\x9a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbd\xe9xj\x84\xe7[H\xf1\x8erm\u05cdp\xe4\xaf>\xd8\x02\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xbd\xed\x11a/\xb5\xc6\u0699\xd1\xe3\x0e2\v\xc0\x99Tf\x14\x1e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xbd\xed~\a\xd0q\x1ehM\xe6Z\u0232\xabW\xc5\\\x1a\x86E\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xbd\xf6\x93\xf83\xc3\xfeG\x17S\x18G\x88\xebK\xfeJ\xdc?\x96\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\xf6\xe6\x8c\f\xd7X@\x80\xe8G\xd7,\xbb#\xaa\xd4j\xeb\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbe\n/8_\t\xdb\xfc\xe9g2\xe1+\xb4\n\xc3I\x87\x1b\xa8\x89WL\x11^\x02\xb8\xbe\x00\x00\u07d4\xbe\f*\x80\xb9\xde\bK\x17(\x94\xa7l\xf4szOR\x9e\x1a\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\x1c\xd7\xf4\xc4r\a\th\xf3\xbd\xe2h6k!\xee\xea\x83!\x89\xe9\x1a|\u045f\xa3\xb0\x00\x00\u07d4\xbe#F\xa2\u007f\xf9\xb7\x02\x04OP\r\xef\xf2\xe7\xff\xe6\x82EA\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbe$q\xa6\u007f`G\x91\x87r\xd0\xe3h9%^\xd9\u0591\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbe+\"\x80R7h\xea\x8a\xc3\\\xd9\xe8\x88\xd6\nq\x93\x00\u0509lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe+2nx\xed\x10\xe5P\xfe\xe8\xef\xa8\xf8\a\x03\x96R/Z\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\xe0\x94\xbe0Zyn3\xbb\xf7\xf9\xae\xaee\x12\x95\x90f\xef\xda\x10\x10\x8a\x02M\xceT\xd3J\x1a\x00\x00\x00\u07d4\xbeG\x8e\x8e=\xdek\xd4\x03\xbb-\x1ce|C\x10\xee\x19'#\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\xbeN}\x98?.*ck\x11\x02\xecp9\xef\xeb\xc8B\u9349\x03\x93\xef\x1aQ'\xc8\x00\x00\u07d4\xbeO\xd0sap\"\xb6\u007f\\\x13I\x9b\x82\u007fv69\xe4\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbeRZ3\xea\x91aw\xf1r\x83\xfc\xa2\x9e\x8b5\v\u007fS\v\x89\x8f\x01\x9a\xafF\xe8x\x00\x00\u07d4\xbeS2/C\xfb\xb5\x84\x94\xd7\xcc\xe1\x9d\xda'+$P\xe8'\x89\n\xd7\u03afB\\\x15\x00\x00\u07d4\xbeS\x82F\xddNo\f \xbfZ\xd17<;F:\x13\x1e\x86\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbeZ`h\x99\x98c\x9a\xd7[\xc1\x05\xa3qt>\xef\x0fy@\x89\x1b2|s\xe1%z\x00\x00\u07d4\xbe\\\xba\x8d7By\x86\xe8\xca&\x00\xe8X\xbb\x03\xc3YR\x0f\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xbe`\x03~\x90qJK\x91~a\xf1\x93\xd84\x90g\x03\xb1:\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbec:77\xf6\x849\xba\xc7\xc9\nR\x14 X\ue38ao\x894\n\xad!\xb3\xb7\x00\x00\x00\xe0\x94\xbee\x9d\x85\xe7\xc3O\x883\xea\u007fH\x8d\xe1\xfb\xb5\xd4\x14\x9b\xef\x8a\x01\xeb\xd2:\xd9\u057br\x00\x00\u07d4\xbes'M\x8cZ\xa4J<\xbe\xfc\x82c\xc3{\xa1!\xb2\n\u04c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbe\x86\u0430C\x84\x19\u03b1\xa081\x927\xbaR\x06\xd7.F\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xbe\x8d\u007f\x18\xad\xfe]l\xc7u9I\x89\xe1\x93\f\x97\x9d\x00}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\x91\x86\xc3JRQJ\xbb\x91\a\x86\x0fgO\x97\xb8!\xbd[\x89\x1b\xa0\x1e\xe4\x06\x03\x10\x00\x00\u07d4\xbe\x93W\x93\xf4[p\xd8\x04]&T\xd8\xdd:\xd2K[a7\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xbe\x98\xa7\u007f\xd4\x10\x97\xb3OY\xd7X\x9b\xaa\xd0!e\x9f\xf7\x12\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xbe\x9b\x8c4\xb7\x8e\xe9G\xff\x81G.\xdaz\xf9\xd2\x04\xbc\x84f\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\xbe\xa0\r\xf1pg\xa4:\x82\xbc\x1d\xae\xca\xfbl\x140\x0e\x89\xe6\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xbe\xa0\xaf\xc9:\xae!\b\xa3\xfa\xc0Yb;\xf8o\xa5\x82\xa7^\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbe\xb35\x8cP\u03dfu\xff\xc7mD<,\u007fU\aZ\x05\x89\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xbe\xb4\xfd1UYC`E\u0739\x9dI\xdc\xec\x03\xf4\fB\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xc2\xe6\xde9\xc0|+\xaeUj\u03fe\xe2\xc4r\x8b\x99\x82\xe3\x89\x1f\x0f\xf8\xf0\x1d\xaa\xd4\x00\x00\u07d4\xbe\xc6d\x0fI\t\xb5\x8c\xbf\x1e\x80cB\x96\x1d`u\x95\tl\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\xc8\xca\xf7\xeeIF\x8f\xeeU.\xff:\xc5#N\xb9\xb1}B\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xce\xf6\x1c\x1cD+\xef|\xe0Ks\xad\xb2I\xa8\xba\x04~\x00\x896;V\u00e7T\xc8\x00\x00\u0794\xbe\xd4d\x9d\xf6F\u2052)\x03-\x88hUo\xe1\xe0S\u04c8\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xbe\xd4\xc8\xf0\x06\xa2|\x1e_|\xe2\x05\xdeu\xf5\x16\xbf\xb9\xf7d\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xbe\xe8\u0430\bB\x19T\xf9-\x00\r9\x0f\xb8\xf8\xe6X\xea\xee\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\xec\u05af\x90\f\x8b\x06J\xfc\xc6\a?-\x85\u055a\xf1\x19V\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe\xef\x94!8y\xe0&\"\x14+\xeaa)\tx\x93\x9a`\u05ca\x016\x85{2\xad\x86\x04\x80\x00\xe0\x94\xbe\xf0}\x97\xc3H\x1f\x9dj\xee\x1c\x98\xf9\xd9\x1a\x18\n2D+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xbe\xfbD\x8c\f_h?\xb6~\xe5p\xba\xf0\xdbV\x86Y\x97Q\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbf\x05\a\f,4!\x93\x11\xc4T\x8b&\x14\xa48\x81\r\xedm\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbf\x05\xff^\xcf\r\xf2\u07c8wY\xfb\x82t\xd928\xac&}\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\xbf\t\xd7pH\xe2p\xb6b3\x0e\x94\x86\xb3\x8bC\xcdx\x14\x95\x8a\\S\x9b{\xf4\xff(\x80\x00\x00\u07d4\xbf\x17\xf3\x97\xf8\xf4o\x1b\xaeE\u0447\x14\x8c\x06\xee\xb9Y\xfaM\x896I\u0156$\xbb0\x00\x00\u07d4\xbf\x186A\xed\xb8\x86\xce`\xb8\x19\x02a\xe1OB\xd9<\xce\x01\x89\x01[5W\xf1\x93\u007f\x80\x00\u07d4\xbf*\xeaZ\x1d\xcfn\u04f5\xe829D\xe9\x83\xfe\xdf\u046c\xfb\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbf@\x96\xbcT}\xbf\xc4\xe7H\t\xa3\x1c\x03\x9e{8\x9d^\x17\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xbfI\xc1H\x981eg\u0637\t\xc2\xe5\x05\x94\xb3f\xc6\u04cc\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4\xbfLs\xa7\xed\xe7\xb1d\xfe\a!\x14\x846T\xe4\xd8x\x1d\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfP\xce.&K\x9f\xe2\xb0h0az\xed\xf5\x02\xb25\x1bE\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfY\xae\xe2\x81\xfaC\xfe\x97\x19CQ\xa9\x85~\x01\xa3\xb8\x97\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbfh\u048a\xaf\x1e\xee\xfe\xf6F\xb6^\x8c\xc8\u0450\xf6\xc6\u069c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfi%\xc0\aQ\x00\x84@\xa6s\x9a\x02\xbf+l\u06ab^:\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfw\x01\xfcb%\u0561x\x15C\x8a\x89A\xd2\x1e\xbc]\x05\x9d\x89e\xea=\xb7UF`\x00\x00\u07d4\xbf\x8b\x80\x05\xd66\xa4\x96d\xf7Bu\xefBC\x8a\xcde\xac\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\x92A\x8a\fl1$M\"\x02`\xcb>\x86}\u05f4\xefI\x89\x05i\x00\xd3<\xa7\xfc\x00\x00\u07d4\xbf\x9a\xcdDE\xd9\xc9UF\x89\u02bb\xba\xb1\x88\x00\xff\x17A\u008965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\x9f'\x1fz~\x12\xe3m\xd2\xfe\x9f\xac\xeb\xf3\x85\xfeaB\xbd\x89\x03f\xf8O{\xb7\x84\x00\x00\u07d4\xbf\xa8\xc8X\xdf\x10,\xb1$!\x00\x8b\n1\xc4\xc7\x19\n\xd5`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\xae\xb9\x10ga}\u03cbD\x17+\x02\xafaVt\x83]\xba\x89\b\xb5\x9e\x88H\x13\b\x80\x00\xe0\x94\xbf\xb0\xea\x02\xfe\xb6\x1d\xec\x9e\"\xa5\a\tY3\x02\x99\xc40r\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xbf\xbc\xa4\x18\xd3R\x9c\xb3\x93\b\x10b\x03*n\x11\x83\u01b2\u070a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xbf\xbe\x05\u831c\xbb\xcc\x0e\x92\xa4\x05\xfa\xc1\xd8]\xe2H\xee$\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xbf\xbf\xbc\xb6V\u0099+\xe8\xfc\u0782\x19\xfb\xc5J\xad\u055f)\x8a\x02\x1e\x18\xd2\xc8!\xc7R\x00\x00\u07d4\xbf\xc5z\xa6f\xfa\u239f\x10zI\xcbP\x89\xa4\xe2!Q\u074965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\u02d70$c\x04p\r\xa9\vAS\xe7\x11Ab.\x1cA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbf\xd9<\x90\u009c\a\xbc_\xb5\xfcI\xae\xeaU\xa4\x0e\x13O5\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\xe0\x94\xbf\xe3\xa1\xfcn$\xc8\xf7\xb3%\x05`\x99\x1f\x93\u02e2\u03c0G\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xbf\u6f30\xf0\xc0xRd3$\xaa]\xf5\xfdb%\xab\xc3\u0289\x04\t\xe5+H6\x9a\x00\x00\u07d4\xbf\xf5\xdfv\x994\xb8\x94<\xa9\x13}\x0e\xfe\xf2\xfen\xbb\xb3N\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbf\xfbi)$\x1fx\x86\x93'>p\"\xe6\x0e>\xab\x1f\xe8O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x06O\x1d\x94t\xab\x91]V\x90l\x9f\xb3 \xa2\xc7\t\x8c\x9b\x89\x13h?\u007f<\x15\xd8\x00\x00\u07d4\xc0\a\xf0\xbd\xb6\xe7\x00\x92\x02\xb7\xaf>\xa9\t\x02i|r\x14\x13\x89\xa2\xa0\xe4>\u007f\xb9\x83\x00\x00\u07d4\xc0\n\xb0\x80\xb6C\xe1\u00ba\xe3c\xe0\u0455\xde.\xff\xfc\x1cD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\xc0 wD\x9a\x13Jz\xd1\xef~M\x92z\xff\xec\ueb75\xae\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc0$q\xe3\xfc.\xa0S&\x15\xa7W\x1dI2\x89\xc1<6\xef\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0-n\xad\xea\xcf\x1bx\xb3\u0285\x03\\c{\xb1\xce\x01\xf4\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc03\xb12Z\n\xf4Tr\xc2U'\x85;\x1f\x1c!\xfa5\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc03\xbe\x10\xcbHa;\xd5\xeb\xcb3\xedI\x02\xf3\x8bX0\x03\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc04[3\xf4\x9c\xe2\u007f\xe8,\xf7\xc8M\x14\x1ch\xf5\x90\xcev\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0=\xe4*\x10\x9bezd\xe9\"$\xc0\x8d\xc1'^\x80\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0@i\u07f1\x8b\tlxg\xf8\xbe\xe7zm\xc7Gz\xd0b\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xc0A?Z|-\x9aK\x81\b(\x9e\xf6\xec\xd2qx\x15$\xf4\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xc0C\xf2E-\u02d6\x02\xefb\xbd6\x0e\x03=\xd29q\xfe\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0OK\xd4\x04\x9f\x04F\x85\xb8\x83\xb6)Y\xaec\x1df~5\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0V\u053dk\xf3\u02ec\xace\xf8\xf5\xa0\xe3\x98\v\x85'@\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0[t\x06 \xf1s\xf1nRG\x1d\u00cb\x9cQJ\v\x15&\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\xc0i\xef\x0e\xb3B\x99\xab\xd2\xe3-\xab\xc4yD\xb2r3H$\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xc0l\xeb\xbb\xf7\xf5\x14\x9af\xf7\xeb\x97k>G\xd5e\x16\xda/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0r^\u00bd\xc3:\x1d\x82`q\u07a2\x9db\xd48Z\x8c%\x8a\b\xa0\x85\x13F:\xa6\x10\x00\x00\u07d4\xc0~8g\xad\xa0\x96\x80z\x05\x1al\x9c4\xcc;?J\xd3J\x89`\xf0f \xa8IE\x00\x00\u07d4\xc0\x89^\xfd\x05m\x9a:\x81\xc3\xdaW\x8a\xda1\x1b\xfb\x93V\u03c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x90\xfe#\xdc\xd8k5\x8c2\xe4\x8d*\xf9\x10$%\x9fef\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x9af\x17*\xea7\r\x9ac\xda\x04\xffq\xff\xbb\xfc\xff\u007f\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x9e<\xfc\x19\xf6\x05\xff>\xc9\xc9\xc7\x0e%@\xd7\xee\x97Cf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc0\xa0*\xb9N\xbeV\xd0E\xb4\x1bb\x9b\x98F.:\x02J\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0\xa3\x93\b\xa8\x0e\x9e\x84\xaa\xaf\x16\xac\x01\xe3\xb0\x1dt\xbdk-\x89\afM\xddL\x1c\v\x80\x00\u07d4\xc0\xa6\u02edwi*=\x88\xd1A\xefv\x9a\x99\xbb\x9e<\x99Q\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xc0\xa7\xe8C]\xff\x14\xc2Uws\x9d\xb5\\$\u057fW\xa3\u064a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xc0\xae\x14\xd7$\x83./\xce'x\xde\u007f{\x8d\xaf{\x12\xa9>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0\xaf\xb7\u0637\x93p\xcf\xd6c\u018c\u01b9p*7\u035e\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0\xb0\xb7\xa8\xa6\xe1\xac\xdd\x05\xe4\u007f\x94\xc0\x96\x88\xaa\x16\u01ed\x8d\x89\x03{m\x02\xacvq\x00\x00\xe0\x94\xc0\xb3\xf2D\xbc\xa7\xb7\xde[H\xa5>\u06dc\xbe\xab\vm\x88\xc0\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0\xc0M\x01\x06\x81\x0e>\xc0\xe5J\x19\U000ab157\xe6\x9aW=\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xc0\xca2w\x94.tE\x87K\xe3\x1c\xeb\x90)rqO\x18#\x89\r\x8drkqw\xa8\x00\x00\u07d4\xc0\u02ed<\xcd\xf6T\xda\"\xcb\xcf\\xe\x97\xca\x19U\xc1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\xcb\xf6\x03/\xa3\x9e|F\xffw\x8a\x94\xf7\xd4E\xfe\"\xcf0\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\xc0\xe0\xb9\x03\b\x8e\fc\xf5=\xd0iWTR\xaf\xf5$\x10\u00c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc0\xe4W\xbdV\xec6\xa1$k\xfa20\xff\xf3\x8eY&\xef\"\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xc0\xed\rJ\xd1\r\xe045\xb1S\xa0\xfc%\xde;\x93\xf4R\x04\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xc0\xf2\x9e\xd0\af\x11\xb5\xe5^\x13\x05G\xe6\x8aH\xe2m\xf5\u4262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc1\x13(x#\\]\u06e5\xd9\xf3\"\x8bR6\xe4p \xdco\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1\x17\r\xba\xad\xb3\xde\xe6\x19\x8e\xa5D\xba\xec\x93%\x18`\xfd\xa5\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\xc1&W=\x87\xb0\x17ZR\x95\xf1\xdd\a\xc5u\u03cc\xfa\x15\xf2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc1'\xaa\xb5\x90e\xa2\x86D\xa5k\xa3\xf1^.\xac\x13\xda)\x95\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xc1+\u007f@\u07da/{\xf9\x83f\x14\"\xab\x84\xc9\xc1\xf5\bX\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc1,\xfb{=\xf7\x0f\xce\xca\x0e\xde&5\x00\xe2xs\xf8\xed\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1/\x88\x1f\xa1\x12\xb8\x19\x9e\xcb\xc7>\xc4\x18W\x90\xe6\x14\xa2\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc18Lnq~\xbeK#\x01NQ\xf3\x1c\x9d\xf7\xe4\xe2[1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1C\x8c\x99\xddQ\xef\x1c\xa88j\xf0\xa3\x17\xe9\xb0AEx\x88\x89\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xc1c\x12(\xef\xbf*.:@\x92\xee\x89\x00\xc69\xed4\xfb\u02093\xc5I\x901r\f\x00\x00\u07d4\xc1u\xbe1\x94\xe6iB-\x15\xfe\xe8\x1e\xb9\xf2\xc5lg\xd9\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\x82v\x86\xc0\x16\x94\x85\xec\x15\xb3\xa7\xc8\xc0\x15\x17\xa2\x87M\xe1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xc1\x8a\xb4g\xfe\xb5\xa0\xaa\xdf\xff\x91#\x0f\xf0VFMx\xd8\x00\x89lk\x93[\x8b\xbd@\x00\x00\u0794\xc1\x95\x05CUM\x8aq0\x03\xf6b\xbba,\x10\xadL\xdf!\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc1\xa4\x1aZ'\x19\x92&\xe4\xc7\xeb\x19\x8b\x03\x1bY\x19o\x98B\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xc1\xb2\xa0\xfb\x9c\xadE\xcdi\x91\x92\xcd'T\v\x88\xd38By\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1\xb2\xaa\x8c\xb2\xbfb\xcd\xc1:G\xec\xc4e\u007f\xac\xaa\x99_\x98\x8967\x93\xfa\x96\u6980\x00\u07d4\xc1\xb5\x00\x01\x1c\xfb\xa9]|\xd66\xe9^l\xbfagFK%\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\xb9\xa5pM5\x1c\xfe\x98?y\xab\xee\xc3\u06fb\xae;\xb6)\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xcb\xd2\xe23*RL\xf2\x19\xb1\r\x87\x1c\xcc \xaf\x1f\xb0\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xc1\xcd\xc6\x01\xf8\x9c\x04(\xb3\x13\x02\u0447\xe0\xdc\b\xad}\x1cW\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xc1\u052f8\xe9\xbay\x90@\x89HI\xb8\xa8!\x93u\xf1\xacx\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc1\xe1@\x9c\xa5,%CQ4\xd0\x06\u00a6\xa8T-\xfbrs\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xc1\xeb\xa5hJ\xa1\xb2L\xbac\x15\x02c\xb7\xa9\x13\x1a\xee\u008d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xec\x81\xdd\x12=K|-\u0674\xd48\xa7\a,\x11\u0707L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc1\xf3\x9b\xd3]\xd9\xce\xc37\xb9oG\xc6w\x81\x81`\xdf7\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xc1\xff\xad\a\u06d6\x13\x8cK*S\x0e\xc1\xc7\xde)\xb8\xa0Y,\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xc2\x1f\xa6d:\x1f\x14\xc0)\x96\xadqD\xb7Y&\xe8~\xcbK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc24\nL\xa9L\x96x\xb7IL<\x85%(\xed\xe5\xeeR\x9f\x89\x02\xa3k\x05\xa3\xfd|\x80\x00\u07d4\xc29\xab\u07ee>\x9a\xf5E\u007fR\xed+\x91\xfd\n\xb4\xd9\xc7\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2;/\x92\x1c\xe4\xa3z%\x9e\u4b4b!X\xd1]fOY\x89\x01`\x89\x95\xe8\xbd?\x80\x00\u07d4\xc2C\x99\xb4\xbf\x86\xf73\x8f\xbfd^;\"\xb0\u0dd79\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2L\u03bc#D\xcc\xe5d\x17\xfbhL\xf8\x16\x13\xf0\xf4\xb9\xbd\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc2Rf\xc7gf2\xf1>\xf2\x9b\xe4U\ud50a\xddVw\x92\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\\\xf8&U\f\x8e\xaf\x10\xaf\"4\xfe\xf9\x04\u0779R\x13\xbe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc2f?\x81E\xdb\xfe\xc6\xc6F\xfc\\I\x96\x13E\xde\x1c\x9f\x11\x89%g\xacp9+\x88\x00\x00\u07d4\xc2pEh\x854+d\vL\xfc\x1bR\x0e\x1aTN\xe0\xd5q\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc2sv\xf4]!\xe1^\xde;&\xf2e_\xce\xe0,\xcc\x0f*\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc2w\x97q\xf0Smy\xa8p\x8fi1\xab\xc4K05\u964a\x047\u04ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc2\xc1>r\xd2h\xe7\x15\r\u01d9\xe7\xc6\xcf\x03\u0209T\xce\u05c9%\xf2s\x93=\xb5p\x00\x00\u07d4\xc2\xcb\x1a\xda]\xa9\xa0B8s\x81G\x93\xf1aD\xef6\xb2\xf3\x89HU~;p\x17\xdf\x00\x00\u07d4\xc2\xd1w\x8e\xf6\xee_\xe4\x88\xc1E\xf3Xkn\xbb\xe3\xfb\xb4E\x89>\x1f\xf1\xe0;U\xa8\x00\x00\xe0\x94\xc2\xd9\xee\xdb\xc9\x01\x92c\xd9\xd1l\u016e\a-\x1d=\xd9\xdb\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc2\xe0XJq4\x8c\xc3\x14\xb7; )\xb6#\v\x92\u06f1\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2\xe2\u0518\xf7\r\xcd\bY\xe5\v\x02:q\nmK!3\xbd\x8989\x11\xf0\f\xbc\xe1\x00\x00\u07d4\xc2\xed_\xfd\u046d\xd8U\xa2i/\xe0b\xb5\xd6\x18t#`\u0509A\rXj \xa4\xc0\x00\x00\u07d4\xc2\xee\x91\xd3\xefX\xc9\u0465\x89\x84N\xa1\xae1%\xd6\u017ai\x894\x95tD\xb8@\xe8\x00\x00\u07d4\xc2\xfa\xfd\xd3\n\xcbmg\x06\xe9)<\xb0&A\xf9\xed\xbe\a\xb5\x89Q\x00\x86\vC\x0fH\x00\x00\u07d4\xc2\xfd\v\xf7\xc7%\xef>\x04~Z\xe1\u009f\xe1\x8f\x12\xa7)\x9c\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\xfe}us\x1fcm\xcd\t\xdb\xda\x06q9;\xa0\xc8*}\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\xc3\x10z\x9a\xf32-R8\xdf\x012A\x911b\x959W}\x89\x1a\xb4\xe4d\xd4\x141\x00\x00\xe0\x94\xc3\x11\v\xe0\x1d\xc9sL\xfcn\x1c\xe0\u007f\x87\xd7}\x13E\xb7\xe1\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xc3 8\xcaR\xae\xe1\x97E\xbe\\1\xfc\xdcT\x14\x8b\xb2\xc4\u0409\x02\xb5\xaa\xd7,e \x00\x00\u07d4\xc3%\xc3R\x80\x1b\xa8\x83\xb3\"l_\xeb\r\xf9\xea\xe2\xd6\xe6S\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xc3.\xc7\xe4*\xd1l\xe3\xe2UZ\xd4\xc5C\x06\xed\xa0\xb2gX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc32\xdfP\xb1<\x014\x90\xa5\xd7\xc7]\xbf\xa3f\u0687\xb6\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc3:\u0373\xba\x1a\xab'P{\x86\xb1]g\xfa\xf9\x1e\xcfb\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3>\u0393Z\x8fN\xf98\xea~\x1b\xac\x87\u02d2]\x84\x90\u028a\a\x03\x8c\x16x\x1fxH\x00\x00\u07d4\xc3@\xf9\xb9\x1c&r\x8c1\xd1!\xd5\xd6\xfc;\xb5m=\x86$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3F\xcb\x1f\xbc\xe2\xab(]\x8eT\x01\xf4-\xd7#M7\xe8m\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\xe0\x94\xc3H=n\x88\xac\x1fJ\xe7<\xc4@\x8dl\x03\xab\xe0\xe4\x9d\u028a\x03\x99\x92d\x8a#\u0220\x00\x00\xe0\x94\xc3H\xfcZF\x13#\xb5{\xe3\x03\u02c96\x1b\x99\x19\x13\xdf(\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc3N;\xa12.\xd0W\x11\x83\xa2O\x94 N\xe4\x9c\x18fA\x89\x03'\xaf\uf927\xbc\x00\x00\xe0\x94\xc3[\x95\xa2\xa3s|\xb8\xf0\xf5\x96\xb3E$\x87+\xd3\r\xa24\x8a\x01\x98\xbe\x85#^-P\x00\x00\xe0\x94\xc3c\x1cv\x98\xb6\xc5\x11\x19\x89\xbfE''\xb3\xf99Zm\xea\x8a\x02C'X\x96d\x1d\xbe\x00\x00\u07d4\xc3l\vc\xbf\xd7\\/\x8e\xfb\x06\b\x83\xd8h\xcc\xcdl\xbd\xb4\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xc3uk\xcd\xcc~\xect\xed\x89j\xdf\xc35'Y0&n\b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u00c4\xacn\xe2|9\xe2\xf2x\xc2 \xbd\xfa[\xae\xd6&\xd9\u04c9 \x86\xac5\x10R`\x00\x00\u07d4\u00e0F\xe3\u04b2\xbfh\x14\x88\x82n2\xd9\xc0aQ\x8c\xfe\x8c\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\u00e9\"j\xe2u\xdf,\xab1+\x91\x10@cJ\x9c\x9c\x9e\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u00f9(\xa7o\xadex\xf0O\x05U\xe69R\xcd!\xd1R\n\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xc2)s)\xa6\xfd\x99\x11~T\xfcj\xf3y\xb4\xd5VT~\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc3\xc3\xc2Q\rg\x80 HZcs]\x13\a\xecL\xa60+\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc3\xcbk6\xafD?,n%\x8bJ9U:\x81\x87G\x81\x1f\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xc3\xdbVW\xbbr\xf1\rX\xf21\xfd\xdf\x11\x98\n\xffg\x86\x93\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xc3\u06df\xb6\xf4lH\n\xf3De\u05d7S\xb4\xe2\xb7Jg\u038a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc3\xddX\x908\x860;\x92\x86%%z\xe1\xa0\x13\xd7\x1a\xe2\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe0G\x1cd\xff5\xfaR2\xcc1!\xd1\u04cd\x1a\x0f\xb7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe2\f\x96\u07cdN8\xf5\v&Z\x98\xa9\x06\xd6\x1b\xc5\x1aq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\u31f0<\xe9\\\xcf\xd7\xfaQ\u0744\x01\x83\xbcCS(\t\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xf8\xf6r\x95\xa5\xcd\x04\x93d\xd0]#P&#\xa3\xe5.\x84\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc4\x01\xc4'\xcc\xcf\xf1\r\xec\xb8d /6\xf5\x80\x83\"\xa0\xa8\x89\xb4{Q\xa6\x9c\xd4\x02\x00\x00\u07d4\xc4\b\x8c\x02_>\x85\x01?T9\xfb4@\xa1s\x01\xe5D\xfe\x89~\t\xdbM\x9f?4\x00\x00\u07d4\xc4\x14a\xa3\u03fd2\u0246UU\xa4\x8117\xc0v1#`\x8965\xc6 G9\u0640\x00\u07d4\xc4 8\x8f\xbe\xe8J\xd6V\xddh\xcd\xc1\xfb\xaa\x93\x92x\v4\x89\n-\xcac\xaa\xf4\u0140\x00\u07d4\xc4\"P\xb0\xfeB\xe6\xb7\xdc\xd5\u0210\xa6\xf0\u020f__\xb5t\x89\b\x1e\xe4\x82SY\x84\x00\x00\u07d4\xc4-j\xebq\x0e:P\xbf\xb4Ml1\t)i\xa1\x1a\xa7\xf3\x89\b\"c\xca\xfd\x8c\xea\x00\x00\xe0\x94\xc4@\xc7\xca/\x96Kir\xeffJ\"a\xdd\xe8\x92a\x9d\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xc4K\xde\xc8\xc3l\\h\xba\xa2\xdd\xf1\xd41i2)rlC\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc4OJ\xb5\xbc`9|s~\xb0h3\x91\xb63\xf8\xa2G\x1b\x12\x1c\xa4\x89 .h\xf2\u00ae\xe4\x00\x00\u07d4\xc4h\x1es\xbb\x0e2\xf6\xb7& H1\xffi\xba\xa4\x87~2\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc4k\xbd\xefv\xd4\xca`\xd3\x16\xc0\u007f]\x1ax\x0e;\x16_~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc4}a\v9\x92P\xf7\x0e\xcf\x13\x89\xba\xb6),\x91&O#\x89\x0f\xa7\xe7\xb5\xdf<\xd0\x00\x00\u07d4\u0100;\xb4\a\xc7b\xf9\vu\x96\xe6\xfd\u1513\x1ev\x95\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0106Q\xc1\xd9\xc1k\xffL\x95T\x88l??&C\x1foh\x89#\xab\x95\x99\xc4?\b\x00\x00\u07d4\u0109\xc8?\xfb\xb0%*\xc0\xdb\xe3R\x12\x17c\x0e\x0fI\x1f\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u010bi<\xac\xef\xdb\xd6\xcb]x\x95\xa4.1\x962~&\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0113H\x9eV\u00fd\xd8)\x00}\xc2\xf9VA)\x06\xf7k\xfa\x89\x02\xa7\x91H\x8eqT\x00\x00\u07d4\u0116\u02f0E\x9aj\x01`\x0f\u0149\xa5Z2\xb4T!\u007f\x9d\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4\u011c\xfa\xa9g\xf3\xaf\xbfU\x03\x10a\xfcL\xef\x88\xf8]\xa5\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0136\xe5\xf0\x9c\xc1\xb9\r\xf0x\x03\xce=M\x13vj\x9cF\xf4\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u013e\xc9c\b\xa2\x0f\x90\u02b1\x83\x99\u0113\xfd=\x06Z\xbfE\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xc4\xc0\x1a\xfc>\x0f\x04R!\xda\x12\x84\u05c7\x85tD/\xb9\xac\x8a\x01\x92\xb5\u0249\x02J\x19\xc1\xbdo\x12\x80\x00\xe0\x94\xc5\x00\xb7 sN\xd2)8\u05cc^H\xb2\xba\x93g\xa5u\xba\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\u07d4\xc5\x0f\xe4\x15\xa6A\xb0\x85lNu\xbf\x96\x05\x15D\x1a\xfa5\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\x13L\xfb\xb1\xdfz \xb0\xedpWb.\xee\u0480\x94}\xad\x89\xcd\xff\x97\xfa\xbc\xb4`\x00\x00\xe0\x94\xc5\x17\xd01\\\x87\x88\x13\xc7\x17\u132f\xa1\xea\xb2eN\x01\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc5\x18y\x9aY%Wb\x13\xe2\x18\x96\xe0S\x9a\xbb\x85\xb0Z\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\"\xe2\x0f\xbf\x04\xed\u007fk\x05\xa3{G\x18\xd6\xfc\xe0\x14.\x1a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc5$\bmF\xc8\x11+\x12\x8b/\xafo|}\x81`\xa88l\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc5-\x1a\fs\u00a1\xbe\x84\x91Q\x85\xf8\xb3O\xaa\n\xdf\x1d\xe3\x89K\xe4\xea\xb3\xfa\x0f\xa6\x80\x00\xe0\x94\xc55\x94\xc7\u03f2\xa0\x8f(L\xc9\u05e6;\xbd\xfc\v1\x972\x8a\nk#(\xff:b\xc0\x00\x00\u07d4\xc57I(\xcd\xf1\x93pTC\xb1L\xc2\r\xa4#G<\xd9\u03c9\a}\x10P\x9b\xb3\xaf\x80\x00\u07d4\xc58\xa0\xff(*\xaa_Ku\u03f6,p\x03~\xe6}O\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5;P\xfd;+r\xbclC\v\xaf\x19JQU\x85\u04d8m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc5=y\xf7\u02dbp\x95/\xd3\x0f\xceX\xd5K\x9f\vY\xf6G\x8a\x01\x13\xe2\xd6tCE\xf8\x00\x00\u07d4\xc5I\u07c3\xc6\xf6^\xec\x0f\x1d\u0260\x93J\\_:P\xfd\x88\x89\x9d\xc0\\\xce(\u00b8\x00\x00\u07d4\xc5P\x05\xa6\xc3~\x8c\xa7\xe5C\xce%\x99s\xa3\xca\u0396\x1aJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5U\xb91V\xf0\x91\x01#\x80\x00\xe0\x94\u0166)\xa3\x96%R\u02ce\xde\u0609cj\xaf\xbd\f\x18\xcee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u016e\x86\xb0\xc6\xc7\xe3\x90\x0f\x13h\x10\\VS\u007f\xaf\x8dt>\x89\n1\x06+\xee\xedp\x00\x00\u07d4\u0170\t\xba\xea\xf7\x88\xa2v\xbd5\x81:\xd6[@\v\x84\x9f;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0175l\xd24&|(\xe8\x9cok\"f\xb0\x86\xa1/\x97\f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xc5\u01a4\x99\x8a3\xfe\xb7dCz\x8b\xe9)\xa7;\xa3J\ad\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x94\xc5\xc7=a\xcc\xe7\xc8\xfeL\x8f\xce)\xf3\x90\x92\xcd\x19>\x0f\xff\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc5\xc7Y\vV!\xec\xf85\x85\x88\u079bh\x90\xf2baC\U000498a1]\tQ\x9b\xe0\x00\x00\u07d4\xc5\xcd\xce\xe0\xe8]\x11}\xab\xbfSj?@i\xbfD?T\xe7\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xc5\u050c\xa2\xdb/\x85\xd8\xc5U\xcb\x0e\x9c\xfe\x82i6x?\x9e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc5\xde\x12\x03\xd3\xcc,\xea1\xc8.\xe2\xdeY\x16\x88\a\x99\xea\xfd\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc5\xe4\x88\xcf+Vw\x939q\xf6L\xb8 -\xd0WR\xa2\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\xe8\x12\xf7o\x15\xf2\xe1\xf2\xf9\xbcH#H<\x88\x04cog\x89\x03\xf5\x14\x19:\xbb\x84\x00\x00\u07d4\xc5\u94d34\xf1%.\u04ba&\x81D\x87\xdf\u0498+1(\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xc5\xebB)^\x9c\xad\xea\xf2\xaf\x12\xde\u078a\x8dS\xc5y\xc4i\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xc5\xed\xbb\xd2\xca\x03WeJ\xd0\xeaG\x93\xf8\xc5\xce\xcd0\xe2T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc5\xf6K\xab\xb7\x031B\xf2\x0eF\u05eab\x01\xed\x86\xf6q\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\xf6\x87qrF\u068a \r \xe5\u9f2c`\xb6\u007f8a\x89\x01\x8d\x99?4\xae\xf1\x00\x00\u07d4\xc6\x04[<5\vL\xe9\xca\fkuO\xb4\x1ai\xb9~\x99\x00\x892$\xf4'#\xd4T\x00\x00\u07d4\xc6\v\x04eN\x00;F\x83\x04\x1f\x1c\xbdk\u00cf\xda|\xdb\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x14F\xb7T\xc2N;\x16B\xd9\xe5\x17e\xb4\xd3\xe4k4\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x18R\x13!\xab\xaf[&Q:J\x95(\bo\"\n\xdco\x89\x01v\xb3D\xf2\xa7\x8c\x00\x00\u07d4\xc6#FW\xa8\a8A&\xf8\x96\x8c\xa1p\x8b\xb0{\xaaI<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6%\xf8\u024d'\xa0\x9a\x1b\u02bdQ(\xb1\u00a9HV\xaf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc65^\xc4v\x8cp\xa4\x9a\xf6\x95\x13\u0343\xa5\xbc\xa7\xe3\xb9\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc6:\xc4\x17\x99.\x9f\x9b`8n\xd9S\xe6\xd7\xdf\xf2\xb0\x90\xe8\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xc6<\u05c8!\x18\xb8\xa9\x1e\aML\x8fK\xa9\x18Q0;\x9a\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xc6R\x87\x1d\x19$\"\u01bc#_\xa0c\xb4J~\x1dC\u3149\bg\x0e\x9e\xc6Y\x8c\x00\x00\xe0\x94\xc6gD\x1e\u007f)y\x9a\xbaadQ\xd5;?H\x9f\x9e\x0fH\x8a\x02\xf2\x9a\xceh\xad\u0740\x00\x00\u07d4\xc6j\xe4\xce\xe8\u007f\xb352\x19\xf7\u007f\x1dd\x86\u0140(\x032\x89\x01\x9a\x16\xb0o\xf8\xcb\x00\x00\u07d4\xc6t\xf2\x8c\x8a\xfd\a?\x8by\x96\x91\xb2\xf0XM\xf9B\xe8D\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0197\xb7\x04w\u02b4.+\x8b&f\x81\xf4\xaesu\xbb%A\x8a\x01.W2\xba\xba\\\x98\x00\x00\u07d4\u019b\x85U9\xce\x1b\x04qG(\xee\xc2Z7\xf3g\x95\x1d\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u019b\xe4@\x13Mb\x80\x98\x01D\xa9\xf6M\x84t\x8a7\xf3I\x89&\u009eG\u0104L\x00\x00\u07d4\u019df<\x8d`\x90\x83\x91\xc8\xd26\x19\x153\xfd\xf7wV\x13\x89\x1aJ\xba\"\\ t\x00\x00\u0794\u01a2\x86\xe0e\xc8_:\xf7H\x12\xed\x8b\u04e8\xce]%\xe2\x1d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\u01a3\x0e\xf5\xbb3 \xf4\r\xc5\xe9\x81#\rR\xae:\xc1\x93\"\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\u01ae(}\xdb\xe1\x14\x9b\xa1m\xdc\xcaO\xe0j\xa2\uaa48\xa9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xc7\xc1\x917\x98\x97\u075c\x9d\x9a3\x83\x9cJ_b\xc0\x89\r\x89\xd8\xd8T\xb2$0h\x80\x00\xe0\x94\xc6\xcdh\xec56,Z\xd8L\x82\xadN\xdc#!%\x91-\x99\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u07d4\xc6\u0615N\x8f?\xc53\xd2\xd20\xff\x02\\\xb4\xdc\xe1O4&\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xdb\u06de\xfd^\xc1\xb3xn\x06q\xeb\"y\xb2S\xf2\x15\xed\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc6\xdf u\xeb\xd2@\xd4Hi\u00bek\u07c2\xe6=N\xf1\xf5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6\xe2\xf5\xaf\x97\x9a\x03\xfdr:\x1bn\xfar\x83\x18\u03dc\x18\x00\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xc6\xe3$\xbe\xeb[6v^\xcdFB`\xf7\xf2`\x06\xc5\xc6.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\xe4\xcc\fr\x83\xfc\x1c\x85\xbcH\x13\xef\xfa\xafr\xb4\x98#\xc0\x89\x0f\x03\x1e\xc9\xc8}\xd3\x00\x00\xe0\x94\xc6\xee5\x93B)i5)\xdcA\u067bq\xa2IfX\xb8\x8e\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xc6\xfb\x1e\xe3t\x17\u0400\xa0\xd0H\x92;\u06ba\xb0\x95\xd0w\u0189\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc7\x05'\xd4D\u0110\xe9\xfc?\\\xc4Nf\xebO0k8\x0f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\r\x85mb\x1e\xc1E0<\nd\x00\xcd\x17\xbb\xd6\xf5\xea\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc7\x0f\xa4Uv\xbf\x9c\x86_\x988\x93\x00,AI&\xf6\x10)\x89\x15\xb4\xaa\x8e\x97\x02h\x00\x00\u07d4\xc7\x11E\xe5)\u01e7\x14\xe6y\x03\xeeb\x06\xe4\xc3\x04+g'\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xc7\x1b*=q5\u04a8_\xb5\xa5q\u073ei^\x13\xfcC\u034965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\x1f\x1du\x87?3\u0732\xddK9\x87\xa1-\a\x91\xa5\xce'\x897\b\xba\xed=h\x90\x00\x00\u07d4\xc7\x1f\x92\xa3\xa5J{\x8c/^\xa4C\x05\xfc\u02c4\xee\xe21H\x89\x02\xb5\x9c\xa11\xd2\x06\x00\x00\u07d4\xc7!\xb2\xa7\xaaD\xc2\x12\x98\xe8P9\xd0\x0e.F\x0eg\v\x9c\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xc7,\xb3\x01%\x8e\x91\xbc\b\x99\x8a\x80]\u0452\xf2\\/\x9a5\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc76\x8b\x97\t\xa5\xc1\xb5\x1c\n\xdf\x18ze\xdf\x14\xe1+}\xba\x8a\x02\x02o\xc7\u007f\x03\u5b80\x00\u07d4\xc79%\x9e\u007f\x85\xf2e\x9b\xef_`\x9e\xd8k=Yl \x1e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc7>!\x12(\"\x15\xdc\ab\xf3+~\x80}\xcd\x1az\xae>\x8a\x01v\f\xbcb;\xb3P\x00\x00\xe0\x94\xc7If\x80B\xe7\x11#\xa6H\x97^\b\xedc\x82\xf8>\x05\xe2\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xc7J9\x95\xf8\a\xde\x1d\xb0\x1a.\xb9\xc6.\x97\xd0T\x8fio\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7Pl\x10\x19\x12\x1f\xf0\x8a,\x8c\x15\x91\xa6^\xb4\xbd\xfbJ?\x89 \x86\xac5\x10R`\x00\x00\u07d4\xc7\\7\xce-\xa0k\xbc@\b\x11Y\u01ba\x0f\x97n9\x93\xb1\x89:y#\x15\x1e\xcfX\x00\x00\u07d4\xc7]\"Y0j\xec}\xf0\"v\x8ci\x89\x9ae!\x85\xdb\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7`\x97\x1b\xbc\x18\x1cj|\xf7tA\xf2BG\u045c\xe9\xb4\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc7a0\xc7<\xb9!\x028\x02\\\x9d\xf9]\v\xe5J\xc6\u007f\xbe\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xc7e\xe0\x04v\x81\tG\x81j\xf1B\xd4m.\u7f28\xccO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc7g^VG\xb9\xd8\xda\xf4\xd3\xdf\xf1\xe5R\xf6\xb0qT\xac8\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xc7{\x01\xa6\xe9\x11\xfa\x98\x8d\x01\xa3\xab3dk\xee\xf9\xc18\xf3\x89'\x1bo\xa5\xdb\xe6\xcc\x00\x00\u07d4\u01c3z\u0420\xbf\x14\x18i7\xac\xe0lUF\xa3j\xa5OF\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01d8\x06\x03+\xc7\xd8(\xf1\x9a\u01a6@\u018e=\x82\x0f\xa4B\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u01d9\xe3N\x88\xff\x88\xbe}\xe2\x8e\x15\xe4\xf2\xa6=\v3\xc4\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u01ddPb\u01d6\xddwa\xf1\xf1>U\x8ds\xa5\x9f\x82\xf3\x8b\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\u01e0\x18\xf0\x96\x8aQ\xd1\xf6`<\\I\xdcT[\xcb\x0f\xf2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01ef\xf9\x19)yt\x89UZ/\xf1\xd1M\\iZ\x10\x83U\x8965\u026d\xc5\u07a0\x00\x00\u0794\u01f1\xc8>c ?\x95G&>\xf6(.}\xa3;n\xd6Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\u01f3\x9b\x06\x04Q\x00\f\xa1\x04\x9b\xa1T\xbc\xfa\x00\xff\x8a\xf2b\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\u01ff\x17\xc4\xc1\x1f\x98\x94\x1fP~w\bO\xff\xbd-\xbd=\xb5\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u01ff.\xd1\xed1)@\xeej\xde\xd1Qn&\x8eJ`HV\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc7\xd4O\xe3,\u007f\x8c\xd5\xf1\xa9t'\xb6\xcd:\xfc\x9eE\x02>\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xc7\xd5\xc7\x05@\x81\xe9\x18\xech{Z\xb3n\x97=\x18\x13)5\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xc7\xde^\x8e\xaf\xb5\xf6+\x1a\n\xf2\x19\\\xf7\x93\u01c9L\x92h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\xe30\xcd\f\x89\n\u025f\xe7q\xfc\xc7\xe7\xb0\t\xb7A=\x8a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\xea\xc3\x1a\xbc\xe6\xd5\xf1\u07a4\"\x02\xb6\xa6t\x15=\xb4z)\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc7\xecb\xb8\x04\xb1\xf6\x9b\x1e0p\xb5\xd3b\xc6/\xb3\t\xb0p\x8a\x02\xc4k\xf5A`f\x11\x00\x00\u07d4\xc7\xf7+\xb7X\x01k7G\x14\u0509\x9b\xce\"\xb4\xae\xc7\n1\x89:&\xc9G\x8f^-\x00\x00\u0794\xc8\v6\u047e\xaf\xba_\xccdM`\xacnF\xed)'\xe7\u0708\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xc8\x11\xc2\xe9\xaa\x1a\xc3F.\xba^\x88\xfc\xb5\x12\x0e\x9fn,\xa2\x89K\xe6\u0607\xbd\x87n\x00\x00\u07d4\xc8\x17\xdf\x1b\x91\xfa\xf3\x0f\xe3%\x15qr|\x97\x11\xb4]\x8f\x06\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xc8\x1f\xb7\xd2\x0f\u0480\x01\x92\xf0\xaa\xc1\x98\xd6\u05a3}?\xcb}\x89\x0e\x11I3\x1c-\xde\x00\x00\u07d4\xc8 \xc7\x11\xf0w\x05'8\a\xaa\xaam\xe4M\x0eKH\xbe.\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4\xc8#\x1b\xa5\xa4\x11\xa1>\"+)\xbf\xc1\b?v1X\xf2&\x8967\tlK\xcci\x00\x00\u07d4\xc86\xe2Jo\xcf)\x94;6\b\xe6b)\n!_e)\xea\x89\x0f\xd4Pd\xea\xee\x10\x00\x00\xe0\x94\xc8;\xa6\u0755I\xbe\x1d2\x87\xa5\xa6T\xd1\x06\xc3Lk]\xa2\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc8>\x9djX%;\uefb7\x93\xe6\xf2\x8b\x05JXI\x1bt\x89\x0fF\u00b6\xf5\xa9\x14\x00\x00\u07d4\xc8A\x88O\xa4x_\xb7s\xb2\x8e\x97\x15\xfa\xe9\x9aQ40]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8M\x9b\xea\n{\x9f\x14\x02 \xfd\x8b\x90\x97\u03ff\xd5\xed\xf5d\x89\x06\xab\x9e\u0091\xad}\x80\x00\u07d4\xc8RB\x8d+Xd\x97\xac\xd3\fV\xaa\x13\xfbU\x82\xf8D\x02\x893B\xd6\r\xff\x19`\x00\x00\u07d4\xc8S![\x9b\x9f-,\xd0t\x1eX^\x98{_\xb8\f!.\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc8S%\uaca5\x9b>\xd8c\xc8j_)\x06\xa0B)\xff\xa9\x89\x19=\u007f}%=\xe0\x00\x00\u07d4\xc8^\xf2}\x82\x04\x03\x80_\xc9\xed%\x9f\xffd\xac\xb8\xd64j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8akN\xc0\x91(\xcd\xff9\xd6\u4e6c\x86\xee\xc4q\xd5\xf2\x89\x01\r:\xa56\xe2\x94\x00\x00\xe0\x94\xc8a\x90\x90K\x8d\a\x9e\xc0\x10\xe4b\xcb\xff\xc9\b4\xff\xaa\\\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4\xc8q\r~\x8bZ;\u059aB\xfe\x0f\xa8\xb8|5\u007f\xdd\xcd\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc8sR\u06e5\x82\xee f\xb9\xc0\x02\xa9b\xe0\x03\x13Ox\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xc8|w\xe3\xc2J\xde\xcd\xcd\x108\xa3\x8bV\xe1\x8d\xea\u04f7\x02\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xc8}:\xe3\u0607\x04\u066b\x00\t\xdc\xc1\xa0\x06q1\xf8\xba<\x89j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\u0201N4R>8\xe1\xf9'\xa7\xdc\xe8FjDz\t6\x03\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0202U\xed\xdc\xf5!\xc6\xf8\x1d\x97\xf5\xa4!\x81\xc9\a=N\xf1\x89\x0f\u00d0D\xd0\n*\x80\x00\u07d4\u0205\xa1\x8a\xab\xf4T\x1b{{~\xcd0\xf6\xfa\u619d\x95i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u020c\xa1\xe6\xe5\xf4\xd5X\xd17\x80\xf4\x88\xf1\rJ\xd3\x13\r4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u020e\xecT\xd3\x05\xc9(\xcc(H\xc2\xfe\xe251\xac\xb9mI\x89lj\u04c2\xd4\xfba\x00\x00\xe0\x94\u021c\xf5\x04\xb9\xf3\xf85\x18\x1f\xd8BO\\\xcb\xc8\xe1\xbd\xdf}\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0222\xc4\xe5\x9e\x1c\u007f\xc5H\x05X\x048\xae\xd3\xe4J\xfd\xf0\x0e\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\u022aI\u301f\b\x99\xf2\x8a\xb5~gCp\x9dXA\x903\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\u022b\x1a<\xf4l\xb8\xb0d\xdf.\"-9`s\x94 2w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0231\x85\x05%\xd9F\xf2\xae\x84\xf3\x17\xb1Q\x88\xc56\xa5\u0706\x89\x91\x8d\xdc:B\xa3\xd4\x00\x00\u07d4\xc8\xd4\xe1Y\x9d\x03\xb7\x98\t\xe0\x13\n\x8d\u00c4\b\xf0^\x8c\u04c9\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xc8\xdd'\xf1k\xf2$P\xf5w\x1b\x9f\xe4\xedO\xfc\xb3\t6\xf4\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xc8\xdezVL\u007f@\x12\xa6\xf6\xd1\x0f\u040fG\x89\x0f\xbf\a\u0509\x10CV\x1a\x88)0\x00\x00\u07d4\xc8\xe2\xad\xebT^I\x9d\x98,\f\x11sc\u03b4\x89\u0171\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xc8\xe5X\xa3\xc5i~o\xb2:%\x94\u0200\xb7\xa1\xb6\x8f\x98`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc8\xf2\xb3 \xe6\xdf\xd7\t\x06\u0157\xba\xd2\xf9P\x13\x12\u01c2Y\x89Q\x93K\x8b:W\xd0\x00\x00\u07d4\xc9\x03\x00\xcb\x1d@w\xe6\xa6\xd7\xe1i\xa4`F\x8c\xf4\xa4\x92\u05c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\f7e\x15k\u028eH\x97\xab\x80$\x19\x15<\xbeR%\xa9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc9\x10\xa9pUl\x97\x16\xeaS\xaff\xdd\xef\x93\x141$\x91=\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94\xc9\x12{\u007ff)\xee\x13\xfc?`\xbc/Dg\xa2\aE\xa7b\x8a\x03|\x9a\xa4\xe7\xceB\x1d\x80\x00\u07d4\xc9\x1b\xb5b\xe4+\xd4a0\xe2\u04eeFR\xb6\xa4\ub1bc\x0f\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\xe0\x94\xc90\x88y\x05m\xfe\x13\x8e\xf8 \x8fy\xa9\x15\u01bc~p\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xc94\xbe\xca\xf7\x1f\"_\x8bJK\xf7\xb1\x97\xf4\xac\x9604\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9?\xbd\xe8\xd4m+\xcc\x0f\xa9\xb3;\u063a\u007f\x80B\x12Ue\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xc9@\x89U:\xe4\xc2,\xa0\x9f\xbc\x98\xf5pu\xcf.\u0155\x04\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc9A\x10\xe7\x1a\xfeW\x8a\xa2\x18\xe4\xfc(d\x03\xb03\n\u038d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc9F\u056c\xc14n\xba\nry\xa0\xac\x1dF\\\x99m\x82~\x8a\x03x=T_\xdf\n\xa4\x00\x00\u07d4\xc9J(\xfb20\xa9\xdd\xfa\x96Nw\x0f,\xe3\xc2S\xa7\xbeO\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc9JXR\x03\xda{\xba\xfd\x93\xe1X\x84\xe6`\u0531\xea\xd8T\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc9O|5\xc0'\xd4}\xf8\xefO\x9d\xf8Z\x92H\xa1}\xd2;\x89\x01\x9f\x8euY\x92L\x00\x00\u07d4\xc9Q\x90\f4\x1a\xbb\xb3\xba\xfb\xf7\xee )7pq\xdb\xc3j\x89\x11\xc2]\x00M\x01\xf8\x00\x00\u07d4\xc9S\xf94\xc0\xeb-\x0f\x14K\u06b0\x04\x83\xfd\x81\x94\x86\\\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9f&r\x8a\xaaLO\xb3\xd3\x1c&\xdf:\xf3\x10\b\x17\x10\u0449\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xc9gQel\n\x8e\xf45{sD2!4\xb9\x83PJ\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\u0240Hh\u007f+\xfc\u027d\x90\xed\x18slW\xed\xd3R\xb6]\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0241\xd3\x12\u0487\xd5X\x87\x1e\u0757:\xbbv\xb9y\xe5\xc3^\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0242Xmc\xb0\xd7L \x1b\x1a\xf8A\x83r\xe3\fv\x16\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u0249CO\x82Z\xaf\x9cU/h^\xba|\x11\xdbJ_\xc7:\x89\x1b(\u014d\x96\x96\xb4\x00\x00\u07d4\u0249\xee\xc3\a\u80db\x9dr7\xcf\xda\b\x82)b\xab\u41c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u0252\xbeY\xc6r\x1c\xafN\x02\x8f\x9e\x8f\x05\xc2\\UQ[\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0255{\xa9L\x1b)\xe5'~\xc3f\"pI\x04\xc6=\xc0#\x89h>\xfcg\x82d,\x00\x00\xe0\x94\u025a\x9c\xd6\xc9\xc1\xbe54\xee\u0352\xec\xc2/\\8\xe9Q[\x8a\x01\x05Y;:\x16\x9dw\x00\x00\xe0\x94\u026c\x01\xc3\xfb\t)\x03?\f\xcc~\x1a\xcf\uaae7\x94]G\x8a\x02\xa3j\x9e\x9c\xa4\xd2\x03\x80\x00\u07d4\u0276\x98\xe8\x98\xd2\rMO@\x8eNM\x06\x19\"\xaa\x85c\a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u0276\xb6\x86\x11\x16\x91\xeej\xa1\x97\xc7#\x1a\x88\xdc`\xbd)]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\u01ec\v\u0753B\xb5\xea\xd46\t#\xf6\x8cr\xa6\xbac:\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\xc8\r\xc1.{\xab\x86\xe9I\xd0\x1eL>\xd3_+\x9b\xba_\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\xd7dF\u056a\xdf\xf8\vh\xb9\x1b\b\u035b\xc8\xf5U\x1a\xc1\x89&\xb4\xbd\x91\x10\xdc\xe8\x00\x00\xe0\x94\xc9\u073b\x05oM\xb7\xd9\xda9\x93b\x02\u017d\x820\xb3\xb4w\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9\xe0&\b\x06h(\x84\x8a\xeb(\xc76r\xa1)%\x18\x1fM\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xca\x042\xcb\x15{Qy\xf0.\xbb\xa5\xc9\u0475O\xecM\x88\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xca\x12,\xf0\U00094216\xb7HC\xf4\x9a\xfe\u043a\x16\x18\xee\u05c9\x1e[\x8f\xa8\xfe*\xc0\x00\x00\xe0\x94\xca\"\u0363`m\xa5\xca\xd0\x13\xb8\aG\x06\xd7\xe9\xe7!\xa5\f\x8a\x01q\x81\xc6\xfa9\x81\x94\x00\x00\u07d4\xca#\xf6-\xff\rd`\x03lb\xe8@\xae\xc5W~\v\xef\u0489\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xca%\xff4\x93L\x19B\xe2*N{\xd5o\x14\x02\x1a\x1a\xf0\x88\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xca7?\xe3\xc9\x06\xb8\xc6U\x9e\xe4\x9c\xcd\a\xf3|\xd4\xfbRf\x89a\t=|,m8\x00\x00\u07d4\xcaA\u032c0\x17 R\xd5\"\xcd//\x95}$\x81S@\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xcaB\x88\x01N\xdd\xc5c/_\xac\xb5\xe3\x85\x17\xa8\xf8\xbc]\x98\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xcaB\x88c\xa5\xca06\x98\x92\xd6\x12\x18>\xf9\xfb\x1a\x04\xbc\xea\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xcaI\xa5\xf5\x8a\xdb\xef\xae#\xeeY\xee\xa2A\xcf\x04\x82b.\xaa\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcaL\xa9\xe4w\x9dS\x0e\u02ec\xd4~j\x80X\xcf\xdee\u064f\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xcae~\xc0o\xe5\xbc\t\xcf#\xe5*\xf7\xf8\f\xc3h\x9en\u07890\xca\x02O\x98{\x90\x00\x00\u07d4\xcaf\xb2(\x0f\xa2\x82\u0176v1\xceU+b\xeeU\xad\x84t\x89j\xc4\"\xf54\x92\x88\x00\x00\xe0\x94\xcal\x81\x8b\xef\xd2Q6\x1e\x02t@h\xbe\x99\u062a`\xb8J\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcap\xf4\u077f\x06\x9d!C\xbdk\xbc\u007fikRx\x9b2\u7262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xcatuvDjL\x8f0\xb0\x83@\xfe\xe1\x98\xdec\xec\x92\u03ca\x01|\x8e\x12\x06r*0\x00\x00\u07d4\xca{\xa3\xffSl~_\x0e\x158\x00\xbd8=\xb81)\x98\xe0\x89\t1\xac=k\xb2@\x00\x00\xe0\x94\u0282v\xc4w\xb4\xa0{\x80\x10{\x845\x94\x18\x96\a\xb5;\xec\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u0284\t\b>\x01\xb3\x97\xcf\x12\x92\x8a\x05\xb6\x84U\xceb\x01\u07c9V\xbcu\xe2\xd61\x00\x00\x00\u07d4\u0298\u01d8\x8e\xfa\b\xe9%\uf719ER\x03&\xe9\xf4;\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u029a\x04*j\x80o\xfc\x92\x17\x95\x00\xd2D)\xe8\xabR\x81\x17\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\u029d\xec\x02\x84\x1a\xdf\\\xc9 WjQ\x87\xed\u04bdCJ\x18\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u029f\xaa\x17T/\xaf\xbb8\x8e\xab!\xbcL\x94\u89f3G\x88\x89lk\x8f\xce\r\x18y\x80\x00\xe0\x94\u02aah\xeel\xdf\r4EJv\x9b\r\xa1H\xa1\xfa\xaa\x18e\x8a\x01\x87.\x1d\xe7\xfeR\xc0\x00\x00\u07d4\u02ad\x9d\xc2\rX\x9c\xe4(\xd8\xfd\xa3\xa9\xd5:`{y\x88\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u02b0\xd3,\xf3v\u007f\xa6\xb3S|\x842\x8b\xaa\x9fPE\x816\x8a\x01\xe5\xb8\xfa\x8f\xe2\xac\x00\x00\x00\u07d4\u02b9\xa3\x01\xe6\xbdF\xe9@5P(\xec\xcd@\xceMZ\x1a\u00c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u02b9\xa9z\xda\x06\\\x87\x81nh`\xa8\xf1Bo\xe6\xb3\xd7u\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u02ba\xb6'N\xd1P\x89s~({\xe8x\xb7W\x93Hd\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u02bd\xaf5OG \xa4f\xa7d\xa5(\xd6\x0e:H*9<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xca\xcbg^\t\x96#T\x04\ufbfb.\u02c1R'\x1bU\xe0\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xca\xd1O\x9e\xbb\xa7f\x80\xeb\x83k\a\x9c\u007f{\xaa\xf4\x81\xedm\x89\f\xef={\xd7\xd04\x00\x00\xe0\x94\xca\xe3\xa2S\xbc\xb2\xcfN\x13\xba\x80\u0098\xab\x04\x02\xda|*\xa0\x8a\x01$\xbc\r\u0752\xe5`\x00\x00\u07d4\xca\xef\x02{\x1a\xb5\x04\xc7?A\xf2\xa1\ty\xb4t\xf9~0\x9f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xca\xf4H\x1d\x9d\xb7\x8d\xc4\xf2_{J\u023d;\x1c\xa0\x10k1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xca\xfd\xe8U\x86L%\x98\xda<\xaf\xc0Z\u064d\U00089380H\x8a\x03\x00\xa8\xed\x96\xffJ\x94\x00\x00\xe0\x94\xcb\r\xd7\xcfN]\x86a\xf6\x02\x89C\xa4\xb9\xb7\\\x91D6\xa7\x8a\x19i6\x89t\xc0[\x00\x00\x00\u07d4\xcb\x1b\xb6\xf1\xda^\xb1\rH\x99\xf7\xe6\x1d\x06\xc1\xb0\x0f\u07f5-\x898E$\xccp\xb7x\x00\x00\u07d4\xcb=vl\x98?\x19+\xce\xca\xc7\x0fN\xe0=\xd9\xffqMQ\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcbB\xb4N\xb5\xfd`\xb5\x83~O\x9e\xb4rgR=\x1a\"\x9c\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xcbG\xbd0\u03e8\xecTh\xaa\xa6\xa9FB\xce\xd9\xc8\x19\xc8\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcbH\xfe\x82e\u066fU\xebp\x06\xbc3VE\xb0\xa3\xa1\x83\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xcbJ\x91M+\xb0)\xf3._\xef\\#LO\xec--\xd5w\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcbJ\xbf\u0082\xae\xd7n]W\xaf\xfd\xa5B\xc1\xf3\x82\xfc\xac\xf4\x8a\x01\xb9\x0f\x11\xc3\x18?\xaa\x00\x00\u07d4\xcbJ\xd0\xc7#\xdaF\xabV\xd5&\xda\f\x1d%\xc7=\xaf\xf1\n\x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\xcbK\xb1\xc6#\xba(\xdcB\xbd\xaa\xa6\xe7N\x1d*\xa1%l*\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xcbPXt\x12\x82#\x04\xeb\u02e0}\xab:\x0f\t\xff\xfe\u4189JD\x91\xbdm\xcd(\x00\x00\u07d4\xcbX\x99\v\u0350\u03ffm\x8f\t\x86\xf6\xfa`\x02v\xb9N-\x8964\xbf9\xab\x98x\x80\x00\u07d4\xcbh\xaeZ\xbe\x02\xdc\xf8\xcb\u016aq\x9c%\x81FQ\xaf\x8b\x85\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xcbty\x10\x9bC\xb2fW\xf4F_M\x18\xc6\xf9t\xbe_B\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xcb}+\x80\x89\xe91,\u026e\xaa's\xf3S\b\xecl*{\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u02c6\xed\xbc\x8b\xbb\x1f\x911\x02+\xe6IV^\xbd\xb0\x9e2\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u02d3\x19\x9b\x9c\x90\xbcI\x15\xbd\x85\x9e=B\x86m\xc8\xc1\x87I\x89\f\x90\xdf\a\xde\xf7\x8c\x00\x00\u07d4\u02d4\xe7o\xeb\xe2\b\x11g3\xe7n\x80]H\xd1\x12\xec\x9f\u028965\u026d\xc5\u07a0\x00\x00\u07d4\u02dbQ\x03\xe4\u0389\xafOd\x91aP\xbf\xf9\xee\u02df\xaa\\\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\\zP<\xc8\xe0\xd0Iq\xca\x05\xc7b\xf9\xb7b\xb4\x8b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\x88\xcd<\x1e\xb4\u055d\xdb\x06\xa6B\x1c\x14\xc3E\xa4{$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u02f3\x18\x9eK\xd7\xf4_\x17\x8b\x1c0\xc7n&1MJK\n\x89\x0f\xfe\vg|e\xa9\x80\x00\xe0\x94\u02f7\xbe\x17\x95?,\u0313\u1f19\x80[\xf4U\x11CNL\x8a\n\xae[\x9d\xf5m/ \x00\x00\xe0\x94\xcb\xc0KM\x8b\x82\xca\xf6p\x99o\x16\f6)@\xd6o\xcf\x1a\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcb\u07974\xb8\xe6\xaaS\x8c)\x1dm\u007f\xac\xed\xb0\xf38\xf8W\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcb\xe1\xb9H\x86M\x84t\xe7e\x14XX\xfc\xa4U\x0fxK\x92\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xe5/\xc53\xd7\xdd`\x8c\x92\xa2`\xb3|?E\u07b4\xeb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcb\xe8\x10\xfe\x0f\xec\xc9dGJ\x1d\xb9w(\xbc\x87\xe9s\xfc\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xf1j\x0f\xe2tRX\xcdR\xdb+\xf2\x19T\xc9u\xfcj\x15\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\xcb\xf3\u007f\xf8T\xa2\xf1\xceS\x93D\x94wx\x92\xd3\xeceW\x82\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xfaj\xf6\u0083\xb0F\xe2w,`c\xb0\xb2\x15S\xc4\x01\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcb\xfav\xdb\x04\xce8\xfb ]7\xb8\xd3w\xcf\x13\x80\xda\x03\x17\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcc\x03I\x85\xd3\xf2\x8c-9\xb1\xa3K\xce\xd4\u04f2\xb6\xca#N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xcc\x04\x8d\u01f9]\xca%\xdf&\xee\xfac\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc+_D\x8f5(\xd3\xfeA\xcc}\x1f\xa9\xc0\xdcv\xf1\xb7v\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc-\x04\xf0\xa4\x01q\x89\xb3@\xcaw\x19\x86A\xdc\xf6Ek\x91\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xccA\x9f\u0651+\x85\x13VY\xe7z\x93\xbc=\xf1\x82\xd4Q\x15\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccE\xfb:U[\xad\x80{8\x8a\x03W\xc8U _|u\xe8\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xccHAM*\xc4\xd4*Yb\xf2\x9e\xeeD\x97\t/C\x13R\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\xccJ/,\xf8l\xf3\xe43u\xf3`\xa4sF\x91\x19_\x14\x90\x89I\x15\x05;\xd1)\t\x80\x00\u07d4\xccO\x0f\xf2\xae\xb6}T\xce;\xc8\xc6Q\v\x9a\xe8>\x9d2\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xccO\xaa\xc0\v\xe6b\x8f\x92\xefk\x8c\xb1\xb1\xe7j\xac\x81\xfa\x18\x89\v\"\xa2\xea\xb0\xf0\xfd\x00\x00\xe0\x94\xccO\xebr\u07d8\xff5\xa18\xe0\x17a\xd1 ?\x9b~\xdf\n\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xcc`oQ\x13\x97\xa3\x8f\u01c7+\u04f0\xbd\x03\xc7\x1b\xbdv\x8b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcc`\xf86\xac\xde\xf3T\x8a\x1f\xef\u0321>\u01a97\xdbD\xa0\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\xccl\x03\xbd`>\t\xdeT\xe9\xc4\u056cmA\xcb\xceqW$\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xccl-\xf0\x0e\x86\xec\xa4\x0f!\xff\xda\x1ag\xa1i\x0fG|e\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\xccm{\x12\x06\x1b\xc9m\x10M`me\xff\xa3+\x006\xeb\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccs\xdd5kIy\xb5y\xb4\x01\xd4\xccz1\xa2h\xdd\xceZ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xccu\x8d\a\x1d%\xa62\n\xf6\x8c]\xc9\xc4\xf6\x95[\xa9E \x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcc{\x04\x81\xcc2\xe6\xfa\xef#\x86\xa0p\"\xbc\xb6\xd2\u00f4\xfc\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\u0314;\xe1\",\xd1@\n#\x99\xdd\x1bE\x94E\xcfmT\xa9\x8a\x02\xa7@\xaee6\xfc\x88\x00\x00\u07d4\u0315\x19\xd1\xf3\x98_k%^\xad\xed\x12\xd5bJ\x97'!\xe1\x8965\u026d\xc5\u07a0\x00\x00\u0794\u031a\xc7\x15\xcdo&\x10\xc5+XgdV\x88B\x97\x01\x8b)\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\u0320{\xb7\x94W\x1dJ\xcf\x04\x1d\xad\x87\xf0\xd1\xef1\x85\xb3\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u032b\xc6\x04\x8aSFD$\xfc\xf7n\xeb\x9en\x18\x01\xfa#\u0509\x02\xab{&\x0f\xf3\xfd\x00\x00\u07d4\u032e\r=\x85*}\xa3\x86\x0f\x066\x15L\nl\xa3\x16(\u0509\x05\xc6\xd1+k\xc1\xa0\x00\x00\u07d4\xcc\xca$\xd8\xc5mn,\a\xdb\bn\xc0~X[\xe2g\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcc\xd5!\x13-\x98l\xb9hi\x84&\"\xa7\u0762l>\xd0W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc\xf49u\xb7k\xfes_\xec<\xb7\xd4\xdd$\xf8\x05\xba\tb\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc\xf6*f?\x13S\xba.\xf8\xe6R\x1d\xc1\xec\xb6s\xec\x8e\xf7\x89\b=lz\xabc`\x00\x00\u07d4\xcc\xf7\x11\r\x1b\u0667K\xfd\x1d}}-\x9dU`~{\x83}\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xcc\xfdrW`\xa6\x88#\xff\x1e\x06/L\xc9~\x13`\xe8\u0657\x89\x15\xacV\xed\xc4\xd1,\x00\x00\u07d4\xcd\x02\x0f\x8e\xdf\xcfRG\x98\xa9\xb7:d\x034\xbb\xf7/\x80\xa5\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xcd\x06\xf8\xc1\xb5\u037d(\xe2\xd9kcF\xc3\xe8Z\x04\x83\xba$\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcd\a.n\x183\x13y\x95\x19m{\xb1r_\xef\x87a\xf6U\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcd\n\x16\x1b\xc3g\xae\t'\xa9*\xac\x9c\xf6\xe5\bg\x14\xef\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\n\xf3GN\"\xf0i\xec4\a\x87\r\xd7pD=[\x12\xb0\x89\x8e^\xb4\xeew\xb2\xef\x00\x00\u07d4\xcd\v\x02W\u70e3\xd2\xc2\u3e9dny\xb7^\xf9\x80$\u0509\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xcd\x10,\xd6\xdb=\xf1J\u05af\x0f\x87\xc7$y\x86\x1b\xfc=$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\x1ef\xedS\x9d\xd9/\xc4\v\xba\xa1\xfa\x16\u078c\x02\xc1ME\x89\fw\xe4%hc\xd8\x00\x00\u07d4\xcd\x1e\xd2c\xfb\xf6\xf6\xf7\xb4\x8a\xef\x8fs=2\x9dC\x82\xc7\u01c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4\xcd*6\xd7S\xe9\xe0\xed\x01*XMqh\aX{A\xd5j\x89\x0e+\xa7[\v\x1f\x1c\x00\x00\u07d4\xcd2\xa4\xa8\xa2\u007f\x1c\xc69T\xaacOxW\x05s4\u01e3\x89:\xd1fWlr\xd4\x00\x00\u07d4\xcd5\xff\x01\x0e\xc5\x01\xa7!\xa1\xb2\xf0z\x9c\xa5\x87}\xfc\xf9Z\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xcdC\x06\xd7\xf6\x94z\xc1tMN\x13\xb8\xef2\xcbe~\x1c\x00\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4\xcdC%\x8bs\x92\xa90\x83\x9aQ\xb2\xef\x8a\xd24\x12\xf7Z\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcdI\xbf\x18^p\xd0E\a\x99\x9f\x92\xa4\xdeDU1('\u040965\u026d\xc5\u07a0\x00\x00\u07d4\xcdU\x10\xa2B\u07f0\x18=\xe9%\xfb\xa8f\xe3\x12\xfa\xbc\x16W\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xcdVj\u05f8\x83\xf0\x1f\u04d9\x8a\x9aX\xa9\xde\xe4rM\u0725\x89\x030\xae\x185\xbe0\x00\x00\xe0\x94\xcdY\xf3\xdd\xe7~\t\x94\v\xef\xb6\xeeX\x03\x19e\xca\xe7\xa36\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcdr]p\xbe\x97\xe6w\xe3\xc8\xe8\\\v&\xef1\xe9\x95PE\x89Hz\x9a0E9D\x00\x00\xe0\x94\xcd~G\x90\x94d\xd8q\xb9\xa6\xdcv\xa8\xe9\x19]\xb3H^z\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xcd~\xce\bkKa\x9b;6\x93R\xee8\xb7\x1d\xdb\x06C\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcd\u007f\t\xd7\xedf\xd0\u00cb\u016dN2\xb7\xf2\xb0\x8d\xc1\xb3\r\x89>;\xb3M\xa2\xa4p\x00\x00\u07d4\u0355)I+\\)\xe4u\xac\xb9A@+=;\xa5\x06\x86\xb0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0355\xfaB=o\xc1 'J\xac\xde\x19\xf4\xee\xb7f\xf1\x04 \x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u035bL\xefs9\f\x83\xa8\xfdq\u05f5@\xa7\xf9\u03cb\x8c\x92\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\u0361t\x11\t\xc0&[?\xb2\xbf\x8d^\xc9\u00b8\xa34kc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0361\xb8\x86\u39d5\u027aw\x91N\n/\xe5go\x0f\\\u03c9\x05\xbf`\xeaB\xc2\x04\x00\x00\u07d4\u0364S\x0fK\x9b\xc5\t\x05\xb7\x9d\x17\u008f\xc4o\x954\x9b\u07c93\x10\xe0I\x11\xf1\xf8\x00\x00\u07d4\u036bF\xa5\x90 \x80do\xbf\x95B\x04 J\xe8\x84\x04\x82+\x89\x1d\x8a\x96\xe5\xc6\x06\xeb\x00\x00\u07d4\u0375\x97)\x900\x18?n-#\x853\xf4d*\xa5\x87T\xb6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xcd\xd5\u0601\xa76,\x90p\a;\u07fcu\xe7$S\xacQ\x0e\x89-\xa5\x18\xea\xe4\x8e\xe8\x00\x00\u07d4\xcd\xd6\rs\xef\xaa\xd8s\u027b\xfb\x17\x8c\xa1\xb7\x10Z\x81\xa6\x81\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xcd\xd9\xef\xacMm`\xbdq\xd9U\x85\xdc\xe5\u0557\x05\xc15d\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcd\xe3m\x81\xd1(\u015d\xa1Ee!\x93\xee\u00bf\xd9e\x86\xef\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcd\xea8o\x9d\x0f\xd8\x04\xd0(\x18\xf27\xb7\xd9\xfavF\xd3^\x89\xa3I\xd3m\x80\xecW\x80\x00\u07d4\xcd\xec\xf5gT3\u0370\xc2\xe5Zh\xdb]\x8b\xbexA\x9d\u0489\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xcd\xfd\x82\x173\x97%\xd7\xeb\xac\x11\xa66U\xf2e\xef\xf1\xcc=\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce\a\x9fQ\x88wt\xd8\x02\x1c\xb3\xb5u\xf5\x8f\x18\xe9\xac\xf9\x84\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xce\x18\x84\u077b\xb8\xe1\x0eM\xbanD\xfe\xee\u00a7\xe5\xf9/\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\x1b\f\xb4j\xae\xcf\u05db\x88\f\xad\x0f-\u068a\x8d\xed\u0431\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xce&\xf9\xa50_\x83\x81\tCT\xdb\xfc\x92fN\x84\xf9\x02\xb5\x89\fz\xaa\xb0Y\x1e\xec\x00\x00\u07d4\xce-\xea\xb5\x1c\n\x9a\xe0\x9c\xd2\x12\xc4\xfaL\xc5+S\xcc\r\xec\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xce.\r\xa8\x93F\x99\xbb\x1aU>U\xa0\xb8\\\x16\x945\xbe\xa3\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce:a\xf0F\x1b\x00\x93^\x85\xfa\x1e\xad\x82\xc4^Zd\u0508\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceK\x06]\xbc\xb20G 2b\xfbH\xc1\x18\x83d\x97tp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceS\xc8\xcd\xd7B\x96\xac\xa9\x87\xb2\xbc\x19\u00b8u\xa4\x87I\u0409\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xce^\x04\xf0\x18Ci\xbc\xfa\x06\xac\xa6o\xfa\x91\xbfY\xfa\x0f\xb9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xce^\xb6:{\xf4\xfb\xc2\xf6\u4ea0\u018a\xb1\xcbL\xf9\x8f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xceb\x12Z\xde\xc37\n\xc5!\x10\x95:Nv\v\xe9E\x1e;\x89\b=lz\xabc`\x00\x00\xe0\x94\xceq\bmL`%T\xb8-\xcb\xfc\xe8\x8d cMS\xccM\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4\u038akmP3\xb1I\x8b\x1f\xfe\xb4\x1aAU\x04\x05\xfa\x03\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0397\x86\xd3q/\xa2\x00\xe9\xf6\x857\xee\xaa\x1a\x06\xa6\xf4ZK\x89a\t=|,m8\x00\x00\u07d4\u039d!\u0192\xcd<\x01\xf2\x01\x1fP_\x87\x006\xfa\x8fl\u0489\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u03a2\x89f#\xf4\x91\x02\x87\xa2\xbd\u017e\x83\xae\xa3\xf2\xe6\xde\b\x8a\x01\xfbZ7Q\xe4\x90\xdc\x00\x00\u07d4\u03a3JM\xd9=\u066e\xfd9\x90\x02\xa9}\x99z\x1bK\x89\u0349QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\u03a4?pu\x81k`\xbb\xfc\u62d9:\xf0\x88\x12p\xf6\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\u03a8t3AS<\xb2\xf0\xb9\xc6\xef\xb8\xfd\xa8\rw\x16(%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u03b0\x89\xec\x8ax3~\x8e\xf8\x8d\xe1\x1bI\xe3\u0751\x0ft\x8f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u03b3=x\xe7Tz\x9d\xa2\xe8}Q\xae\xc5\xf3D\x1c\x87\x92:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u03b3\x898\x1dH\xa8\xaeO\xfcH:\u043b^ L\xfd\xb1\xec\x89('\xe6\xe4\xddb\xba\x80\x00\u07d4\xce\xc6\xfce\x85?\x9c\xce_\x8e\x84Fv6.\x15y\x01_\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xce\xd3\u01fe\x8d\xe7XQ@\x95*\xebP\x1d\xc1\xf8v\ucbf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\xd8\x1e\xc3S?\xf1\xbf\xeb\xf3\xe3\x84>\xe7@\xad\x11u\x8d>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xce\u0733\xa1\u0584?\xb6\xbe\xf6Ca}\xea\U000cf398\xdd_\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xce\xe6\x99\xc0pzx6%+)/\x04|\xe8\xad(\x9b/U\x89\x11\x9a\x1e!\xaaiV\x00\x00\u07d4\xce\xedG\xca[\x89\x9f\xd1b?!\xe9\xbdM\xb6Z\x10\u5c1d\x89\a8w@L\x1e\xee\x00\x00\u07d4\xce\xf7tQ\u07e2\xc6C\xe0\v\x15mlo\xf8N#s\xebf\x89\n1\x06+\xee\xedp\x00\x00\u07d4\xcf\x11i\x04\x1c\x17E\xe4[\x17$5\xa2\xfc\x99\xb4\x9a\xce+\x00\x89\x01\xbb\x88\xba\xab-|\x00\x00\xe0\x94\xcf\x15v\x12vN\x0f\u0596\xc8\xcb_\xba\x85\xdfL\r\xdc<\xb0\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u0794\xcf\x1b\xdby\x9b.\xa6<\xe14f\x8b\xdc\x19\x8bT\x84\x0f\x18\v\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xcf\"\x88\xefN\xbf\x88\xe8m\xb1=\x8a\x0e\v\xf5*\x05e\x82\u00c9\x89Po\xbf\x97@t\x00\x00\u07d4\xcf&Ni%\x13\t\x06\xc4\xd7\xc1\x85\x91\xaaA\xb2\xa6\u007foX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf&\xb4{\xd04\xbcP\x8elK\xcf\xd6\xc7\xd3\x004\x92Wa\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcf.*\xd65\xe9\x86\x1a\xe9\\\xb9\xba\xfc\xca\x03kR\x81\xf5\u038a\at2!~h6\x00\x00\x00\u07d4\xcf.s@B\xa3U\xd0_\xfb.9\x15\xb1h\x11\xf4Zi^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf4\x8f/\xe4{~A<\az{\xaf:u\xfb\xf8B\x86\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcf?\x91(\xb0r\x03\xa3\xe1\r}WU\xc0\u012b\xc6\xe2\xca\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xcf?\xbf\xa1\xfd2\u05e6\xe0\xe6\xf8\xefN\xabW\xbe4\x02\\L\x899\xa1\xc0\xf7YMH\x00\x00\u07d4\xcfAftn\x1d;\xc1\xf8\xd0qK\x01\xf1~\x8ab\xdf\x14d\x896w\x03n\xdf\n\xf6\x00\x00\u07d4\xcfO\x118\xf1\xbdk\xf5\xb6\u0505\xcc\xe4\xc1\x01\u007f\u02c5\xf0}\x89/\u043cw\xc3+\xff\x00\x00\u07d4\xcfZo\x9d\xf7Uy\xc6D\xf7\x94q\x12\x15\xb3\rw\xa0\xce@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf^\x0e\xac\u0473\x9d\x06U\xf2\xf7u5\xeff\b\xeb\x95\v\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcfhM\xfb\x83\x04r\x93U\xb5\x83\x15\xe8\x01\x9b\x1a\xa2\xad\x1b\xac\x89\x17r$\xaa\x84Lr\x00\x00\u07d4\xcfi@\x81\xc7m\x18\xc6L\xa7\x13\x82\xbe\\\xd6;<\xb4v\xf8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcfnR\xe6\xb7t\x80\xb1\x86~\xfe\xc6Dm\x9f\xc3\xcc5w\xe8\x89\f\t\x01\xf6\xbd\x98y\x00\x00\u07d4\u03c8: 2\x96g\xea\"j\x1e\x9a\x92*\x12\xf2\x1f\xaa\x03\x81V\x91\x8cO\u02dc\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xcf\xf7\xf8\x9aMB\x19\xa3\x82\x95%\x131V\x82\x10\xff\xc1\xc14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xcf\xf8\xd0k\x00\xe3\xf5\f\x19\x10\x99\xadV\xbaj\xe2eq\u0348\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcf\xfcI\xc1x~\ubcb5l\xab\xe9$\x04\xb66\x14}EX\x8a\x013\xe00\x8f@\xa3\u0680\x00\u07d4\xd0\bQ;'`J\x89\xba\x17c\xb6\xf8L\u6233F\x94[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x0f\x06r\x86\xc0\xfb\u0402\xf9\xf4\xa6\x10\x83\xecv\u07b3\xce\xe6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x15\xf6\xfc\xb8M\xf7\xbbA\x0e\x8c\x8f\x04\x89J\x88\x1d\xca\xc27\x898E$\xccp\xb7x\x00\x00\u07d4\xd0\x1a\xf9\x13O\xafRW\x17N\x8by\x18oB\xee5Nd-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0!\b\u04ae<\xab\x10\xcb\xcf\x16W\xaf\">\x02|\x82\x10\xf6\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xd0*\xfe\u03ce.\u00b6*\u022d Aa\xfd\x1f\xaew\x1d\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd01\x919\xfb\xab.\x8e*\xcc\xc1\xd9$\u0531\x1d\xf6ilZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd07\xd2\x15\xd1\x1d\x1d\xf3\xd5O\xbd2\x1c\u0495\xc5F^';\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xd0:-\xa4\x1e\x86\x8e\xd3\xfe\xf5t[\x96\xf5\xec\xa4b\xffo\u0689\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xd0?\xc1eWj\xae\xd5%\xe5P,\x8e\x14\x0f\x8b.\x86\x969\x8a\x01sV\u0633%\x01\xc8\x00\x00\u07d4\xd0C\xa0\x11\xecBp\xee~\u0239hsu\x15\xe5\x03\xf80(\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd0K\x86\x1b=\x9a\xccV:\x90\x16\x89\x94\x1a\xb1\xe1\x86\x11a\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd0ZD|\x91\x1d\xbb'[\xfb.Z7\xe5\xa7\x03\xa5o\x99\x97\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd0_\xfb+t\xf8g O\xe51e;\x02H\xe2\x1c\x13TN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0bX\x81q\u03d9\xbb\xebX\xf1&\xb8p\xf9\xa3r\x8da\xec\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\u07d4\xd0c\x8e\xa5q\x89\xa6\xa6\x99\x02J\u05ccq\xd99\xc1\xc2\xff\x8c\x89\x8e\xaeVg\x10\xfc \x00\x00\xe0\x94\xd0d\x8aX\x1b5\b\xe15\xa2\x93]\x12\xc9epE\xd8q\u028a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xd0q\x19)f\xebi\xc3R\x0f\xca:\xa4\xdd\x04)~\xa0KN\x89\x05\xf6\x8e\x811\xec\xf8\x00\x00\u07d4\xd0q\x85 \xea\xe0\xa4\xd6-p\xde\x1b\xe0\xcaC\x1c^\xea$\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd0w]\xba*\xf4\xc3\n:x6Y9\xcdq\xc2\xf9\u0795\u0489i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd0{\xe0\xf9\t\x97\xca\xf9\x03\u022c\x1dS\xcd\xe9\x04\xfb\x19\aA\x8968\x908\xb6\x99\xb4\x00\x00\u07d4\xd0~Q\x18d\xb1\u03d9i\xe3V\x06\x02\x82\x9e2\xfcNq\xf5\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u0400\x94\x98\xc5H\x04z\x1e**\xa6\xa2\x9c\xd6\x1a\x0e\xe2h\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0402'_tZ,\xac\x02v\xfb\xdb\x02\u0532\xa3\xab\x17\x11\xfe\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\u040f\xc0\x9a\x000\xfd\t(\xcd2\x11\x98X\x01\x82\xa7j\xae\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0413\xe8)\x81\x9f\xd2\xe2[\x978\x00\xbb=XA\xdd\x15-\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0414J\xa1\x85\xa13pa\xae \u071d\xd9l\x83\xb2\xbaF\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u0416V[|t\a\xd0e6X\x03U\xfd\xd6\xd29\x14J\xa1\x89\r\x8drkqw\xa8\x00\x00\u07d4\u041c\xb2\xe6\b-i:\x13\xe8\xd2\xf6\x8d\xd1\u0744a\xf5X@\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0426\xc6\xf9\xe9\u0133\x83\xd7\x16\xb3\x1d\xe7\x8dVAM\xe8\xfa\x91\x89\x10CV\x1a\x88)0\x00\x00\u07d4\u0427 \x9b\x80\xcf`\xdbb\xf5}\n]}R\x1ai`fU\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\u0428\xab\xd8\n\x19\x9bT\xb0\x8be\xf0\x1d \x9c'\xfe\xf0\x11[\x8a\x01a\xc6&\xdca\xa2\xef\x80\x00\xe0\x94\u042b\xccp\xc0B\x0e\x0e\x17/\x97\xd4;\x87\xd5\xe8\f3n\xa9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u042es]\x91^\x94hf\xe1\xfe\xa7~^\xa4f\xb5\xca\xdd\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0431\x1do+\u0394^\fjP \u00f5'S\xf8\x03\xf9\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xd0\xc1\x01\xfd\x1f\x01\xc6?k\x1d\x19\xbc\x92\r\x9f\x93#\x14\xb16\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd0\xc5Z\xbf\x97o\xdc=\xb2\xaf\u9f99\u0519HMWl\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\u0422\xadE\xf5\x9a\x9d\xcc\u0195\xd8_%\xcaF\xed1\xa5\xa3\x89-\x89W}}@ \x00\x00\u07d4\xd0\xd6,G\xea`\xfb\x90\xa3c\x92\t\xbb\xfd\xd4\xd93\x99\x1c\u0189\n\x84Jt$\xd9\xc8\x00\x00\u07d4\xd0\xdbEax o\\D0\xfe\x00Pc\x90<=zI\xa7\x89&I\x1eE\xa7S\xc0\x80\x00\u07d4\xd0\xe1\x94\xf3K\x1d\xb6\t(\x85\t\xcc\xd2\xe7;a1\xa2S\x8b\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xd0\xe3^\x04vF\xe7Y\xf4Qp\x93\xd6@\x86BQ\u007f\bM\x89\u054f\xa4h\x18\xec\u02c0\x00\u07d4\xd0\xeeM\x02\xcf$8,0\x90\xd3\xe9\x95`\xde6xs\\\u07c9\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xd0\xf0OR\x10\x9a\xeb\xec\x9a{\x1e\x932v\x1e\x9f\xe2\xb9{\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd0\xf9Yx\x11\xb0\xb9\x92\xbb}7W\xaa%\xb4\xc2V\x1d2\xe2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\x03\x02\xfa\xa1\x92\x9a2i\x04\xd3v\xbf\v\x8d\xc9:\xd0LL\x89a\t=|,m8\x00\x00\xe0\x94\xd1\x10\r\xd0\x0f\xe2\xdd\xf1\x81c\xad\x96M\vi\xf1\xf2\xe9e\x8a\x8a\x01C\x12\tU\xb2Pk\x00\x00\u07d4\xd1\x16\xf3\xdc\xd5\xdbtK\xd0\b\x88v\x87\xaa\x0e\xc9\xfdr\x92\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\x19A|Fs,\xf3M\x1a\x1a\xfby\xc3\xe7\xe2\u034e\xec\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1-w\xae\x01\xa9-5\x11{\xacpZ\xac\u0642\xd0.t\xc1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd15yK\x14\x9a\x18\xe1G\xd1nb\x1ai1\xf0\xa4\n\x96\x9a\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xd1C%8\xe3[vd\x95j\u4563*\xbd\xf0A\xa7\xa2\x1c\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xd1C\x82g#\x17\x04\xfcr\x80\xd5c\xad\xf4v8D\xa8\a\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd1S\x8e\x9a\x87\u5729\xec\x8eX&\xa5\xb7\x93\xf9\x9f\x96\xc4\u00c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd1d\x85\x03\xb1\xcc\u0178\xbe\x03\xfa\x1e\xc4\xf3\xee&~j\xdf{\x8a\x01;\xef\xbfQ\xee\xc0\x90\x00\x00\xe0\x94\xd1h,!Y\x01\x8d\xc3\xd0\u007f\b$\n\x8c`m\xafe\xf8\xe1\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xd1q\xc3\xf2%\x8a\xef5\xe5\x99\xc7\xda\x1a\xa0s\x00#M\xa9\xa6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1w\x8c\x13\xfb\xd9h\xbc\b<\xb7\xd1\x02O\xfe\x1fI\xd0,\xaa\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\xd1\u007f\xbe\"\xd9\x04b\xed7(\x06p\xa2\xea\v0\x86\xa0\xd6\u0589\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\u0441\x1cU\x97i\x80\xf0\x83\x90\x1d\x8a\r\xb2i\"-\xfb\\\xfe\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u044e\xb9\xe1\u0485\u06be\x93\xe5\u053a\xe7k\xee\xfeC\xb5!\xe8\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\u0453\xe5\x83\xd6\a\x05c\xe7\xb8b\xb9aJG\u9509\xf3\xe5\x8965f3\xeb\xd8\xea\x00\x00\u07d4\u0457\x8f.4@\u007f\xab\x1d\xc2\x18=\x95\xcf\xdab`\xb3Y\x82\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4\u045c\xaf9\xbb7\u007f\xdf,\xf1\x9b\xd4\xfbRY\x1c&1\xa6<\x8965\u026d\xc5\u07a0\x00\x00\u0794\u0463\x96\xdc\u06b2\xc7IA0\xb3\xfd0x 4\r\xfd\x8c\x1f\x88\xf9\"P\xe2\xdf\xd0\x00\x00\xe0\x94\u0467\x1b-\bX\xe82p\b]\x95\xa3\xb1T\x96P\x03^#\x8a\x03'\xbb\t\xd0j\xa8P\x00\x00\u07d4\u046c\xb5\xad\xc1\x189s%\x8dk\x85$\xff\xa2\x8f\xfe\xb2=\xe3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0473\u007f\x03\xcb\x10t$\xe9\xc4\xddW\\\xcdOL\xeeW\xe6\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\u0475\xa4T\xac4\x05\xbbAy \x8cl\x84\xde\x00k\u02db\xe9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xc4YT\xa6+\x91\x1a\xd7\x01\xff.\x90\x13\x1e\x8c\xeb\x89\xc9\\\x89K\x91\xa2\xdeE~\x88\x00\x00\u07d4\xd1\xc9np\xf0Z\xe0\xe6\xcd`!\xb2\b7P\xa7q|\xdeV\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\u0571\u007f\xfe-{\xbby\xcc}y0\xbc\xb2\xe5\x18\xfb\x1b\xbf\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd1\xda\f\x8f\xb7\xc2\x10\xe0\xf2\xeca\x8f\x85\xbd\xae}>sK\x1c\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd1\xddy\xfb\x15\x81`\xe5\xb4\xe8\xe2?1.j\x90\u007f\xbcMN\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xdeZ\xad:_\xd8\x03\U00071bb6\x10<\xb8\xe1O\xe7#\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd1\xe1\xf2\xb9\xc1l0\x98t\xde\xe7\xfa\xc3&u\xaf\xf1)\u00d8\x89\x03\xf2M\x8eJ\x00p\x00\x00\xe0\x94\xd1\xe5\xe24\xa9\xf4Bf\xa4\xa6$\x1a\x84\u05e1\xa5Z\u0567\xfe\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd1\xeaMr\xa6{[>\x0f1UY\xf5+\xd0aMq0i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1\xee\x90YW\xfe|\xc7\x0e\xc8\xf2\x86\x8bC\xfeG\xb1?\xeb\xff\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\xd1\xf1iM\"g\x1bZ\xadj\x94\x99\\6\x9f\xbea3go\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\xf4\xdc\x1d\u06ca\xbb\x88H\xa8\xb1N%\xf3\xb5Z\x85\x91\xc2f\x89\r\x8drkqw\xa8\x00\x00\u07d4\xd1\xfe\u042e\xe6\xf5\xdf\xd7\xe2Wi%L<\xfa\xd1Z\xde\u032a\x89'\x92\xc8\xfcKS(\x00\x00\u07d4\xd2\x05\x1c\xb3\xcbg\x04\xf0T\x8c\u0210\xab\n\x19\xdb4\x15\xb4*\x89\x12\x1b.^ddx\x00\x00\u07d4\xd2\x06\xaa\u07736\xd4^yr\xe9<\xb0uG\x1d\x15\x89{]\x89 \x86\xac5\x10R`\x00\x00\u07d4\xd2\tH+\xb5I\xab\xc4w{\xeam\u007fe\x00b\xc9\xc5z\x1c\x89\x11e\x1a\xc3\xe7\xa7X\x00\x00\u07d4\xd2\r\xcb\vxh+\x94\xbc0\x00(\x14H\xd5W\xa2\v\xfc\x83\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4\xd2\x10{57&\u00e2\xb4ef\xea\xa7\xd9\xf8\v]!\xdb\xe3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\x11\xb2\x1f\x1b\x12\xb5\ta\x81Y\r\xe0~\xf8\x1a\x89S~\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd2\x18\xef\xb4\u06d8\x1c\xddjy\u007fK\u050c|&)<\xeb@\x89\xa1Fk1\xc6C\x1c\x00\x00\xe0\x94\xd2\x1asA\xeb\x84\xfd\x15\x10T\xe5\u31fb%\xd3nI\x9c\t\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2$\xf8\x80\xf9G\x9a\x89\xd3/\t\xe5+\u9432\x88\x13\\\xef\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xd2/\f\xa4\xcdG\x9ef\x17u\x05;\xccI\xe3\x90\xf6p\u074a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd21\x92\x975\x13!\x02G\x1b\xa5\x90\a\xb6dL\xc0\xc1\xde>\x8967\tlK\xcci\x00\x00\u07d4\xd25\xd1\\\xb5\xec\xee\xbba)\x9e\x0e\x82\u007f\xa8'H\x91\x1d\x89\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2:$\xd7\xf9F\x83C\xc1C\xa4\x1ds\xb8\x8f|\xbec\xbe^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2=z\xff\xac\xdc>\x9f=\xaez\xfc\xb4\x00oX\xf8\xa4F\x00\x89\xc3(\t>a\xee@\x00\x00\u07d4\xd2C\x18L\x80\x1e]y\xd2\x06?5x\u06ee\x81\u7ce9\u02c9k\u0722h\x1e\x1a\xba\x00\x00\u07d4\xd2KfD\xf49\xc8\x05\x1d\xfcd\u04c1\xb8\xc8lu\xc1u8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2K\xf1--\xdfE}\xec\xb1xt\xef\xde R\xb6\\\xbbI\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2Q\xf9\x03\xae\x18rrY\xee\xe8A\xa1\x89\xa1\xf5i\xa5\xfdv\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd2R\x96\v\v\xf6\xb2\x84\x8f\u07ad\x80\x13m\xb5\xf5\a\xf8\xbe\x02\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2X\x1aU\xce#\xab\x10\u062d\x8cD7\x8fY\a\x9b\xd6\xf6X\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xd2Z\xec\xd7\xeb\x8b\xd64[\x06;]\xbd'\x1cw\xd3QD\x94\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xd2|#O\xf7\xac\xca\xce=\x99g\b\xf8\xf9\xb0Ip\xf9}6\x89Hz\x9a0E9D\x00\x00\u07d4\u0482\x98RM\xf5\xecK$\xb0\xff\xb9\u07c5\x17\n\x14Z\x9e\xb5\x89\x0f\x98\xa3\xb9\xb37\xe2\x00\x00\xe0\x94\u0483\xb8\xed\xb1\n%R\x8aD\x04\xde\x1ce\xe7A\r\xbc\xaag\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u0484\xa5\x03\x82\xf8:am9\xb8\xa9\xc0\xf3\x96\xe0\ubfe9]\x8966\xc2^f\xec\xe7\x00\x00\u07d4\u0488\xe7\xcb{\xa9\xf6 \xab\x0ftR\xe5\bc=\x1cZ\xa2v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u049d\xc0\x8e\xfb\xb3\xd7.&?x\xabv\x10\xd0\"m\xe7k\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u04a00\xac\x89R2_\x9e\x1d\xb3x\xa7\x14\x85\xa2N\x1b\a\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u04a4y@CG\xc5T:\xab)*\xe1\xbbJo\x15\x83W\xfa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u04a5\xa0$#\nW\xcc\xc6fv\v\x89\xb0\xe2l\xaf\u0449\u01ca\n\x96YZ\\n\x8a?\x80\x00\u07d4\u04a8\x03'\xcb\xe5\\L{\xd5\x1f\xf9\xdd\xe4\xcad\x8f\x9e\xb3\xf8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u04a8Oug\\b\xd8\f\x88ulB\x8e\xee+\xcb\x18T!\x89A\rXj \xa4\xc0\x00\x00\u07d4\u04ab\xd8J\x18\x10\x93\xe5\xe2)\x13oB\xd85\xe8#]\xe1\t\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\u04ac\r:X`^\x1d\x0f\x0e\xb3\xde%\xb2\xca\xd1)\xed`X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u04bfg\xa7\xf3\xc6\xceV\xb7\xbeAg]\xbb\xad\xfe~\xa9:3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd2\xdb\xeb\xe8\x9b\x03W\xae\xa9\x8b\xbe\x8eIc8\u07bb(\xe8\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2\xe2\x1e\xd5hh\xfa\xb2\x8e\tG\x92z\xda\xf2\x9f#\xeb\xadl\x89l\x18O\x13U\xd0\xe8\x00\x00\u07d4\xd2\xe8\x17s\x8a\xbf\x1f\xb4\x86X?\x80\xc3P1\x8b\xed\x86\f\x80\x89\r\x02\xce\xcf_]\x81\x00\x00\u07d4\xd2\xed\xd1\xdd\xd6\xd8m\xc0\x05\xba\xebT\x1d\"\xb6@\xd5\xc7\xca\xe5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\xf1\x99\x8e\x1c\xb1X\f\xecOl\x04}\xcd=\xce\xc5L\xf7<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2\xf2A%]\xd7\xc3\xf7<\a\x040q\xec\b\xdd\xd9\xc5\xcd\xe5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd2\xffg \x16\xf6;/\x859\x8fJo\xed\xbb`\xa5\r<\u0389\x12\x91$o[sJ\x00\x00\u07d4\xd3\rLC\xad\xcfU\xb2\xcbS\u0583#&A4I\x8d\x89\u038965\u026d\xc5\u07a0\x00\x00\u07d4\xd3\x0e\xe9\xa1+Mh\xab\xac\xe6\xba\u029a\u05ff\\\xd1\xfa\xf9\x1c\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xd3\x11\x8e\xa3\xc85\x05\xa9\u0613\xbbg\xe2\xde\x14-Sz>\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd3\x11\xbc\u05eaN\x9bO8?\xf3\xd0\u05b6\xe0~!\xe3p]\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd3\x15\xde\xea\x1d\x8c\x12q\xf9\xd11\x12c\xabG\xc0\a\xaf\xb6\xf5\x89\x03\xc8\x1dNeK@\x00\x00\u07d4\xd3+,y\xc3dx\xc5C\x19\x01\xf6\xd7\x00\xb0M\xbe\x9b\x88\x10\x89\x15w\x9a\x9d\xe6\xee\xb0\x00\x00\u07d4\xd3+EVF\x14Ql\x91\xb0\u007f\xa9\xf7-\xcfx|\xceN\x1c\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\xd30r\x811\xfe\x8e:\x15Hz4W<\x93E~*\xfe\x95\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd31\xc8#\x82Z\x9eRc\xd0R\u0611]M\xcd\xe0z\\7\x89\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d4\xd33btE\xf2\u05c7\x90\x1e\xf3;\xb2\xa8\xa3g^'\xff\xec\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3<\xf8+\xf1LY&@\xa0\x86\b\x91L#py\u057e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3Mp\x8ds\x98\x02E3\xa5\xa2\xb20\x9b\x19\xd3\xc5Qq\xbb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3N\x03\xd3j+\xd4\u045a_\xa1b\x18\xd1\xd6\x1e?\xfa\v\x15\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\xd3Pu\xcaa\xfeY\xd1#\x96\x9c6\xa8-\x1a\xb2\xd9\x18\xaa8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xd3g\x00\x9a\xb6X&;b\xc23:\x1c\x9eA@I\x8e\x13\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3g\x9aG\xdf-\x99\xa4\x9b\x01\u024d\x1c>\f\x98|\xe1\xe1X\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u04cf\xa2\xc4\xcc\x14z\xd0j\u0562\xf7Uy(\x1f\"\xa7\xcc\x1f\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\u04da]\xa4`9+\x94\v\u01ee8\xf1e\u007f\x8a\x01f\xc5H\b\x89\xdbw\x00\x00\xe0\x94\xd3\xd6\xe9\xfb\x82T/\u049e\xd9\xea6\t\x89\x1e\x15\x13\x96\xb6\xf7\x8a\voX\x8a\xa7\xbc\xf5\xc0\x00\x00\xe0\x94\xd3\xda\u0476\u040dE\x81\u032ee\xa8s-\xb6\xaci\xf0\u019e\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xd3\xdf;S\xcb;GU\xdeT\xe1\x80E\x1c\xc4L\x9e\x8a\u0a89#\u0114\t\xb9w\x82\x80\x00\u07d4\xd3\xf8s\xbd\x99V\x13W\x89\xab\x00\xeb\xc1\x95\xb9\"\xe9K%\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\x02\xb4\xf6\xa0\x99\xeb\xe7\x16\xcb\x14\xdfOy\xc0\xcd\x01\xc6\a\x1b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd4\r\x00U\xfd\x9a8H\x8a\xff\x92?\xd0=5\xecF\xd7\x11\xb3\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xd4\x0e\xd6j\xb3\xce\xff$\xca\x05\xec\xd4q\ufd12\xc1__\xfa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4\x18\x87\v\xc2\xe4\xfa{\x8aa!\xae\br\xd5RG\xb6%\x01\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xd4\x1d\u007f\xb4\x9f\xe7\x01\xba\xac%qpBl\u0273\x8c\xa3\xa9\xb2\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xd4 U\x92\x84@U\xb3\u01e1\xf8\f\xef\xe3\xb8\xebP\x9b\xcd\xe7\x89\t\xb3\xbf\xd3B\xa9\xfc\x80\x00\u07d4\xd4+ \xbd\x03\x11`\x8bf\xf8\xa6\xd1[*\x95\xe6\xde'\u017f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd44O}\\\xade\xd1~\\-\x0es#\x94=ob\xfe\x92\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xd4>\xe48\xd8=\xe9\xa3ub\xbbN(l\xb1\xbd\x19\xf4\x96M\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd4C4\xb4\xe2:\x16\x9a\f\x16\xbd!\xe8f\xbb\xa5-\x97\x05\x87\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94\xd4M\x81\xe1\x8fF\xe2\u03f5\xc1\xfc\xf5\x04\x1b\xc8V\x97g\xd1\x00\x8a\a\xb4B\xe6\x84\xf6Z\xa4\x00\x00\u07d4\xd4OJ\xc5\xfa\xd7k\xdc\x157\xa3\xb3\xafdr1\x9bA\r\x9d\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xd4O^\xdf+\xcf$3\xf2\x11\xda\xdd\f\xc4P\xdb\x1b\x00\x8e\x14\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xd4Oj\u00d2;_\xd71\xa4\xc4YD\xecO~\xc5*j\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd4[3A\xe8\xf1\\\x802\x93 \u00d7~;\x90\xe7\x82j~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4]]\xaa\x13\x8d\xd1\xd3t\xc7\x1b\x90\x19\x91h\x11\xf4\xb2\nN\x89\x1f9\x9b\x148\xa1\x00\x00\x00\u07d4\xd4`\xa4\xb9\b\xdd+\x05gY\xb4\x88\x85\vf\xa88\xfcw\xa8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd4g\xcf\x06L\bq\x98\x9b\x90\u0632\xeb\x14\xcc\xc6;6\b#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd4k\xaea\xb0'\xe5\xbbB.\x83\xa3\xf9\xc9?<\x8f\xc7}'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4o\x82#E)\x82\xa1\xee\xa0\x19\xa8\x81n\xfc-o\xc0\ah\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xd4uG\u007f\xa5c\x90\xd30\x17Q\x8dg\x11\x02\u007f\x05\U0008dfc9k\x11\x133\xd4\xfdL\x00\x00\u07d4\xd4|$.\xdf\xfe\xa0\x91\xbcT\xd5}\xf5\xd1\xfd\xb91\x01Gl\x89\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4\xd4}\x86\x85\xfa\xee\x14|R\x0f\u0646p\x91u\xbf/\x88k\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\u007fP\u07c9\xa1\xcf\xf9e\x13\xbe\xf1\xb2\xae:)q\xac\xcf,\x89-\x89W}}@ \x00\x00\u07d4\u0502\xe7\xf6\x8eA\xf28\xfeQx)\xde\x15G\u007f\xe0\xf6\xdd\x1d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u0507\x9f\xd1+\x1f:'\xf7\xe1\tv\x1b#\xca4\xfa#\x06K\x1c\xaf\x00Qn(pJ\x82\xa4\xf8\x89Hz\x9a0E9D\x00\x00\u07d4\xd5\x00\xe4\xd1\u0242K\xa9\xf5\xb65\u03e3\xa8\xc2\u00cb\xbdL\xed\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5\b\u04dcp\x91oj\xbcL\xc7\xf9\x99\xf0\x11\xf0w\x10X\x02\x89\x05rM$\xaf\xe7\u007f\x00\x00\u07d4\xd5\x0f\u007f\xa0>8\x98v\u04d0\x8b`\xa57\xa6pc\x04\xfbV\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd5\x13\xa4P\x80\xff/\xeb\xe6,\u0545J\xbe)\xeeDg\xf9\x96\x89\bN\x13\xbcO\xc5\xd8\x00\x00\u07d4\xd5'o\f\xd5\xff\xd5\xff\xb6?\x98\xb5p=U\x94\xed\xe0\x83\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5)KfbB0;m\xf0\xb1\u020d7B\x9b\xc8\xc9e\xaa\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xd5*\xec\xc6I98\xa2\x8c\xa1\xc3g\xb7\x01\xc2\x15\x98\xb6\xa0.\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xd5\x99x\xee \xa3\x8c?I\x8dc\xd5\u007f1\xa3\x9fj\x06\x8a\x022\xb3o\xfcg*\xb0\x00\x00\u07d4\u05568\xd3\xc5\xfa\xa7q\x1b\xf0\x85t_\x9d[\xdc#\u0518\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u055d\x92\xd2\xc8p\x19\x80\xcc\a<7]r\n\xf0dt<\f\x8a\x04\x05\xfd\xf7\u5bc5\xe0\x00\x00\u07d4\u0567\xbe\xc32\xad\xde\x18\xb3\x10KW\x92Tj\xa5\x9b\x87\x9bR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0571\x17\xec\x11n\xb8FA\x89a\xeb~\xdbb\x9c\xd0\xddi\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u0572\x84\x04\x010\xab\xf7\xc1\xd1cq#q\xcc~(\xadf\u0689j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0579\xd2w\u062a\xd2\x06\x97\xa5\x1fv\xe2\tx\x99k\xff\xe0U\x89\a\xc3\xfe<\aj\xb5\x00\x00\u07d4\u057d^\x84U\xc10\x16\x93W\xc4q\xe3\u6077\x99jrv\x89-\x9e(\x8f\x8a\xbb6\x00\x00\u07d4\xd5\u02e5\xb2k\xea]s\xfa\xbb\x1a\xba\xfa\xcd\xef\x85\xde\xf3h\u0309\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd5\xceU\u0476/YC\xc0?\x89\b\xe3\x1f\xe1h\x9d\x8a\x00\x00\u07d4\xd6\x06Q\xe3\x93x4#\xe5\xcc\x1b\xc5\xf8\x89\xe4N\xf7\xea$>\x89\x15\x9ev7\x11)\xc8\x00\x00\u07d4\xd6\t\xbfO\x14n\xeak\r\xc8\xe0m\xdc\xf4D\x8a\x1f\xcc\xc9\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\t\xec\v\xe7\r\n\xd2ong\xc9\xd4v+R\xeeQ\x12,\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6\nRX\a(R\r\xf7Tk\xc1\xe2\x83)\x17\x88\u06ee\f\x8964\x89\xef?\xf0\xd7\x00\x00\u07d4\xd6\v$s!\xa3*Z\xff\xb9k\x1e'\x99'\xccXM\xe9C\x89z\xd0 \xd6\xdd\xd7v\x00\x00\u07d4\xd6\x11\x02v\xcf\xe3\x1eB\x82ZW\u007fkC]\xbc\xc1\f\xf7d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd6\x12Y{\xc3\x17C\u01c63\xf63\xf29\xb1\xe9Bk\xd9%\x8a\x10\x17\xf7\u07d6\xbe\x17\x80\x00\x00\u07d4\xd6#J\xafE\xc6\xf2.f\xa2%\xff\xb9:\xddb\x9bN\xf8\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6.\u06d6\xfc\u259a\xaflT^\x96|\xf1\xc0\xbc\x80R\x05\x89\x04\xa5eSjZ\u0680\x00\u07d4\xd60\v2\x15\xb1\x1d\xe7b\xec\xdeKp\xb7\x92}\x01)\x15\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd69]\xb5\xa4\xbbf\xe6\x0fL\xfb\xcd\xf0\x05{\xb4\xd9xb\xe2\x891T\xc9r\x9d\x05x\x00\x00\xe0\x94\xd6J-P\xf8\x85\x857\x18\x8a$\xe0\xf5\r\xf1h\x1a\xb0~\u05ca\b7Z*\xbc\xca$@\x00\x00\u07d4\xd6X\n\xb5\xedL}\xfaPo\xa6\xfed\xad\\\xe1)pw2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6Y\x8b\x13\x86\xe9<\\\u02d6\x02\xffK\xbb\xec\xdb\xd3p\x1d\u0109\f%\xf4\xec\xb0A\xf0\x00\x00\u07d4\xd6dM@\xe9\v\xc9\u007f\xe7\xdf\xe7\u02bd2i\xfdW\x9b\xa4\xb3\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\xe0\x94\xd6g\f\x03m\xf7T\xbeC\xda\u074fP\xfe\xea(\x9d\x06\x1f\u058a\x01D\xa2\x904H\xce\xf7\x80\x00\u07d4\xd6hR:\x90\xf0)=e\xc58\xd2\xddlWg7\x10\x19n\x89\x02$,0\xb8S\xee\x00\x00\u07d4\xd6j\xb7\x92\x94\aL\x8bb}\x84-\xabA\xe1}\xd7\f]\xe5\x8965\u026d\xc5\u07a0\x00\x00\u0794\xd6j\xcc\r\x11\xb6\x89\u03a6\xd9\xea_\xf4\x01L\"J]\xc7\u0108\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xd6m\xdf\x11Y\xcf\"\xfd\x8czK\xc8\u0540wV\xd43\xc4>\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\u0587\xce\xc0\x05\x90\x87\xfd\xc7\x13\xd4\xd2\xd6^w\xda\xef\xed\xc1_\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u0588\xe7\x85\u024f\x00\xf8K:\xa1S3U\u01e2X\xe8yH\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u05a2.Y\x8d\xab\u04ce\xa6\xe9X\xbdy\u050d\u0756\x04\xf4\u07c965\u026d\xc5\u07a0\x00\x00\u07d4\u05a7\xacM\xe7\xb5\x10\xf0\xe8\xdeQ\x9d\x97?\xa4\xc0\x1b\xa84\x00\x89e\xea=\xb7UF`\x00\x00\u07d4\u05ac\xc2 \xba.Q\xdf\xcf!\xd4C6\x1e\xeav\\\xbd5\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05ac\xff\u043f\u065c8.{\xd5o\xf0\xe6\x14J\x9eR\xb0\x8e\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xd6\xc0\u043c\x93\xa6.%qtp\x0e\x10\xf0$\u0232?\x1f\x87\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd6\xcf\\\x1b\u03dd\xa6b\xbc\xea\"U\x90P\x99\xf9\xd6\xe8M\u030a\x01\u011eB\x01W\xd9\xc2\x00\x00\u07d4\xd6\xd05r\xa4RE\xdb\xd46\x8cO\x82\xc9W\x14\xbd!g\xe2\x89?\x00\xc3\xd6f\x86\xfc\x00\x00\u07d4\xd6\xd6wiX\xee#\x14:\x81\xad\xad\xeb\b8 \t\xe9\x96\u0089\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd6\xd9\xe3\x0f\bB\x01*qv\xa9\x17\xd9\xd2\x04\x8c\xa0s\x87Y\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6\xe0\x9e\x98\xfe\x13\x003!\x04\xc1\xca4\xfb\xfa\xc5T6N\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\xe8\xe9z\u90db\x9e\xe5\a\xee\xdb(\xed\xfbtw\x03\x149\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\uea18\u052e+q\x80'\xa1\x9c\xe9\xa5\xebs\x00\xab\xe3\u0289\x01}J\xce\xeec\u06c0\x00\xe0\x94\xd6\xf1\xe5[\x16\x94\b\x9e\xbc\xb4\xfe}x\x82\xaaf\u0217av\x8a\x04<#\xbd\xbe\x92\x9d\xb3\x00\x00\u07d4\xd6\xf4\xa7\xd0N\x8f\xaf \xe8\xc6\ub15c\xf7\xf7\x8d\xd2=z\x15\x89\a$\xde\xd1\xc7H\x14\x00\x00\u07d4\xd6\xfc\x04F\u01a8\xd4\n\xe3U\x1d\xb7\xe7\x01\xd1\xfa\x87nJI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x03\u01a4\xf1\x1d`\x19Ey\u054c'f\xa7\xef\x16\xc3\n)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x05%\x19uj\xf4%\x90\xf1S\x91\xb7#\xa0?\xa5d\xa9Q\x89\xfa61H\r\x01\xfd\x80\x00\u07d4\xd7\na+\xd6\u0769\xea\xb0\xdd\xdc\xffJ\xafA\"\u04cf\xea\xe4\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xd7\n\xd2\xc4\xe9\uefe67\xefV\xbdHj\u04a1\xe5\xbc\xe0\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x14\f\x8eZC\a\xfa\xb0\xcc'\xba\u0752\x95\x01\x8b\xf8yp\x89\x05\xf1\x01kPv\xd0\x00\x00\u07d4\xd7\x16J\xa2a\xc0\x9a\u0672\xb5\x06\x8dE>\xd8\xebj\xa10\x83\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\x1eC\xa4Qw\xadQ\xcb\xe0\xf7!\x84\xa5\xcbP9\x17(Z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x1f\xb10\xf0\x15\fVRi\xe0\x0e\xfbC\x90+R\xa4U\xa6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\"W8\xdc\xf3W\x848\xf8\xe7\u0233\x83~B\xe0J&/\x89\x18+\x8c\ubec3\xaa\x00\x00\u07d4\xd7'MP\x80M\x9cw\u0693\xfaH\x01V\xef\xe5{\xa5\x01\u0789i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd71\xbbk_<79^\t\u03ac\xcd\x14\xa9\x18\xa6\x06\a\x89\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xd7>\xd2\u0645\xb5\xf2\x1bU\xb2td;\xc6\xda\x03\x1d\x8e\u074d\x8a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xd7D\xac~S\x10\xbeijc\xb0\x03\xc4\v\xd097\x05a\u0189Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\xd7Jn\x8dj\xab4\u0385\x97h\x14\xc12{\xd6\xea\a\x84\u048a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xd7ZP*[gr\x87G\x0fe\u016aQ\xb8|\x10\x15\x05r\x8910\xb4dc\x85t\x00\x00\u07d4\xd7m\xba\xeb\xc3\rN\xf6{\x03\xe6\xe6\xec\xc6\xd8N\x00MP-\x89mv\xb9\x18\x8e\x13\x85\x00\x00\u07d4\xd7q\xd9\xe0\u028a\b\xa1\x13wW1CN\xb3'\x05\x99\xc4\r\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7x\x8e\xf2\x86X\xaa\x06\xccS\xe1\xf3\xf0\xdeX\xe5\xc3q\xbex\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xd7x\x92\xe2';#]v\x89\xe40\xe7\xae\ud73c\xe8\xa1\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u05c1\xf7\xfc\t\x18F\x11V\x85p\xb4\x98n,r\x87+~\u0409\x01\x15\x95a\x06]]\x00\x00\u07d4\u05c5\xa8\xf1\x8c8\xb9\xbcO\xfb\x9b\x8f\xa8\xc7r{\xd6B\xee\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u05ce\xcd%\xad\xc8k\xc2\x05\x1d\x96\xf6Sd\x86kB\xa4&\xb7\x89\xd20X\xbf/&\x12\x00\x00\xe0\x94\u05cf\x84\xe3\x89D\xa0\xe0%_\xae\xceH\xbaIP\u053d9\u048a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u05d4\x83\xf6\xa8DO%I\xd6\x11\xaf\xe0,C-\x15\xe1\x10Q\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05d85\xe4\x04\xfb\x86\xbf\x84_\xba\t\rk\xa2^\f\x88f\xa6\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\u05da\xff\x13\xba-\xa7]F$\f\xac\n$g\xc6V\x94\x98#\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\u05dd\xb5\xabCb\x1az=\xa7\x95\xe5\x89)\xf3\xdd%\xafg\u0649lj\xccg\u05f1\xd4\x00\x00\u07d4\u05e1C\x1e\xe4S\xd1\xe4\x9a\x05P\xd1%hy\xb4\xf5\xd1\x02\x01\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\u05ed\t\xc6\xd3&WhSU\xb5\xc6\uc39fW\xb4\ube42\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u05f7@\xdf\xf8\xc4Wf\x8f\xdft\xf6\xa2f\xbf\xc1\u0737#\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7\u0080>\u05f0\xe0\x83sQA\x1a\x8ef7\xd1h\xbc[\x05\x8a\x06A\xda\xf5\xc9\x1b\xd95\x80\x00\u07d4\xd7\xc6&]\xea\x11\x87l\x90;q\x8eL\u062b$\xfe&[\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xca\u007f\xdc\xfe\xbeE\x88\xef\xf5B\x1d\x15\"\xb6\x13(\xdf{\xf3\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4\xd7\u037dA\xff\xf2\r\xf7'\xc7\vbU\xc1\xbav\x06\x05Th\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xd1W\xe4\xc0\xa9d7\xa6\u0485t\x1d\xd2>\xc46\x1f\xa3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xd2\xc6\xfc\xa8\xad\x1fu9R\x10\xb5}\xe5\xdf\xd6s\x939\t\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94\xd7\xd3\xc7Y Y\x048\xb8,>\x95\x15\xbe.\xb6\xedz\x8b\x1a\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\xd7\xd7\xf2\u02a4b\xa4\x1b;0\xa3J\xeb;\xa6\x10\x10\xe2bo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xe7J\xfd\xba\xd5^\x96\u03bcZ7O,\x8bv\x86\x80\xf2\xb0\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\xe0\x94\xd7\xeb\x901b'\x1c\x1a\xfa5\xfei\xe3s\"\u0224\u049b\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd7\xeb\u0779\xf99\x87w\x9bh\x01U7T8\xdbe\xaf\xcbj\x89\x05t\x1a\xfe\xff\x94L\x00\x00\u07d4\xd7\xef4\x0ef\xb0\u05ef\xcc\xe2\n\x19\xcb{\xfc\x81\xda3\xd9N\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\xf3p\u053e\xd9\xd5|oI\u0259\xder\x9e\xe5i\xd3\xf4\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xfa_\xfb`H\xf9o\xb1\xab\xa0\x9e\xf8{\x1c\x11\xddp\x05\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\x06\x9f\x84\xb5!I?G\x15\x03\u007f2&\xb2_3\xb6\x05\x86\x89g\x8a\x93 b\xe4\x18\x00\x00\u0794\xd8\x15\xe1\xd9\xf4\xe2\xb5\xe5~4\x82k|\xfd\x88\x81\xb8Th\x90\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xd8\x1b\xd5K\xa2\xc4Jok\xeb\x15a\u058b\x80\xb5DNm\u0189?\x17\r~\xe4\"\xf8\x9c\x80-1({\x96q\xe8\x1c\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xd8K\x92/xA\xfcWt\xf0\x0e\x14`J\xe0\xdfB\xc8U\x1e\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xd8U\xb0<\xcb\x02\x9awG\xb1\xf0s\x03\xe0\xa6dy59\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8_\u07af*a\xf9]\xb9\x02\xf9\xb5\xa5<\x9b\x8f\x92f\u00ec\x89l\xf6Z~\x90G(\x00\x00\u07d4\xd8q^\xf9\x17o\x85\v.0\xeb\x8e8'\a\xf7w\xa6\xfb\xe9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8t\xb9\u07eeEj\x92\x9b\xa3\xb1\xa2~W,\x9b,\xec\u07f3\x89\t79SM(h\x00\x00\u07d4\u0613\n9\xc7sW\xc3\n\u04e0`\xf0\v\x06\x04c1\xfdb\x89,s\xc97t,P\x00\x00\u07d4\u061b\xc2q\xb2{\xa3\xabib\xc9JU\x90\x06\xae8\xd5\xf5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0637}\xb9\xb8\x1b\xbe\x90B{b\xf7\x02\xb2\x01\xff\u009f\xf6\x18\x892m\x1eC\x96\xd4\\\x00\x00\u07d4\xd8\xcdd\xe0(N\xecS\xaaF9\xaf\xc4u\b\x10\xb9\u007f\xabV\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xd6C\x84$\x9bwg\x94\x06;V\x98x\xd5\xe3\xb50\xa4\xb2\x89\t\xa0C\u0432\xf9V\x80\x00\u07d4\xd8\xd6T \xc1\x8c#'\xccZ\xf9t%\xf8W\xe4\xa9\xfdQ\xb3\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xd8\xe5\xc9g^\xf4\xde\xed&k\x86\x95o\xc4Y\x0e\xa7\u0522}\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd8\xe8GB\x92\xe7\xa0Q`L\xa1d\xc0pw\x83\xbb(\x85\xe8\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\u07d4\xd8\xebxP>\xc3\x1aT\xa9\x016x\x1a\xe1\t\x00Lt2W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\xee\xf4\xcfK\xeb\x01\xee \xd1\x11t\x8ba\xcbM?d\x1a\x01\x89\x94\x89#z\u06daP\x00\x00\u07d4\xd8\xf4\xba\xe6\xf8M\x91\rm}Z\xc9\x14\xb1\xe6\x83r\xf9A5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd8\xf6 6\xf0;v5\xb8X\xf1\x10?\x8a\x1d\x90\x19\xa8\x92\xb6\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xd8\xf6e\xfd\x8c\xd5\u00bc\xc6\xdd\xc0\xa8\xaeR\x1eM\u01aa``\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xd8\xf9$\fU\xcf\xf05RB\x80\xc0\x9e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xfe\b\x8f\xff\u0394\x8fQ7\xee#\xb0\x1d\x95\x9e\x84\xacB#\x89\f[T\xa9O\xc0\x17\x00\x00\u07d4\xd9\x0f0\t\xdbC~N\x11\u01c0\xbe\u0209os\x8de\xef\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\x10;\xb6\xb6zU\xa7\xfe\xce-\x1a\xf6-E|!x\x94m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\x13\xf0w\x19Iu\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd9D\u0226\x9f\xf2\xca\x12Ii\f\x12)\xc7\x19/6%\x10b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd9JW\x88*Rs\x9b\xbe*\x06G\xc8\f$\xf5\x8a+O\x1c\x89H\xb5N*\xdb\xe1+\x00\x00\xe0\x94\xd9SB\x95<\x8a!\xe8\xb65\xee\xfa\u01c1\x9b\xea0\xf1pG\x8a\x13\xf0l\u007f\xfe\xf0]@\x00\x00\u07d4\xd9\\\x90\xff\xbeT\x84\x86G\x80\xb8gIJ\x83\u0212V\xd6\xe4\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xd9g\x11T\x0e.\x99\x83C\xd4\xf5\x90\xb6\xfc\x8f\xac;\xb8\xb3\x1d\x89_Z@h\xb7\x1c\xb0\x00\x00\u07d4\xd9j\xc2Pt\t\u01e3\x83\xab.\xee\x18\"\xa5\xd78\xb3kV\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd9m\xb3;{Z\x95\f>\xfa-\xc3\x1b\x10\xba\x10\xa52\uf1c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd9wYe\xb7\x16Gfu\xa8\xd5\x13\xeb\x14\xbb\xf7\xb0|\xd1J\x8a\x01\x13.m-#\xc5\xe4\x00\x00\u07d4\xd9{\xc8J\xbdG\xc0[\xbfE{.\xf6Y\xd6\x1c\xa5\xe5\u43c9\x06\x9d\x17\x11\x9d\u0168\x00\x00\u07d4\xd9\u007fE&\u07a9\xb1c\xf8\xe8\xe3:k\u03d2\xfb\x90}\xe6\xec\x89\x0feJ\xafM\xb2\xf0\x00\x00\u07d4\xd9\u007f\xe6\xf5?*X\xf6\xd7mu*\xdft\xa8\xa2\xc1\x8e\x90t\x89\x10\xcd\xf9\xb6\x9aCW\x00\x00\u07d4\u0659\x99\xa2I\r\x94\x94\xa50\xca\xe4\xda\xf3\x85T\xf4\xddc>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\u065d\xf7B\x1b\x93\x82\xe4,\x89\xb0\x06\xc7\xf0\x87p*\aW\xc0\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\xe0\x94\u0677\x83\xd3\x1d2\xad\xc5\x0f\xa3\xea\u02a1]\x92\xb5h\xea\xebG\x8a\a3\xaf\x907L\x1b(\x00\x00\u07d4\xd9\xd3p\xfe\xc65v\xab\x15\xb3\x18\xbf\x9eX6M\u00a3U*\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xd9\xd4/\xd1>\xbdK\xf6\x9c\xac^\x9c~\x82H:\xb4m\xd7\xe9\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xd9\xe2~\xb0}\xfcq\xa7\x06\x06\f\u007f\a\x928\u0293\xe8\x859\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\xe3\x85~\xfd\x1e *D\x17p\xa7w\xa4\x9d\xccE\xe2\xe0\u04c9\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xd9\xec.\xfe\x99\xff\\\xf0\r\x03\xa81{\x92\xa2J\xefD\x1f~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd9\xec\x8f\xe6\x9bw\x16\xc0\x86Z\xf8\x88\xa1\x1b+\x12\xf7 \xed3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\xf1\xb2d\b\xf0\xecg\xad\x1d\ro\xe2.\x85\x15\xe1t\x06$\x89\x01M\x11 \u05f1`\x00\x00\u07d4\xd9\xf5G\xf2\xc1\xde\x0e\u064aS\xd1a\xdfWc]\xd2\x1a\x00\xbd\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xd9\xff\x11]\x01&l\x9fs\xb0c\xc1\xc28\xef5e\xe6;6\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xda\x06\x04N)#&\xffil\x0091h\xceF\xff\xac9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda*\x14\xf9r@\x15\u05d0\x14\xed\x8eY\th\x1dYaH\xf1\x89\x02\xa1\x0f\x0f\x8a\x91\xab\x80\x00\u07d4\xda*\u054ew\xde\xdd\xed\xe2\x18vF\xc4e\x94Z\x8d\xc3\xf6A\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\xda0\x17\xc1P\xdd\r\xce\u007f\u03c8\x1b\nH\xd0\xd1\xc7V\xc4\u01c9\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\xda4\xb2\xea\xe3\v\xaf\xe8\xda\xec\xcd\xe8\x19\xa7\x94\u0349\xe0\x95I\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdaJ_U\u007f;\xab9\n\x92\xf4\x9b\x9b\x90\n\xf3\fF\xae\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdaPU7S\u007f\xfb3\xc4\x15\xfe\xc6Ni\xba\xe0\x90\xc5\xf6\x0f\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdai\x8dd\xc6\\\u007f+,rS\x05\x9c\xd3\u0441\u0619\xb6\xb7\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\u07d4\xdaw2\xf0/.'.\xaf(\u07d7.\xcc\r\xde\xed\x9c\xf4\x98\x89\v \xbf\xbfig\x89\x00\x00\u07d4\xdaz\xd0%\xeb\xde%\xd2\"C\u02c3\x0e\xa1\xd3\xf6JVc#\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\u0685]SG\u007fP^\xc4\xc8\xd5\u8ed1\x80\u04c6\x81\x11\x9c\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\u0687^N/<\xab\xe4\xf3~\x0e\xae\xd7\xd1\xf6\xdc\xc6\xff\xefC\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u068b\xbe\xe1\x82\xe4U\xd2\t\x8a\xcb3\x8amE\xb4\xb1~\u0636\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0698.\x96C\xff\xec\xe7#\aZ@\xfewnZ\xce\x04\xb2\x9b\x89\b\xb8\xb6\u0259\x9b\xf2\x00\x00\u07d4\u069fUF\tF\u05ff\xb5p\xdd\xecu|\xa5w;XB\x9a\x89\x1b\x84]v\x9e\xb4H\x00\x00\u07d4\u06a1\xbdz\x91H\xfb\x86\\\xd6\x12\xdd5\xf1b\x86\x1d\x0f;\u0709\xa68\xabr\xd9,\x13\x80\x00\xe0\x94\u06a6<\xbd\xa4]\u0507\xa3\xf1\xcdJtj\x01\xbb^\x06\v\x90\x8a\x01\x04\x16\u0670*\x89$\x00\x00\u07d4\u06a7v\xa6uDi\u05f9&z\x89\xb8g%\xe7@\xda\x0f\xa0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u06ac\x91\xc1\xe8Y\xd5\xe5~\xd3\bKP \x0f\x97f\xe2\xc5+\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u06ac\xda\xf4\"&\xd1\\\xb1\u03d8\xfa\x15\x04\x8c\u007fL\xee\xfei\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\u06b6\xbc\u06c3\xcf$\xa0\xae\x1c\xb2\x1b;[\x83\xc2\xf3\x82I'\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\u06bb\b\x89\xfc\x04)&\xb0^\xf5{% \x91\n\xbcKAI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06bc\"PB\xa6Y,\xfa\x13\xeb\xe5N\xfaA\x04\bx\xa5\xa2\x89\x0e\x11\xfa\xd5\xd8\\\xa3\x00\x00\u07d4\xda\xc0\xc1w\xf1\x1c\\>>x\xf2\xef\xd6c\xd12!H\x85t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xd16\xb8\x81x\xb4\x83zlx\x0f\xeb\xa2&\xb9\x85i\xa9L\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xda\xdb\xfa\xfd\x8bb\xb9*$\xef\xd7RV\u0743\xab\xdb\u05fb\u06c9\x01\x11du\x9f\xfb2\x00\x00\u07d4\xda\xdc\x00\xaby'`\xaa4\x15i\xfa\x9f\xf5\x98&\x84\x85JJ2\x8an\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xe7 \x1e\xab\x8c\x063\x02\x93\ri9)\xd0\u007f\x95\xe7\x19b\x89\x91\xae\xc0(\xb4\x19\x81\x00\x00\u07d4\xda\xed\u052d\x10{'\x1e\x89Hl\xbf\x80\xeb\xd6!\u0757Ex\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x04\xfa\xd9\u011f\x9e\x88\v\xeb\x8f\xcf\x1d:8\x90\u4cc4o\x89CZ\xe6\xcc\fX\xe5\x00\x00\u07d4\xdb\f\u01cft\u0642{\u070ads'n\xb8O\u0717b\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x12\x93\xa5\x06\xe9\f\xad*Y\xe1\xb8V\x1f^f\x96\x1ag\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x19\xa3\x98\"06\x8f\x01w!\x9c\xb1\f\xb2Y\u0372%|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb#\xa6\xfe\xf1\xaf{X\x1ew,\xf9\x18\x82\u07b2Qo\xc0\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb$O\x97\xd9\xc4K\x15\x8a@\xed\x96\x06\xd9\xf7\xbd8\x9131\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xdb(\x8f\x80\xff\xe22\u00baG\u0314\xc7c\xcfo\u0278+\r\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xdb*\f\x9a\xb6M\xf5\x8d\u07f1\u06ec\xf8\xba\r\x89\xc8[1\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdb4t^\u0785v\xb4\x99\xdb\x01\xbe\xb7\xc1\xec\u0685\xcfJ\xbe\x89\x04V9\x18$O@\x00\x00\u07d4\xdb?%\x8a\xb2\xa3\xc2\xcf3\x9cD\x99\xf7ZK\xd1\xd3G.\x9e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xdbK\xc8;\x0ek\xaa\xdb\x11V\xc5\xcf\x06\xe0\xf7!\x80\x8cR\u01c9/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xdbc\x12-\xe7\x03}\xa4\x97\x151\xfa\u9bc5\x86x\x86\u0192\x89\x0f\x04%\xb0d\x1f4\x00\x00\u07d4\xdbl*s\xda\xc7BJ\xb0\xd01\xb6ga\x12%f\xc0\x10C\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xdbnV\f\x9b\xc6 \u053e\xa3\xa9MG\xf7\x88\v\xf4\u007f-_\x89\x04\xda\x0f\xdf\xcf\x05v\x00\x00\u07d4\xdbo\xf7\x1b=\xb0\x92\x8f\x83\x9e\x05\xa72;\xfbW\u049c\x87\xaa\x891T\xc9r\x9d\x05x\x00\x00\u07d4\xdbsF\vY\xd8\xe8PE\xd5\xe7R\xe6%Y\x87^BP.\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xdbw\xb8\x8d\xcbq/\xd1~\xe9\x1a[\x94t\x8dr\f\x90\xa9\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb}@7\b\x1fle\xf9Gk\x06\x87\xd9\u007f\x1e\x04M\n\x1d\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\u06c8.\xac\xed\xd0\xef\xf2cQ\x1b1*\u06fcY\u01b8\xb2[\x8a\x01\xedO\xdez\"6\xb0\x00\x00\u07d4\u06d3q\xb3\fL\x84NY\xe0>\x92K\xe6\x06\xa98\xd1\xd3\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06e4ym\f\xebM:\x83k\x84\xc9o\x91\n\xfc\x10?[\xa0\x89\t\b\xf4\x93\xf77A\x00\x00\u07d4\u06ed\xc6\x1e\xd5\xf0F\n\u007f\x18\xe5\x1b/\xb2aM\x92d\xa0\xe0\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u06f6\xacH@'\x04\x16B\xbb\xfd\x8d\x80\xf9\xd0\xc1\xcf3\xc1\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06fc\xbby\xbfG\x9aB\xadq\xdb\u02b7{Z\u07ea\x87,X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xdb\xc1\xce\x0eI\xb1\xa7\x05\xd2. 7\xae\xc8x\xee\ru\xc7\x03\x89\r\x8drkqw\xa8\x00\x00\u07d4\xdb\xc1\xd0\xee+\xabS\x11@\xde\x13w\"\xcd6\xbd\xb4\xe4q\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\u015e\u0609s\u07ad1\b\x84\":\xf4\x97c\xc0P0\xf1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xdb\xc6ie\xe4&\xff\x1a\xc8z\xd6\xebx\xc1\xd9Rq\x15\x8f\x9f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xdb\xcb\xcdzW\ua7724\x9b\x87\x8a\xf3K\x1a\xd6B\xa7\xf1\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\xd5\x1c\xdf,;\xfa\xcd\xff\x10b!\xde.\x19\xadmB\x04\x14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdb\xd7\x1e\xfaK\x93\u0209\xe7e\x93\xde`\x9c;\x04\u02ef\xbe\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xdb\xf5\xf0a\xa0\xf4\x8e^ia\x879\xa7}.\xc1\x97h\xd2\x01\x89\b=lz\xabc`\x00\x00\u07d4\xdb\xf8\xb19g\xf5Q%'-\xe0V%6\xc4P\xbaVU\xa0\x89n\xf5x\xf0n\f\xcb\x00\x00\u07d4\xdb\xfb\x1b\xb4d\xb8\xa5\x8eP\r.\xd8\u0797,E\xf5\xf1\xc0\xfb\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xdc\x06~\xd3\xe1-q\x1e\xd4u\xf5\x15n\xf7\xe7\x1a\x80\xd94\xb9\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xdc\b\u007f\x93\x90\xfb\x9e\x97j\xc2:\xb6\x89TJ\tB\xec !\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xdc\x1e\xb9\xb6\xe6CQ\xf5d$P\x96E\xf8>y\xee\xe7l\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\x1f\x19ya_\b!@\xb8\xbbx\xc6{'\xa1\x94'\x13\xb1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xdc#\xb2`\xfc\xc2n}\x10\xf4\xbd\x04J\xf7\x94W\x94`\xd9\u0689\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xdc)\x11\x97E\xd23s \xdaQ\xe1\x91\x00\xc9H\u0640\xb9\x15\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdc-\x15\xa6\x9fk\xb3;$j\xef@E\aQ\xc2\xf6uj\u0489l4\x10\x80\xbd\x1f\xb0\x00\x00\u07d4\xdc=\xaeY\xed\x0f\xe1\x8bXQ\x1eo\xe2\xfbi\xb2\x19h\x94#\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xdc?\x0evr\xf7\x1f\xe7R[\xa3\v\x97U\x18: \xb9\x16j\x8a\x02\b\x9c\xf5{[>\x96\x80\x00\xe0\x94\xdcCE\u0581.\x87\n\xe9\fV\x8cg\xd2\xc5g\u03f4\xf0<\x8a\x01k5-\xa5\xe0\xed0\x00\x00\u07d4\xdcD'[\x17\x15\xba\xea\x1b\x03EsZ)\xacB\xc9\xf5\x1bO\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xdcF\xc13%\u034e\xdf\x020\xd0h\x89d\x86\xf0\a\xbfN\xf1\x89Hz\x9a0E9D\x00\x00\u07d4\xdcQ\xb2\u071d$z\x1d\x0e[\xc3l\xa3\x15oz\xf2\x1f\xf9\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdcS\x05\xb4\x02\n\x06\xb4\x9de||\xa3L5\xc9\x1c_,V\x8a\x01}\xf6\xc1\r\xbe\xba\x97\x00\x00\u07d4\xdcW4[8\xe0\xf0g\u0263\x1d\x9d\xea\xc5'Z\x10\x94\x93!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdcWG}\xaf\xa4/p\\\u007f\xe4\x0e\xae\x9c\x81un\x02%\xf1\x89\x1b\x1b\x81(\xa7An\x00\x00\u07d4\xdc_Z\xd6c\xa6\xf2c2}d\xca\xc9\xcb\x13=,\x96\x05\x97\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdcp:_7\x94\xc8Ml\xb3TI\x18\xca\xe1J5\u00fdO\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\xdcs\x8f\xb2\x17\u03ad/iYL\b\x17\r\xe1\xaf\x10\xc4\x19\xe3\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xdcv\xe8[\xa5\v\x9b1\xec\x1e& \xbc\xe6\xe7\xc8\x05\x8c\x0e\xaf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0703\xb6\xfd\rQ!1 G\a\xea\xf7.\xa0\xc8\u027e\xf9v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u070c)\x12\xf0\x84\xa6\u0444\xaasc\x85\x13\u033c2n\x01\x02\x89F3\xbc6\xcb\xc2\xdc\x00\x00\u07d4\u0711\x1c\xf7\xdc]\u04016Vg\x05(\xe93\x8eg\x03G\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0730;\xfal\x111#NV\xb7\xea|Or\x14\x87Tkz\x89Hz\x9a0E9D\x00\x00\xe0\x94\u0736M\xf47X\xc7\u03d7O\xa6`HO\xbbq\x8f\x8cg\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdc\xc5-\x8f\x8d\x9f\xc7B\xa8\xb8'g\xf0US\x87\xc5c\xef\xff\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xdc\xcb7\x0e\u058a\xa9\"(0C\xef|\xad\x1b\x9d@?\xc3J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\u0324 E\xec>\x16P\x8b`?\xd96\xe7\xfd}\xe5\xf3j\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xdc\xd1\fU\xbb\x85OuD4\xf1!\x9c,\x9a\x98\xac\xe7\x9f\x03\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xdc\u057c\xa2\x00S\x95\xb6u\xfd\xe5\x03VY\xb2k\xfe\xfcI\xee\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xdc\u06fdN&\x04\xe4\x0e\x17\x10\xccg0(\x9d\xcc\xfa\u04c9-\x89\xf9]\xd2\xec'\xcc\xe0\x00\x00\u07d4\xdc\xe3\f1\xf3\xcafr\x1e\xcb!<\x80\x9a\xabV\x1d\x9bR\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdc\xf39eS\x13\x80\x161h\xfc\x11\xf6~\x89\xc6\xf1\xbc\x17\x8a\x89\x12'v\x854\x06\xb0\x80\x00\u07d4\xdc\xf6\xb6W&n\x91\xa4\xda\xe6\x03=\xda\xc1S2\u074d+4\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdc\xf9q\x9b\xe8|oFum\xb4\x89\x1d\xb9\xb6\x11\xd2F\x9cP\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdc\xff\xf3\xe8\xd2<*4\xb5k\u0473\xbdE\u01d3tC\"9\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xdd\x04\xee\xe7N\v\xf3\f?\x8dl,\u007fR\xe0Q\x92\x10\u07d3\x89\x04V9\x18$O@\x00\x00\xe0\x94\xdd&\xb4)\xfdC\xd8N\xc1y\x82S$\xba\u057f\xb9\x16\xb3`\x8a\x01\x16\xbf\x95\xbc\x842\x98\x00\x00\u07d4\xdd*#:\xde\xdef\xfe\x11&\xd6\xc1h#\xb6*\x02\x1f\xed\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd+\u07e9\x17\xc1\xf3\x10\xe6\xfa5\xaa\x8a\xf1i9\xc23\xcd}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xdd5\xcf\xdb\u02d93\x95Sz\xec\xc9\xf5\x90\x85\xa8\xd5\u0776\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xddG\x18\x9a>d9qg\xf0b\x0eHEe\xb7b\xbf\xbb\xf4\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xddM\xd6\xd3`3\xb0co\u030d\t8`\x9fM\xd6OJ\x86\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xddO_\xa2\x11\x1d\xb6\x8fk\xde5\x89\xb60)9[i\xa9-\x89\b\x96=\xd8\xc2\xc5\xe0\x00\x00\xe0\x94\xddc\x04/%\xed2\x88J\xd2n:\xd9Y\xeb\x94\xea6\xbfg\x8a\x04\x84\xd7\xfd\xe7\u0553\xf0\x00\x00\u07d4\xdde\xf6\xe1qc\xb5\xd2\x03d\x1fQ\xcc{$\xb0\x0f\x02\xc8\xfb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xddl\x06!\x93\xea\xc2=/\xdb\xf9\x97\xd5\x06:4k\xb3\xb4p\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdd{\u0366Y$\xaa\xa4\x9b\x80\x98J\xe1su\x02X\xb9(G\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdd\u007f\xf4A\xbao\xfe6q\xf3\xc0\u06bb\xff\x18#\xa5\x043p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0742T\x12\x1an\x94/\xc9\b(\xf2C\x1fQ\x1d\xad\u007f2\u6263\x9b)\xe1\xf3`\xe8\x00\x00\xe0\x94\u074a\xf9\xe7vR#\xf4DoD\xd3\xd5\t\x81\x9a==\xb4\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\u0755\xdb\xe3\x0f\x1f\x18w\xc5\xddv\x84\xae\xef0*\xb6\x88Q\x92\x8a\x01\xc5\xd8\xd6\xeb>2P\x00\x00\xe0\x94\u0756|L_\x8a\xe4~&o\xb4\x16\xaa\u0456N\xe3\xe7\xe8\u00ca\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u075bHZ;\x1c\xd3:j\x9cb\xf1\xe5\xbe\xe9'\x01\x85m%\x89\f3\x83\xed\x03\x1b~\x80\x00\xe0\x94\u0763q\xe6\x00\xd3\x06\x88\xd4q\x0e\b\x8e\x02\xfd\xf2\xb9RM_\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\u0764\xed*X\xa8\xdd \xa72u4{X\rq\xb9[\xf9\x9a\x89\x15\xa1<\xc2\x01\xe4\xdc\x00\x00\xe0\x94\u0764\xff}\xe4\x91\u0187\xdfEt\xdd\x1b\x17\xff\x8f$k\xa3\u044a\x04&\x84\xa4\x1a\xbf\xd8@\x00\x00\u07d4\u076bkQ\xa9\x03\v@\xfb\x95\xcf\vt\x8a\x05\x9c$\x17\xbe\u01c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u076bu\xfb/\xf9\xfe\u02c8\xf8\x94vh\x8e+\x00\xe3g\xeb\xf9\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\xe0\x94\u076b\xf1<<\x8e\xa4\xe3\xd7=x\xecqz\xfa\xfaC\x0eTy\x8a\b\xcf#\xf9\t\xc0\xfa\x00\x00\x00\u07d4\u076c1*\x96UBj\x9c\f\x9e\xfa?\xd8%Y\xefE\x05\xbf\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\u076ck\xf4\xbb\xdd}Y}\x9chm\x06\x95Y;\xed\xcc\xc7\xfa\x89.\xe4IU\b\x98\xe4\x00\x00\xe0\x94\u077d+\x93,v;\xa5\xb1\xb7\xae;6.\xac>\x8d@\x12\x1a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u077d\xdd\x1b\xbd8\xff\xad\xe00]0\xf0 (\xd9.\x9f:\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u077e\xe6\xf0\x94\xea\xe64 \xb0\x03\xfbGW\x14*\xeal\xd0\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd\u059c[\x9b\xf5\xebZ9\xce\xe7\xc34\x1a\x12\r\x97?\xdb4\x89k\xc1K\x8f\x8e\x1b5\x00\x00\xe0\x94\xdd\xdd{\x9en\xab@\x9b\x92&:\xc2r\u0680\x1bfO\x8aW\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4\xdd\xe6p\xd0\x169fuv\xa2-\xd0]2F\xd6\x1f\x06\xe0\x83\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94\xdd\xe7zG@\xba\b\xe7\xf7?\xbe:\x16t\x91)1t.\xeb\x8a\x044\xfeMC\x82\xf1\u0500\x00\u07d4\xdd\xe8\xf0\xc3\x1bt\x15Q\x1d\xce\xd1\xcd}F2>K\xd1\"2\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xdd\xe9i\xae\xf3N\xa8z\u0099\xb7Y~)+J\x01U\u030a\x89\x102\xf2YJ\x01s\x80\x00\u07d4\xdd\xf0\xcc\xe1\xfe\x99m\x91v5\xf0\a\x12\xf4\x05 \x91\xdf\xf9\xea\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdd\xf3\xadv58\x10\xbej\x89\xd71\xb7\x87\xf6\xf1q\x88a+\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xdd\xf5\x81\n\x0e\xb2\xfb.22;\xb2\u0255\t\xab2\x0f$\xac\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x94\xdd\xf9\\\x1e\x99\xce/\x9fV\x98\x05|\x19\xd5\xc9@'\xeeJn\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xdd\xfa\xfd\xbc|\x90\xf12\x0eT\xb9\x8f7F\x17\xfb\xd0\x1d\x10\x9f\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xdd\xfc\xca\x13\xf94\xf0\u03fe#\x1d\xa109\xd7\x04u\xe6\xa1\u040968\"\x16`\xa5\xaa\x80\x00\u07d4\xde\x02~\xfb\xb3\x85\x03\"n\xd8q\t\x9c\xb3\v\xdb\x02\xaf\x135\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xde\x06\xd5\xeawzN\xb1G^`]\xbc\xbfCDN\x807\xea\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xde\a\xfb[zFN;\xa7\xfb\xe0\x9e\x9a\xcb'\x1a\xf53\x8cX\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xde\x11!\x82\x9c\x9a\b(@\x87\xa4?\xbd/\xc1\x14*23\xb4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xde\x17kR\x84\xbc\xee:\x83\x8b\xa2Og\xfc|\xbfg\u05ce\xf6\x89\x02\t\xce\b\xc9b\xb0\x00\x00\u07d4\xde!\"\x93\xf8\xf1\xd21\xfa\x10\xe6\tG\rQ,\xb8\xff\xc5\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde0\xe4\x9eZ\xb3\x13!M/\x01\u072b\u0389@\xb8\x1b\x1cv\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xde3\xd7\b\xa3\xb8\x9e\x90\x9e\xafe;0\xfd\u00e5\xd5\u0334\xb3\x89\t\x9c\x88\"\x9f\xd4\xc2\x00\x00\u07d4\xde7B\x99\xc1\xd0}ySs\x85\x19\x0fD.\xf9\xca$\x06\x1f\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xdeB\xfc\xd2L\xe4#\x93\x830CgY_\x06\x8f\fa\a@\x89\x02r*p\xf1\xa9\xa0\x00\x00\u07d4\xdeP\x86\x8e\xb7\xe3\xc7\x197\xecs\xfa\x89\u074b\x9e\xe1\rE\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdeU\xde\x04X\xf8P\xb3~Mx\xa6A\xdd.\xb2\u074f8\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde[\x00_\xe8\u06ae\x8d\x1f\x05\xde>\xda\x04 f\xc6\xc4i\x1c\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xdea-\a$\xe8N\xa4\xa7\xfe\xaa=!B\xbd^\xe8-2\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdem61\x06\xccb8\xd2\xf0\x92\xf0\xf07!6\xd1\xcdP\u018a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xde}\xee\"\x0f\x04W\xa7\x18}V\xc1\xc4\x1f.\xb0\n\xc5`!\x89\"%\xf3\x9c\x85\x05*\x00\x00\u07d4\u0782\u030dJ\x1b\xb1\xd9CC\x92\x96[>\x80\xba\xd3\xc0=O\x89P\x18nu\u0797\xa6\x00\x00\u07d4\u0797\xf43\a\x00\xb4\x8cImC|\x91\xca\x1d\xe9\u0130\x1b\xa4\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\u07d4\u079e\xffLy\x88\x11\xd9h\xdc\xcbF\r\x9b\x06\x9c\xf3\x02x\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u07b1\xbc4\xd8mJM\xde%\x80\u063e\xaf\aN\xb0\xe1\xa2D\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\u07b2I]j\xca{*j-\x13\x8bn\x1aB\xe2\xdc1\x1f\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\u07b9rTGL\r/Zyp\xdc\xdb/R\xfb\x10\x98\xb8\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07b9\xa4\x9aC\x870 \xf0u\x91\x85\xe2\v\xbbL\U000c1ecf\x89\vx\xed\xb0\xbf.^\x00\x00\u07d4\u07bb\u0743\x1e\x0f \xaen7\x82R\xde\xcd\xf9/|\xf0\xc6X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xc3\xee\xc2d\nu,Fn+~~\u616f\xe9\xacA\xf4\x89G\u0257SYk(\x80\x00\u07d4\xde\xc8#s\xad\xe8\xeb\xcf*\xcbo\x8b\xc2AM\u05eb\xb7\rw\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xde\u0221\xa8\x98\xf1\xb8\x95\xd80\x1f\xe6J\xb3\xad]\xe9A\xf6\x89\x89*\xb4\xf6~\x8as\x0f\x80\x00\u07d4\xde\u025e\x97/\xcaqwP\x8c\x8e\x1aG\xac\"\xd7h\xac\xab|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xd8w7\x84\a\xb9Nx\x1cN\xf4\xaf|\xfc[\xc2 \xb5\x16\x89\x141y\xd8i\x11\x02\x00\x00\u07d4\xde\xe9B\xd5\xca\xf5\xfa\xc1\x14!\xd8k\x01\vE\x8e\\9)\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde\xee&\x89\xfa\x90\x06\xb5\x9c\xf2\x85#}\xe5;:\u007f\xd0\x148\x89\x18ey\xf2\x9e %\x00\x00\u07d4\xde\xfd\xdf\u055b\x8d,\x15N\xec\xf5\xc7\xc1g\xbf\v\xa2\x90]>\x89\x05\x12\xcb^&GB\x00\x00\u07d4\xde\xfe\x91A\xf4pE\x99\x15\x9d{\"=\xe4+\xff\xd8\x04\x96\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xdf\t\x8f^N=\xff\xa5\x1a\xf27\xbd\xa8e,Os\ud726\x89\x1b6\xa6DJ>\x18\x00\x00\xe0\x94\xdf\r\ba{\xd2R\xa9\x11\u07cb\xd4\x1a9\xb8=\u07c0\x96s\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdf\x0f\xf1\xf3\xd2z\x8e\xc9\xfb\x8fk\f\xb2T\xa6;\xba\x82$\xa5\x89\xec\xc5 )E\xd0\x02\x00\x00\u07d4\xdf\x1f\xa2\xe2\x0e1\x98^\xbe,\x0f\f\x93\xb5L\x0f\xb6z&K\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdf!\x1c\xd2\x12\x88\xd6\xc5o\xaef\xc3\xffTb]\u0531T'\x89\x87\x86\xcdvN\x1f,\x00\x00\u07d4\xdf#k\xf6\xab\xf4\xf3)7\x95\xbf\f(q\x8f\x93\u3c73k\x89Hz\x9a0E9D\x00\x00\u07d4\xdf1\x02_VI\xd2\xc6\xee\xa4\x1e\u04fd\xd3G\x1ay\x0fu\x9a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdf7\xc2.`:\xed\xb6\nbrS\xc4}\x8b\xa8f\xf6\xd9r\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xdf;r\u017dq\u0501N\x88\xa6#!\xa9=@\x11\xe3W\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf?W\xb8\xeed4\xd0G\"=\xeft\xb2\x0fc\xf9\xe4\xf9U\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d4\xdfD\xc4\u007f\xc3\x03\xacv\xe7O\x97\x19L\xcag\xb5\xbb<\x02?\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xdfG\xa6\x1brSQ\x93\xc5a\xcc\xccu\xc3\xf3\xce\b\x04\xa2\x0e\x89\x15\x93\\\vN=x\x00\x00\u07d4\xdfG\xa8\xef\x95\xf2\xf4\x9f\x8eoX\x18AT\x14]\x11\xf7'\x97\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xdfS\x003F\xd6\\^zdk\xc04\xf2\xb7\xd3/\xcb\xe5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfW5:\xaf\xf2\xaa\xdb\n\x04\xf9\x01N\x8d\xa7\x88N\x86X\x9c\x89\bH\x86\xa6nO\xb0\x00\x00\u07d4\xdf`\xf1\x8c\x81*\x11\xedN'v\xe7\xa8\x0e\xcf^S\x05\xb3\u05890\xca\x02O\x98{\x90\x00\x00\u07d4\xdfd\x85\xc4)z\xc1R\xb2\x89\xb1\x9d\xde2\xc7~\xc4\x17\xf4}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdff\n\x91\u06b9\xf70\xf6\x19\rP\xc89\x05aP\aV\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfn\xd6\x00jj\xbe\x88n\xd3=\x95\xa4\xde(\xfc\x12\x189'\x891T\xc9r\x9d\x05x\x00\x00\u07d4\u07c5\x10y>\xee\x81\x1c-\xab\x1c\x93\xc6\xf4G?0\xfb\xef[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07cdH\xb1\xeb\a\xb3\xc2\x17y\x0el-\xf0M\xc3\x19\xe7\xe8H\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u07e6\xb8\xb8\xad1\x84\xe3W\xda()Q\u05d1a\u03f0\x89\xbc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u07ef1\xe6\"\xc0=\x9e\x18\xa0\u0778\xbe`\xfb\xe3\xe6a\xbe\n\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\u07f1bn\xf4\x8a\x1d}uR\xa5\xe0)\x8f\x1f\xc2:;H-\x89\\\xe8\x95\u0754\x9e\xfa\x00\x00\xe0\x94\u07f4\u052d\xe5/\u0301\x8a\xccz,k\xb2\xb0\x02$e\x8fx\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u07fdB2\xc1|@z\x98\r\xb8\u007f\xfb\u036060\xe5\xc4Y\x89\x1d\xfc\u007f\x92I#S\x00\x00\u07d4\xdf\xcb\xdf\tEN\x1a^J@\xd3\xee\xf7\xc5\xcf\x1c\xd3\u0794\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf\xdb\xce\xc1\x01K\x96\xda!X\xcaQ>\x9c\x8d;\x9a\xf1\xc3\u0409lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdf\xde\xd2WK'\xd1a:}\x98\xb7\x15\x15\x9b\r\x00\xba\xab(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdf\xdfC9P\x8b\x0fnZ\xb1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe0\x06\x04b\xc4\u007f\xf9g\x9b\xae\xf0qY\xca\xe0\x8c)\xf2t\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\r\x15;\x106\x91C\xf9\u007fT\xb8\xd4\xca\"\x9e\xb3\xe8\xf3$\x89\b=lz\xabc`\x00\x00\u07d4\xe0\x12\xdbE8'\xa5\x8e\x16\xc16V\b\xd3n\xd6Xr\x05\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x15G\xbaB\xfc\xaf\xaf\x93\x93\x8b\xec\xf7i\x9ft)\n\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x16\xdc\x13\x8e%\x81[\x90\xbe?\xe9\xee\xe8\xff\xb2\xe1\x05bO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\x18Y\xf2B\xf1\xa0\xec`/\xa8\xa3\xb0\xb5v@\xec\x89\a^\x89\x1e\x16,\x17{\xe5\xcc\x00\x00\xe0\x94\xe0 \xe8cb\xb4\x87u(6\xa6\xde\v\xc0,\xd8\u061a\x8bj\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xe0#\xf0\x9b(\x87a,|\x9c\xf1\x98\x8e::`+3\x94\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0'\"\x13\xe8\xd2\xfd>\x96\xbdb\x17\xb2KK\xa0\x1bapy\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0+t\xa4v(\xbe1[\x1fv\xb3\x15\x05J\xd4J\xe9qo\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe02 \u0197\xbc\u048f&\xef\vt@J\x8b\xeb\x06\xb2\xba{\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe05/\u07c1\x9b\xa2e\xf1L\x06\xa61\\J\xc1\xfe\x13\x1b.\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe08\x8a\xed\xdd?\xe2\xadV\xf8WH\xe8\x0eq\n4\xb7\xc9.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0<\x00\xd0\x03\x88\xec\xbfO&=\n\xc7x\xbbA\xa5z@\u064966\xc9yd6t\x00\x00\u07d4\xe0I \xdcn\xcc\x1dn\xcc\bO\x88\xaa\n\xf5\u06d7\xbf\x89:\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xe0Ir\xa8<\xa4\x11+\xc8q\xc7-J\xe1al/\a(\u06c9\x0e\x81\xc7\u007f)\xa3/\x00\x00\u07d4\xe0O\xf5\xe5\xa7\u2bd9]\x88W\xce\x02\x90\xb5:+\x0e\xda]\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xe0P)\xac\xeb\axg[\xef\x17A\xab,\u0493\x1e\xf7\xc8K\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0V\xbf?\xf4\x1c&%o\xefQqf\x12\xb9\u04da\u0799\x9c\x89\x05k\xe7W\xa1.\n\x80\x00\u07d4\xe0a\xa4\xf2\xfcw\xb2\x96\u045a\xda#\x8eI\xa5\u02ce\xcb\xfap\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0f>\x8c\xd6g\x92\xa6A\xf5nP\x03f\x01G\x88\x0f\x01\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0f\x8f\xa8,\x14\xd6\xe8\xd9:S\x11>\xf2\x86/\xa8\x15\x81\xbc\x89//9\xfclT\x00\x00\x00\u07d4\xe0i\xc0\x173R\xb1\v\xf6\x83G\x19\xdb[\xed\x01\xad\xf9{\xbc\x89\x01\x064\xf8\xe52;\x00\x00\u07d4\xe0l)\xa8\x15\x17\xe0\u0507\xb6\u007f\xb0\xb6\xaa\xbcOW6\x83\x88\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xe0l\xb6)G\x04\xee\xa7C|/\xc3\xd3\as\xb7\xbf8\x88\x9a\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\xe0q7\xae\r\x11m\x0353\xc4\uad16\xf8\xa9\xfb\tV\x9c\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe0v\xdb0\xabHoy\x19N\xbb\xc4]\x8f\xab\x9a\x92B\xf6T\x8a\x01\x06`~4\x94\xba\xa0\x00\x00\u07d4\xe0~\xbb\xc7\xf4\xdaAnB\xc8\xd4\xf8B\xab\xa1b3\xc1%\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x81\xca\x1fH\x82\xdb`C\u0569\x19\a\x03\xfd\xe0\xab;\xf5m\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x83\xd3Hc\xe0\xe1\u007f\x92ky(\xed\xff1~\x99\x8e\x9cK\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x8b\x9a\xbak\xd9\u048b\xc2\x05gy\xd2\xfb\xf0\xf2\x85Z=\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x8b\u009c+H\xb1i\xff+\xdc\x16qLXnl\xb8\\\u03c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0\x8c`11\x06\xe3\xf93O\xe6\xf7\xe7bM!\x110\xc0w\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xe0\x9ch\xe6\x19\x98\xd9\xc8\x1b\x14\xe4\xee\x80+\xa7\xad\xf6\xd7L\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0\x9f\xeauZ\xee\x1aD\xc0\xa8\x9f\x03\xb5\u07b7b\xba3\x00o\x89;\xa2\x89\xbc\x94O\xf7\x00\x00\xe0\x94\xe0\xa2T\xac\t\xb9r[\xeb\xc8\xe4`C\x1d\xd0s.\xbc\xab\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe0\xaai6UU\xb7?(#3\xd1\xe3\f\x1b\xbd\a(T\xe8\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xe0\xba\u064e\ue598\xdb\xf6\xd7`\x85\xb7\x92=\xe5uN\x90m\x89\t\r\x97/22<\x00\x00\u07d4\xe0\u012b\x90r\xb4\xe6\xe3eJI\xf8\xa8\xdb\x02jK3\x86\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\u0380\xa4a\xb6H\xa5\x01\xfd\v\x82F\x90\u0206\x8b\x0eM\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\xcfi\x8a\x053'\xeb\xd1k}w\x00\t/\xe2\xe8T$F\x89\x05*4\u02f6\x1fW\x80\x00\xe0\x94\xe0\xd21\xe1D\xec\x91\a8l|\x9b\x02\xf1p,\xea\xa4\xf7\x00\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0\xd7kqf\xb1\xf3\xa1+@\x91\xee+)\u078c\xaa}\a\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\xe0\xb2\xe2\x9d\xdes\xafu\x98~\xe4Dl\x82\x9a\x18\x9c\x95\xbc\x89\b\x13\xcaV\x90m4\x00\x00\xe0\x94\xe0\xe9xu=\x98/\u007f\x9d\x1d#\x8a\x18\xbdH\x89\xae\xfeE\x1b\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\xe0\xf3r4|\x96\xb5_}C\x06\x03K\xeb\x83&o\xd9\tf\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\xf9\x03\xc1\xe4\x8a\xc4!\xabHR\x8f=J&H\b\x0f\xe0C\x897\b\xba\xed=h\x90\x00\x00\u07d4\xe0\xff\v\xd9\x15D9\u0125\xb7#>)\x1d}\x86\x8a\xf5?3\x89\x15y!jQ\xbb\xfb\x00\x00\xe0\x94\xe1\n\xc1\x9cTo\xc2T|a\xc19\xf5\xd1\xf4Zff\u0570\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\xe0\x94\xe1\fT\x00\x88\x11?\xa6\xec\x00\xb4\xb2\u0202O\x87\x96\xe9n\u010a2\x0fE\t\xab\x1e\xc7\xc0\x00\x00\xe0\x94\xe1\x17:$})\xd8#\x8d\xf0\x92/M\xf2Z\x05\xf2\xafw\u00ca\bx\xc9]V\x0f0G\x80\x00\xe0\x94\xe1 >\xb3\xa7#\xe9\x9c\" \x11|\xa6\xaf\xebf\xfaBOa\x8a\x02\x00\uf49e2V\xfe\x00\x00\xe0\x94\xe11\xf8~\xfc^\xf0~C\xf0\xf2\xf4\xa7G\xb5Q\xd7P\xd9\xe6\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\u07d4\xe13N\x99\x83y\xdf\xe9\x83\x17pby\x1b\x90\xf8\x0e\xe2-\x8d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe15@\xec\xee\x11\xb2\x12\xe8\xb7u\u070eq\xf3t\xaa\xe9\xb3\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1;=+\xbf\u073c\x87r\xa23\x15rL\x14%\x16|V\x88\x897\xf3y\x14\x1e\xd0K\x80\x00\u07d4\xe1D=\xbd\x95\xccA#\u007fa:HEi\x88\xa0Oh2\x82\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xe1F\x17\xf6\x02%\x01\xe9~{>-\x886\xaaa\xf0\xff-\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe1I\xb5rl\xafm^\xb5\xbf*\xccA\xd4\xe2\xdc2\x8d\u1089i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xe1T\xda\xea\xdbTX8\xcb\u01aa\fUu\x19\x02\xf5(h*\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4\xe1l\xe3Ya\xcdt\xbdY\r\x04\u012dJ\x19\x89\xe0V\x91\u0189\a\xea(2uw\b\x00\x00\u07d4\xe1r\xdf\xc8\xf8\f\xd1\xf8\u03459\xdc&\b \x14\xf5\xa8\xe3\u8262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xe1w\xe0\xc2\x01\xd35\xba9V\x92\x9cW\x15\x88\xb5\x1cR#\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1x\x12\xf6l^e\x94\x1e\x18lF\x92+n{/\x0e\xebF\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe1\x80\u079e\x86\xf5{\xaf\xac\u05d0O\x98&\xb6\xb4\xb2c7\xa3\x89-\x04\x1dpZ,`\x00\x00\xe0\x94\xe1\x92H\x9b\x85\xa9\x82\xc1\x882F\xd9\x15\xb2)\xcb\x13 \u007f8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xe1\x95\xbb\xc6,{tD\x04\x0e\xb9\x96#\x96Ovg\xb3v\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\x06\xfbs$\xe9\u07b7\x9e\x19\x904\x96\u0596\x1b\x9b\xe5f\x03\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe2\aW\x8e\x1fM\u06cf\xf6\u0546{9X-q\xb9\x81*\u0149\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xe2\b\x81*h@\x98\xf3\xdaN\xfej\xba%bV\xad\xfe?\xe6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2\tT\xd0\xf4\x10\x8c\x82\xd4\u0732\x14\x8d&\xbb\xd9$\xf6\xdd$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe2\v\xb9\xf3\x96d\x19\xe1K\xbb\xaa\xaag\x89\xe9$\x96\u03e4y\x89\xbb\xd8%\x03\aRv\x00\x00\u07d4\xe2\r\x1b\xcbq(m\xc7\x12\x8a\x9f\xc7\xc6\xed\u007fs8\x92\xee\xf5\x896d\xf8\xe7\xc2J\xf4\x00\x00\u0794\xe2\x19\x12\x15\x98?3\xfd3\xe2,\u0522I\x00T\xdaS\xfd\u0708\xdbD\xe0I\xbb,\x00\x00\u07d4\xe2\x19\x8c\x8c\xa1\xb3\x99\xf7R\x15a\xfdS\x84\xa7\x13/\xbaHk\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xe2\x1cw\x8e\xf2\xa0\xd7\xf7Q\xea\x8c\aM\x1f\x81\"C\x86>N\x8a\x01\x1f\xc7\x0e,\x8c\x8a\xe1\x80\x00\xe0\x94\xe2)\xe7F\xa8?,\xe2S\xb0\xb0>\xb1G$\x11\xb5~W\x00\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xe2+ \xc7x\x94F;\xafwL\xc2V\u057d\u06ff}\xdd\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe20\xfe\x1b\xff\x03\x18m\x02\x19\xf1]LH\x1b}Y\xbe(j\x89\x01\xfdt\x1e\x80\x88\x97\x00\x00\u07d4\xe27\xba\xa4\xdb\u0252n2\xa3\xd8]\x12d@-T\xdb\x01/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2A\t\xbe/Q=\x87I\x8e\x92j(d\x99uO\x9e\u051e\x890\x0e\xa8\xad\x1f'\xca\x00\x00\u07d4\xe2Fh<\u025d\xb7\u0125+\u02ec\xaa\xb0\xb3/k\xfc\x93\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2Z\x16{\x03\x1e\x84am\x0f\x01?1\xbd\xa9]\xcccP\xb9\x8a\x02\x8c*\xaa\u0243\xd0]\u0187st\xa8\xf4F\xee\xe9\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xe2\x8b\x06\"Y\xe9n\xeb<\x8dA\x04\x94?\x9e\xb3%\x89<\xf5\x89Hz\x9a0E9D\x00\x00\xe0\x94\u237c\x8e\xfd^Ajv.\xc0\xe0\x18\x86K\xb9\xaa\x83({\x8a\x051\xf2\x00\xab>\x03\n\x80\x00\u07d4\xe2\x90K\x1a\xef\xa0V9\x8bb4\xcb5\x81\x12\x88\xd76\xdbg\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u274a\xe4R\xdc\xf3\xb6\xacd^c\x04\t8UQ\xfa\xae\n\x89\x04Z\r\xa4\xad\xf5B\x00\x00\u07d4\xe2\xbb\xf8FA\xe3T\x1fl3\xe6\xedh:cZp\xbd\xe2\xec\x89\x1bA<\xfc\xbfY\xb7\x80\x00\u07d4\xe2\xcf6\n\xa22\x9e\xb7\x9d+\xf7\xca\x04\xa2z\x17\xc52\xe4\u0609\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xe2\xdf#\xf6\xea\x04\xbe\xcfJ\xb7\x01t\x8d\xc0\x961\x84U\\\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2\xe1\\`\xdd8\x1e:K\xe2Pq\xab$\x9aL\\Rd\u0689\u007fk\u011b\x81\xb57\x00\x00\u07d4\xe2\xe2nN\x1d\xcf0\xd0H\xccn\u03ddQ\xec\x12\x05\xa4\xe9&\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe2\xeei\x1f#~\xe6R\x9beW\xf2\xfc\xdd=\xcf\fY\xecc\x8a\x01'r\x9c\x14h| \x00\x00\u07d4\xe2\xef\xa5\xfc\xa7\x958\xce`h\xbf1\xd2\xc5\x16\xd4\xd5<\b\xe5\x89\a\x1c\xc4\b\xdfc@\x00\x00\xe0\x94\xe2\xef\u0429\xbc@~\xce\x03\xd6~\x8e\xc8\xe9\u0483\xf4\x8d*I\x8a\x02\x99\xb3;\xf9\u0144\xe0\x00\x00\u07d4\xe2\xf4\r5\x8f^?\xe7F>\xc7\x04\x80\xbd.\u04d8\xa7\x06;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\xf98=X\x10\xea{C\x18+\x87\x04\xb6+'\xf5\x92]9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe2\xff\x9e\xe4\xb6\xec\xc1AA\xcct\xcaR\xa9\xe7\xa2\xee\x14\xd9\b\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe3\x02\x12\xb2\x01\x1b\xb5k\xdb\xf1\xbc5i\x0f:N\x0f\xd9\x05\xea\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xe3\x03\x16\u007f=I`\xfe\x88\x1b2\x80\n+J\xef\xf1\xb0\x88\u0509lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3\x04\xa3/\x05\xa87btJ\x95B\x97o\xf9\xb7#\xfa1\xea\x89Ur\xf2@\xa3F \x00\x00\u07d4\xe3\bCR\x04y7d\xf5\xfc\xbee\xebQ\x0fZtJeZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3\t\x97L\xe3\x9d`\xaa\xdf.ig2Q\xbf\x0e\x04v\n\x10\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xe3\x1bN\xef\x18L$\xab\t\x8e6\xc8\x02qK\xd4t=\xd0\u0509\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3!\xbbJ\x94j\xda\xfd\xad\xe4W\x1f\xb1\\\x00C\u04de\xe3_\x89Udu8+L\x9e\x00\x00\u07d4\xe3&<\xe8\xafm\xb3\xe4gXE\x02\xedq\t\x12^\xae\"\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3+\x1cG%\xa1\x87TI\u93d7\x0e\xb3\xe5@b\xd1X\x00\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3/\x95vmW\xb5\xcdK\x172\x89\u0587o\x9edU\x81\x94\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe38@\u063c\xa7\u0698\xa6\xf3\u0416\xd8=\xe7\x8bp\xb7\x1e\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe38\xe8Y\xfe.\x8c\x15UHH\xb7\\\xae\u0368w\xa0\xe82\x89a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4\xe3=\x98\x02 \xfa\xb2Y\xafj\x1fK8\xcf\x0e\xf3\xc6\xe2\xea\x1a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe3=\xf4\u0380\u0336*v\xb1+\xcd\xfc\xec\xc4b\x89\x97:\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe3?\xf9\x87T\x1d\xde\\\xde\u0a29m\xcc?3\xc3\xf2L\u008a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xe3A\v\xb7U|\xf9\x1dy\xfai\xd0\xdf\xea\n\xa0u@&Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3Ad-@\u04af\xce.\x91\a\xc6py\xacz&`\bl\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe3TS\xee\xf2\xcc2\x89\x10CR\x8d\t\x84i\x80\x00\xe0\x94\xe5\x10\xd6y\u007f\xba=f\x93\x83Z\x84N\xa2\xadT\x06\x91\x97\x1b\x8a\x03\xae9\xd4s\x83\xe8t\x00\x00\u07d4\xe5\x14!\xf8\xee\"\x10\xc7\x1e\xd8p\xfea\x82v\u0215J\xfb\xe9\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\x1e\xb8~\u007f\xb71\x1fR(\xc4y\xb4\x8e\u0247\x881\xacL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5!V1\xb1BH\xd4Z%R\x96\xbe\xd1\xfb\xfa\x030\xff5\x89G\x03\xe6\xebR\x91\xb8\x00\x00\xe0\x94\xe5(\xa0\xe5\xa2g\xd6g\xe99:e\x84\xe1\x9b4\u071b\xe9s\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xe54%\xd8\xdf\x1f\x11\xc3A\xffX\xae_\x148\xab\xf1\xcaS\u03c9\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\u07d4\xe5No\x9c\xffV\xe1\x9cF\x1e\xb4T\xf9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5A\x02SM\xe8\xf2>\xff\xb0\x93\xb3\x12B\xad;#?\xac\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe5E\xee\x84\xeaH\xe5d\x16\x1e\x94\x82\u055b\xcf@j`,\xa2\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xe5H\x1a\u007f\xedB\xb9\x01\xbb\xed x\x9b\u052d\xe5\r_\x83\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5Y\xb5\xfd3{\x9cUr\xa9\xbf\x9e\x0f%!\xf7\xd4F\xdb\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\\\x80R\n\x1b\x0fu[\x9a,\xd3\xce!Ov%e>\x8a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe5mC\x13$\xc9)\x11\xa1t\x9d\xf2\x92p\x9c\x14\xb7ze\u034a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\xe5})\x95\xb0\xeb\xdf?<\xa6\xc0\x15\xeb\x04&\r\xbb\x98\xb7\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\u51f1j\xbc\x8at\b\x1e6\x13\xe1CB\xc03u\xbf\bG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\x89\xfav\x98M\xb5\xec@\x04\xb4n\u8954\x92\xc3\aD\u0389\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xe5\x8d\xd228\xeen\xa7\xc2\x13\x8d8]\xf5\x00\xc3%\xf3v\xbe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe5\x95?\xeaIq\x04\xef\x9a\xd2\xd4\xe5\x84\x1c'\x1f\a5\x19\u0089&)\xf6n\fS\x00\x00\x00\xe0\x94\u5587\x97F\x8e\xf7g\x10\x1bv\x1dC\x1f\xce\x14\xab\xff\u06f4\x8a\x01\xb3\xd9i\xfaA\x1c\xa0\x00\x00\u07d4\xe5\x97\xf0\x83\xa4i\xc4Y\x1c=+\x1d,w'\x87\xbe\xfe'\xb2\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe5\x9b;\xd3\x00\x89?\x97#>\xf9G\xc4or\x17\xe3\x92\xf7\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xa3e4<\xc4\xeb\x1ew\x03h\xe1\xf1\x14Jw\xb82\xd7\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe5\xa3\xd7\xeb\x13\xb1\\\x10\x01w#m\x1b\xeb0\xd1~\xe1T \x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xaa\v\x83;\xb9\x16\xdc\x19\xa8\xddh?\x0e\xde$\x1d\x98\x8e\xba\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u5def\x14i\x86\xc0\xff\x8f\x85\xd2.l\xc34\a}\x84\xe8$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xb8&\x19l\x0e\x1b\xc1\x11\x9b\x02\x1c\xf6\xd2Y\xa6\x10\u0256p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\xb9o\u026c\x03\xd4H\xc1a:\xc9\x1d\x15\x97\x81E\xdb\xdf\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u5e40\u048e\xec\xe2\xc0o\xcal\x94s\x06\x8b7\u0526\xd6\xe9\x89%\xaf\u058c\xac+\x90\x00\x00\u07d4\u5eb4\xf0\xaf\u0629\u0463\x81\xb4Wa\xaa\x18\xf3\xd3\xcc\xe1\x05\x89Q\xbf\xd7\xc18x\xd1\x00\x00\u07d4\xe5\xbc\u020c;%on\xd5\xfeU\x0eJ\x18\x19\x8b\x943V\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xbd\xf3OL\xccH>L\xa50\xcc|\xf2\xbb\x18\xfe\xbe\x92\xb3\x89\x06\xd85\xa1\v\xbc\xd2\x00\x00\u07d4\xe5\u0713I\xcbR\xe1a\x19a\"\u03c7\xa3\x896\xe2\xc5\u007f4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xe38\x00\xa1\xb2\xe9k\xde\x101c\n\x95\x9a\xa0\a\xf2nQ\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\xe3~\x19@\x8f,\xfb\xec\x834\x9d\u0501S\xa4\xa7\x95\xa0\x8f\x89\u3bb5sr@\xa0\x00\x00\u07d4\xe5\xed\xc7>bo]4A\xa4U9\xb5\xf7\xa3\x98\u0153\xed\xf6\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xe5\xed\xf8\x12?$\x03\xce\x1a\x02\x99\xbe\xcfz\xactM\a_#\x89\n\xdaUGK\x814\x00\x00\u07d4\xe5\xf8\xefm\x97\x066\xb0\u072aO \x0f\xfd\xc9\xe7Z\xf1t\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xfb1\xa5\xca\xeej\x96\xde9;\xdb\xf8\x9f\xbee\xfe\x12[\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xfb\xe3I\x84\xb67\x19o3\x1cg\x9d\f\fG\xd84\x10\xe1\x89llD\xfeG\xec\x05\x00\x00\u07d4\xe6\tU\xdc\v\xc1V\xf6\xc4\x18I\xf6\xbdwk\xa4K\x0e\xf0\xa1\x89\x10C\x16'\xa0\x93;\x00\x00\u07d4\xe6\nU\xf2\u07d9m\u00ee\xdbil\b\xdd\xe09\xb2d\x1d\xe8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6\x11[\x13\xf9y_~\x95e\x02\xd5\aEg\u06b9E\xcek\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xe6\x1f(\t\x15\xc7t\xa3\x1d\"<\xf8\f\x06\x92f\xe5\xad\xf1\x9b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xe6/\x98e\a\x12\xeb\x15\x87S\xd8)r\xb8\u9723\xf6\x18w\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6/\x9d|d\xe8\xe2cZ\xeb\x88=\xd7;\xa6\x84\xee|\x10y\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe6>xt\x14\xb9\x04\x84x\xa5\a35\x9e\xcd\xd7\xe3dz\xa6\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe6FfXr\xe4\v\rz\xa2\xff\x82r\x9c\xaa\xba[\xc3\u8789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe6N\xf0\x12e\x8dT\xf8\xe8`\x9cN\x90#\xc0\x9f\xe8e\xc8;\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\xe6On\x1dd\x01\xb5l\akd\xa1\xb0\x86}\v/1\rN\x89\x02\u02edq\xc5:\xe5\x00\x00\u07d4\xe6g\xf6R\xf9W\u008c\x0ef\u04364\x17\xc8\f\x8c\x9d\xb8x\x89 \x9d\x92/RY\xc5\x00\x00\xe0\x94\xe6w\xc3\x1f\xd9\xcbr\x00u\u0724\x9f\x1a\xbc\xcdY\xec3\xf74\x8a\x01\xa6\u05be\xb1\xd4.\xe0\x00\x00\u07d4\xe6|,\x16e\u02038h\x81\x87b\x9fI\xe9\x9b`\xb2\u04fa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xe6\x9al\xdb:\x8a}\xb8\xe1\xf3\f\x8b\x84\xcds\xba\xe0+\xc0\xf8\x8a\x03\x94\xfd\xc2\xe4R\xf6q\x80\x00\u07d4\xe6\x9d\x1c7\x8bw\x1e\x0f\xef\xf0Q\xdbi\xd9f\xacgy\xf4\xed\x89\x1d\xfaj\xaa\x14\x97\x04\x00\x00\u07d4\xe6\x9f\xcc&\xed\"_{.7\x984\xc5$\xd7\f\x175\u5f09lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\xa3\x01\x0f\x02\x01\xbc\x94\xffg\xa2\xf6\x99\xdf\xc2\x06\xf9\xe7gB\x89/\xa7\xcb\xf6dd\x98\x00\x00\u07d4\xe6\xa6\xf6\xddop\xa4V\xf4\xec\x15\xefz\xd5\xe5\u06f6\x8b\xd7\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe6\xb2\x0f\x98\n\xd8S\xad\x04\xcb\xfc\x88|\xe6`\x1ck\xe0\xb2L\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u6cec?]M\xa5\xa8\x85}\v?0\xfcK+i+w\u05c9O%\x91\xf8\x96\xa6P\x00\x00\u07d4\xe6\xb9T_~\u0406\xe5R\x92F9\xf9\xa9\xed\xbb\xd5T\v>\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\xe0\x94\xe6\xbc\xd3\n\x8f\xa18\xc5\xd9\xe5\xf6\xc7\xd2\u0680i\x92\x81-\u034a7\x0e\xa0\xd4|\xf6\x1a\x80\x00\x00\u07d4\xe6\xc8\x1f\xfc\xec\xb4~\xcd\xc5\\\vq\xe4\x85_>^\x97\xfc\x1e\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\xe6\xcb&\vqmL\n\xb7&\xee\xeb\a\xc8pr\x04\xe2v\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe6\xcb?1$\xc9\xc9\xcc84\xb1'K\xc33dV\xa3\x8b\xac\x89\x17+\x1d\xe0\xa2\x13\xff\x00\x00\xe0\x94\xe6\xd2\"\t\xff\u0438u\t\xad\xe3\xa8\xe2\xefB\x98y\u02c9\xb5\x8a\x03\xa7\xaa\x9e\x18\x99\xca0\x00\x00\u07d4\xe6\u051f\x86\xc2(\xf4sg\xa3^\x88l\xaa\xcb'\x1eS\x94)\x89\x16^\xc0\x9d\xa7\xa1\x98\x00\x00\u07d4\xe6\xe6!\xea\xab\x01\xf2\x0e\xf0\x83k|\xadGFL\xb5\xfd<\x96\x89\x11!\x93B\xaf\xa2K\x00\x00\u07d4\xe6\xe8\x861{jf\xa5\xb4\xf8\x1b\xf1d\xc58\xc2d5\x17e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\u98ddu\x0f\xe9\x949N\xb6\x82\x86\xe5\xeab\xa6\x99x\x82\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xe6\xec\\\xf0\u011b\x9c1~\x1epc\x15\uf7b7\xc0\xbf\x11\xa7\x8a\x03\xa4i\xf3F~\x8e\xc0\x00\x00\u07d4\xe6\xf5\xebd\x9a\xfb\x99Y\x9cAK'\xa9\xc9\xc8U5\u007f\xa8x\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xe6\xfe\n\xfb\x9d\xce\xdd7\xb2\xe2,E\x1b\xa6\xfe\xabg4\x803\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe7\x10\xdc\u041b\x81\x01\xf9C{\xd9}\xb9\ns\xef\x99=\v\xf4\x89\x14\xee6\xc0Z\xc2R\x00\x00\u07d4\xe7'\xe6~\xf9\x11\xb8\x1fl\xf9\xc7?\xcb\xfe\xbc+\x02\xb5\xbf\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7.\x1d3\\\u009a\x96\xb9\xb1\xc0/\x00:\x16\xd9q\xe9\v\x9d\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe71\x1c\x953\xf0\t,rH\xc9s\x9b[,\x86J4\xb1\u0389\x97\xf9}l\xc2m\xfe\x00\x00\u07d4\xe7;\xfe\xad\xa6\xf0\xfd\x01o\xbc\x84>\xbc\xf6\xe3p\xa6[\xe7\f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xe7<\xcfCg%\xc1Q\xe2U\xcc\xf5!\f\xfc\xe5\xa4?\x13\xe3\x89\x01\x15NS!}\xdb\x00\x00\u07d4\xe7B\xb1\xe6\x06\x9a\x8f\xfc'\f\xc6\x1f\xa1d\xac\x15SE\\\x10]\x04\x88~\x14\x89\x06\x96\xd8Y\x00 \xbb\x00\x00\u07d4\xe7\\\x1f\xb1w\b\x9f>X\xb1\x06y5\xa6Yn\xf1s\u007f\xb5\x89\x05j\x87\x9f\xa7uG\x00\x00\u07d4\xe7\\;8\xa5\x8a?3\xd5V\x90\xa5\xa5\x97f\xbe\x18^\x02\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7a\xd2\u007f\xa3P,\xc7k\xb1\xa6\bt\x0e\x14\x03\u03dd\xfci\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe7f\xf3O\xf1o<\xfc\xc9s!r\x1fC\xdd\xf5\xa3\x8b\f\xf4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xe7m\x94Z\xa8\x9d\xf1\xe4W\xaa4+1\x02\x8a^\x910\xb2\u03897\b\xba\xed=h\x90\x00\x00\u07d4\xe7s^\xc7e\x18\xfcj\xa9-\xa8qZ\x9e\xe3\xf6%x\x8f\x13\x89lM\x16\v\xaf\xa1\xb7\x80\x00\xe0\x94\xe7z\x89\xbdE\xdc\x04\xee\xb4\xe4\x1d{Ykp~nQ\xe7L\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xe7}}\uac96\u0234\xfa\a\xca;\xe1\x84\x16=Zm`l\x89\x05\x049\x04\xb6q\x19\x00\x00\u07d4\xe7\u007f\xeb\xab\xdf\b\x0f\x0f]\xca\x1d?Wf\xf2\xa7\x9c\x0f\xfa|\x89K\"\x9d(\xa8Ch\x00\x00\xe0\x94\u7025c\x06\xba\x1ek\xb31\x95,\"S\x9b\x85\x8a\xf9\xf7}\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xe7\x81\xecs-@\x12\x02\xbb\x9b\xd18`\x91\r\xd6\u009a\xc0\xb6\x89C8t\xf62\xcc`\x00\x00\u07d4\xe7\x84\xdc\xc8s\xaa\x8c\x15\x13\xec&\xff6\xbc\x92\xea\xc6\xd4\xc9h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\x91-L\xf4V,W=\xdc[q\xe3s\x10\xe3x\xef\x86\u0249\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xe7\x91\u0545\xb8\x996\xb2])\x8f\x9d5\xf9\xf9\xed\xc2Z)2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\x924\x9c\xe9\xf6\xf1O\x81\xd0g@\x96\xbe\xfa\x1f\x92!\xcd\xea\x89[]#J\r\xb48\x80\x00\u07d4\xe7\x96\xfdN\x83\x9bL\x95\xd7Q\x0f\xb7\xc5\xc7+\x83\xc6\xc3\xe3\u01c9\x1b\xc43\xf2?\x83\x14\x00\x00\xe0\x94\xe7\xa4/Y\xfe\xe0t\xe4\xfb\x13\xea\x9eW\xec\xf1\xccH(\"I\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xe7\xa4V\f\x84\xb2\x0e\x0f\xb5LIg\f)\x03\xb0\xa9lB\xa4\x89 j\xea\u01e9\x03\x98\x00\x00\u07d4\xe7\xa8\xe4q\xea\xfby\x8fET\xccnRg0\xfdV\xe6,}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u7f82\xc6Y<\x1e\xed\xdd*\xe0\xb1P\x01\xff \x1a\xb5{/\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\xe7\u01b5\xfc\x05\xfct\x8e[C\x81rdI\xa1\xc0\xad\x0f\xb0\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\xd1u$\xd0\v\xad\x82I|\x0f'\x15jd\u007f\xf5\x1d'\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe7\xd2\x13\x94\u007f\u02d0J\xd78H\v\x1e\xed/\\2\x9f'\xe8\x89\x01\x03\u00f1\xd3\xe9\xc3\x00\x00\u07d4\xe7\xd6$\x06 \xf4,^\u06f2\xed\xe6\xae\xc4=\xa4\xed\x9bWW\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xda`\x9d@\xcd\xe8\x0f\x00\xce[O\xfbj\xa9\u04304\x94\xfc\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xf0oi\x9b\xe3\x1cD\vC\xb4\xdb\x05\x01\xec\x0e%&\x16D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7\xf4\xd7\xfeoV\x1f\u007f\xa1\xda0\x05\xfd6TQ\xad\x89\u07c9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\xfd\x8f\xd9Y\xae\xd2v~\xa7\xfa\x96\f\xe1\xdbS\xaf\x80%s\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe8\x0e\u007f\xef\x18\xa5\xdb\x15\xb0\x14s\xf3\xadkx\xb2\xa2\xf8\xac\u0649\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe8\x13\u007f\xc1\xb2\xec|\xc7\x10:\xf9!\x89\x9bJ9\xe1\xd9Y\xa1\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xe8\x1c-4l\n\xdfL\xc5g\b\xf69K\xa6\xc8\u0226J\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8,X\xc5yC\x1bg5F\xb5:\x86E\x9a\xca\xf1\u079b\x93\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe84\xc6C\x18 \\\xa7\xddJ!\xab\xcb\b&l\xb2\x1f\xf0,\x8965\xc6 G9\u0640\x00\u07d4\xe86\x04\xe4\xffk\xe7\xf9o`\x18\xd3\xec0r\xecR]\xffk\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94\xe8E\xe3\x87\xc4\xcb\u07d8\"\x80\xf6\xaa\x01\xc4\x0eK\xe9X\u0772\x8a\x05K@\xb1\xf8R\xbd\xa0\x00\x00\u07d4\xe8H\xca~\xbf\xf5\xc2O\x9b\x9c1g\x97\xa4;\xf7\xc3V)-\x89\x06.\x11\\\x00\x8a\x88\x00\x00\u07d4\xe8KU\xb5%\xf1\x03\x9etK\x91\x8c\xb33$\x92\xe4^\xcaz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe8O\x80v\xa0\xf2\x96\x9e\xcd3>\xef\x8d\xe4\x10B\x98b\x91\xf2\x89\x17k4O*x\xc0\x00\x00\u07d4\xe8d\xfe\xc0~\xd1!Je1\x1e\x11\xe3)\xde\x04\r\x04\xf0\xfd\x89Y\u0283\xf5\xc4\x04\x96\x80\x00\u07d4\xe8}\xba\xc66\xa3w!\xdfT\xb0\x8a2\xefIY\xb5\xe4\xff\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe8~\x9b\xbf\xbb\xb7\x1c\x1at\ft\xc7#Bm\xf5]\x06=\u064a\x01\xb1\x92\x8c\x00\u01e68\x00\x00\u07d4\xe8~\xacm`+A\t\xc9g\x1b\xf5{\x95\f,\xfd\xb9\x9dU\x89\x02\xb4\xf2\x19r\xec\xce\x00\x00\xe0\x94\u807b\xbeir-\x81\xef\xec\xaaH\u0455*\x10\xa2\xbf\xac\x8f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xe8\x92Is\x8b~\xce\xd7\xcbfjf\xe4s\xbcv\x82/U\t\x8d\x89\xb9\x1c\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xc3\u04f0\xe1\u007f\x97\xd1\xe7V\xe6\x84\xf9N\x14p\xf9\x9c\x95\xa1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xe8\xc3\xf0E\xbb}8\xc9\xd2\U000d5c3a\x84\x92\xb2S#\t\x01\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\xe8\xccC\xbcO\x8a\xcf9\xbf\xf0N\xbf\xbfB\xaa\xc0j2\x84p\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe8\xd9B\xd8/\x17^\xcb\x1c\x16\xa4\x05\xb1\x01C\xb3\xf4k\x96:\x89\x1e\xd2\xe8\xffm\x97\x1c\x00\x00\u07d4\xe8\u077e\xd72\xeb\xfeu@\x96\xfd\xe9\bk\x8e\xa4\xa4\xcd\xc6\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xder^\xca]\xef\x80_\xf7\x94\x1d1\xac\x1c.4-\xfe\x95\x89\x85~\ro\x1d\xa7j\x00\x00\u07d4\xe8\xe9\x85\x05\x86\xe9OR\x99\xabIK\xb8!\xa5\xf4\f\x00\xbd\x04\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xe8\xea\u047b\x90\xcc\u00ee\xa2\xb0\xdc\u0175\x80VUFU\xd1\u054a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4\xe8\xea\xf1)D\t-\xc3Y\x9b9S\xfa|\xb1\xc9v\x1c\xc2F\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xe8\xedQ\xbb\xb3\xac\xe6\x9e\x06\x02K3\xf8hD\xc4sH\u06de\x8a\"\xf9\xea\x89\xf4\xa7\xd6\xc4\x00\x00\u07d4\xe8\xef\x10\r|\xe0\x89X2\xf2g\x8d\xf7-J\u03cc(\xb8\xe3\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xe8\xf2\x99i\xe7\\e\xe0\x1c\xe3\xd8aT }\n\x9e|v\xf2\x89\xa2/\xa9\xa7:'\x19\x80\x00\u07d4\xe8\xfc6\xb0\x13\x1e\xc1 \xac\x9e\x85\xaf\xc1\f\xe7\vV\u0636\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9\n5L\xec\x04\u059e]\x96\xdd\xc0\xc5\x13\x8d=3\x15\n\xa0\x89\x1b\x1a}\u03caD\u04c0\x00\xe0\x94\xe9\x13>}1\x84]_+f\xa2a\x87\x92\xe8i1\x1a\xcff\x8a\x05\x17\xc0\xcb\xf9\xa3\x90\x88\x00\x00\u07d4\xe9\x1d\xac\x01\x95\xb1\x9e7\xb5\x9bS\xf7\xc0\x17\xc0\xb29[\xa4L\x89e\xea=\xb7UF`\x00\x00\u07d4\xe9\x1f\xa0\xba\xda\u0779\xa9~\x88\xd3\xf4\xdb|U\u05bbt0\xfe\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xe9#\xc0aw\xb3B~\xa4H\xc0\xa6\xff\x01\x9bT\xccT\x8d\x95\x89\x01\xf7\x80\x01Fg\xf2\x80\x00\xe0\x94\xe9=G\xa8\u0288]T\fNRo%\xd5\xc6\xf2\xc1\b\u0138\x8a\x17\xda:\x04\u01f3\xe0\x00\x00\x00\u07d4\xe9E\x8fh\xbb',\xb5g:\x04\xf7\x81\xb4\x03Uo\u04e3\x87\x89\x03N\x8b\x88\xce\xe2\xd4\x00\x00\u07d4\xe9IA\xb6\x03`\x19\xb4\x01j0\xc1\x03}Zi\x03\xba\xba\xad\x89*H\xac\xabb\x04\xb0\x00\x00\u07d4\xe9I[\xa5\x84'(\xc0\ud5fe7\xd0\xe4\"\xb9\x8di ,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe9M\xed\x99\u0735r\xb9\xbb\x1d\u02e3/m\xee\x91\xe0W\x98N\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94\xe9QyR}\uc951l\xa9\xa3\x8f!\\\x1e\x9c\xe77\xb4\u024a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xe9U\x91\x85\xf1f\xfc\x95\x13\xccq\x11aD\xce-\xeb\x0f\x1dK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xe9^\x92\xbb\xc6\xde\a\xbf:f\x0e\xbf_\xeb\x1c\x8a5'\xe1\u0148\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xe9e\u06a3@9\xf7\xf0\xdfb7Z7\u5acar\xb3\x01\xe7\x8a\x01\x03\xfd\xde\u0373\xf5p\x00\x00\u07d4\xe9i\xea\x15\x95\xed\xc5\u0127\a\xcf\xde8\t)c2Q\xa2\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9k\x18N\x1f\x0fT\x92J\xc8t\xf6\v\xbfDptF\xb7+\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\xe0\x94\xe9m}L\xdd\x15U:NM1mmd\x80\xca<\xea\x1e8\x8a\x02\x95]\x02\xe1\xa15\xa0\x00\x00\u07d4\xe9n-8\x13\xef\xd1\x16_\x12\xf6\x02\xf9\u007fJb\x90\x9d\x1b;\xc0\xe9\xaa\"\u007f\x90\x89'\xcaK\xd7\x19\xf0\xb8\x00\x00\u07d4\xea,\x19}&\xe9\x8b\r\xa8>\x1br\u01c7a\x8c\x97\x9d=\xb0\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94\xea7y\xd1J\x13\xf6\u01c5f\xbc\xde@5\x91A:b9\u06ca)\xb7d2\xb9DQ \x00\x00\u07d4\xeaN\x80\x9e&j\xe5\xf1<\xdb\u33dd\x04V\xe68m\x12t\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\xe0\x94\xeaS\xc9T\xf4\xed\x97\xfdH\x10\x11\x1b\u06b6\x9e\xf9\x81\xef%\xb9\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xeaS\xd2ed\x85\x9d\x9e\x90\xbb\x0eS\xb7\xab\xf5`\xe0\x16,8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xea`Ci\x12\xdek\xf1\x87\u04e4r\xff\x8fS3\xa0\xf7\xed\x06\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xea`T\x9e\xc7U?Q\x1d!I\xf2\xd4fl\xbd\x92C\xd9<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeaf\xe7\xb8M\u037f6\xee\xa3\xe7[\x858*u\xf1\xa1]\x96\x89]\xbc\x91\x91&o\x11\x80\x00\u07d4\xeahlPW\t<\x17\x1cf\u06d9\xe0\x1b\x0e\xce\xcb0\x86\x83\x89\x14\u0768],\xe1G\x80\x00\u07d4\xeaj\xfe,\xc9(\xac\x83\x91\xeb\x1e\x16_\xc4\x00@\xe3t!\u7262\u007f\xa0c\xb2\xe2\xe6\x80\x00\u07d4\xeay\x05}\xab\xef^d\xe7\xb4O\u007f\x18d\x8e~S7\x18\u0489\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xea|Mm\xc7)\xcdk\x15|\x03\xad#|\xa1\x9a \x93F\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\x81h\xfb\xf2%\xe7\x86E\x9c\xa6\xbb\x18\xd9c\xd2kPS\t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xea\x81\u02868T\f\xd9\xd4\xd7=\x06\x0f,\xeb\xf2$\x1f\xfc>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xea\x83\x17\x19yYB@A\xd9\xd7\xc6z>\xce\x1d\xbbx\xbbU\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xea\x85'\xfe\xbf\xa1\xad\xe2\x9e&A\x93)\u04d3\xb9@\xbb\xb7\u0709lj\xccg\u05f1\xd4\x00\x00\u07d4\xea\x8f0\xb6\xe4\xc5\xe6R\x90\xfb\x98d%\x9b\u0159\x0f\xa8\ue289\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\x94\xf3(\b\xa2\uf29b\xf0\x86\x1d\x1d$\x04\xf7\xb7\xbe%\x8a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\xa4\\\xea\x02\xd8},\xc8\xfd\xa9CN-\x98[\xd4\x03\x15\x84\x89h\x1f\xc2\xccn+\x8b\x00\x00\xe0\x94\uac3d\x14\x83\t\x18l\xf8\xcb\xd1;r2\xd8\tZ\u02c3:\x8a\x02C\x9a\x88\x1cjq|\x00\x00\u07d4\uaed0\xd3y\x89\xaa\xb3\x1f\xea\xe5G\xe0\xe6\xf3\x99\x9c\xe6\xa3]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xc0\x82~\xff\fn?\xf2\x8a}JT\xf6\\\xb7h\x9d{\x99\x89\x9a\xd9\u67ddGR\x00\x00\u07d4\xea\xc1H(&\xac\xb6\x11\x1e\x19\xd3@\xa4_\xb8QWk\xed`\x89\x01\xbe\x8b\xab\x04\u067e\x80\x00\xe0\x94\xea\xc1{\x81\xedQ\x91\xfb\b\x02\xaaT3s\x13\x83A\a\xaa\xa4\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xea\u00efW\x84\x92\u007f\u9958\xfcN\xec8\xb8\x10/7\xbcX\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xea\u01b9\x88BT.\xa1\v\xb7O&\xd7\xc7H\x8fi\x8bdR\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xea\xc7h\xbf\x14\xb8\xf9C.i\xea\xa8*\x99\xfb\xeb\x94\xcd\f\x9c\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xea\xd2\x1c\x1d\xec\u03ff\x1c\\\xd9f\x88\xa2Gki\xba\a\xceJ\x89\x03\xf2M\x8eJ\x00p\x00\x00\u07d4\xea\xd4\xd2\xee\xfbv\xab\xaeU3\x96\x1e\xdd\x11@\x04\x06\xb2\x98\xfc\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xea\xd6Rb\xed]\x12-\xf2\xb2u\x14\x10\xf9\x8c2\xd1#\x8fQ\x89\x05\x83\x17\xedF\xb9\xb8\x00\x00\u07d4\xea\xd7P\x16\u3801Pr\xb6\xb1\b\xbc\xc1\xb7\x99\xac\xf08>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xea#\xaa\x05r\x00\xe7\xc9\xc1^\x8f\xf1\x90\xd0\xe6l\f\x0e\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xed\x16\xea\xf5\u06ab[\xf0)^^\a\u007fY\xfb\x82U\x90\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xea\xed\xcck\x8bib\xd5\xd9(\x8c\x15lW\x9dG\xc0\xa9\xfc\xff\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xea\xf5#\x88Tn\xc3Z\xcaolc\x93\xd8\xd6\t\xde:K\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xeb\x10E\x8d\xac\xa7\x9eJk$\xb2\x9a\x8a\x8a\xdaq\x1b\u007f.\xb6\x89\u063beI\xb0+\xb8\x00\x00\u07d4\xeb\x1c\xea{E\u047dM\x0e*\x00{\u04ff\xb3Tu\x9e,\x16\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xeb%H\x1f\u035c\"\x1f\x1a\xc7\xe5\xfd\x1e\u0353\a\xa1b\x15\xb8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xeb.\xf3\u04cf\xe6R@<\xd4\xc9\xd8^\xd7\xf0h,\xd7\xc2\u078a\t\x0fSF\b\xa7(\x80\x00\x00\xe0\x94\xeb;\xddY\xdc\u0765\xa9\xbb*\xc1d\x1f\xd0!\x80\xf5\xf3e`\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4\xeb<\xe7\xfc8\x1cQ\xdb}_\xbdi/\x8f\x9e\x05\x8aLp=\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xebE?Z:\xdd\u074a\xb5gP\xfa\xdb\x0f\xe7\xf9M\x9c\x89\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xebO\x00\xe2\x836\xea\t\x94%\x88\ueb12\x18\x11\xc5\"\x14<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebR\xab\x10U4\x922\x9c\x1cT\x83:\xe6\x10\xf3\x98\xa6[\x9d\x89\b=lz\xabc`\x00\x00\u07d4\xebW\r\xba\x97R'\xb1\xc4-n\x8d\xea,V\u026d\x96\x06p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebc\x94\xa7\xbf\xa4\u0489\x11\u0565\xb2>\x93\xf3^4\f\"\x94\x89\x04:w\xaa\xbd\x00x\x00\x00\u07d4\xebh\x10i\x1d\x1a\xe0\u045eG\xbd\"\u03be\u0cfa'\xf8\x8a\x89\x87\x85c\x15\xd8x\x15\x00\x00\u07d4\xebvBL\x0f\u0557\xd3\xe3A\xa9d*\xd1\xee\x11\x8b+W\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb| +F+|\u0145]t\x84u_n&\xefC\xa1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\x83\\\x1a\x91\x18\x17\x87\x8a3\xd1gV\x9e\xa3\xcd\u04c7\xf3(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\ub268\x82g\t\t\xcf7~\x9ex(n\xe9{\xa7\x8dF\u0089+|\xc2\xe9\xc3\"\\\x00\x00\xe0\x94\xeb\x90\u01d3\xb3S\x97a\xe1\xc8\x14\xa2\x96q\x14\x86\x92\x19>\xb4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xeb\x9c\xc9\xfe\bi\xd2\u06b5,\u01ea\xe8\xfdW\xad\xb3_\x9f\xeb\x89j\x93\xbb\x17\xaf\x81\xf8\x00\x00\xe0\x94\ub8c8\xb0\xda'\xc8{\x1c\xc0\xea\xc6\xc5{,Z\vE\x9c\x1a\x8a\x01p\xa0\xf5\x04\x0eP@\x00\x00\u07d4\xeb\xaa!m\xe9\xccZC\x03\x17\a\xd3o\xe6\u057e\xdc\x05\xbd\xf0\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xeb\xac+D\b\xefT1\xa1;\x85\b\xe8bP\x98!\x14\xe1E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb\xb6,\xf8\xe2,\x88K\x1b(\xc6\xfa\x88\xfb\xbc\x17\x93\x8a\xa7\x87\x89+By\x84\x03\u0278\x00\x00\u07d4\xeb\xb7\xd2\xe1\x1b\u01b5\x8f\n\x8dE\xc2\xf6\xde0\x10W\n\u0211\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4\xeb\xbbO,=\xa8\xbe>\xb6-\x1f\xfb\x1f\x95\x02a\u03d8\xec\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\xbdM\xb9\x01\x99R\u058b\x1b\x0fm\x8c\xf0h<\x008{\xb5\x89\x12\x04\x01V=}\x91\x00\x00\u07d4\xeb\xbe\xeb%\x91\x84\xa6\xe0\x1c\xcc\xfc\"\a\xbb\u0603xZ\xc9\n\x89!\x9b\xc1\xb0G\x83\xd3\x00\x00\u07d4\xeb\xd3V\x15j81#4=H\x84;\xff\xeda\x03\xe8f\xb3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xeb\xd3{%ec\xe3\fo\x92\x89\xa8\xe2p/\bR\x88\b3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xeb\xe4l\xc3\xc3L2\xf5\xad\xd6\xc3\x19[\xb4\x86\xc4q>\xb9\x18\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xeb\xff\x84\xbb\xefB0q\xe6\x04\xc3a\xbb\xa6w\xf5Y=\xefN\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xec\t'\xba\xc7\xdc6f\x9c(5J\xb1\xbe\x83\xd7\xee\xc3\t4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\x0e\x18\xa0\x1d\xc4\xdc]\xaa\xe5g\xc3\xfaL\u007f\x8f\x9bY\x02\x05\x89\x11\x1f\xfe@JA\xe6\x00\x00\xe0\x94\xec\x116,\xec\x81\t\x85\xd0\xeb\xbd{sE\x14D\x98[6\x9f\x8a\x06ZNIWpW1\x80\x00\u07d4\xec,\xb8\xb97\x8d\xff1\xae\xc3\xc2.\x0em\xad\xff1J\xb5\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xec0\xad\u0749[\x82\xee1\x9eT\xfb\x04\xcb+\xb09q\xf3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec;\x8bX\xa1'\x03\xe5\x81\xce_\xfd~!\xc5}\x1e\\f?\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xecHg\xd2\x17Z\xb5\xb9F\x93aYUFUF\x84\u0364`\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xecM\b\xaa.GIm\u0287\"]\xe3?+@\xa8\xa5\xb3o\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\xecX\xbc\r\f \xd8\xf4\x94efAS\xc5\xc1\x96\xfeY\u6f89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xec[\x19\x8a\x00\u03f5Z\x97\xb5\xd56D\xcf\xfa\x8a\x04\u04abE\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec]\xf2'\xbf\xa8]z\xd7kBn\x1c\xee\x96;\xc7\xf5\x19\u074965\u026d\xc5\u07a0\x00\x00\xe0\x94\xec_\xea\xfe!\f\x12\xbf\u0265\xd0Y%\xa1#\xf1\xe7?\xbe\xf8\x8a`\x8f\xcf=\x88t\x8d\x00\x00\x00\u07d4\xeci\x04\xba\xe1\xf6\x97\x90Y\x17\t\xb0`\x97\x83s?%s\xe3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xecs\x11L^@o\u06fe\t\xb4\xfab\x1b\xd7\x0e\xd5N\xa1\xef\x8a\x050%\xcd!o\xceP\x00\x00\u07d4\xecs\x83=\xe4\xb8\x10\xbb\x02x\x10\xfc\x8fi\xf5D\xe8<\x12\u044965\u026d\xc5\u07a0\x00\x00\u07d4\xecu\xb4\xa4u\x13\x12\v\xa5\xf8`9\x81O\x19\x98\xe3\x81z\u00c9\t\xb0\xbc\xe2\xe8\xfd\xba\x00\x00\u07d4\xecv\xf1.W\xa6U\x04\x03?,\v\xceo\xc0;\xd7\xfa\n\u0109\xc2\x12z\xf8X\xdap\x00\x00\u0794\xec\x80\x14\xef\xc7\xcb\xe5\xb0\xceP\xf3V,\xf4\xe6\u007f\x85\x93\xcd2\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xec\x82\xf5\r\x06G_hM\xf1\xb3\x92\xe0\r\xa3A\xaa\x14TD\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xec\x83\xe7\x98\u00d6\xb7\xa5^*\"$\xab\u0343K'\xeaE\x9c\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\x89\xf2\xb6x\xa1\xa1[\x914\xec^\xb7\fjb\a\x1f\xba\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\x8c\x1d{j\xac\xcdB\x9d\xb3\xa9\x1e\xe4\xc9\xeb\x1c\xa4\xf6\xf7<\x89\xe6d\x99\"\x88\xf2(\x00\x00\xe0\x94\xec\x98Q\xbd\x91rpa\x02g\xd6\x05\x18\xb5M<\xa2\xb3[\x17\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xec\x99\xe9]\xec\xe4o\xff\xfb\x17^\xb6@\x0f\xbe\xbb\b\ue6d5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xec\xa5\xf5\x87\x92\xb8\xc6-*\xf5Vq~\xe3\xee0(\xbeM\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xabZ\xba[\x82\x8d\xe1pS\x81\xf3\x8b\xc7D\xb3+\xa1\xb47\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\xec\xaf3P\xb7\xce\x14M\x06\x8b\x18`\x10\x85,\x84\xdd\f\xe0\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xb9LV\x8b\xfeY\xad\xe6Pd_O&0lsl\xac\xe4\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xec\xbeB^g\r9\tN \xfbVC\xa9\xd8\x18\xee\xd26\u078a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xec\xbe^\x1c\x9a\u04b1\xdc\xcf\n0_\xc9R/Fi\xdd:\xe7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xec\xcfz\x04W\xb5f\xb3F\xcag:\x18\x0fDA0!j\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4\xec\u0466(\x025\x1aAV\x8d#\x030\x04\xac\xc6\xc0\x05\xa5\u04c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xec\xd2v\xafd\u01dd\x1b\u0669+\x86\xb5\u835a\x95\xeb\x88\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xec\u0506\xfc\x19g\x91\xb9,\xf6\x12\xd3HaO\x91VH\x8b~\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\xda\xf92)\xb4^\xe6r\xf6]\xb5\x06\xfb^\xca\x00\xf7\xfc\xe6\x89W\x01\xf9m\xcc@\xee\x80\x00\u07d4\xec\xe1\x11g\vV<\u037e\xbc\xa5#\x84)\x0e\xcdh\xfe\\\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xec\xe1\x15&\x82\xb7Y\x8f\xe2\xd1\xe2\x1e\xc1U3\x88T5\xac\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xec\xe1)\bw\xb5\x83\xe3a\xa2\xd4\x1b\x00\x93F\xe6'N%8\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xec\xf0]\a\xea\x02n~\xbfIA\x00#5\xba\xf2\xfe\xd0\xf0\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\xf2L\xdd|\"\x92\x8cD\x1eiM\xe4\xaa1\xb0\xfa\xb5\x97x\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xec\xfd\x00M\x02\xf3l\xd4\u0634\xa8\xc1\xa9S;j\xf8\\\xd7\x16\x8a\x01\x0fA\xac\xb4\xbb;\x9c\x00\x00\xe0\x94\xed\x02\x06\xcb#1Q(\xf8\xca\xff&\xf6\xa3\v\x98Tg\xd0\"\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xed\x10e\xdb\u03dds\xc0O\xfcy\b\x87\r\x88\x14h\xc1\xe12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xed\x12vQ;o\u0186(\xa7A\x85\xc2\xe2\f\xbb\xcax\x17\xbf\x89\nZ\xa8P\t\xe3\x9c\x00\x00\xe0\x94\xed\x12\xa1\xba\x1f\xb8\xad\xfc\xb2\r\xfa\x19X.RZ\xa3\xb7E$\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xed\x16\xce9\xfe\xef;\xd7\xf5\xd1b\x04^\x0fg\xc0\xf0\x00F\xbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xed\x1a\\C\xc5t\xd4\xe94)\x9b$\xf1G,\u071f\xd6\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xed\x1b$\xb6\x91-Q\xb34\xac\r\xe6\xe7q\xc7\xc0EF\x95\xea\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xed\x1f\x1e\x11Z\r`\xce\x02\xfb%\xdf\x01M(\x9e:\f\xbe}\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xed10\\1\x9f\x92s\u04d3m\x8f[/q\u9c72)c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xed2z\x14\xd5\u03ed\u0641\x03\xfc\t\x99q\x8d~\xd7\x05(\xea\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d4\xed<\xbc7\x82\u03bdg\x98\x9b0\\A3\xb2\xcd\xe3\"\x11\xeb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xed@\x14S\x8c\xeefJ/\xbc\xb6\xdcf\x9fz\xb1m\v\xa5|\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedA\u188f\\\xaa\x848\x80\xefN\x8b\b\xbdl3\x14\x1e\u07c9*\xd5\xdd\xfaz\x8d\x83\x00\x00\xe0\x94\xedK\xe0J\x05-z\u0333\xdc\u03901\x9d\xba@ \xab,h\x8a\a\xf3zp\xea\xf3b\x17\x80\x00\xe0\x94\xedR\xa2\xcc\bi\u071e\x9f\x84+\u0415|G\xa8\xe9\xb0\xc9\xff\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xed[LA\xe7b\xd9B@Cs\xca\xf2\x1e\xd4a]%\xe6\xc1\x89m-O=\x95%\xb4\x00\x00\u07d4\xed`\u012bnT\x02\x061~5\x94zc\xa9\xcak\x03\xe2\u02c9\x03\x1a\u066d\vF\u007f\x80\x00\u07d4\xedd\x1e\x066\x8f\xb0\xef\xaa\x17\x03\xe0\x1f\xe4\x8fJhS\t\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedfC\xc0\xe8\x88K-2\x11\x857\x85\xa0\x8b\xf8\xf3>\u049f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xedp\xa3|\xdd\x1c\xbd\xa9tm\x93\x96X\xae*a\x81(\x85x\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\xedsFvn\x1agm\r\x06\xec\x82\x18g\xa2v\xa0\x83\xbf1\x89\u064a\t1\xcc-I\x00\x00\u07d4\xed\x86&\x16\xfc\xbf\xb3\xbe\xcbt\x06\xf7<\\\xbf\xf0\f\x94\aU\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xed\x9e\x03\f\xa7\\\xb1\u049e\xa0\x1d\rL\xdf\xdc\xcd8D\xb6\xe4\x89\x01\xac\xc1\x16\u03ef\xb1\x80\x00\xe0\x94\ud7bc\u02e4/\x98\x15\xe7\x823&m\xd6\xe85\xb6\xaf\xc3\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\ud7f1\xf5\xaf/\xbf\u007f\xfcP)\xce\xe4+p\xff\\'[\xf5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xed\xa4\xb2\xfaY\u0584\xb2z\x81\r\xf8\x97\x8as\xdf0\x8ac\u0089\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xed\xb4s59y\xa2\x06\x87\x9d\xe1D\xc1\n:\xcf\x12\xa7'OV9a\xf57R\x9d\x89\xc7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xeer\x88\xd9\x10\x86\xd9\xe2\xeb\x91\x00\x14\u066b\x90\xa0-x\u00a0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xee|=\xed|(\xf4Y\xc9/\xe1;M\x95\xba\xfb\xab\x026}\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xee\x86} \x91k\xd2\xe9\xc9\xec\xe0\x8a\xa0C\x85\xdbf|\x91.\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\ue25b\x02\xcb\xcb99\xcda\xde\x13B\xd5\x04\x82\xab\xb6\x852\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xee\x90m}_\x17H%\x81t\xbeL\xbc8\x93\x03\x02\xab{B\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\ue5ea\x8a\u019e\xdfz\x98}mp\x97\x9f\x8e\xc1\xfb\xcaz\x94\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xee\xa1\xe9y\x88\xdeu\xd8!\xcd(\xadh\"\xb2,\u0398\x8b1\x89\x1c0s\x1c\xec\x03 \x00\x00\xe0\x94\xee\u048c?\x06\x8e\tJ0K\x85<\x95\nh\t\xeb\xcb\x03\xe0\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xee\u04c4\xef-A\xd9\xd2\x03\x97NW\xc1#(\xeav\x0e\b\xea\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xdflB\x80\xe6\xeb\x05\xb94\xac\xe4(\xe1\x1dB1\xb5\x90[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xe7a\x84~3\xfda\u0653\x87\xee\x14b\x86\x94\u047f\xd5%\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xee\xe9\xd0Rn\xda\x01\xe41\x16\xa3\x952-\u0689pW\x8f9\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\xee\xf1\xbb\xb1\xe5\xa8?\u0782H\xf8\x8e\xe3\x01\x8a\xfa-\x132\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xfb\xa1-\xfc\x99gB\xdby\x04d\xca}';\xe6\xe8\x1b>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xfd\x05\xb0\xe3\xc4\x17\xd5[3C\x06\x04\x86\xcd\xd5\xe9*\xa7\xa6\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xef\r\xc7\xddzS\xd6\x12r\x8b\xcb\u04b2|\x19\xddM}fo\x89&A\x1c[5\xf0Z\x00\x00\u07d4\xef\x11RR\xb1\xb8E\u0345\u007f\x00-c\x0f\x1bo\xa3zNP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xef\x1c\x04w\xf1\x18M`\xac\u02b3t\xd3tUz\n>\x10\xf3\x89\b=lz\xabc`\x00\x00\u07d4\xef,4\xbbH}7b\xc3\u0327\x82\xcc\xddz\x8f\xbb\n\x991\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xef5\xf6\u0531\a^j\xa19\x15\x1c\x97K/FX\xf7\x058\x89<;\xc3?\x94\xe5\r\x80\x00\u07d4\xef9\u0291s\xdf\x15S\x1ds\xe6\xb7*hKQ\xba\x0f+\xb4\x89V\xa0\xb4un\xe28\x00\x00\u07d4\xefF<&y\xfb'\x91d\xe2\f=&\x915\x87s\xa0\xad\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xefG\xcf\a>6\xf2q\xd5\"\xd7\xfaNq \xadP\a\xa0\xbc\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\xefa\x15[\xa0\t\xdc\u07be\xf1\v(\xd9\xda=\x1b\xc6\xc9\xce\u0509\x034-`\xdf\xf1\x96\x00\x00\u0794\xefix\x1f2\xff\xce34o,\x9a\xe3\xf0\x84\x93\xf3\xe8/\x89\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xefv\xa4\u034f\xeb\xcb\u0278\x18\xf1x(\xf8\xd94s\xf3\xf3\u02c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\uf4c1\x8fhM\xb0\xc3g^\xc8\x132\xb3\x18>\xcc(\xa4\x95\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94\xef\x9fY\xae\xdaA\x8c\x14\x94h-\x94\x1a\xabI$\xb5\xf4\x92\x9a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\uf9b1\xf0\xdb`57\x82h\x91\xb8\xb4\xbc\x169\x84\xbb@\u03495e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xef\xbdR\xf9}\xa5\xfd:g:F\xcb\xf30D{~\x8a\xad\\\x89\x05l<\x9b\x80\xa0\xa6\x80\x00\xe0\x94\xef\xc8\xcf\x19c\u0269Rg\xb2(\xc0\x86#\x98\x89\xf4\xdf\xd4g\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xef\u02ae\x9f\xf6M,\xd9[RI\xdc\xff\xe7\xfa\xa0\xa0\xc0\xe4M\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xef\xcc\xe0k\xd6\b\x9d\x0eE\x8e\xf5a\xf5\xa6\x89H\n\xfep\x00\x89 \x86\xac5\x10R`\x00\x00\u07d4\xef\xe0g]\xa9\x8a]\xdap\u0356\x19k\x87\xf4\xe7&\xb43H\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xef\xe8\xff\x87\xfc&\x0e\agc\x8d\xd5\xd0/\xc4g.\x0e\xc0m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xeb\x19\x97\xaa\xd2w\xcc3C\x0ea\x11\xed\tCY@H\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xee\xa0\x10uo\x81\xdaK\xa2[r\x17\x87\xf0X\x17\v\uff49\x01\u009c\x9c\xf7p\xef\x00\x00\u07d4\xef\xf5\x1dr\xad\xfa\xe1C\xed\xf3\xa4+\x1a\xecU\xa2\xcc\xdd\v\x90\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xef\xf8kQ#\xbc\xdc\x17\xedL\xe8\xe0[~\x12\xe5\x13\x93\xa1\xf7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xef\xfc\x15\u41f1\xbe\xda\n\x8d\x13%\xbd\xb4\x17\"@\xdcT\n\x89\x03\x8599\xee\xe1\xde\x00\x00\xe0\x94\xf0\x11\x95\xd6W\xef<\x94.l\xb89I\xe5\xa2\v\\\xfa\x8b\x1e\x8a\x05ts\xd0]\xab\xae\x80\x00\x00\u07d4\xf0'\x96)Q\x01gB\x88\xc1\xd94g\x05=\x04\"\x19\xb7\x94\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\xf09h={=\"[\xc7\xd8\u07ed\xefc\x164A\xbeA\xe2\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xf0Jj7\x97\b\xb9B\x8dr*\xa2\xb0kw\xe8\x895\u03c9\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf0M,\x91\xef\xb6\xe9\xc4_\xfb\xe7KCL\x8c_+\x02\x8f\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf0W\xaaf\xcav~\xde\x12J\x1c[\x9c\xc5\xfc\x94\xef\v\x017\x89p\xa2K\u02b6\xf4]\x00\x00\u07d4\xf0[\xa8\u05f6\x859\xd930\v\xc9(\x9c=\x94t\xd0A\x9e\x89\x06\xda'\x02M\xd9`\x00\x00\u07d4\xf0\\\xee\xabeA\x05dp\x99Qw<\x84E\xad\x9fN\u01d7\x89\x10C\x16'\xa0\x93;\x00\x00\xe0\x94\xf0_\xcdL\rs\xaa\x16~US\xc8\xc0\xd6\xd4\xf2\xfa\xa3\x97W\x8a\x02\xd2\xd6l1p\xb2\x98\x00\x00\u07d4\xf0g\xe1\xf1\u0583UjL\xc4\xfd\f\x03\x13#\x9f2\xc4\xcf\u060965\u026d\xc5\u07a0\x00\x00\u07d4\xf0g\xfb\x10\u07f2\x93\u962b\xe5d\xc0U\xe34\x8f\x9f\xbf\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0h\xdf\xe9]\x15\xcd:\u007f\x98\xff\xa6\x88\xb44hB\xbe&\x90\x89D\n\xd8\x19\xe0\x97L\x00\x00\xe0\x94\xf0j\x85J<]\xc3m\x1cI\xf4\xc8}m\xb33\xb5~J\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf0y\xe1\xb1&_P\xe8\u0229\x8e\xc0\u01c1^\xb3\xae\xac\x9e\xb4\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\xe0\x94\xf0{\xd0\xe5\xc2\xcei\xc7\u0127$\xbd&\xbb\xfa\x9d*\x17\xca\x03\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xf0\x83*k\xb2U\x03\xee\xcaC[\xe3\x1b\v\xf9\x05\xca\x1f\xcfW\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf0\x9b>\x87\xf9\x13\xdd\xfdW\xae\x80I\xc71\u06e9\xb66\xdf\u00c9 \xf5\xb1\uab4d\x80\x00\x00\u07d4\xf0\xb14\v\x99oo\v\xf0\xd9V\x1c\x84\x9c\xaf\u007fD0\xbe\xfa\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xb1\xf9\xe2x2\xc6\xdei\x14\xd7\n\xfc#\x8ct\x99\x95\xac\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf0\xb4i\xea\xe8\x9d@\f\xe7\xd5\xd6j\x96\x95\x03p6\xb8\x89\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf0\xb9\u0583\u03a1+\xa6\x00\xba\xac\xe2\x19\xb0\xb3\xc9~\x8c\x00\xe4\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xbe\x0f\xafMy#\xfcDF\"\u0458\f\xf2\u0650\xaa\xb3\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xc0\x81\xdaR\xa9\xae6d*\xdf^\b _\x05\xc5Ah\xa6\x89\x06\x04o7\xe5\x94\\\x00\x00\u07d4\xf0\xc7\r\rm\xabvc\xaa\x9e\xd9\xce\xeaV~\xe2\u01b0'e\x89qC\x8a\u0167\x91\xa0\x80\x00\u07d4\xf0\xcb\xef\x84\xe1ic\x00\x98\xd4\xe3\x01\xb2\x02\b\xef\x05\x84j\u0249\x0e\v\x83EPkN\x00\x00\u07d4\xf0\xd2\x16c\u0630\x17n\x05\xfd\xe1\xb9\x0e\xf3\x1f\x850\xfd\xa9_\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf0\xd5\xc3\x1c\xcbl\xbe0\xc7\xc9\xea\x19\xf2h\xd1Y\x85\x1f\x8c\x9c\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xf0\xd6L\xf9\xdf\tt\x113\xd1pH_\xd2K\x00P\x11\xd5 \x89\x1b\b\x93A\xe1O\xcc\x00\x00\u07d4\xf0\xd8X\x10^\x1bd\x81\x01\xac?\x85\xa0\xf8\"+\xf4\xf8\x1dj\x89 \x86\xac5\x10R`\x00\x00\u07d4\xf0\xdcC\xf2\x05a\x91'P{+\x1c\x1c\xfd\xf3-(1\t \x89\x10^\xb7\x9b\x94\x17\b\x80\x00\u07d4\xf0\xe1\u07e4*\u07ac/\x17\xf6\xfd\xf5\x84\xc9Hb\xfdV3\x93\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf0\xe2d\x9c~j?,]\xfe3\xbb\xfb\xd9'\xca<5\nX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xe7\xfb\x9eB\nS@\xd56\xf4\x04\b4O\xea\xef\xc0j\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf1\x04b\xe5\x8f\xcc\a\U000d5121\x87c\x94Q\x16~\x85\x92\x01\x89\t4\xdd]3\xbc\x97\x00\x00\xe0\x94\xf1\x06a\xff\x94\x14\x0f >zH%rCy8\xbe\xc9\xc3\xf7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xf1\x14\xff\r\x0f$\xef\xf8\x96\xed\xdeTq\u07a4\x84\x82J\x99\xb3\x88\xbe -j\x0e\xda\x00\x00\u07d4\xf1\x16\xb0\xb4h\x0fS\xabr\xc9h\xba\x80.\x10\xaa\x1b\xe1\x1d\u0209\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xf1\x1c\xf5\xd3cto\xeehd\xd3\xca3m\xd8\x06y\xbb\x87\xae\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf1\x1e\x01\u01e9\xd1$\x99\x00_M\xaew\x16\tZ4\x17bw\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf1;\b0\x93\xbaVN-\xc61V\x8c\xf7T\r\x9a\x0e\xc7\x19\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf1O\x0e\xb8m\xb0\xebhu?\x16\x91\x8e]K\x80t7\xbd>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf1Qx\xff\xc4:\xa8\a\x0e\xce2~\x93\x0f\x80\x9a\xb1\xa5O\x9d\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xf1V\xdc\v*\x98\x1e[U\xd3\xf2\xf0;\x814\xe31\u06ed\xb7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf1]\x9dZ!\xb1\x92\x9ey\x03q\xa1\u007f\x16\xd9_\fie\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1^\x18,O\xbb\xady\xbd\x934\"B\xd4\xdc\xcf+\xe5\x89%\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf1bM\x98\ve3o\xea\u0166\xd5A%\x00\\\xfc\xf2\xaa\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1g\xf5\x86\x8d\xcfB3\xa7\x83\x06\th,\xaf-\xf4\xb1\xb8\a\x89\x81\xe5B\xe1\xa78?\x00\x00\u07d4\xf1m\xe1\x89\x1d\x81\x96F\x13\x95\xf9\xb16&[;\x95F\xf6\xef\x89\x01\xb2\x8e\x1f\x98\xbb\u0380\x00\u07d4\xf1z\x92\xe06\x1d\xba\xce\xcd\xc5\xde\r\x18\x94\x95Z\xf6\xa9\xb6\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1z\xdbt\x0fE\u02fd\xe3\tN~\x13qo\x81\x03\xf5c\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x8b\x14\xcb\xf6iC6\xd0\xfe\x12\xac\x1f%\xdf-\xa0\xc0]\xbb\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4\xf1\x9b98\x9dG\xb1\x1b\x8a,?\x1d\xa9\x12M\xec\xff\xbe\xfa\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x9f\x195\b9>M*\x12{ \xb2\x03\x1f9\xc8%\x81\u0189\xbd\xbdz\x83\xbd/l\x00\x00\u07d4\xf1\xa1\xf3 @yd\xfd<\x8f.,\u0224X\r\xa9O\x01\xea\x89ll!wU|D\x00\x00\u07d4\xf1\xb4\xec\xc65%\xf7C,=\x83O\xfe+\x97\x0f\xbe\xb8r\x12\x89\xa2\xa2@h\xfa\u0340\x00\x00\u07d4\U000753ef\xfa\x87\x94\xf5\n\xf8\xe8\x83\t\u01e6&TU\xd5\x1a\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xf1\xc8\u0129A\xb4b\x8c\rl0\xfd\xa5dR\u065c~\x1bd\x89N\x8c\xea\x1e\xdeu\x04\x00\x00\u07d4\xf1\xda@so\x99\xd5\xdf;\x06\x8a]t_\xaf\xc6F?\u0271\x89\x06\x96\xca#\x05\x8d\xa1\x00\x00\u07d4\xf1\u070a\xc8\x10B\xc6z\x9c\\c2!\xa8\xf76>e\x87\f\x9f(t$\u04a9`\x89J\xcfX\xe0rW\x10\x00\x00\u07d4\xf2B\u0684]B\u053fw\x9a\x00\xf2\x95\xb4\aP\xfeI\xea\x13\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2RY\xa5\xc99\xcd%\x96l\x9bc\x03\xd3s\x1cS\u077cL\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf2^Lp\xbcFV2\u021eV%\xa82\xa7r/k\xff\xab\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4\xf2k\xce\xdc\xe3\xfe\xad\u03a3\xbc>\x96\xeb\x10@\xdf\xd8\xff\u1809*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xf2py%v\xf0]QD\x93\xff\xd1\xf5\xe8K\xecK-\xf8\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2s,\xf2\xc1;\x8b\xb8\xe7I*\x98\x8f_\x89\xe3\x82s\xdd\u0209 \x86\xac5\x10R`\x00\x00\xe0\x94\xf2t.hY\xc5i\xd5\xf2\x10\x83Q\xe0\xbfM\xca5*H\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf2\x81:d\xc5&]\x02\x025\u02dc1\x9bl\x96\xf9\x06\xc4\x1e\x89\x12\xf99\u025e\u06b8\x00\x00\u07d4\xf2\x87\xffR\xf4a\x11z\xdb>\x1d\xaaq\x93-\x14\x93\xc6_.\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\xf2\xab\x11au\x02D\xd0\xec\xd0H\xee\r>Q\xab\xb1C\xa2\xfd\x89B\xfe+\x90ss\xbc\x00\x00\u07d4\xf2\xb4\xab,\x94'\xa9\x01^\xf6\xee\xff\xf5\xed\xb6\x019\xb7\x19\u0449&\u06d9*;\x18\x00\x00\x00\u07d4\xf2\xc0>*8\x99\x8c!d\x87`\xf1\xe5\xae~\xa3\a}\x85\"\x89\x8f?q\x93\xab\a\x9c\x00\x00\u0794\xf2\u0090N\x9f\xa6d\xa1\x1e\xe2VV\xd8\xfd,\xc0\u0665\"\xa0\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xf2\xc3b\xb0\xef\x99\x1b\xc8/\xb3nf\xffu\x93*\xe8\u0742%\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\xf2\xd0\xe9\x86\xd8\x14\xea\x13\xc8\xf4f\xa0S\x8cS\u0712&Q\xf0\x89J\xcfX\xe0rW\x10\x00\x00\xe0\x94\xf2\u04775w$\xecL\x03\x18[\x87\x9bc\xf5~&X\x91S\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf2\xd5v<\xe0s\x12~,\xed\xdeo\xab\xa7\x86\xc7<\xa9AA\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\xe0\x94\xf2\u055c\x89#u\x90s\xd6\xf4\x15\xaa\xf8\xeb\x06_\xf2\U000f614a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\xf2\xe9\x9f\\\xbb\x83kz\xd3bGW\x1a0,\xbeKH\x1ci\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf2\xed>w%J\u02c3#\x1d\xc0\x86\x0e\x1a\x11$+\xa6'\u06c9kV\x05\x15\x82\xa9p\x00\x00\xe0\x94\xf2\xed\xde7\xf9\xa8\u00dd\u07a2My\xf4\x01WW\xd0k\xf7\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf2\xef\xe9e`\xc9\xd9{r\xbd6DxC\x88\\\x1d\x90\xc21\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf2\xfb\xb6\u0607\xf8\xb8\xcc:\x86\x9a\xba\x84\u007f=\x1fd\xfcc\x97\xaae\xfbS\xa8\xf0z\x0f\x89:\xae0\xe8\xbc\xee\x89|\xf28\x1fa\x9f\x15\x00\x00\u07d4\xf3@\x83\xec\xea8P\x17\xaa@\xbd\xd3^\xf7\xef\xfbL\xe7v-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf3F\xd7\u0792t\x1c\b\xfcX\xa6M\xb5[\x06-\xde\x01-\x14\x89\x0f\xffk\x1fv\x1em\x00\x00\xe0\x94\xf3U\xd3\xec\f\xfb\x90}\x8d\xbb\x1b\xf3FNE\x81(\x19\v\xac\x8a\x01\v\x04n\u007f\r\x80\x10\x00\x00\u07d4\xf3m\xf0/\xbd\x89`sG\xaf\xce)i\xb9\xc4#jX\xa5\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3s\xe9\u06ac\f\x86u\xf5;yz\x16\x0fo\xc04\xaek#\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3{BeG\xa1d-\x8032H\x14\xf0\xed\xe3\x11O\xc2\x12\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xf3{\xf7\x8cXu\x15G\x11\xcbd\r7\xeam(\xcf\xcb\x12Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf3\x82\xdfX1U\xd8T\x8f?\x93D\f\xd5\xf6\x8c\xb7\x9d`&\x8a8u}\x02\u007f\xc1\xfd\\\x00\x00\xe0\x94\xf3\x82\xe4\xc2\x04\x10\xb9Q\b\x9e\x19\xba\x96\xa2\xfe\xe3\xd9\x1c\xce~\x8a\x01\x11\xfaV\xee\u00a88\x00\x00\xe0\x94\xf3\x8al\xa8\x01hS~\x97M\x14\xe1\xc3\xd19\x90\xa4L,\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xf3\x9a\x9dz\xa3X\x1d\xf0~\xe4'\x9a\xe6\xc3\x12\xef!\x036X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xb6h\xb3\xf1M\x92\x0e\xbc7\x90\x92\u06d8\x03\x1bg\xb2\x19\xb3\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\U000fe679\x10<\xe7U\n\xa7O\xf1\xdb\x18\xe0\x9d\xfe2\xe0\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xc1\xab\u049d\xc5{A\xdc\x19-\x0e8M\x02\x1d\xf0\xb4\xf6\u0509\x97\xae\f\u07cf\x86\xf8\x00\x00\u07d4\xf3\xc4qm\x1e\xe5'\x9a\x86\xd0\x16:\x14a\x81\x81\xe1a6\u01c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf3\u030b\xcbU\x94e\xf8\x1b\xfeX;\u05eb\n#\x06E;\x9e\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf3\u0588\xf0k\xbd\xbfP\xf9\x93,AE\xcb\xe4\x8e\xcd\xf6\x89\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf3\xdb\xcf\x13Z\u02dd\xee\x1aH\x9cY<\x02O\x03\u00bb\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xde_&\xefj\xde\xd6\xf0m;\x91\x13F\xeep@\x1d\xa4\xa0\x89\x13:\xb3}\x9f\x9d\x03\x00\x00\u07d4\xf3\xdfc\xa9q\x99\x93308;>\xd7W\v\x96\u0101#4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xe7OG\f}:?\x003x\x0fv\xa8\x9f>\xf6\x91\xe6\u02c9\xa3\xcf\xe61\xd1Cd\x00\x00\u07d4\xf3\xeb\x19H\xb9Q\xe2-\xf1ax)\xbf;\x8d\x86\x80\xeckh\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xf1\xfa9\x18\xca4\xe2\xcf~\x84g\v\x1fM\x8e\xca\x16\r\xb3\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xf3\xf2O\u009e @?\xc0\xe8\xf5\xeb\xbbU4&\xf7\x82p\xa2\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3\xfar5R\xa5\xd0Q.+b\xf4\x8d\xca{+\x81\x050[\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xf3\xfeQ\xfd\xe3D\x13\xc73\x18\xb9\xc8T7\xfe~\x82\x0fV\x1a\x896b2\\\u044f\xe0\x00\x00\u07d4\xf4\x00\xf9=_\\~?\xc3\x03\x12\x9a\xc8\xfb\f/xd\a\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\v\x13O\xea\"\u01b2\x9c\x84W\xf4\x9f\x00\x0f\x9c\xdax\x9a\u06c9 \x86\xac5\x10R`\x00\x00\u07d4\xf4\x15W\xdf\u07f1\xa1\xbd\xce\xfe\xfe.\xba\x1e!\xfe\nJ\x99B\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\x17z\r\x85\u050b\x0e&B\x11\xce*\xa2\xef\xd3\xf1\xb4\u007f\b\x89\xc2\xcc\xca&\xb7\xe8\x0e\x80\x00\u07d4\xf4/\x90R1\xc7p\xf0\xa4\x06\xf2\xb7h\x87\u007f\xb4\x9e\xee\x0f!\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf42\xb9\u06ef\x11\xbd\xbds\xb6Q\x9f\xc0\xa9\x04\x19\x87q\xaa\u0189\b=lz\xabc`\x00\x00\u07d4\xf4=\xa3\xa4\xe3\xf5\xfa\xb1\x04\u029b\xc1\xa0\xf7\xf3\xbbJV\xf3Q\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf4G\x10\x8b\x98\xdfd\xb5~\x87\x103\x88\\\x1a\xd7\x1d\xb1\xa3\xf9\x8a\x01v\xf4\x9e\xad4\x83P\x80\x00\u07d4\xf4O\x85Q\xac\xe93r\a\x12\xc5\u0111\u0376\xf2\xf9Qsl\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\xf4V\x05Z\x11\xab\x91\xfff\x8e.\xc9\"\x96\x1f*#\xe3\xdb%\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf4V\xa7[\xb9\x96U\xa7A,\xe9}\xa0\x81\x81m\xfd\xb2\xb1\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf4[\x1d\xcb.A\xdc'\xff\xa0$\u06ad\xf6\x19\xc1\x11u\xc0\x87\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xf4c\xa9\f\xb3\xf1>\x1f\x06CB66\xbe\xab\x84\xc1#\xb0m\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf4h\x90n~\xdffJ\xb0\u063e=\x83\xebz\xb3\xf7\xff\xdcx\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xf4i\x80\u3929\u049ajn\x90`E7\xa3\x11K\xcb(\x97\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf4kk\x9c|\xb5R\x82\x9c\x1d=\xfd\x8f\xfb\x11\xaa\xba\xe7\x82\xf6\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xf4v\xe1&\u007f\x86$|\xc9\b\x81o.z\xd58\x8c\x95-\xb0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf4v\xf2\xcbr\b\xa3.\x05\x1f\xd9N\xa8f)\x92c\x82\x87\xa2\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xf4{\xb14\xda0\xa8\x12\xd0\x03\xaf\x8d\u0338\x88\xf4K\xbfW$\x8a\x01\x19Y\xb7\xfe3\x95X\x00\x00\u07d4\xf4\x83\xf6\a\xa2\x1f\xcc(\x10\n\x01\x8cV\x8f\xfb\xe1@8\x04\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf4\x8e\x1f\x13\xf6\xafM\x84\xb3q\xd7\xdeK'=\x03\xa2c'\x8e\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xf4\x9cG\xb3\xef\xd8knj[\xc9A\x8d\x1f\x9f\xec\x81Ki\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xf4\x9fo\x9b\xaa\xbc\x01\x8c\x8f\x8e\x11\x9e\x01\x15\xf4\x91\xfc\x92\xa8\xa4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf4\xa3g\xb1f\u0499\x1a+\xfd\xa9\xf5dc\xa0\x9f%,\x1b\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\xa5\x1f\xceJ\x1d[\x94\xb0q\x83\x89\xbaNx\x14\x13\x9c\xa78\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf4\xa9\xd0\f\xef\xa9{zX\xef\x94\x17\xfcbg\xa5\x06\x909\xee\x89\x01.\x89(\u007f\xa7\x84\x00\x00\u07d4\xf4\xaa\xa3\xa6\x16>7\x06W{I\xc0v~\x94\x8ah\x1e\x16\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\xb1bn$\xf3\v\xca\xd9'!\xb2\x93r\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xf5U\xa2{\xb1\xe2\xfdN,\u01c4\xca\ue493\x9f\xc0n/\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5X\xa2\xb2\xdd&\u0755\x93\xaa\xe0E1\xfd<<\u00c5Kg\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xf5`H\xdd!\x81\u0523od\xfc\xec\xc6!T\x81\xe4*\xbc\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5dB\xf6\x0e!i\x13\x95\u043f\xfa\xa9\x19M\xca\xff\x12\u2dc9\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xf5yqJE\xeb\x8fR\xc3\xd5{\xbd\xef\xd2\xc1[./\x11\u07c9T\x91YV\xc4\t`\x00\x00\u07d4\xf5\x93\xc6R\x85\xeek\xbdf7\U000fe3c9\xad@\u0509\xf6U\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf5\x98\xdb.\t\xa8\xa5\xee}r\r+\\C\xbb\x12m\x11\xec\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf5\x9d\xab\x1b\xf8\xdf\x112~a\xf9\xb7\xa1KV:\x96\xec5T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf5\x9f\x9f\x02\xbb\u024e\xfe\t~\xab\xb7\x82\x10\x97\x90!\x89\x8b\xfd\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\xf5\xa5E\x9f\xcd\xd5\xe5\xb2s\x83\r\xf8\x8e\xeaL\xb7}\xda\u07f9\x89\x04\t\xe5+H6\x9a\x00\x00\u07d4\xf5\xa7gj\xd1H\xae\x9c\x1e\xf8\xb6\xf5\xe5\xa0\xc2\xc4s\xbe\x85\v\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5\xb0h\x98\x9d\xf2\x9c%5w\xd0@Z\xden\x0eu(\xf8\x9e\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xf5\xb6\xe9\x06\x1aN\xb0\x96\x16\aw\xe2gb\xcfH\xbd\u0635]\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xf5\xcf\xfb\xbabN~\xb3!\xbc\x83\xc6\f\xa6\x81\x99\xb4\xe3fq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5\xd1ER\xb1\xdc\xe0\xd6\xdc\x1f2\r\xa6\xff\u02231\xcdo\f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xf5\xd6\x1a\xc4\u0295G^[{\xff\xd5\xf2\xf6\x90\xb3\x16u\x96\x15\x8a\x06\x92\xae\x88\x97\b\x1d\x00\x00\x00\u07d4\xf5\xd9\xcf\x00\xd6X\xddEQzH\xa9\xd3\xf5\xf63T\x1aS=\x89\x06O_\xdfIOx\x00\x00\u07d4\xf5\xea\xdc\xd2\u0478ez\x12\x1f3\xc4X\xa8\xb1>v\xb6U&\x89\r\x8b\x0fZZ\xc2J\x00\x00\u07d4\xf6\a\xc2\x15\r>\x1b\x99\xf2O\xa1\xc7\xd5@\xad\xd3\\N\xbe\x1e\x89\xa7\xf1\xaa\a\xfc\x8f\xaa\x00\x00\u07d4\xf6\v\xd75T>k\xfd.\xa6\xf1\x1b\xffbs@\xbc\x03Z#\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6\f\x1bE\xf1d\xb9X\x0e 'Z\\9\xe1\xd7\x1e5\xf8\x91\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf6\x0fb\xd797\x95?\xef5\x16\x9e\x11\xd8r\xd2\xea1~\xec\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xf6\x12\x83\xb4\xbd\x85\x04\x05\x8c\xa3`\u94d9\x9bb\xcb\xc8\xcdg\x89\r\xd2\xd5\xfc\xf3\xbc\x9c\x00\x00\u07d4\xf6\x17\xb9g\xb9\xbdH_v\x95\xd2\xefQ\xfbw\x92\u0618\xf5\x00\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf6\x18\u0671\x04A\x14\x80\xa8c\xe6#\xfcU#-\x1aOH\xaa\x89\x0eh\x9emD\xb1f\x80\x00\u07d4\xf6\"\u5126b>\xaa\xf9\x9f+\xe4\x9eS\x80\xc5\xcb\xcf\\\u0609\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf62\xad\xffI\r\xa4\xb7-\x126\xd0KQ\x0ft\xd2\xfa\xa3\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4\xf69\xac1\u069fg'\x1b\xd1\x04\x02\xb7eN\\\xe7c\xbdG\x89\x15\xaf\x0fB\xba\xf9&\x00\x00\u07d4\xf6:W\x9b\xc3\xea\u00a9I\x04\x10\x12\x8d\xbc\xeb\xe6\xd9\u0782C\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xf6E\xdd|\x89\x00\x93\xe8\xe4\u022a\x92\xa6\xbb55\"\xd3\u0718\x89\aC\x9f\xa2\t\x9eX\x00\x00\xe0\x94\xf6H\xea\x89\xc2u%q\x01r\x94Ny\xed\xff\x84x\x03\xb7u\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf6JJ\xc8\xd5@\xa9(\x9ch\xd9`\xd5\xfb|\xc4Zw\x83\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6N\xcf!\x17\x93\x1cmSZ1\x1eO\xfe\xae\xf9\u0514\x05\xb8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf6O\xe0\x93\x9a\x8d\x1e\xea*\x0e\u035a\x970\xfdyX\xe31\t\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xf6V\x16\xbe\x9c\x8by~t\x15\"|\x918\xfa\xa0\x89\x17B\u05c9*\xd3s\xcef\x8e\x98\x00\x00\u07d4\xf6W\xfc\xbeh.\xb4\xe8\xdb\x15.\u03c9$V\x00\vQ=\x15\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf6X\x19\xacL\xc1L\x13\u007f\x05\xddyw\xc7\xda\xe0\x8d\x1aJ\xb5\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xf6{\xb8\xe2\x11\x8b\xbc\u0550'fn\xed\xf6\x94>\xc9\xf8\x80\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x84d\xbfd\xf2A\x13V\xe4\xd3%\x0e\xfe\xfe\\P\xa5\xf6[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf6\x86x[\x89r\va\x14_\ua017\x8dj\u030e\v\xc1\x96\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x8c^3\xfa\x97\x13\x9d\xf5\xb2\xe68\x86\xce4\xeb\xf3\u45dc\x89\xb3\xfaAi\xe2\xd8\xe0\x00\x00\u07d4\xf6\xa8cWW\xc5\xe8\xc14\xd2\r\x02\x8c\xf7x\u03c6\t\xe4j\x89O\x1dw/\xae\xc1|\x00\x00\u07d4\xf6\xb7\x82\xf4\xdc\xd7E\xa6\xc0\xe2\xe00`\x0e\x04\xa2K%\xe5B\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xf6\xbc7\xb1\u04a3x\x8dX\x9bm\xe2\x12\xdc\x17\x13\xb2\xf6\u738a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xf6\xc3\u010a\x1a\xc0\xa3G\x99\xf0M\xb8n\u01e9u\xfewh\xf3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf6\xd2]?=\x84m#\x9fR_\xa8\xca\xc9{\xc45x\u06ec\x890\x92\u007ft\xc9\xde\x00\x00\x00\u07d4\xf6\xea\xacp2\u0512\xef\x17\xfd`\x95\xaf\xc1\x1dcOV\xb3\x82\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xf6\xea\xd6}\xbf[~\xb13X\xe1\x0f6\x18\x9dS\xe6C\xcf\u03ca\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf6\xf1\xa4C\t\x05\x1ck%\xe4}\xff\x90\x9b\x17\x9b\xb9\xabY\x1c\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf7\x03(\xef\x97b_\xe7E\xfa\xa4\x9e\xe0\xf9\u052a;\r\xfbi\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\n\x99\x8aq{3\x8d\x1d\u0658T@\x9b\x1a3\x8d\ue930\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\rcz\x84\\\x06\xdbl\u0711\xe67\x1c\xe7\xc48\x8ab\x8e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x15R\x13D\x98\x92tK\xc6\x0f.\x04@\a\x88\xbd\x04\x1f\u0749\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\xe0\x94\xf7\x1bE4\xf2\x86\xe40\x93\xb1\xe1^\xfe\xa7I\xe7Y{\x8bW\x8a\x16\x1c\x13\xd34\x1c\x87(\x00\x00\u07d4\xf74\xec\x03rM\xde\xe5\xbbRy\xaa\x1a\xfc\xf6\x1b\f\xb4H\xa1\x89\xe5\xbf,\u0270\x97\x80\x00\x00\u07d4\xf76\u0716v\x00\x128\x8f\xe8\x8bf\xc0n\xfeW\xe0\xd7\xcf\n\x89q\xd7Z\xb9\xb9 P\x00\x00\u07d4\xf7:\xc4l ;\xe1S\x81\x11\xb1Q\xec\x82 \u01c6\xd8AD\x89\x0f\xf77x\x17\xb8+\x80\x00\u07d4\xf7=\xd9\xc1B\xb7\x1b\xce\x11\xd0n0\xe7\xe7\xd02\xf2\uc71e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf7A\x8a\xa0\xe7\x13\xd2H\"\x87v\xb2\xe7CB\"\xaeu\u3949lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7Nn\x14S\x82\xb4\u06c2\x1f\xe0\xf2\u0643\x88\xf4V\t\u019f\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf7P\f\x16o\x8b\xea/\x824v\x06\xe5\x02K\xe9\xe4\xf4\u0399\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7W\xfc\x87 \xd3\xc4\xfaRw\a^`\xbd\\A\x1a\xeb\xd9w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7[\xb3\x9cy\x97y\xeb\xc0J3m&\r\xa61F\xed\x98\u0409\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xf7h\xf3!\xfdd3\xd9kO5M<\xc1e,\x172\xf5\u007f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf7oi\xce\xe4\xfa\xa0\xa6;0\xae\x1ex\x81\xf4\xf7\x15ep\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf7w6\x1a=\u062bb\xe5\xf1\xb9\xb0GV\x8c\xc0\xb5UpL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7|{\x84QI\xef\xba\x19\xe2a\xbc|u\x15y\b\xaf\xa9\x90\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\u007f\x95\x87\xffz-r\x95\xf1\xf5q\u0206\xbd3\x92jR|\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xf7\x82X\xc1$\x81\xbc\xdd\u06f7*\x8c\xa0\xc0C\tra\xc6\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x98\xd1m\xa4\xe4`\xc4`\xcdH_\xae\x0f\xa0Y\x97\b\ub08965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\xa1\xad\xe2\xd0\xf5)\x12=\x10U\xf1\x9b\x17\x91\x9fV!Ng\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf7\xac\xff\x93K\x84\xda\ti\xdc7\xa8\xfc\xf6C\xb7\xd7\xfb\xedA\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf7\xb1Q\xcc^W\x1c\x17\xc7e9\xdb\xe9\x96L\xbbo\xe5\xdey\x89tq|\xfbh\x83\x10\x00\x00\u07d4\xf7\xb2\x9b\x82\x19\\\x88-\xabx\x97\u00ae\x95\xe7w\x10\xf5xu\x89w5Aa2\xdb\xfc\x00\x00\u07d4\xf7\xbcLD\x91\rZ\xed\xd6n\xd25U8\xa6\xb1\x93\xc3a\xec\x89\x05A\xde,-\x8db\x00\x00\u07d4\xf7\xc0\f\xdb\x1f\x02\x03\x10\u056c\xab{Ij\xaaD\xb7y\b^\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xf7\xc1\xb4C\x96\x8b\x11{]\u0677UW/\xcd9\xca^\xc0K\x89\x18\xb9h\u0092\xf1\xb5\x00\x00\xe0\x94\xf7\xc5\x0f\x92*\xd1ka\xc6\u047a\xa0E\xed\x81h\x15\xba\u010f\x8a\x02\xa99j\x97\x84\xad}\x00\x00\u07d4\xf7\xc7\b\x01Pq\xd4\xfb\n:*\t\xa4]\x15c\x96\xe34\x9e\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf7\xcb\u06e6\xbel\xfeh\xdb\xc2<+\x0f\xf50\xee\x05\"o\x84\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\xd0\xd3\x10\xac\xea\x18@a8\xba\xaa\xbb\xfe\x05q\xe8\r\xe8_\x89Hz\x9a0E9D\x00\x00\u07d4\xf7\u05ef LV\xf3\x1f\xd9C\x98\xe4\r\xf1\x96K\u063f\x12<\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xf7\xdc%\x11\x96\xfb\u02f7|\x94}|\x19F\xb0\xffe\x02\x1c\xea\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf7\xe4Z\x12\xaaq\x1cp\x9a\xce\xfe\x95\xf3;xa-*\xd2*\x8a\x0e\x06U\xe2\xf2k\xc9\x18\x00\x00\u07d4\xf7\xf4\x89\x8cLRm\x95_!\xf0U\xcbnG\xb9\x15\xe5\x19d\x89|\b`\xe5\xa8\r\xc0\x00\x00\u07d4\xf7\xf9\x1ez\xcb[\x81)\xa3\x06\x87|\xe3\x16\x8eoC\x8bf\xa1\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xf7\xfcE\xab\xf7oP\x88\xe2\u5d68\xd12\xf2\x8aMN\xc1\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\x06:\xf4\xcc\x1d\xd9a\x9a\xb5\u063f\xf3\xfc\xd1\xfa\xa8H\x82!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\bnBf\x1e\xa9)\xd2\u0761\xablt\x8c\xe3\x05]\x11\x1e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf8\bw\x86\xb4-\xa0N\xd6\xd1\xe0\xfe&\xf6\xc0\xee\xfe\x1e\x9fZ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf8\r6\x19p/\xa5\x83\x8cH9\x18Y\xa89\xfb\x9c\xe7\x16\x0f\x89l\a\xa7\u0471np\x00\x00\u07d4\xf8\x14y\x9fm\xdfM\xcb)\xc7\xee\x87\x0eu\xf9\xcc-52m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf8\x15\xc1\n\x03-\x13\xc3K\x89v\xfan;\xd2\xc9\x13\x1a\x8b\xa9\x89Hz\x9a0E9D\x00\x00\u07d4\xf8\x16\"\xe5WW\xda\xeafu\x97]\xd958\xda}\x16\x99\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8$\xee3\x1eJ\xc3\xccXv\x939[W\xec\xf6%\xa6\xc0\u0089V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4\xf8'\xd5n\xd2\xd3' \u052b\xf1\x03\xd6\xd0\xefM;\xcdU\x9b\x89\x01l\x80\x06W\x91\xa2\x80\x00\u07d4\xf8)\x85\x91R>P\xb1\x03\xf0\xb7\x01\xd6#\xcb\xf0\xf7EV\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8H\xfc\xe9\xaba\x1c}\x99 n#\xfa\u019a\u0508\xb9O\xe1\x89\x02\xa1\x12\x9d\t6r\x00\x00\u07d4\xf8O\t\n\xdf?\x8d\xb7\u1533P\xfb\xb7u\x00i\x9ff\xfd\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf8Q\xb0\x10\xf63\xc4\n\xf1\xa8\xf0js\ubeabe\az\xb5\x89\xee\x86D/\xcd\x06\xc0\x00\x00\u07d4\xf8X\x17\x1a\x04\xd3W\xa1;IA\xc1n~U\xdd\u0514\x13)\x89\x02F\xa5!\x8f*\x00\x00\x00\u07d4\xf8[\xab\x1c\xb3q\x0f\xc0_\xa1\x9f\xfa\xc2.gR\x1a\v\xa2\x1d\x89l\x955\u007f\xa6\xb3l\x00\x00\u07d4\xf8j>\xa8\a\x1fp\x95\xc7\u06ca\x05\xaePz\x89)\u06f8v\x89\x126\xef\xcb\u02f3@\x00\x00\u07d4\xf8pL\x16\xd2\xfd[\xa3\xa2\xc0\x1d\x0e\xb2\x04\x84\xe6\xec\xfa1\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8p\x99_\xe1\xe5\"2\x1duC7\xa4\\\f\x9d{8\x95\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf8s\xe5ze\xc9;n\x18\xcbu\xf0\xdc\a}[\x893\xdc\\\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf8ua\x9d\x8a#\xe4]\x89\x98\u0444\u0500\xc0t\x89p\x82*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8{\xb0{(\x9d\xf70\x1eT\xc0\xef\xdaj,\xf2\x91\xe8\x92\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u0794\xf8\x89\x00\xdbsyU\xb1Q\x9b\x1a}\x17\n\x18\x86L\xe5\x90\xeb\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf8\x8bX\xdb7B\vFL\v\xe8\x8bE\xee+\x95)\x0f\x8c\xfa\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf8\x96+u\xdb]$\xc7\xe8\xb7\xce\xf1\x06\x8c>g\u03bb0\xa5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xf8\xa0e\xf2\x87\xd9\x1dw\xcdbj\xf3\x8f\xfa\"\r\x9bU*+\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xf8\xa4\x9c\xa29\f\x1fm\\\x0ebQ;\a\x95qt?|\u0189\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf8\xa5\f\xee.h\x8c\xee\u3b24\u0522\x97%\xd4\a,\u0103\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xacJ9\xb5<\x110x \x97;D\x13e\xcf\xfeYof\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xae\x85{g\xa4\xa2\x89:?\xbe|z\x87\xff\x1c\x01\u01a6\xe7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8\xbf\x9c\x04\x87NZw\xf3\x8fL8R~\x80\xc6v\xf7\xb8\x87\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xc7\xf3J8\xb3\x18\x01\xdaC\x064w\xb1+'\xd0\xf2\x03\xff\x89\x1a\u04ba\xbao\xefH\x00\x00\u07d4\xf8\xca3l\x8e\x91\xbd \xe3\x14\xc2\v-\xd4`\x8b\x9c\x8b\x94Y\x89-\u071b\u0173,x\x00\x00\u07d4\xf8\xd1t$\xc7g\xbe\xa3\x12\x05s\x9a+W\xa7'r\x14\uef89\x02F\xdd\xf9yvh\x00\x00\u07d4\xf8\xd5-\xcc_\x96\xcc(\x00{>\u02f4\t\xf7\xe2*dl\xaa\x89\b\x16\x90\xe1\x81(H\x00\x00\u07d4\xf8\xdc\xe8g\xf0\xa3\x9c[\xef\x9e\xeb\xa6\t\"\x9e\xfa\x02g\x8bl\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xf2&\x14*B\x844\xab\x17\xa1\x86J%\x97\xf6J\xab/\x06\x89\tY\x8b/\xb2\xe9\xf2\x80\x00\u07d4\xf8\xf6d^\r\xeedK=\xad\x81\xd5q\uf6ef\x84\x00!\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x01\xc0\x0f\xc1\u06c8\xb6\x9cK\xc3%+\\\xa7\x0e\xa6\xee\\\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9=[\xcb\x06D\xb0\xcc\xe5\xfc\u0763C\xf5\x16\x8f\xfa\xb2\x87}\x89\vb\a\xb6}&\xf9\x00\x00\u07d4\xf9W\x0e\x92L\x95\u07bbpa6\x97\x92\xcf.\xfe\u00a8-^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf9d \x86\xb1\xfb\xaea\xa6\x80M\xbe_\xb1^\xc2\u04b57\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9d\x88i\x85\x90\xdc;,UVB\xb8q4\x8d\xfa\x06z\u0549\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9d\u064d(\x170\xba5\xb2\xe3\xa3\x14yn{B\xfe\xdfg\x89S\xb0\x87`\x98\xd8\f\x00\x00\u07d4\xf9e\ri\x89\xf1\x99\xab\x1c\xc4ycm\xed0\xf2A\x02\x1fe\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xf9h\x83X$Y\x90\x8c\x82v'\xe8o(\xe6F\xf9\xc7\xfcz\x8a\x01\u0127\x877\xcd\u03f8\x00\x00\u07d4\xf9kL\x00voSsj\x85t\xf8\"\xe6GL/!\xda-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9r\x9dH(,\x9e\x87\x16m^\xef-\x01\xed\xa9\xdb\xf7\x88!\x89\x05k\x83\xdd\xc7(T\x80\x00\u07d4\xf9v~N\xcbJY\x80Ru\b\u05fe\xc3\xd4^Ld\x9c\x13\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xf9x\xb0%\xb6B3U\\\xc3\xc1\x9a\xda\u007fA\x99\xc94\x8b\xf7\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4\xf9{V\xeb\u0577z\xbc\x9f\xba\u02eb\u0514\xb9\xd2\xc2!\xcd\x03\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf9\x81\x1f\xa1\x9d\xad\xbf\x02\x9f\x8b\xfeV\x9a\xdb\x18\"\x8c\x80H\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf9\x82Ps\fLa\xc5\u007f\x12\x985\xf2h\b\x94yEB\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xf9\x894gr\x99^\xc1\x90o\xaf\xfe\xba*\u007f\xe7\u079ck\xab\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf9\x98\xca4\x11s\nl\xd1\x0etU\xb0A\x0f\xb0\xf6\xd3\xff\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x9a\xeeDKW\x83\xc0\x93\xcf\xff\xd1\xc4c,\xf9\x90\x9f\xbb\x91\x1d/\x81\x92\xf8B\t\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf9\xbf\xb5\x9dS\x8a\xfcHt\xd4\xf5\x94\x1b\b\xc9s\x0e8\xe2K\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf9\xdd#\x90\b\x18/\xb5\x19\xfb0\xee\xdd \x93\xfe\xd1c\x9b\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9\u07ba\xec\xb5\xf39\xbe\xeaH\x94\xe5 K\xfa4\r\x06\u007f%\x89ZB\x84Fs\xb1d\x00\x00\xe0\x94\xf9\xe3tG@lA!\x97\xb2\u2bbc\x00\x1dn0\u024c`\x8a\x01\xc4y\xbbCI\xc0\xee\x00\x00\u07d4\xf9\xe7\"/\xaa\xf0\xf4\xda@\xc1\u0124\x0607:\t\xbe\u05f6\x89\x9bO\u0730\x94V$\x00\x00\u07d4\xf9\xec\xe0\"\xbc\xcd,\x924i\x11\xe7\x9d\xd5\x03\x03\xc0\x1e\x01\x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfa\x00\xc3v\xe8\x9c\x05\u81c1z\x9d\xd0t\x8d\x96\xf3A\xaa\x89\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xfa\f\x1a\x98\x8c\x8a\x17\xad5(\xeb(\xb3@\x9d\xaaX\"_&\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa\x10_\x1a\x11\xb6\xe4\xb1\xf5`\x12\xa2y\"\xe2\xac-\xa4\x81/\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfa\x14/\xe4~\u0697\xe6P;8k\x18\xa2\xbe\xdds\u0335\xb1\x89.\x15:\xd8\x15H\x10\x00\x00\u07d4\xfa\x14\xb5f#J\xbe\xe70B\xc3\x1d!qq\x82\u02e1J\xa1\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\xfa\x19\xd6\xf7\xa5\x0fO\a\x98\x93\xd1g\xbf\x14\xe2\x1d\x00s\u0456\x89\x1c\xbb:?\xf0\x8d\b\x00\x00\u07d4\xfa\x1f\x19q\xa7u\xc3PO\xefPy\xf6@\xc2\u013c\xe7\xac\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfa'\x9b\xfd\x87g\xf9V\xbf\u007f\xa0\xbdV`\x16\x8d\xa7V\x86\xbd\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xfa'\xccI\xd0\vl\x98s6\xa8u\xae9\xdaX\xfb\x04\x1b.\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfa(2\x99`=\x87X\xe8\u02b0\x82\x12],\x8f}DT)\x8a\x01[\xca\xcb\x1e\x05\x01\xae\x80\x00\u07d4\xfa+\xbc\xa1]?\u37ca2\x8e\x91\xf9\r\xa1Oz\xc6%=\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa/\u049d\x03\xfe\xe9\xa0x\x93\xdf:&\x9fV\xb7/.\x1ed\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfa3U2\x85\xa9sq\x9a\r_\x95o\xf8a\xb2\u061e\xd3\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\fK\x90?n\xa5.\xa7\xab{\x88c\xb6\xa6\x16\xadfP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\x1a\xa4H\x8b5\x1a\xa7V\f\xf5\xeec\n/\xd4\\2\"\x89/\xa4~j\xa74\r\x00\x00\u07d4\xfaA\tq\xad\"\x9c06\xf4\x1a\u03c5/*\u0259(\x19P\x89\u0633\x11\xa8\xdd\xfa|\x00\x00\u07d4\xfaD\xa8U\xe4\x04\xc8m\f\xa8\xef3$%\x1d\xfb4\x9cS\x9e\x89T\"S\xa1&\xce@\x00\x00\xe0\x94\xfaR\x01\xfe\x13B\xaf\x110{\x91B\xa0A$<\xa9./\t\x8a 8\x11j:\xc0C\x98\x00\x00\xe0\x94\xfa`\x86\x8a\xaf\xd4\xffL\\W\x91K\x8e\u054bBWs\u07e9\x8a\x01\xcf\xe5\xc8\b\xf3\x9f\xbc\x00\x00\u07d4\xfag\xb6{O7\xa0\x15\t\x15\x11\x0e\xde\a;\x05\xb8S\xbd\xa2\x89#\x19\xba\x94sq\xad\x00\x00\u07d4\xfah\xe0\xcb>\xdfQ\xf0\xa6\xf2\x11\u0272\xcb^\a<\x9b\xff\xe6\x89\x0f\xc969(\x01\xc0\x00\x00\xe0\x94\xfaj7\xf0\x18\xe9yg\x93\u007f\xc5\xe8a{\xa1\u05c6\xdd_w\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xfav\x06C[5l\xee%{\xd2\xfc\xd3\xd9\xea\xcb<\xd1\xc4\xe1\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfaz\xdff\v\x8d\x99\xce\x15\x93=|_\a/<\xbe\xb9\x9d3\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfa\x86\xca'\xbf(T\u0648p\x83\u007f\xb6\xf6\xdf\xe4\xbfdS\xfc\x89\x11u~\x85%\xcf\x14\x80\x00\u07d4\xfa\x8c\xf4\xe6'i\x8c]W\x88\xab\xb7\x88\x04\x17\xe7P#\x13\x99\x89\xe6\x1a6\x96\xee\xf6\x10\x00\x00\u07d4\xfa\x8e;\x1f\x13C9\x00s}\xaa\xf1\xf6)\x9cH\x87\xf8[_\x89&\u009eG\u0104L\x00\x00\u07d4\xfa\x9e\xc8\xef\xe0\x86\x86\xfaX\xc1\x813Xr\xbai\x85`\ucac9lj\xccg\u05f1\xd4\x00\x00\u07d4\xfa\xad\x90]\x84|{#A\x8a\xee\xcb\xe3\xad\u06cd\xd3\xf8\x92J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xfa\xae\xba\x8f\xc0\xbb\xdaU<\xa7.0\xef=s.&\xe8 A\x89H\x8d(*\xaf\xc9\xf6\x80\x00\u07d4\xfa\xb4\x87P\r\xf2\x0f\xb8>\xbe\xd9\x16y\x1dV\x17r\xad\xbe\xbf\x89lkLM\xa6\u077e\x00\x00\u07d4\xfa\xc5\u0294u\x80x\xfb\xfc\xcd\x19\xdb5X\xda~\u8827h\x897(\xa6+\r\xcf\xf6\x00\x00\u07d4\xfa\xd9j\xb6\xacv\x8a\xd5\t\x94R\xacGw\xbd\x1aG\xed\u010f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfa\xe7g\x19\xd9~\xacA\x87\x04(\xe9@'\x9d\x97\xddW\xb2\xf6\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xfa\u8053pG\x89Zf\f\xf2)v\x0f'\xe6h(\xd6C\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xfa\xe9,\x13p\xe9\u115a]\xf8;V\xd0\xf5\x86\xaa;@L\x89\x05\u0174\xf3\xd8C\x98\x00\x00\xe0\x94\xfa\xf5\xf0\xb7\xb6\xd5X\xf5\t\r\x9e\xa1\xfb-B%\x9cX`x\x8a\x01Z\xff\xb8B\fkd\x00\x00\xe0\x94\xfb\x12o\x0e\xc7i\xf4\x9d\xce\xfc\xa2\xf2\x00(dQX0\x84\xb8\x8a\x01\x0f\xcb\xc25\x03\x96\xbf\x00\x00\xe0\x94\xfb\x13^\xb1Z\x8b\xacr\xb6\x99\x154*`\xbb\xc0k~\a|\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\"<\x1e\"\xea\xc1&\x9b2\xee\x15jS\x85\x92.\xd3o\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb7\xcfkO\x81\xa9\xe2\"\xfb\xa2.\x9b\xd2KP\x98\xb73\u03c9\x02\x1auJm\xc5(\x00\x00\u07d4\xfb8`\xf4\x12\x1cC.\xbd\xc8\xecj\x031\xb1\xb7\ty.\x90\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\xfb9\x18\x9a\xf8v\xe7b\xc7\x1dl>t\x18\x93\xdf\"l\xed\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfb:\v\rkjq\x8fo\xc0)*\x82]\xc9$z\x90\xa5\u0409\n\xd6\xdd\x19\x9e\x97[\x00\x00\xe0\x94\xfb?\xa1\xac\b\xab\xa9\xcc;\xf0\xfe\x9dH8 h\x8fe\xb4\x10\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xfb?\xe0\x9b\xb86\x86\x15)\xd7Q\x8d\xa2v5\xf58PV\x15\x89K\xe3\x92\x16\xfd\xa0p\x00\x00\xe0\x94\xfbQ%\xbf\x0f^\xb0\xb6\xf0 \xe5k\xfc/\xdf=@,\t~\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfbU\x18qL\xef\xc3m\x04\x86]\xe5\x91^\xf0\xffG\xdf\xe7C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb_\xfa\xa0\xf7aW&5x\x91GX\x18\x93\x9d 7\u03d6\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfbh\\\x15\xe49\x96^\xf6&\xbf\r\x83L\u0468\x9f+V\x95\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xfbtK\x95\x1d\tK1\x02b\xc8\xf9\x86\xc8`\u07da\xb1\xdee\x89\x02\xd1\xc5\x15\xf1\xcbJ\x80\x00\u07d4\xfby\xab\u06d2\\U\xb9\xf9\x8e\xfe\xefd\xcf\xc9\xeba\xf5\x1b\xb1\x89a@\xc0V\xfb\n\xc8\x00\x00\u07d4\xfb\x81\x13\xf9M\x91s\xee\xfdZ0s\xf5\x16\x80:\x10\xb2\x86\xae\x89\x04V9\x18$O@\x00\x00\u07d4\xfb\x84,\xa2\xc5\xef\x139\x17\xa26\xa0\u052c@i\x01\x10\xb08\x89\x10\x96\x9ab\xbe\x15\x88\x00\x00\u07d4\xfb\x91\xfb\x1aiUS\xf0\u018e!'m\xec\xf0\xb89\t\xb8m\x89\x05l\x006\x17\xafx\x00\x00\u07d4\xfb\x94s\xcfw\x125\n\x1f\xa09Rs\xfc\x80V\aR\xe4\xfb\x89\x06\xaf!\x98\xba\x85\xaa\x00\x00\xe0\x94\xfb\x94\x9cd\u007f\xdc\xfd%\x14\xc7\u054e1\xf2\x8aS-\x8cX3\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\xa5HmS\xc6\xe2@IBA\xab\xf8~C\xc7`\rA:\x89k\xbfaIIH4\x00\x00\u07d4\xfb\xb1a\xfe\x87_\t)\nK&+\xc6\x01\x10\x84\x8f\r\"&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb\xbb\xeb\u03fe#^W\xdd#\x06\xad\x1a\x9e\u0141\xc7\xf9\xf4\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfb\xc0\x1d\xb5NG\xcd\xc3\xc48iJ\xb7\x17\xa8V\xc2?\xe6\xe9\x8a\x01\xcaqP\xab\x17OG\x00\x00\xe0\x94\xfb\xcf\xccJ{\x0f&\xcf&\xe9\xf33!2\xe2\xfcj#\af\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfb\xe7\x16\"\xbc\xbd1\xc1\xa3iv\xe7\xe5\xf6p\xc0\u007f\xfe\x16\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfb\xed\xe3,4\x9f3\x00\xefL\xd3;M\xe7\xdc\x18\xe4C\xd3&\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xfb\xf2\x04\xc8\x13\xf86\xd89b\u01c7\fx\b\xca4\u007f\xd3>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfb\xf7Y3\xe0\x1bu\xb1T\xef\x06i\ak\xe8\u007fb\xdf\xfa\xe1\x8a\x10\x84cr\xf2I\xd4\xc0\x00\x00\u07d4\xfc\x00\x96\xb2\x1e\x95\xac\xb8\xd6\x19\xd1v\xa4\xa1\xd8\xd5)\xba\xdb\xef\x89\x14\xd9i;\xcb\xec\x02\x80\x00\xe0\x94\xfc\x00\xa4 \xa3a\a\xdf\xd5\xf4\x95\x12\x8a_\u5af2\xdb\x0f4\x8a\x01C\x17\x9d\x86\x91\x10 \x00\x00\xe0\x94\xfc\x01\x8ai\n\xd6tm\xbe:\u03d7\x12\xdd\xcaR\xb6%\x009\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfc\x02s@3\xe5\u007fpQ~\n\xfc~\xe6$a\xf0o\xad\x8e\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfc\x0e\xe6\xf7\u00b3qJ\xe9\x91lEVf\x05\xb6V\xf3$A\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xfc\x10\xb7\xa6{2h\xd53\x1b\xfbj\x14\xde\xf5\xeaJ\x16,\xa3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfc\x15\u02d9\xa8\xd1\x03\v\x12w\n\xdd\x03:y\xee\r\f\x90\x8c\x89\x12\xfa\x00\xbdR\xe6$\x00\x00\u07d4\xfc)R\xb4\u011f\xed\u043c\x05(\xa3\bI^mj\x1cq\u0589lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc,\x1f\x88\x96\x1d\x01\x9c>\x9e\xa30\t\x15.\x06\x93\xfb\xf8\x8a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xfc6\x11\x05\u0750\xf9\xed\xe5fI\x9di\xe9\x13\x03\x95\xf1*\u020aS\xa4\xfe/ N\x80\xe0\x00\x00\u07d4\xfc7/\xf6\x92|\xb3\x96\xd9\xcf)\x805\x00\x11\r\xa62\xbcR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc9\xbeA\tK\x19\x97\xd2\x16\x9e\x82d\xc2\u00fa\xa6\u025b\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc=\"k\xb3jX\xf5&V\x88W\xb0\xbb\x12\xd1\t\xec\x93\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfcC\x82\x9a\u01c7\xff\x88\xaa\xf1\x83\xba5*\xad\xbfZ\x15\xb1\x93\x89\u05ac\n+\x05R\xe0\x00\x00\u07d4\xfcI\xc1C\x9aA\u05b3\xcf&\xbbg\xe06R$\xe5\xe3\x8f_\x8966\u05ef^\u024e\x00\x00\u07d4\xfcU\x00\x82Q\x05\xcfq*1\x8a^\x9c;\xfci\u021d\f\x12\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xfcf\xfa\xba'\u007fK]\xe6J\xd4^\xb1\x9c1\xe0\f\xed>\u054a\x011\xbe\xb9%\xff\xd3 \x00\x00\xe0\x94\xfc~\"\xa5\x03\xecZ\xbe\x9b\b\xc5\v\xd1I\x99\xf5 \xfaH\x84\x8a\x01ZG}\xfb\xe1\xea\x14\x80\x00\u07d4\xfc\x82\x15\xa0\xa6\x99\x13\xf6*C\xbf\x1c\x85\x90\xb9\xdd\xcd\r\x8d\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc\x98\x9c\xb4\x87\xbf\x1a}\x17\xe4\xc1\xb7\u0137\xaa\xfd\xdak\n\x8d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfc\x9b4td\xb2\xf9\x92\x9d\x80~\x03\x9d\xaeH\xd3\u064d\xe3y\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xfc\xa4;\xbc#\xa0\xd3!\xba\x9eF\xb9)s\\\xe7\xd8\xef\f\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfc\xa7>\xff\x87q\xc0\x10;\xa3\xcc\x1a\x9c%\x94H\xc7*\xbf\v\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xad\xa3\x00(?k\xcc\x13J\x91Eg`\xb0\xd7}\xe4\x10\xe0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc\xbc\\q\xac\xe7\x97AE\v\x01,\xf6\xb8\xd3\xf1}\xb6\x8ap\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfc\xbd\x85\xfe\xeajuO\xcf4ID\x9e7\xff\x97\x84\xf7w<\x89\xa7J\xdai\xab\xd7x\x00\x00\xe0\x94\xfc\xc9\u0524&.z\x02z\xb7Q\x91\x10\xd8\x02\u0115\xce\xea9\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\xfc\xcd\r\x1e\xce\xe2z\xdd\xea\x95\xf6\x85z\xee\xc8\u01e0K(\xee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfc\u0434\x82|\xd2\b\xff\xbf^u\x9d\xba\x8c<\xc6\x1d\x8c,<\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfc\xe0\x89c\\\xe9z\xba\xc0kD\x81\x9b\xe5\xbb\n>.\v7\x89\x05\x03\x92\nv0\xa7\x80\x00\u07d4\xfc\xf1\x99\xf8\xb8T\"/\x18.N\x1d\t\x9dN2>*\xae\x01\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xfc:P\x04\xd6xa?\v6\xa6B&\x9a\u007f7\x1c?j\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x19\x1a5\x15}x\x13s\xfbA\x1b\xf9\xf2R\x90\x04|^\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x1f\xaa4{\x0f\u0300L-\xa8l6\xd5\xf1\u044bp\x87\xbb\x89\x02\xd6\xeb$z\x96\xf6\x00\x00\u07d4\xfd\x1f\xb5\xa8\x9a\x89\xa7!\xb8yph\xfb\xc4\u007f>\x9dR\xe1I\x89\f\u0435\x83\u007f\xc6X\x00\x00\u07d4\xfd OOJ\xba%%\xbar\x8a\xfd\xf7\x87\x92\xcb\u07b75\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd'W\xcc5Q\xa0\x95\x87\x8d\x97\x87V\x15\xfe\fj2\xaa\x8a\x89 m\xb1R\x99\xbe\xac\x00\x00\u07d4\xfd(r\u045eW\x85<\xfa\x16\xef\xfe\x93\u0431\xd4{O\x93\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd))'\x1e\x9d \x95\xa2dv~{\r\xf5.\xa0\xd1\xd4\x00\x89\xa2\xa1\xeb%\x1bZ\xe4\x00\x00\u07d4\xfd7z8Rr\x90\f\xb46\xa3\xbbyb\xcd\xff\xe9?]\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd@$+\xb3Jp\x85^\xf0\xfd\x90\xf3\x80-\xec!6\xb3'\x89h\xa8u\a>)$\x00\x00\xe0\x94\xfdE,9i\xec\xe3\x80\x1cT \xf1\xcd\u02a1\xc7\x1e\xd2=\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xfdKU\x1fo\xdb\u0366\xc5\x11\xb5\xbb7\"P\xa6\xb7\x83\xe54\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xfdK\x98\x95X\xae\x11\xbe\f;6\xe2\xd6\xf2\xa5J\x93C\xca.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfdM\xe8\xe3t\x8a(\x9c\xf7\xd0`Q}\x9d88\x8d\xb0\x1f\xb8\x89\r\x8drkqw\xa8\x00\x00\u07d4\xfdZc\x15\u007f\x91O\u04d8\uac5c\x13}\xd9U\v\xb7q\\\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xfd`\u04b5\xaf=5\xf7\xaa\xf0\u00d3\x05.y\xc4\xd8#\u0645\x89\x03\x0e\xb5\r.\x14\b\x00\x00\u07d4\xfdhm\xe5?\xa9\u007f\x99c\x9e%hT\x97 \xbcX\x8c\x9e\xfc\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xfd~\u078fR@\xa0eA\xebi\x9dx,/\x9a\xfb!p\xf6\x89Hz\x9a0E9D\x00\x00\u07d4\xfd\x81+\u019f\xb1p\xefW\xe22~\x80\xaf\xfd\x14\xf8\xe4\xb6\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\x88\xd1\x14\"\x0f\b\x1c\xb3\xd5\xe1[\xe8\x15*\xb0sfWj\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xfd\x91\x856\xa8\xef\xa6\xf6\xce\xfe\x1f\xa1\x159\x95\xfe\xf5\xe3=;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfd\x92\x0fr&\x82\xaf\xb5\xafE\x1b\x05D\xd4\xf4\x1b;\x9dWB\x89~R\x05j\x12?<\x00\x00\u07d4\xfd\x95y\xf1\x19\xbb\xc8\x19\xa0+a\u3348\x03\xc9B\xf2M2\x89\x05\xb9~\x90\x81\xd9@\x00\x00\u07d4\xfd\xa0\xce\x153\a\a\xf1\v\xce2\x01\x17- \x18\xb9\xdd\xeat\x89\x02\xd0A\xd7\x05\xa2\xc6\x00\x00\xe0\x94\xfd\xa3\x04(\x19\xaf>f)\x00\xe1\xb9+CX\xed\xa6\xe9%\x90\x8a\x19\a\xa2\x84\u054fc\xe0\x00\x00\u07d4\xfd\xa6\x81\x0e\xa5\xac\x98]o\xfb\xf1\xc5\x11\xf1\xc1B\xed\xcf\xdd\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd\xb39D\xf26\x06\x15\xe5\xbe#\x95w\u0221\x9b\xa5-\x98\x87\x89 \x9d\x92/RY\xc5\x00\x00\u07d4\xfd\xbaSY\xf7\xec;\xc7p\xacI\x97]\x84N\xc9qbV\xf1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xfd\xc4\xd4vZ\x94/[\xf9i1\xa9\xe8\xccz\xb8\xb7W\xffL\x8a\x12lG\x8a\x0e>\xa8`\x00\x00\xe0\x94\xfd\xcd]\x80\xb1\x05\x89zW\xab\xc4xev\x8b)\x00RB\x95\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794\xfd\xd1\x19_y}O5q}\x15\xe6\xf9\x81\n\x9a?\xf5T`\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xfd\xd5\x02\xa7N\x81;\u03e3U\xce\xda<\x17ojhq\xaf\u007f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfd\u357c\vm\\\xbbL\x1d\x8f\xea>\vK\xffc^\x9d\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xea\xac*\xcf\x1d\x13\x8e\x19\xf2\xfc?\x9f\xb7E\x92\xe3\ud04a\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xfd\xec\xc8-\xdf\xc5a\x92\xe2oV<=h\xcbTJ\x96\xbf\xed\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\xfd\xf4#C\x01\x9b\v\fk\xf2`\xb1s\xaf\xab~E\xb9\xd6!\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xfd\xf4I\xf1\b\xc6\xfbOZ+\b\x1e\xed~E\u645eM%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xfda4\xc0J\x8a\xb7\xeb\x16\xf0\x06C\xf8\xfe\xd7\u06aa\ucc89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfe\x00\xbfC\x99\x11\xa5S\x98-\xb68\x03\x92E\xbc\xf02\xdb\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfe\x01n\xc1~\xc5\xf1\x0e;\xb9\x8f\xf4\xa1\xed\xa0E\x15v\x82\xab\x89\x14_T\x02\xe7\xb2\xe6\x00\x00\u07d4\xfe\x0e0\xe2\x14)\rt=\xd3\x0e\xb0\x82\xf1\xf0\xa5\"Z\xdea\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe!\v\x8f\x04\xdcmOv!j\xcf\xcb\u055b\xa8;\xe9\xb60\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\"\xa0\xb3\x88f\x8d\x1a\xe2d>w\x1d\xac\xf3\x8aCB#\u0309\xd8\xdb^\xbd{&8\x00\x00\u07d4\xfe6&\x88\x84_\xa2D\u0300~K\x110\xeb7A\xa8\x05\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe8'\xd5v0\u03c7a\xd5\x12y{\v\x85\x8eG\x8b\xbd\x12\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfeA\x8bB\x1a\x9cm76\x02y\x04u\xd20>\x11\xa7Y0\x897\b\xba\xed=h\x90\x00\x00\u07d4\xfeBI\x12yP\xe2\xf8\x96\xec\x0e~.=\x05Z\xab\x10U\x0f\x89$=M\x18\"\x9c\xa2\x00\x00\xe0\x94\xfeM\x84\x03!o\xd5qW+\xf1\xbd\xb0\x1d\x00W\x89x\u0588\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xfeS\xb9I\x89\u0619d\xda aS\x95&\xbb\xe9y\xdd.\xa9\x89h\xa8u\a>)$\x00\x00\u07d4\xfeT\x9b\xbf\xe6G@\x18\x98\x92\x93%8\u06afF\u04b6\x1dO\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfea]\x97\\\b\x87\xe0\xc9\x11>\xc7)\x84 \xa7\x93\xaf\x8b\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfee\xc4\x18\x8dy\"Wi\td D\xfd\xc5#\x95V\x01e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfei\u007f\xf2,\xa5G\xbf\xc9^3\xd9`\xda`\\gc\xf3[\x89G\xd4\x11\x9f\xd9`\x94\x00\x00\u07d4\xfej\x89[y\\\xb4\xbf\x85\x90=<\xe0\x9cZ\xa49S\u04ff\x89\xb8Pz\x82\a( \x00\x00\u07d4\xfeo_B\xb6\x19;\x1a\xd1b\x06\u4bf5#\x9dM}\xb4^\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xfep\x11\xb6\x98\xbf3q\x13-tE\xb1\x9e\xb5\xb0\x945j\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x80\xe9#-\xea\xff\x19\xba\xf9\x98i\x88:K\xdf\x00\x04\xe5<\x89.b\xf2\ni\xbe@\x00\x00\u07d4\xfe\x8en6eW\r\xffz\x1b\xdaiz\xa5\x89\xc0\xb4\xe9\x02J\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x8f\x1f\u072b\u007f\xbe\u0266\xa3\xfc\xc5\aa\x96\x00P\\6\xa3\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xfe\x91\xec\xcf+\xd5f\xaf\xa1\x16\x96\xc5\x04\x9f\xa8Lic\nR\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xfe\x96\xc4\xcd8\x15b@\x1a\xa3*\x86\xe6[\x9dR\xfa\x8a\xee'\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\xfe\x98\xc6d\xc3\xe4G\xa9^i\xbdX!q\xb7\x17n\xa2\xa6\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfe\x9a\xd1.\xf0]m\x90&\x1f\x96\xc84\n\x03\x81\x97M\xf4w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x9c\x0f\xff\xef\xb8\x03\b\x12V\xc0\xcfMfY\xe6\xd3>\xb4\xfb\x89R\xd5B\x80O\x1c\xe0\x00\x00\u07d4\xfe\x9c\xfc;\xb2\x93\u0772\x85\xe6%\xf3X/t\xa6\xb0\xa5\xa6\u0349j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xfe\x9e\x11\x97\u05d7JvH\xdc\u01e01\x12\xa8\x8e\xdb\xc9\x04]\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94\xfe\xac\xa2\xactbK\xf3H\xda\u0258QC\xcf\xd6R\xa4\xbeU\x8a\x05\x89\u007f\u02f0)\x14\b\x80\x00\u07d4\xfe\xad\x18\x03\xe5\xe77\xa6\x8e\x18G-\x9a\xc7\x15\xf0\x99L\u00be\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfe\xb8\xb8\xe2\xafqj\xe4\x1f\xc7\xc0K\xcf)T\x01VF\x1ek\x89TQt\xa5(\xa7z\x00\x00\u07d4\xfe\xb9-0\xbf\x01\xff\x9a\x19\x01flUsS+\xfa\a\xee\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe\xbc1s\xbc\x90r\x13cT\x00+{O\xb3\xbf\xc5?\"\xf1\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xfe\xbdH\xd0\xff\xdb\xd5el\xd5\xe6\x866:a\x14R(\xf2y\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xfe\xbd\x9f\x81\xcfx\xbd_\xb6\u0139\xa2K\xd4\x14\xbb\x9b\xfaLN\x89k\xe1\x0f\xb8\xedn\x13\x80\x00\u07d4\xfe\xc0o\xe2{D\u01c4\xb29n\xc9/{\x92:\xd1~\x90w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\xc1NT\x85\xde+>\xef^t\xc4aF\u06ceEN\x035\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\xfe\xd8Gm\x10\u0544\xb3\x8b\xfag7`\x0e\xf1\x9d5\xc4\x1e\u0609b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xfe\xef;n\xab\xc9J\xff\xd31\f\x1cM\x0ee7^\x13\x11\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\xf0\x9dp$?9\xed\x8c\xd8\x00\xbf\x96QG\x9e\x8fJ\xca<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe\xf3\xb3\u07ad\x1ai&\u051a\xa3+\x12\xc2*\xf5M\x9f\xf9\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xff\v|\xb7\x1d\xa9\xd4\xc1\xean\xcc(\xeb\xdaPLc\xf8/\u04498\x8a\x88]\xf2\xfcl\x00\x00\u07d4\xff\f\xc6\u73c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xff'&)AH\xb8lx\xa97$\x97\xe4Y\x89\x8e\xd3\xfe\xe3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xff=\xedz@\u04ef\xf0\u05e8\xc4_\xa6\x13j\xa0C=\xb4W\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xff>\xeeW\xc3Mm\xae\x97\r\x8b1\x11\x17\xc55\x86\xcd5\x02\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xff>\xf6\xba\x15\x1c!\xb5\x99\x86\xaed\xf6\xe8\"\x8b\u0262\xc73\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xffA\xd9\xe1\xb4\xef\xfe\x18\u0630\xd1\xf6?\xc4%_\xb4\xe0l=\x89Hz\x9a0E9D\x00\x00\u07d4\xffE\xcb4\xc9(6M\x9c\xc9\u063b\x0074ta\x8f\x06\xf3\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xffI\xa7u\x81N\xc0\x00Q\xa7\x95\xa8u\xde$Y.\xa4\x00\u050a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xffJ@\x8fP\xe9\xe7!F\xa2\x8c\xe4\xfc\x8d\x90'\x1f\x11n\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xffM\x9c\x84\x84\xc4\x10T\x89H\xa4\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\x7f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94\v\xe9I\x92\x8f\xf1\x99\xc9\xeb\xa9\xe1\x10\xdb!\n\xa5\xc9N\xfa\u040b|\x13\xbcK,\x13\x8e\u0344h\xa0\x03\x7f\x05\x8a\x9d\xaf\xady\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xf9!2\x94BBBBBBBBBBBBBBBBBBBB\x80\xf9!\x19\x80\xb9\x18\xd6`\x80`@R`\x046\x10a\x00?W`\x005`\xe0\x1c\x80c\x01\xff\u0267\x14a\x00DW\x80c\"\x89Q\x18\x14a\x00\xa4W\x80cb\x1f\xd10\x14a\x01\xbaW\x80c\xc5\xf2\x89/\x14a\x02DW[`\x00\x80\xfd[4\x80\x15a\x00PW`\x00\x80\xfd[Pa\x00\x90`\x04\x806\x03` \x81\x10\x15a\x00gW`\x00\x80\xfd[P5\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16a\x02kV[`@\x80Q\x91\x15\x15\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[a\x01\xb8`\x04\x806\x03`\x80\x81\x10\x15a\x00\xbaW`\x00\x80\xfd[\x81\x01\x90` \x81\x01\x815d\x01\x00\x00\x00\x00\x81\x11\x15a\x00\xd5W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x00\xe7W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\tW`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01'W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x019W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01[W`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01yW`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x01\x8bW`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\xadW`\x00\x80\xfd[\x91\x93P\x91P5a\x03\x04V[\x00[4\x80\x15a\x01\xc6W`\x00\x80\xfd[Pa\x01\xcfa\x10\xb5V[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x01\x90\x80\x83\x83`\x00[\x83\x81\x10\x15a\x02\tW\x81\x81\x01Q\x83\x82\x01R` \x01a\x01\xf1V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x026W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xf3[4\x80\x15a\x02PW`\x00\x80\xfd[Pa\x02Ya\x10\xc7V[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[`\x00\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x01\xff\u0267\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x80a\x02\xfeWP\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x85d\t\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14[\x92\x91PPV[`0\x86\x14a\x03]W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18\x05`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x84\x14a\x03\xb6W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`6\x81R` \x01\x80a\x17\x9c`6\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``\x82\x14a\x04\x0fW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`)\x81R` \x01\x80a\x18x`)\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[g\r\u0db3\xa7d\x00\x004\x10\x15a\x04pW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18R`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x06\x15a\x04\xcdW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`3\x81R` \x01\x80a\x17\xd2`3\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x04g\xff\xff\xff\xff\xff\xff\xff\xff\x81\x11\x15a\x055W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80a\x18+`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``a\x05@\x82a\x14\xbaV[\x90P\x7fd\x9b\xbcb\xd0\xe3\x13B\xaf\xeaN\\\xd8-@I\xe7\xe1\xee\x91/\xc0\x88\x9a\xa7\x90\x80;\xe3\x908\u0149\x89\x89\x89\x85\x8a\x8aa\x05u` Ta\x14\xbaV[`@\x80Q`\xa0\x80\x82R\x81\x01\x89\x90R\x90\x81\x90` \x82\x01\x90\x82\x01``\x83\x01`\x80\x84\x01`\xc0\x85\x01\x8e\x8e\x80\x82\x847`\x00\x83\x82\x01R`\x1f\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x91\x01\x87\x81\x03\x86R\x8c\x81R` \x01\x90P\x8c\x8c\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x86R\x8cQ\x81R\x8cQ` \x91\x82\x01\x93\x91\x8e\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06HW\x81\x81\x01Q\x83\x82\x01R` \x01a\x060V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x06uW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x86\x81\x03\x83R\x88\x81R` \x01\x89\x89\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x84R\x89Q\x81R\x89Q` \x91\x82\x01\x93\x91\x8b\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06\xefW\x81\x81\x01Q\x83\x82\x01R` \x01a\x06\xd7V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\a\x1cW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x9dPPPPPPPPPPPPPP`@Q\x80\x91\x03\x90\xa1`\x00`\x02\x8a\x8a`\x00`\x80\x1b`@Q` \x01\x80\x84\x84\x80\x82\x847\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x94\x16\x91\x90\x93\x01\x90\x81R`@\x80Q\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x81\x84\x03\x01\x81R`\x10\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92P` \x85\x01\x91P\x80\x83\x83[` \x83\x10a\a\xfcW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\a\xbfV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\bYW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\bnW`\x00\x80\xfd[PQ\x90P`\x00`\x02\x80a\b\x84`@\x84\x8a\x8ca\x16\xfeV[`@Q` \x01\x80\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\b\xf8W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\b\xbbV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\tUW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\tjW`\x00\x80\xfd[PQ`\x02a\t{\x89`@\x81\x8da\x16\xfeV[`@Q`\x00\x90` \x01\x80\x84\x84\x80\x82\x847\x91\x90\x91\x01\x92\x83RPP`@\x80Q\x80\x83\x03\x81R` \x92\x83\x01\x91\x82\x90R\x80Q\x90\x94P\x90\x92P\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\t\xf4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\t\xb7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\nQW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\nfW`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\n\xdaW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\n\x9dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\v7W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\vLW`\x00\x80\xfd[PQ`@\x80Q` \x81\x01\x85\x81R\x92\x93P`\x00\x92`\x02\x92\x83\x92\x87\x92\x8f\x92\x8f\x92\x01\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\v\xd9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\v\x9cV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\f6W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\fKW`\x00\x80\xfd[PQ`@Q\x86Q`\x02\x91\x88\x91`\x00\x91\x88\x91` \x91\x82\x01\x91\x82\x91\x90\x86\x01\x90\x80\x83\x83[` \x83\x10a\f\xa9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\flV[`\x01\x83` \x03a\x01\x00\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x83g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x81R`\x18\x01\x82\x81R` \x01\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\rNW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\x11V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\r\xabW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\r\xc0W`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\x0e4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\xf7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x0e\x91W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x0e\xa6W`\x00\x80\xfd[PQ\x90P\x85\x81\x14a\x0f\x02W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`T\x81R` \x01\x80a\x17H`T\x919``\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` Tc\xff\xff\xff\xff\x11a\x0f`W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`!\x81R` \x01\x80a\x17'`!\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x80T`\x01\x01\x90\x81\x90U`\x00[` \x81\x10\x15a\x10\xa9W\x81`\x01\x16`\x01\x14\x15a\x0f\xa0W\x82`\x00\x82` \x81\x10a\x0f\x91W\xfe[\x01UPa\x10\xac\x95PPPPPPV[`\x02`\x00\x82` \x81\x10a\x0f\xafW\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x10%W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x0f\xe8V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x10\x82W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x10\x97W`\x00\x80\xfd[PQ\x92P`\x02\x82\x04\x91P`\x01\x01a\x0fnV[P\xfe[PPPPPPPV[``a\x10\xc2` Ta\x14\xbaV[\x90P\x90V[` T`\x00\x90\x81\x90\x81[` \x81\x10\x15a\x12\xf0W\x81`\x01\x16`\x01\x14\x15a\x11\xe6W`\x02`\x00\x82` \x81\x10a\x10\xf5W\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x11kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x11.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x11\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x11\xddW`\x00\x80\xfd[PQ\x92Pa\x12\xe2V[`\x02\x83`!\x83` \x81\x10a\x11\xf6W\xfe[\x01T`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x12kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x12.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x12\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x12\xddW`\x00\x80\xfd[PQ\x92P[`\x02\x82\x04\x91P`\x01\x01a\x10\xd1V[P`\x02\x82a\x12\xff` Ta\x14\xbaV[`\x00`@\x1b`@Q` \x01\x80\x84\x81R` \x01\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x13ZW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x13\x1dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x95\x90\x95\x16\x92\x01\x91\x82RP`@\x80Q\x80\x83\x03\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x01\x81R`\x18\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92\x85\x01\x91P\x80\x83\x83[` \x83\x10a\x14?W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x14\x02V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x14\x9cW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x14\xb1W`\x00\x80\xfd[PQ\x92PPP\x90V[`@\x80Q`\b\x80\x82R\x81\x83\x01\x90\x92R``\x91` \x82\x01\x81\x806\x837\x01\x90PP\x90P`\xc0\x82\x90\x1b\x80`\a\x1a`\xf8\x1b\x82`\x00\x81Q\x81\x10a\x14\xf4W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x06\x1a`\xf8\x1b\x82`\x01\x81Q\x81\x10a\x157W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x05\x1a`\xf8\x1b\x82`\x02\x81Q\x81\x10a\x15zW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x04\x1a`\xf8\x1b\x82`\x03\x81Q\x81\x10a\x15\xbdW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x03\x1a`\xf8\x1b\x82`\x04\x81Q\x81\x10a\x16\x00W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x02\x1a`\xf8\x1b\x82`\x05\x81Q\x81\x10a\x16CW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x01\x1a`\xf8\x1b\x82`\x06\x81Q\x81\x10a\x16\x86W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x00\x1a`\xf8\x1b\x82`\a\x81Q\x81\x10a\x16\xc9W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SPP\x91\x90PV[`\x00\x80\x85\x85\x11\x15a\x17\rW\x81\x82\xfd[\x83\x86\x11\x15a\x17\x19W\x81\x82\xfd[PP\x82\x01\x93\x91\x90\x92\x03\x91PV\xfeDepositContract: merkle tree fullDepositContract: reconstructed DepositData does not match supplied deposit_data_rootDepositContract: invalid withdrawal_credentials lengthDepositContract: deposit value not multiple of gweiDepositContract: invalid pubkey lengthDepositContract: deposit value too highDepositContract: deposit value too lowDepositContract: invalid signature length\xa2dipfsX\"\x12 \x1d\xd2o7\xa6!p0\t\xab\xf1nw\u6713\xdcP\u01dd\xb7\xf6\xcc7T>>\x0e=\xec\u0717dsolcC\x00\x06\v\x003\xf9\b<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\xa0\xf5\xa5\xfdB\xd1j 0'\x98\xefn\xd3\t\x97\x9bC\x00=# \xd9\xf0\xe8\xea\x981\xa9'Y\xfbK\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\xa0\xdbV\x11N\x00\xfd\xd4\xc1\xf8\\\x89+\xf3Z\u0268\x92\x89\xaa\xec\xb1\xeb\u0429l\xde`jt\x8b]q\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xa0\u01c0\t\xfd\xf0\x7f\xc5j\x11\xf1\"7\x06X\xa3S\xaa\xa5B\xedc\xe4LK\xc1_\xf4\xcd\x10Z\xb3<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xa0Sm\x98\x83\x7f-\xd1e\xa5]^\xea\xe9\x14\x85\x95Dr\xd5o$m\xf2V\xbf<\xae\x195*\x12<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xa0\x9e\xfd\xe0R\xaa\x15B\x9f\xae\x05\xba\xd4\u0431\xd7\xc6M\xa6M\x03\u05e1\x85JX\x8c,\xb8C\f\r0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xa0\u060d\xdf\xee\xd4\x00\xa8uU\x96\xb2\x19B\xc1I~\x11L0.a\x18)\x0f\x91\xe6w)v\x04\x1f\xa1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xa0\x87\xeb\r\u06e5~5\xf6\u0486g8\x02\xa4\xafYu\xe2%\x06\xc7\xcfLd\xbbk\xe5\xee\x11R\x7f,\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xa0&\x84dv\xfd_\xc5J]C8Qg\xc9QD\xf2d?S<\xc8[\xb9\xd1kx/\x8d}\xb1\x93\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xa0Pm\x86X-%$\x05\xb8@\x01\x87\x92\xca\u04bf\x12Y\xf1\xefZ\xa5\xf8\x87\xe1<\xb2\xf0\tOQ\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xa0\xff\xff\n\xd7\xe6Yw/\x954\xc1\x95\xc8\x15\xef\xc4\x01N\xf1\xe1\xda\xedD\x04\xc0c\x85\xd1\x11\x92\xe9+\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xa0l\xf0A'\xdb\x05D\x1c\xd83\x10zR\xbe\x85(h\x89\x0eC\x17\xe6\xa0*\xb4v\x83\xaau\x96B \xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\xa0\xb7\xd0_\x87_\x14\x00'\xefQ\x18\xa2${\xbb\x84\u038f/\x0f\x11#b0\x85\xda\xf7\x96\f2\x9f_\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xa0\xdfj\xf5\xf5\xbb\xdbk\xe9\uf2a6\x18\u4fc0s\x96\bg\x17\x1e)go\x8b(M\xeaj\b\xa8^\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xa0\xb5\x8d\x90\x0f^\x18.\x01t\u0285\x18.\xec\x9f:\t\xf6\xa6\xc0\xdfcw\xa5\x10\xd7\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\xa01 o\xa8\nP\xbbj\xbe)\bPX\xf1b\x12!*`\xee\xc8\xf0I\xfe\u02d2\xd8\xc8\xe0\xa8K\xc0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xa0!5+\xfe\xcb\xed\xdd\u94c3\x9faL=\xac\n>\xe3uC\xf9\xb4\x12\xb1a\x99\xdc\x15\x8e#\xb5D\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xa0a\x9e1'$\xbbm|1S\xed\x9d\xe7\x91\xd7d\xa3f\xb3\x89\xaf\x13\u014b\xf8\xa8\xd9\x04\x81\xa4ge\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\xa0|\xdd)\x86&\x82Pb\x8d\f\x10\xe3\x85\u014ca\x91\xe6\xfb\xe0Q\x91\xbc\xc0O\x13?,\xear\xc1\xc4\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xa0\x84\x890\xbd{\xa8\xca\xc5Fa\a!\x13\xfb'\x88i\xe0{\xb8X\x7f\x919)37M\x01{\xcb\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xa0\x88i\xff,\"\xb2\x8c\xc1\x05\x10\u06452\x92\x803(\xbeO\xb0\xe8\x04\x95\u8ecd'\x1f[\x88\x966\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa0\xb5\xfe(\xe7\x9f\x1b\x85\x0f\x86X$l\u9da1\u7d1f\xc0m\xb7\x14>\x8f\xe0\xb4\xf2\xb0\xc5R:\\\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xa0\x98^\x92\x9fp\xaf(\u043d\u0469\n\x80\x8f\x97\x7fY||w\x8cH\x9e\x98\u04fd\x89\x10\xd3\x1a\xc0\xf7\xe1\x94F#\x96\u677f\xa4U\xf4\x05\xf4\u0742\xf3\x01J\xf8\x00;r\x8b\xa5o\xa5\xb9\x90\x19\xa5\xc8\x00\x00\x00\xe0\x94I\xdf<\xca&p\xeb\rY\x11F\xb1cY\xfe3nGo)\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94K\xc6V\xb3M\xe28\x96\xfa`i\u0246/5[t\x04\x01\xaf\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe0\x94M\v\x04\xb4\x05\u01b6,|\xfc:\xe5GYt~,\vFb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94MIl\xcc(\x05\x8b\x1dt\xb7\xa1\x95Af>!\x15O\x9c\x84\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94P\x9avg\xac\x8d\x03 \xe3ar\xc1\x92Pja\x88\xaa\x84\xf6\x8b|\x13\xbcK,\x13\xfa<]\xc1\xaa\x19;\xc6\x03=\xfd\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94jz\xa9\xb8\x82\xd5\v\xb7\xbc]\xa1\xa2Dq\x9c\x99\xf1/\x06\xa3\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94l\xc99|;8s\x9d\xac\xbf\xaah\xea\xd5\xf5\xd7{\xa5\xf4U\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94s\xb2\xe0\xe5E\x10#\x9e\"\u0313o\vJm\xe1\xac\xf0\xab\u078bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94v,\xa6,\xa2T\x9a\xd8\x06v;:\xa1\xea1|B\x9b\xdb\u068a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94w\x8f_\x13\u013ex\xa3\xa4\xd7\x14\x1b\xcb&\x99\x97\x02\xf4\a\u03cbR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\x83M\xbfZ\x03\xe2\x9c%\xbcUE\x9c\u039c\x02\x1e\xeb\xe6v\xad\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x87]%\xeeK\xc6\x04\xc7\x1b\xafb6\xa8H\x8f\"9\x9b\xedK\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u150d\xf7\x87\x8d5q\xbe\xf5\xe5\xa7D\xf9b\x87\xc8\xd2\x03\x86\xd7Z\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\x9eAZ\to\xf7vP\u0712]\xeaTe\x85\xb4\xad\xb3\"\xb6\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa0vke\xa4\xf7\xb1\xday\xa1\xafy\xaciTV\uf886D\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\x9b\x14JD\x9eAJG,`\u01ea\xf1\xaa\xff\xe3)\x02\x1d\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa5S\x95Vk\vT9[2F\xf9j\v\xdcK\x8aH=\xf9\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xac\x9b\xa7/\xb6\x1a\xa7\xc3\x1a\x95\xdf\n\x8bn\xbaoA\xef\x87^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0I\x8c\x15\x87\x9d\xb2\xeeTq\u0512l_\xaa%\u0260\x96\x83\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0J\xef*=-\x86\xb0\x10\x06\xcc\xd43\x9a.\x94=\x9cd\x80\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1531\x9f\xb4\xc1\xf2\x802~`\xed7\xb1\xdcn\xe7u3S\x93\x14\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbb\x97{.\xe8\xa1\x11\u05c8\xb3G}$ x\u04387\xe7+\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xc2\x1c\xb9\u025c1m\x18c\x14/}\xd8m\xd5Im\x81\xa8\u058a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xc4s\xd4\x12\xdcR\xe3I\x86\"\t\x92L\x89\x81\xb2\xeeB\ah\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\u010e#\xc5\xf6\xe1\xea\v\xae\xf6S\a4\xed\u00d6\x8fy\xaf.\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94\xc6\xe2E\x99\x91\xbf\xe2|\xcam\x86r/5\xda#\xa1\xe4\u02d7\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xc9\xca+\xa9\xa2}\xe1\xdbX\x9d\x8c3\xab\x8e\u07e2\x11\x1b1\xfb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xd1\xf7~L\x1cE\x18n\x86S\u0109\xf9\x0e\x00\x8asYr\x96\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe2\x94\u04d9NM2\x02\xdd#\xc8I}\x7fu\xbf\x16G\xd1\xda\x1b\xb1\x8c\x01\x9d\x97\x1eO\xe8@\x1et\x00\x00\x00\xe0\x94\u0726\u9d0e\xa8j\xeb\xfd\xf9\x92\x99I\x12@B)kn4\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe0\x99\x1e\x84@A\xbeo\x11\xb9\x9d\xa5\xb1\x14\xb6\xbc\xf8N\xbdW\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xea(\xd0\x02\x04/\u0649\x8d\r\xb0\x16\xbe\x97X\xee\xaf\xe3\\\x1e\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xef\xa7EO\x11\x16\x80yu\xa4u\vFi^\x96xP\xde]\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xfb\xfdo\xa9\xf7:\u01a0X\xe0\x12Y\x03L(\x00\x1b\xef\x82G\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00" +const hoodiAllocData = "\xf93\x9d\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\x7f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf9!.\x90!\x9a\xb5@5l\xbb\x83\x9c\xbe\x050=w\x05\xfa\x80\xf9!\x19\x80\xb9\x18\xd6`\x80`@R`\x046\x10a\x00?W`\x005`\xe0\x1c\x80c\x01\xff\u0267\x14a\x00DW\x80c\"\x89Q\x18\x14a\x00\xa4W\x80cb\x1f\xd10\x14a\x01\xbaW\x80c\xc5\xf2\x89/\x14a\x02DW[`\x00\x80\xfd[4\x80\x15a\x00PW`\x00\x80\xfd[Pa\x00\x90`\x04\x806\x03` \x81\x10\x15a\x00gW`\x00\x80\xfd[P5\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16a\x02kV[`@\x80Q\x91\x15\x15\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[a\x01\xb8`\x04\x806\x03`\x80\x81\x10\x15a\x00\xbaW`\x00\x80\xfd[\x81\x01\x90` \x81\x01\x815d\x01\x00\x00\x00\x00\x81\x11\x15a\x00\xd5W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x00\xe7W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\tW`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01'W`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x019W`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01[W`\x00\x80\xfd[\x91\x93\x90\x92\x90\x91` \x81\x01\x905d\x01\x00\x00\x00\x00\x81\x11\x15a\x01yW`\x00\x80\xfd[\x82\x01\x83` \x82\x01\x11\x15a\x01\x8bW`\x00\x80\xfd[\x805\x90` \x01\x91\x84`\x01\x83\x02\x84\x01\x11d\x01\x00\x00\x00\x00\x83\x11\x17\x15a\x01\xadW`\x00\x80\xfd[\x91\x93P\x91P5a\x03\x04V[\x00[4\x80\x15a\x01\xc6W`\x00\x80\xfd[Pa\x01\xcfa\x10\xb5V[`@\x80Q` \x80\x82R\x83Q\x81\x83\x01R\x83Q\x91\x92\x83\x92\x90\x83\x01\x91\x85\x01\x90\x80\x83\x83`\x00[\x83\x81\x10\x15a\x02\tW\x81\x81\x01Q\x83\x82\x01R` \x01a\x01\xf1V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x026W\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x92PPP`@Q\x80\x91\x03\x90\xf3[4\x80\x15a\x02PW`\x00\x80\xfd[Pa\x02Ya\x10\xc7V[`@\x80Q\x91\x82RQ\x90\x81\x90\x03` \x01\x90\xf3[`\x00\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x01\xff\u0267\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x80a\x02\xfeWP\x7f\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x7f\x85d\t\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14[\x92\x91PPV[`0\x86\x14a\x03]W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18\x05`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x84\x14a\x03\xb6W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`6\x81R` \x01\x80a\x17\x9c`6\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``\x82\x14a\x04\x0fW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`)\x81R` \x01\x80a\x18x`)\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[g\r\u0db3\xa7d\x00\x004\x10\x15a\x04pW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`&\x81R` \x01\x80a\x18R`&\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x06\x15a\x04\xcdW`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`3\x81R` \x01\x80a\x17\xd2`3\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[c;\x9a\xca\x004\x04g\xff\xff\xff\xff\xff\xff\xff\xff\x81\x11\x15a\x055W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`'\x81R` \x01\x80a\x18+`'\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[``a\x05@\x82a\x14\xbaV[\x90P\x7fd\x9b\xbcb\xd0\xe3\x13B\xaf\xeaN\\\xd8-@I\xe7\xe1\xee\x91/\xc0\x88\x9a\xa7\x90\x80;\xe3\x908\u0149\x89\x89\x89\x85\x8a\x8aa\x05u` Ta\x14\xbaV[`@\x80Q`\xa0\x80\x82R\x81\x01\x89\x90R\x90\x81\x90` \x82\x01\x90\x82\x01``\x83\x01`\x80\x84\x01`\xc0\x85\x01\x8e\x8e\x80\x82\x847`\x00\x83\x82\x01R`\x1f\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x91\x01\x87\x81\x03\x86R\x8c\x81R` \x01\x90P\x8c\x8c\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x86R\x8cQ\x81R\x8cQ` \x91\x82\x01\x93\x91\x8e\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06HW\x81\x81\x01Q\x83\x82\x01R` \x01a\x060V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\x06uW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x86\x81\x03\x83R\x88\x81R` \x01\x89\x89\x80\x82\x847`\x00\x83\x82\x01\x81\x90R`\x1f\x90\x91\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x16\x90\x92\x01\x88\x81\x03\x84R\x89Q\x81R\x89Q` \x91\x82\x01\x93\x91\x8b\x01\x92P\x90\x81\x90\x84\x90\x84\x90[\x83\x81\x10\x15a\x06\xefW\x81\x81\x01Q\x83\x82\x01R` \x01a\x06\xd7V[PPPP\x90P\x90\x81\x01\x90`\x1f\x16\x80\x15a\a\x1cW\x80\x82\x03\x80Q`\x01\x83` \x03a\x01\x00\n\x03\x19\x16\x81R` \x01\x91P[P\x9dPPPPPPPPPPPPPP`@Q\x80\x91\x03\x90\xa1`\x00`\x02\x8a\x8a`\x00`\x80\x1b`@Q` \x01\x80\x84\x84\x80\x82\x847\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x94\x16\x91\x90\x93\x01\x90\x81R`@\x80Q\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x81\x84\x03\x01\x81R`\x10\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92P` \x85\x01\x91P\x80\x83\x83[` \x83\x10a\a\xfcW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\a\xbfV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\bYW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\bnW`\x00\x80\xfd[PQ\x90P`\x00`\x02\x80a\b\x84`@\x84\x8a\x8ca\x16\xfeV[`@Q` \x01\x80\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\b\xf8W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\b\xbbV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\tUW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\tjW`\x00\x80\xfd[PQ`\x02a\t{\x89`@\x81\x8da\x16\xfeV[`@Q`\x00\x90` \x01\x80\x84\x84\x80\x82\x847\x91\x90\x91\x01\x92\x83RPP`@\x80Q\x80\x83\x03\x81R` \x92\x83\x01\x91\x82\x90R\x80Q\x90\x94P\x90\x92P\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\t\xf4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\t\xb7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\nQW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\nfW`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\n\xdaW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\n\x9dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\v7W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\vLW`\x00\x80\xfd[PQ`@\x80Q` \x81\x01\x85\x81R\x92\x93P`\x00\x92`\x02\x92\x83\x92\x87\x92\x8f\x92\x8f\x92\x01\x83\x83\x80\x82\x847\x80\x83\x01\x92PPP\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\v\xd9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\v\x9cV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\f6W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\fKW`\x00\x80\xfd[PQ`@Q\x86Q`\x02\x91\x88\x91`\x00\x91\x88\x91` \x91\x82\x01\x91\x82\x91\x90\x86\x01\x90\x80\x83\x83[` \x83\x10a\f\xa9W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\flV[`\x01\x83` \x03a\x01\x00\n\x03\x80\x19\x82Q\x16\x81\x84Q\x16\x80\x82\x17\x85RPPPPPP\x90P\x01\x83g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16g\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x81R`\x18\x01\x82\x81R` \x01\x93PPPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\rNW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\x11V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\r\xabW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\r\xc0W`\x00\x80\xfd[PQ`@\x80Q` \x81\x81\x01\x94\x90\x94R\x80\x82\x01\x92\x90\x92R\x80Q\x80\x83\x03\x82\x01\x81R``\x90\x92\x01\x90\x81\x90R\x81Q\x91\x92\x90\x91\x82\x91\x84\x01\x90\x80\x83\x83[` \x83\x10a\x0e4W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\r\xf7V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x0e\x91W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x0e\xa6W`\x00\x80\xfd[PQ\x90P\x85\x81\x14a\x0f\x02W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`T\x81R` \x01\x80a\x17H`T\x919``\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` Tc\xff\xff\xff\xff\x11a\x0f`W`@Q\x7f\b\xc3y\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81R`\x04\x01\x80\x80` \x01\x82\x81\x03\x82R`!\x81R` \x01\x80a\x17'`!\x919`@\x01\x91PP`@Q\x80\x91\x03\x90\xfd[` \x80T`\x01\x01\x90\x81\x90U`\x00[` \x81\x10\x15a\x10\xa9W\x81`\x01\x16`\x01\x14\x15a\x0f\xa0W\x82`\x00\x82` \x81\x10a\x0f\x91W\xfe[\x01UPa\x10\xac\x95PPPPPPV[`\x02`\x00\x82` \x81\x10a\x0f\xafW\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x10%W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x0f\xe8V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x10\x82W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x10\x97W`\x00\x80\xfd[PQ\x92P`\x02\x82\x04\x91P`\x01\x01a\x0fnV[P\xfe[PPPPPPPV[``a\x10\xc2` Ta\x14\xbaV[\x90P\x90V[` T`\x00\x90\x81\x90\x81[` \x81\x10\x15a\x12\xf0W\x81`\x01\x16`\x01\x14\x15a\x11\xe6W`\x02`\x00\x82` \x81\x10a\x10\xf5W\xfe[\x01T\x84`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x11kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x11.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x11\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x11\xddW`\x00\x80\xfd[PQ\x92Pa\x12\xe2V[`\x02\x83`!\x83` \x81\x10a\x11\xf6W\xfe[\x01T`@Q` \x01\x80\x83\x81R` \x01\x82\x81R` \x01\x92PPP`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q\x80\x82\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x12kW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x12.V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x12\xc8W=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x12\xddW`\x00\x80\xfd[PQ\x92P[`\x02\x82\x04\x91P`\x01\x01a\x10\xd1V[P`\x02\x82a\x12\xff` Ta\x14\xbaV[`\x00`@\x1b`@Q` \x01\x80\x84\x81R` \x01\x83\x80Q\x90` \x01\x90\x80\x83\x83[` \x83\x10a\x13ZW\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x13\x1dV[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x95\x90\x95\x16\x92\x01\x91\x82RP`@\x80Q\x80\x83\x03\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x01\x81R`\x18\x90\x92\x01\x90\x81\x90R\x81Q\x91\x95P\x93P\x83\x92\x85\x01\x91P\x80\x83\x83[` \x83\x10a\x14?W\x80Q\x82R\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x90\x92\x01\x91` \x91\x82\x01\x91\x01a\x14\x02V[Q\x81Q` \x93\x84\x03a\x01\x00\n\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x80\x19\x90\x92\x16\x91\x16\x17\x90R`@Q\x91\x90\x93\x01\x94P\x91\x92PP\x80\x83\x03\x81\x85Z\xfa\x15\x80\x15a\x14\x9cW=`\x00\x80>=`\x00\xfd[PPP`@Q=` \x81\x10\x15a\x14\xb1W`\x00\x80\xfd[PQ\x92PPP\x90V[`@\x80Q`\b\x80\x82R\x81\x83\x01\x90\x92R``\x91` \x82\x01\x81\x806\x837\x01\x90PP\x90P`\xc0\x82\x90\x1b\x80`\a\x1a`\xf8\x1b\x82`\x00\x81Q\x81\x10a\x14\xf4W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x06\x1a`\xf8\x1b\x82`\x01\x81Q\x81\x10a\x157W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x05\x1a`\xf8\x1b\x82`\x02\x81Q\x81\x10a\x15zW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x04\x1a`\xf8\x1b\x82`\x03\x81Q\x81\x10a\x15\xbdW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x03\x1a`\xf8\x1b\x82`\x04\x81Q\x81\x10a\x16\x00W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x02\x1a`\xf8\x1b\x82`\x05\x81Q\x81\x10a\x16CW\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x01\x1a`\xf8\x1b\x82`\x06\x81Q\x81\x10a\x16\x86W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SP\x80`\x00\x1a`\xf8\x1b\x82`\a\x81Q\x81\x10a\x16\xc9W\xfe[` \x01\x01\x90~\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x19\x16\x90\x81`\x00\x1a\x90SPP\x91\x90PV[`\x00\x80\x85\x85\x11\x15a\x17\rW\x81\x82\xfd[\x83\x86\x11\x15a\x17\x19W\x81\x82\xfd[PP\x82\x01\x93\x91\x90\x92\x03\x91PV\xfeDepositContract: merkle tree fullDepositContract: reconstructed DepositData does not match supplied deposit_data_rootDepositContract: invalid withdrawal_credentials lengthDepositContract: deposit value not multiple of gweiDepositContract: invalid pubkey lengthDepositContract: deposit value too highDepositContract: deposit value too lowDepositContract: invalid signature length\xa2dipfsX\"\x12 \xdc\xec\xa8pk)\xe9\x17\xda\xcf%\xfc\xee\xf9Z\xca\xc8\xd9\rvZ\xc9&f<\xe4\ta\x95\x95+adsolcC\x00\x06\v\x003\xf9\b<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\xa0\xf5\xa5\xfdB\xd1j 0'\x98\xefn\xd3\t\x97\x9bC\x00=# \xd9\xf0\xe8\xea\x981\xa9'Y\xfbK\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\xa0\xdbV\x11N\x00\xfd\xd4\xc1\xf8\\\x89+\xf3Z\u0268\x92\x89\xaa\xec\xb1\xeb\u0429l\xde`jt\x8b]q\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xa0\u01c0\t\xfd\xf0\x7f\xc5j\x11\xf1\"7\x06X\xa3S\xaa\xa5B\xedc\xe4LK\xc1_\xf4\xcd\x10Z\xb3<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xa0Sm\x98\x83\x7f-\xd1e\xa5]^\xea\xe9\x14\x85\x95Dr\xd5o$m\xf2V\xbf<\xae\x195*\x12<\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xa0\x9e\xfd\xe0R\xaa\x15B\x9f\xae\x05\xba\xd4\u0431\xd7\xc6M\xa6M\x03\u05e1\x85JX\x8c,\xb8C\f\r0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xa0\u060d\xdf\xee\xd4\x00\xa8uU\x96\xb2\x19B\xc1I~\x11L0.a\x18)\x0f\x91\xe6w)v\x04\x1f\xa1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xa0\x87\xeb\r\u06e5~5\xf6\u0486g8\x02\xa4\xafYu\xe2%\x06\xc7\xcfLd\xbbk\xe5\xee\x11R\x7f,\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xa0&\x84dv\xfd_\xc5J]C8Qg\xc9QD\xf2d?S<\xc8[\xb9\xd1kx/\x8d}\xb1\x93\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xa0Pm\x86X-%$\x05\xb8@\x01\x87\x92\xca\u04bf\x12Y\xf1\xefZ\xa5\xf8\x87\xe1<\xb2\xf0\tOQ\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xa0\xff\xff\n\xd7\xe6Yw/\x954\xc1\x95\xc8\x15\xef\xc4\x01N\xf1\xe1\xda\xedD\x04\xc0c\x85\xd1\x11\x92\xe9+\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xa0l\xf0A'\xdb\x05D\x1c\xd83\x10zR\xbe\x85(h\x89\x0eC\x17\xe6\xa0*\xb4v\x83\xaau\x96B \xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\xa0\xb7\xd0_\x87_\x14\x00'\xefQ\x18\xa2${\xbb\x84\u038f/\x0f\x11#b0\x85\xda\xf7\x96\f2\x9f_\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xa0\xdfj\xf5\xf5\xbb\xdbk\xe9\uf2a6\x18\u4fc0s\x96\bg\x17\x1e)go\x8b(M\xeaj\b\xa8^\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xa0\xb5\x8d\x90\x0f^\x18.\x01t\u0285\x18.\xec\x9f:\t\xf6\xa6\xc0\xdfcw\xa5\x10\xd7\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\xa01 o\xa8\nP\xbbj\xbe)\bPX\xf1b\x12!*`\xee\xc8\xf0I\xfe\u02d2\xd8\xc8\xe0\xa8K\xc0\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xa0!5+\xfe\xcb\xed\xdd\u94c3\x9faL=\xac\n>\xe3uC\xf9\xb4\x12\xb1a\x99\xdc\x15\x8e#\xb5D\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xa0a\x9e1'$\xbbm|1S\xed\x9d\xe7\x91\xd7d\xa3f\xb3\x89\xaf\x13\u014b\xf8\xa8\xd9\x04\x81\xa4ge\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\xa0|\xdd)\x86&\x82Pb\x8d\f\x10\xe3\x85\u014ca\x91\xe6\xfb\xe0Q\x91\xbc\xc0O\x13?,\xear\xc1\xc4\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xa0\x84\x890\xbd{\xa8\xca\xc5Fa\a!\x13\xfb'\x88i\xe0{\xb8X\x7f\x919)37M\x01{\xcb\xe1\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xa0\x88i\xff,\"\xb2\x8c\xc1\x05\x10\u06452\x92\x803(\xbeO\xb0\xe8\x04\x95\u8ecd'\x1f[\x88\x966\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa0\xb5\xfe(\xe7\x9f\x1b\x85\x0f\x86X$l\u9da1\u7d1f\xc0m\xb7\x14>\x8f\xe0\xb4\xf2\xb0\xc5R:\\\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xa0\x98^\x92\x9fp\xaf(\u043d\u0469\n\x80\x8f\x97\x7fY||w\x8cH\x9e\x98\u04fd\x89\x10\xd3\x1a\xc0\xf7\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xf9\x02Y\x92\ta\xefH\x0e\xb5^\x80\u045a\xd85y\xa6L\x00p\x02\x80\xf9\x02B\x01\xb9\x01\xf83s\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x14`\xcbW`\x11_T\x80\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x14a\x01\xf4W`\x01\x82\x02`\x01\x90_[_\x82\x11\x15`hW\x81\x01\x90\x83\x02\x84\x83\x02\x90\x04\x91`\x01\x01\x91\x90`MV[\x90\x93\x90\x04\x92PPP6`8\x14`\x88W6a\x01\xf4W4a\x01\xf4W_R` _\xf3[4\x10a\x01\xf4W`\x01T`\x01\x01`\x01U`\x03T\x80`\x03\x02`\x04\x013\x81U`\x01\x01_5\x81U`\x01\x01` 5\x90U3``\x1b_R`8_`\x147`L_\xa0`\x01\x01`\x03U\x00[`\x03T`\x02T\x80\x82\x03\x80`\x10\x11`\xdfWP`\x10[_[\x81\x81\x14a\x01\x83W\x82\x81\x01`\x03\x02`\x04\x01\x81`L\x02\x81T``\x1b\x81R`\x14\x01\x81`\x01\x01T\x81R` \x01\x90`\x02\x01T\x80\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x82R\x90`\x10\x01\x90`@\x1c\x90\x81`8\x1c\x81`\a\x01S\x81`0\x1c\x81`\x06\x01S\x81`(\x1c\x81`\x05\x01S\x81` \x1c\x81`\x04\x01S\x81`\x18\x1c\x81`\x03\x01S\x81`\x10\x1c\x81`\x02\x01S\x81`\b\x1c\x81`\x01\x01SS`\x01\x01`\xe1V[\x91\x01\x80\x92\x14a\x01\x95W\x90`\x02Ua\x01\xa0V[\x90P_`\x02U_`\x03U[_T\x80\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x14\x15a\x01\xcdWP_[`\x01T`\x02\x82\x82\x01\x11a\x01\xe2WPP_a\x01\xe8V[\x01`\x02\x90\x03[_U_`\x01U`L\x02_\xf3[__\xfd\xf8D\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf9\x01\xff\x92\xbb\xdd\xc7\xceH\x86B\xfbW\x9f\x8b\x00\xf3\xa5\x90\x00rQ\x80\xf9\x01\xe8\x01\xb9\x01\x9e3s\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x14`\xd3W`\x11_T\x80\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x14a\x01\x9aW`\x01\x82\x02`\x01\x90_[_\x82\x11\x15`hW\x81\x01\x90\x83\x02\x84\x83\x02\x90\x04\x91`\x01\x01\x91\x90`MV[\x90\x93\x90\x04\x92PPP6``\x14`\x88W6a\x01\x9aW4a\x01\x9aW_R` _\xf3[4\x10a\x01\x9aW`\x01T`\x01\x01`\x01U`\x03T\x80`\x04\x02`\x04\x013\x81U`\x01\x01_5\x81U`\x01\x01` 5\x81U`\x01\x01`@5\x90U3``\x1b_R``_`\x147`t_\xa0`\x01\x01`\x03U\x00[`\x03T`\x02T\x80\x82\x03\x80`\x02\x11`\xe7WP`\x02[_[\x81\x81\x14a\x01)W\x82\x81\x01`\x04\x02`\x04\x01\x81`t\x02\x81T``\x1b\x81R`\x14\x01\x81`\x01\x01T\x81R` \x01\x81`\x02\x01T\x81R` \x01\x90`\x03\x01T\x90R`\x01\x01`\xe9V[\x91\x01\x80\x92\x14a\x01;W\x90`\x02Ua\x01FV[\x90P_`\x02U_`\x03U[_T\x80\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x14\x15a\x01sWP_[`\x01T`\x01\x82\x82\x01\x11a\x01\x88WPP_a\x01\x8eV[\x01`\x01\x90\x03[_U_`\x01U`t\x02_\xf3[__\xfd\xf8D\xf8B\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8m\x92\xf9\b'\xf1\xc5:\x10\xcbz\x023[\x17S \x00)5\x80\xf8W\x01\xb8S3s\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x14`FW` 6\x03`BW_5`\x01C\x03\x81\x11`BWa\x1f\xff\x81C\x03\x11`BWa\x1f\xff\x90\x06T_R` _\xf3[__\xfd[_5a\x1f\xff`\x01C\x03\x06U\x00\xc0\xf8|\x93\x0f=\xf6\xd72\x80~\xf11\x9f\xb7\xb8\xbb\x85\"\u043e\xac\x02\x80\xf8e\x01\xb8a3s\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x14`MW` 6\x14`$W__\xfd[_5\x80\x15`IWb\x00\x1f\xff\x81\x06\x90\x81T\x14`\x8e\u0344h\xa0\x03\x7f\x05\x8a\x9d\xaf\xady\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94@O\xfd\x9d\xd6T(\xe0\x96\u0667\xb87\x92Bc\xef@\xfb1\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94E\u0720to\xc5k@\v)\x1f]\x96W\xa7\x94d\xe8\xf1R\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94F#\x96\u677f\xa4U\xf4\x05\xf4\u0742\xf3\x01J\xf8\x00;r\x8b\xa5o\xa5\xb9\x90\x19\xa5\xc8\x00\x00\x00\xe0\x94I\xdf<\xca&p\xeb\rY\x11F\xb1cY\xfe3nGo)\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94M\v\x04\xb4\x05\u01b6,|\xfc:\xe5GYt~,\vFb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94MIl\xcc(\x05\x8b\x1dt\xb7\xa1\x95Af>!\x15O\x9c\x84\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94P\x9avg\xac\x8d\x03 \xe3ar\xc1\x92Pja\x88\xaa\x84\xf6\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94Q\x80\xdb\x027)\x1adI\u0769\xed3\xad\x90\xa3\x87\x87b\x1c\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94Rs\x0f4}\xefk\xa0\x9a\xdf\xf6.\xac`\xd5\xfe\xe8 [\u010a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94^\xac\x0f\xbd=\xfe\xf8\xae>\xfa<]\xc1\xaa\x19;\xc6\x03=\xfd\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94_\x10\u069bh\xf0lv\xf3\xc6$\xf8\xb2\xee;*&\x985\x1b\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94a\bf\xc6\b\x97h\u0695RK\xccL\xe7\xdba\xed\xa3\x93\x1c\x8b\xa5o\xa5\xb9\x90\x19\xa5\xc8\x00\x00\x00\xe1\x94jz\xa9\xb8\x82\xd5\v\xb7\xbc]\xa1\xa2Dq\x9c\x99\xf1/\x06\xa3\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94l\xc99|;8s\x9d\xac\xbf\xaah\xea\xd5\xf5\xd7{\xa5\xf4U\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94s\xb2\xe0\xe5E\x10#\x9e\"\u0313o\vJm\xe1\xac\xf0\xab\u078bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94v,\xa6,\xa2T\x9a\xd8\x06v;:\xa1\xea1|B\x9b\xdb\u068a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94v\x7fuv\x94M2\x13t\x92\x1d\xf18X\x9a0\xe3\xc5\x03\r\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94w\x8f_\x13\u013ex\xa3\xa4\xd7\x14\x1b\xcb&\x99\x97\x02\xf4\a\u03cbR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\x83M\xbfZ\x03\xe2\x9c%\xbcUE\x9c\u039c\x02\x1e\xeb\xe6v\xad\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x87]%\xeeK\xc6\x04\xc7\x1b\xafb6\xa8H\x8f\"9\x9b\xedK\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x8d\xf7\x87\x8d5q\xbe\xf5\xe5\xa7D\xf9b\x87\xc8\xd2\x03\x86\xd7Z\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x90)\xc7r\xdd\xe8Gb-\xf1U>\xd9\u067d\xb7\x81.O\x93\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u251a'\xd0\xc7\x15\xd3\xf2\xaf/\xac9\xa4\x1cI\xed5\x00J;\u03cc\x01\x9d\x97\x1eO\xe8@\x1et\x00\x00\x00\xe0\x94\x9b8?\x8eL\xd5\xd3\xdd_\x90\x06\xb6\xa5\b\x96\n\x1es\x03u\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x9bI\x1f\x041\x89\xafm1\xd3\u0531\xa7\xca\x1c\xf7/@\xc5*\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x9eAZ\to\xf7vP\u0712]\xeaTe\x85\xb4\xad\xb3\"\xb6\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa0vke\xa4\xf7\xb1\xday\xa1\xafy\xaciTV\uf886D\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\x9b\x14JD\x9eAJG,`\u01ea\xf1\xaa\xff\xe3)\x02\x1d\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa5S\x95Vk\vT9[2F\xf9j\v\xdcK\x8aH=\xf9\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xac\x9b\xa7/\xb6\x1a\xa7\xc3\x1a\x95\xdf\n\x8bn\xbaoA\xef\x87^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0I\x8c\x15\x87\x9d\xb2\xeeTq\u0512l_\xaa%\u0260\x96\x83\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xb0J\xef*=-\x86\xb0\x10\x06\xcc\xd43\x9a.\x94=\x9cd\x80\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1531\x9f\xb4\xc1\xf2\x802~`\xed7\xb1\xdcn\xe7u3S\x93\x14\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xc2\x1c\xb9\u025c1m\x18c\x14/}\xd8m\xd5Im\x81\xa8\u058a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xc4s\xd4\x12\xdcR\xe3I\x86\"\t\x92L\x89\x81\xb2\xeeB\ah\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u010e#\xc5\xf6\xe1\xea\v\xae\xf6S\a4\xed\u00d6\x8fy\xaf.\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xc5d\xaf\x15F!\xee\x8d\x05\x89u\x8dSU\x11\xae\xc8\xf6{@\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\xc6\xe2E\x99\x91\xbf\xe2|\xcam\x86r/5\xda#\xa1\xe4\u02d7\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xc9\xca+\xa9\xa2}\xe1\xdbX\x9d\x8c3\xab\x8e\u07e2\x11\x1b1\xfb\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xd1\xf7~L\x1cE\x18n\x86S\u0109\xf9\x0e\x00\x8asYr\x96\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u053bU];\r\x7f\xf1|`aa\xb4N7&\x89\xc1OK\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xda)\xbbqf\x9fF\xf2\xa7y\xb4\xb6/\x03dJ\x84\xee4y\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\xdb\xf6@\u07a0G\xfa~\xe7F\xd0\x1a1x#\x86\xf8'\xcf\xc1\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe0\x94\u0726\u9d0e\xa8j\xeb\xfd\xf9\x92\x99I\x12@B)kn4\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe4\x95^\x10~\xa50\xb4\xc2\u06ca2=\xf0\xa1C\u0628+\x9c\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xea(\xd0\x02\x04/\u0649\x8d\r\xb0\x16\xbe\x97X\xee\xaf\xe3\\\x1e\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xebt.C\x95n\x0e\xa8\x9a-\xb6\xbfb7\u01de\xe4dY\x81\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xef\xa7EO\x11\x16\x80yu\xa4u\vFi^\x96xP\xde]\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xfb\xfdo\xa9\xf7:\u01a0X\xe0\x12Y\x03L(\x00\x1b\xef\x82G\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe1\x94\xfcz\xf4\x9b\x80\xac\xf0AtCf\xb0\"r\x01\x97#\xc9O\x9c\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00" diff --git a/core/genesis_test.go b/core/genesis_test.go index d023422d1..70ec4fc8a 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -104,6 +104,15 @@ func testSetupGenesis(t *testing.T, scheme string) { }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, }, + { + name: "custom block in DB, genesis == hoodi", + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { + tdb := triedb.NewDatabase(db, newDbConfig(scheme)) + customg.Commit(db, tdb) + return SetupGenesisBlock(db, tdb, DefaultHoodiGenesisBlock()) + }, + wantErr: &GenesisMismatchError{Stored: customghash, New: params.HoodiGenesisHash}, + }, { name: "compatible config in DB", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { @@ -178,6 +187,8 @@ func TestGenesisHashes(t *testing.T) { }{ {DefaultGenesisBlock(), params.MainnetGenesisHash}, {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, + {DefaultHoleskyGenesisBlock(), params.HoleskyGenesisHash}, + {DefaultHoodiGenesisBlock(), params.HoodiGenesisHash}, } { // Test via MustCommit db := rawdb.NewMemoryDatabase() diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 1bee45550..ea25bf1e2 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -119,6 +119,7 @@ func TestDeleteBloomBits(t *testing.T) { for s := uint64(0); s < 2; s++ { WriteBloomBits(db, i, s, params.MainnetGenesisHash, []byte{0x01, 0x02}) WriteBloomBits(db, i, s, params.SepoliaGenesisHash, []byte{0x01, 0x02}) + WriteBloomBits(db, i, s, params.HoodiGenesisHash, []byte{0x01, 0x02}) } } check := func(bit uint, section uint64, head common.Hash, exist bool) { @@ -133,24 +134,31 @@ func TestDeleteBloomBits(t *testing.T) { // Check the existence of written data. check(0, 0, params.MainnetGenesisHash, true) check(0, 0, params.SepoliaGenesisHash, true) + check(0, 0, params.HoodiGenesisHash, true) // Check the existence of deleted data. DeleteBloombits(db, 0, 0, 1) check(0, 0, params.MainnetGenesisHash, false) check(0, 0, params.SepoliaGenesisHash, false) + check(0, 0, params.HoodiGenesisHash, false) check(0, 1, params.MainnetGenesisHash, true) check(0, 1, params.SepoliaGenesisHash, true) + check(0, 1, params.HoodiGenesisHash, true) // Check the existence of deleted data. DeleteBloombits(db, 0, 0, 2) check(0, 0, params.MainnetGenesisHash, false) check(0, 0, params.SepoliaGenesisHash, false) + check(0, 0, params.HoodiGenesisHash, false) check(0, 1, params.MainnetGenesisHash, false) check(0, 1, params.SepoliaGenesisHash, false) + check(0, 1, params.HoodiGenesisHash, false) // Bit1 shouldn't be affect. check(1, 0, params.MainnetGenesisHash, true) check(1, 0, params.SepoliaGenesisHash, true) + check(1, 0, params.HoodiGenesisHash, true) check(1, 1, params.MainnetGenesisHash, true) check(1, 1, params.SepoliaGenesisHash, true) + check(1, 1, params.HoodiGenesisHash, true) } diff --git a/params/bootnodes.go b/params/bootnodes.go index 124765313..28e339554 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -28,6 +28,15 @@ var MainnetBootnodes = []string{ "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn } +// HoodiBootnodes are the enode URLs of the P2P bootstrap nodes running on the +// Hoodi test network. +var HoodiBootnodes = []string{ + // EF DevOps + "enode://2112dd3839dd752813d4df7f40936f06829fc54c0e051a93967c26e5f5d27d99d886b57b4ffcc3c475e930ec9e79c56ef1dbb7d86ca5ee83a9d2ccf36e5c240c@134.209.138.84:30303", + "enode://60203fcb3524e07c5df60a14ae1c9c5b24023ea5d47463dfae051d2c9f3219f309657537576090ca0ae641f73d419f53d8e8000d7a464319d4784acd7d2abc41@209.38.124.160:30303", + "enode://8ae4a48101b2299597341263da0deb47cc38aa4d3ef4b7430b897d49bfa10eb1ccfe1655679b1ed46928ef177fbf21b86837bd724400196c508427a6f41602cd@134.199.184.23:30303", +} + // HoleskyBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Holesky test network. var HoleskyBootnodes = []string{ @@ -84,6 +93,8 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string { net = "sepolia" case HoleskyGenesisHash: net = "holesky" + case HoodiGenesisHash: + net = "hoodi" default: return "" } diff --git a/params/config.go b/params/config.go index 29926c59e..f9b9d14be 100644 --- a/params/config.go +++ b/params/config.go @@ -31,6 +31,7 @@ var ( MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") HoleskyGenesisHash = common.HexToHash("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4") SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") + HoodiGenesisHash = common.HexToHash("0xbbe312868b376a3001692a646dd2d7d1e4406380dfd86b98aa8a34d1557c971b") ) func newUint64(val uint64) *uint64 { return &val } @@ -125,6 +126,36 @@ var ( Prague: DefaultPragueBlobConfig, }, } + // HoodiChainConfig contains the chain parameters to run a node on the Hoodi test network. + HoodiChainConfig = &ChainConfig{ + ChainID: big.NewInt(560048), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: nil, + GrayGlacierBlock: nil, + TerminalTotalDifficulty: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + ShanghaiTime: newUint64(0), + CancunTime: newUint64(0), + PragueTime: newUint64(1742999832), + DepositContractAddress: common.HexToAddress("0x00000000219ab540356cBB839Cbe05303d7705Fa"), + Ethash: new(EthashConfig), + BlobScheduleConfig: &BlobScheduleConfig{ + Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, + }, + } // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. AllEthashProtocolChanges = &ChainConfig{ @@ -338,6 +369,7 @@ var NetworkNames = map[string]string{ MainnetChainConfig.ChainID.String(): "mainnet", SepoliaChainConfig.ChainID.String(): "sepolia", HoleskyChainConfig.ChainID.String(): "holesky", + HoodiChainConfig.ChainID.String(): "hoodi", } // ChainConfig is the core config which determines the blockchain settings. From 4b104c81bdfd91f376cc39d82c51a871b7b49e80 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 18 Mar 2025 12:40:38 +0100 Subject: [PATCH 216/354] internal/ethapi: fix logs bloom in eth_simulateV1 (#31411) Geth was returning empty logsBloom for the simulated block. --- internal/ethapi/simulate.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index ac7637242..097de8b0b 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -217,9 +217,13 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil { return nil, nil, err } - tx := call.ToTransaction(types.DynamicFeeTxType) + var ( + tx = call.ToTransaction(types.DynamicFeeTxType) + txHash = tx.Hash() + ) txes[i] = tx - tracer.reset(tx.Hash(), uint(i)) + tracer.reset(txHash, uint(i)) + sim.state.SetTxContext(txHash, i) // EoA check is always skipped, even in validation mode. msg := call.ToMessage(header.BaseFee, !sim.validate, true) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) From 1ce1493920dacb626dc53ad2b7cabcba8be5cb5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Tue, 18 Mar 2025 13:46:23 +0100 Subject: [PATCH 217/354] core/filtermaps: fixed indexer checkpoint initialization (#31419) This PR fixes a bug in the `lastMapBoundaryBefore` logic that resulted in incorrect checkpoint initialization (started rendering from the previous epoch boundary which caused the `needTailEpoch` check to fail). Apparently the bug was present before but went unnoticed because `needTailEpoch` behaved differently. Fixes https://github.com/ethereum/go-ethereum/issues/31413 --- core/filtermaps/indexer.go | 3 +++ core/filtermaps/map_renderer.go | 29 ++++++++++++++++------------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index addda03df..835e84cc0 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -346,6 +346,9 @@ func (f *FilterMaps) needTailEpoch(epoch uint32) bool { if epoch > firstEpoch { return true } + if (epoch+1)<= f.indexedRange.maps.AfterLast() { + return true + } if epoch+1 < firstEpoch { return false } diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 4f45a7f2b..ba2d399e8 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -185,27 +185,30 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMa // lastMapBoundaryBefore returns the latest map boundary before the specified // map index. -func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) { - if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 { +func (f *FilterMaps) lastMapBoundaryBefore(renderBefore uint32) (uint32, bool) { + if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 || renderBefore == 0 { return 0, false } - if mapIndex > f.indexedRange.maps.AfterLast() { - mapIndex = f.indexedRange.maps.AfterLast() + afterLastFullMap := f.indexedRange.maps.AfterLast() + if afterLastFullMap > 0 && f.indexedRange.headIndexed { + afterLastFullMap-- // last map is not full } - if mapIndex > f.indexedRange.maps.First() { - return mapIndex - 1, true + firstRendered := min(renderBefore-1, afterLastFullMap) + if firstRendered == 0 { + return 0, false } - if mapIndex+f.mapsPerEpoch > f.indexedRange.maps.First() { - if mapIndex > f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch { - mapIndex = f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch - } + if firstRendered >= f.indexedRange.maps.First() { + return firstRendered - 1, true + } + if firstRendered+f.mapsPerEpoch > f.indexedRange.maps.First() { + firstRendered = min(firstRendered, f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch) } else { - mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch + firstRendered = (firstRendered >> f.logMapsPerEpoch) << f.logMapsPerEpoch } - if mapIndex == 0 { + if firstRendered == 0 { return 0, false } - return mapIndex - 1, true + return firstRendered - 1, true } // emptyFilterMap returns an empty filter map. From 7f2cbc54c1fe6d3c28cce4c6e3847803367dba37 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 18 Mar 2025 21:32:29 +0800 Subject: [PATCH 218/354] cmd: set name to chaindata for all the opened db (#31352) When I'm running `geth import --metrics`, the metrics is different to normal `geth --metrics`, so the grafana dashboard needs to be updated, eg: `eth_db_chaindata_disk_read` vs `disk_read`. So I think we should always set the name to `eth/db/chaindata` for more convenient. --------- Signed-off-by: jsvisa --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index da8d54a40..17b776ee4 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2251,7 +2251,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. } chainDb = remotedb.New(client) default: - chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly) + chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "eth/db/chaindata/", readonly) } if err != nil { Fatalf("Could not open database: %v", err) From 8fc40e1fd0fbaef625a1206658ea2d2bb948dd6e Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Tue, 18 Mar 2025 09:41:34 -0500 Subject: [PATCH 219/354] ethclient: Add EstimateGasAtBlock[Hash] to estimate against a specific block (#27508) The main use case I see of this is that it allows users to estimate gas against the same state that they query for their nonce, and the same state they base the data of their transaction against. This helps ensure that gas estimation won't fail and the transaction won't revert on-chain because of a mismatch between the state used for gas estimation and the state used to generate the inputs to gas estimation or the transaction's nonce when submitted to the mempool. This PR also updates the EstimateGas comment based on the new geth `eth_estimateGas` default of using latest state as of v1.12.0: https://github.com/ethereum/go-ethereum/pull/24363 --------- Co-authored-by: Felix Lange --- ethclient/ethclient.go | 32 +++++++++++++++++++++++++++++--- ethclient/ethclient_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index d633039a5..ae1fd22a4 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -659,9 +659,13 @@ func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock * } // EstimateGas tries to estimate the gas needed to execute a specific transaction based on -// the current pending state of the backend blockchain. There is no guarantee that this is -// the true gas limit requirement as other transactions may be added or removed by miners, -// but it should provide a basis for setting a reasonable default. +// the current state of the backend blockchain. There is no guarantee that this is the +// true gas limit requirement as other transactions may be added or removed by miners, but +// it should provide a basis for setting a reasonable default. +// +// Note that the state used by this method is implementation-defined by the remote RPC +// server, but it's reasonable to assume that it will either be the pending or latest +// state. func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { var hex hexutil.Uint64 err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) @@ -671,6 +675,28 @@ func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64 return uint64(hex), nil } +// EstimateGasAtBlock is almost the same as EstimateGas except that it selects the block height +// instead of using the remote RPC's default state for gas estimation. +func (ec *Client) EstimateGasAtBlock(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) (uint64, error) { + var hex hexutil.Uint64 + err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), toBlockNumArg(blockNumber)) + if err != nil { + return 0, err + } + return uint64(hex), nil +} + +// EstimateGasAtBlockHash is almost the same as EstimateGas except that it selects the block +// hash instead of using the remote RPC's default state for gas estimation. +func (ec *Client) EstimateGasAtBlockHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) (uint64, error) { + var hex hexutil.Uint64 + err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false)) + if err != nil { + return 0, err + } + return uint64(hex), nil +} + // SendTransaction injects a signed transaction into the pending pool for execution. // // If the transaction was a contract creation use the TransactionReceipt method to get the diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 5d13e5131..ff591389c 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -610,6 +610,33 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { if !bytes.Equal(code, penCode) { t.Fatalf("unexpected code: %v %v", code, penCode) } + // Use HeaderByNumber to get a header for EstimateGasAtBlock and EstimateGasAtBlockHash + latestHeader, err := ec.HeaderByNumber(context.Background(), nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + // EstimateGasAtBlock + msg := ethereum.CallMsg{ + From: testAddr, + To: &common.Address{}, + Gas: 21000, + Value: big.NewInt(1), + } + gas, err := ec.EstimateGasAtBlock(context.Background(), msg, latestHeader.Number) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gas != 21000 { + t.Fatalf("unexpected gas limit: %v", gas) + } + // EstimateGasAtBlockHash + gas, err = ec.EstimateGasAtBlockHash(context.Background(), msg, latestHeader.Hash()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gas != 21000 { + t.Fatalf("unexpected gas limit: %v", gas) + } } func testTransactionSender(t *testing.T, client *rpc.Client) { From d7f7982ad536614f5ccf69e664500753b317965c Mon Sep 17 00:00:00 2001 From: minh-bq Date: Wed, 19 Mar 2025 13:20:50 +0700 Subject: [PATCH 220/354] core/txpool, eth: add GetRLP to transaction pool (#31307) Currently, when answering GetPooledTransaction request, txpool.Get() is used. When the requested hash is blob transaction, blobpool.Get() is called. This function loads the RLP-encoded transaction from limbo then decodes and returns. Later, in answerGetPooledTransactions, we need to RLP encode again. This decode then encode is wasteful. This commit adds GetRLP to transaction pool interface so that answerGetPooledTransactions can use the RLP-encoded from limbo directly. --------- Co-authored-by: Gary Rong --- core/txpool/blobpool/blobpool.go | 24 +++++- core/txpool/legacypool/cachepool.go | 7 ++ core/txpool/legacypool/legacypool.go | 15 ++++ core/txpool/subpool.go | 3 + core/txpool/txpool.go | 11 +++ eth/filters/filter_test.go | 2 +- eth/handler.go | 4 + eth/handler_test.go | 15 ++++ eth/protocols/eth/handler.go | 4 + eth/protocols/eth/handler_test.go | 116 ++++++++++++++++++++++++--- eth/protocols/eth/handlers.go | 15 ++-- 11 files changed, 192 insertions(+), 24 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index c880b6e17..45f5d738d 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1198,8 +1198,7 @@ func (p *BlobPool) Has(hash common.Hash) bool { return p.lookup.exists(hash) } -// Get returns a transaction if it is contained in the pool, or nil otherwise. -func (p *BlobPool) Get(hash common.Hash) *types.Transaction { +func (p *BlobPool) getRLP(hash common.Hash) []byte { // Track the amount of time waiting to retrieve a fully resolved blob tx from // the pool and the amount of time actually spent on pulling the data from disk. getStart := time.Now() @@ -1221,14 +1220,31 @@ func (p *BlobPool) Get(hash common.Hash) *types.Transaction { log.Error("Tracked blob transaction missing from store", "hash", hash, "id", id, "err", err) return nil } + return data +} + +// Get returns a transaction if it is contained in the pool, or nil otherwise. +func (p *BlobPool) Get(hash common.Hash) *types.Transaction { + data := p.getRLP(hash) + if len(data) == 0 { + return nil + } item := new(types.Transaction) - if err = rlp.DecodeBytes(data, item); err != nil { - log.Error("Blobs corrupted for traced transaction", "hash", hash, "id", id, "err", err) + if err := rlp.DecodeBytes(data, item); err != nil { + id, _ := p.lookup.storeidOfTx(hash) + + log.Error("Blobs corrupted for traced transaction", + "hash", hash, "id", id, "err", err) return nil } return item } +// GetRLP returns a RLP-encoded transaction if it is contained in the pool. +func (p *BlobPool) GetRLP(hash common.Hash) []byte { + return p.getRLP(hash) +} + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index 2577b47e4..11b814a0d 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -609,6 +609,13 @@ func (pool *CachePool) Get(hash common.Hash) *types.Transaction { return nil } +// GetRLP returns a RLP-encoded transaction if it is contained in the pool. +// +// For the cache pool, this method will return nothing for now. +func (pool *CachePool) GetRLP(hash common.Hash) []byte { + return nil +} + // GetBlobs is not supported by the cache pool, it is just here to // implement the txpool.SubPool interface. func (pool *CachePool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index b9291e074..7db5dbba7 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" ) @@ -1135,6 +1136,20 @@ func (pool *LegacyPool) get(hash common.Hash) *types.Transaction { return pool.all.Get(hash) } +// GetRLP returns a RLP-encoded transaction if it is contained in the pool. +func (pool *LegacyPool) GetRLP(hash common.Hash) []byte { + tx := pool.all.Get(hash) + if tx == nil { + return nil + } + encoded, err := rlp.EncodeToBytes(tx) + if err != nil { + log.Error("Failed to encoded transaction in legacy pool", "hash", hash, "err", err) + return nil + } + return encoded +} + // GetBlobs is not supported by the legacy transaction pool, it is just here to // implement the txpool.SubPool interface. func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 4c4dbf6d2..9c4ba913b 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -132,6 +132,9 @@ type SubPool interface { // Get returns a transaction if it is contained in the pool, or nil otherwise. Get(hash common.Hash) *types.Transaction + // GetRLP returns a RLP-encoded transaction if it is contained in the pool. + GetRLP(hash common.Hash) []byte + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 9f8889ac9..cfe46ef3f 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -312,6 +312,17 @@ func (p *TxPool) Get(hash common.Hash) *types.Transaction { return nil } +// GetRLP returns a RLP-encoded transaction if it is contained in the pool. +func (p *TxPool) GetRLP(hash common.Hash) []byte { + for _, subpool := range p.subpools { + encoded := subpool.GetRLP(hash) + if len(encoded) != 0 { + return encoded + } + } + return nil +} + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 478cead0e..6af073d42 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -435,7 +435,7 @@ func TestRangeLogs(t *testing.T) { } chain, _ := core.GenerateChain(gspec.Config, gspec.ToBlock(), ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) {}) var l uint64 - bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l) + bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatal(err) } diff --git a/eth/handler.go b/eth/handler.go index 03844b0b4..f81e84299 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -71,6 +71,10 @@ type txPool interface { // tx hash. Get(hash common.Hash) *types.Transaction + // GetRLP retrieves the RLP-encoded transaction from local txpool + // with given tx hash. + GetRLP(hash common.Hash) []byte + // Add should add the given transactions to the pool. Add(txs []*types.Transaction, local bool, sync bool) []error diff --git a/eth/handler_test.go b/eth/handler_test.go index b1dc3fb36..77d1cabeb 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" ) @@ -79,6 +80,20 @@ func (p *testTxPool) Get(hash common.Hash) *types.Transaction { return p.pool[hash] } +// Get retrieves the transaction from local txpool with given +// tx hash. +func (p *testTxPool) GetRLP(hash common.Hash) []byte { + p.lock.Lock() + defer p.lock.Unlock() + + tx := p.pool[hash] + if tx != nil { + blob, _ := rlp.EncodeToBytes(tx) + return blob + } + return nil +} + // Add appends a batch of transactions to the pool, and notifies any // listeners if the addition channel is non nil func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 64fc99f6b..75bf08cb4 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -87,6 +87,10 @@ type Backend interface { type TxPool interface { // Get retrieves the transaction from the local txpool with the given hash. Get(hash common.Hash) *types.Transaction + + // GetRLP retrieves the RLP-encoded transaction from the local txpool with + // the given hash. + GetRLP(hash common.Hash) []byte } // MakeProtocols constructs the P2P protocol definitions for `eth`. diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 1c1b3a24a..c9595ca6b 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -18,9 +18,11 @@ package eth import ( "bytes" + "crypto/sha256" "math" "math/big" "math/rand" + "os" "testing" "time" @@ -30,15 +32,18 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" ) var ( @@ -62,12 +67,12 @@ type testBackend struct { // newTestBackend creates an empty chain and wraps it into a mock backend. func newTestBackend(blocks int) *testBackend { - return newTestBackendWithGenerator(blocks, false, nil) + return newTestBackendWithGenerator(blocks, false, false, nil) } // newTestBackendWithGenerator creates a chain with a number of explicitly defined blocks and // wraps it into a mock backend. -func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend { +func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generator func(int, *core.BlockGen)) *testBackend { var ( // Create a database pre-initialize with a genesis block db = rawdb.NewMemoryDatabase() @@ -99,9 +104,21 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, } } + if cancun { + config.CancunTime = u64(0) + config.BlobScheduleConfig = ¶ms.BlobScheduleConfig{ + Cancun: ¶ms.BlobConfig{ + Target: 3, + Max: 6, + UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction, + }, + } + } + gspec := &core.Genesis{ - Config: config, - Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, + Config: config, + Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, + Difficulty: common.Big0, } chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) @@ -115,8 +132,12 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, txconfig := legacypool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals - pool := legacypool.New(txconfig, chain) - txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{pool}) + storage, _ := os.MkdirTemp("", "blobpool-") + defer os.RemoveAll(storage) + + blobPool := blobpool.New(blobpool.Config{Datadir: storage}, chain) + legacyPool := legacypool.New(txconfig, chain) + txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{legacyPool, blobPool}) return &testBackend{ db: db, @@ -351,7 +372,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { } } - backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen) + backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen) defer backend.close() peer, _ := newTestPeer("peer", protocol, backend) @@ -471,7 +492,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) { } } // Assemble the test environment - backend := newTestBackendWithGenerator(4, false, generator) + backend := newTestBackendWithGenerator(4, false, false, generator) defer backend.close() peer, _ := newTestPeer("peer", protocol, backend) @@ -548,7 +569,7 @@ func setup() (*testBackend, *testPeer) { block.SetExtra([]byte("yeehaw")) } } - backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen) + backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen) peer, _ := newTestPeer("peer", ETH68, backend) // Discard all messages go func() { @@ -573,3 +594,80 @@ func FuzzEthProtocolHandlers(f *testing.F) { handler(backend, decoder{msg: msg}, peer.Peer) }) } + +func TestGetPooledTransaction(t *testing.T) { + t.Run("blobTx", func(t *testing.T) { + testGetPooledTransaction(t, true) + }) + t.Run("legacyTx", func(t *testing.T) { + testGetPooledTransaction(t, false) + }) +} + +func testGetPooledTransaction(t *testing.T, blobTx bool) { + var ( + emptyBlob = kzg4844.Blob{} + emptyBlobs = []kzg4844.Blob{emptyBlob} + emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob) + emptyBlobProof, _ = kzg4844.ComputeBlobProof(&emptyBlob, emptyBlobCommit) + emptyBlobHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit) + ) + backend := newTestBackendWithGenerator(0, true, true, nil) + defer backend.close() + + peer, _ := newTestPeer("peer", ETH68, backend) + defer peer.close() + + var ( + tx *types.Transaction + err error + signer = types.NewCancunSigner(params.TestChainConfig.ChainID) + ) + if blobTx { + tx, err = types.SignNewTx(testKey, signer, &types.BlobTx{ + ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID), + Nonce: 0, + GasTipCap: uint256.NewInt(20_000_000_000), + GasFeeCap: uint256.NewInt(21_000_000_000), + Gas: 21000, + To: testAddr, + BlobHashes: []common.Hash{emptyBlobHash}, + BlobFeeCap: uint256.MustFromBig(common.Big1), + Sidecar: &types.BlobTxSidecar{ + Blobs: emptyBlobs, + Commitments: []kzg4844.Commitment{emptyBlobCommit}, + Proofs: []kzg4844.Proof{emptyBlobProof}, + }, + }) + if err != nil { + t.Fatal(err) + } + } else { + tx, err = types.SignTx( + types.NewTransaction(0, testAddr, big.NewInt(10_000), params.TxGas, big.NewInt(1_000_000_000), nil), + signer, + testKey, + ) + if err != nil { + t.Fatal(err) + } + } + errs := backend.txpool.Add([]*types.Transaction{tx}, false, true) + for _, err := range errs { + if err != nil { + t.Fatal(err) + } + } + + // Send the hash request and verify the response + p2p.Send(peer.app, GetPooledTransactionsMsg, GetPooledTransactionsPacket{ + RequestId: 123, + GetPooledTransactionsRequest: []common.Hash{tx.Hash()}, + }) + if err := p2p.ExpectMsg(peer.app, PooledTransactionsMsg, PooledTransactionsPacket{ + RequestId: 123, + PooledTransactionsResponse: []*types.Transaction{tx}, + }); err != nil { + t.Errorf("pooled transaction mismatch: %v", err) + } +} diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index f5aaf4ab7..18b6d0cdf 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -428,18 +428,13 @@ func answerGetPooledTransactions(backend Backend, query GetPooledTransactionsReq break } // Retrieve the requested transaction, skipping if unknown to us - tx := backend.TxPool().Get(hash) - if tx == nil { + encoded := backend.TxPool().GetRLP(hash) + if len(encoded) == 0 { continue } - // If known, encode and queue for response packet - if encoded, err := rlp.EncodeToBytes(tx); err != nil { - log.Error("Failed to encode transaction", "err", err) - } else { - hashes = append(hashes, hash) - txs = append(txs, encoded) - bytes += len(encoded) - } + hashes = append(hashes, hash) + txs = append(txs, encoded) + bytes += len(encoded) } return hashes, txs } From e3cd81d9b7dd9fd3cdba5133c453d3a23ea3f105 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 19 Mar 2025 07:21:40 +0100 Subject: [PATCH 221/354] core/types: reduce allocs in transaction signing (#31258) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR roughly halves the number of allocations needed to compute the sigHash for a transaction. This sigHash is used whenever we recover a signature of a transaction, so quite often. During a recent benchmark full syncing on Holesky, roughly 2.8% of all allocations were happening here because the fields from the transaction would be copied multiple times. ``` 66168733 153175654 (flat, cum) 2.80% of Total . . 368:func (s londonSigner) Hash(tx *Transaction) common.Hash { . . 369: if tx.Type() != DynamicFeeTxType { . . 370: return s.eip2930Signer.Hash(tx) . . 371: } . 19169966 372: return prefixedRlpHash( . . 373: tx.Type(), 26442187 26442187 374: []interface{}{ . . 375: s.chainId, 6848616 6848616 376: tx.Nonce(), . 19694077 377: tx.GasTipCap(), . 18956774 378: tx.GasFeeCap(), 6357089 6357089 379: tx.Gas(), . 12321050 380: tx.To(), . 16865054 381: tx.Value(), 13435187 13435187 382: tx.Data(), 13085654 13085654 383: tx.AccessList(), . . 384: }) . . 385:} ``` This PR reduces the allocations and speeds up the computation of the sigHash by ~22%, which is quite significantly given that this operation involves a call to Keccak ``` // BenchmarkHash-8 440082 2639 ns/op 384 B/op 13 allocs/op // BenchmarkHash-8 493566 2033 ns/op 240 B/op 6 allocs/op ``` ``` Hash-8 2.691µ ± 8% 2.097µ ± 9% -22.07% (p=0.000 n=10) ``` It also kinda cleans up stuff in my opinion, since the transaction should itself know best how to compute the sighash ![Screenshot_2025-02-25_13-52-41](https://github.com/user-attachments/assets/e2b268aa-e137-417d-926b-f3619daef748) --------- Co-authored-by: Gary Rong --- core/types/transaction.go | 3 ++ core/types/transaction_signing.go | 70 +++---------------------------- core/types/transaction_test.go | 17 ++++++++ core/types/tx_access_list.go | 15 +++++++ core/types/tx_blob.go | 18 ++++++++ core/types/tx_dynamic_fee.go | 16 +++++++ core/types/tx_legacy.go | 13 ++++++ core/types/tx_setcode.go | 17 ++++++++ 8 files changed, 105 insertions(+), 64 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 4e48248b4..a2f410463 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -100,6 +100,9 @@ type TxData interface { encode(*bytes.Buffer) error decode([]byte) error + + // sigHash returns the hash of the transaction that is ought to be signed + sigHash(*big.Int) common.Hash } // EncodeRLP implements rlp.Encoder diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 030fc472a..89c08aedd 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -233,20 +233,7 @@ func (s pragueSigner) Hash(tx *Transaction) common.Hash { if tx.Type() != SetCodeTxType { return s.cancunSigner.Hash(tx) } - return prefixedRlpHash( - tx.Type(), - []interface{}{ - s.chainId, - tx.Nonce(), - tx.GasTipCap(), - tx.GasFeeCap(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - tx.AccessList(), - tx.SetCodeAuthorizations(), - }) + return tx.inner.sigHash(s.chainId) } type cancunSigner struct{ londonSigner } @@ -301,21 +288,7 @@ func (s cancunSigner) Hash(tx *Transaction) common.Hash { if tx.Type() != BlobTxType { return s.londonSigner.Hash(tx) } - return prefixedRlpHash( - tx.Type(), - []interface{}{ - s.chainId, - tx.Nonce(), - tx.GasTipCap(), - tx.GasFeeCap(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - tx.AccessList(), - tx.BlobGasFeeCap(), - tx.BlobHashes(), - }) + return tx.inner.sigHash(s.chainId) } type londonSigner struct{ eip2930Signer } @@ -369,19 +342,7 @@ func (s londonSigner) Hash(tx *Transaction) common.Hash { if tx.Type() != DynamicFeeTxType { return s.eip2930Signer.Hash(tx) } - return prefixedRlpHash( - tx.Type(), - []interface{}{ - s.chainId, - tx.Nonce(), - tx.GasTipCap(), - tx.GasFeeCap(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - tx.AccessList(), - }) + return tx.inner.sigHash(s.chainId) } type eip2930Signer struct{ EIP155Signer } @@ -444,18 +405,7 @@ func (s eip2930Signer) Hash(tx *Transaction) common.Hash { case LegacyTxType: return s.EIP155Signer.Hash(tx) case AccessListTxType: - return prefixedRlpHash( - tx.Type(), - []interface{}{ - s.chainId, - tx.Nonce(), - tx.GasPrice(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - tx.AccessList(), - }) + return tx.inner.sigHash(s.chainId) default: // This _should_ not happen, but in case someone sends in a bad // json struct via RPC, it's probably more prudent to return an @@ -525,15 +475,7 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big // Hash returns the hash to be signed by the sender. // It does not uniquely identify the transaction. func (s EIP155Signer) Hash(tx *Transaction) common.Hash { - return rlpHash([]interface{}{ - tx.Nonce(), - tx.GasPrice(), - tx.Gas(), - tx.To(), - tx.Value(), - tx.Data(), - s.chainId, uint(0), uint(0), - }) + return tx.inner.sigHash(s.chainId) } // HomesteadSigner implements Signer interface using the @@ -597,7 +539,7 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v * // Hash returns the hash to be signed by the sender. // It does not uniquely identify the transaction. func (fs FrontierSigner) Hash(tx *Transaction) common.Hash { - return rlpHash([]interface{}{ + return rlpHash([]any{ tx.Nonce(), tx.GasPrice(), tx.Gas(), diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 17a7dda35..8922448d9 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -576,3 +576,20 @@ func TestYParityJSONUnmarshalling(t *testing.T) { } } } + +func BenchmarkHash(b *testing.B) { + signer := NewLondonSigner(big.NewInt(1)) + to := common.Address{} + tx := NewTx(&DynamicFeeTx{ + ChainID: big.NewInt(123), + Nonce: 1, + Gas: 1000000, + To: &to, + Value: big.NewInt(1), + GasTipCap: big.NewInt(500), + GasFeeCap: big.NewInt(500), + }) + for i := 0; i < b.N; i++ { + signer.Hash(tx) + } +} diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 730a77b75..915de9a8a 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -127,3 +127,18 @@ func (tx *AccessListTx) encode(b *bytes.Buffer) error { func (tx *AccessListTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } + +func (tx *AccessListTx) sigHash(chainID *big.Int) common.Hash { + return prefixedRlpHash( + AccessListTxType, + []any{ + chainID, + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.To, + tx.Value, + tx.Data, + tx.AccessList, + }) +} diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 32401db10..9b1d53958 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -259,3 +259,21 @@ func (tx *BlobTx) decode(input []byte) error { } return nil } + +func (tx *BlobTx) sigHash(chainID *big.Int) common.Hash { + return prefixedRlpHash( + BlobTxType, + []any{ + chainID, + tx.Nonce, + tx.GasTipCap, + tx.GasFeeCap, + tx.Gas, + tx.To, + tx.Value, + tx.Data, + tx.AccessList, + tx.BlobFeeCap, + tx.BlobHashes, + }) +} diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 981755cf7..bba81464f 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -123,3 +123,19 @@ func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error { func (tx *DynamicFeeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } + +func (tx *DynamicFeeTx) sigHash(chainID *big.Int) common.Hash { + return prefixedRlpHash( + DynamicFeeTxType, + []any{ + chainID, + tx.Nonce, + tx.GasTipCap, + tx.GasFeeCap, + tx.Gas, + tx.To, + tx.Value, + tx.Data, + tx.AccessList, + }) +} diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go index 71025b78f..49f0a9880 100644 --- a/core/types/tx_legacy.go +++ b/core/types/tx_legacy.go @@ -123,3 +123,16 @@ func (tx *LegacyTx) encode(*bytes.Buffer) error { func (tx *LegacyTx) decode([]byte) error { panic("decode called on LegacyTx)") } + +// OBS: This is the post-EIP155 hash, the pre-EIP155 does not contain a chainID. +func (tx *LegacyTx) sigHash(chainID *big.Int) common.Hash { + return rlpHash([]any{ + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.To, + tx.Value, + tx.Data, + chainID, uint(0), uint(0), + }) +} diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index 894bac10a..b8e38ef1f 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -223,3 +223,20 @@ func (tx *SetCodeTx) encode(b *bytes.Buffer) error { func (tx *SetCodeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } + +func (tx *SetCodeTx) sigHash(chainID *big.Int) common.Hash { + return prefixedRlpHash( + SetCodeTxType, + []any{ + chainID, + tx.Nonce, + tx.GasTipCap, + tx.GasFeeCap, + tx.Gas, + tx.To, + tx.Value, + tx.Data, + tx.AccessList, + tx.AuthList, + }) +} From b1d16852e266590b2519ef25e0f86eeb267575b5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 19 Mar 2025 16:05:44 +0100 Subject: [PATCH 222/354] core/types: cleanup tx signer logic (#31434) This removes the signer type-train in favor of defining a single object that can handle all tx types. Supported types are enabled via a map. Notably, the new signer also supports disabling legacy transactions. --- cmd/evm/internal/t8ntool/tx_iterator.go | 2 +- core/types/transaction_signing.go | 291 ++++++++---------------- params/forks/forks.go | 4 +- 3 files changed, 98 insertions(+), 199 deletions(-) diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index d4ebb4b39..047626c56 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -102,7 +102,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran if tx.protected { signed, err = types.SignTx(tx.tx, signer, tx.key) } else { - signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key) + signed, err = types.SignTx(tx.tx, types.HomesteadSigner{}, tx.key) } if err != nil { return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 89c08aedd..01aa67c6b 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -20,11 +20,13 @@ import ( "crypto/ecdsa" "errors" "fmt" + "maps" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/params/forks" ) var ErrInvalidChainId = errors.New("invalid chain id for signer") @@ -178,120 +180,122 @@ type Signer interface { Equal(Signer) bool } -type pragueSigner struct{ cancunSigner } - -// NewPragueSigner returns a signer that accepts -// - EIP-7702 set code transactions -// - EIP-4844 blob transactions -// - EIP-1559 dynamic fee transactions -// - EIP-2930 access list transactions, -// - EIP-155 replay protected transactions, and -// - legacy Homestead transactions. -func NewPragueSigner(chainId *big.Int) Signer { - signer, _ := NewCancunSigner(chainId).(cancunSigner) - return pragueSigner{signer} +// modernSigner is the signer implementation that handles non-legacy transaction types. +// For legacy transactions, it defers to one of the legacy signers (frontier, homestead, eip155). +type modernSigner struct { + txtypes map[byte]struct{} + chainID *big.Int + legacy Signer } -func (s pragueSigner) Sender(tx *Transaction) (common.Address, error) { - if tx.Type() != SetCodeTxType { - return s.cancunSigner.Sender(tx) +func newModernSigner(chainID *big.Int, fork forks.Fork) Signer { + if chainID == nil || chainID.Sign() <= 0 { + panic(fmt.Sprintf("invalid chainID %v", chainID)) } - V, R, S := tx.RawSignatureValues() - - // Set code txs are defined to use 0 and 1 as their recovery - // id, add 27 to become equivalent to unprotected Homestead signatures. - V = new(big.Int).Add(V, big.NewInt(27)) - if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) + s := &modernSigner{ + chainID: chainID, + txtypes: make(map[byte]struct{}, 4), } - return recoverPlain(s.Hash(tx), R, S, V, true) + // configure legacy signer + switch { + case fork >= forks.SpuriousDragon: + s.legacy = NewEIP155Signer(chainID) + case fork >= forks.Homestead: + s.legacy = HomesteadSigner{} + default: + s.legacy = FrontierSigner{} + } + s.txtypes[LegacyTxType] = struct{}{} + // configure tx types + if fork >= forks.Berlin { + s.txtypes[AccessListTxType] = struct{}{} + } + if fork >= forks.London { + s.txtypes[DynamicFeeTxType] = struct{}{} + } + if fork >= forks.Cancun { + s.txtypes[BlobTxType] = struct{}{} + } + if fork >= forks.Prague { + s.txtypes[SetCodeTxType] = struct{}{} + } + return s } -func (s pragueSigner) Equal(s2 Signer) bool { - x, ok := s2.(pragueSigner) - return ok && x.chainId.Cmp(s.chainId) == 0 +func (s *modernSigner) ChainID() *big.Int { + return s.chainID } -func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { - txdata, ok := tx.inner.(*SetCodeTx) - if !ok { - return s.cancunSigner.SignatureValues(tx, sig) - } - // Check that chain ID of tx matches the signer. We also accept ID zero here, - // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 { - return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) - } - R, S, _ = decodeSignature(sig) - V = big.NewInt(int64(sig[64])) - return R, S, V, nil +func (s *modernSigner) Equal(s2 Signer) bool { + other, ok := s2.(*modernSigner) + return ok && s.chainID.Cmp(other.chainID) == 0 && maps.Equal(s.txtypes, other.txtypes) && s.legacy.Equal(other.legacy) } -// Hash returns the hash to be signed by the sender. -// It does not uniquely identify the transaction. -func (s pragueSigner) Hash(tx *Transaction) common.Hash { - if tx.Type() != SetCodeTxType { - return s.cancunSigner.Hash(tx) - } - return tx.inner.sigHash(s.chainId) +func (s *modernSigner) Hash(tx *Transaction) common.Hash { + return tx.inner.sigHash(s.chainID) } -type cancunSigner struct{ londonSigner } - -// NewCancunSigner returns a signer that accepts -// - EIP-4844 blob transactions -// - EIP-1559 dynamic fee transactions -// - EIP-2930 access list transactions, -// - EIP-155 replay protected transactions, and -// - legacy Homestead transactions. -func NewCancunSigner(chainId *big.Int) Signer { - return cancunSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}} +func (s *modernSigner) supportsType(txtype byte) bool { + _, ok := s.txtypes[txtype] + return ok } -func (s cancunSigner) Sender(tx *Transaction) (common.Address, error) { - if tx.Type() != BlobTxType { - return s.londonSigner.Sender(tx) +func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) { + tt := tx.Type() + if !s.supportsType(tt) { + return common.Address{}, ErrTxTypeNotSupported } - V, R, S := tx.RawSignatureValues() - // Blob txs are defined to use 0 and 1 as their recovery + if tt == LegacyTxType { + return s.legacy.Sender(tx) + } + if tx.ChainId().Cmp(s.chainID) != 0 { + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainID) + } + // 'modern' txs are defined to use 0 and 1 as their recovery // id, add 27 to become equivalent to unprotected Homestead signatures. + V, R, S := tx.RawSignatureValues() V = new(big.Int).Add(V, big.NewInt(27)) - if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) - } return recoverPlain(s.Hash(tx), R, S, V, true) } -func (s cancunSigner) Equal(s2 Signer) bool { - x, ok := s2.(cancunSigner) - return ok && x.chainId.Cmp(s.chainId) == 0 -} - -func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { - txdata, ok := tx.inner.(*BlobTx) - if !ok { - return s.londonSigner.SignatureValues(tx, sig) +func (s *modernSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { + tt := tx.Type() + if !s.supportsType(tt) { + return nil, nil, nil, ErrTxTypeNotSupported + } + if tt == LegacyTxType { + return s.legacy.SignatureValues(tx, sig) } // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 { - return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) + if tx.inner.chainID().Sign() != 0 && tx.inner.chainID().Cmp(s.chainID) != 0 { + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.inner.chainID(), s.chainID) } R, S, _ = decodeSignature(sig) V = big.NewInt(int64(sig[64])) return R, S, V, nil } -// Hash returns the hash to be signed by the sender. -// It does not uniquely identify the transaction. -func (s cancunSigner) Hash(tx *Transaction) common.Hash { - if tx.Type() != BlobTxType { - return s.londonSigner.Hash(tx) - } - return tx.inner.sigHash(s.chainId) +// NewPragueSigner returns a signer that accepts +// - EIP-7702 set code transactions +// - EIP-4844 blob transactions +// - EIP-1559 dynamic fee transactions +// - EIP-2930 access list transactions, +// - EIP-155 replay protected transactions, and +// - legacy Homestead transactions. +func NewPragueSigner(chainId *big.Int) Signer { + return newModernSigner(chainId, forks.Prague) } -type londonSigner struct{ eip2930Signer } +// NewCancunSigner returns a signer that accepts +// - EIP-4844 blob transactions +// - EIP-1559 dynamic fee transactions +// - EIP-2930 access list transactions, +// - EIP-155 replay protected transactions, and +// - legacy Homestead transactions. +func NewCancunSigner(chainId *big.Int) Signer { + return newModernSigner(chainId, forks.Cancun) +} // NewLondonSigner returns a signer that accepts // - EIP-1559 dynamic fee transactions @@ -299,124 +303,18 @@ type londonSigner struct{ eip2930Signer } // - EIP-155 replay protected transactions, and // - legacy Homestead transactions. func NewLondonSigner(chainId *big.Int) Signer { - return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}} + return newModernSigner(chainId, forks.London) } -func (s londonSigner) Sender(tx *Transaction) (common.Address, error) { - if tx.Type() != DynamicFeeTxType { - return s.eip2930Signer.Sender(tx) - } - V, R, S := tx.RawSignatureValues() - // DynamicFee txs are defined to use 0 and 1 as their recovery - // id, add 27 to become equivalent to unprotected Homestead signatures. - V = new(big.Int).Add(V, big.NewInt(27)) - if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) - } - return recoverPlain(s.Hash(tx), R, S, V, true) -} - -func (s londonSigner) Equal(s2 Signer) bool { - x, ok := s2.(londonSigner) - return ok && x.chainId.Cmp(s.chainId) == 0 -} - -func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { - txdata, ok := tx.inner.(*DynamicFeeTx) - if !ok { - return s.eip2930Signer.SignatureValues(tx, sig) - } - // Check that chain ID of tx matches the signer. We also accept ID zero here, - // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { - return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) - } - R, S, _ = decodeSignature(sig) - V = big.NewInt(int64(sig[64])) - return R, S, V, nil -} - -// Hash returns the hash to be signed by the sender. -// It does not uniquely identify the transaction. -func (s londonSigner) Hash(tx *Transaction) common.Hash { - if tx.Type() != DynamicFeeTxType { - return s.eip2930Signer.Hash(tx) - } - return tx.inner.sigHash(s.chainId) -} - -type eip2930Signer struct{ EIP155Signer } - // NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions, // EIP-155 replay protected transactions, and legacy Homestead transactions. func NewEIP2930Signer(chainId *big.Int) Signer { - return eip2930Signer{NewEIP155Signer(chainId)} -} - -func (s eip2930Signer) ChainID() *big.Int { - return s.chainId -} - -func (s eip2930Signer) Equal(s2 Signer) bool { - x, ok := s2.(eip2930Signer) - return ok && x.chainId.Cmp(s.chainId) == 0 -} - -func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) { - V, R, S := tx.RawSignatureValues() - switch tx.Type() { - case LegacyTxType: - return s.EIP155Signer.Sender(tx) - case AccessListTxType: - // AL txs are defined to use 0 and 1 as their recovery - // id, add 27 to become equivalent to unprotected Homestead signatures. - V = new(big.Int).Add(V, big.NewInt(27)) - default: - return common.Address{}, ErrTxTypeNotSupported - } - if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) - } - return recoverPlain(s.Hash(tx), R, S, V, true) -} - -func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { - switch txdata := tx.inner.(type) { - case *LegacyTx: - return s.EIP155Signer.SignatureValues(tx, sig) - case *AccessListTx: - // Check that chain ID of tx matches the signer. We also accept ID zero here, - // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { - return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) - } - R, S, _ = decodeSignature(sig) - V = big.NewInt(int64(sig[64])) - default: - return nil, nil, nil, ErrTxTypeNotSupported - } - return R, S, V, nil -} - -// Hash returns the hash to be signed by the sender. -// It does not uniquely identify the transaction. -func (s eip2930Signer) Hash(tx *Transaction) common.Hash { - switch tx.Type() { - case LegacyTxType: - return s.EIP155Signer.Hash(tx) - case AccessListTxType: - return tx.inner.sigHash(s.chainId) - default: - // This _should_ not happen, but in case someone sends in a bad - // json struct via RPC, it's probably more prudent to return an - // empty hash instead of killing the node with a panic - //panic("Unsupported transaction type: %d", tx.typ) - return common.Hash{} - } + return newModernSigner(chainId, forks.Berlin) } // EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which // are replay-protected as well as unprotected homestead transactions. +// Deprecated: always use the Signer interface type type EIP155Signer struct { chainId, chainIdMul *big.Int } @@ -478,8 +376,9 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash { return tx.inner.sigHash(s.chainId) } -// HomesteadSigner implements Signer interface using the -// homestead rules. +// HomesteadSigner implements Signer using the homestead rules. The only valid reason to +// use this type is creating legacy transactions which are intentionally not +// replay-protected. type HomesteadSigner struct{ FrontierSigner } func (hs HomesteadSigner) ChainID() *big.Int { @@ -505,8 +404,8 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) { return recoverPlain(hs.Hash(tx), r, s, v, true) } -// FrontierSigner implements Signer interface using the -// frontier rules. +// FrontierSigner implements Signer using the frontier rules. +// Deprecated: always use the Signer interface type type FrontierSigner struct{} func (fs FrontierSigner) ChainID() *big.Int { diff --git a/params/forks/forks.go b/params/forks/forks.go index 2d44e13b0..02f6e5b61 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -24,8 +24,8 @@ const ( FrontierThawing Homestead DAO - TangerineWhistle - SpuriousDragon + TangerineWhistle // a.k.a. the EIP150 fork + SpuriousDragon // a.k.a. the EIP155 fork Byzantium Constantinople Petersburg From f27f85f311ec55f03872fb01841d059536ef97a0 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Mar 2025 13:14:13 +0800 Subject: [PATCH 223/354] cmd/utils: force hash scheme for archive mode (#31439) --- cmd/utils/flags.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 17b776ee4..a589baf8d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1809,12 +1809,16 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn("The flag --txlookuplimit is deprecated and will be removed, please use --history.transactions") cfg.TransactionHistory = ctx.Uint64(TxLookupLimitFlag.Name) } - if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 { - cfg.TransactionHistory = 0 - log.Warn("Disabled transaction unindexing for archive node") + if ctx.String(GCModeFlag.Name) == "archive" { + if cfg.TransactionHistory != 0 { + cfg.TransactionHistory = 0 + log.Warn("Disabled transaction unindexing for archive node") + } - cfg.StateScheme = rawdb.HashScheme - log.Warn("Forcing hash state-scheme for archive mode") + if cfg.StateScheme != rawdb.HashScheme { + cfg.StateScheme = rawdb.HashScheme + log.Warn("Forcing hash state-scheme for archive mode") + } } if ctx.IsSet(LogHistoryFlag.Name) { cfg.LogHistory = ctx.Uint64(LogHistoryFlag.Name) From 5b689d734a4a92271b4055a200cf7828c5d04002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 20 Mar 2025 09:23:10 +0100 Subject: [PATCH 224/354] cmd/workload: fixed filter test request error handling (#31424) This PR fixes the broken request error handling of the workload filter tests. Until now `validateHistoryPruneErr` was invoked with `fq.Err` as an input which was always nil and a timeout or http error was reported as a result content mismatch. Also, in case of `errPrunedHistory` it is wrong to return here without setting an error because then it will look like a valid empty result and the check will later fail. So instead `errPrunedHistory` is always returned now (without printing an error message) and the callers of `run` should handle this special case (typically ignore silently). --- cmd/workload/filtertest.go | 21 ++++++++++-------- cmd/workload/filtertestgen.go | 24 ++++----------------- cmd/workload/filtertestperf.go | 39 ++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/cmd/workload/filtertest.go b/cmd/workload/filtertest.go index bc7685791..52dd6e41a 100644 --- a/cmd/workload/filtertest.go +++ b/cmd/workload/filtertest.go @@ -109,6 +109,9 @@ func (s *filterTestSuite) filterFullRange(t *utesting.T) { func (s *filterTestSuite) queryAndCheck(t *utesting.T, query *filterQuery) { query.run(s.cfg.client, s.cfg.historyPruneBlock) + if query.Err == errPrunedHistory { + return + } if query.Err != nil { t.Errorf("Filter query failed (fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics, query.Err) return @@ -126,6 +129,9 @@ func (s *filterTestSuite) fullRangeQueryAndCheck(t *utesting.T, query *filterQue Topics: query.Topics, } frQuery.run(s.cfg.client, s.cfg.historyPruneBlock) + if frQuery.Err == errPrunedHistory { + return + } if frQuery.Err != nil { t.Errorf("Full range filter query failed (addresses: %v topics: %v error: %v)", frQuery.Address, frQuery.Topics, frQuery.Err) return @@ -206,14 +212,11 @@ func (fq *filterQuery) run(client *client, historyPruneBlock *uint64) { Addresses: fq.Address, Topics: fq.Topics, }) - if err != nil { - if err = validateHistoryPruneErr(fq.Err, uint64(fq.FromBlock), historyPruneBlock); err == errPrunedHistory { - return - } else if err != nil { - fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n", - fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err) - } - fq.Err = err - } fq.results = logs + fq.Err = validateHistoryPruneErr(err, uint64(fq.FromBlock), historyPruneBlock) +} + +func (fq *filterQuery) printError() { + fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n", + fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, fq.Err) } diff --git a/cmd/workload/filtertestgen.go b/cmd/workload/filtertestgen.go index e50ec57b4..6d1f63981 100644 --- a/cmd/workload/filtertestgen.go +++ b/cmd/workload/filtertestgen.go @@ -40,7 +40,6 @@ var ( Action: filterGenCmd, Flags: []cli.Flag{ filterQueryFileFlag, - filterErrorFileFlag, }, } filterQueryFileFlag = &cli.StringFlag{ @@ -72,8 +71,8 @@ func filterGenCmd(ctx *cli.Context) error { query := f.newQuery() query.run(f.client, nil) if query.Err != nil { - f.errors = append(f.errors, query) - continue + query.printError() + exit("filter query failed") } if len(query.results) > 0 && len(query.results) <= maxFilterResultSize { for { @@ -90,8 +89,8 @@ func filterGenCmd(ctx *cli.Context) error { ) } if extQuery.Err != nil { - f.errors = append(f.errors, extQuery) - break + extQuery.printError() + exit("filter query failed") } if len(extQuery.results) > maxFilterResultSize { break @@ -101,7 +100,6 @@ func filterGenCmd(ctx *cli.Context) error { f.storeQuery(query) if time.Since(lastWrite) > time.Second*10 { f.writeQueries() - f.writeErrors() lastWrite = time.Now() } } @@ -112,18 +110,15 @@ func filterGenCmd(ctx *cli.Context) error { type filterTestGen struct { client *client queryFile string - errorFile string finalizedBlock int64 queries [filterBuckets][]*filterQuery - errors []*filterQuery } func newFilterTestGen(ctx *cli.Context) *filterTestGen { return &filterTestGen{ client: makeClient(ctx), queryFile: ctx.String(filterQueryFileFlag.Name), - errorFile: ctx.String(filterErrorFileFlag.Name), } } @@ -360,17 +355,6 @@ func (s *filterTestGen) writeQueries() { file.Close() } -// writeQueries serializes the generated errors to the error file. -func (s *filterTestGen) writeErrors() { - file, err := os.Create(s.errorFile) - if err != nil { - exit(fmt.Errorf("Error creating filter error file %s: %v", s.errorFile, err)) - return - } - defer file.Close() - json.NewEncoder(file).Encode(s.errors) -} - func mustGetFinalizedBlock(client *client) int64 { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() diff --git a/cmd/workload/filtertestperf.go b/cmd/workload/filtertestperf.go index 7f4cad4ab..c7d2fdd02 100644 --- a/cmd/workload/filtertestperf.go +++ b/cmd/workload/filtertestperf.go @@ -17,8 +17,10 @@ package main import ( + "encoding/json" "fmt" "math/rand" + "os" "slices" "sort" "time" @@ -41,7 +43,7 @@ var ( } ) -const passCount = 1 +const passCount = 3 func filterPerfCmd(ctx *cli.Context) error { cfg := testConfigFromCLI(ctx) @@ -61,7 +63,10 @@ func filterPerfCmd(ctx *cli.Context) error { } // Run test queries. - var failed, mismatch int + var ( + failed, pruned, mismatch int + errors []*filterQuery + ) for i := 1; i <= passCount; i++ { fmt.Println("Performance test pass", i, "/", passCount) for len(queries) > 0 { @@ -71,27 +76,35 @@ func filterPerfCmd(ctx *cli.Context) error { queries = queries[:len(queries)-1] start := time.Now() qt.query.run(cfg.client, cfg.historyPruneBlock) + if qt.query.Err == errPrunedHistory { + pruned++ + continue + } qt.runtime = append(qt.runtime, time.Since(start)) slices.Sort(qt.runtime) qt.medianTime = qt.runtime[len(qt.runtime)/2] if qt.query.Err != nil { + qt.query.printError() + errors = append(errors, qt.query) failed++ continue } if rhash := qt.query.calculateHash(); *qt.query.ResultHash != rhash { fmt.Printf("Filter query result mismatch: fromBlock: %d toBlock: %d addresses: %v topics: %v expected hash: %064x calculated hash: %064x\n", qt.query.FromBlock, qt.query.ToBlock, qt.query.Address, qt.query.Topics, *qt.query.ResultHash, rhash) + errors = append(errors, qt.query) + mismatch++ continue } processed = append(processed, qt) if len(processed)%50 == 0 { - fmt.Println(" processed:", len(processed), "remaining", len(queries), "failed:", failed, "result mismatch:", mismatch) + fmt.Println(" processed:", len(processed), "remaining", len(queries), "failed:", failed, "pruned:", pruned, "result mismatch:", mismatch) } } queries, processed = processed, nil } // Show results and stats. - fmt.Println("Performance test finished; processed:", len(queries), "failed:", failed, "result mismatch:", mismatch) + fmt.Println("Performance test finished; processed:", len(queries), "failed:", failed, "pruned:", pruned, "result mismatch:", mismatch) stats := make([]bucketStats, len(f.queries)) var wildcardStats bucketStats for _, qt := range queries { @@ -114,11 +127,14 @@ func filterPerfCmd(ctx *cli.Context) error { sort.Slice(queries, func(i, j int) bool { return queries[i].medianTime > queries[j].medianTime }) - for i := 0; i < 10; i++ { - q := queries[i] + for i, q := range queries { + if i >= 10 { + break + } fmt.Printf("Most expensive query #%-2d median runtime: %13v max runtime: %13v result count: %4d fromBlock: %9d toBlock: %9d addresses: %v topics: %v\n", i+1, q.medianTime, q.runtime[len(q.runtime)-1], len(q.query.results), q.query.FromBlock, q.query.ToBlock, q.query.Address, q.query.Topics) } + writeErrors(ctx.String(filterErrorFileFlag.Name), errors) return nil } @@ -135,3 +151,14 @@ func (st *bucketStats) print(name string) { fmt.Printf("%-20s queries: %4d average block length: %12.2f average log count: %7.2f average runtime: %13v\n", name, st.count, float64(st.blocks)/float64(st.count), float64(st.logs)/float64(st.count), st.runtime/time.Duration(st.count)) } + +// writeQueries serializes the generated errors to the error file. +func writeErrors(errorFile string, errors []*filterQuery) { + file, err := os.Create(errorFile) + if err != nil { + exit(fmt.Errorf("Error creating filter error file %s: %v", errorFile, err)) + return + } + defer file.Close() + json.NewEncoder(file).Encode(errors) +} From 6b615524f8b5ecd350fe47bf8613d846fe763ac3 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:20:51 +0100 Subject: [PATCH 225/354] eth/tracers: hex-encode returnValue (#31216) This is a **breaking change** to the opcode tracer. The top-level `returnValue` field of a trace will be now hex-encoded. If the return data is empty, this field will contain "0x". Fixes #31196 --- eth/tracers/api_test.go | 42 ++++++++++++++++++------------------ eth/tracers/logger/logger.go | 7 +++--- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 7383d4012..dd4c76cd9 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -354,7 +354,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`, }, // Standard JSON trace upon the head, plain transfer. { @@ -366,7 +366,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`, }, // Upon the last state, default to the post block's state { @@ -377,7 +377,7 @@ func TestTraceCall(t *testing.T) { Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))), }, config: nil, - expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`, }, // Before the first transaction, should be failed { @@ -411,7 +411,7 @@ func TestTraceCall(t *testing.T) { }, config: &TraceCallConfig{TxIndex: uintPtr(2)}, expectErr: nil, - expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`, }, // Standard JSON trace upon the non-existent block, error expects { @@ -435,7 +435,7 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, + expect: `{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}`, }, // Tracing on 'pending' should fail: { @@ -458,7 +458,7 @@ func TestTraceCall(t *testing.T) { BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, expectErr: nil, - expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[ + expect: ` {"gas":53018,"failed":false,"returnValue":"0x","structLogs":[ {"pc":0,"op":"NUMBER","gas":24946984,"gasCost":2,"depth":1,"stack":[]}, {"pc":1,"op":"STOP","gas":24946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`, }, @@ -535,7 +535,7 @@ func TestTraceTransaction(t *testing.T) { if !reflect.DeepEqual(have, &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, - ReturnValue: "", + ReturnValue: []byte{}, StructLogs: []json.RawMessage{}, }) { t.Error("Transaction tracing result is different") @@ -596,7 +596,7 @@ func TestTraceBlock(t *testing.T) { // Trace head block { blockNumber: rpc.BlockNumber(genBlocks), - want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash), }, // Trace non-existent block { @@ -606,12 +606,12 @@ func TestTraceBlock(t *testing.T) { // Trace latest block { blockNumber: rpc.LatestBlockNumber, - want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash), }, // Trace pending block { blockNumber: rpc.PendingBlockNumber, - want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash), + want: fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, txHash), }, } for i, tc := range testSuite { @@ -704,7 +704,7 @@ func TestTracingWithOverrides(t *testing.T) { randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, }, }, - want: `{"gas":21000,"failed":false,"returnValue":""}`, + want: `{"gas":21000,"failed":false,"returnValue":"0x"}`, }, // Invalid call without state overriding { @@ -749,7 +749,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`, + want: `{"gas":23347,"failed":false,"returnValue":"0x000000000000000000000000000000000000000000000000000000000000007b"}`, }, { // Override blocknumber blockNumber: rpc.LatestBlockNumber, @@ -761,7 +761,7 @@ func TestTracingWithOverrides(t *testing.T) { config: &TraceCallConfig{ BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, - want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`, + want: `{"gas":59537,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000001337"}`, }, { // Override blocknumber, and query a blockhash blockNumber: rpc.LatestBlockNumber, @@ -781,7 +781,7 @@ func TestTracingWithOverrides(t *testing.T) { config: &TraceCallConfig{ BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, }, - want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, + want: `{"gas":72666,"failed":false,"returnValue":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, }, /* pragma solidity =0.8.12; @@ -815,7 +815,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`, + want: `{"gas":44100,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000001"}`, }, { // Same again, this time with storage override blockNumber: rpc.LatestBlockNumber, @@ -833,7 +833,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, //want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`, - want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`, + want: `{"gas":44100,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000001"}`, }, { // No state override blockNumber: rpc.LatestBlockNumber, @@ -863,7 +863,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000077"}`, + want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000077"}`, }, { // Full state override // The original storage is @@ -901,7 +901,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000011"}`, + want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000011"}`, }, { // Partial state override // The original storage is @@ -939,7 +939,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`, + want: `{"gas":25288,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000055"}`, }, { // Call to precompile ECREC (0x01), but code was modified to add 1 to input blockNumber: rpc.LatestBlockNumber, @@ -1084,7 +1084,7 @@ func TestTraceChain(t *testing.T) { backend.relHook = func() { rel.Add(1) } api := NewAPI(backend) - single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` + single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}` var cases = []struct { start uint64 end uint64 @@ -1198,7 +1198,7 @@ func TestTraceBlockWithBasefee(t *testing.T) { // Trace head block { blockNumber: rpc.BlockNumber(genBlocks), - want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee), + want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"0x","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee), }, } for i, tc := range testSuite { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 02ff8146f..a28cecf13 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -350,14 +350,13 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { failed := l.err != nil returnData := common.CopyBytes(l.output) // Return data when successful and revert reason when reverted, otherwise empty. - returnVal := fmt.Sprintf("%x", returnData) if failed && !errors.Is(l.err, vm.ErrExecutionReverted) { - returnVal = "" + returnData = []byte{} } return json.Marshal(&ExecutionResult{ Gas: l.usedGas, Failed: failed, - ReturnValue: returnVal, + ReturnValue: returnData, StructLogs: l.logs, }) } @@ -527,6 +526,6 @@ func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O type ExecutionResult struct { Gas uint64 `json:"gas"` Failed bool `json:"failed"` - ReturnValue string `json:"returnValue"` + ReturnValue hexutil.Bytes `json:"returnValue"` StructLogs []json.RawMessage `json:"structLogs"` } From 1f686381ff32f2ff5f30690098a4b9e0685fd3ea Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 20 Mar 2025 20:33:13 +0800 Subject: [PATCH 226/354] eth/tracers: fix test (#31445) This pull request fixes a broken unit test ``` === CONT TestTracingWithOverrides api_test.go:1012: result: {"gas":21167,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000002","structLogs":[{"pc":0,"op":"PUSH1","gas":24978860,"gasCost":3,"depth":1,"stack":[]},{"pc":2,"op":"CALLDATALOAD","gas":24978857,"gasCost":3,"depth":1,"stack":["0x0"]},{"pc":3,"op":"PUSH1","gas":24978854,"gasCost":3,"depth":1,"stack":["0x1"]},{"pc":5,"op":"ADD","gas":24978851,"gasCost":3,"depth":1,"stack":["0x1","0x1"]},{"pc":6,"op":"PUSH1","gas":24978848,"gasCost":3,"depth":1,"stack":["0x2"]},{"pc":8,"op":"MSTORE","gas":24978845,"gasCost":6,"depth":1,"stack":["0x2","0x0"]},{"pc":9,"op":"PUSH1","gas":24978839,"gasCost":3,"depth":1,"stack":[]},{"pc":11,"op":"PUSH1","gas":24978836,"gasCost":3,"depth":1,"stack":["0x20"]},{"pc":13,"op":"RETURN","gas":24978833,"gasCost":0,"depth":1,"stack":["0x20","0x0"]}]} api_test.go:1013: test 10, result mismatch, have {21167 false 0x0000000000000000000000000000000000000000000000000000000000000002} , want {21167 false 0000000000000000000000000000000000000000000000000000000000000002} api_test.go:1012: result: {"gas":25664,"failed":false,"returnValue":"0x000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074","structLogs":[]} api_test.go:1013: test 11, result mismatch, have {25664 false 0x000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074} , want {25664 false 000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074} ``` --- eth/tracers/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index dd4c76cd9..f179a6dcf 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -960,7 +960,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":21167,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000002"}`, + want: `{"gas":21167,"failed":false,"returnValue":"0x0000000000000000000000000000000000000000000000000000000000000002"}`, }, { // Call to ECREC Precompiled on a different address, expect the original behaviour of ECREC precompile blockNumber: rpc.LatestBlockNumber, @@ -981,7 +981,7 @@ func TestTracingWithOverrides(t *testing.T) { }, }, }, - want: `{"gas":25664,"failed":false,"returnValue":"000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`, + want: `{"gas":25664,"failed":false,"returnValue":"0x000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`, }, } for i, tc := range testSuite { From 2f992e44bd0d7af7f8fd0dad33adce058c780d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 20 Mar 2025 14:13:58 +0100 Subject: [PATCH 227/354] core/filtermaps: allow log search while head indexing (#31429) This PR changes the matcher syncing conditions so that it is possible to run a search while head indexing is in progress. Previously it was a requirement to have the head indexed in order to perform matcher sync before and after a search. This was unnecessarily strict as the purpose was just to avoid syncing the valid range with the temporary shortened indexed range applied while updating existing head maps. Now the sync condition explicitly checks whether the indexer has a temporary indexed range with some head maps being partially updated. It also fixes a deadlock that happened when matcher synchronization was attempted in the event handler called from the `writeFinishedMaps` periodical callback. --- core/filtermaps/filtermaps.go | 10 ++++++---- core/filtermaps/indexer.go | 14 +++++++++----- core/filtermaps/map_renderer.go | 8 ++++++-- core/filtermaps/matcher_backend.go | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index fe75c1ea7..dfc20521f 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -70,6 +70,7 @@ type FilterMaps struct { indexLock sync.RWMutex indexedRange filterMapsRange indexedView *ChainView // always consistent with the log index + hasTempRange bool // also accessed by indexer and matcher backend but no locking needed. filterMapCache *lru.Cache[uint32, filterMap] @@ -94,7 +95,7 @@ type FilterMaps struct { ptrTailUnindexMap uint32 targetView *ChainView - matcherSyncRequest *FilterMapsMatcherBackend + matcherSyncRequests []*FilterMapsMatcherBackend historyCutoff uint64 finalBlock, lastFinal uint64 lastFinalEpoch uint32 @@ -330,7 +331,7 @@ func (f *FilterMaps) init() error { fmr.blocks = common.NewRange(cp.BlockNumber+1, 0) fmr.maps = common.NewRange(uint32(bestLen)< Date: Thu, 20 Mar 2025 17:11:40 +0100 Subject: [PATCH 228/354] p2p/discover: repeat WHOAREYOU challenge when handshake in progress (#31356) This fixes the handshake in a scenario where the remote end sends two unknown packets in a row. When this happens, we would previously respond to both with a WHOAREYOU challenge, but keep only the latest sent challenge. Transmission is assumed to be unreliable, so any client that sends two request packets simultaneously has to be prepared to follow up on whichever request leads to a handshake. With this fix, we force them to do the handshake that we can actually complete. Fixes #30581 --- p2p/discover/v5_udp.go | 26 +++++++++++- p2p/discover/v5_udp_test.go | 70 +++++++++++++++++++++++++++++++++ p2p/discover/v5wire/encoding.go | 6 +++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 9e849751c..6f7c79715 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -50,11 +50,20 @@ const ( // encoding/decoding and with the handshake; the UDPv5 object handles higher-level concerns. type codecV5 interface { // Encode encodes a packet. - Encode(enode.ID, string, v5wire.Packet, *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) + // + // If the underlying type of 'p' is *v5wire.Whoareyou, a Whoareyou challenge packet is + // encoded. If the 'challenge' parameter is non-nil, the packet is encoded as a + // handshake message packet. Otherwise, the packet will be encoded as an ordinary + // message packet. + Encode(id enode.ID, addr string, p v5wire.Packet, challenge *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) // Decode decodes a packet. It returns a *v5wire.Unknown packet if decryption fails. // The *enode.Node return value is non-nil when the input contains a handshake response. - Decode([]byte, string) (enode.ID, *enode.Node, v5wire.Packet, error) + Decode(b []byte, addr string) (enode.ID, *enode.Node, v5wire.Packet, error) + + // CurrentChallenge returns the most recent WHOAREYOU challenge that was encoded to given node. + // This will return a non-nil value if there is an active handshake attempt with the node, and nil otherwise. + CurrentChallenge(id enode.ID, addr string) *v5wire.Whoareyou } // UDPv5 is the implementation of protocol version 5. @@ -824,6 +833,19 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort // handleUnknown initiates a handshake by responding with WHOAREYOU. func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr netip.AddrPort) { + currentChallenge := t.codec.CurrentChallenge(fromID, fromAddr.String()) + if currentChallenge != nil { + // This case happens when the sender issues multiple concurrent requests. + // Since we only support one in-progress handshake at a time, we need to tell + // them which handshake attempt they need to complete. We tell them to use the + // existing handshake attempt since the response to that one might still be in + // transit. + t.log.Debug("Repeating discv5 handshake challenge", "id", fromID, "addr", fromAddr) + t.sendResponse(fromID, fromAddr, currentChallenge) + return + } + + // Send a fresh challenge. challenge := &v5wire.Whoareyou{Nonce: p.Nonce} crand.Read(challenge.IDNonce[:]) if n := t.GetNode(fromID); n != nil { diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 371f41476..3026dff53 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -140,6 +140,26 @@ func TestUDPv5_unknownPacket(t *testing.T) { test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { check(p, 0) }) +} + +func TestUDPv5_unknownPacketKnownNode(t *testing.T) { + t.Parallel() + test := newUDPV5Test(t) + defer test.close() + + nonce := v5wire.Nonce{1, 2, 3} + check := func(p *v5wire.Whoareyou, wantSeq uint64) { + t.Helper() + if p.Nonce != nonce { + t.Error("wrong nonce in WHOAREYOU:", p.Nonce, nonce) + } + if p.IDNonce == ([16]byte{}) { + t.Error("all zero ID nonce") + } + if p.RecordSeq != wantSeq { + t.Errorf("wrong record seq %d in WHOAREYOU, want %d", p.RecordSeq, wantSeq) + } + } // Make node known. n := test.getNode(test.remotekey, test.remoteaddr).Node() @@ -151,6 +171,42 @@ func TestUDPv5_unknownPacket(t *testing.T) { }) } +// This test checks that, when multiple 'unknown' packets are received during a handshake, +// the node sticks to the first handshake attempt. +func TestUDPv5_handshakeRepeatChallenge(t *testing.T) { + t.Parallel() + test := newUDPV5Test(t) + defer test.close() + + nonce1 := v5wire.Nonce{1} + nonce2 := v5wire.Nonce{2} + nonce3 := v5wire.Nonce{3} + check := func(p *v5wire.Whoareyou, wantNonce v5wire.Nonce) { + t.Helper() + if p.Nonce != wantNonce { + t.Error("wrong nonce in WHOAREYOU:", p.Nonce, wantNonce) + } + } + + // Unknown packet from unknown node. + test.packetIn(&v5wire.Unknown{Nonce: nonce1}) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { + check(p, nonce1) + }) + + // Second unknown packet. Here we expect the response to reference the + // first unknown packet. + test.packetIn(&v5wire.Unknown{Nonce: nonce2}) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { + check(p, nonce1) + }) + // Third unknown packet. This should still return the first nonce. + test.packetIn(&v5wire.Unknown{Nonce: nonce3}) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { + check(p, nonce1) + }) +} + // This test checks that incoming FINDNODE calls are handled correctly. func TestUDPv5_findnodeHandling(t *testing.T) { t.Parallel() @@ -698,6 +754,8 @@ type testCodec struct { test *udpV5Test id enode.ID ctr uint64 + + sentChallenges map[enode.ID]*v5wire.Whoareyou } type testCodecFrame struct { @@ -712,11 +770,23 @@ func (c *testCodec) Encode(toID enode.ID, addr string, p v5wire.Packet, _ *v5wir var authTag v5wire.Nonce binary.BigEndian.PutUint64(authTag[:], c.ctr) + if w, ok := p.(*v5wire.Whoareyou); ok { + // Store recently sent Whoareyou challenges. + if c.sentChallenges == nil { + c.sentChallenges = make(map[enode.ID]*v5wire.Whoareyou) + } + c.sentChallenges[toID] = w + } + penc, _ := rlp.EncodeToBytes(p) frame, err := rlp.EncodeToBytes(testCodecFrame{c.id, authTag, p.Kind(), penc}) return frame, authTag, err } +func (c *testCodec) CurrentChallenge(id enode.ID, addr string) *v5wire.Whoareyou { + return c.sentChallenges[id] +} + func (c *testCodec) Decode(input []byte, addr string) (enode.ID, *enode.Node, v5wire.Packet, error) { frame, p, err := c.decodeFrame(input) if err != nil { diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 904a3ddec..e50b7cd16 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -245,6 +245,12 @@ func (c *Codec) EncodeRaw(id enode.ID, head Header, msgdata []byte) ([]byte, err return c.buf.Bytes(), nil } +// CurrentChallenge returns the latest challenge sent to the given node. +// This will return non-nil while a handshake is in progress. +func (c *Codec) CurrentChallenge(id enode.ID, addr string) *Whoareyou { + return c.sc.getHandshake(id, addr) +} + func (c *Codec) writeHeaders(head *Header) { c.buf.Reset() c.buf.Write(head.IV[:]) From 9f45365e0d966d38f4a1270b26205fe8776525c0 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Mar 2025 05:05:15 +0800 Subject: [PATCH 229/354] core/txpool/legacypool: reject gapped tx from delegated account (#31430) This pull request improves the protection mechanism in the txpool for senders with delegation. A sender with either delegation or pending delegation is now limited to a maximum of one in-flight executable transaction, while gapped transactions will be rejected. Reason: If nonce-gapped transaction from delegated/pending-delegated senders can be acceptable, then it's no-longer possible to send another "executable" transaction with correct nonce due to the policy of at most one inflight tx. The gapped transaction will be stuck in the txpool, with no meaningful way to unlock the sender. --------- Co-authored-by: lightclient --- core/txpool/legacypool/cachepool.go | 34 -------------- core/txpool/legacypool/legacypool.go | 54 ++++++++++++++--------- core/txpool/legacypool/legacypool_test.go | 7 ++- 3 files changed, 38 insertions(+), 57 deletions(-) diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index 11b814a0d..cb9c16861 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -403,40 +403,6 @@ func (pool *CachePool) validateTx(tx *types.Transaction) error { if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil { return err } - return pool.validateAuth(tx) -} - -// validateAuth verifies that the transaction complies with code authorization -// restrictions brought by SetCode transaction type. -func (pool *CachePool) validateAuth(tx *types.Transaction) error { - from, _ := types.Sender(pool.signer, tx) // validated - - // Allow at most one in-flight tx for delegated accounts or those with a - // pending authorization. - if pool.currentState.GetCodeHash(from) != types.EmptyCodeHash || len(pool.all.auths[from]) != 0 { - var ( - count int - exists bool - ) - cached := pool.cached[from] - if cached != nil { - count += cached.Len() - exists = cached.Contains(tx.Nonce()) - } - // Replace the existing in-flight transaction for delegated accounts - // are still supported - if count >= 1 && !exists { - return ErrInflightTxLimitReached - } - } - // Authorities cannot conflict with any cached transactions. - if auths := tx.SetCodeAuthorities(); len(auths) > 0 { - for _, auth := range auths { - if pool.cached[auth] != nil { - return ErrAuthorityReserved - } - } - } return nil } diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 7db5dbba7..a8c056f8d 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -77,6 +77,10 @@ var ( // transactions is reached for specific accounts. ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts") + // ErrOutOfOrderTxFromDelegated is returned when the transaction with gapped + // nonce received from the accounts with delegation or pending delegation. + ErrOutOfOrderTxFromDelegated = errors.New("gapped-nonce tx from delegated accounts") + // ErrAuthorityReserved is returned if a transaction has an authorization // signed by an address which already has in-flight transactions known to the // pool. @@ -727,33 +731,39 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { return pool.validateAuth(tx) } +// checkDelegationLimit determines if the tx sender is delegated or has a +// pending delegation, and if so, ensures they have at most one in-flight +// **executable** transaction, e.g. disallow stacked and gapped transactions +// from the account. +func (pool *LegacyPool) checkDelegationLimit(tx *types.Transaction) error { + from, _ := types.Sender(pool.signer, tx) // validated + + // Short circuit if the sender has neither delegation nor pending delegation. + if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && len(pool.all.auths[from]) == 0 { + return nil + } + pending := pool.pending[from] + if pending == nil { + // Transaction with gapped nonce is not supported for delegated accounts + if pool.pendingNonces.get(from) != tx.Nonce() { + return ErrOutOfOrderTxFromDelegated + } + return nil + } + // Transaction replacement is supported + if pending.Contains(tx.Nonce()) { + return nil + } + return ErrInflightTxLimitReached +} + // validateAuth verifies that the transaction complies with code authorization // restrictions brought by SetCode transaction type. func (pool *LegacyPool) validateAuth(tx *types.Transaction) error { - from, _ := types.Sender(pool.signer, tx) // validated - // Allow at most one in-flight tx for delegated accounts or those with a // pending authorization. - if pool.currentState.GetCodeHash(from) != types.EmptyCodeHash || len(pool.all.auths[from]) != 0 { - var ( - count int - exists bool - ) - pending := pool.pending[from] - if pending != nil { - count += pending.Len() - exists = pending.Contains(tx.Nonce()) - } - queue := pool.queue[from] - if queue != nil { - count += queue.Len() - exists = exists || queue.Contains(tx.Nonce()) - } - // Replace the existing in-flight transaction for delegated accounts - // are still supported - if count >= 1 && !exists { - return ErrInflightTxLimitReached - } + if err := pool.checkDelegationLimit(tx); err != nil { + return err } // Authorities cannot conflict with any pending or queued transactions. if auths := tx.SetCodeAuthorities(); len(auths) > 0 { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index ef887041a..3f269bd69 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -2262,6 +2262,11 @@ func TestSetCodeTransactions(t *testing.T) { aa := common.Address{0xaa, 0xaa} statedb.SetCode(addrA, append(types.DelegationPrefix, aa.Bytes()...)) statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)}) + + // Send gapped transaction, it should be rejected. + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrOutOfOrderTxFromDelegated) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrOutOfOrderTxFromDelegated, err) + } // Send transactions. First is accepted, second is rejected. if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { t.Fatalf("%s: failed to add remote transaction: %v", name, err) @@ -2269,7 +2274,7 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) } - // Also check gapped transaction. + // Check gapped transaction again. if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) } From cae9bb005fca1f171630f32329a564c9657d2268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 21 Mar 2025 10:47:58 +0100 Subject: [PATCH 230/354] core/bloombits: remove old bloombits logic and chain indexer (#31081) This PR is #3 of a 3-part series that implements the new log index intended to replace core/bloombits. Based on https://github.com/ethereum/go-ethereum/pull/31079 and https://github.com/ethereum/go-ethereum/pull/31080 Replaces https://github.com/ethereum/go-ethereum/pull/30370 This part removes the old bloombits package and the chain indexer that was only used by bloombits. Deletes the old bloombits database. FilterMaps data structure explanation: https://gist.github.com/zsfelfoldi/a60795f9da7ae6422f28c7a34e02a07e Log index generator code overview: https://gist.github.com/zsfelfoldi/97105dff0b1a4f5ed557924a24b9b9e7 Search pattern matcher code overview: https://gist.github.com/zsfelfoldi/5981735641c956afb18065e84f8aff34 Note that the possibility of a tree hashing scheme and remote proof protocol are mentioned in the documents above but they are not exactly specified yet. These specs are WIP and will be finalized after the local log indexer/filter code is finalized and merged. --------- Co-authored-by: Felix Lange --- core/blockchain.go | 2 +- core/bloom_indexer.go | 92 ---- core/bloombits/doc.go | 18 - core/bloombits/generator.go | 98 ---- core/bloombits/generator_test.go | 100 ----- core/bloombits/matcher.go | 649 --------------------------- core/bloombits/matcher_test.go | 292 ------------ core/bloombits/scheduler.go | 181 -------- core/bloombits/scheduler_test.go | 103 ----- core/chain_indexer.go | 522 --------------------- core/chain_indexer_test.go | 246 ---------- core/filtermaps/filtermaps.go | 35 +- core/filtermaps/indexer.go | 33 +- core/rawdb/accessors_indexes.go | 56 +-- core/rawdb/accessors_indexes_test.go | 53 --- core/rawdb/database.go | 8 +- core/rawdb/schema.go | 24 +- eth/api_backend.go | 12 - eth/backend.go | 37 +- eth/bloombits.go | 74 --- params/network_params.go | 8 - 21 files changed, 81 insertions(+), 2562 deletions(-) delete mode 100644 core/bloom_indexer.go delete mode 100644 core/bloombits/doc.go delete mode 100644 core/bloombits/generator.go delete mode 100644 core/bloombits/generator_test.go delete mode 100644 core/bloombits/matcher.go delete mode 100644 core/bloombits/matcher_test.go delete mode 100644 core/bloombits/scheduler.go delete mode 100644 core/bloombits/scheduler_test.go delete mode 100644 core/chain_indexer.go delete mode 100644 core/chain_indexer_test.go delete mode 100644 eth/bloombits.go diff --git a/core/blockchain.go b/core/blockchain.go index 5c7c553e1..84a133ca1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -940,7 +940,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha rawdb.DeleteBody(db, hash, num) rawdb.DeleteReceipts(db, hash, num) } - // Todo(rjl493456442) txlookup, bloombits, etc + // Todo(rjl493456442) txlookup, log index, etc } // If SetHead was only called as a chain reparation method, try to skip // touching the header chain altogether, unless the freezer is broken diff --git a/core/bloom_indexer.go b/core/bloom_indexer.go deleted file mode 100644 index 68a35d811..000000000 --- a/core/bloom_indexer.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2021 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 . - -package core - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/core/bloombits" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" -) - -const ( - // bloomThrottling is the time to wait between processing two consecutive index - // sections. It's useful during chain upgrades to prevent disk overload. - bloomThrottling = 100 * time.Millisecond -) - -// BloomIndexer implements a core.ChainIndexer, building up a rotated bloom bits index -// for the Ethereum header bloom filters, permitting blazing fast filtering. -type BloomIndexer struct { - size uint64 // section size to generate bloombits for - db ethdb.Database // database instance to write index data and metadata into - gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index - section uint64 // Section is the section number being processed currently - head common.Hash // Head is the hash of the last header processed -} - -// NewBloomIndexer returns a chain indexer that generates bloom bits data for the -// canonical chain for fast logs filtering. -func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *ChainIndexer { - backend := &BloomIndexer{ - db: db, - size: size, - } - table := rawdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix)) - - return NewChainIndexer(db, table, backend, size, confirms, bloomThrottling, "bloombits") -} - -// Reset implements core.ChainIndexerBackend, starting a new bloombits index -// section. -func (b *BloomIndexer) Reset(ctx context.Context, section uint64, lastSectionHead common.Hash) error { - gen, err := bloombits.NewGenerator(uint(b.size)) - b.gen, b.section, b.head = gen, section, common.Hash{} - return err -} - -// Process implements core.ChainIndexerBackend, adding a new header's bloom into -// the index. -func (b *BloomIndexer) Process(ctx context.Context, header *types.Header) error { - b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom) - b.head = header.Hash() - return nil -} - -// Commit implements core.ChainIndexerBackend, finalizing the bloom section and -// writing it out into the database. -func (b *BloomIndexer) Commit() error { - batch := b.db.NewBatchWithSize((int(b.size) / 8) * types.BloomBitLength) - for i := 0; i < types.BloomBitLength; i++ { - bits, err := b.gen.Bitset(uint(i)) - if err != nil { - return err - } - rawdb.WriteBloomBits(batch, uint(i), b.section, b.head, bitutil.CompressBytes(bits)) - } - return batch.Write() -} - -// Prune returns an empty error since we don't support pruning here. -func (b *BloomIndexer) Prune(threshold uint64) error { - return nil -} diff --git a/core/bloombits/doc.go b/core/bloombits/doc.go deleted file mode 100644 index 3d159e74f..000000000 --- a/core/bloombits/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 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 . - -// Package bloombits implements bloom filtering on batches of data. -package bloombits diff --git a/core/bloombits/generator.go b/core/bloombits/generator.go deleted file mode 100644 index 646151db0..000000000 --- a/core/bloombits/generator.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "errors" - - "github.com/ethereum/go-ethereum/core/types" -) - -var ( - // errSectionOutOfBounds is returned if the user tried to add more bloom filters - // to the batch than available space, or if tries to retrieve above the capacity. - errSectionOutOfBounds = errors.New("section out of bounds") - - // errBloomBitOutOfBounds is returned if the user tried to retrieve specified - // bit bloom above the capacity. - errBloomBitOutOfBounds = errors.New("bloom bit out of bounds") -) - -// Generator takes a number of bloom filters and generates the rotated bloom bits -// to be used for batched filtering. -type Generator struct { - blooms [types.BloomBitLength][]byte // Rotated blooms for per-bit matching - sections uint // Number of sections to batch together - nextSec uint // Next section to set when adding a bloom -} - -// NewGenerator creates a rotated bloom generator that can iteratively fill a -// batched bloom filter's bits. -func NewGenerator(sections uint) (*Generator, error) { - if sections%8 != 0 { - return nil, errors.New("section count not multiple of 8") - } - b := &Generator{sections: sections} - for i := 0; i < types.BloomBitLength; i++ { - b.blooms[i] = make([]byte, sections/8) - } - return b, nil -} - -// AddBloom takes a single bloom filter and sets the corresponding bit column -// in memory accordingly. -func (b *Generator) AddBloom(index uint, bloom types.Bloom) error { - // Make sure we're not adding more bloom filters than our capacity - if b.nextSec >= b.sections { - return errSectionOutOfBounds - } - if b.nextSec != index { - return errors.New("bloom filter with unexpected index") - } - // Rotate the bloom and insert into our collection - byteIndex := b.nextSec / 8 - bitIndex := byte(7 - b.nextSec%8) - for byt := 0; byt < types.BloomByteLength; byt++ { - bloomByte := bloom[types.BloomByteLength-1-byt] - if bloomByte == 0 { - continue - } - base := 8 * byt - b.blooms[base+7][byteIndex] |= ((bloomByte >> 7) & 1) << bitIndex - b.blooms[base+6][byteIndex] |= ((bloomByte >> 6) & 1) << bitIndex - b.blooms[base+5][byteIndex] |= ((bloomByte >> 5) & 1) << bitIndex - b.blooms[base+4][byteIndex] |= ((bloomByte >> 4) & 1) << bitIndex - b.blooms[base+3][byteIndex] |= ((bloomByte >> 3) & 1) << bitIndex - b.blooms[base+2][byteIndex] |= ((bloomByte >> 2) & 1) << bitIndex - b.blooms[base+1][byteIndex] |= ((bloomByte >> 1) & 1) << bitIndex - b.blooms[base][byteIndex] |= (bloomByte & 1) << bitIndex - } - b.nextSec++ - return nil -} - -// Bitset returns the bit vector belonging to the given bit index after all -// blooms have been added. -func (b *Generator) Bitset(idx uint) ([]byte, error) { - if b.nextSec != b.sections { - return nil, errors.New("bloom not fully generated yet") - } - if idx >= types.BloomBitLength { - return nil, errBloomBitOutOfBounds - } - return b.blooms[idx], nil -} diff --git a/core/bloombits/generator_test.go b/core/bloombits/generator_test.go deleted file mode 100644 index ac1aee0b2..000000000 --- a/core/bloombits/generator_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "bytes" - crand "crypto/rand" - "math/rand" - "testing" - - "github.com/ethereum/go-ethereum/core/types" -) - -// Tests that batched bloom bits are correctly rotated from the input bloom -// filters. -func TestGenerator(t *testing.T) { - // Generate the input and the rotated output - var input, output [types.BloomBitLength][types.BloomByteLength]byte - - for i := 0; i < types.BloomBitLength; i++ { - for j := 0; j < types.BloomBitLength; j++ { - bit := byte(rand.Int() % 2) - - input[i][j/8] |= bit << byte(7-j%8) - output[types.BloomBitLength-1-j][i/8] |= bit << byte(7-i%8) - } - } - // Crunch the input through the generator and verify the result - gen, err := NewGenerator(types.BloomBitLength) - if err != nil { - t.Fatalf("failed to create bloombit generator: %v", err) - } - for i, bloom := range input { - if err := gen.AddBloom(uint(i), bloom); err != nil { - t.Fatalf("bloom %d: failed to add: %v", i, err) - } - } - for i, want := range output { - have, err := gen.Bitset(uint(i)) - if err != nil { - t.Fatalf("output %d: failed to retrieve bits: %v", i, err) - } - if !bytes.Equal(have, want[:]) { - t.Errorf("output %d: bit vector mismatch have %x, want %x", i, have, want) - } - } -} - -func BenchmarkGenerator(b *testing.B) { - var input [types.BloomBitLength][types.BloomByteLength]byte - b.Run("empty", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - // Crunch the input through the generator and verify the result - gen, err := NewGenerator(types.BloomBitLength) - if err != nil { - b.Fatalf("failed to create bloombit generator: %v", err) - } - for j, bloom := range &input { - if err := gen.AddBloom(uint(j), bloom); err != nil { - b.Fatalf("bloom %d: failed to add: %v", i, err) - } - } - } - }) - for i := 0; i < types.BloomBitLength; i++ { - crand.Read(input[i][:]) - } - b.Run("random", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - // Crunch the input through the generator and verify the result - gen, err := NewGenerator(types.BloomBitLength) - if err != nil { - b.Fatalf("failed to create bloombit generator: %v", err) - } - for j, bloom := range &input { - if err := gen.AddBloom(uint(j), bloom); err != nil { - b.Fatalf("bloom %d: failed to add: %v", i, err) - } - } - } - }) -} diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go deleted file mode 100644 index 486581fe2..000000000 --- a/core/bloombits/matcher.go +++ /dev/null @@ -1,649 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "bytes" - "context" - "errors" - "math" - "sort" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/crypto" -) - -// bloomIndexes represents the bit indexes inside the bloom filter that belong -// to some key. -type bloomIndexes [3]uint - -// calcBloomIndexes returns the bloom filter bit indexes belonging to the given key. -func calcBloomIndexes(b []byte) bloomIndexes { - b = crypto.Keccak256(b) - - var idxs bloomIndexes - for i := 0; i < len(idxs); i++ { - idxs[i] = (uint(b[2*i])<<8)&2047 + uint(b[2*i+1]) - } - return idxs -} - -// partialMatches with a non-nil vector represents a section in which some sub- -// matchers have already found potential matches. Subsequent sub-matchers will -// binary AND their matches with this vector. If vector is nil, it represents a -// section to be processed by the first sub-matcher. -type partialMatches struct { - section uint64 - bitset []byte -} - -// Retrieval represents a request for retrieval task assignments for a given -// bit with the given number of fetch elements, or a response for such a request. -// It can also have the actual results set to be used as a delivery data struct. -// -// The context and error fields are used by the light client to terminate matching -// early if an error is encountered on some path of the pipeline. -type Retrieval struct { - Bit uint - Sections []uint64 - Bitsets [][]byte - - Context context.Context - Error error -} - -// Matcher is a pipelined system of schedulers and logic matchers which perform -// binary AND/OR operations on the bit-streams, creating a stream of potential -// blocks to inspect for data content. -type Matcher struct { - sectionSize uint64 // Size of the data batches to filter on - - filters [][]bloomIndexes // Filter the system is matching for - schedulers map[uint]*scheduler // Retrieval schedulers for loading bloom bits - - retrievers chan chan uint // Retriever processes waiting for bit allocations - counters chan chan uint // Retriever processes waiting for task count reports - retrievals chan chan *Retrieval // Retriever processes waiting for task allocations - deliveries chan *Retrieval // Retriever processes waiting for task response deliveries - - running atomic.Bool // Atomic flag whether a session is live or not -} - -// NewMatcher creates a new pipeline for retrieving bloom bit streams and doing -// address and topic filtering on them. Setting a filter component to `nil` is -// allowed and will result in that filter rule being skipped (OR 0x11...1). -func NewMatcher(sectionSize uint64, filters [][][]byte) *Matcher { - // Create the matcher instance - m := &Matcher{ - sectionSize: sectionSize, - schedulers: make(map[uint]*scheduler), - retrievers: make(chan chan uint), - counters: make(chan chan uint), - retrievals: make(chan chan *Retrieval), - deliveries: make(chan *Retrieval), - } - // Calculate the bloom bit indexes for the groups we're interested in - m.filters = nil - - for _, filter := range filters { - // Gather the bit indexes of the filter rule, special casing the nil filter - if len(filter) == 0 { - continue - } - bloomBits := make([]bloomIndexes, len(filter)) - for i, clause := range filter { - if clause == nil { - bloomBits = nil - break - } - bloomBits[i] = calcBloomIndexes(clause) - } - // Accumulate the filter rules if no nil rule was within - if bloomBits != nil { - m.filters = append(m.filters, bloomBits) - } - } - // For every bit, create a scheduler to load/download the bit vectors - for _, bloomIndexLists := range m.filters { - for _, bloomIndexList := range bloomIndexLists { - for _, bloomIndex := range bloomIndexList { - m.addScheduler(bloomIndex) - } - } - } - return m -} - -// addScheduler adds a bit stream retrieval scheduler for the given bit index if -// it has not existed before. If the bit is already selected for filtering, the -// existing scheduler can be used. -func (m *Matcher) addScheduler(idx uint) { - if _, ok := m.schedulers[idx]; ok { - return - } - m.schedulers[idx] = newScheduler(idx) -} - -// Start starts the matching process and returns a stream of bloom matches in -// a given range of blocks. If there are no more matches in the range, the result -// channel is closed. -func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) { - // Make sure we're not creating concurrent sessions - if m.running.Swap(true) { - return nil, errors.New("matcher already running") - } - defer m.running.Store(false) - - // Initiate a new matching round - session := &MatcherSession{ - matcher: m, - quit: make(chan struct{}), - ctx: ctx, - } - for _, scheduler := range m.schedulers { - scheduler.reset() - } - sink := m.run(begin, end, cap(results), session) - - // Read the output from the result sink and deliver to the user - session.pend.Add(1) - go func() { - defer session.pend.Done() - defer close(results) - - for { - select { - case <-session.quit: - return - - case res, ok := <-sink: - // New match result found - if !ok { - return - } - // Calculate the first and last blocks of the section - sectionStart := res.section * m.sectionSize - - first := sectionStart - if begin > first { - first = begin - } - last := sectionStart + m.sectionSize - 1 - if end < last { - last = end - } - // Iterate over all the blocks in the section and return the matching ones - for i := first; i <= last; i++ { - // Skip the entire byte if no matches are found inside (and we're processing an entire byte!) - next := res.bitset[(i-sectionStart)/8] - if next == 0 { - if i%8 == 0 { - i += 7 - } - continue - } - // Some bit it set, do the actual submatching - if bit := 7 - i%8; next&(1<= req.section }) - requests[req.bit] = append(queue[:index], append([]uint64{req.section}, queue[index:]...)...) - - // If it's a new bit and we have waiting fetchers, allocate to them - if len(queue) == 0 { - assign(req.bit) - } - - case fetcher := <-retrievers: - // New retriever arrived, find the lowest section-ed bit to assign - bit, best := uint(0), uint64(math.MaxUint64) - for idx := range unallocs { - if requests[idx][0] < best { - bit, best = idx, requests[idx][0] - } - } - // Stop tracking this bit (and alloc notifications if no more work is available) - delete(unallocs, bit) - if len(unallocs) == 0 { - retrievers = nil - } - allocs++ - fetcher <- bit - - case fetcher := <-m.counters: - // New task count request arrives, return number of items - fetcher <- uint(len(requests[<-fetcher])) - - case fetcher := <-m.retrievals: - // New fetcher waiting for tasks to retrieve, assign - task := <-fetcher - if want := len(task.Sections); want >= len(requests[task.Bit]) { - task.Sections = requests[task.Bit] - delete(requests, task.Bit) - } else { - task.Sections = append(task.Sections[:0], requests[task.Bit][:want]...) - requests[task.Bit] = append(requests[task.Bit][:0], requests[task.Bit][want:]...) - } - fetcher <- task - - // If anything was left unallocated, try to assign to someone else - if len(requests[task.Bit]) > 0 { - assign(task.Bit) - } - - case result := <-m.deliveries: - // New retrieval task response from fetcher, split out missing sections and - // deliver complete ones - var ( - sections = make([]uint64, 0, len(result.Sections)) - bitsets = make([][]byte, 0, len(result.Bitsets)) - missing = make([]uint64, 0, len(result.Sections)) - ) - for i, bitset := range result.Bitsets { - if len(bitset) == 0 { - missing = append(missing, result.Sections[i]) - continue - } - sections = append(sections, result.Sections[i]) - bitsets = append(bitsets, bitset) - } - m.schedulers[result.Bit].deliver(sections, bitsets) - allocs-- - - // Reschedule missing sections and allocate bit if newly available - if len(missing) > 0 { - queue := requests[result.Bit] - for _, section := range missing { - index := sort.Search(len(queue), func(i int) bool { return queue[i] >= section }) - queue = append(queue[:index], append([]uint64{section}, queue[index:]...)...) - } - requests[result.Bit] = queue - - if len(queue) == len(missing) { - assign(result.Bit) - } - } - - // End the session when all pending deliveries have arrived. - if shutdown == nil && allocs == 0 { - return - } - } - } -} - -// MatcherSession is returned by a started matcher to be used as a terminator -// for the actively running matching operation. -type MatcherSession struct { - matcher *Matcher - - closer sync.Once // Sync object to ensure we only ever close once - quit chan struct{} // Quit channel to request pipeline termination - - ctx context.Context // Context used by the light client to abort filtering - err error // Global error to track retrieval failures deep in the chain - errLock sync.Mutex - - pend sync.WaitGroup -} - -// Close stops the matching process and waits for all subprocesses to terminate -// before returning. The timeout may be used for graceful shutdown, allowing the -// currently running retrievals to complete before this time. -func (s *MatcherSession) Close() { - s.closer.Do(func() { - // Signal termination and wait for all goroutines to tear down - close(s.quit) - s.pend.Wait() - }) -} - -// Error returns any failure encountered during the matching session. -func (s *MatcherSession) Error() error { - s.errLock.Lock() - defer s.errLock.Unlock() - - return s.err -} - -// allocateRetrieval assigns a bloom bit index to a client process that can either -// immediately request and fetch the section contents assigned to this bit or wait -// a little while for more sections to be requested. -func (s *MatcherSession) allocateRetrieval() (uint, bool) { - fetcher := make(chan uint) - - select { - case <-s.quit: - return 0, false - case s.matcher.retrievers <- fetcher: - bit, ok := <-fetcher - return bit, ok - } -} - -// pendingSections returns the number of pending section retrievals belonging to -// the given bloom bit index. -func (s *MatcherSession) pendingSections(bit uint) int { - fetcher := make(chan uint) - - select { - case <-s.quit: - return 0 - case s.matcher.counters <- fetcher: - fetcher <- bit - return int(<-fetcher) - } -} - -// allocateSections assigns all or part of an already allocated bit-task queue -// to the requesting process. -func (s *MatcherSession) allocateSections(bit uint, count int) []uint64 { - fetcher := make(chan *Retrieval) - - select { - case <-s.quit: - return nil - case s.matcher.retrievals <- fetcher: - task := &Retrieval{ - Bit: bit, - Sections: make([]uint64, count), - } - fetcher <- task - return (<-fetcher).Sections - } -} - -// deliverSections delivers a batch of section bit-vectors for a specific bloom -// bit index to be injected into the processing pipeline. -func (s *MatcherSession) deliverSections(bit uint, sections []uint64, bitsets [][]byte) { - s.matcher.deliveries <- &Retrieval{Bit: bit, Sections: sections, Bitsets: bitsets} -} - -// Multiplex polls the matcher session for retrieval tasks and multiplexes it into -// the requested retrieval queue to be serviced together with other sessions. -// -// This method will block for the lifetime of the session. Even after termination -// of the session, any request in-flight need to be responded to! Empty responses -// are fine though in that case. -func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan *Retrieval) { - waitTimer := time.NewTimer(wait) - defer waitTimer.Stop() - - for { - // Allocate a new bloom bit index to retrieve data for, stopping when done - bit, ok := s.allocateRetrieval() - if !ok { - return - } - // Bit allocated, throttle a bit if we're below our batch limit - if s.pendingSections(bit) < batch { - waitTimer.Reset(wait) - select { - case <-s.quit: - // Session terminating, we can't meaningfully service, abort - s.allocateSections(bit, 0) - s.deliverSections(bit, []uint64{}, [][]byte{}) - return - - case <-waitTimer.C: - // Throttling up, fetch whatever is available - } - } - // Allocate as much as we can handle and request servicing - sections := s.allocateSections(bit, batch) - request := make(chan *Retrieval) - - select { - case <-s.quit: - // Session terminating, we can't meaningfully service, abort - s.deliverSections(bit, sections, make([][]byte, len(sections))) - return - - case mux <- request: - // Retrieval accepted, something must arrive before we're aborting - request <- &Retrieval{Bit: bit, Sections: sections, Context: s.ctx} - - result := <-request - - // Deliver a result before s.Close() to avoid a deadlock - s.deliverSections(result.Bit, result.Sections, result.Bitsets) - - if result.Error != nil { - s.errLock.Lock() - s.err = result.Error - s.errLock.Unlock() - s.Close() - } - } - } -} diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go deleted file mode 100644 index 7f3d5f279..000000000 --- a/core/bloombits/matcher_test.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "context" - "math/rand" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" -) - -const testSectionSize = 4096 - -// Tests that wildcard filter rules (nil) can be specified and are handled well. -func TestMatcherWildcards(t *testing.T) { - t.Parallel() - matcher := NewMatcher(testSectionSize, [][][]byte{ - {common.Address{}.Bytes(), common.Address{0x01}.Bytes()}, // Default address is not a wildcard - {common.Hash{}.Bytes(), common.Hash{0x01}.Bytes()}, // Default hash is not a wildcard - {common.Hash{0x01}.Bytes()}, // Plain rule, sanity check - {common.Hash{0x01}.Bytes(), nil}, // Wildcard suffix, drop rule - {nil, common.Hash{0x01}.Bytes()}, // Wildcard prefix, drop rule - {nil, nil}, // Wildcard combo, drop rule - {}, // Inited wildcard rule, drop rule - nil, // Proper wildcard rule, drop rule - }) - if len(matcher.filters) != 3 { - t.Fatalf("filter system size mismatch: have %d, want %d", len(matcher.filters), 3) - } - if len(matcher.filters[0]) != 2 { - t.Fatalf("address clause size mismatch: have %d, want %d", len(matcher.filters[0]), 2) - } - if len(matcher.filters[1]) != 2 { - t.Fatalf("combo topic clause size mismatch: have %d, want %d", len(matcher.filters[1]), 2) - } - if len(matcher.filters[2]) != 1 { - t.Fatalf("singletone topic clause size mismatch: have %d, want %d", len(matcher.filters[2]), 1) - } -} - -// Tests the matcher pipeline on a single continuous workflow without interrupts. -func TestMatcherContinuous(t *testing.T) { - t.Parallel() - testMatcherDiffBatches(t, [][]bloomIndexes{{{10, 20, 30}}}, 0, 100000, false, 75) - testMatcherDiffBatches(t, [][]bloomIndexes{{{32, 3125, 100}}, {{40, 50, 10}}}, 0, 100000, false, 81) - testMatcherDiffBatches(t, [][]bloomIndexes{{{4, 8, 11}, {7, 8, 17}}, {{9, 9, 12}, {15, 20, 13}}, {{18, 15, 15}, {12, 10, 4}}}, 0, 10000, false, 36) -} - -// Tests the matcher pipeline on a constantly interrupted and resumed work pattern -// with the aim of ensuring data items are requested only once. -func TestMatcherIntermittent(t *testing.T) { - t.Parallel() - testMatcherDiffBatches(t, [][]bloomIndexes{{{10, 20, 30}}}, 0, 100000, true, 75) - testMatcherDiffBatches(t, [][]bloomIndexes{{{32, 3125, 100}}, {{40, 50, 10}}}, 0, 100000, true, 81) - testMatcherDiffBatches(t, [][]bloomIndexes{{{4, 8, 11}, {7, 8, 17}}, {{9, 9, 12}, {15, 20, 13}}, {{18, 15, 15}, {12, 10, 4}}}, 0, 10000, true, 36) -} - -// Tests the matcher pipeline on random input to hopefully catch anomalies. -func TestMatcherRandom(t *testing.T) { - t.Parallel() - for i := 0; i < 10; i++ { - testMatcherBothModes(t, makeRandomIndexes([]int{1}, 50), 0, 10000, 0) - testMatcherBothModes(t, makeRandomIndexes([]int{3}, 50), 0, 10000, 0) - testMatcherBothModes(t, makeRandomIndexes([]int{2, 2, 2}, 20), 0, 10000, 0) - testMatcherBothModes(t, makeRandomIndexes([]int{5, 5, 5}, 50), 0, 10000, 0) - testMatcherBothModes(t, makeRandomIndexes([]int{4, 4, 4}, 20), 0, 10000, 0) - } -} - -// Tests that the matcher can properly find matches if the starting block is -// shifted from a multiple of 8. This is needed to cover an optimisation with -// bitset matching https://github.com/ethereum/go-ethereum/issues/15309. -func TestMatcherShifted(t *testing.T) { - t.Parallel() - // Block 0 always matches in the tests, skip ahead of first 8 blocks with the - // start to get a potential zero byte in the matcher bitset. - - // To keep the second bitset byte zero, the filter must only match for the first - // time in block 16, so doing an all-16 bit filter should suffice. - - // To keep the starting block non divisible by 8, block number 9 is the first - // that would introduce a shift and not match block 0. - testMatcherBothModes(t, [][]bloomIndexes{{{16, 16, 16}}}, 9, 64, 0) -} - -// Tests that matching on everything doesn't crash (special case internally). -func TestWildcardMatcher(t *testing.T) { - t.Parallel() - testMatcherBothModes(t, nil, 0, 10000, 0) -} - -// makeRandomIndexes generates a random filter system, composed of multiple filter -// criteria, each having one bloom list component for the address and arbitrarily -// many topic bloom list components. -func makeRandomIndexes(lengths []int, max int) [][]bloomIndexes { - res := make([][]bloomIndexes, len(lengths)) - for i, topics := range lengths { - res[i] = make([]bloomIndexes, topics) - for j := 0; j < topics; j++ { - for k := 0; k < len(res[i][j]); k++ { - res[i][j][k] = uint(rand.Intn(max-1) + 2) - } - } - } - return res -} - -// testMatcherDiffBatches runs the given matches test in single-delivery and also -// in batches delivery mode, verifying that all kinds of deliveries are handled -// correctly within. -func testMatcherDiffBatches(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, intermittent bool, retrievals uint32) { - singleton := testMatcher(t, filter, start, blocks, intermittent, retrievals, 1) - batched := testMatcher(t, filter, start, blocks, intermittent, retrievals, 16) - - if singleton != batched { - t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, %v in singleton vs. %v in batched mode", filter, blocks, intermittent, singleton, batched) - } -} - -// testMatcherBothModes runs the given matcher test in both continuous as well as -// in intermittent mode, verifying that the request counts match each other. -func testMatcherBothModes(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, retrievals uint32) { - continuous := testMatcher(t, filter, start, blocks, false, retrievals, 16) - intermittent := testMatcher(t, filter, start, blocks, true, retrievals, 16) - - if continuous != intermittent { - t.Errorf("filter = %v blocks = %v: request count mismatch, %v in continuous vs. %v in intermittent mode", filter, blocks, continuous, intermittent) - } -} - -// testMatcher is a generic tester to run the given matcher test and return the -// number of requests made for cross validation between different modes. -func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, intermittent bool, retrievals uint32, maxReqCount int) uint32 { - // Create a new matcher an simulate our explicit random bitsets - matcher := NewMatcher(testSectionSize, nil) - matcher.filters = filter - - for _, rule := range filter { - for _, topic := range rule { - for _, bit := range topic { - matcher.addScheduler(bit) - } - } - } - // Track the number of retrieval requests made - var requested atomic.Uint32 - - // Start the matching session for the filter and the retriever goroutines - quit := make(chan struct{}) - matches := make(chan uint64, 16) - - session, err := matcher.Start(context.Background(), start, blocks-1, matches) - if err != nil { - t.Fatalf("failed to stat matcher session: %v", err) - } - startRetrievers(session, quit, &requested, maxReqCount) - - // Iterate over all the blocks and verify that the pipeline produces the correct matches - for i := start; i < blocks; i++ { - if expMatch3(filter, i) { - match, ok := <-matches - if !ok { - t.Errorf("filter = %v blocks = %v intermittent = %v: expected #%v, results channel closed", filter, blocks, intermittent, i) - return 0 - } - if match != i { - t.Errorf("filter = %v blocks = %v intermittent = %v: expected #%v, got #%v", filter, blocks, intermittent, i, match) - } - // If we're testing intermittent mode, abort and restart the pipeline - if intermittent { - session.Close() - close(quit) - - quit = make(chan struct{}) - matches = make(chan uint64, 16) - - session, err = matcher.Start(context.Background(), i+1, blocks-1, matches) - if err != nil { - t.Fatalf("failed to stat matcher session: %v", err) - } - startRetrievers(session, quit, &requested, maxReqCount) - } - } - } - // Ensure the result channel is torn down after the last block - match, ok := <-matches - if ok { - t.Errorf("filter = %v blocks = %v intermittent = %v: expected closed channel, got #%v", filter, blocks, intermittent, match) - } - // Clean up the session and ensure we match the expected retrieval count - session.Close() - close(quit) - - if retrievals != 0 && requested.Load() != retrievals { - t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested.Load(), retrievals) - } - return requested.Load() -} - -// startRetrievers starts a batch of goroutines listening for section requests -// and serving them. -func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *atomic.Uint32, batch int) { - requests := make(chan chan *Retrieval) - - for i := 0; i < 10; i++ { - // Start a multiplexer to test multiple threaded execution - go session.Multiplex(batch, 100*time.Microsecond, requests) - - // Start a services to match the above multiplexer - go func() { - for { - // Wait for a service request or a shutdown - select { - case <-quit: - return - - case request := <-requests: - task := <-request - - task.Bitsets = make([][]byte, len(task.Sections)) - for i, section := range task.Sections { - if rand.Int()%4 != 0 { // Handle occasional missing deliveries - task.Bitsets[i] = generateBitset(task.Bit, section) - retrievals.Add(1) - } - } - request <- task - } - } - }() - } -} - -// generateBitset generates the rotated bitset for the given bloom bit and section -// numbers. -func generateBitset(bit uint, section uint64) []byte { - bitset := make([]byte, testSectionSize/8) - for i := 0; i < len(bitset); i++ { - for b := 0; b < 8; b++ { - blockIdx := section*testSectionSize + uint64(i*8+b) - bitset[i] += bitset[i] - if (blockIdx % uint64(bit)) == 0 { - bitset[i]++ - } - } - } - return bitset -} - -func expMatch1(filter bloomIndexes, i uint64) bool { - for _, ii := range filter { - if (i % uint64(ii)) != 0 { - return false - } - } - return true -} - -func expMatch2(filter []bloomIndexes, i uint64) bool { - for _, ii := range filter { - if expMatch1(ii, i) { - return true - } - } - return false -} - -func expMatch3(filter [][]bloomIndexes, i uint64) bool { - for _, ii := range filter { - if !expMatch2(ii, i) { - return false - } - } - return true -} diff --git a/core/bloombits/scheduler.go b/core/bloombits/scheduler.go deleted file mode 100644 index a523bc55a..000000000 --- a/core/bloombits/scheduler.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "sync" -) - -// request represents a bloom retrieval task to prioritize and pull from the local -// database or remotely from the network. -type request struct { - section uint64 // Section index to retrieve the bit-vector from - bit uint // Bit index within the section to retrieve the vector of -} - -// response represents the state of a requested bit-vector through a scheduler. -type response struct { - cached []byte // Cached bits to dedup multiple requests - done chan struct{} // Channel to allow waiting for completion -} - -// scheduler handles the scheduling of bloom-filter retrieval operations for -// entire section-batches belonging to a single bloom bit. Beside scheduling the -// retrieval operations, this struct also deduplicates the requests and caches -// the results to minimize network/database overhead even in complex filtering -// scenarios. -type scheduler struct { - bit uint // Index of the bit in the bloom filter this scheduler is responsible for - responses map[uint64]*response // Currently pending retrieval requests or already cached responses - lock sync.Mutex // Lock protecting the responses from concurrent access -} - -// newScheduler creates a new bloom-filter retrieval scheduler for a specific -// bit index. -func newScheduler(idx uint) *scheduler { - return &scheduler{ - bit: idx, - responses: make(map[uint64]*response), - } -} - -// run creates a retrieval pipeline, receiving section indexes from sections and -// returning the results in the same order through the done channel. Concurrent -// runs of the same scheduler are allowed, leading to retrieval task deduplication. -func (s *scheduler) run(sections chan uint64, dist chan *request, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) { - // Create a forwarder channel between requests and responses of the same size as - // the distribution channel (since that will block the pipeline anyway). - pend := make(chan uint64, cap(dist)) - - // Start the pipeline schedulers to forward between user -> distributor -> user - wg.Add(2) - go s.scheduleRequests(sections, dist, pend, quit, wg) - go s.scheduleDeliveries(pend, done, quit, wg) -} - -// reset cleans up any leftovers from previous runs. This is required before a -// restart to ensure the no previously requested but never delivered state will -// cause a lockup. -func (s *scheduler) reset() { - s.lock.Lock() - defer s.lock.Unlock() - - for section, res := range s.responses { - if res.cached == nil { - delete(s.responses, section) - } - } -} - -// scheduleRequests reads section retrieval requests from the input channel, -// deduplicates the stream and pushes unique retrieval tasks into the distribution -// channel for a database or network layer to honour. -func (s *scheduler) scheduleRequests(reqs chan uint64, dist chan *request, pend chan uint64, quit chan struct{}, wg *sync.WaitGroup) { - // Clean up the goroutine and pipeline when done - defer wg.Done() - defer close(pend) - - // Keep reading and scheduling section requests - for { - select { - case <-quit: - return - - case section, ok := <-reqs: - // New section retrieval requested - if !ok { - return - } - // Deduplicate retrieval requests - unique := false - - s.lock.Lock() - if s.responses[section] == nil { - s.responses[section] = &response{ - done: make(chan struct{}), - } - unique = true - } - s.lock.Unlock() - - // Schedule the section for retrieval and notify the deliverer to expect this section - if unique { - select { - case <-quit: - return - case dist <- &request{bit: s.bit, section: section}: - } - } - select { - case <-quit: - return - case pend <- section: - } - } - } -} - -// scheduleDeliveries reads section acceptance notifications and waits for them -// to be delivered, pushing them into the output data buffer. -func (s *scheduler) scheduleDeliveries(pend chan uint64, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) { - // Clean up the goroutine and pipeline when done - defer wg.Done() - defer close(done) - - // Keep reading notifications and scheduling deliveries - for { - select { - case <-quit: - return - - case idx, ok := <-pend: - // New section retrieval pending - if !ok { - return - } - // Wait until the request is honoured - s.lock.Lock() - res := s.responses[idx] - s.lock.Unlock() - - select { - case <-quit: - return - case <-res.done: - } - // Deliver the result - select { - case <-quit: - return - case done <- res.cached: - } - } - } -} - -// deliver is called by the request distributor when a reply to a request arrives. -func (s *scheduler) deliver(sections []uint64, data [][]byte) { - s.lock.Lock() - defer s.lock.Unlock() - - for i, section := range sections { - if res := s.responses[section]; res != nil && res.cached == nil { // Avoid non-requests and double deliveries - res.cached = data[i] - close(res.done) - } - } -} diff --git a/core/bloombits/scheduler_test.go b/core/bloombits/scheduler_test.go deleted file mode 100644 index dcaaa9152..000000000 --- a/core/bloombits/scheduler_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 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 . - -package bloombits - -import ( - "bytes" - "math/big" - "sync" - "sync/atomic" - "testing" -) - -// Tests that the scheduler can deduplicate and forward retrieval requests to -// underlying fetchers and serve responses back, irrelevant of the concurrency -// of the requesting clients or serving data fetchers. -func TestSchedulerSingleClientSingleFetcher(t *testing.T) { testScheduler(t, 1, 1, 5000) } -func TestSchedulerSingleClientMultiFetcher(t *testing.T) { testScheduler(t, 1, 10, 5000) } -func TestSchedulerMultiClientSingleFetcher(t *testing.T) { testScheduler(t, 10, 1, 5000) } -func TestSchedulerMultiClientMultiFetcher(t *testing.T) { testScheduler(t, 10, 10, 5000) } - -func testScheduler(t *testing.T, clients int, fetchers int, requests int) { - t.Parallel() - f := newScheduler(0) - - // Create a batch of handler goroutines that respond to bloom bit requests and - // deliver them to the scheduler. - var fetchPend sync.WaitGroup - fetchPend.Add(fetchers) - defer fetchPend.Wait() - - fetch := make(chan *request, 16) - defer close(fetch) - - var delivered atomic.Uint32 - for i := 0; i < fetchers; i++ { - go func() { - defer fetchPend.Done() - - for req := range fetch { - delivered.Add(1) - - f.deliver([]uint64{ - req.section + uint64(requests), // Non-requested data (ensure it doesn't go out of bounds) - req.section, // Requested data - req.section, // Duplicated data (ensure it doesn't double close anything) - }, [][]byte{ - {}, - new(big.Int).SetUint64(req.section).Bytes(), - new(big.Int).SetUint64(req.section).Bytes(), - }) - } - }() - } - // Start a batch of goroutines to concurrently run scheduling tasks - quit := make(chan struct{}) - - var pend sync.WaitGroup - pend.Add(clients) - - for i := 0; i < clients; i++ { - go func() { - defer pend.Done() - - in := make(chan uint64, 16) - out := make(chan []byte, 16) - - f.run(in, fetch, out, quit, &pend) - - go func() { - for j := 0; j < requests; j++ { - in <- uint64(j) - } - close(in) - }() - b := new(big.Int) - for j := 0; j < requests; j++ { - bits := <-out - if want := b.SetUint64(uint64(j)).Bytes(); !bytes.Equal(bits, want) { - t.Errorf("vector %d: delivered content mismatch: have %x, want %x", j, bits, want) - } - } - }() - } - pend.Wait() - - if have := delivered.Load(); int(have) != requests { - t.Errorf("request count mismatch: have %v, want %v", have, requests) - } -} diff --git a/core/chain_indexer.go b/core/chain_indexer.go deleted file mode 100644 index 2865daa1f..000000000 --- a/core/chain_indexer.go +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2017 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 . - -package core - -import ( - "context" - "encoding/binary" - "errors" - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" -) - -// ChainIndexerBackend defines the methods needed to process chain segments in -// the background and write the segment results into the database. These can be -// used to create filter blooms or CHTs. -type ChainIndexerBackend interface { - // Reset initiates the processing of a new chain segment, potentially terminating - // any partially completed operations (in case of a reorg). - Reset(ctx context.Context, section uint64, prevHead common.Hash) error - - // Process crunches through the next header in the chain segment. The caller - // will ensure a sequential order of headers. - Process(ctx context.Context, header *types.Header) error - - // Commit finalizes the section metadata and stores it into the database. - Commit() error - - // Prune deletes the chain index older than the given threshold. - Prune(threshold uint64) error -} - -// ChainIndexerChain interface is used for connecting the indexer to a blockchain -type ChainIndexerChain interface { - // CurrentHeader retrieves the latest locally known header. - CurrentHeader() *types.Header - - // SubscribeChainHeadEvent subscribes to new head header notifications. - SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription -} - -// ChainIndexer does a post-processing job for equally sized sections of the -// canonical chain (like BlooomBits and CHT structures). A ChainIndexer is -// connected to the blockchain through the event system by starting a -// ChainHeadEventLoop in a goroutine. -// -// Further child ChainIndexers can be added which use the output of the parent -// section indexer. These child indexers receive new head notifications only -// after an entire section has been finished or in case of rollbacks that might -// affect already finished sections. -type ChainIndexer struct { - chainDb ethdb.Database // Chain database to index the data from - indexDb ethdb.Database // Prefixed table-view of the db to write index metadata into - backend ChainIndexerBackend // Background processor generating the index data content - children []*ChainIndexer // Child indexers to cascade chain updates to - - active atomic.Bool // Flag whether the event loop was started - update chan struct{} // Notification channel that headers should be processed - quit chan chan error // Quit channel to tear down running goroutines - ctx context.Context - ctxCancel func() - - sectionSize uint64 // Number of blocks in a single chain segment to process - confirmsReq uint64 // Number of confirmations before processing a completed segment - - storedSections uint64 // Number of sections successfully indexed into the database - knownSections uint64 // Number of sections known to be complete (block wise) - cascadedHead uint64 // Block number of the last completed section cascaded to subindexers - - checkpointSections uint64 // Number of sections covered by the checkpoint - checkpointHead common.Hash // Section head belonging to the checkpoint - - throttling time.Duration // Disk throttling to prevent a heavy upgrade from hogging resources - - log log.Logger - lock sync.Mutex -} - -// NewChainIndexer creates a new chain indexer to do background processing on -// chain segments of a given size after certain number of confirmations passed. -// The throttling parameter might be used to prevent database thrashing. -func NewChainIndexer(chainDb ethdb.Database, indexDb ethdb.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer { - c := &ChainIndexer{ - chainDb: chainDb, - indexDb: indexDb, - backend: backend, - update: make(chan struct{}, 1), - quit: make(chan chan error), - sectionSize: section, - confirmsReq: confirm, - throttling: throttling, - log: log.New("type", kind), - } - // Initialize database dependent fields and start the updater - c.loadValidSections() - c.ctx, c.ctxCancel = context.WithCancel(context.Background()) - - go c.updateLoop() - - return c -} - -// AddCheckpoint adds a checkpoint. Sections are never processed and the chain -// is not expected to be available before this point. The indexer assumes that -// the backend has sufficient information available to process subsequent sections. -// -// Note: knownSections == 0 and storedSections == checkpointSections until -// syncing reaches the checkpoint -func (c *ChainIndexer) AddCheckpoint(section uint64, shead common.Hash) { - c.lock.Lock() - defer c.lock.Unlock() - - // Short circuit if the given checkpoint is below than local's. - if c.checkpointSections >= section+1 || section < c.storedSections { - return - } - c.checkpointSections = section + 1 - c.checkpointHead = shead - - c.setSectionHead(section, shead) - c.setValidSections(section + 1) -} - -// Start creates a goroutine to feed chain head events into the indexer for -// cascading background processing. Children do not need to be started, they -// are notified about new events by their parents. -func (c *ChainIndexer) Start(chain ChainIndexerChain) { - events := make(chan ChainHeadEvent, 10) - sub := chain.SubscribeChainHeadEvent(events) - - go c.eventLoop(chain.CurrentHeader(), events, sub) -} - -// Close tears down all goroutines belonging to the indexer and returns any error -// that might have occurred internally. -func (c *ChainIndexer) Close() error { - var errs []error - - c.ctxCancel() - - // Tear down the primary update loop - errc := make(chan error) - c.quit <- errc - if err := <-errc; err != nil { - errs = append(errs, err) - } - // If needed, tear down the secondary event loop - if c.active.Load() { - c.quit <- errc - if err := <-errc; err != nil { - errs = append(errs, err) - } - } - // Close all children - for _, child := range c.children { - if err := child.Close(); err != nil { - errs = append(errs, err) - } - } - // Return any failures - switch { - case len(errs) == 0: - return nil - - case len(errs) == 1: - return errs[0] - - default: - return fmt.Errorf("%v", errs) - } -} - -// eventLoop is a secondary - optional - event loop of the indexer which is only -// started for the outermost indexer to push chain head events into a processing -// queue. -func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) { - // Mark the chain indexer as active, requiring an additional teardown - c.active.Store(true) - - defer sub.Unsubscribe() - - // Fire the initial new head event to start any outstanding processing - c.newHead(currentHeader.Number.Uint64(), false) - - var ( - prevHeader = currentHeader - prevHash = currentHeader.Hash() - ) - for { - select { - case errc := <-c.quit: - // Chain indexer terminating, report no failure and abort - errc <- nil - return - - case ev, ok := <-events: - // Received a new event, ensure it's not nil (closing) and update - if !ok { - errc := <-c.quit - errc <- nil - return - } - if ev.Header.ParentHash != prevHash { - // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) - // TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly? - - if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash { - if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, ev.Header); h != nil { - c.newHead(h.Number.Uint64(), true) - } - } - } - c.newHead(ev.Header.Number.Uint64(), false) - - prevHeader, prevHash = ev.Header, ev.Header.Hash() - } - } -} - -// newHead notifies the indexer about new chain heads and/or reorgs. -func (c *ChainIndexer) newHead(head uint64, reorg bool) { - c.lock.Lock() - defer c.lock.Unlock() - - // If a reorg happened, invalidate all sections until that point - if reorg { - // Revert the known section number to the reorg point - known := (head + 1) / c.sectionSize - stored := known - if known < c.checkpointSections { - known = 0 - } - if stored < c.checkpointSections { - stored = c.checkpointSections - } - if known < c.knownSections { - c.knownSections = known - } - // Revert the stored sections from the database to the reorg point - if stored < c.storedSections { - c.setValidSections(stored) - } - // Update the new head number to the finalized section end and notify children - head = known * c.sectionSize - - if head < c.cascadedHead { - c.cascadedHead = head - for _, child := range c.children { - child.newHead(c.cascadedHead, true) - } - } - return - } - // No reorg, calculate the number of newly known sections and update if high enough - var sections uint64 - if head >= c.confirmsReq { - sections = (head + 1 - c.confirmsReq) / c.sectionSize - if sections < c.checkpointSections { - sections = 0 - } - if sections > c.knownSections { - if c.knownSections < c.checkpointSections { - // syncing reached the checkpoint, verify section head - syncedHead := rawdb.ReadCanonicalHash(c.chainDb, c.checkpointSections*c.sectionSize-1) - if syncedHead != c.checkpointHead { - c.log.Error("Synced chain does not match checkpoint", "number", c.checkpointSections*c.sectionSize-1, "expected", c.checkpointHead, "synced", syncedHead) - return - } - } - c.knownSections = sections - - select { - case c.update <- struct{}{}: - default: - } - } - } -} - -// updateLoop is the main event loop of the indexer which pushes chain segments -// down into the processing backend. -func (c *ChainIndexer) updateLoop() { - var ( - updating bool - updated time.Time - ) - - for { - select { - case errc := <-c.quit: - // Chain indexer terminating, report no failure and abort - errc <- nil - return - - case <-c.update: - // Section headers completed (or rolled back), update the index - c.lock.Lock() - if c.knownSections > c.storedSections { - // Periodically print an upgrade log message to the user - if time.Since(updated) > 8*time.Second { - if c.knownSections > c.storedSections+1 { - updating = true - c.log.Info("Upgrading chain index", "percentage", c.storedSections*100/c.knownSections) - } - updated = time.Now() - } - // Cache the current section count and head to allow unlocking the mutex - c.verifyLastHead() - section := c.storedSections - var oldHead common.Hash - if section > 0 { - oldHead = c.SectionHead(section - 1) - } - // Process the newly defined section in the background - c.lock.Unlock() - newHead, err := c.processSection(section, oldHead) - if err != nil { - select { - case <-c.ctx.Done(): - <-c.quit <- nil - return - default: - } - c.log.Error("Section processing failed", "error", err) - } - c.lock.Lock() - - // If processing succeeded and no reorgs occurred, mark the section completed - if err == nil && (section == 0 || oldHead == c.SectionHead(section-1)) { - c.setSectionHead(section, newHead) - c.setValidSections(section + 1) - if c.storedSections == c.knownSections && updating { - updating = false - c.log.Info("Finished upgrading chain index") - } - c.cascadedHead = c.storedSections*c.sectionSize - 1 - for _, child := range c.children { - c.log.Trace("Cascading chain index update", "head", c.cascadedHead) - child.newHead(c.cascadedHead, false) - } - } else { - // If processing failed, don't retry until further notification - c.log.Debug("Chain index processing failed", "section", section, "err", err) - c.verifyLastHead() - c.knownSections = c.storedSections - } - } - // If there are still further sections to process, reschedule - if c.knownSections > c.storedSections { - time.AfterFunc(c.throttling, func() { - select { - case c.update <- struct{}{}: - default: - } - }) - } - c.lock.Unlock() - } - } -} - -// processSection processes an entire section by calling backend functions while -// ensuring the continuity of the passed headers. Since the chain mutex is not -// held while processing, the continuity can be broken by a long reorg, in which -// case the function returns with an error. -func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (common.Hash, error) { - c.log.Trace("Processing new chain section", "section", section) - - // Reset and partial processing - if err := c.backend.Reset(c.ctx, section, lastHead); err != nil { - c.setValidSections(0) - return common.Hash{}, err - } - - for number := section * c.sectionSize; number < (section+1)*c.sectionSize; number++ { - hash := rawdb.ReadCanonicalHash(c.chainDb, number) - if hash == (common.Hash{}) { - return common.Hash{}, fmt.Errorf("canonical block #%d unknown", number) - } - header := rawdb.ReadHeader(c.chainDb, hash, number) - if header == nil { - return common.Hash{}, fmt.Errorf("block #%d [%x..] not found", number, hash[:4]) - } else if header.ParentHash != lastHead { - return common.Hash{}, errors.New("chain reorged during section processing") - } - if err := c.backend.Process(c.ctx, header); err != nil { - return common.Hash{}, err - } - lastHead = header.Hash() - } - if err := c.backend.Commit(); err != nil { - return common.Hash{}, err - } - return lastHead, nil -} - -// verifyLastHead compares last stored section head with the corresponding block hash in the -// actual canonical chain and rolls back reorged sections if necessary to ensure that stored -// sections are all valid -func (c *ChainIndexer) verifyLastHead() { - for c.storedSections > 0 && c.storedSections > c.checkpointSections { - if c.SectionHead(c.storedSections-1) == rawdb.ReadCanonicalHash(c.chainDb, c.storedSections*c.sectionSize-1) { - return - } - c.setValidSections(c.storedSections - 1) - } -} - -// Sections returns the number of processed sections maintained by the indexer -// and also the information about the last header indexed for potential canonical -// verifications. -func (c *ChainIndexer) Sections() (uint64, uint64, common.Hash) { - c.lock.Lock() - defer c.lock.Unlock() - - c.verifyLastHead() - return c.storedSections, c.storedSections*c.sectionSize - 1, c.SectionHead(c.storedSections - 1) -} - -// AddChildIndexer adds a child ChainIndexer that can use the output of this one -func (c *ChainIndexer) AddChildIndexer(indexer *ChainIndexer) { - if indexer == c { - panic("can't add indexer as a child of itself") - } - c.lock.Lock() - defer c.lock.Unlock() - - c.children = append(c.children, indexer) - - // Cascade any pending updates to new children too - sections := c.storedSections - if c.knownSections < sections { - // if a section is "stored" but not "known" then it is a checkpoint without - // available chain data so we should not cascade it yet - sections = c.knownSections - } - if sections > 0 { - indexer.newHead(sections*c.sectionSize-1, false) - } -} - -// Prune deletes all chain data older than given threshold. -func (c *ChainIndexer) Prune(threshold uint64) error { - return c.backend.Prune(threshold) -} - -// loadValidSections reads the number of valid sections from the index database -// and caches is into the local state. -func (c *ChainIndexer) loadValidSections() { - data, _ := c.indexDb.Get([]byte("count")) - if len(data) == 8 { - c.storedSections = binary.BigEndian.Uint64(data) - } -} - -// setValidSections writes the number of valid sections to the index database -func (c *ChainIndexer) setValidSections(sections uint64) { - // Set the current number of valid sections in the database - var data [8]byte - binary.BigEndian.PutUint64(data[:], sections) - c.indexDb.Put([]byte("count"), data[:]) - - // Remove any reorged sections, caching the valids in the mean time - for c.storedSections > sections { - c.storedSections-- - c.removeSectionHead(c.storedSections) - } - c.storedSections = sections // needed if new > old -} - -// SectionHead retrieves the last block hash of a processed section from the -// index database. -func (c *ChainIndexer) SectionHead(section uint64) common.Hash { - var data [8]byte - binary.BigEndian.PutUint64(data[:], section) - - hash, _ := c.indexDb.Get(append([]byte("shead"), data[:]...)) - if len(hash) == len(common.Hash{}) { - return common.BytesToHash(hash) - } - return common.Hash{} -} - -// setSectionHead writes the last block hash of a processed section to the index -// database. -func (c *ChainIndexer) setSectionHead(section uint64, hash common.Hash) { - var data [8]byte - binary.BigEndian.PutUint64(data[:], section) - - c.indexDb.Put(append([]byte("shead"), data[:]...), hash.Bytes()) -} - -// removeSectionHead removes the reference to a processed section from the index -// database. -func (c *ChainIndexer) removeSectionHead(section uint64) { - var data [8]byte - binary.BigEndian.PutUint64(data[:], section) - - c.indexDb.Delete(append([]byte("shead"), data[:]...)) -} diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go deleted file mode 100644 index bf3bde756..000000000 --- a/core/chain_indexer_test.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2017 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 . - -package core - -import ( - "context" - "errors" - "fmt" - "math/big" - "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" -) - -// Runs multiple tests with randomized parameters. -func TestChainIndexerSingle(t *testing.T) { - for i := 0; i < 10; i++ { - testChainIndexer(t, 1) - } -} - -// Runs multiple tests with randomized parameters and different number of -// chain backends. -func TestChainIndexerWithChildren(t *testing.T) { - for i := 2; i < 8; i++ { - testChainIndexer(t, i) - } -} - -// testChainIndexer runs a test with either a single chain indexer or a chain of -// multiple backends. The section size and required confirmation count parameters -// are randomized. -func testChainIndexer(t *testing.T, count int) { - db := rawdb.NewMemoryDatabase() - defer db.Close() - - // Create a chain of indexers and ensure they all report empty - backends := make([]*testChainIndexBackend, count) - for i := 0; i < count; i++ { - var ( - sectionSize = uint64(rand.Intn(100) + 1) - confirmsReq = uint64(rand.Intn(10)) - ) - backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)} - backends[i].indexer = NewChainIndexer(db, rawdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i)) - - if sections, _, _ := backends[i].indexer.Sections(); sections != 0 { - t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0) - } - if i > 0 { - backends[i-1].indexer.AddChildIndexer(backends[i].indexer) - } - } - defer backends[0].indexer.Close() // parent indexer shuts down children - // notify pings the root indexer about a new head or reorg, then expect - // processed blocks if a section is processable - notify := func(headNum, failNum uint64, reorg bool) { - backends[0].indexer.newHead(headNum, reorg) - if reorg { - for _, backend := range backends { - headNum = backend.reorg(headNum) - backend.assertSections() - } - return - } - var cascade bool - for _, backend := range backends { - headNum, cascade = backend.assertBlocks(headNum, failNum) - if !cascade { - break - } - backend.assertSections() - } - } - // inject inserts a new random canonical header into the database directly - inject := func(number uint64) { - header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} - if number > 0 { - header.ParentHash = rawdb.ReadCanonicalHash(db, number-1) - } - rawdb.WriteHeader(db, header) - rawdb.WriteCanonicalHash(db, header.Hash(), number) - } - // Start indexer with an already existing chain - for i := uint64(0); i <= 100; i++ { - inject(i) - } - notify(100, 100, false) - - // Add new blocks one by one - for i := uint64(101); i <= 1000; i++ { - inject(i) - notify(i, i, false) - } - // Do a reorg - notify(500, 500, true) - - // Create new fork - for i := uint64(501); i <= 1000; i++ { - inject(i) - notify(i, i, false) - } - for i := uint64(1001); i <= 1500; i++ { - inject(i) - } - // Failed processing scenario where less blocks are available than notified - notify(2000, 1500, false) - - // Notify about a reorg (which could have caused the missing blocks if happened during processing) - notify(1500, 1500, true) - - // Create new fork - for i := uint64(1501); i <= 2000; i++ { - inject(i) - notify(i, i, false) - } -} - -// testChainIndexBackend implements ChainIndexerBackend -type testChainIndexBackend struct { - t *testing.T - indexer *ChainIndexer - section, headerCnt, stored uint64 - processCh chan uint64 -} - -// assertSections verifies if a chain indexer has the correct number of section. -func (b *testChainIndexBackend) assertSections() { - // Keep trying for 3 seconds if it does not match - var sections uint64 - for i := 0; i < 300; i++ { - sections, _, _ = b.indexer.Sections() - if sections == b.stored { - return - } - time.Sleep(10 * time.Millisecond) - } - b.t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, b.stored) -} - -// assertBlocks expects processing calls after new blocks have arrived. If the -// failNum < headNum then we are simulating a scenario where a reorg has happened -// after the processing has started and the processing of a section fails. -func (b *testChainIndexBackend) assertBlocks(headNum, failNum uint64) (uint64, bool) { - var sections uint64 - if headNum >= b.indexer.confirmsReq { - sections = (headNum + 1 - b.indexer.confirmsReq) / b.indexer.sectionSize - if sections > b.stored { - // expect processed blocks - for expectd := b.stored * b.indexer.sectionSize; expectd < sections*b.indexer.sectionSize; expectd++ { - if expectd > failNum { - // rolled back after processing started, no more process calls expected - // wait until updating is done to make sure that processing actually fails - var updating bool - for i := 0; i < 300; i++ { - b.indexer.lock.Lock() - updating = b.indexer.knownSections > b.indexer.storedSections - b.indexer.lock.Unlock() - if !updating { - break - } - time.Sleep(10 * time.Millisecond) - } - if updating { - b.t.Fatalf("update did not finish") - } - sections = expectd / b.indexer.sectionSize - break - } - select { - case <-time.After(10 * time.Second): - b.t.Fatalf("Expected processed block #%d, got nothing", expectd) - case processed := <-b.processCh: - if processed != expectd { - b.t.Errorf("Expected processed block #%d, got #%d", expectd, processed) - } - } - } - b.stored = sections - } - } - if b.stored == 0 { - return 0, false - } - return b.stored*b.indexer.sectionSize - 1, true -} - -func (b *testChainIndexBackend) reorg(headNum uint64) uint64 { - firstChanged := (headNum + 1) / b.indexer.sectionSize - if firstChanged < b.stored { - b.stored = firstChanged - } - return b.stored * b.indexer.sectionSize -} - -func (b *testChainIndexBackend) Reset(ctx context.Context, section uint64, prevHead common.Hash) error { - b.section = section - b.headerCnt = 0 - return nil -} - -func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Header) error { - b.headerCnt++ - if b.headerCnt > b.indexer.sectionSize { - b.t.Error("Processing too many headers") - } - //t.processCh <- header.Number.Uint64() - select { - case <-time.After(10 * time.Second): - b.t.Error("Unexpected call to Process") - // Can't use Fatal since this is not the test's goroutine. - // Returning error stops the chainIndexer's updateLoop - return errors.New("unexpected call to Process") - case b.processCh <- header.Number.Uint64(): - } - return nil -} - -func (b *testChainIndexBackend) Commit() error { - if b.headerCnt != b.indexer.sectionSize { - b.t.Error("Not enough headers processed") - } - return nil -} - -func (b *testChainIndexBackend) Prune(threshold uint64) error { - return nil -} diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index dfc20521f..d74b11da0 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -17,7 +17,6 @@ package filtermaps import ( - "bytes" "errors" "fmt" "os" @@ -242,7 +241,8 @@ func (f *FilterMaps) Start() { log.Error("Could not load head filter map snapshot", "error", err) } } - f.closeWg.Add(1) + f.closeWg.Add(2) + go f.removeBloomBits() go f.indexerLoop() } @@ -292,7 +292,7 @@ func (f *FilterMaps) reset() bool { // deleting the range first ensures that resetDb will be called again at next // startup and any leftover data will be removed even if it cannot finish now. rawdb.DeleteFilterMapsRange(f.db) - return f.removeDbWithPrefix([]byte(rawdb.FilterMapsPrefix), "Resetting log index database") + return f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") } // init initializes an empty log index according to the current targetView. @@ -335,24 +335,25 @@ func (f *FilterMaps) init() error { return batch.Write() } -// removeDbWithPrefix removes data with the given prefix from the database and -// returns true if everything was successfully removed. -func (f *FilterMaps) removeDbWithPrefix(prefix []byte, action string) bool { - it := f.db.NewIterator(prefix, nil) - hasData := it.Next() - it.Release() - if !hasData { - return true - } +// removeBloomBits removes old bloom bits data from the database. +func (f *FilterMaps) removeBloomBits() { + f.safeDeleteRange(rawdb.DeleteBloomBitsDb, "Removing old bloom bits database") + f.closeWg.Done() +} - end := bytes.Clone(prefix) - end[len(end)-1]++ +// safeDeleteRange calls the specified database range deleter function +// repeatedly as long as it returns leveldb.ErrTooManyKeys. +// This wrapper is necessary because of the leveldb fallback implementation +// of DeleteRange. +func (f *FilterMaps) safeDeleteRange(removeFn func(ethdb.KeyValueRangeDeleter) error, action string) bool { start := time.Now() var retry bool for { - err := f.db.DeleteRange(prefix, end) + err := removeFn(f.db) if err == nil { - log.Info(action+" finished", "elapsed", time.Since(start)) + if retry { + log.Info(action+" finished", "elapsed", time.Since(start)) + } return true } if err != leveldb.ErrTooManyKeys { @@ -365,7 +366,7 @@ func (f *FilterMaps) removeDbWithPrefix(prefix []byte, action string) bool { default: } if !retry { - log.Info(action + " in progress...") + log.Info(action+" in progress...", "elapsed", time.Since(start)) retry = true } } diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 61a9bf035..69f42d8b6 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -44,13 +44,18 @@ func (f *FilterMaps) indexerLoop() { if !f.indexedRange.initialized { if err := f.init(); err != nil { log.Error("Error initializing log index", "error", err) - f.waitForEvent() + // unexpected error; there is not a lot we can do here, maybe it + // recovers, maybe not. Calling event processing here ensures + // that we can still properly shutdown in case of an infinite loop. + f.processSingleEvent(true) continue } } if !f.targetHeadIndexed() { if !f.tryIndexHead() { - f.waitForEvent() + // either shutdown or unexpected error; in the latter case ensure + // that proper shutdown is still possible. + f.processSingleEvent(true) } } else { if f.finalBlock != f.lastFinal { @@ -60,7 +65,7 @@ func (f *FilterMaps) indexerLoop() { f.lastFinal = f.finalBlock } if f.tryIndexTail() && f.tryUnindexTail() { - f.waitForEvent() + f.waitForNewHead() } } } @@ -119,8 +124,9 @@ func (f *FilterMaps) WaitIdle() { } } -// waitForEvent blocks until an event happens that the indexer might react to. -func (f *FilterMaps) waitForEvent() { +// waitForNewHead blocks until there is a new target head to index and block +// processing has been finished. +func (f *FilterMaps) waitForNewHead() { for !f.stop && (f.blockProcessing || f.targetHeadIndexed()) { f.processSingleEvent(true) } @@ -129,13 +135,16 @@ func (f *FilterMaps) waitForEvent() { // processEvents processes all events, blocking only if a block processing is // happening and indexing should be suspended. func (f *FilterMaps) processEvents() { - for !f.stop && f.processSingleEvent(f.blockProcessing) { + for f.processSingleEvent(f.blockProcessing) { } } // processSingleEvent processes a single event either in a blocking or -// non-blocking manner. +// non-blocking manner. It returns true if it did process an event. func (f *FilterMaps) processSingleEvent(blocking bool) bool { + if f.stop { + return false + } if !f.hasTempRange { for _, mb := range f.matcherSyncRequests { mb.synced() @@ -356,15 +365,17 @@ func (f *FilterMaps) needTailEpoch(epoch uint32) bool { if epoch+1 < firstEpoch { return false } + var lastBlockOfPrevEpoch uint64 if epoch > 0 { - lastBlockOfPrevEpoch, _, err := f.getLastBlockOfMap(epoch<= firstEpoch } - if f.historyCutoff > lastBlockOfPrevEpoch { - return false - } + } + if f.historyCutoff > lastBlockOfPrevEpoch { + return false } lastBlockOfEpoch, _, err := f.getLastBlockOfMap((epoch+1)<= 0 { - break - } - if len(it.Key()) != len(bloomBitsPrefix)+2+8+32 { - continue - } - db.Delete(it.Key()) - } - if it.Error() != nil { - log.Crit("Failed to delete bloom bits", "err", it.Error()) - } -} - // ReadFilterMapRow retrieves a filter map row at the given mapRowIndex // (see filtermaps.mapRowIndex for the storage index encoding). // Note that zero length rows are not stored in the database and therefore all @@ -485,3 +450,24 @@ func DeleteFilterMapsRange(db ethdb.KeyValueWriter) { log.Crit("Failed to delete filter maps range", "err", err) } } + +// deletePrefixRange deletes everything with the given prefix from the database. +func deletePrefixRange(db ethdb.KeyValueRangeDeleter, prefix []byte) error { + end := bytes.Clone(prefix) + end[len(end)-1]++ + return db.DeleteRange(prefix, end) +} + +// DeleteFilterMapsDb removes the entire filter maps database +func DeleteFilterMapsDb(db ethdb.KeyValueRangeDeleter) error { + return deletePrefixRange(db, []byte(filterMapsPrefix)) +} + +// DeleteFilterMapsDb removes the old bloombits database and the associated +// chain indexer database. +func DeleteBloomBitsDb(db ethdb.KeyValueRangeDeleter) error { + if err := deletePrefixRange(db, bloomBitsPrefix); err != nil { + return err + } + return deletePrefixRange(db, bloomBitsIndexPrefix) +} diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index ea25bf1e2..29b468fb2 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -17,7 +17,6 @@ package rawdb import ( - "bytes" "math/big" "testing" @@ -25,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/blocktest" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -111,54 +109,3 @@ func TestLookupStorage(t *testing.T) { }) } } - -func TestDeleteBloomBits(t *testing.T) { - // Prepare testing data - db := NewMemoryDatabase() - for i := uint(0); i < 2; i++ { - for s := uint64(0); s < 2; s++ { - WriteBloomBits(db, i, s, params.MainnetGenesisHash, []byte{0x01, 0x02}) - WriteBloomBits(db, i, s, params.SepoliaGenesisHash, []byte{0x01, 0x02}) - WriteBloomBits(db, i, s, params.HoodiGenesisHash, []byte{0x01, 0x02}) - } - } - check := func(bit uint, section uint64, head common.Hash, exist bool) { - bits, _ := ReadBloomBits(db, bit, section, head) - if exist && !bytes.Equal(bits, []byte{0x01, 0x02}) { - t.Fatalf("Bloombits mismatch") - } - if !exist && len(bits) > 0 { - t.Fatalf("Bloombits should be removed") - } - } - // Check the existence of written data. - check(0, 0, params.MainnetGenesisHash, true) - check(0, 0, params.SepoliaGenesisHash, true) - check(0, 0, params.HoodiGenesisHash, true) - - // Check the existence of deleted data. - DeleteBloombits(db, 0, 0, 1) - check(0, 0, params.MainnetGenesisHash, false) - check(0, 0, params.SepoliaGenesisHash, false) - check(0, 0, params.HoodiGenesisHash, false) - check(0, 1, params.MainnetGenesisHash, true) - check(0, 1, params.SepoliaGenesisHash, true) - check(0, 1, params.HoodiGenesisHash, true) - - // Check the existence of deleted data. - DeleteBloombits(db, 0, 0, 2) - check(0, 0, params.MainnetGenesisHash, false) - check(0, 0, params.SepoliaGenesisHash, false) - check(0, 0, params.HoodiGenesisHash, false) - check(0, 1, params.MainnetGenesisHash, false) - check(0, 1, params.SepoliaGenesisHash, false) - check(0, 1, params.HoodiGenesisHash, false) - - // Bit1 shouldn't be affect. - check(1, 0, params.MainnetGenesisHash, true) - check(1, 0, params.SepoliaGenesisHash, true) - check(1, 0, params.HoodiGenesisHash, true) - check(1, 1, params.MainnetGenesisHash, true) - check(1, 1, params.SepoliaGenesisHash, true) - check(1, 1, params.HoodiGenesisHash, true) -} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 6b52668bc..9bfdc4422 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -375,7 +375,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { accountSnaps stat storageSnaps stat preimages stat - bloomBits stat filterMaps stat beaconHeaders stat cliqueSnaps stat @@ -437,11 +436,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { metadata.Add(size) case bytes.HasPrefix(key, genesisPrefix) && len(key) == (len(genesisPrefix)+common.HashLength): metadata.Add(size) - case bytes.HasPrefix(key, bloomBitsPrefix) && len(key) == (len(bloomBitsPrefix)+10+common.HashLength): - bloomBits.Add(size) - case bytes.HasPrefix(key, BloomBitsIndexPrefix): - bloomBits.Add(size) - case bytes.HasPrefix(key, []byte(FilterMapsPrefix)): + case bytes.HasPrefix(key, []byte(filterMapsPrefix)): filterMaps.Add(size) case bytes.HasPrefix(key, skeletonHeaderPrefix) && len(key) == (len(skeletonHeaderPrefix)+8): beaconHeaders.Add(size) @@ -507,7 +502,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Block number->hash", numHashPairings.Size(), numHashPairings.Count()}, {"Key-Value store", "Block hash->number", hashNumPairings.Size(), hashNumPairings.Count()}, {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, - {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Log search index", filterMaps.Size(), filterMaps.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, {"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 177f4a67f..dacd71a5d 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -128,8 +128,8 @@ var ( configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db - // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress - BloomBitsIndexPrefix = []byte("iB") + // bloomBitsIndexPrefix is the data table of a chain indexer to track its progress + bloomBitsIndexPrefix = []byte("iB") ChtPrefix = []byte("chtRootV2-") // ChtPrefix + chtNum (uint64 big endian) -> trie root hash ChtTablePrefix = []byte("cht-") @@ -145,11 +145,11 @@ var ( FixedCommitteeRootKey = []byte("fixedRoot-") // bigEndian64(syncPeriod) -> committee root hash SyncCommitteeKey = []byte("committee-") // bigEndian64(syncPeriod) -> serialized committee - FilterMapsPrefix = "fm-" - filterMapsRangeKey = []byte(FilterMapsPrefix + "R") - filterMapRowPrefix = []byte(FilterMapsPrefix + "r") // filterMapRowPrefix + mapRowIndex (uint64 big endian) -> filter row - filterMapLastBlockPrefix = []byte(FilterMapsPrefix + "b") // filterMapLastBlockPrefix + mapIndex (uint32 big endian) -> block number (uint64 big endian) - filterMapBlockLVPrefix = []byte(FilterMapsPrefix + "p") // filterMapBlockLVPrefix + num (uint64 big endian) -> log value pointer (uint64 big endian) + filterMapsPrefix = "fm-" + filterMapsRangeKey = []byte(filterMapsPrefix + "R") + filterMapRowPrefix = []byte(filterMapsPrefix + "r") // filterMapRowPrefix + mapRowIndex (uint64 big endian) -> filter row + filterMapLastBlockPrefix = []byte(filterMapsPrefix + "b") // filterMapLastBlockPrefix + mapIndex (uint32 big endian) -> block number (uint64 big endian) + filterMapBlockLVPrefix = []byte(filterMapsPrefix + "p") // filterMapBlockLVPrefix + num (uint64 big endian) -> log value pointer (uint64 big endian) preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) @@ -230,16 +230,6 @@ func storageSnapshotsKey(accountHash common.Hash) []byte { return append(SnapshotStoragePrefix, accountHash.Bytes()...) } -// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte { - key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...) - - binary.BigEndian.PutUint16(key[1:], uint16(bit)) - binary.BigEndian.PutUint64(key[3:], section) - - return key -} - // skeletonHeaderKey = skeletonHeaderPrefix + num (uint64 big endian) func skeletonHeaderKey(number uint64) []byte { return append(skeletonHeaderPrefix, encodeBlockNumber(number)...) diff --git a/eth/api_backend.go b/eth/api_backend.go index 578b339f8..f12002f31 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -443,17 +442,6 @@ func (b *EthAPIBackend) RPCTxFeeCap() float64 { return b.eth.config.RPCTxFeeCap } -func (b *EthAPIBackend) BloomStatus() (uint64, uint64) { - sections, _, _ := b.eth.bloomIndexer.Sections() - return params.BloomBitsBlocks, sections -} - -func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { - for i := 0; i < bloomFilterThreads; i++ { - go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) - } -} - func (b *EthAPIBackend) NewMatcherBackend() filtermaps.MatcherBackend { return b.eth.filterMaps.NewMatcherBackend() } diff --git a/eth/backend.go b/eth/backend.go index 1466f6320..424c85073 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/dbft" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" @@ -93,10 +92,6 @@ type Ethereum struct { accountManager *accounts.Manager antimevKeystore *antimev.KeyStore - bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests - bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports - closeBloomHandler chan struct{} - filterMaps *filtermaps.FilterMaps closeFilterMaps chan chan struct{} @@ -185,20 +180,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Assemble the Ethereum object. eth := &Ethereum{ - config: config, - chainDb: chainDb, - eventMux: stack.EventMux(), - accountManager: stack.AccountManager(), - engine: engine, - closeBloomHandler: make(chan struct{}), - networkID: networkID, - gasPrice: config.Miner.GasPrice, - etherbase: config.Miner.Etherbase, - bloomRequests: make(chan chan *bloombits.Retrieval), - bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), - p2pServer: stack.Server(), - discmix: enode.NewFairMix(0), - shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), + config: config, + chainDb: chainDb, + eventMux: stack.EventMux(), + accountManager: stack.AccountManager(), + engine: engine, + networkID: networkID, + gasPrice: config.Miner.GasPrice, + etherbase: config.Miner.Etherbase, + p2pServer: stack.Server(), + discmix: enode.NewFairMix(0), + shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } eth.antimevKeystore = stack.AntiMEVKeyStore() // Override the address that mining rewards will be sent to. @@ -266,7 +258,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - eth.bloomIndexer.Start(eth.blockchain) fmConfig := filtermaps.Config{History: config.LogHistory, Disabled: config.LogNoHistory, ExportFileName: config.LogExportCheckpoints} chainView := eth.newChainView(eth.blockchain.CurrentBlock()) eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, 0, 0, filtermaps.DefaultParams, fmConfig) @@ -574,7 +565,6 @@ func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downlo func (s *Ethereum) Synced() bool { return s.handler.synced.Load() } func (s *Ethereum) SetSynced() { s.handler.enableSyncedFeatures() } func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } -func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } func (s *Ethereum) SyncMode() downloader.SyncMode { mode, _ := s.handler.chainSync.modeAndLocalHead() return mode @@ -598,9 +588,6 @@ func (s *Ethereum) Start() error { return err } - // Start the bloom bits servicing goroutines - s.startBloomHandlers(params.BloomBitsBlocks) - // Regularly update shutdown marker s.shutdownTracker.Start() @@ -711,8 +698,6 @@ func (s *Ethereum) Stop() error { s.handler.Stop() // Then stop everything else. - s.bloomIndexer.Close() - close(s.closeBloomHandler) ch := make(chan struct{}) s.closeFilterMaps <- ch <-ch diff --git a/eth/bloombits.go b/eth/bloombits.go deleted file mode 100644 index 0cb7050d2..000000000 --- a/eth/bloombits.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2017 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 . - -package eth - -import ( - "time" - - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/core/rawdb" -) - -const ( - // bloomServiceThreads is the number of goroutines used globally by an Ethereum - // instance to service bloombits lookups for all running filters. - bloomServiceThreads = 16 - - // bloomFilterThreads is the number of goroutines used locally per filter to - // multiplex requests onto the global servicing goroutines. - bloomFilterThreads = 3 - - // bloomRetrievalBatch is the maximum number of bloom bit retrievals to service - // in a single batch. - bloomRetrievalBatch = 16 - - // bloomRetrievalWait is the maximum time to wait for enough bloom bit requests - // to accumulate request an entire batch (avoiding hysteresis). - bloomRetrievalWait = time.Duration(0) -) - -// startBloomHandlers starts a batch of goroutines to accept bloom bit database -// retrievals from possibly a range of filters and serving the data to satisfy. -func (eth *Ethereum) startBloomHandlers(sectionSize uint64) { - for i := 0; i < bloomServiceThreads; i++ { - go func() { - for { - select { - case <-eth.closeBloomHandler: - return - - case request := <-eth.bloomRequests: - task := <-request - task.Bitsets = make([][]byte, len(task.Sections)) - for i, section := range task.Sections { - head := rawdb.ReadCanonicalHash(eth.chainDb, (section+1)*sectionSize-1) - if compVector, err := rawdb.ReadBloomBits(eth.chainDb, task.Bit, section, head); err == nil { - if blob, err := bitutil.DecompressBytes(compVector, int(sectionSize/8)); err == nil { - task.Bitsets[i] = blob - } else { - task.Error = err - } - } else { - task.Error = err - } - } - request <- task - } - } - }() - } -} diff --git a/params/network_params.go b/params/network_params.go index 61bd6b2f4..c016e7fcf 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -20,14 +20,6 @@ package params // aren't necessarily consensus related. const ( - // BloomBitsBlocks is the number of blocks a single bloom bit section vector - // contains on the server side. - BloomBitsBlocks uint64 = 4096 - - // BloomConfirms is the number of confirmation blocks before a bloom section is - // considered probably final and its rotated bits are calculated. - BloomConfirms = 256 - // FullImmutabilityThreshold is the number of blocks after which a chain segment is // considered immutable (i.e. soft finality). It is used by the downloader as a // hard limit against deep ancestors, by the blockchain against deep reorgs, by From 96e6fe8a7d045b6d437b5b4d88884f38c6c87974 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:29:51 +0100 Subject: [PATCH 231/354] core: respect history cutoff in txindexer (#31393) In #31384 we unindex TXes prior to the merge block. However when the node starts up it will try to re-index those back if the config is to index the whole chain. This change makes the indexer aware of the history cutoff block, avoiding reindexing in that segment. --------- Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/rawdb/accessors_chain.go | 8 + core/rawdb/accessors_indexes.go | 48 ++- core/txindexer.go | 151 +++++++-- core/txindexer_test.go | 534 ++++++++++++++++++++++---------- 4 files changed, 541 insertions(+), 200 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index ef33d5f63..86b4128a9 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -277,6 +277,14 @@ func WriteTxIndexTail(db ethdb.KeyValueWriter, number uint64) { } } +// DeleteTxIndexTail deletes the number of oldest indexed block +// from database. +func DeleteTxIndexTail(db ethdb.KeyValueWriter) { + if err := db.Delete(txIndexTailKey); err != nil { + log.Crit("Failed to delete the transaction index tail", "err", err) + } +} + // ReadHeaderRange returns the rlp-encoded headers, starting at 'number', and going // backwards towards genesis. This method assumes that the caller already has // placed a cap on count, to prevent DoS issues. diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 1d5897cef..342aedd8d 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -30,13 +30,8 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -// ReadTxLookupEntry retrieves the positional metadata associated with a transaction -// hash to allow retrieving the transaction or receipt by hash. -func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { - data, _ := db.Get(txLookupKey(hash)) - if len(data) == 0 { - return nil - } +// DecodeTxLookupEntry decodes the supplied tx lookup data. +func DecodeTxLookupEntry(data []byte, db ethdb.Reader) *uint64 { // Database v6 tx lookup just stores the block number if len(data) < common.HashLength { number := new(big.Int).SetBytes(data).Uint64() @@ -49,12 +44,22 @@ func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { // Finally try database v3 tx lookup format var entry LegacyTxLookupEntry if err := rlp.DecodeBytes(data, &entry); err != nil { - log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err) + log.Error("Invalid transaction lookup entry RLP", "blob", data, "err", err) return nil } return &entry.BlockIndex } +// ReadTxLookupEntry retrieves the positional metadata associated with a transaction +// hash to allow retrieving the transaction or receipt by hash. +func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { + data, _ := db.Get(txLookupKey(hash)) + if len(data) == 0 { + return nil + } + return DecodeTxLookupEntry(data, db) +} + // writeTxLookupEntry stores a positional metadata for a transaction, // enabling hash based transaction and receipt lookups. func writeTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash, numberBytes []byte) { @@ -95,6 +100,33 @@ func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) { } } +// DeleteAllTxLookupEntries purges all the transaction indexes in the database. +// If condition is specified, only the entry with condition as True will be +// removed; If condition is not specified, the entry is deleted. +func DeleteAllTxLookupEntries(db ethdb.KeyValueStore, condition func([]byte) bool) { + iter := NewKeyLengthIterator(db.NewIterator(txLookupPrefix, nil), common.HashLength+len(txLookupPrefix)) + defer iter.Release() + + batch := db.NewBatch() + for iter.Next() { + if condition == nil || condition(iter.Value()) { + batch.Delete(iter.Key()) + } + if batch.ValueSize() >= ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + log.Crit("Failed to delete transaction lookup entries", "err", err) + } + batch.Reset() + } + } + if batch.ValueSize() > 0 { + if err := batch.Write(); err != nil { + log.Crit("Failed to delete transaction lookup entries", "err", err) + } + batch.Reset() + } +} + // ReadTransaction retrieves a specific transaction from the database, along with // its added positional metadata. func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) { diff --git a/core/txindexer.go b/core/txindexer.go index 293124f68..29e87905d 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -44,7 +44,11 @@ type txIndexer struct { // * 0: means the entire chain should be indexed // * N: means the latest N blocks [HEAD-N+1, HEAD] should be indexed // and all others shouldn't. - limit uint64 + limit uint64 + + // cutoff denotes the block number before which the chain segment should + // be pruned and not available locally. + cutoff uint64 db ethdb.Database progress chan chan TxIndexProgress term chan chan struct{} @@ -55,6 +59,7 @@ type txIndexer struct { func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { indexer := &txIndexer{ limit: limit, + cutoff: chain.HistoryPruningCutoff(), db: chain.db, progress: make(chan chan TxIndexProgress), term: make(chan chan struct{}), @@ -64,7 +69,11 @@ func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { var msg string if limit == 0 { - msg = "entire chain" + if indexer.cutoff == 0 { + msg = "entire chain" + } else { + msg = fmt.Sprintf("blocks since #%d", indexer.cutoff) + } } else { msg = fmt.Sprintf("last %d blocks", limit) } @@ -74,23 +83,31 @@ func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { } // run executes the scheduled indexing/unindexing task in a separate thread. -// If the stop channel is closed, the task should be terminated as soon as -// possible, the done channel will be closed once the task is finished. -func (indexer *txIndexer) run(tail *uint64, head uint64, stop chan struct{}, done chan struct{}) { +// If the stop channel is closed, the task should terminate as soon as possible. +// The done channel will be closed once the task is complete. +// +// Existing transaction indexes are assumed to be valid, with both the head +// and tail above the configured cutoff. +func (indexer *txIndexer) run(head uint64, stop chan struct{}, done chan struct{}) { defer func() { close(done) }() - // Short circuit if chain is empty and nothing to index. - if head == 0 { + // Short circuit if the chain is either empty, or entirely below the + // cutoff point. + if head == 0 || head < indexer.cutoff { return } // The tail flag is not existent, it means the node is just initialized // and all blocks in the chain (part of them may from ancient store) are // not indexed yet, index the chain according to the configured limit. + tail := rawdb.ReadTxIndexTail(indexer.db) if tail == nil { + // Determine the first block for transaction indexing, taking the + // configured cutoff point into account. from := uint64(0) if indexer.limit != 0 && head >= indexer.limit { from = head - indexer.limit + 1 } + from = max(from, indexer.cutoff) rawdb.IndexTransactions(indexer.db, from, head+1, stop, true) return } @@ -98,25 +115,82 @@ func (indexer *txIndexer) run(tail *uint64, head uint64, stop chan struct{}, don // present), while the whole chain are requested for indexing. if indexer.limit == 0 || head < indexer.limit { if *tail > 0 { - // It can happen when chain is rewound to a historical point which - // is even lower than the indexes tail, recap the indexing target - // to new head to avoid reading non-existent block bodies. - end := *tail - if end > head+1 { - end = head + 1 - } - rawdb.IndexTransactions(indexer.db, 0, end, stop, true) + from := max(uint64(0), indexer.cutoff) + rawdb.IndexTransactions(indexer.db, from, *tail, stop, true) } return } // The tail flag is existent, adjust the index range according to configured // limit and the latest chain head. - if head-indexer.limit+1 < *tail { + from := head - indexer.limit + 1 + from = max(from, indexer.cutoff) + if from < *tail { // Reindex a part of missing indices and rewind index tail to HEAD-limit - rawdb.IndexTransactions(indexer.db, head-indexer.limit+1, *tail, stop, true) + rawdb.IndexTransactions(indexer.db, from, *tail, stop, true) } else { // Unindex a part of stale indices and forward index tail to HEAD-limit - rawdb.UnindexTransactions(indexer.db, *tail, head-indexer.limit+1, stop, false) + rawdb.UnindexTransactions(indexer.db, *tail, from, stop, false) + } +} + +// repair ensures that transaction indexes are in a valid state and invalidates +// them if they are not. The following cases are considered invalid: +// * The index tail is higher than the chain head. +// * The chain head is below the configured cutoff, but the index tail is not empty. +// * The index tail is below the configured cutoff, but it is not empty. +func (indexer *txIndexer) repair(head uint64) { + // If the transactions haven't been indexed yet, nothing to repair + tail := rawdb.ReadTxIndexTail(indexer.db) + if tail == nil { + return + } + // The transaction index tail is higher than the chain head, which may occur + // when the chain is rewound to a historical height below the index tail. + // Purge the transaction indexes from the database. **It's not a common case + // to rewind the chain head below the index tail**. + if *tail > head { + // A crash may occur between the two delete operations, + // potentially leaving dangling indexes in the database. + // However, this is considered acceptable. + rawdb.DeleteTxIndexTail(indexer.db) + rawdb.DeleteAllTxLookupEntries(indexer.db, nil) + log.Warn("Purge transaction indexes", "head", head, "tail", *tail) + return + } + + // If the entire chain is below the configured cutoff point, + // removing the tail of transaction indexing and purges the + // transaction indexes. **It's not a common case, as the cutoff + // is usually defined below the chain head**. + if head < indexer.cutoff { + // A crash may occur between the two delete operations, + // potentially leaving dangling indexes in the database. + // However, this is considered acceptable. + // + // The leftover indexes can't be unindexed by scanning + // the blocks as they are not guaranteed to be available. + // Traversing the database directly within the transaction + // index namespace might be slow and expensive, but we + // have no choice. + rawdb.DeleteTxIndexTail(indexer.db) + rawdb.DeleteAllTxLookupEntries(indexer.db, nil) + log.Warn("Purge transaction indexes", "head", head, "cutoff", indexer.cutoff) + return + } + + // The chain head is above the cutoff while the tail is below the + // cutoff. Shift the tail to the cutoff point and remove the indexes + // below. + if *tail < indexer.cutoff { + // A crash may occur between the two delete operations, + // potentially leaving dangling indexes in the database. + // However, this is considered acceptable. + rawdb.WriteTxIndexTail(indexer.db, indexer.cutoff) + rawdb.DeleteAllTxLookupEntries(indexer.db, func(blob []byte) bool { + n := rawdb.DecodeTxLookupEntry(blob, indexer.db) + return n != nil && *n < indexer.cutoff + }) + log.Warn("Purge transaction indexes below cutoff", "tail", *tail, "cutoff", indexer.cutoff) } } @@ -127,39 +201,39 @@ func (indexer *txIndexer) loop(chain *BlockChain) { // Listening to chain events and manipulate the transaction indexes. var ( - stop chan struct{} // Non-nil if background routine is active. - done chan struct{} // Non-nil if background routine is active. - lastHead uint64 // The latest announced chain head (whose tx indexes are assumed created) - lastTail = rawdb.ReadTxIndexTail(indexer.db) // The oldest indexed block, nil means nothing indexed + stop chan struct{} // Non-nil if background routine is active + done chan struct{} // Non-nil if background routine is active + head = rawdb.ReadHeadBlock(indexer.db).NumberU64() // The latest announced chain head headCh = make(chan ChainHeadEvent) sub = chain.SubscribeChainHeadEvent(headCh) ) defer sub.Unsubscribe() + // Validate the transaction indexes and repair if necessary + indexer.repair(head) + // Launch the initial processing if chain is not empty (head != genesis). // This step is useful in these scenarios that chain has no progress. - if head := rawdb.ReadHeadBlock(indexer.db); head != nil && head.Number().Uint64() != 0 { + if head != 0 { stop = make(chan struct{}) done = make(chan struct{}) - lastHead = head.Number().Uint64() - go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.NumberU64(), stop, done) + go indexer.run(head, stop, done) } for { select { - case head := <-headCh: + case h := <-headCh: if done == nil { stop = make(chan struct{}) done = make(chan struct{}) - go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.Header.Number.Uint64(), stop, done) + go indexer.run(h.Header.Number.Uint64(), stop, done) } - lastHead = head.Header.Number.Uint64() + head = h.Header.Number.Uint64() case <-done: stop = nil done = nil - lastTail = rawdb.ReadTxIndexTail(indexer.db) case ch := <-indexer.progress: - ch <- indexer.report(lastHead, lastTail) + ch <- indexer.report(head) case ch := <-indexer.term: if stop != nil { close(stop) @@ -175,12 +249,27 @@ func (indexer *txIndexer) loop(chain *BlockChain) { } // report returns the tx indexing progress. -func (indexer *txIndexer) report(head uint64, tail *uint64) TxIndexProgress { +func (indexer *txIndexer) report(head uint64) TxIndexProgress { + // Special case if the head is even below the cutoff, + // nothing to index. + if head < indexer.cutoff { + return TxIndexProgress{ + Indexed: 0, + Remaining: 0, + } + } + // Compute how many blocks are supposed to be indexed total := indexer.limit if indexer.limit == 0 || total > head { total = head + 1 // genesis included } + length := head - indexer.cutoff + 1 // all available chain for indexing + if total > length { + total = length + } + // Compute how many blocks have been indexed var indexed uint64 + tail := rawdb.ReadTxIndexTail(indexer.db) if tail != nil { indexed = head - *tail + 1 } diff --git a/core/txindexer_test.go b/core/txindexer_test.go index c96a71297..b189a0668 100644 --- a/core/txindexer_test.go +++ b/core/txindexer_test.go @@ -29,6 +29,46 @@ import ( "github.com/ethereum/go-ethereum/params" ) +func verifyIndexes(t *testing.T, db ethdb.Database, block *types.Block, exist bool) { + for _, tx := range block.Transactions() { + lookup := rawdb.ReadTxLookupEntry(db, tx.Hash()) + if exist && lookup == nil { + t.Fatalf("missing %d %x", block.NumberU64(), tx.Hash().Hex()) + } + if !exist && lookup != nil { + t.Fatalf("unexpected %d %x", block.NumberU64(), tx.Hash().Hex()) + } + } +} + +func verify(t *testing.T, db ethdb.Database, blocks []*types.Block, expTail uint64) { + tail := rawdb.ReadTxIndexTail(db) + if tail == nil { + t.Fatal("Failed to write tx index tail") + return + } + if *tail != expTail { + t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail) + } + for _, b := range blocks { + if b.Number().Uint64() < *tail { + verifyIndexes(t, db, b, false) + } else { + verifyIndexes(t, db, b, true) + } + } +} + +func verifyNoIndex(t *testing.T, db ethdb.Database, blocks []*types.Block) { + tail := rawdb.ReadTxIndexTail(db) + if tail != nil { + t.Fatalf("Unexpected tx index tail %d", *tail) + } + for _, b := range blocks { + verifyIndexes(t, db, b, false) + } +} + // TestTxIndexer tests the functionalities for managing transaction indexes. func TestTxIndexer(t *testing.T) { var ( @@ -50,163 +90,149 @@ func TestTxIndexer(t *testing.T) { gen.AddTx(tx) nonce += 1 }) + var cases = []struct { + limits []uint64 + tails []uint64 + }{ + { + limits: []uint64{0, 1, 64, 129, 0}, + tails: []uint64{0, 128, 65, 0, 0}, + }, + { + limits: []uint64{64, 1, 64, 0}, + tails: []uint64{65, 128, 65, 0}, + }, + { + limits: []uint64{127, 1, 64, 0}, + tails: []uint64{2, 128, 65, 0}, + }, + { + limits: []uint64{128, 1, 64, 0}, + tails: []uint64{1, 128, 65, 0}, + }, + { + limits: []uint64{129, 1, 64, 0}, + tails: []uint64{0, 128, 65, 0}, + }, + } + for _, c := range cases { + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) + rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) - // verifyIndexes checks if the transaction indexes are present or not - // of the specified block. - verifyIndexes := func(db ethdb.Database, number uint64, exist bool) { - if number == 0 { - return + // Index the initial blocks from ancient store + indexer := &txIndexer{ + limit: 0, + db: db, + progress: make(chan chan TxIndexProgress), } - block := blocks[number-1] - for _, tx := range block.Transactions() { - lookup := rawdb.ReadTxLookupEntry(db, tx.Hash()) - if exist && lookup == nil { - t.Fatalf("missing %d %x", number, tx.Hash().Hex()) - } - if !exist && lookup != nil { - t.Fatalf("unexpected %d %x", number, tx.Hash().Hex()) - } + for i, limit := range c.limits { + indexer.limit = limit + indexer.run(chainHead, make(chan struct{}), make(chan struct{})) + verify(t, db, blocks, c.tails[i]) } + db.Close() } - verify := func(db ethdb.Database, expTail uint64, indexer *txIndexer) { - tail := rawdb.ReadTxIndexTail(db) - if tail == nil { - t.Fatal("Failed to write tx index tail") - } - if *tail != expTail { - t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail) - } - if *tail != 0 { - for number := uint64(0); number < *tail; number += 1 { - verifyIndexes(db, number, false) - } - } - for number := *tail; number <= chainHead; number += 1 { - verifyIndexes(db, number, true) - } - progress := indexer.report(chainHead, tail) - if !progress.Done() { - t.Fatalf("Expect fully indexed") +} + +func TestTxIndexerRepair(t *testing.T) { + var ( + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, + BaseFee: big.NewInt(params.InitialBaseFee), } + engine = ethash.NewFaker() + nonce = uint64(0) + chainHead = uint64(128) + ) + _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(chainHead), func(i int, gen *BlockGen) { + tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey) + gen.AddTx(tx) + nonce += 1 + }) + tailPointer := func(n uint64) *uint64 { + return &n } - var cases = []struct { - limitA uint64 - tailA uint64 - limitB uint64 - tailB uint64 - limitC uint64 - tailC uint64 + limit uint64 + head uint64 + cutoff uint64 + expTail *uint64 }{ + // if *tail > head => purge indexes + { + limit: 0, + head: chainHead / 2, + cutoff: 0, + expTail: tailPointer(0), + }, + { + limit: 1, // tail = 128 + head: chainHead / 2, // newhead = 64 + cutoff: 0, + expTail: nil, + }, + { + limit: 64, // tail = 65 + head: chainHead / 2, // newhead = 64 + cutoff: 0, + expTail: nil, + }, + { + limit: 65, // tail = 64 + head: chainHead / 2, // newhead = 64 + cutoff: 0, + expTail: tailPointer(64), + }, + { + limit: 66, // tail = 63 + head: chainHead / 2, // newhead = 64 + cutoff: 0, + expTail: tailPointer(63), + }, + + // if tail < cutoff => remove indexes below cutoff + { + limit: 0, // tail = 0 + head: chainHead, // head = 128 + cutoff: chainHead, // cutoff = 128 + expTail: tailPointer(chainHead), + }, + { + limit: 1, // tail = 128 + head: chainHead, // head = 128 + cutoff: chainHead, // cutoff = 128 + expTail: tailPointer(128), + }, + { + limit: 2, // tail = 127 + head: chainHead, // head = 128 + cutoff: chainHead, // cutoff = 128 + expTail: tailPointer(chainHead), + }, + { + limit: 2, // tail = 127 + head: chainHead, // head = 128 + cutoff: chainHead / 2, // cutoff = 64 + expTail: tailPointer(127), + }, + + // if head < cutoff => purge indexes { - // LimitA: 0 - // TailA: 0 - // - // all blocks are indexed - limitA: 0, - tailA: 0, - - // LimitB: 1 - // TailB: 128 - // - // block-128 is indexed - limitB: 1, - tailB: 128, - - // LimitB: 64 - // TailB: 65 - // - // block [65, 128] are indexed - limitC: 64, - tailC: 65, - }, - { - // LimitA: 64 - // TailA: 65 - // - // block [65, 128] are indexed - limitA: 64, - tailA: 65, - - // LimitB: 1 - // TailB: 128 - // - // block-128 is indexed - limitB: 1, - tailB: 128, - - // LimitB: 64 - // TailB: 65 - // - // block [65, 128] are indexed - limitC: 64, - tailC: 65, - }, - { - // LimitA: 127 - // TailA: 2 - // - // block [2, 128] are indexed - limitA: 127, - tailA: 2, - - // LimitB: 1 - // TailB: 128 - // - // block-128 is indexed - limitB: 1, - tailB: 128, - - // LimitB: 64 - // TailB: 65 - // - // block [65, 128] are indexed - limitC: 64, - tailC: 65, - }, - { - // LimitA: 128 - // TailA: 1 - // - // block [2, 128] are indexed - limitA: 128, - tailA: 1, - - // LimitB: 1 - // TailB: 128 - // - // block-128 is indexed - limitB: 1, - tailB: 128, - - // LimitB: 64 - // TailB: 65 - // - // block [65, 128] are indexed - limitC: 64, - tailC: 65, - }, - { - // LimitA: 129 - // TailA: 0 - // - // block [0, 128] are indexed - limitA: 129, - tailA: 0, - - // LimitB: 1 - // TailB: 128 - // - // block-128 is indexed - limitB: 1, - tailB: 128, - - // LimitB: 64 - // TailB: 65 - // - // block [65, 128] are indexed - limitC: 64, - tailC: 65, + limit: 0, // tail = 0 + head: chainHead, // head = 128 + cutoff: 2 * chainHead, // cutoff = 256 + expTail: nil, + }, + { + limit: 64, // tail = 65 + head: chainHead, // head = 128 + cutoff: chainHead / 2, // cutoff = 64 + expTail: tailPointer(65), }, } for _, c := range cases { @@ -215,26 +241,212 @@ func TestTxIndexer(t *testing.T) { // Index the initial blocks from ancient store indexer := &txIndexer{ - limit: c.limitA, + limit: c.limit, db: db, progress: make(chan chan TxIndexProgress), } - indexer.run(nil, 128, make(chan struct{}), make(chan struct{})) - verify(db, c.tailA, indexer) + indexer.run(chainHead, make(chan struct{}), make(chan struct{})) + + indexer.cutoff = c.cutoff + indexer.repair(c.head) + + if c.expTail == nil { + verifyNoIndex(t, db, blocks) + } else { + verify(t, db, blocks, *c.expTail) + } + db.Close() + } +} + +func TestTxIndexerReport(t *testing.T) { + var ( + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + engine = ethash.NewFaker() + nonce = uint64(0) + chainHead = uint64(128) + ) + _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(chainHead), func(i int, gen *BlockGen) { + tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey) + gen.AddTx(tx) + nonce += 1 + }) + tailPointer := func(n uint64) *uint64 { + return &n + } + var cases = []struct { + head uint64 + limit uint64 + cutoff uint64 + tail *uint64 + expIndexed uint64 + expRemaining uint64 + }{ + // The entire chain is supposed to be indexed + { + // head = 128, limit = 0, cutoff = 0 => all: 129 + head: chainHead, + limit: 0, + cutoff: 0, - indexer.limit = c.limitB - indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) - verify(db, c.tailB, indexer) + // tail = 0 + tail: tailPointer(0), + expIndexed: 129, + expRemaining: 0, + }, + { + // head = 128, limit = 0, cutoff = 0 => all: 129 + head: chainHead, + limit: 0, + cutoff: 0, - indexer.limit = c.limitC - indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) - verify(db, c.tailC, indexer) + // tail = 1 + tail: tailPointer(1), + expIndexed: 128, + expRemaining: 1, + }, + { + // head = 128, limit = 0, cutoff = 0 => all: 129 + head: chainHead, + limit: 0, + cutoff: 0, - // Recover all indexes - indexer.limit = 0 - indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{})) - verify(db, 0, indexer) + // tail = 128 + tail: tailPointer(chainHead), + expIndexed: 1, + expRemaining: 128, + }, + { + // head = 128, limit = 256, cutoff = 0 => all: 129 + head: chainHead, + limit: 256, + cutoff: 0, + // tail = 0 + tail: tailPointer(0), + expIndexed: 129, + expRemaining: 0, + }, + + // The chain with specific range is supposed to be indexed + { + // head = 128, limit = 64, cutoff = 0 => index: [65, 128] + head: chainHead, + limit: 64, + cutoff: 0, + + // tail = 0, part of them need to be unindexed + tail: tailPointer(0), + expIndexed: 129, + expRemaining: 0, + }, + { + // head = 128, limit = 64, cutoff = 0 => index: [65, 128] + head: chainHead, + limit: 64, + cutoff: 0, + + // tail = 64, one of them needs to be unindexed + tail: tailPointer(64), + expIndexed: 65, + expRemaining: 0, + }, + { + // head = 128, limit = 64, cutoff = 0 => index: [65, 128] + head: chainHead, + limit: 64, + cutoff: 0, + + // tail = 65, all of them have been indexed + tail: tailPointer(65), + expIndexed: 64, + expRemaining: 0, + }, + { + // head = 128, limit = 64, cutoff = 0 => index: [65, 128] + head: chainHead, + limit: 64, + cutoff: 0, + + // tail = 66, one of them has to be indexed + tail: tailPointer(66), + expIndexed: 63, + expRemaining: 1, + }, + + // The chain with configured cutoff, the chain range could be capped + { + // head = 128, limit = 64, cutoff = 66 => index: [66, 128] + head: chainHead, + limit: 64, + cutoff: 66, + + // tail = 0, part of them need to be unindexed + tail: tailPointer(0), + expIndexed: 129, + expRemaining: 0, + }, + { + // head = 128, limit = 64, cutoff = 66 => index: [66, 128] + head: chainHead, + limit: 64, + cutoff: 66, + + // tail = 66, all of them have been indexed + tail: tailPointer(66), + expIndexed: 63, + expRemaining: 0, + }, + { + // head = 128, limit = 64, cutoff = 66 => index: [66, 128] + head: chainHead, + limit: 64, + cutoff: 66, + + // tail = 67, one of them has to be indexed + tail: tailPointer(67), + expIndexed: 62, + expRemaining: 1, + }, + { + // head = 128, limit = 64, cutoff = 256 => index: [66, 128] + head: chainHead, + limit: 0, + cutoff: 256, + tail: nil, + expIndexed: 0, + expRemaining: 0, + }, + } + for _, c := range cases { + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) + rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) + + // Index the initial blocks from ancient store + indexer := &txIndexer{ + limit: c.limit, + cutoff: c.cutoff, + db: db, + progress: make(chan chan TxIndexProgress), + } + if c.tail != nil { + rawdb.WriteTxIndexTail(db, *c.tail) + } + p := indexer.report(c.head) + if p.Indexed != c.expIndexed { + t.Fatalf("Unexpected indexed: %d, expected: %d", p.Indexed, c.expIndexed) + } + if p.Remaining != c.expRemaining { + t.Fatalf("Unexpected remaining: %d, expected: %d", p.Remaining, c.expRemaining) + } db.Close() } } From 7c5f770a6687cd92235880c3474c413bd88692f3 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 21 Mar 2025 13:12:56 +0100 Subject: [PATCH 232/354] cmd/geth: add prune history command (#31384) This adds a new subcommand 'geth prune-history' that removes the pre-merge history on supported networks. Geth is not fully ready to work in this mode, please do not run this command on your production node. --------- Co-authored-by: Felix Lange --- cmd/geth/chaincmd.go | 61 ++++++++++++++++++++++ cmd/geth/main.go | 1 + core/blockchain.go | 3 +- core/rawdb/accessors_indexes.go | 5 +- core/rawdb/chain_iterator.go | 36 +++++++++++++ core/rawdb/chain_iterator_test.go | 85 +++++++++++++++++++++++-------- core/txindexer.go | 3 +- tests/testdata | 2 +- 8 files changed, 171 insertions(+), 25 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 95239bd64..05c8bc4c7 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/era" "github.com/ethereum/go-ethereum/log" @@ -189,6 +190,18 @@ It's deprecated, please use "geth db import" instead. This command dumps out the state for a given block (or latest, if none provided). `, } + + pruneCommand = &cli.Command{ + Action: pruneHistory, + Name: "prune-history", + Usage: "Prune blockchain history (block bodies and receipts) up to the merge block", + ArgsUsage: "", + Flags: utils.DatabaseFlags, + Description: ` +The prune-history command removes historical block bodies and receipts from the +blockchain database up to the merge block, while preserving block headers. This +helps reduce storage requirements for nodes that don't need full historical data.`, + } ) // initGenesis will initialise the given JSON format genesis file and writes it as @@ -598,3 +611,51 @@ func hashish(x string) bool { _, err := strconv.Atoi(x) return err != nil } + +func pruneHistory(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + // Open the chain database + chain, chaindb := utils.MakeChain(ctx, stack, false) + defer chaindb.Close() + defer chain.Stop() + + // Determine the prune point. This will be the first PoS block. + prunePoint, ok := ethconfig.HistoryPrunePoints[chain.Genesis().Hash()] + if !ok || prunePoint == nil { + return errors.New("prune point not found") + } + var ( + mergeBlock = prunePoint.BlockNumber + mergeBlockHash = prunePoint.BlockHash.Hex() + ) + + // Check we're far enough past merge to ensure all data is in freezer + currentHeader := chain.CurrentHeader() + if currentHeader == nil { + return errors.New("current header not found") + } + if currentHeader.Number.Uint64() < mergeBlock+params.FullImmutabilityThreshold { + return fmt.Errorf("chain not far enough past merge block, need %d more blocks", + mergeBlock+params.FullImmutabilityThreshold-currentHeader.Number.Uint64()) + } + + // Double-check the prune block in db has the expected hash. + hash := rawdb.ReadCanonicalHash(chaindb, mergeBlock) + if hash != common.HexToHash(mergeBlockHash) { + return fmt.Errorf("merge block hash mismatch: got %s, want %s", hash.Hex(), mergeBlockHash) + } + + log.Info("Starting history pruning", "head", currentHeader.Number, "tail", mergeBlock, "tailHash", mergeBlockHash) + start := time.Now() + rawdb.PruneTransactionIndex(chaindb, mergeBlock) + if _, err := chaindb.TruncateTail(mergeBlock); err != nil { + return fmt.Errorf("failed to truncate ancient data: %v", err) + } + log.Info("History pruning completed", "tail", mergeBlock, "elapsed", common.PrettyDuration(time.Since(start))) + + // TODO(s1na): what if there is a crash between the two prune operations? + + return nil +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f1a1ebfa7..08af9206f 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -244,6 +244,7 @@ func init() { removedbCommand, dumpCommand, dumpGenesisCommand, + pruneCommand, // See accountcmd.go: accountCommand, walletCommand, diff --git a/core/blockchain.go b/core/blockchain.go index 84a133ca1..51b55e133 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -342,7 +342,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) bc.processor = NewStateProcessor(chainConfig, bc.hc) - bc.genesisBlock = bc.GetBlockByNumber(0) + genesisHeader := bc.GetHeaderByNumber(0) + bc.genesisBlock = types.NewBlockWithHeader(genesisHeader) if bc.genesisBlock == nil { return nil, ErrNoGenesis } diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 342aedd8d..7bb96b1fa 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -103,13 +103,14 @@ func DeleteTxLookupEntries(db ethdb.KeyValueWriter, hashes []common.Hash) { // DeleteAllTxLookupEntries purges all the transaction indexes in the database. // If condition is specified, only the entry with condition as True will be // removed; If condition is not specified, the entry is deleted. -func DeleteAllTxLookupEntries(db ethdb.KeyValueStore, condition func([]byte) bool) { +func DeleteAllTxLookupEntries(db ethdb.KeyValueStore, condition func(common.Hash, []byte) bool) { iter := NewKeyLengthIterator(db.NewIterator(txLookupPrefix, nil), common.HashLength+len(txLookupPrefix)) defer iter.Release() batch := db.NewBatch() for iter.Next() { - if condition == nil || condition(iter.Value()) { + txhash := common.Hash(iter.Key()[1:]) + if condition == nil || condition(txhash, iter.Value()) { batch.Delete(iter.Key()) } if batch.ValueSize() >= ethdb.IdealBatchSize { diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 759e5913d..ecbc44e1f 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -17,6 +17,7 @@ package rawdb import ( + "encoding/binary" "runtime" "sync/atomic" "time" @@ -361,3 +362,38 @@ func UnindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch func unindexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) { unindexTransactions(db, from, to, interrupt, hook, false) } + +// PruneTransactionIndex removes all tx index entries below a certain block number. +func PruneTransactionIndex(db ethdb.Database, pruneBlock uint64) { + tail := ReadTxIndexTail(db) + if tail == nil || *tail > pruneBlock { + return // no index, or index ends above pruneBlock + } + // There are blocks below pruneBlock in the index. Iterate the entire index to remove + // their entries. Note if this fails, the index is messed up, but tail still points to + // the old tail. + var count, removed int + DeleteAllTxLookupEntries(db, func(txhash common.Hash, v []byte) bool { + count++ + if count%10000000 == 0 { + log.Info("Pruning tx index", "count", count, "removed", removed) + } + if len(v) > 8 { + log.Error("Skipping legacy tx index entry", "hash", txhash) + return false + } + bn := decodeNumber(v) + if bn < pruneBlock { + removed++ + return true + } + return false + }) + WriteTxIndexTail(db, pruneBlock) +} + +func decodeNumber(b []byte) uint64 { + var numBuffer [8]byte + copy(numBuffer[8-len(b):], b) + return binary.BigEndian.Uint64(numBuffer[:]) +} diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index 390424f67..75bd5a9a9 100644 --- a/core/rawdb/chain_iterator_test.go +++ b/core/rawdb/chain_iterator_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" ) func TestChainIterator(t *testing.T) { @@ -102,19 +103,18 @@ func TestChainIterator(t *testing.T) { } } -func TestIndexTransactions(t *testing.T) { - // Construct test chain db - chainDb := NewMemoryDatabase() - - var block *types.Block +func initDatabaseWithTransactions(db ethdb.Database) ([]*types.Block, []*types.Transaction) { + var blocks []*types.Block var txs []*types.Transaction to := common.BytesToAddress([]byte{0x11}) // Write empty genesis block - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) - WriteBlock(chainDb, block) - WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) + block := types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) + WriteBlock(db, block) + WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + blocks = append(blocks, block) + // Create transactions. for i := uint64(1); i <= 10; i++ { var tx *types.Transaction if i%2 == 0 { @@ -138,10 +138,21 @@ func TestIndexTransactions(t *testing.T) { }) } txs = append(txs, tx) - block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher()) - WriteBlock(chainDb, block) - WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()) + block := types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher()) + WriteBlock(db, block) + WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + blocks = append(blocks, block) } + + return blocks, txs +} + +func TestIndexTransactions(t *testing.T) { + // Construct test chain db + chainDB := NewMemoryDatabase() + + _, txs := initDatabaseWithTransactions(chainDB) + // verify checks whether the tx indices in the range [from, to) // is expected. verify := func(from, to int, exist bool, tail uint64) { @@ -149,7 +160,7 @@ func TestIndexTransactions(t *testing.T) { if i == 0 { continue } - number := ReadTxLookupEntry(chainDb, txs[i-1].Hash()) + number := ReadTxLookupEntry(chainDB, txs[i-1].Hash()) if exist && number == nil { t.Fatalf("Transaction index %d missing", i) } @@ -157,29 +168,29 @@ func TestIndexTransactions(t *testing.T) { t.Fatalf("Transaction index %d is not deleted", i) } } - number := ReadTxIndexTail(chainDb) + number := ReadTxIndexTail(chainDB) if number == nil || *number != tail { t.Fatalf("Transaction tail mismatch") } } - IndexTransactions(chainDb, 5, 11, nil, false) + IndexTransactions(chainDB, 5, 11, nil, false) verify(5, 11, true, 5) verify(0, 5, false, 5) - IndexTransactions(chainDb, 0, 5, nil, false) + IndexTransactions(chainDB, 0, 5, nil, false) verify(0, 11, true, 0) - UnindexTransactions(chainDb, 0, 5, nil, false) + UnindexTransactions(chainDB, 0, 5, nil, false) verify(5, 11, true, 5) verify(0, 5, false, 5) - UnindexTransactions(chainDb, 5, 11, nil, false) + UnindexTransactions(chainDB, 5, 11, nil, false) verify(0, 11, false, 11) // Testing corner cases signal := make(chan struct{}) var once sync.Once - indexTransactionsForTesting(chainDb, 5, 11, signal, func(n uint64) bool { + indexTransactionsForTesting(chainDB, 5, 11, signal, func(n uint64) bool { if n <= 8 { once.Do(func() { close(signal) @@ -190,11 +201,11 @@ func TestIndexTransactions(t *testing.T) { }) verify(9, 11, true, 9) verify(0, 9, false, 9) - IndexTransactions(chainDb, 0, 9, nil, false) + IndexTransactions(chainDB, 0, 9, nil, false) signal = make(chan struct{}) var once2 sync.Once - unindexTransactionsForTesting(chainDb, 0, 11, signal, func(n uint64) bool { + unindexTransactionsForTesting(chainDB, 0, 11, signal, func(n uint64) bool { if n >= 8 { once2.Do(func() { close(signal) @@ -206,3 +217,37 @@ func TestIndexTransactions(t *testing.T) { verify(8, 11, true, 8) verify(0, 8, false, 8) } + +func TestPruneTransactionIndex(t *testing.T) { + chainDB := NewMemoryDatabase() + blocks, _ := initDatabaseWithTransactions(chainDB) + lastBlock := blocks[len(blocks)-1].NumberU64() + pruneBlock := lastBlock - 3 + + IndexTransactions(chainDB, 0, lastBlock+1, nil, false) + + // Check all transactions are in index. + for _, block := range blocks { + for _, tx := range block.Transactions() { + num := ReadTxLookupEntry(chainDB, tx.Hash()) + if num == nil || *num != block.NumberU64() { + t.Fatalf("wrong TxLookup entry: %x -> %v", tx.Hash(), num) + } + } + } + + PruneTransactionIndex(chainDB, pruneBlock) + + // Check transactions from old blocks not included. + for _, block := range blocks { + for _, tx := range block.Transactions() { + num := ReadTxLookupEntry(chainDB, tx.Hash()) + if block.NumberU64() < pruneBlock && num != nil { + t.Fatalf("TxLookup entry not removed: %x -> %v", tx.Hash(), num) + } + if block.NumberU64() >= pruneBlock && (num == nil || *num != block.NumberU64()) { + t.Fatalf("wrong TxLookup entry after pruning: %x -> %v", tx.Hash(), num) + } + } + } +} diff --git a/core/txindexer.go b/core/txindexer.go index 29e87905d..d0fce302f 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -186,7 +187,7 @@ func (indexer *txIndexer) repair(head uint64) { // potentially leaving dangling indexes in the database. // However, this is considered acceptable. rawdb.WriteTxIndexTail(indexer.db, indexer.cutoff) - rawdb.DeleteAllTxLookupEntries(indexer.db, func(blob []byte) bool { + rawdb.DeleteAllTxLookupEntries(indexer.db, func(txhash common.Hash, blob []byte) bool { n := rawdb.DecodeTxLookupEntry(blob, indexer.db) return n != nil && *n < indexer.cutoff }) diff --git a/tests/testdata b/tests/testdata index 81862e484..faf33b471 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 81862e4848585a438d64f911a19b3825f0f4cd95 +Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 From d3a8246fc10592a94aff6feee9bbabf4fb1917d5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Mar 2025 21:08:51 +0800 Subject: [PATCH 233/354] eth/filter: downgrade log level (#31450) --- eth/filters/filter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/filters/filter.go b/eth/filters/filter.go index cedb5b351..b743c2599 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -372,7 +372,7 @@ func (f *Filter) indexedLogs(ctx context.Context, mb filtermaps.MatcherBackend, // iteration and bloom matching. func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) { start := time.Now() - log.Warn("Performing unindexed log search", "begin", begin, "end", end) + log.Debug("Performing unindexed log search", "begin", begin, "end", end) var matches []*types.Log for blockNumber := begin; blockNumber <= end; blockNumber++ { select { @@ -390,7 +390,7 @@ func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types } matches = append(matches, found...) } - log.Trace("Performed unindexed log search", "begin", begin, "end", end, "matches", len(matches), "elapsed", common.PrettyDuration(time.Since(start))) + log.Debug("Performed unindexed log search", "begin", begin, "end", end, "matches", len(matches), "elapsed", common.PrettyDuration(time.Since(start))) return matches, nil } From aa29dc8bf05a1e4884aee3f95ba6f48fb9eeeb92 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Sun, 23 Mar 2025 17:38:26 +0100 Subject: [PATCH 234/354] internal/ethapi: return code 3 from call/estimateGas even if a revert reason was not returned (#31456) --- internal/ethapi/api.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index eeda6b811..eac4b8dd7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -846,8 +846,7 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN if err != nil { return nil, err } - // If the result contains a revert reason, try to unpack and return it. - if len(result.Revert()) > 0 { + if errors.Is(result.Err, vm.ErrExecutionReverted) { return nil, newRevertError(result.Revert()) } return result.Return(), result.Err @@ -943,7 +942,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { - if len(revert) > 0 { + if errors.Is(err, vm.ErrExecutionReverted) { return 0, newRevertError(revert) } return 0, err From 308bdc951bb4035f6dc5df9a003b05f5852c3492 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 24 Mar 2025 10:07:38 +0100 Subject: [PATCH 235/354] core/rawdb: improve database stats output (#31463) Instead of reporting all filtermaps stuff in one line, I'm breaking it down into the three separate kinds of entries here. ``` +-----------------------+-----------------------------+------------+------------+ | DATABASE | CATEGORY | SIZE | ITEMS | +-----------------------+-----------------------------+------------+------------+ | Key-Value store | Log index filter-map rows | 59.21 GiB | 616077345 | | Key-Value store | Log index last-block-of-map | 12.35 MiB | 269755 | | Key-Value store | Log index block-lv | 421.70 MiB | 22109169 | ``` Also added some other changes to make it easier to debug: - restored bloombits into the inspect output, so we notice if it doesn't get deleted for some reason - tracking of unaccounted key examples --- core/rawdb/accessors_indexes.go | 2 +- core/rawdb/database.go | 123 +++++++++++++++++++++----------- core/rawdb/schema.go | 23 +++--- 3 files changed, 94 insertions(+), 54 deletions(-) diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 7bb96b1fa..297e339c8 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -502,5 +502,5 @@ func DeleteBloomBitsDb(db ethdb.KeyValueRangeDeleter) error { if err := deletePrefixRange(db, bloomBitsPrefix); err != nil { return err } - return deletePrefixRange(db, bloomBitsIndexPrefix) + return deletePrefixRange(db, bloomBitsMetaPrefix) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 9bfdc4422..60bb18488 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -20,8 +20,10 @@ import ( "bytes" "errors" "fmt" + "maps" "os" "path/filepath" + "slices" "strings" "time" @@ -360,24 +362,27 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { logged = time.Now() // Key-value store statistics - headers stat - bodies stat - receipts stat - tds stat - numHashPairings stat - hashNumPairings stat - legacyTries stat - stateLookups stat - accountTries stat - storageTries stat - codes stat - txLookups stat - accountSnaps stat - storageSnaps stat - preimages stat - filterMaps stat - beaconHeaders stat - cliqueSnaps stat + headers stat + bodies stat + receipts stat + tds stat + numHashPairings stat + hashNumPairings stat + legacyTries stat + stateLookups stat + accountTries stat + storageTries stat + codes stat + txLookups stat + accountSnaps stat + storageSnaps stat + preimages stat + beaconHeaders stat + cliqueSnaps stat + bloomBits stat + filterMapRows stat + filterMapLastBlock stat + filterMapBlockLV stat // Verkle statistics verkleTries stat @@ -393,6 +398,11 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { // Totals total common.StorageSize + + // This map tracks example keys for unaccounted data. + // For each unique two-byte prefix, the first unaccounted key encountered + // by the iterator will be stored. + unaccountedKeys = make(map[[2]byte][]byte) ) // Inspect key-value database first. for it.Next() { @@ -436,19 +446,33 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { metadata.Add(size) case bytes.HasPrefix(key, genesisPrefix) && len(key) == (len(genesisPrefix)+common.HashLength): metadata.Add(size) - case bytes.HasPrefix(key, []byte(filterMapsPrefix)): - filterMaps.Add(size) case bytes.HasPrefix(key, skeletonHeaderPrefix) && len(key) == (len(skeletonHeaderPrefix)+8): beaconHeaders.Add(size) case bytes.HasPrefix(key, CliqueSnapshotPrefix) && len(key) == 7+common.HashLength: cliqueSnaps.Add(size) - case bytes.HasPrefix(key, ChtTablePrefix) || - bytes.HasPrefix(key, ChtIndexTablePrefix) || - bytes.HasPrefix(key, ChtPrefix): // Canonical hash trie + + // new log index + case bytes.HasPrefix(key, filterMapRowPrefix) && len(key) <= len(filterMapRowPrefix)+9: + filterMapRows.Add(size) + case bytes.HasPrefix(key, filterMapLastBlockPrefix) && len(key) == len(filterMapLastBlockPrefix)+4: + filterMapLastBlock.Add(size) + case bytes.HasPrefix(key, filterMapBlockLVPrefix) && len(key) == len(filterMapBlockLVPrefix)+8: + filterMapBlockLV.Add(size) + + // old log index (deprecated) + case bytes.HasPrefix(key, bloomBitsPrefix) && len(key) == (len(bloomBitsPrefix)+10+common.HashLength): + bloomBits.Add(size) + case bytes.HasPrefix(key, bloomBitsMetaPrefix) && len(key) < len(bloomBitsMetaPrefix)+8: + bloomBits.Add(size) + + // LES indexes (deprecated) + case bytes.HasPrefix(key, chtTablePrefix) || + bytes.HasPrefix(key, chtIndexTablePrefix) || + bytes.HasPrefix(key, chtPrefix): // Canonical hash trie chtTrieNodes.Add(size) - case bytes.HasPrefix(key, BloomTrieTablePrefix) || - bytes.HasPrefix(key, BloomTrieIndexPrefix) || - bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub + case bytes.HasPrefix(key, bloomTrieTablePrefix) || + bytes.HasPrefix(key, bloomTrieIndexPrefix) || + bytes.HasPrefix(key, bloomTriePrefix): // Bloomtrie sub bloomTrieNodes.Add(size) // Verkle trie data is detected, determine the sub-category @@ -468,24 +492,19 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { default: unaccounted.Add(size) } + + // Metadata keys + case slices.ContainsFunc(knownMetadataKeys, func(x []byte) bool { return bytes.Equal(x, key) }): + metadata.Add(size) + default: - var accounted bool - for _, meta := range [][]byte{ - databaseVersionKey, headHeaderKey, headBlockKey, headFastBlockKey, headFinalizedBlockKey, - lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey, snapshotJournalKey, - snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, - uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, - persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey, - } { - if bytes.Equal(key, meta) { - metadata.Add(size) - accounted = true - break + unaccounted.Add(size) + if len(key) >= 2 { + prefix := [2]byte(key[:2]) + if _, ok := unaccountedKeys[prefix]; !ok { + unaccountedKeys[prefix] = bytes.Clone(key) } } - if !accounted { - unaccounted.Add(size) - } } count++ if count%1000 == 0 && time.Since(logged) > 8*time.Second { @@ -502,7 +521,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Block number->hash", numHashPairings.Size(), numHashPairings.Count()}, {"Key-Value store", "Block hash->number", hashNumPairings.Size(), hashNumPairings.Count()}, {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, - {"Key-Value store", "Log search index", filterMaps.Size(), filterMaps.Count()}, + {"Key-Value store", "Log index filter-map rows", filterMapRows.Size(), filterMapRows.Count()}, + {"Key-Value store", "Log index last-block-of-map", filterMapLastBlock.Size(), filterMapLastBlock.Count()}, + {"Key-Value store", "Log index block-lv", filterMapBlockLV.Size(), filterMapBlockLV.Count()}, + {"Key-Value store", "Log bloombits (deprecated)", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, {"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()}, {"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()}, @@ -543,10 +565,23 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { if unaccounted.size > 0 { log.Error("Database contains unaccounted data", "size", unaccounted.size, "count", unaccounted.count) + for _, e := range slices.SortedFunc(maps.Values(unaccountedKeys), bytes.Compare) { + log.Error(fmt.Sprintf(" example key: %x", e)) + } } return nil } +// This is the list of known 'metadata' keys stored in the databasse. +var knownMetadataKeys = [][]byte{ + databaseVersionKey, headHeaderKey, headBlockKey, headFastBlockKey, headFinalizedBlockKey, + lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey, snapshotJournalKey, + snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, + uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, + persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey, + filterMapsRangeKey, +} + // printChainMetadata prints out chain metadata to stderr. func printChainMetadata(db ethdb.KeyValueStore) { fmt.Fprintf(os.Stderr, "Chain metadata\n") @@ -566,6 +601,7 @@ func ReadChainMetadata(db ethdb.KeyValueStore) [][]string { } return fmt.Sprintf("%d (%#x)", *val, *val) } + data := [][]string{ {"databaseVersion", pp(ReadDatabaseVersion(db))}, {"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(db))}, @@ -582,5 +618,8 @@ func ReadChainMetadata(db ethdb.KeyValueStore) [][]string { if b := ReadSkeletonSyncStatus(db); b != nil { data = append(data, []string{"SkeletonSyncStatus", string(b)}) } + if fmr, ok, _ := ReadFilterMapsRange(db); ok { + data = append(data, []string{"filterMapsRange", fmt.Sprintf("%+v", fmr)}) + } return data } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index dacd71a5d..ce081db96 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -128,29 +128,30 @@ var ( configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db - // bloomBitsIndexPrefix is the data table of a chain indexer to track its progress - bloomBitsIndexPrefix = []byte("iB") - - ChtPrefix = []byte("chtRootV2-") // ChtPrefix + chtNum (uint64 big endian) -> trie root hash - ChtTablePrefix = []byte("cht-") - ChtIndexTablePrefix = []byte("chtIndexV2-") - - BloomTriePrefix = []byte("bltRoot-") // BloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash - BloomTrieTablePrefix = []byte("blt-") - BloomTrieIndexPrefix = []byte("bltIndex-") - CliqueSnapshotPrefix = []byte("clique-") BestUpdateKey = []byte("update-") // bigEndian64(syncPeriod) -> RLP(types.LightClientUpdate) (nextCommittee only referenced by root hash) FixedCommitteeRootKey = []byte("fixedRoot-") // bigEndian64(syncPeriod) -> committee root hash SyncCommitteeKey = []byte("committee-") // bigEndian64(syncPeriod) -> serialized committee + // new log index filterMapsPrefix = "fm-" filterMapsRangeKey = []byte(filterMapsPrefix + "R") filterMapRowPrefix = []byte(filterMapsPrefix + "r") // filterMapRowPrefix + mapRowIndex (uint64 big endian) -> filter row filterMapLastBlockPrefix = []byte(filterMapsPrefix + "b") // filterMapLastBlockPrefix + mapIndex (uint32 big endian) -> block number (uint64 big endian) filterMapBlockLVPrefix = []byte(filterMapsPrefix + "p") // filterMapBlockLVPrefix + num (uint64 big endian) -> log value pointer (uint64 big endian) + // old log index + bloomBitsMetaPrefix = []byte("iB") + + // LES indexes + chtPrefix = []byte("chtRootV2-") // ChtPrefix + chtNum (uint64 big endian) -> trie root hash + chtTablePrefix = []byte("cht-") + chtIndexTablePrefix = []byte("chtIndexV2-") + bloomTriePrefix = []byte("bltRoot-") // BloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash + bloomTrieTablePrefix = []byte("blt-") + bloomTrieIndexPrefix = []byte("bltIndex-") + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) From 4c8c51f8ccf7bdf1fa953fd2b2098ae104fa46f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 24 Mar 2025 12:27:11 +0100 Subject: [PATCH 236/354] core/filtermaps: fix log indexer init conditions (#31455) This PR adds an extra condition to the log indexer initialization in order to avoid initializing with block 0 as target head. Previously this caused the indexer to initialize without a checkpoint. Later, when the real chain head was set, it indexed the entire history, then unindexed most of it if only the recent history was supposed to be indexed. Now the init only happens when there is an actual synced chain head and therefore the index is initialized at the most recent checkpoint and only the last year is indexed according to the default parameters. During checkpoint initialization the best available checkpoint is also checked against the history cutoff point and fails if the indexing would have to start from a block older than the cutoff. If initialization fails then the indexer reverts to unindexed mode instead of retrying because the the failure conditions cannot be expected to recover later. --- core/filtermaps/filtermaps.go | 29 +++++++++++++++++++++++++---- core/filtermaps/indexer.go | 15 ++++++++++----- core/filtermaps/matcher_backend.go | 8 ++++---- eth/backend.go | 7 ++++++- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index d74b11da0..db7ab0a42 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -53,7 +53,8 @@ type FilterMaps struct { // This is configured by the --history.logs.disable Geth flag. // We chose to implement disabling this way because it requires less special // case logic in eth/filters. - disabled bool + disabled bool + disabledCh chan struct{} // closed by indexer if disabled closeCh chan struct{} closeWg sync.WaitGroup @@ -196,6 +197,7 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f blockProcessingCh: make(chan bool, 1), history: config.History, disabled: config.Disabled, + disabledCh: make(chan struct{}), exportFileName: config.ExportFileName, Params: params, indexedRange: filterMapsRange{ @@ -206,6 +208,8 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f maps: common.NewRange(rs.MapsFirst, rs.MapsAfterLast-rs.MapsFirst), tailPartialEpoch: rs.TailPartialEpoch, }, + historyCutoff: historyCutoff, + finalBlock: finalBlock, matcherSyncCh: make(chan *FilterMapsMatcherBackend), matchers: make(map[*FilterMapsMatcherBackend]struct{}), filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), @@ -278,8 +282,13 @@ func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView { } // reset un-initializes the FilterMaps structure and removes all related data from -// the database. The function returns true if everything was successfully removed. -func (f *FilterMaps) reset() bool { +// the database. +// Note that in case of leveldb database the fallback implementation of DeleteRange +// might take a long time to finish and deleting the entire database may be +// interrupted by a shutdown. Deleting the filterMapsRange entry first does +// guarantee though that the next init() will not return successfully until the +// entire database has been cleaned. +func (f *FilterMaps) reset() { f.indexLock.Lock() f.indexedRange = filterMapsRange{} f.indexedView = nil @@ -292,11 +301,16 @@ func (f *FilterMaps) reset() bool { // deleting the range first ensures that resetDb will be called again at next // startup and any leftover data will be removed even if it cannot finish now. rawdb.DeleteFilterMapsRange(f.db) - return f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") + f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") } // init initializes an empty log index according to the current targetView. func (f *FilterMaps) init() error { + // ensure that there is no remaining data in the filter maps key range + if !f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") { + return errors.New("could not reset log index database") + } + f.indexLock.Lock() defer f.indexLock.Unlock() @@ -317,6 +331,13 @@ func (f *FilterMaps) init() error { bestIdx, bestLen = idx, max } } + var initBlockNumber uint64 + if bestLen > 0 { + initBlockNumber = checkpoints[bestIdx][bestLen-1].BlockNumber + } + if initBlockNumber < f.historyCutoff { + return errors.New("cannot start indexing before history cutoff point") + } batch := f.db.NewBatch() for epoch := range bestLen { cp := checkpoints[bestIdx][epoch] diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 69f42d8b6..026b3b4f3 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -36,20 +36,25 @@ func (f *FilterMaps) indexerLoop() { if f.disabled { f.reset() + close(f.disabledCh) return } log.Info("Started log indexer") for !f.stop { if !f.indexedRange.initialized { - if err := f.init(); err != nil { - log.Error("Error initializing log index", "error", err) - // unexpected error; there is not a lot we can do here, maybe it - // recovers, maybe not. Calling event processing here ensures - // that we can still properly shutdown in case of an infinite loop. + if f.targetView.headNumber == 0 { + // initialize when chain head is available f.processSingleEvent(true) continue } + if err := f.init(); err != nil { + log.Error("Error initializing log index; reverting to unindexed mode", "error", err) + f.reset() + f.disabled = true + close(f.disabledCh) + return + } } if !f.targetHeadIndexed() { if !f.tryIndexHead() { diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index f24e9706c..01bae7bb2 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -141,10 +141,6 @@ func (fm *FilterMapsMatcherBackend) synced() { // range that has not been changed and has been consistent with all states of the // chain since the previous SyncLogIndex or the creation of the matcher backend. func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange, error) { - if fm.f.disabled { - return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil - } - syncCh := make(chan SyncRange, 1) fm.f.matchersLock.Lock() fm.syncCh = syncCh @@ -154,12 +150,16 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange case fm.f.matcherSyncCh <- fm: case <-ctx.Done(): return SyncRange{}, ctx.Err() + case <-fm.f.disabledCh: + return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil } select { case vr := <-syncCh: return vr, nil case <-ctx.Done(): return SyncRange{}, ctx.Err() + case <-fm.f.disabledCh: + return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil } } diff --git a/eth/backend.go b/eth/backend.go index 424c85073..cf202f52e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -260,7 +260,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } fmConfig := filtermaps.Config{History: config.LogHistory, Disabled: config.LogNoHistory, ExportFileName: config.LogExportCheckpoints} chainView := eth.newChainView(eth.blockchain.CurrentBlock()) - eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, 0, 0, filtermaps.DefaultParams, fmConfig) + historyCutoff := eth.blockchain.HistoryPruningCutoff() + var finalBlock uint64 + if fb := eth.blockchain.CurrentFinalBlock(); fb != nil { + finalBlock = fb.Number.Uint64() + } + eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, historyCutoff, finalBlock, filtermaps.DefaultParams, fmConfig) eth.closeFilterMaps = make(chan chan struct{}) if config.BlobPool.Datadir != "" { From f77920174ca33315a6d1e6d080007ac162d0c466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 24 Mar 2025 12:27:40 +0100 Subject: [PATCH 237/354] beacon/params: new checkpoints (#31470) This PR updates beacon checkpoints. The checkpoints are now stored as embedded hex files, in the same format that https://github.com/ethereum/go-ethereum/pull/31469 uses. --- beacon/params/checkpoint_holesky.hex | 1 + beacon/params/checkpoint_mainnet.hex | 1 + beacon/params/checkpoint_sepolia.hex | 1 + beacon/params/networks.go | 17 ++++++++++++++--- 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 beacon/params/checkpoint_holesky.hex create mode 100644 beacon/params/checkpoint_mainnet.hex create mode 100644 beacon/params/checkpoint_sepolia.hex diff --git a/beacon/params/checkpoint_holesky.hex b/beacon/params/checkpoint_holesky.hex new file mode 100644 index 000000000..f1e27b48f --- /dev/null +++ b/beacon/params/checkpoint_holesky.hex @@ -0,0 +1 @@ +0xf5606a019f0f1006e9ec2070695045f4334450362a48da4c5965314510e0b4c3 \ No newline at end of file diff --git a/beacon/params/checkpoint_mainnet.hex b/beacon/params/checkpoint_mainnet.hex new file mode 100644 index 000000000..a11c3394b --- /dev/null +++ b/beacon/params/checkpoint_mainnet.hex @@ -0,0 +1 @@ +0x3c0cb4aa83beded1803d262664ba4392b1023f334d9cca02dc3a6925987ebe91 \ No newline at end of file diff --git a/beacon/params/checkpoint_sepolia.hex b/beacon/params/checkpoint_sepolia.hex new file mode 100644 index 000000000..e4f2f9673 --- /dev/null +++ b/beacon/params/checkpoint_sepolia.hex @@ -0,0 +1 @@ +0xa8d56457aa414523d93659aef1f7409bbfb72ad75e94d917c8c0b1baa38153ef \ No newline at end of file diff --git a/beacon/params/networks.go b/beacon/params/networks.go index c54798697..7e73a2c69 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -17,14 +17,25 @@ package params import ( + _ "embed" + "github.com/ethereum/go-ethereum/common" ) +//go:embed checkpoint_mainnet.hex +var checkpointMainnet string + +//go:embed checkpoint_sepolia.hex +var checkpointSepolia string + +//go:embed checkpoint_holesky.hex +var checkpointHolesky string + var ( MainnetLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"), GenesisTime: 1606824023, - Checkpoint: common.HexToHash("0x6509b691f4de4f7b083f2784938fd52f0e131675432b3fd85ea549af9aebd3d0"), + Checkpoint: common.HexToHash(checkpointMainnet), }). AddFork("GENESIS", 0, []byte{0, 0, 0, 0}). AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}). @@ -35,7 +46,7 @@ var ( SepoliaLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"), GenesisTime: 1655733600, - Checkpoint: common.HexToHash("0x456e85f5608afab3465a0580bff8572255f6d97af0c5f939e3f7536b5edb2d3f"), + Checkpoint: common.HexToHash(checkpointSepolia), }). AddFork("GENESIS", 0, []byte{144, 0, 0, 105}). AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}). @@ -47,7 +58,7 @@ var ( HoleskyLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"), GenesisTime: 1695902400, - Checkpoint: common.HexToHash("0x6456a1317f54d4b4f2cb5bc9d153b5af0988fe767ef0609f0236cf29030bcff7"), + Checkpoint: common.HexToHash(checkpointHolesky), }). AddFork("GENESIS", 0, []byte{1, 1, 112, 0}). AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}). From 13529110396d0db285be94f8d5e094069f8dae68 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 24 Mar 2025 22:19:14 +0800 Subject: [PATCH 238/354] tests: update test submodule (#31479) This commit upgrades the test submodule to latest version: Latest: https://github.com/ethereum/tests/commit/81862e4848585a438d64f911a19b3825f0f4cd95 Old: https://github.com/ethereum/tests/commit/faf33b471465d3c6cdc3d04fbd690895f78d33f2 --- tests/testdata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testdata b/tests/testdata index faf33b471..81862e484 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 +Subproject commit 81862e4848585a438d64f911a19b3825f0f4cd95 From 50b037b2fd997fd53d445924b656ac8d14e05d4c Mon Sep 17 00:00:00 2001 From: Rez Date: Tue, 25 Mar 2025 05:08:53 +1100 Subject: [PATCH 239/354] internal/ethapi: support for beacon root and withdrawals in simulate api (#31304) Adds block override fields for beacon block root and withdrawals to the eth_simulateV1. Addresses https://github.com/ethereum/go-ethereum/issues/31264 --- eth/gasestimator/gasestimator.go | 4 +- eth/tracers/api.go | 4 +- internal/ethapi/api.go | 4 +- internal/ethapi/api_test.go | 18 ++++++ internal/ethapi/override/override.go | 14 ++++- internal/ethapi/simulate.go | 83 ++++++++++++++++++++++++---- 6 files changed, 110 insertions(+), 17 deletions(-) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index a6c4718cf..fc8e3a2e4 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -223,7 +223,9 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio dirtyState = opts.State.Copy() ) if opts.BlockOverrides != nil { - opts.BlockOverrides.Apply(&evmContext) + if err := opts.BlockOverrides.Apply(&evmContext); err != nil { + return nil, err + } } // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). diff --git a/eth/tracers/api.go b/eth/tracers/api.go index fcd66e5c8..5b0eb2912 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -950,7 +950,9 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) // Apply the customization rules if required. if config != nil { - config.BlockOverrides.Apply(&vmctx) + if overrideErr := config.BlockOverrides.Apply(&vmctx); overrideErr != nil { + return nil, overrideErr + } rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time) precompiles = vm.ActivePrecompiledContracts(rules) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index eac4b8dd7..30012f80c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -736,7 +736,9 @@ func (context *ChainContext) Config() *params.ChainConfig { func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { - blockOverrides.Apply(&blockCtx) + if err := blockOverrides.Apply(&blockCtx); err != nil { + return nil, err + } } rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time) precompiles := vm.ActivePrecompiledContracts(rules) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 31a2e52b2..9fcb00bda 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1152,6 +1152,24 @@ func TestCall(t *testing.T) { }, want: "0x0000000000000000000000000000000000000000000000000000000000000000", }, + { + name: "unsupported block override beaconRoot", + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{}, + blockOverrides: override.BlockOverrides{ + BeaconRoot: &common.Hash{0, 1, 2}, + }, + expectErr: errors.New(`block override "beaconRoot" is not supported for this RPC method`), + }, + { + name: "unsupported block override withdrawals", + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{}, + blockOverrides: override.BlockOverrides{ + Withdrawals: &types.Withdrawals{}, + }, + expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`), + }, } for _, tc := range testSuite { result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) diff --git a/internal/ethapi/override/override.go b/internal/ethapi/override/override.go index f6a8a94ff..0bcf3c444 100644 --- a/internal/ethapi/override/override.go +++ b/internal/ethapi/override/override.go @@ -17,6 +17,7 @@ package override import ( + "errors" "fmt" "math/big" @@ -128,12 +129,20 @@ type BlockOverrides struct { PrevRandao *common.Hash BaseFeePerGas *hexutil.Big BlobBaseFee *hexutil.Big + BeaconRoot *common.Hash + Withdrawals *types.Withdrawals } // Apply overrides the given header fields into the given block context. -func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) { +func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) error { if o == nil { - return + return nil + } + if o.BeaconRoot != nil { + return errors.New(`block override "beaconRoot" is not supported for this RPC method`) + } + if o.Withdrawals != nil { + return errors.New(`block override "withdrawals" is not supported for this RPC method`) } if o.Number != nil { blockCtx.BlockNumber = o.Number.ToInt() @@ -159,6 +168,7 @@ func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) { if o.BlobBaseFee != nil { blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt() } + return nil } // MakeHeader returns a new header object with the overridden diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 097de8b0b..be8254dc5 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi/override" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/trie" ) const ( @@ -95,6 +94,51 @@ type simOpts struct { ReturnFullTransactions bool } +// simChainHeadReader implements ChainHeaderReader which is needed as input for FinalizeAndAssemble. +type simChainHeadReader struct { + context.Context + Backend +} + +func (m *simChainHeadReader) Config() *params.ChainConfig { + return m.Backend.ChainConfig() +} + +func (m *simChainHeadReader) CurrentHeader() *types.Header { + return m.Backend.CurrentHeader() +} + +func (m *simChainHeadReader) GetHeader(hash common.Hash, number uint64) *types.Header { + header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number)) + if err != nil || header == nil { + return nil + } + if header.Hash() != hash { + return nil + } + return header +} + +func (m *simChainHeadReader) GetHeaderByNumber(number uint64) *types.Header { + header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number)) + if err != nil { + return nil + } + return header +} + +func (m *simChainHeadReader) GetHeaderByHash(hash common.Hash) *types.Header { + header, err := m.Backend.HeaderByHash(m.Context, hash) + if err != nil { + return nil + } + return header +} + +func (m *simChainHeadReader) GetTd(hash common.Hash, number uint64) *big.Int { + return nil +} + // simulator is a stateful object that simulates a series of blocks. // it is not safe for concurrent use. type simulator struct { @@ -209,6 +253,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if sim.chainConfig.IsPrague(header.Number, header.Time) || sim.chainConfig.IsVerkle(header.Number, header.Time) { core.ProcessParentBlockHash(header.ParentHash, evm) } + if header.ParentBeaconRoot != nil { + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, evm) + } var allLogs []*types.Log for i, call := range block.Calls { if err := ctx.Err(); err != nil { @@ -258,6 +305,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, } callResults[i] = callRes } + header.GasUsed = gasUsed + if sim.chainConfig.IsCancun(header.Number, header.Time) { + header.BlobGasUsed = &blobGasUsed + } var requests [][]byte // Process EIP-7685 requests if sim.chainConfig.IsPrague(header.Number, header.Time) { @@ -271,20 +322,16 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, // EIP-7251 core.ProcessConsolidationQueue(&requests, evm) } - header.Root = sim.state.IntermediateRoot(true) - header.GasUsed = gasUsed - if sim.chainConfig.IsCancun(header.Number, header.Time) { - header.BlobGasUsed = &blobGasUsed - } - var withdrawals types.Withdrawals - if sim.chainConfig.IsShanghai(header.Number, header.Time) { - withdrawals = make([]*types.Withdrawal, 0) - } if requests != nil { reqHash := types.CalcRequestsHash(requests) header.RequestsHash = &reqHash } - b := types.NewBlock(header, &types.Body{Transactions: txes, Withdrawals: withdrawals}, receipts, trie.NewStackTrie(nil)) + blockBody := &types.Body{Transactions: txes, Withdrawals: *block.BlockOverrides.Withdrawals} + chainHeadReader := &simChainHeadReader{ctx, sim.b} + b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts) + if err != nil { + return nil, nil, err + } repairLogs(callResults, b.Hash()) return b, callResults, nil } @@ -346,6 +393,9 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { n := new(big.Int).Add(prevNumber, big.NewInt(1)) block.BlockOverrides.Number = (*hexutil.Big)(n) } + if block.BlockOverrides.Withdrawals == nil { + block.BlockOverrides.Withdrawals = &types.Withdrawals{} + } diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber) if diff.Cmp(common.Big0) <= 0 { return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)} @@ -360,7 +410,13 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) { for i := uint64(0); i < gap.Uint64(); i++ { n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1))) t := prevTimestamp + timestampIncrement - b := simBlock{BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}} + b := simBlock{ + BlockOverrides: &override.BlockOverrides{ + Number: (*hexutil.Big)(n), + Time: (*hexutil.Uint64)(&t), + Withdrawals: &types.Withdrawals{}, + }, + } prevTimestamp = t res = append(res, b) } @@ -405,6 +461,9 @@ func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) { var parentBeaconRoot *common.Hash if sim.chainConfig.IsCancun(overrides.Number.ToInt(), (uint64)(*overrides.Time)) { parentBeaconRoot = &common.Hash{} + if overrides.BeaconRoot != nil { + parentBeaconRoot = overrides.BeaconRoot + } } header = overrides.MakeHeader(&types.Header{ UncleHash: types.EmptyUncleHash, From a78dc73f26ef9d2b518ca027f2217085b2f1eab2 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 25 Mar 2025 18:16:26 +0800 Subject: [PATCH 240/354] core/txpool: reject stale transaction for local tracking (#31473) Fixes https://github.com/ethereum/go-ethereum/issues/31451 --- core/txpool/locals/tx_tracker_test.go | 179 ++++++++++++++++++++++++++ core/txpool/txpool.go | 54 +++++++- 2 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 core/txpool/locals/tx_tracker_test.go diff --git a/core/txpool/locals/tx_tracker_test.go b/core/txpool/locals/tx_tracker_test.go new file mode 100644 index 000000000..ae700bc94 --- /dev/null +++ b/core/txpool/locals/tx_tracker_test.go @@ -0,0 +1,179 @@ +// Copyright 2025 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 . + +package locals + +import ( + "errors" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" +) + +var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + gspec = &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{ + address: {Balance: funds}, + }, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer = types.LatestSigner(gspec.Config) +) + +type testEnv struct { + chain *core.BlockChain + pool *txpool.TxPool + tracker *TxTracker + genDb ethdb.Database +} + +func newTestEnv(t *testing.T, n int, gasTip uint64, journal string) *testEnv { + genDb, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), n, func(i int, gen *core.BlockGen) { + tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.BaseFee(), nil), signer, key) + if err != nil { + panic(err) + } + gen.AddTx(tx) + }) + + db := rawdb.NewMemoryDatabase() + chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + + legacyPool := legacypool.New(legacypool.DefaultConfig, chain) + pool, err := txpool.New(gasTip, chain, []txpool.SubPool{legacyPool}) + if err != nil { + t.Fatalf("Failed to create tx pool: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("Failed to process block %d: %v", n, err) + } + if err := pool.Sync(); err != nil { + t.Fatalf("Failed to sync the txpool, %v", err) + } + return &testEnv{ + chain: chain, + pool: pool, + tracker: New(journal, time.Minute, gspec.Config, pool), + genDb: genDb, + } +} + +func (env *testEnv) close() { + env.chain.Stop() +} + +func (env *testEnv) setGasTip(gasTip uint64) { + env.pool.SetGasTip(new(big.Int).SetUint64(gasTip)) +} + +func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction { + if nonce == 0 { + head := env.chain.CurrentHeader() + state, _ := env.chain.StateAt(head.Root) + nonce = state.GetNonce(address) + } + if gasPrice == nil { + gasPrice = big.NewInt(params.GWei) + } + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{0x00}, big.NewInt(1000), params.TxGas, gasPrice, nil), signer, key) + return tx +} + +func (env *testEnv) commit() { + head := env.chain.CurrentBlock() + block := env.chain.GetBlock(head.Hash(), head.Number.Uint64()) + blocks, _ := core.GenerateChain(env.chain.Config(), block, ethash.NewFaker(), env.genDb, 1, func(i int, gen *core.BlockGen) { + tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.BaseFee(), nil), signer, key) + if err != nil { + panic(err) + } + gen.AddTx(tx) + }) + env.chain.InsertChain(blocks) + if err := env.pool.Sync(); err != nil { + panic(err) + } +} + +func TestRejectInvalids(t *testing.T) { + env := newTestEnv(t, 10, 0, "") + defer env.close() + + var cases = []struct { + gasTip uint64 + tx *types.Transaction + expErr error + commit bool + }{ + { + tx: env.makeTx(5, nil), // stale + expErr: core.ErrNonceTooLow, + }, + { + tx: env.makeTx(11, nil), // future transaction + expErr: nil, + }, + { + gasTip: params.GWei, + tx: env.makeTx(0, new(big.Int).SetUint64(params.GWei/2)), // low price + expErr: txpool.ErrUnderpriced, + }, + { + tx: types.NewTransaction(10, common.Address{0x00}, big.NewInt(1000), params.TxGas, big.NewInt(params.GWei), nil), // invalid signature + expErr: types.ErrInvalidSig, + }, + { + commit: true, + tx: env.makeTx(10, nil), // stale + expErr: core.ErrNonceTooLow, + }, + { + tx: env.makeTx(11, nil), + expErr: nil, + }, + } + for i, c := range cases { + if c.gasTip != 0 { + env.setGasTip(c.gasTip) + } + if c.commit { + env.commit() + } + gotErr := env.tracker.Track(c.tx) + if c.expErr == nil && gotErr != nil { + t.Fatalf("%d, unexpected error: %v", i, gotErr) + } + if c.expErr != nil && !errors.Is(gotErr, c.expErr) { + t.Fatalf("%d, unexpected error, want: %v, got: %v", i, c.expErr, gotErr) + } + } +} diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index cfe46ef3f..b8e88429b 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -24,11 +24,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" ) // TxStatus is the current status of a transaction as seen by the pool. @@ -56,11 +58,17 @@ var ( // BlockChain defines the minimal set of methods needed to back a tx pool with // a chain. Exists to allow mocking the live chain out of tests. type BlockChain interface { + // Config retrieves the chain's fork configuration. + Config() *params.ChainConfig + // CurrentBlock returns the current head of the chain. CurrentBlock() *types.Header // SubscribeChainHeadEvent subscribes to new blocks being added to the chain. SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription + + // StateAt returns a state database for a given root hash (generally the head). + StateAt(root common.Hash) (*state.StateDB, error) } // TxPool is an aggregator for various transaction specific pools, collectively @@ -70,6 +78,11 @@ type BlockChain interface { // resource constraints. type TxPool struct { subpools []SubPool // List of subpools for specialized transaction handling + chain BlockChain + signer types.Signer + + stateLock sync.RWMutex // The lock for protecting state instance + state *state.StateDB // Current state at the blockchain head reservations map[common.Address]SubPool // Map with the account to pool reservations reserveLock sync.Mutex // Lock protecting the account reservations @@ -89,8 +102,21 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { // during initialization. head := chain.CurrentBlock() + // Initialize the state with head block, or fallback to empty one in + // case the head state is not available (might occur when node is not + // fully synced). + statedb, err := chain.StateAt(head.Root) + if err != nil { + statedb, err = chain.StateAt(types.EmptyRootHash) + } + if err != nil { + return nil, err + } pool := &TxPool{ subpools: subpools, + chain: chain, + signer: types.LatestSigner(chain.Config()), + state: statedb, reservations: make(map[common.Address]SubPool), quit: make(chan chan error), term: make(chan struct{}), @@ -104,7 +130,7 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { return nil, err } } - go pool.loop(head, chain) + go pool.loop(head) return pool, nil } @@ -182,14 +208,14 @@ func (p *TxPool) Close() error { // loop is the transaction pool's main event loop, waiting for and reacting to // outside blockchain events as well as for various reporting and transaction // eviction events. -func (p *TxPool) loop(head *types.Header, chain BlockChain) { +func (p *TxPool) loop(head *types.Header) { // Close the termination marker when the pool stops defer close(p.term) // Subscribe to chain head events to trigger subpool resets var ( newHeadCh = make(chan core.ChainHeadEvent) - newHeadSub = chain.SubscribeChainHeadEvent(newHeadCh) + newHeadSub = p.chain.SubscribeChainHeadEvent(newHeadCh) ) defer newHeadSub.Unsubscribe() @@ -222,6 +248,14 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) { // Try to inject a busy marker and start a reset if successful select { case resetBusy <- struct{}{}: + statedb, err := p.chain.StateAt(newHead.Root) + if err != nil { + log.Crit("Failed to reset txpool state", "err", err) + } + p.stateLock.Lock() + p.state = statedb + p.stateLock.Unlock() + // Busy marker injected, start a new subpool reset go func(oldHead, newHead *types.Header) { for _, subpool := range p.subpools { @@ -342,6 +376,20 @@ func (p *TxPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Pr // ValidateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error { + addr, err := types.Sender(p.signer, tx) + if err != nil { + return err + } + // Reject transactions with stale nonce. Gapped-nonce future transactions + // are considered valid and will be handled by the subpool according to its + // internal policy. + p.stateLock.RLock() + nonce := p.state.GetNonce(addr) + p.stateLock.RUnlock() + + if nonce > tx.Nonce() { + return core.ErrNonceTooLow + } for _, subpool := range p.subpools { if subpool.Filter(tx) { return subpool.ValidateTxBasics(tx) From 3129016192637559d40477627aabb864feab9b2f Mon Sep 17 00:00:00 2001 From: Pierre Rousset Date: Fri, 21 Feb 2025 11:28:11 +0900 Subject: [PATCH 241/354] Fix flakey behavior in simulated backend Rollback --- core/txpool/txpool.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index b8e88429b..2afe80a16 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -583,6 +583,7 @@ func (p *TxPool) Sync() error { // Clear removes all tracked txs from the subpools. func (p *TxPool) Clear() { + p.Sync() for _, subpool := range p.subpools { subpool.Clear() } From cad4df81cbb5e9dd7540033c3cd47cda8648880c Mon Sep 17 00:00:00 2001 From: Pierre R Date: Tue, 11 Mar 2025 18:26:16 +0900 Subject: [PATCH 242/354] Update core/txpool/txpool.go Co-authored-by: jwasinger --- core/txpool/txpool.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 2afe80a16..cc344066b 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -583,6 +583,8 @@ func (p *TxPool) Sync() error { // Clear removes all tracked txs from the subpools. func (p *TxPool) Clear() { + // Invoke Sync to ensure that txs pending addition don't get added to the pool after + // the subpools are subsequently cleared p.Sync() for _, subpool := range p.subpools { subpool.Clear() From 2139dbf340d308fb3d059685ef99f9968277809f Mon Sep 17 00:00:00 2001 From: nethoxa <135072738+nethoxa@users.noreply.github.com> Date: Tue, 25 Mar 2025 14:13:05 +0100 Subject: [PATCH 243/354] core: process EL requests in GenerateVerkleChain (#31175) --- core/chain_makers.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/chain_makers.go b/core/chain_makers.go index e343e9529..28b08f03c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -504,6 +504,13 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine if gen != nil { gen(i, b) } + + requests := b.collectRequests(false) + if requests != nil { + reqHash := types.CalcRequestsHash(requests) + b.header.RequestsHash = &reqHash + } + body := &types.Body{ Transactions: b.txs, Uncles: b.uncles, From 8b57eff16a6e595b8bd1fa83f7ff9cbc8ee7e674 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 25 Mar 2025 21:53:02 +0800 Subject: [PATCH 244/354] all: use fmt.Appendf instead of fmt.Sprintf where possible (#31301) --- cmd/utils/export_test.go | 14 ++++---- common/math/big.go | 2 +- common/math/integer.go | 2 +- core/state/snapshot/generate_test.go | 2 +- core/state/snapshot/iterator_test.go | 32 +++++++++---------- internal/ethapi/api.go | 2 +- p2p/nat/nat.go | 2 +- p2p/nat/natpmp.go | 2 +- .../apitypes/signed_data_internal_test.go | 2 +- signer/core/signed_data_test.go | 2 +- triedb/pathdb/iterator_test.go | 32 +++++++++---------- 11 files changed, 47 insertions(+), 47 deletions(-) diff --git a/cmd/utils/export_test.go b/cmd/utils/export_test.go index b70d2451c..d1a004d9b 100644 --- a/cmd/utils/export_test.go +++ b/cmd/utils/export_test.go @@ -54,8 +54,8 @@ func (iter *testIterator) Next() (byte, []byte, []byte, bool) { if iter.index == 42 { iter.index += 1 } - return OpBatchAdd, []byte(fmt.Sprintf("key-%04d", iter.index)), - []byte(fmt.Sprintf("value %d", iter.index)), true + return OpBatchAdd, fmt.Appendf(nil, "key-%04d", iter.index), + fmt.Appendf(nil, "value %d", iter.index), true } func (iter *testIterator) Release() {} @@ -72,7 +72,7 @@ func testExport(t *testing.T, f string) { } // verify for i := 0; i < 1000; i++ { - v, err := db.Get([]byte(fmt.Sprintf("key-%04d", i))) + v, err := db.Get(fmt.Appendf(nil, "key-%04d", i)) if (i < 5 || i == 42) && err == nil { t.Fatalf("expected no element at idx %d, got '%v'", i, string(v)) } @@ -85,7 +85,7 @@ func testExport(t *testing.T, f string) { } } } - v, err := db.Get([]byte(fmt.Sprintf("key-%04d", 1000))) + v, err := db.Get(fmt.Appendf(nil, "key-%04d", 1000)) if err == nil { t.Fatalf("expected no element at idx %d, got '%v'", 1000, string(v)) } @@ -120,7 +120,7 @@ func (iter *deletionIterator) Next() (byte, []byte, []byte, bool) { if iter.index == 42 { iter.index += 1 } - return OpBatchDel, []byte(fmt.Sprintf("key-%04d", iter.index)), nil, true + return OpBatchDel, fmt.Appendf(nil, "key-%04d", iter.index), nil, true } func (iter *deletionIterator) Release() {} @@ -132,14 +132,14 @@ func testDeletion(t *testing.T, f string) { } db := rawdb.NewMemoryDatabase() for i := 0; i < 1000; i++ { - db.Put([]byte(fmt.Sprintf("key-%04d", i)), []byte(fmt.Sprintf("value %d", i))) + db.Put(fmt.Appendf(nil, "key-%04d", i), fmt.Appendf(nil, "value %d", i)) } err = ImportLDBData(db, f, 5, make(chan struct{})) if err != nil { t.Fatal(err) } for i := 0; i < 1000; i++ { - v, err := db.Get([]byte(fmt.Sprintf("key-%04d", i))) + v, err := db.Get(fmt.Appendf(nil, "key-%04d", i)) if i < 5 || i == 42 { if err != nil { t.Fatalf("expected element at idx %d, got '%v'", i, err) diff --git a/common/math/big.go b/common/math/big.go index 825f4baec..493c2b786 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -72,7 +72,7 @@ func (i *HexOrDecimal256) MarshalText() ([]byte, error) { if i == nil { return []byte("0x0"), nil } - return []byte(fmt.Sprintf("%#x", (*big.Int)(i))), nil + return fmt.Appendf(nil, "%#x", (*big.Int)(i)), nil } // Decimal256 unmarshals big.Int as a decimal string. When unmarshalling, diff --git a/common/math/integer.go b/common/math/integer.go index 25ced8705..dfcb0aecc 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -48,7 +48,7 @@ func (i *HexOrDecimal64) UnmarshalText(input []byte) error { // MarshalText implements encoding.TextMarshaler. func (i HexOrDecimal64) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("%#x", uint64(i))), nil + return fmt.Appendf(nil, "%#x", uint64(i)), nil } // ParseUint64 parses s as an integer in decimal or hexadecimal syntax. diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 661610840..3de7735ef 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -655,7 +655,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) { for i := 0; i < 1000; i++ { acc := &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - key := hashData([]byte(fmt.Sprintf("acc-%d", i))) + key := hashData(fmt.Appendf(nil, "acc-%d", i)) rawdb.WriteAccountSnapshot(helper.diskdb, key, val) } } diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index b9fe370b8..2e882f484 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -329,27 +329,27 @@ func TestAccountIteratorTraversalValues(t *testing.T) { h = make(map[common.Hash][]byte) ) for i := byte(2); i < 0xff; i++ { - a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + a[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 0, i) if i > 20 && i%2 == 0 { - b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + b[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 1, i) } if i%4 == 0 { - c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + c[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 2, i) } if i%7 == 0 { - d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + d[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 3, i) } if i%8 == 0 { - e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + e[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 4, i) } if i > 50 || i < 85 { - f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + f[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 5, i) } if i%64 == 0 { - g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + g[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 6, i) } if i%128 == 0 { - h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + h[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 7, i) } } // Assemble a stack of snapshots from the account layers @@ -428,27 +428,27 @@ func TestStorageIteratorTraversalValues(t *testing.T) { h = make(map[common.Hash][]byte) ) for i := byte(2); i < 0xff; i++ { - a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + a[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 0, i) if i > 20 && i%2 == 0 { - b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + b[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 1, i) } if i%4 == 0 { - c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + c[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 2, i) } if i%7 == 0 { - d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + d[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 3, i) } if i%8 == 0 { - e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + e[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 4, i) } if i > 50 || i < 85 { - f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + f[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 5, i) } if i%64 == 0 { - g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + g[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 6, i) } if i%128 == 0 { - h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + h[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 7, i) } } // Assemble a stack of snapshots from the account layers diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 30012f80c..4eea2b3ad 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1454,7 +1454,7 @@ func recoverSignerAddress(nonce hexutil.Uint64, signature hexutil.Bytes) (*commo v += 27 // Adjust V to match Ethereum's EIP-155 signature convention } signature = append(r, append(s, v-27)...) - recoveredPubkey, err := crypto.SigToPub(accounts.TextHash([]byte(fmt.Sprintf("%d", nonce))), signature) + recoveredPubkey, err := crypto.SigToPub(accounts.TextHash(fmt.Appendf(nil, "%d", nonce)), signature) if err != nil || recoveredPubkey == nil { return nil, fmt.Errorf("signature verification failed: %v", err) } diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 5f7af7424..a0ddb3b29 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -140,7 +140,7 @@ type ExtIP net.IP func (n ExtIP) ExternalIP() (net.IP, error) { return net.IP(n), nil } func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) } -func (n ExtIP) MarshalText() ([]byte, error) { return []byte(fmt.Sprintf("extip:%v", net.IP(n))), nil } +func (n ExtIP) MarshalText() ([]byte, error) { return fmt.Appendf(nil, "extip:%v", net.IP(n)), nil } // These do nothing. diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index b8f59ee89..4a9644ac1 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -71,7 +71,7 @@ func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) { } func (n *pmp) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("natpmp:%v", n.gw)), nil + return fmt.Appendf(nil, "natpmp:%v", n.gw), nil } func discoverPMP() Interface { diff --git a/signer/core/apitypes/signed_data_internal_test.go b/signer/core/apitypes/signed_data_internal_test.go index 1a14b35ef..bee9f1c35 100644 --- a/signer/core/apitypes/signed_data_internal_test.go +++ b/signer/core/apitypes/signed_data_internal_test.go @@ -282,7 +282,7 @@ func TestTypedDataArrayValidate(t *testing.T) { messageHash, tErr := td.HashStruct(td.PrimaryType, td.Message) assert.NoError(t, tErr, "failed to hash message: %v", tErr) - digest := crypto.Keccak256Hash([]byte(fmt.Sprintf("%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash)))) + digest := crypto.Keccak256Hash(fmt.Appendf(nil, "%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash))) assert.Equal(t, tc.Digest, digest.String(), "digest doesn't not match") assert.NoError(t, td.validate(), "validation failed", tErr) diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index b6c080736..001f6b683 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -369,7 +369,7 @@ func sign(typedData apitypes.TypedData) ([]byte, []byte, error) { if err != nil { return nil, nil, err } - rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) + rawData := fmt.Appendf(nil, "\x19\x01%s%s", string(domainSeparator), string(typedDataHash)) sighash := crypto.Keccak256(rawData) return typedDataHash, sighash, nil } diff --git a/triedb/pathdb/iterator_test.go b/triedb/pathdb/iterator_test.go index 05a166d1b..389411803 100644 --- a/triedb/pathdb/iterator_test.go +++ b/triedb/pathdb/iterator_test.go @@ -371,27 +371,27 @@ func TestAccountIteratorTraversalValues(t *testing.T) { h = make(map[common.Hash][]byte) ) for i := byte(2); i < 0xff; i++ { - a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + a[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 0, i) if i > 20 && i%2 == 0 { - b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + b[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 1, i) } if i%4 == 0 { - c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + c[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 2, i) } if i%7 == 0 { - d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + d[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 3, i) } if i%8 == 0 { - e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + e[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 4, i) } if i > 50 || i < 85 { - f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + f[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 5, i) } if i%64 == 0 { - g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + g[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 6, i) } if i%128 == 0 { - h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + h[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 7, i) } } // Assemble a stack of snapshots from the account layers @@ -480,27 +480,27 @@ func TestStorageIteratorTraversalValues(t *testing.T) { h = make(map[common.Hash][]byte) ) for i := byte(2); i < 0xff; i++ { - a[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 0, i)) + a[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 0, i) if i > 20 && i%2 == 0 { - b[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 1, i)) + b[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 1, i) } if i%4 == 0 { - c[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 2, i)) + c[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 2, i) } if i%7 == 0 { - d[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 3, i)) + d[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 3, i) } if i%8 == 0 { - e[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 4, i)) + e[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 4, i) } if i > 50 || i < 85 { - f[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 5, i)) + f[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 5, i) } if i%64 == 0 { - g[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 6, i)) + g[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 6, i) } if i%128 == 0 { - h[common.Hash{i}] = []byte(fmt.Sprintf("layer-%d, key %d", 7, i)) + h[common.Hash{i}] = fmt.Appendf(nil, "layer-%d, key %d", 7, i) } } // Assemble a stack of snapshots from the account layers From ae7e7746dbcc722f36de81fe2e1f9ffa4ebcbd1c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 25 Mar 2025 21:59:44 +0800 Subject: [PATCH 245/354] trie: optimize memory allocation (#30932) This pull request removes the node copy operation to reduce memory allocation. Key Changes as below: **(a) Use `decodeNodeUnsafe` for decoding nodes retrieved from the trie node reader** In the current implementation of the MPT, once a trie node blob is retrieved, it is passed to `decodeNode` for decoding. However, `decodeNode` assumes the supplied byte slice might be mutated later, so it performs a deep copy internally before parsing the node. Given that the node reader is implemented by the path database and the hash database, both of which guarantee the immutability of the returned byte slice. By restricting the node reader interface to explicitly guarantee that the returned byte slice will not be modified, we can safely replace `decodeNode` with `decodeNodeUnsafe`. This eliminates the need for a redundant byte copy during each node resolution. **(b) Modify the trie in place** In the current implementation of the MPT, a copy of a trie node is created before any modifications are made. These modifications include: - Node resolution: Converting the value from a hash to the actual node. - Node hashing: Tagging the hash into its cache. - Node commit: Replacing the children with its hash. - Structural changes: For example, adding a new child to a fullNode or replacing a child of a shortNode. This mechanism ensures that modifications only affect the live tree, leaving all previously created copies unaffected. Unfortunately, this property leads to a huge memory allocation requirement. For example, if we want to modify the fullNode for n times, the node will be copied for n times. In this pull request, all the trie modifications are made in place. In order to make sure all previously created copies are unaffected, the `Copy` function now will deep-copy all the live nodes rather than the root node itself. With this change, while the `Copy` function becomes more expensive, it's totally acceptable as it's not a frequently used one. For the normal trie operations (Get, GetNode, Hash, Commit, Insert, Delete), the node copy is not required anymore. --- trie/committer.go | 39 +++------ trie/hasher.go | 84 +++++++++--------- trie/node.go | 14 ++- trie/trie.go | 68 ++++++++++----- trie/trie_test.go | 168 ++++++++++++++++++++++++++++++++++++ triedb/database/database.go | 2 + 6 files changed, 279 insertions(+), 96 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 6c4374ccf..0939a07ab 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -57,32 +57,26 @@ func (c *committer) commit(path []byte, n node, parallel bool) node { // Commit children, then parent, and remove the dirty flag. switch cn := n.(type) { case *shortNode: - // Commit child - collapsed := cn.copy() - // If the child is fullNode, recursively commit, // otherwise it can only be hashNode or valueNode. if _, ok := cn.Val.(*fullNode); ok { - collapsed.Val = c.commit(append(path, cn.Key...), cn.Val, false) + cn.Val = c.commit(append(path, cn.Key...), cn.Val, false) } // The key needs to be copied, since we're adding it to the // modified nodeset. - collapsed.Key = hexToCompact(cn.Key) - hashedNode := c.store(path, collapsed) + cn.Key = hexToCompact(cn.Key) + hashedNode := c.store(path, cn) if hn, ok := hashedNode.(hashNode); ok { return hn } - return collapsed + return cn case *fullNode: - hashedKids := c.commitChildren(path, cn, parallel) - collapsed := cn.copy() - collapsed.Children = hashedKids - - hashedNode := c.store(path, collapsed) + c.commitChildren(path, cn, parallel) + hashedNode := c.store(path, cn) if hn, ok := hashedNode.(hashNode); ok { return hn } - return collapsed + return cn case hashNode: return cn default: @@ -92,11 +86,10 @@ func (c *committer) commit(path []byte, n node, parallel bool) node { } // commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) [17]node { +func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) { var ( - wg sync.WaitGroup - nodesMu sync.Mutex - children [17]node + wg sync.WaitGroup + nodesMu sync.Mutex ) for i := 0; i < 16; i++ { child := n.Children[i] @@ -106,22 +99,21 @@ func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) [17] // If it's the hashed child, save the hash value directly. // Note: it's impossible that the child in range [0, 15] // is a valueNode. - if hn, ok := child.(hashNode); ok { - children[i] = hn + if _, ok := child.(hashNode); ok { continue } // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. if !parallel { - children[i] = c.commit(append(path, byte(i)), child, false) + n.Children[i] = c.commit(append(path, byte(i)), child, false) } else { wg.Add(1) go func(index int) { p := append(path, byte(index)) childSet := trienode.NewNodeSet(c.nodes.Owner) childCommitter := newCommitter(childSet, c.tracer, c.collectLeaf) - children[index] = childCommitter.commit(p, child, false) + n.Children[index] = childCommitter.commit(p, child, false) nodesMu.Lock() c.nodes.MergeSet(childSet) nodesMu.Unlock() @@ -132,11 +124,6 @@ func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) [17] if parallel { wg.Wait() } - // For the 17th child, it's possible the type is valuenode. - if n.Children[16] != nil { - children[16] = n.Children[16] - } - return children } // store hashes the node n and adds it to the modified nodeset. If leaf collection diff --git a/trie/hasher.go b/trie/hasher.go index 28f7f3d0c..614640ae3 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -53,62 +53,56 @@ func returnHasherToPool(h *hasher) { hasherPool.Put(h) } -// hash collapses a node down into a hash node, also returning a copy of the -// original node initialized with the computed hash to replace the original one. -func (h *hasher) hash(n node, force bool) (hashed node, cached node) { +// hash collapses a node down into a hash node. +func (h *hasher) hash(n node, force bool) node { // Return the cached hash if it's available if hash, _ := n.cache(); hash != nil { - return hash, n + return hash } // Trie not processed yet, walk the children switch n := n.(type) { case *shortNode: - collapsed, cached := h.hashShortNodeChildren(n) + collapsed := h.hashShortNodeChildren(n) hashed := h.shortnodeToHash(collapsed, force) - // We need to retain the possibly _not_ hashed node, in case it was too - // small to be hashed if hn, ok := hashed.(hashNode); ok { - cached.flags.hash = hn + n.flags.hash = hn } else { - cached.flags.hash = nil + n.flags.hash = nil } - return hashed, cached + return hashed case *fullNode: - collapsed, cached := h.hashFullNodeChildren(n) - hashed = h.fullnodeToHash(collapsed, force) + collapsed := h.hashFullNodeChildren(n) + hashed := h.fullnodeToHash(collapsed, force) if hn, ok := hashed.(hashNode); ok { - cached.flags.hash = hn + n.flags.hash = hn } else { - cached.flags.hash = nil + n.flags.hash = nil } - return hashed, cached + return hashed default: // Value and hash nodes don't have children, so they're left as were - return n, n + return n } } -// hashShortNodeChildren collapses the short node. The returned collapsed node -// holds a live reference to the Key, and must not be modified. -func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { - // Hash the short node's child, caching the newly hashed subtree - collapsed, cached = n.copy(), n.copy() - // Previously, we did copy this one. We don't seem to need to actually - // do that, since we don't overwrite/reuse keys - // cached.Key = common.CopyBytes(n.Key) +// hashShortNodeChildren returns a copy of the supplied shortNode, with its child +// being replaced by either the hash or an embedded node if the child is small. +func (h *hasher) hashShortNodeChildren(n *shortNode) *shortNode { + var collapsed shortNode collapsed.Key = hexToCompact(n.Key) - // Unless the child is a valuenode or hashnode, hash it switch n.Val.(type) { case *fullNode, *shortNode: - collapsed.Val, cached.Val = h.hash(n.Val, false) + collapsed.Val = h.hash(n.Val, false) + default: + collapsed.Val = n.Val } - return collapsed, cached + return &collapsed } -func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { - // Hash the full node's children, caching the newly hashed subtrees - cached = n.copy() - collapsed = n.copy() +// hashFullNodeChildren returns a copy of the supplied fullNode, with its child +// being replaced by either the hash or an embedded node if the child is small. +func (h *hasher) hashFullNodeChildren(n *fullNode) *fullNode { + var children [17]node if h.parallel { var wg sync.WaitGroup wg.Add(16) @@ -116,9 +110,9 @@ func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached go func(i int) { hasher := newHasher(false) if child := n.Children[i]; child != nil { - collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) + children[i] = hasher.hash(child, false) } else { - collapsed.Children[i] = nilValueNode + children[i] = nilValueNode } returnHasherToPool(hasher) wg.Done() @@ -128,19 +122,21 @@ func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached } else { for i := 0; i < 16; i++ { if child := n.Children[i]; child != nil { - collapsed.Children[i], cached.Children[i] = h.hash(child, false) + children[i] = h.hash(child, false) } else { - collapsed.Children[i] = nilValueNode + children[i] = nilValueNode } } } - return collapsed, cached + if n.Children[16] != nil { + children[16] = n.Children[16] + } + return &fullNode{flags: nodeFlag{}, Children: children} } -// shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode -// should have hex-type Key, which will be converted (without modification) -// into compact form for RLP encoding. -// If the rlp data is smaller than 32 bytes, `nil` is returned. +// shortNodeToHash computes the hash of the given shortNode. The shortNode must +// first be collapsed, with its key converted to compact form. If the RLP-encoded +// node data is smaller than 32 bytes, the node itself is returned. func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { n.encode(h.encbuf) enc := h.encodedBytes() @@ -151,8 +147,8 @@ func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { return h.hashData(enc) } -// fullnodeToHash is used to create a hashNode from a fullNode, (which -// may contain nil values) +// fullnodeToHash computes the hash of the given fullNode. If the RLP-encoded +// node data is smaller than 32 bytes, the node itself is returned. func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { n.encode(h.encbuf) enc := h.encodedBytes() @@ -203,10 +199,10 @@ func (h *hasher) hashDataTo(dst, data []byte) { func (h *hasher) proofHash(original node) (collapsed, hashed node) { switch n := original.(type) { case *shortNode: - sn, _ := h.hashShortNodeChildren(n) + sn := h.hashShortNodeChildren(n) return sn, h.shortnodeToHash(sn, false) case *fullNode: - fn, _ := h.hashFullNodeChildren(n) + fn := h.hashFullNodeChildren(n) return fn, h.fullnodeToHash(fn, false) default: // Value and hash nodes don't have children, so they're left as were diff --git a/trie/node.go b/trie/node.go index ecc2de192..96f077ebb 100644 --- a/trie/node.go +++ b/trie/node.go @@ -79,15 +79,19 @@ func (n *fullNode) EncodeRLP(w io.Writer) error { return eb.Flush() } -func (n *fullNode) copy() *fullNode { copy := *n; return © } -func (n *shortNode) copy() *shortNode { copy := *n; return © } - // nodeFlag contains caching-related metadata about a node. type nodeFlag struct { hash hashNode // cached hash of the node (may be nil) dirty bool // whether the node has changes that must be written to the database } +func (n nodeFlag) copy() nodeFlag { + return nodeFlag{ + hash: common.CopyBytes(n.hash), + dirty: n.dirty, + } +} + func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n hashNode) cache() (hashNode, bool) { return nil, true } @@ -228,7 +232,9 @@ func decodeRef(buf []byte) (node, []byte, error) { err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen) return nil, buf, err } - n, err := decodeNode(nil, buf) + // The buffer content has already been copied or is safe to use; + // no additional copy is required. + n, err := decodeNodeUnsafe(nil, buf) return n, rest, err case kind == rlp.String && len(val) == 0: // empty node diff --git a/trie/trie.go b/trie/trie.go index ae2a7b21a..fdb4da9be 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -29,11 +29,11 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) -// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on -// top of a database. Whenever trie performs a commit operation, the generated -// nodes will be gathered and returned in a set. Once the trie is committed, -// it's not usable anymore. Callers have to re-create the trie with new root -// based on the updated trie database. +// Trie represents a Merkle Patricia Trie. Use New to create a trie that operates +// on top of a node database. During a commit operation, the trie collects all +// modified nodes into a set for return. After committing, the trie becomes +// unusable, and callers must recreate it with the new root based on the updated +// trie database. // // Trie is not safe for concurrent use. type Trie struct { @@ -67,13 +67,13 @@ func (t *Trie) newFlag() nodeFlag { // Copy returns a copy of Trie. func (t *Trie) Copy() *Trie { return &Trie{ - root: t.root, + root: copyNode(t.root), owner: t.owner, committed: t.committed, + unhashed: t.unhashed, + uncommitted: t.uncommitted, reader: t.reader, tracer: t.tracer.copy(), - uncommitted: t.uncommitted, - unhashed: t.unhashed, } } @@ -169,14 +169,12 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no } value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key)) if err == nil && didResolve { - n = n.copy() n.Val = newnode } return value, n, didResolve, err case *fullNode: value, newnode, didResolve, err = t.get(n.Children[key[pos]], key, pos+1) if err == nil && didResolve { - n = n.copy() n.Children[key[pos]] = newnode } return value, n, didResolve, err @@ -257,7 +255,6 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod } item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key)) if err == nil && resolved > 0 { - n = n.copy() n.Val = newnode } return item, n, resolved, err @@ -265,7 +262,6 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod case *fullNode: item, newnode, resolved, err = t.getNode(n.Children[path[pos]], path, pos+1) if err == nil && resolved > 0 { - n = n.copy() n.Children[path[pos]] = newnode } return item, n, resolved, err @@ -375,7 +371,6 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error if !dirty || err != nil { return false, n, err } - n = n.copy() n.flags = t.newFlag() n.Children[key[0]] = nn return true, n, nil @@ -483,7 +478,6 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { if !dirty || err != nil { return false, n, err } - n = n.copy() n.flags = t.newFlag() n.Children[key[0]] = nn @@ -576,6 +570,36 @@ func concat(s1 []byte, s2 ...byte) []byte { return r } +// copyNode deep-copies the supplied node along with its children recursively. +func copyNode(n node) node { + switch n := (n).(type) { + case nil: + return nil + case valueNode: + return valueNode(common.CopyBytes(n)) + + case *shortNode: + return &shortNode{ + flags: n.flags.copy(), + Key: common.CopyBytes(n.Key), + Val: copyNode(n.Val), + } + case *fullNode: + var children [17]node + for i, cn := range n.Children { + children[i] = copyNode(cn) + } + return &fullNode{ + flags: n.flags.copy(), + Children: children, + } + case hashNode: + return n + default: + panic(fmt.Sprintf("%T: unknown node type", n)) + } +} + func (t *Trie) resolve(n node, prefix []byte) (node, error) { if n, ok := n.(hashNode); ok { return t.resolveAndTrack(n, prefix) @@ -593,15 +617,16 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { return nil, err } t.tracer.onRead(prefix, blob) - return mustDecodeNode(n, blob), nil + + // The returned node blob won't be changed afterward. No need to + // deep-copy the slice. + return decodeNodeUnsafe(n, blob) } // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { - hash, cached := t.hashRoot() - t.root = cached - return common.BytesToHash(hash.(hashNode)) + return common.BytesToHash(t.hashRoot().(hashNode)) } // Commit collects all dirty nodes in the trie and replaces them with the @@ -652,9 +677,9 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { } // hashRoot calculates the root hash of the given trie -func (t *Trie) hashRoot() (node, node) { +func (t *Trie) hashRoot() node { if t.root == nil { - return hashNode(types.EmptyRootHash.Bytes()), nil + return hashNode(types.EmptyRootHash.Bytes()) } // If the number of changes is below 100, we let one thread handle it h := newHasher(t.unhashed >= 100) @@ -662,8 +687,7 @@ func (t *Trie) hashRoot() (node, node) { returnHasherToPool(h) t.unhashed = 0 }() - hashed, cached := h.hash(t.root, true) - return hashed, cached + return h.hash(t.root, true) } // Witness returns a set containing all trie nodes that have been accessed. diff --git a/trie/trie_test.go b/trie/trie_test.go index 77234d9d9..54d1b083d 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -1330,3 +1330,171 @@ func printSet(set *trienode.NodeSet) string { } return out.String() } + +func TestTrieCopy(t *testing.T) { + testTrieCopy(t, []kv{ + {k: []byte("do"), v: []byte("verb")}, + {k: []byte("ether"), v: []byte("wookiedoo")}, + {k: []byte("horse"), v: []byte("stallion")}, + {k: []byte("shaman"), v: []byte("horse")}, + {k: []byte("doge"), v: []byte("coin")}, + {k: []byte("dog"), v: []byte("puppy")}, + }) + + var entries []kv + for i := 0; i < 256; i++ { + entries = append(entries, kv{k: testrand.Bytes(32), v: testrand.Bytes(32)}) + } + testTrieCopy(t, entries) +} + +func testTrieCopy(t *testing.T, entries []kv) { + tr := NewEmpty(nil) + for _, entry := range entries { + tr.Update(entry.k, entry.v) + } + trCpy := tr.Copy() + + if tr.Hash() != trCpy.Hash() { + t.Errorf("Hash mismatch: old %v, copy %v", tr.Hash(), trCpy.Hash()) + } + + // Check iterator + it, _ := tr.NodeIterator(nil) + itCpy, _ := trCpy.NodeIterator(nil) + + for it.Next(false) { + hasNext := itCpy.Next(false) + if !hasNext { + t.Fatal("Iterator is not matched") + } + if !bytes.Equal(it.Path(), itCpy.Path()) { + t.Fatal("Iterator is not matched") + } + if it.Leaf() != itCpy.Leaf() { + t.Fatal("Iterator is not matched") + } + if it.Leaf() && !bytes.Equal(it.LeafBlob(), itCpy.LeafBlob()) { + t.Fatal("Iterator is not matched") + } + } + + // Check commit + root, nodes := tr.Commit(false) + rootCpy, nodesCpy := trCpy.Commit(false) + if root != rootCpy { + t.Fatal("root mismatch") + } + if len(nodes.Nodes) != len(nodesCpy.Nodes) { + t.Fatal("commit node mismatch") + } + for p, n := range nodes.Nodes { + nn, exists := nodesCpy.Nodes[p] + if !exists { + t.Fatalf("node not exists: %v", p) + } + if !reflect.DeepEqual(n, nn) { + t.Fatalf("node mismatch: %v", p) + } + } +} + +func TestTrieCopyOldTrie(t *testing.T) { + testTrieCopyOldTrie(t, []kv{ + {k: []byte("do"), v: []byte("verb")}, + {k: []byte("ether"), v: []byte("wookiedoo")}, + {k: []byte("horse"), v: []byte("stallion")}, + {k: []byte("shaman"), v: []byte("horse")}, + {k: []byte("doge"), v: []byte("coin")}, + {k: []byte("dog"), v: []byte("puppy")}, + }) + + var entries []kv + for i := 0; i < 256; i++ { + entries = append(entries, kv{k: testrand.Bytes(32), v: testrand.Bytes(32)}) + } + testTrieCopyOldTrie(t, entries) +} + +func testTrieCopyOldTrie(t *testing.T, entries []kv) { + tr := NewEmpty(nil) + for _, entry := range entries { + tr.Update(entry.k, entry.v) + } + hash := tr.Hash() + + trCpy := tr.Copy() + for _, val := range entries { + if rand.Intn(2) == 0 { + trCpy.Delete(val.k) + } else { + trCpy.Update(val.k, testrand.Bytes(32)) + } + } + for i := 0; i < 10; i++ { + trCpy.Update(testrand.Bytes(32), testrand.Bytes(32)) + } + trCpy.Hash() + trCpy.Commit(false) + + // Traverse the original tree, the changes made on the copy one shouldn't + // affect the old one + for _, entry := range entries { + d, _ := tr.Get(entry.k) + if !bytes.Equal(d, entry.v) { + t.Errorf("Unexpected data, key: %v, want: %v, got: %v", entry.k, entry.v, d) + } + } + if tr.Hash() != hash { + t.Errorf("Hash mismatch: old %v, new %v", hash, tr.Hash()) + } +} + +func TestTrieCopyNewTrie(t *testing.T) { + testTrieCopyNewTrie(t, []kv{ + {k: []byte("do"), v: []byte("verb")}, + {k: []byte("ether"), v: []byte("wookiedoo")}, + {k: []byte("horse"), v: []byte("stallion")}, + {k: []byte("shaman"), v: []byte("horse")}, + {k: []byte("doge"), v: []byte("coin")}, + {k: []byte("dog"), v: []byte("puppy")}, + }) + + var entries []kv + for i := 0; i < 256; i++ { + entries = append(entries, kv{k: testrand.Bytes(32), v: testrand.Bytes(32)}) + } + testTrieCopyNewTrie(t, entries) +} + +func testTrieCopyNewTrie(t *testing.T, entries []kv) { + tr := NewEmpty(nil) + for _, entry := range entries { + tr.Update(entry.k, entry.v) + } + trCpy := tr.Copy() + hash := trCpy.Hash() + + for _, val := range entries { + if rand.Intn(2) == 0 { + tr.Delete(val.k) + } else { + tr.Update(val.k, testrand.Bytes(32)) + } + } + for i := 0; i < 10; i++ { + tr.Update(testrand.Bytes(32), testrand.Bytes(32)) + } + + // Traverse the original tree, the changes made on the copy one shouldn't + // affect the old one + for _, entry := range entries { + d, _ := trCpy.Get(entry.k) + if !bytes.Equal(d, entry.v) { + t.Errorf("Unexpected data, key: %v, want: %v, got: %v", entry.k, entry.v, d) + } + } + if trCpy.Hash() != hash { + t.Errorf("Hash mismatch: old %v, new %v", hash, tr.Hash()) + } +} diff --git a/triedb/database/database.go b/triedb/database/database.go index cd7ec1d93..8c61ea029 100644 --- a/triedb/database/database.go +++ b/triedb/database/database.go @@ -27,6 +27,8 @@ type NodeReader interface { // node path and the corresponding node hash. No error will be returned // if the node is not found. // + // The returned node content won't be changed after the call. + // // Don't modify the returned byte slice since it's not deep-copied and // still be referenced by database. Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) From f107fcef248c7849c37d5964e4126a7657014109 Mon Sep 17 00:00:00 2001 From: sashabeton <23243361+sashabeton@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:01:21 +0100 Subject: [PATCH 246/354] internal/ethapi: exclude 7702 authorities from result in eth_createAccessList (#31336) closes https://github.com/ethereum/go-ethereum/issues/31335 --------- Co-authored-by: sashabeton --- eth/tracers/logger/access_list_tracer.go | 12 +++------- internal/ethapi/api.go | 29 +++++++++++++++++++++--- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index e8231461b..0d51f4052 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -103,16 +103,10 @@ type AccessListTracer struct { // NewAccessListTracer creates a new tracer that can generate AccessLists. // An optional AccessList can be specified to occupy slots and addresses in // the resulting accesslist. -func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompiles []common.Address) *AccessListTracer { - excl := map[common.Address]struct{}{ - from: {}, to: {}, - } - for _, addr := range precompiles { - excl[addr] = struct{}{} - } +func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Address]struct{}) *AccessListTracer { list := newAccessList() for _, al := range acl { - if _, ok := excl[al.Address]; !ok { + if _, ok := addressesToExclude[al.Address]; !ok { list.addAddress(al.Address) } for _, slot := range al.StorageKeys { @@ -120,7 +114,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } return &AccessListTracer{ - excl: excl, + excl: addressesToExclude, list: list, } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4eea2b3ad..c0791980a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1268,10 +1268,33 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Retrieve the precompiles since they don't need to be added to the access list precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) + // addressesToExclude contains sender, receiver, precompiles and valid authorizations + addressesToExclude := map[common.Address]struct{}{args.from(): {}, to: {}} + for _, addr := range precompiles { + addressesToExclude[addr] = struct{}{} + } + + // Prevent redundant operations if args contain more authorizations than EVM may handle + maxAuthorizations := uint64(*args.Gas) / params.CallNewAccountGas + if uint64(len(args.AuthorizationList)) > maxAuthorizations { + return nil, 0, nil, errors.New("insufficient gas to process all authorizations") + } + + for _, auth := range args.AuthorizationList { + // Duplicating stateTransition.validateAuthorization() logic + if (!auth.ChainID.IsZero() && auth.ChainID.CmpBig(b.ChainConfig().ChainID) != 0) || auth.Nonce+1 < auth.Nonce { + continue + } + + if authority, err := auth.Authority(); err == nil { + addressesToExclude[authority] = struct{}{} + } + } + // Create an initial tracer - prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) + prevTracer := logger.NewAccessListTracer(nil, addressesToExclude) if args.AccessList != nil { - prevTracer = logger.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles) + prevTracer = logger.NewAccessListTracer(*args.AccessList, addressesToExclude) } for { if err := ctx.Err(); err != nil { @@ -1288,7 +1311,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH msg := args.ToMessage(header.BaseFee, true, true) // Apply the transaction with the access list tracer - tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) + tracer := logger.NewAccessListTracer(accessList, addressesToExclude) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} evm := b.GetEVM(ctx, statedb, header, &config, nil) From b810ed9360acb0ba853209fe7128ee11dac0848d Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 26 Mar 2025 12:59:40 +0800 Subject: [PATCH 247/354] core/state: fix double-increment of accountLoaded counter (#31493) --- core/state/statedb.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index efafdc1aa..e3f5b9e1a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -600,7 +600,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { // Insert into the live set obj := newObject(s, addr, acct) s.setStateObject(obj) - s.AccountLoaded++ return obj } From c984c081c9bbbef53c081f6d3d762f7da1c49bc8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 26 Mar 2025 19:48:04 +0800 Subject: [PATCH 248/354] core/rawdb: remove LES database stats (#31495) This removes DB schema for LES related db entries. LES has been non-functional since the merge. --- core/rawdb/database.go | 16 ---------------- core/rawdb/schema.go | 8 -------- 2 files changed, 24 deletions(-) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 60bb18488..553724a48 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -388,10 +388,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { verkleTries stat verkleStateLookups stat - // Les statistic - chtTrieNodes stat - bloomTrieNodes stat - // Meta- and unaccounted data metadata stat unaccounted stat @@ -465,16 +461,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { case bytes.HasPrefix(key, bloomBitsMetaPrefix) && len(key) < len(bloomBitsMetaPrefix)+8: bloomBits.Add(size) - // LES indexes (deprecated) - case bytes.HasPrefix(key, chtTablePrefix) || - bytes.HasPrefix(key, chtIndexTablePrefix) || - bytes.HasPrefix(key, chtPrefix): // Canonical hash trie - chtTrieNodes.Add(size) - case bytes.HasPrefix(key, bloomTrieTablePrefix) || - bytes.HasPrefix(key, bloomTrieIndexPrefix) || - bytes.HasPrefix(key, bloomTriePrefix): // Bloomtrie sub - bloomTrieNodes.Add(size) - // Verkle trie data is detected, determine the sub-category case bytes.HasPrefix(key, VerklePrefix): remain := key[len(VerklePrefix):] @@ -538,8 +524,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Beacon sync headers", beaconHeaders.Size(), beaconHeaders.Count()}, {"Key-Value store", "Clique snapshots", cliqueSnaps.Size(), cliqueSnaps.Count()}, {"Key-Value store", "Singleton metadata", metadata.Size(), metadata.Count()}, - {"Light client", "CHT trie nodes", chtTrieNodes.Size(), chtTrieNodes.Count()}, - {"Light client", "Bloom trie nodes", bloomTrieNodes.Size(), bloomTrieNodes.Count()}, } // Inspect all registered append-only file store then. ancients, err := inspectFreezers(db) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index ce081db96..3bd583078 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -144,14 +144,6 @@ var ( // old log index bloomBitsMetaPrefix = []byte("iB") - // LES indexes - chtPrefix = []byte("chtRootV2-") // ChtPrefix + chtNum (uint64 big endian) -> trie root hash - chtTablePrefix = []byte("cht-") - chtIndexTablePrefix = []byte("chtIndexV2-") - bloomTriePrefix = []byte("bltRoot-") // BloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash - bloomTrieTablePrefix = []byte("blt-") - bloomTrieIndexPrefix = []byte("bltIndex-") - preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil) From d70652aa2c117a8e7ebf966c726097a266d0368d Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Wed, 26 Mar 2025 13:57:08 +0200 Subject: [PATCH 249/354] eth: downgrade peer removal error to warning level (#31492) --- eth/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/handler.go b/eth/handler.go index f81e84299..b9f848baf 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -469,7 +469,7 @@ func (h *handler) unregisterPeer(id string) { // Abort if the peer does not exist peer := h.peers.peer(id) if peer == nil { - logger.Error("Ethereum peer removal failed", "err", errPeerNotRegistered) + logger.Warn("Ethereum peer removal failed", "err", errPeerNotRegistered) return } // Remove the `eth` peer if it exists From 4024ca2a02a92d1dd3651eedf4d18f4e1d2a56db Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Mar 2025 16:14:17 +0100 Subject: [PATCH 250/354] accounts/abi: include access-list in gas estimation (#31394) Simple bugfix to include the access-list in the gas-estimation step of the ABI bindings code. --- accounts/abi/bind/v2/base.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/accounts/abi/bind/v2/base.go b/accounts/abi/bind/v2/base.go index a9b667e69..535c0ed4f 100644 --- a/accounts/abi/bind/v2/base.go +++ b/accounts/abi/bind/v2/base.go @@ -383,13 +383,14 @@ func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Ad } } msg := ethereum.CallMsg{ - From: opts.From, - To: contract, - GasPrice: gasPrice, - GasTipCap: gasTipCap, - GasFeeCap: gasFeeCap, - Value: value, - Data: input, + From: opts.From, + To: contract, + GasPrice: gasPrice, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Value: value, + Data: input, + AccessList: opts.AccessList, } return c.transactor.EstimateGas(ensureContext(opts.Context), msg) } From df1d2fec103de59e137b1c466da5a126f052df31 Mon Sep 17 00:00:00 2001 From: georgehao Date: Thu, 27 Mar 2025 19:22:17 +0800 Subject: [PATCH 251/354] internal/ethapi: CreateAccessList with stateOverrides (#31497) Add support for state overrides in eth_createAccessList. This will make the method consistent with other execution methods. --------- Co-authored-by: Sina Mahmoodi --- internal/ethapi/api.go | 16 ++++++-- internal/ethapi/api_test.go | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c0791980a..b3288106f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1219,12 +1219,13 @@ type accessListResult struct { // CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. -func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { +// StateOverrides can be used to create the accessList while taking into account state changes from previous transactions. +func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) (*accessListResult, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args) + acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args, stateOverrides) if err != nil { return nil, err } @@ -1238,13 +1239,22 @@ func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args Transaction // AccessList creates an access list for the given transaction. // If the accesslist creation fails an error is returned. // If the transaction itself fails, an vmErr is returned. -func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) { +func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs, stateOverrides *override.StateOverride) (acl types.AccessList, gasUsed uint64, vmErr error, err error) { // Retrieve the execution context db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if db == nil || err != nil { return nil, 0, nil, err } + // Apply state overrides immediately after StateAndHeaderByNumberOrHash. + // If not applied here, there could be cases where user-specified overrides (e.g., nonce) + // may conflict with default values from the database, leading to inconsistencies. + if stateOverrides != nil { + if err := stateOverrides.Apply(db, nil); err != nil { + return nil, 0, nil, err + } + } + // Ensure any missing fields are filled, extract the recipient and input data if err = args.setFeeDefaults(ctx, b, header); err != nil { return nil, 0, nil, err diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 9fcb00bda..79363598b 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -3547,3 +3547,76 @@ func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc s func addressToHash(a common.Address) common.Hash { return common.BytesToHash(a.Bytes()) } + +func TestCreateAccessListWithStateOverrides(t *testing.T) { + // Initialize test backend + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{ + common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7"): {Balance: big.NewInt(1000000000000000000)}, + }, + } + backend := newTestBackend(t, 1, genesis, ethash.NewFaker(), nil) + + // Create a new BlockChainAPI instance + api := NewBlockChainAPI(backend) + + // Create test contract code - a simple storage contract + // + // SPDX-License-Identifier: MIT + // pragma solidity ^0.8.0; + // + // contract SimpleStorage { + // uint256 private value; + // + // function retrieve() public view returns (uint256) { + // return value; + // } + // } + var ( + contractCode = hexutil.Bytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80632e64cec114602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60008054905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056")) + // Create state overrides with more complete state + contractAddr = common.HexToAddress("0x1234567890123456789012345678901234567890") + nonce = hexutil.Uint64(1) + overrides = &override.StateOverride{ + contractAddr: override.OverrideAccount{ + Code: &contractCode, + Balance: (*hexutil.Big)(big.NewInt(1000000000000000000)), + Nonce: &nonce, + State: map[common.Hash]common.Hash{ + common.Hash{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"), + }, + }, + } + ) + + // Create transaction arguments with gas and value + var ( + from = common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") + data = hexutil.Bytes(common.Hex2Bytes("2e64cec1")) // retrieve() + gas = hexutil.Uint64(100000) + args = TransactionArgs{ + From: &from, + To: &contractAddr, + Data: &data, + Gas: &gas, + Value: new(hexutil.Big), + } + ) + // Call CreateAccessList + result, err := api.CreateAccessList(context.Background(), args, nil, overrides) + if err != nil { + t.Fatalf("Failed to create access list: %v", err) + } + if err != nil || result == nil { + t.Fatalf("Failed to create access list: %v", err) + } + require.NotNil(t, result.Accesslist) + + // Verify access list contains the contract address and storage slot + expected := &types.AccessList{{ + Address: contractAddr, + StorageKeys: []common.Hash{{}}, + }} + require.Equal(t, expected, result.Accesslist) +} From 1b17683a7dbd3886e23c1bb732d20abc080d9458 Mon Sep 17 00:00:00 2001 From: Delweng Date: Fri, 28 Mar 2025 15:15:13 +0800 Subject: [PATCH 252/354] cmd/geth: update geth subcommand arguments (#31293) --- cmd/geth/chaincmd.go | 35 ++++++++--------- cmd/geth/dbcmd.go | 94 +++++++++++++++++--------------------------- cmd/geth/main.go | 1 - 3 files changed, 53 insertions(+), 77 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 05c8bc4c7..708dd8fb7 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -37,7 +37,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/era" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" @@ -66,7 +68,7 @@ It expects the genesis file as argument.`, Name: "dumpgenesis", Usage: "Dumps genesis block JSON configuration to stdout", ArgsUsage: "", - Flags: append([]cli.Flag{utils.DataDirFlag}, utils.NetworkFlags...), + Flags: slices.Concat([]cli.Flag{utils.DataDirFlag}, utils.NetworkFlags), Description: ` The dumpgenesis command prints the genesis configuration of the network preset if one is set. Otherwise it prints the genesis from the datadir.`, @@ -78,11 +80,11 @@ if one is set. Otherwise it prints the genesis from the datadir.`, ArgsUsage: " ( ... ) ", Flags: slices.Concat([]cli.Flag{ utils.CacheFlag, - utils.SyncModeFlag, utils.GCModeFlag, utils.SnapshotFlag, utils.CacheDatabaseFlag, utils.CacheGCFlag, + utils.NoCompactionFlag, utils.MetricsEnabledFlag, utils.MetricsEnabledExpensiveFlag, utils.MetricsHTTPFlag, @@ -105,7 +107,11 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.LogNoHistoryFlag, utils.LogExportCheckpointsFlag, utils.StateHistoryFlag, - }, utils.DatabaseFlags), + }, utils.DatabaseFlags, debug.Flags), + Before: func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) + return debug.Setup(ctx) + }, Description: ` The import command allows the import of blocks from an RLP-encoded format. This format can be a single file containing multiple RLP-encoded blocks, or multiple files can be given. @@ -119,10 +125,7 @@ to import successfully.`, Name: "export", Usage: "Export blockchain into file", ArgsUsage: " [ ]", - Flags: slices.Concat([]cli.Flag{ - utils.CacheFlag, - utils.SyncModeFlag, - }, utils.DatabaseFlags), + Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags), Description: ` Requires a first argument of the file to write to. Optional second and third arguments control the first and @@ -135,12 +138,7 @@ be gzipped.`, Name: "import-history", Usage: "Import an Era archive", ArgsUsage: "", - Flags: slices.Concat([]cli.Flag{ - utils.TxLookupLimitFlag, - }, - utils.DatabaseFlags, - utils.NetworkFlags, - ), + Flags: slices.Concat([]cli.Flag{utils.TxLookupLimitFlag, utils.TransactionHistoryFlag}, utils.DatabaseFlags, utils.NetworkFlags), Description: ` The import-history command will import blocks and their corresponding receipts from Era archives. @@ -151,7 +149,7 @@ from Era archives. Name: "export-history", Usage: "Export blockchain history to Era archives", ArgsUsage: " ", - Flags: slices.Concat(utils.DatabaseFlags), + Flags: utils.DatabaseFlags, Description: ` The export-history command will export blocks and their corresponding receipts into Era archives. Eras are typically packaged in steps of 8192 blocks. @@ -162,10 +160,7 @@ into Era archives. Eras are typically packaged in steps of 8192 blocks. Name: "import-preimages", Usage: "Import the preimage database from an RLP stream", ArgsUsage: "", - Flags: slices.Concat([]cli.Flag{ - utils.CacheFlag, - utils.SyncModeFlag, - }, utils.DatabaseFlags), + Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags), Description: ` The import-preimages command imports hash preimages from an RLP encoded stream. It's deprecated, please use "geth db import" instead. @@ -435,6 +430,10 @@ func importHistory(ctx *cli.Context) error { network = "mainnet" case ctx.Bool(utils.SepoliaFlag.Name): network = "sepolia" + case ctx.Bool(utils.HoleskyFlag.Name): + network = "holesky" + case ctx.Bool(utils.HoodiFlag.Name): + network = "hoodi" } } else { // No network flag set, try to determine network based on files diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index cd41c57c7..44a52521f 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -86,12 +86,10 @@ Remove blockchain and state databases`, }, } dbInspectCmd = &cli.Command{ - Action: inspect, - Name: "inspect", - ArgsUsage: " ", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: inspect, + Name: "inspect", + ArgsUsage: " ", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Usage: "Inspect the storage size for each type of data in the database", Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`, } @@ -109,16 +107,13 @@ a data corruption.`, Action: dbStats, Name: "stats", Usage: "Print leveldb statistics", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), } dbCompactCmd = &cli.Command{ Action: dbCompact, Name: "compact", Usage: "Compact leveldb database. WARNING: May take a very long time", Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, utils.CacheFlag, utils.CacheDatabaseFlag, }, utils.NetworkFlags, utils.DatabaseFlags), @@ -127,13 +122,11 @@ WARNING: This operation may take a very long time to finish, and may cause datab corruption if it is aborted during execution'!`, } dbGetCmd = &cli.Command{ - Action: dbGet, - Name: "get", - Usage: "Show the value of a database key", - ArgsUsage: "", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: dbGet, + Name: "get", + Usage: "Show the value of a database key", + ArgsUsage: "", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: "This command looks up the specified database key from the database.", } dbDeleteCmd = &cli.Command{ @@ -141,9 +134,7 @@ corruption if it is aborted during execution'!`, Name: "delete", Usage: "Delete a database key (WARNING: may corrupt your database)", ArgsUsage: "", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: `This command deletes the specified database key from the database. WARNING: This is a low-level operation which may cause database corruption!`, } @@ -152,59 +143,47 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "put", Usage: "Set the value of a database key (WARNING: may corrupt your database)", ArgsUsage: " ", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: `This command sets a given database key to the given value. WARNING: This is a low-level operation which may cause database corruption!`, } dbGetSlotsCmd = &cli.Command{ - Action: dbDumpTrie, - Name: "dumptrie", - Usage: "Show the storage key/values of a given storage trie", - ArgsUsage: " ", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: dbDumpTrie, + Name: "dumptrie", + Usage: "Show the storage key/values of a given storage trie", + ArgsUsage: " ", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: "This command looks up the specified database key from the database.", } dbDumpFreezerIndex = &cli.Command{ - Action: freezerInspect, - Name: "freezer-index", - Usage: "Dump out the index of a specific freezer table", - ArgsUsage: " ", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: freezerInspect, + Name: "freezer-index", + Usage: "Dump out the index of a specific freezer table", + ArgsUsage: " ", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: "This command displays information about the freezer index.", } dbImportCmd = &cli.Command{ - Action: importLDBdata, - Name: "import", - Usage: "Imports leveldb-data from an exported RLP dump.", - ArgsUsage: " has .gz suffix, gzip compression will be used.", - ArgsUsage: " ", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: exportChaindata, + Name: "export", + Usage: "Exports the chain data into an RLP dump. If the has .gz suffix, gzip compression will be used.", + ArgsUsage: " ", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.", } dbMetadataCmd = &cli.Command{ - Action: showMetaData, - Name: "metadata", - Usage: "Shows metadata about the chain status.", - Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabaseFlags), + Action: showMetaData, + Name: "metadata", + Usage: "Shows metadata about the chain status.", + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Description: "Shows metadata about the chain status.", } dbInspectHistoryCmd = &cli.Command{ @@ -213,7 +192,6 @@ WARNING: This is a low-level operation which may cause database corruption!`, Usage: "Inspect the state history within block range", ArgsUsage: "
[OPTIONAL ]", Flags: slices.Concat([]cli.Flag{ - utils.SyncModeFlag, &cli.Uint64Flag{ Name: "start", Usage: "block number of the range start, zero means earliest history", diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 08af9206f..8e1ec70c9 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -160,7 +160,6 @@ var ( utils.VMTraceJsonConfigFlag, utils.NetworkIdFlag, utils.EthStatsURLFlag, - utils.NoCompactionFlag, utils.GpoBlocksFlag, utils.GpoPercentileFlag, utils.GpoMaxGasPriceFlag, From 99b670c888a3b5b9a8e814eafd2caed29246feef Mon Sep 17 00:00:00 2001 From: rekyyang <511965710@qq.com> Date: Fri, 28 Mar 2025 15:16:37 +0800 Subject: [PATCH 253/354] core/txpool/legacypool: fix data race in checkDelegationLimit (#31475) --- core/txpool/legacypool/legacypool.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index a8c056f8d..6079b85da 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -739,7 +739,7 @@ func (pool *LegacyPool) checkDelegationLimit(tx *types.Transaction) error { from, _ := types.Sender(pool.signer, tx) // validated // Short circuit if the sender has neither delegation nor pending delegation. - if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && len(pool.all.auths[from]) == 0 { + if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && pool.all.delegationTxsCount(from) == 0 { return nil } pending := pool.pending[from] @@ -1974,6 +1974,13 @@ func (t *lookup) removeAuthorities(tx *types.Transaction) { } } +// delegationTxsCount returns the number of pending authorizations for the specified address. +func (t *lookup) delegationTxsCount(addr common.Address) int { + t.lock.RLock() + defer t.lock.RUnlock() + return len(t.auths[addr]) +} + // numSlots calculates the number of slots needed for a single transaction. func numSlots(tx *types.Transaction) int { return int((tx.Size() + txSlotSize - 1) / txSlotSize) From c132e595053d6861a78a9d8ac873b90c5773d2d6 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 28 Mar 2025 19:32:24 +0800 Subject: [PATCH 254/354] core/txpool: fix nonce assignment in local tracker (#31496) Fixes #31494 --- core/txpool/locals/tx_tracker_test.go | 39 +++++++++++++++++++++++++++ core/txpool/txpool.go | 13 +++++++-- eth/api_backend.go | 2 +- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/core/txpool/locals/tx_tracker_test.go b/core/txpool/locals/tx_tracker_test.go index ae700bc94..7f82c8793 100644 --- a/core/txpool/locals/tx_tracker_test.go +++ b/core/txpool/locals/tx_tracker_test.go @@ -108,6 +108,19 @@ func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction { return tx } +func (env *testEnv) makeTxs(n int) []*types.Transaction { + head := env.chain.CurrentHeader() + state, _ := env.chain.StateAt(head.Root) + nonce := state.GetNonce(address) + + var txs []*types.Transaction + for i := 0; i < n; i++ { + tx, _ := types.SignTx(types.NewTransaction(nonce+uint64(i), common.Address{0x00}, big.NewInt(1000), params.TxGas, big.NewInt(params.GWei), nil), signer, key) + txs = append(txs, tx) + } + return txs +} + func (env *testEnv) commit() { head := env.chain.CurrentBlock() block := env.chain.GetBlock(head.Hash(), head.Number.Uint64()) @@ -177,3 +190,29 @@ func TestRejectInvalids(t *testing.T) { } } } + +func TestResubmit(t *testing.T) { + env := newTestEnv(t, 10, 0, "") + defer env.close() + + txs := env.makeTxs(10) + txsA := txs[:len(txs)/2] + txsB := txs[len(txs)/2:] + env.pool.Add(txsA, true, true) + pending, queued := env.pool.ContentFrom(address) + if len(pending) != len(txsA) || len(queued) != 0 { + t.Fatalf("Unexpected txpool content: %d, %d", len(pending), len(queued)) + } + env.tracker.TrackAll(txs) + + resubmit, all := env.tracker.recheck(true) + if len(resubmit) != len(txsB) { + t.Fatalf("Unexpected transactions to resubmit, got: %d, want: %d", len(resubmit), len(txsB)) + } + if len(all) == 0 || len(all[address]) == 0 { + t.Fatalf("Unexpected transactions being tracked, got: %d, want: %d", 0, len(txs)) + } + if len(all[address]) != len(txs) { + t.Fatalf("Unexpected transactions being tracked, got: %d, want: %d", len(all[address]), len(txs)) + } +} diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index cc344066b..8b7964907 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -483,9 +483,9 @@ func (p *TxPool) SubscribeReannoTransactions(ch chan<- core.ReannoTxsEvent) even return p.subs.Track(event.JoinSubscriptions(subs...)) } -// Nonce returns the next nonce of an account, with all transactions executable +// PoolNonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. -func (p *TxPool) Nonce(addr common.Address) uint64 { +func (p *TxPool) PoolNonce(addr common.Address) uint64 { // Since (for now) accounts are unique to subpools, only one pool will have // (at max) a non-state nonce. To avoid stateful lookups, just return the // highest nonce for now. @@ -498,6 +498,15 @@ func (p *TxPool) Nonce(addr common.Address) uint64 { return nonce } +// Nonce returns the next nonce of an account at the current chain head. Unlike +// PoolNonce, this function does not account for pending executable transactions. +func (p *TxPool) Nonce(addr common.Address) uint64 { + p.stateLock.RLock() + defer p.stateLock.RUnlock() + + return p.state.GetNonce(addr) +} + // GetCachedTransaction returns the transaction cached in amev cache pool. func (p *TxPool) GetCachedTransaction(nonce uint64, sender common.Address) *types.Transaction { for _, subpool := range p.subpools { diff --git a/eth/api_backend.go b/eth/api_backend.go index f12002f31..7d120be4c 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -344,7 +344,7 @@ func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) } func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { - return b.eth.txPool.Nonce(addr), nil + return b.eth.txPool.PoolNonce(addr), nil } func (b *EthAPIBackend) Stats() (runnable int, blocked int) { From 6656672b6bf8f44298077d41de68041f04896958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 28 Mar 2025 16:17:28 +0100 Subject: [PATCH 255/354] core/filtermaps: revert to unindexed mode in case of indexing error (#31500) This PR changes log indexer error handling so that if an indexing error happens then it disables the indexer and reverts to unindexed more without resetting the database (except in case of a failed database init). Resetting the database on the first error would probably be overkill as a client update might fix this without having to reindex the entire history. It would also make debugging very hard. On the other hand, these errors do not resolve themselves automatically so constantly retrying makes no sense either. With these changes a new attempt to resume indexing is made every time the client is restarted. The PR also fixes https://github.com/ethereum/go-ethereum/issues/31491 which originated from the tail indexer trying to resume processing a failed map renderer. --------- Co-authored-by: Felix Lange --- core/filtermaps/chain_view.go | 6 ++- core/filtermaps/indexer.go | 97 ++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index bc0de47de..a8cf53b1c 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -83,7 +83,11 @@ func (cv *ChainView) getReceipts(number uint64) types.Receipts { if number > cv.headNumber { panic("invalid block number") } - return cv.chain.GetReceiptsByHash(cv.blockHash(number)) + blockHash := cv.blockHash(number) + if blockHash == (common.Hash{}) { + log.Error("Chain view: block hash unavailable", "number", number, "head", cv.headNumber) + } + return cv.chain.GetReceiptsByHash(blockHash) } // limitedView returns a new chain view that is a truncated version of the parent view. diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 026b3b4f3..6732dc85e 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -17,6 +17,7 @@ package filtermaps import ( + "errors" "math" "time" @@ -49,18 +50,15 @@ func (f *FilterMaps) indexerLoop() { continue } if err := f.init(); err != nil { - log.Error("Error initializing log index; reverting to unindexed mode", "error", err) - f.reset() - f.disabled = true - close(f.disabledCh) + f.disableForError("initialization", err) + f.reset() // remove broken index from DB return } } if !f.targetHeadIndexed() { - if !f.tryIndexHead() { - // either shutdown or unexpected error; in the latter case ensure - // that proper shutdown is still possible. - f.processSingleEvent(true) + if err := f.tryIndexHead(); err != nil && err != errChainUpdate { + f.disableForError("head rendering", err) + return } } else { if f.finalBlock != f.lastFinal { @@ -69,13 +67,36 @@ func (f *FilterMaps) indexerLoop() { } f.lastFinal = f.finalBlock } - if f.tryIndexTail() && f.tryUnindexTail() { - f.waitForNewHead() + if done, err := f.tryIndexTail(); err != nil { + f.disableForError("tail rendering", err) + return + } else if !done { + continue + } + if done, err := f.tryUnindexTail(); err != nil { + f.disableForError("tail unindexing", err) + return + } else if !done { + continue } + // tail indexing/unindexing is done; if head is also indexed then + // wait here until there is a new head + f.waitForNewHead() } } } +// disableForError is called when the indexer encounters a database error, for example a +// missing receipt. We can't continue operating when the database is broken, so the +// indexer goes into disabled state. +// Note that the partial index is left in disk; maybe a client update can fix the +// issue without reindexing. +func (f *FilterMaps) disableForError(op string, err error) { + log.Error("Log index "+op+" failed, reverting to unindexed mode", "error", err) + f.disabled = true + close(f.disabledCh) +} + type targetUpdate struct { targetView *ChainView historyCutoff, finalBlock uint64 @@ -116,14 +137,15 @@ func (f *FilterMaps) SetBlockProcessing(blockProcessing bool) { // WaitIdle blocks until the indexer is in an idle state while synced up to the // latest targetView. func (f *FilterMaps) WaitIdle() { - if f.disabled { - f.closeWg.Wait() - return - } for { ch := make(chan bool) - f.waitIdleCh <- ch - if <-ch { + select { + case f.waitIdleCh <- ch: + if <-ch { + return + } + case <-f.disabledCh: + f.closeWg.Wait() return } } @@ -196,16 +218,16 @@ func (f *FilterMaps) setTarget(target targetUpdate) { f.finalBlock = target.finalBlock } -// tryIndexHead tries to render head maps according to the current targetView -// and returns true if successful. -func (f *FilterMaps) tryIndexHead() bool { +// tryIndexHead tries to render head maps according to the current targetView. +// Should be called when targetHeadIndexed returns false. If this function +// returns no error then either stop is true or head indexing is finished. +func (f *FilterMaps) tryIndexHead() error { headRenderer, err := f.renderMapsBefore(math.MaxUint32) if err != nil { - log.Error("Error creating log index head renderer", "error", err) - return false + return err } if headRenderer == nil { - return true + return errors.New("head indexer has nothing to do") // tryIndexHead should be called when head is not indexed } if !f.startedHeadIndex { f.lastLogHeadIndex = time.Now() @@ -230,8 +252,7 @@ func (f *FilterMaps) tryIndexHead() bool { f.lastLogHeadIndex = time.Now() } }); err != nil { - log.Error("Log index head rendering failed", "error", err) - return false + return err } if f.loggedHeadIndex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index head rendering finished", @@ -240,7 +261,7 @@ func (f *FilterMaps) tryIndexHead() bool { "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) } f.loggedHeadIndex, f.startedHeadIndex = false, false - return true + return nil } // tryIndexTail tries to render tail epochs until the tail target block is @@ -248,7 +269,7 @@ func (f *FilterMaps) tryIndexHead() bool { // Note that tail indexing is only started if the log index head is fully // rendered according to targetView and is suspended as soon as the targetView // is changed. -func (f *FilterMaps) tryIndexTail() bool { +func (f *FilterMaps) tryIndexTail() (bool, error) { for { firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch if firstEpoch == 0 || !f.needTailEpoch(firstEpoch-1) { @@ -256,7 +277,7 @@ func (f *FilterMaps) tryIndexTail() bool { } f.processEvents() if f.stop || !f.targetHeadIndexed() { - return false + return false, nil } // resume process if tail rendering was interrupted because of head rendering tailRenderer := f.tailRenderer @@ -268,8 +289,7 @@ func (f *FilterMaps) tryIndexTail() bool { var err error tailRenderer, err = f.renderMapsBefore(f.indexedRange.maps.First()) if err != nil { - log.Error("Error creating log index tail renderer", "error", err) - return false + return false, err } } if tailRenderer == nil { @@ -302,13 +322,16 @@ func (f *FilterMaps) tryIndexTail() bool { f.lastLogTailIndex = time.Now() } }) - if err != nil && f.needTailEpoch(firstEpoch-1) { + if err != nil && !f.needTailEpoch(firstEpoch-1) { // stop silently if cutoff point has move beyond epoch boundary while rendering - log.Error("Log index tail rendering failed", "error", err) + return true, nil + } + if err != nil { + return false, err } if !done { f.tailRenderer = tailRenderer // only keep tail renderer if interrupted by stopCb - return false + return false, nil } } if f.loggedTailIndex && f.indexedRange.hasIndexedBlocks() { @@ -318,14 +341,14 @@ func (f *FilterMaps) tryIndexTail() bool { "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) f.loggedTailIndex = false } - return true + return true, nil } // tryUnindexTail removes entire epochs of log index data as long as the first // fully indexed block is at least as old as the tail target. // Note that unindexing is very quick as it only removes continuous ranges of // data from the database and is also called while running head indexing. -func (f *FilterMaps) tryUnindexTail() bool { +func (f *FilterMaps) tryUnindexTail() (bool, error) { for { firstEpoch := (f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch if f.needTailEpoch(firstEpoch) { @@ -333,7 +356,7 @@ func (f *FilterMaps) tryUnindexTail() bool { } f.processEvents() if f.stop { - return false + return false, nil } if !f.startedTailUnindex { f.startedTailUnindexAt = time.Now() @@ -343,7 +366,7 @@ func (f *FilterMaps) tryUnindexTail() bool { } if err := f.deleteTailEpoch(firstEpoch); err != nil { log.Error("Log index tail epoch unindexing failed", "error", err) - return false + return false, err } } if f.startedTailUnindex && f.indexedRange.hasIndexedBlocks() { @@ -354,7 +377,7 @@ func (f *FilterMaps) tryUnindexTail() bool { "elapsed", common.PrettyDuration(time.Since(f.startedTailUnindexAt))) f.startedTailUnindex = false } - return true + return true, nil } // needTailEpoch returns true if the given tail epoch needs to be kept From 113dcc6c31c2efcbd3c7d281bdd57bf54cb9aa59 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 31 Mar 2025 09:49:19 +0200 Subject: [PATCH 256/354] .gitignore: ignore binaries (#31531) Ignores all hand-built binaries (built with go build, everything built with make is already ignored) --- .gitignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitignore b/.gitignore index 0f24cc3d7..d01f66e91 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,16 @@ node_modules /contracts/coverage.json /contracts/ignition /contracts/package-lock.json + +# binaries +cmd/abidump/abidump +cmd/abigen/abigen +cmd/blsync/blsync +cmd/clef/clef +cmd/devp2p/devp2p +cmd/era/era +cmd/ethkey/ethkey +cmd/evm/evm +cmd/geth/geth +cmd/rlpdump/rlpdump +cmd/workload/workload From 1256959e64b9fd924aa372549eb668af2cad2813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 31 Mar 2025 14:47:56 +0200 Subject: [PATCH 257/354] core/filtermaps: hashdb safe delete range (#31525) This PR adds `rawdb.SafeDeleteRange` and uses it for range deletion in `core/filtermaps`. This includes deleting the old bloombits database, resetting the log index database and removing index data for unindexed tail epochs (which previously weren't properly implemented for the fallback case). `SafeDeleteRange` either calls `ethdb.DeleteRange` if the node uses the new path based state scheme or uses an iterator based fallback method that safely skips trie nodes in the range if the old hash based state scheme is used. Note that `ethdb.DeleteRange` also has its own iterator based fallback implementation in `ethdb/leveldb`. If a path based state scheme is used and the backing db is pebble (as it is on the majority of new nodes) then `rawdb.SafeDeleteRange` uses the fast native range delete. Also note that `rawdb.SafeDeleteRange` has different semantics from `ethdb.DeleteRange`, it does not automatically return if the operation takes a long time. Instead it receives a `stopCallback` that can interrupt the process if necessary. This is because in the safe mode potentially a lot of entries are iterated without being deleted (this is definitely the case when deleting the old bloombits database which has a single byte prefix) and therefore restarting the process every time a fixed number of entries have been iterated would result in a quadratic run time in the number of skipped entries. When running in safe mode, unindexing an epoch takes about a second, removing bloombits takes around 10s while resetting a full log index might take a few minutes. If a range delete operation takes a significant amount of time then log messages are printed. Also, any range delete operation can be interrupted by shutdown (tail uinindexing can also be interrupted by head indexing, similarly to how tail indexing works). If the last unindexed epoch might have "dirty" index data left then the indexed map range points to the first valid epoch and `cleanedEpochsBefore` points to the previous, potentially dirty one. At startup it is always assumed that the epoch before the first fully indexed one might be dirty. New tail maps are never rendered and also no further maps are unindexed before the previous unindexing is properly cleaned up. --------- Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/filtermaps/filtermaps.go | 210 ++++++++++++++++++++------------ core/filtermaps/indexer.go | 32 ++--- core/rawdb/accessors_indexes.go | 38 +++--- core/rawdb/database.go | 73 +++++++++++ eth/backend.go | 7 +- ethdb/database.go | 9 +- ethdb/leveldb/leveldb.go | 4 +- 7 files changed, 256 insertions(+), 117 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index db7ab0a42..5722f17da 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/log" ) @@ -59,6 +58,7 @@ type FilterMaps struct { closeCh chan struct{} closeWg sync.WaitGroup history uint64 + hashScheme bool // use hashdb-safe delete range method exportFileName string Params @@ -67,10 +67,11 @@ type FilterMaps struct { // fields written by the indexer and read by matcher backend. Indexer can // read them without a lock and write them under indexLock write lock. // Matcher backend can read them under indexLock read lock. - indexLock sync.RWMutex - indexedRange filterMapsRange - indexedView *ChainView // always consistent with the log index - hasTempRange bool + indexLock sync.RWMutex + indexedRange filterMapsRange + cleanedEpochsBefore uint32 // all unindexed data cleaned before this point + indexedView *ChainView // always consistent with the log index + hasTempRange bool // also accessed by indexer and matcher backend but no locking needed. filterMapCache *lru.Cache[uint32, filterMap] @@ -180,6 +181,10 @@ type Config struct { // This option enables the checkpoint JSON file generator. // If set, the given file will be updated with checkpoint information. ExportFileName string + + // expect trie nodes of hash based state scheme in the filtermaps key range; + // use safe iterator based implementation of DeleteRange that skips them + HashScheme bool } // NewFilterMaps creates a new FilterMaps and starts the indexer. @@ -197,6 +202,7 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f blockProcessingCh: make(chan bool, 1), history: config.History, disabled: config.Disabled, + hashScheme: config.HashScheme, disabledCh: make(chan struct{}), exportFileName: config.ExportFileName, Params: params, @@ -208,15 +214,17 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f maps: common.NewRange(rs.MapsFirst, rs.MapsAfterLast-rs.MapsFirst), tailPartialEpoch: rs.TailPartialEpoch, }, - historyCutoff: historyCutoff, - finalBlock: finalBlock, - matcherSyncCh: make(chan *FilterMapsMatcherBackend), - matchers: make(map[*FilterMapsMatcherBackend]struct{}), - filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), - lastBlockCache: lru.NewCache[uint32, lastBlockOfMap](cachedLastBlocks), - lvPointerCache: lru.NewCache[uint64, uint64](cachedLvPointers), - baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), - renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), + // deleting last unindexed epoch might have been interrupted by shutdown + cleanedEpochsBefore: max(rs.MapsFirst>>params.logMapsPerEpoch, 1) - 1, + historyCutoff: historyCutoff, + finalBlock: finalBlock, + matcherSyncCh: make(chan *FilterMapsMatcherBackend), + matchers: make(map[*FilterMapsMatcherBackend]struct{}), + filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), + lastBlockCache: lru.NewCache[uint32, lastBlockOfMap](cachedLastBlocks), + lvPointerCache: lru.NewCache[uint64, uint64](cachedLvPointers), + baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), + renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), } // Set initial indexer target. @@ -301,14 +309,24 @@ func (f *FilterMaps) reset() { // deleting the range first ensures that resetDb will be called again at next // startup and any leftover data will be removed even if it cannot finish now. rawdb.DeleteFilterMapsRange(f.db) - f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") + f.safeDeleteWithLogs(rawdb.DeleteFilterMapsDb, "Resetting log index database", f.isShuttingDown) +} + +// isShuttingDown returns true if FilterMaps is shutting down. +func (f *FilterMaps) isShuttingDown() bool { + select { + case <-f.closeCh: + return true + default: + return false + } } // init initializes an empty log index according to the current targetView. func (f *FilterMaps) init() error { // ensure that there is no remaining data in the filter maps key range - if !f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") { - return errors.New("could not reset log index database") + if err := f.safeDeleteWithLogs(rawdb.DeleteFilterMapsDb, "Resetting log index database", f.isShuttingDown); err != nil { + return err } f.indexLock.Lock() @@ -358,38 +376,37 @@ func (f *FilterMaps) init() error { // removeBloomBits removes old bloom bits data from the database. func (f *FilterMaps) removeBloomBits() { - f.safeDeleteRange(rawdb.DeleteBloomBitsDb, "Removing old bloom bits database") + f.safeDeleteWithLogs(rawdb.DeleteBloomBitsDb, "Removing old bloom bits database", f.isShuttingDown) f.closeWg.Done() } -// safeDeleteRange calls the specified database range deleter function -// repeatedly as long as it returns leveldb.ErrTooManyKeys. -// This wrapper is necessary because of the leveldb fallback implementation -// of DeleteRange. -func (f *FilterMaps) safeDeleteRange(removeFn func(ethdb.KeyValueRangeDeleter) error, action string) bool { - start := time.Now() - var retry bool - for { - err := removeFn(f.db) - if err == nil { - if retry { - log.Info(action+" finished", "elapsed", time.Since(start)) - } - return true - } - if err != leveldb.ErrTooManyKeys { - log.Error(action+" failed", "error", err) - return false +// safeDeleteWithLogs is a wrapper for a function that performs a safe range +// delete operation using rawdb.SafeDeleteRange. It emits log messages if the +// process takes long enough to call the stop callback. +func (f *FilterMaps) safeDeleteWithLogs(deleteFn func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error, action string, stopCb func() bool) error { + var ( + start = time.Now() + logPrinted bool + lastLogPrinted = start + ) + switch err := deleteFn(f.db, f.hashScheme, func(deleted bool) bool { + if deleted && !logPrinted || time.Since(lastLogPrinted) > time.Second*10 { + log.Info(action+" in progress...", "elapsed", common.PrettyDuration(time.Since(start))) + logPrinted, lastLogPrinted = true, time.Now() } - select { - case <-f.closeCh: - return false - default: - } - if !retry { - log.Info(action+" in progress...", "elapsed", time.Since(start)) - retry = true + return stopCb() + }); { + case err == nil: + if logPrinted { + log.Info(action+" finished", "elapsed", common.PrettyDuration(time.Since(start))) } + return nil + case errors.Is(err, rawdb.ErrDeleteRangeInterrupted): + log.Warn(action+" interrupted", "elapsed", common.PrettyDuration(time.Since(start))) + return err + default: + log.Error(action+" failed", "error", err) + return err } } @@ -658,54 +675,97 @@ func (f *FilterMaps) deleteLastBlockOfMap(batch ethdb.Batch, mapIndex uint32) { rawdb.DeleteFilterMapLastBlock(batch, mapIndex) } -// deleteTailEpoch deletes index data from the earliest, either fully or partially -// indexed epoch. The last block pointer for the last map of the epoch and the -// corresponding block log value pointer are retained as these are always assumed -// to be available for each epoch. -func (f *FilterMaps) deleteTailEpoch(epoch uint32) error { +// deleteTailEpoch deletes index data from the specified epoch. The last block +// pointer for the last map of the epoch and the corresponding block log value +// pointer are retained as these are always assumed to be available for each +// epoch as boundary markers. +// The function returns true if all index data related to the epoch (except for +// the boundary markers) has been fully removed. +func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) { f.indexLock.Lock() defer f.indexLock.Unlock() + // determine epoch boundaries firstMap := epoch << f.logMapsPerEpoch lastBlock, _, err := f.getLastBlockOfMap(firstMap + f.mapsPerEpoch - 1) if err != nil { - return fmt.Errorf("failed to retrieve last block of deleted epoch %d: %v", epoch, err) + return false, fmt.Errorf("failed to retrieve last block of deleted epoch %d: %v", epoch, err) } var firstBlock uint64 if epoch > 0 { firstBlock, _, err = f.getLastBlockOfMap(firstMap - 1) if err != nil { - return fmt.Errorf("failed to retrieve last block before deleted epoch %d: %v", epoch, err) + return false, fmt.Errorf("failed to retrieve last block before deleted epoch %d: %v", epoch, err) } firstBlock++ } - fmr := f.indexedRange - if f.indexedRange.maps.First() == firstMap && - f.indexedRange.maps.AfterLast() > firstMap+f.mapsPerEpoch && - f.indexedRange.tailPartialEpoch == 0 { - fmr.maps.SetFirst(firstMap + f.mapsPerEpoch) - fmr.blocks.SetFirst(lastBlock + 1) - } else if f.indexedRange.maps.First() == firstMap+f.mapsPerEpoch { + // update rendered range if necessary + var ( + fmr = f.indexedRange + firstEpoch = f.indexedRange.maps.First() >> f.logMapsPerEpoch + afterLastEpoch = (f.indexedRange.maps.AfterLast() + f.mapsPerEpoch - 1) >> f.logMapsPerEpoch + ) + if f.indexedRange.tailPartialEpoch != 0 && firstEpoch > 0 { + firstEpoch-- + } + switch { + case epoch < firstEpoch: + // cleanup of already unindexed epoch; range not affected + case epoch == firstEpoch && epoch+1 < afterLastEpoch: + // first fully or partially rendered epoch and there is at least one + // rendered map in the next epoch; remove from indexed range fmr.tailPartialEpoch = 0 + fmr.maps.SetFirst((epoch + 1) << f.logMapsPerEpoch) + fmr.blocks.SetFirst(lastBlock + 1) + f.setRange(f.db, f.indexedView, fmr, false) + default: + // cannot be cleaned or unindexed; return with error + return false, errors.New("invalid tail epoch number") + } + // remove index data + if err := f.safeDeleteWithLogs(func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error { + first := f.mapRowIndex(firstMap, 0) + count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first + if err := rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count), hashScheme, stopCb); err != nil { + return err + } + for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch; mapIndex++ { + f.filterMapCache.Remove(mapIndex) + } + delMapRange := common.NewRange(firstMap, f.mapsPerEpoch-1) // keep last entry + if err := rawdb.DeleteFilterMapLastBlocks(f.db, delMapRange, hashScheme, stopCb); err != nil { + return err + } + for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch-1; mapIndex++ { + f.lastBlockCache.Remove(mapIndex) + } + delBlockRange := common.NewRange(firstBlock, lastBlock-firstBlock) // keep last entry + if err := rawdb.DeleteBlockLvPointers(f.db, delBlockRange, hashScheme, stopCb); err != nil { + return err + } + for blockNumber := firstBlock; blockNumber < lastBlock; blockNumber++ { + f.lvPointerCache.Remove(blockNumber) + } + return nil + }, fmt.Sprintf("Deleting tail epoch #%d", epoch), func() bool { + f.processEvents() + return f.stop || !f.targetHeadIndexed() + }); err == nil { + // everything removed; mark as cleaned and report success + if f.cleanedEpochsBefore == epoch { + f.cleanedEpochsBefore = epoch + 1 + } + return true, nil } else { - return errors.New("invalid tail epoch number") - } - f.setRange(f.db, f.indexedView, fmr, false) - first := f.mapRowIndex(firstMap, 0) - count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first - rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count)) - for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch; mapIndex++ { - f.filterMapCache.Remove(mapIndex) - } - rawdb.DeleteFilterMapLastBlocks(f.db, common.NewRange(firstMap, f.mapsPerEpoch-1)) // keep last enrty - for mapIndex := firstMap; mapIndex < firstMap+f.mapsPerEpoch-1; mapIndex++ { - f.lastBlockCache.Remove(mapIndex) - } - rawdb.DeleteBlockLvPointers(f.db, common.NewRange(firstBlock, lastBlock-firstBlock)) // keep last enrty - for blockNumber := firstBlock; blockNumber < lastBlock; blockNumber++ { - f.lvPointerCache.Remove(blockNumber) + // more data left in epoch range; mark as dirty and report unfinished + if f.cleanedEpochsBefore > epoch { + f.cleanedEpochsBefore = epoch + } + if errors.Is(err, rawdb.ErrDeleteRangeInterrupted) { + return false, nil + } + return false, err } - return nil } // exportCheckpoints exports epoch checkpoints in the format used by checkpoints.go. diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 6732dc85e..9a5424da4 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -67,14 +67,17 @@ func (f *FilterMaps) indexerLoop() { } f.lastFinal = f.finalBlock } - if done, err := f.tryIndexTail(); err != nil { - f.disableForError("tail rendering", err) + // always attempt unindexing before indexing the tail in order to + // ensure that a potentially dirty previously unindexed epoch is + // always cleaned up before any new maps are rendered. + if done, err := f.tryUnindexTail(); err != nil { + f.disableForError("tail unindexing", err) return } else if !done { continue } - if done, err := f.tryUnindexTail(); err != nil { - f.disableForError("tail unindexing", err) + if done, err := f.tryIndexTail(); err != nil { + f.disableForError("tail rendering", err) return } else if !done { continue @@ -349,25 +352,24 @@ func (f *FilterMaps) tryIndexTail() (bool, error) { // Note that unindexing is very quick as it only removes continuous ranges of // data from the database and is also called while running head indexing. func (f *FilterMaps) tryUnindexTail() (bool, error) { - for { - firstEpoch := (f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch) >> f.logMapsPerEpoch - if f.needTailEpoch(firstEpoch) { - break - } - f.processEvents() - if f.stop { - return false, nil - } + firstEpoch := f.indexedRange.maps.First() >> f.logMapsPerEpoch + if f.indexedRange.tailPartialEpoch > 0 && firstEpoch > 0 { + firstEpoch-- + } + for epoch := min(firstEpoch, f.cleanedEpochsBefore); !f.needTailEpoch(epoch); epoch++ { if !f.startedTailUnindex { f.startedTailUnindexAt = time.Now() f.startedTailUnindex = true f.ptrTailUnindexMap = f.indexedRange.maps.First() - f.indexedRange.tailPartialEpoch f.ptrTailUnindexBlock = f.indexedRange.blocks.First() - f.tailPartialBlocks() } - if err := f.deleteTailEpoch(firstEpoch); err != nil { - log.Error("Log index tail epoch unindexing failed", "error", err) + if done, err := f.deleteTailEpoch(epoch); !done { return false, err } + f.processEvents() + if f.stop || !f.targetHeadIndexed() { + return false, nil + } } if f.startedTailUnindex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index tail unindexing finished", diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 297e339c8..c413839b7 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -354,10 +354,8 @@ func WriteFilterMapBaseRows(db ethdb.KeyValueWriter, mapRowIndex uint64, rows [] } } -func DeleteFilterMapRows(db ethdb.KeyValueRangeDeleter, mapRows common.Range[uint64]) { - if err := db.DeleteRange(filterMapRowKey(mapRows.First(), false), filterMapRowKey(mapRows.AfterLast(), false)); err != nil { - log.Crit("Failed to delete range of filter map rows", "err", err) - } +func DeleteFilterMapRows(db ethdb.KeyValueStore, mapRows common.Range[uint64], hashScheme bool, stopCallback func(bool) bool) error { + return SafeDeleteRange(db, filterMapRowKey(mapRows.First(), false), filterMapRowKey(mapRows.AfterLast(), false), hashScheme, stopCallback) } // ReadFilterMapLastBlock retrieves the number of the block that generated the @@ -368,7 +366,7 @@ func ReadFilterMapLastBlock(db ethdb.KeyValueReader, mapIndex uint32) (uint64, c return 0, common.Hash{}, err } if len(enc) != 40 { - return 0, common.Hash{}, errors.New("Invalid block number and id encoding") + return 0, common.Hash{}, errors.New("invalid block number and id encoding") } var id common.Hash copy(id[:], enc[8:]) @@ -394,10 +392,8 @@ func DeleteFilterMapLastBlock(db ethdb.KeyValueWriter, mapIndex uint32) { } } -func DeleteFilterMapLastBlocks(db ethdb.KeyValueRangeDeleter, maps common.Range[uint32]) { - if err := db.DeleteRange(filterMapLastBlockKey(maps.First()), filterMapLastBlockKey(maps.AfterLast())); err != nil { - log.Crit("Failed to delete range of filter map last block pointers", "err", err) - } +func DeleteFilterMapLastBlocks(db ethdb.KeyValueStore, maps common.Range[uint32], hashScheme bool, stopCallback func(bool) bool) error { + return SafeDeleteRange(db, filterMapLastBlockKey(maps.First()), filterMapLastBlockKey(maps.AfterLast()), hashScheme, stopCallback) } // ReadBlockLvPointer retrieves the starting log value index where the log values @@ -408,7 +404,7 @@ func ReadBlockLvPointer(db ethdb.KeyValueReader, blockNumber uint64) (uint64, er return 0, err } if len(encPtr) != 8 { - return 0, errors.New("Invalid log value pointer encoding") + return 0, errors.New("invalid log value pointer encoding") } return binary.BigEndian.Uint64(encPtr), nil } @@ -431,10 +427,8 @@ func DeleteBlockLvPointer(db ethdb.KeyValueWriter, blockNumber uint64) { } } -func DeleteBlockLvPointers(db ethdb.KeyValueRangeDeleter, blocks common.Range[uint64]) { - if err := db.DeleteRange(filterMapBlockLVKey(blocks.First()), filterMapBlockLVKey(blocks.AfterLast())); err != nil { - log.Crit("Failed to delete range of block log value pointers", "err", err) - } +func DeleteBlockLvPointers(db ethdb.KeyValueStore, blocks common.Range[uint64], hashScheme bool, stopCallback func(bool) bool) error { + return SafeDeleteRange(db, filterMapBlockLVKey(blocks.First()), filterMapBlockLVKey(blocks.AfterLast()), hashScheme, stopCallback) } // FilterMapsRange is a storage representation of the block range covered by the @@ -485,22 +479,22 @@ func DeleteFilterMapsRange(db ethdb.KeyValueWriter) { } // deletePrefixRange deletes everything with the given prefix from the database. -func deletePrefixRange(db ethdb.KeyValueRangeDeleter, prefix []byte) error { +func deletePrefixRange(db ethdb.KeyValueStore, prefix []byte, hashScheme bool, stopCallback func(bool) bool) error { end := bytes.Clone(prefix) end[len(end)-1]++ - return db.DeleteRange(prefix, end) + return SafeDeleteRange(db, prefix, end, hashScheme, stopCallback) } // DeleteFilterMapsDb removes the entire filter maps database -func DeleteFilterMapsDb(db ethdb.KeyValueRangeDeleter) error { - return deletePrefixRange(db, []byte(filterMapsPrefix)) +func DeleteFilterMapsDb(db ethdb.KeyValueStore, hashScheme bool, stopCallback func(bool) bool) error { + return deletePrefixRange(db, []byte(filterMapsPrefix), hashScheme, stopCallback) } -// DeleteFilterMapsDb removes the old bloombits database and the associated +// DeleteBloomBitsDb removes the old bloombits database and the associated // chain indexer database. -func DeleteBloomBitsDb(db ethdb.KeyValueRangeDeleter) error { - if err := deletePrefixRange(db, bloomBitsPrefix); err != nil { +func DeleteBloomBitsDb(db ethdb.KeyValueStore, hashScheme bool, stopCallback func(bool) bool) error { + if err := deletePrefixRange(db, bloomBitsPrefix, hashScheme, stopCallback); err != nil { return err } - return deletePrefixRange(db, bloomBitsMetaPrefix) + return deletePrefixRange(db, bloomBitsMetaPrefix, hashScheme, stopCallback) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 553724a48..466286675 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -28,12 +28,15 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/olekukonko/tablewriter" ) +var ErrDeleteRangeInterrupted = errors.New("safe delete range operation interrupted") + // freezerdb is a database wrapper that enables ancient chain segment freezing. type freezerdb struct { ethdb.KeyValueStore @@ -607,3 +610,73 @@ func ReadChainMetadata(db ethdb.KeyValueStore) [][]string { } return data } + +// SafeDeleteRange deletes all of the keys (and values) in the range +// [start,end) (inclusive on start, exclusive on end). +// If hashScheme is true then it always uses an iterator and skips hashdb trie +// node entries. If it is false and the backing db is pebble db then it uses +// the fast native range delete. +// In case of fallback mode (hashdb or leveldb) the range deletion might be +// very slow depending on the number of entries. In this case stopCallback +// is periodically called and if it returns an error then SafeDeleteRange +// stops and also returns that error. The callback is not called if native +// range delete is used or there are a small number of keys only. The bool +// argument passed to the callback is true if enrties have actually been +// deleted already. +func SafeDeleteRange(db ethdb.KeyValueStore, start, end []byte, hashScheme bool, stopCallback func(bool) bool) error { + if !hashScheme { + // delete entire range; use fast native range delete on pebble db + for { + switch err := db.DeleteRange(start, end); { + case err == nil: + return nil + case errors.Is(err, ethdb.ErrTooManyKeys): + if stopCallback(true) { + return ErrDeleteRangeInterrupted + } + default: + return err + } + } + } + + var ( + count, deleted, skipped int + buff = crypto.NewKeccakState() + startTime = time.Now() + ) + + batch := db.NewBatch() + it := db.NewIterator(nil, start) + defer func() { + it.Release() // it might be replaced during the process + log.Debug("SafeDeleteRange finished", "deleted", deleted, "skipped", skipped, "elapsed", common.PrettyDuration(time.Since(startTime))) + }() + + for it.Next() && bytes.Compare(end, it.Key()) > 0 { + // Prevent deletion for trie nodes in hash mode + if len(it.Key()) != 32 || crypto.HashData(buff, it.Value()) != common.BytesToHash(it.Key()) { + if err := batch.Delete(it.Key()); err != nil { + return err + } + deleted++ + } else { + skipped++ + } + count++ + if count > 10000 { // should not block for more than a second + if err := batch.Write(); err != nil { + return err + } + if stopCallback(deleted != 0) { + return ErrDeleteRangeInterrupted + } + start = append(bytes.Clone(it.Key()), 0) // appending a zero gives us the next possible key + it.Release() + batch = db.NewBatch() + it = db.NewIterator(nil, start) + count = 0 + } + } + return batch.Write() +} diff --git a/eth/backend.go b/eth/backend.go index cf202f52e..5c129c0e0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -258,7 +258,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - fmConfig := filtermaps.Config{History: config.LogHistory, Disabled: config.LogNoHistory, ExportFileName: config.LogExportCheckpoints} + fmConfig := filtermaps.Config{ + History: config.LogHistory, + Disabled: config.LogNoHistory, + ExportFileName: config.LogExportCheckpoints, + HashScheme: scheme == rawdb.HashScheme, + } chainView := eth.newChainView(eth.blockchain.CurrentBlock()) historyCutoff := eth.blockchain.HistoryPruningCutoff() var finalBlock uint64 diff --git a/ethdb/database.go b/ethdb/database.go index b1577512f..f2d458b85 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -17,7 +17,10 @@ // Package ethdb defines the interfaces for an Ethereum data store. package ethdb -import "io" +import ( + "errors" + "io" +) // KeyValueReader wraps the Has and Get method of a backing data store. type KeyValueReader interface { @@ -37,10 +40,14 @@ type KeyValueWriter interface { Delete(key []byte) error } +var ErrTooManyKeys = errors.New("too many keys in deleted range") + // KeyValueRangeDeleter wraps the DeleteRange method of a backing data store. type KeyValueRangeDeleter interface { // DeleteRange deletes all of the keys (and values) in the range [start,end) // (inclusive on start, exclusive on end). + // Some implementations of DeleteRange may return ErrTooManyKeys after + // partially deleting entries in the given range. DeleteRange(start, end []byte) error } diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 7f47523b8..ef02e9182 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -207,8 +207,6 @@ func (db *Database) Delete(key []byte) error { return db.db.Delete(key, nil) } -var ErrTooManyKeys = errors.New("too many keys in deleted range") - // DeleteRange deletes all of the keys (and values) in the range [start,end) // (inclusive on start, exclusive on end). // Note that this is a fallback implementation as leveldb does not natively @@ -228,7 +226,7 @@ func (db *Database) DeleteRange(start, end []byte) error { if err := batch.Write(); err != nil { return err } - return ErrTooManyKeys + return ethdb.ErrTooManyKeys } if err := batch.Delete(it.Key()); err != nil { return err From a15b4f0de2094d9e29a5fa8b6a5f4ab31eedcc49 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 31 Mar 2025 18:27:43 +0200 Subject: [PATCH 258/354] .travis.yml: remove macos build --- .travis.yml | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e8a493d0..43f8ced19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,6 @@ language: go go_import_path: github.com/ethereum/go-ethereum sudo: false jobs: - allow_failures: - - stage: build - os: osx - env: - - azure-osx - include: # This builder create and push the Docker images for all architectures - stage: build @@ -62,23 +56,6 @@ jobs: - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - # This builder does the OSX Azure uploads - - stage: build - if: type = push - os: osx - osx_image: xcode14.2 - go: 1.23.1 # See https://github.com/ethereum/go-ethereum/pull/30478 - env: - - azure-osx - git: - submodules: false # avoid cloning ethereum/tests - script: - - ln -sf /Users/travis/gopath/bin/go1.23.1 /usr/local/bin/go # Work around travis go-setup bug - - go run build/ci.go install -dlgo - - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - go run build/ci.go install -dlgo -arch arm64 - - go run build/ci.go archive -arch arm64 -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - # These builders run the tests - stage: build if: type = push From cc830643108ce8fb8a54b2795c736cda9dc0bfee Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:42:01 +0200 Subject: [PATCH 259/354] eth, eth/filters: implement API error code for pruned blocks (#31361) Implements #31275 --------- Co-authored-by: Jared Wasinger Co-authored-by: Felix Lange --- core/blockchain_reader.go | 5 ++ eth/api_backend.go | 46 ++++++++++++++++--- eth/ethconfig/historymode.go | 6 +++ eth/filters/api.go | 5 ++ eth/filters/filter.go | 20 ++++++-- eth/filters/filter_system.go | 10 ++++ eth/filters/filter_system_test.go | 4 ++ internal/ethapi/api.go | 58 +++++++++++++----------- internal/ethapi/api_test.go | 7 +++ internal/ethapi/backend.go | 1 + internal/ethapi/transaction_args_test.go | 2 + rpc/types.go | 2 +- 12 files changed, 128 insertions(+), 38 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index f8c79c229..f27711dad 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -103,6 +103,11 @@ func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { return bc.hc.GetHeaderByNumber(number) } +// GetBlockNumber retrieves the block number associated with a block hash. +func (bc *BlockChain) GetBlockNumber(hash common.Hash) *uint64 { + return bc.hc.GetBlockNumber(hash) +} + // GetHeadersFrom returns a contiguous segment of headers, in rlp-form, going // backwards from the given number. func (bc *BlockChain) GetHeadersFrom(number, count uint64) []rlp.RawValue { diff --git a/eth/api_backend.go b/eth/api_backend.go index 7d120be4c..0a931108b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" @@ -93,7 +94,13 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb } return block, nil } - return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil + var bn uint64 + if number == rpc.EarliestBlockNumber { + bn = b.eth.blockchain.HistoryPruningCutoff() + } else { + bn = uint64(number) + } + return b.eth.blockchain.GetHeaderByNumber(bn), nil } func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { @@ -145,11 +152,27 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe } return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } - return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil + bn := uint64(number) // the resolved number + if number == rpc.EarliestBlockNumber { + bn = b.eth.blockchain.HistoryPruningCutoff() + } + block := b.eth.blockchain.GetBlockByNumber(bn) + if block == nil && bn < b.eth.blockchain.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } + return block, nil } func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return b.eth.blockchain.GetBlockByHash(hash), nil + number := b.eth.blockchain.GetBlockNumber(hash) + if number == nil { + return nil, nil + } + block := b.eth.blockchain.GetBlock(hash, *number) + if block == nil && *number < b.eth.blockchain.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } + return block, nil } // GetBody returns body of a block. It does not resolve special block numbers. @@ -157,10 +180,14 @@ func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rp if number < 0 || hash == (common.Hash{}) { return nil, errors.New("invalid arguments; expect hash and no special block numbers") } - if body := b.eth.blockchain.GetBody(hash); body != nil { - return body, nil + body := b.eth.blockchain.GetBody(hash) + if body == nil { + if uint64(number) < b.eth.blockchain.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } + return nil, errors.New("block body not found") } - return nil, errors.New("block body not found") + return body, nil } func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { @@ -177,6 +204,9 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r } block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64()) if block == nil { + if header.Number.Uint64() < b.eth.blockchain.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } return nil, errors.New("header found, but block body is missing") } return block, nil @@ -236,6 +266,10 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } +func (b *EthAPIBackend) HistoryPruningCutoff() uint64 { + return b.eth.blockchain.HistoryPruningCutoff() +} + func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return b.eth.blockchain.GetReceiptsByHash(hash), nil } diff --git a/eth/ethconfig/historymode.go b/eth/ethconfig/historymode.go index c3661004e..a595d72fe 100644 --- a/eth/ethconfig/historymode.go +++ b/eth/ethconfig/historymode.go @@ -90,3 +90,9 @@ var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{ BlockHash: common.HexToHash("0x229f6b18ca1552f1d5146deceb5387333f40dc6275aebee3f2c5c4ece07d02db"), }, } + +// PrunedHistoryError is returned when the requested history is pruned. +type PrunedHistoryError struct{} + +func (e *PrunedHistoryError) Error() string { return "pruned history unavailable" } +func (e *PrunedHistoryError) ErrorCode() int { return 4444 } diff --git a/eth/filters/api.go b/eth/filters/api.go index b39d0c52f..d432874c1 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -432,9 +433,13 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type if crit.ToBlock != nil { end = crit.ToBlock.Int64() } + // Block numbers below 0 are special cases. if begin > 0 && end > 0 && begin > end { return nil, errInvalidBlockRange } + if begin > 0 && begin < int64(api.events.backend.HistoryPruningCutoff()) { + return nil, ðconfig.PrunedHistoryError{} + } // Construct the range filter filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index b743c2599..e44b37d04 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" ) @@ -86,6 +87,9 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, errors.New("unknown block") } + if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } return f.blockLogs(ctx, header) } @@ -114,11 +118,19 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return 0, errors.New("safe header not found") } return hdr.Number.Uint64(), nil + case rpc.EarliestBlockNumber.Int64(): + earliest := f.sys.backend.HistoryPruningCutoff() + hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(earliest)) + if hdr == nil { + return 0, errors.New("earliest header not found") + } + return hdr.Number.Uint64(), nil + default: + if number < 0 { + return 0, errors.New("negative block number") + } + return uint64(number), nil } - if number < 0 { - return 0, errors.New("negative block number") - } - return uint64(number), nil } // range query need to resolve the special begin/end block number diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 4b2c3d83c..90a392169 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -65,6 +66,7 @@ type Backend interface { CurrentHeader() *types.Header ChainConfig() *params.ChainConfig + HistoryPruningCutoff() uint64 SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription @@ -319,6 +321,14 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ return nil, errPendingLogsUnsupported } + if from == rpc.EarliestBlockNumber { + from = rpc.BlockNumber(es.backend.HistoryPruningCutoff()) + } + // Queries beyond the pruning cutoff are not supported. + if uint64(from) < es.backend.HistoryPruningCutoff() { + return nil, ðconfig.PrunedHistoryError{} + } + // only interested in new mined logs if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index a0af3856e..8c4eb093c 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -192,6 +192,10 @@ func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) { b.pendingReceipts = receipts } +func (b *testBackend) HistoryPruningCutoff() uint64 { + return 0 +} + func newTestFilterSystem(db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { backend := &testBackend{db: db} sys := NewFilterSystem(backend, cfg) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b3288106f..5a44ff183 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -625,21 +625,23 @@ func (api *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, block } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) { + block, err := api.b.BlockByNumber(ctx, blockNr) + if block != nil { n := hexutil.Uint(len(block.Uncles())) - return &n + return &n, nil } - return nil + return nil, err } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error) { + block, err := api.b.BlockByHash(ctx, blockHash) + if block != nil { n := hexutil.Uint(len(block.Uncles())) - return &n + return &n, nil } - return nil + return nil, err } // GetCode returns the code stored at the given address in the state for the given block number. @@ -672,9 +674,7 @@ func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Addre func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) if block == nil || err != nil { - // When the block doesn't exist, the RPC method should return JSON null - // as per specification. - return nil, nil + return nil, err } receipts, err := api.b.GetReceipts(ctx, block.Hash()) if err != nil { @@ -1368,37 +1368,41 @@ func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI { } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) { + block, err := api.b.BlockByNumber(ctx, blockNr) + if block != nil { n := hexutil.Uint(len(block.Transactions())) - return &n + return &n, nil } - return nil + return nil, err } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error) { + block, err := api.b.BlockByHash(ctx, blockHash) + if block != nil { n := hexutil.Uint(len(block.Transactions())) - return &n + return &n, nil } - return nil + return nil, err } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { - if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (*RPCTransaction, error) { + block, err := api.b.BlockByNumber(ctx, blockNr) + if block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()), nil } - return nil + return nil, err } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { - if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (*RPCTransaction, error) { + block, err := api.b.BlockByHash(ctx, blockHash) + if block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()), nil } - return nil + return nil, err } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 79363598b..b43e86d8b 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -526,8 +526,12 @@ func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) if number == rpc.PendingBlockNumber { return b.pending, nil } + if number == rpc.EarliestBlockNumber { + number = 0 + } return b.chain.GetBlockByNumber(uint64(number)), nil } + func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { return b.chain.GetBlockByHash(hash), nil } @@ -636,6 +640,9 @@ func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscripti func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { panic("implement me") } + +func (b testBackend) HistoryPruningCutoff() uint64 { return b.chain.HistoryPruningCutoff() } + func TestEstimateGas(t *testing.T) { t.Parallel() // Initialize test accounts diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 19f6028ac..f11fcc858 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -88,6 +88,7 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine + HistoryPruningCutoff() uint64 // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 83b3523eb..fea99359a 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -415,3 +415,5 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) func (b *backendMock) Engine() consensus.Engine { return nil } func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil } + +func (b *backendMock) HistoryPruningCutoff() uint64 { return 0 } diff --git a/rpc/types.go b/rpc/types.go index 2e53174b8..85f15344e 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -63,11 +63,11 @@ type jsonWriter interface { type BlockNumber int64 const ( + EarliestBlockNumber = BlockNumber(-5) SafeBlockNumber = BlockNumber(-4) FinalizedBlockNumber = BlockNumber(-3) LatestBlockNumber = BlockNumber(-2) PendingBlockNumber = BlockNumber(-1) - EarliestBlockNumber = BlockNumber(0) ) // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: From cabc3a4b61b18d0dab79ebb7bed5ec1b50216b88 Mon Sep 17 00:00:00 2001 From: John <33443230+gazzua@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:07:47 +0900 Subject: [PATCH 260/354] p2p/nat: improve AddMapping code (#31486) It introduces a new variable to store the external port returned by the addAnyPortMapping function and ensures that the correct external port is returned even in case of an error. --------- Co-authored-by: Felix Lange --- p2p/nat/natupnp.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index f1bb95589..1014dc69d 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -82,7 +82,7 @@ func (n *upnp) ExternalIP() (addr net.IP, err error) { func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, lifetime time.Duration) (uint16, error) { ip, err := n.internalAddress() if err != nil { - return 0, nil // TODO: Shouldn't we return the error? + return 0, err } protocol = strings.ToUpper(protocol) lifetimeS := uint32(lifetime / time.Second) @@ -94,14 +94,15 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li if err == nil { return uint16(extport), nil } - - return uint16(extport), n.withRateLimit(func() error { + // Try addAnyPortMapping if mapping specified port didn't work. + err = n.withRateLimit(func() error { p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) if err == nil { extport = int(p) } return err }) + return uint16(extport), err } func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) { From a4cb1624f10e3296ee49f53f45e16bdda2c6c8d0 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 1 Apr 2025 20:10:22 +0800 Subject: [PATCH 261/354] cmd: apply snapshot cache flag in the MakeChain (#31534) --- cmd/utils/flags.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a589baf8d..cc400865e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2364,6 +2364,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } if !ctx.Bool(SnapshotFlag.Name) { cache.SnapshotLimit = 0 // Disabled + } else if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheSnapshotFlag.Name) { + cache.SnapshotLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheSnapshotFlag.Name) / 100 } // If we're in readonly, do not bother generating snapshot data. if readonly { From 0aa55bb33c54b20d5a1fc421ea13f99f3c7c2584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Tue, 1 Apr 2025 14:29:20 +0200 Subject: [PATCH 262/354] core/filtermaps: add metrics (#31511) This PR adds metrics related to map rendering and pattern matching to the `core/filtermaps` package. --- core/filtermaps/filtermaps.go | 21 +++++++++++++++++++++ core/filtermaps/map_renderer.go | 22 +++++++++++++++++++++- core/filtermaps/matcher.go | 12 ++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index 5722f17da..18b1c7dc7 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -30,6 +30,23 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +var ( + mapCountGauge = metrics.NewRegisteredGauge("filtermaps/maps/count", nil) // actual number of rendered maps + mapLogValueMeter = metrics.NewRegisteredMeter("filtermaps/maps/logvalues", nil) // number of log values processed + mapBlockMeter = metrics.NewRegisteredMeter("filtermaps/maps/blocks", nil) // number of block delimiters processed + mapRenderTimer = metrics.NewRegisteredTimer("filtermaps/maps/rendertime", nil) // time elapsed while rendering a single map + mapWriteTimer = metrics.NewRegisteredTimer("filtermaps/maps/writetime", nil) // time elapsed while writing a batch of finished maps to db + matchRequestTimer = metrics.NewRegisteredTimer("filtermaps/match/requesttime", nil) // processing time a matching request in a single epoch + matchEpochTimer = metrics.NewRegisteredTimer("filtermaps/match/epochtime", nil) // total processing time a matching request + matchBaseRowAccessMeter = metrics.NewRegisteredMeter("filtermaps/match/baserowaccess", nil) // number of accessed rows on layer 0 + matchBaseRowSizeMeter = metrics.NewRegisteredMeter("filtermaps/match/baserowsize", nil) // size of accessed rows on layer 0 + matchExtRowAccessMeter = metrics.NewRegisteredMeter("filtermaps/match/extrowaccess", nil) // number of accessed rows on higher layers + matchExtRowSizeMeter = metrics.NewRegisteredMeter("filtermaps/match/extrowsize", nil) // size of accessed rows on higher layers + matchLogLookup = metrics.NewRegisteredMeter("filtermaps/match/loglookup", nil) // number of log lookups based on potential matches + matchAllMeter = metrics.NewRegisteredMeter("filtermaps/match/matchall", nil) // number of requests returned with ErrMatchAll ) const ( @@ -429,8 +446,12 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne TailPartialEpoch: newRange.tailPartialEpoch, } rawdb.WriteFilterMapsRange(batch, rs) + if !isTempRange { + mapCountGauge.Update(int64(newRange.maps.Count() + newRange.tailPartialEpoch)) + } } else { rawdb.DeleteFilterMapsRange(batch) + mapCountGauge.Update(0) } } diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 1eaaa9bb1..28f943abb 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -21,6 +21,7 @@ import ( "fmt" "math" "sort" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" @@ -301,6 +302,11 @@ func (r *mapRenderer) run(stopCb func() bool, writeCb func()) (bool, error) { // renderCurrentMap renders a single map. func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { + var ( + totalTime time.Duration + logValuesProcessed, blocksProcessed int64 + ) + start := time.Now() if !r.iterator.updateChainView(r.f.targetView) { return false, errChainUpdate } @@ -316,9 +322,11 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { for r.iterator.lvIndex < uint64(r.currentMap.mapIndex+1)<= valuesPerCallback { + totalTime += time.Since(start) if stopCb() { return false, nil } + start = time.Now() if !r.iterator.updateChainView(r.f.targetView) { return false, errChainUpdate } @@ -343,8 +351,10 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { return false, fmt.Errorf("failed to advance log iterator at %d while rendering map %d: %v", r.iterator.lvIndex, r.currentMap.mapIndex, err) } if !r.iterator.skipToBoundary { + logValuesProcessed++ r.currentMap.lastBlock = r.iterator.blockNumber if r.iterator.blockStart { + blocksProcessed++ r.currentMap.blockLvPtrs = append(r.currentMap.blockLvPtrs, r.iterator.lvIndex) } if !r.f.testDisableSnapshots && r.renderBefore >= r.f.indexedRange.maps.AfterLast() && @@ -358,12 +368,18 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { r.currentMap.headDelimiter = r.iterator.lvIndex } r.currentMap.lastBlockId = r.f.targetView.getBlockId(r.currentMap.lastBlock) + totalTime += time.Since(start) + mapRenderTimer.Update(totalTime) + mapLogValueMeter.Mark(logValuesProcessed) + mapBlockMeter.Mark(blocksProcessed) return true, nil } // writeFinishedMaps writes rendered maps to the database and updates // filterMapsRange and indexedView accordingly. func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { + var totalTime time.Duration + start := time.Now() if len(r.finishedMaps) == 0 { return nil } @@ -379,7 +395,7 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { if err != nil { return fmt.Errorf("failed to get updated rendered range: %v", err) } - renderedView := r.f.targetView // stopCb callback might still change targetView while writing finished maps + renderedView := r.f.targetView // pauseCb callback might still change targetView while writing finished maps batch := r.f.db.NewBatch() var writeCnt int @@ -393,7 +409,9 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { // do not exit while in partially written state but do allow processing // events and pausing while block processing is in progress r.f.indexLock.Unlock() + totalTime += time.Since(start) pauseCb() + start = time.Now() r.f.indexLock.Lock() batch = r.f.db.NewBatch() } @@ -477,6 +495,8 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { if err := batch.Write(); err != nil { log.Crit("Error writing log index update batch", "error", err) } + totalTime += time.Since(start) + mapWriteTimer.Update(totalTime) return nil } diff --git a/core/filtermaps/matcher.go b/core/filtermaps/matcher.go index 6c05672cb..5738bf166 100644 --- a/core/filtermaps/matcher.go +++ b/core/filtermaps/matcher.go @@ -125,6 +125,7 @@ func GetPotentialMatches(ctx context.Context, backend MatcherBackend, firstBlock start := time.Now() res, err := m.process() + matchRequestTimer.Update(time.Since(start)) if doRuntimeStats { log.Info("Log search finished", "elapsed", time.Since(start)) @@ -202,6 +203,7 @@ func (m *matcherEnv) process() ([]*types.Log, error) { logs = append(logs, tasks[waitEpoch].logs...) if err := tasks[waitEpoch].err; err != nil { if err == ErrMatchAll { + matchAllMeter.Mark(1) return logs, err } return logs, fmt.Errorf("failed to process log index epoch %d: %v", waitEpoch, err) @@ -220,6 +222,7 @@ func (m *matcherEnv) process() ([]*types.Log, error) { // processEpoch returns the potentially matching logs from the given epoch. func (m *matcherEnv) processEpoch(epochIndex uint32) ([]*types.Log, error) { + start := time.Now() var logs []*types.Log // create a list of map indices to process fm, lm := epochIndex< Date: Tue, 1 Apr 2025 22:13:37 +0800 Subject: [PATCH 263/354] accounts/abi/abigen: fix a flaky bind test case `NewSingleStructArgument` (#31501) found the failed testcase here https://ci.appveyor.com/project/ethereum/go-ethereum/builds/51767091/job/rbjke432c05pufja add a timeout to wait the tx to be mined. --------- Signed-off-by: jsvisa Co-authored-by: Jared Wasinger --- accounts/abi/abigen/bind_test.go | 55 ++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/accounts/abi/abigen/bind_test.go b/accounts/abi/abigen/bind_test.go index 387156091..195064fb7 100644 --- a/accounts/abi/abigen/bind_test.go +++ b/accounts/abi/abigen/bind_test.go @@ -541,7 +541,7 @@ var bindTests = []struct { struct A { bytes32 B; } - + function F() public view returns (A[] memory a, uint256[] memory c, bool[] memory d) { A[] memory a = new A[](2); a[0].B = bytes32(uint256(1234) << 96); @@ -549,7 +549,7 @@ var bindTests = []struct { bool[] memory d; return (a, c, d); } - + function G() public view returns (A[] memory a) { A[] memory a = new A[](2); a[0].B = bytes32(uint256(1234) << 96); @@ -571,10 +571,10 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - + sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000) defer sim.Close() - + // Deploy a structs method invoker contract and execute its default method _, _, structs, err := DeployStructs(auth, sim) if err != nil { @@ -1701,13 +1701,13 @@ var bindTests = []struct { `NewFallbacks`, ` pragma solidity >=0.6.0 <0.7.0; - + contract NewFallbacks { event Fallback(bytes data); fallback() external { emit Fallback(msg.data); } - + event Received(address addr, uint value); receive() external payable { emit Received(msg.sender, msg.value); @@ -1719,7 +1719,7 @@ var bindTests = []struct { ` "bytes" "math/big" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/core/types" @@ -1728,22 +1728,22 @@ var bindTests = []struct { ` key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) - + sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 1000000) defer sim.Close() - + opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) _, _, c, err := DeployNewFallbacks(opts, sim) if err != nil { t.Fatalf("Failed to deploy contract: %v", err) } sim.Commit() - + // Test receive function opts.Value = big.NewInt(100) c.Receive(opts) sim.Commit() - + var gotEvent bool iter, _ := c.FilterReceived(nil) defer iter.Close() @@ -1760,14 +1760,14 @@ var bindTests = []struct { if !gotEvent { t.Fatal("Expect to receive event emitted by receive") } - + // Test fallback function gotEvent = false opts.Value = nil calldata := []byte{0x01, 0x02, 0x03} c.Fallback(opts, calldata) sim.Commit() - + iter2, _ := c.FilterFallback(nil) defer iter2.Close() for iter2.Next() { @@ -1806,7 +1806,9 @@ var bindTests = []struct { []string{"608060405234801561001057600080fd5b50610113806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806324ec1d3f14602d575b600080fd5b60336035565b005b7fb4b2ff75e30cb4317eaae16dd8a187dd89978df17565104caa6c2797caae27d460405180604001604052806001815260200160028152506040516078919060ba565b60405180910390a1565b6040820160008201516096600085018260ad565b50602082015160a7602085018260ad565b50505050565b60b48160d3565b82525050565b600060408201905060cd60008301846082565b92915050565b600081905091905056fea26469706673582212208823628796125bf9941ce4eda18da1be3cf2931b231708ab848e1bd7151c0c9a64736f6c63430008070033"}, []string{`[{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"indexed":false,"internalType":"struct Test.MyStruct","name":"s","type":"tuple"}],"name":"StructEvent","type":"event"},{"inputs":[],"name":"TestEvent","outputs":[],"stateMutability":"nonpayable","type":"function"}]`}, ` + "context" "math/big" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" @@ -1828,12 +1830,23 @@ var bindTests = []struct { } sim.Commit() - _, err = d.TestEvent(user) + tx, err := d.TestEvent(user) if err != nil { t.Fatalf("Failed to call contract %v", err) } sim.Commit() + // Wait for the transaction to be mined + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + receipt, err := bind.WaitMined(ctx, sim, tx) + if err != nil { + t.Fatalf("Failed to wait for tx to be mined: %v", err) + } + if receipt.Status != types.ReceiptStatusSuccessful { + t.Fatal("Transaction failed") + } + it, err := d.FilterStructEvent(nil) if err != nil { t.Fatalf("Failed to filter contract event %v", err) @@ -1862,7 +1875,7 @@ var bindTests = []struct { `NewErrors`, ` pragma solidity >0.8.4; - + contract NewErrors { error MyError(uint256); error MyError1(uint256); @@ -1878,7 +1891,7 @@ var bindTests = []struct { ` "context" "math/big" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/core/types" @@ -1892,7 +1905,7 @@ var bindTests = []struct { sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil) ) defer sim.Close() - + _, tx, contract, err := DeployNewErrors(user, sim) if err != nil { t.Fatal(err) @@ -1917,12 +1930,12 @@ var bindTests = []struct { name: `ConstructorWithStructParam`, contract: ` pragma solidity >=0.8.0 <0.9.0; - + contract ConstructorWithStructParam { struct StructType { uint256 field; } - + constructor(StructType memory st) {} } `, @@ -1951,7 +1964,7 @@ var bindTests = []struct { t.Fatalf("DeployConstructorWithStructParam() got err %v; want nil err", err) } sim.Commit() - + if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil { t.Logf("Deployment tx: %+v", tx) t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) @@ -2000,7 +2013,7 @@ var bindTests = []struct { t.Fatalf("DeployNameConflict() got err %v; want nil err", err) } sim.Commit() - + if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil { t.Logf("Deployment tx: %+v", tx) t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) From 9c566eb8bc067d04e619040f7d43496845898a45 Mon Sep 17 00:00:00 2001 From: Ng Wei Han <47109095+weiihann@users.noreply.github.com> Date: Wed, 2 Apr 2025 15:06:54 +0800 Subject: [PATCH 264/354] triedb/pathdb: improve perf by separating nodes map (#31306) This PR refactors the `nodeSet` structure in the path database to use separate maps for account and storage trie nodes, resulting in performance improvements. The change maintains the same API while optimizing the internal data structure. --- triedb/pathdb/nodes.go | 193 ++++++++++++++++++++++++++--------------- 1 file changed, 125 insertions(+), 68 deletions(-) diff --git a/triedb/pathdb/nodes.go b/triedb/pathdb/nodes.go index c56e38066..f90bd0f01 100644 --- a/triedb/pathdb/nodes.go +++ b/triedb/pathdb/nodes.go @@ -36,8 +36,9 @@ import ( // transition, typically corresponding to a block execution. It can also represent // the combined trie node set from several aggregated state transitions. type nodeSet struct { - size uint64 // aggregated size of the trie node - nodes map[common.Hash]map[string]*trienode.Node // node set, mapped by owner and path + size uint64 // aggregated size of the trie node + accountNodes map[string]*trienode.Node // account trie nodes, mapped by path + storageNodes map[common.Hash]map[string]*trienode.Node // storage trie nodes, mapped by owner and path } // newNodeSet constructs the set with the provided dirty trie nodes. @@ -46,7 +47,17 @@ func newNodeSet(nodes map[common.Hash]map[string]*trienode.Node) *nodeSet { if nodes == nil { nodes = make(map[common.Hash]map[string]*trienode.Node) } - s := &nodeSet{nodes: nodes} + s := &nodeSet{ + accountNodes: make(map[string]*trienode.Node), + storageNodes: make(map[common.Hash]map[string]*trienode.Node), + } + for owner, subset := range nodes { + if owner == (common.Hash{}) { + s.accountNodes = subset + } else { + s.storageNodes[owner] = subset + } + } s.computeSize() return s } @@ -54,13 +65,12 @@ func newNodeSet(nodes map[common.Hash]map[string]*trienode.Node) *nodeSet { // computeSize calculates the database size of the held trie nodes. func (s *nodeSet) computeSize() { var size uint64 - for owner, subset := range s.nodes { - var prefix int - if owner != (common.Hash{}) { - prefix = common.HashLength // owner (32 bytes) for storage trie nodes - } + for path, n := range s.accountNodes { + size += uint64(len(n.Blob) + len(path)) + } + for _, subset := range s.storageNodes { for path, n := range subset { - size += uint64(prefix + len(n.Blob) + len(path)) + size += uint64(common.HashLength + len(n.Blob) + len(path)) } } s.size = size @@ -79,15 +89,18 @@ func (s *nodeSet) updateSize(delta int64) { // node retrieves the trie node with node path and its trie identifier. func (s *nodeSet) node(owner common.Hash, path []byte) (*trienode.Node, bool) { - subset, ok := s.nodes[owner] - if !ok { - return nil, false + // Account trie node + if owner == (common.Hash{}) { + n, ok := s.accountNodes[string(path)] + return n, ok } - n, ok := subset[string(path)] + // Storage trie node + subset, ok := s.storageNodes[owner] if !ok { return nil, false } - return n, true + n, ok := subset[string(path)] + return n, ok } // merge integrates the provided dirty nodes into the set. The provided nodeset @@ -97,15 +110,24 @@ func (s *nodeSet) merge(set *nodeSet) { delta int64 // size difference resulting from node merging overwrite counter // counter of nodes being overwritten ) - for owner, subset := range set.nodes { - var prefix int - if owner != (common.Hash{}) { - prefix = common.HashLength + + // Merge account nodes + for path, n := range set.accountNodes { + if orig, exist := s.accountNodes[path]; !exist { + delta += int64(len(n.Blob) + len(path)) + } else { + delta += int64(len(n.Blob) - len(orig.Blob)) + overwrite.add(len(orig.Blob) + len(path)) } - current, exist := s.nodes[owner] + s.accountNodes[path] = n + } + + // Merge storage nodes + for owner, subset := range set.storageNodes { + current, exist := s.storageNodes[owner] if !exist { for path, n := range subset { - delta += int64(prefix + len(n.Blob) + len(path)) + delta += int64(common.HashLength + len(n.Blob) + len(path)) } // Perform a shallow copy of the map for the subset instead of claiming it // directly from the provided nodeset to avoid potential concurrent map @@ -113,19 +135,19 @@ func (s *nodeSet) merge(set *nodeSet) { // accessible even after merging. Therefore, ownership of the nodes map // should still belong to the original layer, and any modifications to it // should be prevented. - s.nodes[owner] = maps.Clone(subset) + s.storageNodes[owner] = maps.Clone(subset) continue } for path, n := range subset { if orig, exist := current[path]; !exist { - delta += int64(prefix + len(n.Blob) + len(path)) + delta += int64(common.HashLength + len(n.Blob) + len(path)) } else { delta += int64(len(n.Blob) - len(orig.Blob)) - overwrite.add(prefix + len(orig.Blob) + len(path)) + overwrite.add(common.HashLength + len(orig.Blob) + len(path)) } current[path] = n } - s.nodes[owner] = current + s.storageNodes[owner] = current } overwrite.report(gcTrieNodeMeter, gcTrieNodeBytesMeter) s.updateSize(delta) @@ -136,34 +158,38 @@ func (s *nodeSet) merge(set *nodeSet) { func (s *nodeSet) revertTo(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node) { var delta int64 for owner, subset := range nodes { - current, ok := s.nodes[owner] - if !ok { - panic(fmt.Sprintf("non-existent subset (%x)", owner)) - } - for path, n := range subset { - orig, ok := current[path] - if !ok { - // There is a special case in merkle tree that one child is removed - // from a fullNode which only has two children, and then a new child - // with different position is immediately inserted into the fullNode. - // In this case, the clean child of the fullNode will also be marked - // as dirty because of node collapse and expansion. In case of database - // rollback, don't panic if this "clean" node occurs which is not - // present in buffer. - var blob []byte - if owner == (common.Hash{}) { - blob = rawdb.ReadAccountTrieNode(db, []byte(path)) - } else { - blob = rawdb.ReadStorageTrieNode(db, owner, []byte(path)) + if owner == (common.Hash{}) { + // Account trie nodes + for path, n := range subset { + orig, ok := s.accountNodes[path] + if !ok { + blob := rawdb.ReadAccountTrieNode(db, []byte(path)) + if bytes.Equal(blob, n.Blob) { + continue + } + panic(fmt.Sprintf("non-existent account node (%v) blob: %v", path, crypto.Keccak256Hash(n.Blob).Hex())) } - // Ignore the clean node in the case described above. - if bytes.Equal(blob, n.Blob) { - continue + s.accountNodes[path] = n + delta += int64(len(n.Blob)) - int64(len(orig.Blob)) + } + } else { + // Storage trie nodes + current, ok := s.storageNodes[owner] + if !ok { + panic(fmt.Sprintf("non-existent subset (%x)", owner)) + } + for path, n := range subset { + orig, ok := current[path] + if !ok { + blob := rawdb.ReadStorageTrieNode(db, owner, []byte(path)) + if bytes.Equal(blob, n.Blob) { + continue + } + panic(fmt.Sprintf("non-existent storage node (%x %v) blob: %v", owner, path, crypto.Keccak256Hash(n.Blob).Hex())) } - panic(fmt.Sprintf("non-existent node (%x %v) blob: %v", owner, path, crypto.Keccak256Hash(n.Blob).Hex())) + current[path] = n + delta += int64(len(n.Blob)) - int64(len(orig.Blob)) } - current[path] = n - delta += int64(len(n.Blob)) - int64(len(orig.Blob)) } } s.updateSize(delta) @@ -184,8 +210,21 @@ type journalNodes struct { // encode serializes the content of trie nodes into the provided writer. func (s *nodeSet) encode(w io.Writer) error { - nodes := make([]journalNodes, 0, len(s.nodes)) - for owner, subset := range s.nodes { + nodes := make([]journalNodes, 0, len(s.storageNodes)+1) + + // Encode account nodes + if len(s.accountNodes) > 0 { + entry := journalNodes{Owner: common.Hash{}} + for path, node := range s.accountNodes { + entry.Nodes = append(entry.Nodes, journalNode{ + Path: []byte(path), + Blob: node.Blob, + }) + } + nodes = append(nodes, entry) + } + // Encode storage nodes + for owner, subset := range s.storageNodes { entry := journalNodes{Owner: owner} for path, node := range subset { entry.Nodes = append(entry.Nodes, journalNode{ @@ -204,43 +243,61 @@ func (s *nodeSet) decode(r *rlp.Stream) error { if err := r.Decode(&encoded); err != nil { return fmt.Errorf("load nodes: %v", err) } - nodes := make(map[common.Hash]map[string]*trienode.Node) + s.accountNodes = make(map[string]*trienode.Node) + s.storageNodes = make(map[common.Hash]map[string]*trienode.Node) + for _, entry := range encoded { - subset := make(map[string]*trienode.Node) - for _, n := range entry.Nodes { - if len(n.Blob) > 0 { - subset[string(n.Path)] = trienode.New(crypto.Keccak256Hash(n.Blob), n.Blob) - } else { - subset[string(n.Path)] = trienode.NewDeleted() + if entry.Owner == (common.Hash{}) { + // Account nodes + for _, n := range entry.Nodes { + if len(n.Blob) > 0 { + s.accountNodes[string(n.Path)] = trienode.New(crypto.Keccak256Hash(n.Blob), n.Blob) + } else { + s.accountNodes[string(n.Path)] = trienode.NewDeleted() + } + } + } else { + // Storage nodes + subset := make(map[string]*trienode.Node) + for _, n := range entry.Nodes { + if len(n.Blob) > 0 { + subset[string(n.Path)] = trienode.New(crypto.Keccak256Hash(n.Blob), n.Blob) + } else { + subset[string(n.Path)] = trienode.NewDeleted() + } } + s.storageNodes[entry.Owner] = subset } - nodes[entry.Owner] = subset } - s.nodes = nodes s.computeSize() return nil } // write flushes nodes into the provided database batch as a whole. func (s *nodeSet) write(batch ethdb.Batch, clean *fastcache.Cache) int { - return writeNodes(batch, s.nodes, clean) + nodes := make(map[common.Hash]map[string]*trienode.Node) + if len(s.accountNodes) > 0 { + nodes[common.Hash{}] = s.accountNodes + } + for owner, subset := range s.storageNodes { + nodes[owner] = subset + } + return writeNodes(batch, nodes, clean) } // reset clears all cached trie node data. func (s *nodeSet) reset() { - s.nodes = make(map[common.Hash]map[string]*trienode.Node) + s.accountNodes = make(map[string]*trienode.Node) + s.storageNodes = make(map[common.Hash]map[string]*trienode.Node) s.size = 0 } // dbsize returns the approximate size of db write. func (s *nodeSet) dbsize() int { var m int - for owner, nodes := range s.nodes { - if owner == (common.Hash{}) { - m += len(nodes) * len(rawdb.TrieNodeAccountPrefix) // database key prefix - } else { - m += len(nodes) * (len(rawdb.TrieNodeStoragePrefix)) // database key prefix - } + m += len(s.accountNodes) * len(rawdb.TrieNodeAccountPrefix) // database key prefix + for _, nodes := range s.storageNodes { + m += len(nodes) * (len(rawdb.TrieNodeStoragePrefix)) // database key prefix } return m + int(s.size) } From a17e838330951181040f9d5f240a4b1bef5a377a Mon Sep 17 00:00:00 2001 From: minh-bq Date: Wed, 2 Apr 2025 14:47:56 +0700 Subject: [PATCH 265/354] core/txpool: add GetMetadata to transaction pool (#31433) This is an alternative to #31309 With eth/68, transaction announcement must have transaction type and size. So in announceTransactions, we need to query the transaction from transaction pool with its hash. This creates overhead in case of blob transaction which needs to load data from billy and RLP decode. This commit creates a lightweight lookup from transaction hash to transaction size and a function GetMetadata to query transaction type and transaction size given the transaction hash. --------- Co-authored-by: Gary Rong --- core/txpool/blobpool/blobpool.go | 81 ++++++++++++++++---------- core/txpool/blobpool/blobpool_test.go | 12 +++- core/txpool/blobpool/evictheap_test.go | 8 +-- core/txpool/blobpool/lookup.go | 35 ++++++++--- core/txpool/legacypool/cachepool.go | 8 +++ core/txpool/legacypool/legacypool.go | 13 +++++ core/txpool/subpool.go | 10 ++++ core/txpool/txpool.go | 11 ++++ eth/handler.go | 4 ++ eth/handler_test.go | 16 +++++ eth/protocols/eth/broadcast.go | 6 +- eth/protocols/eth/handler.go | 5 ++ 12 files changed, 164 insertions(+), 45 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 45f5d738d..58e1a3068 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -87,8 +87,9 @@ type blobTxMeta struct { hash common.Hash // Transaction hash to maintain the lookup table vhashes []common.Hash // Blob versioned hashes to maintain the lookup table - id uint64 // Storage ID in the pool's persistent store - size uint32 // Byte size in the pool's persistent store + id uint64 // Storage ID in the pool's persistent store + storageSize uint32 // Byte size in the pool's persistent store + size uint64 // RLP-encoded size of transaction including the attached blob nonce uint64 // Needed to prioritize inclusion order within an account costCap *uint256.Int // Needed to validate cumulative balance sufficiency @@ -108,19 +109,20 @@ type blobTxMeta struct { // newBlobTxMeta retrieves the indexed metadata fields from a blob transaction // and assembles a helper struct to track in memory. -func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta { +func newBlobTxMeta(id uint64, size uint64, storageSize uint32, tx *types.Transaction) *blobTxMeta { meta := &blobTxMeta{ - hash: tx.Hash(), - vhashes: tx.BlobHashes(), - id: id, - size: size, - nonce: tx.Nonce(), - costCap: uint256.MustFromBig(tx.Cost()), - execTipCap: uint256.MustFromBig(tx.GasTipCap()), - execFeeCap: uint256.MustFromBig(tx.GasFeeCap()), - blobFeeCap: uint256.MustFromBig(tx.BlobGasFeeCap()), - execGas: tx.Gas(), - blobGas: tx.BlobGas(), + hash: tx.Hash(), + vhashes: tx.BlobHashes(), + id: id, + storageSize: storageSize, + size: size, + nonce: tx.Nonce(), + costCap: uint256.MustFromBig(tx.Cost()), + execTipCap: uint256.MustFromBig(tx.GasTipCap()), + execFeeCap: uint256.MustFromBig(tx.GasFeeCap()), + blobFeeCap: uint256.MustFromBig(tx.BlobGasFeeCap()), + execGas: tx.Gas(), + blobGas: tx.BlobGas(), } meta.basefeeJumps = dynamicFeeJumps(meta.execFeeCap) meta.blobfeeJumps = dynamicFeeJumps(meta.blobFeeCap) @@ -489,7 +491,7 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error { return errors.New("missing blob sidecar") } - meta := newBlobTxMeta(id, size, tx) + meta := newBlobTxMeta(id, tx.Size(), size, tx) if p.lookup.exists(meta.hash) { // This path is only possible after a crash, where deleted items are not // removed via the normal shutdown-startup procedure and thus may get @@ -516,7 +518,7 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error { p.spent[sender] = new(uint256.Int).Add(p.spent[sender], meta.costCap) p.lookup.track(meta) - p.stored += uint64(meta.size) + p.stored += uint64(meta.storageSize) return nil } @@ -548,7 +550,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 ids = append(ids, txs[i].id) nonces = append(nonces, txs[i].nonce) - p.stored -= uint64(txs[i].size) + p.stored -= uint64(txs[i].storageSize) p.lookup.untrack(txs[i]) // Included transactions blobs need to be moved to the limbo @@ -589,7 +591,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 nonces = append(nonces, txs[0].nonce) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[0].costCap) - p.stored -= uint64(txs[0].size) + p.stored -= uint64(txs[0].storageSize) p.lookup.untrack(txs[0]) // Included transactions blobs need to be moved to the limbo @@ -645,7 +647,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 dropRepeatedMeter.Mark(1) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) - p.stored -= uint64(txs[i].size) + p.stored -= uint64(txs[i].storageSize) p.lookup.untrack(txs[i]) if err := p.store.Delete(id); err != nil { @@ -667,7 +669,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 nonces = append(nonces, txs[j].nonce) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[j].costCap) - p.stored -= uint64(txs[j].size) + p.stored -= uint64(txs[j].storageSize) p.lookup.untrack(txs[j]) } txs = txs[:i] @@ -705,7 +707,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 nonces = append(nonces, last.nonce) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], last.costCap) - p.stored -= uint64(last.size) + p.stored -= uint64(last.storageSize) p.lookup.untrack(last) } if len(txs) == 0 { @@ -745,7 +747,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 nonces = append(nonces, last.nonce) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], last.costCap) - p.stored -= uint64(last.size) + p.stored -= uint64(last.storageSize) p.lookup.untrack(last) } p.index[addr] = txs @@ -1011,7 +1013,7 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error { } // Update the indices and metrics - meta := newBlobTxMeta(id, p.store.Size(id), tx) + meta := newBlobTxMeta(id, tx.Size(), p.store.Size(id), tx) if _, ok := p.index[addr]; !ok { if err := p.reserve(addr, true); err != nil { log.Warn("Failed to reserve account for blob pool", "tx", tx.Hash(), "from", addr, "err", err) @@ -1025,7 +1027,7 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error { p.spent[addr] = new(uint256.Int).Add(p.spent[addr], meta.costCap) } p.lookup.track(meta) - p.stored += uint64(meta.size) + p.stored += uint64(meta.storageSize) return nil } @@ -1050,7 +1052,7 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { nonces = []uint64{tx.nonce} ) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap) - p.stored -= uint64(tx.size) + p.stored -= uint64(tx.storageSize) p.lookup.untrack(tx) txs[i] = nil @@ -1060,7 +1062,7 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { nonces = append(nonces, tx.nonce) p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap) - p.stored -= uint64(tx.size) + p.stored -= uint64(tx.storageSize) p.lookup.untrack(tx) txs[i+1+j] = nil } @@ -1245,6 +1247,25 @@ func (p *BlobPool) GetRLP(hash common.Hash) []byte { return p.getRLP(hash) } +// GetMetadata returns the transaction type and transaction size with the +// given transaction hash. +// +// The size refers the length of the 'rlp encoding' of a blob transaction +// including the attached blobs. +func (p *BlobPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { + p.lock.RLock() + defer p.lock.RUnlock() + + size, ok := p.lookup.sizeOfTx(hash) + if !ok { + return nil + } + return &txpool.TxMetadata{ + Type: types.BlobTxType, + Size: size, + } +} + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. @@ -1384,7 +1405,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { if err != nil { return err } - meta := newBlobTxMeta(id, p.store.Size(id), tx) + meta := newBlobTxMeta(id, tx.Size(), p.store.Size(id), tx) var ( next = p.state.GetNonce(from) @@ -1412,7 +1433,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { p.lookup.untrack(prev) p.lookup.track(meta) - p.stored += uint64(meta.size) - uint64(prev.size) + p.stored += uint64(meta.storageSize) - uint64(prev.storageSize) } else { // Transaction extends previously scheduled ones p.index[from] = append(p.index[from], meta) @@ -1422,7 +1443,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { } p.spent[from] = new(uint256.Int).Add(p.spent[from], meta.costCap) p.lookup.track(meta) - p.stored += uint64(meta.size) + p.stored += uint64(meta.storageSize) } // Recompute the rolling eviction fields. In case of a replacement, this will // recompute all subsequent fields. In case of an append, this will only do @@ -1509,7 +1530,7 @@ func (p *BlobPool) drop() { p.index[from] = txs p.spent[from] = new(uint256.Int).Sub(p.spent[from], drop.costCap) } - p.stored -= uint64(drop.size) + p.stored -= uint64(drop.storageSize) p.lookup.untrack(drop) // Remove the transaction from the pool's eviction heap: diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index d9137cb67..b7c6cfa51 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -376,7 +376,7 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) { var stored uint64 for _, txs := range pool.index { for _, tx := range txs { - stored += uint64(tx.size) + stored += uint64(tx.storageSize) } } if pool.stored != stored { @@ -1553,6 +1553,16 @@ func TestAdd(t *testing.T) { if err := pool.add(signed); !errors.Is(err, add.err) { t.Errorf("test %d, tx %d: adding transaction error mismatch: have %v, want %v", i, j, err, add.err) } + if add.err == nil { + size, exist := pool.lookup.sizeOfTx(signed.Hash()) + if !exist { + t.Errorf("test %d, tx %d: failed to lookup transaction's size", i, j) + } + if size != signed.Size() { + t.Errorf("test %d, tx %d: transaction's size mismatches: have %v, want %v", + i, j, size, signed.Size()) + } + } verifyPoolInternals(t, pool) } verifyPoolInternals(t, pool) diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go index e39293240..de4076e29 100644 --- a/core/txpool/blobpool/evictheap_test.go +++ b/core/txpool/blobpool/evictheap_test.go @@ -146,7 +146,7 @@ func TestPriceHeapSorting(t *testing.T) { ) index[addr] = []*blobTxMeta{{ id: uint64(j), - size: 128 * 1024, + storageSize: 128 * 1024, nonce: 0, execTipCap: execTip, execFeeCap: execFee, @@ -205,7 +205,7 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { ) index[addr] = []*blobTxMeta{{ id: uint64(i), - size: 128 * 1024, + storageSize: 128 * 1024, nonce: 0, execTipCap: execTip, execFeeCap: execFee, @@ -281,7 +281,7 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { ) index[addr] = []*blobTxMeta{{ id: uint64(i), - size: 128 * 1024, + storageSize: 128 * 1024, nonce: 0, execTipCap: execTip, execFeeCap: execFee, @@ -312,7 +312,7 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { ) metas[i] = &blobTxMeta{ id: uint64(int(blobs) + i), - size: 128 * 1024, + storageSize: 128 * 1024, nonce: 0, execTipCap: execTip, execFeeCap: execFee, diff --git a/core/txpool/blobpool/lookup.go b/core/txpool/blobpool/lookup.go index b5cf4d379..7607cd487 100644 --- a/core/txpool/blobpool/lookup.go +++ b/core/txpool/blobpool/lookup.go @@ -20,18 +20,24 @@ import ( "github.com/ethereum/go-ethereum/common" ) +type txMetadata struct { + id uint64 // the billy id of transction + size uint64 // the RLP encoded size of transaction (blobs are included) +} + // lookup maps blob versioned hashes to transaction hashes that include them, -// and transaction hashes to billy entries that include them. +// transaction hashes to billy entries that include them, transaction hashes +// to the transaction size type lookup struct { blobIndex map[common.Hash]map[common.Hash]struct{} - txIndex map[common.Hash]uint64 + txIndex map[common.Hash]*txMetadata } // newLookup creates a new index for tracking blob to tx; and tx to billy mappings. func newLookup() *lookup { return &lookup{ blobIndex: make(map[common.Hash]map[common.Hash]struct{}), - txIndex: make(map[common.Hash]uint64), + txIndex: make(map[common.Hash]*txMetadata), } } @@ -43,8 +49,11 @@ func (l *lookup) exists(txhash common.Hash) bool { // storeidOfTx returns the datastore storage item id of a transaction. func (l *lookup) storeidOfTx(txhash common.Hash) (uint64, bool) { - id, ok := l.txIndex[txhash] - return id, ok + meta, ok := l.txIndex[txhash] + if !ok { + return 0, false + } + return meta.id, true } // storeidOfBlob returns the datastore storage item id of a blob. @@ -61,6 +70,15 @@ func (l *lookup) storeidOfBlob(vhash common.Hash) (uint64, bool) { return 0, false // Weird, don't choke } +// sizeOfTx returns the RLP-encoded size of transaction +func (l *lookup) sizeOfTx(txhash common.Hash) (uint64, bool) { + meta, ok := l.txIndex[txhash] + if !ok { + return 0, false + } + return meta.size, true +} + // track inserts a new set of mappings from blob versioned hashes to transaction // hashes; and from transaction hashes to datastore storage item ids. func (l *lookup) track(tx *blobTxMeta) { @@ -71,8 +89,11 @@ func (l *lookup) track(tx *blobTxMeta) { } l.blobIndex[vhash][tx.hash] = struct{}{} // may be double mapped if a tx contains the same blob twice } - // Map the transaction hash to the datastore id - l.txIndex[tx.hash] = tx.id + // Map the transaction hash to the datastore id and RLP-encoded transaction size + l.txIndex[tx.hash] = &txMetadata{ + id: tx.id, + size: tx.size, + } } // untrack removes a set of mappings from blob versioned hashes to transaction diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index cb9c16861..1fb6622a0 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -582,6 +582,14 @@ func (pool *CachePool) GetRLP(hash common.Hash) []byte { return nil } +// GetMetadata returns the transaction type and transaction size with the +// given transaction hash. +// +// For the cache pool, this method will return nothing for now. +func (pool *CachePool) GetMetadata(hash common.Hash) *txpool.TxMetadata { + return nil +} + // GetBlobs is not supported by the cache pool, it is just here to // implement the txpool.SubPool interface. func (pool *CachePool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 6079b85da..263e7d3d0 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1160,6 +1160,19 @@ func (pool *LegacyPool) GetRLP(hash common.Hash) []byte { return encoded } +// GetMetadata returns the transaction type and transaction size with the +// given transaction hash. +func (pool *LegacyPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { + tx := pool.all.Get(hash) + if tx == nil { + return nil + } + return &txpool.TxMetadata{ + Type: tx.Type(), + Size: tx.Size(), + } +} + // GetBlobs is not supported by the legacy transaction pool, it is just here to // implement the txpool.SubPool interface. func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 9c4ba913b..27ce03106 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -86,6 +86,12 @@ type PendingFilter struct { OnlyBlobTxs bool // Return only blob transactions (block blob-space filling) } +// TxMetadata denotes the metadata of a transaction. +type TxMetadata struct { + Type uint8 // The type of the transaction + Size uint64 // The length of the 'rlp encoding' of a transaction +} + // SubPool represents a specialized transaction pool that lives on its own (e.g. // blob pool). Since independent of how many specialized pools we have, they do // need to be updated in lockstep and assemble into one coherent view for block @@ -135,6 +141,10 @@ type SubPool interface { // GetRLP returns a RLP-encoded transaction if it is contained in the pool. GetRLP(hash common.Hash) []byte + // GetMetadata returns the transaction type and transaction size with the + // given transaction hash. + GetMetadata(hash common.Hash) *TxMetadata + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 8b7964907..560fcc9dc 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -357,6 +357,17 @@ func (p *TxPool) GetRLP(hash common.Hash) []byte { return nil } +// GetMetadata returns the transaction type and transaction size with the given +// hash. +func (p *TxPool) GetMetadata(hash common.Hash) *TxMetadata { + for _, subpool := range p.subpools { + if meta := subpool.GetMetadata(hash); meta != nil { + return meta + } + } + return nil +} + // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. diff --git a/eth/handler.go b/eth/handler.go index b9f848baf..d19010adf 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -75,6 +75,10 @@ type txPool interface { // with given tx hash. GetRLP(hash common.Hash) []byte + // GetMetadata returns the transaction type and transaction size with the + // given transaction hash. + GetMetadata(hash common.Hash) *txpool.TxMetadata + // Add should add the given transactions to the pool. Add(txs []*types.Transaction, local bool, sync bool) []error diff --git a/eth/handler_test.go b/eth/handler_test.go index 77d1cabeb..da1f58084 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -94,6 +94,22 @@ func (p *testTxPool) GetRLP(hash common.Hash) []byte { return nil } +// GetMetadata returns the transaction type and transaction size with the given +// hash. +func (p *testTxPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { + p.lock.Lock() + defer p.lock.Unlock() + + tx := p.pool[hash] + if tx != nil { + return &txpool.TxMetadata{ + Type: tx.Type(), + Size: tx.Size(), + } + } + return nil +} + // Add appends a batch of transactions to the pool, and notifies any // listeners if the addition channel is non nil func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index ad5395cb8..b1202f781 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -149,10 +149,10 @@ func (p *Peer) announceTransactions() { size common.StorageSize ) for count = 0; count < len(queue) && size < maxTxPacketSize; count++ { - if tx := p.txpool.Get(queue[count]); tx != nil { + if meta := p.txpool.GetMetadata(queue[count]); meta != nil { pending = append(pending, queue[count]) - pendingTypes = append(pendingTypes, tx.Type()) - pendingSizes = append(pendingSizes, uint32(tx.Size())) + pendingTypes = append(pendingTypes, meta.Type) + pendingSizes = append(pendingSizes, uint32(meta.Size)) size += common.HashLength } } diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 75bf08cb4..ed413d39b 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" @@ -91,6 +92,10 @@ type TxPool interface { // GetRLP retrieves the RLP-encoded transaction from the local txpool with // the given hash. GetRLP(hash common.Hash) []byte + + // GetMetadata returns the transaction type and transaction size with the + // given transaction hash. + GetMetadata(hash common.Hash) *txpool.TxMetadata } // MakeProtocols constructs the P2P protocol definitions for `eth`. From 38779a4ca2868a20e6cd1c542b537f5f308fdf30 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 2 Apr 2025 19:47:44 +0800 Subject: [PATCH 266/354] p2p/discover: repeat exact encoding when resending WHOAREYOU packet (#31543) When resending the WHOAREYOU packet, a new nonce and random IV should not be generated. The sent packet needs to match the previously-sent one exactly in order to make the handshake retry work. --------- Co-authored-by: Felix Lange --- p2p/discover/v5_udp_test.go | 40 +++++++++++++++++++++++---------- p2p/discover/v5wire/encoding.go | 16 +++++++++++-- p2p/discover/v5wire/msg.go | 3 +++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 3026dff53..606b35c4f 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -181,29 +181,35 @@ func TestUDPv5_handshakeRepeatChallenge(t *testing.T) { nonce1 := v5wire.Nonce{1} nonce2 := v5wire.Nonce{2} nonce3 := v5wire.Nonce{3} - check := func(p *v5wire.Whoareyou, wantNonce v5wire.Nonce) { + var firstAuthTag *v5wire.Nonce + check := func(p *v5wire.Whoareyou, authTag, wantNonce v5wire.Nonce) { t.Helper() if p.Nonce != wantNonce { - t.Error("wrong nonce in WHOAREYOU:", p.Nonce, wantNonce) + t.Error("wrong nonce in WHOAREYOU:", p.Nonce, "want:", wantNonce) + } + if firstAuthTag == nil { + firstAuthTag = &authTag + } else if authTag != *firstAuthTag { + t.Error("wrong auth tag in WHOAREYOU header:", authTag, "want:", *firstAuthTag) } } // Unknown packet from unknown node. test.packetIn(&v5wire.Unknown{Nonce: nonce1}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { - check(p, nonce1) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) { + check(p, authTag, nonce1) }) // Second unknown packet. Here we expect the response to reference the // first unknown packet. test.packetIn(&v5wire.Unknown{Nonce: nonce2}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { - check(p, nonce1) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) { + check(p, authTag, nonce1) }) // Third unknown packet. This should still return the first nonce. test.packetIn(&v5wire.Unknown{Nonce: nonce3}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { - check(p, nonce1) + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, authTag v5wire.Nonce) { + check(p, authTag, nonce1) }) } @@ -766,20 +772,30 @@ type testCodecFrame struct { } func (c *testCodec) Encode(toID enode.ID, addr string, p v5wire.Packet, _ *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) { + // To match the behavior of v5wire.Codec, we return the cached encoding of + // WHOAREYOU challenges. + if wp, ok := p.(*v5wire.Whoareyou); ok && len(wp.Encoded) > 0 { + return wp.Encoded, wp.Nonce, nil + } + c.ctr++ var authTag v5wire.Nonce binary.BigEndian.PutUint64(authTag[:], c.ctr) + penc, _ := rlp.EncodeToBytes(p) + frame, err := rlp.EncodeToBytes(testCodecFrame{c.id, authTag, p.Kind(), penc}) + if err != nil { + return frame, authTag, err + } + // Store recently sent challenges. if w, ok := p.(*v5wire.Whoareyou); ok { - // Store recently sent Whoareyou challenges. + w.Nonce = authTag + w.Encoded = frame if c.sentChallenges == nil { c.sentChallenges = make(map[enode.ID]*v5wire.Whoareyou) } c.sentChallenges[toID] = w } - - penc, _ := rlp.EncodeToBytes(p) - frame, err := rlp.EncodeToBytes(testCodecFrame{c.id, authTag, p.Kind(), penc}) return frame, authTag, err } diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index e50b7cd16..b16d14eda 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -189,6 +189,11 @@ func (c *Codec) Encode(id enode.ID, addr string, packet Packet, challenge *Whoar ) switch { case packet.Kind() == WhoareyouPacket: + // just send the WHOAREYOU packet raw again, rather than the re-encoded challenge data + w := packet.(*Whoareyou) + if len(w.Encoded) > 0 { + return w.Encoded, w.Nonce, nil + } head, err = c.encodeWhoareyou(id, packet.(*Whoareyou)) case challenge != nil: // We have an unanswered challenge, send handshake. @@ -218,15 +223,22 @@ func (c *Codec) Encode(id enode.ID, addr string, packet Packet, challenge *Whoar // Store sent WHOAREYOU challenges. if challenge, ok := packet.(*Whoareyou); ok { challenge.ChallengeData = bytesCopy(&c.buf) + enc, err := c.EncodeRaw(id, head, msgData) + if err != nil { + return nil, Nonce{}, err + } + challenge.Encoded = bytes.Clone(enc) c.sc.storeSentHandshake(id, addr, challenge) - } else if msgData == nil { + return enc, head.Nonce, err + } + + if msgData == nil { headerData := c.buf.Bytes() msgData, err = c.encryptMessage(session, packet, &head, headerData) if err != nil { return nil, Nonce{}, err } } - enc, err := c.EncodeRaw(id, head, msgData) return enc, head.Nonce, err } diff --git a/p2p/discover/v5wire/msg.go b/p2p/discover/v5wire/msg.go index 401db2f6c..089fd4ebd 100644 --- a/p2p/discover/v5wire/msg.go +++ b/p2p/discover/v5wire/msg.go @@ -73,6 +73,9 @@ type ( Node *enode.Node sent mclock.AbsTime // for handshake GC. + + // Encoded is packet raw data for sending out, but should not be include in the RLP encoding. + Encoded []byte `rlp:"-"` } // PING is sent during liveness checks. From 0b702363d0631b0e96feb069502513bce0ffdaa2 Mon Sep 17 00:00:00 2001 From: thinkAfCod Date: Wed, 2 Apr 2025 20:56:21 +0800 Subject: [PATCH 267/354] p2p/discover: pass node instead of node ID to TALKREQ handler (#31075) This is for the implementation of Portal Network in the Shisui client. Their handler needs access to the node object in order to send further calls to the requesting node. This is a breaking API change but it should be fine, since there are basically no known users of TALKREQ outside of Portal network. --------- Signed-off-by: thinkAfCod Co-authored-by: Felix Lange --- p2p/discover/v5_talk.go | 14 ++++++++++---- p2p/discover/v5_udp.go | 3 +++ p2p/discover/v5_udp_test.go | 6 +++++- p2p/discover/v5wire/encoding.go | 8 ++++++-- p2p/discover/v5wire/encoding_test.go | 14 +++++++------- p2p/discover/v5wire/session.go | 16 ++++++++++++++-- 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/p2p/discover/v5_talk.go b/p2p/discover/v5_talk.go index 2246b4714..dca09870d 100644 --- a/p2p/discover/v5_talk.go +++ b/p2p/discover/v5_talk.go @@ -39,7 +39,7 @@ const talkHandlerLaunchTimeout = 400 * time.Millisecond // Note that talk handlers are expected to come up with a response very quickly, within at // most 200ms or so. If the handler takes longer than that, the remote end may time out // and wont receive the response. -type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte +type TalkRequestHandler func(*enode.Node, *net.UDPAddr, []byte) []byte type talkSystem struct { transport *UDPv5 @@ -72,13 +72,19 @@ func (t *talkSystem) register(protocol string, handler TalkRequestHandler) { // handleRequest handles a talk request. func (t *talkSystem) handleRequest(id enode.ID, addr netip.AddrPort, req *v5wire.TalkRequest) { + n := t.transport.codec.SessionNode(id, addr.String()) + if n == nil { + // The node must be contained in the session here, since we wouldn't have + // received the request otherwise. + panic("missing node in session") + } t.mutex.Lock() handler, ok := t.handlers[req.Protocol] t.mutex.Unlock() if !ok { resp := &v5wire.TalkResponse{ReqID: req.ReqID} - t.transport.sendResponse(id, addr, resp) + t.transport.sendResponse(n.ID(), addr, resp) return } @@ -90,9 +96,9 @@ func (t *talkSystem) handleRequest(id enode.ID, addr netip.AddrPort, req *v5wire go func() { defer func() { t.slots <- struct{}{} }() udpAddr := &net.UDPAddr{IP: addr.Addr().AsSlice(), Port: int(addr.Port())} - respMessage := handler(id, udpAddr, req.Message) + respMessage := handler(n, udpAddr, req.Message) resp := &v5wire.TalkResponse{ReqID: req.ReqID, Message: respMessage} - t.transport.sendFromAnotherThread(id, addr, resp) + t.transport.sendFromAnotherThread(n.ID(), addr, resp) }() case <-timeout.C: // Couldn't get it in time, drop the request. diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 6f7c79715..9679f5c61 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -64,6 +64,9 @@ type codecV5 interface { // CurrentChallenge returns the most recent WHOAREYOU challenge that was encoded to given node. // This will return a non-nil value if there is an active handshake attempt with the node, and nil otherwise. CurrentChallenge(id enode.ID, addr string) *v5wire.Whoareyou + + // SessionNode returns a node that has completed the handshake. + SessionNode(id enode.ID, addr string) *enode.Node } // UDPv5 is the implementation of protocol version 5. diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 606b35c4f..3a384aab1 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -492,7 +492,7 @@ func TestUDPv5_talkHandling(t *testing.T) { defer test.close() var recvMessage []byte - test.udp.RegisterTalkHandler("test", func(id enode.ID, addr *net.UDPAddr, message []byte) []byte { + test.udp.RegisterTalkHandler("test", func(n *enode.Node, addr *net.UDPAddr, message []byte) []byte { recvMessage = message return []byte("test response") }) @@ -811,6 +811,10 @@ func (c *testCodec) Decode(input []byte, addr string) (enode.ID, *enode.Node, v5 return frame.NodeID, nil, p, nil } +func (c *testCodec) SessionNode(id enode.ID, addr string) *enode.Node { + return c.test.nodesByID[id].Node() +} + func (c *testCodec) decodeFrame(input []byte) (frame testCodecFrame, p v5wire.Packet, err error) { if err = rlp.DecodeBytes(input, &frame); err != nil { return frame, nil, fmt.Errorf("invalid frame: %v", err) diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index b16d14eda..ec5ef8a26 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -359,7 +359,7 @@ func (c *Codec) encodeHandshakeHeader(toID enode.ID, addr string, challenge *Who } // TODO: this should happen when the first authenticated message is received - c.sc.storeNewSession(toID, addr, session) + c.sc.storeNewSession(toID, addr, session, challenge.Node) // Encode the auth header. var ( @@ -534,7 +534,7 @@ func (c *Codec) decodeHandshakeMessage(fromAddr string, head *Header, headerData } // Handshake OK, drop the challenge and store the new session keys. - c.sc.storeNewSession(auth.h.SrcID, fromAddr, session) + c.sc.storeNewSession(auth.h.SrcID, fromAddr, session, node) c.sc.deleteHandshake(auth.h.SrcID, fromAddr) return node, msg, nil } @@ -656,6 +656,10 @@ func (c *Codec) decryptMessage(input, nonce, headerData, readKey []byte) (Packet return DecodeMessage(msgdata[0], msgdata[1:]) } +func (c *Codec) SessionNode(id enode.ID, addr string) *enode.Node { + return c.sc.readNode(id, addr) +} + // checkValid performs some basic validity checks on the header. // The packetLen here is the length remaining after the static header. func (h *StaticHeader) checkValid(packetLen int, protocolID [6]byte) error { diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index df97e40e8..2304d0f13 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -166,7 +166,7 @@ func TestHandshake_rekey(t *testing.T) { readKey: []byte("BBBBBBBBBBBBBBBB"), writeKey: []byte("AAAAAAAAAAAAAAAA"), } - net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session) + net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session, net.nodeB.n()) // A -> B FINDNODE (encrypted with zero keys) findnode, authTag := net.nodeA.encode(t, net.nodeB, &Findnode{}) @@ -209,8 +209,8 @@ func TestHandshake_rekey2(t *testing.T) { readKey: []byte("CCCCCCCCCCCCCCCC"), writeKey: []byte("DDDDDDDDDDDDDDDD"), } - net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), initKeysA) - net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), initKeysB) + net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), initKeysA, net.nodeB.n()) + net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), initKeysB, net.nodeA.n()) // A -> B FINDNODE encrypted with initKeysA findnode, authTag := net.nodeA.encode(t, net.nodeB, &Findnode{Distances: []uint{3}}) @@ -362,8 +362,8 @@ func TestTestVectorsV5(t *testing.T) { ENRSeq: 2, }, prep: func(net *handshakeTest) { - net.nodeA.c.sc.storeNewSession(idB, addr, session) - net.nodeB.c.sc.storeNewSession(idA, addr, session.keysFlipped()) + net.nodeA.c.sc.storeNewSession(idB, addr, session, net.nodeB.n()) + net.nodeB.c.sc.storeNewSession(idA, addr, session.keysFlipped(), net.nodeA.n()) }, }, { @@ -499,8 +499,8 @@ func BenchmarkV5_DecodePing(b *testing.B) { readKey: []byte{233, 203, 93, 195, 86, 47, 177, 186, 227, 43, 2, 141, 244, 230, 120, 17}, writeKey: []byte{79, 145, 252, 171, 167, 216, 252, 161, 208, 190, 176, 106, 214, 39, 178, 134}, } - net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session) - net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), session.keysFlipped()) + net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session, net.nodeB.n()) + net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), session.keysFlipped(), net.nodeA.n()) addrB := net.nodeA.addr() ping := &Ping{ReqID: []byte("reqid"), ENRSeq: 5} enc, _, err := net.nodeA.c.Encode(net.nodeB.id(), addrB, ping, nil) diff --git a/p2p/discover/v5wire/session.go b/p2p/discover/v5wire/session.go index 862c21fce..5a2166b14 100644 --- a/p2p/discover/v5wire/session.go +++ b/p2p/discover/v5wire/session.go @@ -54,11 +54,12 @@ type session struct { writeKey []byte readKey []byte nonceCounter uint32 + node *enode.Node } // keysFlipped returns a copy of s with the read and write keys flipped. func (s *session) keysFlipped() *session { - return &session{s.readKey, s.writeKey, s.nonceCounter} + return &session{s.readKey, s.writeKey, s.nonceCounter, s.node} } func NewSessionCache(maxItems int, clock mclock.Clock) *SessionCache { @@ -103,8 +104,19 @@ func (sc *SessionCache) readKey(id enode.ID, addr string) []byte { return nil } +func (sc *SessionCache) readNode(id enode.ID, addr string) *enode.Node { + if s := sc.session(id, addr); s != nil { + return s.node + } + return nil +} + // storeNewSession stores new encryption keys in the cache. -func (sc *SessionCache) storeNewSession(id enode.ID, addr string, s *session) { +func (sc *SessionCache) storeNewSession(id enode.ID, addr string, s *session, n *enode.Node) { + if n == nil { + panic("nil node in storeNewSession") + } + s.node = n sc.sessions.Add(sessionID{id, addr}, s) } From 34fcfc60fd3013ba5a90f44c04ddb2079c396778 Mon Sep 17 00:00:00 2001 From: owen <158327443+owenzimmew06@users.noreply.github.com> Date: Wed, 2 Apr 2025 20:19:25 +0300 Subject: [PATCH 268/354] README: fixup typos (#31540) Fixes a few typos in readme. --- cmd/clef/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/clef/README.md b/cmd/clef/README.md index a73ffd5b4..d23e70a3d 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -1,6 +1,6 @@ # Clef -Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and asks for permission to sign the content. If the users grants the signing request, Clef will send the signature back to the DApp. +Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and ask for permission to sign the content. If the user grants the signing request, Clef will send the signature back to the DApp. This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronized with the chain, or is a node that has no built-in (or limited) account management. @@ -123,7 +123,7 @@ The External API is **untrusted**: it does not accept credentials, nor does it e Clef has one native console-based UI, for operation without any standalone tools. However, there is also an API to communicate with an external UI. To enable that UI, the signer needs to be executed with the `--stdio-ui` option, which allocates `stdin` / `stdout` for the UI API. -An example (insecure) proof-of-concept of has been implemented in `pythonsigner.py`. +An example (insecure) proof-of-concept has been implemented in `pythonsigner.py`. The model is as follows: @@ -335,7 +335,7 @@ Bash example: #### Arguments - content type [string]: type of signed data - - `text/validator`: hex data with custom validator defined in a contract + - `text/validator`: hex data with a custom validator defined in a contract - `application/clique`: [clique](https://github.com/ethereum/EIPs/issues/225) headers - `text/plain`: simple hex data validated by `account_ecRecover` - account [address]: account to sign with From 8b05109d97936415b611ae0162927d980cf23aad Mon Sep 17 00:00:00 2001 From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:52:40 +0300 Subject: [PATCH 269/354] all: fix typos in docs and comments (#31548) Co-authored-by: lightclient --- cmd/clef/rules.md | 2 +- cmd/evm/README.md | 2 +- cmd/evm/eest.go | 2 +- eth/downloader/skeleton.go | 2 +- internal/guide/guide_test.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md index 3cd1bb52c..ef89ec00c 100644 --- a/cmd/clef/rules.md +++ b/cmd/clef/rules.md @@ -2,7 +2,7 @@ The `signer` binary contains a ruleset engine, implemented with [OttoVM](https://github.com/robertkrimen/otto) -It enables usecases like the following: +It enables use cases like the following: * I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period * I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei` diff --git a/cmd/evm/README.md b/cmd/evm/README.md index f95b6b4d7..17d663a50 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -16,7 +16,7 @@ which can 1. Take a prestate, including - Accounts, - Block context information, - - Previous blockshashes (*optional) + - Previous block hashes (*optional) 2. Apply a set of transactions, 3. Apply a mining-reward (*optional), 4. And generate a post-state, including diff --git a/cmd/evm/eest.go b/cmd/evm/eest.go index 43071a3e5..4cda2fc51 100644 --- a/cmd/evm/eest.go +++ b/cmd/evm/eest.go @@ -22,7 +22,7 @@ import "regexp" // within its filename by the execution spec test (EEST). type testMetadata struct { fork string - module string // which python module gnerated the test, e.g. eip7702 + module string // which python module generated the test, e.g. eip7702 file string // exact file the test came from, e.g. test_gas.py function string // func that created the test, e.g. test_valid_mcopy_operations parameters string // the name of the parameters which were used to fill the test, e.g. zero_inputs diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 04421a2bf..ad74dab84 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -275,7 +275,7 @@ func (s *skeleton) startup() { for { // If the sync cycle terminated or was terminated, propagate up when // higher layers request termination. There's no fancy explicit error - // signalling as the sync loop should never terminate (TM). + // signaling as the sync loop should never terminate (TM). newhead, err := s.sync(head) switch { case err == errSyncLinked: diff --git a/internal/guide/guide_test.go b/internal/guide/guide_test.go index 573898d7d..71614c125 100644 --- a/internal/guide/guide_test.go +++ b/internal/guide/guide_test.go @@ -15,7 +15,7 @@ // along with the go-ethereum library. If not, see . // This file contains the code snippets from the developer's guide embedded into -// Go tests. This ensures that any code published in out guides will not break +// Go tests. This ensures that any code published in our guides will not break // accidentally via some code update. If some API changes nonetheless that needs // modifying this file, please port any modification over into the developer's // guide wiki pages too! From 25141aecb11e9e272f5e3e091c97f1a1c55f6690 Mon Sep 17 00:00:00 2001 From: antonis19 Date: Thu, 3 Apr 2025 06:35:52 +0200 Subject: [PATCH 270/354] eth/protocols/eth: improve over/underflow handling in `GetBlockHeaders` (#31522) --- eth/protocols/eth/handler_test.go | 28 ++++++++++++++++++++++++++++ eth/protocols/eth/handlers.go | 17 ++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index c9595ca6b..2c783459d 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -297,6 +297,34 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { backend.chain.GetBlockByNumber(0).Hash(), }, }, + // Check a corner case where skipping causes overflow with reverse=false + { + &GetBlockHeadersRequest{Origin: HashOrNumber{Number: 1}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1}, + []common.Hash{ + backend.chain.GetBlockByNumber(1).Hash(), + }, + }, + // Check a corner case where skipping causes overflow with reverse=true + { + &GetBlockHeadersRequest{Origin: HashOrNumber{Number: 1}, Amount: 2, Reverse: true, Skip: math.MaxUint64 - 1}, + []common.Hash{ + backend.chain.GetBlockByNumber(1).Hash(), + }, + }, + // Check another corner case where skipping causes overflow with reverse=false + { + &GetBlockHeadersRequest{Origin: HashOrNumber{Number: 1}, Amount: 2, Reverse: false, Skip: math.MaxUint64}, + []common.Hash{ + backend.chain.GetBlockByNumber(1).Hash(), + }, + }, + // Check another corner case where skipping causes overflow with reverse=true + { + &GetBlockHeadersRequest{Origin: HashOrNumber{Number: 1}, Amount: 2, Reverse: true, Skip: math.MaxUint64}, + []common.Hash{ + backend.chain.GetBlockByNumber(1).Hash(), + }, + }, // Check a corner case where skipping overflow loops back into the chain start { &GetBlockHeadersRequest{Origin: HashOrNumber{Hash: backend.chain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1}, diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 18b6d0cdf..666900b46 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -127,15 +127,22 @@ func serviceNonContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBloc } case query.Reverse: // Number based traversal towards the genesis block - if query.Origin.Number >= query.Skip+1 { - query.Origin.Number -= query.Skip + 1 - } else { + current := query.Origin.Number + ancestor := current - (query.Skip + 1) + if ancestor >= current { // check for underflow unknown = true + } else { + query.Origin.Number = ancestor } case !query.Reverse: - // Number based traversal towards the leaf block - query.Origin.Number += query.Skip + 1 + current := query.Origin.Number + next := current + query.Skip + 1 + if next <= current { // check for overflow + unknown = true + } else { + query.Origin.Number = next + } } } return headers From defef9139b6a669539698810737524ac95a51319 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 3 Apr 2025 21:16:35 +0800 Subject: [PATCH 271/354] core, eth/downloader: implement pruning mode sync (#31414) This pull request introduces new sync logic for pruning mode. The downloader will now skip insertion of block bodies and receipts before the configured history cutoff point. Originally, in snap sync, the header chain and other components (bodies and receipts) were inserted separately. However, in Proof-of-Stake, this separation is unnecessary since the sync target is already verified by the CL. To simplify the process, this pull request modifies `InsertReceiptChain` to insert headers along with block bodies and receipts together. Besides, `InsertReceiptChain` doesn't have the notion of reorg, as the common ancestor is always be found before the sync and extra side chain is truncated at the beginning if they fall in the ancient store. The stale canonical chain flags will always be rewritten by the new chain. Explicit reorg logic is no longer required in `InsertReceiptChain`. --- cmd/geth/chaincmd.go | 2 +- cmd/utils/cmd.go | 11 +- cmd/utils/history_test.go | 2 +- core/blockchain.go | 268 +++++++++++++---------- core/blockchain_reader.go | 6 + core/blockchain_test.go | 341 +++++++++++++++++++---------- core/error.go | 2 - core/headerchain.go | 10 +- core/rawdb/accessors_chain.go | 30 +++ core/rawdb/accessors_chain_test.go | 46 ++++ core/txindexer.go | 3 +- eth/api_backend.go | 46 +--- eth/backend.go | 34 +-- eth/downloader/beaconsync.go | 3 +- eth/downloader/downloader.go | 76 +------ eth/downloader/queue.go | 12 +- eth/downloader/resultstore.go | 4 +- eth/filters/api.go | 4 - eth/filters/filter.go | 11 - eth/filters/filter_system.go | 10 - internal/ethapi/api_test.go | 5 +- internal/ethapi/backend.go | 1 - 22 files changed, 511 insertions(+), 416 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 708dd8fb7..0c36b82af 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -457,7 +457,7 @@ func importHistory(ctx *cli.Context) error { network = networks[0] } - if err := utils.ImportHistory(chain, db, dir, network); err != nil { + if err := utils.ImportHistory(chain, dir, network); err != nil { return err } fmt.Printf("Import done in %v\n", time.Since(start)) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 40116beb5..18bc79d55 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -245,8 +245,9 @@ func readList(filename string) ([]string, error) { } // ImportHistory imports Era1 files containing historical block information, -// starting from genesis. -func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, network string) error { +// starting from genesis. The assumption is held that the provided chain +// segment in Era1 file should all be canonical and verified. +func ImportHistory(chain *core.BlockChain, dir string, network string) error { if chain.CurrentSnapBlock().Number.BitLen() != 0 { return errors.New("history import only supported when starting from genesis") } @@ -265,7 +266,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ start = time.Now() reported = time.Now() imported = 0 - forker = core.NewForkChoice(chain, nil) h = sha256.New() buf = bytes.NewBuffer(nil) ) @@ -308,11 +308,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ if err != nil { return fmt.Errorf("error reading receipts %d: %w", it.Number(), err) } - if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start, forker); err != nil { - return fmt.Errorf("error inserting header %d: %w", it.Number(), err) - } else if status != core.CanonStatTy { - return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status) - } if _, err := chain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{receipts}, 2^64-1); err != nil { return fmt.Errorf("error inserting body %d: %w", it.Number(), err) } diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index b4616c306..52656e025 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -171,7 +171,7 @@ func TestHistoryImportAndExport(t *testing.T) { if err != nil { t.Fatalf("unable to initialize chain: %v", err) } - if err := ImportHistory(imported, db2, dir, "mainnet"); err != nil { + if err := ImportHistory(imported, dir, "mainnet"); err != nil { t.Fatalf("failed to import chain: %v", err) } if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() { diff --git a/core/blockchain.go b/core/blockchain.go index 51b55e133..5216e00ae 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -24,6 +24,7 @@ import ( "math/big" "runtime" "slices" + "sort" "strings" "sync" "sync/atomic" @@ -137,7 +138,6 @@ const ( // // - Version 9 // The following incompatible database changes were added: - // * Total difficulty has been removed from both the key-value store and the ancient store. // * The metadata structure of freezer is changed by adding 'flushOffset' BlockChainVersion uint64 = 9 ) @@ -160,7 +160,8 @@ type CacheConfig struct { // This defines the cutoff block for history expiry. // Blocks before this number may be unavailable in the chain database. - HistoryPruningCutoff uint64 + HistoryPruningCutoffNumber uint64 + HistoryPruningCutoffHash common.Hash } // triedbConfig derives the configures for trie database. @@ -343,10 +344,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.processor = NewStateProcessor(chainConfig, bc.hc) genesisHeader := bc.GetHeaderByNumber(0) - bc.genesisBlock = types.NewBlockWithHeader(genesisHeader) - if bc.genesisBlock == nil { + if genesisHeader == nil { return nil, ErrNoGenesis } + bc.genesisBlock = types.NewBlockWithHeader(genesisHeader) bc.currentBlock.Store(nil) bc.currentSnapBlock.Store(nil) @@ -1251,86 +1252,72 @@ const ( SideStatTy ) -// InsertReceiptChain attempts to complete an already existing header chain with -// transaction and receipt data. +// InsertReceiptChain inserts a batch of blocks along with their receipts into +// the database. Unlike InsertChain, this function does not verify the state root +// in the blocks. It is used exclusively for snap sync. All the inserted blocks +// will be regarded as canonical, chain reorg is not supported. +// +// The optional ancientLimit can also be specified and chain segment before that +// will be directly stored in the ancient, getting rid of the chain migration. func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts, ancientLimit uint64) (int, error) { - // We don't require the chainMu here since we want to maximize the - // concurrency of header insertion and receipt insertion. - bc.wg.Add(1) - defer bc.wg.Done() - - var ( - ancientBlocks, liveBlocks types.Blocks - ancientReceipts, liveReceipts []types.Receipts - ) - // Do a sanity check that the provided chain is actually ordered and linked - for i, block := range blockChain { - if i != 0 { - prev := blockChain[i-1] - if block.NumberU64() != prev.NumberU64()+1 || block.ParentHash() != prev.Hash() { - log.Error("Non contiguous receipt insert", - "number", block.Number(), "hash", block.Hash(), "parent", block.ParentHash(), - "prevnumber", prev.Number(), "prevhash", prev.Hash()) - return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x..], item %d is #%d [%x..] (parent [%x..])", - i-1, prev.NumberU64(), prev.Hash().Bytes()[:4], - i, block.NumberU64(), block.Hash().Bytes()[:4], block.ParentHash().Bytes()[:4]) - } - } - if block.NumberU64() <= ancientLimit { - ancientBlocks, ancientReceipts = append(ancientBlocks, block), append(ancientReceipts, receiptChain[i]) - } else { - liveBlocks, liveReceipts = append(liveBlocks, block), append(liveReceipts, receiptChain[i]) - } - - // Here we also validate that blob transactions in the block do not contain a sidecar. - // While the sidecar does not affect the block hash / tx hash, sending blobs within a block is not allowed. + // Verify the supplied headers before insertion without lock + var headers []*types.Header + for _, block := range blockChain { + headers = append(headers, block.Header()) + + // Here we also validate that blob transactions in the block do not + // contain a sidecar. While the sidecar does not affect the block hash + // or tx hash, sending blobs within a block is not allowed. for txIndex, tx := range block.Transactions() { if tx.Type() == types.BlobTxType && tx.BlobTxSidecar() != nil { return 0, fmt.Errorf("block #%d contains unexpected blob sidecar in tx at index %d", block.NumberU64(), txIndex) } } } + if n, err := bc.hc.ValidateHeaderChain(headers); err != nil { + return n, err + } + // Hold the mutation lock + if !bc.chainmu.TryLock() { + return 0, errChainStopped + } + defer bc.chainmu.Unlock() var ( stats = struct{ processed, ignored int32 }{} start = time.Now() size = int64(0) ) - - // updateHead updates the head snap sync block if the inserted blocks are better - // and returns an indicator whether the inserted blocks are canonical. - updateHead := func(head *types.Block) bool { - if !bc.chainmu.TryLock() { - return false + // updateHead updates the head header and head snap block flags. + updateHead := func(header *types.Header) error { + reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), header) + if err != nil { + log.Warn("Reorg failed", "err", err) + return err + } else if !reorg { + return nil } - defer bc.chainmu.Unlock() - // Rewind may have occurred, skip in that case. - if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { - reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header()) - if err != nil { - log.Warn("Reorg failed", "err", err) - return false - } else if !reorg { - return false - } - rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) - bc.currentSnapBlock.Store(head.Header()) - headFastBlockGauge.Update(int64(head.NumberU64())) - return true + batch := bc.db.NewBatch() + hash := header.Hash() + rawdb.WriteHeadHeaderHash(batch, hash) + rawdb.WriteHeadFastBlockHash(batch, hash) + if err := batch.Write(); err != nil { + return err } - return false + bc.hc.currentHeader.Store(header) + bc.currentSnapBlock.Store(header) + headHeaderGauge.Update(header.Number.Int64()) + headFastBlockGauge.Update(header.Number.Int64()) + return nil } // writeAncient writes blockchain and corresponding receipt chain into ancient store. // // this function only accepts canonical chain data. All side chain will be reverted // eventually. writeAncient := func(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { - first := blockChain[0] - last := blockChain[len(blockChain)-1] - - // Ensure genesis is in ancients. - if first.NumberU64() == 1 { + // Ensure genesis is in the ancient store + if blockChain[0].NumberU64() == 1 { if frozen, _ := bc.db.Ancients(); frozen == 0 { td := bc.genesisBlock.Difficulty() writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td) @@ -1342,13 +1329,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ log.Info("Wrote genesis to ancients") } } - // Before writing the blocks to the ancients, we need to ensure that - // they correspond to the what the headerchain 'expects'. - // We only check the last block/header, since it's a contiguous chain. - if !bc.HasHeader(last.Hash(), last.NumberU64()) { - return 0, fmt.Errorf("containing header #%d [%x..] unknown", last.Number(), last.Hash().Bytes()[:4]) - } // Write all chain data to ancients. + first := blockChain[0] ptd := bc.GetTd(first.ParentHash(), first.NumberU64()-1) if ptd == nil { return 0, consensus.ErrUnknownAncestor @@ -1365,44 +1347,28 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if err := bc.db.Sync(); err != nil { return 0, err } - // Update the current snap block because all block data is now present in DB. - previousSnapBlock := bc.CurrentSnapBlock().Number.Uint64() - if !updateHead(blockChain[len(blockChain)-1]) { - // We end up here if the header chain has reorg'ed, and the blocks/receipts - // don't match the canonical chain. - if _, err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil { - log.Error("Can't truncate ancient store after failed insert", "err", err) - } - return 0, errSideChainReceipts - } - - // Delete block data from the main database. - var ( - batch = bc.db.NewBatch() - canonHashes = make(map[common.Hash]struct{}, len(blockChain)) - ) + // Write hash to number mappings + batch := bc.db.NewBatch() for _, block := range blockChain { - canonHashes[block.Hash()] = struct{}{} - if block.NumberU64() == 0 { - continue - } - rawdb.DeleteCanonicalHash(batch, block.NumberU64()) - rawdb.DeleteBlockWithoutNumber(batch, block.Hash(), block.NumberU64()) - } - // Delete side chain hash-to-number mappings. - for _, nh := range rawdb.ReadAllHashesInRange(bc.db, first.NumberU64(), last.NumberU64()) { - if _, canon := canonHashes[nh.Hash]; !canon { - rawdb.DeleteHeader(batch, nh.Hash, nh.Number) - } + rawdb.WriteHeaderNumber(batch, block.Hash(), block.NumberU64()) } if err := batch.Write(); err != nil { return 0, err } + // Update the current snap block because all block data is now present in DB. + if err := updateHead(blockChain[len(blockChain)-1].Header()); err != nil { + return 0, err + } stats.processed += int32(len(blockChain)) return 0, nil } - // writeLive writes blockchain and corresponding receipt chain into active store. + // writeLive writes the blockchain and corresponding receipt chain to the active store. + // + // Notably, in different snap sync cycles, the supplied chain may partially reorganize + // existing local chain segments (reorg around the chain tip). The reorganized part + // will be included in the provided chain segment, and stale canonical markers will be + // silently rewritten. Therefore, no explicit reorg logic is needed. writeLive := func(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { var ( skipPresenceCheck = false @@ -1413,10 +1379,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if bc.insertStopped() { return 0, errInsertionInterrupted } - // Short circuit if the owner header is unknown - if !bc.HasHeader(block.Hash(), block.NumberU64()) { - return i, fmt.Errorf("containing header #%d [%x..] unknown", block.Number(), block.Hash().Bytes()[:4]) - } if !skipPresenceCheck { // Ignore if the entire data is already known if bc.HasBlock(block.Hash(), block.NumberU64()) { @@ -1430,7 +1392,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } } // Write all the data out into the database - rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()) + rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) + rawdb.WriteBlock(batch, block) rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receiptChain[i]) // Write everything belongs to the blocks into the database. So that @@ -1454,21 +1417,27 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, err } } - updateHead(blockChain[len(blockChain)-1]) + if err := updateHead(blockChain[len(blockChain)-1].Header()); err != nil { + return 0, err + } return 0, nil } - // Write downloaded chain data and corresponding receipt chain data - if len(ancientBlocks) > 0 { - if n, err := writeAncient(ancientBlocks, ancientReceipts); err != nil { + // Split the supplied blocks into two groups, according to the + // given ancient limit. + index := sort.Search(len(blockChain), func(i int) bool { + return blockChain[i].NumberU64() >= ancientLimit + }) + if index > 0 { + if n, err := writeAncient(blockChain[:index], receiptChain[:index]); err != nil { if err == errInsertionInterrupted { return 0, nil } return n, err } } - if len(liveBlocks) > 0 { - if n, err := writeLive(liveBlocks, liveReceipts); err != nil { + if index != len(blockChain) { + if n, err := writeLive(blockChain[index:], receiptChain[index:]); err != nil { if err == errInsertionInterrupted { return 0, nil } @@ -1487,7 +1456,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ context = append(context, []interface{}{"ignored", stats.ignored}...) } log.Debug("Imported new block receipts", context...) - return 0, nil } @@ -2729,15 +2697,89 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) { if i, err := bc.hc.ValidateHeaderChain(chain); err != nil { return i, err } - if !bc.chainmu.TryLock() { return 0, errChainStopped } defer bc.chainmu.Unlock() + _, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) return 0, err } +// InsertHeadersBeforeCutoff inserts the given headers into the ancient store +// as they are claimed older than the configured chain cutoff point. All the +// inserted headers are regarded as canonical and chain reorg is not supported. +func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, error) { + if len(headers) == 0 { + return 0, nil + } + // TODO(rjl493456442): Headers before the configured cutoff have already + // been verified by the hash of cutoff header. Theoretically, header validation + // could be skipped here. + if n, err := bc.hc.ValidateHeaderChain(headers); err != nil { + return n, err + } + if !bc.chainmu.TryLock() { + return 0, errChainStopped + } + defer bc.chainmu.Unlock() + + // Initialize the ancient store with genesis block if it's empty. + var ( + frozen, _ = bc.db.Ancients() + first = headers[0].Number.Uint64() + firstHeader = headers[0] + ) + if first == 1 && frozen == 0 { + td := bc.genesisBlock.Difficulty() + _, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td) + if err != nil { + log.Error("Error writing genesis to ancients", "err", err) + return 0, err + } + log.Info("Wrote genesis to ancient store") + } else if frozen != first { + return 0, fmt.Errorf("headers are gapped with the ancient store, first: %d, ancient: %d", first, frozen) + } + + // Write headers to the ancient store, with block bodies and receipts set to nil + // to ensure consistency across tables in the freezer. + ptd := bc.GetTd(firstHeader.ParentHash, firstHeader.Number.Uint64()-1) + if ptd == nil { + return 0, consensus.ErrUnknownAncestor + } + _, err := rawdb.WriteAncientHeaderChain(bc.db, headers, ptd) + if err != nil { + return 0, err + } + if err := bc.db.Sync(); err != nil { + return 0, err + } + // Write hash to number mappings + batch := bc.db.NewBatch() + for _, header := range headers { + rawdb.WriteHeaderNumber(batch, header.Hash(), header.Number.Uint64()) + } + // Write head header and head snap block flags + last := headers[len(headers)-1] + rawdb.WriteHeadHeaderHash(batch, last.Hash()) + rawdb.WriteHeadFastBlockHash(batch, last.Hash()) + if err := batch.Write(); err != nil { + return 0, err + } + // Truncate the useless chain segment (zero bodies and receipts) in the + // ancient store. + if _, err := bc.db.TruncateTail(last.Number.Uint64() + 1); err != nil { + return 0, err + } + // Last step update all in-memory markers + bc.hc.currentHeader.Store(last) + bc.currentSnapBlock.Store(last) + headHeaderGauge.Update(last.Number.Int64()) + headFastBlockGauge.Update(last.Number.Int64()) + return 0, nil +} + // SetBlockValidatorAndProcessorForTesting sets the current validator and processor. // This method can be used to force an invalid blockchain to be verified for tests. // This method is unsafe and should only be used before block import starts. @@ -2758,12 +2800,6 @@ func (bc *BlockChain) GetTrieFlushInterval() time.Duration { return time.Duration(bc.flushInterval.Load()) } -// HistoryPruningCutoff returns the configured history pruning point. -// Blocks before this might not be available in the database. -func (bc *BlockChain) HistoryPruningCutoff() uint64 { - return bc.cacheConfig.HistoryPruningCutoff -} - // getParentState retrieves statedb and parent header by hash or block number func (bc *BlockChain) getParentState(block *types.Block) (*state.StateDB, *types.Header, error) { parent := bc.GetBlockByHash(block.ParentHash()) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index f27711dad..da5f6a736 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -430,6 +430,12 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) { return bc.txIndexer.txIndexProgress() } +// HistoryPruningCutoff returns the configured history pruning point. +// Blocks before this might not be available in the database. +func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) { + return bc.cacheConfig.HistoryPruningCutoffNumber, bc.cacheConfig.HistoryPruningCutoffHash +} + // TrieDB retrieves the low level trie database used for data storage. func (bc *BlockChain) TrieDB() *triedb.Database { return bc.triedb diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cb40a39a2..502319c1d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -778,13 +778,6 @@ func testFastVsFullChains(t *testing.T, scheme string) { fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - if n, err := fast.InsertHeaderChain(headers); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -798,9 +791,6 @@ func testFastVsFullChains(t *testing.T, scheme string) { ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() - if n, err := ancient.InsertHeaderChain(headers); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(len(blocks)/2)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -931,13 +921,6 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - if n, err := fast.InsertHeaderChain(headers); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -951,9 +934,6 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() - if n, err := ancient.InsertHeaderChain(headers); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -967,6 +947,11 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() + + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) @@ -1764,13 +1749,6 @@ func testBlockchainRecovery(t *testing.T, scheme string) { defer ancientDb.Close() ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - if n, err := ancient.InsertHeaderChain(headers); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -1795,82 +1773,6 @@ func testBlockchainRecovery(t *testing.T, scheme string) { } } -// This test checks that InsertReceiptChain will roll back correctly when attempting to insert a side chain. -func TestInsertReceiptChainRollback(t *testing.T) { - testInsertReceiptChainRollback(t, rawdb.HashScheme) - testInsertReceiptChainRollback(t, rawdb.PathScheme) -} - -func testInsertReceiptChainRollback(t *testing.T, scheme string) { - // Generate forked chain. The returned BlockChain object is used to process the side chain blocks. - tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains(scheme) - if err != nil { - t.Fatal(err) - } - defer tmpChain.Stop() - // Get the side chain receipts. - if _, err := tmpChain.InsertChain(sideblocks); err != nil { - t.Fatal("processing side chain failed:", err) - } - t.Log("sidechain head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash()) - sidechainReceipts := make([]types.Receipts, len(sideblocks)) - for i, block := range sideblocks { - sidechainReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash()) - } - // Get the canon chain receipts. - if _, err := tmpChain.InsertChain(canonblocks); err != nil { - t.Fatal("processing canon chain failed:", err) - } - t.Log("canon head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash()) - canonReceipts := make([]types.Receipts, len(canonblocks)) - for i, block := range canonblocks { - canonReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash()) - } - - // Set up a BlockChain that uses the ancient store. - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) - if err != nil { - t.Fatalf("failed to create temp freezer db: %v", err) - } - defer ancientDb.Close() - - ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - defer ancientChain.Stop() - - // Import the canonical header chain. - canonHeaders := make([]*types.Header, len(canonblocks)) - for i, block := range canonblocks { - canonHeaders[i] = block.Header() - } - if _, err = ancientChain.InsertHeaderChain(canonHeaders); err != nil { - t.Fatal("can't import canon headers:", err) - } - - // Try to insert blocks/receipts of the side chain. - _, err = ancientChain.InsertReceiptChain(sideblocks, sidechainReceipts, uint64(len(sideblocks))) - if err == nil { - t.Fatal("expected error from InsertReceiptChain.") - } - if ancientChain.CurrentSnapBlock().Number.Uint64() != 0 { - t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentSnapBlock().Number) - } - if frozen, err := ancientChain.db.Ancients(); err != nil || frozen != 1 { - t.Fatalf("failed to truncate ancient data, frozen index is %d", frozen) - } - - // Insert blocks/receipts of the canonical chain. - _, err = ancientChain.InsertReceiptChain(canonblocks, canonReceipts, uint64(len(canonblocks))) - if err != nil { - t.Fatalf("can't import canon chain receipts: %v", err) - } - if ancientChain.CurrentSnapBlock().Number.Uint64() != canonblocks[len(canonblocks)-1].NumberU64() { - t.Fatalf("failed to insert ancient recept chain after rollback") - } - if frozen, _ := ancientChain.db.Ancients(); frozen != uint64(len(canonblocks))+1 { - t.Fatalf("wrong ancients count %d", frozen) - } -} - // Tests that importing a very large side fork, which is larger than the canon chain, // but where the difficulty per block is kept low: this means that it will not // overtake the 'canon' chain until after it's passed canon by about 200 blocks. @@ -2142,14 +2044,6 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { } } else if typ == "receipts" { inserter = func(blocks []*types.Block, receipts []types.Receipts) error { - headers := make([]*types.Header, 0, len(blocks)) - for _, block := range blocks { - headers = append(headers, block.Header()) - } - _, err := chain.InsertHeaderChain(headers) - if err != nil { - return err - } _, err = chain.InsertReceiptChain(blocks, receipts, 0) return err } @@ -2316,14 +2210,6 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } } else if typ == "receipts" { inserter = func(blocks []*types.Block, receipts []types.Receipts) error { - headers := make([]*types.Header, 0, len(blocks)) - for _, block := range blocks { - headers = append(headers, block.Header()) - } - i, err := chain.InsertHeaderChain(headers) - if err != nil { - return fmt.Errorf("index %d: %w", i, err) - } _, err = chain.InsertReceiptChain(blocks, receipts, 0) return err } @@ -4320,3 +4206,220 @@ func TestEIP7702(t *testing.T) { t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual) } } + +// Tests the scenario that the synchronization target in snap sync has been changed +// with a chain reorg at the tip. In this case the reorg'd segment should be unmarked +// with canonical flags. +func TestChainReorgSnapSync(t *testing.T) { + testChainReorgSnapSync(t, 0) + testChainReorgSnapSync(t, 32) + testChainReorgSnapSync(t, gomath.MaxUint64) +} + +func testChainReorgSnapSync(t *testing.T, ancientLimit uint64) { + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true))) + + // Configure and generate a sample block chain + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{address: {Balance: funds}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer = types.LatestSigner(gspec.Config) + engine = beacon.New(ethash.NewFaker()) + ) + genDb, blocks, receipts := GenerateChainWithGenesis(gspec, engine, 32, func(i int, block *BlockGen) { + block.SetCoinbase(common.Address{0x00}) + + // If the block number is multiple of 3, send a few bonus transactions to the miner + if i%3 == 2 { + for j := 0; j < i%4+1; j++ { + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) + if err != nil { + panic(err) + } + block.AddTx(tx) + } + } + }) + chainA, receiptsA := GenerateChain(gspec.Config, blocks[len(blocks)-1], engine, genDb, 16, func(i int, gen *BlockGen) { + gen.SetCoinbase(common.Address{0: byte(0xa), 19: byte(i)}) + }) + chainB, receiptsB := GenerateChain(gspec.Config, blocks[len(blocks)-1], engine, genDb, 20, func(i int, gen *BlockGen) { + gen.SetCoinbase(common.Address{0: byte(0xb), 19: byte(i)}) + }) + + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) + defer db.Close() + + chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + defer chain.Stop() + + if n, err := chain.InsertReceiptChain(blocks, receipts, ancientLimit); err != nil { + t.Fatalf("failed to insert receipt %d: %v", n, err) + } + if n, err := chain.InsertReceiptChain(chainA, receiptsA, ancientLimit); err != nil { + t.Fatalf("failed to insert receipt %d: %v", n, err) + } + // If the common ancestor is below the ancient limit, rewind the chain head. + // It's aligned with the behavior in the snap sync + ancestor := blocks[len(blocks)-1].NumberU64() + if ancestor < ancientLimit { + rawdb.WriteLastPivotNumber(db, ancestor) + chain.SetHead(ancestor) + } + if n, err := chain.InsertReceiptChain(chainB, receiptsB, ancientLimit); err != nil { + t.Fatalf("failed to insert receipt %d: %v", n, err) + } + head := chain.CurrentSnapBlock() + if head.Hash() != chainB[len(chainB)-1].Hash() { + t.Errorf("head snap block #%d: header mismatch: want: %v, got: %v", head.Number, chainB[len(chainB)-1].Hash(), head.Hash()) + } + + // Iterate over all chain data components, and cross reference + for i := 0; i < len(blocks); i++ { + num, hash := blocks[i].NumberU64(), blocks[i].Hash() + header := chain.GetHeaderByNumber(num) + if header.Hash() != hash { + t.Errorf("block #%d: header mismatch: want: %v, got: %v", num, hash, header.Hash()) + } + } + for i := 0; i < len(chainA); i++ { + num, hash := chainA[i].NumberU64(), chainA[i].Hash() + header := chain.GetHeaderByNumber(num) + if header == nil { + continue + } + if header.Hash() == hash { + t.Errorf("block #%d: unexpected canonical header: %v", num, hash) + } + } + for i := 0; i < len(chainB); i++ { + num, hash := chainB[i].NumberU64(), chainB[i].Hash() + header := chain.GetHeaderByNumber(num) + if header.Hash() != hash { + t.Errorf("block #%d: header mismatch: want: %v, got: %v", num, hash, header.Hash()) + } + } +} + +// Tests the scenario that all the inserted chain segment are with the configured +// chain cutoff point. In this case the chain segment before the cutoff should +// be persisted without the receipts and bodies; chain after should be persisted +// normally. +func TestInsertChainWithCutoff(t *testing.T) { + testInsertChainWithCutoff(t, 32, 32) // cutoff = 32, ancientLimit = 32 + testInsertChainWithCutoff(t, 32, 64) // cutoff = 32, ancientLimit = 64 (entire chain in ancient) + testInsertChainWithCutoff(t, 32, 65) // cutoff = 32, ancientLimit = 65 (64 blocks in ancient, 1 block in live) +} + +func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64) { + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true))) + + // Configure and generate a sample block chain + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{address: {Balance: funds}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer = types.LatestSigner(gspec.Config) + engine = beacon.New(ethash.NewFaker()) + ) + _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(2*cutoff), func(i int, block *BlockGen) { + block.SetCoinbase(common.Address{0x00}) + + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) + if err != nil { + panic(err) + } + block.AddTx(tx) + }) + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) + defer db.Close() + + cutoffBlock := blocks[cutoff-1] + config := DefaultCacheConfigWithScheme(rawdb.PathScheme) + config.HistoryPruningCutoffNumber = cutoffBlock.NumberU64() + config.HistoryPruningCutoffHash = cutoffBlock.Hash() + + chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + defer chain.Stop() + + var ( + headersBefore []*types.Header + blocksAfter []*types.Block + receiptsAfter []types.Receipts + ) + for i, b := range blocks { + if b.NumberU64() < cutoffBlock.NumberU64() { + headersBefore = append(headersBefore, b.Header()) + } else { + blocksAfter = append(blocksAfter, b) + receiptsAfter = append(receiptsAfter, receipts[i]) + } + } + if n, err := chain.InsertHeadersBeforeCutoff(headersBefore); err != nil { + t.Fatalf("failed to insert headers before cutoff %d: %v", n, err) + } + if n, err := chain.InsertReceiptChain(blocksAfter, receiptsAfter, ancientLimit); err != nil { + t.Fatalf("failed to insert receipt %d: %v", n, err) + } + headSnap := chain.CurrentSnapBlock() + if headSnap.Hash() != blocks[len(blocks)-1].Hash() { + t.Errorf("head snap block #%d: header mismatch: want: %v, got: %v", headSnap.Number, blocks[len(blocks)-1].Hash(), headSnap.Hash()) + } + headHeader := chain.CurrentHeader() + if headHeader.Hash() != blocks[len(blocks)-1].Hash() { + t.Errorf("head header #%d: header mismatch: want: %v, got: %v", headHeader.Number, blocks[len(blocks)-1].Hash(), headHeader.Hash()) + } + headBlock := chain.CurrentBlock() + if headBlock.Hash() != gspec.ToBlock().Hash() { + t.Errorf("head block #%d: header mismatch: want: %v, got: %v", headBlock.Number, gspec.ToBlock().Hash(), headBlock.Hash()) + } + + // Iterate over all chain data components, and cross reference + for i := 0; i < len(blocks); i++ { + num, hash := blocks[i].NumberU64(), blocks[i].Hash() + + // Canonical headers should be visible regardless of cutoff + header := chain.GetHeaderByNumber(num) + if header.Hash() != hash { + t.Errorf("block #%d: header mismatch: want: %v, got: %v", num, hash, header.Hash()) + } + tail, err := db.Tail() + if err != nil { + t.Fatalf("Failed to get chain tail, %v", err) + } + if tail != cutoffBlock.NumberU64() { + t.Fatalf("Unexpected chain tail, want: %d, got: %d", cutoffBlock.NumberU64(), tail) + } + // Block bodies and receipts before the cutoff should be non-existent + if num < cutoffBlock.NumberU64() { + body := chain.GetBody(hash) + if body != nil { + t.Fatalf("Unexpected block body: %d, cutoff: %d", num, cutoffBlock.NumberU64()) + } + receipts := chain.GetReceiptsByHash(hash) + if receipts != nil { + t.Fatalf("Unexpected block receipts: %d, cutoff: %d", num, cutoffBlock.NumberU64()) + } + } else { + body := chain.GetBody(hash) + if body == nil || len(body.Transactions) != 1 { + t.Fatalf("Missed block body: %d, cutoff: %d", num, cutoffBlock.NumberU64()) + } + receipts := chain.GetReceiptsByHash(hash) + if receipts == nil || len(receipts) != 1 { + t.Fatalf("Missed block receipts: %d, cutoff: %d", num, cutoffBlock.NumberU64()) + } + } + } +} diff --git a/core/error.go b/core/error.go index 9693b6a5f..1217ef83d 100644 --- a/core/error.go +++ b/core/error.go @@ -28,8 +28,6 @@ var ( // ErrNoGenesis is returned when there is no Genesis Block. ErrNoGenesis = errors.New("genesis not found in chain") - - errSideChainReceipts = errors.New("side blocks can't be accepted as ancient chain data") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/headerchain.go b/core/headerchain.go index a484da27c..96d66af60 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -259,7 +259,8 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) { } // writeHeadersAndSetHead writes a batch of block headers and applies the last -// header as the chain head if the fork choicer says it's ok to update the chain. +// header as the chain head. +// // Note: This method is not concurrent-safe with inserting blocks simultaneously // into the chain, as side effects caused by reorganisations cannot be emulated // without the real blocks. Hence, writing headers directly should only be done @@ -303,12 +304,14 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F return result, nil } +// ValidateHeaderChain verifies that the supplied header chain is contiguous +// and conforms to consensus rules. func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 { - hash := chain[i].Hash() - parentHash := chain[i-1].Hash() + hash, parentHash := chain[i].Hash(), chain[i-1].Hash() + // Chain broke ancestry, log a message (programming error) and skip insertion log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", hash, "parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", parentHash) @@ -333,7 +336,6 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { return i, err } } - return 0, nil } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 86b4128a9..ef73b4451 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -793,6 +793,36 @@ func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *type return nil } +// WriteAncientHeaderChain writes the supplied headers along with nil block +// bodies and receipts into the ancient store. It's supposed to be used for +// storing chain segment before the chain cutoff. +// !!! ptd is the td of the parent block of headers[0] +func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header, ptd *big.Int) (int64, error) { + var tdSum = new(big.Int).Set(ptd) + + return db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for _, header := range headers { + num := header.Number.Uint64() + if err := op.AppendRaw(ChainFreezerHashTable, num, header.Hash().Bytes()); err != nil { + return fmt.Errorf("can't add block %d hash: %v", num, err) + } + if err := op.Append(ChainFreezerHeaderTable, num, header); err != nil { + return fmt.Errorf("can't append block header %d: %v", num, err) + } + if err := op.AppendRaw(ChainFreezerBodiesTable, num, nil); err != nil { + return fmt.Errorf("can't append block body %d: %v", num, err) + } + if err := op.AppendRaw(ChainFreezerReceiptTable, num, nil); err != nil { + return fmt.Errorf("can't append block %d receipts: %v", num, err) + } + if err := op.Append(ChainFreezerDifficultyTable, num, tdSum); err != nil { + return fmt.Errorf("can't append block %d td: %v", num, err) + } + } + return nil + }) +} + // DeleteBlock removes all block data associated with a hash. func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { DeleteReceipts(db, hash, number) diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 9dbb8c5a8..3ffac693b 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -496,6 +496,52 @@ func TestAncientStorage(t *testing.T) { } } +func TestWriteAncientHeaderChain(t *testing.T) { + db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), t.TempDir(), "", false) + if err != nil { + t.Fatalf("failed to create database with ancient backend") + } + defer db.Close() + + // Create a test block + var headers []*types.Header + headers = append(headers, &types.Header{ + Number: big.NewInt(0), + Extra: []byte("test block"), + UncleHash: types.EmptyUncleHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, + }) + headers = append(headers, &types.Header{ + Number: big.NewInt(1), + Extra: []byte("test block"), + UncleHash: types.EmptyUncleHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, + }) + // Write and verify the header in the database + ptd := new(big.Int) + WriteAncientHeaderChain(db, headers, ptd) + + for _, header := range headers { + if blob := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); len(blob) == 0 { + t.Fatalf("no header returned") + } + if h := ReadCanonicalHash(db, header.Number.Uint64()); h != header.Hash() { + t.Fatalf("no canonical hash returned") + } + if blob := ReadBodyRLP(db, header.Hash(), header.Number.Uint64()); len(blob) != 0 { + t.Fatalf("unexpected body returned") + } + if blob := ReadReceiptsRLP(db, header.Hash(), header.Number.Uint64()); len(blob) != 0 { + t.Fatalf("unexpected body returned") + } + if blob := ReadTdRLP(db, header.Hash(), header.Number.Uint64()); len(blob) == 0 { + t.Fatalf("unexpected td returned") + } + } +} + func TestCanonicalHashIteration(t *testing.T) { var cases = []struct { from, to uint64 diff --git a/core/txindexer.go b/core/txindexer.go index d0fce302f..31f069995 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -58,9 +58,10 @@ type txIndexer struct { // newTxIndexer initializes the transaction indexer. func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { + cutoff, _ := chain.HistoryPruningCutoff() indexer := &txIndexer{ limit: limit, - cutoff: chain.HistoryPruningCutoff(), + cutoff: cutoff, db: chain.db, progress: make(chan chan TxIndexProgress), term: make(chan chan struct{}), diff --git a/eth/api_backend.go b/eth/api_backend.go index 0a931108b..7d120be4c 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" @@ -94,13 +93,7 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb } return block, nil } - var bn uint64 - if number == rpc.EarliestBlockNumber { - bn = b.eth.blockchain.HistoryPruningCutoff() - } else { - bn = uint64(number) - } - return b.eth.blockchain.GetHeaderByNumber(bn), nil + return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil } func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { @@ -152,27 +145,11 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe } return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } - bn := uint64(number) // the resolved number - if number == rpc.EarliestBlockNumber { - bn = b.eth.blockchain.HistoryPruningCutoff() - } - block := b.eth.blockchain.GetBlockByNumber(bn) - if block == nil && bn < b.eth.blockchain.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } - return block, nil + return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil } func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - number := b.eth.blockchain.GetBlockNumber(hash) - if number == nil { - return nil, nil - } - block := b.eth.blockchain.GetBlock(hash, *number) - if block == nil && *number < b.eth.blockchain.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } - return block, nil + return b.eth.blockchain.GetBlockByHash(hash), nil } // GetBody returns body of a block. It does not resolve special block numbers. @@ -180,14 +157,10 @@ func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rp if number < 0 || hash == (common.Hash{}) { return nil, errors.New("invalid arguments; expect hash and no special block numbers") } - body := b.eth.blockchain.GetBody(hash) - if body == nil { - if uint64(number) < b.eth.blockchain.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } - return nil, errors.New("block body not found") + if body := b.eth.blockchain.GetBody(hash); body != nil { + return body, nil } - return body, nil + return nil, errors.New("block body not found") } func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { @@ -204,9 +177,6 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r } block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64()) if block == nil { - if header.Number.Uint64() < b.eth.blockchain.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } return nil, errors.New("header found, but block body is missing") } return block, nil @@ -266,10 +236,6 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } -func (b *EthAPIBackend) HistoryPruningCutoff() uint64 { - return b.eth.blockchain.HistoryPruningCutoff() -} - func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return b.eth.blockchain.GetReceiptsByHash(hash), nil } diff --git a/eth/backend.go b/eth/backend.go index 5c129c0e0..720e293a7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -163,13 +163,18 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // Validate history pruning configuration. - var historyPruningCutoff uint64 + var ( + cutoffNumber uint64 + cutoffHash common.Hash + ) if config.HistoryMode == ethconfig.PostMergeHistory { prunecfg, ok := ethconfig.HistoryPrunePoints[genesisHash] if !ok { return nil, fmt.Errorf("no history pruning point is defined for genesis %x", genesisHash) } - historyPruningCutoff = prunecfg.BlockNumber + cutoffNumber = prunecfg.BlockNumber + cutoffHash = prunecfg.BlockHash + log.Info("Chain cutoff configured", "number", cutoffNumber, "hash", cutoffHash) } // Set networkID to chainID by default. @@ -219,16 +224,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { EnablePreimageRecording: config.EnablePreimageRecording, } cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: scheme, - HistoryPruningCutoff: historyPruningCutoff, + TrieCleanLimit: config.TrieCleanCache, + TrieCleanNoPrefetch: config.NoPrefetch, + TrieDirtyLimit: config.TrieDirtyCache, + TrieDirtyDisabled: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + Preimages: config.Preimages, + StateHistory: config.StateHistory, + StateScheme: scheme, + HistoryPruningCutoffNumber: cutoffNumber, + HistoryPruningCutoffHash: cutoffHash, } ) if config.VMTrace != "" { @@ -265,7 +271,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { HashScheme: scheme == rawdb.HashScheme, } chainView := eth.newChainView(eth.blockchain.CurrentBlock()) - historyCutoff := eth.blockchain.HistoryPruningCutoff() + historyCutoff, _ := eth.blockchain.HistoryPruningCutoff() var finalBlock uint64 if fb := eth.blockchain.CurrentFinalBlock(); fb != nil { finalBlock = fb.Number.Uint64() @@ -643,7 +649,7 @@ func (s *Ethereum) updateFilterMapsHeads() { if head == nil || newHead.Hash() != head.Hash() { head = newHead chainView := s.newChainView(head) - historyCutoff := s.blockchain.HistoryPruningCutoff() + historyCutoff, _ := s.blockchain.HistoryPruningCutoff() var finalBlock uint64 if fb := s.blockchain.CurrentFinalBlock(); fb != nil { finalBlock = fb.Number.Uint64() diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 89d5cfc3c..a56430ad7 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -272,8 +272,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { // fetchBeaconHeaders feeds skeleton headers to the downloader queue for scheduling // until sync errors or is finished. func (d *Downloader) fetchBeaconHeaders(from uint64) error { - var head *types.Header - _, tail, _, err := d.skeleton.Bounds() + head, tail, _, err := d.skeleton.Bounds() if err != nil { return err } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 8db0b9797..ea569430a 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -626,7 +626,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * fetchers = append(fetchers, func() error { return d.processSnapSyncContent() }) } else if mode == FullSync { - fetchers = append(fetchers, func() error { return d.processFullSyncContent(ttd, beaconMode) }) + fetchers = append(fetchers, func() error { return d.processFullSyncContent() }) } return d.spawnSync(fetchers) } @@ -1310,47 +1310,12 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode // In case of header only syncing, validate the chunk immediately if mode == SnapSync { - // Although the received headers might be all valid, a legacy - // PoW/PoA sync must not accept post-merge headers. Make sure - // that any transition is rejected at this point. - var ( - rejected []*types.Header - td *big.Int - ) - if !beaconMode && ttd != nil { - td = d.blockchain.GetTd(chunkHeaders[0].ParentHash, chunkHeaders[0].Number.Uint64()-1) - if td == nil { - // This should never really happen, but handle gracefully for now - log.Error("Failed to retrieve parent header TD", "number", chunkHeaders[0].Number.Uint64()-1, "hash", chunkHeaders[0].ParentHash) - return fmt.Errorf("%w: parent TD missing", errInvalidChain) - } - for i, header := range chunkHeaders { - td = new(big.Int).Add(td, header.Difficulty) - if td.Cmp(ttd) >= 0 { - // Terminal total difficulty reached, allow the last header in - if new(big.Int).Sub(td, header.Difficulty).Cmp(ttd) < 0 { - chunkHeaders, rejected = chunkHeaders[:i+1], chunkHeaders[i+1:] - if len(rejected) > 0 { - // Make a nicer user log as to the first TD truly rejected - td = new(big.Int).Add(td, rejected[0].Difficulty) - } - } else { - chunkHeaders, rejected = chunkHeaders[:i], chunkHeaders[i:] - } - break - } - } - } if len(chunkHeaders) > 0 { if n, err := d.blockchain.InsertHeaderChain(chunkHeaders); err != nil { log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } } - if len(rejected) != 0 { - log.Info("Legacy sync reached merge threshold", "number", rejected[0].Number, "hash", rejected[0].Hash(), "td", td, "ttd", ttd) - return ErrMergeTransition - } } // If we've reached the allowed number of pending headers, stall a bit for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { @@ -1363,7 +1328,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } // Otherwise insert the headers for content retrieval inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) - if len(inserts) != len(chunkHeaders) { + if inserts != len(chunkHeaders) { return fmt.Errorf("%w: stale headers", errBadPeer) } @@ -1390,7 +1355,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } // processFullSyncContent takes fetch results from the queue and imports them into the chain. -func (d *Downloader) processFullSyncContent(ttd *big.Int, beaconMode bool) error { +func (d *Downloader) processFullSyncContent() error { for { results := d.queue.Results(true) if len(results) == 0 { @@ -1399,44 +1364,9 @@ func (d *Downloader) processFullSyncContent(ttd *big.Int, beaconMode bool) error if d.chainInsertHook != nil { d.chainInsertHook(results) } - // Although the received blocks might be all valid, a legacy PoW/PoA sync - // must not accept post-merge blocks. Make sure that pre-merge blocks are - // imported, but post-merge ones are rejected. - var ( - rejected []*fetchResult - td *big.Int - ) - if !beaconMode && ttd != nil { - td = d.blockchain.GetTd(results[0].Header.ParentHash, results[0].Header.Number.Uint64()-1) - if td == nil { - // This should never really happen, but handle gracefully for now - log.Error("Failed to retrieve parent block TD", "number", results[0].Header.Number.Uint64()-1, "hash", results[0].Header.ParentHash) - return fmt.Errorf("%w: parent TD missing", errInvalidChain) - } - for i, result := range results { - td = new(big.Int).Add(td, result.Header.Difficulty) - if td.Cmp(ttd) >= 0 { - // Terminal total difficulty reached, allow the last block in - if new(big.Int).Sub(td, result.Header.Difficulty).Cmp(ttd) < 0 { - results, rejected = results[:i+1], results[i+1:] - if len(rejected) > 0 { - // Make a nicer user log as to the first TD truly rejected - td = new(big.Int).Add(td, rejected[0].Header.Difficulty) - } - } else { - results, rejected = results[:i], results[i:] - } - break - } - } - } if err := d.importBlockResults(results); err != nil { return err } - if len(rejected) != 0 { - log.Info("Legacy sync reached merge threshold", "number", rejected[0].Header.Number, "hash", rejected[0].Header.Hash(), "td", td, "ttd", ttd) - return ErrMergeTransition - } } } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index a07a529a7..1f8e7ffc2 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -72,7 +72,7 @@ type fetchResult struct { Withdrawals types.Withdrawals } -func newFetchResult(header *types.Header, fastSync bool) *fetchResult { +func newFetchResult(header *types.Header, snapSync bool) *fetchResult { item := &fetchResult{ Header: header, } @@ -81,7 +81,7 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { } else if header.WithdrawalsHash != nil { item.Withdrawals = make(types.Withdrawals, 0) } - if fastSync && !header.EmptyReceipts() { + if snapSync && !header.EmptyReceipts() { item.pending.Store(item.pending.Load() | (1 << receiptType)) } return item @@ -301,12 +301,12 @@ func (q *queue) RetrieveHeaders() ([]*types.Header, []common.Hash, int) { // Schedule adds a set of headers for the download queue for scheduling, returning // the new headers encountered. -func (q *queue) Schedule(headers []*types.Header, hashes []common.Hash, from uint64) []*types.Header { +func (q *queue) Schedule(headers []*types.Header, hashes []common.Hash, from uint64) int { q.lock.Lock() defer q.lock.Unlock() // Insert all the headers prioritised by the contained block number - inserts := make([]*types.Header, 0, len(headers)) + var inserts int for i, header := range headers { // Make sure chain order is honoured and preserved throughout hash := hashes[i] @@ -336,7 +336,7 @@ func (q *queue) Schedule(headers []*types.Header, hashes []common.Hash, from uin q.receiptTaskQueue.Push(header, -int64(header.Number.Uint64())) } } - inserts = append(inserts, header) + inserts++ q.headerHead = hash from++ } @@ -389,7 +389,7 @@ func (q *queue) Results(block bool) []*fetchResult { q.resultSize = common.StorageSize(blockCacheSizeWeight)*size + (1-common.StorageSize(blockCacheSizeWeight))*q.resultSize } - // Using the newly calibrated resultsize, figure out the new throttle limit + // Using the newly calibrated result size, figure out the new throttle limit // on the result cache throttleThreshold := uint64((common.StorageSize(blockCacheMemory) + q.resultSize - 1) / q.resultSize) throttleThreshold = q.resultCache.SetThrottleThreshold(throttleThreshold) diff --git a/eth/downloader/resultstore.go b/eth/downloader/resultstore.go index e4323c04e..36c382fef 100644 --- a/eth/downloader/resultstore.go +++ b/eth/downloader/resultstore.go @@ -76,7 +76,7 @@ func (r *resultStore) SetThrottleThreshold(threshold uint64) uint64 { // throttled - if true, the store is at capacity, this particular header is not prio now // item - the result to store data into // err - any error that occurred -func (r *resultStore) AddFetch(header *types.Header, fastSync bool) (stale, throttled bool, item *fetchResult, err error) { +func (r *resultStore) AddFetch(header *types.Header, snapSync bool) (stale, throttled bool, item *fetchResult, err error) { r.lock.Lock() defer r.lock.Unlock() @@ -86,7 +86,7 @@ func (r *resultStore) AddFetch(header *types.Header, fastSync bool) (stale, thro return stale, throttled, item, err } if item == nil { - item = newFetchResult(header, fastSync) + item = newFetchResult(header, snapSync) r.items[index] = item } return stale, throttled, item, err diff --git a/eth/filters/api.go b/eth/filters/api.go index d432874c1..7f47d1be6 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -437,9 +436,6 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type if begin > 0 && end > 0 && begin > end { return nil, errInvalidBlockRange } - if begin > 0 && begin < int64(api.events.backend.HistoryPruningCutoff()) { - return nil, ðconfig.PrunedHistoryError{} - } // Construct the range filter filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index e44b37d04..c094d763c 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" ) @@ -87,9 +86,6 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, errors.New("unknown block") } - if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } return f.blockLogs(ctx, header) } @@ -118,13 +114,6 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return 0, errors.New("safe header not found") } return hdr.Number.Uint64(), nil - case rpc.EarliestBlockNumber.Int64(): - earliest := f.sys.backend.HistoryPruningCutoff() - hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(earliest)) - if hdr == nil { - return 0, errors.New("earliest header not found") - } - return hdr.Number.Uint64(), nil default: if number < 0 { return 0, errors.New("negative block number") diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 90a392169..4b2c3d83c 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -66,7 +65,6 @@ type Backend interface { CurrentHeader() *types.Header ChainConfig() *params.ChainConfig - HistoryPruningCutoff() uint64 SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription @@ -321,14 +319,6 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ return nil, errPendingLogsUnsupported } - if from == rpc.EarliestBlockNumber { - from = rpc.BlockNumber(es.backend.HistoryPruningCutoff()) - } - // Queries beyond the pruning cutoff are not supported. - if uint64(from) < es.backend.HistoryPruningCutoff() { - return nil, ðconfig.PrunedHistoryError{} - } - // only interested in new mined logs if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index b43e86d8b..0985ed2b9 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -641,7 +641,10 @@ func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { panic("implement me") } -func (b testBackend) HistoryPruningCutoff() uint64 { return b.chain.HistoryPruningCutoff() } +func (b testBackend) HistoryPruningCutoff() uint64 { + cutoff, _ := b.chain.HistoryPruningCutoff() + return cutoff +} func TestEstimateGas(t *testing.T) { t.Parallel() diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index f11fcc858..19f6028ac 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -88,7 +88,6 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine - HistoryPruningCutoff() uint64 // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by From b0bac9a250ff64aec913f9615f4c6e42317d1a89 Mon Sep 17 00:00:00 2001 From: Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:48:35 +0530 Subject: [PATCH 272/354] build: upgrade to golangci-lint v2 (#31530) --- .golangci.yml | 131 +++++++++++++++++++++++++------------------- build/checksums.txt | 106 +++++++++++++++++------------------ 2 files changed, 127 insertions(+), 110 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index a702da524..5ed06537b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,31 +1,25 @@ # This file configures github.com/golangci/golangci-lint. - +version: '2' run: - timeout: 20m tests: true - linters: - disable-all: true + default: none enable: - - goimports - - gosimple - - govet - - ineffassign - - misspell - - unconvert - - typecheck - - unused - - staticcheck - bidichk - - durationcheck - copyloopvar - - whitespace - - revive # only certain checks enabled - durationcheck - gocheckcompilerdirectives - - reassign + - govet + - ineffassign - mirror + - misspell + - reassign + - revive # only certain checks enabled + - staticcheck + - unconvert + - unused - usetesting + - whitespace ### linters we tried and will not be using: ### # - structcheck # lots of false positives @@ -36,44 +30,67 @@ linters: # - exhaustive # silly check # - makezero # false positives # - nilerr # several intentional - -linters-settings: - gofmt: - simplify: true - revive: - enable-all-rules: false - # here we enable specific useful rules - # see https://golangci-lint.run/usage/linters/#revive for supported rules + settings: + staticcheck: + checks: + # disable Quickfixes + - -QF1* + revive: + enable-all-rules: false + # here we enable specific useful rules + # see https://golangci-lint.run/usage/linters/#revive for supported rules + rules: + - name: receiver-naming + severity: warning + disabled: false + exclude: + - '' + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling rules: - - name: receiver-naming - severity: warning - disabled: false - exclude: [""] - -issues: - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - exclude-dirs-use-default: true - exclude-files: - - core/genesis_alloc.go - exclude-rules: - - path: crypto/bn256/cloudflare/optate.go - linters: - - deadcode - - staticcheck - - path: crypto/bn256/ - linters: - - revive - - path: cmd/utils/flags.go - text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - - path: cmd/utils/flags.go - text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - - path: internal/build/pgp.go - text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - - path: core/vm/contracts.go - text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.' - exclude: - - 'SA1019: event.TypeMux is deprecated: use Feed' - - 'SA1019: strings.Title is deprecated' - - 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.' - - 'SA1029: should not use built-in type string as key for value' + - linters: + - deadcode + - staticcheck + path: crypto/bn256/cloudflare/optate.go + - linters: + - revive + path: crypto/bn256/ + - path: cmd/utils/flags.go + text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." + - path: cmd/utils/flags.go + text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead." + - path: internal/build/pgp.go + text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' + - path: core/vm/contracts.go + text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.' + - path: (.+)\.go$ + text: 'SA1019: event.TypeMux is deprecated: use Feed' + - path: (.+)\.go$ + text: 'SA1019: strings.Title is deprecated' + - path: (.+)\.go$ + text: 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.' + - path: (.+)\.go$ + text: 'SA1029: should not use built-in type string as key for value' + paths: + - core/genesis_alloc.go + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - goimports + settings: + gofmt: + simplify: true + exclusions: + generated: lax + paths: + - core/genesis_alloc.go + - third_party$ + - builtin$ + - examples$ diff --git a/build/checksums.txt b/build/checksums.txt index 5ccb85bba..6d3b718c3 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -54,60 +54,60 @@ db128981033ac82a64688a123f631e61297b6b8f52ca913145e57caa8ce94cc3 go1.24.1.windo e28c4e6d0b913955765b46157ab88ae59bb636acaa12d7bec959aa6900f1cebd go1.24.1.windows-arm64.zip 6d352c1f154a102a5b90c480cc64bab205ccf2681e34e78a3a4d3f1ddfbc81e4 go1.24.1.windows-arm64.msi -# version:golangci 1.64.6 +# version:golangci 2.0.2 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.64.6/ -08f9459e7125fed2612abd71596e04d172695921aff82120d1c1e5e9b6fff2a3 golangci-lint-1.64.6-darwin-amd64.tar.gz -8c10d0c7c3935b8c2269d628b6a06a8f48d8fb4cc31af02fe4ce0cd18b0704c1 golangci-lint-1.64.6-darwin-arm64.tar.gz -c07fcabb55deb8d2c4d390025568e76162d7f91b1d14bd2311be45d8d440a624 golangci-lint-1.64.6-freebsd-386.tar.gz -8ed1ef1102e1a42983ffcaae8e06de6a540334c3a69e205c610b8a7c92d469cd golangci-lint-1.64.6-freebsd-amd64.tar.gz -8f8dda66d1b4a85cc8a1daf1b69af6559c3eb0a41dd8033148a9ad85cfc0e1d9 golangci-lint-1.64.6-freebsd-armv6.tar.gz -59e8ca1fa254661b2a55e96515b14a10cd02221d443054deac5b28c3c3e12d6b golangci-lint-1.64.6-freebsd-armv7.tar.gz -e3d323d5f132e9b7593141bfe1d19c8460e65a55cea1008ec96945fed563f981 golangci-lint-1.64.6-illumos-amd64.tar.gz -5ce910f2a864c5fbeb32a30cbd506e1b2ef215f7a0f422cd5be6370b13db6f03 golangci-lint-1.64.6-linux-386.deb -2caab682a26b9a5fb94ba24e3a7e1404fa9eab2c12e36ae1c5548d80a1be190c golangci-lint-1.64.6-linux-386.rpm -2d82d0a4716e6d9b70c95103054855cb4b5f20f7bbdee42297f0189955bd14b6 golangci-lint-1.64.6-linux-386.tar.gz -9cd82503e9841abcaa57663fc899587fe90363c26d86a793a98d3080fd25e907 golangci-lint-1.64.6-linux-amd64.deb -981aaca5e5202d4fbb162ec7080490eb67ef5d32add5fb62fb02210597acc9da golangci-lint-1.64.6-linux-amd64.rpm -71e290acbacb7b3ba4f68f0540fb74dc180c4336ac8a6f3bdcd7fcc48b15148d golangci-lint-1.64.6-linux-amd64.tar.gz -718016bb06c1f598a8d23c7964e2643de621dbe5808688cb38857eb0bb773c84 golangci-lint-1.64.6-linux-arm64.deb -ddc0e7b4b10b47cf894aea157e89e3674bbb60f8f5c480110c21c49cc2c1634d golangci-lint-1.64.6-linux-arm64.rpm -99a7ff13dec7a8781a68408b6ecb8a1c5e82786cba3189eaa91d5cdcc24362ce golangci-lint-1.64.6-linux-arm64.tar.gz -90e360f89c244394912b8709fb83a900b6d56cf19141df2afaf9e902ef3057b1 golangci-lint-1.64.6-linux-armv6.deb -46546ff7c98d873ffcdbee06b39dc1024fc08db4fbf1f6309360a44cf976b5c2 golangci-lint-1.64.6-linux-armv6.rpm -e45c1a42868aca0b0ee54d14fb89da216f3b4409367cd7bce3b5f36788b4fc92 golangci-lint-1.64.6-linux-armv6.tar.gz -3cf6ddbbbf358db3de4b64a24f9683bbe2da3f003cfdee86cb610124b57abafb golangci-lint-1.64.6-linux-armv7.deb -508b6712710da10f11aab9ea5e63af415c932dfe7fff718e649d3100b838f797 golangci-lint-1.64.6-linux-armv7.rpm -da9a8bbee86b4dfee73fbc17e0856ec84c5b04919eb09bf3dd5904c39ce41753 golangci-lint-1.64.6-linux-armv7.tar.gz -ad496a58284e1e9c8ac6f993fec429dcd96c85a8c4715dbb6530a5af0dae7fbd golangci-lint-1.64.6-linux-loong64.deb -3bd70fa737b224750254dce616d9a188570e49b894b0cdb2fd04155e2c061350 golangci-lint-1.64.6-linux-loong64.rpm -a535af973499729f2215a84303eb0de61399057aad6901ddea1b4f73f68d5f2c golangci-lint-1.64.6-linux-loong64.tar.gz -6ad2a1cd37ca30303a488abfca2de52aff57519901c6d8d2608656fe9fb05292 golangci-lint-1.64.6-linux-mips64.deb -5f18369f0ca010a02c267352ebe6e3e0514c6debff49899c9e5520906c0da287 golangci-lint-1.64.6-linux-mips64.rpm -3449d6c13307b91b0e8817f8911c07c3412cdb6931b8d101e42db3e9762e91ad golangci-lint-1.64.6-linux-mips64.tar.gz -d4712a348f65dcaf9f6c58f1cfd6d0984d54a902873dca5e76f0d686f5c59499 golangci-lint-1.64.6-linux-mips64le.deb -57cea4538894558cb8c956d6b69c5509e4304546abe4a467478fc9ada0c736d6 golangci-lint-1.64.6-linux-mips64le.rpm -bc030977d44535b2152fddb2732f056d193c043992fe638ddecea21a40ef09fe golangci-lint-1.64.6-linux-mips64le.tar.gz -1ceb4e492efa527d246c61798c581f49113756fab8c39bb3eefdb1fa97041f92 golangci-lint-1.64.6-linux-ppc64le.deb -454e1c2b3583a8644e0c33a970fb4ce35b8f11848e1a770d9095d99d159ad0ab golangci-lint-1.64.6-linux-ppc64le.rpm -fddf30d35923eb6c7bb57520d8645768f802bf86c4cbf5a3a13049efb9e71b82 golangci-lint-1.64.6-linux-ppc64le.tar.gz -bd75f0dd6f65bee5821c433803b28f3c427ef3582764c3d0e7f7fae1c9d468b6 golangci-lint-1.64.6-linux-riscv64.deb -58457207c225cbd5340c8dcb75d9a44aa890d604e28464115a3a9762febaed04 golangci-lint-1.64.6-linux-riscv64.rpm -82639518a613a6705b7e2de5b28c278e875d782a5c97e9c1b2ac10b4ecd7852f golangci-lint-1.64.6-linux-riscv64.tar.gz -131d69204f8ced200b1437731e987cc886edac30dc87e6e1dcbd4f833d351713 golangci-lint-1.64.6-linux-s390x.deb -ca6caf28ca7a1df7cff720f8fd6ac4b8f2eac10c8cbfe7d2eade70876aded570 golangci-lint-1.64.6-linux-s390x.rpm -ed966d28a6512bc2b1120029a9f78ed77f2015e330b589a731d67d59be30b0b1 golangci-lint-1.64.6-linux-s390x.tar.gz -b181132b41943fc77ace7f9f5523085d12d3613f27774a0e35e17dd5e65ba589 golangci-lint-1.64.6-netbsd-386.tar.gz -f7b81c426006e3c699dc8665797a462aecba8c2cd23ac4971472e55184d95bc9 golangci-lint-1.64.6-netbsd-amd64.tar.gz -663d6fb4c3bef57b8aacdb1b1a4634075e55d294ed170724b443374860897ca6 golangci-lint-1.64.6-netbsd-arm64.tar.gz -8c7a76ee822568cc19352bbb9b2b0863dc5e185eb07782adbbaf648afd02ebcd golangci-lint-1.64.6-netbsd-armv6.tar.gz -0ce26d56ce78e516529e087118ba3f1bcd71d311b4c5b2bde6ec24a6e8966d85 golangci-lint-1.64.6-netbsd-armv7.tar.gz -135d5d998168683f46e4fab308cef5aa3c282025b7de6b258f976aadfb820db7 golangci-lint-1.64.6-source.tar.gz -ccdb0cc249531a205304a76308cfa7cda830083d083d557884416a2461148263 golangci-lint-1.64.6-windows-386.zip -2d88f282e08e1853c70bc7c914b5f58beaa6509903d56098aeb9bc3df30ea9d5 golangci-lint-1.64.6-windows-amd64.zip -6a3c6e7afc6916392679d7d6b95ac239827644e3e50ec4e8ca6ab1e4e6db65fe golangci-lint-1.64.6-windows-arm64.zip -9c9c1ef9687651566987f93e76252f7526c386901d7d8aeee044ca88115da4b1 golangci-lint-1.64.6-windows-armv6.zip -4f0df114155791799dfde8cd8cb6307fecfb17fed70b44205486ec925e2f39cf golangci-lint-1.64.6-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v2.0.2/ +a88cbdc86b483fe44e90bf2dcc3fec2af8c754116e6edf0aa6592cac5baa7a0e golangci-lint-2.0.2-darwin-amd64.tar.gz +664550e7954f5f4451aae99b4f7382c1a47039c66f39ca605f5d9af1a0d32b49 golangci-lint-2.0.2-darwin-arm64.tar.gz +bda0f0f27d300502faceda8428834a76ca25986f6d9fc2bd41d201c3ed73f08e golangci-lint-2.0.2-freebsd-386.tar.gz +1cbd0c7ade3fb027d61d38a646ec1b51be5846952b4b04a5330e7f4687f2270c golangci-lint-2.0.2-freebsd-amd64.tar.gz +1e828a597726198b2e35acdbcc5f3aad85244d79846d2d2bdb05241c5a535f9e golangci-lint-2.0.2-freebsd-armv6.tar.gz +848b49315dc5cddd0c9ce35e96ab33d584db0ea8fb57bcbf9784f1622bec0269 golangci-lint-2.0.2-freebsd-armv7.tar.gz +cabf9a6beab574c7f98581eb237919e580024759e3cdc05c4d516b044dce6770 golangci-lint-2.0.2-illumos-amd64.tar.gz +2fde80d15ed6527791f106d606120620e913c3a663c90a8596861d0a4461169e golangci-lint-2.0.2-linux-386.deb +804bc6e350a8c613aaa0a33d8d45414a80157b0ba1b2c2335ac859f85ad98ebd golangci-lint-2.0.2-linux-386.rpm +e64beb72fecf581e57d88ae3adb1c9d4bf022694b6bd92e3c8e460910bbdc37d golangci-lint-2.0.2-linux-386.tar.gz +9c55aed174d7a52bb1d4006b36e7edee9023631f6b814a80cb39c9860d6f75c3 golangci-lint-2.0.2-linux-amd64.deb +c55a2ef741a687b4c679696931f7fd4a467babd64c9457cf17bb9632fd1cecd1 golangci-lint-2.0.2-linux-amd64.rpm +89cc8a7810dc63b9a37900da03e37c3601caf46d42265d774e0f1a5d883d53e2 golangci-lint-2.0.2-linux-amd64.tar.gz +a3e78583c4e7ea1b63e82559f126bb3a5b12788676f158526752d53e67824b99 golangci-lint-2.0.2-linux-arm64.deb +bd5dd52b5c9f18aa7a2904eda9a9f91c628e98623fe70b7afcbb847e2de84422 golangci-lint-2.0.2-linux-arm64.rpm +789d5b91219ac68c2336f77d41cd7e33a910420594780f455893f8453d09595b golangci-lint-2.0.2-linux-arm64.tar.gz +534cd4c464a66178714ed68152c1ed7aa73e5700bf409e4ed1a8363adf96afca golangci-lint-2.0.2-linux-armv6.deb +cf7d02905a5fc80b96c9a64621693b4cc7337b1ce29986c19fd72608dafe66c5 golangci-lint-2.0.2-linux-armv6.rpm +a0d81cb527d8fe878377f2356b5773e219b0b91832a6b59e7b9bcf9a90fe0b0e golangci-lint-2.0.2-linux-armv6.tar.gz +dedd5be7fff8cba8fe15b658a59347ea90d7d02a9fff87f09c7687e6da05a8b6 golangci-lint-2.0.2-linux-armv7.deb +85521b6f3ad2f5a2bc9bfe14b9b08623f764964048f75ed6dfcfaf8eb7d57cc1 golangci-lint-2.0.2-linux-armv7.rpm +96471046c7780dda4ea680f65e92c2ef56ff58d40bcffaf6cfe9d6d48e3c27aa golangci-lint-2.0.2-linux-armv7.tar.gz +815d914a7738e4362466b2d11004e8618b696b49e8ace13df2c2b25f28fb1e17 golangci-lint-2.0.2-linux-loong64.deb +f16381e3d8a0f011b95e086d83d620248432b915d01f4beab4d29cfe4dc388b0 golangci-lint-2.0.2-linux-loong64.rpm +1bd8d7714f9c92db6a0f23bae89f39c85ba047bec8eeb42b8748d30ae3228d18 golangci-lint-2.0.2-linux-loong64.tar.gz +ea6e9d4aabb526aa298e47e8b026d8893d918c5eb919ba0ab403e315def74cc5 golangci-lint-2.0.2-linux-mips64.deb +519d8d53af83fdc9c25cc3fba8b663331ac22ef68131d4b0084cb6f425b6f79a golangci-lint-2.0.2-linux-mips64.rpm +80d655a0a1ac1b19dcef4b58fa2a7dadb646cc50ad08d460b5c53cdb421165e4 golangci-lint-2.0.2-linux-mips64.tar.gz +aa0e75384bb482c865d4dfc95d23ceb25666bf20461b67a832f0eea6670312ec golangci-lint-2.0.2-linux-mips64le.deb +f2a8b500fb69bdea1b01df6267aaa5218fa4a58aeb781c1a20d0d802fe465a52 golangci-lint-2.0.2-linux-mips64le.rpm +e66a0c0c9a275f02d27a7caa9576112622306f001d73dfc082cf1ae446fc1242 golangci-lint-2.0.2-linux-mips64le.tar.gz +e85ad51aac6428be2d8a37000d053697371a538a5bcbc1644caa7c5e77f6d0af golangci-lint-2.0.2-linux-ppc64le.deb +906798365eac1944af2a9b9a303e6fd49ec9043307bc681b7a96277f7f8beea5 golangci-lint-2.0.2-linux-ppc64le.rpm +f7f1a271b0af274d6c9ce000f5dc6e1fb194350c67bcc62494f96f791882ba92 golangci-lint-2.0.2-linux-ppc64le.tar.gz +eea8bf643a42bf05de9780530db22923e5ab0d588f0e173594dc6518f2a25d2a golangci-lint-2.0.2-linux-riscv64.deb +4ff40f9fe2954400836e2a011ba4744d00ffab5068a51368552dfce6aba3b81b golangci-lint-2.0.2-linux-riscv64.rpm +531d8f225866674977d630afbf0533eb02f9bec607fb13895f7a2cd7b2e0a648 golangci-lint-2.0.2-linux-riscv64.tar.gz +6f827647046c603f40d97ea5aadc6f48cd0bb5d19f7a3d56500c3b833d2a0342 golangci-lint-2.0.2-linux-s390x.deb +387a090e9576d19ca86aac738172e58e07c19f2784a13bb387f4f0d75fb9c8d3 golangci-lint-2.0.2-linux-s390x.rpm +57de1fb7722a9feb2d11ed0a007a93959d05b9db5929a392abc222e30012467e golangci-lint-2.0.2-linux-s390x.tar.gz +ed95e0492ea86bf79eb661f0334474b2a4255093685ff587eccd797c5a54db7e golangci-lint-2.0.2-netbsd-386.tar.gz +eab81d729778166415d349a80e568b2f2b3a781745a9be3212a92abb1e732daf golangci-lint-2.0.2-netbsd-amd64.tar.gz +d20add73f7c2de2c3b01ed4fd7b63ffcf0a6597d5ea228d1699e92339a3cd047 golangci-lint-2.0.2-netbsd-arm64.tar.gz +4e4f44e6057879cd62424ff1800a767d25a595c0e91d6d48809eea9186b4c739 golangci-lint-2.0.2-netbsd-armv6.tar.gz +51ec17b16d8743ae4098a0171f04f0ed4d64561e3051b982778b0e6c306a1b03 golangci-lint-2.0.2-netbsd-armv7.tar.gz +5482cf27b93fae1765c70ee2a95d4074d038e9dee61bdd61d017ce8893d3a4a8 golangci-lint-2.0.2-source.tar.gz +a35d8fdf3e14079a10880dbbb7586b46faec89be96f086b244b3e565aac80313 golangci-lint-2.0.2-windows-386.zip +fe4b946cc01366b989001215687003a9c4a7098589921f75e6228d6d8cffc15c golangci-lint-2.0.2-windows-amd64.zip +646bd9250ef8c771d85cd22fe8e6f2397ae39599179755e3bbfa9ef97ad44090 golangci-lint-2.0.2-windows-arm64.zip +ce1dc0bad6f8a61d64e6b3779eeb773479c175125d6f686b0e67ef9c8432d16e golangci-lint-2.0.2-windows-armv6.zip +92684a48faabe792b11ac27ca8b25551eff940b0a1e84ad7244e98b4994962db golangci-lint-2.0.2-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # From cfb8224fa7c7af1defa8748f247769c676099e44 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 3 Apr 2025 15:58:37 +0200 Subject: [PATCH 273/354] cmd/devp2p/internal/v5test: log test descriptions (#31551) This adds the test description text to the output, instead of keeping it as a Go comment. Logs are visible in the hive UI where these tests run, while Go comments are not. --- cmd/devp2p/internal/v5test/discv5tests.go | 35 ++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/cmd/devp2p/internal/v5test/discv5tests.go b/cmd/devp2p/internal/v5test/discv5tests.go index 7dbd3c3be..2139cd8ca 100644 --- a/cmd/devp2p/internal/v5test/discv5tests.go +++ b/cmd/devp2p/internal/v5test/discv5tests.go @@ -59,8 +59,9 @@ func (s *Suite) AllTests() []utesting.Test { } } -// TestPing sends PING and expects a PONG response. func (s *Suite) TestPing(t *utesting.T) { + t.Log(`This test is just a sanity check. It sends PING and expects a PONG response.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -85,9 +86,10 @@ func checkPong(t *utesting.T, pong *v5wire.Pong, ping *v5wire.Ping, c net.Packet } } -// TestPingLargeRequestID sends PING with a 9-byte request ID, which isn't allowed by the spec. -// The remote node should not respond. func (s *Suite) TestPingLargeRequestID(t *utesting.T) { + t.Log(`This test sends PING with a 9-byte request ID, which isn't allowed by the spec. +The remote node should not respond.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -104,10 +106,11 @@ func (s *Suite) TestPingLargeRequestID(t *utesting.T) { } } -// TestPingMultiIP establishes a session from one IP as usual. The session is then reused -// on another IP, which shouldn't work. The remote node should respond with WHOAREYOU for -// the attempt from a different IP. func (s *Suite) TestPingMultiIP(t *utesting.T) { + t.Log(`This test establishes a session from one IP as usual. The session is then reused +on another IP, which shouldn't work. The remote node should respond with WHOAREYOU for +the attempt from a different IP.`) + conn, l1, l2 := s.listen2(t) defer conn.close() @@ -120,6 +123,7 @@ func (s *Suite) TestPingMultiIP(t *utesting.T) { checkPong(t, resp.(*v5wire.Pong), ping, l1) // Send on l2. This reuses the session because there is only one codec. + t.Log("sending ping from alternate IP", l2.LocalAddr()) ping2 := &v5wire.Ping{ReqID: conn.nextReqID()} conn.write(l2, ping2, nil) switch resp := conn.read(l2).(type) { @@ -158,6 +162,10 @@ func (s *Suite) TestPingMultiIP(t *utesting.T) { // packet instead of a handshake message packet. The remote node should respond with // another WHOAREYOU challenge for the second packet. func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) { + t.Log(`TestPingHandshakeInterrupted starts a handshake, but doesn't finish it and sends a second ordinary message +packet instead of a handshake message packet. The remote node should respond with +another WHOAREYOU challenge for the second packet.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -181,8 +189,10 @@ func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) { } } -// TestTalkRequest sends TALKREQ and expects an empty TALKRESP response. func (s *Suite) TestTalkRequest(t *utesting.T) { + t.Log(`This test sends some examples of TALKREQ with a protocol-id of "test-protocol" +and expects an empty TALKRESP response.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -202,6 +212,7 @@ func (s *Suite) TestTalkRequest(t *utesting.T) { } // Empty request ID. + t.Log("sending TALKREQ with empty request-id") resp = conn.reqresp(l1, &v5wire.TalkRequest{Protocol: "test-protocol"}) switch resp := resp.(type) { case *v5wire.TalkResponse: @@ -216,8 +227,9 @@ func (s *Suite) TestTalkRequest(t *utesting.T) { } } -// TestFindnodeZeroDistance checks that the remote node returns itself for FINDNODE with distance zero. func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) { + t.Log(`This test checks that the remote node returns itself for FINDNODE with distance zero.`) + conn, l1 := s.listen1(t) defer conn.close() @@ -233,9 +245,11 @@ func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) { } } -// TestFindnodeResults pings the node under test from multiple nodes. After waiting for them to be -// accepted into the remote table, the test checks that they are returned by FINDNODE. func (s *Suite) TestFindnodeResults(t *utesting.T) { + t.Log(`This test pings the node under test from multiple other endpoints and node identities +(the 'bystanders'). After waiting for them to be accepted into the remote table, the test checks +that they are returned by FINDNODE.`) + // Create bystanders. nodes := make([]*bystander, 5) added := make(chan enode.ID, len(nodes)) @@ -273,6 +287,7 @@ func (s *Suite) TestFindnodeResults(t *utesting.T) { } // Send FINDNODE for all distances. + t.Log("requesting nodes") conn, l1 := s.listen1(t) defer conn.close() foundNodes, err := conn.findnode(l1, dists) From 4467af50515a0b6f509567b6a36d4523e722c855 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 3 Apr 2025 22:03:03 +0800 Subject: [PATCH 274/354] core, eth, node: use sync write option in pebble (#31519) Fixes #31499 --- core/bench_test.go | 8 ++++---- core/blockchain_repair_test.go | 8 ++++---- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 4 ++-- core/blockchain_test.go | 2 +- ethdb/pebble/pebble.go | 4 ++-- node/database.go | 13 +++++++++---- 7 files changed, 23 insertions(+), 18 deletions(-) diff --git a/core/bench_test.go b/core/bench_test.go index 9f7c525f0..7f7d3e33e 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -183,7 +183,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { if !disk { db = rawdb.NewMemoryDatabase() } else { - pdb, err := pebble.New(b.TempDir(), 128, 128, "", false) + pdb, err := pebble.New(b.TempDir(), 128, 128, "", false, true) if err != nil { b.Fatalf("cannot create temporary database: %v", err) } @@ -304,7 +304,7 @@ func makeChainForBench(db ethdb.Database, genesis *Genesis, full bool, count uin func benchWriteChain(b *testing.B, full bool, count uint64) { genesis := &Genesis{Config: params.AllEthashProtocolChanges} for i := 0; i < b.N; i++ { - pdb, err := pebble.New(b.TempDir(), 1024, 128, "", false) + pdb, err := pebble.New(b.TempDir(), 1024, 128, "", false, true) if err != nil { b.Fatalf("error opening database: %v", err) } @@ -317,7 +317,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) { func benchReadChain(b *testing.B, full bool, count uint64) { dir := b.TempDir() - pdb, err := pebble.New(dir, 1024, 128, "", false) + pdb, err := pebble.New(dir, 1024, 128, "", false, true) if err != nil { b.Fatalf("error opening database: %v", err) } @@ -333,7 +333,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { b.ResetTimer() for i := 0; i < b.N; i++ { - pdb, err = pebble.New(dir, 1024, 128, "", false) + pdb, err = pebble.New(dir, 1024, 128, "", false, true) if err != nil { b.Fatalf("error opening database: %v", err) } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index bea7dda4a..58dac9c8c 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1765,7 +1765,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s datadir := t.TempDir() ancient := filepath.Join(datadir, "ancient") - pdb, err := pebble.New(datadir, 0, 0, "", false) + pdb, err := pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } @@ -1850,7 +1850,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us - pdb, err = pebble.New(datadir, 0, 0, "", false) + pdb, err = pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to reopen persistent key-value database: %v", err) } @@ -1915,7 +1915,7 @@ func testIssue23496(t *testing.T, scheme string) { datadir := t.TempDir() ancient := filepath.Join(datadir, "ancient") - pdb, err := pebble.New(datadir, 0, 0, "", false) + pdb, err := pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } @@ -1973,7 +1973,7 @@ func testIssue23496(t *testing.T, scheme string) { chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us - pdb, err = pebble.New(datadir, 0, 0, "", false) + pdb, err = pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to reopen persistent key-value database: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 66e4f3feb..d8bafe1f7 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1969,7 +1969,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme datadir := t.TempDir() ancient := filepath.Join(datadir, "ancient") - pdb, err := pebble.New(datadir, 0, 0, "", false) + pdb, err := pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 7f00d7595..8d7e55958 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -66,7 +66,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo datadir := t.TempDir() ancient := filepath.Join(datadir, "ancient") - pdb, err := pebble.New(datadir, 0, 0, "", false) + pdb, err := pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } @@ -257,7 +257,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { chain.triedb.Close() // Start a new blockchain back up and see where the repair leads us - pdb, err := pebble.New(snaptest.datadir, 0, 0, "", false) + pdb, err := pebble.New(snaptest.datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 502319c1d..51251bbc8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2545,7 +2545,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { datadir := t.TempDir() ancient := path.Join(datadir, "ancient") - pdb, err := pebble.New(datadir, 0, 0, "", false) + pdb, err := pebble.New(datadir, 0, 0, "", false, true) if err != nil { t.Fatalf("Failed to create persistent key-value database: %v", err) } diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index b87ecb259..969e67af5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -144,7 +144,7 @@ func (l panicLogger) Fatalf(format string, args ...interface{}) { // New returns a wrapped pebble DB object. The namespace is the prefix that the // metrics reporting should use for surfacing internal stats. -func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) { +func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (*Database, error) { // Ensure we have some minimal caching and file guarantees if cache < minCache { cache = minCache @@ -185,7 +185,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( fn: file, log: logger, quitChan: make(chan chan error), - writeOptions: &pebble.WriteOptions{Sync: false}, + writeOptions: &pebble.WriteOptions{Sync: !ephemeral}, } opt := &pebble.Options{ // Pebble has a single combined cache area and the write diff --git a/node/database.go b/node/database.go index e3ccb9106..b7d0d856c 100644 --- a/node/database.go +++ b/node/database.go @@ -36,6 +36,11 @@ type openOptions struct { Cache int // the capacity(in megabytes) of the data caching Handles int // number of files to be open simultaneously ReadOnly bool + + // Ephemeral means that filesystem sync operations should be avoided: + // data integrity in the face of a crash is not important. This option + // should typically be used in tests. + Ephemeral bool } // openDatabase opens both a disk-based key-value database such as leveldb or pebble, but also @@ -78,7 +83,7 @@ func openKeyValueDatabase(o openOptions) (ethdb.Database, error) { } if o.Type == rawdb.DBPebble || existingDb == rawdb.DBPebble { log.Info("Using pebble as the backing database") - return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral) } if o.Type == rawdb.DBLeveldb || existingDb == rawdb.DBLeveldb { log.Info("Using leveldb as the backing database") @@ -86,7 +91,7 @@ func openKeyValueDatabase(o openOptions) (ethdb.Database, error) { } // No pre-existing database, no user-requested one either. Default to Pebble. log.Info("Defaulting to pebble as the backing database") - return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral) } // newLevelDBDatabase creates a persistent key-value database without a freezer @@ -102,8 +107,8 @@ func newLevelDBDatabase(file string, cache int, handles int, namespace string, r // newPebbleDBDatabase creates a persistent key-value database without a freezer // moving immutable chain segments into cold storage. -func newPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) { - db, err := pebble.New(file, cache, handles, namespace, readonly) +func newPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (ethdb.Database, error) { + db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral) if err != nil { return nil, err } From 0ad0cbb01efc99a594b6434ed59e82898b88d34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 3 Apr 2025 16:04:11 +0200 Subject: [PATCH 275/354] beacon/blsync: add checkpoint import/export file feature (#31469) This PR adds a new `--beacon.checkpoint.file` config flag to geth and blsync which specifies a checkpoint import/export file. If a file with an existing checkpoint is specified, it is used for initialization instead of the hardcoded one (except when `--beacon.checkpoint` is also specified simultaneously). Whenever the client encounters a new valid finality update with a suitable finalized beacon block root at an epoch boundary, it saves the block root in hex format to the checkpoint file. --- beacon/blsync/client.go | 10 +++++++++- beacon/light/head_tracker.go | 9 ++++++++- beacon/params/config.go | 34 ++++++++++++++++++++++++++++++++++ cmd/blsync/main.go | 1 + cmd/geth/main.go | 1 + cmd/utils/flags.go | 30 +++++++++++++++++++++++++----- 6 files changed, 78 insertions(+), 7 deletions(-) diff --git a/beacon/blsync/client.go b/beacon/blsync/client.go index 3c93754d3..744f46912 100644 --- a/beacon/blsync/client.go +++ b/beacon/blsync/client.go @@ -23,9 +23,11 @@ import ( "github.com/ethereum/go-ethereum/beacon/light/sync" "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" ) @@ -46,7 +48,13 @@ func NewClient(config params.ClientConfig) *Client { var ( db = memorydb.New() committeeChain = light.NewCommitteeChain(db, &config.ChainConfig, config.Threshold, !config.NoFilter) - headTracker = light.NewHeadTracker(committeeChain, config.Threshold) + headTracker = light.NewHeadTracker(committeeChain, config.Threshold, func(checkpoint common.Hash) { + if saved, err := config.SaveCheckpointToFile(checkpoint); saved { + log.Debug("Saved beacon checkpoint", "file", config.CheckpointFile, "checkpoint", checkpoint) + } else if err != nil { + log.Error("Failed to save beacon checkpoint", "file", config.CheckpointFile, "checkpoint", checkpoint, "error", err) + } + }) ) headSync := sync.NewHeadSync(headTracker, committeeChain) diff --git a/beacon/light/head_tracker.go b/beacon/light/head_tracker.go index 010e548dd..62faf1dbc 100644 --- a/beacon/light/head_tracker.go +++ b/beacon/light/head_tracker.go @@ -21,7 +21,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/beacon/params" "github.com/ethereum/go-ethereum/beacon/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" ) @@ -38,13 +40,15 @@ type HeadTracker struct { hasFinalityUpdate bool prefetchHead types.HeadInfo changeCounter uint64 + saveCheckpoint func(common.Hash) } // NewHeadTracker creates a new HeadTracker. -func NewHeadTracker(committeeChain *CommitteeChain, minSignerCount int) *HeadTracker { +func NewHeadTracker(committeeChain *CommitteeChain, minSignerCount int, saveCheckpoint func(common.Hash)) *HeadTracker { return &HeadTracker{ committeeChain: committeeChain, minSignerCount: minSignerCount, + saveCheckpoint: saveCheckpoint, } } @@ -100,6 +104,9 @@ func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error if replace { h.finalityUpdate, h.hasFinalityUpdate = update, true h.changeCounter++ + if h.saveCheckpoint != nil && update.Finalized.Slot%params.EpochLength == 0 { + h.saveCheckpoint(update.Finalized.Hash()) + } } return replace, err } diff --git a/beacon/params/config.go b/beacon/params/config.go index be2a40f17..2f6ba082c 100644 --- a/beacon/params/config.go +++ b/beacon/params/config.go @@ -54,6 +54,7 @@ type ChainConfig struct { GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation Forks Forks Checkpoint common.Hash + CheckpointFile string } // ForkAtEpoch returns the latest active fork at the given epoch. @@ -211,3 +212,36 @@ func (f Forks) Less(i, j int) bool { } return f[i].knownIndex < f[j].knownIndex } + +// SetCheckpointFile sets the checkpoint import/export file name and attempts to +// read the checkpoint from the file if it already exists. It returns true if +// a checkpoint has been loaded. +func (c *ChainConfig) SetCheckpointFile(checkpointFile string) (bool, error) { + c.CheckpointFile = checkpointFile + file, err := os.ReadFile(checkpointFile) + if os.IsNotExist(err) { + return false, nil // did not load checkpoint + } + if err != nil { + return false, fmt.Errorf("failed to read beacon checkpoint file: %v", err) + } + cp, err := hexutil.Decode(string(file)) + if err != nil { + return false, fmt.Errorf("failed to decode hex string in beacon checkpoint file: %v", err) + } + if len(cp) != 32 { + return false, fmt.Errorf("invalid hex string length in beacon checkpoint file: %d", len(cp)) + } + copy(c.Checkpoint[:len(cp)], cp) + return true, nil +} + +// SaveCheckpointToFile saves the given checkpoint to file if a checkpoint +// import/export file has been specified. +func (c *ChainConfig) SaveCheckpointToFile(checkpoint common.Hash) (bool, error) { + if c.CheckpointFile == "" { + return false, nil + } + err := os.WriteFile(c.CheckpointFile, []byte(checkpoint.Hex()), 0600) + return err == nil, err +} diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index 60caa4aa2..39a940730 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -43,6 +43,7 @@ func main() { utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, + utils.BeaconCheckpointFileFlag, //TODO datadir for optional permanent database utils.MainnetFlag, utils.SepoliaFlag, diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8e1ec70c9..76c4d43d5 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -175,6 +175,7 @@ var ( utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, + utils.BeaconCheckpointFileFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cc400865e..14d09f935 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -343,6 +343,11 @@ var ( Usage: "Beacon chain weak subjectivity checkpoint block hash", Category: flags.BeaconCategory, } + BeaconCheckpointFileFlag = &cli.StringFlag{ + Name: "beacon.checkpoint.file", + Usage: "Beacon chain weak subjectivity checkpoint import/export file", + Category: flags.BeaconCategory, + } BlsyncApiFlag = &cli.StringFlag{ Name: "blsync.engine.api", Usage: "Target EL engine API URL", @@ -2065,7 +2070,7 @@ func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig { if !ctx.IsSet(BeaconGenesisTimeFlag.Name) { Fatalf("Custom beacon chain config is specified but genesis time is missing") } - if !ctx.IsSet(BeaconCheckpointFlag.Name) { + if !ctx.IsSet(BeaconCheckpointFlag.Name) && !ctx.IsSet(BeaconCheckpointFileFlag.Name) { Fatalf("Custom beacon chain config is specified but checkpoint is missing") } config.ChainConfig = bparams.ChainConfig{ @@ -2090,12 +2095,27 @@ func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig { } } // Checkpoint is required with custom chain config and is optional with pre-defined config + // If both checkpoint block hash and checkpoint file are specified then the + // client is initialized with the specified block hash and new checkpoints + // are saved to the specified file. + if ctx.IsSet(BeaconCheckpointFileFlag.Name) { + if _, err := config.SetCheckpointFile(ctx.String(BeaconCheckpointFileFlag.Name)); err != nil { + Fatalf("Could not load beacon checkpoint file", "beacon.checkpoint.file", ctx.String(BeaconCheckpointFileFlag.Name), "error", err) + } + } if ctx.IsSet(BeaconCheckpointFlag.Name) { - if c, err := hexutil.Decode(ctx.String(BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 { - copy(config.Checkpoint[:len(c)], c) - } else { - Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(BeaconCheckpointFlag.Name), "error", err) + hex := ctx.String(BeaconCheckpointFlag.Name) + c, err := hexutil.Decode(hex) + if err != nil { + Fatalf("Invalid hex string", "beacon.checkpoint", hex, "error", err) } + if len(c) != 32 { + Fatalf("Invalid hex string length", "beacon.checkpoint", hex, "length", len(c)) + } + copy(config.Checkpoint[:len(c)], c) + } + if config.Checkpoint == (common.Hash{}) { + Fatalf("Beacon checkpoint not specified") } config.Apis = ctx.StringSlice(BeaconApiFlag.Name) if config.Apis == nil { From 9ca9b9f6a0f663704fe7dd6f9322d049b46d9679 Mon Sep 17 00:00:00 2001 From: Nathan Jo <162083209+qqqeck@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:56:55 +0900 Subject: [PATCH 276/354] p2p/nat: remove forceful port mapping in upnp (#30265) Here we are modifying the port mapping logic so that existing port mappings will only be removed when they were previously created by geth. The AddAnyPortMapping functionality has been adapted to work consistently between the IGDv1 and IGDv2 backends. --- p2p/nat/natpmp.go | 3 +++ p2p/nat/natupnp.go | 36 +++++++++++++++++++++++------------- p2p/server_nat.go | 13 ++++--------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 4a9644ac1..ee07eb4ff 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -49,6 +49,9 @@ func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lif if lifetime <= 0 { return 0, errors.New("lifetime must not be <= 0") } + if extport == 0 { + extport = intport + } // Note order of port arguments is switched between our // AddMapping and the client's AddPortMapping. res, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second)) diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index 1014dc69d..ed00b8eeb 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -86,15 +86,15 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li } protocol = strings.ToUpper(protocol) lifetimeS := uint32(lifetime / time.Second) - n.DeleteMapping(protocol, extport, intport) - err = n.withRateLimit(func() error { - return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) - }) - if err == nil { - return uint16(extport), nil + if extport == 0 { + extport = intport + } else { + // Only delete port mapping if the external port was already used by geth. + n.DeleteMapping(protocol, extport, intport) } - // Try addAnyPortMapping if mapping specified port didn't work. + + // Try to add port mapping, preferring the specified external port. err = n.withRateLimit(func() error { p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) if err == nil { @@ -105,18 +105,28 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li return uint16(extport), err } +// addAnyPortMapping tries to add a port mapping with the specified external port. +// If the external port is already in use, it will try to assign another port. func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) { if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok { return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) } - // It will retry with a random port number if the client does - // not support AddAnyPortMapping. - extport = n.randomPort() + // For IGDv1 and v1 services we should first try to add with extport. err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) - if err != nil { - return 0, err + if err == nil { + return uint16(extport), nil + } + + // If above fails, we retry with a random port. + // We retry several times because of possible port conflicts. + for i := 0; i < 3; i++ { + extport = n.randomPort() + err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + if err == nil { + return uint16(extport), nil + } } - return uint16(extport), nil + return 0, err } func (n *upnp) randomPort() int { diff --git a/p2p/server_nat.go b/p2p/server_nat.go index 933993bc1..5830f950e 100644 --- a/p2p/server_nat.go +++ b/p2p/server_nat.go @@ -150,14 +150,9 @@ func (srv *Server) portMappingLoop() { continue } - external := m.port - if m.extPort != 0 { - external = m.extPort - } - log := newLogger(m.protocol, external, m.port) - + log := newLogger(m.protocol, m.extPort, m.port) log.Trace("Attempting port mapping") - p, err := srv.NAT.AddMapping(m.protocol, external, m.port, m.name, portMapDuration) + p, err := srv.NAT.AddMapping(m.protocol, m.extPort, m.port, m.name, portMapDuration) if err != nil { log.Debug("Couldn't add port mapping", "err", err) m.extPort = 0 @@ -167,8 +162,8 @@ func (srv *Server) portMappingLoop() { // It was mapped! m.extPort = int(p) m.nextTime = srv.clock.Now().Add(portMapRefreshInterval) - if external != m.extPort { - log = newLogger(m.protocol, m.extPort, m.port) + log = newLogger(m.protocol, m.extPort, m.port) + if m.port != m.extPort { log.Info("NAT mapped alternative port") } else { log.Info("NAT mapped port") From d988e37218c744f6cb5366cd6374eea1253d7d78 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 4 Apr 2025 14:07:46 +0200 Subject: [PATCH 277/354] internal/era: random access to header and receipts (#31544) Co-authored-by: lightclient Add GetHeaderByNumber and GetReceiptsByNumber to allow more efficient API request filling from Era files. --- internal/era/e2store/e2store.go | 12 +++++++ internal/era/era.go | 64 ++++++++++++++++++++++++++++----- internal/era/era_test.go | 53 ++++++++++++++++++++++----- 3 files changed, 112 insertions(+), 17 deletions(-) diff --git a/internal/era/e2store/e2store.go b/internal/era/e2store/e2store.go index 9832b72d4..b0d43bf55 100644 --- a/internal/era/e2store/e2store.go +++ b/internal/era/e2store/e2store.go @@ -219,3 +219,15 @@ func (r *Reader) FindAll(want uint16) ([]*Entry, error) { off += int64(headerSize + length) } } + +// SkipN skips `n` entries starting from `offset` and returns the new offset. +func (r *Reader) SkipN(offset int64, n uint64) (int64, error) { + for i := uint64(0); i < n; i++ { + length, err := r.LengthAt(offset) + if err != nil { + return 0, err + } + offset += length + } + return offset, nil +} diff --git a/internal/era/era.go b/internal/era/era.go index daf337963..5129186fe 100644 --- a/internal/era/era.go +++ b/internal/era/era.go @@ -70,7 +70,7 @@ func ReadDir(dir, network string) ([]string, error) { } parts := strings.Split(entry.Name(), "-") if len(parts) != 3 || parts[0] != network { - // invalid era1 filename, skip + // Invalid era1 filename, skip. continue } if epoch, err := strconv.ParseUint(parts[1], 10, 64); err != nil { @@ -126,6 +126,29 @@ func (e *Era) Close() error { return e.f.Close() } +// GetHeaderByNumber returns the header for the given block number. +func (e *Era) GetHeaderByNumber(num uint64) (*types.Header, error) { + if e.m.start > num || e.m.start+e.m.count <= num { + return nil, errors.New("out-of-bounds") + } + off, err := e.readOffset(num) + if err != nil { + return nil, err + } + + // Read and decompress header. + r, _, err := newSnappyReader(e.s, TypeCompressedHeader, off) + if err != nil { + return nil, err + } + var header types.Header + if err := rlp.Decode(r, &header); err != nil { + return nil, err + } + return &header, nil +} + +// GetBlockByNumber returns the block for the given block number. func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) { if e.m.start > num || e.m.start+e.m.count <= num { return nil, errors.New("out-of-bounds") @@ -154,6 +177,34 @@ func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) { return types.NewBlockWithHeader(&header).WithBody(body), nil } +// GetReceiptsByNumber returns the receipts for the given block number. +func (e *Era) GetReceiptsByNumber(num uint64) (types.Receipts, error) { + if e.m.start > num || e.m.start+e.m.count <= num { + return nil, errors.New("out-of-bounds") + } + off, err := e.readOffset(num) + if err != nil { + return nil, err + } + + // Skip over header and body. + off, err = e.s.SkipN(off, 2) + if err != nil { + return nil, err + } + + // Read and decompress receipts. + r, _, err := newSnappyReader(e.s, TypeCompressedReceipts, off) + if err != nil { + return nil, err + } + var receipts types.Receipts + if err := rlp.Decode(r, &receipts); err != nil { + return nil, err + } + return receipts, nil +} + // Accumulator reads the accumulator entry in the Era1 file. func (e *Era) Accumulator() (common.Hash, error) { entry, err := e.s.Find(TypeAccumulator) @@ -187,13 +238,10 @@ func (e *Era) InitialTD() (*big.Int, error) { } off += n - // Skip over next two records. - for i := 0; i < 2; i++ { - length, err := e.s.LengthAt(off) - if err != nil { - return nil, err - } - off += length + // Skip over header and body. + off, err = e.s.SkipN(off, 2) + if err != nil { + return nil, err } // Read total difficulty after first block. diff --git a/internal/era/era_test.go b/internal/era/era_test.go index 72c3b385d..46fc2e91f 100644 --- a/internal/era/era_test.go +++ b/internal/era/era_test.go @@ -18,12 +18,15 @@ package era import ( "bytes" + "fmt" "io" "math/big" "os" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" ) type testchain struct { @@ -48,9 +51,9 @@ func TestEra1Builder(t *testing.T) { chain = testchain{} ) for i := 0; i < 128; i++ { - chain.headers = append(chain.headers, []byte{byte('h'), byte(i)}) - chain.bodies = append(chain.bodies, []byte{byte('b'), byte(i)}) - chain.receipts = append(chain.receipts, []byte{byte('r'), byte(i)}) + chain.headers = append(chain.headers, mustEncode(&types.Header{Number: big.NewInt(int64(i))})) + chain.bodies = append(chain.bodies, mustEncode(&types.Body{Transactions: []*types.Transaction{types.NewTransaction(0, common.Address{byte(i)}, nil, 0, nil, nil)}})) + chain.receipts = append(chain.receipts, mustEncode(&types.Receipts{{CumulativeGasUsed: uint64(i)}})) chain.tds = append(chain.tds, big.NewInt(int64(i))) } @@ -91,13 +94,25 @@ func TestEra1Builder(t *testing.T) { t.Fatalf("unexpected error %v", it.Error()) } // Check headers. - header, err := io.ReadAll(it.Header) + rawHeader, err := io.ReadAll(it.Header) + if err != nil { + t.Fatalf("error reading header from iterator: %v", err) + } + if !bytes.Equal(rawHeader, chain.headers[i]) { + t.Fatalf("mismatched header: want %s, got %s", chain.headers[i], rawHeader) + } + header, err := e.GetHeaderByNumber(i) if err != nil { t.Fatalf("error reading header: %v", err) } - if !bytes.Equal(header, chain.headers[i]) { - t.Fatalf("mismatched header: want %s, got %s", chain.headers[i], header) + encHeader, err := rlp.EncodeToBytes(header) + if err != nil { + t.Fatalf("error encoding header: %v", err) + } + if !bytes.Equal(encHeader, chain.headers[i]) { + t.Fatalf("mismatched header: want %s, got %s", chain.headers[i], encHeader) } + // Check bodies. body, err := io.ReadAll(it.Body) if err != nil { @@ -106,13 +121,25 @@ func TestEra1Builder(t *testing.T) { if !bytes.Equal(body, chain.bodies[i]) { t.Fatalf("mismatched body: want %s, got %s", chain.bodies[i], body) } + // Check receipts. - receipts, err := io.ReadAll(it.Receipts) + rawReceipts, err := io.ReadAll(it.Receipts) + if err != nil { + t.Fatalf("error reading receipts from iterator: %v", err) + } + if !bytes.Equal(rawReceipts, chain.receipts[i]) { + t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], rawReceipts) + } + receipts, err := e.GetReceiptsByNumber(i) if err != nil { t.Fatalf("error reading receipts: %v", err) } - if !bytes.Equal(receipts, chain.receipts[i]) { - t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], receipts) + encReceipts, err := rlp.EncodeToBytes(receipts) + if err != nil { + t.Fatalf("error encoding receipts: %v", err) + } + if !bytes.Equal(encReceipts, chain.receipts[i]) { + t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], encReceipts) } // Check total difficulty. @@ -144,3 +171,11 @@ func TestEraFilename(t *testing.T) { } } } + +func mustEncode(obj any) []byte { + b, err := rlp.EncodeToBytes(obj) + if err != nil { + panic(fmt.Sprintf("failed in encode obj: %v", err)) + } + return b +} From f766348d09e20102613341c927eca246e064c281 Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 7 Apr 2025 13:16:26 +0800 Subject: [PATCH 278/354] cmd/geth: set trie,gc and other cache flags for import chain (#31577) Signed-off-by: jsvisa --- cmd/geth/chaincmd.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 0c36b82af..227950954 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -79,11 +79,15 @@ if one is set. Otherwise it prints the genesis from the datadir.`, Usage: "Import a blockchain file", ArgsUsage: " ( ... ) ", Flags: slices.Concat([]cli.Flag{ - utils.CacheFlag, utils.GCModeFlag, utils.SnapshotFlag, + utils.CacheFlag, utils.CacheDatabaseFlag, + utils.CacheTrieFlag, utils.CacheGCFlag, + utils.CacheSnapshotFlag, + utils.CacheNoPrefetchFlag, + utils.CachePreimagesFlag, utils.NoCompactionFlag, utils.MetricsEnabledFlag, utils.MetricsEnabledExpensiveFlag, From b604a5384545ae61ab43a971733b522b95680415 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Tue, 8 Apr 2025 15:44:13 +0300 Subject: [PATCH 279/354] eth/remotedb: improve error handling (#31331) This PR improves error handling in the remotedb package by fixing two issues: 1. In the `Has` method, we now properly propagate errors instead of silently returning false. This makes the behavior more predictable and helps clients better understand when there are connection issues. 2. In the `New` constructor, we add a nil check for the client parameter to prevent potential panics. This follows Go best practices for constructor functions. These changes make the code more robust and follow Go's error handling idioms without requiring any changes to other parts of the codebase. Changes: - Modified `Has` method to return errors instead of silently returning false - Added nil check in `New` constructor - Fixed field name in constructor to match struct definition --- ethdb/remotedb/remotedb.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index 247a4392d..8a91fdbcf 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -34,7 +34,7 @@ type Database struct { func (db *Database) Has(key []byte) (bool, error) { if _, err := db.Get(key); err != nil { - return false, nil + return false, err } return true, nil } @@ -50,7 +50,7 @@ func (db *Database) Get(key []byte) ([]byte, error) { func (db *Database) HasAncient(kind string, number uint64) (bool, error) { if _, err := db.Ancient(kind, number); err != nil { - return false, nil + return false, err } return true, nil } @@ -144,7 +144,8 @@ func (db *Database) Close() error { } func New(client *rpc.Client) ethdb.Database { - return &Database{ - remote: client, + if client == nil { + return nil } + return &Database{remote: client} } From 031b9386d2056371c2a3659a6f40e55bd4385266 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 8 Apr 2025 21:46:27 +0800 Subject: [PATCH 280/354] core/txpool: add 7702 protection to blobpool (#31526) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces two constraints in the blobPool: (a) If the sender has a pending authorization or delegation, only one in-flight executable transaction can be cached. (b) If the authority address in a SetCode transaction is already reserved by the blobPool, the transaction will be rejected. These constraints mitigate an attack where an attacker spams the pool with numerous blob transactions, evicts other transactions, and then cancels all pending blob transactions by draining the sender’s funds if they have a delegation. Note, because there is no exclusive lock held between different subpools when processing transactions, it's totally possible the SetCode transaction and blob transactions with conflict sender and authorities are accepted simultaneously. I think it's acceptable as it's very hard to be exploited. --------- Co-authored-by: lightclient --- core/txpool/blobpool/blobpool.go | 66 ++++++++--- core/txpool/blobpool/blobpool_test.go | 60 +++------- core/txpool/errors.go | 4 + core/txpool/legacypool/legacypool.go | 60 ++++++---- core/txpool/legacypool/legacypool2_test.go | 8 +- core/txpool/legacypool/legacypool_test.go | 82 +++++--------- core/txpool/reserver.go | 124 +++++++++++++++++++++ core/txpool/subpool.go | 6 +- core/txpool/txpool.go | 79 ++----------- eth/backend.go | 10 +- eth/protocols/eth/handler_test.go | 2 +- 11 files changed, 287 insertions(+), 214 deletions(-) create mode 100644 core/txpool/reserver.go diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 58e1a3068..3bd4e371f 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -298,8 +298,9 @@ func newBlobTxMeta(id uint64, size uint64, storageSize uint32, tx *types.Transac // minimums will need to be done only starting at the swapped in/out nonce // and leading up to the first no-change. type BlobPool struct { - config Config // Pool configuration - reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools + config Config // Pool configuration + reserver *txpool.Reserver // Address reserver to ensure exclusivity across subpools + hasPendingAuth func(common.Address) bool // Determine whether the specified address has a pending 7702-auth store billy.Database // Persistent data store for the tx metadata and blobs stored uint64 // Useful data size of all transactions on disk @@ -329,13 +330,14 @@ type BlobPool struct { // New creates a new blob transaction pool to gather, sort and filter inbound // blob transactions from the network. -func New(config Config, chain BlockChain) *BlobPool { +func New(config Config, chain BlockChain, hasPendingAuth func(common.Address) bool) *BlobPool { // Sanitize the input to ensure no vulnerable gas prices are set config = (&config).sanitize() // Create the transaction pool with its initial settings return &BlobPool{ config: config, + hasPendingAuth: hasPendingAuth, signer: types.LatestSigner(chain.Config()), chain: chain, lookup: newLookup(), @@ -362,8 +364,8 @@ func (p *BlobPool) FilterAdd(tx *types.Transaction, local bool) bool { // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The transaction journal will be loaded // from disk and filtered based on the provided starting settings. -func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error { - p.reserve = reserve +func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver *txpool.Reserver) error { + p.reserver = reserver var ( queuedir string @@ -508,7 +510,7 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error { return err } if _, ok := p.index[sender]; !ok { - if err := p.reserve(sender, true); err != nil { + if err := p.reserver.Hold(sender); err != nil { return err } p.index[sender] = []*blobTxMeta{} @@ -563,7 +565,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 if inclusions != nil { // only during reorgs will the heap be initialized heap.Remove(p.evict, p.evict.index[addr]) } - p.reserve(addr, false) + p.reserver.Release(addr) if gapped { log.Warn("Dropping dangling blob transactions", "from", addr, "missing", next, "drop", nonces, "ids", ids) @@ -716,7 +718,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6 if inclusions != nil { // only during reorgs will the heap be initialized heap.Remove(p.evict, p.evict.index[addr]) } - p.reserve(addr, false) + p.reserver.Release(addr) } else { p.index[addr] = txs } @@ -1015,7 +1017,7 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error { // Update the indices and metrics meta := newBlobTxMeta(id, tx.Size(), p.store.Size(id), tx) if _, ok := p.index[addr]; !ok { - if err := p.reserve(addr, true); err != nil { + if err := p.reserver.Hold(addr); err != nil { log.Warn("Failed to reserve account for blob pool", "tx", tx.Hash(), "from", addr, "err", err) return err } @@ -1075,7 +1077,7 @@ func (p *BlobPool) SetGasTip(tip *big.Int) { delete(p.spent, addr) heap.Remove(p.evict, p.evict.index[addr]) - p.reserve(addr, false) + p.reserver.Release(addr) } // Clear out the transactions from the data store log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids) @@ -1110,6 +1112,39 @@ func (p *BlobPool) ValidateTxBasics(tx *types.Transaction) error { return txpool.ValidateTransaction(tx, p.head, p.signer, opts) } +// checkDelegationLimit determines if the tx sender is delegated or has a +// pending delegation, and if so, ensures they have at most one in-flight +// **executable** transaction, e.g. disallow stacked and gapped transactions +// from the account. +func (p *BlobPool) checkDelegationLimit(tx *types.Transaction) error { + from, _ := types.Sender(p.signer, tx) // validated + + // Short circuit if the sender has neither delegation nor pending delegation. + if p.state.GetCodeHash(from) == types.EmptyCodeHash { + // Because there is no exclusive lock held between different subpools + // when processing transactions, a blob transaction may be accepted + // while other SetCode transactions with pending authorities from the + // same address are also accepted simultaneously. + // + // This scenario is considered acceptable, as the rule primarily ensures + // that attackers cannot easily and endlessly stack blob transactions + // with a delegated or pending delegated sender. + if p.hasPendingAuth == nil || !p.hasPendingAuth(from) { + return nil + } + } + // Allow a single in-flight pending transaction. + pending := p.index[from] + if len(pending) == 0 { + return nil + } + // If account already has a pending transaction, allow replacement only. + if len(pending) == 1 && pending[0].nonce == tx.Nonce() { + return nil + } + return txpool.ErrInflightTxLimitReached +} + // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (p *BlobPool) validateTx(tx *types.Transaction) error { @@ -1150,6 +1185,9 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { if err := txpool.ValidateTransactionWithState(tx, p.signer, stateOpts); err != nil { return err } + if err := p.checkDelegationLimit(tx); err != nil { + return err + } // If the transaction replaces an existing one, ensure that price bumps are // adhered to. var ( @@ -1378,7 +1416,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { // only by this subpool until all transactions are evicted from, _ := types.Sender(p.signer, tx) // already validated above if _, ok := p.index[from]; !ok { - if err := p.reserve(from, true); err != nil { + if err := p.reserver.Hold(from); err != nil { addNonExclusiveMeter.Mark(1) return err } @@ -1390,7 +1428,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { // by a return statement before running deferred methods. Take care with // removing or subscoping err as it will break this clause. if err != nil { - p.reserve(from, false) + p.reserver.Release(from) } }() } @@ -1522,7 +1560,7 @@ func (p *BlobPool) drop() { if last { delete(p.index, from) delete(p.spent, from) - p.reserve(from, false) + p.reserver.Release(from) } else { txs[len(txs)-1] = nil txs = txs[:len(txs)-1] @@ -1810,7 +1848,7 @@ func (p *BlobPool) Clear() { // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. for acct := range p.index { - p.reserve(acct, false) + p.reserver.Release(acct) } p.lookup = newLookup() p.index = make(map[common.Address][]*blobTxMeta) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index b7c6cfa51..4dfba3b52 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -26,7 +26,6 @@ import ( "math/big" "os" "path/filepath" - "sync" "testing" "github.com/ethereum/go-ethereum/common" @@ -168,33 +167,6 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { return bc.statedb, nil } -// makeAddressReserver is a utility method to sanity check that accounts are -// properly reserved by the blobpool (no duplicate reserves or unreserves). -func makeAddressReserver() txpool.AddressReserver { - var ( - reserved = make(map[common.Address]struct{}) - lock sync.Mutex - ) - return func(addr common.Address, reserve bool) error { - lock.Lock() - defer lock.Unlock() - - _, exists := reserved[addr] - if reserve { - if exists { - panic("already reserved") - } - reserved[addr] = struct{}{} - return nil - } - if !exists { - panic("not reserved") - } - delete(reserved, addr) - return nil - } -} - // makeTx is a utility method to construct a random blob transaction and sign it // with a valid key, only setting the interesting fields from the perspective of // the blob pool. @@ -433,6 +405,10 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { } } +func newReserver() *txpool.Reserver { + return txpool.NewReservationTracker().NewHandle(42) +} + // Tests that transactions can be loaded from disk on startup and that they are // correctly discarded if invalid. // @@ -699,8 +675,8 @@ func TestOpenDrops(t *testing.T) { blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), statedb: statedb, } - pool := New(Config{Datadir: storage}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("failed to create blob pool: %v", err) } defer pool.Close() @@ -817,8 +793,8 @@ func TestOpenIndex(t *testing.T) { blobfee: uint256.NewInt(params.BlobTxMinBlobGasprice), statedb: statedb, } - pool := New(Config{Datadir: storage}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("failed to create blob pool: %v", err) } defer pool.Close() @@ -918,8 +894,8 @@ func TestOpenHeap(t *testing.T) { blobfee: uint256.NewInt(105), statedb: statedb, } - pool := New(Config{Datadir: storage}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("failed to create blob pool: %v", err) } defer pool.Close() @@ -997,8 +973,8 @@ func TestOpenCap(t *testing.T) { blobfee: uint256.NewInt(105), statedb: statedb, } - pool := New(Config{Datadir: storage, Datacap: datacap}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage, Datacap: datacap}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("failed to create blob pool: %v", err) } // Verify that enough transactions have been dropped to get the pool's size @@ -1098,8 +1074,8 @@ func TestChangingSlotterSize(t *testing.T) { blobfee: uint256.NewInt(105), statedb: statedb, } - pool := New(Config{Datadir: storage}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("failed to create blob pool: %v", err) } @@ -1541,8 +1517,8 @@ func TestAdd(t *testing.T) { blobfee: uint256.NewInt(105), statedb: statedb, } - pool := New(Config{Datadir: storage}, chain) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + pool := New(Config{Datadir: storage}, chain, nil) + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { t.Fatalf("test %d: failed to create blob pool: %v", i, err) } verifyPoolInternals(t, pool) @@ -1638,10 +1614,10 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { blobfee: uint256.NewInt(blobfee), statedb: statedb, } - pool = New(Config{Datadir: ""}, chain) + pool = New(Config{Datadir: ""}, chain, nil) ) - if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil { + if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil { b.Fatalf("failed to create blob pool: %v", err) } // Make the pool not use disk (just drop everything). This test never reads diff --git a/core/txpool/errors.go b/core/txpool/errors.go index 5ac280749..52b9d2a19 100644 --- a/core/txpool/errors.go +++ b/core/txpool/errors.go @@ -63,4 +63,8 @@ var ( // input transaction of non-blob type when a blob transaction from this sender // remains pending (and vice-versa). ErrAlreadyReserved = errors.New("address already reserved") + + // ErrInflightTxLimitReached is returned when the maximum number of in-flight + // transactions is reached for specific accounts. + ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts") ) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 263e7d3d0..e576f1b39 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -73,10 +73,6 @@ var ( // another remote transaction. ErrTxPoolOverflow = errors.New("txpool is full") - // ErrInflightTxLimitReached is returned when the maximum number of in-flight - // transactions is reached for specific accounts. - ErrInflightTxLimitReached = errors.New("in-flight transaction limit reached for delegated accounts") - // ErrOutOfOrderTxFromDelegated is returned when the transaction with gapped // nonce received from the accounts with delegation or pending delegation. ErrOutOfOrderTxFromDelegated = errors.New("gapped-nonce tx from delegated accounts") @@ -264,8 +260,8 @@ type LegacyPool struct { currentHead atomic.Pointer[types.Header] // Current head of the blockchain currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces + reserver *txpool.Reserver // Address reserver to ensure exclusivity across subpools - reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools pending map[common.Address]*list // All currently processable transactions queue map[common.Address]*list // Queued but non-processable transactions beats map[common.Address]time.Time // Last heartbeat from each known account @@ -350,7 +346,7 @@ func (pool *LegacyPool) FilterAdd(tx *types.Transaction, local bool) bool { // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The internal // goroutines will be spun up and the pool deemed operational afterwards. -func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error { +func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver *txpool.Reserver) error { // Do basic initializations about reserver, gas price and state pool.InitStatic(gasTip, head, nil, reserve, true) @@ -369,7 +365,7 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.A // start loops or load journals, so the pool can be released automatically. func (pool *LegacyPool) InitStatic(gasTip uint64, head *types.Header, statedb *state.StateDB, reserve txpool.AddressReserver, allowMissingState bool) error { // Set the address reserver to request exclusive access to pooled accounts - pool.reserve = reserve + pool.reserver = reserver // Set the basic pool parameters pool.gasTip.Store(uint256.NewInt(gasTip)) @@ -739,7 +735,7 @@ func (pool *LegacyPool) checkDelegationLimit(tx *types.Transaction) error { from, _ := types.Sender(pool.signer, tx) // validated // Short circuit if the sender has neither delegation nor pending delegation. - if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && pool.all.delegationTxsCount(from) == 0 { + if pool.currentState.GetCodeHash(from) == types.EmptyCodeHash && !pool.all.hasAuth(from) { return nil } pending := pool.pending[from] @@ -754,7 +750,7 @@ func (pool *LegacyPool) checkDelegationLimit(tx *types.Transaction) error { if pending.Contains(tx.Nonce()) { return nil } - return ErrInflightTxLimitReached + return txpool.ErrInflightTxLimitReached } // validateAuth verifies that the transaction complies with code authorization @@ -765,12 +761,24 @@ func (pool *LegacyPool) validateAuth(tx *types.Transaction) error { if err := pool.checkDelegationLimit(tx); err != nil { return err } - // Authorities cannot conflict with any pending or queued transactions. + // Authorities must not conflict with any pending or queued transactions, + // nor with addresses that have already been reserved. if auths := tx.SetCodeAuthorities(); len(auths) > 0 { for _, auth := range auths { if pool.pending[auth] != nil || pool.queue[auth] != nil { return ErrAuthorityReserved } + // Because there is no exclusive lock held between different subpools + // when processing transactions, the SetCode transaction may be accepted + // while other transactions with the same sender address are also + // accepted simultaneously in the other pools. + // + // This scenario is considered acceptable, as the rule primarily ensures + // that attackers cannot easily stack a SetCode transaction when the sender + // is reserved by other pools. + if pool.reserver.Has(auth) { + return ErrAuthorityReserved + } } } return nil @@ -804,7 +812,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) { _, hasQueued = pool.queue[from] ) if !hasPending && !hasQueued { - if err := pool.reserve(from, true); err != nil { + if err := pool.reserver.Hold(from); err != nil { return false, err } defer func() { @@ -815,7 +823,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) { // by a return statement before running deferred methods. Take care with // removing or subscoping err as it will break this clause. if err != nil { - pool.reserve(from, false) + pool.reserver.Release(from) } }() } @@ -1212,7 +1220,7 @@ func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bo _, hasQueued = pool.queue[addr] ) if !hasPending && !hasQueued { - pool.reserve(addr, false) + pool.reserver.Release(addr) } }() } @@ -1592,7 +1600,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T delete(pool.queue, addr) delete(pool.beats, addr) if _, ok := pool.pending[addr]; !ok { - pool.reserve(addr, false) + pool.reserver.Release(addr) } } } @@ -1778,7 +1786,7 @@ func (pool *LegacyPool) demoteUnexecutables() { if list.Empty() { delete(pool.pending, addr) if _, ok := pool.queue[addr]; !ok { - pool.reserve(addr, false) + pool.reserver.Release(addr) } } } @@ -1987,11 +1995,13 @@ func (t *lookup) removeAuthorities(tx *types.Transaction) { } } -// delegationTxsCount returns the number of pending authorizations for the specified address. -func (t *lookup) delegationTxsCount(addr common.Address) int { +// hasAuth returns a flag indicating whether there are pending authorizations +// from the specified address. +func (t *lookup) hasAuth(addr common.Address) bool { t.lock.RLock() defer t.lock.RUnlock() - return len(t.auths[addr]) + + return len(t.auths[addr]) > 0 } // numSlots calculates the number of slots needed for a single transaction. @@ -2005,8 +2015,8 @@ func (pool *LegacyPool) Clear() { pool.mu.Lock() defer pool.mu.Unlock() - // unreserve each tracked account. Ideally, we could just clear the - // reservation map in the parent txpool context. However, if we clear in + // unreserve each tracked account. Ideally, we could just clear the + // reservation map in the parent txpool context. However, if we clear in // parent context, to avoid exposing the subpool lock, we have to lock the // reservations and then lock each subpool. // @@ -2017,11 +2027,11 @@ func (pool *LegacyPool) Clear() { // * TxPool.Clear attempts to lock subpool mutex // // The transaction addition may attempt to reserve the sender addr which - // can't happen until Clear releases the reservation lock. Clear cannot + // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. for _, tx := range pool.all.txs { senderAddr, _ := types.Sender(pool.signer, tx) - pool.reserve(senderAddr, false) + pool.reserver.Release(senderAddr) } pool.all = newLookup() pool.priced = newPricedList(pool.all) @@ -2029,3 +2039,9 @@ func (pool *LegacyPool) Clear() { pool.queue = make(map[common.Address]*list) pool.pendingNonces = newNoncer(pool.currentState) } + +// HasPendingAuth returns a flag indicating whether there are pending +// authorizations from the specific address cached in the pool. +func (pool *LegacyPool) HasPendingAuth(addr common.Address) bool { + return pool.all.hasAuth(addr) +} diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index d55e85d74..3f210e3d1 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -86,7 +86,7 @@ func TestTransactionFutureAttack(t *testing.T) { config.GlobalQueue = 100 config.GlobalSlots = 100 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() fillPool(t, pool) pending, _ := pool.Stats() @@ -120,7 +120,7 @@ func TestTransactionFuture1559(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts, fund them and make transactions @@ -153,7 +153,7 @@ func TestTransactionZAttack(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts, fund them and make transactions fillPool(t, pool) @@ -224,7 +224,7 @@ func BenchmarkFutureAttack(b *testing.B) { config.GlobalQueue = 100 config.GlobalSlots = 100 pool := New(config, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() fillPool(b, pool) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 3f269bd69..c47a65520 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -24,7 +24,6 @@ import ( "math/big" "math/rand" "slices" - "sync" "sync/atomic" "testing" "time" @@ -168,42 +167,21 @@ func pricedSetCodeTxWithAuth(nonce uint64, gaslimit uint64, gasFee, tip *uint256 }) } -func makeAddressReserver() txpool.AddressReserver { - var ( - reserved = make(map[common.Address]struct{}) - lock sync.Mutex - ) - return func(addr common.Address, reserve bool) error { - lock.Lock() - defer lock.Unlock() - - _, exists := reserved[addr] - if reserve { - if exists { - panic("already reserved") - } - reserved[addr] = struct{}{} - return nil - } - if !exists { - panic("not reserved") - } - delete(reserved, addr) - return nil - } -} - func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { return setupPoolWithConfig(params.TestChainConfig) } +func newReserver() *txpool.Reserver { + return txpool.NewReservationTracker().NewHandle(42) +} + func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() pool := New(testTxPoolConfig, blockchain) - if err := pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()); err != nil { + if err := pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()); err != nil { panic(err) } // wait for the pool to initialize @@ -336,7 +314,7 @@ func TestStateChangeDuringReset(t *testing.T) { tx1 := transaction(1, 100000, key) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() nonce := pool.Nonce(address) @@ -753,7 +731,7 @@ func TestPostponing(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create two test accounts to produce different gap profiles with @@ -963,7 +941,7 @@ func TestQueueGlobalLimiting(t *testing.T) { config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) pool := New(config, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them (last one will be the local) @@ -1015,7 +993,7 @@ func TestQueueTimeLimiting(t *testing.T) { config.Lifetime = time.Second pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a test account to ensure remotes expire @@ -1176,7 +1154,7 @@ func TestPendingGlobalLimiting(t *testing.T) { config.GlobalSlots = config.AccountSlots * 10 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them @@ -1275,7 +1253,7 @@ func TestCapClearsFromAll(t *testing.T) { config.GlobalSlots = 8 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them @@ -1308,7 +1286,7 @@ func TestPendingMinimumAllowance(t *testing.T) { config.GlobalSlots = 1 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them @@ -1352,7 +1330,7 @@ func TestRepricing(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Keep track of transaction events to ensure all executables get announced @@ -1457,7 +1435,7 @@ func TestMinGasPriceEnforced(t *testing.T) { txPoolConfig := DefaultConfig txPoolConfig.NoLocals = true pool := New(txPoolConfig, blockchain) - pool.Init(txPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(txPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() key, _ := crypto.GenerateKey() @@ -1606,7 +1584,7 @@ func TestUnderpricing(t *testing.T) { config.GlobalQueue = 2 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Keep track of transaction events to ensure all executables get announced @@ -1696,7 +1674,7 @@ func TestStableUnderpricing(t *testing.T) { config.GlobalQueue = 0 pool := New(config, blockchain) - pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Keep track of transaction events to ensure all executables get announced @@ -1899,7 +1877,7 @@ func TestDeduplication(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a test account to add transactions with @@ -1966,7 +1944,7 @@ func TestReplacement(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Keep track of transaction events to ensure all executables get announced @@ -2157,7 +2135,7 @@ func TestStatusCheck(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create the test accounts to check various transaction statuses with @@ -2230,7 +2208,7 @@ func TestSetCodeTransactions(t *testing.T) { blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create the test accounts @@ -2271,12 +2249,12 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { t.Fatalf("%s: failed to add remote transaction: %v", name, err) } - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) } // Check gapped transaction again. - if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) } // Replace by fee. if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil { @@ -2310,8 +2288,8 @@ func TestSetCodeTransactions(t *testing.T) { t.Fatalf("%s: failed to add with pending delegatio: %v", name, err) } // Also check gapped transaction is rejected. - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, ErrInflightTxLimitReached) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrInflightTxLimitReached, err) + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) } }, }, @@ -2386,7 +2364,7 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { t.Fatalf("%s: failed to added single pooled for account with pending delegation: %v", name, err) } - if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), ErrInflightTxLimitReached; !errors.Is(err, want) { + if err, want := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyC)), txpool.ErrInflightTxLimitReached; !errors.Is(err, want) { t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) } }, @@ -2454,7 +2432,7 @@ func TestSetCodeTransactionsReorg(t *testing.T) { blockchain := newTestBlockChain(params.MergedTestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) - pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create the test accounts @@ -2489,8 +2467,8 @@ func TestSetCodeTransactionsReorg(t *testing.T) { t.Fatalf("failed to add with remote setcode transaction: %v", err) } // Try to add a transactions in - if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, ErrInflightTxLimitReached) { - t.Fatalf("unexpected error %v, expecting %v", err, ErrInflightTxLimitReached) + if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1000), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("unexpected error %v, expecting %v", err, txpool.ErrInflightTxLimitReached) } // Simulate the chain moving blockchain.statedb.SetNonce(addrA, 2, tracing.NonceChangeAuthorization) diff --git a/core/txpool/reserver.go b/core/txpool/reserver.go new file mode 100644 index 000000000..76ead0f3b --- /dev/null +++ b/core/txpool/reserver.go @@ -0,0 +1,124 @@ +// Copyright 2025 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 . + +package txpool + +import ( + "errors" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +var ( + // reservationsGaugeName is the prefix of a per-subpool address reservation + // metric. + // + // This is mostly a sanity metric to ensure there's no bug that would make + // some subpool hog all the reservations due to mis-accounting. + reservationsGaugeName = "txpool/reservations" +) + +// ReservationTracker is a struct shared between different subpools. It is used to reserve +// the account and ensure that one address cannot initiate transactions, authorizations, +// and other state-changing behaviors in different pools at the same time. +type ReservationTracker struct { + accounts map[common.Address]int + lock sync.RWMutex +} + +// NewReservationTracker initializes the account reservation tracker. +func NewReservationTracker() *ReservationTracker { + return &ReservationTracker{ + accounts: make(map[common.Address]int), + } +} + +// NewHandle creates a named handle on the ReservationTracker. The handle +// identifies the subpool so ownership of reservations can be determined. +func (r *ReservationTracker) NewHandle(id int) *Reserver { + return &Reserver{r, id} +} + +// Reserver is a named handle on ReservationTracker. It is held by subpools to +// make reservations for accounts it is tracking. The id is used to determine +// which pool owns an address and disallows non-owners to hold or release +// addresses it doesn't own. +type Reserver struct { + tracker *ReservationTracker + id int +} + +// Hold attempts to reserve the specified account address for the given pool. +// Returns an error if the account is already reserved. +func (h *Reserver) Hold(addr common.Address) error { + h.tracker.lock.Lock() + defer h.tracker.lock.Unlock() + + // Double reservations are forbidden even from the same pool to + // avoid subtle bugs in the long term. + owner, exists := h.tracker.accounts[addr] + if exists { + if owner == h.id { + log.Error("pool attempted to reserve already-owned address", "address", addr) + return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed + } + return ErrAlreadyReserved + } + h.tracker.accounts[addr] = h.id + if metrics.Enabled() { + m := fmt.Sprintf("%s/%d", reservationsGaugeName, h.id) + metrics.GetOrRegisterGauge(m, nil).Inc(1) + } + return nil +} + +// Release attempts to release the reservation for the specified account. +// Returns an error if the address is not reserved or is reserved by another pool. +func (h *Reserver) Release(addr common.Address) error { + h.tracker.lock.Lock() + defer h.tracker.lock.Unlock() + + // Ensure subpools only attempt to unreserve their own owned addresses, + // otherwise flag as a programming error. + owner, exists := h.tracker.accounts[addr] + if !exists { + log.Error("pool attempted to unreserve non-reserved address", "address", addr) + return errors.New("address not reserved") + } + if owner != h.id { + log.Error("pool attempted to unreserve non-owned address", "address", addr) + return errors.New("address not owned") + } + delete(h.tracker.accounts, addr) + if metrics.Enabled() { + m := fmt.Sprintf("%s/%d", reservationsGaugeName, h.id) + metrics.GetOrRegisterGauge(m, nil).Dec(1) + } + return nil +} + +// Has returns a flag indicating if the address has been reserved or not. +func (h *Reserver) Has(address common.Address) bool { + h.tracker.lock.RLock() + defer h.tracker.lock.RUnlock() + + _, exists := h.tracker.accounts[address] + return exists +} diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 27ce03106..362b42853 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -67,10 +67,6 @@ type LazyResolver interface { Get(hash common.Hash) *types.Transaction } -// AddressReserver is passed by the main transaction pool to subpools, so they -// may request (and relinquish) exclusive access to certain addresses. -type AddressReserver func(addr common.Address, reserve bool) error - // PendingFilter is a collection of filter rules to allow retrieving a subset // of transactions for announcement or mining. // @@ -117,7 +113,7 @@ type SubPool interface { // These should not be passed as a constructor argument - nor should the pools // start by themselves - in order to keep multiple subpools in lockstep with // one another. - Init(gasTip uint64, head *types.Header, reserve AddressReserver) error + Init(gasTip uint64, head *types.Header, reserver *Reserver) error // Close terminates any background processing threads and releases any held // resources. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 560fcc9dc..c4aeb4463 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" ) @@ -46,15 +45,6 @@ const ( TxStatusCached = 64 ) -var ( - // reservationsGaugeName is the prefix of a per-subpool address reservation - // metric. - // - // This is mostly a sanity metric to ensure there's no bug that would make - // some subpool hog all the reservations due to mis-accounting. - reservationsGaugeName = "txpool/reservations" -) - // BlockChain defines the minimal set of methods needed to back a tx pool with // a chain. Exists to allow mocking the live chain out of tests. type BlockChain interface { @@ -84,9 +74,6 @@ type TxPool struct { stateLock sync.RWMutex // The lock for protecting state instance state *state.StateDB // Current state at the blockchain head - reservations map[common.Address]SubPool // Map with the account to pool reservations - reserveLock sync.Mutex // Lock protecting the account reservations - subs event.SubscriptionScope // Subscription scope to unsubscribe all on shutdown quit chan chan error // Quit channel to tear down the head updater term chan struct{} // Termination channel to detect a closed pool @@ -113,17 +100,17 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { return nil, err } pool := &TxPool{ - subpools: subpools, - chain: chain, - signer: types.LatestSigner(chain.Config()), - state: statedb, - reservations: make(map[common.Address]SubPool), - quit: make(chan chan error), - term: make(chan struct{}), - sync: make(chan chan error), - } + subpools: subpools, + chain: chain, + signer: types.LatestSigner(chain.Config()), + state: statedb, + quit: make(chan chan error), + term: make(chan struct{}), + sync: make(chan chan error), + } + reserver := NewReservationTracker() for i, subpool := range subpools { - if err := subpool.Init(gasTip, head, pool.reserver(i, subpool)); err != nil { + if err := subpool.Init(gasTip, head, reserver.NewHandle(i)); err != nil { for j := i - 1; j >= 0; j-- { subpools[j].Close() } @@ -134,52 +121,6 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) { return pool, nil } -// reserver is a method to create an address reservation callback to exclusively -// assign/deassign addresses to/from subpools. This can ensure that at any point -// in time, only a single subpool is able to manage an account, avoiding cross -// subpool eviction issues and nonce conflicts. -func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver { - return func(addr common.Address, reserve bool) error { - p.reserveLock.Lock() - defer p.reserveLock.Unlock() - - owner, exists := p.reservations[addr] - if reserve { - // Double reservations are forbidden even from the same pool to - // avoid subtle bugs in the long term. - if exists { - if owner == subpool { - log.Error("pool attempted to reserve already-owned address", "address", addr) - return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed - } - return ErrAlreadyReserved - } - p.reservations[addr] = subpool - if metrics.Enabled() { - m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) - metrics.GetOrRegisterGauge(m, nil).Inc(1) - } - return nil - } - // Ensure subpools only attempt to unreserve their own owned addresses, - // otherwise flag as a programming error. - if !exists { - log.Error("pool attempted to unreserve non-reserved address", "address", addr) - return errors.New("address not reserved") - } - if subpool != owner { - log.Error("pool attempted to unreserve non-owned address", "address", addr) - return errors.New("address not owned") - } - delete(p.reservations, addr) - if metrics.Enabled() { - m := fmt.Sprintf("%s/%d", reservationsGaugeName, id) - metrics.GetOrRegisterGauge(m, nil).Dec(1) - } - return nil - } -} - // Close terminates the transaction pool and all its subpools. func (p *TxPool) Close() error { var errs []error diff --git a/eth/backend.go b/eth/backend.go index 720e293a7..b4349b6a0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -279,15 +279,15 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, historyCutoff, finalBlock, filtermaps.DefaultParams, fmConfig) eth.closeFilterMaps = make(chan chan struct{}) - if config.BlobPool.Datadir != "" { - config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) - } - blobPool := blobpool.New(config.BlobPool, eth.blockchain) - if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } legacyPool := legacypool.New(config.TxPool, eth.blockchain) + + if config.BlobPool.Datadir != "" { + config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) + } + blobPool := blobpool.New(config.BlobPool, eth.blockchain, legacyPool.HasPendingAuth) subPools := []txpool.SubPool{legacyPool, blobPool} enableAMEVCachePool := config.TxPool.AMEVCache && !config.TxPool.NoLocals if enableAMEVCachePool { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 2c783459d..0c7398221 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -135,7 +135,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generat storage, _ := os.MkdirTemp("", "blobpool-") defer os.RemoveAll(storage) - blobPool := blobpool.New(blobpool.Config{Datadir: storage}, chain) + blobPool := blobpool.New(blobpool.Config{Datadir: storage}, chain, nil) legacyPool := legacypool.New(txconfig, chain) txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{legacyPool, blobPool}) From 93c25da5d076d4f6c79c28ac789681be879c5b0e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 8 Apr 2025 19:57:45 +0200 Subject: [PATCH 281/354] core/vm: optimize push2 opcode (#31267) During my benchmarks on Holesky, around 10% of all CPU time was spent in PUSH2 ``` ROUTINE ======================== github.com/ethereum/go-ethereum/core/vm.newFrontierInstructionSet.makePush.func1 in github.com/ethereum/go-ethereum/core/vm/instructions.go 16.38s 20.35s (flat, cum) 10.31% of Total 740ms 740ms 976: return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { . . 977: var ( 40ms 40ms 978: codeLen = len(scope.Contract.Code) 970ms 970ms 979: start = min(codeLen, int(*pc+1)) 200ms 200ms 980: end = min(codeLen, start+pushByteSize) . . 981: ) 670ms 2.39s 982: a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end]) . . 983: . . 984: // Missing bytes: pushByteSize - len(pushData) 410ms 410ms 985: if missing := pushByteSize - (end - start); missing > 0 { . . 986: a.Lsh(a, uint(8*missing)) . . 987: } 12.69s 14.94s 988: scope.Stack.push2(*a) 10ms 10ms 989: *pc += size 650ms 650ms 990: return nil, nil . . 991: } . . 992:} ``` Which is quite crazy. We have a handwritten encoder for PUSH1 already, this PR adds one for PUSH2. PUSH2 is the second most used opcode as shown here: https://gist.github.com/shemnon/fb9b292a103abb02d98d64df6fbd35c8 since it is used by solidity quite significantly. Its used ~20 times as much as PUSH20 and PUSH32. # Benchmarks ``` BenchmarkPush/makePush-14 94196547 12.27 ns/op 0 B/op 0 allocs/op BenchmarkPush/push-14 429976924 2.829 ns/op 0 B/op 0 allocs/op ``` --------- Co-authored-by: jwasinger --- core/vm/instructions.go | 17 +++++++++++++++++ core/vm/jump_table.go | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1d68f09ef..839fac480 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -976,6 +976,23 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by return nil, nil } +// opPush2 is a specialized version of pushN +func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + var ( + codeLen = uint64(len(scope.Contract.Code)) + integer = new(uint256.Int) + ) + if *pc+2 < codeLen { + scope.Stack.push(integer.SetBytes2(scope.Contract.Code[*pc+1 : *pc+3])) + } else if *pc+1 < codeLen { + scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc+1]) << 8)) + } else { + scope.Stack.push(integer.Clear()) + } + *pc += 2 + return nil, nil +} + // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index f918022d1..b073e5372 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -637,7 +637,7 @@ func newFrontierInstructionSet() JumpTable { maxStack: maxStack(0, 1), }, PUSH2: { - execute: makePush(2, 2), + execute: opPush2, constantGas: GasFastestStep, minStack: minStack(0, 1), maxStack: maxStack(0, 1), From bec78bdbe822cd998a2505077696f42bcfc38d0a Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Wed, 9 Apr 2025 11:28:29 +0200 Subject: [PATCH 282/354] p2p/nat: fix UPnP port reset (#31566) Make UPnP more robust - Once a random port was mapped, we try to stick to it even if a UPnP refresh fails. Previously we were immediately moving back to try the default port, leading to frequent ENR changes. - We were deleting port mappings before refresh as a possible workaround. This created issues in some UPnP servers. The UPnP (and PMP) specification is explicit about the refresh requirements, and delete is clearly not needed (see https://github.com/ethereum/go-ethereum/pull/30265#issuecomment-2766987859). From now on we only delete when closing. - We were trying to add port mappings only once, and then moved on to random ports. Now we insist a bit more, so that a simple failed request won't lead to ENR changes. Fixes https://github.com/ethereum/go-ethereum/issues/31418 --------- Signed-off-by: Csaba Kiraly Co-authored-by: Felix Lange --- p2p/nat/natupnp.go | 49 +++++++++++++++++++++++++-------------- p2p/server_nat.go | 57 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index ed00b8eeb..d79677db5 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/log" "github.com/huin/goupnp" "github.com/huin/goupnp/dcps/internetgateway1" "github.com/huin/goupnp/dcps/internetgateway2" @@ -34,6 +35,8 @@ import ( const ( soapRequestTimeout = 3 * time.Second rateLimit = 200 * time.Millisecond + retryCount = 3 // number of retries after a failed AddPortMapping + randomCount = 3 // number of random ports to try ) type upnp struct { @@ -89,42 +92,43 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li if extport == 0 { extport = intport - } else { - // Only delete port mapping if the external port was already used by geth. - n.DeleteMapping(protocol, extport, intport) } // Try to add port mapping, preferring the specified external port. - err = n.withRateLimit(func() error { - p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) - if err == nil { - extport = int(p) - } - return err - }) - return uint16(extport), err + return n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS) } // addAnyPortMapping tries to add a port mapping with the specified external port. // If the external port is already in use, it will try to assign another port. func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) { if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok { - return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + return n.portWithRateLimit(func() (uint16, error) { + return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) } // For IGDv1 and v1 services we should first try to add with extport. - err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) - if err == nil { - return uint16(extport), nil + for i := 0; i < retryCount+1; i++ { + err := n.withRateLimit(func() error { + return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) + if err == nil { + return uint16(extport), nil + } + log.Debug("Failed to add port mapping", "protocol", protocol, "extport", extport, "intport", intport, "err", err) } // If above fails, we retry with a random port. // We retry several times because of possible port conflicts. - for i := 0; i < 3; i++ { + var err error + for i := 0; i < randomCount; i++ { extport = n.randomPort() - err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + err := n.withRateLimit(func() error { + return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + }) if err == nil { return uint16(extport), nil } + log.Debug("Failed to add random port mapping", "protocol", protocol, "extport", extport, "intport", intport, "err", err) } return 0, err } @@ -169,6 +173,17 @@ func (n *upnp) String() string { return "UPNP " + n.service } +func (n *upnp) portWithRateLimit(pfn func() (uint16, error)) (uint16, error) { + var port uint16 + var err error + fn := func() error { + port, err = pfn() + return err + } + n.withRateLimit(fn) + return port, err +} + func (n *upnp) withRateLimit(fn func() error) error { n.mu.Lock() defer n.mu.Unlock() diff --git a/p2p/server_nat.go b/p2p/server_nat.go index 5830f950e..298c454a4 100644 --- a/p2p/server_nat.go +++ b/p2p/server_nat.go @@ -31,12 +31,14 @@ const ( portMapRefreshInterval = 8 * time.Minute portMapRetryInterval = 5 * time.Minute extipRetryInterval = 2 * time.Minute + maxRetries = 5 // max number of failed attempts to refresh the mapping ) type portMapping struct { protocol string name string port int + retries int // number of failed attempts to refresh the mapping // for use by the portMappingLoop goroutine: extPort int // the mapped port returned by the NAT interface @@ -154,28 +156,49 @@ func (srv *Server) portMappingLoop() { log.Trace("Attempting port mapping") p, err := srv.NAT.AddMapping(m.protocol, m.extPort, m.port, m.name, portMapDuration) if err != nil { - log.Debug("Couldn't add port mapping", "err", err) - m.extPort = 0 + // Failed to add or refresh port mapping. + if m.extPort == 0 { + log.Debug("Couldn't add port mapping", "err", err) + } else { + // Failed refresh. Since UPnP implementation are often buggy, + // and lifetime is larger than the retry interval, this does not + // mean we lost our existing mapping. We do not reset the external + // port, as it is still our best chance, but we do retry soon. + // We could check the error code, but UPnP implementations are buggy. + log.Debug("Couldn't refresh port mapping", "err", err) + m.retries++ + if m.retries > maxRetries { + m.retries = 0 + err := srv.NAT.DeleteMapping(m.protocol, m.extPort, m.port) + log.Debug("Couldn't refresh port mapping, trying to delete it:", "err", err) + m.extPort = 0 + } + } m.nextTime = srv.clock.Now().Add(portMapRetryInterval) + // Note ENR is not updated here, i.e. we keep the last port. continue } - // It was mapped! - m.extPort = int(p) - m.nextTime = srv.clock.Now().Add(portMapRefreshInterval) - log = newLogger(m.protocol, m.extPort, m.port) - if m.port != m.extPort { - log.Info("NAT mapped alternative port") - } else { - log.Info("NAT mapped port") - } - // Update port in local ENR. - switch m.protocol { - case "TCP": - srv.localnode.Set(enr.TCP(m.extPort)) - case "UDP": - srv.localnode.SetFallbackUDP(m.extPort) + // It was mapped! + m.retries = 0 + log = newLogger(m.protocol, int(p), m.port) + if int(p) != m.extPort { + m.extPort = int(p) + if m.port != m.extPort { + log.Info("NAT mapped alternative port") + } else { + log.Info("NAT mapped port") + } + + // Update port in local ENR. + switch m.protocol { + case "TCP": + srv.localnode.Set(enr.TCP(m.extPort)) + case "UDP": + srv.localnode.SetFallbackUDP(m.extPort) + } } + m.nextTime = srv.clock.Now().Add(portMapRefreshInterval) } } } From ce8f6748853d767ee17765fa6dbf69715a1fe585 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:19:28 -0600 Subject: [PATCH 283/354] core/txpool: add notice to` Clear` that is not meant for production code (#31567) The `Sync(..)` function explicitly says not to rely on in production code, but it is used in `Clear(..)` so should add a similar mention. --- core/txpool/blobpool/blobpool.go | 6 ++++++ core/txpool/legacypool/legacypool.go | 7 +++++-- core/txpool/txpool.go | 11 +++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 3bd4e371f..27a51bde7 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1358,6 +1358,9 @@ func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844. // Add inserts a set of blob transactions into the pool if they pass validation (both // consensus validity and pool restrictions). +// +// Note, if sync is set the method will block until all internal maintenance +// related to the add is finished. Only use this during tests for determinism. func (p *BlobPool) Add(txs []*types.Transaction, sync bool) []error { var ( adds = make([]*types.Transaction, 0, len(txs)) @@ -1813,6 +1816,9 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus { // Clear implements txpool.SubPool, removing all tracked transactions // from the blob pool and persistent store. +// +// Note, do not use this in production / live code. In live code, the pool is +// meant to reset on a separate thread to avoid DoS vectors. func (p *BlobPool) Clear() { p.lock.Lock() defer p.lock.Unlock() diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index e576f1b39..a765c7f93 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1048,8 +1048,8 @@ func (pool *LegacyPool) addRemoteSync(tx *types.Transaction) error { // Add enqueues a batch of transactions into the pool if they are valid. // -// If sync is set, the method will block until all internal maintenance related -// to the add is finished. Only use this during tests for determinism! +// Note, if sync is set the method will block until all internal maintenance +// related to the add is finished. Only use this during tests for determinism. func (pool *LegacyPool) Add(txs []*types.Transaction, sync bool) []error { // Filter out known ones without obtaining the pool lock or recovering signatures var ( @@ -2011,6 +2011,9 @@ func numSlots(tx *types.Transaction) int { // Clear implements txpool.SubPool, removing all tracked txs from the pool // and rotating the journal. +// +// Note, do not use this in production / live code. In live code, the pool is +// meant to reset on a separate thread to avoid DoS vectors. func (pool *LegacyPool) Clear() { pool.mu.Lock() defer pool.mu.Unlock() diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index c4aeb4463..17bb5045c 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -353,6 +353,9 @@ func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error { // Add enqueues a batch of transactions into the pool if they are valid. Due // to the large transaction churn, add may postpone fully integrating the tx // to a later point to batch multiple ones together. +// +// Note, if sync is set the method will block until all internal maintenance +// related to the add is finished. Only use this during tests for determinism. func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error { // Split the input transactions between the subpools. It shouldn't really // happen that we receive merged batches, but better graceful than strange @@ -530,8 +533,8 @@ func (p *TxPool) Status(hash common.Hash) TxStatus { // internal background reset operations. This method will run an explicit reset // operation to ensure the pool stabilises, thus avoiding flakey behavior. // -// Note, do not use this in production / live code. In live code, the pool is -// meant to reset on a separate thread to avoid DoS vectors. +// Note, this method is only used for testing and is susceptible to DoS vectors. +// In production code, the pool is meant to reset on a separate thread. func (p *TxPool) Sync() error { sync := make(chan error) select { @@ -543,6 +546,10 @@ func (p *TxPool) Sync() error { } // Clear removes all tracked txs from the subpools. +// +// Note, this method invokes Sync() and is only used for testing, because it is +// susceptible to DoS vectors. In production code, the pool is meant to reset on +// a separate thread. func (p *TxPool) Clear() { // Invoke Sync to ensure that txs pending addition don't get added to the pool after // the subpools are subsequently cleared From 43502b7dc011f5a9fa66dcfed57944eb73a2c4c6 Mon Sep 17 00:00:00 2001 From: Luis Ayuso Date: Thu, 10 Apr 2025 03:11:24 +0200 Subject: [PATCH 284/354] core/txpool: allow tx and authority regardless of admission order (#31373) This PR proposes a change to the authorizations' validation introduced in commit cdb66c8. These changes make the expected behavior independent of the order of admission of authorizations, improving the predictability of the resulting state and the usability of the system with it. The current implementation behavior is dependent on the transaction submission order: This issue is related to authorities and the sender of a transaction, and can be reproduced respecting the normal nonce rules. The issue can be reproduced by the two following cases: **First case** - Given an empty pool. - Submit transaction `{ from: B, auths [ A ] }`: is accepted. - Submit transaction `{ from: A }`: Is accepted: it becomes the one in-flight transaction allowed. **Second case** - Given an empty pool. - Submit transaction `{ from: A }`: is accepted - Submit transaction `{ from: B, auths [ A ] }`: is rejected since there is already a queued/pending transaction from A. The expected behavior is that both sequences of events would lead to the same sets of accepted and rejected transactions. **Proposed changes** The queued/pending transactions issued from any authority of the transaction being validated have to be counted, allowing one transaction from accounts submitting an authorization. - Notice that the expected behavior was explicitly forbidden in the case "reject-delegation-from-pending-account", I believe that this behavior conflicts to the definition of the limitation, and it is removed in this PR. The expected behavior is tested in "accept-authorization-from-sender-of-one-inflight-tx". - Replacement tests have been separated to improve readability of the acceptance test. - The test "allow-more-than-one-tx-from-replaced-authority" has been extended with one extra transaction, since the system would always have accepted one transaction (but not two). - The test "accept-one-inflight-tx-of-delegated-account" is extended to clean-up state, avoiding leaking the delegation used into the other tests. Additionally, replacement check is removed to be tested in its own test case. **Expected behavior** The expected behavior of the authorizations' validation shall be as follows: ![image](https://github.com/user-attachments/assets/dbde7a1f-9679-4691-94eb-c197a0cbb823) Notice that replacement shall be allowed, and behavior shall remain coherent with the table, according to the replaced transaction. --------- Co-authored-by: lightclient --- consensus/dbft/dbft.go | 2 +- core/txpool/blobpool/blobpool.go | 4 +- core/txpool/blobpool/blobpool_test.go | 43 ++++- core/txpool/legacypool/cachepool.go | 49 +----- core/txpool/legacypool/cachepool_test.go | 10 +- core/txpool/legacypool/legacypool.go | 32 ++-- core/txpool/legacypool/legacypool_test.go | 190 +++++++++++++++++----- core/txpool/reserver.go | 61 +++++-- core/txpool/subpool.go | 2 +- 9 files changed, 269 insertions(+), 124 deletions(-) diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index a0f1a1903..237dcebaf 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -1290,7 +1290,7 @@ func newStaticPool(chain ChainHeaderReader) *legacypool.LegacyPool { // initStaticPool initializes the static pool with the provided parent header. func (c *DBFT) initStaticPool(parent *types.Header, state *state.StateDB) error { - return c.staticPool.InitStatic(legacypool.DefaultConfig.PriceLimit, parent, state, func(addr common.Address, reserve bool) error { return nil }, false) + return c.staticPool.InitStatic(legacypool.DefaultConfig.PriceLimit, parent, state, &txpool.EmptyReservationHandle{}, false) } // validateDecryptedTx checks the validity of the transaction to determine whether the outer envelope transaction should be replaced. diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 27a51bde7..705081336 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -299,7 +299,7 @@ func newBlobTxMeta(id uint64, size uint64, storageSize uint32, tx *types.Transac // and leading up to the first no-change. type BlobPool struct { config Config // Pool configuration - reserver *txpool.Reserver // Address reserver to ensure exclusivity across subpools + reserver txpool.Reserver // Address reserver to ensure exclusivity across subpools hasPendingAuth func(common.Address) bool // Determine whether the specified address has a pending 7702-auth store billy.Database // Persistent data store for the tx metadata and blobs @@ -364,7 +364,7 @@ func (p *BlobPool) FilterAdd(tx *types.Transaction, local bool) bool { // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The transaction journal will be loaded // from disk and filtered based on the provided starting settings. -func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver *txpool.Reserver) error { +func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reserver) error { p.reserver = reserver var ( diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 4dfba3b52..76d21a0c9 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -26,6 +26,7 @@ import ( "math/big" "os" "path/filepath" + "sync" "testing" "github.com/ethereum/go-ethereum/common" @@ -167,6 +168,44 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { return bc.statedb, nil } +// reserver is a utility struct to sanity check that accounts are +// properly reserved by the blobpool (no duplicate reserves or unreserves). +type reserver struct { + accounts map[common.Address]struct{} + lock sync.RWMutex +} + +func newReserver() txpool.Reserver { + return &reserver{accounts: make(map[common.Address]struct{})} +} + +func (r *reserver) Hold(addr common.Address) error { + r.lock.Lock() + defer r.lock.Unlock() + if _, exists := r.accounts[addr]; exists { + panic("already reserved") + } + r.accounts[addr] = struct{}{} + return nil +} + +func (r *reserver) Release(addr common.Address) error { + r.lock.Lock() + defer r.lock.Unlock() + if _, exists := r.accounts[addr]; !exists { + panic("not reserved") + } + delete(r.accounts, addr) + return nil +} + +func (r *reserver) Has(address common.Address) bool { + r.lock.RLock() + defer r.lock.RUnlock() + _, exists := r.accounts[address] + return exists +} + // makeTx is a utility method to construct a random blob transaction and sign it // with a valid key, only setting the interesting fields from the perspective of // the blob pool. @@ -405,10 +444,6 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { } } -func newReserver() *txpool.Reserver { - return txpool.NewReservationTracker().NewHandle(42) -} - // Tests that transactions can be loaded from disk on startup and that they are // correctly discarded if invalid. // diff --git a/core/txpool/legacypool/cachepool.go b/core/txpool/legacypool/cachepool.go index 1fb6622a0..47180b73c 100644 --- a/core/txpool/legacypool/cachepool.go +++ b/core/txpool/legacypool/cachepool.go @@ -104,10 +104,9 @@ type CachePool struct { currentHead atomic.Pointer[types.Header] // Current head of the blockchain currentState *state.StateDB // Current state in the blockchain head - reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools - cached map[common.Address]*list // All currently cached transactions - beats map[common.Address]time.Time // Last heartbeat from each known account - all *lookup // All transactions to allow lookups + cached map[common.Address]*list // All currently cached transactions + beats map[common.Address]time.Time // Last heartbeat from each known account + all *lookup // All transactions to allow lookups reqResetCh chan *txpoolResetRequest reorgDoneCh chan chan struct{} @@ -174,10 +173,7 @@ func (pool *CachePool) FilterAdd(tx *types.Transaction, local bool) bool { // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The internal goroutines will be spun up // and the pool deemed operational afterwards. -func (pool *CachePool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error { - // No need for address reserver processing. - pool.reserve = func(addr common.Address, reserve bool) error { return nil } - +func (pool *CachePool) Init(gasTip uint64, head *types.Header, _ txpool.Reserver) error { // Set the basic pool parameters pool.gasTip.Store(uint256.NewInt(gasTip)) @@ -427,29 +423,6 @@ func (pool *CachePool) add(tx *types.Transaction) (replaced bool, err error) { // already validated by this point from, _ := types.Sender(pool.signer, tx) - // If the address is not yet known, request exclusivity to track the account - // only by this subpool until all transactions are evicted - var ( - _, hasCached = pool.cached[from] - ) - if !hasCached { - if err := pool.reserve(from, true); err != nil { - return false, err - } - defer func() { - // If the transaction is rejected by some post-validation check, remove - // the lock on the reservation set. - // - // Note, `err` here is the named error return, which will be initialized - // by a return statement before running deferred methods. Take care with - // removing or subscoping err as it will break this clause. - // - // This error "ErrTxPoolCached" indicates successful caching, so it needs to be excluded. - if err != nil && !errors.Is(err, ErrTxPoolCached) { - pool.reserve(from, false) - } - }() - } // If the cache pool is full, discard underpriced transactions if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots { // We're about to replace a transaction. The reorg does a more thorough @@ -620,19 +593,6 @@ func (pool *CachePool) removeTx(hash common.Hash, outofbound bool, unreserve boo } addr, _ := types.Sender(pool.signer, tx) // already validated during insertion - // If after deletion there are no more transactions belonging to this account, - // relinquish the address reservation. It's a bit convoluted do this, via a - // defer, but it's safer vs. the many return pathways. - if unreserve { - defer func() { - var ( - _, hasCached = pool.cached[addr] - ) - if !hasCached { - pool.reserve(addr, false) - } - }() - } // Remove it from the list of known transactions pool.all.Remove(hash) // Remove the transaction from the cached lists and reset the account nonce @@ -867,7 +827,6 @@ func (pool *CachePool) demoteUnexecutables() { if list.Empty() { delete(pool.cached, addr) delete(pool.beats, addr) - pool.reserve(addr, false) } } } diff --git a/core/txpool/legacypool/cachepool_test.go b/core/txpool/legacypool/cachepool_test.go index 51ed9ab6a..209e981ef 100644 --- a/core/txpool/legacypool/cachepool_test.go +++ b/core/txpool/legacypool/cachepool_test.go @@ -41,7 +41,7 @@ func setupCachePoolWithConfig(config *params.ChainConfig) (*CachePool, *ecdsa.Pr key, _ := crypto.GenerateKey() pool := NewCache(testCachePoolConfig, blockchain) - if err := pool.Init(1, blockchain.CurrentBlock(), makeAddressReserver()); err != nil { + if err := pool.Init(1, blockchain.CurrentBlock(), newReserver()); err != nil { panic(err) } // wait for the pool to initialize @@ -78,7 +78,7 @@ func TestCachePool(t *testing.T) { config := testCachePoolConfig pool := NewCache(config, blockchain) - pool.Init(1, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(1, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them (last one will be the local) @@ -286,7 +286,7 @@ func TestCacheTimeLimiting(t *testing.T) { config.Lifetime = time.Second pool := NewCache(config, blockchain) - pool.Init(1, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(1, blockchain.CurrentBlock(), newReserver()) defer pool.Close() local, _ := crypto.GenerateKey() @@ -388,7 +388,7 @@ func TestCachePoolCapClearsFromAll(t *testing.T) { config.GlobalSlots = 8 pool := NewCache(config, blockchain) - pool.Init(1, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(1, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create a number of test accounts and fund them @@ -417,7 +417,7 @@ func TestCachePoolStatusCheck(t *testing.T) { blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := NewCache(testCachePoolConfig, blockchain) - pool.Init(1, blockchain.CurrentBlock(), makeAddressReserver()) + pool.Init(1, blockchain.CurrentBlock(), newReserver()) defer pool.Close() // Create the test accounts to check various transaction statuses with diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index a765c7f93..ca0796a93 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -260,7 +260,7 @@ type LegacyPool struct { currentHead atomic.Pointer[types.Header] // Current head of the blockchain currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces - reserver *txpool.Reserver // Address reserver to ensure exclusivity across subpools + reserver txpool.Reserver // Address reserver to ensure exclusivity across subpools pending map[common.Address]*list // All currently processable transactions queue map[common.Address]*list // Queued but non-processable transactions @@ -346,9 +346,9 @@ func (pool *LegacyPool) FilterAdd(tx *types.Transaction, local bool) bool { // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The internal // goroutines will be spun up and the pool deemed operational afterwards. -func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver *txpool.Reserver) error { +func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reserver) error { // Do basic initializations about reserver, gas price and state - pool.InitStatic(gasTip, head, nil, reserve, true) + pool.InitStatic(gasTip, head, nil, reserver, true) // Start the reorg loop early, so it can handle requests generated during // journal loading. @@ -363,7 +363,7 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver *txpool // InitStatic sets the gas price needed to keep a transaction in the pool // and the chain head to allow balance / nonce checks. This method doesn't // start loops or load journals, so the pool can be released automatically. -func (pool *LegacyPool) InitStatic(gasTip uint64, head *types.Header, statedb *state.StateDB, reserve txpool.AddressReserver, allowMissingState bool) error { +func (pool *LegacyPool) InitStatic(gasTip uint64, head *types.Header, statedb *state.StateDB, reserver txpool.Reserver, allowMissingState bool) error { // Set the address reserver to request exclusive access to pooled accounts pool.reserver = reserver @@ -761,11 +761,18 @@ func (pool *LegacyPool) validateAuth(tx *types.Transaction) error { if err := pool.checkDelegationLimit(tx); err != nil { return err } - // Authorities must not conflict with any pending or queued transactions, - // nor with addresses that have already been reserved. + // For symmetry, allow at most one in-flight tx for any authority with a + // pending transaction. if auths := tx.SetCodeAuthorities(); len(auths) > 0 { for _, auth := range auths { - if pool.pending[auth] != nil || pool.queue[auth] != nil { + var count int + if pending := pool.pending[auth]; pending != nil { + count += pending.Len() + } + if queue := pool.queue[auth]; queue != nil { + count += queue.Len() + } + if count > 1 { return ErrAuthorityReserved } // Because there is no exclusive lock held between different subpools @@ -2032,9 +2039,14 @@ func (pool *LegacyPool) Clear() { // The transaction addition may attempt to reserve the sender addr which // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. - for _, tx := range pool.all.txs { - senderAddr, _ := types.Sender(pool.signer, tx) - pool.reserver.Release(senderAddr) + + for addr := range pool.pending { + if _, ok := pool.queue[addr]; !ok { + pool.reserver.Release(addr) + } + } + for addr := range pool.queue { + pool.reserver.Release(addr) } pool.all = newLookup() pool.priced = newPricedList(pool.all) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index c47a65520..bb1323a7d 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -24,6 +24,7 @@ import ( "math/big" "math/rand" "slices" + "sync" "sync/atomic" "testing" "time" @@ -171,8 +172,39 @@ func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { return setupPoolWithConfig(params.TestChainConfig) } -func newReserver() *txpool.Reserver { - return txpool.NewReservationTracker().NewHandle(42) +// reserver is a utility struct to sanity check that accounts are +// properly reserved by the blobpool (no duplicate reserves or unreserves). +type reserver struct { + accounts map[common.Address]struct{} + lock sync.RWMutex +} + +func newReserver() txpool.Reserver { + return &reserver{accounts: make(map[common.Address]struct{})} +} + +func (r *reserver) Hold(addr common.Address) error { + r.lock.Lock() + defer r.lock.Unlock() + if _, exists := r.accounts[addr]; exists { + panic("already reserved") + } + r.accounts[addr] = struct{}{} + return nil +} + +func (r *reserver) Release(addr common.Address) error { + r.lock.Lock() + defer r.lock.Unlock() + if _, exists := r.accounts[addr]; !exists { + panic("not reserved") + } + delete(r.accounts, addr) + return nil +} + +func (r *reserver) Has(address common.Address) bool { + return false // reserver only supports a single pool } func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { @@ -2232,9 +2264,8 @@ func TestSetCodeTransactions(t *testing.T) { }{ { // Check that only one in-flight transaction is allowed for accounts - // with delegation set. Also verify the accepted transaction can be - // replaced by fee. - name: "only-one-in-flight", + // with delegation set. + name: "accept-one-inflight-tx-of-delegated-account", pending: 1, run: func(name string) { aa := common.Address{0xaa, 0xaa} @@ -2249,6 +2280,7 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil { t.Fatalf("%s: failed to add remote transaction: %v", name, err) } + // Second and further transactions shall be rejected if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyA)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) } @@ -2260,44 +2292,90 @@ func TestSetCodeTransactions(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyA)); err != nil { t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) } + + // Reset the delegation, avoid leaking state into the other tests + statedb.SetCode(addrA, nil) }, }, { - name: "allow-setcode-tx-with-pending-authority-tx", + // This test is analogous to the previous one, but the delegation is pending + // instead of set. + name: "allow-one-tx-from-pooled-delegation", pending: 2, run: func(name string) { - // Send two transactions where the first has no conflicting delegations and - // the second should be allowed despite conflicting with the authorities in 1). - if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil { + // Create a pending delegation request from B. + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } - if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { - t.Fatalf("%s: failed to add conflicting delegation: %v", name, err) + // First transaction from B is accepted. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { + t.Fatalf("%s: failed to add remote transaction: %v", name, err) + } + // Second transaction fails due to limit. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) + } + // Replace by fee for first transaction from B works. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(2), keyB)); err != nil { + t.Fatalf("%s: failed to add remote transaction: %v", name, err) } }, }, { - name: "allow-one-tx-from-pooled-delegation", + // This is the symmetric case of the previous one, where the delegation request + // is received after the transaction. The resulting state shall be the same. + name: "accept-authorization-from-sender-of-one-inflight-tx", pending: 2, run: func(name string) { - // Verify C cannot originate another transaction when it has a pooled delegation. - if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyC}})); err != nil { - t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + // The first in-flight transaction is accepted. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { + t.Fatalf("%s: failed to add with pending delegation: %v", name, err) } - if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyC)); err != nil { - t.Fatalf("%s: failed to add with pending delegatio: %v", name, err) + // Delegation is accepted. + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); err != nil { + t.Fatalf("%s: failed to add remote transaction: %v", name, err) } - // Also check gapped transaction is rejected. - if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyC)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + // The second in-flight transaction is rejected. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) } }, }, + { + name: "reject-authorization-from-sender-with-more-than-one-inflight-tx", + pending: 2, + run: func(name string) { + // Submit two transactions. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { + t.Fatalf("%s: failed to add with pending delegation: %v", name, err) + } + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); err != nil { + t.Fatalf("%s: failed to add with pending delegation: %v", name, err) + } + // Delegation rejected since two txs are already in-flight. + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); !errors.Is(err, ErrAuthorityReserved) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrAuthorityReserved, err) + } + }, + }, + { + name: "allow-setcode-tx-with-pending-authority-tx", + pending: 2, + run: func(name string) { + // Send two transactions where the first has no conflicting delegations and + // the second should be allowed despite conflicting with the authorities in the first. + if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { + t.Fatalf("%s: failed to add conflicting delegation: %v", name, err) + } + }, + }, { name: "replace-by-fee-setcode-tx", pending: 1, run: func(name string) { - // 4. Fee bump the setcode tx send. if err := pool.addRemoteSync(setCodeTx(0, keyB, []unsignedAuth{{1, keyC}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } @@ -2307,44 +2385,85 @@ func TestSetCodeTransactions(t *testing.T) { }, }, { - name: "allow-tx-from-replaced-authority", - pending: 2, + name: "allow-more-than-one-tx-from-replaced-authority", + pending: 3, run: func(name string) { - // Fee bump with a different auth list. Make sure that unlocks the authorities. + // Send transaction from A with B as an authority. if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } + // Replace transaction with another having C as an authority. if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(3000), uint256.NewInt(300), keyA, []unsignedAuth{{0, keyC}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } - // Now send a regular tx from B. + // B should not be considred as having an in-flight delegation, so + // should allow more than one pooled transaction. if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(10), keyB)); err != nil { t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) } + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(10), keyB)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } }, }, { + // This test is analogous to the previous one, but the the replaced + // transaction is self-sponsored. name: "allow-tx-from-replaced-self-sponsor-authority", - pending: 2, + pending: 3, run: func(name string) { - // + // Send transaction from A with A as an authority. if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyA}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } + // Replace transaction with a transaction with B as an authority. if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(30), uint256.NewInt(30), keyA, []unsignedAuth{{0, keyB}})); err != nil { t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) } - // Now send a regular tx from keyA. - if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyA)); err != nil { + // The one in-flight transaction limit from A no longer applies, so we + // can stack a second transaction for the account. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1000), keyA)); err != nil { t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) } - // Make sure we can still send from keyB. + // B should still be able to send transactions. if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyB)); err != nil { t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) } + // However B still has the limitation to one in-flight transaction. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) + } }, }, { + name: "replacements-respect-inflight-tx-count", + pending: 2, + run: func(name string) { + // Send transaction from A with B as an authority. + if err := pool.addRemoteSync(pricedSetCodeTx(0, 250000, uint256.NewInt(10), uint256.NewInt(3), keyA, []unsignedAuth{{0, keyB}})); err != nil { + t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) + } + // Send two transactions from B. Only the first should be accepted due + // to in-flight limit. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyB)); err != nil { + t.Fatalf("%s: failed to add remote transaction: %v", name, err) + } + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) + } + // Replace the in-flight transaction from B. + if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(30), keyB)); err != nil { + t.Fatalf("%s: failed to replace with remote transaction: %v", name, err) + } + // Ensure the in-flight limit for B is still in place. + if err := pool.addRemoteSync(pricedTransaction(1, 100000, big.NewInt(1), keyB)); !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("%s: error mismatch: want %v, have %v", name, txpool.ErrInflightTxLimitReached, err) + } + }, + }, + { + // Since multiple authorizations can be pending simultaneously, replacing + // one of them should not break the one in-flight-transaction limit. name: "track-multiple-conflicting-delegations", pending: 3, run: func(name string) { @@ -2369,19 +2488,6 @@ func TestSetCodeTransactions(t *testing.T) { } }, }, - { - name: "reject-delegation-from-pending-account", - pending: 1, - run: func(name string) { - // Attempt to submit a delegation from an account with a pending tx. - if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1000), keyC)); err != nil { - t.Fatalf("%s: failed to add with remote setcode transaction: %v", name, err) - } - if err, want := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{1, keyC}})), ErrAuthorityReserved; !errors.Is(err, want) { - t.Fatalf("%s: error mismatch: want %v, have %v", name, want, err) - } - }, - }, { name: "remove-hash-from-authority-tracker", pending: 10, diff --git a/core/txpool/reserver.go b/core/txpool/reserver.go index 76ead0f3b..ac9b6a573 100644 --- a/core/txpool/reserver.go +++ b/core/txpool/reserver.go @@ -52,22 +52,37 @@ func NewReservationTracker() *ReservationTracker { // NewHandle creates a named handle on the ReservationTracker. The handle // identifies the subpool so ownership of reservations can be determined. -func (r *ReservationTracker) NewHandle(id int) *Reserver { - return &Reserver{r, id} +func (r *ReservationTracker) NewHandle(id int) *ReservationHandle { + return &ReservationHandle{r, id} } -// Reserver is a named handle on ReservationTracker. It is held by subpools to +// Reserver is an interface for creating and releasing owned reservations in the +// ReservationTracker struct, which is shared between subpools. +type Reserver interface { + // Hold attempts to reserve the specified account address for the given pool. + // Returns an error if the account is already reserved. + Hold(addr common.Address) error + + // Release attempts to release the reservation for the specified account. + // Returns an error if the address is not reserved or is reserved by another pool. + Release(addr common.Address) error + + // Has returns a flag indicating if the address has been reserved by a pool + // other than one with the current Reserver handle. + Has(address common.Address) bool +} + +// ReservationHandle is a named handle on ReservationTracker. It is held by subpools to // make reservations for accounts it is tracking. The id is used to determine // which pool owns an address and disallows non-owners to hold or release // addresses it doesn't own. -type Reserver struct { +type ReservationHandle struct { tracker *ReservationTracker id int } -// Hold attempts to reserve the specified account address for the given pool. -// Returns an error if the account is already reserved. -func (h *Reserver) Hold(addr common.Address) error { +// Hold implements the Reserver interface. +func (h *ReservationHandle) Hold(addr common.Address) error { h.tracker.lock.Lock() defer h.tracker.lock.Unlock() @@ -89,9 +104,8 @@ func (h *Reserver) Hold(addr common.Address) error { return nil } -// Release attempts to release the reservation for the specified account. -// Returns an error if the address is not reserved or is reserved by another pool. -func (h *Reserver) Release(addr common.Address) error { +// Release implements the Reserver interface. +func (h *ReservationHandle) Release(addr common.Address) error { h.tracker.lock.Lock() defer h.tracker.lock.Unlock() @@ -114,11 +128,30 @@ func (h *Reserver) Release(addr common.Address) error { return nil } -// Has returns a flag indicating if the address has been reserved or not. -func (h *Reserver) Has(address common.Address) bool { +// Has implements the Reserver interface. +func (h *ReservationHandle) Has(address common.Address) bool { h.tracker.lock.RLock() defer h.tracker.lock.RUnlock() - _, exists := h.tracker.accounts[address] - return exists + id, exists := h.tracker.accounts[address] + return exists && id != h.id +} + +// EmptyReservationHandle is a no-op implementation of the Reserver interface. +type EmptyReservationHandle struct { +} + +// Hold implements the Reserver interface. +func (h *EmptyReservationHandle) Hold(addr common.Address) error { + return nil +} + +// Release implements the Reserver interface. +func (h *EmptyReservationHandle) Release(addr common.Address) error { + return nil +} + +// Has implements the Reserver interface. +func (h *EmptyReservationHandle) Has(address common.Address) bool { + return false } diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 362b42853..c379fd475 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -113,7 +113,7 @@ type SubPool interface { // These should not be passed as a constructor argument - nor should the pools // start by themselves - in order to keep multiple subpools in lockstep with // one another. - Init(gasTip uint64, head *types.Header, reserver *Reserver) error + Init(gasTip uint64, head *types.Header, reserver Reserver) error // Close terminates any background processing threads and releases any held // resources. From 4965085466db26e7d0119773c701188b500638a4 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 10 Apr 2025 12:26:35 +0300 Subject: [PATCH 285/354] eth/fetcher: Fix flaky TestTransactionForgotten test using mock clock (#31468) Fixes #31169 The TestTransactionForgotten test was flaky due to real time dependencies. This PR: - Replaces real time with mock clock for deterministic timing control - Adds precise state checks at timeout boundaries - Verifies underpriced cache states and cleanup - Improves test reliability by controlling transaction timestamps - Adds checks for transaction re-enqueueing behavior The changes ensure consistent test behavior without timing-related flakiness. --------- Co-authored-by: Zsolt Felfoldi --- eth/fetcher/tx_fetcher.go | 14 +-- eth/fetcher/tx_fetcher_test.go | 98 ++++++++++++++++++--- tests/fuzzers/txfetcher/txfetcher_fuzzer.go | 7 +- 3 files changed, 99 insertions(+), 20 deletions(-) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 97d1e2986..1c192d411 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -202,22 +202,23 @@ type TxFetcher struct { fetchTxs func(string, []common.Hash) error // Retrieves a set of txs from a remote peer dropPeer func(string) // Drops a peer in case of announcement violation - step chan struct{} // Notification channel when the fetcher loop iterates - clock mclock.Clock // Time wrapper to simulate in tests - rand *mrand.Rand // Randomizer to use in tests instead of map range loops (soft-random) + step chan struct{} // Notification channel when the fetcher loop iterates + clock mclock.Clock // Monotonic clock or simulated clock for tests + realTime func() time.Time // Real system time or simulated time for tests + rand *mrand.Rand // Randomizer to use in tests instead of map range loops (soft-random) } // NewTxFetcher creates a transaction fetcher to retrieve transaction // based on hash announcements. func NewTxFetcher(hasTx func(common.Hash) bool, addTxs func([]*types.Transaction) []error, fetchTxs func(string, []common.Hash) error, dropPeer func(string)) *TxFetcher { - return NewTxFetcherForTests(hasTx, addTxs, fetchTxs, dropPeer, mclock.System{}, nil) + return NewTxFetcherForTests(hasTx, addTxs, fetchTxs, dropPeer, mclock.System{}, time.Now, nil) } // NewTxFetcherForTests is a testing method to mock out the realtime clock with // a simulated version and the internal randomness with a deterministic one. func NewTxFetcherForTests( hasTx func(common.Hash) bool, addTxs func([]*types.Transaction) []error, fetchTxs func(string, []common.Hash) error, dropPeer func(string), - clock mclock.Clock, rand *mrand.Rand) *TxFetcher { + clock mclock.Clock, realTime func() time.Time, rand *mrand.Rand) *TxFetcher { return &TxFetcher{ notify: make(chan *txAnnounce), cleanup: make(chan *txDelivery), @@ -237,6 +238,7 @@ func NewTxFetcherForTests( fetchTxs: fetchTxs, dropPeer: dropPeer, clock: clock, + realTime: realTime, rand: rand, } } @@ -293,7 +295,7 @@ func (f *TxFetcher) Notify(peer string, types []byte, sizes []uint32, hashes []c // isKnownUnderpriced reports whether a transaction hash was recently found to be underpriced. func (f *TxFetcher) isKnownUnderpriced(hash common.Hash) bool { prevTime, ok := f.underpriced.Peek(hash) - if ok && prevTime.Before(time.Now().Add(-maxTxUnderpricedTimeout)) { + if ok && prevTime.Before(f.realTime().Add(-maxTxUnderpricedTimeout)) { f.underpriced.Remove(hash) return false } diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 52b359108..7f3080f5f 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -2150,9 +2150,22 @@ func containsHashInAnnounces(slice []announce, hash common.Hash) bool { return false } -// Tests that a transaction is forgotten after the timeout. +// TestTransactionForgotten verifies that underpriced transactions are properly +// forgotten after the timeout period, testing both the exact timeout boundary +// and the cleanup of the underpriced cache. func TestTransactionForgotten(t *testing.T) { - fetcher := NewTxFetcher( + // Test ensures that underpriced transactions are properly forgotten after a timeout period, + // including checks for timeout boundary and cache cleanup. + t.Parallel() + + // Create a mock clock for deterministic time control + mockClock := new(mclock.Simulated) + mockTime := func() time.Time { + nanoTime := int64(mockClock.Now()) + return time.Unix(nanoTime/1000000000, nanoTime%1000000000) + } + + fetcher := NewTxFetcherForTests( func(common.Hash) bool { return false }, func(txs []*types.Transaction) []error { errs := make([]error, len(txs)) @@ -2163,24 +2176,83 @@ func TestTransactionForgotten(t *testing.T) { }, func(string, []common.Hash) error { return nil }, func(string) {}, + mockClock, + mockTime, + rand.New(rand.NewSource(0)), // Use fixed seed for deterministic behavior ) fetcher.Start() defer fetcher.Stop() - // Create one TX which is 5 minutes old, and one which is recent - tx1 := types.NewTx(&types.LegacyTx{Nonce: 0}) - tx1.SetTime(time.Now().Add(-maxTxUnderpricedTimeout - 1*time.Second)) - tx2 := types.NewTx(&types.LegacyTx{Nonce: 1}) - // Enqueue both in the fetcher. They will be immediately tagged as underpriced - if err := fetcher.Enqueue("asdf", []*types.Transaction{tx1, tx2}, false); err != nil { + // Create two test transactions with the same timestamp + tx1 := types.NewTransaction(0, common.Address{}, big.NewInt(100), 21000, big.NewInt(1), nil) + tx2 := types.NewTransaction(1, common.Address{}, big.NewInt(100), 21000, big.NewInt(1), nil) + + now := mockTime() + tx1.SetTime(now) + tx2.SetTime(now) + + // Initial state: both transactions should be marked as underpriced + if err := fetcher.Enqueue("peer", []*types.Transaction{tx1, tx2}, false); err != nil { t.Fatal(err) } - // isKnownUnderpriced should trigger removal of the first tx (no longer be known underpriced) - if fetcher.isKnownUnderpriced(tx1.Hash()) { - t.Fatal("transaction should be forgotten by now") + if !fetcher.isKnownUnderpriced(tx1.Hash()) { + t.Error("tx1 should be underpriced") + } + if !fetcher.isKnownUnderpriced(tx2.Hash()) { + t.Error("tx2 should be underpriced") + } + + // Verify cache size + if size := fetcher.underpriced.Len(); size != 2 { + t.Errorf("wrong underpriced cache size: got %d, want %d", size, 2) + } + + // Just before timeout: transactions should still be underpriced + mockClock.Run(maxTxUnderpricedTimeout - time.Second) + if !fetcher.isKnownUnderpriced(tx1.Hash()) { + t.Error("tx1 should still be underpriced before timeout") + } + if !fetcher.isKnownUnderpriced(tx2.Hash()) { + t.Error("tx2 should still be underpriced before timeout") + } + + // Exactly at timeout boundary: transactions should still be present + mockClock.Run(time.Second) + if !fetcher.isKnownUnderpriced(tx1.Hash()) { + t.Error("tx1 should be present exactly at timeout") } - // isKnownUnderpriced should not trigger removal of the second if !fetcher.isKnownUnderpriced(tx2.Hash()) { - t.Fatal("transaction should be known underpriced") + t.Error("tx2 should be present exactly at timeout") + } + + // After timeout: transactions should be forgotten + mockClock.Run(time.Second) + if fetcher.isKnownUnderpriced(tx1.Hash()) { + t.Error("tx1 should be forgotten after timeout") + } + if fetcher.isKnownUnderpriced(tx2.Hash()) { + t.Error("tx2 should be forgotten after timeout") + } + + // Verify cache is empty + if size := fetcher.underpriced.Len(); size != 0 { + t.Errorf("wrong underpriced cache size after timeout: got %d, want 0", size) + } + + // Re-enqueue tx1 with updated timestamp + tx1.SetTime(mockTime()) + if err := fetcher.Enqueue("peer", []*types.Transaction{tx1}, false); err != nil { + t.Fatal(err) + } + if !fetcher.isKnownUnderpriced(tx1.Hash()) { + t.Error("tx1 should be underpriced after re-enqueueing with new timestamp") + } + if fetcher.isKnownUnderpriced(tx2.Hash()) { + t.Error("tx2 should remain forgotten") + } + + // Verify final cache state + if size := fetcher.underpriced.Len(); size != 1 { + t.Errorf("wrong final underpriced cache size: got %d, want 1", size) } } diff --git a/tests/fuzzers/txfetcher/txfetcher_fuzzer.go b/tests/fuzzers/txfetcher/txfetcher_fuzzer.go index 51f2fc3b4..c136253a6 100644 --- a/tests/fuzzers/txfetcher/txfetcher_fuzzer.go +++ b/tests/fuzzers/txfetcher/txfetcher_fuzzer.go @@ -84,7 +84,12 @@ func fuzz(input []byte) int { }, func(string, []common.Hash) error { return nil }, nil, - clock, rand, + clock, + func() time.Time { + nanoTime := int64(clock.Now()) + return time.Unix(nanoTime/1000000000, nanoTime%1000000000) + }, + rand, ) f.Start() defer f.Stop() From b4343994acf3668dcab074982bb0a7d008f9be39 Mon Sep 17 00:00:00 2001 From: HackyMiner Date: Thu, 10 Apr 2025 19:46:54 +0900 Subject: [PATCH 286/354] accounts/usbwallet: full 32bit chainId support for Trezor (#17439) This fix allows Trezor to support full 32bit chainId in geth, with the next version of firmware. For `chainId > 2147483630` case, Trezor returns signature bit only. - Trezor returns only signature parity for `chainId > 2147483630` case. - for `chainId == 2147483630` case, Trezor returns `MAX_UINT32` or `0`, but it doesn't matter. (`2147483630 * 2 + 35` = `4294967295`(`MAX_UINT32`)) chainId | returned signature_v | compatible issue ---------|------------------------|-------------------- 0 < chainId <= 255 | chainId * 2 + 35 + v | no issue (firmware `1.6.2` for Trezor one) 255 < chainId <= 2147483630 | chainId * 2 + 35 + v | ***fixed.*** *firmware `1.6.3`* chainId > 2147483630 | v | *firmware `1.6.3`* Please see also: full 32bit chainId support for Trezor - Trezor one: https://github.com/trezor/trezor-mcu/pull/399 ***merged*** - Trezor model T: https://github.com/trezor/trezor-core/pull/311 ***merged*** --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- accounts/usbwallet/trezor.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 1c4270d25..d4862d161 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -25,6 +25,7 @@ import ( "errors" "fmt" "io" + "math" "math/big" "github.com/ethereum/go-ethereum/accounts" @@ -249,7 +250,11 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction } } // Extract the Ethereum signature and do a sanity validation - if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 || response.GetSignatureV() == 0 { + if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 { + return common.Address{}, nil, errors.New("reply lacks signature") + } else if response.GetSignatureV() == 0 && int(chainID.Int64()) <= (math.MaxUint32-36)/2 { + // for chainId >= (MaxUint32-36)/2, Trezor returns signature bit only + // https://github.com/trezor/trezor-mcu/pull/399 return common.Address{}, nil, errors.New("reply lacks signature") } signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV())) @@ -261,7 +266,11 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction } else { // Trezor backend does not support typed transactions yet. signer = types.NewEIP155Signer(chainID) - signature[64] -= byte(chainID.Uint64()*2 + 35) + // if chainId is above (MaxUint32 - 36) / 2 then the final v values is returned + // directly. Otherwise, the returned value is 35 + chainid * 2. + if signature[64] > 1 && int(chainID.Int64()) <= (math.MaxUint32-36)/2 { + signature[64] -= byte(chainID.Uint64()*2 + 35) + } } // Inject the final signature into the transaction and sanity check the sender From 99cae495662d09766af93fb5510a949ec5184719 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 10 Apr 2025 19:49:54 +0800 Subject: [PATCH 287/354] eth/catalyst: in tests, manually sync txpool after initial chain insertion to prevent race between txpool head reset and promotion of txs that will be subsequently added (#31595) before this changes, this will result in numerous test failures: ``` > go test -run=Eth2AssembleBlock -c > stress ./catalyst.test ``` The reason is that after creating/inserting the test chain, there is a race between the txpool head reset and the promotion of txs added from tests. Ensuring that the txpool state is up to date with the head of the chain before proceeding fixes these flaky tests. --- eth/catalyst/api_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 3a0f5652b..1c67c9e6b 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -447,6 +447,9 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) n.Close() t.Fatal("can't import test blocks:", err) } + if err := ethservice.TxPool().Sync(); err != nil { + t.Fatal("failed to sync txpool after initial blockchain import:", err) + } if !ethservice.SetEtherbase(testAddr) { t.Fatal("can't set Etherbase") From c2c911f4af40c4bea94616c8b129a0163b515f61 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Fri, 11 Apr 2025 00:21:32 +0800 Subject: [PATCH 288/354] internal/testlog: fix log output from sub-loggers (#31539) When we instantiate a sub-logger via `go-ethereum/internal/testlog/logger.With`, we copy the reference to the `bufHandler` from the parent logger. However, internally, `go-ethereum/internal/testlog/logger.With` calls `log/slog/Logger.With` which creates a new handler instance (via `internal/bufHandler.WithAttrs`). This PR modifies sub-logger instantiation to use the newly-instantiated handler, instead of copying the reference from the parent instance. The type cast from `slog.Handler` to `*bufHandler` in `internal/testlog/Logger.With` is safe here because a `internal/testlog/Logger` can only be instantiated with a `*bufHandler` as the underlying handler type. Note, that I've also removed a pre-existing method that broke the above assumption. However, this method is not used in our codebase. I'm not sure if the assumption holds for forks of geth (e.g. optimism has modified the testlogger somewhat allowing test loggers to accept arbitrary handler types), but it seems okay to break API compatibility given that this is in the `internal` package. closes https://github.com/ethereum/go-ethereum/issues/31533 --- internal/testlog/testlog.go | 28 +++++++------ internal/testlog/testlog_test.go | 67 ++++++++++++++++++++++++++++++++ tests/testdata | 2 +- 3 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 internal/testlog/testlog_test.go diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index ad61af9ea..8a3ea8543 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -23,7 +23,6 @@ import ( "fmt" "log/slog" "sync" - "testing" "github.com/ethereum/go-ethereum/log" ) @@ -32,12 +31,21 @@ const ( termTimeFormat = "01-02|15:04:05.000" ) +// T wraps methods from testing.T used by the test logger into an interface. +// It is specified so that unit tests can instantiate the logger with an +// implementation of T which can capture the output of logging statements +// from T.Logf, as this cannot be using testing.T. +type T interface { + Logf(format string, args ...any) + Helper() +} + // logger implements log.Logger such that all output goes to the unit test log via // t.Logf(). All methods in between logger.Trace, logger.Debug, etc. are marked as test // helpers, so the file and line number in unit test output correspond to the call site // which emitted the log message. type logger struct { - t *testing.T + t T l log.Logger mu *sync.Mutex h *bufHandler @@ -78,7 +86,7 @@ func (h *bufHandler) WithGroup(_ string) slog.Handler { } // Logger returns a logger which logs to the unit test log of t. -func Logger(t *testing.T, level slog.Level) log.Logger { +func Logger(t T, level slog.Level) log.Logger { handler := bufHandler{ buf: []slog.Record{}, attrs: []slog.Attr{}, @@ -92,17 +100,6 @@ func Logger(t *testing.T, level slog.Level) log.Logger { } } -// LoggerWithHandler returns -func LoggerWithHandler(t *testing.T, handler slog.Handler) log.Logger { - var bh bufHandler - return &logger{ - t: t, - l: log.NewLogger(handler), - mu: new(sync.Mutex), - h: &bh, - } -} - func (l *logger) Handler() slog.Handler { return l.l.Handler() } @@ -170,7 +167,8 @@ func (l *logger) Crit(msg string, ctx ...interface{}) { } func (l *logger) With(ctx ...interface{}) log.Logger { - return &logger{l.t, l.l.With(ctx...), l.mu, l.h} + newLogger := l.l.With(ctx...) + return &logger{l.t, newLogger, l.mu, newLogger.Handler().(*bufHandler)} } func (l *logger) New(ctx ...interface{}) log.Logger { diff --git a/internal/testlog/testlog_test.go b/internal/testlog/testlog_test.go new file mode 100644 index 000000000..7789a4727 --- /dev/null +++ b/internal/testlog/testlog_test.go @@ -0,0 +1,67 @@ +package testlog + +import ( + "bytes" + "fmt" + "io" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/log" +) + +type mockT struct { + out io.Writer +} + +func (t *mockT) Helper() { + // noop for the purposes of unit tests +} + +func (t *mockT) Logf(format string, args ...any) { + // we could gate this operation in a mutex, but because testlogger + // only calls Logf with its internal mutex held, we just write output here + var lineBuf bytes.Buffer + if _, err := fmt.Fprintf(&lineBuf, format, args...); err != nil { + panic(err) + } + // The timestamp is locale-dependent, so we want to trim that off + // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." + sanitized := strings.Split(lineBuf.String(), "]")[1] + if _, err := t.out.Write([]byte(sanitized)); err != nil { + panic(err) + } +} + +func TestLogging(t *testing.T) { + tests := []struct { + name string + expected string + run func(t *mockT) + }{ + { + "SubLogger", + ` Visible + Hide and seek foobar=123 + Also visible +`, + func(t *mockT) { + l := Logger(t, log.LevelInfo) + subLogger := l.New("foobar", 123) + + l.Info("Visible") + subLogger.Info("Hide and seek") + l.Info("Also visible") + }, + }, + } + + for _, tc := range tests { + outp := bytes.Buffer{} + mock := mockT{&outp} + tc.run(&mock) + if outp.String() != tc.expected { + fmt.Printf("output mismatch.\nwant: '%s'\ngot: '%s'\n", tc.expected, outp.String()) + } + } +} diff --git a/tests/testdata b/tests/testdata index 81862e484..faf33b471 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 81862e4848585a438d64f911a19b3825f0f4cd95 +Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 From 1aff515f79322fd99a7f0480d646240058ed0826 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 10 Apr 2025 23:54:44 +0200 Subject: [PATCH 289/354] tests/testdata: revert to v17.0 The submodule was accidentally updated to another commit by f64aa6eaf7. --- tests/testdata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testdata b/tests/testdata index faf33b471..81862e484 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 +Subproject commit 81862e4848585a438d64f911a19b3825f0f4cd95 From 224c2eb0bff4e00c6af9d13e15859ccd1d31f2bf Mon Sep 17 00:00:00 2001 From: levisyin Date: Fri, 11 Apr 2025 17:28:14 +0800 Subject: [PATCH 290/354] build: upgrade -dlgo version to Go 1.24.2 (#31538) --- build/checksums.txt | 94 ++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 6d3b718c3..a914d7986 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,54 +5,54 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-6%40v1.0.0/ b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz -# version:golang 1.24.1 +# version:golang 1.24.2 # https://go.dev/dl/ -8244ebf46c65607db10222b5806aeb31c1fcf8979c1b6b12f60c677e9a3c0656 go1.24.1.src.tar.gz -8d627dc163a4bffa2b1887112ad6194af175dce108d606ed1714a089fb806033 go1.24.1.aix-ppc64.tar.gz -addbfce2056744962e2d7436313ab93486660cf7a2e066d171b9d6f2da7c7abe go1.24.1.darwin-amd64.tar.gz -58d529334561cff11087cd4ab18fe0b46d8d5aad88f45c02b9645f847e014512 go1.24.1.darwin-amd64.pkg -295581b5619acc92f5106e5bcb05c51869337eb19742fdfa6c8346c18e78ff88 go1.24.1.darwin-arm64.tar.gz -78b0fc8ddc344eb499f1a952c687cb84cbd28ba2b739cfa0d4eb042f07e44e82 go1.24.1.darwin-arm64.pkg -e70053f56f7eb93806d80cbd5726f78509a0a467602f7bea0e2c4ee8ed7c3968 go1.24.1.dragonfly-amd64.tar.gz -3595e2674ed8fe72e604ca59c964d3e5277aafb08475c2b1aaca2d2fd69c24fc go1.24.1.freebsd-386.tar.gz -47d7de8bb64d5c3ee7b6723aa62d5ecb11e3568ef2249bbe1d4bbd432d37c00c go1.24.1.freebsd-amd64.tar.gz -04eec3bcfaa14c1370cdf98e8307fac7e4853496c3045afb9c3124a29cbca205 go1.24.1.freebsd-arm.tar.gz -51aa70146e40cfdc20927424083dc86e6223f85dc08089913a1651973b55665b go1.24.1.freebsd-arm64.tar.gz -3c131d8e3fc285a1340f87813153e24226d3ddbd6e54f3facbd6e4c46a84655e go1.24.1.freebsd-riscv64.tar.gz -201d09da737ba39d5367f87d4e8b31edaeeb3dc9b9c407cb8cfb40f90c5a727a go1.24.1.illumos-amd64.tar.gz -8c530ecedbc17e42ce10177bea07ccc96a3e77c792ea1ea72173a9675d16ffa5 go1.24.1.linux-386.tar.gz -cb2396bae64183cdccf81a9a6df0aea3bce9511fc21469fb89a0c00470088073 go1.24.1.linux-amd64.tar.gz -8df5750ffc0281017fb6070fba450f5d22b600a02081dceef47966ffaf36a3af go1.24.1.linux-arm64.tar.gz -6d95f8d7884bfe2364644c837f080f2b585903d0b771eb5b06044e226a4f120a go1.24.1.linux-armv6l.tar.gz -19304a4a56e46d04604547d2d83235dc4f9b192c79832560ce337d26cc7b835a go1.24.1.linux-loong64.tar.gz -6347be77fa5359c12a5308c8ab87147c1fc4717b0c216493d1706c3b9fcde22d go1.24.1.linux-mips.tar.gz -1647df415f7030b82d4105670192aa7e8910e18563bb0d505192d72800cc2d21 go1.24.1.linux-mips64.tar.gz -762da594e4ec0f9cf6defae6ef971f5f7901203ee6a2d979e317adec96657317 go1.24.1.linux-mips64le.tar.gz -9d8133c7b23a557399fab870b5cf464079c2b623a43b214a7567cf11c254a444 go1.24.1.linux-mipsle.tar.gz -132f10999abbaccbada47fa85462db30c423955913b14d6c692de25f4636c766 go1.24.1.linux-ppc64.tar.gz -0fb522efcefabae6e37e69bdc444094e75bfe824ea6d4cc3cbc70c7ae1b16858 go1.24.1.linux-ppc64le.tar.gz -eaef4323d5467ff97fb1979c8491764060dade19f02f3275a9313f9a0da3b9c0 go1.24.1.linux-riscv64.tar.gz -6c05e14d8f11094cb56a1c50f390b6b658bed8a7cbd8d1a57e926581b7eabfce go1.24.1.linux-s390x.tar.gz -5dbb287d343ea00d58a70b11629f32ee716dc50a6875c459ea2018df0f294cd8 go1.24.1.netbsd-386.tar.gz -617aa3faee50ce84c343db0888e9a210c310a7203666b4ed620f31030c9fb32f go1.24.1.netbsd-amd64.tar.gz -59a928b7080c4a6ac985946274b7c65ce1cecc0b468ecd992d17b7c12fab9296 go1.24.1.netbsd-arm.tar.gz -28daa8d0feb4aef2af60cefa3305bb9314de7e8a05cbca41ac548964cdfe89b7 go1.24.1.netbsd-arm64.tar.gz -b7382b2f5d99813aeac14db482faa3bfbd47a68880b607fa2a7e669e26bab9cd go1.24.1.openbsd-386.tar.gz -2513b6537c45deead5e641c7ce7502913e7d5e6f0b21c52542fb11f81578690f go1.24.1.openbsd-amd64.tar.gz -853c1917d4fc7b144c55a02842aa48542d5cc798dde8db96dc0fdbc263200e04 go1.24.1.openbsd-arm.tar.gz -6bc207b91e6f6ae3347fb54616a8fb2f5c11983713846a4cef111ff3f4f94d14 go1.24.1.openbsd-arm64.tar.gz -4279260e2f2b94ee94e81470d13db7367f4393b061fee60985528fa0fa430df4 go1.24.1.openbsd-ppc64.tar.gz -6fc4023a0a339ee0778522364a127d94c78e62122288d47d820dba703f81dc07 go1.24.1.openbsd-riscv64.tar.gz -b5eb9fafd77146e7e1f748acfd95559580ecc8d2f15abf432a20f58c929c7cd2 go1.24.1.plan9-386.tar.gz -24dcad6361b141fc8cced15b092351e12a99d2e58d7013204a3013c50daf9fdd go1.24.1.plan9-amd64.tar.gz -a026ac3b55aa1e6fdc2aaab30207a117eafbe965ed81d3aa0676409f280ddc37 go1.24.1.plan9-arm.tar.gz -8e4f6a77388dc6e5aa481efd5abdb3b9f5c9463bb82f4db074494e04e5c84992 go1.24.1.solaris-amd64.tar.gz -b799f4ab264eef12a014c759383ed934056608c483e0f73e34ea6caf9f1df5f9 go1.24.1.windows-386.zip -db128981033ac82a64688a123f631e61297b6b8f52ca913145e57caa8ce94cc3 go1.24.1.windows-386.msi -95666b551453209a2b8869d29d177285ff9573af10f085d961d7ae5440f645ce go1.24.1.windows-amd64.zip -5968e7adcf26e68a54f1cd41ad561275a670a8e2ca5263bc375b524638557dfb go1.24.1.windows-amd64.msi -e28c4e6d0b913955765b46157ab88ae59bb636acaa12d7bec959aa6900f1cebd go1.24.1.windows-arm64.zip -6d352c1f154a102a5b90c480cc64bab205ccf2681e34e78a3a4d3f1ddfbc81e4 go1.24.1.windows-arm64.msi +9dc77ffadc16d837a1bf32d99c624cb4df0647cee7b119edd9e7b1bcc05f2e00 go1.24.2.src.tar.gz +427b373540d8fd51dbcc46bdecd340af109cd41514443c000d3dcde72b2c65a3 go1.24.2.aix-ppc64.tar.gz +238d9c065d09ff6af229d2e3b8b5e85e688318d69f4006fb85a96e41c216ea83 go1.24.2.darwin-amd64.tar.gz +535ed9ff283fee39575a7fb9b6d8b1901b6dc640d06dc71fd7d3faeefdaf8030 go1.24.2.darwin-amd64.pkg +b70f8b3c5b4ccb0ad4ffa5ee91cd38075df20fdbd953a1daedd47f50fbcff47a go1.24.2.darwin-arm64.tar.gz +4732f607a47ce4d898c0af01ff68f07e0820a6b50603aef5d5c777d1102505e2 go1.24.2.darwin-arm64.pkg +c17686b5fd61a663fbfafccfa177961be59386cf294e935ce35866b9dcb8e78a go1.24.2.dragonfly-amd64.tar.gz +026f1dd906189acff714c7625686bbc4ed91042618ba010d45b671461acc9e63 go1.24.2.freebsd-386.tar.gz +49399ba759b570a8f87d12179133403da6c2dd296d63a8830dee309161b9c40c go1.24.2.freebsd-amd64.tar.gz +1f48f47183794d97c29736004247ab541177cf984ac6322c78bc43828daa1172 go1.24.2.freebsd-arm.tar.gz +ef856428b60a8c0bd9a2cba596e83024be6f1c2d5574e89cb1ff2262b08df8b9 go1.24.2.freebsd-arm64.tar.gz +ec2088823e16df00600a6d0f72e9a7dc6d2f80c9c140c2043c0cf20e1404d1a9 go1.24.2.freebsd-riscv64.tar.gz +e030e7cedbb8688f1d75cb80f3de6ee2e6617a67d34051e794e5992b53462147 go1.24.2.illumos-amd64.tar.gz +4c382776d52313266f3026236297a224a6688751256a2dffa3f524d8d6f6c0ba go1.24.2.linux-386.tar.gz +68097bd680839cbc9d464a0edce4f7c333975e27a90246890e9f1078c7e702ad go1.24.2.linux-amd64.tar.gz +756274ea4b68fa5535eb9fe2559889287d725a8da63c6aae4d5f23778c229f4b go1.24.2.linux-arm64.tar.gz +438d5d3d7dcb239b58d893a715672eabe670b9730b1fd1c8fc858a46722a598a go1.24.2.linux-armv6l.tar.gz +6aefd3bf59c3c5592eda4fb287322207f119c2210f3795afa9be48d3ccb73e1b go1.24.2.linux-loong64.tar.gz +93e49bb4692783b0e9a2deab9558c6e8d2867f35592aeff285adda60924167f3 go1.24.2.linux-mips.tar.gz +6e86e703675016f3faf6604b8f68f20dc1bba75849136e6dd4f43f69c8a4a9d9 go1.24.2.linux-mips64.tar.gz +f233d237538ca1559a7d7cf519a29f0147923a951377bc4e467af4c059e68851 go1.24.2.linux-mips64le.tar.gz +545e1b9a7939f923fd53bde98334b987ef42eb353ee3e0bfede8aa06079d6b24 go1.24.2.linux-mipsle.tar.gz +6eab31481f2f46187bc1b6c887662eef06fc9d7271a8390854072cdb387c8d74 go1.24.2.linux-ppc64.tar.gz +5fff857791d541c71d8ea0171c73f6f99770d15ff7e2ad979104856d01f36563 go1.24.2.linux-ppc64le.tar.gz +91bda1558fcbd1c92769ad86c8f5cf796f8c67b0d9d9c19f76eecfc75ce71527 go1.24.2.linux-riscv64.tar.gz +1cb3448166d6abb515a85a3ee5afbdf932081fb58ad7143a8fb666fbc06146d9 go1.24.2.linux-s390x.tar.gz +a9a2c0db2e826f20f00b02bee01dfdaeb49591c2f6ffacb78dc64a950894f7ff go1.24.2.netbsd-386.tar.gz +cd1a35b76ed9c7b6c0c1616741bd319699a77867ade0be9924f32496c0a87a3f go1.24.2.netbsd-amd64.tar.gz +8c666388d066e479155cc5116950eeb435df28087ef277c18f1dc7479f836e60 go1.24.2.netbsd-arm.tar.gz +5d42f0be04f58da5be788a1e260f8747c316b8ce182bf0b273c2e4c691feaa1a go1.24.2.netbsd-arm64.tar.gz +688effa23ea3973cc8b0fdf4246712cbeef55ff20c45f3a9e28b0c2db04246cf go1.24.2.openbsd-386.tar.gz +e5daf95f1048d8026b1366450a3f8044d668b0639db6422ad9a83755c6745cf7 go1.24.2.openbsd-amd64.tar.gz +aeadaf74bd544d1a12ba9b14c0e7cdb1964de3ba9a52acb4619e91dbae7def7b go1.24.2.openbsd-arm.tar.gz +9e222d9adb0ce836a5b3c8d5aadbd167c8869c030b113f4a81aa88e9a200f279 go1.24.2.openbsd-arm64.tar.gz +192fffa34536adc3cd1bb7c1ee785b8bc156ae7afd10bbf5db99ec8f2e93066e go1.24.2.openbsd-ppc64.tar.gz +a23e90b451a390549042c2a7efbec6f29ed98b2d5618c8d2a35704e21be96e09 go1.24.2.openbsd-riscv64.tar.gz +5cdcafe455d859b02779611a5a1e1d63e498b922e05818fb3debe410a5959e9e go1.24.2.plan9-386.tar.gz +81351659804fa505c1b3ec6fdf9599f7f88df08614307eeb96071bf5e2e74beb go1.24.2.plan9-amd64.tar.gz +6e337d5def14ed0123423c1c32e2e6d8b19161e5d5ffaa7356dad48ee0fd80b4 go1.24.2.plan9-arm.tar.gz +07e6926ebc476c044d7d5b17706abfc52be52bccc2073d1734174efe63c6b35e go1.24.2.solaris-amd64.tar.gz +13d86cb818bba331da75fcd18246ab31a1067b44fb4a243b6dfd93097eda7f37 go1.24.2.windows-386.zip +8a702d9f7104a15bd935f4191c58c24c0b6389e066b9d5661b93915114a2bef0 go1.24.2.windows-386.msi +29c553aabee0743e2ffa3e9fa0cda00ef3b3cc4ff0bc92007f31f80fd69892e1 go1.24.2.windows-amd64.zip +acefb191e72fea0bdb1a3f5f8f6f5ab18b42b3bbce0c7183f189f25953aff275 go1.24.2.windows-amd64.msi +ab267f7f9a3366d48d7664be9e627ce3e63273231430cce5f7783fb910f14148 go1.24.2.windows-arm64.zip +d187bfe539356c39573d2f46766d1d08122b4f33da00fd14d12485fa9e241ff5 go1.24.2.windows-arm64.msi # version:golangci 2.0.2 # https://github.com/golangci/golangci-lint/releases/ From 76a32a8e0214ffc2522a9fc7c4713df93d00e9f4 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Mon, 14 Apr 2025 10:13:45 +0200 Subject: [PATCH 291/354] p2p: better dial/serve success metrics (#31629) Our previous success metrics gave success even if a peer disconnected right after connection. These metrics only count peers that stayed connected for at least 1 min. The 1 min limit is an arbitrary choice. We do not use this for decision logic, only statistics. --- p2p/metrics.go | 4 ++++ p2p/peer.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/p2p/metrics.go b/p2p/metrics.go index 1fd0f26db..8c9804206 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -51,6 +51,10 @@ var ( dialSuccessMeter = metrics.NewRegisteredMeter("p2p/dials/success", nil) dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) + // count peers that stayed connected for at least 1 min + serve1MinSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success/1min", nil) + dial1MinSuccessMeter = metrics.NewRegisteredMeter("p2p/dials/success/1min", nil) + // handshake error meters dialTooManyPeers = metrics.NewRegisteredMeter("p2p/dials/error/saturated", nil) dialAlreadyConnected = metrics.NewRegisteredMeter("p2p/dials/error/known", nil) diff --git a/p2p/peer.go b/p2p/peer.go index a01df63d0..9ffb94e5a 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -254,6 +254,8 @@ func (p *Peer) run() (remoteRequested bool, err error) { p.wg.Add(2) go p.readLoop(readErr) go p.pingLoop() + live1min := time.NewTimer(1 * time.Minute) + defer live1min.Stop() // Start all protocol handlers. writeStart <- struct{}{} @@ -285,6 +287,12 @@ loop: case err = <-p.disc: reason = discReasonForError(err) break loop + case <-live1min.C: + if p.Inbound() { + serve1MinSuccessMeter.Mark(1) + } else { + dial1MinSuccessMeter.Mark(1) + } } } From 262e7b15397c4aa15d62345abe983fb1bc0d8b84 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Mon, 14 Apr 2025 12:45:27 +0200 Subject: [PATCH 292/354] eth: add logic to drop peers randomly when saturated (#31476) As of now, Geth disconnects peers only on protocol error or timeout, meaning once connection slots are filled, the peerset is largely fixed. As mentioned in https://github.com/ethereum/go-ethereum/issues/31321, Geth should occasionally disconnect peers to ensure some churn. What/when to disconnect could depend on: - the state of geth (e.g. sync or not) - current number of peers - peer level metrics This PR adds a very slow churn using a random drop. --------- Signed-off-by: Csaba Kiraly Co-authored-by: Felix Lange --- eth/backend.go | 7 +++ eth/dropper.go | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ p2p/peer.go | 26 +++++++- p2p/server.go | 10 +-- 4 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 eth/dropper.go diff --git a/eth/backend.go b/eth/backend.go index b4349b6a0..ce2d68055 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -83,6 +83,7 @@ type Ethereum struct { handler *handler discmix *enode.FairMix + dropper *dropper // DB interfaces chainDb ethdb.Database // Block chain database @@ -330,6 +331,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, err } + eth.dropper = newDropper(eth.p2pServer.MaxDialedConns(), eth.p2pServer.MaxInboundConns()) + eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine) if chainConfig.DBFT != nil && len(config.Miner.ExtraData) != 0 { return nil, fmt.Errorf("custom miner Extra is not supported by dBFT") @@ -610,6 +613,9 @@ func (s *Ethereum) Start() error { // Start the networking layer s.handler.Start(s.p2pServer.MaxPeers) + // Start the connection manager + s.dropper.Start(s.p2pServer, func() bool { return !s.Synced() }) + // start log indexer s.filterMaps.Start() go s.updateFilterMapsHeads() @@ -711,6 +717,7 @@ func (s *Ethereum) setupDiscovery() error { func (s *Ethereum) Stop() error { // Stop all the peer-related stuff first. s.discmix.Close() + s.dropper.Stop() s.handler.Stop() // Then stop everything else. diff --git a/eth/dropper.go b/eth/dropper.go new file mode 100644 index 000000000..51f2a7a95 --- /dev/null +++ b/eth/dropper.go @@ -0,0 +1,167 @@ +// Copyright 2025 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 . + +package eth + +import ( + mrand "math/rand" + "slices" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/p2p" +) + +const ( + // Interval between peer drop events (uniform between min and max) + peerDropIntervalMin = 3 * time.Minute + // Interval between peer drop events (uniform between min and max) + peerDropIntervalMax = 7 * time.Minute + // Avoid dropping peers for some time after connection + doNotDropBefore = 10 * time.Minute + // How close to max should we initiate the drop timer. O should be fine, + // dropping when no more peers can be added. Larger numbers result in more + // aggressive drop behavior. + peerDropThreshold = 0 +) + +var ( + // droppedInbound is the number of inbound peers dropped + droppedInbound = metrics.NewRegisteredMeter("eth/dropper/inbound", nil) + // droppedOutbound is the number of outbound peers dropped + droppedOutbound = metrics.NewRegisteredMeter("eth/dropper/outbound", nil) +) + +// dropper monitors the state of the peer pool and makes changes as follows: +// - during sync the Downloader handles peer connections, so dropper is disabled +// - if not syncing and the peer count is close to the limit, it drops peers +// randomly every peerDropInterval to make space for new peers +// - peers are dropped separately from the inboud pool and from the dialed pool +type dropper struct { + maxDialPeers int // maximum number of dialed peers + maxInboundPeers int // maximum number of inbound peers + peersFunc getPeersFunc + syncingFunc getSyncingFunc + + // peerDropTimer introduces churn if we are close to limit capacity. + // We handle Dialed and Inbound connections separately + peerDropTimer *time.Timer + + wg sync.WaitGroup // wg for graceful shutdown + shutdownCh chan struct{} +} + +// Callback type to get the list of connected peers. +type getPeersFunc func() []*p2p.Peer + +// Callback type to get syncing status. +// Returns true while syncing, false when synced. +type getSyncingFunc func() bool + +func newDropper(maxDialPeers, maxInboundPeers int) *dropper { + cm := &dropper{ + maxDialPeers: maxDialPeers, + maxInboundPeers: maxInboundPeers, + peerDropTimer: time.NewTimer(randomDuration(peerDropIntervalMin, peerDropIntervalMax)), + shutdownCh: make(chan struct{}), + } + if peerDropIntervalMin > peerDropIntervalMax { + panic("peerDropIntervalMin duration must be less than or equal to peerDropIntervalMax duration") + } + return cm +} + +// Start the dropper. +func (cm *dropper) Start(srv *p2p.Server, syncingFunc getSyncingFunc) { + cm.peersFunc = srv.Peers + cm.syncingFunc = syncingFunc + cm.wg.Add(1) + go cm.loop() +} + +// Stop the dropper. +func (cm *dropper) Stop() { + cm.peerDropTimer.Stop() + close(cm.shutdownCh) + cm.wg.Wait() +} + +// dropRandomPeer selects one of the peers randomly and drops it from the peer pool. +func (cm *dropper) dropRandomPeer() bool { + peers := cm.peersFunc() + var numInbound int + for _, p := range peers { + if p.Inbound() { + numInbound++ + } + } + numDialed := len(peers) - numInbound + + selectDoNotDrop := func(p *p2p.Peer) bool { + // Avoid dropping trusted and static peers, or recent peers. + // Only drop peers if their respective category (dialed/inbound) + // is close to limit capacity. + return p.Trusted() || p.StaticDialed() || + p.Lifetime() < mclock.AbsTime(doNotDropBefore) || + (p.DynDialed() && cm.maxDialPeers-numDialed > peerDropThreshold) || + (p.Inbound() && cm.maxInboundPeers-numInbound > peerDropThreshold) + } + + droppable := slices.DeleteFunc(peers, selectDoNotDrop) + if len(droppable) > 0 { + p := droppable[mrand.Intn(len(droppable))] + log.Debug("Dropping random peer", "inbound", p.Inbound(), + "id", p.ID(), "duration", common.PrettyDuration(p.Lifetime()), "peercountbefore", len(peers)) + p.Disconnect(p2p.DiscUselessPeer) + if p.Inbound() { + droppedInbound.Mark(1) + } else { + droppedOutbound.Mark(1) + } + return true + } + return false +} + +// randomDuration generates a random duration between min and max. +func randomDuration(min, max time.Duration) time.Duration { + if min > max { + panic("min duration must be less than or equal to max duration") + } + return time.Duration(mrand.Int63n(int64(max-min)) + int64(min)) +} + +// loop is the main loop of the connection dropper. +func (cm *dropper) loop() { + defer cm.wg.Done() + + for { + select { + case <-cm.peerDropTimer.C: + // Drop a random peer if we are not syncing and the peer count is close to the limit. + if !cm.syncingFunc() { + cm.dropRandomPeer() + } + cm.peerDropTimer.Reset(randomDuration(peerDropIntervalMin, peerDropIntervalMax)) + case <-cm.shutdownCh: + return + } + } +} diff --git a/p2p/peer.go b/p2p/peer.go index 9ffb94e5a..9a0a750ac 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -220,11 +220,35 @@ func (p *Peer) String() string { return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr()) } -// Inbound returns true if the peer is an inbound connection +// Inbound returns true if the peer is an inbound (not dialed) connection. func (p *Peer) Inbound() bool { return p.rw.is(inboundConn) } +// Trusted returns true if the peer is configured as trusted. +// Trusted peers are accepted in above the MaxInboundConns limit. +// The peer can be either inbound or dialed. +func (p *Peer) Trusted() bool { + return p.rw.is(trustedConn) +} + +// DynDialed returns true if the peer was dialed successfully (passed handshake) and +// it is not configured as static. +func (p *Peer) DynDialed() bool { + return p.rw.is(dynDialedConn) +} + +// StaticDialed returns true if the peer was dialed successfully (passed handshake) and +// it is configured as static. +func (p *Peer) StaticDialed() bool { + return p.rw.is(staticDialedConn) +} + +// Lifetime returns the time since peer creation. +func (p *Peer) Lifetime() mclock.AbsTime { + return mclock.Now() - p.created +} + func newPeer(log log.Logger, conn *conn, protocols []Protocol) *Peer { protomap := matchProtocols(protocols, conn.caps, conn) p := &Peer{ diff --git a/p2p/server.go b/p2p/server.go index c1564352e..4e72e29fa 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -508,7 +508,7 @@ func (srv *Server) setupDiscovery() error { func (srv *Server) setupDialScheduler() { config := dialConfig{ self: srv.localnode.ID(), - maxDialPeers: srv.maxDialedConns(), + maxDialPeers: srv.MaxDialedConns(), maxActiveDials: srv.MaxPendingPeers, log: srv.Logger, netRestrict: srv.NetRestrict, @@ -527,11 +527,11 @@ func (srv *Server) setupDialScheduler() { } } -func (srv *Server) maxInboundConns() int { - return srv.MaxPeers - srv.maxDialedConns() +func (srv *Server) MaxInboundConns() int { + return srv.MaxPeers - srv.MaxDialedConns() } -func (srv *Server) maxDialedConns() (limit int) { +func (srv *Server) MaxDialedConns() (limit int) { if srv.NoDial || srv.MaxPeers == 0 { return 0 } @@ -736,7 +736,7 @@ func (srv *Server) postHandshakeChecks(peers map[enode.ID]*Peer, inboundCount in switch { case !c.is(trustedConn) && len(peers) >= srv.MaxPeers: return DiscTooManyPeers - case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.maxInboundConns(): + case !c.is(trustedConn) && c.is(inboundConn) && inboundCount >= srv.MaxInboundConns(): return DiscTooManyPeers case peers[c.node.ID()] != nil: return DiscAlreadyConnected From 7e99cca3f5888fa31c046ca8dd675592a5b25fa1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 15 Apr 2025 14:32:46 +0200 Subject: [PATCH 293/354] core: initialize history pruning in BlockChain (#31636) I added the history mode configuration in eth/ethconfig initially, since it seemed like the logical place. But it turns out we need access to the intended pruning setting at a deeper level, and it actually needs to be integrated with the blockchain startup procedure. With this change applied, if a node previously had its history pruned, and is subsequently restarted **without** the `--history.chain postmerge` flag, the `BlockChain` initialization code will now verify the freezer tail against the known pruning point of the predefined network and will restore pruning status. Note that this logic is quite restrictive, we allow non-zero tail only for known networks, and only for the specific pruning point that is defined. --- cmd/geth/chaincmd.go | 4 +- cmd/workload/testsuite.go | 6 +- core/block_validator_test.go | 10 ++- core/blockchain.go | 64 ++++++++++++++++++- core/blockchain_reader.go | 6 +- core/blockchain_test.go | 54 +++++++++++----- .../ethconfig => core/history}/historymode.go | 28 ++++---- eth/backend.go | 44 +++++-------- eth/ethconfig/config.go | 5 +- eth/ethconfig/gen_config.go | 31 +++++++-- internal/ethapi/api_test.go | 4 +- 11 files changed, 177 insertions(+), 79 deletions(-) rename {eth/ethconfig => core/history}/historymode.go (79%) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 227950954..c57a9a947 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -31,11 +31,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/era" @@ -625,7 +625,7 @@ func pruneHistory(ctx *cli.Context) error { defer chain.Stop() // Determine the prune point. This will be the first PoS block. - prunePoint, ok := ethconfig.HistoryPrunePoints[chain.Genesis().Hash()] + prunePoint, ok := history.PrunePoints[chain.Genesis().Hash()] if !ok || prunePoint == nil { return errors.New("prune point not found") } diff --git a/cmd/workload/testsuite.go b/cmd/workload/testsuite.go index e7019e205..e8e25e773 100644 --- a/cmd/workload/testsuite.go +++ b/cmd/workload/testsuite.go @@ -23,7 +23,7 @@ import ( "os" "slices" - "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/log" @@ -124,13 +124,13 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) { cfg.filterQueryFile = "queries/filter_queries_mainnet.json" cfg.historyTestFile = "queries/history_mainnet.json" cfg.historyPruneBlock = new(uint64) - *cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.MainnetGenesisHash].BlockNumber + *cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber case ctx.Bool(testSepoliaFlag.Name): cfg.fsys = builtinTestFiles cfg.filterQueryFile = "queries/filter_queries_sepolia.json" cfg.historyTestFile = "queries/history_sepolia.json" cfg.historyPruneBlock = new(uint64) - *cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.SepoliaGenesisHash].BlockNumber + *cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber default: cfg.fsys = os.DirFS(".") cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name) diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 429cdb3cf..fe09120ad 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -50,8 +50,11 @@ func testHeaderVerification(t *testing.T, scheme string) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chain.Stop() + if err != nil { + t.Fatal(err) + } for i := 0; i < len(blocks); i++ { for j, valid := range []bool{true, false} { @@ -163,8 +166,11 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { postHeaders[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() + if err != nil { + t.Fatal(err) + } // Verify the blocks before the merging for i := 0; i < len(preBlocks); i++ { diff --git a/core/blockchain.go b/core/blockchain.go index 5216e00ae..973b9d1b2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" @@ -160,8 +161,7 @@ type CacheConfig struct { // This defines the cutoff block for history expiry. // Blocks before this number may be unavailable in the chain database. - HistoryPruningCutoffNumber uint64 - HistoryPruningCutoffHash common.Hash + ChainHistoryMode history.HistoryMode } // triedbConfig derives the configures for trie database. @@ -258,6 +258,7 @@ type BlockChain struct { currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block + historyPrunePoint atomic.Pointer[history.PrunePoint] bodyCache *lru.Cache[common.Hash, *types.Body] bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] @@ -558,6 +559,12 @@ func (bc *BlockChain) loadLastState() error { } bc.hc.SetCurrentHeader(headHeader) + // Initialize history pruning. + latest := max(headBlock.NumberU64(), headHeader.Number.Uint64()) + if err := bc.initializeHistoryPruning(latest); err != nil { + return err + } + // Restore the last known head snap block bc.currentSnapBlock.Store(headBlock.Header()) headFastBlockGauge.Update(int64(headBlock.NumberU64())) @@ -580,6 +587,7 @@ func (bc *BlockChain) loadLastState() error { headSafeBlockGauge.Update(int64(block.NumberU64())) } } + // Issue a status log for the user var ( currentSnapBlock = bc.CurrentSnapBlock() @@ -607,9 +615,57 @@ func (bc *BlockChain) loadLastState() error { if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil { log.Info("Loaded last snap-sync pivot marker", "number", *pivot) } + if pruning := bc.historyPrunePoint.Load(); pruning != nil { + log.Info("Chain history is pruned", "earliest", pruning.BlockNumber, "hash", pruning.BlockHash) + } return nil } +// initializeHistoryPruning sets bc.historyPrunePoint. +func (bc *BlockChain) initializeHistoryPruning(latest uint64) error { + freezerTail, _ := bc.db.Tail() + + switch bc.cacheConfig.ChainHistoryMode { + case history.KeepAll: + if freezerTail == 0 { + return nil + } + // The database was pruned somehow, so we need to figure out if it's a known + // configuration or an error. + predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()] + if predefinedPoint == nil || freezerTail != predefinedPoint.BlockNumber { + log.Error("Chain history database is pruned with unknown configuration", "tail", freezerTail) + return fmt.Errorf("unexpected database tail") + } + bc.historyPrunePoint.Store(predefinedPoint) + return nil + + case history.KeepPostMerge: + if freezerTail == 0 && latest != 0 { + // This is the case where a user is trying to run with --history.chain + // postmerge directly on an existing DB. We could just trigger the pruning + // here, but it'd be a bit dangerous since they may not have intended this + // action to happen. So just tell them how to do it. + log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cacheConfig.ChainHistoryMode.String())) + log.Error(fmt.Sprintf("Run 'geth prune-history' to prune pre-merge history.")) + return fmt.Errorf("history pruning requested via configuration") + } + predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()] + if predefinedPoint == nil { + log.Error("Chain history pruning is not supported for this network", "genesis", bc.genesisBlock.Hash()) + return fmt.Errorf("history pruning requested for unknown network") + } else if freezerTail != predefinedPoint.BlockNumber { + log.Error("Chain history database is pruned to unknown block", "tail", freezerTail) + return fmt.Errorf("unexpected database tail") + } + bc.historyPrunePoint.Store(predefinedPoint) + return nil + + default: + return fmt.Errorf("invalid history mode: %d", bc.cacheConfig.ChainHistoryMode) + } +} + // SetHead rewinds the local chain to a new head. Depending on whether the node // was snap synced or full synced and in which state, the method will try to // delete minimal data from disk whilst retaining chain consistency. @@ -1050,7 +1106,9 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.currentSnapBlock.Store(bc.genesisBlock.Header()) headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) - return nil + + // Reset history pruning status. + return bc.initializeHistoryPruning(0) } // Export writes the active chain to the given writer. diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index da5f6a736..43639642f 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -433,7 +433,11 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) { // HistoryPruningCutoff returns the configured history pruning point. // Blocks before this might not be available in the database. func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) { - return bc.cacheConfig.HistoryPruningCutoffNumber, bc.cacheConfig.HistoryPruningCutoffHash + pt := bc.historyPrunePoint.Load() + if pt == nil { + return 0, bc.genesisBlock.Hash() + } + return pt.BlockNumber, pt.BlockHash } // TrieDB retrieves the low level trie database used for data storage. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 51251bbc8..7c880c19a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -4312,13 +4313,7 @@ func testChainReorgSnapSync(t *testing.T, ancientLimit uint64) { // be persisted without the receipts and bodies; chain after should be persisted // normally. func TestInsertChainWithCutoff(t *testing.T) { - testInsertChainWithCutoff(t, 32, 32) // cutoff = 32, ancientLimit = 32 - testInsertChainWithCutoff(t, 32, 64) // cutoff = 32, ancientLimit = 64 (entire chain in ancient) - testInsertChainWithCutoff(t, 32, 65) // cutoff = 32, ancientLimit = 65 (64 blocks in ancient, 1 block in live) -} - -func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64) { - // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true))) + const chainLength = 64 // Configure and generate a sample block chain var ( @@ -4333,24 +4328,51 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64) signer = types.LatestSigner(gspec.Config) engine = beacon.New(ethash.NewFaker()) ) - _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(2*cutoff), func(i int, block *BlockGen) { + _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, block *BlockGen) { block.SetCoinbase(common.Address{0x00}) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) if err != nil { panic(err) } block.AddTx(tx) }) - db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) - defer db.Close() + // Run the actual tests. + t.Run("cutoff-32/ancientLimit-32", func(t *testing.T) { + // cutoff = 32, ancientLimit = 32 + testInsertChainWithCutoff(t, 32, 32, gspec, blocks, receipts) + }) + t.Run("cutoff-32/ancientLimit-64", func(t *testing.T) { + // cutoff = 32, ancientLimit = 64 (entire chain in ancient) + testInsertChainWithCutoff(t, 32, 64, gspec, blocks, receipts) + }) + t.Run("cutoff-32/ancientLimit-64", func(t *testing.T) { + // cutoff = 32, ancientLimit = 65 (64 blocks in ancient, 1 block in live) + testInsertChainWithCutoff(t, 32, 65, gspec, blocks, receipts) + }) +} + +func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64, genesis *Genesis, blocks []*types.Block, receipts []types.Receipts) { + // log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true))) + + // Add a known pruning point for the duration of the test. + ghash := genesis.ToBlock().Hash() cutoffBlock := blocks[cutoff-1] + history.PrunePoints[ghash] = &history.PrunePoint{ + BlockNumber: cutoffBlock.NumberU64(), + BlockHash: cutoffBlock.Hash(), + } + defer func() { + delete(history.PrunePoints, ghash) + }() + + // Enable pruning in cache config. config := DefaultCacheConfigWithScheme(rawdb.PathScheme) - config.HistoryPruningCutoffNumber = cutoffBlock.NumberU64() - config.HistoryPruningCutoffHash = cutoffBlock.Hash() + config.ChainHistoryMode = history.KeepPostMerge - chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) + defer db.Close() + chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) defer chain.Stop() var ( @@ -4381,8 +4403,8 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64) t.Errorf("head header #%d: header mismatch: want: %v, got: %v", headHeader.Number, blocks[len(blocks)-1].Hash(), headHeader.Hash()) } headBlock := chain.CurrentBlock() - if headBlock.Hash() != gspec.ToBlock().Hash() { - t.Errorf("head block #%d: header mismatch: want: %v, got: %v", headBlock.Number, gspec.ToBlock().Hash(), headBlock.Hash()) + if headBlock.Hash() != ghash { + t.Errorf("head block #%d: header mismatch: want: %v, got: %v", headBlock.Number, ghash, headBlock.Hash()) } // Iterate over all chain data components, and cross reference diff --git a/eth/ethconfig/historymode.go b/core/history/historymode.go similarity index 79% rename from eth/ethconfig/historymode.go rename to core/history/historymode.go index a595d72fe..e735222d3 100644 --- a/eth/ethconfig/historymode.go +++ b/core/history/historymode.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package ethconfig +package history import ( "fmt" @@ -27,22 +27,22 @@ import ( type HistoryMode uint32 const ( - // AllHistory (default) means that all chain history down to genesis block will be kept. - AllHistory HistoryMode = iota + // KeepAll (default) means that all chain history down to genesis block will be kept. + KeepAll HistoryMode = iota - // PostMergeHistory sets the history pruning point to the merge activation block. - PostMergeHistory + // KeepPostMerge sets the history pruning point to the merge activation block. + KeepPostMerge ) func (m HistoryMode) IsValid() bool { - return m <= PostMergeHistory + return m <= KeepPostMerge } func (m HistoryMode) String() string { switch m { - case AllHistory: + case KeepAll: return "all" - case PostMergeHistory: + case KeepPostMerge: return "postmerge" default: return fmt.Sprintf("invalid HistoryMode(%d)", m) @@ -61,24 +61,24 @@ func (m HistoryMode) MarshalText() ([]byte, error) { func (m *HistoryMode) UnmarshalText(text []byte) error { switch string(text) { case "all": - *m = AllHistory + *m = KeepAll case "postmerge": - *m = PostMergeHistory + *m = KeepPostMerge default: return fmt.Errorf(`unknown sync mode %q, want "all" or "postmerge"`, text) } return nil } -type HistoryPrunePoint struct { +type PrunePoint struct { BlockNumber uint64 BlockHash common.Hash } -// HistoryPrunePoints contains the pre-defined history pruning cutoff blocks for known networks. +// PrunePoints the pre-defined history pruning cutoff blocks for known networks. // They point to the first post-merge block. Any pruning should truncate *up to* but excluding // given block. -var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{ +var PrunePoints = map[common.Hash]*PrunePoint{ // mainnet params.MainnetGenesisHash: { BlockNumber: 15537393, @@ -91,7 +91,7 @@ var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{ }, } -// PrunedHistoryError is returned when the requested history is pruned. +// PrunedHistoryError is returned by APIs when the requested history is pruned. type PrunedHistoryError struct{} func (e *PrunedHistoryError) Error() string { return "pruned history unavailable" } diff --git a/eth/backend.go b/eth/backend.go index ce2d68055..de4f68d97 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -154,7 +154,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Here we determine genesis hash and active ChainConfig. // We need these to figure out the consensus parameters and to set up history pruning. - chainConfig, genesisHash, err := core.LoadChainConfig(chainDb, config.Genesis) + chainConfig, _, err := core.LoadChainConfig(chainDb, config.Genesis) if err != nil { return nil, err } @@ -162,22 +162,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - - // Validate history pruning configuration. - var ( - cutoffNumber uint64 - cutoffHash common.Hash - ) - if config.HistoryMode == ethconfig.PostMergeHistory { - prunecfg, ok := ethconfig.HistoryPrunePoints[genesisHash] - if !ok { - return nil, fmt.Errorf("no history pruning point is defined for genesis %x", genesisHash) - } - cutoffNumber = prunecfg.BlockNumber - cutoffHash = prunecfg.BlockHash - log.Info("Chain cutoff configured", "number", cutoffNumber, "hash", cutoffHash) - } - // Set networkID to chainID by default. networkID := config.NetworkId if networkID == 0 { @@ -210,6 +194,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer) + // Create BlockChain object. if !config.SkipBcVersionCheck { if bcVersion != nil && *bcVersion > core.BlockChainVersion { return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion) @@ -225,17 +210,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { EnablePreimageRecording: config.EnablePreimageRecording, } cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: scheme, - HistoryPruningCutoffNumber: cutoffNumber, - HistoryPruningCutoffHash: cutoffHash, + TrieCleanLimit: config.TrieCleanCache, + TrieCleanNoPrefetch: config.NoPrefetch, + TrieDirtyLimit: config.TrieDirtyCache, + TrieDirtyDisabled: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + Preimages: config.Preimages, + StateHistory: config.StateHistory, + StateScheme: scheme, + ChainHistoryMode: config.HistoryMode, } ) if config.VMTrace != "" { @@ -265,6 +249,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } + + // Initialize filtermaps log index. fmConfig := filtermaps.Config{ History: config.LogHistory, Disabled: config.LogNoHistory, @@ -280,6 +266,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, historyCutoff, finalBlock, filtermaps.DefaultParams, fmConfig) eth.closeFilterMaps = make(chan chan struct{}) + // TxPool if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } @@ -315,6 +302,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.localTxTracker = locals.New(config.TxPool.Journal, rejournal, eth.blockchain.Config(), eth.txPool) stack.RegisterLifecycle(eth.localTxTracker) } + // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit if eth.handler, err = newHandler(&handlerConfig{ diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b734e5db1..c5511cff3 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/dbft" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" @@ -50,7 +51,7 @@ var FullNodeGPO = gasprice.Config{ // Defaults contains default settings for use on the Ethereum main net. var Defaults = Config{ - HistoryMode: AllHistory, + HistoryMode: history.KeepAll, SyncMode: downloader.SnapSync, NetworkId: 0, // enable auto configuration of networkID == chainID TxLookupLimit: 2350000, @@ -86,7 +87,7 @@ type Config struct { SyncMode downloader.SyncMode // HistoryMode configures chain history retention. - HistoryMode HistoryMode + HistoryMode history.HistoryMode // This can be set to list of enrtree:// URLs which will be queried for // nodes to connect to. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index db29c1441..5e1be4e9c 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" @@ -20,13 +21,16 @@ func (c Config) MarshalTOML() (interface{}, error) { Genesis *core.Genesis `toml:",omitempty"` NetworkId uint64 SyncMode downloader.SyncMode - HistoryMode HistoryMode + HistoryMode history.HistoryMode EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning bool NoPrefetch bool - TxLookupLimit uint64 `toml:",omitempty"` - TransactionHistory uint64 `toml:",omitempty"` + TxLookupLimit uint64 `toml:",omitempty"` + TransactionHistory uint64 `toml:",omitempty"` + LogHistory uint64 `toml:",omitempty"` + LogNoHistory bool `toml:",omitempty"` + LogExportCheckpoints string StateHistory uint64 `toml:",omitempty"` StateScheme string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` @@ -64,6 +68,9 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.NoPrefetch = c.NoPrefetch enc.TxLookupLimit = c.TxLookupLimit enc.TransactionHistory = c.TransactionHistory + enc.LogHistory = c.LogHistory + enc.LogNoHistory = c.LogNoHistory + enc.LogExportCheckpoints = c.LogExportCheckpoints enc.StateHistory = c.StateHistory enc.StateScheme = c.StateScheme enc.RequiredBlocks = c.RequiredBlocks @@ -98,13 +105,16 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { Genesis *core.Genesis `toml:",omitempty"` NetworkId *uint64 SyncMode *downloader.SyncMode - HistoryMode *HistoryMode + HistoryMode *history.HistoryMode EthDiscoveryURLs []string SnapDiscoveryURLs []string NoPruning *bool NoPrefetch *bool - TxLookupLimit *uint64 `toml:",omitempty"` - TransactionHistory *uint64 `toml:",omitempty"` + TxLookupLimit *uint64 `toml:",omitempty"` + TransactionHistory *uint64 `toml:",omitempty"` + LogHistory *uint64 `toml:",omitempty"` + LogNoHistory *bool `toml:",omitempty"` + LogExportCheckpoints *string StateHistory *uint64 `toml:",omitempty"` StateScheme *string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` @@ -165,6 +175,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TransactionHistory != nil { c.TransactionHistory = *dec.TransactionHistory } + if dec.LogHistory != nil { + c.LogHistory = *dec.LogHistory + } + if dec.LogNoHistory != nil { + c.LogNoHistory = *dec.LogNoHistory + } + if dec.LogExportCheckpoints != nil { + c.LogExportCheckpoints = *dec.LogExportCheckpoints + } if dec.StateHistory != nil { c.StateHistory = *dec.StateHistory } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 0985ed2b9..69822c1b4 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -642,8 +642,8 @@ func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { } func (b testBackend) HistoryPruningCutoff() uint64 { - cutoff, _ := b.chain.HistoryPruningCutoff() - return cutoff + bn, _ := b.chain.HistoryPruningCutoff() + return bn } func TestEstimateGas(t *testing.T) { From 6c715f7aee32b2a5c38f9ca2b4091c4114a32a82 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 15 Apr 2025 20:34:34 +0800 Subject: [PATCH 294/354] all: remove martin from CODEOWNERS (#31637) Thank you, @holiman, for being an integral part of the Go-Ethereum and for your invaluable contributions over the years. This will always be your home and you're welcome back anytime! --- .github/CODEOWNERS | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b56918085..681b5e7c6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,12 +9,11 @@ beacon/light/ @zsfelfoldi beacon/merkle/ @zsfelfoldi beacon/types/ @zsfelfoldi @fjl beacon/params/ @zsfelfoldi @fjl -cmd/clef/ @holiman -cmd/evm/ @holiman @MariusVanDerWijden @lightclient -core/state/ @rjl493456442 @holiman -crypto/ @gballet @jwasinger @holiman @fjl -core/ @holiman @rjl493456442 -eth/ @holiman @rjl493456442 +cmd/evm/ @MariusVanDerWijden @lightclient +core/state/ @rjl493456442 +crypto/ @gballet @jwasinger @fjl +core/ @rjl493456442 +eth/ @rjl493456442 eth/catalyst/ @MariusVanDerWijden @lightclient @fjl @jwasinger eth/tracers/ @s1na ethclient/ @fjl @@ -26,11 +25,9 @@ core/tracing/ @s1na graphql/ @s1na internal/ethapi/ @fjl @s1na @lightclient internal/era/ @lightclient -metrics/ @holiman -miner/ @MariusVanDerWijden @holiman @fjl @rjl493456442 +miner/ @MariusVanDerWijden @fjl @rjl493456442 node/ @fjl p2p/ @fjl @zsfelfoldi rlp/ @fjl -params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi -rpc/ @fjl @holiman -signer/ @holiman +params/ @fjl @karalabe @gballet @rjl493456442 @zsfelfoldi +rpc/ @fjl From 9d6577cc4654abe8eab4943a4469c4f99f1fe13f Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Tue, 15 Apr 2025 20:40:30 +0200 Subject: [PATCH 295/354] p2p: fix dial metrics not picking up the right error (#31621) Our metrics related to dial errors were off. The original error was not wrapped, so the caller function had no chance of picking it up. Therefore the most common error, which is "TooManyPeers", was not correctly counted. The metrics were originally introduced in https://github.com/ethereum/go-ethereum/pull/27621 I was thinking of various possible solutions. - the one proposed here wraps both the new error and the origial error. It is not a pattern we use in other parts of the code, but works. This is maybe the smallest possible change. - as an alternate, I could write a proper `errProtoHandshakeError` with it's own wrapped error - finally, I'm not even sure we need `errProtoHandshakeError`, maybe we could just pass up the original error. --------- Signed-off-by: Csaba Kiraly Co-authored-by: Felix Lange --- p2p/metrics.go | 41 ++++++++++++++++++++++++----------------- p2p/server.go | 12 ++++++++---- p2p/server_test.go | 4 ++-- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/p2p/metrics.go b/p2p/metrics.go index 8c9804206..29c2acb0c 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -49,7 +49,7 @@ var ( serveSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success", nil) dialMeter = metrics.NewRegisteredMeter("p2p/dials", nil) dialSuccessMeter = metrics.NewRegisteredMeter("p2p/dials/success", nil) - dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) + dialConnectionError = metrics.NewRegisteredMeter("p2p/dials/error/connection", nil) // dial timeout; no route to host; connection refused; network is unreachable // count peers that stayed connected for at least 1 min serve1MinSuccessMeter = metrics.NewRegisteredMeter("p2p/serves/success/1min", nil) @@ -61,34 +61,41 @@ var ( dialSelf = metrics.NewRegisteredMeter("p2p/dials/error/self", nil) dialUselessPeer = metrics.NewRegisteredMeter("p2p/dials/error/useless", nil) dialUnexpectedIdentity = metrics.NewRegisteredMeter("p2p/dials/error/id/unexpected", nil) - dialEncHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/enc", nil) - dialProtoHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/proto", nil) + dialEncHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/enc", nil) // EOF; connection reset during handshake; message too big; i/o timeout + dialProtoHandshakeError = metrics.NewRegisteredMeter("p2p/dials/error/rlpx/proto", nil) // EOF + + // capture the rest of errors that are not handled by the above meters + dialOtherError = metrics.NewRegisteredMeter("p2p/dials/error/other", nil) ) -// markDialError matches errors that occur while setting up a dial connection -// to the corresponding meter. +// markDialError matches errors that occur while setting up a dial connection to the +// corresponding meter. We don't maintain meters for evert possible error, just for +// the most interesting ones. func markDialError(err error) { if !metrics.Enabled() { return } - if err2 := errors.Unwrap(err); err2 != nil { - err = err2 - } - switch err { - case DiscTooManyPeers: + + var reason DiscReason + var handshakeErr *protoHandshakeError + d := errors.As(err, &reason) + switch { + case d && reason == DiscTooManyPeers: dialTooManyPeers.Mark(1) - case DiscAlreadyConnected: + case d && reason == DiscAlreadyConnected: dialAlreadyConnected.Mark(1) - case DiscSelf: + case d && reason == DiscSelf: dialSelf.Mark(1) - case DiscUselessPeer: + case d && reason == DiscUselessPeer: dialUselessPeer.Mark(1) - case DiscUnexpectedIdentity: + case d && reason == DiscUnexpectedIdentity: dialUnexpectedIdentity.Mark(1) - case errEncHandshakeError: - dialEncHandshakeError.Mark(1) - case errProtoHandshakeError: + case errors.As(err, &handshakeErr): dialProtoHandshakeError.Mark(1) + case errors.Is(err, errEncHandshakeError): + dialEncHandshakeError.Mark(1) + default: + dialOtherError.Mark(1) } } diff --git a/p2p/server.go b/p2p/server.go index 4e72e29fa..d9105976d 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -66,11 +66,15 @@ const ( ) var ( - errServerStopped = errors.New("server stopped") - errEncHandshakeError = errors.New("rlpx enc error") - errProtoHandshakeError = errors.New("rlpx proto error") + errServerStopped = errors.New("server stopped") + errEncHandshakeError = errors.New("rlpx enc error") ) +type protoHandshakeError struct{ err error } + +func (e *protoHandshakeError) Error() string { return fmt.Sprintf("rlpx proto error: %v", e.err) } +func (e *protoHandshakeError) Unwrap() error { return e.err } + // Server manages all peer connections. type Server struct { // Config fields may not be modified while the server is running. @@ -907,7 +911,7 @@ func (srv *Server) setupConn(c *conn, dialDest *enode.Node) error { phs, err := c.doProtoHandshake(srv.ourHandshake) if err != nil { clog.Trace("Failed p2p handshake", "err", err) - return fmt.Errorf("%w: %v", errProtoHandshakeError, err) + return &protoHandshakeError{err: err} } if id := c.node.ID(); !bytes.Equal(crypto.Keccak256(phs.ID), id[:]) { clog.Trace("Wrong devp2p handshake identity", "phsid", hex.EncodeToString(phs.ID)) diff --git a/p2p/server_test.go b/p2p/server_test.go index a0491e984..d42926cf4 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -410,11 +410,11 @@ func TestServerSetupConn(t *testing.T) { wantCloseErr: DiscUnexpectedIdentity, }, { - tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: errProtoHandshakeError}, + tt: &setupTransport{pubkey: clientpub, protoHandshakeErr: DiscTooManyPeers}, dialDest: enode.NewV4(clientpub, nil, 0, 0), flags: dynDialedConn, wantCalls: "doEncHandshake,doProtoHandshake,close,", - wantCloseErr: errProtoHandshakeError, + wantCloseErr: DiscTooManyPeers, }, { tt: &setupTransport{pubkey: srvpub, phs: protoHandshake{ID: crypto.FromECDSAPub(srvpub)[1:]}}, From 112594da1686dbab4a63c51d65e2afac2e5ee250 Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 16 Apr 2025 15:50:05 +0800 Subject: [PATCH 296/354] cmd/geth: remove the unused bloomfilter.size flag (#31646) --- cmd/geth/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 76c4d43d5..7dfcb069e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -109,7 +109,6 @@ var ( utils.LightNoSyncServeFlag, // deprecated utils.EthRequiredBlocksFlag, utils.LegacyWhitelistFlag, // deprecated - utils.BloomFilterSizeFlag, utils.CacheFlag, utils.CacheDatabaseFlag, utils.CacheTrieFlag, From 3647abc5902aba01a0e91dd54c8373238771cb2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 16 Apr 2025 23:30:13 +0200 Subject: [PATCH 297/354] core/filtermaps: fix map renderer reorg issue (#31642) This PR fixes a bug in the map renderer that sometimes used an obsolete block log value pointer to initialize the iterator for rendering from a snapshot. This bug was triggered by chain reorgs and sometimes caused indexing errors and invalid search results. A few other conditions are also made safer that were not reported to cause issues yet but could potentially be unsafe in some corner cases. A new unit test is also added that reproduced the bug but passes with the new fixes. Fixes https://github.com/ethereum/go-ethereum/issues/31593 Might also fix https://github.com/ethereum/go-ethereum/issues/31589 though this issue has not been reproduced yet, but it appears to be related to a log index database corruption around a specific block, similarly to the other issue. Note that running this branch resets and regenerates the log index database. For this purpose a `Version` field has been added to `rawdb.FilterMapsRange` which will also make this easier in the future if a breaking database change is needed or the existing one is considered potentially broken due to a bug, like in this case. --- core/filtermaps/filtermaps.go | 27 +++++-- core/filtermaps/indexer_test.go | 110 +++++++++++++++++++++++++++++ core/filtermaps/map_renderer.go | 45 +++++------- core/filtermaps/matcher_backend.go | 3 + core/rawdb/accessors_indexes.go | 1 + 5 files changed, 153 insertions(+), 33 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index 18b1c7dc7..fa2d6e3ff 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -50,6 +50,7 @@ var ( ) const ( + databaseVersion = 1 // reindexed if database version does not match cachedLastBlocks = 1000 // last block of map pointers cachedLvPointers = 1000 // first log value pointer of block pointers cachedBaseRows = 100 // groups of base layer filter row data @@ -138,13 +139,25 @@ type FilterMaps struct { // as transparent (uncached/unchanged). type filterMap []FilterRow -// copy returns a copy of the given filter map. Note that the row slices are -// copied but their contents are not. This permits extending the rows further +// fastCopy returns a copy of the given filter map. Note that the row slices are +// copied but their contents are not. This permits appending to the rows further // (which happens during map rendering) without affecting the validity of // copies made for snapshots during rendering. -func (fm filterMap) copy() filterMap { +// Appending to the rows of both the original map and the fast copy, or two fast +// copies of the same map would result in data corruption, therefore a fast copy +// should always be used in a read only way. +func (fm filterMap) fastCopy() filterMap { + return slices.Clone(fm) +} + +// fullCopy returns a copy of the given filter map, also making a copy of each +// individual filter row, ensuring that a modification to either one will never +// affect the other. +func (fm filterMap) fullCopy() filterMap { c := make(filterMap, len(fm)) - copy(c, fm) + for i, row := range fm { + c[i] = slices.Clone(row) + } return c } @@ -207,8 +220,9 @@ type Config struct { // NewFilterMaps creates a new FilterMaps and starts the indexer. func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, finalBlock uint64, params Params, config Config) *FilterMaps { rs, initialized, err := rawdb.ReadFilterMapsRange(db) - if err != nil { - log.Error("Error reading log index range", "error", err) + if err != nil || rs.Version != databaseVersion { + rs, initialized = rawdb.FilterMapsRange{}, false + log.Warn("Invalid log index database version; resetting log index") } params.deriveFields() f := &FilterMaps{ @@ -437,6 +451,7 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne f.updateMatchersValidRange() if newRange.initialized { rs := rawdb.FilterMapsRange{ + Version: databaseVersion, HeadIndexed: newRange.headIndexed, HeadDelimiter: newRange.headDelimiter, BlocksFirst: newRange.blocks.First(), diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go index a02f8d245..4dddd2708 100644 --- a/core/filtermaps/indexer_test.go +++ b/core/filtermaps/indexer_test.go @@ -17,8 +17,10 @@ package filtermaps import ( + "context" crand "crypto/rand" "crypto/sha256" + "encoding/binary" "math/big" "math/rand" "sync" @@ -31,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" ) var testParams = Params{ @@ -104,6 +107,7 @@ func TestIndexerRandomRange(t *testing.T) { fork, head = rand.Intn(len(forks)), rand.Intn(1001) ts.chain.setCanonicalChain(forks[fork][:head+1]) case 2: + checkSnapshot = false if head < 1000 { checkSnapshot = !noHistory && head != 0 // no snapshot generated for block 0 // add blocks after the current head @@ -158,6 +162,63 @@ func TestIndexerRandomRange(t *testing.T) { } } +func TestIndexerMatcherView(t *testing.T) { + testIndexerMatcherView(t, false) +} + +func TestIndexerMatcherViewWithConcurrentRead(t *testing.T) { + testIndexerMatcherView(t, true) +} + +func testIndexerMatcherView(t *testing.T, concurrentRead bool) { + ts := newTestSetup(t) + defer ts.close() + + forks := make([][]common.Hash, 20) + hashes := make([]common.Hash, 20) + ts.chain.addBlocks(100, 5, 2, 4, true) + ts.setHistory(0, false) + for i := range forks { + if i != 0 { + ts.chain.setHead(100 - i) + ts.chain.addBlocks(i, 5, 2, 4, true) + } + ts.fm.WaitIdle() + forks[i] = ts.chain.getCanonicalChain() + hashes[i] = ts.matcherViewHash() + } + fork := len(forks) - 1 + for i := 0; i < 5000; i++ { + oldFork := fork + fork = rand.Intn(len(forks)) + stopCh := make(chan chan struct{}) + if concurrentRead { + go func() { + for { + ts.matcherViewHash() + select { + case ch := <-stopCh: + close(ch) + return + default: + } + } + }() + } + ts.chain.setCanonicalChain(forks[fork]) + ts.fm.WaitIdle() + if concurrentRead { + ch := make(chan struct{}) + stopCh <- ch + <-ch + } + hash := ts.matcherViewHash() + if hash != hashes[fork] { + t.Fatalf("Matcher view hash mismatch when switching from for %d to %d", oldFork, fork) + } + } +} + func TestIndexerCompareDb(t *testing.T) { ts := newTestSetup(t) defer ts.close() @@ -291,6 +352,55 @@ func (ts *testSetup) fmDbHash() common.Hash { return result } +func (ts *testSetup) matcherViewHash() common.Hash { + mb := ts.fm.NewMatcherBackend() + defer mb.Close() + + ctx := context.Background() + params := mb.GetParams() + hasher := sha256.New() + var headPtr uint64 + for b := uint64(0); ; b++ { + lvptr, err := mb.GetBlockLvPointer(ctx, b) + if err != nil || (b > 0 && lvptr == headPtr) { + break + } + var enc [8]byte + binary.LittleEndian.PutUint64(enc[:], lvptr) + hasher.Write(enc[:]) + headPtr = lvptr + } + headMap := uint32(headPtr >> params.logValuesPerMap) + var enc [12]byte + for r := uint32(0); r < params.mapHeight; r++ { + binary.LittleEndian.PutUint32(enc[:4], r) + for m := uint32(0); m <= headMap; m++ { + binary.LittleEndian.PutUint32(enc[4:8], m) + row, _ := mb.GetFilterMapRow(ctx, m, r, false) + for _, v := range row { + binary.LittleEndian.PutUint32(enc[8:], v) + hasher.Write(enc[:]) + } + } + } + var hash common.Hash + hasher.Sum(hash[:0]) + for i := 0; i < 50; i++ { + hasher.Reset() + hasher.Write(hash[:]) + lvptr := binary.LittleEndian.Uint64(hash[:8]) % headPtr + if log, _ := mb.GetLogByLvIndex(ctx, lvptr); log != nil { + enc, err := rlp.EncodeToBytes(log) + if err != nil { + panic(err) + } + hasher.Write(enc) + } + hasher.Sum(hash[:0]) + } + return hash +} + func (ts *testSetup) close() { if ts.fm != nil { ts.fm.Stop() diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 28f943abb..cd960ad31 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -84,7 +84,7 @@ func (f *FilterMaps) renderMapsBefore(renderBefore uint32) (*mapRenderer, error) if err != nil { return nil, err } - if snapshot := f.lastCanonicalSnapshotBefore(renderBefore); snapshot != nil && snapshot.mapIndex >= nextMap { + if snapshot := f.lastCanonicalSnapshotOfMap(nextMap); snapshot != nil { return f.renderMapsFromSnapshot(snapshot) } if nextMap >= renderBefore { @@ -97,14 +97,14 @@ func (f *FilterMaps) renderMapsBefore(renderBefore uint32) (*mapRenderer, error) // snapshot made at a block boundary. func (f *FilterMaps) renderMapsFromSnapshot(cp *renderedMap) (*mapRenderer, error) { f.testSnapshotUsed = true - iter, err := f.newLogIteratorFromBlockDelimiter(cp.lastBlock) + iter, err := f.newLogIteratorFromBlockDelimiter(cp.lastBlock, cp.headDelimiter) if err != nil { return nil, fmt.Errorf("failed to create log iterator from block delimiter %d: %v", cp.lastBlock, err) } return &mapRenderer{ f: f, currentMap: &renderedMap{ - filterMap: cp.filterMap.copy(), + filterMap: cp.filterMap.fullCopy(), mapIndex: cp.mapIndex, lastBlock: cp.lastBlock, blockLvPtrs: cp.blockLvPtrs, @@ -137,14 +137,14 @@ func (f *FilterMaps) renderMapsFromMapBoundary(firstMap, renderBefore uint32, st }, nil } -// lastCanonicalSnapshotBefore returns the latest cached snapshot that matches -// the current targetView. -func (f *FilterMaps) lastCanonicalSnapshotBefore(renderBefore uint32) *renderedMap { +// lastCanonicalSnapshotOfMap returns the latest cached snapshot of the given map +// that is also consistent with the current targetView. +func (f *FilterMaps) lastCanonicalSnapshotOfMap(mapIndex uint32) *renderedMap { var best *renderedMap for _, blockNumber := range f.renderSnapshots.Keys() { if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.blocks.AfterLast() && blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId && - cp.mapIndex < renderBefore && (best == nil || blockNumber > best.lastBlock) { + cp.mapIndex == mapIndex && (best == nil || blockNumber > best.lastBlock) { best = cp } } @@ -171,10 +171,9 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMa if err != nil { return 0, 0, 0, fmt.Errorf("failed to retrieve last block of reverse iterated map %d: %v", mapIndex, err) } - if lastBlock >= f.indexedView.headNumber || lastBlock >= f.targetView.headNumber || - lastBlockId != f.targetView.getBlockId(lastBlock) { - // map is not full or inconsistent with targetView; roll back - continue + if (f.indexedRange.headIndexed && mapIndex >= f.indexedRange.maps.Last()) || + lastBlock >= f.targetView.headNumber || lastBlockId != f.targetView.getBlockId(lastBlock) { + continue // map is not full or inconsistent with targetView; roll back } lvPtr, err := f.getBlockLvPointer(lastBlock) if err != nil { @@ -257,11 +256,14 @@ func (f *FilterMaps) loadHeadSnapshot() error { // makeSnapshot creates a snapshot of the current state of the rendered map. func (r *mapRenderer) makeSnapshot() { - r.f.renderSnapshots.Add(r.iterator.blockNumber, &renderedMap{ - filterMap: r.currentMap.filterMap.copy(), + if r.iterator.blockNumber != r.currentMap.lastBlock || r.iterator.chainView != r.f.targetView { + panic("iterator state inconsistent with current rendered map") + } + r.f.renderSnapshots.Add(r.currentMap.lastBlock, &renderedMap{ + filterMap: r.currentMap.filterMap.fastCopy(), mapIndex: r.currentMap.mapIndex, - lastBlock: r.iterator.blockNumber, - lastBlockId: r.f.targetView.getBlockId(r.currentMap.lastBlock), + lastBlock: r.currentMap.lastBlock, + lastBlockId: r.iterator.chainView.getBlockId(r.currentMap.lastBlock), blockLvPtrs: r.currentMap.blockLvPtrs, finished: true, headDelimiter: r.iterator.lvIndex, @@ -661,24 +663,13 @@ var errUnindexedRange = errors.New("unindexed range") // newLogIteratorFromBlockDelimiter creates a logIterator starting at the // given block's first log value entry (the block delimiter), according to the // current targetView. -func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber uint64) (*logIterator, error) { +func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber, lvIndex uint64) (*logIterator, error) { if blockNumber > f.targetView.headNumber { return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.headNumber) } if !f.indexedRange.blocks.Includes(blockNumber) { return nil, errUnindexedRange } - var lvIndex uint64 - if f.indexedRange.headIndexed && blockNumber+1 == f.indexedRange.blocks.AfterLast() { - lvIndex = f.indexedRange.headDelimiter - } else { - var err error - lvIndex, err = f.getBlockLvPointer(blockNumber + 1) - if err != nil { - return nil, fmt.Errorf("failed to retrieve log value pointer of block %d after delimiter: %v", blockNumber+1, err) - } - lvIndex-- - } finished := blockNumber == f.targetView.headNumber l := &logIterator{ chainView: f.targetView, diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index 01bae7bb2..335ac8455 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -75,6 +75,9 @@ func (fm *FilterMapsMatcherBackend) Close() { // on write. // GetFilterMapRow implements MatcherBackend. func (fm *FilterMapsMatcherBackend) GetFilterMapRow(ctx context.Context, mapIndex, rowIndex uint32, baseLayerOnly bool) (FilterRow, error) { + fm.f.indexLock.RLock() + defer fm.f.indexLock.RUnlock() + return fm.f.getFilterMapRow(mapIndex, rowIndex, baseLayerOnly) } diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index c413839b7..1a5c414c8 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -434,6 +434,7 @@ func DeleteBlockLvPointers(db ethdb.KeyValueStore, blocks common.Range[uint64], // FilterMapsRange is a storage representation of the block range covered by the // filter maps structure and the corresponting log value index range. type FilterMapsRange struct { + Version uint32 HeadIndexed bool HeadDelimiter uint64 BlocksFirst, BlocksAfterLast uint64 From c3b6799db8bf44991542589da17af7270f8ff3e6 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 17 Apr 2025 05:46:38 +0800 Subject: [PATCH 298/354] core/state: fix log format (#31610) Log `key` in hexadecimal string format. --- core/state/dump.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/dump.go b/core/state/dump.go index c9aad4f8e..11b5c3278 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -188,7 +188,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] c.OnAccount(address, account) accounts++ if time.Since(logged) > 8*time.Second { - log.Info("Trie dumping in progress", "at", it.Key, "accounts", accounts, + log.Info("Trie dumping in progress", "at", common.Bytes2Hex(it.Key), "accounts", accounts, "elapsed", common.PrettyDuration(time.Since(start))) logged = time.Now() } From 0568833f5e052b3428a5492335d44bbdf2b6c109 Mon Sep 17 00:00:00 2001 From: Miro Date: Wed, 16 Apr 2025 22:36:53 -0400 Subject: [PATCH 299/354] core/txpool/legacypool: fix data race of txlookup access (#31641) --- core/txpool/legacypool/legacypool.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index ca0796a93..5dbf997ca 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1952,6 +1952,16 @@ func (t *lookup) Remove(hash common.Hash) { delete(t.txs, hash) } +// Clear resets the lookup structure, removing all stored entries. +func (t *lookup) Clear() { + t.lock.Lock() + defer t.lock.Unlock() + + t.slots = 0 + t.txs = make(map[common.Hash]*types.Transaction) + t.auths = make(map[common.Address][]common.Hash) +} + // TxsBelowTip finds all remote transactions below the given tip threshold. func (t *lookup) TxsBelowTip(threshold *big.Int) types.Transactions { found := make(types.Transactions, 0, 128) @@ -2048,7 +2058,7 @@ func (pool *LegacyPool) Clear() { for addr := range pool.queue { pool.reserver.Release(addr) } - pool.all = newLookup() + pool.all.Clear() pool.priced = newPricedList(pool.all) pool.pending = make(map[common.Address]*list) pool.queue = make(map[common.Address]*list) From e5be1a98765eb93ad08f8980c9105e1e5f5d2a83 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 17 Apr 2025 04:39:21 +0200 Subject: [PATCH 300/354] core: fix history pruning initialization for empty DB (#31656) This fixes an issue where running geth with `--history.chain postmerge` would not work on an empty database. ``` ERROR[04-16|23:11:12.913] Chain history database is pruned to unknown block tail=0 Fatal: Failed to register the Ethereum service: unexpected database tail ``` --- core/blockchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index 973b9d1b2..f161695bd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -654,7 +654,7 @@ func (bc *BlockChain) initializeHistoryPruning(latest uint64) error { if predefinedPoint == nil { log.Error("Chain history pruning is not supported for this network", "genesis", bc.genesisBlock.Hash()) return fmt.Errorf("history pruning requested for unknown network") - } else if freezerTail != predefinedPoint.BlockNumber { + } else if freezerTail > 0 && freezerTail != predefinedPoint.BlockNumber { log.Error("Chain history database is pruned to unknown block", "tail", freezerTail) return fmt.Errorf("unexpected database tail") } From 5b753c04ffbc50bfe3ceaa1a550d50e57839b40a Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 17 Apr 2025 10:32:40 +0200 Subject: [PATCH 301/354] core: fix sync reset in pruned nodes (#31638) This is an attempt at fixing #31601. I think what happens is the startup logic will try to get the full block body (it's `bc.loadLastState`) and fail because genesis block has been pruned from the freezer. This will cause it to keep repeating the reset logic, causing a deadlock. This can happen when due to an unsuccessful sync we don't have the state for the head (or any other state) fully, and try to redo the snap sync. --------- Co-authored-by: Gary Rong --- core/blockchain.go | 50 +++++++++++++++++++++++++++++++------------ core/txindexer.go | 19 +++++++++++++--- core/txpool/txpool.go | 14 ++++++------ 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f161695bd..446588470 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -539,19 +539,33 @@ func (bc *BlockChain) loadLastState() error { log.Warn("Empty database, resetting chain") return bc.Reset() } - // Make sure the entire head block is available - headBlock := bc.GetBlockByHash(head) + headHeader := bc.GetHeaderByHash(head) + if headHeader == nil { + // Corrupt or empty database, init from scratch + log.Warn("Head header missing, resetting chain", "hash", head) + return bc.Reset() + } + + var headBlock *types.Block + if cmp := headHeader.Number.Cmp(new(big.Int)); cmp == 1 { + // Make sure the entire head block is available. + headBlock = bc.GetBlockByHash(head) + } else if cmp == 0 { + // On a pruned node the block body might not be available. But a pruned + // block should never be the head block. The only exception is when, as + // a last resort, chain is reset to genesis. + headBlock = bc.genesisBlock + } if headBlock == nil { // Corrupt or empty database, init from scratch log.Warn("Head block missing, resetting chain", "hash", head) return bc.Reset() } // Everything seems to be fine, set as the head block - bc.currentBlock.Store(headBlock.Header()) + bc.currentBlock.Store(headHeader) headBlockGauge.Update(int64(headBlock.NumberU64())) // Restore the last known head header - headHeader := headBlock.Header() if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if header := bc.GetHeaderByHash(head); header != nil { headHeader = header @@ -676,11 +690,15 @@ func (bc *BlockChain) SetHead(head uint64) error { // Send chain head event to update the transaction pool header := bc.CurrentBlock() if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil { - // This should never happen. In practice, previously currentBlock - // contained the entire block whereas now only a "marker", so there - // is an ever so slight chance for a race we should handle. - log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) - return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + // In a pruned node the genesis block will not exist in the freezer. + // It should not happen that we set head to any other pruned block. + if header.Number.Uint64() > 0 { + // This should never happen. In practice, previously currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + } } bc.chainHeadFeed.Send(ChainHeadEvent{Header: header}) return nil @@ -697,11 +715,15 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error { // Send chain head event to update the transaction pool header := bc.CurrentBlock() if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil { - // This should never happen. In practice, previously currentBlock - // contained the entire block whereas now only a "marker", so there - // is an ever so slight chance for a race we should handle. - log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) - return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + // In a pruned node the genesis block will not exist in the freezer. + // It should not happen that we set head to any other pruned block. + if header.Number.Uint64() > 0 { + // This should never happen. In practice, previously currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + } } bc.chainHeadFeed.Send(ChainHeadEvent{Header: header}) return nil diff --git a/core/txindexer.go b/core/txindexer.go index 31f069995..64a2e8c49 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -196,6 +196,19 @@ func (indexer *txIndexer) repair(head uint64) { } } +// resolveHead resolves the block number of the current chain head. +func (indexer *txIndexer) resolveHead() uint64 { + headBlockHash := rawdb.ReadHeadBlockHash(indexer.db) + if headBlockHash == (common.Hash{}) { + return 0 + } + headBlockNumber := rawdb.ReadHeaderNumber(indexer.db, headBlockHash) + if headBlockNumber == nil { + return 0 + } + return *headBlockNumber +} + // loop is the scheduler of the indexer, assigning indexing/unindexing tasks depending // on the received chain event. func (indexer *txIndexer) loop(chain *BlockChain) { @@ -203,9 +216,9 @@ func (indexer *txIndexer) loop(chain *BlockChain) { // Listening to chain events and manipulate the transaction indexes. var ( - stop chan struct{} // Non-nil if background routine is active - done chan struct{} // Non-nil if background routine is active - head = rawdb.ReadHeadBlock(indexer.db).NumberU64() // The latest announced chain head + stop chan struct{} // Non-nil if background routine is active + done chan struct{} // Non-nil if background routine is active + head = indexer.resolveHead() // The latest announced chain head headCh = make(chan ChainHeadEvent) sub = chain.SubscribeChainHeadEvent(headCh) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 17bb5045c..1b034fb22 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -189,13 +189,15 @@ func (p *TxPool) loop(head *types.Header) { // Try to inject a busy marker and start a reset if successful select { case resetBusy <- struct{}{}: - statedb, err := p.chain.StateAt(newHead.Root) - if err != nil { - log.Crit("Failed to reset txpool state", "err", err) + // Updates the statedb with the new chain head. The head state may be + // unavailable if the initial state sync has not yet completed. + if statedb, err := p.chain.StateAt(newHead.Root); err != nil { + log.Error("Failed to reset txpool state", "err", err) + } else { + p.stateLock.Lock() + p.state = statedb + p.stateLock.Unlock() } - p.stateLock.Lock() - p.state = statedb - p.stateLock.Unlock() // Busy marker injected, start a new subpool reset go func(oldHead, newHead *types.Header) { From aa1a8cc67b974a7a86faacd34bc018a1f32c7813 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Thu, 17 Apr 2025 10:33:59 +0200 Subject: [PATCH 302/354] eth: fix transaction sender cache miss before broadcast (#31657) BroadcastTransactions needs the Sender address to route message flows from the same Sender address consistently to the same random subset of peers. It however spent considerable time calculating the Sender addresses, even if the Sender address was already calculated and cached in other parts of the code. Since we only need the mapping, we can use any signer, and the one that had already been used is a better choice because of cache reuse. --- eth/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/handler.go b/eth/handler.go index d19010adf..6905caa29 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -601,7 +601,7 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) { total := new(big.Int).Exp(direct, big.NewInt(2), nil) // Stabilise total peer count a bit based on sqrt peers var ( - signer = types.LatestSignerForChainID(h.chain.Config().ChainID) // Don't care about chain status, we just need *a* sender + signer = types.LatestSigner(h.chain.Config()) // Don't care about chain status, we just need *a* sender hasher = crypto.NewKeccakState() hash = make([]byte, 32) ) From 451af77ef77911907e460734833a7870c0dea7dd Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 17 Apr 2025 02:46:00 -0600 Subject: [PATCH 303/354] params: add prague timestamp for mainnet (#31535) https://eips.ethereum.org/EIPS/eip-7600#activation Timestamp: `1746612311` Fork id: `0xc376cf8b` --- core/forkid/forkid_test.go | 19 ++++++++++--------- params/config.go | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 31e2b534b..413e4d77a 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -76,8 +76,10 @@ func TestCreation(t *testing.T) { {20000000, 1681338454, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}}, // Last Gray Glacier block {20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // First Shanghai block {30000000, 1710338134, ID{Hash: checksumToBytes(0xdce96c2d), Next: 1710338135}}, // Last Shanghai block - {40000000, 1710338135, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // First Cancun block - {50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block + {40000000, 1710338135, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // First Cancun block + {30000000, 1746022486, ID{Hash: checksumToBytes(0x9f3d2254), Next: 1746612311}}, // Last Cancun block + {30000000, 1746612311, ID{Hash: checksumToBytes(0xc376cf8b), Next: 0}}, // First Prague block + {50000000, 2000000000, ID{Hash: checksumToBytes(0xc376cf8b), Next: 0}}, // Future Prague block }, }, // Sepolia test cases @@ -137,9 +139,11 @@ func TestCreation(t *testing.T) { // fork ID. func TestValidation(t *testing.T) { // Config that has not timestamp enabled + // TODO(lightclient): this always needs to be updated when a mainnet timestamp is set. legacyConfig := *params.MainnetChainConfig legacyConfig.ShanghaiTime = nil legacyConfig.CancunTime = nil + legacyConfig.PragueTime = nil tests := []struct { config *params.ChainConfig @@ -314,9 +318,7 @@ func TestValidation(t *testing.T) { // Local is mainnet Prague, remote announces Shanghai + knowledge about Cancun. Remote // is definitely out of sync. It may or may not need the Prague update, we don't know yet. - // - // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update all the numbers - //{params.MainnetChainConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + {params.MainnetChainConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 1710338135}, nil}, // Local is mainnet Shanghai, remote announces Cancun. Local is out of sync, accept. {params.MainnetChainConfig, 21000000, 1700000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}, nil}, @@ -324,8 +326,7 @@ func TestValidation(t *testing.T) { // Local is mainnet Shanghai, remote announces Cancun, but is not aware of Prague. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. // - // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update remote checksum - //{params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, + {params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0xc376cf8b), Next: 0}, nil}, // Local is mainnet Cancun. remote announces Shanghai but is not aware of further forks. // Remote needs software update. @@ -342,11 +343,11 @@ func TestValidation(t *testing.T) { // Local is mainnet Shanghai, remote is random Shanghai. {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Cancun, far in the future. Remote announces Gopherium (non existing fork) + // Local is mainnet Prague, far in the future. Remote announces Gopherium (non existing fork) // at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible. // // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - {params.MainnetChainConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0x9f3d2254), Next: 8888888888}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0xc376cf8b), Next: 8888888888}, ErrLocalIncompatibleOrStale}, // Local is mainnet Shanghai. Remote is also in Shanghai, but announces Gopherium (non existing // fork) at timestamp 1668000000, before Cancun. Local is incompatible. diff --git a/params/config.go b/params/config.go index f9b9d14be..03080618d 100644 --- a/params/config.go +++ b/params/config.go @@ -60,10 +60,12 @@ var ( TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 ShanghaiTime: newUint64(1681338455), CancunTime: newUint64(1710338135), + PragueTime: newUint64(1746612311), DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"), Ethash: new(EthashConfig), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, + Prague: DefaultPragueBlobConfig, }, } // HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network. From af196f6bcf0fcf9a2f213d84fd39377c20d9dd0c Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 17 Apr 2025 02:46:47 -0600 Subject: [PATCH 304/354] core,params: add fork readiness indicator in logs (#31340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #31310 This has been requested a few times in the past and I think it is a nice quality-of-life improvement for users. At a predetermined interval, there will now be a "Fork ready" log when a future fork is scheduled, but not yet active. It can only possibly print after block import, which kinda avoids the scenario where the client isn't progressing or is syncing and the user thinks it's "ready" because it sees a ready log. New output: ```console INFO [03-08|21:32:57.472] Imported new potential chain segment number=7 hash=aa24ee..f09e62 blocks=1 txs=0 mgas=0.000 elapsed="874.916µs" mgasps=0.000 snapdiffs=973.00B triediffs=7.05KiB triedirty=0.00B INFO [03-08|21:32:57.473] Ready for fork activation fork=Prague date="18 Mar 25 19:29 CET" remaining=237h57m0s timestamp=1,742,322,597 INFO [03-08|21:32:57.475] Chain head was updated number=7 hash=aa24ee..f09e62 root=19b0de..8d32f2 elapsed="129.125µs" ``` Easiest way to verify this behavior is to apply this patch and run `geth --dev --dev.period=12` ```patch diff --git a/params/config.go b/params/config.go index 9c7719d901..030c4f80e7 100644 --- a/params/config.go +++ b/params/config.go @@ -174,7 +174,7 @@ var ( ShanghaiTime: newUint64(0), CancunTime: newUint64(0), TerminalTotalDifficulty: big.NewInt(0), - PragueTime: newUint64(0), + PragueTime: newUint64(uint64(time.Now().Add(time.Hour * 300).Unix())), BlobScheduleConfig: &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, Prague: DefaultPragueBlobConfig, ``` --- core/blockchain.go | 28 ++++++++++++++++++++++++++++ params/config.go | 17 +++++++++++++++++ params/forks/forks.go | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index 446588470..7ac07cf09 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "math" "math/big" "runtime" "slices" @@ -101,6 +102,10 @@ var ( errInvalidNewChain = errors.New("invalid new chain") ) +var ( + forkReadyInterval = 3 * time.Minute +) + const ( bodyCacheLimit = 256 blockCacheLimit = 256 @@ -283,6 +288,8 @@ type BlockChain struct { forker *ForkChoice vmConfig vm.Config logger *tracing.Hooks + + lastForkReadyAlert time.Time // Last time there was a fork readiness print out } // NewBlockChain returns a fully initialised block chain using information @@ -2050,6 +2057,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness trieDiffNodes, trieBufNodes, _ := bc.triedb.Size() stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, setHead) + // Print confirmation that a future fork is scheduled, but not yet active. + bc.logForkReadiness(block) + if !setHead { // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time @@ -2098,6 +2108,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness stats.queued++ } } + stats.ignored += it.remaining() return witness, it.index, err @@ -2741,6 +2752,23 @@ func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err er log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) } +// logForkReadiness will write a log when a future fork is scheduled, but not +// active. This is useful so operators know their client is ready for the fork. +func (bc *BlockChain) logForkReadiness(block *types.Block) { + c := bc.Config() + current, last := c.LatestFork(block.Time()), c.LatestFork(math.MaxUint64) + t := c.Timestamp(last) + if t == nil { + return + } + at := time.Unix(int64(*t), 0) + if current < last && time.Now().After(bc.lastForkReadyAlert.Add(forkReadyInterval)) { + log.Info("Ready for fork activation", "fork", last, "date", at.Format(time.RFC822), + "remaining", time.Until(at).Round(time.Second), "timestamp", at.Unix()) + bc.lastForkReadyAlert = time.Now() + } +} + // summarizeBadBlock returns a string summarizing the bad block and other // relevant information. func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { diff --git a/params/config.go b/params/config.go index 03080618d..db0ae6cd8 100644 --- a/params/config.go +++ b/params/config.go @@ -987,6 +987,23 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { } } +// Timestamp returns the timestamp associated with the fork or returns nil if +// the fork isn't defined or isn't a time-based fork. +func (c *ChainConfig) Timestamp(fork forks.Fork) *uint64 { + switch { + case fork == forks.Osaka: + return c.OsakaTime + case fork == forks.Prague: + return c.PragueTime + case fork == forks.Cancun: + return c.CancunTime + case fork == forks.Shanghai: + return c.ShanghaiTime + default: + return nil + } +} + // isForkBlockIncompatible returns true if a fork scheduled at block s1 cannot be // rescheduled to block s2 because head is already past the fork. func isForkBlockIncompatible(s1, s2, head *big.Int) bool { diff --git a/params/forks/forks.go b/params/forks/forks.go index 02f6e5b61..5c9612a62 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -20,7 +20,7 @@ package forks type Fork int const ( - Frontier = iota + Frontier Fork = iota FrontierThawing Homestead DAO @@ -41,3 +41,35 @@ const ( Prague Osaka ) + +// String implements fmt.Stringer. +func (f Fork) String() string { + s, ok := forkToString[f] + if !ok { + return "Unknown fork" + } + return s +} + +var forkToString = map[Fork]string{ + Frontier: "Frontier", + FrontierThawing: "Frontier Thawing", + Homestead: "Homestead", + DAO: "DAO", + TangerineWhistle: "Tangerine Whistle", + SpuriousDragon: "Spurious Dragon", + Byzantium: "Byzantium", + Constantinople: "Constantinople", + Petersburg: "Petersburg", + Istanbul: "Istanbul", + MuirGlacier: "Muir Glacier", + Berlin: "Berlin", + London: "London", + ArrowGlacier: "Arrow Glacier", + GrayGlacier: "Gray Glacier", + Paris: "Paris", + Shanghai: "Shanghai", + Cancun: "Cancun", + Prague: "Prague", + Osaka: "Osaka", +} From c32270f078246cc23bc6bb6cdefb06e15ce89e0f Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 17 Apr 2025 20:23:31 +0800 Subject: [PATCH 305/354] eth/catalyst: sanitize simulated beacon period to avoid overflowing time.Duration (#31407) closes #31401 --------- Co-authored-by: Marius van der Wijden Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Felix Lange --- eth/catalyst/simulated_beacon.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index dd9d8f906..b84df9a4d 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -21,6 +21,7 @@ import ( "crypto/sha256" "errors" "fmt" + "math" "sync" "time" @@ -124,9 +125,13 @@ func NewSimulatedBeacon(period uint64, feeRecipient common.Address, eth *eth.Eth return nil, err } } + + // cap the dev mode period to a reasonable maximum value to avoid + // overflowing the time.Duration (int64) that it will occupy + const maxPeriod = uint64(math.MaxInt64 / time.Second) return &SimulatedBeacon{ eth: eth, - period: period, + period: min(period, maxPeriod), shutdownCh: make(chan struct{}), engineAPI: engineAPI, lastBlockTime: block.Time, From e738a1da8d3264dcbc22d4a2b56a344379e9bf1e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 18 Apr 2025 03:27:48 +0800 Subject: [PATCH 306/354] eth: add tx to locals only if it has a chance of acceptance (#31618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request improves error handling for local transaction submissions. Specifically, if a transaction fails with a temporary error but might be accepted later, the error will not be returned to the user; instead, the transaction will be tracked locally for resubmission. However, if the transaction fails with a permanent error (e.g., invalid transaction or insufficient balance), the error will be propagated to the user. These errors returned in the legacyPool are regarded as temporary failure: - `ErrOutOfOrderTxFromDelegated` - `txpool.ErrInflightTxLimitReached` - `ErrAuthorityReserved` - `txpool.ErrUnderpriced` - `ErrTxPoolOverflow` - `ErrFutureReplacePending` Notably, InsufficientBalance is also treated as a permanent error, as it’s highly unlikely that users will transfer funds into the sender account after submitting the transaction. Otherwise, users may be confused—seeing their transaction submitted but unaware that the sender lacks sufficient funds—and continue waiting for it to be included. --------- Co-authored-by: lightclient --- core/txpool/blobpool/blobpool.go | 2 + core/txpool/blobpool/blobpool_test.go | 2 +- core/txpool/errors.go | 13 +- core/txpool/legacypool/legacypool2_test.go | 6 +- core/txpool/legacypool/legacypool_test.go | 59 ++++---- core/txpool/locals/errors.go | 46 ++++++ core/txpool/locals/tx_tracker.go | 20 +-- core/txpool/locals/tx_tracker_test.go | 58 +------- core/txpool/txpool.go | 25 ---- core/txpool/validation.go | 4 +- eth/api_backend.go | 26 ++-- eth/api_backend_test.go | 157 +++++++++++++++++++++ eth/fetcher/tx_fetcher.go | 4 +- eth/fetcher/tx_fetcher_test.go | 6 +- ethclient/simulated/backend_test.go | 8 +- 15 files changed, 284 insertions(+), 152 deletions(-) create mode 100644 core/txpool/locals/errors.go create mode 100644 eth/api_backend_test.go diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 705081336..bcdda044c 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1400,6 +1400,8 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) { switch { case errors.Is(err, txpool.ErrUnderpriced): addUnderpricedMeter.Mark(1) + case errors.Is(err, txpool.ErrTxGasPriceTooLow): + addUnderpricedMeter.Mark(1) case errors.Is(err, core.ErrNonceTooLow): addStaleMeter.Mark(1) case errors.Is(err, core.ErrNonceTooHigh): diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 76d21a0c9..0a323179a 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -1484,7 +1484,7 @@ func TestAdd(t *testing.T) { { // New account, no previous txs, nonce 0, but blob fee cap too low from: "alice", tx: makeUnsignedTx(0, 1, 1, 0), - err: txpool.ErrUnderpriced, + err: txpool.ErrTxGasPriceTooLow, }, { // Same as above but blob fee cap equals minimum, should be accepted from: "alice", diff --git a/core/txpool/errors.go b/core/txpool/errors.go index 52b9d2a19..5ad0e2170 100644 --- a/core/txpool/errors.go +++ b/core/txpool/errors.go @@ -16,7 +16,9 @@ package txpool -import "errors" +import ( + "errors" +) var ( // ErrAlreadyKnown is returned if the transactions is already contained @@ -29,14 +31,19 @@ var ( // ErrBlockedSender is returned if the transaction sender is blocked by policy. ErrBlockedSender = errors.New("blocked sender") - // ErrUnderpriced is returned if a transaction's gas price is below the minimum - // configured for the transaction pool. + // ErrUnderpriced is returned if a transaction's gas price is too low to be + // included in the pool. If the gas price is lower than the minimum configured + // one for the transaction pool, use ErrTxGasPriceTooLow instead. ErrUnderpriced = errors.New("transaction underpriced") // ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced // with a different one without the required price bump. ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") + // ErrTxGasPriceTooLow is returned if a transaction's gas price is below the + // minimum configured for the transaction pool. + ErrTxGasPriceTooLow = errors.New("transaction gas price below minimum") + // ErrAccountLimitExceeded is returned if a transaction would exceed the number // allowed by a pool for a single account. ErrAccountLimitExceeded = errors.New("account limit exceeded") diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 3f210e3d1..deb06aa61 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -82,12 +82,14 @@ func TestTransactionFutureAttack(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) + config := testTxPoolConfig config.GlobalQueue = 100 config.GlobalSlots = 100 pool := New(config, blockchain) pool.Init(config.PriceLimit, blockchain.CurrentBlock(), newReserver()) defer pool.Close() + fillPool(t, pool) pending, _ := pool.Stats() // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops @@ -180,7 +182,9 @@ func TestTransactionZAttack(t *testing.T) { ivPending := countInvalidPending() t.Logf("invalid pending: %d\n", ivPending) - // Now, DETER-Z attack starts, let's add a bunch of expensive non-executables (from N accounts) along with balance-overdraft txs (from one account), and see if the pending-count drops + // Now, DETER-Z attack starts, let's add a bunch of expensive non-executables + // (from N accounts) along with balance-overdraft txs (from one account), and + // see if the pending-count drops for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index bb1323a7d..2fdf89032 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -413,7 +413,7 @@ func TestInvalidTransactions(t *testing.T) { tx = transaction(1, 100000, key) pool.gasTip.Store(uint256.NewInt(1000)) - if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) { + if err, want := pool.addRemote(tx), txpool.ErrTxGasPriceTooLow; !errors.Is(err, want) { t.Errorf("want %v have %v", want, err) } } @@ -484,7 +484,7 @@ func TestNegativeValue(t *testing.T) { tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) testAddBalance(pool, from, big.NewInt(1)) - if err := pool.addRemote(tx); err != txpool.ErrNegativeValue { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrNegativeValue) { t.Error("expected", txpool.ErrNegativeValue, "got", err) } } @@ -497,7 +497,7 @@ func TestTipAboveFeeCap(t *testing.T) { tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) - if err := pool.addRemote(tx); err != core.ErrTipAboveFeeCap { + if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipAboveFeeCap) { t.Error("expected", core.ErrTipAboveFeeCap, "got", err) } } @@ -512,12 +512,12 @@ func TestVeryHighValues(t *testing.T) { veryBigNumber.Lsh(veryBigNumber, 300) tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) - if err := pool.addRemote(tx); err != core.ErrTipVeryHigh { + if err := pool.addRemote(tx); !errors.Is(err, core.ErrTipVeryHigh) { t.Error("expected", core.ErrTipVeryHigh, "got", err) } tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) - if err := pool.addRemote(tx2); err != core.ErrFeeCapVeryHigh { + if err := pool.addRemote(tx2); !errors.Is(err, core.ErrFeeCapVeryHigh) { t.Error("expected", core.ErrFeeCapVeryHigh, "got", err) } } @@ -1424,14 +1424,14 @@ func TestRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Check that we can't add the old transactions back - if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } - if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } - if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) @@ -1476,14 +1476,14 @@ func TestMinGasPriceEnforced(t *testing.T) { tx := pricedTransaction(0, 100000, big.NewInt(2), key) pool.SetGasTip(big.NewInt(tx.GasPrice().Int64() + 1)) - if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrTxGasPriceTooLow) { t.Fatalf("Min tip not enforced") } tx = dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), key) pool.SetGasTip(big.NewInt(tx.GasTipCap().Int64() + 1)) - if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrUnderpriced) { + if err := pool.Add([]*types.Transaction{tx}, true)[0]; !errors.Is(err, txpool.ErrTxGasPriceTooLow) { t.Fatalf("Min tip not enforced") } } @@ -1560,16 +1560,16 @@ func TestRepricingDynamicFee(t *testing.T) { } // Check that we can't add the old transactions back tx := pricedTransaction(1, 100000, big.NewInt(1), keys[0]) - if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } tx = dynamicFeeTx(0, 100000, big.NewInt(2), big.NewInt(1), keys[1]) - if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } tx = dynamicFeeTx(2, 100000, big.NewInt(1), big.NewInt(1), keys[2]) - if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrUnderpriced) { - t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrUnderpriced) + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrTxGasPriceTooLow) { + t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, txpool.ErrTxGasPriceTooLow) } if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) @@ -1673,7 +1673,7 @@ func TestUnderpricing(t *testing.T) { t.Fatalf("failed to add well priced transaction: %v", err) } // Ensure that replacing a pending transaction with a future transaction fails - if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending { + if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); !errors.Is(err, ErrFutureReplacePending) { t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending) } pending, queued = pool.Stats() @@ -1995,7 +1995,7 @@ func TestReplacement(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap pending transaction: %v", err) } - if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { @@ -2008,7 +2008,7 @@ func TestReplacement(t *testing.T) { if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper pending transaction: %v", err) } - if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } if err := pool.addRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { @@ -2022,7 +2022,7 @@ func TestReplacement(t *testing.T) { if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap queued transaction: %v", err) } - if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { @@ -2032,7 +2032,7 @@ func TestReplacement(t *testing.T) { if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper queued transaction: %v", err) } - if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, txpool.ErrReplaceUnderpriced) } if err := pool.addRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { @@ -2096,7 +2096,7 @@ func TestReplacementDynamicFee(t *testing.T) { } // 2. Don't bump tip or feecap => discard tx = dynamicFeeTx(nonce, 100001, big.NewInt(2), big.NewInt(1), key) - if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original cheap %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 3. Bump both more than min => accept @@ -2117,24 +2117,25 @@ func TestReplacementDynamicFee(t *testing.T) { if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add original proper %s transaction: %v", stage, err) } + // 6. Bump tip max allowed so it's still underpriced => discard tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold-1), key) - if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 7. Bump fee cap max allowed so it's still underpriced => discard tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold-1), big.NewInt(gasTipCap), key) - if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 8. Bump tip min for acceptance => accept tx = dynamicFeeTx(nonce, 100000, big.NewInt(gasFeeCap), big.NewInt(tipThreshold), key) - if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 9. Bump fee cap min for acceptance => accept tx = dynamicFeeTx(nonce, 100000, big.NewInt(feeCapThreshold), big.NewInt(gasTipCap), key) - if err := pool.addRemote(tx); err != txpool.ErrReplaceUnderpriced { + if err := pool.addRemote(tx); !errors.Is(err, txpool.ErrReplaceUnderpriced) { t.Fatalf("original proper %s transaction replacement error mismatch: have %v, want %v", stage, err, txpool.ErrReplaceUnderpriced) } // 10. Check events match expected (3 new executable txs during pending, 0 during queue) diff --git a/core/txpool/locals/errors.go b/core/txpool/locals/errors.go new file mode 100644 index 000000000..fda50bf21 --- /dev/null +++ b/core/txpool/locals/errors.go @@ -0,0 +1,46 @@ +// Copyright 2025 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 . + +package locals + +import ( + "errors" + + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" +) + +// IsTemporaryReject determines whether the given error indicates a temporary +// reason to reject a transaction from being included in the txpool. The result +// may change if the txpool's state changes later. +func IsTemporaryReject(err error) bool { + switch { + case errors.Is(err, legacypool.ErrOutOfOrderTxFromDelegated): + return true + case errors.Is(err, txpool.ErrInflightTxLimitReached): + return true + case errors.Is(err, legacypool.ErrAuthorityReserved): + return true + case errors.Is(err, txpool.ErrUnderpriced): + return true + case errors.Is(err, legacypool.ErrTxPoolOverflow): + return true + case errors.Is(err, legacypool.ErrFutureReplacePending): + return true + default: + return false + } +} diff --git a/core/txpool/locals/tx_tracker.go b/core/txpool/locals/tx_tracker.go index 1d3f0c0a9..f7dc68940 100644 --- a/core/txpool/locals/tx_tracker.go +++ b/core/txpool/locals/tx_tracker.go @@ -74,32 +74,22 @@ func New(journalPath string, journalTime time.Duration, chainConfig *params.Chai // Track adds a transaction to the tracked set. // Note: blob-type transactions are ignored. -func (tracker *TxTracker) Track(tx *types.Transaction) error { - return tracker.TrackAll([]*types.Transaction{tx})[0] +func (tracker *TxTracker) Track(tx *types.Transaction) { + tracker.TrackAll([]*types.Transaction{tx}) } // TrackAll adds a list of transactions to the tracked set. // Note: blob-type transactions are ignored. -func (tracker *TxTracker) TrackAll(txs []*types.Transaction) []error { +func (tracker *TxTracker) TrackAll(txs []*types.Transaction) { tracker.mu.Lock() defer tracker.mu.Unlock() - var errors []error for _, tx := range txs { if tx.Type() == types.BlobTxType { - errors = append(errors, nil) - continue - } - // Ignore the transactions which are failed for fundamental - // validation such as invalid parameters. - if err := tracker.pool.ValidateTxBasics(tx); err != nil { - log.Debug("Invalid transaction submitted", "hash", tx.Hash(), "err", err) - errors = append(errors, err) continue } // If we're already tracking it, it's a no-op if _, ok := tracker.all[tx.Hash()]; ok { - errors = append(errors, nil) continue } // Theoretically, checking the error here is unnecessary since sender recovery @@ -108,11 +98,8 @@ func (tracker *TxTracker) TrackAll(txs []*types.Transaction) []error { // Therefore, the error is still checked just in case. addr, err := types.Sender(tracker.signer, tx) if err != nil { - errors = append(errors, err) continue } - errors = append(errors, nil) - tracker.all[tx.Hash()] = tx if tracker.byAddr[addr] == nil { tracker.byAddr[addr] = legacypool.NewSortedMap() @@ -124,7 +111,6 @@ func (tracker *TxTracker) TrackAll(txs []*types.Transaction) []error { } } localGauge.Update(int64(len(tracker.all))) - return errors } // recheck checks and returns any transactions that needs to be resubmitted. diff --git a/core/txpool/locals/tx_tracker_test.go b/core/txpool/locals/tx_tracker_test.go index 7f82c8793..55688189d 100644 --- a/core/txpool/locals/tx_tracker_test.go +++ b/core/txpool/locals/tx_tracker_test.go @@ -17,7 +17,6 @@ package locals import ( - "errors" "math/big" "testing" "time" @@ -91,10 +90,12 @@ func (env *testEnv) close() { env.chain.Stop() } +// nolint:unused func (env *testEnv) setGasTip(gasTip uint64) { env.pool.SetGasTip(new(big.Int).SetUint64(gasTip)) } +// nolint:unused func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction { if nonce == 0 { head := env.chain.CurrentHeader() @@ -121,6 +122,7 @@ func (env *testEnv) makeTxs(n int) []*types.Transaction { return txs } +// nolint:unused func (env *testEnv) commit() { head := env.chain.CurrentBlock() block := env.chain.GetBlock(head.Hash(), head.Number.Uint64()) @@ -137,60 +139,6 @@ func (env *testEnv) commit() { } } -func TestRejectInvalids(t *testing.T) { - env := newTestEnv(t, 10, 0, "") - defer env.close() - - var cases = []struct { - gasTip uint64 - tx *types.Transaction - expErr error - commit bool - }{ - { - tx: env.makeTx(5, nil), // stale - expErr: core.ErrNonceTooLow, - }, - { - tx: env.makeTx(11, nil), // future transaction - expErr: nil, - }, - { - gasTip: params.GWei, - tx: env.makeTx(0, new(big.Int).SetUint64(params.GWei/2)), // low price - expErr: txpool.ErrUnderpriced, - }, - { - tx: types.NewTransaction(10, common.Address{0x00}, big.NewInt(1000), params.TxGas, big.NewInt(params.GWei), nil), // invalid signature - expErr: types.ErrInvalidSig, - }, - { - commit: true, - tx: env.makeTx(10, nil), // stale - expErr: core.ErrNonceTooLow, - }, - { - tx: env.makeTx(11, nil), - expErr: nil, - }, - } - for i, c := range cases { - if c.gasTip != 0 { - env.setGasTip(c.gasTip) - } - if c.commit { - env.commit() - } - gotErr := env.tracker.Track(c.tx) - if c.expErr == nil && gotErr != nil { - t.Fatalf("%d, unexpected error: %v", i, gotErr) - } - if c.expErr != nil && !errors.Is(gotErr, c.expErr) { - t.Fatalf("%d, unexpected error, want: %v, got: %v", i, c.expErr, gotErr) - } - } -} - func TestResubmit(t *testing.T) { env := newTestEnv(t, 10, 0, "") defer env.close() diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 1b034fb22..4dc56ecdb 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -327,31 +327,6 @@ func (p *TxPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Pr return nil, nil } -// ValidateTxBasics checks whether a transaction is valid according to the consensus -// rules, but does not check state-dependent validation such as sufficient balance. -func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error { - addr, err := types.Sender(p.signer, tx) - if err != nil { - return err - } - // Reject transactions with stale nonce. Gapped-nonce future transactions - // are considered valid and will be handled by the subpool according to its - // internal policy. - p.stateLock.RLock() - nonce := p.state.GetNonce(addr) - p.stateLock.RUnlock() - - if nonce > tx.Nonce() { - return core.ErrNonceTooLow - } - for _, subpool := range p.subpools { - if subpool.Filter(tx) { - return subpool.ValidateTxBasics(tx) - } - } - return fmt.Errorf("%w: received type %d", core.ErrTxTypeNotSupported, tx.Type()) -} - // Add enqueues a batch of transactions into the pool if they are valid. Due // to the large transaction churn, add may postpone fully integrating the tx // to a later point to batch multiple ones together. diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 8c44d50f7..c7bf954d1 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -133,12 +133,12 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the gasprice is high enough to cover the requirement of the calling pool if tx.GasTipCapIntCmp(opts.MinTip) < 0 { - return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), opts.MinTip) + return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrTxGasPriceTooLow, tx.GasTipCap(), opts.MinTip) } if tx.Type() == types.BlobTxType { // Ensure the blob fee cap satisfies the minimum blob gas price if tx.BlobGasFeeCapIntCmp(blobTxMinBlobGasPrice) < 0 { - return fmt.Errorf("%w: blob fee cap %v, minimum needed %v", ErrUnderpriced, tx.BlobGasFeeCap(), blobTxMinBlobGasPrice) + return fmt.Errorf("%w: blob fee cap %v, minimum needed %v", ErrTxGasPriceTooLow, tx.BlobGasFeeCap(), blobTxMinBlobGasPrice) } sidecar := tx.BlobTxSidecar() if sidecar == nil { diff --git a/eth/api_backend.go b/eth/api_backend.go index 7d120be4c..add85db78 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/locals" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -285,19 +286,24 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri } func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { - locals := b.eth.localTxTracker - if locals != nil { - if err := locals.Track(signedTx); err != nil { - return err - } - } - // No error will be returned to user if the transaction fails stateful - // validation (e.g., no available slot), as the locally submitted transactions - // may be resubmitted later via the local tracker. err := b.eth.txPool.Add([]*types.Transaction{signedTx}, true, false)[0] - if err != nil && locals == nil { + + // If the local transaction tracker is not configured, returns whatever + // returned from the txpool. + if b.eth.localTxTracker == nil { + return err + } + // If the transaction fails with an error indicating it is invalid, or if there is + // very little chance it will be accepted later (e.g., the gas price is below the + // configured minimum, or the sender has insufficient funds to cover the cost), + // propagate the error to the user. + if err != nil && !locals.IsTemporaryReject(err) { return err } + // No error will be returned to user if the transaction fails with a temporary + // error and might be accepted later (e.g., the transaction pool is full). + // Locally submitted transactions will be resubmitted later via the local tracker. + b.eth.localTxTracker.Track(signedTx) return nil } diff --git a/eth/api_backend_test.go b/eth/api_backend_test.go new file mode 100644 index 000000000..f4cae294b --- /dev/null +++ b/eth/api_backend_test.go @@ -0,0 +1,157 @@ +// Copyright 2025 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 . + +package eth + +import ( + "context" + "crypto/ecdsa" + "errors" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" + "github.com/ethereum/go-ethereum/core/txpool/locals" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000_000_000_000_000) + gspec = &core.Genesis{ + Config: params.MergedTestChainConfig, + Alloc: types.GenesisAlloc{ + address: {Balance: funds}, + }, + Difficulty: common.Big0, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer = types.LatestSignerForChainID(gspec.Config.ChainID) +) + +func initBackend(withLocal bool) *EthAPIBackend { + var ( + // Create a database pre-initialize with a genesis block + db = rawdb.NewMemoryDatabase() + engine = beacon.New(ethash.NewFaker()) + ) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + + txconfig := legacypool.DefaultConfig + txconfig.Journal = "" // Don't litter the disk with test journals + + blobPool := blobpool.New(blobpool.Config{Datadir: ""}, chain, nil) + legacyPool := legacypool.New(txconfig, chain) + txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{legacyPool, blobPool}) + + eth := &Ethereum{ + blockchain: chain, + txPool: txpool, + } + if withLocal { + eth.localTxTracker = locals.New("", time.Minute, gspec.Config, txpool) + } + return &EthAPIBackend{ + eth: eth, + } +} + +func makeTx(nonce uint64, gasPrice *big.Int, amount *big.Int, key *ecdsa.PrivateKey) *types.Transaction { + if gasPrice == nil { + gasPrice = big.NewInt(params.GWei) + } + if amount == nil { + amount = big.NewInt(1000) + } + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{0x00}, amount, params.TxGas, gasPrice, nil), signer, key) + return tx +} + +type unsignedAuth struct { + nonce uint64 + key *ecdsa.PrivateKey +} + +func pricedSetCodeTx(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, unsigned []unsignedAuth) *types.Transaction { + var authList []types.SetCodeAuthorization + for _, u := range unsigned { + auth, _ := types.SignSetCode(u.key, types.SetCodeAuthorization{ + ChainID: *uint256.MustFromBig(gspec.Config.ChainID), + Address: common.Address{0x42}, + Nonce: u.nonce, + }) + authList = append(authList, auth) + } + return pricedSetCodeTxWithAuth(nonce, gaslimit, gasFee, tip, key, authList) +} + +func pricedSetCodeTxWithAuth(nonce uint64, gaslimit uint64, gasFee, tip *uint256.Int, key *ecdsa.PrivateKey, authList []types.SetCodeAuthorization) *types.Transaction { + return types.MustSignNewTx(key, signer, &types.SetCodeTx{ + ChainID: uint256.MustFromBig(gspec.Config.ChainID), + Nonce: nonce, + GasTipCap: tip, + GasFeeCap: gasFee, + Gas: gaslimit, + To: common.Address{}, + Value: uint256.NewInt(100), + Data: nil, + AccessList: nil, + AuthList: authList, + }) +} + +func TestSendTx(t *testing.T) { + testSendTx(t, false) + testSendTx(t, true) +} + +func testSendTx(t *testing.T, withLocal bool) { + b := initBackend(withLocal) + + txA := pricedSetCodeTx(0, 250000, uint256.NewInt(params.GWei), uint256.NewInt(params.GWei), key, []unsignedAuth{ + { + nonce: 0, + key: key, + }, + }) + b.SendTx(context.Background(), txA) + + txB := makeTx(1, nil, nil, key) + err := b.SendTx(context.Background(), txB) + + if withLocal { + if err != nil { + t.Fatalf("Unexpected error sending tx: %v", err) + } + } else { + if !errors.Is(err, txpool.ErrInflightTxLimitReached) { + t.Fatalf("Unexpected error, want: %v, got: %v", txpool.ErrInflightTxLimitReached, err) + } + } +} diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 1c192d411..ff17ae494 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -345,7 +345,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) // Track the transaction hash if the price is too low for us. // Avoid re-request this transaction when we receive another // announcement. - if errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced) { + if errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced) || errors.Is(err, txpool.ErrTxGasPriceTooLow) { f.underpriced.Add(batch[j].Hash(), batch[j].Time()) } // Track a few interesting failure types @@ -355,7 +355,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) case errors.Is(err, txpool.ErrAlreadyKnown): duplicate++ - case errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced): + case errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced) || errors.Is(err, txpool.ErrTxGasPriceTooLow): underpriced++ default: diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 7f3080f5f..c4c8cac56 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -1244,10 +1244,12 @@ func TestTransactionFetcherUnderpricedDedup(t *testing.T) { func(txs []*types.Transaction) []error { errs := make([]error, len(txs)) for i := 0; i < len(errs); i++ { - if i%2 == 0 { + if i%3 == 0 { errs[i] = txpool.ErrUnderpriced - } else { + } else if i%3 == 1 { errs[i] = txpool.ErrReplaceUnderpriced + } else { + errs[i] = txpool.ErrTxGasPriceTooLow } } return errs diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index fc78e8436..303e480a0 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -25,16 +25,14 @@ import ( "testing" "time" - "go.uber.org/goleak" - - "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/holiman/uint256" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" + "go.uber.org/goleak" ) var _ bind.ContractBackend = (Client)(nil) From 12f84c6f967370eb702cf4e83981d982b92992a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 18 Apr 2025 13:39:11 +0200 Subject: [PATCH 307/354] core/filtermaps: only use common ancestor snapshots (#31668) This PR makes the conditions for using a map rendering snapshot stricter so that whenever a reorg happens, only a snapshot of a common ancestor block can be used. The issue fixed in https://github.com/ethereum/go-ethereum/pull/31642 originated from using a snapshot that wasn't a common ancestor. For example in the following reorg scenario: `A->B`, then `A->B2`, then `A->B2->C2`, then `A->B->C` the last reorg triggered a render from snapshot `B` saved earlier. Now this is possible under certain conditions but extra care is needed, for example if block `B` crosses a map boundary then it should not be allowed. With the latest fix the checks are sufficient but I realized I would just feel safer if we disallowed this rare and risky scenario altogether and just render from snapshot `A` after the last reorg in the example above. The performance difference if a few milliseconds and it occurs rarely (about once a day on Holesky, probably much more rare on Mainnet). Note that this PR only makes the snapshot conditions stricter and `TestIndexerRandomRange` does check that snapshots are still used whenever it's obviously possible (adding blocks after the current head without a reorg) so this change can be considered safe. Also I am running the unit tests and the fuzzer and everything seems to be fine. --- core/filtermaps/map_renderer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index cd960ad31..23d84f0ec 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -143,6 +143,7 @@ func (f *FilterMaps) lastCanonicalSnapshotOfMap(mapIndex uint32) *renderedMap { var best *renderedMap for _, blockNumber := range f.renderSnapshots.Keys() { if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.blocks.AfterLast() && + blockNumber <= f.indexedView.headNumber && f.indexedView.getBlockId(blockNumber) == cp.lastBlockId && blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId && cp.mapIndex == mapIndex && (best == nil || blockNumber > best.lastBlock) { best = cp From f4db951e3e8f1e930a67d683f333fc827519f9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 18 Apr 2025 14:00:11 +0200 Subject: [PATCH 308/354] core/filtermaps: make ChainView thread safe (#31671) This PR makes `filtermaps.ChainView` thread safe because it is used concurrently both by the indexer and multiple matcher threads. Even though it represents an immutable view of the chain, adding a mutex lock to the `blockHash` function is necessary because it does so by extending its list of non-canonical hashes if the underlying blockchain is changed. The unsafe concurrency did cause a panic once after running the unit tests for several hours and it could also happen during live operation. --- core/filtermaps/chain_view.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index a8cf53b1c..d6f0a727b 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -17,6 +17,8 @@ package filtermaps import ( + "sync" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -39,6 +41,7 @@ type blockchain interface { // of the underlying blockchain, it should only possess the block headers // and receipts up until the expected chain view head. type ChainView struct { + lock sync.Mutex chain blockchain headNumber uint64 hashes []common.Hash // block hashes starting backwards from headNumber until first canonical hash @@ -147,6 +150,9 @@ func (cv *ChainView) extendNonCanonical() bool { // blockHash returns the given block hash without doing the head number check. func (cv *ChainView) blockHash(number uint64) common.Hash { + cv.lock.Lock() + defer cv.lock.Unlock() + if number+uint64(len(cv.hashes)) <= cv.headNumber { hash := cv.chain.GetCanonicalHash(number) if !cv.extendNonCanonical() { From 48db75365b624c1a4aa3b2c0b4efce509abe84ee Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Sat, 19 Apr 2025 21:42:54 +1000 Subject: [PATCH 309/354] core: fail execution if system call fails to execute (#31639) see: https://github.com/ethereum/pm/issues/1450#issuecomment-2800911584 --- cmd/evm/internal/t8ntool/execution.go | 8 ++++++-- core/chain_makers.go | 8 ++++++-- core/state_processor.go | 27 +++++++++++++++++---------- internal/ethapi/simulate.go | 8 ++++++-- miner/worker.go | 8 ++++++-- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index e38a510ef..18bb9817e 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -372,9 +372,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) } // EIP-7002 - core.ProcessWithdrawalQueue(&requests, evm) + if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process withdrawal requests: %v", err)) + } // EIP-7251 - core.ProcessConsolidationQueue(&requests, evm) + if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process consolidation requests: %v", err)) + } } // Commit block diff --git a/core/chain_makers.go b/core/chain_makers.go index 28b08f03c..dfff0ccaf 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -328,9 +328,13 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) { blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) // EIP-7002 - ProcessWithdrawalQueue(&requests, evm) + if err := ProcessWithdrawalQueue(&requests, evm); err != nil { + panic(fmt.Sprintf("could not process withdrawal requests: %v", err)) + } // EIP-7251 - ProcessConsolidationQueue(&requests, evm) + if err := ProcessConsolidationQueue(&requests, evm); err != nil { + panic(fmt.Sprintf("could not process consolidation requests: %v", err)) + } } return requests } diff --git a/core/state_processor.go b/core/state_processor.go index 132366d58..a4888d6bd 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -131,9 +131,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, err } // EIP-7002 - ProcessWithdrawalQueue(&requests, evm) + if err := ProcessWithdrawalQueue(&requests, evm); err != nil { + return nil, err + } // EIP-7251 - ProcessConsolidationQueue(&requests, evm) + if err := ProcessConsolidationQueue(&requests, evm); err != nil { + return nil, err + } } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) @@ -283,17 +287,17 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. // It returns the opaque request data returned by the contract. -func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) { - processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress) +func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) error { + return processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress) } // ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract. // It returns the opaque request data returned by the contract. -func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) { - processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) +func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error { + return processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress) } -func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) { +func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error { if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(tracer, evm.GetVMContext()) if tracer.OnSystemCallEnd != nil { @@ -310,17 +314,20 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(addr) - ret, _, _ := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) + ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) evm.StateDB.Finalise(true) + if err != nil { + return fmt.Errorf("system call failed to execute: %v", err) + } if len(ret) == 0 { - return // skip empty output + return nil // skip empty output } - // Append prefixed requestsData to the requests list. requestsData := make([]byte, len(ret)+1) requestsData[0] = requestType copy(requestsData[1:], ret) *requests = append(*requests, requestsData) + return nil } var depositTopic = common.HexToHash("0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5") diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index be8254dc5..b4f76de80 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -318,9 +318,13 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, return nil, nil, err } // EIP-7002 - core.ProcessWithdrawalQueue(&requests, evm) + if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { + return nil, nil, err + } // EIP-7251 - core.ProcessConsolidationQueue(&requests, evm) + if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { + return nil, nil, err + } } if requests != nil { reqHash := types.CalcRequestsHash(requests) diff --git a/miner/worker.go b/miner/worker.go index e24cfb1cd..5a77fab47 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1133,9 +1133,13 @@ func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadR return &newPayloadResult{err: err} } // EIP-7002 - core.ProcessWithdrawalQueue(&requests, work.evm) + if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { + return &newPayloadResult{err: err} + } // EIP-7251 consolidations - core.ProcessConsolidationQueue(&requests, work.evm) + if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil { + return &newPayloadResult{err: err} + } } if requests != nil { reqHash := types.CalcRequestsHash(requests) From 64a41ac33042c8afe2f8816a73010903cef2e534 Mon Sep 17 00:00:00 2001 From: Morty <70688412+yiweichi@users.noreply.github.com> Date: Sat, 19 Apr 2025 22:02:31 +0800 Subject: [PATCH 310/354] eth/gasprice: fix eth_feeHistory blobGasUsedRatio divide zero (#31663) The API `eth_feeHistory` returns `{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"json: unsupported value: NaN"}}`, when we query `eth_feeHistory` with a old block that without a blob, or when the field `config.blobSchedule.cancun.max` in genesis.config is 0 (that happens for some projects fork geth but they don't have blob). So here we specially handle the case when maxBlobGas == 0 to prevent this issue from happening. --- eth/gasprice/feehistory.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 5885ce067..b8daeecaa 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -113,7 +113,9 @@ func (oracle *Oracle) processBlock(ctx context.Context, bf *blockFees, percentil bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit) if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil { maxBlobGas := eip4844.MaxBlobGasPerBlock(config, bf.header.Time) - bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobGas) + if maxBlobGas != 0 { + bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobGas) + } } if len(percentiles) == 0 { From 60f7a6caf27a96d33b294ed718d62c7a89f86dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Sun, 20 Apr 2025 09:48:49 +0200 Subject: [PATCH 311/354] eth/filters, core/filtermaps: safe chain view update (#31590) This PR changes the chain view update mechanism of the log filter. Previously the head updates were all wired through the indexer, even in unindexed mode. This was both a bit weird and also unsafe as the indexer's chain view was updates asynchronously with some delay, making some log related tests flaky. Also, the reorg safety of the indexed search was integrated with unindexed search in a weird way, relying on `syncRange.ValidBlocks` in the unindexed case too, with a special condition added to only consider the head of the valid range but not the tail in the unindexed case. In this PR the current chain view is directly accessible through the filter backend and unindexed search is also chain view based, making it inherently safe. The matcher sync mechanism is now only used for indexed search as originally intended, removing a few ugly special conditions. The PR is currently based on top of https://github.com/ethereum/go-ethereum/pull/31642 Together they fix https://github.com/ethereum/go-ethereum/issues/31518 and replace https://github.com/ethereum/go-ethereum/pull/31542 --------- Co-authored-by: Gary Rong --- accounts/abi/abigen/bind_test.go | 5 +- core/filtermaps/chain_view.go | 61 ++++-- core/filtermaps/filtermaps.go | 8 +- core/filtermaps/indexer.go | 8 +- core/filtermaps/map_renderer.go | 32 +-- core/filtermaps/matcher.go | 2 +- core/filtermaps/matcher_backend.go | 6 +- eth/api_backend.go | 8 + eth/filters/filter.go | 252 +++++++++++++---------- eth/filters/filter_system.go | 1 + eth/filters/filter_system_test.go | 5 + eth/filters/filter_test.go | 137 +++++++----- internal/ethapi/api_test.go | 3 + internal/ethapi/backend.go | 1 + internal/ethapi/transaction_args_test.go | 1 + 15 files changed, 328 insertions(+), 202 deletions(-) diff --git a/accounts/abi/abigen/bind_test.go b/accounts/abi/abigen/bind_test.go index 195064fb7..b3c52e81e 100644 --- a/accounts/abi/abigen/bind_test.go +++ b/accounts/abi/abigen/bind_test.go @@ -939,6 +939,7 @@ var bindTests = []struct { if _, err := eventer.RaiseSimpleEvent(auth, common.Address{byte(j)}, [32]byte{byte(j)}, true, big.NewInt(int64(10*i+j))); err != nil { t.Fatalf("block %d, event %d: raise failed: %v", i, j, err) } + time.Sleep(time.Millisecond * 200) } sim.Commit() } @@ -1495,7 +1496,7 @@ var bindTests = []struct { if n != 3 { t.Fatalf("Invalid bar0 event") } - case <-time.NewTimer(3 * time.Second).C: + case <-time.NewTimer(10 * time.Second).C: t.Fatalf("Wait bar0 event timeout") } @@ -1506,7 +1507,7 @@ var bindTests = []struct { if n != 1 { t.Fatalf("Invalid bar event") } - case <-time.NewTimer(3 * time.Second).C: + case <-time.NewTimer(10 * time.Second).C: t.Fatalf("Wait bar event timeout") } close(stopCh) diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index d6f0a727b..aa74f3901 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -58,47 +58,75 @@ func NewChainView(chain blockchain, number uint64, hash common.Hash) *ChainView return cv } -// getBlockHash returns the block hash belonging to the given block number. +// HeadNumber returns the head block number of the chain view. +func (cv *ChainView) HeadNumber() uint64 { + return cv.headNumber +} + +// BlockHash returns the block hash belonging to the given block number. // Note that the hash of the head block is not returned because ChainView might // represent a view where the head block is currently being created. -func (cv *ChainView) getBlockHash(number uint64) common.Hash { - if number >= cv.headNumber { +func (cv *ChainView) BlockHash(number uint64) common.Hash { + cv.lock.Lock() + defer cv.lock.Unlock() + + if number > cv.headNumber { panic("invalid block number") } return cv.blockHash(number) } -// getBlockId returns the unique block id belonging to the given block number. +// BlockId returns the unique block id belonging to the given block number. // Note that it is currently equal to the block hash. In the future it might // be a different id for future blocks if the log index root becomes part of // consensus and therefore rendering the index with the new head will happen // before the hash of that new head is available. -func (cv *ChainView) getBlockId(number uint64) common.Hash { +func (cv *ChainView) BlockId(number uint64) common.Hash { + cv.lock.Lock() + defer cv.lock.Unlock() + if number > cv.headNumber { panic("invalid block number") } return cv.blockHash(number) } -// getReceipts returns the set of receipts belonging to the block at the given +// Header returns the block header at the given block number. +func (cv *ChainView) Header(number uint64) *types.Header { + return cv.chain.GetHeader(cv.BlockHash(number), number) +} + +// Receipts returns the set of receipts belonging to the block at the given // block number. -func (cv *ChainView) getReceipts(number uint64) types.Receipts { - if number > cv.headNumber { - panic("invalid block number") - } - blockHash := cv.blockHash(number) +func (cv *ChainView) Receipts(number uint64) types.Receipts { + blockHash := cv.BlockHash(number) if blockHash == (common.Hash{}) { log.Error("Chain view: block hash unavailable", "number", number, "head", cv.headNumber) } return cv.chain.GetReceiptsByHash(blockHash) } +// SharedRange returns the block range shared by two chain views. +func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { + cv.lock.Lock() + defer cv.lock.Unlock() + + if cv == nil || cv2 == nil || !cv.extendNonCanonical() || !cv2.extendNonCanonical() { + return common.Range[uint64]{} + } + var sharedLen uint64 + for n := min(cv.headNumber+1-uint64(len(cv.hashes)), cv2.headNumber+1-uint64(len(cv2.hashes))); n <= cv.headNumber && n <= cv2.headNumber && cv.blockHash(n) == cv2.blockHash(n); n++ { + sharedLen = n + 1 + } + return common.NewRange(0, sharedLen) +} + // limitedView returns a new chain view that is a truncated version of the parent view. func (cv *ChainView) limitedView(newHead uint64) *ChainView { if newHead >= cv.headNumber { return cv } - return NewChainView(cv.chain, newHead, cv.blockHash(newHead)) + return NewChainView(cv.chain, newHead, cv.BlockHash(newHead)) } // equalViews returns true if the two chain views are equivalent. @@ -106,7 +134,7 @@ func equalViews(cv1, cv2 *ChainView) bool { if cv1 == nil || cv2 == nil { return false } - return cv1.headNumber == cv2.headNumber && cv1.getBlockId(cv1.headNumber) == cv2.getBlockId(cv2.headNumber) + return cv1.headNumber == cv2.headNumber && cv1.BlockId(cv1.headNumber) == cv2.BlockId(cv2.headNumber) } // matchViews returns true if the two chain views are equivalent up until the @@ -120,9 +148,9 @@ func matchViews(cv1, cv2 *ChainView, number uint64) bool { return false } if number == cv1.headNumber || number == cv2.headNumber { - return cv1.getBlockId(number) == cv2.getBlockId(number) + return cv1.BlockId(number) == cv2.BlockId(number) } - return cv1.getBlockHash(number) == cv2.getBlockHash(number) + return cv1.BlockHash(number) == cv2.BlockHash(number) } // extendNonCanonical checks whether the previously known reverse list of head @@ -150,9 +178,6 @@ func (cv *ChainView) extendNonCanonical() bool { // blockHash returns the given block hash without doing the head number check. func (cv *ChainView) blockHash(number uint64) common.Hash { - cv.lock.Lock() - defer cv.lock.Unlock() - if number+uint64(len(cv.hashes)) <= cv.headNumber { hash := cv.chain.GetCanonicalHash(number) if !cv.extendNonCanonical() { diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index fa2d6e3ff..a617de896 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -262,7 +262,7 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f f.targetView = initView if f.indexedRange.initialized { f.indexedView = f.initChainView(f.targetView) - f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.headNumber+1 + f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.HeadNumber()+1 if !f.indexedRange.headIndexed { f.indexedRange.headDelimiter = 0 } @@ -313,7 +313,7 @@ func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView { log.Error("Could not initialize indexed chain view", "error", err) break } - if lastBlockNumber <= chainView.headNumber && chainView.getBlockId(lastBlockNumber) == lastBlockId { + if lastBlockNumber <= chainView.HeadNumber() && chainView.BlockId(lastBlockNumber) == lastBlockId { return chainView.limitedView(lastBlockNumber) } } @@ -370,7 +370,7 @@ func (f *FilterMaps) init() error { for min < max { mid := (min + max + 1) / 2 cp := checkpointList[mid-1] - if cp.BlockNumber <= f.targetView.headNumber && f.targetView.getBlockId(cp.BlockNumber) == cp.BlockId { + if cp.BlockNumber <= f.targetView.HeadNumber() && f.targetView.BlockId(cp.BlockNumber) == cp.BlockId { min = mid } else { max = mid - 1 @@ -512,7 +512,7 @@ func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { } } // get block receipts - receipts := f.indexedView.getReceipts(firstBlockNumber) + receipts := f.indexedView.Receipts(firstBlockNumber) if receipts == nil { return nil, fmt.Errorf("failed to retrieve receipts for block %d containing searched log value index %d: %v", firstBlockNumber, lvIndex, err) } diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 9a5424da4..383ec078c 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -44,7 +44,7 @@ func (f *FilterMaps) indexerLoop() { for !f.stop { if !f.indexedRange.initialized { - if f.targetView.headNumber == 0 { + if f.targetView.HeadNumber() == 0 { // initialize when chain head is available f.processSingleEvent(true) continue @@ -249,7 +249,7 @@ func (f *FilterMaps) tryIndexHead() error { log.Info("Log index head rendering in progress", "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex, - "remaining", f.indexedView.headNumber-f.indexedRange.blocks.Last(), + "remaining", f.indexedView.HeadNumber()-f.indexedRange.blocks.Last(), "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) f.loggedHeadIndex = true f.lastLogHeadIndex = time.Now() @@ -418,10 +418,10 @@ func (f *FilterMaps) needTailEpoch(epoch uint32) bool { // tailTargetBlock returns the target value for the tail block number according // to the log history parameter and the current index head. func (f *FilterMaps) tailTargetBlock() uint64 { - if f.history == 0 || f.indexedView.headNumber < f.history { + if f.history == 0 || f.indexedView.HeadNumber() < f.history { return 0 } - return f.indexedView.headNumber + 1 - f.history + return f.indexedView.HeadNumber() + 1 - f.history } // tailPartialBlocks returns the number of rendered blocks in the partially diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 23d84f0ec..7c2aa8dc3 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -143,8 +143,8 @@ func (f *FilterMaps) lastCanonicalSnapshotOfMap(mapIndex uint32) *renderedMap { var best *renderedMap for _, blockNumber := range f.renderSnapshots.Keys() { if cp, _ := f.renderSnapshots.Get(blockNumber); cp != nil && blockNumber < f.indexedRange.blocks.AfterLast() && - blockNumber <= f.indexedView.headNumber && f.indexedView.getBlockId(blockNumber) == cp.lastBlockId && - blockNumber <= f.targetView.headNumber && f.targetView.getBlockId(blockNumber) == cp.lastBlockId && + blockNumber <= f.indexedView.HeadNumber() && f.indexedView.BlockId(blockNumber) == cp.lastBlockId && + blockNumber <= f.targetView.HeadNumber() && f.targetView.BlockId(blockNumber) == cp.lastBlockId && cp.mapIndex == mapIndex && (best == nil || blockNumber > best.lastBlock) { best = cp } @@ -173,7 +173,7 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMa return 0, 0, 0, fmt.Errorf("failed to retrieve last block of reverse iterated map %d: %v", mapIndex, err) } if (f.indexedRange.headIndexed && mapIndex >= f.indexedRange.maps.Last()) || - lastBlock >= f.targetView.headNumber || lastBlockId != f.targetView.getBlockId(lastBlock) { + lastBlock >= f.targetView.HeadNumber() || lastBlockId != f.targetView.BlockId(lastBlock) { continue // map is not full or inconsistent with targetView; roll back } lvPtr, err := f.getBlockLvPointer(lastBlock) @@ -247,7 +247,7 @@ func (f *FilterMaps) loadHeadSnapshot() error { filterMap: fm, mapIndex: f.indexedRange.maps.Last(), lastBlock: f.indexedRange.blocks.Last(), - lastBlockId: f.indexedView.getBlockId(f.indexedRange.blocks.Last()), + lastBlockId: f.indexedView.BlockId(f.indexedRange.blocks.Last()), blockLvPtrs: lvPtrs, finished: true, headDelimiter: f.indexedRange.headDelimiter, @@ -264,7 +264,7 @@ func (r *mapRenderer) makeSnapshot() { filterMap: r.currentMap.filterMap.fastCopy(), mapIndex: r.currentMap.mapIndex, lastBlock: r.currentMap.lastBlock, - lastBlockId: r.iterator.chainView.getBlockId(r.currentMap.lastBlock), + lastBlockId: r.iterator.chainView.BlockId(r.currentMap.lastBlock), blockLvPtrs: r.currentMap.blockLvPtrs, finished: true, headDelimiter: r.iterator.lvIndex, @@ -370,7 +370,7 @@ func (r *mapRenderer) renderCurrentMap(stopCb func() bool) (bool, error) { r.currentMap.finished = true r.currentMap.headDelimiter = r.iterator.lvIndex } - r.currentMap.lastBlockId = r.f.targetView.getBlockId(r.currentMap.lastBlock) + r.currentMap.lastBlockId = r.f.targetView.BlockId(r.currentMap.lastBlock) totalTime += time.Since(start) mapRenderTimer.Update(totalTime) mapLogValueMeter.Mark(logValuesProcessed) @@ -566,8 +566,8 @@ func (r *mapRenderer) getUpdatedRange() (filterMapsRange, error) { lm := r.finishedMaps[r.finished.Last()] newRange.headIndexed = lm.finished if lm.finished { - newRange.blocks.SetLast(r.f.targetView.headNumber) - if lm.lastBlock != r.f.targetView.headNumber { + newRange.blocks.SetLast(r.f.targetView.HeadNumber()) + if lm.lastBlock != r.f.targetView.HeadNumber() { panic("map rendering finished but last block != head block") } newRange.headDelimiter = lm.headDelimiter @@ -665,13 +665,13 @@ var errUnindexedRange = errors.New("unindexed range") // given block's first log value entry (the block delimiter), according to the // current targetView. func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber, lvIndex uint64) (*logIterator, error) { - if blockNumber > f.targetView.headNumber { - return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.headNumber) + if blockNumber > f.targetView.HeadNumber() { + return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", blockNumber, f.targetView.HeadNumber()) } if !f.indexedRange.blocks.Includes(blockNumber) { return nil, errUnindexedRange } - finished := blockNumber == f.targetView.headNumber + finished := blockNumber == f.targetView.HeadNumber() l := &logIterator{ chainView: f.targetView, params: &f.Params, @@ -687,11 +687,11 @@ func (f *FilterMaps) newLogIteratorFromBlockDelimiter(blockNumber, lvIndex uint6 // newLogIteratorFromMapBoundary creates a logIterator starting at the given // map boundary, according to the current targetView. func (f *FilterMaps) newLogIteratorFromMapBoundary(mapIndex uint32, startBlock, startLvPtr uint64) (*logIterator, error) { - if startBlock > f.targetView.headNumber { - return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", startBlock, f.targetView.headNumber) + if startBlock > f.targetView.HeadNumber() { + return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", startBlock, f.targetView.HeadNumber()) } // get block receipts - receipts := f.targetView.getReceipts(startBlock) + receipts := f.targetView.Receipts(startBlock) if receipts == nil { return nil, fmt.Errorf("receipts not found for start block %d", startBlock) } @@ -758,7 +758,7 @@ func (l *logIterator) next() error { if l.delimiter { l.delimiter = false l.blockNumber++ - l.receipts = l.chainView.getReceipts(l.blockNumber) + l.receipts = l.chainView.Receipts(l.blockNumber) if l.receipts == nil { return fmt.Errorf("receipts not found for block %d", l.blockNumber) } @@ -795,7 +795,7 @@ func (l *logIterator) enforceValidState() { } l.logIndex = 0 } - if l.blockNumber == l.chainView.headNumber { + if l.blockNumber == l.chainView.HeadNumber() { l.finished = true } else { l.delimiter = true diff --git a/core/filtermaps/matcher.go b/core/filtermaps/matcher.go index 5738bf166..a5eeaaa5f 100644 --- a/core/filtermaps/matcher.go +++ b/core/filtermaps/matcher.go @@ -57,7 +57,7 @@ type MatcherBackend interface { // all states of the chain since the previous SyncLogIndex or the creation of // the matcher backend. type SyncRange struct { - HeadNumber uint64 + IndexedView *ChainView // block range where the index has not changed since the last matcher sync // and therefore the set of matches found in this region is guaranteed to // be valid and complete. diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index 335ac8455..ee18a0694 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -128,7 +128,7 @@ func (fm *FilterMapsMatcherBackend) synced() { indexedBlocks.SetAfterLast(indexedBlocks.Last()) // remove partially indexed last block } fm.syncCh <- SyncRange{ - HeadNumber: fm.f.targetView.headNumber, + IndexedView: fm.f.indexedView, ValidBlocks: fm.validBlocks, IndexedBlocks: indexedBlocks, } @@ -154,7 +154,7 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange case <-ctx.Done(): return SyncRange{}, ctx.Err() case <-fm.f.disabledCh: - return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil + return SyncRange{IndexedView: fm.f.indexedView}, nil } select { case vr := <-syncCh: @@ -162,7 +162,7 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange case <-ctx.Done(): return SyncRange{}, ctx.Err() case <-fm.f.disabledCh: - return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil + return SyncRange{IndexedView: fm.f.indexedView}, nil } } diff --git a/eth/api_backend.go b/eth/api_backend.go index add85db78..4c3a49edb 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -448,6 +448,14 @@ func (b *EthAPIBackend) RPCTxFeeCap() float64 { return b.eth.config.RPCTxFeeCap } +func (b *EthAPIBackend) CurrentView() *filtermaps.ChainView { + head := b.eth.blockchain.CurrentBlock() + if head == nil { + return nil + } + return filtermaps.NewChainView(b.eth.blockchain, head.Number.Uint64(), head.Hash()) +} + func (b *EthAPIBackend) NewMatcherBackend() filtermaps.MatcherBackend { return b.eth.filterMaps.NewMatcherBackend() } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index c094d763c..23754fdf7 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -135,25 +135,29 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } const ( - rangeLogsTestSync = iota - rangeLogsTestTrimmed - rangeLogsTestIndexed - rangeLogsTestUnindexed - rangeLogsTestDone + rangeLogsTestDone = iota // zero range + rangeLogsTestSync // before sync; zero range + rangeLogsTestSynced // after sync; valid blocks range + rangeLogsTestIndexed // individual search range + rangeLogsTestUnindexed // individual search range + rangeLogsTestResults // results range after search iteration + rangeLogsTestReorg // results range trimmed by reorg ) type rangeLogsTestEvent struct { - event int - begin, end uint64 + event int + blocks common.Range[uint64] } // searchSession represents a single search session. type searchSession struct { - ctx context.Context - filter *Filter - mb filtermaps.MatcherBackend - syncRange filtermaps.SyncRange // latest synchronized state with the matcher - firstBlock, lastBlock uint64 // specified search range; each can be MaxUint64 + ctx context.Context + filter *Filter + mb filtermaps.MatcherBackend + syncRange filtermaps.SyncRange // latest synchronized state with the matcher + chainView *filtermaps.ChainView // can be more recent than the indexed view in syncRange + // block ranges always refer to the current chainView + firstBlock, lastBlock uint64 // specified search range; MaxUint64 means latest block searchRange common.Range[uint64] // actual search range; end trimmed to latest head matchRange common.Range[uint64] // range in which we have results (subset of searchRange) matches []*types.Log // valid set of matches in matchRange @@ -171,84 +175,99 @@ func newSearchSession(ctx context.Context, filter *Filter, mb filtermaps.Matcher } // enforce a consistent state before starting the search in order to be able // to determine valid range later - if err := s.syncMatcher(0); err != nil { + var err error + s.syncRange, err = s.mb.SyncLogIndex(s.ctx) + if err != nil { + return nil, err + } + if err := s.updateChainView(); err != nil { return nil, err } return s, nil } -// syncMatcher performs a synchronization step with the matcher. The resulting -// syncRange structure holds information about the latest range of indexed blocks -// and the guaranteed valid blocks whose log index have not been changed since -// the previous synchronization. -// The function also performs trimming of the match set in order to always keep -// it consistent with the synced matcher state. -// Tail trimming is only performed if the first block of the valid log index range -// is higher than trimTailThreshold. This is useful because unindexed log search -// is not affected by the valid tail (on the other hand, valid head is taken into -// account in order to provide reorg safety, even though the log index is not used). -// In case of indexed search the tail is only trimmed if the first part of the -// recently obtained results might be invalid. If guaranteed valid new results -// have been added at the head of previously validated results then there is no -// need to discard those even if the index tail have been unindexed since that. -func (s *searchSession) syncMatcher(trimTailThreshold uint64) error { - if s.filter.rangeLogsTestHook != nil && !s.matchRange.IsEmpty() { - s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestSync, begin: s.matchRange.First(), end: s.matchRange.Last()} +// updateChainView updates to the latest view of the underlying chain and sets +// searchRange by replacing MaxUint64 (meaning latest block) with actual head +// number in the specified search range. +// If the session already had an existing chain view and set of matches then +// it also trims part of the match set that a chain reorg might have invalidated. +func (s *searchSession) updateChainView() error { + // update chain view based on current chain head (might be more recent than + // the indexed view of syncRange as the indexer updates it asynchronously + // with some delay + newChainView := s.filter.sys.backend.CurrentView() + if newChainView == nil { + return errors.New("head block not available") + } + head := newChainView.HeadNumber() + + // update actual search range based on current head number + firstBlock, lastBlock := s.firstBlock, s.lastBlock + if firstBlock == math.MaxUint64 { + firstBlock = head } - var err error - s.syncRange, err = s.mb.SyncLogIndex(s.ctx) - if err != nil { - return err + if lastBlock == math.MaxUint64 { + lastBlock = head } - // update actual search range based on current head number - first := min(s.firstBlock, s.syncRange.HeadNumber) - last := min(s.lastBlock, s.syncRange.HeadNumber) - s.searchRange = common.NewRange(first, last+1-first) - // discard everything that is not needed or might be invalid - trimRange := s.syncRange.ValidBlocks - if trimRange.First() <= trimTailThreshold { - // everything before this point is already known to be valid; if this is - // valid then keep everything before - trimRange.SetFirst(0) - } - trimRange = trimRange.Intersection(s.searchRange) - s.trimMatches(trimRange) - if s.filter.rangeLogsTestHook != nil { - if !s.matchRange.IsEmpty() { - s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: s.matchRange.First(), end: s.matchRange.Last()} - } else { - s.filter.rangeLogsTestHook <- rangeLogsTestEvent{event: rangeLogsTestTrimmed, begin: 0, end: 0} - } + if firstBlock > lastBlock || lastBlock > head { + return errInvalidBlockRange } + s.searchRange = common.NewRange(firstBlock, lastBlock+1-firstBlock) + + // Trim existing match set in case a reorg may have invalidated some results + if !s.matchRange.IsEmpty() { + trimRange := newChainView.SharedRange(s.chainView).Intersection(s.searchRange) + s.matchRange, s.matches = s.trimMatches(trimRange, s.matchRange, s.matches) + } + s.chainView = newChainView return nil } -// trimMatches removes any entries from the current set of matches that is outside -// the given range. -func (s *searchSession) trimMatches(trimRange common.Range[uint64]) { - s.matchRange = s.matchRange.Intersection(trimRange) - if s.matchRange.IsEmpty() { - s.matches = nil - return +// trimMatches removes any entries from the specified set of matches that is +// outside the given range. +func (s *searchSession) trimMatches(trimRange, matchRange common.Range[uint64], matches []*types.Log) (common.Range[uint64], []*types.Log) { + newRange := matchRange.Intersection(trimRange) + if newRange == matchRange { + return matchRange, matches } - for len(s.matches) > 0 && s.matches[0].BlockNumber < s.matchRange.First() { - s.matches = s.matches[1:] + if newRange.IsEmpty() { + return newRange, nil } - for len(s.matches) > 0 && s.matches[len(s.matches)-1].BlockNumber > s.matchRange.Last() { - s.matches = s.matches[:len(s.matches)-1] + for len(matches) > 0 && matches[0].BlockNumber < newRange.First() { + matches = matches[1:] } + for len(matches) > 0 && matches[len(matches)-1].BlockNumber > newRange.Last() { + matches = matches[:len(matches)-1] + } + return newRange, matches } // searchInRange performs a single range search, either indexed or unindexed. -func (s *searchSession) searchInRange(r common.Range[uint64], indexed bool) ([]*types.Log, error) { - first, last := r.First(), r.Last() +func (s *searchSession) searchInRange(r common.Range[uint64], indexed bool) (common.Range[uint64], []*types.Log, error) { if indexed { if s.filter.rangeLogsTestHook != nil { - s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestIndexed, first, last} + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestIndexed, r} } - results, err := s.filter.indexedLogs(s.ctx, s.mb, first, last) - if err != filtermaps.ErrMatchAll { - return results, err + results, err := s.filter.indexedLogs(s.ctx, s.mb, r.First(), r.Last()) + if err != nil && !errors.Is(err, filtermaps.ErrMatchAll) { + return common.Range[uint64]{}, nil, err + } + if err == nil { + // sync with filtermaps matcher + if s.filter.rangeLogsTestHook != nil { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestSync, common.Range[uint64]{}} + } + var syncErr error + if s.syncRange, syncErr = s.mb.SyncLogIndex(s.ctx); syncErr != nil { + return common.Range[uint64]{}, nil, syncErr + } + if s.filter.rangeLogsTestHook != nil { + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestSynced, s.syncRange.ValidBlocks} + } + // discard everything that might be invalid + trimRange := s.syncRange.ValidBlocks.Intersection(s.chainView.SharedRange(s.syncRange.IndexedView)) + matchRange, matches := s.trimMatches(trimRange, r, results) + return matchRange, matches, nil } // "match all" filters are not supported by filtermaps; fall back to // unindexed search which is the most efficient in this case @@ -256,79 +275,85 @@ func (s *searchSession) searchInRange(r common.Range[uint64], indexed bool) ([]* // fall through to unindexed case } if s.filter.rangeLogsTestHook != nil { - s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestUnindexed, first, last} + s.filter.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestUnindexed, r} + } + matches, err := s.filter.unindexedLogs(s.ctx, s.chainView, r.First(), r.Last()) + if err != nil { + return common.Range[uint64]{}, nil, err } - return s.filter.unindexedLogs(s.ctx, first, last) + return r, matches, nil } // doSearchIteration performs a search on a range missing from an incomplete set // of results, adds the new section and removes invalidated entries. func (s *searchSession) doSearchIteration() error { switch { - case s.syncRange.IndexedBlocks.IsEmpty(): - // indexer is not ready; fallback to completely unindexed search, do not check valid range - var err error - s.matchRange = s.searchRange - s.matches, err = s.searchInRange(s.searchRange, false) - return err - case s.matchRange.IsEmpty(): // no results yet; try search in entire range indexedSearchRange := s.searchRange.Intersection(s.syncRange.IndexedBlocks) - var err error if s.forceUnindexed = indexedSearchRange.IsEmpty(); !s.forceUnindexed { // indexed search on the intersection of indexed and searched range - s.matchRange = indexedSearchRange - s.matches, err = s.searchInRange(indexedSearchRange, true) + matchRange, matches, err := s.searchInRange(indexedSearchRange, true) if err != nil { return err } - return s.syncMatcher(0) // trim everything that the matcher considers potentially invalid + s.matchRange = matchRange + s.matches = matches + return nil } else { - // no intersection of indexed and searched range; unindexed search on the whole searched range - s.matchRange = s.searchRange - s.matches, err = s.searchInRange(s.searchRange, false) + // no intersection of indexed and searched range; unindexed search on + // the whole searched range + matchRange, matches, err := s.searchInRange(s.searchRange, false) if err != nil { return err } - return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range + s.matchRange = matchRange + s.matches = matches + return nil } case !s.matchRange.IsEmpty() && s.matchRange.First() > s.searchRange.First(): - // we have results but tail section is missing; do unindexed search for - // the tail part but still allow indexed search for missing head section + // Results are available, but the tail section is missing. Perform an unindexed + // search for the missing tail, while still allowing indexed search for the head. + // + // The unindexed search is necessary because the tail portion of the indexes + // has been pruned. tailRange := common.NewRange(s.searchRange.First(), s.matchRange.First()-s.searchRange.First()) - tailMatches, err := s.searchInRange(tailRange, false) + _, tailMatches, err := s.searchInRange(tailRange, false) if err != nil { return err } s.matches = append(tailMatches, s.matches...) s.matchRange = tailRange.Union(s.matchRange) - return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range + return nil case !s.matchRange.IsEmpty() && s.matchRange.First() == s.searchRange.First() && s.searchRange.AfterLast() > s.matchRange.AfterLast(): - // we have results but head section is missing + // Results are available, but the head section is missing. Try to perform + // the indexed search for the missing head, or fallback to unindexed search + // if the tail portion of indexed range has been pruned. headRange := common.NewRange(s.matchRange.AfterLast(), s.searchRange.AfterLast()-s.matchRange.AfterLast()) if !s.forceUnindexed { indexedHeadRange := headRange.Intersection(s.syncRange.IndexedBlocks) if !indexedHeadRange.IsEmpty() && indexedHeadRange.First() == headRange.First() { - // indexed head range search is possible headRange = indexedHeadRange } else { + // The tail portion of the indexes has been pruned, falling back + // to unindexed search. s.forceUnindexed = true } } - headMatches, err := s.searchInRange(headRange, !s.forceUnindexed) + headMatchRange, headMatches, err := s.searchInRange(headRange, !s.forceUnindexed) if err != nil { return err } - s.matches = append(s.matches, headMatches...) - s.matchRange = s.matchRange.Union(headRange) - if s.forceUnindexed { - return s.syncMatcher(math.MaxUint64) // unindexed search is not affected by the tail of valid range - } else { - return s.syncMatcher(headRange.First()) // trim if the tail of latest head search results might be invalid + if headMatchRange.First() != s.matchRange.AfterLast() { + // improbable corner case, first part of new head range invalidated by tail unindexing + s.matches, s.matchRange = headMatches, headMatchRange + return nil } + s.matches = append(s.matches, headMatches...) + s.matchRange = s.matchRange.Union(headMatchRange) + return nil default: panic("invalid search session state") @@ -338,7 +363,7 @@ func (s *searchSession) doSearchIteration() error { func (f *Filter) rangeLogs(ctx context.Context, firstBlock, lastBlock uint64) ([]*types.Log, error) { if f.rangeLogsTestHook != nil { defer func() { - f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestDone, 0, 0} + f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestDone, common.Range[uint64]{}} close(f.rangeLogsTestHook) }() } @@ -355,7 +380,17 @@ func (f *Filter) rangeLogs(ctx context.Context, firstBlock, lastBlock uint64) ([ } for session.searchRange != session.matchRange { if err := session.doSearchIteration(); err != nil { - return session.matches, err + return nil, err + } + if f.rangeLogsTestHook != nil { + f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestResults, session.matchRange} + } + mr := session.matchRange + if err := session.updateChainView(); err != nil { + return nil, err + } + if f.rangeLogsTestHook != nil && session.matchRange != mr { + f.rangeLogsTestHook <- rangeLogsTestEvent{rangeLogsTestReorg, session.matchRange} } } return session.matches, nil @@ -371,7 +406,7 @@ func (f *Filter) indexedLogs(ctx context.Context, mb filtermaps.MatcherBackend, // unindexedLogs returns the logs matching the filter criteria based on raw block // iteration and bloom matching. -func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) { +func (f *Filter) unindexedLogs(ctx context.Context, chainView *filtermaps.ChainView, begin, end uint64) ([]*types.Log, error) { start := time.Now() log.Debug("Performing unindexed log search", "begin", begin, "end", end) var matches []*types.Log @@ -381,9 +416,14 @@ func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types return matches, ctx.Err() default: } - header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(blockNumber)) - if header == nil || err != nil { - return matches, err + if blockNumber > chainView.HeadNumber() { + // check here so that we can return matches up until head along with + // the error + return matches, errInvalidBlockRange + } + header := chainView.Header(blockNumber) + if header == nil { + return matches, errors.New("header not found") } found, err := f.blockLogs(ctx, header) if err != nil { diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 4b2c3d83c..34b06ecdc 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -71,6 +71,7 @@ type Backend interface { SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription + CurrentView() *filtermaps.ChainView NewMatcherBackend() filtermaps.MatcherBackend StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 8c4eb093c..701c5533f 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -160,6 +160,11 @@ func (b *testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHead return b.finalizedHeaderFeed.Subscribe(ch) } +func (b *testBackend) CurrentView() *filtermaps.ChainView { + head := b.CurrentBlock() + return filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash()) +} + func (b *testBackend) NewMatcherBackend() filtermaps.MatcherBackend { return b.fm.NewMatcherBackend() } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 6af073d42..269a93bac 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -453,7 +453,8 @@ func TestRangeLogs(t *testing.T) { addresses = []common.Address{{}} ) - expEvent := func(exp rangeLogsTestEvent) { + expEvent := func(expEvent int, expFirst, expAfterLast uint64) { + exp := rangeLogsTestEvent{expEvent, common.NewRange[uint64](expFirst, expAfterLast-expFirst)} event++ ev := <-filter.rangeLogsTestHook if ev != exp { @@ -472,7 +473,6 @@ func TestRangeLogs(t *testing.T) { for range filter.rangeLogsTestHook { } }(filter) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) } updateHead := func() { @@ -483,81 +483,122 @@ func TestRangeLogs(t *testing.T) { // test case #1 newFilter(300, 500) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 401, 500}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 401, 500}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 401, 500}) - expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 300, 400}) + expEvent(rangeLogsTestIndexed, 401, 501) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 401, 601) + expEvent(rangeLogsTestResults, 401, 501) + expEvent(rangeLogsTestUnindexed, 300, 401) if _, err := bc.InsertChain(chain[600:700]); err != nil { t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 300, 500}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 300, 500}) // unindexed search is not affected by trimmed tail - expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + expEvent(rangeLogsTestResults, 300, 501) + expEvent(rangeLogsTestDone, 0, 0) // test case #2 newFilter(400, int64(rpc.LatestBlockNumber)) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 501, 700}) + expEvent(rangeLogsTestIndexed, 501, 701) if _, err := bc.InsertChain(chain[700:800]); err != nil { t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 501, 700}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 601, 698}) - expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 600}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 698}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 698}) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 699, 800}) - if err := bc.SetHead(750); err != nil { + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 601, 699) + expEvent(rangeLogsTestResults, 601, 699) + expEvent(rangeLogsTestUnindexed, 400, 601) + expEvent(rangeLogsTestResults, 400, 699) + expEvent(rangeLogsTestIndexed, 699, 801) + if _, err := bc.SetCanonical(chain[749]); err != nil { // set head to block 750 t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 800}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 748}) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 749, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 601, 749) + expEvent(rangeLogsTestResults, 400, 749) + expEvent(rangeLogsTestIndexed, 749, 751) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 751) + expEvent(rangeLogsTestResults, 400, 751) + expEvent(rangeLogsTestDone, 0, 0) // test case #3 newFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber)) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750}) - if err := bc.SetHead(740); err != nil { + expEvent(rangeLogsTestIndexed, 750, 751) + if _, err := bc.SetCanonical(chain[739]); err != nil { t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 740, 740}) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 739) + expEvent(rangeLogsTestResults, 0, 0) + expEvent(rangeLogsTestIndexed, 740, 741) if _, err := bc.InsertChain(chain[740:750]); err != nil { t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 740, 740}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 750, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 750, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 750, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestDone, 0, 0}) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 739) + expEvent(rangeLogsTestResults, 0, 0) + expEvent(rangeLogsTestIndexed, 750, 751) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 751) + expEvent(rangeLogsTestResults, 750, 751) + expEvent(rangeLogsTestDone, 0, 0) // test case #4 + if _, err := bc.SetCanonical(chain[499]); err != nil { + t.Fatal(err) + } + updateHead() newFilter(400, int64(rpc.LatestBlockNumber)) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 551, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 551, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 551, 750}) - expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 550}) + expEvent(rangeLogsTestIndexed, 400, 501) + if _, err := bc.InsertChain(chain[500:650]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 451, 499) + expEvent(rangeLogsTestResults, 451, 499) + expEvent(rangeLogsTestUnindexed, 400, 451) + expEvent(rangeLogsTestResults, 400, 499) + // indexed head extension seems possible + expEvent(rangeLogsTestIndexed, 499, 651) + // further head extension causes tail unindexing in searched range + if _, err := bc.InsertChain(chain[650:750]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 649) + // tail trimmed to 551; cannot merge with existing results + expEvent(rangeLogsTestResults, 551, 649) + expEvent(rangeLogsTestUnindexed, 400, 551) + expEvent(rangeLogsTestResults, 400, 649) + expEvent(rangeLogsTestIndexed, 649, 751) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 751) + expEvent(rangeLogsTestResults, 400, 751) + expEvent(rangeLogsTestDone, 0, 0) + + // test case #5 + newFilter(400, int64(rpc.LatestBlockNumber)) + expEvent(rangeLogsTestIndexed, 551, 751) + expEvent(rangeLogsTestSync, 0, 0) + expEvent(rangeLogsTestSynced, 551, 751) + expEvent(rangeLogsTestResults, 551, 751) + expEvent(rangeLogsTestUnindexed, 400, 551) if _, err := bc.InsertChain(chain[750:1000]); err != nil { t.Fatal(err) } updateHead() - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 750}) - // indexed range affected by tail pruning so we have to discard the entire - // match set - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 0, 0}) - expEvent(rangeLogsTestEvent{rangeLogsTestIndexed, 801, 1000}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 801, 1000}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 801, 1000}) - expEvent(rangeLogsTestEvent{rangeLogsTestUnindexed, 400, 800}) - expEvent(rangeLogsTestEvent{rangeLogsTestSync, 400, 1000}) - expEvent(rangeLogsTestEvent{rangeLogsTestTrimmed, 400, 1000}) + expEvent(rangeLogsTestResults, 400, 751) + // indexed tail already beyond results head; revert to unindexed head search + expEvent(rangeLogsTestUnindexed, 751, 1001) + if _, err := bc.SetCanonical(chain[899]); err != nil { + t.Fatal(err) + } + updateHead() + expEvent(rangeLogsTestResults, 400, 1001) + expEvent(rangeLogsTestReorg, 400, 901) + expEvent(rangeLogsTestDone, 0, 0) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 69822c1b4..1464eba42 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -637,6 +637,9 @@ func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { panic("implement me") } +func (b testBackend) CurrentView() *filtermaps.ChainView { + panic("implement me") +} func (b testBackend) NewMatcherBackend() filtermaps.MatcherBackend { panic("implement me") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 19f6028ac..9b48c3dcf 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -98,6 +98,7 @@ type Backend interface { SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription + CurrentView() *filtermaps.ChainView NewMatcherBackend() filtermaps.MatcherBackend } diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index fea99359a..424b746ab 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -414,6 +414,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) func (b *backendMock) Engine() consensus.Engine { return nil } +func (b *backendMock) CurrentView() *filtermaps.ChainView { return nil } func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil } func (b *backendMock) HistoryPruningCutoff() uint64 { return 0 } From af1147b4b1032dafd483b88402695b7225ef78ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Sun, 20 Apr 2025 12:54:40 +0200 Subject: [PATCH 312/354] beacon/params, core/filtermaps: update checkpoints (#31674) This PR updates checkpoints for blsync and filtermaps. --- beacon/params/checkpoint_holesky.hex | 2 +- beacon/params/checkpoint_mainnet.hex | 2 +- beacon/params/checkpoint_sepolia.hex | 2 +- core/filtermaps/checkpoints_holesky.json | 3 ++- core/filtermaps/checkpoints_mainnet.json | 9 ++++++++- core/filtermaps/checkpoints_sepolia.json | 6 +++++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/beacon/params/checkpoint_holesky.hex b/beacon/params/checkpoint_holesky.hex index f1e27b48f..740d7aba2 100644 --- a/beacon/params/checkpoint_holesky.hex +++ b/beacon/params/checkpoint_holesky.hex @@ -1 +1 @@ -0xf5606a019f0f1006e9ec2070695045f4334450362a48da4c5965314510e0b4c3 \ No newline at end of file +0xd60e5310c5d52ced44cfb13be4e9f22a1e6a6dc56964c3cccd429182d26d72d0 \ No newline at end of file diff --git a/beacon/params/checkpoint_mainnet.hex b/beacon/params/checkpoint_mainnet.hex index a11c3394b..45f065ca1 100644 --- a/beacon/params/checkpoint_mainnet.hex +++ b/beacon/params/checkpoint_mainnet.hex @@ -1 +1 @@ -0x3c0cb4aa83beded1803d262664ba4392b1023f334d9cca02dc3a6925987ebe91 \ No newline at end of file +0x02f0bb348b0d45f95a9b7e2bb5705768ad06548876cee03d880a2c9dabb1ff88 \ No newline at end of file diff --git a/beacon/params/checkpoint_sepolia.hex b/beacon/params/checkpoint_sepolia.hex index e4f2f9673..3d1b2885b 100644 --- a/beacon/params/checkpoint_sepolia.hex +++ b/beacon/params/checkpoint_sepolia.hex @@ -1 +1 @@ -0xa8d56457aa414523d93659aef1f7409bbfb72ad75e94d917c8c0b1baa38153ef \ No newline at end of file +0xa0dad451a230c01be6f2492980ec5bb412d8cf33351a75e8b172b5b84a5fd03a \ No newline at end of file diff --git a/core/filtermaps/checkpoints_holesky.json b/core/filtermaps/checkpoints_holesky.json index b8f6be9ca..a56611cc8 100644 --- a/core/filtermaps/checkpoints_holesky.json +++ b/core/filtermaps/checkpoints_holesky.json @@ -17,5 +17,6 @@ {"blockNumber": 3101669, "blockId": "0xa6e66a18fed64d33178c7088f273c404be597662c34f6e6884cf2e24f3ea4ace", "firstIndex": 1073741353}, {"blockNumber": 3221725, "blockId": "0xe771f897dece48b1583cc1d1d10de8015da57407eb1fdf239fdbe46eaab85143", "firstIndex": 1140850137}, {"blockNumber": 3357164, "blockId": "0x6252d0aa54c79623b0680069c88d7b5c47983f0d5c4845b6c811b8d9b5e8ff3c", "firstIndex": 1207959453}, -{"blockNumber": 3447019, "blockId": "0xeb7d585e1e063f3cc05ed399fbf6c2df63c271f62f030acb804e9fb1e74b6dc1", "firstIndex": 1275067542} +{"blockNumber": 3447019, "blockId": "0xeb7d585e1e063f3cc05ed399fbf6c2df63c271f62f030acb804e9fb1e74b6dc1", "firstIndex": 1275067542}, +{"blockNumber": 3546397, "blockId": "0xdabdef7defa4281180a57c5af121877b82274f15ccf074ea0096146f4c246df2", "firstIndex": 1342176778} ] diff --git a/core/filtermaps/checkpoints_mainnet.json b/core/filtermaps/checkpoints_mainnet.json index ca30280e0..70a08b1aa 100644 --- a/core/filtermaps/checkpoints_mainnet.json +++ b/core/filtermaps/checkpoints_mainnet.json @@ -260,5 +260,12 @@ {"blockNumber": 21959188, "blockId": "0x6b9c482cc4822af2ad62a359b923062556ab6a046d1a39a8243b764848690601", "firstIndex": 17381193886}, {"blockNumber": 21994911, "blockId": "0x0d99ef9dd42dd1c62fc5249eb4f618e7672ab93fa0ba7545c77360371cf972e5", "firstIndex": 17448302795}, {"blockNumber": 22026007, "blockId": "0xf7cdc7f6694f2c2ed31fa8a607f65cfa59d0dd7d7424ab5c017f959ae2982c71", "firstIndex": 17515413036}, -{"blockNumber": 22059890, "blockId": "0x82b768a0dddefda2eefd3a33596ea2be075312f1dd4b01f6b0d377faca2af98b", "firstIndex": 17582521768} +{"blockNumber": 22059890, "blockId": "0x82b768a0dddefda2eefd3a33596ea2be075312f1dd4b01f6b0d377faca2af98b", "firstIndex": 17582521768}, +{"blockNumber": 22090784, "blockId": "0xf97c2eaf9a550360ac24000c0ff17ffa388a2bdd6f73f2f36718e332edfa107a", "firstIndex": 17649630983}, +{"blockNumber": 22121157, "blockId": "0xa790025235db782e899f23d8b09663ec2d74ec149e4125d62989f98829b08e2d", "firstIndex": 17716724973}, +{"blockNumber": 22148056, "blockId": "0xbe25ac4f1bdd89a7db5782bf1157e6c4378d80220d67a029397853ef16cd1a4c", "firstIndex": 17783838366}, +{"blockNumber": 22168652, "blockId": "0x6ae43618c915e636794e2cc2d75dde9992766881c7405fe6479c045ed4bee57e", "firstIndex": 17850956277}, +{"blockNumber": 22190975, "blockId": "0x9437121647899a4b7b84d67fbea7cc6ff967481c2eab4328ccd86e2cefe19420", "firstIndex": 17918066140}, +{"blockNumber": 22234357, "blockId": "0x036030830134f9224160d5a0b62da35ec7813dc8855d554bd22e9d38545243ed", "firstIndex": 17985175075}, +{"blockNumber": 22276736, "blockId": "0x5ceb96d98aa1b4c1c2f2fa253ae9cdb1b04e0420c11bf795400e8762c0a1635c", "firstIndex": 18052284344} ] diff --git a/core/filtermaps/checkpoints_sepolia.json b/core/filtermaps/checkpoints_sepolia.json index c6d3cd908..8d799daef 100644 --- a/core/filtermaps/checkpoints_sepolia.json +++ b/core/filtermaps/checkpoints_sepolia.json @@ -64,5 +64,9 @@ {"blockNumber": 7730079, "blockId": "0x08e0d511a93e2a9c004b3456d77d687ae86247417ada1cdd1f85332a62dfed1d", "firstIndex": 4227846795}, {"blockNumber": 7777515, "blockId": "0xeba8faed2e12bb9ed5e7fad19dd82662f15f6f4f512a0d232eedf1e676712428", "firstIndex": 4294966082}, {"blockNumber": 7828860, "blockId": "0x62c054bd24be351dc4777460ee922a75fdcea5c9830455cbac6fa29552719c85", "firstIndex": 4362076087}, -{"blockNumber": 7869890, "blockId": "0x5664bcfa6151f798781e22bea4f9a2c796d097402350cb131e4e3c78e13e461a", "firstIndex": 4429183267} +{"blockNumber": 7869890, "blockId": "0x5664bcfa6151f798781e22bea4f9a2c796d097402350cb131e4e3c78e13e461a", "firstIndex": 4429183267}, +{"blockNumber": 7911722, "blockId": "0x9a85e48e3135c97c51fc1786f2af0596c802e021b6c53cfca65a129cafcd23ed", "firstIndex": 4496287265}, +{"blockNumber": 7960147, "blockId": "0xc9359cc76d7090e1c8a031108f0ab7a8935d971efd4325fe53612a1d99562f6f", "firstIndex": 4563402388}, +{"blockNumber": 8030418, "blockId": "0x21867e68cd8327aed2da2601399d60f7f9e41dca4a4f2f9be982e5a2b9304a88", "firstIndex": 4630511616}, +{"blockNumber": 8087701, "blockId": "0x0fa8c8d7549cc9a8d308262706fe248efe759f8b63511efb1e7f3926e9af2dcb", "firstIndex": 4697614758} ] From c229d23b1dfbeba99c16a2c4ba2226bcbdbadf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 21 Apr 2025 09:27:24 +0200 Subject: [PATCH 313/354] core/filtermaps: clone cached slices, fix tempRange (#31680) This PR ensures that caching a slice or a slice of slices will never affect the original version by always cloning a slice fetched from cache if it is not used in a guaranteed read only way. --- core/filtermaps/filtermaps.go | 9 ++++-- core/filtermaps/indexer.go | 3 ++ core/filtermaps/indexer_test.go | 52 +++++++++++++++++++++++++++++++++ core/filtermaps/map_renderer.go | 6 ++-- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index a617de896..920167ca8 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -128,6 +128,7 @@ type FilterMaps struct { // test hooks testDisableSnapshots, testSnapshotUsed bool + testProcessEventsHook func() } // filterMap is a full or partial in-memory representation of a filter map where @@ -573,7 +574,7 @@ func (f *FilterMaps) getFilterMapRow(mapIndex, rowIndex uint32, baseLayerOnly bo } f.baseRowsCache.Add(baseMapRowIndex, baseRows) } - baseRow := baseRows[mapIndex&(f.baseRowGroupLength-1)] + baseRow := slices.Clone(baseRows[mapIndex&(f.baseRowGroupLength-1)]) if baseLayerOnly { return baseRow, nil } @@ -610,7 +611,9 @@ func (f *FilterMaps) storeFilterMapRowsOfGroup(batch ethdb.Batch, mapIndices []u if uint32(len(mapIndices)) != f.baseRowGroupLength { // skip base rows read if all rows are replaced var ok bool baseRows, ok = f.baseRowsCache.Get(baseMapRowIndex) - if !ok { + if ok { + baseRows = slices.Clone(baseRows) + } else { var err error baseRows, err = rawdb.ReadFilterMapBaseRows(f.db, baseMapRowIndex, f.baseRowGroupLength, f.logMapWidth) if err != nil { @@ -656,7 +659,7 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 { // called from outside the indexerLoop goroutine. func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) { if blockNumber >= f.indexedRange.blocks.AfterLast() && f.indexedRange.headIndexed { - return f.indexedRange.headDelimiter, nil + return f.indexedRange.headDelimiter + 1, nil } if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok { return lvPointer, nil diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 383ec078c..787197345 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -165,6 +165,9 @@ func (f *FilterMaps) waitForNewHead() { // processEvents processes all events, blocking only if a block processing is // happening and indexing should be suspended. func (f *FilterMaps) processEvents() { + if f.testProcessEventsHook != nil { + f.testProcessEventsHook() + } for f.processSingleEvent(f.blockProcessing) { } } diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go index 4dddd2708..e60130ba4 100644 --- a/core/filtermaps/indexer_test.go +++ b/core/filtermaps/indexer_test.go @@ -219,6 +219,58 @@ func testIndexerMatcherView(t *testing.T, concurrentRead bool) { } } +func TestLogsByIndex(t *testing.T) { + ts := newTestSetup(t) + defer func() { + ts.fm.testProcessEventsHook = nil + ts.close() + }() + + ts.chain.addBlocks(1000, 10, 3, 4, true) + ts.setHistory(0, false) + ts.fm.WaitIdle() + firstLog := make([]uint64, 1001) // first valid log position per block + lastLog := make([]uint64, 1001) // last valid log position per block + for i := uint64(0); i <= ts.fm.indexedRange.headDelimiter; i++ { + log, err := ts.fm.getLogByLvIndex(i) + if err != nil { + t.Fatalf("Error getting log by index %d: %v", i, err) + } + if log != nil { + if firstLog[log.BlockNumber] == 0 { + firstLog[log.BlockNumber] = i + } + lastLog[log.BlockNumber] = i + } + } + var failed bool + ts.fm.testProcessEventsHook = func() { + if ts.fm.indexedRange.blocks.IsEmpty() { + return + } + if lvi := firstLog[ts.fm.indexedRange.blocks.First()]; lvi != 0 { + log, err := ts.fm.getLogByLvIndex(lvi) + if log == nil || err != nil { + t.Errorf("Error getting first log of indexed block range: %v", err) + failed = true + } + } + if lvi := lastLog[ts.fm.indexedRange.blocks.Last()]; lvi != 0 { + log, err := ts.fm.getLogByLvIndex(lvi) + if log == nil || err != nil { + t.Errorf("Error getting last log of indexed block range: %v", err) + failed = true + } + } + } + chain := ts.chain.getCanonicalChain() + for i := 0; i < 1000 && !failed; i++ { + head := rand.Intn(len(chain)) + ts.chain.setCanonicalChain(chain[:head+1]) + ts.fm.WaitIdle() + } +} + func TestIndexerCompareDb(t *testing.T) { ts := newTestSetup(t) defer ts.close() diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 7c2aa8dc3..f59a01c03 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "math" + "slices" "sort" "time" @@ -107,7 +108,7 @@ func (f *FilterMaps) renderMapsFromSnapshot(cp *renderedMap) (*mapRenderer, erro filterMap: cp.filterMap.fullCopy(), mapIndex: cp.mapIndex, lastBlock: cp.lastBlock, - blockLvPtrs: cp.blockLvPtrs, + blockLvPtrs: slices.Clone(cp.blockLvPtrs), }, finishedMaps: make(map[uint32]*renderedMap), finished: common.NewRange(cp.mapIndex, 0), @@ -244,7 +245,7 @@ func (f *FilterMaps) loadHeadSnapshot() error { } } f.renderSnapshots.Add(f.indexedRange.blocks.Last(), &renderedMap{ - filterMap: fm, + filterMap: fm.fullCopy(), mapIndex: f.indexedRange.maps.Last(), lastBlock: f.indexedRange.blocks.Last(), lastBlockId: f.indexedView.BlockId(f.indexedRange.blocks.Last()), @@ -536,6 +537,7 @@ func (r *mapRenderer) getTempRange() (filterMapsRange, error) { } else { tempRange.blocks.SetAfterLast(0) } + tempRange.headIndexed = false tempRange.headDelimiter = 0 } return tempRange, nil From d30c1386ffa8468025e694e1f795a59509ac4603 Mon Sep 17 00:00:00 2001 From: georgehao Date: Tue, 22 Apr 2025 12:57:17 +0800 Subject: [PATCH 314/354] internal/debug: add debug_setMemoryLimit (#31441) --- internal/debug/api.go | 19 +++++++++++++++++++ internal/web3ext/web3ext.go | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/internal/debug/api.go b/internal/debug/api.go index 5e93585bf..1bac36e90 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -35,6 +35,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/hashicorp/go-bexpr" ) @@ -237,6 +238,24 @@ func (*HandlerT) SetGCPercent(v int) int { return debug.SetGCPercent(v) } +// SetMemoryLimit sets the GOMEMLIMIT for the process. It returns the previous limit. +// Note: +// +// - The input limit is provided as bytes. A negative input does not adjust the limit +// +// - A zero limit or a limit that's lower than the amount of memory used by the Go +// runtime may cause the garbage collector to run nearly continuously. However, +// the application may still make progress. +// +// - Setting the limit too low will cause Geth to become unresponsive. +// +// - Geth also allocates memory off-heap, particularly for fastCache and Pebble, +// which can be non-trivial (a few gigabytes by default). +func (*HandlerT) SetMemoryLimit(limit int64) int64 { + log.Info("Setting memory limit", "size", common.PrettyDuration(limit)) + return debug.SetMemoryLimit(limit) +} + func writeProfile(name, file string) error { p := pprof.Lookup(name) log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 10984cc7b..fb627a79e 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -316,6 +316,11 @@ web3._extend({ call: 'debug_setGCPercent', params: 1, }), + new web3._extend.Method({ + name: 'setMemoryLimit', + call: 'debug_setMemoryLimit', + params: 1, + }), new web3._extend.Method({ name: 'memStats', call: 'debug_memStats', From 34dcd239ab8c5661022095bae098fe81b7e1a6e3 Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Thu, 24 Apr 2025 03:01:03 +0800 Subject: [PATCH 315/354] ethclient: allow passing AuthorizationList to calls (#31198) This PR adds the `AuthorizationList` field to the `CallMsg` interface to support `eth_call` and `eth_estimateGas` of set-code transactions. --------- Co-authored-by: Sina Mahmoodi --- core/blockchain_test.go | 2 +- core/state_processor_test.go | 3 +- ethclient/ethclient.go | 3 ++ ethclient/gethclient/gethclient.go | 3 ++ interfaces.go | 3 ++ internal/ethapi/api_test.go | 51 +++++++++++++++++++++++++++++- 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 7c880c19a..a113c2bf8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4154,7 +4154,7 @@ func TestEIP7702(t *testing.T) { // The way the auths are combined, it becomes // 1. tx -> addr1 which is delegated to 0xaaaa // 2. addr1:0xaaaa calls into addr2:0xbbbb - // 3. addr2:0xbbbb writes to storage + // 3. addr2:0xbbbb writes to storage auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{ ChainID: *uint256.MustFromBig(gspec.Config.ChainID), Address: aa, diff --git a/core/state_processor_test.go b/core/state_processor_test.go index d08f5e1c9..384cc812a 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -255,7 +255,8 @@ func TestStateProcessorErrors(t *testing.T) { }, want: "could not apply tx 0 [0xc18d10f4c809dbdfa1a074c3300de9bc4b7f16a20f0ec667f6f67312b71b956a]: EIP-7702 transaction with empty auth list (sender 0x71562b71999873DB5b286dF957af199Ec94617F7)", }, - // ErrSetCodeTxCreate cannot be tested: it is impossible to create a SetCode-tx with nil `to`. + // ErrSetCodeTxCreate cannot be tested here: it is impossible to create a SetCode-tx with nil `to`. + // The EstimateGas API tests test this case. } { block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config, false) _, err := blockchain.InsertChain(types.Blocks{block}) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index ae1fd22a4..80f06e82d 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -773,6 +773,9 @@ func toCallArg(msg ethereum.CallMsg) interface{} { if msg.BlobHashes != nil { arg["blobVersionedHashes"] = msg.BlobHashes } + if msg.AuthorizationList != nil { + arg["authorizationList"] = msg.AuthorizationList + } return arg } diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 02b2598b3..39ac4ff20 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -251,6 +251,9 @@ func toCallArg(msg ethereum.CallMsg) interface{} { if msg.BlobHashes != nil { arg["blobVersionedHashes"] = msg.BlobHashes } + if msg.AuthorizationList != nil { + arg["authorizationList"] = msg.AuthorizationList + } return arg } diff --git a/interfaces.go b/interfaces.go index 53e2e3ae1..54a215d6e 100644 --- a/interfaces.go +++ b/interfaces.go @@ -156,6 +156,9 @@ type CallMsg struct { // For BlobTxType BlobGasFeeCap *big.Int BlobHashes []common.Hash + + // For SetCodeTxType + AuthorizationList []types.SetCodeAuthorization } // A ContractCaller provides contract calls, essentially transactions that are executed by diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 1464eba42..76fba32e4 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -686,6 +686,11 @@ func TestEstimateGas(t *testing.T) { b.SetPoS() })) + setCodeAuthorization, _ := types.SignSetCode(accounts[0].key, types.SetCodeAuthorization{ + Address: accounts[0].addr, + Nonce: uint64(genBlocks + 1), + }) + var testSuite = []struct { blockNumber rpc.BlockNumber call TransactionArgs @@ -864,6 +869,50 @@ func TestEstimateGas(t *testing.T) { }, want: 21000, }, + // Should be able to estimate SetCodeTx. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(0)), + AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, + }, + want: 46000, + }, + // Should retrieve the code of 0xef0001 || accounts[0].addr and return an invalid opcode error. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &accounts[0].addr, + Value: (*hexutil.Big)(big.NewInt(0)), + AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, + }, + expectErr: errors.New("invalid opcode: opcode 0xef not defined"), + }, + // SetCodeTx with empty authorization list should fail. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: &common.Address{}, + Value: (*hexutil.Big)(big.NewInt(0)), + AuthorizationList: []types.SetCodeAuthorization{}, + }, + expectErr: core.ErrEmptyAuthList, + }, + // SetCodeTx with nil `to` should fail. + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &accounts[0].addr, + To: nil, + Value: (*hexutil.Big)(big.NewInt(0)), + AuthorizationList: []types.SetCodeAuthorization{setCodeAuthorization}, + }, + expectErr: core.ErrSetCodeTxCreate, + }, } for i, tc := range testSuite { result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) @@ -873,7 +922,7 @@ func TestEstimateGas(t *testing.T) { continue } if !errors.Is(err, tc.expectErr) { - if !reflect.DeepEqual(err, tc.expectErr) { + if err.Error() != tc.expectErr.Error() { t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) } } From 8935c543188dcc1e2f6e6c7e6e6631d6e3ac4859 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 24 Apr 2025 18:19:10 +0200 Subject: [PATCH 316/354] miner: increase default gas limit to 36M (#31705) --- miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/miner.go b/miner/miner.go index 3229d8eb0..48c19657f 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -55,7 +55,7 @@ type Config struct { // DefaultConfig contains default settings for miner. var DefaultConfig = Config{ - GasCeil: 30_000_000, + GasCeil: 36_000_000, GasPrice: big.NewInt(params.GWei), // The default recommit time is chosen as two seconds since From 38042532a6f95135a06eb8d65542d47be9293f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Thu, 24 Apr 2025 21:40:12 +0200 Subject: [PATCH 317/354] beacon/params: add mainnet electra config (#31706) This PR adds the electra beacon chain configuration for mainnet. --- beacon/params/networks.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beacon/params/networks.go b/beacon/params/networks.go index 7e73a2c69..51f67e0c9 100644 --- a/beacon/params/networks.go +++ b/beacon/params/networks.go @@ -41,7 +41,8 @@ var ( AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}). AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}). AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}). - AddFork("DENEB", 269568, []byte{4, 0, 0, 0}) + AddFork("DENEB", 269568, []byte{4, 0, 0, 0}). + AddFork("ELECTRA", 364032, []byte{5, 0, 0, 0}) SepoliaLightConfig = (&ChainConfig{ GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"), From 6588837dc9d729432ce5d5bd11591ac7e14075ca Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 25 Apr 2025 17:57:38 +0800 Subject: [PATCH 318/354] core/filtermaps: fix deadlock in filtermap callback (#31708) This PR fixes a deadlock situation is deleteTailEpoch that might arise when range delete is running in iterator based fallback mode (either using leveldb database or the hashdb state storage scheme). In this case a stopCb callback is called periodically that does check events, including matcher sync requests, in which case it tries to acquire indexLock for read access, while deleteTailEpoch already held it for write access. This pull request removes the indexLock acquiring in `FilterMapsMatcherBackend.synced` as this function is only called in the indexLoop. Fixes https://github.com/ethereum/go-ethereum/issues/31700 --- core/filtermaps/filtermaps.go | 50 ++++++++++++++++++++---------- core/filtermaps/indexer.go | 6 +++- core/filtermaps/matcher_backend.go | 18 +++++++---- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index 920167ca8..3da7f4b72 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -85,11 +85,17 @@ type FilterMaps struct { // fields written by the indexer and read by matcher backend. Indexer can // read them without a lock and write them under indexLock write lock. // Matcher backend can read them under indexLock read lock. - indexLock sync.RWMutex - indexedRange filterMapsRange - cleanedEpochsBefore uint32 // all unindexed data cleaned before this point - indexedView *ChainView // always consistent with the log index - hasTempRange bool + indexLock sync.RWMutex + indexedRange filterMapsRange + indexedView *ChainView // always consistent with the log index + hasTempRange bool + + // cleanedEpochsBefore indicates that all unindexed data before this point + // has been cleaned. + // + // This field is only accessed and modified within tryUnindexTail, so no + // explicit locking is required. + cleanedEpochsBefore uint32 // also accessed by indexer and matcher backend but no locking needed. filterMapCache *lru.Cache[uint32, filterMap] @@ -248,15 +254,16 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f }, // deleting last unindexed epoch might have been interrupted by shutdown cleanedEpochsBefore: max(rs.MapsFirst>>params.logMapsPerEpoch, 1) - 1, - historyCutoff: historyCutoff, - finalBlock: finalBlock, - matcherSyncCh: make(chan *FilterMapsMatcherBackend), - matchers: make(map[*FilterMapsMatcherBackend]struct{}), - filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), - lastBlockCache: lru.NewCache[uint32, lastBlockOfMap](cachedLastBlocks), - lvPointerCache: lru.NewCache[uint64, uint64](cachedLvPointers), - baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), - renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), + + historyCutoff: historyCutoff, + finalBlock: finalBlock, + matcherSyncCh: make(chan *FilterMapsMatcherBackend), + matchers: make(map[*FilterMapsMatcherBackend]struct{}), + filterMapCache: lru.NewCache[uint32, filterMap](cachedFilterMaps), + lastBlockCache: lru.NewCache[uint32, lastBlockOfMap](cachedLastBlocks), + lvPointerCache: lru.NewCache[uint64, uint64](cachedLvPointers), + baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), + renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), } // Set initial indexer target. @@ -444,6 +451,7 @@ func (f *FilterMaps) safeDeleteWithLogs(deleteFn func(db ethdb.KeyValueStore, ha // setRange updates the indexed chain view and covered range and also adds the // changes to the given batch. +// // Note that this function assumes that the index write lock is being held. func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, newRange filterMapsRange, isTempRange bool) { f.indexedView = newView @@ -477,6 +485,7 @@ func (f *FilterMaps) setRange(batch ethdb.KeyValueWriter, newView *ChainView, ne // Note that this function assumes that the log index structure is consistent // with the canonical chain at the point where the given log value index points. // If this is not the case then an invalid result or an error may be returned. +// // Note that this function assumes that the indexer read lock is being held when // called from outside the indexerLoop goroutine. func (f *FilterMaps) getLogByLvIndex(lvIndex uint64) (*types.Log, error) { @@ -655,6 +664,7 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 { // getBlockLvPointer returns the starting log value index where the log values // generated by the given block are located. If blockNumber is beyond the current // head then the first unoccupied log value index is returned. +// // Note that this function assumes that the indexer read lock is being held when // called from outside the indexerLoop goroutine. func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) { @@ -762,7 +772,7 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) { return false, errors.New("invalid tail epoch number") } // remove index data - if err := f.safeDeleteWithLogs(func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error { + deleteFn := func(db ethdb.KeyValueStore, hashScheme bool, stopCb func(bool) bool) error { first := f.mapRowIndex(firstMap, 0) count := f.mapRowIndex(firstMap+f.mapsPerEpoch, 0) - first if err := rawdb.DeleteFilterMapRows(f.db, common.NewRange(first, count), hashScheme, stopCb); err != nil { @@ -786,10 +796,13 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) { f.lvPointerCache.Remove(blockNumber) } return nil - }, fmt.Sprintf("Deleting tail epoch #%d", epoch), func() bool { + } + action := fmt.Sprintf("Deleting tail epoch #%d", epoch) + stopFn := func() bool { f.processEvents() return f.stop || !f.targetHeadIndexed() - }); err == nil { + } + if err := f.safeDeleteWithLogs(deleteFn, action, stopFn); err == nil { // everything removed; mark as cleaned and report success if f.cleanedEpochsBefore == epoch { f.cleanedEpochsBefore = epoch + 1 @@ -808,6 +821,9 @@ func (f *FilterMaps) deleteTailEpoch(epoch uint32) (bool, error) { } // exportCheckpoints exports epoch checkpoints in the format used by checkpoints.go. +// +// Note: acquiring the indexLock read lock is unnecessary here, as this function +// is always called within the indexLoop. func (f *FilterMaps) exportCheckpoints() { finalLvPtr, err := f.getBlockLvPointer(f.finalBlock + 1) if err != nil { diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 787197345..3ec49ca11 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -43,6 +43,8 @@ func (f *FilterMaps) indexerLoop() { log.Info("Started log indexer") for !f.stop { + // Note: acquiring the indexLock read lock is unnecessary here, + // as the `indexedRange` is accessed within the indexerLoop. if !f.indexedRange.initialized { if f.targetView.HeadNumber() == 0 { // initialize when chain head is available @@ -105,7 +107,7 @@ type targetUpdate struct { historyCutoff, finalBlock uint64 } -// SetTargetView sets a new target chain view for the indexer to render. +// SetTarget sets a new target chain view for the indexer to render. // Note that SetTargetView never blocks. func (f *FilterMaps) SetTarget(targetView *ChainView, historyCutoff, finalBlock uint64) { if targetView == nil { @@ -178,6 +180,8 @@ func (f *FilterMaps) processSingleEvent(blocking bool) bool { if f.stop { return false } + // Note: acquiring the indexLock read lock is unnecessary here, + // as this function is always called within the indexLoop. if !f.hasTempRange { for _, mb := range f.matcherSyncRequests { mb.synced() diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index ee18a0694..975178375 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -111,17 +111,17 @@ func (fm *FilterMapsMatcherBackend) GetLogByLvIndex(ctx context.Context, lvIndex // synced signals to the matcher that has triggered a synchronisation that it // has been finished and the log index is consistent with the chain head passed // as a parameter. +// // Note that if the log index head was far behind the chain head then it might not // be synced up to the given head in a single step. Still, the latest chain head // should be passed as a parameter and the existing log index should be consistent // with that chain. +// +// Note: acquiring the indexLock read lock is unnecessary here, as this function +// is always called within the indexLoop. func (fm *FilterMapsMatcherBackend) synced() { - fm.f.indexLock.RLock() fm.f.matchersLock.Lock() - defer func() { - fm.f.matchersLock.Unlock() - fm.f.indexLock.RUnlock() - }() + defer fm.f.matchersLock.Unlock() indexedBlocks := fm.f.indexedRange.blocks if !fm.f.indexedRange.headIndexed && !indexedBlocks.IsEmpty() { @@ -154,6 +154,8 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange case <-ctx.Done(): return SyncRange{}, ctx.Err() case <-fm.f.disabledCh: + // Note: acquiring the indexLock read lock is unnecessary here, + // as the indexer has already been terminated. return SyncRange{IndexedView: fm.f.indexedView}, nil } select { @@ -162,6 +164,8 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange case <-ctx.Done(): return SyncRange{}, ctx.Err() case <-fm.f.disabledCh: + // Note: acquiring the indexLock read lock is unnecessary here, + // as the indexer has already been terminated. return SyncRange{IndexedView: fm.f.indexedView}, nil } } @@ -170,7 +174,9 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange // valid range with the current indexed range. This function should be called // whenever a part of the log index has been removed, before adding new blocks // to it. -// Note that this function assumes that the index read lock is being held. +// +// Note: acquiring the indexLock read lock is unnecessary here, as this function +// is always called within the indexLoop. func (f *FilterMaps) updateMatchersValidRange() { f.matchersLock.Lock() defer f.matchersLock.Unlock() From eb56cb18c99d7a3a8d8b51885c3e20cdd8370320 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 28 Apr 2025 08:26:27 +0200 Subject: [PATCH 319/354] core/txpool/legacypool: refactor truncatePending (#31715) TruncatePending shows up bright red on our nodes, because it computes the length of a map multiple times. I don't know why this is so expensive, but around 20% of our time is spent on this, which is super weird. ``` //PR: BenchmarkTruncatePending-24 17498 69397 ns/op 32872 B/op 3 allocs/op //Master: BenchmarkTruncatePending-24 9960 123954 ns/op 32872 B/op 3 allocs/op ``` ``` benchmark old ns/op new ns/op delta BenchmarkTruncatePending-24 123954 69397 -44.01% benchmark old allocs new allocs delta BenchmarkTruncatePending-24 3 3 +0.00% benchmark old bytes new bytes delta BenchmarkTruncatePending-24 32872 32872 +0.00% ``` This simple PR is a 44% improvement over the old state ``` OUTINE ======================== github.com/ethereum/go-ethereum/core/txpool/legacypool.(*LegacyPool).truncatePending in github.com/ethereum/go-ethereum/core/txpool/legacypool/legacypool.go 1.96s 18.02s (flat, cum) 19.57% of Total . . 1495:func (pool *LegacyPool) truncatePending() { . . 1496: pending := uint64(0) 60ms 2.99s 1497: for _, list := range pool.pending { 250ms 5.48s 1498: pending += uint64(list.Len()) . . 1499: } . . 1500: if pending <= pool.config.GlobalSlots { . . 1501: return . . 1502: } . . 1503: . . 1504: pendingBeforeCap := pending . . 1505: // Assemble a spam order to penalize large transactors first . 510ms 1506: spammers := prque.New[int64, common.Address](nil) 140ms 2.50s 1507: for addr, list := range pool.pending { . . 1508: // Only evict transactions from high rollers 50ms 5.08s 1509: if uint64(list.Len()) > pool.config.AccountSlots { . . 1510: spammers.Push(addr, int64(list.Len())) . . 1511: } . . 1512: } . . 1513: // Gradually drop transactions from offenders . . 1514: offenders := []common.Address{} ``` ```go // Benchmarks the speed of batch transaction insertion in case of multiple accounts. func BenchmarkTruncatePending(b *testing.B) { // Generate a batch of transactions to enqueue into the pool pool, _ := setupPool() defer pool.Close() b.ReportAllocs() batches := make(types.Transactions, 4096+1024+1) for i := range len(batches) { key, _ := crypto.GenerateKey() account := crypto.PubkeyToAddress(key.PublicKey) pool.currentState.AddBalance(account, uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) tx := transaction(uint64(0), 100000, key) batches[i] = tx } for _, tx := range batches { pool.addRemotesSync([]*types.Transaction{tx}) } b.ResetTimer() // benchmark truncating the pending for range b.N { pool.truncatePending() } } ``` --- core/txpool/legacypool/legacypool.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 5dbf997ca..92d31e1d9 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1619,22 +1619,22 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T // equal number for all for accounts with many pending transactions. func (pool *LegacyPool) truncatePending() { pending := uint64(0) - for _, list := range pool.pending { - pending += uint64(list.Len()) - } - if pending <= pool.config.GlobalSlots { - return - } - pendingBeforeCap := pending // Assemble a spam order to penalize large transactors first - spammers := prque.New[int64, common.Address](nil) + spammers := prque.New[uint64, common.Address](nil) for addr, list := range pool.pending { // Only evict transactions from high rollers - if uint64(list.Len()) > pool.config.AccountSlots { - spammers.Push(addr, int64(list.Len())) + length := uint64(list.Len()) + pending += length + if length > pool.config.AccountSlots { + spammers.Push(addr, length) } } + if pending <= pool.config.GlobalSlots { + return + } + pendingBeforeCap := pending + // Gradually drop transactions from offenders offenders := []common.Address{} for pending > pool.config.GlobalSlots && !spammers.Empty() { From ddf17334c41455f9cb587fa0b0e9efbfa9378ca4 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Mon, 28 Apr 2025 08:37:02 +0200 Subject: [PATCH 320/354] trie: add edgecase for rangeproof correctness (#31667) This PR adds checking for an edgecase which theoretically can happen in the range-prover. Right now, we check that a key does not overwrite a previous one by checking that the key is increasing. However, if keys are of different lengths, it is possible to create a key which is increasing _and_ overwrites the previous key. Example: `0xaabbcc` followed by `0xaabbccdd`. This can not happen in go-ethereum, which always uses fixed-size paths for accounts and storage slot paths in the trie, but it might happen if the range prover is used without guaranteed fixed-size keys. This PR also adds some testcases for the errors that are expected. --- trie/proof.go | 14 +++++++++++--- trie/proof_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/trie/proof.go b/trie/proof.go index 2e527348b..751d6f620 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -485,10 +485,18 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu if len(keys) != len(values) { return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)) } - // Ensure the received batch is monotonic increasing and contains no deletions + // Ensure the received batch is + // - monotonically increasing, + // - not expanding down prefix-paths + // - and contains no deletions for i := 0; i < len(keys); i++ { - if i < len(keys)-1 && bytes.Compare(keys[i], keys[i+1]) >= 0 { - return false, errors.New("range is not monotonically increasing") + if i < len(keys)-1 { + if bytes.Compare(keys[i], keys[i+1]) >= 0 { + return false, errors.New("range is not monotonically increasing") + } + if bytes.HasPrefix(keys[i+1], keys[i]) { + return false, errors.New("range contains path prefixes") + } } if len(values[i]) == 0 { return false, errors.New("range contains deletion") diff --git a/trie/proof_test.go b/trie/proof_test.go index fab3a9765..b3c9dd753 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -1000,3 +1000,35 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) { t.Error("expected more to be false") } } + +// TestRangeProofErrors tests a few cases where the prover is supposed +// to exit with errors +func TestRangeProofErrors(t *testing.T) { + // Different number of keys to values + _, err := VerifyRangeProof((common.Hash{}), []byte{}, make([][]byte, 5), make([][]byte, 4), nil) + if have, want := err.Error(), "inconsistent proof data, keys: 5, values: 4"; have != want { + t.Fatalf("wrong error, have %q, want %q", err.Error(), want) + } + // Non-increasing paths + _, err = VerifyRangeProof((common.Hash{}), []byte{}, + [][]byte{[]byte{2, 1}, []byte{2, 1}}, make([][]byte, 2), nil) + if have, want := err.Error(), "range is not monotonically increasing"; have != want { + t.Fatalf("wrong error, have %q, want %q", err.Error(), want) + } + // A prefixed path is never motivated. Inserting the second element will + // require rewriting/overwriting the previous value-node, thus can only + // happen if the data is corrupt. + _, err = VerifyRangeProof((common.Hash{}), []byte{}, + [][]byte{[]byte{2, 1}, []byte{2, 1, 2}}, + [][]byte{[]byte{1}, []byte{1}}, nil) + if have, want := err.Error(), "range contains path prefixes"; have != want { + t.Fatalf("wrong error, have %q, want %q", err.Error(), want) + } + // Empty values (deletions) + _, err = VerifyRangeProof((common.Hash{}), []byte{}, + [][]byte{[]byte{2, 1}, []byte{2, 2}}, + [][]byte{[]byte{1}, []byte{}}, nil) + if have, want := err.Error(), "range contains deletion"; have != want { + t.Fatalf("wrong error, have %q, want %q", err.Error(), want) + } +} From 1373ecb080bc7a5adb19d18b0eb887fb4c140b3a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 29 Apr 2025 08:29:56 +0200 Subject: [PATCH 321/354] core: apply overrides to mainnet chainconfig (#31733) This PR applies the config overrides to the new config as well, otherwise they will not be applied to defined configs, making shadowforks impossible. To test: ``` > ./build/bin/geth --override.prague 123 --dev --datadir /tmp/geth INFO [04-28|21:20:47.009] - Prague: @123 > ./build/bin/geth --override.prague 321 --dev --datadir /tmp/geth INFO [04-28|21:23:59.760] - Prague: @321 `` --- core/genesis.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/genesis.go b/core/genesis.go index 48d781f3b..d5bb09a1a 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -367,6 +367,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g return nil, common.Hash{}, nil, errors.New("missing head header") } newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) + if err := overrides.apply(newCfg); err != nil { + return nil, common.Hash{}, nil, err + } // Sanity-check the new configuration. if err := newCfg.CheckConfigForkOrder(); err != nil { From 14fcdea160fe0dd7735c433c688d610efd5c2cf1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 29 Apr 2025 19:21:18 +0800 Subject: [PATCH 322/354] beacon/engine: omit empty witness in payload response (#31739) Fixes https://github.com/ethereum/go-ethereum/issues/31737 --- beacon/engine/types.go | 2 +- eth/catalyst/api.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 984090ef8..3e52933a9 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -131,7 +131,7 @@ type executionPayloadEnvelopeMarshaling struct { type PayloadStatusV1 struct { Status string `json:"status"` - Witness *hexutil.Bytes `json:"witness"` + Witness *hexutil.Bytes `json:"witness,omitempty"` LatestValidHash *common.Hash `json:"latestValidHash"` ValidationError *string `json:"validationError"` } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 45a0ac874..20c6db66f 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -382,8 +382,11 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl } valid := func(id *engine.PayloadID) engine.ForkChoiceResponse { return engine.ForkChoiceResponse{ - PayloadStatus: engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &update.HeadBlockHash}, - PayloadID: id, + PayloadStatus: engine.PayloadStatusV1{ + Status: engine.VALID, + LatestValidHash: &update.HeadBlockHash, + }, + PayloadID: id, } } if rawdb.ReadCanonicalHash(api.eth.ChainDb(), block.NumberU64()) != update.HeadBlockHash { From d0b7e308a22275080400fce6ddfd29c493380891 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 29 Apr 2025 14:42:17 +0200 Subject: [PATCH 323/354] crypto/kzg4844: add ComputeCells functionality (#31378) For PeerDAS, we need to compute cell proofs. Both ckzg and gokzg support computing these cell proofs. This PR does the following: - Update the go-kzg library from "github.com/crate-crypto/go-kzg-4844" to "github.com/crate-crypto/go-eth-kzg" which will be the new upstream for go-kzg moving forward - Update ckzg from v1.0.0 to v2.0.1 and switch to /v2 - Updates the trusted setup to contain the g1 points both in lagrange and monomial form - Expose `ComputeCells` to compute the cell proofs --- cmd/utils/flags.go | 14 +- crypto/kzg4844/kzg4844.go | 11 + crypto/kzg4844/kzg4844_ckzg_cgo.go | 32 +- crypto/kzg4844/kzg4844_ckzg_nocgo.go | 8 + crypto/kzg4844/kzg4844_gokzg.go | 20 +- crypto/kzg4844/trusted_setup.json | 4098 ++++++++++++++++++++++++++ go.mod | 3 +- go.sum | 6 +- 8 files changed, 4180 insertions(+), 12 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 14d09f935..83ec2ae26 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2026,10 +2026,16 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.String(CryptoKZGFlag.Name) != "gokzg" && ctx.String(CryptoKZGFlag.Name) != "ckzg" { Fatalf("--%s flag must be 'gokzg' or 'ckzg'", CryptoKZGFlag.Name) } - log.Info("Initializing the KZG library", "backend", ctx.String(CryptoKZGFlag.Name)) - if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { - Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) - } + // The initialization of the KZG library can take up to 2 seconds + // We start this here in parallel, so it should be available + // once we start executing blocks. It's threadsafe. + go func() { + log.Info("Initializing the KZG library", "backend", ctx.String(CryptoKZGFlag.Name)) + if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { + Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) + } + }() + if ctx.IsSet(CacheNoPrefetchFlag.Name) { cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name) } diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 39fdfbe74..0a2478cea 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -149,6 +149,17 @@ func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { return gokzgVerifyBlobProof(blob, commitment, proof) } +// ComputeCellProofs returns the KZG cell proofs that are used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ComputeCellProofs(blob *Blob) ([]Proof, error) { + if useCKZG.Load() { + return ckzgComputeCellProofs(blob) + } + return gokzgComputeCellProofs(blob) +} + // CalcBlobHashV1 calculates the 'versioned blob hash' of a commitment. // The given hasher must be a sha256 hash instance, otherwise the result will be invalid! func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) { diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index dce592b44..49a7046fe 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -23,8 +23,8 @@ import ( "errors" "sync" - gokzg4844 "github.com/crate-crypto/go-kzg-4844" - ckzg4844 "github.com/ethereum/c-kzg-4844/bindings/go" + gokzg4844 "github.com/crate-crypto/go-eth-kzg" + ckzg4844 "github.com/ethereum/c-kzg-4844/v2/bindings/go" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -47,15 +47,21 @@ func ckzgInit() { if err = gokzg4844.CheckTrustedSetupIsWellFormed(params); err != nil { panic(err) } - g1s := make([]byte, len(params.SetupG1Lagrange)*(len(params.SetupG1Lagrange[0])-2)/2) + g1Lag := make([]byte, len(params.SetupG1Lagrange)*(len(params.SetupG1Lagrange[0])-2)/2) for i, g1 := range params.SetupG1Lagrange { + copy(g1Lag[i*(len(g1)-2)/2:], hexutil.MustDecode(g1)) + } + g1s := make([]byte, len(params.SetupG1Monomial)*(len(params.SetupG1Monomial[0])-2)/2) + for i, g1 := range params.SetupG1Monomial { copy(g1s[i*(len(g1)-2)/2:], hexutil.MustDecode(g1)) } g2s := make([]byte, len(params.SetupG2)*(len(params.SetupG2[0])-2)/2) for i, g2 := range params.SetupG2 { copy(g2s[i*(len(g2)-2)/2:], hexutil.MustDecode(g2)) } - if err = ckzg4844.LoadTrustedSetup(g1s, g2s); err != nil { + // The last parameter determines the multiplication table, see https://notes.ethereum.org/@jtraglia/windowed_multiplications + // I think 6 is an decent compromise between size and speed + if err = ckzg4844.LoadTrustedSetup(g1s, g1Lag, g2s, 6); err != nil { panic(err) } } @@ -125,3 +131,21 @@ func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { } return nil } + +// ckzgComputeCellProofs returns the KZG cell proofs that are used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) { + ckzgIniter.Do(ckzgInit) + + _, proofs, err := ckzg4844.ComputeCellsAndKZGProofs((*ckzg4844.Blob)(blob)) + if err != nil { + return []Proof{}, err + } + var p []Proof + for _, proof := range proofs { + p = append(p, (Proof)(proof)) + } + return p, nil +} diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go index 0662b2632..6f4bd3b82 100644 --- a/crypto/kzg4844/kzg4844_ckzg_nocgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -60,3 +60,11 @@ func ckzgComputeBlobProof(blob *Blob, commitment Commitment) (Proof, error) { func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { panic("unsupported platform") } + +// ckzgComputeCellProofs returns the KZG cell proofs that are used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) { + panic("unsupported platform") +} diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go index b4af9b167..46a38a891 100644 --- a/crypto/kzg4844/kzg4844_gokzg.go +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -20,7 +20,7 @@ import ( "encoding/json" "sync" - gokzg4844 "github.com/crate-crypto/go-kzg-4844" + gokzg4844 "github.com/crate-crypto/go-eth-kzg" ) // context is the crypto primitive pre-seeded with the trusted setup parameters. @@ -96,3 +96,21 @@ func gokzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error return context.VerifyBlobKZGProof((*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) } + +// gokzgComputeCellProofs returns the KZG cell proofs that are used to verify the blob against +// the commitment. +// +// This method does not verify that the commitment is correct with respect to blob. +func gokzgComputeCellProofs(blob *Blob) ([]Proof, error) { + gokzgIniter.Do(gokzgInit) + + _, proofs, err := context.ComputeCellsAndKZGProofs((*gokzg4844.Blob)(blob), 0) + if err != nil { + return []Proof{}, err + } + var p []Proof + for _, proof := range proofs { + p = append(p, (Proof)(proof)) + } + return p, nil +} diff --git a/crypto/kzg4844/trusted_setup.json b/crypto/kzg4844/trusted_setup.json index c6d724efa..6793490e2 100644 --- a/crypto/kzg4844/trusted_setup.json +++ b/crypto/kzg4844/trusted_setup.json @@ -1,4 +1,4102 @@ { + "g1_monomial": [ + "0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", + "0xad3eb50121139aa34db1d545093ac9374ab7bca2c0f3bf28e27c8dcd8fc7cb42d25926fc0c97b336e9f0fb35e5a04c81", + "0x8029c8ce0d2dce761a7f29c2df2290850c85bdfaec2955626d7acc8864aeb01fe16c9e156863dc63b6c22553910e27c1", + "0xb1386c995d3101d10639e49b9e5d39b9a280dcf0f135c2e6c6928bb3ab8309a9da7178f33925768c324f11c3762cfdd5", + "0x9596d929610e6d2ed3502b1bb0f1ea010f6b6605c95d4859f5e53e09fa68dc71dfd5874905447b5ec6cd156a76d6b6e8", + "0x851e3c3d4b5b7cdbba25d72abf9812cf3d7c5a9dbdec42b6635e2add706cbeea18f985afe5247459f6c908620322f434", + "0xb10f4cf8ec6e02491bbe6d9084d88c16306fdaf399fef3cd1453f58a4f7633f80dc60b100f9236c3103eaf727468374f", + "0xade11ec630127e04d17e70db0237d55f2ff2a2094881a483797e8cddb98b622245e1f608e5dcd1172b9870e733b4a32f", + "0xaf58c8a2f58f904ce20db81005331bf2d251e227e7d1bef575d691bdca842e6233eb2e26c2e116a61a78594772b38d25", + "0xb3c1313c31ec82da5a7a09e9cf6656ca598c243345fe8d4828e520ade91787ffb8b9867db789b34ad67cef47b26ff86d", + "0xa8ed8a235355948e0b04be080b7b3e145293accefb4704d1da9050796b2f6870516c1ebf77ae6a65359edcfd016c0f36", + "0x80e792d5ba24b8058f6d7291a2ec5cb68aab1e16e96d793128e86815631baf42c56b6205c19e25ce9727bd1fd6f9defb", + "0x816288c5d726b094e3fdf95cb8882f442c4d9d1101b92c7938a7dfd49bc50636d73ea1b05f75eb731c908c8fd8dee717", + "0xae009128d128ba2e1519bfa7a0c01ed494a7d461c3aba60f8a301701fed61fe4e31d6c79ce189542ae51df91e73ce1b3", + "0x96a866d60a9007d05825c332476a83e869e15b11d7257172a67690ea9bd3efea44bf9c8d42191454eb04fcf110b16396", + "0x8b250a2a06419adb9b611e89f7f8f2990aa301949b533ad3bf17c4a61ab5f5be0b1d5e2b571864d13f1bb75805c7795d", + "0x8450f49facf2e620fa45ee90e1801178842d927a2a25fc6ed7ba99a4eec7ae40eebfee41028eaa84f107f4a777694976", + "0x91049080cf659c0985a22d1366e59191bb89663f922e8168b9b7d85c8a73d74a6d9dceefd855d3d858b493670c750581", + "0xa1e167aeb2008087f3195926f1985c0a459d6ec57237255b1473a96de4e2c1cf766127c862c7dc853a6909e67cb06cf7", + "0xb667c0d4e26e20698b07567358625d5f003839c92de8088e12dbd74a6f6a3156b4ea8d252c9ad62af5f6c4fec1cf6cc7", + "0x8e4b5e304c0b1b161ae3e4b68b5e3ac66c42acd7c1ee2458044f6527c508a93995e50894d72d57c1350f91afe72775ff", + "0x8c642640aa7915421cdc21fd639f88a42052b1cfa358ff7702e60793a92b7b5926dae15a0c8f8f59cd3013f01c159ba3", + "0xa356f35e713cfc283056bf539de54a21731e61efb4c47319f20de4a4b723d76a33b65f4a67d298b9ec5c2a1579418657", + "0x93ce204146ce95f484dc79c27919a16c9e3fc14a9111c6c63d44491158d5838117d20851cc3227a5e8ba6ccf79e77f39", + "0xb585664cbb9a84b52f89114e1cf0cf1171bea78a136dc1404ac88a11210b2debc3b7a55e702da93ff629095c134a295e", + "0xb6dfd444ec7fdceb14c6328f26ca12c3f9fc4327d8d8c68948e92e7e61262b82d833a65a9e3af6353ffa832b6da25705", + "0xb4d4b8eb9ecfffe3f0d48fb4149c7b31aec1da7041ec03bd0750c52a2a7cbc3a7cfbf09d5bfdc56e3860826a62d0bb91", + "0xa4e248e3d61db52da9683fef188579c470d65e2df9064726847b1599fc774049ffdc6ef2ae578d5ed7874f1298ecdf69", + "0xa68a0fffc2e37d3183feb01b42234c0f4e510f9dc29d09c571e6da00fecad9da224cd0f31550070148667e226c4ca413", + "0x86adda2ffecb77236c18005051f31f9657a0d50fef2a1175dfda32e74d5d53df825c10f289eb0ad39df0c64fc9bc7729", + "0x998266d5c9c3764ed97d66fa9ed176af043999652bae19f0657c8328629d30af453230e3681c5a38e2f01e389ed8d825", + "0xa05261554d3c620af0c914cf27ab98f5d3593c33ab313c198e0c40d6c72022eb5943778cd4f73e9fe8383392a7004976", + "0xad243fb3631bf90fedb9d679fd71fc0cf06bda028591ded2bd4c634ea7b3c2bd22eca2ab318fcdaa6c2cda1e63e1c57b", + "0x89b9859a04f903c95e97fb2951f01cc6418a2505eee0b5bc7266b4d33e01b69b9fe7dc56fa9ebb5856095be0925a422d", + "0xa68d118343a5bbfbbab95ff9bfe53aeb7fdbaf16db983e6f4456366df2aa01fbdb6ee9901cb102fc7d2bd099be2f1f3e", + "0xb49301f25d5a9dd2ec60ddb0b4b477291958487efea9e54dc0e4ef388f03b8bbadd13259d191f7a0b7513876767d8282", + "0x8b93df7fb4513f67749905fd43db78f7026589b704ebb9ea3255d0ad6415437799f40f02e07efccda1e6fd5e8cd0a721", + "0xad88769ace96455da37c3c9019a9f523c694643be3f6b37b1e9dcc5053d1fe8e463abebdb1b3ef2f2fb801528a01c47c", + "0x80f0eb5dcbfaaf421bf59a8b9bd5245c4823c94510093e23e0b0534647fb5525a25ea3aeea0a927a1ee20c057f2c9234", + "0xb10ad82ea6a5aeabe345d00eb17910d6942b6862f7f3773c7d321194e67c9cced0b3310425662606634dcd7f8b976c04", + "0x82f6fd91f87822f6cc977808eeac77889f4a32fb0d618e784b2331263d0ffa820b3f70b069d32e0319c9e033ab75d3b4", + "0x9436d3dc6b5e25b1f695f8c6c1c553dab312ccace4dac3afddc141d3506467cd50cb04a49ea96ea7f5a8a7b0fc65ef37", + "0x8e0a9491651d52be8ebf4315fbbb410272f9a74b965d33b79ff1b9e1be3be59e43d9566773560e43280549c348e48f01", + "0x8809137e5d3a22400d6e645a9bd84e21c492371736c7e62c51cef50fee3aa7f2405724367a83fd051ff702d971167f67", + "0xb536a24f31a346de7f9863fc351fa602158404d2f94747eebe43abf1f21bf8f95a64146c02a4bec27b503f546789a388", + "0xb5cdf5a04fc12a0e0ef7545830061dff7fd8abea46e48fbe6235109e6c36ee6bffcb9529e2f3d0d701cf58bbfb6a4197", + "0xab15377525753467d042b7931f66f862cbbb77464212c9aa72d4e5c04375ef55f619b3a446091c1ba1a3b5d9f05e538f", + "0x905a75b943ad017ff78ea6ddd1d28a45c7273ee1c2e5e3353685813793ead3370c09cabd903fcab9d8b1c6961372d486", + "0x8147df4324faddc02fb0896367a7647b719b6499a361aecfdd3a34296fa6768ad31c34f9e873fd1e683386c44651883e", + "0xac91d08570dd91f89d2e01dca67cdc83b640e20f073ea9f0734759c92182bb66c5d645f15ebd91ed705b66486ed2088d", + "0xac6295ef2513bbea7ef4cdcf37d280300c34e63c4b9704663d55891a61bf5c91b04cc1d202a3a0a7c4520c30edc277c7", + "0xb604be776a012095c0d4ebc77797dd8dec62a54c0559fb2185d7bac6b50d4e5fd471ac2d7f4523206d5d8178eabd9a87", + "0x80ead68def272ce3f57951145e71ed6dc26da98e5825ef439af577c0c5de766d4e39207f205d5d21db903d89f37bbb02", + "0x9950b4a830388c897158c7fe3921e2fe24beedc7c84e2024e8b92b9775f8f99593b54a86b8870ec5087734295ba06032", + "0xb89ba714adabf94e658a7d14ac8fc197376a416841c2a80e1a6dde4f438d5f747d1fb90b39e8ea435c59d6ecda13dea1", + "0xb0c78e7cc60bd05be46d48fbb0421a678c7f14b8d93730deb66fbe1647613b2c62b5075126d917047820c57fc3509cb9", + "0xa860c4acc5444e9ae987e8c93cb9a5f17d954d63c060cc616f724e26bc73d2c54cd36e0492d1fde173847278e55942ba", + "0x8fb8269c9d5c15428e8d45da1251e4c4a4b600d47da0caea29fef246854d8fb6acae86a8e6440d0c429d8dd9c2dfee0c", + "0x96c5d8eb6fd5c525b348ee4335d200139e437e4be83690af0f35b7f336a7cda8c6d2958647988b84da9f2dd7bbb7710b", + "0xa7f62141c4346cc14e9823dc38ac7d587b0427022afc1498d12ee2c43f6ac3a82167057e670dd524b74137f8c3ceb56d", + "0x956aac50d06b46a3e94397f163f593f5010d366aa2d816c2205c7d0f47f90cf0f36c169e964f9bcf698d49182d47d91f", + "0xb812899bcdc0e70d79ca729cb01104bf60e1357b9085a10f64f3ba9865d57e9abd0a505a502d4de07afb46f4d266be2f", + "0xabce02c7e1372e25d40944dc9ece2904a8f59c8854c5f2875fe63ace8ce37d97881f4f9ab4f7bad070ec8e0daee58d3f", + "0x8fb13c515b2d6abb4e14ed753fad5cc36c3631dfe21a23d0f603aad719423dd5423157eefcbd9a9c6074e155b79eb38d", + "0xa9ef67304dc297ab5af778cf8afa849eeac27db4b6978963e97b95ef7a8d3264d0d07775f728c298a2b6daed2ecf5053", + "0xa9b975520adb066e2ff2a4cde53284c23bc84261a22dc43b1634d99eff8e7892e46bb6e6da7319c9e72788aa9ea7a1ea", + "0xa6eaea4ab4206294474d9b956d9d3188d558a5633de2bd05df0d3bac03dbcbe4ed85406349c1d2e660b77c6da1f5bf8c", + "0xaf4a19f77290dddee762e1e0d4bc9945aacea3f75756ae46cd3e58a8f74d1b5db73e4834687946b0f39191e32f2fed0c", + "0xaafa6523f58f1a4cabc924c86d842816d606afeea21fa4b2b8b9573425810fdcc41c98888318e868f9c05e2be12178a3", + "0x8ef38fba0a3fa4ebe985239c8b759c22aaef0c57e6f39050a651c869487803b0d1e389c3d958fb5a7f37740f050ac69e", + "0xb07dfc9f85913c608ca7596a2e361f05e4853fad00e796fd492d247de6414892ce160f627669b1ba933b6ad726415d4e", + "0x94da679ad1d78b2bff5283c938f17b2a7d6e9cbcdf59d340e6dfb652951c7a9e852ac0590f99cfee9631b9410f6f00ea", + "0x98a907c9c021a5b034d3720197c160a82c4b7146cb73d48efeed99b9d0c6b831812cf80ac7e19e85a676a8cd3ead72de", + "0xadb746595466a12929019d0048cea33236b05c1229d2eba73b259a18a786f2bc3f05fc0598d8ce253cecb80bdf679aaf", + "0xa2fbac016996d68f9027a157b0a3f6a336144a798d6113adfcda3a5d05b62c31f108f112aa915906aef22b7f83b9228b", + "0x81841dea1904406d1b6fa49b4b3f7f6cb40b7646cf44d36c9fa07e3dee29f8e47324b40d8356ddf653109673c3374e9b", + "0xa3edbb8aac5e60c775775cbdb19067341b2e2530de48738e84c2c07151241ee31f0d8333bf20c2bc9dcb7b2e638a6b5e", + "0xb8aa6890e22964828787ce86460d3a32f12a655bb5c28de500f2fcf6b61e3334640ec6ba96029a4912af0d18df4b4139", + "0x8ca43169f04243ad0fdb0152de17c60d9e31ee0ab520970fccd98590e05508821a183b4b367967e60d53c2c826ec5dbd", + "0xb179fffd9df8c00486c5a8b9327d599f5a11745ef564f06e126849b06fe2f99273c81f65bc941efb0debaadfecbfec1c", + "0xacf068f1c2b1926279cc82750ce21b0d6b0bfd0406f0d8bbfa959bd83935932957c7f6b8de318315bf0b75f6ee41a0f2", + "0xb97831da260919c856e9f71a41687f5979bc16f8a53b1037285b4a2f9ce93af5cfe70bf0ad484744827fb55c847b58eb", + "0xaff50b0bd907383b0c241727af364fe084d021221bfb1b09fb6c1a7752eeba45d662493d590f1f182764b90b25f17906", + "0xaeeef044c14e3ad41e1235c9e816e1eb49087fd3abe877b89b3bade74459186126e160bb569bcd77779e701b19b5f71a", + "0x8483deb2b7001ca7c438fcdca8ca6aba96c9cbc4becfd9b16a6062705eae270011bcaedcae69bb54630d8c78129e57c7", + "0xaeee8d24be4ac0d9784c029e239fb5e64316ce29b88f47394cfaaa8bb966a72061bff72f99d02dc51c9705854686e77f", + "0x90ae09525a16bb2422169e15d6831c87968a14ebc0d1d27e11a759839c73c655b9d33ee5b12f275d6f440688146fbd2f", + "0xa3a41fc7fefef101422465e506bea7f3ff23c26fe35f5732b86f5f2471fb93b37ebc339f84c6be1e8d22abc812c2e212", + "0x86f4b5293e8aea4af1f1fb05dcf99714cb3aff1cfc849b1bb73524061c921c9da9ad92579a852e1889da29d952f02fe5", + "0x8932ef39d4050a1e9dc0fd8afeaf159472d71c5c27f458c69d2730836606ea56e19c8c4febf2535f930d3260e9bc7637", + "0x86307b9f3696bb21c20e4558e30310389e7367803c353d437e9b696039a0ff054d9a4953b75237ab1d1dd6f71118c189", + "0x96e57730e683ef5b550c91de18b19ac73879f3e26234297db68d28747ed0953beb0f3913cfb720c602720bf9330685d8", + "0xb04a19ee70123782e47b238abde55baf60ac0c66292a998af0d14afc8bbeb1134e557b94cd17a020084631c09a0d3c02", + "0x829abc8718be8139569fcb2c398962f38f4201114d30e2b2fb23566f8a27a5c380f5605cec543415202a12ed859e33f6", + "0xa0744fa488c8fa92a722c5fc4ef5a47dfe824eccd87d26c8bab9c174cbb151d44b1b29082c48652f03d3177e5ec86001", + "0x81d4035ae9fd28bdcd78b135cb54955d3b685a527319df6ee7e904b8e6d796f5f5a5f5035ee1de750c4cb6050e452b9e", + "0xb205e8c2ec24d7104fa0106c09ad34b5a912c1adef553fb718838dd627355993c2ec01055c11d00b2c75b68e9516d44b", + "0xb12d09da7968fa7394e449624fc7174d1d76c069ccb03e140d4d87a2d3f6d1f7b9cfc930f0c80becc673406ebe63f08e", + "0xb23752c158695da85048fdf38b395681cc0e8998630af8a9ed41efbda08c9964c2dc8ae6e53377264be4467d702c0de4", + "0xb0d84582fd73628d96b8c1ec96197697c41a963542451a2ade0890af0d33c7161d0f18e1a1ce2c168ca2dc1e9119d55e", + "0x8b877e618b469aa187632e410b125d2999d5738fd66d482000706b51fd904a0c7e7daa8c9b729fa33817bbc4154cba2a", + "0xb1cfc8a7551b601723b937d497d01dec3ee7614c2bf13d430b1058d5ebc1406045009ff02c2ac15bf8cf16f860193d1e", + "0xb6d9da84f97b21e13175bbb0b5cc8e79e88b470c87a3e115726c1bd98e0288526c58f3faaa8aa170ace0cd6a60852525", + "0xad2e773c2d527671ca5fab7085dde4da31cd35f45d4315dd95d8893ff5fb900494dca08eccfc1a2fc7bf7c7fd2fcab97", + "0x8d5a79b34aeb761d4a0c73f09f02e9548e6d382c33ee6887a759ab05762b490b8a549ef2933c7e3a46415c154c0221c0", + "0xb6f2cbe81bd0a7298403be392f8456bed30aed7ef30216959357698f789affd2942ae5fbaf3f48ecebeb7c273b20cb57", + "0xb5b6c45d99cea7ce6a1dc134aff4a8f630f299b42bd59592a7592345f8cd35bcbee944e61b0723de732fcad6e4425b63", + "0x8077d64dfcb2418974e956ea6dbf8a4c05b25d2a025333ad7e2a379f1976dc036771403383a51bfa3476c9c619ef8bef", + "0xad2e0a9d479c77a5fb73b3613a177fdaad50dcb50fed50e756ba18164c153af30b07fb2565e80ff7469f1b0338b7b5de", + "0x81017d1d80a6b6df4e99d0d7f85a8180b5523e8fa2ea2672fddff604933f8a113cab27fce098dcb454d7d1f7ed266e04", + "0x852355479d68e76c7febf6dfe2ef8e80d575c0d3bd52c983803592021cfa898c571c0b884412c21e66f0dbfe03167b53", + "0x98e1bf8ad48421467c93b9f72b47dded7c41b4fcd36ea55ca43ab24b0d0b876f5a731f422579b7167c7138fad2121266", + "0x803369314abd5422019ed4b0ef652b4dbe97ef5a87b0ea373eec9628b64a12120b2c3d4eb53db405131ff786d14c7ac6", + "0xadf2613fc34f73e1160975c140e925ed84d254e03cc3bc7fc1d19957b499c9ba9d9e4c1639981b594a7095c0a52c6757", + "0xa2f6a68efdff6e4173c00692abcfdfcdaf6f8b62369afad3dafaae4f2f38c4860780b4624d185e20e4f4498b75b5fe94", + "0x8b1658aa0e119fb8401d486ed08d60240d26a8623ef9788e3b45ad09ae31259395b021bd16be395139cbb7149714e764", + "0xa7dd8bf21121285e00672ee8bb84e0cb39b2496fb53a26e35dfbca7f2b04e9a9ff9db15f53fe63fcbeafeb2deeaf2ca4", + "0xb6d8d709e44bc18f3b41d69608edce60c02bcba48d3b7e2fd420842657f0665a7343246dea149a25e8f3416284abae66", + "0xaaf744ca5e9bcb63e3e2939b7a1e96e4a93c88c76bec0cf4294dd7db95cdd3f6a7d92196e352d08680e2328bc4592899", + "0x84434b015a7c398d35f1ec71fce455d62ba4ed4f62da042ec31bb2b4db47073314354cd50bc322297a1cfe35138bf490", + "0x8d70b3a3cd9d5dfefdacfa418c0b775a112a47ce538d33a560a519660009c3f141fd6221c18539129e9c0acdaceeeb80", + "0xb8c6903412a800ec78a4c15f31c24385a267b0c0ece32fd31bbbb557fd70c3b2d60d8fc0f90fbd70f43baa1928ea30ba", + "0x8e391dd445ea06cabb433f057853f8159511b2f9bef41aed9ccd14e0a6fcd912bbaebd38fd5fb736cfde0fa34b7a4874", + "0xa40cd988f70613df32babbd1bbc2f1b29ff1ab0147b01161555a81d56c9621657999bcdb1df38485f687afc51d5d0f23", + "0xb6a008b4426b3d7b28ae04eee4698fc8ef6a35d89008ef5394da39ce582ce1a45dcfae9a33b90f6fa4237f3667803873", + "0x8987280debfb175c3b44a2f152ea82548e4f680966f1fcbee9bf7d714e31bf8080c33f52705ef3aeee70544b22516aba", + "0xa78a51a2c11eea7680a5a0ae417a2981f8c69c396e06da621eadd7510a3664ade49d065617bec67b3de779548a4f4509", + "0xa4d9163f0a1bc048385e94d5e0bcafeee1b18f28eb23505623b9e8ef16f3df76408254dfbe790e45f2884198060d388d", + "0x83dcae2568a0c518793c0f6e38b42f9ceb50673d100b556a17ec8bd9faeec84afe50b8d72422c6b2356959667bb8e2de", + "0x874731941be4474b4576226e5906b5dee89fc9b56a9870dcc7289c1a7d494d345ba6aba31f7546a16f9963283c05f744", + "0x82c1cfab1f501189ac20147fc4631075dbf1abf9125b7d42fcb4f31cf73f3d6461b1bd08fdf6e45cc54bc08a7d5d51d1", + "0xb978228286f5d4a10ce027b6bea3021affcaa805340ca4b5192c69e8c56db59f48e4a14a284ec015f53baf97389f62b2", + "0xaf125f4fdccd1c1b64fdffecb5ec7cf8c7392bbe476e1b89a5b5329c5ba4a526e58c11e72ab9de8a38d60af648d75adc", + "0x8411a41ec14295acab0d36389013535a80dfff6e024bffeb32fb3070762f61256419e8c51b2ad6de9dbe4f1e8e286912", + "0x8ea67a91112a41f9c65515cd496f4b0cdefa1400fc06568eef000c9eae6dc250fb7622eb3f2deca10b37287cd96fa463", + "0x8da99b6c55c31dee6a49aabb54da249d348a31d4416201a10c45a3b04b11e99d4ae9813632f0ee36c523b5cca62f6f49", + "0x8b44656341e039e2bd83a19c3bb9a88f6209482e274f8cd4f8557b728e5948dd80b5745f621b96f4562928689314e8c2", + "0xa02d424a615ba0dce8ed91f477e79852215a3a39d025059826fa278e7eebef19824b2a2844f5b3865a0f471b609a23f5", + "0xa1f115cebc3fff3bcf233da27cef19eae791660f155d088003460f75567a550bef0722885010ddc384acdeac635939dc", + "0xb61a55ce9d143c17876776e064b58a10baf0ba13553c785c1e47f57b5f94c0cda8bc89d43d73386e57816c15b61a8ec8", + "0xb4073f47041e20a8e548c7fb00e07ba3b9056c34eb4ab63bb0e7b48f8e338e8b56a17611a1b5f4c03b352450b86f1d69", + "0xa7b1a07b213205b682fc5b6acb7e76fdf97b280c26621d8f3b76b7c1deb3511957da33a4e358c8e8f3d98b2a8855d67e", + "0xb797e67c2670fbd9844e8a68c585f404b035dc14bd4ec75c3f95f932c777f9db5d5f5df7629164af488fc1213035cc5f", + "0x99618200797b945f595794d6468e5c618649554ad9ba896330f1cc844090eb956ae9fc23132912f9047085c5f0c3bf7b", + "0x81194aa1319abf534cb3927af9adfb178a99d0e3e8c99ab1105f1d3b4fed40ec2971caf1d6647acb0c8d681eca53097b", + "0x80673f18e4978dbc226a6cd4b128a1259d9a7f833879c6e2fbe24d69fef2c3c23a51a4f3e8d88fa4533434bbb0723661", + "0x8125bf6c7dbb2fb63aaa3f53283559f172c788223674adbeb6d5bd17cfe888e6b87a79aec774917f20ce911c1f85f8e7", + "0x884bcdb1878b14fc38adc9fb8b4dd0b3afde404fbeb664f26ddfebc81736018551f23e75ce4cfe4865f610bcd454fbd7", + "0xaec65c8d4be8316e98aa54888af01bc6703a0c5d04b69756ff39a0a947b66817ec59d76afe9f61a25749b5e890f03e02", + "0xaa457aaa1b014a4c5a8992847a187a23321bb43452c98745987d038e3b04046102ae859b7a8e980eea978a39d76a88ef", + "0xa9832ee63b08e19123f719bfe2fe742125f32463efa966c7709a98ebfc65277670e9ea1fa2d2d78b96bdc7523b0c4c3e", + "0xa87b6b1b7858f96d55064274f29fbde56067064962cf3c3e2ba3110b22ea633bc037a74d23543ce3307a46208855d74f", + "0x897cbe4ab68a753020fec732dfcc052c7ed9905342b5a6fe0aa25c631f9ad9b659e0ee75d46f0df6507b6720675ee28c", + "0x97c3b5f0d54c1fc45e79445c3ff30458959e406a069f5bbf7979d684195b4fa0406b87c1c008f4075bc9e602ed863152", + "0x921e65d582ea9322ddfad1c855331c3cac81f53c700b96db5305a643c084eb6793094e07944bfd41dc02c3b3cf671530", + "0x8f23ef1aca02a260a3b65d25b110f28d3bafca44727448c8f2d03c5e77eda620c1721b06681bd816ee6027664d76352a", + "0x946a89b132ec0795aea9ff9dde7b77e7feafffe6e4a2f093042a7e6c71cd6ab87ce0ca914a1b5fabad4e1f96a795f163", + "0xa01e2de9db33df6511172123ad6f7c64074237471df646b32dd9aff8c15278e2723108e4facaedca97e9f49503f8c792", + "0x99dcdcde45b2ea3f15279936feede5f7d3b63ca4972f335b0559c2fa6f9faabd8127aa892a36deb114357ca906553ed8", + "0xa3f8af37bfcf66b04d1896a4bd5d343f4733d4c3305369ac7e75a08f20f2004c10c642d2c7577f4e5c4d1f2cd851ac3b", + "0xb7294d15a3d674a56099f97a1adc9e82c15e90832eaf1722df110fc2abc8634c51515e5ad8522015498a3753b1fa8c49", + "0xb4f27f5062ba7a04ea0048b3025b5e3d5b5d319a9e80310c808a5fb4e8e77b38c10a0f3172cb805cadbcc8bc66d36ec7", + "0xaefe5decee0ae2dc372cc6cf4217daf97c4c908d145f100f0daf1ccdfdf641c78432c2e473e7e4b77dcdf2d4c2bb05f0", + "0xacc84af7648a535ffd218c0cc95c8f7b092418c548815f1bafc286b1fe14f6ccb51b2044db3bff864d0bb70e88604084", + "0x84d8e3dac0df6a22beb03742e1d4af684f139f07e2ea0f7fb27fc2d7d4f1e89b5e89f71af32ff115ed5e6092133535f0", + "0x8ada001e1a03a823c4c056f636e77adc0f9dc08689d28de0d99e0feecab5db13abf37b41ec268dbdb42c75419a046c68", + "0x87dac6c798d1744dff81d8bc3e0e04f3c9bf260e811685ddb9a9a8d6eda73927439b344f9a818d2103fad633de5a4a17", + "0xad9929a7d8a7d5d5954e48281a87e5c84f67e19110d73296b9989a09c76767a57a8115629239ffb4d99dfdf9c52ef6d9", + "0x81ac7cbeef8ec35a5c3b61cc887080c29e6cd3e08af37e45830d17400dbacfb374dd07bf370b979828c3875b2027d5c6", + "0x97f92c9182953b7e10f7a1bbb6b5b5c40b8275eb5a6eec1e29874c4712814749aa8c409651380216e1ff01d7b8511041", + "0xa09794d0bbe7db013045d3fd857c1544fe6231d21afa3495fa300371f6301a3a0f4b8ea175b281503dd06078ff371ae4", + "0x839bb58d320aa08116dd387a57a2b9bd9efc89c4cdfd82d0e47a00cabe644631d09be5436bd485df3b61b75ddf81a3ef", + "0xb1cdaa344f783757e8b9c1f84421da3c5be4c69f019a8fd4c1aa5bf1a63e8970c99e35c22cf3b48a0e6738bc6ba7ce8d", + "0x92af68e3216c78998208fb24b5ba0e645d0d3f5e28222b805668d7e9cdd6c033d3b22fd6df4c2d745d7f910d133cd226", + "0x87640a4ea4e605e2204e5232b29a6c1c31152d83547eef14122cb76a0da52b8653801af48455a3ed713b9dcfee7b1ef1", + "0x8147e5bf0c8f4731155ca0517ef3fae5a32b4d5d2d98ed0007b23893d8dbb7f8a1199c50c1750c2fa7c9cebe594b1bb0", + "0xa76b4473c63c3ab6103c729afd2482822e4150f3155af39983b0ff0766c71cb622455ce6304e23853661eaa322219d18", + "0xb3e2f05ca551bc3adec0067e4034aaffd72e0b64ac18ae25452c996927976c6727966e26d213b032521889be2170800d", + "0xa8414cd14cb3be658e9e0004ce511ef7063439b1cbc3166a11de030613fde4b59caad4e91d426927863c55382afbf476", + "0xb2f0f8ab99f4d0ea785ac84fdbc00b20217b1df59b30b51d9d209d489d53b69dd5d82cdacc16fd1dd15c3a4001595f50", + "0x8b2025d5fd658c9bbed619f3e3f6ac8efe7aeff8aa9401bd66a7ceb0062c44b353608ca073f95be99204f0a913bb77eb", + "0x94a46bc5a87291b42024b2137e623c70115b9c6b196604106bfbfa20f3f56ac7779763f56b580190d3cb2f1c648cada1", + "0xaca9355545118d0769cacf69c4b23d6d68d229cd8f68f1bc0c847c05569c5af6bbbd8c4dceb637b4a6b3b5c83841bf5e", + "0xb0731992cab87c7116406b283a84707a34838bfa3284b0f6082dfabeaf41c5ac2b0ddc1b420547a1b0955aee92de2dc0", + "0xb671f77588c0f69f6830a5b28e7d07ed161b81fa9791bb3a24aae6638e3aa5e186df74978a82549c370c18ebee04d4f0", + "0xb5621ed841780f3e6681d880a76cf519cdd20d35197b112eeaa686764d57b5dfa78ffe1a294b6bc76b6e3949cd2a2369", + "0xafeba2524659d00caecf089645611553187a6ed7102050f6dd20f5a19bed08ac7065912d88371ee06242897d58d652a4", + "0xb78bfb83d44ced14a20135804aba3f00128c3ce1f302e95567ce4097b0d973414153fb305b9f156882a5a0554bf25973", + "0x98510aede95d26b1adf214053eae051ffaf24894e2fa37961a91d0ff5392dd09388196648d95b73e90bd88f2587cc4bf", + "0xb35c682d49c295946b9f120fbc47b95abd9ee86d294abb003a92139fb825b509209562575015856a270eb3eea86397a7", + "0xb9641bf685571dd9c478dd2033a1f1b11cd3a662b26502c78595863b8e536a189674a9a85f7a253453ebfd1b99fbd841", + "0xb2ad37036a59b1c9b8457972665720a6868422ed8157b6810a9c0783006103be34ab732d7aeb8629653edd18fd0f1717", + "0xaf0920cff05179a3896ea6ea322c39adf91ada5bc40fe3f6fb1b1b4e121e907c904bbaa8ca00468b3749f3da144d71f3", + "0x8e269672818ef1e2f9e0c8aa65c84442fcd9151d74bb8e870cee8c0e3fe24526e1a5388b430cef47b67f79b4e4056bcc", + "0xaa29a16fe00ea3d143b1032b1dd26b8ce638f37f95c085c7e777e8e2784bd724bd5c38b1583c61a6ec7c451dd78fd3fb", + "0x87452b7435911cc5f513b0c81b15aa04972ecbe3d7bbd0a5d676c96a8a311301c0e07fac925c53a350b46fbd3d4d0fc1", + "0x869a81c351096f47748e41566ae7b77a454b1cdfaa41d34a5742f80df38fbf5cbb08924b6fdff58e3b18f05c62bbbbb1", + "0x8b7bc1b0486300981147a40a449ada9a41afc06d735cce8bf0fab3ee94ba2e2ea57b1397e3cd31bc295352beb8334ef7", + "0x93e93fc41adb2df279d95654921b4c2edf0d293dab58d0afefb221f777349ef88d0985b3447e3b935954a81f1580a92c", + "0x970fa7cdca8324faf3e62348bb50d78f580b4f43f2e1c11bd8382d48d0074a3c55c6407203a0c9cb1c5f2163ba421ef4", + "0x924983929e608d27e4a36d4ed919297869e3c64de51aca794d32d6e90aea546bf898d98ceca28a0b2187734821b78504", + "0x8d395332529c703d943d68415d443332b5c1342ca9d9a59bfa8bd4ab63e93358c4b0dde6ce1f2e8ea9dc8f52ad7ebd95", + "0x80200dda853e588256599e7f905add5d5ee7c74272780317694fbae39318ae9be05d5bcd7b20cf460069743f3d4ef240", + "0xa287d51d6359c9ef7c7ac1b20e479ce7d0146dba5606397bd04b7a622cec642508d5b45d51b31de71f9763595b6ac88e", + "0xa320396c075175d6599225cf2e1de8c7cab549f6316c07feb0f6eaa21f06b2dd29ab14fbdf2af4543b4890ec0fd08a4d", + "0xb1e9fe230418d20368691058adcbbe30011bab3000422f0371015ff8bd09c60fb5fa85d18550d35b1c900977ca48f58b", + "0x9718fc26a51783b971744933f20490e9b5cd9162f86b84788c4c5217f5409e37b5a39d628b18e5b35a757acf67596321", + "0xa0cf81fdb161f4f1b419c5e4caa36d4bdca2325f0cd25b119a30178016f171bd6fb88403e4e3aec026c4089f180d540e", + "0x8ab1e36bd04625ee794ef04c4dcb8e004d61aceb2b62438377f49ad95dcf025ba25eb799280004941e555bf7172af6fe", + "0x9257b9e3d14d37fc7efae49b0c68d36eaac546035f4a2654d566b3ce1b2c4564cbb03dc8ec66efceb768559a8a507a18", + "0x945d1123b839637ab5154a1972c3c83a0ff34a3b1a3465de6ef0416b1950f649869a3ef88d7f1036648ee385265ce2df", + "0x81449639d708860fc0229c94f754f7262e8a3c7f67960ff12dfd15df95f57a9ffcee2013e81978b7703dd42bd5d0816f", + "0xa865481deaae5a690fd53892791e5fa729db283b75a525a11cdfee1ce17e8e7f0b449d25f20b3c1b43da128dbdf98a8b", + "0x98766812a65fcd25b853546e3bba618a3edc9fd61510e4f8ab60c038a7fa50d197abeec8776109df0f2119be9445ad00", + "0xb1b8dd5379d903dc41d74e999b1ab693607a0d2905692f4fb96adf08f738e5d31f9d00df28ccb8b5856145ca552c3e3c", + "0x99d20be7b511bec78a8ed03c207aa4aa9097ba39d85e18f1b8d52f65431ab7e9a773c7b9ac3e8d8b25458bc91bd00703", + "0xb1b7c3563fe8cb33c7d3e0b89d00bdd13e86452ff507c2e69db7b3af06f247f139155396e9b0278753310dc63940a10b", + "0xb3dc9c08451b1de7c9969b1e47574bffff50490f4a16c51e12390195d9e9c72f794790caf7b0a835d64e01fec995d3ac", + "0xaaaa4761a00022ede0809d7063d3532b7bfae90ff16f45e17a340ad4ebaa2fbac40728ccc5fbe36a67ab0e707566c5dc", + "0x8319a1903314eab01f5442d2aee6ae9c3f6edfda0d9a88b416d0f874d7d1d05d08bb482102f8ca70a4fa34836d0840c1", + "0x932949a6e9edfec344932a74d4f81eec3667ece1e8b8ca840ce07ffd4b5d6d8f01657c764d64ac1b9190f876b136490e", + "0x904db1568128487e312fe629dd8bb920cecafd3bb9cad8b63e269ae0129f2f5c80cd82f0d81e7feca9835c3945a72d28", + "0xa17280693d30dcd43c85de8f6b02d5f30cb9097274ad680cede1ef105c903615b4c40f3c6aaca478642de324972514e0", + "0x8d5f76e093aee71d0cdeb017fdfcb13bd068039746de90690ce150a0bfdbe7ddc4d539df0f82c2d2890a40b191900594", + "0x96fa1f2196a3883cdd73c66d28403cbbb58f6a939a3697ee0d308d8a076393cbb4be86255af986869230ee410c01bcfa", + "0xa8b74438dc5cabd70a91bf25601af915c4418d074327a9b01e0190c27d3922c89bb9b41e0b366e82e313edda8f21983d", + "0xac9fdc1a9b2e3ff379eb2370979372e13c4177bf4574f1490fadf05a7073e6d61e703e2d8eed9ce984aba317d411e219", + "0xa45a6c9b958169f2f8df70143e6ac3e2f6f969a4eed6fd9f1c620711bc2454739bb69f0094079464790c5429c0d8aedd", + "0x8901cbdd1009864386577842c1e3d37835fddf834064d9613b4559ea9aef3084204e1f863c4306f874141f4374f449ff", + "0xb6c582161691e3635536686825be9c4d7399d668a7675738417e0363e064dfd28acdbd8dbc9e34c1dab8a1990f1f0eba", + "0x89e89ddaf3cacc78428f3168549c161283ca8337345750667c98212717b21e7d994eae4e45bbddacc832a18df1d79276", + "0x84be275627eed8e1a73c7af8a20cee1ef5cc568cfeea7ec323d7f91b44e9653e9aeed47c1896a8240b99dde545f0e1fa", + "0xa779a54ab4f40228f6e2539595fb8d509b70aab7c19e1928c1be69ec1dc19285c3898cf15e5f8b8bc725e13af177fe17", + "0x92e2a49d2b9b36349d442283b17d46f8f9bf5932c34223015ce62d2f285e7363b2c12232be4a838b5b6cf08e694c094c", + "0x8b4e28c6f3f36caa2cfb82ba88066c830f8017bd35608b077143dff236f3181230166f5a5c02fa0e5272297331726aed", + "0x85fd77d46162ffac4b8adb25baff0eb0512a53a3d01638b3a376ea34702279ce21c8e7d8884308c03e00c9bcc1a9fd29", + "0xaad5e46916ff1be29009b595d1d8fa160cc7aa01c7fbf3a68f445c87615790dcab1fcdbdceda533d182b6541f09f2f73", + "0x948df7654726250dae393325addd3c0a20431c81f00470962190335ea4b6d9f7463d6f308cda46b92084c1f24390b1da", + "0x8f577474dea132676504376c5542b730b6604fe3d965eaa194659fd11c52233bd0b11ab62e198c0f442327ff1c00e501", + "0xae2f1001546db3e0c19700adad997cd9f765fe7a51a502cbcd9a2a07a3a5db79c8f603e05cf96d80b688cb6c9b6cd3ae", + "0x953b68e5d9561088dd20406ea7fb6894cba33868a38ace38fc30b5813140cb15dd6dd2171befae5b4df2e4a9658889d8", + "0x86c52901655ff11419b084a04da8fc3596eae59d81d3461601c0baff59ba59e3d1dd0b7ce719e741a3e97c013e898579", + "0xb9a72dd5eff73f9912a28b55de073568efb3eb0241a10b77a2bfd4f30c2aa4fbfe0c89eb345c9f07fb725660873cb515", + "0x8e7353f5f2932e4ffd95811caf46c9bd1a53643c27eb41a4ebd211f230955cd71a8b27e17cfe8aa708d8514c0de67a66", + "0xa096b8e66312a92fb10839ebe60189a8d1bd34dff55f7dfae85e4d2f53a1a4a88211c19fc84494f066358ddce82be131", + "0x931c5cd82719d76596832b007969b5f75d65cffabb41b9dac7910300db677c1309abe77eeb9837a68c760bb72013b73a", + "0x8ba10f5118d778085122065b55dd1918fddb650cce7854d15a8f0da747da44d7b12d44fc29ad7dc38f174be803db74c6", + "0x8c971deec679372a328587d91fd24ab91043e936ca709c333453d7afd43ee256d08c71cb89f0ab0e89ae119831df6d86", + "0xa2ac28a58034fbd8fd518f409221bad0efec52670880f202e09c0530e2aabc2171ed95e99891790596ffad163d86c110", + "0xb3354e3dfa8068aba4f3741152b9204baa4e342c1cc77e6dd1419cbaf8da1d118be605846b8609e997d6a62a11f3423a", + "0xa12ab65a213c9d95c24865fddc2dffe0cf9fc527dd6bcdacc1bd7271e79929a4ab3427a231f4f49d0530474e6cbc88f9", + "0x90afd65b7e6973f8aafbe74da0f42441840d3c93bd69bc1bec8fa56824e7ca97ad1b427c8a85da7d588469bd4ccc50c3", + "0xa09175940c59489bac3d3da3a4091270d9118948cbbdd57f2bcc63fbf45b8010651c801d3e58dccf42733ce1d6b446a3", + "0xa843bbf286e3cecc1fe370ff1bcf5f1001bc2e95b34246625ff50d48ee62343e82fba2d25b8a4bd5f7b5ffe90920efa2", + "0xa3c4d1003219157fdbee2707ce07afa6c2a64ae8e450182c307ed7f070024071f30b12c4b0032960ff913c74e73a9976", + "0xb24af3f68d66f825d06fc3ff94fcccebe28b1a0d4ba29c48d3a3c953b9bf7ae6707f193fef25e2dcbd2b74e483c774f0", + "0xb0f657f7723184ef7d7e4381143f1ac8020d8c6c6f2dcbebb0eaf9870d61a81f2d452596503311e46d1b38f625d4756b", + "0xb90091004fc8f6205c51bec68547ac82dba0f5525631e7632cf6efe54eecd9020729fbee6105d1b8012402d3b79c54aa", + "0x8e3fa187713c60eb0a416d6900a894cdf81e6b6b69dae0bb64f6287f3c3f030cfa85c665f7aace1eab4937f380b8f728", + "0x879bf0784ccf6725c9cd1ea8c49fde31c91c605de1ea664a33c2ce24c277ee45d20b66309f98d989acb2ff3b77e13101", + "0xaf3f3a3ddc4e11abd627d5aef8adffa91c25df5f0c68b4d2b5d51e7d9af3395ba4f6f7ae2325a6672847e1ecc6cad628", + "0x973e667289e796d3a40f072e6fea575a9b371a9997cf8961677f8dd934619ddc47c1a3efe91bae9ef95acb11a8fe6d09", + "0xafa81c5606de82f46b93f4bb6db3fc0670f4e0d1091388b138a66b3827322d95a56168c951c30831d59eeadc227500bd", + "0xb83eff77db5b4c18574662942eb36f6261c59f655f8a9c3d3731412d0f257c8e80aacc995c4b2303058a1ba32522a434", + "0x912e5ac9234b9445be8260393ff08e4859a7a385e800b74d1534eeb971f58f74cfb518dfdb89f8705d89fbf721439129", + "0xab27c8ece4a51d23e22c2e22efa43487c941139b37ea1182e96efb54ca4809d8245eae0ebe8ba94f0ed4457896fe11b1", + "0xa6630585d104a745bc79dba266d9292bbdad346449c8ee8140a5e6e8a6194411df9cdbf3d3ef83468a536d4f052e9335", + "0x8b8c128244da48e7fec641a882d0005a2d05c7138d86a293e6a0a97c76bf632b44767d0ce44663c975e7f9f9679e25e3", + "0x87dbcaca67351a4e7d2297d7cdba4796d12f58857e7ee4abd0645563577ff33544a44cd84e50b3a3b420d6998de9b57c", + "0xb859ba43df259d7f8e7fac70bfd7aae546d57a5dc90e107b174a95bf7fd3cf00f740c4434848e69b2a7e6061f66c1ef1", + "0x99d6e20978fefc40c6d310187eb2ad3a39296f189ee122ed64d74f81033c3069d44f7a9d3988a1df635b609603a17272", + "0x99a5ddf3420cc0c92b21f71a805245608d4995ead447d8f73a670d26d33e26920d5f07bfe1f6230bd5f15978055b4253", + "0xb936ac0944d3c5e4b494f48f158000abb37b80b5c763f77fe856398c664b0f1ddbcc0a9a2a672db9278f08b4bafbe2ec", + "0xb4af85fbf4040e35a686dd016adec037c99b47cc2e4dfccaf7870ee9e8c97bff30f3035992def2a9d4af323c0b3af8ae", + "0xa5ee32b8bd5f8fa9000da4da0bf00565659a43285393d37080b555d0166bde64d87317b2eab2d48a0e7b287caa989be2", + "0x894d4ad58ecb1c9ebc4f5a97407082e56cb7358d7a881ba7da72321c5027498454f2c7fa2bd5f67a4b11d38c7f14344a", + "0x965be9eeaa0d450dacc1b1cc2fbf0d5d4b0dd188f2c89aaa9260e7307a2a1eb22db6092fccb662269e9a1abfc547cabb", + "0x805893c424aec206260c1c2d2509d2cb9e67ee528bd5179a8417a667aa216a3f318ed118b50d28da18e36c01f0805e3f", + "0x972d7040d4963b35260ef0cc37cd01746f1a2a87cedc0dc7b0ee7e838c9e4573784ea743f563b5267eb3905d4fa961ba", + "0x8c7156991d4c2e561888feaecf501f721b4174e7d14109e9deeac5a9d748301c07e11fb2b04b09799f0d34ff42cb77d1", + "0x894722ac35af3d507e81d737d21e16c5ba04686f8f004aa75934aae5e17acd3e065b96e229eb011c2f34096f4c62048b", + "0x81237937c247c88e8e31e2c72412189fe59c1daf65c5513489d86cf29ee922c0bb08e5f7890f09f4ada7e5262083d266", + "0x8cf62cda2fe0d9a6b42aa2a1c483f4ad26378c7cc2c2d1510a76df7560b07dba8528b33aaacb15f7f20b9d4c7c9f61f6", + "0xaaf0921fb3e1920eee5d0acb59dcc268b42f4b435d60d25d30357edd7dd758d035919691bd15311d85489dfa2e5ee696", + "0x92cec07be2247ef42002ebcaf65ec855611b8e893a5675796f2225f55412201b0bf9f4761924d0c8377b9f131e09e39f", + "0x8e514a62ac1e91773d99588415426c97ad63e917c10d762fe06ace5277a5c3bf3730e4b9e5d116f8493b9ab8687b70e3", + "0x83932df2d923a5052468a3ea87f7b55c6a80ede3594046ee4fe233046570921822bc16555b92ba6aeabaef9b1dc0805a", + "0xa2b5bfb249de3472113fd3f35bfabf3c21d5609da62a27ea6aab5f309c9068d94bc58ba03efb4ec11be06306d59e60e8", + "0x8106cf3ebe6f0507be8c6e8d137987315fe3689ecb75bb27980f36ba5efac504baccea0e7603549b6d126beccc278804", + "0xa73ee70b6fe8c082443972102c453fc0e386852476cf22224fc0bfe554735c12f96037fbf10922795f4502c4f052b5f4", + "0x932b27e175440169958504f3ed6400e7d6dcd5e716c19dcd0f15c56c04503ed133d5a993e111c016f141e32d68b29886", + "0x96f7ce4595318e0b4a6b368f788ff82226aac676aed4ace343867f751de414453a9aaaabef6e6224ce5aedc3d5cf77c4", + "0xa950c1e3bc9a14484997013d44d876374b939af437ae7c821c131fb886063ee9fe7214a25a0c7084f0b07b99412eff75", + "0xa9dba3886ed6855303106a1bdd26010f294218684e1c178afcfea3f37a2f04fd01724a31d82de3449046617e3507a115", + "0x87a2f776b32a6b550cf3ceeaf78db02819be74968d228b1d14e0d74a1cdf994bb500b7abef6619455e98d728701fac5c", + "0x8cd887b07e335edc0b27e6a660cebb64d210741395be431d79d570139687b056557159407459799a8197b6079644f666", + "0xb81a61fce00588909c13a90c1caa150f15788786af443ff60ce654b57147601f7e70b95659e01f470334a220b547611b", + "0x8aebc51141544c5f3d3b99422250424b9800031a8fdfbf22c430907a3a446fecaa2392105d66d64b1c8e847240da4a6a", + "0x90db7dc12baa02f3f86d3edadf9434e2b9318d4f6f0eca08276b765dbb38d8eb0d08be2fe70adf2bf16ceda5db08d3ca", + "0xaa1839894152d548cc6ad963de20fb6fcc843bc9af2a2bf967c63626b8ad19e900894d6106265f38f3afccca317c22f0", + "0x848e27b741496988a582515c0c8847b2bfc6a001259396cdeea1e1b1d2828ca3a626693a1bf4adf3a3d7f8b1fa3d75fe", + "0xa0aa11754d4ee136ac3ca609b17bcae77758763b2016544ca7921dddedd8aafcc7ad5f2b337c8bf53084eb8e43ea41fb", + "0xb8713b7aa1c112178195fdcc9b7024f46e6bc04c4e76c41abe620aa265287809200d98eaed6c9703fa97e81d6964f0ec", + "0x8605b5b33309e9ea6823542b85383c496794b8481c577497aaf99ba90496e794dce405be615bf92c7b6361460e6b82e3", + "0x826fa34faa7f83e063a7bf172addfc07badabada59cfc6604fdf481d29085251c0a67a1355b2cbd374e2975934b84cb6", + "0xb45d131082dc16fa53af010d43eefb79200dc23d2f3ee26af95ac6a5cebc49c84a9ed293e534ed16ff3ef9a4a25456ec", + "0x91bd6ce3c5396a7a0de489e49f0cdf6dce1cd2d0be7a410326423c3185bd1125ce1e610768be7f15f4e44b62f8834fc3", + "0x903ffbe3d33fbf106c01c727dc3a385201a67ded70d4df623934882f69a3a96c909b027a124f3d70cb072b0046a149e8", + "0xb405359db9d9ef4821a181b440ef2918c240595141d861d19a85867a5afa74d2972d22c988775eab441e734700bae4a3", + "0x8abb756d027233c83751910a832b0ef4d28d100077f1c5d656720c94906f91d85dd0ea94b1cc0ed95b692efee14c786e", + "0xa78ee77ab476a41a3454160ba7ca4085d8b1f7057c63e76db8b07cf20afdeddd2250cd00771a6329133bb4ad48ccc20a", + "0xa41810271d8c37197aa9b3dfcefe3498e42f5978d3f3d59defff4676d6402d8575b40683834f184f143b6cfbfc859b3a", + "0x90c24a0750242660bcc6d487358a3cc015730538a0a8beb00ad5ac2ef33cb8ca8a62121e50bec8f3d2f43900f8e3134a", + "0x8b96c39695d864ef5796941754978a1fd612b369f6b77fe5ae6587beac936ee28190af8f0a3822b63060af35e49a5c8b", + "0xacde2548883d0e63c0fc257bb9dadd919aba60a985b69ebcfa1bca78acca42fc1322ec30bcc8e7c188818f858d04ad33", + "0x895c86ae9ff8d95f2707d4838a3bc8ddb05b2611f0476f014b9c150d0e8332bc73285037a747426f09ac8179ba4e19fc", + "0x821761fe406e18bd86fa9ca9db99d382cd3b5c70c456f471fa3706d57763d147706304c75d54f51ce8f3115aa26e59d9", + "0xa803a80e3e8f47dc3c59ea23eafdec017458eac648b360cd42cbd075e0dde6f6f450b48c7646fb1e178c04f82ae51a12", + "0x91f40e1b6f588bd592829ce937996452c40be0fd6c43793c607866701ac6a8c7227e0891d45c6e7b1599382b0a3fbdbb", + "0x9408246d996a634a58689337f2526dfb3ba9ffef1d3ff91c32aa8cbbed900861ef25d6477308b67d76491edfcc70d65e", + "0xa492325a427f3df1c9c690c5b553daa8ac41f62f5ae55f425539222bacf959e2f67afabbba1732e120d3e7a6dcdf7049", + "0x8fd0c3e15477cae228613a171b6e9ec29ddc63ef74854d99b638adeffe39f89f34346a42851e8445e855a9f2bbef0f57", + "0xb735ed01fafa051004dbaad5e8c9e2faca8f6049ef9b590f256ea4d75b04594af12764ad4e6031735eae36f83179db93", + "0xa7d35f43fca06c86b3425dcb68a87186834ba9740664fd657915771beca4cdc0fa2fc9b4c2e9d9bdad8ec33543ddfa59", + "0xa1156e71e2db1b17df5da28747c88e091bd687bfee59d89096437ab4dc9a543fe5c5272d5023d72adbaab397a6fc94d1", + "0xab06a58bd81b33a411bade8d8c5232d38fadc2e38507159edea6e2e104b8ebd65ca02b05335118f691d44197b847a4dd", + "0x848b67a10f1e6ff8f5c228f226ef2ffeb67fb8f50925fc94cbb588d61896d9dc79726959e649898fd3354fe3ff7b7ee3", + "0xaa933397361f32b388edcf832f0db172a38e756b34d5f7a4a050fa7325058006c22cede26ee27917e8f1b0f301792bd7", + "0x89e49e7f02cfaae4a4b9c4180c9f6559d76e3a45774955859d4147970b1470dac37bdc9aedca1c32a20b045049161590", + "0xadc1825d5ab94fc719f25d8c9773f4d518134ed88eb13ac33cb910b2be3523ef9ef88d9e4aea2418b806e20108317bf6", + "0x96c4b444c8a023da644f3a343ebeeed19a8392d2ce175992461451c318a54273b76c3574d8f2dceda2947ddd34d1a674", + "0x8aa7e97e87c8c5b29bbd51a6d30396a6be1fb82b716ef83800f2c36d5b85467ade7e0f59d2db82c310fa92a9265f0b03", + "0x9146c32d99f02c3a6f764dcd9b4807f1585f528ac69dc4f84e4380f6fda4f9d5057c375671d51e7aca2b2b4140e83da0", + "0xa10760a533d9bc57536bcaf65f080302086aa50225437efd64e176841544711828c23a15c49c0dd1f357d3f10722ab72", + "0xacb0811777e17f7ae7aaba5f6fce81b759c067a4908730916195a2505c7450d0e6e2194c2ef0f241090597d58e70de47", + "0xb24f161e9bcdbad56665e2490b5e4c7768390d4668cd69a04ed74739062dbe832636dd33cda89e9b0afa8c77e93fc641", + "0x96b4d01106b831868a88ef016500ef2fa42d0ce87a37ca8ca4194a92a22c113edfe04eb2ca037329f3c1acc635148f55", + "0xaebbb95fb4f7adcc8e7a217aeb73f9e037cbb873d08c1cd9d68c6c6834511adf1af8b44567fee84327599bdcb734dedb", + "0xa9bd8b17300532fb94d028659bcafbe7bbdf32f8945baf5db4cfaa1bac09e57c94cad0ba046b4514044b8fe81ea8596d", + "0xa5557cbda599857c512533e7cadcf27bf8444daa0602aa7499cafc1cf1cf21f9d16429915db7485f0e9a1b5046cf01c5", + "0x8810307c40bc661c478a9747ebf2a30e5a5ead942d1ac0418db36ba5db0709c476f7d19685cabe6959e33ec1f3bff914", + "0x8829b741f41f2c32e10b252d9338deb486dba2f23996a44cf1dd888ad967a589d51329be34d764139f372a1043f6c2e5", + "0xa6b4728d18857c5fa082fa67bfb3b1d801e76b251b1e211a19c87cea5fe7ce757f943c85071f7a03a718388cd5690e95", + "0x86da7f397e2533cd487f962ae58e87bea2cd50af70ef2df9ea0f29f70b5843cde664d30ec207ab84fc817f3851277e02", + "0x8085776ef4ac6d42ab85b9d9135ecc6380720efd274f966544eeedf4684028197de76ecab919fa5414302597e1962bca", + "0xb05a065c733033d223ba13d16baa7a97bd8c8b8b1f0e59a9bdd36ee17e9922d48eb39bd180c168b122088a77f0bf321a", + "0xa89343fe44a93023dcc7ef71bd3bcb6786f68e1885ad260edc56a52445d34757f476395ba7ad35437f89bc573c7618dc", + "0xa114a9cd6105b524f3969c69faa2e09afe21753a93361a296f9e0e3b4e3e63726ddf2e6bfd3ddc046043e50bd44e539e", + "0x8a5611fec539cf681c05636bb580f29acc06f628bb012649ffa41ea6c1521194a5643d5dd843f09b6eb2c3bdb4d41acd", + "0xade247c4011ec73ec90b72f35afa59a999e64ba5a7e664a4b30874fea53ba6a14a76a41b58a5f891a20d019e5f091bdb", + "0x905b5d96df388160ade1ffe210d0c6d1979081bc3de3b8d93ac0d677cc2fc2dc1ef6dcd49d3947055514292a3fa2932e", + "0xa9520796ca9fccd11b7524d866507f731f0f88976f0de04286e68d7cf6dbd192d0d269f0cd60fd3d34011a9fe9e144c2", + "0x989a1edf4d7dae811eb57a865c8e64297837ffeeaae6ee6ac3af0f1044f023f1ca552bf00f1642491f0f0f20e820632e", + "0x879c8e63713f4935ed6e020559e140ea3073ced79d3096c152c430141272117b4fd9a9fc3eef012e81262df02ea14bd7", + "0x95074738ac1540c0312274333acd1ecad9c5509fee883c4d9295fa8d8200f6e637c363de395f9fa612f05c0dc58fae88", + "0xa770e4fc595269eb806b113ab3187ea75c8f96b57bf9fcfaf535f3eedc1d4d7e6285a20990575de0ff09f62d06ed0692", + "0x81283e5dfb6423439ff513eca1cc316941d196df8da2d1069d2d0b63f5289e630af2fd4119bc0144c002d33313372dab", + "0xabd1b108e743887b78f698f2aba9d5492f87a22868d1351d705d93a1084fd45be67170c68a6e18b07f400d9a01cda8c2", + "0x8509c3f67b92908cea8144f4e2a71631a66a61ac3547601c788907e52e380e5fe8ae4110aed95d13c67d3bcdd5b55a61", + "0x8fa5a790ec5cce6d4114128c295390120869aac5490a82feebd3c37a167120df2e7fdfaf2a4050a7dfebf48fb093212f", + "0x944753e1ea7d8bc727d46a7702077dc01dc0c6574e8263a16579b57ee155ca5901f71bb347a01a9a922b329d3ff75135", + "0xb46bc1fd4590b7a6275e20036d247c5909fc549c78e95b64ae7ed96e3b05bb044840f19f7650ebfe7008ba09fa83c3c9", + "0xb1e47e4d88e59a06c465348c6cc4181d40f45b91e5e883966d370c26622c328415c6144aa2f61ddb88ec752482c550ca", + "0x8bd4f8e293e3f1815c7e67167618fb3b0ea76424bc0985908957cfcede36109378e41b4d89555b8c2541b4c447e00461", + "0xa70589a867b2bfb63d0106083d58475d506637148549ed35c83f14e5c8de996e1b1f3447ecc80cf5cd134ef4db9d2fb6", + "0x8048b80ba6131d07370162724127b0f7cb17fa7f71855e55e5a75bd0a9e4fd71b0d0ea2d16ec98858e458528df8d06b5", + "0x97326cb94bae7530f4ec3235770c5a7ba042759e789d91c31fedbd979e3c0e6a2c69e2af3c1979c6fe0094274dbd53ce", + "0xa18e9c1d3eabd62af4e31a4b8e08494f4167fd4598c95d0123f39c46c53f9e93f76615900246e81a286c782ac37c569f", + "0x80309c59d4522b15aba617cd3c6238663e8b1c7ad84456346082c8f281140fc0edf9caa19de411c7e7fb809ca4fa3f4d", + "0x8e450c0990e2f65923f252311623038899eeff7b5c2da85b3a224e0ef7132588b291b782d53c477ecb70f34501466178", + "0x87843f96f41484e254e754c681a65681b9ae5c96c292140368743df9e60f7e2ada58ca2bb95fa39abe064b2ebf21eeba", + "0x858e8d5bf2a1cf26d8af5036b28b831d450a446026f58a1734b696c18f1f41482796b91cab0e5b443dd2f0b9cffa52b4", + "0x99627dd6bad8c05c5904cd23aa667d664da846496dbbb8452705c4ec01e1480e9c7295504a5a8529e4a0c842306b038d", + "0xb64b33256c18b2c886a837a0c0730fdfe73befb0e2796207c4dc592c5a33cd51f8c2ef47c584dd5773abf9ce9c1b0082", + "0x944f6da2a1546f0bfc4d98c3e73c79e935e33d208b6be26b0b5f8df6d0e3b74a5bda649853b99281bd3a3ec799a7dd04", + "0xa266d165435784d4e884640155e35b2a911b3f89e1e715986de419b166a36a341ba724877d80583fa3da566f6a828971", + "0xadff2698409d0756e78c534032ee926560c13d578cb178d5073172d049ebbce32a92692f7e2033ec781b9b0d894ddce0", + "0xa91933f110756c699c28bf9e24fd405bf432002a28c4349e0ca995528e56a5a2d101b8d78afa90a178ff1a9bf2ba515c", + "0x8e77839c0eb4da2d01e4053912cd823eddffbdc6b9c42199fba707ca6ab49fc324288b57be959fbfb11d59085d49324a", + "0xaa124517c76692036c737e987f27c2660514e12a953e63ff4bcb269dd18fc44dae95e282de8444bed09639ef6577af88", + "0xb285deae99688f1bd80f338772472fa2b35e68887c7eb52c4ef30fc733812444c5cd110050275ad999d5a9b57f782911", + "0x8877b0fa85b44ef31f50bdb70b879fa6df5eb1940e2b304fd0c8f08abb65f3118fa3d97ff93919038c1e452fb1160334", + "0x8a89f3b50dcbca655024542ca7d93df17deff5c7d01c7da2bdb69e76b3e0b4490d85c800fb3debb4b0b4d20c9527f7ad", + "0xb7e5dbe36e985354ac2f4ab7730fea01b850af00767a6c4d8ee72e884d0fe539bb81f2e34638fcf5d07b7c8d605f4c06", + "0xa85a1d78f6d4f9d5d83ec0f2a426708342d4e4a5d15625554e8452f6a843d9aa4db0c7e68caebdaf767c5b3a6a6b2124", + "0xa518078a9dac63c5bf511b21ed8e50d1ccede27ebfe9d240937be813f5ee56aef93dc3bf7c08606be1e6172f13f352ce", + "0x91144eedebda4d1ad801654ef4ecd46683489b177ba1de7259f7dd8242c8c1700e15938e06c5d29aa69f4660564209a0", + "0xa16c4657bc29d1d3271f507847b5a4f6401cee4ad35583ad6b7a68e6c2b9b462d77b5dd359fd88ea91ce93bb99130173", + "0x85b855778f4b506880a2833b8468871c700440a87112fa6a83fd3ddb7e294b3a232d045dc37dfc7100b36f910d93c2ae", + "0x8d86bb149d31bfbf1fabcae1b8183d19087fd601c3826a72a95d2f9cedb8bb0203d1136a754aa2dd61f84b7f515acfa9", + "0xacfe7264eee24e14e9f95251cbcfdd7e7f7112955a1972058444df3c2d2a1070627baefada3574ebd39600f7f2ea7595", + "0x906bd14ecca20ac4ae44bff77cc94eb5a4ecc61eba130de9838e066e8766ed3b58705f32c650e1e222b3100691b3806b", + "0x8f2cbc7b8593c4be941dd01b80dc406fe9dfdf813ef87df911763f644f6309d659ea9e3830ff9155e21b195fc3c01c57", + "0xa68eb15ed78fae0060c6d20852db78f31bebb59d4ddc3c5bdd9a38dbe4efa99141b311473033ff8f8ea23af219bc8125", + "0xa95cb76c9d23fc478c7e8a73161f2ff409c1e28a2624c7d5e026e3cee9e488f22225a0c5907264545a73e83260e3a4ec", + "0xb76f90e55fa37c9e2732fd6eba890dd9f1958c1a3e990bd0ce26055e22fe422d6f0bcc57a8a9890585717f0479180905", + "0xb80cc95f365fabd9602ec370ca67aa4fb1219a46e44adf039d63c432e786835bb6b80756b38f80d0864ecb80e4acb453", + "0xb753c86c82d98a5b04e89de8d005f513f5ea5ea5cf281a561d881ed9ad9d9a4be5febb6438e0dba3d377a7509d839df0", + "0xa664733f3b902fac4d1a65ea0d479bb2b54a4f0e2140ed258570da2e5907746e2ac173ace9120d8de4a5e29657ae6e05", + "0x9479722da1a53446e2559bb0e70c4e5bf3f86c0ce478eede6f686db23be97fcd496f00a9e174ceb89ab27f80621f9b80", + "0xb707fd21b75a8d244d8d578f3302d1b32bb2d09f2bd5247dff638d8b8b678c87d4feab83fe275c5553720a059d403836", + "0x93214c16831c6e1d6e5a1266f09f435bbed5030c3c4c96794b38d4a70871782002e558d960778e4465b1ff296ffedad8", + "0x8648f84e18eb63dad624e5fa0e7a28af2ee6d47c28f191be0918c412bf24b5460c04bf2b7a127c472914a0741843f78b", + "0xb67f61e75d6b773a6b58b847d87084b94f3cdac3daa7bef75c2238903a84250355a986b158ff96ba276ca13a6035fdd6", + "0xae9b094b7b5359ee4239d0858d3755a51aba19fce8ad82b0936cca48017523319c3309409ea6e9883a41bece2077e4d8", + "0x8d1d8e1fba8cebd7a0e1effea785a35e16b1a10842f43e2b161d75add11eccf8f942d2ae91c20eef6c1a0c813731ea9a", + "0xb82bd387458e3603782d5e2dec32ae03890a3fc156d7138d953f98eff4200de27c224f626e3648e80cd3dfc684c4790f", + "0xa6dd02a89ad1c84e25e91176c26355e21a01b126c1df4d22546159dab9d502dbc69bc0d793a017c1456516e4aa5fa53f", + "0xa9ab74a5c5459b8500beb0ad13e9cfe2656e966dc9b4f3f98bec7588023b4ddebf74e4fc722d30423f639f4ee1b2587f", + "0xb03e5f33ab7ecec12cbc547038d3fa4f7ea0437e571891c39660c38d148212d191be29e04eb2dc001b674219b7a15a9c", + "0x925df4fc6e898ca55090ad1a8f756cc5014167a042affda5b24896eeb6aac408545134920586a8e1a2b997de9758b78a", + "0x98c8580fb56ed329fad9665bdf5b1676934ddfb701a339cc52c2c051e006f8202e1b2b0f5de01127c2cacf3b84deb384", + "0xafc3765d374c60fac209abd976fe2c6f03ce5cc5c392f664bb8fac01be6d5a6e6251ac5fb54cfcd73e3b2db6af587cbb", + "0x8e7e98fb5a0b5b50d1a64a411f216c6738baaca97e06d1eba1c561e5c52809b9dab1da9f378b5f7d56a01af077e4f8cf", + "0xb724bf90309651afb2c5babaa62dc6eac2b8a565701520fe0508cee937f4f7b6f483fc164b15d4be4e29414ce5d3c7d4", + "0x9665160e7bf73c94f956ecb8ba8c46fe43ae55c354ce36da40ccc7594beae21d48d9c34d1af15228c42d062a84353a0c", + "0x8600ab3aa86b408ee6e477c55572573ed8cfb23689bbdadf9fccb00161b921ec66427d9988763a7009b823fa79f8a187", + "0xb0d8d19fd1022e7bc628d456b9bd1a2584dce504eb0bf0802bdb1abd7a069abbeeccdb97ce688f3f84a229342dbc1c33", + "0x8f447d5e5a65bb4b717d6939cbd06485b1d9870fe43d12f2da93ca3bb636133a96e49f46d2658b6c59f0436d4eede857", + "0xb94e327d408d8553a54e263f6daa5f150f9067364ded7406dcb5c32db3c2dffd81d466ee65378db78d1c90bc20b08ab3", + "0xb58c02781b74ef6f57f9d0714a96161d6bfa04aa758473fb4d67cc02094cd0c0f29d0527c37679a62b98771420cf638b", + "0x8cfa0a687ea51561713e928271c43324b938aa11bb90f7ffaa0e4a779b3e98899f2af59364ce67b73a46a88748c76efa", + "0x95d6d39c814c5362df69116558d81ce6f1c65fb400fc62de037f670d85f23f392c1451d43341c59bc342bc31842c8582", + "0xaf888b384c52d9e04e4db6c4e507c2037eb5857e9bcc33acf84fc3a02d93cbde8cce32141fce9f5fec715b5f24d56356", + "0xa7822bbc3c236fd58bd978f0fc15fe0b60933a0c953db6436a233441219418090ae0c07c490a6548e319029771cdaba7", + "0x8c53729f750922e5eb461774be8851a3f40fe42eed170881cc8024d590bf0a161d861f5c967144d15cdcdc3dc6b5cf88", + "0xa052a25a4aeab0d5bb79bc92a6ae14b5ad07d1baca73f4f6684ccecfc7ea69bc21eadeb9510452fdba116c0502dd698f", + "0x923946b83d37f60555dbac99f141f5a232728c6eb819a37e568c8c6e4d9e97a4229fb75d1de7e9d81f3356f69e6d36f1", + "0x8cab82cf7e415b64a63bd272fe514d8b1fa03ba29852ec8ef04e9c73d02a2b0d12092a8937756fdec02d27c8080fb125", + "0xb1123314852495e8d2789260e7b3c6f3e38cb068a47bdf54ed05f963258d8bcabaa36ccbea095ba008e07a2678ec85a7", + "0xa685b779514961e2652155af805996ceb15fb45c7af89c5896f161cac18e07b78c9776047c95b196362c9ad5430bcb22", + "0xb734dd88f6cc6329c1cb0316c08ade03369a11dc33191086c6a177cf24540c7ceee8199b7afa86c344d78d513f828e81", + "0xb0bf492fb136ecdb602c37636ed4deef44560ab752c0af5080a79c9f76a1f954eba60a0bf6ba8bd7b8cac21848c29741", + "0xa5c74682323e85ac20f912ab9c1d6e1b9246c4c829dca40c8a7d58ec07ea0ad3524be30623f351269552f49b65a1245c", + "0x837403b9cf830fb33ecc11a7c8433e07745973c36acdeb3fc9ea8f7d8d690d462e1250b7410f79f2f4180fe8f3962a4f", + "0xb03d64b944d49c83608f2c5b9c14070c025f7568c4c33d4eeb1da31d07f0bc5897e498b35b50d557ee129f0c3c68e254", + "0x827272aab8bf757e2483156e00fbebe1093a58070dd3af9855bbf946c7abfb9c8a850a6a8acda8c620902f391f968b8f", + "0x84c4eb863a865282d321302d06b362f8bd11c2bb0090f90ebffedd3eb3e7af704cff00d39a6d48cbea4262942e95200b", + "0xb044eb91653dc55dce75c8d636308a5a0dae1298de4382d318e934140a21ca90e8a210e06fdf93aadbbeab1c2ef3904a", + "0xa8c08955a4378522e09a351ecb21b54025a90f2936b974068e80862803e7da2b5380c4b83b4b4aad0409df8d6c8cc0cb", + "0xa763a5fb32bd6cb7d7c6199041f429782deacac22b6a8467077fab68824dd69343ebca63a11004c637b9cb3129dbf493", + "0x8c44c8afa9a623f05c2e2aba12e381abdb6753bb494da81f238452f24c758c0a0d517982f3999d2537b7279d381625ed", + "0x8613f47fda577cd3bda7c99b80cf4b2dd40699edfd3df78acb5e456dd41fd0773bc8da6c5e8cbf726a519b9fb7646ccc", + "0xb21a30d49d7e1c52068482b837a4475568d0923d38e813cea429c1000b5f79b8905b08f6db237e2eccf7ef3e29848162", + "0xb9bdf4915f3fbb8d84cdfd0deedf2c9dc5b14f52bf299ef5dca2f816988e66322df078da2c54b934b69728fd3bef40b5", + "0x993b45f389f55eba8e5ba1042d9a87242c383a066cbf19bc871b090abe04de9ff6c1438cb091875d21b8c10fac51db58", + "0xa85a95d14633d52d499727f3939979a498c154fd7ebb444b08f637b32c1caf5cca5e933a2f5d94f26851ae162707b77d", + "0xb9874c7c4be1c88a9646e0c2f467cd76bc21765b5ab85d551305f5ec0b4419e39d90703d4ac1bb01feb3b160517e97b7", + "0xad6771177fc78812904c90594712956357de1533a07fec3082ba707f19c5866596d624efc3e11773b3100547d8f6c202", + "0xa79f31921134f7197f79c43a4b5d5b86736a8d3ad5af1bdf4ad8789c2bfe1c905199c5e9f21e9f446247224f82b334f8", + "0xa7f1b6c45321222a350a86543162c6e4e3d2a7c2dce41aeb94c42c02418f0892dbd70c31700245d78c4d125163b2cd5e", + "0x92abafe3ec9dbe55c193fb69042500067eb8f776e9bf0f1cb5ab8eb12e3d34986d1204136856fb115c12784c3b8dea6e", + "0x89bc761238a4d989006ca5af5303c910c584fe7e6f22aa9f65f0718a1bc171e452c43695e9f5a591725e870770c0eceb", + "0xaa0e44c2b006a27d35e8087779411ba2f9f1966a0f5646ff6871bcf63a8b1a4a7638751b94c9b9798ccd491c940bc53f", + "0x8736fe82862b8106e7fdab7b5a964d87ec291a74b8eb1cb5a6c046a648c1b686064ef3d52297043b8940bfe870c712f8", + "0x956a3def1942f05144d8e9c3a82fd2d3610064b53b9eefde3d5594a8f705bf8f6849eb2c22181796beffeba43cc74ee4", + "0xaf27416d00cf97d5a1f4a1b6b51c010884cceca294f1151c3b684a3f83c3c8a3c30771df1166d833cbddf6c873c400c3", + "0xaac3b8dca2336fc4ffc63c362df461289e4bbd3418c621bde6c581d3ecedf66e2b3e523d4db39e3d8ba014577bf85efd", + "0x94c3a8167f62074e5b28c2bffe4b6ce645439a9a0c5da3ca1b3ee956590a465d6f84a8a4dbbe9070ffbd6bbc734e4d62", + "0x95e23ba6986d25ed4451215da05bd72c5491528271726d79a94c8cb16aef1c85b190d6c5b8a3a1191c7cafbab1dccf0c", + "0x953e3dadb5ad68f7de31ac09692948655d174fe16d88b96930ef35b331da7f1dbc4c17863cd07b4ec3135b5205891a27", + "0x915d018f18b5d63cb3301c2bb5c6e85e75a88ba80663c964d06575b6bacbbe59139d030b218ce0998271d5b28c00b26d", + "0x8c871ba3dd138a908b2f7effeea0e71df096b23e0dd47cab10b9762b250abfd1221da94a8ee884e05bdf02271fb85a04", + "0x96bad5c6ebc3080ecbe337409ae398bbeada651221c42a43ea3b7c08c21841ddbcfde544c9b8d4772de6f2ce92c0b963", + "0xb5dbcd0b1c44c62108841558ec0a48df4b327a741e208c38b1c052321eda6e6ad01af71d49dfcdd445ab6fa6f0c34e6d", + "0x97dba59219b69e8aef2659d1f10bbea98d74aefff1f6451de3f41be39acbac0122b8ff58b02e90554469e88911ec3547", + "0xb7e5682ec306478be4858296f5d03364a61f3260636a4242f984d351a02e8723378496beb30c4ca22def9c9ca193ea70", + "0x9656a7a3df4d11df3d8bc35930dff70a5e78a488ca57bba20bb06814fc390fc6c7cb3f39b22134992aad196cced577de", + "0x8b269695aa63eb56d0324ba984279dc4c88e565321f1d61d553622bd4f1910d5eff68393d3a830eb924472bd478c2aa3", + "0x9177bcd04b28c87bc0440268b4c8995c6790cad6039594971b2c177f0e197055231e776927d3fa30d98fb897a2ba401f", + "0xae0e943973482001c4f214b9da82e1c27e38aa254d0555e016095c537c835d3702bc2de5c67b234ab151e02b3b7a43a6", + "0x82fc719a7d38bf4787fe1888019ad89fbf29beb951d2fece8686d2beb9119d0c8c6d13bc598748c72c70d73d488140ca", + "0xb716dc66f87eb16b95df8066877353962d91bf98cf7346a7f27056c2a4956fb65e55cb512af278783887ab269e91cd76", + "0x81d58cd8bc6657362d724b966321cd29a1b5cdc4601a49fa06e07e1ad13b05e9f387ca4f053ed42396c508cd065c5219", + "0xb32ad0280df6651c27bb6ddbdc61d5eb8246722140a2e29c02b8b52127de57a970e1ded5c2a67f9491ae9667349f4c46", + "0xb68a2eb64cc43f423be8985b1a068e3814b0d6217837fb8fbfd9c786db9cca91885c86899c50a1242040b53bf304ced9", + "0x85887515d4e371eabb81194cbc070e0c422179e01dbda050b359bd5870449c7950e6b3947b7a4a0eb68199341cc89fc3", + "0xac5fff3c27dfbab78eb8aad37ac31cc747a82401ebf3644a4f4f5aa98d37b8bf3b3f4bd8a3428b32a127c25c9e19d239", + "0x86fceaa6fbf8913553a9e1e907fcb1f1986d5e401a7eafd353beefd1899d571454fea96ff5b2a21254d9fb693ec94951", + "0xb6778bb296d3f0de2531b67d36fdbfa21475be0ca48b9dfcc38f396c41b557823735ed0b583e525a2bae1fe06e04058c", + "0x898088babeb5b9866537d6489f7514524c118704abd66b54210dc40a1c1ddb0a1edf7fe0b6e0db53b836f1828ecf939e", + "0xb27854364b97274765f0fb8d1f80d3660d469785d1b68da05e2bd1e4b8cbbe04304804d4c8aabb44cf030eba6c496510", + "0x8c55bbf3603dc11cb78b6395ccbc01e08afcef13611f7c52956b7a65ccf9c70551bff3ae274367200be9fc2d5cb26506", + "0x947726f73cd6281cd448d94f21d3b91b96de7ad3ff039f9153befbb5f172db9f53cacb4f88c80a3db26e6a0f7a846eb0", + "0xa7b733a05e97528812d71cecb4f638a90d51acf6b8fcbc054787d6deb7e2595b7b8d1cbe1aa09d78375b5e684a2019bc", + "0x8d5ca6d161341461544c533314fe0a6655cde032c2d96f0e4ea7e41098b8b39fa075d38e2d8c74e2d0308f250d6cf353", + "0xb960e9f081393e2260b41f988935285586a26657a3d00b0692ea85420373b9f279b2f1bb2da2caae72dd2e314045f1bd", + "0x852a49c7388c10821b387c6d51617add97ba72485f52be95d347bac44c638c92e9c6a44ba0d32afc4d59178a497d944a", + "0x8412162a65147e1334ad5af512982b2b48eef565682b3f3e0bbe93fbc5e1103db9375a0c486bdb1b2c57e4cb3a8e7851", + "0x8f52c3eb5d4f1e1e82cfd2b291d4910195427603b796f6c311deb35ef14a01a57a9e6cad39619ad108f3e86f384f9e1c", + "0x88d221088f2bf0103c53e44d0d96cd7881ec2b0a965db9121a47481771a8b796edd5ac23c4f9c208a171dab301f7d3bb", + "0xb49c3235e8b3617ed08a1891b9e2bcb33dbdacceb94ca96330555b7e00904fe6a749ced9312b8634f88bcb4e76f91cb1", + "0xa85834215e32f284d6dfb0cbfd97f6cffc7b9d354e8f8126d54598bb42d7f858a2b914cf84fa664069632db2ff89a332", + "0xaa3d48eb483c6120c27d9b3e3d0178c1c942632ff54b69f5b3cfbc6ad4ff5b2b9ce6eb771fd1eea8edf4a74c97027265", + "0xa446cfded353cdd9487783b45846402b973cdeddf87e2bf10cf4661610fff35743cc25e8d3b5771dcedfb46b018a5d18", + "0x80998377b3b393ef3073f1a655ad9d1e34980750e9a5cfb95f53a221b053ddb4d6985747217e9c920735b0c851d7551f", + "0xa35ac469790fac6b8b07b486f36d0c02421a5f74ea2f0a20ffc5da8b622ac45dfccabfb737efa6e1689b4bd908234536", + "0x8fb1f6d8e9c463b16ac1d0f36e04544320d5a482dd6ffaec90ea0f02b4611aaca984828bf67f84dcc3506b69af0a00a1", + "0xb6e818d61aea62c5ed39c0a22ccbb327178feebdabda0c9927aa1549d2c5bb0637785c4aed2a6d9a7b4989fa8634c64a", + "0xb4e7208d16018bf67caafe996d436113eac619732e3f529a6efb7e6f094d8ebea55b7be0e122be075770f5957b6ea6f0", + "0xb691d38b552befac61f6d367287c38d01fec73b7f2efdb6713ca30314a37fb7c177eb111fe6bee657f2681014e07630a", + "0x9817587e418e6e7e8e97ae27067f17b55d25dfb14e98f63f530620c855d9a348c9fa571c8508e2741f902f8b9fdc0c5c", + "0xb6a6e5ca779ba140bf1d84cd5394ede8262f7479637ec0087a4b152243a1774ba916d8115ce759a3bebd1b409de5f2fc", + "0xb53d1c84ad766ff794bf497db3228efd2cc8ed5fc1958d89c1126efdff361610ecb45ea8e329b39035ab00a66c1259c7", + "0xadc31333c507c8e0f4aa2934fcdca57fd9c786722a50dbd5404e129541f7ac182cc7373bf14e1e4e06e6cf94b31b90eb", + "0xa82b7fde4642d982d95cec669efee140ad797a2442c7f6620580527d163accbf021b893446cbb8038ea82fe25b15d029", + "0x91f7acf8a8903979afa281646fdecb54aa4d2ed905748e156e92f0910de268fa29d67107d40863935d677d1de8039be2", + "0x86fea71c6d43a7d93216a92fc24dfce8521fd4534a9558b33762d002081247867a6eff54cad7116023277fb4049403ad", + "0x8ae5369a7f9f4c91f3be44b98089efd9c97c08f5bb4cd8b3150c115ecd86288fa0865a046a489c782973a111eb93966e", + "0xb6fb9e829aa2c81c2d9eac72bb2fd7f3a08e0cd763532c2ce3287444d33cf48b3621f205e9603ec58525934b61a795a9", + "0x83e35ca808d84e41fc92115e9f6e283e928c3a614e6dfc48fe78c33b6411262e7bfa731eadb1e1937bc03cff60032e1d", + "0x832fca5196c95098ad47b7d24ba2f9d042e1c73ad2273edd1c2ce36386796ccc26e8567847697f3fcc2a0536a2a2087a", + "0x8fdb7038bc8f462ab2b76bf7053362f9c030019f1b6105cf42219a4e620ecc961e3eacb16a8e581a562a97f1418b0128", + "0x8d3a5a404b51b1ad8ce3b23970e0d5cc57b573922341008e3a952a1dd24a135e19e55b79d86a70cfd82e1c0e9630f874", + "0xba00c025c1c21c57c03cdfc0bfd094b35422281ff0a64b68b240617aa58c6b18800af5f2047d3ff9068bbe987d6c7980", + "0xb468f0dd51964b3806b0aa04f3fe28a035e8f5567fc7d27555be33d02701a838b8dbfe1348b6422c4eac46d2c75c40c7", + "0x8a73a18c97da9958903c38584b08d0e7e26993a5d9b068a5e0e1ee0d8a873942745cf795f94f7a3d3ba88790a9fbb2f6", + "0x953a0a40c2c8102723736854d13b228698c14a02d85c8d2e61db1a768019ac305faf0d5db62ac976430ce087a5b20f1e", + "0x8998219da6b34f657cb8a621c890a52cb98c2bc0f26f26e2af666eebeadadc5e8bdf4f830a91d04aca8ce186190152c8", + "0x8941e08c3155ad432236ed05460420a05dd0aaab30477493ffb364b14c00ea5b9183d30d3442b6321d2d20c36e4f5c7e", + "0x93f293ff7fb56cf5b03aee6f3ad2ad78444398ed5b3be56d7bf5b56b5aa5a2b980d13895dd57a5726d1b067c20cc55e2", + "0x84a16f313e3f75e31824f58d19ab24c6611fb4c75140a7cadc3c166f68819547c1d0ff7f7d13f5d8ae30dff1d80e2aa4", + "0xb6e3e830b15039d3e28b08f5465bb089eade11ee3bd80afe39e010df7db1fcf0c56d698717677a41ddbc91eeaf6544d3", + "0x95e928e6dfff51351281568ae72da7d1edeb6e9fe01f30af0499e7505ba35a22b5bb919d41bb809a432dce83f3977663", + "0xaabeeb60ca46f9b0232ff82ea7766dcab8cc5aaf9d23539f30174f9486640bc9312868ca493b59b314519fc399973e47", + "0xb393a11e957d0bbb3ecf617b075b5906a3450b348e62916c04791b366f0a7397cccd6648440ac544bc30526e1f95aad8", + "0xabb5bfc3964a6d246da60bd809d0ea6daf4f8222efdc12ceb6730194e85f413ee7eb03bae300abf7ea900dbbc3d08971", + "0x96c1bd1d1d216a4bfbcf000c123f296c0d31e1684e9e3884c14df23bf528c8d599f82bb98fcea491716b617216a8e0be", + "0x92d1e570a56f1741fd9f3d9f488cc336421c6256c14a08d340a63720be49b0029e3780e3e193a2e22bf66cc652fa22a3", + "0x8769c08551e3a730e46f8e5d0db9cf38e565a001dfb50db3c30fa7fa0e98b19438edc23c6e03c8c144581b720d7b33a4", + "0xb850bd67fdf5d77d9288680b2f6b3bc0f210580447fb6c404eb01139a43fccb7ed20051999ae2323ea5a58de9676bfb4", + "0x80285da7a0aaf72c4528a137182d89a4db22a446e6c4a488cf3411937f4e83f7b00ec7549b0b4417682e283f91225dfe", + "0x80520368a80b97d80feb09dbc6908096c40ff7120f415702c1614d7112b0b57f6729581c71f4a3ce794ac959a46494ff", + "0x9817b4c27a490b1cd5a6337e7bc7e8005fa075dd980c6bf075ddfa46cd51cc307ad1d9f24e613b762a20fc6c877eab41", + "0xad66bda1a3034ec5e420b78107896ecf36126ce3ef9705163db259072dfa438c6107717a33572272062b9f60cb89557c", + "0x876114ef078c2915288e29c9abe6b0ad6a756b5ee2930ba1b8a17257f3f0557602d1225e8aa41ce8606af71ada2a971b", + "0xaa3d6cde4c3b9d3d5d0c77a33e67f182a3e1cf89b0921423b2024236171955b34afc52b1f25b1dad9da9b001371771d7", + "0x984d3e3a72412d290e3459339757af7520d1739c7af0cbcf659c71999328db44f407d92e8a69fea11625612c49eac927", + "0xae890d0faf5bd3280dcad20a5f90e23a206661be8842375fea2ab22aadc500849ffbc52fe743b376d46bb926cedae6a6", + "0xb1f231f3f4d710c3fe80099faeb56dac67c1baf53b8fe67a9920fe4f90e52cb9a4bf19211249a6456613b28efe337f18", + "0x8caa54b418ba609d16520af3dff2e96d5f2eeb162c065a1763beb926547b2cfb3ae41d738db2c5681a9bc8bc9e6b9a1a", + "0x932157ff56c5ac29cf6cf44f450c882b3acfbb9f43d12d118da3d6256bde4e6eb3183aea304ab6967f37baa718ffec99", + "0x9360bed8fc5b6aac36aa69473040689bfc30411d20ffb7275ef39b9ff5789f9055d149383ce9f0f7709a1f9d683adbfe", + "0x98b5b33209068335da72782179d0c7aeeabe94b5560a19d72088fe8323e56db7ce65debe37a97536b6b8a0ca3b840b61", + "0x89a385c11be40064160b030a1bb28c3921fc8078522618a238c7ea0f86f34717ed9af9b4e2e20f5128e5f7fc66ad841e", + "0xb615703cbc64b4192990cc7e4903b74aed6a0076ce113b59ef7719197ffa46fb29eb78ca56b49873487432d0625c0faa", + "0x90f0d77abae9d3ad73a218e5ccec505ad108ea098451461567ae8ef9661606ca8e78df53b5d628b20b7037bd24622330", + "0x92e0e7cc4dfadc5fa0ee6da0c8de0493030db6e54ba0317f52f232a6708b732068b6077bd13a17eb7eb40b88368085b5", + "0xa24dad20094985bfccc6df1343506ed3bf9dcbdf4b2085a87627a5d71f7568db067304e465f8f380c5c88e8a27291a01", + "0x8629a45a10619354c84bdc2f6c42f540eab5a46f53f2ae11970433d7a2aef007897590bf31dfba1c921614c6d6fe1687", + "0x84ac64040d4206f82b08c771f375da4b7d752e41d2aa0da20ce845f6bc1b880a855d3ee966bca19b8ec327b4b43e7f0e", + "0x9608e6050c25996c052509f43f24a85cdf184135f46eaac520a9a6e78e0d44a6cee50ebc054048c708aefde8cd6651c2", + "0xa32032b0e0d7cc35e480c328f315327f9385adb102a708c9ba637878deb74582ae26bb6d6e5f8c9e3a839b0e0154b82a", + "0xb7e3c78d63acc6564a49e9f00b0a820b56d4f37a2374af1f7f1d016268011df9e7af0670ed2b0eee961f15aa948328dd", + "0x8b88bfdd353acc91ad0d308a43e5fb40da22c228f2fe093c6d6904d70f69c6203f56636ed898b05df51d33f1095ef609", + "0xb1d7a430c51fc857af55047683fc18c453b013527196c5e1bf776819a3dffca802217e9249ae03f084e2ea03ad67fcc2", + "0x80558e28a819ddb5e72e97c54be0f57c173ccf78038d360d190b7f1350a19577b8e3f43fa2f7bf113a228cd3b965b2e4", + "0xb4b2ec44e746c00dfc5661ba2514930934fc805cdc29adc531c02d28ce3cc754414b0485d4ee593232cd1175f357ad66", + "0xb57cee5d32835f76572330f61ccd25a203f0e4a7e5053d32965db283aad92f287645533e8e615137208383ec51b1fd99", + "0x930256086b419a8a6581c52590d0dbd9f8a3564c79424198fca3866b786df2f6098a18c50dc4abd20853a7184b1ce15d", + "0x8e75fd01181cffcd618a983492390f486e8c889972a46c1f34a4e1b38f384e8e4efc7e3c18533aa2057da9f9623e2238", + "0xb375d927dd988429f9e2764e5943916131092c394fce13b311baa10f34b023dd3571da02553176091a0738cc23771b9a", + "0xb9e28e4c0d0477518034d000e32464852e6951c8db6f64ccdb1d2566f5094716213fbf2fc0e29ac88d0e79f725e3c926", + "0x963981e99392afbd2b8318d5a6b2b0cc69c7f2f2f13f4b38dddbfedb2b0eaf0584aecfcbda20a4c60789c15d77970a58", + "0xa7804e1977aa77c263c7c001afa6cf568032dea940e350d6a58ce4614f1a91c13ae1c78bfea740c229dce2444556976a", + "0x8787204177da3cde6d35cd3497fa8774d244f9faa9f4bd91b636a613a32ce2ea0326378cf9c4cf475e73ef751b355c4b", + "0x895aeef46a07152a04ec812f1aa1fd431389fa0ef6c6e96a5b833e70ea14073bc9984757a8ee456dbec9788e74e6f0ca", + "0x8d17f0e5826783440d1f0ec868003510a4d9952bfe4a638e44a36d94482ac18ba70ef7ff773bdf7a3b62d714dcf0fcba", + "0x810d5e36b31310b2e054a666d3b3f7ed16dfcb1765532d87ca2a3920316f0187303c27dd113db145d47e8961062a6c03", + "0xb4e2fb48ae04cf8580bb6a28095076c9b95e5f13122b917328f334d4ac8a8648ce442919e28319a40148987350ab5303", + "0xb85549a313544fa1eb3ceb78473b7d3d717fc85b808de7b79db7dbd0af838ebb020622a7503f1cbacab688dddb648f84", + "0x80665adee057088eae827a5fe904ec3ad77d8843cdce0322d535e0659b4abc74a4d7ddd8a94c27f2def5c34ac2c038ee", + "0xad72fc19c2ce99b5b717e35528fe7d3ac8add340b02ebeb4889d9a94c32f312a0b45ea84d21c54f84cc40ee4958b72e1", + "0x99d530c843dff89a47a5ee8c87303ab18f8a82b0d5b808fca050354b35da5c5a5594d55921c6362d6cc917d75bdc18dc", + "0x99c7286c293e1be21c5b2a669dfdfcd5aa587105d2886fc5a8eaf8984da4e907f7d7b8c2362d64a4f1621b077a2a08a0", + "0xb4a39e1a9ed5d80c9563c3ca3fadf76f5478c63a98f4346a61b930c9c733e002f3ff02bc16abfdb53d776184cc3f87ba", + "0x9378ea71b941979404c92d01fb70b33fa68d085bf15d60eb1c9fc2b5fcdee6379f5583389a3660a756a50019a2f19a69", + "0xb68e17344a2bc45b8e2e19466b86dc139afefbf9bad2e2e28276a725099ebac7f5763f3cb52002261e3abe45ef51eb1a", + "0x819e64dc412b2d194d693b9b3157c1070a226af35c629837df145ea12ad52fa8eabd65b025a63c1fb0726207a58cdde8", + "0xa5e8ff8748419466ff6df5d389125f3d46aedacf44eaf12cbfe2f68d218c7d5ab6de4a8279d13aecc25f3b1d98230894", + "0x91560d54a9715cfda9cf7133ae51c432d0bf7fcbaeb468004994e6838bfc5ddcfa30e4e780667d0c4c0376780b083017", + "0xae8adb3309cc89d79a55ff74f129bb311fe4f5351a8b87600a87e0c3ba60825f71fccf67eadcf7e4b243c619417540fd", + "0x8d92cc1a6baa7bfa96fbce9940e7187b3d142f1888bdcb09bb5c8abf63355e9fb942ac4b4819d9be0e0e822d3e8e2e08", + "0xa6e8b79fdd90c34735bb8fbef02165ccbe55ea726dc203b15e7a015bf311c9cac56efd84d221cc55eaa710ee749dbdfe", + "0xa409b151de37bddf39ce5f8aa3def60ee91d6f03ddd533fce9bf7bdbeac618cc982c4f1ffbf6e302b8353d8f28f8c479", + "0xb9693975ef82171b3b9fc318ca296e4fe6110b26cbdfd653418f7754563fa7b6e22d64f8025ee4243483fa321572bfe4", + "0xa039ebe0d9ee4a03ade08e2104ffd7169975b224061924cca2aae71464d250851e9f5f6f6cb288b5bf15df9e252712a6", + "0xb27834db422395bd330e53736a001341ce02c9b148c277dabac67dc422741bfa983c28d47c27e8214cd861f2bad8c6f6", + "0xa2bafaf4e2daf629fd27d7d5ac09fb5efc930ff2ae610f37519808683aa583fe1c6f37207daf73de1d8a164f79a0c981", + "0xb856cee1cfcf5e50db9af4ab0aed3db2f43c936eaea369b5bba65582f61f383c285efbda97b1c068c5d230cbe94f7722", + "0xa61ab205554c0550fa267e46a3d454cd1b0a631646b3df140623ff1bfffaa118e9abe6b62814968cc2a506e9c03ea9a0", + "0x8c78edcd106377b9cbdfa2abd5278724aed0d9e4ae5869b5d2b568fdabb7804c953bae96294fcc70ef3cd52ba2cbe4ed", + "0x8570869a9bbf6cc84966545a36586a60be4d694839f367b73dfc40b5f623fc4e246b39b9a3090694aa2e17e652d07fd1", + "0xa905b82c4da8d866a894da72315a95dc98faa3c7b3d809aef18f3b2be4801e736a1b79a406179e8cac8f74d27e71ac52", + "0xa8eb8679ff1a64908515f6720ff69434cb33d63aeb22d565fde506618908b1d37585e3bd4d044fd0838b55787af06b42", + "0xaf4d86b2fbd1684a657dffe4210321a71e6ae560c144d44668d1f324dc9630e98348c3d444622a689327c1a59cc169dd", + "0x80359c6eab16954559ab0e6a1fee9a0526c45d3cae1a371159a2e3aa9b893afdc3a785c9559a5fd9cd8cd774234bf819", + "0x8d4e5ff81eb5d17bbe8ae6416538ca51a9427ce142b311f5cbb14febbbbb9c1ffc6489fd625b9266264c366c12a9d997", + "0x92e181c66489c5fa063ba2a1a354b6fd3439b8b4365a8c90e42e169bfaa1fb5766bf3e0fe804399d18bc8fbcafb5c3b1", + "0xa9ddf229360a095393885083716cb69c819b2d7cfb100e459c2e6beb999ff04446d1e4a0534832ae3b178cbe29f4f1d3", + "0x8e085ef7d919302a1cc797857b75cff194bdbc1c5216434fa808c3dea0cf666f39d9b00f6d12b409693d7a9bd50a912c", + "0x916dc4dc89e5e6acf69e4485a09fc66968f9b292eac61a146df1b750aa3da2425a0743d492179f90a543a0d4cd72c980", + "0xb9cbf17e32c43d7863150d4811b974882da338cf0ed1313765b431b89457021dd1e421eeaa52840ef00551bb630962dc", + "0xa6fb875786daec1a91484481787093d8d691dd07e15c9c0c6ae0404bf9dc26083ed15d03c6d3fe03e29f28e20da21269", + "0xa870fcb54b9a029e8086de9b08da8782c64ad2cc2e7fdf955b913d294038bb8136193256b85267e75a4ca205808a76b4", + "0x99883f057e09b88bf0e316f9814c091837fd5c26eeb16fec108c9fed4b7a2bd1c783dac0e4242b5a906621ab606c1e50", + "0x85d89069ca3190577dab39bbec43c16bf6dbca439ad3eebd8f5e9f507d84c3c43e77fd6323224582566a3aa2c8018951", + "0x9363ba219e0003f6e8a9d8937b9e1449e4b2c5cd57194563b758bea39deab88778e8f8e4f7816970a617fb077e1e1d42", + "0x820622f25553c035326145c1d2d537dc9cfd064c2f5bdf6d4ec97814de5fe9a0fbd443345fa2ea0a9d40d81d3936aa56", + "0x87e31110aaf447e70c3316459250e4f7f8c24420c97828f9eb33b22107542c5535bdb48b0e58682dd842edea2886ff08", + "0x95bf80cac6f42029d843d1246588acb40a74802f9e94b2bf69b1833936767e701ef7b0e099e22ab9f20f8c0c4a794b6c", + "0xa46ecf612b2763d099b27fb814bd8fdbaee51d6b9ac277ad6f28350b843ce91d701371adfaaf4509400dc11628089b58", + "0x8604decf299fb17e073969708be5befeb1090ab688ad9f3f97a0847a40ea9a11bbcfc7a91e8dc27bc67a155123f3bd02", + "0x8eb765c8dc509061825f3688cb2d78b6fef90cf44db33783d256f09be284bc7282205279725b78882688a514247c4976", + "0xb5c30b2244fa109d66b3a5270b178960fdec47d31e63db0b374b80d2b626409eb76d2e8d1ebf47ef96c166743032fc5e", + "0xaab01e76290a7e936989530221646160bf8f64e61e79282e980c8c5dcaaa805ff096efd01d075a2c75917a3f4bf15041", + "0xb9d79671debd0b83d0c7c7c3e64c0fb1274300564b262771f839b49218501e7f38ef80cae1f7e5a3c34acdc74c89dab6", + "0x92c0eaceadf036b3b9dfd2712013aba3dd7c30b7760f501f52141618265baa31840fe77850a7014dc528f71f8cf39ce6", + "0xb3cdd098059980455dd5b1c04182df1bd12fa844a866f02a9f8a86aab95b59945baa9af99f687410bffc5b07153cb23c", + "0xb361b73a62f71256b7f6ea8e0f6615e14fc5a06ee98b928ab3c9dd3eef9d9d30070e9855c82b7facb639cacb3401e01f", + "0xb9c85fc0f25a3271cf28b1ca900078eaaa66cbab0a3e677606e898ac32781a2dfce4d9cbd07404599e2c3c02fa161c9d", + "0xac5b4fdac2a0b2e6430d9fc72bde4249d72183b197fc7347bb1546ae6f544426686bbe0caec3ee973b6836da5e831c44", + "0xb675aebf24b92e398e166f171a6df442b3f5919b6bee192f31675a5e8eeb77d34c6590a6f0c0857417e0f78cfb085db8", + "0xa9bef942044d8d62e6a40169f7dc7b49e40cd0d77f8678dd7c7bae6f46c46786f9b1e319a3fa408f22a54fd2a4d70804", + "0xa20d19cd917d5102ae9ca0cf532127d2b953aa3303310e8a8c4b3da025dded993a47e3a28e6b02acfadb6d65dc2d41a3", + "0xa47fdb04059b83b2afb86a47b2368bbd7247c337a36d3333b6e5ef2cc9476a92c4907e4c58a845c9ef9b497621e0b714", + "0x94a9e9ffc14b411e11a4ffa59878d59460263589003dc7b6915247c549f67feede279bf3645fdd92379022fb21e3caeb", + "0xb92e1177dd9ecdaf1370c71b14954219cf0851f309bc216d5907a4e2e84e0df3457018224150c142cc6bf86644bb4b73", + "0x8bc57fadd68a265b7df9b42227a9c0968db7b1bb50dc12f7d755505779f1ff2c408672b3091e903366acc9ce15d19fb6", + "0xb6b5efbe1ac4e1bd2e8447c45000d09397b772ca5496acc447b881022608a41c4f60388814607a01890190105bee7be3", + "0x95f7c85fd614df968f8ccf8d086579c9e1cec4644ecf06da26e3511cb39635a7326b3cec47bd51cf5646f1c660425e9c", + "0xb81765fb319bcdc74b4d608383ccb4af7dd84413b23af637be12e2827a75f7e4bcd14441cf979ed9038ae366fbb6f022", + "0xa120ea76cda8c6c50c97035078f6648afe6537809bdba26e7c9e61de8f3070d2347160f9d34010effbf2ec7e94f5749f", + "0x92c1b8631953b40d3cc77eee2c72a064b999c09a9b92c11d8fa7b4072966273901c9dba25f9f79f384d9f11a56f3fc7a", + "0xa4b00dc0ab67b2300abc9c516e34daf444d6497b066a90cfe3381ed2812304ed37b14f3b948990443dc6c1cf1bed460c", + "0xa9e9f7e13c9f031bc7b9e6f1417c7abcc38894fe7d3f54869ee277afd2efa3e6fb50757dd36c8c94d591e0abdea322cc", + "0x84f3e98f831792b5ad14bcfe62a4c9f296476c6087c4c1ec7767fc642fbca141ff6a3deeb8b4d4106a9cda5a9937eea0", + "0x8eb1a7931bbea9a714226fd74b0100ab88355287d9b0a349c095e9b5809b98f237ffd706bce7d67a770da355fb9cec7b", + "0x9738ef8739e1742c1f26b51a1621be0b89d37406a370c531e236f635c7064c661818817bb3858908986aa687b28b21be", + "0xa9cf3ce8501b003ccaf57552a4c4ec31081e44526d3aa3791d3dc4a7e438a357c0956f93c500356186d8fd4588ffac5e", + "0xa7af6a219cca59225839a9de5b19263cb23d75557d448bc7d677b62591a2e068c45e5f4457cceb3e9efa01d0601fc18a", + "0x972a24ece5eda7692cbb6fb727f92740451bc1281835e2a02931b2b05824a16b01dbe5edd03a0ed5b441ff25a5cc0188", + "0xb21d1ec7597ce95a42f759c9a8d79c8275d7e29047a22e08150f0f65014702f10b7edce8c03f6e7ab578ce8c3b0ec665", + "0xa13a1c7df341bd689e1f8116b7afc149c1ef39161e778aa7903e3df2569356ad31834fa58ceb191485585ce5ef6835c3", + "0xa57bdb08119dc3bc089b5b2b5383455c4de0c2fcdac2dcfa21c7ac5071a61635ff83eceb7412f53fab42d1a01991de32", + "0xb2968748fa4a6921ee752d97aa225d289f599a7db7a222450e69706533573ded450380c87f8cdd4a8b8c8db1b42b5c97", + "0x8718ec04e0d5f38e3034ecd2f13dfde840add500f43a5e13457a1c73db0d18138f938690c8c315b5bcbeb51e8b9a2781", + "0x82094789e26c4a04f2f30bdb97b9aecca9b756cbd28d22ab3c8bed8afc5b2963340ddfc5a5f505e679bf058cbc5dcbb8", + "0xa35b8a566dd6ab67eddc2467906bffc76c345d508e52e9e4bb407b4f2b2c5f39b31d5a4bf5022f87bf7181dc6be2fe41", + "0xa8c93b1e893d4777c0e3a1b4bef3be90c215781501407c4011457fc3240e13524b4d2bea64a6d0a3efe3f3b0dae9b8ab", + "0x877095ad18b1e5870818f7a606127ba1736a0b55b0dbcd281ec307c84b08afc0c9117e3a880fe48bfc225fbf37671a97", + "0x84405ee0421ed2db1add3593df8426a9c1fcc8063e875f5311a917febc193748678dd63171d0c21665fb68b6d786c378", + "0xa52cdc8209c3c310bed15a5db260c4f4d4857f19c10e4c4a4cfe9dfc324dfac851421bb801509cf8147f65068d21603c", + "0x8f8a028a70dda7285b664722387666274db92230b09b0672f1ead0d778cee79aae60688c3dfd3a8ed1efdeda5784c9d4", + "0xa0be42fecc86f245a45a8ed132d6efc4a0c4e404e1880d14601f5dce3f1c087d8480bad850d18b61629cf0d7b98e0ae0", + "0x83d157445fc45cb963b063f11085746e93ab40ece64648d3d05e33e686770c035022c14fdf3024b32b321abf498689ad", + "0x8a72bbf5a732e2d4f02e05f311027c509f228aef3561fc5edac3ef4f93313845d3a9f43c69f42e36f508efcc64a20be0", + "0xb9ca29b0ec8e41c6a02f54d8c16aebf377982488cbe2ed1753090f2db4f804f6269af03e015d647a82ef06ffaa8cba6c", + "0xb4df3858d61bbb5ded1cf0be22a79df65ae956e961fbb56c883e1881c4c21fe642e3f5a0c108a882e553ac59595e3241", + "0x86457d8890ac8858d7bab180ef66851247c2bf5e52bf69a4051d1d015252c389684fcc30bb4b664d42fbf670574ab3a3", + "0x86d5576ea6dfa06d9ebce4cd885450f270c88a283e1e0d29cab27851c14ed2f00355e167b52e1539f1218ad11d8f13dd", + "0x883ad1364dc2a92388bfafaa9bc943c55b2f813525831e817a6208c666829a40455dde494eba054b2495a95f7ce69e8a", + "0x8942371e6925231c2c603b5f5a882d8404d39f0c7c4232557c2610b21c2c07f145466da798ea78b7932da2b774aa3128", + "0xa799eb71496783cc7faf12c9d9804bf6180699a004b2f07fc5cc36840f63ce7eee7dde9275819a9aa3f8d92dc0d47557", + "0x8eb3fb5c769548ee38c7882f51b959c5d5a42b5935269ccf987d6ddbb25a206e80c6000bcc328af149e0727c0b7c02c0", + "0x8f3910d64e421a8f2d8db4c7b352ba5b3fc519d5663973fea5962efe4364fb74448770df944ef37ffe0382648fb56946", + "0xb41413e0c26ff124cf334dab0dc8e538293d8d519d11cc2d10895a96b2064ac60c7da39f08589b38726cffa4c3f0bfef", + "0xb46ef2eb10abae0f35fa4c9c7ee2665e8044b8d9f91988a241da40fd5bbc63166925582151941b400006e28bbc5ba22a", + "0xb8baa8b4c420bb572a3b6b85479b67d994c49a7ebfe1274687d946a0d0b36dfed7630cfb897350fa166f5e2eff8f9809", + "0x964b46d359c687e0dcfbdab0c2797fc2bd1042af79b7418795b43d32ffca4de89358cee97b9b30401392ff54c7834f9f", + "0x8410d0203d382ebf07f200fd02c89b80676957b31d561b76563e4412bebce42ca7cafe795039f46baf5e701171360a85", + "0xb1a8d5d473c1a912ed88ea5cfa37c2aea5c459967546d8f2f5177e04e0813b8d875b525a79c29cb3009c20e7e7292626", + "0xafaab9a1637429251d075e0ba883380043eaf668e001f16d36737028fded6faa6eeed6b5bb340f710961cee1f8801c41", + "0xaef17650003b5185d28d1e2306b2f304279da50925f2704a6a3a68312f29fe5c2f2939f14e08b0ba9dee06ea950ad001", + "0x97bcc442f370804aa4c48c2f8318d6f3452da8389af9335e187482d2e2b83b9382e5c297dce1a0f02935e227b74e09a3", + "0x8a67a27b199f0bcd02d52a3e32f9b76a486b830ec481a49a4e11807e98408b7052b48581b5dd9f0b3e93052ec45dfb68", + "0xb113bf15f430923c9805a5df2709082ab92dcdf686431bbad8c5888ca71cc749290fa4d4388a955c6d6ee3a3b9bc3c53", + "0x8629ca24440740ce86c212afed406026f4ea077e7aa369c4151b6fa57bca7f33f9d026900e5e6e681ae669fd2bd6c186", + "0x933a528371dcecc1ec6ded66b1c7b516bd691b3b8f127c13f948bfbcda3f2c774c7e4a8fbee72139c152064232103bdf", + "0x8568ddd01f81a4df34e5fa69c7f4bb8c3c04274147498156aec2e3bd98ea3e57c8a23503925de8fa3de4184563a2b79e", + "0x8160874ec030f30fda8f55bcf62613994ff7ed831e4901c7560eac647182b4a9b43bfaff74b916602b9d6ae3bfcaf929", + "0xae71c48d48cf9459800cdf9f8e96bc22e2d4e37259e5c92a2b24fbe2c6ca42675e312288603c81762f6ceb15400bc4c9", + "0xb05f39bb83fda73e0559db1fd4a71423938a87ad9f060d616d4f4a6c64bf99472a2cbfb95f88b9257c9630fc21a0b81f", + "0x80c8479a640ed7a39e67f2db5ad8dfd28979f5443e8e6c23da8087fc24134d4b9e7c94320ffa4154163270f621188c27", + "0x9969ba20ee29c64cb3285a3433a7e56a0fe4ddc6f3d93e147f49fe021bed4a9315266ebb2fb0eb3036bb02001ae015e6", + "0xa198c89fef2ab88e498703b9021becc940a80e32eb897563d65db57cc714eaa0e79092b09dd3a84cfab199250186edcc", + "0x8df14a3db8fe558a54d6120bad87405ba9415a92b08c498812c20416c291b09fed33d1e2fcf698eb14471f451e396089", + "0x81e245ef2649b8a5c8d4b27188dd7e985ef6639090bdc03462c081396cf7fc86ed7d01bfe7e649d2b399255e842bdc21", + "0x8659f622c7ab7b40061bcf7a10144b51ad3ab5348567195924f2944e8c4ce137a37f1ba328e4716c10806f3fb7271689", + "0xa575d610fc8fe09334ca619ecdadf02d468ca71dd158a5a913252ca55ea8d8f9ce4548937c239b9cb8ab752a4d5af24a", + "0x94744549cd9f29d99f4c8c663997bdfa90e975b31f1086214245de9c87b0c32209f515a0de64d72d5ef49c09b0a031fa", + "0x80a8677862b056df59e350c967a27436c671b65d58854e100115bac9824ba177e94c2a1bfcaa191a071b9cefdbee3989", + "0x91be9a5504ec99922440f92a43fe97ddce2f21b9d94cd3a94c085a89b70c903696cec203bbab6d0a70693ba4e558fb01", + "0x8c5a0087bcd370734d12d9b3ab7bc19e9a336d4b49fc42825b2bfedcd73bb85eb47bf8bb8552b9097cc0790e8134d08c", + "0x933aa9e6bd86df5d043e0577a48e17eea3352e23befdbb7d7dcac33b5703d5ace230443ac0a40e23bf95da4cc2313478", + "0x984b7ee4bd081ee06c484db6114c2ce0ba356988efb90f4c46ff85ed2865fb37f56a730166c29ef0ae3345a39cdeae7a", + "0xae830f908ea60276c6c949fb8813e2386cf8d1df26dcf8206aa8c849e4467243e074471380ed433465dc8925c138ea4c", + "0x874c1df98d45b510b4f22feff46a7e8ed22cfc3fad2ac4094b53b9e6477c8dfc604976ca3cee16c07906dece471aa6c6", + "0xa603eb60d4c0fb90fa000d2913689126849c0261e6a8649218270e22a994902965a4e7f8c9462447259495fe17296093", + "0xa7c73d759a8ad5e3a64c6d050740d444e8d6b6c9ade6fb31cb660fa93dc4a79091230baccb51c888da05c28cb26f6f3f", + "0xa4411b79b6a85c79ea173bd9c23d49d19e736475f3d7d53213c5349ebb94a266d510d12ba52b2ac7a62deaaaec7339b8", + "0x943b84f8bbcee53b06266b5c4cd24d649d972593837fe82b0bf5d5e1bbc1a2bf148e1426c366d7c39ab566b10224cadc", + "0x8300012096a8b4cefecc080054bf3ceb0918162ba263c6848860423407796b5eb517170c0bad8e4905ac69a383055a21", + "0x8244a1e3ad41908c6f037e2f8db052e81f281646141334829f36c707f307448b9ab79a7f382a1e8d86f877c90b59271c", + "0x8eca1b74687802ecc36a5d39e4516a9dee3de61a2047252d9ed737b49e0090c386e9d792ac004c96337681c7f29a16ad", + "0xb70fa47535f0524835039a20036c61e77f66146ad79d3d339214d8744742db41ceeb577c829d000011aeafbb12e09579", + "0x84b3abbce48689f3adbb99889c7fd1f3e15ab455d477e34f5151c5c1c358ed77a5b6a581879f7e0f1f34106e0792e547", + "0xab45ecb58c0ef0dbce3d16afc6ac281e0d90ec48741ea96a141152647e98fcc87f3a3ff07ba81f3179118453ce123156", + "0x90d231a145ba36a59087e259bbfc019fa369201fcfeaa4347d5fd0a22cd8a716e5a797f3cc357f2779edb08f3b666169", + "0xa4f6074d23c6c97e00130bc05f25213ca4fa76c69ca1ace9dece904a2bdd9d987661f5d55023b50028c444af47ff7a08", + "0x933af884939ad0241f3f1f8e8be65f91d77ac0fb234e1134d92713b7cfb927f1933f164aec39177daa13b39c1370fac8", + "0x80d1db6933ce72091332ae47dc691acb2a9038f1239327b26d08ea9d40aa8f2e44410bbda64f2842a398cbe8f74f770f", + "0xa7a08605be2241ccc00151b00b3196d9c0717c4150909a2e9cd05538781231762b6cc6994bebbd4cddae7164d048e7b2", + "0x96db0d839765a8fdbbac03430fa800519e11e06c9b402039e9ae8b6503840c7ecac44123df37e3d220ac03e77612f4e4", + "0x96d70f8e9acd5a3151a8a9100ad94f16c289a31d61df681c23b17f21749c9062622d0a90f6d12c52397b609c6e997f76", + "0x8cf8e22273f7459396ff674749ab7e24c94fe8ab36d45d8235e83be98d556f2b8668ba3a4ec1cb98fac3c0925335c295", + "0x97b7e796a822262abc1a1f5a54cb72a1ea12c6c5824ac34cd1310be02d858a3c3aa56a80f340439b60d100e59c25097d", + "0xa48208328b08769737aa1a30482563a4a052aea736539eceab148fa6653a80cb6a80542e8b453f1f92a33d0480c20961", + "0xb612184941413fd6c85ff6aa517b58303b9938958aa85a85911e53ed308778624d77eadb27ccf970573e25d3dfd83df7", + "0xb3717068011648c7d03bbd1e2fc9521a86d2c3ae69113d732c2468880a3b932ebec93596957026477b02842ed71a331b", + "0xa0ad363e1352dcf035b03830fef4e27d5fd6481d29d5e8c9d51e851e3862d63cdcbaf8e330d61c1b90886921dac2c6fd", + "0x8db409fdacfa4bfdaf01cc87c8e97b53ca3a6e3a526d794eaad1c2023f3df4b888f1bf19fee9a990fe6d5c7c3063f30c", + "0xb34d6975310ab15938b75ef15020a165fc849949065d32d912554b51ffa1d3f428a6d1a396cb9329367670391de33842", + "0x9117285e9e6762853fc074b8a92b3923864de2c88c13cea7bab574aaf8cdd324843455d2c3f83c00f91f27c7ecc5592a", + "0xb4b2e8f190ea0b60819894710c866bf8578dd1b231ae701d430797cc7ede6e216e8ca6a304f3af9484061563645bf2ab", + "0x8c493c6853ab135d96a464815dd06cad8b3e8b163849cdefc23d1f20211685753b3d3e147be43e61e92e35d35a0a0697", + "0x9864d7880f778c42d33cf102c425e380d999d55a975a29c2774cad920dfddb80087a446c4f32ed9a6ab5f22ec6f82af0", + "0x90f67fe26f11ca13e0c72b2c2798c0d0569ed6bc4ce5bbaf517c096e7296d5dd5685a25012f6c6d579af5b4f5d400b37", + "0xa228872348966f26e28a962af32e8fa7388d04bc07cfc0224a12be10757ac7ab16a3387c0b8318fcb0c67384b0e8c1a4", + "0xa9d9d64bba3c03b51acf70aeb746a2712ddafe3b3667ae3c25622df377c2b5504e7ab598263bec835ab972283c9a168b", + "0x932128971c9d333f32939a1b46c4f7cf7e9d8417bd08dc5bd4573ccbd6ec5b460ac8880fb7f142f7ef8a40eef76d0c6d", + "0x964115e7838f2f197d6f09c06fbb2301d6e27c0ecdf208350cf3b36c748436dac50f47f9f9ac651c09ab7ad7221c7e43", + "0xa5941f619e5f55a9cf6e7f1499b1f1bcddcc7cf5e274efedaaad73a75bc71b1fc5c29cd903f6c69dc9a366a6933ca9d1", + "0xa154bf5eaec096029e5fe7c8bf6c695ae51ace356bb1ad234747776c7e1b406dee2d58864c3f4af84ed69f310974125e", + "0xb504e6209d48b0338ab1e4bdab663bac343bb6e0433466b70e49dc4464c1ec05f4a98111fd4450393607510ae467c915", + "0x813411918ea79bdde295393284dc378b9bdc6cfcb34678b9733ea8c041ac9a32c1e7906e814887469f2c1e39287e80f8", + "0x8be0369f94e4d72c561e6edb891755368660208853988647c55a8eed60275f2dd6ee27db976de6ecf54ac5c66aaf0ae6", + "0xa7e2701e55b1e7ea9294994c8ad1c080db06a6fc8710cd0c9f804195dce2a97661c566089c80652f27b39018f774f85e", + "0x956b537703133b6ddf620d873eac67af058805a8cc4beb70f9c16c6787bf3cc9765e430d57a84a4c3c9fbdd11a007257", + "0x835ae5b3bb3ee5e52e048626e3ddaa49e28a65cb94b7ecdc2e272ff603b7058f1f90b4c75b4b9558f23851f1a5547a35", + "0x85d67c371d1bf6dc72cca7887fa7c886ce988b5d77dc176d767be3205e80f6af2204d6530f7060b1f65d360a0eaeff30", + "0xa84a6647a10fcef8353769ef5f55a701c53870054691a6e9d7e748cbe417b3b41dbb881bae67adc12cb6596c0d8be376", + "0x87ffe271fc0964cb225551c7a61008d8bcb8b3d3942970dbcc2b9f4f9045a767971880368ea254e2038a3a0b94ecf236", + "0x964bb721c51d43ee7dd67c1a2b7dd2cc672ce8fad78c22dcddb43e6aab48d9a4a7dc595d702aa54a6fb0ffabf01f2780", + "0xa89b3f84bb7dcbe3741749776f5b78a269f6b1bebb8e95d3cc80b834fd2177c6be058d16cacfd0d5e1e35e85cde8b811", + "0xb4314538e003a1587b5592ff07355ea03239f17e75c49d51f32babe8e048b90b046a73357bcb9ce382d3e8fbe2f8e68b", + "0x86daf4bf201ae5537b5d4f4d734ed2934b9cf74de30513e3280402078f1787871b6973aa60f75858bdf696f19935a0e2", + "0xb1adf5d4f83f089dc4f5dae9dbd215322fa98c964e2eaa409bf8ca3fa5c627880a014ed209492c3894b3df1c117236c4", + "0xb508d52382c5bac5749bc8c89f70c650bb2ed3ef9dc99619468c387c1b6c9ff530a906dfa393f78f34c4f2f31478508a", + "0xa8349a5865cb1f191bebb845dfbc25c747681d769dbffd40d8cedf9c9a62fa2cbc14b64bb6121120dab4e24bef8e6b37", + "0xaf0500d4af99c83db8890a25f0be1de267a382ec5e9835e2f3503e1bac9412acf9ff83a7b9385708ef8187a38a37bc77", + "0xb76d57a1c1f85b8a8e1722a47057b4c572800957a6b48882d1fc21309c2e45f648a8db0fcff760d1dbc7732cf37c009b", + "0xb93c996cec0d3714667b5a5a5f7c05a7dc00bbc9f95ac8e310626b9e41ae4cc5707fac3e5bd86e1e1f2f6d9627b0da94", + "0x93216fdb864217b4c761090a0921cf8d42649ab7c4da1e009ec5450432564cb5a06cb6e8678579202d3985bd9e941cef", + "0x8b8be41105186a339987ae3a5f075fbc91f34b9984d222dfed0f0f85d2f684b56a56ab5dc812a411570491743d6c8b18", + "0x959b72782a6b2469e77fe4d492674cc51db148119b0671bd5d1765715f49fa8a87e907646671161586e84979ef16d631", + "0x86b7fc72fb7e7904ea71d5e66ba0d5d898ace7850985c8cc4a1c4902c5bf94351d23ce62eed45e24321fb02adfa49fc8", + "0xa2f244e7c9aa272cb0d067d81d25e5a3045b80b5a520b49fd5996ece267a7f1bea42e53147bbf153d9af215ea605fc9e", + "0x81aa2efa5520eebc894ce909ba5ce3250f2d96baa5f4f186a0637a1eea0080dd3a96c2f9fadf92262c1c5566ddb79bab", + "0xb607dd110cfe510d087bcff9a18480ba2912662256d0ab7b1d8120b22db4ad036b2266f46152754664c4e08d0fc583f6", + "0x8f588d5f4837e41312744caac5eee9ddc3ad7085871041694f0b5813edf83dc13af7970f7c9b6d234a886e07fa676a04", + "0x924921b903207783b31016cbec4e6c99e70f5244e775755c90d03a8b769738be3ba61577aca70f706a9c2b80040c9485", + "0xae0a42a222f1a71cd0d3c69ffb2f04c13e1940cce8efabe032629f650be3ceed6abb79651dbb81cb39a33286eb517639", + "0xa07d7d76460f31f5f0e32e40a5ea908d9d2aebf111ac4fadee67ef6540b916733c35a777dcdc05f6417726ca1f2d57dd", + "0x88d7f8a31f8c99794291847d28745e5d0b5d3b9684ca4170b686ffbb5bb521a3ef6746c3c8db22e4250a0cdff7939d96", + "0x849573071fd98c020dc9a8622a9eff221cb9f889bde259e7127a8886b73bef7ad430b87750915658918dcfb6b7b4d8d3", + "0xb12d59f732fa47fad175d6263734da8db89230fd340a46ad1cdee51e577041a5c80bf24cd195593e637daf1a66ef5a98", + "0xabbcfb8a4a6d5e269ee1ac5e277df84416c73ca55ec88317f73608201af25af0cb65b943c54684a5651df3a26e3daca2", + "0xab157f589bdbaf067a6a7ba7513df0492933855d39f3a081196cf2352e0ddc0162d476c433320366e3df601e0556278d", + "0xa86c0619b92e5ae4f7daa876a2abc5ba189156afc2fa05eef464dfa342ba37fc670d0dc308ad3822fcb461ab001bac30", + "0xa3f292946476cfe8d5e544a5325439a00e0165a5f9bf3bb6a53f477baeac7697cc0377745536681aa116f326ce911390", + "0x8aecbbfd442a6a0f01c1c09db5d9d50213eb6f1ff6fab674cde3da06a4edff3ed317e804f78300c22ef70c336123e05d", + "0x834ed4b58211fcd647d7bf7c0a3ba9085184c5c856b085e8a0fcd5215c661ef43d36f3f0f6329a9f1370501b4e73b6e4", + "0xa114ea5ad2b402a0de6105e5730907f2f1e458d28ae35144cf49836e0ad21325fe3e755cfb67984ae0a32e65402aad1e", + "0xa005f12bed97d71cee288b59afe9affb4d256888727343944a99913980df2c963fe02f218e6ea992f88db693a4498066", + "0xa010f286ab06b966e3b91ff8f1bdbe2fe9ab41a27bc392d5787aa02a46e5080e58c62c7d907818caae9f6a8b8123e381", + "0x857bd6df2ddef04dbc7c4f923e0b1696d3016c8bfed07fdfa28a3a3bd62d89b0f9df49aae81cbb6883d5e7b4fadae280", + "0xb3927030da445bc4756ac7230a5d87412a4f7510581fb422212ce2e8cf49689aca7ba71678743af06d4de4914c5aa4a0", + "0xb86403182c98fcce558d995f86752af316b3b2d53ba32075f71c7da2596747b7284c34a1a87de604fcc71e7e117a8add", + "0x98dd19b5527733041689b2a4568edaf6aa0fe1a3dd800c290cda157b171e053648a5772c5d3d4c80e5a795bc49adf12e", + "0x88a3c227bb7c9bff383f9ad3f7762245939a718ab85ae6e5e13180b12bf724d42054d3852b421c1cd1b3670baddecb63", + "0xb3cfd9ad66b52bbe57b5fff0fad723434d23761409b92c4893124a574acc1e6b1e14b4ec507661551cbbe05e16db362e", + "0x923e1bb482cf421dd77801f9780f49c3672b88508a389b94015fd907888dc647ee9ea8ec8d97131d235d066daf1f42b7", + "0x8d5e16240f04f92aa948181d421006bdbc7b215648fb6554193224d00cf337ebbb958f7548cf01b4d828acffb9fbc452", + "0x8b2b8f18ad0559746f6cda3acca294a1467fb1a3bc6b6371bc3a61a3bfe59418934fa8706f78b56005d85d9cb7f90454", + "0xa9316e2a94d6e31426d2ae7312878ba6baaac40f43e2b8a2fa3ab5a774c6918551554b2dbb23dc82f70ba3e0f60b5b0d", + "0x9593116d92cf06b8cd6905a2ce569ee6e69a506c897911f43ae80fc66c4914da209fc9347962034eebbc6e3e0fe59517", + "0x887d89d2b2d3c82b30e8f0acf15f0335532bd598b1861755498610cb2dd41ff5376b2a0bb757cb477add0ce8cfe7a9fc", + "0xb514cfe17875ecb790ad055271cc240ea4bda39b6cfa6a212908849c0875cb10c3a07826550b24c4b94ea68c6bb9e614", + "0xa563d5187966d1257d2ed71d53c945308f709bcc98e3b13a2a07a1933dc17bcb34b30796bd68c156d91811fbd49da2cb", + "0xa7195ccc53b58e65d1088868aeeb9ee208103e8197ad4c317235bb2d0ad3dc56cb7d9a7186416e0b23c226078095d44c", + "0xa838e7a368e75b73b5c50fbfedde3481d82c977c3d5a95892ac1b1a3ea6234b3344ad9d9544b5a532ccdef166e861011", + "0x9468ed6942e6b117d76d12d3a36138f5e5fb46e3b87cf6bb830c9b67d73e8176a1511780f55570f52d8cdb51dcf38e8c", + "0x8d2fc1899bc3483a77298de0e033085b195caf0e91c8be209fd4f27b60029cbe1f9a801fbd0458b4a686609762108560", + "0x8f4e44f8ca752a56aa96f3602e9234ad905ad9582111daf96a8c4d6f203bf3948f7ce467c555360ad58376ee8effd2ba", + "0x8fb88640b656e8f1c7c966c729eb2ba5ccf780c49873f8b873c6971840db7d986bdf1332ba80f8a0bb4b4ee7401468fa", + "0xb72aa3235868186913fb5f1d324e748cd3ce1a17d3d6e6ea7639a5076430fe0b08841c95feb19bb94181fe59c483a9eb", + "0xb8b102690ebb94fc4148742e7e3fd00f807b745b02cbe92cd92992c9143b6db7bb23a70da64a8b2233e4a6e572fc2054", + "0x8c9ae291f6cd744e2c6afe0719a7fc3e18d79307f781921fb848a0bf222e233879c1eca8236b4b1be217f9440859b6ce", + "0xa658ede47e14b3aad789e07f5374402f60e9cacb56b1b57a7c6044ca2418b82c98874e5c8c461898ebd69e38fecd5770", + "0x89c0cb423580e333923eb66bda690f5aca6ec6cba2f92850e54afd882ba608465a7dbb5aa077cd0ca65d9d00909348ab", + "0xaed8e28d98d5508bd3818804cf20d296fe050b023db2ed32306f19a7a3f51c7aaafed9d0847a3d2cd5ba5b4dabbc5401", + "0x96a0fcd6235f87568d24fb57269a94402c23d4aa5602572ad361f3f915a5f01be4e6945d576d51be0d37c24b8b0f3d72", + "0x935d0c69edd5dfa8ed07c49661b3e725b50588f814eb38ea31bcc1d36b262fae40d038a90feff42329930f8310348a50", + "0x900518288aa8ea824c7042f76710f2ea358c8bb7657f518a6e13de9123be891fa847c61569035df64605a459dad2ecc8", + "0x947d743a570e84831b4fb5e786024bd752630429d0673bf12028eb4642beb452e133214aff1cfa578a8856c5ebcb1758", + "0xa787266f34d48c13a01b44e02f34a0369c36f7ec0aae3ec92d27a5f4a15b3f7be9b30b8d9dd1217d4eeedff5fd71b2e5", + "0xa24b797214707ccc9e7a7153e94521900c01a1acd7359d4c74b343bfa11ea2cdf96f149802f4669312cd58d5ab159c93", + "0x97f5ee9c743b6845f15c7f0951221468b40e1edaef06328653a0882793f91e8146c26ac76dd613038c5fdcf5448e2948", + "0x80abd843693aed1949b4ea93e0188e281334163a1de150c080e56ca1f655c53eb4e5d65a67bc3fc546ed4445a3c71d00", + "0x908e499eb3d44836808dacff2f6815f883aeced9460913cf8f2fbbb8fe8f5428c6fc9875f60b9996445a032fd514c70f", + "0xae1828ef674730066dc83da8d4dd5fa76fc6eb6fa2f9d91e3a6d03a9e61d7c3a74619f4483fe14cddf31941e5f65420a", + "0xa9f4dbe658cd213d77642e4d11385a8f432245b098fccd23587d7b168dbeebe1cca4f37ee8d1725adb0d60af85f8c12f", + "0x93e20ee8a314b7772b2439be9d15d0bf30cd612719b64aa2b4c3db48e6df46cea0a22db08ca65a36299a48d547e826a7", + "0xa8746a3e24b08dffa57ae78e53825a9ddbbe12af6e675269d48bff4720babdc24f907fde5f1880a6b31c5d5a51fbb00e", + "0xb5e94dfab3c2f5d3aea74a098546aa6a465aa1e3f5989377d0759d1899babf543ad688bb84811d3e891c8713c45886c5", + "0xa3929bada828bd0a72cda8417b0d057ecb2ddd8454086de235540a756e8032f2f47f52001eb1d7b1355339a128f0a53b", + "0xb684231711a1612866af1f0b7a9a185a3f8a9dac8bde75c101f3a1022947ceddc472beb95db9d9d42d9f6ccef315edbc", + "0xaf7809309edbb8eb61ef9e4b62f02a474c04c7c1ffa89543d8c6bf2e4c3d3e5ecbd39ec2fc1a4943a3949b8a09d315a6", + "0xb6f6e224247d9528ef0da4ad9700bee6e040bbf63e4d4c4b5989d0b29a0c17f7b003c60f74332fefa3c8ddbd83cd95c1", + "0xadbcec190a6ac2ddd7c59c6933e5b4e8507ce5fd4e230effc0bd0892fc00e6ac1369a2115f3398dfc074987b3b005c77", + "0x8a735b1bd7f2246d3fa1b729aecf2b1df8e8c3f86220a3a265c23444bdf540d9d6fe9b18ed8e6211fad2e1f25d23dd57", + "0x96b1bf31f46766738c0c687af3893d098d4b798237524cb2c867ed3671775651d5852da6803d0ea7356a6546aa9b33f2", + "0x8036e4c2b4576c9dcf98b810b5739051de4b5dde1e3e734a8e84ab52bc043e2e246a7f6046b07a9a95d8523ec5f7b851", + "0x8a4f4c32ee2203618af3bb603bf10245be0f57f1cfec71037d327fa11c1283b833819cb83b6b522252c39de3ce599fa5", + "0xad06ed0742c9838e3abaaffdb0ac0a64bad85b058b5be150e4d97d0346ed64fd6e761018d51d4498599669e25a6e3148", + "0x8d91cb427db262b6f912c693db3d0939b5df16bf7d2ab6a7e1bc47f5384371747db89c161b78ff9587259fdb3a49ad91", + "0xae0a3f84b5acb54729bcd7ef0fbfdcf9ed52da595636777897268d66db3de3f16a9cf237c9f8f6028412d37f73f2dfad", + "0x8f774109272dc387de0ca26f434e26bc5584754e71413e35fa4d517ee0f6e845b83d4f503f777fe31c9ec05796b3b4bc", + "0xa8670e0db2c537ad387cf8d75c6e42724fae0f16eca8b34018a59a6d539d3c0581e1066053a2ec8a5280ffabad2ca51f", + "0xac4929ed4ecad8124f2a2a482ec72e0ef86d6a4c64ac330dab25d61d1a71e1ee1009d196586ce46293355146086cabba", + "0x845d222cb018207976cc2975a9aa3543e46c861486136d57952494eb18029a1ebb0d08b6d7c67c0f37ee82a5c754f26f", + "0xb99fa4a29090eac44299f0e4b5a1582eb89b26ed2d4988b36338b9f073851d024b4201cd39a2b176d324f12903c38bee", + "0x9138823bc45640b8f77a6464c171af2fe1700bdc2b7b88f4d66b1370b3eafe12f5fbb7b528a7e1d55d9a70ca2f9fc8e6", + "0x8ac387dc4cf52bc48a240f2965ab2531ae3b518d4d1f99c0f520a3d6eb3d5123a35ef96bed8fa71ee2f46793fa5b33b3", + "0x864adec6339d4c2ba2525621fceabd4c455902f6f690f31a26e55413e0722e5711c509dc47ce0bcc27bbdc7651768d2d", + "0xa0a52edb72268a15201a968dabc26a22909620bda824bd548fb8c26cc848f704166ed730d958f0173bd3b0a672f367bd", + "0x949e445b0459983abd399571a1a7150aab3dd79f4b52a1cd5d733e436c71c1d4b74287c6b0ce6cc90c6711ba4c541586", + "0x858966355dac11369e3b6552f2b381665181693d5a32e596984da3314021710b25a37d8c548b08700eea13d86cb22f21", + "0x974bcbb8d38c5e6518745cc03ad436e585b61f31d705e7e2e5085da9655d768ac4d800904f892c3dab65d6223e3f1fd6", + "0x8092b6506b01308bf6187fde5ebd4fa7448c9a640961ba231be22ac5fa2c7635ef01e8b357722c7695d09b723101ea2a", + "0xa5b8ef360bf28533ee17d8cd131fff661d265f609db49599085c0c7d83b0af409a1b5c28e3a5e5d7f8459a368aa121e8", + "0xb031b6d5e3ceab0f0c93314b3b675f55cf18cbc86f70444af266fe39cb22fd7dad75d8c84e07f1c1bfa2cb8283e1361a", + "0x93ad489e4f74658320c1cceed0137c023d3001a2c930ed87e6a21dbf02f2eb6ad1c1d8bcb3739c85dcfbecb040928707", + "0xb15e4ec2cdab0d34aec8d6c50338812eb6ecd588cf123a3e9d22a7ca23b5a98662af18289f09e6cdd85a39a2863c945c", + "0xb304f71a9717cf40c22073f942618b44bf27cd5e2ed4a386ad45d75b0fcb5a8dafd35158211eaf639495c6f1a651cedb", + "0xb82d78d3eaaa7c5101b7a5aae02bd4f002cd5802d18c3abcda0dd53b036661c6d3c8b79e0abe591eab90b6fdc5fef5e3", + "0xabbd1884243a35578b80914a5084449c237ee4e4660c279d1073a4d4217d1b55c6b7e9c087dfd08d94ac1416273d8d07", + "0x92f4b61c62502745e3e198ec29bca2e18696c69dcb914d1f3a73f4998d012b90caf99df46e9bb59942e43cce377fe8fd", + "0x906e79df98185820c8208844e1ba6bd86cb96965814b01310bd62f22cbec9b5d379b2ef16772d6fc45a421b60cfd68fe", + "0xa0eae2784ef596e2eb270dd40c48d6c508e4394c7d6d08d4cc1b56fde42b604d10ba752b3a80f2c4a737e080ef51b44f", + "0x94c084985e276dc249b09029e49a4ef8a369cd1737b51c1772fbb458d61e3fe120d0f517976eba8ffa5711ba93e46976", + "0x83619a0157eff3f480ab91d1d6225fead74c96a6fd685333f1e8e4d746f6273e226bad14232f1d1168a274e889f202f1", + "0xa724fe6a83d05dbbf9bb3f626e96db2c10d6d5c650c0a909415fbda9b5711c8b26e377201fb9ce82e94fa2ab0bf99351", + "0xa8a10c1b91a3a1fa2d7fd1f78a141191987270b13004600601d0f1f357042891010717319489f681aa8a1da79f7f00d5", + "0xa398a2e95b944940b1f8a8e5d697c50e7aa03994a8a640dfad4ea65cfb199a4d97861a3ec62d1c7b2b8d6e26488ca909", + "0xa2eedfe5452513b2a938fffd560798ef81379c5a5032d5b0da7b3bb812addbaad51f564c15d9acbbfc59bb7eddd0b798", + "0xab31c572f6f145a53e13b962f11320a1f4d411739c86c88989f8f21ab629639905b3eedb0628067942b0dc1814b678ca", + "0xad032736dd0e25652d3566f6763b48b34ea1507922ed162890cd050b1125ec03b6d41d34fccba36ec90336f7cdf788ed", + "0x83028a558a5847293147c483b74173eca28578186137df220df747fccd7d769528d7277336ea03c5d9cdd0bc5ae3d666", + "0xab5d182cd1181de8e14d3ef615580217c165e470b7a094a276b78a3003089123db75c6e1650bf57d23e587c587cd7472", + "0xa4793e089fbdb1597654f43b4f7e02d843d4ab99ee54099c3d9f0bd5c0c5657c90bb076379a055b00c01b12843415251", + "0x98bdc52ee062035356fb2b5c3b41673198ddc60b2d1e546cb44e3bb36094ef3c9cf2e12bbc890feb7d9b15925439d1ea", + "0xa4f90cca6f48024a0341bd231797b03693b34e23d3e5b712eb24aba37a27827319b2c16188f97c0636a0c115381dc659", + "0x8888e6c2e4a574d04ba5f4264e77abc24ccc195f1a7e3194169b8a2ceded493740c52db4f9833b3dbf4d67a3c5b252cb", + "0x83dc4e302b8b0a76dc0292366520b7d246d73c6aebe1bdd16a02f645c082197bcff24a4369deda60336172cefbcf09af", + "0xa4eb2741699febfeb793914da3054337cc05c6fa00d740e5f97cb749ae16802c6256c9d4f0f7297dcdbb8b9f22fc0afa", + "0x8b65557d5be273d1cb992a25cfce40d460c3f288d5cb0a54bdef25cbd17cdea5c32ec966e493addf5a74fd8e95b23e63", + "0x97c6577e76c73837bcb398b947cb4d3323d511141e0ddd0b456f59fbb1e8f920a5c20d7827a24309145efddee786140f", + "0xabcc0849ffe2a6a72157de907907b0a52deece04cf8317bee6fe1d999444b96e461eac95b6afde3d4fe530344086a625", + "0x9385c0115cb826a49df1917556efa47b5b5e4022b6a0d2082053d498ec9681da904ecf375368bb4e385833116ea61414", + "0x8b868c1841f0cdc175c90a81e610b0652c181db06731f5c8e72f8fafa0191620742e61a00db8215a991d60567b6a81ca", + "0xa8df15406f31b8fcf81f8ff98c01f3df73bf9ec84544ddec396bdf7fafa6fe084b3237bf7ef08ad43b26517de8c3cd26", + "0xa9943d21e35464ce54d4cc8b135731265a5d82f9ccf66133effa460ffdb443cdb694a25320506923eede88d972241bf2", + "0xa1378ee107dd7a3abcf269fd828887c288363e9b9ca2711377f2e96d2ed5e7c5ec8d3f1da995a3dcbedf1752d9c088fc", + "0x8a230856f9227b834c75bdebc1a57c7298a8351874bf39805c3e0255d6fd0e846f7ad49709b65ec1fd1a309331a83935", + "0x877bcf42549d42610e1780e721f5800972b51ba3b45c95c12b34cb35eeaf7eac8fa752edd7b342411820cf9093fea003", + "0x84c7a0b63842e50905624f1d2662506b16d1f3ea201877dfc76c79181c338b498eceb7cad24c2142c08919120e62f915", + "0x8e18b1bd04b1d65f6ed349b5d33a26fe349219043ead0e350b50ae7a65d6ff5f985dd9d318d3b807d29faa1a7de4fe42", + "0x8ea7b5a7503e1f0b3c3cd01f8e50207044b0a9c50ed1697794048bbe8efd6659e65134d172fb22f95439e1644f662e23", + "0xb1954a2818cad1dad6d343a7b23afa9aa8ad4463edc4eb51e26e087c2010927535020d045d97d44086d76acdb5818cbf", + "0xa5271ea85d0d21fa1ff59b027cf88847c0f999bbf578599083ff789a9b5228bc161e1c81deb97e74db1a82a0afd61c50", + "0xaa2fa4c05af3387e2c799315781d1910f69977ec1cfea57a25f1a37c63c4daaa3f0ecd400884a1673e17dd5300853bcf", + "0xb1cd2a74ca0b8e6090da29787aef9b037b03b96607983a308b790133bd21297b21ca4e2edec890874096dbf54e9d04c3", + "0x801931607ec66a81272feaa984f0b949ad12d75ecf324ba96627bd4dc5ddead8ebf088f78e836b6587c2b6c0b3366b6c", + "0x95d79504710bdf0ad9b9c3da79068c30665818c2f0cdbba02cc0a5e46e29d596032ac984441b429bd62e34535c8d55b0", + "0x9857d41e25e67876510ff8dadf0162019590f902da1897da0ef6fc8556e3c98961edb1eb3a3a5c000f6c494413ded15e", + "0x8740c9ffe6bd179c19a400137c3bd3a593b85bd4c264e26b4dfb9e2e17ac73e5b52dfacc1dcb4033cfc0cd04785f4363", + "0x977f98f29d948b4097a4abdf9345f4c1fb0aa94ba0c6bf6faa13b76f3a3efc8f688e1fe96099b71b3e1c05041118c8d1", + "0xa364422b1239126e3e8d7b84953ce2181f9856319b0a29fcab81e17ac27d35798088859c1cfc9fc12b2dbbf54d4f70b3", + "0xa0f6ba637f0db7a48e07439bb92ddb20d590ce9e2ed5bab08d73aa22d82c32a9a370fe934cbe9c08aeb84b11adcf2e0e", + "0xa2c548641bd5b677c7748327cca598a98a03a031945276be6d5c4357b6d04f8f40dd1c942ee6ec8499d56a1290ac134d", + "0x9863e9cc5fbcdbd105a41d9778d7c402686bfd2d81d9ed107b4fda15e728871c38647529693306855bee33a00d257a7e", + "0xa54173bf47b976290c88fd41f99300135de222f1f76293757a438450880e6f13dbde3d5fe7afc687bdfbcfc4fbc1fc47", + "0xb8db413917c60907b73a997b5ab42939abd05552c56a13525e3253eb72b83f0d5cc52b695968a10005c2e2fe13290e61", + "0xa1f8388ef21697c94ba90b1a1c157f0dc138e502379e6fc5dc47890d284563e5db7716266e1b91927e5adf3cde4c0a72", + "0x9949013a59d890eb358eab12e623b2b5edb1acbee238dfad8b7253102abc6173922e188d5b89ec405aa377be8be5f16d", + "0xa00fdb7710db992041f6ddb3c00099e1ce311dea43c252c58f560c0d499983a89de67803a8e57baa01ee9d0ee6fa1e44", + "0xa8b1bcbed1951c9cdb974b61078412881b830b48cd6b384db0c00fa68bcc3f4312f8e56c892ea99d3511857ef79d3db9", + "0x8f3ee78404edc08af23b1a28c2012cee0bdf3599a6cb4ea689fc47df4a765ef519191819a72562b91a0fbcdb896a937e", + "0x8155bbb7fa8d386848b0a87caae4da3dec1f3dade95c750a64a8e3555166ccc8799f638bd80ed116c74e3a995541587a", + "0xabfe30adbc0a6f1fd95c630ed5dac891b85384fa9331e86b83217f29dff0bd7cad19d328485715a7e3df9a19069d4d2f", + "0x89d0783e496ee8dbb695764b87fb04cee14d4e96c4ba613a19736971c577d312079048142c12ce5b32b21e4d491d281b", + "0x856b8dbc9c5d8f56b6bb7d909f339ca6da9a8787bba91f09130a025ab6d29b64dbf728ba6ed26e160a23c1cdb9bc037b", + "0x8a30dd2ea24491141047a7dfe1a4af217661c693edf70b534d52ca547625c7397a0d721e568d5b8398595856e80e9730", + "0xae7e1412feb68c5721922ed9279fb05549b7ef6812a4fd33dbbbd7effab756ab74634f195d0c072143c9f1fd0e1ee483", + "0xb7ce970e06fa9832b82eef572f2902c263fda29fdce9676f575860aae20863046243558ede2c92343616be5184944844", + "0x85ed0531f0e5c1a5d0bfe819d1aa29d6d5ff7f64ad8a0555560f84b72dee78e66931a594c72e1c01b36a877d48e017ca", + "0xb8595be631dc5b7ea55b7eb8f2982c74544b1e5befc4984803b1c69727eac0079558182f109e755df3fd64bee00fcaa5", + "0x99e15a66e5b32468ef8813e106271df4f8ba43a57629162832835b8b89402eb32169f3d2c8de1eb40201ce10e346a025", + "0x844c6f5070a8c73fdfb3ed78d1eddca1be31192797ad53d47f98b10b74cc47a325d2bc07f6ee46f05e26cf46a6433efb", + "0x974059da7f13da3694ad33f95829eb1e95f3f3bfc35ef5ef0247547d3d8ee919926c3bd473ab8b877ff4faa07fcc8580", + "0xb6f025aecc5698f6243cc531782b760f946efebe0c79b9a09fe99de1da9986d94fa0057003d0f3631c39783e6d84c7d5", + "0xb0c5358bc9c6dfe181c5fdf853b16149536fbb70f82c3b00db8d854aefe4db26f87332c6117f017386af8b40288d08f9", + "0xa3106be5e52b63119040b167ff9874e2670bd059b924b9817c78199317deb5905ae7bff24a8ff170de54a02c34ff40a4", + "0xad846eb8953a41c37bcd80ad543955942a47953cbc8fb4d766eac5307892d34e17e5549dc14467724205255bc14e9b39", + "0xb16607e7f0f9d3636e659e907af4a086ad4731488f5703f0917c4ce71a696072a14a067db71a3d103530920e1ec50c16", + "0x8ed820e27116e60c412c608582e9bb262eaaf197197c9b7df6d62b21a28b26d49ea6c8bb77dfde821869d9b58025f939", + "0x97bc25201d98cde389dd5c0c223a6f844393b08f75d3b63326343073e467ac23aacef630ddc68545ea874299ba4a3b4f", + "0xb73c9695ad2eefd6cc989a251c433fab7d431f5e19f11d415a901762717d1004bb61e0cc4497af5a8abf2d567e59fef4", + "0xadaabe331eea932533a7cc0cf642e2a5e9d60bbc92dd2924d9b429571cbf0d62d32c207b346607a40643c6909b8727e2", + "0xa7b1bbfe2a5e9e8950c7cb4daab44a40c3ffab01dc012ed7fe445f4af47fa56d774a618fafe332ab99cac4dfb5cf4794", + "0xb4a3c454dcd5af850212e8b9ba5fe5c0d958d6b1cabbf6c6cfe3ccbc4d4c943309c18b047256867daf359006a23f3667", + "0xa5c0b32f6cef993834c1381ec57ad1b6f26ae7a8190dd26af0116e73dadc53bb0eeb1911419d609b79ce98b51fdc33bc", + "0xac2f52de3ecf4c437c06c91f35f7ac7d171121d0b16d294a317897918679f3b9db1cef3dd0f43adb6b89fe3030728415", + "0x94722ae6d328b1f8feaf6f0f78804e9b0219de85d6f14e8626c2845681841b2261d3e6a2c5b124086b7931bf89e26b46", + "0xa841a0602385d17afabca3a1bb6039167d75e5ec870fea60cfcaec4863039b4d745f1a008b40ec07bca4e42cb73f0d21", + "0x8c355f0a1886ffced584b4a002607e58ff3f130e9de827e36d38e57cb618c0cb0b2d2dea2966c461cb3a3887ede9aef1", + "0xa6a9817b0fc2fd1786f5ba1a7b3d8595310987fb8d62f50a752c6bb0b2a95b67d03a4adfd13e10aa6190a280b7ee9a67", + "0xa1d2e552581ecbafeaef08e389eaa0b600a139d446e7d0648ac5db8bbbf3c438d59497e3a2874fc692b4924b87ff2f83", + "0xa1b271c55389f25639fe043e831e2c33a8ba045e07683d1468c6edd81fedb91684e4869becfb164330451cfe699c31a8", + "0x8c263426e7f7e52f299d57d047a09b5eeb893644b86f4d149535a5046afd655a36d9e3fdb35f3201c2ccac2323a9582e", + "0xb41c242a7f7880c714241a97d56cce658ee6bcb795aec057a7b7c358d65f809eb901e0d51256826727dc0dc1d1887045", + "0x93001b9445813c82f692f94c0dc1e55298f609936b743cf7aae5ebfa86204f38833d3a73f7b67314be67c06a1de5682d", + "0x82087536dc5e78422ad631af6c64c8d44f981c195ddea07d5af9bb0e014cdc949c6fa6e42fce823e0087fdb329d50a34", + "0x8e071861ceba2737792741c031f57e0294c4892684506b7c4a0fc8b2f9a0a6b0a5635de3d1e8716c34df0194d789ae86", + "0xb471c997e1e11774bd053f15609d58838a74073a6c089a7a32c37dd3f933badf98c7e5833263f3e77bc0d156a62dd750", + "0x8d2d8686fb065b61714414bb6878fff3f9e1e303c8e02350fd79e2a7f0555ded05557628152c00166ce71c62c4d2feaa", + "0xae4c75274d21c02380730e91de2056c0262ffcecf0cbdb519f0bdb0b5a10ae2d4996b3dc4b3e16dbaea7f0c63d497fef", + "0x97140d819e8ca6330e589c6debdee77041c5a9cedb9b8cbd9c541a49207eeb7f6e6b1c7e736ec8ba6b3ab10f7fcd443a", + "0xaf6659f31f820291a160be452e64d1293aa68b5074b4c066dac169b8d01d0179139504df867dc56e2a6120354fc1f5be", + "0xa5e5d8088a368024617bfde6b731bf9eee35fc362bed3f5dfdd399e23a2495f97f17728fec99ca945b3282d1858aa338", + "0xa59cfc79d15dbdde51ab8e5129c97d3baba5a0a09272e6d2f3862370fdbaf90994e522e8bd99d6b14b3bb2e9e5545c6f", + "0xa30499b068083b28d6c7ddcc22f6b39b5ec84c8ee31c5630822c50ea736bb9dca41c265cffc6239f1c9ef2fd21476286", + "0x88ffe103eca84bbe7d1e39a1aa599a5c7c9d5533204d5c4e085402a51441bb8efb8971efe936efbbfa05e5cb0d4b8017", + "0xb202356fbf95a4d699154639e8cb03d02112c3e0128aab54d604645d8510a9ba98936028349b661672c3a4b36b9cb45d", + "0x8b89bb6574bf3524473cff1ff743abcf1406bd11fb0a72070ccd7d8fce9493b0069fb0c6655252a5164aee9e446ea772", + "0x93247b1038fa7e26667ee6446561d4882dc808d1015daafb705935ddc3598bb1433182c756465960480f7b2de391649e", + "0xb027f94d3358cbb8b6c8c227300293a0dee57bf2fee190a456ad82ecfb6c32f8090afa783e2ab16f8139805e1fb69534", + "0xa18bb1849b2f06c1d2214371031d41c76ffa803ee3aa60920d29dbf3db5fbfac2b7383d5d0080ba29ce25c7baa7c306b", + "0x827bf9fd647e238d5ac961c661e5bbf694b4c80b3af8079f94a2484cb8fba2c8cf60e472ebcd0b0024d98ae80ad2ff5a", + "0x838e891218c626a7f39b8fd546b013587408e8e366ecc636b54f97fa76f0a758bc1effa1d0f9b6b3bc1a7fcc505970a0", + "0x836523b5e8902d6e430c6a12cff01e417d2bd7b402e03904034e3b39755dee540d382778c1abe851d840d318ebedce7f", + "0x850a77dda9ac6c217e2ef00bf386a1adec18b7f462f52801c4f541215690502a77ef7519b690e22fdf54dc2109e0ca38", + "0xa8265c6ae7b29fc2bda6a2f99ced0c1945dd514b1c6ca19da84b5269514f48a4f7b2ccbab65c9107cfd5b30b26e5462f", + "0xab3d02ee1f1267e8d9d8f27cc388e218f3af728f1de811242b10e01de83471a1c8f623e282da5a284d77884d9b8cde0e", + "0x831edaf4397e22871ea5ddee1e7036bab9cc72f8d955c7d8a97f5e783f40532edbbb444d0520fefcffeab75677864644", + "0x80484487977e4877738744d67b9a35b6c96be579a9faa4a263e692295bb6e01f6e5a059181f3dd0278e2c3c24d10a451", + "0xaae65a18f28c8812617c11ecf30ad525421f31fb389b8b52d7892415e805a133f46d1feca89923f8f5b8234bd233486a", + "0xb3a36fd78979e94288b4cefed82f043a7e24a4a8025479cc7eb39591e34603048a41ee606ee03c0b5781ebe26a424399", + "0xb748b3fc0d1e12e876d626a1ba8ad6ad0c1f41ea89c3948e9f7d2666e90173eb9438027fadcd741d3ae0696bd13840f1", + "0xacdd252d7c216c470683a140a808e011c4d5f1b4e91aeb947f099c717b6a3bad6651142cde988330827eb7d19d5fb25c", + "0xb9a25556a6ca35db1ed59a1ec6f23343eab207a3146e4fc3324136e411c8dba77efd567938c63a39c2f1c676b07d8cdb", + "0xa8db6aef8f5680d2bdb415d7bcaae11de1458678dcb8c90c441d5986c44f83a9e5855662d0c1aace999172d8628d8fe1", + "0xaf58147108e9909c3a9710cc186eab598682dca4bfd22481e040b8c000593ecb22c4ede4253ac9504e964dfa95a9b150", + "0x8dd8bb70f1c9aec0fcc9478f24dfc9c3c36c0bf5ff7a67c017fa4dab2ec633fbd7bc9d8aa41ea63e2696971ed7e375f5", + "0xaa98d600b22aff993a4d7a3ccabd314e1825b200cb598f6b797d7e4d6a76d89e34a4d156c06bddfc62f2ef9b4c809d1d", + "0x8a8fc960d6c51294b8205d1dabe430bef59bda69824fa5c3c3105bef22ac77c36d2d0f38ffc95ce63731de5544ccbeff", + "0xb6d1020efe01dc8032bd1b35e622325d7b9af9dcd5c9c87c48d7d6ebc58644454294c59b7f4b209204b5b1f899f473bf", + "0x8a750dc9fe4891f2dfe5759fb985939810e4cdc0b4e243ff324b6143f87676d8cb4bcb9dfb01b550801cedcaaa5349e2", + "0x98c13142d3a9c5f8d452245c40c6dae4327dd958e0fda85255ea0f87e0bcbaa42a3a0bd50407ed2b23f9f6317a8a4bc5", + "0x99f2b83d9ec4fc46085a6d2a70fd0345df10f4a724c1ba4dee082a1fde9e642e3091992ebf5f90a731abcb6ec11f6d9b", + "0xb218546ab2db565b2489ea4205b79daa19ef2acbf772ccaaa5e40150e67ea466090d07198444b48e7109939aa2319148", + "0x84f9d1d868e4b55e535f1016558f1789df0daa0ead2d13153e02f715fe8049b1ce79f5bc1b0bbbb0b7e4dd3c04783f3f", + "0x80d870d212fbddfdda943e90d35a5a8aa0509a7a1e7f8909f2fcb09c51c3026be47cc7a22620a3063406872105b4f81a", + "0xb5b15138ff6551fac535d4bbce2ea6adc516b6b7734b4601c66ec029da2615e3119dc9ad6a937344acfd7b50e4a1a2ae", + "0x95d2f97652086e7ceb54e1d32692b1c867ffba23c4325740c7f10d369283d1b389e8afa0df967831ade55696931e7934", + "0x8a5b580403e1a99cd208f707e8ce0d3f658c8280417683f69008d09cc74d835a85f7380f391b36ead9ac66d9eedd1cbe", + "0xa8b0c90bff34c86720637b5a2081f0f144cfe2205c1176cacd87d348609bc67af68aed72414dc9aa6f44a82c92c2a890", + "0x865abbdd96c496892c165a8de0f9e73348bf24fce361d7a9048710178a3625881afb0006e9f5ee39124866b87904c904", + "0xace67bb994adef4b6f841cdf349195608030044562780a7e9b00b58a4ff117268a03ff01e5a3a9d9d7eff1dd01f5f4bf", + "0xb9371d59185b3d2d320d3fefeadb06ba2aa7d164352fb8dc37571509509fa214d736d244ac625a09a033a10d51611e2e", + "0xa8ef992771422dcf2d6d84386fde9fe5dba88bfded3dfcd14074ca04331b4fd53a7f316615cdfaf10ed932cbb424a153", + "0x868cbc75f8f789ea45eded2768a1dac0763347e0d8e8028d316a21005f17be179d26d5965903e51b037f2f57fe41765d", + "0xb607111bcdfd05fa144aa0281b13ee736079ebbbf384d938a60e5e3579639ed8ef8eb9ca184868cdb220a8e130d4a952", + "0xaca55702af5cae4cae65576769effd98858307a71b011841c563b97c2aa5aeb5c4f8645d254f631ed1582df3dbbf17da", + "0xb9b5cbace76246e80c20dfcc6f1e2c757a22ab53f7fd9ff8a1d309538b55174e55e557a13bf68f095ff6a4fa637ef21a", + "0x8571b0a96871f254e2397c9be495c76379faf347801cb946b94e63212d6a0da61c80e5d7bebbabcd6eaa7f1029172fe5", + "0x902540326281e6dc9c20d9c4deaaf6fbbbcc3d1869bd0cf7f081c0525bea33df5cfa24ead61430fda47fb964fcc7994b", + "0x841af09279d3536a666fa072278950fabf27c59fc15f79bd52acb078675f8087f657929c97b4bc761cbade0ecb955541", + "0xa1f958b147ddf80ab2c0746ba11685c4bae37eb25bfa0442e7e1078a00d5311d25499da30f6d168cb9302ea1f2e35091", + "0x863d939381db37d5a5866964be3392a70be460f0353af799d6b3ed6307176972686bd378f8ad457435a4094d27e8dfb7", + "0x835cd4d7f36eff553d17483eb6c041b14280beb82c7c69bca115929658455a1931212976c619bafb8179aed9940a8cc6", + "0x8d0770e3cb8225e39c454a1fc76954118491b59d97193c72c174ecc7613051e5aed48a534016a8cf0795c524f771a010", + "0x91aa4edb82f6f40db2b7bd4789cc08786f6996ebed3cb6f06248e4884bc949793f04a4c5ea6eefe77984b1cc2a45d699", + "0x8fb494ca2449f659ff4838833507a55500a016be9293e76598bbae0a7cb5687e4693757c2b6d76e62bd6c7f19ed080bb", + "0xb59b104449a880a282c1dd6a3d8debb1d8814ef35aab5673c1e500ee4cb0e840fb23e05fa5a0af92509c26b97f098f90", + "0xaca908e3bad65e854ae6be6c5db441a06bcd47f5abafdfa8f5a83c8cd3c6e08c33cab139c45887887a478338e19ceb9f", + "0x806f5d802040313a31964fc3eb0ee18ac91b348685bed93c13440984ee46f3d2da7194af18c63dea4196549129660a4e", + "0xae4b2dca75c28d8f23b3ab760b19d839f39ff5a3112e33cb44cff22492604a63c382b88ec67be4b0266924dd438c3183", + "0x99d1c29c6bd8bf384e79cd46e30b8f79f9cbc7d3bf980e9d6ffba048f0fc487cac45c364a8a44bb6027ad90721475482", + "0xa16e861c1af76d35528c25bf804bfc41c4e1e91b2927d07d8e96bffe3a781b4934e9d131ecf173be9399800b8269efac", + "0xa253303234fb74f5829060cdcef1d98652441ab6db7344b1e470d195a95722675988048d840201c3b98e794b1e8b037c", + "0x905ac8a0ea9ce0eb373fb0f83dd4cbe20afb45b9d21ae307846fd4757d4d891b26a6711924e081e2b8151e14a496da18", + "0xb485315791e775b9856cc5a820b10f1fa5028d5b92c2f0e003ba55134e1eddb3eb25f985f2611a2257acf3e7cfdfab5e", + "0xb6189c0458b9a043ebc500abc4d88083a3487b7ac47ed5e13ab2a41e0a1bee50d54a406063f92bc96959f19e822a89a7", + "0xa30e15f995fd099a223fc6dc30dad4b8d40bee00caa2bc3223ba6d53cd717c4968a3e90c4618c711ed37cc4cd4c56cf3", + "0xa1b1ed07fcc350bb12a09cd343768d208fc51a6b3486f0ece8f5a52f8a5810b4bc7ab75582ec0bc2770aed52f68eace5", + "0x88aa739fbae4bece147ba51a863e45d5f7203dbc3138975dc5aef1c32656feb35f014d626e0d5b3d8b1a2bda6f547509", + "0xab570f3c8eabfca325b3a2ea775ef6b0c6e6138c39d53c2310329e8fb162869fde22b0e55688de9eb63d65c37598fca3", + "0x89d274762c02158e27cb37052e296a78f2b643eb7f9ae409f8dac5c587d8b4d82be4ef7c79344a08ebec16ac4a895714", + "0x99c411d2ad531e64f06e604d44c71c7c384424498ecd0a567d31ec380727fb605af76643d0d5513dd0a8d018076dd087", + "0x80d0777fa9f79f4a0f0f937d6de277eec22b3507e2e398f44b16e11e40edf5feff55b3b07a69e95e7e3a1621add5ed58", + "0xb2430a460783f44feb6e4e342106571ef81ad36e3ddd908ec719febeb7acaf4b833de34998f83a1dab8f0137a3744c11", + "0xb8f38ccfc7279e1e30ad7cefc3ea146b0e2dff62430c50a5c72649a4f38f2bac2996124b03af2079d942b47b078cc4f8", + "0xa178a450a62f30ec2832ac13bbc48789549c64fc9d607b766f6d7998558a0e2fad007ae0148fc5747189b713f654e6ba", + "0x98c5ede296f3016f6597f7ccc5f82c88fd38ed6dc3d6da3e4a916bfd7c4c95928722a1d02534fe89387c201d70aa6fd2", + "0xa8cc5e98573705d396576e022b2ba2c3e7c7ece45cd8605cb534b511763682582299e91b4bb4100c967019d9f15bbfaf", + "0x848480ea7b7d9536e469da721236d932870b7bbee31ccf7ae31b4d98d91413f59b94a1e0d1786ee7342295aa3734969c", + "0xb88ea38f9ee432f49e09e4e013b19dff5a50b65453e17caf612155fff6622198f3cba43b2ea493a87e160935aaaf20a9", + "0x949376934a61e0ef8894339c8913b5f3b228fa0ae5c532ad99b8d783b9e4451e4588541f223d87273c0e96c0020d5372", + "0x96f90bb65ca6b476527d32c415814b9e09061648d34993f72f28fae7dc9c197e04ef979f804076d107bb218dfd9cb299", + "0xa4402da95d9942c8f26617e02a7cef0ebc4b757fac72f222a7958e554c82cc216444de93f659e4a1d643b3e55a95d526", + "0x81179cbc26a33f6d339b05ea3e1d6b9e1190bd44e94161ae36357b9cdf1e37d745d45c61735feed64371fe5384102366", + "0xad4dc22bdbd60e147fdac57d98166de37c727f090059cfc33e5ee6cf85e23c2643996b75cf1b37c63f3dc9d3c57ffa18", + "0x8a9b1b93dc56e078ce3bb61c2b0088fd6c3e303ba6b943231cc79d4a8e8572f4109bbde5f5aa7333aae3287909cb0fe2", + "0x8876ef583bc1513322457a4807d03381ba1f4d13e179260eaa3bddfede8df677b02b176c6c9f74c8e6eab0e5edee6de6", + "0xb6c67e228bf190fbaeb2b7ec34d4717ce710829c3e4964f56ebb7e64dc85058c30be08030fa87cc94f1734c5206aef5f", + "0xa00cb53b804ee9e85ce12c0103f12450d977bc54a41195819973c8a06dcb3f46f2bf83c3102db62c92c57ab4dd1e9218", + "0xa7675a64772eefddf8e94636fb7d1d28f277074327c02eea8fae88989de0c5f2dc1efed010f4992d57b5f59a0ab40d69", + "0x8d42bb915e0bf6a62bcdf2d9330eca9b64f9ec36c21ae14bf1d9b0805e5e0228b8a5872be61be8133ad06f11cb77c363", + "0xa5b134de0d76df71af3001f70e65c6d78bed571bc06bfddf40d0baad7ea2767608b1777b7ef4c836a8445949877eeb34", + "0xaeadbc771eaa5de3a353229d33ed8c66e85efbd498e5be467709cb7ff70d3f1a7640002568b0940e3abd7b2da81d2821", + "0x8c28da8e57a388007bd2620106f6226b011ee716a795c5d9f041c810edf9cf7345b2e2e7d06d8a6b6afa1ee01a5badc1", + "0x8ed070626a4d39ffd952ddb177bc68fd35b325312e7c11694c99b691f92a8ea7734aeb96cf9cc73e05b3c1b1dcad6978", + "0xada83e18e4842f3d8871881d5dbc81aed88a1328298bfdc9e28275094bd88d71b02e7b8501c380fa8d93096cbc62f4fb", + "0x8befc3bec82dcf000a94603b4a35c1950ba5d00d4bed12661e4237afa75062aa5dcef8eac0b9803136c76d2dd424a689", + "0x97c6f36c91ca5ca9230bfcbf109d813728b965a29b62e5f54c8e602d14a52ac38fa1270de8bfe1ab365426f3fc3654c7", + "0xb01d192af3d8dbce2fe2fece231449e70eb9ac194ec98e758da11ca53294a0fa8c29b1d23a5d9064b938b259ea3b4fb5", + "0x819a2c20646178f2f02865340db1c3c6ebc18f4e6559dd93aa604388796a34bd9fed28ad3ccc8afc57a5b60bb5c4e4ec", + "0xa9ffc877470afc169fecf9ec2dc33253b677371938b0c4ffa10f77bb80089afa2b4488437be90bb1bcf7586a6f4286e3", + "0xb533051c7ce7107176bcb34ad49fdb41fac32d145854d2fe0a561c200dcf242da484156177e2c8f411c3fdf1559ecf83", + "0x8fe2caff2e4241d353110a3618832f1443f7afe171fd14607009a4a0aa18509a4f1367b67913e1235ac19de15e732eb1", + "0x84705c6370619403b9f498059f9869fdf5f188d9d9231a0cb67b1da2e8c906ead51b934286497293698bba269c48aa59", + "0x899dddf312a37e3b10bdaaacc1789d71d710994b6ee2928ac982ad3fd8a4f6167672bc8bf3419412711c591afe801c28", + "0xb2f7916d946b903ded57b9d57025386143410a41a139b183b70aeca09cf43f5089ead1450fce4e6eb4fba2c8f5c5bbe5", + "0x8d5f742fe27a41623b5820914c5ca59f82246010fa974304204839880e5d0db8bc45ebab2ad19287f0de4ac6af25c09e", + "0xb93d4a1f6f73ac34da5ffbd2a4199cf1d51888bc930dc3e481b78806f454fcb700b4021af7525b108d49ebbbaa936309", + "0x8606f8d9121512e0217a70249937e5c7f35fbfe019f02248b035fa3a87d607bc23ae66d0443e26a4324f1f8e57fd6a25", + "0xb21312cdec9c2c30dd7e06e9d3151f3c1aceeb0c2f47cf9800cce41521b9d835cb501f98b410dc1d49a310fdda9bc250", + "0xa56420b64286bdddda1e212bba268e9d1ba6bdb7132484bf7f0b9e38099b94a540884079b07c501c519b0813c184f6b4", + "0x80b2cf0e010118cb2260f9c793cef136f8fa7b5e2711703735524e71d43bce2d296c093be41f2f59118cac71f1c5a2ff", + "0xadcb12d65163804d2f66b53f313f97152841c3625dbbda765e889b9937195c6fcd55d45cc48ebffabb56a5e5fe041611", + "0x8b8a42e50dc6b08ab2f69fc0f6d45e1ea3f11ba0c1008ee48448d79d1897356599e84f7f9d8a100329ed384d6787cfc4", + "0xaaa9c74afa2dec7eccfbd8bb0fc6f24ed04e74c9e2566c0755a00afdfdf3c4c7c59e2a037ec89c2f20af3fae1dd83b46", + "0xaa9f6e8fd59187171c6083ae433627d702eb78084f59010ff07aff8f821f7022ef5fbbe23d76814d811b720a8bfa6cc3", + "0xa56a3ded501659ad006d679af3287080b7ee8449e579406c2cae9706ef8bf19c1fc2eb2a6f9eaf2d3c7582cded73e477", + "0x81971e077c1da25845840222b4191e65f6d242b264af4e86800f80072d97d2a27a6adc87c3a1cb1b0dd63d233fbafa81", + "0xa6fa5453c4aaad2947969ee856616bf6448224f7c5bf578f440bcfc85a55beb40bef79df8096c4db59d1bd8ef33293ea", + "0x87c545adbfaaf71e0ab4bac9ae4e1419718f52b0060e8bb16b33db6d71b7248ae259d8dd4795b36a4bbb17f8fae9fd86", + "0xb4c7a9bc0910e905713291d549cec5309e2d6c9b5ea96954489b1dff2e490a6c8b1fa1e392232575f0a424ba94202f61", + "0x802350b761bcaba21b7afe82c8c6d36ee892b4524ab67e2161a91bbfa1d8e92e7e771efb1f22c14126218dd2cb583957", + "0xb4e7ddb9143d4d78ea8ea54f1c908879877d3c96ee8b5e1cb738949dcfceb3012a464506d8ae97aa99ea1de2abf34e3d", + "0xa49a214065c512ad5b7cc45154657a206ef3979aa753b352f8b334411f096d28fd42bca17e57d4baaafb014ac798fc10", + "0x8a80c70a06792678a97fe307520c0bf8ed3669f2617308752a2ab3c76fdf3726b014335a9b4c9cbcfc1df3b9e983c56f", + "0xa34721d9e2a0e4d08995a9d986dc9c266c766296d8d85e7b954651ad2ca07e55abb1b215898ee300da9b67114b036e0d", + "0x8cfce4564a526d7dca31e013e0531a9510b63845bbbd868d5783875ed45f92c1c369ce4a01d9d541f55f83c2c0a94f03", + "0xab3f5f03a5afc727778eb3edf70e4249061810eba06dc3b96b718e194c89429c5bfbec4b06f8bce8a2118a2fdce67b59", + "0xaa80c2529fc19d428342c894d4a30cb876169b1a2df81a723ab313a071cba28321de3511a4de7846207e916b395abcc9", + "0x82b7828249bf535ef24547d6618164b3f72691c17ca1268a5ee9052dba0db2fdd9987c8e083307a54399eab11b0f76b1", + "0x8fbcb56b687adad8655a6cf43364a18a434bf635e60512fad2c435cf046f914228fb314f7d8d24d7e5e774fb5ffb1735", + "0xa3010a61a2642f5ebbce7b4bc5d6ecb3df98722a49eb1655fe43c1d4b08f11dfad4bcec3e3f162d4cc7af6a504f4d47c", + "0xb3dcc0fdf531478e7c9ef53190aa5607fd053a7d2af6c24a15d74c279dbb47e3c803a1c6517d7e45d6534bb59e3527f5", + "0x8648f6316c898baaca534dff577c38e046b8dfa8f5a14ee7c7bc95d93ae42aa7794ba0f95688a13b554eeb58aeedf9ba", + "0x89fca6fc50407695e9315483b24f8b4e75936edf1475bcf609eed1c4370819abac0e6a7c3c44f669560367d805d9ba63", + "0xa367a17db374f34cd50f66fb31ba5b7de9dbe040f23db2dcc1d6811c0e863606f6c51850af203956f3399000f284d05f", + "0x91030f9ca0fff3e2dbd5947dcf2eba95eb3dbca92ee2df0ed83a1f73dbf274611af7daf1bb0c5c2ee46893ab87013771", + "0x84d56181f304ce94015ea575afeef1f84ea0c5dbb5d29fb41f25c7f26077b1a495aff74bd713b83bce48c62d7c36e42d", + "0x8fe2f84f178739c3e2a2f7dcac5351c52cbed5fa30255c29b9ae603ffd0c1a181da7fb5da40a4a39eec6ce971c328fcf", + "0xa6f9b77b2fdf0b9ee98cb6ff61073260b134eb7a428e14154b3aa34f57628e8980c03664c20f65becfe50d2bdd2751d4", + "0x8c6760865445b9327c34d2a1247583694fbeb876055a6a0a9e5cb460e35d0b2c419e7b14768f1cc388a6468c94fd0a0f", + "0xaf0350672488a96fe0089d633311ac308978a2b891b6dbb40a73882f1bda7381a1a24a03e115ead2937bf9dcd80572ad", + "0xa8e528ec2ee78389dd31d8280e07c3fdd84d49556a0969d9d5c134d9a55cd79e1d65463367b9512389f125ed956bc36a", + "0x942c66589b24f93e81fe3a3be3db0cd4d15a93fb75260b1f7419f58d66afaa57c8d2d8e6571536790e2b415eec348fd9", + "0x83fe4184b4b277d8bf65fb747b3c944170824b5832751057e43465526560f60da6e5bbee2f183cb20b896a20197168c7", + "0x88a71aada494e22c48db673d9e203eef7a4e551d25063b126017066c7c241ee82bedaa35741de4bd78a3dd8e21a8af44", + "0x8c642a3186ca264aac16ee5e27bd8da7e40e9c67ae159b5d32daa87b7de394bf2d7e80e7efb1a5506c53bfd6edd8c2c3", + "0x81855d6de9a59cef51bef12c72f07f1e0e8fe324fcc7ec3f850a532e96dcd434c247130610aaee413956f56b31cbb0dc", + "0xa01e61390dcd56a58ad2fcdb3275704ddfbedef3ba8b7c5fce4814a6cdd03d19d985dba6fd3383d4db089444ea9b9b4d", + "0x96494e89cbf3f9b69488a875434302000c2c49b5d07e5ff048a5b4a8147c98291ae222529b61bb66f1903b2e988e5425", + "0xb9689b3e8dddc6ec9d5c42ba9877f02c1779b2c912bba5183778dc2f022b49aed21c61c8ec7e3c02d74fe3f020a15986", + "0xa2a85e213b80b0511395da318cbb9935c87b82c305f717a264155a28a2ea204e9e726bae04ce6f012e331bd6730cbb9d", + "0x91b70f44c7d8c5980ce77e9033a34b05781cbe773854d3f49d2905cc711a3d87c20d5d496801ad6fd82438874ce732b8", + "0x884596417ff741bb4d11925d73852ffeea7161c7f232be3bdce9e6bbe7884c3a784f8f1807356ae49d336b7b53a2b495", + "0xae2aed8ab6951d8d768789f5bc5d638838d290d33ccc152edfb123e88ba04c6272b44294b0c460880451ad7b3868cc6a", + "0x89d8ebfb9beebc77189d27de31c55f823da87798a50bca21622cbf871e5d9f1d3182cf32ee9b90f157e6ce298e9efccf", + "0xafd00a4db4c2ed93cf047378c9402914b6b3255779f3bb47ded4ab206acb7eaebba0fd7762928e681b1aebcfee994adc", + "0xa2e49b6cd32e95d141ebc29f8c0b398bb5e1a04945f09e7e30a4062142111cd7aa712ac0e3e6394cfb73dd854f41ad77", + "0xae8e714ab6e01812a4de5828d84060f626358bb2b955f6fb99ae887b0d5ce4f67ebc079ab9e27d189bf1d3f24f7c2014", + "0xa3100c1eebf46d604e75ebf78569c25acf938d112b29ccbe1a91582f6bd8ef5548ae3961c808d3fb73936ac244e28dbc", + "0xa9a02dcff0e93d47ead9cdddc4759971c2d848580bf50e117eb100cafca6afeaa7b87208513d5f96b1e1440ffc1b0212", + "0x894ab01462137e1b0db7b84920a3b677fbb46c52b6f4c15320ef64f985e0fc05cec84cd48f389ce039779d5376966ea3", + "0xb1e40e8399ee793e5f501c9c43bde23538e3ce473c20a9f914f4a64f5b565748d13ab2406efe40a048965ee4476113e4", + "0xa5a7d97a19e636238968670a916d007bf2ce6ae8e352345d274101d0bbe3ac9b898f5b85814a7e4c433dd22ac2e000ff", + "0xb6394c43b82923231d93fd0aa8124b757163ba62df369898b9481f0118cb85375d0caac979a198ece432dbb4eb7cc357", + "0x82d522ae3ff4fe2c607b34b42af6f39c0cf96fcfe1f5b1812fca21c8d20cece78376da86dcbd6cdb140e23c93ae0bcb2", + "0xb6e0d986383bc4955508d35af92f2993e7e89db745f4525948c5274cfd500880cb5a9d58a5b13d96f6368bb266a4433e", + "0xb0b4325772ec156571d740c404e1add233fb693579f653b0fae0042b03157d3b904838f05c321d2d30f2dbd27c4d08ad", + "0xac41367250263a2099006ef80c30bac1d2f25731d4874be623b6e315c45b0dc9a65f530fce82fb3dc25bd0610008c760", + "0xb6c0b1ed7df53da04a6f3e796d3bfa186f9551c523bc67898bc0ecfc6b4a4a22f8c4d3bfc740ebf7b9fa5b0ea9431808", + "0x8e78fca17346601219d01e5cd6a4837161a7c8f86fe2a8d93574d8006da5f06ae7c48eea7d2b70992c2a69184619663c", + "0xa21f91f47e04fafbfafacf3185b6863766a2d0c324ccac2c3853a4748af5897dbbe31d91473b480f646121339c9bae2d", + "0xa464d68786ab1fc64bd8734fce0be6fbe8dc021d3e771ff492ada76eedff466577c25e282b7c8ab4c1fd95ef5ff3631e", + "0x829a24badc7714081e03509ccfb00818ce40430682c1c0e4a399cd10b690bda1f921aabcbf1edfb1d8a2e98e6c0cedd6", + "0x87ccf7e4bbcb818ef525435e7a7f039ecbb9c6670b0af163173da38cbdb07f18bc0b40b7e0c771a74e5a4bc8f12dfe2c", + "0x94087bd2af9dbeb449eb7f014cfbf3ee4348c0f47cde7dc0ad401a3c18481a8a33b89322227dee0822244965ae5a2abb", + "0x896b83ed78724dac8a3d5a75a99de8e056a083690152c303326aa833618b93ef9ec19ab8c6ef0efe9da2dbcccac54431", + "0x821e6a0d7ccf3c7bd6a6cc67cde6c5b92fb96542cb6b4e65a44bbc90bbc40c51ff9e04702cb69dd2452f39a2ff562898", + "0xb35b2096cda729090663a49cb09656c019fef1fc69a88496028d3a258ad2b3fd6d91ab832163eaa0077989f647e85e7e", + "0xb7857ef62c56d8bce62476cdb2ab965eddff24d932e20fc992bd820598686defe6cc0a7232d2be342696c2990d80721a", + "0xb343d974dfda3f6589043acd25d53aecf7c34b1e980ae135a55cda554ff55e531bc7c2dfe89b0d2c30e523c7b065dad1", + "0x8d139e16a73cd892b75f3f4e445a10d55d1118f8eeafc75b259d098338419e72e950df6ca49cb45677a3c4e16fb19cdc", + "0x817b8535bd759da392b2c5760c51b3952ecf663662a137c997f595c533cd561ed7e655673c11144242160e41d1f2dd71", + "0x817ee0f0819b0ccb794df17982d5b4332abff5fec5e23b69579db2767855642156d9b9acccf6ceab43332ccc8d2744dc", + "0x9835d2b652aec9b0eba0c8e3b6169567e257a6a3f274ec705dbc250ee63f0f8e4b342e47b9e0c280c778208483d47af8", + "0xb78c40177f54f0e6d03083a4f50d8e56b5aafdb90f1b047bb504777d6e27be5a58170330aee12fbaa5f1e9d4f944acfc", + "0xab8eebacf3806fac7ab951f6a9f3695545e2e3b839ca399a4ef360a73e77f089bb53d3d31dbd84ddfde55e5f013626e0", + "0x96c411fc6aecca39d07d2aff44d94b40814d8cfc4ee5a192fd23b54589b2801694d820a0dd217e44863ccff31dda891b", + "0x8249c424a0caf87d4f7ff255950bbc64064d4d1b093324bfe99583e8457c1f50e6996e3517bf281aa9b252c2a7c5a83a", + "0xacf6ed86121821a3dd63f3875b185c5ebe024bdb37878c8a8d558943d36db0616545a60db90789c0925295f45d021225", + "0xa37f155621a789f774dd13e57016b8e91b3a2512b5c75377ec8871b22a66db99655d101f57acaecd93115297caabfc21", + "0x92e60ee245bd4d349f1c656e034b1a7f0c6415a39ac4c54d383112734305488b3b90b0145024255735e0a32f38dba656", + "0xacec614e562ccfc93366309cfdc78c7d7ee0a23e3a7782a4fc4807b8803e6ebfb894a489d03e9a3c817ff2ec14813eba", + "0xb912f9dd26ed552cb14b007b893e6ed2494d12517e5761dbeb88521270144f8c3eb9571a0ad444b30a8a65e80bd95996", + "0x8375408dae79c547a29e9a9e5d4ec8241b36b82e45e4ca3b0c36d2227c02d17bb171528d3778eac3bbdc75d6c4e8a367", + "0x8c2d0e6e4406836da112edbbb63996408bb3cda4a2712fd245e4bb29a0100fdc89a2746d859b84a94565bc1cfa681813", + "0xa7431bf59e111c072d28c97626cd54fcdf018421d053a787d2aef454b91251ee8ff9d3702d06b088f92b9ad2bbebff15", + "0x8f3659b0fbeb90b7f30b7a49233325e806551a32911a654dca86e290b314483bbb33fe6482387bc48c35d85c1dd0441c", + "0x8dca5ba23f0bb76f7dacabf12886053552ba829a72827b472a2f01e19a893155cdce65f1fb670000f43e8c75ba015a31", + "0x8c1514c083c77624eeb5d995d60994a2866192e15c4474d0be4189fae0e9dbd62494ebb4c02fbc176b53be548abbc5a1", + "0x80498d2ed153381baf3b0f81da839ed0eea6af5796c422b8e59be805dba48c4395bb97824ac308170bb4f14f319c5ddf", + "0x84f5ebc3bf96362457993e9fa31493c31c4283075e2403f63d581b6b0db8a3df294b2085643f2007f4de38cb5d627776", + "0x958e6e38774da518193a98397978dbc73d1c3827b4996ec00b4183da2c305a187a0ada9aa306242814b229a395be83c9", + "0xab8b8fbf73845615e7fab3e09e96cc181159eab09f36b4c1239b3c03313c9aeb4bbb51e16316fe338b2319ed2571b810", + "0x977e4e33b33bd53394e591eba4f9a183e13704c61e467d74b28f4ad0b69aa51501a5221cb1e0e42bcb548ca518caa619", + "0xa9bb7ecb9846cc30d04aad56d253c3df7004cebb272f6adf7b40a84adef9f57291e0d08d64c961b9fc406cdb198aab9b", + "0x8d2b72dc36406a545a9da44e1fddfb953d4894710ca026d6421a4ac91e02d0373a599f2acfe41d8258bc9679cf6f43d3", + "0x904192fc8fe250f61ecb8a36abbbccae85f592bbf00c10039c30b5a1c733d752a04e4fd8a1000c6578616f8a16aa83a3", + "0x87f5fdfe20bbbf931b529ec9be77bbfcc398cad9d932d29f62c846e08a91d2f47ae56ad5345122d62a56f629f9a76c4d", + "0x84cc3a53b2e7b7e03015f796b6cb7c32d6ded95c5b49c233ac27fafa792994b43c93cda6e618b66fce381f3db69838ba", + "0xaab58da10d7bbe091788988d43d66a335644f3d0897bbc98df27dcc0c0fcee0ac72e24f1abdd77e25196a1d0d0728e98", + "0xa10ea8677c2b7da563d84aa91a314a54cab27bb417c257826ebdd3b045d2a0f12729fe630bbbf785d04874f99f26bee8", + "0xacc4970ef2a4435937a9b8a5a5a311226ca188d8f26af1adfcd6efb2376a59155b9a9ff1cff591bde4b684887d5da6e5", + "0x8dc7cf6fcca483c44eb55e7fb924bf3f76cf79b411ae4b01c6c968910877ac9c166b71350f4d935f19bdffb056477961", + "0xac2dd1182ded2054c2f4dbf27b71a0b517fb57193733a4e4e56aca8a069cff5078ffd3fd033683d076c1c639a4de63c7", + "0x932ec87c450cd0dc678daf8c63cd1bf46124fa472934e517fbbfb78199f288ff7f354b36e0cc6c8739d3f496cfe0913b", + "0xb0d631ced213e8492be60ea334dbe3b7799b86d85d5e8e70d02beef3ae87b1d76e1df3bdb5f7ba8a41904c96f6a64455", + "0x929d7239ead7575867e26b536b8badf2e11ca37840034d0e5c77039f8cce122eff5a1bf6e0bcadde6b3858e9f483d475", + "0xaaae5d372d02ee25b14de585af6fbc48f2c7cd2a6af4f08352951b45aa469599eff41e820df642ca1a0f881120e89dbe", + "0xb23c411741a6b059f04fa4f5fd9dd10e2a64915f2de6ea31e39c32f2f347a776a953320e5f7613fcb1167efe502f5c5c", + "0xa4581b0ae633fe29c6f09928e5efb16db019eeac57f79fef2fa1d3c9bee42ce0e852bc60b9d0133265373747e52a67a4", + "0x81b33afffd7b2575d4a9a1c5dd6eee675c084f82e06b9b3a52a3c9f76e087f12dca6e0ffddc42fb81ce1adb559d47a38", + "0x89cc890f06b424591556aabdfdbb36d7a23700425e90c9cfed7d3da226b4debe414ac5bdf175273828ce6c5355712514", + "0xa4399438be75cfae2bf825496704da5ed9001bed8538d8ac346c8cf0d4407808e9ee67573eb95fe1c6872ac21f639aaa", + "0xad537f7ce74a1ca9a46fc06f15c1c8a6c32363bd6ac78a3c579ed8f84252e38a914cac16709fe65360e822ef47896de4", + "0x8e53b69f5e3e86b86299452e20ea8068b49565d0d0ab5d50ce00158a18403ae44e1b078a3cfd3f919aa81eb049a30c6e", + "0xa59f2542c67a430fd3526215c60c02353ee18af2ff87cb6231a2564fe59b8efec421f18d8b8cc7f084675ecf57b3fd05", + "0xb8d9bac93ef56cb4026dd1c731d92260a608fd55b8321e39166678e1dab834d0efddb717685da87786caeb1aaf258089", + "0xaa2df56f4c6fe9e0f899116c37302675f796a1608338700f05a13e779eb7cf278e01947864a8c2c74cc9d9a763804446", + "0xb0108ff2e327dcb6982961232bf7a9a0356d4297902f4b38d380ff1b954bfbcae0093df0f133dd9e84d5966c7b1aada7", + "0xb06b813b01fe7f8cf05b79dc95006f0c01d73101583d456278d71cd78638df2b1115897072b20947943fa263ddab0cd6", + "0xaa41e6c4d50da8abf0ea3c3901412fe9c9dff885383e2c0c0c50ed2f770ada888a27ea08bbb5342b5ff402e7b1230f12", + "0xa48635dbb7debac10cb93d422c2910e5358ba0c584b73f9845028af4a763fd20da8f928b54b27782b27ca47e631ebf38", + "0x80a574c208e994799e4fa9ef895163f33153bc6487491d817c4049e376054c641c4717bda8efbeb09152fa421a7268a7", + "0xb592bfd78ae228afc219c186589b9b0b5c571e314976d1ed5c1642db9159d577679a73c049cfc3dcfefcd5a4f174eeea", + "0xaa1f08af3918c61eadf567a5b1a3cdcdfb1b925f23f1f9e3c47889762f4d979d64686ce1ce990055ef8c1030d98daa3b", + "0x857df4cfd56d41c6d0c7fcc1c657e83c888253bae58d33b86e0803a37461be5a57140a77fb4b61108d1d8565091ada1c", + "0x8fae66a72361df509d253012a94160d84d0b2260822c788927d32fd3c89500500908c8f850ef70df68ddaeb077fd0820", + "0xaa1dbefc9aef1e7b896ff7303837053c63cfb5c8a3d8204680d3228ac16c23636748fe59286468c99699ae668e769a0c", + "0xb64b1cb2ba28665ed10bad1dddc42f3f97383c39bad463c6615b527302e2aaf93eb6062946d2150bd41c329697d101be", + "0xb6d35e3b524186e9065cee73ea17c082feff1811b5ab5519dd7991cdff2f397e3a79655969755309bd08c7d5a66f5d78", + "0xa4dae7f584270743bbba8bb633bdb8bc4dcc43580e53d3e9e509ff6c327e384f14104b5bdfe5c662dc6568806950da37", + "0xaae84d3d9ad4e237b07c199813a42ed2af3bf641339c342d9abf7ebec29b5bd06249c4488ce5c9277d87f7b71b3ddd37", + "0xb82a463cf643821618a058bddf9f2acb34ac86a8de42a0fa18c9626e51c20351d27a9575398a31227e21e291b0da183e", + "0x8b6c921e8707aded3ea693f490322971b1a7f64786ef071bc9826c73a06bd8ae6bf21bc980425769627b529d30b253ce", + "0x80724937b27fc50f033c11c50835c632369f0905f413b1713a2b0a2274bec5d7a30438e94193d479ba6679dbe09a65ef", + "0xa1d9b259a2ca9cff8af6678b3af0a290c2f51e9cf26d5fe3c6a4fa3d28cbf33cb709b7f78b4f61cb9419427983c61925", + "0x96a3e69a5ed7a98ce59c4481f2ffb75be9542122ad0eb4952c84d4536760df217854d4ec561ce2f4a79d3793c22fa4f4", + "0x990c4d9a4a22d63a8976d34833cafc35936b165f04aed3504e9b435f0de1be4c83b097bbaa062483cf3dee3833b4f5b6", + "0xb9bf5e4b270aec4a0dc219457b5fed984b548892c4b700482525ba1a7df19284464f841dab94abfabcaa9a7b7a757484", + "0xacaecf49cb4786d17cf867d7a93bd4ffee0781766e11b5c1b29089ae0024c859d11b45828fbff5330b888543264d74a9", + "0xb0e1a0865b1e6f9e4a0e31d0c885526ac06678acc526fda5124742a2c303bd0e8871a0cb7951ec8ed9540fc247c8d844", + "0x82b3d327b3d1a631758451e12870816956cd0cef91fcf313a90dd533d5291193a0ff3cc447054564ce68c9b027a7ffd7", + "0xa2843602abb98f0f83e000f3415039788da1e9a096bfe8fed6b99bab96df948c814560424ffebe755cb72f40436fb590", + "0xab1c7b43cf838798d1e314bc26e04fc021e99a7bfbfc8ffde62fa8d7f92139de86a377289d5177021154229de01ede15", + "0x95e5cf5dd87ae3aed41b03c6c55f9dfad38dc126b17e7e587c156f7745c8da0bd1d60acb718fc1a03b61344f01e3de4d", + "0x86f021a3762bb47167f80d4ef1b1c873a91fe83409f9704f192efeebbc3ece0729cd2f92f63419907ea38ae47bc907d2", + "0xaaa1445dafbbcd645d4332d9806225e9346ee5ac6b22ad45e8922134fe12f3d433f567a6a4c19efdd9d5775a7de1e92f", + "0x8fd7e15688eef75df7b8bca3d61bc9fca4f56e047cdb6d0b864e7d1c4966eac27d6094b0c8482b49739f83ec51050198", + "0x80aab8b4d394eb011d4ec6a4c2815617308c9b847c6fa6a3d7e6af1c79420ef6ff2a13934a398581c40ee4cf1cac02ac", + "0x8970b97ac076a1d8a321ce00eada0edf974a46bf3cc26f6854e4218cdfc8d2b0c32199d9658f254b4fbae5a2c5535f41", + "0xa1aa2ec5b03df0a630e73dd048680ed6d3032c324941423f45cd1f16038789e5e75b876a13948732e9079a422f66a9fc", + "0xb5fe5f5e2f2ae2beeb8e95859a02fc45f01f9fb0ebb2bd8ec9ec976b3e806228821a9775096d341d662bc536c4d89452", + "0xa2bc1f170b62d0d5788b02391337b2ab157c38e725694e80aeead7383e05599be0e2f0fa27ef05db007061809356e147", + "0xa8a69701d4a8d0d972390e9f831fd8e9f424b2c2ef069e56bd763e9e835b3ce5f7cf5de5e5c297c06ace4aa74df1067c", + "0xb43d551af4ff3873557efe3f3fb98e5ede9008492f181f4796dd1a6bcda8b9445c155e8146966baa812afae1abe06b48", + "0xb4b1dae44fd596813f30602ab20e9b1fb20cb1bd650daacc97b7e054e5c0178b8131d439a9e5b142ca483cc012a362b3", + "0xb95b8a94c30a831eaaebea98c65cc5d0228c78afd6603d4aa426d8186aecc951f1a11c33951f51df04c7e6fa43ffb5ae", + "0xb100059624cf9db371bec80013a57a8f296d006c139a8766308f1ea821c7eccc26cad65bc640ab3f6cef9062653bf17d", + "0x8e5a2cb76716e0000d13bce5ef87acac307362a6096f090f5f64e5c5c71a10fddfdee8435e7166ba8c3ad8c3f540f3e4", + "0x93d2c43e21588c1e83c4255c52604b4ac3f40e656352d1827e95dd5222a45aebff9674e34fbbe7ed21eca77bd9b8dcbc", + "0x8aeaed611546bb9073b07512a9a1f38a7f436ab45e11775a0f9754baaf63e9bcc7bb59b47546a5ded5e4ba2f698e3b5f", + "0xaf9e6792e74a1163fe27612f999a2f3cfa9048914c5bef69e3b2a75162bb0ce6ece81af699ad7f0c5278a8df0ba000d2", + "0x850bf2d5d34791c371a36404036ad6fdcd8fb62d1bb17a57e88bda7a78ea322397ce24d1abf4d0c89b9cf0b4cc42feb3", + "0x87f7e2a1625e2b7861b11d593aaac933ed08a7c768aebd00a45d893ed295bbb6ed865037b152bb574d70be006ddc1791", + "0x8dcce8f4ad163b29a2348ea15431c2c6ea1189ece88d2790e9f46b9125bd790b22503ec391bc2dee8f35419863b2c50c", + "0xb4bf5266c37f12421dd684b29517982d5e4b65dfdfba5fc7bd7479fd854aabf250627498f1e1188a51c0a88d848ec951", + "0x8651623c690247f747af8fdffdc3e5f73d0662bc3279fa2423a3c654af9b6433b9e5e0155f1ce53857e67388e7e3401d", + "0xb155120f196d52760129dde2e2b1990039b99484cdc948fa98095cd23da87679850f522e5955eae34ac267d2144160d3", + "0xaec8115e8d7b6601fbceeccf92e35845a06706d46acd188452c9f7d49abef14c6b3a9a9369a8bab2fd4eb9288e2aaca5", + "0x998a8ca4dc0f145f67a8c456f1d6a7323c4836fe036dcbb0f27eb1c596d121eb97369638a9908cfaf218c7706f266245", + "0xb235fbafac62802742ee3d26b1f4e887f7d2da4d711ba7f9bb6ca024de7beec1de66bb830ce96d69538f7dcb93c51b26", + "0x9258d2ddc21ab4e3edcde7eb7f6a382a29f1b626003cc6fdd8858be90f4ad13240072d8a8d44ef8de51ca4f477fa6c45", + "0x99d038487821c948142c678acd8c792960993dd8cb5e02cb229153a1ee9f88249f4ad9007f08e5d82e2a71fb96bb5f32", + "0xa88ee9dbc73d3d8e0f447b76fdb3a27936bde479a58d5799176885583dc93830ac58bca9087075950ea75100cf51af23", + "0x88b9b15816e5a0387153c1f4b90f613beb3ea4596037da01a81fdd2bcbd0baf5598db99f77e7694e5a0d35e822758108", + "0x907ae4b637d06b15846ee27d08c9c9af42df261c5bdd10cf5bc71f8e5ca34b33ac2405307023c50bdb8dc7b98a2cd5fe", + "0x9393d6900e1d2d1a1e42412fefd99578d9ac1d855c90a3e7930a739085496448609d674ca9b34016ad91f22d1cac538e", + "0xa28ac56b216730b7dcdb5ab3fc22d424c21a677db99a9897a89ed253ea83acfd9d83125133f5be6d9cd92298df110af8", + "0xb027590ee8766f1e352f831fda732adbaf77152485223ad5489ef3b0ce2d2e9f98d547c111fe133847ebb738987fb928", + "0xa9cc08fbd5c3fee8f77cf6eb996a5cafa195df5134dab000e4d0312f970a5577942ee89794e618074f49841f1f933a42", + "0xa8b3535c3df0b1a409d3fc740527ee7dd5ac21756115cde6f87f98cc7623f50cfcf16790689cab113ee7c35a5bd4879f", + "0xb61420227b97e5603ae8a716c6759b619f02b8fdc48acbf854352aa6519dad74b97bacc1723ca564cbf3ca48539ed773", + "0x853762498de80eebf955a6c8ddd259af463e4e25f0b6ba7b6a27b19bdbf4c585de55760a16e2d9345cdba6b2a02610f3", + "0xa711c1b13fc6c30745203c5d06390e6c82bd7c50f61734aa8d99c626faba30119bc910be63ec916c91ba53f8483c05a8", + "0xb488c0a793f4481f46b5875d96eecd73e46209a91677769f0890c5e002ecd7d4b1c9f4ba68c47fbed40e3857b1d8717a", + "0xa651c5e812ae65b1c66d92c607e80be330737ea49c1dcfe019c0ecea0f41a320406935bb09206a4abff0d1c24599b9ad", + "0x85e34e7d96e4b97db98a43247b6c244383b11ca10bf4777364acf509a6faa618bc973e2136a4693fbc8ab597e308fd5a", + "0x99837214102b394fffa7f3883759554c6bb7a070f5c809303595a44195e02b9a169460dc6bbffb62bdc0e7ced5f0a5c1", + "0xa952f89c0afb4bdae8c62b89cc3cfb60d0576ba4fe01a5d99534792f38d8848d919b3fc7577435d8443a044d2ee0bcfa", + "0xa1ac1f81acb29798acdfc493854663519e2d1b0e9d23d286ce33882c34b4c1c0bb43dd9638166d8026315a44d9ec92a8", + "0xac9c58aa38219ae659d23007cc7b97fd25b7b610b2d81a8f9f94ddb089efc49c049a8ea4c56e6eaf7b6498f422a97b3c", + "0x87e61d501c242b484fb9a937ef21d485f6678d75257fc8fe831b528979068cadbe7e12b49c34058ec96d70a9d179ab14", + "0xaa45f6852f35cc8b65a4a8b5380641d2602a4fa4e3a035db9664df3ac2e170b1280c4a8b7b55161430063e54de4158a6", + "0xa46975614ddde6d134753c8d82c381966f87203d6e5a5fb99a93b0d43aa461466b37f07b8d0973a1abd6ee2b40f24348", + "0x8d35f97297773422351f4d99564c1359ef1a10cfb60aa0e6c8985a78f39b4268486312c8ebf9dd2ef50a771aa03158eb", + "0x8497c6242102d21e8b3ade9a9896c96308ab39171ab74cbd94e304c47598e2c2a7b0a0822492ac5c076ba91d4176481d", + "0x973f8fcb5f26915b3a3ef6fe58cc44bc7f4e115cd0ad9727d8d1b8113e126ae2e253a19922c5433be4ab2311a839c214", + "0xae3ee9f1d765a9baf54b4617a289c3b24930aa8d57658a6b0b113bbf9b000c4a78499296c6f428bbb64755dfd4f795d2", + "0xa5be7a8e522ef3dcf9d2951220faf22bb865d050f4af2880b8483222ff7aad7c0866219fcc573df9d829c6efbb517f98", + "0xa5f3c7fabd7853a57695c5ad6d5b99167d08b5414e35ed1068ae386e0cb1ee2afbbe4d2b9024379b6fc3b10c39024d36", + "0x978d5592d4798c9e6baceff095413589461267d6a5b56cd558ec85011342da16f4365d879b905168256f61d36d891b1f", + "0xb7b6eaffa095ecbd76d6e1e88ceebabaf674d9ef7e331e875c6d9b9faa1762c800ff1ea597c214c28080f67a50a96c1e", + "0x8a1ab53ae5ceaa42e06e58dd8faf6c215fc09ba111ca9eeb800612334d30d5971448be90fec62ed194328aadd8c8eecc", + "0xa9ca532cac8ace9a9e845382f8a7840bf40cb426f2fcad8a2f40aadbb400b3a74021627cc9351b0966b841b30284962e", + "0x8dddeda8854c8e7ddc52676dd1d0fed1da610ed5415ddd7d25b835bd8420a6f83d7b67ec682270c9648b2e2186343591", + "0x888906aac64fd41d5c518a832d4e044fdc430cfe142fd431caf4676cafc58853ce576f098910d729011be0a9d50d67b5", + "0x96a3f886a2824e750b1e2ea5c587132f52a0c5e3ff192260d8783c666206bd8ebd539933816d7cdd97e4bc374e0b1edf", + "0xa150a29ffb2632cc7ec560983d9804cd6da3596c0c25956d27eb04776508eae809659fc883834269437871735de5f9ed", + "0x81f7ad4d2959d9d4009d1dfbc6fee38f930f163eb5eac11e98dc38bd2f7f224e3f5c767583f8e52d58d34f3417a6cf90", + "0x97ccac905ea7d9c6349132dd0397b6a2de9e57fd2d70f55e50860e019de15c20171a50b28a5c00ef90d43b838253b3d1", + "0x95694f00c21e8a205d6cbda09956b5b6ec9242ec8c799a91f515b07dcc7de3b6f573e2c0ba149f5a83700cda2d1df0f5", + "0x82bbc3c4a3b3997584903db30fffd182a266c7d1df3e913f908d5a53122fa12cf5acd11d915d85d5bd110fcc43cee736", + "0x8d3f24b4949aa1b4162c28dfbb9f813dd1d8b330f71325448dc45ea34d59b69ca95059402aae011e1b5aba6e536bc6ec", + "0x92c734c19752d24782331e74c9af97a8399ddfdd32954e91cda7363dba876aca4f730b451c50a8913950420682da8121", + "0x8653d2c79f77b8c7dcdf7e8dee42433998aeedf1b583abfca686d47a854de1b75e9a4351580c96d1a2a9532659203361", + "0x886f0e414cb558c1a534a1916d3531320a9b6024639712ffe18164ce6313993a553e2b9aafe9c0716318f81a5d0bb1da", + "0xb31b5efaba5a5020c3bcea0f54860e0688c2c3f27b9b0e44b45d745158f484e474d5d3b1a0044dd6753c7fb4bf8ace34", + "0xb2d615bbdfdc042d6f67a6170127392d99f0e77ae17b0e1be6786ff2f281795f1bf11f83f2e0f8723b5cdd1db1856e09", + "0xa6e014cca531e6ac2922239b5bee39d69d9ba6d0fa96a4b812217dd342657d35606f0b9c5a317efd423cdb1047815e3d", + "0xa8921736b69c9fbb29f443715174bac753e908251804620c542fad6cfbfda7bdfe287f2902f30b043a8a4b4818cfdeef", + "0x8d73a9949a042ec2dcefa476e454cd9877eee543b1a6b3b96a78ffcff87421e8b26dd54d5b3192ac32073cb36497acc3", + "0xb936a71ee8df0e48867f3790adf55dc8efc6585024128de2495f8873bd00fd9fa0984472125e801ed9c3cdce6698f160", + "0x82f69c06209c28f64874e850601dda56af44ffc864f42efa8f9c6a0758207bf0a00f583840982dec0a517ab899a98e5b", + "0xb7a0a14411101473406f30e82f14b13e6efc9699e7193c0be04bb43d1b49e8c54812ce0f9b39131a20379c4c39d3bbe3", + "0x81159c969f38107af3b858d7582b22925a7ccced02fae3698482d7e9cdc6c568e959651991c6cf16c53a997442054b61", + "0x8bf1116a206e0ce9199fcab6ed2b44a9e46e8143bff3ed3f1431f8d55508fe2728b8902670cfd8d9b316f575f288ed9d", + "0xa279b2149824b64144eb92f5a36b22036d34a52bd5a66e5da4b61fbc95af6eda8e485c7914f448abd8674fc14d268d9d", + "0x8b98279b5f3588d1a2f8589d2756458690a502728800f8d94b28e00df842a101c96ab9c5aee87c5bbe65552c0c383b80", + "0xb4a27a351ec54420f94e0a0a79d7c7a7337940399646631baca93eeab5fd429d7fb39428be77dcbce64a13eaa3c8ca1d", + "0x90c08baa29ec8338ffce381eae3d23ce3f6ba54e5242dec21dc3caaed69cac13f2ab5e8d9d719bc95720fa182eee399c", + "0x85156d65bb4fef69ffd539ab918b3286105ca6f1c36a74351ab3310b339727483433e8f8784791f47b4ba35ca933c379", + "0x923005013c27209d07c06a6b92b0cbb248a69c5e15c600bbcc643e8dcd2402adebd94dd4cafb44ec422a127e9780aaec", + "0x863b23eb5463a6ef5a12039edc2f8e18e3c97b244841bc50af02459b1bcc558367edf2f6e4fe69f45f37887469dd536d", + "0x87a4a7708a112724ff9b69ebb25d623b5cae362ae0946daed2ec80e917800dbfcd69f999c253542533242e7b9a5cc959", + "0x8bf4347ceea7f94b53564f26b1a4749a16f13bf71a9e03a546f906f7c423089820ff217066159b0637d9d6824e9c101c", + "0xab07eef925d264145971628a39e4dd93ff849767f68ed06065802cf22756fc6bf384cf6d9ab174bfc1a87bcc37b037aa", + "0x8e3f10a42fad43887d522dc76b1480063267991c2457c39f1e790e0c16c03e38a4c8e79a0b7622892464957bf517ebd8", + "0xa8722fc7b1acf0be18f6ddf3ee97a5a9b02a98da5bc1126a8b7bf10d18ee415be9a85668eb604ef5a1f48659bc447eb5", + "0x878d6b2a9c0aca8e2bc2a5eb7dd8d842aa839bbd7754860c396a641d5794eab88a55f8448de7dbddf9e201cbc54fe481", + "0xada881c167d39d368c1e9b283cf50491c6bfc66072815608ba23ab468cfbd31ca1bd7f140e158e0d9e4d7ebfa670bc2d", + "0xa2b48578fa899d77a7ee1b9cb1e228b40c20b303b3d403fd6612649c81e7db5a7313ba9702adc89627b5fd7439f8b754", + "0x8e051280e10551558dcb5522120ac9216281c29071c0371aaa9bde52961fe26b21d78de3f98cb8cd63e65cff86d1b25c", + "0xa7c5022047930c958e499e8051056c5244ae03beb60d4ba9fe666ab77a913a067324dfb6debcb4da4694645145716c9d", + "0x95cff6ec03e38c5ab0f6f8dccde252d91856093d8429b7494efc7772996e7985d2d6965307c7fdfa484559c129cca9f9", + "0x993eb550d5e8661791f63e2fa259ab1f78a0e3edad467eb419b076a70923fede2e00ddc48a961d20001aaae89fad11e8", + "0xabb2826e4d4b381d64787a09934b9c4fe1d5f5742f90858228e484f3c546e16ee8a2a0b0a952d834a93154a8b18f3d16", + "0xa922ca9f2061996e65ef38a7c5c7755e59d8d5ce27d577abcdd8165b23b4877398d735f9cb470a771335fc7d99ecb7fc", + "0x90f22862216f6bc1bbf5437740a47605d1ff5147b1f06f7b13fec446e4c5a4a4a84792cb244a1905f3478a36f8d7065b", + "0x87f3d9a86afef5b79ea1ca690ee1ee4bb9754b66f7c50a42ad6b99af7c222c853ca161f440a0a2a60b3b5a54e3493240", + "0x80a9ca9a2d33b9cf61976b3860d79f5d00de89a06ef043d2a52931809018aeb4ce70423cbef375b29c2c750c2c8704c2", + "0xb4e798ef1d615896108dae37ac50c1e859216ab6dbac11653e44d06ce5209057b4b0dd6d31dcfcda87664a23c8ef1cbd", + "0xaaed6d1e7c5b1db06f80dae6c24857daadfb0268f20e48a98fba4b76de1ebf65fb84c3be95fd6a418b498f8285ec63bd", + "0xaeceaa316c6369492c939f94809bc80e0857abac86c0d85be8066bbf61afbaaec67e28c572437a8d35c49dd596b3134f", + "0xb791c3d53ed34a7d1c8aa89b7953e3684c3cd529230824dc529739a5fbe74b58b87f01e56e7a169f61c508237ef67160", + "0x9351f8c80634386c45c0050d2f813193f9d839173be941e2092d729be5403632a2f18dffdc323d69eb0dc31fa31c5866", + "0x97693184d5c0056ae244dfb6709cafa23a795dc22d497a307a7f9cf442d7452024023c54a8d6bda5d90a355ba2c84f3a", + "0x85362daa003d23511ca174a8caafe83d52b6436dc4e43c4c049e5388d9211b5cbef3885896914d86d39be0dd1f910511", + "0xa2511b5fa34b24eeb0e1bcbcf872a569d1ff5570fe7b0fb48f5542f7fe57bad808d34b50afa87580866a6cb0eba02f27", + "0xb382e3327eb1401f2d378dbb56ac7250adde0961bd718575a64d264ffd44772c20752d4035c3ba60eb435e160b375e20", + "0xafad8a5d40b536c0720556845a6b257ed42165c14fb4b4a874717d107752f49ed9380c5b048df3aca67287bb8fc411a8", + "0x8fad0c98434ca5373c2d767868f679b76b4a8d04bca8240ea3f388558262c2d61b73b16fc1160932652b5688c25fffcf", + "0x83898008b5cbb6f08f8ef3ec179427869682bb4e8d38f6e6a687a214d4a307436afc64ee67d70a5a8ba9730bf839aecc", + "0xb85232e79913785fd82b06890706972b4ad7a309489930ae23390d51aa5189731f8a2df24800409a8c36b3dd6fc91275", + "0xa24ff26ec792f3701da4c5638c1fca4fa4dae95b01827d6200d583c4caf17ea3171393ba2a8c23d1ee8b88402916f176", + "0xadc5c7a7ff6b41d6cc386b7fc69d7bb04179bdf267864f9aa577f0f6a88438191fa81ebaf13055c2f2d7290be6421ace", + "0xa05e835abd502d31454d40a019010ff90b6b0b1f993075a35c9907aeab7a342ac0ba6144dc9379aada6119157970e9b2", + "0x85ff07ba58463e7f153fc83f11302e9061e648a5cbd272bb0545030b20e11facd8b3ff90c9ac8c280a704fbda5c9d1b0", + "0xa6c735ada8f4587da8cdad7ea3ada01650b5a3ecab8d81daa7a5f5de51ef4a6592b524692584306f06be3f6701f2870c", + "0xb138deee4e53ae8d677fae104f713ef1b8babfecec16b6a85785a66a72784eb09d44c3b63567222ade714e98f7d1604e", + "0xae79c1a49dafcdd972acd95d8ad0a35c02adc7fd736d4c44c3cd13df5789d339b5ea16bddbbd43e486a061ab31baa5c0", + "0xab3cf2371a1d7dcd0ffe3869a0178230964b06694bf258b2073ea66a2afccd845b38485da83d02e1d607d4c5c36b78a8", + "0xab9609f28a325fd01cb39540e3a714506c44e52ef28ee640f361deb5760aadbb23e804663b0fa20a66e239c33f8d8bb8", + "0x8ed95ea8e76e1b42823d7915a6aae77d93746f846bf602841dfce0e47543a36efb9ee7e5b42c73c3209d911225cc471b", + "0xa80b6162036d43811482323f0ce59eb18740e33a63d7c7bbbf3be206985919e5342d53a69df537d43e8b7d7f51e8892f", + "0x93c03d0a5083408ba00c125a8a9385213d4c860072f0297857b1235045819b904e07f2425c13a661d0a01d2e53347f4b", + "0xa6581200f00f96c461621e1d26b14a23687dd97eb9f7df4ba641a84340ee7306dc1796248fba4804f185947ad13b4385", + "0x8be174018fa40f7e0cedc5ae68f38969eb7695f2205e9c573641e533d56f68c20abf38a23d2f0dcac371e60b21b18615", + "0x857ad4ee3218c647c58f09b8ab22bcc8976f00a768ab1f708618e868e6143474be846422ce2710a0ed39b5155b6f13a1", + "0xa490bec40f322d599f26bcefcdddd8f2ef6576aa737d5ce7e8d5d422741abe749e3e6a48489aed8c560633f72857e3c2", + "0xa9c0ee339621f1c4a2410f9b4d2f03f1b558dae2973807b8bccd920e8feb7f65dfde3e79986b72ad21fcc4567240381d", + "0x8592251568e750a430f7d2c6ddbb3ec82a4dd9fd83efe389e69aa177fd97ac2c96c59a6e86db20d8e6f125d65b46c4d3", + "0xa4e2f4aa6a682913b423b097c4069c4e46a1f3af9556b1bfd0580d0fc01e3991488458049e0735b2a629684a79271c8f", + "0x8c4f6a3e738cf74112b08b1680be08158013ef8a515a81215d8a36c9b756786d1b4cb4563923463f3329292f4b48bf6d", + "0x8bace547353c02ea00dd547eeda7259aa354d4772dd5e0c486c723cf88627b7112e196b879c3c92a9561b674d9fc486d", + "0x8d372f4901e25e8db64fa098148d4a4e709b0e9dcb756d0f90dad99dea393054193ae1a33d292a3dd772ff7ba05e4b71", + "0xa8c7ea6a6a031ed23d65639f01f5423190775558f479700597df7ae7e338a6ae5e9b32f470aff20787ac8b7eec84df6c", + "0xb6e9dcba240fdbbf66033410a79a2dd3e9e1ffdf2eae949b3a9ed720e939d92339991dc3e70a5ac7d5253f317daf0b7d", + "0x974dec4cd61af75721071752c664d9c2a5121f06ff1515c56139a177a3ca825f763b69d431d4607e393fa74dcc91cc58", + "0x958863e6ad583a9d370a6db3639066982e44766904e7afa849b132f6666b7d08ab931131b3bec7a506d6583e93d56767", + "0x8b93a33b5da9b3300c20a96d80b894e3789c77041183c2cb21751579c8c96857f60cfc2f075201b64e95a78985c5b321", + "0xb726cb9f7ef34ddbc2fad82b3b0af0b30cc913e26c5a614ae5c19cc9c55c8e6dae069db5315a8dcb6d987415bb550ca8", + "0xa730f515398a71bddd66cab2ff996659d4e47dfbb08ce7958a41021f76d269b91c7498b708cd14b183a8ef469c772803", + "0xa4eb3b18132eb0f5337f14e01d63ca0bec0db6a43870f800e5491db756c2f5fce519d8dba5528b4bcef550d06b33699c", + "0xb1ab6621eec1ee6784e632e214693f39a14f3715991996b883d66200963e065c86fa0667f7bc36b93b40b5d90ff708c2", + "0x80486a26c3532ad6e19f76d8c9344e2626c07363fd495264927cb5935fa9565ece670dc98767afb04af6a9a5c9231075", + "0x8ee20e0df3c84a1c6b0e21bcc325cf99235b747ffe47f17fdfba548a358ca75cbcc331dd50db2311b400ae882256a608", + "0xaef4268959e5541e7ec69c921a1e81a8374d7e44bf1bb2debf4101cf3cd6b7d6ca7f441758b388de96b3e0edb5b97be9", + "0x8793629bd29d689ec94b016de8886cac6e2ca6638911babb22db4a787661422da0639a4e4089ebeb689d173abfe75950", + "0xb487b3551c20a29e9a5abbda8c50ff594826283e443c09e3ae09b914e46060b3f9abf70434444ce1487e2a74e562616b", + "0x8f11531cfc5997dd04b997cb87ba1831aa7041d5434fe72de66304e3f165d882fac891391fbb1eb955c65319e65293b6", + "0xb195136875fd02a75676c33cb3e60504d5964f7a9e81f4c8c8fd38af62e2145c55f765b3158664566191188ac678f381", + "0xb374174b0b3eb04fa49eb4ece45173f0db5d829eac370a20a62309566e0f98b18f72f3633626893c053b7be6bfbd2366", + "0xb2a2f6b0cf652775679b2d677048f2ed8c31a3269e6cddcc7a10e3e6fee89e486b50d9d55fbe452b79c4157c0270fb77", + "0x892177c364dc59032594e7a6fd032286ffdf4fa0b9e3baeb37ec839faebfd2fd46c57b2c9bfe9977b59c93a9cc0ead1d", + "0x8ab7c0038a7dbb2ef200dbbe9acbc875829ecad4883792d5c6ce283de67ccd9aa935a9cc7b30b2bd9de7fca7bf2a9a05", + "0x83745cfc78ca709835aa6c6a233c2b86fb31e3f9f6a8becf63e501f2841c4366fb7d131b746c9d3291afda714ff05579", + "0xa723dcb67925ef007e8339dc578d2622d9bb77cfda87cca0088854a59414c02338752c56116a6c1281917842e8467c38", + "0x8a098142da0af2254c425fdbbd0d1b1a17b2bd781391ab37f181775524b8563c64ab8a1602aee2ac6c0a82ba11a8b1d1", + "0xb13bd7529a9b351c5d395c794c28bcb0a3167f1c992e8c062eef47be9be27895945231d249c73a0b6949daa295e14944", + "0xa20dcd2fc2222eaae467d9f5db861040f58bcb991a26e5663ac3aa5e1ff13d0010657c5af586cc4621757add2b905073", + "0xb818f660c3cc4e9f273c25ceeabe562c8afa8ff88529c26f2cf45ae6b2813cca5f350e3cbd56f6257c4df41722dabd25", + "0xb225d5987108b24411bc389276f12509a45e86d5ad6b6d929af5274df0be11109c0fed329669a0acafdf3b0beaa8f2ec", + "0x91fcb6d04576d3c6bae947bb7843b430e5fb0592ae49b0a65dfa5791f4eaa4bf2c7f436c8de7360f217001c2b4e5c67a", + "0x8821f7a1424ca3fdc5d4a5606ad10dfaba6094cf36669fa9f84cf7617e50425405d14980780e1e18a1ecea7913cda896", + "0x990dcb7f38f56521a70cb71bf4522649fcd46ac052c7feabb0748dfcac9f9c0f95d29e070d32af3cd0adbf869535e17b", + "0xb0fac1029fe2c1100f24e2f4bf10c7672199fce53513c7dde2e8d9b00702edf0143e0e1dc7ceae7dcc6994edc2422b6f", + "0xa514ebb1a33451b4915c05114db0b10168393613744df848b24e43e09f0bda23baefd9d731075198aace586615ac7911", + "0x8b77f7953c2e67049fdca3653b8d8cf3f799677f79b954da02bdad8cc4d6c855c1c7c16b4f6f9ba35f46426ec28b2d84", + "0x875520cfbda16ec5b1d1d00f578a910d0fc052f17870ba093e22e310bb07648d34817cc2b8811b6f52de535f7046a0d0", + "0xb8c77b4be0b430851c4ff69e91cb770db1935d848198601393810ef395efab52deb9d5c6525472bab720273d5e0e7a79", + "0xb6d4d437146671bdea62fb6545395ea3df39f1cdef21b8476b68e7a25aa7354f847740576d6c9f187bbae9941f0ae450", + "0x95c642f1bccdb62cd6a2212dcdd6ff8d49aee426ca08b7cf3a9d15249d24a9eed5533f92a70c84498c0797f8a57efa27", + "0xb617978047ed0f748c305aa7f30c2dacd0db00baa67fe0c5ce346ef0e6991dc7e05f18dcb2702467421f8390f27aa815", + "0x86411c7a00b3e8b43bf22fb061b1f54ad9bbf632cd74395a478218389c0f544668acf3dd7726532d080ca7da9a5f8608", + "0x97bf684a8849626c4710a6992f6c11f6b5406fd4dfe9e6aa502425aaafe9827e2c435aaf9a5d3d2ba3a4c0e8aec79ba4", + "0x8b178e2a125b461d3180906ffba0af3dce614c64058501fdd35243ababf892d6fcdea4834ce42c25d5569452b782a709", + "0x8ebed2c8a25c61da6a6a8cb0d8f5ea179e28869753eacc728f2c076f7aed8598cd3aa0981f120f9e7ea55b3a689ae882", + "0xa6f235b8e655ca3d634740b53d8c0a757ecc75d2b8838b7948997c1985473d01943d935f687b86cee56cd47c8e773443", + "0xa7959c465a9646908b9d8032a589e41a7dd999f2ffc54bb42f22e5f8a4d8c493a31bcc7ea2cac6c8dbcc59acace7181b", + "0x96d0532df2e12da20a57cadb6cf5f6c4ee1aa4775629358c25f1d51677a3e96d1fe3b232532324b4f02f941952d4cc68", + "0x90f493473d686b639a30d1ddc9c72eae6e983f1236e162e58e967a477c0654973ea2e1bdf4ba1a44d7247bc1befc2cab", + "0x8b2d87876d9c4085102a07ebb41c565ba69acab99ffc03efc18f20e48d3f3bbe4fc6ddab9c78fe479d9ada80504d85ba", + "0x829a0fb3200a28e09cacd6c5346000e7786116ddfd898f37dfd17bef454a8abc0fe939ed8735c00769f7f2f33cd4f906", + "0x86194ec9e88ddb7150e8b03e7a535b6e99863fc6762835601efd03615aa97aaeb413cb210e86035086ed852b39c9d019", + "0xb02efd116a7189cb317ceae392bc301ae55470f0489fa89934e182aeb8c67e280299b975786fe9a470bff46827defb9b", + "0x87d7c3903bd22b12d815506f150373f518d47dfc6e5fd74347d88b518124c9923d1e4c98defeb3a45d53d50b423e2175", + "0xa1a430406b28254a7d6348bc98e697e9bab43839aa05d53faee97546f84541ea0b559162619b2045182938f69bf61cae", + "0x99d243c226c61c6697fb3d2594f3533fa5dfd7cfc87107908cacde337d7a077fa5a9dc702d26081b065edb1227498e65", + "0x800ee5006ab6217161f42db0cfc552a81728bb4fbd7af6e4620ea099a65ef6664184af3f65a07fcec7e965529c5b49bf", + "0x91bfd307579cadc8f81009558605be3edbcb8dbba271475803484017f40130b2b216aef4f620d960193be681877d3a53", + "0x96a060459dec458d19a6f8af6e49dc6c7c58c55dd18915c5fce5e0f4b4a422fce3b9632f6059388fe760289abf70f173", + "0x9921a37f3e657222c7fda3588418a9071409711d9f1fccede7494429f02a45fbc52d79fbb64e9ccd518f60d06d0520d3", + "0x81052b0d15773cb75975ca9230ebb2579700e489c7e3f07cd9cde206fef38b8139bd4976d2b4a7840495fc645f96df03", + "0x88ac37ba66d1de5e23878c992e4d54023729e97e77351f50dc5918d738b5a73faf1dc6feec7e85784761836ba1c6f778", + "0xae1e6072c13060775f6086d1ae1f88b627ffcb810fc0e0e97deea1f3a15ef0aaa52a6dce2563e4beedadc131af2a8281", + "0x8b60a340f5e4f90badf83001b495ac9f13974c3d2054ddcb3e6b8ca99dec5cd63a263e05c282454191ab2e087d5a2911", + "0x832e2d56ba69dbf817b2b9dbd25c1538d5b8dbf5d9bc05e6be85054a423ebb66a71b157e166e0b9444ac171b34b7ccc9", + "0x8586036fc7dde1e7e3ecb61663130c4529866ae9f5f5095b9fccd24a4c70eea899aae5f10ea1ba66d1665b2d83be35b0", + "0xa77969453b5c083a207913272b5b69d4ccbd8718bdf54be8fbe11b4bd0a2168aae3ba8f9362afa69c0ffa28d7e5a2340", + "0xb7fe9568c214baad0ac5f83745611b481f744ec1c4fa78a549b180dcf79633e5ba75dc20055012a13d849eb7a9be57d3", + "0xb01cad1d2a6c51c0ce88243d1f52f95fb5ee315a905079688027511f0c4ecd0563a3a81846709d272fa5ccb9665e8043", + "0x8eae0a21adfc569aa57237654021c2bdb2c6f0f52ccc90a126682c21a1f9413c63d285f92b2b2f8649150a9284bf70b7", + "0x942acc947192b5f3cf60e92383e5d35f79e7a5904e8e9fd1c8a351676c83ad29b0afb6578d555457cf909f8f4d27adfd", + "0xa74e092f8628fba9abcabc27e2e9f3d5a9a941dfe50a2dfde2ad179aabc73afd196676925c2d98643ab8b3d02bdb66ad", + "0x896159daa2afd757cf3f9d34af248ad68bb3c62e4c9ac49919422727479cf669098f270b9e645607a7d11adad4c889b2", + "0xa428d8370813d78e7a2a24eebd36e9da2f8bb3605e5a39b5fcda939b531c35a8ebaaa642ba556250a37bddeec90326fb", + "0xa5fa04eb60a1d5ee9820e78f42f7be15e1c02757b539aead995768c6209684d6c183c71d282e0c12a4c15c03f9a89d4d", + "0x93c77d5d220e40affa7269a6915c076c9aef4db552c643ae5d560a79c955b491c6346ca4cf11cbb7fe1894e28d47b065", + "0x802e605d2de745eef6981d88e7a57ef4046a2062725e8080995374cea2b3273c27f35b7774d0dcba014710d8d6c501f2", + "0x82f7169e6ec9b3e2bd450f35ea2e66d06bcf900acf5b73139677b48e078ce2e16599103027b2326770c99c0a690f2015", + "0xb0c8581879439f9b997551233fe2de71aa03604f9cec37a7b18c5854342d9b67be468f3cac4bf6f64fe8a0066248c498", + "0xa3f626848a4db6e9fb01cac90d3362ec521e969ebd5228af694ea3671061476149f13d652942ac1e39f65591fed740f9", + "0x88a8e759b9cbe16a7c16e43f4afa2de6100d2eafa4dee75ccd653ec38c919013d0a6b35c1ee1eaee7c1985b58bcc9e92", + "0xa3d5fc7aaea072798490616552d947e95f49cf02a420314307aafb555287ec607d75589ba24b009cd68299dc6f7942fa", + "0xa809cceeb84f9bcf3c3ddafde3041e7bc3b1d14df8830ab849002176a0725e6f16f70774d8962cb0b8ac0dc43c4ac66f", + "0xb8f2e46c031cc8fa160a08c2ebdfa85345ed14771b06daa9636b0e7792b7fddbc501dfc85cc626a01104a43a7d3230c3", + "0xb5367e2a521c318b802ce16ceac80c4b8139f73ddb10ddf38433397cda70a86ea1f051cc55626a4e99d27f30f3975ff5", + "0x96d963660121c1441cd13141279cd371a6a0aa18b6a20761b18df60aa9c14e13489afd83695a0921d5232efe72045f07", + "0x80818d492fd85d666bd91aaf6257b86527fdd796773c793407df1d4a0f91d74649a6bab4d15155c36ed4c6e0a32c5636", + "0x931e22918905fd6c230d3d867ea42861f3074d320d14e1929031924c8ac209a5c552b679b24563bb12f9749b4ee983bd", + "0xa4de2c333e74ed9bfa3c0bf6a0beb90427abd9aa4221294cda74331646b58ef46ed57cccc8798ba2b9309894b17cfd69", + "0x883881554c1d88c0ed8d3b6dec3d200f6fea69a77ace3e4d6f86b41506a23724b4394ec8384075f9c75c3868ba8a8e8e", + "0xaa0539ecf6ec9bf06f24443027f8f24b6b3d8c5b2084248eecd4bcad3c9a69716e1a0d01057f09a65bff1006ac5e157a", + "0x856d74d44c943c9e809b42dc493dff20eca03cb0cf5ed45108c69b1f90d8592a53ae8100e99380a274fafad23e74cdfc", + "0x9188257446661c88da093b7c5ce998135913f63842d7c1586065377b169ee35b062d925367fb9b909ca971f1188667b1", + "0x8d3aa57cdafbe998938787479f5d590c1484c6dbe94e6c487e57a746ef5252be0eaa5976d6270de7db64b6b92e57a0f7", + "0xb8f4d6997240f9eda5aca0c43323a828d1563c491b3db2087f60ac4120a3fcd06075fb42bb19d0339ab5ee3fb7db25d2", + "0xad247ea94b8ae1e81eae4c9fd7b39e6601b53cff47b2547ff90a3cca87192eae28408082774a1fd14bf9ab459b7a4f1f", + "0x9598598070f8bdbcc49056c40971e673726cd8c1bc4baa0b5124dfb5fb750e7baa7a7df18eae2bd91955ddcb1ec67955", + "0xb874131ab1608667fa60ea29092d090859eed1812e90c609afff96d79e82c5ba546f617f4c96fc32c9bba97431c1e9af", + "0xb00750a9cdc75c2a54f0d3cc99b0fe02300754f25166f7ac85ff41ab5e9cfcca33a29be76a480f12a2d410c7cd5032e5", + "0x84b5bd1c90bb6c66755b28ba4af493ca1b0c3a4df9f436aac67d2e07289053f925cf6a149a84e74e1027dc8758150179", + "0x99caf64bd9d193ff306e8ab5da3f1bb2a190a60c3a82099b8d03d17fa810dc53d176c21379f479e828f60d25beb3ffd0", + "0xa8fd9de502f1c261d5733430e5a18d8b7892a98c9529a016fc2ee53892ae965dcd9c75850bcda4c7edb980b8d88e60ea", + "0x848c02cac636e047028a3fe8c1bf4066fb7591b96b0340f8fbd476ff01b35fa3e37d309333771a134f24800e5f3f9289", + "0xa1eab1a06dcca3439f0166441e7e7f2f5b56f5f8aa9f45e411c561f556e0fb71c514c06c26ac53b49a576caca5faac3d", + "0xaa603f970dcbe953e700e61c151182c8d32cbbb53ceef572ac93383db33a4b098b5c7b267e42d514ca66b740c0925efe", + "0xb55fd5301bd700ddb0b4f72fabe9a91ad49759506101fa802ed1677e9553595aa4d2c66f7574e78d21ce882ce0120ae7", + "0x829137bc4da7b4886d3d04d2c39cbf4b1dc40c813ac1adb425c7b9abf9142b516314cab79c68454df5d71994ce416144", + "0xb83a3a22735001f783dd48a01c4fb3598a51ff3987e842b8045c71c035b9e43645a55254ca5911a5676ef4a8af12d056", + "0x8ca8d463deb13f9eef5e533bc39efaeb0c15631282c5c0deee1673b0053a7cccd514af09801dd6c158caa159fe9351ac", + "0xa9ffb1427828f3c456b9c8cc50782de1ab0029b9233a0fd998bad0fd014d27e15c4a32d1e16ad41bff748378b5abdf49", + "0x9627e29f725ddd86456aff813976bbc4a836f4deabf5ad9f73d1a260ceb30948824df9c8841e6b3c529652202be181b3", + "0xb52c988647fe3d9276eed3c262e1044f57fbb116c64cf4f207235c205b3fda0f3d789bf90f5217401b468d85fdfda404", + "0x833bbd6e2924f5c4446cb76b881d1434a5badce9eb9b003f85d076e297ad7ef45b822069fe54d17427a348c3263fb838", + "0xa067a36352db6f82a116cb87d3db5f60b18576852409e2076cbbfc7843af78866313a4969385a40271051dd195d51116", + "0x902b99545971f9a103f99d7399acc347ac46fe156166e51deefc0e92aebf5893460c69aeeae11f5af9f49418e289ce6c", + "0x9206a0e9ce9b9880f29ef0417c96931985f5d83bb17cebdbba4ff2af81a3d37155b04649426f698aed372e4f669599e6", + "0xb54a5d7c976e45c0b1d44433595eae9d1ae9aeabfd58cd5ecb0c5804756a7b01c9a517754423b4714a3695533a3114c8", + "0x91b612131e84580ece228b81ace83da0269b53f94d3c02a1a0879ebbd81bdc252064b3d03a7e140b43a90f237d9a45a0", + "0xa6cead3b8607eaeafe37135bd6de8fbd16f806c131eb71c8d36bfbe295d45b070255e50dabf076e2c3f6b8699be71d6a", + "0x931da21e67b11ba6ce438546a24d063bcd51aebe39b4220a78d9c0aab88b2d37969b5ef3502d835507f9c8d6d006714c", + "0x8fda408caa9daf01122a2308b7b9d328f52e1e2f138a8bec30492488f4d710e5e52524a6455a3a2ae2818ec8a610b650", + "0xad8ad5c189644352d90c462731c46145410e5adf38682bb80f95495dd64d9d13782537d68690847bbb06c6be7175dbc7", + "0x87bb5cc466ade60feb0961421c3fabdc8a7e20f11df8437bfff63d3f8bd25305002a396c9d0fa4fb9a9986d4717f12c4", + "0x827cff72870ba00c29064a7d2b4973f322d6b6de7924c93d8bf8825e7a0e8478c7748f90f5c716bf83c55b2795d315d8", + "0xa225895a8e94229776ceb51b05356291f2dce748be17a60d5aeb33ef8507c368bafe5d1d6eea927f28b9d1422b661b9a", + "0x8e011323ce670ff51c964241a6b72e0e0ffbb3ff9bb2762492323fc3a4abf4718091be0945287c7329850e4f74462cde", + "0xa2c03c2e5f4e9d3ef361f68b188451994ad1b24de9f323370559c8abfcdc7bffd289d92e78a5f6b104b0a12c84dab2ef", + "0xa22b4771116ce22276fab1fec6826610707ce8a342f9f60b079c4e0259dac3cc41c96c560dfd0ada6edd2828f7c0e8d6", + "0x97c17441d0af9be83b42097aa8b7cec84a253b9a2b957214b8fa93c26d2add46144faffa7b8a55312059b10690f711f1", + "0x94bdf348849f31a2737cbae5e5848aee711067bac85c11c2e68b44c398cfafbf3493a3226cd1ddf7a916e7613fc7b6f6", + "0x838f59c6e8469a8ec6fd40b978a3607439aaebe1e50ff707eec72c0b8278af05b477bf12a384b56d03e3d4eb91e56f67", + "0xa1940f0db58185e2b3aedd2b0bc2b73b4a65c68e09b046f38e9dcd4e13c94f5406bea92635190bf315e48ec64eceef2f", + "0xb2f4e0ae44e1f1210a91d8f280f17091fa994034ba8c991583f8182a323e9b3001a712e3584fc2d64ecbf2d319d076b2", + "0x9342b89c721338d02c7854cd7466fb24d93d7313b6114ea591e6607439c8ddb911d1cf35f01898e9c557982bdff8f9b6", + "0x8583fcab15be1dd14d5a415f4b14d706c8c62f058500f1344b37730c8be6741779691f87ded3cbcf6516468b373cafb0", + "0x8fa9587c7989646571ad9032f34cedd353caee14f5be5cde1e9e0a1710f90c08faf6fa96a60e1f150f761c9c8ae7417d", + "0x8d9ff904cc08141f5a9879f5f77dc600e6edbe859082231a4d819953890199bcc5f940b730ea688332f07e5279d49e1c", + "0xb5f82b46e5ef9a2df8d144202d6e2e4f3bdae8e2048d2af5ea7deb3f722fbe6d370401954e74ff0d8cb1010ffb1f38d5", + "0xa3b5b57d435b06ed70530e060002a8fea71746ad07d969ca23f22b5e52624527595b6a6d54b4e953fb7b7596bac378f0", + "0xb90f89390df6d4b7879b915aa3c29b8d779d035033f8873bb7ac54a14ec98f0d08c0e3bf696e2ffa7b5730d736f571f8", + "0x8e81e371b92887e43d95c0dbdcc9575282b26ccebdc8cbf46587e4f2a83b61e9bc0c6d7d1f114b9d21e04fd6c180b12a", + "0x8d682947c51dffc6e0fe0a486293c9ed121f441805168236393087cf62f2a429cca60bf0e472564844347d32c6bea27e", + "0xa8341ec7dd189fa7168759240224192c58209b53fc961c18082deba217928c399bde08ceae42bffd37c1135b4d14a845", + "0xa94bb076dcc5ee5ec82fac57c5b384c690df12631882bd1b960e1eb8c04f787bc22b7bac315b9dc5a8a098f17f051a0b", + "0xab64e1c6f01b87706c88a3bd974454a438722768de7340b834ccf93ea9880c14ee7c2181432acf51f980d56de73832ee", + "0xb7b0058bb724d879e5ad7aed6230297c54cb599ef659e86bf2cc84c38225899fb388391df9b2e6fdf063171937fd8c72", + "0xae856f4fb74c27cc98b67429186e7df4feb01278cd57bfd3170af6e52e0a23b9e926bf9565a890cfb4ae8f2d590b2cd5", + "0x804b9c6702f0596d328f92fc1ed5a30a7ba17b9204524135001b569233fc4937035031d079f52fd04968f37c24013898", + "0x84274ed1af6bd6a968583995622b4d18c6a2bc703ce0d0edce45bb736529b4836343dcd11911a94a134dca7877e6cab8", + "0x88808098463f7505034c3b6328c8a08186b33f7a981c08376e429dd64b79b97753170531ed078dd265ded4ec0a1ed8d5", + "0x92823bfb23a4eb84d3759e7d717f0c8641ece0927cd2ba8c728c26bb35df2629a838002f353c8d3d75eb19520aab5f25", + "0x8db36bae4d960cdb9c51f419d7ddc81f372e56be605bc96a9d4072b829f05527c37c8f255cc6115300a2a0d2e6568d89", + "0xa8fcdbd7f3b4d7ff04149a209feb75e97149e7efceaa42d66a6b8e432590fe7bd01f1a77fa8b47108f670b612e33fee9", + "0xa9f4c53c62db7e5dbdea6918862d3c6d24b5bd8732a218edf0ba61e9d1861182323d8ecd7bef8f895b42970b492f6e40", + "0x8b95bc7f07818f4d7b409aff8da0b2c2ae136cde386f53a71565cae9fd14c73c13cc1cfd79c0f97cd77839fb738c5b9a", + "0xadbd1d11adc756b51a571ddbcbf4392415231ddad93da09acfafee03a9e4f9e1ce3826110619e5271feadfaffce3e793", + "0x95d327c8bb195cdf25fd79c98f9406a6b0316214b1630ebcce95bdaeffafa36fc1accc6882e0e5d13a8db5c0f3c0e61c", + "0x8cb2f1e2fb25558869afdacc7bb866544cfdd566cefcd048b48d458a886130bd086ecb7600a960a7f2563c61cb326510", + "0xb3aa8c4bf5b933d89cd74ca7f7176d6624d562d7d58b041328b49d7562a30b489cb606abb3c49e85baf04c28e9cd1f44", + "0x97f9053a85250c420599827297453c2cfde087065b823d9e43139e6a9cac3a2ec40a1b6e2f0726bdc870fff215462f0b", + "0x878d5dbe6b881389c2ca126ff66d87127c9aaa3f62f0d2c1ec0ea2b279ac95f8a06710dce166415db227655e2345a04d", + "0xb2c33a6b4203e3ca5247f0890e475518317ffc44cfbb1da9a1ba02114e8b752bea618050b876de5cf3b1906140a64471", + "0xa56170c8313d2b5541a795bea9934d4425b185b5c409f0484df6f44f0e4bcbf50b860ff46b7245cd99c1cfa8fc1965b7", + "0x96e2b658e2876a14147385fc423d2702a3cb76962b6b437222cf9cea39ebf4bdc03bbf434b747866d4bf72b4ceefa639", + "0x89c4a74fa2f067e7ae49c84ef782c331bcc9245db7e941804e2e99d12e987b4d25cb827778ad4c3566c4fc68018650b6", + "0xa01d30cea7d01c80ff26650020fab02e78fc3842e2398a81b44b21d58d4e9816166ff4ed2418831fa995a28ff35cb6f1", + "0xb960c80b55a8845bbf24bc3f23b0110ca701f9544ab6a5bb7929330213cb471321e55c390ceca3e24bff69bdb0d331c0", + "0x802c5b13f22be7be0e5db11eb3be0f0ea7f9182c932265060ba05fba20ea093dd2810d3b969ee3e387e60fe6ee834e8d", + "0x92478f88ef7435d15e39a97916c736abb28ea318394b88678fddbbaab3eaf31776110936abad116a8ff6ca632dd12043", + "0xa6d3da0370c303001d5ed99d1db8bce1f26b0e442f0f042e36db9674e92dcd6e80465e772f1e669f99221caee3392fe9", + "0x938f04f70a8f947d6df2f0c0e9af3cce0c06edbb3c131970dd60884fc0b0a0959c504a2a36c3ff76dfe919905671626a", + "0xa7117e55224230822e9983df2132347eb7208cb6798f291df926ab51e04b1a1f78d5568c9a8924ee6f57426134360f20", + "0xb91074c77ad93fe48dc2b10c0c5a62ca3ab7d98345b919c52d84a9dc419b59fc1b267e1c2d4b2e120016ef84bbdb0cbe", + "0xaa175c6b6edf02fe8778762c9575581c0ee6efc9dbf99c291a41444a23a056b893be6c45333d907d0bbe9fb0eef84d08", + "0xad36dcb4e2ab425aa339ae464b038d550cb11186741dcf257f1b8b80ed4f32ffabbece45e2dc1525d4c3eeed819ea04f", + "0x91cb35c1ffa9cd5aebef523edb8325078da3eb5cf9e95c675a76446fc7692aaee6f949de064ca2f3e0f082cc3fa93e20", + "0x82622f9410c143a86bc4d756b3c7b324dc295231ce865de020d61cc0868f2c150a473cea3a5b756b36771ce1032415a5", + "0xa5c29996ad3a53468ece9356a5b4ccb68971ea1c89cf39644f1da2d4a477c2ea99bf791ef902b87c225d8c53d67c4c92", + "0x92893eceed1af34fa92b23dcbab175b6a0188a27dbac9ad3317c4e39955a763cb383ab13fb1c519cde311d8a4d12e8b3", + "0x8a093cb191b94b0200e38d31955f9d240e2be1edcd6810a2396a061f17c3ddc9c4f4d56766ddff4e121be7110e03b869", + "0x93981473df0cb1f4b47c7d9b64e3123dcf1593845b401e619f5d7c70b5dbea375d1ca43fca65845fcf0a6b2e0af43791", + "0xa6beb6b0697070f9562910add88d9ba91992f8da127b27be81868b1596d1012f09ea7ed601b4a6474c921a1a1a6d866c", + "0x92026b1ee30f2ed61c9f30337c3356844217926aabdff383c19ca3c21e0bc49811ca5b308012bee4ef250cfae1615800", + "0xac0ebaea6d35f84dac4ce648af096305ba68a7a0aea0a11ab2fbe3162075444a158433c98141bc92ef3b3400d6deb46a", + "0x83046f482dee24ac3ca83373f0d1b82ac1c4beda0f229a9011a81ec659ff5fc1fb105e219975b5c744308c77a24f71e4", + "0xaa5a312c47ff7248dcb9c6ffbe5a0628ccd565c07365c4413734d415cd4fb35772622ed833862dddff520a67c509c6a5", + "0xa02fb88805c34018ac33582e19ed0a7e4616acc3dd0867e5f21914c2031c05c6dca30b8b35b57c2b137750f3878a6f8c", + "0xa60528f1f14bf0c496491d46a0fbbd6c343e4eb3f1631e92f96a3c5e5c684091aabe5801df7a67f7c6dfd1b0d35269d4", + "0xa1fd8e7fad8ca05a340c05a051bb0eb4197eed345f4104629a9e38e234b09d789cc5537024615feb4a6177d32d39e39e", + "0x8e70e36c1aa070815440e19443f1f04aae23b1b59fdbcba43b47b94a026c82c8f66c5dfe54f826f4d95ee1930cdb8008", + "0x8234c1969fa7e9079661e4ca309b71b1aaa10f4372be0b963205c23a81f5a3d52ec08ba9ff65b37f832b52d631580d61", + "0xa18cb4134127fb37c4abca328cd0047378a2e1423490af2bd3eba9ffcc99ca81a3c22404c0886f21f65c7b93c41d7981", + "0xb46fa45fe538816de776eec086e040005706cb3eca097e290abfb6864e745c879868aac8361894f3c3564373ef9ad55c", + "0xb96ca43b96c59e95439f75d1e726a35a9362f0dbd34963b156e103e080a8126a8dc3501f9fd541ff3bcf4677f5c4a86b", + "0xa8e8c87c7301613818d57387009e601a7ab5cbdc2890f63d985c30c74f9cea2d0584c116baf0d9cd5594386ee93fc661", + "0xb47e4f1b9153ef0981f813948150f283b47a7346fd9921d51fe8e4daedaef78ddeb4fd467c2ccb7cebd9816243da1c6e", + "0xa370c202a99c8441ffe96fad0f801086d4d7cc7b960f6e98cca29ceedf492afddfd0f351c9c4d29ac008bc255ec1a2a8", + "0x8f5e6ce1655d1c059b006174e3f5a55c88e1821c97f9702ad8e8455d46c2a83ae4482f2d43edda74a835686ec45a8a15", + "0xa30421e694930a3b65d397b2720d5f8e1eec2b6e2bb5a28d3f9b0a84db9aabd83850268bae64c2b10e313cccf120151b", + "0x8abe87163046f7a9b18e2a3c0b66e258facc1b31431420e0b70354b7a60ebd250a784634a76692e7d6f4330b62114945", + "0x894f033cf077d4eb312e3258d9dca414356271abce1d6094ecce6d018c5fadb1c15d8d69451574ad0701a2876db191c5", + "0xb0923d64f88ffc872654e1a294bb1af8681689c21cf08f39afe51448a68e60a9a0a74ccce9969276a932a52c07d095a3", + "0xb9ca23b5be8725fae7fa710eefd45522889c50c29c26384e00b78a962384f0aeff9d15cb5910e9565da12a577eb7e5ba", + "0xb242ccf292757197a9f470f2d80ccddc48c7f1235ba026bc68a93be2738bc968e8a200aff3e2f4807216442eb3fc50dc", + "0xadc2c3b375b308524b79a024ff87d122055440643fea6fc0a651bdb312c7cbe6a456afa9d342bc76446d77d8daf08bc2", + "0xab645955356c2ebf2f3df9da275e01daf0b44a52afc309277d6d9ad1b05484e5ae0d9d41ad485fe481e5e362826a86ae", + "0x8de96ac587a4449fcc8b7fd0a51b4b5185d9c2eb3434f94cbadd092de1e26b0f6b3f7b15a37e8424b1429121ddca0ecd", + "0x94c70ad4e9b871566f3da98170b665a09788d421818299857cde0853789fb943cbcf7d4b2c95246ea7b72edc56a8e36c", + "0xb2574be63497843340700b701d5cc8be6d23125bd62058802ee67cce1f3b5f5602b27c93fea5611f27dc695ac563f042", + "0x869ec89da7850cedd88bcb3a50a15cece233119b31b64a61bf6b2310892ce42d8b473b584b11e61db29ed24ce8033f83", + "0x8fbaa269da8e28e9adf4c1b08f109da786dbe9cba871c32eecbfb10619b7a5d65a26f9bb33e201a8ed20b3de94003fbb", + "0x8bf7a059c37242caf7f821a6314e4e4adf799e0dd86b37892a7172598892c07272acebd05b534755c57b51556b2d610f", + "0xb4e72645fca459898cdd9214892ed08b5c99f82049c0a30d72bac0b9717caa9c6cc16c3dc7aa6ea4d42dcd2a6c175df6", + "0xa39170da87a3495da55bbb9701c5461f3403447174ed6a4af75712f7ba4ac35f51a4234bc4b94da888a0959ee109c0c7", + "0xb45675b2774ea7696089dbf7a0afe6c22e85fd0e4ef3db508fbaf96c9d07f700c991789206da9309fd291be696357c5f", + "0xb52899e3e3f6341eefcbe1291db6664bf3b6e8021d32fb9c3e37b6258a35c1da927747b2ce990937d6f4c6c3e7d020d2", + "0x84e5bdb3dfe19700d79dd3fabb0159ccfa084f7288db836c855b827613ce8071067c8d7ac5cc2b4e88ed7f84b690f6e1", + "0x801477d200b6d12fc6e0a9bab1c8211193ab06e44551e037a9b4c36fc2d4f67760b9ff4eba9a3bc7b6e177e891f64ff6", + "0xb6b71a5116d3c22af26a7530f535e9b7851f25a84e562a8f17a125d55b9b3fc1bd8cfe65bdcbeeb328409521e802051c", + "0x8687e21c34d7804c12489d30680d131ce2133e2981bfa993afd8a8eeda958ebd5e6881d342d725338659882d9f21cf98", + "0xa024e97a7c4de32b6383c34431994abc533ecdbd6be9bff836ec1af022f5a86773bf345c6f33273797a61fb70a8fd5d6", + "0x83f784f095da20ce5b31f54d6cb14b32a8a12675f0029289c9cd036b7c87a8077be2d04a62618685720e6ee69c875e97", + "0xb4e9dfe7cb9d9efd3fe00d99ae5e48769d4af4bf43d4e05c0b54c9cfd8bc854de96b8d3ebf4dcc06b9dac66b7471a0de", + "0xa08b79f9d4673afcf7f38b57f484f88feb7c908f597663a2417f92c348150c2be6b5603f914eba0d9d5bdd4e5c5572c1", + "0xb0eaf919589988798cb01ba0610cd1b7fa3c08715675ece8ecd5f9ef6d5d7b2c4c8ae1ea7dfd202237171aa3e6f9de74", + "0xabff99a98baae4dd0954052503ce81827781694a5ea8c1149f96a3adde75dc2d630e138598cd2ae7fdc7a654aa17df8f", + "0x83e369b8680d8b9d995222b033b4f4f3e3b20e782113c941325c7fa9c742feef8747e4a212d9aa23285a259cc4faef8d", + "0xb16d5855dd2716613697eba36e2fae0872aaea6999e91cf6552f93f9a0b85ed4f6ff922a91b50816bd6cf8e7a4513fc9", + "0x848373db600e32e741aa1d37726bbb28956783f89ce2d781e95fb1ee1adf4359968a141678af268077eae4c25503204e", + "0x93a0dd0fdac18a31875564505b4e28f9e8bb2915faae666538597731ac56cd77f23f2456461e2f672983fb24ad91f6e0", + "0xab1ebbe49fa56524b564bc2e43784147073e6ea5d27a9540fbf2e04d0f87c645ed2fd28b3e4982cc4c0af1734ee47a6f", + "0xb3ee30b733839edab6f61f0738e3f4afaeccf700d8dc7415684f193b36d70d07acd5780cf539f12e0fbf8d4683be773a", + "0x88388f2cbdec47a6b3ae460b69eb0d2130ac14de950c22fd86de03e40d02292bb93cebe62432da39d509c1289f785fef", + "0x9370c41a54b68ff486b4cc6329c3a851716ebf1d088d77a6c56dec93a18b8a77b596cde74cc17d2adb2b2f411a2e4bbb", + "0xb9083b60dc16531f77b05a955b51a237a8f8c0173d72c352c5ca441b55abbc890b14937e457aaec4be5cbbf80cae0099", + "0xaafff8f6c6ebaad952c65054dfc7c829453ec735331bf8135e06406b7a9f740c9a200dc48bb2175516b41f77dc160121", + "0xb43d31fbbaf10526809e9e5bd8bb47a76e0fabd7852ee7744404559ab89f0f215ff518f3271a6aa972a459cab82ac558", + "0xb581ede48c6ef34e678f91dc4b89507413e00e70712e3e8c32a80eed770ec8d8b98caee9702d068aeaca6f704be57bd8", + "0x8cb0a137e68b001a5ccac61de27cac9fb78d4af7b2f5a00b8d95d33ac19cc50c69e760c5e0330a85c0ded1edce0fe6f9", + "0xb947fca07c7aa6c2bf13048275402b00b77b28f1d0ba4b589fbcede13f93b5b931c588560ab8ceba23bb8e748031b55d", + "0x81753cced5ff819901740a9a584334e355b497cb699f0be5a52cd555a4c9f149535c7bb355b54407f7f0ec27de6c2e19", + "0xb3d59273951ce97838c4853ec329782a255b5fc7c848e7992ded1be28a5ada7fa3254123afe32607b9991ec6e0659b08", + "0x86b253de246f82be1cb0cef01e87c3d022ca1829d2cc7e6a160a5afbd3ca6b94d75739b122e3bb16f8bde28a8f3223ba", + "0xb728b659fa2d8487e061a37f7d14a4c2d70cc37497a8715695d8d332cb274deee2ce23b9b5f6a7408516c02c3d526a49", + "0x81277b46d98848a45abfbe39842495659dcbb80dee985a4fc91d77d52b815487aa8bb455f411fcce4c3879c7a075a93f", + "0xb05b6f1fb4a6e654f0ee6b83e08b58b57059bb0b7c490405bc8d963c4a2d6be39c558917977e554e1e9e3169961cbf3e", + "0x88f75fa7d016fb6442551ec071cc1e2beeb3ccd213d16d744f573a82f5d70f41dd1b18af71d5f9e73d87f2f6b7dbe889", + "0x81a46434f1bbd65a661a0ff45a0295b8fd8a42a7969c5953721bc98698b64bddee3f806876d1e9983063fdd0c11f99df", + "0x8b4f6d33c510a4c9c7d623d9ae0c9aa631fcb987704726b2a4d8519372123bce3c439202f25b5b47045ec14ce39a21a8", + "0x8d5112b330fb63cf6ef3d2164b404c14ff9907d685015701399a260951912b19b8f270f869df317e9050a127763d7980", + "0xaadab394e84dfb82db15ecd2427f39b62352c3e1647c3bcd14fb24ae830ad0116f0fed87ddb63963b424a4741961386e", + "0x81ca4e5600d00a3bda24cbdea7a532a4cbbd893c10e7ff10667c15ffa8138b91667abe5466b31a3dcdd60155c48538c1", + "0xad943af1b8a5fcfcf309ed8f2f916339f254cd555c71a407a47365a139306286a05a8314e1c70e20a65fccd75d36fa12", + "0xb16597a0b437060a390467bbfab94c0bdd695ae898894f4689f939e30cc2119cc08ecb594546304adf876f4e275ebcd9", + "0xa44a4e0a6693be356065891c27eefa040a1a79475be53d54d5fdcea7e0668ff9b35f850974000ed119f6865aa6faa721", + "0xadef27d1b6e6921f4eaf69c79e2e01f5174f7033eaafdd33edcfa5119af23f3a834ffe1bdf19576581b797abd1865b34", + "0x90c1e9202f3ffe28f8e1f58e9650dc4ff4dbc158005b6f2296ec36147e524b4f2f87f8aafc39db5b006fe0c491c92f45", + "0xac817cd54288b6f7fe6338415344fc9e7b669414051631ab2f27851c052c044be06bf7235d668e194bef695923256368", + "0xab14944ef653a14456d4ebc12e3196df3f1b4707c4e50b317b5ccc8ca3a0720f0330609f0e7e71793f6ca01583f38c70", + "0xad5353f2f380837e5ffdf079350b3d42935a0517861d03af98db5ed3ea8501abd68885c8c65f5a66e944b1874826a450", + "0x8b5583863f84af8443ce8970b02e26cc5d959e47efbf8a66a54106ab165f1f76b36423aee74c7b5402fd1c4d7c1adfe6", + "0xb3b46037eed9fc30e4f8f0da8bdbdcc40a38e22e876ce9fde981883017854aba82c18eb00887d92ad847d30082fe7271", + "0x98a2b6fc90b7ad172e4368c1e54675b75c8bf2096d91c9f2b60b3397d3be3b705aed5389845dbd68f0f84438cd0f7687", + "0xb155e800852a5f90a2eac69cc4483428da1dc2c31588a13c924e60a7616ce9baeb7d4b829c772b260277cadd8ed84719", + "0xb8b92c520a1302b0cf7d993a52e1dacd7f27bda9868d59c55687d995ae676b7070af4c0792a9bc1c2635d44a4fee01bb", + "0x96dfe9bde526b8fc829eda825f55168b88e8f4e43d4d708cc3060df03437b46e12a8ac70d7788aa75760f6294d3e84d8", + "0xa3fa66c54e2fa084ced3bd838614c6c33042f492a5745d167a723c60d5e7d6020ffd1747981a23f8b68df21ad8f0fa77", + "0xb573ca10cc41fc04a642f6f62c355a4fda69b94b8e95dbb02fd1ccce4bce1191356e1fd66d372159944eb36a7071f005", + "0xacd0a1c9abddfd0ea223eda1722aaada362d34234455bd1c6be115d41e535b16f12ca428da7820a757fa4c98884a385d", + "0x96f242eee99c4db383b8754fa7987c0c159652e1866faec905a8d3f010e0a1ad05bd77b9ea8dfd653738959180f58430", + "0x9215a9b672a5d6e435e0e0a45156e0e20f75cbbdf1d14940fed3ddb63d433bef643796c7a4fff881829ebb2b2eba9460", + "0xb8ad9bfceaf08dc5a874387219ddd1170bc3a5e25ed72d321d59ae713be5ddf9fdfbd3aa7ab163be28dfa0dd14614e19", + "0xa19a1050590bc500b32c502f393e407abc3d8e683d6f6b978873aff3e3299b18b1f6b59e2b0fe237d819dbdfcfdc98ca", + "0xa6870fb11d4429686e52e1f44c8dcfc7ea24a020df9570c021578dbc1f9bdc8cf797cb3a72d7fc52805dba35d59f2cd0", + "0xa7be733b64d5c06c127bd1c87250e42bfe30ca91ed8ce51e0b6e377f454e8f6fef7f99bff650695df2fd10c375da349b", + "0xa1b97145dab30330eea2cdc8739b2446a3704b64505fcea3dd8a9b4a72edf222e98d967d6fd7f76794acfd97aa091065", + "0xb2127049907d2a3b654d1c940b740bfba3dbaf660f86ea79c2f909af7c9fe2a07a1caeb1be12370aeffaf8faa50f1582", + "0x8a207701214bb28e99b0784e9228b1c34afa701966267fe7110f6f29f5bb41eaae6cdb98844d0400787978fabd224de8", + "0x9925147a383b6f5f814520220ffdbf20b214225882c3ef49b1a1ca677709176ec82466fb9c4be2dfbe5640afb63b014a", + "0x8416ad93871623fb555b5390b80de99edaaf317350cc0c1ae9d54d59517074d40061f315cce8ba2026d9c1e6f6a1009f", + "0xa315f943deebbf0a2cdbcf3f8323e215a406e9cbfbcc3f6288714cb3a6befb1bf71b2a21ff7a2ec4731c65044c45b6b5", + "0x8213e0c2539c24efd186ffa8b6dd401ad2233bc19166a0623b26dd1e93614bbf792823f5599ac116231e2efde9885709", + "0x8e5cafd2f34a127a4a896f05e4d929eef06972a1826b3566446942198df26d62f7679b987db2b3765d9d8058b1cd85c2", + "0xb5302b399c9cdf912fd59007ad4737255552663b1e56dbe64a7b2ddd88d2093c73ea319b45db2dd49d1e03f5bef1a0ae", + "0xa0c2bcfbed4b008e1a56e5d2f2419aa59d7dd0ebd990f1c18588de702ad0fa79f445d69965fa9381e700eda13b309378", + "0x80a44eea1ffe24c26b16b8e2e70ee519258b9ad4b3e83cc4e5cca88ebc48d0160066f8b91d0581095b0de2428390c8b3", + "0x84a90cb9c7d2f799f1c4ed060387a4b793ab41c5c3eaffd3b60face9b9c3bae93cd2017283bf3de1e3dac63d0d84dd42", + "0x81d22febca276a05ba9bbc5591ee087b0491beb35b4d9f8fc0d041d642a574667ddc57660b20f5c568f7d61fdcb41bda", + "0xa3ac965ac27a28e102a439b74fbfc157e75fd57620e4c0750a466165f8aeecb2191dcf8e656f7525aa50d9c7c69b0b5c", + "0x913c17434ff0d9fc52e2ece4fec71b37d4474a18f3ea26925c1be2b250434d49759f58033ba0fce1c6862c6197930dc4", + "0xac430559c151a5e461f67b49c7786c97e1653fa8698e9759ddbdd99f5daf17fc5a012ae6330739440880728f24eba7c9", + "0xb10d8e9f8aed9361b042d1398ec74364f7c7c1cc5c7f917060572761138bdbe89bf409389ee3879f93bc8032dd67b308", + "0x937271005a4cc6a6ec134870c1b56471aa84ed4f4af1b3d5f334bc0c42762fae0c9a6a2828d3de6151a76dad7b72781c", + "0xa10e4dcf51889f69e6bd4c052f8d4036b9571ced98a3d7d779cbcb9fa5c3a82228566ea7cc1d012bf56dea0a40c5a64c", + "0xa0ed026528d9a8bb3201bc9dcd20598933e8c72fd315deea8da63d06e97392aa729d98a55a8a60fa4d5573513ba5c9fe", + "0xb723fcd04cddbd4c36feae827a03746ffef251c4f4c55a88beedaeeee194430a99f566f483668a0d88b13e7a4a37f1de", + "0x84a2cdceed44828c7c05a6a762edec0165e434e7029df617d6646aba48776e6c3b823f40689cee136536f8c93e08a629", + "0xb786264e3a237ac3a1d56c9f4e87438dfed620c867100fd38b01287f5b755c7820937403bfb86644e082094d3e410a00", + "0x92cc35b2065fca157c7bba54410f8bd85907a01c9f760aa0ddb7a82cb55811d24cb4dc6b725367a6a1c293b809a48ead", + "0xa12bbf22b117f00164a42515bc57cc9e6c43cc77fb737ee3d0c0cad94cb50cd3847d61cab469cf8ca76f7958bdcfc771", + "0x85985b00de533bde2a757eddf53be79ea39091d16af3fc92327bcd1cd59bf2bf4411a334da29ad775e8ffaf3cea7d7b8", + "0xaf9eb24185b0d330d0ea1d0b0fa78af0dcf42ced81cb0128f16cafdea687a9c5582bb6d7c5744117b271cd0b3303f0b5", + "0x8c8aaa1d85ed6327f85d579767c7a9158d209171b3efcb3e8a9d9e534c078e821b6aade255101d2c9ef6d67ba66f10be", + "0xa450518a03ffb40e1df89e0f88fd55b5b06f4872cdfb7ec55f40dc40d9424b3b289866336c195bdd54597d95569e0096", + "0x81e61cc69f93c435bd77f155e80626a9c764dd92b6c76af15c41346527948d8a6ca87d6351a0fe7987e2ee3aa66a9625", + "0xb615e0cebf4fdff4cb23a20c8389c370915ba26aa703b28efe4ab070b1603d1c5b6541684acf46b52a915f6aee447539", + "0xa7f51885c7a71885cc84ef734ecd107e8bf5f7a25131415f671d143cc1de92859e65001125323c7985799993af6c410d", + "0xabfbf7a46f32066989c32f774edcc68163f085ca81e94fe8c9fb32f8d451bbb2c20ac45cd8d97f9e618ab40186933b1a", + "0x8cf35a522b5cac1934004aa9dd236bc77198d43272888afa860cfc79b4b28dabf7a3c74098f84510897566fdd609aa45", + "0x86aa927df78f7a06a4985eb0a4f0b93529cef14f9fd2812d46abffbf25e618ead14d99c70e3c3bb2e17f3f7fabc9c264", + "0x860f1b4f4a398e9a8bb4739587cf96979cfbbe1687b7e91e5bd1198db726391b09b1a261bf12e96698818f60b5bd3537", + "0x8e7c4ee19ff115881051e8637dce1f5d6c65e865d0c757e8ce41b6d7bcd86c7070cce60649692bbf28c868c7e2e1e2f4", + "0xacf7ba01b0220419f09169ac8d16e5cc13dce08e88c90b8fdfaa33aab417f011a20b79a178d8a9f7211589d2e0affd7d", + "0xb404bde8e715aefbb9f20a353b911b79173ef3e2cf0aba98b5ae6190b90597d65043b0b4e014ad9ea6c77da2d213ea12", + "0x97e3615d1c77a402253bb55da2d1cdf82de316cefffe42b1022c94b4818d6dc4a313731db85321c537914bdf716a875c", + "0x940e950b96a4096a578c6874d747515936652b9b113a5f27f5a834a610867b05f9881e2679b0b289b8527baa0009b6dd", + "0x8de15a13ca236a3a285ce6e6826c502ae7365bbe468b6e8ac67b15b0bb49be0e996f1eec81ef69e4b7f54f8e4779a054", + "0xa12244777eacb08ecd42b5676b3a51153022ab97e9353ace0f47c6054c22de9ba60d2a60f59a36841c2a791cb1b7c288", + "0x94f7580203e39a2642ee2e7c969b9911f011d7f3a90c398e1302d26edb3df03df1d0c43baa1c6cf90dde95296d49e742", + "0x82ead33144aaecab965faf63af384565992f38fc1066e71e33d53f43ac93892e27fe78c4eaca1cccbc53364e26ff31e9", + "0xa0c129e9706d354249a7f8aa664ccd7ede89aa1445c5547410814b56d10dc086720953363ab1da8ff5f1ed5d8e575104", + "0x93b3057bf3f74edc95237781ae012cc4b1d3fd0455565ceaac7110290aa518ac32478ba4eb9851555fa87270fcc84f1f", + "0x949c2fd0b94f31f7cbf00c679bd3f6ec1a2f4056654708d39edf1a450b4e19a6e251d0bb24eb765087e698f61d3fca2c", + "0x99fd2e50e211ccb66b895eb2fc42f260f3ad5767f04c2fe238b81dae98aa6e3977443a51f4fe7b43f499caabe45699a5", + "0x84fe19626503218f327b5325bfd7c0c3d2614b47d34964aa0259d564e769c6c81502132cc1765b0b31fbe39852706927", + "0xb43287ec29d9010bec4284de58fed48dd1e129bac79f09d45153c9949131782f77b11b0c9f8ee06a39e5e9bbaa8e2c6d", + "0x908902f3ed45482df2f94415fc8e5a308057a40c8905d7cbbd58ec4848e19276577b7f7e69e5e684a8b981738e10f7ef", + "0x85cc7d9c1eae372b4f88758cd6e21604b4bc9f0794e1e74b6d9de96347f81944d01331385fae7a38e5f6096c1dc23465", + "0xaf60288c702082fc258b3dbd6952c6b75c1641a623905f491b1e72f49b9d39b33d150a336450abd3911a4c128166acdf", + "0xa7d8ac7e589558c4014369ab6f4c1f2196205b03e4278152ec0dbbd7ba54e803c3369a71d364a773aac8dbbd117e4a13", + "0x9833aed34e48c206e9328073597aee1123f5bec085339b4e6839a389a429bf3042798a31fac1464ce963204adface76b", + "0x84631a4f012bbb62133030224b57deb32dcf464cacc8ffde7775adbe68707263ab5527a1c75e597e03aa703ba658b889", + "0xa686a61f6467858a2a4c13e70ad81b1901290d3e51bbc0c6e366f9e652f575e91b11c75f640ccef8b0c6c1b05a43c9a0", + "0xb585f0ffd5144907703b41539bfad7f9f058f5985f63db911064ba6b07af8da2796b84b16db42b8d11135c3f846cd9e2", + "0xb525539516c7bb25f1d7e165f269dc8c9eedbba74df44887e178ab8fd798e2a31f39812ca922d6b64d91564f14012a64", + "0x91e480d7568fd2fae39c35b0a8d623e66a3160fee1dd4e9097255004938b11ac1cd3918dc6a1e5fbcb700c95a547e5e8", + "0x936ef55c69b842b6177de71fa48dc5442bf5132116b214302f8f242ca36a273a6bbfbfaf373777104dadbe8e7da5e970", + "0x8e950c0f6688abdff8a3b8bd77be6da6f2565c7b55711f5860ea62a3ab1d51aac31821c602bc11a45e33c69e7dde3ea4", + "0x90eed4595104a0527f8db1e028ff622ff70db4eae99cf47f6c2a0246ec7b103570a6a9a877e32e9647cc74969006743d", + "0xb756344f6c4ea05b792e416d9bd9ce9dd4bd904e7622761f28a85628506bfc9d88a25e5f04db62fad30a92fb1d8d8556", + "0xad79ba76534c1a02ac3e9b7308d390792984cd75b7e1d0e5e4ff123642d99d4ea1825643091aa8117336333c40d5bd94", + "0x832b08144887de0c0341d84f6945450af8d7a4eb32367d7703118186c1be525df9382ce61fed5f3b65a0bb3449185f7f", + "0xa322fb944e46d8e47994820890c94af423674716da810ea1da71e0a7733ad72c22114ca39a4b59c98ce4291a5684c154", + "0xb982851a65140dbea79bd3b5487e236feccee051deddcc17c2853032efca289ddb6eaf64be3dd85a73012fdbe9d2d4f3", + "0x8eed5e230e201830b44b9fadca4e156fe1a16bf840cf29da0f381ea0587b20c226de2465c67e6268973e776809af68e1", + "0x81c8f1c04490f36e41a53ee1b5185cb8adbb37c258fd6c3be8c56835bf574c37183a94d55b6554fca35d6e6dd9af0133", + "0x8c4928724107cc16d36f2976677eac0b852fc4c3c0bb2f9cd4d59cd24a113faf33b2faf405c3fcce25be51d41e42c2c4", + "0x8e4ba842636fdfc4d71f0983538ea5037d420acd26abd12efca48c252eea85544b2fa9fccdfec4e7c2a6359baffa112d", + "0xb4315b84700e26dec26f3488d308430fdff4809c10d4c24309627911cbb769ffaad0d1ecccd622dd02194eaf5ba59f91", + "0xab888308f757faef32648c1db01650dbc9aea248b09d06e6efcc996d395f48ec96f2d54a02de441d753fe8737862d991", + "0x805094cfd77e207d5c75f3cad99f41f763ec15443052cfd758c6a82ba422d831a1103a7f9b100da49c28198279c3d3dc", + "0xad857f33243e4a2cd2a773700def21fc7f94939d1a6d2c2125ecd58fc206ccafb07a2c02a1cfce19857d3654aca2c70c", + "0xa4d12d40149953daa70b89a329e918e9d93efb4e8004a9357fe76682dab9662c8507e16db83e849340f05cdb4933a373", + "0xa0dbac2ed4b5d03606524245e8a31080eb5bd3e9a0c51dad88c3b18e3e6bc5d64953a81c8e60425b80107ee6b62b1fb4", + "0x86da05355900f327164a78901f6e3db857531b33b1e855df1a67a9ba222c6b05fdb6b0ffbacaeb1ba5b45ff8979b6b68", + "0x932c9873aa3e226dd922b5a616c75153bd0390ce8f332a414b9c8cb6606c2501a37a2aa88097bc7d8e2c4261706eb38c", + "0xaccd9cdf07ccdd42033ce3b105e00bfd39e2304b1e3d66f8b1128645634452c20f759ec45adcef2fdf04408f62c4cc04", + "0xb75cfdfc1cb48918752eab17eb579820ee6e71e6667abdb64df834ffc8c1362fbbc23ca2c80dee248fe1fbb72d87dfc8", + "0x88b998c73b00638fde7d3dd650a08c5ab996dac6ac34251337fbff3fb5ae4a25dd20c1a16c987ad7ded19eca23cea891", + "0x8afef0956c942571a27f504553fb312cca9e50ce41b44e0466d0516c5abe4d8acf4594cdb03b1ccdbe3f2e6a9093b713", + "0x9042cd83c5ff261e9ebda26398caa16cac2cb840d19062fa8ae50e044c27104972948318f4c866dc4d578798272d3e49", + "0xad536719a64570a2cd1d72b6590ea1d02c8c49f259a7867be26c8191445165954bcfad50ea12688ace3fdfb0e98143bd", + "0x97c86328d63d297b6bc9718dc1ad5a05b908a750d1c455c700d84315589128ce4eea958aef2bcf0fcf4adbd8e3ce58d1", + "0x8e592cf0802e6a9541eeb654dc55055e11f3d757847285197132935ca35bbb1a9156829a39384dfa6f645ff89eb36738", + "0xac16c614998944f77590bf3913a010e13f2d3bbf6a172293baf5983506c1a2d89989fb72e598f5bba1ea10a691377c93", + "0xab8e6f5b46baa6632de3621497bcbdd584decb999fe7d8a3364843a1e0b76497600630b6a24dd30119d8bcbfca29f335", + "0xabe1d3af5279e60122d9cea8cc6581c819d7a0e20e3715da0f6da7e02d13a7653db643bd946e2fa9ba338eca81fbe140", + "0x8c33bd831ecfb18d1d0713e16beba768e9c42df62170c1f8a16764912be77f2ac5915623d1d25e8c462aa9c2f6669ca4", + "0x903692becae4a6409f7bdb127d9b11de57a5739fe24218dcbaa0092648d5332dfeef29a908ee9e43e5e0a51a4c3639bc", + "0x92591e90347ae286acd365eba32cd9ad8f20f4c9cad2dc579b195147ff290adf0d776bcb3d4b04a25d68a941fc0c781b", + "0xb64bbccf860299aec16e1f95c768a1f337c740bde612e6ba260e393edb8b04540127194761c42597abb9bcb771c576c3", + "0x9194f056ccfdfeb78a11c5347e2255d7a7ebd1251f9aebc0b58feb68d3e03a7dbbb74e3ef7309455853adfb4694bd01a", + "0xaa4f15f6d6a53ae65b7f6f91e8981d07a5919d2138679a561f7bb608dc4596e45ca06c9441d51fb678b2ad89ae7a17ae", + "0x90e3d18507beb30bde08c5001faf489a19ab545c177efb3f73fbf5605f9a0abcdc8bfbc44f832d6028e3e0a834bea98f", + "0x8f31dc0118c8c88a6e79e502d10e57652b7aba8409a5bf572ca63fed6b7cbad7f28bbc92ac2264f649792fc1d0715085", + "0xa307d1067ea4c56437b6f8913aa8fcbf4a24580fc1e3336e7f6518f0f3adb9c4733090e459a3f737414ec0048179c30a", + "0xb7cc41fdf89595cd81a821669be712cd75f3a6c7a18f95da7d7a73de4f51bb0b44771c1f7cd3cd949e6f711313308716", + "0xa9dc74e197fe60e8c0db06b18f8fe536381946edecdf31e9bd90e1ebfcad7f361544884e2fe83c23b5632912ec284faf", + "0x8b3e1e81326d611567e26ed29108f33ddb838c45bbd1355b3ae7e5d463612af64b63fff9fa8e6f2c14c8806021a5a080", + "0x92f6537bca12778866335acc1eb4c3dfc2c8e7e5cf03399743dcea46aa66cac92ac2963b0892784263ad0ebe26ffdbf6", + "0xb5cc0061f7a3e41513199c7dd91ac60d727366482a4c7328527f7bd4fc3509412f711bb722b4413b3736a219b843d15d", + "0xb3e9711d68d2c6f6e2cc27e385d5f603d9a1c9a96edeefa1ffdf390439954d19504d6aadc566b47e229ad4940ef020d2", + "0xa09d0d3f0e5dc73a4a0827b72710b514bbfce4a7fcd5141d498a5aad6c38071077f50d3f91af897d9ab677b7041dedda", + "0xb177fe260f3b86e9ac21f1bfbe2682ae5dd8c9aecebb84f37054bdab6e39094e611ce582210ceeddde66adf759dadb6d", + "0xb0ac6595eba9f5dc4b2fd21856267cfbcfb5b12aa34ec69ca32b80071c5b652e85c25a224d80443d503bf25fbbfe07e9", + "0x81f3c0e11b196bd4a2e8f07f8c037002566dc9037da81f3988add458a520c24dd1be3d43d851e28c0c6a85de4b57a542", + "0xa44308c95615f7fedb2d2127012924468c015df9f48359cc2e36ab4223870b0bfc1e9040baabefdf5266f93afaad896b", + "0x8493ec4c32d5a13b81039f1b436eb83f259945dc950e3c6c2ccf5087ec56dd2f60890ed4edf01728b6a54950e19b35c6", + "0xa1a439ec2a6a95bdac9aaa925ff337ba956c0d236ab5318354270e73ed6b73b4ae2d27b4c1686cf97b6526d04e65be81", + "0xb4659b7b53c55a4b2bbe210b53520b392f893500e18990d843b72d7379d45fb44dd1dd2184348d6fd853d6b9ecc6b7c6", + "0xafb2c68d75d00130b0e1b4f250001920213121791698ec04262db714cf7b1408d39f6cc10421f954845aad5b8250b77e", + "0xb22b843b40a97210f94043b552f348f66743055a3f274856a738e7d90a625b80e9bbb80cbbb450e1666eb56b8bd5c60f", + "0x800895ced82fe13d5fff65a93b0051c3df698bf1221b682accfdb63e3970f669ca37025750697f4e8ff2a3322ad57be4", + "0xb21f598c50d7b9f4a584d548f85e42055ef8e24991906d973749090261584c7f4f5e984b528926f7e75375dd84d51af8", + "0x849b1c68192d18274598dd6d0bf48fb5ee3b1ba25b331cff2d06f345bef3bed49760ca5690848cf33388f6a9a32cd646", + "0xaeb6fd9478b10ef456f6bbb1e6dd19b14475e65497772d12cfc097948383d3fbd191bf95f046b8bf1989954118e483d0", + "0xb1b5e0ea2835f7fc8b66e7731e392b43d16cbce04b52906b6751ab1b91978899db5fecbdabc23a19dabb253005468136", + "0x91b6b1284770cf6f7ef35bc0b872b76c7763ffcfa68f9c8cfabcb2f264a66d47598bb9293f6a40f4c3dd33c265f45176", + "0xb9ffed029846487c2cfb8a4bb61782bd8a878f3afdb73c377a0ebe63139fa070e3fcdc583eec3a53fdc5a421ff1fa877", + "0x998007249d041b0b40ff546131cfc86d0b3598dcedf9a8778a223f7ed68ba4833b97324cbb1de91292b8ff51beab44b3", + "0x8eb77ce9e0e406bf6f002870fb2fd1447646dd240df9bd485f8e0869298a1fc799d8a41b130c04370e9a9cc5c7540ca5", + "0x853db8157462c46f2af7e8f94f2ed1c9b9a7ba2896b4973296898ff3d523d6e29e0b63a5d26cecd5e490b33c87a4cecf", + "0xb1436b6f3278768f0979ee852944258f2599977d255bea6fc912ba17c5dff5bdc850cf3e1fc52be9d6d188e868670f4f", + "0xa76acbc5832019b3b35667ab027feff49f01199a80016620f5c463dfcbfb51bf276ed17b7b683158ba450660cc7973eb", + "0x94540cdb051faf3ae8b8c52662868c2dab66bd02505c4f5f8eb4d6b2e2e5fd9a610890c5dcf8fd887eee796d2b5753a8", + "0xaa35099666bceccf4eb3b65b13bba88e30a8be93693ab6761d8e5523343e8d6dd42d977e66499352fe4e9e9784a1dd0d", + "0x894471aad17be54319083c4b5e40adcfacf7c36c4aab0b671030b7ef321c53590a25eccd836efd20f32a93185fd315bb", + "0x8f52a9f705bb0dea958fcfbd52e2b6c08ad0f89a07a6b2942c1b4c37eead0d97a38a9e9aeb08d5d59b7fa2a9347f738b", + "0x9031c16b4f936c9cab55585dc5064739f696c3347ee2c0792320c9f749e760d120e396e8485ffc79d81c9f3337ad3d1c", + "0x82090a0d0d9b05459ec1c328ecd4707c333b784e3aaa0ef0072cee1eac83f9a653a75d83b9f63512a8c41200494826b4", + "0x92c3a9553001f9ea4d67236b8ad1a33275378202cc1babc03f313895458f4b2549bfbbbdd37bfb8fbff0decb6b9f820a", + "0x88651868f4da37338a22bc553388df5dd1dd0cb78c4d7d07c637d8f6faef4bed72476fdcd4304d5bedf3514011135f08", + "0x83fa0141bfebd88063f1d787719721b4c6b19ecf565b866de9d7d5d1a890e0e3d859b364bb65f8f8e688654456a40263", + "0x90a7fab753e5d56dfc0e53a6b4e6ab14508220f3a62b3f3f30570c4c9ad225e74122635826c92e8e3227ec45e551432a", + "0x8fa375b0345bf6e5e062d108f9feaec91029345ecac67ccf1264eac77b8654cbfdda1f10579f481889c0e210254eadde", + "0xb83f06116da9daebdb013b26724523f077debaf6bc618b48a7a68858a98d275f7899c4ec73a0a827219b9248dd81c8c9", + "0x8be1cada55e0c5ebb4fd460b2d209ae5326285a20c8bdd54ed9d1a87302f4063c8730bfda52d9d40e0d6fe43a0628465", + "0xa68ad6f813743ec13a811f2ef3982c82d9d9ac1f7733936aa1e122f8dc7f4a305cc221579ab8fc170c3f123a1576f9ab", + "0x8878f1128214fdbbb8a0edd85223741e021508ab6d36c50d38680f2951ee713ea056ed03f62b9461897963d50ceefe0b", + "0xacc0d43d1b0260528b7425b260a5dea445b232b37240759fc65fe26f7c9d8e51569c5722bc33e94de6492f4ba1783504", + "0xad80b1dd717b076910ee5ceabcb762e75e4d094dc83b93b65c16de1f75bc712cef223c05d5579c1561829406c07a97d9", + "0xa6fc9803f9c09d95fc326cc284f42ea5566255eb215dba8a9afb0be155ea11bcc55938b2d16f01cd2f2eda218c715efb", + "0x83ad733dbdfbaae8095a403dbf09130513f4ed4f08dcf8dd76ce83d1ea72999b7eea3a7b731da0d2bc80a83c6ee0e3e0", + "0x8748912fbd08cb34a85416b0937d9c4327e9eed20d6e30aeb024a7253f14f1e0d774f3326e54738d71aae080e28da0fe", + "0x8997e78d8acf23051428af67183ae9b2c4aa42b503745ffe33df35a35103c589987e1473ab14dcd28ee78ebcb10d8e95", + "0xa2f340502a7eb3c4a36412e6f028321372c4fa18a4743945607424e932af1271fa3e6598a162c872072529576eba6283", + "0x868ccf19b5044ab93b45c9ed3ae34fcb504fe1453d6c4a1d12c325032cf01eb90356de82080ed897e97dba13cae33a02", + "0xac8867005fe4354d67aa37b866a7e581d2f94f7bd0b9f4efb5c2d1370ec13147a60692051b02fd00ae60b512bce9b1ff", + "0x8fd01886b046819c83c12bb779e432b25ba13713f9227be702074ec3abb2bba6be37220a0a26a4bd4171b99b14e32bc4", + "0xa128981ed199f92b5959975c150a93a62fec50b61c80a3fa0634d90fc8058f76f5cbee77aae6889af12d296b30e613cd", + "0x81fe618552ff7a36c9235c6d4066cf2f930b5b38de4089e18166e4a06ca5723eadd1976d25e34b74b3ce942300b23e5b", + "0xab1223ea049e6e0fbf9b611de7fd7c15e5e9637cbd73aa0e36aea08a7503ba6804f2aa807186fdc9aa7f4f9195f72e24", + "0xb97285286981b2665f898abc13f3243b63005bef8db4cab3f658bf6167036b61af400f08db0fc3c640a9c623b760690d", + "0xae3ddff7c1f0fbb6a13dbbc667a61e863c2c7c51c2051e33cd61620142e7e30a7e0c4c1f8fbb512aa3a8640267c6ac26", + "0x99c2a89d5bef236060e51c4f952664094c20fbfca647e5d24a55c1fb8df2f3df58244fbbf3635db07b1c29ee3234fa6f", + "0xa5010764d4b9cd3b410638334d1f70c5f4843f45b4f4a9316aaea5fbb2c510a97449dd7a07b49f47334a69d37d9955d3", + "0x86706d011dcdc9e9d165d01fea1df68dd74bedaf15a39f92893c030cafe96f4498c4c1fec2d2136354341b3f440a1462", + "0x88fd57eb62bd7dc35722f3a0576c2138403a2f663a2603482e8974a895cf56ddbb02657dc6b89eb2cf5c1f9d1aff6426", + "0xb0dfd4c68e3acb6bb8a776adaa421fc5e268ed4d5964bb90a727091e5113b55b3f9c6d33cedb3ee47ff7acc5df8b1749", + "0x93b92bc942e1a636fc5c2dc1840de5faf158a113d640d5a475b48e2c56ccccaf9db0e37e90ce74c4b3f5c9ac3b2eb523", + "0xb29a16fa1ea95cbfc1873c435ad40dc8495ba6341801b72bd95d908147dcffb1b4bb426dd635f3af4c88984f56594dd8", + "0xb8f367105e1a2d554ac30200c66aeb579d3d30a8953d20fb6ebba2d876ec39c52ea5d654f1bb89b8ddf3d9d651f31cdf", + "0xb5fbc228c983d08adf8612eba5b3db3acff604439226f86aa133b02cce4ffde2f977c8dbb8b446b4375673f71634c89d", + "0xa399bea37d3056e0559f6644faa0af93063b4b545d504d7e228d3dbbc294af83d3c4cf37fe026b63899b4e7d50fd08f5", + "0x928ef411a36414b24aea26fdbed4bdb1bb6bdc2d967e2553ce54c7c4e077e76869cea590257645c9129dd55ce025295c", + "0x9684a4adeed416a9ce82ad79b55c4a3adcfbd43950bc442ed8a340381caedb70f4baaaf821e3a152f483f965d8f56162", + "0x92558a37f214d6f4cb6d72cd2f4ad24dff9d17611b9e4a41ee5c741a5d1ca9e4053b0584533ef4da206110b5dc3e2a35", + "0x973bf0724d1785cc5e85d2a8ee8c354ad4cf557217ced0b7940f6f064024c20b2bfc5b144c820b5083da4bf70690de4d", + "0xadaf1389dfa528210ca9c2657c5ff10d51f7e3b18e93a59c37211be0506c3576cb2c04ec80cd0f82605e53c5a3556620", + "0x85b58b223b09fda6f3ab674d75e780c49eb2167837243df049281e8f4fed653811138b398db9cdfe7405fdb8485602fe", + "0x849504d3db408d80745a07e850b0a804607b91a59922a5d3bc40da2748c029c029419cda38d2a4485cc0824c6b2504f0", + "0xa3f4afcb353bc2582a02be758ebf0cd18752410ca2e64231176bfa23828423e0a450a65f241a9ed8eab36cae8d9c567b", + "0xae362786cdf121206537af9590d330abbc6dc328b53cdd145dbed0e5df1364c816aae757c4c81f9d619e3698dd32bcdf", + "0x9024cfa5b0101eb02ab97866d5a3832944e5aa6888484cfba3d856576b920787b364fba5956bd7c68a305afedc958201", + "0x8a116df09fed923acefb2aecf38a4fbc4b973ee964d67f03791d70bee6356af43ffca117d4e9463ffaf0e0d5d5e5a69f", + "0x9163016175c73f1bbc912ddfe03bd4e1db19c64951c8909ee6befe71a1249d838e0db49f03670bb4c5c9b2ab0fb4fef3", + "0x8f6357318d8d16e7240a02b05ce5a4976b6079d49daa258789c6dbf4a47950ebe9de6411780fab06c7c1f35651433380", + "0x8e63cbae8be7341892dbedee3111adf0307c4ee9e375181aa53478f5ba9cdce164d6ae890e5f480119a3a51c6e989165", + "0xa9782f30674a4874d91bfba7eda63aeb5dbe66b040c768d6a925d8ee135f0655ea56276b105239cc0668fc91ddb68cd1", + "0x8d9d94b61ab84ec08665cbe0244ea41756785df019e453ef078c19380bd44c39d2958e8465c72eacf41eed5696037805", + "0xb1470e6f5d2e314474937cb5a3bc30c8bf5fc3f79014945f6ee895fe20028ffc272f9d3a7320aac93e36c96d8a5454e3", + "0xa444911bbafc71179766594f3606b6eaff041826607fd3192f62dec05cd0f01b78598609a530f6930e8440db66f76713", + "0xa9823d44e2638fca7bcc8796cc91c3eb17f46ad6db9f7f6510e093727614aa3a4f9b2c4011ef91dc1c2d224d08d8d05b", + "0xab86020972c359ab98294212558b4b14862040139876c67fc494184b5c9bcea1dbe32fe0c8dd9e60be9daa304acd599a", + "0xb7e5cb685bbdcfdb1e48259a5d68d047846c8a35c5b3f90172fb183d1df40d22eaf0edaca2761a07c29c577000ccfed0", + "0x8c88319dae4b28989817e79e6667fd891181e8d2ed91b9c6b614985bca14b12982462ec58b17be0463c24bbb79dd62a1", + "0x8c1c6867e7107fb2178157c991b9c8b0f90c8d57a51220bf3650438ccabccf62da4db8a9916491e730ff3d0c106496e3", + "0xa00a79bd58da6528b9af033087260f9f3d00519eafb4746b355204ee994e89481591b508eaa5402821083e250d38467b", + "0x8785abd7c37690f6aa870ee5c799eef72e398a7898b6767f698515be277b9c2fc1af12ea89b0620a848221343a3b5ec3", + "0x8aadae68543db65cef71d0e230a09508d72061398ef2fabec0f856aacff2125b79c70e620744aaf331faf3dfc8afb9bc", + "0x8ff0cd437fcad9630b8a2333176a55e178db4142ec841581590594d74d5b53baeac5fb903fdf7bcf83e245b95b58285e", + "0xaf274e8fad6b190be4e5dc92d2705ba6ac0d7e1ea29e958a5cdd4cb764de46a56d9eef62c999a16e7c50a50b2d9fe3a8", + "0x865e6ec7d1aa848786d6a7a4e87a24d442311f0810b01ef5a74928ab59fdfd651e48880b49680047e5b0df6b3c7c2ecc", + "0x800706baaeb35bf3bc33bdea9a8b5cb00d82df407b3b7e1b781a9359cf44fb410ed311591080181b768aae223d9246aa", + "0xa9496389d0780b309c6998374ae159f58a8d0fe9a1c24c36cebcb45b27d818e653b51a8ee1f01e30a9b2c46a548126ef", + "0xb5fccf4fc3186661939fbee2e89c2aa0e3a6ad4907bcc98c7750520540c4c183b1bbfcdf47f2f1c5e75c3a30cdf30c75", + "0xa90028e39081b736e628c2230cc1338f9210ed01309a40fdf08d39c10cced2cdf71271013bea6dba3a0444fe47963106", + "0xa0815cbb325a8fecf2e1bcc5046644be32d43a8001bd5d8cf0022e4572cd0d481b3e717002f7ab21e16da5f5d16886d6", + "0xb2024787fcda52abc4138150f15e81f4a5be442929b1651ddccbfd558029912be4d61c3c9b467605fff640edf7392494", + "0xab5aa60032304a584cc9245a33f528eae7157808dedd1ad83ebae00aadc25dbe1cd5917eb8b6b2c800df15e67bdd4c4d", + "0x866643847ef512c5119f2f6e4e3b8d3f4abb885f530bb16fcef0edb698a5b0768905e51536283925b6795a5e68b60ddc", + "0x806aa99c9a46ee11cc3ebf0db2344b7515db8c45b09a46a85f8b2082940a6f7263f3c9b12214116c88310e706f8e973a", + "0xa6eada8b9ff3cd010f3174f3d894eb8bb19efdbff4c6d88976514a5b9968b0f1827d8ac4fe510fb0ba92b64583734a1e", + "0x98480db817c3abbc8b7baedf9bf5674ec4afcfd0cd0fd670363510a426dad1bcf1b1cb3bf0f1860e54530deb99460291", + "0x81ab480187af4a3dfbc87be29eca39b342a7e8e1d1df3fc61985e0e43d8d116b8eac2f1021bde4ae4e5e3606c1b67a21", + "0x8a37df12dc997bf9b800f8fd581a614a1d5e32b843f067d63d1ca7fde2e229d24413d3a8308ec1e8389bf88154adb517", + "0xb045a55ca0bb505bd5e8fcc4cfdd5e9af1a7d5fe7a797c7ede3f0b09712b37f493d3fcf6ef0e759d7e0157db1f583c95", + "0xad502e53a50691238323642e1d8b519b3c2c2f0fd6a0dd29de231f453be730cf1adc672887d97df42af0a300f7631087", + "0x80597648f10c6d8fcd7421caf4e7f126179633078a1724817d2adc41b783723f302eabc947a7ba7767166dacf4ce8fa1", + "0xaefb56427966c81081999dffbe89f8a0c402041929cd4e83d6612866cfbb97744f4ab802578349fbecc641fa9955e81b", + "0xa340e493fb3fb604eab864d4b18a6e40ba657003f1f88787e88e48b995da3d0ab4926ce438bdc8d100a41912a47dace0", + "0xa6d777bfc0895eac541a092e14499ff8bf7156689d916a678b50a1460583b38e68158984bea113a0a8e970d8a6799a85", + "0x90ce469410f0e8cfff40472817eb445770833cdcf2895a69bc32bcf959854d41712599ceb2b0422008d7300b05e62e02", + "0x815c51be91d8516d5adc2fd61b6600957ed07cf5fdc809aa652b059bea8ed179638a19077a3f040334032f0e7900ac8b", + "0xb3ec6c0c3c007c49c6b7f7fc2ffd3d3a41cdff5ad3ac40831f53bfc0c799ffeed5f440a27acc5f64432e847cc17dd82e", + "0x823637abeab5fb19e4810b045254558d98828126e9a2d5895a34b9e4b4f49ab0a5b3ee2422f1f378995ea05df5516057", + "0xac05412bcf46c254f6548d8107a63928bba19ab6889de5d331eb68cf4d8ce206055b83af4cb7c6c23b50188391e93f84", + "0x88514163c587068178302bc56e9a8b3ad2fa62afd405db92f2478bb730101358c99c0fe40020eeed818c4e251007de9c", + "0xb1e657d0f7772795b3f5a84317b889e8ded7a08ea5beb2ab437bebf56bcb508ae7215742819ed1e4ae3969995fe3b35d", + "0xa727d4f03027fe858656ca5c51240a65924915bd8bd7ffa3cfc8314a03594738234df717e78bb55a7add61a0a4501836", + "0xb601682830fc4d48ece2bdc9f1a1d5b9a2879c40c46135f00c2c3ae1187c821412f0f0cfbc83d4e144ddd7b702ca8e78", + "0xb5cfea436aa1f29c4446979272a8637cb277f282825674ddb3acac2c280662fb119e6b2bdd52c4b8dbf2c39b1d2070d6", + "0x85c211645ff746669f60aa314093703b9045966604c6aa75aae28422621b256c0c2be835b87e87a00d3f144e8ab7b5f0", + "0x867628d25bab4cb85d448fd50fdd117be1decdd57292e194a8baa0655978fae551912851660a1d5b9de7a2afbb88ef5c", + "0xa4e79c55d1b13c959ff93ddcf1747722c6312a7941a3b49f79006b3165334bab369e5469f1bddebadb12bfaff53806d5", + "0xac61f0973e84546487c5da7991209526c380e3731925b93228d93a93bce1283a3e0807152354f5fe7f3ea44fc447f8fe", + "0xa1aa676735a73a671a4e10de2078fd2725660052aa344ca2eb4d56ee0fd04552fe9873ee14a85b09c55708443182183a", + "0x8e2f13269f0a264ef2b772d24425bef5b9aa7ea5bbfbefbcc5fd2a5efd4927641c3d2374d0548439a9f6302d7e4ba149", + "0xb0aacdaf27548d4f9de6e1ec3ad80e196761e3fb07c440909524a83880d78c93465aea13040e99de0e60340e5a5503cd", + "0xa41b25ae64f66de4726013538411d0ac10fdb974420352f2adb6ce2dcad7b762fd7982c8062a9bac85cdfcc4b577fd18", + "0xb32d87d5d551f93a16ec983fd4ef9c0efcdae4f5e242ce558e77bcde8e472a0df666875af0aeec1a7c10daebebab76ea", + "0xb8515795775856e25899e487bf4e5c2b49e04b7fbe40cb3b5c25378bcccde11971da280e8b7ba44d72b8436e2066e20f", + "0x91769a608c9a32f39ca9d14d5451e10071de2fd6b0baec9a541c8fad22da75ed4946e7f8b081f79cc2a67bd2452066a9", + "0x87b1e6dbca2b9dbc8ce67fd2f54ffe96dfcce9609210a674a4cb47dd71a8d95a5a24191d87ba4effa4a84d7db51f9ba0", + "0xa95accf3dbcbf3798bab280cabe46e3e3688c5db29944dbe8f9bd8559d70352b0cfac023852adc67c73ce203cbb00a81", + "0xa835f8ce7a8aa772c3d7cfe35971c33fc36aa3333b8fae5225787533a1e4839a36c84c0949410bb6aace6d4085588b1e", + "0x8ef7faa2cf93889e7a291713ab39b3a20875576a34a8072a133fed01046f8093ace6b858463e1e8a7f923d57e4e1bc38", + "0x969ecd85643a16d937f148e15fb56c9550aefd68a638425de5058333e8c0f94b1df338eaab1bd683190bfde68460622b", + "0x8982f4c76b782b9b47a9c5aeb135278e5c991b1558e47b79328c4fae4b30b2b20c01204ff1afb62b7797879d9dee48e2", + "0xb5098b7ba813178ced68f873c8c223e23a3283d9f1a061c95b68f37310bca4b2934a3a725fff1de1341c79bb3ba6007e", + "0x97b160787009f7b9649ed63db9387d48a669e17b2aba8656792eb4f5685bb8e6386f275476b4dfbb1b4cb0c2a69bc752", + "0x88b69369c71daad6b84fa51a0f64a6962d8c77e555b13c035ad6fa1038e7190af455b1bd61ae328b65d6a14cf3d5f0d5", + "0xaf88b87801361f0de26bd2533554ee6f4d8067e3122b54161c313c52cc9eafea00661c5c43e2d533485d1f26da4e5510", + "0x98ab18e3bbcb23ac1e34439849e56009bb765ab2f2558ebfd0a57cbe742169f114bceb930533fb911b22cb5a8fe172bc", + "0x9027507f1725d81e5ac0f0854c89ab627df3020fe928cb8745f887bf3310086c58fca1119fd5cd18a7d3561c042d58de", + "0xa676583f8a26e6f8991a0791916ce785b596ce372812f5eb7b4243ba9367ea95c797170fdac5b0c5e6b7f6519cc2b026", + "0xb91b0ab32638aef3365035a41c6068e36d2303bfee8640565e16c9a56c21703270fd45946ce663238a72c053eb3f2230", + "0xaaf4cd1ac0a30906dcd2b66b37848c6cc443da511e0b0367fd792887fdaf1500551590440e61d837dbee9d24c9801108", + "0xa06f20a02d3cd76029baad5a12592f181738378a83a95e90470fa7cc82a5ae9d2ed824a20eeb1e96e6edc0619f298688", + "0xa465d379c3481b294efc3f2f940b651c45579607cf72d143b99705eae42103a0279eb3595966453130e18935265e35d6", + "0x892a8af7816a806295278027a956663ea1297118ede0f2a7e670483b81fb14dccacc7a652e12f160e531d806ca5f2861", + "0xb480917c0e8b6e00de11b4416a20af6c48a343450a32ee43224559d30e1fecdece52cc699493e1754c0571b84f6c02c2", + "0xb3182da84c81e5a52e22cebed985b0efc3056350ec59e8646e7fd984cdb32e6ac14e76609d0ffaca204a7a3c20e9f95d", + "0xa04ea6392f3b5a176fa797ddec3214946962b84a8f729ffbd01ca65767ff6237da8147fc9dc7dd88662ad0faefdb538c", + "0x95c0d10a9ba2b0eb1fd7aa60c743b6cf333bb7f3d7adedce055d6cd35b755d326bf9102afabb1634f209d8dacfd47f1a", + "0xa1a583d28b07601541fa666767f4f45c954431f8f3cc3f96380364c5044ff9f64114160e5002fb2bbc20812b8cbd36cb", + "0xa1a0708af5034545e8fcc771f41e14dff421eed08b4606f6d051f2d7799efd00d3a59a1b9a811fa4eddf5682e63102ea", + "0xab27c7f54096483dd85c866cfb347166abe179dc5ffaca0c29cf3bfe5166864c7fa5f954c919b3ba00bdbab38e03407d", + "0xac8c82271c8ca71125b380ed6c61b326c1cfe5664ccd7f52820e11f2bea334b6f60b1cf1d31599ed94d8218aa6fbf546", + "0xa015ea84237d6aa2adb677ce1ff8a137ef48b460afaca20ae826a53d7e731320ebdd9ee836de7d812178bec010dd6799", + "0x925418cda78a56c5b15d0f2dc66f720bda2885f15ffafb02ce9c9eed7167e68c04ad6ae5aa09c8c1c2f387aa39ad6d1b", + "0x87c00bba80a965b3742deacafb269ca94ead4eb57fdb3ed28e776b1d0989e1b1dba289019cfb1a0f849e58668a4f1552", + "0x948d492db131ca194f4e6f9ae1ea6ebc46ebbed5d11f1f305d3d90d6b4995b1218b9606d114f48282a15661a8a8051ca", + "0x8179617d64306417d6865add8b7be8452f1759721f97d737ef8a3c90da6551034049af781b6686b2ea99f87d376bce64", + "0x918e3da425b7c41e195ed7b726fa26b15a64299fe12a3c22f51a2a257e847611ac6cfcc99294317523fc491e1cbe60c4", + "0xa339682a37844d15ca37f753599d0a71eedfbbf7b241f231dd93e5d349c6f7130e0d0b97e6abd2d894f8b701da37cb11", + "0x8fc284f37bee79067f473bc8b6de4258930a21c28ac54aaf00b36f5ac28230474250f3aa6a703b6057f7fb79a203c2c1", + "0xa2c474e3a52a48cd1928e755f610fefa52d557eb67974d02287dbb935c4b9aab7227a325424fed65f8f6d556d8a46812", + "0x99b88390fa856aa1b8e615a53f19c83e083f9b50705d8a15922e7c3e8216f808a4cc80744ca12506b1661d31d8d962e4", + "0xa1cbd03e4d4f58fc4d48fa165d824b77838c224765f35d976d3107d44a6cf41e13f661f0e86f87589292721f4de703fb", + "0xb3a5dde8a40e55d8d5532beaa5f734ee8e91eafad3696df92399ae10793a8a10319b6dc53495edcc9b5cfd50a389a086", + "0x996e25e1df5c2203647b9a1744bd1b1811857f742aee0801508457a3575666fcc8fc0c047c2b4341d4b507008cd674c2", + "0x93e0a66039e74e324ee6c38809b3608507c492ef752202fff0b2c0e1261ca28f1790b3af4fdb236f0ed7e963e05c1ec0", + "0xb6084e5818d2d860ac1606d3858329fbad4708f79d51a6f072dc370a21fdb1e1b207b74bc265a8547658bfb6a9569bb3", + "0xa5336126a99c0ecfc890584b2a167922a26cae652dfc96a96ab2faf0bf9842f166b39ceaf396cd3d300d0ebb2e6e0ebf", + "0xb8b6f13ce9201decaba76d4eca9b9fa2e7445f9bc7dc9f82c262f49b15a40d45d5335819b71ff2ee40465da47d015c47", + "0xb45df257b40c68b7916b768092e91c72b37d3ed2a44b09bf23102a4f33348849026cb3f9fbb484adfea149e2d2a180ff", + "0xa50d38ee017e28021229c4bb7d83dd9cdad27ab3aa38980b2423b96aa3f7dc618e3b23895b0e1379ca20299ff1919bbf", + "0x97542cf600d34e4fdc07d074e8054e950708284ed99c96c7f15496937242365c66e323b0e09c49c9c38113096640a1b6", + "0x822d198629697dcd663be9c95ff1b39419eae2463fa7e6d996b2c009d746bedc8333be241850153d16c5276749c10b20", + "0x9217bc14974766ebdfbf6b434dd84b32b04658c8d8d3c31b5ff04199795d1cfad583782fd0c7438df865b81b2f116f9c", + "0x93477879fa28a89471a2c65ef6e253f30911da44260833dd51030b7a2130a923770ebd60b9120f551ab373f7d9ed80aa", + "0x87d89ff7373f795a3a798f03e58a0f0f0e7deab8db2802863fab84a7be64ae4dcf82ece18c4ddbefccd356262c2e8176", + "0xa3ba26bd31d3cc53ceeced422eb9a63c0383cde9476b5f1902b7fe2b19e0bbf420a2172ac5c8c24f1f5c466eecc615d4", + "0xa0fe061c76c90d84bd4353e52e1ef4b0561919769dbabe1679b08ef6c98dcfb6258f122bb440993d976c0ab38854386b", + "0xb3070aa470185cb574b3af6c94b4069068b89bb9f7ea7db0a668df0b5e6aabdfe784581f13f0cf35cd4c67726f139a8c", + "0x9365e4cdf25e116cbc4a55de89d609bba0eaf0df2a078e624765509f8f5a862e5da41b81883df086a0e5005ce1576223", + "0xa9036081945e3072fa3b5f022df698a8f78e62ab1e9559c88f9c54e00bc091a547467d5e2c7cbf6bc7396acb96dd2c46", + "0x8309890959fcc2a4b3d7232f9062ee51ece20c7e631a00ec151d6b4d5dfccf14c805ce5f9aa569d74fb13ae25f9a6bbe", + "0xb1dc43f07303634157f78e213c2fae99435661cc56a24be536ccbd345ef666798b3ac53c438209b47eb62b91d6fea90a", + "0x84eb451e0a74ef14a2c2266ff01bd33d9a91163c71f89d0a9c0b8edfcfe918fc549565509cd96eed5720a438ff55f7f2", + "0x9863b85a10db32c4317b19cc9245492b9389b318cf128d9bbc7ec80a694fcbbd3c0d3189a8cad00cc9290e67e5b361ee", + "0x8a150ee474ebe48bdfcac1b29e46ac90dcded8abbe4807a165214e66f780f424be367df5ef1e94b09acf4a00cd2e614d", + "0xa6677a373130b83e30849af12475e192f817ba4f3226529a9cca8baaefb8811db376e4a044b42bf1481268c249b1a66e", + "0xb969cbf444c1297aa50d1dfa0894de4565161cb1fc59ba03af9655c5bf94775006fe8659d3445b546538a22a43be6b93", + "0x8383167e5275e0707e391645dc9dea9e8a19640ecfa23387f7f6fcaddff5cde0b4090dfad7af3c36f8d5c7705568e8d8", + "0xa353ddbc6b6837773e49bb1e33a3e00ca2fb5f7e1dba3a004b0de75f94a4e90860d082a455968851ef050ae5904452e0", + "0xadeccf320d7d2831b495479b4db4aa0e25c5f3574f65a978c112e9981b2663f59de4c2fa88974fdcabb2eedb7adab452", + "0xafa0eacc9fdbe27fb5e640ecad7ecc785df0daf00fc1325af716af61786719dd7f2d9e085a71d8dc059e54fd68a41f24", + "0xa5b803a5bbe0ca77c8b95e1e7bacfd22feae9f053270a191b4fd9bca850ef21a2d4bd9bcd50ecfb971bb458ff2354840", + "0xb023c9c95613d9692a301ef33176b655ba11769a364b787f02b42ceb72338642655ea7a3a55a3eec6e1e3b652c3a179e", + "0x8fa616aa7196fc2402f23a19e54620d4cf4cf48e1adfb7ea1f3711c69705481ddcc4c97236d47a92e974984d124589e5", + "0xa49e11e30cb81cb7617935e8a30110b8d241b67df2d603e5acc66af53702cf1e9c3ef4a9b777be49a9f0f576c65dcc30", + "0x8df70b0f19381752fe327c81cce15192389e695586050f26344f56e451df2be0b1cdf7ec0cba7ce5b911dcff2b9325ae", + "0x8fbbc21a59d5f5a14ff455ca78a9a393cab91deb61cf1c25117db2714d752e0054ed3e7e13dd36ad423815344140f443", + "0xa9a03285488668ab97836a713c6e608986c571d6a6c21e1adbd99ae4009b3dde43721a705d751f1bd4ebf1ea7511dfed", + "0xb2f32b8e19e296e8402251df67bae6066aeefd89047586d887ffa2eacdf38e83d4f9dc32e553799024c7a41818945755", + "0x942cf596b2278ad478be5c0ab6a2ad0ceafe110263cc93d15b9a3f420932104e462cf37586c374f10b1040cb83b862e0", + "0xaaa077a55f501c875ceae0a27ef2b180be9de660ef3d6b2132eb17256771ce609d9bc8aaf687f2b56ae46af34ad12b30", + "0x90ac74885be1448101cf3b957d4486e379673328a006ea42715c39916e9334ea77117ff4a60d858e2ccce9694547a14f", + "0x9256cdfc2339e89db56fd04bd9b0611be0eefc5ee30711bcece4aadf2efcc5a6dcc0cfd5f733e0e307e3a58055dff612", + "0xa4c7384e208a0863f4c056248f595473dcde70f019ddaede45b8caf0752575c241bac6e436439f380ac88eee23a858e9", + "0xa3aa67391781e0736dddc389f86b430b2fc293b7bd56bfd5a8ec01d1dd52ed940593c3ad4ce25905061936da062b0af6", + "0x80299275ec322fbb66cc7dce4482ddd846534e92121186b6906c9a5d5834346b7de75909b22b98d73120caec964e7012", + "0xaa3a6cd88e5f98a12738b6688f54478815e26778357bcc2bc9f2648db408d6076ef73cced92a0a6b8b486453c9379f18", + "0xb07c444681dc87b08a7d7c86708b82e82f8f2dbd4001986027b82cfbed17b9043e1104ade612e8e7993a00a4f8128c93", + "0xaf40e01b68d908ac2a55dca9b07bb46378c969839c6c822d298a01bc91540ea7a0c07720a098be9a3cfe9c27918e80e8", + "0xabd8947c3bbc3883c80d8c873f8e2dc9b878cbbb4fc4a753a68f5027de6d8c26aa8fbbafeb85519ac94e2db660f31f26", + "0xa234f9d1a8f0cb5d017ccca30b591c95ec416c1cb906bd3e71b13627f27960f61f41ed603ffbcf043fd79974ec3169a8", + "0x835aaf52a6af2bc7da4cf1586c1a27c72ad9de03c88922ad172dce7550d70f6f3efcc3820d38cd56ae3f7fc2f901f7a0", + "0xae75db982a45ad01f4aa7bc50d642ff188219652bb8d521d13a9877049425d57852f3c9e4d340ffec12a4d0c639e7062", + "0xb88884aa9187c33dc784a96832c86a44d24e9ffe6315544d47fc25428f11337b9ffd56eb0a03ad709d1bf86175059096", + "0x8492ca5afcc6c0187b06453f01ed45fd57eb56facbeea30c93686b9e1dab8eaabd89e0ccb24b5f35d3d19cd7a58b5338", + "0x9350623b6e1592b7ea31b1349724114512c3cce1e5459cd5bddd3d0a9b2accc64ab2bf67a71382d81190c3ab7466ba08", + "0x98e8bf9bed6ae33b7c7e0e49fc43de135bffdba12b5dcb9ff38cb2d2a5368bb570fe7ee8e7fbe68220084d1d3505d5be", + "0xab56144393f55f4c6f80c67e0ab68f445568d68b5aa0118c0c666664a43ba6307ee6508ba0bb5eb17664817bc9749af0", + "0x827d5717a41b8592cfd1b796a30d6b2c3ca2cdc92455f9f4294b051c4c97b7ad6373f692ddafda67884102e6c2a16113", + "0x8445ce2bb81598067edaa2a9e356eda42fb6dc5dd936ccf3d1ff847139e6020310d43d0fec1fe70296e8f9e41a40eb20", + "0x9405178d965ee51e8d76d29101933837a85710961bb61f743d563ef17263f3c2e161d57e133afac209cdb5c46b105e31", + "0xb209f9ed324c0daa68f79800c0a1338bbaf6d37b539871cb7570f2c235caca238a2c4407961fcb7471a103545495ef2c", + "0x92ae6437af6bbd97e729b82f5b0d8fb081ca822f340e20fae1875bdc65694cd9b8c037a5a1d49aa9cae3d33f5bad414e", + "0x9445bdb666eae03449a38e00851629e29a7415c8274e93343dc0020f439a5df0009cd3c4f5b9ce5c0f79aefa53ceac99", + "0x93fdab5f9f792eada28f75e9ac6042a2c7f3142ba416bfdb1f90aa8461dbe4af524eee6db4f421cb70c7bc204684d043", + "0xa7f4dc949af4c3163953320898104a2b17161f7be5a5615da684f881633174fb0b712d0b7584b76302e811f3fac3c12f", + "0xa8ac84da817b3066ba9789bf2a566ccf84ab0a374210b8a215a9dcf493656a3fa0ecf07c4178920245fee0e46de7c3ec", + "0x8e6a0ae1273acda3aa50d07d293d580414110a63bc3fb6330bb2ee6f824aff0d8f42b7375a1a5ba85c05bfbe9da88cb5", + "0xa5dea98852bd6f51a84fa06e331ea73a08d9d220cda437f694ad9ad02cf10657882242e20bdf21acbbaa545047da4ce5", + "0xb13f410bf4cfce0827a5dfd1d6b5d8eabc60203b26f4c88238b8000f5b3aaf03242cdeadc2973b33109751da367069e1", + "0xa334315a9d61b692ad919b616df0aa75a9f73e4ea6fc27d216f48964e7daebd84b796418580cf97d4f08d4a4b51037cd", + "0x8901ba9e963fcd2f7e08179b6d19c7a3b8193b78ca0e5cf0175916de873ca0d000cd7ac678c0473be371e0ac132f35a2", + "0xb11a445433745f6cb14c9a65314bbf78b852f7b00786501b05d66092b871111cd7bee25f702d9e550d7dd91601620abb", + "0x8c2f7b8e7b906c71f2f154cc9f053e8394509c37c07b9d4f21b4495e80484fc5fc8ab4bdc525bd6cfa9518680ba0d1a2", + "0xb9733cebe92b43b899d3d1bfbf4b71d12f40d1853b2c98e36e635fdd8a0603ab03119890a67127e6bc79afae35b0bef2", + "0xa560f6692e88510d9ba940371e1ada344caf0c36440f492a3067ba38e9b7011caac37ba096a8a4accb1c8656d3c019b3", + "0xac18624339c1487b2626eef00d66b302bdb1526b6340d6847befe2fdfb2b410be5555f82939f8707f756db0e021ed398", + "0xafd9a3b8866a7fe4f7bc13470c0169b9705fcd3073685f5a6dcff3bdbbc2be50ac6d9908f9a10c5104b0bffc2bc14dad", + "0x97f15c92fe1f10949ed9def5dd238bc1429706e5037a0e0afb71c2d0e5845e2fed95a171c393e372077a7c7059f8c0e0", + "0x9453a1d4d09c309b70968ea527007d34df9c4cfd3048e5391aac5f9b64ca0c05dde5b8c949c481cfc83ef2e57b687595", + "0xb80e4b7c379ad435c91b20b3706253b763cbc980db78f782f955d2516af44c07bbfa5888cbf3a8439dc3907320feb25a", + "0x8939f458d28fefe45320b95d75b006e98330254056d063e4a2f20f04bcb25936024efe8d436d491ed34b482f9b9ae49c", + "0xa9ead2e833f71f7e574c766440c4b3c9c3363698c7ade14499a56003a272832ee6d99440887fa43ccdf80265b9d56b97", + "0xb6547a36934f05ce7b779e68049d61351cf229ae72dc211cc96a2a471b2724782f9355fdb415ea6f0ea1eb84fe00e785", + "0x828bfb3099b7b650b29b0f21279f829391f64520a6ab916d1056f647088f1e50fac9253ef7464eceab5380035c5a59c4", + "0x8d714b9ea650be4342ff06c0256189e85c5c125adf6c7aeca3dba9b21d5e01a28b688fc2116ce285a0714a8f1425c0b8", + "0x8a82eda041b2e72a3d73d70d85a568e035fbd6dc32559b6c6cfdf6f4edcb59a6ba85b6294a721aa0a71b07714e0b99ae", + "0xaf5665ebc83d027173b14ffb0e05af0a192b719177889fadc9ac8c082fda721e9a75d9ce3f5602dbfd516600ee3b6405", + "0xa68fdddf03d77bebdb676e40d93e59bd854408793df2935d0a5600601f7691b879981a398d02658c2da39dbbf61ef96c", + "0x8c001ebc84fcf0470b837a08a7b6125126b73a2762db47bbdc38c0e7992b1c66bac7a64faa1bf1020d1c63b40adc3082", + "0x8553889b49f9491109792db0a69347880a9cf2911b4f16f59f7f424e5e6b553687d51282e8f95be6a543635247e2e2c2", + "0xa2c269d6370b541daf1f23cc6b5d2b03a5fa0c7538d53ae500ef875952fe215e74a5010329ff41461f4c58b32ad97b3d", + "0xa5dae097285392b4eba83a9fd24baa03d42d0a157a37fae4b6efc3f45be86024b1182e4a6b6eadcf5efe37704c0a1ae5", + "0x89871a77d2032387d19369933cd50a26bda643e40cfd0ce73febe717a51b39fae981406fd41e50f4a837c02a99524ef9", + "0x8a76d495e90093ec2ac22f53759dc1cf36fbb8370fb586acbd3895c56a90bbf3796bcc4fc422ca4058adf337ead1402e", + "0xad4eb7576c4954d20623c1336c63662c2a6fb46ec6ef99b7f8e946aa47488dcb136eab60b35600f98c78c16c10c99013", + "0x894c2b120cec539feb1d281baaadde1e44beafedeeec29b804473fe024e25c1db652f151c956e88d9081fb39d27e0b19", + "0x9196bd5c100878792444c573d02b380a69e1b4b30cb59a48114852085058a5fd952df4afee3ecceb5c4ede21e1ed4a1a", + "0xa996fffc910764ea87a1eedc3a3d600e6e0ff70e6a999cb435c9b713a89600fc130d1850174efe9fc18244bb7c6c5936", + "0x8591bb8826befa8bee9663230d9a864a5068589f059e37b450e8c85e15ce9a1992f0ce1ead1d9829b452997727edcf9d", + "0x9465e20bb22c41bf1fa728be8e069e25cda3f7c243381ca9973cbedad0c7b07d3dd3e85719d77cf80b1058ce60e16d68", + "0x926b5ce39b6e60b94878ffeae9ff20178656c375fb9cfe160b82318ca500eb3e2e3144608b6c3f8d6c856b8fe1e2fbcf", + "0xa1ef29cbc83c45eb28ad468d0ce5d0fdd6b9d8191ba5ffa1a781c2b232ed23db6b7b04de06ef31763a6bfe377fa2f408", + "0x9328e63a3c8acf457c9f1f28b32d90d0eeadb0f650b5d43486a61d7374757a7ada5fc1def2a1e600fa255d8b3f48036f", + "0xa9c64880fcb7654f4dd08f4c90baac95712dd6dd407e17ea60606e9a97dc8e54dd25cb72a9bf3fc61f8d0ad569fe369d", + "0xa908eb7b940c1963f73046d6b35d40e09013bfbfbeb2ccd64df441867e202b0f3b625fa32dd04987c3d7851360abdffc", + "0xb3947b5ed6d59e59e4472cdb1c3261de1b5278fb7cb9b5fca553f328b3b3e094596861ea526eca02395f7b7358155b7b", + "0x99da7f190d37bc58945f981cf484d40fcf0855cf8178e2ce8d057c7f0a9d9f77425fdbce9ef8366f44f671b20fd27d0b", + "0x913976d77d80e3657977df39571577fdf0be68ba846883705b454f8493578baa741cfaede53783e2c97cc08964395d83", + "0x8d754a61e5164a80b5090c13f3e936056812d4ae8dc5cc649e6c7f37464777249bc4ae760a9806939131f39d92cca5bf", + "0x82ffd098480828a90cb221a8c28584e15904bad477c13b2e2d6ef0b96a861ce4a309a328fe44342365349456ad7c654f", + "0x89ae3ce4b0357044579ca17be85d8361bb1ce3941f87e82077dd67e43ec0f95edd4bd3426225c90994a81a99e79490b7", + "0xa170892074016d57c9d8e5a529379d7e08d2c1158b9ac4487ac9b95266c4fd51cb18ae768a2f74840137eec05000dd5a", + "0xaafd8acd1071103c7af8828a7a08076324d41ea530df90f7d98fafb19735fc27ead91b50c2ca45851545b41d589d0f77", + "0x8623c849e61d8f1696dc9752116a26c8503fd36e2cbbc9650feffdd3a083d8cdbb3b2a4e9743a84b9b2ad91ac33083f2", + "0xac7166ddd253bb22cdbd8f15b0933c001d1e8bc295e7c38dc1d2be30220e88e2155ecd2274e79848087c05e137e64d01", + "0xa5276b216d3df3273bbfa46210b63b84cfe1e599e9e5d87c4e2e9d58666ecf1af66cb7ae65caebbe74b6806677215bd0", + "0x88792f4aa3597bb0aebadb70f52ee8e9db0f7a9d74f398908024ddda4431221a7783e060e0a93bf1f6338af3d9b18f68", + "0x8f5fafff3ecb3aad94787d1b358ab7d232ded49b15b3636b585aa54212f97dc1d6d567c180682cca895d9876cacb7833", + "0xab7cb1337290842b33e936162c781aa1093565e1a5b618d1c4d87dd866daea5cebbcc486aaa93d8b8542a27d2f8694c7", + "0x88480a6827699da98642152ebc89941d54b4791fbc66110b7632fb57a5b7d7e79943c19a4b579177c6cf901769563f2f", + "0xa725ee6d201b3a610ede3459660658ee391803f770acc639cfc402d1667721089fb24e7598f00e49e81e50d9fd8c2423", + "0x98924372da8aca0f67c8c5cad30fa5324519b014fae7849001dcd51b6286118f12b6c49061219c37714e11142b4d46de", + "0xa62c27360221b1a7c99697010dfe1fb31ceb17d3291cf2172624ebeff090cbaa3c3b01ec89fe106dace61d934711d42d", + "0x825173c3080be62cfdc50256c3f06fe190bc5f190d0eb827d0af5b99d80936e284a4155b46c0d462ee574fe31d60983d", + "0xa28980b97023f9595fadf404ed4aa36898d404fe611c32fd66b70252f01618896f5f3fda71aea5595591176aabf0c619", + "0xa50f5f9def2114f6424ff298f3b128068438f40860c2b44e9a6666f43c438f1780be73cf3de884846f1ba67f9bef0802", + "0xb1eee2d730da715543aeb87f104aff6122cb2bf11de15d2519ff082671330a746445777924521ec98568635f26988d0c", + "0x862f6994a1ff4adfd9fb021925cccf542fca4d4b0b80fb794f97e1eb2964ef355608a98eec6e07aadd4b45ee625b2a21", + "0x8ce69a18df2f9b9f6e94a456a7d94842c61dea9b00892da7cf5c08144de9be39b8c304aeca8b2e4222f87ba367e61006", + "0xb5f325b1cecd435f5346b6bc562d92f264f1a6d91be41d612df012684fdd69e86063db077bc11ea4e22c5f2a13ae7bee", + "0x85526870a911127835446cb83db8986b12d5637d59e0f139ad6501ac949a397a6c73bd2e7fba731b1bb357efe068242c", + "0x8552247d3f7778697f77389717def5a149fc20f677914048e1ed41553b039b5427badc930491c0bae663e67668038fd1", + "0xa545640ee5e51f3fe5de7050e914cfe216202056cd9d642c90e89a166566f909ee575353cb43a331fde17f1c9021414e", + "0x8b51229b53cff887d4cab573ba32ec52668d197c084414a9ee5589b285481cea0c3604a50ec133105f661321c3ca50f5", + "0x8cdc0b960522bed284d5c88b1532142863d97bbb7dc344a846dc120397570f7bd507ceb15ed97964d6a80eccfef0f28e", + "0xa40683961b0812d9d53906e795e6470addc1f30d09affebf5d4fbbd21ddfa88ce441ca5ea99c33fd121405be3f7a3757", + "0xa527875eb2b99b4185998b5d4cf97dd0d4a937724b6ad170411fc8e2ec80f6cee2050f0dd2e6fee9a2b77252d98b9e64", + "0x84f3a75f477c4bc4574f16ebc21aaa32924c41ced435703c4bf07c9119dd2b6e066e0c276ff902069887793378f779e0", + "0xa3544bc22d1d0cab2d22d44ced8f7484bfe391b36991b87010394bfd5012f75d580596ffd4f42b00886749457bb6334b", + "0xb81f6eb26934b920285acc20ceef0220dd23081ba1b26e22b365d3165ce2fbae733bbc896bd0932f63dcc84f56428c68", + "0x95e94d40a4f41090185a77bf760915a90b6a3e3ace5e53f0cb08386d438d3aa3479f0cd81081b47a9b718698817265cd", + "0xb69bd1625b3d6c17fd1f87ac6e86efa0d0d8abb69f8355a08739109831baeec03fd3cd4c765b5ff8b1e449d33d050504", + "0x8448f4e4c043519d98552c2573b76eebf2483b82d32abb3e2bfc64a538e79e4f59c6ca92adff1e78b2f9d0a91f19e619", + "0x8f11c42d6a221d1fda50887fb68b15acdb46979ab21d909ed529bcad6ae10a66228ff521a54a42aca0dad6547a528233", + "0xa3adb18d7e4a882b13a067784cf80ea96a1d90f5edc61227d1f6e4da560c627688bdf6555d33fe54cab1bca242986871", + "0xa24d333d807a48dc851932ed21cbdd7e255bad2699909234f1706ba55dea4bb6b6f8812ffc0be206755868ba8a4af3f9", + "0xa322de66c22a606e189f7734dbb7fda5d75766d5e69ec04b4e1671d4477f5bcb9ff139ccc18879980ebc3b64ab4a2c49", + "0x88f54b6b410a1edbf125db738d46ee1a507e69bc5a8f2f443eb787b9aa7dbd6e55014ec1e946aabeb3e27a788914fb04", + "0xb32ee6da1dcd8d0a7fd7c1821bb1f1fe919c8922b4c1eeed56e5b068a5a6e68457c42b192cbaef5dc6d49b17fa45bc0f", + "0x8a44402da0b3a15c97b0f15db63e460506cb8bef56c457166aea5e8881087d8202724c539ef0feb97131919a73aefca8", + "0xb967e3fead6171fa1d19fd976535d428b501baff59e118050f9901a54b12cc8e4606348454c8f0fc25bd6644e0a5532e", + "0xb7a0c9e9371c3efbbb2c6783ce2cc5f149135175f25b6d79b09c808bce74139020e77f0c616fa6dcb3d87a378532529d", + "0xa54207782ffc909cd1bb685a3aafabbc4407cda362d7b3c1b14608b6427e1696817aeb4f3f85304ac36e86d3d8caa65b", + "0x98c1da056813a7bfebc81d8db7206e3ef9b51f147d9948c088976755826cc5123c239ca5e3fe59bed18b5d0a982f3c3f", + "0xae1c86174dfafa9c9546b17b8201719aecd359f5bbeb1900475041f2d5b8a9600d54d0000c43dd061cfda390585726ff", + "0xa8ee5a8be0bd1372a35675c87bfd64221c6696dc16e2d5e0996e481fec5cdbcb222df466c24740331d60f0521285f7d3", + "0x8ddadbe3cf13af50d556ce8fc0dd77971ac83fad9985c3d089b1b02d1e3afc330628635a31707b32595626798ea22d45", + "0xa5c80254baf8a1628dc77c2445ebe21fbda0de09dd458f603e6a9851071b2b7438fe74214df293dfa242c715d4375c95", + "0xb9d83227ed2600a55cb74a7052003a317a85ca4bea50aa3e0570f4982b6fe678e464cc5156be1bd5e7bba722f95e92c5", + "0xb56085f9f3a72bea9aa3a8dc143a96dd78513fa327b4b9ba26d475c088116cab13843c2bff80996bf3b43d3e2bddb1d6", + "0x8fa9b39558c69a9757f1e7bc3f07295e4a433da3e6dd8c0282397d26f64c1ecd8eb3ba9824a7cacfb87496ebbb45d962", + "0x879c6d0cb675812ed9dee68c3479a499f088068501e2677caeae035e6f538da91a49e245f5fcce135066169649872bee", + "0x91aa9fd3fed0c2a23d1edda8a6542188aeb8abee8772818769bdee4b512d431e4625a343af5d59767c468779222cf234", + "0xa6be0bb2348c35c4143482c7ef6da9a93a5356f8545e8e9d791d6c08ed55f14d790d21ee61d3a56a2ae7f888a8fd46ca", + "0x808ee396a94e1b8755f2b13a6ffbedef9e0369e6c2e53627c9f60130c137299d0e4924d8ef367e0a7fad7f68a8c9193c", + "0xad1086028fcdac94d5f1e7629071e7e47e30ad0190ae59aaebfb7a7ef6202ab91323a503c527e3226a23d7937af41a52", + "0x9102bdaf79b907d1b25b2ec6b497e2d301c8eac305e848c6276b392f0ad734131a39cc02ed42989a53ca8da3d6839172", + "0x8c976c48a45b6bc7cd7a7acea3c2d7c5f43042863b0661d5cd8763e8b50730552187a8eecf6b3d17be89110208808e77", + "0xa2624c7e917e8297faa3af89b701953006bf02b7c95dfba00c9f3de77748bc0b13d6e15bb8d01377f4d98fb189538142", + "0xa405f1e66783cdcfe20081bce34623ec3660950222d50b7255f8b3cc5d4369aeb366e265e5224c0204911539f0fa165e", + "0x8d69bdcaa5d883b5636ac8f8842026fcc58c5e2b71b7349844a3f5d6fbecf44443ef4f768eac376f57fb763606e92c9f", + "0x82fce0643017d16ec1c3543db95fb57bfa4855cc325f186d109539fcacf8ea15539be7c4855594d4f6dc628f5ad8a7b0", + "0x8860e6ff58b3e8f9ae294ff2487f0d3ffae4cf54fd3e69931662dabc8efd5b237b26b3def3bcd4042869d5087d22afcf", + "0x88c80c442251e11c558771f0484f56dc0ed1b7340757893a49acbf96006aa73dfc3668208abea6f65375611278afb02a", + "0x8be3d18c6b4aa8e56fcd74a2aacb76f80b518a360814f71edb9ccf3d144bfd247c03f77500f728a62fca7a2e45e504c5", + "0x8b8ebf0df95c3f9b1c9b80469dc0d323784fd4a53f5c5357bb3f250a135f4619498af5700fe54ad08744576588b3dfff", + "0xa8d88abdaadd9c2a66bc8db3072032f63ed8f928d64fdb5f810a65074efc7e830d56e0e738175579f6660738b92d0c65", + "0xa0a10b5d1a525eb846b36357983c6b816b8c387d3890af62efb20f50b1cb6dd69549bbef14dab939f1213118a1ae8ec2", + "0x8aadf9b895aeb8fdc9987daa937e25d6964cbd5ec5d176f5cdf2f0c73f6f145f0f9759e7560ab740bf623a3279736c37", + "0x99aeda8a495031cc5bdf9b842a4d7647c55004576a0edc0bd9b985d60182608361ed5459a9d4b21aa8e2bd353d10a086", + "0x832c8b3bfcd6e68eee4b100d58014522de9d4cefa99498bc06c6dca83741e4572e20778e0d846884b33439f160932bca", + "0x841f56ebefc0823ab484fc445d62f914e13957e47904419e42771aa605e33ab16c44f781f6f9aa42e3a1baf377f54b42", + "0xa6e40271d419e295a182725d3a9b541ffd343f23e37549c51ecaa20d13cf0c8d282d6d15b24def5702bfee8ba10b12ac", + "0x8ac00925ac6187a4c5cde48ea2a4eaf99a607e58b2c617ee6f01df30d03fafada2f0469178dd960d9d64cbd33a0087d8", + "0xb6b80916b540f8a0fe4f23b1a06e2b830008ad138271d5ba3cd16d6619e521fe2a7623c16c41cba48950793386eea942", + "0x8412c0857b96a650e73af9d93087d4109dd092ddf82188e514f18fcac644f44d4d62550bfa63947f2d574a2e9d995bbb", + "0xb871395baa28b857e992a28ac7f6d95ec461934b120a688a387e78498eb26a15913b0228488c3e2360391c6b7260b504", + "0x926e2d25c58c679be77d0e27ec3b580645956ba6f13adcbc2ea548ee1b7925c61fcf74c582337a3b999e5427b3f752f2", + "0xa165fa43fecae9b913d5dcfc232568e3e7b8b320ce96b13800035d52844c38fd5dbf7c4d564241d860c023049de4bcbc", + "0xb4976d7572fd9cc0ee3f24888634433f725230a7a2159405946a79315bc19e2fc371448c1c9d52bf91539fd1fe39574b", + "0xa6b461eb72e07a9e859b9e16dfa5907f4ac92a5a7ca4368b518e4a508dc43f9b4be59db6849739f3ef4c44967b63b103", + "0xb976606d3089345d0bc501a43525d9dca59cf0b25b50dfc8a61c5bd30fac2467331f0638fab2dc68838aa6ee8d2b6bc9", + "0xb16ea61c855da96e180abf7647fa4d9dd6fd90adebadb4c5ed4d7cd24737e500212628fca69615d89cb40e9826e5a214", + "0x95a3e3162eb5ea27a613f8c188f2e0dcc5cbd5b68c239858b989b004d87113e6aa3209fa9fad0ee6ecef42814ba9db1a", + "0xb6a026ab56d3224220e5bce8275d023c8d39d1bdf7eec3b0923429b7d5ef18cf613a3591d364be8727bb1fa0ba11eabb", + "0x949f117e2e141e25972ee9ccdd0b7a21150de7bbf92bbd89624a0c5f5a88da7b2b172ba2e9e94e1768081f260c2a2f8d", + "0xb7c5e9e6630287d2a20a2dfb783ffe6a6ff104ff627c6e4e4342acc2f3eb6e60e9c22f465f8a8dc58c42f49840eca435", + "0x872be5a75c3b85de21447bb06ac9eb610f3a80759f516a2f99304930ddf921f34cbffc7727989cdd7181d5fc62483954", + "0xa50976ea5297d797d220932856afdd214d1248230c9dcd840469ecc28ea9f305b6d7b38339fedb0c00b5251d77af8c95", + "0x80b360f8b44914ff6f0ffbd8b5360e3cabe08639f6fe06d0c1526b1fe9fe9f18c497f1752580b30e950abd3e538ad416", + "0xa2f98f9bf7fac78c9da6bb41de267742a9d31cf5a04b2fb74f551084ec329b376f651a59e1ae919b2928286fb566e495", + "0x8b9d218a8a6c150631548e7f24bbd43f132431ae275c2b72676abbea752f554789c5ff4aac5c0eeee5529af7f2b509ef", + "0xaa21a243b07e9c7b169598bf0b102c3c280861780f83121b2ef543b780d47aaa4b1850430ee7927f33ece9847c4e0e1a", + "0x8a6f90f4ce58c8aa5d3656fe4e05acccf07a6ec188a5f3cde7bf59a8ae468e66f055ac6dfc50b6e8e98f2490d8deedc5", + "0x8e39f77ca4b5149ffe9945ceac35d068760ba338d469d57c14f626dd8c96dbe993dd7011beff727c32117298c95ee854", + "0x83bd641c76504222880183edd42267e0582642c4993fe2c7a20ce7168e4c3cbf7586e1d2d4b08c84d9b0bf2f6b8800b8", + "0xa9d332993cf0c1c55130e5cf3a478eb5e0bfb49c25c07538accc692ef03d82b458750a7b991cc0b41b813d361a5d31e3", + "0xa0fc60e6a6015df9bee04cea8f20f01d02b14b6f7aa03123ab8d65da071b2d0df5012c2a69e7290baae6ed6dd29ebe07", + "0xa2949dde2e48788ceaac7ec7243f287ffe7c3e788cdba97a4ab0772202aeef2d50382bed8bf7eff5478243f7eabe0bda", + "0xa7879373ea18572dba6cf29868ca955ffa55b8af627f29862f6487ee398b81fe3771d8721ca8e06716c5d91b9ac587cb", + "0xb3c7081e2c5306303524fbe9fe5645111a57dffd4ec25b7384da12e56376a0150ab52f9d9cc6ca7bdd950695e39b766d", + "0xa634a6a19d52dcb9f823352b36c345d2de54b75197bcd90528d27830bd6606d1a9971170de0849ed5010afa9f031d5be", + "0x88f2062f405fa181cfdb8475eaf52906587382c666ca09a9522537cfebbc7de8337be12a7fd0db6d6f2f7ab5aefab892", + "0xb1f0058c1f273191247b98783b2a6f5aa716cf799a8370627fc3456683f03a624d0523b63a154fe9243c0dfd5b37c460", + "0xae39a227cc05852437d87be6a446782c3d7fbe6282e25cf57b6b6e12b189bdc0d4a6e2c3a60b3979256b6b5baf8f1c5f", + "0x802a1af228ab0c053b940e695e7ef3338f5be7acf4e5ed01ac8498e55b492d3a9f07996b1700a84e22f0b589638909cd", + "0xa36490832f20e4b2f9e79ee358b66d413f034d6a387534b264cdeac2bca96e8b5bcbdd28d1e98c44498032a8e63d94d2", + "0x8728c9a87db2d006855cb304bba54c3c704bf8f1228ae53a8da66ca93b2dac7e980a2a74f402f22b9bc40cd726e9c438", + "0xa08f08ab0c0a1340e53b3592635e256d0025c4700559939aeb9010ed63f7047c8021b4210088f3605f5c14fb51d1c613", + "0x9670fd7e2d90f241e8e05f9f0b475aa260a5fb99aa1c9e61cd023cbad8ed1270ae912f168e1170e62a0f6d319cf45f49", + "0xa35e60f2dd04f098bf274d2999c3447730fe3e54a8aff703bc5a3c274d22f97db4104d61a37417d93d52276b27ef8f31", + "0x859df7a21bc35daec5695201bd69333dc4f0f9e4328f2b75a223e6615b22b29d63b44d338413ca97eb74f15563628cb7", + "0xb2b44ad3e93bc076548acdf2477803203108b89ecc1d0a19c3fb9814d6b342afc420c20f75e9c2188ad75fdb0d34bb2d", + "0x941173ee2c87765d10758746d103b667b1227301e1bcfecef2f38f9ab612496a9abd3050cef5537bf28cfecd2aacc449", + "0x92b0bea30ebed20ac30648efb37bac2b865daaa514316e6f5470e1de6cb84651ff77c127aa7beed4521bda5e8fc81122", + "0xaf17bf813bb238cf8bb437433f816786612209180a6c0a1d5141292dc2d2c37164ef13bfc50c718bfcc6ce26369298a2", + "0x8461fd951bdfda099318e05cc6f75698784b033f15a71bce26165f0ce421fd632d50df9eeced474838c0050b596e672c", + "0x83281aa18ae4b01e8201e1f64248cc6444c92ee846ae72adb178cef356531558597d84ff93a05abf76bfe313eb7dbe86", + "0xb62b150f73999c341daa4d2f7328d2f6ca1ef3b549e01df58182e42927537fc7971c360fe8264af724f4c0247850ef12", + "0xa7022a201f79c012f982b574c714d813064838a04f56964d1186691413757befeeaada063e7884297606e0eea1b1ed43", + "0xa42ac9e8be88e143853fd8e6a9ff21a0461801f0ac76b69cca669597f9af17ecb62cccdcdcbe7f19b62ab93d7f838406", + "0x80f1ca73b6ba3a2fbae6b79b39c0be8c39df81862d46c4990c87cbf45b87996db7859d833abc20af2fcb4faf059c436a", + "0xb355943e04132d5521d7bbe49aea26f6aa1c32f5d0853e77cc2400595325e923a82e0ff7601d1aee79f45fd8a254f6ae", + "0x87142c891d93e539b31d0b5ead9ea600b9c84db9be9369ff150a8312fe3d10513f4c5b4d483a82b42bc65c45dd9dd3bd", + "0x823c3d7f6dda98a9d8c42b3fee28d3154a95451402accadb6cf75fc45d2653c46a569be75a433094fa9e09c0d5cf1c90", + "0xb3c3497fe7356525c1336435976e79ec59c5624c2fb6185ee09ca0510d58b1e392965e25df8a74d90d464c4e8bb1422b", + "0x88c48d83e8ddc0d7eea051f3d0e21bc0d3a0bb2b6a39ece76750c1c90c382a538c9a35dc9478b8ceb8157dcccbbf187a", + "0x93da81a8939f5f58b668fefdc6f5f7eca6dc1133054de4910b651f8b4a3267af1e44d5a1c9e5964dc7ab741eb146894b", + "0x8b396e64985451ac337f16be61105106e262e381ea04660add0b032409b986e1ac64da3bc2feae788e24e9cb431d8668", + "0x9472068b6e331ea67e9b5fbf8057672da93c209d7ded51e2914dbb98dccd8c72b7079b51fd97a7190f8fc8712c431538", + "0xac47e1446cb92b0a7406f45c708567f520900dfa0070d5e91783139d1bfc946d6e242e2c7b3bf4020500b9f867139709", + "0x896053706869fb26bb6f7933b3d9c7dd6db5c6bd1269c7a0e222b73039e2327d44bda7d7ae82bf5988808b9831d78bcd", + "0xa55e397fa7a02321a9fe686654c86083ecedb5757586d7c0250ec813ca6d37151a12061d5feca4691a0fd59d2f0fdd81", + "0xae23f08ac2b370d845036518f1bddb7fea8dc59371c288a6af310486effeb61963f2eef031ca90f9bdbcf0e475b67068", + "0xb5462921597a79f66c0fec8d4c7cfd89f427692a7ce30d787e6fd6acd2377f238ec74689a0fdbe8ef3c9c9bd24b908dc", + "0xae67e8ea7c46e29e6aae6005131c29472768326819aa294aaf5a280d877de377b44959adb1348fa3e929dcbc3ae1f2c0", + "0x84962b4c66500a20c4424191bdfb619a46cda35bdb34c2d61edcb0b0494f7f61dd5bf8f743302842026b7b7d49edd4b5", + "0x846f76286dc3cc59cb15e5dabb72a54a27c78190631df832d3649b2952fa0408ecde7d4dfdae7046c728efa29879fb51", + "0x8f76c854eaee8b699547e07ad286f7dadfa6974c1328d12502bd7630ae619f6129272fdd15e2137ffef0143c42730977", + "0x8007b163d4ea4ec6d79e7a2aa19d06f388da0b3a56f3ee121441584e22a246c0e792431655632bf6e5e02cb86914eebf", + "0xac4d2cecc1f33e6fb73892980b61e62095ddff5fd6167f53ca93d507328b3c05440729a277dc3649302045b734398af1", + "0x92d2a88f2e9c9875abaff0d42624ccb6d65401de7127b5d42c25e6adccd7a664504c5861618f9031ced8aeb08b779f06", + "0xa832c1821c1b220eb003fc532af02c81196e98df058cdcc9c9748832558362915ea77526937f30a2f74f25073cb89afb", + "0xb6f947ab4cc2baec100ed8ec7739a2fd2f9504c982b39ab84a4516015ca56aea8eef5545cfc057dd44c69b42125fb718", + "0xb24afacf2e90da067e5c050d2a63878ee17aaf8fd446536f2462da4f162de87b7544e92c410d35bf2172465940c19349", + "0xb7a0aa92deac71eaab07be8fa43086e071e5580f5dbf9b624427bdd7764605d27303ae86e5165bed30229c0c11958c38", + "0xb0d1d5bfa1823392c5cf6ed927c1b9e84a09a24b284c2cd8fcb5fda8e392c7c59412d8f74eb7c48c6851dff23ae66f58", + "0xa24125ef03a92d2279fb384186ca0274373509cfec90b34a575490486098438932ee1be0334262d22d5f7d3db91efe67", + "0x83e08e5fba9e8e11c164373794f4067b9b472d54f57f4dbe3c241cf7b5b7374102de9d458018a8c51ab3aed1dddf146f", + "0x9453101b77bb915ed40990e1e1d2c08ea8ec5deb5b571b0c50d45d1c55c2e2512ec0ceca616ff0376a65678a961d344d", + "0x92a0516e9eb6ad233d6b165a8d64a062ce189b25f95d1b3264d6b58da9c8d17da2cd1f534800c43efcf2be73556cd2ff", + "0x958d0b5d7d8faf25d2816aa6a2c5770592ad448db778dd9b374085baa66c755b129822632eaabcb65ee35f0bf4b73634", + "0x90a749de8728b301ad2a6b044e8c5fd646ccd8d20220e125cba97667e0bb1d0a62f6e3143b28f3d93f69cdc6aa04122a", + "0x84bd34c8d8f74dec07595812058db24d62133c11afed5eb2a8320d3bfc28e442c7f0cfd51011b7b0bb3e5409cb7b6290", + "0xaecc250b556115d97b553ad7b2153f1d69e543e087890000eaa60f4368b736921d0342ce5563124f129096f5d5e2ca9d", + "0x977f17ac82ed1fbf422f9b95feb3047a182a27b00960296d804fd74d54bb39ad2c055e665c1240d2ad2e06a3d7501b00", + "0xaf5be9846bd4879ebe0af5e7ad253a632f05aedfe306d31fe6debe701ba5aa4e33b65efc05043bc73aadb199f94baed4", + "0x9199e12ec5f2aaaeed6db5561d2dcc1a8fe9c0854f1a069cba090d2dff5e5ba52b10c841ccbd49006a91d881f206150d", + "0x8f4a96a96ed8ceaf3beba026c89848c9ca4e6452ce23b7cf34d12f9cc532984a498e051de77745bdc17c7c44c31b7c30", + "0xaf3f2a3dbe8652c4bfca0d37fb723f0e66aab4f91b91a625114af1377ad923da8d36da83f75deb7a3219cd63135a3118", + "0xa6d46963195df8962f7aa791d104c709c38caa438ddd192f7647a884282e81f748c94cdf0bb25d38a7b0dc1b1d7bbcf7", + "0x86f3de4b22c42d3e4b24b16e6e8033e60120af341781ab70ae390cb7b5c5216f6e7945313c2e04261a51814a8cb5db92", + "0xb9f86792e3922896cfd847d8ff123ff8d69ecf34968fb3de3f54532f6cd1112b5d34eeabdca46ae64ad9f6e7e5b55edc", + "0x83edfbcbc4968381d1e91ab813b3c74ab940eaf6358c226f79182f8b21148ec130685fd91b0ea65916b0a50bccf524ea", + "0x93b61daca7a8880b7926398760f50016f2558b0bab74c21181280a1baf3414fc539911bb0b79c4288d29d3c4ad0f4417", + "0xad541aeb83a47526d38f2e47a5ce7e23a9adabe5efeae03541026881e6d5ef07da3ac1a6ed466ca924fa8e7a91fcff88", + "0xac4bba31723875025640ed6426003ed8529215a44c9ffd44f37e928feef9fc4dfa889088131c9be3da87e8f3fdf55975", + "0x88fa4d49096586bc9d29592909c38ea3def24629feacd378cc5335b70d13814d6dac415f8c699ee1bf4fe8b85eb89b38", + "0xb67d0b76cbd0d79b71f4673b96e77b6cda516b8faa1510cfe58ff38cc19000bb5d73ff8418b3dab8c1c7960cb9c81e36", + "0x98b4f8766810f0cfecf67bd59f8c58989eb66c07d3dfeee4f4bbce8fd1fce7cc4f69468372eaec7d690748543bd9691d", + "0x8445891af3c298b588dec443beacdf41536adb84c812c413a2b843fd398e484eb379075c64066b460839b5fe8f80177c", + "0xb603635c3ed6fdc013e2a091fc5164e09acf5f6a00347d87c6ebadb1f44e52ff1a5f0466b91f3f7ffc47d25753e44b75", + "0x87ec2fc928174599a9dafe7538fec7dcf72e6873b17d953ed50708afff0da37653758b52b7cafa0bf50dfcf1eafbb46c", + "0xb9dbd0e704d047a457d60efe6822dc679e79846e4cbcb11fa6c02079d65673ee19bbf0d14e8b7b200b9205f4738df7c7", + "0x9591ec7080f3f5ba11197a41f476f9ba17880f414d74f821a072ec5061eab040a2acba3d9856ff8555dfe5eaeb14ca19", + "0xb34c9d1805b5f1ce38a42b800dec4e7f3eb8c38e7d2b0a525378e048426fed150dbfe9cc61f5db82b406d1b9ff2d10bf", + "0xa36fdc649dc08f059dfa361e3969d96b4cc4a1ebf10b0cd01a7dd708430979e8d870961fef85878f8779b8e23caafb18", + "0x88dfc739a80c16c95d9d6f73c3357a92d82fa8c3c670c72bee0f1e4bac9ec338e1751eb786eda3e10f747dd7a686900f", + "0x84a535ad04f0961756c61c70001903a9adf13126983c11709430a18133c4b4040d17a33765b4a06968f5d536f4bfb5c5", + "0x8c86d695052a2d2571c5ace744f2239840ef21bb88e742f050c7fa737cd925418ecef0971333eb89daa6b3ddfede268c", + "0x8e9a700157069dc91e08ddcbdde3a9ad570272ad225844238f1015004239c542fceb0acce6d116c292a55f0d55b6175e", + "0x84d659e7f94e4c1d15526f47bc5877a4ef761c2a5f76ec8b09c3a9a30992d41b0e2e38ed0c0106a6b6c86d670c4235f3", + "0xa99253d45d7863db1d27c0ab561fb85da8c025ba578b4b165528d0f20c511a9ca9aff722f4ff7004843f618eb8fced95", + "0x89a3cacb15b84b20e95cd6135550146bbe6c47632cc6d6e14d825a0c79b1e02b66f05d57d1260cb947dc4ae5b0283882", + "0x8385b1555e794801226c44bd5e878cbe68aeac0a19315625a8e5ea0c3526b58cdd4f53f9a14a167a5e8a293b530d615a", + "0xb68c729e9df66c5cd22af4909fb3b0057b6a231c4a31cd6bf0fa0e53c5809419d15feb483de6e9408b052458e819b097", + "0x924f56eda269ec7ec2fc20c5731bf7f521546ddf573ccbe145592f1c9fee5134747eb648d9335119a8066ca50a1f7e50", + "0xb2100a26b9c3bec7ec5a53f0febbf56303f199be2f26b2d564cfee2adc65483b84192354f2865c2f4c035fa16252ae55", + "0x8f64dbed62e638563967ec1605a83216aed17eb99aa618c0543d74771ea8f60bbb850c88608d4f8584f922e30a8a0a72", + "0xb31b9e1ffe8d7260479c9413f8e680f3fe391ae8fcf44fcca3000d9b2473a40c1d32299f8f63865a57579a2d6c7e9f08", + "0xa5b1d136142eb23e322c6c07cb838a3f58ab6925472352ebd0bb47041a0d8729e1074ca223922f3a7a672ced7a1e562d", + "0x8d9470a5a15d833a447b5f108333d50f30aa7659e331c3f8080b1e928a99922edc650466a2f54f3d48afdb34bff42142", + "0x866368f5891564e5b2de37ad21ff0345c01129a14ea5667f9b64aad12d13ec034622872e414743af0bf20adb2041b497", + "0x88ef9c2ebf25fd0c04b7cfa35fbac2e4156d2f1043fa9f98998b2aa402c8f9a4f1039e782451a46840f3e0e4b3fa47d3", + "0x94ba04a4859273697e264a2d238dc5c9ff573ebc91e4796ea58eebe4080c1bf991255ab2ad8fb1e0301ce7b79cc6e69b", + "0x86b6bd0953309a086e526211bf1a99327269304aa74d8cdc994cee63c3a2d4b883e832b0635888dff2a13f1b02eb8df4", + "0x843ea6ea5f2c7a1fd50be56a5765dcce3ea61c99b77c1a729ee0cd8ec706385ac7062e603479d4c8d3527f030762d049", + "0x8d3675195a3b06f2d935d45becc59f9fa8fa440c8df80c029775e47fe9c90e20f7c8e4cc9a2542dd6bfe87536c428f0d", + "0x8978580b0c9b0aa3ab2d47e3cfd92fa891d3ddee57829ee4f9780e8e651900457d8e759d1a9b3e8f6ae366e4b57f2865", + "0x890112ec81d0f24b0dfbb4d228e418eff02ae63dc691caf59c1d103e1d194e6e2550e1bec41c0bfdb74fed454f621d0c", + "0x97da00bd4b19d1e88caff7f95b8b9a7d29bc0afe85d0c6a163b4b9ef336f0e90e2c49ce6777024bb08df908cc04ea1ca", + "0xb458268d275a5211106ccaa8333ce796ef2939b1c4517e502b6462e1f904b41184a89c3954e7c4f933d68b87427a7bfd", + "0xaac9c043ba8ba9283e8428044e6459f982413380ee7005a996dc3cc468f6a21001ecaa3b845ce2e73644c2e721940033", + "0x82145013c2155a1200246a1e8720adf8a1d1436b10d0854369d5b1b6208353e484dd16ce59280c6be84a223f2d45e5e2", + "0xb301bafa041f9b203a46beab5f16160d463aa92117c77a3dc6a9261a35645991b9bafcc186c8891ca95021bd35f7f971", + "0xa531b8d2ac3de09b92080a8d8857efa48fb6a048595279110e5104fee7db1dd7f3cfb8a9c45c0ed981cbad101082e335", + "0xa22ac1d627d08a32a8abd41504b5222047c87d558ffae4232cefdeb6a3dc2a8671a4d8ddfba2ff9068a9a3ffb0fe99b1", + "0xb8d9f0e383c35afb6d69be7ff04f31e25c74dd5751f0e51290c18814fbb49ee1486649e64355c80e93a3d9278bd21229", + "0x8165babccd13033a3614c878be749dfa1087ecbeee8e95abcfffe3aa06695711122cb94477a4d55cffd2febf0c1173de", + "0xa4c1bc84ecb9d995d1d21c2804adf25621676d60334bd359dac3a2ec5dc8de567aa2831c10147034025fb3e3afb33c4b", + "0xb77307cab8e7cb21e4038493058fb6db9e2ec91dda9d7f96f25acbc90309daf7b6d8a205682143ee35d675e9800c3b08", + "0xaaf7466083cd1f325ba860efe3faf4cebe6a5eecf52c3e8375d72043a5cfc8e6cb4b40f8e48f97266e84f0d488e8badf", + "0x9264a05a3abc2a5b4958f957f3a486a5eb3ddd10ff57aa6943c9430d0cfa01d63b72695b1ade50ac1b302d312175e702", + "0xb3f9e4c589ad28b1eceed99dc9980fac832524cfcbe4a486dfeedb4b97c080e24bdb3967e9ca63d2240e77f9addfaefd", + "0xb2c1e253a78e7179e5d67204422e0debfa09c231970b1bfb70f31a8d77c7f5059a095ca79d2e9830f12c4a8f88881516", + "0x81865a8a25913d1072cb5fd9505c73e0fde45e4c781ddd20fb0a7560d8b1cd5e1f63881c6efc05360e9204dfa6c3ce16", + "0xab71c2ea7fa7853469a2236dedb344a19a6130dc96d5fd6d87d42d3fffda172557d203b7688ce0f86acd913ce362e6cd", + "0x8aa2051bc3926c7bd63565f3782e6f77da824cb3b22bb056aa1c5bccfa274c0d9e49a91df62d0e88876e2bd7776e44b9", + "0xb94e7074167745323d1d353efe7cfb71f40a390e0232354d5dfd041ef523ac8f118fb6dcc42bf16c796e3f61258f36f8", + "0x8210fcf01267300cb1ccf650679cf6e1ee46df24ae4be5364c5ff715332746c113d680c9a8be3f17cacaeb3a7ba226ce", + "0x905ac223568eedc5acd8b54e892be05a21abbb4083c5dbec919129f9d9ffa2c4661d78d43bf5656d8d7aafa06f89d647", + "0xa6e93da7e0c998e6ce2592d1aa87d12bf44e71bec12b825139d56682cdce8f0ba6dbfe9441a9989e10578479351a3d9d", + "0xacde928a5e2df0d65de595288f2b81838155d5673013100a49b0cb0eb3d633237af1378148539e33ccd1b9a897f0fec3", + "0xa6e1a47e77f0114be6ae7acd2a51e6a9e38415cce7726373988153cdd5d4f86ef58f3309adc5681af4a159300ed4e5b5", + "0xad2b6a0d72f454054cb0c2ebc42cd59ff2da7990526bd4c9886003ba63b1302a8343628b8fe3295d3a15aa85150e0969", + "0xb0bc3aea89428d7918c2ee0cc57f159fba134dad224d0e72d21a359ca75b08fbb4373542f57a6408352033e1769f72c6", + "0xaad0497525163b572f135fad23fdd8763631f11deeaf61dea5c423f784fe1449c866040f303555920dc25e39cdb2e9b4", + "0x8ce5d8310d2e17342bf881d517c9afc484d12e1f4b4b08ad026b023d98cba410cd9a7cc8e2c3c63456652a19278b6960", + "0x8d9d57dbb24d68b6152337872bd5d422198da773174ade94b633f7c7f27670ff91969579583532ae7d8fe662c6d8a3b0", + "0x855a1c2d83becb3f02a8f9a83519d1cb112102b61d4cdd396844b5206e606b3fefdbcc5aa8751da2b256d987d74d9506", + "0x90eb7e6f938651f733cf81fcd2e7e8f611b627f8d94d4ac17ac00de6c2b841e4f80cada07f4063a13ae87b4a7736ca28", + "0x8161459a21d55e7f5f1cecfc1595c7f468406a82080bfa46d7fb1af4b5ec0cd2064c2c851949483db2aa376e9df418e6", + "0x8344ccd322b2072479f8db2ab3e46df89f536408cba0596f1e4ec6c1957ff0c73f3840990f9028ae0f21c1e9a729d7df", + "0x929be2190ddd54a5afe98c3b77591d1eae0ab2c9816dc6fe47508d9863d58f1ea029d503938c8d9e387c5e80047d6f1e", + "0x856e3d1f701688c650c258fecd78139ce68e19de5198cf1cd7bb11eba9d0f1c5af958884f58df10e3f9a08d8843f3406", + "0x8490ae5221e27a45a37ca97d99a19a8867bcc026a94f08bdccfbb4b6fa09b83c96b37ec7e0fd6ee05f4ae6141b6b64a8", + "0xb02dbd4d647a05ac248fda13708bba0d6a9cd00cae5634c1938b4c0abbb3a1e4f00f47aa416dcd00ffcdf166330bff9a", + "0x9076164bb99ca7b1a98d1e11cb2f965f5c22866658e8259445589b80e3cb3119c8710ede18f396ba902696785619079c", + "0xaacf016920936dae63778ad171386f996f65fe98e83cfcdd75e23774f189303e65cc8ad334a7a62f9230ed2c6b7f6fa4", + "0xa8031d46c7f2474789123469ef42e81c9c35eb245d38d8f4796bba406c02b57053f5ec554d45373ab437869a0b1af3f0", + "0xa4b76cd82dc1f305a0ee053e9a4212b67f5acc5e69962a8640d190a176b73fbc2b0644f896ff3927cd708d524668ed09", + "0xb00b029c74e6fdf7fb94df95ef1ccad025c452c19cddb5dccfb91efdcb8a9a1c17847cfa4486eae4f510e8a6c1f0791a", + "0x9455e5235f29a73e9f1a707a97ddb104c55b9d6a92cc9952600d49f0447d38ea073ee5cf0d13f7f55f12b4a5132f4b10", + "0xae118847542ed1084d269e8f3b503d0b6571a2c077def116ad685dcca2fca3dcb3f86e3f244284bdcd5ae7ac968d08a5", + "0x8dcb4965cd57e8b89cd71d6fc700d66caa805bfd29ab71357961527a7894e082d49145c2614b670dcb231ab9050d0663", + "0xadd6ed14f3183f4acc73feea19b22c9a330e431c674e5034924da31b69e8c02d79b570d12ef771a04215c4809e0f8a80", + "0x96ae7e110412ee87d0478fdbdbaab290eb0b6edd741bb864961845e87fd44bcbe630371060b8104d8bf17c41f2e3fca0", + "0xa20db17f384e9573ca0928af61affab6ff9dd244296b69b026d737f0c6cd28568846eca8dadf903ee0eecbb47368351d", + "0x937bfdf5feb0797863bc7c1be4dcc4f2423787952a3c77dfa3bfe7356f5dbcc4daebde976b84fc6bd97d5124fb8f85c9", + "0xa7050cc780445c124e46bba1acc0347ddcfa09a85b35a52cc5808bf412c859c0c680c0a82218f15a6daeefe73f0d0309", + "0xa9d9b93450e7630f1c018ea4e6a5ca4c19baa4b662eadfbe5c798fe798d8a3775ed1eb12bd96a458806b37ab82bdc10a", + "0xa52a4d5639e718380915daaefad7de60764d2d795443a3db7aeab5e16a1b8faa9441a4ccc6e809d8f78b0ac13eef3409", + "0x8e6f72b6664a8433b032849b03af68f9376b3c16c0bc86842c43fc7bf31e40bc9fc105952d5c5780c4afa19d7b802caa", + "0xa107ae72f037000c6ee14093de8e9f2c92aa5f89a0a20007f4126419e5cb982469c32187e51a820f94805c9fccd51365", + "0x9708218f9a984fe03abc4e699a4f3378a06530414a2e95e12ca657f031ef2e839c23fd83f96a4ba72f8203d54a1a1e82", + "0xb9129770f4c5fcac999e98c171d67e148abd145e0bf2a36848eb18783bb98dff2c5cef8b7407f2af188de1fae9571b1c", + "0x88cc9db8ff27eb583871eeeb517db83039b85404d735517c0c850bdfa99ae1b57fd24cf661ab60b4726878c17e047f37", + "0xa358c9aadc705a11722df49f90b17a2a6ba057b2e652246dc6131aaf23af66c1ca4ac0d5f11073a304f1a1b006bc0aa5", + "0xac79f25af6364a013ba9b82175ccee143309832df8f9c3f62c193660253679284624e38196733fb2af733488ab1a556e", + "0x82338e3ed162274d41a1783f44ae53329610134e6c62565353fbcc81131e88ce9f8a729d01e59e6d73695a378315111b", + "0xaa5ddcabf580fd43b6b0c3c8be45ffd26c9de8fa8d4546bb92d34f05469642b92a237d0806a1ad354f3046a4fcf14a92", + "0xb308d2c292052a8e17862c52710140ffafa0b3dbedd6a1b6334934b059fe03e49883529d6baf8b361c6e67b3fbf70100", + "0x96d870a15c833dddd8545b695139733d4a4c07d6206771a1524500c12607048731c49ec4ac26f5acc92dd9b974b2172c", + "0x8e99ee9ed51956d05faaf5038bffd48a2957917a76d9974a78df6c1ff3c5423c5d346778f55de07098b578ad623a390e", + "0xa19052d0b4b89b26172c292bbf6fd73e7486e7fd3a63c7a501bbd5cf7244e8e8ce3c1113624086b7cdf1a7693fdad8b5", + "0x958957caf99dc4bb6d3c0bc4821be10e3a816bd0ba18094603b56d9d2d1383ccc3ee8bc36d2d0aea90c8a119d4457eb4", + "0x8482589af6c3fc4aa0a07db201d8c0d750dd21ae5446ff7a2f44decf5bff50965fd6338745d179c67ea54095ecd3add4", + "0x8a088cc12cf618761eaa93da12c9158b050c86f10cd9f865b451c69e076c7e5b5a023e2f91c2e1eed2b40746ca06a643", + "0x85e81101590597d7671f606bd1d7d6220c80d3c62e9f20423e734482c94547714a6ac0307e86847cce91de46503c6a8a", + "0xb1bd39b481fc452d9abf0fcb73b48c501aaae1414c1c073499e079f719c4e034da1118da4ff5e0ce1c5a71d8af3f4279", + "0x942ae5f64ac7a5353e1deb2213f68aa39daa16bff63eb5c69fc8d9260e59178c0452227b982005f720a3c858542246c8", + "0x99fea18230e39df925f98e26ff03ab959cae7044d773de84647d105dfa75fd602b4f519c8e9d9f226ec0e0de0140e168", + "0x97b9841af4efd2bfd56b9e7cd2275bc1b4ff5606728f1f2b6e24630dbe44bc96f4f2132f7103bca6c37057fc792aeaab", + "0x94cdad044a6ab29e646ed30022c6f9a30d259f38043afcea0feceef0edc5f45297770a30718cbfec5ae7d6137f55fe08", + "0xa533a5efa74e67e429b736bb60f2ccab74d3919214351fe01f40a191e3ec321c61f54dd236f2d606c623ad556d9a8b63", + "0xb7bd0bb72cd537660e081f420545f50a6751bb4dd25fde25e8218cab2885dd81ffe3b888d608a396dfcb78d75ba03f3f", + "0xb1479e7aa34594ec8a45a97611d377206597149ece991a8cef1399738e99c3fa124a40396a356ab2ea135550a9f6a89f", + "0xb75570fc94b491aef11f70ef82aeb00b351c17d216770f9f3bd87f3b5ac90893d70f319b8e0d2450dc8e21b57e26df94", + "0xa5e3f3ab112530fe5c3b41167f7db5708e65479b765b941ce137d647adb4f03781f7821bb4de80c5dc282c6d2680a13d", + "0xb9b9c81b4cac7aca7e7c7baac2369d763dd9846c9821536d7467b1a7ec2e2a87b22637ab8bbeddb61879a64d111aa345", + "0xb1e3ee2c4dd03a60b2991d116c372de18f18fe279f712829b61c904103a2bd66202083925bc816d07884982e52a03212", + "0xa13f0593791dbbd360b4f34af42d5cc275816a8db4b82503fe7c2ff6acc22ae4bd9581a1c8c236f682d5c4c02cc274cc", + "0x86ba8238d3ed490abcc3f9ecc541305876315fb71bca8aaf87538012daab019992753bf1e10f8670e33bff0d36db0bf0", + "0xb65fbb89fafb0e2a66fe547a60246d00b98fe2cb65db4922d9cef6668de7b2f4bb6c25970f1e112df06b4d1d953d3f34", + "0xabb2d413e6f9e3c5f582e6020f879104473a829380b96a28123eb2bdd41a7a195f769b6ac70b35ba52a9fee9d6a289c3", + "0x88ec764573e501c9d69098a11ea1ad20cdc171362f76eb215129cfcca43460140741ea06cee65a1f21b708afb6f9d5b0", + "0xa7aaec27246a3337911b0201f4c5b746e45780598004dac15d9d15e5682b4c688158adffdef7179abb654f686e4c6adc", + "0xa1128589258f1fbfa33341604c3cb07f2a30c651086f90dce63ae48b4f01782e27c3829de5102f847cde140374567c58", + "0xaaf2b149c1ca9352c94cc201125452b1ed7ca7c361ed022d626899426cb2d4cc915d76c58fa58b3ad4a6284a9ae1bc45", + "0xaaf5c71b18b27cd8fe1a9028027f2293f0753d400481655c0d88b081f150d0292fb9bd3e6acabb343a6afb4afdb103b5", + "0x947c0257d1fb29ecc26c4dc5eab977ebb47d698b48f9357ce8ff2d2ed461c5725228cc354a285d2331a60d20de09ff67", + "0xb73e996fa30f581699052ed06054c474ebdf3ae662c4dc6f889e827b8b6263df67aeff7f2c7f2919df319a99bdfdceb1", + "0xb696355d3f742dd1bf5f6fbb8eee234e74653131278861bf5a76db85768f0988a73084e1ae03c2100644a1fa86a49688", + "0xb0abca296a8898ac5897f61c50402bd96b59a7932de61b6e3c073d880d39fc8e109998c9dba666b774415edddcff1997", + "0xb7abe07643a82a7cb409ee4177616e4f91ec1cf733699bf24dec90da0617fe3b52622edec6e12f54897c4b288278e4f3", + "0x8a3fae76993edbc81d7b47f049279f4dd5c408133436605d934dee0eadde187d03e6483409713db122a2a412cd631647", + "0x82eb8e48becfdf06b2d1b93bf072c35df210cf64ed6086267033ad219bf130c55ee60718f28a0e1cad7bc0a39d940260", + "0xa88f783e32944a82ea1ea4206e52c4bcf9962b4232e3c3b45bd72932ee1082527bf80864ce82497e5a8e40f2a60962d0", + "0x830cf6b1e99430ae93a3f26fbfb92c741c895b017924dcd9e418c3dc4a5b21105850a8dd2536fa052667e508b90738f2", + "0x990dce4c2c6f44bb6870328fba6aa2a26b0b8b2d57bfb24acf398b1edc0f3790665275f650884bd438d5403973469fa2", + "0xa2e5b6232d81c94bcb7fed782e2d00ff70fc86a3abddbe4332cb0544b4e109ae9639a180ae4c1f416752ed668d918420", + "0xb4cdf7c2b3753c8d96d92eb3d5fa984fef5d346a76dc5016552069e3f110356b82e9585b9c2f5313c76ffaecef3d6fd8", + "0x83b23b87f91d8d602bff3a4aa1ead39fcc04b26cf113a9da6d2bd08ba7ea827f10b69a699c16911605b0126a9132140f", + "0x8aae7a2d9daa8a2b14f9168fe82933b35587a3e9ebf0f9c37bf1f8aa015f18fb116b7fba85a25c0b5e9f4b91ba1d350b", + "0x80d1163675145cc1fab9203d5581e4cd2bed26ad49f077a7927dec88814e0bed7912e6bbe6507613b8e393d5ee3be9be", + "0x93ddeb77b6a4c62f69b11cf36646ed089dcaa491590450456a525faf5659d810323b3effa0b908000887c20ac6b12c80", + "0x9406360a2b105c44c45ba440055e40da5c41f64057e6b35a3786526869b853472e615e6beb957b62698a2e8a93608e13", + "0x93bfc435ab9183d11e9ad17dac977a5b7e518db720e79a99072ce7e1b8fcb13a738806f414df5a3caa3e0b8a6ce38625", + "0x8a12402c2509053500e8456d8b77470f1bbb9785dd7995ebbbe32fd7171406c7ce7bd89a96d0f41dbc6194e8f7442f42", + "0xaab901e35bf17e6422722c52a9da8b7062d065169bf446ef0cbf8d68167a8b92dab57320c1470fee1f4fc6100269c6e2", + "0x8cad277d9e2ba086378190d33f1116ba40071d2cb78d41012ec605c23f13009e187d094d785012b9c55038ec96324001", + "0x85511c72e2894e75075436a163418279f660c417e1d7792edce5f95f2a52024d1b5677e2e150bf4339ad064f70420c60", + "0x85549ca8dcbe49d16d4b3e2b8a30495f16c0de35711978ada1e2d88ad28e80872fca3fb02deb951b8bcb01b6555492e4", + "0x8d379ab35194fe5edf98045a088db240a643509ddc2794c9900aa6b50535476daa92fd2b0a3d3d638c2069e535cd783b", + "0xb45cfebe529556b110392cb64059f4eb4d88aaf10f1000fdd986f7f140fdd878ce529c3c69dfd2c9d06f7b1e426e38f3", + "0xac009efd11f0c4cdd07dd4283a8181420a2ba6a4155b32c2fed6b9f913d98e057d0f5f85e6af82efc19eb4e2a97a82df", + "0xb2c2cdffa82f614e9cb5769b7c33c7d555e264e604e9b6138e19bcfc49284721180b0781ecbf321d7e60259174da9c3c", + "0x95789960f848797abbe1c66ef05d01d920228ca1f698130c7b1e6ca73bfda82cee672d30a9787688620554e8886554ee", + "0x98444018fa01b7273d3370eeb01adc8db902d5a69b9afc0aa9eadfeb43c4356863f19078d3c0d74e80f06ecf5a5223f4", + "0x87d20b058050542f497c6645de59b8310f6eeec53acbc084e38b85414c3ea3016da3da690853498bde1c14de1db6f391", + "0xa5c12b3a40e54bee82a315c503c1ce431309a862458030dde02376745ec1d6b9c1dbeea481ae6883425e9dae608e444e", + "0xb9daa3bf33f0a2979785067dcece83250e7bf6deb75bb1dbbab4af9e95ddfb3d38c288cbef3f80519a8916a77a43b56c", + "0xb682ec3118f71bde6c08f06ea53378ea404f8a1c4c273dd08989f2df39d6634f6463be1d172ac0e06f0fa19ac4a62366", + "0xa4f94fd51ecf9d2065177593970854d3dce745eebb2a6d49c573cbf64a586ae949ddfa60466aaef0c0afb22bd92e0b57", + "0x86cd5609efd570c51adbc606c1c63759c5f4f025fcbefab6bc3045b6ad2423628c68f5931ff56fdda985168ce993cc24", + "0x981192e31e62e45572f933e86cdd5b1d28b1790b255c491c79bd9bb4964359b0e5f94f2ae0e00ef7fe7891b5c3904932", + "0x9898f52b57472ebc7053f7bf7ab6695ce8df6213fc7f2d6f6ea68b5baad86ec1371a29304cae1baadf15083296958d27", + "0xb676c4a8a791ae00a2405a0c88b9544878749a7235d3a5a9f53a3f822e0c5c1b147a7f3f0fc228049dc46e87aa6b6368", + "0x9976e10beff544e5c1645c81a807739eff90449df58ffdd8d1aa45dd50b4c62f9370538b9855a00dd596480f38ebe7a5", + "0xa0e91404894187ec23c16d39d647ada912a2c4febfd050a1ea433c4bfdc1568b4e97a78a89ba643aca3e2782033c3c58", + "0x91a6ea9a80476ed137eb81558ff1d55b8581663cccd41db4fc286876226b6515fd38661557419e1e46b6a3bc9cda3741", + "0xb9e8a1e23c60335a37a16f8085f80178a17d5e055d87ffe8cf63c532af923e5a5a2d76cf078164fb577996683796caa6", + "0xad8e151d87a37e8df438d0a6a7c02c3f511143efb93fde8aef334d218cb25932baf9e97c2f36c633620a024a5626af3d", + "0x978f942f210e8a482015e6fdc35a4c967c67b66e6e2a17a05cc7a0f2163aed227b775d4352b0c3cca6cbf4bd5bafaf75", + "0xb5e2e3d8b2e871c07f5899e108e133f87479959b80cb8a103fbecde00ccdbfbd997540eef33079c5cc14b1c00c009fd1", + "0x88a164b3fefd36857f429ab10002243b053f5d386466dbb9e5135ed3c72dd369a5a25e5e2aaa11f25488535e044e2f12", + "0xa66091c0db4e7cf05a089ec2b9ff74744354d0196968201f5e201699144b52bb13b4e68e12502727163e6db96e3565f2", + "0x8e65aff8e37240461b7374c20bfd1d58b73a525c28994a98f723daed9486130b3189f8efe5c5efcd7f5390cc366038da", + "0x8b37c21dd7304c3aa366959ba8c77ea8b22164a67e136808b6f8e48604297f7429a6c6ecf67b1d09b8b7ec083eacd7e0", + "0xb689b1277ad050f53da91a702516a06d7406ff33a4714ea859b3b2b69f8d0aa8f983c7e039b19c0759a3815d841fa409", + "0xb17f7a0a182ed4937f88489e4c4e6163dcf49fd2ea4d9efbba8126c743bea951cd769752acd02e921774dc8ebcfae33b", + "0x8b7fab4f90be825ac5d782a438e55c0a86be1c314a5dbc3cc6ed60760a8a94ef296391f1f6363652200cce4c188dae67", + "0xab8410c4eaa2bb43b0dd271aa2836061bc95cb600b0be331dada76ddb46711ff7a4ad8c466cc1078b9f9131f0dc9d879", + "0x9194bd7b3cc218624459d51c4d6dbc13da5d3de313448f8175650fa4cfab7cc4afcda5427b6676c3c13897dc638b401e", + "0x980f61a0f01349acd8fc9fdc88fc2c5813610c07eecb6ab14af0845a980792a60dadf13bb4437b0169ae3eff8f5984ce", + "0xb783bee24acea9c99d16434195c6940cf01fc2db135e21f16acae45a509eca3af6b9232a8aa3a86f9715c5f6a85cb1c3", + "0xa3079931c4b90966d1faa948db847741878b5828bc60325f5ebe554dcab4adcc19ee8bce645e48a8f4a9413bb3c6a093", + "0x801f61ac9318f6e033a99071a46ae06ed249394638c19720831fff850226363a4ae8486dd00967746298ee9f1d65462f", + "0xb34dbbed4f3bb91f28285c40f64ce60c691737cc2b2d2be5c7d0210611cd58341bb5bda51bb642d3ee2d80882e642a13", + "0x8750af19abfb915e63c81542b13d84526a0c809179bbcc1cd8a52b29f3aba3ae0f7cf6f4f01790bf64ef7db01d8ee887", + "0xa6ea10000eb2dd4efc242ac95bc3b3873cdd882fbeb7c9538c87e3143a263ca3a2e192b2159316a625cfb5fb0b6cdcb3", + "0xaa40ca54bc758a6c64cb932924917581062e088b3ad43976b28f2e11d8a7dea73f1fb50aeaa0e70182bb2dc07d805bb9", + "0xa4779dfd25b5ec9d75dfb54a4bb030364899a5e75c1492403acb19f2adc782c7ac4daeb66d2f5aeb74135afe9f318e3f", + "0xb4551e2805d63ca453f4f38b1921ac87ff687e1d70575ad38f3469d6f0608ef76b7b1b98ae1e6b1e7d928773aaab6e3b", + "0x99490ee722f96aad2743b08dd37bfeb75a8c59efaee4c9b694eaa05eb8a6bb23861a4480544c7617d04d23fd5e2543b4", + "0x8a7050d964d295fff98ae30d77ce730a055719313457e773fcce94c4d71a9b7cf63db67e54a8aab20fb1335b0130b5d5", + "0x903144e6bbee0a4fec17ff80fef0d2103981140c3d41776cfb184ced17f480a687dd093f6b538584327e6142812e3cd5", + "0xa5b30f7c6939bdc24a84ae784add927fec798b5a5ee3dd156c652df020728dd6d43898be364cf5ee181725fbcffc0964", + "0xb43d97ec2bc66af92d921a5c5c20a03ef2be2bc2c9b345f46d8287409fcbfd88ebc49d4509d64468222cd1d2021bf236", + "0x82dc23c7f5086c9ac6b4566359bfb830d203544b0d8332a210775670f899cd9ff48b94bfeba40040c25664ebdd5cfad8", + "0x9294cd017fea581dabb73dcc8c619904d7e022b664b0a8502c9d30f3807668af279948e7e41030ae296d492225297e95", + "0x8d6c9dc636c8e884f9a4299e5cff06d044ebc94ad783a4b71788347ea4a336d4d048b8a9ecabae789e8fcdc459723dfb", + "0x801a80bc49e882ec81b04e37407713f033f7bdac79252dfa3dc8c5bd0229fcbd4019890e402cf843b9378df08f72ab84", + "0xb4313ca32569d973900f6196363c0b280ddfa1b47c88d019e5f399b805b444a777950fc21ae198fc23ece52674b94abf", + "0x96f06056fd255fdabf78986e315e7c4fdf5495cf850536b7976baa97a994cc6a99c34609c33a0f2facba5e6f1026dce6", + "0x983ed80220a5545ffd70ef5e6ac10217d82ec9cd8f9a27ee77a5ff4074092308c0e6396fc4e9932a77ddd474e61f8b55", + "0x872a059aa630af73c4abbd076e8b333a973ffc5bdecf5dcc0600b00162184213cb19d4f601795030033beb808d5810ce", + "0xb040f318d9d3b8833da854014a44296dbd6762dd17cab13f91987256c54353b7f0800547cb645a7cc231997454209fdd", + "0xa8c4731a555308e8ce0b8325eb7a4cbf6113d07e9f41932df04480b72628d313b941c7055f1cc2ac45c7353b56e96ca9", + "0x8c24031440b77637e045a52e5ea3f488926ab0b426148975edf066c40a4581beecc1bfb18fc4cf5f9f96dc6681b4bd28", + "0xb39254b475abf342f301298feaa17a4b3051f30ea23a18acf59e003e2704ac96fe40691f1da387913bdf7aee6389f9a8", + "0xa1dbf938b604ccc6d60881cc71f38df568aa02752aa44d123514154017503f6c1c335ae43e359f1487bc8934073cd9c1", + "0x8d52aa1be9f429ece0580498d8fe9fef46d4a11f49436a82b8927f9503dacc41245907f126594c1cd30701286f8c092c", + "0xb826f396486942c0326d16f30a01b00a682c30a75553dc6ac34fd5b3e96b13c33b94738f522eebaffb59ff8c571c76e9", + "0xaa89f51cbf6e6c3e2aa2806187b69ab3361c84e89f393f3ed284fe84db46fc3944aa44f8928e3964f9c1a1ec27048f68", + "0xa254df0efa4203fb92b42a1cd81ca955922e14bf408262c8f7cb7dc703da0ca2c71556bd2d05b22ce9a90ad77309833d", + "0x93263c507e4d5f4e5df88e85b3d85c46ea729fb542a718b196333e2d9fb8a2e62dc1347cf146466a54ba12d200ef09d9", + "0x922e3c4a84246d89a07aa3e90f02e04b2cea9bebc0e68b742156f702aed31b28c6dfa7ac936ea2fc2e029adf68361f98", + "0x9a00628eeeda4ccbed3ef7834149aec4c77aac1a14bc2491ba5d1a4a2c5d29afb82ceaa5aac1c5ce1e42cdcaf53e30ba", + "0xab3a88df36d703920f6648a295a70ffa5316c96044f39ff132937bfda768937cb6a479e9ba4a4e66b377f3a9996a88c4", + "0x966b11526ab099d550ab33c6a9667e5cfdedf255da17a80a519d09acd78d2ea24ec18bd1ea7d8d63cf0a408f1c1fe0b3", + "0xb5c21b9817dc32f3df9d9988aa3560e1e840d586d01cd596bc0f850ab416b6013cbf7dbfd05ac981f26014c74bd2d2b2", + "0x9040abef5e2523e7f139c9f744a64b98fea3a57952059ffe4d5ed77fa87068203c090ef4e7f52c88fb82ea8a6fdca33e", + "0xa0dcdaeb7d3f5d30d49c004c5f478818c470187f4b0b4856812dcd1b3a86de58a99acb8ceb44c6b80c3060cf967c43a4", + "0xb5f4be9a69e4a6719ea91104820df8623b6d1073e8ee4168de10a7e49c8babea772bcbc6b0908185e98d607e49cd3609", + "0x8634020a5a78650015763c06121c606d2dd7b324aa17387910513dd6480fb797df541fc15b70d269b2794ad190595084", + "0x9504d1d0fb31ff1926c89040c04d51fd1f5cddf9d7ca3d036e7fd17e7a0f767ef33cee1d8bf7e17e2bc40949e7630417", + "0x812c72846ef6d692cf11d8f8c3de8fa78cc287303315114492667b19c702cd24d462020f1276895df26e937c38f361f8", + "0x8c97aa5e9ef2aa9a1435ef9ddfe62e850f0360864ed5fb82bf9fef4ef04d8fb4f827dc078bc911ee275e4501edd6617c", + "0xac5f7af5e23c8e429aaa6b6825129922b59d25b4608f07b65f21388a9ac3aa89096712f320afe6d56e44e1f0d51a4eb9", + "0xa8c84d9a8593a0cb5be1e450960f59878a4e6b70da54a7613dfc25911b7cc9e6d789d39401b0a0d6471ab9dcdc707976", + "0x8c9d5fd89611392c0f085ffa4fa642a181f0b9b23593deb5e10fdd1642722ca75ef34a037e88a8d03f2888fe7461f27c", + "0x8c74b05f91fb95c85e7bd41f6d9a1e41e667e68f3d19b325c1f25df1767019919edab89b92af237896cbc4e6d6dc1854", + "0xa3caecb91640821f0b2c4981b23f2069df8d2b98ce026c1538bc096b292f5f956a5d52c1c8d6a8165a1608083ba6494b", + "0x8ae8e0c36f8b79a69176ff29855df45d0fcd9e4d1dbaed8899f8fcdece676e418ec034a6c161e2a894f0c834aaecbfd1", + "0xb88d18c67dc3b1b6ed60ee437c441c1ed14ecddebccf43683605716f30058b1aa4ba05ff10cd8171ee97d8f58d70c094", + "0x94f43d84dcdfd9cd19115c7d8e9c1e856828eafbfdec93b876cf0007e317e30b2ad951dbabc186aa6ef90fdee4d91990", + "0xb44e4723f41fc1d5b0057f371e3381ae02566590b3f964b6eb07b2104f66ff78410c407235fa98d04f635694f3baca09", + "0xaddd8390173d29ca0811534d389253831fed75fed135398617836b6e70767269eacb1560b39a58f02042ca3b97fe59c4", + "0x80bdbdacc0c358c7ea52aeacdc5f9ceb6928bcf6e7dee7c17d8ae3bf7c2372aa7a0372363888968fc0921aaf4776d5d0", + "0xa486e2b6f04f403f9e609d69dfb3cfb992af56ecad1683271df3e3faa3b86638b81e73b39978fb829ee7133d72901f2d", + "0xa19472da57457e10c6a6307895393ddaec8f523760d66937fe26a025817319e234eaf69756ffdf1b84c81733424a96d7", + "0xad6a195397cbc2d75171f5e82090441eed60bd1ba42c39ef565b8b5a8281b04400678625b1dc46d617f694a7652a8e5d", + "0x8f98e721c06cec432e2221f2e1b06bb1469d916a8d88d6973acf68d1e003441d00390dafcead8ecdbf9eae4509baf5aa", + "0x91d62a0f9d13c59adfe1376ed6d057eae244d13c6b3d99be49a49e0075cf20f4085cf127774644ac93615be9ac9e5db6", + "0xaf45dec199245e2b326a0d79c4899ed44b1c0219db42602a4a6184ace0ff831a3276297af28f92e8b008ba412318e33e", + "0x8754bde54e8d2d169e6a7d6f0eae6097bc0461c395192bd00dd6f105677ea56ab384c02553ea5eeac0a65adcb0df77ee", + "0xb676afd2f5afc37a314c943d496e31b4885efcbcc2061036e370a74cfde5642bb035622d78d693bfc3136fc036c7edb4", + "0xaab6ffe6cc234397cf1822e02912bc282dfb314e92fb5a9e10d0c34ee9b5856d4b76e166bc2bb6fcdd66aabea35ec4ef", + "0xada6e62f90ee6b852ec4b72b22367acac2896f0df2c105beda27096583ddbedddc710d171330569f111c6e44a5b57ae7", + "0x802139dd15241a6de663d9b810121bdd9cf11f7f8c8ca6de63f4f8e731409e40d1fd3558b4f619ed42ee54929dff1c7e", + "0xad8e70531cec21b4e6f55be1751c2d025bd2d7d8158269b054cfe57fa29252d052ce4478ec7db6ec705789e2118d63b3", + "0xa8e4a4271769480e1b33a28c87a150ecc0b48bfe8a15ae04152197881de4ce4b03453aefe574842424edbbe4173e1a3a", + "0xb98c65726296610cef16c5b58da5491acd33bd5c5c5af4d934a9840649ef85730fbce8018dee09ded14e278009ed094a", + "0x8e213a7861223287b860f040e5caaa563daa0b681e4e09ec79ad00cc459238e70bbeaf7486bbe182fc12650700034ec5", + "0xa2879f9e1a556cf89b9b5b3bd8646a8cce6b60bcbc8095df44637f66a2da5858eee2dc9091475a8f64bb5aff849389cd", + "0x8a17cdb4077b9b0bcf28b93294ac5ae4c8bba8839fce0f1012b53187ac008f9858b02925fbfc421f1123afcdbd8b7753", + "0x86fd9c11528aa43946e4415ff64a3ca6409ee6f807368c68997b18605da65e415ccd85ad913820d450cb386593de666d", + "0x8ed55923b963c3d85a91aca11c40ff9c6c7f1e2b9bc199d1a270e5fb16aa62dec0136e97866145ae9d58a493e8b1cbbb", + "0xae32af5b5d418668ae123c639b149e5eed602404e8516da4a61db944b537a3620545e8e3d38cf10cdaea980ab2f80973", + "0x95cb8d9e9d6762d78dde0ad73869ffaca904a7d763a378b8cc11a7933d3e7d1c8aec4271a079b1b00f8887ee5b1ea21f", + "0xb5ea20b42a3ca247f00ab5328c05f0cf194973d5f7271c66c41c5055b1ffdca136be179709e0c1de209fbe07b9820bf3", + "0x98682f7cce471c92a8d6d15fee4ddf4d43dd97c3e3811d2913618ecacc6440b737717c07736ae4558c910e11ee98104e", + "0xa67da2c7cbba48e929ca4e4b9a6299fe01ef79eff8cc5cd3fdbdc0721a68130e4079f30ae151a573a7dcca8ecf2e684e", + "0xa9981c9f9dcbb3b0f6996f664fb2acd7573189f203be37b2b714662aa273551396abfb1f612ccde4e4c8127a050dbe4b", + "0x92d55eff8da600f886da9bf68e8eecf482faa4b268f3f286b3b3e5cc91b19604081498d4905b201bb4ec68e32b5591d9", + "0x963e3f1728de9d719c86d390f3eb9c3f99d1928347fab0abf10dbb37d76b59ddb64d4734c977863a6cd03ffece5ca895", + "0x93480e2de83c921056b6d8628ac37cd5ef7555ba43b0308fc13386cb0515d42c12ecd06057137aa71a7931beaf90b9ce", + "0x8feae57ff0e6a162cc81c99f45c6187d268fc0bee8c2bffc92142ef76c253d201f0e932943cf2fa312982b281ce1066b", + "0x8f8f4bd4200fb87afcd743274480220d77571928000d4197410dbb75439d368df6a06d941a6152206371d2ca9cac99e4", + "0x8ee7f11e79af4478e0a70eb424fe8078237ad99ba6d7e6bf1a8d5e44e40abd22d404bd39b718ad6fdf4c6601f2a47665", + "0xa98acfcec612b574943195b9ba95bebcc9c0b945c9f6b3e8760b2a4635909246a9d73b0b095c27b4ecb3339704e389b7", + "0xb520efd19f65e81dc285031ea3593f8c5dad793e4426beb9196ab46e45346f265fd71e50adb0da657977c60ed5724128", + "0xa3d9d0b7415280ce4dfa2429d47b2b8e37604a5157280a72cc81d541ffe44612dbb3ef7d03693fc42a569169d5842dc3", + "0x8c29e2d0b33801f6d9a9c065a76c5cad1fb0a001506b970307e21765ee97c732a4cbf1d7c1b72d95e0ad340b3b075224", + "0x839e21f292892a6eb596b9b1e9c4bd7c22a6fe71d3d04487c77840028d48392c5cbe73140a4e742338e0c8475cd0c1ad", + "0x8bea5c68e7743998619185bb662e958f1b4d3ca81019d84ac43c88911aab3abe4ee9bcc73cb95aa3ae87c0138801bde3", + "0xb8f262d21a94604049e008ce03dc857848168e1efca4522acb0ccc827ffb37f545e1947843a356563a76bc6489605b66", + "0xa7bd0842b0bb38d9943b82aa883f36f4eb8a6e8a7790d4f87faf306608f51d250a19b73984f1156cef5dd2581664614b", + "0xa993e649bd953627a88a2539dac3a12ec7f37a4c65b01425d9d34edf7ee10a71aa98f65c9e013107f824faf8aee041a9", + "0x8e07eced75c67cb4d2ec01857f6ac1408482e6b31cb2faa249e8cf99f180575587df530c7782a7539b5221121ef48aa0", + "0xb2f4578f26c05ecb9e2669ca744eb19d4f737321ac7d04fafd18beb7866e0fec9dd063953ae1f077b44b9c6f54db1279", + "0xb6b3788a6c7bcaf467d19daf6ab884d549aa866970c05a9181f544ff190d043192c84fe437a75a30b78b425461cca062", + "0xa270684903c61544b85a7041e81f65e787e1c1e23e57538fa8a69836bed0ca1673861dd29f743a1280f2f38eddd3aa83", + "0xa9c2397c4773dcad2821266dadfd2401d013d9f35de6744f2ec201f3507700adb1e6ec4f5a453be4764da8bf68543f26", + "0x83a3025ed6fd5df9d98be32a74e10a0d9728b560942d33ba028536fb148fc34ae87e92be2df3e420a8dfec08da495982", + "0x90dc70c183a90bab988b4a85b7b921c8070af0e5f220364fe11afa0722990b2c971e1e98eef62d3287fedfd9411f1df7", + "0x82d940937a6c636224d04f8e2536f93dcf20dc97a5f188875ad76c21b804aef9af10839419b61143c1f88a695959a6b4", + "0x8017f9473ce49d498d6f168137e77e62fe553e5a51e75b519cf2cbd1ab9afdafad80fd5e6fd0860e640b0d78ca8ed947", + "0x80573a0ec049fe1f7b3013b2839e145cd87e07c0e43826a29ef8c92516f9a30896c2ffcf3ed77ed22a6cf3101b1789d5", + "0x953349abd2559f9824db07cec857ad54f1a05018f3076425f8dbae37f8d92a46af2c04ab7c8ec0250449541187696e98", + "0xab7bd2c4f05ee9a9f252c4e16a20993a12c535c3809d124bae24642616521a9768d3f19eceaf8524583f47ae1f527684", + "0x9883b77ee834ee0112ca2f366d2a6fc213e0cf454e061438c2901a5ba35b7378f64da8adf6a476eb1562991ef5b4a5bc", + "0x89291811db308637356dbf7ed22cf07bfce33eb977734ee346e8c15a231b35d8b4443574f3fa97a40867b3e23b0bbfa4", + "0x93d753849d7d9588d39e38217500b123a6b628a873876612d9f98b5d611f52c89c573432d2176752b5d1cc2d94899b8b", + "0xa45add3c4844db3b7a237295fc85fddc788ac1ec395a0524d2fc90a539571a247146aea4aa10eec30a95e9617c85b98d", + "0x90f94578842db7a4de672da1e483858ece5e466c73c12f725a0fc71f42ff880c9447a33fa9096839bee817536f2591e2", + "0xb2c1b6fb031bb30460f157356562b44b4de096a0a112eab4fb3cc500aad38bc770da1fc2e73caf687a0da5e8537049c0", + "0xafb15e15fd930929c0e3c66482068a5afe0c7b7f82e216a76c5eb1113625bfa0b045a52259d472284cfbaf4796c71456", + "0xad222a9a3d907713418c151b8793d5e37634354322068f8206b9d0da1a3f53b0004193713d23ec35990639a1b6c2e075", + "0xb44a128dce97e8c4b178cdbca0a5c1b3f6e164490fac0fd68dbfe0aafa89920bb4ea420a8527e06c80dd19c2f135e3ef", + "0x8596e993ef18b8d94e9c42a90cb7060affc586b8e9b526820d25124285de5590134e2e86592e9dc4dd45ccf5d578fa60", + "0xb71bb0ad138141ed506b2253e84110d2db97cc2d24a3fd0d096b0022d9f38f87aa74e2f505074632d64e90bcc491aa30", + "0x84841eafd357309de47b92ca5ec163dec094a2e5271bc65898c31932e0160bee165e4decb23af339cfe09c83e1cc5441", + "0x8a2915ee39a6fd4a240b98533d7690ef1773ce578ed1fb05ed414ebe36f7ef289fa46f41768df57190438c356331e329", + "0x90bb337165386f1990cbd8ed2e8321ef21bc18125b015b4da0c37e5fcc446b26005379ee4fad8ce9348ceb4ab49e82e2", + "0xb707b50ea2ab05c6d183671587f25fe29eef23fe569d731459a1ac111a0b83a2cd65b88242876b34aeead3b05a15d745", + "0xae1f159f79b7996315c4f9acce7e21a6ed59d4ef76331196fc86911fda3035edd5c11d568b105175a36c948d0263b382", + "0x922bc525bace05e5dff6b5cabde5469ddd2c1c601f7131abc04ecefdd35095e6ac015b1aec3c3b25c5dee8d139baf60d", + "0xa7b060405b2740f82db64683187b1bb89e5f40c8438663c7cbc8ef2513929fe5f92625667a7f2f599a72a96b1fc8f08a", + "0xb9dfe94a08651db5efefbb813269bce80d814e3089b80c0654491e438d820bf521f8a4a4477909344ba88f7683eebb43", + "0x841817a9729465743576950b6e8eea32ebf39cca99ace86c4792f9f35926e2d6830c52854a3b2eaeb61694e6845008bd", + "0x934128034bde8fc7b93b952aa56e0ed28b36cfa04cfa1f0d5b38266dd40beedff5e0bab86e4717b0fb56c56be2eae26b", + "0xaee9d64caf28596308782cd8f3cf819506daf3378f86157ff775e618596411adf94efd0e9542787ca942066f02cbd332", + "0x85871184db314411a49575fee088c52ed5dba4e916ee001ec24d90898a0154d9790a06aa8a707ca7a8b986c0293b8d89", + "0x8d3d87edcc0187a099c97b581a598d357a41ac152303bb27c849eb78e72e15cb97cf9a0468fc36f245c3e152c76bb7dd", + "0x900475d165dec18b99eb7b5f9e9ad1d2d4f632e55fdcc4c5ecd7775fed462990e6aaafe9c669f40508f9b15f00bda31f", + "0xa25b5954edd57e7811a0d18532043d975c7b44b80f65cd630935d7b16ada05f30fe2b7be7ae8a2f54c25957faf3f1950", + "0xa089019afa3a7a15f7e7874e73b6773c0a824e6d3379b4c928e173321fb165ad979a6be004d394c28d19d410b2655d3e", + "0xb28f46797dee0c538bd3de815df641a0ef718ad3e52b2764aec380d6905b38b50ad6f60d0f68e096ca39960ba7734355", + "0xb0ac155d3d05851b04104e6b459f1a68e9e155437c92421a7c0e4dd511ef89cf71dfa3cc920769492ee283a65ebf029e", + "0x813c69a810745580d43d5b5480f0ba81000fbef0071e6b655c7346bef5ed774e9214a7816d40eb1774a5bd033767a046", + "0xb176345ca75c64f10ec33daa0dcf1f282b66a862fcd3d8d66c913f9a02db4c9d283dadc02eff13aaab94bc932a42234e", + "0x92560f67e5b995db4a489bb86ee78b4aee0800143b3535ad557a53e9e08716bd0202d9f5714722c2a5e8310046e3f5b3", + "0x8adb427bad9cc15fc6c457a96a6750dda8c46d859c5f69bf0e7ab8fc0964430b33967fd47cf0675b6ba1757f91255e6e", + "0xb120f723b80389a025b2daa891b140b3d7b8d520ae2a6a313f6e3d365a217af73292dcb249dca1f414ec05e865e3cdc7", + "0xa61a5d261a8dfe5996c42ea0a5ae703a2adcfda80e86837074d868eee16f87d38da19596c48b55dbd7a7cbec1a9b4996", + "0x99dc921eacc6bb867c5825ad4c83bc4af9dd78a18b3d0e1a60ad493e3805b8fb9b7922b577da1adb3d805edfc128d51d", + "0x85455fa165a07282aaab4a5bfb88027f47b9532e4af8195c048515f88b0db7e80f42e7a385fd4944faaa7f2a6544ad17", + "0x96dff2d1c8a879d443fe576d46bcceaf5f4551d2e8aad9c1a30883637c91090de99ad5eec228eb5febf93911502d3cbb", + "0xa87eb7f439377fb26c6bfe779701f4aea78dd7980b452a386afec62905e75217a1996c5234853432a62ef8bab21c31c3", + "0xb598278293823e9ccb638232a799211173b906444376337fdf044d0227d28fcc4c5867e6ecb3200e59ca0b139e71cac9", + "0xaa6fe147edc95027654d68140f428ec53cede3552c5f49c09d18bc6f6ae8c739a63042eb7291d14d717a4e1f0778abcb", + "0xae8ee18913d328b2fba71efe65526d3ee9c81beda53cf776baec4019ea30212010758cbb5dc85ed6620ce04b189f01f2", + "0xae9fb686777e88dffdd42805fe4114aa0da1b350d92a27ff3f8a817fb25af1fcfc9a06155affe0273bf13caad16a5351", + "0x95d372ba3a2ee38371538f34aae91b4844488e273f70c02f1992370f89fc2343eff95692d52ce9f21206abbee4959958", + "0xb15260376f0a34ca2827ff53acd7eaaef94c9acc2f244b36500423069cb1cdaa57ac8dd74adb5b53d0fd4265fcbb28ea", + "0xb0ffce6a8059537ef6affdbbc300547ef86e00109289239b0c6930456c562b4ed97f2e523963af17736dd71b46c44ac7", + "0xb5499a1277d34f9892f7579731ff53f423f2ffffa9ea43a6e929df8c525e301396249a2324818a6a03daa0e71fcd47b3", + "0x98dbfb8e97a377a25605a7665d4d53e66146204d8953afda661ae506858c5cd77ff7f21f5f10232e06dbc37378638948", + "0x84177e27e6da0e900c51f17077f5991e0e61bff00ca62c1623e627c5aea1b743f86eef6d55b13219a1947515150bade6", + "0xb50407bb5c61b057ab8935df94fd43ca04870015705b4f30ceac85c1035db0eb8293babc3d40e513b6fb6792ecbc27a9", + "0x988699a16917514e37f41ab5c24f4835ed8a2ca85d99972646fcc47c7e2a83c2816011144a8968a119657c4cda78d517", + "0x920c43fdcb738239ad542cb6504ab34498bce892311c781971d7db4dec70e288676de4d8697024b108cfa8757fa74035", + "0xaaa106329aac882e8d46b523f126a86d3cee2d888035ce65c0be4eaae3e92fd862f6ac2da458a835539cccafaba9e626", + "0x96e4c1562d14b7556f3d3e8a1b34ea4addc5a8170e1df541dc344728bcb74cd1630eb7ba4c70e9c68fd23c5c5d5a729b", + "0xa616ac5016d4e68e03074273cd3df9693ee0ce3458e8758b117a5c1bc6306dd2c7fad96b1bb37219c57ac62c78ad7a3e", + "0x8db7d9b20abfb1445babd484ae9e38ff9153ac8492230d7591e14e3fca7388a5ca6ef7d92ed445c8943cf5263e4a6ad7", + "0x88464134221aa7134878eb10928f31c8bd752ab68c27c9061c1de3f145c85731a4b76acdc7e939b399b6e497f9e6c136", + "0xa5f7c794f70b7c191c835dded21d442b6514bab5e4d19b56f630b6a2f1a84a1d69102d7a0dcca256aab5882d3f30f3ca", + "0xb96b6f98b6817b5fa6b1b1044e2411bdf08bf3ffaa9f38915d59e1d2b9bed8b3d645eee322ee611102ce308be19dbc15", + "0x92c26ade2e57257f498ac4ff0672d60b7ea26dad3eb39ed9a265162ccd205c36b882dba3689758c675f29e20836b62d9", + "0x8379a0299e75774930577071d258e89e471951642b98e5e664c148af584d80df4caa4bd370174dae258848c306f44be5", + "0xa0e53beda02bd82bf3d24bd1b65b656238128e734b6c7a65e3e45d3658d934f909c86ca4c3f2d19e0ac3c7aae58b342e", + "0x8ca5ceaeaf139188afd48f9bf034d8baf77bbf9669791c7e56ebf783394d7fcdf2a25fa4bdfcddfde649aa0dc67ccccd", + "0xa8060e6448844e9db4e9fb4da1c04bcf88fda4542def5d223f62c161490cf1408a85b7c484341929c0f9ce2a1d63e84b", + "0xaf6e1a5ecf50b754bb9eb2723096c9e9a8e82c29e9dcaa8856ab70074430534c5395534e1c0ed9ce98f4b84d4082fa67", + "0x81c8dbbef98f1b561e531683d5ae0f9b27b7f45dc6b2f6d61119ca0d559bf4ceb676d320afc5aba1811eeef7547a59d8", + "0x85b46cd64d605c7090a2faf1a2aadf22403b3692b3de1d83e38b2de0108d90ac56be35b0dca92c7a41c4b179a3567268", + "0x8dd3cc3062ddbe17fd962c2452c2968c73739608f007ad81fa1788931c0e0dda65032f344a12249d743852eb1a6d52a9", + "0x8630f1707aea9c90937b915f1f3d9d7ba6bda6d7fdef7a40877a40c1ee52471fd888f84c2b2c30b125451b2834f90d3b", + "0xb4a747e0bd4e1e0357861184dacec6714b2b7e4ee52fa227724369334cf54861d2f61724a4666dae249aa967d8e3972f", + "0xa72de682e6f9490b808d58f34a0d67f25db393c6941f9342a375de9ca560e4c5825c83797d7df6ed812b71a25e582fff", + "0x8d5ea7d5c01f1f41fffe282a334262cc4c31b5dcf31f42cc31d6c8e37c9bd2f1620a45519dab71e108fe21211c275b6c", + "0x8ccdc7e3642c2894acbf9367f3e99c85963cea46dc5473d175339a2391be57dd8815feacadec766e13645971213b9eb8", + "0x858e9b5fc8c13b651ff8eb92324bdda281db4cf39f7e7bd0472908b3e50b761fa06687f3d46f4047643029dc3e0ceeaa", + "0xae20d36c70cd754128c07cbc18dcb8d58b17d7e83416e84964b71ccff9701f63d93b2b44ec3fddc13bbe42ebdd66221e", + "0x860dbf7013da7709e24b491de198cb2fa2ffd49a392a7714ad2ab69a656ca23f6eafa90d6fdc2aa04a70f2c056af2703", + "0x8f809e5119429840cb464ed0a1428762ba5e177a16c92581679d7a63f59e510fdc651c6cc84d11e3f663834fcafeafdd", + "0x8d8a8dce82c3c8ea7d1cb771865c618d1e3da2348e5d216c4cbbd0ac541107e19b8f8c826220ca631d6f0a329215a8d6", + "0x86e3115c895ae965b819e9161511540445e887815502562930cedc040b162ecb1e8bdc1b6705f74d52bf3e927bc6b057", + "0xb9833b81a14115865ca48c9c6a3855f985228e04cbc285f59bf163dca5e966d69579ea4dba530b1e53f20bd4dccdc919", + "0xa71f5801838a6dbb162aa6f0be7beea56fadac1a4bcd8113a0a74ab14fc470a03775908c76822d64eb52a79b35530c05", + "0xa77ab73ae94b6d3378884f57eee400eff4a2969aa26e76281f577a61257347de704794761ea1465dd22a6cc6304fbc4a", + "0xacd1c5df3c487c04cf27f002e81f2348a0119349b3691012526a7b0d3bf911cdd3accbc9883112ed2ba852145e57fe68", + "0x8a28515a48832ac9eaf8a3fb3ad0829c46c944b4cb28acbcdbca1d0d4c3c623a36cda53a29291b8f2e0ea8ee056b1dee", + "0x846bafca11a7f45b674237359b2966b7bf5161916a18cf69f3ec42c855792d967d3bf3f3799b72d008766206bb7a1aa3", + "0xb24b341675b1db9a72c3405bbe4a95ccdfd18fa96f876ec946ccb5108f73e8816019998218a036b005ef9a458e75aeb3", + "0xb99c267b4a09193f3448bc8c323e91ef5b97e23aeff227033fe5f00e19bab5583f6e5fcb472ec84f12b13a54d5c0e286", + "0xa088aa478dbe45973b04ecafbcbd7ee85c9a77f594046545cdb83697a0c2b01b22b1af0b97dd75d387bb889e17f17aa7", + "0xa0c6b0cdff2d69964134a014e36c3709d9e63f6463c5cd7b01b6f0be673731b202d577539d89dd57a888326da1df95af", + "0xb4e6dc4ef11b2b41794ece70a8968e56705199d183366759568b6fa845d2cae127486e926b5b27ae9118bb21d1682c1d", + "0xa007804353f174098f02540a57e96227232444d5ae0a24232c244647148b6c049848cbd2b50d0a25af3ca9164bfff8ee", + "0x873fb034cc39c9cee553ece908fbf315f62efbc412b9afdde6a1889326b7f6f813e050b0601ba9921688e958cb75942e", + "0xb5676c90f0106c40d8683299e59d564f505ec990230cb076caef3ae33f2021e6aa5c9b27bb8fead05fc076df034c28f5", + "0xb5a67fc4c5539ad1ddf946a063110f824f7f08d2e4d30762c9d437748c96c9147a88efc22260573803ab545c18b108f2", + "0x817ff2b748a949973a91b69b0ec38efbd945aeb26a176d19f0fb76e261c7526c759e6f5516f9ed34de6eb1ac7838c9cb", + "0x99b76bda3526a5d841e059010fdb14eb2fa035a7d10463373a062a98c3c1a123e2da0848421dd7546d776438fd05e304", + "0xaa0d363270f90d56bbee7ea577b0c358532bda36d9247af6c57d000044a97ba41e35bb0db438f4c94551c6350e4e0674", + "0xacdae205d05f54b9544be96c9032350511895ccf413dbbc56d1f03053185df22a6d5b7ffcc3fbe96c3e2ce898ccfa73e", + "0xb091c220a1de18d384f50dd071dca4648ca4e708162c52a60e2cedc0188e77c54639f75bce9a468a64b2549119c07ded", + "0x878676133e5c700b1d4844564fa92a9930badb5293d882aa25ee6721a9f2cfab02088c31d62cf1342ae3edaea99a1ea0", + "0x9756d0793e6aba3b4dff48100bb49a5ec08ec733f966cb438379b91caf52fc2a5930830ec3f49aa15a02c82c1914dc7a", + "0x9722f760184d3b2d67cb2cea7fa41b1ff920a63446006bd98c6347c03d224d2d8328fa20ccd057690093d284b9a80360", + "0xb5a68489de4f253715a67f0879437bfe8f4dfc4e655ca344848980e6153b1d728acde028bb66fd626fa72eedd46ff683", + "0xa8cfc900b34835d9fd3add08044636f69614eff9ae929eac616c39bd760fd275ee89bf24b0f275dd77a66e54fd6b94e5", + "0x89967479bebf70b2893cad993bf7236a9efe4042d4408022fdbb47788fabedcec27d3bba99db778fcde41e43887e45af", + "0x889235938fcec60275c2cf0f19d73a44d03877d817b60bb26f4cbce09db0afae86d42d6847b21f07b650af9b9381fa82", + "0xb7fc321fa94557d8fbdd9fff55ab5c8788764614c1300d5ef1024290b2dbb9216bce15cb125da541f47b411a2e7e3c2d", + "0xb11b0c4dc9477176b3cda6b17858dbd8c35a933ed31364801093f310af082cb5a61700f36851e94835c5d4625bf89e32", + "0x9874e54d2939ee0600f4194f183877c30da26d7515e9e268fea8d24a675dd2945d1565d9016b62b1baab875ac892f4d2", + "0x90df3a77280d6f1fa25a986309bba9d5b89c3cf13656c933069bc78e6c314058716b62eacfa7ab4aff43518b8b815698", + "0x962b08299a287d77f28d3609f39fd31bc0069f7d478de17539e61fcc517045050644b0307c917208b300ce5d32affcca", + "0xb30eedca41afb6f083442aaa00f2e4d5dc0fda58e66aaf0f44e93d4af5c4bf8ea22afec888cacbf3fae26d88e8d344cc", + "0x847747a22fab3fe3c8cd67f3f1d54440f0b34ce7b513225dc8eb4fa789d7d9f3577631c0890a3d251e782a78418fecfa", + "0x8d1ef3cb5836e4039b34ee4e1b4820128eb1e8540e350309e4b8fea80f3ae803d1f25f4b9c115482b324adf7c8178bc7", + "0x8f8a2b0b0f24f09920b58c76f7d99ec2eb2e780b5a66f2f30a9ed267dcaea0ec63b472282076c7bf8548211376c72f6e", + "0x831ee6dc8889bbf4d345eaeb2f425959c112d2190764abbbe33bc44e1d9698af87ff5a54d01fac00cfee5878dee7c0f6", + "0xa7eb2479ac80d0ee23f2648fd46c5e819ad3a1f4752b613607ae712961b300e37f98704880ac0a75f700f87d67853c7a", + "0xaa4d1b9cec62db549833000d51e83b930db21af1d37c250fdc15d97bc98de7a5af60dbf7268c8ec9c194d5d5ccda3c1d", + "0x87396fd7e78c4bcf270369c23bc533b7fb363ca50d67262937dab40c7f15bd8448a8ba42e93cf35fb8b22af76740d5e1", + "0xa958b2a9ffccbca13c0c408f41afcfc14d3c7a4d30ea496ce786927399baaf3514ff70970ef4b2a72740105b8a304509", + "0xa5963a9dd3fe5507e3453b3b8ed4b593a4d2ced75293aee21bfed7280283348d9e08bf8244c1fce459aa2470211d41ea", + "0x8b06ddc3359827558b2bb57caf78b3e5a319504f8047735fcc8ec0becf099c0104a60d4d86773e7b841eb5b6b3c0cc03", + "0x9437e7278283f6d4d1a53d976c3c2c85c5fe9b5aec7e29d54a5423e425b4be15400ed314f72e22e7c44ee4bacf0e681c", + "0xb56067ee26a485ed532c16ec622bb09135a36c29b0451949aa36fee0b0954d4bf012e30d7e3fc56e9f153616b19349bc", + "0xa5c72f7f5d9f5b35e789830a064a59c10175093a0ce17654da7048827d0b9709b443a947346b0e5d96b5ea89b8d7c575", + "0xa8318d01182d4c9af2847a29a6b947feef5795fc12e487a30001cc1ec482b48450c77af4837edfa1aedf69f0642c7e5e", + "0x82ea421c091552d3dafa7da161420cb5601b819e861dd2ba1a788c3d1b5e8fa75cc3f2b0db125dde8742eb45b335efa2", + "0x8679fd1c7771ea3b12006d4a972f4f2892e61f108107d4586f58ee7f2533d95d89b9695d369cdace665f19c6bc3bc85e", + "0xb5ab3e8adee4c950fce4d33a0e2f85d3d886e60a6e2f4454b57bc68725f0cf246372d863167482cce1ea10a7c67c3af2", + "0xa85696927075ec188979180326c689016a0dc7a2f14ae02ea27c39ef91418cd44177d3fca5752cf6b298fd75fa012e26", + "0xa44f87b7232f102cd092f86c952a88afb635484a984da90a41a57a3d883c9469064bf105b9026024090486b6c6baa939", + "0x866ac91a437db945bbfdc11fcee583f3669fa0a78a7cecf50fbfa6ed1026d63ad6125deba8291452bf0c04f2a50e5981", + "0xb780d5a1e278fd4eef6139982e093ceafea16cb71d930768dea07c9689369ff589d0c7f47d5821d75fe93b28c5f41575", + "0xb025d0046e643506e66642c2c6a5397a8117bbfe086cee4175ff8b7120e4f1e6794e1e3f6ec11390993cca26d207ae43", + "0xa04a22b6e28c959ab265c7f48cde42bb6a00832c6beb2595b5df2879080a9424890960417d7d7ceb013d697d0ebf7267", + "0x81de9c656ac27f54d60d0252e33aff4e9e9e9c3363a50740baf15a2b9061f730a51ae1704e8c4a626153cf66d47f19b1", + "0xa15fab90599df889df11fa60c752948b68fba54005491180dafb66c5775547976d0eef33945e55d4818653e0818c6f92", + "0xb06f9be44ddb103a72fa4ebc242c8ee1975fe9bf9ef7124afeda9967ff3db644dbf31440151b824869406851a90984a2", + "0x99abdfe6806ae5efa2d11577da17bd874d847c5f810460148bc045bcf38c4fd564917eacb6ed61bb9164ed58055cd684", + "0xac53231077f83f0ae5f25e52b70bb6105d561c0ba178040c11c3df8450c508ed5df34f067fdaacf716f90b4926f36df5", + "0x99e3f509af44fc8d4ebc693d3682db45fd282971659f142c1b9c61592573a008fc00502c6af296c59c2e3e43ed31ec7a", + "0x98f2f5819670aff9a344e1c401f9faf5db83f5c0953d3244cfa760762560e1c3a3c7692bb7107ea6eaf5247ac6fd7cc8", + "0xb5b9f90391cec935db8d2b142571650fcbb6f6eb65b89c9329e84b10bfa1c656026674d70280ade4ba87eeaf9333714d", + "0xb0696b77ca8a0cdbe86cad12f358880926906fb50e14f55b1afc1e08478ae6376215cbb79bc9035de2808c7cd2b13b85", + "0xa51d746833062a65fd458a48a390631d5d59e98e2230b80d8f852cfc57d77f05eefcfd3c395ade1e86d4a39c2141365c", + "0x812d67654319f4ef3c9e4a2d4f027a4cb7768f1ea3f5fdde8d1b79187a4b874ff9a5c70f15b7efa079c2dc69d1b9b1fe", + "0x968978b653c6416bf810f6c2ffa3d1abbefbd06f66b6686e9a4fdce3f869e0ab1e43cce14dc83786596761c100ae17e1", + "0x98e1e6ab562ca7743783b802faeb0a24f1341abfb9655f106920aef08964a3c0e8083e1acda7ae28fed7cdd5478decb6", + "0xa91c0b982a0a7085a103600edf99e9d0bee4c4e7db6d9f8f376c215c7d42476218462a3765f2928e12c3dd49d688e4fd", + "0x8a43395b3124fab9e2438635bf88952e8e3084dad7ecb3a9927f9af0e0887bce4707084043671fc98ad03621e40a149e", + "0xb0b37626143d4a8c6f5693d5f1fe871525b4dd946c4239cde032b91f60a4d7a930d7ba28959737550d71c4a870a3a3be", + "0xb01c74acae1715c19df08d5f4a10e0c19d1356264eb17938d97127bf57e09ced05ba30d0fc1a9f32d6cff8b0d5f91c9a", + "0xb4c2328eb8a5a673406faed8f0aebb8540d2791646e37ce46e0e382506570ca276eb6f8e166dbbf9e0a84064873473b9", + "0x85cb9f769a185e3538e4a4beda9a008694e1bf8dfeea9dc07c5c40a9ceb1d31fcb13cacfaa52849ba1894b5027cb8c30", + "0x8742f91cddc9a115ddc73982f980f750d82d3760f2d46ee4490d5b17c6c3bb57c7d4c7b8d6311b7b41e59464c009b6a5", + "0x948ef86d17128a061e1bdd3ea7fcc7348e3ec87ec35dc20a58dd757d5d18037fe5e052bb359e27ab4c2320d9a52a6a0b", + "0xa70f6a214097c271e0d2d95e30fce72d38c30a2f186271fdff0e38e005aff5baed53739b8c4f9501aa7f529c5cb2da59", + "0x892a7574cf6704ad75b346c95ae6f2668904f1218c35b89b07a0c2dbf3c62173c348f6fd9473926eef56a37c0f635c04", + "0x837e85a41f39b4ded1420aa8fc3be46a7adb99305e0928c6d7643b7c44434b72984cea08eb68f5f803661df0db78c87d", + "0x94e495329f2aab3eeb68f347961d1006e69d990095877a4dcc376546233adf29a14bf6b16a0c39aa477e15368e87014c", + "0x851860a8fdf76a97048396553262637dade27f1f63f926997e74c7c72b14b10293eae7824e8dedffad1aead57c124f79", + "0x90481017a250972055ab1cf45ff17d2469517f10f18c9d4ef79a9bdc97a49093289bbacfefa8a1e491bbb75388b34ac0", + "0x983db15f7463df28091c691608ca9c51095530fa6b1b7b5b099c612e673d29e16787cc9ae1c64370ba6560582ce623c0", + "0xa477dab41014c778a1b78a7ce5936b7b842124509424e3bfc02cc58878c841c45f9e04ccc58b4f2ff8231488fff0b627", + "0x868ebba1c85d1f2a3bf34c0ab18721ea725378b24f6b6785637ee4019e65d4850e051c8408fe94a995cc918c7b193089", + "0x93cbf4238a37ccd4c8654f01a96af809a7d5b81b9e1eab04be2f861d9d2470996fb67367e5bf9dcd602dc11a3e4cf185", + "0x83113f4e696030cca9fdc2efc96ba179cf26887c677f76cde13820940ad6891cb106bb5b436d6b0f8867f2fd03933f7d", + "0x90c709f4e3359a6d215d03f45ad5cf8067aedd4aab03512dd62229696485a41dcd64e2acce327fda390e0352152fce13", + "0x9945cfced107a36f3cf028ba04c653360afc5013858b9a12fac48802efcbc198c9baf3a7f9b23dfdd5036e88bc7274c8", + "0x832ae60192b47fc735a8ddeaf68314b16256c90ab68099f58e43073e249c6939895c544a02fa34e40805bc6b5db33461", + "0x8b12c335818b643c1d22cbc2869606cf64e7ae54a7713617fc4dd3b2f052ebd6b920ca59ba2e9c7aa8cf71bb4f40f9e8", + "0xa2033eb7a373931c65d66989644aa0892ac3778b9a811b2f413d8bf534e282c339717979f9aa742162abb3468c195f87", + "0xaba2b4c37dea36bed6d39323e5f628ab607699c66767f9bf24ef5df1bfcad00c2664123c0d8d5bd782f1e14a06f4c769", + "0xb71963777535b4d407286d08f6f55da8f50418486392a0018ee10f9ae007a377b8b8336f33386b0eb01c45695c3ed2da", + "0x88dc87826941340913b564a4f9b74985a311371c8e7b47881235d81c081f1682bef313c2f86561a038757fb7d6a1a8dc", + "0x869e13e3fcf91396750150f9dc9307460494c1d365f57893fd06fb8acf87ac7dddc24e4320d9cad0414119013ea739b8", + "0x92194e292303d32b91ae9cecb8d6367c8799c2d928b2e2846dab1b901371a4e522fc4089aad8f4ee676f0614ff8b19d7", + "0xaa589a3e512cb4f8589bc61e826a06d9f9cb9fdfd57cf5c8a5a63841435b0548e30a424ca3d9ef52bf82cc83c6cb1134", + "0x81802e0194bc351b9a5e7a0a47911d3a0a331b280cf1936c6cf86b839d3a4ab64e800a3fe80ea6c72c3751356005a38b", + "0x88e5e9e3c802314ddd21cb86f2014948b7618502a70321c1caf72401654e361aac6990a674239afa1f46698545614c93", + "0xabac1e0f85d5c3ff6d54ed94930c81716d0ac92be49e3d393bed858833f4796c2b80bf7c943e7110de7b2d148463bfbf", + "0xb7eb416004febd574aef281745464f93ef835fd65b77d460b6ad5d5a85a24b536b4dec800cfe80ae98489e54447e8bb6", + "0xb3fd8ed1c30e7c15b0bc0baf0d9d1ecad266bafb281cd4e37c55edc76c202fb1e4ea315a91a2848f40f481793ae35058", + "0x86ef674ddf4b7d303c68bbfb53db00b925ccbf11d7d775ca09e458f4ecd868ca828103e8e7cd9d99672a193e81b83923", + "0x95ef414e9f7e93f0aaaeb63cd84eb37fc059eb8b6eced2f01b24835b043b1afb3458069c45218da790c44de7246860c9", + "0x93ec8f84c20b7752bfc84bb88c11d5f76456136377272b9ac95d46c34fce6dcfc54c0e4f45186dd8df6e2f924f7726ab", + "0x95df5f3f677c03a238a76582d7cb22ed998b9f89aecf701475467616335c18e435283764fb733fb7099810fec35932ae", + "0x8cda640695c6bc1497d19b9edc5ff4ea94c1c135d86f573d744358758f6066c1458901f9367190dcd24432ae41684cf0", + "0xb19aedf5569435ff62019d71baa5e0a970c6d95fe4758081604f16b8e6120e6b557209cdea0ccd2efec6ff9e902d6ce6", + "0xb3041f21f07d52e6bd723068df610aa894dfdde88094897593e50c5694c23025e412ef87a9d16cadd1adbb1c6e89ced4", + "0xa7f8d6ab0a7beb4f8d1cfef6960ebdaa364239eca949b535607dee5caeff8e5dfc2a9cfb880cc4466780c696cff2c3a6", + "0x99a565b4796e2b990bfcb234772d93c5ffdbe10453b5aa94662272009a606ba6ea30cc0c3c26aa22982c1e90738418a5", + "0x90c54b55ff19157c1e679d8d4f7f0687a70a27d88f123179a973c62565adfcc9347cfe31f54539038cf2f34556c86870", + "0x8612f34bcd018d742202d77d7ce26cf9bc4e0d78e50ddf75250b9944583b2c6648f992b635ea13fdaae119764e7c28d5", + "0xa04fb38e5529bf9c76ec2b5e3a1ef3c6f9effb6246c7f67301cfed707356ba1bf774f2867c77a5805933f0c8ad0ec644", + "0xb4800e7b503da0164885d253135c3b989690794d145182572181995e6fa1989f3d0324993e871bbd5f48fadd869d8a18", + "0x9981cd4f28ae7b7dadf454fb3aec29746dc2e0ca3bd371b2a57cd2135a7d93559e02132528ccd2d305b639d7ac51613d", + "0xa3ceec012dd1fbad3ef9f9f1d6fe7618e13d4d59e3f50540d2a57010d651092979c75442ec8b38a1ab678505e30b710d", + "0x8b97b8654d067fb4319a6e4ee439fb8de0f22fd9db5569ba0935a02235cb4edd40a4740836c303ec2394c59a0b96308b", + "0xb3d1bf4410fec669a269622c3ce63282c9ac864620d7b46c9dfcec52d8e79b90c4c90a69c32763136a7f2d148493524e", + "0x93174eba1e03f879e44921084aa0ee3562e48c2be49085de96ed7621c768ff52324d14c8cc81f17d7ed50c38ffb2c964", + "0xaa2194cd0fb7aec3dac9a1bd8ea08be785926ed6812538be6d3c54218ea4b563646af1f5c5f95cb914f37edfae55137d", + "0x93f2c0dd59364f6061d3da189e04d6c64389a3563b062e8f969a982cd68cc55b4f38b21546c8a67c8df466ff4f61f9c5", + "0xaa7dd497cc949c10209c7010ba4ce8a1efd3cd806a849971e3e01716ea06a62e9d5e122ad1d2b8e5a535fae0a01a7761", + "0xad402424b2a32bca775a66aa087580d7a81f0867f293f1c35580b9e87ccc5a2bab00c29a50fd0d7bd711085ae2248965", + "0x96237843d8e29ac77fc6ebf4acc12946ad11697de8e5f152fe5776f2475b790226a7d156ac48968dd68b89512dc55943", + "0xa45c25cdbb9fc327cc49a1666988af9ab4c5f79cea751437d576793a01c3eeea4c962c05c0947852fe0e4c63e1c84771", + "0x93dcf834a614a6f5484cc4ba059e733ab5dcc54253229df65ff5ad57b447353ebbc930736a4c96322e264e65736948dc", + "0xb9a94f82a82c0c5a26f2c1d5381afec3645e8ee04c947dc3b7ad59a73018db1e9965ab3642f2bbf60f32c430b074fb22", + "0x94eab29b3524ccbe0c4b928e5fa5dd8f684074b332fcf301c634d11083653ffee4f7e92ddbcb87ed038024954ad1747b", + "0xb8dca5f679931d6abef0674bad0639aefad64c2b80572d646aaab17adf5ca1ab2ebeecd5a526cadc230bec92ed933fc2", + "0x944d394958e539251b475c4304f103a09f62448b7d8a8eaef2f58e7de4f6e2e657d58d5b38e8513474115f323f6ec601", + "0x8a5ae1f13d433962d05df79d049b28e63fe72688fc3e6660aa28e0876a860c3dbc5fc889d79f5c4dec4b3a34cdf89277", + "0xafa5278724998eced338bb5932ecf1043d2be5dd93f4d231d05d2ea05b4455f2ffdc0eadcb335dcace96dd8b2b4926fb", + "0xb91153a2f4647ae82fc4ee7396d2ca23270ec7f8884ce9eead7e9376270678edd42dd3d4d6c003dfc2dde9fd88cc6e7c", + "0xadc932f1c679bf7889cb1ff4a2d2897d7973483fa283979a0ea3640c80ed106ea0934c1961dd42d74b22504be49851f2", + "0xa82e90761fae684d1415cee0649bb031bcb325ae0b28f128ab8e3650bccedd302a70de1a341ca8decfdda76f3349cad0", + "0x8ae353188b4b98835f4ef0333cccb9e29e1ac3ec11d554bc96f5880c101cb3c84b8eefe72f2287b0812735339fe66cfa", + "0xb8b41135bb1a1ffb64afbd83e2189e755f2c350e1273cf47c38ae9b8c4800d831436a69458b8ef9fa8b95a148d8ec9fd", + "0x96f75a04d8752fa93dc1eaf85ad333cff4eeec902a345576139e16de3a88eeb71b6726224349bb9844065cc454d959e9", + "0xab82b05e3923ad4c26f5727c60dc0d23063c03f5a4fd8077da66aa87042cad1bd99586d4ab35aa5e4ce6f4da6fecf3c1", + "0xa50c83db91c26ef7bf1720d8815b41bd056b49fd99710943679a162ccf46097a7a24585750ece886e38eb4fdb866fa37", + "0xa719f667914a84f62350dcc6f4f30b9ab428eac6837b70318c3ac491c1e69d48af5e1656c021818f377d911fe947c113", + "0xa148807aafddfa0a5624c7cb9e42468219e4bdb9994ec36bc19b6e6d7c4a54d3a0763d13ca80624af48bbd96d73afca5", + "0xaa012f205daf22a03e9fb13a63783dda7666f788a237232598d02a4d4becec7a699ab493f78d722ce68519262924c708", + "0x97fc15fab5952c5a2d698fd6f7ad48aff1c8aa589f7d3b14285fea5e858c471cf72f09a892e814104fa2b27eb9771e73", + "0x8da8840236812667c4c51c8fc8ab96d20dae8e2025290b9cde0147570a03384370b0fcbe20339c6aff09cca5d63e726f", + "0xb477d85359a8e423fed73409f61417a806cb89c9a401967622aba32bf85b569e82bca1b3394c79e180114a0d60b97316", + "0xb3d6ee2ed1e4c5cf8ba2c3a4f329832e41c7fdcbcda8a3fcbe8f60967fdb1717665610b7c1ac65582534d269d762aa09", + "0xa0b3b30b1b830b8331ee19f96b4a4321a6b93a3395b95d3a895682c65ec6ea64774b878b93514eaf353f2e4be28617b8", + "0xa2b88e9617f4d30ef4e686d1932ad43cd555fadcb5102e51bea19e6fca649284ccf4debb37b5cb2090ef386fa5bf5327", + "0x8a4446f7e8463ea977a68d6217a9046ad4356d6fc1c18d46c5d2ab681ea977b8faff136d65abea6bbf8936369cb33117", + "0x91e7464bc56e03f436228104939ddd50caace5a38f68817bb2991e193b57adf6835152bbf3dbcdebf0382ac9823f60c9", + "0x961a441e6cdf8106c4f45e5b47190d35644faec701c9cfc41ced40cfdd1fa83752fd56c1ac49131a47f1970a8f825904", + "0x94b7b165cc71c2ae82976b8f03c035fb70e90028992b853aa902c0467b384c7bcf01d56166bec5def4453e4d0c907e52", + "0xa5d32cffabbf547f900026b34ef46f08075b7a244565f615370d2f04edf50b094c95088a4a139ce07caf55bcd99afa07", + "0xb4e06e73660745f75ab2f34d9f6d2675b58f80f911ab6dd4c5a6ce1095f9a2b50d86f6ff9a05394190bdf96af0827920", + "0xad3fd8f83c0103b29d41319209dffca201d2b98094362da08da3fd6ff0ba96796b49d6bed525c9adb96c2954858e7f48", + "0xb0c27430695f0fd20ae31e1ec621da090094f2203e17411db9384695ffcf5c7c6badf461ba49ba70164aacebd6f278ee", + "0xb9bc6e972fc3b532fd2b1eeafc4bceb77604885f32132af6a9a842fa2440df452f49ec0cd9d86da1180e8deb0723b260", + "0x9729e22d6104b0174c136a854920f542b384d375040adcebe36acc253bdb55845eb43e34dc5a7cc27d22c417973c24d0", + "0xa8b420b36d48786c9231d454468a6e855dd7f71dcfd095efc9855ee70dbece0f06ad277f7829c5813fc30524c3e40308", + "0x8757dff5499668c93fc5d9cea0a8db61817b8ed407200d623030b5849a913d12f8371b667cfde8d8082026eda7407e8c", + "0xb859ad747ca5af661fbd03a1a282df6e84c224ecea645bc2d4ba5e35fa06cbf047387319fca0cbc76b712398c0798968", + "0x8e3173c27875f1460297af0fa736c945dc842ec3e476a973d3d5f790bf183ad3ffe96ac13868c5101d8e299890791864", + "0xa9d725e2b92c878be42b5eecc2c3081c63c7231ccc7e2dee17ca6a4caaeae22788fab1f1465fcbd7fc236613fc2bae4c", + "0x86f6c4f04a354cb2470ef91914816fd740f8d5795ce7ff981f55a2634695fde5951bbae7a4bbc4c63747040f8644170a", + "0x851773cb26f320f0c3f252d95ea7e058ffcc795dd0dc35e459aa1b6b448238909230d809e82022e64b7fca5d40b8324c", + "0x8962641e0306220d9892fe2d452caa286301a3c465185757be7bce2d9b2c9beb3040280099606cc86773e43941fd3439", + "0x8beb6e08c440b0de5fb85251d39d9e72db4e556a2dfe3dae59efd8b359d08492064cebd8d8993254b43bde8bd67d969a", + "0xa7e047894466ffe3dec4ab8d5462f2b1d8ac0df006b1d2dd26caf499ea857d93a811cf42233f9e948c9cb903beec004c", + "0x92eedd95557a91691a5e2835170390ce2401e223da43b78615a804c49566f9d31cbb7f10c8a8390c4bdcf691544fdba9", + "0xa5e5b5d8fa65824e958bbae98d146b4b332f97ed50e0bc2c58851dc2c174ab71bcbb1ae015cd2955c26b368487dd862f", + "0x853a494eafb308175629d581ed04bed71bbc3af9ca4c0dc483d03d27c993a2bbd88cea47c2085a6928d166fe6938fb77", + "0x83f06b88d29afbfbe8f61811690322ac4fdd6abb9a23612162e7a2dd6bcbb5f14cee298ebebc1a382484f7346dc51e60", + "0x8c9cf05735ea5a0e563490bdc7ed29a4426643711c651e35c8551ca6f855c8458ae8f0933a022d0bb9a952edfed411f6", + "0xb906b48d807748a26cc2a8848455a76ce502261afe31f61777b71917bdf7de2fece419db636439478c7582058f626c29", + "0x97efe1fa7c9b25d8bea79d74b6cdcf88f63f1e865f54b58512a2e60428630b0b40b8b6af1b5f71df47520507548c3cad", + "0x8ef5ca6e753818906bb3fc71405928d8e4108854ef0ef01c1009071b353bc2852e771fcb619d5fea45590e8f61003d7f", + "0x8e4d901661e2913740d70ba4d0745df5e8c9c0a260149d9362beadc7e669630ba909ff0e8a6cc85c54d6b7435d0d351e", + "0xb7c6ba3bebbd9592967954e3a480ee8df1d9f5965f04e7d78a5415b645128deae7ddaf6ed507c8877bfca91ce078e529", + "0x840bedb0ad4e25acf6cd25dee4f98fea495b2312dc5cb7a8388c5ab00b2acb9cd25da08e9fbead145a3107972b1ccd5d", + "0xa8d4578dbafdb27f3911af59962d89e75dea74db55346720357790da677312c203107d9c7911535aa563446fde7d4c47", + "0x86d3b77f231bfa09251b7fd2ce09c27ac520ec35d783e912476f9a4863f83d269eb175790d6e735da9260293d707f8ee", + "0xb34909f1cc033232652da0c34051a769dc76adb1aee00674a59dc1b860f6e610974c3b4bb69a69ccc73e01f042431242", + "0x90799854d0cf34e1d91ff8e101bc7c5007423d34d2f3bd9adea2ecac57e83f3a65a506bb93d4caea49b29f6d18149957", + "0x8ef94cde29b037e19a1ce7bf4418ad3c95cd9457412796ea385750c19a6690f13a3bb5bb6a9ee81e7a40face1e0a8bca", + "0x97053d21ae8d75972fb37f6fe516c38c32ab162fb56b9f510f954858f4e3ef6ac8c3a9557ed3f41b7b6aef05fe97f931", + "0x90a9f9f0f40991f3bddc58b92d40382147db22cce50d092d4a05aad251b46b94e71ec9f7107a180243288059fcc5ce29", + "0xa14265b1344ac2921b0f890d13bcfc432e4f648ce403e261fce4d3bb32ffee9e2794c02830346054f998e82784c77040", + "0x91928402ae121e56a3e64cd6f390127e6e92fbfb1967ec6efa4f52f3e8058f1f41a0f4fe96b5bcc11641c1139e790b2b", + "0x921c8c92b6d40da6c5a7b592acc74fc0f577d93767b9aa4a1cd302a72dbf503a1ea5b2c29fa0d0359bff3b8f252246d1", + "0x93ae0ebe0e8e133fd80cf67a499047e30ec4c4660ccec9d49098717ef57721a030f423e00c5e74af4ff4acf014a10497", + "0x82c865e21905aebfe0496af1c6ac7e342b5f446a9edb4f7da0f2fb0340abfd8e6fc545da874459d9aabe6bce0dd9bfcb", + "0xaee3961d8d2687c0f134b9c28b920bdc4021d925fbe14323c84224a9fe161248789249fb85436a5891d0bbff42c2a3e9", + "0x91aee420b98b6949482b8ff4be996b97245b4e8f583a6e085226539074f42aa89818395efd1a6699735a569bfe19d623", + "0xa48eec22c192e495b01722d0016a54acc45ff837e2a95c4294ce81d5a4e43e0053a6f0ead8a4fb3ddd35faf6607275b0", + "0xa26e15937c11faa30ffa64817f035e294cab0e839f73d29de8a244ad039be4e221eb47ea08d9a4658b0152fc3caf6110", + "0xb84450f948aa7c8682fccb9cae84d8e3558adf2d0ca5fb81eb200415291158720f8f3470542ab5b88c6873ad08e7fa9a", + "0xa8e8ec27d0608d020169a85d6ecdb40eb402f006a3b97afe32cc01987721b3a68a92ec693aeb4d357e189e05fadf699e", + "0xac87cd535ef5699312cc26f86adb71baa0be42e858bd5a2d94ac05737dac63430691e29b9a30d2559ad581a172519b2c", + "0xa4481e67b524f8cddf2046625efd3d75efee6aab87ddd2c1b22835647e918157e5e924ac760db2195c86d326f3db1615", + "0x891f29ded231486ee826840c8895cb325f7e84a5a6d2eac246cb3573612cde274720233b1978318a57ed337a046330a6", + "0x906b6e750e6178289012769807d2598925d7e51c260c14497d8af978b1695990e3352e6e809a752f376597a68083870c", + "0xb7a056898ee1e46f7f29702fb39232f678ec173eccd170303b3b0a30c8d8cf1a5321384e3513e3b03bb742c238deaa54", + "0x8f2f035fd96c3a336354c89ec9b8222803bf42e95fb2412c28d4e75eec99c1d4d402501ccae17357b757db8bdb0bfeab", + "0x81228625ffcedf977fba9cfa13f6edead3985e2651d5974789c394a69401cd7face9e20ae6694be4c0d4bab5e99c61a8", + "0x885a83eae25e61439ad809567a2ab148583402e01cfdd77b0e37ab4038935425c64b4e0886949bf06438c35e80aa13f4", + "0x8926387f48752f6933899c48e038cf14e7941ec6a58bcc0a436614b396296a17aa53e6873803dd3041dae470bd493fcb", + "0x95d0d3fa061f4d856eca78a569aa132db14cede7646f97e2aceb6da0c8ea53195d3b7a566fe5ec8c41b95ecdd89a1c6b", + "0xa3c817f4062ed6aa94064ea695d76c1825f3bf77b310fe1db28b8bedc9aaacbf1019dbd128adfd53042fb943d863a2b7", + "0xaf1208417aa584052da309169854149ede38a3ad63c76cad6e43afb6f1a7b854edf8310a0b00088c039259cedf0f859b", + "0x8b713fc3196bad35dbf364089049ada5477e540d78d76a5f0a9df98f7ba4a0e65dd0644509c149f9b07887298bf74b04", + "0x89c09c43c5b733c4a417cd9ebc0795cc3348b72778d31828a9171427779a82ef023c1a4fcfcdc919ae25056f9c826fde", + "0xa0759c850ed320c8c874435e90ace6edfb8e7b3f2a09d942b8ad8339c508044ee2ee26c70f1b626ec49a77971433b6a8", + "0xb85cbc58d4fd52286e714ac4eaaa0b2743a1de06fa03ddf8f6668ec6f1d204acccce93b10620272afb8c0b49bc4b0a43", + "0x814e0a87384e159892a8d23036985fa3f489c53bce192e107bd2d64f57b1bf5ea0acc1ef46c7a42bbc5cd0924d92b4a0", + "0xaa6821da96ad89d7881b878e141076522f104ea9a5bbdd1fce9f641898f7d6232c518a87a0f666871d7e3165c26081e4", + "0xa9041d714bfc067b5427252186fa3557bad598fc0067dc8521aa9bc1ae298f6e96113db5ac9f6bade9a85d5a950c9755", + "0xb8669340f3064692625e1bf682d34fbe69a61689e3aa6d6a3e822c781d406b0300dba9c3f7b8152a8c2513f1310d4291", + "0xa78c53316ce768a1dc5968030bf4fc885f4029b1ddb6a5d84a61c85af686c73727f62823891edfcb6ccf4545de366cff", + "0xad1d3aa29ea28292ddd438c865e2b5d93f32cdf009e6d5f5dc726de996583925727e6348bf1c28c22dec0bd86aaf867f", + "0xae1447a2062e9e28af5f38aecc60fe150cd10c2edeaf2110034aa144f6235ed7fbce432a58805d4fe1f6b12652d6e1cd", + "0xa32146634332d3303934550705353c6d4fae5fa5985105bba35041e74cd71e2aad67b45da171221f6ed80f36bf6dffa3", + "0xa232e8286184196ea77427b53d8b52c44d758ecc42d22556529db3136379b4989dec61cff610cc6cf6700a450a847a94", + "0x8a72c7255125a736da52dff5f77e44c3de29f88fc05f5ff9227c69df296930caaa11446595e6bea3bd946baac5ef957c", + "0x9688a981a9457678067f629f8efa6b522e7318b529f88d37ef56c5bf8f1c34fb9bb3a918ab73caab82bf5abb0c03518b", + "0x88286f3eabd71115fc3b17a6bf6981340a81cf7e5f96b0a1a016d4ec8c18fb486d46c70919123d0c189a6f5d6ff29a1e", + "0xb535e701b40d793c02ac0d625ca91620d3f4a512aa9741f71389e58381008b2f93d597586d06213c4e103d67d0ddf6c5", + "0x80d0c9dd941e8d8d3700cc51a434a5aaa3308cf8ebfd14128ccfd258f826b27cc3cf5c3ad7851340393abb1eeab3a157", + "0x87049225fa2380d93f18d3d90cb0697a56b373b66d7f24ab209966aed8b55a2790194d5885399db29dd5b1f189eda64f", + "0xa52df158ce8670e0290551e8878d63dd33b4759d6f50e448e63fc7fe6ea99dddb6f180be5fc0fc3918ce54c05f80b356", + "0x8b2a728b39c465fb0f60b0c486e5dc8d5845ccec03d3dd93b393cedeeb3fe1b44518359f1ed55fc770a8f74bfeb9923d", + "0x91fc05419dba718fa4a910dcf256ebea356bbea00522d8d5ec3e7ba4271a26035aac15e8d9f707969df1d655d92dac55", + "0x97c8779ae80c24c1f82d5a714762d6ee81069224e39515e41d8a71c9310dc5d1c55cc92bc5c6a4bd391ae4c321d1d4d2", + "0xb5e5aedba378c4484e3a7a4ed41b75b0844f674261c2501497de6f91f7274b5a4c1be0e055f2e0c0cab843d891169fbf", + "0x8a26212f27211b295beea500abc8e9d430a8500d3a350cc62f895d39e8b4668aa638c17633804ba353010000165637ae", + "0x864a95118e5d394e00e99efebd505df0125525c9ebe165764c453b80ad3edc730feebde3d93850745dfd88a27bb8f20b", + "0xa092e0b78290e826cc1ae56afffdd08f7c10954f549a3ea6666f3db1b6cdaeb7df53db28dd2a92446342930fe60a27ce", + "0xa1720224c0626a081b6c637b2a6d37da85d9a82241e5efef3bc15699b02a69f6304e43d8ff3144d60c16e00225d6b39e", + "0xa7b3d098cebea9cf32e19c5195608182b6afe9d4af6b9df532c047eb7a941a971279b2ae6a4b80f2f9d9313a6d788ce3", + "0xa3d2451e6788944802c5077a778d7b7299dbb9d1612676bb6baae78f39976e0fd879493cc4a4d737b8174b472a456850", + "0x930121b73da844571b1411d56760e80923a4ee09917b3e9cff4d3dcb0bc27026ff2c4e2c44e7aca7d3f8383f129c7f9b", + "0xb4b0119d163ee00a2b74bdf188a5cdcf054daaa48c483b94bbb4d09ff615afb4a91347db6363bc7535e2af9054ec2214", + "0xa5846decee706780201095a8cdd48fbf3d3a2eac8d089a818e5e22c29457494bbfb4399323b067f3d2be2197c33dbd98", + "0x96ba600df10ee7af5a9df29c0ca31dbed275d647faf9c66c7342de927ceb25b5bdd852dd7aae0228b27897f90fdd5d62", + "0xb6ac51ddc98edd9fb9f54ef84bf372a041d58dfdf0dfdbdc4b08ddc1a7ba93ddbb1413dda3c1545a3fd7386c6b85975c", + "0xb35f3efd91a0723e0d486188ea9675a3462106470455118392d7610470b623caca2fa33829721c05fbeb0fabcf570bfc", + "0x87f49e85df5f8055714a8ce7adf37f6a278e64e76ed74c60abe3edfc3611ef5b0426d4c6da45e5f3b74d30be1dc6f539", + "0x8ff8bb06902a71b1e9177a77367318b2e3e0a88f5d74d6907ca9943f4f9f1ceb5f297132c2a025259d17a67e880d1bad", + "0x85eb6de6c70fe5c53ab0ab27aa0fec439f136c979c557d317337cafa6e6c5cb3169679c9169567dec5f6c72b3c057d83", + "0xac18715ed1080771d760cb7066c6328faf65d9b30517903f8a5cad8d66d5c6381156b521107d7cd75ebb8c30e250706c", + "0xb95b9eae4703727e4ac9ddf2ae675906487bb78905a5f9cba74a4cbfd118d96b7afb6ef3ed5edf14fd963b830d71338c", + "0xa3b47b52fda16b62b11c8aa4daa56b0b669c4d5c56a3059b7d063284d8a91f6fff9ccccab23d6ceb9650483b2d353039", + "0x96a95b3f327df94c85e92f2e406f1649ac621533c256b062738f3c3ee137059a735a3e6072247acf57b1b0d8c219bd7f", + "0xb19b33cc04570be94eae8e943d5bb17bb0c96e9de4ca84f9f41b37320a1a03d397d53747dc13275fef1b356de557214f", + "0xa1faa3dcb931dd91507f3f12a17c43f6627fa2bc5c71fbdd27548e091eaaaba262477949cd51290e81196bffb954a492", + "0xb060a16079dca1d28a1fb33cbc26f368630ee042d980ce305230005d5b9ab533a7a695281ab76e9214458303932d8bbc", + "0xb303783196a858fe45d67e0520c30576da605fd69964449c20009fbd5099cf1de52a32d326d7c3b864de07440195ef40", + "0xaa550a4c20d1003d137ffd8fbdc1196d09ad53cfa0e202302093a80fa3bbc4c9aff83f34f2151785cc1ce5f30255693b", + "0xa7f8585f45566a351058e10c6f1ff4a7ba24811f1482a47202f581525615ca770da93f2f58878788b45b92cb446ef4ec", + "0x8206f63a9a5b59bd68e64a843e68fcdf706f4c13bbfcdfa9928298e5b9251006ae0bbd80c715aa3c9957d2c0148b5059", + "0xac9490abe1241319658f1c2c645cfa01296f5d4106020c7894b7ba4a65cdd52f6c5401bd3b3cf1c9863e088cd8c9a16f", + "0x85dd6d9c80a1b58c24c4d2cb7590d33d2454f381f58e820979948e5831972360cde67bbd56e1860077ef5192fcacb904", + "0x8b0285944c676fe2519cb68da0973275fa29c0718d838d363ce46651b068d29f867cf9fe579ff8da0bb8b37d202bb23c", + "0x95147275da658d43a758b203b9ca1f1c1478853e9bf77b5218593142e2bd9c0bf46d2206ab64cef99295de6e9a268edc", + "0xb8efa187fdd3e1f46c15cd596e9567690c10e253b5beaa5be8074b6ea4e6d3d06e0f2b05323453239e419ae1e7128521", + "0x8340464f52c92e31806fd3e8e65f56e27194d1f6daa4a0f0b3831e8102aba16f88bb5a621633ddb7dd0342e1d2d12343", + "0x8615d87dcab85a78dc052f05a01e751176b756b5dc9985014347454ce5752f459dd6464e1c5aff36cb6c51b783fa2692", + "0x80c6e35c0d3defbe4d3968792724a23f0b8830dd2fac58663583a49339ea20f1812cc4140e3ee867c7e716177319bbbe", + "0xa7aa63dbfc201dde8f29bb6e23d7aa5020dd35bd18a0cc93c8a10c35d695913fe25b9e8cf9b5fd1899e9657b22bc8863", + "0x97c2a4ba80c4caba2e729a603d2faa0120915e3fe64cbb065f7ff33de5f877f1ec9461cf455e88ec9e9ded9393939dba", + "0xa54bd1419f0e2d2d87757870f37c476c7e3a13502f1ada82fd7394fd29f8a00c4986473d753034d0954a2550badbac0b", + "0x8d3e2bf900d0d2b9b46e6e2f37620f0cc90526dbbcfaad4e4a37ed53f39fdd23bd3a6f21aa7e800eaec937d9710dd6e3", + "0xa88d2b1c7802b2dc216c2b6532406c091bfb12f29121b9a82c1154470e250188413ddd3e79f7e009ea987a4c45b332e5", + "0x8c552c2101dfdc3f99c2da436115452e4d364eefe029b12946f05673c5ce1cfb48d39a579625849236dc6c8e7277dd30", + "0x8415c252d52a26a6400c3189c928a98559bf24162ecf3eef1d10e439269c31d854b0b4f6ec7a2430e3f11b5d77de78d6", + "0x8b38905bad93a8d42339dbdb5e510003c51fcaf05e04f88fd7083753353bc1c4c00a5dd4a67431cd4456d0669c7040e2", + "0xb1d0ed8862250d0f0d9ef9dcf0cd16d84313d1a795dc0c08e0b150dadf9ce73d32d735e04632b289cafa69a6ee75dc89", + "0x9434e18a5fb631b10edb02057f2d1fe16000ee55ada3c26a079c9fc3943e29d6de99e52829fe7b333e962270c712e51e", + "0xb1b9f3914007e6fca8ad3e7e848a1108988cb2318da36df24767d804e95d1272943fda948451135cc1b5052a3953b081", + "0x8c02947a76d7b6c0a700a83dfb971dc105bfe996e18c521445f036310914b349ab28e57571e36ae08d13a46fb01c2f43", + "0x893472fbc225f973a0ac6a0a0130b9cfb7ab6869dff80df71a62b1f6beb4afd069bbf35b4f327165bc31dff39e4fcaa4", + "0xa7c176c0903175f3540d62f9afee994d5d9bf37081e094644b22f017e94c515afefde7bb07f638342abef7de657f8848", + "0x860186c2b1d3b1e657729bc804275fb5f5ee89eaa60848fcabd3871289665ea9f0efc8a95792d884972bcfa2de96223b", + "0x865b38aea6386d0ac8f501a7d934e23d01dc50105324e354d4c4fa3cb1d4c29c26f4566df7b1a728e10cfaa9d24552e6", + "0xb4eea5548de6969dada658df604b5d9c49002e2258352838003e0fdf7b299d81fb025807a7f37cf5b547cebd7f2c1f93", + "0x8982de11ba68d63a649a3b296d4d56c71e3c3eec016db250d733ab7c3b9a620c09c5a5d0b64fd30d3bc03037ca4b17c9", + "0x84d8b8a10d67eda4716673167c360fc9b95717cf36ef1d5bc6f2ef5b9d2624f0e76c2a704d016adf03e775ea8e28d83a", + "0x834d03ebd51aff4d777714783e750b84c16cb6627f8311bd8ff17c3b97fc4a5bba57d6c8f6d74f195d3030bcb5f07612", + "0xaaf49e0def0c4d5f2c1e9c17b51e931d2f754b19e80070954980b6c160178349f6d3c8d4808801d362e77f41a0008918", + "0x8ef4115edec841854e89f2bbd11498dac7396bca35dda554290d3db1c459ffc17be671f4a46d29fa78cbd6064cc2da20", + "0x9641dc8a64f4acd38e343a3062787c48c312f1382f7e310ccea3e95e066ab6dc980f6ed90a633236a435e68bf6b3c625", + "0x8a84cfc2cbeb18a11dd6c2a0aebb3f6fd58a33bb4b26101e826add03748595022e816afac79a4e7c20b3805252839dca", + "0x9770782d729017659844421e1639ffcda66a2044df9e19769b90292df87dcb146b20c6b9141bb2302029d84a5310665d", + "0x98c7ec9696454868ac52799d1c098c15ec4e08b34884dda186ebfe87d32840b81fd3282295df141c91137faf4cc02da8", + "0xa3f6eb921247617292162dfc8eec5b830ddc294a0fb92f5b4828a541091ffdaff34c392c1d7168259d6204405d90ec72", + "0xb185f77a468f07a54222d968a95635234e74fc942485604909308a9028ed2753b15902b9134749f381f7cd6b89cc8c3d", + "0x867608a682d53bd691dbc92eeb460d1c300b362ca49c11a280f6768ccec217f1145f9d59fe50d994f715ce89d38a74e1", + "0xafaad630ad8827cd71aade80edf3d7aeb65a344878db12fa848759e6233f6fceca563aa437e506ea9e0f1e47b126d45b", + "0xa12afbc84e3441594aecf85d089423dd3bb8bb33a1a384ddf7cc14caa72284caaa56aa179c15e3140fd56bb532491a67", + "0x98757b0b5e5837ddc156a4a01ce78f33bb1fce51e0c1254ee9b6d3942268d0feb50b93edbf6aa88f9ea7b3c0309830d8", + "0x89573f4a4ae752e9f964e42bec77d28a41840c28e4bcdf86a98a131d0b85367b885077823a6f916972de6ac110821bd2", + "0xa17f2745052de5de9c059307308fc49f56cb5230e7a41cb7e14a61c9efa742ee14c41023ce90c7f2261adc71e31045f8", + "0x914b07c53a41c0d480083f41a61c10429ea42dafea9a0db93862d2269ff69c41db8b110b4768687b88089b5e095523cf", + "0xb380cc3e0d26370976fe891d24ea4eeb1b6be8cfce01f47fd68838a27190e644fd57b049d3aa0a9589370de20e276944", + "0x906385fdfad60feec79eb1c303e750c659ceb22d9c16a95faaae093daadd53e7aa039a45d57e20951d6e1ca0dc899ef2", + "0xb5211ceee31b194dba60b616bfd91536e71b9213a3aaaf5aaf9b2f4cbdeb05191861d78b97eec58e3c81abe4f0488c04", + "0x97878e9e38c2f69d697800e7a2f132fc4babaacf471c79c26a757f771606e55fe696ece68a3163a0ffeb2f72274cf214", + "0x959431c1f54c46500c05aaa9a2bc4230531dad97ae768fa92bb85436c0ecc6374cf20fb0ef82d122db116820a943b401", + "0xb69e5a1c6798f30d33e42cb8d124f025d2c77c993c4c7107a539aacddf44d8d4d2239e802ece32e60ee4dbfdce201bdb", + "0xa8b09e5e9f802ad273b2efa02bcbc3d4a65ac68510510b9400a08d75b47b31c6f61ffdb3704abf535a3d6d9362fc6244", + "0xa41ace7f1efa930564544af9aa7d42a9f50f8ba834badcaf64b0801aaed0f1616b295284e74ca00c29a1e10c3de68996", + "0xa8f2aa0bbbc19420a7c7cec3e8d4229129b4eb08fff814d959300cd7a017ddb6548c9a6efebad567d5a6fde679a6ac6a", + "0x9683da74490a2161252d671d0bc16eb07110f7af171a1080dc4d9e4684854336a44c022efe3074eb29958ae8a1a14ace", + "0x8ef44d78d10795050c161b36afa9ab2f2f004ccf50fdeef42fe9cdc72ebb15a09389ca72a00001cd6d9b1d7b3bb766c3", + "0xadca54f3b14fb18298098970b0267301b7312afb75894deea1b2afa3e85b7a3b4efac9971ab54c5cbecba2da9f18507e", + "0xac5d4528f06fdccfc1370d5c3d03ed982fed0861a93a3f6453aa64e99360b124926d1892faaf72d89459e663721dfa99", + "0x98aa1c801bd615b8cba728fa993021e181e0ad717ba01c0290e7355694155407083eb53cb70819c4775da39d33224db7", + "0x8b3aea4c7c2bfe1020de3261ec085d79c7bf8a7903b825d2c70ebbb84af197bcc54e3653c5373a2045c3021526b63b66", + "0xa29f3de4cb3d99afff1daf7d431b38a33a9804fedc41626618928ed059df6f6fe9f298a046b594ffee951ed4d4e1400f", + "0x803fd346be540c5242667c18ee41b26bc812456ab13ff117196ed69b90ee608c8cb6554396b64066a546ec87a71ed6a9", + "0xa9c18d81ffd029c0339c72c499bb51685392253b996b6eabd8b76f05c6191ed8444a1397d63b9923743661a319517f7e", + "0xa048d5c390d08f07161faac71c5994baf152c883b205f3bb10d3501709d6516ae54d491b486303a11b751857a31f0052", + "0x9156fb4803e40e28d8d57d928481a8de4373687288da44fe88c5676a8ae013ed1fcc09d56a31140bf74e7f767253810e", + "0x98e289c725b18e0085afdfaf2acbc674dae7b0a2ecc2537a7d0b87e20eb785404ab05973a787f0495d2adb3e5565c09b", + "0x8a7237b249325bd67cdc1f9fb278710069033c304afbf270b7ea24dbc10c8eabe559a484d3edc733c77b4384932deb41", + "0x9056f2e5b02e5c2e04a69fa1323bbf1859d143761268d18e74632e43800a2a9c76fd681e924a19bc141de0e128d3e462", + "0xb9f2bf9e4e7263014296a82b9ecbb05d3f1efa4b2e675e3b38d3eace59da06a89c859256e1b77847886d6aa15f98f649", + "0x83b22949cca19030289bbf7cd2a0d8b84e1d468e78bc85271a6753241b89122627632723bc293cf904a5eb2b5dc6c3ae", + "0xa919aaf35dd0116168d2ee845122026416bec9633df113fbd913d8db5996221e234f98470d029a8ff182825b59fda20a", + "0x91726901f49d32b41afa15219073842278f60dcee223640903d871e318a1c2b541136b7b38a7b2ab7d31e4242fc29674", + "0x942b77666545bc9a858d36cfe857ab1a787c9528f4a0b87918a06bf510793264dcafd12ae6bd3ee300179dab7f40aed0", + "0x80adc1f2f9c47a96d416e44fcba41628abc0fae1f88f6a26aea4648419ab726f7fcc2187c7d5145e3d8f5a75c03937f4", + "0x8041e0f66ba9dcee01e336dd4d16ae5e4e1618512fc147cc8230003aa2940848162dc2187d4130bf550dc1f3559849d4", + "0x999e8adc51bab54386af1c5e8822986ad1b7ecaf1f8a4c2baa5bb2fe9d10710e49545c5a8bd89ed0e61a3d73a908e5ef", + "0x89272ffd39b6e9f99fafdd58bd9dc00f66f26a1d36b38a1ac6215e3546d966739eecda7fc236335479207cef95cce484", + "0xb8e0b7532af13f15dc04a0eb4ea8abd67e58f1b1c6ad2e70c0ffa04a5c18ec2018b5d7f4be2f9f86db5e0b3986f639d9", + "0xb96bd11b0f6ead4abd5fe1e4c6e995da7583b901afd01cc05e87d04663fb997997d6d39dd9fb067c62cb1b1cbb67516f", + "0x94ab08914088b973e8dbd5685decb95f3bf9e7e4700d50a05dbf5aaac9aea4be2c10c83096c02252e9238ceea1351d05", + "0xa188de419b062af21275d976494c131ba18d2b2ead8bdbfa38a777832448e64d4d9725c6a1d530ffb6513f18d5b68d9d", + "0x8f73c8c118fa25c76a4ec5611351953c491452743056a819c8c82ba4737a37d88da0b55f837e7239a5f46d2c05a1bbba", + "0x894a44769e0be1c26648b0d89c4c9f46dbdeb3a71b90c493093bee372bb9f2d3f319850fd886d51f4f58db0de5641742", + "0x87d239923b0db024a8d9b0281111d47b0761d81c50652268b074efa3ea70d793e30f874a91ce33a4acecd0cf38c01951", + "0xb1b48b75a97f9fc2dc9530dc69f6268829dd0ddd574516e7eb1b9f5c3a90058889a7bcf3d378738e6d4b02f5fbfa44db", + "0x83e3ee9526ffcb60c6e75b75550fc017912ec0daf96d0a0d5f58c1b229cce90c684ac7c3e17fb998def8e7e2e155d750", + "0xb9b7bba579e474b0abdc7775ff5f84c9f117c6ca17788cf5a5f01b2c35a14aa39036031c8d799fec2cfb371d9f7471fd", + "0x90d7faf4891fbc368a32f575dfb69f13e37161ab4f63a7139be103285a49490c2851a907f8d36e09e7d1a190dddbc6cd", + "0x968c8b9affe18fc34a4e21f0d8c5518341c566099e6b45b8721c9912bab3693c9cc343406fe90279692a1eef2a3f7311", + "0x8735baaf4704207550f77df73fb701d9a63329993a8cb355ccc0d80daf950145f37e9b4b22be2aba29898e974f9fd552", + "0x90f52b2dccf525b9191d836b205ffe966d9a94f6c5800f8f51f51f6c822619e5abdf1257ee523597858032d2e21014ec", + "0x831209f8f5257bb3eb452d3ee643d5f063299f8e4bfea91b47fc27453ac49fd0ba3cf9d493c24f2ca10d3c06d7c51cd6", + "0xa5a4db4571f69b0f60fb3e63af37c3c2f99b2add4fc0e5baf1a22de24f456e6146c8dc66a2ecaafeb71dce970083cd68", + "0xb63da69108fad437e48bd5c4fc6f7a06c4274afc904b77e3993db4575d3275fce6cffa1246de1346c10a617074b57c07", + "0xa449448d4156b6b701b1fa6e0fe334d7d5dd758432a0f91d785b4d45fb8a78e29d42631bc22aaa4ea26f8669e531fed7", + "0xaabe43de1350b6831ef03b0eef52c49ffb0ccd6189cce6f87f97c57a510ac0440806700ce2902e2e0b7a57b851405845", + "0x91015f144fe12d5d0b0808c61fa03efe0249058e1829bb18770242f5fb3811e4c8b57ff9cb43deccfc70552e4993892f", + "0x8e9c570811ce44133ce3e0a208053acb2493ef18aade57c319276ad532578a60d939ed0bde92f98b0e6a8d8aabd60111", + "0x8b21839b5dc1c9a38515c1076b45cedec245d1c185c0faac1d3d317f71f1bfebba57c2559bcdb413d9d7f0a2b07f3563", + "0x90413bbd162be1b711e9355d83769e6aac52fdfa74802d628ff009325aa174c68f5329ddd552ef93e8fdcb9b03b34af3", + "0x8b6b02e3f9dd1031ebd3df9a30432a3c86e64306062ef00a6d1243620d0cb66dc76f8d0d412eceff877ff8768c2696ce", + "0x9894b41d9fc715f8f6addace65451f41dc5ce7b983dd8cb33757b4d7259bef12f144e0077d0b662aa847d5a45f33c563", + "0xa353a9740f6188d73aa4175a6c5f97898a05ed7aae9d2a365f15b91dfa7c28b921fdef0a32d90b6fb82718b33d3ddb8d", + "0x984eab8faed87c403c9979f2d2340fb090cc26d00cb4092aeb187c3f4ee1df3f57cb8363f7764073188790b16dfc464b", + "0xa5c5ae0ba435fb7f3ddd5ad962358da326239ff236fc3b51bd22e88296236b109951cee1b98f444302badc58d1b5bfbe", + "0x880be1006b0156f2788813432f450f613d235f41aba52a6000d2ad310408ad73d86b79f6081aef1e8c51010d404ba670", + "0x937da751aae68f865c7a33fa38d718f20e2a1c65cb18c8e08f8441f0cdc77662789d2793794dd0a427cad30cd0b33f42", + "0x9496fde66c834ff86f205897db12bbf9a9bb78d9ba8b5fb539cd0a2c927cc6b4120c017b0a652750b45edbe5f650e5dd", + "0x97a6f409ffeb593e149307a14bc47befb632412d70565c5f13d6b7d032acd2e3ed0f7b6af701b387f11d69ee4a8094d7", + "0x97ed94934263dc0260f4f7513745ed3483cdddb9adb85dc33193c3a8b4d52affaf1ded23b59c34651afbffe80d40dc36", + "0xb2b26378d44f916bcf999db218b9892e06de8075f205c7dafd6d37a252185c2d1b58e2e809c717963d25627e31f068e4", + "0xb8f9fa1fb45fb19a45223f7be06c37d3a3501dd227c3e15999d1c34b605f888123026590697d0ae24d6c421df8112520", + "0x997aa71e3b2e8c780f6855e94453c682bee1356b5ce804619ef14834475511105b1e4d01470fe4e2215dc72182d9909c", + "0xac2cb2a7cf55aaf990cfada0218453853047e813d3f51f5a623d09f4714da79de6592671358a5edf938a67f905b6cb5b", + "0x8d8340d0c3081cd30d34f3ff6191e1ff6ad7994b4ebac19e5936f1157ca84e1813228b7605ee226366d6bab1e2bf62a2", + "0x9693b17669086003cb46c75fed26ea83914a54901a145e18c799a777db1df9c9ca6b2ea3ee91e7b0ab848dc89cf77f19", + "0xa6b6b2a6cd8c4922d78c8ba379373b375d66ac6ea04b830a23d5a496cf714a9439d81c865da92d52600aa4e2e43afcf1", + "0x89cb665020abc3f5e11a03c7ba5ec9d890fa9ed2630f1443a8e45a28c32786ed980b5343ffffaea60eeff5b313bc0d66", + "0xb37b989106594221bc6cf33a1a83c3e65ecdef279e90333a9e105b8139dc28384bb2277edd4b77c9e59d15e6afe074c5", + "0x98ce5aee5918d18b2326b30c1ba41669cce20bc7a1d1b585363305fbdea66055164a7ac398ca0f0e670291a3061022eb", + "0xb57f472d5f34beb4cf430d7c0f8ac5bd1c0621a284633ed36e6f7804bc2b7847f54b469c7ea163a436510d9e3b32f97e", + "0xae673a6579dbf0504c8fd0c8fc0252d2f7ae8da615a06f4d215c2f8a8f516201f24e5cc42967630c252905e5dbbd6377", + "0x97c1501835a31091a5a83f0546e01c85ee847a0ca52fb3cc0653f6a826e13d25ddc623a5dea139108f7270a1fd7043ea", + "0x9376ee667f3834f6c0da4324fdcca5c04712e0649877ee19da79a2d23be24640c38758fce562470ce2134ca34148ffe3", + "0x818af89c40379a10074cfaba6d5968ecf667f1a68a7edaa18e8977ccb34e0829f237c5634fbd079e7f22928b277f1096", + "0xb8e0af0be0a252b28df25d4a509f31878bcddf702af0e5553393c3dfd4a1f1247ad8dc2668bc8dedc9b41f6ad8e71b15", + "0x811667ffb60bc4316e44bd04573503f5b4dc44d1ec824393a699c950e5fa085b146537ddd6a08a3fede7700396a0df7d", + "0xad834cbf850b2f61ce799c4a0f8ab0c57039d4e1113933c50b0c00175171aadee84894d1376cf325bfd434c3deb44315", + "0xa8b7dfcdb40373ba4d55e751ccfb9070554434df9e359fc165284ee3dc35db6fb6055657ecf5a9e9b7b8e2e1abea4375", + "0xb56a5b9fd41c9d3f65532aa58bf71a38fcf07782e1ae0084dc537862fa02e6d66658b19d6f71c39cd5dbfac418da1837", + "0xa935af5ed224b9533b41a7e79f872f6851591da9e9d906050ccd1b2c772a1d6d010c5fc7160c4f8cd7d3aa14c3bcdc26", + "0xa81e580fc98692567b28323fc746f70c3139d989fb6aabf3529504d42d0620f05327e3385c2bd5faea010d60dd5c8bdf", + "0xa8b352054cdcde8ddb24989329a249b71498a5593a13edad1e913c795dcad3d24789abca9c7ed1d57efcc9e3156da479", + "0xb0de8a2bd7f93284b2bc700e442f52ada16a22ad8d86329591547411c23fff0333b2ab0c9edf82bf7903ebf69916eed1", + "0x843e9781b653d1a427f3534b2e86add49d308ca247546f9fcf565f9e08df921e4d969e1b8ed83f3f849e98c0f63e39be", + "0x84a4098c5dca9f73e827d44025473096101affd7193c40a0307e3215e850e753e9a08e6e74a442d57626ff26df77faac", + "0xb463eaaa2f3315b511c22a97fad353014d840a6a95fe0d457d0677e63e571407d7f5268f8775381a5e7adc3b4163eb88", + "0xad0417edaa16cfddc288eef4173aa7057ca4f81e815541ac588ef5f24b98d56fed6845deb6ae1a9740a28bb1cd8780a7", + "0x9271963b8fb2288a96e07eac13c0543ec41abdc6d978bd7c44ae08251ea49994412b542c77c8208cd71fd8e7852d4a70", + "0x8b68b6db9044d8bafc155d69e0daba95cd59d6afebb085791e999afed4f33a2479c633d31d534ff767b8cd433d591a23", + "0xa6a06a0e433e385437d9996ce823abda9848754aa9cdd25ec8701af35c9ec15df999825669bbc2e17cedb597a96e8eeb", + "0x94d414bff8b6b8597634b77a77d1060db8e1af0d0ddfb737a9bf1c66c8430e93a425510af2464bce4a7b29bc66cf325b", + "0xb6514049562af1c6fb7d0e8df6987b020f0b7a6e721f4862e36b1ba0e19af19414ede04b346be22d348b50875803d1bf", + "0xa42c7fb34f2fbee8aaccd1d86672d0acdf4e6bb083ff0456512d7e1e43be041cc0924322fcd986e6e1bce5d5ecce6f92", + "0x867cbdd169a52440ae0a75d33a28c7d00aa92b4b65aaac5e62aa53a8fc367c08ab8828cc8fa18b6e7d1f908d158e3382", + "0xa6fe0b768fff3e4a6153e59a7b7508eb2ee8165eaf5274d41ac2812bd4563c4ca2b132f0e27ea2f1c98759cc3589b61c", + "0xb3eb1dba43d10b9e17ffec8def053fc96f9883bacb49330a089a0ca5b9ab0182e8b5111ad4aa55c1ce1b6f4afa5c70a3", + "0xa1531351098bdfcda566ff4d811301c0305626c77f954a38420c490e7c684f517eb1a4e4bd2c3904a10bac889cba314a", + "0x92278d106ad2f27eacdb86bdb1faa0a07a93765bb79dcff191873c52253af83480114b2299ffe5324f9c31d0abbdbbd1", + "0x8900ba95a90c447fb6fa1f528af3d7a378aec25feb0620516b6b97e54b328fc31af42e46a8ad5e6e3029d83a6f2bbe5f", + "0x86053d481179c1ac910d5e7b9a5de82794b442f20e854583512ce1f9c3f09e71d1bf97d6700fe776debfe1527ab97a82", + "0xa32a60de492fc4340336416bccbd2591b5e414fca0aead82281212e24490acc01747537b3da783684e27aeb987245cc8", + "0x9820fe8e0338f21797143f368177e3669a1f3894b40ae9fa3b353125f7c8e85cc424dcf89878f2c7667f65db3b1e4165", + "0x934d64711b4348ac5e1395cc6a3215e5643b540f591380d254165486b0ec2a1d0d21c7d2c6310f9e0eed3d08ecf4b57c", + "0xb9fd32d589432eddcb66dc30ad78981360915854cc44b2afeb826b5d48a08e377dc91be66f5bf1e783d1a8bb320f7ccb", + "0x98c972cf01efff4fc2e485b47572e2d8dde22461d127ef401b71a111b0603203971e3cde40912643affd7341cd27e57a", + "0x8db6c1620760063edabd376f4399b6e1355462e04f5c81cdcb3989fdc00f9a466bc85ed899e886c89c149adad69edbad", + "0xad7b7fda0aa6e2aa66a27235ac5cc680aa04b85dce329fc4be84f75c9c961120a3d9e446aa44539aaac8ea203eecb4eb", + "0x8ccb01eaf41d816ce69ebd57754859e263530915e775c4e7d9dac37b2457a9099b9ae9b4c6cb09eb5ff246e3c9320c59", + "0xb895b83b5f7ca46e02697dbaa6157df6c7571864c83e504a8c77d965bc2ba97bf9353a71c56a020df64498bd40e30b21", + "0x8018c07a81c522fbc25f2cb14f2321c61b98bd8962ed8eb7d5823dbe5d1958a5ec2fb5622fd0868e991bcb6cae016ea1", + "0x95b16364e94d01b3664812264d7185032722a4afc23bdd33bc16ae87ee61816c741657c37138d9312cebfb5fcfbb3b2d", + "0x94a709209990a8b09bfb4b9581ab471aae3a29526eae861108b28edb84aab6d28f1d7a25dddd8150b70af34bee4ca2e4", + "0xae06c80839c5a13269b984ff4d8a5938c6f4d8d647b1b1daa8cf7f6145340b76a286cd615ec251a65501e6290162da50", + "0x875cbd0694eeb90d3567da9dc7f570d97b02bd9cf17bfa011efdd48f1d580608a3213bff4006603b8b4079fa66bded10", + "0xb27f88c455f025e1cd902097d6a224d76bdf9c9195adee30bef4a0b0411fff980787285896e1943a62271d0aca531446", + "0x8024880cde783cdb2b863e3dd856be92bacc5b2a1347e96e039fe34279ce528560d2df7d4d1624a4595dbafb40529697", + "0x8883d02c2a5c0e026d941c785128d4ac6f7a9de625ea735b7d6ff27a5ba10fa4d6370d450d99a855d919f40d64f86afc", + "0xa1beb985c45fdc30ac536f1c385b40b6113ef6fabc2f76d255490fe529468847a776efa674ba8fed72180f07d3f701f1", + "0xab83bd9b007561695210e3276fde72e507456ba277ad4c348a2aec7a6e9ebdc2277cb4bd0bca73bd79bd2240a1fc4456", + "0x8db27f516153812149854fd6bb1250e843a3ae1c9637df818b08bd016a769d0497ab6087fe3b2fd4080882713607bf46", + "0xb3891dde4e00d60386aeff161b4a0fbc30bb31ee7918ce5fc0b49aac3238a000ced192c9c4c08d90de3a0ba973d7cfd6", + "0x90a2049a15c02e59024a7a1cb0adea97501c60b1c7442fbbe560054c3d69264e69627ac57b7d9be01bef498bb2a60198", + "0x87df67a4bd72444b5faa4f3b067204c4927c869dd3b29ad192d859589a9b2c1d6d35ed68310081e140add254a9463092", + "0x8f80986a8dc8a0d6408ebbcb4f234e76413c11cb0d66067f9436bb232373100f20a4fded60f08dec3525315abfaa8523", + "0xb061e10beb12ba3683688a4ae3a91600d14878ef78a308d01b93e4918efc666450e3f7b0e56283468e218934231df98c", + "0x86b9e55f3783d62e381659d3e06699d788b88aab1ff99848db328a83c97d223f602201bf2127c5ecf419752fed0a224d", + "0x858d878e29925c87243e010020007f96fa33264e89c8693af12857b362aee3fac2244057e159651c476ebe1dfbd67bcb", + "0x8fd47cdef87d7a569ffce806d2c2dad100692d6c53e5f5dfc6e274f897dccadcee30fc6c6e61373961bbc1f3ecbfa698", + "0x892f2822daf3df3a759bef03168c1cb07408df62e024747a788e94d2da325f880bb9c6e136c7f6643f45b021c6ccb654", + "0x8714e37ac24f5a198f219e7c88a92172fc3db129e044e914663ac708d8101851e7c53fce79d32d0e6da74f2ccd1d30ff", + "0xae95e1dbba8b9e2c8dfbe1c202e9ccfd04fa396470035a699b902fbd86d5e6a31732a7c8cae00b9a4f6e51c8d560c7c3", + "0xb0cd058e77498e860fa20c5f8d9bd09bb249add1badf84ba8d1bd49e704b9b4bcd67a5c3d211840a2c8fefab3fea639b", + "0xb78e468d3a7da0dd481f333ae56534e2ef97587be2e259a458e25aa37952aed1cc5f835640f812d8052f5bada8f57b12", + "0x835de7965c6b26e7ad1b92eb6f0261d1f376fa12d61eb618d9b342b597c9c117a5a8f6a36269aeea88072b4641e6b5bf", + "0xb4d0eb99136b3643468c9c48a20fad62785a60fbdd3c054efac4bd1fa7979b4c9ca6c2c0b18069c0912bea2f19832790", + "0xa00c47315dc0700a850966836a95f3cebfde04dd094bde0742dee77b89a05b5ad655921f86fafd1e902938ff34d4c58d", + "0xab13fa0afaa92229a71ee91efae6d1b15f14b6eacefffb7401d41d0d6db24e24a8dbe8ee19b4680ecb69d2a0cb4e84e7", + "0xaa56c0fb18401210062dbc653df8e3732aa8921a1280e9737e99b26a0100a13a9cba8ad0317a69bba16193362ee0f030", + "0x8b410324a6406b345df0fa25f541ac20b7313fa55832752f70cf4c79f43b0bd3d5b4cdc447e6ba7bca08d0edffa8e29c", + "0x893362241ae412d9e5df46506407595c58ffbd7fb1fdaf0694c3432470599291238997abe118bf7737e56a4f5c9dc292", + "0x921618194a756be81cb49d6357cb392b32cc62d96c8ffb7e16d9659a0f226a0436bd378da7b835054dbe0de2c6372ef2", + "0x94a2904f10994928ff5367b777e1430047736fbece33442cf452018bfdeae62e84cd75cf80f8468285e347d504c94111", + "0xb4b81545b767f380bfe10e0fea9c3cc62ca8db40b43c83ffb245259378731298e3eb6c3bdc3a16932f88f5d8a86edc4d", + "0x936203c2453ff01c6fc635e4d54320d69e60047d805daae3b75633c2259108497b778f011e5a057249f11b2b888ea76c", + "0xb90bf6378d29339443c3f2008b1e2b5f0345f86e393027f14a295e583bf6e6c2b10f54b6dcc42079ff0d356c405b03bb", + "0x916913f550d327de2d8d6c7723dcef2e3869efaf95fd963d95c8980b97748c61ad8e2e629cead8577266d93fe39203bd", + "0xa033c6f3d5ecbabeb83eb363e54e5faa7ed2d7f4fb771b161762c4f003eac4e1afb236806b784baf2222cad54e2d3cd9", + "0xab289d4a5771147e6c29ff9ac2bf65d70081ea6c6af2d9b728c3c144574a31b5fd8632af57c18c389aa2cd994938bb0b", + "0x9488da2019ff13e290eeac132b491df58b5b7b23c2898ff1a67bffd7e9c9464c39bc8177a57950fd28589e3d9ff9c6c4", + "0xa5abe42b2e0891851440fb2aa6c1d8a86b571bce8b80c8e9e2692e5cb6d45a1b2f055c9fc4c74a7cd292871604129ea9", + "0x90bfef698e83c2ba4dc9304aa01edd274169a978b7154bca518daef394f55857d0d1922ebef3d91fc5ecb3b895d9e0ec", + "0x92328f1372b6406ec80786041b6d57018b8507e3881a08727aadfecfdfcfb0824394cbb1150117ac5da5d71b89e895ae", + "0x9719751c5f7a65ae2bed8aff7b4b8c34539ff011b259b7ff54f63f9d987b3fbdce5c99534ed561aadaf07bb6e939e208", + "0xa151816774aa9379fccec21cf212429a1c68cf91b055cbb9d931f461a8d5616c693331a11ac5c6fcfbd17d84ee0b44e4", + "0xa72977b1285618a45943ad00f33f37102e2885eccd2f76785254eeca495068fb1d8d49865343e9e8313c6c2c3b2024da", + "0xa6f5ad2e023a1585d90625c9f7094f0e8851c79f0eede8ec582ee8e063407cc5b8298e5fdc4c786e4fbbcecaf33e787e", + "0x82901e008febcea0c0a14ae21d985a397630e18ee6e346f4a449f23be228e8f338df567d30211a11180b94fbc5204bec", + "0xb9b57fdb8d14d1be87a25f89553b3966eb7869e0519ffdf4cc4d51f4cec90d68f7b81cdc0450e04207276e9c63ace721", + "0xa06eabcf43585a001448f3dc30411f3d5b74fd0a695c81eda9981842ba2bb0081d3f5a8360aa18b6d43ef13ea78b293d", + "0x926fe48a7e8f07559b7237beff9504476dd97b5b4d67acd01a3633358a6ba4c7abed5c87683a11209aa2ee759888e00e", + "0xa716cd3a84a963e2a5a46145b6ef4ebce705de52bf2945c374152a1e41c228a9c4eae0b6d1e222c1eea8b9c13c002177", + "0x8a9b5985df6fb32cdb06ba1591a977545444478f2fe985ed1b10de61c630f0a4693c2185d63f0dc0256b208072c43b17", + "0xa8eab26ae0ebcdf96a59fad1dc2d5e83b94abb2ea1774b607023f9d9e0fe065853b1e2242e794f989a80a47f550c0bd9", + "0x84adbf38164cd04f3d770a7f4b8eae7a5d25b4a803fb63c02b95b71b33e454319c44e07a760d22bf5f58e7e372d09a16", + "0x90f443a3ba1b9129a0bee400b5b29d42e50bb2aa56b0022bbfc3c6f8d69db40299871ec7c1b68421cc89e1af6b13a39a", + "0x81c5a94b379eb98c494a8d0067c748ba47e87a2ada0105202ed7651eb4e5111a0cd8569b06ae68d392c4fd74a37833d2", + "0x8f92324b14a1549ee0b186073a26691088e41556d33b54258fc6e0b000e9624156db4e97861a0ec22960e6c47ca8a1dd", + "0x8b021cd0fffe055068cc460aec3cc455952e2ac32be5fa060e0d1b6cf30ed15381618f801249e893b1b9f10dd82077b0", + "0xb3e9f0dcb3d6f0b138f589fa54dfb01f849890ab97016372d004aac55103f363a64bc0e606ddf75430f1534a30fc522d", + "0x8fdfe64af891db89b25daa859864d479cb7599486bd6f36e593f8f2f839f942261ffc3eed5001a93fde44cbcdc24c583", + "0xa9e4554373c5073e135874e2bacbee69c65308eb0785532fec6a37834e8d0b437b77a2f11cc63c87d7183b82cd9b6bc9", + "0xb4c47daca723ad7193ac5098cad4dcab654186ec5ea5c0fd014a3ac39726be954565a901694ba211820c011fa1c59e18", + "0x8835427e86cdceb4c11cbea331ed724e4e78af15e3bab5be54f6b926bf66b5d99bcc40dbc456d86342c9fa83a033c2d5", + "0x8ea84590a400cedba047c2661378921a42f5ca0421da58c1bcb37bc686a2aed98afab3fa5e6ba3a51029390ef3cdf4d4", + "0xb48551170fc479d69fffb00fae4fba301e92e37cae08f596db6f6489c3b7020edc074f9e8d7465b84e9dcef1b6b3aecc", + "0xa6f318b1eaab00836a330710e88bfe400395b3081485f6a212e3cba9463f6fe7864ba4f71e57a411ecdf2bcb4d189f96", + "0x848d5137a39999141a79f4bdf91150796ba36352d8525821bf3bd6e070b352792d79147341b8254dd60fa8c36e9e2618", + "0xa8526f8904b1eac4ae2a25534aa91e8031e9aac7b8f58d8f49897e920c36c0232f4a30aa6eed305deb0f7793c115b267", + "0xb8b6a727c44c37a8388383e959d195d1d0e51a657d4ba360633d219d43c5df645383e2406c25f1d418e72b862c3a6e9b", + "0x92e64adf65b42c978f36dd03ab22ba983bfbb61944efccdb45b337ceb486beda99818bf20d32a545503c4572bb0a4983", + "0x9653bb83df66260a0bd059cd4244ef7c661b089e403d26ba777d2090783ff31f963f5d3a9c125b1ad1a1d19134f3fc8d", + "0xa74e72355e71ae5eb36dc75191643500ca3e67f18833ee981010e7e7e60a68e1b01b05901eff05014b9ef29aa4829f45", + "0x8b2139a5da14524cf6acc593144db23db424b95b8c7041d8f6c7a14a6725dda1cd09c42bb3ae26a5a3650affaa742800", + "0xa60ddff4300ca44a7c7a00a1f98441ad1438e07c30275bc46551cee1b681926d2c825cc8f90399ee5f36bb9fbd07d3dd", + "0xa04e5e9958867a5acc15fdea0d88951cfebd37c657102f6ba1dcdaa5e46cf1c823ad0d98718e88e436f260b770599102", + "0x95e977abeb70d46fe8d7584204770f14c856a77680607304ce58077550152733758e7a8b98b11b378540542b1175fecd", + "0x8c9ec93ed35a25ce00d61609e92d567459a45e39922ccd1c64ab512e292787125bd4164c00af4cf89fd3cf9deddcd8bb", + "0x819819ad0338250d9c89aceda9e217df12ac54e940c77fb8420575caa3fa78930689d0377ba88f16d38179a807135dc6", + "0x8baafb379d4150ac382b14a64788d819146480d7a1dccd3deef6889686ded375900f5df069843ef14d754ad3d7540401", + "0xab827236996bb79b447714c6993af941c5ae66248df4d9a6f3650d44b853badb5c0cb67804210e07a7b9d66ca43092f6", + "0x927656c3eac8d2eb575e3daeb77f9605771170c325bee6aeade10c083d42bd8dcbf3bcc3d929ea437001c7cf9a95e2da", + "0xaf22b212d5ee44fd4197966b9690487c38a119cd6536cfb8c181f38a94610dd9e057f95774047a446504dd96dd11e326", + "0xa44bd94b9e01e3ba36340f2ac2201ecb477495d4f1fb6726a6b439302deabb5a35d237c6a6aeb7e3b0a65649f8656716", + "0xaf367aeeae3bba14fbdb05bcc1a521000dd9d37f5c34ae56fb306d3dfda201d0329a8b6e89d98e15825cb3c6bfdb1194", + "0xabcc4fbdea43e50ded9e2fb01464f4e87fb136e960141e8d39214f92794cfab5634f22cd40b18d8c0e501f2307aad23e", + "0x920786cbd674348b9853689915dfcab02cce2a4596d117962bce36aadddf4bdd143891e22f2c8015517039a64e8aede3", + "0x8cde63b9bd57cb3ef743f1f3e8250669eed739e5fbd68c500a3cc0c12f93862a69aebcdbc69dd8f476c2eb307f572a53", + "0xb967e65a5f1cd8d5d570f5e87e7e186fba51b9504f8e466392a76d8a971fb91fd9b7565bcc1647f50d7d15e48b93bc95", + "0x8d5a87b25fedf5edd57d870304bfd9081dc78c3e3e3b38b997260a92edac7feccdaf24feb51822d2edc223b70bb4ed5f", + "0xb6cd5d340a57f8ec73723c4f3ecd6601620dc8137a3e75a5d3c578bc79a9cae86b379950c644dee2ff99dad780d025c1", + "0xb6f0a8e754b7f52a85a2a2e6512cfd017f7fb0418d19bb318308951c4e242d3c65bbcb9748da9cbc91a738f9ca577332", + "0xa89dcf7d410bccec385400dd96b1cc6af89026a431d0f531aa992cbd7bc8bfd7c5f360bcb665bda1d72efa17bb982551", + "0x97788e7522427a46c4b6258d15623ef7a565712812fa80d001e1de8dc1791392702f3fa3cce5a8cd1c5755625a0ad10a", + "0xb5338fb5e137ff625b27c5148298f27ce8f493e2527c5d0facaa49f29cae34580d0d6c3c1074a2e46cd8db3f56004ea9", + "0x8962f006d7b1095dd0dd132ffe7e87e328510c95ad893cf3b2ab21c177c5cf2c27f47d8856f87e9762c547be009d25c0", + "0x87fee9ce9c26aa476e67e0791a809e0a06a8a98facf3faea730d438d3e516cdf75d645fa75c906e4e44ab9237a22c016", + "0xb75ab972e1a1214bab0b38cc3e973d44bb233acda5b4291f5e110b6fb78fdcab93dc63f01168debd898e165f615be1f7", + "0xb5a0fb52bca279d3853761a94b206acaf313df33ae6303d9b71edae90b66fc507adbc60fb11e758888736c81d5d80c0a", + "0x849b8f0005010e684701cd3a4e59e8c89e5fec59af6d2de5b6332cde03b865ea84f07f0b80ec3404380b0e148fbd2c24", + "0x96e2b0b6fe78408f9208f809f5c40398100b2dac202c8c5c33c2189560dea868270a598c419871a5a2b67783354f6014", + "0xb234b81f996142d0df2c719760bf996544820a03195a6dc0ff6a72543692f5a369bf63d1f0b477ef2fe7b3234e41f685", + "0xb85e39bcf40da1a12a535740176f4de749a93824079deb5fdaa004f3282fdefaf5275e3418c88c419bd42a3dd2ed2b3b", + "0xa27279304b89a18a4e2b443246f2368fb8b15f46a34533179b6bd2ef683f6e98e222b7a32880b39b8fac1afa90133803", + "0x8923c22cf15c9c1964213d725b337ece9ea854775a06f75f232c4859c7142a3942f418354e33066298aedfba3cb27e62", + "0xb109f714311fb9bc431ef57911e2cad6a3949455b9f23255cd7edea35be629e07f845fe53e2b12a32305ee2f4f264f27", + "0xb51e82ae5c7d48050e405897d0053e9ea4b2714d002e88f78c9a307cd50b9c6b3ee7cb86f86527be9d964b01895fab20", + "0x90db256931c7f98bcf3bffff4d496739185e7a20f329ee7bffd4e0850a37739948ec745285703967f4ca50ec370cf68b", + "0xa0485ac0445d88dafac56bfba2563b020cfc370f54c1606c89d12cfd8a4d1336d2ba50306e476155a6f5b0e0a1f2d092", + "0xa00754c3462e74bda928da855bbf90f9077db395e32f03cce9b2955546d900b72330d247b7d607b65e130f5b0d883de0", + "0x8547d56727c3ad8b5c8ce622ed9ad86fe8cd78e6e4848c9845914b5063b17330bd10b46d8d3f18f83ca09ecb28d1afb2", + "0x95b937b2a979bce0e159ac75c7d5d659be8599c92305e73e942aab414793364a3ec28c7c1c8491a5750ba84a29828d8d", + "0xb011e150f0294e45a0f4c69409999d0c2e602449dbd67ab95e8258466687cd733a0329083a31b03722f4e2580ddc95e9", + "0x924651a733ad5e5d9adadad3ea6a6babb8e455c8d5f2cb5bdc83fa422e7752592190ccedaa827b866861e73506a6968e", + "0xa4d5180122f8e31503ae027e54da50f72f5cfb910a6f7309bd882b5cd666f454672591f1f20e461e182a47d03b47052a", + "0xab19ae659c4f73ea3d21895269dbec583c7029955a36469124ebe295027010faab56c4a475973497f28e9a77c03b8fd0", + "0xae7ea1a803d0f439e91494f8f35fc1167dae23834c0c699ffe65d3da8b09f8df5a53195a99ca7b8558242279e69578fa", + "0xb9d63cf0e30f9800101b43b980bcd2f229758e74b21ad5354866b4e684791c08a184330dc316228a0d67fe0210f2bc4d", + "0x8c41629744391ddb96dcbbf9cd99b13d36e57d65962e0aeb92ebccf1c4cc769626feb3ec0363def08eceb102b3dd4ad6", + "0xb2848ff24faf9e667a8c19d050a93896e9e75b86595f7b762c7c74ccdfb9db126ae094961fee7f5d1192776c1ac1a524", + "0xaf013bc29206743ce934d5887b8d0fb3667c89bda465d2321835a3618513fba6a459dd7566268220ffce7e0c97e22b2c", + "0x8bb799e36db1132da8e8b028ea8487dd3266b4628c56dfae4ea275f3c47c78e3d7445ab8d0aaee4cbf42148b3a148175", + "0xae2b81fd47c038b5195a52ab8431f0d3cab4cf24c4237252d955aad2156adc16dda9d3270157e0bfe5a44022e5c051ef", + "0x8e0129213b1698d2ec6df132356805a8633ba79e672e586dfef664ffccca71834253ba14f296da962651fcba2c002622", + "0xa1ae30b500ae77cd9bbb803d737b4a5991cc780618ac22b5cc179efd8fe10afb8c135457f2e7b86ded485ea12eae70e5", + "0x8a39723077b7c0df6e3bf6548afa3910c214ee275951fbe5155a39473be98099626ea14d844630a6fa90292b9594665d", + "0xa628386c79b61aa7314b01d9814aeec20c2a66e3deda322a39957e7135c2e52b1da486d1b9cd61c87afb22c1d10f6462", + "0x97867f469b01249820aadd9a54e12d4fdadd4555f2d530450e1f8f6d2dae57360578e2c2c8ba41e3b5950df596537a98", + "0x97f192d0457c217affa5a24267dd16cb4c01de8fefde9df4884e1906d2f22e73382dcee6c7d910bf6430bb03f4a4f1e1", + "0x86d5b5739de8442dc74d0d8dc78e49210fe11bf8c6ff0f0faecbc47b64812d6b28c8afddf6d9c0212f1988451d6ccb1c", + "0x8ff3312ce9693cd4a9f4b8e75bd805f65b0790ee43fd9e075fe4cebc87185bdf161335049819f22530f54fed2779a5b9", + "0x8dc41d85548bee5d51941d55752a500bde3c5a8f3b362da4eec307a963968e26605048a111c9166d448b8dddf6f53892", + "0x996bdfd004b534151e309ac925fa5ee7801c9da4f6b4c43e156d1158b134535a2a3956e1255e0dd72ac2af6bddaebcaf", + "0xaead652704b788bf4983c8f725c644c327a6e9f6683215f5c826c09f82fd2e40631791f51d14e6aded91fdc018d45501", + "0x991ffab58a82b98ed8fc7b00c3faca153589fe09cebf6a137ad506387a1ca4dba475b0e4a1b9bdad829f1422facaec39", + "0x9652e6c4ae084221d6bad855ec0bc11b5f855c6efba67f644e0902ab790a98861cecc6ce047c68273c3aa7eeb2f4c7d9", + "0xb88b816507aaeea6dc92b861eabdc96988b74d7883f20a4b30ba249158acaff3c50d261742fc9ad2e9eba888a8d59065", + "0xacd028a51e16c07a10d2073b9d03070457ac5f1246365295a1359d015c460b92b4861125fabe6f114de8197045df408d", + "0x806d3cd9d02d41c49179fe7dac5b05dcfc9a205a283135d4f008d0771c58e6f963d7ad0f6798606edda718eb5c7ff3ed", + "0xb9b71f1657a6b206fc40159a941e127f252a7b324dea864ecd804f48c0ed86da9778a925fb65491204a92bc2a26fef32", + "0x80ed67bd0e74350c875abedc0e07fd42ce7cb926f0f3fb1949c6ac73f2300b5a14a5c6f6ff8aed99d5ea5029bb8e7ae6", + "0x9875f67a7a473714e4dd75ee0c763ddf88101532d9680724b3848fef69e218b04a96b90f88e0f4409aa40b9a21507ecc", + "0xb4a2bb1b421e5243e5e7576a0672dc19f9f70315a03f6411c19f76616ffbb70fc5dc0e57fd4ab85e24ea2261b7ce38ab", + "0x879723002ce43e6c75ba2246f51436efe3376242beff987d025c3c4476495af32d52a54fad5d9ec329a442b93bcff1ce", + "0xa4121efbefd9c3eb143619afa52a916f199c75024908047763b29466cdfc837c2fcc894aca63044c33c41c777e529b5b", + "0x895f637b497a9766714a3d9e3c275a1f0c9ddab105bf4c8b7e663f36cd79492022415bb4938c1a4849bda73106ace77c", + "0xb119acb8b161ce4384a924645a248a656a831af526cd337d97e08405415b9dd22060849c76b88a4785eb5e7214961759", + "0x802e712f4c0a17009c4be6c1e5ba2ca3b82adcb68793ec81f4489b7985babd8a3873d544de63d5e5de0cb4dc5048c030", + "0xab111051e4651b910c68ecfdc33f2d99e7bf4182df68cedbdbbcac219a543e04d93ecb2763fe32b40c095c7ca193c331", + "0x855c73ef6afc6bcaab4c1e6388519fd5cbb682f91995bebd558167715db454f38012291beccea8186a3fb7045c685b67", + "0xa29d02ec6d9baf84c19dfd0eb378307703bfafc0744b73335550f3cd1b647275e70215f02d1f4ab82a5df4d4e12dd938", + "0x91510a45b8a50cac982d2db8faf8318352418c3f1c59bc6bc95eab0089d5d3a3a215533c415380e50b7928b9d388ff89", + "0x8286e7a2751ca4e23ea7a15851ad96d2cadf5b47f39f43165dde40d38ddb33f63a07bc00600c22e41d68a66fd8a0fa51", + "0xa413d4e619b63799dd0f42ac57e99628d338b676d52aec2bb0d1bb39155ad9344b50cdfe1fe643ff041f1bc9e2cec833", + "0x85524e5bb43ae58784d7e0966a664717289e541c8fcaff651541718d79a718f040a70aa8daf735f6635dabfc85c00663", + "0x97f0d48a4028ff4266faf1c6997b6ad27404daa50ca4420c00b90f0b3e2d82ef8134d0a04108a74955e61e8dfeac082c", + "0x8df6145c6cc39034c2f7331d488b8a411931c8faa25d99c5432831292637fd983d4f6b1a6f55522b4a42a462d63c6845", + "0x98c2060f67a916991b391e67fcf23e5f305112807fe95bdddb8ce6c4084126557e4c5f003afb32e30bc6808b30d4b526", + "0x8964246b3c2b8f7312f0a99647c38ef41daf70d2b99b112412356e680185da6810ab8ee0855ad7409d334173bcc4438f", + "0xb56c2c416a7069c14bdb3f2e208c5a6ad5aac1cbe5b1faf99dc89c7141d0259d1c6250be9d9195500c4a41182ad2ec3d", + "0xb7864583a4cae3b1083dcdcff7f123d24a69920a57d6594d0b7219e31bf0e236682442b6499a1f6795cfeb4f5f236695", + "0xa064f94139bf1b70d476bde97099631b1284aa6b4d87f16bfc65c075e58b2f1b3c2d057605259f806e545674a1169881", + "0x80d1bc4acf14c0f487cd57c5d6157b7f38917e93cb660f1c25e474fcdcac3c3dfda50f6bcccfd6676bae25c4b6b5014e", + "0x8ad9a4976c4e3e282843518149fcf5d454240740f4b91466f6310b7216d23d70b9b47c42870293252f29f092f330967a", + "0x914197593d2d99d784c704cad7ecd3f0b9f55dce03fc928d13e1a1034566c4de754f1c2a5ade047b0956415fe40399ec", + "0x8d77f5e29c572ec3c0ca39cbae2072ba4102403265b3d8c347a00386da9c0b8688d6e3280c96037c300d57b3545f3773", + "0xabfdf79d935fd4f06a04938d6580a8cbf9735f0d498f49677f26e73d3b34b7075d525afcb4f14ef1632cb375bef7dd55", + "0xa97a8c446e3edc86efac7bda5e2e5d0158c909552a3bf86151df20ece63b8d18b608f477286fb1c7f05605ab7e6a7c2c", + "0x8618d946c7fd62486551c35486fa466bdfcdc63c941e4cff5a01fbbe566b7ea9dc763cbe73e2acae063060b619a212a9", + "0x8d03ee468070936004b06acf64b868963f721f37faa09887f8a82c155ad5c5732572a6855b531db58af03b1afe034a18", + "0x8d3247f75966ea63935ef6049f7c889c1651374adb446f49499fc9191dbcde7ea33cbc1f1e2d3d1756b6e69870404643", + "0xafc853c3a3facb4ba0267512b8242327cd88007cef3bf549184ee891b5ddc8c27267bae7700758ad5bc32753ebf55dae", + "0x80df863eaea289de5a2101f2288046fdbfaa64f2cf1d6419a0e0eb8c93e3880d3a3fdf4940f7524ea1514eef77fb514e", + "0x8434b5888c2b51d12d57da6fb7392fff29393c2e3bfee8e3f9d395e23ddc016f10ebe3e3182d9584fddbd93a6effcefc", + "0xb78cbb4c9e80e3808c8f006dc3148a59a9cace55bcbb20dd27597557f931e5df7eb3efd18d880fe63466636701a8925e", + "0xacb140e44098414ae513b6ef38480e4f6180c6d5f9d1ca40ae7fbadb8b046829f79c97fe2cc663cbccd5ccf3994180c6", + "0x936cb8dc959e1fc574f6bb31f28b756499532ebb79b2c97ff58b720d1cd50dc24b1c17d3beb853ba76cb8334106ce807", + "0xadda2116d9fab2c214ec10c0b75f7f1d75e0dd01e9c3e295a0a126af0ea2c66373d977f0aefdda2e569c0a25f4921d0e", + "0x89a5cefb80c92dcad7653b1545f11701d6312aef392986835d048f39d5bc062cabc8a9501c5439c2b922efc5f04954d0", + "0xb9acb52747ce7f759b9cdc781f54938968c7eeacb27c1a080474e59394a55ae1d5734caf22d80289d3392aab76441e89", + "0x8564f72ce60f15a4225f1a223d757ebd19300e341fd9c1fe5a8ece8776c69c601938fa2d5c21b0935bd2bb593293272b", + "0xa5567d7b277c4ebf80e09c7e200c20d6cb27acbaa118c66ef71cbccb33ee3ddce0e0f57b77277ae1db9c66ed6e2d8f30", + "0xb82e9c2d8df1cdd3b2417bf316d53e9f3cb58473c4cb5383f521ef53e0af961ef916e4f6557a6d8b4655ec01415231cd", + "0xaa816dfd2814c8a25bd2cbaf66303ee49784df471bac4b3188074ea30816f00f425234454d40d8ad8035aa925d74da36", + "0x9919f384df20faaa2d226b521cab207dd2b62420d25ebbda28c9b2ca76a2a52203b2ad7844c1a25f5c75f005c5a83149", + "0xb24a6aa35c2d0f87e36598b36224c64427cd69642b6f9c1bd478a62c70f8ee69f85028648f6603b4f04fb21355f2afb1", + "0x892e044bdb1276b455eac2204be105e1821f987c2570494b1f32aa09506caba7ed343cd09b1bc126fed5e0fda3d0eaad", + "0xaf0e01a3ad954dc048de18bc46bb1c4971db2467e839698e4dd05cd1adcb9261013fe9fd0cafb946c0b586f6aad86d4e", + "0xac152f0a9ace425378daf02510eb7923ff1ed2c0f8d1deb918e4efb63655de1ba58c96438e9aa23abdf2431dc771370d", + "0xad8c7419c097709347e2394195924e09617b47ac5c7a84aeb9deab8975f22155de0f70cf20d8a976551b14e3a2683a2b", + "0x808f14f67ae801536fb70a5898ab86e50ad35340cffd0648daed2f2c4564c9ad538034b2a179a6a8bfa27e9d93b4cbe0", + "0x80a74ab7ce4769db93cfa695a166db95f0a9c47885ff826ad5d93310f36d6b18b5351c67c858b9837b925e85a1995b63", + "0x95b88c3cdd64401c345828f4e4754b1a88b4875a14c08a668b90acd499b3b858842669ecd73a46c5d9f1de32ec1a0120", + "0x8ddbd770b7b18a5917eb43926fa05004e819f1d1ead05b915269e4a86b53e0633a90559007e59f6705a3769e2126ac56", + "0xab6db5fc220754f19948bef98844e6e38dd623565d1695e1198040c228ac4fd863c1f168cac1d036bbfb718d9d8dd036", + "0x97bef628e977c069e60c395a17740e0e1bc1828f5607ae7f30ce5a0c95f02b53af2ad062700a75212e462aa22c3c5465", + "0xb68d465e04fd17ca98501e61eccb0ce30401855e98046e0c1debba71c2153d6a7a704aa36a6f12454696e78e87181cdc", + "0xa79cfdd048f4181e005bd0fbac0a8424495474956b58ce858d2b700fb0f931c406282bd33bfa25c8991bc528d12a69c1", + "0x843f55fa0a6a0969daf2b48080738f30b269b2e7ec123a799e5b203c0b3b4b956dc95d095bc6550b0013918cdff8a225", + "0xb683cdf2823036827e5b454bfe04af9bec1850d25a7a7a44aee7696b6ff0468b7ed6885a41dde2b8f3ecc4aec880c3d2", + "0x8b500796e82acdc89778e0c0f230f744fb05f762000fee877bcf57e8fb703d212dbc2374887bdc2e7b7a273d83a85798", + "0xac35a8ee87bafecb1a87f15abc7ccf4109aab4ac91d357821e417f9b1474d196c38cc41cd13667f68d1ffab5e79a6e92", + "0xb6e517739390cfed5b395d33b14bce7cd7aaece57fe79a7eb3cbf150dc10765c3ea9fef7976a21a2243687e6eea38ef6", + "0xb53901eeee26692273365b789f2a60afc9b5f0df229c6d21b07016cf4c0e7985beec748aeca52262f68084393ab038e1", + "0xac4804f33d8ba2b4854ca3537bd8bf2dda72d4e94ff7ecaaf9bd3b7f098343d74d765471ef80072ae34f860b052cbfb1", + "0x8c6a30a93f1dde18039bbdd1ef294552bf79856e20bce863e4b8dd72d906be3ff22468ff3610e06b5a7d1745dde7ead9", + "0x88f0607fa3b7cefe20a02115572b16fc3222be86bb19e592c86c48afbe7e0dd523492b0c29a3bceb9a20f5538bc3134c", + "0xa660b801bbddad725975ddf9a8f606f76ecef831f954be224d6178c368e1c72d346f00c4a4c95c289b62d36f2af323cf", + "0xa75b9a6aea9542b698938dcd6cc2f6fe0c43e29f64b2f54aeb05d35fac73d41aa7fd750af4fa9333644aab8db90775b9", + "0x83e1b7129d963d1cd076c3baa5fe422148e939273db173e4d59d1858a7d841eacac7fe817d15ab8f8a493bf46c2045e6", + "0x9060a2e9c24de11f9c70e039b5ffe9e6d32f1ae39f3dda263610df2265d917679e689898e4a8bd84ad34613dca5e3761", + "0xb42fc8b863a2af15e04d1fe6693c09b46007c0b8298973fb4762b45b4590ad7fe0aa758918b2fe5ed1ed0359754fd955", + "0x83e6de7860fb256ecf7b47506a5e557d0fb0aefe57fb513c7dee2bd9604712d08ca26adca7ba9a54b712372a7c585a26", + "0x90586e9cbbf71475ecd3e7b5753b286804dcce61e165502a82b960099e79272de8b7494b8877b54ae838eb5d0f71af2f", + "0xb2e4b0d21208f73b7b75e08df80cde20c4578e117d37092a490af82354e2afd3a7dbab46fa2d12fcb731cdaece69c2ba", + "0xa010961239bb8809fc7fb4aa08fa30d33a130f9f417ee9ea60f587dcc5ef4e1b7abcdcbf8e848ecdcb7972ef6af46e78", + "0x8f511fd58d1e3403a5eefdc0a4ba6b8af848c7efddbf9575ee84449facde05ae9a24aa41a5725416467f6fbd11369c52", + "0xb24ebbd2d4482eb618cea1ac4fbfd9ed8c46c0988a27259300a7ce5ce1bb256aeca0357828cbbc4cf0dfafbf586040e1", + "0xb3ea29e9cca55250e9b7b9bd854edae40f0f0cc65fe478cd468795d1288cc20d7b34ced33bd1356f1f54a4291faa877d", + "0x8a8b20f222d9e65bbde33638033972e7d44c6a310b92a9d9c5273b324c4ad1a94f2a10cbce8300c34dbd9beb618c877d", + "0xb2436a9a647dc3f12c550e4ddc5b010e6f9cb3f3504742d377384b625fc38f5b71710a49fb73ffaf95b9856047c98201", + "0xa13f8b77c70621e421be94c7412454adc1937b9e09845c2853ef72cdbe500e5c1bf08e3c8b8d6b8eff4bce5b8dec9213", + "0xb25de8780c80d779e6c2e3c4e839a5a107d55b9cccc3ad7c575f9fe37ef44b35db4c1b58f6114a5f2f9ca11e1eb9c5fa", + "0x96ba6ad4358c7a645e5edb07d23836cbd35c47d9a66937d09486570e68da3c8f72a578bd2e14188d3acc17e563a652d7", + "0xa7f55989814051fda73f83b5f1a3d5385cd31dc34baf94b37c208b3eaca008ff696fd7f41e2ecffc2dd586de905bf613", + "0x882d0c7c81e58eb9560349f35c35e4498dcde7af7be8d7974b79d262304c26ab67ffa5ed287bb193d5f0ab46b4096015", + "0xa607158f0c1fd0377a8ee5e9715ac230abf97406c19b233d22f5911ebe716967cc10425546dc44e40c38bd6c2b4bca2e", + "0x87e8cde50e5d852d3f073a43d652f7186bac7354612517cfaecd4a1b942f06fef6f14546279c0dc0262e2997b835b2a4", + "0xa1c93acc6db9d5ee426fb4a0b846bb7a7b8d5915bec777a9fe6907246b0beafb8938941c8c79ed6082155f75dbc1e332", + "0xb1e4f61457b86f76cd93eafd7536f72baf239ce5a62bd5a8085a34e90576b1e118e25002d2de49b01d6e9a245ee7d3a2", + "0xa0435fe9a4bd1031ec5973a103ec9396b2ce9fd982f6d9ed780fa80ac06a6e47a0a6eb2daf52df1dc9292db622ee9fa3", + "0xb66d8e8a1717e4bfa42083b6ef4490e090a73168b2912f2111743e089027be0a4945a229ecf5d0b5eec11b23f0e11303", + "0x8eb764f26904eea4f4169be6e75beaa6a39e4eb524625a15a78befe3d8e3cc82692d9b135590c20ed460d6e4ba630ef7", + "0xb7e4aea6bb09829e53fe83e53f49a7a331a6d7bf76e0073d758577e6d6fbe63dab642b23657355cad48896ad8715119c", + "0x8f94207982373a99ffa282673f192aa98d0c4461fb77c31dc4549628bd9687a249f1b3c66b1840929341e42516c5c64a", + "0xa9c673cb247b13e17fa5e616f0399b7f5c7ad043e143e44ae68855a840870ab3d2aad737ebcf74c2cc9688d17ef3a794", + "0xb02635104dd28c02068985256975c0af783899eb996e37d021d9a35238deeea9e836760db21869be7b6c82aa687ded29", + "0xb33bc0966389710812b5f6698afa3e9c84839a1b85492ba11e6ded26695260abf66be6fb355d12d3a8524966f0f89e0f", + "0xa79c0dd09506951c33da3cbc23843fd02d641fc24c640a205e6e8150240372847312b9381fb03c5d301fe4dbee8d0da2", + "0xb74de6f3a2c502b5b658ebe8a9b7edd78afd036f5a2736aa06502863b6865d131b9e3542e72a86fa2e1d2db4927661ed", + "0x99e365def1452ff9fb4b9eccd36ff4154d128469ba5bd73e83ae457ab53977cf6fc04a5d05bdcde357ab539e34bd9fe0", + "0xb4f2bfb95abb47c67870aa6ca38ac8f3ae1b1a2bed064b1be7ff90865ea12e4930fcf66429c7ecd1183fae4a01539386", + "0xae4bde87f36b912e92398bf72e11d5389e93b2de1b277d7ed4b6fb5a9ab9f71a959ec3bcb734c11079440fe42b86fafd", + "0xb826459e568efdeeb66688482b67ef5020787275123fd3192f979b6175e3b0ed59e17cb734a0a052bf13f0afc7bd237c", + "0xa99dd735f4a7c85cb23dcc7f4835f9ab32026886909aaa95876b98029c37dc4d621726c872d3a9e50403443c958f4029", + "0x99083545034768010988bf8a9f34486c2cd9da27a1d10db3ab86eb69a1dd9c8ee723e7da4ef2aced63c1dbd53ccc52cb", + "0x8ac3209349f0142546c714ef7e9d1b094aab5469b8f080c0a37cb0362da5349e108760f272fbba770aa468e48d9a34c4", + "0xaf5f48ed74b21e3f2c1430192adb4b804dc873cd7e8f07130c556c30e7b78df0ef5a14b205368848fa9185e5a68dee0d", + "0xb8b741b65d68df89443523ba74203226f1e0d13bab073d183662d124e83e76cd318b2bfff09879c04d81b577ac895638", + "0x914abe4282d11176d4f2f08c6f15e6c2d0cde1ab4de00bbe888015c205f51929d97296a0a8d3ca5641f085a29ea89505", + "0x83ec306b2a9a6780efafe799df90b1aebdbff7d47921a136ea8a5648b9708a97231245a1082fea38e47ecafbbe000528", + "0x95d6b58d70b388dfcee4eda0c9805362ccfb60a87603add565b175b2c14ed92999dfdb0d3724ee3e5d30535f282641e9", + "0x97eeb4de607c8306e1d4e494f0d5db126d53fd04983ab5674ec5996b971899e734fa4011f2c889da21154ea1e76dbd2f", + "0x84ff21977fbd873ea06bec444d4ec9ff0e3902edc29dfa25f3bed269b3709e3116e99dc06cc3e77f53c53b736bf8fc29", + "0x8ecf483874a040a4a1c293af145094fedf203a5eb37c3e165857e108cce3e1210e0bfc0f26f4ae5e2194024929ba034d", + "0x97d9b92b2ef34609d69402167f81bce225ed3a95718a3b403f702b93e96a121a8f7f072d0ff47e8b25164e204d1576bf", + "0xab87c39cca1803b4e84b32e40ff30289e3cbbcfbe16a70f9e025643824752359be1f10c3e5398df402b6fec64d5a3537", + "0xaf84ca57e6944332884b5c84750afe0d5950015e127acec161853d55d48fd864c7da8d59cc5aba4ceceac650b813fcc0", + "0xb1d23d98edbe7089ce0a8432e0eb3b427c350fb4bb39eb2aca3c2bef68c432078cb9b4b2c4966255e00e734fa616638b", + "0x8e2b5252e0ea96d40835ebfb5693af49946509975682d68651396d6bb1463f09e75fd0afa04ccea49893b5b9c3e77e40", + "0x8db25e762f1d4a89a9a1cbc61c01698e775906bc88a921b2905735457a35df9ab84bae12e1b1b8dafadd50212f1acda1", + "0xb5f7cd163a801770a4034e2b837e00191b0ac63a2b91032ae9a99ec182d748798df48a14644935fabdbac9a43a26749a", + "0x998e7232e5906843d6272d4e04f3f00ca41a57e6dcc393c68b5b5899e6d3f23001913a24383ed00955d5ec823dbd3844", + "0xab2110a5174ae55ebb0a788f753597bd060ee8d6beafc5f7ce25046ea036dba939d67104bba91103d7838b50e36703d1", + "0xa211972a4f6a0303bec6c86f5c23c0d25ab4df0ba25876cbaad66ae010b5a00aa0c5daded85e4326261a17a563508a25", + "0xa49f53496a4041a01e07f2c2cf1e84e2ee726917bb103fd267451b9b7bb1331c0afde85a79a55409bfde27328b2a4745", + "0x934e915c67c7fc47adeabdde49f63f04644fe234672003be2aa0a2454dc8d9288f94293478936a450f2e3f249d395b5b", + "0xb6e69e9d6808ff7f60a01b7aea6781495d7a20f5b547852d3f0af727a7434209d3015a9dd04cbe3e272918e32e345508", + "0xb348d3462092b5c6fead7e515e09611438db8d69650876dd3b56226e303252bbeb9e9f3b888fb911445b0c87132a1d0e", + "0x8d6510334a905efe5a32001e167f1ba06f9bc4af7ffbf11b7f7bf3c0076b5cca373d8c47e98c1ba8755bb22632bfe0e7", + "0xa2d5200f20985dcd473d119ee97e1c0fafafa0f191185bfed9cac429cef8198d17665dac4f70342eea66e6e4a7370d58", + "0x8dd7eb6b1841b3f33425a158d33a172b79b2dc8a01378e4174e67a1a4c8f4b887f02c7c3a8f354ed9eac718155bcdf37", + "0xb16ca19388642f71afcd9f7007b490d82f83210ac1a989da9d4bf4c419de07af8c048cd301ec7e01b9d06abda7c169d5", + "0x93cb2d847d1a88de8c1c9d5b3c83efd0b7afb3682942bd2c8ab5ef35b33dc31a097a3e181daab8630d4e840b677216dc", + "0xa8b648c769e77a7b41c0c689fe2fba9bc585067e004bcb1732cb7b1618e97b317781c36c23a00680fc780b58c301a789", + "0x918c321100d57712866bdae84edf7e42df30a32853af257e0cb4da028842a43b49e775f3cecb85cd817269c728de7319", + "0xa7b0f6ce42e00c519e69b2c78fd9b75a2e7103e5892d3c1afd70c9b5b9e706180a4bf73dbb2d3eed52bfd521103ec5b3", + "0x90041994af3322b010891356afd8115340bd7fd7ba328716fbc4fe458236c8cad8c7564ae473d6091ec3a54bdab524c0", + "0xacb1ac83809573846231f9be2dc5f3e986cc36dd9574a620b1cced45bad0b11ea957ce8c6cbf964a0af916781c574f05", + "0xac54677dc002698fc4d454c7beb862ad085d0514f92576f3485a44c0cb47afb9db2c085058918a3508f9b3de0137d97c", + "0x8dea56e1bfa150e442f8484b2952b116781d08cfa3072d08657cc09b0217276efc4ab6f5fd726bfd826f6976ced8da29", + "0xa2b09e25baf01d4364b5205fa0c4dea84ef8fe03709113b034f88a0f0a502a81bf92c1d4641e2ac9f3a6f4203d3645ee", + "0xb95fe37aa351b4292691a9c2e547224c37ec2751a31ecce59810cb2ae0993da6fbe5efe0ab82f164462fa3764b6eb20f", + "0xa3498947e91a3a540e86940be664fc82f1e83ff41a0d95eb84b925e820602a41b7393c8b458bd4ebbe574a754586787a", + "0xaa2516d3620c832e5728fefdb1af0be30c871cbad4b166a7a4565af676e73bddc2f2f51acc603b3a022056daad2b330e", + "0xa9251b56467fb55f64c70729e2ec77a59d7eac79cc0b4b25ee405ac02aea46bf1cbc858bc773934a6d9bea57cb528185", + "0xae8c0a4ca7ba6bdca8764bac98df0581f00358db904e57867e6ffdf15542e55f7bad2dedac152ef88038b466ed901934", + "0xb0881e27e52cc6a57c4f3f278dffc7f63a9174b68bc867c16d8a151d9cc4d0aeb703d1074d1927faa9ffb43e10912c9a", + "0xb67138465d6654ded486d18e682f11a238d6a65d90f23d6b13eb6a1b7471efbac9ada6345dfb13e5432196d2a256829a", + "0x944c69a6f1126edd38f6eef60b8a5bd17147ab511e44e8e0a442e87244d8f35236ee0b8d3dac0631f8598f16486a5f74", + "0x995679dbe03dec775da26708cb9200dabcad983825f1ba601eb9395f9da350ca71e8af61dbff4c668fd0eebac7e4e356", + "0x89de362f02dc14de6995d43cdea3c854a0986c605ba5eb5dacf24e3a85983229bc99a2fcf50aba3df59f0fb20daffe29", + "0x84607f0e2d078df22d0866285614f5d78cf7697c94a7d1b5e02b770101ceecbfd53806b377b124a7320d9fed65000b97", + "0x93e3faab60050dac76ab44a29bcd521813e76ec8e4ae22712d77bb489bb49f98f9087acfd6a77016a09a42ddedab2d73", + "0xb7d64a7a35f21747b8e6a874be31ba770c0d13cbd41448411994e8cebb59591295a26bacbf74ee91e248a5b111aacca0", + "0x8dcad429a2b0d66b9eb8c1c3924d7a72979727db6a535526a3518bed2a9532d12aad1c5a778824ca4cb98e3e513f85f8", + "0x980882895faa347bd2fd1dda7b8ee7ed49e69843afe646f677b371eecc7a10e0f4e40bb55f28995a40080df471876816", + "0x89e8e7fb51df79971e2f7bf65783614abbb0d7f3f1b4a15d3f0d160deafa7ed1c446d9a5ae1a77160d4dd94ceed8af13", + "0x93fda8d350392e9c4d4ffe6534f7e7be53f32483d9319093e8436fbb8166a3c01085dc858373e65c7f4d014e0dc2bab7", + "0x897521a87b7ebf7152de5260c0875e3c7df1c53e734c672569219ee6f9bd196c5ecef159b6a1d3b7cd95e91b9b8803ff", + "0xb59affa408a0f7bd7930fa3b88750fd043ce672c10a3adeba95a12f23f0dda1793f761a86f7409ce1e6fd3b3b7195381", + "0xb4422ccc12f4fe99c530cda610053af9ffe635b633d52492fd81271d1f6f91b87171d572d5bd0e46ff63e221fb2fc4a5", + "0xa4542cdf3346ee0867c08d630c2aefc57442f1c05c0eba52d223bfdca5e9d0bb80775cff6ce2e28aa2730231fd7b1bb1", + "0xa7d297bb09118b914d286e5d1e87bdf13f7d174b988e38fb5427902e8e8c674072f36b19055a1070abcf357f8668f35b", + "0x9213b0ae24b7cb43ae95e25c09fead8bdbac55141694137d67eb5eab5e90a348a13d4d4d2cbc6436fc4f4f9f7334ced2", + "0x8aed71a0d116d832a372b42a0bb92a1980f3edf8189bdbaed7cde89fc0418b3ab21a04f5c6e1d3b8edf73f1f62bd6b15", + "0xa6c47d77d714c285c84c6b9458cbec5e3b191c0502dffd10ce049cf1ea27ddf868ef0cff13a2377289fa6c932b8e4f28", + "0x92f45622ec02483f2c1e07075a6695416d3768c8984856f284f40734346d56cb5b3322f20c2c9f0ef8e58ddc294a309a", + "0xaf6450d02b79ac9fc79f35655b58fd3619cd5d38c5317564b453f5f2d79d7a030bf767e399fe01b658a72fbd2cac2356", + "0xa3c01fed5240eb8a61ffa8ff4a120dbcebb53b8e19845949c77fb4f9b2c3dd52c7001df6219ad2f76c785a4ee0f64a2a", + "0xaf3136bfe8f774187bdf87555a1ac505322a956229a285d28bab1c88d4f4d12245af8dff35914a62e90e49f3dce6acb0", + "0xb20e21d28444fc96737958cd951858fda324b924b4d3d08932540fd4b87150f053db6985b96903906ce83dde0578cbb2", + "0xb7978101071268d1f485134b4dfd1e35f89b82c7d99ae91f58b6745f5e0273b7e06f3b23009033ecc3e41b2e9e85219b", + "0x9104b7d75245b784187175912cc0ad869e12f1983b98e052710fb33663224362bffd69ceed43e7d4ad7f998c0a699eb7", + "0xa7624cd71b92699ce3fde0e747976ee04ee820032ac45dd27d769edf3b3379a4b8db358e50c9d057c63b5a9b13d76bcd", + "0x9354a76f294005de8c59db10e638ae6e8c6d6b86a699d8da93143da8478d36116211c788d8285d8e01ea6647dfcaa1aa", + "0xb85935c04cae14af9848db5339ab6420122c041075ec1549314e3c9c5a610d9b794ea3617c50ca7af6b4aec8b06bc7dd", + "0xad6835a62311c84b30ce90e86c91c0f31c4a44bf0a1db65bf331b7cf530cca0488efaac009ab9ed14c1d487da9e88feb", + "0x80339f0245cc37a42bd14cd58d2a8d50c554364d3a8485d0520ea6d2c83db3597bf51a858b10c838bfc8b6bc35619638", + "0xb370420ac1a011f6d8f930511b788708ccf2fe23ca7b775b65faa5f5a15c112a4667ed6496ae452baf2204e9ce0dbf09", + "0x8ceab3dadca807a1c8de58ac5788313419c37bc89603692c7a4d96e2311b7fe9e813cc691a7e25a242828cdf98f8bbcd", + "0xac1526ebc6bd4ac92ee1b239f915e494d0279fbd065e4cab1f1b8a1663f67daa89560f6c99bbc3e63fa845520316d2e6", + "0x8240ab0bc36a29d43ec3059c7e6355ff39567e135f93b243145d3ada97fd1c970743819e0d58bd5171967daec144e7a1", + "0xa99743192a6f1967511b2d3038cc73edacb7e85f84b2926d8880d932d2fa12f5215592311a7548494b68a87ec70c93eb", + "0x8ffffc31c235997e59ab33c2f79f468399eb52b776fd7968f37a73e41949111957434f2c0a27645ab34c741eb627cd1f", + "0x8949d955309415d6d2cf6ee682ccd0427565142c1bfe43b17c38de05cd7185c48549a35b67665a0380f51aef10b62a8e", + "0x9614f727a9dac8ecd22b5b81b6e14d34f516db23a1a7d81771ddaa11f516ed04d4e78b78fda5dc9c276a55372f44c4d4", + "0xaa85d3ef157407bd8aa74032f66bc375fddaff90c612470b5ff5d93659f8c3523b2d1b6937b3cc4201c2aa339621180e", + "0x86f8fe8bf4c262dc6a04620a848e3844f5e39a2e1700c960f20ee66d4a559a90141ef4e5091d0f32acb1e915af1e0472", + "0xb3af2eb785b00588371beb3b49536b7919a3f2175d4817de5dcbf7fcc20c512852ef0f313327fd0589b10173f77b92e0", + "0x8388703c512eea59190351f3bd2cce83ff8bcb3c5aefc114cccf9e9b3f78200d8034c3ebe60448aaf6c912f0ff8f0cc4", + "0x95d0dbbbf08ec1ed3975fe7dd542be0a05156a2b3db5092825d918a849411ee536ed958201f74a5513e9743674d6658d", + "0x8d1a48802f1a2db247e633ddf61d3ef7a2c062c48dda59bf858916e04f56651a7d51e367d6535964ebf3ae6d2b21b421", + "0x971436871bfe868f25247145a55802945409b3150008535b372c949760d7949dd2fdb40d9b96ae7473bc8f6e9b83ecdb", + "0x8ca431728ac0f156763090828a7b6d860bf591e5b9dd3bb3b7f3ba0ca74191f9710ee55efd32db7d18eab5b479cee8a4", + "0x81e28f1a506e84c2b9aba1df720cb50e0b597b2c22f98acc34e710c934cc6f97dcaf33d589e845c2c1f6d8716d05ccac", + "0x8f43b11d3f00c41d16c9bc9bc0c44227c056bd77de4f1ca9a799418c5601e744f99066bef47da2d9088ae88eb259327c", + "0x8d330aa52744c08ef98cc5599eec8b9b4dd18aa01b803f1d1ca0e29b74f1aa2886ed0224390fc377af25852851fbee03", + "0xa06f5b203b67134c685039ec2bdbcc787353e2575ce73a415db24a517c0c31b59d1de89f12b97cbef0219fb6a1e90a20", + "0x9269a5f49bbb8fec1a387b5d105df88a027de615d5ca6afae20fe89b11746f8d23880db78dac238c955fc8bb3de18046", + "0xaf5074b3bc0656421c314547b45b5abd3045ca1b17f5e34ba39d8c1f7928a55d4ca5ea9c2ab59a55909b25255233e04e", + "0x8e7ee5d733c8e08f3fb7d85f0628de3de6835121672c65374905dc6d19e02fa2df14c13d5e9835dacd609a4df09abd26", + "0xa9b9aaf83d31e879dfb8e73a0708801b4dbdb5d7c8654b27d2c0f5797ebcacc8d00a82143e2060f0917c9d41f1a03de6", + "0x904872aa1c093cb00e1c8e369a3bdae6931c5b1ed705dd3bffba243dc4f42df3e7d7cf70303d513b34d2245743d765cf", + "0x8a4d6b3b1d6afe67383c66693f70b397e510be28e3d97dbc8ec543d699b6cbb0e72eb90a7f65e83cf9f7ef50fb18b128", + "0xa914de13916e6a0dc0e0fefecb3a443cca80d83276513b70c22c6e566a2d41acbd33a0e2836ee09abeffd3a4894e437e", + "0xb9c408f5f05934b0aefab301ba22f8254c5ebbf5405b6aa788f76e4b328c150b395f441e3566015a0deb3eca89afe9ff", + "0x8d32aa2c81b2a8b89f347c2e0b6567b2117ddbb778fda8a3f19004b7f5aa9dd814b9b3ad35f9223715d2447b2d12f159", + "0x8230e8b9c84cada1bf14ea6aa9ecdadd978d893cf5962fee6c7167ed21239210ea491987f2c8f2e8cfea8c140704ca28", + "0xa5d7b6285fea51c6f21d0976a7c3a97baa3d733a201bfaac0994db6c65611d91c5fc0ebc2a7724ee02b371e575573649", + "0xa54f00a9530f6930069f5e3a8b8b1d52ee1def0aad1763e3c609ec07f25410969b43d5943a94c235ed5eb207b33a402e", + "0xa8dc6e96399b81397734c61c3a8154e55a670fa25fa5854b3c66734cbb4ec0d8f6ba650ee3c71da3773ffc9e37abf8bd", + "0x8841fbfae1af4d400d49f74495f864804f043416c09c64705251d021b3ab7881f134a00b0241e61010617d04979d747d", + "0x95acea7ff4861cc969c1d8cc8775c5eae014ad6e2e0e2d0a911dd916c34ae69f53eef779cc24ff1eac18c2b478d3ba2b", + "0xa5dce74abcfb8c68031b47364bd9baf71a91db01e45514ab6216f5eb582ef8fe9b06aaa02f17be8b93392d9b19ab9c06", + "0x89e111169e4ae2f4016c07c574a3bdacd8d2f359561fbbdaa3474de9bc24ef8936784dfe6fe0e29a13cac85a3e622b61", + "0xa4c511af6bdf3892939aab651828259e4ef6ebecfdd503ecc14e61001575b313a89e209cb55a77ec19a64d29ada066ef", + "0x923c62156fbf3a44926ffb5dc71f7cef602dbe941a98c61f019a27a18a50c16b6135b6099fe04a2e1dc88a6cad989fb7", + "0xafb9191c541b61afa0ef14652e563cc5a557842ce2afea13e21507dde0ebbe6da5233af949c998c00865c79bb3d45ec8", + "0x8a1f0ad65cb2b225931f41dc53547d756111ecbf5bc57c5ee2cc1ffd61b126d0389d311ffe26cf06eaead95af09c5ca3", + "0x9040b20b5ac2e1a9d30abf7a4eea1ec2db8f3077cb2cfc8736b37222d8d3937f5d9f421167086dc5551e9f0bd2522d07", + "0xb6d888b8c6bd448dccaf99c3f690d47f802e134709ce102fb6f6fc68156943c0762be6f386338163e01eed2d1dd5f734", + "0xb94f0e27bbcda793e4a272603b3dcc739d3bf3207798df7319f8dc9d37cbd850e3724bdd30498c929debad971950223c", + "0x9769827767be9d7bacba1b687289e0794c6fe630d33c9b607da1f6a65e3f34cb8bd65327d9287c8c5f3c8b5f6d3d133e", + "0xaaac72c993aa2356c9a6a030950441de42b2d746bace29865382f0ef54835bc96958b2f00237d805ee6a69ca82117c1b", + "0xa2b1f027d80c1b0e79bfc7dd252e095b436fba23a97a1b2b16cdd39fd39a49e06a1ca9a1345c4dbb3d601ffa99f42bdc", + "0xb3fa0ad1478ca571e8aa230921f95d81aed7eca00275a51b33aadabd5cb9c530030691d1242a6ff24e2d4cfd72a47203", + "0xa43ed4368e78daad51b9bf1a685b1e1bfe05bed7340d4a00df718133f686690c99198b60031513328fc353c6825a5f2f", + "0x965e145711ecf998b01a18843cbb8db6b91ff46f668229281d4ca52236c4d40804ebc54276e9c168d2a2bfc299bcf397", + "0xae18e6efc6f54c1d9230210ac859c2f19180f31d2e37a94da2983a4264dbb58ad328ab3cbc6884ce4637c8c2390f7fc1", + "0x83a9200486d4d85f5671643b6daf3d0290b2e41520fb7ea7030e7e342d7789023da6a293a3984308b27eb55f879ad99d", + "0xb925fb6ca83479355a44abbcdf182bfac8a3c7cce6cfc7962be277ce34460eb837c561257569be3cb28023208dea80dd", + "0x9583dd991b62ae4bd5f379ccd3cec72cfae1c08137ddfbacc659a9641e7d5a82083de60005f74fc807bd2acd218d0789", + "0xae73bc32e9ff5926e1e06c07a3963080881b976c9875777f8e4cf96af91bf41bdbed4bd77e91253b8ec3c15b4a6d3977", + "0xb2a3ea90aa398717ba7d8c46743e4c487b63c5abb140555d8d20e5115df2f70d3c84a2cb9a5e0536b2d93d24f271b38d", + "0x91d119d3bf1d34cd839eb69c6de998b78482ab66bc93fa97e31fb9592f36cdfcd673f52366f8c8e8877e313b92d4a2ad", + "0xa1907e20120902cf68912cc3046f8806cabbd7673e80218814cb088e080dd93b5dccba395b13e0025f5755c183276c3a", + "0xb2e2011df72504065ec4c12cbc2137b95cfcd1355509671feb7b00dbf7f8d500476a49754cb7fb9219cb5cba7c8afe01", + "0xa48589fb7a74a3dfd782cb3503e6294a81dbb6adb412887569f9408e9079371edbd9822388e0b7ec8d3297ba270f53ef", + "0xa203909bfe196ac65ed3e6800d577b6ca5c8fe1d40f7f925a43852951e38883f2ffd250a9e16fab3ed3dc1249650247b", + "0x997ac293722a8b98f7e819f8e6c2d4c5bd1103b82d489d8b8aabeb905e95450b9b75bd61442cf68cc957212ec1c55617", + "0x9895a3de62395c33509b153b7820bd94fd2b011f0cac135fcf916482f1eda272ecc79f83a61837e99c3a3c4ab2c5c2a2", + "0x98c2ece4d49a64ec8e06407a0585081003bcef88af35210e22eab91169f8f0c044d611494b755e5bd915804b1d857747", + "0x8bc6dd083b36d076ddf0e0bb1bb87cfd059283ddabb3886f02eb7e27f1f0539b2819527b56b5c13436523c4603ac1d12", + "0x85ab8b7a696333c82dd5e179e12b2e127e67d911de609ff9a03cab95cbeedb1f364aa1f2b5e59353e4ba0d177f996151", + "0xa9478e214afa68c395aa2c7daf8ba1627feb71ad6d8bc7339734cdcdd5a42838e032736c28e6251c808d5a4875ef0d06", + "0x8c53f62cf06a35321c8af3871ee4459768d0745ebf48942b9f464206309f42fc7b2c50f196ae1e43b664f0e2e718a23a", + "0x8ba80662f6642d8866e832ec8082a4204ebc993fc304c4b794666856de0407620131a18dc053597bb40a3de0bf8aca22", + "0x8c8fac6b911785d1561a985580c03fb2ebc613ae33e486a92638aa7d4493374118d9a6d9d99121e29c68c3d67ee4e3f3", + "0x90f2c793eee07ad90157040b30558bb3b0164e8ddf856389d6742cf5bd1c712e4c6a8e5678da70a8e9e242ec7864117e", + "0x954abed8f6d58896b7f6438c9780236c1c83b02d60a29fa7361559e619e5bc9d67b3646ee39ffafe2b3019bb3357fb50", + "0xb79874f757a33085e1e751544de8fe3afbea92e0234f9c00254c2b36115a16ee46f085f22aa66e0c9177e5106f51b03b", + "0xaa148b287cf4f60c64f774282b421aae075f0eaa93a45aab4927750f47e2ef0b811d1846bbb15eeb2f293c80a7612e83", + "0xa588d8825e7b0168d45499dcff6faf0dfe1ba4f090fdc7c06d50344960c0121f10ad109b0b9d13b06ef22de5a04eef87", + "0x8f61ec93d14ebfa9c31731f9ef0fb8907505fedc79378e9a3f65c27bed4d74b41e129c97672ce5f567d897befbceec8c", + "0xa008218633f1da10efd01c155f7ed739faec902da6dc48e9f19ccbc8d32bb318d71806285cf2003de2c907bbdd4f8b22", + "0x88ad82c66f7085632d7e348d69da84200c53594553acf5432b50dd1e87f410c802dfea91be3cf804e3117ce13103f23e", + "0x8498dba17de0318af227a3f9ed86df37a5c33f9a538be9823f8dce4efc3579e8296cb3b7200cee7c5e0bfd9da23a4b69", + "0xb3c0342231dffe4c9bc7d9265597bc8cc4a82e2980ac6d1407108db5b00349dc91d5116fab51cf2802d58f05f653861d", + "0xb3f2730455f9bf5a058598bc60f47740117ba51f6a767e1134516a4e42338b513f377027acf8825da5c4d047a62984fd", + "0x816360914fbc9d8b865157bfab07aeb7b90bb5a7c5cd64847b1c3184a52266cd3f8f8f3ef99309ba2edc4622304bacc0", + "0x8fd21b2315b44a52d60b39ebc45970a47b9495f42b88217ae057bebcd3ea0e2476c0c3d13de7f72016ae12ae966a008d", + "0xb62014485bc217a0fe892ef1aef0e59604ad5a868face7a93f77a70ba3d7413443fbe7a44552a784d8eae1acb1d1c52b", + "0xa905822507e431b35f56724f6c8d2e93b0607ed7a4533073a99cce2b7c1c35367382447073a53036dfdb0d04978ccf2a", + "0x81672e39c2b31845142963351de3d9cd04c67c806fdfe77467867463dbbd8a9b0e2400ccc55016e57cbedb02d83a0544", + "0x90919c970ec668de8ec48a2a73bb75cb94f0f8380c79a7909fd8084df61ecd631476ddd474b27103c6817c8f3f260db9", + "0x8fbe37dfb04bf1d3029f8070fd988fc5e4b585e61eab6a8b66caf0ffef979d3ed6a662cd99468ce98ec802e985da5fad", + "0x950939aabb90b57a3d667f9820880eb0c4fee5c27fe211ce8ecd34663c21b5543c810b3676111d079ac98644c75ee0ae", + "0xb06201ec3c3cfdaf864a66af128effee8ec42d25f1e173c1edf9207979fa52c871757000c591d71a9b6cde40f5001a06", + "0xa79054e8febd0450c96ac7a5fd6bf419c4b17a5926f3bc23a8616f0cfbc2849d97470174cd1baa7c739b12615334b6b7", + "0x81c7391b2a1844ed26a84f054b5f03865b442b7a8d614cd44805b5705fe6a356ac182b66a3c8d415132e389efac5f6b2", + "0x825af1563d0fe53925ec9ac0df65d8211b333474e59359bf1bde8861eecd03f2ac74534d34b7e61031227c2fa7a74e1e", + "0xb60dd9bf036f1825295cd2014ef1f6d520cf729b4d6cee0b42cb871b60ae539b27c83aa3f96ee3d490ec27ce7e915115", + "0x89ca43d5b7f3622b42df7887572297a7f52d5204d85e2e1ac6e5d7aa7f8aaea5e3a07280477d910db025d17cd2e7373b", + "0xb93a2bc9b1b597f0e514fde76ce5bfb6e61eee39cbf1971ea6db38c3ecb055e7913ec8cd07fb0b0ffae3ca345883101c", + "0x8d45546bc30266b20c6c59fc4339eb633155aa58f115a8f976d13789eaae20a95b064fedead247c46665cc13ba856663", + "0xaa8eacfe00e8a4d9815de3f7619d9c420629ada6489933ca66a571bf6c044d08b391e0d9eec7d1cbebe8def1e7523f1e", + "0xb32fefc59a0d0319ccb1946b351ed70445d78d9fbb536fa710d3162b9659f10288f12d82b32ecc026d55f16cbad55441", + "0x99c7c45c34044c056b24e8f57123ba5e2c2c039e9f038a66899362840cffe021733e078866a8708504cdc35816cb335d", + "0x80def162c134540d5ec071b25ccc3eef4efe158be453af41a310b7916c49ec0ce06bb43dfee96b6d77339e11587de448", + "0xb5f2fa4f68f6a26bcb70d8eab62ad73509c08ee7aa622a14b3d16973ffff508ce6f1aff9ced77b8dcfef7319245cf2de", + "0xb4d0436019e779c789464716e1741c189e8945dab7f3072720bd9aa89882fa5b085a1755c48da21541f3cd70a41b0a71", + "0x931e798ef672e1472f4f84c727a101e70d77b3a9f0c0803a5220958d6bbeb8aeeb56c769ab472a3d6451249a13a3f56e", + "0x918c10a84de268aa8f1ba24b38fe55ff907be07b1e86b4a4adbf305c0d705c1cf5f65ce99e03e11676cedc89f1a4f331", + "0x8e55a8413b823715ccd92daee357cedd797e69a0e78b6fcdacb7318646b9903dfe05e5501f47b3c52e74055b9eb619a4", + "0x8b329bb63e6c985d7d072dff4680b3f8b1217ed20543277386bd30ec25240d9dc378837dcd5cf4fd9548658635f4c537", + "0x8c2be5386052b22986b33dbc63c5afacb6d0095495564ba4aa28fc8c880a3c78242fb083248d788ed928deb1e30a82c2", + "0x83a2b7bdfcbd25d6b059f27218e009ecb5ecc4da68ead885e00216411d8222062ca42f21c4d9cfa19c31522080af677b", + "0x9620334d2633e85646b2e2fc48dc6c3f09c64ef1706ed78a3bb6ce1f6b274a727364df71e97531dfdcb392f70f27f536", + "0xb6c84970ec04545121ec3b79376f4e45053c97e8bf2b11922cc2490a429c38735466097ecb81cc9d9692c74d2fb8abc8", + "0x8e55d707dcf265c5ae29a32c27ce66f200fddb724faa5bbf145ef42280ef645fa2f0cc3cfe2db8599b26c83b91e077df", + "0xb910b96b763966402bbebd68a32c15a225ec21e1357fa298478c5981a4310e556103fef0c73bd8903e11c4ed2c065647", + "0xa8fd933a0e9fe8c459809bd93b8ce153e2af55df94b61a1490736b19c89469954da8b72dbd072d798fc06fc3d7a3d60a", + "0x811b279c113828e114fd82c2070caa7eb089a46c8cabf865f9c77354a77ebebe0c4c6400dda0e66dd017cfc44d76851d", + "0x8ed03e91c331afb3ad6e42767e1b3e8d3a35fb831805ff1b5fd3e91878e04027ff5af1165a3ac295f1578faf2c83b581", + "0x95bf53683d64a0621bf1ca6ee17446783f6c535b7a54d6ea57723487a215759a54f886597a55dfdd560424e368ab2759", + "0xa9bea378768fb1d7ba365a16531c51fc1975f1c73caf2a0891da28509805fa84e2a8db7c6ccfbc620e9002317abf174c", + "0xb8308250891015deaf851c4e5a4cf4704d104f94064418488d7e3076d49f36240dcf6fdcf83f45fe8a1d97fb02e3db59", + "0xadcda6b63da21f4074f142f8e7f3a2274f624c733e3a4001054a1809711529c61356aa087f73aed877a58ccb41d38d12", + "0xb80e7869239ae26d1da2e6683f064d1dc93cf4a2b66e9439b3ad9b25324e969bf98014760d29e6b8de7ff152ef498d0f", + "0x8e9bf968911df3bb5e3a7655e9d8143e91ee87f14464d7ba9c86e1e31b03ab31b91eda121281b79cd974d9ed2657e33e", + "0x9007277e8335a43e6bc3c2f5f98c0ba7024a679b7156aeefe964f1a962e5ac82154ac39d1ffbad85a8f2440f3c1e354b", + "0x9422b9d670e997b7c919a429499f38e863c69c6a4d2bb28d85e36ae0895c620f68b71e39eba785e3d39a45be91507757", + "0x926094e01132938000d82dd9a571fef5ef104cd25b4015a25e3442af0329e585aaad5472f0e7a69899ba2d6f734b40aa", + "0x95552d8057f7e32c24d69e4d6c51c98403f198a20c5be8826254d19cab2f84d5758e2220cea7e38b7c8a7a23178fd564", + "0x8abcf8dcc8488bcc9ab23c51b9e7a0d91dfc7bebe88b7ed370ee68eceba643e939c5eae66a4aa5fe85120751780e351c", + "0xa91bf8198f029e6a4cf6f0cc39b629e9aeff1c77b8739e1d5c73d8c1d3fb5c8f6f23e27b435bf10b5b4ec1cf6a7249ed", + "0xb932d87ee3a4b81341511f90fe5aa36c571e8b914f25abcc33dd40ca67a3f6444fe9362c1434744e4af18d6e045c54a3", + "0xa8e960c2be9b1d805d387b3ebe2134d421a65f1fd4c1b4cccdce78f9926f139eea78e3afb449b3d6dd19b5d16ace48fe", + "0xa7e2f57cce509fe66707eaba9b4c042c1be93fd6034a9b51d1d30c45c4363eac79d54663d525c9873ab0eec0b1cc4ed3", + "0xaa162a31c2078f4b080199debf24494a8dfdfb9d8fc85b198a861b12a629c73128c55a883e4c2de3dfed6e0e1b83eeab", + "0xb5a4d075433eaf4115717a84b4dc37f843d44bba0bf820c92ecdedd5afb61be60f7708c8a151a678d9d5c0ae531bffb7", + "0xb56ab96f7a463c0079e05dc766f3a6a31cae5c5044947734ebe0a26e01367c6763cc8de6c2ee2f3b8218f05bef217474", + "0xb60792ac506b901065a8bc0180a86e028fe34b62ceae1ad640c759538ebf3a2ad9c8c927d662deed6f489ff3ff7813c4", + "0x8c8c2cdf075504d12d441a58542e1f8e4bdf92b3ee4775e836b2734c5ec1e3df919b931386417d04489a1dca806c87d2", + "0x8ed78e91e5c4a68894cefc2f7fa71f02e5e12d40f1bb74332139bc7be4d92c24e07d5ece0e82150ed474aa1337af4c18", + "0x87119c22ff8aa31150bde537d863cad661cc5159b12f084cc319224c533f0deb28526ed8568d00a1441e7d8bb4f05673", + "0x83a60ba5a9cccf22cebadf7318b706c9f29abd25db0e2fc1c802965351b53cbf316df72ee3e9b2d3ae7f3c4494cfdff1", + "0xb73b6a9fdd3e7463fbdaabc9a885b7c82201ad867d1bced1c2484300a01cbbb3f1e21afa95d4c7cbb6cb983416b63b90", + "0xb1d89ad16981ff9217708090d4017662d8838f21f3a3296cffe14590b533905fa06a20e40dd497bd291fa4dfd1bfc511", + "0x8abde560083e071a402e3c7bf31930f537f67d2a7bbc734a7480b1b760aa712ebd1cbcb65b00e11e384e980222fe14a9", + "0x89c731d8f31afea8bdc9c32527bdca257f2a840764d40f6e49403b8e75ae51017d505ea4fff91bf28b6f3a1bc65b8bbc", + "0x80e9ac8e077e86ad050ee73dfce268a69564ff1b8419e9c236d981fe7a5f0c2bc756e8603ec604b3b9e36da8fe10a49c", + "0xb4f1eea0f304898b1323c6382732e6f40e556bfc68af9ce73f6d54e92f5f23cc4f78eb3f43d578d81e7627fb40f092b3", + "0xa0e3a8d1348f8f153e08ac4839232d75d1d6e81b5de184ec4724f8213baf98d3fe739a96f6b39d79a053b628c3a09981", + "0xa6915ba0b52ffe4a381bbb8ff3791d9d3b848bf89b3bacbb2a7d2e5ae21f1353cdc304b3cb6e82416f7e604035c27d7e", + "0xb2c4c9cdfdd2fc9a340ba3ade9423344b9f429e8c7e20a8abbf26400376e312f3ae35d1c456be99dfb5c02fc8a36cbfa", + "0x9657d57ca0641825a0aa5687f3f87659d893f33aee819bafa5b1ca1db554811c1c844f971e278606e3a2f096defdc67c", + "0xa4ad24d0a557704ada24d8e27a15604bca28679e260b2c69ccc8e6cae5499866724b700605a90df7dfb35130756939b9", + "0xb18d9ea6682f73a1f99a9a4fc98c38fcda02c1a18e8c5fc080cf935a2ac877dc5223fca273dcde190b906178d0fd05bc", + "0x8ea5fefad0799c885f50ff10d94bd0af5b99b0a446cd1f367ae5ff529cc47e09f3018115f3c0ccac2fa05bb65b84945e", + "0x92450d52e6c7d13ebfcdf5674d6761bbae2fc5aabc865d35d031b588c383e0a64cf69a73dc93948632e2b98f74a5ed86", + "0xa356f171a98df4ec5a96d556eaccc6ad34b4238aafcf0e94ece27cdbb491749fc9692e78b84dfe80bdef2914079d34b5", + "0xb918703a4d3507d266414712ba8eb7ad17da07cc5f952b5c62ef130cc6ed1ae3bf01237fc8848c179725bdddd465b301", + "0xad2b0554570bfc9d97510cf59bc38e10ca54a93649c30ac9919bd0255e43bf525ab11b74f78a51ac0973cd0c5a5dcb54", + "0xa7ecaf4b631d179d32ac1632390d95196a0035e00da6c0e6e13b5c09ae44b15ae6c21538b5a31b73bc5f650ecd979b59", + "0xa37704eb4d728df2a367e59fcb6c26023136230e37f3b8a2f3ceeb1467f5cd30186fc0116f98b64a8146fd2c5903e8d9", + "0xb09373ce92314678299ae10ec1f93c702911beb4115c6b5ba6efbcab9c7afb599f59793912df70a98868bce6545a33dd", + "0xb52a878a1393094fd2b93f2d1eccabf2830ab10800ba4cc24dcc7849cd0978733263aef2fcb766a7cb575a7a99383db8", + "0x8dac097e006fda4fb9d6d7ae52adabd9448ebc8d5bd5b38ac0c4ed38ceb510763174f7adfb0b473c38e52147ccab4239", + "0x86b19c41efb949937d74a7875549ee5e997f9fdac7f7198085afda233cf74341a38d0ca3767c76cd35f875b89a35f78c", + "0x99f0d927e5ad25cd134f1c70b72631cc6b5cb4ddb86c0642b900464e33d971213a5239dddaf71f7a42f2d6d02a12dcc6", + "0x8355c38806c335d747d4e97f0083fb96585677da18b409a85175ec35dc3f74671817b34203eb18c2f729717ce083ede8", + "0xabb3603adb061a036eae0afa5f23d79c3b62442e0e3bcdeef896f88995585c1105cd3065410368456a4d36b5b0485a83", + "0x9051c5c0011784885187d04749f774b9b4f6bc594b0e4e18226de79dedc4d7aefa3529c3d2c728e180f96f3e204d578b", + "0x91888213e7d321d0bfac884edbd5cb756b280753bb5f8bc6acfc208f525757beca24bdf86fc68d3d8736ef176a960b49", + "0x91258bd7ce6e3b7516fe2f5391a368d826da299e0e99b1f82eaa44b62b110ab696adc92debab8ba098a52f38dfb3c5d8", + "0x96e3907340dffa9da3602d3b94bacff7e1bb8649edd3b9bbd06e1bc6781e78f91ababab12c0b9be7c66dfedc7001b66e", + "0x9513555688fcfb12ba63952ab36a67b36affdd71f7b843e8eb99ccbd45421698024608233efbdc905eaeb26b334b33af", + "0x9913ca9bcf11eeb408da02e4317c5ca0010fb2f4490b282ddb758001c08b438c3b35351a8cbe10b7fffc1293ccd22d4b", + "0x85dc2471860ebca88e5a2766161fdd77f926d2a34825d1134a30418f91a741759668e32fd1e37c415d07ab5824338e8a", + "0x8b128917e828a0b5eb6fa8ed72b52fae2dfaf74febee69a2e2f87e8df702f0c5bc0fb620c8d1d2a07f35a15ec9c0f5a8", + "0x964c39e7840c130b01bb481ae7bfc92682b0f124c9c383f9dbf3027f2249151925f4faf36905af476a54778d69da3f48", + "0x80671ece658cf850e522d46d25678f934ce6df043f25f8707235125765d40c2eaaf39eda6092f75039b22cb58bf2c29d", + "0xad4bb0e79fdaa340b1347a46b0f64e801c72a89770dda0a6e4bfd35f2df5146fce9934e4baecb1c2671077c771eb8089", + "0x80b3bd3adc6cf198fcd997f8867d2839a2eb28f57390352ec423b8a14cc1f2ab21c6e286505d6a21fb134dcd8d8f11cf", + "0xa26d46a6b8a75748895a1d599e7fd120d896340e79813167a400b2fe463452532a4cab419074663fe1d29fa716b76a33", + "0x82b1f3a8a1df29207d7ff020809113ab06080a7f0c631f76ad33f47cdfb6a567143144df97b4ed7f676d929195b04bba", + "0xad96633a3744648ff0a2e4491e8219c9c6ba6e655cb058c36320a8f72cd5f72c00bddf97083d07650ea9ddc005fc1ff4", + "0x91d0783788626c91662359dc3ff36a8bcc6831e3f4114f85c99910256b1d8f88a8612f53c7c417d55581dea486f38926", + "0x84edd9e87ff3d193ebb25f43474c33fe502a1e2100fd3f93fda6520f5e42214cc12e9f8045f99aa2423a0ee35e671854", + "0xb55e06a4b1fc3ff9a5520e0b7c8b5ac11b28385cce78d91ce93b82f1bd7f7afdd4195d0c13a76e80d0ed5a4f12325fa7", + "0xb0b15c7ddede2b81d9c835ecaa887650622e75d0d85f81b8bbec7ef24e9a31a9c9e3de1f382d8c76d878d1b01373f6c8", + "0xb1adb47c20f29784116b80f3670182d01b17612d5d91bd6502b0dcecdcf072541f582aafc5e7dd9a765cad52151684f4", + "0x8efd1018df9c9e9814a9c48f68c168551b999914a6719229f0c5bf0f20a288a2f5ba4a48ba966c5bffb0fbd346a4fcc6", + "0xb34ea2bd3269a4ddb2fbf2514401d2712fc46c22642f3557e3b9c7acbce9b454dcf789573ede9aa14f39605fdd03f8c4", + "0xa9e1428ce24eacfc460aec2e787c053327ba612f50d93510d58b2cb0f13291ca3d16358325ab3e86693fe686e4f526f7", + "0x91eac7361af4c66f725c153da665a3c55aca9ae73ead84ca2662cf736fe6a348a301be1954723206dda4a2120202954b", + "0xa6f02db89739c686407825fa7e84000ceedb9bd943e8a0908fef6f0d35dbc33c336072ba65e33e15ecfcd5714d01c2f0", + "0xa25666faa12e843a80365c0fef7d328a480c6e3cb7f224763c11d8cbabd0e7e91a5b647585ee905cc036afca14842bae", + "0xb4348576439cd2e48c01cb9cded7cc4a0ea364ab936dd679ddc7d58b48807e7fab070f2f1ea88595b11af4500849026a", + "0xa8c6c731e0d0464ef7e4fc1b049065eb4ce100c01e1a376365c636a0b23851022bf55805963bc15eb57434a837e81167", + "0xb0952937b154e3a4c206f96cd96c76ba37624956b0e4d43470bdd97b4af878326b589e3eaee82fc192437123096799a2", + "0x97d07ec31ecc9923192e48d37df2cf08750050fb452dcfbdb350fbc43e146bae3590c5b732b31ebfa1ce5d884ad5ad57", + "0xa69359aebbfe4cbc4d39d178150039fbf284cbc0edc68a6bd635ee3a1c76569a4a575c907fff691b2a4d82a384c2945f", + "0xb321c2c0f6b5902ee9056cce7404d858da9a573d27348c1a6bfea29b2746f2aee7abcb6192504e5a583b0caeaba117d7", + "0xa74e738aa6eb4eea58855ae6f422af22812fb388c83aacca5bd5fa4a88d4c01463174a229aea2830c348dd9ab9307854", + "0x94306a3b106bc1644346bc45c05cdc8287811d5c86cad691bde0c65d6a686eb9c0ce79ad91baa4547e5d058ae8bf7310", + "0xb64140fd77a07633e4ca8d60786452311dcdb8ce7095ba51dad8486f57c3bf4e69bced92603f71da992a48ad817ab275", + "0xaffe7f4310f1dc68e5e3cd640bedf864f51bfb46bb752063bfc18e95930021f784e509261ff9c560f53000c361b142d1", + "0xb0d2fee222c6f963ba3385547f921a48964da031d737892604f8f2677d4905dbf615046db57eae6c6dd756709ae6932a", + "0x81700c66aad7c2e51168e028b0fe086dea75d3b17d93a4dc1f47a6a0f025df0bae1c8c997901837ad859a84197e7bb00", + "0xaa4ac5fdd602f8b79cace18690e67bad557a93d00c0e295074185e8c6b4059a65495d9971685de2fc01d2171ac8b706a", + "0xa8becb3a64fdf35d65d2857898dcf8053b5057a73ab8c5bb5324af1a8015cff47efb85dc3eae7364cd5c850b7962bedf", + "0xb72ea09bd0b72f8cde3466f359ea69b194ede93dced534efba1b9ebc6f3bd53942fe2965e992e82edb6050cac4ed88dd", + "0x85bb8dd7eef023a251fb6f220af54687747f4c91983ff728163c4618ffac40ee6edc29a0aa6d455276bbe017f63757c2", + "0x85a485254a11b4c4a943d9ec509c0dd1cbfc0ff5273a00cf5c9f0babec973efb15348e5d9451b548293d778e3a2b62a5", + "0xb109f3ac809391e772b589c196b013db69a9b2b10ac3898feb70b986973731f30722b573cd0c9324158ec20416825385", + "0x8a4eb579a840d438bed008644f373ea9ba2f28470d50cf1d70af38ba0e17326c948527b1719dd1bd9ac656ebd5aedd10", + "0xa52e9d66ead5ee1e02ce6108e4ded790d8ec83164a0fa275ab1f89a32200726c8e988d66df131df9e62dd80203c13dce", + "0xb541cee9febf15d252475507e11d65c4b7819c26cf6d90352f5e8a8f5c63e254eddf22df0c35a7be5b244233e8e4ee5e", + "0x8153c297772adf4603c39349142f98cc15baeccaeae10c3230ee87d62255f6814d88d6ed208c368d2c02332426589748", + "0x970dc9782f1828474e9fab7dcdec19aa106725465a5844caed948eef5c9e48199c1b6bc1a637ed7864116927e84bc65a", + "0xa975a920624967f4ecc77ea5d9869c434caa64c330024194615a8d0640c5d4d4fb139ea11a0c73a5c6ae6dd3fbf0ab5d", + "0x811f0f9e0c12acfb4b9dca359eaef3bed18083bad96188befc036ad3143b121fff4777ca6dc70a835bbc4921bd25f5ff", + "0x82341c6ebdb97c8b72910da95c7eebccd1308b6a92999886aab552f0642882d5c7cc60931577d200efd6066530c998dd", + "0x860f7162c2f5fd1c0953c6ce75bd8c52eaa48032b914410681b8cc05e00b64130d1f96ec5a52df66a04c78a9f9f42981", + "0x8a578e674875571fe1a0459843495a5ee1d9fb6cd684b244feb9488f999a46f43363938cd0542879ea18ed14fba10a6e", + "0x8df217aba4da6781f0f5139aced472025523ed6e17e504511c04b677ca8197488e237d8bb5dff7b6b3898cd5a6393dd5", + "0xb2c9230ad35d7b471d3aee6f771517cf3145ad26200bd6fe9c7cf28120e2945fed402e212d2330a692f97bb9ac4dcf12", + "0xb78b89e29e8b782603b222cc8724eeb83b2d9d56bc02f59a3c899ab76429dc721358b07dcdaf422f59520b7e7ab4fb55", + "0x82682a5617843c4ac8d4efb4c3ce715c76c1da2c3bab1ede387db503f3489c1bfdfc07d9231d96f955df84fd225bc81b", + "0xb0f53725cc610e78b8e8a4e6823a2ffe44dd15a9a5bc8151ab7a3787ddd97e1d7f2f0e6efd2876e5f96417157143e3bf", + "0x92c5a93233085e2b244519078770c7192af62f3562113abc8902f9d72591eacf52bd15ce78653ab9170d5067606287f8", + "0xa43ef97dcd9b6ad288846bf31fccf78df72f94bc7ad768baf5bf0d5dfa27bd74ffcc6b6c6ed1d1f09e09be3afa5eaedf", + "0x817d43bd684a261fb30f709f7926cc4e1a31fd3a1a5e7e53ba4d664856827b340d7867e23d55617ab3514c8a26a7040d", + "0xa599e22d3286b32fafaaf79bd5b0c5b72f6bf266ec68948478f055391336d756b58f9afea0167b961fd94234989f0f02", + "0xb70db7d8e8356df2e2070f8d658e560081442f3f3b95e20f4bf30106835d76161101163659d5d12cc0f335fb042dc66e", + "0xb8f725b70c957aa3cd6b4bef0d9647393f7c9e0b7343e92439372f0e9aa3ceddd0cb9c30be331742b87c53f2eb030593", + "0xb2fb5e7762f26036e7e966f4454f886758804d1f4c2da17f3d13b0b67ca337f1fd89fd3cc798b07da6e05e8582c9537b", + "0xa377f944dccc300921e238ed67989872338137fe57f04cb5a913c787842e08b8a1adcfb4d2200abdc911fc1c766a7092", + "0xb82e98a606071c2a33f2ad44e7ace6d9471d5434500de8307b5d4e0083e3a5cbc67f0609ca8055f0ea0ee7501b9ed916", + "0x8e58f9a04d33a41ace4944615041662dc35057e645f63e127cf0d70f96ac307d33a62ce98f164d6eed8536c1a747dcbe", + "0xb5b11388071ffbf57ac47fc195736613b964ebb91cc8e2c17b32646f91d64ea506282b881897fca96c317364d3290de2", + "0xa40ee9b7551133856cfb3904837f9949a9558e59a418898affb78adf1500fd6ef6328fc4422161909aea2c79ad08c14b", + "0x81f9eb4ef28aacdb43e11dfc9aa92ba990be4d3c14b484fa677edad3a3fbfeaa859a7f9322b5e95818240d7326215abf", + "0x84939b2b6bc859437d1a7a8d6ec9a357c6b716c4b4cc22abc274af872655940cfc72c99f5d0283d90e05191fcdb1c232", + "0xb78a5b74a90a805410b6225fb9576d6d73752520f25cc3fd1edf8ea9f6559d3080f9acaa2246809b6a66879cd2ae446b", + "0x8d0a92baa88bf38dce5385ccf15d345b28e2e5d0a2d469e689353d80eaed8e8408933816d70ad752f226c59a0d5b5f0c", + "0xa7e15f8a8c1655b7b346c9488cff278c793505379b781b31b273b4bf09b3bdfca1c8ab2334746075d636b2e05859f215", + "0xb70daf14f2adce03c7b92d6aa181f0c507a80a37493d8dd12419d5ed5f943a98099fefb46ac827d6e4efb9b8233c99d6", + "0x8c2480814661744d116fba7355bc6b1914975e44cf0e976d50b6a20092bb1c636b7b44ed3fe8d63b5555ffc89fa759d6", + "0xa6059528a4fed36abb74ab992b22a4f9bf1d05c5de2bfe6837b9af1adfed98bc37ed7481b5a99675d432743021fcfdb3", + "0xb7e19f1b25bc159e5a769811e773c3a8ffe8be8ac77ed0b711540915e5c6e7bafdb407cf9b85c551f67fd621ce8142a5", + "0xa2f66d4f7d16ed3e7ef5fc90b42676c61a98ff18bd26ccce91de03b6a0130c1db17a6bc57be135e410a76d2255b15813", + "0xa139c916927dc3d3fb83598da9217ca64f0ae127215332e9a7ed82be923b89a801c44580d5617297175f9dafb1c4eaf3", + "0xaf08e1e1b04ec95366a12d99c80a9a9ac40ac984a575dd0230cdf4eb346a7686da55ef0a276f3356f814af31f9cbf1aa", + "0x98840aefe287369221c0721cd7c1b15b1d670c3cbbfda191cdb5434bcad757e59c30ec82b2d8c75947405888d44da435", + "0xb7c61c8d42daf2e278a12d8f6eed76090b71c82275f8b33504aba75d95103840e8acd083e97a5a5aa79897876a68940d", + "0xa0264048d2a2061d32eee4f661957ff351e78436bf49ef973c059612874ce9c91970869d011dc13a5b7c754476880a68", + "0x897199a4d8db8aa2db5d9be3d4f4312e41fa0739eb06c62e2e046c4b9be829a447e5d47227e2d96195d3b7b66eb59da6", + "0xb512a9082881f5dc90b02f8bc4f38b133348c2e933813852f6a8e7d8c270c9ce68a5524af7d1d3123e53b2d02a53d465", + "0x80b332469254a96f53c95ec79bb5a8bb1c387d40e58b73d72f84384c696ba0d3c81d6ac90be2979c364c44294e90432e", + "0xab680c2e547ea5cbf95bf813020beb461d50ee4341dea944eb48f6a8584d35682d20186e3b190b849a1ba25625a7f499", + "0x9070581993a0531d6be372d370c2e4ab2ee53f30e04a75ae61ea0fc2c320914506c4d2d4b4487c1f8fa88356fc45c895", + "0x8424303dad6b4051ab633ad27ee51783b2ead61c5a6dae1eb3ed72fc1f36e2a9b1f315504a4bd90f9664091f2f403d4c", + "0x82225611eee626556553b9316dab4043aff241a81826a33aebd9864a91e299b765ba1fb43eea2c2047e6b75b6d7fe3de", + "0x8a3fb221c616ad55c352dd5e0c09ee892022013d6965aef40d4f277a42e9fa01226fe973cb99aaf6ffe4f4f348fb54d1", + "0xb07c07679aa51713e8a7d7bc304dc15ed5664b66bd371877023f3b110b3927e09e259ef22895c4001421a69c6c013cc6", + "0x83556c76bdac0dd8db6da231b863c335be076e7299802eebc259e0818c369f933a4a4b18e2df8ca07e82f60767b462e0", + "0xa516f659b7915d2f7cd0f0f5ea2491b15f0c84dcb191e7671b28adf7cf14a56d42cfc0da94b3c269b45c535f6eeded49", + "0x80d7cc6f26066f753041b17ff1bd27f6d4b5603a43729d33d596e21a67356db84ca9710158089def425f6afaf3207f9e", + "0xb802a47f9009dbd48851209ea1e2739020e717f0ae80671d9f97a0e43de923273f66b7fcc136a064c8467372a5b02d28", + "0xac92fec1864a8a911633f377df87aab56713876316d48240fefeee49ab97f7406c22e70f4938b5912c5c4e766146b7a5", + "0x89224225b9835d04428b0a74edbff53dee2be285ddd1e5a3a8c37307c0500578155f0c4052e4bc8be04c56862fac099d", + "0xb1d3c8492fbf22ea60732745edd3b0163ba5a20d1a3315e3773f2540ee38cf308d42ec72cbb3e3dcea457d1d132c3904", + "0x8bd00e38ec30ee6c44a0e5b222f1f737c9ed2a4bb9225f1741d6334df966318c8a0fd2fbb109557fe8c9479694b8d8dc", + "0xa930ce5454efc0b247dc148aff869963fc5c240241d5590415cbd36634801a04d3873d93635911bb9c0c42ecb005cc63", + "0xb83d4f80e9e0fa47b42175df74935ba8aad2e559b80e84478ab1685bc3eb65d51b93e5738d5ca968cc055ca0c552a03c", + "0xb3ae21258f98051f13af3878b8103bc541fe6f20b1c3f8fb4689ddb8800b3c25cca9b55f0a4104bdf15dc4d5844abb8c", + "0x831ef8684c1cd446c58c59d0152aeade5cc305bca6aa296b92162615f052ba280fe289edd62fda6d9f0667c186445f52", + "0x97bf9659b14f133885916733b7d4ac7e215495953caba970fa259f7bf6b79e661090ec8d79e1c9ce8dfb17e8552f93af", + "0x84d5a89cc2332baaaf3d19627a65f4b107f8dd9228a1434b327732f59883bb54fb8ce60d6acd026ed4b0e94e545d1c33", + "0x8e66cb743f95ca5486400b0d89d02e20b98044be1e3a12983ff9fe086179e5a0ebf4dcd5098703191552e9aa660a6de5", + "0x87b4cfb35bacec805f8148786788db84eb8f4bcecdd0570ecb592c705450ce1a90b6d183d37ef58780ede3995be67497", + "0xa72a4fece5478011973afa543f6d8a8ea06a64b241cf7d8bd81fa3740ac2a4cf10e5120abcc1c1101f94da89507a40ca", + "0x89dc6001a96adcd2679916f43dd19ea00508c8d5dd6b0090eab7982fd2f3571b62f3029588a0649e73f49124525407ea", + "0x8ca75edf1259599e873530eff6151c822a4018e71a340534219ef8641cb6683215891df41d4e3c0ca2560e57a7aa913e", + "0x9282d32f868e5ee6f7fc229dda5b94b603476de30cec0a44a30edf396b52dc0ebd472b8f726d4b67d76179fecc1666a1", + "0xafa24704223707db89690bcf9761f07a093f6009ca9fc945e0a8801fc29f9f51292bf95243e466fe736088af36c55ca6", + "0xb51332508ddd9a2610edd2b0ad120272ca342e96c28baae37a2c4f07e689303a46c237712d07e446b1d67c75aa8ce32f", + "0x9219249f3799dfa4eb4770ee323f821e559e7406bb11b1f1889286221b22c8b40ccacbd9ac50ea3fa9ed754860bc24f0", + "0x993515270c128ede64fe6f06755259105d0ec74947b7eb05924a375fa5c6d14822f3d7d41dd04fa5df8aa2aa205a1dec", + "0xa83be4c2511bae430034ab15b194ac719d7b7041f9c0e321317f513a97db39e97b9ee1df92a1962f265b7a3e98cdd753", + "0x8ac7feaecd26f7b99fda3ed0b8a08bd6dd33ed5ba687c913ec0ffc64bbbefcda6f265072add4d944f2005634601ce68b", + "0xb4e3ac6b09299db9e1a469f3a0b2d8d724ee47a417a517bebc4c2ac3efc5cde086b57b9aa4efccdef2bcf8f456d973f6", + "0x9262a24a84fb7b2a84d700f98dcf3fefab8b47293778c20bfc356860cb84e0bf102bae9facd9986d92d1762e0a955836", + "0x97be2041c42bd25e5eb519279163b0857f8bef627492c27b1182f8bf0033769246be5886422cbd2409c08a2615352465", + "0xb0b87d059a00e3effa2e5e4925da913b245785f2932ac3ed364ad19a064d3561b8aa6afea22c951316074f0df179af36", + "0x891644b7b3321b06a2a40cd96c2b8b29d81cde5b48546483fdda439000982a9cbf1f6333fb6c089d39da6492cdfaefe9", + "0x8da9149b7f4783a24240b7b9c7e6df4abf8d699d3834e31ee591489bf4744141ab199c173db64397c1f9bd5f9c862ca1", + "0x8ad7f9fb2742654aa2964fd468e7645436cefd1308b064fd63fdf0d3adb4caf6cfe5426354f6cc284f208b03d6b2d918", + "0x8435e4668f7aeb027100d21e4e0b6ee22b401d21966a3736b95610de86c7e2f2c9ee5d0f901353675eee5ff458dad69e", + "0x9010895f045538bd11b47bb8996f27198c8d6cffd3220569e6b7407f68f35c47d1efdbcecbf9b5e241c3c2879a4f6936", + "0x92a9aa443b5ee7bf13b6f43f2d8d8db7f6f33fd4073a606ec5772421a55f464831419726130dd97829a7d4bfeb1ab078", + "0x843f3266560be6dcbe0258c3c7d7e332330e10630c069892954290288eda301e247f479505a8a1bf7e59c99ccafd104f", + "0x915bd1dad808f8a568725bd243f80b5476a2999d0ef60ea3ef6e754155bc4121b2b879d01570725b510c5a3f09cd83ef", + "0x97250d781815b1825be192714884630e9f564b9bd737d55b8ac79ab48d0fb3ca53bd21ead7b2fa82a05f24083f25645d", + "0x81e2d52333391ff2faab39611689a62d6ead77039e8703f4e012d53eea17a4d46f2e3342e44b6edbe73a542b461bda45", + "0x89c9f9fd5f638156b018831c1bb70c91215f4a2f5a73c84b1208bdf6ad652a55df7213336ce12bd910a0e1a726474f95", + "0x92bd02984d090ea7e2f3eb7d36d1e7b9d731b6b047e3cdd4af7cc4ee177415fea7a145205e484b366d84191f06af85c9", + "0x85a86fc61d5d916ccbb219db52953e1495230aaaca63237e9165276405f07ad9644e253ae394f1ccdd231944e7143313", + "0xa2ca5b3fbc9f3530f88c0ed7071ec3d89b272174c366eedb5d15d2b648c65d23c0faa4e92c776357e7c6883a0084d03c", + "0xad171f5badcc99c8ffc9d8b707d792046f86cd0aa478e0e2fbb32fe095f96cd134ca548d1f7713057694dc6b26465315", + "0x96bd15d57da9980870fbadc98c68db76824407dff2700c45b859bb70d98374d4a4ba99e3ed0b0c17f480fe08f16c6b8a", + "0x8300bac69ca088c3ff35749b437215e9e35a16393e9dc094f520516ba57a485def7029d30adfc72bca36eeb285c19301", + "0x8a09e20be64f346668fcc7b07fee9c0ea8094c935cbf4f3a4cdbb613d4b936c1edb9256b7c884efb72393d97c0da00e1", + "0xb1f85827ee6f041f93ab174d847a55710824fa131c9ade9561168c3962a25c617475ebc4105eba6e738961a754442bc8", + "0xa131558f92e215969f41b6a57d1e2f424149eea531723821dd4cf8c54325cbe66b002de2c8287de6b41ab4b5c35f060a", + "0x81ba492b8956f73557f361a856c6c884ebb300d828287d5699e22e0cfa75c8e77a61616551d0be5178263898c461d6f7", + "0xb2608f44d3c22fac8e13cb59e4ade8b9a98c4eb1ec0959ea400c97eb937ae3f66837e91917057148befade8389af2f6a", + "0xa6ff0323b5a18a4becb2cc6b376086b47cb2baffbfd1b0f2229ef2286fb4a34c5cd83a5faed5def7bbad519fcab8a856", + "0x857d879cb9eff22501d883071382832730704bfcc5cd5b07cdce7ab8dc41c565a1eb0e7e4befce8e0e03a4975d3f11ef", + "0xa2879a20c0360c516811c490289be7dfbf7dbd41d2f172c9239f99e3d091957e0446854f9d0f753d90384a80feb6fa56", + "0x83518624f33f19f87096a47d7b8e5f2d019b927e935a9021823fac6564c4f2328dcb172e25bb052748191e75ac682bd0", + "0x817ec79132faa4e2950665712b2c503d7fb542aa57b7b36e324f77cda79f8b77bde12314e2df65c5b5296a6bca9bb0b4", + "0xb2abf8fb7c3690816fa133d5b4aa509cd5a6e3257cfeb7513d1408b12371c4d58c44d123ac07360be0d0dd378e5bcf99", + "0xa9fe1e4fb1574c1affac5560939face1af6657f5d6abce08d32fc9d98ef03186dbb2dbb9fd1decd6d8f4e4687afecce9", + "0x89b2f41e51f33c3ca3e44b692e8a6681eb42a7f90b81c9e0a0bc538341df9e2039ee61f26d2ebe9e68df5ed1bccf8cdf", + "0x8b35aa7b1d9e2135b35a1d801f6c9f47c08a80e48603f3850b425f64e7fb9860d1adda04f92a1ba22d00dd0a26e781ca", + "0x960574978cadedbd4cd9f764bee92f94e08b7af65403de36b21bffc9424bcee845b3b028af2e9e545dd77cf1e69a6a7d", + "0x840aa0f34b5b6c39471f54d9e85f1eb946468c4fc01963a9027cd7864df01f73c2e864f1f07aeed4b1b1af72808dfa07", + "0x834464a84a11200e3c60f816044c254a7d9baed64aed45a17325cef7fd62338e0a26da78d199d30ac3411714dc813223", + "0xb4ac6fe2f5059546f4ad9a361426ead33237b6b9030b129bf0122085c85fe4ccb33cf90f5a7f23c5b708a5ac64b487f6", + "0xa12aa9035464795f2a67f3eaba478d5ebc838ed9e997c7dfa241e1ed60a94b367d3f969ccf0ef02028c35215698b309f", + "0xac8d926492ec2bb68c6d8aa9bce49085d3d266f3d5f1f924032b87c42b44e41da7c047eeb01e4618f9d0f123dcaa537d", + "0xa5142425825d813ed8ce1849d81aa40b11f1cc3daa89a9f798dd83065c74820b4da6122b3308f528b074531df66e1a5e", + "0x87ff55c9f5aae079e7bf24084dd9c6b3bc260727d942d79cbe8dc13341d98525b4ece3ed8169994b56a387642f09134a", + "0x88e680f148ef2ecdcfed33b61f9e0224790fddc9069bd6999e9bede1791e761637c0fd60b52990b6c93e6e5429e483ce", + "0x94bc20bf5aac6e9f1060d02eacd06c42aeac9a1c5635b15a83985dfb03938ddb4999a822e865635201489c7f75601b29", + "0x849221cab7599f25f0b114df092bd5e8c2430503ae959bef1543a101de0790a78245db6a145e26f40b5f9bcf533219a3", + "0x88b6f2c2e7a7954fad11009d839ce50780921f80292320868d481e38d26aecd80fa607e82219a99532d88cf33b39f562", + "0xb0d82947dc23c0b88b86c321b582c15decdb825ed909a731b42d46bc895009515a3dc646c98dbec7d71b0722df82392e", + "0xa2cfb9f7c1a76c8073363c1c3bebe5dc29fa76533caea41046c51ea9bbdc693a121b957cd96be5b6da18704d1865cff7", + "0x8f0ffab9a83355a22683a9d998d1c1089449eb308711eaad4265f05927ec6d0d1ca39217082a0b372e02234e78dbaaad", + "0xab024661e2b2937ad374c8cf2e3669f1dc55558a3a881e9ec4d461f27e0fa92e2bc88230f038bfb051cf2145ca747a07", + "0xb98d9b9ec9eefa56d38cca959ce1aee7b6d4b41a8dbbd34b3f50c0a5f97f84ed2502ded1ce8cdb5895872360d4ba6d61", + "0x851244158b3184a62d2c98d148e2b1102cf0d5500906bbc2deda95acc5e3bc4b4a3344febbb31ce05a56dfee86a74913", + "0x860d9e2cb886bd3620b5d7499d14b415532482569bd45fd76e3e8052d78a73ae4b2b41f139f9cfb136564108cd93c0f3", + "0x8305a052a0fb2bcd41f3aca075c5f7f233bd8f861451d03f3a6e6e31f7d08dd89fe1eb4dd7b238a78b12ddceaad9768c", + "0xadb703e4778c7e14fb83541ab00b5fc344108243ec6827c5d9b302ee68321aa569da1718424e6a57979ab7536d5eb43b", + "0xb1a754b87b9e21aeb86217ec5b4fadb7535344567f1bd15e88ec12a833fed68e26bfbe03b7709ce24ba6c925ea0a0e07", + "0x8c1e2f6bf820e1653f3b8213e9d959d8649196223c2aab57b7ebda094f4919f88d883bcc6a0cd0be335f26f5a2a9c962", + "0xa082deb9865fe8668e91db0e4fd7fb50fb3fdae3e7bf1217ce0aa6f286a624624cf936d762bb2b6c3fead6826694f846", + "0xa10540ca05fbcccdd0a2a66aabab3b36e9bb525794cbae68bc3dace6116f58942218e9d5e9af10d67b5f6fb6c774fdd4", + "0xb81d22c4ab0ccaf447cc5fc2ff3bd21746617e6773bf43257c0d80331be2e8437b88c9c45309ee46402b38d3d4911caf", + "0x84c7c6e924713cab3b149f641dabf63ad5abbc17c1d8ee7802a6630507aa1137f7e034ba1d12ec13f1e31efbab79bf13", + "0x8773b9d236e5fcfa8c32e471b555264692006bf9a869a3c327aed33da22dfbf5780ecea7158904d4d6ac4acfe9789388", + "0xa4c2c1bb7290eb7af2013f7dde78282148593f066b09faf42e61a3fcf81297caa5a00fdbf6b93609c8c5782a0f25341a", + "0xa7bfa6e3f273da3dcfac7cb9906bbe9fa4fc2872b184d79813ee273e6cc4d7f37f46164362707a1976f5b6a2c5d7ed1a", + "0x8b71502019e4263fcda354a0fd10aaa7da47f4abb7a0c715c7b017e9eea14f2b64009b29b467394668c7ca995adedf82", + "0xad7460fba7deccc3f9a7d204233de47ce30ffa55e1e164975cdf06480a6108720bc397b93ca8c959df77d44a1e1f05f4", + "0xa5b8df96ccb7b078a3918e74b1b10da21df982538d2c9313f5129b2797c8a6db9ff8707241ff72d3e9d5983397321736", + "0xaa6cfa6386660c01879656da6c4e72497690708bae6c5cd1d088f443cb5bbbe75561d6eec256a72b9728377eb83ef973", + "0xb9699ce7c5c878e44114ab7a598646c6c7616b8e08a9ef8ec291189ef9945c1a538d2abf1ce3b0da0f8eecb303b81b43", + "0xb8d0fd1d278f53c455de92ec4357885fc6648dc5f276930263da7dc885b4a9628a2113e28b66b1e64fd08189427c614f", + "0x84ad8d262f6ef5d93e82ff6f4af995148eedf6d8e079124daee9b99f506e2968922eac2c7d4aea741fceb7733f20b2d2", + "0xab5e30ab54641e3a44450118b8235554e0fcfffdfbe1430ceb3f7ef33325725741995fbbbb0c16f0875aef0f1e0c98ec", + "0x80e2cf8bf386ebda46045852751611f2af80eca2e910d9ec5f6e2c7376611534604ceafa639272b3d503b02bd66525a6", + "0xaaac69af8fbb87da1c1b7c1b9e59942887ae839a91f0c1d191c40fe8163d7f1dbe984e4fd33619c73e63abfa7058f1e3", + "0xa6194224ad838ab86e84dc80e9b8abb121ae6c3c7fddc476463d81f14168131e429a9757e18219b3896a667edda2c751", + "0xb68f36aa57aedc7d65752b74761e49127afa65466005a42556230dd608ecc8f5efdb2ce90bb445a8466e1fc780eea8c3", + "0x886c3fa235d6977822846b3d6eccb77f1e2cd8ba3dc04780666cf070cae208b7513dc4525d19a3fb6385cb55f5048e2a", + "0xa9801273ef850b99eb28f3dee84ba4c4017c95398730c447efe8c1146b0719f252709d3397ce60509e05da74ed0f373f", + "0xa58c2a5dd13e08ffa26a6c5e5eb18bd8f761ab64a711e928e6101512401ef2b1c41f67ba6d0823e16e89395d6b03ebb7", + "0x91318b564ec8b2d8c347ca827d4d3a060272aec585e1acd693b2bafa750565c72fec6a52c73bb3ae964fdaa479700532", + "0xa058db5d76f329c7e6873e80c7b6a088974522390ccaf171896066f0476742fd87a12fe9606c20d80920786a88d42cec", + "0x9838e07f9ed8b3fbca701be0ef32a3f90752bbe325aca4eaea5150d99eb2243332745c9e544fd1bb17e7e917202edab9", + "0x85a9ae7dd354f36e73baa5ecf8465d03f0c53b24caf510036b3e796e4764a2bc17f0373013af5b9f1b8973226eb58cd1", + "0x896a4ff4508d069a7da6ef7bed66e1080991daee8b227f3c959b4f47feaf75fd1b9e03d0917b247c2db11e105395d685", + "0xa36d9a6a037bf498dfc0e535f2034e6cd433c7b52e520469811eb2e9f04499a6ce40257d2905300df7d81f38d1bba075", + "0x97aac3c5492aca879b4c06db1834b30b8850a244d29296046a84c637d9580c8521ab4752ef814c96f255a139660d7639", + "0x8552bf592a84ab4b356d01643c90347377ebf1f2b38a8c2e55a3f34537b8c7dcbd62e6776d6c2114f2bc2d4344d1567c", + "0x84474ad163db8e590943ccd1dc50b4f444beb8275919b33f53d42cba89831e9d42ce2de52b26f4412e2a0676ce913277", + "0x900799dfaf5eafeb297c7b4f892438bf2a65ce04034d66f8e5cc3836e4eaffe782fba4f4455a0fcab49102a240d1780e", + "0x817176415e35ad4a204b9fd5771bae6cc270f6ff050996cec89efbe461b2940ae5dd3c6c7d7e31b1da5285b207efed27", + "0x965e5791c927d47569bc54ec9b4c5305788aecd87a26e402aabeaeccc03480df46f0586ca2e2a9918885cd03332af166", + "0xb96d9ada4b5a04a94807d71726bd557de94fbd44042d7dba40560eebe8658d1da49eba54499360619f3b2c38e8b5ed6a", + "0xa07b6d641a43e02e7868f30db4dd5069a2f221b4f122ce9b11eac04abadc4f25f3207f1d2d86c7935b1a3d9992ea9814", + "0x8250d4d8ccac846a4b1a9fa392d9279b5bf2283c8b95d8164c3c0d199fec8849eab85755f2a2a99d584a0407742e3200", + "0x8324cf49f56fc14162f9a9ebda1ebda0388d09d8688f1938aef7dbf9505fc119069efc552f68cc7cd9213f96fda2c6de", + "0xa98e6f1e85268dccbe3bf4e92c9f455c58dcb53de1dba3b78589adf2e50e79f8e245f956e0d098eb46f5d3746826c6dd", + "0xb103ec12f266b4153d67b54d8fc079357ee342cbe5008adc3e0689a7f788534c4601e60e939731f49e4a1e24fd589f82", + "0xb2d7681e866420413cc98eae67614d383943e3762d5742cb3c57e26157633c20880eea1209feaf68402d5d33dd699708", + "0x99fed0ae4112ec9ed74baac70d202a885aa51cb555a3886b49016744dd4017640dd5dd564998c4d842a9f38f3e004e68", + "0x95c35401314467219c8bfb1ccd1f1eae6ef4fa9e48fbea14f70d5315e67b16c46cd03554471840e4a5030b077d2a3856", + "0x8d029380e0c294400d6b8673a23aed43697cb6460fc1bcf217aca3b47cf240886644ed09521d6a05f6abf56f99722d84", + "0x8ef54d1dc0b84575d3a01ecba8a249739edfd25513714dd4d1941fbde99dbbc392f7eb9fb96690d7052609af23aa57f7", + "0xb8ad2b7af4812417aa8de8f33a26547f84bb84f39501d4b7c484cc8bb54c7e166c849b95240fbe459a4719a6e3bf1651", + "0x9858545de898721d19930d8b360cacc5ce262c8e004867a050f849f7a2f2aba968c28d51f24a9af56aaba23a9ded4349", + "0x94ea5043b70df1db63f9b66b4f9d8082776f721b559f27d37b45e0a84faf47f948d7c4532dfd854a4bac49fb2ec8e69e", + "0xa2fd88d7b15e3c2778f6c74470d0f9e1a1f979a4d58bd205361eacadab9973d585a6508e685e640b272d6f8a448eae05", + "0x88defd6bccd55db8ca84e3c8d0fc55a3456b41788f1e209d0aec19c9c70febebf3ae32cacaa1dbbf796d7ddea4b17995", + "0x88b8cde2449d5ee7de2ee2f32e845d27e171a51ef64f1d3d8a5fd7dbb9f898ea70eb7f6410cddfd7b7ae70ea8073cc2e", + "0x8e044fff6ec557824866ac76301b6d93ed19b7177aa6baa95046330f5d69b572b59200e3653cf2f2b559455e782e8960", + "0xb5446b4d6741c824885790d2d26258729dc0ba2f469c85a47d38886d933b785a4f38a951d37f3ef4bd5091c03fa3a071", + "0x956c8afa8056e9a71ab2e8be5241ddbb3a8b3cff2110cb0e7389493d9fa45e6c4b769ebef540a952db6dcd8bd55baf64", + "0x925950cae25615246e29d594ebf34fa7d52f78a9867338648158f2131e6eb4dc17e18f9db8a5fdd76d017b3a9798b3a7", + "0xa17ea4b43211ba990270c21562690b3ef154a46c3d669c4674c80bd424cdfa95d8850c8e882b8d06504f929cba3d93af", + "0xb315ec723973a138508afc387ef651fd8a8804f93975fc36c2eeb796a304eeb1508518d8703e666a74d14318253f526f", + "0xa995742d7433b3f230e622de23cb2d81cac76de54831491cc29768eb4a56da60a5cbd573e1da81fddc359b489a98f85c", + "0xadb2e89f0d15294d7118fc06d4fdbd9c51d3ecbcc23c69797e5b8197eea0d6cd1240910cf22fcab4ef1e2dc2dd99da91", + "0xb5ec9f9fcd0b5d176b643df989bb4c4c1c167112373d662fb414875662d1a93160dc0b5cdf540e8a30e5fcbe6cfbbd49", + "0xb1291b53f90aed275df8b540c74a1f9c6f582e16c5df9f5393a453a3e95624ab7552e93d6e2999784e164046e92ef219", + "0x8bc7b7b1a584a12d5ae63d0bbe4dc1b63c9df9c89bdd1095ff4b8e7c822bf8c1994c92310a3644033c7c9689f4b7d2b0", + "0xad7fc45506a10ca48f991714ecc055cea376c0cbe667f3b40ee8dad8446218835439ae59bccc474cf47b053748ceba6d", + "0xb134756828a5f5725c0b95109e09ca450e3834b127163a0aeeb544e63cc0cdcdf66f8ed98c331c7c98758f46af369a84", + "0x94535bf1636be0974b112fcec480ed8eafc529933f3065c40e417e608e43a392206cfde8bb5a87b720263446c90de663", + "0xa4df4f6efbc3701000fb072e5cbed2754b9ef5618386c51ff12f95d281d1b700fea81fc1365f4afc66a7c83bd0228fbf", + "0xb0336b3552b721087c7e2194976a9119aee13ebed9f1c3c494353707fffde52d004a712965f460062ec9443620716302", + "0x99a39d1d1ee4283b75fa8c1fa42b6a3836b734be48bdd48050f9b05e48db6354fef509623c6ec8d447d630a9b3352b77", + "0x8e3dc3583d40956f9e784e8bbd0b5e65671d2ff2a7c387b20fcb7da9b969f2d122aaf7f054d450dc611737604548c03a", + "0xb5068ec5b7bcb5d8583d51cb25345990f50d1f7b82fe535a6a6b17756355885047916f466ea3ab09eef5516bbf2dda90", + "0xa8284ec1eb1d21e693f31a6c074199ee85d8a8da2167bffab5fe240defa2773971c8437e358a18f7e58d1e2954f57f6f", + "0xaa7415639d29081acbaac3e9c6b059d68e8702db3f430b86bb6e220d476fa74841c875e9d471c8a5423c58b6fee3cb54", + "0x8afcfe6f65fa6e07c2cb3e1756c0ef2c589830be96edd50c3c248e3b17f51a4b08ba92ef7eed7991d81667ddfbf2bf7f", + "0x83b9c8dec8ca8f9b85f0e36c08c5523cfeafb15a544398e6f93b48b5fc4b15a0bd05c0f176a9c2469664acab8dffb0a8", + "0x82a128a89ea46b9debe5c903b950c0ab30cd7570b979ca911500b5c2cca5c4ee6b2c2fa414b5f28e367f4671ffce60f4", + "0xb79fd0ccd2629a361cd6f9307c02ecd4d1f07e4ee03ce4b542997e055b07a026cbc0ba05fe3da309efc58db2e401a8fe", + "0xb190751141093823b4b5324cc26c4f3258552f7893241201f2fca1ae9b1a1d4d4964a9abdde8642cf308ded61ce5ef09", + "0x935fd48b95aa6f9eada0cf9a25a573f0ffe039888b3410788c41d173747bf384c0ec40371bb4383ddcc7d9f2db3d386b", + "0xb9affe100d878491ff345636ffd874ce1f27852a92417694afce4163e6a80c78b2f28d78102fd06c3283ef273ad37642", + "0xa877670276d49ec1d16c9f1671e43ade11c0c1a1413755f6b92be9ad56bc283e4bd2ad860367c675d5b32ff567301fc4", + "0x8c660d16464878590761bd1990fd0fc30766e7e49e97b82ec24346937856f43990e45aa8ad37283cb83fa16080d4a818", + "0xae1412087da5a88f3ccc45b1483096aeb4dcf4f519ff3dbe613f63712f484bdd8b2c98a152a9db54cf1a239ae808f075", + "0xad83cead97a9c3d26a141604268f8a627a100c3db7e5eefaf55a1787ddc1dd5ffc7544e4947784cb73b90d1729003c8f", + "0x97c3140ce435512a509e6ff3150da385fdf9e0883a5dc7cb83d616ec8d0a0014e4e0fa57a4d12c7997cd84e07d49a303", + "0xa353773ff68f1615454555bf658eabdcca40a9c7bced8537ea6fa8d54764fd1f032889e910d2a2a342835513352e2d2e", + "0x89e8df0c17a36ffe08149c2ef8b27306d04cdf437135aaeba697abc65e3c8e91bcf1817919a8a826acdbbe7dce79a18a", + "0x9928c2da15ac6cb20b15859c22508cfcd452c5643cd22eb84abf5f0a1a694fdefcd8fc329c9b40babc52630743d6b65a", + "0x99d837b556f8d13108eef6c26333a183f59383b39958dd807b10590c3d37f62ade6c4a320ca2e70567e0218b0ad5807d", + "0x9272da080e4aa18720b634640b01bf1fe506c7c8a89dee8759a53e2ca5cdbbd4a4f3aca54924c46b935362cf1eca066e", + "0xb4d39752c882de1c1daf3854202c1d58c2bcf35c882006eb640fe54a97be2655281cdb91c30d1a41c698617c2cf64b01", + "0x8bf827f4a7d47e07374d338a3d8b5c2cc3183015b5a474b64b6086fcf0cdcf4852046c9e34d7917d69caa65a9f80346c", + "0x901bffc7db9c9416e06f593a76d14f6d9e5dea1c5f9557bd8c93b9e70aa4782bab3518775c2a5b285739323579f7cf0a", + "0xaf7e204388568627ca23e517bcf95112ca8afd4c6056b7f2c77c4da4b838c48791191565fd38398587761c8047d11c47", + "0xab2576b5366e6bd88b347703f9549da7947520d4e9de95d7e49966d98249406ed9270fe69347c7752dad47e42c4ea2f4", + "0xb12e3b228b761dedd99d02928105494ded6d4fea3026d73d65ebffa2e85e2cd75b6d091135d418dd95ac102c22b5ee31", + "0xa20b4a752685d5e31ee7e2353c8a1b9a5265f12bb775004d282a3ecd9deda44831bac1ac5151646428b66909b2a423f5", + "0x91a1d4bc0062a86cc6786a96fd3eb4436d8a4a187b7cbba02190d1cd6ed3c3797d9ae7d6ddc413f1c94a21f62bd04ef5", + "0x977f18da1a5df5cfdd0276f583cfba2b2a0fc6139520664e20068f8dfdde33e29d179abfd722f142448f4677aa47be6c", + "0xabc3ece90f0f7b1d80fd917de27ab0d88cca584ef959da520825e54cb5a71336b15f8b348532d08d47a6fa600527ef25", + "0x888d36a2c7cc13a1c1aa338a183a74a1f57713e76cb825f9837f43279ce4741999b76a16928147537bcc20f2e0195b0f", + "0xaf3f5dfdc2dcfe19de893f385f39f550cb1dab67c2e97f1d5fa735e5ec96d6680066803e8a0eb010dd4399f654195513", + "0xa0fb4e08ff56530a940a86c28830956eb6dec2f020f7faaea7566faf0a4fafe0cffe01480e87763ec22f201be51a6451", + "0x92343c5b107910b203c64a79c93d354f7ee5b7d1e62e56732386776e275285561cb887019cc00d3fdbe3b5d54460bec1", + "0xacfe7df83c4624188a1011ad88c1e1490d31a8a8c8016b40aebcdd7590d9c0793e80d2d7ce6a7048876621c252a06a5e", + "0xa7da001dc1e33e0e129c192d469d2bd6e5d2982eb38f3ba78bae0670690c8e70f40e8114a57bd0718c870ca5dd25b648", + "0xa903de5ff97dc83628290d781e206ef9d7c6b6d00cadc5bacffb31dc8935623ab96ade616413cb196a50f533e63641d6", + "0x8f9658d42ad14a60bbf7263f6bd516cfee6b37b91a8f53715d69f718a090ad92484061c2cef999816760a78552fae45b", + "0x8c15b72b3d5fcb9ffd377fd67d9dfbdd706593fba9629002639973db12aac987bd1db70250ded31c88e19efff612cdb8", + "0x88a2a4034decd854fb557960194ff3404e239953818a8a891bf72a0b26a8e570a65c4a630884de991ae7452b3234f31a", + "0xa09cae5c4c190537bf1dd75bd7bce56f7b799762af865bb9d1ee970f6a133c27cce0dd0f14a0e0516ceac41054e6998f", + "0x9760ebb1b40f9a97530c3b940d4ef772a225e5b63bf18283f8e302b9436c5209f6294980fd37058060e429fb7fdc3a56", + "0xadaa9400eb86d857dc591b25dbe3bc8f207b69e77b03cb5ee01f7e4b006b5c8f6ba2b51b5a45687479885708509363de", + "0x949efe6b00b3248846747a9ad4a934d6e4255994c2b540a59fbbde395fe96d69bb67908441cfadd8c8bbb561fe52da03", + "0xa19a45504b6b1dc3a0fe0e6a1384734a3dcd5a7cb8fb59eb70e49426c4fc44946547443d558e5719a04884ab3a2811ca", + "0x8934c9ee21e8d1435426fd0f64232a0670a7946ec524c054cd4f2cc8b1be9f89cc11002ca8aebae646a2050d91716b10", + "0xb1150ff8ffb34ffdcf7d603348c0aed61e5f90ee0a1b814079fc2a41325c75f2f9ee81542797ede3f947884266a772e0", + "0x86ce8cc7c1f92af68de2bca96ccb732f9b3374dad6657dfd523a95e8a931a0af2a80df74098514a06174406a40c16ba5", + "0x90faabb9ace9e13fd9584932846ab28a618f50958d2ce0d50310a50c3bc6b0da4338288e06e5fcbaa499f24a42c000d5", + "0xaf4a935c2d8df73332a16dc6da490075cf93365bd0e53e2374ef397514c30c250bcac569b6df443985cf3720a4534889", + "0xb7f948ee90f394789eb0644d9f5ad0b700c8e44e5e9ed0e49da4cc18483676d25740710b1c15a557965da635f425b62e", + "0xa917913091245beed6a997ff7043ecf60c4d655c4db0b1ef1c704fd9b0e1ea1335ce8b9f45d6e120f81805ce31555e30", + "0xa48099da8406399bfb1ba834f6f7d864111d0036969a5cb64089947a63dd9467d3857b605e9f57f5ad5f4ec915088d9b", + "0x9784c3f9be42eed354542b1446d734521f8e3f01cd9d495ae98f2e4a3a16767fe2ad909e0def5d9a6267f3fc6a172cd2", + "0x8d9afaa323847a3226ad7d7b60d87322ffcda2e4a8df89f58a076f7972d896588de685a2e155e243bcf9456b0a0d6d1f", + "0x994413faf0b843f4ec1842c706c45ea5f24351c68674a27887bc8b182eda756856e507a4e8bbfd937e2c4c581b629ee6", + "0xb3e72d9d1ddaa00c7d22f25462d6e9f2faf55e30d138dce8bb1517eb0b67132db758668aac26164fd934d732633bdea5", + "0x8e95875e338f714e9e293df104f0ad66833bbd7a49d53a4f7f5fd5b18a66a61aa0a0f65cc31d55e0c075e0d3e412cb90", + "0xb980091862b1a9f9334b428eae14bbf1cecb4849e3a5809773b0d071d609727270f6ad97f329eca896c178ce65883db9", + "0x915d7ae5ae780bdba27ba51a9788a8852a15355b569581d1f18f0d94bcdfed2c1ed5a4f58e049e9825cda11f92b2c2d4", + "0x83e581058edf9259d0b06128282327cacbb6afc939578223cbf93544599f799a8dce1fb21d52464f990a877086f42506", + "0x803612a38b6f6efb97941997e101ac1878e192456f8fbddb3359aa7f3023434ed8fa92e60ec8e7b4473b1948850e4311", + "0x864a1bf4ac046161617dde282e44ab3cc1843da01a09ca58aa00ed00eaea9351a07a9ec16d910819e7dcc28b8d2c8ada", + "0x922eb142845975d5f6f7dcfee6cac8c299b3730400e6bf82cc0bdd9888de21de9d9f1530640f702c003e1ed63b140cc7", + "0xa7db03c5be647dce1385ebc02f4825a654447fa8c4c8d4b22e635dbdd2b3ccdf219384e49a80cfb1e9e6182b6e4227ed", + "0xa167289ff0f0967bbab6479e4a8a6f508b001bbe0d16cad36ab4c105ad44f3f180e39a6694e6cd53bc300fe64dac1e8c", + "0xb7766431f6379ce62cba22ab938cdbb1b0c7903dfb43980a417e0ee96c10b86b447241e9dd4722fa716283061b847fb3", + "0x90cda18c5d66f5945c07c8c7dc453dee1370217ccb851bbea32578599aa669b4dd245dd8a9711b27c5df918eadf9746c", + "0xac690cd2af39932874385fbf73c22b5d0162f371c2d818ec8a83761e0a57d2db2fca1d757343e141e1a0348016d5fc44", + "0xabac820f170ae9daa820661f32a603ed81013c6130d1ca1659137d94835e1546c39a2be898b187108662cdcbb99d24fe", + "0xb2ea5a5950096772f2b210d9f562f1a4cfacc021c2e3801ac3a935f2120d537471307d27b13d538dcbf877a35ff79a2e", + "0xad94af4d0699cd49ba8ca3f15945bd09f3f7d20c3aa282a3113cdf89f943d7793e59468386b067e3c1d53425dfe84db4", + "0x83788367ec97cc4bbc18241cbed465b19baa76fab51759355d5618067009298c79d0a62a22e2a1e6dc63c7b90f21a4a5", + "0xa3e142d879096d90b1e0a778e726351fa71996466c39ee58a964e6b5a29855123d4a8af47e159027e8e6be0ca93d9955", + "0x860831f8d3edaabd41be5d4d79c94921625252aaec806251fb508e364e39fde8808d38b10d557e487603a1b274c9bc3a", + "0x88da39f334bd656a73c414ec17dda532059183664bbbac44eb4686c2601629ef8ff9da992c337a842e3885b684dd0032", + "0xb50addbdf7164e8303f33de5ce854d6f023d39c1c1984b214d9e5fb6f6001cd5bdda816f048a438ff3d696872672f805", + "0x999e58c4c69a912b84561cb09610e415b43832beeb95897eca8c403ef4754f4277754d492eef3673afd4362f50060fc9", + "0xb88ea0f60f8119c5a1fd9294796d387472dfad22442b29659713d1d88e7d854cb7cf5c9ef773627781188626bb2fb573", + "0xa068b3844e9dbcf74b54fd55904d56af754d8ce4c619fead7a07f9bfb9d02118db7c512ccec2489d2a84374ec1d1fb6d", + "0x871dee023768636003c799e6f6fd8d31315a4c0da7286345cd64264a016693b3485e0732be1bbd34dd5fa04dfa58a983", + "0x8021e8f508680df12e4a5a1bd49f2d7142df65158b0a7198ffa83abd16053a542fb93ffc33e5279020ba8c6a26feacf2", + "0xb5d3cd64df5bc965228b0bd4ce9e5797c409f7b64a172ba165e44a8e4b38e3d5fabc3e0b9a19afbfe427f887c40a315d", + "0xa54fdebbb594bafcefb1a03697711e0091c072e1cc24fb441fefd4e0a0518675a1d7b0966cb8294051d7ec0ac175d0cd", + "0x93922202337f72969d6d6e14a29c9c75e0420dfba712029941d1504b9f6f9761d706cbc0652cd09a1aa5d22aec766af1", + "0x9711ebf1c7c7426190d4afd5dd03b014a456bbd9d90ed101623866a280550df26a629dde400c03ee3699f7d827dc0bb9", + "0xb4d686d8bc5c1e822a50124c1cc23c6bc3a1577a3d0b8d4b70d1797418aaa763283c09e8a0d31ae6d4e6115f39e713c4", + "0xa533ea2ac683e4ba07e320501a5d82a1cfc4fa1d65451000c3043f0fdac0a765cc1125d6cc14fe69975f3b346be0fdde", + "0x94ee563134fe233a4a48cf1380df55ead2a8ec3bf58313c208659003fb615a71477e5c994dc4dcfb2a8c6f2d0cb27594", + "0x93e97d3f3f70664d0925be7aee3a358e95ae7da394220928ae48da7251e287a6dfbd3e04003a31fab771c874328ae005", + "0xb57440d34615e2e7b1f676f2a8e379e1d961209fe00a0cf6798f42b7c28dbd03172fce689305e5b83e54424bc3f4a47c", + "0x97644084c6f7b4162bc098bed781dd3af6e49e7661db510975528f1dea8154f3d87e979bcae90c3df3a7752eb0752889", + "0xa923b27b225b2a6dd5bdc2e3d295b101cac5b629a86c483577e073cea1c7d942c457d7ff66b42fcf33e26c510b180bc2", + "0x86698d3b3873ed3f8ab3269556f03ac8d53c6e2c47e5174ec5d14b3ed5c939750245441c00e2e9bb4d6f604179f255ef", + "0x87946826d3aa6c7d53435c78005509b178fdb9befc191c107aee0b48fbe4c88a54cebf1aae08c32c3df103c678bad0ca", + "0x860864896c32b5d4cb075176f4755ea87fea6b9cb541c255a83d56c0a4092f92396a3e2b357c71833979b23508865457", + "0xb78fa75d687349e28b4ddfe9e2d32bb6a3be13220b8f3ff1ded712088bd0643da9b72778bcca9e3b103b80097f48bdd0", + "0x8a188b940446598d1f0e8c6d81d3cada34c4c1ae0118ec7e0eacc70d1bced28ae34b99667d5793d9d315a414601c3b22", + "0x842ac6f7dc14191ab6dddffcbc7cb9effba42700a77584aa6a8e17a855cd444c5d138f9d61bf55f43c6ffbcc83f92bc9", + "0xb6742902c3d145a6af9738c01cf9880dd05c85f0d0ef7dbe93c06fdd6493333d218339ebc2a02be1895436a2f734a866", + "0x98bf18488483c627b7181b049d3e6f849fce1f15794de59dcde6e5a9b0d76fd484a46e48822a6a93001d3aa12f48bc6d", + "0x8769cac10bda8c53a1c19419ef073a5998f73dcf2ba1b849561615a17cbc0a49bfe3eb4ff8801dd36a22fa34b9a3a7e2", + "0xb45c084d58028fdfae792210fcd183abc4ffddeb4cf52ebf3f8a50e4c4eec2a2758f1241b0920bebcb24b757c778577c", + "0x85c1216eec8e1fbc1af9b36b93c5d073a81d5fba86a6daae38748ec1573eacc6bef209e76c87a6efbd7a3f80e11d4c3c", + "0xb8007e34bb3f927ec06a050b51e633d7eb9e9a44715d5b39712e69c36177a03cd68391090cc3293098e54f6cf65f6caf", + "0x8e85527b27c9152b1ba3fdd532a76a79064ab097570508f233e09978761dfe3012d537411b47d0e4b65265eb32cea2ae", + "0x899779f3c31a20b76068ec8d59d97a64d2249588ddfd69dcbaac6bfaee8ce0ff3c5afc4e17c934ae7cd041b760eb555d", + "0xa5dac3d8f5fbef018509612e25d179f60d2a62451c76426bf546e9666fcdc73263d34aa6fa7e2bfd4c9947bbf5095eff", + "0x896900eeef9be2b2e755128e7b1c436af6fb3984f1e66c444bc15fcf3959013b4902c381f0eab1247f878a6ebd1f4ee0", + "0x8cb17f4b0af2e9b2cbb56f46e6a5d6874ea0daf147aae77303020b4e592ddc92e0dd058def7da96258b3a68b223bf22d", + "0xa1b6d3f09a9fa7ecc021ab7c5396541895da6e9bf1f9a156c08fc6f2b815a57f18c337ccfe540b62d79e0d261facb2be", + "0xae70888811434ef93da60aeee44f113510069fd21161e5bb787295492eb8df85103794663fc9305f04adcbcf11ff0c5e", + "0xa84bbc8624100acfae080ba8cfb48fd4d0229a60b62d070bd08fade709efc6914dc232d3f7bed76a59204f9252321aad", + "0xaea47d54652abd8ca213cfc623c8e30780f37b095b59ac4795252a29c2b6bc703a5203acff8831314478b8ee8771d4d7", + "0x8dd438eb8be14935f759aa93021c2b24e1d588f7a162c42c90ec3a647b0ff857f60e24c0a8953eb7bb04e04be70f11ce", + "0x922b07b5469680a10e7532766e099896f4dc3d70c522d8add18f5f7765d4ddb840df109146607b51ceddd2189fa7b9c0", + "0x83ef6ebd0ae6c569d580093e8b0b78daa964760556272d202d343e824c38eccb424262e5b7809d3c586f9e2e9c5c5f22", + "0x97f98bd357db6e093e967fe180cf67ed09fa711580a5ad48f07cf095b2e8fabbe6319f97d1f15d62c0ec2227569d8dbf", + "0xa1953a4a22fe6c2beaf2a5e39666b0eb53018af6976e3a7aab5515550ff2efa89400605a43fb2c4ac1e51961dbd271d8", + "0xa5cbd67f4c0bc98e20aa74c09e6f5fb6f42c08e59aaa477b4b4e61434c8884bc14f17cf11faecf46dc4b6c055affbad2", + "0x87d96818f2c4f12fd7705cf4060a97bd28037c5ac0f0cc38f71189ec49361e438ce863e6617651977708094d5336d1da", + "0x85e7c2daae5fe59f8a1541c94df50402a671a17dbb8838113fa4b7aaff6114cf2bb5969410cf21e6a162857f2f7a83a8", + "0xa19575083e1731bb04bb4a49414e97aaadb36d883aa993d1f6847db50007315444814740e67e10177a14e0e074fd4c7d", + "0xa00ebfb5bcc3a6da835078189038a1e56b7dab6be74332b5ff7440e53b0f9e1eb9973effecbbf37000021fcf50c7c1ff", + "0x8969d7943abd3b1375fdfc7d6124dde82b0f7193068ed6ec83bcf908734daf3487a6a30f7b322e54a4818ae5f86d91c0", + "0xb959c8d210fa43af9b20d1fe0ea8c4921280eb4544ef6ea913309ff9d61c9327096707e84dc1662960519be8e7d080a4", + "0x9011d8ac651c42e0cb03931a9e960f58e02524c6b666047525e3b9097e9f35fb2b4b278efcce2bd5ad463c6d7fd56694", + "0x937e3b22ed0fcdbd9ea5a1b97b84bbe86b7f5b2de3866a930611112f2217f4ee7d9822c4ab1253823f77bceeae0c8e10", + "0x828997e5d121f4c305e018a0a0ba338bd6a34a7b4dc3c5ceab098ee57490311c130e2c045b9238a83908d07098d9fc32", + "0x8d114808eac0f2e1a942d80dad16756ec24f0276763cd6771acb6049472e05a9bb1d3bbd5957f092936b415d25c746b0", + "0xa063c5c26267ae12887387cbebbe51fd31bc604630b3a6e8e177e71d4f26263be89112cd12d139dd4c39f55f0e496be0", + "0xab1e1582c8d67196d10f969eeb44e6e16214f1316aa4a2a821f65ba5834326da6cba04373eabfd3b3072e79e5c9717e6", + "0xa17b1dbaa11d41457e71a9d45d032448091df7a006c1a7836557923ab1a8d7290ec92a7a02b7e2a29fcea8f8e374c096", + "0xa1ed7198da3591771c7c6802a1d547cf4fcd055ca9010756d2a89a49a3581dfe9886e02ee08c4a2f00b2688d0600509a", + "0xaf09aa60c0a185e19b3d99ffdc8c6196d8806169086c8ff577bf3801c8ab371e74165ba0f7329981e9252bfe965be617", + "0x98c04cc8bb26ffce187fa0051d068977c8f09303a08a575175072744e0a5fb61191b1769f663a426c30d405515329986", + "0xa542bf1c9c3262d488ea896f973d62923be982e572172e2461e0146190f2a531f62acd44a5e955a9f1e242b3e46d63ae", + "0xaef7b7f30efd50e4a66c87482386f39f095bff6108e68f74fd3bb92156c71c75757912b111060cdee46a6b3452eed657", + "0x8afe1e0ccd00079702f16ab364a23bbbd3da1889d07c4f8cb04fd994bf9353216360dbd364492932bfe20b8b69ae8028", + "0x9896c690999db3c08cd7b25efb1b912c3e0f976db98a3e830f086aef93222d06ce570a7b2babcd7c81d8f9955169669c", + "0xac7bcab6a281468907ef1ea8a6c1cd624159c88839131bef6aa0c22f331fc87ec6128a2c2a333fb79df549e4587e1a12", + "0x987935c08a30b099d19f96901315a2e60591baf898581c40bf5eddcda806ff24a4536e30ed1e6c0b128a83fc77b6e81d", + "0xa0a6945bbede3bb09a4a09ef27baa20619d3e15af5673b9350601bcebe952597c989870746cf75767ffb73b32c6c9c6f", + "0xb0f5590079f0a0302b08a0cc1b7a5f39cc6900c2a5cdc7baa333d8328a731b2df5dbb67e27a154d3c44ed1a795fc4adb", + "0xa7294bdeea210e528f277f3d50e89e6d79950494478998181ecb38de675020130256f2f2a075899170be964d478458b0", + "0x8ab3041b895a631869b439d5599a66facba919226ca9b39d915f19d59f9fc82393ea781377e9bd3bcc5a310e41376914", + "0x8da399b59151fd48b2579948bb82698e3c9804d70ec7d6f3cc7e82901f9f2de5ee850349a7d6f43e5e9ebd47bd78620f", + "0x80e8c32de83d1083916d768b11a982955614a345d26d85b457f2280ff6c52bb776958add7c1c8878f7d520d815b8e014", + "0x81bbec7bd99d2917d2dcd8a288722fb33ad5a4bf5416fba8609fa215fb80e0f873535349e7dc287f892aa56eb9e39c4a", + "0x9665796fe04c8519206fba58496bc84a8b9113e7ea8e152b65f7f732e88beea271dc97b1ea420dbc8257cc4b18a77463", + "0xa97e342aaaf693ddc87e02790278e4bb50117af4413cd703bdf3b7cad2d1facf31fde1303b43ab2e0265467474f97a8a", + "0x925549ebebed348886e37773b05cd8ad04906eca4536bfed951d1ee41b3d362ddc6e1a302c21ff3a2d1e70e95117922c", + "0x818fdf74d7903502101551bbf48d3c7819786b04b192d9e94362d2fcb85760d8b6f45165a5443aa5221bef400525ddb4", + "0xa9d29de7e8fd31b59f4a087168d062a478b1329cd3c81c31e56de4fb40de7a5be9a5269ef0be452c487443a0b097dd50", + "0xa85286ad573db4c9aa56221135da1e31d742e0f6ff01d6b159086d7258f78b08dad55ec8eb5c91ee9d3404b2eeb67e1e", + "0x92a79b37db5e777f9ebbebde24a95430a199e866e56597c7d0b0e7fb54c7b092c2f6cf61fb24470ddf250cf609898281", + "0x8d79f5ca67ed67d52c82949af342a9fc60fb793c47c76d84b4863c550796fcae2dd59e285897c6fb96fe31cee1efa62c", + "0x8ad2e0bda03415ab86324992bb62dfa3612d2d003765bcad1468087c27971d08bdbae5252681f0115a184f4885d444e4", + "0xa08815af979286538c31b4aa5ec805053790af1ca58a8c4341be51136d094a8a05e569d876a079033298ad355ccb7ca8", + "0xb96c2978d0165d619d08281d295e90df78bc2375d0afbc3142ebff9c2cd4b0f0aa97a9a0e3740bc4dce0ff8a9fac8252", + "0xb7752cd0e582f35ab0d0036ca9c0a9fe893a6ad325164d78d865a604a85d3d23729e0362553e8b8a3d51816beeaa30cf", + "0x99cef1fafc29e7adfe247c753c475ad4bda7a5f9558b79c86e8a65968ede67adb38dc30071925c9d66a13860027a6735", + "0xb9f6c65af178c791b6137d71980651fb09cb5b42f268999c728c6e129985a9c7d77b3dc3b50751bd29ec9ee0b3111dfc", + "0x8d73ae61fff5be883a281782698075c5650083f00399992688738856d76d159803be0059fbd9dec48f4f0432f0590bbb", + "0xa8a4a2865226de9bbf19e12c7e75318439fa6cf1cbf344d5e79a8f363439d3bc5bcf4df91b54581e7866e46db04eaf0d", + "0x894582aeff222e145f092ba15c60d3207340c38f2c6792ee2ab4d82d50fb544ae366c2985cc2b6c2f970bcc5f4b46385", + "0x956014ba2d20a056fd86cb8c7ceeab9a2c6f905dae24fc1c5278fa5b84335148ebdefec5dcde8eb9b084700724fc93d7", + "0xaf217fe2b654eff6d11a2a79fe0339a1d4cb3708b7be9f09d852158b5a44b4f9b04406d6d67c4f144fb6b69a41ae9d0f", + "0xa90752a784bc00df94d960e523f5596695d16a534fc806179e0f878fc0e82a91b25e758e91a165debd815dd1af5f1028", + "0xa697606fb32979549ad822b31df8eaaf50de4ead984439a0a33e955937d326519bb9f62c8243ad37f764655f8d32cc80", + "0xa3ad4a30922e45a3e665551e5611384f1c2d414f6fa806184b0c826af05f014dc872585e255543794ee41e43cdadd856", + "0xb29c255843a82ea74a013bac6c36a694646e61e6b9cefc4c130e2ee261e3bb5da3e0fe3ee7e6fbb009deed0530bc1c82", + "0x87e1cc7febefa829cf050aa2aea59385d1048f8617abba691f7ea9ef58eb90ad12eeb9c439af228b0e34897ba1cf1b47", + "0x994d3222f89e9c8c154362190be7167c8c2662f0cfa9d50eb4d8175b255ff0de09dc548ee312fc8226963c8c16f43e8b", + "0x8f1a980be640820f2d1e953264ca4c30330878971669852be3d5d6b41c488be1628b935388bfa2bd4de484acb0fe661d", + "0x854d90d0721579c8c88e147a4aa83553c960617b18075f8224b975562dccb30b0e02e81fa9df7070f356a0eeffc3b14f", + "0x8e156da9d4330a03e32a25a2f0b861fd3ea5c719fa4f834119baab6e5fa5236a9baaf0d44147bf0841418900037f6eac", + "0x96586fc49e53a6799242ddf617000db5a0ad20c6cb1686af2102623d64a71aaddb8e468b15fa6d100d0384e448548db4", + "0xb44d8d85c8df95d504f82d597f8c515866d4d4a326fa1b816dcc5bb0cc4ef1a52647aa5d2e84c62e194c01cae0885d21", + "0xb75c43e676a7efd199f8b32ae31f176ec667e714df355e9eecee97246f72af5bef9c5b04c11e7e90fc37bb9163f957ec", + "0xa49835ac0565a79f6a9078cf0443c5be20561a68b448289589721fded55188583f1d301925a34eea647f90a6e66c6774", + "0xb47c17ff6824a00b8f29df0adb7f06223208d062bd703b0f763c6eee4ae62d4217eef2da4f4dde33f0b469c2f2db9e42", + "0x957cf039cea6f6d41e368e2bd0cf77315938a0738f15ed9ca342f0a28658b763659ac1d1a85ecb362f13de12b77bb582", + "0x903a52f8d2439fa63f59e1e9aba864d87b0464ded63814474947112375236a6f84e8fa003cc4433c8208d80e05fbd1b0", + "0x8afd524209ff08d1eb6312b078f7afeb8e1155af649e930ab711dedda226dc2db6b0354aab9652eea7f433f90015bf7b", + "0xa95c3c9277b11bc8fe191773bf567641be57c0549913b973fb18740ff9cd7b3f7ce198fa4dc1086b2b8a446012459193", + "0x9455ce8163fce04aeff61e7808ef3aac4725e51404f0858fe5d39d7344f55dcc7871ca332aa5cb1a63a4399529e48907", + "0x809fa35b6958f94e781f2c584438b33f5ed528a6b492d08960cf22ecf63ea3aa1e2d29bc879e17296e0a6cc495439cb6", + "0xb0f50774de212dd33e5837f6b496556215c665437e657f674fc5117e5c07dadbd0d057e6ac4c42d50a8eb81edfebf315", + "0x844c65e263891d0b2fea7db6934cc4b7fb6bee2c1d0b9ab4c47f2eb3e9c5d7197dad828d38c54139123740151420280b", + "0xb13c78c9efcbb3b28eb3fe0b971380b7d5151c80948a99cd93c78b4c3ab0e86df6226a64d91e0a2ea4a1c0a46bc0404e", + "0x90300a541decad460c348b8f4257f7a29687b2362ebee8d92fd03cc0e85b285ccb0ab1cb2ff5e29c5cc5295e351017cd", + "0xac49b409ded770c6d74f6e70104c2cdc95b7b90609da0743c9923179e8e5201ead03becc0ab10d65b3d91a5be0d52371", + "0xa257b815bd8289dfdfc21af218aaba12ccfd84ebf77642cc4cf744d9b0174ca0b0d7ab2a545c2a314fd5f63c140f41ab", + "0xa34778d8446e4d74d8fe33de64b2694ef1e50bc140e252af6eff3ce7b57acf8b6577a02ba94b74a8ae32e5113cf0a29b", + "0xab9e935bcf0d8607e3d66f013d9bce7909962cb7a81174923db02dc89e485c2b1c33d6065bdc7bbbe0450b5c49fbe640", + "0x94d2c5c5c309c9eac04be4636f61bc47fd9579b47aded57cc6c736fefb8dfd8f8a5de32210f7baf2052d04c0219d3b4b", + "0xb8dda9046ae265214086355101be3460421f7cd0ed01bde9c1621da510941d42bc93cd8060fd73f374fb1b0a5f38d45e", + "0xa6674649dab5f92ab9fa811d9da1d342cf89ff6eff13ad49f4d81de45438e81a384098d3ae5ccce4c67bda5dbe246d95", + "0x8d619f7564677bacba29c346c4ef67c211f7a3a14c73433dd1a7692e16a7e2562f1d0532454af62fc04c2fd2bb1789b0", + "0xa2b93d2fd4c707f5908f624a0fc889e20164d3c61850af9125f47a1719757a6ce6375aa1910eafa4c1e8b6e20c312775", + "0xa07d5585447654d82817ef4d199984542328b238157976eb9a267f0bdb2229acc25aee510be68f65a312b68fdd9e0447", + "0x8ef55cf95e2b24d8ec88e4136399a7763bd1b73d5e90ea45e9845123e9d39a625cc336e9b67988374b8ebcbc75f2ed21", + "0xb62c1fc32e27c767c461411b02fe9aa44a86586e1427406f4ef0b346d077db91952abce79318b382ec75b7be23058cac", + "0xb252900345f5fa15a4b77fb6af6a2d04db16e878b7bd98005333f7f6e3c8e6e46cf38fc5d1b2bc399c5c2ff4af730dc6", + "0xa4ab5ac0cc15d3d17b1747c6e3133d586870eae0a0d9c8fa7fd990ebd4fbb62e9090557ca2792a6bc6271856aa3c9a05", + "0x8e706b3f2e902faee10b22742c6c33bea6f670a8937c243db96885143c1db5c979e33ab73a38359b52b8d668ccd092a9", + "0x8a6792190ee6c959d79f60c22980ca140c638d88d75660adaf9bcbe6dc4692ab5f01e0c460170f09f74d5e582e85ff1f", + "0x97ffeedfc94c98ec85ea937e064d7b290a326838e62cebd407facd1ab4f08d9c0c109d79af7cb6170fccfa6c8243c127", + "0xb79970b67c09453614ffd83a0c923c17f857c6ce3c87a356298f8351cab0def7ed83efd4f6638f48df67e07bef4ad9d8", + "0xb90f1931c7cf1822cc0a97401119910cdfd0482daf09a4d7612e4e05046295cfb4cc50d5214b31676bb1a1c9d15f9c7f", + "0x922921ad813c01fb5d12fa7fb7ed8e0b0abbf7b19affa190b36013c55b88fe3c7df0ae663c970eec7725ba37b95a7cb7", + "0xa124f33e7f28feabb4089a063a08d52b7395d24eecd06857a720439dd9414b7073bb86fbd0b04e7bfac62d3dc0fdb2f2", + "0xb252fe50bc6677c004550f240fe670974a33ffe7191ed7675da6ac36c780c2f8d02be7da5d92cbe2d0ce90147847f8b1", + "0xae5f8c9c56070f919f3df2d2284348fa4b2e39881f7bc42c9b2f5b7cb1ebeef8ecac000f37329bbe04cc1680cefc7f4e", + "0xb432a4575caf7337f11eecfcbd34a6705d0f82c216301725ceae2b3c9df20fa53d1ebef65513e305013d1e0c2df522b6", + "0xb7c016fbbc4614cdbb12db1c9ac41f9a45d5e5ce82594d568a30cd2c66c3cc9d91a2c959697b67c582a0913de661505d", + "0x8f6f3e5e0347dddc1b2a34ec0dbbbb7cafbf976f19c9c902efb5c1427d1bbd4b71abd9f3fba20dda75c35a39393c989f", + "0xb0042a1d33a1ee9fdf3fad2299b8d70c4f1862d8393b5ebe3ac2189a2c5a58bb826128cd7a39b70d524a6dd976097e26", + "0x85297c4e8ae8d9b44c3fe51aa926c77d55db766c2a9f91b659040de36e34c9a4fc6f44380f8d61704498f6fd52395a49", + "0x8c61a988b6a00fe5a277450f30bf6daa932e42a2eae844568e3babf8815e09311f3c352dae6eb2d57a98d16b7beb2d22", + "0x990be28aaecd932e7edb2a97b9be2789a3905cb88737b1c79881302585801c69a3dd5fb230808b39db1352fc06e0b4a8", + "0x82fd14bdb335aa46f022dfe0ed4d631911e6b6f5eefb10d11e9e2e02a7df55012ed8162249d10b58eb76ced5a7b06cda", + "0xac39cb058df764e161db9c39b185f09aa210bddbd66f681f1697ddbe6b305735612d5dd321d3ffbb4876771bdb321e2f", + "0x858a3f7e57ccb81387caf8e89f9b6039e9aadeab06886d8688fe6427151a59ab2e77e85ba850c67d099965426c97779a", + "0xb57fb9ea623cec432946819937c6bded0b5d03c8c67b52b44a4b67d34adfb055e6cabca67a48e4d859b4be45162c5083", + "0xb84d2990b563d6d7fe1f4c1894989db25b81745090b94b1fe2ef708ac3b2110ef93d647820b2a51fcf78e3f00fef5412", + "0x817d85b9f5e1521733d2b1fa6d4f4957ac445dc803f97fc495e20b819b14e651332f9e0573d684b854fd47824c53f0e8", + "0xb09e18e97e93a8523101af594422fb71afc5b8826002314269016fcc1b44002d91bcb7c90d923d460f0cc03bddfe9af1", + "0xb867cbede82102de7cf6cd0dae68506869576eaa66c3fc806e73585310602682fc912dc37adf5ff6f0f34a07831735b1", + "0xb1126255798368b692f2796a3470ed16e5ffdee2d8c9e0f7ee3d2e92950c3e6365c32895171c3494aff2a6d6356f7e25", + "0xb05f0a0996dec16335c770a5df3f0b08e20020c838c2caaa1d3a4a2490ede98552f5de349de2ce6e4c4a839731d80919", + "0x98c512bb91c8fa191120ddf5d63c88076581cf41e15eec3c168822f12b3dd0ce4d6df74a7e3093d3e35cad1cb3135421", + "0x84ce38fd97f7f90012c2c1e59a67bf9f465a7ccfb6f308bdd0446cc82b8a26ff7c30e5c7cc375011718cad1b31adaa9f", + "0x93139db52c9fb96dee97a0825f21e34c5d6d36838e1e42f4d12d01eacbe94426c85a811fe16ca78e89e08f1c27383d28", + "0x81454037b1e7a1765f67e4288b8742eebf6d864d9b0f508ab44fa3243168ce0ed30cb5f33dfcdb995cd2c2710ff97a6d", + "0x828deb2a26efb2ff1842f735e2cc27162360f619b6e3e27a85bedf384912d4726bb2759a3016937973092ece1bf90540", + "0x87e5a7d4e7bd301078f625d9a99b99e6e8e1207c9f8a679f8ebbbfb467bfa0b5f7ef4a4d577c7d2670efa88221153012", + "0xb9dc9d0ea48deee201e34379447bec789c8924aecd030eeb93db159af77eff230976ef60ea9f4b4a9e9e95c1f9f4284e", + "0xaa6528268d46bf0627d87d58e243d3ac34b863513c725908a2617e4c6a46ccb1d8c8334bd6dd0eea7ffebec44259dae5", + "0x8d26c9ce07293f6a32a664d31e6df9a7ace47e6c38001635918efd9872aceab62de7757b13b783d422eb67bd28ce7bbb", + "0xb0d3ca88d9829a7459b89b0dcbdb8bbb5180b00d750bd959bd110f53c2dd5d4db554b6005c4765fbe7ec5903669e5ebc", + "0xa94d1c72bf3b2dc6bfebc9dee40f6a89a516b252bd9f4fad96f156e3dbfc151a9b8a02324d764c7656d59230a18eb61f", + "0x88996e79171e30b16505638d8ecb25afd875e5f3cc3e29860937f2b5e751c66e78dc77f744a0cc454a8a655142a93ffb", + "0xaf4d94f342665fe7ecda318de6cf1bc1c40c37dd83d060fedaf827459728152b5f0e280286ff5e6a0012036f6715f53f", + "0x96beaa7a2d565ec14a4e5cb895d33624c69da56b75c8d06ac729cb6d0cb64470ed4f9b0387083cd827b1609c8cabde8c", + "0x96b773fa2fcb7377bf71a7e286f37f1f24ee42cba5b4f33903c4566e5e5bcc501ea360e3c8435749107c3de84e272d8e", + "0xa69ac6218454c3f40ad0beb48821a218fb0a4f33ebade986d2fffd9a3900d8cfa613bc71676c46cfeaa5f644d1f239a9", + "0x857f139c08fcc45370f448ce3e4915bcb30f23daa4134407fc6d78efac7d718b2cd89e9a743eec7bf2cc0eccf55eb907", + "0xadeeba36af137fd3c371a2adbefea614c3ae3a69f8755ce892d0dd7102fb60717f5245d30119c69c582804e7e56f1626", + "0xafa97ca3548b35aeda6bfed7fbb39af907ed82a09348004d5705b4bb000173270ce44eb5d181819088aa5a2f20a547a2", + "0x8423bd2d07073b0e87819b4e81997e4d3188b0a5592621a30981dc0a5a9d0578fde1638a364f015078a001afb00891c2", + "0xb92e9d4ec3966981ee574695d6e4865810b8e75313e48c1e4bc5eebae77eb28740e97ecc3e5c42040f9eb1ee4b13b0ea", + "0xb07b218321d54cecfcd2ed54a5fd588a6be8d7a5b6a66dff7facfe061222c40553e076e57cbdfa0bdb08e0a009c94ba5", + "0xa71e1ae4d6096eac9ea4c21f621c875423de7c620544e520fb6ec3cb41a78554aedd79493cbd2c2ba4f0387f902ddd2a", + "0x807cdac291246a02f60c8937532c8969e689b1cfe811f239bfdee0791e7aa0545e9686cfb9ed0c1df84748e5efa5e3da", + "0xa1faeb4504c057304d27d54fb3ec681462384a354a4f0b6c759d4fa313253a789250c6b0f44f751b0718592637438a19", + "0x996bcd3215182d49f1cd15a05e1e0a4bf57e264400bf14f7253c6611d2571de7130cce81fd28e0411e0a80e9054f4f98", + "0x89d15b38f14bcd46f4b2dcae82b0e7bf9a35e40bf57aa947e9c4a8f87a440b5cea95229708de08ca596762062c34aaa0", + "0x8d8ddcaf79374c750b8b0b3d196acb6bb921e51b4619876a29d09161ba82a42271066187211ef746f9f40a5ca17b75f7", + "0xa3dc7f70f3a6c7edc483e712770abbaa94bfa3174cfee872b2cc011b267e0ef9baa1ab49e4a6c6c30dbba0e0a1237117", + "0xaa9e958bbdcb192b19c43fc6fd34afcd754949fdada98e9f4848e8db0e23acb27d19dd073c951a8819000f2356aa22e1", + "0xa4714e45ec853eadfe5c3bee7f683b81f97857bbd7833192a48936dd1460aee68f700a21658658b74b737c4fecf90c7f", + "0xa1ecab4215c1892e4a8ff3405d710163875e5dfef8a8cb84f5cac4e317d89c7696e3f496ed1747ca6f52b304190f4ba1", + "0xb9b48943eca3686219575026d395b969e6ff8159dc5317005df090e79d26901984e40ae4b1af060ed3ff6f42e0417d76", + "0x9644b9f90a66edb0396abd8c00066886f978ebf56fc22081031fbc9ce371bf9b04aa5a4ef59e59319b3a05bb7fb88b43", + "0xb2bb14f1c055a78596488e4e2d4135a6470c1ee43961952160b8498f674a4d23040606e937c02c1fc23dbd47e9bd4633", + "0x8c61f2fce9a42b94a389c7e52d7d093fc011099d0f4914f6d6f05b631df7b88182826edf9bbb1225971a080ca5c0d15a", + "0xaa6a7b8499cc7d256043eacad18528d38bf3be970bea4c6d4cb886690280bdb373688ceba3e506471e1d9493dc76f3f4", + "0x8127703363b3b35b06762c2353d4de82b7b85bb860db1028d3640f46bdb78f2d104fa77ee3e0d9db83833d2b12a966f8", + "0xb7b01f5909f2c66ae0fab156be5d79954e3a304615e1fe55945049dd4bd95f973bb3821117eb54db7e9ed1ee9a527652", + "0x8be47ba5dfe212420649193490838670c40540e0ea24adbab18c4a66e7ac3dcf94f068dec2533b60e08c1f64e7533e54", + "0x905a6c7e24b86aa54a05c329a6b4616d335bb0b1f1e9987562eee0acf82ad302c7c44981a1dd6b24c6121ca12fb92996", + "0x86969ccfd91deed93b355a2c21319e3bb08cc652b741463bf68c626b7ba2afce3f7cc397f2fb74588c2893477c948ae2", + "0xb5a9d20eb12c331d0d300fd4b85b0ac0bb74573178a5fac8ec9dce5e95acba07fab444260355ece442a846737a2dcd1c", + "0xa13497c11df21b11fc1a63b0ffdcf7f432da4dc2c98f8d07d36da4fa68aceb57af2158088e5b05e334fe0f264aeb7a97", + "0x882e4597cc66498a45e86a2ed9ee24652da4699af00ad35f73b5e74fde6ac3cee70630962d5ddd86162d4aaf11bbc11c", + "0xb748858c2bafa4a14ce44af35195e9c52aa75e109719243bbe278095acbfd6a7ae7e084caf8dae6939039b5a4e8fd675", + "0x83a2e0524507e74f51fe976441108f8226ba1b3a33f4e16ec45c5661ce80cb1840a93d17122cb8ca9e0f80d14f69877d", + "0x846cd2946c93ee5f24243d9ebc69936b3a1a6d59f45fec6c79b1eddf15ce30a8e73ad03cf606ee66baea3d8ff115f70f", + "0x8d98d0a3a94f6efe158f8423c041b546416145c5c2254bfa157efea0d1c99fe58acc7df6424ef29f75960b18d664ea4e", + "0xa39fa47e4b79f54dbf59d0b1726f1e78bc219fcfc56ad238c84b4b610e7892ff1e65d537baf5118a32f5e2eb80d5ee0c", + "0x8c30969a4519131de5e30121c84c04f67b98c8ad109fa4710dd3149cae303d51778add3f258f0482f1c89c169824dffc", + "0xaf7f80d141ceb78b4762015de17fef49d7ff6202d292e9604deb508272ee7569f7fd5be3b2438da1dfecf0c26533ef86", + "0x97cf82f70128251944d79b8845506975405bd720e150d836205b048ff36ba8801eb74cdcc6425f28f6bc0acec0a81463", + "0x8c276c876eb88688957d1868bf3a1462375e608ff72b49870a5dac82cbf6584e00e3f36f236f732348a47502ccf9539d", + "0x964765f1a5c8a41d8025ddf56dc01b78424703d8a64a4e5539e477cb2445cb541c70127c561e717256d13f91a830ba83", + "0xa2aacd9e21b8c8efaf2319611addea1b9f41430aee42e7f2a640cc693aa395287cc8fdc2806b76b577d84fbd05378ead", + "0xab11eabbf5be4345a77323a3b75f9ee93b011fd2a9d0154e88183cafe47f82a7888666af16b40d3cb677c94bcc755ff7", + "0xa0bfe715a7af5a29b1b6148b8cbee585d2b49fa6ce59bcd173ea3bbc60d71a62f9da27ffcbbd5a6da75502112fe44d70", + "0x902e6cc38ee42245103d90b65028a471bc7a48b825599d361aa81d8c56e0fcf9fbe8d4c13802040d2cfb85b7e022eea1", + "0x8832e2b5014fdef4003bdbb87e3298fdbdbbe49673f6b66e2373f1cb2605f9c4af2cdf9bfd45d1993208681d29ee1c9d", + "0xa7d39d3fa1ec1e0c87730fa43d4900e91932d1cafb36c76b2934907becf7d15a1d84d7234591ad4c322b5a24673bba8d", + "0x836ed5f09d99624204aa3aa7ac601980fda223f3b4b96b4a8fb235c574a3545d518787c12f81bd5851987f2860d41886", + "0x94235e94445e6086f6e9331923262070a4c2ed930ec519eabb8a30133bd4fc6debb99185f4b668431fae1b485c5c81b7", + "0x9828ffe20b9405f117dac044159be2d3c6e2b50ecdd1651d6a73f7633e6e2a7ba3d783ae939973604446d3a1ef0fb20f", + "0x92f03dc365dfe9154743ca70e6dd2758f064e3286fc543cf8c50f68effdf7c554bd17b3507c6ff4127046d9bbb5522ef", + "0x91ed07df479d8eb3d31292a0e987672a7f3d45ecafe72935b7abbc3f23493605134ce573f309e226c9efe830b6868220", + "0x93bee582661e6d6cefeff29002afc2f36dd2c13dbf33f0574c35b290ddc426170a5f7f196369ad592efcd72cfb6f8fc0", + "0x89a51467d966f48fed15dea5a12dda54d0015f69e2169b5e34f44c7b5a5d4c282d6f138116a0cd06a8476980e420f8d8", + "0xb8ccebc14b6679ba2399370848864f15f63512fd6139df7359b7b93e82c1007fd85137ecb0597294b46643e1a9e7ab5e", + "0x841fa301567fc57b2cd09508ce75326684e12bfb8add671dc208f579b2500b93d5b641e9f59bba798ed4ed1259757f7d", + "0xb3cb45c15eb00b4ccb7013299f761cb8fefc17adf6db50e9ecb8abe927a3bc7f28e359e64693813e078e1dac800ad55b", + "0x96e55d3b9f445f5679e34fa5425b3e87cb221cfbdd07f8353868c7f7f4ba388ee3841cb9a1d638583bc20d03a9d071f2", + "0xa7dee9377de740270c5b57cf86699004ba8dc2766af56b388b5cb0814ec71bb99ecf43ee3d82a552733854ecc7def0fe", + "0xb129dfff23b3c1c95ddb214c4711961fcb129efe2b6557ec9e116ada909593d0d2eec2c628434493393c58c52aa86847", + "0xaed2670e201cb3e38a8be3c86735a4d76255e1e5a4c67b91df6ed262d09c8d10b0a3891da3e6ab934058cc9a7178931b", + "0xb20b8921ae52e5b3c94fa3a8b46489044174f7b897779e7763d6eb419e808d76705b7e7ba5131576f425aa81b6b0de53", + "0xa7e45bbc3ba1bc36617291ba7663806e247f1b57a89e31520c64a90cbf8d426cac2e2f381338baf78c8f92fdbbcb7026", + "0xa99e651e73a507e9e663e2364fcc193ec77e8afdc08c2bed6ad864e49b537ec31e9114ee72291a7657899f2033a849e2", + "0xaf966033636c2e9e8280d173f556fe07f8b6940bbcf6b2df7e2165c30bea66cced2596f6c17ca7c1aa0e614174953ba9", + "0xb69ca7a79e3d55ef21e0ebdc6f0c4bd17182d30cf6290cccca7d2551c91c12b966020d8e40e4ee4179488c9809c03ae4", + "0xb981cd36244e035fef043f70b1d7188d7cd045b4de0581c459fc5730e10eb7f3d5893b54cc4243849c0855e4e621167a", + "0xb20fea858a36921b35a3051ce787b73f70fdecd3fef283c15a2eb1bffb1dcba5991eee4a047ce4e87802da923fd9457b", + "0xb040e6f2e56dc1860274c263d4045837456f74b354a679f6b5ea70919835ebe5d32bf1f519e218730096c98ff396dc9d", + "0x8d2dd60e702c923a7204b530e7d6c193c6f93ca648c4f7bb38f4edbeb0aaed84184213afafb8db6aeb9197c24364276c", + "0x95dfa7348709e43d71285b28a0bfad3ca805b6ed4ae99753e9f736c79d58a35a3a50b42760ccdd03eda50f6e59494968", + "0xb8585632a13f18c139a411bb2f02df809591834d127cd1ff081e26d0abfe0e3fbb54abea26538b25a0dcb4d7e969590e", + "0xb46ba47858a29c6d523c9982660949567666daf2582b93393a4802a9e077eedbc0d49d454731696bc8e46ca50c7caa40", + "0x84b756b901b98a4404e58d70f39f6ccac877146c866732ae65e7e82727448d1550343bf7cdff1bfd4ee1ed73793db255", + "0x83e5be888eaf877a2c755897410865f64a6d1169a8ccf0336092f3932abab915e542ab75a35ffe016042340d581ee987", + "0x8cb274fc39285aed451a7def72cfbf73168ee10be02affe355a2bf87cf361a81ad284e9334cf00c5bf99a13d9f75e116", + "0x91ff6220924b94ae13f50eeac16a159232e4f16a73fbd5c22c0e185cd1998403904d36bad203baa82b85819ee4a8ac10", + "0x87f46e08e09aea2ab37b55fc300689d9b58ff3e72f1cffe023386035888f714fac4673c7c5193d3f3f3c568c640694f0", + "0x835d7d84ca7641e1b15095830114aa6072fe12260d2202456cafe2308c22651af9ffbcf6b7e56af97167dd0c4e2a4cf2", + "0x91202183f79794f114fd9e3b9bd05553c0e8985919965101a57d97ef666b028863e6cea9735af016dc1864f1542dee51", + "0x81ab2b02a9b0a490a74ae615ddd4fe560734c1bfdde6b8dd13303c1481ba0e8ab14473535a93cfe4e824a0ab29445f8c", + "0x8a32d73f4fc006551d4e2c61eec6130355ec9b8c39a65c24ec1edc00e80155ca83a8ef2455e892521a3d47634d82a987", + "0xaf70d7b8f13bc90193cc1cfb0c400c4224cf10f1887848aa93e6380f7087782fc41a159926ab53c53eb95c2383b1a849", + "0x989bf42f9d357c51774f1c7c0f7c0c46a8cb7398a74497141c32685be098e38b4230ffe833a6d880ec391a35b1a747b6", + "0x94cb6715ee95700020c630b8c19e35f231de970219bd7e6ba7ced01899197da473b6c45cacfab0d652ddaf547b4ea58c", + "0xb12e3331f1f7d7458393a785e22e9a5e1d1daea521b4e78c0ee8ca59b41ade1735a29820e18f6afb2f2c3c56fecc16b6", + "0xad4b7cf654349d136fb41fb0dd65b588199f68b462b05f5c4e5c2b468bfaa6c26329033e3c3f7873dc8ace89cf873ea5", + "0xa3279969e1ab596df0559ffc5ac7a6dc849680354e01c3f4fd34c6413a3f9f046f89c1e1be0b315d8b6dfab3d23d5c14", + "0xac74cc5562836ed89d09a9ae6a3644c936d64bdda9e77659d9982f1be29541b03ef2723236d5465e398373ea19a4ccc6", + "0x98138ebce1af531dd8b631b3e74c84f0c700355a2a9bde31e5e51bb10c8bbd766559c63f6041f4002568803fe08438e0", + "0x9006445da131349fe5714e0777a4f82a82da343612589a0c1596393e8b6894ce1cf42784f95ff67a8384ffe1f1a4ad76", + "0x88502a84a85e4ce54cfed297b5d355867cc770a8ffd0714a6f23b1ab320a9903c6e42809e034bb67dbf94c4fc0d9c790", + "0xaa8b4bf123d1a6ccaa44b86be8f980005f2a0a388a76cb111b0e85cd072ef64167fb0c097c7b23c4bca64c0260f6cce0", + "0xad49eb35dfea9feabb513a78dd1152ad7eba22fbb02a80cefc494a7037699c8df81202dfec12acc1b9e33ad680cb72d2", + "0x8694da730231b29afd5196371ddcb15b4dcc499574bdd063f4864ab80749833ea38ab8b0ca1629a367fe378e87a60a86", + "0x8eca7b488e810c479e7e32e24b8afcd837f7df183fe4f621a0336b53a9ed77603c84bdc365d8be68179a32b71a1deb7e", + "0x8875cd3e23c7e1af55af1b091025a08255743984186770bcd43f30b4a58d175cfdf1984bad97a15e08dac2da27198c3d", + "0xabdafcf58ec72997e494d4714645f40d09dcd0fbd0733e640eca44eeea67c25bb0c270299c459991f2fae59d13b4f4d5", + "0x8f040970141e61489284f3efd907705eae6ec757fe8e1d284eac123d313e9ac1e8dc14ae3f04d281e1effc49d5d2f51d", + "0xa7ff115f0d2dbf66c0e8770b3d05157b37357b9e33e9a447f0f3fa9da69ad04e371fd1e4848cfb9e8d05e3165bd969d8", + "0xa39b1a8c39d317fcc97bf6c396e6ed4a85640aeeadbf45166bd02bc3bdfb6266509159c03afd492e642384c635b824c0", + "0xa2e1b90f3dd2d0038eaa5be52127844ccf35d997143179d95ffd3749c0896398b130094d01eb1bb31ffe80ef34b42b48", + "0xa2bbe31f89b0c3c375ffaf63c8b7831860a921d5e388eb7907dbf61f2601ea40db86bb3952ecaa26a5eca4317a848ff9", + "0x87d885bb0f2ce04b40ce94d2557c15f1698dc652e938f9a2d69a73ccf4899e08eafa1a59a20cae92823795f5b94f04b9", + "0x8f7746370f8a24a2889d351f3e36b8a7d60e75e50e8f5abeea7dafc75441e95915721654e61ceac51bb6f112780d352c", + "0xa7272847526ed3d9e0d0fea1d8685b07b5b908971490bf8a46748c8b1783c629b8644feb5bac772ae615daae383d5e72", + "0x978c9aa2996d8bd6fda7e0393fa8b38747f8f99712427705c00f6e9a12c36f8d8b4cedb03fcb9867155cbddb5200e6e1", + "0xa4dec4a2354b2b32434c5bcdc380bf84580c6f9940f94dc0498a5bfe89c675a0921e66b807a3d859a6059a464cb2a9ac", + "0x99459ddecc7abce437f68722dae556d8ffaf8ed974f459e52e6d4a64f176caa4d42c2f2ec57e8a5b5f2034638e8acb0a", + "0x928c68c0c9213fe6258ab5bb0c693d97203d15da359784de7824dec143212da57d062a1fc70a79172cee31adc7aff382", + "0xaad3f318f1622ea87e12541dfd982d71629b8f1ded4c301f9f6b6af9432716ad057773c33bdaa6f15dc151b0ee4505ea", + "0x8eb8e978f149a983fd6ad01773f9aacf57bd0cc622d8a301e404184b37e610123dd081faeda571a0ab1f149a3960af10", + "0x851e7191d7b94bd422bcece5b92609fc1b1c8556229bc53e32963b2d2fd1cacd8ce5da9040b599eca6e610540f8a7987", + "0x9414157fe9d50e5a0b5a7397417681bcb3a651eec1cab63f2a88d5df68ab1fef6e4c1d7ba657cbaf241a7cb790297633", + "0xb5cb2dafdc5408959780754a58b2da55b2a9136672ebca42f34da4e329ddc89360e7218cde3efdbf784ddb390deacc57", + "0xac6b70f65503a8e94b773fda3e72615745824930114fe72b6d833484285462392617c1b2eea4a250fedbee88f503f3ba", + "0xb0829a5312f9ac6c06fddee2f835a3452fe994f6d42c9edfc390d7d5b3240ca544433b544cbbddd6516b38a6d5d7c21d", + "0x95f8e2c59905957e34d53be3d6fb85732f834e2cb9ab4c333fea2f502452a87ccd035fc9075d7c0bd8530bb0a0c96527", + "0xb93f279b7045f2d97c674495f6e69a3e352f32f43cc60300193b936c2850b2805c15457251f7e3f633f435cb2b60405c", + "0x915abf16cba1a0b655b92a8a70c03e7fb306b86f3bbfb66967ca63e64c003b59c7a5953675efa4fa0bce9bed536b6700", + "0xac2047f50a319d09df1ec44d71afdcec5ac3bd2765dc98aba347734aa780863545df9f6d71214d443e3f37edc0dae45a", + "0xad49c74ddb24c8a26b14ec08bc807313c77c5967fbb36237f55994d7511bbac8d7e7b9b8ec53eb1b3b066989f078dbd9", + "0x961483105f605e959213fe9e8a52b76dac62d7efd2319ec71fc4e92d68fbe44cd2f65d7adefb2eb64d591b91648b8085", + "0xb67fcafc97d8df2b3075bbff7b3d7471dbf1f3048f309e55d5e2c5bcbc7a73aebcb0697859be9f387cbc7ce98041e154", + "0x8da70ac16468cab6066992389cb37c79ff5e0babbe67d76878aef9408b9597a3dc2eb5de87428bc761a0d78957b0eb28", + "0xaec0ce89770d299b631f15ae12f94b1e1014ac57d38fcf037c2c7712d770d074affa06e97c60691bad8733874b6ad2ed", + "0x8b702c85fa4c915a09fc86507f44d7aeda0993b77af87780d70cc98d580c6e996b64b7c16cdb4dd4562cb0f75da36ee7", + "0xaaeb43aa472aac2253e211fd1066c3a5422ea041cef20168702d0618a1a742a44f7fb30a76677640fea1a24e7fae1996", + "0xa8820e92825d6e02b9b4ad5ebc86161d3244cddd3d244333ba1576b6ae10948145b68d9e926bf6b7a2c25dab4cf43f3e", + "0x8ffdae28a1f1d15d7ffa473628a66ee9a739073f59ba781248286b39cb8f7255f66d62337064246713cbb5017e615174", + "0xadfc5dd142b7911326d8424881d5d92006f3b17de4cce91674d6ea37f00fbb266c791ac13f6c7a0f61d04f2a952e6a04", + "0x87f98982444bf661f539bec73a10256f079a4baa88a1cea0351ae3de929e1c500485b2d1b5d933063cd7d9123d5050e4", + "0x8f217ba4dd404c5ee384f0c9a126686db001ff0344c01c82174c5e5ef89d1a241b146008c534b13a0da6c8afe7450fbb", + "0xafc85476dddaf1cbb4ba8b22186789f3818c7964f9f613e55010278800cd95422702248bdf9c73760702ef24854795ec", + "0xa59e0f6ac2ccdfbd01f002008034390c0ea78716f5e0de4e474e3558755705c9c7afb6e3c5c4370e7bbc85958a9c7a63", + "0x97c0695c58d792ec31d9b86d3b2fc1382f0855057b24d5f6a54c41f76f9e2f52882cadc89a8b2f121530e7f1393faa95", + "0x8e49112de0b2649c08a96cf737af68fa8055f1af594846a2d0534c94df6f926f200405edaa6e6ac9db7e380707a2571d", + "0x99a1bd83a7ac5f8d77ddf044c80ebfc5745b998714696d67b94d185c97e9d6db989bacac646d9def463127a8b2febc00", + "0xaba80725f9f9f7abe10760eca73ba427ca8df864a157122eb9af828a05b0199de3add02019a297750bdab5380e505c58", + "0xae18f62573275c1eb268f74c5e54e8958547f9e7d1d36a05b084eb53e5704fafe2200b8aff95cc7e9af5be2391c42b7c", + "0x908b8031d09d22b2aefeaa876a998e0a97c7a1070aad9e9c97836cc5aa6d2d5ef94230e1222074837b5e21b4e6490f01", + "0xb3132282e8b41ca6789ec5c43c1fecf3a65b8eefbc2f3d10f746a843b9ba4ce6db664678e75e424f7b11a00c1440de15", + "0xa1eb49440cc106ebc09cf198c93e8070271eb5a936d31c04858a2b311a037350100c7957d5545c9653f396aa968b91f4", + "0x81df6ad1bdd5eee4cc2f94318467b8602d15cc1be2b48b09ade12cc46ee05cbaaf77a20397e5015030b1f1db5dd9dac0", + "0x87236c68a2a93c8442d15d7f1d1dc01d1fd123439c183e1d843f4ddd2bcf638c128f66f1ef9b710e5d1f64a52726007a", + "0x84f2e7f85563bb2f61b10a712c7605d63f79af5be0dba056814fd3efebc20e9c53227c56577b72c68d185571b775eff6", + "0xa36d4ae06688ece2927aeb2c7f058a3cd2aa1de1601282d4e688e1d76ef20728b892928deda2314eba41675eba3912f1", + "0xb8326dcbcdcfce017b263c456c47692fb476c4225c95981666fff0b7d4522fc23b7f12273f0f47cf0442662124e6648f", + "0x84c66463ab277cda2cc7007d0509269e89cdd41c5e0d3773a92615f0fc5da63811186b05d7a11088048a5d4834a7e0df", + "0xb20d3571d970712ef4699b0e7034fd269c361f53e1572e2ea2676b4245e992d43b8b5931a801439a44d977a988cc360b", + "0x94dba6007e6d4998ca1eb84aa8e2a7e9f5c164b9d80df2825f2208ce5640a05aacac2e4f08918268990f43ae1ccab69a", + "0xa1c25f0b3ef9d1982153207570d9ce8d692e1b6963b509958dc4d9bcd80074bb221c46804a6d9a29e76149cc7787c282", + "0x8857748fcdab1199fc96084323a81d3bd8b5a7f0b1abc5bc3b5252a19268344e2e7d2d086c90fc9b5fa4b92feedb93a4", + "0x8b9c1d841447354b6c086549e4d1d435ab64c13933488c34bc30f0f6eb36c5c5b838b7b6bb018542247edd1ada091045", + "0x8f5b655416da0e719a204fc567e93792c301acb4374cf7bbabc6ce51dbeaaadfd75c2db0e16ce073ab8e91fd3d7ea9d4", + "0x90f2846b19be46a75c5cd0cafefcf9192e6fd80c479e8d6320c4b8d8d7d96703c9e77ff31a67afa9858e6b7bde1f7cce", + "0xa53e383947fd98aa1a55ac956214b46b20a52758461e8ba41341a23a835ebb713038bf048edb1202bbfd0b56a96bf292", + "0x9542d7debbcfb9cda6fa279c699a7b655c03b9a9b456a5d3cfc41a826c94eafa43e01155a29e39ff0bcd965f4c0c512d", + "0xa43792864ec5fc549f7afc02622454afc0e425c310c4039ba615067243ebb26a4c7ebfd19bd4d57ff412a4bb2a7958a0", + "0xb85123950e30c048465bf32365d24a5d4b21fffc6183cdbf71643a07b87463989b72dd9a6a47f134856f704909a6b38f", + "0x944ea689aec1376f855c0bc9c51378ad06ff758a2c075b95a60b535b88b36eca0be11e4edb5152e98cb2137d6e749f27", + "0xa6bef52cda22325e4c62d323e2a0e3fa91c5552fcfce951edfd52ad6f652bfdcc2341f1cd349e6b5d447924dc569bfe2", + "0xb56bff8ffe981bfcb30791836da10b87f2ccbe17ed969e7f7a650af07d27ae0223805b1264d985148208483be50578a6", + "0x8b209cac898dd580c82d854a553e2517497ad1a4cd198e1360b8b50639b380aee70ee4b87625d9b2278228ff644cd25c", + "0x877cce233fec74c7158b3c5bf108365e98238418b8a71f058f1aca44a0fd3a1021e3e9025bd11fe244d9fe0f5034ce7f", + "0xb1b871aeedb03d6f6accc99816b89f5958178738d8d8cd9717527d04363c80fdb5f6848122ae19fdbc450cfa11e753c8", + "0x858aca51b9e5b0a724e88688d5124eb24c9faf01a3d465e74d31de6da315f311143f22f60201ea09f62c92f61f09d889", + "0x8521d409615dfc8c8289e00f6aaa6297c2c4e1439b25952afd76aac641b81c70b9cef07cd58c1c0198382bddd2bd8544", + "0x88647c3e41666b88acca42505f1f5da226937e0522b538fe0cebb724e9a99730ca2522989e94a96cac94109aef675c0f", + "0xb417fdaf719caf38854e89ce52031b30ce61a632e6c3135adec9002280e022d82ab0ea4ac5ebdb21f1f0169e4c37bcda", + "0x9367a6feb5e23ea2eab8ddd5e7bdf32b4d2419fad1c71a1ed327b77362d8942dad971a1c2e6f7073885149cdf0a0c339", + "0xa71c5c08d50c57d094d6a4f02e97d3799bada92f238ffc07bd223bbe8379507b7310d20b28f5bbbf331e5e153515e491", + "0x9630a9a3bcb044b51299c4d3d3388a4ff47308dd27be3229601985478c0f6b55faa7e20815d8694f910611396a9d0d45", + "0xb0bfaf56a5aa59b48960aa7c1617e832e65c823523fb2a5cd44ba606800501cf873e8db1d0dda64065285743dc40786e" + ], "g1_lagrange": [ "0xa0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654", "0x8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57", diff --git a/go.mod b/go.mod index 2f5f7a3fa..519531c8c 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/cockroachdb/pebble v1.1.2 github.com/consensys/gnark v0.13.0 github.com/consensys/gnark-crypto v0.18.0 + github.com/crate-crypto/go-eth-kzg v1.3.0 github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/davecgh/go-spew v1.1.1 @@ -23,7 +24,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 - github.com/ethereum/c-kzg-4844 v1.0.0 + github.com/ethereum/c-kzg-4844/v2 v2.1.0 github.com/ethereum/go-verkle v0.2.2 github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.3 diff --git a/go.sum b/go.sum index 053e13aec..ebb1fadc6 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= +github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= @@ -169,8 +171,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= -github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= +github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= From 9a81183845e5752a80dd91eae346126a31b06250 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Wed, 30 Apr 2025 11:00:17 +0800 Subject: [PATCH 324/354] cmd/geth: print crit log if chain config is not compatible (#31743) --- cmd/geth/chaincmd.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c57a9a947..1c82ac7c0 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -246,10 +246,13 @@ func initGenesis(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) defer triedb.Close() - _, hash, _, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) + _, hash, compatErr, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } + if compatErr != nil { + utils.Fatalf("Failed to write chain config: %v", err) + } log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash) return nil From d050a8d3089cb075a483d3f52ff4a89fbcbffd36 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Wed, 30 Apr 2025 05:02:11 +0200 Subject: [PATCH 325/354] eth/fetcher: define BatchSize as a constant (#31742) --- eth/fetcher/tx_fetcher.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index ff17ae494..98a1c6e9a 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -69,6 +69,9 @@ const ( // txGatherSlack is the interval used to collate almost-expired announces // with network fetches. txGatherSlack = 100 * time.Millisecond + + // addTxsBatchSize it the max number of transactions to add in a single batch from a peer. + addTxsBatchSize = 128 ) var ( @@ -329,8 +332,8 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) metas = make([]txMetadata, 0, len(txs)) ) // proceed in batches - for i := 0; i < len(txs); i += 128 { - end := i + 128 + for i := 0; i < len(txs); i += addTxsBatchSize { + end := i + addTxsBatchSize if end > len(txs) { end = len(txs) } @@ -372,7 +375,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) otherRejectMeter.Mark(otherreject) // If 'other reject' is >25% of the deliveries in any batch, sleep a bit. - if otherreject > 128/4 { + if otherreject > addTxsBatchSize/4 { time.Sleep(200 * time.Millisecond) log.Debug("Peer delivering stale transactions", "peer", peer, "rejected", otherreject) } From 25c2db8669518bf2012e3256b1fab28aa2400f8b Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 30 Apr 2025 09:23:08 +0200 Subject: [PATCH 326/354] core/filtermaps: do not derive full receipts during rendering (#31716) This changes the filtermaps to only pull up the raw receipts, not the derived receipts which saves a lot of allocations. During normal execution this will reduce the allocations of the whole geth node by ~15%. --- core/blockchain_reader.go | 8 ++++++++ core/filtermaps/chain_view.go | 14 ++++++++++++++ core/filtermaps/indexer_test.go | 7 +++++++ core/filtermaps/map_renderer.go | 4 ++-- eth/filters/filter_system_test.go | 7 +++++++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 43639642f..a1ad119cd 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -251,6 +251,14 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { return receipts } +func (bc *BlockChain) GetRawReceiptsByHash(hash common.Hash) types.Receipts { + number := rawdb.ReadHeaderNumber(bc.db, hash) + if number == nil { + return nil + } + return rawdb.ReadRawReceipts(bc.db, hash, *number) +} + // GetUnclesInChain retrieves all the uncles from a given block backwards until // a specific distance is reached. func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types.Header { diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index aa74f3901..63df2cfb6 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -29,6 +29,7 @@ type blockchain interface { GetHeader(hash common.Hash, number uint64) *types.Header GetCanonicalHash(number uint64) common.Hash GetReceiptsByHash(hash common.Hash) types.Receipts + GetRawReceiptsByHash(hash common.Hash) types.Receipts } // ChainView represents an immutable view of a chain with a block id and a set @@ -102,10 +103,23 @@ func (cv *ChainView) Receipts(number uint64) types.Receipts { blockHash := cv.BlockHash(number) if blockHash == (common.Hash{}) { log.Error("Chain view: block hash unavailable", "number", number, "head", cv.headNumber) + return nil } return cv.chain.GetReceiptsByHash(blockHash) } +// RawReceipts returns the set of receipts belonging to the block at the given +// block number. Does not derive the fields of the receipts, should only be +// used during creation of the filter maps, please use cv.Receipts during querying. +func (cv *ChainView) RawReceipts(number uint64) types.Receipts { + blockHash := cv.BlockHash(number) + if blockHash == (common.Hash{}) { + log.Error("Chain view: block hash unavailable", "number", number, "head", cv.headNumber) + return nil + } + return cv.chain.GetRawReceiptsByHash(blockHash) +} + // SharedRange returns the block range shared by two chain views. func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { cv.lock.Lock() diff --git a/core/filtermaps/indexer_test.go b/core/filtermaps/indexer_test.go index e60130ba4..2782b2cbe 100644 --- a/core/filtermaps/indexer_test.go +++ b/core/filtermaps/indexer_test.go @@ -515,6 +515,13 @@ func (tc *testChain) GetReceiptsByHash(hash common.Hash) types.Receipts { return tc.receipts[hash] } +func (tc *testChain) GetRawReceiptsByHash(hash common.Hash) types.Receipts { + tc.lock.RLock() + defer tc.lock.RUnlock() + + return tc.receipts[hash] +} + func (tc *testChain) addBlocks(count, maxTxPerBlock, maxLogsPerReceipt, maxTopicsPerLog int, random bool) { tc.lock.Lock() blockGen := func(i int, gen *core.BlockGen) { diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index f59a01c03..74baec6a1 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -693,7 +693,7 @@ func (f *FilterMaps) newLogIteratorFromMapBoundary(mapIndex uint32, startBlock, return nil, fmt.Errorf("iterator entry point %d after target chain head block %d", startBlock, f.targetView.HeadNumber()) } // get block receipts - receipts := f.targetView.Receipts(startBlock) + receipts := f.targetView.RawReceipts(startBlock) if receipts == nil { return nil, fmt.Errorf("receipts not found for start block %d", startBlock) } @@ -760,7 +760,7 @@ func (l *logIterator) next() error { if l.delimiter { l.delimiter = false l.blockNumber++ - l.receipts = l.chainView.Receipts(l.blockNumber) + l.receipts = l.chainView.RawReceipts(l.blockNumber) if l.receipts == nil { return fmt.Errorf("receipts not found for block %d", l.blockNumber) } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 701c5533f..434af7fa6 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -82,6 +82,13 @@ func (b *testBackend) GetReceiptsByHash(hash common.Hash) types.Receipts { return r } +func (b *testBackend) GetRawReceiptsByHash(hash common.Hash) types.Receipts { + if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { + return rawdb.ReadRawReceipts(b.db, hash, *number) + } + return nil +} + func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { var ( hash common.Hash From 681bdcdd53a98e25f3b1b304aea883fe29afef56 Mon Sep 17 00:00:00 2001 From: ericxtheodore Date: Wed, 30 Apr 2025 18:37:48 +0800 Subject: [PATCH 327/354] cmd/geth: fix compatErr in initGenesis (#31746) --- cmd/geth/chaincmd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 1c82ac7c0..a947f35f2 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -251,7 +251,7 @@ func initGenesis(ctx *cli.Context) error { utils.Fatalf("Failed to write genesis block: %v", err) } if compatErr != nil { - utils.Fatalf("Failed to write chain config: %v", err) + utils.Fatalf("Failed to write chain config: %v", compatErr) } log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash) From de80f1eff39e25b6884285ff66df979f5856247e Mon Sep 17 00:00:00 2001 From: Shude Li Date: Fri, 2 May 2025 21:19:54 +0800 Subject: [PATCH 328/354] ethclient: fix retrieval of pending block (#31504) Since the block hash is not returned for pending blocks, ethclient cannot unmarshal into RPC block. This makes hash optional on rpc block and compute the hash locally for pending blocks to correctly key the tx sender cache. https://github.com/ethereum/go-ethereum/blob/a82303f4e3cedcebe31540a53dde4f24fc93da80/internal/ethapi/api.go#L500-L504 --------- Co-authored-by: lightclient --- ethclient/ethclient.go | 10 ++++++++-- ethclient/ethclient_test.go | 33 +++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 80f06e82d..090b1d981 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -131,7 +131,7 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb } type rpcBlock struct { - Hash common.Hash `json:"hash"` + Hash *common.Hash `json:"hash"` Transactions []rpcTransaction `json:"transactions"` UncleHashes []common.Hash `json:"uncles"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` @@ -158,6 +158,12 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface if err := json.Unmarshal(raw, &body); err != nil { return nil, err } + // Pending blocks don't return a block hash, compute it for sender caching. + if body.Hash == nil { + tmp := head.Hash() + body.Hash = &tmp + } + // Quick-verify transaction and uncle lists. This mostly helps with debugging the server. if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { return nil, errors.New("server returned non-empty uncle list but block header indicates no uncles") @@ -199,7 +205,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface txs := make([]*types.Transaction, len(body.Transactions)) for i, tx := range body.Transactions { if tx.From != nil { - setSenderFromServer(tx.tx, *tx.From, body.Hash) + setSenderFromServer(tx.tx, *tx.From, *body.Hash) } txs[i] = tx.tx } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index ff591389c..ca06bf5b2 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -307,6 +307,12 @@ func testTransactionInBlock(t *testing.T, client *rpc.Client) { if tx.Hash() != testTx2.Hash() { t.Fatalf("unexpected transaction: %v", tx) } + + // Test pending block + _, err = ec.BlockByNumber(context.Background(), big.NewInt(int64(rpc.PendingBlockNumber))) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } } func testChainID(t *testing.T, client *rpc.Client) { @@ -637,6 +643,21 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { if gas != 21000 { t.Fatalf("unexpected gas limit: %v", gas) } + + // Verify that sender address of pending transaction is saved in cache. + pendingBlock, err := ec.BlockByNumber(context.Background(), big.NewInt(int64(rpc.PendingBlockNumber))) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + // No additional RPC should be required, ensure the server is not asked by + // canceling the context. + sender, err := ec.TransactionSender(newCanceledContext(), pendingBlock.Transactions()[0], pendingBlock.Hash(), 0) + if err != nil { + t.Fatal("unable to recover sender:", err) + } + if sender != testAddr { + t.Fatal("wrong sender:", sender) + } } func testTransactionSender(t *testing.T, client *rpc.Client) { @@ -658,10 +679,7 @@ func testTransactionSender(t *testing.T, client *rpc.Client) { // The sender address is cached in tx1, so no additional RPC should be required in // TransactionSender. Ensure the server is not asked by canceling the context here. - canceledCtx, cancel := context.WithCancel(context.Background()) - cancel() - <-canceledCtx.Done() // Ensure the close of the Done channel - sender1, err := ec.TransactionSender(canceledCtx, tx1, block2.Hash(), 0) + sender1, err := ec.TransactionSender(newCanceledContext(), tx1, block2.Hash(), 0) if err != nil { t.Fatal(err) } @@ -680,6 +698,13 @@ func testTransactionSender(t *testing.T, client *rpc.Client) { } } +func newCanceledContext() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + <-ctx.Done() // Ensure the close of the Done channel + return ctx +} + func sendTransaction(ec *ethclient.Client) error { chainID, err := ec.ChainID(context.Background()) if err != nil { From 44160d2ed60a464dc3ef5271fddc06c0803ffcaa Mon Sep 17 00:00:00 2001 From: Abel <1033309821@qq.com> Date: Fri, 2 May 2025 22:31:50 +0800 Subject: [PATCH 329/354] cmd/devp2p: test for non-existent block request (#31506) Add tests for GetBlockHeaders that verify client does not disconnect when unlikely block numbers are requested, e.g. max uint64. --------- Co-authored-by: lightclient --- cmd/devp2p/internal/ethtest/suite.go | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 8ebbe2a05..a16d308df 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -70,6 +70,7 @@ func (s *Suite) EthTests() []utesting.Test { {Name: "Status", Fn: s.TestStatus}, // get block headers {Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders}, + {Name: "GetNonexistentBlockHeaders", Fn: s.TestGetNonexistentBlockHeaders}, {Name: "SimultaneousRequests", Fn: s.TestSimultaneousRequests}, {Name: "SameRequestID", Fn: s.TestSameRequestID}, {Name: "ZeroRequestID", Fn: s.TestZeroRequestID}, @@ -158,6 +159,48 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) { } } +func (s *Suite) TestGetNonexistentBlockHeaders(t *utesting.T) { + t.Log(`This test sends GetBlockHeaders requests for nonexistent blocks (using max uint64 value) +to check if the node disconnects after receiving multiple invalid requests.`) + + conn, err := s.dial() + if err != nil { + t.Fatalf("dial failed: %v", err) + } + defer conn.Close() + + if err := conn.peer(s.chain, nil); err != nil { + t.Fatalf("peering failed: %v", err) + } + + // Create request with max uint64 value for a nonexistent block + badReq := ð.GetBlockHeadersPacket{ + GetBlockHeadersRequest: ð.GetBlockHeadersRequest{ + Origin: eth.HashOrNumber{Number: ^uint64(0)}, + Amount: 1, + Skip: 0, + Reverse: false, + }, + } + + // Send request 10 times. Some clients are lient on the first few invalids. + for i := 0; i < 10; i++ { + badReq.RequestId = uint64(i) + if err := conn.Write(ethProto, eth.GetBlockHeadersMsg, badReq); err != nil { + if err == errDisc { + t.Fatalf("peer disconnected after %d requests", i+1) + } + t.Fatalf("write failed: %v", err) + } + } + + // Check if peer disconnects at the end. + code, _, err := conn.Read() + if err == errDisc || code == discMsg { + t.Fatal("peer improperly disconnected") + } +} + func (s *Suite) TestSimultaneousRequests(t *utesting.T) { t.Log(`This test requests blocks headers from the node, performing two requests concurrently, with different request IDs.`) From ef254558d40bf301eb1111bdaf3bf78bc4104b87 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Fri, 2 May 2025 23:21:17 +0800 Subject: [PATCH 330/354] node: avoid double close resp.Body (#31710) The functions `rpcRequest` and `batchRpcRequest` call `baseRpcRequest`. And `resp.Body` will be closed in the function `baseRpcRequest` later by `t.Cleanup`: ```go func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) *http.Response { // ...... t.Cleanup(func() { resp.Body.Close() }) return resp } ``` --- node/rpcstack_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index eb0bbac93..54e58cccb 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -570,7 +570,6 @@ func TestHTTPWriteTimeout(t *testing.T) { // Send normal request t.Run("message", func(t *testing.T) { resp := rpcRequest(t, url, "test_sleep") - defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) @@ -584,7 +583,6 @@ func TestHTTPWriteTimeout(t *testing.T) { t.Run("batch", func(t *testing.T) { want := fmt.Sprintf("[%s,%s,%s]", greetRes, timeoutRes, timeoutRes) resp := batchRpcRequest(t, url, []string{"test_greet", "test_sleep", "test_greet"}) - defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) From 0b9c453aba8679726733af7434b2e4a651c8e82a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 2 May 2025 23:43:06 +0800 Subject: [PATCH 331/354] core, eth/gasestimator: introduce MaxGasUsed for estimation (#31735) This PR improves gas estimation for data-heavy transactions which hit the floor data gas cost. --- core/state_transition.go | 26 ++++++++++++++++---------- eth/gasestimator/gasestimator.go | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 59be0a81c..4403cd2a7 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -36,10 +36,10 @@ import ( // ExecutionResult includes all output after executing given evm // message no matter the execution itself is successful or not. type ExecutionResult struct { - UsedGas uint64 // Total used gas, not including the refunded gas - RefundedGas uint64 // Total gas refunded after execution - Err error // Any error encountered during the execution(listed in core/vm/errors.go) - ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) + UsedGas uint64 // Total used gas, not including the refunded gas + MaxUsedGas uint64 // Maximum gas consumed during execution, excluding gas refunds. + Err error // Any error encountered during the execution(listed in core/vm/errors.go) + ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) } // Unwrap returns the internal evm error which allows us for further @@ -549,9 +549,12 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ret, st.gasRemaining, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value) } + // Record the gas used excluding gas refunds. This value represents the actual + // gas allowance required to complete execution. + peakGasUsed := st.gasUsed() + // Compute refund counter, capped to a refund quotient. - gasRefund := st.calcRefund() - st.gasRemaining += gasRefund + st.gasRemaining += st.calcRefund() if rules.IsPrague { // After EIP-7623: Data-heavy transactions pay the floor gas. if st.gasUsed() < floorDataGas { @@ -561,6 +564,9 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) } } + if peakGasUsed < floorDataGas { + peakGasUsed = floorDataGas + } } st.returnGas() @@ -589,10 +595,10 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } return &ExecutionResult{ - UsedGas: st.gasUsed(), - RefundedGas: gasRefund, - Err: vmerr, - ReturnData: ret, + UsedGas: st.gasUsed(), + MaxUsedGas: peakGasUsed, + Err: vmerr, + ReturnData: ret, }, nil } diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index fc8e3a2e4..98a4f74b3 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -144,7 +144,7 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin // There's a fairly high chance for the transaction to execute successfully // with gasLimit set to the first execution's usedGas + gasRefund. Explicitly // check that gas amount and use as a limit for the binary search. - optimisticGasLimit := (result.UsedGas + result.RefundedGas + params.CallStipend) * 64 / 63 + optimisticGasLimit := (result.MaxUsedGas + params.CallStipend) * 64 / 63 if optimisticGasLimit < hi { failed, _, err = execute(ctx, call, opts, optimisticGasLimit) if err != nil { From 9c59ee15d52c3da3e90ece87defae9a09c314455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Fri, 2 May 2025 17:50:22 +0200 Subject: [PATCH 332/354] core/filtermaps: fix log value search range (#31734) This PR fixes the out-of-range block number logic of `getBlockLvPointer` which sometimes caused searches to fail if the head was updated in the wrong moment. This logic ensures that querying the pointer of a future block returns the pointer after the last fully indexed block (instead of failing) and therefore an async range update will not cause the search to fail. Earier this behaviour only worked when `headIndexed` was true and `headDelimiter` pointed to the end of the indexed range. Now it also works for an unfinished index. This logic is also moved from `FilterMaps.getBlockLvPointer` to `FilterMapsMatcherBackend.GetBlockLvPointer` because it is only required by the search anyways. `FilterMaps.getBlockLvPointer` now only returns a pointer for existing blocks, consistently with how it is used in the indexer/renderer. Note that this unhandled case has been present in the code for a long time but went unnoticed because either one of two previously fixed bugs did prevent it from being triggered; the incorrectly positive `tempRange.headIndexed` (fixed in https://github.com/ethereum/go-ethereum/pull/31680), though caused other problems, prevented this one from being triggered as with a positive `headIndexed` no database read was triggered in `getBlockLvPointer`. Also, the unnecessary `indexLock` in `synced()` (fixed in https://github.com/ethereum/go-ethereum/pull/31708) usually did prevent the search seeing the temp range and therefore avoided noticeable issues. --- core/filtermaps/filtermaps.go | 6 +----- core/filtermaps/matcher_backend.go | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index 3da7f4b72..ffe2bfcbb 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -662,15 +662,11 @@ func (f *FilterMaps) mapRowIndex(mapIndex, rowIndex uint32) uint64 { } // getBlockLvPointer returns the starting log value index where the log values -// generated by the given block are located. If blockNumber is beyond the current -// head then the first unoccupied log value index is returned. +// generated by the given block are located. // // Note that this function assumes that the indexer read lock is being held when // called from outside the indexerLoop goroutine. func (f *FilterMaps) getBlockLvPointer(blockNumber uint64) (uint64, error) { - if blockNumber >= f.indexedRange.blocks.AfterLast() && f.indexedRange.headIndexed { - return f.indexedRange.headDelimiter + 1, nil - } if lvPointer, ok := f.lvPointerCache.Get(blockNumber); ok { return lvPointer, nil } diff --git a/core/filtermaps/matcher_backend.go b/core/filtermaps/matcher_backend.go index 975178375..e19a63e18 100644 --- a/core/filtermaps/matcher_backend.go +++ b/core/filtermaps/matcher_backend.go @@ -82,13 +82,26 @@ func (fm *FilterMapsMatcherBackend) GetFilterMapRow(ctx context.Context, mapInde } // GetBlockLvPointer returns the starting log value index where the log values -// generated by the given block are located. If blockNumber is beyond the current -// head then the first unoccupied log value index is returned. +// generated by the given block are located. If blockNumber is beyond the last +// indexed block then the pointer will point right after this block, ensuring +// that the matcher does not fail and can return a set of results where the +// valid range is correct. // GetBlockLvPointer implements MatcherBackend. func (fm *FilterMapsMatcherBackend) GetBlockLvPointer(ctx context.Context, blockNumber uint64) (uint64, error) { fm.f.indexLock.RLock() defer fm.f.indexLock.RUnlock() + if blockNumber >= fm.f.indexedRange.blocks.AfterLast() { + if fm.f.indexedRange.headIndexed { + // return index after head block + return fm.f.indexedRange.headDelimiter + 1, nil + } + if fm.f.indexedRange.blocks.Count() > 0 { + // return index at the beginning of the last, partially indexed + // block (after the last fully indexed one) + blockNumber = fm.f.indexedRange.blocks.Last() + } + } return fm.f.getBlockLvPointer(blockNumber) } From 931074edbd3695473c4d1e6a61b2a873d445ec3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Sat, 3 May 2025 18:40:24 +0200 Subject: [PATCH 333/354] core/filtermaps: fix log index initialization (#31750) This PR fixes an initialization bug that in some cases caused the map renderer to leave the last, partially rendered map as is and resume rendering from the next map. At initialization we check whether the existing rendered maps are consistent with the current chain view and revert them if necessary. Until now this happened through an ugly hacky solution, a "limited" chain view that was supposed to trigger a rollback of some maps in the renderer logic if necessary. This whole setup worked under assumptions that just weren't true any more. As a result it always tried to revert the last map but also it did not shorten the indexed range, only set `headIndexed` to false which indicated to the renderer logic that the last map is fully populated (which it wasn't). Now an explicit rollback of any unusable (reorged) maps happens at startup, which also means that no hacky chain view is necessary, as soon as the new `FilterMaps` is returned, the indexed range and view are consistent with each other. In the first commit an extra check is also added to `writeFinishedMaps` so that if there is ever again a bug that would result in a gapped index then it will not break the db with writing the incomplete data. Instead it will return an indexing error which causes the indexer to revert to unindexed mode and print an error log instantly. Hopefully this will not ever happen in the future, but in order to test this safeguard check I manually triggered the bug with only the first commit enabled, which caused an indexing error as expected. With the second commit added (the actual fix) the same operation succeeded without any issues. Note that the database version is also bumped in this PR in order to enforce a full reindexing as any existing database might be potentially broken. Fixes https://github.com/ethereum/go-ethereum/issues/31729 --- core/filtermaps/chain_view.go | 8 ----- core/filtermaps/filtermaps.go | 63 ++++++++++++++++++--------------- core/filtermaps/map_renderer.go | 18 +++++++--- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/core/filtermaps/chain_view.go b/core/filtermaps/chain_view.go index 63df2cfb6..874ff19e3 100644 --- a/core/filtermaps/chain_view.go +++ b/core/filtermaps/chain_view.go @@ -135,14 +135,6 @@ func (cv *ChainView) SharedRange(cv2 *ChainView) common.Range[uint64] { return common.NewRange(0, sharedLen) } -// limitedView returns a new chain view that is a truncated version of the parent view. -func (cv *ChainView) limitedView(newHead uint64) *ChainView { - if newHead >= cv.headNumber { - return cv - } - return NewChainView(cv.chain, newHead, cv.BlockHash(newHead)) -} - // equalViews returns true if the two chain views are equivalent. func equalViews(cv1, cv2 *ChainView) bool { if cv1 == nil || cv2 == nil { diff --git a/core/filtermaps/filtermaps.go b/core/filtermaps/filtermaps.go index ffe2bfcbb..b2c63f2e5 100644 --- a/core/filtermaps/filtermaps.go +++ b/core/filtermaps/filtermaps.go @@ -50,7 +50,7 @@ var ( ) const ( - databaseVersion = 1 // reindexed if database version does not match + databaseVersion = 2 // reindexed if database version does not match cachedLastBlocks = 1000 // last block of map pointers cachedLvPointers = 1000 // first log value pointer of block pointers cachedBaseRows = 100 // groups of base layer filter row data @@ -244,6 +244,8 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f disabledCh: make(chan struct{}), exportFileName: config.ExportFileName, Params: params, + targetView: initView, + indexedView: initView, indexedRange: filterMapsRange{ initialized: initialized, headIndexed: rs.HeadIndexed, @@ -265,16 +267,8 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f baseRowsCache: lru.NewCache[uint64, [][]uint32](cachedBaseRows), renderSnapshots: lru.NewCache[uint64, *renderedMap](cachedRenderSnapshots), } + f.checkRevertRange() // revert maps that are inconsistent with the current chain view - // Set initial indexer target. - f.targetView = initView - if f.indexedRange.initialized { - f.indexedView = f.initChainView(f.targetView) - f.indexedRange.headIndexed = f.indexedRange.blocks.AfterLast() == f.indexedView.HeadNumber()+1 - if !f.indexedRange.headIndexed { - f.indexedRange.headDelimiter = 0 - } - } if f.indexedRange.hasIndexedBlocks() { log.Info("Initialized log indexer", "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), @@ -303,29 +297,40 @@ func (f *FilterMaps) Stop() { f.closeWg.Wait() } -// initChainView returns a chain view consistent with both the current target -// view and the current state of the log index as found in the database, based -// on the last block of stored maps. -// Note that the returned view might be shorter than the existing index if -// the latest maps are not consistent with targetView. -func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView { - mapIndex := f.indexedRange.maps.AfterLast() - for { - var ok bool - mapIndex, ok = f.lastMapBoundaryBefore(mapIndex) - if !ok { - break +// checkRevertRange checks whether the existing index is consistent with the +// current indexed view and reverts inconsistent maps if necessary. +func (f *FilterMaps) checkRevertRange() { + if f.indexedRange.maps.Count() == 0 { + return + } + lastMap := f.indexedRange.maps.Last() + lastBlockNumber, lastBlockId, err := f.getLastBlockOfMap(lastMap) + if err != nil { + log.Error("Error initializing log index database; resetting log index", "error", err) + f.reset() + return + } + for lastBlockNumber > f.indexedView.HeadNumber() || f.indexedView.BlockId(lastBlockNumber) != lastBlockId { + // revert last map + if f.indexedRange.maps.Count() == 1 { + f.reset() // reset database if no rendered maps remained + return } - lastBlockNumber, lastBlockId, err := f.getLastBlockOfMap(mapIndex) + lastMap-- + newRange := f.indexedRange + newRange.maps.SetLast(lastMap) + lastBlockNumber, lastBlockId, err = f.getLastBlockOfMap(lastMap) if err != nil { - log.Error("Could not initialize indexed chain view", "error", err) - break - } - if lastBlockNumber <= chainView.HeadNumber() && chainView.BlockId(lastBlockNumber) == lastBlockId { - return chainView.limitedView(lastBlockNumber) + log.Error("Error initializing log index database; resetting log index", "error", err) + f.reset() + return } + newRange.blocks.SetAfterLast(lastBlockNumber) // lastBlockNumber is probably partially indexed + newRange.headIndexed = false + newRange.headDelimiter = 0 + // only shorten range and leave map data; next head render will overwrite it + f.setRange(f.db, f.indexedView, newRange, false) } - return chainView.limitedView(0) } // reset un-initializes the FilterMaps structure and removes all related data from diff --git a/core/filtermaps/map_renderer.go b/core/filtermaps/map_renderer.go index 74baec6a1..5379cbb15 100644 --- a/core/filtermaps/map_renderer.go +++ b/core/filtermaps/map_renderer.go @@ -468,15 +468,25 @@ func (r *mapRenderer) writeFinishedMaps(pauseCb func() bool) error { r.f.filterMapCache.Remove(mapIndex) } } + var blockNumber uint64 + if r.finished.First() > 0 { + // in order to always ensure continuous block pointers, initialize + // blockNumber based on the last block of the previous map, then verify + // against the first block associated with each rendered map + lastBlock, _, err := r.f.getLastBlockOfMap(r.finished.First() - 1) + if err != nil { + return fmt.Errorf("failed to get last block of previous map %d: %v", r.finished.First()-1, err) + } + blockNumber = lastBlock + 1 + } // add or update block pointers - blockNumber := r.finishedMaps[r.finished.First()].firstBlock() for mapIndex := range r.finished.Iter() { renderedMap := r.finishedMaps[mapIndex] - r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId) - checkWriteCnt() if blockNumber != renderedMap.firstBlock() { - panic("non-continuous block numbers") + return fmt.Errorf("non-continuous block numbers in rendered map %d (next expected: %d first rendered: %d)", mapIndex, blockNumber, renderedMap.firstBlock()) } + r.f.storeLastBlockOfMap(batch, mapIndex, renderedMap.lastBlock, renderedMap.lastBlockId) + checkWriteCnt() for _, lvPtr := range renderedMap.blockLvPtrs { r.f.storeBlockLvPointer(batch, blockNumber, lvPtr) checkWriteCnt() From 4ea56910193fe7f8587f1b633ea2bd8d54d5a9a0 Mon Sep 17 00:00:00 2001 From: Miro Date: Sat, 3 May 2025 22:16:33 -0400 Subject: [PATCH 334/354] core/txpool/legacypool: fix data race of pricedList access (#31758) --- core/txpool/legacypool/legacypool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 92d31e1d9..c2ea8e8a5 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -2059,7 +2059,7 @@ func (pool *LegacyPool) Clear() { pool.reserver.Release(addr) } pool.all.Clear() - pool.priced = newPricedList(pool.all) + pool.priced.Reheap() pool.pending = make(map[common.Address]*list) pool.queue = make(map[common.Address]*list) pool.pendingNonces = newNoncer(pool.currentState) From 6f2d0f9846b349fb11633ada8a51ac0590bdaf80 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Sun, 4 May 2025 20:40:31 +0800 Subject: [PATCH 335/354] params: fix comment for `DefaultBlobSchedule` (#31760) `DefaultBlobSchedule` is actually used downstream to calculate blob fees (e.g., [src](https://github.com/ethereum-optimism/optimism/blob/601a380e47853c2922ea1f8944cda05f0eac16f4/op-service/eth/blob.go#L301)), this PR makes it explicit that these params are for `Ethereum prod` instead of `test chains`. --- params/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/config.go b/params/config.go index db0ae6cd8..31b9557fe 100644 --- a/params/config.go +++ b/params/config.go @@ -358,7 +358,7 @@ var ( Max: 9, UpdateFraction: 5007716, } - // DefaultBlobSchedule is the latest configured blob schedule for test chains. + // DefaultBlobSchedule is the latest configured blob schedule for Ethereum mainnet. DefaultBlobSchedule = &BlobScheduleConfig{ Cancun: DefaultCancunBlobConfig, Prague: DefaultPragueBlobConfig, From bbfdfef11156175329cecf190279a0fc29bcb7c0 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 5 May 2025 04:07:55 +0200 Subject: [PATCH 336/354] core: reduce load on txindexer from API (#31752) Fixes https://github.com/ethereum/go-ethereum/issues/31732. This logic was removed in the recent refactoring in the txindexer to handle history cutoff (#31393). It was first introduced in this PR: https://github.com/ethereum/go-ethereum/pull/28908. I have tested it and it works as an alternative to #31745. This PR packs 3 changes to the flow of fetching txs from the API: - It caches the indexer tail after each run is over to avoid hitting the db all the time as was done originally in #28908. - Changes `backend.GetTransaction`. It doesn't return an error anymore when tx indexer is in progress. It shifts the responsibility to the caller to check the progress. The reason is that in most cases we anyway check the txpool for the tx. If it was indeed a pending tx we can avoid the indexer progress check. --------- Co-authored-by: Gary Rong --- core/blockchain_reader.go | 54 ++++++++---------- core/txindexer.go | 72 ++++++++++++++---------- core/txindexer_test.go | 22 +++----- eth/api_backend.go | 28 +++++---- eth/tracers/api.go | 14 +++-- eth/tracers/api_test.go | 8 ++- ethstats/ethstats.go | 6 +- graphql/graphql.go | 6 +- internal/ethapi/api.go | 46 ++++++++------- internal/ethapi/api_test.go | 11 +++- internal/ethapi/backend.go | 5 +- internal/ethapi/transaction_args_test.go | 9 ++- 12 files changed, 150 insertions(+), 131 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index a1ad119cd..606752c83 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -287,42 +287,20 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max // GetTransactionLookup retrieves the lookup along with the transaction // itself associate with the given transaction hash. // -// An error will be returned if the transaction is not found, and background -// indexing for transactions is still in progress. The transaction might be -// reachable shortly once it's indexed. -// -// A null will be returned in the transaction is not found and background -// transaction indexing is already finished. The transaction is not existent -// from the node's perspective. -func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction, error) { +// A null will be returned if the transaction is not found. This can be due to +// the transaction indexer not being finished. The caller must explicitly check +// the indexer progress. +func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction) { bc.txLookupLock.RLock() defer bc.txLookupLock.RUnlock() // Short circuit if the txlookup already in the cache, retrieve otherwise if item, exist := bc.txLookupCache.Get(hash); exist { - return item.lookup, item.transaction, nil + return item.lookup, item.transaction } tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash) if tx == nil { - progress, err := bc.TxIndexProgress() - if err != nil { - // No error is returned if the transaction indexing progress is unreachable - // due to unexpected internal errors. In such cases, it is impossible to - // determine whether the transaction does not exist or has simply not been - // indexed yet without a progress marker. - // - // In such scenarios, the transaction is treated as unreachable, though - // this is clearly an unintended and unexpected situation. - return nil, nil, nil - } - // The transaction indexing is not finished yet, returning an - // error to explicitly indicate it. - if !progress.Done() { - return nil, nil, errors.New("transaction indexing still in progress") - } - // The transaction is already indexed, the transaction is either - // not existent or not in the range of index, returning null. - return nil, nil, nil + return nil, nil } lookup := &rawdb.LegacyTxLookupEntry{ BlockHash: blockHash, @@ -333,7 +311,23 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo lookup: lookup, transaction: tx, }) - return lookup, tx, nil + return lookup, tx +} + +// TxIndexDone returns true if the transaction indexer has finished indexing. +func (bc *BlockChain) TxIndexDone() bool { + progress, err := bc.TxIndexProgress() + if err != nil { + // No error is returned if the transaction indexing progress is unreachable + // due to unexpected internal errors. In such cases, it is impossible to + // determine whether the transaction does not exist or has simply not been + // indexed yet without a progress marker. + // + // In such scenarios, the transaction is treated as unreachable, though + // this is clearly an unintended and unexpected situation. + return true + } + return progress.Done() } // GetTd retrieves a block's total difficulty in the canonical chain from the @@ -435,7 +429,7 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) { if bc.txIndexer == nil { return TxIndexProgress{}, errors.New("tx indexer is not enabled") } - return bc.txIndexer.txIndexProgress() + return bc.txIndexer.txIndexProgress(), nil } // HistoryPruningCutoff returns the configured history pruning point. diff --git a/core/txindexer.go b/core/txindexer.go index 64a2e8c49..587118ed7 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -17,8 +17,8 @@ package core import ( - "errors" "fmt" + "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -47,26 +47,38 @@ type txIndexer struct { // and all others shouldn't. limit uint64 + // The current head of blockchain for transaction indexing. This field + // is accessed by both the indexer and the indexing progress queries. + head atomic.Uint64 + + // The current tail of the indexed transactions, null indicates + // that no transactions have been indexed yet. + // + // This field is accessed by both the indexer and the indexing + // progress queries. + tail atomic.Pointer[uint64] + // cutoff denotes the block number before which the chain segment should // be pruned and not available locally. - cutoff uint64 - db ethdb.Database - progress chan chan TxIndexProgress - term chan chan struct{} - closed chan struct{} + cutoff uint64 + db ethdb.Database + term chan chan struct{} + closed chan struct{} } // newTxIndexer initializes the transaction indexer. func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { cutoff, _ := chain.HistoryPruningCutoff() indexer := &txIndexer{ - limit: limit, - cutoff: cutoff, - db: chain.db, - progress: make(chan chan TxIndexProgress), - term: make(chan chan struct{}), - closed: make(chan struct{}), + limit: limit, + cutoff: cutoff, + db: chain.db, + term: make(chan chan struct{}), + closed: make(chan struct{}), } + indexer.head.Store(indexer.resolveHead()) + indexer.tail.Store(rawdb.ReadTxIndexTail(chain.db)) + go indexer.loop(chain) var msg string @@ -154,6 +166,7 @@ func (indexer *txIndexer) repair(head uint64) { // A crash may occur between the two delete operations, // potentially leaving dangling indexes in the database. // However, this is considered acceptable. + indexer.tail.Store(nil) rawdb.DeleteTxIndexTail(indexer.db) rawdb.DeleteAllTxLookupEntries(indexer.db, nil) log.Warn("Purge transaction indexes", "head", head, "tail", *tail) @@ -174,6 +187,7 @@ func (indexer *txIndexer) repair(head uint64) { // Traversing the database directly within the transaction // index namespace might be slow and expensive, but we // have no choice. + indexer.tail.Store(nil) rawdb.DeleteTxIndexTail(indexer.db) rawdb.DeleteAllTxLookupEntries(indexer.db, nil) log.Warn("Purge transaction indexes", "head", head, "cutoff", indexer.cutoff) @@ -187,6 +201,7 @@ func (indexer *txIndexer) repair(head uint64) { // A crash may occur between the two delete operations, // potentially leaving dangling indexes in the database. // However, this is considered acceptable. + indexer.tail.Store(&indexer.cutoff) rawdb.WriteTxIndexTail(indexer.db, indexer.cutoff) rawdb.DeleteAllTxLookupEntries(indexer.db, func(txhash common.Hash, blob []byte) bool { n := rawdb.DecodeTxLookupEntry(blob, indexer.db) @@ -216,16 +231,15 @@ func (indexer *txIndexer) loop(chain *BlockChain) { // Listening to chain events and manipulate the transaction indexes. var ( - stop chan struct{} // Non-nil if background routine is active - done chan struct{} // Non-nil if background routine is active - head = indexer.resolveHead() // The latest announced chain head - + stop chan struct{} // Non-nil if background routine is active + done chan struct{} // Non-nil if background routine is active headCh = make(chan ChainHeadEvent) sub = chain.SubscribeChainHeadEvent(headCh) ) defer sub.Unsubscribe() // Validate the transaction indexes and repair if necessary + head := indexer.head.Load() indexer.repair(head) // Launch the initial processing if chain is not empty (head != genesis). @@ -238,17 +252,18 @@ func (indexer *txIndexer) loop(chain *BlockChain) { for { select { case h := <-headCh: + indexer.head.Store(h.Header.Number.Uint64()) if done == nil { stop = make(chan struct{}) done = make(chan struct{}) go indexer.run(h.Header.Number.Uint64(), stop, done) } - head = h.Header.Number.Uint64() + case <-done: stop = nil done = nil - case ch := <-indexer.progress: - ch <- indexer.report(head) + indexer.tail.Store(rawdb.ReadTxIndexTail(indexer.db)) + case ch := <-indexer.term: if stop != nil { close(stop) @@ -264,7 +279,7 @@ func (indexer *txIndexer) loop(chain *BlockChain) { } // report returns the tx indexing progress. -func (indexer *txIndexer) report(head uint64) TxIndexProgress { +func (indexer *txIndexer) report(head uint64, tail *uint64) TxIndexProgress { // Special case if the head is even below the cutoff, // nothing to index. if head < indexer.cutoff { @@ -284,7 +299,6 @@ func (indexer *txIndexer) report(head uint64) TxIndexProgress { } // Compute how many blocks have been indexed var indexed uint64 - tail := rawdb.ReadTxIndexTail(indexer.db) if tail != nil { indexed = head - *tail + 1 } @@ -300,16 +314,12 @@ func (indexer *txIndexer) report(head uint64) TxIndexProgress { } } -// txIndexProgress retrieves the tx indexing progress, or an error if the -// background tx indexer is already stopped. -func (indexer *txIndexer) txIndexProgress() (TxIndexProgress, error) { - ch := make(chan TxIndexProgress, 1) - select { - case indexer.progress <- ch: - return <-ch, nil - case <-indexer.closed: - return TxIndexProgress{}, errors.New("indexer is closed") - } +// txIndexProgress retrieves the transaction indexing progress. The reported +// progress may slightly lag behind the actual indexing state, as the tail is +// only updated at the end of each indexing operation. However, this delay is +// considered acceptable. +func (indexer *txIndexer) txIndexProgress() TxIndexProgress { + return indexer.report(indexer.head.Load(), indexer.tail.Load()) } // close shutdown the indexer. Safe to be called for multiple times. diff --git a/core/txindexer_test.go b/core/txindexer_test.go index b189a0668..b0233d5d4 100644 --- a/core/txindexer_test.go +++ b/core/txindexer_test.go @@ -121,9 +121,8 @@ func TestTxIndexer(t *testing.T) { // Index the initial blocks from ancient store indexer := &txIndexer{ - limit: 0, - db: db, - progress: make(chan chan TxIndexProgress), + limit: 0, + db: db, } for i, limit := range c.limits { indexer.limit = limit @@ -241,9 +240,8 @@ func TestTxIndexerRepair(t *testing.T) { // Index the initial blocks from ancient store indexer := &txIndexer{ - limit: c.limit, - db: db, - progress: make(chan chan TxIndexProgress), + limit: c.limit, + db: db, } indexer.run(chainHead, make(chan struct{}), make(chan struct{})) @@ -432,15 +430,11 @@ func TestTxIndexerReport(t *testing.T) { // Index the initial blocks from ancient store indexer := &txIndexer{ - limit: c.limit, - cutoff: c.cutoff, - db: db, - progress: make(chan chan TxIndexProgress), + limit: c.limit, + cutoff: c.cutoff, + db: db, } - if c.tail != nil { - rawdb.WriteTxIndexTail(db, *c.tail) - } - p := indexer.report(c.head) + p := indexer.report(c.head, c.tail) if p.Indexed != c.expIndexed { t.Fatalf("Unexpected indexed: %d, expected: %d", p.Indexed, c.expIndexed) } diff --git a/eth/api_backend.go b/eth/api_backend.go index 4c3a49edb..f89f7bd7b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -331,22 +331,20 @@ func (b *EthAPIBackend) GetCachedTransaction(nonce uint64, sender common.Address // GetTransaction retrieves the lookup along with the transaction itself associate // with the given transaction hash. // -// An error will be returned if the transaction is not found, and background -// indexing for transactions is still in progress. The error is used to indicate the -// scenario explicitly that the transaction might be reachable shortly. -// -// A null will be returned in the transaction is not found and background transaction -// indexing is already finished. The transaction is not existent from the perspective -// of node. -func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { - lookup, tx, err := b.eth.blockchain.GetTransactionLookup(txHash) - if err != nil { - return false, nil, common.Hash{}, 0, 0, err - } +// A null will be returned if the transaction is not found. The transaction is not +// existent from the node's perspective. This can be due to the transaction indexer +// not being finished. The caller must explicitly check the indexer progress. +func (b *EthAPIBackend) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { + lookup, tx := b.eth.blockchain.GetTransactionLookup(txHash) if lookup == nil || tx == nil { - return false, nil, common.Hash{}, 0, 0, nil + return false, nil, common.Hash{}, 0, 0 } - return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index, nil + return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index +} + +// TxIndexDone returns true if the transaction indexer has finished indexing. +func (b *EthAPIBackend) TxIndexDone() bool { + return b.eth.blockchain.TxIndexDone() } func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { @@ -373,7 +371,7 @@ func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.S return b.eth.txPool.SubscribeTransactions(ch, true) } -func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress { +func (b *EthAPIBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress { prog := b.eth.Downloader().Progress() if txProg, err := b.eth.blockchain.TxIndexProgress(); err == nil { prog.TxIndexFinishedBlocks = txProg.Indexed diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 5b0eb2912..469d24b66 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -82,7 +82,8 @@ type Backend interface { HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) - GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) + GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) + TxIndexDone() bool RPCGasCap() uint64 ChainConfig() *params.ChainConfig Engine() consensus.Engine @@ -858,12 +859,13 @@ func containsTx(block *types.Block, hash common.Hash) bool { // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { - found, _, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) - if err != nil { - return nil, ethapi.NewTxIndexingError() - } - // Only mined txes are supported + found, _, blockHash, blockNumber, index := api.backend.GetTransaction(hash) if !found { + // Warn in case tx indexer is not done. + if !api.backend.TxIndexDone() { + return nil, ethapi.NewTxIndexingError() + } + // Only mined txes are supported return nil, errTxNotFound } // It shouldn't happen in practice. diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index f179a6dcf..3fb7fcf8e 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -116,9 +116,13 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) return b.chain.GetBlockByNumber(uint64(number)), nil } -func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { +func (b *testBackend) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash) - return tx != nil, tx, hash, blockNumber, index, nil + return tx != nil, tx, hash, blockNumber, index +} + +func (b *testBackend) TxIndexDone() bool { + return true } func (b *testBackend) RPCGasCap() uint64 { diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index c656b1230..29ff0378f 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -68,7 +68,7 @@ type backend interface { HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) GetTd(ctx context.Context, hash common.Hash) *big.Int Stats() (pending int, queued int) - SyncProgress() ethereum.SyncProgress + SyncProgress(ctx context.Context) ethereum.SyncProgress } // fullNodeBackend encompasses the functionality necessary for a full node @@ -785,7 +785,7 @@ func (s *Service) reportStats(conn *connWrapper) error { mining = miningBackend.Miner().Mining() } - sync := fullBackend.SyncProgress() + sync := fullBackend.SyncProgress(context.Background()) syncing = !sync.Done() price, _ := fullBackend.SuggestGasTipCap(context.Background()) @@ -794,7 +794,7 @@ func (s *Service) reportStats(conn *connWrapper) error { gasprice += int(basefee.Uint64()) } } else { - sync := s.backend.SyncProgress() + sync := s.backend.SyncProgress(context.Background()) syncing = !sync.Done() } // Assemble the node stats and send it to the server diff --git a/graphql/graphql.go b/graphql/graphql.go index bfdadd647..42c7f8701 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -230,7 +230,7 @@ func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block) return t.tx, t.block } // Try to return an already finalized transaction - found, tx, blockHash, _, index, _ := t.r.backend.GetTransaction(ctx, t.hash) + found, tx, blockHash, _, index := t.r.backend.GetTransaction(t.hash) if found { t.tx = tx blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) @@ -1536,8 +1536,8 @@ func (s *SyncState) TxIndexRemainingBlocks() hexutil.Uint64 { // - healingBytecode: number of bytecodes pending // - txIndexFinishedBlocks: number of blocks whose transactions are indexed // - txIndexRemainingBlocks: number of blocks whose transactions are not indexed yet -func (r *Resolver) Syncing() (*SyncState, error) { - progress := r.backend.SyncProgress() +func (r *Resolver) Syncing(ctx context.Context) (*SyncState, error) { + progress := r.backend.SyncProgress(ctx) // Return not syncing if the synchronisation already completed if progress.Done() { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 5a44ff183..0a6427014 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -169,8 +169,8 @@ func (api *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (api *EthereumAPI) Syncing() (interface{}, error) { - progress := api.b.SyncProgress() +func (api *EthereumAPI) Syncing(ctx context.Context) (interface{}, error) { + progress := api.b.SyncProgress(ctx) // Return not syncing if the synchronisation already completed if progress.Done() { @@ -1443,17 +1443,19 @@ func (api *TransactionAPI) GetTransactionCount(ctx context.Context, address comm // GetTransactionByHash returns the transaction for the given hash func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction - found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) + found, tx, blockHash, blockNumber, index := api.b.GetTransaction(hash) if !found { // No finalized transaction, try to retrieve it from the pool if tx := api.b.GetPoolTransaction(hash); tx != nil { baseFee := api.nextBaseFeeCache.getNextBaseFee(api.b.CurrentHeader().Number.Int64()) return NewRPCPendingTransaction(tx, api.b.CurrentHeader(), api.b.ChainConfig(), baseFee), nil } - if err == nil { - return nil, nil + // If also not in the pool there is a chance the tx indexer is still in progress. + if !api.b.TxIndexDone() { + return nil, NewTxIndexingError() } - return nil, NewTxIndexingError() + // If the transaction is not found in the pool and the indexer is done, return nil + return nil, nil } header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { @@ -1465,15 +1467,17 @@ func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common // GetRawTransactionByHash returns the bytes of the transaction for the given hash. func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) + found, tx, _, _, _ := api.b.GetTransaction(hash) if !found { if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } - if err == nil { - return nil, nil + // If also not in the pool there is a chance the tx indexer is still in progress. + if !api.b.TxIndexDone() { + return nil, NewTxIndexingError() } - return nil, NewTxIndexingError() + // If the transaction is not found in the pool and the indexer is done, return nil + return nil, nil } return tx.MarshalBinary() } @@ -1513,12 +1517,14 @@ func (s *TransactionAPI) GetCachedTransaction(ctx context.Context, Nonce hexutil // GetTransactionReceipt returns the transaction receipt for the given transaction hash. func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { - found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) - if err != nil { - return nil, NewTxIndexingError() // transaction is not fully indexed - } + found, tx, blockHash, blockNumber, index := api.b.GetTransaction(hash) if !found { - return nil, nil // transaction is not existent or reachable + // Make sure indexer is done. + if !api.b.TxIndexDone() { + return nil, NewTxIndexingError() + } + // No such tx. + return nil, nil } header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { @@ -1925,15 +1931,17 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block // GetRawTransaction returns the bytes of the transaction for the given hash. func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) + found, tx, _, _, _ := api.b.GetTransaction(hash) if !found { if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } - if err == nil { - return nil, nil + // If also not in the pool there is a chance the tx indexer is still in progress. + if !api.b.TxIndexDone() { + return nil, NewTxIndexingError() } - return nil, NewTxIndexingError() + // Transaction is not found in the pool and the indexer is done. + return nil, nil } return tx.MarshalBinary() } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 76fba32e4..89666c444 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -472,7 +472,9 @@ func (b *testBackend) setPendingBlock(block *types.Block) { b.pending = block } -func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } +func (b testBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress { + return ethereum.SyncProgress{} +} func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return big.NewInt(0), nil } @@ -604,9 +606,12 @@ func (b testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeade func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { panic("implement me") } -func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { +func (b testBackend) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash) - return true, tx, blockHash, blockNumber, index, nil + return true, tx, blockHash, blockNumber, index +} +func (b testBackend) TxIndexDone() bool { + return true } func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 9b48c3dcf..bae02972b 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -41,7 +41,7 @@ import ( // both full and light clients) with access to necessary functions. type Backend interface { // General Ethereum API - SyncProgress() ethereum.SyncProgress + SyncProgress(ctx context.Context) ethereum.SyncProgress SuggestGasTipCap(ctx context.Context) (*big.Int, error) EnvelopeFee(ctx context.Context) (*big.Int, error) @@ -76,7 +76,8 @@ type Backend interface { // Transaction pool API SendTx(ctx context.Context, signedTx *types.Transaction) error - GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) + GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) + TxIndexDone() bool GetPoolTransactions() (types.Transactions, error) GetPoolTransaction(txHash common.Hash) *types.Transaction GetCachedTransaction(nonce uint64, sender common.Address) *types.Transaction diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 424b746ab..c93b0b9f8 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -329,7 +329,9 @@ func (b *backendMock) CurrentHeader() *types.Header { return b.current } func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } // Other methods needed to implement Backend interface. -func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } +func (b *backendMock) SyncProgress(ctx context.Context) ethereum.SyncProgress { + return ethereum.SyncProgress{} +} func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { return nil, nil, nil, nil, nil, nil, nil } @@ -388,9 +390,10 @@ func (b *backendMock) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHead return nil } func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } -func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { - return false, nil, [32]byte{}, 0, 0, nil +func (b *backendMock) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { + return false, nil, [32]byte{}, 0, 0 } +func (b *backendMock) TxIndexDone() bool { return true } func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil } func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil } func (b *backendMock) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { From 121ca0443420051bff04bfd18e03acf067eb1244 Mon Sep 17 00:00:00 2001 From: Marcel <153717436+MonkeyMarcel@users.noreply.github.com> Date: Mon, 5 May 2025 10:09:58 +0800 Subject: [PATCH 337/354] logs(indexer)Clean up log format in head index progress messages (#31761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates the log entries in `core/filtermaps/indexer.go` to remove double quotes around keys like "first block" and "last block", changing them to `firstblock` and `lastblock`. This brings them in line with the general logging style used across the codebase, where log keys are unquoted single words. For example, the log: ` INFO [...] "first block"=..., "last block"=...` Is now rendered as: ` INFO [...] firstblock=..., lastblock=...` This change improves readability and maintains consistency with logs such as: ` INFO [...] number=2 sealhash=... uncles=0 txs=0 ...` No functional behavior is changed — this is purely a formatting cleanup for better developer experience. --- core/filtermaps/indexer.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/filtermaps/indexer.go b/core/filtermaps/indexer.go index 3ec49ca11..02ae2b920 100644 --- a/core/filtermaps/indexer.go +++ b/core/filtermaps/indexer.go @@ -254,7 +254,7 @@ func (f *FilterMaps) tryIndexHead() error { ((!f.loggedHeadIndex && time.Since(f.startedHeadIndexAt) > headLogDelay) || time.Since(f.lastLogHeadIndex) > logFrequency) { log.Info("Log index head rendering in progress", - "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "firstblock", f.indexedRange.blocks.First(), "lastblock", f.indexedRange.blocks.Last(), "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex, "remaining", f.indexedView.HeadNumber()-f.indexedRange.blocks.Last(), "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) @@ -266,7 +266,7 @@ func (f *FilterMaps) tryIndexHead() error { } if f.loggedHeadIndex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index head rendering finished", - "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "firstblock", f.indexedRange.blocks.First(), "lastblock", f.indexedRange.blocks.Last(), "processed", f.indexedRange.blocks.AfterLast()-f.ptrHeadIndex, "elapsed", common.PrettyDuration(time.Since(f.startedHeadIndexAt))) } @@ -323,7 +323,7 @@ func (f *FilterMaps) tryIndexTail() (bool, error) { if f.indexedRange.hasIndexedBlocks() && f.ptrTailIndex >= f.indexedRange.blocks.First() && (!f.loggedTailIndex || time.Since(f.lastLogTailIndex) > logFrequency) { log.Info("Log index tail rendering in progress", - "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "firstblock", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), "processed", f.ptrTailIndex-f.indexedRange.blocks.First()+tpb, "remaining", remaining, "next tail epoch percentage", f.indexedRange.tailPartialEpoch*100/f.mapsPerEpoch, @@ -346,7 +346,7 @@ func (f *FilterMaps) tryIndexTail() (bool, error) { } if f.loggedTailIndex && f.indexedRange.hasIndexedBlocks() { log.Info("Log index tail rendering finished", - "first block", f.indexedRange.blocks.First(), "last block", f.indexedRange.blocks.Last(), + "firstblock", f.indexedRange.blocks.First(), "lastblock", f.indexedRange.blocks.Last(), "processed", f.ptrTailIndex-f.indexedRange.blocks.First(), "elapsed", common.PrettyDuration(time.Since(f.startedTailIndexAt))) f.loggedTailIndex = false From 2cc72618fa778ed9b2c2ba15a61fc50a21c759e8 Mon Sep 17 00:00:00 2001 From: GarmashAlex Date: Mon, 5 May 2025 09:01:53 +0300 Subject: [PATCH 338/354] triedb: add test suite for preimage store (#31574) --- triedb/preimages_test.go | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 triedb/preimages_test.go diff --git a/triedb/preimages_test.go b/triedb/preimages_test.go new file mode 100644 index 000000000..da2ec8dbe --- /dev/null +++ b/triedb/preimages_test.go @@ -0,0 +1,78 @@ +// Copyright 2023 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 . + +package triedb + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/triedb/hashdb" +) + +// TestDatabasePreimages tests the preimage functionality of the trie database. +func TestDatabasePreimages(t *testing.T) { + // Create a database with preimages enabled + memDB := rawdb.NewMemoryDatabase() + config := &Config{ + Preimages: true, + HashDB: hashdb.Defaults, + } + db := NewDatabase(memDB, config) + defer db.Close() + + // Test inserting and retrieving preimages + preimages := make(map[common.Hash][]byte) + for i := 0; i < 10; i++ { + data := []byte{byte(i), byte(i + 1), byte(i + 2)} + hash := common.BytesToHash(data) + preimages[hash] = data + } + + // Insert preimages into the database + db.InsertPreimage(preimages) + + // Verify all preimages are retrievable + for hash, data := range preimages { + retrieved := db.Preimage(hash) + if retrieved == nil { + t.Errorf("Preimage for %x not found", hash) + } + if !bytes.Equal(retrieved, data) { + t.Errorf("Preimage data mismatch: got %x want %x", retrieved, data) + } + } + + // Test non-existent preimage + nonExistentHash := common.HexToHash("deadbeef") + if data := db.Preimage(nonExistentHash); data != nil { + t.Errorf("Unexpected preimage data for non-existent hash: %x", data) + } + + // Force preimage commit and verify again + db.WritePreimages() + for hash, data := range preimages { + retrieved := db.Preimage(hash) + if retrieved == nil { + t.Errorf("Preimage for %x not found after forced commit", hash) + } + if !bytes.Equal(retrieved, data) { + t.Errorf("Preimage data mismatch after forced commit: got %x want %x", retrieved, data) + } + } +} From 688fd4d6632d5f83102ba04876a7b68284969ac8 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 5 May 2025 12:42:19 +0200 Subject: [PATCH 339/354] internal/ethapi: fix tx.from in eth_simulateV1 (#31480) Issue statement: when user requests eth_simulateV1 to return full transaction objects, these objects always had an empty `from` field. The reason is we lose the sender when translation the message into a types.Transaction which is then later on serialized. I did think of an alternative but opted to keep with this approach as it keeps complexity at the edge. The alternative would be to pass down a signer object to RPCMarshal* methods and define a custom signer which keeps the senders in its state and doesn't attempt the signature recovery. --- internal/ethapi/api_test.go | 71 +++++++++++++++++++++++++++++++++++++ internal/ethapi/simulate.go | 43 +++++++++++++++------- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 89666c444..e1d66f1ca 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -2506,6 +2506,77 @@ func TestSimulateV1ChainLinkage(t *testing.T) { require.Equal(t, block2.Hash().Bytes(), []byte(results[2].Calls[1].ReturnValue), "returned blockhash for block2 does not match") } +func TestSimulateV1TxSender(t *testing.T) { + var ( + sender = common.Address{0xaa, 0xaa} + sender2 = common.Address{0xaa, 0xab} + sender3 = common.Address{0xaa, 0xac} + recipient = common.Address{0xbb, 0xbb} + gspec = &core.Genesis{ + Config: params.MergedTestChainConfig, + Alloc: types.GenesisAlloc{ + sender: {Balance: big.NewInt(params.Ether)}, + sender2: {Balance: big.NewInt(params.Ether)}, + sender3: {Balance: big.NewInt(params.Ether)}, + }, + } + ctx = context.Background() + ) + backend := newTestBackend(t, 0, gspec, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {}) + stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)) + if err != nil { + t.Fatalf("failed to get state and header: %v", err) + } + + sim := &simulator{ + b: backend, + state: stateDB, + base: baseHeader, + chainConfig: backend.ChainConfig(), + gp: new(core.GasPool).AddGas(math.MaxUint64), + traceTransfers: false, + validate: false, + fullTx: true, + } + + results, err := sim.execute(ctx, []simBlock{ + {Calls: []TransactionArgs{ + {From: &sender, To: &recipient, Value: (*hexutil.Big)(big.NewInt(1000))}, + {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(2000))}, + {From: &sender3, To: &recipient, Value: (*hexutil.Big)(big.NewInt(3000))}, + }}, + {Calls: []TransactionArgs{ + {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(4000))}, + }}, + }) + if err != nil { + t.Fatalf("simulation execution failed: %v", err) + } + require.Len(t, results, 2, "expected 2 simulated blocks") + require.Len(t, results[0].Block.Transactions(), 3, "expected 3 transaction in simulated block") + require.Len(t, results[1].Block.Transactions(), 1, "expected 1 transaction in 2nd simulated block") + enc, err := json.Marshal(results) + if err != nil { + t.Fatalf("failed to marshal results: %v", err) + } + type resultType struct { + Transactions []struct { + From common.Address `json:"from"` + } + } + var summary []resultType + if err := json.Unmarshal(enc, &summary); err != nil { + t.Fatalf("failed to unmarshal results: %v", err) + } + require.Len(t, summary, 2, "expected 2 simulated blocks") + require.Len(t, summary[0].Transactions, 3, "expected 3 transaction in simulated block") + require.Equal(t, sender, summary[0].Transactions[0].From, "sender address mismatch") + require.Equal(t, sender2, summary[0].Transactions[1].From, "sender address mismatch") + require.Equal(t, sender3, summary[0].Transactions[2].From, "sender address mismatch") + require.Len(t, summary[1].Transactions, 1, "expected 1 transaction in simulated block") + require.Equal(t, sender2, summary[1].Transactions[0].From, "sender address mismatch") +} + func TestSignTransaction(t *testing.T) { t.Parallel() // Initialize test accounts diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index b4f76de80..f46c50b8e 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -78,11 +78,25 @@ type simBlockResult struct { chainConfig *params.ChainConfig Block *types.Block Calls []simCallResult + // senders is a map of transaction hashes to their senders. + senders map[common.Hash]common.Address } func (r *simBlockResult) MarshalJSON() ([]byte, error) { blockData := RPCMarshalBlock(r.Block, true, r.fullTx, r.chainConfig) blockData["calls"] = r.Calls + // Set tx sender if user requested full tx objects. + if r.fullTx { + if raw, ok := blockData["transactions"].([]any); ok { + for _, tx := range raw { + if tx, ok := tx.(*RPCTransaction); ok { + tx.From = r.senders[tx.Hash] + } else { + return nil, errors.New("simulated transaction result has invalid type") + } + } + } + } return json.Marshal(blockData) } @@ -185,18 +199,18 @@ func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlo parent = sim.base ) for bi, block := range blocks { - result, callResults, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout) + result, callResults, senders, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout) if err != nil { return nil, err } headers[bi] = result.Header() - results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults} + results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders} parent = result.Header() } return results, nil } -func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, error) { +func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, map[common.Hash]common.Address, error) { // Set header fields that depend only on parent block. // Parent hash is needed for evm.GetHashFn to work. header.ParentHash = parent.Hash() @@ -226,7 +240,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, precompiles := sim.activePrecompiles(sim.base) // State overrides are applied prior to execution of a block if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil { - return nil, nil, err + return nil, nil, nil, err } var ( gasUsed, blobGasUsed uint64 @@ -239,6 +253,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, NoBaseFee: !sim.validate, Tracer: tracer.Hooks(), } + // senders is a map of transaction hashes to their senders. + // Transaction objects contain only the signature, and we lose track + // of the sender when translating the arguments into a transaction object. + senders = make(map[common.Hash]common.Address) ) tracingStateDB := vm.StateDB(sim.state) if hooks := tracer.Hooks(); hooks != nil { @@ -259,16 +277,17 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, var allLogs []*types.Log for i, call := range block.Calls { if err := ctx.Err(); err != nil { - return nil, nil, err + return nil, nil, nil, err } if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil { - return nil, nil, err + return nil, nil, nil, err } var ( tx = call.ToTransaction(types.DynamicFeeTxType) txHash = tx.Hash() ) txes[i] = tx + senders[txHash] = call.from() tracer.reset(txHash, uint(i)) sim.state.SetTxContext(txHash, i) // EoA check is always skipped, even in validation mode. @@ -276,7 +295,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) if err != nil { txErr := txValidationError(err) - return nil, nil, txErr + return nil, nil, nil, txErr } // Update the state with pending changes. var root []byte @@ -315,15 +334,15 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, requests = [][]byte{} // EIP-6110 if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil { - return nil, nil, err + return nil, nil, nil, err } // EIP-7002 if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { - return nil, nil, err + return nil, nil, nil, err } // EIP-7251 if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { - return nil, nil, err + return nil, nil, nil, err } } if requests != nil { @@ -334,10 +353,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, chainHeadReader := &simChainHeadReader{ctx, sim.b} b, err := sim.b.Engine().FinalizeAndAssemble(chainHeadReader, header, sim.state, blockBody, receipts) if err != nil { - return nil, nil, err + return nil, nil, nil, err } repairLogs(callResults, b.Hash()) - return b, callResults, nil + return b, callResults, senders, nil } // repairLogs updates the block hash in the logs present in the result of From c6f8cded91e4ab8c45635c3d4178db8609cb0c91 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Mon, 5 May 2025 14:43:47 +0200 Subject: [PATCH 340/354] rpc: add method name length limit (#31711) This change adds a limit for RPC method names to prevent potential abuse where large method names could lead to large response sizes. The limit is enforced in: - handleCall for regular RPC method calls - handleSubscribe for subscription method calls Added tests in websocket_test.go to verify the length limit functionality for both regular method calls and subscriptions. --------- Co-authored-by: Felix Lange --- rpc/handler.go | 9 ++++++ rpc/json.go | 1 + rpc/websocket_test.go | 74 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/rpc/handler.go b/rpc/handler.go index f23b544b5..45558d582 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -501,6 +501,10 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage if msg.isUnsubscribe() { callb = h.unsubscribeCb } else { + // Check method name length + if len(msg.Method) > maxMethodNameLength { + return msg.errorResponse(&invalidRequestError{fmt.Sprintf("method name too long: %d > %d", len(msg.Method), maxMethodNameLength)}) + } callb = h.reg.callback(msg.Method) } if callb == nil { @@ -536,6 +540,11 @@ func (h *handler) handleSubscribe(cp *callProc, msg *jsonrpcMessage) *jsonrpcMes return msg.errorResponse(ErrNotificationsUnsupported) } + // Check method name length + if len(msg.Method) > maxMethodNameLength { + return msg.errorResponse(&invalidRequestError{fmt.Sprintf("subscription name too long: %d > %d", len(msg.Method), maxMethodNameLength)}) + } + // Subscription method name is first argument. name, err := parseSubscriptionName(msg.Params) if err != nil { diff --git a/rpc/json.go b/rpc/json.go index e932389d1..fcd801fc9 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -35,6 +35,7 @@ const ( subscribeMethodSuffix = "_subscribe" unsubscribeMethodSuffix = "_unsubscribe" notificationMethodSuffix = "_subscription" + maxMethodNameLength = 2048 defaultWriteTimeout = 10 * time.Second // used if context has no deadline ) diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index 10a998b35..a8d862490 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -391,3 +391,77 @@ func wsPingTestHandler(t *testing.T, conn *websocket.Conn, shutdown, sendPing <- } } } + +func TestWebsocketMethodNameLengthLimit(t *testing.T) { + t.Parallel() + + var ( + srv = newTestServer() + httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"})) + wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") + ) + defer srv.Stop() + defer httpsrv.Close() + + client, err := DialWebsocket(context.Background(), wsURL, "") + if err != nil { + t.Fatalf("can't dial: %v", err) + } + defer client.Close() + + // Test cases + tests := []struct { + name string + method string + params []interface{} + expectedError string + isSubscription bool + }{ + { + name: "valid method name", + method: "test_echo", + params: []interface{}{"test", 1}, + expectedError: "", + isSubscription: false, + }, + { + name: "method name too long", + method: "test_" + string(make([]byte, maxMethodNameLength+1)), + params: []interface{}{"test", 1}, + expectedError: "method name too long", + isSubscription: false, + }, + { + name: "valid subscription", + method: "nftest_subscribe", + params: []interface{}{"someSubscription", 1, 2}, + expectedError: "", + isSubscription: true, + }, + { + name: "subscription name too long", + method: string(make([]byte, maxMethodNameLength+1)) + "_subscribe", + params: []interface{}{"newHeads"}, + expectedError: "subscription name too long", + isSubscription: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var result interface{} + err := client.Call(&result, tt.method, tt.params...) + if tt.expectedError == "" { + if err != nil { + t.Errorf("unexpected error: %v", err) + } + } else { + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("expected error containing %q, got %q", tt.expectedError, err.Error()) + } + } + }) + } +} From a82da7b690922276beef04e1c75b8d6cb4695030 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 5 May 2025 22:15:59 +0800 Subject: [PATCH 341/354] eth/tracers: fix `standardTraceBlockToFile` (#31763) Fixes methods debug_standardTraceBlockToFile and debug_standardTraceBadBlockToFile which were outputting empty files. --------- Co-authored-by: maskpp Co-authored-by: Sina Mahmoodi --- eth/tracers/api.go | 64 +++++++++++----------- eth/tracers/api_test.go | 116 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 30 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 469d24b66..f6933b585 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -778,6 +778,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Note: This copies the config, to not screw up the main config chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } + evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) @@ -787,42 +788,45 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution - var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) - vmConf vm.Config - dump *os.File - writer *bufio.Writer - err error - ) - // If the transaction needs tracing, swap out the configs - if tx.Hash() == txHash || txHash == (common.Hash{}) { - // Generate a unique temporary file to dump it into - prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4]) - if !canon { - prefix = fmt.Sprintf("%valt-", prefix) - } - dump, err = os.CreateTemp(os.TempDir(), prefix) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + if txHash != (common.Hash{}) && tx.Hash() != txHash { + // Process the tx to update state, but don't trace it. + _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { - return nil, err - } - dumps = append(dumps, dump.Name()) - - // Swap out the noop logger to the standard tracer - writer = bufio.NewWriter(dump) - vmConf = vm.Config{ - Tracer: logger.NewJSONLogger(&logConfig, writer), - EnablePreimageRecording: true, + return dumps, err } + // Finalize the state so any modifications are written to the trie + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + continue } + // The transaction should be traced. + // Generate a unique temporary file to dump it into. + prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4]) + if !canon { + prefix = fmt.Sprintf("%valt-", prefix) + } + var dump *os.File + dump, err := os.CreateTemp(os.TempDir(), prefix) + if err != nil { + return nil, err + } + dumps = append(dumps, dump.Name()) + // Set up the tracer and EVM for the transaction. + var ( + writer = bufio.NewWriter(dump) + tracer = logger.NewJSONLogger(&logConfig, writer) + evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{ + Tracer: tracer, + NoBaseFee: true, + }) + ) // Execute the transaction and flush any traces to disk statedb.SetTxContext(tx.Hash(), i) - if vmConf.Tracer.OnTxStart != nil { - vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) - } - vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) - if vmConf.Tracer.OnTxEnd != nil { - vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + if tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } + _, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if writer != nil { writer.Flush() } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 3fb7fcf8e..8be4dd15d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "math/big" + "os" "reflect" "slices" "sync/atomic" @@ -1218,3 +1219,118 @@ func TestTraceBlockWithBasefee(t *testing.T) { } } } + +func TestStandardTraceBlockToFile(t *testing.T) { + var ( + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + + // first contract the sender transacts with + aa = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f43") + aaCode = []byte{byte(vm.PUSH1), 0x00, byte(vm.POP)} + + // second contract the sender transacts with + bb = common.HexToAddress("0x7217d81b76bdd8707601e959454e3d776aee5f44") + bbCode = []byte{byte(vm.PUSH2), 0x00, 0x01, byte(vm.POP)} + ) + + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{ + address: {Balance: funds}, + aa: { + Code: aaCode, + Nonce: 1, + Balance: big.NewInt(0), + }, + bb: { + Code: bbCode, + Nonce: 1, + Balance: big.NewInt(0), + }, + }, + } + txHashs := make([]common.Hash, 0, 2) + backend := newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { + b.SetCoinbase(common.Address{1}) + // first tx to aa + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 0, + To: &aa, + Value: big.NewInt(0), + Gas: 50000, + GasPrice: b.BaseFee(), + Data: nil, + }), types.HomesteadSigner{}, key) + b.AddTx(tx) + txHashs = append(txHashs, tx.Hash()) + // second tx to bb + tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: 1, + To: &bb, + Value: big.NewInt(1), + Gas: 100000, + GasPrice: b.BaseFee(), + Data: nil, + }), types.HomesteadSigner{}, key) + b.AddTx(tx) + txHashs = append(txHashs, tx.Hash()) + }) + defer backend.chain.Stop() + + var testSuite = []struct { + blockNumber rpc.BlockNumber + config *StdTraceConfig + want []string + }{ + { + // test that all traces in the block were outputted if no trace config is specified + blockNumber: rpc.LatestBlockNumber, + config: nil, + want: []string{ + `{"pc":0,"op":96,"gas":"0x7148","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":80,"gas":"0x7145","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"POP"} +{"pc":3,"op":0,"gas":"0x7143","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x5"} +`, + `{"pc":0,"op":97,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":3,"op":80,"gas":"0x13495","gasCost":"0x2","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"POP"} +{"pc":4,"op":0,"gas":"0x13493","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x5"} +`, + }, + }, + { + // test that only a specific tx is traced if specified + blockNumber: rpc.LatestBlockNumber, + config: &StdTraceConfig{TxHash: txHashs[1]}, + want: []string{ + `{"pc":0,"op":97,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH2"} +{"pc":3,"op":80,"gas":"0x13495","gasCost":"0x2","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"POP"} +{"pc":4,"op":0,"gas":"0x13493","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x5"} +`, + }, + }, + } + + api := NewAPI(backend) + for i, tc := range testSuite { + block, _ := api.blockByNumber(context.Background(), tc.blockNumber) + txTraces, err := api.StandardTraceBlockToFile(context.Background(), block.Hash(), tc.config) + if err != nil { + t.Fatalf("test index %d received error %v", i, err) + } + for j, traceFileName := range txTraces { + traceReceived, err := os.ReadFile(traceFileName) + if err != nil { + t.Fatalf("could not read trace file: %v", err) + } + if tc.want[j] != string(traceReceived) { + t.Fatalf("unexpected trace result. expected\n'%s'\n\nreceived\n'%s'\n", tc.want[j], string(traceReceived)) + } + } + } +} From 25bae7a1556b326c01129ec780fa6fcd55a0b395 Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Tue, 16 Sep 2025 15:28:38 +0800 Subject: [PATCH 342/354] all: some adjustments to the details, ref https://github.com/bane-labs/go-ethereum/commit/766025cb59dc111cba3184e360c141f9c8347704, https://github.com/bane-labs/go-ethereum/commit/227cb3bf9d23bb14f00f34c2ba432341d3b0913a --- Makefile | 34 +- consensus/beacon/consensus.go | 84 ++--- core/blockchain.go | 30 +- core/blockchain_test.go | 62 ++- core/chain_makers_test.go | 5 +- core/rawdb/accessors_chain.go | 9 +- eth/backend.go | 65 +++- eth/catalyst/api_test.go | 94 ++++- eth/handler.go | 15 + eth/protocols/eth/handler_test.go | 1 + eth/tracers/internal/tracetest/supply_test.go | 2 - graphql/graphql_test.go | 10 +- miner/miner.go | 28 +- miner/miner_test.go | 3 +- miner/payload_building.go | 2 +- miner/payload_building_test.go | 2 +- miner/worker.go | 356 +++++++++--------- miner/worker_test.go | 2 +- privnet/zk/genesis_privnet.json | 7 + signer/core/api.go | 2 + 20 files changed, 504 insertions(+), 309 deletions(-) diff --git a/Makefile b/Makefile index 8ef8bebc6..9f544096b 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth android ios evm all test clean privnet_nodes_stop privnet_bootnode_stop privnet_stop privnet_clean privnet_start privnet_start_four privnet_start_seven +.PHONY: geth all test lint fmt clean devtools help privnet_nodes_stop privnet_bootnode_stop privnet_stop privnet_clean privnet_start privnet_start_four privnet_start_seven GETHBIN = ./build/bin GO ?= latest @@ -86,7 +86,7 @@ define run_bootnode endef define run_miner_node_with_zk_dkg - $(call run_node,$(1),$(2),$(3),$(4),$(5),$(6),--mine --miner.etherbase="0x$$(cat $(1)/$(7)/node_address.txt)" --antimev.password=$(1)/$(7)/password.txt --dkg.one-msg-r1cs=$(1)/r1cs/one_message.ccs --dkg.two-msg-r1cs=$(1)/r1cs/two_message.ccs --dkg.seven-msg-r1cs=$(1)/r1cs/seven_message.ccs --dkg.one-msg-pk=$(1)/provingkey/one_message.pk --dkg.two-msg-pk=$(1)/provingkey/two_message.pk --dkg.seven-msg-pk=$(1)/provingkey/seven_message.pk) + $(call run_node,$(1),$(2),$(3),$(4),$(5),$(6),--mine --miner.etherbase="0x$$(cat $(1)/$(7)/node_address.txt)" --antimev.password=$(1)/$(7)/password.txt --dkg.one-msg-r1cs=$(1)/r1cs/R1CS_1 --dkg.two-msg-r1cs=$(1)/r1cs/R1CS_2 --dkg.seven-msg-r1cs=$(1)/r1cs/R1CS_7 --dkg.one-msg-pk=$(1)/provingkey/PK_1 --dkg.two-msg-pk=$(1)/provingkey/PK_2 --dkg.seven-msg-pk=$(1)/provingkey/PK_7) endef define run_miner_node @@ -120,25 +120,29 @@ define init_node @$(GETHBIN)/geth init --datadir $(1)/$(2) $(1)/$(GENESIS_WORK_JSON) > $(1)/$(2)/geth_init.log 2>&1 endef -#? geth: Build geth +#? geth: Build geth. geth: $(GORUN) build/ci.go install ./cmd/geth @echo "Done building." @echo "Run \"$(GETHBIN)/geth\" to launch geth." -#? all: Build all packages and executables +#? all: Build all packages and executables. all: $(GORUN) build/ci.go install -#? test: Run the tests +#? test: Run the tests. test: all $(GORUN) build/ci.go test -#? lint: Run certain pre-selected linters +#? lint: Run certain pre-selected linters. lint: ## Run linters. $(GORUN) build/ci.go lint -#? clean: Clean go cache, built executables, and the auto generated folder +#? fmt: Ensure consistent code formatting. +fmt: + gofmt -s -w $(shell find . -name "*.go") + +#? clean: Clean go cache, built executables, and the auto generated folder. clean: go clean -cache rm -fr build/_workspace/pkg/ $(GETHBIN)/* @@ -155,8 +159,16 @@ devtools: @type "solc" 2> /dev/null || echo 'Please install solc' @type "protoc" 2> /dev/null || echo 'Please install protoc' -# Privnet targets +#? help: Get more info on make commands. +help: Makefile + @echo '' + @echo 'Usage:' + @echo ' make [target]' + @echo '' + @echo 'Targets:' + @sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /' +# Privnet targets privnet_nodes_stop: @echo "Killing nodes processes" @killall -w -v -INT geth || : @@ -347,9 +359,3 @@ docker_privnet_stop_seven: docker_clean_node_img: docker rmi neox_node - -#? help: Get more info on make commands. -help: Makefile - @echo " Choose a command run in go-ethereum:" - @sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /' -.PHONY: help diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 967d762b1..6502e520e 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -93,67 +93,55 @@ func (beacon *Beacon) Author(header *types.Header) (common.Address, error) { // VerifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error { - reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) - if err != nil { - return err - } - if !reached { - return beacon.ethone.VerifyHeader(chain, header) - } - // Short circuit if the parent is not known + // During the live merge transition, the consensus engine used the terminal + // total difficulty to detect when PoW (PoA) switched to PoS. Maintaining the + // total difficulty values however require applying all the blocks from the + // genesis to build up the TD. This stops being a possibility if the tail of + // the chain is pruned already during sync. + // + // One heuristic that can be used to distinguish pre-merge and post-merge + // blocks is whether their *difficulty* is >0 or ==0 respectively. This of + // course would mean that we cannot prove anymore for a past chain that it + // truly transitioned at the correct TTD, but if we consider that ancient + // point in time finalized a long time ago, there should be no attempt from + // the consensus client to rewrite very old history. + // + // One thing that's probably not needed but which we can add to make this + // verification even stricter is to enforce that the chain can switch from + // >0 to ==0 TD only once by forbidding an ==0 to be followed by a >0. + + // Verify that we're not reverting to pre-merge from post-merge parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) if parent == nil { return consensus.ErrUnknownAncestor } - // Sanity checks passed, do a proper verification - return beacon.verifyHeader(chain, header, parent) -} - -// errOut constructs an error channel with prefilled errors inside. -func errOut(n int, err error) chan error { - errs := make(chan error, n) - for i := 0; i < n; i++ { - errs <- err + if parent.Difficulty.Sign() == 0 && header.Difficulty.Sign() > 0 { + return consensus.ErrInvalidTerminalBlock + } + // Check >0 TDs with pre-merge, --0 TDs with post-merge rules + if header.Difficulty.Sign() > 0 { + return beacon.ethone.VerifyHeader(chain, header) } - return errs + return beacon.verifyHeader(chain, header, parent) } // splitHeaders splits the provided header batch into two parts according to -// the configured ttd. It requires the parent of header batch along with its -// td are stored correctly in chain. If ttd is not configured yet, all headers -// will be treated legacy PoW headers. +// the difficulty field. +// // Note, this function will not verify the header validity but just split them. -func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) { - // TTD is not defined yet, all headers should be in legacy format. - ttd := chain.Config().TerminalTotalDifficulty - ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1) - if ptd == nil { - return nil, nil, consensus.ErrUnknownAncestor - } - // The entire header batch already crosses the transition. - if ptd.Cmp(ttd) >= 0 { - return nil, headers, nil - } +func (beacon *Beacon) splitHeaders(headers []*types.Header) ([]*types.Header, []*types.Header) { var ( preHeaders = headers postHeaders []*types.Header - td = new(big.Int).Set(ptd) - tdPassed bool ) for i, header := range headers { - if tdPassed { + if header.Difficulty.Sign() == 0 { preHeaders = headers[:i] postHeaders = headers[i:] break } - td = td.Add(td, header.Difficulty) - if td.Cmp(ttd) >= 0 { - // This is the last PoW header, it still belongs to - // the preHeaders, so we cannot split+break yet. - tdPassed = true - } } - return preHeaders, postHeaders, nil + return preHeaders, postHeaders } // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers @@ -161,10 +149,7 @@ func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers [] // a results channel to retrieve the async verifications. // VerifyHeaders expect the headers to be ordered and continuous. func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { - preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers) - if err != nil { - return make(chan struct{}), errOut(len(headers), err) - } + preHeaders, postHeaders := beacon.splitHeaders(headers) if len(postHeaders) == 0 { return beacon.ethone.VerifyHeaders(chain, headers) } @@ -344,7 +329,12 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [ // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the beacon protocol. The changes are done inline. func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { - if !isPostMerge(chain.Config(), header.Number.Uint64(), header.Time) { + // Transition isn't triggered yet, use the legacy rules for preparation. + reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) + if err != nil { + return err + } + if !reached { return beacon.ethone.Prepare(chain, header) } header.Difficulty = beaconDifficulty diff --git a/core/blockchain.go b/core/blockchain.go index 7ac07cf09..0083b1236 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1375,7 +1375,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ start = time.Now() size = int64(0) ) - // updateHead updates the head header and head snap block flags. + // updateHead updates the head snap sync block if the inserted blocks are better + // and returns an indicator whether the inserted blocks are canonical. updateHead := func(header *types.Header) error { reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), header) if err != nil { @@ -1384,7 +1385,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } else if !reorg { return nil } - batch := bc.db.NewBatch() hash := header.Hash() rawdb.WriteHeadHeaderHash(batch, hash) @@ -1417,12 +1417,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } } // Write all chain data to ancients. - first := blockChain[0] - ptd := bc.GetTd(first.ParentHash(), first.NumberU64()-1) + ptd := bc.GetTd(blockChain[0].ParentHash(), blockChain[0].NumberU64()-1) if ptd == nil { return 0, consensus.ErrUnknownAncestor } - td := new(big.Int).Add(ptd, first.Difficulty()) + td := new(big.Int).Add(ptd, blockChain[0].Difficulty()) writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, td) if err != nil { log.Error("Error importing chain data to ancients", "err", err) @@ -1461,7 +1460,13 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ skipPresenceCheck = false batch = bc.db.NewBatch() ) + ptd := bc.GetTd(blockChain[0].ParentHash(), blockChain[0].NumberU64()-1) + if ptd == nil { + return 0, consensus.ErrUnknownAncestor + } + tdSum := new(big.Int).Set(ptd) for i, block := range blockChain { + tdSum.Add(tdSum, block.Difficulty()) // Short circuit insertion if shutting down or processing failed if bc.insertStopped() { return 0, errInsertionInterrupted @@ -1479,6 +1484,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } } // Write all the data out into the database + rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), tdSum) rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) rawdb.WriteBlock(batch, block) rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receiptChain[i]) @@ -1681,6 +1687,8 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types return NonStatTy, err } currentBlock := bc.CurrentBlock() + + // Reorganise the chain if the parent is not the head block reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header()) if err != nil { return NonStatTy, err @@ -1696,6 +1704,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types } else { status = SideStatTy } + // Set new head. if status == CanonStatTy { bc.writeHeadBlock(block) @@ -2108,7 +2117,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness stats.queued++ } } - stats.ignored += it.remaining() return witness, it.index, err @@ -2834,13 +2842,11 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e // Initialize the ancient store with genesis block if it's empty. var ( - frozen, _ = bc.db.Ancients() - first = headers[0].Number.Uint64() - firstHeader = headers[0] + frozen, _ = bc.db.Ancients() + first = headers[0].Number.Uint64() ) if first == 1 && frozen == 0 { - td := bc.genesisBlock.Difficulty() - _, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td) + _, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, bc.genesisBlock.Difficulty()) if err != nil { log.Error("Error writing genesis to ancients", "err", err) return 0, err @@ -2852,7 +2858,7 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e // Write headers to the ancient store, with block bodies and receipts set to nil // to ensure consistency across tables in the freezer. - ptd := bc.GetTd(firstHeader.ParentHash, firstHeader.Number.Uint64()-1) + ptd := bc.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1) if ptd == nil { return 0, consensus.ErrUnknownAncestor } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index a113c2bf8..0355f53fd 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -779,6 +779,13 @@ func testFastVsFullChains(t *testing.T, scheme string) { fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + if n, err := fast.InsertHeaderChain(headers); err != nil { + t.Fatalf("failed to insert header %d: %v", n, err) + } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -792,6 +799,9 @@ func testFastVsFullChains(t *testing.T, scheme string) { ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() + if n, err := ancient.InsertHeaderChain(headers); err != nil { + t.Fatalf("failed to insert header %d: %v", n, err) + } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(len(blocks)/2)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -922,6 +932,13 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + if n, err := fast.InsertHeaderChain(headers); err != nil { + t.Fatalf("failed to insert header %d: %v", n, err) + } if n, err := fast.InsertReceiptChain(blocks, receipts, 0); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -935,6 +952,9 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() + if n, err := ancient.InsertHeaderChain(headers); err != nil { + t.Fatalf("failed to insert header %d: %v", n, err) + } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -948,11 +968,6 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() - - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) @@ -1256,7 +1271,7 @@ func testSideLogRebirth(t *testing.T, scheme string) { } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) - // Generate side chain with lower difficulty + // Generate side chain with lower difficulty, after the merge, the chain will be accepted even if it is lower difficulty genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) @@ -1271,7 +1286,7 @@ func testSideLogRebirth(t *testing.T, scheme string) { } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) - // Generate a new block based on side chain. + // Generate a new block based on side chain. Should not emit any events anymore. newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(newBlocks); err != nil { t.Fatalf("failed to insert forked chain: %v", err) @@ -1693,8 +1708,8 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { if chain.HasState(shared[len(shared)-1].Root()) { t.Fatalf("common-but-old ancestor still cache") } - // Import the competitor chain without exceeding the canonical's TD and ensure - // we have not processed any of the blocks (protection against malicious blocks) + // Import the competitor chain without exceeding the canonical's TD. + // Post-merge the side chain should be executed if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil { t.Fatalf("failed to insert competitor chain: %v", err) } @@ -1703,8 +1718,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { t.Fatalf("competitor %d: low TD chain became processed", i) } } - // Import the head of the competitor chain, triggering the reorg and ensure we - // successfully reprocess all the stashed away blocks. + // Import the head of the competitor chain. if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } @@ -1750,6 +1764,13 @@ func testBlockchainRecovery(t *testing.T, scheme string) { defer ancientDb.Close() ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + if n, err := ancient.InsertHeaderChain(headers); err != nil { + t.Fatalf("failed to insert header %d: %v", n, err) + } if n, err := ancient.InsertReceiptChain(blocks, receipts, uint64(3*len(blocks)/4)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) } @@ -1877,6 +1898,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + chain.Config().TerminalTotalDifficulty = gspec.Config.TerminalTotalDifficulty } genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) @@ -1912,6 +1934,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ttd := big.NewInt(int64(len(blocks))) ttd.Mul(ttd, params.GenesisDifficulty) gspec.Config.TerminalTotalDifficulty = ttd + chain.Config().TerminalTotalDifficulty = gspec.Config.TerminalTotalDifficulty mergeBlock = len(blocks) } @@ -2045,6 +2068,14 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { } } else if typ == "receipts" { inserter = func(blocks []*types.Block, receipts []types.Receipts) error { + headers := make([]*types.Header, 0, len(blocks)) + for _, block := range blocks { + headers = append(headers, block.Header()) + } + _, err := chain.InsertHeaderChain(headers) + if err != nil { + return err + } _, err = chain.InsertReceiptChain(blocks, receipts, 0) return err } @@ -2211,6 +2242,14 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } } else if typ == "receipts" { inserter = func(blocks []*types.Block, receipts []types.Receipts) error { + headers := make([]*types.Header, 0, len(blocks)) + for _, block := range blocks { + headers = append(headers, block.Header()) + } + i, err := chain.InsertHeaderChain(headers) + if err != nil { + return fmt.Errorf("index %d: %w", i, err) + } _, err = chain.InsertReceiptChain(blocks, receipts, 0) return err } @@ -2583,7 +2622,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) } - // Now re-import some old blocks blockToReimport := blocks[5:8] _, err = chain.InsertChain(blockToReimport) if err != nil { diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 118434819..8004e1a3f 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -76,9 +76,8 @@ func TestGeneratePOSChain(t *testing.T) { Code: common.Hex2Bytes("600154600354"), } genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, triedb.HashDefaults)) - engine := beacon.New(ethash.NewFaker()) - genchain, genreceipts := GenerateChain(gspec.Config, genesis, engine, gendb, 4, func(i int, gen *BlockGen) { + genchain, genreceipts := GenerateChain(gspec.Config, genesis, beacon.New(ethash.NewFaker()), gendb, 4, func(i int, gen *BlockGen) { gen.SetParentBeaconRoot(common.Hash{byte(i + 1)}) // Add value transfer tx. @@ -119,7 +118,7 @@ func TestGeneratePOSChain(t *testing.T) { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(genchain); err != nil { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index ef73b4451..74b3d9b4b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -796,13 +796,12 @@ func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *type // WriteAncientHeaderChain writes the supplied headers along with nil block // bodies and receipts into the ancient store. It's supposed to be used for // storing chain segment before the chain cutoff. -// !!! ptd is the td of the parent block of headers[0] -func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header, ptd *big.Int) (int64, error) { - var tdSum = new(big.Int).Set(ptd) - +func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header, td *big.Int) (int64, error) { return db.ModifyAncients(func(op ethdb.AncientWriteOp) error { + tdSum := new(big.Int).Set(td) for _, header := range headers { num := header.Number.Uint64() + tdSum.Add(tdSum, header.Difficulty) if err := op.AppendRaw(ChainFreezerHashTable, num, header.Hash().Bytes()); err != nil { return fmt.Errorf("can't add block %d hash: %v", num, err) } @@ -816,7 +815,7 @@ func WriteAncientHeaderChain(db ethdb.AncientWriter, headers []*types.Header, pt return fmt.Errorf("can't append block %d receipts: %v", num, err) } if err := op.Append(ChainFreezerDifficultyTable, num, tdSum); err != nil { - return fmt.Errorf("can't append block %d td: %v", num, err) + return fmt.Errorf("can't append block %d total difficulty: %v", num, err) } } return nil diff --git a/eth/backend.go b/eth/backend.go index de4f68d97..ded145b99 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -241,11 +241,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } - // TODO (MariusVanDerWijden) get rid of shouldPreserve in a follow-up PR - shouldPreserve := func(header *types.Header) bool { - return false - } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, shouldPreserve, &config.TransactionHistory) + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TransactionHistory) if err != nil { return nil, err } @@ -321,7 +317,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { eth.dropper = newDropper(eth.p2pServer.MaxDialedConns(), eth.p2pServer.MaxInboundConns()) - eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine) + eth.miner = miner.New(eth, &config.Miner, eth.EventMux(), eth.engine) if chainConfig.DBFT != nil && len(config.Miner.ExtraData) != 0 { return nil, fmt.Errorf("custom miner Extra is not supported by dBFT") } @@ -465,6 +461,63 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) bool { return true } +// isLocalBlock checks whether the specified block is mined +// by local miner accounts. +// +// We regard two types of accounts as local miner account: etherbase +// and accounts specified via `txpool.locals` flag. +func (s *Ethereum) isLocalBlock(header *types.Header) bool { + author, err := s.engine.Author(header) + if err != nil { + log.Warn("Failed to retrieve block author", "number", header.Number.Uint64(), "hash", header.Hash(), "err", err) + return false + } + // Check whether the given address is etherbase. + s.lock.RLock() + etherbase := s.etherbase + s.lock.RUnlock() + if author == etherbase { + return true + } + // Check whether the given address is specified by `txpool.local` + // CLI flag. + for _, account := range s.config.TxPool.Locals { + if account == author { + return true + } + } + return false +} + +// shouldPreserve checks whether we should preserve the given block +// during the chain reorg depending on whether the author of block +// is a local account. +func (s *Ethereum) shouldPreserve(header *types.Header) bool { + // The reason we need to disable the self-reorg preserving for clique + // is it can be probable to introduce a deadlock. + // + // e.g. If there are 7 available signers + // + // r1 A + // r2 B + // r3 C + // r4 D + // r5 A [X] F G + // r6 [X] + // + // In the round5, the in-turn signer E is offline, so the worst case + // is A, F and G sign the block of round5 and reject the block of opponents + // and in the round6, the last available signer B is offline, the whole + // network is stuck. + if _, ok := s.engine.(*clique.Clique); ok { + return false + } + if _, ok := s.engine.(*dbft.DBFT); ok { + return false + } + return s.isLocalBlock(header) +} + // StartMining starts the miner with the given number of CPU threads. If mining // is already running, this method adjust the number of threads allowed to use // and updates the minimum price required by the transaction pool. diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 1c67c9e6b..7abe4abb4 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -32,7 +32,8 @@ import ( "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus" + beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -62,15 +63,11 @@ var ( func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { config := *params.AllEthashProtocolChanges - engine := beacon.New(ethash.NewFaker()) + engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker())) if merged { config.TerminalTotalDifficulty = common.Big0 - config.MergeNetsplitBlock = common.Big0 - } else { - // When !merged, the tests expect the next block after the generated chain to be in PoS. - config.MergeNetsplitBlock = big.NewInt(int64(n + 1)) + engine = beaconConsensus.New(ethash.NewFaker()) } - genesis := &core.Genesis{ Config: &config, Alloc: types.GenesisAlloc{ @@ -105,6 +102,7 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { } config.TerminalTotalDifficulty = totalDifficulty } + return genesis, blocks } @@ -167,6 +165,24 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { } } +func TestSetHeadBeforeTotalDifficulty(t *testing.T) { + genesis, blocks := generateMergeChain(10, false) + n, ethservice := startEthService(t, genesis, blocks) + defer n.Close() + + api := NewConsensusAPI(ethservice) + fcState := engine.ForkchoiceStateV1{ + HeadBlockHash: blocks[5].Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { + t.Errorf("fork choice updated should not error: %v", err) + } else if resp.PayloadStatus.Status != engine.INVALID_TERMINAL_BLOCK.Status { + t.Errorf("fork choice updated before total terminal difficulty should be INVALID") + } +} + func TestEth2PrepareAndGetPayload(t *testing.T) { genesis, blocks := generateMergeChain(10, false) // We need to properly set the terminal total difficulty @@ -892,6 +908,70 @@ func TestInvalidBloom(t *testing.T) { } } +func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { + genesis, preMergeBlocks := generateMergeChain(100, false) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + defer n.Close() + api := NewConsensusAPI(ethservice) + + // Test parent already post TTD in FCU + parent := preMergeBlocks[len(preMergeBlocks)-2] + fcState := engine.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + resp, err := api.ForkchoiceUpdatedV1(fcState, nil) + if err != nil { + t.Fatalf("error sending forkchoice, err=%v", err) + } + if resp.PayloadStatus != engine.INVALID_TERMINAL_BLOCK { + t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) + } + + // Test parent already post TTD in NewPayload + args := &miner.BuildPayloadArgs{ + Parent: parent.Hash(), + Timestamp: parent.Time() + 1, + Random: crypto.Keccak256Hash([]byte{byte(1)}), + FeeRecipient: parent.Coinbase(), + } + payload, err := api.eth.Miner().BuildPayload(args, false) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + data := *payload.Resolve().ExecutionPayload + // We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash + txs, _ := decodeTransactions(data.Transactions) + header := &types.Header{ + ParentHash: data.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: data.FeeRecipient, + Root: data.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: data.ReceiptsRoot, + Bloom: types.BytesToBloom(data.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(data.Number), + GasLimit: data.GasLimit, + GasUsed: data.GasUsed, + Time: data.Timestamp, + BaseFee: data.BaseFeePerGas, + Extra: data.ExtraData, + MixDigest: data.Random, + } + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs}) + data.BlockHash = block.Hash() + // Send the new payload + resp2, err := api.NewPayloadV1(data) + if err != nil { + t.Fatalf("error sending NewPayload, err=%v", err) + } + if resp2 != engine.INVALID_TERMINAL_BLOCK { + t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) + } +} + // TestSimultaneousNewBlock does several parallel inserts, both as // newPayLoad and forkchoiceUpdate. This is to test that the api behaves // well even of the caller is not being 'serial'. diff --git a/eth/handler.go b/eth/handler.go index 6905caa29..c053b1de1 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -25,6 +25,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/dbft" "github.com/ethereum/go-ethereum/core" @@ -200,6 +201,20 @@ func newHandler(config *handlerConfig) (*handler, error) { } // Construct the downloader (long sync) h.downloader = downloader.New(config.Database, h.eventMux, h.chain, h.removePeer, h.enableSyncedFeatures) + if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil { + head := h.chain.CurrentBlock() + if td := h.chain.GetTd(head.Hash(), head.Number.Uint64()); td.Cmp(ttd) >= 0 { + log.Info("Chain post-TTD, sync via beacon client") + } else { + log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") + } + } else { + if _, ok := h.chain.Engine().(consensus.PoS); ok { + log.Info("Chain configured with PoS engine but no TTD.") + } else { + log.Error("Chain configured without TTD. Are you debugging sync?") + } + } // Construct the fetcher (short sync) validator := func(header *types.Header) error { // Reject all the PoS style headers in the first place. No matter diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 0c7398221..cc6876eb9 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -79,6 +79,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generat config = params.TestChainConfig engine = beacon.New(ethash.NewFaker()) ) + if shanghai { config = ¶ms.ChainConfig{ ChainID: big.NewInt(1), diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index f009b2059..b3cbe45db 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -75,8 +75,6 @@ func TestSupplyOmittedFields(t *testing.T) { } ) - gspec.Config.TerminalTotalDifficulty = big.NewInt(0) - out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { b.SetPoS() }) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 0f6ba10b9..2c33bdf53 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "io" + "math" "math/big" "net/http" "strings" @@ -28,6 +29,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -455,16 +457,18 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge RPCGasCap: 1000000, StateScheme: rawdb.HashScheme, } - var engine = beacon.New(ethash.NewFaker()) + var engine consensus.Engine = ethash.NewFaker() if shanghai { + engine = beacon.New(ethash.NewFaker()) gspec.Config.TerminalTotalDifficulty = common.Big0 - gspec.Config.MergeNetsplitBlock = common.Big0 // GenerateChain will increment timestamps by 10. // Shanghai upgrade at block 1. shanghaiTime := uint64(5) gspec.Config.ShanghaiTime = &shanghaiTime + } else { + // set an arbitrary large ttd as chains are required to be known to be merged + gspec.Config.TerminalTotalDifficulty = big.NewInt(math.MaxInt64) } - ethBackend, err := eth.New(stack, ethConf) if err != nil { t.Fatalf("could not create eth backend: %v", err) diff --git a/miner/miner.go b/miner/miner.go index 48c19657f..fe4b69c6e 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -69,7 +69,6 @@ var DefaultConfig = Config{ // engine and gathering the sealing result. type Miner struct { mux *event.TypeMux - eth Backend engine consensus.Engine exitCh chan struct{} startCh chan struct{} @@ -79,15 +78,14 @@ type Miner struct { wg sync.WaitGroup } -func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner { +func New(eth Backend, config *Config, mux *event.TypeMux, engine consensus.Engine) *Miner { miner := &Miner{ mux: mux, - eth: eth, engine: engine, exitCh: make(chan struct{}), startCh: make(chan struct{}), stopCh: make(chan struct{}), - worker: newWorker(config, chainConfig, engine, eth, mux, true), + worker: newWorker(config, engine, eth, mux, true), } miner.wg.Add(1) go miner.update() @@ -199,31 +197,33 @@ func (miner *Miner) SetExtra(extra []byte) error { return nil } -func (miner *Miner) SetGasTip(tip *big.Int) error { - miner.worker.setGasTip(tip) - return nil -} - // SetRecommitInterval sets the interval for sealing work resubmitting. func (miner *Miner) SetRecommitInterval(interval time.Duration) { miner.worker.setRecommitInterval(interval) } -func (miner *Miner) SetEtherbase(addr common.Address) { - miner.worker.setEtherbase(addr) -} - // SetPrioAddresses sets a list of addresses to prioritize for transaction inclusion. func (miner *Miner) SetPrioAddresses(prio []common.Address) { miner.worker.setPrioAddresses(prio) } +// SetEtherbase sets the etherbase address for the miner. +func (miner *Miner) SetEtherbase(addr common.Address) { + miner.worker.setEtherbase(addr) +} + // SetGasCeil sets the gaslimit to strive for when mining blocks post 1559. // For pre-1559 blocks, it sets the ceiling. func (miner *Miner) SetGasCeil(ceil uint64) { miner.worker.setGasCeil(ceil) } +// SetGasTip sets the minimum gas tip for inclusion. +func (miner *Miner) SetGasTip(tip *big.Int) error { + miner.worker.setGasTip(tip) + return nil +} + // SubscribePendingLogs starts delivering logs from pending transactions // to the given channel. func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { @@ -232,5 +232,5 @@ func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscript // BuildPayload builds the payload according to the provided parameters. func (miner *Miner) BuildPayload(args *BuildPayloadArgs, witness bool) (*Payload, error) { - return miner.worker.buildPayload(args, witness) + return miner.worker.buildPayload(args) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 6714e4405..310942454 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -294,6 +294,7 @@ func minerTestGenesisBlock(period uint64, gasLimit uint64, faucet common.Address }, } } + func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { // Create Ethash config config := Config{ @@ -325,7 +326,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { // Create event Mux mux := new(event.TypeMux) // Create Miner - miner := New(backend, &config, chainConfig, mux, engine) + miner := New(backend, &config, mux, engine) cleanup := func(skipMiner bool) { bc.Stop() engine.Close() diff --git a/miner/payload_building.go b/miner/payload_building.go index 5b1b0bb61..78d6574d1 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -206,7 +206,7 @@ func (payload *Payload) ResolveFull() *engine.ExecutionPayloadEnvelope { } // buildPayload builds the payload according to the provided parameters. -func (w *worker) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload, error) { +func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something // to deliver for not missing slot. diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 5e3af6f62..38e1b30d4 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -45,7 +45,7 @@ func TestBuildPayload(t *testing.T) { Random: common.Hash{}, FeeRecipient: recipient, } - payload, err := w.buildPayload(args, false) + payload, err := w.buildPayload(args) if err != nil { t.Fatalf("Failed to build payload %v", err) } diff --git a/miner/worker.go b/miner/worker.go index 5a77fab47..8bd33a6ae 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -170,6 +170,18 @@ type newPayloadResult struct { witness *stateless.Witness // Witness is an optional stateless proof } +// generateParams wraps various settings for generating sealing task. +type generateParams struct { + timestamp uint64 // The timestamp for sealing task + forceTime bool // Flag whether the given timestamp is immutable or not + parentHash common.Hash // Parent block hash, empty means the latest chain head + coinbase common.Address // The fee recipient address for including transaction + random common.Hash // The randomness generated by beacon chain, empty before the merge + withdrawals types.Withdrawals // List of withdrawals to include in block. + beaconRoot *common.Hash // The beacon root (cancun field). + noTxs bool // Flag whether an empty block without any transaction is expected +} + // getWorkReq represents a request for getting a new sealing work with provided parameters. type getWorkReq struct { params *generateParams @@ -188,7 +200,7 @@ type worker struct { config *Config chainConfig *params.ChainConfig engine consensus.Engine - eth Backend + txpool *txpool.TxPool chain *core.BlockChain // Feeds @@ -245,12 +257,12 @@ type worker struct { resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. } -func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, init bool) *worker { +func newWorker(config *Config, engine consensus.Engine, eth Backend, mux *event.TypeMux, init bool) *worker { worker := &worker{ config: config, - chainConfig: chainConfig, + chainConfig: eth.BlockChain().Config(), engine: engine, - eth: eth, + txpool: eth.TxPool(), chain: eth.BlockChain(), mux: mux, coinbase: config.Etherbase, @@ -269,8 +281,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), } // Override address to send miner rewards to in case of dBFT. - if chainConfig.DBFT != nil { - worker.coinbase = chainConfig.DBFT.Coinbase + if worker.chainConfig.DBFT != nil { + worker.coinbase = worker.chainConfig.DBFT.Coinbase } // Subscribe for transaction insertion events (whether from network or resurrects) worker.txsSub = eth.TxPool().SubscribeTransactions(worker.txsCh, true) @@ -538,7 +550,7 @@ func (w *worker) mainLoop() { for _, tx := range ev.Txs { acc, _ := types.Sender(w.current.signer, tx) txs[acc] = append(txs[acc], &txpool.LazyTransaction{ - Pool: w.eth.TxPool(), // We don't know where this came from, yolo resolve from everywhere + Pool: w.txpool, // We don't know where this came from, yolo resolve from everywhere Hash: tx.Hash(), Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in Time: tx.Time(), @@ -701,6 +713,160 @@ func (w *worker) resultLoop() { } } +// generateWork generates a sealing block based on the given parameters. +func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadResult { + work, err := w.prepareWork(params, witness) + if err != nil { + return &newPayloadResult{err: err} + } + defer work.discard() + + if !params.noTxs { + interrupt := new(atomic.Int32) + timer := time.AfterFunc(w.recommit, func() { + interrupt.Store(commitInterruptTimeout) + }) + defer timer.Stop() + + err := w.fillTransactions(interrupt, work) + if errors.Is(err, errBlockInterruptedByTimeout) { + log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.recommit)) + } + } + + body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} + allLogs := make([]*types.Log, 0) + for _, r := range work.receipts { + allLogs = append(allLogs, r.Logs...) + } + + // Collect consensus-layer requests if Prague is enabled. + var requests [][]byte + if w.chainConfig.IsPrague(work.header.Number, work.header.Time) { + requests = [][]byte{} + // EIP-6110 deposits + if err := core.ParseDepositLogs(&requests, allLogs, w.chainConfig); err != nil { + return &newPayloadResult{err: err} + } + // EIP-7002 + if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { + return &newPayloadResult{err: err} + } + // EIP-7251 consolidations + if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil { + return &newPayloadResult{err: err} + } + } + if requests != nil { + reqHash := types.CalcRequestsHash(requests) + work.header.RequestsHash = &reqHash + } + + block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, &body, work.receipts) + if err != nil { + return &newPayloadResult{err: err} + } + return &newPayloadResult{ + block: block, + fees: totalFees(block, work.receipts), + sidecars: work.sidecars, + stateDB: work.state, + receipts: work.receipts, + requests: requests, + witness: work.witness, + } +} + +// prepareWork constructs the sealing task according to the given parameters, +// either based on the last chain head or specified parent. In this function +// the pending transactions are not filled yet, only the empty task returned. +func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environment, error) { + w.mu.RLock() + defer w.mu.RUnlock() + + // Find the parent block for sealing task + parent := w.chain.CurrentBlock() + if genParams.parentHash != (common.Hash{}) { + block := w.chain.GetBlockByHash(genParams.parentHash) + if block == nil { + return nil, errors.New("missing parent") + } + parent = block.Header() + } + // Sanity check the timestamp correctness, recap the timestamp + // to parent+1 if the mutation is allowed. + timestamp := genParams.timestamp + if parent.Time >= timestamp { + if genParams.forceTime { + return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp) + } + timestamp = parent.Time + 1 + } + // Construct the sealing block header. + header := &types.Header{ + ParentHash: parent.Hash(), + Number: new(big.Int).Add(parent.Number, common.Big1), + GasLimit: core.CalcGasLimit(parent.GasLimit, w.config.GasCeil), + Time: timestamp, + Coinbase: genParams.coinbase, + } + // Set the extra field. + if len(w.extra) != 0 { + header.Extra = w.extra + } + // Set the randomness field from the beacon chain if it's available. + if genParams.random != (common.Hash{}) { + header.MixDigest = genParams.random + } + // Set baseFee and GasLimit if we are on an EIP-1559 chain + if w.chainConfig.IsLondon(header.Number) { + state, err := w.chain.StateAt(parent.Root) + if err != nil { + log.Error("Failed to get state", "err", err) + return nil, err + } + header.BaseFee = eip1559.CalcBaseFeeDBFT(w.chainConfig, parent, state) + if !w.chainConfig.IsLondon(parent.Number) { + parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() + header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) + } + } + // Run the consensus preparation with the default or customized consensus engine. + // Note that the `header.Time` may be changed. + if err := w.engine.Prepare(w.chain, header); err != nil { + log.Error("Failed to prepare header for sealing", "err", err) + return nil, err + } + // Apply EIP-4844, EIP-4788. + if w.chainConfig.IsCancun(header.Number, header.Time) { + var excessBlobGas uint64 + if w.chainConfig.IsCancun(parent.Number, parent.Time) { + excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent, timestamp) + } + header.BlobGasUsed = new(uint64) + header.ExcessBlobGas = &excessBlobGas + header.ParentBeaconRoot = genParams.beaconRoot + } + // Could potentially happen if starting to mine in an odd state. + // Note genParams.coinbase can be different with header.Coinbase + // since clique algorithm can modify the coinbase field in header. + env, err := w.makeEnv(parent, header, genParams.coinbase, witness) + if err != nil { + log.Error("Failed to create sealing context", "err", err) + return nil, err + } + if header.ParentBeaconRoot != nil { + core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) + } + if w.chainConfig.IsPrague(header.Number, header.Time) { + core.ProcessParentBlockHash(header.ParentHash, env.evm) + } + if w.chain.Config().DBFT != nil { + core.ProcessOnPersist(env.evm) + } + return env, nil +} + // makeEnv creates a new environment for the sealing block. func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, witness bool) (*environment, error) { // Retrieve the parent state to execute on top. @@ -936,108 +1102,6 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac return nil } -// generateParams wraps various settings for generating sealing task. -type generateParams struct { - timestamp uint64 // The timestamp for sealing task - forceTime bool // Flag whether the given timestamp is immutable or not - parentHash common.Hash // Parent block hash, empty means the latest chain head - coinbase common.Address // The fee recipient address for including transaction - random common.Hash // The randomness generated by beacon chain, empty before the merge - withdrawals types.Withdrawals // List of withdrawals to include in block. - beaconRoot *common.Hash // The beacon root (cancun field). - noTxs bool // Flag whether an empty block without any transaction is expected -} - -// prepareWork constructs the sealing task according to the given parameters, -// either based on the last chain head or specified parent. In this function -// the pending transactions are not filled yet, only the empty task returned. -func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environment, error) { - w.mu.RLock() - defer w.mu.RUnlock() - - // Find the parent block for sealing task - parent := w.chain.CurrentBlock() - if genParams.parentHash != (common.Hash{}) { - block := w.chain.GetBlockByHash(genParams.parentHash) - if block == nil { - return nil, errors.New("missing parent") - } - parent = block.Header() - } - // Sanity check the timestamp correctness, recap the timestamp - // to parent+1 if the mutation is allowed. - timestamp := genParams.timestamp - if parent.Time >= timestamp { - if genParams.forceTime { - return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp) - } - timestamp = parent.Time + 1 - } - // Construct the sealing block header. - header := &types.Header{ - ParentHash: parent.Hash(), - Number: new(big.Int).Add(parent.Number, common.Big1), - GasLimit: core.CalcGasLimit(parent.GasLimit, w.config.GasCeil), - Time: timestamp, - Coinbase: genParams.coinbase, - } - // Set the extra field. - if len(w.extra) != 0 { - header.Extra = w.extra - } - // Set the randomness field from the beacon chain if it's available. - if genParams.random != (common.Hash{}) { - header.MixDigest = genParams.random - } - // Set baseFee and GasLimit if we are on an EIP-1559 chain - if w.chainConfig.IsLondon(header.Number) { - state, err := w.chain.StateAt(parent.Root) - if err != nil { - log.Error("Failed to get state", "err", err) - return nil, err - } - header.BaseFee = eip1559.CalcBaseFeeDBFT(w.chainConfig, parent, state) - if !w.chainConfig.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() - header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) - } - } - // Run the consensus preparation with the default or customized consensus engine. - // Note that the `header.Time` may be changed. - if err := w.engine.Prepare(w.chain, header); err != nil { - log.Error("Failed to prepare header for sealing", "err", err) - return nil, err - } - // Apply EIP-4844, EIP-4788. - if w.chainConfig.IsCancun(header.Number, header.Time) { - var excessBlobGas uint64 - if w.chainConfig.IsCancun(parent.Number, parent.Time) { - excessBlobGas = eip4844.CalcExcessBlobGas(w.chainConfig, parent, timestamp) - } - header.BlobGasUsed = new(uint64) - header.ExcessBlobGas = &excessBlobGas - header.ParentBeaconRoot = genParams.beaconRoot - } - // Could potentially happen if starting to mine in an odd state. - // Note genParams.coinbase can be different with header.Coinbase - // since clique algorithm can modify the coinbase field in header. - env, err := w.makeEnv(parent, header, genParams.coinbase, witness) - if err != nil { - log.Error("Failed to create sealing context", "err", err) - return nil, err - } - if header.ParentBeaconRoot != nil { - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) - } - if w.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, env.evm) - } - if w.chain.Config().DBFT != nil { - core.ProcessOnPersist(env.evm) - } - return env, nil -} - // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. @@ -1058,10 +1122,10 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(w.chainConfig, env.header)) } filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false - pendingPlainTxs := w.eth.TxPool().Pending(filter) + pendingPlainTxs := w.txpool.Pending(filter) filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true - pendingBlobTxs := w.eth.TxPool().Pending(filter) + pendingBlobTxs := w.txpool.Pending(filter) // Split the pending transactions into locals and remotes. prioPlainTxs, normalPlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs @@ -1097,74 +1161,9 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err return nil } -// generateWork generates a sealing block based on the given parameters. -func (w *worker) generateWork(params *generateParams, witness bool) *newPayloadResult { - work, err := w.prepareWork(params, witness) - if err != nil { - return &newPayloadResult{err: err} - } - defer work.discard() - - if !params.noTxs { - interrupt := new(atomic.Int32) - timer := time.AfterFunc(w.recommit, func() { - interrupt.Store(commitInterruptTimeout) - }) - defer timer.Stop() - - err := w.fillTransactions(interrupt, work) - if errors.Is(err, errBlockInterruptedByTimeout) { - log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.recommit)) - } - } - - body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} - allLogs := make([]*types.Log, 0) - for _, r := range work.receipts { - allLogs = append(allLogs, r.Logs...) - } - - // Collect consensus-layer requests if Prague is enabled. - var requests [][]byte - if w.chainConfig.IsPrague(work.header.Number, work.header.Time) { - requests = [][]byte{} - // EIP-6110 deposits - if err := core.ParseDepositLogs(&requests, allLogs, w.chainConfig); err != nil { - return &newPayloadResult{err: err} - } - // EIP-7002 - if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { - return &newPayloadResult{err: err} - } - // EIP-7251 consolidations - if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil { - return &newPayloadResult{err: err} - } - } - if requests != nil { - reqHash := types.CalcRequestsHash(requests) - work.header.RequestsHash = &reqHash - } - - block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, &body, work.receipts) - if err != nil { - return &newPayloadResult{err: err} - } - return &newPayloadResult{ - block: block, - fees: totalFees(block, work.receipts), - sidecars: work.sidecars, - stateDB: work.state, - receipts: work.receipts, - requests: requests, - witness: work.witness, - } -} - // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. func (w *worker) commitWork(interrupt *atomic.Int32, timestamp int64) { - // Here preparation done on timer // Abort committing if node is still syncing if w.syncing.Load() { return @@ -1239,9 +1238,8 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti // Create a local environment copy, avoid the data race with snapshot state. // https://github.com/ethereum/go-ethereum/issues/24299 env := env.copy() - body := types.Body{Transactions: env.txs} // Withdrawals are set to nil here, because this is only called in PoW. - block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, &body, env.receipts) + block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, &types.Body{Transactions: env.txs}, env.receipts) if err != nil { return err } @@ -1252,8 +1250,6 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti fees := totalFees(block, env.receipts) feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), - "parent hash", block.ParentHash(), - "etherbase", block.Coinbase().String(), "txs", env.tcount, "gas", block.GasUsed(), "fees", feesInEther, "elapsed", common.PrettyDuration(time.Since(start))) diff --git a/miner/worker_test.go b/miner/worker_test.go index 95fd4b184..b2231fe07 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -177,7 +177,7 @@ func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) backend.txPool.Add(pendingTxs, true, false) - w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), false) + w := newWorker(testConfig, engine, backend, new(event.TypeMux), false) w.setEtherbase(testBankAddress) return w, backend } diff --git a/privnet/zk/genesis_privnet.json b/privnet/zk/genesis_privnet.json index dc87b7f7c..d26823903 100644 --- a/privnet/zk/genesis_privnet.json +++ b/privnet/zk/genesis_privnet.json @@ -19,6 +19,13 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + }, "dbft": { "period": 5, "standbyValidators": [ diff --git a/signer/core/api.go b/signer/core/api.go index 12acf925f..849736827 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -184,6 +184,8 @@ func StartClefAccountManager(ksLocation string, nousb, lightKDF bool, scpath str } } } + + // Clef doesn't allow insecure http account unlock. return accounts.NewManager(nil, backends...) } From abbc333a4dea06eb1e5536efa272a27369e5a568 Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Fri, 19 Sep 2025 11:34:52 +0800 Subject: [PATCH 343/354] privnet: enable prague fork --- privnet/four/genesis_privnet.json | 6 ++++++ privnet/seven/genesis_privnet.json | 6 ++++++ privnet/single/genesis_privnet.json | 6 ++++++ privnet/zk/genesis_privnet.json | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/privnet/four/genesis_privnet.json b/privnet/four/genesis_privnet.json index a7e42b6d1..3d4bfe368 100644 --- a/privnet/four/genesis_privnet.json +++ b/privnet/four/genesis_privnet.json @@ -19,11 +19,17 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "pragueTime": 0, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 6, + "max": 9, + "baseFeeUpdateFraction": 5007716 } }, "dbft": { diff --git a/privnet/seven/genesis_privnet.json b/privnet/seven/genesis_privnet.json index 30129bef1..72a33b531 100644 --- a/privnet/seven/genesis_privnet.json +++ b/privnet/seven/genesis_privnet.json @@ -19,11 +19,17 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "pragueTime": 0, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 6, + "max": 9, + "baseFeeUpdateFraction": 5007716 } }, "dbft": { diff --git a/privnet/single/genesis_privnet.json b/privnet/single/genesis_privnet.json index 6b6aa8932..76de92328 100644 --- a/privnet/single/genesis_privnet.json +++ b/privnet/single/genesis_privnet.json @@ -19,11 +19,17 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "pragueTime": 0, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 6, + "max": 9, + "baseFeeUpdateFraction": 5007716 } }, "dbft": { diff --git a/privnet/zk/genesis_privnet.json b/privnet/zk/genesis_privnet.json index d26823903..b8a8704bb 100644 --- a/privnet/zk/genesis_privnet.json +++ b/privnet/zk/genesis_privnet.json @@ -19,11 +19,17 @@ "neoXAMEVBlock": 0, "neoXEthSigBlock": 0, "cancunTime": 0, + "pragueTime": 0, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 6, + "max": 9, + "baseFeeUpdateFraction": 5007716 } }, "dbft": { From 8a29fb1dd46d6f8201b481e3a711cbcab3a38290 Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Fri, 19 Sep 2025 12:11:22 +0800 Subject: [PATCH 344/354] dbft: fix prague fork bug --- consensus/dbft/dbft.go | 11 +++++++++++ miner/worker.go | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index 237dcebaf..9ff2b6d29 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -1794,6 +1794,17 @@ func (c *DBFT) verifyHeader(chain consensus.ChainHeaderReader, header *types.Hea if !cancun && header.ParentBeaconRoot != nil { return fmt.Errorf("invalid parentBeaconRoot, have %x, expected nil", header.ParentBeaconRoot) } + + prague := chain.Config().IsPrague(header.Number, header.Time) + if !prague { + if header.RequestsHash != nil { + return fmt.Errorf("invalid RequestsHash, have %#x, expected nil", header.RequestsHash) + } + } else { + if header.RequestsHash == nil { + return errors.New("header has nil RequestsHash after Prague") + } + } // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents, isSealed) } diff --git a/miner/worker.go b/miner/worker.go index 8bd33a6ae..afd429acd 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -846,6 +846,10 @@ func (w *worker) prepareWork(genParams *generateParams, witness bool) (*environm header.BlobGasUsed = new(uint64) header.ExcessBlobGas = &excessBlobGas header.ParentBeaconRoot = genParams.beaconRoot + + if w.chainConfig.IsPrague(header.Number, header.Time) { + header.RequestsHash = &types.EmptyRequestsHash + } } // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase From 8594b4374f6eeb5497b4286ee043c8800fbc4f85 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Thu, 9 Oct 2025 12:07:01 +0800 Subject: [PATCH 345/354] core/rawdb: fix TestWriteAncientHeaderChain --- core/rawdb/accessors_chain_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 3ffac693b..a67c96476 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -507,6 +507,7 @@ func TestWriteAncientHeaderChain(t *testing.T) { var headers []*types.Header headers = append(headers, &types.Header{ Number: big.NewInt(0), + Difficulty: big.NewInt(2), Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, TxHash: types.EmptyTxsHash, @@ -514,14 +515,14 @@ func TestWriteAncientHeaderChain(t *testing.T) { }) headers = append(headers, &types.Header{ Number: big.NewInt(1), + Difficulty: big.NewInt(2), Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, TxHash: types.EmptyTxsHash, ReceiptHash: types.EmptyReceiptsHash, }) // Write and verify the header in the database - ptd := new(big.Int) - WriteAncientHeaderChain(db, headers, ptd) + WriteAncientHeaderChain(db, headers, new(big.Int)) for _, header := range headers { if blob := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); len(blob) == 0 { From ffba5f80c5e6220d8d380540472b34cda5dcc72a Mon Sep 17 00:00:00 2001 From: Eric <511488397@qq.com> Date: Thu, 9 Oct 2025 14:28:53 +0800 Subject: [PATCH 346/354] eth/downloader: fix snap sync of the db on the path scheme --- eth/downloader/downloader.go | 17 +++++++++++++++++ eth/handler_eth.go | 7 +++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index ea569430a..36c2d06ce 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -468,6 +468,23 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * if err != nil { return err } + if d.blockchain.TrieDB().Scheme() == rawdb.PathScheme && mode == SnapSync { + // Ensure the pivot is above the minimum full block threshold + pivotNumber := uint64(0) + if pivot != nil { + pivotNumber = pivot.Number.Uint64() + } + if pivotNumber < uint64(fsMinFullBlocks) { + block := d.blockchain.CurrentBlock() + if err = d.blockchain.TrieDB().Enable(block.Root); err != nil { + return fmt.Errorf("failed to enable trie db: %v", err) + } + log.Info("Disabling snap sync of the db on the path scheme due to the pivot header being positioned too low", + "pivot", pivotNumber) + <-time.After(3 * time.Second) + return errCanceled + } + } } else { // In beacon mode, use the skeleton chain to retrieve the headers from latest, _, final, err = d.skeleton.Bounds() diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 1d6b9d4c4..52f0eee55 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -65,7 +65,7 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { return h.handleBlockAnnounces(peer, hashes, numbers) case *eth.NewBlockPacket: - return h.handleBlockBroadcast(peer, packet.Block, packet.TD) + return h.handleBlockBroadcast(peer, packet) case *eth.NewPooledTransactionHashesPacket: return h.txFetcher.Notify(peer.ID(), packet.Types, packet.Sizes, packet.Hashes) @@ -121,7 +121,10 @@ func (h *ethHandler) handleBlockAnnounces(peer *eth.Peer, hashes []common.Hash, // handleBlockBroadcast is invoked from a peer's message handler when it transmits a // block broadcast for the local node to process. -func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, block *types.Block, td *big.Int) error { +func (h *ethHandler) handleBlockBroadcast(peer *eth.Peer, packet *eth.NewBlockPacket) error { + block := packet.Block + td := packet.TD + // Schedule the block for import h.blockFetcher.Enqueue(peer.ID(), block) From 1a369ec4b0ea1322422902d11997a01d33711384 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Fri, 10 Oct 2025 10:35:47 +0800 Subject: [PATCH 347/354] eth: update apis with pruning cutoff --- eth/api_backend.go | 51 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index f89f7bd7b..6c7644fc8 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/filtermaps" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/systemcontracts" @@ -94,7 +95,13 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb } return block, nil } - return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil + var bn uint64 + if number == rpc.EarliestBlockNumber { + bn = b.HistoryPruningCutoff() + } else { + bn = uint64(number) + } + return b.eth.blockchain.GetHeaderByNumber(bn), nil } func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { @@ -146,11 +153,27 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe } return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } - return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil + bn := uint64(number) // the resolved number + if number == rpc.EarliestBlockNumber { + bn = b.HistoryPruningCutoff() + } + block := b.eth.blockchain.GetBlockByNumber(bn) + if block == nil && bn < b.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } + return block, nil } func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return b.eth.blockchain.GetBlockByHash(hash), nil + number := b.eth.blockchain.GetBlockNumber(hash) + if number == nil { + return nil, nil + } + block := b.eth.blockchain.GetBlock(hash, *number) + if block == nil && *number < b.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } + return block, nil } // GetBody returns body of a block. It does not resolve special block numbers. @@ -158,10 +181,14 @@ func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rp if number < 0 || hash == (common.Hash{}) { return nil, errors.New("invalid arguments; expect hash and no special block numbers") } - if body := b.eth.blockchain.GetBody(hash); body != nil { - return body, nil + body := b.eth.blockchain.GetBody(hash) + if body == nil { + if uint64(number) < b.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } + return nil, errors.New("block body not found") } - return nil, errors.New("block body not found") + return body, nil } func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { @@ -178,6 +205,9 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r } block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64()) if block == nil { + if header.Number.Uint64() < b.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } return nil, errors.New("header found, but block body is missing") } return block, nil @@ -237,6 +267,11 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } +func (b *EthAPIBackend) HistoryPruningCutoff() uint64 { + bn, _ := b.eth.blockchain.HistoryPruningCutoff() + return bn +} + func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return b.eth.blockchain.GetReceiptsByHash(hash), nil } @@ -418,10 +453,6 @@ func (b *EthAPIBackend) ChainDb() ethdb.Database { return b.eth.ChainDb() } -func (b *EthAPIBackend) EventMux() *event.TypeMux { - return b.eth.EventMux() -} - func (b *EthAPIBackend) AccountManager() *accounts.Manager { return b.eth.AccountManager() } From 4ed40ede5cd4af66e608dcd00caeafdfe89ef297 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Sat, 11 Oct 2025 15:26:29 +0800 Subject: [PATCH 348/354] eth/downloader: update with pruning cutoff --- eth/downloader/beaconsync.go | 21 ++++++ eth/downloader/downloader.go | 131 ++++++++++++++++++++++++++--------- 2 files changed, 121 insertions(+), 31 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index a56430ad7..d0bdac94a 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -292,6 +292,27 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { fsHeaderContCheckTimer := time.NewTimer(fsHeaderContCheck) defer fsHeaderContCheckTimer.Stop() + // Verify the header at configured chain cutoff, ensuring it's matched with + // the configured hash. Skip the check if the configured cutoff is even higher + // than the sync target, which is definitely not a common case. + if d.chainCutoffNumber != 0 && d.chainCutoffNumber >= from && d.chainCutoffNumber <= head.Number.Uint64() { + h := d.skeleton.Header(d.chainCutoffNumber) + if h == nil { + if d.chainCutoffNumber < tail.Number.Uint64() { + dist := tail.Number.Uint64() - d.chainCutoffNumber + if len(localHeaders) >= int(dist) { + h = localHeaders[dist-1] + } + } + } + if h == nil { + return fmt.Errorf("header at chain cutoff is not available, cutoff: %d", d.chainCutoffNumber) + } + if h.Hash() != d.chainCutoffHash { + return fmt.Errorf("header at chain cutoff mismatched, want: %v, got: %v", d.chainCutoffHash, h.Hash()) + } + } + for { // Some beacon headers might have appeared since the last cycle, make // sure we're always syncing to all available ones diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 36c2d06ce..e10cd5e29 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "math/big" + "sort" "sync" "sync/atomic" "time" @@ -121,6 +122,12 @@ type Downloader struct { committed atomic.Bool ancientLimit uint64 // The maximum block number which can be regarded as ancient data. + // The cutoff block number and hash before which chain segments (bodies + // and receipts) are skipped during synchronization. 0 means the entire + // chain segment is aimed for synchronization. + chainCutoffNumber uint64 + chainCutoffHash common.Hash + // Channels headerProcCh chan *headerTask // Channel to feed the header processor new tasks @@ -193,6 +200,10 @@ type BlockChain interface { // SnapSyncCommitHead directly commits the head block to a certain entity. SnapSyncCommitHead(common.Hash) error + // InsertHeadersBeforeCutoff inserts a batch of headers before the configured + // chain cutoff into the ancient store. + InsertHeadersBeforeCutoff([]*types.Header) (int, error) + // InsertChain inserts a batch of blocks into the local chain. InsertChain(types.Blocks) (int, error) @@ -205,22 +216,29 @@ type BlockChain interface { // TrieDB retrieves the low level trie database used for interacting // with trie nodes. TrieDB() *triedb.Database + + // HistoryPruningCutoff returns the configured history pruning point. + // Block bodies along with the receipts will be skipped for synchronization. + HistoryPruningCutoff() (uint64, common.Hash) } // New creates a new downloader to fetch hashes and blocks from remote peers. func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, dropPeer peerDropFn, success func()) *Downloader { + cutoffNumber, cutoffHash := chain.HistoryPruningCutoff() dl := &Downloader{ - stateDB: stateDb, - mux: mux, - queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), - peers: newPeerSet(), - blockchain: chain, - dropPeer: dropPeer, - headerProcCh: make(chan *headerTask, 1), - quitCh: make(chan struct{}), - SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()), - stateSyncStart: make(chan *stateSync), - syncStartBlock: chain.CurrentSnapBlock().Number.Uint64(), + stateDB: stateDb, + mux: mux, + queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), + peers: newPeerSet(), + blockchain: chain, + chainCutoffNumber: cutoffNumber, + chainCutoffHash: cutoffHash, + dropPeer: dropPeer, + headerProcCh: make(chan *headerTask, 1), + quitCh: make(chan struct{}), + SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()), + stateSyncStart: make(chan *stateSync), + syncStartBlock: chain.CurrentSnapBlock().Number.Uint64(), } // Create the post-merge skeleton syncer and start the process dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success)) @@ -599,6 +617,12 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * d.ancientLimit = 0 } } + // Extend the ancient chain segment range if the ancient limit is even + // below the pre-configured chain cutoff. + if d.chainCutoffNumber != 0 && d.chainCutoffNumber > d.ancientLimit { + d.ancientLimit = d.chainCutoffNumber + log.Info("Extend the ancient range with configured cutoff", "cutoff", d.chainCutoffNumber) + } frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here. // If a part of blockchain data has already been written into active store, @@ -617,8 +641,17 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * log.Info("Truncated excess ancient chain segment", "oldhead", frozen-1, "newhead", origin) } } + // Skip ancient chain segments if Geth is running with a configured chain cutoff. + // These segments are not guaranteed to be available in the network. + chainOffset := origin + 1 + if mode == SnapSync && d.chainCutoffNumber != 0 { + if chainOffset < d.chainCutoffNumber { + chainOffset = d.chainCutoffNumber + log.Info("Skip chain segment before cutoff", "origin", origin, "cutoff", d.chainCutoffNumber) + } + } // Initiate the sync using a concurrent header and content retrieval algorithm - d.queue.Prepare(origin+1, mode) + d.queue.Prepare(chainOffset, mode) if d.syncInitHook != nil { d.syncInitHook(origin, height) } @@ -632,8 +665,8 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * } fetchers := []func() error{ headerFetcher, // Headers are always retrieved - func() error { return d.fetchBodies(origin+1, beaconMode) }, // Bodies are retrieved during normal and snap sync - func() error { return d.fetchReceipts(origin+1, beaconMode) }, // Receipts are retrieved during snap sync + func() error { return d.fetchBodies(chainOffset, beaconMode) }, // Bodies are retrieved during normal and snap sync + func() error { return d.fetchReceipts(chainOffset, beaconMode) }, // Receipts are retrieved during snap sync func() error { return d.processHeaders(origin+1, td, ttd, beaconMode) }, } if mode == SnapSync { @@ -1307,7 +1340,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode return nil } // Otherwise split the chunk of headers into batches and process them - headers, hashes := task.headers, task.hashes + headers, hashes, scheduled := task.headers, task.hashes, false gotHeaders = true for len(headers) > 0 { @@ -1325,10 +1358,25 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode chunkHeaders := headers[:limit] chunkHashes := hashes[:limit] - // In case of header only syncing, validate the chunk immediately + // Split the headers around the chain cutoff + var cutoff int + if mode == SnapSync && d.chainCutoffNumber != 0 { + cutoff = sort.Search(len(chunkHeaders), func(i int) bool { + return chunkHeaders[i].Number.Uint64() >= d.chainCutoffNumber + }) + } + // Insert the header chain into the ancient store (with block bodies and + // receipts set to nil) if they fall before the cutoff. if mode == SnapSync { - if len(chunkHeaders) > 0 { - if n, err := d.blockchain.InsertHeaderChain(chunkHeaders); err != nil { + if cutoff != 0 { + if n, err := d.blockchain.InsertHeadersBeforeCutoff(chunkHeaders[:cutoff]); err != nil { + log.Warn("Failed to insert ancient header chain", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) + return fmt.Errorf("%w: %v", errInvalidChain, err) + } + log.Debug("Inserted headers before cutoff", "number", chunkHeaders[cutoff-1].Number, "hash", chunkHashes[cutoff-1]) + } + if len(chunkHeaders[cutoff:]) > 0 { + if n, err := d.blockchain.InsertHeaderChain(chunkHeaders[cutoff:]); err != nil { log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } @@ -1343,12 +1391,21 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode case <-timer.C: } } - // Otherwise insert the headers for content retrieval - inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) - if inserts != len(chunkHeaders) { - return fmt.Errorf("%w: stale headers", errBadPeer) + // Otherwise, schedule the headers for content retrieval (block bodies and + // potentially receipts in snap sync). + // + // Skip the bodies/receipts retrieval scheduling before the cutoff in snap + // sync if chain pruning is configured. + if mode == SnapSync && cutoff != 0 { + chunkHeaders = chunkHeaders[cutoff:] + chunkHashes = chunkHashes[cutoff:] + } + if len(chunkHeaders) > 0 { + scheduled = true + if d.queue.Schedule(chunkHeaders, chunkHashes, origin+uint64(cutoff)) != len(chunkHeaders) { + return fmt.Errorf("%w: stale headers", errBadPeer) + } } - headers = headers[limit:] hashes = hashes[limit:] origin += uint64(limit) @@ -1360,11 +1417,13 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } d.syncStatsLock.Unlock() - // Signal the content downloaders of the availability of new tasks - for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { - select { - case ch <- true: - default: + // Signal the downloader of the availability of new tasks + if scheduled { + for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { + select { + case ch <- true: + default: + } } } } @@ -1724,10 +1783,20 @@ func (d *Downloader) reportSnapSyncProgress(force bool) { header = d.blockchain.CurrentHeader() block = d.blockchain.CurrentSnapBlock() ) - syncedBlocks := block.Number.Uint64() - d.syncStartBlock - if syncedBlocks == 0 { + // Prevent reporting if nothing has been synchronized yet + if block.Number.Uint64() <= d.syncStartBlock { return } + // Prevent reporting noise if the actual chain synchronization (headers + // and bodies) hasn't started yet. Inserting the ancient header chain is + // fast enough and would introduce significant bias if included in the count. + if d.chainCutoffNumber != 0 && block.Number.Uint64() <= d.chainCutoffNumber { + return + } + fetchedBlocks := block.Number.Uint64() - d.syncStartBlock + if d.chainCutoffNumber != 0 && d.chainCutoffNumber > d.syncStartBlock { + fetchedBlocks = block.Number.Uint64() - d.chainCutoffNumber + } // Retrieve the current chain head and calculate the ETA latest, _, _, err := d.skeleton.Bounds() if err != nil { @@ -1742,7 +1811,7 @@ func (d *Downloader) reportSnapSyncProgress(force bool) { } var ( left = latest.Number.Uint64() - block.Number.Uint64() - eta = time.Since(d.syncStartTime) / time.Duration(syncedBlocks) * time.Duration(left) + eta = time.Since(d.syncStartTime) / time.Duration(fetchedBlocks) * time.Duration(left) progress = fmt.Sprintf("%.2f%%", float64(block.Number.Uint64())*100/float64(latest.Number.Uint64())) headers = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(header.Number.Uint64()), common.StorageSize(headerBytes).TerminalString()) From 1c902b34167b440a7977ab04a69a295a70cbe6f8 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Sat, 11 Oct 2025 17:29:53 +0800 Subject: [PATCH 349/354] *: revert 1940bd3a48c1bfc62a319169b1e2cdab68ec51ae --- consensus/consensus.go | 8 --- consensus/dbft/dbft.go | 12 ---- core/blockchain.go | 60 +++++-------------- core/blockchain_reader.go | 25 +------- core/events.go | 3 - core/headerchain.go | 11 ---- core/txpool/blobpool/blobpool.go | 4 +- eth/api_backend.go | 4 -- eth/ethconfig/config.go | 1 + eth/filters/api.go | 59 ------------------- eth/filters/filter_system.go | 74 ++++++------------------ eth/filters/filter_system_test.go | 21 +++---- eth/handler.go | 7 +-- internal/ethapi/api_test.go | 3 - internal/ethapi/backend.go | 1 - internal/ethapi/transaction_args_test.go | 3 - 16 files changed, 47 insertions(+), 249 deletions(-) diff --git a/consensus/consensus.go b/consensus/consensus.go index c246295b5..ff76d31f5 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -118,11 +118,3 @@ type Engine interface { // Close terminates any background threads maintained by the consensus engine. Close() error } - -// PoS consensus engine. -type PoS interface { - Engine - - // GetFinalizedHeader retrieves the finalized header for a given header. - GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header -} diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index 9ff2b6d29..a85ccbd3d 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -2959,15 +2959,3 @@ func unpackContractExecutionResult(res interface{}, result *core.ExecutionResult } return contractAbi.UnpackIntoInterface(&res, method, result.Return()) } - -// GetFinalizedHeader returns highest finalized block header. -func (c *DBFT) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *types.Header) *types.Header { - if chain == nil || header == nil { - return nil - } - if !chain.Config().IsNeoXDKG(header.Number) || header.Number.Uint64() < 1 { - return chain.GetHeaderByNumber(0) - } - - return chain.GetHeaderByNumber(header.Number.Uint64() - 1) -} diff --git a/core/blockchain.go b/core/blockchain.go index 0083b1236..c75ab5bd4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -244,16 +244,15 @@ type BlockChain struct { statedb *state.CachingDB // State database to reuse between imports (contains state cache) txIndexer *txIndexer // Transaction indexer, might be nil if not enabled - hc *HeaderChain - rmLogsFeed event.Feed - chainFeed event.Feed - chainHeadFeed event.Feed - logsFeed event.Feed - blockProcFeed event.Feed - finalizedHeaderFeed event.Feed - blockProcCounter int32 - scope event.SubscriptionScope - genesisBlock *types.Block + hc *HeaderChain + rmLogsFeed event.Feed + chainFeed event.Feed + chainHeadFeed event.Feed + logsFeed event.Feed + blockProcFeed event.Feed + blockProcCounter int32 + scope event.SubscriptionScope + genesisBlock *types.Block // This mutex synchronizes chain write operations. // Readers don't need to take it, they can just read the database. @@ -525,17 +524,6 @@ func (bc *BlockChain) empty() bool { return true } -// GetFinalizedNumber returns the highest finalized number before the specific block. -func (bc *BlockChain) GetFinalizedNumber(header *types.Header) uint64 { - if p, ok := bc.engine.(consensus.PoS); ok { - if finalizedHeader := p.GetFinalizedHeader(bc, header); finalizedHeader != nil { - return finalizedHeader.Number.Uint64() - } - } - - return 0 -} - // loadLastState loads the last known chain state from the database. This method // assumes that the chain manager mutex is held. func (bc *BlockChain) loadLastState() error { @@ -611,7 +599,8 @@ func (bc *BlockChain) loadLastState() error { // Issue a status log for the user var ( - currentSnapBlock = bc.CurrentSnapBlock() + currentSnapBlock = bc.CurrentSnapBlock() + currentFinalBlock = bc.CurrentFinalBlock() headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64()) blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64()) @@ -624,14 +613,9 @@ func (bc *BlockChain) loadLastState() error { snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) } - if p, ok := bc.engine.(consensus.PoS); ok { - if currentFinalizedHeader := p.GetFinalizedHeader(bc, headHeader); currentFinalizedHeader != nil { - bc.currentFinalBlock.Store(currentFinalizedHeader) - if currentFinalizedBlock := bc.GetBlockByHash(currentFinalizedHeader.Hash()); currentFinalizedBlock != nil { - finalTd := bc.GetTd(currentFinalizedBlock.Hash(), currentFinalizedBlock.NumberU64()) - log.Info("Loaded most recent local finalized block", "number", currentFinalizedBlock.Number(), "hash", currentFinalizedBlock.Hash(), "root", currentFinalizedBlock.Root(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalizedBlock.Time()), 0))) - } - } + if currentFinalBlock != nil { + finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64()) + log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0))) } if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil { log.Info("Loaded last snap-sync pivot marker", "number", *pivot) @@ -1716,14 +1700,6 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types if len(logs) > 0 { bc.logsFeed.Send(logs) } - - var finalizedHeader *types.Header - if p, ok := bc.Engine().(consensus.PoS); ok { - if finalizedHeader = p.GetFinalizedHeader(bc, block.Header()); finalizedHeader != nil { - bc.SetFinalized(finalizedHeader) - } - } - // In theory, we should fire a ChainHeadEvent when we inject // a canonical block, but sometimes we can insert a batch of // canonical blocks. Avoid firing too many ChainHeadEvents, @@ -1731,9 +1707,6 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types // event here. if emitHeadEvent { bc.chainHeadFeed.Send(ChainHeadEvent{Header: block.Header()}) - if finalizedHeader != nil { - bc.finalizedHeaderFeed.Send(FinalizedHeaderEvent{finalizedHeader}) - } } } return status, nil @@ -1827,11 +1800,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness defer func() { if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { bc.chainHeadFeed.Send(ChainHeadEvent{Header: lastCanon.Header()}) - if p, ok := bc.Engine().(consensus.PoS); ok { - if finalizedHeader := p.GetFinalizedHeader(bc, lastCanon.Header()); finalizedHeader != nil { - bc.finalizedHeaderFeed.Send(FinalizedHeaderEvent{finalizedHeader}) - } - } } }() // Start the parallel header verifier diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 606752c83..94e3fae2c 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -54,29 +54,13 @@ func (bc *BlockChain) CurrentSnapBlock() *types.Header { // CurrentFinalBlock retrieves the current finalized block of the canonical // chain. The block is retrieved from the blockchain's internal cache. func (bc *BlockChain) CurrentFinalBlock() *types.Header { - if p, ok := bc.engine.(consensus.PoS); ok { - currentHeader := bc.CurrentHeader() - if currentHeader == nil { - return nil - } - return p.GetFinalizedHeader(bc, currentHeader) - } - - return nil + return bc.currentFinalBlock.Load() } // CurrentSafeBlock retrieves the current safe block of the canonical // chain. The block is retrieved from the blockchain's internal cache. func (bc *BlockChain) CurrentSafeBlock() *types.Header { - if p, ok := bc.engine.(consensus.PoS); ok { - currentHeader := bc.CurrentHeader() - if currentHeader == nil { - return nil - } - return p.GetFinalizedHeader(bc, currentHeader) - } - - return nil + return bc.currentSafeBlock.Load() } // HasHeader checks if a block header is present in the database or not, caching @@ -477,8 +461,3 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription { return bc.scope.Track(bc.blockProcFeed.Subscribe(ch)) } - -// SubscribeFinalizedHeaderEvent registers a subscription of FinalizedHeaderEvent. -func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription { - return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch)) -} diff --git a/core/events.go b/core/events.go index 5f00a58a5..433d101fd 100644 --- a/core/events.go +++ b/core/events.go @@ -32,9 +32,6 @@ type NewMinedBlockEvent struct{ Block *types.Block } // RemovedLogsEvent is posted when a reorg happens type RemovedLogsEvent struct{ Logs []*types.Log } -// FinalizedHeaderEvent is posted when a finalized header is reached. -type FinalizedHeaderEvent struct{ Header *types.Header } - type ChainEvent struct { Header *types.Header } diff --git a/core/headerchain.go b/core/headerchain.go index 96d66af60..506cd7049 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -99,17 +99,6 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c return hc, nil } -// GetFinalizedNumber returns the highest finalized number before the specific block. -func (hc *HeaderChain) GetFinalizedNumber(header *types.Header) uint64 { - if p, ok := hc.engine.(consensus.PoS); ok { - if finalizedHeader := p.GetFinalizedHeader(hc, header); finalizedHeader != nil { - return finalizedHeader.Number.Uint64() - } - } - - return 0 -} - // GetBlockNumber retrieves the block number belonging to the given hash // from the cache or database func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index bcdda044c..cb092652f 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -840,7 +840,9 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) { } // Flush out any blobs from limbo that are older than the latest finality if p.chain.Config().IsCancun(p.head.Number, p.head.Time) { - p.limbo.finalize(p.chain.CurrentFinalBlock()) + if h := p.chain.CurrentFinalBlock(); h != nil { + p.limbo.finalize(h) + } } // Reset the price heap for the new set of basefee/blobfee pairs var ( diff --git a/eth/api_backend.go b/eth/api_backend.go index 6c7644fc8..f8dff5d01 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -312,10 +312,6 @@ func (b *EthAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) e return b.eth.BlockChain().SubscribeChainHeadEvent(ch) } -func (b *EthAPIBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { - return b.eth.BlockChain().SubscribeFinalizedHeaderEvent(ch) -} - func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return b.eth.BlockChain().SubscribeLogsEvent(ch) } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index c5511cff3..aeb49b656 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -197,6 +197,7 @@ type Config struct { // Clique is allowed for now to live standalone, but ethash is forbidden and can // only exist on already merged networks. func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database, statisticsCfg dbft.StatisticsConfig) (consensus.Engine, error) { + // TODO: config TTD correctly and move this check back after Clique if config.DBFT != nil { bft, err := dbft.New(config, db, statisticsCfg) if err != nil { diff --git a/eth/filters/api.go b/eth/filters/api.go index 7f47d1be6..a32b48433 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -273,65 +273,6 @@ func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { return rpcSub, nil } -// NewFinalizedHeaderFilter creates a filter that fetches finalized headers that are reached. -func (api *FilterAPI) NewFinalizedHeaderFilter() rpc.ID { - var ( - headers = make(chan *types.Header) - headerSub = api.events.SubscribeNewFinalizedHeaders(headers) - ) - - api.filtersMu.Lock() - api.filters[headerSub.ID] = &filter{typ: FinalizedHeadersSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: headerSub} - api.filtersMu.Unlock() - - go func() { - for { - select { - case h := <-headers: - api.filtersMu.Lock() - if f, found := api.filters[headerSub.ID]; found { - f.hashes = append(f.hashes, h.Hash()) - } - api.filtersMu.Unlock() - case <-headerSub.Err(): - api.filtersMu.Lock() - delete(api.filters, headerSub.ID) - api.filtersMu.Unlock() - return - } - } - }() - - return headerSub.ID -} - -// NewFinalizedHeaders send a notification each time a new finalized header is reached. -func (api *FilterAPI) NewFinalizedHeaders(ctx context.Context) (*rpc.Subscription, error) { - notifier, supported := rpc.NotifierFromContext(ctx) - if !supported { - return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported - } - - rpcSub := notifier.CreateSubscription() - - go func() { - headers := make(chan *types.Header) - headersSub := api.events.SubscribeNewFinalizedHeaders(headers) - defer headersSub.Unsubscribe() - - for { - select { - case h := <-headers: - notifier.Notify(rpcSub.ID, h) - case <-rpcSub.Err(): - return - } - } - }() - - return rpcSub, nil -} - // Logs creates a subscription that fires for all new log that match the given filter criteria. func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 34b06ecdc..1bf6496bb 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -67,7 +67,6 @@ type Backend interface { ChainConfig() *params.ChainConfig SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription - SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription @@ -160,8 +159,6 @@ const ( BlocksSubscription // LastIndexSubscription keeps track of the last index LastIndexSubscription - // FinalizedHeadersSubscription queries hashes for finalized headers that are reached - FinalizedHeadersSubscription ) const ( @@ -174,8 +171,6 @@ const ( logsChanSize = 10 // chainEvChanSize is the size of channel listening to ChainEvent. chainEvChanSize = 10 - // finalizedHeaderEvChanSize is the size of channel listening to FinalizedHeaderEvent. - finalizedHeaderEvChanSize = 10 ) type subscription struct { @@ -197,20 +192,18 @@ type EventSystem struct { sys *FilterSystem // Subscriptions - txsSub event.Subscription // Subscription for new transaction event - logsSub event.Subscription // Subscription for new log event - rmLogsSub event.Subscription // Subscription for removed log event - chainSub event.Subscription // Subscription for new chain event - finalizedHeaderSub event.Subscription // Subscription for new finalized header + txsSub event.Subscription // Subscription for new transaction event + logsSub event.Subscription // Subscription for new log event + rmLogsSub event.Subscription // Subscription for removed log event + chainSub event.Subscription // Subscription for new chain event // Channels - install chan *subscription // install filter for event notification - uninstall chan *subscription // remove filter for event notification - txsCh chan core.NewTxsEvent // Channel to receive new transactions event - logsCh chan []*types.Log // Channel to receive new log event - rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event - chainCh chan core.ChainEvent // Channel to receive new chain event - finalizedHeaderCh chan core.FinalizedHeaderEvent // Channel to receive new finalized header event + install chan *subscription // install filter for event notification + uninstall chan *subscription // remove filter for event notification + txsCh chan core.NewTxsEvent // Channel to receive new transactions event + logsCh chan []*types.Log // Channel to receive new log event + rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event + chainCh chan core.ChainEvent // Channel to receive new chain event } // NewEventSystem creates a new manager that listens for event on the given mux, @@ -221,15 +214,14 @@ type EventSystem struct { // or by stopping the given mux. func NewEventSystem(sys *FilterSystem) *EventSystem { m := &EventSystem{ - sys: sys, - backend: sys.backend, - install: make(chan *subscription), - uninstall: make(chan *subscription), - txsCh: make(chan core.NewTxsEvent, txChanSize), - logsCh: make(chan []*types.Log, logsChanSize), - rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize), - chainCh: make(chan core.ChainEvent, chainEvChanSize), - finalizedHeaderCh: make(chan core.FinalizedHeaderEvent, finalizedHeaderEvChanSize), + sys: sys, + backend: sys.backend, + install: make(chan *subscription), + uninstall: make(chan *subscription), + txsCh: make(chan core.NewTxsEvent, txChanSize), + logsCh: make(chan []*types.Log, logsChanSize), + rmLogsCh: make(chan core.RemovedLogsEvent, rmLogsChanSize), + chainCh: make(chan core.ChainEvent, chainEvChanSize), } // Subscribe events @@ -237,15 +229,11 @@ func NewEventSystem(sys *FilterSystem) *EventSystem { m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh) m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) - m.finalizedHeaderSub = m.backend.SubscribeFinalizedHeaderEvent(m.finalizedHeaderCh) // Make sure none of the subscriptions are empty if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil { log.Crit("Subscribe for event system failed") } - if m.finalizedHeaderSub == nil { - log.Warn("Subscribe for finalized header event failed") - } go m.eventLoop() return m @@ -368,22 +356,6 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti return es.subscribe(sub) } -// SubscribeNewFinalizedHeaders creates a subscription that writes the finalized header of a block that is -// reached recently. -func (es *EventSystem) SubscribeNewFinalizedHeaders(headers chan *types.Header) *Subscription { - sub := &subscription{ - id: rpc.NewID(), - typ: FinalizedHeadersSubscription, - created: time.Now(), - logs: make(chan []*types.Log), - txs: make(chan []*types.Transaction), - headers: headers, - installed: make(chan struct{}), - err: make(chan error), - } - return es.subscribe(sub) -} - // SubscribePendingTxs creates a subscription that writes transactions for // transactions that enter the transaction pool. func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subscription { @@ -425,11 +397,6 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) f.headers <- ev.Header } } -func (es *EventSystem) handleFinalizedHeaderEvent(filters filterIndex, ev core.FinalizedHeaderEvent) { - for _, f := range filters[FinalizedHeadersSubscription] { - f.headers <- ev.Header - } -} // eventLoop (un)installs filters and processes mux events. func (es *EventSystem) eventLoop() { @@ -439,7 +406,6 @@ func (es *EventSystem) eventLoop() { es.logsSub.Unsubscribe() es.rmLogsSub.Unsubscribe() es.chainSub.Unsubscribe() - es.finalizedHeaderSub.Unsubscribe() }() index := make(filterIndex) @@ -457,8 +423,6 @@ func (es *EventSystem) eventLoop() { es.handleLogs(index, ev.Logs) case ev := <-es.chainCh: es.handleChainEvent(index, ev) - case ev := <-es.finalizedHeaderCh: - es.handleFinalizedHeaderEvent(index, ev) case f := <-es.install: index[f.typ][f.id] = f @@ -477,8 +441,6 @@ func (es *EventSystem) eventLoop() { return case <-es.chainSub.Err(): return - case <-es.finalizedHeaderSub.Err(): - return } } } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 434af7fa6..70433c242 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -40,15 +40,14 @@ import ( ) type testBackend struct { - db ethdb.Database - fm *filtermaps.FilterMaps - txFeed event.Feed - logsFeed event.Feed - rmLogsFeed event.Feed - chainFeed event.Feed - finalizedHeaderFeed event.Feed - pendingBlock *types.Block - pendingReceipts types.Receipts + db ethdb.Database + fm *filtermaps.FilterMaps + txFeed event.Feed + logsFeed event.Feed + rmLogsFeed event.Feed + chainFeed event.Feed + pendingBlock *types.Block + pendingReceipts types.Receipts } func (b *testBackend) ChainConfig() *params.ChainConfig { @@ -163,10 +162,6 @@ func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc return b.chainFeed.Subscribe(ch) } -func (b *testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { - return b.finalizedHeaderFeed.Subscribe(ch) -} - func (b *testBackend) CurrentView() *filtermaps.ChainView { head := b.CurrentBlock() return filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash()) diff --git a/eth/handler.go b/eth/handler.go index c053b1de1..4b0a8a98c 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -25,7 +25,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/dbft" "github.com/ethereum/go-ethereum/core" @@ -209,11 +208,7 @@ func newHandler(config *handlerConfig) (*handler, error) { log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") } } else { - if _, ok := h.chain.Engine().(consensus.PoS); ok { - log.Info("Chain configured with PoS engine but no TTD.") - } else { - log.Error("Chain configured without TTD. Are you debugging sync?") - } + log.Error("Chain configured without TTD") } // Construct the fetcher (short sync) validator := func(header *types.Header) error { diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index e1d66f1ca..1e7b5fa92 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -600,9 +600,6 @@ func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscr func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { panic("implement me") } -func (b testBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { - panic("implement me") -} func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { panic("implement me") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index bae02972b..29450e59c 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -97,7 +97,6 @@ type Backend interface { GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription CurrentView() *filtermaps.ChainView NewMatcherBackend() filtermaps.MatcherBackend diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index c93b0b9f8..f5271843f 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -386,9 +386,6 @@ func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { return nil } -func (b *backendMock) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription { - return nil -} func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } func (b *backendMock) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { return false, nil, [32]byte{}, 0, 0 From 0d2d14916a6c249cb1506d7bad461aed557f3d42 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Fri, 17 Oct 2025 16:27:27 +0800 Subject: [PATCH 350/354] core/txpool: set 128 blocks as the fallback value for old blob eviction --- core/txpool/blobpool/blobpool.go | 4 +--- core/txpool/blobpool/limbo.go | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index cb092652f..ba2a8694d 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -840,9 +840,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) { } // Flush out any blobs from limbo that are older than the latest finality if p.chain.Config().IsCancun(p.head.Number, p.head.Time) { - if h := p.chain.CurrentFinalBlock(); h != nil { - p.limbo.finalize(h) - } + p.limbo.finalize(p.chain.CurrentFinalBlock(), newHead) } // Reset the price heap for the new set of basefee/blobfee pairs var ( diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index d5992f290..006f9d470 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -112,15 +112,25 @@ func (l *limbo) parseBlob(id uint64, data []byte) error { } // finalize evicts all blobs belonging to a recently finalized block or older. -func (l *limbo) finalize(final *types.Header) { +func (l *limbo) finalize(final *types.Header, current *types.Header) { // Just in case there's no final block yet (network not yet merged, weird - // restart, sethead, etc), fail gracefully. - if final == nil { - log.Error("Nil finalized block cannot evict old blobs") - return + // restart, sethead, etc), take 128 blocks ago as fallback. + // TODO: Remove this fallback once there is a stable source of finality. + // 128 is an impossible reorg depth, for about 10 mins under 5s block time. + last := uint64(0) + if final != nil { + last = final.Number.Uint64() + } else { + if current == nil { + log.Error("Nil finalized and current block cannot evict old blobs") + return + } + if current.Number.Uint64() > 128 { + last = current.Number.Uint64() - 128 + } } for block, ids := range l.groups { - if block > final.Number.Uint64() { + if block > last { continue } for id, owner := range ids { From 4b9dee754726a2826f771273125257b89b95de7d Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Mon, 20 Oct 2025 15:18:11 +0800 Subject: [PATCH 351/354] consensus/dbft: forbid new transaction types in envelope verification --- antimev/envelope.go | 2 +- consensus/dbft/dbft.go | 37 +++++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/antimev/envelope.go b/antimev/envelope.go index e0911eb44..efd3782f2 100644 --- a/antimev/envelope.go +++ b/antimev/envelope.go @@ -51,7 +51,7 @@ var ( // IsEnvelope checks whether a transaction is an Envelope transaction. The criteria // include receiver's address, data prefix and data length check. func IsEnvelope(tx *types.Transaction) bool { - return IsEnvelopeToAddress(tx.To()) && IsEnvelopeData(tx.Data()) + return (tx.Type() != types.BlobTxType && tx.Type() != types.SetCodeTxType) && IsEnvelopeToAddress(tx.To()) && IsEnvelopeData(tx.Data()) } // IsEnvelopeToAddress checks whether an address pointer has the expected value for diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index a85ccbd3d..39b0ace44 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -926,13 +926,19 @@ func (c *DBFT) verifyPreBlockCb(b dbft.PreBlock[common.Hash]) bool { } ethBlock := dbftBlock.ToEthBlock() - errs := c.staticPool.Add(dbftBlock.transactions, false) + // Only take legacy pool transactions. + legacyTxs := make(types.Transactions, 0, len(dbftBlock.transactions)) + for _, tx := range dbftBlock.transactions { + if tx.Type() != types.BlobTxType { + legacyTxs = append(legacyTxs, tx) + } + } + errs := c.staticPool.Add(legacyTxs, false) c.staticPool.ResetStatic() for i, err := range errs { if err != nil { log.Warn("proposed PreBlock has invalid transaction", - "index", i, - "hash", dbftBlock.transactions[i].Hash(), + "hash", legacyTxs[i].Hash(), "error", err, ) return false @@ -1144,15 +1150,17 @@ func (c *DBFT) processPreBlockCb(b dbft.PreBlock[common.Hash]) error { "envelope index", i, "reason", reason) } - errs := c.staticPool.Add([]*types.Transaction{pre.transactions[i]}, false) - if errs[0] != nil { - log.Info("Falling back to original set of transactions", - "envelope hash", pre.transactions[i].Hash(), - "envelope index", i, - "reason", fmt.Sprintf("envelope has pool conflicts: %s", errs[0])) - txx = pre.transactions - hasDecryptedTxs = false - return false + if pre.transactions[i].Type() != types.BlobTxType { + errs := c.staticPool.Add([]*types.Transaction{pre.transactions[i]}, false) + if errs[0] != nil { + log.Info("Falling back to original set of transactions", + "envelope hash", pre.transactions[i].Hash(), + "envelope index", i, + "reason", fmt.Sprintf("envelope has pool conflicts: %s", errs[0])) + txx = pre.transactions + hasDecryptedTxs = false + return false + } } txx[i] = pre.transactions[i] if incrementJ { @@ -1295,6 +1303,11 @@ func (c *DBFT) initStaticPool(parent *types.Header, state *state.StateDB) error // validateDecryptedTx checks the validity of the transaction to determine whether the outer envelope transaction should be replaced. func (c *DBFT) validateDecryptedTx(head *types.Header, decryptedTx *types.Transaction, envelope *types.Transaction, envelopeReceipt *types.Receipt) error { + // Make sure the transaction type is supported by legacy tx pool + if decryptedTx.Type() == types.BlobTxType { + return fmt.Errorf("decryptedTx has unsupported type: %v", decryptedTx.Type()) + } + // Make sure the transaction is signed properly and has the same sender and nonce with envelope if decryptedTx.Nonce() != envelope.Nonce() { return fmt.Errorf("decryptedTx nonce mismatch: decryptedNonce %v, envelopeNonce %v", decryptedTx.Nonce(), envelope.Nonce()) From 3034529eb42202dce0728517e4956e758a26d764 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Mon, 20 Oct 2025 15:19:31 +0800 Subject: [PATCH 352/354] privnet: fix network ids in genesis --- privnet/four/genesis_privnet.json | 2 +- privnet/single/genesis_privnet.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/privnet/four/genesis_privnet.json b/privnet/four/genesis_privnet.json index 3d4bfe368..349f8d94e 100644 --- a/privnet/four/genesis_privnet.json +++ b/privnet/four/genesis_privnet.json @@ -1,6 +1,6 @@ { "config": { - "chainId": 2312251829, + "chainId": 2312051114, "homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, diff --git a/privnet/single/genesis_privnet.json b/privnet/single/genesis_privnet.json index 76de92328..dafe99e91 100644 --- a/privnet/single/genesis_privnet.json +++ b/privnet/single/genesis_privnet.json @@ -1,6 +1,6 @@ { "config": { - "chainId": 2312251829, + "chainId": 2312051126, "homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, From 5d8319798a09311885960948cd13d9ec6fb7b4db Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Mon, 20 Oct 2025 16:27:53 +0800 Subject: [PATCH 353/354] consensus/dbft: forbid blobsidecar fetching from local pool --- consensus/dbft/dbft.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/dbft/dbft.go b/consensus/dbft/dbft.go index 39b0ace44..7588db095 100644 --- a/consensus/dbft/dbft.go +++ b/consensus/dbft/dbft.go @@ -614,7 +614,7 @@ func (c *DBFT) getTxCb(h common.Hash) dbft.Transaction[common.Hash] { // expects a pure nil. if tx != nil { return &Transaction{ - Tx: tx, + Tx: tx.WithoutBlobTxSidecar(), } } From d43373c5fe81adf768f39cede9755dd4f59f7be9 Mon Sep 17 00:00:00 2001 From: Hu Shili <799498265@qq.com> Date: Tue, 21 Oct 2025 15:33:02 +0800 Subject: [PATCH 354/354] eth/filter: handle cutoff chain correctly --- eth/filters/api.go | 4 ++++ eth/filters/filter.go | 11 +++++++++++ eth/filters/filter_system.go | 10 ++++++++++ internal/ethapi/backend.go | 1 + 4 files changed, 26 insertions(+) diff --git a/eth/filters/api.go b/eth/filters/api.go index a32b48433..8788e8b4a 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" @@ -377,6 +378,9 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type if begin > 0 && end > 0 && begin > end { return nil, errInvalidBlockRange } + if begin > 0 && begin < int64(api.events.backend.HistoryPruningCutoff()) { + return nil, &history.PrunedHistoryError{} + } // Construct the range filter filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 23754fdf7..dd6643c59 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/filtermaps" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -86,6 +87,9 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, errors.New("unknown block") } + if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } return f.blockLogs(ctx, header) } @@ -114,6 +118,13 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return 0, errors.New("safe header not found") } return hdr.Number.Uint64(), nil + case rpc.EarliestBlockNumber.Int64(): + earliest := f.sys.backend.HistoryPruningCutoff() + hdr, _ := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(earliest)) + if hdr == nil { + return 0, errors.New("earliest header not found") + } + return hdr.Number.Uint64(), nil default: if number < 0 { return 0, errors.New("negative block number") diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 1bf6496bb..49912843f 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/filtermaps" + "github.com/ethereum/go-ethereum/core/history" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -65,6 +66,7 @@ type Backend interface { CurrentHeader() *types.Header ChainConfig() *params.ChainConfig + HistoryPruningCutoff() uint64 SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription @@ -308,6 +310,14 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ return nil, errPendingLogsUnsupported } + if from == rpc.EarliestBlockNumber { + from = rpc.BlockNumber(es.backend.HistoryPruningCutoff()) + } + // Queries beyond the pruning cutoff are not supported. + if uint64(from) < es.backend.HistoryPruningCutoff() { + return nil, &history.PrunedHistoryError{} + } + // only interested in new mined logs if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber { return es.subscribeLogs(crit, logs), nil diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 29450e59c..2ecac1303 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -89,6 +89,7 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine + HistoryPruningCutoff() uint64 // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by